From 4f238fec7371f68aa14e15909cd37ef3f5c6d66f Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Mon, 5 Mar 2018 16:14:28 -0500 Subject: [PATCH] initial commit --- atf.h | 128 + buf.c | 111 + edit.h | 101 + stdc.h | 207 + tags | 10982 ++ testbuf.c | 638 + testdocs/crlf.txt | 5 + testdocs/lang-utf16.txt | 38 + testdocs/lang-utf8.txt | 38 + testdocs/lf.txt | 5 + testdocs/longlines.txt | 2 + testdocs/lorem.txt | 998 + testdocs/numbers.txt | 1001 + testdocs/sherlock.txt | 128457 +++++++++++++++++++++++ testdocs/sqlite3.c | 202918 +++++++++++++++++++++++++++++++++++++ testdocs/test.xml | 100002 ++++++++++++++++++ testdocs/utf8.txt | 204 + testdocs/waf | 169 + testdocs/zeros.c | 50 + utf.h | 26 + 20 files changed, 446080 insertions(+) create mode 100644 atf.h create mode 100644 buf.c create mode 100644 edit.h create mode 100644 stdc.h create mode 100644 tags create mode 100644 testbuf.c create mode 100644 testdocs/crlf.txt create mode 100644 testdocs/lang-utf16.txt create mode 100644 testdocs/lang-utf8.txt create mode 100644 testdocs/lf.txt create mode 100644 testdocs/longlines.txt create mode 100644 testdocs/lorem.txt create mode 100644 testdocs/numbers.txt create mode 100644 testdocs/sherlock.txt create mode 100644 testdocs/sqlite3.c create mode 100644 testdocs/test.xml create mode 100644 testdocs/utf8.txt create mode 100755 testdocs/waf create mode 100644 testdocs/zeros.c create mode 100644 utf.h diff --git a/atf.h b/atf.h new file mode 100644 index 0000000..465ac44 --- /dev/null +++ b/atf.h @@ -0,0 +1,128 @@ +/** + @brief A minimalistic unit testing framework for C. + @author Michael D. Lowis + @license BSD 2-clause License +*/ +#ifndef ATF_H +#define ATF_H + +#include +#include + +extern char* Curr_Test; +void atf_init(int argc, char** argv); +void atf_test_start(char* file, unsigned int line, char* name); +bool atf_test_assert(bool success, char* expr_str, char* file, int line); +void atf_test_fail(char* expr, char* file, int line); +int atf_print_results(void); + +#define IGNORE(msg) \ + printf("%s:%d:%s:IGNORE:\n\t%s\n", __FILE__, __LINE__, Curr_Test, msg); break + +#define CHECK(expr) \ + if(atf_test_assert((expr), #expr, __FILE__, __LINE__)) break + +#define TEST_SUITE(name) \ + void name(void) + +#define TEST(desc) \ + for(atf_test_start(__FILE__,__LINE__,#desc); Curr_Test != NULL; Curr_Test = NULL) + +#define RUN_TEST_SUITE(name) \ + name(); + +#define RUN_EXTERN_TEST_SUITE(name) \ + do { extern TEST_SUITE(name); RUN_TEST_SUITE(name); } while(0) + +#define PRINT_TEST_RESULTS \ + atf_print_results + +/* Function Definitions + *****************************************************************************/ +#ifdef INCLUDE_DEFS +#include +#include +#ifndef NO_SIGNALS +#include +#endif + +char* Curr_Test = NULL; +char* Curr_File = NULL; +unsigned int Curr_Line = 0; +static unsigned int Total = 0; +static unsigned int Failed = 0; + +#ifndef NO_SIGNALS +static void handle_signal(int sig) { + /* Determine the signal name */ + char* sig_name = NULL; + switch(sig) { + case SIGABRT: sig_name = "SIGABRT"; break; + case SIGBUS: sig_name = "SIGBUS"; break; + case SIGFPE: sig_name = "SIGFPE"; break; + case SIGILL: sig_name = "SIGILL"; break; + case SIGSEGV: sig_name = "SIGSEGV"; break; + case SIGSYS: sig_name = "SIGSYS"; break; + /* If we don't recognize it then just return and let the default handler + catch it. */ + default: return; + } + /* Error and exit. No summary will be printed but the user will know which + test has crashed. */ + fprintf(stderr,"%s:%d:0:%s:CRASH (signal: %d - %s)\n", Curr_File, Curr_Line, Curr_Test, sig, sig_name); + Failed++; + (void)atf_print_results(); + _Exit(1); +} +#endif + +void atf_init(int argc, char** argv) { + /* I reserve the right to use these later */ + (void)argc; + (void)argv; + +#ifndef NO_SIGNALS + /* Init signal handler */ + signal(SIGABRT, handle_signal); + signal(SIGBUS, handle_signal); + signal(SIGFPE, handle_signal); + signal(SIGILL, handle_signal); + signal(SIGSEGV, handle_signal); + signal(SIGSYS, handle_signal); +#endif +} + +void atf_test_start(char* file, unsigned int line, char* name) { + Curr_File = file; + Curr_Line = line; + Curr_Test = name; + Total++; +} + +bool atf_test_assert(bool success, char* expr, char* file, int line) { + bool failed = !success; + if (failed) atf_test_fail(expr,file,line); + return failed; +} + +void atf_test_fail(char* expr, char* file, int line) { + Failed++; + printf("%s:%d:0:%s:FAIL:( %s )\n", file, line, Curr_Test, expr); \ +} + +int atf_print_results(void) { + static const char* results_string = + "\nUnit Test Summary" + "\n-----------------" + "\nTotal: %d" + "\nPassed: %d" + "\nFailed: %d" + "\n\n"; + printf(results_string, Total, Total - Failed, Failed); + return Failed; +} + +#undef INCLUDE_DEFS +#endif + +#endif /* ATF_H */ diff --git a/buf.c b/buf.c new file mode 100644 index 0000000..973a8c0 --- /dev/null +++ b/buf.c @@ -0,0 +1,111 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int CfgTabWidth = 4; +int CfgExpandTabs = true; + +/******************************************************************************/ + +static size_t pagealign(size_t sz) { + size_t pgsize = sysconf(_SC_PAGE_SIZE); + size_t alignmask = pgsize - 1; + if (sz & alignmask) + sz += pgsize - (sz & alignmask); + return sz; +} + +void die(const char* msgfmt, ...) { + va_list args; + va_start(args, msgfmt); + fprintf(stderr, "error: "); + vfprintf(stderr, msgfmt, args); + va_end(args); + if (*msgfmt && msgfmt[strlen(msgfmt)-1] == ':') + fprintf(stderr, " %s", strerror(errno)); + fprintf(stderr, "\n"); + exit(EXIT_FAILURE); +} + +/******************************************************************************/ + +void buf_init(Buf* buf, void (*errfn)(char*)) { + /* cleanup old data if there is any */ + if (buf->bufstart) { + free(buf->bufstart); + buf->bufstart = NULL; + } + /* reset the state to defaults */ + buf->modified = false; + buf->expand_tabs = CfgExpandTabs; + buf->crlf = 0; + buf->bufsize = pagealign(1); + buf->bufstart = malloc(buf->bufsize * sizeof(Rune)); + buf->bufend = buf->bufstart + buf->bufsize; + buf->gapstart = buf->bufstart; + buf->gapend = buf->bufend; + buf->undo = NULL; + buf->redo = NULL; + buf->errfn = errfn; + assert(buf->bufstart); +} + +void buf_load(Buf* buf, Sel* sel, char* path) { + /* process the file path and address */ + if (path && path[0] == '.' && path[1] == '/') + path += 2; + buf->path = strdup(path); + char* addr = strrchr(buf->path, ':'); + if (addr) *addr = '\0', addr++; + /* load the contents from the file */ + int fd, nread; + struct stat sb = {0}; + if (((fd = open(path, O_RDONLY, 0)) >= 0) && (fstat(fd, &sb) >= 0) && (sb.st_size > 0)) { + /* allocate the buffer in advance */ + free(buf->bufstart); + buf->bufsize = pagealign(sb.st_size); + buf->bufstart = malloc(buf->bufsize); + buf->bufend = buf->bufstart + buf->bufsize; + buf->gapstart = buf->bufstart; + buf->gapend = buf->bufend; + if (!buf->bufstart) die("malloc() :"); + /* Read the file into the buffer */ + while (sb.st_size && (nread = read(fd, buf->gapstart, sb.st_size)) > 0) + buf->gapstart += nread, sb.st_size -= nread; + if (nread < 0) die("read() :"); + } + if (fd > 0) close(fd); + if (sel) *sel = (Sel){0}; +} + +void buf_reload(Buf* buf) { + void (*errfn)(char*) = buf->errfn; + char* path = buf->path; + buf_init(buf, errfn); + buf_load(buf, NULL, path); +} + +void buf_save(Buf* buf) { +} + +Rune buf_getc(Buf* buf, Sel* sel) +{ + return 0; +} + +void buf_putc(Buf* buf, Sel* sel, Rune rune, int fmtopts) +{ +} + +void buf_last(Buf* buf, Sel* sel) +{ +} diff --git a/edit.h b/edit.h new file mode 100644 index 0000000..61ff34c --- /dev/null +++ b/edit.h @@ -0,0 +1,101 @@ +/* Utility Functions + *****************************************************************************/ +/* Memory-mapped file representation */ +typedef struct { + uint8_t* buf; /* memory mapped byte buffer */ + size_t len; /* length of the buffer */ +} FMap; + +/* Buffer management functions + *****************************************************************************/ +/* undo/redo list item */ +typedef struct Log { + struct Log* next; /* pointer to next operation in the stack */ + bool insert; /* whether this operation was an insert or delete */ + uint transid; /* transaction id used to group related edits together */ + union { + struct { + size_t beg; /* offset in the file where insertion started */ + size_t end; /* offset in the file where insertion ended */ + } ins; + struct { + size_t off; /* offset in the file where the deletion occurred */ + size_t len; /* number of runes deleted */ + Rune* runes; /* array of runes containing deleted content */ + } del; + } data; +} Log; + +/* gap buffer main data structure */ +typedef struct { + char* path; /* the path to the open file */ + uint64_t modtime; /* modification time of the opened file */ + int crlf; /* tracks whether the file uses dos style line endings */ + size_t bufsize; /* size of the buffer in runes */ + char* bufstart; /* start of the data buffer */ + char* bufend; /* end of the data buffer */ + char* gapstart; /* start of the gap */ + char* gapend; /* end of the gap */ + Log* undo; /* undo list */ + Log* redo; /* redo list */ + bool modified; /* tracks whether the buffer has been modified */ + bool expand_tabs; /* tracks current mode */ + uint transid; /* tracks the last used transaction id for log entries */ + void (*errfn)(char*); /* callback for error messages */ +} Buf; + +/* cursor/selection representation */ +typedef struct { + size_t beg; + size_t end; + size_t col; +} Sel; + +enum { + LEFT = -1, + RIGHT = +1, + UP = -1, + DOWN = +1 +}; + +void buf_init(Buf* buf, void (*errfn)(char*)); +void buf_load(Buf* buf, Sel* sel, char* path); +void buf_reload(Buf* buf); +void buf_save(Buf* buf); + +Rune buf_getc(Buf* buf, Sel* sel); +void buf_putc(Buf* buf, Sel* sel, Rune rune, int fmtopts); +void buf_last(Buf* buf, Sel* sel); + +#if 0 +Rune buf_get(Buf* buf, size_t pos); +size_t buf_end(Buf* buf); +size_t buf_insert(Buf* buf, bool indent, size_t off, Rune rune); +size_t buf_delete(Buf* buf, size_t beg, size_t end); +size_t buf_change(Buf* buf, size_t beg, size_t end); + +void buf_chomp(Buf* buf); +void buf_undo(Buf* buf, Sel* sel); +void buf_redo(Buf* buf, Sel* sel); +void buf_loglock(Buf* buf); +void buf_logclear(Buf* buf); +bool buf_iseol(Buf* buf, size_t pos); +size_t buf_bol(Buf* buf, size_t pos); +size_t buf_eol(Buf* buf, size_t pos); +size_t buf_bow(Buf* buf, size_t pos); +size_t buf_eow(Buf* buf, size_t pos); +size_t buf_lscan(Buf* buf, size_t pos, Rune r); +size_t buf_rscan(Buf* buf, size_t pos, Rune r); +void buf_getword(Buf* buf, bool (*isword)(Rune), Sel* sel); +void buf_getblock(Buf* buf, Rune beg, Rune end, Sel* sel); +size_t buf_byrune(Buf* buf, size_t pos, int count); +size_t buf_byword(Buf* buf, size_t pos, int count); +size_t buf_byline(Buf* buf, size_t pos, int count); +void buf_findstr(Buf* buf, int dir, char* str, size_t* beg, size_t* end); +void buf_lastins(Buf* buf, size_t* beg, size_t* end); +size_t buf_setln(Buf* buf, size_t line); +size_t buf_getln(Buf* buf, size_t off); +size_t buf_getcol(Buf* buf, size_t pos); +size_t buf_setcol(Buf* buf, size_t pos, size_t col); +#endif + diff --git a/stdc.h b/stdc.h new file mode 100644 index 0000000..3d867af --- /dev/null +++ b/stdc.h @@ -0,0 +1,207 @@ +/** + @brief Collection of useful C types and functions. + @author Michael D. Lowis + @license BSD 2-clause License +*/ + +/* Standard Macros and Types */ +#include +#include +#include +#include +#include +#include + +/* Useful Standard Functions */ +#include +#include +#include +#include +#include + +/* Type Definitions + *****************************************************************************/ +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef unsigned long ulong; +typedef unsigned int uint; +typedef signed char schar; +typedef long long vlong; +typedef unsigned long long uvlong; + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + +typedef uintptr_t uintptr; +typedef intptr_t intptr; + +/* Generic Death Function + *****************************************************************************/ +void die(const char* msgfmt, ...) __attribute__((__noreturn__)); + +/* Option Parsing + * + * This following macros implement a simple POSIX-style option parsing strategy. + * They are heavily influenced and inspired by the arg.h file from suckless.org + * (http://git.suckless.org/libsl/tree/arg.h). That file is in turn inspired by + * the corresponding macros defined in plan9. + * + * The interface assumes that the main function will have the following + * prototype: + * + * int main(int argc, char** argv); + * + * An example usage of the interface would look something like the follwoing: + * + * char* ARGV0; + * int main(int argc, char** argv) { + * OPTBEGIN { + * case 'a': printf("Simple option\n"); break; + * case 'b': printf("Option with arg: %s\n", OPTARG()); break; + * default: printf("Unknown option!\n"); + * } OPTEND; + * return 0; + * } + */ + +/* This variable contains the value of argv[0] so that it can be referenced + * again once the option parsing is done. This variable must be defined by the + * program. + * + * NOTE: Ensure that you define this variable with external linkage (i.e. not + * static) */ +extern char* ARGV0; + +/* This is a helper function used by the following macros to parse the next + * option from the command line. */ +static inline char* _getopt_(int* p_argc, char*** p_argv) { + if (!(*p_argv)[0][1] && !(*p_argv)[1]) { + return (char*)0; + } else if ((*p_argv)[0][1]) { + return &(*p_argv)[0][1]; + } else { + *p_argv = *p_argv + 1; + *p_argc = *p_argc - 1; + return (*p_argv)[0]; + } +} + +/* This macro is almost identical to the ARGBEGIN macro from suckless.org. If + * it ain't broke, don't fix it. */ +#define OPTBEGIN \ + for ( \ + ARGV0 = *argv, argc--, argv++; \ + argv[0] && argv[0][1] && argv[0][0] == '-'; \ + argc--, argv++ \ + ) { \ + int brk_; char argc_ , **argv_, *optarg_; \ + if (argv[0][1] == '-' && !argv[0][2]) { \ + argv++, argc--; break; \ + } \ + for (brk_=0, argv[0]++, argv_=argv; argv[0][0] && !brk_; argv[0]++) { \ + if (argv_ != argv) break; \ + argc_ = argv[0][0]; \ + switch (argc_) + +/* Terminate the option parsing. */ +#define OPTEND }} + +/* Get the current option character */ +#define OPTC() (argc_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro returns NULL */ +#define OPTARG() \ + (optarg_ = _getopt_(&argc,&argv), brk_ = (optarg_!=0), optarg_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro executes the provided code. If that code + * returns, then abort is called. */ +#define EOPTARG(code) \ + (optarg_ = _getopt_(&argc,&argv), \ + (!optarg_ ? ((code), abort(), (char*)0) : (brk_ = 1, optarg_))) + +/* Helper macro to recognize number options */ +#define OPTNUM \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +/* Helper macro to recognize "long" options ala GNU style. */ +#define OPTLONG \ + case '-' + +/* Error Handling + *****************************************************************************/ +#define trace() \ + fprintf(stderr, "%s:%d\n", __FILE__, __LINE__) + +#ifdef NDEBUG + #define debug(msg, ...) \ + ((void)0) +#else + #define debug(msg, ...) \ + fprintf(stderr, "DEBUG %s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__) +#endif + +#define errnostr() \ + (errno == 0 ? "None" : strerror(errno)) + +#define print_error(msg, ...) \ + fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " msg "\n", __FILE__, __LINE__, errnostr(), ##__VA_ARGS__) + +#define check(expr, msg, ...) \ + if(!(expr)) { print_error(msg, ##__VA_ARGS__); errno=0; goto error; } + +#define sentinel(msg, ...) \ + { print_error(msg, ##__VA_ARGS__); errno=0; goto error; } + +/* Miscellaneous + *****************************************************************************/ +#ifndef nelem + #define nelem(x) \ + (sizeof(x)/sizeof((x)[0])) +#endif + +#ifndef container_of + #define container_of(obj, type, member) \ + (type*)((uintptr_t)obj - offsetof(type, member)) +#endif + +#define concat(a,b) \ + a##b + +#define ident(a) \ + concat(id, a) + +#define unique_id \ + ident(__LINE__) + +#ifndef static_assert + #define static_assert(expr) \ + typedef char unique_id[( expr )?1:-1] +#endif + +#ifndef min + #define min(x,y) \ + ((x) < (y) ? (x) : (y)) +#endif + +#ifndef max + #define max(x,y) \ + ((x) > (y) ? (x) : (y)) +#endif diff --git a/tags b/tags new file mode 100644 index 0000000..faa42dc --- /dev/null +++ b/tags @@ -0,0 +1,10982 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.8 // +ADDR testdocs/sqlite3.c /^#define ADDR(/;" d file: +AGGREGATE testdocs/sqlite3.c /^#define AGGREGATE(/;" d file: +AGGREGATE2 testdocs/sqlite3.c /^#define AGGREGATE2(/;" d file: +ALLBITS testdocs/sqlite3.c /^#define ALLBITS /;" d file: +ALWAYS testdocs/sqlite3.c /^# define ALWAYS(/;" d file: +ALWAYS testdocs/sqlite3.c /^#define ALWAYS(/;" d file: +ASSERT_SZLEAF_OK testdocs/sqlite3.c /^#define ASSERT_SZLEAF_OK(/;" d file: +ATF_H atf.h /^#define ATF_H$/;" d +AdjustTree testdocs/sqlite3.c /^static int AdjustTree($/;" f file: +AggInfo testdocs/sqlite3.c /^struct AggInfo {$/;" s file: +AggInfo testdocs/sqlite3.c /^typedef struct AggInfo AggInfo;$/;" t typeref:struct:AggInfo file: +AggInfo_col testdocs/sqlite3.c /^ struct AggInfo_col { \/* For each column used in source tables *\/$/;" s struct:AggInfo file: +AggInfo_func testdocs/sqlite3.c /^ struct AggInfo_func { \/* For each aggregate function *\/$/;" s struct:AggInfo file: +ApplyCostMultiplier testdocs/sqlite3.c /^# define ApplyCostMultiplier(/;" d file: +ArraySize testdocs/sqlite3.c /^# define ArraySize(/;" d file: +ArraySize testdocs/sqlite3.c /^#define ArraySize(/;" d file: +AsciiTokenizer testdocs/sqlite3.c /^struct AsciiTokenizer {$/;" s file: +AsciiTokenizer testdocs/sqlite3.c /^typedef struct AsciiTokenizer AsciiTokenizer;$/;" t typeref:struct:AsciiTokenizer file: +AuthContext testdocs/sqlite3.c /^struct AuthContext {$/;" s file: +AuthContext testdocs/sqlite3.c /^typedef struct AuthContext AuthContext;$/;" t typeref:struct:AuthContext file: +AutoincInfo testdocs/sqlite3.c /^struct AutoincInfo {$/;" s file: +AutoincInfo testdocs/sqlite3.c /^typedef struct AutoincInfo AutoincInfo;$/;" t typeref:struct:AutoincInfo file: +AuxData testdocs/sqlite3.c /^struct AuxData {$/;" s file: +AuxData testdocs/sqlite3.c /^typedef struct AuxData AuxData;$/;" t typeref:struct:AuxData file: +BITVEC_HASH testdocs/sqlite3.c /^#define BITVEC_HASH(/;" d file: +BITVEC_MXHASH testdocs/sqlite3.c /^#define BITVEC_MXHASH /;" d file: +BITVEC_NBIT testdocs/sqlite3.c /^#define BITVEC_NBIT /;" d file: +BITVEC_NELEM testdocs/sqlite3.c /^#define BITVEC_NELEM /;" d file: +BITVEC_NINT testdocs/sqlite3.c /^#define BITVEC_NINT /;" d file: +BITVEC_NPTR testdocs/sqlite3.c /^#define BITVEC_NPTR /;" d file: +BITVEC_SZ testdocs/sqlite3.c /^#define BITVEC_SZ /;" d file: +BITVEC_SZELEM testdocs/sqlite3.c /^#define BITVEC_SZELEM /;" d file: +BITVEC_TELEM testdocs/sqlite3.c /^#define BITVEC_TELEM /;" d file: +BITVEC_USIZE testdocs/sqlite3.c /^#define BITVEC_USIZE /;" d file: +BMS testdocs/sqlite3.c /^#define BMS /;" d file: +BTALLOC_ANY testdocs/sqlite3.c /^#define BTALLOC_ANY /;" d file: +BTALLOC_EXACT testdocs/sqlite3.c /^#define BTALLOC_EXACT /;" d file: +BTALLOC_LE testdocs/sqlite3.c /^#define BTALLOC_LE /;" d file: +BTCF_AtLast testdocs/sqlite3.c /^#define BTCF_AtLast /;" d file: +BTCF_Incrblob testdocs/sqlite3.c /^#define BTCF_Incrblob /;" d file: +BTCF_Multiple testdocs/sqlite3.c /^#define BTCF_Multiple /;" d file: +BTCF_ValidNKey testdocs/sqlite3.c /^#define BTCF_ValidNKey /;" d file: +BTCF_ValidOvfl testdocs/sqlite3.c /^#define BTCF_ValidOvfl /;" d file: +BTCF_WriteFlag testdocs/sqlite3.c /^#define BTCF_WriteFlag /;" d file: +BTCURSOR_MAX_DEPTH testdocs/sqlite3.c /^#define BTCURSOR_MAX_DEPTH /;" d file: +BTREE_APPEND testdocs/sqlite3.c /^#define BTREE_APPEND /;" d file: +BTREE_APPLICATION_ID testdocs/sqlite3.c /^#define BTREE_APPLICATION_ID /;" d file: +BTREE_AUTOVACUUM_FULL testdocs/sqlite3.c /^#define BTREE_AUTOVACUUM_FULL /;" d file: +BTREE_AUTOVACUUM_INCR testdocs/sqlite3.c /^#define BTREE_AUTOVACUUM_INCR /;" d file: +BTREE_AUTOVACUUM_NONE testdocs/sqlite3.c /^#define BTREE_AUTOVACUUM_NONE /;" d file: +BTREE_AUXDELETE testdocs/sqlite3.c /^#define BTREE_AUXDELETE /;" d file: +BTREE_BLOBKEY testdocs/sqlite3.c /^#define BTREE_BLOBKEY /;" d file: +BTREE_BULKLOAD testdocs/sqlite3.c /^#define BTREE_BULKLOAD /;" d file: +BTREE_DATA_VERSION testdocs/sqlite3.c /^#define BTREE_DATA_VERSION /;" d file: +BTREE_DEFAULT_CACHE_SIZE testdocs/sqlite3.c /^#define BTREE_DEFAULT_CACHE_SIZE /;" d file: +BTREE_FILE_FORMAT testdocs/sqlite3.c /^#define BTREE_FILE_FORMAT /;" d file: +BTREE_FORDELETE testdocs/sqlite3.c /^#define BTREE_FORDELETE /;" d file: +BTREE_FREE_PAGE_COUNT testdocs/sqlite3.c /^#define BTREE_FREE_PAGE_COUNT /;" d file: +BTREE_HINT_RANGE testdocs/sqlite3.c /^#define BTREE_HINT_RANGE /;" d file: +BTREE_INCR_VACUUM testdocs/sqlite3.c /^#define BTREE_INCR_VACUUM /;" d file: +BTREE_INTKEY testdocs/sqlite3.c /^#define BTREE_INTKEY /;" d file: +BTREE_LARGEST_ROOT_PAGE testdocs/sqlite3.c /^#define BTREE_LARGEST_ROOT_PAGE /;" d file: +BTREE_MEMORY testdocs/sqlite3.c /^#define BTREE_MEMORY /;" d file: +BTREE_OMIT_JOURNAL testdocs/sqlite3.c /^#define BTREE_OMIT_JOURNAL /;" d file: +BTREE_SAVEPOSITION testdocs/sqlite3.c /^#define BTREE_SAVEPOSITION /;" d file: +BTREE_SCHEMA_VERSION testdocs/sqlite3.c /^#define BTREE_SCHEMA_VERSION /;" d file: +BTREE_SEEK_EQ testdocs/sqlite3.c /^#define BTREE_SEEK_EQ /;" d file: +BTREE_SINGLE testdocs/sqlite3.c /^#define BTREE_SINGLE /;" d file: +BTREE_TEXT_ENCODING testdocs/sqlite3.c /^#define BTREE_TEXT_ENCODING /;" d file: +BTREE_UNORDERED testdocs/sqlite3.c /^#define BTREE_UNORDERED /;" d file: +BTREE_USER_VERSION testdocs/sqlite3.c /^#define BTREE_USER_VERSION /;" d file: +BTREE_WRCSR testdocs/sqlite3.c /^#define BTREE_WRCSR /;" d file: +BTS_EXCLUSIVE testdocs/sqlite3.c /^#define BTS_EXCLUSIVE /;" d file: +BTS_INITIALLY_EMPTY testdocs/sqlite3.c /^#define BTS_INITIALLY_EMPTY /;" d file: +BTS_NO_WAL testdocs/sqlite3.c /^#define BTS_NO_WAL /;" d file: +BTS_PAGESIZE_FIXED testdocs/sqlite3.c /^#define BTS_PAGESIZE_FIXED /;" d file: +BTS_PENDING testdocs/sqlite3.c /^#define BTS_PENDING /;" d file: +BTS_READ_ONLY testdocs/sqlite3.c /^#define BTS_READ_ONLY /;" d file: +BTS_SECURE_DELETE testdocs/sqlite3.c /^#define BTS_SECURE_DELETE /;" d file: +BYTESWAP32 testdocs/sqlite3.c /^#define BYTESWAP32(/;" d file: +BenignMallocHooks testdocs/sqlite3.c /^static SQLITE_WSD struct BenignMallocHooks {$/;" s file: +BenignMallocHooks testdocs/sqlite3.c /^typedef struct BenignMallocHooks BenignMallocHooks;$/;" t typeref:struct:BenignMallocHooks file: +BitFlagAllTest testdocs/sqlite3.c /^#define BitFlagAllTest(/;" d file: +BitFlagTest testdocs/sqlite3.c /^#define BitFlagTest(/;" d file: +Bitmask testdocs/sqlite3.c /^ typedef SQLITE_BITMASK_TYPE Bitmask;$/;" t file: +Bitmask testdocs/sqlite3.c /^ typedef u64 Bitmask;$/;" t file: +Bitvec testdocs/sqlite3.c /^struct Bitvec {$/;" s file: +Bitvec testdocs/sqlite3.c /^typedef struct Bitvec Bitvec;$/;" t typeref:struct:Bitvec file: +Blob testdocs/sqlite3.c /^struct Blob {$/;" s file: +Blob testdocs/sqlite3.c /^typedef struct Blob Blob;$/;" t typeref:struct:Blob file: +Bool testdocs/sqlite3.c /^typedef unsigned Bool;$/;" t file: +BtCursor testdocs/sqlite3.c /^struct BtCursor {$/;" s file: +BtCursor testdocs/sqlite3.c /^typedef struct BtCursor BtCursor;$/;" t typeref:struct:BtCursor file: +BtLock testdocs/sqlite3.c /^struct BtLock {$/;" s file: +BtLock testdocs/sqlite3.c /^typedef struct BtLock BtLock;$/;" t typeref:struct:BtLock file: +BtShared testdocs/sqlite3.c /^struct BtShared {$/;" s file: +BtShared testdocs/sqlite3.c /^typedef struct BtShared BtShared;$/;" t typeref:struct:BtShared file: +Btree testdocs/sqlite3.c /^struct Btree {$/;" s file: +Btree testdocs/sqlite3.c /^typedef struct Btree Btree;$/;" t typeref:struct:Btree file: +BtreePayload testdocs/sqlite3.c /^struct BtreePayload {$/;" s file: +BtreePayload testdocs/sqlite3.c /^typedef struct BtreePayload BtreePayload;$/;" t typeref:struct:BtreePayload file: +Buf edit.h /^} Buf;$/;" t typeref:struct:__anon5 +BusyHandler testdocs/sqlite3.c /^struct BusyHandler {$/;" s file: +BusyHandler testdocs/sqlite3.c /^typedef struct BusyHandler BusyHandler;$/;" t typeref:struct:BusyHandler file: +ByteRangeLockPB2 testdocs/sqlite3.c /^struct ByteRangeLockPB2$/;" s file: +C1 testdocs/waf /^C1='#.'$/;" v +C2 testdocs/waf /^C2='#,'$/;" v +C3 testdocs/waf /^C3='#('$/;" v +CACHE_STALE testdocs/sqlite3.c /^#define CACHE_STALE /;" d file: +CC_AND testdocs/sqlite3.c /^#define CC_AND /;" d file: +CC_BANG testdocs/sqlite3.c /^#define CC_BANG /;" d file: +CC_COMMA testdocs/sqlite3.c /^#define CC_COMMA /;" d file: +CC_DIGIT testdocs/sqlite3.c /^#define CC_DIGIT /;" d file: +CC_DOLLAR testdocs/sqlite3.c /^#define CC_DOLLAR /;" d file: +CC_DOT testdocs/sqlite3.c /^#define CC_DOT /;" d file: +CC_EQ testdocs/sqlite3.c /^#define CC_EQ /;" d file: +CC_GT testdocs/sqlite3.c /^#define CC_GT /;" d file: +CC_ID testdocs/sqlite3.c /^#define CC_ID /;" d file: +CC_ILLEGAL testdocs/sqlite3.c /^#define CC_ILLEGAL /;" d file: +CC_KYWD testdocs/sqlite3.c /^#define CC_KYWD /;" d file: +CC_LP testdocs/sqlite3.c /^#define CC_LP /;" d file: +CC_LT testdocs/sqlite3.c /^#define CC_LT /;" d file: +CC_MINUS testdocs/sqlite3.c /^#define CC_MINUS /;" d file: +CC_PERCENT testdocs/sqlite3.c /^#define CC_PERCENT /;" d file: +CC_PIPE testdocs/sqlite3.c /^#define CC_PIPE /;" d file: +CC_PLUS testdocs/sqlite3.c /^#define CC_PLUS /;" d file: +CC_QUOTE testdocs/sqlite3.c /^#define CC_QUOTE /;" d file: +CC_QUOTE2 testdocs/sqlite3.c /^#define CC_QUOTE2 /;" d file: +CC_RP testdocs/sqlite3.c /^#define CC_RP /;" d file: +CC_SEMI testdocs/sqlite3.c /^#define CC_SEMI /;" d file: +CC_SLASH testdocs/sqlite3.c /^#define CC_SLASH /;" d file: +CC_SPACE testdocs/sqlite3.c /^#define CC_SPACE /;" d file: +CC_STAR testdocs/sqlite3.c /^#define CC_STAR /;" d file: +CC_TILDA testdocs/sqlite3.c /^#define CC_TILDA /;" d file: +CC_VARALPHA testdocs/sqlite3.c /^#define CC_VARALPHA /;" d file: +CC_VARNUM testdocs/sqlite3.c /^#define CC_VARNUM /;" d file: +CC_X testdocs/sqlite3.c /^#define CC_X /;" d file: +CCurHint testdocs/sqlite3.c /^struct CCurHint {$/;" s file: +CHECK atf.h /^#define CHECK(/;" d +CHECK_PAGE testdocs/sqlite3.c /^#define CHECK_PAGE(/;" d file: +CInstIter testdocs/sqlite3.c /^struct CInstIter {$/;" s file: +CInstIter testdocs/sqlite3.c /^typedef struct CInstIter CInstIter;$/;" t typeref:struct:CInstIter file: +CKCNSTRNT_COLUMN testdocs/sqlite3.c /^#define CKCNSTRNT_COLUMN /;" d file: +CKCNSTRNT_ROWID testdocs/sqlite3.c /^#define CKCNSTRNT_ROWID /;" d file: +CLEARBIT testdocs/sqlite3.c /^#define CLEARBIT(/;" d file: +CODEC1 testdocs/sqlite3.c /^# define CODEC1(/;" d file: +CODEC2 testdocs/sqlite3.c /^# define CODEC2(/;" d file: +COLFLAG_HASTYPE testdocs/sqlite3.c /^#define COLFLAG_HASTYPE /;" d file: +COLFLAG_HIDDEN testdocs/sqlite3.c /^#define COLFLAG_HIDDEN /;" d file: +COLFLAG_PRIMKEY testdocs/sqlite3.c /^#define COLFLAG_PRIMKEY /;" d file: +COLNAME_COLUMN testdocs/sqlite3.c /^#define COLNAME_COLUMN /;" d file: +COLNAME_DATABASE testdocs/sqlite3.c /^#define COLNAME_DATABASE /;" d file: +COLNAME_DECLTYPE testdocs/sqlite3.c /^#define COLNAME_DECLTYPE /;" d file: +COLNAME_N testdocs/sqlite3.c /^# define COLNAME_N /;" d file: +COLNAME_N testdocs/sqlite3.c /^# define COLNAME_N /;" d file: +COLNAME_NAME testdocs/sqlite3.c /^#define COLNAME_NAME /;" d file: +COLNAME_TABLE testdocs/sqlite3.c /^#define COLNAME_TABLE /;" d file: +COLUMN_MASK testdocs/sqlite3.c /^#define COLUMN_MASK(/;" d file: +CORRUPT_DB testdocs/sqlite3.c /^#define CORRUPT_DB /;" d file: +CTIMEOPT_VAL testdocs/sqlite3.c /^#define CTIMEOPT_VAL(/;" d file: +CTIMEOPT_VAL_ testdocs/sqlite3.c /^#define CTIMEOPT_VAL_(/;" d file: +CTRL_FREE testdocs/sqlite3.c /^#define CTRL_FREE /;" d file: +CTRL_LOGSIZE testdocs/sqlite3.c /^#define CTRL_LOGSIZE /;" d file: +CURSOR_FAULT testdocs/sqlite3.c /^#define CURSOR_FAULT /;" d file: +CURSOR_INVALID testdocs/sqlite3.c /^#define CURSOR_INVALID /;" d file: +CURSOR_REQUIRESEEK testdocs/sqlite3.c /^#define CURSOR_REQUIRESEEK /;" d file: +CURSOR_SKIPNEXT testdocs/sqlite3.c /^#define CURSOR_SKIPNEXT /;" d file: +CURSOR_VALID testdocs/sqlite3.c /^#define CURSOR_VALID /;" d file: +CURTYPE_BTREE testdocs/sqlite3.c /^#define CURTYPE_BTREE /;" d file: +CURTYPE_PSEUDO testdocs/sqlite3.c /^#define CURTYPE_PSEUDO /;" d file: +CURTYPE_SORTER testdocs/sqlite3.c /^#define CURTYPE_SORTER /;" d file: +CURTYPE_VTAB testdocs/sqlite3.c /^#define CURTYPE_VTAB /;" d file: +CellArray testdocs/sqlite3.c /^struct CellArray {$/;" s file: +CellArray testdocs/sqlite3.c /^typedef struct CellArray CellArray;$/;" t typeref:struct:CellArray file: +CellInfo testdocs/sqlite3.c /^struct CellInfo {$/;" s file: +CellInfo testdocs/sqlite3.c /^typedef struct CellInfo CellInfo;$/;" t typeref:struct:CellInfo file: +CfgExpandTabs buf.c /^int CfgExpandTabs = true;$/;" v +CfgTabWidth buf.c /^int CfgTabWidth = 4;$/;" v +ChooseLeaf testdocs/sqlite3.c /^static int ChooseLeaf($/;" f file: +Cleanup testdocs/sqlite3.c /^static void Cleanup(Vdbe *p){$/;" f file: +CollSeq testdocs/sqlite3.c /^struct CollSeq {$/;" s file: +CollSeq testdocs/sqlite3.c /^typedef struct CollSeq CollSeq;$/;" t typeref:struct:CollSeq file: +Column testdocs/sqlite3.c /^struct Column {$/;" s file: +Column testdocs/sqlite3.c /^typedef struct Column Column;$/;" t typeref:struct:Column file: +ConstFactorOk testdocs/sqlite3.c /^#define ConstFactorOk(/;" d file: +CountCtx testdocs/sqlite3.c /^struct CountCtx {$/;" s file: +CountCtx testdocs/sqlite3.c /^typedef struct CountCtx CountCtx;$/;" t typeref:struct:CountCtx file: +CsrFlagClear testdocs/sqlite3.c /^#define CsrFlagClear(/;" d file: +CsrFlagSet testdocs/sqlite3.c /^#define CsrFlagSet(/;" d file: +CsrFlagTest testdocs/sqlite3.c /^#define CsrFlagTest(/;" d file: +Cte testdocs/sqlite3.c /^ struct Cte { \/* For each CTE in the WITH clause.... *\/$/;" s struct:With file: +Curr_File atf.h /^char* Curr_File = NULL;$/;" v +Curr_Line atf.h /^unsigned int Curr_Line = 0;$/;" v +Curr_Test atf.h /^char* Curr_Test = NULL;$/;" v +D testdocs/sqlite3.c /^ int Y, M, D; \/* Year, month, and day *\/$/;" m struct:DateTime file: +DB_Empty testdocs/sqlite3.c /^#define DB_Empty /;" d file: +DB_SchemaLoaded testdocs/sqlite3.c /^#define DB_SchemaLoaded /;" d file: +DB_UnresetViews testdocs/sqlite3.c /^#define DB_UnresetViews /;" d file: +DCOORD testdocs/sqlite3.c /^# define DCOORD(/;" d file: +DFUNCTION testdocs/sqlite3.c /^#define DFUNCTION(/;" d file: +DIRECT_MODE testdocs/sqlite3.c /^# define DIRECT_MODE /;" d file: +DOCID_CMP testdocs/sqlite3.c /^#define DOCID_CMP(/;" d file: +DOTLOCK_SUFFIX testdocs/sqlite3.c /^#define DOTLOCK_SUFFIX /;" d file: +DOWN edit.h /^ DOWN = +1$/;" e enum:__anon7 +DO_OS_MALLOC_TEST testdocs/sqlite3.c /^ #define DO_OS_MALLOC_TEST(/;" d file: +DateTime testdocs/sqlite3.c /^struct DateTime {$/;" s file: +DateTime testdocs/sqlite3.c /^typedef struct DateTime DateTime;$/;" t typeref:struct:DateTime file: +Db testdocs/sqlite3.c /^struct Db {$/;" s file: +Db testdocs/sqlite3.c /^typedef struct Db Db;$/;" t typeref:struct:Db file: +DbClearProperty testdocs/sqlite3.c /^#define DbClearProperty(/;" d file: +DbFixer testdocs/sqlite3.c /^struct DbFixer {$/;" s file: +DbFixer testdocs/sqlite3.c /^typedef struct DbFixer DbFixer;$/;" t typeref:struct:DbFixer file: +DbHasAnyProperty testdocs/sqlite3.c /^#define DbHasAnyProperty(/;" d file: +DbHasProperty testdocs/sqlite3.c /^#define DbHasProperty(/;" d file: +DbMaskAllZero testdocs/sqlite3.c /^# define DbMaskAllZero(/;" d file: +DbMaskNonZero testdocs/sqlite3.c /^# define DbMaskNonZero(/;" d file: +DbMaskSet testdocs/sqlite3.c /^# define DbMaskSet(/;" d file: +DbMaskTest testdocs/sqlite3.c /^# define DbMaskTest(/;" d file: +DbMaskZero testdocs/sqlite3.c /^# define DbMaskZero(/;" d file: +DbPage testdocs/sqlite3.c /^typedef struct PgHdr DbPage;$/;" t typeref:struct:PgHdr file: +DbSetProperty testdocs/sqlite3.c /^#define DbSetProperty(/;" d file: +Deephemeralize testdocs/sqlite3.c /^#define Deephemeralize(/;" d file: +DistinctCtx testdocs/sqlite3.c /^struct DistinctCtx {$/;" s file: +DistinctCtx testdocs/sqlite3.c /^typedef struct DistinctCtx DistinctCtx;$/;" t typeref:struct:DistinctCtx file: +EIGHT_BYTE_ALIGNMENT testdocs/sqlite3.c /^# define EIGHT_BYTE_ALIGNMENT(/;" d file: +ENC testdocs/sqlite3.c /^#define ENC(/;" d file: +EOPTARG stdc.h /^#define EOPTARG(/;" d +EP_Agg testdocs/sqlite3.c /^#define EP_Agg /;" d file: +EP_Alias testdocs/sqlite3.c /^#define EP_Alias /;" d file: +EP_CanBeNull testdocs/sqlite3.c /^#define EP_CanBeNull /;" d file: +EP_Collate testdocs/sqlite3.c /^#define EP_Collate /;" d file: +EP_ConstFunc testdocs/sqlite3.c /^#define EP_ConstFunc /;" d file: +EP_DblQuoted testdocs/sqlite3.c /^#define EP_DblQuoted /;" d file: +EP_Distinct testdocs/sqlite3.c /^#define EP_Distinct /;" d file: +EP_Error testdocs/sqlite3.c /^#define EP_Error /;" d file: +EP_FromJoin testdocs/sqlite3.c /^#define EP_FromJoin /;" d file: +EP_Generic testdocs/sqlite3.c /^#define EP_Generic /;" d file: +EP_InfixFunc testdocs/sqlite3.c /^#define EP_InfixFunc /;" d file: +EP_IntValue testdocs/sqlite3.c /^#define EP_IntValue /;" d file: +EP_Leaf testdocs/sqlite3.c /^#define EP_Leaf /;" d file: +EP_MemToken testdocs/sqlite3.c /^#define EP_MemToken /;" d file: +EP_NoReduce testdocs/sqlite3.c /^#define EP_NoReduce /;" d file: +EP_Propagate testdocs/sqlite3.c /^#define EP_Propagate /;" d file: +EP_Reduced testdocs/sqlite3.c /^#define EP_Reduced /;" d file: +EP_Resolved testdocs/sqlite3.c /^#define EP_Resolved /;" d file: +EP_Skip testdocs/sqlite3.c /^#define EP_Skip /;" d file: +EP_Static testdocs/sqlite3.c /^#define EP_Static /;" d file: +EP_Subquery testdocs/sqlite3.c /^#define EP_Subquery /;" d file: +EP_TokenOnly testdocs/sqlite3.c /^#define EP_TokenOnly /;" d file: +EP_Unlikely testdocs/sqlite3.c /^#define EP_Unlikely /;" d file: +EP_VarSelect testdocs/sqlite3.c /^#define EP_VarSelect /;" d file: +EP_xIsSelect testdocs/sqlite3.c /^#define EP_xIsSelect /;" d file: +EXCLUSIVE_LOCK testdocs/sqlite3.c /^#define EXCLUSIVE_LOCK /;" d file: +EXPRDUP_REDUCE testdocs/sqlite3.c /^#define EXPRDUP_REDUCE /;" d file: +EXPR_FULLSIZE testdocs/sqlite3.c /^#define EXPR_FULLSIZE /;" d file: +EXPR_REDUCEDSIZE testdocs/sqlite3.c /^#define EXPR_REDUCEDSIZE /;" d file: +EXPR_TOKENONLYSIZE testdocs/sqlite3.c /^#define EXPR_TOKENONLYSIZE /;" d file: +EntropyGatherer testdocs/sqlite3.c /^struct EntropyGatherer {$/;" s file: +EntropyGatherer testdocs/sqlite3.c /^typedef struct EntropyGatherer EntropyGatherer;$/;" t typeref:struct:EntropyGatherer file: +ExpandBlob testdocs/sqlite3.c /^ #define ExpandBlob(/;" d file: +Expr testdocs/sqlite3.c /^struct Expr {$/;" s file: +Expr testdocs/sqlite3.c /^typedef struct Expr Expr;$/;" t typeref:struct:Expr file: +ExprClearProperty testdocs/sqlite3.c /^#define ExprClearProperty(/;" d file: +ExprHasAllProperty testdocs/sqlite3.c /^#define ExprHasAllProperty(/;" d file: +ExprHasProperty testdocs/sqlite3.c /^#define ExprHasProperty(/;" d file: +ExprList testdocs/sqlite3.c /^struct ExprList {$/;" s file: +ExprList testdocs/sqlite3.c /^typedef struct ExprList ExprList;$/;" t typeref:struct:ExprList file: +ExprList_item testdocs/sqlite3.c /^ struct ExprList_item { \/* For each expression in the list *\/$/;" s struct:ExprList file: +ExprSetProperty testdocs/sqlite3.c /^#define ExprSetProperty(/;" d file: +ExprSetVVAProperty testdocs/sqlite3.c /^# define ExprSetVVAProperty(/;" d file: +ExprSpan testdocs/sqlite3.c /^struct ExprSpan {$/;" s file: +ExprSpan testdocs/sqlite3.c /^typedef struct ExprSpan ExprSpan;$/;" t typeref:struct:ExprSpan file: +FILEHANDLEID testdocs/sqlite3.c /^#define FILEHANDLEID(/;" d file: +FILE_ATTRIBUTE_MASK testdocs/sqlite3.c /^# define FILE_ATTRIBUTE_MASK /;" d file: +FILE_FLAG_MASK testdocs/sqlite3.c /^# define FILE_FLAG_MASK /;" d file: +FKey testdocs/sqlite3.c /^struct FKey {$/;" s file: +FKey testdocs/sqlite3.c /^typedef struct FKey FKey;$/;" t typeref:struct:FKey file: +FLAG_SIGNED testdocs/sqlite3.c /^#define FLAG_SIGNED /;" d file: +FLAG_STRING testdocs/sqlite3.c /^#define FLAG_STRING /;" d file: +FMap edit.h /^} FMap;$/;" t typeref:struct:__anon1 +FOREGUARD testdocs/sqlite3.c /^#define FOREGUARD /;" d file: +FOUR_BYTE_INT testdocs/sqlite3.c /^#define FOUR_BYTE_INT(/;" d file: +FOUR_BYTE_UINT testdocs/sqlite3.c /^#define FOUR_BYTE_UINT(/;" d file: +FTS3_AUX_SCHEMA testdocs/sqlite3.c /^#define FTS3_AUX_SCHEMA /;" d file: +FTS3_DOCID_SEARCH testdocs/sqlite3.c /^#define FTS3_DOCID_SEARCH /;" d file: +FTS3_EVAL_FILTER testdocs/sqlite3.c /^#define FTS3_EVAL_FILTER /;" d file: +FTS3_EVAL_MATCHINFO testdocs/sqlite3.c /^#define FTS3_EVAL_MATCHINFO /;" d file: +FTS3_EVAL_NEXT testdocs/sqlite3.c /^#define FTS3_EVAL_NEXT /;" d file: +FTS3_FULLSCAN_SEARCH testdocs/sqlite3.c /^#define FTS3_FULLSCAN_SEARCH /;" d file: +FTS3_FULLTEXT_SEARCH testdocs/sqlite3.c /^#define FTS3_FULLTEXT_SEARCH /;" d file: +FTS3_HASH_BINARY testdocs/sqlite3.c /^#define FTS3_HASH_BINARY /;" d file: +FTS3_HASH_STRING testdocs/sqlite3.c /^#define FTS3_HASH_STRING /;" d file: +FTS3_HAVE_DOCID_GE testdocs/sqlite3.c /^#define FTS3_HAVE_DOCID_GE /;" d file: +FTS3_HAVE_DOCID_LE testdocs/sqlite3.c /^#define FTS3_HAVE_DOCID_LE /;" d file: +FTS3_HAVE_LANGID testdocs/sqlite3.c /^#define FTS3_HAVE_LANGID /;" d file: +FTS3_MATCHINFO_AVGLENGTH testdocs/sqlite3.c /^#define FTS3_MATCHINFO_AVGLENGTH /;" d file: +FTS3_MATCHINFO_DEFAULT testdocs/sqlite3.c /^#define FTS3_MATCHINFO_DEFAULT /;" d file: +FTS3_MATCHINFO_HITS testdocs/sqlite3.c /^#define FTS3_MATCHINFO_HITS /;" d file: +FTS3_MATCHINFO_LCS testdocs/sqlite3.c /^#define FTS3_MATCHINFO_LCS /;" d file: +FTS3_MATCHINFO_LENGTH testdocs/sqlite3.c /^#define FTS3_MATCHINFO_LENGTH /;" d file: +FTS3_MATCHINFO_LHITS testdocs/sqlite3.c /^#define FTS3_MATCHINFO_LHITS /;" d file: +FTS3_MATCHINFO_LHITS_BM testdocs/sqlite3.c /^#define FTS3_MATCHINFO_LHITS_BM /;" d file: +FTS3_MATCHINFO_NCOL testdocs/sqlite3.c /^#define FTS3_MATCHINFO_NCOL /;" d file: +FTS3_MATCHINFO_NDOC testdocs/sqlite3.c /^#define FTS3_MATCHINFO_NDOC /;" d file: +FTS3_MATCHINFO_NPHRASE testdocs/sqlite3.c /^#define FTS3_MATCHINFO_NPHRASE /;" d file: +FTS3_MAX_PENDING_DATA testdocs/sqlite3.c /^#define FTS3_MAX_PENDING_DATA /;" d file: +FTS3_MERGE_COUNT testdocs/sqlite3.c /^#define FTS3_MERGE_COUNT /;" d file: +FTS3_NODE_CHUNKSIZE testdocs/sqlite3.c /^# define FTS3_NODE_CHUNKSIZE /;" d file: +FTS3_NODE_CHUNK_THRESHOLD testdocs/sqlite3.c /^# define FTS3_NODE_CHUNK_THRESHOLD /;" d file: +FTS3_NODE_PADDING testdocs/sqlite3.c /^#define FTS3_NODE_PADDING /;" d file: +FTS3_SEGCURSOR_ALL testdocs/sqlite3.c /^#define FTS3_SEGCURSOR_ALL /;" d file: +FTS3_SEGCURSOR_PENDING testdocs/sqlite3.c /^#define FTS3_SEGCURSOR_PENDING /;" d file: +FTS3_SEGDIR_MAXLEVEL testdocs/sqlite3.c /^#define FTS3_SEGDIR_MAXLEVEL /;" d file: +FTS3_SEGDIR_MAXLEVEL_STR testdocs/sqlite3.c /^#define FTS3_SEGDIR_MAXLEVEL_STR /;" d file: +FTS3_SEGMENT_COLUMN_FILTER testdocs/sqlite3.c /^#define FTS3_SEGMENT_COLUMN_FILTER /;" d file: +FTS3_SEGMENT_FIRST testdocs/sqlite3.c /^#define FTS3_SEGMENT_FIRST /;" d file: +FTS3_SEGMENT_IGNORE_EMPTY testdocs/sqlite3.c /^#define FTS3_SEGMENT_IGNORE_EMPTY /;" d file: +FTS3_SEGMENT_PREFIX testdocs/sqlite3.c /^#define FTS3_SEGMENT_PREFIX /;" d file: +FTS3_SEGMENT_REQUIRE_POS testdocs/sqlite3.c /^#define FTS3_SEGMENT_REQUIRE_POS /;" d file: +FTS3_SEGMENT_SCAN testdocs/sqlite3.c /^#define FTS3_SEGMENT_SCAN /;" d file: +FTS3_TOK_SCHEMA testdocs/sqlite3.c /^#define FTS3_TOK_SCHEMA /;" d file: +FTS3_VARINT_MAX testdocs/sqlite3.c /^#define FTS3_VARINT_MAX /;" d file: +FTS4AUX_EQ_CONSTRAINT testdocs/sqlite3.c /^#define FTS4AUX_EQ_CONSTRAINT /;" d file: +FTS4AUX_GE_CONSTRAINT testdocs/sqlite3.c /^#define FTS4AUX_GE_CONSTRAINT /;" d file: +FTS4AUX_LE_CONSTRAINT testdocs/sqlite3.c /^#define FTS4AUX_LE_CONSTRAINT /;" d file: +FTS5CSR_EOF testdocs/sqlite3.c /^#define FTS5CSR_EOF /;" d file: +FTS5CSR_FREE_ZRANK testdocs/sqlite3.c /^#define FTS5CSR_FREE_ZRANK /;" d file: +FTS5CSR_REQUIRE_CONTENT testdocs/sqlite3.c /^#define FTS5CSR_REQUIRE_CONTENT /;" d file: +FTS5CSR_REQUIRE_DOCSIZE testdocs/sqlite3.c /^#define FTS5CSR_REQUIRE_DOCSIZE /;" d file: +FTS5CSR_REQUIRE_INST testdocs/sqlite3.c /^#define FTS5CSR_REQUIRE_INST /;" d file: +FTS5CSR_REQUIRE_POSLIST testdocs/sqlite3.c /^#define FTS5CSR_REQUIRE_POSLIST /;" d file: +FTS5CSR_REQUIRE_RESEEK testdocs/sqlite3.c /^#define FTS5CSR_REQUIRE_RESEEK /;" d file: +FTS5INDEX_QUERY_DESC testdocs/sqlite3.c /^#define FTS5INDEX_QUERY_DESC /;" d file: +FTS5INDEX_QUERY_NOOUTPUT testdocs/sqlite3.c /^#define FTS5INDEX_QUERY_NOOUTPUT /;" d file: +FTS5INDEX_QUERY_PREFIX testdocs/sqlite3.c /^#define FTS5INDEX_QUERY_PREFIX /;" d file: +FTS5INDEX_QUERY_SCAN testdocs/sqlite3.c /^#define FTS5INDEX_QUERY_SCAN /;" d file: +FTS5INDEX_QUERY_SKIPEMPTY testdocs/sqlite3.c /^#define FTS5INDEX_QUERY_SKIPEMPTY /;" d file: +FTS5INDEX_QUERY_TEST_NOIDX testdocs/sqlite3.c /^#define FTS5INDEX_QUERY_TEST_NOIDX /;" d file: +FTS5TOKEN testdocs/sqlite3.c /^#define FTS5TOKEN /;" d file: +FTS5_AND testdocs/sqlite3.c /^#define FTS5_AND /;" d file: +FTS5_AVERAGES_ROWID testdocs/sqlite3.c /^#define FTS5_AVERAGES_ROWID /;" d file: +FTS5_BEGIN testdocs/sqlite3.c /^#define FTS5_BEGIN /;" d file: +FTS5_BI_MATCH testdocs/sqlite3.c /^#define FTS5_BI_MATCH /;" d file: +FTS5_BI_ORDER_DESC testdocs/sqlite3.c /^#define FTS5_BI_ORDER_DESC /;" d file: +FTS5_BI_ORDER_RANK testdocs/sqlite3.c /^#define FTS5_BI_ORDER_RANK /;" d file: +FTS5_BI_ORDER_ROWID testdocs/sqlite3.c /^#define FTS5_BI_ORDER_ROWID /;" d file: +FTS5_BI_RANK testdocs/sqlite3.c /^#define FTS5_BI_RANK /;" d file: +FTS5_BI_ROWID_EQ testdocs/sqlite3.c /^#define FTS5_BI_ROWID_EQ /;" d file: +FTS5_BI_ROWID_GE testdocs/sqlite3.c /^#define FTS5_BI_ROWID_GE /;" d file: +FTS5_BI_ROWID_LE testdocs/sqlite3.c /^#define FTS5_BI_ROWID_LE /;" d file: +FTS5_COLON testdocs/sqlite3.c /^#define FTS5_COLON /;" d file: +FTS5_COMMA testdocs/sqlite3.c /^#define FTS5_COMMA /;" d file: +FTS5_COMMIT testdocs/sqlite3.c /^#define FTS5_COMMIT /;" d file: +FTS5_CONTENT_EXTERNAL testdocs/sqlite3.c /^#define FTS5_CONTENT_EXTERNAL /;" d file: +FTS5_CONTENT_NONE testdocs/sqlite3.c /^#define FTS5_CONTENT_NONE /;" d file: +FTS5_CONTENT_NORMAL testdocs/sqlite3.c /^#define FTS5_CONTENT_NORMAL /;" d file: +FTS5_CORRUPT testdocs/sqlite3.c /^# define FTS5_CORRUPT /;" d file: +FTS5_CURRENT_VERSION testdocs/sqlite3.c /^#define FTS5_CURRENT_VERSION /;" d file: +FTS5_DATA_DLI_B testdocs/sqlite3.c /^#define FTS5_DATA_DLI_B /;" d file: +FTS5_DATA_HEIGHT_B testdocs/sqlite3.c /^#define FTS5_DATA_HEIGHT_B /;" d file: +FTS5_DATA_ID_B testdocs/sqlite3.c /^#define FTS5_DATA_ID_B /;" d file: +FTS5_DATA_PADDING testdocs/sqlite3.c /^#define FTS5_DATA_PADDING /;" d file: +FTS5_DATA_PAGE_B testdocs/sqlite3.c /^#define FTS5_DATA_PAGE_B /;" d file: +FTS5_DATA_ZERO_PADDING testdocs/sqlite3.c /^#define FTS5_DATA_ZERO_PADDING /;" d file: +FTS5_DEFAULT_AUTOMERGE testdocs/sqlite3.c /^#define FTS5_DEFAULT_AUTOMERGE /;" d file: +FTS5_DEFAULT_CRISISMERGE testdocs/sqlite3.c /^#define FTS5_DEFAULT_CRISISMERGE /;" d file: +FTS5_DEFAULT_HASHSIZE testdocs/sqlite3.c /^#define FTS5_DEFAULT_HASHSIZE /;" d file: +FTS5_DEFAULT_NEARDIST testdocs/sqlite3.c /^#define FTS5_DEFAULT_NEARDIST /;" d file: +FTS5_DEFAULT_PAGE_SIZE testdocs/sqlite3.c /^#define FTS5_DEFAULT_PAGE_SIZE /;" d file: +FTS5_DEFAULT_RANK testdocs/sqlite3.c /^#define FTS5_DEFAULT_RANK /;" d file: +FTS5_DEFAULT_USERMERGE testdocs/sqlite3.c /^#define FTS5_DEFAULT_USERMERGE /;" d file: +FTS5_DETAIL_COLUMNS testdocs/sqlite3.c /^#define FTS5_DETAIL_COLUMNS /;" d file: +FTS5_DETAIL_FULL testdocs/sqlite3.c /^#define FTS5_DETAIL_FULL /;" d file: +FTS5_DETAIL_NONE testdocs/sqlite3.c /^#define FTS5_DETAIL_NONE /;" d file: +FTS5_DLIDX_ROWID testdocs/sqlite3.c /^#define FTS5_DLIDX_ROWID(/;" d file: +FTS5_EOF testdocs/sqlite3.c /^#define FTS5_EOF /;" d file: +FTS5_LARGEST_INT64 testdocs/sqlite3.c /^#define FTS5_LARGEST_INT64 /;" d file: +FTS5_LCP testdocs/sqlite3.c /^#define FTS5_LCP /;" d file: +FTS5_LOOKAHEAD_EOF testdocs/sqlite3.c /^#define FTS5_LOOKAHEAD_EOF /;" d file: +FTS5_LP testdocs/sqlite3.c /^#define FTS5_LP /;" d file: +FTS5_MAIN_PREFIX testdocs/sqlite3.c /^#define FTS5_MAIN_PREFIX /;" d file: +FTS5_MAX_PAGE_SIZE testdocs/sqlite3.c /^#define FTS5_MAX_PAGE_SIZE /;" d file: +FTS5_MAX_PREFIX_INDEXES testdocs/sqlite3.c /^#define FTS5_MAX_PREFIX_INDEXES /;" d file: +FTS5_MAX_SEGMENT testdocs/sqlite3.c /^#define FTS5_MAX_SEGMENT /;" d file: +FTS5_MAX_TOKEN_SIZE testdocs/sqlite3.c /^#define FTS5_MAX_TOKEN_SIZE /;" d file: +FTS5_MINUS testdocs/sqlite3.c /^#define FTS5_MINUS /;" d file: +FTS5_MIN_DLIDX_SIZE testdocs/sqlite3.c /^#define FTS5_MIN_DLIDX_SIZE /;" d file: +FTS5_NOINLINE testdocs/sqlite3.c /^# define FTS5_NOINLINE /;" d file: +FTS5_NOINLINE testdocs/sqlite3.c /^# define FTS5_NOINLINE$/;" d file: +FTS5_NOT testdocs/sqlite3.c /^#define FTS5_NOT /;" d file: +FTS5_OPT_WORK_UNIT testdocs/sqlite3.c /^#define FTS5_OPT_WORK_UNIT /;" d file: +FTS5_OR testdocs/sqlite3.c /^#define FTS5_OR /;" d file: +FTS5_PLAN_MATCH testdocs/sqlite3.c /^#define FTS5_PLAN_MATCH /;" d file: +FTS5_PLAN_ROWID testdocs/sqlite3.c /^#define FTS5_PLAN_ROWID /;" d file: +FTS5_PLAN_SCAN testdocs/sqlite3.c /^#define FTS5_PLAN_SCAN /;" d file: +FTS5_PLAN_SORTED_MATCH testdocs/sqlite3.c /^#define FTS5_PLAN_SORTED_MATCH /;" d file: +FTS5_PLAN_SOURCE testdocs/sqlite3.c /^#define FTS5_PLAN_SOURCE /;" d file: +FTS5_PLAN_SPECIAL testdocs/sqlite3.c /^#define FTS5_PLAN_SPECIAL /;" d file: +FTS5_PLUS testdocs/sqlite3.c /^#define FTS5_PLUS /;" d file: +FTS5_PORTER_MAX_TOKEN testdocs/sqlite3.c /^#define FTS5_PORTER_MAX_TOKEN /;" d file: +FTS5_POS2COLUMN testdocs/sqlite3.c /^#define FTS5_POS2COLUMN(/;" d file: +FTS5_POS2OFFSET testdocs/sqlite3.c /^#define FTS5_POS2OFFSET(/;" d file: +FTS5_RANK_NAME testdocs/sqlite3.c /^#define FTS5_RANK_NAME /;" d file: +FTS5_RCP testdocs/sqlite3.c /^#define FTS5_RCP /;" d file: +FTS5_RELEASE testdocs/sqlite3.c /^#define FTS5_RELEASE /;" d file: +FTS5_ROLLBACK testdocs/sqlite3.c /^#define FTS5_ROLLBACK /;" d file: +FTS5_ROLLBACKTO testdocs/sqlite3.c /^#define FTS5_ROLLBACKTO /;" d file: +FTS5_ROWID_NAME testdocs/sqlite3.c /^#define FTS5_ROWID_NAME /;" d file: +FTS5_RP testdocs/sqlite3.c /^#define FTS5_RP /;" d file: +FTS5_SAVEPOINT testdocs/sqlite3.c /^#define FTS5_SAVEPOINT /;" d file: +FTS5_SEGITER_ONETERM testdocs/sqlite3.c /^#define FTS5_SEGITER_ONETERM /;" d file: +FTS5_SEGITER_REVERSE testdocs/sqlite3.c /^#define FTS5_SEGITER_REVERSE /;" d file: +FTS5_SEGMENT_ROWID testdocs/sqlite3.c /^#define FTS5_SEGMENT_ROWID(/;" d file: +FTS5_STAR testdocs/sqlite3.c /^#define FTS5_STAR /;" d file: +FTS5_STMT_DELETE_CONTENT testdocs/sqlite3.c /^#define FTS5_STMT_DELETE_CONTENT /;" d file: +FTS5_STMT_DELETE_DOCSIZE testdocs/sqlite3.c /^#define FTS5_STMT_DELETE_DOCSIZE /;" d file: +FTS5_STMT_INSERT_CONTENT testdocs/sqlite3.c /^#define FTS5_STMT_INSERT_CONTENT /;" d file: +FTS5_STMT_LOOKUP testdocs/sqlite3.c /^#define FTS5_STMT_LOOKUP /;" d file: +FTS5_STMT_LOOKUP_DOCSIZE testdocs/sqlite3.c /^#define FTS5_STMT_LOOKUP_DOCSIZE /;" d file: +FTS5_STMT_REPLACE_CONFIG testdocs/sqlite3.c /^#define FTS5_STMT_REPLACE_CONFIG /;" d file: +FTS5_STMT_REPLACE_CONTENT testdocs/sqlite3.c /^#define FTS5_STMT_REPLACE_CONTENT /;" d file: +FTS5_STMT_REPLACE_DOCSIZE testdocs/sqlite3.c /^#define FTS5_STMT_REPLACE_DOCSIZE /;" d file: +FTS5_STMT_SCAN testdocs/sqlite3.c /^#define FTS5_STMT_SCAN /;" d file: +FTS5_STMT_SCAN_ASC testdocs/sqlite3.c /^#define FTS5_STMT_SCAN_ASC /;" d file: +FTS5_STMT_SCAN_DESC testdocs/sqlite3.c /^#define FTS5_STMT_SCAN_DESC /;" d file: +FTS5_STRING testdocs/sqlite3.c /^#define FTS5_STRING /;" d file: +FTS5_STRUCTURE_ROWID testdocs/sqlite3.c /^#define FTS5_STRUCTURE_ROWID /;" d file: +FTS5_SYNC testdocs/sqlite3.c /^#define FTS5_SYNC /;" d file: +FTS5_TERM testdocs/sqlite3.c /^#define FTS5_TERM /;" d file: +FTS5_TOKENIZE_AUX testdocs/sqlite3.c /^#define FTS5_TOKENIZE_AUX /;" d file: +FTS5_TOKENIZE_DOCUMENT testdocs/sqlite3.c /^#define FTS5_TOKENIZE_DOCUMENT /;" d file: +FTS5_TOKENIZE_PREFIX testdocs/sqlite3.c /^#define FTS5_TOKENIZE_PREFIX /;" d file: +FTS5_TOKENIZE_QUERY testdocs/sqlite3.c /^#define FTS5_TOKENIZE_QUERY /;" d file: +FTS5_TOKEN_COLOCATED testdocs/sqlite3.c /^#define FTS5_TOKEN_COLOCATED /;" d file: +FTS5_VOCAB_COL testdocs/sqlite3.c /^#define FTS5_VOCAB_COL /;" d file: +FTS5_VOCAB_COL_SCHEMA testdocs/sqlite3.c /^#define FTS5_VOCAB_COL_SCHEMA /;" d file: +FTS5_VOCAB_ROW testdocs/sqlite3.c /^#define FTS5_VOCAB_ROW /;" d file: +FTS5_VOCAB_ROW_SCHEMA testdocs/sqlite3.c /^#define FTS5_VOCAB_ROW_SCHEMA /;" d file: +FTS5_VOCAB_TERM_EQ testdocs/sqlite3.c /^#define FTS5_VOCAB_TERM_EQ /;" d file: +FTS5_VOCAB_TERM_GE testdocs/sqlite3.c /^#define FTS5_VOCAB_TERM_GE /;" d file: +FTS5_VOCAB_TERM_LE testdocs/sqlite3.c /^#define FTS5_VOCAB_TERM_LE /;" d file: +FTS5_WORK_UNIT testdocs/sqlite3.c /^#define FTS5_WORK_UNIT /;" d file: +FTSQUERY_AND testdocs/sqlite3.c /^#define FTSQUERY_AND /;" d file: +FTSQUERY_NEAR testdocs/sqlite3.c /^#define FTSQUERY_NEAR /;" d file: +FTSQUERY_NOT testdocs/sqlite3.c /^#define FTSQUERY_NOT /;" d file: +FTSQUERY_OR testdocs/sqlite3.c /^#define FTSQUERY_OR /;" d file: +FTSQUERY_PHRASE testdocs/sqlite3.c /^#define FTSQUERY_PHRASE /;" d file: +FTS_CORRUPT_VTAB testdocs/sqlite3.c /^# define FTS_CORRUPT_VTAB /;" d file: +FTS_MAX_APPENDABLE_HEIGHT testdocs/sqlite3.c /^#define FTS_MAX_APPENDABLE_HEIGHT /;" d file: +FTS_STAT_AUTOINCRMERGE testdocs/sqlite3.c /^#define FTS_STAT_AUTOINCRMERGE /;" d file: +FTS_STAT_DOCTOTAL testdocs/sqlite3.c /^#define FTS_STAT_DOCTOTAL /;" d file: +FTS_STAT_INCRMERGEHINT testdocs/sqlite3.c /^#define FTS_STAT_INCRMERGEHINT /;" d file: +FULLY_WITHIN testdocs/sqlite3.c /^#define FULLY_WITHIN /;" d file: +FUNCTION testdocs/sqlite3.c /^#define FUNCTION(/;" d file: +FUNCTION2 testdocs/sqlite3.c /^#define FUNCTION2(/;" d file: +FUNC_PERFECT_MATCH testdocs/sqlite3.c /^#define FUNC_PERFECT_MATCH /;" d file: +Failed atf.h /^static unsigned int Failed = 0;$/;" v +FileChunk testdocs/sqlite3.c /^struct FileChunk {$/;" s file: +FileChunk testdocs/sqlite3.c /^typedef struct FileChunk FileChunk;$/;" t typeref:struct:FileChunk file: +FilePoint testdocs/sqlite3.c /^struct FilePoint {$/;" s file: +FilePoint testdocs/sqlite3.c /^typedef struct FilePoint FilePoint;$/;" t typeref:struct:FilePoint file: +Fts3Cursor testdocs/sqlite3.c /^struct Fts3Cursor {$/;" s file: +Fts3Cursor testdocs/sqlite3.c /^typedef struct Fts3Cursor Fts3Cursor;$/;" t typeref:struct:Fts3Cursor file: +Fts3DeferredToken testdocs/sqlite3.c /^struct Fts3DeferredToken {$/;" s file: +Fts3DeferredToken testdocs/sqlite3.c /^typedef struct Fts3DeferredToken Fts3DeferredToken;$/;" t typeref:struct:Fts3DeferredToken file: +Fts3Doclist testdocs/sqlite3.c /^struct Fts3Doclist {$/;" s file: +Fts3Doclist testdocs/sqlite3.c /^typedef struct Fts3Doclist Fts3Doclist;$/;" t typeref:struct:Fts3Doclist file: +Fts3Expr testdocs/sqlite3.c /^struct Fts3Expr {$/;" s file: +Fts3Expr testdocs/sqlite3.c /^typedef struct Fts3Expr Fts3Expr;$/;" t typeref:struct:Fts3Expr file: +Fts3Hash testdocs/sqlite3.c /^struct Fts3Hash {$/;" s file: +Fts3Hash testdocs/sqlite3.c /^typedef struct Fts3Hash Fts3Hash;$/;" t typeref:struct:Fts3Hash file: +Fts3HashElem testdocs/sqlite3.c /^struct Fts3HashElem {$/;" s file: +Fts3HashElem testdocs/sqlite3.c /^typedef struct Fts3HashElem Fts3HashElem;$/;" t typeref:struct:Fts3HashElem file: +Fts3Index testdocs/sqlite3.c /^ struct Fts3Index {$/;" s struct:Fts3Table file: +Fts3MultiSegReader testdocs/sqlite3.c /^struct Fts3MultiSegReader {$/;" s file: +Fts3MultiSegReader testdocs/sqlite3.c /^typedef struct Fts3MultiSegReader Fts3MultiSegReader;$/;" t typeref:struct:Fts3MultiSegReader file: +Fts3Phrase testdocs/sqlite3.c /^struct Fts3Phrase {$/;" s file: +Fts3Phrase testdocs/sqlite3.c /^typedef struct Fts3Phrase Fts3Phrase;$/;" t typeref:struct:Fts3Phrase file: +Fts3PhraseToken testdocs/sqlite3.c /^struct Fts3PhraseToken {$/;" s file: +Fts3PhraseToken testdocs/sqlite3.c /^typedef struct Fts3PhraseToken Fts3PhraseToken;$/;" t typeref:struct:Fts3PhraseToken file: +Fts3SegFilter testdocs/sqlite3.c /^struct Fts3SegFilter {$/;" s file: +Fts3SegFilter testdocs/sqlite3.c /^typedef struct Fts3SegFilter Fts3SegFilter;$/;" t typeref:struct:Fts3SegFilter file: +Fts3SegReader testdocs/sqlite3.c /^struct Fts3SegReader {$/;" s file: +Fts3SegReader testdocs/sqlite3.c /^typedef struct Fts3SegReader Fts3SegReader;$/;" t typeref:struct:Fts3SegReader file: +Fts3Table testdocs/sqlite3.c /^struct Fts3Table {$/;" s file: +Fts3Table testdocs/sqlite3.c /^typedef struct Fts3Table Fts3Table;$/;" t typeref:struct:Fts3Table file: +Fts3TokenAndCost testdocs/sqlite3.c /^struct Fts3TokenAndCost {$/;" s file: +Fts3TokenAndCost testdocs/sqlite3.c /^typedef struct Fts3TokenAndCost Fts3TokenAndCost;$/;" t typeref:struct:Fts3TokenAndCost file: +Fts3auxColstats testdocs/sqlite3.c /^ struct Fts3auxColstats {$/;" s struct:Fts3auxCursor file: +Fts3auxCursor testdocs/sqlite3.c /^struct Fts3auxCursor {$/;" s file: +Fts3auxCursor testdocs/sqlite3.c /^typedef struct Fts3auxCursor Fts3auxCursor;$/;" t typeref:struct:Fts3auxCursor file: +Fts3auxTable testdocs/sqlite3.c /^struct Fts3auxTable {$/;" s file: +Fts3auxTable testdocs/sqlite3.c /^typedef struct Fts3auxTable Fts3auxTable;$/;" t typeref:struct:Fts3auxTable file: +Fts3tokCursor testdocs/sqlite3.c /^struct Fts3tokCursor {$/;" s file: +Fts3tokCursor testdocs/sqlite3.c /^typedef struct Fts3tokCursor Fts3tokCursor;$/;" t typeref:struct:Fts3tokCursor file: +Fts3tokTable testdocs/sqlite3.c /^struct Fts3tokTable {$/;" s file: +Fts3tokTable testdocs/sqlite3.c /^typedef struct Fts3tokTable Fts3tokTable;$/;" t typeref:struct:Fts3tokTable file: +Fts5Auxdata testdocs/sqlite3.c /^struct Fts5Auxdata {$/;" s file: +Fts5Auxdata testdocs/sqlite3.c /^typedef struct Fts5Auxdata Fts5Auxdata;$/;" t typeref:struct:Fts5Auxdata file: +Fts5Auxiliary testdocs/sqlite3.c /^struct Fts5Auxiliary {$/;" s file: +Fts5Auxiliary testdocs/sqlite3.c /^typedef struct Fts5Auxiliary Fts5Auxiliary;$/;" t typeref:struct:Fts5Auxiliary file: +Fts5Bm25Data testdocs/sqlite3.c /^struct Fts5Bm25Data {$/;" s file: +Fts5Bm25Data testdocs/sqlite3.c /^typedef struct Fts5Bm25Data Fts5Bm25Data;$/;" t typeref:struct:Fts5Bm25Data file: +Fts5Buffer testdocs/sqlite3.c /^struct Fts5Buffer {$/;" s file: +Fts5Buffer testdocs/sqlite3.c /^typedef struct Fts5Buffer Fts5Buffer;$/;" t typeref:struct:Fts5Buffer file: +Fts5CResult testdocs/sqlite3.c /^struct Fts5CResult {$/;" s file: +Fts5CResult testdocs/sqlite3.c /^typedef struct Fts5CResult Fts5CResult;$/;" t typeref:struct:Fts5CResult file: +Fts5Colset testdocs/sqlite3.c /^struct Fts5Colset {$/;" s file: +Fts5Colset testdocs/sqlite3.c /^typedef struct Fts5Colset Fts5Colset;$/;" t typeref:struct:Fts5Colset file: +Fts5Config testdocs/sqlite3.c /^struct Fts5Config {$/;" s file: +Fts5Config testdocs/sqlite3.c /^typedef struct Fts5Config Fts5Config;$/;" t typeref:struct:Fts5Config file: +Fts5Context testdocs/sqlite3.c /^typedef struct Fts5Context Fts5Context;$/;" t typeref:struct:Fts5Context file: +Fts5Cursor testdocs/sqlite3.c /^struct Fts5Cursor {$/;" s file: +Fts5Cursor testdocs/sqlite3.c /^typedef struct Fts5Cursor Fts5Cursor;$/;" t typeref:struct:Fts5Cursor file: +Fts5Data testdocs/sqlite3.c /^struct Fts5Data {$/;" s file: +Fts5Data testdocs/sqlite3.c /^typedef struct Fts5Data Fts5Data;$/;" t typeref:struct:Fts5Data file: +Fts5DlidxIter testdocs/sqlite3.c /^struct Fts5DlidxIter {$/;" s file: +Fts5DlidxIter testdocs/sqlite3.c /^typedef struct Fts5DlidxIter Fts5DlidxIter;$/;" t typeref:struct:Fts5DlidxIter file: +Fts5DlidxLvl testdocs/sqlite3.c /^struct Fts5DlidxLvl {$/;" s file: +Fts5DlidxLvl testdocs/sqlite3.c /^typedef struct Fts5DlidxLvl Fts5DlidxLvl;$/;" t typeref:struct:Fts5DlidxLvl file: +Fts5DlidxWriter testdocs/sqlite3.c /^struct Fts5DlidxWriter {$/;" s file: +Fts5DlidxWriter testdocs/sqlite3.c /^typedef struct Fts5DlidxWriter Fts5DlidxWriter;$/;" t typeref:struct:Fts5DlidxWriter file: +Fts5DoclistIter testdocs/sqlite3.c /^struct Fts5DoclistIter {$/;" s file: +Fts5DoclistIter testdocs/sqlite3.c /^typedef struct Fts5DoclistIter Fts5DoclistIter;$/;" t typeref:struct:Fts5DoclistIter file: +Fts5Enum testdocs/sqlite3.c /^struct Fts5Enum {$/;" s file: +Fts5Enum testdocs/sqlite3.c /^typedef struct Fts5Enum Fts5Enum;$/;" t typeref:struct:Fts5Enum file: +Fts5Expr testdocs/sqlite3.c /^struct Fts5Expr {$/;" s file: +Fts5Expr testdocs/sqlite3.c /^typedef struct Fts5Expr Fts5Expr;$/;" t typeref:struct:Fts5Expr file: +Fts5ExprCtx testdocs/sqlite3.c /^struct Fts5ExprCtx {$/;" s file: +Fts5ExprCtx testdocs/sqlite3.c /^typedef struct Fts5ExprCtx Fts5ExprCtx;$/;" t typeref:struct:Fts5ExprCtx file: +Fts5ExprNearset testdocs/sqlite3.c /^struct Fts5ExprNearset {$/;" s file: +Fts5ExprNearset testdocs/sqlite3.c /^typedef struct Fts5ExprNearset Fts5ExprNearset;$/;" t typeref:struct:Fts5ExprNearset file: +Fts5ExprNode testdocs/sqlite3.c /^struct Fts5ExprNode {$/;" s file: +Fts5ExprNode testdocs/sqlite3.c /^typedef struct Fts5ExprNode Fts5ExprNode;$/;" t typeref:struct:Fts5ExprNode file: +Fts5ExprPhrase testdocs/sqlite3.c /^struct Fts5ExprPhrase {$/;" s file: +Fts5ExprPhrase testdocs/sqlite3.c /^typedef struct Fts5ExprPhrase Fts5ExprPhrase;$/;" t typeref:struct:Fts5ExprPhrase file: +Fts5ExprTerm testdocs/sqlite3.c /^struct Fts5ExprTerm {$/;" s file: +Fts5ExprTerm testdocs/sqlite3.c /^typedef struct Fts5ExprTerm Fts5ExprTerm;$/;" t typeref:struct:Fts5ExprTerm file: +Fts5ExtensionApi testdocs/sqlite3.c /^struct Fts5ExtensionApi {$/;" s file: +Fts5ExtensionApi testdocs/sqlite3.c /^typedef struct Fts5ExtensionApi Fts5ExtensionApi;$/;" t typeref:struct:Fts5ExtensionApi file: +Fts5FlushCtx testdocs/sqlite3.c /^struct Fts5FlushCtx {$/;" s file: +Fts5FlushCtx testdocs/sqlite3.c /^typedef struct Fts5FlushCtx Fts5FlushCtx;$/;" t typeref:struct:Fts5FlushCtx file: +Fts5Global testdocs/sqlite3.c /^struct Fts5Global {$/;" s file: +Fts5Global testdocs/sqlite3.c /^typedef struct Fts5Global Fts5Global;$/;" t typeref:struct:Fts5Global file: +Fts5Hash testdocs/sqlite3.c /^struct Fts5Hash {$/;" s file: +Fts5Hash testdocs/sqlite3.c /^typedef struct Fts5Hash Fts5Hash;$/;" t typeref:struct:Fts5Hash file: +Fts5HashEntry testdocs/sqlite3.c /^struct Fts5HashEntry {$/;" s file: +Fts5HashEntry testdocs/sqlite3.c /^typedef struct Fts5HashEntry Fts5HashEntry;$/;" t typeref:struct:Fts5HashEntry file: +Fts5Index testdocs/sqlite3.c /^struct Fts5Index {$/;" s file: +Fts5Index testdocs/sqlite3.c /^typedef struct Fts5Index Fts5Index;$/;" t typeref:struct:Fts5Index file: +Fts5IndexIter testdocs/sqlite3.c /^struct Fts5IndexIter {$/;" s file: +Fts5IndexIter testdocs/sqlite3.c /^typedef struct Fts5IndexIter Fts5IndexIter;$/;" t typeref:struct:Fts5IndexIter file: +Fts5InsertCtx testdocs/sqlite3.c /^struct Fts5InsertCtx {$/;" s file: +Fts5InsertCtx testdocs/sqlite3.c /^typedef struct Fts5InsertCtx Fts5InsertCtx;$/;" t typeref:struct:Fts5InsertCtx file: +Fts5IntegrityCtx testdocs/sqlite3.c /^struct Fts5IntegrityCtx {$/;" s file: +Fts5IntegrityCtx testdocs/sqlite3.c /^typedef struct Fts5IntegrityCtx Fts5IntegrityCtx;$/;" t typeref:struct:Fts5IntegrityCtx file: +Fts5Iter testdocs/sqlite3.c /^struct Fts5Iter {$/;" s file: +Fts5Iter testdocs/sqlite3.c /^typedef struct Fts5Iter Fts5Iter;$/;" t typeref:struct:Fts5Iter file: +Fts5LookaheadReader testdocs/sqlite3.c /^struct Fts5LookaheadReader {$/;" s file: +Fts5LookaheadReader testdocs/sqlite3.c /^typedef struct Fts5LookaheadReader Fts5LookaheadReader;$/;" t typeref:struct:Fts5LookaheadReader file: +Fts5MatchPhrase testdocs/sqlite3.c /^struct Fts5MatchPhrase {$/;" s file: +Fts5NearTrimmer testdocs/sqlite3.c /^struct Fts5NearTrimmer {$/;" s file: +Fts5NearTrimmer testdocs/sqlite3.c /^typedef struct Fts5NearTrimmer Fts5NearTrimmer;$/;" t typeref:struct:Fts5NearTrimmer file: +Fts5NodeIsString testdocs/sqlite3.c /^#define Fts5NodeIsString(/;" d file: +Fts5PageWriter testdocs/sqlite3.c /^struct Fts5PageWriter {$/;" s file: +Fts5PageWriter testdocs/sqlite3.c /^typedef struct Fts5PageWriter Fts5PageWriter;$/;" t typeref:struct:Fts5PageWriter file: +Fts5Parse testdocs/sqlite3.c /^struct Fts5Parse {$/;" s file: +Fts5Parse testdocs/sqlite3.c /^typedef struct Fts5Parse Fts5Parse;$/;" t typeref:struct:Fts5Parse file: +Fts5PhraseIter testdocs/sqlite3.c /^struct Fts5PhraseIter {$/;" s file: +Fts5PhraseIter testdocs/sqlite3.c /^typedef struct Fts5PhraseIter Fts5PhraseIter;$/;" t typeref:struct:Fts5PhraseIter file: +Fts5PoslistPopulator testdocs/sqlite3.c /^struct Fts5PoslistPopulator {$/;" s file: +Fts5PoslistPopulator testdocs/sqlite3.c /^typedef struct Fts5PoslistPopulator Fts5PoslistPopulator;$/;" t typeref:struct:Fts5PoslistPopulator file: +Fts5PoslistReader testdocs/sqlite3.c /^struct Fts5PoslistReader {$/;" s file: +Fts5PoslistReader testdocs/sqlite3.c /^typedef struct Fts5PoslistReader Fts5PoslistReader;$/;" t typeref:struct:Fts5PoslistReader file: +Fts5PoslistWriter testdocs/sqlite3.c /^struct Fts5PoslistWriter {$/;" s file: +Fts5PoslistWriter testdocs/sqlite3.c /^typedef struct Fts5PoslistWriter Fts5PoslistWriter;$/;" t typeref:struct:Fts5PoslistWriter file: +Fts5SFinder testdocs/sqlite3.c /^struct Fts5SFinder {$/;" s file: +Fts5SFinder testdocs/sqlite3.c /^typedef struct Fts5SFinder Fts5SFinder;$/;" t typeref:struct:Fts5SFinder file: +Fts5SegIter testdocs/sqlite3.c /^struct Fts5SegIter {$/;" s file: +Fts5SegIter testdocs/sqlite3.c /^typedef struct Fts5SegIter Fts5SegIter;$/;" t typeref:struct:Fts5SegIter file: +Fts5SegWriter testdocs/sqlite3.c /^struct Fts5SegWriter {$/;" s file: +Fts5SegWriter testdocs/sqlite3.c /^typedef struct Fts5SegWriter Fts5SegWriter;$/;" t typeref:struct:Fts5SegWriter file: +Fts5Sorter testdocs/sqlite3.c /^struct Fts5Sorter {$/;" s file: +Fts5Sorter testdocs/sqlite3.c /^typedef struct Fts5Sorter Fts5Sorter;$/;" t typeref:struct:Fts5Sorter file: +Fts5Storage testdocs/sqlite3.c /^struct Fts5Storage {$/;" s file: +Fts5Storage testdocs/sqlite3.c /^typedef struct Fts5Storage Fts5Storage;$/;" t typeref:struct:Fts5Storage file: +Fts5Structure testdocs/sqlite3.c /^struct Fts5Structure {$/;" s file: +Fts5Structure testdocs/sqlite3.c /^typedef struct Fts5Structure Fts5Structure;$/;" t typeref:struct:Fts5Structure file: +Fts5StructureLevel testdocs/sqlite3.c /^struct Fts5StructureLevel {$/;" s file: +Fts5StructureLevel testdocs/sqlite3.c /^typedef struct Fts5StructureLevel Fts5StructureLevel;$/;" t typeref:struct:Fts5StructureLevel file: +Fts5StructureSegment testdocs/sqlite3.c /^struct Fts5StructureSegment {$/;" s file: +Fts5StructureSegment testdocs/sqlite3.c /^typedef struct Fts5StructureSegment Fts5StructureSegment;$/;" t typeref:struct:Fts5StructureSegment file: +Fts5Table testdocs/sqlite3.c /^struct Fts5Table {$/;" s file: +Fts5Table testdocs/sqlite3.c /^typedef struct Fts5Table Fts5Table;$/;" t typeref:struct:Fts5Table file: +Fts5Termset testdocs/sqlite3.c /^struct Fts5Termset {$/;" s file: +Fts5Termset testdocs/sqlite3.c /^typedef struct Fts5Termset Fts5Termset;$/;" t typeref:struct:Fts5Termset file: +Fts5TermsetEntry testdocs/sqlite3.c /^struct Fts5TermsetEntry {$/;" s file: +Fts5TermsetEntry testdocs/sqlite3.c /^typedef struct Fts5TermsetEntry Fts5TermsetEntry;$/;" t typeref:struct:Fts5TermsetEntry file: +Fts5Token testdocs/sqlite3.c /^struct Fts5Token {$/;" s file: +Fts5Token testdocs/sqlite3.c /^typedef struct Fts5Token Fts5Token;$/;" t typeref:struct:Fts5Token file: +Fts5Tokenizer testdocs/sqlite3.c /^typedef struct Fts5Tokenizer Fts5Tokenizer;$/;" t typeref:struct:Fts5Tokenizer file: +Fts5TokenizerModule testdocs/sqlite3.c /^struct Fts5TokenizerModule {$/;" s file: +Fts5TokenizerModule testdocs/sqlite3.c /^typedef struct Fts5TokenizerModule Fts5TokenizerModule;$/;" t typeref:struct:Fts5TokenizerModule file: +Fts5TransactionState testdocs/sqlite3.c /^struct Fts5TransactionState {$/;" s file: +Fts5VocabCursor testdocs/sqlite3.c /^struct Fts5VocabCursor {$/;" s file: +Fts5VocabCursor testdocs/sqlite3.c /^typedef struct Fts5VocabCursor Fts5VocabCursor;$/;" t typeref:struct:Fts5VocabCursor file: +Fts5VocabTable testdocs/sqlite3.c /^struct Fts5VocabTable {$/;" s file: +Fts5VocabTable testdocs/sqlite3.c /^typedef struct Fts5VocabTable Fts5VocabTable;$/;" t typeref:struct:Fts5VocabTable file: +FuncDef testdocs/sqlite3.c /^struct FuncDef {$/;" s file: +FuncDef testdocs/sqlite3.c /^typedef struct FuncDef FuncDef;$/;" t typeref:struct:FuncDef file: +FuncDefHash testdocs/sqlite3.c /^struct FuncDefHash {$/;" s file: +FuncDefHash testdocs/sqlite3.c /^typedef struct FuncDefHash FuncDefHash;$/;" t typeref:struct:FuncDefHash file: +FuncDestructor testdocs/sqlite3.c /^struct FuncDestructor {$/;" s file: +FuncDestructor testdocs/sqlite3.c /^typedef struct FuncDestructor FuncDestructor;$/;" t typeref:struct:FuncDestructor file: +GCC_VERSION testdocs/sqlite3.c /^# define GCC_VERSION /;" d file: +GETVARINT_INIT testdocs/sqlite3.c /^#define GETVARINT_INIT(/;" d file: +GETVARINT_STEP testdocs/sqlite3.c /^#define GETVARINT_STEP(/;" d file: +GIT testdocs/waf /^GIT="1fa2e6f7e1420e3fc64b29bf7abef531220da538"$/;" v +GLOBAL testdocs/sqlite3.c /^ #define GLOBAL(/;" d file: +HANDLE_TO_WINFILE testdocs/sqlite3.c /^#define HANDLE_TO_WINFILE(/;" d file: +HASHSIZE testdocs/sqlite3.c /^#define HASHSIZE /;" d file: +HASHTABLE_HASH_1 testdocs/sqlite3.c /^#define HASHTABLE_HASH_1 /;" d file: +HASHTABLE_NPAGE testdocs/sqlite3.c /^#define HASHTABLE_NPAGE /;" d file: +HASHTABLE_NPAGE_ONE testdocs/sqlite3.c /^#define HASHTABLE_NPAGE_ONE /;" d file: +HASHTABLE_NSLOT testdocs/sqlite3.c /^#define HASHTABLE_NSLOT /;" d file: +HASH_APPEND testdocs/sqlite3.c /^#define HASH_APPEND(/;" d file: +HAS_UPDATE_HOOK testdocs/sqlite3.c /^# define HAS_UPDATE_HOOK(/;" d file: +HAVE_FCHOWN testdocs/sqlite3.c /^#define HAVE_FCHOWN /;" d file: +HAVE_FULLFSYNC testdocs/sqlite3.c /^# define HAVE_FULLFSYNC /;" d file: +HAVE_GETHOSTUUID testdocs/sqlite3.c /^# define HAVE_GETHOSTUUID /;" d file: +HAVE_LOCALTIME_S testdocs/sqlite3.c /^#define HAVE_LOCALTIME_S /;" d file: +HAVE_LOCALTIME_S testdocs/sqlite3.c /^#undef HAVE_LOCALTIME_S$/;" d file: +HAVE_LSTAT testdocs/sqlite3.c /^#define HAVE_LSTAT /;" d file: +HAVE_MREMAP testdocs/sqlite3.c /^# define HAVE_MREMAP /;" d file: +HAVE_PREAD testdocs/sqlite3.c /^# define HAVE_PREAD /;" d file: +HAVE_PWRITE testdocs/sqlite3.c /^# define HAVE_PWRITE /;" d file: +HAVE_READLINK testdocs/sqlite3.c /^#define HAVE_READLINK /;" d file: +HAVE_UTIME testdocs/sqlite3.c /^#define HAVE_UTIME /;" d file: +HasRowid testdocs/sqlite3.c /^#define HasRowid(/;" d file: +Hash testdocs/sqlite3.c /^struct Hash {$/;" s file: +Hash testdocs/sqlite3.c /^typedef struct Hash Hash;$/;" t typeref:struct:Hash file: +HashElem testdocs/sqlite3.c /^struct HashElem {$/;" s file: +HashElem testdocs/sqlite3.c /^typedef struct HashElem HashElem;$/;" t typeref:struct:HashElem file: +HavingToWhereCtx testdocs/sqlite3.c /^struct HavingToWhereCtx {$/;" s file: +HighlightContext testdocs/sqlite3.c /^struct HighlightContext {$/;" s file: +HighlightContext testdocs/sqlite3.c /^typedef struct HighlightContext HighlightContext;$/;" t typeref:struct:HighlightContext file: +IGNORE atf.h /^#define IGNORE(/;" d +INCLUDE_DEFS atf.h /^#undef INCLUDE_DEFS$/;" d +INCLUDE_DEFS testbuf.c /^#define INCLUDE_DEFS$/;" d file: +INCRINIT_NORMAL testdocs/sqlite3.c /^#define INCRINIT_NORMAL /;" d file: +INCRINIT_ROOT testdocs/sqlite3.c /^#define INCRINIT_ROOT /;" d file: +INCRINIT_TASK testdocs/sqlite3.c /^#define INCRINIT_TASK /;" d file: +INSTALL testdocs/waf /^INSTALL=''$/;" v +INT16_TYPE testdocs/sqlite3.c /^# define INT16_TYPE /;" d file: +INT8_TYPE testdocs/sqlite3.c /^# define INT8_TYPE /;" d file: +INTERFACE testdocs/sqlite3.c /^# define INTERFACE /;" d file: +INT_464269060799999 testdocs/sqlite3.c /^#define INT_464269060799999 /;" d file: +INVALID_FILE_ATTRIBUTES testdocs/sqlite3.c /^# define INVALID_FILE_ATTRIBUTES /;" d file: +INVALID_SET_FILE_POINTER testdocs/sqlite3.c /^# define INVALID_SET_FILE_POINTER /;" d file: +IN_DECLARE_VTAB testdocs/sqlite3.c /^ #define IN_DECLARE_VTAB /;" d file: +IN_INDEX_EPH testdocs/sqlite3.c /^#define IN_INDEX_EPH /;" d file: +IN_INDEX_INDEX_ASC testdocs/sqlite3.c /^#define IN_INDEX_INDEX_ASC /;" d file: +IN_INDEX_INDEX_DESC testdocs/sqlite3.c /^#define IN_INDEX_INDEX_DESC /;" d file: +IN_INDEX_LOOP testdocs/sqlite3.c /^#define IN_INDEX_LOOP /;" d file: +IN_INDEX_MEMBERSHIP testdocs/sqlite3.c /^#define IN_INDEX_MEMBERSHIP /;" d file: +IN_INDEX_NOOP testdocs/sqlite3.c /^#define IN_INDEX_NOOP /;" d file: +IN_INDEX_NOOP_OK testdocs/sqlite3.c /^#define IN_INDEX_NOOP_OK /;" d file: +IN_INDEX_ROWID testdocs/sqlite3.c /^#define IN_INDEX_ROWID /;" d file: +IOMETHODS testdocs/sqlite3.c /^#define IOMETHODS(/;" d file: +IOTRACE testdocs/sqlite3.c /^# define IOTRACE(/;" d file: +ISAUTOVACUUM testdocs/sqlite3.c /^#define ISAUTOVACUUM /;" d file: +IS_BIG_INT testdocs/sqlite3.c /^#define IS_BIG_INT(/;" d file: +IS_LOCK_ERROR testdocs/sqlite3.c /^#define IS_LOCK_ERROR(/;" d file: +IcuCursor testdocs/sqlite3.c /^struct IcuCursor {$/;" s file: +IcuCursor testdocs/sqlite3.c /^typedef struct IcuCursor IcuCursor;$/;" t typeref:struct:IcuCursor file: +IcuTokenizer testdocs/sqlite3.c /^struct IcuTokenizer {$/;" s file: +IcuTokenizer testdocs/sqlite3.c /^typedef struct IcuTokenizer IcuTokenizer;$/;" t typeref:struct:IcuTokenizer file: +IdChar testdocs/sqlite3.c /^#define IdChar(/;" d file: +IdList testdocs/sqlite3.c /^struct IdList {$/;" s file: +IdList testdocs/sqlite3.c /^typedef struct IdList IdList;$/;" t typeref:struct:IdList file: +IdList_item testdocs/sqlite3.c /^ struct IdList_item {$/;" s struct:IdList file: +IdxCover testdocs/sqlite3.c /^struct IdxCover {$/;" s file: +IdxExprTrans testdocs/sqlite3.c /^typedef struct IdxExprTrans {$/;" s file: +IdxExprTrans testdocs/sqlite3.c /^} IdxExprTrans;$/;" t typeref:struct:IdxExprTrans file: +IfNotOmitAV testdocs/sqlite3.c /^#define IfNotOmitAV(/;" d file: +IgnorableOrderby testdocs/sqlite3.c /^#define IgnorableOrderby(/;" d file: +InLoop testdocs/sqlite3.c /^ struct InLoop {$/;" s struct:WhereLevel::__anon27::__anon28 file: +IncrMerger testdocs/sqlite3.c /^struct IncrMerger {$/;" s file: +IncrMerger testdocs/sqlite3.c /^typedef struct IncrMerger IncrMerger; \/* Read & merge multiple PMAs *\/$/;" t typeref:struct:IncrMerger file: +Incrblob testdocs/sqlite3.c /^struct Incrblob {$/;" s file: +Incrblob testdocs/sqlite3.c /^typedef struct Incrblob Incrblob;$/;" t typeref:struct:Incrblob file: +IncrmergeWriter testdocs/sqlite3.c /^struct IncrmergeWriter {$/;" s file: +IncrmergeWriter testdocs/sqlite3.c /^typedef struct IncrmergeWriter IncrmergeWriter;$/;" t typeref:struct:IncrmergeWriter file: +Index testdocs/sqlite3.c /^struct Index {$/;" s file: +Index testdocs/sqlite3.c /^typedef struct Index Index;$/;" t typeref:struct:Index file: +IndexSample testdocs/sqlite3.c /^struct IndexSample {$/;" s file: +IndexSample testdocs/sqlite3.c /^typedef struct IndexSample IndexSample;$/;" t typeref:struct:IndexSample file: +InitData testdocs/sqlite3.c /^} InitData;$/;" t typeref:struct:__anon16 file: +IntegrityCk testdocs/sqlite3.c /^struct IntegrityCk {$/;" s file: +IntegrityCk testdocs/sqlite3.c /^typedef struct IntegrityCk IntegrityCk;$/;" t typeref:struct:IntegrityCk file: +IsHiddenColumn testdocs/sqlite3.c /^# define IsHiddenColumn(/;" d file: +IsOrdinaryHiddenColumn testdocs/sqlite3.c /^# define IsOrdinaryHiddenColumn(/;" d file: +IsPowerOfTwo testdocs/sqlite3.c /^#define IsPowerOfTwo(/;" d file: +IsPrimaryKeyIndex testdocs/sqlite3.c /^#define IsPrimaryKeyIndex(/;" d file: +IsStat3 testdocs/sqlite3.c /^# define IsStat3 /;" d file: +IsStat34 testdocs/sqlite3.c /^#define IsStat34 /;" d file: +IsStat4 testdocs/sqlite3.c /^# define IsStat4 /;" d file: +IsUniqueIndex testdocs/sqlite3.c /^#define IsUniqueIndex(/;" d file: +IsVirtual testdocs/sqlite3.c /^# define IsVirtual(/;" d file: +JEACH_ATOM testdocs/sqlite3.c /^#define JEACH_ATOM /;" d file: +JEACH_FULLKEY testdocs/sqlite3.c /^#define JEACH_FULLKEY /;" d file: +JEACH_ID testdocs/sqlite3.c /^#define JEACH_ID /;" d file: +JEACH_JSON testdocs/sqlite3.c /^#define JEACH_JSON /;" d file: +JEACH_KEY testdocs/sqlite3.c /^#define JEACH_KEY /;" d file: +JEACH_PARENT testdocs/sqlite3.c /^#define JEACH_PARENT /;" d file: +JEACH_PATH testdocs/sqlite3.c /^#define JEACH_PATH /;" d file: +JEACH_ROOT testdocs/sqlite3.c /^#define JEACH_ROOT /;" d file: +JEACH_TYPE testdocs/sqlite3.c /^#define JEACH_TYPE /;" d file: +JEACH_VALUE testdocs/sqlite3.c /^#define JEACH_VALUE /;" d file: +JNODE_APPEND testdocs/sqlite3.c /^#define JNODE_APPEND /;" d file: +JNODE_ESCAPE testdocs/sqlite3.c /^#define JNODE_ESCAPE /;" d file: +JNODE_LABEL testdocs/sqlite3.c /^#define JNODE_LABEL /;" d file: +JNODE_PATCH testdocs/sqlite3.c /^#define JNODE_PATCH /;" d file: +JNODE_RAW testdocs/sqlite3.c /^#define JNODE_RAW /;" d file: +JNODE_REMOVE testdocs/sqlite3.c /^#define JNODE_REMOVE /;" d file: +JNODE_REPLACE testdocs/sqlite3.c /^#define JNODE_REPLACE /;" d file: +JOURNAL_HDR_SZ testdocs/sqlite3.c /^#define JOURNAL_HDR_SZ(/;" d file: +JOURNAL_PG_SZ testdocs/sqlite3.c /^#define JOURNAL_PG_SZ(/;" d file: +JSON_ARRAY testdocs/sqlite3.c /^#define JSON_ARRAY /;" d file: +JSON_CACHE_ID testdocs/sqlite3.c /^#define JSON_CACHE_ID /;" d file: +JSON_FALSE testdocs/sqlite3.c /^#define JSON_FALSE /;" d file: +JSON_INT testdocs/sqlite3.c /^#define JSON_INT /;" d file: +JSON_MAX_DEPTH testdocs/sqlite3.c /^#define JSON_MAX_DEPTH /;" d file: +JSON_NOINLINE testdocs/sqlite3.c /^# define JSON_NOINLINE /;" d file: +JSON_NOINLINE testdocs/sqlite3.c /^# define JSON_NOINLINE$/;" d file: +JSON_NULL testdocs/sqlite3.c /^#define JSON_NULL /;" d file: +JSON_OBJECT testdocs/sqlite3.c /^#define JSON_OBJECT /;" d file: +JSON_REAL testdocs/sqlite3.c /^#define JSON_REAL /;" d file: +JSON_STRING testdocs/sqlite3.c /^#define JSON_STRING /;" d file: +JSON_SUBTYPE testdocs/sqlite3.c /^#define JSON_SUBTYPE /;" d file: +JSON_TRUE testdocs/sqlite3.c /^#define JSON_TRUE /;" d file: +JT_CROSS testdocs/sqlite3.c /^#define JT_CROSS /;" d file: +JT_ERROR testdocs/sqlite3.c /^#define JT_ERROR /;" d file: +JT_INNER testdocs/sqlite3.c /^#define JT_INNER /;" d file: +JT_LEFT testdocs/sqlite3.c /^#define JT_LEFT /;" d file: +JT_NATURAL testdocs/sqlite3.c /^#define JT_NATURAL /;" d file: +JT_OUTER testdocs/sqlite3.c /^#define JT_OUTER /;" d file: +JT_RIGHT testdocs/sqlite3.c /^#define JT_RIGHT /;" d file: +JsonEachCursor testdocs/sqlite3.c /^struct JsonEachCursor {$/;" s file: +JsonEachCursor testdocs/sqlite3.c /^typedef struct JsonEachCursor JsonEachCursor;$/;" t typeref:struct:JsonEachCursor file: +JsonNode testdocs/sqlite3.c /^struct JsonNode {$/;" s file: +JsonNode testdocs/sqlite3.c /^typedef struct JsonNode JsonNode;$/;" t typeref:struct:JsonNode file: +JsonParse testdocs/sqlite3.c /^struct JsonParse {$/;" s file: +JsonParse testdocs/sqlite3.c /^typedef struct JsonParse JsonParse;$/;" t typeref:struct:JsonParse file: +JsonString testdocs/sqlite3.c /^struct JsonString {$/;" s file: +JsonString testdocs/sqlite3.c /^typedef struct JsonString JsonString;$/;" t typeref:struct:JsonString file: +KeyClass testdocs/sqlite3.c /^typedef struct KeyClass KeyClass;$/;" t typeref:struct:KeyClass file: +KeyInfo testdocs/sqlite3.c /^struct KeyInfo {$/;" s file: +KeyInfo testdocs/sqlite3.c /^typedef struct KeyInfo KeyInfo;$/;" t typeref:struct:KeyInfo file: +LARGEST_INT64 testdocs/sqlite3.c /^# define LARGEST_INT64 /;" d file: +LARGEST_INT64 testdocs/sqlite3.c /^#define LARGEST_INT64 /;" d file: +LCS_ITERATOR_FINISHED testdocs/sqlite3.c /^#define LCS_ITERATOR_FINISHED /;" d file: +LEFT edit.h /^ LEFT = -1,$/;" e enum:__anon7 +LIKEFUNC testdocs/sqlite3.c /^#define LIKEFUNC(/;" d file: +LOCATE_NOERR testdocs/sqlite3.c /^#define LOCATE_NOERR /;" d file: +LOCATE_VIEW testdocs/sqlite3.c /^#define LOCATE_VIEW /;" d file: +LOCKFILE_EXCLUSIVE_LOCK testdocs/sqlite3.c /^# define LOCKFILE_EXCLUSIVE_LOCK /;" d file: +LOCKFILE_FAIL_IMMEDIATELY testdocs/sqlite3.c /^# define LOCKFILE_FAIL_IMMEDIATELY /;" d file: +LOGMAX testdocs/sqlite3.c /^#define LOGMAX /;" d file: +LONGDOUBLE_TYPE testdocs/sqlite3.c /^# define LONGDOUBLE_TYPE /;" d file: +LcsIterator testdocs/sqlite3.c /^struct LcsIterator {$/;" s file: +LcsIterator testdocs/sqlite3.c /^typedef struct LcsIterator LcsIterator;$/;" t typeref:struct:LcsIterator file: +LimitVal testdocs/sqlite3.c /^struct LimitVal {$/;" s file: +LoadDoclistCtx testdocs/sqlite3.c /^struct LoadDoclistCtx {$/;" s file: +LoadDoclistCtx testdocs/sqlite3.c /^typedef struct LoadDoclistCtx LoadDoclistCtx;$/;" t typeref:struct:LoadDoclistCtx file: +Log edit.h /^typedef struct Log {$/;" s +Log edit.h /^} Log;$/;" t typeref:struct:Log +LogEst testdocs/sqlite3.c /^typedef INT16_TYPE LogEst;$/;" t file: +Lookaside testdocs/sqlite3.c /^struct Lookaside {$/;" s file: +Lookaside testdocs/sqlite3.c /^typedef struct Lookaside Lookaside;$/;" t typeref:struct:Lookaside file: +LookasideSlot testdocs/sqlite3.c /^struct LookasideSlot {$/;" s file: +LookasideSlot testdocs/sqlite3.c /^typedef struct LookasideSlot LookasideSlot;$/;" t typeref:struct:LookasideSlot file: +M testdocs/sqlite3.c /^ int Y, M, D; \/* Year, month, and day *\/$/;" m struct:DateTime file: +MASKBIT testdocs/sqlite3.c /^#define MASKBIT(/;" d file: +MASKBIT32 testdocs/sqlite3.c /^#define MASKBIT32(/;" d file: +MASTER_NAME testdocs/sqlite3.c /^#define MASTER_NAME /;" d file: +MASTER_ROOT testdocs/sqlite3.c /^#define MASTER_ROOT /;" d file: +MAX testdocs/sqlite3.c /^# define MAX(/;" d file: +MAX testdocs/sqlite3.c /^#define MAX(/;" d file: +MAX_6BYTE testdocs/sqlite3.c /^# define MAX_6BYTE /;" d file: +MAX_INCR_PHRASE_TOKENS testdocs/sqlite3.c /^#define MAX_INCR_PHRASE_TOKENS /;" d file: +MAX_PATH testdocs/sqlite3.c /^# define MAX_PATH /;" d file: +MAX_PATHNAME testdocs/sqlite3.c /^#define MAX_PATHNAME /;" d file: +MAX_ROWID testdocs/sqlite3.c /^# define MAX_ROWID /;" d file: +MAX_SECTOR_SIZE testdocs/sqlite3.c /^#define MAX_SECTOR_SIZE /;" d file: +MEM5LINK testdocs/sqlite3.c /^#define MEM5LINK(/;" d file: +MEMCELLSIZE testdocs/sqlite3.c /^#define MEMCELLSIZE /;" d file: +MEMDB testdocs/sqlite3.c /^# define MEMDB /;" d file: +MEMJOURNAL_DFLT_FILECHUNKSIZE testdocs/sqlite3.c /^#define MEMJOURNAL_DFLT_FILECHUNKSIZE /;" d file: +MEMTYPE_HEAP testdocs/sqlite3.c /^#define MEMTYPE_HEAP /;" d file: +MEMTYPE_LOOKASIDE testdocs/sqlite3.c /^#define MEMTYPE_LOOKASIDE /;" d file: +MEMTYPE_PCACHE testdocs/sqlite3.c /^#define MEMTYPE_PCACHE /;" d file: +MEMTYPE_SCRATCH testdocs/sqlite3.c /^#define MEMTYPE_SCRATCH /;" d file: +MEM_AffMask testdocs/sqlite3.c /^#define MEM_AffMask /;" d file: +MEM_Agg testdocs/sqlite3.c /^#define MEM_Agg /;" d file: +MEM_Blob testdocs/sqlite3.c /^#define MEM_Blob /;" d file: +MEM_Cleared testdocs/sqlite3.c /^#define MEM_Cleared /;" d file: +MEM_Dyn testdocs/sqlite3.c /^#define MEM_Dyn /;" d file: +MEM_Ephem testdocs/sqlite3.c /^#define MEM_Ephem /;" d file: +MEM_Frame testdocs/sqlite3.c /^#define MEM_Frame /;" d file: +MEM_Int testdocs/sqlite3.c /^#define MEM_Int /;" d file: +MEM_Null testdocs/sqlite3.c /^#define MEM_Null /;" d file: +MEM_Real testdocs/sqlite3.c /^#define MEM_Real /;" d file: +MEM_RowSet testdocs/sqlite3.c /^#define MEM_RowSet /;" d file: +MEM_Static testdocs/sqlite3.c /^#define MEM_Static /;" d file: +MEM_Str testdocs/sqlite3.c /^#define MEM_Str /;" d file: +MEM_Subtype testdocs/sqlite3.c /^#define MEM_Subtype /;" d file: +MEM_Term testdocs/sqlite3.c /^#define MEM_Term /;" d file: +MEM_TypeMask testdocs/sqlite3.c /^#define MEM_TypeMask /;" d file: +MEM_Undefined testdocs/sqlite3.c /^#define MEM_Undefined /;" d file: +MEM_Zero testdocs/sqlite3.c /^ #define MEM_Zero /;" d file: +MEM_Zero testdocs/sqlite3.c /^ #undef MEM_Zero$/;" d file: +MEM_Zero testdocs/sqlite3.c /^#define MEM_Zero /;" d file: +MIN testdocs/sqlite3.c /^# define MIN(/;" d file: +MIN testdocs/sqlite3.c /^#define MIN(/;" d file: +MSVC_VERSION testdocs/sqlite3.c /^# define MSVC_VERSION /;" d file: +MUTEX_LOGIC testdocs/sqlite3.c /^#define MUTEX_LOGIC(/;" d file: +MX_CELL testdocs/sqlite3.c /^#define MX_CELL(/;" d file: +MX_CELL_SIZE testdocs/sqlite3.c /^#define MX_CELL_SIZE(/;" d file: +MX_CLOSE_ATTEMPT testdocs/sqlite3.c /^#define MX_CLOSE_ATTEMPT /;" d file: +MX_SMALL testdocs/sqlite3.c /^#define MX_SMALL /;" d file: +MatchInfo testdocs/sqlite3.c /^struct MatchInfo {$/;" s file: +MatchInfo testdocs/sqlite3.c /^typedef struct MatchInfo MatchInfo;$/;" t typeref:struct:MatchInfo file: +MatchinfoBuffer testdocs/sqlite3.c /^struct MatchinfoBuffer {$/;" s file: +MatchinfoBuffer testdocs/sqlite3.c /^typedef struct MatchinfoBuffer MatchinfoBuffer;$/;" t typeref:struct:MatchinfoBuffer file: +Mem testdocs/sqlite3.c /^typedef struct sqlite3_value Mem;$/;" t typeref:struct:sqlite3_value file: +Mem0Global testdocs/sqlite3.c /^static SQLITE_WSD struct Mem0Global {$/;" s file: +Mem3Block testdocs/sqlite3.c /^struct Mem3Block {$/;" s file: +Mem3Block testdocs/sqlite3.c /^typedef struct Mem3Block Mem3Block;$/;" t typeref:struct:Mem3Block file: +Mem3Global testdocs/sqlite3.c /^static SQLITE_WSD struct Mem3Global {$/;" s file: +Mem5Global testdocs/sqlite3.c /^static SQLITE_WSD struct Mem5Global {$/;" s file: +Mem5Link testdocs/sqlite3.c /^struct Mem5Link {$/;" s file: +Mem5Link testdocs/sqlite3.c /^typedef struct Mem5Link Mem5Link;$/;" t typeref:struct:Mem5Link file: +MemBlockHdr testdocs/sqlite3.c /^struct MemBlockHdr {$/;" s file: +MemJournal testdocs/sqlite3.c /^struct MemJournal {$/;" s file: +MemJournal testdocs/sqlite3.c /^typedef struct MemJournal MemJournal;$/;" t typeref:struct:MemJournal file: +MemJournalMethods testdocs/sqlite3.c /^static const struct sqlite3_io_methods MemJournalMethods = {$/;" v typeref:struct:sqlite3_io_methods file: +MemPage testdocs/sqlite3.c /^struct MemPage {$/;" s file: +MemPage testdocs/sqlite3.c /^typedef struct MemPage MemPage;$/;" t typeref:struct:MemPage file: +MemSetTypeFlag testdocs/sqlite3.c /^#define MemSetTypeFlag(/;" d file: +MemValue testdocs/sqlite3.c /^ union MemValue {$/;" u struct:sqlite3_value file: +MergeEngine testdocs/sqlite3.c /^struct MergeEngine {$/;" s file: +MergeEngine testdocs/sqlite3.c /^typedef struct MergeEngine MergeEngine; \/* Merge PMAs together *\/$/;" t typeref:struct:MergeEngine file: +Module testdocs/sqlite3.c /^struct Module {$/;" s file: +Module testdocs/sqlite3.c /^typedef struct Module Module;$/;" t typeref:struct:Module file: +NB testdocs/sqlite3.c /^#define NB /;" d file: +NCELL testdocs/sqlite3.c /^#define NCELL(/;" d file: +NCSIZE testdocs/sqlite3.c /^#define NCSIZE /;" d file: +NC_AllowAgg testdocs/sqlite3.c /^#define NC_AllowAgg /;" d file: +NC_HasAgg testdocs/sqlite3.c /^#define NC_HasAgg /;" d file: +NC_IdxExpr testdocs/sqlite3.c /^#define NC_IdxExpr /;" d file: +NC_InAggFunc testdocs/sqlite3.c /^#define NC_InAggFunc /;" d file: +NC_IsCheck testdocs/sqlite3.c /^#define NC_IsCheck /;" d file: +NC_MinMaxAgg testdocs/sqlite3.c /^#define NC_MinMaxAgg /;" d file: +NC_PartIdx testdocs/sqlite3.c /^#define NC_PartIdx /;" d file: +NC_VarSelect testdocs/sqlite3.c /^#define NC_VarSelect /;" d file: +NDEBUG testdocs/sqlite3.c /^# define NDEBUG /;" d file: +NDEBUG testdocs/sqlite3.c /^# undef NDEBUG$/;" d file: +NDELAY testdocs/sqlite3.c /^# define NDELAY /;" d file: +NEVER testdocs/sqlite3.c /^# define NEVER(/;" d file: +NEVER testdocs/sqlite3.c /^#define NEVER(/;" d file: +NN testdocs/sqlite3.c /^#define NN /;" d file: +NOT_WITHIN testdocs/sqlite3.c /^#define NOT_WITHIN /;" d file: +NO_LOCK testdocs/sqlite3.c /^#define NO_LOCK /;" d file: +NTDDI_WIN8 testdocs/sqlite3.c /^# define NTDDI_WIN8 /;" d file: +NTDDI_WINBLUE testdocs/sqlite3.c /^# define NTDDI_WINBLUE /;" d file: +NTDDI_WINTHRESHOLD testdocs/sqlite3.c /^# define NTDDI_WINTHRESHOLD /;" d file: +N_HASH testdocs/sqlite3.c /^#define N_HASH /;" d file: +N_OR_COST testdocs/sqlite3.c /^#define N_OR_COST /;" d file: +N_SORT_BUCKET testdocs/sqlite3.c /^#define N_SORT_BUCKET /;" d file: +N_STATEMENT testdocs/sqlite3.c /^ #define N_STATEMENT /;" d file: +NameContext testdocs/sqlite3.c /^struct NameContext {$/;" s file: +NameContext testdocs/sqlite3.c /^typedef struct NameContext NameContext;$/;" t typeref:struct:NameContext file: +NodeReader testdocs/sqlite3.c /^struct NodeReader {$/;" s file: +NodeReader testdocs/sqlite3.c /^typedef struct NodeReader NodeReader;$/;" t typeref:struct:NodeReader file: +NodeWriter testdocs/sqlite3.c /^struct NodeWriter {$/;" s file: +NodeWriter testdocs/sqlite3.c /^typedef struct NodeWriter NodeWriter;$/;" t typeref:struct:NodeWriter file: +OE_Abort testdocs/sqlite3.c /^#define OE_Abort /;" d file: +OE_Cascade testdocs/sqlite3.c /^#define OE_Cascade /;" d file: +OE_Default testdocs/sqlite3.c /^#define OE_Default /;" d file: +OE_Fail testdocs/sqlite3.c /^#define OE_Fail /;" d file: +OE_Ignore testdocs/sqlite3.c /^#define OE_Ignore /;" d file: +OE_None testdocs/sqlite3.c /^#define OE_None /;" d file: +OE_Replace testdocs/sqlite3.c /^#define OE_Replace /;" d file: +OE_Restrict testdocs/sqlite3.c /^#define OE_Restrict /;" d file: +OE_Rollback testdocs/sqlite3.c /^#define OE_Rollback /;" d file: +OE_SetDflt testdocs/sqlite3.c /^#define OE_SetDflt /;" d file: +OE_SetNull testdocs/sqlite3.c /^#define OE_SetNull /;" d file: +OMIT_TEMPDB testdocs/sqlite3.c /^#define OMIT_TEMPDB /;" d file: +ONEPASS_MULTI testdocs/sqlite3.c /^#define ONEPASS_MULTI /;" d file: +ONEPASS_OFF testdocs/sqlite3.c /^#define ONEPASS_OFF /;" d file: +ONEPASS_SINGLE testdocs/sqlite3.c /^#define ONEPASS_SINGLE /;" d file: +ONE_BYTE_INT testdocs/sqlite3.c /^#define ONE_BYTE_INT(/;" d file: +ONLY_IF_REALLOC_STRESS testdocs/sqlite3.c /^# define ONLY_IF_REALLOC_STRESS(/;" d file: +OPFLAG_APPEND testdocs/sqlite3.c /^#define OPFLAG_APPEND /;" d file: +OPFLAG_AUXDELETE testdocs/sqlite3.c /^#define OPFLAG_AUXDELETE /;" d file: +OPFLAG_BULKCSR testdocs/sqlite3.c /^#define OPFLAG_BULKCSR /;" d file: +OPFLAG_EPHEM testdocs/sqlite3.c /^#define OPFLAG_EPHEM /;" d file: +OPFLAG_FORDELETE testdocs/sqlite3.c /^#define OPFLAG_FORDELETE /;" d file: +OPFLAG_ISNOOP testdocs/sqlite3.c /^#define OPFLAG_ISNOOP /;" d file: +OPFLAG_ISUPDATE testdocs/sqlite3.c /^#define OPFLAG_ISUPDATE /;" d file: +OPFLAG_LASTROWID testdocs/sqlite3.c /^#define OPFLAG_LASTROWID /;" d file: +OPFLAG_LENGTHARG testdocs/sqlite3.c /^#define OPFLAG_LENGTHARG /;" d file: +OPFLAG_NCHANGE testdocs/sqlite3.c /^#define OPFLAG_NCHANGE /;" d file: +OPFLAG_P2ISREG testdocs/sqlite3.c /^#define OPFLAG_P2ISREG /;" d file: +OPFLAG_PERMUTE testdocs/sqlite3.c /^#define OPFLAG_PERMUTE /;" d file: +OPFLAG_SAVEPOSITION testdocs/sqlite3.c /^#define OPFLAG_SAVEPOSITION /;" d file: +OPFLAG_SEEKEQ testdocs/sqlite3.c /^#define OPFLAG_SEEKEQ /;" d file: +OPFLAG_TYPEOFARG testdocs/sqlite3.c /^#define OPFLAG_TYPEOFARG /;" d file: +OPFLAG_USESEEKRESULT testdocs/sqlite3.c /^#define OPFLAG_USESEEKRESULT /;" d file: +OPFLG_IN1 testdocs/sqlite3.c /^#define OPFLG_IN1 /;" d file: +OPFLG_IN2 testdocs/sqlite3.c /^#define OPFLG_IN2 /;" d file: +OPFLG_IN3 testdocs/sqlite3.c /^#define OPFLG_IN3 /;" d file: +OPFLG_INITIALIZER testdocs/sqlite3.c /^#define OPFLG_INITIALIZER /;" d file: +OPFLG_JUMP testdocs/sqlite3.c /^#define OPFLG_JUMP /;" d file: +OPFLG_OUT2 testdocs/sqlite3.c /^#define OPFLG_OUT2 /;" d file: +OPFLG_OUT3 testdocs/sqlite3.c /^#define OPFLG_OUT3 /;" d file: +OPTARG stdc.h /^#define OPTARG(/;" d +OPTBEGIN stdc.h /^#define OPTBEGIN /;" d +OPTC stdc.h /^#define OPTC(/;" d +OPTEND stdc.h /^#define OPTEND /;" d +OPTLONG stdc.h /^#define OPTLONG /;" d +OPTNUM stdc.h /^#define OPTNUM /;" d +OP_Add testdocs/sqlite3.c /^#define OP_Add /;" d file: +OP_AddImm testdocs/sqlite3.c /^#define OP_AddImm /;" d file: +OP_Affinity testdocs/sqlite3.c /^#define OP_Affinity /;" d file: +OP_AggFinal testdocs/sqlite3.c /^#define OP_AggFinal /;" d file: +OP_AggStep testdocs/sqlite3.c /^#define OP_AggStep /;" d file: +OP_AggStep0 testdocs/sqlite3.c /^#define OP_AggStep0 /;" d file: +OP_And testdocs/sqlite3.c /^#define OP_And /;" d file: +OP_AutoCommit testdocs/sqlite3.c /^#define OP_AutoCommit /;" d file: +OP_BitAnd testdocs/sqlite3.c /^#define OP_BitAnd /;" d file: +OP_BitNot testdocs/sqlite3.c /^#define OP_BitNot /;" d file: +OP_BitOr testdocs/sqlite3.c /^#define OP_BitOr /;" d file: +OP_Blob testdocs/sqlite3.c /^#define OP_Blob /;" d file: +OP_Cast testdocs/sqlite3.c /^#define OP_Cast /;" d file: +OP_Checkpoint testdocs/sqlite3.c /^#define OP_Checkpoint /;" d file: +OP_Clear testdocs/sqlite3.c /^#define OP_Clear /;" d file: +OP_Close testdocs/sqlite3.c /^#define OP_Close /;" d file: +OP_CollSeq testdocs/sqlite3.c /^#define OP_CollSeq /;" d file: +OP_Column testdocs/sqlite3.c /^#define OP_Column /;" d file: +OP_ColumnsUsed testdocs/sqlite3.c /^#define OP_ColumnsUsed /;" d file: +OP_Compare testdocs/sqlite3.c /^#define OP_Compare /;" d file: +OP_Concat testdocs/sqlite3.c /^#define OP_Concat /;" d file: +OP_Copy testdocs/sqlite3.c /^#define OP_Copy /;" d file: +OP_Count testdocs/sqlite3.c /^#define OP_Count /;" d file: +OP_CreateIndex testdocs/sqlite3.c /^#define OP_CreateIndex /;" d file: +OP_CreateTable testdocs/sqlite3.c /^#define OP_CreateTable /;" d file: +OP_CursorHint testdocs/sqlite3.c /^#define OP_CursorHint /;" d file: +OP_DecrJumpZero testdocs/sqlite3.c /^#define OP_DecrJumpZero /;" d file: +OP_Delete testdocs/sqlite3.c /^#define OP_Delete /;" d file: +OP_Destroy testdocs/sqlite3.c /^#define OP_Destroy /;" d file: +OP_Divide testdocs/sqlite3.c /^#define OP_Divide /;" d file: +OP_DropIndex testdocs/sqlite3.c /^#define OP_DropIndex /;" d file: +OP_DropTable testdocs/sqlite3.c /^#define OP_DropTable /;" d file: +OP_DropTrigger testdocs/sqlite3.c /^#define OP_DropTrigger /;" d file: +OP_ElseNotEq testdocs/sqlite3.c /^#define OP_ElseNotEq /;" d file: +OP_EndCoroutine testdocs/sqlite3.c /^#define OP_EndCoroutine /;" d file: +OP_Eq testdocs/sqlite3.c /^#define OP_Eq /;" d file: +OP_Expire testdocs/sqlite3.c /^#define OP_Expire /;" d file: +OP_Explain testdocs/sqlite3.c /^#define OP_Explain /;" d file: +OP_FkCounter testdocs/sqlite3.c /^#define OP_FkCounter /;" d file: +OP_FkIfZero testdocs/sqlite3.c /^#define OP_FkIfZero /;" d file: +OP_Found testdocs/sqlite3.c /^#define OP_Found /;" d file: +OP_Function testdocs/sqlite3.c /^#define OP_Function /;" d file: +OP_Function0 testdocs/sqlite3.c /^#define OP_Function0 /;" d file: +OP_Ge testdocs/sqlite3.c /^#define OP_Ge /;" d file: +OP_Gosub testdocs/sqlite3.c /^#define OP_Gosub /;" d file: +OP_Goto testdocs/sqlite3.c /^#define OP_Goto /;" d file: +OP_Gt testdocs/sqlite3.c /^#define OP_Gt /;" d file: +OP_Halt testdocs/sqlite3.c /^#define OP_Halt /;" d file: +OP_HaltIfNull testdocs/sqlite3.c /^#define OP_HaltIfNull /;" d file: +OP_IdxDelete testdocs/sqlite3.c /^#define OP_IdxDelete /;" d file: +OP_IdxGE testdocs/sqlite3.c /^#define OP_IdxGE /;" d file: +OP_IdxGT testdocs/sqlite3.c /^#define OP_IdxGT /;" d file: +OP_IdxInsert testdocs/sqlite3.c /^#define OP_IdxInsert /;" d file: +OP_IdxLE testdocs/sqlite3.c /^#define OP_IdxLE /;" d file: +OP_IdxLT testdocs/sqlite3.c /^#define OP_IdxLT /;" d file: +OP_IdxRowid testdocs/sqlite3.c /^#define OP_IdxRowid /;" d file: +OP_If testdocs/sqlite3.c /^#define OP_If /;" d file: +OP_IfNot testdocs/sqlite3.c /^#define OP_IfNot /;" d file: +OP_IfNotZero testdocs/sqlite3.c /^#define OP_IfNotZero /;" d file: +OP_IfNullRow testdocs/sqlite3.c /^#define OP_IfNullRow /;" d file: +OP_IfPos testdocs/sqlite3.c /^#define OP_IfPos /;" d file: +OP_IfSmaller testdocs/sqlite3.c /^#define OP_IfSmaller /;" d file: +OP_IncrVacuum testdocs/sqlite3.c /^#define OP_IncrVacuum /;" d file: +OP_Init testdocs/sqlite3.c /^#define OP_Init /;" d file: +OP_InitCoroutine testdocs/sqlite3.c /^#define OP_InitCoroutine /;" d file: +OP_Insert testdocs/sqlite3.c /^#define OP_Insert /;" d file: +OP_InsertInt testdocs/sqlite3.c /^#define OP_InsertInt /;" d file: +OP_Int64 testdocs/sqlite3.c /^#define OP_Int64 /;" d file: +OP_IntCopy testdocs/sqlite3.c /^#define OP_IntCopy /;" d file: +OP_Integer testdocs/sqlite3.c /^#define OP_Integer /;" d file: +OP_IntegrityCk testdocs/sqlite3.c /^#define OP_IntegrityCk /;" d file: +OP_IsNull testdocs/sqlite3.c /^#define OP_IsNull /;" d file: +OP_JournalMode testdocs/sqlite3.c /^#define OP_JournalMode /;" d file: +OP_Jump testdocs/sqlite3.c /^#define OP_Jump /;" d file: +OP_Last testdocs/sqlite3.c /^#define OP_Last /;" d file: +OP_Le testdocs/sqlite3.c /^#define OP_Le /;" d file: +OP_LoadAnalysis testdocs/sqlite3.c /^#define OP_LoadAnalysis /;" d file: +OP_Lt testdocs/sqlite3.c /^#define OP_Lt /;" d file: +OP_MakeRecord testdocs/sqlite3.c /^#define OP_MakeRecord /;" d file: +OP_MaxPgcnt testdocs/sqlite3.c /^#define OP_MaxPgcnt /;" d file: +OP_MemMax testdocs/sqlite3.c /^#define OP_MemMax /;" d file: +OP_Move testdocs/sqlite3.c /^#define OP_Move /;" d file: +OP_Multiply testdocs/sqlite3.c /^#define OP_Multiply /;" d file: +OP_MustBeInt testdocs/sqlite3.c /^#define OP_MustBeInt /;" d file: +OP_Ne testdocs/sqlite3.c /^#define OP_Ne /;" d file: +OP_NewRowid testdocs/sqlite3.c /^#define OP_NewRowid /;" d file: +OP_Next testdocs/sqlite3.c /^#define OP_Next /;" d file: +OP_NextIfOpen testdocs/sqlite3.c /^#define OP_NextIfOpen /;" d file: +OP_NoConflict testdocs/sqlite3.c /^#define OP_NoConflict /;" d file: +OP_Noop testdocs/sqlite3.c /^#define OP_Noop /;" d file: +OP_Not testdocs/sqlite3.c /^#define OP_Not /;" d file: +OP_NotExists testdocs/sqlite3.c /^#define OP_NotExists /;" d file: +OP_NotFound testdocs/sqlite3.c /^#define OP_NotFound /;" d file: +OP_NotNull testdocs/sqlite3.c /^#define OP_NotNull /;" d file: +OP_Null testdocs/sqlite3.c /^#define OP_Null /;" d file: +OP_NullRow testdocs/sqlite3.c /^#define OP_NullRow /;" d file: +OP_OffsetLimit testdocs/sqlite3.c /^#define OP_OffsetLimit /;" d file: +OP_Once testdocs/sqlite3.c /^#define OP_Once /;" d file: +OP_OpenAutoindex testdocs/sqlite3.c /^#define OP_OpenAutoindex /;" d file: +OP_OpenDup testdocs/sqlite3.c /^#define OP_OpenDup /;" d file: +OP_OpenEphemeral testdocs/sqlite3.c /^#define OP_OpenEphemeral /;" d file: +OP_OpenPseudo testdocs/sqlite3.c /^#define OP_OpenPseudo /;" d file: +OP_OpenRead testdocs/sqlite3.c /^#define OP_OpenRead /;" d file: +OP_OpenWrite testdocs/sqlite3.c /^#define OP_OpenWrite /;" d file: +OP_Or testdocs/sqlite3.c /^#define OP_Or /;" d file: +OP_Pagecount testdocs/sqlite3.c /^#define OP_Pagecount /;" d file: +OP_Param testdocs/sqlite3.c /^#define OP_Param /;" d file: +OP_ParseSchema testdocs/sqlite3.c /^#define OP_ParseSchema /;" d file: +OP_Permutation testdocs/sqlite3.c /^#define OP_Permutation /;" d file: +OP_Prev testdocs/sqlite3.c /^#define OP_Prev /;" d file: +OP_PrevIfOpen testdocs/sqlite3.c /^#define OP_PrevIfOpen /;" d file: +OP_Program testdocs/sqlite3.c /^#define OP_Program /;" d file: +OP_ReadCookie testdocs/sqlite3.c /^#define OP_ReadCookie /;" d file: +OP_Real testdocs/sqlite3.c /^#define OP_Real /;" d file: +OP_RealAffinity testdocs/sqlite3.c /^#define OP_RealAffinity /;" d file: +OP_Remainder testdocs/sqlite3.c /^#define OP_Remainder /;" d file: +OP_ReopenIdx testdocs/sqlite3.c /^#define OP_ReopenIdx /;" d file: +OP_ResetCount testdocs/sqlite3.c /^#define OP_ResetCount /;" d file: +OP_ResetSorter testdocs/sqlite3.c /^#define OP_ResetSorter /;" d file: +OP_ResultRow testdocs/sqlite3.c /^#define OP_ResultRow /;" d file: +OP_Return testdocs/sqlite3.c /^#define OP_Return /;" d file: +OP_Rewind testdocs/sqlite3.c /^#define OP_Rewind /;" d file: +OP_RowData testdocs/sqlite3.c /^#define OP_RowData /;" d file: +OP_RowSetAdd testdocs/sqlite3.c /^#define OP_RowSetAdd /;" d file: +OP_RowSetRead testdocs/sqlite3.c /^#define OP_RowSetRead /;" d file: +OP_RowSetTest testdocs/sqlite3.c /^#define OP_RowSetTest /;" d file: +OP_Rowid testdocs/sqlite3.c /^#define OP_Rowid /;" d file: +OP_SCopy testdocs/sqlite3.c /^#define OP_SCopy /;" d file: +OP_Savepoint testdocs/sqlite3.c /^#define OP_Savepoint /;" d file: +OP_Seek testdocs/sqlite3.c /^#define OP_Seek /;" d file: +OP_SeekGE testdocs/sqlite3.c /^#define OP_SeekGE /;" d file: +OP_SeekGT testdocs/sqlite3.c /^#define OP_SeekGT /;" d file: +OP_SeekLE testdocs/sqlite3.c /^#define OP_SeekLE /;" d file: +OP_SeekLT testdocs/sqlite3.c /^#define OP_SeekLT /;" d file: +OP_SeekRowid testdocs/sqlite3.c /^#define OP_SeekRowid /;" d file: +OP_Sequence testdocs/sqlite3.c /^#define OP_Sequence /;" d file: +OP_SequenceTest testdocs/sqlite3.c /^#define OP_SequenceTest /;" d file: +OP_SetCookie testdocs/sqlite3.c /^#define OP_SetCookie /;" d file: +OP_ShiftLeft testdocs/sqlite3.c /^#define OP_ShiftLeft /;" d file: +OP_ShiftRight testdocs/sqlite3.c /^#define OP_ShiftRight /;" d file: +OP_SoftNull testdocs/sqlite3.c /^#define OP_SoftNull /;" d file: +OP_Sort testdocs/sqlite3.c /^#define OP_Sort /;" d file: +OP_SorterCompare testdocs/sqlite3.c /^#define OP_SorterCompare /;" d file: +OP_SorterData testdocs/sqlite3.c /^#define OP_SorterData /;" d file: +OP_SorterInsert testdocs/sqlite3.c /^#define OP_SorterInsert /;" d file: +OP_SorterNext testdocs/sqlite3.c /^#define OP_SorterNext /;" d file: +OP_SorterOpen testdocs/sqlite3.c /^#define OP_SorterOpen /;" d file: +OP_SorterSort testdocs/sqlite3.c /^#define OP_SorterSort /;" d file: +OP_SqlExec testdocs/sqlite3.c /^#define OP_SqlExec /;" d file: +OP_String testdocs/sqlite3.c /^#define OP_String /;" d file: +OP_String8 testdocs/sqlite3.c /^#define OP_String8 /;" d file: +OP_Subtract testdocs/sqlite3.c /^#define OP_Subtract /;" d file: +OP_TableLock testdocs/sqlite3.c /^#define OP_TableLock /;" d file: +OP_Transaction testdocs/sqlite3.c /^#define OP_Transaction /;" d file: +OP_VBegin testdocs/sqlite3.c /^#define OP_VBegin /;" d file: +OP_VColumn testdocs/sqlite3.c /^#define OP_VColumn /;" d file: +OP_VCreate testdocs/sqlite3.c /^#define OP_VCreate /;" d file: +OP_VDestroy testdocs/sqlite3.c /^#define OP_VDestroy /;" d file: +OP_VFilter testdocs/sqlite3.c /^#define OP_VFilter /;" d file: +OP_VNext testdocs/sqlite3.c /^#define OP_VNext /;" d file: +OP_VOpen testdocs/sqlite3.c /^#define OP_VOpen /;" d file: +OP_VRename testdocs/sqlite3.c /^#define OP_VRename /;" d file: +OP_VUpdate testdocs/sqlite3.c /^#define OP_VUpdate /;" d file: +OP_Vacuum testdocs/sqlite3.c /^#define OP_Vacuum /;" d file: +OP_Variable testdocs/sqlite3.c /^#define OP_Variable /;" d file: +OP_Yield testdocs/sqlite3.c /^#define OP_Yield /;" d file: +OSTRACE testdocs/sqlite3.c /^# define OSTRACE(/;" d file: +OS_VXWORKS testdocs/sqlite3.c /^#define OS_VXWORKS /;" d file: +O_BINARY testdocs/sqlite3.c /^# define O_BINARY /;" d file: +O_LARGEFILE testdocs/sqlite3.c /^# define O_LARGEFILE /;" d file: +O_LARGEFILE testdocs/sqlite3.c /^# undef O_LARGEFILE$/;" d file: +O_NOFOLLOW testdocs/sqlite3.c /^# define O_NOFOLLOW /;" d file: +Op testdocs/sqlite3.c /^typedef struct VdbeOp Op;$/;" t typeref:struct:VdbeOp file: +OpHelp testdocs/sqlite3.c /^# define OpHelp(/;" d file: +OpenCounter testdocs/sqlite3.c /^#define OpenCounter(/;" d file: +OptimizationDisabled testdocs/sqlite3.c /^#define OptimizationDisabled(/;" d file: +OptimizationEnabled testdocs/sqlite3.c /^#define OptimizationEnabled(/;" d file: +P4_ADVANCE testdocs/sqlite3.c /^#define P4_ADVANCE /;" d file: +P4_COLLSEQ testdocs/sqlite3.c /^#define P4_COLLSEQ /;" d file: +P4_DYNAMIC testdocs/sqlite3.c /^#define P4_DYNAMIC /;" d file: +P4_EXPR testdocs/sqlite3.c /^#define P4_EXPR /;" d file: +P4_FUNCCTX testdocs/sqlite3.c /^#define P4_FUNCCTX /;" d file: +P4_FUNCDEF testdocs/sqlite3.c /^#define P4_FUNCDEF /;" d file: +P4_INT32 testdocs/sqlite3.c /^#define P4_INT32 /;" d file: +P4_INT64 testdocs/sqlite3.c /^#define P4_INT64 /;" d file: +P4_INTARRAY testdocs/sqlite3.c /^#define P4_INTARRAY /;" d file: +P4_KEYINFO testdocs/sqlite3.c /^#define P4_KEYINFO /;" d file: +P4_MEM testdocs/sqlite3.c /^#define P4_MEM /;" d file: +P4_NOTUSED testdocs/sqlite3.c /^#define P4_NOTUSED /;" d file: +P4_REAL testdocs/sqlite3.c /^#define P4_REAL /;" d file: +P4_STATIC testdocs/sqlite3.c /^#define P4_STATIC /;" d file: +P4_SUBPROGRAM testdocs/sqlite3.c /^#define P4_SUBPROGRAM /;" d file: +P4_TABLE testdocs/sqlite3.c /^#define P4_TABLE /;" d file: +P4_TRANSIENT testdocs/sqlite3.c /^#define P4_TRANSIENT /;" d file: +P4_VTAB testdocs/sqlite3.c /^#define P4_VTAB /;" d file: +P5_ConstraintCheck testdocs/sqlite3.c /^#define P5_ConstraintCheck /;" d file: +P5_ConstraintFK testdocs/sqlite3.c /^#define P5_ConstraintFK /;" d file: +P5_ConstraintNotNull testdocs/sqlite3.c /^#define P5_ConstraintNotNull /;" d file: +P5_ConstraintUnique testdocs/sqlite3.c /^#define P5_ConstraintUnique /;" d file: +PAGERID testdocs/sqlite3.c /^#define PAGERID(/;" d file: +PAGERTRACE testdocs/sqlite3.c /^#define PAGERTRACE(/;" d file: +PAGER_CACHESPILL testdocs/sqlite3.c /^#define PAGER_CACHESPILL /;" d file: +PAGER_CKPT_FULLFSYNC testdocs/sqlite3.c /^#define PAGER_CKPT_FULLFSYNC /;" d file: +PAGER_ERROR testdocs/sqlite3.c /^#define PAGER_ERROR /;" d file: +PAGER_FLAGS_MASK testdocs/sqlite3.c /^#define PAGER_FLAGS_MASK /;" d file: +PAGER_FULLFSYNC testdocs/sqlite3.c /^#define PAGER_FULLFSYNC /;" d file: +PAGER_GET_NOCONTENT testdocs/sqlite3.c /^#define PAGER_GET_NOCONTENT /;" d file: +PAGER_GET_READONLY testdocs/sqlite3.c /^#define PAGER_GET_READONLY /;" d file: +PAGER_INCR testdocs/sqlite3.c /^# define PAGER_INCR(/;" d file: +PAGER_JOURNALMODE_DELETE testdocs/sqlite3.c /^#define PAGER_JOURNALMODE_DELETE /;" d file: +PAGER_JOURNALMODE_MEMORY testdocs/sqlite3.c /^#define PAGER_JOURNALMODE_MEMORY /;" d file: +PAGER_JOURNALMODE_OFF testdocs/sqlite3.c /^#define PAGER_JOURNALMODE_OFF /;" d file: +PAGER_JOURNALMODE_PERSIST testdocs/sqlite3.c /^#define PAGER_JOURNALMODE_PERSIST /;" d file: +PAGER_JOURNALMODE_QUERY testdocs/sqlite3.c /^#define PAGER_JOURNALMODE_QUERY /;" d file: +PAGER_JOURNALMODE_TRUNCATE testdocs/sqlite3.c /^#define PAGER_JOURNALMODE_TRUNCATE /;" d file: +PAGER_JOURNALMODE_WAL testdocs/sqlite3.c /^#define PAGER_JOURNALMODE_WAL /;" d file: +PAGER_LOCKINGMODE_EXCLUSIVE testdocs/sqlite3.c /^#define PAGER_LOCKINGMODE_EXCLUSIVE /;" d file: +PAGER_LOCKINGMODE_NORMAL testdocs/sqlite3.c /^#define PAGER_LOCKINGMODE_NORMAL /;" d file: +PAGER_LOCKINGMODE_QUERY testdocs/sqlite3.c /^#define PAGER_LOCKINGMODE_QUERY /;" d file: +PAGER_MAX_PGNO testdocs/sqlite3.c /^#define PAGER_MAX_PGNO /;" d file: +PAGER_MEMORY testdocs/sqlite3.c /^#define PAGER_MEMORY /;" d file: +PAGER_MJ_PGNO testdocs/sqlite3.c /^#define PAGER_MJ_PGNO(/;" d file: +PAGER_OMIT_JOURNAL testdocs/sqlite3.c /^#define PAGER_OMIT_JOURNAL /;" d file: +PAGER_OPEN testdocs/sqlite3.c /^#define PAGER_OPEN /;" d file: +PAGER_READER testdocs/sqlite3.c /^#define PAGER_READER /;" d file: +PAGER_STAT_HIT testdocs/sqlite3.c /^#define PAGER_STAT_HIT /;" d file: +PAGER_STAT_MISS testdocs/sqlite3.c /^#define PAGER_STAT_MISS /;" d file: +PAGER_STAT_WRITE testdocs/sqlite3.c /^#define PAGER_STAT_WRITE /;" d file: +PAGER_SYNCHRONOUS_EXTRA testdocs/sqlite3.c /^#define PAGER_SYNCHRONOUS_EXTRA /;" d file: +PAGER_SYNCHRONOUS_FULL testdocs/sqlite3.c /^#define PAGER_SYNCHRONOUS_FULL /;" d file: +PAGER_SYNCHRONOUS_MASK testdocs/sqlite3.c /^#define PAGER_SYNCHRONOUS_MASK /;" d file: +PAGER_SYNCHRONOUS_NORMAL testdocs/sqlite3.c /^#define PAGER_SYNCHRONOUS_NORMAL /;" d file: +PAGER_SYNCHRONOUS_OFF testdocs/sqlite3.c /^#define PAGER_SYNCHRONOUS_OFF /;" d file: +PAGER_WRITER_CACHEMOD testdocs/sqlite3.c /^#define PAGER_WRITER_CACHEMOD /;" d file: +PAGER_WRITER_DBMOD testdocs/sqlite3.c /^#define PAGER_WRITER_DBMOD /;" d file: +PAGER_WRITER_FINISHED testdocs/sqlite3.c /^#define PAGER_WRITER_FINISHED /;" d file: +PAGER_WRITER_LOCKED testdocs/sqlite3.c /^#define PAGER_WRITER_LOCKED /;" d file: +PARSE_HDR_SZ testdocs/sqlite3.c /^#define PARSE_HDR_SZ /;" d file: +PARSE_RECURSE_SZ testdocs/sqlite3.c /^#define PARSE_RECURSE_SZ /;" d file: +PARSE_TAIL testdocs/sqlite3.c /^#define PARSE_TAIL(/;" d file: +PARSE_TAIL_SZ testdocs/sqlite3.c /^#define PARSE_TAIL_SZ /;" d file: +PARTLY_WITHIN testdocs/sqlite3.c /^#define PARTLY_WITHIN /;" d file: +PCACHE1_MIGHT_USE_GROUP_MUTEX testdocs/sqlite3.c /^# define PCACHE1_MIGHT_USE_GROUP_MUTEX /;" d file: +PCACHE_DIRTYLIST_ADD testdocs/sqlite3.c /^#define PCACHE_DIRTYLIST_ADD /;" d file: +PCACHE_DIRTYLIST_FRONT testdocs/sqlite3.c /^#define PCACHE_DIRTYLIST_FRONT /;" d file: +PCACHE_DIRTYLIST_REMOVE testdocs/sqlite3.c /^#define PCACHE_DIRTYLIST_REMOVE /;" d file: +PCache testdocs/sqlite3.c /^struct PCache {$/;" s file: +PCache testdocs/sqlite3.c /^typedef struct PCache PCache;$/;" t typeref:struct:PCache file: +PCache1 testdocs/sqlite3.c /^struct PCache1 {$/;" s file: +PCache1 testdocs/sqlite3.c /^typedef struct PCache1 PCache1;$/;" t typeref:struct:PCache1 file: +PCacheGlobal testdocs/sqlite3.c /^static SQLITE_WSD struct PCacheGlobal {$/;" s file: +PENDING_BYTE testdocs/sqlite3.c /^# define PENDING_BYTE /;" d file: +PENDING_BYTE_PAGE testdocs/sqlite3.c /^# define PENDING_BYTE_PAGE(/;" d file: +PENDING_LOCK testdocs/sqlite3.c /^#define PENDING_LOCK /;" d file: +PGHDR_CLEAN testdocs/sqlite3.c /^#define PGHDR_CLEAN /;" d file: +PGHDR_DIRTY testdocs/sqlite3.c /^#define PGHDR_DIRTY /;" d file: +PGHDR_DONT_WRITE testdocs/sqlite3.c /^#define PGHDR_DONT_WRITE /;" d file: +PGHDR_MMAP testdocs/sqlite3.c /^#define PGHDR_MMAP /;" d file: +PGHDR_NEED_SYNC testdocs/sqlite3.c /^#define PGHDR_NEED_SYNC /;" d file: +PGHDR_WAL_APPEND testdocs/sqlite3.c /^#define PGHDR_WAL_APPEND /;" d file: +PGHDR_WRITEABLE testdocs/sqlite3.c /^#define PGHDR_WRITEABLE /;" d file: +PGroup testdocs/sqlite3.c /^struct PGroup {$/;" s file: +PGroup testdocs/sqlite3.c /^typedef struct PGroup PGroup;$/;" t typeref:struct:PGroup file: +POSITION_LIST_END testdocs/sqlite3.c /^#define POSITION_LIST_END /;" d file: +POS_COLUMN testdocs/sqlite3.c /^#define POS_COLUMN /;" d file: +POS_END testdocs/sqlite3.c /^#define POS_END /;" d file: +PRINT_TEST_RESULTS atf.h /^#define PRINT_TEST_RESULTS /;" d +PROXY_CONCHVERSION testdocs/sqlite3.c /^#define PROXY_CONCHVERSION /;" d file: +PROXY_HEADERLEN testdocs/sqlite3.c /^#define PROXY_HEADERLEN /;" d file: +PROXY_HOSTIDLEN testdocs/sqlite3.c /^#define PROXY_HOSTIDLEN /;" d file: +PROXY_MAXCONCHLEN testdocs/sqlite3.c /^#define PROXY_MAXCONCHLEN /;" d file: +PROXY_PATHINDEX testdocs/sqlite3.c /^#define PROXY_PATHINDEX /;" d file: +PTF_INTKEY testdocs/sqlite3.c /^#define PTF_INTKEY /;" d file: +PTF_LEAF testdocs/sqlite3.c /^#define PTF_LEAF /;" d file: +PTF_LEAFDATA testdocs/sqlite3.c /^#define PTF_LEAFDATA /;" d file: +PTF_ZERODATA testdocs/sqlite3.c /^#define PTF_ZERODATA /;" d file: +PTRMAP_BTREE testdocs/sqlite3.c /^#define PTRMAP_BTREE /;" d file: +PTRMAP_FREEPAGE testdocs/sqlite3.c /^#define PTRMAP_FREEPAGE /;" d file: +PTRMAP_ISPAGE testdocs/sqlite3.c /^#define PTRMAP_ISPAGE(/;" d file: +PTRMAP_OVERFLOW1 testdocs/sqlite3.c /^#define PTRMAP_OVERFLOW1 /;" d file: +PTRMAP_OVERFLOW2 testdocs/sqlite3.c /^#define PTRMAP_OVERFLOW2 /;" d file: +PTRMAP_PAGENO testdocs/sqlite3.c /^#define PTRMAP_PAGENO(/;" d file: +PTRMAP_PTROFFSET testdocs/sqlite3.c /^#define PTRMAP_PTROFFSET(/;" d file: +PTRMAP_ROOTPAGE testdocs/sqlite3.c /^#define PTRMAP_ROOTPAGE /;" d file: +Pager testdocs/sqlite3.c /^struct Pager {$/;" s file: +Pager testdocs/sqlite3.c /^typedef struct Pager Pager;$/;" t typeref:struct:Pager file: +PagerSavepoint testdocs/sqlite3.c /^struct PagerSavepoint {$/;" s file: +PagerSavepoint testdocs/sqlite3.c /^typedef struct PagerSavepoint PagerSavepoint;$/;" t typeref:struct:PagerSavepoint file: +Parse testdocs/sqlite3.c /^struct Parse {$/;" s file: +Parse testdocs/sqlite3.c /^typedef struct Parse Parse;$/;" t typeref:struct:Parse file: +ParseContext testdocs/sqlite3.c /^struct ParseContext {$/;" s file: +ParseContext testdocs/sqlite3.c /^typedef struct ParseContext ParseContext;$/;" t typeref:struct:ParseContext file: +PendingList testdocs/sqlite3.c /^struct PendingList {$/;" s file: +PendingList testdocs/sqlite3.c /^typedef struct PendingList PendingList;$/;" t typeref:struct:PendingList file: +PgFreeslot testdocs/sqlite3.c /^struct PgFreeslot {$/;" s file: +PgFreeslot testdocs/sqlite3.c /^typedef struct PgFreeslot PgFreeslot;$/;" t typeref:struct:PgFreeslot file: +PgHdr testdocs/sqlite3.c /^struct PgHdr {$/;" s file: +PgHdr testdocs/sqlite3.c /^typedef struct PgHdr PgHdr;$/;" t typeref:struct:PgHdr file: +PgHdr1 testdocs/sqlite3.c /^struct PgHdr1 {$/;" s file: +PgHdr1 testdocs/sqlite3.c /^typedef struct PgHdr1 PgHdr1;$/;" t typeref:struct:PgHdr1 file: +Pgno testdocs/sqlite3.c /^typedef u32 Pgno;$/;" t file: +PmaReader testdocs/sqlite3.c /^struct PmaReader {$/;" s file: +PmaReader testdocs/sqlite3.c /^typedef struct PmaReader PmaReader; \/* Incrementally read one PMA *\/$/;" t typeref:struct:PmaReader file: +PmaWriter testdocs/sqlite3.c /^struct PmaWriter {$/;" s file: +PmaWriter testdocs/sqlite3.c /^typedef struct PmaWriter PmaWriter; \/* Incrementally write one PMA *\/$/;" t typeref:struct:PmaWriter file: +PorterContext testdocs/sqlite3.c /^struct PorterContext {$/;" s file: +PorterContext testdocs/sqlite3.c /^typedef struct PorterContext PorterContext;$/;" t typeref:struct:PorterContext file: +PorterRule testdocs/sqlite3.c /^struct PorterRule {$/;" s file: +PorterRule testdocs/sqlite3.c /^typedef struct PorterRule PorterRule;$/;" t typeref:struct:PorterRule file: +PorterTokenizer testdocs/sqlite3.c /^struct PorterTokenizer {$/;" s file: +PorterTokenizer testdocs/sqlite3.c /^typedef struct PorterTokenizer PorterTokenizer;$/;" t typeref:struct:PorterTokenizer file: +PoslistCallbackCtx testdocs/sqlite3.c /^struct PoslistCallbackCtx {$/;" s file: +PoslistCallbackCtx testdocs/sqlite3.c /^typedef struct PoslistCallbackCtx PoslistCallbackCtx;$/;" t typeref:struct:PoslistCallbackCtx file: +PoslistOffsetsCtx testdocs/sqlite3.c /^struct PoslistOffsetsCtx {$/;" s file: +PoslistOffsetsCtx testdocs/sqlite3.c /^typedef struct PoslistOffsetsCtx PoslistOffsetsCtx;$/;" t typeref:struct:PoslistOffsetsCtx file: +PragFlg_NeedSchema testdocs/sqlite3.c /^#define PragFlg_NeedSchema /;" d file: +PragFlg_NoColumns testdocs/sqlite3.c /^#define PragFlg_NoColumns /;" d file: +PragFlg_NoColumns1 testdocs/sqlite3.c /^#define PragFlg_NoColumns1 /;" d file: +PragFlg_ReadOnly testdocs/sqlite3.c /^#define PragFlg_ReadOnly /;" d file: +PragFlg_Result0 testdocs/sqlite3.c /^#define PragFlg_Result0 /;" d file: +PragFlg_Result1 testdocs/sqlite3.c /^#define PragFlg_Result1 /;" d file: +PragFlg_SchemaOpt testdocs/sqlite3.c /^#define PragFlg_SchemaOpt /;" d file: +PragFlg_SchemaReq testdocs/sqlite3.c /^#define PragFlg_SchemaReq /;" d file: +PragTyp_ACTIVATE_EXTENSIONS testdocs/sqlite3.c /^#define PragTyp_ACTIVATE_EXTENSIONS /;" d file: +PragTyp_AUTO_VACUUM testdocs/sqlite3.c /^#define PragTyp_AUTO_VACUUM /;" d file: +PragTyp_BUSY_TIMEOUT testdocs/sqlite3.c /^#define PragTyp_BUSY_TIMEOUT /;" d file: +PragTyp_CACHE_SIZE testdocs/sqlite3.c /^#define PragTyp_CACHE_SIZE /;" d file: +PragTyp_CACHE_SPILL testdocs/sqlite3.c /^#define PragTyp_CACHE_SPILL /;" d file: +PragTyp_CASE_SENSITIVE_LIKE testdocs/sqlite3.c /^#define PragTyp_CASE_SENSITIVE_LIKE /;" d file: +PragTyp_COLLATION_LIST testdocs/sqlite3.c /^#define PragTyp_COLLATION_LIST /;" d file: +PragTyp_COMPILE_OPTIONS testdocs/sqlite3.c /^#define PragTyp_COMPILE_OPTIONS /;" d file: +PragTyp_DATABASE_LIST testdocs/sqlite3.c /^#define PragTyp_DATABASE_LIST /;" d file: +PragTyp_DATA_STORE_DIRECTORY testdocs/sqlite3.c /^#define PragTyp_DATA_STORE_DIRECTORY /;" d file: +PragTyp_DEFAULT_CACHE_SIZE testdocs/sqlite3.c /^#define PragTyp_DEFAULT_CACHE_SIZE /;" d file: +PragTyp_ENCODING testdocs/sqlite3.c /^#define PragTyp_ENCODING /;" d file: +PragTyp_FLAG testdocs/sqlite3.c /^#define PragTyp_FLAG /;" d file: +PragTyp_FOREIGN_KEY_CHECK testdocs/sqlite3.c /^#define PragTyp_FOREIGN_KEY_CHECK /;" d file: +PragTyp_FOREIGN_KEY_LIST testdocs/sqlite3.c /^#define PragTyp_FOREIGN_KEY_LIST /;" d file: +PragTyp_HEADER_VALUE testdocs/sqlite3.c /^#define PragTyp_HEADER_VALUE /;" d file: +PragTyp_HEXKEY testdocs/sqlite3.c /^#define PragTyp_HEXKEY /;" d file: +PragTyp_INCREMENTAL_VACUUM testdocs/sqlite3.c /^#define PragTyp_INCREMENTAL_VACUUM /;" d file: +PragTyp_INDEX_INFO testdocs/sqlite3.c /^#define PragTyp_INDEX_INFO /;" d file: +PragTyp_INDEX_LIST testdocs/sqlite3.c /^#define PragTyp_INDEX_LIST /;" d file: +PragTyp_INTEGRITY_CHECK testdocs/sqlite3.c /^#define PragTyp_INTEGRITY_CHECK /;" d file: +PragTyp_JOURNAL_MODE testdocs/sqlite3.c /^#define PragTyp_JOURNAL_MODE /;" d file: +PragTyp_JOURNAL_SIZE_LIMIT testdocs/sqlite3.c /^#define PragTyp_JOURNAL_SIZE_LIMIT /;" d file: +PragTyp_KEY testdocs/sqlite3.c /^#define PragTyp_KEY /;" d file: +PragTyp_LOCKING_MODE testdocs/sqlite3.c /^#define PragTyp_LOCKING_MODE /;" d file: +PragTyp_LOCK_PROXY_FILE testdocs/sqlite3.c /^#define PragTyp_LOCK_PROXY_FILE /;" d file: +PragTyp_LOCK_STATUS testdocs/sqlite3.c /^#define PragTyp_LOCK_STATUS /;" d file: +PragTyp_MMAP_SIZE testdocs/sqlite3.c /^#define PragTyp_MMAP_SIZE /;" d file: +PragTyp_OPTIMIZE testdocs/sqlite3.c /^#define PragTyp_OPTIMIZE /;" d file: +PragTyp_PAGE_COUNT testdocs/sqlite3.c /^#define PragTyp_PAGE_COUNT /;" d file: +PragTyp_PAGE_SIZE testdocs/sqlite3.c /^#define PragTyp_PAGE_SIZE /;" d file: +PragTyp_PARSER_TRACE testdocs/sqlite3.c /^#define PragTyp_PARSER_TRACE /;" d file: +PragTyp_REKEY testdocs/sqlite3.c /^#define PragTyp_REKEY /;" d file: +PragTyp_SECURE_DELETE testdocs/sqlite3.c /^#define PragTyp_SECURE_DELETE /;" d file: +PragTyp_SHRINK_MEMORY testdocs/sqlite3.c /^#define PragTyp_SHRINK_MEMORY /;" d file: +PragTyp_SOFT_HEAP_LIMIT testdocs/sqlite3.c /^#define PragTyp_SOFT_HEAP_LIMIT /;" d file: +PragTyp_STATS testdocs/sqlite3.c /^#define PragTyp_STATS /;" d file: +PragTyp_SYNCHRONOUS testdocs/sqlite3.c /^#define PragTyp_SYNCHRONOUS /;" d file: +PragTyp_TABLE_INFO testdocs/sqlite3.c /^#define PragTyp_TABLE_INFO /;" d file: +PragTyp_TEMP_STORE testdocs/sqlite3.c /^#define PragTyp_TEMP_STORE /;" d file: +PragTyp_TEMP_STORE_DIRECTORY testdocs/sqlite3.c /^#define PragTyp_TEMP_STORE_DIRECTORY /;" d file: +PragTyp_THREADS testdocs/sqlite3.c /^#define PragTyp_THREADS /;" d file: +PragTyp_WAL_AUTOCHECKPOINT testdocs/sqlite3.c /^#define PragTyp_WAL_AUTOCHECKPOINT /;" d file: +PragTyp_WAL_CHECKPOINT testdocs/sqlite3.c /^#define PragTyp_WAL_CHECKPOINT /;" d file: +PragmaName testdocs/sqlite3.c /^typedef struct PragmaName {$/;" s file: +PragmaName testdocs/sqlite3.c /^} PragmaName;$/;" t typeref:struct:PragmaName file: +PragmaVtab testdocs/sqlite3.c /^struct PragmaVtab {$/;" s file: +PragmaVtab testdocs/sqlite3.c /^typedef struct PragmaVtab PragmaVtab;$/;" t typeref:struct:PragmaVtab file: +PragmaVtabCursor testdocs/sqlite3.c /^struct PragmaVtabCursor {$/;" s file: +PragmaVtabCursor testdocs/sqlite3.c /^typedef struct PragmaVtabCursor PragmaVtabCursor;$/;" t typeref:struct:PragmaVtabCursor file: +PreUpdate testdocs/sqlite3.c /^struct PreUpdate {$/;" s file: +PreUpdate testdocs/sqlite3.c /^typedef struct PreUpdate PreUpdate;$/;" t typeref:struct:PreUpdate file: +PrintfArguments testdocs/sqlite3.c /^struct PrintfArguments {$/;" s file: +PrintfArguments testdocs/sqlite3.c /^typedef struct PrintfArguments PrintfArguments;$/;" t typeref:struct:PrintfArguments file: +RBU_CREATE_STATE testdocs/sqlite3.c /^#define RBU_CREATE_STATE /;" d file: +RBU_DELETE testdocs/sqlite3.c /^#define RBU_DELETE /;" d file: +RBU_IDX_DELETE testdocs/sqlite3.c /^#define RBU_IDX_DELETE /;" d file: +RBU_IDX_INSERT testdocs/sqlite3.c /^#define RBU_IDX_INSERT /;" d file: +RBU_INSERT testdocs/sqlite3.c /^#define RBU_INSERT /;" d file: +RBU_PK_EXTERNAL testdocs/sqlite3.c /^#define RBU_PK_EXTERNAL /;" d file: +RBU_PK_IPK testdocs/sqlite3.c /^#define RBU_PK_IPK /;" d file: +RBU_PK_NONE testdocs/sqlite3.c /^#define RBU_PK_NONE /;" d file: +RBU_PK_NOTABLE testdocs/sqlite3.c /^#define RBU_PK_NOTABLE /;" d file: +RBU_PK_VTAB testdocs/sqlite3.c /^#define RBU_PK_VTAB /;" d file: +RBU_PK_WITHOUT_ROWID testdocs/sqlite3.c /^#define RBU_PK_WITHOUT_ROWID /;" d file: +RBU_REPLACE testdocs/sqlite3.c /^#define RBU_REPLACE /;" d file: +RBU_STAGE_CAPTURE testdocs/sqlite3.c /^#define RBU_STAGE_CAPTURE /;" d file: +RBU_STAGE_CKPT testdocs/sqlite3.c /^#define RBU_STAGE_CKPT /;" d file: +RBU_STAGE_DONE testdocs/sqlite3.c /^#define RBU_STAGE_DONE /;" d file: +RBU_STAGE_MOVE testdocs/sqlite3.c /^#define RBU_STAGE_MOVE /;" d file: +RBU_STAGE_OAL testdocs/sqlite3.c /^#define RBU_STAGE_OAL /;" d file: +RBU_STATE_CKPT testdocs/sqlite3.c /^#define RBU_STATE_CKPT /;" d file: +RBU_STATE_COOKIE testdocs/sqlite3.c /^#define RBU_STATE_COOKIE /;" d file: +RBU_STATE_IDX testdocs/sqlite3.c /^#define RBU_STATE_IDX /;" d file: +RBU_STATE_OALSZ testdocs/sqlite3.c /^#define RBU_STATE_OALSZ /;" d file: +RBU_STATE_PHASEONESTEP testdocs/sqlite3.c /^#define RBU_STATE_PHASEONESTEP /;" d file: +RBU_STATE_PROGRESS testdocs/sqlite3.c /^#define RBU_STATE_PROGRESS /;" d file: +RBU_STATE_ROW testdocs/sqlite3.c /^#define RBU_STATE_ROW /;" d file: +RBU_STATE_STAGE testdocs/sqlite3.c /^#define RBU_STATE_STAGE /;" d file: +RBU_STATE_TBL testdocs/sqlite3.c /^#define RBU_STATE_TBL /;" d file: +RBU_UPDATE testdocs/sqlite3.c /^#define RBU_UPDATE /;" d file: +READMARK_NOT_USED testdocs/sqlite3.c /^#define READMARK_NOT_USED /;" d file: +READ_LOCK testdocs/sqlite3.c /^#define READ_LOCK /;" d file: +READ_UTF16BE testdocs/sqlite3.c /^#define READ_UTF16BE(/;" d file: +READ_UTF16LE testdocs/sqlite3.c /^#define READ_UTF16LE(/;" d file: +READ_UTF8 testdocs/sqlite3.c /^#define READ_UTF8(/;" d file: +REARGUARD testdocs/sqlite3.c /^#define REARGUARD /;" d file: +REGISTER_TRACE testdocs/sqlite3.c /^# define REGISTER_TRACE(/;" d file: +RESERVED_BYTE testdocs/sqlite3.c /^#define RESERVED_BYTE /;" d file: +RESERVED_LOCK testdocs/sqlite3.c /^#define RESERVED_LOCK /;" d file: +REVISION testdocs/waf /^REVISION="f34901f5b68face907b47c9bd9abce84"$/;" v +RIGHT edit.h /^ RIGHT = +1,$/;" e enum:__anon7 +RNDAWAY testdocs/sqlite3.c /^#define RNDAWAY /;" d file: +RNDTOWARDS testdocs/sqlite3.c /^#define RNDTOWARDS /;" d file: +ROUND8 testdocs/sqlite3.c /^#define ROUND8(/;" d file: +ROUNDDOWN8 testdocs/sqlite3.c /^#define ROUNDDOWN8(/;" d file: +ROWSET_ALLOCATION_SIZE testdocs/sqlite3.c /^#define ROWSET_ALLOCATION_SIZE /;" d file: +ROWSET_ENTRY_PER_CHUNK testdocs/sqlite3.c /^#define ROWSET_ENTRY_PER_CHUNK /;" d file: +ROWSET_NEXT testdocs/sqlite3.c /^#define ROWSET_NEXT /;" d file: +ROWSET_SORTED testdocs/sqlite3.c /^#define ROWSET_SORTED /;" d file: +RTREE_CACHE_SZ testdocs/sqlite3.c /^#define RTREE_CACHE_SZ /;" d file: +RTREE_COORD_INT32 testdocs/sqlite3.c /^#define RTREE_COORD_INT32 /;" d file: +RTREE_COORD_REAL32 testdocs/sqlite3.c /^#define RTREE_COORD_REAL32 /;" d file: +RTREE_DECODE_COORD testdocs/sqlite3.c /^#define RTREE_DECODE_COORD(/;" d file: +RTREE_DEFAULT_ROWEST testdocs/sqlite3.c /^#define RTREE_DEFAULT_ROWEST /;" d file: +RTREE_EQ testdocs/sqlite3.c /^#define RTREE_EQ /;" d file: +RTREE_GE testdocs/sqlite3.c /^#define RTREE_GE /;" d file: +RTREE_GEOMETRY_MAGIC testdocs/sqlite3.c /^#define RTREE_GEOMETRY_MAGIC /;" d file: +RTREE_GT testdocs/sqlite3.c /^#define RTREE_GT /;" d file: +RTREE_LE testdocs/sqlite3.c /^#define RTREE_LE /;" d file: +RTREE_LT testdocs/sqlite3.c /^#define RTREE_LT /;" d file: +RTREE_MATCH testdocs/sqlite3.c /^#define RTREE_MATCH /;" d file: +RTREE_MAXCELLS testdocs/sqlite3.c /^#define RTREE_MAXCELLS /;" d file: +RTREE_MAX_DEPTH testdocs/sqlite3.c /^#define RTREE_MAX_DEPTH /;" d file: +RTREE_MAX_DIMENSIONS testdocs/sqlite3.c /^#define RTREE_MAX_DIMENSIONS /;" d file: +RTREE_MINCELLS testdocs/sqlite3.c /^#define RTREE_MINCELLS(/;" d file: +RTREE_MIN_ROWEST testdocs/sqlite3.c /^#define RTREE_MIN_ROWEST /;" d file: +RTREE_OF_CURSOR testdocs/sqlite3.c /^#define RTREE_OF_CURSOR(/;" d file: +RTREE_QUERY testdocs/sqlite3.c /^#define RTREE_QUERY /;" d file: +RTREE_QUEUE_TRACE testdocs/sqlite3.c /^# define RTREE_QUEUE_TRACE(/;" d file: +RTREE_REINSERT testdocs/sqlite3.c /^#define RTREE_REINSERT(/;" d file: +RTREE_ZERO testdocs/sqlite3.c /^# define RTREE_ZERO /;" d file: +RUNE_CRLF utf.h /^ RUNE_CRLF = -2, \/* rune value representing a \\r\\n sequence *\/$/;" e enum:__anon40 +RUNE_EOF utf.h /^ RUNE_EOF = -1, \/* rune value representing end of file *\/$/;" e enum:__anon40 +RUNE_ERR utf.h /^ RUNE_ERR = 0xFFFD, \/* rune value representing an error *\/$/;" e enum:__anon40 +RUNE_MAX utf.h /^ RUNE_MAX = 0x10FFFF, \/* Maximum decodable rune value *\/$/;" e enum:__anon40 +RUNE_SELF utf.h /^ RUNE_SELF = 0x80, \/* byte values larger than this are *not* ascii *\/$/;" e enum:__anon40 +RUN_EXTERN_TEST_SUITE atf.h /^#define RUN_EXTERN_TEST_SUITE(/;" d +RUN_TEST_SUITE atf.h /^#define RUN_TEST_SUITE(/;" d +RbuFrame testdocs/sqlite3.c /^struct RbuFrame {$/;" s file: +RbuFrame testdocs/sqlite3.c /^typedef struct RbuFrame RbuFrame;$/;" t typeref:struct:RbuFrame file: +RbuObjIter testdocs/sqlite3.c /^struct RbuObjIter {$/;" s file: +RbuObjIter testdocs/sqlite3.c /^typedef struct RbuObjIter RbuObjIter;$/;" t typeref:struct:RbuObjIter file: +RbuState testdocs/sqlite3.c /^struct RbuState {$/;" s file: +RbuState testdocs/sqlite3.c /^typedef struct RbuState RbuState;$/;" t typeref:struct:RbuState file: +RbuUpdateStmt testdocs/sqlite3.c /^struct RbuUpdateStmt {$/;" s file: +RbuUpdateStmt testdocs/sqlite3.c /^typedef struct RbuUpdateStmt RbuUpdateStmt;$/;" t typeref:struct:RbuUpdateStmt file: +RecordCompare testdocs/sqlite3.c /^typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);$/;" t file: +Reinsert testdocs/sqlite3.c /^static int Reinsert($/;" f file: +ReusableSpace testdocs/sqlite3.c /^struct ReusableSpace {$/;" s file: +RowSet testdocs/sqlite3.c /^struct RowSet {$/;" s file: +RowSet testdocs/sqlite3.c /^typedef struct RowSet RowSet;$/;" t typeref:struct:RowSet file: +RowSetChunk testdocs/sqlite3.c /^struct RowSetChunk {$/;" s file: +RowSetEntry testdocs/sqlite3.c /^struct RowSetEntry {$/;" s file: +Rtree testdocs/sqlite3.c /^struct Rtree {$/;" s file: +Rtree testdocs/sqlite3.c /^typedef struct Rtree Rtree;$/;" t typeref:struct:Rtree file: +RtreeCell testdocs/sqlite3.c /^struct RtreeCell {$/;" s file: +RtreeCell testdocs/sqlite3.c /^typedef struct RtreeCell RtreeCell;$/;" t typeref:struct:RtreeCell file: +RtreeConstraint testdocs/sqlite3.c /^struct RtreeConstraint {$/;" s file: +RtreeConstraint testdocs/sqlite3.c /^typedef struct RtreeConstraint RtreeConstraint;$/;" t typeref:struct:RtreeConstraint file: +RtreeCoord testdocs/sqlite3.c /^typedef union RtreeCoord RtreeCoord;$/;" t typeref:union:RtreeCoord file: +RtreeCoord testdocs/sqlite3.c /^union RtreeCoord {$/;" u file: +RtreeCursor testdocs/sqlite3.c /^struct RtreeCursor {$/;" s file: +RtreeCursor testdocs/sqlite3.c /^typedef struct RtreeCursor RtreeCursor;$/;" t typeref:struct:RtreeCursor file: +RtreeDValue testdocs/sqlite3.c /^ typedef double RtreeDValue; \/* High accuracy coordinate *\/$/;" t file: +RtreeDValue testdocs/sqlite3.c /^ typedef sqlite3_int64 RtreeDValue; \/* High accuracy coordinate *\/$/;" t file: +RtreeGeomCallback testdocs/sqlite3.c /^struct RtreeGeomCallback {$/;" s file: +RtreeGeomCallback testdocs/sqlite3.c /^typedef struct RtreeGeomCallback RtreeGeomCallback;$/;" t typeref:struct:RtreeGeomCallback file: +RtreeMatchArg testdocs/sqlite3.c /^struct RtreeMatchArg {$/;" s file: +RtreeMatchArg testdocs/sqlite3.c /^typedef struct RtreeMatchArg RtreeMatchArg;$/;" t typeref:struct:RtreeMatchArg file: +RtreeNode testdocs/sqlite3.c /^struct RtreeNode {$/;" s file: +RtreeNode testdocs/sqlite3.c /^typedef struct RtreeNode RtreeNode;$/;" t typeref:struct:RtreeNode file: +RtreeSearchPoint testdocs/sqlite3.c /^struct RtreeSearchPoint {$/;" s file: +RtreeSearchPoint testdocs/sqlite3.c /^typedef struct RtreeSearchPoint RtreeSearchPoint;$/;" t typeref:struct:RtreeSearchPoint file: +RtreeValue testdocs/sqlite3.c /^ typedef float RtreeValue; \/* Low accuracy coordinate *\/$/;" t file: +RtreeValue testdocs/sqlite3.c /^ typedef int RtreeValue; \/* Low accuracy coordinate *\/$/;" t file: +Rune utf.h /^typedef int32_t Rune;$/;" t +SAVEPOINT_BEGIN testdocs/sqlite3.c /^#define SAVEPOINT_BEGIN /;" d file: +SAVEPOINT_RELEASE testdocs/sqlite3.c /^#define SAVEPOINT_RELEASE /;" d file: +SAVEPOINT_ROLLBACK testdocs/sqlite3.c /^#define SAVEPOINT_ROLLBACK /;" d file: +SCHEMA_ENC testdocs/sqlite3.c /^#define SCHEMA_ENC(/;" d file: +SCHEMA_TABLE testdocs/sqlite3.c /^#define SCHEMA_TABLE(/;" d file: +SELECTTRACE testdocs/sqlite3.c /^# define SELECTTRACE(/;" d file: +SELECTTRACE_ENABLED testdocs/sqlite3.c /^# define SELECTTRACE_ENABLED /;" d file: +SESSIONS_STRM_CHUNK_SIZE testdocs/sqlite3.c /^# define SESSIONS_STRM_CHUNK_SIZE /;" d file: +SESSION_UINT32 testdocs/sqlite3.c /^#define SESSION_UINT32(/;" d file: +SETBIT testdocs/sqlite3.c /^#define SETBIT(/;" d file: +SET_FULLSYNC testdocs/sqlite3.c /^# define SET_FULLSYNC(/;" d file: +SF_Aggregate testdocs/sqlite3.c /^#define SF_Aggregate /;" d file: +SF_All testdocs/sqlite3.c /^#define SF_All /;" d file: +SF_Compound testdocs/sqlite3.c /^#define SF_Compound /;" d file: +SF_Converted testdocs/sqlite3.c /^#define SF_Converted /;" d file: +SF_Distinct testdocs/sqlite3.c /^#define SF_Distinct /;" d file: +SF_Expanded testdocs/sqlite3.c /^#define SF_Expanded /;" d file: +SF_FixedLimit testdocs/sqlite3.c /^#define SF_FixedLimit /;" d file: +SF_HasAgg testdocs/sqlite3.c /^#define SF_HasAgg /;" d file: +SF_HasTypeInfo testdocs/sqlite3.c /^#define SF_HasTypeInfo /;" d file: +SF_IncludeHidden testdocs/sqlite3.c /^#define SF_IncludeHidden /;" d file: +SF_MaybeConvert testdocs/sqlite3.c /^#define SF_MaybeConvert /;" d file: +SF_MinMaxAgg testdocs/sqlite3.c /^#define SF_MinMaxAgg /;" d file: +SF_MultiValue testdocs/sqlite3.c /^#define SF_MultiValue /;" d file: +SF_NestedFrom testdocs/sqlite3.c /^#define SF_NestedFrom /;" d file: +SF_Recursive testdocs/sqlite3.c /^#define SF_Recursive /;" d file: +SF_Resolved testdocs/sqlite3.c /^#define SF_Resolved /;" d file: +SF_UsesEphemeral testdocs/sqlite3.c /^#define SF_UsesEphemeral /;" d file: +SF_Values testdocs/sqlite3.c /^#define SF_Values /;" d file: +SHARED_FIRST testdocs/sqlite3.c /^#define SHARED_FIRST /;" d file: +SHARED_LOCK testdocs/sqlite3.c /^#define SHARED_LOCK /;" d file: +SHARED_SIZE testdocs/sqlite3.c /^#define SHARED_SIZE /;" d file: +SLOT_2_0 testdocs/sqlite3.c /^#define SLOT_2_0 /;" d file: +SLOT_4_2_0 testdocs/sqlite3.c /^#define SLOT_4_2_0 /;" d file: +SMALLEST_INT64 testdocs/sqlite3.c /^# define SMALLEST_INT64 /;" d file: +SMALLEST_INT64 testdocs/sqlite3.c /^#define SMALLEST_INT64 /;" d file: +SORTER_MAX_MERGE_COUNT testdocs/sqlite3.c /^#define SORTER_MAX_MERGE_COUNT /;" d file: +SORTER_TYPE_INTEGER testdocs/sqlite3.c /^#define SORTER_TYPE_INTEGER /;" d file: +SORTER_TYPE_TEXT testdocs/sqlite3.c /^#define SORTER_TYPE_TEXT /;" d file: +SORTFLAG_UseSorter testdocs/sqlite3.c /^#define SORTFLAG_UseSorter /;" d file: +SPILLFLAG_NOSYNC testdocs/sqlite3.c /^#define SPILLFLAG_NOSYNC /;" d file: +SPILLFLAG_OFF testdocs/sqlite3.c /^#define SPILLFLAG_OFF /;" d file: +SPILLFLAG_ROLLBACK testdocs/sqlite3.c /^#define SPILLFLAG_ROLLBACK /;" d file: +SQLITE3EXT_H testdocs/sqlite3.c /^#define SQLITE3EXT_H$/;" d file: +SQLITE3_H testdocs/sqlite3.c /^#define SQLITE3_H$/;" d file: +SQLITE3_MUTEX_INITIALIZER testdocs/sqlite3.c /^#define SQLITE3_MUTEX_INITIALIZER /;" d file: +SQLITE3_TEXT testdocs/sqlite3.c /^#define SQLITE3_TEXT /;" d file: +SQLITEINT_H testdocs/sqlite3.c /^#define SQLITEINT_H$/;" d file: +SQLITE_ABORT testdocs/sqlite3.c /^#define SQLITE_ABORT /;" d file: +SQLITE_ABORT_ROLLBACK testdocs/sqlite3.c /^#define SQLITE_ABORT_ROLLBACK /;" d file: +SQLITE_ACCESS_EXISTS testdocs/sqlite3.c /^#define SQLITE_ACCESS_EXISTS /;" d file: +SQLITE_ACCESS_READ testdocs/sqlite3.c /^#define SQLITE_ACCESS_READ /;" d file: +SQLITE_ACCESS_READWRITE testdocs/sqlite3.c /^#define SQLITE_ACCESS_READWRITE /;" d file: +SQLITE_AFF_BLOB testdocs/sqlite3.c /^#define SQLITE_AFF_BLOB /;" d file: +SQLITE_AFF_INTEGER testdocs/sqlite3.c /^#define SQLITE_AFF_INTEGER /;" d file: +SQLITE_AFF_MASK testdocs/sqlite3.c /^#define SQLITE_AFF_MASK /;" d file: +SQLITE_AFF_NUMERIC testdocs/sqlite3.c /^#define SQLITE_AFF_NUMERIC /;" d file: +SQLITE_AFF_REAL testdocs/sqlite3.c /^#define SQLITE_AFF_REAL /;" d file: +SQLITE_AFF_TEXT testdocs/sqlite3.c /^#define SQLITE_AFF_TEXT /;" d file: +SQLITE_ALLOW_COVERING_INDEX_SCAN testdocs/sqlite3.c /^# define SQLITE_ALLOW_COVERING_INDEX_SCAN /;" d file: +SQLITE_ALTER_TABLE testdocs/sqlite3.c /^#define SQLITE_ALTER_TABLE /;" d file: +SQLITE_AMALGAMATION testdocs/sqlite3.c /^#define SQLITE_AMALGAMATION /;" d file: +SQLITE_ANALYZE testdocs/sqlite3.c /^#define SQLITE_ANALYZE /;" d file: +SQLITE_ANY testdocs/sqlite3.c /^#define SQLITE_ANY /;" d file: +SQLITE_API testdocs/sqlite3.c /^# define SQLITE_API$/;" d file: +SQLITE_APICALL testdocs/sqlite3.c /^# define SQLITE_APICALL$/;" d file: +SQLITE_ASCII testdocs/sqlite3.c /^# define SQLITE_ASCII /;" d file: +SQLITE_ATTACH testdocs/sqlite3.c /^#define SQLITE_ATTACH /;" d file: +SQLITE_AUTH testdocs/sqlite3.c /^#define SQLITE_AUTH /;" d file: +SQLITE_AUTH_USER testdocs/sqlite3.c /^#define SQLITE_AUTH_USER /;" d file: +SQLITE_AllOpts testdocs/sqlite3.c /^#define SQLITE_AllOpts /;" d file: +SQLITE_AutoIndex testdocs/sqlite3.c /^#define SQLITE_AutoIndex /;" d file: +SQLITE_BIGENDIAN testdocs/sqlite3.c /^# define SQLITE_BIGENDIAN /;" d file: +SQLITE_BIG_DBL testdocs/sqlite3.c /^# define SQLITE_BIG_DBL /;" d file: +SQLITE_BIG_DBL testdocs/sqlite3.c /^# define SQLITE_BIG_DBL /;" d file: +SQLITE_BLDF_INDEXED testdocs/sqlite3.c /^#define SQLITE_BLDF_INDEXED /;" d file: +SQLITE_BLDF_UNIQUE testdocs/sqlite3.c /^#define SQLITE_BLDF_UNIQUE /;" d file: +SQLITE_BLOB testdocs/sqlite3.c /^#define SQLITE_BLOB /;" d file: +SQLITE_BTREE_H testdocs/sqlite3.c /^#define SQLITE_BTREE_H$/;" d file: +SQLITE_BUSY testdocs/sqlite3.c /^#define SQLITE_BUSY /;" d file: +SQLITE_BUSY_RECOVERY testdocs/sqlite3.c /^#define SQLITE_BUSY_RECOVERY /;" d file: +SQLITE_BUSY_SNAPSHOT testdocs/sqlite3.c /^#define SQLITE_BUSY_SNAPSHOT /;" d file: +SQLITE_BYTEORDER testdocs/sqlite3.c /^# define SQLITE_BYTEORDER /;" d file: +SQLITE_BYTEORDER testdocs/sqlite3.c /^# define SQLITE_BYTEORDER /;" d file: +SQLITE_CALLBACK testdocs/sqlite3.c /^# define SQLITE_CALLBACK$/;" d file: +SQLITE_CANTOPEN testdocs/sqlite3.c /^#define SQLITE_CANTOPEN /;" d file: +SQLITE_CANTOPEN_BKPT testdocs/sqlite3.c /^#define SQLITE_CANTOPEN_BKPT /;" d file: +SQLITE_CANTOPEN_CONVPATH testdocs/sqlite3.c /^#define SQLITE_CANTOPEN_CONVPATH /;" d file: +SQLITE_CANTOPEN_FULLPATH testdocs/sqlite3.c /^#define SQLITE_CANTOPEN_FULLPATH /;" d file: +SQLITE_CANTOPEN_ISDIR testdocs/sqlite3.c /^#define SQLITE_CANTOPEN_ISDIR /;" d file: +SQLITE_CANTOPEN_NOTEMPDIR testdocs/sqlite3.c /^#define SQLITE_CANTOPEN_NOTEMPDIR /;" d file: +SQLITE_CDECL testdocs/sqlite3.c /^# define SQLITE_CDECL$/;" d file: +SQLITE_CHANGESET_ABORT testdocs/sqlite3.c /^#define SQLITE_CHANGESET_ABORT /;" d file: +SQLITE_CHANGESET_CONFLICT testdocs/sqlite3.c /^#define SQLITE_CHANGESET_CONFLICT /;" d file: +SQLITE_CHANGESET_CONSTRAINT testdocs/sqlite3.c /^#define SQLITE_CHANGESET_CONSTRAINT /;" d file: +SQLITE_CHANGESET_DATA testdocs/sqlite3.c /^#define SQLITE_CHANGESET_DATA /;" d file: +SQLITE_CHANGESET_FOREIGN_KEY testdocs/sqlite3.c /^#define SQLITE_CHANGESET_FOREIGN_KEY /;" d file: +SQLITE_CHANGESET_NOTFOUND testdocs/sqlite3.c /^#define SQLITE_CHANGESET_NOTFOUND /;" d file: +SQLITE_CHANGESET_OMIT testdocs/sqlite3.c /^#define SQLITE_CHANGESET_OMIT /;" d file: +SQLITE_CHANGESET_REPLACE testdocs/sqlite3.c /^#define SQLITE_CHANGESET_REPLACE /;" d file: +SQLITE_CHECKPOINT_FULL testdocs/sqlite3.c /^#define SQLITE_CHECKPOINT_FULL /;" d file: +SQLITE_CHECKPOINT_PASSIVE testdocs/sqlite3.c /^#define SQLITE_CHECKPOINT_PASSIVE /;" d file: +SQLITE_CHECKPOINT_RESTART testdocs/sqlite3.c /^#define SQLITE_CHECKPOINT_RESTART /;" d file: +SQLITE_CHECKPOINT_TRUNCATE testdocs/sqlite3.c /^#define SQLITE_CHECKPOINT_TRUNCATE /;" d file: +SQLITE_CONFIG_COVERING_INDEX_SCAN testdocs/sqlite3.c /^#define SQLITE_CONFIG_COVERING_INDEX_SCAN /;" d file: +SQLITE_CONFIG_GETMALLOC testdocs/sqlite3.c /^#define SQLITE_CONFIG_GETMALLOC /;" d file: +SQLITE_CONFIG_GETMUTEX testdocs/sqlite3.c /^#define SQLITE_CONFIG_GETMUTEX /;" d file: +SQLITE_CONFIG_GETPCACHE testdocs/sqlite3.c /^#define SQLITE_CONFIG_GETPCACHE /;" d file: +SQLITE_CONFIG_GETPCACHE2 testdocs/sqlite3.c /^#define SQLITE_CONFIG_GETPCACHE2 /;" d file: +SQLITE_CONFIG_HEAP testdocs/sqlite3.c /^#define SQLITE_CONFIG_HEAP /;" d file: +SQLITE_CONFIG_LOG testdocs/sqlite3.c /^#define SQLITE_CONFIG_LOG /;" d file: +SQLITE_CONFIG_LOOKASIDE testdocs/sqlite3.c /^#define SQLITE_CONFIG_LOOKASIDE /;" d file: +SQLITE_CONFIG_MALLOC testdocs/sqlite3.c /^#define SQLITE_CONFIG_MALLOC /;" d file: +SQLITE_CONFIG_MEMSTATUS testdocs/sqlite3.c /^#define SQLITE_CONFIG_MEMSTATUS /;" d file: +SQLITE_CONFIG_MMAP_SIZE testdocs/sqlite3.c /^#define SQLITE_CONFIG_MMAP_SIZE /;" d file: +SQLITE_CONFIG_MULTITHREAD testdocs/sqlite3.c /^#define SQLITE_CONFIG_MULTITHREAD /;" d file: +SQLITE_CONFIG_MUTEX testdocs/sqlite3.c /^#define SQLITE_CONFIG_MUTEX /;" d file: +SQLITE_CONFIG_PAGECACHE testdocs/sqlite3.c /^#define SQLITE_CONFIG_PAGECACHE /;" d file: +SQLITE_CONFIG_PCACHE testdocs/sqlite3.c /^#define SQLITE_CONFIG_PCACHE /;" d file: +SQLITE_CONFIG_PCACHE2 testdocs/sqlite3.c /^#define SQLITE_CONFIG_PCACHE2 /;" d file: +SQLITE_CONFIG_PCACHE_HDRSZ testdocs/sqlite3.c /^#define SQLITE_CONFIG_PCACHE_HDRSZ /;" d file: +SQLITE_CONFIG_PMASZ testdocs/sqlite3.c /^#define SQLITE_CONFIG_PMASZ /;" d file: +SQLITE_CONFIG_SCRATCH testdocs/sqlite3.c /^#define SQLITE_CONFIG_SCRATCH /;" d file: +SQLITE_CONFIG_SERIALIZED testdocs/sqlite3.c /^#define SQLITE_CONFIG_SERIALIZED /;" d file: +SQLITE_CONFIG_SINGLETHREAD testdocs/sqlite3.c /^#define SQLITE_CONFIG_SINGLETHREAD /;" d file: +SQLITE_CONFIG_SQLLOG testdocs/sqlite3.c /^#define SQLITE_CONFIG_SQLLOG /;" d file: +SQLITE_CONFIG_STMTJRNL_SPILL testdocs/sqlite3.c /^#define SQLITE_CONFIG_STMTJRNL_SPILL /;" d file: +SQLITE_CONFIG_URI testdocs/sqlite3.c /^#define SQLITE_CONFIG_URI /;" d file: +SQLITE_CONFIG_WIN32_HEAPSIZE testdocs/sqlite3.c /^#define SQLITE_CONFIG_WIN32_HEAPSIZE /;" d file: +SQLITE_CONSTRAINT testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT /;" d file: +SQLITE_CONSTRAINT_CHECK testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_CHECK /;" d file: +SQLITE_CONSTRAINT_COMMITHOOK testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_COMMITHOOK /;" d file: +SQLITE_CONSTRAINT_FOREIGNKEY testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_FOREIGNKEY /;" d file: +SQLITE_CONSTRAINT_FUNCTION testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_FUNCTION /;" d file: +SQLITE_CONSTRAINT_NOTNULL testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_NOTNULL /;" d file: +SQLITE_CONSTRAINT_PRIMARYKEY testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_PRIMARYKEY /;" d file: +SQLITE_CONSTRAINT_ROWID testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_ROWID /;" d file: +SQLITE_CONSTRAINT_TRIGGER testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_TRIGGER /;" d file: +SQLITE_CONSTRAINT_UNIQUE testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_UNIQUE /;" d file: +SQLITE_CONSTRAINT_VTAB testdocs/sqlite3.c /^#define SQLITE_CONSTRAINT_VTAB /;" d file: +SQLITE_COPY testdocs/sqlite3.c /^#define SQLITE_COPY /;" d file: +SQLITE_CORE testdocs/sqlite3.c /^ #define SQLITE_CORE /;" d file: +SQLITE_CORE testdocs/sqlite3.c /^# define SQLITE_CORE /;" d file: +SQLITE_CORE testdocs/sqlite3.c /^#define SQLITE_CORE /;" d file: +SQLITE_CORRUPT testdocs/sqlite3.c /^#define SQLITE_CORRUPT /;" d file: +SQLITE_CORRUPT_BKPT testdocs/sqlite3.c /^#define SQLITE_CORRUPT_BKPT /;" d file: +SQLITE_CORRUPT_VTAB testdocs/sqlite3.c /^#define SQLITE_CORRUPT_VTAB /;" d file: +SQLITE_CREATE_INDEX testdocs/sqlite3.c /^#define SQLITE_CREATE_INDEX /;" d file: +SQLITE_CREATE_TABLE testdocs/sqlite3.c /^#define SQLITE_CREATE_TABLE /;" d file: +SQLITE_CREATE_TEMP_INDEX testdocs/sqlite3.c /^#define SQLITE_CREATE_TEMP_INDEX /;" d file: +SQLITE_CREATE_TEMP_TABLE testdocs/sqlite3.c /^#define SQLITE_CREATE_TEMP_TABLE /;" d file: +SQLITE_CREATE_TEMP_TRIGGER testdocs/sqlite3.c /^#define SQLITE_CREATE_TEMP_TRIGGER /;" d file: +SQLITE_CREATE_TEMP_VIEW testdocs/sqlite3.c /^#define SQLITE_CREATE_TEMP_VIEW /;" d file: +SQLITE_CREATE_TRIGGER testdocs/sqlite3.c /^#define SQLITE_CREATE_TRIGGER /;" d file: +SQLITE_CREATE_VIEW testdocs/sqlite3.c /^#define SQLITE_CREATE_VIEW /;" d file: +SQLITE_CREATE_VTABLE testdocs/sqlite3.c /^#define SQLITE_CREATE_VTABLE /;" d file: +SQLITE_CacheSpill testdocs/sqlite3.c /^#define SQLITE_CacheSpill /;" d file: +SQLITE_CellSizeCk testdocs/sqlite3.c /^#define SQLITE_CellSizeCk /;" d file: +SQLITE_CkptFullFSync testdocs/sqlite3.c /^#define SQLITE_CkptFullFSync /;" d file: +SQLITE_ColumnCache testdocs/sqlite3.c /^#define SQLITE_ColumnCache /;" d file: +SQLITE_CountRows testdocs/sqlite3.c /^#define SQLITE_CountRows /;" d file: +SQLITE_CoverIdxScan testdocs/sqlite3.c /^#define SQLITE_CoverIdxScan /;" d file: +SQLITE_CursorHints testdocs/sqlite3.c /^#define SQLITE_CursorHints /;" d file: +SQLITE_DBCONFIG_ENABLE_FKEY testdocs/sqlite3.c /^#define SQLITE_DBCONFIG_ENABLE_FKEY /;" d file: +SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER testdocs/sqlite3.c /^#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER /;" d file: +SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION testdocs/sqlite3.c /^#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION /;" d file: +SQLITE_DBCONFIG_ENABLE_TRIGGER testdocs/sqlite3.c /^#define SQLITE_DBCONFIG_ENABLE_TRIGGER /;" d file: +SQLITE_DBCONFIG_LOOKASIDE testdocs/sqlite3.c /^#define SQLITE_DBCONFIG_LOOKASIDE /;" d file: +SQLITE_DBCONFIG_MAINDBNAME testdocs/sqlite3.c /^#define SQLITE_DBCONFIG_MAINDBNAME /;" d file: +SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE testdocs/sqlite3.c /^#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE /;" d file: +SQLITE_DBSTATUS_CACHE_HIT testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_CACHE_HIT /;" d file: +SQLITE_DBSTATUS_CACHE_MISS testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_CACHE_MISS /;" d file: +SQLITE_DBSTATUS_CACHE_USED testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_CACHE_USED /;" d file: +SQLITE_DBSTATUS_CACHE_USED_SHARED testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_CACHE_USED_SHARED /;" d file: +SQLITE_DBSTATUS_CACHE_WRITE testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_CACHE_WRITE /;" d file: +SQLITE_DBSTATUS_DEFERRED_FKS testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_DEFERRED_FKS /;" d file: +SQLITE_DBSTATUS_LOOKASIDE_HIT testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_LOOKASIDE_HIT /;" d file: +SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL /;" d file: +SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE /;" d file: +SQLITE_DBSTATUS_LOOKASIDE_USED testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_LOOKASIDE_USED /;" d file: +SQLITE_DBSTATUS_MAX testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_MAX /;" d file: +SQLITE_DBSTATUS_SCHEMA_USED testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_SCHEMA_USED /;" d file: +SQLITE_DBSTATUS_STMT_USED testdocs/sqlite3.c /^#define SQLITE_DBSTATUS_STMT_USED /;" d file: +SQLITE_DEBUG_OS_TRACE testdocs/sqlite3.c /^# define SQLITE_DEBUG_OS_TRACE /;" d file: +SQLITE_DEFAULT_AUTOVACUUM testdocs/sqlite3.c /^ #define SQLITE_DEFAULT_AUTOVACUUM /;" d file: +SQLITE_DEFAULT_CACHE_SIZE testdocs/sqlite3.c /^# define SQLITE_DEFAULT_CACHE_SIZE /;" d file: +SQLITE_DEFAULT_FILE_FORMAT testdocs/sqlite3.c /^# define SQLITE_DEFAULT_FILE_FORMAT /;" d file: +SQLITE_DEFAULT_FILE_PERMISSIONS testdocs/sqlite3.c /^# define SQLITE_DEFAULT_FILE_PERMISSIONS /;" d file: +SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT testdocs/sqlite3.c /^ #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT /;" d file: +SQLITE_DEFAULT_LOOKASIDE testdocs/sqlite3.c /^# define SQLITE_DEFAULT_LOOKASIDE /;" d file: +SQLITE_DEFAULT_MEMSTATUS testdocs/sqlite3.c /^# define SQLITE_DEFAULT_MEMSTATUS /;" d file: +SQLITE_DEFAULT_MMAP_SIZE testdocs/sqlite3.c /^# define SQLITE_DEFAULT_MMAP_SIZE /;" d file: +SQLITE_DEFAULT_MMAP_SIZE testdocs/sqlite3.c /^# undef SQLITE_DEFAULT_MMAP_SIZE$/;" d file: +SQLITE_DEFAULT_MMAP_SIZE_xc testdocs/sqlite3.c /^# define SQLITE_DEFAULT_MMAP_SIZE_xc /;" d file: +SQLITE_DEFAULT_PAGE_SIZE testdocs/sqlite3.c /^# define SQLITE_DEFAULT_PAGE_SIZE /;" d file: +SQLITE_DEFAULT_PAGE_SIZE testdocs/sqlite3.c /^# undef SQLITE_DEFAULT_PAGE_SIZE$/;" d file: +SQLITE_DEFAULT_PCACHE_INITSZ testdocs/sqlite3.c /^# define SQLITE_DEFAULT_PCACHE_INITSZ /;" d file: +SQLITE_DEFAULT_PROXYDIR_PERMISSIONS testdocs/sqlite3.c /^# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS /;" d file: +SQLITE_DEFAULT_RECURSIVE_TRIGGERS testdocs/sqlite3.c /^# define SQLITE_DEFAULT_RECURSIVE_TRIGGERS /;" d file: +SQLITE_DEFAULT_SECTOR_SIZE testdocs/sqlite3.c /^# define SQLITE_DEFAULT_SECTOR_SIZE /;" d file: +SQLITE_DEFAULT_SYNCHRONOUS testdocs/sqlite3.c /^# define SQLITE_DEFAULT_SYNCHRONOUS /;" d file: +SQLITE_DEFAULT_WAL_AUTOCHECKPOINT testdocs/sqlite3.c /^# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT /;" d file: +SQLITE_DEFAULT_WAL_SYNCHRONOUS testdocs/sqlite3.c /^# define SQLITE_DEFAULT_WAL_SYNCHRONOUS /;" d file: +SQLITE_DEFAULT_WORKER_THREADS testdocs/sqlite3.c /^# define SQLITE_DEFAULT_WORKER_THREADS /;" d file: +SQLITE_DELETE testdocs/sqlite3.c /^#define SQLITE_DELETE /;" d file: +SQLITE_DENY testdocs/sqlite3.c /^#define SQLITE_DENY /;" d file: +SQLITE_DEPRECATED testdocs/sqlite3.c /^#define SQLITE_DEPRECATED$/;" d file: +SQLITE_DETACH testdocs/sqlite3.c /^#define SQLITE_DETACH /;" d file: +SQLITE_DETERMINISTIC testdocs/sqlite3.c /^#define SQLITE_DETERMINISTIC /;" d file: +SQLITE_DONE testdocs/sqlite3.c /^#define SQLITE_DONE /;" d file: +SQLITE_DROP_INDEX testdocs/sqlite3.c /^#define SQLITE_DROP_INDEX /;" d file: +SQLITE_DROP_TABLE testdocs/sqlite3.c /^#define SQLITE_DROP_TABLE /;" d file: +SQLITE_DROP_TEMP_INDEX testdocs/sqlite3.c /^#define SQLITE_DROP_TEMP_INDEX /;" d file: +SQLITE_DROP_TEMP_TABLE testdocs/sqlite3.c /^#define SQLITE_DROP_TEMP_TABLE /;" d file: +SQLITE_DROP_TEMP_TRIGGER testdocs/sqlite3.c /^#define SQLITE_DROP_TEMP_TRIGGER /;" d file: +SQLITE_DROP_TEMP_VIEW testdocs/sqlite3.c /^#define SQLITE_DROP_TEMP_VIEW /;" d file: +SQLITE_DROP_TRIGGER testdocs/sqlite3.c /^#define SQLITE_DROP_TRIGGER /;" d file: +SQLITE_DROP_VIEW testdocs/sqlite3.c /^#define SQLITE_DROP_VIEW /;" d file: +SQLITE_DROP_VTABLE testdocs/sqlite3.c /^#define SQLITE_DROP_VTABLE /;" d file: +SQLITE_DYNAMIC testdocs/sqlite3.c /^#define SQLITE_DYNAMIC /;" d file: +SQLITE_DeferFKs testdocs/sqlite3.c /^#define SQLITE_DeferFKs /;" d file: +SQLITE_DistinctOpt testdocs/sqlite3.c /^#define SQLITE_DistinctOpt /;" d file: +SQLITE_EBCDIC testdocs/sqlite3.c /^# define SQLITE_EBCDIC /;" d file: +SQLITE_ECEL_DUP testdocs/sqlite3.c /^#define SQLITE_ECEL_DUP /;" d file: +SQLITE_ECEL_FACTOR testdocs/sqlite3.c /^#define SQLITE_ECEL_FACTOR /;" d file: +SQLITE_ECEL_OMITREF testdocs/sqlite3.c /^#define SQLITE_ECEL_OMITREF /;" d file: +SQLITE_ECEL_REF testdocs/sqlite3.c /^#define SQLITE_ECEL_REF /;" d file: +SQLITE_EMPTY testdocs/sqlite3.c /^#define SQLITE_EMPTY /;" d file: +SQLITE_ENABLE_EXPLAIN_COMMENTS testdocs/sqlite3.c /^# define SQLITE_ENABLE_EXPLAIN_COMMENTS /;" d file: +SQLITE_ENABLE_EXPLAIN_COMMENTS testdocs/sqlite3.c /^# undef SQLITE_ENABLE_EXPLAIN_COMMENTS$/;" d file: +SQLITE_ENABLE_FTS3 testdocs/sqlite3.c /^# define SQLITE_ENABLE_FTS3 /;" d file: +SQLITE_ENABLE_FTS3 testdocs/sqlite3.c /^# define SQLITE_ENABLE_FTS3$/;" d file: +SQLITE_ENABLE_FTS3 testdocs/sqlite3.c /^# undef SQLITE_ENABLE_FTS3$/;" d file: +SQLITE_ENABLE_FTS4 testdocs/sqlite3.c /^# undef SQLITE_ENABLE_FTS4$/;" d file: +SQLITE_ENABLE_LOCKING_STYLE testdocs/sqlite3.c /^# define SQLITE_ENABLE_LOCKING_STYLE /;" d file: +SQLITE_ENABLE_LOCKING_STYLE testdocs/sqlite3.c /^#define SQLITE_ENABLE_LOCKING_STYLE /;" d file: +SQLITE_ENABLE_MEMSYS3 testdocs/sqlite3.c /^#undef SQLITE_ENABLE_MEMSYS3$/;" d file: +SQLITE_ENABLE_STAT3 testdocs/sqlite3.c /^# undef SQLITE_ENABLE_STAT3$/;" d file: +SQLITE_ENABLE_STAT3_OR_STAT4 testdocs/sqlite3.c /^# define SQLITE_ENABLE_STAT3_OR_STAT4 /;" d file: +SQLITE_ENABLE_STAT3_OR_STAT4 testdocs/sqlite3.c /^# undef SQLITE_ENABLE_STAT3_OR_STAT4$/;" d file: +SQLITE_ERROR testdocs/sqlite3.c /^#define SQLITE_ERROR /;" d file: +SQLITE_EXPERIMENTAL testdocs/sqlite3.c /^#define SQLITE_EXPERIMENTAL$/;" d file: +SQLITE_EXTENSION_INIT1 testdocs/sqlite3.c /^# define SQLITE_EXTENSION_INIT1 /;" d file: +SQLITE_EXTENSION_INIT2 testdocs/sqlite3.c /^# define SQLITE_EXTENSION_INIT2(/;" d file: +SQLITE_EXTENSION_INIT3 testdocs/sqlite3.c /^# define SQLITE_EXTENSION_INIT3 /;" d file: +SQLITE_EXTERN testdocs/sqlite3.c /^# define SQLITE_EXTERN /;" d file: +SQLITE_EnableTrigger testdocs/sqlite3.c /^#define SQLITE_EnableTrigger /;" d file: +SQLITE_FAIL testdocs/sqlite3.c /^#define SQLITE_FAIL /;" d file: +SQLITE_FAULTINJECTOR_COUNT testdocs/sqlite3.c /^#define SQLITE_FAULTINJECTOR_COUNT /;" d file: +SQLITE_FAULTINJECTOR_MALLOC testdocs/sqlite3.c /^#define SQLITE_FAULTINJECTOR_MALLOC /;" d file: +SQLITE_FCNTL_BUSYHANDLER testdocs/sqlite3.c /^#define SQLITE_FCNTL_BUSYHANDLER /;" d file: +SQLITE_FCNTL_CHUNK_SIZE testdocs/sqlite3.c /^#define SQLITE_FCNTL_CHUNK_SIZE /;" d file: +SQLITE_FCNTL_COMMIT_PHASETWO testdocs/sqlite3.c /^#define SQLITE_FCNTL_COMMIT_PHASETWO /;" d file: +SQLITE_FCNTL_DB_UNCHANGED testdocs/sqlite3.c /^#define SQLITE_FCNTL_DB_UNCHANGED /;" d file: +SQLITE_FCNTL_FILE_POINTER testdocs/sqlite3.c /^#define SQLITE_FCNTL_FILE_POINTER /;" d file: +SQLITE_FCNTL_GET_LOCKPROXYFILE testdocs/sqlite3.c /^#define SQLITE_FCNTL_GET_LOCKPROXYFILE /;" d file: +SQLITE_FCNTL_HAS_MOVED testdocs/sqlite3.c /^#define SQLITE_FCNTL_HAS_MOVED /;" d file: +SQLITE_FCNTL_JOURNAL_POINTER testdocs/sqlite3.c /^#define SQLITE_FCNTL_JOURNAL_POINTER /;" d file: +SQLITE_FCNTL_LAST_ERRNO testdocs/sqlite3.c /^#define SQLITE_FCNTL_LAST_ERRNO /;" d file: +SQLITE_FCNTL_LOCKSTATE testdocs/sqlite3.c /^#define SQLITE_FCNTL_LOCKSTATE /;" d file: +SQLITE_FCNTL_MMAP_SIZE testdocs/sqlite3.c /^#define SQLITE_FCNTL_MMAP_SIZE /;" d file: +SQLITE_FCNTL_OVERWRITE testdocs/sqlite3.c /^#define SQLITE_FCNTL_OVERWRITE /;" d file: +SQLITE_FCNTL_PDB testdocs/sqlite3.c /^#define SQLITE_FCNTL_PDB /;" d file: +SQLITE_FCNTL_PERSIST_WAL testdocs/sqlite3.c /^#define SQLITE_FCNTL_PERSIST_WAL /;" d file: +SQLITE_FCNTL_POWERSAFE_OVERWRITE testdocs/sqlite3.c /^#define SQLITE_FCNTL_POWERSAFE_OVERWRITE /;" d file: +SQLITE_FCNTL_PRAGMA testdocs/sqlite3.c /^#define SQLITE_FCNTL_PRAGMA /;" d file: +SQLITE_FCNTL_RBU testdocs/sqlite3.c /^#define SQLITE_FCNTL_RBU /;" d file: +SQLITE_FCNTL_RBUCNT testdocs/sqlite3.c /^#define SQLITE_FCNTL_RBUCNT /;" d file: +SQLITE_FCNTL_SET_LOCKPROXYFILE testdocs/sqlite3.c /^#define SQLITE_FCNTL_SET_LOCKPROXYFILE /;" d file: +SQLITE_FCNTL_SIZE_HINT testdocs/sqlite3.c /^#define SQLITE_FCNTL_SIZE_HINT /;" d file: +SQLITE_FCNTL_SYNC testdocs/sqlite3.c /^#define SQLITE_FCNTL_SYNC /;" d file: +SQLITE_FCNTL_SYNC_OMITTED testdocs/sqlite3.c /^#define SQLITE_FCNTL_SYNC_OMITTED /;" d file: +SQLITE_FCNTL_TEMPFILENAME testdocs/sqlite3.c /^#define SQLITE_FCNTL_TEMPFILENAME /;" d file: +SQLITE_FCNTL_TRACE testdocs/sqlite3.c /^#define SQLITE_FCNTL_TRACE /;" d file: +SQLITE_FCNTL_VFSNAME testdocs/sqlite3.c /^#define SQLITE_FCNTL_VFSNAME /;" d file: +SQLITE_FCNTL_VFS_POINTER testdocs/sqlite3.c /^#define SQLITE_FCNTL_VFS_POINTER /;" d file: +SQLITE_FCNTL_WAL_BLOCK testdocs/sqlite3.c /^#define SQLITE_FCNTL_WAL_BLOCK /;" d file: +SQLITE_FCNTL_WIN32_AV_RETRY testdocs/sqlite3.c /^#define SQLITE_FCNTL_WIN32_AV_RETRY /;" d file: +SQLITE_FCNTL_WIN32_GET_HANDLE testdocs/sqlite3.c /^#define SQLITE_FCNTL_WIN32_GET_HANDLE /;" d file: +SQLITE_FCNTL_WIN32_SET_HANDLE testdocs/sqlite3.c /^#define SQLITE_FCNTL_WIN32_SET_HANDLE /;" d file: +SQLITE_FCNTL_ZIPVFS testdocs/sqlite3.c /^#define SQLITE_FCNTL_ZIPVFS /;" d file: +SQLITE_FILE_HEADER testdocs/sqlite3.c /^# define SQLITE_FILE_HEADER /;" d file: +SQLITE_FLOAT testdocs/sqlite3.c /^#define SQLITE_FLOAT /;" d file: +SQLITE_FORMAT testdocs/sqlite3.c /^#define SQLITE_FORMAT /;" d file: +SQLITE_FREE testdocs/sqlite3.c /^#define SQLITE_FREE(/;" d file: +SQLITE_FSFLAGS_IS_MSDOS testdocs/sqlite3.c /^#define SQLITE_FSFLAGS_IS_MSDOS /;" d file: +SQLITE_FTS3_DEFAULT_NEAR_PARAM testdocs/sqlite3.c /^#define SQLITE_FTS3_DEFAULT_NEAR_PARAM /;" d file: +SQLITE_FTS3_MAX_EXPR_DEPTH testdocs/sqlite3.c /^# define SQLITE_FTS3_MAX_EXPR_DEPTH /;" d file: +SQLITE_FULL testdocs/sqlite3.c /^#define SQLITE_FULL /;" d file: +SQLITE_FUNCTION testdocs/sqlite3.c /^#define SQLITE_FUNCTION /;" d file: +SQLITE_FUNC_AFFINITY testdocs/sqlite3.c /^#define SQLITE_FUNC_AFFINITY /;" d file: +SQLITE_FUNC_CASE testdocs/sqlite3.c /^#define SQLITE_FUNC_CASE /;" d file: +SQLITE_FUNC_COALESCE testdocs/sqlite3.c /^#define SQLITE_FUNC_COALESCE /;" d file: +SQLITE_FUNC_CONSTANT testdocs/sqlite3.c /^#define SQLITE_FUNC_CONSTANT /;" d file: +SQLITE_FUNC_COUNT testdocs/sqlite3.c /^#define SQLITE_FUNC_COUNT /;" d file: +SQLITE_FUNC_ENCMASK testdocs/sqlite3.c /^#define SQLITE_FUNC_ENCMASK /;" d file: +SQLITE_FUNC_EPHEM testdocs/sqlite3.c /^#define SQLITE_FUNC_EPHEM /;" d file: +SQLITE_FUNC_HASH_SZ testdocs/sqlite3.c /^#define SQLITE_FUNC_HASH_SZ /;" d file: +SQLITE_FUNC_LENGTH testdocs/sqlite3.c /^#define SQLITE_FUNC_LENGTH /;" d file: +SQLITE_FUNC_LIKE testdocs/sqlite3.c /^#define SQLITE_FUNC_LIKE /;" d file: +SQLITE_FUNC_MINMAX testdocs/sqlite3.c /^#define SQLITE_FUNC_MINMAX /;" d file: +SQLITE_FUNC_NEEDCOLL testdocs/sqlite3.c /^#define SQLITE_FUNC_NEEDCOLL /;" d file: +SQLITE_FUNC_SLOCHNG testdocs/sqlite3.c /^#define SQLITE_FUNC_SLOCHNG /;" d file: +SQLITE_FUNC_TYPEOF testdocs/sqlite3.c /^#define SQLITE_FUNC_TYPEOF /;" d file: +SQLITE_FUNC_UNLIKELY testdocs/sqlite3.c /^#define SQLITE_FUNC_UNLIKELY /;" d file: +SQLITE_FactorOutConst testdocs/sqlite3.c /^#define SQLITE_FactorOutConst /;" d file: +SQLITE_ForeignKeys testdocs/sqlite3.c /^#define SQLITE_ForeignKeys /;" d file: +SQLITE_Fts3Tokenizer testdocs/sqlite3.c /^#define SQLITE_Fts3Tokenizer /;" d file: +SQLITE_FullColNames testdocs/sqlite3.c /^#define SQLITE_FullColNames /;" d file: +SQLITE_FullFSync testdocs/sqlite3.c /^#define SQLITE_FullFSync /;" d file: +SQLITE_GET_LOCKPROXYFILE testdocs/sqlite3.c /^#define SQLITE_GET_LOCKPROXYFILE /;" d file: +SQLITE_GroupByOrder testdocs/sqlite3.c /^#define SQLITE_GroupByOrder /;" d file: +SQLITE_HASH_H testdocs/sqlite3.c /^#define SQLITE_HASH_H$/;" d file: +SQLITE_HAVE_ISNAN testdocs/sqlite3.c /^# undef SQLITE_HAVE_ISNAN$/;" d file: +SQLITE_HAVE_OS_TRACE testdocs/sqlite3.c /^# define SQLITE_HAVE_OS_TRACE$/;" d file: +SQLITE_HAVE_OS_TRACE testdocs/sqlite3.c /^# undef SQLITE_HAVE_OS_TRACE$/;" d file: +SQLITE_HOMEGROWN_RECURSIVE_MUTEX testdocs/sqlite3.c /^#define SQLITE_HOMEGROWN_RECURSIVE_MUTEX /;" d file: +SQLITE_HWTIME_H testdocs/sqlite3.c /^#define SQLITE_HWTIME_H$/;" d file: +SQLITE_ICU_READ_UTF8 testdocs/sqlite3.c /^#define SQLITE_ICU_READ_UTF8(/;" d file: +SQLITE_ICU_SKIP_UTF8 testdocs/sqlite3.c /^#define SQLITE_ICU_SKIP_UTF8(/;" d file: +SQLITE_IDXTYPE_APPDEF testdocs/sqlite3.c /^#define SQLITE_IDXTYPE_APPDEF /;" d file: +SQLITE_IDXTYPE_PRIMARYKEY testdocs/sqlite3.c /^#define SQLITE_IDXTYPE_PRIMARYKEY /;" d file: +SQLITE_IDXTYPE_UNIQUE testdocs/sqlite3.c /^#define SQLITE_IDXTYPE_UNIQUE /;" d file: +SQLITE_IGNORE testdocs/sqlite3.c /^#define SQLITE_IGNORE /;" d file: +SQLITE_INDEX_CONSTRAINT_EQ testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_EQ /;" d file: +SQLITE_INDEX_CONSTRAINT_GE testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_GE /;" d file: +SQLITE_INDEX_CONSTRAINT_GLOB testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_GLOB /;" d file: +SQLITE_INDEX_CONSTRAINT_GT testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_GT /;" d file: +SQLITE_INDEX_CONSTRAINT_LE testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_LE /;" d file: +SQLITE_INDEX_CONSTRAINT_LIKE testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_LIKE /;" d file: +SQLITE_INDEX_CONSTRAINT_LT testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_LT /;" d file: +SQLITE_INDEX_CONSTRAINT_MATCH testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_MATCH /;" d file: +SQLITE_INDEX_CONSTRAINT_REGEXP testdocs/sqlite3.c /^#define SQLITE_INDEX_CONSTRAINT_REGEXP /;" d file: +SQLITE_INDEX_SCAN_UNIQUE testdocs/sqlite3.c /^#define SQLITE_INDEX_SCAN_UNIQUE /;" d file: +SQLITE_INSERT testdocs/sqlite3.c /^#define SQLITE_INSERT /;" d file: +SQLITE_INTEGER testdocs/sqlite3.c /^#define SQLITE_INTEGER /;" d file: +SQLITE_INTEGRITY_CHECK_ERROR_MAX testdocs/sqlite3.c /^# define SQLITE_INTEGRITY_CHECK_ERROR_MAX /;" d file: +SQLITE_INTERNAL testdocs/sqlite3.c /^#define SQLITE_INTERNAL /;" d file: +SQLITE_INTERRUPT testdocs/sqlite3.c /^#define SQLITE_INTERRUPT /;" d file: +SQLITE_INT_TO_PTR testdocs/sqlite3.c /^# define SQLITE_INT_TO_PTR(/;" d file: +SQLITE_IOCAP_ATOMIC testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC /;" d file: +SQLITE_IOCAP_ATOMIC16K testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC16K /;" d file: +SQLITE_IOCAP_ATOMIC1K testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC1K /;" d file: +SQLITE_IOCAP_ATOMIC2K testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC2K /;" d file: +SQLITE_IOCAP_ATOMIC32K testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC32K /;" d file: +SQLITE_IOCAP_ATOMIC4K testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC4K /;" d file: +SQLITE_IOCAP_ATOMIC512 testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC512 /;" d file: +SQLITE_IOCAP_ATOMIC64K testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC64K /;" d file: +SQLITE_IOCAP_ATOMIC8K testdocs/sqlite3.c /^#define SQLITE_IOCAP_ATOMIC8K /;" d file: +SQLITE_IOCAP_IMMUTABLE testdocs/sqlite3.c /^#define SQLITE_IOCAP_IMMUTABLE /;" d file: +SQLITE_IOCAP_POWERSAFE_OVERWRITE testdocs/sqlite3.c /^#define SQLITE_IOCAP_POWERSAFE_OVERWRITE /;" d file: +SQLITE_IOCAP_SAFE_APPEND testdocs/sqlite3.c /^#define SQLITE_IOCAP_SAFE_APPEND /;" d file: +SQLITE_IOCAP_SEQUENTIAL testdocs/sqlite3.c /^#define SQLITE_IOCAP_SEQUENTIAL /;" d file: +SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN testdocs/sqlite3.c /^#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN /;" d file: +SQLITE_IOERR testdocs/sqlite3.c /^#define SQLITE_IOERR /;" d file: +SQLITE_IOERR_ACCESS testdocs/sqlite3.c /^#define SQLITE_IOERR_ACCESS /;" d file: +SQLITE_IOERR_AUTH testdocs/sqlite3.c /^#define SQLITE_IOERR_AUTH /;" d file: +SQLITE_IOERR_BLOCKED testdocs/sqlite3.c /^#define SQLITE_IOERR_BLOCKED /;" d file: +SQLITE_IOERR_CHECKRESERVEDLOCK testdocs/sqlite3.c /^#define SQLITE_IOERR_CHECKRESERVEDLOCK /;" d file: +SQLITE_IOERR_CLOSE testdocs/sqlite3.c /^#define SQLITE_IOERR_CLOSE /;" d file: +SQLITE_IOERR_CONVPATH testdocs/sqlite3.c /^#define SQLITE_IOERR_CONVPATH /;" d file: +SQLITE_IOERR_DELETE testdocs/sqlite3.c /^#define SQLITE_IOERR_DELETE /;" d file: +SQLITE_IOERR_DELETE_NOENT testdocs/sqlite3.c /^#define SQLITE_IOERR_DELETE_NOENT /;" d file: +SQLITE_IOERR_DIR_CLOSE testdocs/sqlite3.c /^#define SQLITE_IOERR_DIR_CLOSE /;" d file: +SQLITE_IOERR_DIR_FSYNC testdocs/sqlite3.c /^#define SQLITE_IOERR_DIR_FSYNC /;" d file: +SQLITE_IOERR_FSTAT testdocs/sqlite3.c /^#define SQLITE_IOERR_FSTAT /;" d file: +SQLITE_IOERR_FSYNC testdocs/sqlite3.c /^#define SQLITE_IOERR_FSYNC /;" d file: +SQLITE_IOERR_GETTEMPPATH testdocs/sqlite3.c /^#define SQLITE_IOERR_GETTEMPPATH /;" d file: +SQLITE_IOERR_LOCK testdocs/sqlite3.c /^#define SQLITE_IOERR_LOCK /;" d file: +SQLITE_IOERR_MMAP testdocs/sqlite3.c /^#define SQLITE_IOERR_MMAP /;" d file: +SQLITE_IOERR_NOMEM testdocs/sqlite3.c /^#define SQLITE_IOERR_NOMEM /;" d file: +SQLITE_IOERR_NOMEM_BKPT testdocs/sqlite3.c /^# define SQLITE_IOERR_NOMEM_BKPT /;" d file: +SQLITE_IOERR_RDLOCK testdocs/sqlite3.c /^#define SQLITE_IOERR_RDLOCK /;" d file: +SQLITE_IOERR_READ testdocs/sqlite3.c /^#define SQLITE_IOERR_READ /;" d file: +SQLITE_IOERR_SEEK testdocs/sqlite3.c /^#define SQLITE_IOERR_SEEK /;" d file: +SQLITE_IOERR_SHMLOCK testdocs/sqlite3.c /^#define SQLITE_IOERR_SHMLOCK /;" d file: +SQLITE_IOERR_SHMMAP testdocs/sqlite3.c /^#define SQLITE_IOERR_SHMMAP /;" d file: +SQLITE_IOERR_SHMOPEN testdocs/sqlite3.c /^#define SQLITE_IOERR_SHMOPEN /;" d file: +SQLITE_IOERR_SHMSIZE testdocs/sqlite3.c /^#define SQLITE_IOERR_SHMSIZE /;" d file: +SQLITE_IOERR_SHORT_READ testdocs/sqlite3.c /^#define SQLITE_IOERR_SHORT_READ /;" d file: +SQLITE_IOERR_TRUNCATE testdocs/sqlite3.c /^#define SQLITE_IOERR_TRUNCATE /;" d file: +SQLITE_IOERR_UNLOCK testdocs/sqlite3.c /^#define SQLITE_IOERR_UNLOCK /;" d file: +SQLITE_IOERR_VNODE testdocs/sqlite3.c /^#define SQLITE_IOERR_VNODE /;" d file: +SQLITE_IOERR_WRITE testdocs/sqlite3.c /^#define SQLITE_IOERR_WRITE /;" d file: +SQLITE_IgnoreChecks testdocs/sqlite3.c /^#define SQLITE_IgnoreChecks /;" d file: +SQLITE_InternChanges testdocs/sqlite3.c /^#define SQLITE_InternChanges /;" d file: +SQLITE_JUMPIFNULL testdocs/sqlite3.c /^#define SQLITE_JUMPIFNULL /;" d file: +SQLITE_KEEPNULL testdocs/sqlite3.c /^#define SQLITE_KEEPNULL /;" d file: +SQLITE_LAST_ERRNO testdocs/sqlite3.c /^#define SQLITE_LAST_ERRNO /;" d file: +SQLITE_LIMIT_ATTACHED testdocs/sqlite3.c /^#define SQLITE_LIMIT_ATTACHED /;" d file: +SQLITE_LIMIT_COLUMN testdocs/sqlite3.c /^#define SQLITE_LIMIT_COLUMN /;" d file: +SQLITE_LIMIT_COMPOUND_SELECT testdocs/sqlite3.c /^#define SQLITE_LIMIT_COMPOUND_SELECT /;" d file: +SQLITE_LIMIT_EXPR_DEPTH testdocs/sqlite3.c /^#define SQLITE_LIMIT_EXPR_DEPTH /;" d file: +SQLITE_LIMIT_FUNCTION_ARG testdocs/sqlite3.c /^#define SQLITE_LIMIT_FUNCTION_ARG /;" d file: +SQLITE_LIMIT_LENGTH testdocs/sqlite3.c /^#define SQLITE_LIMIT_LENGTH /;" d file: +SQLITE_LIMIT_LIKE_PATTERN_LENGTH testdocs/sqlite3.c /^#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH /;" d file: +SQLITE_LIMIT_SQL_LENGTH testdocs/sqlite3.c /^#define SQLITE_LIMIT_SQL_LENGTH /;" d file: +SQLITE_LIMIT_TRIGGER_DEPTH testdocs/sqlite3.c /^#define SQLITE_LIMIT_TRIGGER_DEPTH /;" d file: +SQLITE_LIMIT_VARIABLE_NUMBER testdocs/sqlite3.c /^#define SQLITE_LIMIT_VARIABLE_NUMBER /;" d file: +SQLITE_LIMIT_VDBE_OP testdocs/sqlite3.c /^#define SQLITE_LIMIT_VDBE_OP /;" d file: +SQLITE_LIMIT_WORKER_THREADS testdocs/sqlite3.c /^#define SQLITE_LIMIT_WORKER_THREADS /;" d file: +SQLITE_LITTLEENDIAN testdocs/sqlite3.c /^# define SQLITE_LITTLEENDIAN /;" d file: +SQLITE_LOCKED testdocs/sqlite3.c /^#define SQLITE_LOCKED /;" d file: +SQLITE_LOCKED_SHAREDCACHE testdocs/sqlite3.c /^#define SQLITE_LOCKED_SHAREDCACHE /;" d file: +SQLITE_LOCKFILEEX_FLAGS testdocs/sqlite3.c /^# define SQLITE_LOCKFILEEX_FLAGS /;" d file: +SQLITE_LOCKFILE_FLAGS testdocs/sqlite3.c /^# define SQLITE_LOCKFILE_FLAGS /;" d file: +SQLITE_LOCK_EXCLUSIVE testdocs/sqlite3.c /^#define SQLITE_LOCK_EXCLUSIVE /;" d file: +SQLITE_LOCK_NONE testdocs/sqlite3.c /^#define SQLITE_LOCK_NONE /;" d file: +SQLITE_LOCK_PENDING testdocs/sqlite3.c /^#define SQLITE_LOCK_PENDING /;" d file: +SQLITE_LOCK_RESERVED testdocs/sqlite3.c /^#define SQLITE_LOCK_RESERVED /;" d file: +SQLITE_LOCK_SHARED testdocs/sqlite3.c /^#define SQLITE_LOCK_SHARED /;" d file: +SQLITE_LegacyFileFmt testdocs/sqlite3.c /^#define SQLITE_LegacyFileFmt /;" d file: +SQLITE_LoadExtFunc testdocs/sqlite3.c /^#define SQLITE_LoadExtFunc /;" d file: +SQLITE_LoadExtension testdocs/sqlite3.c /^#define SQLITE_LoadExtension /;" d file: +SQLITE_MAGIC_BUSY testdocs/sqlite3.c /^#define SQLITE_MAGIC_BUSY /;" d file: +SQLITE_MAGIC_CLOSED testdocs/sqlite3.c /^#define SQLITE_MAGIC_CLOSED /;" d file: +SQLITE_MAGIC_ERROR testdocs/sqlite3.c /^#define SQLITE_MAGIC_ERROR /;" d file: +SQLITE_MAGIC_OPEN testdocs/sqlite3.c /^#define SQLITE_MAGIC_OPEN /;" d file: +SQLITE_MAGIC_SICK testdocs/sqlite3.c /^#define SQLITE_MAGIC_SICK /;" d file: +SQLITE_MAGIC_ZOMBIE testdocs/sqlite3.c /^#define SQLITE_MAGIC_ZOMBIE /;" d file: +SQLITE_MALLOC testdocs/sqlite3.c /^#define SQLITE_MALLOC(/;" d file: +SQLITE_MALLOCSIZE testdocs/sqlite3.c /^# define SQLITE_MALLOCSIZE /;" d file: +SQLITE_MALLOCSIZE testdocs/sqlite3.c /^# define SQLITE_MALLOCSIZE(/;" d file: +SQLITE_MALLOCSIZE testdocs/sqlite3.c /^#define SQLITE_MALLOCSIZE(/;" d file: +SQLITE_MALLOC_SOFT_LIMIT testdocs/sqlite3.c /^# define SQLITE_MALLOC_SOFT_LIMIT /;" d file: +SQLITE_MATCH testdocs/sqlite3.c /^#define SQLITE_MATCH /;" d file: +SQLITE_MAX_ATTACHED testdocs/sqlite3.c /^# define SQLITE_MAX_ATTACHED /;" d file: +SQLITE_MAX_COLUMN testdocs/sqlite3.c /^# define SQLITE_MAX_COLUMN /;" d file: +SQLITE_MAX_COMPOUND_SELECT testdocs/sqlite3.c /^# define SQLITE_MAX_COMPOUND_SELECT /;" d file: +SQLITE_MAX_DEFAULT_PAGE_SIZE testdocs/sqlite3.c /^# define SQLITE_MAX_DEFAULT_PAGE_SIZE /;" d file: +SQLITE_MAX_DEFAULT_PAGE_SIZE testdocs/sqlite3.c /^# undef SQLITE_MAX_DEFAULT_PAGE_SIZE$/;" d file: +SQLITE_MAX_EXPR_DEPTH testdocs/sqlite3.c /^# define SQLITE_MAX_EXPR_DEPTH /;" d file: +SQLITE_MAX_FILE_FORMAT testdocs/sqlite3.c /^#define SQLITE_MAX_FILE_FORMAT /;" d file: +SQLITE_MAX_FUNCTION_ARG testdocs/sqlite3.c /^# define SQLITE_MAX_FUNCTION_ARG /;" d file: +SQLITE_MAX_LENGTH testdocs/sqlite3.c /^# define SQLITE_MAX_LENGTH /;" d file: +SQLITE_MAX_LIKE_PATTERN_LENGTH testdocs/sqlite3.c /^# define SQLITE_MAX_LIKE_PATTERN_LENGTH /;" d file: +SQLITE_MAX_MMAP_SIZE testdocs/sqlite3.c /^# define SQLITE_MAX_MMAP_SIZE /;" d file: +SQLITE_MAX_MMAP_SIZE testdocs/sqlite3.c /^# define SQLITE_MAX_MMAP_SIZE /;" d file: +SQLITE_MAX_MMAP_SIZE testdocs/sqlite3.c /^# undef SQLITE_MAX_MMAP_SIZE$/;" d file: +SQLITE_MAX_MMAP_SIZE_xc testdocs/sqlite3.c /^# define SQLITE_MAX_MMAP_SIZE_xc /;" d file: +SQLITE_MAX_PAGE_COUNT testdocs/sqlite3.c /^# define SQLITE_MAX_PAGE_COUNT /;" d file: +SQLITE_MAX_PAGE_SIZE testdocs/sqlite3.c /^# undef SQLITE_MAX_PAGE_SIZE$/;" d file: +SQLITE_MAX_PAGE_SIZE testdocs/sqlite3.c /^#define SQLITE_MAX_PAGE_SIZE /;" d file: +SQLITE_MAX_PMASZ testdocs/sqlite3.c /^#define SQLITE_MAX_PMASZ /;" d file: +SQLITE_MAX_SCHEMA_RETRY testdocs/sqlite3.c /^# define SQLITE_MAX_SCHEMA_RETRY /;" d file: +SQLITE_MAX_SQL_LENGTH testdocs/sqlite3.c /^# define SQLITE_MAX_SQL_LENGTH /;" d file: +SQLITE_MAX_SYMLINKS testdocs/sqlite3.c /^#define SQLITE_MAX_SYMLINKS /;" d file: +SQLITE_MAX_TRIGGER_DEPTH testdocs/sqlite3.c /^# define SQLITE_MAX_TRIGGER_DEPTH /;" d file: +SQLITE_MAX_U32 testdocs/sqlite3.c /^#define SQLITE_MAX_U32 /;" d file: +SQLITE_MAX_VARIABLE_NUMBER testdocs/sqlite3.c /^# define SQLITE_MAX_VARIABLE_NUMBER /;" d file: +SQLITE_MAX_VDBE_OP testdocs/sqlite3.c /^# define SQLITE_MAX_VDBE_OP /;" d file: +SQLITE_MAX_WORKER_THREADS testdocs/sqlite3.c /^# define SQLITE_MAX_WORKER_THREADS /;" d file: +SQLITE_MAX_WORKER_THREADS testdocs/sqlite3.c /^# undef SQLITE_MAX_WORKER_THREADS$/;" d file: +SQLITE_MINIMUM_FILE_DESCRIPTOR testdocs/sqlite3.c /^# define SQLITE_MINIMUM_FILE_DESCRIPTOR /;" d file: +SQLITE_MISMATCH testdocs/sqlite3.c /^#define SQLITE_MISMATCH /;" d file: +SQLITE_MISUSE testdocs/sqlite3.c /^#define SQLITE_MISUSE /;" d file: +SQLITE_MISUSE_BKPT testdocs/sqlite3.c /^#define SQLITE_MISUSE_BKPT /;" d file: +SQLITE_MIXED_ENDIAN_64BIT_FLOAT testdocs/sqlite3.c /^# undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT$/;" d file: +SQLITE_MSVC_H testdocs/sqlite3.c /^#define SQLITE_MSVC_H$/;" d file: +SQLITE_MUTEX_FAST testdocs/sqlite3.c /^#define SQLITE_MUTEX_FAST /;" d file: +SQLITE_MUTEX_NOOP testdocs/sqlite3.c /^# define SQLITE_MUTEX_NOOP$/;" d file: +SQLITE_MUTEX_NREF testdocs/sqlite3.c /^# define SQLITE_MUTEX_NREF /;" d file: +SQLITE_MUTEX_OMIT testdocs/sqlite3.c /^# define SQLITE_MUTEX_OMIT$/;" d file: +SQLITE_MUTEX_PTHREADS testdocs/sqlite3.c /^# define SQLITE_MUTEX_PTHREADS$/;" d file: +SQLITE_MUTEX_RECURSIVE testdocs/sqlite3.c /^#define SQLITE_MUTEX_RECURSIVE /;" d file: +SQLITE_MUTEX_STATIC_APP1 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_APP1 /;" d file: +SQLITE_MUTEX_STATIC_APP2 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_APP2 /;" d file: +SQLITE_MUTEX_STATIC_APP3 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_APP3 /;" d file: +SQLITE_MUTEX_STATIC_LRU testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_LRU /;" d file: +SQLITE_MUTEX_STATIC_LRU2 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_LRU2 /;" d file: +SQLITE_MUTEX_STATIC_MASTER testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_MASTER /;" d file: +SQLITE_MUTEX_STATIC_MEM testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_MEM /;" d file: +SQLITE_MUTEX_STATIC_MEM2 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_MEM2 /;" d file: +SQLITE_MUTEX_STATIC_OPEN testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_OPEN /;" d file: +SQLITE_MUTEX_STATIC_PMEM testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_PMEM /;" d file: +SQLITE_MUTEX_STATIC_PRNG testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_PRNG /;" d file: +SQLITE_MUTEX_STATIC_VFS1 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_VFS1 /;" d file: +SQLITE_MUTEX_STATIC_VFS2 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_VFS2 /;" d file: +SQLITE_MUTEX_STATIC_VFS3 testdocs/sqlite3.c /^#define SQLITE_MUTEX_STATIC_VFS3 /;" d file: +SQLITE_MUTEX_W32 testdocs/sqlite3.c /^# define SQLITE_MUTEX_W32$/;" d file: +SQLITE_MX_JUMP_OPCODE testdocs/sqlite3.c /^#define SQLITE_MX_JUMP_OPCODE /;" d file: +SQLITE_NEED_ERR_NAME testdocs/sqlite3.c /^# define SQLITE_NEED_ERR_NAME$/;" d file: +SQLITE_NEED_ERR_NAME testdocs/sqlite3.c /^# undef SQLITE_NEED_ERR_NAME$/;" d file: +SQLITE_NOINLINE testdocs/sqlite3.c /^# define SQLITE_NOINLINE /;" d file: +SQLITE_NOINLINE testdocs/sqlite3.c /^# define SQLITE_NOINLINE$/;" d file: +SQLITE_NOLFS testdocs/sqlite3.c /^#define SQLITE_NOLFS /;" d file: +SQLITE_NOMATCH testdocs/sqlite3.c /^#define SQLITE_NOMATCH /;" d file: +SQLITE_NOMEM testdocs/sqlite3.c /^#define SQLITE_NOMEM /;" d file: +SQLITE_NOMEM_BKPT testdocs/sqlite3.c /^# define SQLITE_NOMEM_BKPT /;" d file: +SQLITE_NOTADB testdocs/sqlite3.c /^#define SQLITE_NOTADB /;" d file: +SQLITE_NOTFOUND testdocs/sqlite3.c /^#define SQLITE_NOTFOUND /;" d file: +SQLITE_NOTICE testdocs/sqlite3.c /^#define SQLITE_NOTICE /;" d file: +SQLITE_NOTICE_RECOVER_ROLLBACK testdocs/sqlite3.c /^#define SQLITE_NOTICE_RECOVER_ROLLBACK /;" d file: +SQLITE_NOTICE_RECOVER_WAL testdocs/sqlite3.c /^#define SQLITE_NOTICE_RECOVER_WAL /;" d file: +SQLITE_NOTNULL testdocs/sqlite3.c /^#define SQLITE_NOTNULL /;" d file: +SQLITE_NOWILDCARDMATCH testdocs/sqlite3.c /^#define SQLITE_NOWILDCARDMATCH /;" d file: +SQLITE_NULL testdocs/sqlite3.c /^#define SQLITE_NULL /;" d file: +SQLITE_NULLEQ testdocs/sqlite3.c /^#define SQLITE_NULLEQ /;" d file: +SQLITE_N_BTREE_META testdocs/sqlite3.c /^#define SQLITE_N_BTREE_META /;" d file: +SQLITE_N_COLCACHE testdocs/sqlite3.c /^# define SQLITE_N_COLCACHE /;" d file: +SQLITE_N_KEYWORD testdocs/sqlite3.c /^#define SQLITE_N_KEYWORD /;" d file: +SQLITE_N_LIMIT testdocs/sqlite3.c /^#define SQLITE_N_LIMIT /;" d file: +SQLITE_NoCkptOnClose testdocs/sqlite3.c /^#define SQLITE_NoCkptOnClose /;" d file: +SQLITE_NullCallback testdocs/sqlite3.c /^#define SQLITE_NullCallback /;" d file: +SQLITE_OK testdocs/sqlite3.c /^#define SQLITE_OK /;" d file: +SQLITE_OK_LOAD_PERMANENTLY testdocs/sqlite3.c /^#define SQLITE_OK_LOAD_PERMANENTLY /;" d file: +SQLITE_OMIT_DATETIME_FUNCS testdocs/sqlite3.c /^# define SQLITE_OMIT_DATETIME_FUNCS /;" d file: +SQLITE_OMIT_LOAD_EXTENSION testdocs/sqlite3.c /^#define SQLITE_OMIT_LOAD_EXTENSION /;" d file: +SQLITE_OMIT_TRACE testdocs/sqlite3.c /^# define SQLITE_OMIT_TRACE /;" d file: +SQLITE_OPEN_AUTOPROXY testdocs/sqlite3.c /^#define SQLITE_OPEN_AUTOPROXY /;" d file: +SQLITE_OPEN_CREATE testdocs/sqlite3.c /^#define SQLITE_OPEN_CREATE /;" d file: +SQLITE_OPEN_DELETEONCLOSE testdocs/sqlite3.c /^#define SQLITE_OPEN_DELETEONCLOSE /;" d file: +SQLITE_OPEN_EXCLUSIVE testdocs/sqlite3.c /^#define SQLITE_OPEN_EXCLUSIVE /;" d file: +SQLITE_OPEN_FULLMUTEX testdocs/sqlite3.c /^#define SQLITE_OPEN_FULLMUTEX /;" d file: +SQLITE_OPEN_MAIN_DB testdocs/sqlite3.c /^#define SQLITE_OPEN_MAIN_DB /;" d file: +SQLITE_OPEN_MAIN_JOURNAL testdocs/sqlite3.c /^#define SQLITE_OPEN_MAIN_JOURNAL /;" d file: +SQLITE_OPEN_MASTER_JOURNAL testdocs/sqlite3.c /^#define SQLITE_OPEN_MASTER_JOURNAL /;" d file: +SQLITE_OPEN_MEMORY testdocs/sqlite3.c /^#define SQLITE_OPEN_MEMORY /;" d file: +SQLITE_OPEN_NOMUTEX testdocs/sqlite3.c /^#define SQLITE_OPEN_NOMUTEX /;" d file: +SQLITE_OPEN_PRIVATECACHE testdocs/sqlite3.c /^#define SQLITE_OPEN_PRIVATECACHE /;" d file: +SQLITE_OPEN_READONLY testdocs/sqlite3.c /^#define SQLITE_OPEN_READONLY /;" d file: +SQLITE_OPEN_READWRITE testdocs/sqlite3.c /^#define SQLITE_OPEN_READWRITE /;" d file: +SQLITE_OPEN_SHAREDCACHE testdocs/sqlite3.c /^#define SQLITE_OPEN_SHAREDCACHE /;" d file: +SQLITE_OPEN_SUBJOURNAL testdocs/sqlite3.c /^#define SQLITE_OPEN_SUBJOURNAL /;" d file: +SQLITE_OPEN_TEMP_DB testdocs/sqlite3.c /^#define SQLITE_OPEN_TEMP_DB /;" d file: +SQLITE_OPEN_TEMP_JOURNAL testdocs/sqlite3.c /^#define SQLITE_OPEN_TEMP_JOURNAL /;" d file: +SQLITE_OPEN_TRANSIENT_DB testdocs/sqlite3.c /^#define SQLITE_OPEN_TRANSIENT_DB /;" d file: +SQLITE_OPEN_URI testdocs/sqlite3.c /^#define SQLITE_OPEN_URI /;" d file: +SQLITE_OPEN_WAL testdocs/sqlite3.c /^#define SQLITE_OPEN_WAL /;" d file: +SQLITE_OS_OTHER testdocs/sqlite3.c /^# undef SQLITE_OS_OTHER$/;" d file: +SQLITE_OS_OTHER testdocs/sqlite3.c /^# define SQLITE_OS_OTHER /;" d file: +SQLITE_OS_OTHER testdocs/sqlite3.c /^#define SQLITE_OS_OTHER /;" d file: +SQLITE_OS_SETUP_H testdocs/sqlite3.c /^#define SQLITE_OS_SETUP_H$/;" d file: +SQLITE_OS_UNIX testdocs/sqlite3.c /^# define SQLITE_OS_UNIX /;" d file: +SQLITE_OS_UNIX testdocs/sqlite3.c /^# define SQLITE_OS_UNIX /;" d file: +SQLITE_OS_UNIX testdocs/sqlite3.c /^# undef SQLITE_OS_UNIX$/;" d file: +SQLITE_OS_WIN testdocs/sqlite3.c /^# define SQLITE_OS_WIN /;" d file: +SQLITE_OS_WIN testdocs/sqlite3.c /^# define SQLITE_OS_WIN /;" d file: +SQLITE_OS_WIN testdocs/sqlite3.c /^# undef SQLITE_OS_WIN$/;" d file: +SQLITE_OS_WINCE testdocs/sqlite3.c /^# define SQLITE_OS_WINCE /;" d file: +SQLITE_OS_WINNT testdocs/sqlite3.c /^# define SQLITE_OS_WINNT /;" d file: +SQLITE_OS_WINRT testdocs/sqlite3.c /^# define SQLITE_OS_WINRT /;" d file: +SQLITE_OS_WIN_H testdocs/sqlite3.c /^#define SQLITE_OS_WIN_H$/;" d file: +SQLITE_OS_WIN_THREADS testdocs/sqlite3.c /^# define SQLITE_OS_WIN_THREADS /;" d file: +SQLITE_OmitNoopJoin testdocs/sqlite3.c /^#define SQLITE_OmitNoopJoin /;" d file: +SQLITE_OrderByIdxJoin testdocs/sqlite3.c /^#define SQLITE_OrderByIdxJoin /;" d file: +SQLITE_PAGER_H testdocs/sqlite3.c /^#define SQLITE_PAGER_H$/;" d file: +SQLITE_PERM testdocs/sqlite3.c /^#define SQLITE_PERM /;" d file: +SQLITE_POWERSAFE_OVERWRITE testdocs/sqlite3.c /^# define SQLITE_POWERSAFE_OVERWRITE /;" d file: +SQLITE_PRAGMA testdocs/sqlite3.c /^#define SQLITE_PRAGMA /;" d file: +SQLITE_PRINTF_INTERNAL testdocs/sqlite3.c /^#define SQLITE_PRINTF_INTERNAL /;" d file: +SQLITE_PRINTF_MALLOCED testdocs/sqlite3.c /^#define SQLITE_PRINTF_MALLOCED /;" d file: +SQLITE_PRINTF_SQLFUNC testdocs/sqlite3.c /^#define SQLITE_PRINTF_SQLFUNC /;" d file: +SQLITE_PRINT_BUF_SIZE testdocs/sqlite3.c /^# define SQLITE_PRINT_BUF_SIZE /;" d file: +SQLITE_PRIVATE testdocs/sqlite3.c /^# define SQLITE_PRIVATE /;" d file: +SQLITE_PROTOCOL testdocs/sqlite3.c /^#define SQLITE_PROTOCOL /;" d file: +SQLITE_PTRSIZE testdocs/sqlite3.c /^# define SQLITE_PTRSIZE /;" d file: +SQLITE_PTR_TO_INT testdocs/sqlite3.c /^# define SQLITE_PTR_TO_INT(/;" d file: +SQLITE_PreferBuiltin testdocs/sqlite3.c /^#define SQLITE_PreferBuiltin /;" d file: +SQLITE_QueryFlattener testdocs/sqlite3.c /^#define SQLITE_QueryFlattener /;" d file: +SQLITE_QueryOnly testdocs/sqlite3.c /^#define SQLITE_QueryOnly /;" d file: +SQLITE_RANGE testdocs/sqlite3.c /^#define SQLITE_RANGE /;" d file: +SQLITE_RBU_STATE_CHECKPOINT testdocs/sqlite3.c /^#define SQLITE_RBU_STATE_CHECKPOINT /;" d file: +SQLITE_RBU_STATE_DONE testdocs/sqlite3.c /^#define SQLITE_RBU_STATE_DONE /;" d file: +SQLITE_RBU_STATE_ERROR testdocs/sqlite3.c /^#define SQLITE_RBU_STATE_ERROR /;" d file: +SQLITE_RBU_STATE_MOVE testdocs/sqlite3.c /^#define SQLITE_RBU_STATE_MOVE /;" d file: +SQLITE_RBU_STATE_OAL testdocs/sqlite3.c /^#define SQLITE_RBU_STATE_OAL /;" d file: +SQLITE_RBU_UPDATE_CACHESIZE testdocs/sqlite3.c /^#define SQLITE_RBU_UPDATE_CACHESIZE /;" d file: +SQLITE_READ testdocs/sqlite3.c /^#define SQLITE_READ /;" d file: +SQLITE_READONLY testdocs/sqlite3.c /^#define SQLITE_READONLY /;" d file: +SQLITE_READONLY_CANTLOCK testdocs/sqlite3.c /^#define SQLITE_READONLY_CANTLOCK /;" d file: +SQLITE_READONLY_DBMOVED testdocs/sqlite3.c /^#define SQLITE_READONLY_DBMOVED /;" d file: +SQLITE_READONLY_RECOVERY testdocs/sqlite3.c /^#define SQLITE_READONLY_RECOVERY /;" d file: +SQLITE_READONLY_ROLLBACK testdocs/sqlite3.c /^#define SQLITE_READONLY_ROLLBACK /;" d file: +SQLITE_REALLOC testdocs/sqlite3.c /^#define SQLITE_REALLOC(/;" d file: +SQLITE_RECURSIVE testdocs/sqlite3.c /^#define SQLITE_RECURSIVE /;" d file: +SQLITE_REINDEX testdocs/sqlite3.c /^#define SQLITE_REINDEX /;" d file: +SQLITE_REPLACE testdocs/sqlite3.c /^#define SQLITE_REPLACE /;" d file: +SQLITE_ROLLBACK testdocs/sqlite3.c /^#define SQLITE_ROLLBACK /;" d file: +SQLITE_ROW testdocs/sqlite3.c /^#define SQLITE_ROW /;" d file: +SQLITE_ReadUncommitted testdocs/sqlite3.c /^#define SQLITE_ReadUncommitted /;" d file: +SQLITE_RecTriggers testdocs/sqlite3.c /^#define SQLITE_RecTriggers /;" d file: +SQLITE_RecoveryMode testdocs/sqlite3.c /^#define SQLITE_RecoveryMode /;" d file: +SQLITE_ReverseOrder testdocs/sqlite3.c /^#define SQLITE_ReverseOrder /;" d file: +SQLITE_SAVEPOINT testdocs/sqlite3.c /^#define SQLITE_SAVEPOINT /;" d file: +SQLITE_SCANSTAT_EST testdocs/sqlite3.c /^#define SQLITE_SCANSTAT_EST /;" d file: +SQLITE_SCANSTAT_EXPLAIN testdocs/sqlite3.c /^#define SQLITE_SCANSTAT_EXPLAIN /;" d file: +SQLITE_SCANSTAT_NAME testdocs/sqlite3.c /^#define SQLITE_SCANSTAT_NAME /;" d file: +SQLITE_SCANSTAT_NLOOP testdocs/sqlite3.c /^#define SQLITE_SCANSTAT_NLOOP /;" d file: +SQLITE_SCANSTAT_NVISIT testdocs/sqlite3.c /^#define SQLITE_SCANSTAT_NVISIT /;" d file: +SQLITE_SCANSTAT_SELECTID testdocs/sqlite3.c /^#define SQLITE_SCANSTAT_SELECTID /;" d file: +SQLITE_SCHEMA testdocs/sqlite3.c /^#define SQLITE_SCHEMA /;" d file: +SQLITE_SELECT testdocs/sqlite3.c /^#define SQLITE_SELECT /;" d file: +SQLITE_SET_LOCKPROXYFILE testdocs/sqlite3.c /^#define SQLITE_SET_LOCKPROXYFILE /;" d file: +SQLITE_SHM_EXCLUSIVE testdocs/sqlite3.c /^#define SQLITE_SHM_EXCLUSIVE /;" d file: +SQLITE_SHM_LOCK testdocs/sqlite3.c /^#define SQLITE_SHM_LOCK /;" d file: +SQLITE_SHM_NLOCK testdocs/sqlite3.c /^#define SQLITE_SHM_NLOCK /;" d file: +SQLITE_SHM_SHARED testdocs/sqlite3.c /^#define SQLITE_SHM_SHARED /;" d file: +SQLITE_SHM_UNLOCK testdocs/sqlite3.c /^#define SQLITE_SHM_UNLOCK /;" d file: +SQLITE_SKIP_UTF8 testdocs/sqlite3.c /^#define SQLITE_SKIP_UTF8(/;" d file: +SQLITE_SORTER_PMASZ testdocs/sqlite3.c /^# define SQLITE_SORTER_PMASZ /;" d file: +SQLITE_SOURCE_ID testdocs/sqlite3.c /^#define SQLITE_SOURCE_ID /;" d file: +SQLITE_SO_ASC testdocs/sqlite3.c /^#define SQLITE_SO_ASC /;" d file: +SQLITE_SO_DESC testdocs/sqlite3.c /^#define SQLITE_SO_DESC /;" d file: +SQLITE_SO_UNDEFINED testdocs/sqlite3.c /^#define SQLITE_SO_UNDEFINED /;" d file: +SQLITE_STAT4_SAMPLES testdocs/sqlite3.c /^# define SQLITE_STAT4_SAMPLES /;" d file: +SQLITE_STAT4_SAMPLES testdocs/sqlite3.c /^# undef SQLITE_STAT4_SAMPLES$/;" d file: +SQLITE_STATIC testdocs/sqlite3.c /^#define SQLITE_STATIC /;" d file: +SQLITE_STATUS_MALLOC_COUNT testdocs/sqlite3.c /^#define SQLITE_STATUS_MALLOC_COUNT /;" d file: +SQLITE_STATUS_MALLOC_SIZE testdocs/sqlite3.c /^#define SQLITE_STATUS_MALLOC_SIZE /;" d file: +SQLITE_STATUS_MEMORY_USED testdocs/sqlite3.c /^#define SQLITE_STATUS_MEMORY_USED /;" d file: +SQLITE_STATUS_PAGECACHE_OVERFLOW testdocs/sqlite3.c /^#define SQLITE_STATUS_PAGECACHE_OVERFLOW /;" d file: +SQLITE_STATUS_PAGECACHE_SIZE testdocs/sqlite3.c /^#define SQLITE_STATUS_PAGECACHE_SIZE /;" d file: +SQLITE_STATUS_PAGECACHE_USED testdocs/sqlite3.c /^#define SQLITE_STATUS_PAGECACHE_USED /;" d file: +SQLITE_STATUS_PARSER_STACK testdocs/sqlite3.c /^#define SQLITE_STATUS_PARSER_STACK /;" d file: +SQLITE_STATUS_SCRATCH_OVERFLOW testdocs/sqlite3.c /^#define SQLITE_STATUS_SCRATCH_OVERFLOW /;" d file: +SQLITE_STATUS_SCRATCH_SIZE testdocs/sqlite3.c /^#define SQLITE_STATUS_SCRATCH_SIZE /;" d file: +SQLITE_STATUS_SCRATCH_USED testdocs/sqlite3.c /^#define SQLITE_STATUS_SCRATCH_USED /;" d file: +SQLITE_STDCALL testdocs/sqlite3.c /^# define SQLITE_STDCALL /;" d file: +SQLITE_STMTJRNL_SPILL testdocs/sqlite3.c /^# define SQLITE_STMTJRNL_SPILL /;" d file: +SQLITE_STMTSTATUS_AUTOINDEX testdocs/sqlite3.c /^#define SQLITE_STMTSTATUS_AUTOINDEX /;" d file: +SQLITE_STMTSTATUS_FULLSCAN_STEP testdocs/sqlite3.c /^#define SQLITE_STMTSTATUS_FULLSCAN_STEP /;" d file: +SQLITE_STMTSTATUS_SORT testdocs/sqlite3.c /^#define SQLITE_STMTSTATUS_SORT /;" d file: +SQLITE_STMTSTATUS_VM_STEP testdocs/sqlite3.c /^#define SQLITE_STMTSTATUS_VM_STEP /;" d file: +SQLITE_STOREP2 testdocs/sqlite3.c /^#define SQLITE_STOREP2 /;" d file: +SQLITE_SYNC_DATAONLY testdocs/sqlite3.c /^#define SQLITE_SYNC_DATAONLY /;" d file: +SQLITE_SYNC_FULL testdocs/sqlite3.c /^#define SQLITE_SYNC_FULL /;" d file: +SQLITE_SYNC_MASK testdocs/sqlite3.c /^#define SQLITE_SYNC_MASK /;" d file: +SQLITE_SYNC_NORMAL testdocs/sqlite3.c /^#define SQLITE_SYNC_NORMAL /;" d file: +SQLITE_SYSAPI testdocs/sqlite3.c /^# define SQLITE_SYSAPI$/;" d file: +SQLITE_SYSTEM_MALLOC testdocs/sqlite3.c /^# define SQLITE_SYSTEM_MALLOC /;" d file: +SQLITE_ShortColNames testdocs/sqlite3.c /^#define SQLITE_ShortColNames /;" d file: +SQLITE_SqlTrace testdocs/sqlite3.c /^#define SQLITE_SqlTrace /;" d file: +SQLITE_Stat34 testdocs/sqlite3.c /^#define SQLITE_Stat34 /;" d file: +SQLITE_SubqCoroutine testdocs/sqlite3.c /^#define SQLITE_SubqCoroutine /;" d file: +SQLITE_TCLAPI testdocs/sqlite3.c /^# define SQLITE_TCLAPI$/;" d file: +SQLITE_TEMP_FILE_PREFIX testdocs/sqlite3.c /^# define SQLITE_TEMP_FILE_PREFIX /;" d file: +SQLITE_TEMP_STORE testdocs/sqlite3.c /^# define SQLITE_TEMP_STORE /;" d file: +SQLITE_TEMP_STORE_xc testdocs/sqlite3.c /^# define SQLITE_TEMP_STORE_xc /;" d file: +SQLITE_TESTCTRL_ALWAYS testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_ALWAYS /;" d file: +SQLITE_TESTCTRL_ASSERT testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_ASSERT /;" d file: +SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS /;" d file: +SQLITE_TESTCTRL_BITVEC_TEST testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_BITVEC_TEST /;" d file: +SQLITE_TESTCTRL_BYTEORDER testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_BYTEORDER /;" d file: +SQLITE_TESTCTRL_EXPLAIN_STMT testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_EXPLAIN_STMT /;" d file: +SQLITE_TESTCTRL_FAULT_INSTALL testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_FAULT_INSTALL /;" d file: +SQLITE_TESTCTRL_FIRST testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_FIRST /;" d file: +SQLITE_TESTCTRL_IMPOSTER testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_IMPOSTER /;" d file: +SQLITE_TESTCTRL_ISINIT testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_ISINIT /;" d file: +SQLITE_TESTCTRL_ISKEYWORD testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_ISKEYWORD /;" d file: +SQLITE_TESTCTRL_LAST testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_LAST /;" d file: +SQLITE_TESTCTRL_LOCALTIME_FAULT testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_LOCALTIME_FAULT /;" d file: +SQLITE_TESTCTRL_NEVER_CORRUPT testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_NEVER_CORRUPT /;" d file: +SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD /;" d file: +SQLITE_TESTCTRL_OPTIMIZATIONS testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_OPTIMIZATIONS /;" d file: +SQLITE_TESTCTRL_PENDING_BYTE testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_PENDING_BYTE /;" d file: +SQLITE_TESTCTRL_PRNG_RESET testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_PRNG_RESET /;" d file: +SQLITE_TESTCTRL_PRNG_RESTORE testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_PRNG_RESTORE /;" d file: +SQLITE_TESTCTRL_PRNG_SAVE testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_PRNG_SAVE /;" d file: +SQLITE_TESTCTRL_RESERVE testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_RESERVE /;" d file: +SQLITE_TESTCTRL_SCRATCHMALLOC testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_SCRATCHMALLOC /;" d file: +SQLITE_TESTCTRL_SORTER_MMAP testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_SORTER_MMAP /;" d file: +SQLITE_TESTCTRL_VDBE_COVERAGE testdocs/sqlite3.c /^#define SQLITE_TESTCTRL_VDBE_COVERAGE /;" d file: +SQLITE_TEXT testdocs/sqlite3.c /^# define SQLITE_TEXT /;" d file: +SQLITE_TEXT testdocs/sqlite3.c /^# undef SQLITE_TEXT$/;" d file: +SQLITE_THREADSAFE testdocs/sqlite3.c /^# define SQLITE_THREADSAFE /;" d file: +SQLITE_THREADS_IMPLEMENTED testdocs/sqlite3.c /^#define SQLITE_THREADS_IMPLEMENTED /;" d file: +SQLITE_TOOBIG testdocs/sqlite3.c /^#define SQLITE_TOOBIG /;" d file: +SQLITE_TRACE_CLOSE testdocs/sqlite3.c /^#define SQLITE_TRACE_CLOSE /;" d file: +SQLITE_TRACE_LEGACY testdocs/sqlite3.c /^#define SQLITE_TRACE_LEGACY /;" d file: +SQLITE_TRACE_PROFILE testdocs/sqlite3.c /^#define SQLITE_TRACE_PROFILE /;" d file: +SQLITE_TRACE_ROW testdocs/sqlite3.c /^#define SQLITE_TRACE_ROW /;" d file: +SQLITE_TRACE_STMT testdocs/sqlite3.c /^#define SQLITE_TRACE_STMT /;" d file: +SQLITE_TRANSACTION testdocs/sqlite3.c /^#define SQLITE_TRANSACTION /;" d file: +SQLITE_TRANSIENT testdocs/sqlite3.c /^#define SQLITE_TRANSIENT /;" d file: +SQLITE_Transitive testdocs/sqlite3.c /^#define SQLITE_Transitive /;" d file: +SQLITE_UNIX_THREADS testdocs/sqlite3.c /^# define SQLITE_UNIX_THREADS /;" d file: +SQLITE_UPDATE testdocs/sqlite3.c /^#define SQLITE_UPDATE /;" d file: +SQLITE_USE_MALLOC_H testdocs/sqlite3.c /^# define SQLITE_USE_MALLOC_H /;" d file: +SQLITE_USE_MALLOC_H testdocs/sqlite3.c /^# define SQLITE_USE_MALLOC_H$/;" d file: +SQLITE_USE_MALLOC_USABLE_SIZE testdocs/sqlite3.c /^# define SQLITE_USE_MALLOC_USABLE_SIZE /;" d file: +SQLITE_USE_MSIZE testdocs/sqlite3.c /^# define SQLITE_USE_MSIZE$/;" d file: +SQLITE_USE_URI testdocs/sqlite3.c /^# define SQLITE_USE_URI /;" d file: +SQLITE_UTF16 testdocs/sqlite3.c /^#define SQLITE_UTF16 /;" d file: +SQLITE_UTF16BE testdocs/sqlite3.c /^#define SQLITE_UTF16BE /;" d file: +SQLITE_UTF16LE testdocs/sqlite3.c /^#define SQLITE_UTF16LE /;" d file: +SQLITE_UTF16NATIVE testdocs/sqlite3.c /^# define SQLITE_UTF16NATIVE /;" d file: +SQLITE_UTF16_ALIGNED testdocs/sqlite3.c /^#define SQLITE_UTF16_ALIGNED /;" d file: +SQLITE_UTF8 testdocs/sqlite3.c /^#define SQLITE_UTF8 /;" d file: +SQLITE_VDBEINT_H testdocs/sqlite3.c /^#define SQLITE_VDBEINT_H$/;" d file: +SQLITE_VDBE_H testdocs/sqlite3.c /^#define SQLITE_VDBE_H$/;" d file: +SQLITE_VERSION testdocs/sqlite3.c /^# undef SQLITE_VERSION$/;" d file: +SQLITE_VERSION testdocs/sqlite3.c /^#define SQLITE_VERSION /;" d file: +SQLITE_VERSION_NUMBER testdocs/sqlite3.c /^# undef SQLITE_VERSION_NUMBER$/;" d file: +SQLITE_VERSION_NUMBER testdocs/sqlite3.c /^#define SQLITE_VERSION_NUMBER /;" d file: +SQLITE_VTAB_CONSTRAINT_SUPPORT testdocs/sqlite3.c /^#define SQLITE_VTAB_CONSTRAINT_SUPPORT /;" d file: +SQLITE_Vacuum testdocs/sqlite3.c /^#define SQLITE_Vacuum /;" d file: +SQLITE_VdbeAddopTrace testdocs/sqlite3.c /^#define SQLITE_VdbeAddopTrace /;" d file: +SQLITE_VdbeEQP testdocs/sqlite3.c /^#define SQLITE_VdbeEQP /;" d file: +SQLITE_VdbeListing testdocs/sqlite3.c /^#define SQLITE_VdbeListing /;" d file: +SQLITE_VdbeTrace testdocs/sqlite3.c /^#define SQLITE_VdbeTrace /;" d file: +SQLITE_W32_MUTEX_INITIALIZER testdocs/sqlite3.c /^#define SQLITE_W32_MUTEX_INITIALIZER /;" d file: +SQLITE_WAL_H testdocs/sqlite3.c /^#define SQLITE_WAL_H$/;" d file: +SQLITE_WARNING testdocs/sqlite3.c /^#define SQLITE_WARNING /;" d file: +SQLITE_WARNING_AUTOINDEX testdocs/sqlite3.c /^#define SQLITE_WARNING_AUTOINDEX /;" d file: +SQLITE_WIN32_CACHE_SIZE testdocs/sqlite3.c /^# define SQLITE_WIN32_CACHE_SIZE /;" d file: +SQLITE_WIN32_CACHE_SIZE testdocs/sqlite3.c /^# define SQLITE_WIN32_CACHE_SIZE /;" d file: +SQLITE_WIN32_CACHE_SIZE testdocs/sqlite3.c /^# undef SQLITE_WIN32_CACHE_SIZE$/;" d file: +SQLITE_WIN32_CREATEFILEMAPPINGA testdocs/sqlite3.c /^# define SQLITE_WIN32_CREATEFILEMAPPINGA /;" d file: +SQLITE_WIN32_DATA_DIRECTORY_TYPE testdocs/sqlite3.c /^# define SQLITE_WIN32_DATA_DIRECTORY_TYPE /;" d file: +SQLITE_WIN32_DBG_BUF_SIZE testdocs/sqlite3.c /^# define SQLITE_WIN32_DBG_BUF_SIZE /;" d file: +SQLITE_WIN32_GETVERSIONEX testdocs/sqlite3.c /^# define SQLITE_WIN32_GETVERSIONEX /;" d file: +SQLITE_WIN32_HAS_ANSI testdocs/sqlite3.c /^# define SQLITE_WIN32_HAS_ANSI$/;" d file: +SQLITE_WIN32_HAS_WIDE testdocs/sqlite3.c /^# define SQLITE_WIN32_HAS_WIDE$/;" d file: +SQLITE_WIN32_HEAP_CREATE testdocs/sqlite3.c /^# define SQLITE_WIN32_HEAP_CREATE /;" d file: +SQLITE_WIN32_HEAP_FLAGS testdocs/sqlite3.c /^# define SQLITE_WIN32_HEAP_FLAGS /;" d file: +SQLITE_WIN32_HEAP_INIT_EXTRA testdocs/sqlite3.c /^# define SQLITE_WIN32_HEAP_INIT_EXTRA /;" d file: +SQLITE_WIN32_HEAP_INIT_SIZE testdocs/sqlite3.c /^# define SQLITE_WIN32_HEAP_INIT_SIZE /;" d file: +SQLITE_WIN32_HEAP_MAX_INIT_SIZE testdocs/sqlite3.c /^# define SQLITE_WIN32_HEAP_MAX_INIT_SIZE /;" d file: +SQLITE_WIN32_HEAP_MAX_SIZE testdocs/sqlite3.c /^# define SQLITE_WIN32_HEAP_MAX_SIZE /;" d file: +SQLITE_WIN32_IOERR_RETRY testdocs/sqlite3.c /^# define SQLITE_WIN32_IOERR_RETRY /;" d file: +SQLITE_WIN32_IOERR_RETRY_DELAY testdocs/sqlite3.c /^# define SQLITE_WIN32_IOERR_RETRY_DELAY /;" d file: +SQLITE_WIN32_MAX_CACHE_SIZE testdocs/sqlite3.c /^# define SQLITE_WIN32_MAX_CACHE_SIZE /;" d file: +SQLITE_WIN32_MAX_ERRMSG_CHARS testdocs/sqlite3.c /^# define SQLITE_WIN32_MAX_ERRMSG_CHARS /;" d file: +SQLITE_WIN32_MAX_PATH_BYTES testdocs/sqlite3.c /^# define SQLITE_WIN32_MAX_PATH_BYTES /;" d file: +SQLITE_WIN32_MAX_PATH_CHARS testdocs/sqlite3.c /^# define SQLITE_WIN32_MAX_PATH_CHARS /;" d file: +SQLITE_WIN32_TEMP_DIRECTORY_TYPE testdocs/sqlite3.c /^# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE /;" d file: +SQLITE_WIN32_VOLATILE testdocs/sqlite3.c /^# define SQLITE_WIN32_VOLATILE /;" d file: +SQLITE_WIN32_VOLATILE testdocs/sqlite3.c /^# define SQLITE_WIN32_VOLATILE$/;" d file: +SQLITE_WINNT_MAX_PATH_BYTES testdocs/sqlite3.c /^# define SQLITE_WINNT_MAX_PATH_BYTES /;" d file: +SQLITE_WINNT_MAX_PATH_CHARS testdocs/sqlite3.c /^# define SQLITE_WINNT_MAX_PATH_CHARS /;" d file: +SQLITE_WITHIN testdocs/sqlite3.c /^#define SQLITE_WITHIN(/;" d file: +SQLITE_WSD testdocs/sqlite3.c /^ #define SQLITE_WSD /;" d file: +SQLITE_WSD testdocs/sqlite3.c /^ #define SQLITE_WSD$/;" d file: +SQLITE_WriteSchema testdocs/sqlite3.c /^#define SQLITE_WriteSchema /;" d file: +SQL_CHOMP_SEGDIR testdocs/sqlite3.c /^#define SQL_CHOMP_SEGDIR /;" d file: +SQL_CONTENT_INSERT testdocs/sqlite3.c /^#define SQL_CONTENT_INSERT /;" d file: +SQL_DELETE_ALL_CONTENT testdocs/sqlite3.c /^#define SQL_DELETE_ALL_CONTENT /;" d file: +SQL_DELETE_ALL_DOCSIZE testdocs/sqlite3.c /^#define SQL_DELETE_ALL_DOCSIZE /;" d file: +SQL_DELETE_ALL_SEGDIR testdocs/sqlite3.c /^#define SQL_DELETE_ALL_SEGDIR /;" d file: +SQL_DELETE_ALL_SEGMENTS testdocs/sqlite3.c /^#define SQL_DELETE_ALL_SEGMENTS /;" d file: +SQL_DELETE_ALL_STAT testdocs/sqlite3.c /^#define SQL_DELETE_ALL_STAT /;" d file: +SQL_DELETE_ALL_TERMS_SEGDIR testdocs/sqlite3.c /^#define SQL_DELETE_ALL_TERMS_SEGDIR /;" d file: +SQL_DELETE_CONTENT testdocs/sqlite3.c /^#define SQL_DELETE_CONTENT /;" d file: +SQL_DELETE_DOCSIZE testdocs/sqlite3.c /^#define SQL_DELETE_DOCSIZE /;" d file: +SQL_DELETE_SEGDIR_ENTRY testdocs/sqlite3.c /^#define SQL_DELETE_SEGDIR_ENTRY /;" d file: +SQL_DELETE_SEGDIR_LEVEL testdocs/sqlite3.c /^#define SQL_DELETE_SEGDIR_LEVEL /;" d file: +SQL_DELETE_SEGDIR_RANGE testdocs/sqlite3.c /^#define SQL_DELETE_SEGDIR_RANGE /;" d file: +SQL_DELETE_SEGMENTS_RANGE testdocs/sqlite3.c /^#define SQL_DELETE_SEGMENTS_RANGE /;" d file: +SQL_FIND_MERGE_LEVEL testdocs/sqlite3.c /^#define SQL_FIND_MERGE_LEVEL /;" d file: +SQL_INSERT_SEGDIR testdocs/sqlite3.c /^#define SQL_INSERT_SEGDIR /;" d file: +SQL_INSERT_SEGMENTS testdocs/sqlite3.c /^#define SQL_INSERT_SEGMENTS /;" d file: +SQL_IS_EMPTY testdocs/sqlite3.c /^#define SQL_IS_EMPTY /;" d file: +SQL_MAX_LEAF_NODE_ESTIMATE testdocs/sqlite3.c /^#define SQL_MAX_LEAF_NODE_ESTIMATE /;" d file: +SQL_NEXT_SEGMENTS_ID testdocs/sqlite3.c /^#define SQL_NEXT_SEGMENTS_ID /;" d file: +SQL_NEXT_SEGMENT_INDEX testdocs/sqlite3.c /^#define SQL_NEXT_SEGMENT_INDEX /;" d file: +SQL_REPLACE_DOCSIZE testdocs/sqlite3.c /^#define SQL_REPLACE_DOCSIZE /;" d file: +SQL_REPLACE_STAT testdocs/sqlite3.c /^#define SQL_REPLACE_STAT /;" d file: +SQL_SEGMENT_IS_APPENDABLE testdocs/sqlite3.c /^#define SQL_SEGMENT_IS_APPENDABLE /;" d file: +SQL_SELECT_ALL_LANGID testdocs/sqlite3.c /^#define SQL_SELECT_ALL_LANGID /;" d file: +SQL_SELECT_ALL_PREFIX_LEVEL testdocs/sqlite3.c /^#define SQL_SELECT_ALL_PREFIX_LEVEL /;" d file: +SQL_SELECT_CONTENT_BY_ROWID testdocs/sqlite3.c /^#define SQL_SELECT_CONTENT_BY_ROWID /;" d file: +SQL_SELECT_DOCSIZE testdocs/sqlite3.c /^#define SQL_SELECT_DOCSIZE /;" d file: +SQL_SELECT_INDEXES testdocs/sqlite3.c /^#define SQL_SELECT_INDEXES /;" d file: +SQL_SELECT_LEVEL testdocs/sqlite3.c /^#define SQL_SELECT_LEVEL /;" d file: +SQL_SELECT_LEVEL_COUNT testdocs/sqlite3.c /^#define SQL_SELECT_LEVEL_COUNT /;" d file: +SQL_SELECT_LEVEL_RANGE testdocs/sqlite3.c /^#define SQL_SELECT_LEVEL_RANGE /;" d file: +SQL_SELECT_LEVEL_RANGE2 testdocs/sqlite3.c /^#define SQL_SELECT_LEVEL_RANGE2 /;" d file: +SQL_SELECT_MXLEVEL testdocs/sqlite3.c /^#define SQL_SELECT_MXLEVEL /;" d file: +SQL_SELECT_SEGDIR testdocs/sqlite3.c /^#define SQL_SELECT_SEGDIR /;" d file: +SQL_SELECT_SEGDIR_MAX_LEVEL testdocs/sqlite3.c /^#define SQL_SELECT_SEGDIR_MAX_LEVEL /;" d file: +SQL_SELECT_STAT testdocs/sqlite3.c /^#define SQL_SELECT_STAT /;" d file: +SQL_SHIFT_SEGDIR_ENTRY testdocs/sqlite3.c /^#define SQL_SHIFT_SEGDIR_ENTRY /;" d file: +SQL_UPDATE_LEVEL testdocs/sqlite3.c /^#define SQL_UPDATE_LEVEL /;" d file: +SQL_UPDATE_LEVEL_IDX testdocs/sqlite3.c /^#define SQL_UPDATE_LEVEL_IDX /;" d file: +SQLiteThread testdocs/sqlite3.c /^struct SQLiteThread {$/;" s file: +SQLiteThread testdocs/sqlite3.c /^typedef struct SQLiteThread SQLiteThread;$/;" t typeref:struct:SQLiteThread file: +SRT_Coroutine testdocs/sqlite3.c /^#define SRT_Coroutine /;" d file: +SRT_Discard testdocs/sqlite3.c /^#define SRT_Discard /;" d file: +SRT_DistFifo testdocs/sqlite3.c /^#define SRT_DistFifo /;" d file: +SRT_DistQueue testdocs/sqlite3.c /^#define SRT_DistQueue /;" d file: +SRT_EphemTab testdocs/sqlite3.c /^#define SRT_EphemTab /;" d file: +SRT_Except testdocs/sqlite3.c /^#define SRT_Except /;" d file: +SRT_Exists testdocs/sqlite3.c /^#define SRT_Exists /;" d file: +SRT_Fifo testdocs/sqlite3.c /^#define SRT_Fifo /;" d file: +SRT_Mem testdocs/sqlite3.c /^#define SRT_Mem /;" d file: +SRT_Output testdocs/sqlite3.c /^#define SRT_Output /;" d file: +SRT_Queue testdocs/sqlite3.c /^#define SRT_Queue /;" d file: +SRT_Set testdocs/sqlite3.c /^#define SRT_Set /;" d file: +SRT_Table testdocs/sqlite3.c /^#define SRT_Table /;" d file: +SRT_Union testdocs/sqlite3.c /^#define SRT_Union /;" d file: +SRVAL testdocs/sqlite3.c /^#define SRVAL(/;" d file: +STAT_GET_NDLT testdocs/sqlite3.c /^#define STAT_GET_NDLT /;" d file: +STAT_GET_NEQ testdocs/sqlite3.c /^#define STAT_GET_NEQ /;" d file: +STAT_GET_NLT testdocs/sqlite3.c /^#define STAT_GET_NLT /;" d file: +STAT_GET_ROWID testdocs/sqlite3.c /^#define STAT_GET_ROWID /;" d file: +STAT_GET_STAT1 testdocs/sqlite3.c /^#define STAT_GET_STAT1 /;" d file: +STRACCUM_NOMEM testdocs/sqlite3.c /^#define STRACCUM_NOMEM /;" d file: +STRACCUM_TOOBIG testdocs/sqlite3.c /^#define STRACCUM_TOOBIG /;" d file: +STR_FUNCTION testdocs/sqlite3.c /^#define STR_FUNCTION(/;" d file: +SWAP testdocs/sqlite3.c /^# define SWAP(/;" d file: +SWAP testdocs/sqlite3.c /^#define SWAP(/;" d file: +SWAPVAL testdocs/sqlite3.c /^#define SWAPVAL(/;" d file: +SYSCALL testdocs/sqlite3.c /^# define SYSCALL /;" d file: +Savepoint testdocs/sqlite3.c /^struct Savepoint {$/;" s file: +Savepoint testdocs/sqlite3.c /^typedef struct Savepoint Savepoint;$/;" t typeref:struct:Savepoint file: +ScanStatus testdocs/sqlite3.c /^struct ScanStatus {$/;" s file: +ScanStatus testdocs/sqlite3.c /^typedef struct ScanStatus ScanStatus;$/;" t typeref:struct:ScanStatus file: +Schema testdocs/sqlite3.c /^struct Schema {$/;" s file: +Schema testdocs/sqlite3.c /^typedef struct Schema Schema;$/;" t typeref:struct:Schema file: +ScratchFreeslot testdocs/sqlite3.c /^typedef struct ScratchFreeslot {$/;" s file: +ScratchFreeslot testdocs/sqlite3.c /^} ScratchFreeslot;$/;" t typeref:struct:ScratchFreeslot file: +Scripting testdocs/waf /^ from waflib import Scripting$/;" i +SegmentNode testdocs/sqlite3.c /^struct SegmentNode {$/;" s file: +SegmentNode testdocs/sqlite3.c /^typedef struct SegmentNode SegmentNode;$/;" t typeref:struct:SegmentNode file: +SegmentWriter testdocs/sqlite3.c /^struct SegmentWriter {$/;" s file: +SegmentWriter testdocs/sqlite3.c /^typedef struct SegmentWriter SegmentWriter;$/;" t typeref:struct:SegmentWriter file: +Sel edit.h /^} Sel;$/;" t typeref:struct:__anon6 +Select testdocs/sqlite3.c /^struct Select {$/;" s file: +Select testdocs/sqlite3.c /^typedef struct Select Select;$/;" t typeref:struct:Select file: +SelectDest testdocs/sqlite3.c /^struct SelectDest {$/;" s file: +SelectDest testdocs/sqlite3.c /^typedef struct SelectDest SelectDest;$/;" t typeref:struct:SelectDest file: +SessionApplyCtx testdocs/sqlite3.c /^struct SessionApplyCtx {$/;" s file: +SessionApplyCtx testdocs/sqlite3.c /^typedef struct SessionApplyCtx SessionApplyCtx;$/;" t typeref:struct:SessionApplyCtx file: +SessionBuffer testdocs/sqlite3.c /^struct SessionBuffer {$/;" s file: +SessionBuffer testdocs/sqlite3.c /^typedef struct SessionBuffer SessionBuffer;$/;" t typeref:struct:SessionBuffer file: +SessionChange testdocs/sqlite3.c /^struct SessionChange {$/;" s file: +SessionChange testdocs/sqlite3.c /^typedef struct SessionChange SessionChange;$/;" t typeref:struct:SessionChange file: +SessionDiffCtx testdocs/sqlite3.c /^struct SessionDiffCtx {$/;" s file: +SessionDiffCtx testdocs/sqlite3.c /^typedef struct SessionDiffCtx SessionDiffCtx;$/;" t typeref:struct:SessionDiffCtx file: +SessionHook testdocs/sqlite3.c /^struct SessionHook {$/;" s file: +SessionHook testdocs/sqlite3.c /^typedef struct SessionHook SessionHook;$/;" t typeref:struct:SessionHook file: +SessionInput testdocs/sqlite3.c /^struct SessionInput {$/;" s file: +SessionInput testdocs/sqlite3.c /^typedef struct SessionInput SessionInput;$/;" t typeref:struct:SessionInput file: +SessionTable testdocs/sqlite3.c /^struct SessionTable {$/;" s file: +SessionTable testdocs/sqlite3.c /^typedef struct SessionTable SessionTable;$/;" t typeref:struct:SessionTable file: +ShmRegion testdocs/sqlite3.c /^ struct ShmRegion {$/;" s struct:winShmNode file: +SimulateDiskfullError testdocs/sqlite3.c /^#define SimulateDiskfullError(/;" d file: +SimulateIOError testdocs/sqlite3.c /^#define SimulateIOError(/;" d file: +SimulateIOErrorBenign testdocs/sqlite3.c /^#define SimulateIOErrorBenign(/;" d file: +SizeofArray testdocs/sqlite3.c /^#define SizeofArray(/;" d file: +SnippetFragment testdocs/sqlite3.c /^struct SnippetFragment {$/;" s file: +SnippetFragment testdocs/sqlite3.c /^typedef struct SnippetFragment SnippetFragment;$/;" t typeref:struct:SnippetFragment file: +SnippetIter testdocs/sqlite3.c /^struct SnippetIter {$/;" s file: +SnippetIter testdocs/sqlite3.c /^typedef struct SnippetIter SnippetIter;$/;" t typeref:struct:SnippetIter file: +SnippetPhrase testdocs/sqlite3.c /^struct SnippetPhrase {$/;" s file: +SnippetPhrase testdocs/sqlite3.c /^typedef struct SnippetPhrase SnippetPhrase;$/;" t typeref:struct:SnippetPhrase file: +SortByDimension testdocs/sqlite3.c /^static void SortByDimension($/;" f file: +SortByDistance testdocs/sqlite3.c /^static void SortByDistance($/;" f file: +SortCtx testdocs/sqlite3.c /^struct SortCtx {$/;" s file: +SortCtx testdocs/sqlite3.c /^typedef struct SortCtx SortCtx;$/;" t typeref:struct:SortCtx file: +SortSubtask testdocs/sqlite3.c /^struct SortSubtask {$/;" s file: +SortSubtask testdocs/sqlite3.c /^typedef struct SortSubtask SortSubtask; \/* A sub-task in the sort process *\/$/;" t typeref:struct:SortSubtask file: +SorterCompare testdocs/sqlite3.c /^typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);$/;" t file: +SorterFile testdocs/sqlite3.c /^struct SorterFile {$/;" s file: +SorterFile testdocs/sqlite3.c /^typedef struct SorterFile SorterFile; \/* Temporary file object wrapper *\/$/;" t typeref:struct:SorterFile file: +SorterList testdocs/sqlite3.c /^struct SorterList {$/;" s file: +SorterList testdocs/sqlite3.c /^typedef struct SorterList SorterList; \/* In-memory list of records *\/$/;" t typeref:struct:SorterList file: +SorterRecord testdocs/sqlite3.c /^struct SorterRecord {$/;" s file: +SorterRecord testdocs/sqlite3.c /^typedef struct SorterRecord SorterRecord; \/* A record being sorted *\/$/;" t typeref:struct:SorterRecord file: +SplitNode testdocs/sqlite3.c /^static int SplitNode($/;" f file: +Sqlite3Config testdocs/sqlite3.c /^struct Sqlite3Config {$/;" s file: +SrcCount testdocs/sqlite3.c /^struct SrcCount {$/;" s file: +SrcList testdocs/sqlite3.c /^struct SrcList {$/;" s file: +SrcList testdocs/sqlite3.c /^typedef struct SrcList SrcList;$/;" t typeref:struct:SrcList file: +SrcList_item testdocs/sqlite3.c /^ struct SrcList_item {$/;" s struct:SrcList file: +Stat4Accum testdocs/sqlite3.c /^struct Stat4Accum {$/;" s file: +Stat4Accum testdocs/sqlite3.c /^typedef struct Stat4Accum Stat4Accum;$/;" t typeref:struct:Stat4Accum file: +Stat4Sample testdocs/sqlite3.c /^struct Stat4Sample {$/;" s file: +Stat4Sample testdocs/sqlite3.c /^typedef struct Stat4Sample Stat4Sample;$/;" t typeref:struct:Stat4Sample file: +StatCell testdocs/sqlite3.c /^struct StatCell {$/;" s file: +StatCell testdocs/sqlite3.c /^typedef struct StatCell StatCell;$/;" t typeref:struct:StatCell file: +StatCursor testdocs/sqlite3.c /^struct StatCursor {$/;" s file: +StatCursor testdocs/sqlite3.c /^typedef struct StatCursor StatCursor;$/;" t typeref:struct:StatCursor file: +StatPage testdocs/sqlite3.c /^struct StatPage {$/;" s file: +StatPage testdocs/sqlite3.c /^typedef struct StatPage StatPage;$/;" t typeref:struct:StatPage file: +StatTable testdocs/sqlite3.c /^struct StatTable {$/;" s file: +StatTable testdocs/sqlite3.c /^typedef struct StatTable StatTable;$/;" t typeref:struct:StatTable file: +StrAccum testdocs/sqlite3.c /^struct StrAccum {$/;" s file: +StrAccum testdocs/sqlite3.c /^typedef struct StrAccum StrAccum;$/;" t typeref:struct:StrAccum file: +StrBuffer testdocs/sqlite3.c /^struct StrBuffer {$/;" s file: +StrBuffer testdocs/sqlite3.c /^typedef struct StrBuffer StrBuffer;$/;" t typeref:struct:StrBuffer file: +Stringify testdocs/sqlite3.c /^#define Stringify(/;" d file: +SubProgram testdocs/sqlite3.c /^struct SubProgram {$/;" s file: +SubProgram testdocs/sqlite3.c /^typedef struct SubProgram SubProgram;$/;" t typeref:struct:SubProgram file: +SubstContext testdocs/sqlite3.c /^typedef struct SubstContext {$/;" s file: +SubstContext testdocs/sqlite3.c /^} SubstContext;$/;" t typeref:struct:SubstContext file: +SumCtx testdocs/sqlite3.c /^struct SumCtx {$/;" s file: +SumCtx testdocs/sqlite3.c /^typedef struct SumCtx SumCtx;$/;" t typeref:struct:SumCtx file: +TEMP_MASTER_NAME testdocs/sqlite3.c /^#define TEMP_MASTER_NAME /;" d file: +TERM_ANDINFO testdocs/sqlite3.c /^#define TERM_ANDINFO /;" d file: +TERM_CODED testdocs/sqlite3.c /^#define TERM_CODED /;" d file: +TERM_COPIED testdocs/sqlite3.c /^#define TERM_COPIED /;" d file: +TERM_DYNAMIC testdocs/sqlite3.c /^#define TERM_DYNAMIC /;" d file: +TERM_IS testdocs/sqlite3.c /^#define TERM_IS /;" d file: +TERM_LIKE testdocs/sqlite3.c /^#define TERM_LIKE /;" d file: +TERM_LIKECOND testdocs/sqlite3.c /^#define TERM_LIKECOND /;" d file: +TERM_LIKEOPT testdocs/sqlite3.c /^#define TERM_LIKEOPT /;" d file: +TERM_ORINFO testdocs/sqlite3.c /^#define TERM_ORINFO /;" d file: +TERM_OR_OK testdocs/sqlite3.c /^#define TERM_OR_OK /;" d file: +TERM_VIRTUAL testdocs/sqlite3.c /^#define TERM_VIRTUAL /;" d file: +TERM_VNULL testdocs/sqlite3.c /^# define TERM_VNULL /;" d file: +TEST atf.h /^#define TEST(/;" d +TESTBIT testdocs/sqlite3.c /^#define TESTBIT(/;" d file: +TESTONLY testdocs/sqlite3.c /^# define TESTONLY(/;" d file: +TEST_SUITE atf.h /^#define TEST_SUITE(/;" d +TEST_SUITE testbuf.c /^TEST_SUITE(BufferTests) {$/;" f +TF_Autoincrement testdocs/sqlite3.c /^#define TF_Autoincrement /;" d file: +TF_Ephemeral testdocs/sqlite3.c /^#define TF_Ephemeral /;" d file: +TF_HasNotNull testdocs/sqlite3.c /^#define TF_HasNotNull /;" d file: +TF_HasPrimaryKey testdocs/sqlite3.c /^#define TF_HasPrimaryKey /;" d file: +TF_HasStat1 testdocs/sqlite3.c /^#define TF_HasStat1 /;" d file: +TF_NoVisibleRowid testdocs/sqlite3.c /^#define TF_NoVisibleRowid /;" d file: +TF_OOOHidden testdocs/sqlite3.c /^#define TF_OOOHidden /;" d file: +TF_Readonly testdocs/sqlite3.c /^#define TF_Readonly /;" d file: +TF_StatsUsed testdocs/sqlite3.c /^#define TF_StatsUsed /;" d file: +TF_WithoutRowid testdocs/sqlite3.c /^#define TF_WithoutRowid /;" d file: +THREE_BYTE_INT testdocs/sqlite3.c /^#define THREE_BYTE_INT(/;" d file: +TIMER_ELAPSED testdocs/sqlite3.c /^#define TIMER_ELAPSED /;" d file: +TIMER_END testdocs/sqlite3.c /^#define TIMER_END /;" d file: +TIMER_END testdocs/sqlite3.c /^#define TIMER_END$/;" d file: +TIMER_START testdocs/sqlite3.c /^#define TIMER_START /;" d file: +TIMER_START testdocs/sqlite3.c /^#define TIMER_START$/;" d file: +TKFLG_DONTFOLD testdocs/sqlite3.c /^#define TKFLG_DONTFOLD /;" d file: +TKFLG_MASK testdocs/sqlite3.c /^#define TKFLG_MASK /;" d file: +TK_ABORT testdocs/sqlite3.c /^#define TK_ABORT /;" d file: +TK_ACTION testdocs/sqlite3.c /^#define TK_ACTION /;" d file: +TK_ADD testdocs/sqlite3.c /^#define TK_ADD /;" d file: +TK_AFTER testdocs/sqlite3.c /^#define TK_AFTER /;" d file: +TK_AGG_COLUMN testdocs/sqlite3.c /^#define TK_AGG_COLUMN /;" d file: +TK_AGG_FUNCTION testdocs/sqlite3.c /^#define TK_AGG_FUNCTION /;" d file: +TK_ALL testdocs/sqlite3.c /^#define TK_ALL /;" d file: +TK_ALTER testdocs/sqlite3.c /^#define TK_ALTER /;" d file: +TK_ANALYZE testdocs/sqlite3.c /^#define TK_ANALYZE /;" d file: +TK_AND testdocs/sqlite3.c /^#define TK_AND /;" d file: +TK_ANY testdocs/sqlite3.c /^#define TK_ANY /;" d file: +TK_AS testdocs/sqlite3.c /^#define TK_AS /;" d file: +TK_ASC testdocs/sqlite3.c /^#define TK_ASC /;" d file: +TK_ASTERISK testdocs/sqlite3.c /^#define TK_ASTERISK /;" d file: +TK_ATTACH testdocs/sqlite3.c /^#define TK_ATTACH /;" d file: +TK_AUTOINCR testdocs/sqlite3.c /^#define TK_AUTOINCR /;" d file: +TK_BEFORE testdocs/sqlite3.c /^#define TK_BEFORE /;" d file: +TK_BEGIN testdocs/sqlite3.c /^#define TK_BEGIN /;" d file: +TK_BETWEEN testdocs/sqlite3.c /^#define TK_BETWEEN /;" d file: +TK_BITAND testdocs/sqlite3.c /^#define TK_BITAND /;" d file: +TK_BITNOT testdocs/sqlite3.c /^#define TK_BITNOT /;" d file: +TK_BITOR testdocs/sqlite3.c /^#define TK_BITOR /;" d file: +TK_BLOB testdocs/sqlite3.c /^#define TK_BLOB /;" d file: +TK_BY testdocs/sqlite3.c /^#define TK_BY /;" d file: +TK_CASCADE testdocs/sqlite3.c /^#define TK_CASCADE /;" d file: +TK_CASE testdocs/sqlite3.c /^#define TK_CASE /;" d file: +TK_CAST testdocs/sqlite3.c /^#define TK_CAST /;" d file: +TK_CHECK testdocs/sqlite3.c /^#define TK_CHECK /;" d file: +TK_COLLATE testdocs/sqlite3.c /^#define TK_COLLATE /;" d file: +TK_COLUMN testdocs/sqlite3.c /^#define TK_COLUMN /;" d file: +TK_COLUMNKW testdocs/sqlite3.c /^#define TK_COLUMNKW /;" d file: +TK_COMMA testdocs/sqlite3.c /^#define TK_COMMA /;" d file: +TK_COMMIT testdocs/sqlite3.c /^#define TK_COMMIT /;" d file: +TK_CONCAT testdocs/sqlite3.c /^#define TK_CONCAT /;" d file: +TK_CONFLICT testdocs/sqlite3.c /^#define TK_CONFLICT /;" d file: +TK_CONSTRAINT testdocs/sqlite3.c /^#define TK_CONSTRAINT /;" d file: +TK_CREATE testdocs/sqlite3.c /^#define TK_CREATE /;" d file: +TK_CTIME_KW testdocs/sqlite3.c /^#define TK_CTIME_KW /;" d file: +TK_DATABASE testdocs/sqlite3.c /^#define TK_DATABASE /;" d file: +TK_DEFAULT testdocs/sqlite3.c /^#define TK_DEFAULT /;" d file: +TK_DEFERRABLE testdocs/sqlite3.c /^#define TK_DEFERRABLE /;" d file: +TK_DEFERRED testdocs/sqlite3.c /^#define TK_DEFERRED /;" d file: +TK_DELETE testdocs/sqlite3.c /^#define TK_DELETE /;" d file: +TK_DESC testdocs/sqlite3.c /^#define TK_DESC /;" d file: +TK_DETACH testdocs/sqlite3.c /^#define TK_DETACH /;" d file: +TK_DISTINCT testdocs/sqlite3.c /^#define TK_DISTINCT /;" d file: +TK_DOT testdocs/sqlite3.c /^#define TK_DOT /;" d file: +TK_DROP testdocs/sqlite3.c /^#define TK_DROP /;" d file: +TK_EACH testdocs/sqlite3.c /^#define TK_EACH /;" d file: +TK_ELSE testdocs/sqlite3.c /^#define TK_ELSE /;" d file: +TK_END testdocs/sqlite3.c /^#define TK_END /;" d file: +TK_END_OF_FILE testdocs/sqlite3.c /^#define TK_END_OF_FILE /;" d file: +TK_EQ testdocs/sqlite3.c /^#define TK_EQ /;" d file: +TK_ESCAPE testdocs/sqlite3.c /^#define TK_ESCAPE /;" d file: +TK_EXCEPT testdocs/sqlite3.c /^#define TK_EXCEPT /;" d file: +TK_EXCLUSIVE testdocs/sqlite3.c /^#define TK_EXCLUSIVE /;" d file: +TK_EXISTS testdocs/sqlite3.c /^#define TK_EXISTS /;" d file: +TK_EXPLAIN testdocs/sqlite3.c /^#define TK_EXPLAIN /;" d file: +TK_FAIL testdocs/sqlite3.c /^#define TK_FAIL /;" d file: +TK_FLOAT testdocs/sqlite3.c /^#define TK_FLOAT /;" d file: +TK_FOR testdocs/sqlite3.c /^#define TK_FOR /;" d file: +TK_FOREIGN testdocs/sqlite3.c /^#define TK_FOREIGN /;" d file: +TK_FROM testdocs/sqlite3.c /^#define TK_FROM /;" d file: +TK_FUNCTION testdocs/sqlite3.c /^#define TK_FUNCTION /;" d file: +TK_GE testdocs/sqlite3.c /^#define TK_GE /;" d file: +TK_GROUP testdocs/sqlite3.c /^#define TK_GROUP /;" d file: +TK_GT testdocs/sqlite3.c /^#define TK_GT /;" d file: +TK_HAVING testdocs/sqlite3.c /^#define TK_HAVING /;" d file: +TK_ID testdocs/sqlite3.c /^#define TK_ID /;" d file: +TK_IF testdocs/sqlite3.c /^#define TK_IF /;" d file: +TK_IF_NULL_ROW testdocs/sqlite3.c /^#define TK_IF_NULL_ROW /;" d file: +TK_IGNORE testdocs/sqlite3.c /^#define TK_IGNORE /;" d file: +TK_ILLEGAL testdocs/sqlite3.c /^#define TK_ILLEGAL /;" d file: +TK_IMMEDIATE testdocs/sqlite3.c /^#define TK_IMMEDIATE /;" d file: +TK_IN testdocs/sqlite3.c /^#define TK_IN /;" d file: +TK_INDEX testdocs/sqlite3.c /^#define TK_INDEX /;" d file: +TK_INDEXED testdocs/sqlite3.c /^#define TK_INDEXED /;" d file: +TK_INITIALLY testdocs/sqlite3.c /^#define TK_INITIALLY /;" d file: +TK_INSERT testdocs/sqlite3.c /^#define TK_INSERT /;" d file: +TK_INSTEAD testdocs/sqlite3.c /^#define TK_INSTEAD /;" d file: +TK_INTEGER testdocs/sqlite3.c /^#define TK_INTEGER /;" d file: +TK_INTERSECT testdocs/sqlite3.c /^#define TK_INTERSECT /;" d file: +TK_INTO testdocs/sqlite3.c /^#define TK_INTO /;" d file: +TK_IS testdocs/sqlite3.c /^#define TK_IS /;" d file: +TK_ISNOT testdocs/sqlite3.c /^#define TK_ISNOT /;" d file: +TK_ISNULL testdocs/sqlite3.c /^#define TK_ISNULL /;" d file: +TK_JOIN testdocs/sqlite3.c /^#define TK_JOIN /;" d file: +TK_JOIN_KW testdocs/sqlite3.c /^#define TK_JOIN_KW /;" d file: +TK_KEY testdocs/sqlite3.c /^#define TK_KEY /;" d file: +TK_LE testdocs/sqlite3.c /^#define TK_LE /;" d file: +TK_LIKE_KW testdocs/sqlite3.c /^#define TK_LIKE_KW /;" d file: +TK_LIMIT testdocs/sqlite3.c /^#define TK_LIMIT /;" d file: +TK_LP testdocs/sqlite3.c /^#define TK_LP /;" d file: +TK_LSHIFT testdocs/sqlite3.c /^#define TK_LSHIFT /;" d file: +TK_LT testdocs/sqlite3.c /^#define TK_LT /;" d file: +TK_MATCH testdocs/sqlite3.c /^#define TK_MATCH /;" d file: +TK_MINUS testdocs/sqlite3.c /^#define TK_MINUS /;" d file: +TK_NE testdocs/sqlite3.c /^#define TK_NE /;" d file: +TK_NO testdocs/sqlite3.c /^#define TK_NO /;" d file: +TK_NOT testdocs/sqlite3.c /^#define TK_NOT /;" d file: +TK_NOTNULL testdocs/sqlite3.c /^#define TK_NOTNULL /;" d file: +TK_NULL testdocs/sqlite3.c /^#define TK_NULL /;" d file: +TK_OF testdocs/sqlite3.c /^#define TK_OF /;" d file: +TK_OFFSET testdocs/sqlite3.c /^#define TK_OFFSET /;" d file: +TK_ON testdocs/sqlite3.c /^#define TK_ON /;" d file: +TK_OR testdocs/sqlite3.c /^#define TK_OR /;" d file: +TK_ORDER testdocs/sqlite3.c /^#define TK_ORDER /;" d file: +TK_PLAN testdocs/sqlite3.c /^#define TK_PLAN /;" d file: +TK_PLUS testdocs/sqlite3.c /^#define TK_PLUS /;" d file: +TK_PRAGMA testdocs/sqlite3.c /^#define TK_PRAGMA /;" d file: +TK_PRIMARY testdocs/sqlite3.c /^#define TK_PRIMARY /;" d file: +TK_QUERY testdocs/sqlite3.c /^#define TK_QUERY /;" d file: +TK_RAISE testdocs/sqlite3.c /^#define TK_RAISE /;" d file: +TK_RECURSIVE testdocs/sqlite3.c /^#define TK_RECURSIVE /;" d file: +TK_REFERENCES testdocs/sqlite3.c /^#define TK_REFERENCES /;" d file: +TK_REGISTER testdocs/sqlite3.c /^#define TK_REGISTER /;" d file: +TK_REINDEX testdocs/sqlite3.c /^#define TK_REINDEX /;" d file: +TK_RELEASE testdocs/sqlite3.c /^#define TK_RELEASE /;" d file: +TK_REM testdocs/sqlite3.c /^#define TK_REM /;" d file: +TK_RENAME testdocs/sqlite3.c /^#define TK_RENAME /;" d file: +TK_REPLACE testdocs/sqlite3.c /^#define TK_REPLACE /;" d file: +TK_RESTRICT testdocs/sqlite3.c /^#define TK_RESTRICT /;" d file: +TK_ROLLBACK testdocs/sqlite3.c /^#define TK_ROLLBACK /;" d file: +TK_ROW testdocs/sqlite3.c /^#define TK_ROW /;" d file: +TK_RP testdocs/sqlite3.c /^#define TK_RP /;" d file: +TK_RSHIFT testdocs/sqlite3.c /^#define TK_RSHIFT /;" d file: +TK_SAVEPOINT testdocs/sqlite3.c /^#define TK_SAVEPOINT /;" d file: +TK_SELECT testdocs/sqlite3.c /^#define TK_SELECT /;" d file: +TK_SELECT_COLUMN testdocs/sqlite3.c /^#define TK_SELECT_COLUMN /;" d file: +TK_SEMI testdocs/sqlite3.c /^#define TK_SEMI /;" d file: +TK_SET testdocs/sqlite3.c /^#define TK_SET /;" d file: +TK_SLASH testdocs/sqlite3.c /^#define TK_SLASH /;" d file: +TK_SPACE testdocs/sqlite3.c /^#define TK_SPACE /;" d file: +TK_SPAN testdocs/sqlite3.c /^#define TK_SPAN /;" d file: +TK_STAR testdocs/sqlite3.c /^#define TK_STAR /;" d file: +TK_STRING testdocs/sqlite3.c /^#define TK_STRING /;" d file: +TK_TABLE testdocs/sqlite3.c /^#define TK_TABLE /;" d file: +TK_TEMP testdocs/sqlite3.c /^#define TK_TEMP /;" d file: +TK_THEN testdocs/sqlite3.c /^#define TK_THEN /;" d file: +TK_TO testdocs/sqlite3.c /^#define TK_TO /;" d file: +TK_TO_BLOB testdocs/sqlite3.c /^#define TK_TO_BLOB /;" d file: +TK_TO_INT testdocs/sqlite3.c /^#define TK_TO_INT /;" d file: +TK_TO_NUMERIC testdocs/sqlite3.c /^#define TK_TO_NUMERIC /;" d file: +TK_TO_REAL testdocs/sqlite3.c /^#define TK_TO_REAL /;" d file: +TK_TO_TEXT testdocs/sqlite3.c /^#define TK_TO_TEXT /;" d file: +TK_TRANSACTION testdocs/sqlite3.c /^#define TK_TRANSACTION /;" d file: +TK_TRIGGER testdocs/sqlite3.c /^#define TK_TRIGGER /;" d file: +TK_UMINUS testdocs/sqlite3.c /^#define TK_UMINUS /;" d file: +TK_UNCLOSED_STRING testdocs/sqlite3.c /^#define TK_UNCLOSED_STRING /;" d file: +TK_UNION testdocs/sqlite3.c /^#define TK_UNION /;" d file: +TK_UNIQUE testdocs/sqlite3.c /^#define TK_UNIQUE /;" d file: +TK_UPDATE testdocs/sqlite3.c /^#define TK_UPDATE /;" d file: +TK_UPLUS testdocs/sqlite3.c /^#define TK_UPLUS /;" d file: +TK_USING testdocs/sqlite3.c /^#define TK_USING /;" d file: +TK_VACUUM testdocs/sqlite3.c /^#define TK_VACUUM /;" d file: +TK_VALUES testdocs/sqlite3.c /^#define TK_VALUES /;" d file: +TK_VARIABLE testdocs/sqlite3.c /^#define TK_VARIABLE /;" d file: +TK_VECTOR testdocs/sqlite3.c /^#define TK_VECTOR /;" d file: +TK_VIEW testdocs/sqlite3.c /^#define TK_VIEW /;" d file: +TK_VIRTUAL testdocs/sqlite3.c /^#define TK_VIRTUAL /;" d file: +TK_WHEN testdocs/sqlite3.c /^#define TK_WHEN /;" d file: +TK_WHERE testdocs/sqlite3.c /^#define TK_WHERE /;" d file: +TK_WITH testdocs/sqlite3.c /^#define TK_WITH /;" d file: +TK_WITHOUT testdocs/sqlite3.c /^#define TK_WITHOUT /;" d file: +TOKEN testdocs/sqlite3.c /^#define TOKEN /;" d file: +TRACE testdocs/sqlite3.c /^# define TRACE(/;" d file: +TRACE_IDX_INPUTS testdocs/sqlite3.c /^#define TRACE_IDX_INPUTS(/;" d file: +TRACE_IDX_INPUTS testdocs/sqlite3.c /^static void TRACE_IDX_INPUTS(sqlite3_index_info *p){$/;" f file: +TRACE_IDX_OUTPUTS testdocs/sqlite3.c /^#define TRACE_IDX_OUTPUTS(/;" d file: +TRACE_IDX_OUTPUTS testdocs/sqlite3.c /^static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){$/;" f file: +TRANS_NONE testdocs/sqlite3.c /^#define TRANS_NONE /;" d file: +TRANS_READ testdocs/sqlite3.c /^#define TRANS_READ /;" d file: +TRANS_WRITE testdocs/sqlite3.c /^#define TRANS_WRITE /;" d file: +TRIGGER_AFTER testdocs/sqlite3.c /^#define TRIGGER_AFTER /;" d file: +TRIGGER_BEFORE testdocs/sqlite3.c /^#define TRIGGER_BEFORE /;" d file: +TWO_BYTE_INT testdocs/sqlite3.c /^#define TWO_BYTE_INT(/;" d file: +TabResult testdocs/sqlite3.c /^typedef struct TabResult {$/;" s file: +TabResult testdocs/sqlite3.c /^} TabResult;$/;" t typeref:struct:TabResult file: +Table testdocs/sqlite3.c /^struct Table {$/;" s file: +Table testdocs/sqlite3.c /^typedef struct Table Table;$/;" t typeref:struct:Table file: +TableLock testdocs/sqlite3.c /^struct TableLock {$/;" s file: +TableLock testdocs/sqlite3.c /^typedef struct TableLock TableLock;$/;" t typeref:struct:TableLock file: +TermOffset testdocs/sqlite3.c /^struct TermOffset {$/;" s file: +TermOffset testdocs/sqlite3.c /^typedef struct TermOffset TermOffset;$/;" t typeref:struct:TermOffset file: +TermOffsetCtx testdocs/sqlite3.c /^struct TermOffsetCtx {$/;" s file: +TermOffsetCtx testdocs/sqlite3.c /^typedef struct TermOffsetCtx TermOffsetCtx;$/;" t typeref:struct:TermOffsetCtx file: +TermSelect testdocs/sqlite3.c /^struct TermSelect {$/;" s file: +TermSelect testdocs/sqlite3.c /^typedef struct TermSelect TermSelect;$/;" t typeref:struct:TermSelect file: +TestBuf testbuf.c /^static Buf TestBuf;$/;" v file: +Token testdocs/sqlite3.c /^struct Token {$/;" s file: +Token testdocs/sqlite3.c /^typedef struct Token Token;$/;" t typeref:struct:Token file: +TokenCtx testdocs/sqlite3.c /^struct TokenCtx {$/;" s file: +TokenCtx testdocs/sqlite3.c /^typedef struct TokenCtx TokenCtx;$/;" t typeref:struct:TokenCtx file: +TokenDoclist testdocs/sqlite3.c /^struct TokenDoclist {$/;" s file: +TokenDoclist testdocs/sqlite3.c /^typedef struct TokenDoclist TokenDoclist;$/;" t typeref:struct:TokenDoclist file: +Total atf.h /^static unsigned int Total = 0;$/;" v +TreeView testdocs/sqlite3.c /^struct TreeView {$/;" s file: +TreeView testdocs/sqlite3.c /^typedef struct TreeView TreeView;$/;" t typeref:struct:TreeView file: +TrigEvent testdocs/sqlite3.c /^struct TrigEvent { int a; IdList * b; };$/;" s file: +Trigger testdocs/sqlite3.c /^struct Trigger {$/;" s file: +Trigger testdocs/sqlite3.c /^typedef struct Trigger Trigger;$/;" t typeref:struct:Trigger file: +TriggerPrg testdocs/sqlite3.c /^struct TriggerPrg {$/;" s file: +TriggerPrg testdocs/sqlite3.c /^typedef struct TriggerPrg TriggerPrg;$/;" t typeref:struct:TriggerPrg file: +TriggerStep testdocs/sqlite3.c /^struct TriggerStep {$/;" s file: +TriggerStep testdocs/sqlite3.c /^typedef struct TriggerStep TriggerStep;$/;" t typeref:struct:TriggerStep file: +UAUTH_Admin testdocs/sqlite3.c /^#define UAUTH_Admin /;" d file: +UAUTH_Fail testdocs/sqlite3.c /^#define UAUTH_Fail /;" d file: +UAUTH_Unknown testdocs/sqlite3.c /^#define UAUTH_Unknown /;" d file: +UAUTH_User testdocs/sqlite3.c /^#define UAUTH_User /;" d file: +UINT16_TYPE testdocs/sqlite3.c /^# define UINT16_TYPE /;" d file: +UINT32_TYPE testdocs/sqlite3.c /^# define UINT32_TYPE /;" d file: +UINT8_TYPE testdocs/sqlite3.c /^# define UINT8_TYPE /;" d file: +UNICODE_STRING_MAX_CHARS testdocs/sqlite3.c /^# define UNICODE_STRING_MAX_CHARS /;" d file: +UNIXFILE_DELETE testdocs/sqlite3.c /^#define UNIXFILE_DELETE /;" d file: +UNIXFILE_DIRSYNC testdocs/sqlite3.c /^# define UNIXFILE_DIRSYNC /;" d file: +UNIXFILE_EXCL testdocs/sqlite3.c /^#define UNIXFILE_EXCL /;" d file: +UNIXFILE_NOLOCK testdocs/sqlite3.c /^#define UNIXFILE_NOLOCK /;" d file: +UNIXFILE_PERSIST_WAL testdocs/sqlite3.c /^#define UNIXFILE_PERSIST_WAL /;" d file: +UNIXFILE_PSOW testdocs/sqlite3.c /^#define UNIXFILE_PSOW /;" d file: +UNIXFILE_RDONLY testdocs/sqlite3.c /^#define UNIXFILE_RDONLY /;" d file: +UNIXFILE_URI testdocs/sqlite3.c /^#define UNIXFILE_URI /;" d file: +UNIXVFS testdocs/sqlite3.c /^ #define UNIXVFS(/;" d file: +UNIX_SHM_BASE testdocs/sqlite3.c /^#define UNIX_SHM_BASE /;" d file: +UNIX_SHM_DMS testdocs/sqlite3.c /^#define UNIX_SHM_DMS /;" d file: +UNKNOWN_LOCK testdocs/sqlite3.c /^#define UNKNOWN_LOCK /;" d file: +UNUSED_PARAM testdocs/sqlite3.c /^# define UNUSED_PARAM(/;" d file: +UNUSED_PARAM2 testdocs/sqlite3.c /^# define UNUSED_PARAM2(/;" d file: +UNUSED_PARAMETER testdocs/sqlite3.c /^# define UNUSED_PARAMETER(/;" d file: +UNUSED_PARAMETER testdocs/sqlite3.c /^#define UNUSED_PARAMETER(/;" d file: +UNUSED_PARAMETER2 testdocs/sqlite3.c /^#define UNUSED_PARAMETER2(/;" d file: +UNUSED_VARIABLE_VALUE testdocs/sqlite3.c /^# define UNUSED_VARIABLE_VALUE(/;" d file: +UP edit.h /^ UP = -1,$/;" e enum:__anon7 +UPDATE_MAX_BLOBSIZE testdocs/sqlite3.c /^# define UPDATE_MAX_BLOBSIZE(/;" d file: +USEFETCH testdocs/sqlite3.c /^# define USEFETCH(/;" d file: +USE_PREAD testdocs/sqlite3.c /^# define USE_PREAD /;" d file: +USE_PREAD testdocs/sqlite3.c /^# undef USE_PREAD$/;" d file: +USE_PREAD64 testdocs/sqlite3.c /^# define USE_PREAD64 /;" d file: +USE_PREAD64 testdocs/sqlite3.c /^# undef USE_PREAD64$/;" d file: +UTF8_SeqBits buf.c /^const uint8_t UTF8_SeqBits[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };$/;" v +UTF8_SeqLens buf.c /^const uint8_t UTF8_SeqLens[] = { 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00 };$/;" v +UTF8_SeqMask buf.c /^const uint8_t UTF8_SeqMask[] = { 0x00, 0xFF, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00 };$/;" v +UTF_MAX utf.h /^ UTF_MAX = 6u, \/* maximum number of bytes that make up a rune *\/$/;" e enum:__anon40 +Unicode61Tokenizer testdocs/sqlite3.c /^struct Unicode61Tokenizer {$/;" s file: +Unicode61Tokenizer testdocs/sqlite3.c /^typedef struct Unicode61Tokenizer Unicode61Tokenizer;$/;" t typeref:struct:Unicode61Tokenizer file: +UnixUnusedFd testdocs/sqlite3.c /^struct UnixUnusedFd {$/;" s file: +UnixUnusedFd testdocs/sqlite3.c /^typedef struct UnixUnusedFd UnixUnusedFd; \/* An unused file descriptor *\/$/;" t typeref:struct:UnixUnusedFd file: +UnpackedRecord testdocs/sqlite3.c /^struct UnpackedRecord {$/;" s file: +UnpackedRecord testdocs/sqlite3.c /^typedef struct UnpackedRecord UnpackedRecord;$/;" t typeref:struct:UnpackedRecord file: +UpperToLower testdocs/sqlite3.c /^#define UpperToLower /;" d file: +Utf8Read testdocs/sqlite3.c /^# define Utf8Read(/;" d file: +VDBE_DISPLAY_P4 testdocs/sqlite3.c /^# define VDBE_DISPLAY_P4 /;" d file: +VDBE_MAGIC_DEAD testdocs/sqlite3.c /^#define VDBE_MAGIC_DEAD /;" d file: +VDBE_MAGIC_HALT testdocs/sqlite3.c /^#define VDBE_MAGIC_HALT /;" d file: +VDBE_MAGIC_INIT testdocs/sqlite3.c /^#define VDBE_MAGIC_INIT /;" d file: +VDBE_MAGIC_RESET testdocs/sqlite3.c /^#define VDBE_MAGIC_RESET /;" d file: +VDBE_MAGIC_RUN testdocs/sqlite3.c /^#define VDBE_MAGIC_RUN /;" d file: +VDBE_OFFSET_LINENO testdocs/sqlite3.c /^# define VDBE_OFFSET_LINENO(/;" d file: +VERSION testdocs/waf /^VERSION="1.9.1"$/;" v +VFUNCTION testdocs/sqlite3.c /^#define VFUNCTION(/;" d file: +VList testdocs/sqlite3.c /^typedef int VList;$/;" t file: +VTAB_SCHEMA testdocs/sqlite3.c /^#define VTAB_SCHEMA /;" d file: +VTable testdocs/sqlite3.c /^struct VTable {$/;" s file: +VTable testdocs/sqlite3.c /^typedef struct VTable VTable;$/;" t typeref:struct:VTable file: +VVA_ONLY testdocs/sqlite3.c /^# define VVA_ONLY(/;" d file: +ValueNewStat4Ctx testdocs/sqlite3.c /^struct ValueNewStat4Ctx {$/;" s file: +Vdbe testdocs/sqlite3.c /^struct Vdbe {$/;" s file: +Vdbe testdocs/sqlite3.c /^typedef struct Vdbe Vdbe;$/;" t typeref:struct:Vdbe file: +VdbeBranchTaken testdocs/sqlite3.c /^# define VdbeBranchTaken(/;" d file: +VdbeComment testdocs/sqlite3.c /^# define VdbeComment(/;" d file: +VdbeCoverage testdocs/sqlite3.c /^# define VdbeCoverage(/;" d file: +VdbeCoverageAlwaysTaken testdocs/sqlite3.c /^# define VdbeCoverageAlwaysTaken(/;" d file: +VdbeCoverageIf testdocs/sqlite3.c /^# define VdbeCoverageIf(/;" d file: +VdbeCoverageNeverTaken testdocs/sqlite3.c /^# define VdbeCoverageNeverTaken(/;" d file: +VdbeCursor testdocs/sqlite3.c /^struct VdbeCursor {$/;" s file: +VdbeCursor testdocs/sqlite3.c /^typedef struct VdbeCursor VdbeCursor;$/;" t typeref:struct:VdbeCursor file: +VdbeFrame testdocs/sqlite3.c /^struct VdbeFrame {$/;" s file: +VdbeFrame testdocs/sqlite3.c /^typedef struct VdbeFrame VdbeFrame;$/;" t typeref:struct:VdbeFrame file: +VdbeFrameMem testdocs/sqlite3.c /^#define VdbeFrameMem(/;" d file: +VdbeMemDynamic testdocs/sqlite3.c /^#define VdbeMemDynamic(/;" d file: +VdbeModuleComment testdocs/sqlite3.c /^# define VdbeModuleComment(/;" d file: +VdbeModuleComment testdocs/sqlite3.c /^# define VdbeModuleComment(/;" d file: +VdbeNoopComment testdocs/sqlite3.c /^# define VdbeNoopComment(/;" d file: +VdbeOp testdocs/sqlite3.c /^struct VdbeOp {$/;" s file: +VdbeOp testdocs/sqlite3.c /^typedef struct VdbeOp VdbeOp;$/;" t typeref:struct:VdbeOp file: +VdbeOpIter testdocs/sqlite3.c /^struct VdbeOpIter {$/;" s file: +VdbeOpIter testdocs/sqlite3.c /^typedef struct VdbeOpIter VdbeOpIter;$/;" t typeref:struct:VdbeOpIter file: +VdbeOpList testdocs/sqlite3.c /^struct VdbeOpList {$/;" s file: +VdbeOpList testdocs/sqlite3.c /^typedef struct VdbeOpList VdbeOpList;$/;" t typeref:struct:VdbeOpList file: +VdbeSorter testdocs/sqlite3.c /^struct VdbeSorter {$/;" s file: +VdbeSorter testdocs/sqlite3.c /^typedef struct VdbeSorter VdbeSorter;$/;" t typeref:struct:VdbeSorter file: +VisibleRowid testdocs/sqlite3.c /^#define VisibleRowid(/;" d file: +VtabCtx testdocs/sqlite3.c /^struct VtabCtx {$/;" s file: +VtabCtx testdocs/sqlite3.c /^typedef struct VtabCtx VtabCtx;$/;" t typeref:struct:VtabCtx file: +WAF testdocs/waf /^WAF='waf'$/;" v +WALINDEX_HDR_SIZE testdocs/sqlite3.c /^#define WALINDEX_HDR_SIZE /;" d file: +WALINDEX_LOCK_OFFSET testdocs/sqlite3.c /^#define WALINDEX_LOCK_OFFSET /;" d file: +WALINDEX_MAX_VERSION testdocs/sqlite3.c /^#define WALINDEX_MAX_VERSION /;" d file: +WALINDEX_PGSZ testdocs/sqlite3.c /^#define WALINDEX_PGSZ /;" d file: +WALTRACE testdocs/sqlite3.c /^# define WALTRACE(/;" d file: +WAL_ALL_BUT_WRITE testdocs/sqlite3.c /^#define WAL_ALL_BUT_WRITE /;" d file: +WAL_CKPT_LOCK testdocs/sqlite3.c /^#define WAL_CKPT_LOCK /;" d file: +WAL_EXCLUSIVE_MODE testdocs/sqlite3.c /^#define WAL_EXCLUSIVE_MODE /;" d file: +WAL_FRAME_HDRSIZE testdocs/sqlite3.c /^#define WAL_FRAME_HDRSIZE /;" d file: +WAL_HDRSIZE testdocs/sqlite3.c /^#define WAL_HDRSIZE /;" d file: +WAL_HEAPMEMORY_MODE testdocs/sqlite3.c /^#define WAL_HEAPMEMORY_MODE /;" d file: +WAL_LOCK_CKPT testdocs/sqlite3.c /^#define WAL_LOCK_CKPT /;" d file: +WAL_LOCK_READ0 testdocs/sqlite3.c /^#define WAL_LOCK_READ0 /;" d file: +WAL_LOCK_WRITE testdocs/sqlite3.c /^#define WAL_LOCK_WRITE /;" d file: +WAL_MAGIC testdocs/sqlite3.c /^#define WAL_MAGIC /;" d file: +WAL_MAX_VERSION testdocs/sqlite3.c /^#define WAL_MAX_VERSION /;" d file: +WAL_NORMAL_MODE testdocs/sqlite3.c /^#define WAL_NORMAL_MODE /;" d file: +WAL_NREADER testdocs/sqlite3.c /^#define WAL_NREADER /;" d file: +WAL_RDONLY testdocs/sqlite3.c /^#define WAL_RDONLY /;" d file: +WAL_RDWR testdocs/sqlite3.c /^#define WAL_RDWR /;" d file: +WAL_READ_LOCK testdocs/sqlite3.c /^#define WAL_READ_LOCK(/;" d file: +WAL_RECOVER_LOCK testdocs/sqlite3.c /^#define WAL_RECOVER_LOCK /;" d file: +WAL_RETRY testdocs/sqlite3.c /^#define WAL_RETRY /;" d file: +WAL_SAVEPOINT_NDATA testdocs/sqlite3.c /^#define WAL_SAVEPOINT_NDATA /;" d file: +WAL_SHM_RDONLY testdocs/sqlite3.c /^#define WAL_SHM_RDONLY /;" d file: +WAL_SYNC_TRANSACTIONS testdocs/sqlite3.c /^#define WAL_SYNC_TRANSACTIONS /;" d file: +WAL_WRITE_LOCK testdocs/sqlite3.c /^#define WAL_WRITE_LOCK /;" d file: +WHERETRACE testdocs/sqlite3.c /^# define WHERETRACE(/;" d file: +WHERETRACE_ENABLED testdocs/sqlite3.c /^# define WHERETRACE_ENABLED /;" d file: +WHERE_AUTO_INDEX testdocs/sqlite3.c /^#define WHERE_AUTO_INDEX /;" d file: +WHERE_BOTH_LIMIT testdocs/sqlite3.c /^#define WHERE_BOTH_LIMIT /;" d file: +WHERE_BTM_LIMIT testdocs/sqlite3.c /^#define WHERE_BTM_LIMIT /;" d file: +WHERE_COLUMN_EQ testdocs/sqlite3.c /^#define WHERE_COLUMN_EQ /;" d file: +WHERE_COLUMN_IN testdocs/sqlite3.c /^#define WHERE_COLUMN_IN /;" d file: +WHERE_COLUMN_NULL testdocs/sqlite3.c /^#define WHERE_COLUMN_NULL /;" d file: +WHERE_COLUMN_RANGE testdocs/sqlite3.c /^#define WHERE_COLUMN_RANGE /;" d file: +WHERE_CONSTRAINT testdocs/sqlite3.c /^#define WHERE_CONSTRAINT /;" d file: +WHERE_DISTINCTBY testdocs/sqlite3.c /^#define WHERE_DISTINCTBY /;" d file: +WHERE_DISTINCT_NOOP testdocs/sqlite3.c /^#define WHERE_DISTINCT_NOOP /;" d file: +WHERE_DISTINCT_ORDERED testdocs/sqlite3.c /^#define WHERE_DISTINCT_ORDERED /;" d file: +WHERE_DISTINCT_UNIQUE testdocs/sqlite3.c /^#define WHERE_DISTINCT_UNIQUE /;" d file: +WHERE_DISTINCT_UNORDERED testdocs/sqlite3.c /^#define WHERE_DISTINCT_UNORDERED /;" d file: +WHERE_DUPLICATES_OK testdocs/sqlite3.c /^#define WHERE_DUPLICATES_OK /;" d file: +WHERE_GROUPBY testdocs/sqlite3.c /^#define WHERE_GROUPBY /;" d file: +WHERE_IDX_ONLY testdocs/sqlite3.c /^#define WHERE_IDX_ONLY /;" d file: +WHERE_INDEXED testdocs/sqlite3.c /^#define WHERE_INDEXED /;" d file: +WHERE_IN_ABLE testdocs/sqlite3.c /^#define WHERE_IN_ABLE /;" d file: +WHERE_IPK testdocs/sqlite3.c /^#define WHERE_IPK /;" d file: +WHERE_LOOP_XFER_SZ testdocs/sqlite3.c /^# define WHERE_LOOP_XFER_SZ /;" d file: +WHERE_MULTI_OR testdocs/sqlite3.c /^#define WHERE_MULTI_OR /;" d file: +WHERE_ONEPASS_DESIRED testdocs/sqlite3.c /^#define WHERE_ONEPASS_DESIRED /;" d file: +WHERE_ONEPASS_MULTIROW testdocs/sqlite3.c /^#define WHERE_ONEPASS_MULTIROW /;" d file: +WHERE_ONEROW testdocs/sqlite3.c /^#define WHERE_ONEROW /;" d file: +WHERE_ORDERBY_LIMIT testdocs/sqlite3.c /^#define WHERE_ORDERBY_LIMIT /;" d file: +WHERE_ORDERBY_MAX testdocs/sqlite3.c /^#define WHERE_ORDERBY_MAX /;" d file: +WHERE_ORDERBY_MIN testdocs/sqlite3.c /^#define WHERE_ORDERBY_MIN /;" d file: +WHERE_ORDERBY_NORMAL testdocs/sqlite3.c /^#define WHERE_ORDERBY_NORMAL /;" d file: +WHERE_OR_SUBCLAUSE testdocs/sqlite3.c /^#define WHERE_OR_SUBCLAUSE /;" d file: +WHERE_PARTIALIDX testdocs/sqlite3.c /^#define WHERE_PARTIALIDX /;" d file: +WHERE_SEEK_TABLE testdocs/sqlite3.c /^#define WHERE_SEEK_TABLE /;" d file: +WHERE_SEEK_UNIQ_TABLE testdocs/sqlite3.c /^#define WHERE_SEEK_UNIQ_TABLE /;" d file: +WHERE_SKIPSCAN testdocs/sqlite3.c /^#define WHERE_SKIPSCAN /;" d file: +WHERE_SORTBYGROUP testdocs/sqlite3.c /^#define WHERE_SORTBYGROUP /;" d file: +WHERE_TOP_LIMIT testdocs/sqlite3.c /^#define WHERE_TOP_LIMIT /;" d file: +WHERE_UNQ_WANTED testdocs/sqlite3.c /^#define WHERE_UNQ_WANTED /;" d file: +WHERE_USE_LIMIT testdocs/sqlite3.c /^#define WHERE_USE_LIMIT /;" d file: +WHERE_VIRTUALTABLE testdocs/sqlite3.c /^#define WHERE_VIRTUALTABLE /;" d file: +WHERE_WANT_DISTINCT testdocs/sqlite3.c /^#define WHERE_WANT_DISTINCT /;" d file: +WINCE_DELETION_ATTEMPTS testdocs/sqlite3.c /^#define WINCE_DELETION_ATTEMPTS /;" d file: +WINFILE_PERSIST_WAL testdocs/sqlite3.c /^#define WINFILE_PERSIST_WAL /;" d file: +WINFILE_PSOW testdocs/sqlite3.c /^#define WINFILE_PSOW /;" d file: +WINFILE_RDONLY testdocs/sqlite3.c /^#define WINFILE_RDONLY /;" d file: +WINMEM_MAGIC1 testdocs/sqlite3.c /^#define WINMEM_MAGIC1 /;" d file: +WINMEM_MAGIC2 testdocs/sqlite3.c /^#define WINMEM_MAGIC2 /;" d file: +WINSHM_RDLCK testdocs/sqlite3.c /^#define WINSHM_RDLCK /;" d file: +WINSHM_UNLCK testdocs/sqlite3.c /^#define WINSHM_UNLCK /;" d file: +WINSHM_WRLCK testdocs/sqlite3.c /^#define WINSHM_WRLCK /;" d file: +WIN_SHM_BASE testdocs/sqlite3.c /^#define WIN_SHM_BASE /;" d file: +WIN_SHM_DMS testdocs/sqlite3.c /^#define WIN_SHM_DMS /;" d file: +WO_ALL testdocs/sqlite3.c /^#define WO_ALL /;" d file: +WO_AND testdocs/sqlite3.c /^#define WO_AND /;" d file: +WO_EQ testdocs/sqlite3.c /^#define WO_EQ /;" d file: +WO_EQUIV testdocs/sqlite3.c /^#define WO_EQUIV /;" d file: +WO_GE testdocs/sqlite3.c /^#define WO_GE /;" d file: +WO_GT testdocs/sqlite3.c /^#define WO_GT /;" d file: +WO_IN testdocs/sqlite3.c /^#define WO_IN /;" d file: +WO_IS testdocs/sqlite3.c /^#define WO_IS /;" d file: +WO_ISNULL testdocs/sqlite3.c /^#define WO_ISNULL /;" d file: +WO_LE testdocs/sqlite3.c /^#define WO_LE /;" d file: +WO_LT testdocs/sqlite3.c /^#define WO_LT /;" d file: +WO_MATCH testdocs/sqlite3.c /^#define WO_MATCH /;" d file: +WO_NOOP testdocs/sqlite3.c /^#define WO_NOOP /;" d file: +WO_OR testdocs/sqlite3.c /^#define WO_OR /;" d file: +WO_SINGLE testdocs/sqlite3.c /^#define WO_SINGLE /;" d file: +WRC_Abort testdocs/sqlite3.c /^#define WRC_Abort /;" d file: +WRC_Continue testdocs/sqlite3.c /^#define WRC_Continue /;" d file: +WRC_Prune testdocs/sqlite3.c /^#define WRC_Prune /;" d file: +WRITE_LOCK testdocs/sqlite3.c /^#define WRITE_LOCK /;" d file: +WRITE_UTF16BE testdocs/sqlite3.c /^#define WRITE_UTF16BE(/;" d file: +WRITE_UTF16LE testdocs/sqlite3.c /^#define WRITE_UTF16LE(/;" d file: +WRITE_UTF8 testdocs/sqlite3.c /^#define WRITE_UTF8(/;" d file: +Wal testdocs/sqlite3.c /^struct Wal {$/;" s file: +Wal testdocs/sqlite3.c /^typedef struct Wal Wal;$/;" t typeref:struct:Wal file: +WalCkptInfo testdocs/sqlite3.c /^struct WalCkptInfo {$/;" s file: +WalCkptInfo testdocs/sqlite3.c /^typedef struct WalCkptInfo WalCkptInfo;$/;" t typeref:struct:WalCkptInfo file: +WalIndexHdr testdocs/sqlite3.c /^struct WalIndexHdr {$/;" s file: +WalIndexHdr testdocs/sqlite3.c /^typedef struct WalIndexHdr WalIndexHdr;$/;" t typeref:struct:WalIndexHdr file: +WalIterator testdocs/sqlite3.c /^struct WalIterator {$/;" s file: +WalIterator testdocs/sqlite3.c /^typedef struct WalIterator WalIterator;$/;" t typeref:struct:WalIterator file: +WalSegment testdocs/sqlite3.c /^ struct WalSegment {$/;" s struct:WalIterator file: +WalWriter testdocs/sqlite3.c /^typedef struct WalWriter {$/;" s file: +WalWriter testdocs/sqlite3.c /^} WalWriter;$/;" t typeref:struct:WalWriter file: +Walker testdocs/sqlite3.c /^struct Walker {$/;" s file: +Walker testdocs/sqlite3.c /^typedef struct Walker Walker;$/;" t typeref:struct:Walker file: +WhereAndInfo testdocs/sqlite3.c /^struct WhereAndInfo {$/;" s file: +WhereAndInfo testdocs/sqlite3.c /^typedef struct WhereAndInfo WhereAndInfo;$/;" t typeref:struct:WhereAndInfo file: +WhereClause testdocs/sqlite3.c /^struct WhereClause {$/;" s file: +WhereClause testdocs/sqlite3.c /^typedef struct WhereClause WhereClause;$/;" t typeref:struct:WhereClause file: +WhereInfo testdocs/sqlite3.c /^struct WhereInfo {$/;" s file: +WhereInfo testdocs/sqlite3.c /^typedef struct WhereInfo WhereInfo;$/;" t typeref:struct:WhereInfo file: +WhereLevel testdocs/sqlite3.c /^struct WhereLevel {$/;" s file: +WhereLevel testdocs/sqlite3.c /^typedef struct WhereLevel WhereLevel;$/;" t typeref:struct:WhereLevel file: +WhereLoop testdocs/sqlite3.c /^struct WhereLoop {$/;" s file: +WhereLoop testdocs/sqlite3.c /^typedef struct WhereLoop WhereLoop;$/;" t typeref:struct:WhereLoop file: +WhereLoopBuilder testdocs/sqlite3.c /^struct WhereLoopBuilder {$/;" s file: +WhereLoopBuilder testdocs/sqlite3.c /^typedef struct WhereLoopBuilder WhereLoopBuilder;$/;" t typeref:struct:WhereLoopBuilder file: +WhereMaskSet testdocs/sqlite3.c /^struct WhereMaskSet {$/;" s file: +WhereMaskSet testdocs/sqlite3.c /^typedef struct WhereMaskSet WhereMaskSet;$/;" t typeref:struct:WhereMaskSet file: +WhereOrCost testdocs/sqlite3.c /^struct WhereOrCost {$/;" s file: +WhereOrCost testdocs/sqlite3.c /^typedef struct WhereOrCost WhereOrCost;$/;" t typeref:struct:WhereOrCost file: +WhereOrInfo testdocs/sqlite3.c /^struct WhereOrInfo {$/;" s file: +WhereOrInfo testdocs/sqlite3.c /^typedef struct WhereOrInfo WhereOrInfo;$/;" t typeref:struct:WhereOrInfo file: +WhereOrSet testdocs/sqlite3.c /^struct WhereOrSet {$/;" s file: +WhereOrSet testdocs/sqlite3.c /^typedef struct WhereOrSet WhereOrSet;$/;" t typeref:struct:WhereOrSet file: +WherePath testdocs/sqlite3.c /^struct WherePath {$/;" s file: +WherePath testdocs/sqlite3.c /^typedef struct WherePath WherePath;$/;" t typeref:struct:WherePath file: +WhereScan testdocs/sqlite3.c /^struct WhereScan {$/;" s file: +WhereScan testdocs/sqlite3.c /^typedef struct WhereScan WhereScan;$/;" t typeref:struct:WhereScan file: +WhereTerm testdocs/sqlite3.c /^struct WhereTerm {$/;" s file: +WhereTerm testdocs/sqlite3.c /^typedef struct WhereTerm WhereTerm;$/;" t typeref:struct:WhereTerm file: +With testdocs/sqlite3.c /^struct With {$/;" s file: +With testdocs/sqlite3.c /^typedef struct With With;$/;" t typeref:struct:With file: +XN_EXPR testdocs/sqlite3.c /^#define XN_EXPR /;" d file: +XN_ROWID testdocs/sqlite3.c /^#define XN_ROWID /;" d file: +Y testdocs/sqlite3.c /^ int Y, M, D; \/* Year, month, and day *\/$/;" m struct:DateTime file: +YYACTIONTYPE testdocs/sqlite3.c /^#define YYACTIONTYPE /;" d file: +YYCODETYPE testdocs/sqlite3.c /^#define YYCODETYPE /;" d file: +YYFALLBACK testdocs/sqlite3.c /^#define YYFALLBACK /;" d file: +YYMALLOCARGTYPE testdocs/sqlite3.c /^# define YYMALLOCARGTYPE /;" d file: +YYMALLOCARGTYPE testdocs/sqlite3.c /^#define YYMALLOCARGTYPE /;" d file: +YYMINORTYPE testdocs/sqlite3.c /^} YYMINORTYPE;$/;" t typeref:union:__anon33 file: +YYNOCODE testdocs/sqlite3.c /^#define YYNOCODE /;" d file: +YYNOERRORRECOVERY testdocs/sqlite3.c /^#define YYNOERRORRECOVERY /;" d file: +YYNRULE testdocs/sqlite3.c /^#define YYNRULE /;" d file: +YYNSTATE testdocs/sqlite3.c /^#define YYNSTATE /;" d file: +YYPARSEFREENEVERNULL testdocs/sqlite3.c /^#define YYPARSEFREENEVERNULL /;" d file: +YYSTACKDEPTH testdocs/sqlite3.c /^#define YYSTACKDEPTH /;" d file: +YYWILDCARD testdocs/sqlite3.c /^#define YYWILDCARD /;" d file: +YY_ACCEPT_ACTION testdocs/sqlite3.c /^#define YY_ACCEPT_ACTION /;" d file: +YY_ACTTAB_COUNT testdocs/sqlite3.c /^#define YY_ACTTAB_COUNT /;" d file: +YY_ERROR_ACTION testdocs/sqlite3.c /^#define YY_ERROR_ACTION /;" d file: +YY_MAX_REDUCE testdocs/sqlite3.c /^#define YY_MAX_REDUCE /;" d file: +YY_MAX_SHIFT testdocs/sqlite3.c /^#define YY_MAX_SHIFT /;" d file: +YY_MAX_SHIFTREDUCE testdocs/sqlite3.c /^#define YY_MAX_SHIFTREDUCE /;" d file: +YY_MIN_REDUCE testdocs/sqlite3.c /^#define YY_MIN_REDUCE /;" d file: +YY_MIN_SHIFTREDUCE testdocs/sqlite3.c /^#define YY_MIN_SHIFTREDUCE /;" d file: +YY_NO_ACTION testdocs/sqlite3.c /^#define YY_NO_ACTION /;" d file: +YY_REDUCE_COUNT testdocs/sqlite3.c /^#define YY_REDUCE_COUNT /;" d file: +YY_REDUCE_MAX testdocs/sqlite3.c /^#define YY_REDUCE_MAX /;" d file: +YY_REDUCE_MIN testdocs/sqlite3.c /^#define YY_REDUCE_MIN /;" d file: +YY_REDUCE_USE_DFLT testdocs/sqlite3.c /^#define YY_REDUCE_USE_DFLT /;" d file: +YY_SHIFT_COUNT testdocs/sqlite3.c /^#define YY_SHIFT_COUNT /;" d file: +YY_SHIFT_MAX testdocs/sqlite3.c /^#define YY_SHIFT_MAX /;" d file: +YY_SHIFT_MIN testdocs/sqlite3.c /^#define YY_SHIFT_MIN /;" d file: +YY_SHIFT_USE_DFLT testdocs/sqlite3.c /^#define YY_SHIFT_USE_DFLT /;" d file: +_BSD_SOURCE testdocs/sqlite3.c /^# define _BSD_SOURCE$/;" d file: +_CRT_RAND_S testdocs/sqlite3.c /^# define _CRT_RAND_S$/;" d file: +_FILE_OFFSET_BITS testdocs/sqlite3.c /^# define _FILE_OFFSET_BITS /;" d file: +_FTS3_HASH_H_ testdocs/sqlite3.c /^#define _FTS3_HASH_H_$/;" d file: +_FTS3_TOKENIZER_H_ testdocs/sqlite3.c /^#define _FTS3_TOKENIZER_H_$/;" d file: +_FTS5INT_H testdocs/sqlite3.c /^#define _FTS5INT_H$/;" d file: +_FTS5_H testdocs/sqlite3.c /^#define _FTS5_H$/;" d file: +_FTSINT_H testdocs/sqlite3.c /^#define _FTSINT_H$/;" d file: +_GNU_SOURCE testdocs/sqlite3.c /^# define _GNU_SOURCE$/;" d file: +_LARGEFILE_SOURCE testdocs/sqlite3.c /^# define _LARGEFILE_SOURCE /;" d file: +_LARGE_FILE testdocs/sqlite3.c /^# define _LARGE_FILE /;" d file: +_OS_COMMON_H_ testdocs/sqlite3.c /^#define _OS_COMMON_H_$/;" d file: +_POSIX_C_SOURCE buf.c /^#define _POSIX_C_SOURCE /;" d file: +_SQLITE3RBU_H testdocs/sqlite3.c /^#define _SQLITE3RBU_H$/;" d file: +_SQLITE3RTREE_H_ testdocs/sqlite3.c /^#define _SQLITE3RTREE_H_$/;" d file: +_SQLITE_OS_H_ testdocs/sqlite3.c /^#define _SQLITE_OS_H_$/;" d file: +_USE_32BIT_TIME_T testdocs/sqlite3.c /^# define _USE_32BIT_TIME_T$/;" d file: +_XOPEN_SOURCE testdocs/sqlite3.c /^# define _XOPEN_SOURCE /;" d file: +__SQLITESESSION_H_ testdocs/sqlite3.c /^#define __SQLITESESSION_H_ /;" d file: +__declspec testdocs/sqlite3.c /^ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){$/;" f +__declspec testdocs/sqlite3.c /^__declspec(dllexport)$/;" f +_fts3ht testdocs/sqlite3.c /^ struct _fts3ht { \/* the hash table *\/$/;" s struct:Fts3Hash file: +_getopt_ stdc.h /^static inline char* _getopt_(int* p_argc, char*** p_argv) {$/;" f +_ht testdocs/sqlite3.c /^ struct _ht { \/* the hash table *\/$/;" s struct:Hash file: +_sqliteZone_ testdocs/sqlite3.c /^static malloc_zone_t* _sqliteZone_;$/;" v file: +a testdocs/sqlite3.c /^ FuncDef *a[SQLITE_FUNC_HASH_SZ]; \/* Hash table for functions *\/$/;" m struct:FuncDefHash file: +a testdocs/sqlite3.c /^ Stat4Sample *a; \/* Array of mxSample Stat4Sample objects *\/$/;" m struct:Stat4Accum file: +a testdocs/sqlite3.c /^ WhereLevel a[1]; \/* Information about each nest loop in WHERE *\/$/;" m struct:WhereInfo file: +a testdocs/sqlite3.c /^ WhereOrCost a[N_OR_COST]; \/* Set of best costs *\/$/;" m struct:WhereOrSet file: +a testdocs/sqlite3.c /^ WhereTerm *a; \/* Each a[] describes a term of the WHERE cluase *\/$/;" m struct:WhereClause file: +a testdocs/sqlite3.c /^ char *a; \/* Pointer to allocation *\/$/;" m struct:Blob file: +a testdocs/sqlite3.c /^ const u8 *a; \/* Buffer containing position list *\/$/;" m struct:Fts5LookaheadReader file: +a testdocs/sqlite3.c /^ const u8 *a; \/* Position list to iterate through *\/$/;" m struct:Fts5PoslistReader file: +a testdocs/sqlite3.c /^ const unsigned char *a;$/;" m struct:Fts5PhraseIter file: +a testdocs/sqlite3.c /^ unsigned char *a; \/* Gather entropy into this buffer *\/$/;" m struct:EntropyGatherer file: +a testdocs/sqlite3.c /^ } *a;$/;" m struct:IdList typeref:struct:IdList::IdList_item file: +a testdocs/sqlite3.c /^ } a[1]; \/* One slot for each expression in the list *\/$/;" m struct:ExprList typeref:struct:ExprList::ExprList_item file: +a testdocs/sqlite3.c /^ } a[1]; \/* One entry for each identifier on the list *\/$/;" m struct:SrcList typeref:struct:SrcList::SrcList_item file: +a testdocs/sqlite3.c /^ } a[1];$/;" m struct:With typeref:struct:With::Cte file: +a testdocs/sqlite3.c /^struct TrigEvent { int a; IdList * b; };$/;" m struct:TrigEvent file: +aAction testdocs/sqlite3.c /^ u8 aAction[2]; \/* ON DELETE and ON UPDATE actions, respectively *\/$/;" m struct:FKey file: +aAll testdocs/sqlite3.c /^ char *aAll; \/* Array containing doclist (or NULL) *\/$/;" m struct:Fts3Doclist file: +aAlloc testdocs/sqlite3.c /^ u8 *aAlloc; \/* Space for aKey if aBuffer and pMap wont work *\/$/;" m struct:PmaReader file: +aAltMap testdocs/sqlite3.c /^ int *aAltMap; \/* Mapping from table to index column numbers *\/$/;" m struct:VdbeCursor file: +aAsciiTokenChar testdocs/sqlite3.c /^static unsigned char aAsciiTokenChar[128] = {$/;" v file: +aAvgEq testdocs/sqlite3.c /^ tRowcnt *aAvgEq; \/* Average nEq values for keys not in aSample *\/$/;" m struct:Index file: +aBest testdocs/sqlite3.c /^ Stat4Sample *aBest; \/* Array of nCol best samples *\/$/;" m struct:Stat4Accum file: +aBitmap testdocs/sqlite3.c /^ BITVEC_TELEM aBitmap[BITVEC_NELEM]; \/* Bitmap representation *\/$/;" m union:Bitvec::__anon24 file: +aBuf testdocs/sqlite3.c /^ char *aBuf;$/;" m struct:PorterContext file: +aBuf testdocs/sqlite3.c /^ char aBuf[FTS5_PORTER_MAX_TOKEN + 64];$/;" m struct:PorterTokenizer file: +aBuf testdocs/sqlite3.c /^ u8 *aBuf; \/* Pointer to changeset buffer *\/$/;" m struct:SessionBuffer file: +aBuf testdocs/sqlite3.c /^ u8 *aBuf;$/;" m struct:sqlite3rbu file: +aBuffer testdocs/sqlite3.c /^ char *aBuffer; \/* Buffer to merge doclists in *\/$/;" m struct:Fts3MultiSegReader file: +aBuffer testdocs/sqlite3.c /^ u8 *aBuffer; \/* Pointer to write buffer *\/$/;" m struct:PmaWriter file: +aBuffer testdocs/sqlite3.c /^ u8 *aBuffer; \/* Current read buffer *\/$/;" m struct:PmaReader file: +aCell testdocs/sqlite3.c /^ StatCell *aCell; \/* Array of parsed cells *\/$/;" m struct:StatPage file: +aCellIdx testdocs/sqlite3.c /^ u8 *aCellIdx; \/* The cell index area *\/$/;" m struct:MemPage file: +aChar testdocs/sqlite3.c /^ UChar *aChar; \/* Copy of input using utf-16 encoding *\/$/;" m struct:IcuCursor file: +aCksum testdocs/sqlite3.c /^ u32 aCksum[2]; \/* Checksum over all prior fields *\/$/;" m struct:WalIndexHdr file: +aCnt testdocs/sqlite3.c /^ i64 *aCnt;$/;" m struct:Fts5VocabCursor file: +aCol testdocs/sqlite3.c /^ Column *aCol; \/* Information about each column *\/$/;" m struct:Table file: +aCol testdocs/sqlite3.c /^ } *aCol;$/;" m struct:AggInfo typeref:struct:AggInfo::AggInfo_col file: +aCol testdocs/sqlite3.c /^ } aCol[1]; \/* One entry for each of nCol columns *\/$/;" m struct:FKey typeref:struct:FKey::sColMap file: +aColCache testdocs/sqlite3.c /^ } aColCache[SQLITE_N_COLCACHE]; \/* One for each column cache entry *\/$/;" m struct:Parse typeref:struct:Parse::yColCache file: +aColExpr testdocs/sqlite3.c /^ ExprList *aColExpr; \/* Column expressions *\/$/;" m struct:Index file: +aColName testdocs/sqlite3.c /^ Mem *aColName; \/* Column names to return *\/$/;" m struct:Vdbe file: +aColl testdocs/sqlite3.c /^ CollSeq *aColl[1]; \/* Collating sequence for each term of the key *\/$/;" m struct:KeyInfo file: +aCollSeq testdocs/sqlite3.c /^ Hash aCollSeq; \/* All collating sequences *\/$/;" m struct:sqlite3 file: +aColmask testdocs/sqlite3.c /^ u32 aColmask[2]; \/* Masks of old.*, new.* columns accessed *\/$/;" m struct:TriggerPrg file: +aColumnSize testdocs/sqlite3.c /^ int *aColumnSize; \/* Values for xColumnSize() *\/$/;" m struct:Fts5Cursor file: +aConstraint testdocs/sqlite3.c /^ RtreeConstraint *aConstraint; \/* Search constraints. *\/$/;" m struct:RtreeCursor file: +aConstraint testdocs/sqlite3.c /^ } *aConstraint; \/* Table of WHERE clause constraints *\/$/;" m struct:sqlite3_index_info typeref:struct:sqlite3_index_info::sqlite3_index_constraint file: +aConstraintUsage testdocs/sqlite3.c /^ } *aConstraintUsage;$/;" m struct:sqlite3_index_info typeref:struct:sqlite3_index_info::sqlite3_index_constraint_usage file: +aCoord testdocs/sqlite3.c /^ RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; \/* Bounding box coordinates *\/$/;" m struct:RtreeCell file: +aCoord testdocs/sqlite3.c /^ sqlite3_rtree_dbl *aCoord; \/* Coordinates of node or entry to check *\/$/;" m struct:sqlite3_rtree_query_info file: +aCounter testdocs/sqlite3.c /^ u32 aCounter[5]; \/* Counters used by sqlite3_stmt_status() *\/$/;" m struct:Vdbe file: +aCtrl testdocs/sqlite3.c /^ u8 *aCtrl;$/;" m struct:Mem5Global file: +aData testdocs/sqlite3.c /^ char *aData; \/* Node data *\/$/;" m struct:SegmentNode file: +aData testdocs/sqlite3.c /^ char *aData; \/* Pointer to block from malloc() *\/$/;" m struct:SegmentWriter file: +aData testdocs/sqlite3.c /^ char *aData;$/;" m struct:PendingList file: +aData testdocs/sqlite3.c /^ u8 *aData; \/* Pointer to buffer containing changeset *\/$/;" m struct:SessionInput file: +aData testdocs/sqlite3.c /^ u8 *aData; \/* Pointer to disk image of the page data *\/$/;" m struct:MemPage file: +aDataEnd testdocs/sqlite3.c /^ u8 *aDataEnd; \/* One byte past the end of usable data *\/$/;" m struct:MemPage file: +aDataOfst testdocs/sqlite3.c /^ u8 *aDataOfst; \/* Same as aData for leaves. aData+4 for interior *\/$/;" m struct:MemPage file: +aDb testdocs/sqlite3.c /^ Db *aDb; \/* All backends *\/$/;" m struct:sqlite3 file: +aDbStatic testdocs/sqlite3.c /^ Db aDbStatic[2]; \/* Static space for the 2 default backends *\/$/;" m struct:sqlite3 file: +aDigits testdocs/sqlite3.c /^static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";$/;" v file: +aDlidx testdocs/sqlite3.c /^ Fts5DlidxWriter *aDlidx; \/* Array of Fts5DlidxWriter objects *\/$/;" m struct:Fts5SegWriter file: +aDoc testdocs/sqlite3.c /^ i64 *aDoc;$/;" m struct:Fts5VocabCursor file: +aDoclist testdocs/sqlite3.c /^ char *aDoclist; \/* List of docids for full-text queries *\/$/;" m struct:Fts3Cursor file: +aDoclist testdocs/sqlite3.c /^ char *aDoclist; \/* Pointer to doclist buffer *\/$/;" m struct:Fts3MultiSegReader file: +aDoclist testdocs/sqlite3.c /^ char *aDoclist; \/* Pointer to doclist of current entry *\/$/;" m struct:Fts3SegReader file: +aDoclist testdocs/sqlite3.c /^ const char *aDoclist; \/* Pointer to doclist *\/$/;" m struct:NodeReader file: +aEntry testdocs/sqlite3.c /^ struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; \/* Allocated entries *\/$/;" m struct:RowSetChunk typeref:struct:RowSetChunk::RowSetEntry file: +aEof testdocs/sqlite3.c /^ u8 *aEof; \/* Pointer to 1 byte past end of doclist *\/$/;" m struct:Fts5DoclistIter file: +aExt testdocs/sqlite3.c /^ void (**aExt)(void); \/* Pointers to the extension init functions *\/$/;" m struct:sqlite3AutoExtList file: +aExtension testdocs/sqlite3.c /^ void **aExtension; \/* Array of shared library handles *\/$/;" m struct:sqlite3 file: +aFile testdocs/sqlite3.c /^ SorterFile aFile[2]; \/* aFile[0] for reading, [1] for writing *\/$/;" m struct:IncrMerger file: +aFirst testdocs/sqlite3.c /^ Fts5CResult *aFirst; \/* Current merge state (see above) *\/$/;" m struct:Fts5Iter file: +aFirst testdocs/sqlite3.c /^ int *aFirst; \/* Array of first token in each sentence *\/$/;" m struct:Fts5SFinder file: +aFold testdocs/sqlite3.c /^ char *aFold; \/* Buffer to fold text into *\/$/;" m struct:Unicode61Tokenizer file: +aFrame testdocs/sqlite3.c /^ RbuFrame *aFrame;$/;" m struct:sqlite3rbu file: +aFrameCksum testdocs/sqlite3.c /^ u32 aFrameCksum[2]; \/* Checksum of last frame in log *\/$/;" m struct:WalIndexHdr file: +aFreq testdocs/sqlite3.c /^ double *aFreq; \/* Array used to calculate phrase freq. *\/$/;" m struct:Fts5Bm25Data file: +aFunc testdocs/sqlite3.c /^ Hash aFunc; \/* Hash table of connection functions *\/$/;" m struct:sqlite3 file: +aFunc testdocs/sqlite3.c /^ } *aFunc;$/;" m struct:AggInfo typeref:struct:AggInfo::AggInfo_func file: +aHardLimit testdocs/sqlite3.c /^static const int aHardLimit[] = {$/;" v file: +aHash testdocs/sqlite3.c /^ u32 aHash[BITVEC_NINT]; \/* Hash table representation *\/$/;" m union:Bitvec::__anon24 file: +aHash testdocs/sqlite3.c /^ RtreeNode *aHash[HASHSIZE]; \/* Hash table of in-memory nodes. *\/$/;" m struct:Rtree file: +aIDF testdocs/sqlite3.c /^ double *aIDF; \/* IDF for each phrase *\/$/;" m struct:Fts5Bm25Data file: +aIdx testdocs/sqlite3.c /^ int aIdx[1]; \/* Offsets into aPoslist for current row *\/$/;" m struct:Fts5Sorter file: +aInLoop testdocs/sqlite3.c /^ } *aInLoop; \/* Information about each nested IN operator *\/$/;" m struct:WhereLevel::__anon27::__anon28 typeref:struct:WhereLevel::__anon27::__anon28::InLoop file: +aIndex testdocs/sqlite3.c /^ ht_slot *aIndex; \/* i0, i1, i2... such that aPgno[iN] ascend *\/$/;" m struct:WalIterator::WalSegment file: +aIndex testdocs/sqlite3.c /^ } *aIndex;$/;" m struct:Fts3Table typeref:struct:Fts3Table::Fts3Index file: +aInput testdocs/sqlite3.c /^ const unsigned char *aInput; \/* Input text being tokenized *\/$/;" m struct:unicode_cursor file: +aInst testdocs/sqlite3.c /^ int *aInst; \/* 3 integers per phrase instance *\/$/;" m struct:Fts5Cursor file: +aInstIter testdocs/sqlite3.c /^ Fts5PoslistReader *aInstIter; \/* One for each phrase *\/$/;" m struct:Fts5Cursor file: +aJournalMagic testdocs/sqlite3.c /^static const unsigned char aJournalMagic[] = {$/;" v file: +aKey testdocs/sqlite3.c /^ u8 *aKey; \/* Pointer to current key *\/$/;" m struct:PmaReader file: +aLTerm testdocs/sqlite3.c /^ WhereTerm **aLTerm; \/* WhereTerms used *\/$/;" m struct:WhereLoop file: +aLTermSpace testdocs/sqlite3.c /^ WhereTerm *aLTermSpace[3]; \/* Initial aLTerm[] space *\/$/;" m struct:WhereLoop file: +aLabel testdocs/sqlite3.c /^ int *aLabel; \/* Space to hold the labels *\/$/;" m struct:Parse file: +aLevel testdocs/sqlite3.c /^ Fts5StructureLevel aLevel[1]; \/* Array of nLevel level objects *\/$/;" m struct:Fts5Structure file: +aLimit testdocs/sqlite3.c /^ int aLimit[SQLITE_N_LIMIT]; \/* Limits *\/$/;" m struct:sqlite3 file: +aLock testdocs/sqlite3.c /^ u8 aLock[SQLITE_SHM_NLOCK]; \/* Reserved space for locks *\/$/;" m struct:WalCkptInfo file: +aLoop testdocs/sqlite3.c /^ WhereLoop **aLoop; \/* Array of WhereLoop objects implementing this path *\/$/;" m struct:WherePath file: +aLvl testdocs/sqlite3.c /^ Fts5DlidxLvl aLvl[1];$/;" m struct:Fts5DlidxIter file: +aMI testdocs/sqlite3.c /^ u32 *aMI; \/* See above *\/$/;" m struct:Fts3Expr file: +aMap testdocs/sqlite3.c /^ u8 *aMap; \/* Pointer to mapping of entire file *\/$/;" m struct:PmaReader file: +aMatchinfo testdocs/sqlite3.c /^ u32 *aMatchinfo; \/* Pre-allocated buffer *\/$/;" m struct:MatchInfo file: +aMatchinfo testdocs/sqlite3.c /^ u32 aMatchinfo[1];$/;" m struct:MatchinfoBuffer file: +aMem testdocs/sqlite3.c /^ Mem *aMem; \/* Array of memory cells for parent frame *\/$/;" m struct:VdbeFrame file: +aMem testdocs/sqlite3.c /^ Mem *aMem; \/* The memory locations *\/$/;" m struct:Vdbe file: +aMem testdocs/sqlite3.c /^ Mem *aMem; \/* Values *\/$/;" m struct:UnpackedRecord file: +aMem testdocs/sqlite3.c /^ sqlite3_value *aMem; \/* First of nMem value in the unpacked pKey *\/$/;" m struct:BtreePayload file: +aMemory testdocs/sqlite3.c /^ u8 *aMemory; \/* If non-NULL, bulk memory to hold pList *\/$/;" m struct:SorterList file: +aModule testdocs/sqlite3.c /^ Hash aModule; \/* populated by sqlite3_create_module() *\/$/;" m struct:sqlite3 file: +aNew testdocs/sqlite3.c /^ Mem *aNew; \/* Array of new.* values *\/$/;" m struct:PreUpdate file: +aNode testdocs/sqlite3.c /^ JsonNode *aNode; \/* Array of nodes containing the parse *\/$/;" m struct:JsonParse file: +aNode testdocs/sqlite3.c /^ RtreeNode *aNode[RTREE_CACHE_SZ]; \/* Rtree node cache *\/$/;" m struct:RtreeCursor file: +aNode testdocs/sqlite3.c /^ char *aNode; \/* Pointer to node data (or NULL) *\/$/;" m struct:Fts3SegReader file: +aNode testdocs/sqlite3.c /^ const char *aNode;$/;" m struct:NodeReader file: +aNodeWriter testdocs/sqlite3.c /^ NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT];$/;" m struct:IncrmergeWriter file: +aOffset testdocs/sqlite3.c /^ int *aOffset; \/* Offsets of each character in utf-8 input *\/$/;" m struct:IcuCursor file: +aOffset testdocs/sqlite3.c /^ u32 *aOffset; \/* Pointer to aType[nField] *\/$/;" m struct:VdbeCursor file: +aOnce testdocs/sqlite3.c /^ u8 *aOnce; \/* Array of OP_Once flags *\/$/;" m struct:SubProgram file: +aOnce testdocs/sqlite3.c /^ u8 *aOnce; \/* Bitmask used by OP_Once *\/$/;" m struct:VdbeFrame file: +aOp testdocs/sqlite3.c /^ Op *aOp; \/* Program instructions for parent frame *\/$/;" m struct:VdbeFrame file: +aOp testdocs/sqlite3.c /^ Op *aOp; \/* Space to hold the virtual machine's program *\/$/;" m struct:Vdbe file: +aOp testdocs/sqlite3.c /^ VdbeOp *aOp; \/* Array of opcodes for sub-program *\/$/;" m struct:SubProgram file: +aOrderBy testdocs/sqlite3.c /^ } *aOrderBy; \/* The ORDER BY clause *\/$/;" m struct:sqlite3_index_info typeref:struct:sqlite3_index_info::sqlite3_index_orderby file: +aOverflow testdocs/sqlite3.c /^ Pgno *aOverflow; \/* Cache of overflow page locations *\/$/;" m struct:BtCursor file: +aOvfl testdocs/sqlite3.c /^ u32 *aOvfl; \/* Array of overflow page numbers *\/$/;" m struct:StatCell file: +aPadding testdocs/sqlite3.c /^ char aPadding[32];$/;" m struct:unixFile file: +aPage testdocs/sqlite3.c /^ StatPage aPage[32];$/;" m struct:StatCursor file: +aParam testdocs/sqlite3.c /^ RtreeDValue aParam[1]; \/* Values for parameters to the SQL function *\/$/;" m struct:RtreeMatchArg file: +aParam testdocs/sqlite3.c /^ sqlite3_rtree_dbl *aParam; \/* value of function parameters *\/$/;" m struct:sqlite3_rtree_query_info file: +aParam testdocs/sqlite3.c /^ sqlite3_rtree_dbl *aParam; \/* Parameters passed to SQL geom function *\/$/;" m struct:sqlite3_rtree_geometry file: +aPgRef testdocs/sqlite3.c /^ u8 *aPgRef; \/* 1 bit per page in the db (see above) *\/$/;" m struct:IntegrityCk file: +aPgno testdocs/sqlite3.c /^ u32 *aPgno; \/* Array of page numbers. *\/$/;" m struct:WalIterator::WalSegment file: +aPhrase testdocs/sqlite3.c /^ SnippetPhrase *aPhrase; \/* Array of size nPhrase *\/$/;" m struct:SnippetIter file: +aPoint testdocs/sqlite3.c /^ RtreeSearchPoint *aPoint; \/* Priority queue for search points *\/$/;" m struct:RtreeCursor file: +aPool testdocs/sqlite3.c /^ Mem3Block *aPool;$/;" m struct:Mem3Global file: +aPopulator testdocs/sqlite3.c /^ Fts5PoslistPopulator *aPopulator;$/;" m struct:Fts5ExprCtx file: +aPoslist testdocs/sqlite3.c /^ const u8 *aPoslist; \/* Position lists for current row *\/$/;" m struct:Fts5Sorter file: +aPoslist testdocs/sqlite3.c /^ u8 *aPoslist;$/;" m struct:Fts5DoclistIter file: +aPragmaName testdocs/sqlite3.c /^static const PragmaName aPragmaName[] = {$/;" v file: +aPrefix testdocs/sqlite3.c /^ int *aPrefix; \/* Sizes in bytes of nPrefix prefix indexes *\/$/;" m struct:Fts5Config file: +aPrefix testdocs/sqlite3.c /^static const char aPrefix[] = "-x0\\000X0";$/;" v file: +aReadMark testdocs/sqlite3.c /^ u32 aReadMark[WAL_NREADER]; \/* Reader marks *\/$/;" m struct:WalCkptInfo file: +aReadr testdocs/sqlite3.c /^ PmaReader *aReadr; \/* Array of PmaReaders to merge data from *\/$/;" m struct:MergeEngine file: +aRecord testdocs/sqlite3.c /^ u8 *aRecord; \/* Buffer containing old.* record *\/$/;" m struct:SessionChange file: +aRecord testdocs/sqlite3.c /^ u8 *aRecord; \/* old.* database record *\/$/;" m struct:PreUpdate file: +aRef testdocs/sqlite3.c /^ u8 aRef[3];$/;" m struct:MatchinfoBuffer file: +aRegion testdocs/sqlite3.c /^ } *aRegion;$/;" m struct:winShmNode typeref:struct:winShmNode::ShmRegion file: +aRow testdocs/sqlite3.c /^ const u8 *aRow; \/* Data for the current row, if all on one page *\/$/;" m struct:VdbeCursor file: +aRowid testdocs/sqlite3.c /^ u8 *aRowid; \/* Key for WITHOUT ROWID tables *\/$/;" m union:Stat4Sample::__anon26 file: +aRowidOffset testdocs/sqlite3.c /^ int *aRowidOffset; \/* Array of offset to rowid fields *\/$/;" m struct:Fts5SegIter file: +aSalt testdocs/sqlite3.c /^ u32 aSalt[2]; \/* Two salt values copied from WAL header *\/$/;" m struct:WalIndexHdr file: +aSample testdocs/sqlite3.c /^ IndexSample *aSample; \/* Samples of the left-most key *\/$/;" m struct:Index file: +aSavepoint testdocs/sqlite3.c /^ PagerSavepoint *aSavepoint; \/* Array of active savepoints *\/$/;" m struct:Pager file: +aScan testdocs/sqlite3.c /^ ScanStatus *aScan; \/* Scan definitions for sqlite3_stmt_scanstatus() *\/$/;" m struct:Vdbe file: +aSeg testdocs/sqlite3.c /^ Fts5SegIter aSeg[1]; \/* Array of segment iterators *\/$/;" m struct:Fts5Iter file: +aSeg testdocs/sqlite3.c /^ Fts5StructureSegment *aSeg; \/* Array of segments. aSeg[0] is oldest. *\/$/;" m struct:Fts5StructureLevel file: +aSegment testdocs/sqlite3.c /^ } aSegment[1]; \/* One for every 32KB page in the wal-index *\/$/;" m struct:WalIterator typeref:struct:WalIterator::WalSegment file: +aSemName testdocs/sqlite3.c /^ char aSemName[MAX_PATHNAME+2]; \/* Name of that semaphore *\/$/;" m struct:unixInodeInfo file: +aSlot testdocs/sqlite3.c /^ Fts5HashEntry **aSlot; \/* Array of hash slots *\/$/;" m struct:Fts5Hash file: +aSortOrder testdocs/sqlite3.c /^ u8 *aSortOrder; \/* for each column: True==DESC, False==ASC *\/$/;" m struct:Index file: +aSortOrder testdocs/sqlite3.c /^ u8 *aSortOrder; \/* Sort order for each column. *\/$/;" m struct:KeyInfo file: +aStat testdocs/sqlite3.c /^ int aStat[3]; \/* Total cache hits, misses and writes *\/$/;" m struct:Pager file: +aStat testdocs/sqlite3.c /^ } *aStat;$/;" m struct:Fts3auxCursor typeref:struct:Fts3auxCursor::Fts3auxColstats file: +aStatic testdocs/sqlite3.c /^ WhereTerm aStatic[1]; \/* Initial static space for a[] *\/$/;" m struct:WhereClause file: +aStatic testdocs/sqlite3.c /^ WhereTerm aStatic[8]; \/* Initial static space for a[] *\/$/;" m struct:WhereClause file: +aStmt testdocs/sqlite3.c /^ sqlite3_stmt *aStmt[11];$/;" m struct:Fts5Storage file: +aStmt testdocs/sqlite3.c /^ sqlite3_stmt *aStmt[40];$/;" m struct:Fts3Table file: +aSyscall testdocs/sqlite3.c /^} aSyscall[] = {$/;" v typeref:struct:unix_syscall file: +aSyscall testdocs/sqlite3.c /^} aSyscall[] = {$/;" v typeref:struct:win_syscall file: +aTableLock testdocs/sqlite3.c /^ TableLock *aTableLock; \/* Required table locks for shared-cache mode *\/$/;" m struct:Parse file: +aTask testdocs/sqlite3.c /^ SortSubtask aTask[1]; \/* One or more subtasks *\/$/;" m struct:VdbeSorter file: +aTempReg testdocs/sqlite3.c /^ int aTempReg[8]; \/* Holding area for temporary registers *\/$/;" m struct:Parse file: +aTerm testdocs/sqlite3.c /^ Fts5ExprTerm aTerm[1]; \/* Terms that make up this phrase *\/$/;" m struct:Fts5ExprPhrase file: +aTerm testdocs/sqlite3.c /^ TermOffset *aTerm;$/;" m struct:TermOffsetCtx file: +aToken testdocs/sqlite3.c /^ Fts3PhraseToken aToken[1]; \/* One entry for each token in the phrase *\/$/;" m struct:Fts3Phrase file: +aTokenChar testdocs/sqlite3.c /^ unsigned char aTokenChar[128]; \/* ASCII range token characters *\/$/;" m struct:Unicode61Tokenizer file: +aTokenChar testdocs/sqlite3.c /^ unsigned char aTokenChar[128];$/;" m struct:AsciiTokenizer file: +aTotalSize testdocs/sqlite3.c /^ i64 *aTotalSize; \/* Total sizes of each column *\/$/;" m struct:Fts5Storage file: +aTree testdocs/sqlite3.c /^ int *aTree; \/* Current state of incremental merge *\/$/;" m struct:MergeEngine file: +aType testdocs/sqlite3.c /^ u32 aType[1]; \/* Type values record decode. MUST BE LAST *\/$/;" m struct:VdbeCursor file: +aUp testdocs/sqlite3.c /^ u32 *aUp; \/* Index of parent of each node *\/$/;" m struct:JsonParse file: +aVTrans testdocs/sqlite3.c /^ VTable **aVTrans; \/* Virtual tables with open transactions *\/$/;" m struct:sqlite3 file: +aVar testdocs/sqlite3.c /^ Mem *aVar; \/* Values for the OP_Variable opcode. *\/$/;" m struct:Vdbe file: +aWalData testdocs/sqlite3.c /^ u32 aWalData[WAL_SAVEPOINT_NDATA]; \/* WAL savepoint context *\/$/;" m struct:PagerSavepoint file: +aXformType testdocs/sqlite3.c /^} aXformType[] = {$/;" v typeref:struct:__anon19 file: +aaOutput testdocs/sqlite3.c /^ char *aaOutput[16]; \/* Malloc'd output buffers *\/$/;" m struct:TermSelect file: +abIndexed testdocs/sqlite3.c /^ u8 *abIndexed; \/* Array of flags, set on indexed & PK cols *\/$/;" m struct:RbuObjIter file: +abNotNull testdocs/sqlite3.c /^ u8 *abNotNull; \/* Array of flags, set on NOT NULL columns *\/$/;" m struct:RbuObjIter file: +abNotindexed testdocs/sqlite3.c /^ u8 *abNotindexed; \/* True for 'notindexed' columns *\/$/;" m struct:Fts3Table file: +abPK testdocs/sqlite3.c /^ u8 *abPK; \/* Array of primary key flags *\/$/;" m struct:SessionTable file: +abPK testdocs/sqlite3.c /^ u8 *abPK; \/* Boolean array - true if column is in PK *\/$/;" m struct:SessionApplyCtx file: +abPK testdocs/sqlite3.c /^ u8 *abPK; \/* Primary key array *\/$/;" m struct:sqlite3_changeset_iter file: +abTblPk testdocs/sqlite3.c /^ u8 *abTblPk; \/* Array of flags, set on target PK columns *\/$/;" m struct:RbuObjIter file: +abUnindexed testdocs/sqlite3.c /^ u8 *abUnindexed; \/* True for unindexed columns *\/$/;" m struct:Fts5Config file: +absFunc testdocs/sqlite3.c /^static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){$/;" f file: +accError testdocs/sqlite3.c /^ u8 accError; \/* STRACCUM_NOMEM or STRACCUM_TOOBIG *\/$/;" m struct:StrAccum file: +accessPayload testdocs/sqlite3.c /^static int accessPayload($/;" f file: +accessPayloadChecked testdocs/sqlite3.c /^static SQLITE_NOINLINE int accessPayloadChecked($/;" f file: +actionName testdocs/sqlite3.c /^static const char *actionName(u8 action){$/;" f file: +addAggInfoColumn testdocs/sqlite3.c /^static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){$/;" f file: +addAggInfoFunc testdocs/sqlite3.c /^static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){$/;" f file: +addArgumentToVtab testdocs/sqlite3.c /^static void addArgumentToVtab(Parse *pParse){$/;" f file: +addColOffset testdocs/sqlite3.c /^ int addColOffset; \/* Offset in CREATE TABLE stmt to add a new column *\/$/;" m struct:Table file: +addModuleArgument testdocs/sqlite3.c /^static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){$/;" f file: +addToBlockedList testdocs/sqlite3.c /^static void addToBlockedList(sqlite3 *db){$/;" f file: +addToSavepointBitvecs testdocs/sqlite3.c /^static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){$/;" f file: +addToVTrans testdocs/sqlite3.c /^static void addToVTrans(sqlite3 *db, VTable *pVTab){$/;" f file: +addWhereTerm testdocs/sqlite3.c /^static void addWhereTerm($/;" f file: +addrBody testdocs/sqlite3.c /^ int addrBody; \/* Beginning of the body of this loop *\/$/;" m struct:WhereLevel file: +addrBrk testdocs/sqlite3.c /^ int addrBrk; \/* Jump here to break out of the loop *\/$/;" m struct:WhereLevel file: +addrCont testdocs/sqlite3.c /^ int addrCont; \/* Jump here to continue with the next loop cycle *\/$/;" m struct:WhereLevel file: +addrCrTab testdocs/sqlite3.c /^ int addrCrTab; \/* Address of OP_CreateTable opcode on CREATE TABLE *\/$/;" m struct:Parse file: +addrExplain testdocs/sqlite3.c /^ int addrExplain; \/* OP_Explain for loop *\/$/;" m struct:ScanStatus file: +addrFillSub testdocs/sqlite3.c /^ int addrFillSub; \/* Address of subroutine to manifest a subquery *\/$/;" m struct:SrcList::SrcList_item file: +addrFirst testdocs/sqlite3.c /^ int addrFirst; \/* First instruction of interior of the loop *\/$/;" m struct:WhereLevel file: +addrInTop testdocs/sqlite3.c /^ int addrInTop; \/* Top of the IN loop *\/$/;" m struct:WhereLevel::__anon27::__anon28::InLoop file: +addrLikeRep testdocs/sqlite3.c /^ int addrLikeRep; \/* LIKE range processing address *\/$/;" m struct:WhereLevel file: +addrLoop testdocs/sqlite3.c /^ int addrLoop; \/* Address of "loops" counter *\/$/;" m struct:ScanStatus file: +addrNxt testdocs/sqlite3.c /^ int addrNxt; \/* Jump here to start the next IN combination *\/$/;" m struct:WhereLevel file: +addrOpenEphm testdocs/sqlite3.c /^ int addrOpenEphm[2]; \/* OP_OpenEphem opcodes related to this select *\/$/;" m struct:Select file: +addrSkip testdocs/sqlite3.c /^ int addrSkip; \/* Jump here for next iteration of skip-scan *\/$/;" m struct:WhereLevel file: +addrSortIndex testdocs/sqlite3.c /^ int addrSortIndex; \/* Address of the OP_SorterOpen or OP_OpenEphemeral *\/$/;" m struct:SortCtx file: +addrTnct testdocs/sqlite3.c /^ int addrTnct; \/* Address of OP_OpenEphemeral opcode for tabTnct *\/$/;" m struct:DistinctCtx file: +addrVisit testdocs/sqlite3.c /^ int addrVisit; \/* Address of "rows visited" counter *\/$/;" m struct:ScanStatus file: +addrVisit testdocs/sqlite3.c /^ int addrVisit; \/* Address at which row is visited *\/$/;" m struct:WhereLevel file: +adjustStats testdocs/sqlite3.c /^static void adjustStats(int iSize, int increment){$/;" f file: +affinity testdocs/sqlite3.c /^ char affinity; \/* The affinity of the column or 0 if not a column *\/$/;" m struct:Expr file: +affinity testdocs/sqlite3.c /^ char affinity; \/* One of the SQLITE_AFF_... values *\/$/;" m struct:Column file: +afpCheckReservedLock testdocs/sqlite3.c /^static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){$/;" f file: +afpClose testdocs/sqlite3.c /^static int afpClose(sqlite3_file *id) {$/;" f file: +afpLock testdocs/sqlite3.c /^static int afpLock(sqlite3_file *id, int eFileLock){$/;" f file: +afpLockingContext testdocs/sqlite3.c /^struct afpLockingContext {$/;" s file: +afpLockingContext testdocs/sqlite3.c /^typedef struct afpLockingContext afpLockingContext;$/;" t typeref:struct:afpLockingContext file: +afpSetLock testdocs/sqlite3.c /^static int afpSetLock($/;" f file: +afpUnlock testdocs/sqlite3.c /^static int afpUnlock(sqlite3_file *id, int eFileLock) {$/;" f file: +afpfsByteRangeLock2FSCTL testdocs/sqlite3.c /^#define afpfsByteRangeLock2FSCTL /;" d file: +aggregate_context testdocs/sqlite3.c /^ void * (*aggregate_context)(sqlite3_context*,int nBytes);$/;" m struct:sqlite3_api_routines file: +aggregate_count testdocs/sqlite3.c /^ int (*aggregate_count)(sqlite3_context*);$/;" m struct:sqlite3_api_routines file: +ai testdocs/sqlite3.c /^ int *ai; \/* Used when p4type is P4_INTARRAY *\/$/;" m union:VdbeOp::p4union file: +aiClass testdocs/sqlite3.c /^static const unsigned char aiClass[] = {$/;" v file: +aiCol testdocs/sqlite3.c /^ int *aiCol; \/* array of column indexes *\/$/;" m union:Walker::__anon17 file: +aiCol testdocs/sqlite3.c /^ int aiCol[1];$/;" m struct:Fts5Colset file: +aiColumn testdocs/sqlite3.c /^ i16 *aiColumn; \/* Which columns are used by this index. 1st is 0 *\/$/;" m struct:Index file: +aiColumn testdocs/sqlite3.c /^ i16 aiColumn[11]; \/* Corresponding column number in the eq-class *\/$/;" m struct:WhereScan file: +aiCur testdocs/sqlite3.c /^ int aiCur[11]; \/* Cursors in the equivalence class *\/$/;" m struct:WhereScan file: +aiCurOnePass testdocs/sqlite3.c /^ int aiCurOnePass[2]; \/* OP_OpenWrite cursors for the ONEPASS opt *\/$/;" m struct:WhereInfo file: +aiException testdocs/sqlite3.c /^ int *aiException;$/;" m struct:Unicode61Tokenizer file: +aiException testdocs/sqlite3.c /^ int *aiException;$/;" m struct:unicode_tokenizer file: +aiFreelist testdocs/sqlite3.c /^ int aiFreelist[LOGMAX+1];$/;" m struct:Mem5Global file: +aiHash testdocs/sqlite3.c /^ u32 aiHash[N_HASH]; \/* For sizes MX_SMALL+1 and larger *\/$/;" m struct:Mem3Global file: +aiIdx testdocs/sqlite3.c /^ u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; \/* Current index in apPage[i] *\/$/;" m struct:BtCursor file: +aiOvfl testdocs/sqlite3.c /^ u16 aiOvfl[4]; \/* Insert the i-th overflow cell before the aiOvfl-th$/;" m struct:MemPage file: +aiRowEst testdocs/sqlite3.c /^ tRowcnt *aiRowEst; \/* Non-logarithmic stat1 data for this index *\/$/;" m struct:Index file: +aiRowLogEst testdocs/sqlite3.c /^ LogEst *aiRowLogEst; \/* From ANALYZE: Est. rows selected by each column *\/$/;" m struct:Index file: +aiSmall testdocs/sqlite3.c /^ u32 aiSmall[MX_SMALL-1]; \/* For sizes 2 through MX_SMALL, inclusive *\/$/;" m struct:Mem3Global file: +aiSrcOrder testdocs/sqlite3.c /^ int *aiSrcOrder; \/* src table col -> target table col *\/$/;" m struct:RbuObjIter file: +alarmBusy testdocs/sqlite3.c /^ int alarmBusy;$/;" m struct:Mem3Global file: +alarmThreshold testdocs/sqlite3.c /^ sqlite3_int64 alarmThreshold; \/* The soft heap limit *\/$/;" m struct:Mem0Global file: +allSpaces testdocs/sqlite3.c /^static int allSpaces(const char *z, int n){$/;" f file: +allocSpace testdocs/sqlite3.c /^static void *allocSpace($/;" f file: +allocVdbe testdocs/sqlite3.c /^static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){$/;" f file: +allocateBtreePage testdocs/sqlite3.c /^static int allocateBtreePage($/;" f file: +allocateCursor testdocs/sqlite3.c /^static VdbeCursor *allocateCursor($/;" f file: +allocateIndexInfo testdocs/sqlite3.c /^static sqlite3_index_info *allocateIndexInfo($/;" f file: +allocateSpace testdocs/sqlite3.c /^static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){$/;" f file: +allocateTempSpace testdocs/sqlite3.c /^static void allocateTempSpace(BtShared *pBt){$/;" f file: +allowedOp testdocs/sqlite3.c /^static int allowedOp(int op){$/;" f file: +anDLt testdocs/sqlite3.c /^ tRowcnt *anDLt; \/* sqlite_stat4.nDLt *\/$/;" m struct:Stat4Sample file: +anDLt testdocs/sqlite3.c /^ tRowcnt *anDLt; \/* Est. number of distinct keys less than this sample *\/$/;" m struct:IndexSample file: +anEq testdocs/sqlite3.c /^ tRowcnt *anEq; \/* sqlite_stat4.nEq *\/$/;" m struct:Stat4Sample file: +anEq testdocs/sqlite3.c /^ tRowcnt *anEq; \/* Est. number of rows where the key equals this sample *\/$/;" m struct:IndexSample file: +anExec testdocs/sqlite3.c /^ i64 *anExec; \/* Event counters from parent frame *\/$/;" m struct:VdbeFrame file: +anExec testdocs/sqlite3.c /^ i64 *anExec; \/* Number of times each op has been executed *\/$/;" m struct:Vdbe file: +anLt testdocs/sqlite3.c /^ tRowcnt *anLt; \/* sqlite_stat4.nLt *\/$/;" m struct:Stat4Sample file: +anLt testdocs/sqlite3.c /^ tRowcnt *anLt; \/* Est. number of rows where key is less than this sample *\/$/;" m struct:IndexSample file: +anOutput testdocs/sqlite3.c /^ int anOutput[16]; \/* Size each output buffer in bytes *\/$/;" m struct:TermSelect file: +anQueue testdocs/sqlite3.c /^ u32 anQueue[RTREE_MAX_DEPTH+1]; \/* Number of queued entries by iLevel *\/$/;" m struct:RtreeCursor file: +anQueue testdocs/sqlite3.c /^ unsigned int *anQueue; \/* Number of pending entries in the queue *\/$/;" m struct:sqlite3_rtree_query_info file: +anStat testdocs/sqlite3.c /^ int anStat[3]; \/* 0: hits. 1: size misses. 2: full misses *\/$/;" m struct:Lookaside file: +analysisInfo testdocs/sqlite3.c /^struct analysisInfo {$/;" s file: +analysisInfo testdocs/sqlite3.c /^typedef struct analysisInfo analysisInfo;$/;" t typeref:struct:analysisInfo file: +analysisLoader testdocs/sqlite3.c /^static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){$/;" f file: +analyzeAggregate testdocs/sqlite3.c /^static int analyzeAggregate(Walker *pWalker, Expr *pExpr){$/;" f file: +analyzeAggregatesInSelect testdocs/sqlite3.c /^static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){$/;" f file: +analyzeDatabase testdocs/sqlite3.c /^static void analyzeDatabase(Parse *pParse, int iDb){$/;" f file: +analyzeOneTable testdocs/sqlite3.c /^static void analyzeOneTable($/;" f file: +analyzeTable testdocs/sqlite3.c /^static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){$/;" f file: +apArg testdocs/sqlite3.c /^ Mem **apArg; \/* Arguments to currently executing user function *\/$/;" m struct:Vdbe file: +apArg testdocs/sqlite3.c /^ sqlite3_value **apArg; \/* The argument values *\/$/;" m struct:PrintfArguments file: +apCell testdocs/sqlite3.c /^ u8 **apCell; \/* All cells begin balanced *\/$/;" m struct:CellArray file: +apChange testdocs/sqlite3.c /^ SessionChange **apChange; \/* Hash table buckets *\/$/;" m struct:SessionTable file: +apChild testdocs/sqlite3.c /^ Fts5ExprNode *apChild[1]; \/* Array of child nodes *\/$/;" m struct:Fts5ExprNode file: +apCsr testdocs/sqlite3.c /^ VdbeCursor **apCsr; \/* Array of Vdbe cursors for parent frame *\/$/;" m struct:VdbeFrame file: +apCsr testdocs/sqlite3.c /^ VdbeCursor **apCsr; \/* One element of this array for each open cursor *\/$/;" m struct:Vdbe file: +apExprPhrase testdocs/sqlite3.c /^ Fts5ExprPhrase **apExprPhrase; \/* Pointers to phrase objects *\/$/;" m struct:Fts5Expr file: +apHash testdocs/sqlite3.c /^ Fts5TermsetEntry *apHash[512];$/;" m struct:Fts5Termset file: +apHash testdocs/sqlite3.c /^ PgHdr1 **apHash; \/* Hash table for fast lookup by key *\/$/;" m struct:PCache1 file: +apOvfl testdocs/sqlite3.c /^ u8 *apOvfl[4]; \/* Pointers to the body of overflow cells *\/$/;" m struct:MemPage file: +apPage testdocs/sqlite3.c /^ MemPage *apPage[BTCURSOR_MAX_DEPTH]; \/* Pages from root to current page *\/$/;" m struct:BtCursor file: +apPhrase testdocs/sqlite3.c /^ Fts5ExprPhrase **apPhrase; \/* Array of all phrases *\/$/;" m struct:Fts5Parse file: +apPhrase testdocs/sqlite3.c /^ Fts5ExprPhrase *apPhrase[1]; \/* Array of phrase pointers *\/$/;" m struct:Fts5ExprNearset file: +apRankArg testdocs/sqlite3.c /^ sqlite3_value **apRankArg; \/* Array of trailing arguments *\/$/;" m struct:Fts5Cursor file: +apRegion testdocs/sqlite3.c /^ char **apRegion; \/* Array of mapped shared-memory regions *\/$/;" m struct:unixShmNode file: +apSegment testdocs/sqlite3.c /^ Fts3SegReader **apSegment; \/* Array of Fts3SegReader objects *\/$/;" m struct:Fts3MultiSegReader file: +apShm testdocs/sqlite3.c /^ char **apShm; \/* Array of mmap'd *-shm regions *\/$/;" m struct:rbu_file file: +apSqlParam testdocs/sqlite3.c /^ sqlite3_value **apSqlParam; \/* Original SQL values of parameters *\/$/;" m struct:sqlite3_rtree_query_info file: +apSqlParam testdocs/sqlite3.c /^ sqlite3_value **apSqlParam; \/* Original SQL parameter values *\/$/;" m struct:RtreeMatchArg file: +apSub testdocs/sqlite3.c /^ Bitvec *apSub[BITVEC_NPTR]; \/* Recursive representation *\/$/;" m union:Bitvec::__anon24 file: +apSub testdocs/sqlite3.c /^ SubProgram **apSub; \/* Array of subprograms *\/$/;" m struct:VdbeOpIter file: +apTrigger testdocs/sqlite3.c /^ Trigger *apTrigger[2];\/* Triggers for aAction[] actions *\/$/;" m struct:FKey file: +apValue testdocs/sqlite3.c /^ sqlite3_value **apValue; \/* old.* and new.* values *\/$/;" m struct:sqlite3_changeset_iter file: +apVtabLock testdocs/sqlite3.c /^ Table **apVtabLock; \/* Pointer to virtual tables needing locking *\/$/;" m struct:Parse file: +apWiData testdocs/sqlite3.c /^ volatile u32 **apWiData; \/* Pointer to wal-index content in memory *\/$/;" m struct:Wal file: +api testdocs/sqlite3.c /^ fts5_api api; \/* User visible part of object (see fts5.h) *\/$/;" m struct:Fts5Global file: +apiOomError testdocs/sqlite3.c /^static SQLITE_NOINLINE int apiOomError(sqlite3 *db){$/;" f file: +applyAffinity testdocs/sqlite3.c /^static void applyAffinity($/;" f file: +applyNumericAffinity testdocs/sqlite3.c /^static void applyNumericAffinity(Mem *pRec, int bTryForInt){$/;" f file: +approx testdocs/sqlite3.c /^ u8 approx; \/* True if non-integer value was input to the sum *\/$/;" m struct:SumCtx file: +argc testdocs/sqlite3.c /^ u8 argc; \/* Number of arguments *\/$/;" m struct:sqlite3_context file: +argv testdocs/sqlite3.c /^ sqlite3_value *argv[1]; \/* Argument set *\/$/;" m struct:sqlite3_context file: +argvIndex testdocs/sqlite3.c /^ int argvIndex; \/* if >0, constraint is part of argv to xFilter *\/$/;" m struct:sqlite3_index_info::sqlite3_index_constraint_usage file: +asciiFold testdocs/sqlite3.c /^static void asciiFold(char *aOut, const char *aIn, int nByte){$/;" f file: +assertCellInfo testdocs/sqlite3.c /^ #define assertCellInfo(/;" d file: +assertCellInfo testdocs/sqlite3.c /^ static void assertCellInfo(BtCursor *pCur){$/;" f file: +assertColumnName testdocs/sqlite3.c /^# define assertColumnName(/;" d file: +assertColumnName testdocs/sqlite3.c /^static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){$/;" f file: +assertMutexHeld testdocs/sqlite3.c /^#define assertMutexHeld(/;" d file: +assertParentIndex testdocs/sqlite3.c /^# define assertParentIndex(/;" d file: +assertParentIndex testdocs/sqlite3.c /^static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){$/;" f file: +assertTruncateConstraint testdocs/sqlite3.c /^# define assertTruncateConstraint(/;" d file: +assertTruncateConstraint testdocs/sqlite3.c /^static void assertTruncateConstraint(Pager *pPager){$/;" f file: +assertTruncateConstraintCb testdocs/sqlite3.c /^static void assertTruncateConstraintCb(PgHdr *pPg){$/;" f file: +assert_nc testdocs/sqlite3.c /^# define assert_nc(/;" d file: +assert_pager_state testdocs/sqlite3.c /^static int assert_pager_state(Pager *p){$/;" f file: +atEOF testdocs/sqlite3.c /^ u8 atEOF; \/* True if at end of search *\/$/;" m struct:RtreeCursor file: +atf_init atf.h /^void atf_init(int argc, char** argv) {$/;" f +atf_print_results atf.h /^int atf_print_results(void) {$/;" f +atf_test_assert atf.h /^bool atf_test_assert(bool success, char* expr, char* file, int line) {$/;" f +atf_test_fail atf.h /^void atf_test_fail(char* expr, char* file, int line) {$/;" f +atf_test_start atf.h /^void atf_test_start(char* file, unsigned int line, char* name) {$/;" f +attachBackupObject testdocs/sqlite3.c /^static void attachBackupObject(sqlite3_backup *p){$/;" f file: +attachFunc testdocs/sqlite3.c /^static void attachFunc($/;" f file: +auth testdocs/sqlite3.c /^ sqlite3_userauth auth; \/* User authentication information *\/$/;" m struct:sqlite3 file: +authLevel testdocs/sqlite3.c /^ u8 authLevel; \/* Current authentication level *\/$/;" m struct:sqlite3_userauth file: +autoCommit testdocs/sqlite3.c /^ u8 autoCommit; \/* The auto-commit flag. *\/$/;" m struct:sqlite3 file: +autoIncBegin testdocs/sqlite3.c /^# define autoIncBegin(/;" d file: +autoIncBegin testdocs/sqlite3.c /^static int autoIncBegin($/;" f file: +autoIncStep testdocs/sqlite3.c /^# define autoIncStep(/;" d file: +autoIncStep testdocs/sqlite3.c /^static void autoIncStep(Parse *pParse, int memId, int regRowid){$/;" f file: +autoIncrementEnd testdocs/sqlite3.c /^static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){$/;" f file: +autoVacuum testdocs/sqlite3.c /^ u8 autoVacuum; \/* True if auto-vacuum is enabled *\/$/;" m struct:BtShared file: +autoVacuumCommit testdocs/sqlite3.c /^static int autoVacuumCommit(BtShared *pBt){$/;" f file: +auto_extension testdocs/sqlite3.c /^ int (*auto_extension)(void(*)(void));$/;" m struct:sqlite3_api_routines file: +autolockIoFinder testdocs/sqlite3.c /^ *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;$/;" v file: +autolockIoFinderImpl testdocs/sqlite3.c /^static const sqlite3_io_methods *autolockIoFinderImpl($/;" f file: +avgFinalize testdocs/sqlite3.c /^static void avgFinalize(sqlite3_context *context){$/;" f file: +avgdl testdocs/sqlite3.c /^ double avgdl; \/* Average number of tokens in each row *\/$/;" m struct:Fts5Bm25Data file: +azArg testdocs/sqlite3.c /^ char *azArg[2]; \/* Value of the argument and schema *\/$/;" m struct:PragmaVtabCursor file: +azCol testdocs/sqlite3.c /^ char **azCol; \/* Column names *\/$/;" m struct:Fts5Config file: +azCol testdocs/sqlite3.c /^ const char **azCol; \/* Array of column names for fts3 table *\/$/;" m struct:ParseContext file: +azCol testdocs/sqlite3.c /^ const char **azCol; \/* Array of column names *\/$/;" m struct:SessionApplyCtx file: +azCol testdocs/sqlite3.c /^ const char **azCol; \/* Column names *\/$/;" m struct:SessionTable file: +azColl testdocs/sqlite3.c /^ const char **azColl; \/* Array of collation sequence names for index *\/$/;" m struct:Index file: +azColumn testdocs/sqlite3.c /^ char **azColumn; \/* column names. malloced *\/$/;" m struct:Fts3Table file: +azCompileOpt testdocs/sqlite3.c /^static const char * const azCompileOpt[] = {$/;" v file: +azFileLock testdocs/sqlite3.c /^static const char *azFileLock(int eFileLock){$/;" f file: +azModuleArg testdocs/sqlite3.c /^ char **azModuleArg; \/* 0: module 1: schema 2: vtab name 3...: args *\/$/;" m struct:Table file: +azResult testdocs/sqlite3.c /^ char **azResult; \/* Accumulated output *\/$/;" m struct:TabResult file: +azTblCol testdocs/sqlite3.c /^ char **azTblCol; \/* Array of unquoted target column names *\/$/;" m struct:RbuObjIter file: +azTblType testdocs/sqlite3.c /^ char **azTblType; \/* Array of target column types *\/$/;" m struct:RbuObjIter file: +b testdocs/sqlite3.c /^ const unsigned char *b;$/;" m struct:Fts5PhraseIter file: +b testdocs/sqlite3.c /^struct TrigEvent { int a; IdList * b; };$/;" m struct:TrigEvent file: +b testdocs/waf /^ def b(x):$/;" f function:b +b testdocs/waf /^def b(x):$/;" f +bAutoAttach testdocs/sqlite3.c /^ int bAutoAttach; \/* True to auto-attach tables *\/$/;" m struct:sqlite3_session file: +bBenignMalloc testdocs/sqlite3.c /^ u8 bBenignMalloc; \/* Do not require OOMs if true *\/$/;" m struct:sqlite3 file: +bBusy testdocs/sqlite3.c /^ u8 bBusy; \/* Prevent endless loops on corrupt database files *\/$/;" m struct:MemPage file: +bCleanup testdocs/sqlite3.c /^ int bCleanup; \/* True in "cleanup" state *\/$/;" m struct:RbuObjIter file: +bColumnsize testdocs/sqlite3.c /^ int bColumnsize; \/* "columnsize=" option value (dflt==1) *\/$/;" m struct:Fts5Config file: +bConstraint testdocs/sqlite3.c /^ u8 bConstraint; \/* True if constraints are supported *\/$/;" m struct:VTable file: +bContent testdocs/sqlite3.c /^ u8 bContent; \/* Set content-flag (detail=none mode) *\/$/;" m struct:Fts5HashEntry file: +bCoreMutex testdocs/sqlite3.c /^ int bCoreMutex; \/* True to enable core mutexing *\/$/;" m struct:Sqlite3Config file: +bDeclared testdocs/sqlite3.c /^ int bDeclared; \/* True after sqlite3_declare_vtab() is called *\/$/;" m struct:VtabCtx file: +bDeferConstraints testdocs/sqlite3.c /^ int bDeferConstraints; \/* True to defer constraints *\/$/;" m struct:SessionApplyCtx file: +bDeferred testdocs/sqlite3.c /^ u8 bDeferred; \/* True if this expression is entirely deferred *\/$/;" m struct:Fts3Expr file: +bDel testdocs/sqlite3.c /^ u8 bDel; \/* Set delete-flag @ iSzPoslist *\/$/;" m struct:Fts5HashEntry file: +bDel testdocs/sqlite3.c /^ u8 bDel; \/* True if the delete flag is set *\/$/;" m struct:Fts5SegIter file: +bDelete testdocs/sqlite3.c /^ int bDelete; \/* Current write is a delete *\/$/;" m struct:Fts5Index file: +bDesc testdocs/sqlite3.c /^ int bDesc; \/* Iterate in descending rowid order *\/$/;" m struct:Fts5Expr file: +bDesc testdocs/sqlite3.c /^ int bDesc; \/* True for "ORDER BY rowid DESC" queries *\/$/;" m struct:Fts5Cursor file: +bDesc testdocs/sqlite3.c /^ u8 bDesc; \/* True to sort in descending order *\/$/;" m struct:Fts3Cursor file: +bDescIdx testdocs/sqlite3.c /^ u8 bDescIdx; \/* True if doclists are in reverse order *\/$/;" m struct:Fts3Table file: +bDestLocked testdocs/sqlite3.c /^ int bDestLocked; \/* True once a write-transaction is open on pDest *\/$/;" m struct:sqlite3_backup file: +bDisable testdocs/sqlite3.c /^ u32 bDisable; \/* Only operate the lookaside when zero *\/$/;" m struct:Lookaside file: +bDoTruncate testdocs/sqlite3.c /^ u8 bDoTruncate; \/* True to truncate db on commit *\/$/;" m struct:BtShared file: +bDone testdocs/sqlite3.c /^ int bDone; \/* Set if thread is finished but not joined *\/$/;" m struct:SortSubtask file: +bEnable testdocs/sqlite3.c /^ int bEnable; \/* True if currently recording *\/$/;" m struct:sqlite3_session file: +bEof testdocs/sqlite3.c /^ int bEof; \/* Set to true after xInput finished *\/$/;" m struct:SessionInput file: +bEof testdocs/sqlite3.c /^ int bEof; \/* Set to true when merge is finished *\/$/;" m struct:IncrMerger file: +bEof testdocs/sqlite3.c /^ int bEof; \/* True at EOF *\/$/;" m struct:Fts5ExprNode file: +bEof testdocs/sqlite3.c /^ int bEof; \/* True if this cursor is at EOF *\/$/;" m struct:Fts5VocabCursor file: +bEof testdocs/sqlite3.c /^ int bEof; \/* At EOF already *\/$/;" m struct:Fts5DlidxLvl file: +bEof testdocs/sqlite3.c /^ u8 bEof; \/* Set to true at EOF *\/$/;" m struct:Fts5PoslistReader file: +bEof testdocs/sqlite3.c /^ u8 bEof; \/* True this expression is at EOF already *\/$/;" m struct:Fts3Expr file: +bEof testdocs/sqlite3.c /^ u8 bEof;$/;" m struct:Fts5IndexIter file: +bErr testdocs/sqlite3.c /^ u8 bErr; \/* True if an error has been encountered *\/$/;" m struct:JsonString file: +bExclusive testdocs/sqlite3.c /^ BOOL bExclusive; \/* Indicates an exclusive lock has been obtained *\/$/;" m struct:winceLock file: +bFirst testdocs/sqlite3.c /^ int bFirst; \/* True if token must appear at position 0 *\/$/;" m struct:Fts3PhraseToken file: +bFirstRowidInDoclist testdocs/sqlite3.c /^ u8 bFirstRowidInDoclist; \/* True if next rowid is first in doclist *\/$/;" m struct:Fts5SegWriter file: +bFirstRowidInPage testdocs/sqlite3.c /^ u8 bFirstRowidInPage; \/* True if next rowid is first in page *\/$/;" m struct:Fts5SegWriter file: +bFirstTermInPage testdocs/sqlite3.c /^ u8 bFirstTermInPage; \/* True if next term will be first in leaf *\/$/;" m struct:Fts5SegWriter file: +bFlag testdocs/sqlite3.c /^ u8 bFlag; \/* For client use (any custom purpose) *\/$/;" m struct:Fts5PoslistReader file: +bFreeList testdocs/sqlite3.c /^ int bFreeList; \/* True if pList should be sqlite3_free()d *\/$/;" m struct:Fts3Doclist file: +bFts4 testdocs/sqlite3.c /^ int bFts4; \/* True to allow FTS4-only syntax *\/$/;" m struct:ParseContext file: +bFts4 testdocs/sqlite3.c /^ u8 bFts4; \/* True for FTS4, false for FTS3 *\/$/;" m struct:Fts3Table file: +bFullMutex testdocs/sqlite3.c /^ int bFullMutex; \/* True to enable full mutexing *\/$/;" m struct:Sqlite3Config file: +bGlobal testdocs/sqlite3.c /^ int bGlobal; \/* Set if global data is loaded *\/$/;" m struct:MatchinfoBuffer file: +bHasDocsize testdocs/sqlite3.c /^ u8 bHasDocsize; \/* True if %_docsize table exists *\/$/;" m struct:Fts3Table file: +bHasStat testdocs/sqlite3.c /^ u8 bHasStat; \/* True if %_stat table exists (2==unknown) *\/$/;" m struct:Fts3Table file: +bIgnore testdocs/sqlite3.c /^ int bIgnore;$/;" m struct:TokenDoclist file: +bIgnoreSavepoint testdocs/sqlite3.c /^ u8 bIgnoreSavepoint; \/* True to ignore xSavepoint invocations *\/$/;" m struct:Fts3Table file: +bIncr testdocs/sqlite3.c /^ int bIncr; \/* True if doclist is loaded incrementally *\/$/;" m struct:Fts3Phrase file: +bIndirect testdocs/sqlite3.c /^ int bIndirect; \/* True if all changes are indirect *\/$/;" m struct:sqlite3_session file: +bIndirect testdocs/sqlite3.c /^ int bIndirect; \/* True if current change was indirect *\/$/;" m struct:sqlite3_changeset_iter file: +bIndirect testdocs/sqlite3.c /^ int bIndirect; \/* True if this change is "indirect" *\/$/;" m struct:SessionChange file: +bIsReader testdocs/sqlite3.c /^ bft bIsReader:1; \/* True for statements that read *\/$/;" m struct:Vdbe file: +bLine testdocs/sqlite3.c /^ u8 bLine[100]; \/* Draw vertical in column i if bLine[i] is true *\/$/;" m struct:TreeView file: +bLocaltimeFault testdocs/sqlite3.c /^ int bLocaltimeFault; \/* True to fail localtime() calls *\/$/;" m struct:Sqlite3Config file: +bLookup testdocs/sqlite3.c /^ int bLookup; \/* True if a lookup of a single entry. *\/$/;" m struct:Fts3MultiSegReader file: +bLookup testdocs/sqlite3.c /^ u8 bLookup; \/* True for a lookup only *\/$/;" m struct:Fts3SegReader file: +bMalloced testdocs/sqlite3.c /^ u8 bMalloced; \/* True if pStart obtained from sqlite3_malloc() *\/$/;" m struct:Lookaside file: +bMemstat testdocs/sqlite3.c /^ int bMemstat; \/* True to enable memory status *\/$/;" m struct:Sqlite3Config file: +bMiss testdocs/sqlite3.c /^ int bMiss;$/;" m struct:Fts5PoslistPopulator file: +bNoDiscard testdocs/sqlite3.c /^ int bNoDiscard; \/* If true, discard no data *\/$/;" m struct:SessionInput file: +bNoIncrDoclist testdocs/sqlite3.c /^ int bNoIncrDoclist;$/;" m struct:Fts3Table file: +bNoLeafData testdocs/sqlite3.c /^ u8 bNoLeafData; \/* If true, store 0 for segment size *\/$/;" m struct:IncrmergeWriter file: +bNoLock testdocs/sqlite3.c /^ BOOL bNoLock; \/* Non-zero if locking is disabled. *\/$/;" m struct:winVfsAppData file: +bNolock testdocs/sqlite3.c /^ u8 bNolock; \/* True to fail EXCLUSIVE locks *\/$/;" m struct:rbu_file file: +bNomatch testdocs/sqlite3.c /^ int bNomatch; \/* True if entry is not a match *\/$/;" m struct:Fts5ExprNode file: +bOk testdocs/sqlite3.c /^ int bOk; \/* True if ok to populate *\/$/;" m struct:Fts5PoslistPopulator file: +bOpenUri testdocs/sqlite3.c /^ int bOpenUri; \/* True to interpret filenames as URIs *\/$/;" m struct:Sqlite3Config file: +bOrderedInnerLoop testdocs/sqlite3.c /^ u8 bOrderedInnerLoop; \/* True if only the inner-most loop is ordered *\/$/;" m struct:WhereInfo file: +bOrderedInnerLoop testdocs/sqlite3.c /^ u8 bOrderedInnerLoop; \/* ORDER BY correctly sorts the inner loop *\/$/;" m struct:SortCtx file: +bOwned testdocs/sqlite3.c /^ BOOL bOwned; \/* Do we own the heap (i.e. destroy it on shutdown)? *\/$/;" m struct:winMemData file: +bPatch testdocs/sqlite3.c /^ int bPatch; \/* True to accumulate patchsets *\/$/;" m struct:sqlite3_changegroup file: +bPatchset testdocs/sqlite3.c /^ int bPatchset; \/* True if this is a patchset *\/$/;" m struct:sqlite3_changeset_iter file: +bPending testdocs/sqlite3.c /^ BOOL bPending; \/* Indicates a pending lock has been obtained *\/$/;" m struct:winceLock file: +bPoint testdocs/sqlite3.c /^ u8 bPoint; \/* True if sPoint is valid *\/$/;" m struct:RtreeCursor file: +bPrefix testdocs/sqlite3.c /^ int bPrefix; \/* True for a prefix term *\/$/;" m struct:Fts5ExprTerm file: +bPrefixIndex testdocs/sqlite3.c /^ int bPrefixIndex; \/* True to use prefix-indexes *\/$/;" m struct:Fts5Config file: +bPrevDelete testdocs/sqlite3.c /^ int bPrevDelete; \/* True if last operation was a delete *\/$/;" m struct:Fts3Table file: +bPrevValid testdocs/sqlite3.c /^ int bPrevValid; \/* True if iPrev is valid *\/$/;" m struct:Fts5DlidxWriter file: +bProcessLock testdocs/sqlite3.c /^ unsigned char bProcessLock; \/* An exclusive process lock is held *\/$/;" m struct:unixInodeInfo file: +bPurgeable testdocs/sqlite3.c /^ int bPurgeable; \/* True if cache is purgeable *\/$/;" m struct:PCache1 file: +bPurgeable testdocs/sqlite3.c /^ u8 bPurgeable; \/* True if pages are on backing store *\/$/;" m struct:PCache file: +bRecursive testdocs/sqlite3.c /^ u8 bRecursive; \/* True for json_tree(). False for json_each() *\/$/;" m struct:JsonEachCursor file: +bRemoveDiacritic testdocs/sqlite3.c /^ int bRemoveDiacritic; \/* True if remove_diacritics=1 is set *\/$/;" m struct:Unicode61Tokenizer file: +bRemoveDiacritic testdocs/sqlite3.c /^ int bRemoveDiacritic;$/;" m struct:unicode_tokenizer file: +bReserved testdocs/sqlite3.c /^ BOOL bReserved; \/* Indicates a reserved lock has been obtained *\/$/;" m struct:winceLock file: +bRestart testdocs/sqlite3.c /^ int bRestart;$/;" m struct:Fts3MultiSegReader file: +bRev testdocs/sqlite3.c /^ int bRev; \/* True to iterate in reverse order *\/$/;" m struct:Fts5Iter file: +bSeekStmt testdocs/sqlite3.c /^ u8 bSeekStmt; \/* True if pStmt is a seek *\/$/;" m struct:Fts3Cursor file: +bSkipEmpty testdocs/sqlite3.c /^ u8 bSkipEmpty; \/* True to skip deleted entries *\/$/;" m struct:Fts5Iter file: +bSpanIsTab testdocs/sqlite3.c /^ unsigned bSpanIsTab :1; \/* zSpan holds DB.TABLE.COLUMN *\/$/;" m struct:ExprList::ExprList_item file: +bStart testdocs/sqlite3.c /^ u8 bStart; \/* True if iDocid is valid *\/$/;" m struct:Fts3Expr file: +bStatic testdocs/sqlite3.c /^ u8 bStatic; \/* True if zBuf is static space *\/$/;" m struct:JsonString file: +bSyncSet testdocs/sqlite3.c /^ u8 bSyncSet; \/* True if "PRAGMA synchronous=N" has been run *\/$/;" m struct:Db file: +bTermEq testdocs/sqlite3.c /^ u8 bTermEq; \/* True if the terms are equal *\/$/;" m struct:Fts5CResult file: +bTotalsValid testdocs/sqlite3.c /^ int bTotalsValid; \/* True if nTotalRow\/aTotalSize[] are valid *\/$/;" m struct:Fts5Storage file: +bUnderPressure testdocs/sqlite3.c /^ int bUnderPressure; \/* True if low on PAGECACHE memory *\/$/;" m struct:PCacheGlobal file: +bUnique testdocs/sqlite3.c /^ int bUnique; \/* Current index is unique *\/$/;" m struct:RbuObjIter file: +bUnordered testdocs/sqlite3.c /^ unsigned bUnordered:1; \/* Use this index for == or IN queries only *\/$/;" m struct:Index file: +bUseCis testdocs/sqlite3.c /^ int bUseCis; \/* Use covering indices for full-scans *\/$/;" m struct:Sqlite3Config file: +bUseFetch testdocs/sqlite3.c /^ u8 bUseFetch; \/* True to use xFetch() *\/$/;" m struct:Pager file: +bUsePMA testdocs/sqlite3.c /^ u8 bUsePMA; \/* True if one or more PMAs created *\/$/;" m struct:VdbeSorter file: +bUseThread testdocs/sqlite3.c /^ int bUseThread; \/* True to use a bg thread for this object *\/$/;" m struct:IncrMerger file: +bUseThreads testdocs/sqlite3.c /^ u8 bUseThreads; \/* True to use background threads *\/$/;" m struct:VdbeSorter file: +bVarOnly testdocs/sqlite3.c /^ int bVarOnly; \/* Check for variable references only *\/$/;" m struct:DbFixer file: +backtrace testdocs/sqlite3.c /^# define backtrace(/;" d file: +backtrace_symbols_fd testdocs/sqlite3.c /^# define backtrace_symbols_fd(/;" d file: +backupOnePage testdocs/sqlite3.c /^static int backupOnePage($/;" f file: +backupTruncateFile testdocs/sqlite3.c /^static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){$/;" f file: +backupUpdate testdocs/sqlite3.c /^static SQLITE_NOINLINE void backupUpdate($/;" f file: +backup_finish testdocs/sqlite3.c /^ int (*backup_finish)(sqlite3_backup*);$/;" m struct:sqlite3_api_routines file: +backup_init testdocs/sqlite3.c /^ sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);$/;" m struct:sqlite3_api_routines file: +backup_pagecount testdocs/sqlite3.c /^ int (*backup_pagecount)(sqlite3_backup*);$/;" m struct:sqlite3_api_routines file: +backup_remaining testdocs/sqlite3.c /^ int (*backup_remaining)(sqlite3_backup*);$/;" m struct:sqlite3_api_routines file: +backup_step testdocs/sqlite3.c /^ int (*backup_step)(sqlite3_backup*,int);$/;" m struct:sqlite3_api_routines file: +balance testdocs/sqlite3.c /^static int balance(BtCursor *pCur){$/;" f file: +balance_deeper testdocs/sqlite3.c /^static int balance_deeper(MemPage *pRoot, MemPage **ppChild){$/;" f file: +balance_nonroot testdocs/sqlite3.c /^static int balance_nonroot($/;" f file: +balance_quick testdocs/sqlite3.c /^static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){$/;" f file: +base testdocs/sqlite3.c /^ Fts5IndexIter base; \/* Base class containing output vars *\/$/;" m struct:Fts5Iter file: +base testdocs/sqlite3.c /^ etByte base; \/* The base for radix conversion *\/$/;" m struct:et_info file: +base testdocs/sqlite3.c /^ sqlite3_file base; \/* sqlite3_file methods *\/$/;" m struct:rbu_file file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer base; \/* Base class *\/$/;" m struct:porter_tokenizer file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer base;$/;" m struct:IcuTokenizer file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer base;$/;" m struct:simple_tokenizer file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer base;$/;" m struct:unicode_tokenizer file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer_cursor base;$/;" m struct:IcuCursor file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer_cursor base;$/;" m struct:porter_tokenizer_cursor file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer_cursor base;$/;" m struct:simple_tokenizer_cursor file: +base testdocs/sqlite3.c /^ sqlite3_tokenizer_cursor base;$/;" m struct:unicode_cursor file: +base testdocs/sqlite3.c /^ sqlite3_vfs base; \/* rbu VFS shim methods *\/$/;" m struct:rbu_vfs file: +base testdocs/sqlite3.c /^ sqlite3_vtab base; \/* Base class used by SQLite core *\/$/;" m struct:Fts3Table file: +base testdocs/sqlite3.c /^ sqlite3_vtab base; \/* Base class used by SQLite core *\/$/;" m struct:Fts3auxTable file: +base testdocs/sqlite3.c /^ sqlite3_vtab base; \/* Base class used by SQLite core *\/$/;" m struct:Fts3tokTable file: +base testdocs/sqlite3.c /^ sqlite3_vtab base; \/* Base class used by SQLite core *\/$/;" m struct:Fts5Table file: +base testdocs/sqlite3.c /^ sqlite3_vtab base; \/* Base class. Must be first *\/$/;" m struct:Rtree file: +base testdocs/sqlite3.c /^ sqlite3_vtab base; \/* Base class. Must be first *\/$/;" m struct:PragmaVtab file: +base testdocs/sqlite3.c /^ sqlite3_vtab base;$/;" m struct:Fts5VocabTable file: +base testdocs/sqlite3.c /^ sqlite3_vtab base;$/;" m struct:StatTable file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base; \/* Base class. Must be first *\/$/;" m struct:RtreeCursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base; \/* Base class used by SQLite core *\/$/;" m struct:Fts3Cursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base; \/* Base class used by SQLite core *\/$/;" m struct:Fts3auxCursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base; \/* Base class used by SQLite core *\/$/;" m struct:Fts3tokCursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base; \/* Base class used by SQLite core *\/$/;" m struct:Fts5Cursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base; \/* Base class - must be first *\/$/;" m struct:JsonEachCursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base; \/* Base class. Must be first *\/$/;" m struct:PragmaVtabCursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base;$/;" m struct:Fts5VocabCursor file: +base testdocs/sqlite3.c /^ sqlite3_vtab_cursor base;$/;" m struct:StatCursor file: +beg edit.h /^ size_t beg; \/* offset in the file where insertion started *\/$/;" m struct:Log::__anon2::__anon3 +beg edit.h /^ size_t beg;$/;" m struct:__anon6 +bft testdocs/sqlite3.c /^typedef unsigned bft; \/* Bit Field Type *\/$/;" t file: +bigEndCksum testdocs/sqlite3.c /^ u8 bigEndCksum; \/* True if checksums in WAL are big-endian *\/$/;" m struct:WalIndexHdr file: +binCollFunc testdocs/sqlite3.c /^static int binCollFunc($/;" f file: +binaryCompareP5 testdocs/sqlite3.c /^static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){$/;" f file: +binaryToUnaryIfNull testdocs/sqlite3.c /^ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){$/;" f file: +bindText testdocs/sqlite3.c /^static int bindText($/;" f file: +bind_blob testdocs/sqlite3.c /^ int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +bind_blob64 testdocs/sqlite3.c /^ int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,$/;" m struct:sqlite3_api_routines file: +bind_double testdocs/sqlite3.c /^ int (*bind_double)(sqlite3_stmt*,int,double);$/;" m struct:sqlite3_api_routines file: +bind_int testdocs/sqlite3.c /^ int (*bind_int)(sqlite3_stmt*,int,int);$/;" m struct:sqlite3_api_routines file: +bind_int64 testdocs/sqlite3.c /^ int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);$/;" m struct:sqlite3_api_routines file: +bind_null testdocs/sqlite3.c /^ int (*bind_null)(sqlite3_stmt*,int);$/;" m struct:sqlite3_api_routines file: +bind_parameter_count testdocs/sqlite3.c /^ int (*bind_parameter_count)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +bind_parameter_index testdocs/sqlite3.c /^ int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);$/;" m struct:sqlite3_api_routines file: +bind_parameter_name testdocs/sqlite3.c /^ const char * (*bind_parameter_name)(sqlite3_stmt*,int);$/;" m struct:sqlite3_api_routines file: +bind_text testdocs/sqlite3.c /^ int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +bind_text16 testdocs/sqlite3.c /^ int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +bind_text64 testdocs/sqlite3.c /^ int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,$/;" m struct:sqlite3_api_routines file: +bind_value testdocs/sqlite3.c /^ int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +bind_zeroblob testdocs/sqlite3.c /^ int (*bind_zeroblob)(sqlite3_stmt*,int,int);$/;" m struct:sqlite3_api_routines file: +bind_zeroblob64 testdocs/sqlite3.c /^ int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);$/;" m struct:sqlite3_api_routines file: +bldFlags testdocs/sqlite3.c /^ unsigned int bldFlags; \/* SQLITE_BLDF_* flags *\/$/;" m struct:WhereLoopBuilder file: +blobGrowBuffer testdocs/sqlite3.c /^static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){$/;" f file: +blobReadWrite testdocs/sqlite3.c /^static int blobReadWrite($/;" f file: +blobSeekToRow testdocs/sqlite3.c /^static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){$/;" f file: +blob_bytes testdocs/sqlite3.c /^ int (*blob_bytes)(sqlite3_blob*);$/;" m struct:sqlite3_api_routines file: +blob_close testdocs/sqlite3.c /^ int (*blob_close)(sqlite3_blob*);$/;" m struct:sqlite3_api_routines file: +blob_open testdocs/sqlite3.c /^ int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,$/;" m struct:sqlite3_api_routines file: +blob_read testdocs/sqlite3.c /^ int (*blob_read)(sqlite3_blob*,void*,int,int);$/;" m struct:sqlite3_api_routines file: +blob_reopen testdocs/sqlite3.c /^ int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);$/;" m struct:sqlite3_api_routines file: +blob_write testdocs/sqlite3.c /^ int (*blob_write)(sqlite3_blob*,const void*,int,int);$/;" m struct:sqlite3_api_routines file: +block testdocs/sqlite3.c /^ Blob block; \/* Current block image *\/$/;" m struct:NodeWriter file: +btree testdocs/sqlite3.c /^ } btree;$/;" m union:WhereLoop::__anon29 typeref:struct:WhereLoop::__anon29::__anon30 file: +btreeClearHasContent testdocs/sqlite3.c /^static void btreeClearHasContent(BtShared *pBt){$/;" f file: +btreeCreateTable testdocs/sqlite3.c /^static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){$/;" f file: +btreeCursor testdocs/sqlite3.c /^static int btreeCursor($/;" f file: +btreeDropTable testdocs/sqlite3.c /^static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){$/;" f file: +btreeEndTransaction testdocs/sqlite3.c /^static void btreeEndTransaction(Btree *p){$/;" f file: +btreeEnterAll testdocs/sqlite3.c /^static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){$/;" f file: +btreeGetHasContent testdocs/sqlite3.c /^static int btreeGetHasContent(BtShared *pBt, Pgno pgno){$/;" f file: +btreeGetPage testdocs/sqlite3.c /^static int btreeGetPage($/;" f file: +btreeGetUnusedPage testdocs/sqlite3.c /^static int btreeGetUnusedPage($/;" f file: +btreeHeapInsert testdocs/sqlite3.c /^static void btreeHeapInsert(u32 *aHeap, u32 x){$/;" f file: +btreeHeapPull testdocs/sqlite3.c /^static int btreeHeapPull(u32 *aHeap, u32 *pOut){$/;" f file: +btreeInitPage testdocs/sqlite3.c /^static int btreeInitPage(MemPage *pPage){$/;" f file: +btreeIntegrity testdocs/sqlite3.c /^#define btreeIntegrity(/;" d file: +btreeInvokeBusyHandler testdocs/sqlite3.c /^static int btreeInvokeBusyHandler(void *pArg){$/;" f file: +btreeLeaveAll testdocs/sqlite3.c /^static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){$/;" f file: +btreeLockCarefully testdocs/sqlite3.c /^static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){$/;" f file: +btreeMask testdocs/sqlite3.c /^ yDbMask btreeMask; \/* Bitmask of db->aDb[] entries referenced *\/$/;" m struct:Vdbe file: +btreeMoveto testdocs/sqlite3.c /^static int btreeMoveto($/;" f file: +btreeNext testdocs/sqlite3.c /^static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){$/;" f file: +btreePageFromDbPage testdocs/sqlite3.c /^static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){$/;" f file: +btreePageLookup testdocs/sqlite3.c /^static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){$/;" f file: +btreePagecount testdocs/sqlite3.c /^static Pgno btreePagecount(BtShared *pBt){$/;" f file: +btreeParseCell testdocs/sqlite3.c /^static void btreeParseCell($/;" f file: +btreeParseCellAdjustSizeForOverflow testdocs/sqlite3.c /^static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow($/;" f file: +btreeParseCellPtr testdocs/sqlite3.c /^static void btreeParseCellPtr($/;" f file: +btreeParseCellPtrIndex testdocs/sqlite3.c /^static void btreeParseCellPtrIndex($/;" f file: +btreeParseCellPtrNoPayload testdocs/sqlite3.c /^static void btreeParseCellPtrNoPayload($/;" f file: +btreePrevious testdocs/sqlite3.c /^static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){$/;" f file: +btreeReleaseAllCursorPages testdocs/sqlite3.c /^static void btreeReleaseAllCursorPages(BtCursor *pCur){$/;" f file: +btreeRestoreCursorPosition testdocs/sqlite3.c /^static int btreeRestoreCursorPosition(BtCursor *pCur){$/;" f file: +btreeSetHasContent testdocs/sqlite3.c /^static int btreeSetHasContent(BtShared *pBt, Pgno pgno){$/;" f file: +btsFlags testdocs/sqlite3.c /^ u16 btsFlags; \/* Boolean parameters. See BTS_* macros below *\/$/;" m struct:BtShared file: +btterm testdocs/sqlite3.c /^ Fts5Buffer btterm; \/* Next term to insert into %_idx table *\/$/;" m struct:Fts5SegWriter file: +buf edit.h /^ uint8_t* buf; \/* memory mapped byte buffer *\/$/;" m struct:__anon1 +buf testdocs/sqlite3.c /^ Fts5Buffer buf; \/* Buffer containing leaf data *\/$/;" m struct:Fts5PageWriter file: +buf testdocs/sqlite3.c /^ Fts5Buffer buf; \/* Buffer containing page data *\/$/;" m struct:Fts5DlidxWriter file: +buf testdocs/sqlite3.c /^ SessionBuffer buf; \/* Current read buffer *\/$/;" m struct:SessionInput file: +buf_bol buf.c /^size_t buf_bol(Buf* buf, size_t off) {$/;" f +buf_bow buf.c /^size_t buf_bow(Buf* buf, size_t off) {$/;" f +buf_byline buf.c /^size_t buf_byline(Buf* buf, size_t pos, int count) {$/;" f +buf_byrune buf.c /^size_t buf_byrune(Buf* buf, size_t pos, int count) {$/;" f +buf_byword buf.c /^size_t buf_byword(Buf* buf, size_t off, int count) {$/;" f +buf_change buf.c /^size_t buf_change(Buf* buf, size_t beg, size_t end) {$/;" f +buf_chomp buf.c /^void buf_chomp(Buf* buf) {$/;" f +buf_delete buf.c /^size_t buf_delete(Buf* buf, size_t beg, size_t end) {$/;" f +buf_end buf.c /^size_t buf_end(Buf* buf) {$/;" f +buf_eol buf.c /^size_t buf_eol(Buf* buf, size_t off) {$/;" f +buf_eow buf.c /^size_t buf_eow(Buf* buf, size_t off) {$/;" f +buf_findstr buf.c /^void buf_findstr(Buf* buf, int dir, char* str, size_t* beg, size_t* end) {$/;" f +buf_get buf.c /^Rune buf_get(Buf* buf, size_t off) {$/;" f +buf_getblock buf.c /^void buf_getblock(Buf* buf, Rune first, Rune last, Sel* sel) {$/;" f +buf_getcol buf.c /^size_t buf_getcol(Buf* buf, size_t pos) {$/;" f +buf_getln buf.c /^size_t buf_getln(Buf* buf, size_t off) {$/;" f +buf_getword buf.c /^void buf_getword(Buf* buf, bool (*isword)(Rune), Sel* sel) {$/;" f +buf_init buf.c /^void buf_init(Buf* buf, void (*errfn)(char*)) {$/;" f +buf_insert buf.c /^size_t buf_insert(Buf* buf, bool fmt, size_t off, Rune rune) {$/;" f +buf_iseol buf.c /^bool buf_iseol(Buf* buf, size_t off) {$/;" f +buf_lastins buf.c /^void buf_lastins(Buf* buf, size_t* beg, size_t* end) {$/;" f +buf_load buf.c /^size_t buf_load(Buf* buf, char* path) {$/;" f +buf_logclear buf.c /^void buf_logclear(Buf* buf) {$/;" f +buf_loglock buf.c /^void buf_loglock(Buf* buf) {$/;" f +buf_lscan buf.c /^size_t buf_lscan(Buf* buf, size_t pos, Rune r) {$/;" f +buf_redo buf.c /^void buf_redo(Buf* buf, Sel* sel) {$/;" f +buf_reload buf.c /^void buf_reload(Buf* buf) {$/;" f +buf_resize buf.c /^static void buf_resize(Buf* buf, size_t sz) {$/;" f file: +buf_rscan buf.c /^size_t buf_rscan(Buf* buf, size_t pos, Rune r) {$/;" f +buf_save buf.c /^void buf_save(Buf* buf) {$/;" f +buf_setcol buf.c /^size_t buf_setcol(Buf* buf, size_t pos, size_t col) {$/;" f +buf_setln buf.c /^size_t buf_setln(Buf* buf, size_t line) {$/;" f +buf_text_eq testbuf.c /^static bool buf_text_eq(char* str) {$/;" f file: +buf_undo buf.c /^void buf_undo(Buf* buf, Sel* sel) {$/;" f +bufend edit.h /^ Rune* bufend; \/* end of the data buffer *\/$/;" m struct:__anon5 +bufsize edit.h /^ size_t bufsize; \/* size of the buffer in runes *\/$/;" m struct:__anon5 +bufstart edit.h /^ Rune* bufstart; \/* start of the data buffer *\/$/;" m struct:__anon5 +busy testdocs/sqlite3.c /^ u8 busy; \/* TRUE if currently initializing *\/$/;" m struct:sqlite3::sqlite3InitInfo file: +busyHandler testdocs/sqlite3.c /^ BusyHandler busyHandler; \/* Busy callback *\/$/;" m struct:sqlite3 file: +busyTimeout testdocs/sqlite3.c /^ int busyTimeout; \/* Busy handler timeout, in msec *\/$/;" m struct:sqlite3 file: +busy_handler testdocs/sqlite3.c /^ int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);$/;" m struct:sqlite3_api_routines file: +busy_timeout testdocs/sqlite3.c /^ int (*busy_timeout)(sqlite3*,int ms);$/;" m struct:sqlite3_api_routines file: +cId testdocs/sqlite3.c /^ char cId; \/* Symbolic ID of this loop for debugging use *\/$/;" m struct:WhereLoop file: +cType testdocs/sqlite3.c /^static const char cType[] = {$/;" v file: +cacheCtr testdocs/sqlite3.c /^ u32 cacheCtr; \/* VdbeCursor row cache generation counter *\/$/;" m struct:Vdbe file: +cacheEntryClear testdocs/sqlite3.c /^static void cacheEntryClear(Parse *pParse, int i){$/;" f file: +cacheStatus testdocs/sqlite3.c /^ u32 cacheStatus; \/* Cache is valid if this matches Vdbe.cacheCtr *\/$/;" m struct:VdbeCursor file: +cache_size testdocs/sqlite3.c /^ int cache_size; \/* Number of pages to use in the cache *\/$/;" m struct:Schema file: +cachedCellSize testdocs/sqlite3.c /^static u16 cachedCellSize(CellArray *p, int N){$/;" f file: +callCollNeeded testdocs/sqlite3.c /^static void callCollNeeded(sqlite3 *db, int enc, const char *zName){$/;" f file: +callFinaliser testdocs/sqlite3.c /^static void callFinaliser(sqlite3 *db, int offset){$/;" f file: +callStatGet testdocs/sqlite3.c /^static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){$/;" f file: +cancel_auto_extension testdocs/sqlite3.c /^ int (*cancel_auto_extension)(void(*)(void));$/;" m struct:sqlite3_api_routines file: +cannotBeFunction testdocs/sqlite3.c /^static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){$/;" f file: +cb testdocs/sqlite3.c /^ RtreeGeomCallback cb; \/* Info about the callback functions *\/$/;" m struct:RtreeMatchArg file: +cdateFunc testdocs/sqlite3.c /^static void cdateFunc($/;" f file: +cellArea testdocs/sqlite3.c /^static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){$/;" f file: +cellContains testdocs/sqlite3.c /^static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){$/;" f file: +cellGrowth testdocs/sqlite3.c /^static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){$/;" f file: +cellMargin testdocs/sqlite3.c /^static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){$/;" f file: +cellOffset testdocs/sqlite3.c /^ u16 cellOffset; \/* Index in aData of first cell pointer *\/$/;" m struct:MemPage file: +cellOverlap testdocs/sqlite3.c /^static RtreeDValue cellOverlap($/;" f file: +cellSize testdocs/sqlite3.c /^static u16 cellSize(MemPage *pPage, int iCell){$/;" f file: +cellSizePtr testdocs/sqlite3.c /^static u16 cellSizePtr(MemPage *pPage, u8 *pCell){$/;" f file: +cellSizePtrNoPayload testdocs/sqlite3.c /^static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){$/;" f file: +cellUnion testdocs/sqlite3.c /^static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){$/;" f file: +chain testdocs/sqlite3.c /^ Fts3HashElem *chain; \/* Pointer to first entry with this hash *\/$/;" m struct:Fts3Hash::_fts3ht file: +chain testdocs/sqlite3.c /^ HashElem *chain; \/* Pointer to first entry with this hash *\/$/;" m struct:Hash::_ht file: +changeCntOn testdocs/sqlite3.c /^ bft changeCntOn:1; \/* True to update the change-counter *\/$/;" m struct:Vdbe file: +changeCountDone testdocs/sqlite3.c /^ u8 changeCountDone; \/* Set after incrementing the change-counter *\/$/;" m struct:Pager file: +changeTempStorage testdocs/sqlite3.c /^static int changeTempStorage(Parse *pParse, const char *zStorageType){$/;" f file: +changes testdocs/sqlite3.c /^ int (*changes)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +changes testdocs/sqlite3.c /^static void changes($/;" f file: +charFunc testdocs/sqlite3.c /^static void charFunc($/;" f file: +charMap testdocs/sqlite3.c /^# define charMap(/;" d file: +charset testdocs/sqlite3.c /^ etByte charset; \/* Offset into aDigits[] of the digits string *\/$/;" m struct:et_info file: +charstorunes buf.c /^Rune* charstorunes(char* str) {$/;" f +check stdc.h /^#define check(/;" d +checkActiveVdbeCnt testdocs/sqlite3.c /^#define checkActiveVdbeCnt(/;" d file: +checkActiveVdbeCnt testdocs/sqlite3.c /^static void checkActiveVdbeCnt(sqlite3 *db){$/;" f file: +checkAppendMsg testdocs/sqlite3.c /^static void checkAppendMsg($/;" f file: +checkColumnOverlap testdocs/sqlite3.c /^static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){$/;" f file: +checkConstraintExprNode testdocs/sqlite3.c /^static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){$/;" f file: +checkConstraintUnchanged testdocs/sqlite3.c /^static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){$/;" f file: +checkList testdocs/sqlite3.c /^static void checkList($/;" f file: +checkListProperties testdocs/sqlite3.c /^# define checkListProperties(/;" d file: +checkListProperties testdocs/sqlite3.c /^static void checkListProperties(sqlite3 *db){$/;" f file: +checkPage testdocs/sqlite3.c /^static void checkPage(PgHdr *pPg){$/;" f file: +checkProfileCallback testdocs/sqlite3.c /^# define checkProfileCallback(/;" d file: +checkPtrmap testdocs/sqlite3.c /^static void checkPtrmap($/;" f file: +checkReadTransaction testdocs/sqlite3.c /^static int checkReadTransaction(sqlite3 *db, Btree *p){$/;" f file: +checkRef testdocs/sqlite3.c /^static int checkRef(IntegrityCk *pCheck, Pgno iPage){$/;" f file: +checkSavepointCount testdocs/sqlite3.c /^static int checkSavepointCount(sqlite3 *db){$/;" f file: +checkSchema testdocs/sqlite3.c /^ u8 checkSchema; \/* Causes schema cookie check after an error *\/$/;" m struct:Parse file: +checkTreePage testdocs/sqlite3.c /^static int checkTreePage($/;" f file: +childPtrSize testdocs/sqlite3.c /^ u8 childPtrSize; \/* 0 if leaf==1. 4 if leaf==0 *\/$/;" m struct:MemPage file: +ckBase testdocs/sqlite3.c /^ int ckBase; \/* Base register of data during check constraints *\/$/;" m struct:Parse file: +ckptLock testdocs/sqlite3.c /^ u8 ckptLock; \/* True if holding a checkpoint lock *\/$/;" m struct:Wal file: +ckptSyncFlags testdocs/sqlite3.c /^ u8 ckptSyncFlags; \/* SYNC_NORMAL or SYNC_FULL for checkpoint *\/$/;" m struct:Pager file: +cksum testdocs/sqlite3.c /^ u64 cksum;$/;" m struct:Fts5IntegrityCtx file: +cksumInit testdocs/sqlite3.c /^ u32 cksumInit; \/* Quasi-random value added to every checksum *\/$/;" m struct:Pager file: +clearAllSharedCacheTableLocks testdocs/sqlite3.c /^ #define clearAllSharedCacheTableLocks(/;" d file: +clearAllSharedCacheTableLocks testdocs/sqlite3.c /^static void clearAllSharedCacheTableLocks(Btree *p){$/;" f file: +clearCell testdocs/sqlite3.c /^static int clearCell($/;" f file: +clearDatabasePage testdocs/sqlite3.c /^static int clearDatabasePage($/;" f file: +clearSelect testdocs/sqlite3.c /^static void clearSelect(sqlite3 *db, Select *p, int bFree){$/;" f file: +clearYMD_HMS_TZ testdocs/sqlite3.c /^static void clearYMD_HMS_TZ(DateTime *p){$/;" f file: +clear_bindings testdocs/sqlite3.c /^ int (*clear_bindings)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +close testdocs/sqlite3.c /^ int (*close)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +closeAllCursors testdocs/sqlite3.c /^static void closeAllCursors(Vdbe *p){$/;" f file: +closeCursorsInFrame testdocs/sqlite3.c /^static void closeCursorsInFrame(Vdbe *p){$/;" f file: +closePendingFds testdocs/sqlite3.c /^static void closePendingFds(unixFile *pFile){$/;" f file: +closeUnixFile testdocs/sqlite3.c /^static int closeUnixFile(sqlite3_file *id){$/;" f file: +close_v2 testdocs/sqlite3.c /^ int (*close_v2)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +cnt testdocs/sqlite3.c /^ i64 cnt; \/* Number of elements summed *\/$/;" m struct:SumCtx file: +cnt testdocs/sqlite3.c /^ int cnt; \/* Number of entries without a matching leave *\/$/;" m struct:sqlite3_debug_mutex file: +cnt testdocs/sqlite3.c /^ u32 cnt; \/* Number of times this instruction was executed *\/$/;" m struct:VdbeOp file: +codeAllEqualityTerms testdocs/sqlite3.c /^static int codeAllEqualityTerms($/;" f file: +codeApplyAffinity testdocs/sqlite3.c /^static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){$/;" f file: +codeAttach testdocs/sqlite3.c /^static void codeAttach($/;" f file: +codeCompare testdocs/sqlite3.c /^static int codeCompare($/;" f file: +codeCursorHint testdocs/sqlite3.c /^# define codeCursorHint(/;" d file: +codeCursorHint testdocs/sqlite3.c /^static void codeCursorHint($/;" f file: +codeCursorHintCheckExpr testdocs/sqlite3.c /^static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){$/;" f file: +codeCursorHintFixExpr testdocs/sqlite3.c /^static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){$/;" f file: +codeCursorHintIsOrFunction testdocs/sqlite3.c /^static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){$/;" f file: +codeDeferredSeek testdocs/sqlite3.c /^static void codeDeferredSeek($/;" f file: +codeDistinct testdocs/sqlite3.c /^static void codeDistinct($/;" f file: +codeEqualityTerm testdocs/sqlite3.c /^static int codeEqualityTerm($/;" f file: +codeExprOrVector testdocs/sqlite3.c /^static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){$/;" f file: +codeInteger testdocs/sqlite3.c /^static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){$/;" f file: +codeOffset testdocs/sqlite3.c /^static void codeOffset($/;" f file: +codeReal testdocs/sqlite3.c /^static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){$/;" f file: +codeRowTrigger testdocs/sqlite3.c /^static TriggerPrg *codeRowTrigger($/;" f file: +codeTableLocks testdocs/sqlite3.c /^ #define codeTableLocks(/;" d file: +codeTableLocks testdocs/sqlite3.c /^static void codeTableLocks(Parse *pParse){$/;" f file: +codeTriggerProgram testdocs/sqlite3.c /^static int codeTriggerProgram($/;" f file: +codeVectorCompare testdocs/sqlite3.c /^static void codeVectorCompare($/;" f file: +col edit.h /^ size_t col;$/;" m struct:__anon6 +colFlags testdocs/sqlite3.c /^ u8 colFlags; \/* Boolean properties. See COLFLAG_ defines below *\/$/;" m struct:Column file: +colNamesSet testdocs/sqlite3.c /^ u8 colNamesSet; \/* TRUE after OP_ColumnName has been issued to pVdbe *\/$/;" m struct:Parse file: +colUsed testdocs/sqlite3.c /^ Bitmask colUsed; \/* Bit N (1<intKey *\/$/;" m struct:BtCursor file: +curPagerFlags testdocs/sqlite3.c /^ u8 curPagerFlags; \/* Flags to send to sqlite3PagerGet() *\/$/;" m struct:BtCursor file: +current testdocs/sqlite3.c /^ Stat4Sample current; \/* Current row as a Stat4Sample *\/$/;" m struct:Stat4Accum file: +currentCount testdocs/sqlite3.c /^ u32 currentCount; \/* Current number of distinct checkouts *\/$/;" m struct:Mem5Global file: +currentOut testdocs/sqlite3.c /^ u32 currentOut; \/* Current checkout, including internal fragmentation *\/$/;" m struct:Mem5Global file: +currentTimeFunc testdocs/sqlite3.c /^static void currentTimeFunc($/;" f file: +cursorHoldsMutex testdocs/sqlite3.c /^static int cursorHoldsMutex(BtCursor *p){$/;" f file: +cursorOwnsBtShared testdocs/sqlite3.c /^static int cursorOwnsBtShared(BtCursor *p){$/;" f file: +cwd testdocs/waf /^cwd = os.getcwd()$/;" v +cycles testdocs/sqlite3.c /^ u64 cycles; \/* Total time spent executing this instruction *\/$/;" m struct:VdbeOp file: +data edit.h /^ } data;$/;" m struct:Log typeref:union:Log::__anon2 +data testdocs/sqlite3.c /^ void *data; \/* Data associated with this element *\/$/;" m struct:HashElem file: +data testdocs/sqlite3.c /^ void *data; \/* Data associated with this element *\/$/;" m struct:Fts3HashElem file: +data_count testdocs/sqlite3.c /^ int (*data_count)(sqlite3_stmt*pStmt);$/;" m struct:sqlite3_api_routines file: +databaseIsUnmoved testdocs/sqlite3.c /^static int databaseIsUnmoved(Pager *pPager){$/;" f file: +dateFunc testdocs/sqlite3.c /^static void dateFunc($/;" f file: +datetimeError testdocs/sqlite3.c /^static void datetimeError(DateTime *p){$/;" f file: +datetimeFunc testdocs/sqlite3.c /^static void datetimeFunc($/;" f file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Associated database connection *\/$/;" m struct:Fts5Global file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Database connection *\/$/;" m struct:VdbeSorter file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Database handle *\/$/;" m struct:Fts5Config file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Database handle *\/$/;" m struct:Fts5VocabTable file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Database handle session is attached to *\/$/;" m struct:sqlite3_session file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The database connection *\/$/;" m struct:Fts3Table file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The database connection *\/$/;" m struct:RowSet file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Host database connection *\/$/;" m struct:Rtree file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Database connection associated with this table *\/$/;" m struct:VTable file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Database connection, for malloc() *\/$/;" m struct:Stat4Accum file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The database connection to which it belongs *\/$/;" m struct:PragmaVtab file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The associated database *\/$/;" m struct:Incrblob file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The database connection that owns this statement *\/$/;" m struct:Vdbe file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Database connection currently using this Btree *\/$/;" m struct:BtShared file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* Optional database for lookaside. Can be NULL *\/$/;" m struct:StrAccum file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The main database structure *\/$/;" m struct:Parse file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The associated database connection *\/$/;" m struct:sqlite3_value file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The database being initialized *\/$/;" m struct:__anon16 file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The database connection *\/$/;" m struct:KeyInfo file: +db testdocs/sqlite3.c /^ sqlite3 *db; \/* The database connection holding this btree *\/$/;" m struct:Btree file: +db testdocs/sqlite3.c /^ sqlite3 *db;$/;" m struct:SessionApplyCtx file: +db testdocs/sqlite3.c /^ sqlite3 *db;$/;" m struct:StatTable file: +db testdocs/sqlite3.c /^ sqlite3 *db;$/;" m struct:analysisInfo file: +dbFileSize testdocs/sqlite3.c /^ Pgno dbFileSize; \/* Number of pages in the database file *\/$/;" m struct:Pager file: +dbFileVers testdocs/sqlite3.c /^ char dbFileVers[16]; \/* Changes whenever database file changes *\/$/;" m struct:Pager file: +dbHintSize testdocs/sqlite3.c /^ Pgno dbHintSize; \/* Value passed to FCNTL_SIZE_HINT call *\/$/;" m struct:Pager file: +dbMain testdocs/sqlite3.c /^ sqlite3 *dbMain; \/* target database handle *\/$/;" m struct:sqlite3rbu file: +dbMallocRawFinish testdocs/sqlite3.c /^static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){$/;" f file: +dbOptFlags testdocs/sqlite3.c /^ u16 dbOptFlags; \/* Flags to enable\/disable optimizations *\/$/;" m struct:sqlite3 file: +dbOrigSize testdocs/sqlite3.c /^ Pgno dbOrigSize; \/* dbSize before the current transaction *\/$/;" m struct:Pager file: +dbPath testdocs/sqlite3.c /^ char *dbPath; \/* Name of the open file *\/$/;" m struct:proxyLockingContext file: +dbPath testdocs/sqlite3.c /^ const char *dbPath; \/* Name of the open file *\/$/;" m struct:afpLockingContext file: +dbRbu testdocs/sqlite3.c /^ sqlite3 *dbRbu; \/* rbu database handle *\/$/;" m struct:sqlite3rbu file: +dbReallocFinish testdocs/sqlite3.c /^static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){$/;" f file: +dbSize testdocs/sqlite3.c /^ Pgno dbSize; \/* Number of pages in the database *\/$/;" m struct:Pager file: +dbUpdate testdocs/sqlite3.c /^ unsigned char dbUpdate; \/* True if any part of database file changed *\/$/;" m struct:unixFile file: +db_cacheflush testdocs/sqlite3.c /^ int (*db_cacheflush)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +db_config testdocs/sqlite3.c /^ int (*db_config)(sqlite3*,int,...);$/;" m struct:sqlite3_api_routines file: +db_filename testdocs/sqlite3.c /^ const char *(*db_filename)(sqlite3*,const char*);$/;" m struct:sqlite3_api_routines file: +db_handle testdocs/sqlite3.c /^ sqlite3 * (*db_handle)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +db_mutex testdocs/sqlite3.c /^ sqlite3_mutex *(*db_mutex)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +db_readonly testdocs/sqlite3.c /^ int (*db_readonly)(sqlite3*,const char*);$/;" m struct:sqlite3_api_routines file: +db_release_memory testdocs/sqlite3.c /^ int (*db_release_memory)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +db_status testdocs/sqlite3.c /^ int (*db_status)(sqlite3*,int,int*,int*,int);$/;" m struct:sqlite3_api_routines file: +debug stdc.h /^ #define debug(/;" d +debugMutexAlloc testdocs/sqlite3.c /^static sqlite3_mutex *debugMutexAlloc(int id){$/;" f file: +debugMutexEnd testdocs/sqlite3.c /^static int debugMutexEnd(void){ return SQLITE_OK; }$/;" f file: +debugMutexEnter testdocs/sqlite3.c /^static void debugMutexEnter(sqlite3_mutex *pX){$/;" f file: +debugMutexFree testdocs/sqlite3.c /^static void debugMutexFree(sqlite3_mutex *pX){$/;" f file: +debugMutexHeld testdocs/sqlite3.c /^static int debugMutexHeld(sqlite3_mutex *pX){$/;" f file: +debugMutexInit testdocs/sqlite3.c /^static int debugMutexInit(void){ return SQLITE_OK; }$/;" f file: +debugMutexLeave testdocs/sqlite3.c /^static void debugMutexLeave(sqlite3_mutex *pX){$/;" f file: +debugMutexNotheld testdocs/sqlite3.c /^static int debugMutexNotheld(sqlite3_mutex *pX){$/;" f file: +debugMutexTry testdocs/sqlite3.c /^static int debugMutexTry(sqlite3_mutex *pX){$/;" f file: +declareVtab testdocs/sqlite3.c /^ u8 declareVtab; \/* True if inside sqlite3_declare_vtab() *\/$/;" m struct:Parse file: +declare_vtab testdocs/sqlite3.c /^ int (*declare_vtab)(sqlite3*,const char*);$/;" m struct:sqlite3_api_routines file: +decodeFlags testdocs/sqlite3.c /^static int decodeFlags(MemPage *pPage, int flagByte){$/;" f file: +decodeIntArray testdocs/sqlite3.c /^static void decodeIntArray($/;" f file: +default_rc testdocs/sqlite3.c /^ i8 default_rc; \/* Comparison result if keys are equal *\/$/;" m struct:UnpackedRecord file: +deferredMoveto testdocs/sqlite3.c /^ u8 deferredMoveto; \/* A call to sqlite3BtreeMoveto() is needed *\/$/;" m struct:VdbeCursor file: +defragmentPage testdocs/sqlite3.c /^static int defragmentPage(MemPage *pPage, int nMaxFrag){$/;" f file: +del edit.h /^ } del;$/;" m union:Log::__anon2 typeref:struct:Log::__anon2::__anon4 +delete buf.c /^static void delete(Buf* buf, size_t off) {$/;" f file: +deleteCell testdocs/sqlite3.c /^static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){$/;" f file: +deleteTable testdocs/sqlite3.c /^static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){$/;" f file: +delim testdocs/sqlite3.c /^ char delim[128]; \/* flag ASCII delimiters *\/$/;" m struct:simple_tokenizer file: +desc testdocs/sqlite3.c /^ unsigned char desc; \/* True for DESC. False for ASC. *\/$/;" m struct:sqlite3_index_info::sqlite3_index_orderby file: +deserializeGeometry testdocs/sqlite3.c /^static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){$/;" f file: +destroyRootPage testdocs/sqlite3.c /^static void destroyRootPage(Parse *pParse, int iTable, int iDb){$/;" f file: +destroyTable testdocs/sqlite3.c /^static void destroyTable(Parse *pParse, Table *pTab){$/;" f file: +detachFunc testdocs/sqlite3.c /^static void detachFunc($/;" f file: +dev testdocs/sqlite3.c /^ dev_t dev; \/* Device number *\/$/;" m struct:unixFileId file: +deviceCharacteristics testdocs/sqlite3.c /^ int deviceCharacteristics; \/* Precomputed device characteristics *\/$/;" m struct:unixFile file: +dfltLockMode testdocs/sqlite3.c /^ u8 dfltLockMode; \/* Default locking-mode for attached dbs *\/$/;" m struct:sqlite3 file: +die buf.c /^void die(const char* msgfmt, ...) {$/;" f +directMode testdocs/sqlite3.c /^ u8 directMode; \/* Direct rendering mode means take data directly$/;" m struct:AggInfo file: +disableLookaside testdocs/sqlite3.c /^ u8 disableLookaside; \/* Number of times lookaside has been disabled *\/$/;" m struct:Parse file: +disableLookaside testdocs/sqlite3.c /^static void disableLookaside(Parse *pParse){$/;" f file: +disableTerm testdocs/sqlite3.c /^static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){$/;" f file: +disableTriggers testdocs/sqlite3.c /^ u8 disableTriggers; \/* True to disable triggers *\/$/;" m struct:Parse file: +disable_simulated_io_errors testdocs/sqlite3.c /^# define disable_simulated_io_errors(/;" d file: +disable_simulated_io_errors testdocs/sqlite3.c /^void disable_simulated_io_errors(void){$/;" f +disallow testdocs/sqlite3.c /^ int disallow; \/* Do not allow memory allocation *\/$/;" m struct:__anon20 file: +disconnectAllVtab testdocs/sqlite3.c /^static void disconnectAllVtab(sqlite3 *db){$/;" f file: +displayComment testdocs/sqlite3.c /^static int displayComment($/;" f file: +displayP4 testdocs/sqlite3.c /^static char *displayP4(Op *pOp, char *zTemp, int nTemp){$/;" f file: +displayP4Expr testdocs/sqlite3.c /^static void displayP4Expr(StrAccum *p, Expr *pExpr){$/;" f file: +doNotSpill testdocs/sqlite3.c /^ u8 doNotSpill; \/* Do not spill the cache when non-zero *\/$/;" m struct:Pager file: +doWalCallbacks testdocs/sqlite3.c /^static int doWalCallbacks(sqlite3 *db){$/;" f file: +doclist testdocs/sqlite3.c /^ Fts3Doclist doclist;$/;" m struct:Fts3Phrase file: +doingRerun testdocs/sqlite3.c /^ bft doingRerun:1; \/* True if rerunning after an auto-reprepare *\/$/;" m struct:Vdbe file: +done testdocs/sqlite3.c /^ unsigned done :1; \/* A flag to indicate when processing is finished *\/$/;" m struct:ExprList::ExprList_item file: +done testdocs/sqlite3.c /^ int done; \/* Set to true when thread finishes *\/$/;" m struct:SQLiteThread file: +dotlockCheckReservedLock testdocs/sqlite3.c /^static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {$/;" f file: +dotlockClose testdocs/sqlite3.c /^static int dotlockClose(sqlite3_file *id) {$/;" f file: +dotlockLock testdocs/sqlite3.c /^static int dotlockLock(sqlite3_file *id, int eFileLock) {$/;" f file: +dotlockUnlock testdocs/sqlite3.c /^static int dotlockUnlock(sqlite3_file *id, int eFileLock) {$/;" f file: +double testdocs/sqlite3.c /^# define double /;" d file: +double testdocs/sqlite3.c /^# undef double$/;" d file: +doubleConsonant testdocs/sqlite3.c /^static int doubleConsonant(const char *z){$/;" f file: +doubleToInt64 testdocs/sqlite3.c /^static SQLITE_NOINLINE i64 doubleToInt64(double r){$/;" f file: +downgradeAllSharedCacheTableLocks testdocs/sqlite3.c /^ #define downgradeAllSharedCacheTableLocks(/;" d file: +downgradeAllSharedCacheTableLocks testdocs/sqlite3.c /^static void downgradeAllSharedCacheTableLocks(Btree *p){$/;" f file: +dropCell testdocs/sqlite3.c /^static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){$/;" f file: +dupedExprNodeSize testdocs/sqlite3.c /^static int dupedExprNodeSize(Expr *p, int flags){$/;" f file: +dupedExprSize testdocs/sqlite3.c /^static int dupedExprSize(Expr *p, int flags){$/;" f file: +dupedExprStructSize testdocs/sqlite3.c /^static int dupedExprStructSize(Expr *p, int flags){$/;" f file: +eCode testdocs/sqlite3.c /^ u8 eCode; \/* A small processing code *\/$/;" m struct:Walker file: +eContent testdocs/sqlite3.c /^ int eContent; \/* An FTS5_CONTENT value *\/$/;" m struct:Fts5Config file: +eCoordType testdocs/sqlite3.c /^ u8 eCoordType; \/* RTREE_COORD_REAL32 or RTREE_COORD_INT32 *\/$/;" m struct:Rtree file: +eCreate testdocs/sqlite3.c /^ u8 eCreate; \/* eCreate value for for xFetch() *\/$/;" m struct:PCache file: +eCurType testdocs/sqlite3.c /^ u8 eCurType; \/* One of the CURTYPE_* values above *\/$/;" m struct:VdbeCursor file: +eDest testdocs/sqlite3.c /^ u8 eDest; \/* How to dispose of the results. On of SRT_* above. *\/$/;" m struct:SelectDest file: +eDetail testdocs/sqlite3.c /^ int eDetail; \/* Copy of Fts5Config.eDetail *\/$/;" m struct:Fts5Hash file: +eDetail testdocs/sqlite3.c /^ int eDetail; \/* FTS5_DETAIL_XXX value *\/$/;" m struct:Fts5Config file: +eDistinct testdocs/sqlite3.c /^ u8 eDistinct; \/* One of the WHERE_DISTINCT_* values *\/$/;" m struct:WhereInfo file: +eEndLoopOp testdocs/sqlite3.c /^ u8 eEndLoopOp; \/* IN Loop terminator. OP_Next or OP_Prev *\/$/;" m struct:WhereLevel::__anon27::__anon28::InLoop file: +eEvalmode testdocs/sqlite3.c /^ int eEvalmode; \/* An FTS3_EVAL_XX constant *\/$/;" m struct:Fts3Cursor file: +eFWErr testdocs/sqlite3.c /^ int eFWErr; \/* Non-zero if in an error state *\/$/;" m struct:PmaWriter file: +eFileLock testdocs/sqlite3.c /^ unsigned char eFileLock; \/* The type of lock held on this fd *\/$/;" m struct:unixFile file: +eFileLock testdocs/sqlite3.c /^ unsigned char eFileLock; \/* One of SHARED_LOCK, RESERVED_LOCK etc. *\/$/;" m struct:unixInodeInfo file: +eLock testdocs/sqlite3.c /^ u8 eLock; \/* Current lock held on database file *\/$/;" m struct:Pager file: +eLock testdocs/sqlite3.c /^ u8 eLock; \/* READ_LOCK or WRITE_LOCK *\/$/;" m struct:BtLock file: +eMatchOp testdocs/sqlite3.c /^ u8 eMatchOp; \/* Op for vtab MATCH\/LIKE\/GLOB\/REGEXP terms *\/$/;" m struct:WhereTerm file: +eOnePass testdocs/sqlite3.c /^ u8 eOnePass; \/* ONEPASS_OFF, or _SINGLE, or _MULTI *\/$/;" m struct:WhereInfo file: +eOperator testdocs/sqlite3.c /^ u16 eOperator; \/* A WO_xx value describing *\/$/;" m struct:WhereTerm file: +eOrconf testdocs/sqlite3.c /^ u8 eOrconf; \/* Default ON CONFLICT policy for trigger steps *\/$/;" m struct:Parse file: +eParentWithin testdocs/sqlite3.c /^ int eParentWithin; \/* Visibility of parent node *\/$/;" m struct:sqlite3_rtree_query_info file: +ePlan testdocs/sqlite3.c /^ int ePlan; \/* FTS5_PLAN_XXX value *\/$/;" m struct:Fts5Cursor file: +ePragTyp testdocs/sqlite3.c /^ u8 ePragTyp; \/* PragTyp_XXX value *\/$/;" m struct:PragmaName file: +eSearch testdocs/sqlite3.c /^ i16 eSearch; \/* Search strategy (see below) *\/$/;" m struct:Fts3Cursor file: +eStage testdocs/sqlite3.c /^ int eStage; \/* Value of RBU_STATE_STAGE field *\/$/;" m struct:sqlite3rbu file: +eStage testdocs/sqlite3.c /^ int eStage;$/;" m struct:RbuState file: +eState testdocs/sqlite3.c /^ int eState; \/* 0==closed, 1==open, 2==synced *\/$/;" m struct:Fts5TransactionState file: +eState testdocs/sqlite3.c /^ int eState; \/* See above *\/$/;" m struct:PoslistCallbackCtx file: +eState testdocs/sqlite3.c /^ u8 eState; \/* Pager state (OPEN, READER, WRITER_LOCKED..) *\/$/;" m struct:Pager file: +eState testdocs/sqlite3.c /^ u8 eState; \/* One of the CURSOR_XXX constants (see below) *\/$/;" m struct:BtCursor file: +eSubtype testdocs/sqlite3.c /^ u8 eSubtype; \/* Subtype for this value *\/$/;" m struct:sqlite3_value file: +eTnctType testdocs/sqlite3.c /^ u8 eTnctType; \/* One of the WHERE_DISTINCT_* operators *\/$/;" m struct:DistinctCtx file: +eTriggerOp testdocs/sqlite3.c /^ u8 eTriggerOp; \/* TK_UPDATE, TK_INSERT or TK_DELETE *\/$/;" m struct:Parse file: +eType testdocs/sqlite3.c /^ int eType; \/* FTS5_VOCAB_COL or ROW *\/$/;" m struct:Fts5VocabTable file: +eType testdocs/sqlite3.c /^ int eType; \/* Node type *\/$/;" m struct:Fts5ExprNode file: +eType testdocs/sqlite3.c /^ int eType; \/* Table type - an RBU_PK_XXX value *\/$/;" m struct:RbuObjIter file: +eType testdocs/sqlite3.c /^ int eType; \/* One of the FTSQUERY_XXX values defined below *\/$/;" m struct:Fts3Expr file: +eType testdocs/sqlite3.c /^ u8 eType; \/* Allocation type code *\/$/;" m struct:MemBlockHdr file: +eType testdocs/sqlite3.c /^ u8 eType; \/* Type of top-level element *\/$/;" m struct:JsonEachCursor file: +eType testdocs/sqlite3.c /^ u8 eType; \/* One of the JSON_ type values *\/$/;" m struct:JsonNode file: +eType testdocs/sqlite3.c /^ u8 eType; \/* Transformation type code *\/$/;" m struct:__anon19 file: +eVal testdocs/sqlite3.c /^ int eVal;$/;" m struct:Fts5Enum file: +eWithin testdocs/sqlite3.c /^ int eWithin; \/* OUT: Visiblity *\/$/;" m struct:sqlite3_rtree_query_info file: +eWithin testdocs/sqlite3.c /^ u8 eWithin; \/* PARTLY_WITHIN or FULLY_WITHIN *\/$/;" m struct:RtreeSearchPoint file: +ebcdicToAscii testdocs/sqlite3.c /^const unsigned char ebcdicToAscii[] = {$/;" v +editPage testdocs/sqlite3.c /^static int editPage($/;" f file: +enable_shared_cache testdocs/sqlite3.c /^ int (*enable_shared_cache)(int);$/;" m struct:sqlite3_api_routines file: +enable_simulated_io_errors testdocs/sqlite3.c /^# define enable_simulated_io_errors(/;" d file: +enable_simulated_io_errors testdocs/sqlite3.c /^void enable_simulated_io_errors(void){$/;" f +enc testdocs/sqlite3.c /^ u8 enc; \/* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE *\/$/;" m struct:sqlite3_value file: +enc testdocs/sqlite3.c /^ u8 enc; \/* Text encoding *\/$/;" m struct:sqlite3 file: +enc testdocs/sqlite3.c /^ u8 enc; \/* Text encoding handled by xCmp() *\/$/;" m struct:CollSeq file: +enc testdocs/sqlite3.c /^ u8 enc; \/* Text encoding used by this database *\/$/;" m struct:Schema file: +enc testdocs/sqlite3.c /^ u8 enc; \/* Text encoding - one of the SQLITE_UTF* values *\/$/;" m struct:KeyInfo file: +end edit.h /^ size_t end; \/* offset in the file where insertion ended *\/$/;" m struct:Log::__anon2::__anon3 +end edit.h /^ size_t end;$/;" m struct:__anon6 +endpoint testdocs/sqlite3.c /^ FilePoint endpoint; \/* Pointer to the end of the file *\/$/;" m struct:MemJournal file: +enlargeAndAppend testdocs/sqlite3.c /^static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){$/;" f file: +enterMutex testdocs/sqlite3.c /^static void enterMutex(void){$/;" f file: +eqSeen testdocs/sqlite3.c /^ u8 eqSeen; \/* True if an equality comparison has been seen *\/$/;" m struct:UnpackedRecord file: +err testdocs/waf /^def err(m):$/;" f +errCode testdocs/sqlite3.c /^ int errCode; \/* Most recent error code (SQLITE_*) *\/$/;" m struct:sqlite3 file: +errCode testdocs/sqlite3.c /^ int errCode; \/* One of several kinds of errors *\/$/;" m struct:Pager file: +errCode testdocs/sqlite3.c /^ u8 errCode; \/* Error detected by xRecordCompare (CORRUPT or NOMEM) *\/$/;" m struct:UnpackedRecord file: +errMask testdocs/sqlite3.c /^ int errMask; \/* & result codes with this before returning *\/$/;" m struct:sqlite3 file: +errMsg testdocs/sqlite3.c /^ StrAccum errMsg; \/* Accumulate the error message text here *\/$/;" m struct:IntegrityCk file: +errcode testdocs/sqlite3.c /^ int (*errcode)(sqlite3*db);$/;" m struct:sqlite3_api_routines file: +errfn edit.h /^ void (*errfn)(char*); \/* callback for error messages *\/$/;" m struct:__anon5 +errlogFunc testdocs/sqlite3.c /^static void errlogFunc($/;" f file: +errmsg testdocs/sqlite3.c /^ const char * (*errmsg)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +errmsg16 testdocs/sqlite3.c /^ const void * (*errmsg16)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +errnostr stdc.h /^#define errnostr(/;" d +errorAction testdocs/sqlite3.c /^ u8 errorAction; \/* Recovery action to do in case of an error *\/$/;" m struct:Vdbe file: +errstr testdocs/sqlite3.c /^ const char *(*errstr)(int);$/;" m struct:sqlite3_api_routines file: +estLog testdocs/sqlite3.c /^static LogEst estLog(LogEst N){$/;" f file: +estimateIndexWidth testdocs/sqlite3.c /^static void estimateIndexWidth(Index *pIdx){$/;" f file: +estimateTableWidth testdocs/sqlite3.c /^static void estimateTableWidth(Table *pTab){$/;" f file: +estimatedCost testdocs/sqlite3.c /^ double estimatedCost; \/* Estimated cost of using this index *\/$/;" m struct:sqlite3_index_info file: +estimatedRows testdocs/sqlite3.c /^ sqlite3_int64 estimatedRows; \/* Estimated number of rows returned *\/$/;" m struct:sqlite3_index_info file: +etBUFSIZE testdocs/sqlite3.c /^#define etBUFSIZE /;" d file: +etByte testdocs/sqlite3.c /^typedef unsigned char etByte;$/;" t file: +etCHARX testdocs/sqlite3.c /^#define etCHARX /;" d file: +etDECIMAL testdocs/sqlite3.c /^#define etDECIMAL /;" d file: +etDYNSTRING testdocs/sqlite3.c /^#define etDYNSTRING /;" d file: +etEXP testdocs/sqlite3.c /^#define etEXP /;" d file: +etFLOAT testdocs/sqlite3.c /^#define etFLOAT /;" d file: +etGENERIC testdocs/sqlite3.c /^#define etGENERIC /;" d file: +etINVALID testdocs/sqlite3.c /^#define etINVALID /;" d file: +etORDINAL testdocs/sqlite3.c /^#define etORDINAL /;" d file: +etPERCENT testdocs/sqlite3.c /^#define etPERCENT /;" d file: +etPOINTER testdocs/sqlite3.c /^#define etPOINTER /;" d file: +etRADIX testdocs/sqlite3.c /^#define etRADIX /;" d file: +etSIZE testdocs/sqlite3.c /^#define etSIZE /;" d file: +etSQLESCAPE testdocs/sqlite3.c /^#define etSQLESCAPE /;" d file: +etSQLESCAPE2 testdocs/sqlite3.c /^#define etSQLESCAPE2 /;" d file: +etSQLESCAPE3 testdocs/sqlite3.c /^#define etSQLESCAPE3 /;" d file: +etSRCLIST testdocs/sqlite3.c /^#define etSRCLIST /;" d file: +etSTRING testdocs/sqlite3.c /^#define etSTRING /;" d file: +etTOKEN testdocs/sqlite3.c /^#define etTOKEN /;" d file: +et_getdigit testdocs/sqlite3.c /^static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){$/;" f file: +et_info testdocs/sqlite3.c /^typedef struct et_info { \/* Information about each format field *\/$/;" s file: +et_info testdocs/sqlite3.c /^} et_info;$/;" t typeref:struct:et_info file: +exclMask testdocs/sqlite3.c /^ u16 exclMask; \/* Mask of exclusive locks held *\/$/;" m struct:unixShm file: +exclMask testdocs/sqlite3.c /^ u16 exclMask; \/* Mask of exclusive locks held *\/$/;" m struct:winShm file: +exclMask testdocs/sqlite3.c /^ u8 exclMask; \/* Mask of exclusive locks held *\/$/;" m struct:unixShmNode file: +exclusiveMode testdocs/sqlite3.c /^ u8 exclusiveMode; \/* Boolean. True if locking_mode==EXCLUSIVE *\/$/;" m struct:Pager file: +exclusiveMode testdocs/sqlite3.c /^ u8 exclusiveMode; \/* Non-zero if connection is in exclusive mode *\/$/;" m struct:Wal file: +exec testdocs/sqlite3.c /^ int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);$/;" m struct:sqlite3_api_routines file: +execSql testdocs/sqlite3.c /^static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){$/;" f file: +execSqlF testdocs/sqlite3.c /^static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){$/;" f file: +expand_tabs edit.h /^ bool expand_tabs; \/* tracks current mode *\/$/;" m struct:__anon5 +expanded_sql testdocs/sqlite3.c /^ char *(*expanded_sql)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +expired testdocs/sqlite3.c /^ bft expired:1; \/* True if the VM needs to be recompiled *\/$/;" m struct:Vdbe file: +expired testdocs/sqlite3.c /^ int (*expired)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +explain testdocs/sqlite3.c /^ bft explain:2; \/* True if EXPLAIN present on SQL command *\/$/;" m struct:Vdbe file: +explain testdocs/sqlite3.c /^ u8 explain; \/* True if the EXPLAIN flag is found on the query *\/$/;" m struct:Parse file: +explainAppendTerm testdocs/sqlite3.c /^static void explainAppendTerm($/;" f file: +explainComposite testdocs/sqlite3.c /^# define explainComposite(/;" d file: +explainComposite testdocs/sqlite3.c /^static void explainComposite($/;" f file: +explainIndexColumnName testdocs/sqlite3.c /^static const char *explainIndexColumnName(Index *pIdx, int i){$/;" f file: +explainIndexRange testdocs/sqlite3.c /^static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){$/;" f file: +explainSetInteger testdocs/sqlite3.c /^# define explainSetInteger(/;" d file: +explainSimpleCount testdocs/sqlite3.c /^# define explainSimpleCount(/;" d file: +explainSimpleCount testdocs/sqlite3.c /^static void explainSimpleCount($/;" f file: +explainTempTable testdocs/sqlite3.c /^# define explainTempTable(/;" d file: +explainTempTable testdocs/sqlite3.c /^static void explainTempTable(Parse *pParse, const char *zUsage){$/;" f file: +expmask testdocs/sqlite3.c /^ u32 expmask; \/* Binding to these vars invalidates VM *\/$/;" m struct:Vdbe file: +exprAlwaysFalse testdocs/sqlite3.c /^static int exprAlwaysFalse(Expr *p){$/;" f file: +exprAlwaysTrue testdocs/sqlite3.c /^static int exprAlwaysTrue(Expr *p){$/;" f file: +exprAnalyze testdocs/sqlite3.c /^static void exprAnalyze($/;" f file: +exprAnalyzeOrTerm testdocs/sqlite3.c /^static void exprAnalyzeOrTerm($/;" f file: +exprCodeBetween testdocs/sqlite3.c /^static void exprCodeBetween($/;" f file: +exprCodeSubselect testdocs/sqlite3.c /^static int exprCodeSubselect(Parse *pParse, Expr *pExpr){$/;" f file: +exprCodeVector testdocs/sqlite3.c /^static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){$/;" f file: +exprCommute testdocs/sqlite3.c /^static void exprCommute(Parse *pParse, Expr *pExpr){$/;" f file: +exprDup testdocs/sqlite3.c /^static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){$/;" f file: +exprINAffinity testdocs/sqlite3.c /^static char *exprINAffinity(Parse *pParse, Expr *pExpr){$/;" f file: +exprIdxCover testdocs/sqlite3.c /^static int exprIdxCover(Walker *pWalker, Expr *pExpr){$/;" f file: +exprIsConst testdocs/sqlite3.c /^static int exprIsConst(Expr *p, int initFlag, int iCur){$/;" f file: +exprListDeleteNN testdocs/sqlite3.c /^static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){$/;" f file: +exprMightBeIndexed testdocs/sqlite3.c /^static int exprMightBeIndexed($/;" f file: +exprMightBeIndexed2 testdocs/sqlite3.c /^static SQLITE_NOINLINE int exprMightBeIndexed2($/;" f file: +exprNodeIsConstant testdocs/sqlite3.c /^static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){$/;" f file: +exprNodeIsConstantOrGroupBy testdocs/sqlite3.c /^static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){$/;" f file: +exprNot testdocs/sqlite3.c /^ static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){$/;" f file: +exprProbability testdocs/sqlite3.c /^static int exprProbability(Expr *p){$/;" f file: +exprSelectUsage testdocs/sqlite3.c /^static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){$/;" f file: +exprSetHeight testdocs/sqlite3.c /^#define exprSetHeight(/;" d file: +exprSetHeight testdocs/sqlite3.c /^static void exprSetHeight(Expr *p){$/;" f file: +exprSrcCount testdocs/sqlite3.c /^static int exprSrcCount(Walker *pWalker, Expr *pExpr){$/;" f file: +exprStructSize testdocs/sqlite3.c /^static int exprStructSize(Expr *p){$/;" f file: +exprTableColumn testdocs/sqlite3.c /^static Expr *exprTableColumn($/;" f file: +exprTableRegister testdocs/sqlite3.c /^static Expr *exprTableRegister($/;" f file: +exprToRegister testdocs/sqlite3.c /^static void exprToRegister(Expr *p, int iReg){$/;" f file: +exprToString testdocs/sqlite3.c /^static char *exprToString(Fts3Expr *pExpr, char *zBuf){$/;" f file: +exprVectorRegister testdocs/sqlite3.c /^static int exprVectorRegister($/;" f file: +extended_errcode testdocs/sqlite3.c /^ int (*extended_errcode)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +extended_result_codes testdocs/sqlite3.c /^ int (*extended_result_codes)(sqlite3*,int);$/;" m struct:sqlite3_api_routines file: +extraSync testdocs/sqlite3.c /^ u8 extraSync; \/* sync directory after journal delete *\/$/;" m struct:Pager file: +f testdocs/sqlite3.c /^ RtreeValue f; \/* Floating point value *\/$/;" m union:RtreeCoord file: +fErrorOrAux testdocs/sqlite3.c /^ u8 fErrorOrAux; \/* isError!=0 or pVdbe->pAuxData modified *\/$/;" m struct:sqlite3_context file: +fcntlSizeHint testdocs/sqlite3.c /^static int fcntlSizeHint(unixFile *pFile, i64 nByte){$/;" f file: +fd testdocs/sqlite3.c /^ int fd; \/* file desc to assoc this lock with *\/$/;" m struct:ByteRangeLockPB2 file: +fd testdocs/sqlite3.c /^ int fd; \/* File descriptor to close *\/$/;" m struct:UnixUnusedFd file: +fd testdocs/sqlite3.c /^ sqlite3_file *fd; \/* File descriptor for database *\/$/;" m struct:Pager file: +fdatasync testdocs/sqlite3.c /^# define fdatasync /;" d file: +fetchPayload testdocs/sqlite3.c /^static const void *fetchPayload($/;" f file: +fg testdocs/sqlite3.c /^ } fg;$/;" m struct:SrcList::SrcList_item typeref:struct:SrcList::SrcList_item::__anon14 file: +file testdocs/sqlite3.c /^ SorterFile file; \/* Temp file for level-0 PMAs *\/$/;" m struct:SortSubtask file: +file2 testdocs/sqlite3.c /^ SorterFile file2; \/* Space for other PMAs *\/$/;" m struct:SortSubtask file: +fileChunkSize testdocs/sqlite3.c /^#define fileChunkSize(/;" d file: +fileHasMoved testdocs/sqlite3.c /^static int fileHasMoved(unixFile *pFile){$/;" f file: +fileId testdocs/sqlite3.c /^ struct unixFileId fileId; \/* The lookup key *\/$/;" m struct:unixInodeInfo typeref:struct:unixInodeInfo::unixFileId file: +file_control testdocs/sqlite3.c /^ int (*file_control)(sqlite3*,const char*,int,void*);$/;" m struct:sqlite3_api_routines file: +file_format testdocs/sqlite3.c /^ u8 file_format; \/* Schema format version for this file *\/$/;" m struct:Schema file: +fillInCell testdocs/sqlite3.c /^static int fillInCell($/;" f file: +fillInUnixFile testdocs/sqlite3.c /^static int fillInUnixFile($/;" f file: +filter testdocs/sqlite3.c /^ Fts3SegFilter filter;$/;" m struct:Fts3auxCursor file: +finalDbSize testdocs/sqlite3.c /^static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){$/;" f file: +finalize testdocs/sqlite3.c /^ int (*finalize)(sqlite3_stmt*pStmt);$/;" m struct:sqlite3_api_routines file: +finalizeAggFunctions testdocs/sqlite3.c /^static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){$/;" f file: +findBtree testdocs/sqlite3.c /^static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){$/;" f file: +findCell testdocs/sqlite3.c /^#define findCell(/;" d file: +findCellPastPtr testdocs/sqlite3.c /^#define findCellPastPtr(/;" d file: +findCollSeqEntry testdocs/sqlite3.c /^static CollSeq *findCollSeqEntry($/;" f file: +findCreateFileMode testdocs/sqlite3.c /^static int findCreateFileMode($/;" f file: +findElementWithHash testdocs/sqlite3.c /^static HashElem *findElementWithHash($/;" f file: +findIndexCol testdocs/sqlite3.c /^static int findIndexCol($/;" f file: +findIndexOrPrimaryKey testdocs/sqlite3.c /^static Index *findIndexOrPrimaryKey($/;" f file: +findInodeInfo testdocs/sqlite3.c /^static int findInodeInfo($/;" f file: +findLeafNode testdocs/sqlite3.c /^static int findLeafNode($/;" f file: +findNextHostParameter testdocs/sqlite3.c /^static int findNextHostParameter(const char *zSql, int *pnToken){$/;" f file: +findReusableFd testdocs/sqlite3.c /^static UnixUnusedFd *findReusableFd(const char *zPath, int flags){$/;" f file: +findRightmost testdocs/sqlite3.c /^static Select *findRightmost(Select *p){$/;" f file: +find_lib testdocs/waf /^def find_lib():$/;" f +finder_type testdocs/sqlite3.c /^typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);$/;" t file: +first testdocs/sqlite3.c /^ Fts3HashElem *first; \/* The first element of the array *\/$/;" m struct:Fts3Hash file: +first testdocs/sqlite3.c /^ HashElem *first; \/* The first element of the array *\/$/;" m struct:Hash file: +fixBoundingBox testdocs/sqlite3.c /^static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){$/;" f file: +fixLeafParent testdocs/sqlite3.c /^static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){$/;" f file: +fixpy2 testdocs/waf /^ import fixpy2$/;" i +fkActionTrigger testdocs/sqlite3.c /^static Trigger *fkActionTrigger($/;" f file: +fkChildIsModified testdocs/sqlite3.c /^static int fkChildIsModified($/;" f file: +fkLookupParent testdocs/sqlite3.c /^static void fkLookupParent($/;" f file: +fkParentIsModified testdocs/sqlite3.c /^static int fkParentIsModified($/;" f file: +fkScanChildren testdocs/sqlite3.c /^static void fkScanChildren($/;" f file: +fkTriggerDelete testdocs/sqlite3.c /^static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){$/;" f file: +fkeyHash testdocs/sqlite3.c /^ Hash fkeyHash; \/* All foreign keys by referenced table name *\/$/;" m struct:Schema file: +flag testdocs/sqlite3.c /^ char flag;$/;" m struct:MatchInfo file: +flags testdocs/sqlite3.c /^ etByte flags; \/* One or more of FLAG_ constants below *\/$/;" m struct:et_info file: +flags testdocs/sqlite3.c /^ int flags; \/* Mask of configuration flags *\/$/;" m struct:Fts5SegIter file: +flags testdocs/sqlite3.c /^ int flags; \/* xOpen flags *\/$/;" m struct:MemJournal file: +flags testdocs/sqlite3.c /^ int flags; \/* Miscellaneous flags. See below *\/$/;" m struct:sqlite3 file: +flags testdocs/sqlite3.c /^ int flags; \/* Flags this file descriptor was opened with *\/$/;" m struct:UnixUnusedFd file: +flags testdocs/sqlite3.c /^ int flags;$/;" m struct:Fts3SegFilter file: +flags testdocs/sqlite3.c /^ u16 flags; \/* PGHDR flags defined below *\/$/;" m struct:PgHdr file: +flags testdocs/sqlite3.c /^ u16 flags; \/* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. *\/$/;" m struct:sqlite3_value file: +flags testdocs/sqlite3.c /^ u32 flags; \/* Various flags. EP_* See below *\/$/;" m struct:Expr file: +flags testdocs/sqlite3.c /^ u8 flags; \/* Copy of flags byte *\/$/;" m struct:StatPage file: +flattenSubquery testdocs/sqlite3.c /^static int flattenSubquery($/;" f file: +float testdocs/sqlite3.c /^# define float /;" d file: +floatSwap testdocs/sqlite3.c /^static u64 floatSwap(u64 in){$/;" f file: +flockCheckReservedLock testdocs/sqlite3.c /^static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){$/;" f file: +flockClose testdocs/sqlite3.c /^static int flockClose(sqlite3_file *id) {$/;" f file: +flockLock testdocs/sqlite3.c /^static int flockLock(sqlite3_file *id, int eFileLock) {$/;" f file: +flockUnlock testdocs/sqlite3.c /^static int flockUnlock(sqlite3_file *id, int eFileLock) {$/;" f file: +fmtinfo testdocs/sqlite3.c /^static const et_info fmtinfo[] = {$/;" v file: +fmttype testdocs/sqlite3.c /^ char fmttype; \/* The format field code letter *\/$/;" m struct:et_info file: +free testdocs/sqlite3.c /^ void (*free)(void*);$/;" m struct:sqlite3_api_routines file: +freeCursorConstraints testdocs/sqlite3.c /^static void freeCursorConstraints(RtreeCursor *pCsr){$/;" f file: +freeEphemeralFunction testdocs/sqlite3.c /^static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){$/;" f file: +freeIndex testdocs/sqlite3.c /^static void freeIndex(sqlite3 *db, Index *p){$/;" f file: +freeP4 testdocs/sqlite3.c /^static void freeP4(sqlite3 *db, int p4type, void *p4){$/;" f file: +freeP4FuncCtx testdocs/sqlite3.c /^static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){$/;" f file: +freeP4Mem testdocs/sqlite3.c /^static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){$/;" f file: +freePage testdocs/sqlite3.c /^static void freePage(MemPage *pPage, int *pRC){$/;" f file: +freePage2 testdocs/sqlite3.c /^static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){$/;" f file: +freeSpace testdocs/sqlite3.c /^static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){$/;" f file: +freeTempSpace testdocs/sqlite3.c /^static void freeTempSpace(BtShared *pBt){$/;" f file: +free_table testdocs/sqlite3.c /^ void (*free_table)(char**result);$/;" m struct:sqlite3_api_routines file: +fsFlags testdocs/sqlite3.c /^ unsigned fsFlags; \/* cached details from statfs() *\/$/;" m struct:unixFile file: +fts3AllocateSegdirIdx testdocs/sqlite3.c /^static int fts3AllocateSegdirIdx($/;" f file: +fts3AppendToNode testdocs/sqlite3.c /^static int fts3AppendToNode($/;" f file: +fts3Appendf testdocs/sqlite3.c /^static void fts3Appendf($/;" f file: +fts3BeginMethod testdocs/sqlite3.c /^static int fts3BeginMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3BestIndexMethod testdocs/sqlite3.c /^static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){$/;" f file: +fts3BestSnippet testdocs/sqlite3.c /^static int fts3BestSnippet($/;" f file: +fts3BinCompare testdocs/sqlite3.c /^static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){$/;" f file: +fts3BinHash testdocs/sqlite3.c /^static int fts3BinHash(const void *pKey, int nKey){$/;" f file: +fts3ChecksumEntry testdocs/sqlite3.c /^static u64 fts3ChecksumEntry($/;" f file: +fts3ChecksumIndex testdocs/sqlite3.c /^static u64 fts3ChecksumIndex($/;" f file: +fts3CloseMethod testdocs/sqlite3.c /^static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3ColumnFilter testdocs/sqlite3.c /^static void fts3ColumnFilter($/;" f file: +fts3ColumnMethod testdocs/sqlite3.c /^static int fts3ColumnMethod($/;" f file: +fts3ColumnlistCopy testdocs/sqlite3.c /^static void fts3ColumnlistCopy(char **pp, char **ppPoslist){$/;" f file: +fts3ColumnlistCount testdocs/sqlite3.c /^static int fts3ColumnlistCount(char **ppCollist){$/;" f file: +fts3CommitMethod testdocs/sqlite3.c /^static int fts3CommitMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3CompareElemByTerm testdocs/sqlite3.c /^static int SQLITE_CDECL fts3CompareElemByTerm($/;" f file: +fts3ConnectMethod testdocs/sqlite3.c /^static int fts3ConnectMethod($/;" f file: +fts3ContentColumns testdocs/sqlite3.c /^static int fts3ContentColumns($/;" f file: +fts3CreateMethod testdocs/sqlite3.c /^static int fts3CreateMethod($/;" f file: +fts3CreateTables testdocs/sqlite3.c /^static int fts3CreateTables(Fts3Table *p){$/;" f file: +fts3CursorFinalizeStmt testdocs/sqlite3.c /^static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){$/;" f file: +fts3CursorSeek testdocs/sqlite3.c /^static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){$/;" f file: +fts3CursorSeekStmt testdocs/sqlite3.c /^static int fts3CursorSeekStmt(Fts3Cursor *pCsr){$/;" f file: +fts3DatabasePageSize testdocs/sqlite3.c /^static void fts3DatabasePageSize(int *pRc, Fts3Table *p){$/;" f file: +fts3DbExec testdocs/sqlite3.c /^static void fts3DbExec($/;" f file: +fts3DeclareVtab testdocs/sqlite3.c /^static void fts3DeclareVtab(int *pRc, Fts3Table *p){$/;" f file: +fts3DecodeIntArray testdocs/sqlite3.c /^static void fts3DecodeIntArray($/;" f file: +fts3DeleteAll testdocs/sqlite3.c /^static int fts3DeleteAll(Fts3Table *p, int bContent){$/;" f file: +fts3DeleteByRowid testdocs/sqlite3.c /^static int fts3DeleteByRowid($/;" f file: +fts3DeleteSegdir testdocs/sqlite3.c /^static int fts3DeleteSegdir($/;" f file: +fts3DeleteSegment testdocs/sqlite3.c /^static int fts3DeleteSegment($/;" f file: +fts3DeleteTerms testdocs/sqlite3.c /^static void fts3DeleteTerms($/;" f file: +fts3DestroyMethod testdocs/sqlite3.c /^static int fts3DestroyMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3DisconnectMethod testdocs/sqlite3.c /^static int fts3DisconnectMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3DoAutoincrmerge testdocs/sqlite3.c /^static int fts3DoAutoincrmerge($/;" f file: +fts3DoIncrmerge testdocs/sqlite3.c /^static int fts3DoIncrmerge($/;" f file: +fts3DoIntegrityCheck testdocs/sqlite3.c /^static int fts3DoIntegrityCheck($/;" f file: +fts3DoOptimize testdocs/sqlite3.c /^static int fts3DoOptimize(Fts3Table *p, int bReturnDone){$/;" f file: +fts3DoRebuild testdocs/sqlite3.c /^static int fts3DoRebuild(Fts3Table *p){$/;" f file: +fts3DocidRange testdocs/sqlite3.c /^static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){$/;" f file: +fts3DoclistCountDocids testdocs/sqlite3.c /^static int fts3DoclistCountDocids(char *aList, int nList){$/;" f file: +fts3DoclistOrMerge testdocs/sqlite3.c /^static int fts3DoclistOrMerge($/;" f file: +fts3DoclistPhraseMerge testdocs/sqlite3.c /^static int fts3DoclistPhraseMerge($/;" f file: +fts3EncodeIntArray testdocs/sqlite3.c /^static void fts3EncodeIntArray($/;" f file: +fts3EofMethod testdocs/sqlite3.c /^static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3EvalAllocateReaders testdocs/sqlite3.c /^static void fts3EvalAllocateReaders($/;" f file: +fts3EvalAverageDocsize testdocs/sqlite3.c /^static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){$/;" f file: +fts3EvalDeferredPhrase testdocs/sqlite3.c /^static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){$/;" f file: +fts3EvalDlPhraseNext testdocs/sqlite3.c /^static void fts3EvalDlPhraseNext($/;" f file: +fts3EvalGatherStats testdocs/sqlite3.c /^static int fts3EvalGatherStats($/;" f file: +fts3EvalIncrPhraseNext testdocs/sqlite3.c /^static int fts3EvalIncrPhraseNext($/;" f file: +fts3EvalInvalidatePoslist testdocs/sqlite3.c /^static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){$/;" f file: +fts3EvalNearTest testdocs/sqlite3.c /^static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){$/;" f file: +fts3EvalNearTrim testdocs/sqlite3.c /^static int fts3EvalNearTrim($/;" f file: +fts3EvalNext testdocs/sqlite3.c /^static int fts3EvalNext(Fts3Cursor *pCsr){$/;" f file: +fts3EvalNextRow testdocs/sqlite3.c /^static void fts3EvalNextRow($/;" f file: +fts3EvalPhraseLoad testdocs/sqlite3.c /^static int fts3EvalPhraseLoad($/;" f file: +fts3EvalPhraseMergeToken testdocs/sqlite3.c /^static int fts3EvalPhraseMergeToken($/;" f file: +fts3EvalPhraseNext testdocs/sqlite3.c /^static int fts3EvalPhraseNext($/;" f file: +fts3EvalPhraseStart testdocs/sqlite3.c /^static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){$/;" f file: +fts3EvalRestart testdocs/sqlite3.c /^static void fts3EvalRestart($/;" f file: +fts3EvalSelectDeferred testdocs/sqlite3.c /^static int fts3EvalSelectDeferred($/;" f file: +fts3EvalStart testdocs/sqlite3.c /^static int fts3EvalStart(Fts3Cursor *pCsr){$/;" f file: +fts3EvalStartReaders testdocs/sqlite3.c /^static void fts3EvalStartReaders($/;" f file: +fts3EvalTestExpr testdocs/sqlite3.c /^static int fts3EvalTestExpr($/;" f file: +fts3EvalTokenCosts testdocs/sqlite3.c /^static void fts3EvalTokenCosts($/;" f file: +fts3EvalUpdateCounts testdocs/sqlite3.c /^static void fts3EvalUpdateCounts(Fts3Expr *pExpr){$/;" f file: +fts3ExprBalance testdocs/sqlite3.c /^static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){$/;" f file: +fts3ExprCheckDepth testdocs/sqlite3.c /^static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){$/;" f file: +fts3ExprGlobalHitsCb testdocs/sqlite3.c /^static int fts3ExprGlobalHitsCb($/;" f file: +fts3ExprIterate testdocs/sqlite3.c /^static int fts3ExprIterate($/;" f file: +fts3ExprIterate2 testdocs/sqlite3.c /^static int fts3ExprIterate2($/;" f file: +fts3ExprLHitGather testdocs/sqlite3.c /^static void fts3ExprLHitGather($/;" f file: +fts3ExprLHits testdocs/sqlite3.c /^static void fts3ExprLHits($/;" f file: +fts3ExprLoadDoclists testdocs/sqlite3.c /^static int fts3ExprLoadDoclists($/;" f file: +fts3ExprLoadDoclistsCb testdocs/sqlite3.c /^static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){$/;" f file: +fts3ExprLocalHitsCb testdocs/sqlite3.c /^static int fts3ExprLocalHitsCb($/;" f file: +fts3ExprParse testdocs/sqlite3.c /^static int fts3ExprParse($/;" f file: +fts3ExprParseUnbalanced testdocs/sqlite3.c /^static int fts3ExprParseUnbalanced($/;" f file: +fts3ExprPhraseCount testdocs/sqlite3.c /^static int fts3ExprPhraseCount(Fts3Expr *pExpr){$/;" f file: +fts3ExprPhraseCountCb testdocs/sqlite3.c /^static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){$/;" f file: +fts3ExprTermOffsetInit testdocs/sqlite3.c /^static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){$/;" f file: +fts3ExprTest testdocs/sqlite3.c /^static void fts3ExprTest($/;" f file: +fts3FilterMethod testdocs/sqlite3.c /^static int fts3FilterMethod($/;" f file: +fts3FindElementByHash testdocs/sqlite3.c /^static Fts3HashElem *fts3FindElementByHash($/;" f file: +fts3FindFunctionMethod testdocs/sqlite3.c /^static int fts3FindFunctionMethod($/;" f file: +fts3FreeExprNode testdocs/sqlite3.c /^static void fts3FreeExprNode(Fts3Expr *p){$/;" f file: +fts3FunctionArg testdocs/sqlite3.c /^static int fts3FunctionArg($/;" f file: +fts3GetDeltaPosition testdocs/sqlite3.c /^static void fts3GetDeltaPosition(char **pp, int *piPos){$/;" f file: +fts3GetDeltaVarint testdocs/sqlite3.c /^static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){$/;" f file: +fts3GetDeltaVarint3 testdocs/sqlite3.c /^static void fts3GetDeltaVarint3($/;" f file: +fts3GetMatchinfo testdocs/sqlite3.c /^static void fts3GetMatchinfo($/;" f file: +fts3GetReverseVarint testdocs/sqlite3.c /^static void fts3GetReverseVarint($/;" f file: +fts3GetVarint32 testdocs/sqlite3.c /^#define fts3GetVarint32(/;" d file: +fts3Getint testdocs/sqlite3.c /^static int fts3Getint(const char **pz){$/;" f file: +fts3GobbleInt testdocs/sqlite3.c /^static int fts3GobbleInt(const char **pp, int *pnOut){$/;" f file: +fts3HashClear testdocs/sqlite3.c /^#define fts3HashClear /;" d file: +fts3HashCount testdocs/sqlite3.c /^#define fts3HashCount(/;" d file: +fts3HashData testdocs/sqlite3.c /^#define fts3HashData(/;" d file: +fts3HashFind testdocs/sqlite3.c /^#define fts3HashFind /;" d file: +fts3HashFindElem testdocs/sqlite3.c /^#define fts3HashFindElem /;" d file: +fts3HashFirst testdocs/sqlite3.c /^#define fts3HashFirst(/;" d file: +fts3HashFree testdocs/sqlite3.c /^static void fts3HashFree(void *p){$/;" f file: +fts3HashInit testdocs/sqlite3.c /^#define fts3HashInit /;" d file: +fts3HashInsert testdocs/sqlite3.c /^#define fts3HashInsert /;" d file: +fts3HashInsertElement testdocs/sqlite3.c /^static void fts3HashInsertElement($/;" f file: +fts3HashKey testdocs/sqlite3.c /^#define fts3HashKey(/;" d file: +fts3HashKeysize testdocs/sqlite3.c /^#define fts3HashKeysize(/;" d file: +fts3HashMalloc testdocs/sqlite3.c /^static void *fts3HashMalloc(int n){$/;" f file: +fts3HashNext testdocs/sqlite3.c /^#define fts3HashNext(/;" d file: +fts3IncrmergeAppend testdocs/sqlite3.c /^static int fts3IncrmergeAppend($/;" f file: +fts3IncrmergeChomp testdocs/sqlite3.c /^static int fts3IncrmergeChomp($/;" f file: +fts3IncrmergeCsr testdocs/sqlite3.c /^static int fts3IncrmergeCsr($/;" f file: +fts3IncrmergeHintLoad testdocs/sqlite3.c /^static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){$/;" f file: +fts3IncrmergeHintPop testdocs/sqlite3.c /^static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){$/;" f file: +fts3IncrmergeHintPush testdocs/sqlite3.c /^static void fts3IncrmergeHintPush($/;" f file: +fts3IncrmergeHintStore testdocs/sqlite3.c /^static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){$/;" f file: +fts3IncrmergeLoad testdocs/sqlite3.c /^static int fts3IncrmergeLoad($/;" f file: +fts3IncrmergeOutputIdx testdocs/sqlite3.c /^static int fts3IncrmergeOutputIdx($/;" f file: +fts3IncrmergePush testdocs/sqlite3.c /^static int fts3IncrmergePush($/;" f file: +fts3IncrmergeRelease testdocs/sqlite3.c /^static void fts3IncrmergeRelease($/;" f file: +fts3IncrmergeWriter testdocs/sqlite3.c /^static int fts3IncrmergeWriter($/;" f file: +fts3InitVtab testdocs/sqlite3.c /^static int fts3InitVtab($/;" f file: +fts3InsertData testdocs/sqlite3.c /^static int fts3InsertData($/;" f file: +fts3InsertDocsize testdocs/sqlite3.c /^static void fts3InsertDocsize($/;" f file: +fts3InsertTerms testdocs/sqlite3.c /^static int fts3InsertTerms($/;" f file: +fts3IntegrityCheck testdocs/sqlite3.c /^static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){$/;" f file: +fts3IsAppendable testdocs/sqlite3.c /^static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){$/;" f file: +fts3IsEmpty testdocs/sqlite3.c /^static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){$/;" f file: +fts3IsSpecialColumn testdocs/sqlite3.c /^static int fts3IsSpecialColumn($/;" f file: +fts3LcsIteratorAdvance testdocs/sqlite3.c /^static int fts3LcsIteratorAdvance(LcsIterator *pIter){$/;" f file: +fts3LogMerge testdocs/sqlite3.c /^#define fts3LogMerge(/;" d file: +fts3LogMerge testdocs/sqlite3.c /^static void fts3LogMerge(int nMerge, sqlite3_int64 iAbsLevel){$/;" f file: +fts3MIBufferAlloc testdocs/sqlite3.c /^static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){$/;" f file: +fts3MIBufferFree testdocs/sqlite3.c /^static void fts3MIBufferFree(void *p){$/;" f file: +fts3MIBufferNew testdocs/sqlite3.c /^static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){$/;" f file: +fts3MIBufferSetGlobal testdocs/sqlite3.c /^static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){$/;" f file: +fts3MallocZero testdocs/sqlite3.c /^static void *fts3MallocZero(int nByte){$/;" f file: +fts3MatchinfoCheck testdocs/sqlite3.c /^static int fts3MatchinfoCheck($/;" f file: +fts3MatchinfoFunc testdocs/sqlite3.c /^static void fts3MatchinfoFunc($/;" f file: +fts3MatchinfoLcs testdocs/sqlite3.c /^static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){$/;" f file: +fts3MatchinfoLcsCb testdocs/sqlite3.c /^static int fts3MatchinfoLcsCb($/;" f file: +fts3MatchinfoSelectDoctotal testdocs/sqlite3.c /^static int fts3MatchinfoSelectDoctotal($/;" f file: +fts3MatchinfoSize testdocs/sqlite3.c /^static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){$/;" f file: +fts3MatchinfoValues testdocs/sqlite3.c /^static int fts3MatchinfoValues($/;" f file: +fts3Module testdocs/sqlite3.c /^static const sqlite3_module fts3Module = {$/;" v file: +fts3MsrBufferData testdocs/sqlite3.c /^static int fts3MsrBufferData($/;" f file: +fts3NextMethod testdocs/sqlite3.c /^static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3NodeAddTerm testdocs/sqlite3.c /^static int fts3NodeAddTerm($/;" f file: +fts3NodeFree testdocs/sqlite3.c /^static void fts3NodeFree(SegmentNode *pTree){$/;" f file: +fts3NodeWrite testdocs/sqlite3.c /^static int fts3NodeWrite($/;" f file: +fts3OffsetsFunc testdocs/sqlite3.c /^static void fts3OffsetsFunc($/;" f file: +fts3OpenMethod testdocs/sqlite3.c /^static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){$/;" f file: +fts3OptimizeFunc testdocs/sqlite3.c /^static void fts3OptimizeFunc($/;" f file: +fts3PendingListAppend testdocs/sqlite3.c /^static int fts3PendingListAppend($/;" f file: +fts3PendingListAppendVarint testdocs/sqlite3.c /^static int fts3PendingListAppendVarint($/;" f file: +fts3PendingListDelete testdocs/sqlite3.c /^static void fts3PendingListDelete(PendingList *pList){$/;" f file: +fts3PendingTermsAdd testdocs/sqlite3.c /^static int fts3PendingTermsAdd($/;" f file: +fts3PendingTermsAddOne testdocs/sqlite3.c /^static int fts3PendingTermsAddOne($/;" f file: +fts3PendingTermsDocid testdocs/sqlite3.c /^static int fts3PendingTermsDocid($/;" f file: +fts3PoslistCopy testdocs/sqlite3.c /^static void fts3PoslistCopy(char **pp, char **ppPoslist){$/;" f file: +fts3PoslistMerge testdocs/sqlite3.c /^static void fts3PoslistMerge($/;" f file: +fts3PoslistNearMerge testdocs/sqlite3.c /^static int fts3PoslistNearMerge($/;" f file: +fts3PoslistPhraseMerge testdocs/sqlite3.c /^static int fts3PoslistPhraseMerge($/;" f file: +fts3PrefixCompress testdocs/sqlite3.c /^static int fts3PrefixCompress($/;" f file: +fts3PrefixParameter testdocs/sqlite3.c /^static int fts3PrefixParameter($/;" f file: +fts3PromoteSegments testdocs/sqlite3.c /^static int fts3PromoteSegments($/;" f file: +fts3PutColNumber testdocs/sqlite3.c /^static int fts3PutColNumber(char **pp, int iCol){$/;" f file: +fts3PutDeltaVarint testdocs/sqlite3.c /^static void fts3PutDeltaVarint($/;" f file: +fts3PutDeltaVarint3 testdocs/sqlite3.c /^static void fts3PutDeltaVarint3($/;" f file: +fts3QuoteId testdocs/sqlite3.c /^static char *fts3QuoteId(char const *zInput){$/;" f file: +fts3ReadEndBlockField testdocs/sqlite3.c /^static void fts3ReadEndBlockField($/;" f file: +fts3ReadExprList testdocs/sqlite3.c /^static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){$/;" f file: +fts3ReadNextPos testdocs/sqlite3.c /^static void fts3ReadNextPos($/;" f file: +fts3ReallocOrFree testdocs/sqlite3.c /^static void *fts3ReallocOrFree(void *pOrig, int nNew){$/;" f file: +fts3Rehash testdocs/sqlite3.c /^static int fts3Rehash(Fts3Hash *pH, int new_size){$/;" f file: +fts3ReleaseMethod testdocs/sqlite3.c /^static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){$/;" f file: +fts3RemoveElementByHash testdocs/sqlite3.c /^static void fts3RemoveElementByHash($/;" f file: +fts3RemoveSegdirEntry testdocs/sqlite3.c /^static int fts3RemoveSegdirEntry($/;" f file: +fts3RenameMethod testdocs/sqlite3.c /^static int fts3RenameMethod($/;" f file: +fts3RepackSegdirLevel testdocs/sqlite3.c /^static int fts3RepackSegdirLevel($/;" f file: +fts3ReversePoslist testdocs/sqlite3.c /^static void fts3ReversePoslist(char *pStart, char **ppPoslist){$/;" f file: +fts3RollbackMethod testdocs/sqlite3.c /^static int fts3RollbackMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3RollbackToMethod testdocs/sqlite3.c /^static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){$/;" f file: +fts3RowidMethod testdocs/sqlite3.c /^static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){$/;" f file: +fts3SavepointMethod testdocs/sqlite3.c /^static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){$/;" f file: +fts3ScanInteriorNode testdocs/sqlite3.c /^static int fts3ScanInteriorNode($/;" f file: +fts3SegReaderCmp testdocs/sqlite3.c /^static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){$/;" f file: +fts3SegReaderCursor testdocs/sqlite3.c /^static int fts3SegReaderCursor($/;" f file: +fts3SegReaderCursorAddZero testdocs/sqlite3.c /^static int fts3SegReaderCursorAddZero($/;" f file: +fts3SegReaderCursorAppend testdocs/sqlite3.c /^static int fts3SegReaderCursorAppend($/;" f file: +fts3SegReaderCursorFree testdocs/sqlite3.c /^static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){$/;" f file: +fts3SegReaderDoclistCmp testdocs/sqlite3.c /^static int fts3SegReaderDoclistCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){$/;" f file: +fts3SegReaderDoclistCmpRev testdocs/sqlite3.c /^static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){$/;" f file: +fts3SegReaderFirstDocid testdocs/sqlite3.c /^static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){$/;" f file: +fts3SegReaderIncrRead testdocs/sqlite3.c /^static int fts3SegReaderIncrRead(Fts3SegReader *pReader){$/;" f file: +fts3SegReaderIsPending testdocs/sqlite3.c /^#define fts3SegReaderIsPending(/;" d file: +fts3SegReaderIsRootOnly testdocs/sqlite3.c /^#define fts3SegReaderIsRootOnly(/;" d file: +fts3SegReaderNext testdocs/sqlite3.c /^static int fts3SegReaderNext($/;" f file: +fts3SegReaderNextDocid testdocs/sqlite3.c /^static int fts3SegReaderNextDocid($/;" f file: +fts3SegReaderRequire testdocs/sqlite3.c /^static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){$/;" f file: +fts3SegReaderSetEof testdocs/sqlite3.c /^static void fts3SegReaderSetEof(Fts3SegReader *pSeg){$/;" f file: +fts3SegReaderSort testdocs/sqlite3.c /^static void fts3SegReaderSort($/;" f file: +fts3SegReaderStart testdocs/sqlite3.c /^static int fts3SegReaderStart($/;" f file: +fts3SegReaderTermCmp testdocs/sqlite3.c /^static int fts3SegReaderTermCmp($/;" f file: +fts3SegWriterAdd testdocs/sqlite3.c /^static int fts3SegWriterAdd($/;" f file: +fts3SegWriterFlush testdocs/sqlite3.c /^static int fts3SegWriterFlush($/;" f file: +fts3SegWriterFree testdocs/sqlite3.c /^static void fts3SegWriterFree(SegmentWriter *pWriter){$/;" f file: +fts3SegmentIsMaxLevel testdocs/sqlite3.c /^static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){$/;" f file: +fts3SegmentMaxLevel testdocs/sqlite3.c /^static int fts3SegmentMaxLevel($/;" f file: +fts3SegmentMerge testdocs/sqlite3.c /^static int fts3SegmentMerge($/;" f file: +fts3SelectDocsize testdocs/sqlite3.c /^static int fts3SelectDocsize($/;" f file: +fts3SelectLeaf testdocs/sqlite3.c /^static int fts3SelectLeaf($/;" f file: +fts3SetEstimatedRows testdocs/sqlite3.c /^static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){$/;" f file: +fts3SetHasStat testdocs/sqlite3.c /^static int fts3SetHasStat(Fts3Table *p){$/;" f file: +fts3SetUniqueFlag testdocs/sqlite3.c /^static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){$/;" f file: +fts3SnippetAdvance testdocs/sqlite3.c /^static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){$/;" f file: +fts3SnippetDetails testdocs/sqlite3.c /^static void fts3SnippetDetails($/;" f file: +fts3SnippetFindPositions testdocs/sqlite3.c /^static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){$/;" f file: +fts3SnippetFunc testdocs/sqlite3.c /^static void fts3SnippetFunc($/;" f file: +fts3SnippetNextCandidate testdocs/sqlite3.c /^static int fts3SnippetNextCandidate(SnippetIter *pIter){$/;" f file: +fts3SnippetShift testdocs/sqlite3.c /^static int fts3SnippetShift($/;" f file: +fts3SnippetText testdocs/sqlite3.c /^static int fts3SnippetText($/;" f file: +fts3SpecialInsert testdocs/sqlite3.c /^static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){$/;" f file: +fts3SqlExec testdocs/sqlite3.c /^static void fts3SqlExec($/;" f file: +fts3SqlStmt testdocs/sqlite3.c /^static int fts3SqlStmt($/;" f file: +fts3StartNode testdocs/sqlite3.c /^static void fts3StartNode(Blob *pNode, int iHeight, sqlite3_int64 iChild){$/;" f file: +fts3StrCompare testdocs/sqlite3.c /^static int fts3StrCompare(const void *pKey1, int n1, const void *pKey2, int n2){$/;" f file: +fts3StrHash testdocs/sqlite3.c /^static int fts3StrHash(const void *pKey, int nKey){$/;" f file: +fts3StringAppend testdocs/sqlite3.c /^static int fts3StringAppend($/;" f file: +fts3SyncMethod testdocs/sqlite3.c /^static int fts3SyncMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3TermCmp testdocs/sqlite3.c /^static int fts3TermCmp($/;" f file: +fts3TermSegReaderCursor testdocs/sqlite3.c /^static int fts3TermSegReaderCursor($/;" f file: +fts3TermSelect testdocs/sqlite3.c /^static int fts3TermSelect($/;" f file: +fts3TermSelectFinishMerge testdocs/sqlite3.c /^static int fts3TermSelectFinishMerge(Fts3Table *p, TermSelect *pTS){$/;" f file: +fts3TermSelectMerge testdocs/sqlite3.c /^static int fts3TermSelectMerge($/;" f file: +fts3TokenizerEnabled testdocs/sqlite3.c /^static int fts3TokenizerEnabled(sqlite3_context *context){$/;" f file: +fts3TokenizerFunc testdocs/sqlite3.c /^static void fts3TokenizerFunc($/;" f file: +fts3TreeFinishNode testdocs/sqlite3.c /^static int fts3TreeFinishNode($/;" f file: +fts3TruncateNode testdocs/sqlite3.c /^static int fts3TruncateNode($/;" f file: +fts3TruncateSegment testdocs/sqlite3.c /^static int fts3TruncateSegment($/;" f file: +fts3UpdateDocTotals testdocs/sqlite3.c /^static void fts3UpdateDocTotals($/;" f file: +fts3UpdateMethod testdocs/sqlite3.c /^static int fts3UpdateMethod($/;" f file: +fts3WriteExprList testdocs/sqlite3.c /^static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){$/;" f file: +fts3WriteSegdir testdocs/sqlite3.c /^static int fts3WriteSegdir($/;" f file: +fts3WriteSegment testdocs/sqlite3.c /^static int fts3WriteSegment($/;" f file: +fts3Writelock testdocs/sqlite3.c /^static int fts3Writelock(Fts3Table *p){$/;" f file: +fts3_isalnum testdocs/sqlite3.c /^static int fts3_isalnum(int x){$/;" f file: +fts3auxBestIndexMethod testdocs/sqlite3.c /^static int fts3auxBestIndexMethod($/;" f file: +fts3auxCloseMethod testdocs/sqlite3.c /^static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3auxColumnMethod testdocs/sqlite3.c /^static int fts3auxColumnMethod($/;" f file: +fts3auxConnectMethod testdocs/sqlite3.c /^static int fts3auxConnectMethod($/;" f file: +fts3auxDisconnectMethod testdocs/sqlite3.c /^static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3auxEofMethod testdocs/sqlite3.c /^static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3auxFilterMethod testdocs/sqlite3.c /^static int fts3auxFilterMethod($/;" f file: +fts3auxGrowStatArray testdocs/sqlite3.c /^static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){$/;" f file: +fts3auxNextMethod testdocs/sqlite3.c /^static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3auxOpenMethod testdocs/sqlite3.c /^static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){$/;" f file: +fts3auxRowidMethod testdocs/sqlite3.c /^static int fts3auxRowidMethod($/;" f file: +fts3isspace testdocs/sqlite3.c /^static int fts3isspace(char c){$/;" f file: +fts3tokBestIndexMethod testdocs/sqlite3.c /^static int fts3tokBestIndexMethod($/;" f file: +fts3tokCloseMethod testdocs/sqlite3.c /^static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3tokColumnMethod testdocs/sqlite3.c /^static int fts3tokColumnMethod($/;" f file: +fts3tokConnectMethod testdocs/sqlite3.c /^static int fts3tokConnectMethod($/;" f file: +fts3tokDequoteArray testdocs/sqlite3.c /^static int fts3tokDequoteArray($/;" f file: +fts3tokDisconnectMethod testdocs/sqlite3.c /^static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){$/;" f file: +fts3tokEofMethod testdocs/sqlite3.c /^static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3tokFilterMethod testdocs/sqlite3.c /^static int fts3tokFilterMethod($/;" f file: +fts3tokNextMethod testdocs/sqlite3.c /^static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts3tokOpenMethod testdocs/sqlite3.c /^static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){$/;" f file: +fts3tokQueryTokenizer testdocs/sqlite3.c /^static int fts3tokQueryTokenizer($/;" f file: +fts3tokResetCursor testdocs/sqlite3.c /^static void fts3tokResetCursor(Fts3tokCursor *pCsr){$/;" f file: +fts3tokRowidMethod testdocs/sqlite3.c /^static int fts3tokRowidMethod($/;" f file: +fts5AllocateSegid testdocs/sqlite3.c /^static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){$/;" f file: +fts5ApiCallback testdocs/sqlite3.c /^static void fts5ApiCallback($/;" f file: +fts5ApiColumnCount testdocs/sqlite3.c /^static int fts5ApiColumnCount(Fts5Context *pCtx){$/;" f file: +fts5ApiColumnSize testdocs/sqlite3.c /^static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){$/;" f file: +fts5ApiColumnText testdocs/sqlite3.c /^static int fts5ApiColumnText($/;" f file: +fts5ApiColumnTotalSize testdocs/sqlite3.c /^static int fts5ApiColumnTotalSize($/;" f file: +fts5ApiGetAuxdata testdocs/sqlite3.c /^static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){$/;" f file: +fts5ApiInst testdocs/sqlite3.c /^static int fts5ApiInst($/;" f file: +fts5ApiInstCount testdocs/sqlite3.c /^static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){$/;" f file: +fts5ApiInvoke testdocs/sqlite3.c /^static void fts5ApiInvoke($/;" f file: +fts5ApiPhraseCount testdocs/sqlite3.c /^static int fts5ApiPhraseCount(Fts5Context *pCtx){$/;" f file: +fts5ApiPhraseFirst testdocs/sqlite3.c /^static int fts5ApiPhraseFirst($/;" f file: +fts5ApiPhraseFirstColumn testdocs/sqlite3.c /^static int fts5ApiPhraseFirstColumn($/;" f file: +fts5ApiPhraseNext testdocs/sqlite3.c /^static void fts5ApiPhraseNext($/;" f file: +fts5ApiPhraseNextColumn testdocs/sqlite3.c /^static void fts5ApiPhraseNextColumn($/;" f file: +fts5ApiPhraseSize testdocs/sqlite3.c /^static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){$/;" f file: +fts5ApiQueryPhrase testdocs/sqlite3.c /^static int fts5ApiQueryPhrase($/;" f file: +fts5ApiRowCount testdocs/sqlite3.c /^static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){$/;" f file: +fts5ApiRowid testdocs/sqlite3.c /^static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){$/;" f file: +fts5ApiSetAuxdata testdocs/sqlite3.c /^static int fts5ApiSetAuxdata($/;" f file: +fts5ApiTokenize testdocs/sqlite3.c /^static int fts5ApiTokenize($/;" f file: +fts5ApiUserData testdocs/sqlite3.c /^static void *fts5ApiUserData(Fts5Context *pCtx){$/;" f file: +fts5AppendPoslist testdocs/sqlite3.c /^static void fts5AppendPoslist($/;" f file: +fts5AppendRowid testdocs/sqlite3.c /^static void fts5AppendRowid($/;" f file: +fts5AsciiAddExceptions testdocs/sqlite3.c /^static void fts5AsciiAddExceptions($/;" f file: +fts5AsciiCreate testdocs/sqlite3.c /^static int fts5AsciiCreate($/;" f file: +fts5AsciiDelete testdocs/sqlite3.c /^static void fts5AsciiDelete(Fts5Tokenizer *p){$/;" f file: +fts5AsciiTokenize testdocs/sqlite3.c /^static int fts5AsciiTokenize($/;" f file: +fts5AssertComparisonResult testdocs/sqlite3.c /^static void fts5AssertComparisonResult($/;" f file: +fts5AssertMultiIterSetup testdocs/sqlite3.c /^# define fts5AssertMultiIterSetup(/;" d file: +fts5AssertMultiIterSetup testdocs/sqlite3.c /^static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){$/;" f file: +fts5BeginMethod testdocs/sqlite3.c /^static int fts5BeginMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5BestIndexMethod testdocs/sqlite3.c /^static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){$/;" f file: +fts5Bm25Function testdocs/sqlite3.c /^static void fts5Bm25Function($/;" f file: +fts5Bm25GetData testdocs/sqlite3.c /^static int fts5Bm25GetData($/;" f file: +fts5BufferAppendBlob testdocs/sqlite3.c /^#define fts5BufferAppendBlob(/;" d file: +fts5BufferAppendVarint testdocs/sqlite3.c /^#define fts5BufferAppendVarint(/;" d file: +fts5BufferCompare testdocs/sqlite3.c /^static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){$/;" f file: +fts5BufferCompareBlob testdocs/sqlite3.c /^static int fts5BufferCompareBlob($/;" f file: +fts5BufferFree testdocs/sqlite3.c /^#define fts5BufferFree(/;" d file: +fts5BufferGrow testdocs/sqlite3.c /^#define fts5BufferGrow(/;" d file: +fts5BufferSafeAppendBlob testdocs/sqlite3.c /^#define fts5BufferSafeAppendBlob(/;" d file: +fts5BufferSafeAppendVarint testdocs/sqlite3.c /^#define fts5BufferSafeAppendVarint(/;" d file: +fts5BufferSet testdocs/sqlite3.c /^#define fts5BufferSet(/;" d file: +fts5BufferSwap testdocs/sqlite3.c /^static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){$/;" f file: +fts5BufferZero testdocs/sqlite3.c /^#define fts5BufferZero(/;" d file: +fts5CInstIterInit testdocs/sqlite3.c /^static int fts5CInstIterInit($/;" f file: +fts5CInstIterNext testdocs/sqlite3.c /^static int fts5CInstIterNext(CInstIter *pIter){$/;" f file: +fts5CacheInstArray testdocs/sqlite3.c /^static int fts5CacheInstArray(Fts5Cursor *pCsr){$/;" f file: +fts5CheckTransactionState testdocs/sqlite3.c /^# define fts5CheckTransactionState(/;" d file: +fts5CheckTransactionState testdocs/sqlite3.c /^static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){$/;" f file: +fts5ChunkIterate testdocs/sqlite3.c /^static void fts5ChunkIterate($/;" f file: +fts5CloneColset testdocs/sqlite3.c /^static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){$/;" f file: +fts5CloseMethod testdocs/sqlite3.c /^static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts5CloseReader testdocs/sqlite3.c /^static void fts5CloseReader(Fts5Index *p){$/;" f file: +fts5ColumnMethod testdocs/sqlite3.c /^static int fts5ColumnMethod($/;" f file: +fts5ColumnSizeCb testdocs/sqlite3.c /^static int fts5ColumnSizeCb($/;" f file: +fts5CommitMethod testdocs/sqlite3.c /^static int fts5CommitMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5ConfigDefaultTokenizer testdocs/sqlite3.c /^static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){$/;" f file: +fts5ConfigGobbleWord testdocs/sqlite3.c /^static const char *fts5ConfigGobbleWord($/;" f file: +fts5ConfigMakeExprlist testdocs/sqlite3.c /^static int fts5ConfigMakeExprlist(Fts5Config *p){$/;" f file: +fts5ConfigParseColumn testdocs/sqlite3.c /^static int fts5ConfigParseColumn($/;" f file: +fts5ConfigParseSpecial testdocs/sqlite3.c /^static int fts5ConfigParseSpecial($/;" f file: +fts5ConfigSetEnum testdocs/sqlite3.c /^static int fts5ConfigSetEnum($/;" f file: +fts5ConfigSkipArgs testdocs/sqlite3.c /^static const char *fts5ConfigSkipArgs(const char *pIn){$/;" f file: +fts5ConfigSkipBareword testdocs/sqlite3.c /^static const char *fts5ConfigSkipBareword(const char *pIn){$/;" f file: +fts5ConfigSkipLiteral testdocs/sqlite3.c /^static const char *fts5ConfigSkipLiteral(const char *pIn){$/;" f file: +fts5ConfigSkipWhitespace testdocs/sqlite3.c /^static const char *fts5ConfigSkipWhitespace(const char *pIn){$/;" f file: +fts5ConnectMethod testdocs/sqlite3.c /^static int fts5ConnectMethod($/;" f file: +fts5CountCb testdocs/sqlite3.c /^static int fts5CountCb($/;" f file: +fts5CreateAux testdocs/sqlite3.c /^static int fts5CreateAux($/;" f file: +fts5CreateMethod testdocs/sqlite3.c /^static int fts5CreateMethod($/;" f file: +fts5CreateTokenizer testdocs/sqlite3.c /^static int fts5CreateTokenizer($/;" f file: +fts5CsrNewrow testdocs/sqlite3.c /^static void fts5CsrNewrow(Fts5Cursor *pCsr){$/;" f file: +fts5CsrPoslist testdocs/sqlite3.c /^static int fts5CsrPoslist($/;" f file: +fts5CursorFirst testdocs/sqlite3.c /^static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){$/;" f file: +fts5CursorFirstSorted testdocs/sqlite3.c /^static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){$/;" f file: +fts5CursorFromCsrid testdocs/sqlite3.c /^static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){$/;" f file: +fts5CursorParseRank testdocs/sqlite3.c /^static int fts5CursorParseRank($/;" f file: +fts5CursorReseek testdocs/sqlite3.c /^static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){$/;" f file: +fts5CursorRowid testdocs/sqlite3.c /^static i64 fts5CursorRowid(Fts5Cursor *pCsr){$/;" f file: +fts5DataDelete testdocs/sqlite3.c /^static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){$/;" f file: +fts5DataRead testdocs/sqlite3.c /^static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){$/;" f file: +fts5DataRelease testdocs/sqlite3.c /^static void fts5DataRelease(Fts5Data *pData){$/;" f file: +fts5DataRemoveSegment testdocs/sqlite3.c /^static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){$/;" f file: +fts5DataWrite testdocs/sqlite3.c /^static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){$/;" f file: +fts5DebugRowid testdocs/sqlite3.c /^static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){$/;" f file: +fts5DebugStructure testdocs/sqlite3.c /^static void fts5DebugStructure($/;" f file: +fts5DecodeAverages testdocs/sqlite3.c /^static void fts5DecodeAverages($/;" f file: +fts5DecodeDoclist testdocs/sqlite3.c /^static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){$/;" f file: +fts5DecodeFunction testdocs/sqlite3.c /^static void fts5DecodeFunction($/;" f file: +fts5DecodePoslist testdocs/sqlite3.c /^static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){$/;" f file: +fts5DecodeRowid testdocs/sqlite3.c /^static void fts5DecodeRowid($/;" f file: +fts5DecodeRowidList testdocs/sqlite3.c /^static void fts5DecodeRowidList($/;" f file: +fts5DecodeStructure testdocs/sqlite3.c /^static void fts5DecodeStructure($/;" f file: +fts5Dequote testdocs/sqlite3.c /^static int fts5Dequote(char *z){$/;" f file: +fts5DestroyMethod testdocs/sqlite3.c /^static int fts5DestroyMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5DisconnectMethod testdocs/sqlite3.c /^static int fts5DisconnectMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5DlidxExtractFirstRowid testdocs/sqlite3.c /^static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){$/;" f file: +fts5DlidxIterEof testdocs/sqlite3.c /^static int fts5DlidxIterEof(Fts5Index *p, Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxIterFirst testdocs/sqlite3.c /^static int fts5DlidxIterFirst(Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxIterFree testdocs/sqlite3.c /^static void fts5DlidxIterFree(Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxIterInit testdocs/sqlite3.c /^static Fts5DlidxIter *fts5DlidxIterInit($/;" f file: +fts5DlidxIterLast testdocs/sqlite3.c /^static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxIterNext testdocs/sqlite3.c /^static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxIterNextR testdocs/sqlite3.c /^static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){$/;" f file: +fts5DlidxIterPgno testdocs/sqlite3.c /^static int fts5DlidxIterPgno(Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxIterPrev testdocs/sqlite3.c /^static int fts5DlidxIterPrev(Fts5Index *p, Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxIterPrevR testdocs/sqlite3.c /^static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){$/;" f file: +fts5DlidxIterRowid testdocs/sqlite3.c /^static i64 fts5DlidxIterRowid(Fts5DlidxIter *pIter){$/;" f file: +fts5DlidxLvlNext testdocs/sqlite3.c /^static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){$/;" f file: +fts5DlidxLvlPrev testdocs/sqlite3.c /^static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){$/;" f file: +fts5DoclistIterInit testdocs/sqlite3.c /^static void fts5DoclistIterInit($/;" f file: +fts5DoclistIterNext testdocs/sqlite3.c /^static void fts5DoclistIterNext(Fts5DoclistIter *pIter){$/;" f file: +fts5EntryKey testdocs/sqlite3.c /^#define fts5EntryKey(/;" d file: +fts5EofMethod testdocs/sqlite3.c /^static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts5ExecPrintf testdocs/sqlite3.c /^static int fts5ExecPrintf($/;" f file: +fts5ExprAddChildren testdocs/sqlite3.c /^static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){$/;" f file: +fts5ExprAdvanceto testdocs/sqlite3.c /^static int fts5ExprAdvanceto($/;" f file: +fts5ExprAssignXNext testdocs/sqlite3.c /^static void fts5ExprAssignXNext(Fts5ExprNode *pNode){$/;" f file: +fts5ExprCheckPoslists testdocs/sqlite3.c /^static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){$/;" f file: +fts5ExprClearPoslists testdocs/sqlite3.c /^static void fts5ExprClearPoslists(Fts5ExprNode *pNode){$/;" f file: +fts5ExprColsetTest testdocs/sqlite3.c /^static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){$/;" f file: +fts5ExprFold testdocs/sqlite3.c /^static void fts5ExprFold($/;" f file: +fts5ExprFunction testdocs/sqlite3.c /^static void fts5ExprFunction($/;" f file: +fts5ExprFunctionHr testdocs/sqlite3.c /^static void fts5ExprFunctionHr($/;" f file: +fts5ExprFunctionTcl testdocs/sqlite3.c /^static void fts5ExprFunctionTcl($/;" f file: +fts5ExprGetToken testdocs/sqlite3.c /^static int fts5ExprGetToken($/;" f file: +fts5ExprIsAlnum testdocs/sqlite3.c /^static void fts5ExprIsAlnum($/;" f file: +fts5ExprIsspace testdocs/sqlite3.c /^static int fts5ExprIsspace(char t){$/;" f file: +fts5ExprNearInitAll testdocs/sqlite3.c /^static int fts5ExprNearInitAll($/;" f file: +fts5ExprNearIsMatch testdocs/sqlite3.c /^static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){$/;" f file: +fts5ExprNearTest testdocs/sqlite3.c /^static int fts5ExprNearTest($/;" f file: +fts5ExprNodeFirst testdocs/sqlite3.c /^static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){$/;" f file: +fts5ExprNodeNext testdocs/sqlite3.c /^#define fts5ExprNodeNext(/;" d file: +fts5ExprNodeNext_AND testdocs/sqlite3.c /^static int fts5ExprNodeNext_AND($/;" f file: +fts5ExprNodeNext_NOT testdocs/sqlite3.c /^static int fts5ExprNodeNext_NOT($/;" f file: +fts5ExprNodeNext_OR testdocs/sqlite3.c /^static int fts5ExprNodeNext_OR($/;" f file: +fts5ExprNodeNext_STRING testdocs/sqlite3.c /^static int fts5ExprNodeNext_STRING($/;" f file: +fts5ExprNodeNext_TERM testdocs/sqlite3.c /^static int fts5ExprNodeNext_TERM($/;" f file: +fts5ExprNodeTest testdocs/sqlite3.c /^static int fts5ExprNodeTest($/;" f file: +fts5ExprNodeTest_AND testdocs/sqlite3.c /^static int fts5ExprNodeTest_AND($/;" f file: +fts5ExprNodeTest_NOT testdocs/sqlite3.c /^static int fts5ExprNodeTest_NOT($/;" f file: +fts5ExprNodeTest_OR testdocs/sqlite3.c /^static void fts5ExprNodeTest_OR($/;" f file: +fts5ExprNodeTest_STRING testdocs/sqlite3.c /^static int fts5ExprNodeTest_STRING($/;" f file: +fts5ExprNodeTest_TERM testdocs/sqlite3.c /^static int fts5ExprNodeTest_TERM($/;" f file: +fts5ExprNodeZeroPoslist testdocs/sqlite3.c /^static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){$/;" f file: +fts5ExprPhraseFree testdocs/sqlite3.c /^static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){$/;" f file: +fts5ExprPhraseIsMatch testdocs/sqlite3.c /^static int fts5ExprPhraseIsMatch($/;" f file: +fts5ExprPopulatePoslistsCb testdocs/sqlite3.c /^static int fts5ExprPopulatePoslistsCb($/;" f file: +fts5ExprPrint testdocs/sqlite3.c /^static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){$/;" f file: +fts5ExprPrintTcl testdocs/sqlite3.c /^static char *fts5ExprPrintTcl($/;" f file: +fts5ExprSetEof testdocs/sqlite3.c /^static void fts5ExprSetEof(Fts5ExprNode *pNode){$/;" f file: +fts5ExprSynonymAdvanceto testdocs/sqlite3.c /^static int fts5ExprSynonymAdvanceto($/;" f file: +fts5ExprSynonymList testdocs/sqlite3.c /^static int fts5ExprSynonymList($/;" f file: +fts5ExprSynonymRowid testdocs/sqlite3.c /^static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){$/;" f file: +fts5ExprTermPrint testdocs/sqlite3.c /^static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){$/;" f file: +fts5FastGetVarint32 testdocs/sqlite3.c /^#define fts5FastGetVarint32(/;" d file: +fts5FilterMethod testdocs/sqlite3.c /^static int fts5FilterMethod($/;" f file: +fts5FindAuxiliary testdocs/sqlite3.c /^static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){$/;" f file: +fts5FindFunctionMethod testdocs/sqlite3.c /^static int fts5FindFunctionMethod($/;" f file: +fts5FindRankFunction testdocs/sqlite3.c /^static int fts5FindRankFunction(Fts5Cursor *pCsr){$/;" f file: +fts5FindTokenizer testdocs/sqlite3.c /^static int fts5FindTokenizer($/;" f file: +fts5FlushOneHash testdocs/sqlite3.c /^static void fts5FlushOneHash(Fts5Index *p){$/;" f file: +fts5FreeCursorComponents testdocs/sqlite3.c /^static void fts5FreeCursorComponents(Fts5Cursor *pCsr){$/;" f file: +fts5FreeVtab testdocs/sqlite3.c /^static void fts5FreeVtab(Fts5Table *pTab){$/;" f file: +fts5Fts5Func testdocs/sqlite3.c /^static void fts5Fts5Func($/;" f file: +fts5GetPoslistSize testdocs/sqlite3.c /^static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){$/;" f file: +fts5GetRowidLimit testdocs/sqlite3.c /^static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){$/;" f file: +fts5GetU16 testdocs/sqlite3.c /^static u16 fts5GetU16(const u8 *aIn){$/;" f file: +fts5GetVarint testdocs/sqlite3.c /^#define fts5GetVarint /;" d file: +fts5GetVarint32 testdocs/sqlite3.c /^#define fts5GetVarint32(/;" d file: +fts5HashAddPoslistSize testdocs/sqlite3.c /^static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){$/;" f file: +fts5HashEntryMerge testdocs/sqlite3.c /^static Fts5HashEntry *fts5HashEntryMerge($/;" f file: +fts5HashEntrySort testdocs/sqlite3.c /^static int fts5HashEntrySort($/;" f file: +fts5HashKey testdocs/sqlite3.c /^static unsigned int fts5HashKey(int nSlot, const u8 *p, int n){$/;" f file: +fts5HashKey2 testdocs/sqlite3.c /^static unsigned int fts5HashKey2(int nSlot, u8 b, const u8 *p, int n){$/;" f file: +fts5HashResize testdocs/sqlite3.c /^static int fts5HashResize(Fts5Hash *pHash){$/;" f file: +fts5HighlightAppend testdocs/sqlite3.c /^static void fts5HighlightAppend($/;" f file: +fts5HighlightCb testdocs/sqlite3.c /^static int fts5HighlightCb($/;" f file: +fts5HighlightFunction testdocs/sqlite3.c /^static void fts5HighlightFunction($/;" f file: +fts5IdxMalloc testdocs/sqlite3.c /^static void *fts5IdxMalloc(Fts5Index *p, int nByte){$/;" f file: +fts5IdxSelectStmt testdocs/sqlite3.c /^static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){$/;" f file: +fts5IndexAutomerge testdocs/sqlite3.c /^static void fts5IndexAutomerge($/;" f file: +fts5IndexCharlen testdocs/sqlite3.c /^static int fts5IndexCharlen(const char *pIn, int nIn){$/;" f file: +fts5IndexColsetTest testdocs/sqlite3.c /^static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){$/;" f file: +fts5IndexCrisismerge testdocs/sqlite3.c /^static void fts5IndexCrisismerge($/;" f file: +fts5IndexDataVersion testdocs/sqlite3.c /^static i64 fts5IndexDataVersion(Fts5Index *p){$/;" f file: +fts5IndexDiscardData testdocs/sqlite3.c /^static void fts5IndexDiscardData(Fts5Index *p){$/;" f file: +fts5IndexExtractCol testdocs/sqlite3.c /^static int fts5IndexExtractCol($/;" f file: +fts5IndexExtractColset testdocs/sqlite3.c /^static void fts5IndexExtractColset($/;" f file: +fts5IndexFlush testdocs/sqlite3.c /^static void fts5IndexFlush(Fts5Index *p){$/;" f file: +fts5IndexIntegrityCheckEmpty testdocs/sqlite3.c /^static void fts5IndexIntegrityCheckEmpty($/;" f file: +fts5IndexIntegrityCheckSegment testdocs/sqlite3.c /^static void fts5IndexIntegrityCheckSegment($/;" f file: +fts5IndexMerge testdocs/sqlite3.c /^static int fts5IndexMerge($/;" f file: +fts5IndexMergeLevel testdocs/sqlite3.c /^static void fts5IndexMergeLevel($/;" f file: +fts5IndexOptimizeStruct testdocs/sqlite3.c /^static Fts5Structure *fts5IndexOptimizeStruct($/;" f file: +fts5IndexPrepareStmt testdocs/sqlite3.c /^static int fts5IndexPrepareStmt($/;" f file: +fts5IndexReturn testdocs/sqlite3.c /^static int fts5IndexReturn(Fts5Index *p){$/;" f file: +fts5IndexSkipVarint testdocs/sqlite3.c /^#define fts5IndexSkipVarint(/;" d file: +fts5Init testdocs/sqlite3.c /^static int fts5Init(sqlite3 *db){$/;" f file: +fts5InitVtab testdocs/sqlite3.c /^static int fts5InitVtab($/;" f file: +fts5IntegrityCheckPgidx testdocs/sqlite3.c /^static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){$/;" f file: +fts5IsContentless testdocs/sqlite3.c /^static int fts5IsContentless(Fts5Table *pTab){$/;" f file: +fts5IterSetOutputCb testdocs/sqlite3.c /^static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){$/;" f file: +fts5IterSetOutputs_Col testdocs/sqlite3.c /^static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){$/;" f file: +fts5IterSetOutputs_Col100 testdocs/sqlite3.c /^static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){$/;" f file: +fts5IterSetOutputs_Full testdocs/sqlite3.c /^static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){$/;" f file: +fts5IterSetOutputs_Nocolset testdocs/sqlite3.c /^static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){$/;" f file: +fts5IterSetOutputs_None testdocs/sqlite3.c /^static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){$/;" f file: +fts5IterSetOutputs_Noop testdocs/sqlite3.c /^static void fts5IterSetOutputs_Noop(Fts5Iter *pUnused1, Fts5SegIter *pUnused2){$/;" f file: +fts5IterSetOutputs_ZeroColset testdocs/sqlite3.c /^static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){$/;" f file: +fts5LeafFirstRowidOff testdocs/sqlite3.c /^#define fts5LeafFirstRowidOff(/;" d file: +fts5LeafFirstTermOff testdocs/sqlite3.c /^static int fts5LeafFirstTermOff(Fts5Data *pLeaf){$/;" f file: +fts5LeafIsTermless testdocs/sqlite3.c /^#define fts5LeafIsTermless(/;" d file: +fts5LeafRead testdocs/sqlite3.c /^static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){$/;" f file: +fts5LeafSeek testdocs/sqlite3.c /^static void fts5LeafSeek($/;" f file: +fts5LeafTermOff testdocs/sqlite3.c /^#define fts5LeafTermOff(/;" d file: +fts5LocateTokenizer testdocs/sqlite3.c /^static Fts5TokenizerModule *fts5LocateTokenizer($/;" f file: +fts5LookaheadReaderInit testdocs/sqlite3.c /^static int fts5LookaheadReaderInit($/;" f file: +fts5LookaheadReaderNext testdocs/sqlite3.c /^static int fts5LookaheadReaderNext(Fts5LookaheadReader *p){$/;" f file: +fts5MergeAppendDocid testdocs/sqlite3.c /^#define fts5MergeAppendDocid(/;" d file: +fts5MergeChunkCallback testdocs/sqlite3.c /^static void fts5MergeChunkCallback($/;" f file: +fts5MergeColset testdocs/sqlite3.c /^static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){$/;" f file: +fts5MergePrefixLists testdocs/sqlite3.c /^static void fts5MergePrefixLists($/;" f file: +fts5MergeRowidLists testdocs/sqlite3.c /^static void fts5MergeRowidLists($/;" f file: +fts5ModuleDestroy testdocs/sqlite3.c /^static void fts5ModuleDestroy(void *pCtx){$/;" f file: +fts5MultiIterAdvanceRowid testdocs/sqlite3.c /^static int fts5MultiIterAdvanceRowid($/;" f file: +fts5MultiIterAdvanced testdocs/sqlite3.c /^static void fts5MultiIterAdvanced($/;" f file: +fts5MultiIterAlloc testdocs/sqlite3.c /^static Fts5Iter *fts5MultiIterAlloc($/;" f file: +fts5MultiIterDoCompare testdocs/sqlite3.c /^static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){$/;" f file: +fts5MultiIterEof testdocs/sqlite3.c /^static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){$/;" f file: +fts5MultiIterFree testdocs/sqlite3.c /^static void fts5MultiIterFree(Fts5Iter *pIter){$/;" f file: +fts5MultiIterIsEmpty testdocs/sqlite3.c /^static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5Iter *pIter){$/;" f file: +fts5MultiIterNew testdocs/sqlite3.c /^static void fts5MultiIterNew($/;" f file: +fts5MultiIterNew2 testdocs/sqlite3.c /^static void fts5MultiIterNew2($/;" f file: +fts5MultiIterNext testdocs/sqlite3.c /^static void fts5MultiIterNext($/;" f file: +fts5MultiIterNext2 testdocs/sqlite3.c /^static void fts5MultiIterNext2($/;" f file: +fts5MultiIterNextFrom testdocs/sqlite3.c /^static void fts5MultiIterNextFrom($/;" f file: +fts5MultiIterRowid testdocs/sqlite3.c /^static i64 fts5MultiIterRowid(Fts5Iter *pIter){$/;" f file: +fts5MultiIterSetEof testdocs/sqlite3.c /^static void fts5MultiIterSetEof(Fts5Iter *pIter){$/;" f file: +fts5MultiIterTerm testdocs/sqlite3.c /^static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){$/;" f file: +fts5NewTransaction testdocs/sqlite3.c /^static int fts5NewTransaction(Fts5Table *pTab){$/;" f file: +fts5NextMethod testdocs/sqlite3.c /^static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts5NextRowid testdocs/sqlite3.c /^static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){$/;" f file: +fts5NodeCompare testdocs/sqlite3.c /^static int fts5NodeCompare($/;" f file: +fts5OpenMethod testdocs/sqlite3.c /^static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){$/;" f file: +fts5ParseAlloc testdocs/sqlite3.c /^static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }$/;" f file: +fts5ParseColset testdocs/sqlite3.c /^static Fts5Colset *fts5ParseColset($/;" f file: +fts5ParseFree testdocs/sqlite3.c /^static void fts5ParseFree(void *p){ sqlite3_free(p); }$/;" f file: +fts5ParseSetColset testdocs/sqlite3.c /^static void fts5ParseSetColset($/;" f file: +fts5ParseStringFromToken testdocs/sqlite3.c /^static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){$/;" f file: +fts5ParseTokenize testdocs/sqlite3.c /^static int fts5ParseTokenize($/;" f file: +fts5PorterCb testdocs/sqlite3.c /^static int fts5PorterCb($/;" f file: +fts5PorterCreate testdocs/sqlite3.c /^static int fts5PorterCreate($/;" f file: +fts5PorterDelete testdocs/sqlite3.c /^static void fts5PorterDelete(Fts5Tokenizer *pTok){$/;" f file: +fts5PorterGobbleVC testdocs/sqlite3.c /^static int fts5PorterGobbleVC(char *zStem, int nStem, int bPrevCons){$/;" f file: +fts5PorterIsVowel testdocs/sqlite3.c /^static int fts5PorterIsVowel(char c, int bYIsVowel){$/;" f file: +fts5PorterStep1A testdocs/sqlite3.c /^static void fts5PorterStep1A(char *aBuf, int *pnBuf){$/;" f file: +fts5PorterStep1B testdocs/sqlite3.c /^static int fts5PorterStep1B(char *aBuf, int *pnBuf){$/;" f file: +fts5PorterStep1B2 testdocs/sqlite3.c /^static int fts5PorterStep1B2(char *aBuf, int *pnBuf){$/;" f file: +fts5PorterStep2 testdocs/sqlite3.c /^static int fts5PorterStep2(char *aBuf, int *pnBuf){$/;" f file: +fts5PorterStep3 testdocs/sqlite3.c /^static int fts5PorterStep3(char *aBuf, int *pnBuf){$/;" f file: +fts5PorterStep4 testdocs/sqlite3.c /^static int fts5PorterStep4(char *aBuf, int *pnBuf){$/;" f file: +fts5PorterTokenize testdocs/sqlite3.c /^static int fts5PorterTokenize($/;" f file: +fts5Porter_MEq1 testdocs/sqlite3.c /^static int fts5Porter_MEq1(char *zStem, int nStem){$/;" f file: +fts5Porter_MGt0 testdocs/sqlite3.c /^static int fts5Porter_MGt0(char *zStem, int nStem){$/;" f file: +fts5Porter_MGt1 testdocs/sqlite3.c /^static int fts5Porter_MGt1(char *zStem, int nStem){$/;" f file: +fts5Porter_MGt1_and_S_or_T testdocs/sqlite3.c /^static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){$/;" f file: +fts5Porter_Ostar testdocs/sqlite3.c /^static int fts5Porter_Ostar(char *zStem, int nStem){$/;" f file: +fts5Porter_Vowel testdocs/sqlite3.c /^static int fts5Porter_Vowel(char *zStem, int nStem){$/;" f file: +fts5PoslistBlob testdocs/sqlite3.c /^static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){$/;" f file: +fts5PoslistCallback testdocs/sqlite3.c /^static void fts5PoslistCallback($/;" f file: +fts5PoslistFilterCallback testdocs/sqlite3.c /^static void fts5PoslistFilterCallback($/;" f file: +fts5PoslistOffsetsCallback testdocs/sqlite3.c /^static void fts5PoslistOffsetsCallback($/;" f file: +fts5PoslistPrefix testdocs/sqlite3.c /^static int fts5PoslistPrefix(const u8 *aBuf, int nMax){$/;" f file: +fts5PrefixCompress testdocs/sqlite3.c /^static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){$/;" f file: +fts5PrepareStatement testdocs/sqlite3.c /^static int fts5PrepareStatement($/;" f file: +fts5PrintStructure testdocs/sqlite3.c /^# define fts5PrintStructure(/;" d file: +fts5PrintfAppend testdocs/sqlite3.c /^static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){$/;" f file: +fts5PutU16 testdocs/sqlite3.c /^static void fts5PutU16(u8 *aOut, u16 iVal){$/;" f file: +fts5PutVarint64 testdocs/sqlite3.c /^static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){$/;" f file: +fts5QueryCksum testdocs/sqlite3.c /^static int fts5QueryCksum($/;" f file: +fts5ReleaseMethod testdocs/sqlite3.c /^static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){$/;" f file: +fts5RenameMethod testdocs/sqlite3.c /^static int fts5RenameMethod($/;" f file: +fts5RollbackMethod testdocs/sqlite3.c /^static int fts5RollbackMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5RollbackToMethod testdocs/sqlite3.c /^static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){$/;" f file: +fts5RowidCmp testdocs/sqlite3.c /^static int fts5RowidCmp($/;" f file: +fts5RowidFunction testdocs/sqlite3.c /^static void fts5RowidFunction($/;" f file: +fts5RowidMethod testdocs/sqlite3.c /^static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){$/;" f file: +fts5SavepointMethod testdocs/sqlite3.c /^static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){$/;" f file: +fts5SeekCursor testdocs/sqlite3.c /^static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){$/;" f file: +fts5SegIterClear testdocs/sqlite3.c /^static void fts5SegIterClear(Fts5SegIter *pIter){$/;" f file: +fts5SegIterGotoPage testdocs/sqlite3.c /^static void fts5SegIterGotoPage($/;" f file: +fts5SegIterHashInit testdocs/sqlite3.c /^static void fts5SegIterHashInit($/;" f file: +fts5SegIterInit testdocs/sqlite3.c /^static void fts5SegIterInit($/;" f file: +fts5SegIterLoadDlidx testdocs/sqlite3.c /^static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){$/;" f file: +fts5SegIterLoadNPos testdocs/sqlite3.c /^static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){$/;" f file: +fts5SegIterLoadRowid testdocs/sqlite3.c /^static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){$/;" f file: +fts5SegIterLoadTerm testdocs/sqlite3.c /^static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){$/;" f file: +fts5SegIterNext testdocs/sqlite3.c /^static void fts5SegIterNext($/;" f file: +fts5SegIterNextFrom testdocs/sqlite3.c /^static void fts5SegIterNextFrom($/;" f file: +fts5SegIterNextPage testdocs/sqlite3.c /^static void fts5SegIterNextPage($/;" f file: +fts5SegIterNext_None testdocs/sqlite3.c /^static void fts5SegIterNext_None($/;" f file: +fts5SegIterNext_Reverse testdocs/sqlite3.c /^static void fts5SegIterNext_Reverse($/;" f file: +fts5SegIterReverse testdocs/sqlite3.c /^static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){$/;" f file: +fts5SegIterReverseInitPage testdocs/sqlite3.c /^static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){$/;" f file: +fts5SegIterReverseNewPage testdocs/sqlite3.c /^static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){$/;" f file: +fts5SegIterSeekInit testdocs/sqlite3.c /^static void fts5SegIterSeekInit($/;" f file: +fts5SegIterSetNext testdocs/sqlite3.c /^static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){$/;" f file: +fts5SegiterPoslist testdocs/sqlite3.c /^static void fts5SegiterPoslist($/;" f file: +fts5SegmentSize testdocs/sqlite3.c /^static int fts5SegmentSize(Fts5StructureSegment *pSeg){$/;" f file: +fts5SentenceFinderAdd testdocs/sqlite3.c /^static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){$/;" f file: +fts5SentenceFinderCb testdocs/sqlite3.c /^static int fts5SentenceFinderCb($/;" f file: +fts5SetUniqueFlag testdocs/sqlite3.c /^static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){$/;" f file: +fts5SetVtabError testdocs/sqlite3.c /^static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){$/;" f file: +fts5SetupPrefixIter testdocs/sqlite3.c /^static void fts5SetupPrefixIter($/;" f file: +fts5SnippetFunction testdocs/sqlite3.c /^static void fts5SnippetFunction($/;" f file: +fts5SnippetScore testdocs/sqlite3.c /^static int fts5SnippetScore($/;" f file: +fts5SorterNext testdocs/sqlite3.c /^static int fts5SorterNext(Fts5Cursor *pCsr){$/;" f file: +fts5SourceIdFunc testdocs/sqlite3.c /^static void fts5SourceIdFunc($/;" f file: +fts5SpecialDelete testdocs/sqlite3.c /^static int fts5SpecialDelete($/;" f file: +fts5SpecialInsert testdocs/sqlite3.c /^static int fts5SpecialInsert($/;" f file: +fts5SpecialMatch testdocs/sqlite3.c /^static int fts5SpecialMatch($/;" f file: +fts5StmtType testdocs/sqlite3.c /^static int fts5StmtType(Fts5Cursor *pCsr){$/;" f file: +fts5StorageCount testdocs/sqlite3.c /^static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){$/;" f file: +fts5StorageDecodeSizeArray testdocs/sqlite3.c /^static int fts5StorageDecodeSizeArray($/;" f file: +fts5StorageDeleteFromIndex testdocs/sqlite3.c /^static int fts5StorageDeleteFromIndex($/;" f file: +fts5StorageGetStmt testdocs/sqlite3.c /^static int fts5StorageGetStmt($/;" f file: +fts5StorageInsert testdocs/sqlite3.c /^static void fts5StorageInsert($/;" f file: +fts5StorageInsertCallback testdocs/sqlite3.c /^static int fts5StorageInsertCallback($/;" f file: +fts5StorageInsertDocsize testdocs/sqlite3.c /^static int fts5StorageInsertDocsize($/;" f file: +fts5StorageIntegrityCallback testdocs/sqlite3.c /^static int fts5StorageIntegrityCallback($/;" f file: +fts5StorageLoadTotals testdocs/sqlite3.c /^static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){$/;" f file: +fts5StorageNewRowid testdocs/sqlite3.c /^static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){$/;" f file: +fts5StorageRenameOne testdocs/sqlite3.c /^static void fts5StorageRenameOne($/;" f file: +fts5StorageSaveTotals testdocs/sqlite3.c /^static int fts5StorageSaveTotals(Fts5Storage *p){$/;" f file: +fts5StructureAddLevel testdocs/sqlite3.c /^static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){$/;" f file: +fts5StructureCountSegments testdocs/sqlite3.c /^static int fts5StructureCountSegments(Fts5Structure *pStruct){$/;" f file: +fts5StructureDecode testdocs/sqlite3.c /^static int fts5StructureDecode($/;" f file: +fts5StructureExtendLevel testdocs/sqlite3.c /^static void fts5StructureExtendLevel($/;" f file: +fts5StructureInvalidate testdocs/sqlite3.c /^static void fts5StructureInvalidate(Fts5Index *p){$/;" f file: +fts5StructurePromote testdocs/sqlite3.c /^static void fts5StructurePromote($/;" f file: +fts5StructurePromoteTo testdocs/sqlite3.c /^static void fts5StructurePromoteTo($/;" f file: +fts5StructureRead testdocs/sqlite3.c /^static Fts5Structure *fts5StructureRead(Fts5Index *p){$/;" f file: +fts5StructureReadUncached testdocs/sqlite3.c /^static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){$/;" f file: +fts5StructureRef testdocs/sqlite3.c /^static void fts5StructureRef(Fts5Structure *pStruct){$/;" f file: +fts5StructureRelease testdocs/sqlite3.c /^static void fts5StructureRelease(Fts5Structure *pStruct){$/;" f file: +fts5StructureWrite testdocs/sqlite3.c /^static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){$/;" f file: +fts5SyncMethod testdocs/sqlite3.c /^static int fts5SyncMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5TestDlidxReverse testdocs/sqlite3.c /^# define fts5TestDlidxReverse(/;" d file: +fts5TestDlidxReverse testdocs/sqlite3.c /^static void fts5TestDlidxReverse($/;" f file: +fts5TestTerm testdocs/sqlite3.c /^# define fts5TestTerm(/;" d file: +fts5TestTerm testdocs/sqlite3.c /^static void fts5TestTerm($/;" f file: +fts5TrimSegments testdocs/sqlite3.c /^static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){$/;" f file: +fts5TripCursors testdocs/sqlite3.c /^static void fts5TripCursors(Fts5Table *pTab){$/;" f file: +fts5UnicodeAddExceptions testdocs/sqlite3.c /^static int fts5UnicodeAddExceptions($/;" f file: +fts5UnicodeCreate testdocs/sqlite3.c /^static int fts5UnicodeCreate($/;" f file: +fts5UnicodeDelete testdocs/sqlite3.c /^static void fts5UnicodeDelete(Fts5Tokenizer *pTok){$/;" f file: +fts5UnicodeIsAlnum testdocs/sqlite3.c /^static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){$/;" f file: +fts5UnicodeIsException testdocs/sqlite3.c /^static int fts5UnicodeIsException(Unicode61Tokenizer *p, int iCode){$/;" f file: +fts5UnicodeTokenize testdocs/sqlite3.c /^static int fts5UnicodeTokenize($/;" f file: +fts5UpdateMethod testdocs/sqlite3.c /^static int fts5UpdateMethod($/;" f file: +fts5VocabBestIndexMethod testdocs/sqlite3.c /^static int fts5VocabBestIndexMethod($/;" f file: +fts5VocabCloseMethod testdocs/sqlite3.c /^static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts5VocabColumnMethod testdocs/sqlite3.c /^static int fts5VocabColumnMethod($/;" f file: +fts5VocabConnectMethod testdocs/sqlite3.c /^static int fts5VocabConnectMethod($/;" f file: +fts5VocabCreateMethod testdocs/sqlite3.c /^static int fts5VocabCreateMethod($/;" f file: +fts5VocabDestroyMethod testdocs/sqlite3.c /^static int fts5VocabDestroyMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5VocabDisconnectMethod testdocs/sqlite3.c /^static int fts5VocabDisconnectMethod(sqlite3_vtab *pVtab){$/;" f file: +fts5VocabEofMethod testdocs/sqlite3.c /^static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts5VocabFilterMethod testdocs/sqlite3.c /^static int fts5VocabFilterMethod($/;" f file: +fts5VocabInitVtab testdocs/sqlite3.c /^static int fts5VocabInitVtab($/;" f file: +fts5VocabNextMethod testdocs/sqlite3.c /^static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){$/;" f file: +fts5VocabOpenMethod testdocs/sqlite3.c /^static int fts5VocabOpenMethod($/;" f file: +fts5VocabResetCursor testdocs/sqlite3.c /^static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){$/;" f file: +fts5VocabRowidMethod testdocs/sqlite3.c /^static int fts5VocabRowidMethod($/;" f file: +fts5VocabTableType testdocs/sqlite3.c /^static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){$/;" f file: +fts5WriteAppendPoslistData testdocs/sqlite3.c /^static void fts5WriteAppendPoslistData($/;" f file: +fts5WriteAppendRowid testdocs/sqlite3.c /^static void fts5WriteAppendRowid($/;" f file: +fts5WriteAppendTerm testdocs/sqlite3.c /^static void fts5WriteAppendTerm($/;" f file: +fts5WriteBtreeNoTerm testdocs/sqlite3.c /^static void fts5WriteBtreeNoTerm($/;" f file: +fts5WriteBtreeTerm testdocs/sqlite3.c /^static void fts5WriteBtreeTerm($/;" f file: +fts5WriteDlidxAppend testdocs/sqlite3.c /^static void fts5WriteDlidxAppend($/;" f file: +fts5WriteDlidxClear testdocs/sqlite3.c /^static void fts5WriteDlidxClear($/;" f file: +fts5WriteDlidxGrow testdocs/sqlite3.c /^static int fts5WriteDlidxGrow($/;" f file: +fts5WriteFinish testdocs/sqlite3.c /^static void fts5WriteFinish($/;" f file: +fts5WriteFlushBtree testdocs/sqlite3.c /^static void fts5WriteFlushBtree(Fts5Index *p, Fts5SegWriter *pWriter){$/;" f file: +fts5WriteFlushDlidx testdocs/sqlite3.c /^static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){$/;" f file: +fts5WriteFlushLeaf testdocs/sqlite3.c /^static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){$/;" f file: +fts5WriteInit testdocs/sqlite3.c /^static void fts5WriteInit($/;" f file: +fts5YYACTIONTYPE testdocs/sqlite3.c /^#define fts5YYACTIONTYPE /;" d file: +fts5YYCODETYPE testdocs/sqlite3.c /^#define fts5YYCODETYPE /;" d file: +fts5YYMALLOCARGTYPE testdocs/sqlite3.c /^# define fts5YYMALLOCARGTYPE /;" d file: +fts5YYMALLOCARGTYPE testdocs/sqlite3.c /^#define fts5YYMALLOCARGTYPE /;" d file: +fts5YYMINORTYPE testdocs/sqlite3.c /^} fts5YYMINORTYPE;$/;" t typeref:union:__anon38 file: +fts5YYNOCODE testdocs/sqlite3.c /^#define fts5YYNOCODE /;" d file: +fts5YYNOERRORRECOVERY testdocs/sqlite3.c /^#define fts5YYNOERRORRECOVERY /;" d file: +fts5YYNRULE testdocs/sqlite3.c /^#define fts5YYNRULE /;" d file: +fts5YYNSTATE testdocs/sqlite3.c /^#define fts5YYNSTATE /;" d file: +fts5YYPARSEFREENOTNULL testdocs/sqlite3.c /^#define fts5YYPARSEFREENOTNULL /;" d file: +fts5YYSTACKDEPTH testdocs/sqlite3.c /^#define fts5YYSTACKDEPTH /;" d file: +fts5YY_ACCEPT_ACTION testdocs/sqlite3.c /^#define fts5YY_ACCEPT_ACTION /;" d file: +fts5YY_ACTTAB_COUNT testdocs/sqlite3.c /^#define fts5YY_ACTTAB_COUNT /;" d file: +fts5YY_ERROR_ACTION testdocs/sqlite3.c /^#define fts5YY_ERROR_ACTION /;" d file: +fts5YY_MAX_REDUCE testdocs/sqlite3.c /^#define fts5YY_MAX_REDUCE /;" d file: +fts5YY_MAX_SHIFT testdocs/sqlite3.c /^#define fts5YY_MAX_SHIFT /;" d file: +fts5YY_MAX_SHIFTREDUCE testdocs/sqlite3.c /^#define fts5YY_MAX_SHIFTREDUCE /;" d file: +fts5YY_MIN_REDUCE testdocs/sqlite3.c /^#define fts5YY_MIN_REDUCE /;" d file: +fts5YY_MIN_SHIFTREDUCE testdocs/sqlite3.c /^#define fts5YY_MIN_SHIFTREDUCE /;" d file: +fts5YY_NO_ACTION testdocs/sqlite3.c /^#define fts5YY_NO_ACTION /;" d file: +fts5YY_REDUCE_COUNT testdocs/sqlite3.c /^#define fts5YY_REDUCE_COUNT /;" d file: +fts5YY_REDUCE_MAX testdocs/sqlite3.c /^#define fts5YY_REDUCE_MAX /;" d file: +fts5YY_REDUCE_MIN testdocs/sqlite3.c /^#define fts5YY_REDUCE_MIN /;" d file: +fts5YY_REDUCE_USE_DFLT testdocs/sqlite3.c /^#define fts5YY_REDUCE_USE_DFLT /;" d file: +fts5YY_SHIFT_COUNT testdocs/sqlite3.c /^#define fts5YY_SHIFT_COUNT /;" d file: +fts5YY_SHIFT_MAX testdocs/sqlite3.c /^#define fts5YY_SHIFT_MAX /;" d file: +fts5YY_SHIFT_MIN testdocs/sqlite3.c /^#define fts5YY_SHIFT_MIN /;" d file: +fts5YY_SHIFT_USE_DFLT testdocs/sqlite3.c /^#define fts5YY_SHIFT_USE_DFLT /;" d file: +fts5_api testdocs/sqlite3.c /^struct fts5_api {$/;" s file: +fts5_api testdocs/sqlite3.c /^typedef struct fts5_api fts5_api;$/;" t typeref:struct:fts5_api file: +fts5_dri testdocs/sqlite3.c /^#define fts5_dri(/;" d file: +fts5_extension_function testdocs/sqlite3.c /^typedef void (*fts5_extension_function)($/;" t file: +fts5_isdigit testdocs/sqlite3.c /^static int fts5_isdigit(char a){$/;" f file: +fts5_isopenquote testdocs/sqlite3.c /^static int fts5_isopenquote(char x){$/;" f file: +fts5_iswhitespace testdocs/sqlite3.c /^static int fts5_iswhitespace(char x){$/;" f file: +fts5_remove_diacritic testdocs/sqlite3.c /^static int fts5_remove_diacritic(int c){$/;" f file: +fts5_tokenizer testdocs/sqlite3.c /^struct fts5_tokenizer {$/;" s file: +fts5_tokenizer testdocs/sqlite3.c /^typedef struct fts5_tokenizer fts5_tokenizer;$/;" t typeref:struct:fts5_tokenizer file: +fts5yy0 testdocs/sqlite3.c /^ sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0;$/;" m union:__anon38 file: +fts5yy11 testdocs/sqlite3.c /^ Fts5Colset* fts5yy11;$/;" m union:__anon38 file: +fts5yy24 testdocs/sqlite3.c /^ Fts5ExprNode* fts5yy24;$/;" m union:__anon38 file: +fts5yy4 testdocs/sqlite3.c /^ int fts5yy4;$/;" m union:__anon38 file: +fts5yy46 testdocs/sqlite3.c /^ Fts5ExprNearset* fts5yy46;$/;" m union:__anon38 file: +fts5yy53 testdocs/sqlite3.c /^ Fts5ExprPhrase* fts5yy53;$/;" m union:__anon38 file: +fts5yyFallback testdocs/sqlite3.c /^static const fts5YYCODETYPE fts5yyFallback[] = {$/;" v file: +fts5yyGrowStack testdocs/sqlite3.c /^static int fts5yyGrowStack(fts5yyParser *p){$/;" f file: +fts5yyParser testdocs/sqlite3.c /^struct fts5yyParser {$/;" s file: +fts5yyParser testdocs/sqlite3.c /^typedef struct fts5yyParser fts5yyParser;$/;" t typeref:struct:fts5yyParser file: +fts5yyRuleInfo testdocs/sqlite3.c /^} fts5yyRuleInfo[] = {$/;" v typeref:struct:__anon39 file: +fts5yyRuleName testdocs/sqlite3.c /^static const char *const fts5yyRuleName[] = {$/;" v file: +fts5yyStackEntry testdocs/sqlite3.c /^struct fts5yyStackEntry {$/;" s file: +fts5yyStackEntry testdocs/sqlite3.c /^typedef struct fts5yyStackEntry fts5yyStackEntry;$/;" t typeref:struct:fts5yyStackEntry file: +fts5yyStackOverflow testdocs/sqlite3.c /^static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){$/;" f file: +fts5yyTokenName testdocs/sqlite3.c /^static const char *const fts5yyTokenName[] = {$/;" v file: +fts5yyTraceFILE testdocs/sqlite3.c /^static FILE *fts5yyTraceFILE = 0;$/;" v file: +fts5yyTracePrompt testdocs/sqlite3.c /^static char *fts5yyTracePrompt = 0;$/;" v file: +fts5yyTraceShift testdocs/sqlite3.c /^# define fts5yyTraceShift(/;" d file: +fts5yyTraceShift testdocs/sqlite3.c /^static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){$/;" f file: +fts5yy_accept testdocs/sqlite3.c /^static void fts5yy_accept($/;" f file: +fts5yy_action testdocs/sqlite3.c /^static const fts5YYACTIONTYPE fts5yy_action[] = {$/;" v file: +fts5yy_default testdocs/sqlite3.c /^static const fts5YYACTIONTYPE fts5yy_default[] = {$/;" v file: +fts5yy_destructor testdocs/sqlite3.c /^static void fts5yy_destructor($/;" f file: +fts5yy_find_reduce_action testdocs/sqlite3.c /^static int fts5yy_find_reduce_action($/;" f file: +fts5yy_find_shift_action testdocs/sqlite3.c /^static unsigned int fts5yy_find_shift_action($/;" f file: +fts5yy_lookahead testdocs/sqlite3.c /^static const fts5YYCODETYPE fts5yy_lookahead[] = {$/;" v file: +fts5yy_parse_failed testdocs/sqlite3.c /^static void fts5yy_parse_failed($/;" f file: +fts5yy_pop_parser_stack testdocs/sqlite3.c /^static void fts5yy_pop_parser_stack(fts5yyParser *pParser){$/;" f file: +fts5yy_reduce testdocs/sqlite3.c /^static void fts5yy_reduce($/;" f file: +fts5yy_reduce_ofst testdocs/sqlite3.c /^static const signed char fts5yy_reduce_ofst[] = {$/;" v file: +fts5yy_shift testdocs/sqlite3.c /^static void fts5yy_shift($/;" f file: +fts5yy_shift_ofst testdocs/sqlite3.c /^static const unsigned char fts5yy_shift_ofst[] = {$/;" v file: +fts5yy_syntax_error testdocs/sqlite3.c /^static void fts5yy_syntax_error($/;" f file: +fts5yyerrcnt testdocs/sqlite3.c /^ int fts5yyerrcnt; \/* Shifts left before out of the error *\/$/;" m struct:fts5yyParser file: +fts5yyhwm testdocs/sqlite3.c /^ int fts5yyhwm; \/* High-water mark of the stack *\/$/;" m struct:fts5yyParser file: +fts5yyinit testdocs/sqlite3.c /^ int fts5yyinit;$/;" m union:__anon38 file: +fts5yystack testdocs/sqlite3.c /^ fts5yyStackEntry *fts5yystack; \/* The parser's stack *\/$/;" m struct:fts5yyParser file: +fts5yystk0 testdocs/sqlite3.c /^ fts5yyStackEntry fts5yystk0; \/* First stack entry *\/$/;" m struct:fts5yyParser file: +fts5yystksz testdocs/sqlite3.c /^ int fts5yystksz; \/* Current side of the stack *\/$/;" m struct:fts5yyParser file: +fts5yytestcase testdocs/sqlite3.c /^# define fts5yytestcase(/;" d file: +fts5yytestcase testdocs/sqlite3.c /^#define fts5yytestcase(/;" d file: +fts5yytos testdocs/sqlite3.c /^ fts5yyStackEntry *fts5yytos; \/* Pointer to top element of the stack *\/$/;" m struct:fts5yyParser file: +ftsCompareFunction testdocs/sqlite3.c /^static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){$/;" f file: +ftsHashFunction testdocs/sqlite3.c /^static int (*ftsHashFunction(int keyClass))(const void*,int){$/;" f file: +fullSync testdocs/sqlite3.c /^ u8 fullSync; \/* Do extra syncs of the journal for robustness *\/$/;" m struct:Pager file: +full_fsync testdocs/sqlite3.c /^static int full_fsync(int fd, int fullSync, int dataOnly){$/;" f file: +funcFlags testdocs/sqlite3.c /^ u16 funcFlags; \/* Some combination of SQLITE_FUNC_* *\/$/;" m struct:FuncDef file: +functionDestroy testdocs/sqlite3.c /^static void functionDestroy(sqlite3 *db, FuncDef *p){$/;" f file: +functionSearch testdocs/sqlite3.c /^static FuncDef *functionSearch($/;" f file: +g_elapsed testdocs/sqlite3.c /^static sqlite_uint64 g_elapsed;$/;" v file: +g_start testdocs/sqlite3.c /^static sqlite_uint64 g_start;$/;" v file: +gapend edit.h /^ Rune* gapend; \/* end of the gap *\/$/;" m struct:__anon5 +gapstart edit.h /^ Rune* gapstart; \/* start of the gap *\/$/;" m struct:__anon5 +generateColumnNames testdocs/sqlite3.c /^static void generateColumnNames($/;" f file: +generateColumnTypes testdocs/sqlite3.c /^static void generateColumnTypes($/;" f file: +generateOutputSubroutine testdocs/sqlite3.c /^static int generateOutputSubroutine($/;" f file: +generateSortTail testdocs/sqlite3.c /^static void generateSortTail($/;" f file: +generateWithRecursiveQuery testdocs/sqlite3.c /^static void generateWithRecursiveQuery($/;" f file: +geomCallback testdocs/sqlite3.c /^static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){$/;" f file: +get2byte testdocs/sqlite3.c /^# define get2byte(/;" d file: +get2byte testdocs/sqlite3.c /^#define get2byte(/;" d file: +get2byteAligned testdocs/sqlite3.c /^# define get2byteAligned(/;" d file: +get2byteNotZero testdocs/sqlite3.c /^#define get2byteNotZero(/;" d file: +get4byte testdocs/sqlite3.c /^#define get4byte /;" d file: +getAbsoluteLevel testdocs/sqlite3.c /^static sqlite3_int64 getAbsoluteLevel($/;" f file: +getAndInitPage testdocs/sqlite3.c /^static int getAndInitPage($/;" f file: +getAutoVacuum testdocs/sqlite3.c /^static int getAutoVacuum(const char *z){$/;" f file: +getCellInfo testdocs/sqlite3.c /^static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){$/;" f file: +getDigits testdocs/sqlite3.c /^static int getDigits(const char *zDate, const char *zFormat, ...){$/;" f file: +getDoubleArg testdocs/sqlite3.c /^static double getDoubleArg(PrintfArguments *p){$/;" f file: +getFileMode testdocs/sqlite3.c /^static int getFileMode($/;" f file: +getIntArg testdocs/sqlite3.c /^static sqlite3_int64 getIntArg(PrintfArguments *p){$/;" f file: +getIntFromStmt testdocs/sqlite3.c /^static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){$/;" f file: +getLocalPayload testdocs/sqlite3.c /^static void getLocalPayload($/;" f file: +getLockingMode testdocs/sqlite3.c /^static int getLockingMode(const char *z){$/;" f file: +getNextNode testdocs/sqlite3.c /^static int getNextNode($/;" f file: +getNextString testdocs/sqlite3.c /^static int getNextString($/;" f file: +getNextToken testdocs/sqlite3.c /^static int getNextToken($/;" f file: +getNodeSize testdocs/sqlite3.c /^static int getNodeSize($/;" f file: +getOverflowPage testdocs/sqlite3.c /^static int getOverflowPage($/;" f file: +getPageError testdocs/sqlite3.c /^static int getPageError($/;" f file: +getPageMMap testdocs/sqlite3.c /^static int getPageMMap($/;" f file: +getPageNormal testdocs/sqlite3.c /^static int getPageNormal($/;" f file: +getPageReferenced testdocs/sqlite3.c /^static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){$/;" f file: +getRowTrigger testdocs/sqlite3.c /^static TriggerPrg *getRowTrigger($/;" f file: +getSafetyLevel testdocs/sqlite3.c /^static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){$/;" f file: +getTempStore testdocs/sqlite3.c /^static int getTempStore(const char *z){$/;" f file: +getTextArg testdocs/sqlite3.c /^static char *getTextArg(PrintfArguments *p){$/;" f file: +getVarint testdocs/sqlite3.c /^#define getVarint /;" d file: +getVarint32 testdocs/sqlite3.c /^#define getVarint32(/;" d file: +get_autocommit testdocs/sqlite3.c /^ int (*get_autocommit)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +get_auxdata testdocs/sqlite3.c /^ void * (*get_auxdata)(sqlite3_context*,int);$/;" m struct:sqlite3_api_routines file: +get_table testdocs/sqlite3.c /^ int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);$/;" m struct:sqlite3_api_routines file: +globInfo testdocs/sqlite3.c /^static const struct compareInfo globInfo = { '*', '?', '[', 0 };$/;" v typeref:struct:compareInfo file: +global_recover testdocs/sqlite3.c /^ int (*global_recover)(void);$/;" m struct:sqlite3_api_routines file: +groupConcatFinalize testdocs/sqlite3.c /^static void groupConcatFinalize(sqlite3_context *context){$/;" f file: +groupConcatStep testdocs/sqlite3.c /^static void groupConcatStep($/;" f file: +growOp3 testdocs/sqlite3.c /^static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){$/;" f file: +growOpArray testdocs/sqlite3.c /^static int growOpArray(Vdbe *v, int nOp){$/;" f file: +growVTrans testdocs/sqlite3.c /^static int growVTrans(sqlite3 *db){$/;" f file: +grp testdocs/sqlite3.c /^ PGroup grp; \/* The global PGroup for mode (2) *\/$/;" m struct:PCacheGlobal file: +h testdocs/sqlite3.c /^ HANDLE h; \/* Handle for accessing the file *\/$/;" m struct:winFile file: +h testdocs/sqlite3.c /^ int h, m; \/* Hour and minutes *\/$/;" m struct:DateTime file: +h testdocs/sqlite3.c /^ int h; \/* The file descriptor *\/$/;" m struct:unixFile file: +h testdocs/sqlite3.c /^ int h; \/* Open file descriptor *\/$/;" m struct:unixShmNode file: +hFile testdocs/sqlite3.c /^ winFile hFile; \/* File handle from winOpen *\/$/;" m struct:winShmNode file: +hHeap testdocs/sqlite3.c /^ HANDLE hHeap; \/* The handle to our heap. *\/$/;" m struct:winMemData file: +hMap testdocs/sqlite3.c /^ HANDLE hMap; \/* File handle from CreateFileMapping *\/$/;" m struct:winShmNode::ShmRegion file: +hMap testdocs/sqlite3.c /^ HANDLE hMap; \/* Handle for accessing memory mapping *\/$/;" m struct:winFile file: +hMutex testdocs/sqlite3.c /^ HANDLE hMutex; \/* Mutex used to control access to shared lock *\/$/;" m struct:winFile file: +hPending testdocs/sqlite3.c /^ Fts3Hash hPending; \/* Pending terms table for this index *\/$/;" m struct:Fts3Table::Fts3Index file: +hShared testdocs/sqlite3.c /^ HANDLE hShared; \/* Shared memory segment used for locking *\/$/;" m struct:winFile file: +handleDeferredMoveto testdocs/sqlite3.c /^static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){$/;" f file: +handleMovedCursor testdocs/sqlite3.c /^static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){$/;" f file: +handle_signal atf.h /^static void handle_signal(int sig) {$/;" f +hasColumn testdocs/sqlite3.c /^static int hasColumn(const i16 *aiCol, int nCol, int x){$/;" f file: +hasCompound testdocs/sqlite3.c /^ u8 hasCompound; \/* Need to invoke convertCompoundSelectToSubquery() *\/$/;" m struct:Parse file: +hasHeldSharedLock testdocs/sqlite3.c /^ u8 hasHeldSharedLock; \/* True if a shared lock has ever been held *\/$/;" m struct:Pager file: +hasHotJournal testdocs/sqlite3.c /^static int hasHotJournal(Pager *pPager, int *pExists){$/;" f file: +hasIncrblobCur testdocs/sqlite3.c /^ u8 hasIncrblobCur; \/* True if there are one or more Incrblob cursors *\/$/;" m struct:Btree file: +hasMutex testdocs/sqlite3.c /^ u8 hasMutex; \/* True if holding the unixShmNode mutex *\/$/;" m struct:unixShm file: +hasMutex testdocs/sqlite3.c /^ u8 hasMutex; \/* True if holding the winShmNode mutex *\/$/;" m struct:winShm file: +hasReadConflicts testdocs/sqlite3.c /^ #define hasReadConflicts(/;" d file: +hasReadConflicts testdocs/sqlite3.c /^static int hasReadConflicts(Btree *pBtree, Pgno iRoot){$/;" f file: +hasSharedCacheTableLock testdocs/sqlite3.c /^ #define hasSharedCacheTableLock(/;" d file: +hasSharedCacheTableLock testdocs/sqlite3.c /^static int hasSharedCacheTableLock($/;" f file: +hasStat1 testdocs/sqlite3.c /^ unsigned hasStat1:1; \/* aiRowLogEst values come from sqlite_stat1 *\/$/;" m struct:Index file: +hasVowel testdocs/sqlite3.c /^static int hasVowel(const char *z){$/;" f file: +hashDestroy testdocs/sqlite3.c /^static void hashDestroy(void *p){$/;" f file: +havingToWhere testdocs/sqlite3.c /^static void havingToWhere($/;" f file: +havingToWhereExprCb testdocs/sqlite3.c /^static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){$/;" f file: +hdr testdocs/sqlite3.c /^ } hdr;$/;" m union:Mem3Block::__anon21 typeref:struct:Mem3Block::__anon21::__anon22 file: +hdr testdocs/sqlite3.c /^ WalIndexHdr hdr; \/* Wal-index header for current transaction *\/$/;" m struct:Wal file: +hdrOffset testdocs/sqlite3.c /^ u8 hdrOffset; \/* 100 for page 1. 0 otherwise *\/$/;" m struct:MemPage file: +heap testdocs/sqlite3.c /^ u32 *heap; \/* Min-heap used for analyzing cell coverage *\/$/;" m struct:IntegrityCk file: +heightOfExpr testdocs/sqlite3.c /^static void heightOfExpr(Expr *p, int *pnHeight){$/;" f file: +heightOfExprList testdocs/sqlite3.c /^static void heightOfExprList(ExprList *p, int *pnHeight){$/;" f file: +heightOfSelect testdocs/sqlite3.c /^static void heightOfSelect(Select *p, int *pnHeight){$/;" f file: +hexFunc testdocs/sqlite3.c /^static void hexFunc($/;" f file: +hexdigits testdocs/sqlite3.c /^static const char hexdigits[] = {$/;" v file: +hidden testdocs/sqlite3.c /^ unsigned char hidden[48];$/;" m struct:sqlite3_snapshot file: +hints testdocs/sqlite3.c /^ u8 hints; \/* As configured by CursorSetHints() *\/$/;" m struct:BtCursor file: +hlmask testdocs/sqlite3.c /^ u64 hlmask; \/* Mask of snippet terms to highlight *\/$/;" m struct:SnippetFragment file: +hook testdocs/sqlite3.c /^ SessionHook hook; \/* APIs to grab new and old data with *\/$/;" m struct:sqlite3_session file: +ht testdocs/sqlite3.c /^ } *ht;$/;" m struct:Fts3Hash typeref:struct:Fts3Hash::_fts3ht file: +ht testdocs/sqlite3.c /^ } *ht;$/;" m struct:Hash typeref:struct:Hash::_ht file: +ht_slot testdocs/sqlite3.c /^typedef u16 ht_slot;$/;" t file: +htsize testdocs/sqlite3.c /^ int htsize; \/* Number of buckets in the hash table *\/$/;" m struct:Fts3Hash file: +htsize testdocs/sqlite3.c /^ unsigned int htsize; \/* Number of buckets in the hash table *\/$/;" m struct:Hash file: +i testdocs/sqlite3.c /^ i64 i; \/* Integer value used when MEM_Int is set in flags *\/$/;" m union:sqlite3_value::MemValue file: +i testdocs/sqlite3.c /^ int i; \/* Integer value if p4type==P4_INT32 *\/$/;" m union:VdbeOp::p4union file: +i testdocs/sqlite3.c /^ int i; \/* Current offset in a[] *\/$/;" m struct:Fts5PoslistReader file: +i testdocs/sqlite3.c /^ int i; \/* Current offset in position list *\/$/;" m struct:Fts5LookaheadReader file: +i testdocs/sqlite3.c /^ int i; \/* XOR next input into a[i] *\/$/;" m struct:EntropyGatherer file: +i testdocs/sqlite3.c /^ int i; \/* Integer value *\/$/;" m union:RtreeCoord file: +i testdocs/sqlite3.c /^ u32 i; \/* Index in sParse.aNode[] of current row *\/$/;" m struct:JsonEachCursor file: +i testdocs/sqlite3.c /^ unsigned char i, j; \/* State variables *\/$/;" m struct:sqlite3PrngType file: +i16 testdocs/sqlite3.c /^typedef INT16_TYPE i16; \/* 2-byte signed integer *\/$/;" t file: +i16 testdocs/sqlite3.c /^typedef short i16;$/;" t file: +i16 testdocs/sqlite3.c /^typedef short int i16; \/* 2-byte (or larger) signed integer *\/$/;" t file: +i64 testdocs/sqlite3.c /^typedef sqlite3_int64 i64; \/* 8-byte signed integer *\/$/;" t file: +i64 testdocs/sqlite3.c /^typedef sqlite3_int64 i64;$/;" t file: +i64 testdocs/sqlite3.c /^typedef sqlite_int64 i64; \/* 8-byte signed integer *\/$/;" t file: +i8 testdocs/sqlite3.c /^typedef INT8_TYPE i8; \/* 1-byte signed integer *\/$/;" t file: +iAbsLevel testdocs/sqlite3.c /^ sqlite3_int64 iAbsLevel; \/* Absolute level of input segments *\/$/;" m struct:IncrmergeWriter file: +iAddr testdocs/sqlite3.c /^ int iAddr; \/* Address of next instruction to return *\/$/;" m struct:VdbeOpIter file: +iAgg testdocs/sqlite3.c /^ i16 iAgg; \/* Which entry in pAggInfo->aCol[] or ->aFunc[] *\/$/;" m struct:Expr file: +iAlias testdocs/sqlite3.c /^ u16 iAlias; \/* Index into Parse.aAlias[] for zName *\/$/;" m struct:ExprList::ExprList_item::__anon12::__anon13 file: +iAppend testdocs/sqlite3.c /^ u32 iAppend; \/* More terms for ARRAY and OBJECT *\/$/;" m union:JsonNode::__anon37 file: +iArg testdocs/sqlite3.c /^ u32 iArg; \/* Extra argument *\/$/;" m struct:PragmaName file: +iAuxArg testdocs/sqlite3.c /^ int iAuxArg; \/* Index of function argument. *\/$/;" m struct:AuxData file: +iAuxOp testdocs/sqlite3.c /^ int iAuxOp; \/* Instruction number of OP_Function opcode *\/$/;" m struct:AuxData file: +iBatch testdocs/sqlite3.c /^ int iBatch; \/* Current insert batch *\/$/;" m struct:RowSet file: +iBegin testdocs/sqlite3.c /^ u32 iBegin; \/* The first node of the scan *\/$/;" m struct:JsonEachCursor file: +iBlock testdocs/sqlite3.c /^ sqlite3_int64 iBlock; \/* Current block id *\/$/;" m struct:NodeWriter file: +iBreak testdocs/sqlite3.c /^ int iBreak; \/* Jump here to break out of the loop *\/$/;" m struct:WhereInfo file: +iBtPage testdocs/sqlite3.c /^ int iBtPage; \/* Page number corresponding to btterm *\/$/;" m struct:Fts5SegWriter file: +iBufEnd testdocs/sqlite3.c /^ int iBufEnd; \/* Last byte of buffer to write *\/$/;" m struct:PmaWriter file: +iBufStart testdocs/sqlite3.c /^ int iBufStart; \/* First byte of buffer to write *\/$/;" m struct:PmaWriter file: +iCacheCnt testdocs/sqlite3.c /^ int iCacheCnt; \/* Counter used to generate aColCache[].lru values *\/$/;" m struct:Parse file: +iCacheLevel testdocs/sqlite3.c /^ int iCacheLevel; \/* ColCache valid when aColCache[].iLevel<=iCacheLevel *\/$/;" m struct:Parse file: +iCallback testdocs/sqlite3.c /^ u32 iCallback; \/* Value to pass to log callback (or 0) *\/$/;" m struct:Wal file: +iCell testdocs/sqlite3.c /^ int iCell;$/;" m struct:StatPage file: +iCell testdocs/sqlite3.c /^ u8 iCell; \/* Cell index within the node *\/$/;" m struct:RtreeSearchPoint file: +iChange testdocs/sqlite3.c /^ u32 iChange; \/* Counter incremented each transaction *\/$/;" m struct:WalIndexHdr file: +iChild testdocs/sqlite3.c /^ sqlite3_int64 iChild; \/* Pointer to child node *\/$/;" m struct:NodeReader file: +iChildPg testdocs/sqlite3.c /^ u32 iChildPg; \/* Child node (or 0 if this is a leaf) *\/$/;" m struct:StatCell file: +iCol testdocs/sqlite3.c /^ i16 iCol; \/* Column of last value written *\/$/;" m struct:Fts5HashEntry file: +iCol testdocs/sqlite3.c /^ int iCol; \/* Column of table to populate aTerm for *\/$/;" m struct:TermOffsetCtx file: +iCol testdocs/sqlite3.c /^ int iCol; \/* Column snippet is extracted from *\/$/;" m struct:SnippetFragment file: +iCol testdocs/sqlite3.c /^ int iCol; \/* Column to search *\/$/;" m struct:CInstIter file: +iCol testdocs/sqlite3.c /^ int iCol; \/* Column token must occur in *\/$/;" m struct:Fts3DeferredToken file: +iCol testdocs/sqlite3.c /^ int iCol; \/* Current value of 'col' column *\/$/;" m struct:Fts3auxCursor file: +iCol testdocs/sqlite3.c /^ int iCol; \/* Extract snippet from this column *\/$/;" m struct:SnippetIter file: +iCol testdocs/sqlite3.c /^ int iCol; \/* If !isPSample, the reason for inclusion *\/$/;" m struct:Stat4Sample file: +iCol testdocs/sqlite3.c /^ int iCol; \/* The column the token must match *\/$/;" m struct:Fts3TokenAndCost file: +iCol testdocs/sqlite3.c /^ int iCol;$/;" m struct:Fts3SegFilter file: +iCol testdocs/sqlite3.c /^ int iCol;$/;" m struct:Fts5InsertCtx file: +iCol testdocs/sqlite3.c /^ int iCol;$/;" m struct:Fts5IntegrityCtx file: +iCol testdocs/sqlite3.c /^ int iCol;$/;" m struct:Fts5VocabCursor file: +iCol testdocs/sqlite3.c /^ u16 iCol; \/* Table column this handle is open on *\/$/;" m struct:Incrblob file: +iColFilter testdocs/sqlite3.c /^ int iColFilter; \/* If >=0, filter for this column *\/$/;" m struct:Fts3MultiSegReader file: +iColumn testdocs/sqlite3.c /^ int iColumn; \/* Column constrained. -1 for ROWID *\/$/;" m struct:sqlite3_index_info::sqlite3_index_constraint file: +iColumn testdocs/sqlite3.c /^ int iColumn; \/* Column number *\/$/;" m struct:sqlite3_index_info::sqlite3_index_orderby file: +iColumn testdocs/sqlite3.c /^ i16 iColumn; \/* Table column number *\/$/;" m struct:Parse::yColCache file: +iColumn testdocs/sqlite3.c /^ int iColumn; \/* Column number within the source table *\/$/;" m struct:AggInfo::AggInfo_col file: +iColumn testdocs/sqlite3.c /^ int iColumn; \/* Index of column this phrase must match *\/$/;" m struct:Fts3Phrase file: +iColumn testdocs/sqlite3.c /^ ynVar iColumn; \/* TK_COLUMN: column index. -1 for rowid.$/;" m struct:Expr file: +iConstExprReg testdocs/sqlite3.c /^ int iConstExprReg; \/* Register in which Expr value is cached *\/$/;" m union:ExprList::ExprList_item::__anon12 file: +iContinue testdocs/sqlite3.c /^ int iContinue; \/* Jump here to continue with next record *\/$/;" m struct:WhereInfo file: +iCookie testdocs/sqlite3.c /^ int iCookie; \/* Incremented when %_config is modified *\/$/;" m struct:Fts5Config file: +iCookie testdocs/sqlite3.c /^ u32 iCookie; \/* Cookie value for main db files *\/$/;" m struct:rbu_file file: +iCookie testdocs/sqlite3.c /^ u32 iCookie;$/;" m struct:RbuState file: +iCoord testdocs/sqlite3.c /^ int iCoord; \/* Index of constrained coordinate *\/$/;" m struct:RtreeConstraint file: +iCsrId testdocs/sqlite3.c /^ i64 iCsrId; \/* Cursor id *\/$/;" m struct:Fts5Cursor file: +iCur testdocs/sqlite3.c /^ int iCur; \/* The VDBE cursor used by this IN operator *\/$/;" m struct:WhereLevel::__anon27::__anon28::InLoop file: +iCur testdocs/sqlite3.c /^ int iCur; \/* A cursor number *\/$/;" m union:Walker::__anon17 file: +iCur testdocs/sqlite3.c /^ int iCur; \/* Cursor number for the table corresponding to the index *\/$/;" m struct:IdxCover file: +iCurrent testdocs/sqlite3.c /^ int iCurrent; \/* First token of current snippet *\/$/;" m struct:SnippetIter file: +iCurrent testdocs/sqlite3.c /^ int iCurrent; \/* Offset in aData[] of current change *\/$/;" m struct:SessionInput file: +iCurrentBlock testdocs/sqlite3.c /^ sqlite3_int64 iCurrentBlock; \/* Current leaf block (or 0) *\/$/;" m struct:Fts3SegReader file: +iCurrentTime testdocs/sqlite3.c /^ i64 iCurrentTime; \/* Value of julianday('now') for this statement *\/$/;" m struct:Vdbe file: +iCursor testdocs/sqlite3.c /^ int iCursor; \/* The VDBE cursor number used to access this table *\/$/;" m struct:SrcList::SrcList_item file: +iDataVersion testdocs/sqlite3.c /^ u32 iDataVersion; \/* Changes whenever database content changes *\/$/;" m struct:Pager file: +iDataVersion testdocs/sqlite3.c /^ u32 iDataVersion; \/* Combines with pBt->pPager->iDataVersion *\/$/;" m struct:Btree file: +iDb testdocs/sqlite3.c /^ u8 iDb; \/* Which db file is being initialized *\/$/;" m struct:sqlite3::sqlite3InitInfo file: +iDb testdocs/sqlite3.c /^ i8 iDb; \/* Index of cursor database in db->aDb[] (or -1) *\/$/;" m struct:VdbeCursor file: +iDb testdocs/sqlite3.c /^ int iDb; \/* Index of database to analyze *\/$/;" m struct:StatTable file: +iDb testdocs/sqlite3.c /^ int iDb; \/* Schema used for this query *\/$/;" m struct:StatCursor file: +iDb testdocs/sqlite3.c /^ int iDb; \/* The database containing the table to be locked *\/$/;" m struct:TableLock file: +iDb testdocs/sqlite3.c /^ int iDb; \/* Index in sqlite3.aDb[] of database holding pTab *\/$/;" m struct:AutoincInfo file: +iDb testdocs/sqlite3.c /^ int iDb; \/* 0 for main database. 1 for TEMP, 2.. for ATTACHed *\/$/;" m struct:__anon16 file: +iDbPage testdocs/sqlite3.c /^ u32 iDbPage;$/;" m struct:RbuFrame file: +iDefaultCol testdocs/sqlite3.c /^ int iDefaultCol; \/* Default column to query *\/$/;" m struct:ParseContext file: +iDepth testdocs/sqlite3.c /^ int iDepth; \/* Current depth of the r-tree structure *\/$/;" m struct:Rtree file: +iDepth testdocs/sqlite3.c /^ u16 iDepth; \/* Nesting depth *\/$/;" m struct:JsonParse file: +iDestSchema testdocs/sqlite3.c /^ u32 iDestSchema; \/* Original schema cookie in destination *\/$/;" m struct:sqlite3_backup file: +iDistinct testdocs/sqlite3.c /^ int iDistinct; \/* Ephemeral table used to enforce DISTINCT *\/$/;" m struct:AggInfo::AggInfo_func file: +iDivisor testdocs/sqlite3.c /^ u32 iDivisor; \/* Number of bits handled by each apSub[] entry. *\/$/;" m struct:Bitvec file: +iDocid testdocs/sqlite3.c /^ sqlite3_int64 iDocid; \/* Current docid (if pList!=0) *\/$/;" m struct:Fts3Doclist file: +iDocid testdocs/sqlite3.c /^ sqlite3_int64 iDocid; \/* Current docid *\/$/;" m struct:Fts3Expr file: +iDocid testdocs/sqlite3.c /^ sqlite3_int64 iDocid;$/;" m struct:Fts3SegReader file: +iDocid testdocs/sqlite3.c /^ sqlite3_int64 iDocid;$/;" m struct:TermOffsetCtx file: +iDocid testdocs/sqlite3.c /^ sqlite3_int64 iDocid;$/;" m struct:TokenDoclist file: +iDoclistToken testdocs/sqlite3.c /^ int iDoclistToken;$/;" m struct:Fts3Phrase file: +iECursor testdocs/sqlite3.c /^ int iECursor; \/* Cursor number for the sorter *\/$/;" m struct:SortCtx file: +iEnd testdocs/sqlite3.c /^ int iEnd; \/* Current 'end' value *\/$/;" m struct:Fts3tokCursor file: +iEnd testdocs/sqlite3.c /^ int iEnd; \/* Last token in coalesced phrase instance *\/$/;" m struct:CInstIter file: +iEnd testdocs/sqlite3.c /^ sqlite3_int64 iEnd; \/* Block number of last allocated block *\/$/;" m struct:IncrmergeWriter file: +iEnd testdocs/sqlite3.c /^ u32 iEnd; \/* EOF when i equals or exceeds this value *\/$/;" m struct:JsonEachCursor file: +iEndBlock testdocs/sqlite3.c /^ sqlite3_int64 iEndBlock; \/* Rowid of final block in segment (or 0) *\/$/;" m struct:Fts3SegReader file: +iEndofDoclist testdocs/sqlite3.c /^ int iEndofDoclist;$/;" m struct:Fts5SegIter file: +iEof testdocs/sqlite3.c /^ i64 iEof; \/* Bytes of data stored in pFd *\/$/;" m struct:SorterFile file: +iEof testdocs/sqlite3.c /^ i64 iEof; \/* 1 byte past EOF for this PmaReader *\/$/;" m struct:PmaReader file: +iEquiv testdocs/sqlite3.c /^ unsigned char iEquiv; \/* Next unused slot in aEquiv[] *\/$/;" m struct:WhereScan file: +iField testdocs/sqlite3.c /^ int iField; \/* Field in (?,?,?) IN (SELECT...) vector *\/$/;" m struct:WhereTerm file: +iFirst testdocs/sqlite3.c /^ sqlite3_int64 iFirst; \/* First slot in %_segments written *\/$/;" m struct:SegmentWriter file: +iFirst testdocs/sqlite3.c /^ u16 iFirst; \/* aSeg[] index of firstest iterator *\/$/;" m struct:Fts5CResult file: +iFirstOff testdocs/sqlite3.c /^ int iFirstOff; \/* Used by reverse iterators *\/$/;" m struct:Fts5DlidxLvl file: +iFirstRowid testdocs/sqlite3.c /^ i64 iFirstRowid; \/* Return no rowids earlier than this *\/$/;" m struct:Fts5Cursor file: +iForeGuard testdocs/sqlite3.c /^ int iForeGuard; \/* Guard word for sanity *\/$/;" m struct:MemBlockHdr file: +iFree testdocs/sqlite3.c /^ sqlite3_int64 iFree; \/* Next free slot in %_segments *\/$/;" m struct:SegmentWriter file: +iFrom testdocs/sqlite3.c /^ int iFrom; \/* Index of column in pFrom *\/$/;" m struct:FKey::sColMap file: +iFrom testdocs/sqlite3.c /^ u8 iFrom; \/* Which entry in the FROM clause *\/$/;" m struct:WhereLevel file: +iGeneration testdocs/sqlite3.c /^ int iGeneration; \/* Generation counter. Incremented with each change *\/$/;" m struct:Schema file: +iGet testdocs/sqlite3.c /^ int iGet; \/* Index of current sample accessed by stat_get() *\/$/;" m struct:Stat4Accum file: +iHash testdocs/sqlite3.c /^ u32 iHash; \/* Tiebreaker hash *\/$/;" m struct:Stat4Sample file: +iHdrOffset testdocs/sqlite3.c /^ i64 iHdrOffset; \/* See above *\/$/;" m struct:PagerSavepoint file: +iHdrOffset testdocs/sqlite3.c /^ u32 iHdrOffset; \/* Offset to next unparsed byte of the header *\/$/;" m struct:VdbeCursor file: +iHead testdocs/sqlite3.c /^ int iHead; \/* Next value in position list *\/$/;" m struct:SnippetPhrase file: +iHidden testdocs/sqlite3.c /^ u8 iHidden; \/* Index of the first hidden column *\/$/;" m struct:PragmaVtab file: +iIdx testdocs/sqlite3.c /^ int iIdx; \/* Index (main or aPrefix[] entry) *\/$/;" m struct:Fts5TermsetEntry file: +iIdx testdocs/sqlite3.c /^ int iIdx; \/* Index of *output* segment in iAbsLevel+1 *\/$/;" m struct:IncrmergeWriter file: +iIdx testdocs/sqlite3.c /^ int iIdx; \/* Index within level, or 0x7FFFFFFF for PT *\/$/;" m struct:Fts3SegReader file: +iIdxCol testdocs/sqlite3.c /^ int iIdxCol; \/* The column for the index *\/$/;" m struct:IdxExprTrans file: +iIdxCur testdocs/sqlite3.c /^ int iIdxCur; \/* The VDBE cursor used to access pIdx *\/$/;" m struct:WhereLevel file: +iIdxCur testdocs/sqlite3.c /^ int iIdxCur; \/* The cursor for the index *\/$/;" m struct:IdxExprTrans file: +iIdxCur testdocs/sqlite3.c /^ int iIdxCur; \/* Cursor for the index, if pIdx!=0. Unused otherwise *\/$/;" m struct:CCurHint file: +iInst testdocs/sqlite3.c /^ int iInst; \/* Next phrase instance index *\/$/;" m struct:CInstIter file: +iJD testdocs/sqlite3.c /^ sqlite3_int64 iJD; \/* The julian day number times 86400000 *\/$/;" m struct:DateTime file: +iKey testdocs/sqlite3.c /^ u32 iKey; \/* Key for ARRAY objects in json_tree() *\/$/;" m union:JsonNode::__anon37 file: +iKey testdocs/sqlite3.c /^ unsigned int iKey; \/* Key value (page number) *\/$/;" m struct:PgHdr1 file: +iKey1 testdocs/sqlite3.c /^ i64 iKey1; \/* First key value passed to hook *\/$/;" m struct:PreUpdate file: +iKey2 testdocs/sqlite3.c /^ i64 iKey2; \/* Second key value passed to hook *\/$/;" m struct:PreUpdate file: +iLangid testdocs/sqlite3.c /^ int iLangid; \/* Language id used with tokenizer *\/$/;" m struct:ParseContext file: +iLangid testdocs/sqlite3.c /^ int iLangid; \/* Language being queried for *\/$/;" m struct:Fts3Cursor file: +iLangid testdocs/sqlite3.c /^ int iLangid; \/* Language id to query *\/$/;" m struct:Fts3auxCursor file: +iLastCol testdocs/sqlite3.c /^ sqlite3_int64 iLastCol;$/;" m struct:PendingList file: +iLastDocid testdocs/sqlite3.c /^ sqlite3_int64 iLastDocid;$/;" m struct:PendingList file: +iLastPos testdocs/sqlite3.c /^ sqlite3_int64 iLastPos;$/;" m struct:PendingList file: +iLastRowid testdocs/sqlite3.c /^ i64 iLastRowid; \/* Return no rowids later than this *\/$/;" m struct:Fts5Cursor file: +iLeafEndBlock testdocs/sqlite3.c /^ sqlite3_int64 iLeafEndBlock; \/* Rowid of final leaf block to traverse *\/$/;" m struct:Fts3SegReader file: +iLeafOffset testdocs/sqlite3.c /^ int iLeafOffset; \/* Byte offset within current leaf *\/$/;" m struct:Fts5SegIter file: +iLeafPgno testdocs/sqlite3.c /^ int iLeafPgno; \/* Current leaf page number *\/$/;" m struct:Fts5SegIter file: +iLeafPgno testdocs/sqlite3.c /^ int iLeafPgno; \/* Page number of current leaf page *\/$/;" m struct:Fts5DlidxLvl file: +iLeftJoin testdocs/sqlite3.c /^ int iLeftJoin; \/* Memory cell used to implement LEFT OUTER JOIN *\/$/;" m struct:WhereLevel file: +iLevel testdocs/sqlite3.c /^ int iLevel; \/* Nesting level *\/$/;" m struct:Parse::yColCache file: +iLevel testdocs/sqlite3.c /^ int iLevel; \/* Level of current node or entry *\/$/;" m struct:sqlite3_rtree_query_info file: +iLevel testdocs/sqlite3.c /^ int iLevel; \/* Which level of the tree we are on *\/$/;" m struct:TreeView file: +iLevel testdocs/sqlite3.c /^ u8 iLevel; \/* 0=entries. 1=leaf node. 2+ for higher *\/$/;" m struct:RtreeSearchPoint file: +iLikeRepCntr testdocs/sqlite3.c /^ u32 iLikeRepCntr; \/* LIKE range processing counter register (times 2) *\/$/;" m struct:WhereLevel file: +iLimit testdocs/sqlite3.c /^ LogEst iLimit; \/* LIMIT if wctrlFlags has WHERE_USE_LIMIT *\/$/;" m struct:WhereInfo file: +iLimit testdocs/sqlite3.c /^ int iLimit, iOffset; \/* Memory registers holding LIMIT & OFFSET counters *\/$/;" m struct:Select file: +iLookahead testdocs/sqlite3.c /^ i64 iLookahead; \/* Next position *\/$/;" m struct:Fts5LookaheadReader file: +iMaster testdocs/sqlite3.c /^ u32 iMaster;$/;" m struct:Mem3Global file: +iMaxDocid testdocs/sqlite3.c /^ i64 iMaxDocid; \/* Maximum docid to return *\/$/;" m struct:Fts3Cursor file: +iMaxFrame testdocs/sqlite3.c /^ u32 iMaxFrame; \/* Largest iWalFrame value in aFrame[] *\/$/;" m struct:sqlite3rbu file: +iMaxKey testdocs/sqlite3.c /^ unsigned int iMaxKey; \/* Largest key seen since xTruncate() *\/$/;" m struct:PCache1 file: +iMem testdocs/sqlite3.c /^ int iMem; \/* Memory location that acts as accumulator *\/$/;" m struct:AggInfo::AggInfo_col file: +iMem testdocs/sqlite3.c /^ int iMem; \/* Memory location that acts as accumulator *\/$/;" m struct:AggInfo::AggInfo_func file: +iMemory testdocs/sqlite3.c /^ int iMemory; \/* Offset of free space in list.aMemory *\/$/;" m struct:VdbeSorter file: +iMin testdocs/sqlite3.c /^ int iMin; \/* Index in a[] of entry with minimum score *\/$/;" m struct:Stat4Accum file: +iMinDocid testdocs/sqlite3.c /^ i64 iMinDocid; \/* Minimum docid to return *\/$/;" m struct:Fts3Cursor file: +iNewReg testdocs/sqlite3.c /^ int iNewReg; \/* Register for new.* values *\/$/;" m struct:PreUpdate file: +iNewTable testdocs/sqlite3.c /^ int iNewTable; \/* New table number *\/$/;" m struct:SubstContext file: +iNext testdocs/sqlite3.c /^ int iNext; \/* Next slot in aIndex[] not yet returned *\/$/;" m struct:WalIterator::WalSegment file: +iNext testdocs/sqlite3.c /^ int iNext; \/* Offset within aMemory of next record *\/$/;" m union:SorterRecord::__anon25 file: +iNext testdocs/sqlite3.c /^ Pgno iNext; \/* Page number of the next source page to copy *\/$/;" m struct:sqlite3_backup file: +iNext testdocs/sqlite3.c /^ int iNext; \/* Offset in aData[] of next change *\/$/;" m struct:SessionInput file: +iNextId testdocs/sqlite3.c /^ i64 iNextId; \/* Used to allocate unique cursor ids *\/$/;" m struct:Fts5Global file: +iNextSelectId testdocs/sqlite3.c /^ int iNextSelectId; \/* Next available select ID for EXPLAIN output *\/$/;" m struct:Parse file: +iNode testdocs/sqlite3.c /^ i64 iNode; \/* The node number *\/$/;" m struct:RtreeNode file: +iNodeSize testdocs/sqlite3.c /^ int iNodeSize; \/* Size in bytes of each node in the node table *\/$/;" m struct:Rtree file: +iOalSz testdocs/sqlite3.c /^ i64 iOalSz;$/;" m struct:RbuState file: +iOalSz testdocs/sqlite3.c /^ i64 iOalSz;$/;" m struct:sqlite3rbu file: +iOff testdocs/sqlite3.c /^ i64 iOff;$/;" m struct:Fts5ExprCtx file: +iOff testdocs/sqlite3.c /^ int iOff; \/* Current offset within aInput[] *\/$/;" m struct:unicode_cursor file: +iOff testdocs/sqlite3.c /^ int iOff; \/* Current offset within aNode[] *\/$/;" m struct:NodeReader file: +iOff testdocs/sqlite3.c /^ int iOff; \/* Current offset within zIn[] *\/$/;" m struct:HighlightContext file: +iOff testdocs/sqlite3.c /^ int iOff; \/* Offset of this term from read positions *\/$/;" m struct:TermOffset file: +iOff testdocs/sqlite3.c /^ int iOff; \/* Current offset into pData *\/$/;" m struct:Fts5DlidxLvl file: +iOffset testdocs/sqlite3.c /^ i64 iOffset; \/* Value of 'pgOffset' column *\/$/;" m struct:StatCursor file: +iOffset testdocs/sqlite3.c /^ i64 iOffset; \/* Starting offset in main journal *\/$/;" m struct:PagerSavepoint file: +iOffset testdocs/sqlite3.c /^ int iLimit, iOffset; \/* Memory registers holding LIMIT & OFFSET counters *\/$/;" m struct:Select file: +iOffset testdocs/sqlite3.c /^ int iOffset; \/* current position in pInput *\/$/;" m struct:simple_tokenizer_cursor file: +iOffset testdocs/sqlite3.c /^ int iOffset; \/* current position in zInput *\/$/;" m struct:porter_tokenizer_cursor file: +iOffset testdocs/sqlite3.c /^ int iOffset; \/* Byte offset of blob in cursor data *\/$/;" m struct:Incrblob file: +iOffset testdocs/sqlite3.c /^ sqlite3_int64 iOffset; \/* Offset from the beginning of the file *\/$/;" m struct:FilePoint file: +iOnceResetThreshold testdocs/sqlite3.c /^ int iOnceResetThreshold; \/* When to reset OP_Once counters *\/$/;" m struct:Sqlite3Config file: +iOp testdocs/sqlite3.c /^ int iOp; \/* Instruction number of OP_Function *\/$/;" m struct:sqlite3_context file: +iOrDocid testdocs/sqlite3.c /^ i64 iOrDocid;$/;" m struct:Fts3Phrase file: +iOrderByCol testdocs/sqlite3.c /^ u16 iOrderByCol; \/* For ORDER BY, column number in result set *\/$/;" m struct:ExprList::ExprList_item::__anon12::__anon13 file: +iOvfl testdocs/sqlite3.c /^ int iOvfl; \/* Iterates through aOvfl[] *\/$/;" m struct:StatCell file: +iPKey testdocs/sqlite3.c /^ i16 iPKey; \/* If not negative, use aCol[iPKey] as the rowid *\/$/;" m struct:Table file: +iPage testdocs/sqlite3.c /^ i8 iPage; \/* Index of current page in apPage *\/$/;" m struct:BtCursor file: +iPage testdocs/sqlite3.c /^ int iPage; \/* Current entry in aPage[] *\/$/;" m struct:StatCursor file: +iPageno testdocs/sqlite3.c /^ u32 iPageno; \/* Value of 'pageno' column *\/$/;" m struct:StatCursor file: +iParent testdocs/sqlite3.c /^ int iParent; \/* Disable pWC->a[iParent] when this term disabled *\/$/;" m struct:WhereTerm file: +iPgidxOff testdocs/sqlite3.c /^ int iPgidxOff; \/* Next offset in pgidx *\/$/;" m struct:Fts5SegIter file: +iPgno testdocs/sqlite3.c /^ u32 iPgno;$/;" m struct:StatPage file: +iPhrase testdocs/sqlite3.c /^ int iPhrase; \/* Index of this phrase in matchinfo() results *\/$/;" m struct:Fts3Expr file: +iPkSortOrder testdocs/sqlite3.c /^ u8 iPkSortOrder; \/* ASC or DESC for INTEGER PRIMARY KEY *\/$/;" m struct:Parse file: +iPkTnum testdocs/sqlite3.c /^ int iPkTnum; \/* If eType==EXTERNAL, root of PK index *\/$/;" m struct:RbuObjIter file: +iPos testdocs/sqlite3.c /^ i64 iPos; \/* (iCol<<32) + iPos *\/$/;" m struct:Fts5PoslistReader file: +iPos testdocs/sqlite3.c /^ i64 iPos; \/* Current position *\/$/;" m struct:Fts5LookaheadReader file: +iPos testdocs/sqlite3.c /^ int iPos; \/* Current 'pos' value *\/$/;" m struct:Fts3tokCursor file: +iPos testdocs/sqlite3.c /^ int iPos; \/* Current position *\/$/;" m struct:LcsIterator file: +iPos testdocs/sqlite3.c /^ int iPos; \/* Current token offset in zIn[] *\/$/;" m struct:HighlightContext file: +iPos testdocs/sqlite3.c /^ int iPos; \/* Current token position *\/$/;" m struct:Fts5SFinder file: +iPos testdocs/sqlite3.c /^ int iPos; \/* Index of first token in snippet *\/$/;" m struct:SnippetFragment file: +iPos testdocs/sqlite3.c /^ int iPos; \/* Position just read from pList *\/$/;" m struct:TermOffset file: +iPos testdocs/sqlite3.c /^ int iPos; \/* Position of last value written *\/$/;" m struct:Fts5HashEntry file: +iPosOffset testdocs/sqlite3.c /^ int iPosOffset; \/* Tokens count up to end of this phrase *\/$/;" m struct:LcsIterator file: +iPragCName testdocs/sqlite3.c /^ u8 iPragCName; \/* Start of column names in pragCName[] *\/$/;" m struct:PragmaName file: +iPrev testdocs/sqlite3.c /^ i64 iPrev; \/* Previous rowid value written to page *\/$/;" m struct:Fts5DlidxWriter file: +iPrev testdocs/sqlite3.c /^ i64 iPrev;$/;" m struct:Fts5PoslistWriter file: +iPrev testdocs/sqlite3.c /^ u8 iPrev; \/* Previous thread used to flush PMA *\/$/;" m struct:VdbeSorter file: +iPrevDocid testdocs/sqlite3.c /^ sqlite_int64 iPrevDocid; \/* Docid of most recently inserted document *\/$/;" m struct:Fts3Table file: +iPrevId testdocs/sqlite3.c /^ sqlite3_int64 iPrevId; \/* Previous id read from aDoclist *\/$/;" m struct:Fts3Cursor file: +iPrevLangid testdocs/sqlite3.c /^ int iPrevLangid; \/* Langid of recently inserted document *\/$/;" m struct:Fts3Table file: +iPrevPgidx testdocs/sqlite3.c /^ int iPrevPgidx; \/* Previous value written into pgidx *\/$/;" m struct:Fts5PageWriter file: +iPrevRowid testdocs/sqlite3.c /^ i64 iPrevRowid; \/* Previous rowid written to current leaf *\/$/;" m struct:Fts5SegWriter file: +iPrior testdocs/sqlite3.c /^ int iPrior; \/* Last result returned from the iterator *\/$/;" m struct:WalIterator file: +iPrn testdocs/sqlite3.c /^ u32 iPrn; \/* Pseudo-random number used for sampling *\/$/;" m struct:Stat4Accum file: +iRangeEnd testdocs/sqlite3.c /^ int iRangeEnd; \/* If non-zero, last token to include *\/$/;" m struct:HighlightContext file: +iRangeReg testdocs/sqlite3.c /^ int iRangeReg; \/* First register in temporary register block *\/$/;" m struct:Parse file: +iRangeStart testdocs/sqlite3.c /^ int iRangeStart; \/* First token to include *\/$/;" m struct:HighlightContext file: +iReCksum testdocs/sqlite3.c /^ u32 iReCksum; \/* On commit, recalculate checksums from here *\/$/;" m struct:Wal file: +iRead testdocs/sqlite3.c /^ int iRead;$/;" m struct:PoslistOffsetsCtx file: +iReadOff testdocs/sqlite3.c /^ i64 iReadOff; \/* Current read offset *\/$/;" m struct:PmaReader file: +iReg testdocs/sqlite3.c /^ int iReg; \/* Reg with value of this column. 0 means none. *\/$/;" m struct:Parse::yColCache file: +iReinsertHeight testdocs/sqlite3.c /^ int iReinsertHeight; \/* Height of sub-trees Reinsert() has run on *\/$/;" m struct:Rtree file: +iReplace testdocs/sqlite3.c /^ u32 iReplace; \/* Replacement content for JNODE_REPLACE *\/$/;" m union:JsonNode::__anon37 file: +iRightChildPg testdocs/sqlite3.c /^ u32 iRightChildPg; \/* Right-child page number (or 0) *\/$/;" m struct:StatPage file: +iRightJoinTable testdocs/sqlite3.c /^ i16 iRightJoinTable; \/* If EP_FromJoin, the right table of the join *\/$/;" m struct:Expr file: +iRowid testdocs/sqlite3.c /^ i64 iRowid; \/* Rowid in main table of the key *\/$/;" m union:Stat4Sample::__anon26 file: +iRowid testdocs/sqlite3.c /^ i64 iRowid; \/* Node or entry ID *\/$/;" m struct:RtreeCell file: +iRowid testdocs/sqlite3.c /^ i64 iRowid; \/* Current rowid *\/$/;" m struct:Fts5ExprNode file: +iRowid testdocs/sqlite3.c /^ i64 iRowid; \/* Current rowid *\/$/;" m struct:Fts5SegIter file: +iRowid testdocs/sqlite3.c /^ i64 iRowid; \/* Current rowid *\/$/;" m struct:Fts5Sorter file: +iRowid testdocs/sqlite3.c /^ i64 iRowid; \/* Rowid of last value written *\/$/;" m struct:Fts5HashEntry file: +iRowid testdocs/sqlite3.c /^ i64 iRowid; \/* First rowid on leaf iLeafPgno *\/$/;" m struct:Fts5DlidxLvl file: +iRowid testdocs/sqlite3.c /^ i64 iRowid;$/;" m struct:Fts5DoclistIter file: +iRowid testdocs/sqlite3.c /^ i64 iRowid;$/;" m struct:Fts5IndexIter file: +iRowid testdocs/sqlite3.c /^ i64 iRowid;$/;" m struct:Fts5IntegrityCtx file: +iRowid testdocs/sqlite3.c /^ int iRowid; \/* Current 'rowid' value *\/$/;" m struct:Fts3tokCursor file: +iRowid testdocs/sqlite3.c /^ sqlite3_int64 iRowid; \/* Rowid for current entry *\/$/;" m struct:sqlite3_rtree_query_info file: +iRowid testdocs/sqlite3.c /^ sqlite3_int64 iRowid; \/* Current rowid *\/$/;" m struct:Fts3auxCursor file: +iRowid testdocs/sqlite3.c /^ sqlite_int64 iRowid; \/* Current rowid *\/$/;" m struct:PragmaVtabCursor file: +iRowid testdocs/sqlite3.c /^ u32 iRowid; \/* The rowid *\/$/;" m struct:JsonEachCursor file: +iRowidOffset testdocs/sqlite3.c /^ int iRowidOffset; \/* Current entry in aRowidOffset[] *\/$/;" m struct:Fts5SegIter file: +iSDParm testdocs/sqlite3.c /^ int iSDParm; \/* A parameter used by the eDest disposal method *\/$/;" m struct:SelectDest file: +iSavepoint testdocs/sqlite3.c /^ int iSavepoint; \/* Number of open savepoints (0 -> none) *\/$/;" m struct:Fts5TransactionState file: +iSavepoint testdocs/sqlite3.c /^ int iSavepoint; \/* Depth of the SAVEPOINT stack *\/$/;" m struct:VTable file: +iSdst testdocs/sqlite3.c /^ int iSdst; \/* Base register where results are written *\/$/;" m struct:SelectDest file: +iSegid testdocs/sqlite3.c /^ int iSegid; \/* Segid to write to *\/$/;" m struct:Fts5SegWriter file: +iSegid testdocs/sqlite3.c /^ int iSegid; \/* Segment id *\/$/;" m struct:Fts5StructureSegment file: +iSegid testdocs/sqlite3.c /^ int iSegid;$/;" m struct:Fts5DlidxIter file: +iSelectID testdocs/sqlite3.c /^ int iSelectID; \/* The "Select-ID" for this loop *\/$/;" m struct:ScanStatus file: +iSelectId testdocs/sqlite3.c /^ u8 iSelectId; \/* If pSelect!=0, the id of the sub-select in EQP *\/$/;" m struct:SrcList::SrcList_item file: +iSelectId testdocs/sqlite3.c /^ int iSelectId; \/* ID of current select for EXPLAIN output *\/$/;" m struct:Parse file: +iSelfTab testdocs/sqlite3.c /^ int iSelfTab; \/* Table of an index whose exprs are being coded *\/$/;" m struct:Parse file: +iSize testdocs/sqlite3.c /^ i64 iSize; \/* Size of this allocation *\/$/;" m struct:MemBlockHdr file: +iSize testdocs/sqlite3.c /^ u32 iSize; \/* Maximum bit index. Max iSize is 4,294,967,296. *\/$/;" m struct:Bitvec file: +iSortIdx testdocs/sqlite3.c /^ u8 iSortIdx; \/* Sorting index number. 0==None *\/$/;" m struct:WhereLoop file: +iSorterColumn testdocs/sqlite3.c /^ int iSorterColumn; \/* Column number in the sorting index *\/$/;" m struct:AggInfo::AggInfo_col file: +iSpecial testdocs/sqlite3.c /^ i64 iSpecial; \/* Result of special query *\/$/;" m struct:Fts5Cursor file: +iSrcLine testdocs/sqlite3.c /^ int iSrcLine; \/* Source-code line that generated this opcode *\/$/;" m struct:VdbeOp file: +iStart testdocs/sqlite3.c /^ int iStart; \/* Current 'start' value *\/$/;" m struct:Fts3tokCursor file: +iStart testdocs/sqlite3.c /^ int iStart; \/* First token in coalesced phrase instance *\/$/;" m struct:CInstIter file: +iStart testdocs/sqlite3.c /^ sqlite3_int64 iStart; \/* Block number of first allocated block *\/$/;" m struct:IncrmergeWriter file: +iStartBlock testdocs/sqlite3.c /^ sqlite3_int64 iStartBlock; \/* Rowid of first leaf block to traverse *\/$/;" m struct:Fts3SegReader file: +iStartOff testdocs/sqlite3.c /^ i64 iStartOff; \/* Offset to start writing file at *\/$/;" m struct:IncrMerger file: +iStatement testdocs/sqlite3.c /^ int iStatement; \/* Statement number (or 0 if has not opened stmt) *\/$/;" m struct:Vdbe file: +iStrategy testdocs/sqlite3.c /^ int iStrategy; \/* Copy of idxNum search parameter *\/$/;" m struct:RtreeCursor file: +iStructVersion testdocs/sqlite3.c /^ i64 iStructVersion; \/* data_version when pStruct read *\/$/;" m struct:Fts5Index file: +iSub testdocs/sqlite3.c /^ int iSub; \/* 0 = main program, 1 = first sub-program etc. *\/$/;" m struct:VdbeOpIter file: +iSubRec testdocs/sqlite3.c /^ Pgno iSubRec; \/* Index of first record in sub-journal *\/$/;" m struct:PagerSavepoint file: +iSum testdocs/sqlite3.c /^ i64 iSum; \/* Integer sum *\/$/;" m struct:SumCtx file: +iSwitchRowid testdocs/sqlite3.c /^ i64 iSwitchRowid; \/* Firstest rowid of other than aFirst[1] *\/$/;" m struct:Fts5Iter file: +iSyncPoint testdocs/sqlite3.c /^ sqlite3_int64 iSyncPoint; \/* Fsync at this offset *\/$/;" m struct:WalWriter file: +iSysErrno testdocs/sqlite3.c /^ int iSysErrno; \/* Errno value from last system error *\/$/;" m struct:sqlite3 file: +iSzPoslist testdocs/sqlite3.c /^ int iSzPoslist; \/* Offset of space for 4-byte poslist size *\/$/;" m struct:Fts5HashEntry file: +iTab testdocs/sqlite3.c /^ int iTab; \/* The root page of the table to be locked *\/$/;" m struct:TableLock file: +iTab testdocs/sqlite3.c /^ u8 iTab; \/* Position in FROM clause of table for this loop *\/$/;" m struct:WhereLoop file: +iTabCur testdocs/sqlite3.c /^ int iTabCur; \/* The VDBE cursor used to access the table *\/$/;" m struct:WhereLevel file: +iTabCur testdocs/sqlite3.c /^ int iTabCur; \/* The cursor of the corresponding table *\/$/;" m struct:IdxExprTrans file: +iTabCur testdocs/sqlite3.c /^ int iTabCur; \/* Cursor for the main table *\/$/;" m struct:CCurHint file: +iTable testdocs/sqlite3.c /^ int iTable; \/* Cursor number of the source table *\/$/;" m struct:AggInfo::AggInfo_col file: +iTable testdocs/sqlite3.c /^ int iTable; \/* Table cursor number *\/$/;" m struct:Parse::yColCache file: +iTable testdocs/sqlite3.c /^ Pgno iTable; \/* Root page of table *\/$/;" m struct:BtLock file: +iTable testdocs/sqlite3.c /^ int iTable; \/* Replace references to this table *\/$/;" m struct:SubstContext file: +iTable testdocs/sqlite3.c /^ int iTable; \/* TK_COLUMN: cursor number of table holding column$/;" m struct:Expr file: +iTail testdocs/sqlite3.c /^ int iTail; \/* Next value in trailing position list *\/$/;" m struct:SnippetPhrase file: +iTerm testdocs/sqlite3.c /^ int iTerm;$/;" m struct:TermOffsetCtx file: +iTermLeafOffset testdocs/sqlite3.c /^ int iTermLeafOffset;$/;" m struct:Fts5SegIter file: +iTermLeafPgno testdocs/sqlite3.c /^ int iTermLeafPgno;$/;" m struct:Fts5SegIter file: +iTermOffset testdocs/sqlite3.c /^ int iTermOffset; \/* Used internally - xBestIndex should ignore *\/$/;" m struct:sqlite3_index_info::sqlite3_index_constraint file: +iTnum testdocs/sqlite3.c /^ int iTnum; \/* Root page of current object *\/$/;" m struct:RbuObjIter file: +iToken testdocs/sqlite3.c /^ int iToken; \/* Index of next token to be returned *\/$/;" m struct:unicode_cursor file: +iToken testdocs/sqlite3.c /^ int iToken; \/* Position of token in phrase *\/$/;" m struct:Fts3TokenAndCost file: +iToken testdocs/sqlite3.c /^ int iToken; \/* index of next token to be returned *\/$/;" m struct:porter_tokenizer_cursor file: +iToken testdocs/sqlite3.c /^ int iToken; \/* index of next token to be returned *\/$/;" m struct:simple_tokenizer_cursor file: +iToken testdocs/sqlite3.c /^ int iToken;$/;" m struct:IcuCursor file: +iTop testdocs/sqlite3.c /^ int iTop; \/* The very beginning of the WHERE loop *\/$/;" m struct:WhereInfo file: +iVal testdocs/sqlite3.c /^ int iVal;$/;" m struct:ValueNewStat4Ctx file: +iValue testdocs/sqlite3.c /^ int iValue; \/* Non-negative integer value if EP_IntValue *\/$/;" m union:Expr::__anon10 file: +iVersion testdocs/sqlite3.c /^ int iVersion; \/* Currently always set to 2 *\/$/;" m struct:fts5_api file: +iVersion testdocs/sqlite3.c /^ int iVersion; \/* Currently always set to 3 *\/$/;" m struct:Fts5ExtensionApi file: +iVersion testdocs/sqlite3.c /^ int iVersion; \/* Structure version number (currently 3) *\/$/;" m struct:sqlite3_vfs file: +iVersion testdocs/sqlite3.c /^ int iVersion;$/;" m struct:sqlite3_io_methods file: +iVersion testdocs/sqlite3.c /^ int iVersion;$/;" m struct:sqlite3_module file: +iVersion testdocs/sqlite3.c /^ int iVersion;$/;" m struct:sqlite3_pcache_methods2 file: +iVersion testdocs/sqlite3.c /^ int iVersion;$/;" m struct:sqlite3_tokenizer_module file: +iVersion testdocs/sqlite3.c /^ u32 iVersion; \/* Wal-index version *\/$/;" m struct:WalIndexHdr file: +iWalCksum testdocs/sqlite3.c /^ i64 iWalCksum;$/;" m struct:RbuState file: +iWalCksum testdocs/sqlite3.c /^ i64 iWalCksum;$/;" m struct:sqlite3rbu file: +iWalFrame testdocs/sqlite3.c /^ u32 iWalFrame;$/;" m struct:RbuFrame file: +iWrite testdocs/sqlite3.c /^ int iWrite;$/;" m struct:PoslistOffsetsCtx file: +iWriteOff testdocs/sqlite3.c /^ i64 iWriteOff; \/* Offset of start of buffer in file *\/$/;" m struct:PmaWriter file: +iWriteRowid testdocs/sqlite3.c /^ i64 iWriteRowid; \/* Rowid for current doc being written *\/$/;" m struct:Fts5Index file: +iWriteVer testdocs/sqlite3.c /^ u8 iWriteVer; \/* "write-version" value for main db files *\/$/;" m struct:rbu_file file: +iZero testdocs/sqlite3.c /^ int iZero; \/* Frame number associated with aPgno[0] *\/$/;" m struct:WalIterator::WalSegment file: +icuCaseFunc16 testdocs/sqlite3.c /^static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){$/;" f file: +icuClose testdocs/sqlite3.c /^static int icuClose(sqlite3_tokenizer_cursor *pCursor){$/;" f file: +icuCollationColl testdocs/sqlite3.c /^static int icuCollationColl($/;" f file: +icuCollationDel testdocs/sqlite3.c /^static void icuCollationDel(void *pCtx){$/;" f file: +icuCreate testdocs/sqlite3.c /^static int icuCreate($/;" f file: +icuDestroy testdocs/sqlite3.c /^static int icuDestroy(sqlite3_tokenizer *pTokenizer){$/;" f file: +icuFunctionError testdocs/sqlite3.c /^static void icuFunctionError($/;" f file: +icuLikeCompare testdocs/sqlite3.c /^static int icuLikeCompare($/;" f file: +icuLikeFunc testdocs/sqlite3.c /^static void icuLikeFunc($/;" f file: +icuLoadCollation testdocs/sqlite3.c /^static void icuLoadCollation($/;" f file: +icuNext testdocs/sqlite3.c /^static int icuNext($/;" f file: +icuOpen testdocs/sqlite3.c /^static int icuOpen($/;" f file: +icuRegexpDelete testdocs/sqlite3.c /^static void icuRegexpDelete(void *p){$/;" f file: +icuRegexpFunc testdocs/sqlite3.c /^static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){$/;" f file: +icuTokenizerModule testdocs/sqlite3.c /^static const sqlite3_tokenizer_module icuTokenizerModule = {$/;" v file: +icuUtf8Trans1 testdocs/sqlite3.c /^static const unsigned char icuUtf8Trans1[] = {$/;" v file: +id testdocs/sqlite3.c /^ int id; \/* Mutex type *\/$/;" m struct:sqlite3_mutex file: +id testdocs/sqlite3.c /^ int id; \/* The mutex type *\/$/;" m struct:sqlite3_debug_mutex file: +id testdocs/sqlite3.c /^ sqlite3_int64 id; \/* Node ID *\/$/;" m struct:RtreeSearchPoint file: +id testdocs/sqlite3.c /^ u8 id; \/* Id of this connection with its winShmNode *\/$/;" m struct:winShm file: +id testdocs/sqlite3.c /^ u8 id; \/* Id of this connection within its unixShmNode *\/$/;" m struct:unixShm file: +id testdocs/sqlite3.c /^ unsigned id; \/* The thread identifier *\/$/;" m struct:SQLiteThread file: +ident stdc.h /^#define ident(/;" d +identLength testdocs/sqlite3.c /^static int identLength(const char *z){$/;" f file: +identPut testdocs/sqlite3.c /^static void identPut(char *z, int *pIdx, char *zSignedIdent){$/;" f file: +idx testdocs/sqlite3.c /^ int idx; \/* Index in some Table.aCol[] of a column named zName *\/$/;" m struct:IdList::IdList_item file: +idxFlags testdocs/sqlite3.c /^ int idxFlags; \/* Mask of SQLITE_INDEX_SCAN_* flags *\/$/;" m struct:sqlite3_index_info file: +idxHash testdocs/sqlite3.c /^ Hash idxHash; \/* All (named) indices indexed by name *\/$/;" m struct:Schema file: +idxNum testdocs/sqlite3.c /^ int idxNum; \/* Index number *\/$/;" m struct:WhereLoop::__anon29::__anon31 file: +idxNum testdocs/sqlite3.c /^ int idxNum; \/* Number used to identify the index *\/$/;" m struct:sqlite3_index_info file: +idxStr testdocs/sqlite3.c /^ char *idxStr; \/* Index identifier string *\/$/;" m struct:WhereLoop::__anon29::__anon31 file: +idxStr testdocs/sqlite3.c /^ char *idxStr; \/* String, possibly obtained from sqlite3_malloc *\/$/;" m struct:sqlite3_index_info file: +idxType testdocs/sqlite3.c /^ unsigned idxType:2; \/* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX *\/$/;" m struct:Index file: +idxaff testdocs/sqlite3.c /^ char idxaff; \/* Must match this affinity, if zCollName!=NULL *\/$/;" m struct:WhereScan file: +imposterTable testdocs/sqlite3.c /^ u8 imposterTable; \/* Building an imposter table *\/$/;" m struct:sqlite3::sqlite3InitInfo file: +in testdocs/sqlite3.c /^ } in; \/* Used when pWLoop->wsFlags&WHERE_IN_ABLE *\/$/;" m union:WhereLevel::__anon27 typeref:struct:WhereLevel::__anon27::__anon28 file: +in testdocs/sqlite3.c /^ SessionInput in; \/* Input buffer or stream *\/$/;" m struct:sqlite3_changeset_iter file: +inNormalWrite testdocs/sqlite3.c /^ unsigned char inNormalWrite; \/* True if in a normal write operation *\/$/;" m struct:unixFile file: +inProgress testdocs/sqlite3.c /^ int inProgress; \/* True while initialization in progress *\/$/;" m struct:Sqlite3Config file: +inTrans testdocs/sqlite3.c /^ u8 inTrans; \/* TRANS_NONE, TRANS_READ or TRANS_WRITE *\/$/;" m struct:Btree file: +inTransaction testdocs/sqlite3.c /^ int inTransaction; \/* True after xBegin but before xCommit\/xRollback *\/$/;" m struct:Fts3Table file: +inTransaction testdocs/sqlite3.c /^ u8 inTransaction; \/* Transaction state *\/$/;" m struct:BtShared file: +inWrTrans testdocs/sqlite3.c /^ u8 inWrTrans; \/* True if inside write transaction *\/$/;" m struct:Rtree file: +incrAggDepth testdocs/sqlite3.c /^static int incrAggDepth(Walker *pWalker, Expr *pExpr){$/;" f file: +incrAggFunctionDepth testdocs/sqlite3.c /^static void incrAggFunctionDepth(Expr *pExpr, int N){$/;" f file: +incrPhraseTokenNext testdocs/sqlite3.c /^static int incrPhraseTokenNext($/;" f file: +incrVacuum testdocs/sqlite3.c /^ u8 incrVacuum; \/* True if incr-vacuum is enabled *\/$/;" m struct:BtShared file: +incrVacuumStep testdocs/sqlite3.c /^static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){$/;" f file: +indexColumnNotNull testdocs/sqlite3.c /^static int indexColumnNotNull(Index *pIdx, int iCol){$/;" f file: +indexMightHelpWithOrderBy testdocs/sqlite3.c /^static int indexMightHelpWithOrderBy($/;" f file: +indexable testdocs/sqlite3.c /^ Bitmask indexable; \/* Bitmask of all indexable tables in the clause *\/$/;" m struct:WhereOrInfo file: +info testdocs/sqlite3.c /^ CellInfo info; \/* A parse of the cell we are pointing at *\/$/;" m struct:BtCursor file: +init testdocs/sqlite3.c /^ } init;$/;" m struct:sqlite3 typeref:struct:sqlite3::sqlite3InitInfo file: +initAvgEq testdocs/sqlite3.c /^static void initAvgEq(Index *pIdx){$/;" f file: +initMaskSet testdocs/sqlite3.c /^#define initMaskSet(/;" d file: +initMemArray testdocs/sqlite3.c /^static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){$/;" f file: +ino testdocs/sqlite3.c /^ u64 ino; \/* Inode number *\/$/;" m struct:unixFileId file: +inodeList testdocs/sqlite3.c /^static unixInodeInfo *inodeList = 0;$/;" v file: +ins edit.h /^ } ins;$/;" m union:Log::__anon2 typeref:struct:Log::__anon2::__anon3 +insert buf.c /^static size_t insert(Buf* buf, size_t off, Rune rune) {$/;" f file: +insert edit.h /^ bool insert; \/* whether this operation was an insert or delete *\/$/;" m struct:Log +insertBinaryOperator testdocs/sqlite3.c /^static void insertBinaryOperator($/;" f file: +insertCell testdocs/sqlite3.c /^static void insertCell($/;" f file: +insertElement testdocs/sqlite3.c /^static void insertElement($/;" f file: +inspect testdocs/waf /^import os, sys, inspect$/;" i +instrFunc testdocs/sqlite3.c /^static void instrFunc($/;" f file: +int16 stdc.h /^typedef int16_t int16;$/;" t +int32 stdc.h /^typedef int32_t int32;$/;" t +int64 stdc.h /^typedef int64_t int64;$/;" t +int8 stdc.h /^typedef int8_t int8;$/;" t +intKey testdocs/sqlite3.c /^ u8 intKey; \/* True if table b-trees. False for index b-trees *\/$/;" m struct:MemPage file: +intKeyLeaf testdocs/sqlite3.c /^ u8 intKeyLeaf; \/* True if the leaf of an intKey table *\/$/;" m struct:MemPage file: +intTestFunc testdocs/sqlite3.c /^static void intTestFunc($/;" f file: +integrityCheckResultRow testdocs/sqlite3.c /^static int integrityCheckResultRow(Vdbe *v, int regResult){$/;" f file: +interruptx testdocs/sqlite3.c /^ void (*interruptx)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +intptr stdc.h /^typedef intptr_t intptr;$/;" t +invalidateAllOverflowCache testdocs/sqlite3.c /^static void invalidateAllOverflowCache(BtShared *pBt){$/;" f file: +invalidateIncrblobCursors testdocs/sqlite3.c /^ #define invalidateIncrblobCursors(/;" d file: +invalidateIncrblobCursors testdocs/sqlite3.c /^static void invalidateIncrblobCursors($/;" f file: +invalidateOverflowCache testdocs/sqlite3.c /^#define invalidateOverflowCache(/;" d file: +invalidateTempStorage testdocs/sqlite3.c /^static int invalidateTempStorage(Parse *pParse){$/;" f file: +invokeProfileCallback testdocs/sqlite3.c /^static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){$/;" f file: +invokeValueDestructor testdocs/sqlite3.c /^static int invokeValueDestructor($/;" f file: +isAllZero testdocs/sqlite3.c /^static int isAllZero(const char *z, int n){$/;" f file: +isAnchor testdocs/sqlite3.c /^ u8 isAnchor; \/* This is the PGroup.lru element *\/$/;" m struct:PgHdr1 file: +isAttached testdocs/sqlite3.c /^ int isAttached; \/* True once backup has been registered with pager *\/$/;" m struct:sqlite3_backup file: +isBulkLocal testdocs/sqlite3.c /^ u8 isBulkLocal; \/* This page from bulk local storage *\/$/;" m struct:PgHdr1 file: +isCandidateForInOpt testdocs/sqlite3.c /^static Select *isCandidateForInOpt(Expr *pX){$/;" f file: +isConsonant testdocs/sqlite3.c /^static int isConsonant(const char *z){$/;" f file: +isCorrelated testdocs/sqlite3.c /^ unsigned isCorrelated :1; \/* True if sub-query is correlated *\/$/;" m struct:SrcList::SrcList_item::__anon14 file: +isCovering testdocs/sqlite3.c /^ unsigned isCovering:1; \/* True if this is a covering index *\/$/;" m struct:Index file: +isDate testdocs/sqlite3.c /^static int isDate($/;" f file: +isDeferred testdocs/sqlite3.c /^ u8 isDeferred; \/* True if constraint checking is deferred till COMMIT *\/$/;" m struct:FKey file: +isDelim testdocs/sqlite3.c /^#define isDelim(/;" d file: +isDirty testdocs/sqlite3.c /^ int isDirty; \/* True if the node needs to be written to disk *\/$/;" m struct:RtreeNode file: +isDistinctRedundant testdocs/sqlite3.c /^static int isDistinctRedundant($/;" f file: +isEof testdocs/sqlite3.c /^ int isEof; \/* After pStmt has returned SQLITE_DONE *\/$/;" m struct:StatCursor file: +isEof testdocs/sqlite3.c /^ int isEof; \/* True if cursor is at EOF *\/$/;" m struct:Fts3auxCursor file: +isEof testdocs/sqlite3.c /^ u8 isEof; \/* True if at End Of Results *\/$/;" m struct:Fts3Cursor file: +isEphemeral testdocs/sqlite3.c /^ Bool isEphemeral:1; \/* True for an ephemeral table *\/$/;" m struct:VdbeCursor file: +isError testdocs/sqlite3.c /^ char isError; \/* An overflow has occurred *\/$/;" m struct:DateTime file: +isError testdocs/sqlite3.c /^ int isError; \/* Error code returned by the function. *\/$/;" m struct:sqlite3_context file: +isFatalError testdocs/sqlite3.c /^static int isFatalError(int rc){$/;" f file: +isIndexedBy testdocs/sqlite3.c /^ unsigned isIndexedBy :1; \/* True if there is an INDEXED BY clause *\/$/;" m struct:SrcList::SrcList_item::__anon14 file: +isInit testdocs/sqlite3.c /^ int isInit; \/* True after initialization has finished *\/$/;" m struct:Sqlite3Config file: +isInit testdocs/sqlite3.c /^ int isInit; \/* True if initialized *\/$/;" m struct:PCacheGlobal file: +isInit testdocs/sqlite3.c /^ u8 isInit; \/* 1 when initialized *\/$/;" m struct:WalIndexHdr file: +isInit testdocs/sqlite3.c /^ u8 isInit; \/* True if previously initialized. MUST BE FIRST! *\/$/;" m struct:MemPage file: +isInit testdocs/sqlite3.c /^ unsigned char isInit; \/* True if initialized *\/$/;" m struct:sqlite3PrngType file: +isInterrupted testdocs/sqlite3.c /^ volatile int isInterrupted; \/* True if sqlite3_interrupt has been called *\/$/;" m union:sqlite3::__anon8 file: +isLeftJoin testdocs/sqlite3.c /^ int isLeftJoin; \/* Add TK_IF_NULL_ROW opcodes on each replacement *\/$/;" m struct:SubstContext file: +isLikeOrGlob testdocs/sqlite3.c /^static int isLikeOrGlob($/;" f file: +isLookaside testdocs/sqlite3.c /^#define isLookaside(/;" d file: +isLookaside testdocs/sqlite3.c /^static int isLookaside(sqlite3 *db, void *p){$/;" f file: +isMallocInit testdocs/sqlite3.c /^ int isMallocInit; \/* True after malloc is initialized *\/$/;" m struct:Sqlite3Config file: +isMalloced testdocs/sqlite3.c /^#define isMalloced(/;" d file: +isMatchOfColumn testdocs/sqlite3.c /^static int isMatchOfColumn($/;" f file: +isMatchinfoNeeded testdocs/sqlite3.c /^ int isMatchinfoNeeded; \/* True when aMatchinfo[] needs filling in *\/$/;" m struct:Fts3Cursor file: +isMultiWrite testdocs/sqlite3.c /^ u8 isMultiWrite; \/* True if statement may modify\/insert multiple rows *\/$/;" m struct:Parse file: +isMutexInit testdocs/sqlite3.c /^ int isMutexInit; \/* True after mutexes are initialized *\/$/;" m struct:Sqlite3Config file: +isNot testdocs/sqlite3.c /^ int isNot; \/* True if getNextNode() sees a unary - *\/$/;" m struct:ParseContext file: +isOpen testdocs/sqlite3.c /^#define isOpen(/;" d file: +isOrdered testdocs/sqlite3.c /^ i8 isOrdered; \/* True if satisfies ORDER BY *\/$/;" m struct:WhereLoop::__anon29::__anon31 file: +isOrdered testdocs/sqlite3.c /^ Bool isOrdered:1; \/* True if the table is not BTREE_UNORDERED *\/$/;" m struct:VdbeCursor file: +isOrdered testdocs/sqlite3.c /^ i8 isOrdered; \/* No. of ORDER BY terms satisfied. -1 for unknown *\/$/;" m struct:WherePath file: +isPCacheInit testdocs/sqlite3.c /^ int isPCacheInit; \/* True after malloc is initialized *\/$/;" m struct:Sqlite3Config file: +isPSample testdocs/sqlite3.c /^ u8 isPSample; \/* True if a periodic sample *\/$/;" m struct:Stat4Sample file: +isPinned testdocs/sqlite3.c /^ u8 isPinned; \/* Page in use, not on the LRU list *\/$/;" m struct:PgHdr1 file: +isPrefix testdocs/sqlite3.c /^ int isPrefix; \/* True if token ends with a "*" character *\/$/;" m struct:Fts3PhraseToken file: +isPrepareV2 testdocs/sqlite3.c /^ bft isPrepareV2:1; \/* True if prepared with prepare_v2() *\/$/;" m struct:Vdbe file: +isReadonly testdocs/sqlite3.c /^ u8 isReadonly; \/* True if read-only *\/$/;" m struct:unixShmNode file: +isRecursive testdocs/sqlite3.c /^ unsigned isRecursive :1; \/* True for recursive reference in WITH *\/$/;" m struct:SrcList::SrcList_item::__anon14 file: +isRequireSeek testdocs/sqlite3.c /^ u8 isRequireSeek; \/* True if must seek pStmt to %_content row *\/$/;" m struct:Fts3Cursor file: +isResized testdocs/sqlite3.c /^ unsigned isResized:1; \/* True if resizeIndexObject() has been called *\/$/;" m struct:Index file: +isSelfJoinView testdocs/sqlite3.c /^static struct SrcList_item *isSelfJoinView($/;" f file: +isSetNullAction testdocs/sqlite3.c /^static int isSetNullAction(Parse *pParse, FKey *pFKey){$/;" f file: +isSimpleCount testdocs/sqlite3.c /^static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){$/;" f file: +isSorter testdocs/sqlite3.c /^#define isSorter(/;" d file: +isSystemTable testdocs/sqlite3.c /^static int isSystemTable(Parse *pParse, const char *zName){$/;" f file: +isTabFunc testdocs/sqlite3.c /^ unsigned isTabFunc :1; \/* True if table-valued-function syntax *\/$/;" m struct:SrcList::SrcList_item::__anon14 file: +isTable testdocs/sqlite3.c /^ u8 isTable; \/* True for rowid tables. False for indexes *\/$/;" m struct:VdbeCursor file: +isTnct testdocs/sqlite3.c /^ u8 isTnct; \/* True if the DISTINCT keyword is present *\/$/;" m struct:DistinctCtx file: +isTransactionSavepoint testdocs/sqlite3.c /^ u8 isTransactionSavepoint; \/* True if the outermost savepoint is a TS *\/$/;" m struct:sqlite3 file: +isView testdocs/sqlite3.c /^ #undef isView$/;" d file: +isView testdocs/sqlite3.c /^# define isView /;" d file: +isView testdocs/sqlite3.c /^# undef isView$/;" d file: +isVowel testdocs/sqlite3.c /^static int isVowel(const char *z){$/;" f file: +isWriteLock testdocs/sqlite3.c /^ u8 isWriteLock; \/* True for write lock. False for a read lock *\/$/;" m struct:TableLock file: +iter testdocs/sqlite3.c /^ CInstIter iter; \/* Coalesced Instance Iterator *\/$/;" m struct:HighlightContext file: +ix testdocs/sqlite3.c /^ int ix[BMS]; \/* Cursor assigned to each bit *\/$/;" m struct:WhereMaskSet file: +ix testdocs/sqlite3.c /^ u16 ix; \/* Current index for apPage[iPage] *\/$/;" m struct:BtCursor file: +j testdocs/sqlite3.c /^ unsigned char i, j; \/* State variables *\/$/;" m struct:sqlite3PrngType file: +jfd testdocs/sqlite3.c /^ sqlite3_file *jfd; \/* File descriptor for main journal *\/$/;" m struct:Pager file: +jnFlags testdocs/sqlite3.c /^ u8 jnFlags; \/* JNODE flags *\/$/;" m struct:JsonNode file: +join testdocs/waf /^join = os.path.join$/;" v +jointype testdocs/sqlite3.c /^ u8 jointype; \/* Type of join between this table and the previous *\/$/;" m struct:SrcList::SrcList_item::__anon14 file: +journalHdr testdocs/sqlite3.c /^ i64 journalHdr; \/* Byte offset to previous journal header *\/$/;" m struct:Pager file: +journalHdrOffset testdocs/sqlite3.c /^static i64 journalHdrOffset(Pager *pPager){$/;" f file: +journalMode testdocs/sqlite3.c /^ u8 journalMode; \/* One of the PAGER_JOURNALMODE_* values *\/$/;" m struct:Pager file: +journalOff testdocs/sqlite3.c /^ i64 journalOff; \/* Current write offset in the journal file *\/$/;" m struct:Pager file: +journalSizeLimit testdocs/sqlite3.c /^ i64 journalSizeLimit; \/* Size limit for persistent journal files *\/$/;" m struct:Pager file: +jrnlBufferSize testdocs/sqlite3.c /^# define jrnlBufferSize(/;" d file: +jrnlBufferSize testdocs/sqlite3.c /^static int jrnlBufferSize(Pager *pPager){$/;" f file: +jsonAppendChar testdocs/sqlite3.c /^static void jsonAppendChar(JsonString *p, char c){$/;" f file: +jsonAppendRaw testdocs/sqlite3.c /^static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){$/;" f file: +jsonAppendSeparator testdocs/sqlite3.c /^static void jsonAppendSeparator(JsonString *p){$/;" f file: +jsonAppendString testdocs/sqlite3.c /^static void jsonAppendString(JsonString *p, const char *zIn, u32 N){$/;" f file: +jsonAppendValue testdocs/sqlite3.c /^static void jsonAppendValue($/;" f file: +jsonArrayFinal testdocs/sqlite3.c /^static void jsonArrayFinal(sqlite3_context *ctx){$/;" f file: +jsonArrayFunc testdocs/sqlite3.c /^static void jsonArrayFunc($/;" f file: +jsonArrayLengthFunc testdocs/sqlite3.c /^static void jsonArrayLengthFunc($/;" f file: +jsonArrayStep testdocs/sqlite3.c /^static void jsonArrayStep($/;" f file: +jsonEachBestIndex testdocs/sqlite3.c /^static int jsonEachBestIndex($/;" f file: +jsonEachClose testdocs/sqlite3.c /^static int jsonEachClose(sqlite3_vtab_cursor *cur){$/;" f file: +jsonEachColumn testdocs/sqlite3.c /^static int jsonEachColumn($/;" f file: +jsonEachComputePath testdocs/sqlite3.c /^static void jsonEachComputePath($/;" f file: +jsonEachConnect testdocs/sqlite3.c /^static int jsonEachConnect($/;" f file: +jsonEachCursorReset testdocs/sqlite3.c /^static void jsonEachCursorReset(JsonEachCursor *p){$/;" f file: +jsonEachDisconnect testdocs/sqlite3.c /^static int jsonEachDisconnect(sqlite3_vtab *pVtab){$/;" f file: +jsonEachEof testdocs/sqlite3.c /^static int jsonEachEof(sqlite3_vtab_cursor *cur){$/;" f file: +jsonEachFilter testdocs/sqlite3.c /^static int jsonEachFilter($/;" f file: +jsonEachModule testdocs/sqlite3.c /^static sqlite3_module jsonEachModule = {$/;" v file: +jsonEachNext testdocs/sqlite3.c /^static int jsonEachNext(sqlite3_vtab_cursor *cur){$/;" f file: +jsonEachOpenEach testdocs/sqlite3.c /^static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){$/;" f file: +jsonEachOpenTree testdocs/sqlite3.c /^static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){$/;" f file: +jsonEachRowid testdocs/sqlite3.c /^static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){$/;" f file: +jsonExtractFunc testdocs/sqlite3.c /^static void jsonExtractFunc($/;" f file: +jsonGrow testdocs/sqlite3.c /^static int jsonGrow(JsonString *p, u32 N){$/;" f file: +jsonInit testdocs/sqlite3.c /^static void jsonInit(JsonString *p, sqlite3_context *pCtx){$/;" f file: +jsonIs4Hex testdocs/sqlite3.c /^static int jsonIs4Hex(const char *z){$/;" f file: +jsonIsSpace testdocs/sqlite3.c /^static const char jsonIsSpace[] = {$/;" v file: +jsonLabelCompare testdocs/sqlite3.c /^static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){$/;" f file: +jsonLookup testdocs/sqlite3.c /^static JsonNode *jsonLookup($/;" f file: +jsonLookupAppend testdocs/sqlite3.c /^static JsonNode *jsonLookupAppend($/;" f file: +jsonLookupStep testdocs/sqlite3.c /^static JsonNode *jsonLookupStep($/;" f file: +jsonMergePatch testdocs/sqlite3.c /^static JsonNode *jsonMergePatch($/;" f file: +jsonNodeSize testdocs/sqlite3.c /^static u32 jsonNodeSize(JsonNode *pNode){$/;" f file: +jsonObjectFinal testdocs/sqlite3.c /^static void jsonObjectFinal(sqlite3_context *ctx){$/;" f file: +jsonObjectFunc testdocs/sqlite3.c /^static void jsonObjectFunc($/;" f file: +jsonObjectStep testdocs/sqlite3.c /^static void jsonObjectStep($/;" f file: +jsonOom testdocs/sqlite3.c /^static void jsonOom(JsonString *p){$/;" f file: +jsonParse testdocs/sqlite3.c /^static int jsonParse($/;" f file: +jsonParseAddNode testdocs/sqlite3.c /^static int jsonParseAddNode($/;" f file: +jsonParseAddNodeExpand testdocs/sqlite3.c /^static JSON_NOINLINE int jsonParseAddNodeExpand($/;" f file: +jsonParseCached testdocs/sqlite3.c /^static JsonParse *jsonParseCached($/;" f file: +jsonParseFillInParentage testdocs/sqlite3.c /^static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){$/;" f file: +jsonParseFindParents testdocs/sqlite3.c /^static int jsonParseFindParents(JsonParse *pParse){$/;" f file: +jsonParseFree testdocs/sqlite3.c /^static void jsonParseFree(JsonParse *pParse){$/;" f file: +jsonParseFunc testdocs/sqlite3.c /^static void jsonParseFunc($/;" f file: +jsonParseReset testdocs/sqlite3.c /^static void jsonParseReset(JsonParse *pParse){$/;" f file: +jsonParseValue testdocs/sqlite3.c /^static int jsonParseValue(JsonParse *pParse, u32 i){$/;" f file: +jsonPatchFunc testdocs/sqlite3.c /^static void jsonPatchFunc($/;" f file: +jsonPathSyntaxError testdocs/sqlite3.c /^static char *jsonPathSyntaxError(const char *zErr){$/;" f file: +jsonPrintf testdocs/sqlite3.c /^static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){$/;" f file: +jsonQuoteFunc testdocs/sqlite3.c /^static void jsonQuoteFunc($/;" f file: +jsonRemoveAllNulls testdocs/sqlite3.c /^static void jsonRemoveAllNulls(JsonNode *pNode){$/;" f file: +jsonRemoveFunc testdocs/sqlite3.c /^static void jsonRemoveFunc($/;" f file: +jsonRenderNode testdocs/sqlite3.c /^static void jsonRenderNode($/;" f file: +jsonReplaceFunc testdocs/sqlite3.c /^static void jsonReplaceFunc($/;" f file: +jsonReset testdocs/sqlite3.c /^static void jsonReset(JsonString *p){$/;" f file: +jsonResult testdocs/sqlite3.c /^static void jsonResult(JsonString *p){$/;" f file: +jsonReturn testdocs/sqlite3.c /^static void jsonReturn($/;" f file: +jsonReturnJson testdocs/sqlite3.c /^static void jsonReturnJson($/;" f file: +jsonSetFunc testdocs/sqlite3.c /^static void jsonSetFunc($/;" f file: +jsonTest1Func testdocs/sqlite3.c /^static void jsonTest1Func($/;" f file: +jsonTreeModule testdocs/sqlite3.c /^static sqlite3_module jsonTreeModule = {$/;" v file: +jsonType testdocs/sqlite3.c /^static const char * const jsonType[] = {$/;" v file: +jsonTypeFunc testdocs/sqlite3.c /^static void jsonTypeFunc($/;" f file: +jsonValidFunc testdocs/sqlite3.c /^static void jsonValidFunc($/;" f file: +jsonWrongNumArgs testdocs/sqlite3.c /^static void jsonWrongNumArgs($/;" f file: +jsonZero testdocs/sqlite3.c /^static void jsonZero(JsonString *p){$/;" f file: +juliandayFunc testdocs/sqlite3.c /^static void juliandayFunc($/;" f file: +k testdocs/sqlite3.c /^ int k; \/* Resume scanning at this->pWC->a[this->k] *\/$/;" m struct:WhereScan file: +key testdocs/sqlite3.c /^ Blob key; \/* Last key written to the current block *\/$/;" m struct:NodeWriter file: +keyClass testdocs/sqlite3.c /^ char keyClass; \/* HASH_INT, _POINTER, _STRING, _BINARY *\/$/;" m struct:Fts3Hash file: +keyConf testdocs/sqlite3.c /^ u8 keyConf; \/* What to do in case of uniqueness conflict on iPKey *\/$/;" m struct:Table file: +keyInfoFromExprList testdocs/sqlite3.c /^static KeyInfo *keyInfoFromExprList($/;" f file: +keyinfo testdocs/sqlite3.c /^ KeyInfo keyinfo;$/;" m struct:PreUpdate file: +keywordCode testdocs/sqlite3.c /^static int keywordCode(const char *z, int n, int *pType){$/;" f file: +labelBkOut testdocs/sqlite3.c /^ int labelBkOut; \/* Start label for the block-output subroutine *\/$/;" m struct:SortCtx file: +labelDone testdocs/sqlite3.c /^ int labelDone; \/* Jump here when done, ex: LIMIT reached *\/$/;" m struct:SortCtx file: +langidFromSelect testdocs/sqlite3.c /^static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){$/;" f file: +lastErrno testdocs/sqlite3.c /^ DWORD lastErrno; \/* The Windows errno from the last I\/O error *\/$/;" m struct:winShmNode file: +lastErrno testdocs/sqlite3.c /^ DWORD lastErrno; \/* The Windows errno from the last I\/O error *\/$/;" m struct:winFile file: +lastErrno testdocs/sqlite3.c /^ int lastErrno; \/* The unix errno from last I\/O error *\/$/;" m struct:unixFile file: +lastRowid testdocs/sqlite3.c /^ i64 lastRowid; \/* ROWID of most recent insert (see above) *\/$/;" m struct:sqlite3 file: +lastRowid testdocs/sqlite3.c /^ i64 lastRowid; \/* Last insert rowid (sqlite3.lastRowid) *\/$/;" m struct:VdbeFrame file: +last_insert_rowid testdocs/sqlite3.c /^ sqlite_int64 (*last_insert_rowid)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +last_insert_rowid testdocs/sqlite3.c /^static void last_insert_rowid($/;" f file: +leaf testdocs/sqlite3.c /^ u8 leaf; \/* True if a leaf page *\/$/;" m struct:MemPage file: +leaveMutex testdocs/sqlite3.c /^static void leaveMutex(void){$/;" f file: +leftColumn testdocs/sqlite3.c /^ int leftColumn; \/* Column number of X in "X " *\/$/;" m union:WhereTerm::__anon32 file: +leftCursor testdocs/sqlite3.c /^ int leftCursor; \/* Cursor number of X in "X " *\/$/;" m struct:WhereTerm file: +len edit.h /^ size_t len; \/* number of runes deleted *\/$/;" m struct:Log::__anon2::__anon4 +len edit.h /^ size_t len; \/* length of the buffer *\/$/;" m struct:__anon1 +length testdocs/sqlite3.c /^ unsigned long long length; \/* nbr of bytes to lock *\/$/;" m struct:ByteRangeLockPB2 file: +lengthFunc testdocs/sqlite3.c /^static void lengthFunc($/;" f file: +lhs testdocs/sqlite3.c /^ YYCODETYPE lhs; \/* Symbol on the left-hand side of the rule *\/$/;" m struct:__anon35 file: +lhs testdocs/sqlite3.c /^ fts5YYCODETYPE lhs; \/* Symbol on the left-hand side of the rule *\/$/;" m struct:__anon39 file: +libversion testdocs/sqlite3.c /^ const char * (*libversion)(void);$/;" m struct:sqlite3_api_routines file: +libversion_number testdocs/sqlite3.c /^ int (*libversion_number)(void);$/;" m struct:sqlite3_api_routines file: +likeFunc testdocs/sqlite3.c /^static void likeFunc($/;" f file: +likeInfoAlt testdocs/sqlite3.c /^static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };$/;" v typeref:struct:compareInfo file: +likeInfoNorm testdocs/sqlite3.c /^static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };$/;" v typeref:struct:compareInfo file: +likely testdocs/sqlite3.c /^#define likely(/;" d file: +limit testdocs/sqlite3.c /^ int (*limit)(sqlite3*,int,int);$/;" m struct:sqlite3_api_routines file: +list testdocs/sqlite3.c /^ } list;$/;" m union:Mem3Block::__anon21 typeref:struct:Mem3Block::__anon21::__anon23 file: +list testdocs/sqlite3.c /^ SorterList list; \/* List for thread to write to a PMA *\/$/;" m struct:SortSubtask file: +list testdocs/sqlite3.c /^ SorterList list; \/* List of in-memory records *\/$/;" m struct:VdbeSorter file: +loadAnalysis testdocs/sqlite3.c /^static void loadAnalysis(Parse *pParse, int iDb){$/;" f file: +loadExt testdocs/sqlite3.c /^static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){$/;" f file: +loadStat4 testdocs/sqlite3.c /^static int loadStat4(sqlite3 *db, const char *zDb){$/;" f file: +loadStatTbl testdocs/sqlite3.c /^static int loadStatTbl($/;" f file: +load_extension testdocs/sqlite3.c /^ int (*load_extension)(sqlite3*,const char*,const char*,char**);$/;" m struct:sqlite3_api_routines file: +local testdocs/sqlite3.c /^ winceLock local; \/* Locks obtained by this instance of winFile *\/$/;" m struct:winFile file: +local_ioerr testdocs/sqlite3.c /^static void local_ioerr(){$/;" f file: +localtime testdocs/sqlite3.c /^struct tm *__cdecl localtime(const time_t *t)$/;" f +localtimeOffset testdocs/sqlite3.c /^static sqlite3_int64 localtimeOffset($/;" f file: +lock testdocs/sqlite3.c /^ BtLock lock; \/* Object used to lock page 1 *\/$/;" m struct:Btree file: +lockBtree testdocs/sqlite3.c /^static int lockBtree(BtShared *pBt){$/;" f file: +lockBtreeMutex testdocs/sqlite3.c /^static void lockBtreeMutex(Btree *p){$/;" f file: +lockError testdocs/sqlite3.c /^ u8 lockError; \/* True if a locking error has occurred *\/$/;" m struct:Wal file: +lockMask testdocs/sqlite3.c /^ yDbMask lockMask; \/* Subset of btreeMask that requires a lock *\/$/;" m struct:Vdbe file: +lockProxy testdocs/sqlite3.c /^ unixFile *lockProxy; \/* Open proxy lock file *\/$/;" m struct:proxyLockingContext file: +lockProxyPath testdocs/sqlite3.c /^ char *lockProxyPath; \/* Name of the proxy lock file *\/$/;" m struct:proxyLockingContext file: +lockTrace testdocs/sqlite3.c /^static int lockTrace(int fd, int op, struct flock *p){$/;" f file: +locked testdocs/sqlite3.c /^ u8 locked; \/* True if db currently has pBt locked *\/$/;" m struct:Btree file: +lockingContext testdocs/sqlite3.c /^ void *lockingContext; \/* Locking style specific state *\/$/;" m struct:unixFile file: +locktype testdocs/sqlite3.c /^ u8 locktype; \/* Type of lock currently held on this file *\/$/;" m struct:winFile file: +log testdocs/sqlite3.c /^ void (*log)(int,const char*,...);$/;" m struct:sqlite3_api_routines file: +logBadConnection testdocs/sqlite3.c /^static void logBadConnection(const char *zType){$/;" f file: +log_clear buf.c /^static void log_clear(Log** list) {$/;" f file: +log_delete buf.c /^static void log_delete(Buf* buf, Log** list, size_t off, Rune* r, size_t len) {$/;" f file: +log_insert buf.c /^static void log_insert(Buf* buf, Log** list, size_t beg, size_t end) {$/;" f file: +lookaside testdocs/sqlite3.c /^ Lookaside lookaside; \/* Lookaside malloc configuration *\/$/;" m struct:sqlite3 file: +lookupName testdocs/sqlite3.c /^static int lookupName($/;" f file: +lowerFunc testdocs/sqlite3.c /^static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){$/;" f file: +lru testdocs/sqlite3.c /^ int lru; \/* Least recently used entry has the smallest value *\/$/;" m struct:Parse::yColCache file: +lru testdocs/sqlite3.c /^ PgHdr1 lru; \/* The beginning and end of the LRU list *\/$/;" m struct:PGroup file: +lseek testdocs/sqlite3.c /^# define lseek /;" d file: +m testdocs/sqlite3.c /^ int h, m; \/* Hour and minutes *\/$/;" m struct:DateTime file: +m testdocs/sqlite3.c /^ sqlite3_mem_methods m; \/* Low-level memory allocation interface *\/$/;" m struct:Sqlite3Config file: +mLock testdocs/sqlite3.c /^ u32 mLock;$/;" m struct:sqlite3rbu file: +mPragFlg testdocs/sqlite3.c /^ u8 mPragFlg; \/* Zero or more PragFlg_XXX values *\/$/;" m struct:PragmaName file: +mTrace testdocs/sqlite3.c /^ u8 mTrace; \/* zero or more SQLITE_TRACE flags *\/$/;" m struct:sqlite3 file: +m_eq_1 testdocs/sqlite3.c /^static int m_eq_1(const char *z){$/;" f file: +m_gt_0 testdocs/sqlite3.c /^static int m_gt_0(const char *z){$/;" f file: +m_gt_1 testdocs/sqlite3.c /^static int m_gt_1(const char *z){$/;" f file: +magic testdocs/sqlite3.c /^ u32 magic; \/* Magic number for detect library misuse *\/$/;" m struct:sqlite3 file: +magic testdocs/sqlite3.c /^ u32 magic; \/* Always RTREE_GEOMETRY_MAGIC *\/$/;" m struct:RtreeMatchArg file: +magic testdocs/sqlite3.c /^ u32 magic; \/* Magic number for sanity checking *\/$/;" m struct:Vdbe file: +magic1 testdocs/sqlite3.c /^ u32 magic1; \/* Magic number to detect structure corruption. *\/$/;" m struct:winMemData file: +magic2 testdocs/sqlite3.c /^ u32 magic2; \/* Magic number to detect structure corruption. *\/$/;" m struct:winMemData file: +main testbuf.c /^int main(int argc, char** argv) {$/;" f +major testdocs/sqlite3.c /^ YYCODETYPE major; \/* The major token value. This is the code$/;" m struct:yyStackEntry file: +major testdocs/sqlite3.c /^ fts5YYCODETYPE major; \/* The major token value. This is the code$/;" m struct:fts5yyStackEntry file: +malloc testdocs/sqlite3.c /^ void *(*malloc)(int);$/;" m struct:sqlite3_api_routines file: +malloc64 testdocs/sqlite3.c /^ void *(*malloc64)(sqlite3_uint64);$/;" m struct:sqlite3_api_routines file: +mallocFailed testdocs/sqlite3.c /^ int mallocFailed; \/* A memory allocation error has occurred *\/$/;" m struct:IntegrityCk file: +mallocFailed testdocs/sqlite3.c /^ u8 mallocFailed; \/* True if we have seen a malloc failure *\/$/;" m struct:sqlite3 file: +mallocWithAlarm testdocs/sqlite3.c /^static void mallocWithAlarm(int n, void **pp){$/;" f file: +markTermAsChild testdocs/sqlite3.c /^static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){$/;" f file: +mask testdocs/sqlite3.c /^ struct {int value; int mask;} yy497;$/;" m struct:__anon33::__anon34 file: +maskLoop testdocs/sqlite3.c /^ Bitmask maskLoop; \/* Bitmask of all WhereLoop objects in this path *\/$/;" m struct:WherePath file: +maskPage testdocs/sqlite3.c /^ u16 maskPage; \/* Mask for page offset *\/$/;" m struct:MemPage file: +maskSelf testdocs/sqlite3.c /^ Bitmask maskSelf; \/* Bitmask identifying table iTab *\/$/;" m struct:WhereLoop file: +maskUsed testdocs/sqlite3.c /^ u64 maskUsed; \/* Mask of columns used by this cursor *\/$/;" m struct:VdbeCursor file: +matchAll testdocs/sqlite3.c /^ u8 matchAll; \/* "*" or "%" *\/$/;" m struct:compareInfo file: +matchOne testdocs/sqlite3.c /^ u8 matchOne; \/* "?" or "_" *\/$/;" m struct:compareInfo file: +matchQuality testdocs/sqlite3.c /^static int matchQuality($/;" f file: +matchSet testdocs/sqlite3.c /^ u8 matchSet; \/* "[" or 0 *\/$/;" m struct:compareInfo file: +max stdc.h /^ #define max(/;" d +max1bytePayload testdocs/sqlite3.c /^ u8 max1bytePayload; \/* Maximum first byte of cell for a 1-byte payload *\/$/;" m struct:BtShared file: +max1bytePayload testdocs/sqlite3.c /^ u8 max1bytePayload; \/* min(maxLocal,127) *\/$/;" m struct:MemPage file: +maxCount testdocs/sqlite3.c /^ u32 maxCount; \/* Maximum instantaneous currentCount *\/$/;" m struct:Mem5Global file: +maxLeaf testdocs/sqlite3.c /^ u16 maxLeaf; \/* Maximum local payload in a LEAFDATA table *\/$/;" m struct:BtShared file: +maxLocal testdocs/sqlite3.c /^ u16 maxLocal; \/* Maximum local payload in non-LEAFDATA tables *\/$/;" m struct:BtShared file: +maxLocal testdocs/sqlite3.c /^ u16 maxLocal; \/* Copy of BtShared.maxLocal or BtShared.maxLeaf *\/$/;" m struct:MemPage file: +maxOut testdocs/sqlite3.c /^ u32 maxOut; \/* Maximum instantaneous currentOut *\/$/;" m struct:Mem5Global file: +maxRequest testdocs/sqlite3.c /^ u32 maxRequest; \/* Largest allocation (exclusive of internal frag) *\/$/;" m struct:Mem5Global file: +mayAbort testdocs/sqlite3.c /^ u8 mayAbort; \/* True if statement may throw an ABORT exception *\/$/;" m struct:Parse file: +measureAllocationSize testdocs/sqlite3.c /^static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){$/;" f file: +mem testdocs/sqlite3.c /^} mem;$/;" v typeref:struct:__anon20 file: +mem0 testdocs/sqlite3.c /^#define mem0 /;" d file: +mem0 testdocs/sqlite3.c /^} mem0 = { 0, 0, 0, 0, 0, 0 };$/;" v typeref:struct:Mem0Global file: +mem3 testdocs/sqlite3.c /^#define mem3 /;" d file: +mem3 testdocs/sqlite3.c /^} mem3 = { 97535575 };$/;" v typeref:struct:Mem3Global file: +mem5 testdocs/sqlite3.c /^#define mem5 /;" d file: +mem5 testdocs/sqlite3.c /^} mem5;$/;" v typeref:struct:Mem5Global file: +memAboutToChange testdocs/sqlite3.c /^# define memAboutToChange(/;" d file: +memDb testdocs/sqlite3.c /^ u8 memDb; \/* True to inhibit all file I\/O *\/$/;" m struct:Pager file: +memIntValue testdocs/sqlite3.c /^static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){$/;" f file: +memIsValid testdocs/sqlite3.c /^#define memIsValid(/;" d file: +memRealValue testdocs/sqlite3.c /^static SQLITE_NOINLINE double memRealValue(Mem *pMem){$/;" f file: +memTracePrint testdocs/sqlite3.c /^static void memTracePrint(Mem *p){$/;" f file: +memcpy testdocs/sqlite3.c /^# define memcpy(/;" d file: +memjrnlClose testdocs/sqlite3.c /^static int memjrnlClose(sqlite3_file *pJfd){$/;" f file: +memjrnlCreateFile testdocs/sqlite3.c /^static int memjrnlCreateFile(MemJournal *p){$/;" f file: +memjrnlFileSize testdocs/sqlite3.c /^static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){$/;" f file: +memjrnlFreeChunks testdocs/sqlite3.c /^static void memjrnlFreeChunks(MemJournal *p){$/;" f file: +memjrnlRead testdocs/sqlite3.c /^static int memjrnlRead($/;" f file: +memjrnlSync testdocs/sqlite3.c /^static int memjrnlSync(sqlite3_file *pJfd, int flags){$/;" f file: +memjrnlTruncate testdocs/sqlite3.c /^static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){$/;" f file: +memjrnlWrite testdocs/sqlite3.c /^static int memjrnlWrite($/;" f file: +memory_highwater testdocs/sqlite3.c /^ sqlite3_int64 (*memory_highwater)(int);$/;" m struct:sqlite3_api_routines file: +memory_used testdocs/sqlite3.c /^ sqlite3_int64 (*memory_used)(void);$/;" m struct:sqlite3_api_routines file: +memsys3Checkout testdocs/sqlite3.c /^static void *memsys3Checkout(u32 i, u32 nBlock){$/;" f file: +memsys3Enter testdocs/sqlite3.c /^static void memsys3Enter(void){$/;" f file: +memsys3Free testdocs/sqlite3.c /^static void memsys3Free(void *pPrior){$/;" f file: +memsys3FreeUnsafe testdocs/sqlite3.c /^static void memsys3FreeUnsafe(void *pOld){$/;" f file: +memsys3FromMaster testdocs/sqlite3.c /^static void *memsys3FromMaster(u32 nBlock){$/;" f file: +memsys3Init testdocs/sqlite3.c /^static int memsys3Init(void *NotUsed){$/;" f file: +memsys3Leave testdocs/sqlite3.c /^static void memsys3Leave(void){$/;" f file: +memsys3Link testdocs/sqlite3.c /^static void memsys3Link(u32 i){$/;" f file: +memsys3LinkIntoList testdocs/sqlite3.c /^static void memsys3LinkIntoList(u32 i, u32 *pRoot){$/;" f file: +memsys3Malloc testdocs/sqlite3.c /^static void *memsys3Malloc(int nBytes){$/;" f file: +memsys3MallocUnsafe testdocs/sqlite3.c /^static void *memsys3MallocUnsafe(int nByte){$/;" f file: +memsys3Merge testdocs/sqlite3.c /^static void memsys3Merge(u32 *pRoot){$/;" f file: +memsys3OutOfMemory testdocs/sqlite3.c /^static void memsys3OutOfMemory(int nByte){$/;" f file: +memsys3Realloc testdocs/sqlite3.c /^static void *memsys3Realloc(void *pPrior, int nBytes){$/;" f file: +memsys3Roundup testdocs/sqlite3.c /^static int memsys3Roundup(int n){$/;" f file: +memsys3Shutdown testdocs/sqlite3.c /^static void memsys3Shutdown(void *NotUsed){$/;" f file: +memsys3Size testdocs/sqlite3.c /^static int memsys3Size(void *p){$/;" f file: +memsys3Unlink testdocs/sqlite3.c /^static void memsys3Unlink(u32 i){$/;" f file: +memsys3UnlinkFromList testdocs/sqlite3.c /^static void memsys3UnlinkFromList(u32 i, u32 *pRoot){$/;" f file: +memsys5Enter testdocs/sqlite3.c /^static void memsys5Enter(void){$/;" f file: +memsys5Free testdocs/sqlite3.c /^static void memsys5Free(void *pPrior){$/;" f file: +memsys5FreeUnsafe testdocs/sqlite3.c /^static void memsys5FreeUnsafe(void *pOld){$/;" f file: +memsys5Init testdocs/sqlite3.c /^static int memsys5Init(void *NotUsed){$/;" f file: +memsys5Leave testdocs/sqlite3.c /^static void memsys5Leave(void){$/;" f file: +memsys5Link testdocs/sqlite3.c /^static void memsys5Link(int i, int iLogsize){$/;" f file: +memsys5Log testdocs/sqlite3.c /^static int memsys5Log(int iValue){$/;" f file: +memsys5Malloc testdocs/sqlite3.c /^static void *memsys5Malloc(int nBytes){$/;" f file: +memsys5MallocUnsafe testdocs/sqlite3.c /^static void *memsys5MallocUnsafe(int nByte){$/;" f file: +memsys5Realloc testdocs/sqlite3.c /^static void *memsys5Realloc(void *pPrior, int nBytes){$/;" f file: +memsys5Roundup testdocs/sqlite3.c /^static int memsys5Roundup(int n){$/;" f file: +memsys5Shutdown testdocs/sqlite3.c /^static void memsys5Shutdown(void *NotUsed){$/;" f file: +memsys5Size testdocs/sqlite3.c /^static int memsys5Size(void *p){$/;" f file: +memsys5Unlink testdocs/sqlite3.c /^static void memsys5Unlink(int i, int iLogsize){$/;" f file: +min stdc.h /^ #define min(/;" d +minFrame testdocs/sqlite3.c /^ u32 minFrame; \/* Ignore wal frames before this one *\/$/;" m struct:Wal file: +minLeaf testdocs/sqlite3.c /^ u16 minLeaf; \/* Minimum local payload in a LEAFDATA table *\/$/;" m struct:BtShared file: +minLocal testdocs/sqlite3.c /^ u16 minLocal; \/* Minimum local payload in non-LEAFDATA tables *\/$/;" m struct:BtShared file: +minLocal testdocs/sqlite3.c /^ u16 minLocal; \/* Copy of BtShared.minLocal or BtShared.minLeaf *\/$/;" m struct:MemPage file: +minMaxFinalize testdocs/sqlite3.c /^static void minMaxFinalize(sqlite3_context *context){$/;" f file: +minMaxQuery testdocs/sqlite3.c /^static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){$/;" f file: +minWriteFileFormat testdocs/sqlite3.c /^ u8 minWriteFileFormat; \/* Minimum file format for writable database files *\/$/;" m struct:Vdbe file: +minmaxFunc testdocs/sqlite3.c /^static void minmaxFunc($/;" f file: +minmaxStep testdocs/sqlite3.c /^static void minmaxStep($/;" f file: +minor testdocs/sqlite3.c /^ YYMINORTYPE minor; \/* The user-supplied minor token value. This$/;" m struct:yyStackEntry file: +minor testdocs/sqlite3.c /^ fts5YYMINORTYPE minor; \/* The user-supplied minor token value. This$/;" m struct:fts5yyStackEntry file: +mkFullPathname testdocs/sqlite3.c /^static int mkFullPathname($/;" f file: +mmapSize testdocs/sqlite3.c /^ sqlite3_int64 mmapSize; \/* Usable size of mapping at pMapRegion *\/$/;" m struct:unixFile file: +mmapSize testdocs/sqlite3.c /^ sqlite3_int64 mmapSize; \/* Usable size of mapped region *\/$/;" m struct:winFile file: +mmapSizeActual testdocs/sqlite3.c /^ sqlite3_int64 mmapSizeActual; \/* Actual size of mapping at pMapRegion *\/$/;" m struct:unixFile file: +mmapSizeActual testdocs/sqlite3.c /^ sqlite3_int64 mmapSizeActual; \/* Actual size of mapped region *\/$/;" m struct:winFile file: +mmapSizeMax testdocs/sqlite3.c /^ sqlite3_int64 mmapSizeMax; \/* Configured FCNTL_MMAP_SIZE value *\/$/;" m struct:unixFile file: +mmapSizeMax testdocs/sqlite3.c /^ sqlite3_int64 mmapSizeMax; \/* Configured FCNTL_MMAP_SIZE value *\/$/;" m struct:winFile file: +mmap_close buf.c /^void mmap_close(FMap file) {$/;" f +mmap_readonly buf.c /^FMap mmap_readonly(char* path) {$/;" f +mmap_readwrite buf.c /^FMap mmap_readwrite(char* path, size_t sz) {$/;" f +mnMaster testdocs/sqlite3.c /^ u32 mnMaster;$/;" m struct:Mem3Global file: +mnPmaSize testdocs/sqlite3.c /^ int mnPmaSize; \/* Minimum PMA size, in bytes *\/$/;" m struct:VdbeSorter file: +mnReg testdocs/sqlite3.c /^ int mnReg, mxReg; \/* Range of registers allocated for aCol and aFunc *\/$/;" m struct:AggInfo file: +mnReq testdocs/sqlite3.c /^ int mnReq, mxReq; \/* Min and max heap requests sizes *\/$/;" m struct:Sqlite3Config file: +modified edit.h /^ bool modified; \/* tracks whether the buffer has been modified *\/$/;" m struct:__anon5 +modifyPagePointer testdocs/sqlite3.c /^static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){$/;" f file: +modtime buf.c /^uint64_t modtime(char* path) {$/;" f +modtime edit.h /^ uint64_t modtime; \/* modification time of the opened file *\/$/;" m struct:__anon5 +moveToChild testdocs/sqlite3.c /^static int moveToChild(BtCursor *pCur, u32 newPgno){$/;" f file: +moveToLeftmost testdocs/sqlite3.c /^static int moveToLeftmost(BtCursor *pCur){$/;" f file: +moveToParent testdocs/sqlite3.c /^static void moveToParent(BtCursor *pCur){$/;" f file: +moveToRightmost testdocs/sqlite3.c /^static int moveToRightmost(BtCursor *pCur){$/;" f file: +moveToRoot testdocs/sqlite3.c /^static int moveToRoot(BtCursor *pCur){$/;" f file: +movetoTarget testdocs/sqlite3.c /^ i64 movetoTarget; \/* Argument to the deferred sqlite3BtreeMoveto() *\/$/;" m struct:VdbeCursor file: +mprintf testdocs/sqlite3.c /^ char * (*mprintf)(const char*,...);$/;" m struct:sqlite3_api_routines file: +msize testdocs/sqlite3.c /^ sqlite3_uint64 (*msize)(void*);$/;" m struct:sqlite3_api_routines file: +multiSelect testdocs/sqlite3.c /^static int multiSelect($/;" f file: +multiSelectCollSeq testdocs/sqlite3.c /^static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){$/;" f file: +multiSelectOrderBy testdocs/sqlite3.c /^static int multiSelectOrderBy($/;" f file: +multiSelectOrderByKeyInfo testdocs/sqlite3.c /^static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){$/;" f file: +multiSelectValues testdocs/sqlite3.c /^static int multiSelectValues($/;" f file: +mutex testdocs/sqlite3.c /^ CRITICAL_SECTION mutex; \/* Mutex controlling the lock *\/$/;" m struct:sqlite3_mutex file: +mutex testdocs/sqlite3.c /^ pthread_mutex_t mutex; \/* Mutex controlling the lock *\/$/;" m struct:sqlite3_mutex file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* Mutex to protect pMain *\/$/;" m struct:rbu_vfs file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* MUTEX_STATIC_LRU or NULL *\/$/;" m struct:PGroup file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* Mutex for accessing the following: *\/$/;" m struct:PCacheGlobal file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* Connection mutex *\/$/;" m struct:sqlite3 file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* Mutex to serialize access *\/$/;" m struct:Mem0Global file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* Mutex to access this object *\/$/;" m struct:unixShmNode file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* Mutex to access this object *\/$/;" m struct:winShmNode file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex; \/* Non-recursive mutex required to access this object *\/$/;" m struct:BtShared file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex;$/;" m struct:Mem3Global file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex;$/;" m struct:Mem5Global file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex *mutex;$/;" m struct:__anon20 file: +mutex testdocs/sqlite3.c /^ sqlite3_mutex_methods mutex; \/* Low-level mutex interface *\/$/;" m struct:Sqlite3Config file: +mutexIsInit testdocs/sqlite3.c /^static SQLITE_WSD int mutexIsInit = 0;$/;" v file: +mutex_alloc testdocs/sqlite3.c /^ sqlite3_mutex *(*mutex_alloc)(int);$/;" m struct:sqlite3_api_routines file: +mutex_enter testdocs/sqlite3.c /^ void (*mutex_enter)(sqlite3_mutex*);$/;" m struct:sqlite3_api_routines file: +mutex_free testdocs/sqlite3.c /^ void (*mutex_free)(sqlite3_mutex*);$/;" m struct:sqlite3_api_routines file: +mutex_leave testdocs/sqlite3.c /^ void (*mutex_leave)(sqlite3_mutex*);$/;" m struct:sqlite3_api_routines file: +mutex_try testdocs/sqlite3.c /^ int (*mutex_try)(sqlite3_mutex*);$/;" m struct:sqlite3_api_routines file: +mxAlloc testdocs/sqlite3.c /^ u32 mxAlloc; \/* Maximum allowed allocation. 0 for no malloc usage *\/$/;" m struct:StrAccum file: +mxCurrent testdocs/sqlite3.c /^ int mxCurrent[NCSIZE]; \/* Highwater mark for nCurrent *\/$/;" m struct:__anon20 file: +mxErr testdocs/sqlite3.c /^ int mxErr; \/* Stop accumulating errors when this reaches zero *\/$/;" m struct:IntegrityCk file: +mxFrame testdocs/sqlite3.c /^ u32 mxFrame; \/* Index of last valid frame in the WAL *\/$/;" m struct:WalIndexHdr file: +mxKeysize testdocs/sqlite3.c /^ int mxKeysize; \/* Largest serialized key seen so far *\/$/;" m struct:VdbeSorter file: +mxLevel testdocs/sqlite3.c /^ int mxLevel; \/* The largest iLevel value in the tree *\/$/;" m struct:sqlite3_rtree_query_info file: +mxLevel testdocs/sqlite3.c /^ int mxLevel; \/* iLevel value for root of the tree *\/$/;" m struct:RtreeCursor file: +mxMmap testdocs/sqlite3.c /^ sqlite3_int64 mxMmap; \/* Maximum value for szMmap *\/$/;" m struct:Sqlite3Config file: +mxOut testdocs/sqlite3.c /^ int mxOut; \/* Highwater mark for nOut *\/$/;" m struct:Lookaside file: +mxParserStack testdocs/sqlite3.c /^ int mxParserStack; \/* maximum depth of the parser stack *\/$/;" m struct:Sqlite3Config file: +mxPathname testdocs/sqlite3.c /^ int mxPathname; \/* Maximum file pathname length *\/$/;" m struct:sqlite3_vfs file: +mxPgno testdocs/sqlite3.c /^ Pgno mxPgno; \/* Maximum allowed size of the database *\/$/;" m struct:Pager file: +mxPinned testdocs/sqlite3.c /^ unsigned int mxPinned; \/* nMaxpage + 10 - nMinPage *\/$/;" m struct:PGroup file: +mxPmaSize testdocs/sqlite3.c /^ int mxPmaSize; \/* Maximum PMA size, in bytes. 0==no limit *\/$/;" m struct:VdbeSorter file: +mxReg testdocs/sqlite3.c /^ int mnReg, mxReg; \/* Range of registers allocated for aCol and aFunc *\/$/;" m struct:AggInfo file: +mxReq testdocs/sqlite3.c /^ int mnReq, mxReq; \/* Min and max heap requests sizes *\/$/;" m struct:Sqlite3Config file: +mxSample testdocs/sqlite3.c /^ int mxSample; \/* Maximum number of samples to accumulate *\/$/;" m struct:Stat4Accum file: +mxSavepoint testdocs/sqlite3.c /^ int mxSavepoint; \/* Largest valid xSavepoint integer *\/$/;" m struct:Fts3Table file: +mxStrlen testdocs/sqlite3.c /^ int mxStrlen; \/* Maximum string length *\/$/;" m struct:Sqlite3Config file: +mxSz testdocs/sqlite3.c /^ int mxSz; \/* Maximum bytes of data to store *\/$/;" m struct:IncrMerger file: +mxValue testdocs/sqlite3.c /^ sqlite3StatValueType mxValue[10]; \/* Maximum value *\/$/;" m struct:sqlite3StatType file: +mxWalSize testdocs/sqlite3.c /^ i64 mxWalSize; \/* Truncate WAL to this size upon reset *\/$/;" m struct:Wal file: +n testdocs/sqlite3.c /^ int n; \/* A counter *\/$/;" m union:Walker::__anon17 file: +n testdocs/sqlite3.c /^ i64 n;$/;" m struct:CountCtx file: +n testdocs/sqlite3.c /^ int n; \/* Length of z in bytes (excl. nul-term) *\/$/;" m struct:StrBuffer file: +n testdocs/sqlite3.c /^ int n; \/* Number of bytes in buffer z *\/$/;" m struct:Fts3PhraseToken file: +n testdocs/sqlite3.c /^ int n; \/* Number of valid bytes of data in a[] *\/$/;" m struct:Blob file: +n testdocs/sqlite3.c /^ int n; \/* Size of buffer a[] in bytes *\/$/;" m struct:Fts5LookaheadReader file: +n testdocs/sqlite3.c /^ int n; \/* Size of buffer at a[] in bytes *\/$/;" m struct:Fts5PoslistReader file: +n testdocs/sqlite3.c /^ int n; \/* Size of buffer p in bytes *\/$/;" m struct:Fts5Token file: +n testdocs/sqlite3.c /^ int n; \/* Number of assigned cursor values *\/$/;" m struct:WhereMaskSet file: +n testdocs/sqlite3.c /^ int n; \/* Number of characters in string value, excluding '\\0' *\/$/;" m struct:sqlite3_value file: +n testdocs/sqlite3.c /^ int n; \/* Size of record in bytes *\/$/;" m struct:IndexSample file: +n testdocs/sqlite3.c /^ int n;$/;" m struct:Fts5Buffer file: +n testdocs/sqlite3.c /^ u16 n; \/* Number of valid a[] entries *\/$/;" m struct:WhereOrSet file: +n testdocs/sqlite3.c /^ u32 n; \/* Bytes of content, or number of sub-nodes *\/$/;" m struct:JsonNode file: +n testdocs/sqlite3.c /^ unsigned int n; \/* Number of characters in this token *\/$/;" m struct:Token file: +n90pct testdocs/sqlite3.c /^ unsigned int n90pct; \/* nMax*9\/10 *\/$/;" m struct:PCache1 file: +nAccumulator testdocs/sqlite3.c /^ int nAccumulator; \/* Number of columns that show through to the output.$/;" m struct:AggInfo file: +nAdvance testdocs/sqlite3.c /^ int nAdvance; \/* How many seg-readers to advance *\/$/;" m struct:Fts3MultiSegReader file: +nAll testdocs/sqlite3.c /^ int nAll; \/* Size of a[] in bytes *\/$/;" m struct:Fts3Doclist file: +nAlloc testdocs/sqlite3.c /^ int nAlloc; \/* Allocated size of a[] (nAlloc>=n) *\/$/;" m struct:Blob file: +nAlloc testdocs/sqlite3.c /^ int nAlloc; \/* Allocated size of buffer z in bytes *\/$/;" m struct:StrBuffer file: +nAlloc testdocs/sqlite3.c /^ int nAlloc; \/* Size of allocation containing aBuf *\/$/;" m struct:SessionBuffer file: +nAlloc testdocs/sqlite3.c /^ int nAlloc; \/* Total size of allocation *\/$/;" m struct:Fts5HashEntry file: +nAlloc testdocs/sqlite3.c /^ int nAlloc; \/* space allocated at zToken *\/$/;" m struct:unicode_cursor file: +nAlloc testdocs/sqlite3.c /^ int nAlloc; \/* Bytes of space at aAlloc *\/$/;" m struct:PmaReader file: +nAlloc testdocs/sqlite3.c /^ int nAlloc; \/* Number of a[] slots allocated *\/$/;" m struct:ExprList file: +nAlloc testdocs/sqlite3.c /^ int nAlloc[NCSIZE]; \/* Total number of allocations *\/$/;" m struct:__anon20 file: +nAlloc testdocs/sqlite3.c /^ u32 nAlloc; \/* Amount of space allocated in zText *\/$/;" m struct:StrAccum file: +nAlloc testdocs/sqlite3.c /^ u32 nAlloc; \/* Number of slots of aNode[] allocated *\/$/;" m struct:JsonParse file: +nAlloc testdocs/sqlite3.c /^ u32 nAlloc; \/* Slots allocated for azResult[] *\/$/;" m struct:TabResult file: +nAlloc testdocs/sqlite3.c /^ u32 nAlloc; \/* Number of entries allocated in a[] below *\/$/;" m struct:SrcList file: +nAlloc testdocs/sqlite3.c /^ u64 nAlloc; \/* Bytes of storage available in zBuf[] *\/$/;" m struct:JsonString file: +nAlloc testdocs/sqlite3.c /^ u64 nAlloc; \/* Total number of calls to malloc *\/$/;" m struct:Mem5Global file: +nAllocated testdocs/sqlite3.c /^ int nAllocated; \/* space allocated to zToken buffer *\/$/;" m struct:porter_tokenizer_cursor file: +nArg testdocs/sqlite3.c /^ i8 nArg; \/* Number of arguments. -1 means unlimited *\/$/;" m struct:FuncDef file: +nArg testdocs/sqlite3.c /^ int nArg; \/* Total number of arguments *\/$/;" m struct:PrintfArguments file: +nAuthPW testdocs/sqlite3.c /^ int nAuthPW; \/* Size of the zAuthPW in bytes *\/$/;" m struct:sqlite3_userauth file: +nAutoincrmerge testdocs/sqlite3.c /^ int nAutoincrmerge; \/* Value configured by 'automerge' *\/$/;" m struct:Fts3Table file: +nAutomerge testdocs/sqlite3.c /^ int nAutomerge; \/* 'automerge' setting *\/$/;" m struct:Fts5Config file: +nBackfill testdocs/sqlite3.c /^ u32 nBackfill; \/* Number of WAL frames backfilled into DB *\/$/;" m struct:WalCkptInfo file: +nBackfillAttempted testdocs/sqlite3.c /^ u32 nBackfillAttempted; \/* WAL frames perhaps written, or maybe not *\/$/;" m struct:WalCkptInfo file: +nBacktrace testdocs/sqlite3.c /^ char nBacktrace; \/* Number of backtraces on this alloc *\/$/;" m struct:MemBlockHdr file: +nBacktrace testdocs/sqlite3.c /^ int nBacktrace;$/;" m struct:__anon20 file: +nBacktraceSlots testdocs/sqlite3.c /^ char nBacktraceSlots; \/* Available backtrace slots *\/$/;" m struct:MemBlockHdr file: +nBackup testdocs/sqlite3.c /^ int nBackup; \/* Number of backup operations reading this btree *\/$/;" m struct:Btree file: +nBlock testdocs/sqlite3.c /^ int nBlock; \/* Number of szAtom sized blocks in zPool *\/$/;" m struct:Mem5Global file: +nBtm testdocs/sqlite3.c /^ u16 nBtm; \/* Size of BTM vector *\/$/;" m struct:WhereLoop::__anon29::__anon30 file: +nBuf testdocs/sqlite3.c /^ int nBuf; \/* Size of buffer aBuf *\/$/;" m struct:SessionBuffer file: +nBuffer testdocs/sqlite3.c /^ int nBuffer; \/* Allocated size of aBuffer[] in bytes *\/$/;" m struct:Fts3MultiSegReader file: +nBuffer testdocs/sqlite3.c /^ int nBuffer; \/* Size of write buffer in bytes *\/$/;" m struct:PmaWriter file: +nBuffer testdocs/sqlite3.c /^ int nBuffer; \/* Size of read buffer in bytes *\/$/;" m struct:PmaReader file: +nBuffer testdocs/sqlite3.c /^ int nBuffer;$/;" m struct:IcuCursor file: +nBusy testdocs/sqlite3.c /^ int nBusy; \/* Incremented with each busy call *\/$/;" m struct:BusyHandler file: +nBusy testdocs/sqlite3.c /^ u32 nBusy; \/* Current number of users of this structure *\/$/;" m struct:Rtree file: +nByte testdocs/sqlite3.c /^ int nByte; \/* Size of open blob, in bytes *\/$/;" m struct:Incrblob file: +nBytes testdocs/sqlite3.c /^ int nBytes; \/* size of the input *\/$/;" m struct:simple_tokenizer_cursor file: +nBytesPerCell testdocs/sqlite3.c /^ u8 nBytesPerCell; \/* Bytes consumed per cell *\/$/;" m struct:Rtree file: +nCell testdocs/sqlite3.c /^ int nCell; \/* Number of cells on page *\/$/;" m struct:StatPage file: +nCell testdocs/sqlite3.c /^ int nCell; \/* Value of 'ncell' column *\/$/;" m struct:StatCursor file: +nCell testdocs/sqlite3.c /^ int nCell; \/* Number of cells in apCell[] *\/$/;" m struct:CellArray file: +nCell testdocs/sqlite3.c /^ u16 nCell; \/* Number of cells on this page, local and ovfl *\/$/;" m struct:MemPage file: +nChange testdocs/sqlite3.c /^ int nChange; \/* Size of apChange[] array *\/$/;" m struct:SessionTable file: +nChange testdocs/sqlite3.c /^ int nChange; \/* Value returned by sqlite3_changes() *\/$/;" m struct:sqlite3 file: +nChange testdocs/sqlite3.c /^ int nChange; \/* Number of db changes made since last reset *\/$/;" m struct:Vdbe file: +nChange testdocs/sqlite3.c /^ int nChange; \/* Statement changes (Vdbe.nChange) *\/$/;" m struct:VdbeFrame file: +nChar testdocs/sqlite3.c /^ int nChar; \/* Number of UChar elements in pInput *\/$/;" m struct:IcuCursor file: +nChar testdocs/sqlite3.c /^ u32 nChar; \/* Length of the string so far *\/$/;" m struct:StrAccum file: +nChild testdocs/sqlite3.c /^ int nChild; \/* Number of child nodes *\/$/;" m struct:Fts5ExprNode file: +nChild testdocs/sqlite3.c /^ u8 nChild; \/* Number of children that must disable us *\/$/;" m struct:WhereTerm file: +nChildCsr testdocs/sqlite3.c /^ int nChildCsr; \/* Number of cursors for child frame *\/$/;" m struct:VdbeFrame file: +nChildMem testdocs/sqlite3.c /^ int nChildMem; \/* Number of memory cells for child frame *\/$/;" m struct:VdbeFrame file: +nChunkSize testdocs/sqlite3.c /^ int nChunkSize; \/* In-memory chunk-size *\/$/;" m struct:MemJournal file: +nCkpt testdocs/sqlite3.c /^ u32 nCkpt; \/* Checkpoint sequence counter in the wal-header *\/$/;" m struct:Wal file: +nCol testdocs/sqlite3.c /^ i16 nCol; \/* Number of columns in this table *\/$/;" m struct:Table file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of entries in azCol[] *\/$/;" m struct:ParseContext file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of columns *\/$/;" m struct:Fts5Config file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of columns in current object *\/$/;" m struct:RbuObjIter file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of columns in table *\/$/;" m struct:MatchInfo file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of columns in table zName *\/$/;" m struct:SessionTable file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of columns in zTab *\/$/;" m struct:sqlite3_changeset_iter file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Size of azCol[] and abPK[] arrays *\/$/;" m struct:SessionApplyCtx file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of columns in index + pk\/rowid *\/$/;" m struct:Stat4Accum file: +nCol testdocs/sqlite3.c /^ int nCol; \/* Number of columns in this key *\/$/;" m struct:FKey file: +nCol testdocs/sqlite3.c /^ int nCol;$/;" m struct:Fts5Colset file: +nColCache testdocs/sqlite3.c /^ u8 nColCache; \/* Number of entries in aColCache[] *\/$/;" m struct:Parse file: +nColumn testdocs/sqlite3.c /^ int nColumn; \/* number of named columns in virtual table *\/$/;" m struct:Fts3Table file: +nColumn testdocs/sqlite3.c /^ int nColumn; \/* Number of used entries in aCol[] *\/$/;" m struct:AggInfo file: +nColumn testdocs/sqlite3.c /^ u16 nColumn; \/* Number of columns stored in the index *\/$/;" m struct:Index file: +nColumn testdocs/sqlite3.c /^ u32 nColumn; \/* Number of columns in the result *\/$/;" m struct:TabResult file: +nConstraint testdocs/sqlite3.c /^ int nConstraint; \/* Number of entries in aConstraint *\/$/;" m struct:RtreeCursor file: +nConstraint testdocs/sqlite3.c /^ int nConstraint; \/* Number of entries in aConstraint *\/$/;" m struct:sqlite3_index_info file: +nCoord testdocs/sqlite3.c /^ int nCoord; \/* Number of coordinates *\/$/;" m struct:sqlite3_rtree_query_info file: +nCost testdocs/sqlite3.c /^ int nCost; \/* Cost of running iterator *\/$/;" m struct:Fts3MultiSegReader file: +nCrisisMerge testdocs/sqlite3.c /^ int nCrisisMerge; \/* Maximum allowed segments per level *\/$/;" m struct:Fts5Config file: +nCsr testdocs/sqlite3.c /^ int nCsr; \/* Number of cursors required *\/$/;" m struct:SubProgram file: +nCte testdocs/sqlite3.c /^ int nCte; \/* Number of CTEs in the WITH clause *\/$/;" m struct:With file: +nCurrent testdocs/sqlite3.c /^ int nCurrent[NCSIZE]; \/* Current number of allocations *\/$/;" m struct:__anon20 file: +nCurrentPage testdocs/sqlite3.c /^ unsigned int nCurrentPage; \/* Number of purgeable pages allocated *\/$/;" m struct:PGroup file: +nCursor testdocs/sqlite3.c /^ int nCursor; \/* Number of entries in apCsr *\/$/;" m struct:VdbeFrame file: +nCursor testdocs/sqlite3.c /^ int nCursor; \/* Number of slots in apCsr[] *\/$/;" m struct:Vdbe file: +nCursor testdocs/sqlite3.c /^ u32 nCursor; \/* Number of open cursors *\/$/;" m struct:Rtree file: +nData testdocs/sqlite3.c /^ int nData; \/* Bytes of data in aData *\/$/;" m struct:SegmentWriter file: +nData testdocs/sqlite3.c /^ int nData; \/* Bytes of valid data so far *\/$/;" m struct:SegmentNode file: +nData testdocs/sqlite3.c /^ int nData; \/* Number of bytes in aData *\/$/;" m struct:SessionInput file: +nData testdocs/sqlite3.c /^ int nData; \/* Total bytes of data (incl. structure) *\/$/;" m struct:Fts5HashEntry file: +nData testdocs/sqlite3.c /^ int nData; \/* Size of pData. 0 if none. *\/$/;" m struct:BtreePayload file: +nData testdocs/sqlite3.c /^ int nData;$/;" m struct:Fts5IndexIter file: +nData testdocs/sqlite3.c /^ int nData;$/;" m struct:PendingList file: +nData testdocs/sqlite3.c /^ u32 nData; \/* Slots used in azResult[]. (nRow+1)*nColumn *\/$/;" m struct:TabResult file: +nDb testdocs/sqlite3.c /^ int nDb; \/* Number of backends currently in use *\/$/;" m struct:sqlite3 file: +nDbChange testdocs/sqlite3.c /^ int nDbChange; \/* Value of db->nChange *\/$/;" m struct:VdbeFrame file: +nDeferredCons testdocs/sqlite3.c /^ i64 nDeferredCons; \/* Number of deferred fk violations *\/$/;" m struct:Savepoint file: +nDeferredCons testdocs/sqlite3.c /^ i64 nDeferredCons; \/* Net deferred constraints this transaction. *\/$/;" m struct:sqlite3 file: +nDeferredImmCons testdocs/sqlite3.c /^ i64 nDeferredImmCons; \/* Number of deferred imm fk. *\/$/;" m struct:Savepoint file: +nDeferredImmCons testdocs/sqlite3.c /^ i64 nDeferredImmCons; \/* Net deferred immediate constraints *\/$/;" m struct:sqlite3 file: +nDim testdocs/sqlite3.c /^ u8 nDim; \/* Number of dimensions *\/$/;" m struct:Rtree file: +nDim2 testdocs/sqlite3.c /^ u8 nDim2; \/* Twice the number of dimensions *\/$/;" m struct:Rtree file: +nDlidx testdocs/sqlite3.c /^ int nDlidx; \/* Allocated size of aDlidx[] array *\/$/;" m struct:Fts5SegWriter file: +nDoc testdocs/sqlite3.c /^ sqlite3_int64 nDoc; \/* 'documents' values for current csr row *\/$/;" m struct:Fts3auxCursor::Fts3auxColstats file: +nDoc testdocs/sqlite3.c /^ sqlite3_int64 nDoc; \/* Documents in table *\/$/;" m struct:Fts3Cursor file: +nDoc testdocs/sqlite3.c /^ sqlite3_int64 nDoc; \/* Number of docs in database *\/$/;" m struct:MatchInfo file: +nDoclist testdocs/sqlite3.c /^ int nDoclist; \/* Size of aDoclist[] in bytes *\/$/;" m struct:Fts3MultiSegReader file: +nDoclist testdocs/sqlite3.c /^ int nDoclist; \/* Size of buffer at aDoclist *\/$/;" m struct:Fts3Cursor file: +nDoclist testdocs/sqlite3.c /^ int nDoclist; \/* Size of doclist in bytes *\/$/;" m struct:NodeReader file: +nDoclist testdocs/sqlite3.c /^ int nDoclist; \/* Size of doclist in current entry *\/$/;" m struct:Fts3SegReader file: +nElem testdocs/sqlite3.c /^ int nElem;$/;" m struct:MatchinfoBuffer file: +nEmpty testdocs/sqlite3.c /^ int nEmpty; \/* Number of contiguous term-less nodes *\/$/;" m struct:Fts5SegWriter file: +nEntry testdocs/sqlite3.c /^ int nEntry; \/* Nr. of entries in aPgno[] and aIndex[] *\/$/;" m struct:WalIterator::WalSegment file: +nEntry testdocs/sqlite3.c /^ int nEntry; \/* Number of entries currently in hash *\/$/;" m struct:Fts5Hash file: +nEntry testdocs/sqlite3.c /^ int nEntry; \/* Number of terms written to node so far *\/$/;" m struct:SegmentNode file: +nEntry testdocs/sqlite3.c /^ int nEntry; \/* Total number of entries in hash table *\/$/;" m struct:SessionTable file: +nEq testdocs/sqlite3.c /^ u16 nEq; \/* Number of equality constraints *\/$/;" m struct:WhereLoop::__anon29::__anon30 file: +nEquiv testdocs/sqlite3.c /^ unsigned char nEquiv; \/* Number of entries in aEquiv[] *\/$/;" m struct:WhereScan file: +nErr testdocs/sqlite3.c /^ int nErr; \/* Number of errors encountered while resolving names *\/$/;" m struct:NameContext file: +nErr testdocs/sqlite3.c /^ int nErr; \/* Number of errors seen *\/$/;" m struct:Parse file: +nErr testdocs/sqlite3.c /^ int nErr; \/* Number of messages written to zErrMsg so far *\/$/;" m struct:IntegrityCk file: +nErr testdocs/sqlite3.c /^ u8 nErr; \/* Number of errors seen *\/$/;" m struct:JsonParse file: +nEst testdocs/sqlite3.c /^ LogEst nEst; \/* Estimated output rows per loop *\/$/;" m struct:ScanStatus file: +nException testdocs/sqlite3.c /^ int nException;$/;" m struct:Unicode61Tokenizer file: +nException testdocs/sqlite3.c /^ int nException;$/;" m struct:unicode_tokenizer file: +nExpr testdocs/sqlite3.c /^ int nExpr; \/* Number of expressions on the list *\/$/;" m struct:ExprList file: +nExt testdocs/sqlite3.c /^ u32 nExt; \/* Number of entries in aExt[] *\/$/;" m struct:sqlite3AutoExtList file: +nExtension testdocs/sqlite3.c /^ int nExtension; \/* Number of loaded extensions *\/$/;" m struct:sqlite3 file: +nExtra testdocs/sqlite3.c /^ u16 nExtra; \/* Add this many bytes to each in-memory page *\/$/;" m struct:Pager file: +nFails testdocs/sqlite3.c /^ int nFails; \/* Number of conch taking failures *\/$/;" m struct:proxyLockingContext file: +nFetchOut testdocs/sqlite3.c /^ int nFetchOut; \/* Number of outstanding xFetch refs *\/$/;" m struct:unixFile file: +nFetchOut testdocs/sqlite3.c /^ int nFetchOut; \/* Number of outstanding xFetch references *\/$/;" m struct:winFile file: +nField testdocs/sqlite3.c /^ i16 nField; \/* Number of fields in the header *\/$/;" m struct:VdbeCursor file: +nField testdocs/sqlite3.c /^ u16 nField; \/* Number of entries in apMem[] *\/$/;" m struct:UnpackedRecord file: +nField testdocs/sqlite3.c /^ u16 nField; \/* Number of key columns in the index *\/$/;" m struct:KeyInfo file: +nFirst testdocs/sqlite3.c /^ int nFirst; \/* Number of entries in aFirst[] *\/$/;" m struct:Fts5SFinder file: +nFirstAlloc testdocs/sqlite3.c /^ int nFirstAlloc; \/* Allocated size of aFirst[] *\/$/;" m struct:Fts5SFinder file: +nFkConstraint testdocs/sqlite3.c /^ i64 nFkConstraint; \/* Number of imm. FK constraints this VM *\/$/;" m struct:Vdbe file: +nFold testdocs/sqlite3.c /^ int nFold; \/* Size of aFold[] in bytes *\/$/;" m struct:Unicode61Tokenizer file: +nFrame testdocs/sqlite3.c /^ int nFrame; \/* Entries in aFrame[] array *\/$/;" m struct:sqlite3rbu file: +nFrame testdocs/sqlite3.c /^ int nFrame; \/* Number of frames in pFrame list *\/$/;" m struct:Vdbe file: +nFrameAlloc testdocs/sqlite3.c /^ int nFrameAlloc; \/* Allocated size of aFrame[] array *\/$/;" m struct:sqlite3rbu file: +nFree testdocs/sqlite3.c /^ int nFree; \/* Bytes of available memory *\/$/;" m struct:ReusableSpace file: +nFree testdocs/sqlite3.c /^ u16 nFree; \/* Number of free bytes on the page *\/$/;" m struct:MemPage file: +nFreeSlot testdocs/sqlite3.c /^ int nFreeSlot; \/* Number of unused pcache slots *\/$/;" m struct:PCacheGlobal file: +nFresh testdocs/sqlite3.c /^ u16 nFresh; \/* Number of objects on pFresh *\/$/;" m struct:RowSet file: +nFunc testdocs/sqlite3.c /^ int nFunc; \/* Number of entries in aFunc[] *\/$/;" m struct:AggInfo file: +nHash testdocs/sqlite3.c /^ unsigned int nHash; \/* Number of slots in apHash[] *\/$/;" m struct:PCache1 file: +nHashSize testdocs/sqlite3.c /^ int nHashSize; \/* Bytes of memory for in-memory hash *\/$/;" m struct:Fts5Config file: +nHdrParsed testdocs/sqlite3.c /^ u16 nHdrParsed; \/* Number of header fields parsed so far *\/$/;" m struct:VdbeCursor file: +nHeap testdocs/sqlite3.c /^ int nHeap; \/* Size of pHeap[] *\/$/;" m struct:Sqlite3Config file: +nHeight testdocs/sqlite3.c /^ int nHeight; \/* Expression tree height of current sub-select *\/$/;" m struct:Parse file: +nHeight testdocs/sqlite3.c /^ int nHeight; \/* Height of the tree headed by this node *\/$/;" m struct:Expr file: +nHidden testdocs/sqlite3.c /^ u8 nHidden; \/* Number of hidden columns *\/$/;" m struct:PragmaVtab file: +nId testdocs/sqlite3.c /^ int nId; \/* Number of identifiers on the list *\/$/;" m struct:IdList file: +nIdx testdocs/sqlite3.c /^ int nIdx; \/* Number of entries in aIdx[] *\/$/;" m struct:Fts5Sorter file: +nIdxCol testdocs/sqlite3.c /^ u16 nIdxCol; \/* Index column used for ORDER BY *\/$/;" m struct:WhereLoop::__anon29::__anon30 file: +nIn testdocs/sqlite3.c /^ int nIn; \/* Number of entries in aInLoop[] *\/$/;" m struct:WhereLevel::__anon27::__anon28 file: +nIn testdocs/sqlite3.c /^ int nIn; \/* Size of input text in bytes *\/$/;" m struct:HighlightContext file: +nIndex testdocs/sqlite3.c /^ int nIndex; \/* Number of aux. indexes on table zTbl *\/$/;" m struct:RbuObjIter file: +nIndex testdocs/sqlite3.c /^ int nIndex; \/* Size of aIndex[] *\/$/;" m struct:Fts3Table file: +nInitPage testdocs/sqlite3.c /^ int nInitPage; \/* Initial bulk allocation size *\/$/;" m struct:PCacheGlobal file: +nInput testdocs/sqlite3.c /^ int nInput; \/* Size of aInput[] in bytes *\/$/;" m struct:unicode_cursor file: +nInput testdocs/sqlite3.c /^ int nInput; \/* size of the input *\/$/;" m struct:porter_tokenizer_cursor file: +nInst testdocs/sqlite3.c /^ int nInst; \/* Total number of phrase instances *\/$/;" m struct:CInstIter file: +nInstAlloc testdocs/sqlite3.c /^ int nInstAlloc; \/* Size of aInst[] array (entries \/ 3) *\/$/;" m struct:Fts5Cursor file: +nInstCount testdocs/sqlite3.c /^ int nInstCount; \/* Number of phrase instances *\/$/;" m struct:Fts5Cursor file: +nJson testdocs/sqlite3.c /^ int nJson; \/* Length of the zJson string in bytes *\/$/;" m struct:JsonParse file: +nKey testdocs/sqlite3.c /^ i64 nKey; \/* Size of pKey, or last integer key *\/$/;" m struct:BtCursor file: +nKey testdocs/sqlite3.c /^ i64 nKey; \/* The key for INTKEY tables, or nPayload otherwise *\/$/;" m struct:CellInfo file: +nKey testdocs/sqlite3.c /^ int nKey; \/* Length of key in bytes *\/$/;" m struct:Fts5HashEntry file: +nKey testdocs/sqlite3.c /^ int nKey; \/* Number of bytes in key *\/$/;" m struct:PmaReader file: +nKey testdocs/sqlite3.c /^ sqlite3_int64 nKey; \/* Size of pKey for indexes. PRIMARY KEY for tabs *\/$/;" m struct:BtreePayload file: +nKey testdocs/sqlite3.c /^ void *pKey; int nKey; \/* Key associated with this element *\/$/;" m struct:Fts3HashElem file: +nKeyCol testdocs/sqlite3.c /^ int nKeyCol; \/* Number of index columns w\/o the pk\/rowid *\/$/;" m struct:Stat4Accum file: +nKeyCol testdocs/sqlite3.c /^ u16 nKeyCol; \/* Number of columns forming the key *\/$/;" m struct:Index file: +nLSlot testdocs/sqlite3.c /^ u16 nLSlot; \/* Number of slots allocated for aLTerm[] *\/$/;" m struct:WhereLoop file: +nLTerm testdocs/sqlite3.c /^ u16 nLTerm; \/* Number of entries in aLTerm[] *\/$/;" m struct:WhereLoop file: +nLabel testdocs/sqlite3.c /^ int nLabel; \/* Number of labels used *\/$/;" m struct:Parse file: +nLastOvfl testdocs/sqlite3.c /^ int nLastOvfl; \/* Bytes of payload on final overflow page *\/$/;" m struct:StatCell file: +nLeTerm testdocs/sqlite3.c /^ int nLeTerm; \/* Size of zLeTerm in bytes *\/$/;" m struct:Fts5VocabCursor file: +nLeafAdd testdocs/sqlite3.c /^ u32 nLeafAdd; \/* Number of leaf blocks added this trans *\/$/;" m struct:Fts3Table file: +nLeafData testdocs/sqlite3.c /^ i64 nLeafData; \/* Number of bytes of leaf data written *\/$/;" m struct:SegmentWriter file: +nLeafData testdocs/sqlite3.c /^ sqlite3_int64 nLeafData; \/* Bytes of leaf page data so far *\/$/;" m struct:IncrmergeWriter file: +nLeafEst testdocs/sqlite3.c /^ int nLeafEst; \/* Space allocated for leaf blocks *\/$/;" m struct:IncrmergeWriter file: +nLeafWritten testdocs/sqlite3.c /^ int nLeafWritten; \/* Number of leaf pages written *\/$/;" m struct:Fts5SegWriter file: +nLevel testdocs/sqlite3.c /^ int nLevel; \/* Number of levels in this index *\/$/;" m struct:Fts5Structure file: +nLevel testdocs/sqlite3.c /^ u8 nLevel; \/* Number of nested loop *\/$/;" m struct:WhereInfo file: +nList testdocs/sqlite3.c /^ int nList; \/* Length of position list *\/$/;" m struct:Fts3Doclist file: +nList testdocs/sqlite3.c /^ int nList;$/;" m struct:TokenDoclist file: +nLocal testdocs/sqlite3.c /^ int nLocal; \/* Bytes of local payload *\/$/;" m struct:StatCell file: +nLocal testdocs/sqlite3.c /^ u16 nLocal; \/* Amount of payload held locally, not on overflow *\/$/;" m struct:CellInfo file: +nLock testdocs/sqlite3.c /^ int nLock; \/* Number of outstanding file locks *\/$/;" m struct:unixInodeInfo file: +nLookaside testdocs/sqlite3.c /^ int nLookaside; \/* Default lookaside buffer count *\/$/;" m struct:Sqlite3Config file: +nLvl testdocs/sqlite3.c /^ int nLvl;$/;" m struct:Fts5DlidxIter file: +nMalloc testdocs/sqlite3.c /^ int nMalloc; \/* Size of malloc'd buffer at zMalloc *\/$/;" m struct:SegmentNode file: +nMalloc testdocs/sqlite3.c /^ int nMalloc; \/* Size of malloc'd buffer at zMalloc *\/$/;" m struct:SegmentWriter file: +nMax testdocs/sqlite3.c /^ unsigned int nMax; \/* Configured "cache_size" value *\/$/;" m struct:PCache1 file: +nMaxArg testdocs/sqlite3.c /^ int nMaxArg; \/* Max args passed to user function by sub-program *\/$/;" m struct:Parse file: +nMaxEqZero testdocs/sqlite3.c /^ int nMaxEqZero; \/* Max leading 0 in anEq[] for any a[] entry *\/$/;" m struct:Stat4Accum file: +nMaxPage testdocs/sqlite3.c /^ unsigned int nMaxPage; \/* Sum of nMax for purgeable caches *\/$/;" m struct:PGroup file: +nMaxPendingData testdocs/sqlite3.c /^ int nMaxPendingData; \/* Max pending data before flush to disk *\/$/;" m struct:Fts3Table file: +nMaxSorterMmap testdocs/sqlite3.c /^ int nMaxSorterMmap; \/* Maximum size of regions mapped by sorter *\/$/;" m struct:sqlite3 file: +nMem testdocs/sqlite3.c /^ int nMem; \/* Number of memory cells required *\/$/;" m struct:SubProgram file: +nMem testdocs/sqlite3.c /^ int nMem; \/* Number of entries in aMem *\/$/;" m struct:VdbeFrame file: +nMem testdocs/sqlite3.c /^ int nMem; \/* Number of memory locations currently allocated *\/$/;" m struct:Vdbe file: +nMem testdocs/sqlite3.c /^ int nMem; \/* Number of memory cells used so far *\/$/;" m struct:Parse file: +nMem testdocs/sqlite3.c /^ u16 nMem; \/* Number of aMem[] value. Might be zero *\/$/;" m struct:BtreePayload file: +nMemory testdocs/sqlite3.c /^ int nMemory; \/* Size of list.aMemory allocation in bytes *\/$/;" m struct:VdbeSorter file: +nMerge testdocs/sqlite3.c /^ int nMerge; \/* Number of segments in incr-merge *\/$/;" m struct:Fts5StructureLevel file: +nMin testdocs/sqlite3.c /^ unsigned int nMin; \/* Minimum number of pages reserved *\/$/;" m struct:PCache1 file: +nMinPage testdocs/sqlite3.c /^ unsigned int nMinPage; \/* Sum of nMin for purgeable caches *\/$/;" m struct:PGroup file: +nMmapOut testdocs/sqlite3.c /^ int nMmapOut; \/* Number of mmap pages currently outstanding *\/$/;" m struct:Pager file: +nModuleArg testdocs/sqlite3.c /^ int nModuleArg; \/* Number of arguments to the module *\/$/;" m struct:Table file: +nMxPayload testdocs/sqlite3.c /^ int nMxPayload; \/* Largest payload of any cell on this page *\/$/;" m struct:StatPage file: +nMxPayload testdocs/sqlite3.c /^ int nMxPayload; \/* Value of 'mx_payload' column *\/$/;" m struct:StatCursor file: +nName testdocs/sqlite3.c /^ int nName; \/* Length of the zCanonicalName[] string *\/$/;" m struct:vxworksFileId file: +nName testdocs/sqlite3.c /^ u8 nName; \/* Length of th name *\/$/;" m struct:__anon19 file: +nNear testdocs/sqlite3.c /^ int nNear; \/* NEAR parameter *\/$/;" m struct:Fts5ExprNearset file: +nNear testdocs/sqlite3.c /^ int nNear; \/* Valid if eType==FTSQUERY_NEAR *\/$/;" m struct:Fts3Expr file: +nNeeded testdocs/sqlite3.c /^ int nNeeded; \/* Total bytes that could not be allocated *\/$/;" m struct:ReusableSpace file: +nNest testdocs/sqlite3.c /^ int nNest; \/* Number of nested brackets *\/$/;" m struct:ParseContext file: +nNode testdocs/sqlite3.c /^ int nNode; \/* Size of buffer at aNode (or 0) *\/$/;" m struct:Fts3SegReader file: +nNode testdocs/sqlite3.c /^ int nNode;$/;" m struct:NodeReader file: +nNode testdocs/sqlite3.c /^ u32 nNode; \/* Number of slots of aNode[] used *\/$/;" m struct:JsonParse file: +nNodeSize testdocs/sqlite3.c /^ int nNodeSize; \/* Soft limit for node size *\/$/;" m struct:Fts3Table file: +nOBSat testdocs/sqlite3.c /^ i8 nOBSat; \/* Number of ORDER BY terms satisfied by indices *\/$/;" m struct:WhereInfo file: +nOBSat testdocs/sqlite3.c /^ int nOBSat; \/* Number of ORDER BY terms satisfied by indices *\/$/;" m struct:SortCtx file: +nOcc testdocs/sqlite3.c /^ sqlite3_int64 nOcc; \/* 'occurrences' values for current csr row *\/$/;" m struct:Fts3auxCursor::Fts3auxColstats file: +nOffsetList testdocs/sqlite3.c /^ int nOffsetList; \/* For descending pending seg-readers only *\/$/;" m struct:Fts3SegReader file: +nOldOff testdocs/sqlite3.c /^ int nOldOff;$/;" m struct:SessionDiffCtx file: +nOp testdocs/sqlite3.c /^ int nOp; \/* Elements in aOp[] *\/$/;" m struct:SubProgram file: +nOp testdocs/sqlite3.c /^ int nOp; \/* Number of instructions in the program *\/$/;" m struct:Vdbe file: +nOp testdocs/sqlite3.c /^ int nOp; \/* Size of aOp array *\/$/;" m struct:VdbeFrame file: +nOpAlloc testdocs/sqlite3.c /^ int nOpAlloc; \/* Number of slots allocated for Vdbe.aOp[] *\/$/;" m struct:Parse file: +nOrderBy testdocs/sqlite3.c /^ int nOrderBy; \/* Number of terms in the ORDER BY clause *\/$/;" m struct:sqlite3_index_info file: +nOrig testdocs/sqlite3.c /^ Pgno nOrig; \/* Original number of pages in file *\/$/;" m struct:PagerSavepoint file: +nOther testdocs/sqlite3.c /^ int nOther; \/* Number of references to columns in other FROM clauses *\/$/;" m struct:SrcCount file: +nOut testdocs/sqlite3.c /^ LogEst nOut; \/* Estimated number of output rows *\/$/;" m struct:WhereLoop file: +nOut testdocs/sqlite3.c /^ LogEst nOut; \/* Number of outputs for this subquery *\/$/;" m struct:WhereOrCost file: +nOut testdocs/sqlite3.c /^ int nOut; \/* Number of buffers currently checked out *\/$/;" m struct:Lookaside file: +nOutput testdocs/sqlite3.c /^ int nOutput;$/;" m struct:PorterRule file: +nOverflow testdocs/sqlite3.c /^ u8 nOverflow; \/* Number of overflow cell bodies in aCell[] *\/$/;" m struct:MemPage file: +nOvfl testdocs/sqlite3.c /^ int nOvfl; \/* Entries in aOvfl[] *\/$/;" m struct:StatCell file: +nOvfl testdocs/sqlite3.c /^ int nOvfl; \/* Number of overflow pages to load doclist *\/$/;" m struct:Fts3TokenAndCost file: +nOvflAlloc testdocs/sqlite3.c /^ int nOvflAlloc; \/* Allocated size of aOverflow[] array *\/$/;" m struct:BtCursor file: +nPMA testdocs/sqlite3.c /^ int nPMA; \/* Number of PMAs currently in file *\/$/;" m struct:SortSubtask file: +nPSample testdocs/sqlite3.c /^ tRowcnt nPSample; \/* How often to do a periodic sample *\/$/;" m struct:Stat4Accum file: +nPage testdocs/sqlite3.c /^ Pgno nPage; \/* Number of pages in the database *\/$/;" m struct:IntegrityCk file: +nPage testdocs/sqlite3.c /^ int nPage; \/* Number of pages in pPage[] *\/$/;" m struct:Sqlite3Config file: +nPage testdocs/sqlite3.c /^ u32 nPage; \/* Size of database in pages *\/$/;" m struct:WalIndexHdr file: +nPage testdocs/sqlite3.c /^ u32 nPage; \/* Number of pages in the database *\/$/;" m struct:BtShared file: +nPage testdocs/sqlite3.c /^ unsigned int nPage; \/* Total number of pages in apHash *\/$/;" m struct:PCache1 file: +nPagePerSector testdocs/sqlite3.c /^ int nPagePerSector; \/* Pages per sector for pTargetFd *\/$/;" m struct:sqlite3rbu file: +nPagecount testdocs/sqlite3.c /^ Pgno nPagecount; \/* Total number of pages to copy *\/$/;" m struct:sqlite3_backup file: +nParam testdocs/sqlite3.c /^ int nParam; \/* Number of function parameters *\/$/;" m struct:sqlite3_rtree_query_info file: +nParam testdocs/sqlite3.c /^ int nParam; \/* Size of array aParam[] *\/$/;" m struct:sqlite3_rtree_geometry file: +nParam testdocs/sqlite3.c /^ int nParam; \/* Number of parameters to the SQL function *\/$/;" m struct:RtreeMatchArg file: +nPayload testdocs/sqlite3.c /^ int nPayload; \/* Value of 'payload' column *\/$/;" m struct:StatCursor file: +nPayload testdocs/sqlite3.c /^ u32 nPayload; \/* Bytes of payload *\/$/;" m struct:CellInfo file: +nPendingData testdocs/sqlite3.c /^ int nPendingData; \/* Current bytes of pending data *\/$/;" m struct:Fts3Table file: +nPendingData testdocs/sqlite3.c /^ int nPendingData; \/* Current bytes of pending data *\/$/;" m struct:Fts5Index file: +nPgsz testdocs/sqlite3.c /^ int nPgsz; \/* Page size for host database *\/$/;" m struct:Fts3Table file: +nPhaseOneStep testdocs/sqlite3.c /^ i64 nPhaseOneStep;$/;" m struct:RbuState file: +nPhaseOneStep testdocs/sqlite3.c /^ i64 nPhaseOneStep;$/;" m struct:sqlite3rbu file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Number of entries in aPhrase[] array *\/$/;" m struct:Fts5ExprNearset file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Number of matchable phrases in query *\/$/;" m struct:Fts3Cursor file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Number of matchable phrases in query *\/$/;" m struct:MatchInfo file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Number of phrases in expression *\/$/;" m struct:Fts5Expr file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Number of phrases in query *\/$/;" m struct:Fts5Bm25Data file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Number of phrases in query *\/$/;" m struct:SnippetIter file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Number of phrases seen so far *\/$/;" m struct:LoadDoclistCtx file: +nPhrase testdocs/sqlite3.c /^ int nPhrase; \/* Size of apPhrase array *\/$/;" m struct:Fts5Parse file: +nPoint testdocs/sqlite3.c /^ int nPoint; \/* Number of slots used in aPoint[] *\/$/;" m struct:RtreeCursor file: +nPointAlloc testdocs/sqlite3.c /^ int nPointAlloc; \/* Number of slots allocated for aPoint[] *\/$/;" m struct:RtreeCursor file: +nPool testdocs/sqlite3.c /^ u32 nPool;$/;" m struct:Mem3Global file: +nPopulate testdocs/sqlite3.c /^ int nPopulate; \/* If >0, bytes of buffer aNode[] loaded *\/$/;" m struct:Fts3SegReader file: +nPos testdocs/sqlite3.c /^ int nPos; \/* Number of bytes in current position list *\/$/;" m struct:Fts5SegIter file: +nPoslist testdocs/sqlite3.c /^ int nPoslist;$/;" m struct:Fts5DoclistIter file: +nPragCName testdocs/sqlite3.c /^ u8 nPragCName; \/* Num of col names. 0 means use pragma name *\/$/;" m struct:PragmaName file: +nPrefix testdocs/sqlite3.c /^ int nPrefix; \/* Prefix length (0 for main terms index) *\/$/;" m struct:Fts3Table::Fts3Index file: +nPrefix testdocs/sqlite3.c /^ int nPrefix; \/* Number of prefix indexes *\/$/;" m struct:Fts5Config file: +nProgress testdocs/sqlite3.c /^ i64 nProgress;$/;" m struct:RbuState file: +nProgress testdocs/sqlite3.c /^ int nProgress; \/* Rows processed for all objects *\/$/;" m struct:sqlite3rbu file: +nProgressOps testdocs/sqlite3.c /^ unsigned nProgressOps; \/* Number of opcodes for progress callback *\/$/;" m struct:sqlite3 file: +nQueryLoop testdocs/sqlite3.c /^ u32 nQueryLoop; \/* Est number of iterations of a query (10*log2(N)) *\/$/;" m struct:Parse file: +nRangeReg testdocs/sqlite3.c /^ int nRangeReg; \/* Size of the temporary register block *\/$/;" m struct:Parse file: +nRankArg testdocs/sqlite3.c /^ int nRankArg; \/* Number of trailing arguments for rank() *\/$/;" m struct:Fts5Cursor file: +nRbu testdocs/sqlite3.c /^ int nRbu; \/* Number of RBU VFS in the stack *\/$/;" m struct:sqlite3rbu file: +nRead testdocs/sqlite3.c /^ int nRead; \/* Total number of blocks read *\/$/;" m struct:Fts5Index file: +nRead testdocs/sqlite3.c /^ int nRead; \/* Database pages read *\/$/;" m struct:Pager file: +nReaders testdocs/sqlite3.c /^ int nReaders; \/* Number of reader locks obtained *\/$/;" m struct:winceLock file: +nRec testdocs/sqlite3.c /^ int nRec; \/* Pages journalled since last j-header written *\/$/;" m struct:Pager file: +nRecValid testdocs/sqlite3.c /^ int nRecValid; \/* Number of valid fields currently in pRec *\/$/;" m struct:WhereLoopBuilder file: +nRecord testdocs/sqlite3.c /^ int nRecord; \/* Number of bytes in buffer aRecord[] *\/$/;" m struct:SessionChange file: +nRecyclable testdocs/sqlite3.c /^ unsigned int nRecyclable; \/* Number of pages in the LRU list *\/$/;" m struct:PCache1 file: +nRef testdocs/sqlite3.c /^ i16 nRef; \/* Number of users of this page *\/$/;" m struct:PgHdr file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of open cursors *\/$/;" m struct:sqlite3_vtab file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of pointers to this structure *\/$/;" m struct:unixInodeInfo file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Object reference count *\/$/;" m struct:Fts5Structure file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of references to this one *\/$/;" m struct:vxworksFileId file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of references to this node *\/$/;" m struct:RtreeNode file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of unixShm objects pointing to this *\/$/;" m struct:unixShmNode file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of winShm objects pointing to this *\/$/;" m struct:winShmNode file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of pointers to this structure *\/$/;" m struct:VTable file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of references to this structure *\/$/;" m struct:BtShared file: +nRef testdocs/sqlite3.c /^ int nRef; \/* Number of names resolved by this context *\/$/;" m struct:NameContext file: +nRef testdocs/sqlite3.c /^ int nRef;$/;" m struct:FuncDestructor file: +nRef testdocs/sqlite3.c /^ u32 nRef; \/* Number of references to this KeyInfo object *\/$/;" m struct:KeyInfo file: +nRef testdocs/sqlite3.c /^ volatile int nRef; \/* Number of enterances *\/$/;" m struct:sqlite3_mutex file: +nRef testdocs/sqlite3.c /^ volatile int nRef; \/* Number of entrances *\/$/;" m struct:sqlite3_mutex file: +nRefInitMutex testdocs/sqlite3.c /^ int nRefInitMutex; \/* Number of users of pInitMutex *\/$/;" m struct:Sqlite3Config file: +nRefSum testdocs/sqlite3.c /^ int nRefSum; \/* Sum of ref counts over all pages *\/$/;" m struct:PCache file: +nRegion testdocs/sqlite3.c /^ int nRegion; \/* Size of array apRegion *\/$/;" m struct:winShmNode file: +nRegion testdocs/sqlite3.c /^ u16 nRegion; \/* Size of array apRegion *\/$/;" m struct:unixShmNode file: +nRemaining testdocs/sqlite3.c /^ Pgno nRemaining; \/* Number of pages left to copy *\/$/;" m struct:sqlite3_backup file: +nResColumn testdocs/sqlite3.c /^ u16 nResColumn; \/* Number of columns in one row of the result set *\/$/;" m struct:Vdbe file: +nReserve testdocs/sqlite3.c /^ i16 nReserve; \/* Number of unused bytes at end of each page *\/$/;" m struct:Pager file: +nReserve testdocs/sqlite3.c /^ int nReserve; \/* Try to keep nFreeSlot above this *\/$/;" m struct:PCacheGlobal file: +nRow testdocs/sqlite3.c /^ LogEst nRow; \/* Estimated number of rows generated by this path *\/$/;" m struct:WherePath file: +nRow testdocs/sqlite3.c /^ int nRow;$/;" m struct:RbuState file: +nRow testdocs/sqlite3.c /^ tRowcnt nRow; \/* Number of rows in the entire table *\/$/;" m struct:Stat4Accum file: +nRow testdocs/sqlite3.c /^ u32 nRow; \/* Number of rows in the result *\/$/;" m struct:TabResult file: +nRowAvg testdocs/sqlite3.c /^ int nRowAvg; \/* Average size of database rows, in pages *\/$/;" m struct:Fts3Cursor file: +nRowEst testdocs/sqlite3.c /^ i64 nRowEst; \/* Estimated number of rows in this table *\/$/;" m struct:Rtree file: +nRowEst0 testdocs/sqlite3.c /^ tRowcnt nRowEst0; \/* Non-logarithmic number of rows in the index *\/$/;" m struct:Index file: +nRowLogEst testdocs/sqlite3.c /^ LogEst nRowLogEst; \/* Estimated rows in table - from sqlite_stat1 table *\/$/;" m struct:Table file: +nRowOut testdocs/sqlite3.c /^ LogEst nRowOut; \/* Estimated number of output rows *\/$/;" m struct:WhereInfo file: +nRowid testdocs/sqlite3.c /^ u32 nRowid; \/* Sizeof aRowid[] *\/$/;" m struct:Stat4Sample file: +nRowidOffset testdocs/sqlite3.c /^ int nRowidOffset; \/* Allocated size of aRowidOffset[] array *\/$/;" m struct:Fts5SegIter file: +nSample testdocs/sqlite3.c /^ int nSample; \/* Current number of samples *\/$/;" m struct:Stat4Accum file: +nSample testdocs/sqlite3.c /^ int nSample; \/* Number of elements in aSample[] *\/$/;" m struct:Index file: +nSampleCol testdocs/sqlite3.c /^ int nSampleCol; \/* Size of IndexSample.anEq[] and so on *\/$/;" m struct:Index file: +nSavepoint testdocs/sqlite3.c /^ int nSavepoint; \/* Number of non-transaction savepoints *\/$/;" m struct:sqlite3 file: +nSavepoint testdocs/sqlite3.c /^ int nSavepoint; \/* Number of elements in aSavepoint[] *\/$/;" m struct:Pager file: +nScan testdocs/sqlite3.c /^ int nScan; \/* Entries in aScan[] *\/$/;" m struct:Vdbe file: +nScratch testdocs/sqlite3.c /^ int nScratch; \/* Number of scratch buffers *\/$/;" m struct:Sqlite3Config file: +nScratchFree testdocs/sqlite3.c /^ u32 nScratchFree;$/;" m struct:Mem0Global file: +nSdst testdocs/sqlite3.c /^ int nSdst; \/* Number of registers allocated *\/$/;" m struct:SelectDest file: +nSeg testdocs/sqlite3.c /^ int nSeg; \/* Size of aSeg[] array *\/$/;" m struct:Fts5Iter file: +nSeg testdocs/sqlite3.c /^ int nSeg; \/* Total number of segments on level *\/$/;" m struct:Fts5StructureLevel file: +nSegment testdocs/sqlite3.c /^ int nSegment; \/* Number of entries in aSegment[] *\/$/;" m struct:WalIterator file: +nSegment testdocs/sqlite3.c /^ int nSegment; \/* Size of apSegment array *\/$/;" m struct:Fts3MultiSegReader file: +nSegment testdocs/sqlite3.c /^ int nSegment; \/* Total segments in this structure *\/$/;" m struct:Fts5Structure file: +nSelect testdocs/sqlite3.c /^ int nSelect; \/* Number of SELECT statements seen *\/$/;" m struct:Parse file: +nSelectIndent testdocs/sqlite3.c /^ int nSelectIndent; \/* How far to indent SELECTTRACE() output *\/$/;" m struct:Parse file: +nSelectRow testdocs/sqlite3.c /^ LogEst nSelectRow; \/* Estimated number of result rows *\/$/;" m struct:Select file: +nSet testdocs/sqlite3.c /^ u32 nSet; \/* Number of bits that are set - only valid for aHash$/;" m struct:Bitvec file: +nShared testdocs/sqlite3.c /^ int nShared; \/* Number of SHARED locks held *\/$/;" m struct:unixInodeInfo file: +nShm testdocs/sqlite3.c /^ int nShm; \/* Number of entries in apShm[] array *\/$/;" m struct:rbu_file file: +nSize testdocs/sqlite3.c /^ int nSize; \/* Bytes of data currently in memory *\/$/;" m struct:MemJournal file: +nSize testdocs/sqlite3.c /^ int nSize; \/* Size of allocation at aData *\/$/;" m struct:SegmentWriter file: +nSize testdocs/sqlite3.c /^ int nSize;$/;" m struct:Fts5DoclistIter file: +nSize testdocs/sqlite3.c /^ u16 nSize; \/* Size of the cell content on the main b-tree page *\/$/;" m struct:CellInfo file: +nSkip testdocs/sqlite3.c /^ u16 nSkip; \/* Number of NULL aLTerm[] entries *\/$/;" m struct:WhereLoop file: +nSlot testdocs/sqlite3.c /^ int nSlot; \/* Size of aSlot[] array *\/$/;" m struct:Fts5Hash file: +nSlot testdocs/sqlite3.c /^ int nSlot; \/* The number of pcache slots *\/$/;" m struct:PCacheGlobal file: +nSlot testdocs/sqlite3.c /^ int nSlot; \/* Number of entries in a[] *\/$/;" m struct:WhereClause file: +nSnippet testdocs/sqlite3.c /^ int nSnippet; \/* Requested snippet length (in tokens) *\/$/;" m struct:SnippetIter file: +nSortingColumn testdocs/sqlite3.c /^ int nSortingColumn; \/* Number of columns in the sorting index *\/$/;" m struct:AggInfo file: +nSpace testdocs/sqlite3.c /^ int nSpace;$/;" m struct:Fts5Buffer file: +nSpace testdocs/sqlite3.c /^ int nSpace;$/;" m struct:PendingList file: +nSpill testdocs/sqlite3.c /^ int nSpill; \/* Bytes of data before flushing *\/$/;" m struct:MemJournal file: +nSqlExec testdocs/sqlite3.c /^ u8 nSqlExec; \/* Number of pending OP_SqlExec opcodes *\/$/;" m struct:sqlite3 file: +nSrc testdocs/sqlite3.c /^ int nSrc; \/* Number of tables or subqueries in the FROM clause *\/$/;" m struct:SrcList file: +nStat testdocs/sqlite3.c /^ int nStat; \/* Size of aStat[] array *\/$/;" m struct:Fts3auxCursor file: +nStatement testdocs/sqlite3.c /^ int nStatement; \/* Number of nested statement-transactions *\/$/;" m struct:sqlite3 file: +nStep testdocs/sqlite3.c /^ int nStep; \/* Rows processed for current object *\/$/;" m struct:sqlite3rbu file: +nStmtDefCons testdocs/sqlite3.c /^ i64 nStmtDefCons; \/* Number of def. constraints when stmt started *\/$/;" m struct:Vdbe file: +nStmtDefImmCons testdocs/sqlite3.c /^ i64 nStmtDefImmCons; \/* Number of def. imm constraints when stmt started *\/$/;" m struct:Vdbe file: +nStmtSpill testdocs/sqlite3.c /^ int nStmtSpill; \/* Stmt-journal spill-to-disk threshold *\/$/;" m struct:Sqlite3Config file: +nStop testdocs/sqlite3.c /^ int nStop; \/* Byte-length of string zStop *\/$/;" m struct:Fts3auxCursor file: +nSub testdocs/sqlite3.c /^ int nSub; \/* Number of entries in apSub *\/$/;" m struct:VdbeOpIter file: +nSubRec testdocs/sqlite3.c /^ u32 nSubRec; \/* Number of records written to sub-journal *\/$/;" m struct:Pager file: +nSuffix testdocs/sqlite3.c /^ int nSuffix;$/;" m struct:PorterRule file: +nTab testdocs/sqlite3.c /^ int nTab; \/* Number of previously allocated VDBE cursors *\/$/;" m struct:Parse file: +nTabRef testdocs/sqlite3.c /^ u32 nTabRef; \/* Number of pointers to this Table *\/$/;" m struct:Table file: +nTableLock testdocs/sqlite3.c /^ int nTableLock; \/* Number of locks in aTableLock *\/$/;" m struct:Parse file: +nTask testdocs/sqlite3.c /^ u8 nTask; \/* Size of aTask[] array *\/$/;" m struct:VdbeSorter file: +nTblCol testdocs/sqlite3.c /^ int nTblCol; \/* Size of azTblCol[] array *\/$/;" m struct:RbuObjIter file: +nTempReg testdocs/sqlite3.c /^ u8 nTempReg; \/* Number of temporary registers in aTempReg[] *\/$/;" m struct:Parse file: +nTerm testdocs/sqlite3.c /^ int nTerm; \/* Number of bytes in current term *\/$/;" m struct:Fts3SegReader file: +nTerm testdocs/sqlite3.c /^ int nTerm; \/* Number of bytes in zTerm *\/$/;" m struct:SegmentNode file: +nTerm testdocs/sqlite3.c /^ int nTerm; \/* Number of bytes in zTerm *\/$/;" m struct:SegmentWriter file: +nTerm testdocs/sqlite3.c /^ int nTerm; \/* Number of entries in aTerm[] *\/$/;" m struct:Fts5ExprPhrase file: +nTerm testdocs/sqlite3.c /^ int nTerm; \/* Size of phrase in terms *\/$/;" m struct:Fts5MatchPhrase file: +nTerm testdocs/sqlite3.c /^ int nTerm; \/* Size of zTerm in bytes *\/$/;" m struct:Fts3MultiSegReader file: +nTerm testdocs/sqlite3.c /^ int nTerm; \/* Number of terms *\/$/;" m struct:WhereClause file: +nTerm testdocs/sqlite3.c /^ int nTerm;$/;" m struct:Fts3SegFilter file: +nTerm testdocs/sqlite3.c /^ int nTerm;$/;" m struct:Fts5TermsetEntry file: +nTermAlloc testdocs/sqlite3.c /^ int nTermAlloc; \/* Allocated size of zTerm buffer *\/$/;" m struct:Fts3SegReader file: +nThis testdocs/sqlite3.c /^ int nThis; \/* Number of references to columns in pSrcList *\/$/;" m struct:SrcCount file: +nTitle testdocs/sqlite3.c /^ int nTitle; \/* Bytes of zTitle to save. Includes '\\0' and padding *\/$/;" m struct:__anon20 file: +nTitle testdocs/sqlite3.c /^ u8 nTitle; \/* Bytes of title; includes '\\0' *\/$/;" m struct:MemBlockHdr file: +nToken testdocs/sqlite3.c /^ int nToken; \/* Number of tokens in phrase *\/$/;" m struct:SnippetPhrase file: +nToken testdocs/sqlite3.c /^ int nToken; \/* Number of tokens seen so far *\/$/;" m struct:LoadDoclistCtx file: +nToken testdocs/sqlite3.c /^ int nToken; \/* Size of zToken in bytes *\/$/;" m struct:Fts3tokCursor file: +nToken testdocs/sqlite3.c /^ int nToken; \/* Number of tokens in the phrase *\/$/;" m struct:Fts3Phrase file: +nTokenAllocated testdocs/sqlite3.c /^ int nTokenAllocated; \/* space allocated to zToken buffer *\/$/;" m struct:simple_tokenizer_cursor file: +nTop testdocs/sqlite3.c /^ u16 nTop; \/* Size of TOP vector *\/$/;" m struct:WhereLoop::__anon29::__anon30 file: +nTotalChange testdocs/sqlite3.c /^ int nTotalChange; \/* Value returned by sqlite3_total_changes() *\/$/;" m struct:sqlite3 file: +nTotalRow testdocs/sqlite3.c /^ i64 nTotalRow; \/* Total number of rows in FTS table *\/$/;" m struct:Fts5Storage file: +nTransaction testdocs/sqlite3.c /^ int nTransaction; \/* Number of open transactions (read + write) *\/$/;" m struct:BtShared file: +nTree testdocs/sqlite3.c /^ int nTree; \/* Used size of aTree\/aReadr (power of 2) *\/$/;" m struct:MergeEngine file: +nUnused testdocs/sqlite3.c /^ int nUnused; \/* Number of unused bytes on page *\/$/;" m struct:StatPage file: +nUnused testdocs/sqlite3.c /^ int nUnused; \/* Value of 'unused' column *\/$/;" m struct:StatCursor file: +nUsed testdocs/sqlite3.c /^ int nUsed; \/* Number of arguments used so far *\/$/;" m struct:PrintfArguments file: +nUsed testdocs/sqlite3.c /^ u64 nUsed; \/* Bytes of zBuf[] currently used *\/$/;" m struct:JsonString file: +nUsermerge testdocs/sqlite3.c /^ int nUsermerge; \/* 'usermerge' setting *\/$/;" m struct:Fts5Config file: +nVDestroy testdocs/sqlite3.c /^ int nVDestroy; \/* Number of active OP_VDestroy operations *\/$/;" m struct:sqlite3 file: +nVTrans testdocs/sqlite3.c /^ int nVTrans; \/* Allocated size of aVTrans *\/$/;" m struct:sqlite3 file: +nVal testdocs/sqlite3.c /^ int nVal; \/* Size of the record in bytes *\/$/;" m struct:SorterRecord file: +nVar testdocs/sqlite3.c /^ ynVar nVar; \/* Number of '?' variables seen in the SQL so far *\/$/;" m struct:Parse file: +nVar testdocs/sqlite3.c /^ ynVar nVar; \/* Number of entries in aVar[] *\/$/;" m struct:Vdbe file: +nVdbeActive testdocs/sqlite3.c /^ int nVdbeActive; \/* Number of VDBEs currently running *\/$/;" m struct:sqlite3 file: +nVdbeExec testdocs/sqlite3.c /^ int nVdbeExec; \/* Number of nested calls to VdbeExec() *\/$/;" m struct:sqlite3 file: +nVdbeRead testdocs/sqlite3.c /^ int nVdbeRead; \/* Number of active VDBEs that read or write *\/$/;" m struct:sqlite3 file: +nVdbeWrite testdocs/sqlite3.c /^ int nVdbeWrite; \/* Number of active VDBEs that read and write *\/$/;" m struct:sqlite3 file: +nVtabLock testdocs/sqlite3.c /^ int nVtabLock; \/* Number of virtual tables to lock *\/$/;" m struct:Parse file: +nWiData testdocs/sqlite3.c /^ int nWiData; \/* Size of array apWiData *\/$/;" m struct:Wal file: +nWork testdocs/sqlite3.c /^ int nWork; \/* Number of leaf pages flushed *\/$/;" m struct:IncrmergeWriter file: +nWorkUnit testdocs/sqlite3.c /^ int nWorkUnit; \/* Leaf pages in a "unit" of work *\/$/;" m struct:Fts5Index file: +nWorker testdocs/sqlite3.c /^# define nWorker /;" d file: +nWorker testdocs/sqlite3.c /^#undef nWorker /;" d file: +nWriteCounter testdocs/sqlite3.c /^ u64 nWriteCounter; \/* Total leaves written to level 0 *\/$/;" m struct:Fts5Structure file: +nXField testdocs/sqlite3.c /^ u16 nXField; \/* Number of columns beyond the key columns *\/$/;" m struct:KeyInfo file: +nXor testdocs/sqlite3.c /^ int nXor; \/* Number of XOR operations done *\/$/;" m struct:EntropyGatherer file: +nZero testdocs/sqlite3.c /^ int nZero; \/* Used when bit MEM_Zero is set in flags *\/$/;" m union:sqlite3_value::MemValue file: +nZero testdocs/sqlite3.c /^ int nZero; \/* Extra zero data appended after pData,nData *\/$/;" m struct:BtreePayload file: +na testdocs/sqlite3.c /^ int na; \/* Size of a[] in bytes *\/$/;" m struct:EntropyGatherer file: +nameInUsingClause testdocs/sqlite3.c /^static int nameInUsingClause(IdList *pUsing, const char *zCol){$/;" f file: +ncFlags testdocs/sqlite3.c /^ u16 ncFlags; \/* Zero or more NC_* flags defined below *\/$/;" m struct:NameContext file: +nearlyFull testdocs/sqlite3.c /^ int nearlyFull;$/;" m struct:Mem0Global file: +needFree testdocs/sqlite3.c /^ u8 needFree; \/* True if sqlite3_free(idxStr) is needed *\/$/;" m struct:WhereLoop::__anon29::__anon31 file: +needToFreeIdxStr testdocs/sqlite3.c /^ int needToFreeIdxStr; \/* Free idxStr using sqlite3_free() if true *\/$/;" m struct:sqlite3_index_info file: +nelem stdc.h /^ #define nelem(/;" d +nested testdocs/sqlite3.c /^ u8 nested; \/* Number of nested calls to the parser\/code generator *\/$/;" m struct:Parse file: +neverCorrupt testdocs/sqlite3.c /^ int neverCorrupt; \/* Database is always well-formed *\/$/;" m struct:Sqlite3Config file: +newDatabase testdocs/sqlite3.c /^static int newDatabase(BtShared *pBt){$/;" f file: +newRowid testdocs/sqlite3.c /^static int newRowid(Rtree *pRtree, i64 *piRowid){$/;" f file: +newTnum testdocs/sqlite3.c /^ int newTnum; \/* Rootpage of table being initialized *\/$/;" m struct:sqlite3::sqlite3InitInfo file: +newmask testdocs/sqlite3.c /^ u32 newmask; \/* Mask of new.* columns referenced *\/$/;" m struct:Parse file: +next edit.h /^ struct Log* next; \/* pointer to next operation in the stack *\/$/;" m struct:Log typeref:struct:Log::Log +next testdocs/sqlite3.c /^ u32 next; \/* Index in mem3.aPool[] of next free chunk *\/$/;" m struct:Mem3Block::__anon21::__anon23 file: +next testdocs/sqlite3.c /^ Fts3HashElem *next, *prev; \/* Next and previous elements in the table *\/$/;" m struct:Fts3HashElem file: +next testdocs/sqlite3.c /^ HashElem *next, *prev; \/* Next and previous elements in the table *\/$/;" m struct:HashElem file: +next testdocs/sqlite3.c /^ int next; \/* Index of next free chunk *\/$/;" m struct:Mem5Link file: +nextAutovac testdocs/sqlite3.c /^ signed char nextAutovac; \/* Autovac setting after VACUUM if >=0 *\/$/;" m struct:sqlite3 file: +nextPagesize testdocs/sqlite3.c /^ int nextPagesize; \/* Pagesize after VACUUM if >0 *\/$/;" m struct:sqlite3 file: +nextShmId testdocs/sqlite3.c /^ u8 nextShmId; \/* Next available unixShm.id value *\/$/;" m struct:unixShmNode file: +nextShmId testdocs/sqlite3.c /^ u8 nextShmId; \/* Next available winShm.id value *\/$/;" m struct:winShmNode file: +next_size buf.c /^static size_t next_size(size_t curr) {$/;" f file: +next_stmt testdocs/sqlite3.c /^ sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +nextrune buf.c /^static Rune nextrune(Buf* buf, size_t off, int move, bool (*testfn)(Rune)) {$/;" f file: +nfsUnlock testdocs/sqlite3.c /^static int nfsUnlock(sqlite3_file *id, int eFileLock){$/;" f file: +nn testdocs/sqlite3.c /^ int nn; \/* Size of record in bytes *\/$/;" m struct:Fts5Data file: +noCase testdocs/sqlite3.c /^ u8 noCase; \/* true to ignore case differences *\/$/;" m struct:compareInfo file: +noLock testdocs/sqlite3.c /^ u8 noLock; \/* Do not lock (except in WAL mode) *\/$/;" m struct:Pager file: +noSkipScan testdocs/sqlite3.c /^ unsigned noSkipScan:1; \/* Do not try to use skip-scan if true *\/$/;" m struct:Index file: +noSync testdocs/sqlite3.c /^ u8 noSync; \/* Do not sync the journal if true *\/$/;" m struct:Pager file: +nocaseCollatingFunc testdocs/sqlite3.c /^static int nocaseCollatingFunc($/;" f file: +nodeAcquire testdocs/sqlite3.c /^static int nodeAcquire($/;" f file: +nodeBlobReset testdocs/sqlite3.c /^static void nodeBlobReset(Rtree *pRtree){$/;" f file: +nodeDeleteCell testdocs/sqlite3.c /^static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){$/;" f file: +nodeGetCell testdocs/sqlite3.c /^static void nodeGetCell($/;" f file: +nodeGetCoord testdocs/sqlite3.c /^static void nodeGetCoord($/;" f file: +nodeGetRowid testdocs/sqlite3.c /^static i64 nodeGetRowid($/;" f file: +nodeHash testdocs/sqlite3.c /^static int nodeHash(i64 iNode){$/;" f file: +nodeHashDelete testdocs/sqlite3.c /^static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){$/;" f file: +nodeHashInsert testdocs/sqlite3.c /^static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){$/;" f file: +nodeHashLookup testdocs/sqlite3.c /^static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){$/;" f file: +nodeInsertCell testdocs/sqlite3.c /^static int nodeInsertCell($/;" f file: +nodeNew testdocs/sqlite3.c /^static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){$/;" f file: +nodeOverwriteCell testdocs/sqlite3.c /^static void nodeOverwriteCell($/;" f file: +nodeParentIndex testdocs/sqlite3.c /^static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){$/;" f file: +nodeReaderInit testdocs/sqlite3.c /^static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){$/;" f file: +nodeReaderNext testdocs/sqlite3.c /^static int nodeReaderNext(NodeReader *p){$/;" f file: +nodeReaderRelease testdocs/sqlite3.c /^static void nodeReaderRelease(NodeReader *p){$/;" f file: +nodeReference testdocs/sqlite3.c /^static void nodeReference(RtreeNode *p){$/;" f file: +nodeRelease testdocs/sqlite3.c /^static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){$/;" f file: +nodeRowidIndex testdocs/sqlite3.c /^static int nodeRowidIndex($/;" f file: +nodeWrite testdocs/sqlite3.c /^static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){$/;" f file: +nodeZero testdocs/sqlite3.c /^static void nodeZero(Rtree *pRtree, RtreeNode *p){$/;" f file: +nolockCheckReservedLock testdocs/sqlite3.c /^static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){$/;" f file: +nolockClose testdocs/sqlite3.c /^static int nolockClose(sqlite3_file *id) {$/;" f file: +nolockLock testdocs/sqlite3.c /^static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){$/;" f file: +nolockUnlock testdocs/sqlite3.c /^static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){$/;" f file: +noopFunc testdocs/sqlite3.c /^#define noopFunc /;" d file: +noopMutexAlloc testdocs/sqlite3.c /^static sqlite3_mutex *noopMutexAlloc(int id){$/;" f file: +noopMutexEnd testdocs/sqlite3.c /^static int noopMutexEnd(void){ return SQLITE_OK; }$/;" f file: +noopMutexEnter testdocs/sqlite3.c /^static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }$/;" f file: +noopMutexFree testdocs/sqlite3.c /^static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }$/;" f file: +noopMutexInit testdocs/sqlite3.c /^static int noopMutexInit(void){ return SQLITE_OK; }$/;" f file: +noopMutexLeave testdocs/sqlite3.c /^static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }$/;" f file: +noopMutexTry testdocs/sqlite3.c /^static int noopMutexTry(sqlite3_mutex *p){$/;" f file: +notIndexed testdocs/sqlite3.c /^ unsigned notIndexed :1; \/* True if there is a NOT INDEXED clause *\/$/;" m struct:SrcList::SrcList_item::__anon14 file: +notNull testdocs/sqlite3.c /^ u8 notNull; \/* An OE_ code for handling a NOT NULL constraint *\/$/;" m struct:Column file: +notReady testdocs/sqlite3.c /^ Bitmask notReady; \/* FROM entries not usable at this level *\/$/;" m struct:WhereLevel file: +notUsed0 testdocs/sqlite3.c /^ u32 notUsed0; \/* Available for future enhancements *\/$/;" m struct:WalCkptInfo file: +notUsed1 testdocs/sqlite3.c /^ double notUsed1; \/* Spacer *\/$/;" m union:sqlite3::__anon8 file: +notValid testdocs/sqlite3.c /^static void notValid($/;" f file: +nowValue testdocs/sqlite3.c /^ sqlite3StatValueType nowValue[10]; \/* Current value *\/$/;" m struct:sqlite3StatType file: +nrhs testdocs/sqlite3.c /^ unsigned char nrhs; \/* Number of right-hand side symbols in the rule *\/$/;" m struct:__anon35 file: +nrhs testdocs/sqlite3.c /^ unsigned char nrhs; \/* Number of right-hand side symbols in the rule *\/$/;" m struct:__anon39 file: +nullRow testdocs/sqlite3.c /^ u8 nullRow; \/* True if pointing to a row with no data *\/$/;" m struct:VdbeCursor file: +nullifFunc testdocs/sqlite3.c /^static void nullifFunc($/;" f file: +numberOfCachePages testdocs/sqlite3.c /^static int numberOfCachePages(PCache *p){$/;" f file: +numericType testdocs/sqlite3.c /^static u16 numericType(Mem *pMem){$/;" f file: +objiter testdocs/sqlite3.c /^ RbuObjIter objiter; \/* Iterator for skipping through tbl\/idx *\/$/;" m struct:sqlite3rbu file: +off edit.h /^ size_t off; \/* offset in the file where the deletion occurred *\/$/;" m struct:Log::__anon2::__anon4 +offset testdocs/sqlite3.c /^ unsigned long long offset; \/* offset to first byte to lock *\/$/;" m struct:ByteRangeLockPB2 file: +offsetof testdocs/sqlite3.c /^#define offsetof(/;" d file: +okConstFactor testdocs/sqlite3.c /^ u8 okConstFactor; \/* OK to factor out constants *\/$/;" m struct:Parse file: +oldLockingContext testdocs/sqlite3.c /^ void *oldLockingContext; \/* Original lockingcontext to restore on close *\/$/;" m struct:proxyLockingContext file: +oldmask testdocs/sqlite3.c /^ u32 oldmask; \/* Mask of old.* columns referenced *\/$/;" m struct:Parse file: +omit testdocs/sqlite3.c /^ unsigned char omit; \/* Do not code a test for this constraint *\/$/;" m struct:sqlite3_index_info::sqlite3_index_constraint_usage file: +omitMask testdocs/sqlite3.c /^ u16 omitMask; \/* Terms that may be omitted *\/$/;" m struct:WhereLoop::__anon29::__anon31 file: +onError testdocs/sqlite3.c /^ u8 onError; \/* OE_Abort, OE_Ignore, OE_Replace, or OE_None *\/$/;" m struct:Index file: +onErrorText testdocs/sqlite3.c /^static const char *onErrorText(int onError){$/;" f file: +onerror testbuf.c /^static void onerror(char* msg) {$/;" f file: +oom testdocs/sqlite3.c /^ u8 oom; \/* Set to true if out of memory *\/$/;" m struct:JsonParse file: +op testdocs/sqlite3.c /^ unsigned char op; \/* Constraint operator *\/$/;" m struct:sqlite3_index_info::sqlite3_index_constraint file: +op testdocs/sqlite3.c /^ int op; \/* Constraining operation *\/$/;" m struct:RtreeConstraint file: +op testdocs/sqlite3.c /^ int op; \/* Current operation *\/$/;" m struct:sqlite3_changeset_iter file: +op testdocs/sqlite3.c /^ int op; \/* One of SQLITE_INSERT, UPDATE, DELETE *\/$/;" m struct:PreUpdate file: +op testdocs/sqlite3.c /^ int op; \/* One of UPDATE, DELETE, INSERT *\/$/;" m struct:SessionChange file: +op testdocs/sqlite3.c /^ u8 op, p3, p5; \/* Opcode, P3 & P5 of the opcode that ends the loop *\/$/;" m struct:WhereLevel file: +op testdocs/sqlite3.c /^ u8 op; \/* Split operator. TK_AND or TK_OR *\/$/;" m struct:WhereClause file: +op testdocs/sqlite3.c /^ u8 op; \/* One of TK_DELETE, TK_UPDATE, TK_INSERT *\/$/;" m struct:Trigger file: +op testdocs/sqlite3.c /^ u8 op; \/* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT *\/$/;" m struct:Select file: +op testdocs/sqlite3.c /^ u8 op; \/* Operation performed by this node *\/$/;" m struct:Expr file: +op testdocs/sqlite3.c /^ u8 op; \/* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT *\/$/;" m struct:TriggerStep file: +op2 testdocs/sqlite3.c /^ u8 op2; \/* TK_REGISTER: original value of Expr.op$/;" m struct:Expr file: +opIterNext testdocs/sqlite3.c /^static Op *opIterNext(VdbeOpIter *p){$/;" f file: +opMask testdocs/sqlite3.c /^ u32 opMask; \/* Acceptable operators *\/$/;" m struct:WhereScan file: +opPrecedence testdocs/sqlite3.c /^static int opPrecedence(Fts3Expr *p){$/;" f file: +opcode testdocs/sqlite3.c /^ u8 opcode; \/* What operation to perform *\/$/;" m struct:VdbeOp file: +opcode testdocs/sqlite3.c /^ u8 opcode; \/* What operation to perform *\/$/;" m struct:VdbeOpList file: +open testdocs/sqlite3.c /^ int (*open)(const char*,sqlite3**);$/;" m struct:sqlite3_api_routines file: +open16 testdocs/sqlite3.c /^ int (*open16)(const void*,sqlite3**);$/;" m struct:sqlite3_api_routines file: +openDatabase testdocs/sqlite3.c /^static int openDatabase($/;" f file: +openDirectory testdocs/sqlite3.c /^static int openDirectory(const char *zFilename, int *pFd){$/;" f file: +openFlags testdocs/sqlite3.c /^ int openFlags; \/* The flags specified at open() *\/$/;" m struct:unixFile file: +openFlags testdocs/sqlite3.c /^ int openFlags; \/* Flags this file was opened with *\/$/;" m struct:rbu_file file: +openFlags testdocs/sqlite3.c /^ u8 openFlags; \/* Flags to sqlite3BtreeOpen() *\/$/;" m struct:BtShared file: +openFlags testdocs/sqlite3.c /^ unsigned int openFlags; \/* Flags passed to sqlite3_vfs.xOpen() *\/$/;" m struct:sqlite3 file: +openRbuHandle testdocs/sqlite3.c /^static sqlite3rbu *openRbuHandle($/;" f file: +openStatTable testdocs/sqlite3.c /^static void openStatTable($/;" f file: +openSubJournal testdocs/sqlite3.c /^static int openSubJournal(Pager *pPager){$/;" f file: +open_v2 testdocs/sqlite3.c /^ int (*open_v2)(const char*,sqlite3**,int,const char*);$/;" m struct:sqlite3_api_routines file: +operatorMask testdocs/sqlite3.c /^static u16 operatorMask(int op){$/;" f file: +optimalReserve testdocs/sqlite3.c /^ u8 optimalReserve; \/* Desired amount of reserved space per page *\/$/;" m struct:BtShared file: +orconf testdocs/sqlite3.c /^ int orconf; \/* Default ON CONFLICT policy *\/$/;" m struct:TriggerPrg file: +orconf testdocs/sqlite3.c /^ u8 orconf; \/* OE_Rollback etc. *\/$/;" m struct:TriggerStep file: +orderByConsumed testdocs/sqlite3.c /^ int orderByConsumed; \/* True if output is already ordered *\/$/;" m struct:sqlite3_index_info file: +orphanTrigger testdocs/sqlite3.c /^ u8 orphanTrigger; \/* Last statement is orphaned TEMP trigger *\/$/;" m struct:sqlite3::sqlite3InitInfo file: +os testdocs/waf /^import os, sys, inspect$/;" i +osAccess testdocs/sqlite3.c /^#define osAccess /;" d file: +osAreFileApisANSI testdocs/sqlite3.c /^# define osAreFileApisANSI(/;" d file: +osAreFileApisANSI testdocs/sqlite3.c /^#define osAreFileApisANSI /;" d file: +osCharLowerW testdocs/sqlite3.c /^#define osCharLowerW /;" d file: +osCharUpperW testdocs/sqlite3.c /^#define osCharUpperW /;" d file: +osClose testdocs/sqlite3.c /^#define osClose /;" d file: +osCloseHandle testdocs/sqlite3.c /^#define osCloseHandle /;" d file: +osCreateEventExW testdocs/sqlite3.c /^#define osCreateEventExW /;" d file: +osCreateFile2 testdocs/sqlite3.c /^#define osCreateFile2 /;" d file: +osCreateFileA testdocs/sqlite3.c /^#define osCreateFileA /;" d file: +osCreateFileMappingA testdocs/sqlite3.c /^#define osCreateFileMappingA /;" d file: +osCreateFileMappingFromApp testdocs/sqlite3.c /^#define osCreateFileMappingFromApp /;" d file: +osCreateFileMappingW testdocs/sqlite3.c /^#define osCreateFileMappingW /;" d file: +osCreateFileW testdocs/sqlite3.c /^#define osCreateFileW /;" d file: +osCreateMutexW testdocs/sqlite3.c /^#define osCreateMutexW /;" d file: +osDeleteFileA testdocs/sqlite3.c /^#define osDeleteFileA /;" d file: +osDeleteFileW testdocs/sqlite3.c /^#define osDeleteFileW /;" d file: +osFallocate testdocs/sqlite3.c /^#define osFallocate /;" d file: +osFchmod testdocs/sqlite3.c /^#define osFchmod /;" d file: +osFchown testdocs/sqlite3.c /^#define osFchown /;" d file: +osFcntl testdocs/sqlite3.c /^#define osFcntl /;" d file: +osFcntl testdocs/sqlite3.c /^#undef osFcntl$/;" d file: +osFileTimeToLocalFileTime testdocs/sqlite3.c /^#define osFileTimeToLocalFileTime /;" d file: +osFileTimeToSystemTime testdocs/sqlite3.c /^#define osFileTimeToSystemTime /;" d file: +osFlushFileBuffers testdocs/sqlite3.c /^#define osFlushFileBuffers /;" d file: +osFlushViewOfFile testdocs/sqlite3.c /^#define osFlushViewOfFile /;" d file: +osFormatMessageA testdocs/sqlite3.c /^#define osFormatMessageA /;" d file: +osFormatMessageW testdocs/sqlite3.c /^#define osFormatMessageW /;" d file: +osFreeLibrary testdocs/sqlite3.c /^#define osFreeLibrary /;" d file: +osFstat testdocs/sqlite3.c /^#define osFstat(/;" d file: +osFtruncate testdocs/sqlite3.c /^#define osFtruncate /;" d file: +osGetCurrentProcessId testdocs/sqlite3.c /^#define osGetCurrentProcessId /;" d file: +osGetDiskFreeSpaceA testdocs/sqlite3.c /^#define osGetDiskFreeSpaceA /;" d file: +osGetDiskFreeSpaceW testdocs/sqlite3.c /^#define osGetDiskFreeSpaceW /;" d file: +osGetFileAttributesA testdocs/sqlite3.c /^#define osGetFileAttributesA /;" d file: +osGetFileAttributesExW testdocs/sqlite3.c /^#define osGetFileAttributesExW /;" d file: +osGetFileAttributesW testdocs/sqlite3.c /^#define osGetFileAttributesW /;" d file: +osGetFileInformationByHandleEx testdocs/sqlite3.c /^#define osGetFileInformationByHandleEx /;" d file: +osGetFileSize testdocs/sqlite3.c /^#define osGetFileSize /;" d file: +osGetFullPathNameA testdocs/sqlite3.c /^#define osGetFullPathNameA /;" d file: +osGetFullPathNameW testdocs/sqlite3.c /^#define osGetFullPathNameW /;" d file: +osGetLastError testdocs/sqlite3.c /^#define osGetLastError /;" d file: +osGetNativeSystemInfo testdocs/sqlite3.c /^#define osGetNativeSystemInfo /;" d file: +osGetProcAddressA testdocs/sqlite3.c /^#define osGetProcAddressA /;" d file: +osGetProcessHeap testdocs/sqlite3.c /^#define osGetProcessHeap /;" d file: +osGetSystemInfo testdocs/sqlite3.c /^#define osGetSystemInfo /;" d file: +osGetSystemTime testdocs/sqlite3.c /^#define osGetSystemTime /;" d file: +osGetSystemTimeAsFileTime testdocs/sqlite3.c /^#define osGetSystemTimeAsFileTime /;" d file: +osGetTempPathA testdocs/sqlite3.c /^#define osGetTempPathA /;" d file: +osGetTempPathW testdocs/sqlite3.c /^#define osGetTempPathW /;" d file: +osGetTickCount testdocs/sqlite3.c /^#define osGetTickCount /;" d file: +osGetTickCount64 testdocs/sqlite3.c /^#define osGetTickCount64 /;" d file: +osGetVersionExA testdocs/sqlite3.c /^#define osGetVersionExA /;" d file: +osGetVersionExW testdocs/sqlite3.c /^#define osGetVersionExW /;" d file: +osGetcwd testdocs/sqlite3.c /^#define osGetcwd /;" d file: +osGeteuid testdocs/sqlite3.c /^#define osGeteuid /;" d file: +osGetpagesize testdocs/sqlite3.c /^#define osGetpagesize /;" d file: +osGetpid testdocs/sqlite3.c /^#define osGetpid(/;" d file: +osHeapAlloc testdocs/sqlite3.c /^#define osHeapAlloc /;" d file: +osHeapCompact testdocs/sqlite3.c /^#define osHeapCompact /;" d file: +osHeapCreate testdocs/sqlite3.c /^#define osHeapCreate /;" d file: +osHeapDestroy testdocs/sqlite3.c /^#define osHeapDestroy /;" d file: +osHeapFree testdocs/sqlite3.c /^#define osHeapFree /;" d file: +osHeapReAlloc testdocs/sqlite3.c /^#define osHeapReAlloc /;" d file: +osHeapSize testdocs/sqlite3.c /^#define osHeapSize /;" d file: +osHeapValidate testdocs/sqlite3.c /^#define osHeapValidate /;" d file: +osInterlockedCompareExchange testdocs/sqlite3.c /^#define osInterlockedCompareExchange /;" d file: +osIsNT testdocs/sqlite3.c /^# define osIsNT(/;" d file: +osLoadLibraryA testdocs/sqlite3.c /^#define osLoadLibraryA /;" d file: +osLoadLibraryW testdocs/sqlite3.c /^#define osLoadLibraryW /;" d file: +osLoadPackagedLibrary testdocs/sqlite3.c /^#define osLoadPackagedLibrary /;" d file: +osLocalFree testdocs/sqlite3.c /^#define osLocalFree /;" d file: +osLocaltime testdocs/sqlite3.c /^static int osLocaltime(time_t *t, struct tm *pTm){$/;" f file: +osLockFile testdocs/sqlite3.c /^#define osLockFile /;" d file: +osLockFileEx testdocs/sqlite3.c /^#define osLockFileEx /;" d file: +osLstat testdocs/sqlite3.c /^#define osLstat /;" d file: +osMapViewOfFile testdocs/sqlite3.c /^#define osMapViewOfFile /;" d file: +osMapViewOfFileFromApp testdocs/sqlite3.c /^#define osMapViewOfFileFromApp /;" d file: +osMkdir testdocs/sqlite3.c /^#define osMkdir /;" d file: +osMmap testdocs/sqlite3.c /^#define osMmap /;" d file: +osMremap testdocs/sqlite3.c /^#define osMremap /;" d file: +osMultiByteToWideChar testdocs/sqlite3.c /^#define osMultiByteToWideChar /;" d file: +osMunmap testdocs/sqlite3.c /^#define osMunmap /;" d file: +osOpen testdocs/sqlite3.c /^#define osOpen /;" d file: +osOpenDirectory testdocs/sqlite3.c /^#define osOpenDirectory /;" d file: +osOutputDebugStringA testdocs/sqlite3.c /^#define osOutputDebugStringA /;" d file: +osOutputDebugStringW testdocs/sqlite3.c /^#define osOutputDebugStringW /;" d file: +osPread testdocs/sqlite3.c /^#define osPread /;" d file: +osPread64 testdocs/sqlite3.c /^#define osPread64 /;" d file: +osPwrite testdocs/sqlite3.c /^#define osPwrite /;" d file: +osPwrite64 testdocs/sqlite3.c /^#define osPwrite64 /;" d file: +osQueryPerformanceCounter testdocs/sqlite3.c /^#define osQueryPerformanceCounter /;" d file: +osRead testdocs/sqlite3.c /^#define osRead /;" d file: +osReadFile testdocs/sqlite3.c /^#define osReadFile /;" d file: +osReadlink testdocs/sqlite3.c /^#define osReadlink /;" d file: +osRmdir testdocs/sqlite3.c /^#define osRmdir /;" d file: +osSetEndOfFile testdocs/sqlite3.c /^#define osSetEndOfFile /;" d file: +osSetFilePointer testdocs/sqlite3.c /^#define osSetFilePointer /;" d file: +osSetFilePointerEx testdocs/sqlite3.c /^#define osSetFilePointerEx /;" d file: +osSleep testdocs/sqlite3.c /^#define osSleep /;" d file: +osStat testdocs/sqlite3.c /^#define osStat /;" d file: +osSystemTimeToFileTime testdocs/sqlite3.c /^#define osSystemTimeToFileTime /;" d file: +osUnlink testdocs/sqlite3.c /^#define osUnlink /;" d file: +osUnlockFile testdocs/sqlite3.c /^#define osUnlockFile /;" d file: +osUnlockFileEx testdocs/sqlite3.c /^#define osUnlockFileEx /;" d file: +osUnmapViewOfFile testdocs/sqlite3.c /^#define osUnmapViewOfFile /;" d file: +osUuidCreate testdocs/sqlite3.c /^#define osUuidCreate /;" d file: +osUuidCreateSequential testdocs/sqlite3.c /^#define osUuidCreateSequential /;" d file: +osWaitForSingleObject testdocs/sqlite3.c /^#define osWaitForSingleObject /;" d file: +osWaitForSingleObjectEx testdocs/sqlite3.c /^#define osWaitForSingleObjectEx /;" d file: +osWideCharToMultiByte testdocs/sqlite3.c /^#define osWideCharToMultiByte /;" d file: +osWrite testdocs/sqlite3.c /^#define osWrite /;" d file: +osWriteFile testdocs/sqlite3.c /^#define osWriteFile /;" d file: +out2Prerelease testdocs/sqlite3.c /^static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){$/;" f file: +out2PrereleaseWithClear testdocs/sqlite3.c /^static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){$/;" f file: +overflow testdocs/sqlite3.c /^ u8 overflow; \/* True if integer overflow seen *\/$/;" m struct:SumCtx file: +overload_function testdocs/sqlite3.c /^ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);$/;" m struct:sqlite3_api_routines file: +owner testdocs/sqlite3.c /^ volatile DWORD owner; \/* Thread holding this mutex *\/$/;" m struct:sqlite3_mutex file: +owner testdocs/sqlite3.c /^ volatile pthread_t owner; \/* Thread that is within this mutex *\/$/;" m struct:sqlite3_mutex file: +p testdocs/sqlite3.c /^ void *p; \/* Generic pointer *\/$/;" m union:VdbeOp::p4union file: +p testdocs/sqlite3.c /^ const char *p; \/* Token text (not NULL terminated) *\/$/;" m struct:Fts5Token file: +p testdocs/sqlite3.c /^ u8 *p; \/* Pointer to buffer containing record *\/$/;" m struct:Fts5Data file: +p testdocs/sqlite3.c /^ u8 *p;$/;" m struct:Fts5Buffer file: +p testdocs/sqlite3.c /^ void *p; \/* Pointer to sampled record *\/$/;" m struct:IndexSample file: +p1 testdocs/sqlite3.c /^ int p1, p2; \/* Operands of the opcode used to ends the loop *\/$/;" m struct:WhereLevel file: +p1 testdocs/sqlite3.c /^ int p1; \/* First operand *\/$/;" m struct:VdbeOp file: +p1 testdocs/sqlite3.c /^ signed char p1; \/* First operand *\/$/;" m struct:VdbeOpList file: +p2 testdocs/sqlite3.c /^ int p1, p2; \/* Operands of the opcode used to ends the loop *\/$/;" m struct:WhereLevel file: +p2 testdocs/sqlite3.c /^ int p2; \/* Second parameter (often the jump destination) *\/$/;" m struct:VdbeOp file: +p2 testdocs/sqlite3.c /^ signed char p2; \/* Second parameter (often the jump destination) *\/$/;" m struct:VdbeOpList file: +p3 testdocs/sqlite3.c /^ int p3; \/* The third parameter *\/$/;" m struct:VdbeOp file: +p3 testdocs/sqlite3.c /^ signed char p3; \/* Third parameter *\/$/;" m struct:VdbeOpList file: +p3 testdocs/sqlite3.c /^ u8 op, p3, p5; \/* Opcode, P3 & P5 of the opcode that ends the loop *\/$/;" m struct:WhereLevel file: +p4 testdocs/sqlite3.c /^ } p4;$/;" m struct:VdbeOp typeref:union:VdbeOp::p4union file: +p4type testdocs/sqlite3.c /^ signed char p4type; \/* One of the P4_xxx constants for p4 *\/$/;" m struct:VdbeOp file: +p4union testdocs/sqlite3.c /^ union p4union { \/* fourth parameter *\/$/;" u struct:VdbeOp file: +p5 testdocs/sqlite3.c /^ u16 p5; \/* Fifth parameter is an unsigned 16-bit integer *\/$/;" m struct:VdbeOp file: +p5 testdocs/sqlite3.c /^ u8 op, p3, p5; \/* Opcode, P3 & P5 of the opcode that ends the loop *\/$/;" m struct:WhereLevel file: +pAggInfo testdocs/sqlite3.c /^ AggInfo *pAggInfo; \/* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION *\/$/;" m struct:Expr file: +pAggInfo testdocs/sqlite3.c /^ AggInfo *pAggInfo; \/* Information about aggregates at this level *\/$/;" m struct:NameContext file: +pAinc testdocs/sqlite3.c /^ AutoincInfo *pAinc; \/* Information about AUTOINCREMENT counters *\/$/;" m struct:Parse file: +pAltCursor testdocs/sqlite3.c /^ VdbeCursor *pAltCursor; \/* Associated index cursor from which to read *\/$/;" m struct:VdbeCursor file: +pAndInfo testdocs/sqlite3.c /^ WhereAndInfo *pAndInfo; \/* Extra information if (eOperator& WO_AND)!=0 *\/$/;" m union:WhereTerm::__anon32 file: +pApi testdocs/sqlite3.c /^ const Fts5ExtensionApi *pApi; \/* API offered by current FTS version *\/$/;" m struct:CInstIter file: +pAppData testdocs/sqlite3.c /^ void *pAppData; \/* The extra pAppData, if any. *\/$/;" m struct:winVfsAppData file: +pAppData testdocs/sqlite3.c /^ void *pAppData; \/* Argument to xInit() and xShutdown() *\/$/;" m struct:sqlite3_mem_methods file: +pAppData testdocs/sqlite3.c /^ void *pAppData; \/* Pointer to application-specific data *\/$/;" m struct:sqlite3_vfs file: +pArg testdocs/sqlite3.c /^ void *pArg; \/* First arg to busy callback *\/$/;" m struct:BusyHandler file: +pArg testdocs/sqlite3.c /^ void *pArg;$/;" m struct:sqlite3_pcache_methods file: +pArg testdocs/sqlite3.c /^ void *pArg;$/;" m struct:sqlite3_pcache_methods2 file: +pAuthArg testdocs/sqlite3.c /^ void *pAuthArg; \/* 1st argument to the access auth function *\/$/;" m struct:sqlite3 file: +pAux testdocs/sqlite3.c /^ Fts5Auxiliary *pAux; \/* Currently executing extension function *\/$/;" m struct:Fts5Cursor file: +pAux testdocs/sqlite3.c /^ Fts5Auxiliary *pAux; \/* Extension to which this belongs *\/$/;" m struct:Fts5Auxdata file: +pAux testdocs/sqlite3.c /^ Fts5Auxiliary *pAux; \/* First in list of all aux. functions *\/$/;" m struct:Fts5Global file: +pAux testdocs/sqlite3.c /^ void *pAux; \/* pAux passed to create_module() *\/$/;" m struct:Module file: +pAux testdocs/sqlite3.c /^ void *pAux; \/* Aux data pointer *\/$/;" m struct:AuxData file: +pAuxData testdocs/sqlite3.c /^ AuxData *pAuxData; \/* Linked list of auxdata allocations *\/$/;" m struct:Vdbe file: +pAuxData testdocs/sqlite3.c /^ AuxData *pAuxData; \/* Linked list of auxdata allocations *\/$/;" m struct:VdbeFrame file: +pAuxdata testdocs/sqlite3.c /^ Fts5Auxdata *pAuxdata; \/* First in linked list of saved aux-data *\/$/;" m struct:Fts5Cursor file: +pBackup testdocs/sqlite3.c /^ sqlite3_backup *pBackup; \/* Pointer to list of ongoing backup processes *\/$/;" m struct:Pager file: +pBlob testdocs/sqlite3.c /^ sqlite3_blob *pBlob; \/* If not NULL, blob handle to read node *\/$/;" m struct:Fts3SegReader file: +pBlockingConnection testdocs/sqlite3.c /^ sqlite3 *pBlockingConnection; \/* Connection that caused SQLITE_LOCKED *\/$/;" m struct:sqlite3 file: +pBt testdocs/sqlite3.c /^ BtShared *pBt; \/* The BtShared this cursor points to *\/$/;" m struct:BtCursor file: +pBt testdocs/sqlite3.c /^ BtShared *pBt; \/* Pointer to BtShared that this page is part of *\/$/;" m struct:MemPage file: +pBt testdocs/sqlite3.c /^ BtShared *pBt; \/* Sharable content of this btree *\/$/;" m struct:Btree file: +pBt testdocs/sqlite3.c /^ BtShared *pBt; \/* The tree being checked out *\/$/;" m struct:IntegrityCk file: +pBt testdocs/sqlite3.c /^ Btree *pBt; \/* The B*Tree structure for this database file *\/$/;" m struct:Db file: +pBtree testdocs/sqlite3.c /^ Btree *pBtree; \/* The Btree to which this cursor belongs *\/$/;" m struct:BtCursor file: +pBtree testdocs/sqlite3.c /^ Btree *pBtree; \/* Btree handle holding this lock *\/$/;" m struct:BtLock file: +pBtx testdocs/sqlite3.c /^ Btree *pBtx; \/* Separate file holding temporary table *\/$/;" m struct:VdbeCursor file: +pBuf testdocs/sqlite3.c /^ Fts5Buffer *pBuf; \/* Append to this buffer *\/$/;" m struct:PoslistCallbackCtx file: +pBuf testdocs/sqlite3.c /^ Fts5Buffer *pBuf; \/* Append to this buffer *\/$/;" m struct:PoslistOffsetsCtx file: +pBuf testdocs/sqlite3.c /^ void *pBuf; \/* The content of the page *\/$/;" m struct:sqlite3_pcache_page file: +pBulk testdocs/sqlite3.c /^ void *pBulk; \/* Bulk memory used by pcache-local *\/$/;" m struct:PCache1 file: +pBusyHandlerArg testdocs/sqlite3.c /^ void *pBusyHandlerArg; \/* Context argument for xBusyHandler *\/$/;" m struct:Pager file: +pCCurHint testdocs/sqlite3.c /^ struct CCurHint *pCCurHint; \/* Used by codeCursorHint() *\/$/;" m union:Walker::__anon17 typeref:struct:Walker::__anon17::CCurHint file: +pCache testdocs/sqlite3.c /^ PCache *pCache; \/* Cache that owns this page *\/$/;" m struct:PgHdr file: +pCache testdocs/sqlite3.c /^ PCache1 *pCache; \/* Cache that currently owns this page *\/$/;" m struct:PgHdr1 file: +pCache testdocs/sqlite3.c /^ sqlite3_pcache *pCache; \/* Pluggable cache module *\/$/;" m struct:PCache file: +pCheck testdocs/sqlite3.c /^ ExprList *pCheck; \/* All CHECK constraints *\/$/;" m struct:Table file: +pChunk testdocs/sqlite3.c /^ FileChunk *pChunk; \/* Specific chunk into which cursor points *\/$/;" m struct:FilePoint file: +pChunk testdocs/sqlite3.c /^ struct RowSetChunk *pChunk; \/* List of all chunk allocations *\/$/;" m struct:RowSet typeref:struct:RowSet::RowSetChunk file: +pCodec testdocs/sqlite3.c /^ void *pCodec; \/* First argument to xCodec... methods *\/$/;" m struct:Pager file: +pColl testdocs/sqlite3.c /^ CollSeq *pColl; \/* Used when p4type is P4_COLLSEQ *\/$/;" m union:VdbeOp::p4union file: +pCollNeededArg testdocs/sqlite3.c /^ void *pCollNeededArg;$/;" m struct:sqlite3 file: +pCols testdocs/sqlite3.c /^ ExprList *pCols; \/* List of explicit column names, or NULL *\/$/;" m struct:With::Cte file: +pColset testdocs/sqlite3.c /^ Fts5Colset *pColset; \/* Columns to search (NULL -> all columns) *\/$/;" m struct:Fts5ExprNearset file: +pColset testdocs/sqlite3.c /^ Fts5Colset *pColset; \/* Restrict matches to these columns *\/$/;" m struct:Fts5Iter file: +pColset testdocs/sqlite3.c /^ Fts5Colset *pColset; \/* Restrict matches to this column *\/$/;" m struct:PoslistCallbackCtx file: +pColset testdocs/sqlite3.c /^ Fts5Colset *pColset; \/* Restrict matches to this column *\/$/;" m struct:PoslistOffsetsCtx file: +pColumns testdocs/sqlite3.c /^ IdList *pColumns; \/* If this is an UPDATE OF trigger,$/;" m struct:Trigger file: +pCommitArg testdocs/sqlite3.c /^ void *pCommitArg; \/* Argument to xCommitCallback() *\/$/;" m struct:sqlite3 file: +pConfig testdocs/sqlite3.c /^ Fts5Config *pConfig; \/* Fts5 table configuration *\/$/;" m struct:Fts5VocabCursor file: +pConfig testdocs/sqlite3.c /^ Fts5Config *pConfig; \/* Virtual table configuration *\/$/;" m struct:Fts5Index file: +pConfig testdocs/sqlite3.c /^ Fts5Config *pConfig; \/* Virtual table configuration *\/$/;" m struct:Fts5Table file: +pConfig testdocs/sqlite3.c /^ Fts5Config *pConfig;$/;" m struct:Fts5Expr file: +pConfig testdocs/sqlite3.c /^ Fts5Config *pConfig;$/;" m struct:Fts5IntegrityCtx file: +pConfig testdocs/sqlite3.c /^ Fts5Config *pConfig;$/;" m struct:Fts5Parse file: +pConfig testdocs/sqlite3.c /^ Fts5Config *pConfig;$/;" m struct:Fts5Storage file: +pConflict testdocs/sqlite3.c /^ sqlite3_stmt *pConflict; \/* Points to conflicting row, if any *\/$/;" m struct:sqlite3_changeset_iter file: +pConstExpr testdocs/sqlite3.c /^ ExprList *pConstExpr;\/* Constant expressions *\/$/;" m struct:Parse file: +pContext testdocs/sqlite3.c /^ void *pContext; \/* pContext from when function registered *\/$/;" m struct:sqlite3_rtree_query_info file: +pContext testdocs/sqlite3.c /^ void *pContext; \/* Copy of pContext passed to s_r_g_c() *\/$/;" m struct:sqlite3_rtree_geometry file: +pContext testdocs/sqlite3.c /^ void *pContext;$/;" m struct:RtreeGeomCallback file: +pCovidx testdocs/sqlite3.c /^ Index *pCovidx; \/* Possible covering index for WHERE_MULTI_OR *\/$/;" m union:WhereLevel::__anon27 file: +pCsr testdocs/sqlite3.c /^ BtCursor *pCsr; \/* Cursor pointing at blob row *\/$/;" m struct:Incrblob file: +pCsr testdocs/sqlite3.c /^ Fts3Cursor *pCsr; \/* Cursor snippet is being generated from *\/$/;" m struct:SnippetIter file: +pCsr testdocs/sqlite3.c /^ Fts3Cursor *pCsr; \/* FTS3 Cursor *\/$/;" m struct:LoadDoclistCtx file: +pCsr testdocs/sqlite3.c /^ Fts3Cursor *pCsr;$/;" m struct:TermOffsetCtx file: +pCsr testdocs/sqlite3.c /^ Fts5Cursor *pCsr; \/* First in list of all open cursors *\/$/;" m struct:Fts5Global file: +pCsr testdocs/sqlite3.c /^ VdbeCursor *pCsr; \/* Cursor to read old values from *\/$/;" m struct:PreUpdate file: +pCsr testdocs/sqlite3.c /^ sqlite3_tokenizer_cursor *pCsr; \/* Cursor to iterate through zInput *\/$/;" m struct:Fts3tokCursor file: +pCtx testdocs/sqlite3.c /^ sqlite3_context *pCtx; \/* Used when p4type is P4_FUNCCTX *\/$/;" m union:VdbeOp::p4union file: +pCtx testdocs/sqlite3.c /^ sqlite3_context *pCtx; \/* Write error message here *\/$/;" m struct:ParseContext file: +pCtx testdocs/sqlite3.c /^ sqlite3_context *pCtx; \/* Function context - put error messages here *\/$/;" m struct:JsonString file: +pCtx testdocs/sqlite3.c /^ void *pCtx;$/;" m struct:PorterContext file: +pCtx testdocs/sqlite3.c /^ void *pCtx;$/;" m struct:SessionHook file: +pCurrent testdocs/sqlite3.c /^ sqlite3_syscall_ptr pCurrent; \/* Current value of the system call *\/$/;" m struct:unix_syscall file: +pCurrent testdocs/sqlite3.c /^ sqlite3_syscall_ptr pCurrent; \/* Current value of the system call *\/$/;" m struct:win_syscall file: +pCursor testdocs/sqlite3.c /^ BtCursor *pCursor; \/* CURTYPE_BTREE. Btree cursor *\/$/;" m union:VdbeCursor::__anon18 file: +pCursor testdocs/sqlite3.c /^ BtCursor *pCursor; \/* A list of all open cursors *\/$/;" m struct:BtShared file: +pCursor testdocs/sqlite3.c /^ Fts3Cursor *pCursor; \/* FTS3 Cursor *\/$/;" m struct:MatchInfo file: +pData testdocs/sqlite3.c /^ Fts5Data *pData; \/* Data for current page of this level *\/$/;" m struct:Fts5DlidxLvl file: +pData testdocs/sqlite3.c /^ const u8 *pData;$/;" m struct:Fts5IndexIter file: +pData testdocs/sqlite3.c /^ const void *pData; \/* Data for tables. NULL for indexes *\/$/;" m struct:BtreePayload file: +pData testdocs/sqlite3.c /^ void *pData; \/* Page data *\/$/;" m struct:PgHdr file: +pDataVersion testdocs/sqlite3.c /^ sqlite3_stmt *pDataVersion;$/;" m struct:Fts5Index file: +pDbFd testdocs/sqlite3.c /^ sqlite3_file *pDbFd; \/* File handle for the database file *\/$/;" m struct:Wal file: +pDbPage testdocs/sqlite3.c /^ DbPage *pDbPage; \/* Pager page handle *\/$/;" m struct:MemPage file: +pDef testdocs/sqlite3.c /^ FuncDef *pDef; \/* Used only when flags==MEM_Agg *\/$/;" m union:sqlite3_value::MemValue file: +pDefault testdocs/sqlite3.c /^ sqlite3_syscall_ptr pDefault; \/* Default value *\/$/;" m struct:unix_syscall file: +pDefault testdocs/sqlite3.c /^ sqlite3_syscall_ptr pDefault; \/* Default value *\/$/;" m struct:win_syscall file: +pDeferred testdocs/sqlite3.c /^ Fts3DeferredToken *pDeferred; \/* Deferred search tokens, if any *\/$/;" m struct:Fts3Cursor file: +pDeferred testdocs/sqlite3.c /^ Fts3DeferredToken *pDeferred; \/* Deferred token object for this token *\/$/;" m struct:Fts3PhraseToken file: +pDelFrame testdocs/sqlite3.c /^ VdbeFrame *pDelFrame; \/* List of frame objects to free on VM reset *\/$/;" m struct:Vdbe file: +pDelete testdocs/sqlite3.c /^ sqlite3_stmt *pDelete; \/* DELETE statement *\/$/;" m struct:SessionApplyCtx file: +pDelete testdocs/sqlite3.c /^ sqlite3_stmt *pDelete; \/* Statement for DELETE ops *\/$/;" m struct:RbuObjIter file: +pDeleteNode testdocs/sqlite3.c /^ sqlite3_stmt *pDeleteNode;$/;" m struct:Rtree file: +pDeleteParent testdocs/sqlite3.c /^ sqlite3_stmt *pDeleteParent;$/;" m struct:Rtree file: +pDeleteRowid testdocs/sqlite3.c /^ sqlite3_stmt *pDeleteRowid;$/;" m struct:Rtree file: +pDeleted testdocs/sqlite3.c /^ RtreeNode *pDeleted;$/;" m struct:Rtree file: +pDeleter testdocs/sqlite3.c /^ sqlite3_stmt *pDeleter; \/* "DELETE FROM %_data ... id>=? AND id<=?" *\/$/;" m struct:Fts5Index file: +pDest testdocs/sqlite3.c /^ Btree *pDest; \/* Destination b-tree file *\/$/;" m struct:sqlite3_backup file: +pDestDb testdocs/sqlite3.c /^ sqlite3* pDestDb; \/* Destination database handle *\/$/;" m struct:sqlite3_backup file: +pDestructor testdocs/sqlite3.c /^ FuncDestructor *pDestructor; \/* Reference counted destructor function *\/$/;" m union:FuncDef::__anon9 file: +pDflt testdocs/sqlite3.c /^ Expr *pDflt; \/* Default value of this column *\/$/;" m struct:Column file: +pDfltColl testdocs/sqlite3.c /^ CollSeq *pDfltColl; \/* The default collating sequence (BINARY) *\/$/;" m struct:sqlite3 file: +pDfltTok testdocs/sqlite3.c /^ Fts5TokenizerModule *pDfltTok; \/* Default tokenizer module *\/$/;" m struct:Fts5Global file: +pDirty testdocs/sqlite3.c /^ PgHdr *pDirty, *pDirtyTail; \/* List of dirty pages in LRU order *\/$/;" m struct:PCache file: +pDirty testdocs/sqlite3.c /^ PgHdr *pDirty; \/* Transient list of dirty sorted by pgno *\/$/;" m struct:PgHdr file: +pDirtyNext testdocs/sqlite3.c /^ PgHdr *pDirtyNext; \/* Next element in list of dirty pages *\/$/;" m struct:PgHdr file: +pDirtyPrev testdocs/sqlite3.c /^ PgHdr *pDirtyPrev; \/* Previous element in list of dirty pages *\/$/;" m struct:PgHdr file: +pDirtyTail testdocs/sqlite3.c /^ PgHdr *pDirty, *pDirtyTail; \/* List of dirty pages in LRU order *\/$/;" m struct:PCache file: +pDisconnect testdocs/sqlite3.c /^ VTable *pDisconnect; \/* Disconnect these in next sqlite3_prepare() *\/$/;" m struct:sqlite3 file: +pDlidx testdocs/sqlite3.c /^ Fts5DlidxIter *pDlidx; \/* If there is a doclist-index *\/$/;" m struct:Fts5SegIter file: +pEList testdocs/sqlite3.c /^ ExprList *pEList; \/* Replacement expressions *\/$/;" m struct:SubstContext file: +pEList testdocs/sqlite3.c /^ ExprList *pEList; \/* The fields of the result *\/$/;" m struct:Select file: +pEList testdocs/sqlite3.c /^ ExprList *pEList; \/* Optional list of result-set columns *\/$/;" m struct:NameContext file: +pEnd testdocs/sqlite3.c /^ void *pEnd; \/* First byte past end of available space *\/$/;" m struct:Lookaside file: +pEnd testdocs/sqlite3.c /^ void *pStart, *pEnd; \/* Bounds of global page cache memory *\/$/;" m struct:PCacheGlobal file: +pEntry testdocs/sqlite3.c /^ struct RowSetEntry *pEntry; \/* List of entries using pRight *\/$/;" m struct:RowSet typeref:struct:RowSet::RowSetEntry file: +pEpoTab testdocs/sqlite3.c /^ Table *pEpoTab; \/* Eponymous table for this module *\/$/;" m struct:Module file: +pErr testdocs/sqlite3.c /^ sqlite3_value *pErr; \/* Most recent error message *\/$/;" m struct:sqlite3 file: +pExpr testdocs/sqlite3.c /^ Expr *pExpr; \/* Expression encoding the function *\/$/;" m struct:AggInfo::AggInfo_func file: +pExpr testdocs/sqlite3.c /^ Expr *pExpr; \/* The original expression *\/$/;" m struct:AggInfo::AggInfo_col file: +pExpr testdocs/sqlite3.c /^ Expr *pExpr; \/* The parse tree for this expression *\/$/;" m struct:ExprList::ExprList_item file: +pExpr testdocs/sqlite3.c /^ Expr *pExpr; \/* Used when p4type is P4_EXPR *\/$/;" m union:VdbeOp::p4union file: +pExpr testdocs/sqlite3.c /^ Expr *pExpr; \/* Pointer to the subexpression that is this term *\/$/;" m struct:WhereTerm file: +pExpr testdocs/sqlite3.c /^ Expr *pExpr; \/* The expression parse tree *\/$/;" m struct:ExprSpan file: +pExpr testdocs/sqlite3.c /^ Fts3Expr *pExpr; \/* Parsed MATCH query string *\/$/;" m struct:Fts3Cursor file: +pExpr testdocs/sqlite3.c /^ Fts3Expr *pExpr; \/* Pointer to phrase expression *\/$/;" m struct:LcsIterator file: +pExpr testdocs/sqlite3.c /^ Fts5Expr *pExpr; \/* Expression for MATCH queries *\/$/;" m struct:Fts5Cursor file: +pExpr testdocs/sqlite3.c /^ Fts5Expr *pExpr;$/;" m struct:Fts5ExprCtx file: +pExpr testdocs/sqlite3.c /^ Fts5ExprNode *pExpr; \/* Result of a successful parse *\/$/;" m struct:Fts5Parse file: +pExprList testdocs/sqlite3.c /^ ExprList *pExprList; \/* SET clause for UPDATE. *\/$/;" m struct:TriggerStep file: +pExtra testdocs/sqlite3.c /^ void *pExtra; \/* Extra content *\/$/;" m struct:PgHdr file: +pExtra testdocs/sqlite3.c /^ void *pExtra; \/* Extra information associated with the page *\/$/;" m struct:sqlite3_pcache_page file: +pFKey testdocs/sqlite3.c /^ FKey *pFKey; \/* Linked list of all foreign keys in this table *\/$/;" m struct:Table file: +pFd testdocs/sqlite3.c /^ sqlite3_file *pFd; \/* File handle *\/$/;" m struct:SorterFile file: +pFd testdocs/sqlite3.c /^ sqlite3_file *pFd; \/* File handle to write to *\/$/;" m struct:PmaWriter file: +pFd testdocs/sqlite3.c /^ sqlite3_file *pFd; \/* The WAL file to which we write *\/$/;" m struct:WalWriter file: +pFd testdocs/sqlite3.c /^ sqlite3_file *pFd; \/* File handle we are reading from *\/$/;" m struct:PmaReader file: +pFiller testdocs/sqlite3.c /^ void *pFiller; \/* So that sizeof(Mem) is a multiple of 8 *\/$/;" m struct:sqlite3_value file: +pFilter testdocs/sqlite3.c /^ Fts3SegFilter *pFilter; \/* Pointer to filter object *\/$/;" m struct:Fts3MultiSegReader file: +pFilterCtx testdocs/sqlite3.c /^ void *pFilterCtx; \/* First argument to pass to xTableFilter *\/$/;" m struct:sqlite3_session file: +pFirst testdocs/sqlite3.c /^ FileChunk *pFirst; \/* Head of in-memory chunk-list *\/$/;" m struct:MemJournal file: +pFirst testdocs/sqlite3.c /^ struct MemBlockHdr *pFirst;$/;" m struct:__anon20 typeref:struct:__anon20::MemBlockHdr file: +pFirst testdocs/sqlite3.c /^ unixShm *pFirst; \/* All unixShm objects pointing to this *\/$/;" m struct:unixShmNode file: +pFirst testdocs/sqlite3.c /^ winShm *pFirst; \/* All winShm objects pointing to this *\/$/;" m struct:winShmNode file: +pForest testdocs/sqlite3.c /^ struct RowSetEntry *pForest; \/* List of binary trees of entries *\/$/;" m struct:RowSet typeref:struct:RowSet::RowSetEntry file: +pFrame testdocs/sqlite3.c /^ VdbeFrame *pFrame; \/* Used when flags==MEM_Frame *\/$/;" m union:sqlite3_value::MemValue file: +pFrame testdocs/sqlite3.c /^ VdbeFrame *pFrame; \/* Parent frame *\/$/;" m struct:Vdbe file: +pFree testdocs/sqlite3.c /^ LookasideSlot *pFree; \/* List of available buffers *\/$/;" m struct:Lookaside file: +pFree testdocs/sqlite3.c /^ PgFreeslot *pFree; \/* Free page blocks *\/$/;" m struct:PCacheGlobal file: +pFree testdocs/sqlite3.c /^ PgHdr1 *pFree; \/* List of unused pcache-local pages *\/$/;" m struct:PCache1 file: +pFree testdocs/sqlite3.c /^ void *pFree; \/* Free this when deleting the vdbe *\/$/;" m struct:Vdbe file: +pFresh testdocs/sqlite3.c /^ struct RowSetEntry *pFresh; \/* Source of new entry objects *\/$/;" m struct:RowSet typeref:struct:RowSet::RowSetEntry file: +pFrom testdocs/sqlite3.c /^ Table *pFrom; \/* Table containing the REFERENCES clause (aka: Child) *\/$/;" m struct:FKey file: +pFts testdocs/sqlite3.c /^ Fts5Context *pFts; \/* First arg to pass to pApi functions *\/$/;" m struct:CInstIter file: +pFts3Tab testdocs/sqlite3.c /^ Fts3Table *pFts3Tab;$/;" m struct:Fts3auxTable file: +pFunc testdocs/sqlite3.c /^ FuncDef *pFunc; \/* The aggregate function implementation *\/$/;" m struct:AggInfo::AggInfo_func file: +pFunc testdocs/sqlite3.c /^ FuncDef *pFunc; \/* Used when p4type is P4_FUNCDEF *\/$/;" m union:VdbeOp::p4union file: +pFunc testdocs/sqlite3.c /^ FuncDef *pFunc; \/* Pointer to function information *\/$/;" m struct:sqlite3_context file: +pFuncArg testdocs/sqlite3.c /^ ExprList *pFuncArg; \/* Arguments to table-valued-function *\/$/;" m union:SrcList::SrcList_item::__anon15 file: +pGlobal testdocs/sqlite3.c /^ Fts5Global *pGlobal; \/* FTS5 global object for this database *\/$/;" m struct:Fts5VocabTable file: +pGlobal testdocs/sqlite3.c /^ Fts5Global *pGlobal; \/* Global (connection wide) data *\/$/;" m struct:Fts5Table file: +pGlobal testdocs/sqlite3.c /^ Fts5Global *pGlobal; \/* Global context for this function *\/$/;" m struct:Fts5Auxiliary file: +pGroup testdocs/sqlite3.c /^ PGroup *pGroup; \/* PGroup this cache belongs to *\/$/;" m struct:PCache1 file: +pGroupBy testdocs/sqlite3.c /^ ExprList *pGroupBy; \/* GROUP BY clause *\/$/;" m union:Walker::__anon17 file: +pGroupBy testdocs/sqlite3.c /^ ExprList *pGroupBy; \/* The group by clause *\/$/;" m struct:AggInfo file: +pGroupBy testdocs/sqlite3.c /^ ExprList *pGroupBy; \/* The GROUP BY clause *\/$/;" m struct:Select file: +pGroupBy testdocs/sqlite3.c /^ ExprList *pGroupBy;$/;" m struct:HavingToWhereCtx file: +pHasContent testdocs/sqlite3.c /^ Bitvec *pHasContent; \/* Set of pages moved to free-list this transaction *\/$/;" m struct:BtShared file: +pHash testdocs/sqlite3.c /^ FuncDef *pHash; \/* Next with a different name but the same hash *\/$/;" m union:FuncDef::__anon9 file: +pHash testdocs/sqlite3.c /^ Fts5Hash *pHash; \/* Hash table for in-memory data *\/$/;" m struct:Fts5Index file: +pHashNext testdocs/sqlite3.c /^ Fts5HashEntry *pHashNext; \/* Next hash entry with same hash-key *\/$/;" m struct:Fts5HashEntry file: +pHaving testdocs/sqlite3.c /^ Expr *pHaving; \/* The HAVING clause *\/$/;" m struct:Select file: +pHavingCtx testdocs/sqlite3.c /^ struct HavingToWhereCtx *pHavingCtx; \/* HAVING to WHERE clause ctx *\/$/;" m union:Walker::__anon17 typeref:struct:Walker::__anon17::HavingToWhereCtx file: +pHead testdocs/sqlite3.c /^ char *pHead; \/* Position list data following iHead *\/$/;" m struct:SnippetPhrase file: +pHeap testdocs/sqlite3.c /^ void *pHeap; \/* Heap storage space *\/$/;" m struct:Sqlite3Config file: +pI64 testdocs/sqlite3.c /^ i64 *pI64; \/* Used when p4type is P4_INT64 *\/$/;" m union:VdbeOp::p4union file: +pIBIndex testdocs/sqlite3.c /^ Index *pIBIndex; \/* Index structure corresponding to u1.zIndexedBy *\/$/;" m struct:SrcList::SrcList_item file: +pId testdocs/sqlite3.c /^ struct vxworksFileId *pId; \/* Unique file ID *\/$/;" m struct:unixFile typeref:struct:unixFile::vxworksFileId file: +pId testdocs/sqlite3.c /^ struct vxworksFileId *pId; \/* Unique file ID for vxworks. *\/$/;" m struct:unixFileId typeref:struct:unixFileId::vxworksFileId file: +pIdList testdocs/sqlite3.c /^ IdList *pIdList; \/* Column names for INSERT *\/$/;" m struct:TriggerStep file: +pIdx testdocs/sqlite3.c /^ Fts5Index *pIdx;$/;" m struct:Fts5FlushCtx file: +pIdx testdocs/sqlite3.c /^ Index *pIdx; \/* The index to be tested for coverage *\/$/;" m struct:IdxCover file: +pIdx testdocs/sqlite3.c /^ Index *pIdx; \/* The index used to access the table *\/$/;" m struct:CCurHint file: +pIdx testdocs/sqlite3.c /^ Index *pIdx;$/;" m struct:ValueNewStat4Ctx file: +pIdxCover testdocs/sqlite3.c /^ struct IdxCover *pIdxCover; \/* Check for index coverage *\/$/;" m union:Walker::__anon17 typeref:struct:Walker::__anon17::IdxCover file: +pIdxDeleter testdocs/sqlite3.c /^ sqlite3_stmt *pIdxDeleter; \/* "DELETE FROM %_idx WHERE segid=? *\/$/;" m struct:Fts5Index file: +pIdxExpr testdocs/sqlite3.c /^ Expr *pIdxExpr; \/* Search for this index expression *\/$/;" m struct:WhereScan file: +pIdxExpr testdocs/sqlite3.c /^ Expr *pIdxExpr; \/* The index expression *\/$/;" m struct:IdxExprTrans file: +pIdxIter testdocs/sqlite3.c /^ sqlite3_stmt *pIdxIter; \/* Index iterator *\/$/;" m struct:RbuObjIter file: +pIdxSelect testdocs/sqlite3.c /^ sqlite3_stmt *pIdxSelect;$/;" m struct:Fts5Index file: +pIdxTrans testdocs/sqlite3.c /^ struct IdxExprTrans *pIdxTrans; \/* Convert indexed expr to column *\/$/;" m union:Walker::__anon17 typeref:struct:Walker::__anon17::IdxExprTrans file: +pIdxWriter testdocs/sqlite3.c /^ sqlite3_stmt *pIdxWriter; \/* "INSERT ... %_idx VALUES(?,?,?,?)" *\/$/;" m struct:Fts5Index file: +pIn testdocs/sqlite3.c /^ void *pIn; \/* First argument to xInput *\/$/;" m struct:SessionInput file: +pIn testdocs/sqlite3.c /^ void *pIn; \/* Argument to the thread *\/$/;" m struct:SQLiteThread file: +pIn testdocs/sqlite3.c /^ void *pIn; \/* Argument to xTask *\/$/;" m struct:SQLiteThread file: +pInJournal testdocs/sqlite3.c /^ Bitvec *pInJournal; \/* One bit for each page in the database file *\/$/;" m struct:Pager file: +pInSavepoint testdocs/sqlite3.c /^ Bitvec *pInSavepoint; \/* Set of pages in this savepoint *\/$/;" m struct:PagerSavepoint file: +pIncr testdocs/sqlite3.c /^ IncrMerger *pIncr; \/* Incremental merger *\/$/;" m struct:PmaReader file: +pIndex testdocs/sqlite3.c /^ Index *pIndex; \/* Index used, or NULL *\/$/;" m struct:WhereLoop::__anon29::__anon30 file: +pIndex testdocs/sqlite3.c /^ Fts5Index *pIndex; \/* Associated FTS5 index *\/$/;" m struct:Fts5VocabCursor file: +pIndex testdocs/sqlite3.c /^ Fts5Index *pIndex; \/* Full-text index *\/$/;" m struct:Fts5Table file: +pIndex testdocs/sqlite3.c /^ Fts5Index *pIndex; \/* Index that owns this iterator *\/$/;" m struct:Fts5Iter file: +pIndex testdocs/sqlite3.c /^ Fts5Index *pIndex;$/;" m struct:Fts5Expr file: +pIndex testdocs/sqlite3.c /^ Fts5Index *pIndex;$/;" m struct:Fts5Storage file: +pIndex testdocs/sqlite3.c /^ Index *pIndex; \/* List of SQL indexes on this table. *\/$/;" m struct:Table file: +pInfo testdocs/sqlite3.c /^ sqlite3_rtree_query_info *pInfo; \/* xGeom and xQueryFunc argument *\/$/;" m struct:RtreeConstraint file: +pInitMutex testdocs/sqlite3.c /^ sqlite3_mutex *pInitMutex; \/* Mutex used by sqlite3_initialize() *\/$/;" m struct:Sqlite3Config file: +pInode testdocs/sqlite3.c /^ unixInodeInfo *pInode; \/* Info about locks on this inode *\/$/;" m struct:unixFile file: +pInode testdocs/sqlite3.c /^ unixInodeInfo *pInode; \/* unixInodeInfo that owns this SHM node *\/$/;" m struct:unixShmNode file: +pInput testdocs/sqlite3.c /^ const char *pInput; \/* input we are tokenizing *\/$/;" m struct:simple_tokenizer_cursor file: +pInsert testdocs/sqlite3.c /^ sqlite3_stmt *pInsert; \/* INSERT statement *\/$/;" m struct:SessionApplyCtx file: +pInsert testdocs/sqlite3.c /^ sqlite3_stmt *pInsert; \/* Statement for INSERT operations *\/$/;" m struct:RbuObjIter file: +pIter testdocs/sqlite3.c /^ Fts5IndexIter *pIter; \/* Iterator for this term *\/$/;" m struct:Fts5ExprTerm file: +pIter testdocs/sqlite3.c /^ Fts5IndexIter *pIter; \/* Term\/rowid iterator object *\/$/;" m struct:Fts5VocabCursor file: +pIter testdocs/sqlite3.c /^ UBreakIterator *pIter; \/* ICU break-iterator object *\/$/;" m struct:IcuCursor file: +pKey testdocs/sqlite3.c /^ const char *pKey; \/* Key associated with this element *\/$/;" m struct:HashElem file: +pKey testdocs/sqlite3.c /^ const void *pKey; \/* Key content for indexes. NULL for tables *\/$/;" m struct:BtreePayload file: +pKey testdocs/sqlite3.c /^ void *pKey; \/* Saved key that was cursor last known position *\/$/;" m struct:BtCursor file: +pKey testdocs/sqlite3.c /^ void *pKey; int nKey; \/* Key associated with this element *\/$/;" m struct:Fts3HashElem file: +pKeyInfo testdocs/sqlite3.c /^ KeyInfo *pKeyInfo; \/* Used when p4type is P4_KEYINFO *\/$/;" m union:VdbeOp::p4union file: +pKeyInfo testdocs/sqlite3.c /^ KeyInfo *pKeyInfo; \/* How to compare records *\/$/;" m struct:VdbeSorter file: +pKeyInfo testdocs/sqlite3.c /^ KeyInfo *pKeyInfo; \/* Info about index keys needed by index cursors *\/$/;" m struct:VdbeCursor file: +pKeyInfo testdocs/sqlite3.c /^ KeyInfo *pKeyInfo; \/* Collation and sort-order information *\/$/;" m struct:UnpackedRecord file: +pKeyInfo testdocs/sqlite3.c /^ struct KeyInfo *pKeyInfo; \/* Arg passed to comparison function *\/$/;" m struct:BtCursor typeref:struct:BtCursor::KeyInfo file: +pLast testdocs/sqlite3.c /^ TriggerStep *pLast; \/* Last element in link-list. Valid for 1st elem only *\/$/;" m struct:TriggerStep file: +pLast testdocs/sqlite3.c /^ struct MemBlockHdr *pLast;$/;" m struct:__anon20 typeref:struct:__anon20::MemBlockHdr file: +pLast testdocs/sqlite3.c /^ struct RowSetEntry *pLast; \/* Last entry on the pEntry list *\/$/;" m struct:RowSet typeref:struct:RowSet::RowSetEntry file: +pLeaf testdocs/sqlite3.c /^ Fts5Data *pLeaf; \/* Current leaf data *\/$/;" m struct:Fts5SegIter file: +pLeft testdocs/sqlite3.c /^ Expr *pLeft; \/* Left subnode *\/$/;" m struct:Expr file: +pLeft testdocs/sqlite3.c /^ Fts3Expr *pLeft; \/* Left operand *\/$/;" m struct:Fts3Expr file: +pLeft testdocs/sqlite3.c /^ struct RowSetEntry *pLeft; \/* Left subtree (smaller entries) *\/$/;" m struct:RowSetEntry typeref:struct:RowSetEntry::RowSetEntry file: +pLeftmost testdocs/sqlite3.c /^ SegmentNode *pLeftmost; \/* Pointer to left-most node of this depth *\/$/;" m struct:SegmentNode file: +pLimit testdocs/sqlite3.c /^ Expr *pLimit; \/* LIMIT expression. NULL means not used. *\/$/;" m struct:Select file: +pLimit testdocs/sqlite3.c /^ Expr *pLimit; \/* The LIMIT expression. NULL if there is no limit *\/$/;" m struct:LimitVal file: +pList testdocs/sqlite3.c /^ ExprList *pList; \/* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN *\/$/;" m union:Expr::__anon11 file: +pList testdocs/sqlite3.c /^ PendingList *pList; \/* Doclist is assembled here *\/$/;" m struct:Fts3DeferredToken file: +pList testdocs/sqlite3.c /^ SessionTable *pList; \/* List of tables in current patch *\/$/;" m struct:sqlite3_changegroup file: +pList testdocs/sqlite3.c /^ SorterRecord *pList; \/* Linked list of records *\/$/;" m struct:SorterList file: +pList testdocs/sqlite3.c /^ char *pList; \/* Pointer to start of phrase position list *\/$/;" m struct:SnippetPhrase file: +pList testdocs/sqlite3.c /^ char *pList; \/* Position-list *\/$/;" m struct:TermOffset file: +pList testdocs/sqlite3.c /^ char *pList; \/* Pointer to position list following iDocid *\/$/;" m struct:Fts3Doclist file: +pList testdocs/sqlite3.c /^ char *pList;$/;" m struct:TokenDoclist file: +pLock testdocs/sqlite3.c /^ BtLock *pLock; \/* List of locks held on this shared-btree struct *\/$/;" m struct:BtShared file: +pLogArg testdocs/sqlite3.c /^ void *pLogArg; \/* First argument to xLog() *\/$/;" m struct:Sqlite3Config file: +pLoops testdocs/sqlite3.c /^ WhereLoop *pLoops; \/* List of all WhereLoop objects *\/$/;" m struct:WhereInfo file: +pLruNext testdocs/sqlite3.c /^ PgHdr1 *pLruNext; \/* Next in LRU list of unpinned pages *\/$/;" m struct:PgHdr1 file: +pLruPrev testdocs/sqlite3.c /^ PgHdr1 *pLruPrev; \/* Previous in LRU list of unpinned pages *\/$/;" m struct:PgHdr1 file: +pMIBuffer testdocs/sqlite3.c /^ MatchinfoBuffer *pMIBuffer; \/* Buffer for matchinfo data *\/$/;" m struct:Fts3Cursor file: +pMain testdocs/sqlite3.c /^ rbu_file *pMain; \/* Linked list of main db files *\/$/;" m struct:rbu_vfs file: +pMainNext testdocs/sqlite3.c /^ rbu_file *pMainNext; \/* Next MAIN_DB file *\/$/;" m struct:rbu_file file: +pMap testdocs/sqlite3.c /^ void *pMap;$/;" m struct:winShmNode::ShmRegion file: +pMapRegion testdocs/sqlite3.c /^ void *pMapRegion; \/* Memory mapped region *\/$/;" m struct:unixFile file: +pMapRegion testdocs/sqlite3.c /^ void *pMapRegion; \/* Area memory mapped *\/$/;" m struct:winFile file: +pMem testdocs/sqlite3.c /^ Mem *pMem; \/* Used when p4type is P4_MEM *\/$/;" m union:VdbeOp::p4union file: +pMem testdocs/sqlite3.c /^ Mem *pMem; \/* Memory cell used to store aggregate context *\/$/;" m struct:sqlite3_context file: +pMerger testdocs/sqlite3.c /^ MergeEngine *pMerger; \/* Merge engine thread reads data from *\/$/;" m struct:IncrMerger file: +pMerger testdocs/sqlite3.c /^ MergeEngine *pMerger; \/* Or here, if bUseThreads==0 *\/$/;" m struct:VdbeSorter file: +pMethod testdocs/sqlite3.c /^ const sqlite3_io_methods *pMethod; \/* Parent class. MUST BE FIRST *\/$/;" m struct:MemJournal file: +pMethod testdocs/sqlite3.c /^ const sqlite3_io_methods *pMethod; \/* The file I\/O methods to use. *\/$/;" m struct:winVfsAppData file: +pMethod testdocs/sqlite3.c /^ const sqlite3_io_methods *pMethod; \/*** Must be first ***\/$/;" m struct:winFile file: +pMethod testdocs/sqlite3.c /^ sqlite3_io_methods const *pMethod; \/* Always the first entry *\/$/;" m struct:unixFile file: +pMethods testdocs/sqlite3.c /^ const struct sqlite3_io_methods *pMethods; \/* Methods for an open file *\/$/;" m struct:sqlite3_file typeref:struct:sqlite3_file::sqlite3_io_methods file: +pMmapFreelist testdocs/sqlite3.c /^ PgHdr *pMmapFreelist; \/* List of free mmap page headers (pDirty) *\/$/;" m struct:Pager file: +pMod testdocs/sqlite3.c /^ Module *pMod; \/* Pointer to module implementation *\/$/;" m struct:VTable file: +pMod testdocs/sqlite3.c /^ const sqlite3_tokenizer_module *pMod;$/;" m struct:Fts3tokTable file: +pModule testdocs/sqlite3.c /^ const sqlite3_module *pModule; \/* Callback pointers *\/$/;" m struct:Module file: +pModule testdocs/sqlite3.c /^ const sqlite3_module *pModule; \/* The module for this virtual table *\/$/;" m struct:sqlite3_vtab file: +pModule testdocs/sqlite3.c /^ const sqlite3_tokenizer_module *pModule; \/* The module for this tokenizer *\/$/;" m struct:sqlite3_tokenizer file: +pNC testdocs/sqlite3.c /^ NameContext *pNC; \/* Naming context *\/$/;" m union:Walker::__anon17 file: +pName testdocs/sqlite3.c /^ const PragmaName *pName; \/* Name of the pragma *\/$/;" m struct:PragmaVtab file: +pName testdocs/sqlite3.c /^ const Token *pName; \/* Name of the container - used for error messages *\/$/;" m struct:DbFixer file: +pNear testdocs/sqlite3.c /^ Fts5ExprNearset *pNear; \/* For FTS5_STRING - cluster of phrases *\/$/;" m struct:Fts5ExprNode file: +pNew testdocs/sqlite3.c /^ WhereLoop *pNew; \/* Template WhereLoop *\/$/;" m struct:WhereLoopBuilder file: +pNewTable testdocs/sqlite3.c /^ Table *pNewTable; \/* A table being constructed by CREATE TABLE *\/$/;" m struct:Parse file: +pNewTrigger testdocs/sqlite3.c /^ Trigger *pNewTrigger; \/* Trigger under construct by a CREATE TRIGGER *\/$/;" m struct:Parse file: +pNewUnpacked testdocs/sqlite3.c /^ UnpackedRecord *pNewUnpacked; \/* Unpacked version of new.* record *\/$/;" m struct:PreUpdate file: +pNext testdocs/sqlite3.c /^ SorterRecord *pNext; \/* Pointer to next record in list *\/$/;" m union:SorterRecord::__anon25 file: +pNext testdocs/sqlite3.c /^ AutoincInfo *pNext; \/* Next info block in a list of them all *\/$/;" m struct:AutoincInfo file: +pNext testdocs/sqlite3.c /^ BtCursor *pNext; \/* Forms a linked list of all cursors *\/$/;" m struct:BtCursor file: +pNext testdocs/sqlite3.c /^ BtLock *pNext; \/* Next in BtShared.pLock list *\/$/;" m struct:BtLock file: +pNext testdocs/sqlite3.c /^ BtShared *pNext; \/* Next on a list of sharable BtShared structs *\/$/;" m struct:BtShared file: +pNext testdocs/sqlite3.c /^ Btree *pNext; \/* List of other sharable Btrees from the same db *\/$/;" m struct:Btree file: +pNext testdocs/sqlite3.c /^ FileChunk *pNext; \/* Next chunk in the journal *\/$/;" m struct:FileChunk file: +pNext testdocs/sqlite3.c /^ Fts3DeferredToken *pNext; \/* Next in list of deferred tokens *\/$/;" m struct:Fts3DeferredToken file: +pNext testdocs/sqlite3.c /^ Fts5Auxdata *pNext; \/* Next object in linked list *\/$/;" m struct:Fts5Auxdata file: +pNext testdocs/sqlite3.c /^ Fts5Auxiliary *pNext; \/* Next registered auxiliary function *\/$/;" m struct:Fts5Auxiliary file: +pNext testdocs/sqlite3.c /^ Fts5Cursor *pNext; \/* Next cursor in Fts5Cursor.pCsr list *\/$/;" m struct:Fts5Cursor file: +pNext testdocs/sqlite3.c /^ Fts5TermsetEntry *pNext;$/;" m struct:Fts5TermsetEntry file: +pNext testdocs/sqlite3.c /^ Fts5TokenizerModule *pNext; \/* Next registered tokenizer module *\/$/;" m struct:Fts5TokenizerModule file: +pNext testdocs/sqlite3.c /^ FuncDef *pNext; \/* Next function with same name *\/$/;" m struct:FuncDef file: +pNext testdocs/sqlite3.c /^ Index *pNext; \/* The next index associated with the same table *\/$/;" m struct:Index file: +pNext testdocs/sqlite3.c /^ LookasideSlot *pNext; \/* Next buffer in the list of free buffers *\/$/;" m struct:LookasideSlot file: +pNext testdocs/sqlite3.c /^ NameContext *pNext; \/* Next outer name context. NULL for outermost *\/$/;" m struct:NameContext file: +pNext testdocs/sqlite3.c /^ PgFreeslot *pNext; \/* Next free slot *\/$/;" m struct:PgFreeslot file: +pNext testdocs/sqlite3.c /^ PgHdr1 *pNext; \/* Next in hash table chain *\/$/;" m struct:PgHdr1 file: +pNext testdocs/sqlite3.c /^ RbuUpdateStmt *pNext;$/;" m struct:RbuUpdateStmt file: +pNext testdocs/sqlite3.c /^ RtreeNode *pNext; \/* Next node in this hash collision chain *\/$/;" m struct:RtreeNode file: +pNext testdocs/sqlite3.c /^ Savepoint *pNext; \/* Parent savepoint (if any) *\/$/;" m struct:Savepoint file: +pNext testdocs/sqlite3.c /^ Select *pNext; \/* Next select to the left in a compound *\/$/;" m struct:Select file: +pNext testdocs/sqlite3.c /^ SessionChange *pNext; \/* For hash-table collisions *\/$/;" m struct:SessionChange file: +pNext testdocs/sqlite3.c /^ SessionTable *pNext;$/;" m struct:SessionTable file: +pNext testdocs/sqlite3.c /^ SubProgram *pNext; \/* Next sub-program already visited *\/$/;" m struct:SubProgram file: +pNext testdocs/sqlite3.c /^ Trigger *pNext; \/* Next trigger associated with the table *\/$/;" m struct:Trigger file: +pNext testdocs/sqlite3.c /^ TriggerPrg *pNext; \/* Next entry in Parse.pTriggerPrg list *\/$/;" m struct:TriggerPrg file: +pNext testdocs/sqlite3.c /^ TriggerStep *pNext; \/* Next in the link-list *\/$/;" m struct:TriggerStep file: +pNext testdocs/sqlite3.c /^ UnixUnusedFd *pNext; \/* Next unused file descriptor on same file *\/$/;" m struct:UnixUnusedFd file: +pNext testdocs/sqlite3.c /^ VTable *pNext; \/* Next in linked list (see above) *\/$/;" m struct:VTable file: +pNext testdocs/sqlite3.c /^ Vdbe *pPrev,*pNext; \/* Linked list of VDBEs with the same Vdbe.db *\/$/;" m struct:Vdbe file: +pNext testdocs/sqlite3.c /^ sqlite3_backup *pNext; \/* Next backup associated with source pager *\/$/;" m struct:sqlite3_backup file: +pNext testdocs/sqlite3.c /^ sqlite3_session *pNext; \/* Next session object on same db. *\/$/;" m struct:sqlite3_session file: +pNext testdocs/sqlite3.c /^ sqlite3_vfs *pNext; \/* Next registered VFS *\/$/;" m struct:sqlite3_vfs file: +pNext testdocs/sqlite3.c /^ struct MemBlockHdr *pNext, *pPrev; \/* Linked list of all unfreed memory *\/$/;" m struct:MemBlockHdr typeref:struct:MemBlockHdr::MemBlockHdr file: +pNext testdocs/sqlite3.c /^ struct ScratchFreeslot *pNext; \/* Next unused scratch buffer *\/$/;" m struct:ScratchFreeslot typeref:struct:ScratchFreeslot::ScratchFreeslot file: +pNext testdocs/sqlite3.c /^ struct vxworksFileId *pNext; \/* Next in a list of them all *\/$/;" m struct:vxworksFileId typeref:struct:vxworksFileId::vxworksFileId file: +pNext testdocs/sqlite3.c /^ unixInodeInfo *pNext; \/* List of all unixInodeInfo objects *\/$/;" m struct:unixInodeInfo file: +pNext testdocs/sqlite3.c /^ unixShm *pNext; \/* Next unixShm with the same unixShmNode *\/$/;" m struct:unixShm file: +pNext testdocs/sqlite3.c /^ winShm *pNext; \/* Next winShm with the same winShmNode *\/$/;" m struct:winShm file: +pNext testdocs/sqlite3.c /^ winShmNode *pNext; \/* Next in list of all winShmNode objects *\/$/;" m struct:winShmNode file: +pNextAux testdocs/sqlite3.c /^ AuxData *pNextAux; \/* Next element in list *\/$/;" m struct:AuxData file: +pNextBlocked testdocs/sqlite3.c /^ sqlite3 *pNextBlocked; \/* Next in list of all blocked connections *\/$/;" m struct:sqlite3 file: +pNextChunk testdocs/sqlite3.c /^ struct RowSetChunk *pNextChunk; \/* Next chunk on list of them all *\/$/;" m struct:RowSetChunk typeref:struct:RowSetChunk::RowSetChunk file: +pNextDocid testdocs/sqlite3.c /^ char *pNextDocid; \/* Pointer to next docid *\/$/;" m struct:Fts3Doclist file: +pNextFrom testdocs/sqlite3.c /^ FKey *pNextFrom; \/* Next FKey with the same in pFrom. Next parent of pFrom *\/$/;" m struct:FKey file: +pNextId testdocs/sqlite3.c /^ char *pNextId; \/* Pointer into the body of aDoclist *\/$/;" m struct:Fts3Cursor file: +pNextLeaf testdocs/sqlite3.c /^ Fts5Data *pNextLeaf; \/* Leaf page (iLeafPgno+1) *\/$/;" m struct:Fts5SegIter file: +pNextLoop testdocs/sqlite3.c /^ WhereLoop *pNextLoop; \/* Next WhereLoop object in the WhereClause *\/$/;" m struct:WhereLoop file: +pNextTo testdocs/sqlite3.c /^ FKey *pNextTo; \/* Next with the same zTo. Next child of zTo. *\/$/;" m struct:FKey file: +pNextZombie testdocs/sqlite3.c /^ Table *pNextZombie; \/* Next on the Parse.pZombieTab list *\/$/;" m struct:Table file: +pNode testdocs/sqlite3.c /^ Fts5ExprNode *pNode; \/* FTS5_STRING node this phrase is part of *\/$/;" m struct:Fts5ExprPhrase file: +pNodeBlob testdocs/sqlite3.c /^ sqlite3_blob *pNodeBlob;$/;" m struct:Rtree file: +pOffset testdocs/sqlite3.c /^ Expr *pOffset; \/* OFFSET expression. NULL means not used. *\/$/;" m struct:Select file: +pOffset testdocs/sqlite3.c /^ Expr *pOffset; \/* The OFFSET expression. NULL if there is none *\/$/;" m struct:LimitVal file: +pOffsetList testdocs/sqlite3.c /^ char *pOffsetList;$/;" m struct:Fts3SegReader file: +pOldMethod testdocs/sqlite3.c /^ sqlite3_io_methods const *pOldMethod; \/* Original I\/O methods for close *\/$/;" m struct:proxyLockingContext file: +pOn testdocs/sqlite3.c /^ Expr *pOn; \/* The ON clause of a join *\/$/;" m struct:SrcList::SrcList_item file: +pOrInfo testdocs/sqlite3.c /^ WhereOrInfo *pOrInfo; \/* Extra information if (eOperator & WO_OR)!=0 *\/$/;" m union:WhereTerm::__anon32 file: +pOrPoslist testdocs/sqlite3.c /^ char *pOrPoslist;$/;" m struct:Fts3Phrase file: +pOrSet testdocs/sqlite3.c /^ WhereOrSet *pOrSet; \/* Record best loops here, if not NULL *\/$/;" m struct:WhereLoopBuilder file: +pOrderBy testdocs/sqlite3.c /^ ExprList *pOrderBy; \/* ORDER BY clause *\/$/;" m struct:WhereLoopBuilder file: +pOrderBy testdocs/sqlite3.c /^ ExprList *pOrderBy; \/* The ORDER BY clause or NULL *\/$/;" m struct:WhereInfo file: +pOrderBy testdocs/sqlite3.c /^ ExprList *pOrderBy; \/* The ORDER BY clause *\/$/;" m struct:Select file: +pOrderBy testdocs/sqlite3.c /^ ExprList *pOrderBy; \/* The ORDER BY (or GROUP BY clause) *\/$/;" m struct:SortCtx file: +pOrderBy testdocs/sqlite3.c /^ ExprList *pOrderBy; \/* Key columns for SRT_Queue and SRT_DistQueue *\/$/;" m struct:SelectDest file: +pOrigWC testdocs/sqlite3.c /^ WhereClause *pOrigWC; \/* Original, innermost WhereClause *\/$/;" m struct:WhereScan file: +pOut testdocs/sqlite3.c /^ Fts5Buffer *pOut; \/* Output poslist *\/$/;" m struct:Fts5NearTrimmer file: +pOut testdocs/sqlite3.c /^ Mem *pOut; \/* The return value is stored here *\/$/;" m struct:sqlite3_context file: +pOut testdocs/sqlite3.c /^ void *pOut; \/* Result returned by the thread *\/$/;" m struct:SQLiteThread file: +pOuter testdocs/sqlite3.c /^ WhereClause *pOuter; \/* Outer conjunction *\/$/;" m struct:WhereClause file: +pOuter testdocs/sqlite3.c /^ With *pOuter; \/* Containing WITH clause, or NULL *\/$/;" m struct:With file: +pPCache testdocs/sqlite3.c /^ PCache *pPCache; \/* Pointer to page cache object *\/$/;" m struct:Pager file: +pPage testdocs/sqlite3.c /^ sqlite3_pcache_page *pPage; \/* Pcache object page handle *\/$/;" m struct:PgHdr file: +pPage testdocs/sqlite3.c /^ void *pPage; \/* Page cache memory *\/$/;" m struct:Sqlite3Config file: +pPage1 testdocs/sqlite3.c /^ MemPage *pPage1; \/* First page of the database *\/$/;" m struct:BtShared file: +pPager testdocs/sqlite3.c /^ Pager *pPager; \/* The pager this page is part of *\/$/;" m struct:PgHdr file: +pPager testdocs/sqlite3.c /^ Pager *pPager; \/* The page cache *\/$/;" m struct:BtShared file: +pPager testdocs/sqlite3.c /^ Pager *pPager; \/* The associated pager. Also accessible by pBt->pPager *\/$/;" m struct:IntegrityCk file: +pParent testdocs/sqlite3.c /^ Fts3Expr *pParent; \/* pParent->pLeft==this or pParent->pRight==this *\/$/;" m struct:Fts3Expr file: +pParent testdocs/sqlite3.c /^ RtreeNode *pParent; \/* Parent node *\/$/;" m struct:RtreeNode file: +pParent testdocs/sqlite3.c /^ SegmentNode *pParent; \/* Parent node (or NULL for root node) *\/$/;" m struct:SegmentNode file: +pParent testdocs/sqlite3.c /^ VdbeFrame *pParent; \/* Parent of this frame, or NULL if parent is main *\/$/;" m struct:VdbeFrame file: +pParse testdocs/sqlite3.c /^ Parse *pParse; \/* Parser context. *\/$/;" m struct:Walker file: +pParse testdocs/sqlite3.c /^ Parse *pParse; \/* The Parse structure *\/$/;" m struct:AuthContext file: +pParse testdocs/sqlite3.c /^ Parse *pParse; \/* Parsing and code generating context *\/$/;" m struct:WhereInfo file: +pParse testdocs/sqlite3.c /^ Parse *pParse; \/* The parsing context *\/$/;" m struct:SubstContext file: +pParse testdocs/sqlite3.c /^ Parse *pParse; \/* Parsing context used to create this Vdbe *\/$/;" m struct:Vdbe file: +pParse testdocs/sqlite3.c /^ Parse *pParse; \/* The parser *\/$/;" m struct:NameContext file: +pParse testdocs/sqlite3.c /^ Parse *pParse; \/* The parsing context. Error messages written here *\/$/;" m struct:DbFixer file: +pParse testdocs/sqlite3.c /^ Parse *pParse;$/;" m struct:ValueNewStat4Ctx file: +pPartIdxWhere testdocs/sqlite3.c /^ Expr *pPartIdxWhere; \/* WHERE clause for partial indices *\/$/;" m struct:Index file: +pPatch testdocs/sqlite3.c /^ JsonNode *pPatch; \/* Node chain of patch for JNODE_PATCH *\/$/;" m union:JsonNode::__anon37 file: +pPayload testdocs/sqlite3.c /^ u8 *pPayload; \/* Pointer to the start of payload *\/$/;" m struct:CellInfo file: +pPg testdocs/sqlite3.c /^ DbPage *pPg;$/;" m struct:StatPage file: +pPhrase testdocs/sqlite3.c /^ Fts3Phrase *pPhrase; \/* The phrase the token belongs to *\/$/;" m struct:Fts3TokenAndCost file: +pPhrase testdocs/sqlite3.c /^ Fts3Phrase *pPhrase; \/* Valid if eType==FTSQUERY_PHRASE *\/$/;" m struct:Fts3Expr file: +pPhrase testdocs/sqlite3.c /^ Fts5ExprPhrase *pPhrase;$/;" m struct:TokenCtx file: +pPk testdocs/sqlite3.c /^ Index *pPk; \/* PK index if pTab is WITHOUT ROWID *\/$/;" m struct:PreUpdate file: +pPoslist testdocs/sqlite3.c /^ Fts5Buffer *pPoslist; \/* Pointer to current poslist *\/$/;" m struct:Fts5MatchPhrase file: +pPragma testdocs/sqlite3.c /^ sqlite3_stmt *pPragma; \/* The pragma statement to run *\/$/;" m struct:PragmaVtabCursor file: +pPreUpdate testdocs/sqlite3.c /^ PreUpdate *pPreUpdate; \/* Context for active pre-update callback *\/$/;" m struct:sqlite3 file: +pPreUpdateArg testdocs/sqlite3.c /^ void *pPreUpdateArg; \/* First argument to xPreUpdateCallback *\/$/;" m struct:sqlite3 file: +pPrev testdocs/sqlite3.c /^ Btree *pPrev; \/* Back pointer of the same list *\/$/;" m struct:Btree file: +pPrev testdocs/sqlite3.c /^ Vdbe *pPrev,*pNext; \/* Linked list of VDBEs with the same Vdbe.db *\/$/;" m struct:Vdbe file: +pPrev testdocs/sqlite3.c /^ struct MemBlockHdr *pNext, *pPrev; \/* Linked list of all unfreed memory *\/$/;" m struct:MemBlockHdr typeref:struct:MemBlockHdr:: file: +pPrev testdocs/sqlite3.c /^ unixInodeInfo *pPrev; \/* .... doubly linked *\/$/;" m struct:unixInodeInfo file: +pPrevTo testdocs/sqlite3.c /^ FKey *pPrevTo; \/* Previous with the same zTo *\/$/;" m struct:FKey file: +pPrior testdocs/sqlite3.c /^ Select *pPrior; \/* Prior select in a compound select statement *\/$/;" m struct:Select file: +pPrior testdocs/sqlite3.c /^ VtabCtx *pPrior; \/* Parent context (if any) *\/$/;" m struct:VtabCtx file: +pProfileArg testdocs/sqlite3.c /^ void *pProfileArg; \/* Argument to profile function *\/$/;" m struct:sqlite3 file: +pProgram testdocs/sqlite3.c /^ SubProgram *pProgram; \/* Used when p4type is P4_SUBPROGRAM *\/$/;" m union:VdbeOp::p4union file: +pProgram testdocs/sqlite3.c /^ SubProgram *pProgram; \/* Linked list of all sub-programs used by VM *\/$/;" m struct:Vdbe file: +pProgram testdocs/sqlite3.c /^ SubProgram *pProgram; \/* Program implementing pTrigger\/orconf *\/$/;" m struct:TriggerPrg file: +pProgressArg testdocs/sqlite3.c /^ void *pProgressArg; \/* Argument to the progress callback *\/$/;" m struct:sqlite3 file: +pPtr testdocs/sqlite3.c /^ void *pPtr; \/* Pointer value *\/$/;" m struct:Fts5Auxdata file: +pRank testdocs/sqlite3.c /^ Fts5Auxiliary *pRank; \/* Rank callback (or NULL) *\/$/;" m struct:Fts5Cursor file: +pRankArgStmt testdocs/sqlite3.c /^ sqlite3_stmt *pRankArgStmt; \/* Origin of objects in apRankArg[] *\/$/;" m struct:Fts5Cursor file: +pRbu testdocs/sqlite3.c /^ sqlite3rbu *pRbu; \/* Pointer to rbu object (rbu target only) *\/$/;" m struct:rbu_file file: +pRbuFd testdocs/sqlite3.c /^ rbu_file *pRbuFd; \/* Fd for main db of dbRbu *\/$/;" m struct:sqlite3rbu file: +pRbuUpdate testdocs/sqlite3.c /^ RbuUpdateStmt *pRbuUpdate;$/;" m struct:RbuObjIter file: +pRbuVfs testdocs/sqlite3.c /^ rbu_vfs *pRbuVfs; \/* Pointer to the rbu_vfs object *\/$/;" m struct:rbu_file file: +pRead testdocs/sqlite3.c /^ char *pRead; \/* Cursor used to iterate through aDoclist *\/$/;" m struct:LcsIterator file: +pReadParent testdocs/sqlite3.c /^ sqlite3_stmt *pReadParent;$/;" m struct:Rtree file: +pReadRowid testdocs/sqlite3.c /^ sqlite3_stmt *pReadRowid;$/;" m struct:Rtree file: +pReader testdocs/sqlite3.c /^ PmaReader *pReader; \/* Readr data from here after Rewind() *\/$/;" m struct:VdbeSorter file: +pReader testdocs/sqlite3.c /^ sqlite3_blob *pReader; \/* RO incr-blob open on %_data table *\/$/;" m struct:Fts5Index file: +pReal testdocs/sqlite3.c /^ double *pReal; \/* Used when p4type is P4_REAL *\/$/;" m union:VdbeOp::p4union file: +pReal testdocs/sqlite3.c /^ sqlite3_file *pReal; \/* Underlying file handle *\/$/;" m struct:rbu_file file: +pRealVfs testdocs/sqlite3.c /^ sqlite3_vfs *pRealVfs; \/* Underlying VFS *\/$/;" m struct:rbu_vfs file: +pRec testdocs/sqlite3.c /^ UnpackedRecord *pRec; \/* Probe for stat4 (if required) *\/$/;" m struct:WhereLoopBuilder file: +pRef testdocs/sqlite3.c /^ MemPage *pRef; \/* Reference page *\/$/;" m struct:CellArray file: +pReprepare testdocs/sqlite3.c /^ Vdbe *pReprepare; \/* VM being reprepared (sqlite3Reprepare()) *\/$/;" m struct:Parse file: +pResult testdocs/sqlite3.c /^ void *pResult; \/* Result of xTask *\/$/;" m struct:SQLiteThread file: +pResultSet testdocs/sqlite3.c /^ ExprList *pResultSet; \/* Result set of the query *\/$/;" m struct:WhereInfo file: +pResultSet testdocs/sqlite3.c /^ Mem *pResultSet; \/* Pointer to an array of results *\/$/;" m struct:Vdbe file: +pRight testdocs/sqlite3.c /^ Expr *pRight; \/* Right subnode *\/$/;" m struct:Expr file: +pRight testdocs/sqlite3.c /^ Fts3Expr *pRight; \/* Right operand *\/$/;" m struct:Fts3Expr file: +pRight testdocs/sqlite3.c /^ SegmentNode *pRight; \/* Pointer to right-sibling *\/$/;" m struct:SegmentNode file: +pRight testdocs/sqlite3.c /^ struct RowSetEntry *pRight; \/* Right subtree (larger entries) or list *\/$/;" m struct:RowSetEntry typeref:struct:RowSetEntry::RowSetEntry file: +pRollbackArg testdocs/sqlite3.c /^ void *pRollbackArg; \/* Argument to xRollbackCallback() *\/$/;" m struct:sqlite3 file: +pRoot testdocs/sqlite3.c /^ Fts3Expr *pRoot; \/* Root of NEAR\/AND cluster *\/$/;" m struct:Fts3TokenAndCost file: +pRoot testdocs/sqlite3.c /^ Fts5ExprNode *pRoot;$/;" m struct:Fts5Expr file: +pRowSet testdocs/sqlite3.c /^ RowSet *pRowSet; \/* Used only when flags==MEM_RowSet *\/$/;" m union:sqlite3_value::MemValue file: +pSavepoint testdocs/sqlite3.c /^ Savepoint *pSavepoint; \/* List of active savepoints *\/$/;" m struct:sqlite3 file: +pScan testdocs/sqlite3.c /^ Fts5HashEntry *pScan; \/* Current ordered scan item *\/$/;" m struct:Fts5Hash file: +pScanNext testdocs/sqlite3.c /^ Fts5HashEntry *pScanNext; \/* Next entry in sorted order *\/$/;" m struct:Fts5HashEntry file: +pSchema testdocs/sqlite3.c /^ Schema *pSchema; \/* Schema to which this item is fixed *\/$/;" m struct:SrcList::SrcList_item file: +pSchema testdocs/sqlite3.c /^ Schema *pSchema; \/* Schema containing this index *\/$/;" m struct:Index file: +pSchema testdocs/sqlite3.c /^ Schema *pSchema; \/* Schema containing the trigger *\/$/;" m struct:Trigger file: +pSchema testdocs/sqlite3.c /^ Schema *pSchema; \/* Pointer to database schema (possibly shared) *\/$/;" m struct:Db file: +pSchema testdocs/sqlite3.c /^ Schema *pSchema; \/* Schema that contains this table *\/$/;" m struct:Table file: +pSchema testdocs/sqlite3.c /^ Schema *pSchema; \/* Fix items to this schema *\/$/;" m struct:DbFixer file: +pSchema testdocs/sqlite3.c /^ void *pSchema; \/* Pointer to space allocated by sqlite3BtreeSchema() *\/$/;" m struct:BtShared file: +pScopyFrom testdocs/sqlite3.c /^ Mem *pScopyFrom; \/* This Mem is a shallow copy of pScopyFrom *\/$/;" m struct:sqlite3_value file: +pScratch testdocs/sqlite3.c /^ void *pScratch; \/* Scratch memory *\/$/;" m struct:Sqlite3Config file: +pScratchEnd testdocs/sqlite3.c /^ void *pScratchEnd;$/;" m struct:Mem0Global file: +pScratchFree testdocs/sqlite3.c /^ ScratchFreeslot *pScratchFree;$/;" m struct:Mem0Global file: +pSeekStmt testdocs/sqlite3.c /^ sqlite3_stmt *pSeekStmt; \/* Cache for fts3CursorSeekStmt() *\/$/;" m struct:Fts3Table file: +pSeg testdocs/sqlite3.c /^ Fts5StructureSegment *pSeg; \/* Segment to iterate through *\/$/;" m struct:Fts5SegIter file: +pSegcsr testdocs/sqlite3.c /^ Fts3MultiSegReader *pSegcsr; \/* Segment-reader for this token *\/$/;" m struct:Fts3PhraseToken file: +pSegments testdocs/sqlite3.c /^ sqlite3_blob *pSegments; \/* Blob handle open on %_segments table *\/$/;" m struct:Fts3Table file: +pSelect testdocs/sqlite3.c /^ Select *pSelect; \/* The definition of this CTE *\/$/;" m struct:With::Cte file: +pSelect testdocs/sqlite3.c /^ Select *pSelect; \/* EP_xIsSelect and op = IN, EXISTS, SELECT *\/$/;" m union:Expr::__anon11 file: +pSelect testdocs/sqlite3.c /^ Select *pSelect; \/* A SELECT statement used in place of a table name *\/$/;" m struct:SrcList::SrcList_item file: +pSelect testdocs/sqlite3.c /^ Select *pSelect; \/* NULL for tables. Points to definition if a view. *\/$/;" m struct:Table file: +pSelect testdocs/sqlite3.c /^ Select *pSelect; \/* SELECT statement or RHS of INSERT INTO SELECT ... *\/$/;" m struct:TriggerStep file: +pSelect testdocs/sqlite3.c /^ sqlite3_stmt *pSelect; \/* SELECT statement *\/$/;" m struct:SessionApplyCtx file: +pSelect testdocs/sqlite3.c /^ sqlite3_stmt *pSelect; \/* Source data *\/$/;" m struct:RbuObjIter file: +pSem testdocs/sqlite3.c /^ sem_t *pSem; \/* Named POSIX semaphore *\/$/;" m struct:unixInodeInfo file: +pSeqTab testdocs/sqlite3.c /^ Table *pSeqTab; \/* The sqlite_sequence table used by AUTOINCREMENT *\/$/;" m struct:Schema file: +pShm testdocs/sqlite3.c /^ unixShm *pShm; \/* Shared memory segment information *\/$/;" m struct:unixFile file: +pShm testdocs/sqlite3.c /^ winShm *pShm; \/* Instance of shared memory on this file *\/$/;" m struct:winFile file: +pShmNode testdocs/sqlite3.c /^ unixShmNode *pShmNode; \/* Shared memory associated with this inode *\/$/;" m struct:unixInodeInfo file: +pShmNode testdocs/sqlite3.c /^ unixShmNode *pShmNode; \/* The underlying unixShmNode object *\/$/;" m struct:unixShm file: +pShmNode testdocs/sqlite3.c /^ winShmNode *pShmNode; \/* The underlying winShmNode object *\/$/;" m struct:winShm file: +pSnapshot testdocs/sqlite3.c /^ WalIndexHdr *pSnapshot; \/* Start transaction here if not NULL *\/$/;" m struct:Wal file: +pSortCsr testdocs/sqlite3.c /^ Fts5Cursor *pSortCsr; \/* Sort data from this cursor *\/$/;" m struct:Fts5Table file: +pSorter testdocs/sqlite3.c /^ VdbeSorter *pSorter; \/* CURTYPE_SORTER. Sorter object *\/$/;" m union:VdbeCursor::__anon18 file: +pSorter testdocs/sqlite3.c /^ Fts5Sorter *pSorter; \/* Sorter for "ORDER BY rank" queries *\/$/;" m struct:Fts5Cursor file: +pSorter testdocs/sqlite3.c /^ VdbeSorter *pSorter; \/* Sorter that owns this sub-task *\/$/;" m struct:SortSubtask file: +pSpace testdocs/sqlite3.c /^ u8 *pSpace; \/* Available memory *\/$/;" m struct:ReusableSpace file: +pSqllogArg testdocs/sqlite3.c /^ void *pSqllogArg;$/;" m struct:Sqlite3Config file: +pSrc testdocs/sqlite3.c /^ Btree *pSrc; \/* Source b-tree file *\/$/;" m struct:sqlite3_backup file: +pSrc testdocs/sqlite3.c /^ SrcList *pSrc; \/* The FROM clause *\/$/;" m struct:Select file: +pSrc testdocs/sqlite3.c /^ SrcList *pSrc; \/* One particular FROM clause in a nested query *\/$/;" m struct:SrcCount file: +pSrcCount testdocs/sqlite3.c /^ struct SrcCount *pSrcCount; \/* Counting column references *\/$/;" m union:Walker::__anon17 typeref:struct:Walker::__anon17::SrcCount file: +pSrcDb testdocs/sqlite3.c /^ sqlite3* pSrcDb; \/* Source database handle *\/$/;" m struct:sqlite3_backup file: +pSrcList testdocs/sqlite3.c /^ SrcList *pSrcList; \/* FROM clause *\/$/;" m union:Walker::__anon17 file: +pSrcList testdocs/sqlite3.c /^ SrcList *pSrcList; \/* One or more tables used to resolve names *\/$/;" m struct:NameContext file: +pStart testdocs/sqlite3.c /^ void *pStart, *pEnd; \/* Bounds of global page cache memory *\/$/;" m struct:PCacheGlobal file: +pStart testdocs/sqlite3.c /^ void *pStart; \/* First byte of available memory space *\/$/;" m struct:Lookaside file: +pStmt testdocs/sqlite3.c /^ sqlite3_stmt *pStmt; \/* Iterates through set of root pages *\/$/;" m struct:StatCursor file: +pStmt testdocs/sqlite3.c /^ sqlite3_stmt *pStmt; \/* Prepared statement in use by the cursor *\/$/;" m struct:Fts3Cursor file: +pStmt testdocs/sqlite3.c /^ sqlite3_stmt *pStmt; \/* Statement holding lock on pIndex *\/$/;" m struct:Fts5VocabCursor file: +pStmt testdocs/sqlite3.c /^ sqlite3_stmt *pStmt; \/* Statement used to read %_content *\/$/;" m struct:Fts5Cursor file: +pStmt testdocs/sqlite3.c /^ sqlite3_stmt *pStmt; \/* Statement holding cursor open *\/$/;" m struct:Incrblob file: +pStmt testdocs/sqlite3.c /^ sqlite3_stmt *pStmt;$/;" m struct:Fts5Sorter file: +pStmt testdocs/sqlite3.c /^ sqlite3_stmt *pStmt;$/;" m struct:SessionDiffCtx file: +pStorage testdocs/sqlite3.c /^ Fts5Storage *pStorage; \/* Document store *\/$/;" m struct:Fts5Table file: +pStorage testdocs/sqlite3.c /^ Fts5Storage *pStorage;$/;" m struct:Fts5InsertCtx file: +pStress testdocs/sqlite3.c /^ void *pStress; \/* Argument to xStress *\/$/;" m struct:PCache file: +pStruct testdocs/sqlite3.c /^ Fts5Structure *pStruct; \/* Current db structure (or NULL) *\/$/;" m struct:Fts5Index file: +pStruct testdocs/sqlite3.c /^ Fts5Structure *pStruct; \/* Database structure for this iterator *\/$/;" m struct:Fts5Iter file: +pSynced testdocs/sqlite3.c /^ PgHdr *pSynced; \/* Last synced page in dirty page list *\/$/;" m struct:PCache file: +pSynonym testdocs/sqlite3.c /^ Fts5ExprTerm *pSynonym; \/* Pointer to first in list of synonyms *\/$/;" m struct:Fts5ExprTerm file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* Source table *\/$/;" m struct:AggInfo::AggInfo_col file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* Used when p4type is P4_TABLE *\/$/;" m union:VdbeOp::p4union file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* An SQL table corresponding to zName *\/$/;" m struct:SrcList::SrcList_item file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* Schema object being upated *\/$/;" m struct:PreUpdate file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* Table object *\/$/;" m struct:Incrblob file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* Table for TK_COLUMN expressions. *\/$/;" m struct:Expr file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* Table this info block refers to *\/$/;" m struct:AutoincInfo file: +pTab testdocs/sqlite3.c /^ Table *pTab; \/* The Table object to which the virtual table belongs *\/$/;" m struct:VtabCtx file: +pTabList testdocs/sqlite3.c /^ SrcList *pTabList; \/* List of tables in the join *\/$/;" m struct:WhereInfo file: +pTabSchema testdocs/sqlite3.c /^ Schema *pTabSchema; \/* Schema containing the table *\/$/;" m struct:Trigger file: +pTable testdocs/sqlite3.c /^ SessionTable *pTable; \/* List of attached tables *\/$/;" m struct:sqlite3_session file: +pTable testdocs/sqlite3.c /^ Table *pTable; \/* The SQL table being indexed *\/$/;" m struct:Index file: +pTail testdocs/sqlite3.c /^ char *pTail; \/* Position list data following iTail *\/$/;" m struct:SnippetPhrase file: +pTargetFd testdocs/sqlite3.c /^ rbu_file *pTargetFd; \/* File handle open on target db *\/$/;" m struct:sqlite3rbu file: +pTask testdocs/sqlite3.c /^ SortSubtask *pTask; \/* Task that owns this merger *\/$/;" m struct:IncrMerger file: +pTask testdocs/sqlite3.c /^ SortSubtask *pTask; \/* Used by this thread only *\/$/;" m struct:MergeEngine file: +pTblIter testdocs/sqlite3.c /^ sqlite3_stmt *pTblIter; \/* Iterate through tables *\/$/;" m struct:RbuObjIter file: +pTerm testdocs/sqlite3.c /^ char *pTerm;$/;" m struct:Fts5TermsetEntry file: +pTermset testdocs/sqlite3.c /^ Fts5Termset *pTermset;$/;" m struct:Fts5IntegrityCtx file: +pThread testdocs/sqlite3.c /^ SQLiteThread *pThread; \/* Background thread, if any *\/$/;" m struct:SortSubtask file: +pTmpInsert testdocs/sqlite3.c /^ sqlite3_stmt *pTmpInsert; \/* Insert into rbu_tmp_$zDataTbl *\/$/;" m struct:RbuObjIter file: +pTmpSpace testdocs/sqlite3.c /^ char *pTmpSpace; \/* Pager.pageSize bytes of space for tmp use *\/$/;" m struct:Pager file: +pTmpSpace testdocs/sqlite3.c /^ u8 *pTmpSpace; \/* Temp space sufficient to hold a single cell *\/$/;" m struct:BtShared file: +pTok testdocs/sqlite3.c /^ Fts5Tokenizer *pTok;$/;" m struct:Fts5Config file: +pTok testdocs/sqlite3.c /^ Fts5TokenizerModule *pTok; \/* First in list of all tokenizer modules *\/$/;" m struct:Fts5Global file: +pTok testdocs/sqlite3.c /^ sqlite3_tokenizer *pTok;$/;" m struct:Fts3tokTable file: +pTokApi testdocs/sqlite3.c /^ fts5_tokenizer *pTokApi;$/;" m struct:Fts5Config file: +pToken testdocs/sqlite3.c /^ Fts3PhraseToken *pToken; \/* Pointer to corresponding expr token *\/$/;" m struct:Fts3DeferredToken file: +pToken testdocs/sqlite3.c /^ Fts3PhraseToken *pToken; \/* The token itself *\/$/;" m struct:Fts3TokenAndCost file: +pToken testdocs/sqlite3.c /^ char *pToken; \/* storage for current token *\/$/;" m struct:simple_tokenizer_cursor file: +pTokenizer testdocs/sqlite3.c /^ Fts5Tokenizer *pTokenizer; \/* Parent tokenizer instance *\/$/;" m struct:PorterTokenizer file: +pTokenizer testdocs/sqlite3.c /^ sqlite3_tokenizer *pTokenizer; \/* Tokenizer for this cursor. *\/$/;" m struct:sqlite3_tokenizer_cursor file: +pTokenizer testdocs/sqlite3.c /^ sqlite3_tokenizer *pTokenizer; \/* Tokenizer module *\/$/;" m struct:ParseContext file: +pTokenizer testdocs/sqlite3.c /^ sqlite3_tokenizer *pTokenizer; \/* tokenizer for inserts and queries *\/$/;" m struct:Fts3Table file: +pToplevel testdocs/sqlite3.c /^ Parse *pToplevel; \/* Parse structure for main program (or NULL) *\/$/;" m struct:Parse file: +pTraceArg testdocs/sqlite3.c /^ void *pTraceArg; \/* Argument to the trace function *\/$/;" m struct:sqlite3 file: +pTree testdocs/sqlite3.c /^ SegmentNode *pTree; \/* Pointer to interior tree structure *\/$/;" m struct:SegmentWriter file: +pTrig testdocs/sqlite3.c /^ Trigger *pTrig; \/* The trigger that this step is a part of *\/$/;" m struct:TriggerStep file: +pTrigger testdocs/sqlite3.c /^ Trigger *pTrigger; \/* Trigger this program was coded from *\/$/;" m struct:TriggerPrg file: +pTrigger testdocs/sqlite3.c /^ Trigger *pTrigger; \/* List of triggers stored in pSchema *\/$/;" m struct:Table file: +pTrigger testdocs/sqlite3.c /^ #undef pTrigger$/;" d file: +pTriggerPrg testdocs/sqlite3.c /^ TriggerPrg *pTriggerPrg; \/* Linked list of coded triggers *\/$/;" m struct:Parse file: +pTriggerTab testdocs/sqlite3.c /^ Table *pTriggerTab; \/* Table triggers are being coded for *\/$/;" m struct:Parse file: +pUnlockArg testdocs/sqlite3.c /^ void *pUnlockArg; \/* Argument to xUnlockNotify *\/$/;" m struct:sqlite3 file: +pUnlockConnection testdocs/sqlite3.c /^ sqlite3 *pUnlockConnection; \/* Connection to watch for unlock *\/$/;" m struct:sqlite3 file: +pUnpacked testdocs/sqlite3.c /^ UnpackedRecord *pUnpacked; \/* Space to unpack a record *\/$/;" m struct:SortSubtask file: +pUnpacked testdocs/sqlite3.c /^ UnpackedRecord *pUnpacked; \/* Unpacked version of aRecord[] *\/$/;" m struct:PreUpdate file: +pUnpacked testdocs/sqlite3.c /^ UnpackedRecord *pUnpacked; \/* Used by VdbeSorterCompare() *\/$/;" m struct:VdbeSorter file: +pUnused testdocs/sqlite3.c /^ UnixUnusedFd *pUnused; \/* Pre-allocated UnixUnusedFd *\/$/;" m struct:unixFile file: +pUnused testdocs/sqlite3.c /^ UnixUnusedFd *pUnused; \/* Unused file descriptors to close *\/$/;" m struct:unixInodeInfo file: +pUpdate testdocs/sqlite3.c /^ sqlite3_stmt *pUpdate; \/* Last update statement (or NULL) *\/$/;" m struct:RbuUpdateStmt file: +pUpdate testdocs/sqlite3.c /^ sqlite3_stmt *pUpdate; \/* UPDATE statement *\/$/;" m struct:SessionApplyCtx file: +pUpdateArg testdocs/sqlite3.c /^ void *pUpdateArg;$/;" m struct:sqlite3 file: +pUser testdocs/sqlite3.c /^ void *pUser; \/* callback can use this, if desired *\/$/;" m struct:sqlite3_rtree_query_info file: +pUser testdocs/sqlite3.c /^ void *pUser; \/* Callback implementation user data *\/$/;" m struct:sqlite3_rtree_geometry file: +pUser testdocs/sqlite3.c /^ void *pUser; \/* First argument to xCmp() *\/$/;" m struct:CollSeq file: +pUserData testdocs/sqlite3.c /^ void *pUserData; \/* User pointer passed to xCreate() *\/$/;" m struct:Fts5TokenizerModule file: +pUserData testdocs/sqlite3.c /^ void *pUserData; \/* User-data pointer *\/$/;" m struct:Fts5Auxiliary file: +pUserData testdocs/sqlite3.c /^ void *pUserData; \/* User data parameter *\/$/;" m struct:FuncDef file: +pUserData testdocs/sqlite3.c /^ void *pUserData;$/;" m struct:FuncDestructor file: +pUsing testdocs/sqlite3.c /^ IdList *pUsing; \/* The USING clause of a join *\/$/;" m struct:SrcList::SrcList_item file: +pVCur testdocs/sqlite3.c /^ sqlite3_vtab_cursor *pVCur; \/* CURTYPE_VTAB. Vtab cursor *\/$/;" m union:VdbeCursor::__anon18 file: +pVList testdocs/sqlite3.c /^ VList *pVList; \/* Mapping between variable names and numbers *\/$/;" m struct:Parse file: +pVList testdocs/sqlite3.c /^ VList *pVList; \/* Name of variables *\/$/;" m struct:Vdbe file: +pVTable testdocs/sqlite3.c /^ VTable *pVTable; \/* List of VTable objects. *\/$/;" m struct:Table file: +pVTable testdocs/sqlite3.c /^ VTable *pVTable; \/* The virtual table being constructed *\/$/;" m struct:VtabCtx file: +pVdbe testdocs/sqlite3.c /^ Vdbe *pVdbe; \/* The VM that owns this context *\/$/;" m struct:sqlite3_context file: +pVdbe testdocs/sqlite3.c /^ Vdbe *pVdbe; \/* An engine for executing database bytecode *\/$/;" m struct:Parse file: +pVdbe testdocs/sqlite3.c /^ struct Vdbe *pVdbe; \/* List of active virtual machines *\/$/;" m struct:sqlite3 typeref:struct:sqlite3::Vdbe file: +pVdbeBranchArg testdocs/sqlite3.c /^ void *pVdbeBranchArg; \/* 1st argument *\/$/;" m struct:Sqlite3Config file: +pVfs testdocs/sqlite3.c /^ sqlite3_vfs *pVfs; \/* The VFS that created this unixFile *\/$/;" m struct:unixFile file: +pVfs testdocs/sqlite3.c /^ sqlite3_vfs *pVfs; \/* The "real" underlying VFS *\/$/;" m struct:MemJournal file: +pVfs testdocs/sqlite3.c /^ sqlite3_vfs *pVfs; \/* OS Interface *\/$/;" m struct:sqlite3 file: +pVfs testdocs/sqlite3.c /^ sqlite3_vfs *pVfs; \/* OS functions to use for IO *\/$/;" m struct:Pager file: +pVfs testdocs/sqlite3.c /^ sqlite3_vfs *pVfs; \/* The VFS used to create pDbFd *\/$/;" m struct:Wal file: +pVfs testdocs/sqlite3.c /^ sqlite3_vfs *pVfs; \/* The VFS used to open this file *\/$/;" m struct:winFile file: +pVtab testdocs/sqlite3.c /^ VTable *pVtab; \/* Used when p4type is P4_VTAB *\/$/;" m union:VdbeOp::p4union file: +pVtab testdocs/sqlite3.c /^ sqlite3_vtab *pVtab; \/* Pointer to vtab instance *\/$/;" m struct:VTable file: +pVtab testdocs/sqlite3.c /^ sqlite3_vtab *pVtab; \/* Virtual table of this cursor *\/$/;" m struct:sqlite3_vtab_cursor file: +pVtabCtx testdocs/sqlite3.c /^ VtabCtx *pVtabCtx; \/* Context for active vtab connect\/create *\/$/;" m struct:sqlite3 file: +pWC testdocs/sqlite3.c /^ WhereClause *pWC; \/* WhereClause currently being scanned *\/$/;" m struct:WhereScan file: +pWC testdocs/sqlite3.c /^ WhereClause *pWC; \/* WHERE clause terms *\/$/;" m struct:WhereLoopBuilder file: +pWC testdocs/sqlite3.c /^ WhereClause *pWC; \/* The clause this term is part of *\/$/;" m struct:WhereTerm file: +pWInfo testdocs/sqlite3.c /^ WhereInfo *pWInfo; \/* Information about this WHERE *\/$/;" m struct:WhereLoopBuilder file: +pWInfo testdocs/sqlite3.c /^ WhereInfo *pWInfo; \/* WHERE clause processing context *\/$/;" m struct:WhereClause file: +pWLoop testdocs/sqlite3.c /^ struct WhereLoop *pWLoop; \/* The selected WhereLoop object *\/$/;" m struct:WhereLevel typeref:struct:WhereLevel::WhereLoop file: +pWal testdocs/sqlite3.c /^ Wal *pWal; \/* The complete WAL information *\/$/;" m struct:WalWriter file: +pWal testdocs/sqlite3.c /^ Wal *pWal; \/* Write-ahead log used by "journal_mode=wal" *\/$/;" m struct:Pager file: +pWalArg testdocs/sqlite3.c /^ void *pWalArg;$/;" m struct:sqlite3 file: +pWalFd testdocs/sqlite3.c /^ rbu_file *pWalFd; \/* Wal file descriptor for this main db *\/$/;" m struct:rbu_file file: +pWalFd testdocs/sqlite3.c /^ sqlite3_file *pWalFd; \/* File handle for WAL file *\/$/;" m struct:Wal file: +pWhen testdocs/sqlite3.c /^ Expr *pWhen; \/* The WHEN clause of the expression (may be NULL) *\/$/;" m struct:Trigger file: +pWhere testdocs/sqlite3.c /^ Expr *pWhere; \/* The complete WHERE clause *\/$/;" m struct:WhereInfo file: +pWhere testdocs/sqlite3.c /^ Expr *pWhere; \/* The WHERE clause *\/$/;" m struct:Select file: +pWhere testdocs/sqlite3.c /^ Expr *pWhere; \/* The WHERE clause for DELETE or UPDATE steps *\/$/;" m struct:TriggerStep file: +pWith testdocs/sqlite3.c /^ With *pWith; \/* Current WITH clause, or NULL *\/$/;" m struct:Parse file: +pWith testdocs/sqlite3.c /^ With *pWith; \/* WITH clause attached to this select. Or NULL. *\/$/;" m struct:Select file: +pWithToFree testdocs/sqlite3.c /^ With *pWithToFree; \/* Free this WITH object at the end of the parse *\/$/;" m struct:Parse file: +pWriteNode testdocs/sqlite3.c /^ sqlite3_stmt *pWriteNode;$/;" m struct:Rtree file: +pWriteParent testdocs/sqlite3.c /^ sqlite3_stmt *pWriteParent;$/;" m struct:Rtree file: +pWriteRowid testdocs/sqlite3.c /^ sqlite3_stmt *pWriteRowid;$/;" m struct:Rtree file: +pWriter testdocs/sqlite3.c /^ Btree *pWriter; \/* Btree with currently open write transaction *\/$/;" m struct:BtShared file: +pWriter testdocs/sqlite3.c /^ sqlite3_stmt *pWriter; \/* "INSERT ... %_data VALUES(?,?)" *\/$/;" m struct:Fts5Index file: +pZombieTab testdocs/sqlite3.c /^ Table *pZombieTab; \/* List of Table objects to delete after code gen *\/$/;" m struct:Parse file: +padToSectorBoundary testdocs/sqlite3.c /^ u8 padToSectorBoundary; \/* Pad transactions out to the next sector *\/$/;" m struct:Wal file: +page testdocs/sqlite3.c /^ sqlite3_pcache_page page; \/* Base class. Must be first. pBuf & pExtra *\/$/;" m struct:PgHdr1 file: +pageFindSlot testdocs/sqlite3.c /^static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){$/;" f file: +pageFreeArray testdocs/sqlite3.c /^static int pageFreeArray($/;" f file: +pageHash testdocs/sqlite3.c /^ u32 pageHash; \/* Hash of page content *\/$/;" m struct:PgHdr file: +pageInJournal testdocs/sqlite3.c /^static int pageInJournal(Pager *pPager, PgHdr *pPg){$/;" f file: +pageInsertArray testdocs/sqlite3.c /^static int pageInsertArray($/;" f file: +pageReinit testdocs/sqlite3.c /^static void pageReinit(DbPage *pData){$/;" f file: +pageSize testdocs/sqlite3.c /^ int pageSize; \/* Number of bytes in a page *\/$/;" m struct:Pager file: +pageSize testdocs/sqlite3.c /^ u32 pageSize; \/* Total number of bytes on a page *\/$/;" m struct:BtShared file: +pagealign buf.c /^static size_t pagealign(size_t sz) {$/;" f file: +pagerAcquireMapPage testdocs/sqlite3.c /^static int pagerAcquireMapPage($/;" f file: +pagerAddPageToRollbackJournal testdocs/sqlite3.c /^static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){$/;" f file: +pagerBeginReadTransaction testdocs/sqlite3.c /^# define pagerBeginReadTransaction(/;" d file: +pagerBeginReadTransaction testdocs/sqlite3.c /^static int pagerBeginReadTransaction(Pager *pPager){$/;" f file: +pagerExclusiveLock testdocs/sqlite3.c /^static int pagerExclusiveLock(Pager *pPager){$/;" f file: +pagerFixMaplimit testdocs/sqlite3.c /^static void pagerFixMaplimit(Pager *pPager){$/;" f file: +pagerFlushOnCommit testdocs/sqlite3.c /^static int pagerFlushOnCommit(Pager *pPager, int bCommit){$/;" f file: +pagerFreeMapHdrs testdocs/sqlite3.c /^static void pagerFreeMapHdrs(Pager *pPager){$/;" f file: +pagerLockDb testdocs/sqlite3.c /^static int pagerLockDb(Pager *pPager, int eLock){$/;" f file: +pagerOpenSavepoint testdocs/sqlite3.c /^static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){$/;" f file: +pagerOpenWal testdocs/sqlite3.c /^static int pagerOpenWal(Pager *pPager){$/;" f file: +pagerOpenWalIfPresent testdocs/sqlite3.c /^# define pagerOpenWalIfPresent(/;" d file: +pagerOpenWalIfPresent testdocs/sqlite3.c /^static int pagerOpenWalIfPresent(Pager *pPager){$/;" f file: +pagerOpentemp testdocs/sqlite3.c /^static int pagerOpentemp($/;" f file: +pagerPagecount testdocs/sqlite3.c /^static int pagerPagecount(Pager *pPager, Pgno *pnPage){$/;" f file: +pagerPlaybackSavepoint testdocs/sqlite3.c /^static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){$/;" f file: +pagerReleaseMapPage testdocs/sqlite3.c /^static void pagerReleaseMapPage(PgHdr *pPg){$/;" f file: +pagerReportSize testdocs/sqlite3.c /^# define pagerReportSize(/;" d file: +pagerReportSize testdocs/sqlite3.c /^static void pagerReportSize(Pager *pPager){$/;" f file: +pagerRollbackWal testdocs/sqlite3.c /^# define pagerRollbackWal(/;" d file: +pagerRollbackWal testdocs/sqlite3.c /^static int pagerRollbackWal(Pager *pPager){$/;" f file: +pagerStress testdocs/sqlite3.c /^static int pagerStress(void *p, PgHdr *pPg){$/;" f file: +pagerSyncHotJournal testdocs/sqlite3.c /^static int pagerSyncHotJournal(Pager *pPager){$/;" f file: +pagerUndoCallback testdocs/sqlite3.c /^static int pagerUndoCallback(void *pCtx, Pgno iPg){$/;" f file: +pagerUnlockAndRollback testdocs/sqlite3.c /^static void pagerUnlockAndRollback(Pager *pPager){$/;" f file: +pagerUnlockDb testdocs/sqlite3.c /^static int pagerUnlockDb(Pager *pPager, int eLock){$/;" f file: +pagerUnlockIfUnused testdocs/sqlite3.c /^static void pagerUnlockIfUnused(Pager *pPager){$/;" f file: +pagerUseWal testdocs/sqlite3.c /^# define pagerUseWal(/;" d file: +pagerWalFrames testdocs/sqlite3.c /^# define pagerWalFrames(/;" d file: +pagerWalFrames testdocs/sqlite3.c /^static int pagerWalFrames($/;" f file: +pagerWriteLargeSector testdocs/sqlite3.c /^static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){$/;" f file: +pager_cksum testdocs/sqlite3.c /^static u32 pager_cksum(Pager *pPager, const u8 *aData){$/;" f file: +pager_datahash testdocs/sqlite3.c /^#define pager_datahash(/;" d file: +pager_datahash testdocs/sqlite3.c /^static u32 pager_datahash(int nByte, unsigned char *pData){$/;" f file: +pager_delmaster testdocs/sqlite3.c /^static int pager_delmaster(Pager *pPager, const char *zMaster){$/;" f file: +pager_end_transaction testdocs/sqlite3.c /^static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){$/;" f file: +pager_error testdocs/sqlite3.c /^static int pager_error(Pager *pPager, int rc){$/;" f file: +pager_incr_changecounter testdocs/sqlite3.c /^static int pager_incr_changecounter(Pager *pPager, int isDirectMode){$/;" f file: +pager_open_journal testdocs/sqlite3.c /^static int pager_open_journal(Pager *pPager){$/;" f file: +pager_pagehash testdocs/sqlite3.c /^#define pager_pagehash(/;" d file: +pager_pagehash testdocs/sqlite3.c /^static u32 pager_pagehash(PgHdr *pPage){$/;" f file: +pager_playback testdocs/sqlite3.c /^static int pager_playback(Pager *pPager, int isHot){$/;" f file: +pager_playback_one_page testdocs/sqlite3.c /^static int pager_playback_one_page($/;" f file: +pager_reset testdocs/sqlite3.c /^static void pager_reset(Pager *pPager){$/;" f file: +pager_set_pagehash testdocs/sqlite3.c /^#define pager_set_pagehash(/;" d file: +pager_set_pagehash testdocs/sqlite3.c /^static void pager_set_pagehash(PgHdr *pPage){$/;" f file: +pager_truncate testdocs/sqlite3.c /^static int pager_truncate(Pager *pPager, Pgno nPage){$/;" f file: +pager_unlock testdocs/sqlite3.c /^static void pager_unlock(Pager *pPager){$/;" f file: +pager_wait_on_lock testdocs/sqlite3.c /^static int pager_wait_on_lock(Pager *pPager, int locktype){$/;" f file: +pager_write testdocs/sqlite3.c /^static int pager_write(PgHdr *pPg){$/;" f file: +pager_write_changecounter testdocs/sqlite3.c /^static void pager_write_changecounter(PgHdr *pPg){$/;" f file: +pager_write_pagelist testdocs/sqlite3.c /^static int pager_write_pagelist(Pager *pPager, PgHdr *pList){$/;" f file: +parentWrite testdocs/sqlite3.c /^static int parentWrite(Rtree *pRtree, sqlite3_int64 iNode, sqlite3_int64 iPar){$/;" f file: +parseDateOrTime testdocs/sqlite3.c /^static int parseDateOrTime($/;" f file: +parseHhMmSs testdocs/sqlite3.c /^static int parseHhMmSs(const char *zDate, DateTime *p){$/;" f file: +parseModifier testdocs/sqlite3.c /^static int parseModifier($/;" f file: +parseTimezone testdocs/sqlite3.c /^static int parseTimezone(const char *zDate, DateTime *p){$/;" f file: +parseYyyyMmDd testdocs/sqlite3.c /^static int parseYyyyMmDd(const char *zDate, DateTime *p){$/;" f file: +parserAddExprIdListTerm testdocs/sqlite3.c /^ static ExprList *parserAddExprIdListTerm($/;" f file: +parserDoubleLinkSelect testdocs/sqlite3.c /^ static void parserDoubleLinkSelect(Parse *pParse, Select *p){$/;" f file: +path edit.h /^ char* path; \/* the path to the open file *\/$/;" m struct:__anon5 +patternCompare testdocs/sqlite3.c /^static int patternCompare($/;" f file: +payloadSize testdocs/sqlite3.c /^ u32 payloadSize; \/* Total number of bytes in the record *\/$/;" m struct:VdbeCursor file: +pc testdocs/sqlite3.c /^ int pc; \/* Program Counter in parent (calling) frame *\/$/;" m struct:VdbeFrame file: +pc testdocs/sqlite3.c /^ int pc; \/* The program counter *\/$/;" m struct:Vdbe file: +pcache1 testdocs/sqlite3.c /^#define pcache1 /;" d file: +pcache1Alloc testdocs/sqlite3.c /^static void *pcache1Alloc(int nByte){$/;" f file: +pcache1AllocPage testdocs/sqlite3.c /^static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){$/;" f file: +pcache1Cachesize testdocs/sqlite3.c /^static void pcache1Cachesize(sqlite3_pcache *p, int nMax){$/;" f file: +pcache1Create testdocs/sqlite3.c /^static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){$/;" f file: +pcache1Destroy testdocs/sqlite3.c /^static void pcache1Destroy(sqlite3_pcache *p){$/;" f file: +pcache1EnforceMaxPage testdocs/sqlite3.c /^static void pcache1EnforceMaxPage(PCache1 *pCache){$/;" f file: +pcache1EnterMutex testdocs/sqlite3.c /^# define pcache1EnterMutex(/;" d file: +pcache1Fetch testdocs/sqlite3.c /^static sqlite3_pcache_page *pcache1Fetch($/;" f file: +pcache1FetchNoMutex testdocs/sqlite3.c /^static PgHdr1 *pcache1FetchNoMutex($/;" f file: +pcache1FetchStage2 testdocs/sqlite3.c /^static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2($/;" f file: +pcache1FetchWithMutex testdocs/sqlite3.c /^static PgHdr1 *pcache1FetchWithMutex($/;" f file: +pcache1Free testdocs/sqlite3.c /^static void pcache1Free(void *p){$/;" f file: +pcache1FreePage testdocs/sqlite3.c /^static void pcache1FreePage(PgHdr1 *p){$/;" f file: +pcache1Init testdocs/sqlite3.c /^static int pcache1Init(void *NotUsed){$/;" f file: +pcache1InitBulk testdocs/sqlite3.c /^static int pcache1InitBulk(PCache1 *pCache){$/;" f file: +pcache1LeaveMutex testdocs/sqlite3.c /^# define pcache1LeaveMutex(/;" d file: +pcache1MemSize testdocs/sqlite3.c /^static int pcache1MemSize(void *p){$/;" f file: +pcache1Pagecount testdocs/sqlite3.c /^static int pcache1Pagecount(sqlite3_pcache *p){$/;" f file: +pcache1PinPage testdocs/sqlite3.c /^static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){$/;" f file: +pcache1Rekey testdocs/sqlite3.c /^static void pcache1Rekey($/;" f file: +pcache1RemoveFromHash testdocs/sqlite3.c /^static void pcache1RemoveFromHash(PgHdr1 *pPage, int freeFlag){$/;" f file: +pcache1ResizeHash testdocs/sqlite3.c /^static void pcache1ResizeHash(PCache1 *p){$/;" f file: +pcache1Shrink testdocs/sqlite3.c /^static void pcache1Shrink(sqlite3_pcache *p){$/;" f file: +pcache1Shutdown testdocs/sqlite3.c /^static void pcache1Shutdown(void *NotUsed){$/;" f file: +pcache1Truncate testdocs/sqlite3.c /^static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){$/;" f file: +pcache1TruncateUnsafe testdocs/sqlite3.c /^static void pcache1TruncateUnsafe($/;" f file: +pcache1UnderMemoryPressure testdocs/sqlite3.c /^static int pcache1UnderMemoryPressure(PCache1 *pCache){$/;" f file: +pcache1Unpin testdocs/sqlite3.c /^static void pcache1Unpin($/;" f file: +pcache1_g testdocs/sqlite3.c /^} pcache1_g;$/;" v typeref:struct:PCacheGlobal file: +pcache2 testdocs/sqlite3.c /^ sqlite3_pcache_methods2 pcache2; \/* Low-level page-cache interface *\/$/;" m struct:Sqlite3Config file: +pcacheDump testdocs/sqlite3.c /^ void pcacheDump(PCache *pCache){$/;" f +pcacheDump testdocs/sqlite3.c /^# define pcacheDump(/;" d file: +pcacheFetchFinishWithInit testdocs/sqlite3.c /^static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit($/;" f file: +pcacheManageDirtyList testdocs/sqlite3.c /^static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){$/;" f file: +pcacheMergeDirtyList testdocs/sqlite3.c /^static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){$/;" f file: +pcacheSortDirtyList testdocs/sqlite3.c /^static PgHdr *pcacheSortDirtyList(PgHdr *pIn){$/;" f file: +pcacheTrace testdocs/sqlite3.c /^# define pcacheTrace(/;" d file: +pcacheUnpin testdocs/sqlite3.c /^static void pcacheUnpin(PgHdr *p){$/;" f file: +pgidx testdocs/sqlite3.c /^ Fts5Buffer pgidx; \/* Buffer containing page-index *\/$/;" m struct:Fts5PageWriter file: +pgno testdocs/sqlite3.c /^ Pgno pgno; \/* Page number for this page *\/$/;" m struct:PgHdr file: +pgno testdocs/sqlite3.c /^ Pgno pgno; \/* Page number for this page *\/$/;" m struct:MemPage file: +pgno testdocs/sqlite3.c /^ int pgno; \/* Page number for this page *\/$/;" m struct:Fts5DlidxWriter file: +pgno testdocs/sqlite3.c /^ int pgno; \/* Page number for this page *\/$/;" m struct:Fts5PageWriter file: +pgnoFirst testdocs/sqlite3.c /^ int pgnoFirst; \/* First leaf page number in segment *\/$/;" m struct:Fts5StructureSegment file: +pgnoLast testdocs/sqlite3.c /^ int pgnoLast; \/* Last leaf page number in segment *\/$/;" m struct:Fts5StructureSegment file: +pgnoRoot testdocs/sqlite3.c /^ Pgno pgnoRoot; \/* The root page of this tree *\/$/;" m struct:BtCursor file: +pgnoRoot testdocs/sqlite3.c /^ Pgno pgnoRoot; \/* Root page of the open btree cursor *\/$/;" m struct:VdbeCursor file: +pgsz testdocs/sqlite3.c /^ int pgsz; \/* Approximate page size used in %_data *\/$/;" m struct:Fts5Config file: +pgsz testdocs/sqlite3.c /^ int pgsz; \/* Main database page size *\/$/;" m struct:VdbeSorter file: +pgsz testdocs/sqlite3.c /^ int pgsz;$/;" m struct:sqlite3rbu file: +pnByte testdocs/sqlite3.c /^ int *pnByte; \/* Pointer to bytes counter *\/$/;" m struct:Fts5Hash file: +pnBytesFreed testdocs/sqlite3.c /^ int *pnBytesFreed; \/* If not NULL, increment this in DbFree() *\/$/;" m struct:sqlite3 file: +populateCellCache testdocs/sqlite3.c /^static void populateCellCache(CellArray *p, int idx, int N){$/;" f file: +porterClose testdocs/sqlite3.c /^static int porterClose(sqlite3_tokenizer_cursor *pCursor){$/;" f file: +porterCreate testdocs/sqlite3.c /^static int porterCreate($/;" f file: +porterDestroy testdocs/sqlite3.c /^static int porterDestroy(sqlite3_tokenizer *pTokenizer){$/;" f file: +porterIdChar testdocs/sqlite3.c /^static const char porterIdChar[] = {$/;" v file: +porterNext testdocs/sqlite3.c /^static int porterNext($/;" f file: +porterOpen testdocs/sqlite3.c /^static int porterOpen($/;" f file: +porterTokenizerModule testdocs/sqlite3.c /^static const sqlite3_tokenizer_module porterTokenizerModule = {$/;" v file: +porter_stemmer testdocs/sqlite3.c /^static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){$/;" f file: +porter_tokenizer testdocs/sqlite3.c /^typedef struct porter_tokenizer {$/;" s file: +porter_tokenizer testdocs/sqlite3.c /^} porter_tokenizer;$/;" t typeref:struct:porter_tokenizer file: +porter_tokenizer_cursor testdocs/sqlite3.c /^typedef struct porter_tokenizer_cursor {$/;" s file: +porter_tokenizer_cursor testdocs/sqlite3.c /^} porter_tokenizer_cursor;$/;" t typeref:struct:porter_tokenizer_cursor file: +posixOpen testdocs/sqlite3.c /^static int posixOpen(const char *zFile, int flags, int mode){$/;" f file: +posixUnlock testdocs/sqlite3.c /^static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){$/;" f file: +poslist testdocs/sqlite3.c /^ Fts5Buffer poslist; \/* Buffer containing current poslist *\/$/;" m struct:Fts5Iter file: +poslist testdocs/sqlite3.c /^ Fts5Buffer poslist; \/* Current position list *\/$/;" m struct:Fts5ExprPhrase file: +ppNextElem testdocs/sqlite3.c /^ Fts3HashElem **ppNextElem;$/;" m struct:Fts3SegReader file: +ppRec testdocs/sqlite3.c /^ UnpackedRecord **ppRec;$/;" m struct:ValueNewStat4Ctx file: +ppWhere testdocs/sqlite3.c /^ Expr **ppWhere;$/;" m struct:HavingToWhereCtx file: +pragCName testdocs/sqlite3.c /^static const char *const pragCName[] = {$/;" v file: +pragmaLocate testdocs/sqlite3.c /^static const PragmaName *pragmaLocate(const char *zName){$/;" f file: +pragmaVtabBestIndex testdocs/sqlite3.c /^static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){$/;" f file: +pragmaVtabClose testdocs/sqlite3.c /^static int pragmaVtabClose(sqlite3_vtab_cursor *cur){$/;" f file: +pragmaVtabColumn testdocs/sqlite3.c /^static int pragmaVtabColumn($/;" f file: +pragmaVtabConnect testdocs/sqlite3.c /^static int pragmaVtabConnect($/;" f file: +pragmaVtabCursorClear testdocs/sqlite3.c /^static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){$/;" f file: +pragmaVtabDisconnect testdocs/sqlite3.c /^static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){$/;" f file: +pragmaVtabEof testdocs/sqlite3.c /^static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){$/;" f file: +pragmaVtabFilter testdocs/sqlite3.c /^static int pragmaVtabFilter($/;" f file: +pragmaVtabModule testdocs/sqlite3.c /^static const sqlite3_module pragmaVtabModule = {$/;" v file: +pragmaVtabNext testdocs/sqlite3.c /^static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){$/;" f file: +pragmaVtabOpen testdocs/sqlite3.c /^static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){$/;" f file: +pragmaVtabRowid testdocs/sqlite3.c /^static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){$/;" f file: +prefix testdocs/sqlite3.c /^ etByte prefix; \/* Offset into aPrefix[] of the prefix string *\/$/;" m struct:et_info file: +prepare testdocs/sqlite3.c /^ int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);$/;" m struct:sqlite3_api_routines file: +prepare16 testdocs/sqlite3.c /^ int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);$/;" m struct:sqlite3_api_routines file: +prepare16_v2 testdocs/sqlite3.c /^ int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);$/;" m struct:sqlite3_api_routines file: +prepareAndCollectError testdocs/sqlite3.c /^static int prepareAndCollectError($/;" f file: +prepareFreeAndCollectError testdocs/sqlite3.c /^static int prepareFreeAndCollectError($/;" f file: +prepare_v2 testdocs/sqlite3.c /^ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);$/;" m struct:sqlite3_api_routines file: +prereq testdocs/sqlite3.c /^ Bitmask prereq; \/* Bitmask of other loops that must run first *\/$/;" m struct:WhereLoop file: +prereq testdocs/sqlite3.c /^ Bitmask prereq; \/* Prerequisites *\/$/;" m struct:WhereOrCost file: +prereqAll testdocs/sqlite3.c /^ Bitmask prereqAll; \/* Bitmask of tables referenced by pExpr *\/$/;" m struct:WhereTerm file: +prereqRight testdocs/sqlite3.c /^ Bitmask prereqRight; \/* Bitmask of tables used by pExpr->pRight *\/$/;" m struct:WhereTerm file: +prev testdocs/sqlite3.c /^ u32 prev; \/* Index in mem3.aPool[] of previous free chunk *\/$/;" m struct:Mem3Block::__anon21::__anon23 file: +prev testdocs/sqlite3.c /^ Fts3HashElem *next, *prev; \/* Next and previous elements in the table *\/$/;" m struct:Fts3HashElem file: +prev testdocs/sqlite3.c /^ HashElem *next, *prev; \/* Next and previous elements in the table *\/$/;" m struct:HashElem file: +prev testdocs/sqlite3.c /^ int prev; \/* Index of previous free chunk *\/$/;" m struct:Mem5Link file: +prevSize testdocs/sqlite3.c /^ u32 prevSize; \/* Size of previous chunk in Mem3Block elements *\/$/;" m struct:Mem3Block::__anon21::__anon22 file: +print_error stdc.h /^#define print_error(/;" d +print_pager_state testdocs/sqlite3.c /^static char *print_pager_state(Pager *p){$/;" f file: +printfFlags testdocs/sqlite3.c /^ u8 printfFlags; \/* SQLITE_PRINTF flags below *\/$/;" m struct:StrAccum file: +printfFunc testdocs/sqlite3.c /^static void printfFunc($/;" f file: +profile testdocs/sqlite3.c /^ void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);$/;" m struct:sqlite3_api_routines file: +progress_handler testdocs/sqlite3.c /^ void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);$/;" m struct:sqlite3_api_routines file: +proxyBreakConchLock testdocs/sqlite3.c /^static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){$/;" f file: +proxyCheckReservedLock testdocs/sqlite3.c /^static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) {$/;" f file: +proxyClose testdocs/sqlite3.c /^static int proxyClose(sqlite3_file *id) {$/;" f file: +proxyConchLock testdocs/sqlite3.c /^static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){$/;" f file: +proxyCreateConchPathname testdocs/sqlite3.c /^static int proxyCreateConchPathname(char *dbPath, char **pConchPath){$/;" f file: +proxyCreateLockPath testdocs/sqlite3.c /^static int proxyCreateLockPath(const char *lockPath){$/;" f file: +proxyCreateUnixFile testdocs/sqlite3.c /^static int proxyCreateUnixFile($/;" f file: +proxyFileControl testdocs/sqlite3.c /^static int proxyFileControl(sqlite3_file *id, int op, void *pArg){$/;" f file: +proxyGetDbPathForUnixFile testdocs/sqlite3.c /^static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){$/;" f file: +proxyGetHostID testdocs/sqlite3.c /^static int proxyGetHostID(unsigned char *pHostID, int *pError){$/;" f file: +proxyGetLockPath testdocs/sqlite3.c /^static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){$/;" f file: +proxyLock testdocs/sqlite3.c /^static int proxyLock(sqlite3_file *id, int eFileLock) {$/;" f file: +proxyLockingContext testdocs/sqlite3.c /^struct proxyLockingContext {$/;" s file: +proxyLockingContext testdocs/sqlite3.c /^typedef struct proxyLockingContext proxyLockingContext;$/;" t typeref:struct:proxyLockingContext file: +proxyReleaseConch testdocs/sqlite3.c /^static int proxyReleaseConch(unixFile *pFile){$/;" f file: +proxyTakeConch testdocs/sqlite3.c /^static int proxyTakeConch(unixFile *pFile){$/;" f file: +proxyTransformUnixFile testdocs/sqlite3.c /^static int proxyTransformUnixFile(unixFile *pFile, const char *path) {$/;" f file: +proxyUnlock testdocs/sqlite3.c /^static int proxyUnlock(sqlite3_file *id, int eFileLock) {$/;" f file: +pseudoTableReg testdocs/sqlite3.c /^ int pseudoTableReg; \/* CURTYPE_PSEUDO. Reg holding content. *\/$/;" m union:VdbeCursor::__anon18 file: +pthreadMutexAlloc testdocs/sqlite3.c /^static sqlite3_mutex *pthreadMutexAlloc(int iType){$/;" f file: +pthreadMutexEnd testdocs/sqlite3.c /^static int pthreadMutexEnd(void){ return SQLITE_OK; }$/;" f file: +pthreadMutexEnter testdocs/sqlite3.c /^static void pthreadMutexEnter(sqlite3_mutex *p){$/;" f file: +pthreadMutexFree testdocs/sqlite3.c /^static void pthreadMutexFree(sqlite3_mutex *p){$/;" f file: +pthreadMutexHeld testdocs/sqlite3.c /^static int pthreadMutexHeld(sqlite3_mutex *p){$/;" f file: +pthreadMutexInit testdocs/sqlite3.c /^static int pthreadMutexInit(void){ return SQLITE_OK; }$/;" f file: +pthreadMutexLeave testdocs/sqlite3.c /^static void pthreadMutexLeave(sqlite3_mutex *p){$/;" f file: +pthreadMutexNotheld testdocs/sqlite3.c /^static int pthreadMutexNotheld(sqlite3_mutex *p){$/;" f file: +pthreadMutexTry testdocs/sqlite3.c /^static int pthreadMutexTry(sqlite3_mutex *p){$/;" f file: +ptrmapGet testdocs/sqlite3.c /^ #define ptrmapGet(/;" d file: +ptrmapGet testdocs/sqlite3.c /^static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){$/;" f file: +ptrmapPageno testdocs/sqlite3.c /^static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){$/;" f file: +ptrmapPut testdocs/sqlite3.c /^ #define ptrmapPut(/;" d file: +ptrmapPut testdocs/sqlite3.c /^static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){$/;" f file: +ptrmapPutOvflPtr testdocs/sqlite3.c /^ #define ptrmapPutOvflPtr(/;" d file: +ptrmapPutOvflPtr testdocs/sqlite3.c /^static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){$/;" f file: +pushDownWhereTerms testdocs/sqlite3.c /^static int pushDownWhereTerms($/;" f file: +pushOntoSorter testdocs/sqlite3.c /^static void pushOntoSorter($/;" f file: +put2byte testdocs/sqlite3.c /^#define put2byte(/;" d file: +put32bits testdocs/sqlite3.c /^#define put32bits(/;" d file: +put4byte testdocs/sqlite3.c /^#define put4byte /;" d file: +putVarint testdocs/sqlite3.c /^#define putVarint /;" d file: +putVarint32 testdocs/sqlite3.c /^#define putVarint32(/;" d file: +putVarint64 testdocs/sqlite3.c /^static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){$/;" f file: +pzErrMsg testdocs/sqlite3.c /^ char **pzErrMsg; \/* Error message stored here *\/$/;" m struct:__anon16 file: +pzErrmsg testdocs/sqlite3.c /^ char **pzErrmsg;$/;" m struct:Fts5Config file: +querySharedCacheTableLock testdocs/sqlite3.c /^ #define querySharedCacheTableLock(/;" d file: +querySharedCacheTableLock testdocs/sqlite3.c /^static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){$/;" f file: +queryTestTokenizer testdocs/sqlite3.c /^static int queryTestTokenizer($/;" f file: +queryTokenizer testdocs/sqlite3.c /^int queryTokenizer($/;" f file: +quoteFunc testdocs/sqlite3.c /^static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){$/;" f file: +r testdocs/sqlite3.c /^ double r; \/* Real value used when MEM_Real is set in flags *\/$/;" m union:sqlite3_value::MemValue file: +r1 testdocs/sqlite3.c /^ i8 r1; \/* Value to return if (lhs > rhs) *\/$/;" m struct:UnpackedRecord file: +r2 testdocs/sqlite3.c /^ i8 r2; \/* Value to return if (rhs < lhs) *\/$/;" m struct:UnpackedRecord file: +rCost testdocs/sqlite3.c /^ LogEst rCost; \/* Total cost of this path *\/$/;" m struct:WherePath file: +rLimit testdocs/sqlite3.c /^ double rLimit; \/* Maximum NNN value for this transform *\/$/;" m struct:__anon19 file: +rParentScore testdocs/sqlite3.c /^ sqlite3_rtree_dbl rParentScore; \/* Score of parent node *\/$/;" m struct:sqlite3_rtree_query_info file: +rRun testdocs/sqlite3.c /^ LogEst rRun; \/* Cost of running each loop *\/$/;" m struct:WhereLoop file: +rRun testdocs/sqlite3.c /^ LogEst rRun; \/* Cost of running this subquery *\/$/;" m struct:WhereOrCost file: +rScore testdocs/sqlite3.c /^ RtreeDValue rScore; \/* The score for this node. Smallest goes first. *\/$/;" m struct:RtreeSearchPoint file: +rScore testdocs/sqlite3.c /^ sqlite3_rtree_dbl rScore; \/* OUT: Write the score here *\/$/;" m struct:sqlite3_rtree_query_info file: +rSetup testdocs/sqlite3.c /^ LogEst rSetup; \/* One-time setup cost (ex: create transient index) *\/$/;" m struct:WhereLoop file: +rSum testdocs/sqlite3.c /^ double rSum; \/* Floating point sum *\/$/;" m struct:SumCtx file: +rUnsorted testdocs/sqlite3.c /^ LogEst rUnsorted; \/* Total cost of this path ignoring sorting costs *\/$/;" m struct:WherePath file: +rValue testdocs/sqlite3.c /^ RtreeDValue rValue; \/* Constraint value. *\/$/;" m union:RtreeConstraint::__anon36 file: +rXform testdocs/sqlite3.c /^ double rXform; \/* Constant used for this transform *\/$/;" m struct:__anon19 file: +randomBlob testdocs/sqlite3.c /^static void randomBlob($/;" f file: +randomFill testdocs/sqlite3.c /^static void randomFill(char *pBuf, int nByte){$/;" f file: +randomFunc testdocs/sqlite3.c /^static void randomFunc($/;" f file: +randomness testdocs/sqlite3.c /^ void (*randomness)(int,void*);$/;" m struct:sqlite3_api_routines file: +randomnessPid testdocs/sqlite3.c /^static pid_t randomnessPid = 0;$/;" v file: +rawS testdocs/sqlite3.c /^ char rawS; \/* Raw numeric value stored in s *\/$/;" m struct:DateTime file: +rbuAllocateIterArrays testdocs/sqlite3.c /^static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){$/;" f file: +rbuBadControlError testdocs/sqlite3.c /^static void rbuBadControlError(sqlite3rbu *p){$/;" f file: +rbuCaptureDbWrite testdocs/sqlite3.c /^static int rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){$/;" f file: +rbuCaptureWalRead testdocs/sqlite3.c /^static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){$/;" f file: +rbuCheckpointFrame testdocs/sqlite3.c /^static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){$/;" f file: +rbuCopyPragma testdocs/sqlite3.c /^static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){$/;" f file: +rbuCreateImposterTable testdocs/sqlite3.c /^static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){$/;" f file: +rbuCreateImposterTable2 testdocs/sqlite3.c /^static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){$/;" f file: +rbuCreateTargetSchema testdocs/sqlite3.c /^static void rbuCreateTargetSchema(sqlite3rbu *p){$/;" f file: +rbuCreateVfs testdocs/sqlite3.c /^static void rbuCreateVfs(sqlite3rbu *p){$/;" f file: +rbuDeleteOalFile testdocs/sqlite3.c /^static void rbuDeleteOalFile(sqlite3rbu *p){$/;" f file: +rbuDeleteVfs testdocs/sqlite3.c /^static void rbuDeleteVfs(sqlite3rbu *p){$/;" f file: +rbuDeltaApply testdocs/sqlite3.c /^static int rbuDeltaApply($/;" f file: +rbuDeltaChecksum testdocs/sqlite3.c /^static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){$/;" f file: +rbuDeltaGetInt testdocs/sqlite3.c /^static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){$/;" f file: +rbuDeltaOutputSize testdocs/sqlite3.c /^static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){$/;" f file: +rbuEditErrmsg testdocs/sqlite3.c /^static void rbuEditErrmsg(sqlite3rbu *p){$/;" f file: +rbuFileSuffix3 testdocs/sqlite3.c /^static void rbuFileSuffix3(const char *zBase, char *z){$/;" f file: +rbuFinalize testdocs/sqlite3.c /^static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){$/;" f file: +rbuFindMaindb testdocs/sqlite3.c /^static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){$/;" f file: +rbuFossilDeltaFunc testdocs/sqlite3.c /^static void rbuFossilDeltaFunc($/;" f file: +rbuFreeState testdocs/sqlite3.c /^static void rbuFreeState(RbuState *p){$/;" f file: +rbuGetU32 testdocs/sqlite3.c /^static u32 rbuGetU32(u8 *aBuf){$/;" f file: +rbuGetUpdateStmt testdocs/sqlite3.c /^static int rbuGetUpdateStmt($/;" f file: +rbuIncrSchemaCookie testdocs/sqlite3.c /^static void rbuIncrSchemaCookie(sqlite3rbu *p){$/;" f file: +rbuIndexCntFunc testdocs/sqlite3.c /^static void rbuIndexCntFunc($/;" f file: +rbuInitPhaseOneSteps testdocs/sqlite3.c /^static void rbuInitPhaseOneSteps(sqlite3rbu *p){$/;" f file: +rbuIsVacuum testdocs/sqlite3.c /^#define rbuIsVacuum(/;" d file: +rbuLoadState testdocs/sqlite3.c /^static RbuState *rbuLoadState(sqlite3rbu *p){$/;" f file: +rbuLockDatabase testdocs/sqlite3.c /^static void rbuLockDatabase(sqlite3rbu *p){$/;" f file: +rbuMPrintf testdocs/sqlite3.c /^static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){$/;" f file: +rbuMPrintfExec testdocs/sqlite3.c /^static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){$/;" f file: +rbuMainToWal testdocs/sqlite3.c /^static const char *rbuMainToWal(const char *zName, int flags){$/;" f file: +rbuMalloc testdocs/sqlite3.c /^static void *rbuMalloc(sqlite3rbu *p, int nByte){$/;" f file: +rbuMisuseError testdocs/sqlite3.c /^static sqlite3rbu *rbuMisuseError(void){$/;" f file: +rbuMoveOalFile testdocs/sqlite3.c /^static void rbuMoveOalFile(sqlite3rbu *p){$/;" f file: +rbuObjIterCacheIndexedCols testdocs/sqlite3.c /^static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){$/;" f file: +rbuObjIterCacheTableInfo testdocs/sqlite3.c /^static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){$/;" f file: +rbuObjIterClearStatements testdocs/sqlite3.c /^static void rbuObjIterClearStatements(RbuObjIter *pIter){$/;" f file: +rbuObjIterFinalize testdocs/sqlite3.c /^static void rbuObjIterFinalize(RbuObjIter *pIter){$/;" f file: +rbuObjIterFirst testdocs/sqlite3.c /^static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){$/;" f file: +rbuObjIterFreeCols testdocs/sqlite3.c /^static void rbuObjIterFreeCols(RbuObjIter *pIter){$/;" f file: +rbuObjIterGetBindlist testdocs/sqlite3.c /^static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){$/;" f file: +rbuObjIterGetCollist testdocs/sqlite3.c /^static char *rbuObjIterGetCollist($/;" f file: +rbuObjIterGetIndexCols testdocs/sqlite3.c /^static char *rbuObjIterGetIndexCols($/;" f file: +rbuObjIterGetOldlist testdocs/sqlite3.c /^static char *rbuObjIterGetOldlist($/;" f file: +rbuObjIterGetSetlist testdocs/sqlite3.c /^static char *rbuObjIterGetSetlist($/;" f file: +rbuObjIterGetWhere testdocs/sqlite3.c /^static char *rbuObjIterGetWhere($/;" f file: +rbuObjIterNext testdocs/sqlite3.c /^static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){$/;" f file: +rbuObjIterPrepareAll testdocs/sqlite3.c /^static int rbuObjIterPrepareAll($/;" f file: +rbuObjIterPrepareTmpInsert testdocs/sqlite3.c /^static void rbuObjIterPrepareTmpInsert($/;" f file: +rbuOpenDatabase testdocs/sqlite3.c /^static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){$/;" f file: +rbuOpenDbhandle testdocs/sqlite3.c /^static sqlite3 *rbuOpenDbhandle($/;" f file: +rbuPutU16 testdocs/sqlite3.c /^static void rbuPutU16(u8 *aBuf, u16 iVal){$/;" f file: +rbuPutU32 testdocs/sqlite3.c /^static void rbuPutU32(u8 *aBuf, u32 iVal){$/;" f file: +rbuSaveState testdocs/sqlite3.c /^static void rbuSaveState(sqlite3rbu *p, int eStage){$/;" f file: +rbuSetupCheckpoint testdocs/sqlite3.c /^static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){$/;" f file: +rbuSetupOal testdocs/sqlite3.c /^static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){$/;" f file: +rbuShmChecksum testdocs/sqlite3.c /^static i64 rbuShmChecksum(sqlite3rbu *p){$/;" f file: +rbuStep testdocs/sqlite3.c /^static int rbuStep(sqlite3rbu *p){$/;" f file: +rbuStepOneOp testdocs/sqlite3.c /^static void rbuStepOneOp(sqlite3rbu *p, int eType){$/;" f file: +rbuStepType testdocs/sqlite3.c /^static int rbuStepType(sqlite3rbu *p, const char **pzMask){$/;" f file: +rbuStrCompare testdocs/sqlite3.c /^static int rbuStrCompare(const char *z1, const char *z2){$/;" f file: +rbuStrndup testdocs/sqlite3.c /^static char *rbuStrndup(const char *zStr, int *pRc){$/;" f file: +rbuTableType testdocs/sqlite3.c /^static void rbuTableType($/;" f file: +rbuTargetNameFunc testdocs/sqlite3.c /^static void rbuTargetNameFunc($/;" f file: +rbuTmpInsertFunc testdocs/sqlite3.c /^static void rbuTmpInsertFunc($/;" f file: +rbuUnlockShm testdocs/sqlite3.c /^static void rbuUnlockShm(rbu_file *p){$/;" f file: +rbuVfsAccess testdocs/sqlite3.c /^static int rbuVfsAccess($/;" f file: +rbuVfsCheckReservedLock testdocs/sqlite3.c /^static int rbuVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){$/;" f file: +rbuVfsClose testdocs/sqlite3.c /^static int rbuVfsClose(sqlite3_file *pFile){$/;" f file: +rbuVfsCurrentTime testdocs/sqlite3.c /^static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){$/;" f file: +rbuVfsDelete testdocs/sqlite3.c /^static int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){$/;" f file: +rbuVfsDeviceCharacteristics testdocs/sqlite3.c /^static int rbuVfsDeviceCharacteristics(sqlite3_file *pFile){$/;" f file: +rbuVfsDlClose testdocs/sqlite3.c /^static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){$/;" f file: +rbuVfsDlError testdocs/sqlite3.c /^static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){$/;" f file: +rbuVfsDlOpen testdocs/sqlite3.c /^static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){$/;" f file: +rbuVfsDlSym testdocs/sqlite3.c /^static void (*rbuVfsDlSym($/;" f file: +rbuVfsFileControl testdocs/sqlite3.c /^static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){$/;" f file: +rbuVfsFileSize testdocs/sqlite3.c /^static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){$/;" f file: +rbuVfsFullPathname testdocs/sqlite3.c /^static int rbuVfsFullPathname($/;" f file: +rbuVfsGetLastError testdocs/sqlite3.c /^static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){$/;" f file: +rbuVfsLock testdocs/sqlite3.c /^static int rbuVfsLock(sqlite3_file *pFile, int eLock){$/;" f file: +rbuVfsOpen testdocs/sqlite3.c /^static int rbuVfsOpen($/;" f file: +rbuVfsRandomness testdocs/sqlite3.c /^static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){$/;" f file: +rbuVfsRead testdocs/sqlite3.c /^static int rbuVfsRead($/;" f file: +rbuVfsSectorSize testdocs/sqlite3.c /^static int rbuVfsSectorSize(sqlite3_file *pFile){$/;" f file: +rbuVfsShmBarrier testdocs/sqlite3.c /^static void rbuVfsShmBarrier(sqlite3_file *pFile){$/;" f file: +rbuVfsShmLock testdocs/sqlite3.c /^static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){$/;" f file: +rbuVfsShmMap testdocs/sqlite3.c /^static int rbuVfsShmMap($/;" f file: +rbuVfsShmUnmap testdocs/sqlite3.c /^static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){$/;" f file: +rbuVfsSleep testdocs/sqlite3.c /^static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){$/;" f file: +rbuVfsSync testdocs/sqlite3.c /^static int rbuVfsSync(sqlite3_file *pFile, int flags){$/;" f file: +rbuVfsTruncate testdocs/sqlite3.c /^static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){$/;" f file: +rbuVfsUnlock testdocs/sqlite3.c /^static int rbuVfsUnlock(sqlite3_file *pFile, int eLock){$/;" f file: +rbuVfsWrite testdocs/sqlite3.c /^static int rbuVfsWrite($/;" f file: +rbuWinUtf8ToUnicode testdocs/sqlite3.c /^static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){$/;" f file: +rbuWithoutRowidPK testdocs/sqlite3.c /^static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){$/;" f file: +rbu_file testdocs/sqlite3.c /^struct rbu_file {$/;" s file: +rbu_file testdocs/sqlite3.c /^typedef struct rbu_file rbu_file;$/;" t typeref:struct:rbu_file file: +rbu_vfs testdocs/sqlite3.c /^struct rbu_vfs {$/;" s file: +rbu_vfs testdocs/sqlite3.c /^typedef struct rbu_vfs rbu_vfs;$/;" t typeref:struct:rbu_vfs file: +rc testdocs/sqlite3.c /^ int rc; \/* Current error code *\/$/;" m struct:Fts5Index file: +rc testdocs/sqlite3.c /^ int rc; \/* Error code *\/$/;" m struct:sqlite3_changegroup file: +rc testdocs/sqlite3.c /^ int rc; \/* Iterator error code *\/$/;" m struct:sqlite3_changeset_iter file: +rc testdocs/sqlite3.c /^ int rc; \/* Non-zero if an error has occurred *\/$/;" m struct:sqlite3_session file: +rc testdocs/sqlite3.c /^ int rc; \/* Value returned by last rbu_step() call *\/$/;" m struct:sqlite3rbu file: +rc testdocs/sqlite3.c /^ int rc; \/* Backup process error code *\/$/;" m struct:sqlite3_backup file: +rc testdocs/sqlite3.c /^ int rc; \/* Value to return *\/$/;" m struct:Vdbe file: +rc testdocs/sqlite3.c /^ int rc; \/* Return code from execution *\/$/;" m struct:Parse file: +rc testdocs/sqlite3.c /^ int rc; \/* Result code stored here *\/$/;" m struct:__anon16 file: +rc testdocs/sqlite3.c /^ int rc; \/* Return code from sqlite3_exec() *\/$/;" m struct:TabResult file: +rc testdocs/sqlite3.c /^ int rc;$/;" m struct:Fts5Parse file: +rc testdocs/sqlite3.c /^ int rc;$/;" m struct:TokenCtx file: +rcApp testdocs/sqlite3.c /^ int rcApp; \/* errcode set by sqlite3_result_error_code() *\/$/;" m struct:Vdbe file: +read32bits testdocs/sqlite3.c /^static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){$/;" f file: +readCoord testdocs/sqlite3.c /^static void readCoord(u8 *p, RtreeCoord *pCoord){$/;" f file: +readDbPage testdocs/sqlite3.c /^static int readDbPage(PgHdr *pPg, u32 iFrame){$/;" f file: +readInt16 testdocs/sqlite3.c /^static int readInt16(u8 *p){$/;" f file: +readInt64 testdocs/sqlite3.c /^static i64 readInt64(u8 *p){$/;" f file: +readJournalHdr testdocs/sqlite3.c /^static int readJournalHdr($/;" f file: +readLock testdocs/sqlite3.c /^ i16 readLock; \/* Which read lock is being held. -1 for none *\/$/;" m struct:Wal file: +readMasterJournal testdocs/sqlite3.c /^static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){$/;" f file: +readOnly testdocs/sqlite3.c /^ bft readOnly:1; \/* True for statements that do not write *\/$/;" m struct:Vdbe file: +readOnly testdocs/sqlite3.c /^ u8 readOnly; \/* True for a read-only database *\/$/;" m struct:Pager file: +readOnly testdocs/sqlite3.c /^ u8 readOnly; \/* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY *\/$/;" m struct:Wal file: +reader testdocs/sqlite3.c /^ Fts5LookaheadReader reader; \/* Input iterator *\/$/;" m struct:Fts5NearTrimmer file: +readpoint testdocs/sqlite3.c /^ FilePoint readpoint; \/* Pointer to the end of the last xRead() *\/$/;" m struct:MemJournal file: +readsTable testdocs/sqlite3.c /^static int readsTable(Parse *p, int iDb, Table *pTab){$/;" f file: +realloc testdocs/sqlite3.c /^ void *(*realloc)(void*,int);$/;" m struct:sqlite3_api_routines file: +realloc64 testdocs/sqlite3.c /^ void *(*realloc64)(void*,sqlite3_uint64);$/;" m struct:sqlite3_api_routines file: +rebuildPage testdocs/sqlite3.c /^static int rebuildPage($/;" f file: +recordFunc testdocs/sqlite3.c /^static void recordFunc($/;" f file: +redo edit.h /^ Log* redo; \/* redo list *\/$/;" m struct:__anon5 +regCtr testdocs/sqlite3.c /^ int regCtr; \/* Memory register holding the rowid counter *\/$/;" m struct:AutoincInfo file: +regResult testdocs/sqlite3.c /^ int regResult; \/* Registers holding results of a co-routine *\/$/;" m struct:SrcList::SrcList_item file: +regReturn testdocs/sqlite3.c /^ int regReturn; \/* Register holding return address of addrFillSub *\/$/;" m struct:SrcList::SrcList_item file: +regReturn testdocs/sqlite3.c /^ int regReturn; \/* Register holding block-output return address *\/$/;" m struct:SortCtx file: +regRoot testdocs/sqlite3.c /^ int regRoot; \/* Register holding root page number for new objects *\/$/;" m struct:Parse file: +regRowid testdocs/sqlite3.c /^ int regRowid; \/* Register holding rowid of CREATE TABLE entry *\/$/;" m struct:Parse file: +registerTokenizer testdocs/sqlite3.c /^int registerTokenizer($/;" f file: +registerTrace testdocs/sqlite3.c /^static void registerTrace(int iReg, Mem *p){$/;" f file: +rehash testdocs/sqlite3.c /^static int rehash(Hash *pH, unsigned int new_size){$/;" f file: +reindexDatabases testdocs/sqlite3.c /^static void reindexDatabases(Parse *pParse, char const *zColl){$/;" f file: +reindexTable testdocs/sqlite3.c /^static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){$/;" f file: +reinsertNodeContent testdocs/sqlite3.c /^static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){$/;" f file: +releaseAllSavepoints testdocs/sqlite3.c /^static void releaseAllSavepoints(Pager *pPager){$/;" f file: +releaseInodeInfo testdocs/sqlite3.c /^static void releaseInodeInfo(unixFile *pFile){$/;" f file: +releaseMemArray testdocs/sqlite3.c /^static void releaseMemArray(Mem *p, int N){$/;" f file: +releasePage testdocs/sqlite3.c /^static void releasePage(MemPage *pPage){$/;" f file: +releasePageNotNull testdocs/sqlite3.c /^static void releasePageNotNull(MemPage *pPage){$/;" f file: +release_memory testdocs/sqlite3.c /^ int (*release_memory)(int);$/;" m struct:sqlite3_api_routines file: +reloadTableSchema testdocs/sqlite3.c /^static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){$/;" f file: +relocatePage testdocs/sqlite3.c /^static int relocatePage($/;" f file: +removeElementGivenHash testdocs/sqlite3.c /^static void removeElementGivenHash($/;" f file: +removeFromBlockedList testdocs/sqlite3.c /^static void removeFromBlockedList(sqlite3 *db){$/;" f file: +removeFromSharingList testdocs/sqlite3.c /^static int removeFromSharingList(BtShared *pBt){$/;" f file: +removeNode testdocs/sqlite3.c /^static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){$/;" f file: +remove_diacritic testdocs/sqlite3.c /^static int remove_diacritic(int c){$/;" f file: +renameParentFunc testdocs/sqlite3.c /^static void renameParentFunc($/;" f file: +renameTableFunc testdocs/sqlite3.c /^static void renameTableFunc($/;" f file: +renameTriggerFunc testdocs/sqlite3.c /^static void renameTriggerFunc($/;" f file: +renderLogMsg testdocs/sqlite3.c /^static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){$/;" f file: +replaceFunc testdocs/sqlite3.c /^static void replaceFunc($/;" f file: +reportError testdocs/sqlite3.c /^static int reportError(int iErr, int lineno, const char *zType){$/;" f file: +reserved testdocs/sqlite3.c /^ int reserved;$/;" m struct:afpLockingContext file: +reset testdocs/sqlite3.c /^ int (*reset)(sqlite3_stmt*pStmt);$/;" m struct:sqlite3_api_routines file: +resetAccumulator testdocs/sqlite3.c /^static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){$/;" f file: +resetAndCollectError testdocs/sqlite3.c /^static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){$/;" f file: +reset_auto_extension testdocs/sqlite3.c /^ void (*reset_auto_extension)(void);$/;" m struct:sqlite3_api_routines file: +resizeIndexObject testdocs/sqlite3.c /^static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){$/;" f file: +resolveAlias testdocs/sqlite3.c /^static void resolveAlias($/;" f file: +resolveAsName testdocs/sqlite3.c /^static int resolveAsName($/;" f file: +resolveAttachExpr testdocs/sqlite3.c /^static int resolveAttachExpr(NameContext *pName, Expr *pExpr)$/;" f file: +resolveCompoundOrderBy testdocs/sqlite3.c /^static int resolveCompoundOrderBy($/;" f file: +resolveExprStep testdocs/sqlite3.c /^static int resolveExprStep(Walker *pWalker, Expr *pExpr){$/;" f file: +resolveOrderByTermToExprList testdocs/sqlite3.c /^static int resolveOrderByTermToExprList($/;" f file: +resolveOrderGroupBy testdocs/sqlite3.c /^static int resolveOrderGroupBy($/;" f file: +resolveOutOfRangeError testdocs/sqlite3.c /^static void resolveOutOfRangeError($/;" f file: +resolveP2Values testdocs/sqlite3.c /^static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){$/;" f file: +resolveSelectStep testdocs/sqlite3.c /^static int resolveSelectStep(Walker *pWalker, Select *p){$/;" f file: +restoreCursorPosition testdocs/sqlite3.c /^#define restoreCursorPosition(/;" d file: +result_blob testdocs/sqlite3.c /^ void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +result_blob64 testdocs/sqlite3.c /^ void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,$/;" m struct:sqlite3_api_routines file: +result_double testdocs/sqlite3.c /^ void (*result_double)(sqlite3_context*,double);$/;" m struct:sqlite3_api_routines file: +result_error testdocs/sqlite3.c /^ void (*result_error)(sqlite3_context*,const char*,int);$/;" m struct:sqlite3_api_routines file: +result_error16 testdocs/sqlite3.c /^ void (*result_error16)(sqlite3_context*,const void*,int);$/;" m struct:sqlite3_api_routines file: +result_error_code testdocs/sqlite3.c /^ void (*result_error_code)(sqlite3_context*,int);$/;" m struct:sqlite3_api_routines file: +result_error_nomem testdocs/sqlite3.c /^ void (*result_error_nomem)(sqlite3_context*);$/;" m struct:sqlite3_api_routines file: +result_error_toobig testdocs/sqlite3.c /^ void (*result_error_toobig)(sqlite3_context*);$/;" m struct:sqlite3_api_routines file: +result_int testdocs/sqlite3.c /^ void (*result_int)(sqlite3_context*,int);$/;" m struct:sqlite3_api_routines file: +result_int64 testdocs/sqlite3.c /^ void (*result_int64)(sqlite3_context*,sqlite_int64);$/;" m struct:sqlite3_api_routines file: +result_null testdocs/sqlite3.c /^ void (*result_null)(sqlite3_context*);$/;" m struct:sqlite3_api_routines file: +result_subtype testdocs/sqlite3.c /^ void (*result_subtype)(sqlite3_context*,unsigned int);$/;" m struct:sqlite3_api_routines file: +result_text testdocs/sqlite3.c /^ void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +result_text16 testdocs/sqlite3.c /^ void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +result_text16be testdocs/sqlite3.c /^ void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +result_text16le testdocs/sqlite3.c /^ void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));$/;" m struct:sqlite3_api_routines file: +result_text64 testdocs/sqlite3.c /^ void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,$/;" m struct:sqlite3_api_routines file: +result_value testdocs/sqlite3.c /^ void (*result_value)(sqlite3_context*,sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +result_zeroblob testdocs/sqlite3.c /^ void (*result_zeroblob)(sqlite3_context*,int);$/;" m struct:sqlite3_api_routines file: +result_zeroblob64 testdocs/sqlite3.c /^ int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);$/;" m struct:sqlite3_api_routines file: +retRangeStart testdocs/sqlite3.c /^ unsigned long long retRangeStart; \/* nbr of 1st byte locked if successful *\/$/;" m struct:ByteRangeLockPB2 file: +returnSingleInt testdocs/sqlite3.c /^static void returnSingleInt(Vdbe *v, i64 value){$/;" f file: +returnSingleText testdocs/sqlite3.c /^static void returnSingleText($/;" f file: +reusable testdocs/sqlite3.c /^ unsigned reusable :1; \/* Constant expression is reusable *\/$/;" m struct:ExprList::ExprList_item file: +revLoop testdocs/sqlite3.c /^ Bitmask revLoop; \/* aLoop[]s that should be reversed for ORDER BY *\/$/;" m struct:WherePath file: +revMask testdocs/sqlite3.c /^ Bitmask revMask; \/* Mask of ORDER BY terms that need reversing *\/$/;" m struct:WhereInfo file: +risblank buf.c /^bool risblank(Rune r) {$/;" f +risword buf.c /^bool risword(Rune r) {$/;" f +robustFchown testdocs/sqlite3.c /^static int robustFchown(int fd, uid_t uid, gid_t gid){$/;" f file: +robust_close testdocs/sqlite3.c /^static void robust_close(unixFile *pFile, int h, int lineno){$/;" f file: +robust_flock testdocs/sqlite3.c /^# define robust_flock(/;" d file: +robust_flock testdocs/sqlite3.c /^static int robust_flock(int fd, int op){$/;" f file: +robust_ftruncate testdocs/sqlite3.c /^static int robust_ftruncate(int h, sqlite3_int64 sz){$/;" f file: +robust_open testdocs/sqlite3.c /^static int robust_open(const char *z, int f, mode_t m){$/;" f file: +rollback_hook testdocs/sqlite3.c /^ void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);$/;" m struct:sqlite3_api_routines file: +rootOnly testdocs/sqlite3.c /^ u8 rootOnly; \/* True for a root-only reader *\/$/;" m struct:Fts3SegReader file: +roundFunc testdocs/sqlite3.c /^static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){$/;" f file: +rowSetEntryAlloc testdocs/sqlite3.c /^static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){$/;" f file: +rowSetEntryMerge testdocs/sqlite3.c /^static struct RowSetEntry *rowSetEntryMerge($/;" f file: +rowSetEntrySort testdocs/sqlite3.c /^static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){$/;" f file: +rowSetListToTree testdocs/sqlite3.c /^static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){$/;" f file: +rowSetNDeepTree testdocs/sqlite3.c /^static struct RowSetEntry *rowSetNDeepTree($/;" f file: +rowSetTreeToList testdocs/sqlite3.c /^static void rowSetTreeToList($/;" f file: +rowid testdocs/sqlite3.c /^ i64 rowid; \/* This table's current rowid value *\/$/;" m struct:Fts5VocabCursor file: +rowidWrite testdocs/sqlite3.c /^static int rowidWrite(Rtree *pRtree, sqlite3_int64 iRowid, sqlite3_int64 iNode){$/;" f file: +rsFlags testdocs/sqlite3.c /^ u16 rsFlags; \/* Various flags *\/$/;" m struct:RowSet file: +rstrlen buf.c /^size_t rstrlen(Rune* runes) {$/;" f +rtreeBeginTransaction testdocs/sqlite3.c /^static int rtreeBeginTransaction(sqlite3_vtab *pVtab){$/;" f file: +rtreeBestIndex testdocs/sqlite3.c /^static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){$/;" f file: +rtreeCallbackConstraint testdocs/sqlite3.c /^static int rtreeCallbackConstraint($/;" f file: +rtreeClose testdocs/sqlite3.c /^static int rtreeClose(sqlite3_vtab_cursor *cur){$/;" f file: +rtreeColumn testdocs/sqlite3.c /^static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){$/;" f file: +rtreeConnect testdocs/sqlite3.c /^static int rtreeConnect($/;" f file: +rtreeConstraintError testdocs/sqlite3.c /^static int rtreeConstraintError(Rtree *pRtree, int iCol){$/;" f file: +rtreeCreate testdocs/sqlite3.c /^static int rtreeCreate($/;" f file: +rtreeDeleteRowid testdocs/sqlite3.c /^static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){$/;" f file: +rtreeDestroy testdocs/sqlite3.c /^static int rtreeDestroy(sqlite3_vtab *pVtab){$/;" f file: +rtreeDisconnect testdocs/sqlite3.c /^static int rtreeDisconnect(sqlite3_vtab *pVtab){$/;" f file: +rtreeEndTransaction testdocs/sqlite3.c /^static int rtreeEndTransaction(sqlite3_vtab *pVtab){$/;" f file: +rtreeEnqueue testdocs/sqlite3.c /^static RtreeSearchPoint *rtreeEnqueue($/;" f file: +rtreeEof testdocs/sqlite3.c /^static int rtreeEof(sqlite3_vtab_cursor *cur){$/;" f file: +rtreeFilter testdocs/sqlite3.c /^static int rtreeFilter($/;" f file: +rtreeFreeCallback testdocs/sqlite3.c /^static void rtreeFreeCallback(void *p){$/;" f file: +rtreeInit testdocs/sqlite3.c /^static int rtreeInit($/;" f file: +rtreeInsertCell testdocs/sqlite3.c /^static int rtreeInsertCell($/;" f file: +rtreeLeafConstraint testdocs/sqlite3.c /^static void rtreeLeafConstraint($/;" f file: +rtreeMatchArgFree testdocs/sqlite3.c /^static void rtreeMatchArgFree(void *pArg){$/;" f file: +rtreeModule testdocs/sqlite3.c /^static sqlite3_module rtreeModule = {$/;" v file: +rtreeNext testdocs/sqlite3.c /^static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){$/;" f file: +rtreeNodeOfFirstSearchPoint testdocs/sqlite3.c /^static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){$/;" f file: +rtreeNonleafConstraint testdocs/sqlite3.c /^static void rtreeNonleafConstraint($/;" f file: +rtreeOpen testdocs/sqlite3.c /^static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){$/;" f file: +rtreeQueryStat1 testdocs/sqlite3.c /^static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){$/;" f file: +rtreeReference testdocs/sqlite3.c /^static void rtreeReference(Rtree *pRtree){$/;" f file: +rtreeRelease testdocs/sqlite3.c /^static void rtreeRelease(Rtree *pRtree){$/;" f file: +rtreeRename testdocs/sqlite3.c /^static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){$/;" f file: +rtreeRowid testdocs/sqlite3.c /^static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){$/;" f file: +rtreeSavepoint testdocs/sqlite3.c /^static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){$/;" f file: +rtreeSearchPointCompare testdocs/sqlite3.c /^static int rtreeSearchPointCompare($/;" f file: +rtreeSearchPointFirst testdocs/sqlite3.c /^static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){$/;" f file: +rtreeSearchPointNew testdocs/sqlite3.c /^static RtreeSearchPoint *rtreeSearchPointNew($/;" f file: +rtreeSearchPointPop testdocs/sqlite3.c /^static void rtreeSearchPointPop(RtreeCursor *p){$/;" f file: +rtreeSearchPointSwap testdocs/sqlite3.c /^static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){$/;" f file: +rtreeSqlInit testdocs/sqlite3.c /^static int rtreeSqlInit($/;" f file: +rtreeStepToLeaf testdocs/sqlite3.c /^static int rtreeStepToLeaf(RtreeCursor *pCur){$/;" f file: +rtreeUpdate testdocs/sqlite3.c /^static int rtreeUpdate($/;" f file: +rtreeValueDown testdocs/sqlite3.c /^static RtreeValue rtreeValueDown(sqlite3_value *v){$/;" f file: +rtreeValueUp testdocs/sqlite3.c /^static RtreeValue rtreeValueUp(sqlite3_value *v){$/;" f file: +rtreedepth testdocs/sqlite3.c /^static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){$/;" f file: +rtreenode testdocs/sqlite3.c /^static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){$/;" f file: +runOnlyOnce testdocs/sqlite3.c /^ bft runOnlyOnce:1; \/* Automatically expire on reset *\/$/;" m struct:Vdbe file: +rune_match buf.c /^static int rune_match(Buf* buf, size_t mbeg, size_t mend, Rune* runes) {$/;" f file: +runelen buf.c /^static size_t runelen(Rune rune) {$/;" f file: +runes edit.h /^ Rune* runes; \/* array of runes containing deleted content *\/$/;" m struct:Log::__anon2::__anon4 +runevalid buf.c /^static bool runevalid(Rune val) {$/;" f file: +runewidth buf.c /^int runewidth(unsigned col, Rune r) {$/;" f +s testdocs/sqlite3.c /^ double s; \/* Seconds *\/$/;" m struct:DateTime file: +s testdocs/sqlite3.c /^ unsigned char s[256]; \/* State variables *\/$/;" m struct:sqlite3PrngType file: +sArg testdocs/sqlite3.c /^ Token sArg; \/* Complete text of a module argument *\/$/;" m struct:Parse file: +sColMap testdocs/sqlite3.c /^ struct sColMap { \/* Mapping of columns in pFrom to columns in zTo *\/$/;" s struct:FKey file: +sFts5Api testdocs/sqlite3.c /^static const Fts5ExtensionApi sFts5Api = {$/;" v file: +sLastToken testdocs/sqlite3.c /^ Token sLastToken; \/* The last token parsed *\/$/;" m struct:Parse file: +sMaskSet testdocs/sqlite3.c /^ WhereMaskSet sMaskSet; \/* Map cursor numbers to bitmasks *\/$/;" m struct:WhereInfo file: +sNameToken testdocs/sqlite3.c /^ Token sNameToken; \/* Token with unqualified schema object name *\/$/;" m struct:Parse file: +sParse testdocs/sqlite3.c /^ JsonParse sParse; \/* Parse of the input JSON *\/$/;" m struct:JsonEachCursor file: +sPoint testdocs/sqlite3.c /^ RtreeSearchPoint sPoint; \/* Cached next search point *\/$/;" m struct:RtreeCursor file: +sWC testdocs/sqlite3.c /^ WhereClause sWC; \/* Decomposition of the WHERE clause *\/$/;" m struct:WhereInfo file: +safe_isalnum testdocs/sqlite3.c /^# define safe_isalnum(/;" d file: +safe_isdigit testdocs/sqlite3.c /^# define safe_isdigit(/;" d file: +safe_isspace testdocs/sqlite3.c /^#define safe_isspace(/;" d file: +safe_isxdigit testdocs/sqlite3.c /^# define safe_isxdigit(/;" d file: +safety_level testdocs/sqlite3.c /^ u8 safety_level; \/* How aggressive at syncing data to disk *\/$/;" m struct:Db file: +sampleClear testdocs/sqlite3.c /^static void sampleClear(sqlite3 *db, Stat4Sample *p){$/;" f file: +sampleCopy testdocs/sqlite3.c /^static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){$/;" f file: +sampleInsert testdocs/sqlite3.c /^static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){$/;" f file: +sampleIsBetter testdocs/sqlite3.c /^static int sampleIsBetter($/;" f file: +sampleIsBetterPost testdocs/sqlite3.c /^static int sampleIsBetterPost($/;" f file: +samplePushPrevious testdocs/sqlite3.c /^static void samplePushPrevious(Stat4Accum *p, int iChng){$/;" f file: +sampleSetRowid testdocs/sqlite3.c /^static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){$/;" f file: +sampleSetRowidInt64 testdocs/sqlite3.c /^static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){$/;" f file: +saveAllCursors testdocs/sqlite3.c /^static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){$/;" f file: +saveCursorKey testdocs/sqlite3.c /^static int saveCursorKey(BtCursor *pCur){$/;" f file: +saveCursorPosition testdocs/sqlite3.c /^static int saveCursorPosition(BtCursor *pCur){$/;" f file: +saveCursorsOnList testdocs/sqlite3.c /^static int SQLITE_NOINLINE saveCursorsOnList($/;" f file: +savedNQueryLoop testdocs/sqlite3.c /^ int savedNQueryLoop; \/* pParse->nQueryLoop outside the WHERE loop *\/$/;" m struct:WhereInfo file: +saved_cnt testdocs/sqlite3.c /^static int saved_cnt;$/;" v file: +schar stdc.h /^typedef signed char schar;$/;" t +schemaFlags testdocs/sqlite3.c /^ u16 schemaFlags; \/* Flags associated with this schema *\/$/;" m struct:Schema file: +schemaIsValid testdocs/sqlite3.c /^static void schemaIsValid(Parse *pParse){$/;" f file: +schema_cookie testdocs/sqlite3.c /^ int schema_cookie; \/* Database schema version number for this file *\/$/;" m struct:Schema file: +scratchAllocOut testdocs/sqlite3.c /^static int scratchAllocOut = 0;$/;" v file: +searchWith testdocs/sqlite3.c /^static struct Cte *searchWith($/;" f file: +sectorSize testdocs/sqlite3.c /^ int sectorSize; \/* Device sector size *\/$/;" m struct:unixFile file: +sectorSize testdocs/sqlite3.c /^ u32 sectorSize; \/* Assumed sector size during rollback *\/$/;" m struct:Pager file: +seekAndRead testdocs/sqlite3.c /^static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){$/;" f file: +seekAndWrite testdocs/sqlite3.c /^static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){$/;" f file: +seekAndWriteFd testdocs/sqlite3.c /^static int seekAndWriteFd($/;" f file: +seekOp testdocs/sqlite3.c /^ u8 seekOp; \/* Most recent seek operation on this cursor *\/$/;" m struct:VdbeCursor file: +seekResult testdocs/sqlite3.c /^ int seekResult; \/* Result of previous sqlite3BtreeMoveto() or 0$/;" m struct:VdbeCursor file: +selFlags testdocs/sqlite3.c /^ u32 selFlags; \/* Various SF_* values *\/$/;" m struct:Select file: +selectAddSubqueryTypeInfo testdocs/sqlite3.c /^static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){$/;" f file: +selectExpander testdocs/sqlite3.c /^static int selectExpander(Walker *pWalker, Select *p){$/;" f file: +selectInnerLoop testdocs/sqlite3.c /^static void selectInnerLoop($/;" f file: +selectNodeIsConstant testdocs/sqlite3.c /^static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){$/;" f file: +selectOpName testdocs/sqlite3.c /^static const char *selectOpName(int id){$/;" f file: +selectPopWith testdocs/sqlite3.c /^#define selectPopWith /;" d file: +selectPopWith testdocs/sqlite3.c /^static void selectPopWith(Walker *pWalker, Select *p){$/;" f file: +semXCheckReservedLock testdocs/sqlite3.c /^static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) {$/;" f file: +semXClose testdocs/sqlite3.c /^static int semXClose(sqlite3_file *id) {$/;" f file: +semXLock testdocs/sqlite3.c /^static int semXLock(sqlite3_file *id, int eFileLock) {$/;" f file: +semXUnlock testdocs/sqlite3.c /^static int semXUnlock(sqlite3_file *id, int eFileLock) {$/;" f file: +sentinel stdc.h /^#define sentinel(/;" d +separateCache testdocs/sqlite3.c /^ int separateCache; \/* Use a new PGroup for each PCache *\/$/;" m struct:PCacheGlobal file: +seqCount testdocs/sqlite3.c /^ i64 seqCount; \/* Sequence counter *\/$/;" m struct:VdbeCursor file: +serialGet testdocs/sqlite3.c /^static u32 SQLITE_NOINLINE serialGet($/;" f file: +sessionAppendBlob testdocs/sqlite3.c /^static void sessionAppendBlob($/;" f file: +sessionAppendByte testdocs/sqlite3.c /^static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){$/;" f file: +sessionAppendCol testdocs/sqlite3.c /^static void sessionAppendCol($/;" f file: +sessionAppendDelete testdocs/sqlite3.c /^static int sessionAppendDelete($/;" f file: +sessionAppendIdent testdocs/sqlite3.c /^static void sessionAppendIdent($/;" f file: +sessionAppendInteger testdocs/sqlite3.c /^static void sessionAppendInteger($/;" f file: +sessionAppendStr testdocs/sqlite3.c /^static void sessionAppendStr($/;" f file: +sessionAppendTableHdr testdocs/sqlite3.c /^static void sessionAppendTableHdr($/;" f file: +sessionAppendUpdate testdocs/sqlite3.c /^static int sessionAppendUpdate($/;" f file: +sessionAppendValue testdocs/sqlite3.c /^static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){$/;" f file: +sessionAppendVarint testdocs/sqlite3.c /^static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){$/;" f file: +sessionApplyOneOp testdocs/sqlite3.c /^static int sessionApplyOneOp($/;" f file: +sessionApplyOneWithRetry testdocs/sqlite3.c /^static int sessionApplyOneWithRetry($/;" f file: +sessionBindRow testdocs/sqlite3.c /^static int sessionBindRow($/;" f file: +sessionBindValue testdocs/sqlite3.c /^static int sessionBindValue($/;" f file: +sessionBufferGrow testdocs/sqlite3.c /^static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){$/;" f file: +sessionChangeEqual testdocs/sqlite3.c /^static int sessionChangeEqual($/;" f file: +sessionChangeHash testdocs/sqlite3.c /^static unsigned int sessionChangeHash($/;" f file: +sessionChangeMerge testdocs/sqlite3.c /^static int sessionChangeMerge($/;" f file: +sessionChangegroupOutput testdocs/sqlite3.c /^static int sessionChangegroupOutput($/;" f file: +sessionChangesetApply testdocs/sqlite3.c /^static int sessionChangesetApply($/;" f file: +sessionChangesetBufferRecord testdocs/sqlite3.c /^static int sessionChangesetBufferRecord($/;" f file: +sessionChangesetBufferTblhdr testdocs/sqlite3.c /^static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){$/;" f file: +sessionChangesetInvert testdocs/sqlite3.c /^static int sessionChangesetInvert($/;" f file: +sessionChangesetNew testdocs/sqlite3.c /^#define sessionChangesetNew(/;" d file: +sessionChangesetNext testdocs/sqlite3.c /^static int sessionChangesetNext($/;" f file: +sessionChangesetOld testdocs/sqlite3.c /^#define sessionChangesetOld(/;" d file: +sessionChangesetReadTblhdr testdocs/sqlite3.c /^static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){$/;" f file: +sessionChangesetStart testdocs/sqlite3.c /^static int sessionChangesetStart($/;" f file: +sessionChangesetToHash testdocs/sqlite3.c /^static int sessionChangesetToHash($/;" f file: +sessionConflictHandler testdocs/sqlite3.c /^static int sessionConflictHandler($/;" f file: +sessionDeleteRow testdocs/sqlite3.c /^static int sessionDeleteRow($/;" f file: +sessionDeleteTable testdocs/sqlite3.c /^static void sessionDeleteTable(SessionTable *pList){$/;" f file: +sessionDiffCount testdocs/sqlite3.c /^static int sessionDiffCount(void *pCtx){$/;" f file: +sessionDiffDepth testdocs/sqlite3.c /^static int sessionDiffDepth(void *pCtx){$/;" f file: +sessionDiffFindModified testdocs/sqlite3.c /^static int sessionDiffFindModified($/;" f file: +sessionDiffFindNew testdocs/sqlite3.c /^static int sessionDiffFindNew($/;" f file: +sessionDiffHooks testdocs/sqlite3.c /^static void sessionDiffHooks($/;" f file: +sessionDiffNew testdocs/sqlite3.c /^static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){$/;" f file: +sessionDiffOld testdocs/sqlite3.c /^static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){$/;" f file: +sessionDiscardData testdocs/sqlite3.c /^static void sessionDiscardData(SessionInput *pIn){$/;" f file: +sessionExprCompareOther testdocs/sqlite3.c /^static char *sessionExprCompareOther($/;" f file: +sessionExprComparePK testdocs/sqlite3.c /^static char *sessionExprComparePK($/;" f file: +sessionFindTable testdocs/sqlite3.c /^static int sessionFindTable($/;" f file: +sessionGenerateChangeset testdocs/sqlite3.c /^static int sessionGenerateChangeset($/;" f file: +sessionGetI64 testdocs/sqlite3.c /^static sqlite3_int64 sessionGetI64(u8 *aRec){$/;" f file: +sessionGrowHash testdocs/sqlite3.c /^static int sessionGrowHash(int bPatchset, SessionTable *pTab){$/;" f file: +sessionHashAppendBlob testdocs/sqlite3.c /^static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){$/;" f file: +sessionHashAppendI64 testdocs/sqlite3.c /^static unsigned int sessionHashAppendI64(unsigned int h, i64 i){$/;" f file: +sessionHashAppendType testdocs/sqlite3.c /^static unsigned int sessionHashAppendType(unsigned int h, int eType){$/;" f file: +sessionInitTable testdocs/sqlite3.c /^static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){$/;" f file: +sessionInputBuffer testdocs/sqlite3.c /^static int sessionInputBuffer(SessionInput *pIn, int nByte){$/;" f file: +sessionInsertRow testdocs/sqlite3.c /^static int sessionInsertRow($/;" f file: +sessionMergeRecord testdocs/sqlite3.c /^static void sessionMergeRecord($/;" f file: +sessionMergeUpdate testdocs/sqlite3.c /^static int sessionMergeUpdate($/;" f file: +sessionMergeValue testdocs/sqlite3.c /^static u8 *sessionMergeValue($/;" f file: +sessionPreupdateCount testdocs/sqlite3.c /^static int sessionPreupdateCount(void *pCtx){$/;" f file: +sessionPreupdateDepth testdocs/sqlite3.c /^static int sessionPreupdateDepth(void *pCtx){$/;" f file: +sessionPreupdateEqual testdocs/sqlite3.c /^static int sessionPreupdateEqual($/;" f file: +sessionPreupdateHash testdocs/sqlite3.c /^static int sessionPreupdateHash($/;" f file: +sessionPreupdateHooks testdocs/sqlite3.c /^static void sessionPreupdateHooks($/;" f file: +sessionPreupdateNew testdocs/sqlite3.c /^static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){$/;" f file: +sessionPreupdateOld testdocs/sqlite3.c /^static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){$/;" f file: +sessionPreupdateOneChange testdocs/sqlite3.c /^static void sessionPreupdateOneChange($/;" f file: +sessionPutI64 testdocs/sqlite3.c /^static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){$/;" f file: +sessionReadRecord testdocs/sqlite3.c /^static int sessionReadRecord($/;" f file: +sessionRetryConstraints testdocs/sqlite3.c /^static int sessionRetryConstraints($/;" f file: +sessionSeekToRow testdocs/sqlite3.c /^static int sessionSeekToRow($/;" f file: +sessionSelectBind testdocs/sqlite3.c /^static int sessionSelectBind($/;" f file: +sessionSelectFindNew testdocs/sqlite3.c /^static char *sessionSelectFindNew($/;" f file: +sessionSelectRow testdocs/sqlite3.c /^static int sessionSelectRow($/;" f file: +sessionSelectStmt testdocs/sqlite3.c /^static int sessionSelectStmt($/;" f file: +sessionSerialLen testdocs/sqlite3.c /^static int sessionSerialLen(u8 *a){$/;" f file: +sessionSerializeValue testdocs/sqlite3.c /^static int sessionSerializeValue($/;" f file: +sessionSkipRecord testdocs/sqlite3.c /^static void sessionSkipRecord($/;" f file: +sessionTableInfo testdocs/sqlite3.c /^static int sessionTableInfo($/;" f file: +sessionUpdateRow testdocs/sqlite3.c /^static int sessionUpdateRow($/;" f file: +sessionValueSetStr testdocs/sqlite3.c /^static int sessionValueSetStr($/;" f file: +sessionVarintGet testdocs/sqlite3.c /^static int sessionVarintGet(u8 *aBuf, int *piVal){$/;" f file: +sessionVarintLen testdocs/sqlite3.c /^static int sessionVarintLen(int iVal){$/;" f file: +sessionVarintPut testdocs/sqlite3.c /^static int sessionVarintPut(u8 *aBuf, int iVal){$/;" f file: +setAllPagerFlags testdocs/sqlite3.c /^# define setAllPagerFlags(/;" d file: +setAllPagerFlags testdocs/sqlite3.c /^static void setAllPagerFlags(sqlite3 *db){$/;" f file: +setChildPtrmaps testdocs/sqlite3.c /^# define setChildPtrmaps(/;" d file: +setChildPtrmaps testdocs/sqlite3.c /^static int setChildPtrmaps(MemPage *pPage){$/;" f file: +setDateTimeToCurrent testdocs/sqlite3.c /^static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){$/;" f file: +setDefaultSyncFlag testdocs/sqlite3.c /^# define setDefaultSyncFlag(/;" d file: +setDefaultSyncFlag testdocs/sqlite3.c /^static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){$/;" f file: +setDestPgsz testdocs/sqlite3.c /^static int setDestPgsz(sqlite3_backup *p){$/;" f file: +setGetterMethod testdocs/sqlite3.c /^static void setGetterMethod(Pager *pPager){$/;" f file: +setJoinExpr testdocs/sqlite3.c /^static void setJoinExpr(Expr *p, int iTable){$/;" f file: +setLikeOptFlag testdocs/sqlite3.c /^static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){$/;" f file: +setMaster testdocs/sqlite3.c /^ u8 setMaster; \/* True if a m-j name has been written to jrnl *\/$/;" m struct:Pager file: +setPageReferenced testdocs/sqlite3.c /^static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){$/;" f file: +setPendingFd testdocs/sqlite3.c /^static void setPendingFd(unixFile *pFile){$/;" f file: +setPragmaResultColumnNames testdocs/sqlite3.c /^static void setPragmaResultColumnNames($/;" f file: +setRawDateNumber testdocs/sqlite3.c /^static void setRawDateNumber(DateTime *p, double r){$/;" f file: +setResultStrOrError testdocs/sqlite3.c /^static void setResultStrOrError($/;" f file: +setSectorSize testdocs/sqlite3.c /^static void setSectorSize(Pager *pPager){$/;" f file: +setSharedCacheTableLock testdocs/sqlite3.c /^ #define setSharedCacheTableLock(/;" d file: +setSharedCacheTableLock testdocs/sqlite3.c /^static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){$/;" f file: +setStrAccumError testdocs/sqlite3.c /^static void setStrAccumError(StrAccum *p, u8 eError){$/;" f file: +set_authorizer testdocs/sqlite3.c /^ int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,$/;" m struct:sqlite3_api_routines file: +set_auxdata testdocs/sqlite3.c /^ void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));$/;" m struct:sqlite3_api_routines file: +set_buffer_text testbuf.c /^static void set_buffer_text(char* str) {$/;" f file: +set_last_insert_rowid testdocs/sqlite3.c /^ void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);$/;" m struct:sqlite3_api_routines file: +setupLookaside testdocs/sqlite3.c /^static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){$/;" f file: +sharable testdocs/sqlite3.c /^ u8 sharable; \/* True if we can share pBt with another db *\/$/;" m struct:Btree file: +shared testdocs/sqlite3.c /^ winceLock *shared; \/* Global shared lock memory for the file *\/$/;" m struct:winFile file: +sharedByte testdocs/sqlite3.c /^ unsigned long long sharedByte; \/* for AFP simulated shared lock *\/$/;" m struct:unixInodeInfo file: +sharedCacheEnabled testdocs/sqlite3.c /^ int sharedCacheEnabled; \/* true if shared-cache mode enabled *\/$/;" m struct:Sqlite3Config file: +sharedLockByte testdocs/sqlite3.c /^ short sharedLockByte; \/* Randomly chosen byte used as a shared lock *\/$/;" m struct:winFile file: +sharedMask testdocs/sqlite3.c /^ u16 sharedMask; \/* Mask of shared locks held *\/$/;" m struct:unixShm file: +sharedMask testdocs/sqlite3.c /^ u16 sharedMask; \/* Mask of shared locks held *\/$/;" m struct:winShm file: +sharedMask testdocs/sqlite3.c /^ u8 sharedMask; \/* Mask of shared locks held *\/$/;" m struct:unixShmNode file: +shutil testdocs/waf /^ import shutil, tarfile$/;" i +simpleClose testdocs/sqlite3.c /^static int simpleClose(sqlite3_tokenizer_cursor *pCursor){$/;" f file: +simpleCreate testdocs/sqlite3.c /^static int simpleCreate($/;" f file: +simpleDelim testdocs/sqlite3.c /^static int simpleDelim(simple_tokenizer *t, unsigned char c){$/;" f file: +simpleDestroy testdocs/sqlite3.c /^static int simpleDestroy(sqlite3_tokenizer *pTokenizer){$/;" f file: +simpleNext testdocs/sqlite3.c /^static int simpleNext($/;" f file: +simpleOpen testdocs/sqlite3.c /^static int simpleOpen($/;" f file: +simpleTokenizerModule testdocs/sqlite3.c /^static const sqlite3_tokenizer_module simpleTokenizerModule = {$/;" v file: +simple_tokenizer testdocs/sqlite3.c /^typedef struct simple_tokenizer {$/;" s file: +simple_tokenizer testdocs/sqlite3.c /^} simple_tokenizer;$/;" t typeref:struct:simple_tokenizer file: +simple_tokenizer_cursor testdocs/sqlite3.c /^typedef struct simple_tokenizer_cursor {$/;" s file: +simple_tokenizer_cursor testdocs/sqlite3.c /^} simple_tokenizer_cursor;$/;" t typeref:struct:simple_tokenizer_cursor file: +size4x testdocs/sqlite3.c /^ u32 size4x; \/* 4x the size of current chunk in Mem3Block elements *\/$/;" m struct:Mem3Block::__anon21::__anon22 file: +sjfd testdocs/sqlite3.c /^ sqlite3_file *sjfd; \/* File descriptor for sub-journal *\/$/;" m struct:Pager file: +skipBtreeMutex testdocs/sqlite3.c /^ u8 skipBtreeMutex; \/* True if no shared-cache backends *\/$/;" m struct:sqlite3 file: +skipFlag testdocs/sqlite3.c /^ u8 skipFlag; \/* Skip accumulator loading if true *\/$/;" m struct:sqlite3_context file: +skipNext testdocs/sqlite3.c /^ int skipNext; \/* Prev() is noop if negative. Next() is noop if positive.$/;" m struct:BtCursor file: +sleep testdocs/sqlite3.c /^ int (*sleep)(int);$/;" m struct:sqlite3_api_routines file: +sleepObj testdocs/sqlite3.c /^static HANDLE sleepObj = NULL;$/;" v file: +snprintf testdocs/sqlite3.c /^ char * (*snprintf)(int,char*,const char*,...);$/;" m struct:sqlite3_api_routines file: +soft_heap_limit testdocs/sqlite3.c /^ void (*soft_heap_limit)(int);$/;" m struct:sqlite3_api_routines file: +soft_heap_limit64 testdocs/sqlite3.c /^ sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);$/;" m struct:sqlite3_api_routines file: +sortFlags testdocs/sqlite3.c /^ u8 sortFlags; \/* Zero or more SORTFLAG_* bits *\/$/;" m struct:SortCtx file: +sortOrder testdocs/sqlite3.c /^ u8 sortOrder; \/* 1 for DESC or 0 for ASC *\/$/;" m struct:ExprList::ExprList_item file: +sorted testdocs/sqlite3.c /^ u8 sorted; \/* True if really sorted (not just grouped) *\/$/;" m struct:WhereInfo file: +sortingIdx testdocs/sqlite3.c /^ int sortingIdx; \/* Cursor number of the sorting index *\/$/;" m struct:AggInfo file: +sortingIdxPTab testdocs/sqlite3.c /^ int sortingIdxPTab; \/* Cursor number of pseudo-table *\/$/;" m struct:AggInfo file: +soundexFunc testdocs/sqlite3.c /^static void soundexFunc($/;" f file: +sourceid testdocs/sqlite3.c /^ const char *(*sourceid)(void);$/;" m struct:sqlite3_api_routines file: +sourceidFunc testdocs/sqlite3.c /^static void sourceidFunc($/;" f file: +spanBinaryExpr testdocs/sqlite3.c /^ static void spanBinaryExpr($/;" f file: +spanExpr testdocs/sqlite3.c /^ static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){$/;" f file: +spanSet testdocs/sqlite3.c /^ static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){$/;" f file: +spanUnaryPostfix testdocs/sqlite3.c /^ static void spanUnaryPostfix($/;" f file: +spanUnaryPrefix testdocs/sqlite3.c /^ static void spanUnaryPrefix($/;" f file: +splitNodeStartree testdocs/sqlite3.c /^static int splitNodeStartree($/;" f file: +sql testdocs/sqlite3.c /^ const char *(*sql)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +sqlite3 testdocs/sqlite3.c /^struct sqlite3 {$/;" s file: +sqlite3 testdocs/sqlite3.c /^typedef struct sqlite3 sqlite3;$/;" t typeref:struct:sqlite3 file: +sqlite3AbsInt32 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3AbsInt32(int x){$/;" f +sqlite3AddCheckConstraint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AddCheckConstraint($/;" f +sqlite3AddCollateType testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){$/;" f +sqlite3AddColumn testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){$/;" f +sqlite3AddDefaultValue testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){$/;" f +sqlite3AddInt64 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){$/;" f +sqlite3AddNotNull testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){$/;" f +sqlite3AddPrimaryKey testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AddPrimaryKey($/;" f +sqlite3AffinityType testdocs/sqlite3.c /^SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){$/;" f +sqlite3AllocateIndexObject testdocs/sqlite3.c /^SQLITE_PRIVATE Index *sqlite3AllocateIndexObject($/;" f +sqlite3AlterBeginAddColumn testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){$/;" f +sqlite3AlterFinishAddColumn testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){$/;" f +sqlite3AlterFunctions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AlterFunctions(void){$/;" f +sqlite3AlterRenameTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AlterRenameTable($/;" f +sqlite3AnalysisLoad testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){$/;" f +sqlite3Analyze testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){$/;" f +sqlite3AnalyzeFunctions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){$/;" f +sqlite3ApiExit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){$/;" f +sqlite3Apis testdocs/sqlite3.c /^static const sqlite3_api_routines sqlite3Apis = {$/;" v file: +sqlite3AppendChar testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){$/;" f +sqlite3ArrayAllocate testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3ArrayAllocate($/;" f +sqlite3AtoF testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){$/;" f +sqlite3Atoi testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Atoi(const char *z){$/;" f +sqlite3Atoi64 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){$/;" f +sqlite3Attach testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){$/;" f +sqlite3AuthCheck testdocs/sqlite3.c /^# define sqlite3AuthCheck(/;" d file: +sqlite3AuthCheck testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3AuthCheck($/;" f +sqlite3AuthContextPop testdocs/sqlite3.c /^# define sqlite3AuthContextPop(/;" d file: +sqlite3AuthContextPop testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){$/;" f +sqlite3AuthContextPush testdocs/sqlite3.c /^# define sqlite3AuthContextPush(/;" d file: +sqlite3AuthContextPush testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AuthContextPush($/;" f +sqlite3AuthRead testdocs/sqlite3.c /^# define sqlite3AuthRead(/;" d file: +sqlite3AuthRead testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AuthRead($/;" f +sqlite3AuthReadCol testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3AuthReadCol($/;" f +sqlite3AutoExtList testdocs/sqlite3.c /^static SQLITE_WSD struct sqlite3AutoExtList {$/;" s file: +sqlite3AutoExtList testdocs/sqlite3.c /^typedef struct sqlite3AutoExtList sqlite3AutoExtList;$/;" t typeref:struct:sqlite3AutoExtList file: +sqlite3AutoLoadExtensions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){$/;" f +sqlite3Autoext testdocs/sqlite3.c /^} sqlite3Autoext = { 0, 0 };$/;" v typeref:struct:sqlite3AutoExtList file: +sqlite3AutoincrementBegin testdocs/sqlite3.c /^# define sqlite3AutoincrementBegin(/;" d file: +sqlite3AutoincrementBegin testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){$/;" f +sqlite3AutoincrementEnd testdocs/sqlite3.c /^# define sqlite3AutoincrementEnd(/;" d file: +sqlite3AutoincrementEnd testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){$/;" f +sqlite3BackupRestart testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *pBackup){$/;" f +sqlite3BackupUpdate testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){$/;" f +sqlite3BeginBenignMalloc testdocs/sqlite3.c /^ #define sqlite3BeginBenignMalloc(/;" d file: +sqlite3BeginBenignMalloc testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){$/;" f +sqlite3BeginTransaction testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){$/;" f +sqlite3BeginTrigger testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BeginTrigger($/;" f +sqlite3BeginWriteOperation testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){$/;" f +sqlite3BenignMallocHooks testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BenignMallocHooks($/;" f +sqlite3BinaryCompareCollSeq testdocs/sqlite3.c /^SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq($/;" f +sqlite3BitvecBuiltinTest testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){$/;" f +sqlite3BitvecClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){$/;" f +sqlite3BitvecCreate testdocs/sqlite3.c /^SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){$/;" f +sqlite3BitvecDestroy testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec *p){$/;" f +sqlite3BitvecSet testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){$/;" f +sqlite3BitvecSize testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){$/;" f +sqlite3BitvecTest testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){$/;" f +sqlite3BitvecTestNotNull testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec *p, u32 i){$/;" f +sqlite3BlobCompare testdocs/sqlite3.c /^static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){$/;" f file: +sqlite3BlockedList testdocs/sqlite3.c /^static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;$/;" v file: +sqlite3BtreeBeginStmt testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){$/;" f +sqlite3BtreeBeginTrans testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){$/;" f +sqlite3BtreeCheckpoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){$/;" f +sqlite3BtreeClearCursor testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *pCur){$/;" f +sqlite3BtreeClearTable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){$/;" f +sqlite3BtreeClearTableOfCursor testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){$/;" f +sqlite3BtreeClose testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){$/;" f +sqlite3BtreeCloseCursor testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){$/;" f +sqlite3BtreeCommit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){$/;" f +sqlite3BtreeCommitPhaseOne testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){$/;" f +sqlite3BtreeCommitPhaseTwo testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){$/;" f +sqlite3BtreeConnectionCount testdocs/sqlite3.c /^# define sqlite3BtreeConnectionCount(/;" d file: +sqlite3BtreeConnectionCount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){$/;" f +sqlite3BtreeCopyFile testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){$/;" f +sqlite3BtreeCount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){$/;" f +sqlite3BtreeCreateTable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){$/;" f +sqlite3BtreeCursor testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCursor($/;" f +sqlite3BtreeCursorHasHint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){$/;" f +sqlite3BtreeCursorHasMoved testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){$/;" f +sqlite3BtreeCursorHint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){$/;" f +sqlite3BtreeCursorHintFlags testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){$/;" f +sqlite3BtreeCursorIsValid testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){$/;" f +sqlite3BtreeCursorIsValidNN testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){$/;" f +sqlite3BtreeCursorRestore testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){$/;" f +sqlite3BtreeCursorSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){$/;" f +sqlite3BtreeCursorZero testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){$/;" f +sqlite3BtreeDelete testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){$/;" f +sqlite3BtreeDropTable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){$/;" f +sqlite3BtreeEnter testdocs/sqlite3.c /^# define sqlite3BtreeEnter(/;" d file: +sqlite3BtreeEnter testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){$/;" f +sqlite3BtreeEnterAll testdocs/sqlite3.c /^# define sqlite3BtreeEnterAll(/;" d file: +sqlite3BtreeEnterAll testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){$/;" f +sqlite3BtreeEnterCursor testdocs/sqlite3.c /^# define sqlite3BtreeEnterCursor(/;" d file: +sqlite3BtreeEnterCursor testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){$/;" f +sqlite3BtreeEof testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){$/;" f +sqlite3BtreeFirst testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){$/;" f +sqlite3BtreeGetAutoVacuum testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){$/;" f +sqlite3BtreeGetFilename testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *p){$/;" f +sqlite3BtreeGetJournalname testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *p){$/;" f +sqlite3BtreeGetMeta testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){$/;" f +sqlite3BtreeGetOptimalReserve testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){$/;" f +sqlite3BtreeGetPageSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){$/;" f +sqlite3BtreeGetReserveNoMutex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){$/;" f +sqlite3BtreeHoldsAllMutexes testdocs/sqlite3.c /^# define sqlite3BtreeHoldsAllMutexes(/;" d file: +sqlite3BtreeHoldsAllMutexes testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){$/;" f +sqlite3BtreeHoldsMutex testdocs/sqlite3.c /^# define sqlite3BtreeHoldsMutex(/;" d file: +sqlite3BtreeHoldsMutex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){$/;" f +sqlite3BtreeIncrVacuum testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){$/;" f +sqlite3BtreeIncrblobCursor testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){$/;" f +sqlite3BtreeInsert testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeInsert($/;" f +sqlite3BtreeIntegerKey testdocs/sqlite3.c /^SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){$/;" f +sqlite3BtreeIntegrityCheck testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck($/;" f +sqlite3BtreeIsInBackup testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){$/;" f +sqlite3BtreeIsInReadTrans testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree *p){$/;" f +sqlite3BtreeIsInTrans testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){$/;" f +sqlite3BtreeIsReadonly testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){$/;" f +sqlite3BtreeLast testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){$/;" f +sqlite3BtreeLastPage testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){$/;" f +sqlite3BtreeLeave testdocs/sqlite3.c /^# define sqlite3BtreeLeave(/;" d file: +sqlite3BtreeLeave testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeLeave(Btree *p){$/;" f +sqlite3BtreeLeaveAll testdocs/sqlite3.c /^# define sqlite3BtreeLeaveAll(/;" d file: +sqlite3BtreeLeaveAll testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){$/;" f +sqlite3BtreeLeaveCursor testdocs/sqlite3.c /^# define sqlite3BtreeLeaveCursor(/;" d file: +sqlite3BtreeLeaveCursor testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){$/;" f +sqlite3BtreeLockTable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){$/;" f +sqlite3BtreeMaxPageCount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){$/;" f +sqlite3BtreeMovetoUnpacked testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked($/;" f +sqlite3BtreeNewDb testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){$/;" f +sqlite3BtreeNext testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){$/;" f +sqlite3BtreeOpen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeOpen($/;" f +sqlite3BtreePager testdocs/sqlite3.c /^SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){$/;" f +sqlite3BtreePayload testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){$/;" f +sqlite3BtreePayloadChecked testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){$/;" f +sqlite3BtreePayloadFetch testdocs/sqlite3.c /^SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){$/;" f +sqlite3BtreePayloadSize testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){$/;" f +sqlite3BtreePrevious testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){$/;" f +sqlite3BtreePutData testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){$/;" f +sqlite3BtreeRollback testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){$/;" f +sqlite3BtreeRowCountEst testdocs/sqlite3.c /^SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){$/;" f +sqlite3BtreeSavepoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){$/;" f +sqlite3BtreeSchema testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){$/;" f +sqlite3BtreeSchemaLocked testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){$/;" f +sqlite3BtreeSecureDelete testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){$/;" f +sqlite3BtreeSetAutoVacuum testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){$/;" f +sqlite3BtreeSetCacheSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){$/;" f +sqlite3BtreeSetMmapLimit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){$/;" f +sqlite3BtreeSetPageSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){$/;" f +sqlite3BtreeSetPagerFlags testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags($/;" f +sqlite3BtreeSetSpillSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){$/;" f +sqlite3BtreeSetVersion testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){$/;" f +sqlite3BtreeSharable testdocs/sqlite3.c /^# define sqlite3BtreeSharable(/;" d file: +sqlite3BtreeSharable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){$/;" f +sqlite3BtreeTripAllCursors testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){$/;" f +sqlite3BtreeUpdateMeta testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){$/;" f +sqlite3BuiltinFunctions testdocs/sqlite3.c /^SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;$/;" v +sqlite3CantopenError testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3CantopenError(int lineno){$/;" f +sqlite3ChangeCookie testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){$/;" f +sqlite3CheckCollSeq testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){$/;" f +sqlite3CheckObjectName testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){$/;" f +sqlite3Checkpoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){$/;" f +sqlite3ClearStatTables testdocs/sqlite3.c /^static void sqlite3ClearStatTables($/;" f file: +sqlite3ClearTempRegCache testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){$/;" f +sqlite3Close testdocs/sqlite3.c /^static int sqlite3Close(sqlite3 *db, int forceZombie){$/;" f file: +sqlite3CloseExtensions testdocs/sqlite3.c /^# define sqlite3CloseExtensions(/;" d file: +sqlite3CloseExtensions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){$/;" f +sqlite3CloseSavepoints testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){$/;" f +sqlite3CodeDropTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){$/;" f +sqlite3CodeRowTrigger testdocs/sqlite3.c /^# define sqlite3CodeRowTrigger(/;" d file: +sqlite3CodeRowTrigger testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CodeRowTrigger($/;" f +sqlite3CodeRowTriggerDirect testdocs/sqlite3.c /^# define sqlite3CodeRowTriggerDirect(/;" d file: +sqlite3CodeRowTriggerDirect testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect($/;" f +sqlite3CodeSubselect testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3CodeSubselect($/;" f +sqlite3CodeVerifyNamedSchema testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){$/;" f +sqlite3CodeVerifySchema testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){$/;" f +sqlite3CollapseDatabaseArray testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){$/;" f +sqlite3ColumnDefault testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){$/;" f +sqlite3ColumnOfIndex testdocs/sqlite3.c /^SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){$/;" f +sqlite3ColumnPropertiesFromName testdocs/sqlite3.c /^# define sqlite3ColumnPropertiesFromName(/;" d file: +sqlite3ColumnPropertiesFromName testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){$/;" f +sqlite3ColumnType testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){$/;" f +sqlite3ColumnsFromExprList testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ColumnsFromExprList($/;" f +sqlite3CommitInternalChanges testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){$/;" f +sqlite3CommitTransaction testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){$/;" f +sqlite3CompareAffinity testdocs/sqlite3.c /^SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){$/;" f +sqlite3CompleteInsertion testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CompleteInsertion($/;" f +sqlite3Config testdocs/sqlite3.c /^SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {$/;" v typeref:struct:Sqlite3Config +sqlite3Config testdocs/sqlite3.c /^SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;$/;" v typeref:struct:Sqlite3Config +sqlite3ConnectionBlocked testdocs/sqlite3.c /^ #define sqlite3ConnectionBlocked(/;" d file: +sqlite3ConnectionBlocked testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){$/;" f +sqlite3ConnectionClosed testdocs/sqlite3.c /^ #define sqlite3ConnectionClosed(/;" d file: +sqlite3ConnectionClosed testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){$/;" f +sqlite3ConnectionUnlocked testdocs/sqlite3.c /^ #define sqlite3ConnectionUnlocked(/;" d file: +sqlite3ConnectionUnlocked testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){$/;" f +sqlite3CorruptError testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3CorruptError(int lineno){$/;" f +sqlite3Coverage testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Coverage(int x){$/;" f +sqlite3CreateColumnExpr testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){$/;" f +sqlite3CreateForeignKey testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CreateForeignKey($/;" f +sqlite3CreateFunc testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3CreateFunc($/;" f +sqlite3CreateIndex testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CreateIndex($/;" f +sqlite3CreateView testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3CreateView($/;" f +sqlite3CtypeMap testdocs/sqlite3.c /^SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {$/;" v +sqlite3CtypeMap testdocs/sqlite3.c /^SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];$/;" v +sqlite3DbFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){$/;" f +sqlite3DbFreeNN testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){$/;" f +sqlite3DbMallocRaw testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){$/;" f +sqlite3DbMallocRawNN testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){$/;" f +sqlite3DbMallocSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){$/;" f +sqlite3DbMallocZero testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){$/;" f +sqlite3DbMaskAllZero testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){$/;" f +sqlite3DbNameToBtree testdocs/sqlite3.c /^SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){$/;" f +sqlite3DbRealloc testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){$/;" f +sqlite3DbReallocOrFree testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){$/;" f +sqlite3DbStrDup testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){$/;" f +sqlite3DbStrNDup testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){$/;" f +sqlite3DbstatRegister testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }$/;" f +sqlite3DbstatRegister testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){$/;" f +sqlite3DebugPrintf testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){$/;" f +sqlite3DecOrHexToI64 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){$/;" f +sqlite3DefaultMutex testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){$/;" f +sqlite3DefaultRowEst testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){$/;" f +sqlite3DeferForeignKey testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){$/;" f +sqlite3DeleteColumnNames testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){$/;" f +sqlite3DeleteFrom testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DeleteFrom($/;" f +sqlite3DeleteIndexSamples testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){$/;" f +sqlite3DeleteTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){$/;" f +sqlite3DeleteTrigger testdocs/sqlite3.c /^# define sqlite3DeleteTrigger(/;" d file: +sqlite3DeleteTrigger testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){$/;" f +sqlite3DeleteTriggerStep testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){$/;" f +sqlite3Dequote testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Dequote(char *z){$/;" f +sqlite3Detach testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){$/;" f +sqlite3DropIndex testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){$/;" f +sqlite3DropTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){$/;" f +sqlite3DropTrigger testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){$/;" f +sqlite3DropTriggerPtr testdocs/sqlite3.c /^# define sqlite3DropTriggerPtr(/;" d file: +sqlite3DropTriggerPtr testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){$/;" f +sqlite3EndBenignMalloc testdocs/sqlite3.c /^ #define sqlite3EndBenignMalloc(/;" d file: +sqlite3EndBenignMalloc testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){$/;" f +sqlite3EndTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3EndTable($/;" f +sqlite3ErrName testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3ErrName(int rc){$/;" f +sqlite3ErrStr testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){$/;" f +sqlite3Error testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){$/;" f +sqlite3ErrorFinish testdocs/sqlite3.c /^static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){$/;" f file: +sqlite3ErrorMsg testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){$/;" f +sqlite3ErrorWithMsg testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){$/;" f +sqlite3ExpirePreparedStatements testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db){$/;" f +sqlite3Expr testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3Expr($/;" f +sqlite3ExprAddCollateString testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){$/;" f +sqlite3ExprAddCollateToken testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken($/;" f +sqlite3ExprAffinity testdocs/sqlite3.c /^SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){$/;" f +sqlite3ExprAlloc testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprAlloc($/;" f +sqlite3ExprAnalyzeAggList testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){$/;" f +sqlite3ExprAnalyzeAggregates testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){$/;" f +sqlite3ExprAnd testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){$/;" f +sqlite3ExprAssignVarNumber testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){$/;" f +sqlite3ExprAttachSubtrees testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprAttachSubtrees($/;" f +sqlite3ExprCacheAffinityChange testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){$/;" f +sqlite3ExprCacheClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){$/;" f +sqlite3ExprCachePinRegister testdocs/sqlite3.c /^static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){$/;" f file: +sqlite3ExprCachePop testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){$/;" f +sqlite3ExprCachePush testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){$/;" f +sqlite3ExprCacheRemove testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){$/;" f +sqlite3ExprCacheStore testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){$/;" f +sqlite3ExprCanBeNull testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){$/;" f +sqlite3ExprCheckHeight testdocs/sqlite3.c /^ #define sqlite3ExprCheckHeight(/;" d file: +sqlite3ExprCheckHeight testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){$/;" f +sqlite3ExprCheckIN testdocs/sqlite3.c /^# define sqlite3ExprCheckIN(/;" d file: +sqlite3ExprCheckIN testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){$/;" f +sqlite3ExprCode testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){$/;" f +sqlite3ExprCodeAndCache testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){$/;" f +sqlite3ExprCodeAtInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCodeAtInit($/;" f +sqlite3ExprCodeCopy testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){$/;" f +sqlite3ExprCodeExprList testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCodeExprList($/;" f +sqlite3ExprCodeFactorable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){$/;" f +sqlite3ExprCodeGetColumn testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCodeGetColumn($/;" f +sqlite3ExprCodeGetColumnOfTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable($/;" f +sqlite3ExprCodeGetColumnToReg testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg($/;" f +sqlite3ExprCodeIN testdocs/sqlite3.c /^static void sqlite3ExprCodeIN($/;" f file: +sqlite3ExprCodeLoadIndexColumn testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn($/;" f +sqlite3ExprCodeMove testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){$/;" f +sqlite3ExprCodeTarget testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){$/;" f +sqlite3ExprCodeTemp testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){$/;" f +sqlite3ExprCollSeq testdocs/sqlite3.c /^SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){$/;" f +sqlite3ExprCompare testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){$/;" f +sqlite3ExprCompareSkip testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){$/;" f +sqlite3ExprContainsSubquery testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){$/;" f +sqlite3ExprCoveredByIndex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprCoveredByIndex($/;" f +sqlite3ExprDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){$/;" f +sqlite3ExprDeleteNN testdocs/sqlite3.c /^static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){$/;" f file: +sqlite3ExprDup testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){$/;" f +sqlite3ExprForVectorField testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprForVectorField($/;" f +sqlite3ExprFunction testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){$/;" f +sqlite3ExprIfFalse testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){$/;" f +sqlite3ExprIfFalseDup testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){$/;" f +sqlite3ExprIfTrue testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){$/;" f +sqlite3ExprImpliesExpr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){$/;" f +sqlite3ExprIsConstant testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){$/;" f +sqlite3ExprIsConstantNotJoin testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){$/;" f +sqlite3ExprIsConstantOrFunction testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){$/;" f +sqlite3ExprIsConstantOrGroupBy testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){$/;" f +sqlite3ExprIsInteger testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){$/;" f +sqlite3ExprIsTableConstant testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){$/;" f +sqlite3ExprIsVector testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){$/;" f +sqlite3ExprListAppend testdocs/sqlite3.c /^SQLITE_PRIVATE ExprList *sqlite3ExprListAppend($/;" f +sqlite3ExprListAppendVector testdocs/sqlite3.c /^SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector($/;" f +sqlite3ExprListCheckLength testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprListCheckLength($/;" f +sqlite3ExprListCompare testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){$/;" f +sqlite3ExprListDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){$/;" f +sqlite3ExprListDup testdocs/sqlite3.c /^SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){$/;" f +sqlite3ExprListFlags testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){$/;" f +sqlite3ExprListSetName testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprListSetName($/;" f +sqlite3ExprListSetSortOrder testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){$/;" f +sqlite3ExprListSetSpan testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprListSetSpan($/;" f +sqlite3ExprNeedsNoAffinityChange testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){$/;" f +sqlite3ExprSetHeightAndFlags testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){$/;" f +sqlite3ExprSkipCollate testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){$/;" f +sqlite3ExprVectorSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){$/;" f +sqlite3ExprWalkNoop testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){$/;" f +sqlite3FaultSim testdocs/sqlite3.c /^# define sqlite3FaultSim(/;" d file: +sqlite3FaultSim testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FaultSim(int iTest){$/;" f +sqlite3FileSuffix3 testdocs/sqlite3.c /^# define sqlite3FileSuffix3(/;" d file: +sqlite3FileSuffix3 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){$/;" f +sqlite3FindCollSeq testdocs/sqlite3.c /^SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq($/;" f +sqlite3FindDb testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){$/;" f +sqlite3FindDbName testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){$/;" f +sqlite3FindFunction testdocs/sqlite3.c /^SQLITE_PRIVATE FuncDef *sqlite3FindFunction($/;" f +sqlite3FindInIndex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FindInIndex($/;" f +sqlite3FindIndex testdocs/sqlite3.c /^SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){$/;" f +sqlite3FindTable testdocs/sqlite3.c /^SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){$/;" f +sqlite3FinishCoding testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){$/;" f +sqlite3FinishTrigger testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FinishTrigger($/;" f +sqlite3FixExpr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FixExpr($/;" f +sqlite3FixExprList testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FixExprList($/;" f +sqlite3FixInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FixInit($/;" f +sqlite3FixSelect testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FixSelect($/;" f +sqlite3FixSrcList testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FixSrcList($/;" f +sqlite3FixTriggerStep testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FixTriggerStep($/;" f +sqlite3FkActions testdocs/sqlite3.c /^ #define sqlite3FkActions(/;" d file: +sqlite3FkActions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FkActions($/;" f +sqlite3FkCheck testdocs/sqlite3.c /^ #define sqlite3FkCheck(/;" d file: +sqlite3FkCheck testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FkCheck($/;" f +sqlite3FkDelete testdocs/sqlite3.c /^ #define sqlite3FkDelete(/;" d file: +sqlite3FkDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){$/;" f +sqlite3FkDropTable testdocs/sqlite3.c /^ #define sqlite3FkDropTable(/;" d file: +sqlite3FkDropTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){$/;" f +sqlite3FkLocateIndex testdocs/sqlite3.c /^ #define sqlite3FkLocateIndex(/;" d file: +sqlite3FkLocateIndex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FkLocateIndex($/;" f +sqlite3FkOldmask testdocs/sqlite3.c /^ #define sqlite3FkOldmask(/;" d file: +sqlite3FkOldmask testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3FkOldmask($/;" f +sqlite3FkReferences testdocs/sqlite3.c /^ #define sqlite3FkReferences(/;" d file: +sqlite3FkReferences testdocs/sqlite3.c /^SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){$/;" f +sqlite3FkRequired testdocs/sqlite3.c /^ #define sqlite3FkRequired(/;" d file: +sqlite3FkRequired testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FkRequired($/;" f +sqlite3Fts3AllSegdirs testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3AllSegdirs($/;" f +sqlite3Fts3Always testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3Always(int b) { assert( b ); return b; }$/;" f +sqlite3Fts3CacheDeferredDoclists testdocs/sqlite3.c /^# define sqlite3Fts3CacheDeferredDoclists(/;" d file: +sqlite3Fts3CacheDeferredDoclists testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){$/;" f +sqlite3Fts3Corrupt testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3Corrupt(){$/;" f +sqlite3Fts3CreateStatTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){$/;" f +sqlite3Fts3DeferToken testdocs/sqlite3.c /^# define sqlite3Fts3DeferToken(/;" d file: +sqlite3Fts3DeferToken testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3DeferToken($/;" f +sqlite3Fts3DeferredTokenList testdocs/sqlite3.c /^# define sqlite3Fts3DeferredTokenList(/;" d file: +sqlite3Fts3DeferredTokenList testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList($/;" f +sqlite3Fts3Dequote testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){$/;" f +sqlite3Fts3DoclistNext testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3DoclistNext($/;" f +sqlite3Fts3DoclistPrev testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3DoclistPrev($/;" f +sqlite3Fts3ErrMsg testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char **pzErr, const char *zFormat, ...){$/;" f +sqlite3Fts3EvalPhraseCleanup testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){$/;" f +sqlite3Fts3EvalPhrasePoslist testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist($/;" f +sqlite3Fts3EvalPhraseStats testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats($/;" f +sqlite3Fts3EvalTestDeferred testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){$/;" f +sqlite3Fts3ExprFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){$/;" f +sqlite3Fts3ExprInitTestInterface testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){$/;" f +sqlite3Fts3ExprParse testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3ExprParse($/;" f +sqlite3Fts3FirstFilter testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3FirstFilter($/;" f +sqlite3Fts3FreeDeferredDoclists testdocs/sqlite3.c /^# define sqlite3Fts3FreeDeferredDoclists(/;" d file: +sqlite3Fts3FreeDeferredDoclists testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){$/;" f +sqlite3Fts3FreeDeferredTokens testdocs/sqlite3.c /^# define sqlite3Fts3FreeDeferredTokens(/;" d file: +sqlite3Fts3FreeDeferredTokens testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){$/;" f +sqlite3Fts3GetVarint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){$/;" f +sqlite3Fts3GetVarint32 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){$/;" f +sqlite3Fts3HashClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash *pH){$/;" f +sqlite3Fts3HashFind testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){$/;" f +sqlite3Fts3HashFindElem testdocs/sqlite3.c /^SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem($/;" f +sqlite3Fts3HashInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey){$/;" f +sqlite3Fts3HashInsert testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3Fts3HashInsert($/;" f +sqlite3Fts3IcuTokenizerModule testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule($/;" f +sqlite3Fts3Incrmerge testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){$/;" f +sqlite3Fts3Init testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){$/;" f +sqlite3Fts3InitAux testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){$/;" f +sqlite3Fts3InitHashTable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3InitHashTable($/;" f +sqlite3Fts3InitTok testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){$/;" f +sqlite3Fts3InitTokenizer testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3InitTokenizer($/;" f +sqlite3Fts3IsIdChar testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){$/;" f +sqlite3Fts3MIBufferFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){$/;" f +sqlite3Fts3Matchinfo testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3Matchinfo($/;" f +sqlite3Fts3MaxLevel testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){$/;" f +sqlite3Fts3MsrIncrNext testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext($/;" f +sqlite3Fts3MsrIncrRestart testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){$/;" f +sqlite3Fts3MsrIncrStart testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart($/;" f +sqlite3Fts3MsrOvfl testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3MsrOvfl($/;" f +sqlite3Fts3Never testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3Never(int b) { assert( !b ); return b; }$/;" f +sqlite3Fts3NextToken testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){$/;" f +sqlite3Fts3Offsets testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3Offsets($/;" f +sqlite3Fts3OpenTokenizer testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer($/;" f +sqlite3Fts3Optimize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){$/;" f +sqlite3Fts3PendingTermsClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){$/;" f +sqlite3Fts3PendingTermsFlush testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){$/;" f +sqlite3Fts3PorterTokenizerModule testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule($/;" f +sqlite3Fts3PutVarint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){$/;" f +sqlite3Fts3ReadBlock testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3ReadBlock($/;" f +sqlite3Fts3SegReaderCursor testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor($/;" f +sqlite3Fts3SegReaderFinish testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish($/;" f +sqlite3Fts3SegReaderFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){$/;" f +sqlite3Fts3SegReaderNew testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3SegReaderNew($/;" f +sqlite3Fts3SegReaderPending testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3SegReaderPending($/;" f +sqlite3Fts3SegReaderStart testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3SegReaderStart($/;" f +sqlite3Fts3SegReaderStep testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3SegReaderStep($/;" f +sqlite3Fts3SegmentsClose testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){$/;" f +sqlite3Fts3SelectDocsize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3SelectDocsize($/;" f +sqlite3Fts3SelectDoctotal testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal($/;" f +sqlite3Fts3SimpleTokenizerModule testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule($/;" f +sqlite3Fts3Snippet testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3Snippet($/;" f +sqlite3Fts3UnicodeTokenizer testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){$/;" f +sqlite3Fts3UpdateMethod testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3UpdateMethod($/;" f +sqlite3Fts3VarintLen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64 v){$/;" f +sqlite3Fts5AuxInit testdocs/sqlite3.c /^static int sqlite3Fts5AuxInit(fts5_api *pApi){$/;" f file: +sqlite3Fts5BufferAppendBlob testdocs/sqlite3.c /^static void sqlite3Fts5BufferAppendBlob($/;" f file: +sqlite3Fts5BufferAppendPrintf testdocs/sqlite3.c /^static void sqlite3Fts5BufferAppendPrintf($/;" f file: +sqlite3Fts5BufferAppendString testdocs/sqlite3.c /^static void sqlite3Fts5BufferAppendString($/;" f file: +sqlite3Fts5BufferAppendVarint testdocs/sqlite3.c /^static void sqlite3Fts5BufferAppendVarint(int *pRc, Fts5Buffer *pBuf, i64 iVal){$/;" f file: +sqlite3Fts5BufferFree testdocs/sqlite3.c /^static void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){$/;" f file: +sqlite3Fts5BufferSet testdocs/sqlite3.c /^static void sqlite3Fts5BufferSet($/;" f file: +sqlite3Fts5BufferSize testdocs/sqlite3.c /^static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){$/;" f file: +sqlite3Fts5BufferZero testdocs/sqlite3.c /^static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){$/;" f file: +sqlite3Fts5ConfigDeclareVtab testdocs/sqlite3.c /^static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){$/;" f file: +sqlite3Fts5ConfigFree testdocs/sqlite3.c /^static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){$/;" f file: +sqlite3Fts5ConfigLoad testdocs/sqlite3.c /^static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){$/;" f file: +sqlite3Fts5ConfigParse testdocs/sqlite3.c /^static int sqlite3Fts5ConfigParse($/;" f file: +sqlite3Fts5ConfigParseRank testdocs/sqlite3.c /^static int sqlite3Fts5ConfigParseRank($/;" f file: +sqlite3Fts5ConfigSetValue testdocs/sqlite3.c /^static int sqlite3Fts5ConfigSetValue($/;" f file: +sqlite3Fts5Corrupt testdocs/sqlite3.c /^static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }$/;" f file: +sqlite3Fts5CreateTable testdocs/sqlite3.c /^static int sqlite3Fts5CreateTable($/;" f file: +sqlite3Fts5Dequote testdocs/sqlite3.c /^static void sqlite3Fts5Dequote(char *z){$/;" f file: +sqlite3Fts5DropAll testdocs/sqlite3.c /^static int sqlite3Fts5DropAll(Fts5Config *pConfig){$/;" f file: +sqlite3Fts5ExprCheckPoslists testdocs/sqlite3.c /^static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){$/;" f file: +sqlite3Fts5ExprClearPoslists testdocs/sqlite3.c /^static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){$/;" f file: +sqlite3Fts5ExprClonePhrase testdocs/sqlite3.c /^static int sqlite3Fts5ExprClonePhrase($/;" f file: +sqlite3Fts5ExprEof testdocs/sqlite3.c /^static int sqlite3Fts5ExprEof(Fts5Expr *p){$/;" f file: +sqlite3Fts5ExprFirst testdocs/sqlite3.c /^static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){$/;" f file: +sqlite3Fts5ExprFree testdocs/sqlite3.c /^static void sqlite3Fts5ExprFree(Fts5Expr *p){$/;" f file: +sqlite3Fts5ExprInit testdocs/sqlite3.c /^static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){$/;" f file: +sqlite3Fts5ExprNew testdocs/sqlite3.c /^static int sqlite3Fts5ExprNew($/;" f file: +sqlite3Fts5ExprNext testdocs/sqlite3.c /^static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){$/;" f file: +sqlite3Fts5ExprPhraseCollist testdocs/sqlite3.c /^static int sqlite3Fts5ExprPhraseCollist($/;" f file: +sqlite3Fts5ExprPhraseCount testdocs/sqlite3.c /^static int sqlite3Fts5ExprPhraseCount(Fts5Expr *pExpr){$/;" f file: +sqlite3Fts5ExprPhraseSize testdocs/sqlite3.c /^static int sqlite3Fts5ExprPhraseSize(Fts5Expr *pExpr, int iPhrase){$/;" f file: +sqlite3Fts5ExprPopulatePoslists testdocs/sqlite3.c /^static int sqlite3Fts5ExprPopulatePoslists($/;" f file: +sqlite3Fts5ExprPoslist testdocs/sqlite3.c /^static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){$/;" f file: +sqlite3Fts5ExprRowid testdocs/sqlite3.c /^static i64 sqlite3Fts5ExprRowid(Fts5Expr *p){$/;" f file: +sqlite3Fts5Get32 testdocs/sqlite3.c /^static int sqlite3Fts5Get32(const u8 *aBuf){$/;" f file: +sqlite3Fts5GetTokenizer testdocs/sqlite3.c /^static int sqlite3Fts5GetTokenizer($/;" f file: +sqlite3Fts5GetVarint testdocs/sqlite3.c /^static u8 sqlite3Fts5GetVarint(const unsigned char *p, u64 *v){$/;" f file: +sqlite3Fts5GetVarint32 testdocs/sqlite3.c /^static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){$/;" f file: +sqlite3Fts5GetVarintLen testdocs/sqlite3.c /^static int sqlite3Fts5GetVarintLen(u32 iVal){$/;" f file: +sqlite3Fts5HashClear testdocs/sqlite3.c /^static void sqlite3Fts5HashClear(Fts5Hash *pHash){$/;" f file: +sqlite3Fts5HashFree testdocs/sqlite3.c /^static void sqlite3Fts5HashFree(Fts5Hash *pHash){$/;" f file: +sqlite3Fts5HashNew testdocs/sqlite3.c /^static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){$/;" f file: +sqlite3Fts5HashQuery testdocs/sqlite3.c /^static int sqlite3Fts5HashQuery($/;" f file: +sqlite3Fts5HashScanEntry testdocs/sqlite3.c /^static void sqlite3Fts5HashScanEntry($/;" f file: +sqlite3Fts5HashScanEof testdocs/sqlite3.c /^static int sqlite3Fts5HashScanEof(Fts5Hash *p){$/;" f file: +sqlite3Fts5HashScanInit testdocs/sqlite3.c /^static int sqlite3Fts5HashScanInit($/;" f file: +sqlite3Fts5HashScanNext testdocs/sqlite3.c /^static void sqlite3Fts5HashScanNext(Fts5Hash *p){$/;" f file: +sqlite3Fts5HashWrite testdocs/sqlite3.c /^static int sqlite3Fts5HashWrite($/;" f file: +sqlite3Fts5IndexBeginWrite testdocs/sqlite3.c /^static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){$/;" f file: +sqlite3Fts5IndexCharlenToBytelen testdocs/sqlite3.c /^static int sqlite3Fts5IndexCharlenToBytelen($/;" f file: +sqlite3Fts5IndexClose testdocs/sqlite3.c /^static int sqlite3Fts5IndexClose(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexEntryCksum testdocs/sqlite3.c /^static u64 sqlite3Fts5IndexEntryCksum($/;" f file: +sqlite3Fts5IndexFromCsrid testdocs/sqlite3.c /^static Fts5Index *sqlite3Fts5IndexFromCsrid($/;" f file: +sqlite3Fts5IndexGetAverages testdocs/sqlite3.c /^static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){$/;" f file: +sqlite3Fts5IndexInit testdocs/sqlite3.c /^static int sqlite3Fts5IndexInit(sqlite3 *db){$/;" f file: +sqlite3Fts5IndexIntegrityCheck testdocs/sqlite3.c /^static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){$/;" f file: +sqlite3Fts5IndexLoadConfig testdocs/sqlite3.c /^static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexMerge testdocs/sqlite3.c /^static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){$/;" f file: +sqlite3Fts5IndexOpen testdocs/sqlite3.c /^static int sqlite3Fts5IndexOpen($/;" f file: +sqlite3Fts5IndexOptimize testdocs/sqlite3.c /^static int sqlite3Fts5IndexOptimize(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexQuery testdocs/sqlite3.c /^static int sqlite3Fts5IndexQuery($/;" f file: +sqlite3Fts5IndexReads testdocs/sqlite3.c /^static int sqlite3Fts5IndexReads(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexReinit testdocs/sqlite3.c /^static int sqlite3Fts5IndexReinit(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexReset testdocs/sqlite3.c /^static int sqlite3Fts5IndexReset(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexRollback testdocs/sqlite3.c /^static int sqlite3Fts5IndexRollback(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexSetAverages testdocs/sqlite3.c /^static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){$/;" f file: +sqlite3Fts5IndexSetCookie testdocs/sqlite3.c /^static int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){$/;" f file: +sqlite3Fts5IndexSync testdocs/sqlite3.c /^static int sqlite3Fts5IndexSync(Fts5Index *p){$/;" f file: +sqlite3Fts5IndexWrite testdocs/sqlite3.c /^static int sqlite3Fts5IndexWrite($/;" f file: +sqlite3Fts5Init testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){$/;" f +sqlite3Fts5IsBareword testdocs/sqlite3.c /^static int sqlite3Fts5IsBareword(char t){$/;" f file: +sqlite3Fts5IterClose testdocs/sqlite3.c /^static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){$/;" f file: +sqlite3Fts5IterEof testdocs/sqlite3.c /^#define sqlite3Fts5IterEof(/;" d file: +sqlite3Fts5IterNext testdocs/sqlite3.c /^static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){$/;" f file: +sqlite3Fts5IterNextFrom testdocs/sqlite3.c /^static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){$/;" f file: +sqlite3Fts5IterNextScan testdocs/sqlite3.c /^static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){$/;" f file: +sqlite3Fts5IterTerm testdocs/sqlite3.c /^static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){$/;" f file: +sqlite3Fts5MallocZero testdocs/sqlite3.c /^static void *sqlite3Fts5MallocZero(int *pRc, int nByte){$/;" f file: +sqlite3Fts5Mprintf testdocs/sqlite3.c /^static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){$/;" f file: +sqlite3Fts5ParseColset testdocs/sqlite3.c /^static Fts5Colset *sqlite3Fts5ParseColset($/;" f file: +sqlite3Fts5ParseColsetInvert testdocs/sqlite3.c /^static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){$/;" f file: +sqlite3Fts5ParseError testdocs/sqlite3.c /^static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){$/;" f file: +sqlite3Fts5ParseFinished testdocs/sqlite3.c /^static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){$/;" f file: +sqlite3Fts5ParseImplicitAnd testdocs/sqlite3.c /^static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd($/;" f file: +sqlite3Fts5ParseNear testdocs/sqlite3.c /^static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){$/;" f file: +sqlite3Fts5ParseNearset testdocs/sqlite3.c /^static Fts5ExprNearset *sqlite3Fts5ParseNearset($/;" f file: +sqlite3Fts5ParseNearsetFree testdocs/sqlite3.c /^static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset *pNear){$/;" f file: +sqlite3Fts5ParseNode testdocs/sqlite3.c /^static Fts5ExprNode *sqlite3Fts5ParseNode($/;" f file: +sqlite3Fts5ParseNodeFree testdocs/sqlite3.c /^static void sqlite3Fts5ParseNodeFree(Fts5ExprNode *p){$/;" f file: +sqlite3Fts5ParsePhraseFree testdocs/sqlite3.c /^static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase *pPhrase){$/;" f file: +sqlite3Fts5ParseSetColset testdocs/sqlite3.c /^static void sqlite3Fts5ParseSetColset($/;" f file: +sqlite3Fts5ParseSetDistance testdocs/sqlite3.c /^static void sqlite3Fts5ParseSetDistance($/;" f file: +sqlite3Fts5ParseTerm testdocs/sqlite3.c /^static Fts5ExprPhrase *sqlite3Fts5ParseTerm($/;" f file: +sqlite3Fts5Parser testdocs/sqlite3.c /^static void sqlite3Fts5Parser($/;" f file: +sqlite3Fts5ParserARG_FETCH testdocs/sqlite3.c /^#define sqlite3Fts5ParserARG_FETCH /;" d file: +sqlite3Fts5ParserARG_PDECL testdocs/sqlite3.c /^#define sqlite3Fts5ParserARG_PDECL /;" d file: +sqlite3Fts5ParserARG_SDECL testdocs/sqlite3.c /^#define sqlite3Fts5ParserARG_SDECL /;" d file: +sqlite3Fts5ParserARG_STORE testdocs/sqlite3.c /^#define sqlite3Fts5ParserARG_STORE /;" d file: +sqlite3Fts5ParserAlloc testdocs/sqlite3.c /^static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){$/;" f file: +sqlite3Fts5ParserFTS5TOKENTYPE testdocs/sqlite3.c /^#define sqlite3Fts5ParserFTS5TOKENTYPE /;" d file: +sqlite3Fts5ParserFinalize testdocs/sqlite3.c /^static void sqlite3Fts5ParserFinalize(void *p){$/;" f file: +sqlite3Fts5ParserFree testdocs/sqlite3.c /^static void sqlite3Fts5ParserFree($/;" f file: +sqlite3Fts5ParserInit testdocs/sqlite3.c /^static void sqlite3Fts5ParserInit(void *fts5yypParser){$/;" f file: +sqlite3Fts5ParserStackPeak testdocs/sqlite3.c /^static int sqlite3Fts5ParserStackPeak(void *p){$/;" f file: +sqlite3Fts5ParserTrace testdocs/sqlite3.c /^static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){$/;" f file: +sqlite3Fts5PoslistNext64 testdocs/sqlite3.c /^static int sqlite3Fts5PoslistNext64($/;" f file: +sqlite3Fts5PoslistReaderInit testdocs/sqlite3.c /^static int sqlite3Fts5PoslistReaderInit($/;" f file: +sqlite3Fts5PoslistReaderNext testdocs/sqlite3.c /^static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){$/;" f file: +sqlite3Fts5PoslistSafeAppend testdocs/sqlite3.c /^static void sqlite3Fts5PoslistSafeAppend($/;" f file: +sqlite3Fts5PoslistWriterAppend testdocs/sqlite3.c /^static int sqlite3Fts5PoslistWriterAppend($/;" f file: +sqlite3Fts5Put32 testdocs/sqlite3.c /^static void sqlite3Fts5Put32(u8 *aBuf, int iVal){$/;" f file: +sqlite3Fts5PutVarint testdocs/sqlite3.c /^static int sqlite3Fts5PutVarint(unsigned char *p, u64 v){$/;" f file: +sqlite3Fts5StorageClose testdocs/sqlite3.c /^static int sqlite3Fts5StorageClose(Fts5Storage *p){$/;" f file: +sqlite3Fts5StorageConfigValue testdocs/sqlite3.c /^static int sqlite3Fts5StorageConfigValue($/;" f file: +sqlite3Fts5StorageContentInsert testdocs/sqlite3.c /^static int sqlite3Fts5StorageContentInsert($/;" f file: +sqlite3Fts5StorageDelete testdocs/sqlite3.c /^static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){$/;" f file: +sqlite3Fts5StorageDeleteAll testdocs/sqlite3.c /^static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){$/;" f file: +sqlite3Fts5StorageDocsize testdocs/sqlite3.c /^static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){$/;" f file: +sqlite3Fts5StorageIndexInsert testdocs/sqlite3.c /^static int sqlite3Fts5StorageIndexInsert($/;" f file: +sqlite3Fts5StorageIntegrity testdocs/sqlite3.c /^static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){$/;" f file: +sqlite3Fts5StorageMerge testdocs/sqlite3.c /^static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){$/;" f file: +sqlite3Fts5StorageOpen testdocs/sqlite3.c /^static int sqlite3Fts5StorageOpen($/;" f file: +sqlite3Fts5StorageOptimize testdocs/sqlite3.c /^static int sqlite3Fts5StorageOptimize(Fts5Storage *p){$/;" f file: +sqlite3Fts5StorageRebuild testdocs/sqlite3.c /^static int sqlite3Fts5StorageRebuild(Fts5Storage *p){$/;" f file: +sqlite3Fts5StorageRename testdocs/sqlite3.c /^static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){$/;" f file: +sqlite3Fts5StorageReset testdocs/sqlite3.c /^static int sqlite3Fts5StorageReset(Fts5Storage *p){$/;" f file: +sqlite3Fts5StorageRollback testdocs/sqlite3.c /^static int sqlite3Fts5StorageRollback(Fts5Storage *p){$/;" f file: +sqlite3Fts5StorageRowCount testdocs/sqlite3.c /^static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){$/;" f file: +sqlite3Fts5StorageSize testdocs/sqlite3.c /^static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){$/;" f file: +sqlite3Fts5StorageStmt testdocs/sqlite3.c /^static int sqlite3Fts5StorageStmt($/;" f file: +sqlite3Fts5StorageStmtRelease testdocs/sqlite3.c /^static void sqlite3Fts5StorageStmtRelease($/;" f file: +sqlite3Fts5StorageSync testdocs/sqlite3.c /^static int sqlite3Fts5StorageSync(Fts5Storage *p){$/;" f file: +sqlite3Fts5Strndup testdocs/sqlite3.c /^static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){$/;" f file: +sqlite3Fts5TermsetAdd testdocs/sqlite3.c /^static int sqlite3Fts5TermsetAdd($/;" f file: +sqlite3Fts5TermsetFree testdocs/sqlite3.c /^static void sqlite3Fts5TermsetFree(Fts5Termset *p){$/;" f file: +sqlite3Fts5TermsetNew testdocs/sqlite3.c /^static int sqlite3Fts5TermsetNew(Fts5Termset **pp){$/;" f file: +sqlite3Fts5Tokenize testdocs/sqlite3.c /^static int sqlite3Fts5Tokenize($/;" f file: +sqlite3Fts5TokenizerInit testdocs/sqlite3.c /^static int sqlite3Fts5TokenizerInit(fts5_api *pApi){$/;" f file: +sqlite3Fts5UnicodeFold testdocs/sqlite3.c /^static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){$/;" f file: +sqlite3Fts5UnicodeIsalnum testdocs/sqlite3.c /^static int sqlite3Fts5UnicodeIsalnum(int c){$/;" f file: +sqlite3Fts5UnicodeIsdiacritic testdocs/sqlite3.c /^static int sqlite3Fts5UnicodeIsdiacritic(int c){$/;" f file: +sqlite3Fts5VocabInit testdocs/sqlite3.c /^static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){$/;" f file: +sqlite3FtsUnicodeFold testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){$/;" f +sqlite3FtsUnicodeIsalnum testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){$/;" f +sqlite3FtsUnicodeIsdiacritic testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){$/;" f +sqlite3FunctionUsesThisSrc testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){$/;" f +sqlite3GenerateConstraintChecks testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3GenerateConstraintChecks($/;" f +sqlite3GenerateIndexKey testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3GenerateIndexKey($/;" f +sqlite3GenerateRowDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3GenerateRowDelete($/;" f +sqlite3GenerateRowIndexDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete($/;" f +sqlite3Get4byte testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){$/;" f +sqlite3GetBoolean testdocs/sqlite3.c /^SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z, u8 dflt){$/;" f +sqlite3GetCollSeq testdocs/sqlite3.c /^SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq($/;" f +sqlite3GetFuncCollSeq testdocs/sqlite3.c /^static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){$/;" f file: +sqlite3GetInt32 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){$/;" f +sqlite3GetTempRange testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){$/;" f +sqlite3GetTempReg testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){$/;" f +sqlite3GetToken testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){$/;" f +sqlite3GetVTable testdocs/sqlite3.c /^# define sqlite3GetVTable(/;" d file: +sqlite3GetVTable testdocs/sqlite3.c /^SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){$/;" f +sqlite3GetVarint testdocs/sqlite3.c /^SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){$/;" f +sqlite3GetVarint32 testdocs/sqlite3.c /^SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){$/;" f +sqlite3GetVdbe testdocs/sqlite3.c /^SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){$/;" f +sqlite3GlobalConfig testdocs/sqlite3.c /^ #define sqlite3GlobalConfig /;" d file: +sqlite3HaltConstraint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3HaltConstraint($/;" f +sqlite3HashClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){$/;" f +sqlite3HashFind testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){$/;" f +sqlite3HashInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){$/;" f +sqlite3HashInsert testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){$/;" f +sqlite3HeaderSizeBtree testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }$/;" f +sqlite3HeaderSizePcache testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }$/;" f +sqlite3HeaderSizePcache1 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }$/;" f +sqlite3HeapNearlyFull testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){$/;" f +sqlite3HexToBlob testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){$/;" f +sqlite3HexToInt testdocs/sqlite3.c /^SQLITE_PRIVATE u8 sqlite3HexToInt(int h){$/;" f +sqlite3Hooks testdocs/sqlite3.c /^} sqlite3Hooks = { 0, 0 };$/;" v typeref:struct:BenignMallocHooks file: +sqlite3Hwtime testdocs/sqlite3.c /^ __inline__ sqlite_uint64 sqlite3Hwtime(void){$/;" f +sqlite3Hwtime testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }$/;" f +sqlite3IcuInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){$/;" f +sqlite3IdListAppend testdocs/sqlite3.c /^SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){$/;" f +sqlite3IdListDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){$/;" f +sqlite3IdListDup testdocs/sqlite3.c /^SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){$/;" f +sqlite3IdListIndex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){$/;" f +sqlite3InRhsIsConstant testdocs/sqlite3.c /^static int sqlite3InRhsIsConstant(Expr *pIn){$/;" f file: +sqlite3IndexAffinityOk testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){$/;" f +sqlite3IndexAffinityStr testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){$/;" f +sqlite3IndexColumnAffinity testdocs/sqlite3.c /^SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){$/;" f +sqlite3IndexedByLookup testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){$/;" f +sqlite3Init testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){$/;" f +sqlite3InitCallback testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){$/;" f +sqlite3InitInfo testdocs/sqlite3.c /^ struct sqlite3InitInfo { \/* Information used during initialization *\/$/;" s struct:sqlite3 file: +sqlite3InitOne testdocs/sqlite3.c /^static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){$/;" f file: +sqlite3Insert testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Insert($/;" f +sqlite3InsertBuiltinFuncs testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs($/;" f +sqlite3IntFloatCompare testdocs/sqlite3.c /^static int sqlite3IntFloatCompare(i64 i, double r){$/;" f file: +sqlite3IntTokens testdocs/sqlite3.c /^SQLITE_PRIVATE const Token sqlite3IntTokens[] = {$/;" v +sqlite3IntTokens testdocs/sqlite3.c /^SQLITE_PRIVATE const Token sqlite3IntTokens[];$/;" v +sqlite3InvalidFunction testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3InvalidFunction($/;" f +sqlite3InvokeBusyHandler testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){$/;" f +sqlite3IoTrace testdocs/sqlite3.c /^SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);$/;" v +sqlite3IoTrace testdocs/sqlite3.c /^SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0;$/;" v +sqlite3IoerrnomemError testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){$/;" f +sqlite3IsEbcdicIdChar testdocs/sqlite3.c /^SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = {$/;" v +sqlite3IsEbcdicIdChar testdocs/sqlite3.c /^SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];$/;" v +sqlite3IsIdChar testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); }$/;" f +sqlite3IsLikeFunction testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){$/;" f +sqlite3IsNaN testdocs/sqlite3.c /^# define sqlite3IsNaN(/;" d file: +sqlite3IsNaN testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IsNaN(double x){$/;" f +sqlite3IsNumericAffinity testdocs/sqlite3.c /^#define sqlite3IsNumericAffinity(/;" d file: +sqlite3IsReadOnly testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){$/;" f +sqlite3IsRowid testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3IsRowid(const char *z){$/;" f +sqlite3IsToplevel testdocs/sqlite3.c /^# define sqlite3IsToplevel(/;" d file: +sqlite3Isalnum testdocs/sqlite3.c /^# define sqlite3Isalnum(/;" d file: +sqlite3Isalpha testdocs/sqlite3.c /^# define sqlite3Isalpha(/;" d file: +sqlite3Isdigit testdocs/sqlite3.c /^# define sqlite3Isdigit(/;" d file: +sqlite3Isquote testdocs/sqlite3.c /^# define sqlite3Isquote(/;" d file: +sqlite3Isspace testdocs/sqlite3.c /^# define sqlite3Isspace(/;" d file: +sqlite3Isxdigit testdocs/sqlite3.c /^# define sqlite3Isxdigit(/;" d file: +sqlite3JoinType testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){$/;" f +sqlite3JournalCreate testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){$/;" f +sqlite3JournalIsInMemory testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){$/;" f +sqlite3JournalModename testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){$/;" f +sqlite3JournalOpen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3JournalOpen($/;" f +sqlite3JournalSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){$/;" f +sqlite3Json1Init testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){$/;" f +sqlite3KeyInfoAlloc testdocs/sqlite3.c /^SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){$/;" f +sqlite3KeyInfoIsWriteable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }$/;" f +sqlite3KeyInfoOfIndex testdocs/sqlite3.c /^SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){$/;" f +sqlite3KeyInfoRef testdocs/sqlite3.c /^SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){$/;" f +sqlite3KeyInfoUnref testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){$/;" f +sqlite3KeywordCode testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){$/;" f +sqlite3LeaveMutexAndCloseZombie testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){$/;" f +sqlite3LimitWhere testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3LimitWhere($/;" f +sqlite3LoadExtension testdocs/sqlite3.c /^static int sqlite3LoadExtension($/;" f file: +sqlite3LocateCollSeq testdocs/sqlite3.c /^SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){$/;" f +sqlite3LocateTable testdocs/sqlite3.c /^SQLITE_PRIVATE Table *sqlite3LocateTable($/;" f +sqlite3LocateTableItem testdocs/sqlite3.c /^SQLITE_PRIVATE Table *sqlite3LocateTableItem($/;" f +sqlite3LockAndPrepare testdocs/sqlite3.c /^static int sqlite3LockAndPrepare($/;" f file: +sqlite3LogEst testdocs/sqlite3.c /^SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){$/;" f +sqlite3LogEstAdd testdocs/sqlite3.c /^SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){$/;" f +sqlite3LogEstFromDouble testdocs/sqlite3.c /^SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){$/;" f +sqlite3LogEstToInt testdocs/sqlite3.c /^SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){$/;" f +sqlite3MPrintf testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){$/;" f +sqlite3Malloc testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3Malloc(u64 n){$/;" f +sqlite3MallocAlarm testdocs/sqlite3.c /^static void sqlite3MallocAlarm(int nByte){$/;" f file: +sqlite3MallocEnd testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MallocEnd(void){$/;" f +sqlite3MallocInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MallocInit(void){$/;" f +sqlite3MallocMutex testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){$/;" f +sqlite3MallocSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MallocSize(void *p){$/;" f +sqlite3MallocZero testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){$/;" f +sqlite3MatchSpanName testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MatchSpanName($/;" f +sqlite3MaterializeView testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MaterializeView($/;" f +sqlite3MayAbort testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MayAbort(Parse *pParse){$/;" f +sqlite3MemCompare testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){$/;" f +sqlite3MemFree testdocs/sqlite3.c /^static void sqlite3MemFree(void *pPrior){ return; }$/;" f file: +sqlite3MemFree testdocs/sqlite3.c /^static void sqlite3MemFree(void *pPrior){$/;" f file: +sqlite3MemGetMemsys3 testdocs/sqlite3.c /^SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){$/;" f +sqlite3MemGetMemsys5 testdocs/sqlite3.c /^SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){$/;" f +sqlite3MemGetWin32 testdocs/sqlite3.c /^SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){$/;" f +sqlite3MemInit testdocs/sqlite3.c /^static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; }$/;" f file: +sqlite3MemInit testdocs/sqlite3.c /^static int sqlite3MemInit(void *NotUsed){$/;" f file: +sqlite3MemJournalOpen testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){$/;" f +sqlite3MemMalloc testdocs/sqlite3.c /^static void *sqlite3MemMalloc(int nByte){ return 0; }$/;" f file: +sqlite3MemMalloc testdocs/sqlite3.c /^static void *sqlite3MemMalloc(int nByte){$/;" f file: +sqlite3MemRealloc testdocs/sqlite3.c /^static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; }$/;" f file: +sqlite3MemRealloc testdocs/sqlite3.c /^static void *sqlite3MemRealloc(void *pPrior, int nByte){$/;" f file: +sqlite3MemRoundup testdocs/sqlite3.c /^static int sqlite3MemRoundup(int n){ return n; }$/;" f file: +sqlite3MemRoundup testdocs/sqlite3.c /^static int sqlite3MemRoundup(int n){$/;" f file: +sqlite3MemSetDefault testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemSetDefault(void){$/;" f +sqlite3MemShutdown testdocs/sqlite3.c /^static void sqlite3MemShutdown(void *NotUsed){ return; }$/;" f file: +sqlite3MemShutdown testdocs/sqlite3.c /^static void sqlite3MemShutdown(void *NotUsed){$/;" f file: +sqlite3MemSize testdocs/sqlite3.c /^static int sqlite3MemSize(void *p){$/;" f file: +sqlite3MemSize testdocs/sqlite3.c /^static int sqlite3MemSize(void *pPrior){ return 0; }$/;" f file: +sqlite3MemSize testdocs/sqlite3.c /^static int sqlite3MemSize(void *pPrior){$/;" f file: +sqlite3MemdebugBacktrace testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemdebugBacktrace(int depth){$/;" f +sqlite3MemdebugBacktraceCallback testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){$/;" f +sqlite3MemdebugDump testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){$/;" f +sqlite3MemdebugHasType testdocs/sqlite3.c /^# define sqlite3MemdebugHasType(/;" d file: +sqlite3MemdebugHasType testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){$/;" f +sqlite3MemdebugMallocCount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){$/;" f +sqlite3MemdebugNoType testdocs/sqlite3.c /^# define sqlite3MemdebugNoType(/;" d file: +sqlite3MemdebugNoType testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){$/;" f +sqlite3MemdebugSetType testdocs/sqlite3.c /^# define sqlite3MemdebugSetType(/;" d file: +sqlite3MemdebugSetType testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){$/;" f +sqlite3MemdebugSettitle testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemdebugSettitle(const char *zTitle){$/;" f +sqlite3MemdebugSync testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemdebugSync(){$/;" f +sqlite3MemoryBarrier testdocs/sqlite3.c /^# define sqlite3MemoryBarrier(/;" d file: +sqlite3MemoryBarrier testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MemoryBarrier(void){$/;" f +sqlite3Memsys3Dump testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){$/;" f +sqlite3Memsys5Dump testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){$/;" f +sqlite3MemsysGetHeader testdocs/sqlite3.c /^static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){$/;" f file: +sqlite3MisuseError testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MisuseError(int lineno){$/;" f +sqlite3MulInt64 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){$/;" f +sqlite3MultiWrite testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){$/;" f +sqlite3MutexAlloc testdocs/sqlite3.c /^#define sqlite3MutexAlloc(/;" d file: +sqlite3MutexAlloc testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){$/;" f +sqlite3MutexEnd testdocs/sqlite3.c /^#define sqlite3MutexEnd(/;" d file: +sqlite3MutexEnd testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MutexEnd(void){$/;" f +sqlite3MutexInit testdocs/sqlite3.c /^#define sqlite3MutexInit(/;" d file: +sqlite3MutexInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3MutexInit(void){$/;" f +sqlite3NameFromToken testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){$/;" f +sqlite3NestedParse testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){$/;" f +sqlite3NoTempsInRange testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){$/;" f +sqlite3NomemError testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3NomemError(int lineno){$/;" f +sqlite3NoopMutex testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){$/;" f +sqlite3OSTrace testdocs/sqlite3.c /^ int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE;$/;" v +sqlite3OomClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){$/;" f +sqlite3OomFault testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){$/;" f +sqlite3OpcodeName testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){$/;" f +sqlite3OpcodeProperty testdocs/sqlite3.c /^SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;$/;" v +sqlite3OpcodeProperty testdocs/sqlite3.c /^SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];$/;" v +sqlite3OpenMasterTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){$/;" f +sqlite3OpenTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OpenTable($/;" f +sqlite3OpenTableAndIndices testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OpenTableAndIndices($/;" f +sqlite3OpenTempDatabase testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){$/;" f +sqlite3OsAccess testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsAccess($/;" f +sqlite3OsCheckReservedLock testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){$/;" f +sqlite3OsClose testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){$/;" f +sqlite3OsCloseFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){$/;" f +sqlite3OsCurrentTimeInt64 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){$/;" f +sqlite3OsDelete testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){$/;" f +sqlite3OsDeviceCharacteristics testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){$/;" f +sqlite3OsDlClose testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){$/;" f +sqlite3OsDlError testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){$/;" f +sqlite3OsDlOpen testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){$/;" f +sqlite3OsDlSym testdocs/sqlite3.c /^SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){$/;" f +sqlite3OsFetch testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){$/;" f +sqlite3OsFileControl testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){$/;" f +sqlite3OsFileControlHint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){$/;" f +sqlite3OsFileSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){$/;" f +sqlite3OsFullPathname testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsFullPathname($/;" f +sqlite3OsGetLastError testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){$/;" f +sqlite3OsInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsInit(void){$/;" f +sqlite3OsLock testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){$/;" f +sqlite3OsOpen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsOpen($/;" f +sqlite3OsOpenMalloc testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsOpenMalloc($/;" f +sqlite3OsRandomness testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){$/;" f +sqlite3OsRead testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){$/;" f +sqlite3OsSectorSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){$/;" f +sqlite3OsShmBarrier testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){$/;" f +sqlite3OsShmLock testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){$/;" f +sqlite3OsShmMap testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsShmMap($/;" f +sqlite3OsShmUnmap testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){$/;" f +sqlite3OsSleep testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){$/;" f +sqlite3OsSync testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){$/;" f +sqlite3OsTruncate testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){$/;" f +sqlite3OsUnfetch testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){$/;" f +sqlite3OsUnlock testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){$/;" f +sqlite3OsWrite testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){$/;" f +sqlite3PCacheBufferSetup testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){$/;" f +sqlite3PCachePercentDirty testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){$/;" f +sqlite3PCacheSetDefault testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){$/;" f +sqlite3PExpr testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3PExpr($/;" f +sqlite3PExprAddSelect testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){$/;" f +sqlite3PageFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PageFree(void *p){$/;" f +sqlite3PageMalloc testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){$/;" f +sqlite3PagerAlignReserve testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){$/;" f +sqlite3PagerBackupPtr testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){$/;" f +sqlite3PagerBegin testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){$/;" f +sqlite3PagerCacheStat testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){$/;" f +sqlite3PagerCheckpoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerCheckpoint($/;" f +sqlite3PagerClearCache testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){$/;" f +sqlite3PagerClose testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){$/;" f +sqlite3PagerCloseWal testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){$/;" f +sqlite3PagerCodec testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){$/;" f +sqlite3PagerCommitPhaseOne testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne($/;" f +sqlite3PagerCommitPhaseTwo testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){$/;" f +sqlite3PagerDataVersion testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){$/;" f +sqlite3PagerDontWrite testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){$/;" f +sqlite3PagerExclusiveLock testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){$/;" f +sqlite3PagerFile testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){$/;" f +sqlite3PagerFilename testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){$/;" f +sqlite3PagerFlush testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){$/;" f +sqlite3PagerGet testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerGet($/;" f +sqlite3PagerGetCodec testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){$/;" f +sqlite3PagerGetData testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){$/;" f +sqlite3PagerGetExtra testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){$/;" f +sqlite3PagerGetJournalMode testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){$/;" f +sqlite3PagerIsMemdb testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){$/;" f +sqlite3PagerIsreadonly testdocs/sqlite3.c /^SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){$/;" f +sqlite3PagerIswriteable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){$/;" f +sqlite3PagerJournalSizeLimit testdocs/sqlite3.c /^SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){$/;" f +sqlite3PagerJournalname testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){$/;" f +sqlite3PagerJrnlFile testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){$/;" f +sqlite3PagerLockingMode testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){$/;" f +sqlite3PagerLookup testdocs/sqlite3.c /^SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){$/;" f +sqlite3PagerMaxPageCount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){$/;" f +sqlite3PagerMemUsed testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){$/;" f +sqlite3PagerMovepage testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){$/;" f +sqlite3PagerOkToChangeJournalMode testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){$/;" f +sqlite3PagerOpen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerOpen($/;" f +sqlite3PagerOpenSavepoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){$/;" f +sqlite3PagerOpenWal testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerOpenWal($/;" f +sqlite3PagerPageRefcount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){$/;" f +sqlite3PagerPagecount testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){$/;" f +sqlite3PagerPagenumber testdocs/sqlite3.c /^SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage *pPg){$/;" f +sqlite3PagerReadFileheader testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){$/;" f +sqlite3PagerRef testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){$/;" f +sqlite3PagerRefcount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){$/;" f +sqlite3PagerRekey testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){$/;" f +sqlite3PagerRollback testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){$/;" f +sqlite3PagerSavepoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){$/;" f +sqlite3PagerSetBusyhandler testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerSetBusyhandler($/;" f +sqlite3PagerSetCachesize testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){$/;" f +sqlite3PagerSetCodec testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerSetCodec($/;" f +sqlite3PagerSetFlags testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerSetFlags($/;" f +sqlite3PagerSetJournalMode testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){$/;" f +sqlite3PagerSetMmapLimit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){$/;" f +sqlite3PagerSetPagesize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){$/;" f +sqlite3PagerSetSpillsize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){$/;" f +sqlite3PagerSharedLock testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){$/;" f +sqlite3PagerShrink testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){$/;" f +sqlite3PagerSnapshotGet testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){$/;" f +sqlite3PagerSnapshotOpen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){$/;" f +sqlite3PagerSnapshotRecover testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){$/;" f +sqlite3PagerState testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){$/;" f +sqlite3PagerStats testdocs/sqlite3.c /^SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){$/;" f +sqlite3PagerSync testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){$/;" f +sqlite3PagerTempSpace testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){$/;" f +sqlite3PagerTruncateImage testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){$/;" f +sqlite3PagerUnref testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){$/;" f +sqlite3PagerUnrefNotNull testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){$/;" f +sqlite3PagerUseWal testdocs/sqlite3.c /^# define sqlite3PagerUseWal(/;" d file: +sqlite3PagerUseWal testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){$/;" f +sqlite3PagerVfs testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){$/;" f +sqlite3PagerWalCallback testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){$/;" f +sqlite3PagerWalFramesize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){$/;" f +sqlite3PagerWalSupported testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){$/;" f +sqlite3PagerWrite testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){$/;" f +sqlite3ParseToplevel testdocs/sqlite3.c /^# define sqlite3ParseToplevel(/;" d file: +sqlite3ParseUri testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ParseUri($/;" f +sqlite3Parser testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Parser($/;" f +sqlite3ParserARG_FETCH testdocs/sqlite3.c /^#define sqlite3ParserARG_FETCH /;" d file: +sqlite3ParserARG_PDECL testdocs/sqlite3.c /^#define sqlite3ParserARG_PDECL /;" d file: +sqlite3ParserARG_SDECL testdocs/sqlite3.c /^#define sqlite3ParserARG_SDECL /;" d file: +sqlite3ParserARG_STORE testdocs/sqlite3.c /^#define sqlite3ParserARG_STORE /;" d file: +sqlite3ParserAlloc testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){$/;" f +sqlite3ParserFinalize testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){$/;" f +sqlite3ParserFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ParserFree($/;" f +sqlite3ParserInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){$/;" f +sqlite3ParserReset testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){$/;" f +sqlite3ParserStackPeak testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){$/;" f +sqlite3ParserTOKENTYPE testdocs/sqlite3.c /^#define sqlite3ParserTOKENTYPE /;" d file: +sqlite3ParserTrace testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){$/;" f +sqlite3Parser_ENGINEALWAYSONSTACK testdocs/sqlite3.c /^# define sqlite3Parser_ENGINEALWAYSONSTACK /;" d file: +sqlite3Pcache1Mutex testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){$/;" f +sqlite3PcacheCleanAll testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){$/;" f +sqlite3PcacheClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){$/;" f +sqlite3PcacheClearSyncFlags testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){$/;" f +sqlite3PcacheClearWritable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){$/;" f +sqlite3PcacheClose testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){$/;" f +sqlite3PcacheDirtyList testdocs/sqlite3.c /^SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){$/;" f +sqlite3PcacheDrop testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){$/;" f +sqlite3PcacheFetch testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch($/;" f +sqlite3PcacheFetchFinish testdocs/sqlite3.c /^SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish($/;" f +sqlite3PcacheFetchStress testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheFetchStress($/;" f +sqlite3PcacheGetCachesize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){$/;" f +sqlite3PcacheInitialize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheInitialize(void){$/;" f +sqlite3PcacheIterateDirty testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){$/;" f +sqlite3PcacheMakeClean testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){$/;" f +sqlite3PcacheMakeDirty testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){$/;" f +sqlite3PcacheMove testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){$/;" f +sqlite3PcacheMxDump testdocs/sqlite3.c /^ int sqlite3PcacheMxDump = 9999; \/* Max cache entries for pcacheDump() *\/$/;" v +sqlite3PcacheOpen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheOpen($/;" f +sqlite3PcachePageRefcount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){$/;" f +sqlite3PcachePageSanity testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){$/;" f +sqlite3PcachePagecount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){$/;" f +sqlite3PcacheRef testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){$/;" f +sqlite3PcacheRefCount testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){$/;" f +sqlite3PcacheRelease testdocs/sqlite3.c /^SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){$/;" f +sqlite3PcacheReleaseMemory testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){$/;" f +sqlite3PcacheSetCachesize testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){$/;" f +sqlite3PcacheSetPageSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){$/;" f +sqlite3PcacheSetSpillsize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){$/;" f +sqlite3PcacheShrink testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){$/;" f +sqlite3PcacheShutdown testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheShutdown(void){$/;" f +sqlite3PcacheSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }$/;" f +sqlite3PcacheStats testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheStats($/;" f +sqlite3PcacheTrace testdocs/sqlite3.c /^ int sqlite3PcacheTrace = 2; \/* 0: off 1: simple 2: cache dumps *\/$/;" v +sqlite3PcacheTruncate testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){$/;" f +sqlite3PendingByte testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;$/;" v +sqlite3PendingByte testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PendingByte;$/;" v +sqlite3Pragma testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Pragma($/;" f +sqlite3PragmaVtabRegister testdocs/sqlite3.c /^SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){$/;" f +sqlite3Prepare testdocs/sqlite3.c /^static int sqlite3Prepare($/;" f file: +sqlite3Prepare16 testdocs/sqlite3.c /^static int sqlite3Prepare16($/;" f file: +sqlite3PrimaryKeyIndex testdocs/sqlite3.c /^SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){$/;" f +sqlite3Prng testdocs/sqlite3.c /^} sqlite3Prng;$/;" v typeref:struct:sqlite3PrngType file: +sqlite3PrngRestoreState testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PrngRestoreState(void){$/;" f +sqlite3PrngSaveState testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3PrngSaveState(void){$/;" f +sqlite3PrngType testdocs/sqlite3.c /^static SQLITE_WSD struct sqlite3PrngType {$/;" s file: +sqlite3Put4byte testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){$/;" f +sqlite3PutVarint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){$/;" f +sqlite3ReadSchema testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){$/;" f +sqlite3Realloc testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){$/;" f +sqlite3RefillIndex testdocs/sqlite3.c /^static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){$/;" f file: +sqlite3RegisterBuiltinFunctions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){$/;" f +sqlite3RegisterDateTimeFunctions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){$/;" f +sqlite3RegisterLikeFunctions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){$/;" f +sqlite3RegisterPerConnectionBuiltinFunctions testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){$/;" f +sqlite3Reindex testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){$/;" f +sqlite3ReleaseTempRange testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){$/;" f +sqlite3ReleaseTempReg testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){$/;" f +sqlite3Reprepare testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){$/;" f +sqlite3ResetAllSchemasOfConnection testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){$/;" f +sqlite3ResetOneSchema testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){$/;" f +sqlite3ResolveExprListNames testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ResolveExprListNames($/;" f +sqlite3ResolveExprNames testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ResolveExprNames($/;" f +sqlite3ResolveOrderGroupBy testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy($/;" f +sqlite3ResolvePartIdxLabel testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){$/;" f +sqlite3ResolveSelectNames testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ResolveSelectNames($/;" f +sqlite3ResolveSelfReference testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ResolveSelfReference($/;" f +sqlite3ResultSetOfSelect testdocs/sqlite3.c /^SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){$/;" f +sqlite3RollbackAll testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){$/;" f +sqlite3RollbackTransaction testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){$/;" f +sqlite3RootPageMoved testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){$/;" f +sqlite3RowSetClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){$/;" f +sqlite3RowSetInit testdocs/sqlite3.c /^SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){$/;" f +sqlite3RowSetInsert testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){$/;" f +sqlite3RowSetNext testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){$/;" f +sqlite3RowSetTest testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){$/;" f +sqlite3RowidConstraint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3RowidConstraint($/;" f +sqlite3RtreeInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){$/;" f +sqlite3RunParser testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){$/;" f +sqlite3RunVacuum testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){$/;" f +sqlite3SafetyCheckOk testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){$/;" f +sqlite3SafetyCheckSickOrOk testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){$/;" f +sqlite3SavedPrng testdocs/sqlite3.c /^static SQLITE_WSD struct sqlite3PrngType sqlite3SavedPrng;$/;" v typeref:struct:sqlite3PrngType file: +sqlite3Savepoint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){$/;" f +sqlite3SchemaClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SchemaClear(void *p){$/;" f +sqlite3SchemaGet testdocs/sqlite3.c /^SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){$/;" f +sqlite3SchemaMutexHeld testdocs/sqlite3.c /^# define sqlite3SchemaMutexHeld(/;" d file: +sqlite3SchemaMutexHeld testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){$/;" f +sqlite3SchemaToIndex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){$/;" f +sqlite3ScratchFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ScratchFree(void *p){$/;" f +sqlite3ScratchMalloc testdocs/sqlite3.c /^SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){$/;" f +sqlite3SectorSize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){$/;" f +sqlite3Select testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Select($/;" f +sqlite3SelectAddColumnTypeAndCollation testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation($/;" f +sqlite3SelectAddTypeInfo testdocs/sqlite3.c /^static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){$/;" f file: +sqlite3SelectDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){$/;" f +sqlite3SelectDestInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){$/;" f +sqlite3SelectDup testdocs/sqlite3.c /^SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){$/;" f +sqlite3SelectDup testdocs/sqlite3.c /^SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){$/;" f +sqlite3SelectExpand testdocs/sqlite3.c /^static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){$/;" f file: +sqlite3SelectExprHeight testdocs/sqlite3.c /^ #define sqlite3SelectExprHeight(/;" d file: +sqlite3SelectExprHeight testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){$/;" f +sqlite3SelectNew testdocs/sqlite3.c /^SQLITE_PRIVATE Select *sqlite3SelectNew($/;" f +sqlite3SelectPrep testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SelectPrep($/;" f +sqlite3SelectSetName testdocs/sqlite3.c /^# define sqlite3SelectSetName(/;" d file: +sqlite3SelectSetName testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){$/;" f +sqlite3SelectTrace testdocs/sqlite3.c /^\/***\/ int sqlite3SelectTrace = 0;$/;" v +sqlite3SelectWrongNumTermsError testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){$/;" f +sqlite3SetHasNullFlag testdocs/sqlite3.c /^static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){$/;" f file: +sqlite3SetMakeRecordP5 testdocs/sqlite3.c /^# define sqlite3SetMakeRecordP5(/;" d file: +sqlite3SetMakeRecordP5 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){$/;" f +sqlite3SetString testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){$/;" f +sqlite3SharedCacheList testdocs/sqlite3.c /^SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;$/;" v +sqlite3SharedCacheList testdocs/sqlite3.c /^static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;$/;" v file: +sqlite3SkipAccumulatorLoad testdocs/sqlite3.c /^static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){$/;" f file: +sqlite3SmallTypeSizes testdocs/sqlite3.c /^static const u8 sqlite3SmallTypeSizes[] = {$/;" v file: +sqlite3SrcListAppend testdocs/sqlite3.c /^SQLITE_PRIVATE SrcList *sqlite3SrcListAppend($/;" f +sqlite3SrcListAppendFromTerm testdocs/sqlite3.c /^SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm($/;" f +sqlite3SrcListAssignCursors testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){$/;" f +sqlite3SrcListDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){$/;" f +sqlite3SrcListDup testdocs/sqlite3.c /^SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){$/;" f +sqlite3SrcListEnlarge testdocs/sqlite3.c /^SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge($/;" f +sqlite3SrcListFuncArgs testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){$/;" f +sqlite3SrcListIndexedBy testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){$/;" f +sqlite3SrcListLookup testdocs/sqlite3.c /^SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){$/;" f +sqlite3SrcListShiftJoinType testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){$/;" f +sqlite3StackAllocRaw testdocs/sqlite3.c /^# define sqlite3StackAllocRaw(/;" d file: +sqlite3StackAllocZero testdocs/sqlite3.c /^# define sqlite3StackAllocZero(/;" d file: +sqlite3StackFree testdocs/sqlite3.c /^# define sqlite3StackFree(/;" d file: +sqlite3StartTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StartTable($/;" f +sqlite3Stat testdocs/sqlite3.c /^} sqlite3Stat = { {0,}, {0,} };$/;" v typeref:struct:sqlite3StatType file: +sqlite3Stat4Column testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Stat4Column($/;" f +sqlite3Stat4ProbeFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){$/;" f +sqlite3Stat4ProbeSetValue testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue($/;" f +sqlite3Stat4ValueFromExpr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr($/;" f +sqlite3StatType testdocs/sqlite3.c /^static SQLITE_WSD struct sqlite3StatType {$/;" s file: +sqlite3StatType testdocs/sqlite3.c /^typedef struct sqlite3StatType sqlite3StatType;$/;" t typeref:struct:sqlite3StatType file: +sqlite3StatValueType testdocs/sqlite3.c /^typedef sqlite3_int64 sqlite3StatValueType;$/;" t file: +sqlite3StatValueType testdocs/sqlite3.c /^typedef u32 sqlite3StatValueType;$/;" t file: +sqlite3StatusDown testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){$/;" f +sqlite3StatusHighwater testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){$/;" f +sqlite3StatusUp testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StatusUp(int op, int N){$/;" f +sqlite3StatusValue testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){$/;" f +sqlite3Step testdocs/sqlite3.c /^static int sqlite3Step(Vdbe *p){$/;" f file: +sqlite3StmtCurrentTime testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){$/;" f +sqlite3StrAccumAppend testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){$/;" f +sqlite3StrAccumAppendAll testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){$/;" f +sqlite3StrAccumEnlarge testdocs/sqlite3.c /^static int sqlite3StrAccumEnlarge(StrAccum *p, int N){$/;" f file: +sqlite3StrAccumFinish testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){$/;" f +sqlite3StrAccumInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){$/;" f +sqlite3StrAccumReset testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){$/;" f +sqlite3StrBINARY testdocs/sqlite3.c /^SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";$/;" v +sqlite3StrBINARY testdocs/sqlite3.c /^SQLITE_PRIVATE const char sqlite3StrBINARY[];$/;" v +sqlite3StrICmp testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){$/;" f +sqlite3StrNICmp testdocs/sqlite3.c /^#define sqlite3StrNICmp /;" d file: +sqlite3StringToId testdocs/sqlite3.c /^static void sqlite3StringToId(Expr *p){$/;" f file: +sqlite3Strlen30 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Strlen30(const char *z){$/;" f +sqlite3SubInt64 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){$/;" f +sqlite3SubselectError testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){$/;" f +sqlite3SystemError testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){$/;" f +sqlite3TableAffinity testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){$/;" f +sqlite3TableColumnAffinity testdocs/sqlite3.c /^SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){$/;" f +sqlite3TableLock testdocs/sqlite3.c /^ #define sqlite3TableLock(/;" d file: +sqlite3TableLock testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TableLock($/;" f +sqlite3TempInMemory testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){$/;" f +sqlite3ThreadCreate testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ThreadCreate($/;" f +sqlite3ThreadJoin testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){$/;" f +sqlite3ThreadProc testdocs/sqlite3.c /^static unsigned __stdcall sqlite3ThreadProc($/;" f file: +sqlite3TokenInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){$/;" f +sqlite3Tolower testdocs/sqlite3.c /^# define sqlite3Tolower(/;" d file: +sqlite3Toupper testdocs/sqlite3.c /^# define sqlite3Toupper(/;" d file: +sqlite3TransferBindings testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){$/;" f +sqlite3TreeViewBareExprList testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TreeViewBareExprList($/;" f +sqlite3TreeViewExpr testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){$/;" f +sqlite3TreeViewExprList testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TreeViewExprList($/;" f +sqlite3TreeViewItem testdocs/sqlite3.c /^static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){$/;" f file: +sqlite3TreeViewLine testdocs/sqlite3.c /^static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){$/;" f file: +sqlite3TreeViewPop testdocs/sqlite3.c /^static void sqlite3TreeViewPop(TreeView *p){$/;" f file: +sqlite3TreeViewPush testdocs/sqlite3.c /^static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){$/;" f file: +sqlite3TreeViewSelect testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){$/;" f +sqlite3TreeViewWith testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){$/;" f +sqlite3TriggerColmask testdocs/sqlite3.c /^# define sqlite3TriggerColmask(/;" d file: +sqlite3TriggerColmask testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3TriggerColmask($/;" f +sqlite3TriggerDeleteStep testdocs/sqlite3.c /^SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep($/;" f +sqlite3TriggerInsertStep testdocs/sqlite3.c /^SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep($/;" f +sqlite3TriggerList testdocs/sqlite3.c /^# define sqlite3TriggerList(/;" d file: +sqlite3TriggerList testdocs/sqlite3.c /^SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){$/;" f +sqlite3TriggerSelectStep testdocs/sqlite3.c /^SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){$/;" f +sqlite3TriggerUpdateStep testdocs/sqlite3.c /^SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep($/;" f +sqlite3TriggersExist testdocs/sqlite3.c /^# define sqlite3TriggersExist(/;" d file: +sqlite3TriggersExist testdocs/sqlite3.c /^SQLITE_PRIVATE Trigger *sqlite3TriggersExist($/;" f +sqlite3TwoPartName testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3TwoPartName($/;" f +sqlite3UniqueConstraint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3UniqueConstraint($/;" f +sqlite3UnlinkAndDeleteIndex testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){$/;" f +sqlite3UnlinkAndDeleteTable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){$/;" f +sqlite3UnlinkAndDeleteTrigger testdocs/sqlite3.c /^# define sqlite3UnlinkAndDeleteTrigger(/;" d file: +sqlite3UnlinkAndDeleteTrigger testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){$/;" f +sqlite3Update testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Update($/;" f +sqlite3UpperToLower testdocs/sqlite3.c /^SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {$/;" v +sqlite3UpperToLower testdocs/sqlite3.c /^SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];$/;" v +sqlite3UserAuthTable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){$/;" f +sqlite3Utf16ByteLen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){$/;" f +sqlite3Utf16to8 testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){$/;" f +sqlite3Utf8CharLen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){$/;" f +sqlite3Utf8Read testdocs/sqlite3.c /^# define sqlite3Utf8Read(/;" d file: +sqlite3Utf8Read testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3Utf8Read($/;" f +sqlite3Utf8To8 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char *zIn){$/;" f +sqlite3Utf8Trans1 testdocs/sqlite3.c /^static const unsigned char sqlite3Utf8Trans1[] = {$/;" v file: +sqlite3UtfSelfTest testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3UtfSelfTest(void){$/;" f +sqlite3VListAdd testdocs/sqlite3.c /^SQLITE_PRIVATE VList *sqlite3VListAdd($/;" f +sqlite3VListNameToNum testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nName){$/;" f +sqlite3VListNumToName testdocs/sqlite3.c /^SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){$/;" f +sqlite3VMPrintf testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){$/;" f +sqlite3VXPrintf testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VXPrintf($/;" f +sqlite3Vacuum testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){$/;" f +sqlite3ValueApplyAffinity testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ValueApplyAffinity($/;" f +sqlite3ValueBytes testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){$/;" f +sqlite3ValueFree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){$/;" f +sqlite3ValueFromExpr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ValueFromExpr($/;" f +sqlite3ValueNew testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){$/;" f +sqlite3ValueSetNull testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){$/;" f +sqlite3ValueSetStr testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3ValueSetStr($/;" f +sqlite3ValueText testdocs/sqlite3.c /^SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){$/;" f +sqlite3VarintLen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VarintLen(u64 v){$/;" f +sqlite3VdbeAddOp0 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){$/;" f +sqlite3VdbeAddOp1 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){$/;" f +sqlite3VdbeAddOp2 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){$/;" f +sqlite3VdbeAddOp3 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){$/;" f +sqlite3VdbeAddOp4 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAddOp4($/;" f +sqlite3VdbeAddOp4Dup8 testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8($/;" f +sqlite3VdbeAddOp4Int testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAddOp4Int($/;" f +sqlite3VdbeAddOpList testdocs/sqlite3.c /^SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList($/;" f +sqlite3VdbeAddParseSchemaOp testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){$/;" f +sqlite3VdbeAllocUnpackedRecord testdocs/sqlite3.c /^SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord($/;" f +sqlite3VdbeAppendP4 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){$/;" f +sqlite3VdbeAssertMayAbort testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){$/;" f +sqlite3VdbeChangeEncoding testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){$/;" f +sqlite3VdbeChangeOpcode testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){$/;" f +sqlite3VdbeChangeP1 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){$/;" f +sqlite3VdbeChangeP2 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){$/;" f +sqlite3VdbeChangeP3 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){$/;" f +sqlite3VdbeChangeP4 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){$/;" f +sqlite3VdbeChangeP5 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){$/;" f +sqlite3VdbeChangeToNoop testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){$/;" f +sqlite3VdbeCheckFk testdocs/sqlite3.c /^# define sqlite3VdbeCheckFk(/;" d file: +sqlite3VdbeCheckFk testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){$/;" f +sqlite3VdbeCheckMemInvariants testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){$/;" f +sqlite3VdbeClearObject testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){$/;" f +sqlite3VdbeCloseStatement testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){$/;" f +sqlite3VdbeComment testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){$/;" f +sqlite3VdbeCountChanges testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){$/;" f +sqlite3VdbeCreate testdocs/sqlite3.c /^SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){$/;" f +sqlite3VdbeCurrentAddr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){$/;" f +sqlite3VdbeCursorMoveto testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){$/;" f +sqlite3VdbeCursorRestore testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){$/;" f +sqlite3VdbeDb testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){$/;" f +sqlite3VdbeDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){$/;" f +sqlite3VdbeDeleteAuxData testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){$/;" f +sqlite3VdbeDeletePriorOpcode testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){$/;" f +sqlite3VdbeEndCoroutine testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){$/;" f +sqlite3VdbeEnter testdocs/sqlite3.c /^# define sqlite3VdbeEnter(/;" d file: +sqlite3VdbeEnter testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){$/;" f +sqlite3VdbeError testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){$/;" f +sqlite3VdbeExec testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeExec($/;" f +sqlite3VdbeExpandSql testdocs/sqlite3.c /^SQLITE_PRIVATE char *sqlite3VdbeExpandSql($/;" f +sqlite3VdbeFinalize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){$/;" f +sqlite3VdbeFindCompare testdocs/sqlite3.c /^SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){$/;" f +sqlite3VdbeFrameDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){$/;" f +sqlite3VdbeFrameRestore testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){$/;" f +sqlite3VdbeFreeCursor testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){$/;" f +sqlite3VdbeGetBoundValue testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){$/;" f +sqlite3VdbeGetOp testdocs/sqlite3.c /^SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){$/;" f +sqlite3VdbeGoto testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe *p, int iDest){$/;" f +sqlite3VdbeHalt testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){$/;" f +sqlite3VdbeIOTraceSql testdocs/sqlite3.c /^# define sqlite3VdbeIOTraceSql(/;" d file: +sqlite3VdbeIOTraceSql testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){$/;" f +sqlite3VdbeIdxKeyCompare testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare($/;" f +sqlite3VdbeIdxRowid testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){$/;" f +sqlite3VdbeIntValue testdocs/sqlite3.c /^SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){$/;" f +sqlite3VdbeIntegerAffinity testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){$/;" f +sqlite3VdbeJumpHere testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){$/;" f +sqlite3VdbeLeave testdocs/sqlite3.c /^# define sqlite3VdbeLeave(/;" d file: +sqlite3VdbeLeave testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){$/;" f +sqlite3VdbeLinkSubProgram testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){$/;" f +sqlite3VdbeList testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeList($/;" f +sqlite3VdbeLoadString testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){$/;" f +sqlite3VdbeMakeLabel testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){$/;" f +sqlite3VdbeMakeReady testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMakeReady($/;" f +sqlite3VdbeMemAboutToChange testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){$/;" f +sqlite3VdbeMemCast testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){$/;" f +sqlite3VdbeMemClearAndResize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){$/;" f +sqlite3VdbeMemCopy testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){$/;" f +sqlite3VdbeMemExpandBlob testdocs/sqlite3.c /^ #define sqlite3VdbeMemExpandBlob(/;" d file: +sqlite3VdbeMemExpandBlob testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){$/;" f +sqlite3VdbeMemFinalize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){$/;" f +sqlite3VdbeMemFromBtree testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemFromBtree($/;" f +sqlite3VdbeMemGrow testdocs/sqlite3.c /^SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){$/;" f +sqlite3VdbeMemHandleBom testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){$/;" f +sqlite3VdbeMemInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){$/;" f +sqlite3VdbeMemIntegerify testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){$/;" f +sqlite3VdbeMemMakeWriteable testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){$/;" f +sqlite3VdbeMemMove testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){$/;" f +sqlite3VdbeMemNulTerminate testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){$/;" f +sqlite3VdbeMemNumerify testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){$/;" f +sqlite3VdbeMemPrettyPrint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){$/;" f +sqlite3VdbeMemRealify testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){$/;" f +sqlite3VdbeMemRelease testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){$/;" f +sqlite3VdbeMemSetDouble testdocs/sqlite3.c /^# define sqlite3VdbeMemSetDouble /;" d file: +sqlite3VdbeMemSetDouble testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){$/;" f +sqlite3VdbeMemSetInt64 testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){$/;" f +sqlite3VdbeMemSetNull testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){$/;" f +sqlite3VdbeMemSetRowSet testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){$/;" f +sqlite3VdbeMemSetStr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemSetStr($/;" f +sqlite3VdbeMemSetZeroBlob testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){$/;" f +sqlite3VdbeMemShallowCopy testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){$/;" f +sqlite3VdbeMemStringify testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){$/;" f +sqlite3VdbeMemTooBig testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){$/;" f +sqlite3VdbeMemTranslate testdocs/sqlite3.c /^SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){$/;" f +sqlite3VdbeMultiLoad testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){$/;" f +sqlite3VdbeNoopComment testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){$/;" f +sqlite3VdbeOneByteSerialTypeLen testdocs/sqlite3.c /^SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){$/;" f +sqlite3VdbeParameterIndex testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){$/;" f +sqlite3VdbePreUpdateHook testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbePreUpdateHook($/;" f +sqlite3VdbePrintOp testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){$/;" f +sqlite3VdbePrintSql testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe *p){$/;" f +sqlite3VdbeRealValue testdocs/sqlite3.c /^SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){$/;" f +sqlite3VdbeRecordCompare testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeRecordCompare($/;" f +sqlite3VdbeRecordCompareWithSkip testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip($/;" f +sqlite3VdbeRecordUnpack testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeRecordUnpack($/;" f +sqlite3VdbeReset testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){$/;" f +sqlite3VdbeResetStepResult testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){$/;" f +sqlite3VdbeResolveLabel testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){$/;" f +sqlite3VdbeReusable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){$/;" f +sqlite3VdbeRewind testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){$/;" f +sqlite3VdbeRunOnlyOnce testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){$/;" f +sqlite3VdbeScanStatus testdocs/sqlite3.c /^# define sqlite3VdbeScanStatus(/;" d file: +sqlite3VdbeScanStatus testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeScanStatus($/;" f +sqlite3VdbeSerialGet testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3VdbeSerialGet($/;" f +sqlite3VdbeSerialPut testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){$/;" f +sqlite3VdbeSerialType testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){$/;" f +sqlite3VdbeSerialTypeLen testdocs/sqlite3.c /^SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){$/;" f +sqlite3VdbeSetChanges testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){$/;" f +sqlite3VdbeSetColName testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeSetColName($/;" f +sqlite3VdbeSetLineNumber testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){$/;" f +sqlite3VdbeSetNumCols testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){$/;" f +sqlite3VdbeSetP4KeyInfo testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){$/;" f +sqlite3VdbeSetSql testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){$/;" f +sqlite3VdbeSetVarmask testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){$/;" f +sqlite3VdbeSorterClose testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){$/;" f +sqlite3VdbeSorterCompare testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeSorterCompare($/;" f +sqlite3VdbeSorterInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeSorterInit($/;" f +sqlite3VdbeSorterNext testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){$/;" f +sqlite3VdbeSorterReset testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){$/;" f +sqlite3VdbeSorterRewind testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){$/;" f +sqlite3VdbeSorterRowkey testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){$/;" f +sqlite3VdbeSorterWrite testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeSorterWrite($/;" f +sqlite3VdbeSwap testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){$/;" f +sqlite3VdbeTakeOpArray testdocs/sqlite3.c /^SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){$/;" f +sqlite3VdbeTransferError testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){$/;" f +sqlite3VdbeUsesBtree testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){$/;" f +sqlite3VdbeVerifyNoMallocRequired testdocs/sqlite3.c /^# define sqlite3VdbeVerifyNoMallocRequired(/;" d file: +sqlite3VdbeVerifyNoMallocRequired testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){$/;" f +sqlite3VdbeVerifyNoResultRow testdocs/sqlite3.c /^# define sqlite3VdbeVerifyNoResultRow(/;" d file: +sqlite3VdbeVerifyNoResultRow testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){$/;" f +sqlite3VectorErrorMsg testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){$/;" f +sqlite3VectorFieldSubexpr testdocs/sqlite3.c /^SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){$/;" f +sqlite3ViewGetColumnNames testdocs/sqlite3.c /^# define sqlite3ViewGetColumnNames(/;" d file: +sqlite3ViewGetColumnNames testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){$/;" f +sqlite3VtabArgExtend testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){$/;" f +sqlite3VtabArgInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabArgInit(Parse *pParse){$/;" f +sqlite3VtabBegin testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){$/;" f +sqlite3VtabBeginParse testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabBeginParse($/;" f +sqlite3VtabCallConnect testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){$/;" f +sqlite3VtabCallCreate testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){$/;" f +sqlite3VtabCallDestroy testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){$/;" f +sqlite3VtabClear testdocs/sqlite3.c /^# define sqlite3VtabClear(/;" d file: +sqlite3VtabClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){$/;" f +sqlite3VtabCommit testdocs/sqlite3.c /^# define sqlite3VtabCommit(/;" d file: +sqlite3VtabCommit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db){$/;" f +sqlite3VtabCreateModule testdocs/sqlite3.c /^SQLITE_PRIVATE Module *sqlite3VtabCreateModule($/;" f +sqlite3VtabDisconnect testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){$/;" f +sqlite3VtabEponymousTableClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){$/;" f +sqlite3VtabEponymousTableInit testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){$/;" f +sqlite3VtabFinishParse testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){$/;" f +sqlite3VtabImportErrmsg testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){$/;" f +sqlite3VtabInSync testdocs/sqlite3.c /^# define sqlite3VtabInSync(/;" d file: +sqlite3VtabLock testdocs/sqlite3.c /^# define sqlite3VtabLock(/;" d file: +sqlite3VtabLock testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabLock(VTable *pVTab){$/;" f +sqlite3VtabMakeWritable testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){$/;" f +sqlite3VtabOverloadFunction testdocs/sqlite3.c /^SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction($/;" f +sqlite3VtabRollback testdocs/sqlite3.c /^# define sqlite3VtabRollback(/;" d file: +sqlite3VtabRollback testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){$/;" f +sqlite3VtabSavepoint testdocs/sqlite3.c /^# define sqlite3VtabSavepoint(/;" d file: +sqlite3VtabSavepoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){$/;" f +sqlite3VtabSync testdocs/sqlite3.c /^# define sqlite3VtabSync(/;" d file: +sqlite3VtabSync testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe *p){$/;" f +sqlite3VtabUnlock testdocs/sqlite3.c /^# define sqlite3VtabUnlock(/;" d file: +sqlite3VtabUnlock testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){$/;" f +sqlite3VtabUnlockList testdocs/sqlite3.c /^# define sqlite3VtabUnlockList(/;" d file: +sqlite3VtabUnlockList testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){$/;" f +sqlite3WalBeginReadTransaction testdocs/sqlite3.c /^# define sqlite3WalBeginReadTransaction(/;" d file: +sqlite3WalBeginReadTransaction testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){$/;" f +sqlite3WalBeginWriteTransaction testdocs/sqlite3.c /^# define sqlite3WalBeginWriteTransaction(/;" d file: +sqlite3WalBeginWriteTransaction testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){$/;" f +sqlite3WalCallback testdocs/sqlite3.c /^# define sqlite3WalCallback(/;" d file: +sqlite3WalCallback testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){$/;" f +sqlite3WalCheckpoint testdocs/sqlite3.c /^# define sqlite3WalCheckpoint(/;" d file: +sqlite3WalCheckpoint testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalCheckpoint($/;" f +sqlite3WalClose testdocs/sqlite3.c /^# define sqlite3WalClose(/;" d file: +sqlite3WalClose testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalClose($/;" f +sqlite3WalDbsize testdocs/sqlite3.c /^# define sqlite3WalDbsize(/;" d file: +sqlite3WalDbsize testdocs/sqlite3.c /^SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){$/;" f +sqlite3WalDefaultHook testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalDefaultHook($/;" f +sqlite3WalEndReadTransaction testdocs/sqlite3.c /^# define sqlite3WalEndReadTransaction(/;" d file: +sqlite3WalEndReadTransaction testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){$/;" f +sqlite3WalEndWriteTransaction testdocs/sqlite3.c /^# define sqlite3WalEndWriteTransaction(/;" d file: +sqlite3WalEndWriteTransaction testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){$/;" f +sqlite3WalExclusiveMode testdocs/sqlite3.c /^# define sqlite3WalExclusiveMode(/;" d file: +sqlite3WalExclusiveMode testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){$/;" f +sqlite3WalFile testdocs/sqlite3.c /^# define sqlite3WalFile(/;" d file: +sqlite3WalFile testdocs/sqlite3.c /^SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){$/;" f +sqlite3WalFindFrame testdocs/sqlite3.c /^# define sqlite3WalFindFrame(/;" d file: +sqlite3WalFindFrame testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalFindFrame($/;" f +sqlite3WalFrames testdocs/sqlite3.c /^# define sqlite3WalFrames(/;" d file: +sqlite3WalFrames testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalFrames($/;" f +sqlite3WalFramesize testdocs/sqlite3.c /^# define sqlite3WalFramesize(/;" d file: +sqlite3WalFramesize testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){$/;" f +sqlite3WalHeapMemory testdocs/sqlite3.c /^# define sqlite3WalHeapMemory(/;" d file: +sqlite3WalHeapMemory testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){$/;" f +sqlite3WalLimit testdocs/sqlite3.c /^# define sqlite3WalLimit(/;" d file: +sqlite3WalLimit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){$/;" f +sqlite3WalOpen testdocs/sqlite3.c /^# define sqlite3WalOpen(/;" d file: +sqlite3WalOpen testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalOpen($/;" f +sqlite3WalReadFrame testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalReadFrame($/;" f +sqlite3WalSavepoint testdocs/sqlite3.c /^# define sqlite3WalSavepoint(/;" d file: +sqlite3WalSavepoint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){$/;" f +sqlite3WalSavepointUndo testdocs/sqlite3.c /^# define sqlite3WalSavepointUndo(/;" d file: +sqlite3WalSavepointUndo testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){$/;" f +sqlite3WalSnapshotGet testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){$/;" f +sqlite3WalSnapshotOpen testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){$/;" f +sqlite3WalSnapshotRecover testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){$/;" f +sqlite3WalTrace testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalTrace = 0;$/;" v +sqlite3WalUndo testdocs/sqlite3.c /^# define sqlite3WalUndo(/;" d file: +sqlite3WalUndo testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){$/;" f +sqlite3WalkExpr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){$/;" f +sqlite3WalkExprList testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalkExprList(Walker *pWalker, ExprList *p){$/;" f +sqlite3WalkSelect testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){$/;" f +sqlite3WalkSelectExpr testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){$/;" f +sqlite3WalkSelectFrom testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){$/;" f +sqlite3WhereAddScanStatus testdocs/sqlite3.c /^# define sqlite3WhereAddScanStatus(/;" d file: +sqlite3WhereAddScanStatus testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereAddScanStatus($/;" f +sqlite3WhereBegin testdocs/sqlite3.c /^SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin($/;" f +sqlite3WhereBreakLabel testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){$/;" f +sqlite3WhereClauseClear testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){$/;" f +sqlite3WhereClauseInit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereClauseInit($/;" f +sqlite3WhereClausePrint testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){$/;" f +sqlite3WhereCodeOneLoopStart testdocs/sqlite3.c /^SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart($/;" f +sqlite3WhereContinueLabel testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){$/;" f +sqlite3WhereEnd testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){$/;" f +sqlite3WhereExplainOneScan testdocs/sqlite3.c /^# define sqlite3WhereExplainOneScan(/;" d file: +sqlite3WhereExplainOneScan testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereExplainOneScan($/;" f +sqlite3WhereExprAnalyze testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereExprAnalyze($/;" f +sqlite3WhereExprListUsage testdocs/sqlite3.c /^SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){$/;" f +sqlite3WhereExprUsage testdocs/sqlite3.c /^SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){$/;" f +sqlite3WhereFindTerm testdocs/sqlite3.c /^SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm($/;" f +sqlite3WhereGetMask testdocs/sqlite3.c /^SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){$/;" f +sqlite3WhereIsDistinct testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){$/;" f +sqlite3WhereIsOrdered testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){$/;" f +sqlite3WhereIsSorted testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo *pWInfo){$/;" f +sqlite3WhereOkOnePass testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){$/;" f +sqlite3WhereOrderedInnerLoop testdocs/sqlite3.c /^SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){$/;" f +sqlite3WhereOutputRowCount testdocs/sqlite3.c /^SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){$/;" f +sqlite3WhereSplit testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){$/;" f +sqlite3WhereTabFuncArgs testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WhereTabFuncArgs($/;" f +sqlite3WhereTrace testdocs/sqlite3.c /^\/***\/ int sqlite3WhereTrace = 0;$/;" v +sqlite3WhereTrace testdocs/sqlite3.c /^\/***\/ int sqlite3WhereTrace;$/;" v +sqlite3Win32Wait testdocs/sqlite3.c /^SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){$/;" f +sqlite3WithAdd testdocs/sqlite3.c /^SQLITE_PRIVATE With *sqlite3WithAdd($/;" f +sqlite3WithDelete testdocs/sqlite3.c /^#define sqlite3WithDelete(/;" d file: +sqlite3WithDelete testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){$/;" f +sqlite3WithPush testdocs/sqlite3.c /^#define sqlite3WithPush(/;" d file: +sqlite3WithPush testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){$/;" f +sqlite3XPrintf testdocs/sqlite3.c /^SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){$/;" f +sqlite3_aggregate_context testdocs/sqlite3.c /^#define sqlite3_aggregate_context /;" d file: +sqlite3_aggregate_context testdocs/sqlite3.c /^SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){$/;" f +sqlite3_aggregate_count testdocs/sqlite3.c /^#define sqlite3_aggregate_count /;" d file: +sqlite3_aggregate_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){$/;" f +sqlite3_api_routines testdocs/sqlite3.c /^struct sqlite3_api_routines {$/;" s file: +sqlite3_api_routines testdocs/sqlite3.c /^typedef struct sqlite3_api_routines sqlite3_api_routines;$/;" t typeref:struct:sqlite3_api_routines file: +sqlite3_auto_extension testdocs/sqlite3.c /^#define sqlite3_auto_extension /;" d file: +sqlite3_auto_extension testdocs/sqlite3.c /^SQLITE_API int sqlite3_auto_extension($/;" f +sqlite3_backup testdocs/sqlite3.c /^struct sqlite3_backup {$/;" s file: +sqlite3_backup testdocs/sqlite3.c /^typedef struct sqlite3_backup sqlite3_backup;$/;" t typeref:struct:sqlite3_backup file: +sqlite3_backup_finish testdocs/sqlite3.c /^#define sqlite3_backup_finish /;" d file: +sqlite3_backup_finish testdocs/sqlite3.c /^SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){$/;" f +sqlite3_backup_init testdocs/sqlite3.c /^#define sqlite3_backup_init /;" d file: +sqlite3_backup_init testdocs/sqlite3.c /^SQLITE_API sqlite3_backup *sqlite3_backup_init($/;" f +sqlite3_backup_pagecount testdocs/sqlite3.c /^#define sqlite3_backup_pagecount /;" d file: +sqlite3_backup_pagecount testdocs/sqlite3.c /^SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){$/;" f +sqlite3_backup_remaining testdocs/sqlite3.c /^#define sqlite3_backup_remaining /;" d file: +sqlite3_backup_remaining testdocs/sqlite3.c /^SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){$/;" f +sqlite3_backup_step testdocs/sqlite3.c /^#define sqlite3_backup_step /;" d file: +sqlite3_backup_step testdocs/sqlite3.c /^SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){$/;" f +sqlite3_bind_blob testdocs/sqlite3.c /^#define sqlite3_bind_blob /;" d file: +sqlite3_bind_blob testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_blob($/;" f +sqlite3_bind_blob64 testdocs/sqlite3.c /^#define sqlite3_bind_blob64 /;" d file: +sqlite3_bind_blob64 testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_blob64($/;" f +sqlite3_bind_double testdocs/sqlite3.c /^#define sqlite3_bind_double /;" d file: +sqlite3_bind_double testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){$/;" f +sqlite3_bind_int testdocs/sqlite3.c /^#define sqlite3_bind_int /;" d file: +sqlite3_bind_int testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){$/;" f +sqlite3_bind_int64 testdocs/sqlite3.c /^#define sqlite3_bind_int64 /;" d file: +sqlite3_bind_int64 testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){$/;" f +sqlite3_bind_null testdocs/sqlite3.c /^#define sqlite3_bind_null /;" d file: +sqlite3_bind_null testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_bind_parameter_count testdocs/sqlite3.c /^#define sqlite3_bind_parameter_count /;" d file: +sqlite3_bind_parameter_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){$/;" f +sqlite3_bind_parameter_index testdocs/sqlite3.c /^#define sqlite3_bind_parameter_index /;" d file: +sqlite3_bind_parameter_index testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){$/;" f +sqlite3_bind_parameter_name testdocs/sqlite3.c /^#define sqlite3_bind_parameter_name /;" d file: +sqlite3_bind_parameter_name testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_bind_text testdocs/sqlite3.c /^#define sqlite3_bind_text /;" d file: +sqlite3_bind_text testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_text($/;" f +sqlite3_bind_text16 testdocs/sqlite3.c /^# define sqlite3_bind_text16 /;" d file: +sqlite3_bind_text16 testdocs/sqlite3.c /^#define sqlite3_bind_text16 /;" d file: +sqlite3_bind_text16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_text16($/;" f +sqlite3_bind_text64 testdocs/sqlite3.c /^#define sqlite3_bind_text64 /;" d file: +sqlite3_bind_text64 testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_text64($/;" f +sqlite3_bind_value testdocs/sqlite3.c /^#define sqlite3_bind_value /;" d file: +sqlite3_bind_value testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){$/;" f +sqlite3_bind_zeroblob testdocs/sqlite3.c /^#define sqlite3_bind_zeroblob /;" d file: +sqlite3_bind_zeroblob testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){$/;" f +sqlite3_bind_zeroblob64 testdocs/sqlite3.c /^#define sqlite3_bind_zeroblob64 /;" d file: +sqlite3_bind_zeroblob64 testdocs/sqlite3.c /^SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){$/;" f +sqlite3_blob testdocs/sqlite3.c /^typedef struct sqlite3_blob sqlite3_blob;$/;" t typeref:struct:sqlite3_blob file: +sqlite3_blob_bytes testdocs/sqlite3.c /^#define sqlite3_blob_bytes /;" d file: +sqlite3_blob_bytes testdocs/sqlite3.c /^SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){$/;" f +sqlite3_blob_close testdocs/sqlite3.c /^#define sqlite3_blob_close /;" d file: +sqlite3_blob_close testdocs/sqlite3.c /^SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){$/;" f +sqlite3_blob_open testdocs/sqlite3.c /^#define sqlite3_blob_open /;" d file: +sqlite3_blob_open testdocs/sqlite3.c /^SQLITE_API int sqlite3_blob_open($/;" f +sqlite3_blob_read testdocs/sqlite3.c /^#define sqlite3_blob_read /;" d file: +sqlite3_blob_read testdocs/sqlite3.c /^SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){$/;" f +sqlite3_blob_reopen testdocs/sqlite3.c /^#define sqlite3_blob_reopen /;" d file: +sqlite3_blob_reopen testdocs/sqlite3.c /^SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){$/;" f +sqlite3_blob_write testdocs/sqlite3.c /^#define sqlite3_blob_write /;" d file: +sqlite3_blob_write testdocs/sqlite3.c /^SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){$/;" f +sqlite3_busy_handler testdocs/sqlite3.c /^#define sqlite3_busy_handler /;" d file: +sqlite3_busy_handler testdocs/sqlite3.c /^SQLITE_API int sqlite3_busy_handler($/;" f +sqlite3_busy_timeout testdocs/sqlite3.c /^#define sqlite3_busy_timeout /;" d file: +sqlite3_busy_timeout testdocs/sqlite3.c /^SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){$/;" f +sqlite3_callback testdocs/sqlite3.c /^typedef int (*sqlite3_callback)(void*,int,char**, char**);$/;" t file: +sqlite3_cancel_auto_extension testdocs/sqlite3.c /^#define sqlite3_cancel_auto_extension /;" d file: +sqlite3_cancel_auto_extension testdocs/sqlite3.c /^SQLITE_API int sqlite3_cancel_auto_extension($/;" f +sqlite3_changegroup testdocs/sqlite3.c /^struct sqlite3_changegroup {$/;" s file: +sqlite3_changegroup testdocs/sqlite3.c /^typedef struct sqlite3_changegroup sqlite3_changegroup;$/;" t typeref:struct:sqlite3_changegroup file: +sqlite3_changes testdocs/sqlite3.c /^#define sqlite3_changes /;" d file: +sqlite3_changes testdocs/sqlite3.c /^SQLITE_API int sqlite3_changes(sqlite3 *db){$/;" f +sqlite3_changeset_iter testdocs/sqlite3.c /^struct sqlite3_changeset_iter {$/;" s file: +sqlite3_changeset_iter testdocs/sqlite3.c /^typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;$/;" t typeref:struct:sqlite3_changeset_iter file: +sqlite3_clear_bindings testdocs/sqlite3.c /^#define sqlite3_clear_bindings /;" d file: +sqlite3_clear_bindings testdocs/sqlite3.c /^SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){$/;" f +sqlite3_close testdocs/sqlite3.c /^#define sqlite3_close /;" d file: +sqlite3_close testdocs/sqlite3.c /^SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }$/;" f +sqlite3_close_v2 testdocs/sqlite3.c /^#define sqlite3_close_v2 /;" d file: +sqlite3_close_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }$/;" f +sqlite3_collation_needed testdocs/sqlite3.c /^#define sqlite3_collation_needed /;" d file: +sqlite3_collation_needed testdocs/sqlite3.c /^SQLITE_API int sqlite3_collation_needed($/;" f +sqlite3_collation_needed16 testdocs/sqlite3.c /^# define sqlite3_collation_needed16 /;" d file: +sqlite3_collation_needed16 testdocs/sqlite3.c /^#define sqlite3_collation_needed16 /;" d file: +sqlite3_collation_needed16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_collation_needed16($/;" f +sqlite3_column_blob testdocs/sqlite3.c /^#define sqlite3_column_blob /;" d file: +sqlite3_column_blob testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_bytes testdocs/sqlite3.c /^#define sqlite3_column_bytes /;" d file: +sqlite3_column_bytes testdocs/sqlite3.c /^SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_bytes16 testdocs/sqlite3.c /^#define sqlite3_column_bytes16 /;" d file: +sqlite3_column_bytes16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_count testdocs/sqlite3.c /^#define sqlite3_column_count /;" d file: +sqlite3_column_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){$/;" f +sqlite3_column_database_name testdocs/sqlite3.c /^# define sqlite3_column_database_name /;" d file: +sqlite3_column_database_name testdocs/sqlite3.c /^#define sqlite3_column_database_name /;" d file: +sqlite3_column_database_name testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_database_name16 testdocs/sqlite3.c /^# define sqlite3_column_database_name16 /;" d file: +sqlite3_column_database_name16 testdocs/sqlite3.c /^#define sqlite3_column_database_name16 /;" d file: +sqlite3_column_database_name16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_decltype testdocs/sqlite3.c /^# define sqlite3_column_decltype /;" d file: +sqlite3_column_decltype testdocs/sqlite3.c /^#define sqlite3_column_decltype /;" d file: +sqlite3_column_decltype testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_decltype16 testdocs/sqlite3.c /^# define sqlite3_column_decltype16 /;" d file: +sqlite3_column_decltype16 testdocs/sqlite3.c /^#define sqlite3_column_decltype16 /;" d file: +sqlite3_column_decltype16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_double testdocs/sqlite3.c /^#define sqlite3_column_double /;" d file: +sqlite3_column_double testdocs/sqlite3.c /^SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_int testdocs/sqlite3.c /^#define sqlite3_column_int /;" d file: +sqlite3_column_int testdocs/sqlite3.c /^SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_int64 testdocs/sqlite3.c /^#define sqlite3_column_int64 /;" d file: +sqlite3_column_int64 testdocs/sqlite3.c /^SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_name testdocs/sqlite3.c /^#define sqlite3_column_name /;" d file: +sqlite3_column_name testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_name16 testdocs/sqlite3.c /^# define sqlite3_column_name16 /;" d file: +sqlite3_column_name16 testdocs/sqlite3.c /^#define sqlite3_column_name16 /;" d file: +sqlite3_column_name16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_origin_name testdocs/sqlite3.c /^# define sqlite3_column_origin_name /;" d file: +sqlite3_column_origin_name testdocs/sqlite3.c /^#define sqlite3_column_origin_name /;" d file: +sqlite3_column_origin_name testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_origin_name16 testdocs/sqlite3.c /^# define sqlite3_column_origin_name16 /;" d file: +sqlite3_column_origin_name16 testdocs/sqlite3.c /^#define sqlite3_column_origin_name16 /;" d file: +sqlite3_column_origin_name16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_table_name testdocs/sqlite3.c /^# define sqlite3_column_table_name /;" d file: +sqlite3_column_table_name testdocs/sqlite3.c /^#define sqlite3_column_table_name /;" d file: +sqlite3_column_table_name testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_table_name16 testdocs/sqlite3.c /^# define sqlite3_column_table_name16 /;" d file: +sqlite3_column_table_name16 testdocs/sqlite3.c /^#define sqlite3_column_table_name16 /;" d file: +sqlite3_column_table_name16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){$/;" f +sqlite3_column_text testdocs/sqlite3.c /^#define sqlite3_column_text /;" d file: +sqlite3_column_text testdocs/sqlite3.c /^SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_text16 testdocs/sqlite3.c /^# define sqlite3_column_text16 /;" d file: +sqlite3_column_text16 testdocs/sqlite3.c /^#define sqlite3_column_text16 /;" d file: +sqlite3_column_text16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_type testdocs/sqlite3.c /^#define sqlite3_column_type /;" d file: +sqlite3_column_type testdocs/sqlite3.c /^SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_column_value testdocs/sqlite3.c /^#define sqlite3_column_value /;" d file: +sqlite3_column_value testdocs/sqlite3.c /^SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){$/;" f +sqlite3_commit_hook testdocs/sqlite3.c /^#define sqlite3_commit_hook /;" d file: +sqlite3_commit_hook testdocs/sqlite3.c /^SQLITE_API void *sqlite3_commit_hook($/;" f +sqlite3_compileoption_get testdocs/sqlite3.c /^#define sqlite3_compileoption_get /;" d file: +sqlite3_compileoption_get testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_compileoption_get(int N){$/;" f +sqlite3_compileoption_used testdocs/sqlite3.c /^#define sqlite3_compileoption_used /;" d file: +sqlite3_compileoption_used testdocs/sqlite3.c /^SQLITE_API int sqlite3_compileoption_used(const char *zOptName){$/;" f +sqlite3_complete testdocs/sqlite3.c /^# define sqlite3_complete /;" d file: +sqlite3_complete testdocs/sqlite3.c /^#define sqlite3_complete /;" d file: +sqlite3_complete testdocs/sqlite3.c /^SQLITE_API int sqlite3_complete(const char *zSql){$/;" f +sqlite3_complete16 testdocs/sqlite3.c /^# define sqlite3_complete16 /;" d file: +sqlite3_complete16 testdocs/sqlite3.c /^#define sqlite3_complete16 /;" d file: +sqlite3_complete16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_complete16(const void *zSql){$/;" f +sqlite3_config testdocs/sqlite3.c /^SQLITE_API int sqlite3_config(int op, ...){$/;" f +sqlite3_context testdocs/sqlite3.c /^struct sqlite3_context {$/;" s file: +sqlite3_context testdocs/sqlite3.c /^typedef struct sqlite3_context sqlite3_context;$/;" t typeref:struct:sqlite3_context file: +sqlite3_context_db_handle testdocs/sqlite3.c /^#define sqlite3_context_db_handle /;" d file: +sqlite3_context_db_handle testdocs/sqlite3.c /^SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){$/;" f +sqlite3_create_collation testdocs/sqlite3.c /^#define sqlite3_create_collation /;" d file: +sqlite3_create_collation testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_collation($/;" f +sqlite3_create_collation16 testdocs/sqlite3.c /^# define sqlite3_create_collation16 /;" d file: +sqlite3_create_collation16 testdocs/sqlite3.c /^#define sqlite3_create_collation16 /;" d file: +sqlite3_create_collation16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_collation16($/;" f +sqlite3_create_collation_v2 testdocs/sqlite3.c /^#define sqlite3_create_collation_v2 /;" d file: +sqlite3_create_collation_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_collation_v2($/;" f +sqlite3_create_function testdocs/sqlite3.c /^#define sqlite3_create_function /;" d file: +sqlite3_create_function testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_function($/;" f +sqlite3_create_function16 testdocs/sqlite3.c /^# define sqlite3_create_function16 /;" d file: +sqlite3_create_function16 testdocs/sqlite3.c /^#define sqlite3_create_function16 /;" d file: +sqlite3_create_function16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_function16($/;" f +sqlite3_create_function_v2 testdocs/sqlite3.c /^#define sqlite3_create_function_v2 /;" d file: +sqlite3_create_function_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_function_v2($/;" f +sqlite3_create_module testdocs/sqlite3.c /^# define sqlite3_create_module /;" d file: +sqlite3_create_module testdocs/sqlite3.c /^#define sqlite3_create_module /;" d file: +sqlite3_create_module testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_module($/;" f +sqlite3_create_module_v2 testdocs/sqlite3.c /^# define sqlite3_create_module_v2 /;" d file: +sqlite3_create_module_v2 testdocs/sqlite3.c /^#define sqlite3_create_module_v2 /;" d file: +sqlite3_create_module_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_create_module_v2($/;" f +sqlite3_current_time testdocs/sqlite3.c /^SQLITE_API int sqlite3_current_time = 0; \/* Fake system time in seconds since 1970. *\/$/;" v +sqlite3_data_count testdocs/sqlite3.c /^#define sqlite3_data_count /;" d file: +sqlite3_data_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){$/;" f +sqlite3_data_directory testdocs/sqlite3.c /^SQLITE_API char *sqlite3_data_directory = 0;$/;" v +sqlite3_data_directory testdocs/sqlite3.c /^SQLITE_API char *sqlite3_data_directory;$/;" v +sqlite3_db_cacheflush testdocs/sqlite3.c /^#define sqlite3_db_cacheflush /;" d file: +sqlite3_db_cacheflush testdocs/sqlite3.c /^SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){$/;" f +sqlite3_db_config testdocs/sqlite3.c /^#define sqlite3_db_config /;" d file: +sqlite3_db_config testdocs/sqlite3.c /^SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){$/;" f +sqlite3_db_filename testdocs/sqlite3.c /^#define sqlite3_db_filename /;" d file: +sqlite3_db_filename testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){$/;" f +sqlite3_db_handle testdocs/sqlite3.c /^#define sqlite3_db_handle /;" d file: +sqlite3_db_handle testdocs/sqlite3.c /^SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){$/;" f +sqlite3_db_mutex testdocs/sqlite3.c /^#define sqlite3_db_mutex /;" d file: +sqlite3_db_mutex testdocs/sqlite3.c /^SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){$/;" f +sqlite3_db_readonly testdocs/sqlite3.c /^#define sqlite3_db_readonly /;" d file: +sqlite3_db_readonly testdocs/sqlite3.c /^SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){$/;" f +sqlite3_db_release_memory testdocs/sqlite3.c /^#define sqlite3_db_release_memory /;" d file: +sqlite3_db_release_memory testdocs/sqlite3.c /^SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){$/;" f +sqlite3_db_status testdocs/sqlite3.c /^#define sqlite3_db_status /;" d file: +sqlite3_db_status testdocs/sqlite3.c /^SQLITE_API int sqlite3_db_status($/;" f +sqlite3_debug_mutex testdocs/sqlite3.c /^typedef struct sqlite3_debug_mutex {$/;" s file: +sqlite3_debug_mutex testdocs/sqlite3.c /^} sqlite3_debug_mutex;$/;" t typeref:struct:sqlite3_debug_mutex file: +sqlite3_declare_vtab testdocs/sqlite3.c /^# define sqlite3_declare_vtab /;" d file: +sqlite3_declare_vtab testdocs/sqlite3.c /^#define sqlite3_declare_vtab /;" d file: +sqlite3_declare_vtab testdocs/sqlite3.c /^SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){$/;" f +sqlite3_destructor_type testdocs/sqlite3.c /^typedef void (*sqlite3_destructor_type)(void*);$/;" t file: +sqlite3_diskfull testdocs/sqlite3.c /^SQLITE_API int sqlite3_diskfull = 0;$/;" v +sqlite3_diskfull_pending testdocs/sqlite3.c /^SQLITE_API int sqlite3_diskfull_pending = 0;$/;" v +sqlite3_enable_load_extension testdocs/sqlite3.c /^SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){$/;" f +sqlite3_enable_shared_cache testdocs/sqlite3.c /^# define sqlite3_enable_shared_cache /;" d file: +sqlite3_enable_shared_cache testdocs/sqlite3.c /^#define sqlite3_enable_shared_cache /;" d file: +sqlite3_enable_shared_cache testdocs/sqlite3.c /^SQLITE_API int sqlite3_enable_shared_cache(int enable){$/;" f +sqlite3_errcode testdocs/sqlite3.c /^#define sqlite3_errcode /;" d file: +sqlite3_errcode testdocs/sqlite3.c /^SQLITE_API int sqlite3_errcode(sqlite3 *db){$/;" f +sqlite3_errmsg testdocs/sqlite3.c /^#define sqlite3_errmsg /;" d file: +sqlite3_errmsg testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){$/;" f +sqlite3_errmsg16 testdocs/sqlite3.c /^# define sqlite3_errmsg16 /;" d file: +sqlite3_errmsg16 testdocs/sqlite3.c /^#define sqlite3_errmsg16 /;" d file: +sqlite3_errmsg16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){$/;" f +sqlite3_errstr testdocs/sqlite3.c /^#define sqlite3_errstr /;" d file: +sqlite3_errstr testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_errstr(int rc){$/;" f +sqlite3_exec testdocs/sqlite3.c /^#define sqlite3_exec /;" d file: +sqlite3_exec testdocs/sqlite3.c /^SQLITE_API int sqlite3_exec($/;" f +sqlite3_expanded_sql testdocs/sqlite3.c /^#define sqlite3_expanded_sql /;" d file: +sqlite3_expanded_sql testdocs/sqlite3.c /^SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){$/;" f +sqlite3_expired testdocs/sqlite3.c /^#define sqlite3_expired /;" d file: +sqlite3_expired testdocs/sqlite3.c /^SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){$/;" f +sqlite3_extended_errcode testdocs/sqlite3.c /^#define sqlite3_extended_errcode /;" d file: +sqlite3_extended_errcode testdocs/sqlite3.c /^SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){$/;" f +sqlite3_extended_result_codes testdocs/sqlite3.c /^#define sqlite3_extended_result_codes /;" d file: +sqlite3_extended_result_codes testdocs/sqlite3.c /^SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){$/;" f +sqlite3_file testdocs/sqlite3.c /^struct sqlite3_file {$/;" s file: +sqlite3_file testdocs/sqlite3.c /^typedef struct sqlite3_file sqlite3_file;$/;" t typeref:struct:sqlite3_file file: +sqlite3_file_control testdocs/sqlite3.c /^#define sqlite3_file_control /;" d file: +sqlite3_file_control testdocs/sqlite3.c /^SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){$/;" f +sqlite3_finalize testdocs/sqlite3.c /^#define sqlite3_finalize /;" d file: +sqlite3_finalize testdocs/sqlite3.c /^SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){$/;" f +sqlite3_found_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_found_count = 0;$/;" v +sqlite3_free testdocs/sqlite3.c /^#define sqlite3_free /;" d file: +sqlite3_free testdocs/sqlite3.c /^SQLITE_API void sqlite3_free(void *p){$/;" f +sqlite3_free_table testdocs/sqlite3.c /^# define sqlite3_free_table /;" d file: +sqlite3_free_table testdocs/sqlite3.c /^#define sqlite3_free_table /;" d file: +sqlite3_free_table testdocs/sqlite3.c /^SQLITE_API void sqlite3_free_table($/;" f +sqlite3_fts3_enable_parentheses testdocs/sqlite3.c /^# define sqlite3_fts3_enable_parentheses /;" d file: +sqlite3_fts3_enable_parentheses testdocs/sqlite3.c /^SQLITE_API int sqlite3_fts3_enable_parentheses = 0;$/;" v +sqlite3_fts5_may_be_corrupt testdocs/sqlite3.c /^SQLITE_API int sqlite3_fts5_may_be_corrupt = 1;$/;" v +sqlite3_fullsync_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_fullsync_count = 0;$/;" v +sqlite3_get_autocommit testdocs/sqlite3.c /^#define sqlite3_get_autocommit /;" d file: +sqlite3_get_autocommit testdocs/sqlite3.c /^SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){$/;" f +sqlite3_get_auxdata testdocs/sqlite3.c /^#define sqlite3_get_auxdata /;" d file: +sqlite3_get_auxdata testdocs/sqlite3.c /^SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){$/;" f +sqlite3_get_table testdocs/sqlite3.c /^# define sqlite3_get_table /;" d file: +sqlite3_get_table testdocs/sqlite3.c /^#define sqlite3_get_table /;" d file: +sqlite3_get_table testdocs/sqlite3.c /^SQLITE_API int sqlite3_get_table($/;" f +sqlite3_get_table_cb testdocs/sqlite3.c /^static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){$/;" f file: +sqlite3_global_recover testdocs/sqlite3.c /^#define sqlite3_global_recover /;" d file: +sqlite3_global_recover testdocs/sqlite3.c /^SQLITE_API int sqlite3_global_recover(void){$/;" f +sqlite3_hostid_num testdocs/sqlite3.c /^SQLITE_API int sqlite3_hostid_num = 0;$/;" v +sqlite3_index_constraint testdocs/sqlite3.c /^ struct sqlite3_index_constraint {$/;" s struct:sqlite3_index_info file: +sqlite3_index_constraint_usage testdocs/sqlite3.c /^ struct sqlite3_index_constraint_usage {$/;" s struct:sqlite3_index_info file: +sqlite3_index_info testdocs/sqlite3.c /^struct sqlite3_index_info {$/;" s file: +sqlite3_index_info testdocs/sqlite3.c /^typedef struct sqlite3_index_info sqlite3_index_info;$/;" t typeref:struct:sqlite3_index_info file: +sqlite3_index_orderby testdocs/sqlite3.c /^ struct sqlite3_index_orderby {$/;" s struct:sqlite3_index_info file: +sqlite3_initialize testdocs/sqlite3.c /^SQLITE_API int sqlite3_initialize(void){$/;" f +sqlite3_int64 testdocs/sqlite3.c /^typedef sqlite_int64 sqlite3_int64;$/;" t file: +sqlite3_interrupt testdocs/sqlite3.c /^#define sqlite3_interrupt /;" d file: +sqlite3_interrupt testdocs/sqlite3.c /^SQLITE_API void sqlite3_interrupt(sqlite3 *db){$/;" f +sqlite3_interrupt_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_interrupt_count = 0;$/;" v +sqlite3_io_error_benign testdocs/sqlite3.c /^SQLITE_API int sqlite3_io_error_benign = 0; \/* True if errors are benign *\/$/;" v +sqlite3_io_error_hardhit testdocs/sqlite3.c /^SQLITE_API int sqlite3_io_error_hardhit = 0; \/* Number of non-benign errors *\/$/;" v +sqlite3_io_error_hit testdocs/sqlite3.c /^SQLITE_API int sqlite3_io_error_hit = 0; \/* Total number of I\/O Errors *\/$/;" v +sqlite3_io_error_pending testdocs/sqlite3.c /^SQLITE_API int sqlite3_io_error_pending = 0; \/* Count down to first I\/O error *\/$/;" v +sqlite3_io_error_persist testdocs/sqlite3.c /^SQLITE_API int sqlite3_io_error_persist = 0; \/* True if I\/O errors persist *\/$/;" v +sqlite3_io_methods testdocs/sqlite3.c /^struct sqlite3_io_methods {$/;" s file: +sqlite3_io_methods testdocs/sqlite3.c /^typedef struct sqlite3_io_methods sqlite3_io_methods;$/;" t typeref:struct:sqlite3_io_methods file: +sqlite3_last_insert_rowid testdocs/sqlite3.c /^#define sqlite3_last_insert_rowid /;" d file: +sqlite3_last_insert_rowid testdocs/sqlite3.c /^SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){$/;" f +sqlite3_libversion testdocs/sqlite3.c /^#define sqlite3_libversion /;" d file: +sqlite3_libversion testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }$/;" f +sqlite3_libversion_number testdocs/sqlite3.c /^#define sqlite3_libversion_number /;" d file: +sqlite3_libversion_number testdocs/sqlite3.c /^SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }$/;" f +sqlite3_like_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_like_count = 0;$/;" v +sqlite3_limit testdocs/sqlite3.c /^#define sqlite3_limit /;" d file: +sqlite3_limit testdocs/sqlite3.c /^SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){$/;" f +sqlite3_load_extension testdocs/sqlite3.c /^#define sqlite3_load_extension /;" d file: +sqlite3_load_extension testdocs/sqlite3.c /^SQLITE_API int sqlite3_load_extension($/;" f +sqlite3_loadext_entry testdocs/sqlite3.c /^typedef int (*sqlite3_loadext_entry)($/;" t file: +sqlite3_log testdocs/sqlite3.c /^#define sqlite3_log /;" d file: +sqlite3_log testdocs/sqlite3.c /^SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){$/;" f +sqlite3_malloc testdocs/sqlite3.c /^#define sqlite3_malloc /;" d file: +sqlite3_malloc testdocs/sqlite3.c /^SQLITE_API void *sqlite3_malloc(int n){$/;" f +sqlite3_malloc64 testdocs/sqlite3.c /^#define sqlite3_malloc64 /;" d file: +sqlite3_malloc64 testdocs/sqlite3.c /^SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){$/;" f +sqlite3_max_blobsize testdocs/sqlite3.c /^SQLITE_API int sqlite3_max_blobsize = 0;$/;" v +sqlite3_mem_methods testdocs/sqlite3.c /^struct sqlite3_mem_methods {$/;" s file: +sqlite3_mem_methods testdocs/sqlite3.c /^typedef struct sqlite3_mem_methods sqlite3_mem_methods;$/;" t typeref:struct:sqlite3_mem_methods file: +sqlite3_memdebug_vfs_oom_test testdocs/sqlite3.c /^SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;$/;" v +sqlite3_memory_alarm testdocs/sqlite3.c /^SQLITE_API int sqlite3_memory_alarm($/;" f +sqlite3_memory_highwater testdocs/sqlite3.c /^#define sqlite3_memory_highwater /;" d file: +sqlite3_memory_highwater testdocs/sqlite3.c /^SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){$/;" f +sqlite3_memory_used testdocs/sqlite3.c /^#define sqlite3_memory_used /;" d file: +sqlite3_memory_used testdocs/sqlite3.c /^SQLITE_API sqlite3_int64 sqlite3_memory_used(void){$/;" f +sqlite3_module testdocs/sqlite3.c /^struct sqlite3_module {$/;" s file: +sqlite3_module testdocs/sqlite3.c /^typedef struct sqlite3_module sqlite3_module;$/;" t typeref:struct:sqlite3_module file: +sqlite3_mprintf testdocs/sqlite3.c /^#define sqlite3_mprintf /;" d file: +sqlite3_mprintf testdocs/sqlite3.c /^SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){$/;" f +sqlite3_msize testdocs/sqlite3.c /^#define sqlite3_msize /;" d file: +sqlite3_msize testdocs/sqlite3.c /^SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){$/;" f +sqlite3_mutex testdocs/sqlite3.c /^struct sqlite3_mutex {$/;" s file: +sqlite3_mutex testdocs/sqlite3.c /^typedef struct sqlite3_mutex sqlite3_mutex;$/;" t typeref:struct:sqlite3_mutex file: +sqlite3_mutex_alloc testdocs/sqlite3.c /^#define sqlite3_mutex_alloc /;" d file: +sqlite3_mutex_alloc testdocs/sqlite3.c /^#define sqlite3_mutex_alloc(/;" d file: +sqlite3_mutex_alloc testdocs/sqlite3.c /^SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){$/;" f +sqlite3_mutex_enter testdocs/sqlite3.c /^#define sqlite3_mutex_enter /;" d file: +sqlite3_mutex_enter testdocs/sqlite3.c /^#define sqlite3_mutex_enter(/;" d file: +sqlite3_mutex_enter testdocs/sqlite3.c /^SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){$/;" f +sqlite3_mutex_free testdocs/sqlite3.c /^#define sqlite3_mutex_free /;" d file: +sqlite3_mutex_free testdocs/sqlite3.c /^#define sqlite3_mutex_free(/;" d file: +sqlite3_mutex_free testdocs/sqlite3.c /^SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){$/;" f +sqlite3_mutex_held testdocs/sqlite3.c /^#define sqlite3_mutex_held(/;" d file: +sqlite3_mutex_held testdocs/sqlite3.c /^SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){$/;" f +sqlite3_mutex_leave testdocs/sqlite3.c /^#define sqlite3_mutex_leave /;" d file: +sqlite3_mutex_leave testdocs/sqlite3.c /^#define sqlite3_mutex_leave(/;" d file: +sqlite3_mutex_leave testdocs/sqlite3.c /^SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){$/;" f +sqlite3_mutex_methods testdocs/sqlite3.c /^struct sqlite3_mutex_methods {$/;" s file: +sqlite3_mutex_methods testdocs/sqlite3.c /^typedef struct sqlite3_mutex_methods sqlite3_mutex_methods;$/;" t typeref:struct:sqlite3_mutex_methods file: +sqlite3_mutex_notheld testdocs/sqlite3.c /^#define sqlite3_mutex_notheld(/;" d file: +sqlite3_mutex_notheld testdocs/sqlite3.c /^SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){$/;" f +sqlite3_mutex_try testdocs/sqlite3.c /^#define sqlite3_mutex_try /;" d file: +sqlite3_mutex_try testdocs/sqlite3.c /^#define sqlite3_mutex_try(/;" d file: +sqlite3_mutex_try testdocs/sqlite3.c /^SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){$/;" f +sqlite3_next_stmt testdocs/sqlite3.c /^#define sqlite3_next_stmt /;" d file: +sqlite3_next_stmt testdocs/sqlite3.c /^SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){$/;" f +sqlite3_open testdocs/sqlite3.c /^#define sqlite3_open /;" d file: +sqlite3_open testdocs/sqlite3.c /^SQLITE_API int sqlite3_open($/;" f +sqlite3_open16 testdocs/sqlite3.c /^# define sqlite3_open16 /;" d file: +sqlite3_open16 testdocs/sqlite3.c /^#define sqlite3_open16 /;" d file: +sqlite3_open16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_open16($/;" f +sqlite3_open_file_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_open_file_count = 0;$/;" v +sqlite3_open_v2 testdocs/sqlite3.c /^#define sqlite3_open_v2 /;" d file: +sqlite3_open_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_open_v2($/;" f +sqlite3_opentemp_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_opentemp_count = 0;$/;" v +sqlite3_os_end testdocs/sqlite3.c /^SQLITE_API int sqlite3_os_end(void){$/;" f +sqlite3_os_init testdocs/sqlite3.c /^SQLITE_API int sqlite3_os_init(void){$/;" f +sqlite3_os_type testdocs/sqlite3.c /^SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;$/;" v +sqlite3_os_type testdocs/sqlite3.c /^static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;$/;" v file: +sqlite3_overload_function testdocs/sqlite3.c /^#define sqlite3_overload_function /;" d file: +sqlite3_overload_function testdocs/sqlite3.c /^SQLITE_API int sqlite3_overload_function($/;" f +sqlite3_pager_readdb_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_pager_readdb_count = 0; \/* Number of full pages read from DB *\/$/;" v +sqlite3_pager_writedb_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_pager_writedb_count = 0; \/* Number of full pages written to DB *\/$/;" v +sqlite3_pager_writej_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_pager_writej_count = 0; \/* Number of pages written to journal *\/$/;" v +sqlite3_pcache testdocs/sqlite3.c /^typedef struct sqlite3_pcache sqlite3_pcache;$/;" t typeref:struct:sqlite3_pcache file: +sqlite3_pcache_methods testdocs/sqlite3.c /^struct sqlite3_pcache_methods {$/;" s file: +sqlite3_pcache_methods testdocs/sqlite3.c /^typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;$/;" t typeref:struct:sqlite3_pcache_methods file: +sqlite3_pcache_methods2 testdocs/sqlite3.c /^struct sqlite3_pcache_methods2 {$/;" s file: +sqlite3_pcache_methods2 testdocs/sqlite3.c /^typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2;$/;" t typeref:struct:sqlite3_pcache_methods2 file: +sqlite3_pcache_page testdocs/sqlite3.c /^struct sqlite3_pcache_page {$/;" s file: +sqlite3_pcache_page testdocs/sqlite3.c /^typedef struct sqlite3_pcache_page sqlite3_pcache_page;$/;" t typeref:struct:sqlite3_pcache_page file: +sqlite3_prepare testdocs/sqlite3.c /^#define sqlite3_prepare /;" d file: +sqlite3_prepare testdocs/sqlite3.c /^SQLITE_API int sqlite3_prepare($/;" f +sqlite3_prepare16 testdocs/sqlite3.c /^# define sqlite3_prepare16 /;" d file: +sqlite3_prepare16 testdocs/sqlite3.c /^#define sqlite3_prepare16 /;" d file: +sqlite3_prepare16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_prepare16($/;" f +sqlite3_prepare16_v2 testdocs/sqlite3.c /^# define sqlite3_prepare16_v2 /;" d file: +sqlite3_prepare16_v2 testdocs/sqlite3.c /^#define sqlite3_prepare16_v2 /;" d file: +sqlite3_prepare16_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_prepare16_v2($/;" f +sqlite3_prepare_v2 testdocs/sqlite3.c /^#define sqlite3_prepare_v2 /;" d file: +sqlite3_prepare_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_prepare_v2($/;" f +sqlite3_preupdate_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){$/;" f +sqlite3_preupdate_depth testdocs/sqlite3.c /^SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){$/;" f +sqlite3_preupdate_hook testdocs/sqlite3.c /^SQLITE_API void *sqlite3_preupdate_hook($/;" f +sqlite3_preupdate_new testdocs/sqlite3.c /^SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){$/;" f +sqlite3_preupdate_old testdocs/sqlite3.c /^SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){$/;" f +sqlite3_profile testdocs/sqlite3.c /^# define sqlite3_profile /;" d file: +sqlite3_profile testdocs/sqlite3.c /^#define sqlite3_profile /;" d file: +sqlite3_profile testdocs/sqlite3.c /^SQLITE_API void *sqlite3_profile($/;" f +sqlite3_progress_handler testdocs/sqlite3.c /^# define sqlite3_progress_handler /;" d file: +sqlite3_progress_handler testdocs/sqlite3.c /^#define sqlite3_progress_handler /;" d file: +sqlite3_progress_handler testdocs/sqlite3.c /^SQLITE_API void sqlite3_progress_handler($/;" f +sqlite3_randomness testdocs/sqlite3.c /^#define sqlite3_randomness /;" d file: +sqlite3_randomness testdocs/sqlite3.c /^SQLITE_API void sqlite3_randomness(int N, void *pBuf){$/;" f +sqlite3_realloc testdocs/sqlite3.c /^#define sqlite3_realloc /;" d file: +sqlite3_realloc testdocs/sqlite3.c /^SQLITE_API void *sqlite3_realloc(void *pOld, int n){$/;" f +sqlite3_realloc64 testdocs/sqlite3.c /^#define sqlite3_realloc64 /;" d file: +sqlite3_realloc64 testdocs/sqlite3.c /^SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){$/;" f +sqlite3_release_memory testdocs/sqlite3.c /^#define sqlite3_release_memory /;" d file: +sqlite3_release_memory testdocs/sqlite3.c /^SQLITE_API int sqlite3_release_memory(int n){$/;" f +sqlite3_reset testdocs/sqlite3.c /^#define sqlite3_reset /;" d file: +sqlite3_reset testdocs/sqlite3.c /^SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){$/;" f +sqlite3_reset_auto_extension testdocs/sqlite3.c /^#define sqlite3_reset_auto_extension /;" d file: +sqlite3_reset_auto_extension testdocs/sqlite3.c /^SQLITE_API void sqlite3_reset_auto_extension(void){$/;" f +sqlite3_result_blob testdocs/sqlite3.c /^#define sqlite3_result_blob /;" d file: +sqlite3_result_blob testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_blob($/;" f +sqlite3_result_blob64 testdocs/sqlite3.c /^#define sqlite3_result_blob64 /;" d file: +sqlite3_result_blob64 testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_blob64($/;" f +sqlite3_result_double testdocs/sqlite3.c /^#define sqlite3_result_double /;" d file: +sqlite3_result_double testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){$/;" f +sqlite3_result_error testdocs/sqlite3.c /^#define sqlite3_result_error /;" d file: +sqlite3_result_error testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){$/;" f +sqlite3_result_error16 testdocs/sqlite3.c /^# define sqlite3_result_error16 /;" d file: +sqlite3_result_error16 testdocs/sqlite3.c /^#define sqlite3_result_error16 /;" d file: +sqlite3_result_error16 testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){$/;" f +sqlite3_result_error_code testdocs/sqlite3.c /^#define sqlite3_result_error_code /;" d file: +sqlite3_result_error_code testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){$/;" f +sqlite3_result_error_nomem testdocs/sqlite3.c /^#define sqlite3_result_error_nomem /;" d file: +sqlite3_result_error_nomem testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){$/;" f +sqlite3_result_error_toobig testdocs/sqlite3.c /^#define sqlite3_result_error_toobig /;" d file: +sqlite3_result_error_toobig testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){$/;" f +sqlite3_result_int testdocs/sqlite3.c /^#define sqlite3_result_int /;" d file: +sqlite3_result_int testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){$/;" f +sqlite3_result_int64 testdocs/sqlite3.c /^#define sqlite3_result_int64 /;" d file: +sqlite3_result_int64 testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){$/;" f +sqlite3_result_null testdocs/sqlite3.c /^#define sqlite3_result_null /;" d file: +sqlite3_result_null testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){$/;" f +sqlite3_result_subtype testdocs/sqlite3.c /^#define sqlite3_result_subtype /;" d file: +sqlite3_result_subtype testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){$/;" f +sqlite3_result_text testdocs/sqlite3.c /^#define sqlite3_result_text /;" d file: +sqlite3_result_text testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_text($/;" f +sqlite3_result_text16 testdocs/sqlite3.c /^# define sqlite3_result_text16 /;" d file: +sqlite3_result_text16 testdocs/sqlite3.c /^#define sqlite3_result_text16 /;" d file: +sqlite3_result_text16 testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_text16($/;" f +sqlite3_result_text16be testdocs/sqlite3.c /^# define sqlite3_result_text16be /;" d file: +sqlite3_result_text16be testdocs/sqlite3.c /^#define sqlite3_result_text16be /;" d file: +sqlite3_result_text16be testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_text16be($/;" f +sqlite3_result_text16le testdocs/sqlite3.c /^# define sqlite3_result_text16le /;" d file: +sqlite3_result_text16le testdocs/sqlite3.c /^#define sqlite3_result_text16le /;" d file: +sqlite3_result_text16le testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_text16le($/;" f +sqlite3_result_text64 testdocs/sqlite3.c /^#define sqlite3_result_text64 /;" d file: +sqlite3_result_text64 testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_text64($/;" f +sqlite3_result_value testdocs/sqlite3.c /^#define sqlite3_result_value /;" d file: +sqlite3_result_value testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){$/;" f +sqlite3_result_zeroblob testdocs/sqlite3.c /^#define sqlite3_result_zeroblob /;" d file: +sqlite3_result_zeroblob testdocs/sqlite3.c /^SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){$/;" f +sqlite3_result_zeroblob64 testdocs/sqlite3.c /^#define sqlite3_result_zeroblob64 /;" d file: +sqlite3_result_zeroblob64 testdocs/sqlite3.c /^SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){$/;" f +sqlite3_rollback_hook testdocs/sqlite3.c /^#define sqlite3_rollback_hook /;" d file: +sqlite3_rollback_hook testdocs/sqlite3.c /^SQLITE_API void *sqlite3_rollback_hook($/;" f +sqlite3_rtree_dbl testdocs/sqlite3.c /^ typedef double sqlite3_rtree_dbl;$/;" t file: +sqlite3_rtree_dbl testdocs/sqlite3.c /^ typedef sqlite3_int64 sqlite3_rtree_dbl;$/;" t file: +sqlite3_rtree_geometry testdocs/sqlite3.c /^struct sqlite3_rtree_geometry {$/;" s file: +sqlite3_rtree_geometry testdocs/sqlite3.c /^typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;$/;" t typeref:struct:sqlite3_rtree_geometry file: +sqlite3_rtree_geometry_callback testdocs/sqlite3.c /^SQLITE_API int sqlite3_rtree_geometry_callback($/;" f +sqlite3_rtree_query_callback testdocs/sqlite3.c /^SQLITE_API int sqlite3_rtree_query_callback($/;" f +sqlite3_rtree_query_info testdocs/sqlite3.c /^struct sqlite3_rtree_query_info {$/;" s file: +sqlite3_rtree_query_info testdocs/sqlite3.c /^typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;$/;" t typeref:struct:sqlite3_rtree_query_info file: +sqlite3_search_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_search_count = 0;$/;" v +sqlite3_session testdocs/sqlite3.c /^struct sqlite3_session {$/;" s file: +sqlite3_session testdocs/sqlite3.c /^typedef struct sqlite3_session sqlite3_session;$/;" t typeref:struct:sqlite3_session file: +sqlite3_set_authorizer testdocs/sqlite3.c /^# define sqlite3_set_authorizer /;" d file: +sqlite3_set_authorizer testdocs/sqlite3.c /^#define sqlite3_set_authorizer /;" d file: +sqlite3_set_authorizer testdocs/sqlite3.c /^SQLITE_API int sqlite3_set_authorizer($/;" f +sqlite3_set_auxdata testdocs/sqlite3.c /^#define sqlite3_set_auxdata /;" d file: +sqlite3_set_auxdata testdocs/sqlite3.c /^SQLITE_API void sqlite3_set_auxdata($/;" f +sqlite3_set_last_insert_rowid testdocs/sqlite3.c /^#define sqlite3_set_last_insert_rowid /;" d file: +sqlite3_set_last_insert_rowid testdocs/sqlite3.c /^SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){$/;" f +sqlite3_shutdown testdocs/sqlite3.c /^SQLITE_API int sqlite3_shutdown(void){$/;" f +sqlite3_sleep testdocs/sqlite3.c /^#define sqlite3_sleep /;" d file: +sqlite3_sleep testdocs/sqlite3.c /^SQLITE_API int sqlite3_sleep(int ms){$/;" f +sqlite3_snapshot testdocs/sqlite3.c /^typedef struct sqlite3_snapshot {$/;" s file: +sqlite3_snapshot testdocs/sqlite3.c /^} sqlite3_snapshot;$/;" t typeref:struct:sqlite3_snapshot file: +sqlite3_snapshot_cmp testdocs/sqlite3.c /^SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){$/;" f +sqlite3_snapshot_free testdocs/sqlite3.c /^SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){$/;" f +sqlite3_snapshot_get testdocs/sqlite3.c /^SQLITE_API int sqlite3_snapshot_get($/;" f +sqlite3_snapshot_open testdocs/sqlite3.c /^SQLITE_API int sqlite3_snapshot_open($/;" f +sqlite3_snapshot_recover testdocs/sqlite3.c /^SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){$/;" f +sqlite3_snprintf testdocs/sqlite3.c /^#define sqlite3_snprintf /;" d file: +sqlite3_snprintf testdocs/sqlite3.c /^SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){$/;" f +sqlite3_soft_heap_limit testdocs/sqlite3.c /^#define sqlite3_soft_heap_limit /;" d file: +sqlite3_soft_heap_limit testdocs/sqlite3.c /^SQLITE_API void sqlite3_soft_heap_limit(int n){$/;" f +sqlite3_soft_heap_limit64 testdocs/sqlite3.c /^#define sqlite3_soft_heap_limit64 /;" d file: +sqlite3_soft_heap_limit64 testdocs/sqlite3.c /^SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){$/;" f +sqlite3_sort_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_sort_count = 0;$/;" v +sqlite3_sourceid testdocs/sqlite3.c /^#define sqlite3_sourceid /;" d file: +sqlite3_sourceid testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }$/;" f +sqlite3_sql testdocs/sqlite3.c /^#define sqlite3_sql /;" d file: +sqlite3_sql testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){$/;" f +sqlite3_status testdocs/sqlite3.c /^#define sqlite3_status /;" d file: +sqlite3_status testdocs/sqlite3.c /^SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){$/;" f +sqlite3_status64 testdocs/sqlite3.c /^#define sqlite3_status64 /;" d file: +sqlite3_status64 testdocs/sqlite3.c /^SQLITE_API int sqlite3_status64($/;" f +sqlite3_step testdocs/sqlite3.c /^#define sqlite3_step /;" d file: +sqlite3_step testdocs/sqlite3.c /^SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){$/;" f +sqlite3_stmt testdocs/sqlite3.c /^typedef struct sqlite3_stmt sqlite3_stmt;$/;" t typeref:struct:sqlite3_stmt file: +sqlite3_stmt_busy testdocs/sqlite3.c /^#define sqlite3_stmt_busy /;" d file: +sqlite3_stmt_busy testdocs/sqlite3.c /^SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){$/;" f +sqlite3_stmt_readonly testdocs/sqlite3.c /^#define sqlite3_stmt_readonly /;" d file: +sqlite3_stmt_readonly testdocs/sqlite3.c /^SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){$/;" f +sqlite3_stmt_scanstatus testdocs/sqlite3.c /^SQLITE_API int sqlite3_stmt_scanstatus($/;" f +sqlite3_stmt_scanstatus_reset testdocs/sqlite3.c /^SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){$/;" f +sqlite3_stmt_status testdocs/sqlite3.c /^#define sqlite3_stmt_status /;" d file: +sqlite3_stmt_status testdocs/sqlite3.c /^SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){$/;" f +sqlite3_strglob testdocs/sqlite3.c /^#define sqlite3_strglob /;" d file: +sqlite3_strglob testdocs/sqlite3.c /^SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){$/;" f +sqlite3_stricmp testdocs/sqlite3.c /^#define sqlite3_stricmp /;" d file: +sqlite3_stricmp testdocs/sqlite3.c /^SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){$/;" f +sqlite3_strlike testdocs/sqlite3.c /^#define sqlite3_strlike /;" d file: +sqlite3_strlike testdocs/sqlite3.c /^SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){$/;" f +sqlite3_strnicmp testdocs/sqlite3.c /^#define sqlite3_strnicmp /;" d file: +sqlite3_strnicmp testdocs/sqlite3.c /^SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){$/;" f +sqlite3_sync_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_sync_count = 0;$/;" v +sqlite3_syscall_ptr testdocs/sqlite3.c /^typedef void (*sqlite3_syscall_ptr)(void);$/;" t file: +sqlite3_system_errno testdocs/sqlite3.c /^#define sqlite3_system_errno /;" d file: +sqlite3_system_errno testdocs/sqlite3.c /^SQLITE_API int sqlite3_system_errno(sqlite3 *db){$/;" f +sqlite3_table_column_metadata testdocs/sqlite3.c /^#define sqlite3_table_column_metadata /;" d file: +sqlite3_table_column_metadata testdocs/sqlite3.c /^SQLITE_API int sqlite3_table_column_metadata($/;" f +sqlite3_temp_directory testdocs/sqlite3.c /^SQLITE_API char *sqlite3_temp_directory = 0;$/;" v +sqlite3_temp_directory testdocs/sqlite3.c /^SQLITE_API char *sqlite3_temp_directory;$/;" v +sqlite3_test_control testdocs/sqlite3.c /^#define sqlite3_test_control /;" d file: +sqlite3_test_control testdocs/sqlite3.c /^SQLITE_API int sqlite3_test_control(int op, ...){$/;" f +sqlite3_thread_cleanup testdocs/sqlite3.c /^#define sqlite3_thread_cleanup /;" d file: +sqlite3_thread_cleanup testdocs/sqlite3.c /^SQLITE_API void sqlite3_thread_cleanup(void){$/;" f +sqlite3_threadsafe testdocs/sqlite3.c /^#define sqlite3_threadsafe /;" d file: +sqlite3_threadsafe testdocs/sqlite3.c /^SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }$/;" f +sqlite3_tokenizer testdocs/sqlite3.c /^struct sqlite3_tokenizer {$/;" s file: +sqlite3_tokenizer testdocs/sqlite3.c /^typedef struct sqlite3_tokenizer sqlite3_tokenizer;$/;" t typeref:struct:sqlite3_tokenizer file: +sqlite3_tokenizer_cursor testdocs/sqlite3.c /^struct sqlite3_tokenizer_cursor {$/;" s file: +sqlite3_tokenizer_cursor testdocs/sqlite3.c /^typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;$/;" t typeref:struct:sqlite3_tokenizer_cursor file: +sqlite3_tokenizer_module testdocs/sqlite3.c /^struct sqlite3_tokenizer_module {$/;" s file: +sqlite3_tokenizer_module testdocs/sqlite3.c /^typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;$/;" t typeref:struct:sqlite3_tokenizer_module file: +sqlite3_total_changes testdocs/sqlite3.c /^#define sqlite3_total_changes /;" d file: +sqlite3_total_changes testdocs/sqlite3.c /^SQLITE_API int sqlite3_total_changes(sqlite3 *db){$/;" f +sqlite3_trace testdocs/sqlite3.c /^# define sqlite3_trace /;" d file: +sqlite3_trace testdocs/sqlite3.c /^#define sqlite3_trace /;" d file: +sqlite3_trace testdocs/sqlite3.c /^SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){$/;" f +sqlite3_trace_v2 testdocs/sqlite3.c /^# define sqlite3_trace_v2 /;" d file: +sqlite3_trace_v2 testdocs/sqlite3.c /^#define sqlite3_trace_v2 /;" d file: +sqlite3_trace_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_trace_v2($/;" f +sqlite3_transfer_bindings testdocs/sqlite3.c /^#define sqlite3_transfer_bindings /;" d file: +sqlite3_transfer_bindings testdocs/sqlite3.c /^SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){$/;" f +sqlite3_uint64 testdocs/sqlite3.c /^typedef sqlite_uint64 sqlite3_uint64;$/;" t file: +sqlite3_unlock_notify testdocs/sqlite3.c /^#define sqlite3_unlock_notify /;" d file: +sqlite3_unlock_notify testdocs/sqlite3.c /^SQLITE_API int sqlite3_unlock_notify($/;" f +sqlite3_update_hook testdocs/sqlite3.c /^#define sqlite3_update_hook /;" d file: +sqlite3_update_hook testdocs/sqlite3.c /^SQLITE_API void *sqlite3_update_hook($/;" f +sqlite3_uri_boolean testdocs/sqlite3.c /^#define sqlite3_uri_boolean /;" d file: +sqlite3_uri_boolean testdocs/sqlite3.c /^SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){$/;" f +sqlite3_uri_int64 testdocs/sqlite3.c /^#define sqlite3_uri_int64 /;" d file: +sqlite3_uri_int64 testdocs/sqlite3.c /^SQLITE_API sqlite3_int64 sqlite3_uri_int64($/;" f +sqlite3_uri_parameter testdocs/sqlite3.c /^#define sqlite3_uri_parameter /;" d file: +sqlite3_uri_parameter testdocs/sqlite3.c /^SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){$/;" f +sqlite3_uri_vsnprintf testdocs/sqlite3.c /^#define sqlite3_uri_vsnprintf /;" d file: +sqlite3_user_data testdocs/sqlite3.c /^#define sqlite3_user_data /;" d file: +sqlite3_user_data testdocs/sqlite3.c /^SQLITE_API void *sqlite3_user_data(sqlite3_context *p){$/;" f +sqlite3_userauth testdocs/sqlite3.c /^struct sqlite3_userauth {$/;" s file: +sqlite3_userauth testdocs/sqlite3.c /^typedef struct sqlite3_userauth sqlite3_userauth;$/;" t typeref:struct:sqlite3_userauth file: +sqlite3_value testdocs/sqlite3.c /^struct sqlite3_value {$/;" s file: +sqlite3_value testdocs/sqlite3.c /^typedef struct sqlite3_value sqlite3_value;$/;" t typeref:struct:sqlite3_value file: +sqlite3_value_blob testdocs/sqlite3.c /^#define sqlite3_value_blob /;" d file: +sqlite3_value_blob testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){$/;" f +sqlite3_value_bytes testdocs/sqlite3.c /^#define sqlite3_value_bytes /;" d file: +sqlite3_value_bytes testdocs/sqlite3.c /^SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){$/;" f +sqlite3_value_bytes16 testdocs/sqlite3.c /^#define sqlite3_value_bytes16 /;" d file: +sqlite3_value_bytes16 testdocs/sqlite3.c /^SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){$/;" f +sqlite3_value_double testdocs/sqlite3.c /^#define sqlite3_value_double /;" d file: +sqlite3_value_double testdocs/sqlite3.c /^SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){$/;" f +sqlite3_value_dup testdocs/sqlite3.c /^#define sqlite3_value_dup /;" d file: +sqlite3_value_dup testdocs/sqlite3.c /^SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){$/;" f +sqlite3_value_free testdocs/sqlite3.c /^#define sqlite3_value_free /;" d file: +sqlite3_value_free testdocs/sqlite3.c /^SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){$/;" f +sqlite3_value_int testdocs/sqlite3.c /^#define sqlite3_value_int /;" d file: +sqlite3_value_int testdocs/sqlite3.c /^SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){$/;" f +sqlite3_value_int64 testdocs/sqlite3.c /^#define sqlite3_value_int64 /;" d file: +sqlite3_value_int64 testdocs/sqlite3.c /^SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){$/;" f +sqlite3_value_numeric_type testdocs/sqlite3.c /^#define sqlite3_value_numeric_type /;" d file: +sqlite3_value_numeric_type testdocs/sqlite3.c /^SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){$/;" f +sqlite3_value_subtype testdocs/sqlite3.c /^#define sqlite3_value_subtype /;" d file: +sqlite3_value_subtype testdocs/sqlite3.c /^SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){$/;" f +sqlite3_value_text testdocs/sqlite3.c /^#define sqlite3_value_text /;" d file: +sqlite3_value_text testdocs/sqlite3.c /^SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){$/;" f +sqlite3_value_text16 testdocs/sqlite3.c /^# define sqlite3_value_text16 /;" d file: +sqlite3_value_text16 testdocs/sqlite3.c /^#define sqlite3_value_text16 /;" d file: +sqlite3_value_text16 testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){$/;" f +sqlite3_value_text16be testdocs/sqlite3.c /^# define sqlite3_value_text16be /;" d file: +sqlite3_value_text16be testdocs/sqlite3.c /^#define sqlite3_value_text16be /;" d file: +sqlite3_value_text16be testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){$/;" f +sqlite3_value_text16le testdocs/sqlite3.c /^# define sqlite3_value_text16le /;" d file: +sqlite3_value_text16le testdocs/sqlite3.c /^#define sqlite3_value_text16le /;" d file: +sqlite3_value_text16le testdocs/sqlite3.c /^SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){$/;" f +sqlite3_value_type testdocs/sqlite3.c /^#define sqlite3_value_type /;" d file: +sqlite3_value_type testdocs/sqlite3.c /^SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){$/;" f +sqlite3_version testdocs/sqlite3.c /^SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;$/;" v +sqlite3_vfs testdocs/sqlite3.c /^struct sqlite3_vfs {$/;" s file: +sqlite3_vfs testdocs/sqlite3.c /^typedef struct sqlite3_vfs sqlite3_vfs;$/;" t typeref:struct:sqlite3_vfs file: +sqlite3_vfs_find testdocs/sqlite3.c /^#define sqlite3_vfs_find /;" d file: +sqlite3_vfs_find testdocs/sqlite3.c /^SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){$/;" f +sqlite3_vfs_register testdocs/sqlite3.c /^#define sqlite3_vfs_register /;" d file: +sqlite3_vfs_register testdocs/sqlite3.c /^SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){$/;" f +sqlite3_vfs_unregister testdocs/sqlite3.c /^#define sqlite3_vfs_unregister /;" d file: +sqlite3_vfs_unregister testdocs/sqlite3.c /^SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){$/;" f +sqlite3_vmprintf testdocs/sqlite3.c /^#define sqlite3_vmprintf /;" d file: +sqlite3_vmprintf testdocs/sqlite3.c /^SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){$/;" f +sqlite3_vsnprintf testdocs/sqlite3.c /^#define sqlite3_vsnprintf /;" d file: +sqlite3_vsnprintf testdocs/sqlite3.c /^SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){$/;" f +sqlite3_vtab testdocs/sqlite3.c /^struct sqlite3_vtab {$/;" s file: +sqlite3_vtab testdocs/sqlite3.c /^typedef struct sqlite3_vtab sqlite3_vtab;$/;" t typeref:struct:sqlite3_vtab file: +sqlite3_vtab_config testdocs/sqlite3.c /^# define sqlite3_vtab_config /;" d file: +sqlite3_vtab_config testdocs/sqlite3.c /^#define sqlite3_vtab_config /;" d file: +sqlite3_vtab_config testdocs/sqlite3.c /^SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){$/;" f +sqlite3_vtab_cursor testdocs/sqlite3.c /^struct sqlite3_vtab_cursor {$/;" s file: +sqlite3_vtab_cursor testdocs/sqlite3.c /^typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;$/;" t typeref:struct:sqlite3_vtab_cursor file: +sqlite3_vtab_on_conflict testdocs/sqlite3.c /^# define sqlite3_vtab_on_conflict /;" d file: +sqlite3_vtab_on_conflict testdocs/sqlite3.c /^#define sqlite3_vtab_on_conflict /;" d file: +sqlite3_vtab_on_conflict testdocs/sqlite3.c /^SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){$/;" f +sqlite3_wal_autocheckpoint testdocs/sqlite3.c /^#define sqlite3_wal_autocheckpoint /;" d file: +sqlite3_wal_autocheckpoint testdocs/sqlite3.c /^SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){$/;" f +sqlite3_wal_checkpoint testdocs/sqlite3.c /^#define sqlite3_wal_checkpoint /;" d file: +sqlite3_wal_checkpoint testdocs/sqlite3.c /^SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){$/;" f +sqlite3_wal_checkpoint_v2 testdocs/sqlite3.c /^#define sqlite3_wal_checkpoint_v2 /;" d file: +sqlite3_wal_checkpoint_v2 testdocs/sqlite3.c /^SQLITE_API int sqlite3_wal_checkpoint_v2($/;" f +sqlite3_wal_hook testdocs/sqlite3.c /^#define sqlite3_wal_hook /;" d file: +sqlite3_wal_hook testdocs/sqlite3.c /^SQLITE_API void *sqlite3_wal_hook($/;" f +sqlite3_win32_compact_heap testdocs/sqlite3.c /^SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){$/;" f +sqlite3_win32_is_nt testdocs/sqlite3.c /^SQLITE_API int sqlite3_win32_is_nt(void){$/;" f +sqlite3_win32_mbcs_to_utf8 testdocs/sqlite3.c /^SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){$/;" f +sqlite3_win32_mbcs_to_utf8_v2 testdocs/sqlite3.c /^SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){$/;" f +sqlite3_win32_reset_heap testdocs/sqlite3.c /^SQLITE_API int sqlite3_win32_reset_heap(){$/;" f +sqlite3_win32_set_directory testdocs/sqlite3.c /^SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){$/;" f +sqlite3_win32_sleep testdocs/sqlite3.c /^SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){$/;" f +sqlite3_win32_unicode_to_utf8 testdocs/sqlite3.c /^SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){$/;" f +sqlite3_win32_utf8_to_mbcs testdocs/sqlite3.c /^SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){$/;" f +sqlite3_win32_utf8_to_mbcs_v2 testdocs/sqlite3.c /^SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){$/;" f +sqlite3_win32_utf8_to_unicode testdocs/sqlite3.c /^SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){$/;" f +sqlite3_win32_write_debug testdocs/sqlite3.c /^SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){$/;" f +sqlite3_xauth testdocs/sqlite3.c /^ typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,$/;" t file: +sqlite3_xferopt_count testdocs/sqlite3.c /^SQLITE_API int sqlite3_xferopt_count;$/;" v +sqlite3changegroup_add testdocs/sqlite3.c /^SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){$/;" f +sqlite3changegroup_add_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3changegroup_add_strm($/;" f +sqlite3changegroup_delete testdocs/sqlite3.c /^SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){$/;" f +sqlite3changegroup_new testdocs/sqlite3.c /^SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){$/;" f +sqlite3changegroup_output testdocs/sqlite3.c /^SQLITE_API int sqlite3changegroup_output($/;" f +sqlite3changegroup_output_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3changegroup_output_strm($/;" f +sqlite3changeset_apply testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_apply($/;" f +sqlite3changeset_apply_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_apply_strm($/;" f +sqlite3changeset_concat testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_concat($/;" f +sqlite3changeset_concat_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_concat_strm($/;" f +sqlite3changeset_conflict testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_conflict($/;" f +sqlite3changeset_finalize testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *p){$/;" f +sqlite3changeset_fk_conflicts testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_fk_conflicts($/;" f +sqlite3changeset_invert testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_invert($/;" f +sqlite3changeset_invert_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_invert_strm($/;" f +sqlite3changeset_new testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_new($/;" f +sqlite3changeset_next testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){$/;" f +sqlite3changeset_old testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_old($/;" f +sqlite3changeset_op testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_op($/;" f +sqlite3changeset_pk testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_pk($/;" f +sqlite3changeset_start testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_start($/;" f +sqlite3changeset_start_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3changeset_start_strm($/;" f +sqlite3one testdocs/sqlite3.c /^ const int sqlite3one = 1;$/;" v +sqlite3one testdocs/sqlite3.c /^SQLITE_PRIVATE const int sqlite3one = 1;$/;" v +sqlite3rbu testdocs/sqlite3.c /^struct sqlite3rbu {$/;" s file: +sqlite3rbu testdocs/sqlite3.c /^typedef struct sqlite3rbu sqlite3rbu;$/;" t typeref:struct:sqlite3rbu file: +sqlite3rbu_bp_progress testdocs/sqlite3.c /^SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){$/;" f +sqlite3rbu_close testdocs/sqlite3.c /^SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){$/;" f +sqlite3rbu_create_vfs testdocs/sqlite3.c /^SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){$/;" f +sqlite3rbu_db testdocs/sqlite3.c /^SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){$/;" f +sqlite3rbu_destroy_vfs testdocs/sqlite3.c /^SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName){$/;" f +sqlite3rbu_open testdocs/sqlite3.c /^SQLITE_API sqlite3rbu *sqlite3rbu_open($/;" f +sqlite3rbu_progress testdocs/sqlite3.c /^SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){$/;" f +sqlite3rbu_savestate testdocs/sqlite3.c /^SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){$/;" f +sqlite3rbu_state testdocs/sqlite3.c /^SQLITE_API int sqlite3rbu_state(sqlite3rbu *p){$/;" f +sqlite3rbu_step testdocs/sqlite3.c /^SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){$/;" f +sqlite3rbu_vacuum testdocs/sqlite3.c /^SQLITE_API sqlite3rbu *sqlite3rbu_vacuum($/;" f +sqlite3session_attach testdocs/sqlite3.c /^SQLITE_API int sqlite3session_attach($/;" f +sqlite3session_changeset testdocs/sqlite3.c /^SQLITE_API int sqlite3session_changeset($/;" f +sqlite3session_changeset_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3session_changeset_strm($/;" f +sqlite3session_create testdocs/sqlite3.c /^SQLITE_API int sqlite3session_create($/;" f +sqlite3session_delete testdocs/sqlite3.c /^SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){$/;" f +sqlite3session_diff testdocs/sqlite3.c /^SQLITE_API int sqlite3session_diff($/;" f +sqlite3session_enable testdocs/sqlite3.c /^SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){$/;" f +sqlite3session_indirect testdocs/sqlite3.c /^SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){$/;" f +sqlite3session_isempty testdocs/sqlite3.c /^SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){$/;" f +sqlite3session_patchset testdocs/sqlite3.c /^SQLITE_API int sqlite3session_patchset($/;" f +sqlite3session_patchset_strm testdocs/sqlite3.c /^SQLITE_API int sqlite3session_patchset_strm($/;" f +sqlite3session_table_filter testdocs/sqlite3.c /^SQLITE_API void sqlite3session_table_filter($/;" f +sqliteAuthBadReturnCode testdocs/sqlite3.c /^static void sqliteAuthBadReturnCode(Parse *pParse){$/;" f file: +sqliteDefaultBusyCallback testdocs/sqlite3.c /^static int sqliteDefaultBusyCallback($/;" f file: +sqliteErrorFromPosixError testdocs/sqlite3.c /^static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {$/;" f file: +sqliteHashData testdocs/sqlite3.c /^#define sqliteHashData(/;" d file: +sqliteHashFirst testdocs/sqlite3.c /^#define sqliteHashFirst(/;" d file: +sqliteHashNext testdocs/sqlite3.c /^#define sqliteHashNext(/;" d file: +sqliteProcessJoin testdocs/sqlite3.c /^static int sqliteProcessJoin(Parse *pParse, Select *p){$/;" f file: +sqliteViewResetAll testdocs/sqlite3.c /^# define sqliteViewResetAll(/;" d file: +sqliteViewResetAll testdocs/sqlite3.c /^static void sqliteViewResetAll(sqlite3 *db, int idx){$/;" f file: +sqlite_int64 testdocs/sqlite3.c /^ typedef SQLITE_INT64_TYPE sqlite_int64;$/;" t file: +sqlite_int64 testdocs/sqlite3.c /^ typedef __int64 sqlite_int64;$/;" t file: +sqlite_int64 testdocs/sqlite3.c /^ typedef long long int sqlite_int64;$/;" t file: +sqlite_uint64 testdocs/sqlite3.c /^ typedef SQLITE_UINT64_TYPE sqlite_uint64;$/;" t file: +sqlite_uint64 testdocs/sqlite3.c /^ typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;$/;" t file: +sqlite_uint64 testdocs/sqlite3.c /^ typedef unsigned __int64 sqlite_uint64;$/;" t file: +sqlite_uint64 testdocs/sqlite3.c /^ typedef unsigned long long int sqlite_uint64;$/;" t file: +star_oh testdocs/sqlite3.c /^static int star_oh(const char *z){$/;" f file: +startEndFlag testdocs/sqlite3.c /^ unsigned char startEndFlag; \/* 1=rel to end of fork, 0=rel to start *\/$/;" m struct:ByteRangeLockPB2 file: +startTime testdocs/sqlite3.c /^ i64 startTime; \/* Time when query started - used for profiling *\/$/;" m struct:Vdbe file: +stat4Destructor testdocs/sqlite3.c /^static void stat4Destructor(void *pOld){$/;" f file: +stat4ValueFromExpr testdocs/sqlite3.c /^static int stat4ValueFromExpr($/;" f file: +statBestIndex testdocs/sqlite3.c /^static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){$/;" f file: +statClearPage testdocs/sqlite3.c /^static void statClearPage(StatPage *p){$/;" f file: +statClose testdocs/sqlite3.c /^static int statClose(sqlite3_vtab_cursor *pCursor){$/;" f file: +statColumn testdocs/sqlite3.c /^static int statColumn($/;" f file: +statConnect testdocs/sqlite3.c /^static int statConnect($/;" f file: +statDecodePage testdocs/sqlite3.c /^static int statDecodePage(Btree *pBt, StatPage *p){$/;" f file: +statDisconnect testdocs/sqlite3.c /^static int statDisconnect(sqlite3_vtab *pVtab){$/;" f file: +statEof testdocs/sqlite3.c /^static int statEof(sqlite3_vtab_cursor *pCursor){$/;" f file: +statFilter testdocs/sqlite3.c /^static int statFilter($/;" f file: +statGet testdocs/sqlite3.c /^static void statGet($/;" f file: +statGetFuncdef testdocs/sqlite3.c /^static const FuncDef statGetFuncdef = {$/;" v file: +statInit testdocs/sqlite3.c /^static void statInit($/;" f file: +statInitFuncdef testdocs/sqlite3.c /^static const FuncDef statInitFuncdef = {$/;" v file: +statMutex testdocs/sqlite3.c /^static const char statMutex[] = {$/;" v file: +statNext testdocs/sqlite3.c /^static int statNext(sqlite3_vtab_cursor *pCursor){$/;" f file: +statOpen testdocs/sqlite3.c /^static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){$/;" f file: +statPush testdocs/sqlite3.c /^static void statPush($/;" f file: +statPushFuncdef testdocs/sqlite3.c /^static const FuncDef statPushFuncdef = {$/;" v file: +statResetCsr testdocs/sqlite3.c /^static void statResetCsr(StatCursor *pCsr){$/;" f file: +statRowid testdocs/sqlite3.c /^static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){$/;" f file: +statSizeAndOffset testdocs/sqlite3.c /^static void statSizeAndOffset(StatCursor *pCsr){$/;" f file: +stateno testdocs/sqlite3.c /^ YYACTIONTYPE stateno; \/* The state-number, or reduce action in SHIFTREDUCE *\/$/;" m struct:yyStackEntry file: +stateno testdocs/sqlite3.c /^ fts5YYACTIONTYPE stateno; \/* The state-number, or reduce action in SHIFTREDUCE *\/$/;" m struct:fts5yyStackEntry file: +static_assert stdc.h /^ #define static_assert(/;" d +status testdocs/sqlite3.c /^ int (*status)(int,int*,int*,int);$/;" m struct:sqlite3_api_routines file: +status64 testdocs/sqlite3.c /^ int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);$/;" m struct:sqlite3_api_routines file: +stem testdocs/sqlite3.c /^static int stem($/;" f file: +step testdocs/sqlite3.c /^ int (*step)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +step_list testdocs/sqlite3.c /^ TriggerStep *step_list; \/* Link list of trigger program steps *\/$/;" m struct:Trigger file: +stmt_busy testdocs/sqlite3.c /^ int (*stmt_busy)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +stmt_readonly testdocs/sqlite3.c /^ int (*stmt_readonly)(sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +stmt_status testdocs/sqlite3.c /^ int (*stmt_status)(sqlite3_stmt*,int,int);$/;" m struct:sqlite3_api_routines file: +storeLastErrno testdocs/sqlite3.c /^static void storeLastErrno(unixFile *pFile, int error){$/;" f file: +strAccumFinishRealloc testdocs/sqlite3.c /^static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){$/;" f file: +strHash testdocs/sqlite3.c /^static unsigned int strHash(const char *z){$/;" f file: +strftimeFunc testdocs/sqlite3.c /^static void strftimeFunc($/;" f file: +strglob testdocs/sqlite3.c /^ int (*strglob)(const char*,const char*);$/;" m struct:sqlite3_api_routines file: +stricmp testdocs/sqlite3.c /^ int (*stricmp)(const char*,const char*);$/;" m struct:sqlite3_api_routines file: +stringdup buf.c /^char* stringdup(const char* s) {$/;" f +strlike testdocs/sqlite3.c /^ int (*strlike)(const char*,const char*,unsigned int);$/;" m struct:sqlite3_api_routines file: +strnicmp testdocs/sqlite3.c /^ int (*strnicmp)(const char*,const char*,int);$/;" m struct:sqlite3_api_routines file: +subjInMemory testdocs/sqlite3.c /^ u8 subjInMemory; \/* True to use in-memory sub-journals *\/$/;" m struct:Pager file: +subjRequiresPage testdocs/sqlite3.c /^static int subjRequiresPage(PgHdr *pPg){$/;" f file: +subjournalPage testdocs/sqlite3.c /^static int subjournalPage(PgHdr *pPg){$/;" f file: +subjournalPageIfRequired testdocs/sqlite3.c /^static int subjournalPageIfRequired(PgHdr *pPg){$/;" f file: +substExpr testdocs/sqlite3.c /^static Expr *substExpr($/;" f file: +substExprList testdocs/sqlite3.c /^static void substExprList($/;" f file: +substSelect testdocs/sqlite3.c /^static void substSelect($/;" f file: +substrFunc testdocs/sqlite3.c /^static void substrFunc($/;" f file: +sumFinalize testdocs/sqlite3.c /^static void sumFinalize(sqlite3_context *context){$/;" f file: +sumStep testdocs/sqlite3.c /^static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){$/;" f file: +suppressErr testdocs/sqlite3.c /^ u8 suppressErr; \/* Do not issue error messages if true *\/$/;" m struct:sqlite3 file: +swapMixedEndianFloat testdocs/sqlite3.c /^# define swapMixedEndianFloat(/;" d file: +swaplog buf.c /^static void swaplog(Buf* buf, Log** from, Log** to, Sel* sel) {$/;" f file: +switchLockProxyPath testdocs/sqlite3.c /^static int switchLockProxyPath(unixFile *pFile, const char *path) {$/;" f file: +syncFlags testdocs/sqlite3.c /^ int syncFlags; \/* Flags for the fsync *\/$/;" m struct:WalWriter file: +syncFlags testdocs/sqlite3.c /^ u8 syncFlags; \/* SYNC_NORMAL or SYNC_FULL otherwise *\/$/;" m struct:Pager file: +syncFlags testdocs/sqlite3.c /^ u8 syncFlags; \/* Flags to use to sync header writes *\/$/;" m struct:Wal file: +syncHeader testdocs/sqlite3.c /^ u8 syncHeader; \/* Fsync the WAL header if true *\/$/;" m struct:Wal file: +syncJournal testdocs/sqlite3.c /^static int syncJournal(Pager *pPager, int newHdr){$/;" f file: +syncgap buf.c /^static void syncgap(Buf* buf, size_t off) {$/;" f file: +synthCollSeq testdocs/sqlite3.c /^static int synthCollSeq(sqlite3 *db, CollSeq *pColl){$/;" f file: +sys testdocs/waf /^import os, sys, inspect$/;" i +system_errno testdocs/sqlite3.c /^ int (*system_errno)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +sz testdocs/sqlite3.c /^ u16 sz; \/* Size of each buffer in bytes *\/$/;" m struct:Lookaside file: +szAlloc testdocs/sqlite3.c /^ int szAlloc; \/* Total size of one pcache line *\/$/;" m struct:PCache1 file: +szAtom testdocs/sqlite3.c /^ int szAtom; \/* Smallest possible allocation in bytes *\/$/;" m struct:Mem5Global file: +szCache testdocs/sqlite3.c /^ int szCache; \/* Configured cache size *\/$/;" m struct:PCache file: +szCell testdocs/sqlite3.c /^ u16 *szCell; \/* Local size of all cells in apCell[] *\/$/;" m struct:CellArray file: +szChunk testdocs/sqlite3.c /^ int szChunk; \/* Configured by FCNTL_CHUNK_SIZE *\/$/;" m struct:unixFile file: +szChunk testdocs/sqlite3.c /^ int szChunk; \/* Chunk size configured by FCNTL_CHUNK_SIZE *\/$/;" m struct:winFile file: +szCol testdocs/sqlite3.c /^ int szCol; \/* Size of column value in tokens *\/$/;" m struct:Fts5InsertCtx file: +szCol testdocs/sqlite3.c /^ int szCol;$/;" m struct:Fts5IntegrityCtx file: +szEst testdocs/sqlite3.c /^ u8 szEst; \/* Estimated size of value in this column. sizeof(INT)==1 *\/$/;" m struct:Column file: +szExtra testdocs/sqlite3.c /^ int szExtra; \/* Size of extra space for each page *\/$/;" m struct:PCache file: +szExtra testdocs/sqlite3.c /^ int szExtra; \/* sizeof(MemPage)+sizeof(PgHdr) *\/$/;" m struct:PCache1 file: +szFirstBlock testdocs/sqlite3.c /^ int szFirstBlock; \/* Size of first block written to WAL file *\/$/;" m struct:Wal file: +szIdxRow testdocs/sqlite3.c /^ LogEst szIdxRow; \/* Estimated average row size in bytes *\/$/;" m struct:Index file: +szLeaf testdocs/sqlite3.c /^ int szLeaf; \/* Size of leaf without page-index *\/$/;" m struct:Fts5Data file: +szLookaside testdocs/sqlite3.c /^ int szLookaside; \/* Default lookaside buffer size *\/$/;" m struct:Sqlite3Config file: +szMalloc testdocs/sqlite3.c /^ int szMalloc; \/* Size of the zMalloc allocation *\/$/;" m struct:sqlite3_value file: +szMaster testdocs/sqlite3.c /^ u32 szMaster;$/;" m struct:Mem3Global file: +szMmap testdocs/sqlite3.c /^ i64 szMmap; \/* Default mmap_size setting *\/$/;" m struct:sqlite3 file: +szMmap testdocs/sqlite3.c /^ sqlite3_int64 szMmap; \/* mmap() space per open file *\/$/;" m struct:Sqlite3Config file: +szMmap testdocs/sqlite3.c /^ sqlite3_int64 szMmap; \/* Desired maximum mmap size *\/$/;" m struct:Pager file: +szOpAlloc testdocs/sqlite3.c /^ int szOpAlloc; \/* Bytes of memory space allocated for Vdbe.aOp[] *\/$/;" m struct:Parse file: +szOsFile testdocs/sqlite3.c /^ int szOsFile; \/* Size of subclassed sqlite3_file *\/$/;" m struct:sqlite3_vfs file: +szPMA testdocs/sqlite3.c /^ int szPMA; \/* Size of pList as PMA in bytes *\/$/;" m struct:SorterList file: +szPage testdocs/sqlite3.c /^ int szPage; \/* Size of database content section *\/$/;" m struct:PCache1 file: +szPage testdocs/sqlite3.c /^ int szPage; \/* Size of every page in this cache *\/$/;" m struct:PCache file: +szPage testdocs/sqlite3.c /^ int szPage; \/* Size of each page in pPage[] *\/$/;" m struct:Sqlite3Config file: +szPage testdocs/sqlite3.c /^ int szPage; \/* Value of 'pgSize' column *\/$/;" m struct:StatCursor file: +szPage testdocs/sqlite3.c /^ int szPage; \/* Size of one page *\/$/;" m struct:WalWriter file: +szPage testdocs/sqlite3.c /^ u16 szPage; \/* Database page size in bytes. 1==64K *\/$/;" m struct:WalIndexHdr file: +szPage testdocs/sqlite3.c /^ u32 szPage; \/* Database page size *\/$/;" m struct:Wal file: +szPma testdocs/sqlite3.c /^ u32 szPma; \/* Maximum Sorter PMA size *\/$/;" m struct:Sqlite3Config file: +szRegion testdocs/sqlite3.c /^ int szRegion; \/* Size of shared-memory regions *\/$/;" m struct:unixShmNode file: +szRegion testdocs/sqlite3.c /^ int szRegion; \/* Size of shared-memory regions *\/$/;" m struct:winShmNode file: +szRow testdocs/sqlite3.c /^ u32 szRow; \/* Byte available in aRow *\/$/;" m struct:VdbeCursor file: +szScratch testdocs/sqlite3.c /^ int szScratch; \/* Size of each scratch buffer *\/$/;" m struct:Sqlite3Config file: +szSlot testdocs/sqlite3.c /^ int szSlot; \/* Size of each free slot *\/$/;" m struct:PCacheGlobal file: +szSpill testdocs/sqlite3.c /^ int szSpill; \/* Size before spilling occurs *\/$/;" m struct:PCache file: +szTabRow testdocs/sqlite3.c /^ LogEst szTabRow; \/* Estimated size of each table row in bytes *\/$/;" m struct:Table file: +tRowcnt testdocs/sqlite3.c /^ typedef u32 tRowcnt; \/* 32-bit is the default *\/$/;" t file: +tRowcnt testdocs/sqlite3.c /^ typedef u64 tRowcnt; \/* 64-bit only if requested at compile-time *\/$/;" t file: +tabFlags testdocs/sqlite3.c /^ u32 tabFlags; \/* Mask of TF_* values *\/$/;" m struct:Table file: +tabTnct testdocs/sqlite3.c /^ int tabTnct; \/* Ephemeral table used for DISTINCT processing *\/$/;" m struct:DistinctCtx file: +table testdocs/sqlite3.c /^ char *table; \/* The table or view to which the trigger applies *\/$/;" m struct:Trigger file: +tableAndColumnIndex testdocs/sqlite3.c /^static int tableAndColumnIndex($/;" f file: +tableOfTrigger testdocs/sqlite3.c /^static Table *tableOfTrigger(Trigger *pTrigger){$/;" f file: +tableWithCursor testdocs/sqlite3.c /^static Table *tableWithCursor(SrcList *pList, int iCursor){$/;" f file: +table_column_metadata testdocs/sqlite3.c /^ int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,$/;" m struct:sqlite3_api_routines file: +tarfile testdocs/waf /^ import shutil, tarfile$/;" i +targetSrcList testdocs/sqlite3.c /^static SrcList *targetSrcList($/;" f file: +tblHash testdocs/sqlite3.c /^ Hash tblHash; \/* All tables indexed by name *\/$/;" m struct:Schema file: +tblhdr testdocs/sqlite3.c /^ SessionBuffer tblhdr; \/* Buffer to hold apValue\/zTab\/abPK\/ *\/$/;" m struct:sqlite3_changeset_iter file: +tempFile testdocs/sqlite3.c /^ u8 tempFile; \/* zFilename is a temporary or immutable file *\/$/;" m struct:Pager file: +tempReg testdocs/sqlite3.c /^ u8 tempReg; \/* iReg is a temp register that needs to be freed *\/$/;" m struct:Parse::yColCache file: +temp_store testdocs/sqlite3.c /^ u8 temp_store; \/* 1: file 2: memory 0: default *\/$/;" m struct:sqlite3 file: +term testdocs/sqlite3.c /^ Blob term; \/* Current term *\/$/;" m struct:NodeReader file: +term testdocs/sqlite3.c /^ Fts5Buffer term; \/* Buffer containing previous term on page *\/$/;" m struct:Fts5PageWriter file: +term testdocs/sqlite3.c /^ Fts5Buffer term; \/* Current term *\/$/;" m struct:Fts5SegIter file: +term testdocs/sqlite3.c /^ Fts5Buffer term; \/* Current value of 'term' column *\/$/;" m struct:Fts5VocabCursor file: +termCanDriveIndex testdocs/sqlite3.c /^static int termCanDriveIndex($/;" f file: +termIsEquivalence testdocs/sqlite3.c /^static int termIsEquivalence(Parse *pParse, Expr *pExpr){$/;" f file: +test testdocs/waf /^def test(dir):$/;" f +testFunc testdocs/sqlite3.c /^static void testFunc($/;" f file: +test_addop_breakpoint testdocs/sqlite3.c /^static void test_addop_breakpoint(void){$/;" f file: +test_control testdocs/sqlite3.c /^ int (*test_control)(int, ...);$/;" m struct:sqlite3_api_routines file: +test_fts3_node_chunk_threshold testdocs/sqlite3.c /^int test_fts3_node_chunk_threshold = (4*1024)*4;$/;" v +test_fts3_node_chunksize testdocs/sqlite3.c /^int test_fts3_node_chunksize = (4*1024);$/;" v +testcase testdocs/sqlite3.c /^# define testcase(/;" d file: +testcase testdocs/sqlite3.c /^#define testcase(/;" d file: +thread_cleanup testdocs/sqlite3.c /^ void (*thread_cleanup)(void);$/;" m struct:sqlite3_api_routines file: +threadid testdocs/sqlite3.c /^#define threadid /;" d file: +tid testdocs/sqlite3.c /^ pthread_t tid; \/* Thread ID *\/$/;" m struct:SQLiteThread file: +tid testdocs/sqlite3.c /^ void *tid; \/* The thread handle *\/$/;" m struct:SQLiteThread file: +timeFunc testdocs/sqlite3.c /^static void timeFunc($/;" f file: +tkCREATE testdocs/sqlite3.c /^#define tkCREATE /;" d file: +tkEND testdocs/sqlite3.c /^#define tkEND /;" d file: +tkEXPLAIN testdocs/sqlite3.c /^#define tkEXPLAIN /;" d file: +tkOTHER testdocs/sqlite3.c /^#define tkOTHER /;" d file: +tkSEMI testdocs/sqlite3.c /^#define tkSEMI /;" d file: +tkTEMP testdocs/sqlite3.c /^#define tkTEMP /;" d file: +tkTRIGGER testdocs/sqlite3.c /^#define tkTRIGGER /;" d file: +tkWS testdocs/sqlite3.c /^#define tkWS /;" d file: +tmask testdocs/sqlite3.c /^ #undef tmask$/;" d file: +tnum testdocs/sqlite3.c /^ int tnum; \/* DB Page containing root of this index *\/$/;" m struct:Index file: +tnum testdocs/sqlite3.c /^ int tnum; \/* Root BTree page for this table *\/$/;" m struct:Table file: +token testdocs/sqlite3.c /^ void *token; \/* id that may be used to recursive triggers *\/$/;" m struct:SubProgram file: +token testdocs/sqlite3.c /^ void *token; \/* Copy of SubProgram.token *\/$/;" m struct:VdbeFrame file: +tokenizer testdocs/sqlite3.c /^ fts5_tokenizer tokenizer; \/* Parent tokenizer module *\/$/;" m struct:PorterTokenizer file: +totalAlloc testdocs/sqlite3.c /^ u64 totalAlloc; \/* Total of all malloc calls - includes internal frag *\/$/;" m struct:Mem5Global file: +totalExcess testdocs/sqlite3.c /^ u64 totalExcess; \/* Total internal fragmentation *\/$/;" m struct:Mem5Global file: +totalFinalize testdocs/sqlite3.c /^static void totalFinalize(sqlite3_context *context){$/;" f file: +total_changes testdocs/sqlite3.c /^ int (*total_changes)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +total_changes testdocs/sqlite3.c /^static void total_changes($/;" f file: +tr_tm testdocs/sqlite3.c /^ u8 tr_tm; \/* One of TRIGGER_BEFORE, TRIGGER_AFTER *\/$/;" m struct:Trigger file: +trace stdc.h /^#define trace(/;" d +trace testdocs/sqlite3.c /^ int trace; \/* True to trace changes *\/$/;" m struct:sqlite3_mutex file: +trace testdocs/sqlite3.c /^ void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);$/;" m struct:sqlite3_api_routines file: +trace testdocs/sqlite3.c /^ volatile int trace; \/* True to trace changes *\/$/;" m struct:sqlite3_mutex file: +trace_v2 testdocs/sqlite3.c /^ int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);$/;" m struct:sqlite3_api_routines file: +transCntrChng testdocs/sqlite3.c /^ unsigned char transCntrChng; \/* True if the transaction counter changed *\/$/;" m struct:unixFile file: +transferJoinMarkings testdocs/sqlite3.c /^static void transferJoinMarkings(Expr *pDerived, Expr *pBase){$/;" f file: +transferParseError testdocs/sqlite3.c /^static void transferParseError(Parse *pTo, Parse *pFrom){$/;" f file: +transfer_bindings testdocs/sqlite3.c /^ int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);$/;" m struct:sqlite3_api_routines file: +transid edit.h /^ uint transid; \/* tracks the last used transaction id for log entries *\/$/;" m struct:__anon5 +transid edit.h /^ uint transid; \/* transaction id used to group related edits together *\/$/;" m struct:Log +translateColumnToCopy testdocs/sqlite3.c /^static void translateColumnToCopy($/;" f file: +translateP testdocs/sqlite3.c /^static int translateP(char c, const Op *pOp){$/;" f file: +trigHash testdocs/sqlite3.c /^ Hash trigHash; \/* All triggers indexed by name *\/$/;" m struct:Schema file: +triggerStepAllocate testdocs/sqlite3.c /^static TriggerStep *triggerStepAllocate($/;" f file: +trimFunc testdocs/sqlite3.c /^static void trimFunc($/;" f file: +truncateOnCommit testdocs/sqlite3.c /^ u8 truncateOnCommit; \/* True to truncate WAL file on commit *\/$/;" m struct:Wal file: +truthProb testdocs/sqlite3.c /^ LogEst truthProb; \/* Probability of truth for this expression *\/$/;" m struct:WhereTerm file: +ts testdocs/sqlite3.c /^ struct Fts5TransactionState ts;$/;" m struct:Fts5Table typeref:struct:Fts5Table::Fts5TransactionState file: +type testdocs/sqlite3.c /^ etByte type; \/* Conversion paradigm *\/$/;" m struct:et_info file: +typeMask testdocs/sqlite3.c /^ u8 typeMask;$/;" m struct:VdbeSorter file: +typeofFunc testdocs/sqlite3.c /^static void typeofFunc($/;" f file: +tz testdocs/sqlite3.c /^ int tz; \/* Timezone offset in minutes *\/$/;" m struct:DateTime file: +tzSet testdocs/sqlite3.c /^ char tzSet; \/* Timezone was set explicitly *\/$/;" m struct:DateTime file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:ExprList::ExprList_item typeref:union:ExprList::ExprList_item::__anon12 file: +u testdocs/sqlite3.c /^ u32 u; \/* Unsigned for byte-order conversions *\/$/;" m union:RtreeCoord file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:Bitvec typeref:union:Bitvec::__anon24 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:Expr typeref:union:Expr::__anon10 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:FuncDef typeref:union:FuncDef::__anon9 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:JsonNode typeref:union:JsonNode::__anon37 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:Mem3Block typeref:union:Mem3Block::__anon21 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:RtreeConstraint typeref:union:RtreeConstraint::__anon36 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:SorterRecord typeref:union:SorterRecord::__anon25 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:Stat4Sample typeref:union:Stat4Sample::__anon26 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:Walker typeref:union:Walker::__anon17 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:WhereLevel typeref:union:WhereLevel::__anon27 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:WhereLoop typeref:union:WhereLoop::__anon29 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:WhereTerm typeref:union:WhereTerm::__anon32 file: +u testdocs/sqlite3.c /^ } u;$/;" m struct:sqlite3_value typeref:union:sqlite3_value::MemValue file: +u1 testdocs/sqlite3.c /^ } u1;$/;" m struct:SrcList::SrcList_item typeref:union:SrcList::SrcList_item::__anon15 file: +u1 testdocs/sqlite3.c /^ } u1;$/;" m struct:sqlite3 typeref:union:sqlite3::__anon8 file: +u16 testdocs/sqlite3.c /^ typedef unsigned short int u16;$/;" t file: +u16 testdocs/sqlite3.c /^typedef UINT16_TYPE u16; \/* 2-byte unsigned integer *\/$/;" t file: +u16 testdocs/sqlite3.c /^typedef unsigned short u16;$/;" t file: +u32 testdocs/sqlite3.c /^ typedef unsigned int u32;$/;" t file: +u32 testdocs/sqlite3.c /^typedef UINT32_TYPE u32; \/* 4-byte unsigned integer *\/$/;" t file: +u32 testdocs/sqlite3.c /^typedef unsigned int u32;$/;" t file: +u32 testdocs/sqlite3.c /^typedef unsigned int u32; \/* 4-byte unsigned integer *\/$/;" t file: +u32 testdocs/sqlite3.c /^typedef unsigned int u32;$/;" t file: +u64 testdocs/sqlite3.c /^ typedef sqlite3_uint64 u64;$/;" t file: +u64 testdocs/sqlite3.c /^typedef sqlite3_uint64 u64; \/* 8-byte unsigned integer *\/$/;" t file: +u64 testdocs/sqlite3.c /^typedef sqlite3_uint64 u64;$/;" t file: +u64 testdocs/sqlite3.c /^typedef sqlite_uint64 u64; \/* 8-byte unsigned integer *\/$/;" t file: +u8 testdocs/sqlite3.c /^ typedef unsigned char u8;$/;" t file: +u8 testdocs/sqlite3.c /^typedef UINT8_TYPE u8; \/* 1-byte unsigned integer *\/$/;" t file: +u8 testdocs/sqlite3.c /^typedef unsigned char u8;$/;" t file: +u8 testdocs/sqlite3.c /^typedef unsigned char u8; \/* 1-byte (or larger) unsigned integer *\/$/;" t file: +u8 testdocs/sqlite3.c /^typedef unsigned char u8;$/;" t file: +uTemp testdocs/sqlite3.c /^ u32 uTemp; \/* Transient storage for serial_type in OP_MakeRecord *\/$/;" m struct:sqlite3_value file: +uc testdocs/sqlite3.c /^ } uc;$/;" m struct:VdbeCursor typeref:union:VdbeCursor::__anon18 file: +uchar stdc.h /^typedef unsigned char uchar;$/;" t +uint stdc.h /^typedef unsigned int uint;$/;" t +uint16 stdc.h /^typedef uint16_t uint16;$/;" t +uint32 stdc.h /^typedef uint32_t uint32;$/;" t +uint64 stdc.h /^typedef uint64_t uint64;$/;" t +uint8 stdc.h /^typedef uint8_t uint8;$/;" t +uintptr stdc.h /^typedef uintptr_t uintptr;$/;" t +ulong stdc.h /^typedef unsigned long ulong;$/;" t +unLockFlag testdocs/sqlite3.c /^ unsigned char unLockFlag; \/* 1 = unlock, 0 = lock *\/$/;" m struct:ByteRangeLockPB2 file: +undo edit.h /^ Log* undo; \/* undo list *\/$/;" m struct:__anon5 +unicodeAddExceptions testdocs/sqlite3.c /^static int unicodeAddExceptions($/;" f file: +unicodeClose testdocs/sqlite3.c /^static int unicodeClose(sqlite3_tokenizer_cursor *pCursor){$/;" f file: +unicodeCreate testdocs/sqlite3.c /^static int unicodeCreate($/;" f file: +unicodeDestroy testdocs/sqlite3.c /^static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){$/;" f file: +unicodeFunc testdocs/sqlite3.c /^static void unicodeFunc($/;" f file: +unicodeIsAlnum testdocs/sqlite3.c /^static int unicodeIsAlnum(unicode_tokenizer *p, int iCode){$/;" f file: +unicodeIsException testdocs/sqlite3.c /^static int unicodeIsException(unicode_tokenizer *p, int iCode){$/;" f file: +unicodeNext testdocs/sqlite3.c /^static int unicodeNext($/;" f file: +unicodeOpen testdocs/sqlite3.c /^static int unicodeOpen($/;" f file: +unicode_cursor testdocs/sqlite3.c /^struct unicode_cursor {$/;" s file: +unicode_cursor testdocs/sqlite3.c /^typedef struct unicode_cursor unicode_cursor;$/;" t typeref:struct:unicode_cursor file: +unicode_tokenizer testdocs/sqlite3.c /^struct unicode_tokenizer {$/;" s file: +unicode_tokenizer testdocs/sqlite3.c /^typedef struct unicode_tokenizer unicode_tokenizer;$/;" t typeref:struct:unicode_tokenizer file: +uniqNotNull testdocs/sqlite3.c /^ unsigned uniqNotNull:1; \/* True if UNIQUE and NOT NULL for all columns *\/$/;" m struct:Index file: +unique_id stdc.h /^#define unique_id /;" d +unixAccess testdocs/sqlite3.c /^static int unixAccess($/;" f file: +unixCheckReservedLock testdocs/sqlite3.c /^static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){$/;" f file: +unixClose testdocs/sqlite3.c /^static int unixClose(sqlite3_file *id){$/;" f file: +unixCurrentTime testdocs/sqlite3.c /^# define unixCurrentTime /;" d file: +unixCurrentTime testdocs/sqlite3.c /^static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){$/;" f file: +unixCurrentTimeInt64 testdocs/sqlite3.c /^static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){$/;" f file: +unixDelete testdocs/sqlite3.c /^static int unixDelete($/;" f file: +unixDeviceCharacteristics testdocs/sqlite3.c /^static int unixDeviceCharacteristics(sqlite3_file *id){$/;" f file: +unixDlClose testdocs/sqlite3.c /^ #define unixDlClose /;" d file: +unixDlClose testdocs/sqlite3.c /^static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){$/;" f file: +unixDlError testdocs/sqlite3.c /^ #define unixDlError /;" d file: +unixDlError testdocs/sqlite3.c /^static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){$/;" f file: +unixDlOpen testdocs/sqlite3.c /^ #define unixDlOpen /;" d file: +unixDlOpen testdocs/sqlite3.c /^static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){$/;" f file: +unixDlSym testdocs/sqlite3.c /^ #define unixDlSym /;" d file: +unixDlSym testdocs/sqlite3.c /^static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){$/;" f file: +unixEnterMutex testdocs/sqlite3.c /^static void unixEnterMutex(void){$/;" f file: +unixFetch testdocs/sqlite3.c /^static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){$/;" f file: +unixFile testdocs/sqlite3.c /^struct unixFile {$/;" s file: +unixFile testdocs/sqlite3.c /^typedef struct unixFile unixFile;$/;" t typeref:struct:unixFile file: +unixFileControl testdocs/sqlite3.c /^static int unixFileControl(sqlite3_file *id, int op, void *pArg){$/;" f file: +unixFileId testdocs/sqlite3.c /^struct unixFileId {$/;" s file: +unixFileLock testdocs/sqlite3.c /^static int unixFileLock(unixFile *pFile, struct flock *pLock){$/;" f file: +unixFileSize testdocs/sqlite3.c /^static int unixFileSize(sqlite3_file *id, i64 *pSize){$/;" f file: +unixFullPathname testdocs/sqlite3.c /^static int unixFullPathname($/;" f file: +unixGetLastError testdocs/sqlite3.c /^static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){$/;" f file: +unixGetSystemCall testdocs/sqlite3.c /^static sqlite3_syscall_ptr unixGetSystemCall($/;" f file: +unixGetTempname testdocs/sqlite3.c /^static int unixGetTempname(int nBuf, char *zBuf){$/;" f file: +unixGetpagesize testdocs/sqlite3.c /^static int unixGetpagesize(void){$/;" f file: +unixInodeInfo testdocs/sqlite3.c /^struct unixInodeInfo {$/;" s file: +unixInodeInfo testdocs/sqlite3.c /^typedef struct unixInodeInfo unixInodeInfo; \/* An i-node *\/$/;" t typeref:struct:unixInodeInfo file: +unixLeaveMutex testdocs/sqlite3.c /^static void unixLeaveMutex(void){$/;" f file: +unixLock testdocs/sqlite3.c /^static int unixLock(sqlite3_file *id, int eFileLock){$/;" f file: +unixLogError testdocs/sqlite3.c /^#define unixLogError(/;" d file: +unixLogErrorAtLine testdocs/sqlite3.c /^static int unixLogErrorAtLine($/;" f file: +unixMapfile testdocs/sqlite3.c /^static int unixMapfile(unixFile *pFd, i64 nMap){$/;" f file: +unixModeBit testdocs/sqlite3.c /^static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){$/;" f file: +unixMutexHeld testdocs/sqlite3.c /^static int unixMutexHeld(void) {$/;" f file: +unixNextSystemCall testdocs/sqlite3.c /^static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){$/;" f file: +unixOpen testdocs/sqlite3.c /^static int unixOpen($/;" f file: +unixOpenSharedMemory testdocs/sqlite3.c /^static int unixOpenSharedMemory(unixFile *pDbFd){$/;" f file: +unixRandomness testdocs/sqlite3.c /^static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){$/;" f file: +unixRead testdocs/sqlite3.c /^static int unixRead($/;" f file: +unixRemapfile testdocs/sqlite3.c /^static void unixRemapfile($/;" f file: +unixSectorSize testdocs/sqlite3.c /^static int unixSectorSize(sqlite3_file *NotUsed){$/;" f file: +unixSectorSize testdocs/sqlite3.c /^static int unixSectorSize(sqlite3_file *id){$/;" f file: +unixSetSystemCall testdocs/sqlite3.c /^static int unixSetSystemCall($/;" f file: +unixShm testdocs/sqlite3.c /^struct unixShm {$/;" s file: +unixShm testdocs/sqlite3.c /^typedef struct unixShm unixShm; \/* Connection shared memory *\/$/;" t typeref:struct:unixShm file: +unixShmBarrier testdocs/sqlite3.c /^# define unixShmBarrier /;" d file: +unixShmBarrier testdocs/sqlite3.c /^static void unixShmBarrier($/;" f file: +unixShmLock testdocs/sqlite3.c /^# define unixShmLock /;" d file: +unixShmLock testdocs/sqlite3.c /^static int unixShmLock($/;" f file: +unixShmMap testdocs/sqlite3.c /^# define unixShmMap /;" d file: +unixShmMap testdocs/sqlite3.c /^static int unixShmMap($/;" f file: +unixShmNode testdocs/sqlite3.c /^struct unixShmNode {$/;" s file: +unixShmNode testdocs/sqlite3.c /^typedef struct unixShmNode unixShmNode; \/* Shared memory instance *\/$/;" t typeref:struct:unixShmNode file: +unixShmPurge testdocs/sqlite3.c /^static void unixShmPurge(unixFile *pFd){$/;" f file: +unixShmRegionPerMap testdocs/sqlite3.c /^static int unixShmRegionPerMap(void){$/;" f file: +unixShmSystemLock testdocs/sqlite3.c /^static int unixShmSystemLock($/;" f file: +unixShmUnmap testdocs/sqlite3.c /^# define unixShmUnmap /;" d file: +unixShmUnmap testdocs/sqlite3.c /^static int unixShmUnmap($/;" f file: +unixSleep testdocs/sqlite3.c /^static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){$/;" f file: +unixSync testdocs/sqlite3.c /^static int unixSync(sqlite3_file *id, int flags){$/;" f file: +unixTempFileDir testdocs/sqlite3.c /^static const char *unixTempFileDir(void){$/;" f file: +unixTruncate testdocs/sqlite3.c /^static int unixTruncate(sqlite3_file *id, i64 nByte){$/;" f file: +unixUnfetch testdocs/sqlite3.c /^static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){$/;" f file: +unixUnlock testdocs/sqlite3.c /^static int unixUnlock(sqlite3_file *id, int eFileLock){$/;" f file: +unixUnmapfile testdocs/sqlite3.c /^static void unixUnmapfile(unixFile *pFd){$/;" f file: +unixWrite testdocs/sqlite3.c /^static int unixWrite($/;" f file: +unix_syscall testdocs/sqlite3.c /^static struct unix_syscall {$/;" s file: +unknownFunc testdocs/sqlite3.c /^static void unknownFunc($/;" f file: +unlikely testdocs/sqlite3.c /^#define unlikely(/;" d file: +unlockBtreeIfUnused testdocs/sqlite3.c /^static void unlockBtreeIfUnused(BtShared *pBt){$/;" f file: +unlockBtreeMutex testdocs/sqlite3.c /^static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){$/;" f file: +unlock_notify testdocs/sqlite3.c /^ int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);$/;" m struct:sqlite3_api_routines file: +unpack_wafdir testdocs/waf /^def unpack_wafdir(dir, src):$/;" f +untestedTerms testdocs/sqlite3.c /^ u8 untestedTerms; \/* Not all WHERE terms resolved by outer loop *\/$/;" m struct:WhereInfo file: +unused testdocs/sqlite3.c /^ u32 unused; \/* Unused (padding) field *\/$/;" m struct:WalIndexHdr file: +updateAccumulator testdocs/sqlite3.c /^static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){$/;" f file: +updateMapping testdocs/sqlite3.c /^static int updateMapping($/;" f file: +updateMaxBlobsize testdocs/sqlite3.c /^static void updateMaxBlobsize(Mem *p){$/;" f file: +updateRangeAffinityStr testdocs/sqlite3.c /^static void updateRangeAffinityStr($/;" f file: +updateVirtualTable testdocs/sqlite3.c /^static void updateVirtualTable($/;" f file: +update_hook testdocs/sqlite3.c /^ void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,$/;" m struct:sqlite3_api_routines file: +upperFunc testdocs/sqlite3.c /^static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){$/;" f file: +uptr testdocs/sqlite3.c /^ typedef u32 uptr;$/;" t file: +uptr testdocs/sqlite3.c /^ typedef u64 uptr;$/;" t file: +uptr testdocs/sqlite3.c /^ typedef uintptr_t uptr;$/;" t file: +uri_boolean testdocs/sqlite3.c /^ int (*uri_boolean)(const char*,const char*,int);$/;" m struct:sqlite3_api_routines file: +uri_int64 testdocs/sqlite3.c /^ sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);$/;" m struct:sqlite3_api_routines file: +uri_parameter testdocs/sqlite3.c /^ const char *(*uri_parameter)(const char*,const char*);$/;" m struct:sqlite3_api_routines file: +usable testdocs/sqlite3.c /^ unsigned char usable; \/* True if this constraint is usable *\/$/;" m struct:sqlite3_index_info::sqlite3_index_constraint file: +usableSize testdocs/sqlite3.c /^ u32 usableSize; \/* Number of usable bytes on each page *\/$/;" m struct:BtShared file: +useJournal testdocs/sqlite3.c /^ u8 useJournal; \/* Use a rollback journal on this file *\/$/;" m struct:Pager file: +useRandomRowid testdocs/sqlite3.c /^ Bool useRandomRowid:1; \/* Generate new record numbers semi-randomly *\/$/;" m struct:VdbeCursor file: +useSortingIdx testdocs/sqlite3.c /^ u8 useSortingIdx; \/* In direct mode, reference the sorting index rather$/;" m struct:AggInfo file: +usedAsColumnCache testdocs/sqlite3.c /^static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){$/;" f file: +user_data testdocs/sqlite3.c /^ void * (*user_data)(sqlite3_context*);$/;" m struct:sqlite3_api_routines file: +usesStmtJournal testdocs/sqlite3.c /^ bft usesStmtJournal:1; \/* True if uses a statement journal *\/$/;" m struct:Vdbe file: +ushort stdc.h /^typedef unsigned short ushort;$/;" t +utf8decode buf.c /^bool utf8decode(Rune* rune, size_t* length, int byte) {$/;" f +utf8encode buf.c /^size_t utf8encode(char str[UTF_MAX], Rune rune) {$/;" f +utfseq buf.c /^static uint8_t utfseq(uint8_t byte) {$/;" f file: +uvlong stdc.h /^typedef unsigned long long uvlong;$/;" t +v testdocs/sqlite3.c /^ Vdbe *v; \/* Vdbe to iterate through the opcodes of *\/$/;" m struct:VdbeOpIter file: +v testdocs/sqlite3.c /^ Vdbe *v; \/* VM this frame belongs to *\/$/;" m struct:VdbeFrame file: +v testdocs/sqlite3.c /^ Vdbe *v;$/;" m struct:PreUpdate file: +v testdocs/sqlite3.c /^ i64 v; \/* ROWID value for this entry *\/$/;" m struct:RowSetEntry file: +v1 testdocs/sqlite3.c /^ int v1, v2; \/* Values for up to two %d fields in zPfx *\/$/;" m struct:IntegrityCk file: +v2 testdocs/sqlite3.c /^ int v1, v2; \/* Values for up to two %d fields in zPfx *\/$/;" m struct:IntegrityCk file: +validHMS testdocs/sqlite3.c /^ char validHMS; \/* True (1) if h,m,s are valid *\/$/;" m struct:DateTime file: +validJD testdocs/sqlite3.c /^ char validJD; \/* True (1) if iJD is valid *\/$/;" m struct:DateTime file: +validJulianDay testdocs/sqlite3.c /^static int validJulianDay(sqlite3_int64 iJD){$/;" f file: +validTZ testdocs/sqlite3.c /^ char validTZ; \/* True (1) if tz is valid *\/$/;" m struct:DateTime file: +validYMD testdocs/sqlite3.c /^ char validYMD; \/* True (1) if Y,M,D are valid *\/$/;" m struct:DateTime file: +value testdocs/sqlite3.c /^ struct {int value; int mask;} yy497;$/;" m struct:__anon33::__anon34 file: +valueBytes testdocs/sqlite3.c /^static SQLITE_NOINLINE int valueBytes(sqlite3_value *pVal, u8 enc){$/;" f file: +valueFromExpr testdocs/sqlite3.c /^static int valueFromExpr($/;" f file: +valueFromFunction testdocs/sqlite3.c /^# define valueFromFunction(/;" d file: +valueFromFunction testdocs/sqlite3.c /^static int valueFromFunction($/;" f file: +valueNew testdocs/sqlite3.c /^static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){$/;" f file: +valueToText testdocs/sqlite3.c /^static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){$/;" f file: +value_blob testdocs/sqlite3.c /^ const void * (*value_blob)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_bytes testdocs/sqlite3.c /^ int (*value_bytes)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_bytes16 testdocs/sqlite3.c /^ int (*value_bytes16)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_double testdocs/sqlite3.c /^ double (*value_double)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_dup testdocs/sqlite3.c /^ sqlite3_value *(*value_dup)(const sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_free testdocs/sqlite3.c /^ void (*value_free)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_int testdocs/sqlite3.c /^ int (*value_int)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_int64 testdocs/sqlite3.c /^ sqlite_int64 (*value_int64)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_numeric_type testdocs/sqlite3.c /^ int (*value_numeric_type)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_subtype testdocs/sqlite3.c /^ unsigned int (*value_subtype)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_text testdocs/sqlite3.c /^ const unsigned char * (*value_text)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_text16 testdocs/sqlite3.c /^ const void * (*value_text16)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_text16be testdocs/sqlite3.c /^ const void * (*value_text16be)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_text16le testdocs/sqlite3.c /^ const void * (*value_text16le)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +value_type testdocs/sqlite3.c /^ int (*value_type)(sqlite3_value*);$/;" m struct:sqlite3_api_routines file: +vdbeAssertFieldCountWithinLimits testdocs/sqlite3.c /^# define vdbeAssertFieldCountWithinLimits(/;" d file: +vdbeAssertFieldCountWithinLimits testdocs/sqlite3.c /^static void vdbeAssertFieldCountWithinLimits($/;" f file: +vdbeChangeP4Full testdocs/sqlite3.c /^static void SQLITE_NOINLINE vdbeChangeP4Full($/;" f file: +vdbeCloseStatement testdocs/sqlite3.c /^static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){$/;" f file: +vdbeClrCopy testdocs/sqlite3.c /^static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){$/;" f file: +vdbeCommit testdocs/sqlite3.c /^static int vdbeCommit(sqlite3 *db, Vdbe *p){$/;" f file: +vdbeCompareMemString testdocs/sqlite3.c /^static int vdbeCompareMemString($/;" f file: +vdbeFreeOpArray testdocs/sqlite3.c /^static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){$/;" f file: +vdbeFreeUnpacked testdocs/sqlite3.c /^static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){$/;" f file: +vdbeIncrBgPopulate testdocs/sqlite3.c /^static int vdbeIncrBgPopulate(IncrMerger *pIncr){$/;" f file: +vdbeIncrFree testdocs/sqlite3.c /^static void vdbeIncrFree(IncrMerger *pIncr){$/;" f file: +vdbeIncrMergerNew testdocs/sqlite3.c /^static int vdbeIncrMergerNew($/;" f file: +vdbeIncrMergerSetThreads testdocs/sqlite3.c /^static void vdbeIncrMergerSetThreads(IncrMerger *pIncr){$/;" f file: +vdbeIncrPopulate testdocs/sqlite3.c /^static int vdbeIncrPopulate(IncrMerger *pIncr){$/;" f file: +vdbeIncrPopulateThread testdocs/sqlite3.c /^static void *vdbeIncrPopulateThread(void *pCtx){$/;" f file: +vdbeIncrSwap testdocs/sqlite3.c /^static int vdbeIncrSwap(IncrMerger *pIncr){$/;" f file: +vdbeInvokeSqllog testdocs/sqlite3.c /^# define vdbeInvokeSqllog(/;" d file: +vdbeInvokeSqllog testdocs/sqlite3.c /^static void vdbeInvokeSqllog(Vdbe *v){$/;" f file: +vdbeLeave testdocs/sqlite3.c /^static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){$/;" f file: +vdbeMemAddTerminator testdocs/sqlite3.c /^static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){$/;" f file: +vdbeMemClear testdocs/sqlite3.c /^static SQLITE_NOINLINE void vdbeMemClear(Mem *p){$/;" f file: +vdbeMemClearExternAndSetNull testdocs/sqlite3.c /^static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){$/;" f file: +vdbeMemFromBtreeResize testdocs/sqlite3.c /^static SQLITE_NOINLINE int vdbeMemFromBtreeResize($/;" f file: +vdbeMergeEngineCompare testdocs/sqlite3.c /^static void vdbeMergeEngineCompare($/;" f file: +vdbeMergeEngineFree testdocs/sqlite3.c /^static void vdbeMergeEngineFree(MergeEngine *pMerger){$/;" f file: +vdbeMergeEngineInit testdocs/sqlite3.c /^static int vdbeMergeEngineInit($/;" f file: +vdbeMergeEngineLevel0 testdocs/sqlite3.c /^static int vdbeMergeEngineLevel0($/;" f file: +vdbeMergeEngineNew testdocs/sqlite3.c /^static MergeEngine *vdbeMergeEngineNew(int nReader){$/;" f file: +vdbeMergeEngineStep testdocs/sqlite3.c /^static int vdbeMergeEngineStep($/;" f file: +vdbePmaReadBlob testdocs/sqlite3.c /^static int vdbePmaReadBlob($/;" f file: +vdbePmaReadVarint testdocs/sqlite3.c /^static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){$/;" f file: +vdbePmaReaderBgIncrInit testdocs/sqlite3.c /^static void *vdbePmaReaderBgIncrInit(void *pCtx){$/;" f file: +vdbePmaReaderClear testdocs/sqlite3.c /^static void vdbePmaReaderClear(PmaReader *pReadr){$/;" f file: +vdbePmaReaderIncrInit testdocs/sqlite3.c /^static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){$/;" f file: +vdbePmaReaderIncrMergeInit testdocs/sqlite3.c /^static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){$/;" f file: +vdbePmaReaderInit testdocs/sqlite3.c /^static int vdbePmaReaderInit($/;" f file: +vdbePmaReaderNext testdocs/sqlite3.c /^static int vdbePmaReaderNext(PmaReader *pReadr){$/;" f file: +vdbePmaReaderSeek testdocs/sqlite3.c /^static int vdbePmaReaderSeek($/;" f file: +vdbePmaWriteBlob testdocs/sqlite3.c /^static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){$/;" f file: +vdbePmaWriteVarint testdocs/sqlite3.c /^static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){$/;" f file: +vdbePmaWriterFinish testdocs/sqlite3.c /^static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){$/;" f file: +vdbePmaWriterInit testdocs/sqlite3.c /^static void vdbePmaWriterInit($/;" f file: +vdbeRecordCompareDebug testdocs/sqlite3.c /^static int vdbeRecordCompareDebug($/;" f file: +vdbeRecordCompareInt testdocs/sqlite3.c /^static int vdbeRecordCompareInt($/;" f file: +vdbeRecordCompareString testdocs/sqlite3.c /^static int vdbeRecordCompareString($/;" f file: +vdbeRecordDecodeInt testdocs/sqlite3.c /^static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){$/;" f file: +vdbeReleaseAndSetInt64 testdocs/sqlite3.c /^static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){$/;" f file: +vdbeSafety testdocs/sqlite3.c /^static int vdbeSafety(Vdbe *p){$/;" f file: +vdbeSafetyNotNull testdocs/sqlite3.c /^static int vdbeSafetyNotNull(Vdbe *p){$/;" f file: +vdbeSortAllocUnpacked testdocs/sqlite3.c /^static int vdbeSortAllocUnpacked(SortSubtask *pTask){$/;" f file: +vdbeSortSubtaskCleanup testdocs/sqlite3.c /^static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){$/;" f file: +vdbeSorterAddToTree testdocs/sqlite3.c /^static int vdbeSorterAddToTree($/;" f file: +vdbeSorterBlockDebug testdocs/sqlite3.c /^# define vdbeSorterBlockDebug(/;" d file: +vdbeSorterBlockDebug testdocs/sqlite3.c /^static void vdbeSorterBlockDebug($/;" f file: +vdbeSorterCompare testdocs/sqlite3.c /^static int vdbeSorterCompare($/;" f file: +vdbeSorterCompareInt testdocs/sqlite3.c /^static int vdbeSorterCompareInt($/;" f file: +vdbeSorterCompareTail testdocs/sqlite3.c /^static int vdbeSorterCompareTail($/;" f file: +vdbeSorterCompareText testdocs/sqlite3.c /^static int vdbeSorterCompareText($/;" f file: +vdbeSorterCreateThread testdocs/sqlite3.c /^static int vdbeSorterCreateThread($/;" f file: +vdbeSorterExtendFile testdocs/sqlite3.c /^# define vdbeSorterExtendFile(/;" d file: +vdbeSorterExtendFile testdocs/sqlite3.c /^static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){$/;" f file: +vdbeSorterFlushPMA testdocs/sqlite3.c /^static int vdbeSorterFlushPMA(VdbeSorter *pSorter){$/;" f file: +vdbeSorterFlushThread testdocs/sqlite3.c /^static void *vdbeSorterFlushThread(void *pCtx){$/;" f file: +vdbeSorterGetCompare testdocs/sqlite3.c /^static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){$/;" f file: +vdbeSorterJoinAll testdocs/sqlite3.c /^# define vdbeSorterJoinAll(/;" d file: +vdbeSorterJoinAll testdocs/sqlite3.c /^static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){$/;" f file: +vdbeSorterJoinThread testdocs/sqlite3.c /^# define vdbeSorterJoinThread(/;" d file: +vdbeSorterJoinThread testdocs/sqlite3.c /^static int vdbeSorterJoinThread(SortSubtask *pTask){$/;" f file: +vdbeSorterListToPMA testdocs/sqlite3.c /^static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){$/;" f file: +vdbeSorterMapFile testdocs/sqlite3.c /^static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){$/;" f file: +vdbeSorterMerge testdocs/sqlite3.c /^static SorterRecord *vdbeSorterMerge($/;" f file: +vdbeSorterMergeTreeBuild testdocs/sqlite3.c /^static int vdbeSorterMergeTreeBuild($/;" f file: +vdbeSorterOpenTempFile testdocs/sqlite3.c /^static int vdbeSorterOpenTempFile($/;" f file: +vdbeSorterPopulateDebug testdocs/sqlite3.c /^# define vdbeSorterPopulateDebug(/;" d file: +vdbeSorterPopulateDebug testdocs/sqlite3.c /^static void vdbeSorterPopulateDebug($/;" f file: +vdbeSorterRecordFree testdocs/sqlite3.c /^static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){$/;" f file: +vdbeSorterRewindDebug testdocs/sqlite3.c /^# define vdbeSorterRewindDebug(/;" d file: +vdbeSorterRewindDebug testdocs/sqlite3.c /^static void vdbeSorterRewindDebug(const char *zEvent){$/;" f file: +vdbeSorterRowkey testdocs/sqlite3.c /^static void *vdbeSorterRowkey($/;" f file: +vdbeSorterSetupMerge testdocs/sqlite3.c /^static int vdbeSorterSetupMerge(VdbeSorter *pSorter){$/;" f file: +vdbeSorterSort testdocs/sqlite3.c /^static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){$/;" f file: +vdbeSorterTreeDepth testdocs/sqlite3.c /^static int vdbeSorterTreeDepth(int nPMA){$/;" f file: +vdbeSorterWorkDebug testdocs/sqlite3.c /^# define vdbeSorterWorkDebug(/;" d file: +vdbeSorterWorkDebug testdocs/sqlite3.c /^static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){$/;" f file: +vdbeTakeBranch testdocs/sqlite3.c /^ static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){$/;" f file: +vdbeUnbind testdocs/sqlite3.c /^static int vdbeUnbind(Vdbe *p, int i){$/;" f file: +vdbeUnpackRecord testdocs/sqlite3.c /^static UnpackedRecord *vdbeUnpackRecord($/;" f file: +vdbeVComment testdocs/sqlite3.c /^static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){$/;" f file: +verifyDbFile testdocs/sqlite3.c /^static void verifyDbFile(unixFile *pFile){$/;" f file: +versionFunc testdocs/sqlite3.c /^static void versionFunc($/;" f file: +vfsFlags testdocs/sqlite3.c /^ u32 vfsFlags; \/* Flags for sqlite3_vfs.xOpen() *\/$/;" m struct:Pager file: +vfsList testdocs/sqlite3.c /^#define vfsList /;" d file: +vfsList testdocs/sqlite3.c /^static sqlite3_vfs * SQLITE_WSD vfsList = 0;$/;" v file: +vfsUnlink testdocs/sqlite3.c /^static void vfsUnlink(sqlite3_vfs *pVfs){$/;" f file: +vfs_find testdocs/sqlite3.c /^ sqlite3_vfs *(*vfs_find)(const char*);$/;" m struct:sqlite3_api_routines file: +vfs_register testdocs/sqlite3.c /^ int (*vfs_register)(sqlite3_vfs*,int);$/;" m struct:sqlite3_api_routines file: +vfs_unregister testdocs/sqlite3.c /^ int (*vfs_unregister)(sqlite3_vfs*);$/;" m struct:sqlite3_api_routines file: +viaCoroutine testdocs/sqlite3.c /^ unsigned viaCoroutine :1; \/* Implemented as a co-routine *\/$/;" m struct:SrcList::SrcList_item::__anon14 file: +vlong stdc.h /^typedef long long vlong;$/;" t +vmprintf testdocs/sqlite3.c /^ char *(*vmprintf)(const char*,va_list);$/;" m struct:sqlite3_api_routines file: +vsnprintf testdocs/sqlite3.c /^ char *(*vsnprintf)(int,char*,const char*,va_list);$/;" m struct:sqlite3_api_routines file: +vtab testdocs/sqlite3.c /^ } vtab;$/;" m union:WhereLoop::__anon29 typeref:struct:WhereLoop::__anon29::__anon31 file: +vtabBestIndex testdocs/sqlite3.c /^static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){$/;" f file: +vtabCallConstructor testdocs/sqlite3.c /^static int vtabCallConstructor($/;" f file: +vtabDisconnectAll testdocs/sqlite3.c /^static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){$/;" f file: +vtabOnConflict testdocs/sqlite3.c /^ u8 vtabOnConflict; \/* Value to return for s3_vtab_on_conflict() *\/$/;" m struct:sqlite3 file: +vtab_config testdocs/sqlite3.c /^ int (*vtab_config)(sqlite3*,int op,...);$/;" m struct:sqlite3_api_routines file: +vtab_on_conflict testdocs/sqlite3.c /^ int (*vtab_on_conflict)(sqlite3*);$/;" m struct:sqlite3_api_routines file: +vxworksFileId testdocs/sqlite3.c /^struct vxworksFileId {$/;" s file: +vxworksFileList testdocs/sqlite3.c /^static struct vxworksFileId *vxworksFileList = 0;$/;" v typeref:struct:vxworksFileId file: +vxworksFindFileId testdocs/sqlite3.c /^static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){$/;" f file: +vxworksIoFinder testdocs/sqlite3.c /^ *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl;$/;" v file: +vxworksIoFinderImpl testdocs/sqlite3.c /^static const sqlite3_io_methods *vxworksIoFinderImpl($/;" f file: +vxworksReleaseFileId testdocs/sqlite3.c /^static void vxworksReleaseFileId(struct vxworksFileId *pId){$/;" f file: +vxworksSimplifyName testdocs/sqlite3.c /^static int vxworksSimplifyName(char *z, int n){$/;" f file: +wafdir testdocs/waf /^wafdir = find_lib()$/;" v +walBusyLock testdocs/sqlite3.c /^static int walBusyLock($/;" f file: +walCheckpoint testdocs/sqlite3.c /^static int walCheckpoint($/;" f file: +walChecksumBytes testdocs/sqlite3.c /^static void walChecksumBytes($/;" f file: +walCkptInfo testdocs/sqlite3.c /^static volatile WalCkptInfo *walCkptInfo(Wal *pWal){$/;" f file: +walCleanupHash testdocs/sqlite3.c /^static void walCleanupHash(Wal *pWal){$/;" f file: +walDecodeFrame testdocs/sqlite3.c /^static int walDecodeFrame($/;" f file: +walEncodeFrame testdocs/sqlite3.c /^static void walEncodeFrame($/;" f file: +walFrameOffset testdocs/sqlite3.c /^#define walFrameOffset(/;" d file: +walFramePage testdocs/sqlite3.c /^static int walFramePage(u32 iFrame){$/;" f file: +walFramePgno testdocs/sqlite3.c /^static u32 walFramePgno(Wal *pWal, u32 iFrame){$/;" f file: +walHash testdocs/sqlite3.c /^static int walHash(u32 iPage){$/;" f file: +walHashGet testdocs/sqlite3.c /^static int walHashGet($/;" f file: +walIndexAppend testdocs/sqlite3.c /^static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){$/;" f file: +walIndexClose testdocs/sqlite3.c /^static void walIndexClose(Wal *pWal, int isDelete){$/;" f file: +walIndexHdr testdocs/sqlite3.c /^static volatile WalIndexHdr *walIndexHdr(Wal *pWal){$/;" f file: +walIndexPage testdocs/sqlite3.c /^static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){$/;" f file: +walIndexReadHdr testdocs/sqlite3.c /^static int walIndexReadHdr(Wal *pWal, int *pChanged){$/;" f file: +walIndexRecover testdocs/sqlite3.c /^static int walIndexRecover(Wal *pWal){$/;" f file: +walIndexTryHdr testdocs/sqlite3.c /^static int walIndexTryHdr(Wal *pWal, int *pChanged){$/;" f file: +walIndexWriteHdr testdocs/sqlite3.c /^static void walIndexWriteHdr(Wal *pWal){$/;" f file: +walIteratorFree testdocs/sqlite3.c /^static void walIteratorFree(WalIterator *p){$/;" f file: +walIteratorInit testdocs/sqlite3.c /^static int walIteratorInit(Wal *pWal, WalIterator **pp){$/;" f file: +walIteratorNext testdocs/sqlite3.c /^static int walIteratorNext($/;" f file: +walLimitSize testdocs/sqlite3.c /^static void walLimitSize(Wal *pWal, i64 nMax){$/;" f file: +walLockExclusive testdocs/sqlite3.c /^static int walLockExclusive(Wal *pWal, int lockIdx, int n){$/;" f file: +walLockName testdocs/sqlite3.c /^static const char *walLockName(int lockIdx){$/;" f file: +walLockShared testdocs/sqlite3.c /^static int walLockShared(Wal *pWal, int lockIdx){$/;" f file: +walMerge testdocs/sqlite3.c /^static void walMerge($/;" f file: +walMergesort testdocs/sqlite3.c /^static void walMergesort($/;" f file: +walNextHash testdocs/sqlite3.c /^static int walNextHash(int iPriorHash){$/;" f file: +walPagesize testdocs/sqlite3.c /^static int walPagesize(Wal *pWal){$/;" f file: +walRestartHdr testdocs/sqlite3.c /^static void walRestartHdr(Wal *pWal, u32 salt1){$/;" f file: +walRestartLog testdocs/sqlite3.c /^static int walRestartLog(Wal *pWal){$/;" f file: +walRewriteChecksums testdocs/sqlite3.c /^static int walRewriteChecksums(Wal *pWal, u32 iLast){$/;" f file: +walShmBarrier testdocs/sqlite3.c /^static void walShmBarrier(Wal *pWal){$/;" f file: +walSyncFlags testdocs/sqlite3.c /^ u8 walSyncFlags; \/* SYNC_NORMAL or SYNC_FULL for wal writes *\/$/;" m struct:Pager file: +walTryBeginRead testdocs/sqlite3.c /^static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){$/;" f file: +walUnlockExclusive testdocs/sqlite3.c /^static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){$/;" f file: +walUnlockShared testdocs/sqlite3.c /^static void walUnlockShared(Wal *pWal, int lockIdx){$/;" f file: +walWriteOneFrame testdocs/sqlite3.c /^static int walWriteOneFrame($/;" f file: +walWriteToLog testdocs/sqlite3.c /^static int walWriteToLog($/;" f file: +wal_autocheckpoint testdocs/sqlite3.c /^ int (*wal_autocheckpoint)(sqlite3*,int);$/;" m struct:sqlite3_api_routines file: +wal_checkpoint testdocs/sqlite3.c /^ int (*wal_checkpoint)(sqlite3*,const char*);$/;" m struct:sqlite3_api_routines file: +wal_checkpoint_v2 testdocs/sqlite3.c /^ int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);$/;" m struct:sqlite3_api_routines file: +wal_hook testdocs/sqlite3.c /^ void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);$/;" m struct:sqlite3_api_routines file: +walkExpr testdocs/sqlite3.c /^static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){$/;" f file: +walkerDepth testdocs/sqlite3.c /^ int walkerDepth; \/* Number of subqueries *\/$/;" m struct:Walker file: +wantToLock testdocs/sqlite3.c /^ int wantToLock; \/* Number of nested calls to sqlite3BtreeEnter() *\/$/;" m struct:Btree file: +wc testdocs/sqlite3.c /^ WhereClause wc; \/* Decomposition into subterms *\/$/;" m struct:WhereOrInfo file: +wc testdocs/sqlite3.c /^ WhereClause wc; \/* The subexpression broken out *\/$/;" m struct:WhereAndInfo file: +wctrlFlags testdocs/sqlite3.c /^ u16 wctrlFlags; \/* Flags originally passed to sqlite3WhereBegin() *\/$/;" m struct:WhereInfo file: +whereAndInfoDelete testdocs/sqlite3.c /^static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){$/;" f file: +whereClauseInsert testdocs/sqlite3.c /^static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){$/;" f file: +whereCombineDisjuncts testdocs/sqlite3.c /^static void whereCombineDisjuncts($/;" f file: +whereEqualScanEst testdocs/sqlite3.c /^static int whereEqualScanEst($/;" f file: +whereForeignKeys testdocs/sqlite3.c /^static char *whereForeignKeys(Parse *pParse, Table *pTab){$/;" f file: +whereInScanEst testdocs/sqlite3.c /^static int whereInScanEst($/;" f file: +whereIndexExprTrans testdocs/sqlite3.c /^static void whereIndexExprTrans($/;" f file: +whereIndexExprTransNode testdocs/sqlite3.c /^static int whereIndexExprTransNode(Walker *p, Expr *pExpr){$/;" f file: +whereInfoFree testdocs/sqlite3.c /^static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){$/;" f file: +whereKeyStats testdocs/sqlite3.c /^static int whereKeyStats($/;" f file: +whereLikeOptimizationStringFixup testdocs/sqlite3.c /^# define whereLikeOptimizationStringFixup(/;" d file: +whereLikeOptimizationStringFixup testdocs/sqlite3.c /^static void whereLikeOptimizationStringFixup($/;" f file: +whereLoopAddAll testdocs/sqlite3.c /^static int whereLoopAddAll(WhereLoopBuilder *pBuilder){$/;" f file: +whereLoopAddBtree testdocs/sqlite3.c /^static int whereLoopAddBtree($/;" f file: +whereLoopAddBtreeIndex testdocs/sqlite3.c /^static int whereLoopAddBtreeIndex($/;" f file: +whereLoopAddOr testdocs/sqlite3.c /^static int whereLoopAddOr($/;" f file: +whereLoopAddVirtual testdocs/sqlite3.c /^static int whereLoopAddVirtual($/;" f file: +whereLoopAddVirtualOne testdocs/sqlite3.c /^static int whereLoopAddVirtualOne($/;" f file: +whereLoopAdjustCost testdocs/sqlite3.c /^static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){$/;" f file: +whereLoopCheaperProperSubset testdocs/sqlite3.c /^static int whereLoopCheaperProperSubset($/;" f file: +whereLoopClear testdocs/sqlite3.c /^static void whereLoopClear(sqlite3 *db, WhereLoop *p){$/;" f file: +whereLoopClearUnion testdocs/sqlite3.c /^static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){$/;" f file: +whereLoopDelete testdocs/sqlite3.c /^static void whereLoopDelete(sqlite3 *db, WhereLoop *p){$/;" f file: +whereLoopFindLesser testdocs/sqlite3.c /^static WhereLoop **whereLoopFindLesser($/;" f file: +whereLoopInit testdocs/sqlite3.c /^static void whereLoopInit(WhereLoop *p){$/;" f file: +whereLoopInsert testdocs/sqlite3.c /^static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){$/;" f file: +whereLoopOutputAdjust testdocs/sqlite3.c /^static void whereLoopOutputAdjust($/;" f file: +whereLoopPrint testdocs/sqlite3.c /^static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){$/;" f file: +whereLoopResize testdocs/sqlite3.c /^static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){$/;" f file: +whereLoopXfer testdocs/sqlite3.c /^static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){$/;" f file: +whereNthSubterm testdocs/sqlite3.c /^static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){$/;" f file: +whereOrInfoDelete testdocs/sqlite3.c /^static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){$/;" f file: +whereOrInsert testdocs/sqlite3.c /^static int whereOrInsert($/;" f file: +whereOrMove testdocs/sqlite3.c /^static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){$/;" f file: +whereOrName testdocs/sqlite3.c /^static char *whereOrName(sqlite3 *db, char *zWhere, char *zConstant){$/;" f file: +wherePathName testdocs/sqlite3.c /^static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){$/;" f file: +wherePathSatisfiesOrderBy testdocs/sqlite3.c /^static i8 wherePathSatisfiesOrderBy($/;" f file: +wherePathSolver testdocs/sqlite3.c /^static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){$/;" f file: +whereRangeAdjust testdocs/sqlite3.c /^static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){$/;" f file: +whereRangeScanEst testdocs/sqlite3.c /^static int whereRangeScanEst($/;" f file: +whereRangeSkipScanEst testdocs/sqlite3.c /^static int whereRangeSkipScanEst($/;" f file: +whereRangeVectorLen testdocs/sqlite3.c /^static int whereRangeVectorLen($/;" f file: +whereScanInit testdocs/sqlite3.c /^static WhereTerm *whereScanInit($/;" f file: +whereScanNext testdocs/sqlite3.c /^static WhereTerm *whereScanNext(WhereScan *pScan){$/;" f file: +whereShortCut testdocs/sqlite3.c /^static int whereShortCut(WhereLoopBuilder *pBuilder){$/;" f file: +whereSortingCost testdocs/sqlite3.c /^static LogEst whereSortingCost($/;" f file: +whereTempTriggers testdocs/sqlite3.c /^static char *whereTempTriggers(Parse *pParse, Table *pTab){$/;" f file: +whereTermPrint testdocs/sqlite3.c /^static void whereTermPrint(WhereTerm *pTerm, int iTerm){$/;" f file: +whereUsablePartialIndex testdocs/sqlite3.c /^static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){$/;" f file: +winAccess testdocs/sqlite3.c /^static int winAccess($/;" f file: +winAppData testdocs/sqlite3.c /^static winVfsAppData winAppData = {$/;" v file: +winCheckReservedLock testdocs/sqlite3.c /^static int winCheckReservedLock(sqlite3_file *id, int *pResOut){$/;" f file: +winClose testdocs/sqlite3.c /^static int winClose(sqlite3_file *id){$/;" f file: +winConvertFromUtf8Filename testdocs/sqlite3.c /^static void *winConvertFromUtf8Filename(const char *zFilename){$/;" f file: +winConvertToUtf8Filename testdocs/sqlite3.c /^static char *winConvertToUtf8Filename(const void *zFilename){$/;" f file: +winCurrentTime testdocs/sqlite3.c /^static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){$/;" f file: +winCurrentTimeInt64 testdocs/sqlite3.c /^static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){$/;" f file: +winDelete testdocs/sqlite3.c /^static int winDelete($/;" f file: +winDeviceCharacteristics testdocs/sqlite3.c /^static int winDeviceCharacteristics(sqlite3_file *id){$/;" f file: +winDlClose testdocs/sqlite3.c /^ #define winDlClose /;" d file: +winDlClose testdocs/sqlite3.c /^static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){$/;" f file: +winDlError testdocs/sqlite3.c /^ #define winDlError /;" d file: +winDlError testdocs/sqlite3.c /^static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){$/;" f file: +winDlOpen testdocs/sqlite3.c /^ #define winDlOpen /;" d file: +winDlOpen testdocs/sqlite3.c /^static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){$/;" f file: +winDlSym testdocs/sqlite3.c /^ #define winDlSym /;" d file: +winDlSym testdocs/sqlite3.c /^static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){$/;" f file: +winFetch testdocs/sqlite3.c /^static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){$/;" f file: +winFile testdocs/sqlite3.c /^struct winFile {$/;" s file: +winFile testdocs/sqlite3.c /^typedef struct winFile winFile;$/;" t typeref:struct:winFile file: +winFileControl testdocs/sqlite3.c /^static int winFileControl(sqlite3_file *id, int op, void *pArg){$/;" f file: +winFileSize testdocs/sqlite3.c /^static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){$/;" f file: +winFullPathname testdocs/sqlite3.c /^static int winFullPathname($/;" f file: +winGetDirSep testdocs/sqlite3.c /^# define winGetDirSep(/;" d file: +winGetLastError testdocs/sqlite3.c /^static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){$/;" f file: +winGetLastErrorMsg testdocs/sqlite3.c /^static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){$/;" f file: +winGetReadLock testdocs/sqlite3.c /^static int winGetReadLock(winFile *pFile){$/;" f file: +winGetSystemCall testdocs/sqlite3.c /^static sqlite3_syscall_ptr winGetSystemCall($/;" f file: +winGetTempname testdocs/sqlite3.c /^static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){$/;" f file: +winIoMethod testdocs/sqlite3.c /^static const sqlite3_io_methods winIoMethod = {$/;" v file: +winIoNolockMethod testdocs/sqlite3.c /^static const sqlite3_io_methods winIoNolockMethod = {$/;" v file: +winIoerrCanRetry1 testdocs/sqlite3.c /^#define winIoerrCanRetry1(/;" d file: +winIoerrRetry testdocs/sqlite3.c /^static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;$/;" v file: +winIoerrRetryDelay testdocs/sqlite3.c /^static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;$/;" v file: +winIsDir testdocs/sqlite3.c /^static int winIsDir(const void *zConverted){$/;" f file: +winIsDirSep testdocs/sqlite3.c /^# define winIsDirSep(/;" d file: +winIsDriveLetterAndColon testdocs/sqlite3.c /^static BOOL winIsDriveLetterAndColon($/;" f file: +winIsVerbatimPathname testdocs/sqlite3.c /^static BOOL winIsVerbatimPathname($/;" f file: +winLock testdocs/sqlite3.c /^static int winLock(sqlite3_file *id, int locktype){$/;" f file: +winLockFile testdocs/sqlite3.c /^static BOOL winLockFile($/;" f file: +winLogError testdocs/sqlite3.c /^#define winLogError(/;" d file: +winLogErrorAtLine testdocs/sqlite3.c /^static int winLogErrorAtLine($/;" f file: +winLogIoerr testdocs/sqlite3.c /^static void winLogIoerr(int nRetry, int lineno){$/;" f file: +winMakeEndInDirSep testdocs/sqlite3.c /^static int winMakeEndInDirSep(int nBuf, char *zBuf){$/;" f file: +winMapfile testdocs/sqlite3.c /^static int winMapfile(winFile *pFd, sqlite3_int64 nByte){$/;" f file: +winMbcsToUnicode testdocs/sqlite3.c /^static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){$/;" f file: +winMbcsToUtf8 testdocs/sqlite3.c /^static char *winMbcsToUtf8(const char *zText, int useAnsi){$/;" f file: +winMemAssertMagic testdocs/sqlite3.c /^#define winMemAssertMagic(/;" d file: +winMemAssertMagic1 testdocs/sqlite3.c /^#define winMemAssertMagic1(/;" d file: +winMemAssertMagic2 testdocs/sqlite3.c /^#define winMemAssertMagic2(/;" d file: +winMemData testdocs/sqlite3.c /^struct winMemData {$/;" s file: +winMemData testdocs/sqlite3.c /^typedef struct winMemData winMemData;$/;" t typeref:struct:winMemData file: +winMemFree testdocs/sqlite3.c /^static void winMemFree(void *pPrior){$/;" f file: +winMemGetDataPtr testdocs/sqlite3.c /^#define winMemGetDataPtr(/;" d file: +winMemGetHeap testdocs/sqlite3.c /^#define winMemGetHeap(/;" d file: +winMemGetOwned testdocs/sqlite3.c /^#define winMemGetOwned(/;" d file: +winMemInit testdocs/sqlite3.c /^static int winMemInit(void *pAppData){$/;" f file: +winMemMalloc testdocs/sqlite3.c /^static void *winMemMalloc(int nBytes){$/;" f file: +winMemRealloc testdocs/sqlite3.c /^static void *winMemRealloc(void *pPrior, int nBytes){$/;" f file: +winMemRoundup testdocs/sqlite3.c /^static int winMemRoundup(int n){$/;" f file: +winMemShutdown testdocs/sqlite3.c /^static void winMemShutdown(void *pAppData){$/;" f file: +winMemSize testdocs/sqlite3.c /^static int winMemSize(void *p){$/;" f file: +winModeBit testdocs/sqlite3.c /^static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){$/;" f file: +winMutexAlloc testdocs/sqlite3.c /^static sqlite3_mutex *winMutexAlloc(int iType){$/;" f file: +winMutexEnd testdocs/sqlite3.c /^static int winMutexEnd(void){$/;" f file: +winMutexEnter testdocs/sqlite3.c /^static void winMutexEnter(sqlite3_mutex *p){$/;" f file: +winMutexFree testdocs/sqlite3.c /^static void winMutexFree(sqlite3_mutex *p){$/;" f file: +winMutexHeld testdocs/sqlite3.c /^static int winMutexHeld(sqlite3_mutex *p){$/;" f file: +winMutexInit testdocs/sqlite3.c /^static int winMutexInit(void){$/;" f file: +winMutexLeave testdocs/sqlite3.c /^static void winMutexLeave(sqlite3_mutex *p){$/;" f file: +winMutexNotheld testdocs/sqlite3.c /^static int winMutexNotheld(sqlite3_mutex *p){$/;" f file: +winMutexNotheld2 testdocs/sqlite3.c /^static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){$/;" f file: +winMutexTry testdocs/sqlite3.c /^static int winMutexTry(sqlite3_mutex *p){$/;" f file: +winMutex_isInit testdocs/sqlite3.c /^static int winMutex_isInit = 0;$/;" v file: +winMutex_isNt testdocs/sqlite3.c /^static int winMutex_isNt = -1; \/* <0 means "need to query" *\/$/;" v file: +winMutex_lock testdocs/sqlite3.c /^static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;$/;" v file: +winMutex_staticMutexes testdocs/sqlite3.c /^static sqlite3_mutex winMutex_staticMutexes[] = {$/;" v file: +winNextSystemCall testdocs/sqlite3.c /^static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){$/;" f file: +winNolockAppData testdocs/sqlite3.c /^static winVfsAppData winNolockAppData = {$/;" v file: +winNolockCheckReservedLock testdocs/sqlite3.c /^static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){$/;" f file: +winNolockLock testdocs/sqlite3.c /^static int winNolockLock(sqlite3_file *id, int locktype){$/;" f file: +winNolockUnlock testdocs/sqlite3.c /^static int winNolockUnlock(sqlite3_file *id, int locktype){$/;" f file: +winOpen testdocs/sqlite3.c /^static int winOpen($/;" f file: +winOpenSharedMemory testdocs/sqlite3.c /^static int winOpenSharedMemory(winFile *pDbFd){$/;" f file: +winRandomness testdocs/sqlite3.c /^static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){$/;" f file: +winRead testdocs/sqlite3.c /^static int winRead($/;" f file: +winRetryIoerr testdocs/sqlite3.c /^static int winRetryIoerr(int *pnRetry, DWORD *pError){$/;" f file: +winSectorSize testdocs/sqlite3.c /^static int winSectorSize(sqlite3_file *id){$/;" f file: +winSeekFile testdocs/sqlite3.c /^static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){$/;" f file: +winSetSystemCall testdocs/sqlite3.c /^static int winSetSystemCall($/;" f file: +winShm testdocs/sqlite3.c /^struct winShm {$/;" s file: +winShm testdocs/sqlite3.c /^typedef struct winShm winShm; \/* A connection to shared-memory *\/$/;" t typeref:struct:winShm file: +winShmBarrier testdocs/sqlite3.c /^# define winShmBarrier /;" d file: +winShmBarrier testdocs/sqlite3.c /^static void winShmBarrier($/;" f file: +winShmEnterMutex testdocs/sqlite3.c /^static void winShmEnterMutex(void){$/;" f file: +winShmLeaveMutex testdocs/sqlite3.c /^static void winShmLeaveMutex(void){$/;" f file: +winShmLock testdocs/sqlite3.c /^# define winShmLock /;" d file: +winShmLock testdocs/sqlite3.c /^static int winShmLock($/;" f file: +winShmMap testdocs/sqlite3.c /^# define winShmMap /;" d file: +winShmMap testdocs/sqlite3.c /^static int winShmMap($/;" f file: +winShmMutexHeld testdocs/sqlite3.c /^static int winShmMutexHeld(void) {$/;" f file: +winShmNode testdocs/sqlite3.c /^struct winShmNode {$/;" s file: +winShmNode testdocs/sqlite3.c /^typedef struct winShmNode winShmNode; \/* A region of shared-memory *\/$/;" t typeref:struct:winShmNode file: +winShmNodeList testdocs/sqlite3.c /^static winShmNode *winShmNodeList = 0;$/;" v file: +winShmPurge testdocs/sqlite3.c /^static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){$/;" f file: +winShmSystemLock testdocs/sqlite3.c /^static int winShmSystemLock($/;" f file: +winShmUnmap testdocs/sqlite3.c /^# define winShmUnmap /;" d file: +winShmUnmap testdocs/sqlite3.c /^static int winShmUnmap($/;" f file: +winSleep testdocs/sqlite3.c /^static int winSleep(sqlite3_vfs *pVfs, int microsec){$/;" f file: +winSync testdocs/sqlite3.c /^static int winSync(sqlite3_file *id, int flags){$/;" f file: +winSysInfo testdocs/sqlite3.c /^static SYSTEM_INFO winSysInfo;$/;" v file: +winTruncate testdocs/sqlite3.c /^static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){$/;" f file: +winUnfetch testdocs/sqlite3.c /^static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){$/;" f file: +winUnicodeToMbcs testdocs/sqlite3.c /^static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){$/;" f file: +winUnicodeToUtf8 testdocs/sqlite3.c /^static char *winUnicodeToUtf8(LPCWSTR zWideText){$/;" f file: +winUnlock testdocs/sqlite3.c /^static int winUnlock(sqlite3_file *id, int locktype){$/;" f file: +winUnlockFile testdocs/sqlite3.c /^static BOOL winUnlockFile($/;" f file: +winUnlockReadLock testdocs/sqlite3.c /^static int winUnlockReadLock(winFile *pFile){$/;" f file: +winUnmapfile testdocs/sqlite3.c /^static int winUnmapfile(winFile *pFile){$/;" f file: +winUtf8ToMbcs testdocs/sqlite3.c /^static char *winUtf8ToMbcs(const char *zText, int useAnsi){$/;" f file: +winUtf8ToUnicode testdocs/sqlite3.c /^static LPWSTR winUtf8ToUnicode(const char *zText){$/;" f file: +winVfsAppData testdocs/sqlite3.c /^struct winVfsAppData {$/;" s file: +winVfsAppData testdocs/sqlite3.c /^typedef struct winVfsAppData winVfsAppData;$/;" t typeref:struct:winVfsAppData file: +winWrite testdocs/sqlite3.c /^static int winWrite($/;" f file: +win_mem_data testdocs/sqlite3.c /^static struct winMemData win_mem_data = {$/;" v typeref:struct:winMemData file: +win_syscall testdocs/sqlite3.c /^static struct win_syscall {$/;" s file: +winceCreateLock testdocs/sqlite3.c /^static int winceCreateLock(const char *zFilename, winFile *pFile){$/;" f file: +winceDestroyLock testdocs/sqlite3.c /^static void winceDestroyLock(winFile *pFile){$/;" f file: +winceLock testdocs/sqlite3.c /^typedef struct winceLock {$/;" s file: +winceLock testdocs/sqlite3.c /^} winceLock;$/;" t typeref:struct:winceLock file: +winceLockFile testdocs/sqlite3.c /^static BOOL winceLockFile($/;" f file: +winceMutexAcquire testdocs/sqlite3.c /^static void winceMutexAcquire(HANDLE h){$/;" f file: +winceMutexRelease testdocs/sqlite3.c /^#define winceMutexRelease(/;" d file: +winceUnlockFile testdocs/sqlite3.c /^static BOOL winceUnlockFile($/;" f file: +windll testdocs/waf /^ from ctypes import windll$/;" i +withDup testdocs/sqlite3.c /^# define withDup(/;" d file: +withDup testdocs/sqlite3.c /^static With *withDup(sqlite3 *db, With *p){$/;" f file: +withExpand testdocs/sqlite3.c /^static int withExpand($/;" f file: +wrFlag testdocs/sqlite3.c /^ u8 wrFlag; \/* The wrFlag argument to sqlite3BtreeCursor() *\/$/;" m struct:VdbeCursor file: +write32bits testdocs/sqlite3.c /^static int write32bits(sqlite3_file *fd, i64 offset, u32 val){$/;" f file: +writeCoord testdocs/sqlite3.c /^static int writeCoord(u8 *p, RtreeCoord *pCoord){$/;" f file: +writeInt16 testdocs/sqlite3.c /^static void writeInt16(u8 *p, int i){$/;" f file: +writeInt64 testdocs/sqlite3.c /^static int writeInt64(u8 *p, i64 i){$/;" f file: +writeJournalHdr testdocs/sqlite3.c /^static int writeJournalHdr(Pager *pPager){$/;" f file: +writeLock testdocs/sqlite3.c /^ u8 writeLock; \/* True if in a write transaction *\/$/;" m struct:Wal file: +writeMask testdocs/sqlite3.c /^ yDbMask writeMask; \/* Start a write transaction on these databases *\/$/;" m struct:Parse file: +writeMasterJournal testdocs/sqlite3.c /^static int writeMasterJournal(Pager *pPager, const char *zMaster){$/;" f file: +writer testdocs/sqlite3.c /^ Fts5PageWriter writer; \/* PageWriter object *\/$/;" m struct:Fts5SegWriter file: +writer testdocs/sqlite3.c /^ Fts5PoslistWriter writer; \/* Writer context *\/$/;" m struct:Fts5NearTrimmer file: +writer testdocs/sqlite3.c /^ Fts5PoslistWriter writer;$/;" m struct:Fts5PoslistPopulator file: +writer testdocs/sqlite3.c /^ Fts5SegWriter writer;$/;" m struct:Fts5FlushCtx file: +wsFlags testdocs/sqlite3.c /^ u32 wsFlags; \/* WHERE_* flags describing the plan *\/$/;" m struct:WhereLoop file: +wsdAutoext testdocs/sqlite3.c /^# define wsdAutoext /;" d file: +wsdAutoextInit testdocs/sqlite3.c /^# define wsdAutoextInit /;" d file: +wsdAutoextInit testdocs/sqlite3.c /^# define wsdAutoextInit$/;" d file: +wsdHooks testdocs/sqlite3.c /^# define wsdHooks /;" d file: +wsdHooksInit testdocs/sqlite3.c /^# define wsdHooksInit /;" d file: +wsdHooksInit testdocs/sqlite3.c /^# define wsdHooksInit$/;" d file: +wsdPrng testdocs/sqlite3.c /^# define wsdPrng /;" d file: +wsdStat testdocs/sqlite3.c /^# define wsdStat /;" d file: +wsdStatInit testdocs/sqlite3.c /^# define wsdStatInit /;" d file: +wsdStatInit testdocs/sqlite3.c /^# define wsdStatInit$/;" d file: +wtFlags testdocs/sqlite3.c /^ u16 wtFlags; \/* TERM_xxx bit flags. See below *\/$/;" m struct:WhereTerm file: +x testdocs/sqlite3.c /^ } x;$/;" m union:ExprList::ExprList_item::__anon12 typeref:struct:ExprList::ExprList_item::__anon12::__anon13 file: +x testdocs/sqlite3.c /^ fts5_tokenizer x; \/* Tokenizer functions *\/$/;" m struct:Fts5TokenizerModule file: +x testdocs/sqlite3.c /^ } x;$/;" m struct:Expr typeref:union:Expr::__anon11 file: +xAccess testdocs/sqlite3.c /^ int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);$/;" m struct:sqlite3_vfs file: +xAdvance testdocs/sqlite3.c /^ int (*xAdvance)(BtCursor *, int *);$/;" m union:VdbeOp::p4union file: +xAuth testdocs/sqlite3.c /^ sqlite3_xauth xAuth; \/* Access authorization function *\/$/;" m struct:sqlite3 file: +xBacktrace testdocs/sqlite3.c /^ void (*xBacktrace)(int, int, void **);$/;" m struct:__anon20 file: +xBegin testdocs/sqlite3.c /^ int (*xBegin)(sqlite3_vtab *pVTab);$/;" m struct:sqlite3_module file: +xBenignBegin testdocs/sqlite3.c /^ void (*xBenignBegin)(void);$/;" m struct:BenignMallocHooks file: +xBenignEnd testdocs/sqlite3.c /^ void (*xBenignEnd)(void);$/;" m struct:BenignMallocHooks file: +xBestIndex testdocs/sqlite3.c /^ int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);$/;" m struct:sqlite3_module file: +xBusyHandler testdocs/sqlite3.c /^ int (*xBusyHandler)(void*); \/* Function to call when busy *\/$/;" m struct:Pager file: +xCachesize testdocs/sqlite3.c /^ void (*xCachesize)(sqlite3_pcache*, int nCachesize);$/;" m struct:sqlite3_pcache_methods file: +xCachesize testdocs/sqlite3.c /^ void (*xCachesize)(sqlite3_pcache*, int nCachesize);$/;" m struct:sqlite3_pcache_methods2 file: +xCellSize testdocs/sqlite3.c /^ u16 (*xCellSize)(MemPage*,u8*); \/* cellSizePtr method *\/$/;" m struct:MemPage file: +xCheckReservedLock testdocs/sqlite3.c /^ int (*xCheckReservedLock)(sqlite3_file*, int *pResOut);$/;" m struct:sqlite3_io_methods file: +xClose testdocs/sqlite3.c /^ int (*xClose)(sqlite3_file*);$/;" m struct:sqlite3_io_methods file: +xClose testdocs/sqlite3.c /^ int (*xClose)(sqlite3_tokenizer_cursor *pCursor);$/;" m struct:sqlite3_tokenizer_module file: +xClose testdocs/sqlite3.c /^ int (*xClose)(sqlite3_vtab_cursor*);$/;" m struct:sqlite3_module file: +xCmp testdocs/sqlite3.c /^ int (*xCmp)(void*,int, const void*, int, const void*);$/;" m struct:CollSeq file: +xCodec testdocs/sqlite3.c /^ void *(*xCodec)(void*,void*,Pgno,int); \/* Routine for en\/decoding data *\/$/;" m struct:Pager file: +xCodecFree testdocs/sqlite3.c /^ void (*xCodecFree)(void*); \/* Destructor for the codec *\/$/;" m struct:Pager file: +xCodecSizeChng testdocs/sqlite3.c /^ void (*xCodecSizeChng)(void*,int,int); \/* Notify of page size changes *\/$/;" m struct:Pager file: +xCollNeeded testdocs/sqlite3.c /^ void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);$/;" m struct:sqlite3 file: +xCollNeeded16 testdocs/sqlite3.c /^ void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);$/;" m struct:sqlite3 file: +xColumn testdocs/sqlite3.c /^ int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);$/;" m struct:sqlite3_module file: +xColumnCount testdocs/sqlite3.c /^ int (*xColumnCount)(Fts5Context*);$/;" m struct:Fts5ExtensionApi file: +xColumnSize testdocs/sqlite3.c /^ int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);$/;" m struct:Fts5ExtensionApi file: +xColumnText testdocs/sqlite3.c /^ int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);$/;" m struct:Fts5ExtensionApi file: +xColumnTotalSize testdocs/sqlite3.c /^ int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);$/;" m struct:Fts5ExtensionApi file: +xCommit testdocs/sqlite3.c /^ int (*xCommit)(sqlite3_vtab *pVTab);$/;" m struct:sqlite3_module file: +xCommitCallback testdocs/sqlite3.c /^ int (*xCommitCallback)(void*); \/* Invoked at every commit. *\/$/;" m struct:sqlite3 file: +xCompare testdocs/sqlite3.c /^ SorterCompare xCompare; \/* Compare function to use *\/$/;" m struct:SortSubtask file: +xCond testdocs/sqlite3.c /^ int (*xCond)(char *zStem, int nStem);$/;" m struct:PorterRule file: +xConnect testdocs/sqlite3.c /^ int (*xConnect)(sqlite3*, void *pAux,$/;" m struct:sqlite3_module file: +xCount testdocs/sqlite3.c /^ int (*xCount)(void*);$/;" m struct:SessionHook file: +xCreate testdocs/sqlite3.c /^ int (*xCreate)($/;" m struct:sqlite3_tokenizer_module file: +xCreate testdocs/sqlite3.c /^ int (*xCreate)(sqlite3*, void *pAux,$/;" m struct:sqlite3_module file: +xCreate testdocs/sqlite3.c /^ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);$/;" m struct:fts5_tokenizer file: +xCreate testdocs/sqlite3.c /^ sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable);$/;" m struct:sqlite3_pcache_methods file: +xCreate testdocs/sqlite3.c /^ sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable);$/;" m struct:sqlite3_pcache_methods2 file: +xCreateFunction testdocs/sqlite3.c /^ int (*xCreateFunction)($/;" m struct:fts5_api file: +xCreateTokenizer testdocs/sqlite3.c /^ int (*xCreateTokenizer)($/;" m struct:fts5_api file: +xCurrentTime testdocs/sqlite3.c /^ int (*xCurrentTime)(sqlite3_vfs*, double*);$/;" m struct:sqlite3_vfs file: +xCurrentTimeInt64 testdocs/sqlite3.c /^ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);$/;" m struct:sqlite3_vfs file: +xDel testdocs/sqlite3.c /^ void (*xDel)(void*); \/* Destructor for pUser *\/$/;" m struct:CollSeq file: +xDel testdocs/sqlite3.c /^ void (*xDel)(void*);\/* Destructor for Mem.z - only valid if MEM_Dyn *\/$/;" m struct:sqlite3_value file: +xDelUser testdocs/sqlite3.c /^ void (*xDelUser)(void *); \/* Called by SQLite to clean up pUser *\/$/;" m struct:sqlite3_rtree_geometry file: +xDelUser testdocs/sqlite3.c /^ void (*xDelUser)(void*); \/* function to free pUser *\/$/;" m struct:sqlite3_rtree_query_info file: +xDelete testdocs/sqlite3.c /^ int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);$/;" m struct:sqlite3_vfs file: +xDelete testdocs/sqlite3.c /^ void (*xDelete)(Fts5Tokenizer*);$/;" m struct:fts5_tokenizer file: +xDelete testdocs/sqlite3.c /^ void(*xDelete)(void*); \/* Destructor *\/$/;" m struct:Fts5Auxdata file: +xDeleteAux testdocs/sqlite3.c /^ void (*xDeleteAux)(void*); \/* Destructor for the aux data *\/$/;" m struct:AuxData file: +xDepth testdocs/sqlite3.c /^ int (*xDepth)(void*);$/;" m struct:SessionHook file: +xDestroy testdocs/sqlite3.c /^ int (*xDestroy)(sqlite3_tokenizer *pTokenizer);$/;" m struct:sqlite3_tokenizer_module file: +xDestroy testdocs/sqlite3.c /^ int (*xDestroy)(sqlite3_vtab *pVTab);$/;" m struct:sqlite3_module file: +xDestroy testdocs/sqlite3.c /^ void (*xDestroy)(sqlite3_pcache*);$/;" m struct:sqlite3_pcache_methods file: +xDestroy testdocs/sqlite3.c /^ void (*xDestroy)(sqlite3_pcache*);$/;" m struct:sqlite3_pcache_methods2 file: +xDestroy testdocs/sqlite3.c /^ void (*xDestroy)(void *); \/* Module destructor function *\/$/;" m struct:Module file: +xDestroy testdocs/sqlite3.c /^ void (*xDestroy)(void *);$/;" m struct:FuncDestructor file: +xDestroy testdocs/sqlite3.c /^ void (*xDestroy)(void*); \/* Destructor function *\/$/;" m struct:Fts5Auxiliary file: +xDestroy testdocs/sqlite3.c /^ void (*xDestroy)(void*); \/* Destructor function *\/$/;" m struct:Fts5TokenizerModule file: +xDestructor testdocs/sqlite3.c /^ void (*xDestructor)(void*);$/;" m struct:RtreeGeomCallback file: +xDeviceCharacteristics testdocs/sqlite3.c /^ int (*xDeviceCharacteristics)(sqlite3_file*);$/;" m struct:sqlite3_io_methods file: +xDisconnect testdocs/sqlite3.c /^ int (*xDisconnect)(sqlite3_vtab *pVTab);$/;" m struct:sqlite3_module file: +xDlClose testdocs/sqlite3.c /^ void (*xDlClose)(sqlite3_vfs*, void*);$/;" m struct:sqlite3_vfs file: +xDlError testdocs/sqlite3.c /^ void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);$/;" m struct:sqlite3_vfs file: +xDlOpen testdocs/sqlite3.c /^ void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);$/;" m struct:sqlite3_vfs file: +xEof testdocs/sqlite3.c /^ int (*xEof)(sqlite3_vtab_cursor*);$/;" m struct:sqlite3_module file: +xExprCallback testdocs/sqlite3.c /^ int (*xExprCallback)(Walker*, Expr*); \/* Callback for expressions *\/$/;" m struct:Walker file: +xFetch testdocs/sqlite3.c /^ int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);$/;" m struct:sqlite3_io_methods file: +xFetch testdocs/sqlite3.c /^ sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);$/;" m struct:sqlite3_pcache_methods2 file: +xFetch testdocs/sqlite3.c /^ void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);$/;" m struct:sqlite3_pcache_methods file: +xFileControl testdocs/sqlite3.c /^ int (*xFileControl)(sqlite3_file*, int op, void *pArg);$/;" m struct:sqlite3_io_methods file: +xFileSize testdocs/sqlite3.c /^ int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize);$/;" m struct:sqlite3_io_methods file: +xFilter testdocs/sqlite3.c /^ int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,$/;" m struct:sqlite3_module file: +xFinalize testdocs/sqlite3.c /^ void (*xFinalize)(sqlite3_context*); \/* Agg finalizer *\/$/;" m struct:FuncDef file: +xFindFunction testdocs/sqlite3.c /^ int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,$/;" m struct:sqlite3_module file: +xFindTokenizer testdocs/sqlite3.c /^ int (*xFindTokenizer)($/;" m struct:fts5_api file: +xFree testdocs/sqlite3.c /^ void (*xFree)(void*); \/* Free a prior allocation *\/$/;" m struct:sqlite3_mem_methods file: +xFree testdocs/sqlite3.c /^static void xFree(void *p){$/;" f file: +xFreeSchema testdocs/sqlite3.c /^ void (*xFreeSchema)(void*); \/* Destructor for BtShared.pSchema *\/$/;" m struct:BtShared file: +xFullPathname testdocs/sqlite3.c /^ int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);$/;" m struct:sqlite3_vfs file: +xFunc testdocs/sqlite3.c /^ fts5_extension_function xFunc; \/* Callback function *\/$/;" m struct:Fts5Auxiliary file: +xFunc testdocs/sqlite3.c /^ int (*xFunc)(void *,int); \/* The busy callback *\/$/;" m struct:BusyHandler file: +xGeom testdocs/sqlite3.c /^ int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*);$/;" m union:RtreeConstraint::__anon36 file: +xGeom testdocs/sqlite3.c /^ int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);$/;" m struct:RtreeGeomCallback file: +xGet testdocs/sqlite3.c /^ int (*xGet)(Pager*,Pgno,DbPage**,int); \/* Routine to fetch a patch *\/$/;" m struct:Pager file: +xGetAuxdata testdocs/sqlite3.c /^ void *(*xGetAuxdata)(Fts5Context*, int bClear);$/;" m struct:Fts5ExtensionApi file: +xGetLastError testdocs/sqlite3.c /^ int (*xGetLastError)(sqlite3_vfs*, int, char *);$/;" m struct:sqlite3_vfs file: +xGetSystemCall testdocs/sqlite3.c /^ sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);$/;" m struct:sqlite3_vfs file: +xInit testdocs/sqlite3.c /^ int (*xInit)(void*); \/* Initialize the memory allocator *\/$/;" m struct:sqlite3_mem_methods file: +xInit testdocs/sqlite3.c /^ int (*xInit)(void*);$/;" m struct:sqlite3_pcache_methods file: +xInit testdocs/sqlite3.c /^ int (*xInit)(void*);$/;" m struct:sqlite3_pcache_methods2 file: +xInput testdocs/sqlite3.c /^ int (*xInput)(void*, void*, int*); \/* Input stream call (or NULL) *\/$/;" m struct:SessionInput file: +xInst testdocs/sqlite3.c /^ int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);$/;" m struct:Fts5ExtensionApi file: +xInstCount testdocs/sqlite3.c /^ int (*xInstCount)(Fts5Context*, int *pnInst);$/;" m struct:Fts5ExtensionApi file: +xLanguageid testdocs/sqlite3.c /^ int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);$/;" m struct:sqlite3_tokenizer_module file: +xLock testdocs/sqlite3.c /^ int (*xLock)(sqlite3_file*, int);$/;" m struct:sqlite3_io_methods file: +xLog testdocs/sqlite3.c /^ void (*xLog)(void*,int,const char*); \/* Function for logging *\/$/;" m struct:Sqlite3Config file: +xMalloc testdocs/sqlite3.c /^ void *(*xMalloc)(int); \/* Memory allocation function *\/$/;" m struct:sqlite3_mem_methods file: +xMutexAlloc testdocs/sqlite3.c /^ sqlite3_mutex *(*xMutexAlloc)(int);$/;" m struct:sqlite3_mutex_methods file: +xMutexEnd testdocs/sqlite3.c /^ int (*xMutexEnd)(void);$/;" m struct:sqlite3_mutex_methods file: +xMutexEnter testdocs/sqlite3.c /^ void (*xMutexEnter)(sqlite3_mutex *);$/;" m struct:sqlite3_mutex_methods file: +xMutexFree testdocs/sqlite3.c /^ void (*xMutexFree)(sqlite3_mutex *);$/;" m struct:sqlite3_mutex_methods file: +xMutexHeld testdocs/sqlite3.c /^ int (*xMutexHeld)(sqlite3_mutex *);$/;" m struct:sqlite3_mutex_methods file: +xMutexInit testdocs/sqlite3.c /^ int (*xMutexInit)(void);$/;" m struct:sqlite3_mutex_methods file: +xMutexLeave testdocs/sqlite3.c /^ void (*xMutexLeave)(sqlite3_mutex *);$/;" m struct:sqlite3_mutex_methods file: +xMutexNotheld testdocs/sqlite3.c /^ int (*xMutexNotheld)(sqlite3_mutex *);$/;" m struct:sqlite3_mutex_methods file: +xMutexTry testdocs/sqlite3.c /^ int (*xMutexTry)(sqlite3_mutex *);$/;" m struct:sqlite3_mutex_methods file: +xNew testdocs/sqlite3.c /^ int (*xNew)(void*,int,sqlite3_value**);$/;" m struct:SessionHook file: +xNext testdocs/sqlite3.c /^ int (*xNext)($/;" m struct:sqlite3_tokenizer_module file: +xNext testdocs/sqlite3.c /^ int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);$/;" m struct:Fts5ExprNode file: +xNext testdocs/sqlite3.c /^ int (*xNext)(sqlite3_vtab_cursor*);$/;" m struct:sqlite3_module file: +xNext testdocs/sqlite3.c /^ void (*xNext)(Fts5Index*, Fts5SegIter*, int*);$/;" m struct:Fts5SegIter file: +xNextSystemCall testdocs/sqlite3.c /^ const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);$/;" m struct:sqlite3_vfs file: +xOld testdocs/sqlite3.c /^ int (*xOld)(void*,int,sqlite3_value**);$/;" m struct:SessionHook file: +xOpen testdocs/sqlite3.c /^ int (*xOpen)($/;" m struct:sqlite3_tokenizer_module file: +xOpen testdocs/sqlite3.c /^ int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,$/;" m struct:sqlite3_vfs file: +xOpen testdocs/sqlite3.c /^ int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);$/;" m struct:sqlite3_module file: +xPagecount testdocs/sqlite3.c /^ int (*xPagecount)(sqlite3_pcache*);$/;" m struct:sqlite3_pcache_methods file: +xPagecount testdocs/sqlite3.c /^ int (*xPagecount)(sqlite3_pcache*);$/;" m struct:sqlite3_pcache_methods2 file: +xParseCell testdocs/sqlite3.c /^ void (*xParseCell)(MemPage*,u8*,CellInfo*); \/* btreeParseCell method *\/$/;" m struct:MemPage file: +xPhraseCount testdocs/sqlite3.c /^ int (*xPhraseCount)(Fts5Context*);$/;" m struct:Fts5ExtensionApi file: +xPhraseFirst testdocs/sqlite3.c /^ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);$/;" m struct:Fts5ExtensionApi file: +xPhraseFirstColumn testdocs/sqlite3.c /^ int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);$/;" m struct:Fts5ExtensionApi file: +xPhraseNext testdocs/sqlite3.c /^ void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);$/;" m struct:Fts5ExtensionApi file: +xPhraseNextColumn testdocs/sqlite3.c /^ void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);$/;" m struct:Fts5ExtensionApi file: +xPhraseSize testdocs/sqlite3.c /^ int (*xPhraseSize)(Fts5Context*, int iPhrase);$/;" m struct:Fts5ExtensionApi file: +xPreUpdate testdocs/sqlite3.c /^static void xPreUpdate($/;" f file: +xPreUpdateCallback testdocs/sqlite3.c /^ void (*xPreUpdateCallback)( \/* Registered using sqlite3_preupdate_hook() *\/$/;" m struct:sqlite3 file: +xProfile testdocs/sqlite3.c /^ void (*xProfile)(void*,const char*,u64); \/* Profiling function *\/$/;" m struct:sqlite3 file: +xProgress testdocs/sqlite3.c /^ int (*xProgress)(void *); \/* The progress callback *\/$/;" m struct:sqlite3 file: +xQueryFunc testdocs/sqlite3.c /^ int (*xQueryFunc)(sqlite3_rtree_query_info*);$/;" m union:RtreeConstraint::__anon36 file: +xQueryFunc testdocs/sqlite3.c /^ int (*xQueryFunc)(sqlite3_rtree_query_info*);$/;" m struct:RtreeGeomCallback file: +xQueryPhrase testdocs/sqlite3.c /^ int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,$/;" m struct:Fts5ExtensionApi file: +xRandomness testdocs/sqlite3.c /^ int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);$/;" m struct:sqlite3_vfs file: +xRead testdocs/sqlite3.c /^ int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);$/;" m struct:sqlite3_io_methods file: +xRealloc testdocs/sqlite3.c /^ void *(*xRealloc)(void*,int); \/* Resize an allocation *\/$/;" m struct:sqlite3_mem_methods file: +xReiniter testdocs/sqlite3.c /^ void (*xReiniter)(DbPage*); \/* Call this routine when reloading pages *\/$/;" m struct:Pager file: +xRekey testdocs/sqlite3.c /^ void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,$/;" m struct:sqlite3_pcache_methods2 file: +xRekey testdocs/sqlite3.c /^ void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey);$/;" m struct:sqlite3_pcache_methods file: +xRelease testdocs/sqlite3.c /^ int (*xRelease)(sqlite3_vtab *pVTab, int);$/;" m struct:sqlite3_module file: +xRename testdocs/sqlite3.c /^ int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);$/;" m struct:sqlite3_module file: +xRollback testdocs/sqlite3.c /^ int (*xRollback)(sqlite3_vtab *pVTab);$/;" m struct:sqlite3_module file: +xRollbackCallback testdocs/sqlite3.c /^ void (*xRollbackCallback)(void*); \/* Invoked at every commit. *\/$/;" m struct:sqlite3 file: +xRollbackTo testdocs/sqlite3.c /^ int (*xRollbackTo)(sqlite3_vtab *pVTab, int);$/;" m struct:sqlite3_module file: +xRoundup testdocs/sqlite3.c /^ int (*xRoundup)(int); \/* Round up request size to allocation size *\/$/;" m struct:sqlite3_mem_methods file: +xRowCount testdocs/sqlite3.c /^ int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);$/;" m struct:Fts5ExtensionApi file: +xRowid testdocs/sqlite3.c /^ int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);$/;" m struct:sqlite3_module file: +xRowid testdocs/sqlite3.c /^ sqlite3_int64 (*xRowid)(Fts5Context*);$/;" m struct:Fts5ExtensionApi file: +xSFunc testdocs/sqlite3.c /^ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); \/* func or agg-step *\/$/;" m struct:FuncDef file: +xSavepoint testdocs/sqlite3.c /^ int (*xSavepoint)(sqlite3_vtab *pVTab, int);$/;" m struct:sqlite3_module file: +xSectorSize testdocs/sqlite3.c /^ int (*xSectorSize)(sqlite3_file*);$/;" m struct:sqlite3_io_methods file: +xSelectCallback testdocs/sqlite3.c /^ int (*xSelectCallback)(Walker*,Select*); \/* Callback for SELECTs *\/$/;" m struct:Walker file: +xSelectCallback2 testdocs/sqlite3.c /^ void (*xSelectCallback2)(Walker*,Select*);\/* Second callback for SELECTs *\/$/;" m struct:Walker file: +xSetAuxdata testdocs/sqlite3.c /^ int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));$/;" m struct:Fts5ExtensionApi file: +xSetOutputs testdocs/sqlite3.c /^ void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*);$/;" m struct:Fts5Iter file: +xSetSystemCall testdocs/sqlite3.c /^ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);$/;" m struct:sqlite3_vfs file: +xShmBarrier testdocs/sqlite3.c /^ void (*xShmBarrier)(sqlite3_file*);$/;" m struct:sqlite3_io_methods file: +xShmLock testdocs/sqlite3.c /^ int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);$/;" m struct:sqlite3_io_methods file: +xShmMap testdocs/sqlite3.c /^ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**);$/;" m struct:sqlite3_io_methods file: +xShmUnmap testdocs/sqlite3.c /^ int (*xShmUnmap)(sqlite3_file*, int deleteFlag);$/;" m struct:sqlite3_io_methods file: +xShrink testdocs/sqlite3.c /^ void (*xShrink)(sqlite3_pcache*);$/;" m struct:sqlite3_pcache_methods2 file: +xShutdown testdocs/sqlite3.c /^ void (*xShutdown)(void*); \/* Deinitialize the memory allocator *\/$/;" m struct:sqlite3_mem_methods file: +xShutdown testdocs/sqlite3.c /^ void (*xShutdown)(void*);$/;" m struct:sqlite3_pcache_methods file: +xShutdown testdocs/sqlite3.c /^ void (*xShutdown)(void*);$/;" m struct:sqlite3_pcache_methods2 file: +xSize testdocs/sqlite3.c /^ int (*xSize)(void*); \/* Return the size of an allocation *\/$/;" m struct:sqlite3_mem_methods file: +xSleep testdocs/sqlite3.c /^ int (*xSleep)(sqlite3_vfs*, int microseconds);$/;" m struct:sqlite3_vfs file: +xSqllog testdocs/sqlite3.c /^ void(*xSqllog)(void*,sqlite3*,const char*, int);$/;" m struct:Sqlite3Config file: +xStress testdocs/sqlite3.c /^ int (*xStress)(void*,PgHdr*); \/* Call to try make a page clean *\/$/;" m struct:PCache file: +xSync testdocs/sqlite3.c /^ int (*xSync)(sqlite3_file*, int flags);$/;" m struct:sqlite3_io_methods file: +xSync testdocs/sqlite3.c /^ int (*xSync)(sqlite3_vtab *pVTab);$/;" m struct:sqlite3_module file: +xTableFilter testdocs/sqlite3.c /^ int (*xTableFilter)(void *pCtx, const char *zTab);$/;" m struct:sqlite3_session file: +xTask testdocs/sqlite3.c /^ void *(*xTask)(void*); \/* The thread routine *\/$/;" m struct:SQLiteThread file: +xTask testdocs/sqlite3.c /^ void *(*xTask)(void*); \/* The routine to run as a thread *\/$/;" m struct:SQLiteThread file: +xTestCallback testdocs/sqlite3.c /^ int (*xTestCallback)(int); \/* Invoked by sqlite3FaultSim() *\/$/;" m struct:Sqlite3Config file: +xToken testdocs/sqlite3.c /^ int (*xToken)(void*, int, const char*, int, int, int);$/;" m struct:PorterContext file: +xTokenize testdocs/sqlite3.c /^ int (*xTokenize)(Fts5Context*,$/;" m struct:Fts5ExtensionApi file: +xTokenize testdocs/sqlite3.c /^ int (*xTokenize)(Fts5Tokenizer*,$/;" m struct:fts5_tokenizer file: +xTrace testdocs/sqlite3.c /^ int (*xTrace)(u32,void*,void*,void*); \/* Trace function *\/$/;" m struct:sqlite3 file: +xTruncate testdocs/sqlite3.c /^ int (*xTruncate)(sqlite3_file*, sqlite3_int64 size);$/;" m struct:sqlite3_io_methods file: +xTruncate testdocs/sqlite3.c /^ void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);$/;" m struct:sqlite3_pcache_methods file: +xTruncate testdocs/sqlite3.c /^ void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);$/;" m struct:sqlite3_pcache_methods2 file: +xUnfetch testdocs/sqlite3.c /^ int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);$/;" m struct:sqlite3_io_methods file: +xUnlock testdocs/sqlite3.c /^ int (*xUnlock)(sqlite3_file*, int);$/;" m struct:sqlite3_io_methods file: +xUnlockNotify testdocs/sqlite3.c /^ void (*xUnlockNotify)(void **, int); \/* Unlock notify callback *\/$/;" m struct:sqlite3 file: +xUnpin testdocs/sqlite3.c /^ void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);$/;" m struct:sqlite3_pcache_methods2 file: +xUnpin testdocs/sqlite3.c /^ void (*xUnpin)(sqlite3_pcache*, void*, int discard);$/;" m struct:sqlite3_pcache_methods file: +xUpdate testdocs/sqlite3.c /^ int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);$/;" m struct:sqlite3_module file: +xUpdateCallback testdocs/sqlite3.c /^ void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);$/;" m struct:sqlite3 file: +xUserData testdocs/sqlite3.c /^ void *(*xUserData)(Fts5Context*);$/;" m struct:Fts5ExtensionApi file: +xVdbeBranch testdocs/sqlite3.c /^ void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); \/* Callback *\/$/;" m struct:Sqlite3Config file: +xWalCallback testdocs/sqlite3.c /^ int (*xWalCallback)(void *, sqlite3 *, const char *, int);$/;" m struct:sqlite3 file: +xWrite testdocs/sqlite3.c /^ int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);$/;" m struct:sqlite3_io_methods file: +xferCompatibleIndex testdocs/sqlite3.c /^static int xferCompatibleIndex(Index *pDest, Index *pSrc){$/;" f file: +xferOptimization testdocs/sqlite3.c /^static int xferOptimization($/;" f file: +xorMemory testdocs/sqlite3.c /^static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){$/;" f file: +xthreadsafe testdocs/sqlite3.c /^ int (*xthreadsafe)(void);$/;" m struct:sqlite3_api_routines file: +yColCache testdocs/sqlite3.c /^ struct yColCache {$/;" s struct:Parse file: +yDbMask testdocs/sqlite3.c /^ typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)\/8];$/;" t file: +yDbMask testdocs/sqlite3.c /^ typedef unsigned int yDbMask;$/;" t file: +ynVar testdocs/sqlite3.c /^typedef i16 ynVar;$/;" t file: +ynVar testdocs/sqlite3.c /^typedef int ynVar;$/;" t file: +yy0 testdocs/sqlite3.c /^ sqlite3ParserTOKENTYPE yy0;$/;" m union:__anon33 file: +yy145 testdocs/sqlite3.c /^ TriggerStep* yy145;$/;" m union:__anon33 file: +yy148 testdocs/sqlite3.c /^ ExprList* yy148;$/;" m union:__anon33 file: +yy185 testdocs/sqlite3.c /^ SrcList* yy185;$/;" m union:__anon33 file: +yy190 testdocs/sqlite3.c /^ ExprSpan yy190;$/;" m union:__anon33 file: +yy194 testdocs/sqlite3.c /^ int yy194;$/;" m union:__anon33 file: +yy243 testdocs/sqlite3.c /^ Select* yy243;$/;" m union:__anon33 file: +yy254 testdocs/sqlite3.c /^ IdList* yy254;$/;" m union:__anon33 file: +yy285 testdocs/sqlite3.c /^ With* yy285;$/;" m union:__anon33 file: +yy332 testdocs/sqlite3.c /^ struct TrigEvent yy332;$/;" m union:__anon33 typeref:struct:__anon33::TrigEvent file: +yy354 testdocs/sqlite3.c /^ struct LimitVal yy354;$/;" m union:__anon33 typeref:struct:__anon33::LimitVal file: +yy497 testdocs/sqlite3.c /^ struct {int value; int mask;} yy497;$/;" m union:__anon33 typeref:struct:__anon33::__anon34 file: +yy72 testdocs/sqlite3.c /^ Expr* yy72;$/;" m union:__anon33 file: +yyFallback testdocs/sqlite3.c /^static const YYCODETYPE yyFallback[] = {$/;" v file: +yyGrowStack testdocs/sqlite3.c /^static int yyGrowStack(yyParser *p){$/;" f file: +yyParser testdocs/sqlite3.c /^struct yyParser {$/;" s file: +yyParser testdocs/sqlite3.c /^typedef struct yyParser yyParser;$/;" t typeref:struct:yyParser file: +yyRuleInfo testdocs/sqlite3.c /^} yyRuleInfo[] = {$/;" v typeref:struct:__anon35 file: +yyRuleName testdocs/sqlite3.c /^static const char *const yyRuleName[] = {$/;" v file: +yyStackEntry testdocs/sqlite3.c /^struct yyStackEntry {$/;" s file: +yyStackEntry testdocs/sqlite3.c /^typedef struct yyStackEntry yyStackEntry;$/;" t typeref:struct:yyStackEntry file: +yyStackOverflow testdocs/sqlite3.c /^static void yyStackOverflow(yyParser *yypParser){$/;" f file: +yyTokenName testdocs/sqlite3.c /^static const char *const yyTokenName[] = {$/;" v file: +yyTraceFILE testdocs/sqlite3.c /^static FILE *yyTraceFILE = 0;$/;" v file: +yyTracePrompt testdocs/sqlite3.c /^static char *yyTracePrompt = 0;$/;" v file: +yyTraceShift testdocs/sqlite3.c /^# define yyTraceShift(/;" d file: +yyTraceShift testdocs/sqlite3.c /^static void yyTraceShift(yyParser *yypParser, int yyNewState){$/;" f file: +yy_accept testdocs/sqlite3.c /^static void yy_accept($/;" f file: +yy_action testdocs/sqlite3.c /^static const YYACTIONTYPE yy_action[] = {$/;" v file: +yy_default testdocs/sqlite3.c /^static const YYACTIONTYPE yy_default[] = {$/;" v file: +yy_destructor testdocs/sqlite3.c /^static void yy_destructor($/;" f file: +yy_find_reduce_action testdocs/sqlite3.c /^static int yy_find_reduce_action($/;" f file: +yy_find_shift_action testdocs/sqlite3.c /^static unsigned int yy_find_shift_action($/;" f file: +yy_lookahead testdocs/sqlite3.c /^static const YYCODETYPE yy_lookahead[] = {$/;" v file: +yy_parse_failed testdocs/sqlite3.c /^static void yy_parse_failed($/;" f file: +yy_pop_parser_stack testdocs/sqlite3.c /^static void yy_pop_parser_stack(yyParser *pParser){$/;" f file: +yy_reduce testdocs/sqlite3.c /^static void yy_reduce($/;" f file: +yy_reduce_ofst testdocs/sqlite3.c /^static const short yy_reduce_ofst[] = {$/;" v file: +yy_shift testdocs/sqlite3.c /^static void yy_shift($/;" f file: +yy_shift_ofst testdocs/sqlite3.c /^static const short yy_shift_ofst[] = {$/;" v file: +yy_syntax_error testdocs/sqlite3.c /^static void yy_syntax_error($/;" f file: +yyerrcnt testdocs/sqlite3.c /^ int yyerrcnt; \/* Shifts left before out of the error *\/$/;" m struct:yyParser file: +yyhwm testdocs/sqlite3.c /^ int yyhwm; \/* High-water mark of the stack *\/$/;" m struct:yyParser file: +yyinit testdocs/sqlite3.c /^ int yyinit;$/;" m union:__anon33 file: +yystack testdocs/sqlite3.c /^ yyStackEntry *yystack; \/* The parser's stack *\/$/;" m struct:yyParser file: +yystk0 testdocs/sqlite3.c /^ yyStackEntry yystk0; \/* First stack entry *\/$/;" m struct:yyParser file: +yystksz testdocs/sqlite3.c /^ int yystksz; \/* Current side of the stack *\/$/;" m struct:yyParser file: +yytestcase testdocs/sqlite3.c /^# define yytestcase(/;" d file: +yytestcase testdocs/sqlite3.c /^#define yytestcase(/;" d file: +yytos testdocs/sqlite3.c /^ yyStackEntry *yytos; \/* Pointer to top element of the stack *\/$/;" m struct:yyParser file: +z testdocs/sqlite3.c /^ char *z; \/* Pointer to data for string (char array) types *\/$/;" m union:VdbeOp::p4union file: +z testdocs/sqlite3.c /^ char *z; \/* Pointer to buffer containing string *\/$/;" m struct:StrBuffer file: +z testdocs/sqlite3.c /^ char *z; \/* Text of the token *\/$/;" m struct:Fts3PhraseToken file: +z testdocs/sqlite3.c /^ char *z; \/* String or BLOB value *\/$/;" m struct:sqlite3_value file: +z testdocs/sqlite3.c /^ const char *z; \/* Text of the token. Not NULL-terminated! *\/$/;" m struct:Token file: +zAffSdst testdocs/sqlite3.c /^ char *zAffSdst; \/* Affinity used when eDest==SRT_Set *\/$/;" m struct:SelectDest file: +zAlias testdocs/sqlite3.c /^ char *zAlias; \/* The "B" part of a "A AS B" phrase. zName is the "A" *\/$/;" m struct:SrcList::SrcList_item file: +zAuthContext testdocs/sqlite3.c /^ const char *zAuthContext; \/* Put saved Parse.zAuthContext here *\/$/;" m struct:AuthContext file: +zAuthContext testdocs/sqlite3.c /^ const char *zAuthContext; \/* The 6th parameter to db->xAuth callbacks *\/$/;" m struct:Parse file: +zAuthPW testdocs/sqlite3.c /^ char *zAuthPW; \/* Password used to authenticate *\/$/;" m struct:sqlite3_userauth file: +zAuthUser testdocs/sqlite3.c /^ char *zAuthUser; \/* User name used to authenticate *\/$/;" m struct:sqlite3_userauth file: +zBase testdocs/sqlite3.c /^ char *zBase; \/* A base allocation. Not from malloc. *\/$/;" m struct:StrAccum file: +zBuf testdocs/sqlite3.c /^ char *zBuf; \/* Append JSON content here *\/$/;" m struct:JsonString file: +zBuffer testdocs/sqlite3.c /^ char *zBuffer;$/;" m struct:IcuCursor file: +zCanonicalName testdocs/sqlite3.c /^ char *zCanonicalName; \/* Canonical filename *\/$/;" m struct:vxworksFileId file: +zChunk testdocs/sqlite3.c /^ u8 zChunk[8]; \/* Content of this chunk *\/$/;" m struct:FileChunk file: +zClose testdocs/sqlite3.c /^ const char *zClose; \/* Closing highlight *\/$/;" m struct:HighlightContext file: +zCol testdocs/sqlite3.c /^ char *zCol; \/* Name of column in zTo. If NULL use PRIMARY KEY *\/$/;" m struct:FKey::sColMap file: +zColAff testdocs/sqlite3.c /^ char *zColAff; \/* String defining the affinity of each column *\/$/;" m struct:Index file: +zColAff testdocs/sqlite3.c /^ char *zColAff; \/* String defining the affinity of each column *\/$/;" m struct:Table file: +zColl testdocs/sqlite3.c /^ char *zColl; \/* Collating sequence. If NULL, use the default *\/$/;" m struct:Column file: +zCollName testdocs/sqlite3.c /^ const char *zCollName; \/* Required collating sequence, if not NULL *\/$/;" m struct:WhereScan file: +zComment testdocs/sqlite3.c /^ char *zComment; \/* Comment to improve readability *\/$/;" m struct:VdbeOp file: +zContent testdocs/sqlite3.c /^ char *zContent; \/* content table *\/$/;" m struct:Fts5Config file: +zContentExprlist testdocs/sqlite3.c /^ char *zContentExprlist;$/;" m struct:Fts5Config file: +zContentRowid testdocs/sqlite3.c /^ char *zContentRowid; \/* "content_rowid=" option value *\/$/;" m struct:Fts5Config file: +zContentTbl testdocs/sqlite3.c /^ char *zContentTbl; \/* content=xxx option, or NULL *\/$/;" m struct:Fts3Table file: +zCteErr testdocs/sqlite3.c /^ const char *zCteErr; \/* Error message for circular references *\/$/;" m struct:With::Cte file: +zData testdocs/sqlite3.c /^ u8 *zData; \/* Content of the node, as should be on disk *\/$/;" m struct:RtreeNode file: +zDataTbl testdocs/sqlite3.c /^ char *zDataTbl; \/* Name of %_data table *\/$/;" m struct:Fts5Index file: +zDataTbl testdocs/sqlite3.c /^ const char *zDataTbl; \/* Name of rbu db table (or null) *\/$/;" m struct:RbuObjIter file: +zDatabase testdocs/sqlite3.c /^ char *zDatabase; \/* Name of database holding this table *\/$/;" m struct:SrcList::SrcList_item file: +zDatabase testdocs/sqlite3.c /^ const char *zDatabase;$/;" m struct:analysisInfo file: +zDb testdocs/sqlite3.c /^ char *zDb; \/* Database holding FTS index (e.g. "main") *\/$/;" m struct:Fts5Config file: +zDb testdocs/sqlite3.c /^ char *zDb; \/* Name of database session is attached to *\/$/;" m struct:sqlite3_session file: +zDb testdocs/sqlite3.c /^ char *zDb; \/* Name of database containing r-tree table *\/$/;" m struct:Rtree file: +zDb testdocs/sqlite3.c /^ char *zDb; \/* Database name *\/$/;" m struct:Incrblob file: +zDb testdocs/sqlite3.c /^ const char *zDb; \/* logical database name *\/$/;" m struct:Fts3Table file: +zDb testdocs/sqlite3.c /^ const char *zDb; \/* Make sure all objects are contained in this database *\/$/;" m struct:DbFixer file: +zDbSName testdocs/sqlite3.c /^ char *zDbSName; \/* Name of this database. (schema name, not filename) *\/$/;" m struct:Db file: +zDel testdocs/sqlite3.c /^ char *zDel; \/* Delete this when closing file *\/$/;" m struct:rbu_file file: +zDeleteOnClose testdocs/sqlite3.c /^ LPWSTR zDeleteOnClose; \/* Name of file to delete when closing *\/$/;" m struct:winFile file: +zDoc testdocs/sqlite3.c /^ const char *zDoc; \/* Document being tokenized *\/$/;" m struct:Fts5SFinder file: +zEnd testdocs/sqlite3.c /^ const char *zEnd; \/* One character past the end of input text *\/$/;" m struct:ExprSpan file: +zErr testdocs/sqlite3.c /^ char *zErr;$/;" m struct:Fts5Parse file: +zErrMsg testdocs/sqlite3.c /^ char *zErrMsg; \/* Error message from sqlite3_mprintf() *\/$/;" m struct:sqlite3_vtab file: +zErrMsg testdocs/sqlite3.c /^ char *zErrMsg; \/* Error message written here *\/$/;" m struct:Vdbe file: +zErrMsg testdocs/sqlite3.c /^ char *zErrMsg; \/* An error message *\/$/;" m struct:Parse file: +zErrMsg testdocs/sqlite3.c /^ char *zErrMsg; \/* Error message text, if an error occurs *\/$/;" m struct:TabResult file: +zErrmsg testdocs/sqlite3.c /^ char *zErrmsg; \/* Error message if rc!=SQLITE_OK *\/$/;" m struct:sqlite3rbu file: +zFilename testdocs/sqlite3.c /^ char *zFilename; \/* Name of the database file *\/$/;" m struct:Pager file: +zFilename testdocs/sqlite3.c /^ char *zFilename; \/* Name of the file *\/$/;" m struct:winShmNode file: +zFilename testdocs/sqlite3.c /^ char *zFilename; \/* Name of the mmapped file *\/$/;" m struct:unixShmNode file: +zFts5Db testdocs/sqlite3.c /^ char *zFts5Db; \/* Db containing fts5 table *\/$/;" m struct:Fts5VocabTable file: +zFts5Tbl testdocs/sqlite3.c /^ char *zFts5Tbl; \/* Name of fts5 table *\/$/;" m struct:Fts5VocabTable file: +zFunc testdocs/sqlite3.c /^ char *zFunc; \/* Function name (nul-terminated) *\/$/;" m struct:Fts5Auxiliary file: +zIdx testdocs/sqlite3.c /^ char *zIdx;$/;" m struct:RbuState file: +zIdx testdocs/sqlite3.c /^ const char *zIdx; \/* Name of target db index (or null) *\/$/;" m struct:RbuObjIter file: +zIn testdocs/sqlite3.c /^ const char *zIn; \/* Input text *\/$/;" m struct:HighlightContext file: +zIndexedBy testdocs/sqlite3.c /^ char *zIndexedBy; \/* Identifier from "INDEXED BY " clause *\/$/;" m union:SrcList::SrcList_item::__anon15 file: +zInput testdocs/sqlite3.c /^ char *zInput; \/* Input string *\/$/;" m struct:Fts3tokCursor file: +zInput testdocs/sqlite3.c /^ const char *zInput; \/* input we are tokenizing *\/$/;" m struct:porter_tokenizer_cursor file: +zJContent testdocs/sqlite3.c /^ const char *zJContent; \/* Content for INT, REAL, and STRING *\/$/;" m union:JsonNode::__anon37 file: +zJournal testdocs/sqlite3.c /^ char *zJournal; \/* Name of the journal file *\/$/;" m struct:Pager file: +zJournal testdocs/sqlite3.c /^ const char *zJournal; \/* Name of the journal file *\/$/;" m struct:MemJournal file: +zJson testdocs/sqlite3.c /^ char *zJson; \/* Input JSON *\/$/;" m struct:JsonEachCursor file: +zJson testdocs/sqlite3.c /^ const char *zJson; \/* Original JSON string *\/$/;" m struct:JsonParse file: +zLanguageid testdocs/sqlite3.c /^ char *zLanguageid; \/* languageid=xxx option, or NULL *\/$/;" m struct:Fts3Table file: +zLeTerm testdocs/sqlite3.c /^ char *zLeTerm; \/* (term <= $zLeTerm) paramater, or NULL *\/$/;" m struct:Fts5VocabCursor file: +zLocale testdocs/sqlite3.c /^ char *zLocale;$/;" m struct:IcuTokenizer file: +zLockName testdocs/sqlite3.c /^ const char *zLockName; \/* Name of the table *\/$/;" m struct:TableLock file: +zMagicHeader testdocs/sqlite3.c /^static const char zMagicHeader[] = SQLITE_FILE_HEADER;$/;" v file: +zMalloc testdocs/sqlite3.c /^ char *zMalloc; \/* Malloc'd space (possibly) used for zTerm *\/$/;" m struct:SegmentNode file: +zMalloc testdocs/sqlite3.c /^ char *zMalloc; \/* Malloc'd space (possibly) used for zTerm *\/$/;" m struct:SegmentWriter file: +zMalloc testdocs/sqlite3.c /^ char *zMalloc; \/* Space to hold MEM_Str or MEM_Blob if szMalloc>0 *\/$/;" m struct:sqlite3_value file: +zMask testdocs/sqlite3.c /^ char *zMask; \/* Copy of update mask used with pUpdate *\/$/;" m struct:RbuUpdateStmt file: +zMatchinfo testdocs/sqlite3.c /^ char *zMatchinfo;$/;" m struct:MatchinfoBuffer file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of this CTE *\/$/;" m struct:With::Cte file: +zName testdocs/sqlite3.c /^ char *zName; \/* Token associated with this expression *\/$/;" m struct:ExprList::ExprList_item file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of the identifier *\/$/;" m struct:IdList::IdList_item file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of the table *\/$/;" m struct:SrcList::SrcList_item file: +zName testdocs/sqlite3.c /^ char *zName; \/* Savepoint name (nul-terminated) *\/$/;" m struct:Savepoint file: +zName testdocs/sqlite3.c /^ char *zName; \/* Local name of table *\/$/;" m struct:SessionTable file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of FTS index *\/$/;" m struct:Fts5Config file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of table or index *\/$/;" m struct:ScanStatus file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of tokenizer *\/$/;" m struct:Fts5TokenizerModule file: +zName testdocs/sqlite3.c /^ char *zName; \/* Value of 'name' column *\/$/;" m struct:StatCursor file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of r-tree table *\/$/;" m struct:Rtree file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of this index *\/$/;" m struct:Index file: +zName testdocs/sqlite3.c /^ char *zName; \/* The name of the trigger *\/$/;" m struct:Trigger file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of the collating sequence, UTF-8 encoded *\/$/;" m struct:CollSeq file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of the table or view *\/$/;" m struct:Table file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of the transformation *\/$/;" m struct:__anon19 file: +zName testdocs/sqlite3.c /^ char *zName; \/* Name of this column, \\000, then the type *\/$/;" m struct:Column file: +zName testdocs/sqlite3.c /^ const char *const zName; \/* Name of pragma *\/$/;" m struct:PragmaName file: +zName testdocs/sqlite3.c /^ const char *zName; \/* Name passed to create_module() *\/$/;" m struct:Module file: +zName testdocs/sqlite3.c /^ const char *zName; \/* virtual table name *\/$/;" m struct:Fts3Table file: +zName testdocs/sqlite3.c /^ const char *zName; \/* Name of the system call *\/$/;" m struct:unix_syscall file: +zName testdocs/sqlite3.c /^ const char *zName; \/* Name of the system call *\/$/;" m struct:win_syscall file: +zName testdocs/sqlite3.c /^ const char *zName; \/* Name of this virtual file system *\/$/;" m struct:sqlite3_vfs file: +zName testdocs/sqlite3.c /^ const char *zName; \/* SQL name of the function. *\/$/;" m struct:FuncDef file: +zName testdocs/sqlite3.c /^ const char *zName;$/;" m struct:Fts5Enum file: +zOpen testdocs/sqlite3.c /^ const char *zOpen; \/* Opening highlight *\/$/;" m struct:HighlightContext file: +zOut testdocs/sqlite3.c /^ char *zOut; \/* Output value *\/$/;" m struct:HighlightContext file: +zOutput testdocs/sqlite3.c /^ const char *zOutput;$/;" m struct:PorterRule file: +zPagetype testdocs/sqlite3.c /^ char *zPagetype; \/* Value of 'pagetype' column *\/$/;" m struct:StatCursor file: +zPath testdocs/sqlite3.c /^ char *zPath; \/* Path to this page *\/$/;" m struct:StatPage file: +zPath testdocs/sqlite3.c /^ char *zPath; \/* Value of 'path' column *\/$/;" m struct:StatCursor file: +zPath testdocs/sqlite3.c /^ const char *zPath; \/* Name of the file *\/$/;" m struct:unixFile file: +zPath testdocs/sqlite3.c /^ const char *zPath; \/* Full pathname of this file *\/$/;" m struct:winFile file: +zPfx testdocs/sqlite3.c /^ const char *zPfx; \/* Error message prefix *\/$/;" m struct:IntegrityCk file: +zPool testdocs/sqlite3.c /^ u8 *zPool; \/* Memory available to be allocated *\/$/;" m struct:Mem5Global file: +zRank testdocs/sqlite3.c /^ char *zRank; \/* Custom rank function *\/$/;" m struct:Fts5Cursor file: +zRank testdocs/sqlite3.c /^ char *zRank; \/* Name of rank function *\/$/;" m struct:Fts5Config file: +zRankArgs testdocs/sqlite3.c /^ char *zRankArgs; \/* Arguments to rank function *\/$/;" m struct:Fts5Config file: +zRankArgs testdocs/sqlite3.c /^ char *zRankArgs; \/* Custom rank function args *\/$/;" m struct:Fts5Cursor file: +zRbu testdocs/sqlite3.c /^ char *zRbu; \/* Path to rbu db *\/$/;" m struct:sqlite3rbu file: +zReadExprlist testdocs/sqlite3.c /^ char *zReadExprlist;$/;" m struct:Fts3Table file: +zRoot testdocs/sqlite3.c /^ char *zRoot; \/* Path by which to filter zJson *\/$/;" m struct:JsonEachCursor file: +zSegmentsTbl testdocs/sqlite3.c /^ char *zSegmentsTbl; \/* Name of %_segments table *\/$/;" m struct:Fts3Table file: +zSelName testdocs/sqlite3.c /^ char zSelName[12]; \/* Symbolic name of this SELECT use for debugging *\/$/;" m struct:Select file: +zSpace testdocs/sqlite3.c /^ char zSpace[100]; \/* Initial static space *\/$/;" m struct:JsonString file: +zSpan testdocs/sqlite3.c /^ char *zSpan; \/* Original text of the expression *\/$/;" m struct:ExprList::ExprList_item file: +zSql testdocs/sqlite3.c /^ char *zSql; \/* Text of the SQL statement that generated this *\/$/;" m struct:Vdbe file: +zStart testdocs/sqlite3.c /^ const char *zStart; \/* First character of input text *\/$/;" m struct:ExprSpan file: +zState testdocs/sqlite3.c /^ char *zState; \/* Path to state db (or NULL if zRbu) *\/$/;" m struct:sqlite3rbu file: +zStateDb testdocs/sqlite3.c /^ char zStateDb[5]; \/* Db name for state ("stat" or "main") *\/$/;" m struct:sqlite3rbu file: +zStop testdocs/sqlite3.c /^ char *zStop;$/;" m struct:Fts3auxCursor file: +zSuffix testdocs/sqlite3.c /^ const char *zSuffix;$/;" m struct:PorterRule file: +zTab testdocs/sqlite3.c /^ char *zTab; \/* Current table *\/$/;" m struct:sqlite3_changeset_iter file: +zTail testdocs/sqlite3.c /^ const char *zTail; \/* All SQL text past the last semicolon parsed *\/$/;" m struct:Parse file: +zTarget testdocs/sqlite3.c /^ char *zTarget; \/* Path to target db *\/$/;" m struct:sqlite3rbu file: +zTarget testdocs/sqlite3.c /^ char *zTarget; \/* Target table for DELETE, UPDATE, INSERT *\/$/;" m struct:TriggerStep file: +zTbl testdocs/sqlite3.c /^ char *zTbl;$/;" m struct:RbuState file: +zTbl testdocs/sqlite3.c /^ const char *zTbl; \/* Name of target db table *\/$/;" m struct:RbuObjIter file: +zTerm testdocs/sqlite3.c /^ char *zTerm; \/* Pointer to current term *\/$/;" m struct:Fts3SegReader file: +zTerm testdocs/sqlite3.c /^ char *zTerm; \/* Pointer to previous term buffer *\/$/;" m struct:SegmentNode file: +zTerm testdocs/sqlite3.c /^ char *zTerm; \/* Pointer to previous term buffer *\/$/;" m struct:SegmentWriter file: +zTerm testdocs/sqlite3.c /^ char *zTerm; \/* Pointer to term buffer *\/$/;" m struct:Fts3MultiSegReader file: +zTerm testdocs/sqlite3.c /^ char *zTerm; \/* nul-terminated term *\/$/;" m struct:Fts5ExprTerm file: +zTerm testdocs/sqlite3.c /^ const char *zTerm;$/;" m struct:Fts3SegFilter file: +zText testdocs/sqlite3.c /^ char *zText; \/* The string collected so far *\/$/;" m struct:StrAccum file: +zTitle testdocs/sqlite3.c /^ char zTitle[100]; \/* The title text *\/$/;" m struct:__anon20 file: +zTo testdocs/sqlite3.c /^ char *zTo; \/* Name of table that the key points to (aka: Parent) *\/$/;" m struct:FKey file: +zToken testdocs/sqlite3.c /^ char *zToken; \/* Token value. Zero terminated and dequoted *\/$/;" m union:Expr::__anon10 file: +zToken testdocs/sqlite3.c /^ char *zToken; \/* storage for current token *\/$/;" m struct:unicode_cursor file: +zToken testdocs/sqlite3.c /^ char *zToken; \/* storage for current token *\/$/;" m struct:porter_tokenizer_cursor file: +zToken testdocs/sqlite3.c /^ const char *zToken; \/* Current 'token' value *\/$/;" m struct:Fts3tokCursor file: +zType testdocs/sqlite3.c /^ const char *zType; \/* Type of the container - used for error messages *\/$/;" m struct:DbFixer file: +zVfsName testdocs/sqlite3.c /^ const char *zVfsName; \/* Name of automatically created rbu vfs *\/$/;" m struct:sqlite3rbu file: +zWal testdocs/sqlite3.c /^ char *zWal; \/* File name for write-ahead log *\/$/;" m struct:Pager file: +zWal testdocs/sqlite3.c /^ const char *zWal; \/* Wal filename for this main db file *\/$/;" m struct:rbu_file file: +zWalName testdocs/sqlite3.c /^ const char *zWalName; \/* Name of WAL file *\/$/;" m struct:Wal file: +zWriteExprlist testdocs/sqlite3.c /^ char *zWriteExprlist;$/;" m struct:Fts3Table file: +zeroJournalHdr testdocs/sqlite3.c /^static int zeroJournalHdr(Pager *pPager, int doTruncate){$/;" f file: +zeroPage testdocs/sqlite3.c /^static void zeroPage(MemPage *pPage, int flags){$/;" f file: +zeroblobFunc testdocs/sqlite3.c /^static void zeroblobFunc($/;" f file: diff --git a/testbuf.c b/testbuf.c new file mode 100644 index 0000000..54b00d4 --- /dev/null +++ b/testbuf.c @@ -0,0 +1,638 @@ +#define INCLUDE_DEFS +#include +#include +#include +#include +#include + +extern int CfgTabWidth; +extern int CfgExpandTabs; +extern int CfgCopyIndent; + + +static Buf TestBuf; + +static void onerror(char* msg) { +} + +static void set_buffer_text(char* str) { + int i = 0; + buf_init(&TestBuf, onerror); +#if 0 + TestBuf.crlf = 1; + for (Rune* curr = TestBuf.bufstart; curr < TestBuf.bufend; curr++) + *curr = '-'; + while (*str) + buf_putc(&TestBuf, false, i++, (Rune)*str++); +#endif +} + +static bool buf_text_eq(char* str) { +#if 0 + for (unsigned i = 0; i < buf_last(&TestBuf); i++) { + //printf("'%c'", buf_getc(&TestBuf, i)); + if ((Rune)*(str++) != buf_getc(&TestBuf, i)) { + //printf("\n"); + return false; + } + } + //printf("\n"); +#endif + return true; +} + +TEST_SUITE(BufferTests) { + /* Initializing + *************************************************************************/ + TEST(buf_init should initialize an empty buffer) { + Buf buf = {0}; + buf_init(&buf, (void*)0x12345678); + CHECK(buf.modified == false); + CHECK(buf.expand_tabs == CfgExpandTabs); + CHECK(buf.crlf == 0); + CHECK(buf.bufsize == sysconf(_SC_PAGE_SIZE)); + CHECK(buf.bufstart != NULL); + CHECK(buf.bufend == buf.bufstart + buf.bufsize); + CHECK(buf.gapstart == buf.bufstart); + CHECK(buf.gapend == buf.bufend); + CHECK(buf.undo == NULL); + CHECK(buf.redo == NULL); + CHECK(buf.errfn == (void*)0x12345678); + } + + TEST(buf_init shoud free old buffer and reinitialize) { + Buf buf = {0}; + buf_init(&buf, onerror); + buf_putc(&buf, false, 0, 'a'); + buf_init(&buf, (void*)0x12345678); + CHECK(buf.modified == false); + CHECK(buf.expand_tabs == CfgExpandTabs); + CHECK(buf.crlf == 0); + CHECK(buf.bufsize == sysconf(_SC_PAGE_SIZE)); + CHECK(buf.bufstart != NULL); + CHECK(buf.bufend == buf.bufstart + buf.bufsize); + CHECK(buf.gapstart == buf.bufstart); + CHECK(buf.gapend == buf.bufend); + CHECK(buf.undo == NULL); + CHECK(buf.redo == NULL); + CHECK(buf.errfn == (void*)0x12345678); + } + + /* Loading + *************************************************************************/ + TEST(buf_load should load a UTF-8 file from disk) { + Sel sel; + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, NULL, "testdocs/lorem.txt"); + CHECK(sel.end == 0); + CHECK(TestBuf.modified == false); + CHECK(TestBuf.expand_tabs == true); + CHECK(TestBuf.crlf == 0); + CHECK(TestBuf.bufsize == 61440); + CHECK(TestBuf.undo == NULL); + CHECK(TestBuf.redo == NULL); + CHECK(TestBuf.errfn == NULL); + CHECK(!strcmp(TestBuf.path, "testdocs/lorem.txt")); + } + + TEST(buf_load should load a file from disk and jump to a specific line) { + IGNORE("Jumping to a specific line is not implemented yet."); + Sel sel; + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, &sel, "testdocs/lorem.txt:2"); + CHECK(sel.end == 70); + CHECK(TestBuf.modified == false); + CHECK(TestBuf.expand_tabs == true); + CHECK(TestBuf.crlf == 0); + CHECK(TestBuf.bufsize == 61440); + CHECK(TestBuf.undo == NULL); + CHECK(TestBuf.redo == NULL); + CHECK(TestBuf.errfn == NULL); + CHECK(!strcmp(TestBuf.path, "testdocs/lorem.txt")); + } + + TEST(buf_load should remove ./ from file path) { + Sel sel; + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, &sel, "./testdocs/lorem.txt"); + CHECK(sel.end == 0); + CHECK(TestBuf.modified == false); + CHECK(TestBuf.expand_tabs == true); + CHECK(TestBuf.crlf == 0); + CHECK(TestBuf.bufsize == 61440); + CHECK(TestBuf.undo == NULL); + CHECK(TestBuf.redo == NULL); + CHECK(TestBuf.errfn == NULL); + CHECK(!strcmp(TestBuf.path, "testdocs/lorem.txt")); + } + + TEST(buf_reload should reload the file from disk) { + Sel sel; + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, &sel, "testdocs/waf"); + TestBuf.path = "testdocs/lorem.txt"; + buf_reload(&TestBuf); + CHECK(sel.end == 0); + CHECK(TestBuf.modified == false); + CHECK(TestBuf.expand_tabs == true); + CHECK(TestBuf.crlf == 0); + CHECK(TestBuf.bufsize == 61440); + CHECK(TestBuf.undo == NULL); + CHECK(TestBuf.redo == NULL); + CHECK(TestBuf.errfn == NULL); + CHECK(!strcmp(TestBuf.path, "testdocs/lorem.txt")); + } + + TEST(buf_load should handle non-existent paths) { + Sel sel; + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, &sel, "nonexistent.txt"); + buf_reload(&TestBuf); + CHECK(sel.end == 0); + CHECK(TestBuf.modified == false); + CHECK(TestBuf.expand_tabs == true); + CHECK(TestBuf.crlf == 0); + CHECK(TestBuf.bufsize == sysconf(_SC_PAGE_SIZE)); + CHECK(TestBuf.undo == NULL); + CHECK(TestBuf.redo == NULL); + CHECK(TestBuf.errfn == NULL); + CHECK(!strcmp(TestBuf.path, "nonexistent.txt")); + } + +#if 0 + /* Saving + *************************************************************************/ + TEST(buf_save should save a UTF-8 file to disk) { + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, "testdocs/lorem.txt"); + TestBuf.modified = true; + buf_save(&TestBuf); + CHECK(TestBuf.modified == false); + } + + TEST(buf_save should save a non UTF-8 file to disk) { + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, "testdocs/waf"); + TestBuf.modified = true; + buf_save(&TestBuf); + CHECK(TestBuf.modified == false); + } + + TEST(buf_save should save a file to disk with unix line endings) { + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, "testdocs/lf.txt"); + TestBuf.modified = true; + buf_save(&TestBuf); + CHECK(TestBuf.modified == false); + } + + TEST(buf_save should save a file to disk with dos line endings) { + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, "testdocs/crlf.txt"); + TestBuf.modified = true; + buf_save(&TestBuf); + CHECK(TestBuf.modified == false); + } + + TEST(buf_save should make sure unix file ends witn newline) { + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, "testdocs/lf.txt"); + TestBuf.modified = true; + size_t end = buf_last(&TestBuf); + buf_delete(&TestBuf, end-1, end); + CHECK(end-1 == buf_last(&TestBuf)); + buf_save(&TestBuf); + CHECK(end == buf_last(&TestBuf)); + CHECK(TestBuf.modified == false); + } + + TEST(buf_save should make sure dos file ends witn newline) { + buf_init(&TestBuf, NULL); + buf_load(&TestBuf, "testdocs/crlf.txt"); + TestBuf.modified = true; + size_t end = buf_last(&TestBuf); + buf_delete(&TestBuf, end-1, end); + CHECK(end-1 == buf_last(&TestBuf)); + buf_save(&TestBuf); + CHECK(end == buf_last(&TestBuf)); + CHECK(TestBuf.modified == false); + } + + /* Insertions + *************************************************************************/ + TEST(buf_putc should insert at 0 in empty buf) { + buf_init(&TestBuf, onerror); + buf_putc(&TestBuf, false, 0, 'a'); + CHECK(buf_text_eq("a")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_putc should insert at 0) { + buf_init(&TestBuf, onerror); + buf_putc(&TestBuf, false, 0, 'b'); + buf_putc(&TestBuf, false, 0, 'a'); + CHECK(buf_text_eq("ab")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_putc should insert at 1) { + buf_init(&TestBuf, onerror); + buf_putc(&TestBuf, false, 0, 'a'); + buf_putc(&TestBuf, false, 1, 'b'); + CHECK(buf_text_eq("ab")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_putc should insert at 1) { + buf_init(&TestBuf, onerror); + buf_putc(&TestBuf, false, 0, 'a'); + buf_putc(&TestBuf, false, 1, 'c'); + buf_putc(&TestBuf, false, 1, 'b'); + CHECK(buf_text_eq("abc")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_putc should sentence in larger text) { + set_buffer_text( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); + buf_putc(&TestBuf, false, 5, ' '); + buf_putc(&TestBuf, false, 6, 'a'); + CHECK(buf_text_eq( + "Lorem a ipsum dolor sit amet, consectetur adipiscing elit." )); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_putc should expand tabs) { + set_buffer_text(""); + TestBuf.expand_tabs = true; + buf_putc(&TestBuf, true, 0, '\t'); + CHECK(buf_text_eq(" ")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_putc should copy indent) { + set_buffer_text(" "); + TestBuf.crlf = 0; + buf_putc(&TestBuf, true, 4, '\n'); + CHECK(buf_text_eq(" \n ")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + /* Deletions + *************************************************************************/ + TEST(buf_delete should delete first char) { + set_buffer_text("abc"); + buf_delete(&TestBuf, 0, 1); + CHECK(buf_text_eq("bc")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_delete should delete second char) { + set_buffer_text("abc"); + buf_delete(&TestBuf, 1, 2); + CHECK(buf_text_eq("ac")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_delete should delete third char) { + set_buffer_text("abc"); + buf_delete(&TestBuf, 2, 3); + CHECK(buf_text_eq("ab")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + TEST(buf_delete should delete more than one char) { + set_buffer_text("abcdef"); + buf_delete(&TestBuf, 1, 5); + CHECK(buf_text_eq("af")); + CHECK(TestBuf.modified == true); + CHECK(TestBuf.redo == NULL); + } + + /* Undo/Redo + *************************************************************************/ + TEST(buf_undo should undo an insert) { + Sel sel; + set_buffer_text(""); + buf_putc(&TestBuf, true, 0, 'a'); + CHECK(buf_text_eq("a")); + CHECK(TestBuf.redo == NULL); + CHECK(TestBuf.undo != NULL); + buf_undo(&TestBuf, &sel); + CHECK(buf_text_eq("")); + CHECK(TestBuf.redo != NULL); + CHECK(TestBuf.undo == NULL); + } + + TEST(buf_undo should undo a delete) { + Sel sel; + set_buffer_text("a"); + buf_delete(&TestBuf, 0, 1); + CHECK(buf_text_eq("")); + CHECK(TestBuf.redo == NULL); + CHECK(TestBuf.undo != NULL); + buf_undo(&TestBuf, &sel); + CHECK(buf_text_eq("a")); + CHECK(TestBuf.redo != NULL); + CHECK(TestBuf.undo != NULL); + } + + /* Accessors + *************************************************************************/ + // buf_getc + TEST(buf_getc should return newline for indexes outside the buffer) { + set_buffer_text("test"); + CHECK('\n' == buf_getc(&TestBuf, 4)); + } + + TEST(buf_getc should indexed character before the gap) { + set_buffer_text("ac"); + buf_putc(&TestBuf, false, 1, 'b'); + CHECK('a' == buf_getc(&TestBuf, 0)); + } + + TEST(buf_getc should indexed character after the gap) { + set_buffer_text("ac"); + buf_putc(&TestBuf, false, 1, 'b'); + CHECK('c' == buf_getc(&TestBuf, 2)); + } + + TEST(buf_last should return the index just after the last rune in the buffer) { + set_buffer_text("abc"); + CHECK(3 == buf_last(&TestBuf)); + } + + TEST(buf_iseol should return true if index points to a newline rune) { + set_buffer_text("abc\ncba"); + CHECK(buf_iseol(&TestBuf, 3)); + } + + TEST(buf_iseol should return true if index points to a crlf rune) { + IGNORE("Test causes an assertion in the syncgap function. no idea why"); + set_buffer_text("abc\r\ncba"); + CHECK(buf_iseol(&TestBuf, 0)); + } + + TEST(buf_iseol should return false if index does not point to a newline rune) { + set_buffer_text("abc\ncba"); + CHECK(!buf_iseol(&TestBuf, 2)); + } + + /* Movements + *************************************************************************/ + // Start of Line + TEST(buf_bol should return 0 if column 1 of first line) { + set_buffer_text("ab\ncd"); + CHECK(0 == buf_bol(&TestBuf, 2)); + } + + TEST(buf_bol should return 0 if column 2 of first line) { + set_buffer_text("ab\ncd"); + CHECK(0 == buf_bol(&TestBuf, 1)); + } + + TEST(buf_bol should return 0 if index points to newline) { + set_buffer_text("ab\ncd"); + CHECK(0 == buf_bol(&TestBuf, 0)); + } + + TEST(buf_bol should return 3 if column 1 of second line) { + set_buffer_text("ab\ncd"); + CHECK(3 == buf_bol(&TestBuf, 3)); + } + + TEST(buf_bol should return 3 if column 2 of second line) { + set_buffer_text("ab\ncd"); + CHECK(3 == buf_bol(&TestBuf, 4)); + } + + TEST(buf_bol should return input if index is outside buffer) { + set_buffer_text("ab\ncd"); + CHECK(6 == buf_bol(&TestBuf, 6)); + } + + // End of Line + TEST(buf_eol should return 2 if column 1 of first line) { + set_buffer_text("ab\ncd"); + CHECK(2 == buf_eol(&TestBuf, 0)); + } + + TEST(buf_eol should return 2 if column 2 of first line) { + set_buffer_text("ab\ncd"); + CHECK(2 == buf_eol(&TestBuf, 1)); + } + + TEST(buf_eol should return 2 if column 3 of first line) { + set_buffer_text("ab\ncd"); + CHECK(2 == buf_eol(&TestBuf, 2)); + } + + TEST(buf_eol should return 5 if column 1 of second line) { + set_buffer_text("ab\ncd"); + CHECK(5 == buf_eol(&TestBuf, 3)); + } + + TEST(buf_eol should return 5 if column 2 of second line) { + set_buffer_text("ab\ncd"); + CHECK(5 == buf_eol(&TestBuf, 4)); + } + + TEST(buf_eol should return 5 if column 3 of second line) { + set_buffer_text("ab\ncd"); + CHECK(5 == buf_eol(&TestBuf, 5)); + } + + // Start of Word + TEST(buf_bow should return input when pointing to whitespace before word) { + set_buffer_text(" abc "); + CHECK(0 == buf_bow(&TestBuf, 0)); + } + + TEST(buf_bow should return 1 when first rune of word) { + set_buffer_text(" abc "); + CHECK(1 == buf_bow(&TestBuf, 1)); + } + + TEST(buf_bow should return 1 when second rune of word) { + set_buffer_text(" abc "); + CHECK(1 == buf_bow(&TestBuf, 2)); + } + + TEST(buf_bow should return 1 when third rune of word) { + set_buffer_text(" abc "); + CHECK(1 == buf_bow(&TestBuf, 3)); + } + + TEST(buf_bow should return input when pointing to whitespace after word) { + IGNORE("this may be correct but moving by word is janky right now. revisit later"); + set_buffer_text(" abc "); + CHECK(4 == buf_bow(&TestBuf, 4)); + } + + // End of Word + TEST(buf_eow should return input when pointing to whitespace before word) { + IGNORE("this may be correct but moving by word is janky right now. revisit later"); + set_buffer_text(" abc "); + CHECK(0 == buf_eow(&TestBuf, 0)); + } + + TEST(buf_eow should return 3 when first rune of word) { + set_buffer_text(" abc "); + CHECK(3 == buf_eow(&TestBuf, 1)); + } + + TEST(buf_eow should return 3 when second rune of word) { + set_buffer_text(" abc "); + CHECK(3 == buf_eow(&TestBuf, 2)); + } + + TEST(buf_eow should return 3 when third rune of word) { + set_buffer_text(" abc "); + CHECK(3 == buf_eow(&TestBuf, 3)); + } + + TEST(buf_eow should return input when pointing to whitespace after word) { + IGNORE("this may be correct but moving by word is janky right now. revisit later"); + set_buffer_text(" abc "); + CHECK(4 == buf_eow(&TestBuf, 4)); + } + + // Scan Left + TEST(buf_lscan should return location of token to the left) { + set_buffer_text("a{bc}"); + CHECK(1 == buf_lscan(&TestBuf, 4, '{')); + } + + TEST(buf_lscan should return input location if token not found) { + set_buffer_text("{ab}"); + CHECK(3 == buf_lscan(&TestBuf, 3, '[')); + } + + // Scan Right + TEST(buf_rscan should return location of token to the right) { + set_buffer_text("{ab}c"); + CHECK(3 == buf_rscan(&TestBuf, 0, '}')); + } + + TEST(buf_rscan should return input location if token not found) { + set_buffer_text("{ab}c"); + CHECK(0 == buf_rscan(&TestBuf, 0, ']')); + } + + // By Rune + TEST(buf_byrune should do nothing for -1 at beginning of file) { + set_buffer_text("abc\n"); + CHECK(0 == buf_byrune(&TestBuf, 0, -1)); + } + + TEST(buf_byrune should move to first rune for -1 at second rune of file) { + set_buffer_text("abc\n"); + CHECK(0 == buf_byrune(&TestBuf, 1, -2)); + } + + TEST(buf_byrune should move to just after last rune for +1 at end of file) { + set_buffer_text("abc\n"); + CHECK(4 == buf_byrune(&TestBuf, 3, 2)); + } + + TEST(buf_byrune should move to just after last rune for +2 at second to last rune) { + set_buffer_text("abc\n"); + CHECK(4 == buf_byrune(&TestBuf, 2, 3)); + } + + TEST(buf_byrune should move from blank line to non-blank line for +1) { + set_buffer_text("ab\n\ncd\n"); + CHECK(4 == buf_byrune(&TestBuf, 3, 1)); + } + + // By Line + TEST(buf_byline should not move before first line) { + set_buffer_text("ab\n\ncd\n"); + CHECK(0 == buf_byline(&TestBuf, 0, -1)); + } + + TEST(buf_byline should not move before first line) { + set_buffer_text("a\nb\nc\nd\n"); + CHECK(0 == buf_byline(&TestBuf, 7, -10)); + } + + TEST(buf_byline should move back multiple lines) { + set_buffer_text("a\nb\nc\nd\n"); + CHECK(2 == buf_byline(&TestBuf, 7, -2)); + } + + TEST(buf_byline should move back a line) { + set_buffer_text("abc\ndef"); + CHECK(0 == buf_byline(&TestBuf, 4, -1)); + } + + TEST(buf_byline should move forward a line) { + set_buffer_text("abc\ndef"); + CHECK(4 == buf_byline(&TestBuf, 2, 1)); + } + + TEST(buf_byline should not move after last line) { + set_buffer_text("abc\ndef"); + CHECK(6 == buf_byline(&TestBuf, 6, 1)); + } + + TEST(buf_byline should do nothing at end of buffer) { + set_buffer_text("abc\ndef"); + CHECK(7 == buf_byline(&TestBuf, buf_last(&TestBuf), 1)); + } + + /* Cursor Column Tracking + *************************************************************************/ + TEST(buf_getccol should return the column associated with the position) { + set_buffer_text("abcdef"); + CHECK(4 == buf_getccol(&TestBuf, 4)); + } + + TEST(buf_getccol should return the column associated with the position on second line) { + set_buffer_text("abcdef\nabcdef"); + CHECK(0 == buf_getccol(&TestBuf, 7)); + } + + TEST(buf_getccol should handle tab characters) { + set_buffer_text("\tabcdef"); + CHECK(4 == buf_getccol(&TestBuf, 1)); + } + + TEST(buf_setcol should set the column to column 1 of second line) { + set_buffer_text("abc\ndef"); + CHECK(4 == buf_setcol(&TestBuf, 4, 0)); + } + + TEST(buf_setcol should set the column to column 2 of second line) { + set_buffer_text("abc\ndef"); + CHECK(5 == buf_setcol(&TestBuf, 4, 1)); + } + + TEST(buf_setcol should handle tabs) { + set_buffer_text("abc\n\tdef"); + CHECK(5 == buf_setcol(&TestBuf, 4, 4)); + } + + TEST(buf_setcol should not set column past the last rune) { + set_buffer_text("abc\n\tdef"); + CHECK(8 == buf_setcol(&TestBuf, 4, 100)); + } +#endif +} + +int main(int argc, char** argv) { + atf_init(argc,argv); + RUN_EXTERN_TEST_SUITE(BufferTests); + return atf_print_results(); +} + diff --git a/testdocs/crlf.txt b/testdocs/crlf.txt new file mode 100644 index 0000000..dab8c54 --- /dev/null +++ b/testdocs/crlf.txt @@ -0,0 +1,5 @@ +this file +uses +dos +line +endings diff --git a/testdocs/lang-utf16.txt b/testdocs/lang-utf16.txt new file mode 100644 index 0000000..5053dce --- /dev/null +++ b/testdocs/lang-utf16.txt @@ -0,0 +1,38 @@ +外国語の学習と教授 +Language Learning and Teaching + +Изучение и обучение иностранных языков + +Tere Daaheng Aneng Karimah + +語文教學・语文教学 + +Enseñanza y estudio de idiomas + +Изучаване и Преподаване на Чужди Езици + +ქართული ენის შესწავლა და სწავლება + +'læŋɡwidʒ 'lɘr:niŋ ænd 'ti:tʃiŋ + +Lus kawm thaib qhia + +Ngôn Ngữ, Sự học, + +‭‫ללמוד וללמד את השֵפה + +L'enseignement et l'étude des langues + +말배우기와 가르치기 + +Nauka języków obcych + +Γλωσσική Εκμὰθηση και Διδασκαλία + +‭‫ﺗﺪﺭﯾﺲ ﻭ ﯾﺎﺩﮔﯿﺮﯼ ﺯﺑﺎﻥ + +Sprachlernen und -lehren + +‭‫ﺗﻌﻠ‫‫ُّ‪‪‫ﻢ ﻭﺗﺪﺭﻳﺲ ﺍﻟﻌﺮﺑﻴﺔ + +เรียนและสอนภาษา diff --git a/testdocs/lang-utf8.txt b/testdocs/lang-utf8.txt new file mode 100644 index 0000000..59800c7 --- /dev/null +++ b/testdocs/lang-utf8.txt @@ -0,0 +1,38 @@ +外国語の学習と教授 +Language Learning and Teaching + +Изучение и обучение иностранных языков + +Tere Daaheng Aneng Karimah + +語文教學・语文教学 + +Enseñanza y estudio de idiomas + +Изучаване и Преподаване на Чужди Езици + +ქართული ენის შესწავლა და სწავლება + +'læŋɡwidʒ 'lɘr:niŋ ænd 'ti:tʃiŋ + +Lus kawm thaib qhia + +Ngôn Ngữ, Sự học, + +‭‫ללמוד וללמד את השֵפה + +L'enseignement et l'étude des langues + +말배우기와 가르치기 + +Nauka języków obcych + +Γλωσσική Εκμὰθηση και Διδασκαλία + +‭‫ﺗﺪﺭﯾﺲ ﻭ ﯾﺎﺩﮔﯿﺮﯼ ﺯﺑﺎﻥ + +Sprachlernen und -lehren + +‭‫ﺗﻌﻠﻢ ﻭﺗﺪﺭﻳﺲ ﺍﻟﻌﺮﺑﻴﺔ + +เรียนและสอนภาษา diff --git a/testdocs/lf.txt b/testdocs/lf.txt new file mode 100644 index 0000000..d8027d5 --- /dev/null +++ b/testdocs/lf.txt @@ -0,0 +1,5 @@ +this file +uses +unix +line +endings diff --git a/testdocs/longlines.txt b/testdocs/longlines.txt new file mode 100644 index 0000000..7c9eb69 --- /dev/null +++ b/testdocs/longlines.txt @@ -0,0 +1,2 @@ +hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there +hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there hello there diff --git a/testdocs/lorem.txt b/testdocs/lorem.txt new file mode 100644 index 0000000..3e893fe --- /dev/null +++ b/testdocs/lorem.txt @@ -0,0 +1,998 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nec +imperdiet tortor. Cras nunc lectus, elementum vel lobortis vitae, lobortis +vitae est. Vivamus lacinia ante quis lorem auctor pulvinar. Cras imperdiet +eu tortor pretium aliquam. Fusce at tincidunt mi. Nulla vitae eleifend +ex, et ultrices libero. Maecenas facilisis finibus felis, in malesuada +eros vulputate ut. Curabitur a imperdiet leo. Aliquam eget fermentum +orci. Quisque dictum efficitur ligula, eget tempor magna cursus a. Nam +consequat eros et sapien faucibus, a finibus magna varius. Phasellus +sollicitudin nulla quis finibus tincidunt. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Nunc nec condimentum lectus. Donec rhoncus, +velit sed tempor molestie, est odio auctor quam, ac facilisis diam felis +id massa. Donec feugiat lectus nibh, et volutpat magna molestie sed. + +Proin tristique pharetra felis ut faucibus. Nulla in luctus nunc. Fusce +placerat molestie fermentum. Phasellus congue elit neque, id porta +elit ornare ac. Cras consequat, sem at lacinia iaculis, ipsum mauris +hendrerit erat, ultrices varius odio sem commodo erat. Phasellus ut +justo sapien. Duis vel dolor at dolor volutpat bibendum. Proin eget +mauris nec augue posuere maximus. + +Maecenas sollicitudin elit at risus tempor, non tristique massa +ultricies. Morbi vel vehicula elit, non suscipit justo. Cras gravida risus +id mauris pharetra, at rutrum nisl blandit. Donec luctus metus turpis, sed +auctor purus elementum a. Maecenas pulvinar, diam ac hendrerit varius, +velit dui maximus tortor, eu ultricies mauris sapien ut justo. Nunc +viverra turpis ac mauris porta, non vehicula arcu rhoncus. Nullam rutrum +lorem a blandit porta. + +Integer a scelerisque magna. Donec et quam cursus, fermentum magna et, +vestibulum lorem. Sed id urna bibendum, cursus sem quis, dictum arcu. Cras +sed pharetra nisl, sit amet iaculis justo. Cras maximus odio scelerisque, +volutpat nisl vitae, tempus erat. Cras elementum fringilla massa. Quisque +nunc nulla, suscipit ac ultricies id, suscipit id sapien. Cras aliquet et +diam ac faucibus. Etiam eu libero vehicula magna interdum ornare laoreet +vel erat. Pellentesque eu venenatis ligula, ac venenatis dolor. Mauris +vel turpis dui. + +Integer nec purus mi. Sed eu nunc vitae dui lacinia rutrum. Morbi eu +fringilla tortor, quis suscipit libero. Praesent eu elit aliquam nisi +euismod vehicula. Proin eleifend eget eros non imperdiet. Vivamus commodo +leo nunc, ut malesuada libero commodo in. Aliquam venenatis nisl suscipit +gravida pulvinar. Fusce et velit blandit, lobortis lectus ac, ullamcorper +leo. Donec fermentum purus sem, in aliquet mauris tempor sed. Donec +dignissim elit id quam fringilla ornare eu eu massa. Aliquam vitae finibus +lorem. Fusce ultricies nisi quis mi pharetra sodales. Vivamus orci enim, +placerat a libero eget, euismod finibus orci. Mauris blandit at velit +a ullamcorper. + +Maecenas posuere nisi et lectus vestibulum, a auctor turpis +placerat. Mauris consectetur enim eu urna lacinia, vel imperdiet dolor +tempus. Etiam ut tellus vitae justo ultrices molestie. Duis vel massa +malesuada, commodo urna in, cursus orci. Nullam ac nulla et tortor +tristique viverra. Vivamus in velit lobortis, pretium quam ut, congue +dolor. Vestibulum tincidunt imperdiet augue ac feugiat. Pellentesque +hendrerit semper orci, et laoreet odio efficitur eget. Lorem ipsum dolor +sit amet, consectetur adipiscing elit. Nulla eget purus hendrerit diam +dignissim auctor eu id mauris. Duis turpis ex, porttitor ac turpis a, +fermentum hendrerit odio. + +Aenean vitae enim nisl. Donec felis lorem, condimentum venenatis est +tristique, luctus facilisis est. Ut posuere tempus orci, sed tempor justo +porttitor eu. Proin id accumsan libero, quis ullamcorper odio. Mauris +cursus rutrum arcu, quis mattis elit dignissim vel. Nunc urna diam, +aliquam pharetra urna vitae, finibus ultricies eros. Proin a viverra arcu. + +Duis ipsum ex, pharetra eu massa in, sollicitudin viverra tortor. Lorem +ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at sodales +quam, non tempor dui. Donec justo mauris, iaculis et vulputate non, mattis +eget leo. Praesent sed lacus vitae mi ornare luctus eu at dolor. Curabitur +lacinia eu nisl vitae facilisis. Proin ornare dolor in tortor sollicitudin +dictum. Suspendisse aliquet rutrum metus, non feugiat lacus varius at. + +Aliquam nisi urna, pharetra eget ullamcorper ut, tincidunt quis +massa. Phasellus sed nulla accumsan, egestas justo vel, porttitor +ligula. Nam sollicitudin augue eget placerat commodo. Cras et +sagittis massa, sit amet lobortis dui. Phasellus eleifend euismod +tortor ullamcorper volutpat. Pellentesque bibendum urna ac lectus +laoreet porttitor. Donec dolor massa, dictum sit amet vehicula ut, +porta id sapien. Aliquam erat volutpat. Aliquam quis velit euismod nisi +porta semper. Duis fringilla efficitur eleifend. Aenean sed vulputate +felis. Suspendisse quis semper velit. Sed pellentesque erat eget ipsum +laoreet tristique. Integer viverra, mauris sed rhoncus pulvinar, tellus +sapien facilisis velit, a blandit libero purus et ipsum. Suspendisse +cursus ante sapien, eget hendrerit metus ultricies ac. Donec porttitor +hendrerit ex, sit amet vulputate nisl ornare et. + +Maecenas leo mauris, egestas nec nunc in, convallis mollis mi. Donec +sollicitudin at sapien a interdum. Pellentesque varius orci in nisl +congue, eu euismod lorem faucibus. Quisque vel mi mi. Donec feugiat +dapibus euismod. Duis vitae euismod orci. Nunc et finibus odio, quis +finibus quam. Morbi sem leo, laoreet at eros non, malesuada pellentesque +ex. Vivamus vel pellentesque purus, at pharetra quam. Fusce dictum +neque nec rhoncus facilisis. Proin egestas nisl varius eros gravida +euismod. Vivamus lacinia dui et tellus tristique ornare. Nullam nec +vulputate nibh. Sed molestie tempus tortor vitae dapibus. Curabitur sed +pulvinar lectus, id molestie quam. Sed vel ipsum hendrerit, tincidunt +lectus at, condimentum diam. + +Mauris cursus interdum felis, vel tincidunt massa condimentum ac. Donec +varius euismod neque vel finibus. Sed quis pretium nunc. Praesent bibendum +erat eleifend ultricies accumsan. Aenean accumsan mauris vel mi tempus, +et vulputate urna placerat. Cras maximus malesuada lobortis. Etiam ac +urna vel massa faucibus dictum non ut magna. Morbi lectus mi, placerat +vitae congue ut, egestas vel odio. Suspendisse id velit augue. Proin +viverra quis nunc aliquam volutpat. Integer a accumsan ex. + +Maecenas magna magna, imperdiet a odio vel, commodo lacinia leo. Nulla at +odio lectus. Cras libero arcu, maximus sit amet blandit vitae, faucibus +vel felis. Suspendisse potenti. Curabitur tincidunt interdum elit, +sed accumsan ligula suscipit ac. Pellentesque habitant morbi tristique +senectus et netus et malesuada fames ac turpis egestas. Interdum et +malesuada fames ac ante ipsum primis in faucibus. Suspendisse rhoncus +odio in eros ultricies, id venenatis dolor aliquam. Suspendisse eu +dui blandit, sollicitudin lorem nec, commodo mauris. Nunc elit libero, +ornare non neque et, molestie malesuada lectus. Praesent scelerisque, +enim vitae vulputate molestie, nisi massa tristique mi, sit amet accumsan +nunc mauris et ligula. Donec eget molestie metus. Nunc suscipit quam et +lorem vulputate, id lacinia velit cursus. Sed quis condimentum massa, +id lobortis metus. + +Donec vestibulum quis ligula a faucibus. Pellentesque et accumsan +tortor. Nullam id neque vitae mauris maximus hendrerit eu ac felis. Nam +sapien eros, molestie vitae diam vitae, euismod fringilla purus. Aliquam +vitae orci ante. Aenean nec neque id orci ullamcorper suscipit. Lorem +ipsum dolor sit amet, consectetur adipiscing elit. Praesent porta, risus +ut mollis consequat, nulla nisl fringilla mauris, malesuada volutpat eros +ante ut metus. Integer finibus eget diam quis mollis. Phasellus tincidunt +mi justo, non hendrerit elit semper a. Sed nunc dolor, vulputate ac +vehicula eu, vehicula vitae risus. Integer ut libero diam. Pellentesque +convallis maximus orci, quis vulputate magna volutpat sit amet. Integer +nunc quam, faucibus quis erat nec, egestas convallis arcu. Morbi a +vestibulum risus. + +Phasellus bibendum leo purus, non cursus eros eleifend et. Mauris dictum +mollis neque, vel facilisis lacus blandit nec. Quisque vitae massa +quis erat ultricies porttitor. Nunc dapibus nibh eu massa molestie, +id pellentesque eros mattis. Aliquam at augue posuere, tempus ipsum +at, tristique erat. Integer ac purus congue, tempor nulla nec, pretium +tortor. Integer id urna dui. Nulla porta ut augue ac hendrerit. Donec +congue sem at nisi dictum aliquet. Vivamus in placerat sem, eget +pellentesque nisl. Praesent egestas diam vel metus commodo, eu egestas +nunc iaculis. Phasellus ultrices tristique posuere. Pellentesque ac nisi +placerat, commodo neque eu, pulvinar sem. + +Phasellus et pellentesque turpis. Vivamus iaculis rhoncus ex +et ullamcorper. Nullam egestas eget mi non ornare. Pellentesque +habitant morbi tristique senectus et netus et malesuada fames ac turpis +egestas. Donec ac dolor felis. Orci varius natoque penatibus et magnis dis +parturient montes, nascetur ridiculus mus. Sed at sagittis tellus. Duis a +lacus vel lorem ultrices vehicula sit amet in dui. Nullam eget volutpat +enim. Etiam et neque est. Sed ornare velit risus, nec ultrices dui +vestibulum eget. Sed sollicitudin commodo ipsum et sodales. Mauris +eget rutrum massa. Suspendisse non leo fermentum tellus consequat +facilisis. Nulla semper mi ut volutpat malesuada. + +Cras vel lorem magna. Duis feugiat enim vel pretium ullamcorper. Nam +ac turpis odio. Donec eget augue iaculis, congue odio et, sollicitudin +mi. Mauris et purus dapibus, lacinia metus id, volutpat velit. Vestibulum +cursus sapien sit amet mi condimentum ornare. Donec rutrum aliquam +cursus. Sed id tellus leo. + +Phasellus auctor tristique nibh, non sodales augue placerat +quis. Mauris pulvinar bibendum iaculis. Nullam elementum et magna quis +auctor. Pellentesque iaculis pellentesque convallis. Vestibulum convallis +euismod turpis, accumsan convallis risus gravida in. Donec ac bibendum +diam. Mauris tincidunt enim sit amet sapien congue semper. Sed auctor +gravida consectetur. Donec pharetra nibh lorem, aliquam venenatis dolor +interdum bibendum. Praesent ut tortor ligula. Integer diam eros, bibendum +eu ullamcorper viverra, volutpat eu felis. Aliquam porta maximus magna, +in mattis lacus porttitor sit amet. + +Donec a facilisis urna, eu porttitor nisi. Duis vestibulum quam at +lobortis ornare. Vestibulum a turpis bibendum, tincidunt velit sit +amet, ornare leo. Maecenas porttitor luctus odio vel dignissim. Sed +mi lacus, feugiat quis tortor ac, maximus tincidunt nunc. Praesent +et aliquet neque. Maecenas pharetra neque a ipsum ornare, ut laoreet +tellus semper. Ut vehicula purus non fermentum molestie. Vestibulum +eu mi eget lorem ultrices vulputate. Aliquam eu sagittis mauris, ut +posuere augue. Aliquam commodo non augue in rutrum. Morbi faucibus diam +in gravida sagittis. Vivamus non fringilla elit. Morbi ut nibh tincidunt +neque laoreet commodo. Vivamus fermentum ultrices tellus non varius. + +Etiam faucibus, urna sed aliquet iaculis, orci odio euismod diam, +eu aliquam lorem nisi et lacus. Integer nulla mi, pellentesque eu +lectus quis, lacinia aliquet erat. Vestibulum odio lacus, scelerisque +a lacus et, blandit tincidunt quam. Ut convallis tellus et arcu +malesuada, vitae tincidunt justo fermentum. Pellentesque tempor +sapien vel pulvinar feugiat. Nam nec gravida justo. Curabitur rhoncus +convallis viverra. Aenean id posuere tortor, non accumsan risus. Nulla +facilisi. Morbi molestie eu odio ut dapibus. Nullam molestie pulvinar +sollicitudin. Fusce iaculis felis justo, sed mattis magna placerat +at. Proin tristique non odio sed gravida. Quisque varius augue quis +commodo semper. Pellentesque at orci ac neque pellentesque blandit. + +Morbi vel ipsum pellentesque, interdum magna non, dapibus erat. Praesent +leo massa, imperdiet ac gravida sed, luctus eu arcu. Nulla scelerisque +ornare ex, vitae mattis libero luctus eget. Donec venenatis lorem ut porta +dignissim. Suspendisse consectetur enim id arcu interdum rhoncus. Nunc +efficitur elit a magna fringilla bibendum vitae nec mauris. Orci +varius natoque penatibus et magnis dis parturient montes, nascetur +ridiculus mus. Proin a ultrices augue, sed facilisis mauris. Class +aptent taciti sociosqu ad litora torquent per conubia nostra, per +inceptos himenaeos. Proin consequat finibus felis, egestas pulvinar +turpis facilisis vel. Maecenas vitae mattis tortor. + +Pellentesque semper mattis ultricies. Duis convallis malesuada urna, eget +facilisis metus commodo et. Sed ut lectus varius, consectetur ipsum vel, +tincidunt tellus. Curabitur malesuada ex ut ipsum pretium, sed venenatis +magna vehicula. Orci varius natoque penatibus et magnis dis parturient +montes, nascetur ridiculus mus. Donec congue ac nunc eget auctor. Nunc +placerat, leo eu sodales euismod, magna justo consectetur erat, vel +consequat est tortor sit amet eros. Nullam euismod mi ac erat tempus, +nec elementum justo bibendum. Sed hendrerit pulvinar lectus et mollis. + +Etiam tempor, tortor nec ultricies aliquet, turpis purus sollicitudin +diam, ullamcorper faucibus lorem diam sed sem. Quisque vitae mauris +quis magna fringilla ornare et egestas nunc. Ut maximus libero vitae +dolor luctus rutrum. In suscipit erat id pretium bibendum. Pellentesque +tincidunt sapien accumsan commodo lobortis. Nam auctor, enim nec placerat +convallis, orci metus laoreet libero, sed rhoncus neque quam et lacus. In +eu faucibus velit. Quisque ac dignissim libero. + +Donec porttitor elit eget neque consectetur aliquam. Maecenas elementum +felis ac eleifend imperdiet. In facilisis, est at accumsan euismod, lacus +lorem rhoncus diam, eu egestas magna risus non purus. Aliquam eleifend ex +molestie porttitor porta. Interdum et malesuada fames ac ante ipsum primis +in faucibus. Morbi ac pretium mauris. Nulla ullamcorper magna at justo +aliquet interdum. Mauris vel lacinia lorem. Cras enim augue, convallis in +gravida at, pellentesque eu neque. Nam nec augue feugiat, euismod sapien +at, gravida nisl. Quisque nisl leo, cursus sit amet purus vitae, ultrices +vulputate velit. Nam a ultricies magna. Vestibulum tellus mi, dictum a +euismod non, aliquam vitae turpis. Vivamus tincidunt tincidunt dignissim. + +Cras nec vestibulum felis. In vel feugiat risus. Etiam pellentesque +malesuada quam. Maecenas in dapibus leo. Aenean ultricies aliquet +risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices +posuere cubilia Curae; Ut eget arcu tellus. Aenean quis nisi accumsan, +eleifend nulla et, varius neque. Nulla eget sodales erat. + +Nam rhoncus est augue, sit amet viverra lectus euismod in. Proin +consectetur, quam eget porttitor porttitor, quam orci imperdiet lorem, +eu sollicitudin justo ante a lacus. Curabitur eget viverra turpis, ut +sollicitudin lorem. Donec porta sapien vel mollis scelerisque. Nullam +rutrum nibh sed turpis ullamcorper, ac interdum lacus sagittis. Duis at +dictum eros, ut lacinia erat. Pellentesque ut rutrum neque, sit amet +elementum mi. Integer congue eros nec lorem consectetur, eu imperdiet +sem consectetur. + +Mauris lobortis, felis id dignissim ultricies, massa felis porta mi, sed +fringilla nisl ipsum ac felis. Sed lobortis non diam id fringilla. Duis +sit amet egestas quam, consectetur facilisis lectus. Cras efficitur +risus sed lacus congue, eu rhoncus nibh ornare. Vestibulum tincidunt +nulla risus, vel consequat turpis auctor ut. Pellentesque eu lectus +convallis, ullamcorper nisi sit amet, porta leo. Aenean semper lorem eget +tincidunt blandit. Etiam est nunc, ullamcorper ut mollis id, convallis +quis lectus. Duis sed porta ipsum, ac gravida nulla. Class aptent +taciti sociosqu ad litora torquent per conubia nostra, per inceptos +himenaeos. Vivamus sit amet justo eget lectus ultricies dictum. Sed +malesuada congue diam at accumsan. In ac nisl rhoncus, suscipit purus +et, lacinia ante. Curabitur purus lectus, tempor vel magna quis, mollis +egestas quam. Sed tincidunt erat quis sapien rhoncus, in dapibus ante +interdum. + +Mauris consequat velit elit, et cursus orci cursus posuere. Nullam in +volutpat erat, eget commodo lacus. Proin sed metus quam. Suspendisse +potenti. Donec auctor justo quis fermentum porttitor. Nam a velit vitae +justo hendrerit blandit fringilla rhoncus magna. Morbi et eleifend +lectus, ut luctus eros. Ut aliquet, ipsum eget eleifend pharetra, felis +massa iaculis lorem, ac suscipit diam enim ac nunc. In volutpat elit eu +faucibus vestibulum. Duis id urna faucibus, dictum nisl non, ullamcorper +urna. Pellentesque finibus et nibh eget commodo. Mauris feugiat efficitur +aliquam. Curabitur lacinia mollis arcu at condimentum. In et lorem +purus. Vivamus elit mauris, laoreet in ipsum sed, mollis malesuada arcu. + +In ut diam in leo vestibulum consectetur. Nunc sagittis enim nec tellus +lacinia vehicula. Nunc sapien nulla, condimentum ut malesuada eget, +varius et sapien. Donec sodales auctor velit eget vestibulum. Sed at enim +a turpis volutpat ultricies. Ut tincidunt vestibulum viverra. Vivamus +a purus et orci blandit pharetra. Nulla feugiat augue sed libero +tincidunt, sit amet consequat est bibendum. Nunc et dolor id magna +condimentum tristique ac ac lorem. Fusce tincidunt, ipsum ac ornare +sodales, nunc libero pellentesque elit, vitae consectetur nulla nisl +eleifend risus. Pellentesque ultricies neque a odio hendrerit finibus +vel quis eros. Phasellus sit amet feugiat lectus, sit amet ullamcorper +ligula. Donec quis condimentum metus, non facilisis ipsum. Vivamus quis +venenatis eros. Pellentesque ac pellentesque sem. Etiam tincidunt justo +ultricies dolor ornare venenatis gravida auctor neque. + +Etiam dapibus orci mauris, sed lacinia arcu congue nec. Aenean aliquet +molestie scelerisque. Aliquam tempus nunc nunc, ut molestie tellus +posuere sit amet. Sed faucibus faucibus tortor. Integer lorem ligula, +pellentesque vitae purus nec, fringilla tempor nisi. Nam euismod +luctus ex, nec tincidunt nibh euismod vitae. Vivamus luctus fermentum +pretium. Fusce in tempor enim. Nulla tincidunt nibh vestibulum enim +semper, vel porta dui mattis. Phasellus euismod ipsum efficitur justo +mollis pellentesque. Maecenas vehicula urna quis odio aliquet sagittis +id a ipsum. Vestibulum cursus enim vitae risus sodales volutpat. Cras +lacus purus, blandit dignissim felis vitae, bibendum dictum velit. Aenean +vestibulum tristique felis, at facilisis quam dictum in. Sed ac nisl +pharetra, egestas enim vel, hendrerit tellus. Maecenas id aliquet lectus. + +Sed rutrum sit amet nulla eu commodo. Curabitur scelerisque ante molestie, +dignissim quam in, faucibus lorem. Proin non varius dolor. Nulla metus +lectus, ullamcorper in augue a, fringilla interdum nisl. Duis condimentum +nulla ac neque commodo, eget lobortis nibh porttitor. Nunc sapien felis, +interdum vitae lectus quis, luctus ullamcorper tortor. Nunc quis metus +at velit bibendum suscipit. In vitae placerat dolor, mollis rutrum +purus. Pellentesque ut lacus eu mi sagittis aliquet. Nullam quis auctor +ante, sit amet dapibus nisi. Etiam a nisi sit amet nibh aliquet pulvinar +quis vitae erat. Quisque sollicitudin risus quis eros egestas dictum. + +Cras molestie id libero a varius. Lorem ipsum dolor sit amet, +consectetur adipiscing elit. Aliquam erat volutpat. Integer at tortor +ac mauris rhoncus aliquam et consectetur urna. In hac habitasse platea +dictumst. Suspendisse venenatis quis elit in lobortis. Donec tristique +dictum sodales. Mauris nec pretium ex. Donec sit amet condimentum +odio. Nullam molestie tempus magna. Nunc nec orci in felis porta +porttitor. + +Fusce ut tincidunt felis. Pellentesque fermentum ipsum a felis +lacinia, nec mattis nibh accumsan. Etiam lobortis elit at elit +vestibulum, quis suscipit felis tincidunt. Morbi bibendum efficitur +tortor et hendrerit. Donec eget lorem vitae odio varius elementum +non id nisl. Quisque eu lacinia massa. Sed fringilla ac tellus +in dignissim. Vivamus at nulla vulputate, cursus lorem tristique, +suscipit lacus. Quisque nulla massa, tempor non mollis ac, pretium eget +augue. Maecenas laoreet blandit lorem non iaculis. Proin ornare ac nisi +sed rutrum. Pellentesque rutrum tortor eu metus convallis venenatis. Proin +vel nunc scelerisque, sagittis nisl ac, luctus velit. Cras lacinia nulla +porta viverra interdum. Cras interdum lorem risus. + +Morbi leo dolor, varius quis tincidunt id, varius ac ipsum. Donec ornare +est et enim vehicula, id condimentum nunc feugiat. Morbi ullamcorper +dapibus ligula eget dignissim. Duis interdum laoreet orci a posuere. Donec +eros nibh, finibus viverra ex a, venenatis faucibus massa. Class aptent +taciti sociosqu ad litora torquent per conubia nostra, per inceptos +himenaeos. Donec dignissim magna eget neque dapibus, ac pretium sem +porta. Donec viverra hendrerit nisl, ultrices tristique tortor luctus +eget. Integer porttitor ipsum mauris, sed aliquet tortor suscipit +sed. Vivamus eget orci ultrices, convallis ante non, volutpat ex. Cras +vestibulum mi neque, et tempor elit hendrerit eget. Pellentesque ipsum +sem, dictum nec erat vel, eleifend lacinia sapien. Sed eu sollicitudin +est, ac tristique eros. Proin sed porttitor tellus. Sed accumsan convallis +tellus at eleifend. + +Donec in mollis odio. Etiam ac justo nunc. Pellentesque rhoncus fringilla +eros quis pharetra. Nam sit amet nisl nisl. Sed non purus vitae felis +tempor pretium. Mauris vitae lectus posuere, tincidunt nulla in, lacinia +purus. Proin euismod id lorem nec vulputate. Aenean vitae ipsum at risus +hendrerit semper eu in sem. + +Aliquam et sapien purus. Mauris dignissim erat vitae egestas tempus. Morbi +ut purus in ipsum fringilla gravida sed in tellus. Fusce felis metus, +ultrices ac porta non, facilisis at purus. Nulla non tortor eget lorem +convallis placerat. Duis ac felis orci. Nullam hendrerit consequat ante +in malesuada. + +Aliquam aliquam metus id massa hendrerit facilisis. In consectetur mi +lorem, quis tempus ipsum pharetra ac. Maecenas ut metus feugiat, luctus +nisl auctor, aliquam sem. Vestibulum in consequat velit, nec dignissim +odio. Sed gravida elit sit amet finibus fringilla. Aliquam eget venenatis +tellus. Sed ut diam a purus finibus faucibus at id nibh. Vivamus ac +libero orci. Suspendisse sit amet laoreet augue. Nullam vel dolor +condimentum, volutpat augue at, interdum quam. Curabitur vehicula, +sem ornare mollis placerat, mauris metus blandit eros, sed volutpat ex +dolor in mi. Curabitur tempor mauris nec dolor fringilla facilisis in +in odio. Sed fermentum congue sollicitudin. Pellentesque dapibus, elit +dapibus condimentum imperdiet, enim metus fringilla est, ac porttitor +felis arcu ac nisl. Quisque sagittis feugiat condimentum. Vivamus diam +enim, pellentesque ac dictum sed, ultrices vel odio. + +Suspendisse nec arcu vel nisl interdum molestie. Duis finibus lacus eros, +malesuada dignissim leo cursus sed. Ut feugiat facilisis libero. Cras +quis magna ac orci lobortis euismod at a risus. Proin facilisis enim +vitae dolor consequat imperdiet. In tempor sodales lorem, hendrerit ornare +lacus consectetur egestas. Morbi in dictum diam. In hac habitasse platea +dictumst. Donec malesuada lorem vitae interdum luctus. Mauris auctor, +urna nec ornare tempus, felis nisl congue metus, eget elementum justo +sem quis nulla. Cras consectetur eget mi at malesuada. Sed vel ex +condimentum, rutrum eros ac, semper augue. Sed vel facilisis magna, +in pulvinar nisl. Suspendisse sit amet turpis sem. Praesent in leo +efficitur ligula blandit commodo. + +Donec pellentesque nibh quis magna consectetur, blandit aliquam odio +fermentum. Maecenas dapibus hendrerit enim, in sagittis enim interdum +a. Vestibulum laoreet ante in lacus mattis vehicula. Vivamus molestie +molestie rutrum. Sed tristique augue et mi imperdiet, non convallis +tellus eleifend. Nunc porttitor est ut mauris aliquam, in auctor enim +sollicitudin. Nunc a ligula neque. Quisque non ante in est rutrum +volutpat quis ac eros. Sed bibendum felis in elit condimentum, a semper +turpis consequat. + +Maecenas erat risus, tempus quis convallis vel, faucibus sed libero. Sed +lacinia, arcu rutrum accumsan suscipit, augue risus pulvinar dui, +eu egestas ante lorem a quam. Praesent dapibus tempor lectus sit amet +scelerisque. Curabitur tempor laoreet arcu, ultrices gravida elit posuere +sit amet. Vivamus laoreet ac massa sed blandit. Morbi ut quam quis eros +egestas tincidunt. Curabitur laoreet vehicula neque, eget interdum mi +auctor nec. Vivamus fringilla sed velit sed convallis. Sed fermentum +risus ultrices velit tempus, sed congue tortor imperdiet. Sed pharetra +lorem in purus bibendum, vel fermentum nunc sagittis. Cras mauris purus, +eleifend eu commodo ac, facilisis a sem. + +Nullam commodo nisi odio, vitae pellentesque sapien mollis ac. Maecenas +tristique nisi vel metus euismod fringilla. Aenean tristique enim ante, +vitae ultricies mi suscipit eget. Cras condimentum ipsum ipsum. Integer +vestibulum molestie nunc. Duis fermentum, sem in cursus tristique, +lectus diam porttitor tellus, at porta enim erat quis leo. Phasellus +accumsan odio ipsum, in pretium neque faucibus sit amet. Curabitur +et nunc non libero sagittis condimentum. Mauris malesuada, mauris nec +malesuada aliquet, nunc massa mollis enim, vitae elementum lorem tellus +non neque. Vestibulum interdum posuere lectus. Duis elementum, ipsum sit +amet facilisis venenatis, lacus magna dignissim risus, ac elementum magna +leo id elit. Integer urna tellus, tincidunt quis ipsum vitae, eleifend +congue massa. In ut velit ut purus euismod posuere. Vestibulum in luctus +nulla, nec faucibus metus. Proin placerat lobortis velit. Praesent vel +elit et tortor viverra tempor. + +Cras pretium sem in lectus maximus mollis. Donec ut fringilla +magna. Vestibulum in viverra velit. Ut quis sapien magna. Nam sit amet +ultrices ipsum. Nullam in bibendum ligula. Vivamus posuere velit at tellus +dapibus, convallis tristique enim blandit. Mauris fringilla ullamcorper +eros vitae maximus. Interdum et malesuada fames ac ante ipsum primis in +faucibus. Sed enim diam, rhoncus id viverra nec, iaculis ullamcorper +dolor. Aliquam fringilla metus neque, nec venenatis felis consequat +facilisis. Etiam malesuada convallis lectus eu finibus. Nunc est elit, +ultrices id pulvinar aliquet, volutpat at dui. Nunc vitae nisi vel sapien +finibus facilisis. + +Donec sit amet justo pretium, porttitor eros sit amet, tincidunt +nisi. Pellentesque eget blandit quam, in pulvinar nulla. Maecenas +id pretium lectus. Duis vehicula massa nec velit accumsan +malesuada. Curabitur vitae orci nulla. Sed sit amet nisl mollis, iaculis +odio at, blandit felis. Quisque ut lectus lacus. Orci varius natoque +penatibus et magnis dis parturient montes, nascetur ridiculus mus. In +dictum dolor eu arcu feugiat vestibulum vel a enim. + +Vestibulum sed leo congue, molestie mauris vitae, condimentum +felis. Aliquam ac sapien at neque convallis mollis mattis eget dui. Nullam +nec massa lorem. Duis suscipit porta tincidunt. Nam congue tortor eleifend +pellentesque fermentum. Integer nec purus sed enim sodales aliquam. Nulla +in ornare ipsum, nec facilisis enim. Nulla rutrum vitae massa lobortis +hendrerit. Vivamus vel congue massa, eget porttitor dolor. Quisque in +venenatis tellus. Fusce accumsan, nulla eu gravida aliquet, eros nisi +accumsan nunc, id mattis est tellus vel felis. Praesent dignissim mi at +nulla tempor gravida. Nullam hendrerit purus neque, vitae suscipit libero +blandit sed. Vivamus ut justo semper, vestibulum lectus ut, blandit purus. + +Donec feugiat mattis libero sit amet laoreet. Nunc eget diam lorem. Fusce +volutpat neque at nulla rutrum, eget tempus arcu ultricies. Duis ornare +nunc scelerisque metus porta, eget lobortis sem dapibus. Aenean in nisi +quis urna consequat dapibus. Ut nec ante ut justo semper sollicitudin +id a nulla. Vivamus pharetra finibus erat a ornare. + +Integer sollicitudin, lorem ut euismod pellentesque, mauris odio +laoreet orci, at porta lorem lacus et tellus. Duis in tellus congue, +viverra ligula eget, vestibulum ex. Sed nisl nibh, cursus vel purus et, +tincidunt venenatis sapien. Phasellus et scelerisque massa, nec cursus +libero. Nunc et urna lectus. Aenean interdum, augue ac accumsan iaculis, +odio nisi venenatis sem, non pretium tellus metus sed nisl. Cras tempus +ante suscipit, fermentum justo maximus, tincidunt libero. Ut pulvinar +ex id libero ultricies, quis faucibus ipsum gravida. Proin faucibus ante +laoreet neque imperdiet, id tincidunt ipsum viverra. + +Proin dignissim arcu sed lacinia fermentum. Proin at felis ac elit +consectetur pellentesque vel ut quam. Phasellus volutpat semper +consectetur. Praesent diam felis, cursus in magna vel, semper +bibendum quam. Integer eros leo, tempor non est ut, consequat +suscipit est. Praesent tincidunt dolor quis nisl posuere, ut mattis +dolor ullamcorper. Aliquam pharetra vulputate ligula sit amet +iaculis. Pellentesque vitae tortor urna. Fusce lectus ligula, luctus +quis dignissim quis, lacinia vel nisi. Nunc a est orci. Cras eu sapien +accumsan, fermentum elit eu, suscipit ipsum. In scelerisque justo +laoreet augue bibendum, at vestibulum urna imperdiet. Vivamus tortor +nisl, dapibus id enim at, tincidunt sodales lectus. In eget sodales +neque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, +per inceptos himenaeos. + +Curabitur efficitur felis in blandit pulvinar. Proin ultrices pretium +magna sed sagittis. Quisque et sem rhoncus, dapibus lorem non, tincidunt +tortor. Proin id viverra velit, id ullamcorper nibh. Praesent purus diam, +congue non blandit eget, ultrices sagittis lorem. Vivamus id tortor +sit amet dui vulputate interdum a at nisl. Ut eleifend tristique sem, +sagittis tincidunt tortor aliquet ut. Aliquam commodo ligula tellus, in +interdum risus condimentum a. Sed rhoncus, dolor malesuada vestibulum +vehicula, neque est pellentesque est, nec semper tortor arcu nec +neque. Maecenas hendrerit risus et urna faucibus tempor. Suspendisse +sed gravida elit, quis consequat libero. Sed lectus ex, scelerisque sed +ligula lobortis, posuere facilisis sapien. Praesent porttitor tristique +dui non pellentesque. Ut malesuada, ante ut mattis lacinia, justo est +volutpat turpis, id lobortis enim tellus et tellus. + +Ut vitae est ut sapien malesuada venenatis. Nam euismod venenatis +sapien, eu fringilla urna. Morbi accumsan eleifend arcu, non tristique +orci dapibus vel. Sed eleifend ut eros nec pretium. Aenean eget laoreet +neque. Curabitur non mi malesuada, suscipit est at, egestas velit. Aenean +quis libero ultricies, vehicula lorem vel, semper orci. Morbi vitae +efficitur ex. Ut ultricies lacus vitae augue consequat, bibendum tempor +dolor luctus. Nunc mi ipsum, egestas vel dictum id, facilisis nec dui. + +Vivamus non commodo nunc, quis interdum leo. Phasellus sit amet orci in +risus gravida pellentesque ut eu erat. Curabitur hendrerit a orci vitae +convallis. Sed sagittis ipsum massa, sit amet ultrices tortor facilisis +nec. Donec mattis odio sed mi tincidunt commodo. Ut at rhoncus sapien, +ac facilisis nisi. Sed interdum orci a ante scelerisque, porttitor +elementum metus sagittis. Ut placerat neque enim, vitae consectetur +tellus dapibus a. + +Nulla pulvinar nibh non lectus facilisis, eget facilisis lacus +bibendum. Mauris commodo, sapien ac viverra posuere, odio neque mattis +dui, vel rhoncus mauris enim at eros. Quisque vulputate metus arcu, +ut facilisis elit sagittis nec. Curabitur a nibh vitae risus eleifend +varius sed a neque. In a neque enim. Aliquam vel nunc eros. Aenean +viverra eget elit eu feugiat. Nulla enim quam, porta eu sapien nec, +sollicitudin lacinia dolor. Vestibulum ut ex molestie, lacinia erat ut, +tristique dui. Proin dui dolor, lobortis ac enim sit amet, scelerisque +interdum nisi. Aenean efficitur malesuada ante. + +Proin luctus, ligula at dignissim sodales, erat velit porttitor eros, quis +euismod turpis ipsum ac nunc. Vestibulum in risus orci. Etiam placerat +tortor mollis sagittis congue. Donec ex enim, interdum vehicula massa +facilisis, ultricies feugiat arcu. Pellentesque ornare, purus sit amet +molestie sodales, elit risus ultricies tortor, vitae maximus neque felis +ac orci. Etiam ac quam sit amet lorem pretium pharetra. Suspendisse ut +purus vulputate, sollicitudin eros viverra, eleifend leo. Nulla sodales +eget urna vitae congue. Praesent in nisi faucibus neque pretium dapibus +in at lacus. + +Nam ut tellus fermentum ligula vestibulum mattis non vel sem. Aenean orci +lorem, varius ac pharetra id, vestibulum et tortor. Aliquam convallis +sagittis dictum. Nunc porttitor mauris in ipsum maximus viverra. Mauris +euismod, tortor condimentum dictum vestibulum, orci lectus pharetra diam, +eget pellentesque velit tortor ut libero. Phasellus et libero massa. Proin +non ultricies libero. Proin accumsan risus vel nunc rutrum, non pretium mi +porta. Proin facilisis imperdiet odio, ut vehicula enim auctor ac. Duis +finibus lectus eu nulla finibus, eget auctor augue pharetra. Quisque et +mauris ipsum. Vestibulum rhoncus sit amet felis eu sagittis. + +Nullam dictum dignissim nisi at tincidunt. Sed vulputate pulvinar elit, +nec ullamcorper risus. Mauris nec bibendum augue. Maecenas laoreet felis +interdum ligula viverra, eu aliquet leo rhoncus. Curabitur in tincidunt +ligula, quis congue dui. Morbi vel congue justo, eget condimentum +ante. In eleifend sed metus quis semper. Curabitur suscipit facilisis +nunc, sit amet imperdiet libero eleifend id. Phasellus sapien lectus, +rutrum eget tincidunt in, malesuada ut ex. Nam vel erat quis libero +ultricies lacinia sed in mauris. + +Cras sodales, justo eu gravida tincidunt, lacus tortor tempus mi, vitae +lacinia ipsum metus ut justo. Cras maximus magna ut nisl ultricies, +sit amet aliquet eros vestibulum. Etiam porta mollis vulputate. Nam +at dolor ut est facilisis auctor ac vestibulum purus. Quisque dolor +nisl, interdum at efficitur et, vestibulum a sapien. Vestibulum sodales +placerat pulvinar. Nulla rutrum felis in dolor lobortis, quis vulputate +diam feugiat. Proin sagittis enim vel nisi aliquet, eget mollis dolor +finibus. Aenean fringilla facilisis turpis sit amet tempor. Nam velit +purus, mollis sed placerat non, vulputate at libero. Donec non eleifend +libero. Donec porta varius consequat. Morbi dictum justo sem, sit amet +mattis sem varius quis. Maecenas eget congue urna. Phasellus fermentum +sodales ligula. Aliquam non faucibus ipsum. + +Sed at hendrerit ex, ac ultricies metus. Vestibulum ultrices mauris +a tellus varius ultricies quis sed elit. Nam vitae efficitur +massa. Phasellus a nunc magna. Nam posuere nisl at pellentesque +fermentum. Curabitur justo mauris, ultrices a elit ac, feugiat commodo +ligula. Maecenas sodales purus ac molestie semper. Quisque in maximus +orci. Cras arcu massa, ullamcorper in dolor eu, tristique euismod +tellus. Aliquam sollicitudin cursus nunc vitae eleifend. Donec nisi lacus, +iaculis a sem id, feugiat ullamcorper lectus. Integer et magna sit amet +lectus rutrum porttitor sed in mi. Quisque non enim dapibus magna tempus +pulvinar. In ipsum nunc, bibendum et metus eu, aliquam volutpat magna. + +Aliquam dictum in magna auctor volutpat. In volutpat, libero in +egestas tristique, elit eros hendrerit quam, ac dignissim elit velit +eu massa. Suspendisse in sem eget eros congue maximus non eleifend +purus. Donec eleifend, mi eget imperdiet placerat, tortor nisi bibendum +nisi, vel mollis ante massa eu est. Sed laoreet gravida quam sed +blandit. Duis tincidunt orci vitae mauris ultrices venenatis. Vivamus +efficitur felis et ultricies bibendum. Aliquam erat volutpat. + +Curabitur fringilla finibus cursus. Vestibulum diam eros, auctor in nisi +eu, rhoncus molestie urna. Donec quis erat eu dolor consequat lacinia quis +eu ante. Aliquam gravida non nunc eu blandit. Mauris efficitur ultricies +velit, id tincidunt eros luctus gravida. Nam vel lorem et dolor volutpat +sagittis at in lacus. Duis aliquam odio at eros tincidunt, ac facilisis +diam dignissim. Aliquam ornare nulla nec rhoncus dignissim. Vivamus +rhoncus eleifend malesuada. Maecenas mattis, arcu ut mattis porttitor, +urna sem pretium velit, non sodales felis nunc ut eros. + +Sed sodales blandit tincidunt. Nulla lorem nulla, laoreet vel tristique +placerat, faucibus non dolor. Mauris tempor tristique nisl quis +sollicitudin. Cras nec tortor facilisis, feugiat nisl eget, dapibus +leo. Nunc eu nisi posuere purus viverra rutrum. Integer ut tempor eros, +in blandit ipsum. Nullam eget faucibus augue. Interdum et malesuada +fames ac ante ipsum primis in faucibus. Suspendisse potenti. + +Integer elementum vestibulum elementum. Suspendisse varius, velit +consequat consectetur bibendum, sem nibh molestie dolor, in tempor +ipsum urna eget metus. Quisque vel sodales quam, ut semper leo. Aenean +condimentum vitae nibh in accumsan. Fusce elementum laoreet risus, nec +consectetur magna. Nullam in molestie ipsum. Proin at nisl mi. Aenean +pulvinar velit quis semper elementum. Nam vehicula leo sed auctor +venenatis. Suspendisse eget volutpat lorem. + +Ut vel leo sollicitudin, pulvinar elit vel, consequat enim. Maecenas +scelerisque efficitur lorem, sit amet maximus lacus. In hac habitasse +platea dictumst. Phasellus pulvinar sed odio nec faucibus. Donec +fringilla quam nec finibus fermentum. Integer tellus diam, dapibus nec +dolor eget, facilisis sagittis purus. Morbi ullamcorper dictum ante, quis +blandit neque porta quis. Nam et fermentum ligula, id lacinia leo. Etiam +luctus finibus est nec maximus. Donec luctus vehicula malesuada. Vivamus +ullamcorper nunc arcu, sed tristique ex sollicitudin eu. Proin pulvinar +sapien sed eleifend lacinia. Vivamus a neque gravida, scelerisque felis +et, semper ligula. Donec tristique elementum est, eget molestie erat +elementum at. + +Fusce a sem molestie, egestas sapien in, pretium urna. Nulla in orci et +augue congue eleifend. Pellentesque vel tortor maximus, tempus mi et, +maximus urna. Integer molestie nibh ullamcorper leo mollis, ac hendrerit +nunc facilisis. Vivamus congue porttitor porttitor. Suspendisse volutpat +cursus tempor. Sed commodo diam sed arcu tempor, eu accumsan sapien +vehicula. Nam sagittis dignissim urna sit amet cursus. Pellentesque +habitant morbi tristique senectus et netus et malesuada fames +ac turpis egestas. Aliquam at ante vulputate, accumsan est non, +vehicula lorem. Fusce posuere nulla nulla, nec rutrum felis interdum sit +amet. Vivamus non nulla leo. Phasellus auctor, ante ut aliquam fermentum, +risus ex congue lacus, eu luctus risus massa nec lacus. Donec metus +felis, porta vitae faucibus id, scelerisque in arcu. Aenean viverra mi +non libero mattis, nec placerat nibh elementum. Aenean lectus lorem, +lobortis at lobortis quis, ultrices at odio. + +Nam sagittis nisi est, ut congue neque egestas id. Sed aliquet ultricies +nulla, sed consectetur eros scelerisque et. Curabitur sed risus vitae +dui euismod vestibulum a sed metus. Fusce vehicula fermentum ex at +facilisis. Sed eget rhoncus justo. Sed sed nulla nibh. Cras felis +odio, tristique bibendum urna quis, bibendum egestas lacus. Nulla +dignissim enim at venenatis tincidunt. Nam dapibus eget velit id +pretium. Aliquam tincidunt venenatis pellentesque. Quisque eleifend +faucibus mi at consectetur. Vivamus mattis porta libero, ac dictum metus +auctor id. Vestibulum pretium luctus lobortis. In hac habitasse platea +dictumst. Integer ut nulla tincidunt, pharetra erat non, porttitor odio. + +Vivamus in ullamcorper arcu, eu venenatis turpis. Nunc consectetur +augue sed mauris semper blandit. Nullam lacinia sem purus, ut luctus +ligula aliquet eu. Proin ac efficitur tortor. Sed elementum metus enim, +id pretium metus egestas a. Mauris malesuada congue pulvinar. Fusce +suscipit eu nulla a lobortis. Nunc a nisl nibh. Etiam eu augue porttitor +eros lacinia ullamcorper. Nullam ac diam et lorem feugiat lacinia at +vitae risus. + +Vestibulum molestie metus non neque aliquet, a venenatis mi +dignissim. Aenean convallis eleifend dui, sed venenatis lorem egestas +sollicitudin. Sed viverra cursus blandit. Fusce egestas faucibus urna +in commodo. Nam lobortis turpis et nunc ornare posuere. Aenean quis +nisi vestibulum, bibendum risus eget, facilisis quam. Aenean ac magna +rutrum, bibendum sapien nec, volutpat sem. Suspendisse nec odio interdum, +luctus nisl vitae, facilisis turpis. Vivamus in tellus urna. Quisque +sit amet posuere leo, quis condimentum orci. Etiam quis mauris sit amet +nunc sodales interdum sit amet nec augue. Curabitur eu felis eu arcu +ornare rutrum. + +Cras ut orci dui. Donec placerat eros eu condimentum aliquam. Nulla sed +turpis at mi condimentum pharetra. Morbi vulputate urna sit amet augue +accumsan, id eleifend magna efficitur. In non venenatis risus. In vel +nunc urna. Etiam dictum, arcu varius congue faucibus, enim velit pharetra +ante, vel rhoncus odio velit quis justo. Nulla aliquet enim sit amet +tortor fringilla, in tincidunt tortor congue. Nam sit amet dui ac purus +gravida luctus quis et ipsum. Mauris dictum metus orci, ut tincidunt +quam ornare et. Etiam a ipsum erat. Nam mattis, libero eget placerat +ultricies, lectus nisl iaculis nibh, ac ultrices mauris metus vitae risus. + +Donec molestie ante non nulla fringilla, eu interdum ligula +egestas. Maecenas lectus metus, tincidunt ut ultrices vestibulum, porta +vel odio. Donec quis nisi rhoncus, porttitor tellus vitae, condimentum +sem. Quisque ac venenatis urna. Pellentesque et quam diam. Etiam quis +dapibus est. Cras luctus augue quis gravida blandit. Integer at feugiat +sapien. Vivamus suscipit libero vel faucibus pellentesque. + +Sed tincidunt maximus diam, sed aliquam lorem. Aliquam nec vestibulum +ante. Curabitur laoreet dui vel augue convallis, ac consequat mauris +aliquet. Sed sed massa maximus, auctor nunc ut, ultrices tellus. Nunc +et sodales dui. Morbi in vestibulum eros, sed tristique urna. Nunc +dictum, ante in ullamcorper molestie, elit ligula ullamcorper sem, id +vehicula enim libero eget est. Mauris iaculis lobortis vulputate. Integer +efficitur luctus nulla vel dictum. Aliquam at augue volutpat, gravida +est eget, aliquam tortor. Ut sed ante ligula. In tempus nulla eu euismod +commodo. Vestibulum a quam facilisis, vulputate lacus a, porttitor +purus. Nam eleifend quam sit amet eros bibendum dictum. Morbi convallis +cursus dignissim. Donec quis libero ullamcorper, auctor arcu porta, +vulputate ex. + +Ut egestas rhoncus ipsum non vulputate. Pellentesque ac diam non magna +semper eleifend. Maecenas lacinia bibendum ullamcorper. Donec felis quam, +vulputate at nisi quis, bibendum congue tortor. Interdum et malesuada +fames ac ante ipsum primis in faucibus. Suspendisse potenti. Sed +ullamcorper tristique nibh, eu mollis tellus rutrum eu. Quisque porta +auctor urna eget faucibus. Pellentesque habitant morbi tristique senectus +et netus et malesuada fames ac turpis egestas. Maecenas laoreet orci +dictum tortor laoreet ornare. Suspendisse potenti. Ut at elit in metus +semper consequat. + +Aliquam erat volutpat. In semper rutrum elit, in ultricies orci hendrerit +in. Quisque nec maximus massa, sed vestibulum mauris. Donec nisi risus, +fringilla ac est a, mattis finibus est. Etiam velit turpis, suscipit sed +augue et, euismod congue lacus. Pellentesque ut arcu ut tellus iaculis +faucibus quis non odio. In at mauris ac quam mattis fermentum. Etiam +eget sem non diam rutrum ultricies. + +Nunc porta, est in ultricies varius, sem diam scelerisque ante, eget +mattis mauris nisi ac mauris. Orci varius natoque penatibus et magnis +dis parturient montes, nascetur ridiculus mus. Integer dolor dui, mattis +eu congue ut, blandit non dolor. Mauris at quam eleifend, dignissim +augue ac, euismod ex. Nulla dictum tristique ipsum nec sagittis. Sed +et orci viverra, viverra orci ut, maximus nunc. Sed sed laoreet massa, +eleifend convallis risus. Aenean pellentesque faucibus eros. In rhoncus +accumsan nisl, vitae aliquam massa convallis eget. Praesent a tincidunt +justo, a tincidunt lectus. Donec et lacus nec odio volutpat placerat in +id mi. Nullam euismod justo sit amet rutrum fermentum. Vivamus semper +enim eu elit tristique feugiat. + +Maecenas non ornare quam. Praesent varius eros eu nisl hendrerit, ut +lobortis sapien interdum. Praesent aliquet et neque at suscipit. Maecenas +pharetra ullamcorper maximus. Curabitur fermentum nibh nec nisl accumsan +gravida. Quisque tempus consectetur dolor vitae fringilla. Curabitur +ut iaculis orci. Nullam a quam augue. Vivamus viverra pulvinar +vulputate. Donec aliquet justo id justo pharetra, vitae rhoncus neque +aliquam. Proin in augue eget turpis ornare pharetra et id arcu. Nulla +id varius turpis. Nunc eu viverra ligula. Donec porta tellus id libero +viverra, ac lacinia odio scelerisque. Cras dignissim felis id mollis +rhoncus. Suspendisse potenti. + +Vestibulum id nunc et felis pulvinar dignissim in quis erat. Nam nec +enim at purus ullamcorper porta. Pellentesque bibendum lectus ligula, +vel tempor lectus viverra nec. Suspendisse potenti. Nulla eget orci eget +metus consectetur vestibulum. Maecenas luctus, lectus nec viverra commodo, +tortor lorem iaculis risus, eget gravida sapien massa et mauris. Mauris +nec elementum sem. Aliquam quis leo erat. Quisque sem augue, gravida ac +scelerisque quis, venenatis nec nisl. Aenean convallis, nunc in interdum +blandit, dui lorem luctus felis, mollis imperdiet lacus libero ac odio. + +Aliquam erat volutpat. Integer laoreet consequat lectus, at imperdiet +augue fringilla in. Aliquam tincidunt interdum risus, id molestie purus +lacinia a. Maecenas quis finibus leo. Mauris id condimentum felis, +in finibus urna. Cras fermentum metus ut augue molestie sodales. Proin +pretium purus nec erat varius vestibulum. Cras blandit augue felis, non +tincidunt leo cursus at. Sed eleifend, tellus scelerisque tempus vehicula, +est lorem posuere quam, a volutpat ante tellus sed arcu. Pellentesque +eros elit, porta id hendrerit eget, consectetur ut lectus. Vestibulum +ornare ac lacus ac suscipit. Curabitur egestas mattis felis, in pretium +libero viverra non. Class aptent taciti sociosqu ad litora torquent +per conubia nostra, per inceptos himenaeos. Mauris nec erat elementum, +porta lectus ut, malesuada massa. + +Fusce lobortis tortor vel ipsum consectetur, eget feugiat dui +rutrum. Mauris nisi sem, ullamcorper in porta ac, efficitur non +est. Pellentesque sodales nulla sit amet aliquam ornare. Fusce et +feugiat ligula. Donec interdum aliquam est, non consectetur magna +lacinia vitae. Praesent ac ex vulputate, ultrices ligula in, fringilla +turpis. Quisque sed mi id libero pharetra faucibus ut ut ligula. + +Curabitur venenatis mauris quis erat ullamcorper gravida. Mauris felis +odio, viverra sed imperdiet a, finibus sed velit. Donec condimentum +porta nibh, in lobortis lectus suscipit vel. Nam massa metus, consequat +ullamcorper blandit ut, ullamcorper ut odio. Duis fermentum enim eu nulla +viverra scelerisque quis at lacus. Vivamus vel rutrum dui. Phasellus +convallis lectus sit amet elit lobortis auctor. Aliquam erat volutpat. + +Integer bibendum interdum eros, nec viverra magna cursus ac. Curabitur +ultricies felis efficitur elit posuere mollis. Morbi consectetur +sapien nec maximus sollicitudin. Nam sodales ligula quis elit +dapibus, vitae condimentum lorem pharetra. Aenean volutpat in mi at +scelerisque. Suspendisse tincidunt magna risus, vel volutpat mi egestas +a. In hac habitasse platea dictumst. Vivamus quis nisl vel ipsum cursus +commodo quis in magna. Vivamus porttitor gravida leo a porta. Donec +mollis nunc nunc, ut elementum ante vehicula commodo. Morbi erat magna, +blandit eget porttitor a, porta vitae turpis. Donec et malesuada velit, +eget tempor massa. Morbi nec nisi vel diam mattis tristique. In a lacinia +ipsum, ac laoreet risus. Aliquam ultrices est eget dolor feugiat, id +tempus orci egestas. + +Aenean hendrerit imperdiet rutrum. Sed sed nunc quis dolor malesuada +convallis rhoncus ac ante. Etiam imperdiet arcu sit amet ex fermentum +mattis. Morbi cursus, massa sit amet efficitur blandit, tellus dolor +vehicula metus, eget varius felis ex sagittis velit. Curabitur scelerisque +libero diam, vitae volutpat purus mollis porttitor. Maecenas leo odio, +posuere sed venenatis a, pharetra sed ligula. Vestibulum quis neque +mattis, fermentum sapien et, dignissim nibh. Vivamus a quam porttitor +est consequat maximus. Nunc mauris ligula, euismod quis eleifend id, +pretium eu ipsum. + +Sed viverra magna id velit consectetur, quis viverra ligula semper. Nam +ullamcorper mollis purus, sed venenatis neque rhoncus bibendum. Phasellus +at lorem at urna ultricies auctor. Sed a venenatis diam, id iaculis +urna. Pellentesque elit eros, pulvinar in tristique non, pharetra pretium +nunc. Sed pretium lacinia lectus nec accumsan. Phasellus sollicitudin, +turpis eu convallis tincidunt, dolor tortor auctor quam, eu tincidunt +massa augue a ligula. + +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere +cubilia Curae; Aenean rutrum quam ac nisi vulputate, in dignissim tellus +vehicula. Pellentesque eget eros venenatis, luctus neque sit amet, +maximus ex. In varius tempus ultrices. Integer pharetra turpis mi, +nec auctor tortor varius at. Nam nec odio ut libero efficitur efficitur +id eu enim. Cras ac ligula non neque bibendum auctor eu id ante. Cras +vitae aliquam orci. Quisque tincidunt faucibus sapien. Donec consectetur +magna magna, quis commodo urna ullamcorper eget. Maecenas nulla erat, +fringilla ut mauris ut, laoreet auctor tortor. Quisque feugiat luctus +tellus, in lacinia ex porta at. Nulla quis auctor nunc, et dignissim ex. + +Integer vitae enim velit. Etiam congue libero vel porttitor aliquam. Sed +dui tellus, fringilla non dictum a, bibendum eu orci. Duis ornare +nisl eget pellentesque congue. Fusce augue diam, rhoncus quis urna +at, semper molestie velit. Mauris ut augue sit amet ipsum egestas +lobortis. Pellentesque tristique, sapien id cursus ultrices, risus sem +tincidunt tortor, non pharetra eros tortor at ante. Curabitur vitae +bibendum nisl, a lacinia lectus. + +Praesent mattis ante ac convallis interdum. Etiam ac tincidunt +tortor. Proin magna risus, commodo nec sem eu, mattis maximus +risus. Integer ante mi, ultrices in blandit ultrices, mollis +non odio. Aenean lacus purus, mollis sed facilisis eu, aliquet id +tellus. Aliquam pretium ante vitae convallis faucibus. Nunc euismod +eget purus vel pulvinar. Donec dictum augue sit amet felis eleifend +pulvinar. Maecenas interdum interdum convallis. Morbi pulvinar sem +congue, gravida augue at, faucibus nunc. Nunc luctus justo ac aliquet +faucibus. Quisque sollicitudin magna ac euismod vulputate. + +Donec neque lorem, elementum nec pharetra sit amet, euismod id enim. Class +aptent taciti sociosqu ad litora torquent per conubia nostra, per +inceptos himenaeos. Cras non sapien hendrerit, luctus augue sit amet, +porttitor enim. Nam auctor nunc quis mauris sollicitudin, sit amet +viverra ipsum ultricies. Ut id lectus ultrices, hendrerit enim eget, +accumsan ipsum. Aenean eget nisl eleifend, aliquet tellus ac, placerat +tortor. Nam imperdiet erat quis tellus ullamcorper, non commodo orci +tincidunt. Vestibulum eu ullamcorper purus. Donec in interdum enim, a +aliquet nibh. Nunc turpis orci, consequat eleifend odio in, ultricies +vulputate justo. Vivamus vitae sem in est placerat aliquam tempus at +lorem. In enim sem, dapibus quis feugiat a, elementum et magna. Mauris +pretium vel sem id vehicula. Ut id lectus risus. + +Quisque sem nibh, vulputate ut risus eget, egestas accumsan tortor. Duis +euismod, odio nec viverra gravida, urna elit consequat enim, eu rutrum +neque neque in dui. Sed fringilla massa quis orci mollis commodo. Sed +fringilla ultrices est tincidunt finibus. Duis sit amet tincidunt +lorem. Nullam sit amet ex id massa semper ornare ut sed leo. Class aptent +taciti sociosqu ad litora torquent per conubia nostra, per inceptos +himenaeos. Suspendisse vel arcu non orci molestie accumsan sed nec ex. In +hac habitasse platea dictumst. Vivamus non auctor lacus. In pellentesque +nisl interdum lorem sollicitudin, ut tempus elit pretium. + +Vestibulum interdum feugiat dui, non tristique orci. Cras arcu nibh, +blandit ut scelerisque ac, pulvinar ac elit. Mauris sodales fringilla +nunc, a porta libero. Morbi non interdum libero. Suspendisse euismod leo +lorem, vitae vehicula dui vestibulum a. In hendrerit dui vitae iaculis +pulvinar. Suspendisse porta justo eu nunc pulvinar, at cursus urna +ornare. Cras vitae lacus nec sem eleifend pharetra ut vel nisl. Curabitur +lobortis arcu eu metus sagittis laoreet. Vivamus id lacinia risus. + +In et urna id nisi elementum malesuada. Fusce fermentum, justo vitae +vulputate varius, enim nunc scelerisque turpis, vel feugiat ligula ante ut +elit. Praesent interdum augue eu augue cursus luctus. Vestibulum egestas +mauris bibendum risus pulvinar eleifend. Vestibulum arcu tortor, hendrerit +vitae ornare sit amet, cursus eget quam. Morbi sodales magna felis, et +placerat ipsum iaculis nec. Nullam pretium, massa a tempor tincidunt, +arcu sapien blandit libero, id tempus leo lorem ullamcorper risus. Mauris +iaculis ligula justo, ac fermentum mi congue non. Nullam blandit nisl +risus, quis tincidunt enim cursus a. Class aptent taciti sociosqu ad +litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum +et leo nunc. + +Phasellus placerat vehicula augue, in maximus diam dapibus eget. Nunc +mauris velit, tempor vitae leo vel, facilisis interdum metus. Donec +imperdiet fermentum semper. Praesent eleifend nisl non neque pretium, +ac malesuada ex malesuada. Sed non ante tellus. Nunc rhoncus magna nisl, +ut ultrices tortor ornare id. Class aptent taciti sociosqu ad litora +torquent per conubia nostra, per inceptos himenaeos. Fusce egestas, dolor +id eleifend pharetra, urna risus condimentum nulla, nec euismod massa +lorem quis dolor. Integer nec justo non mauris pellentesque dictum vitae +in nibh. Praesent eu velit eget nisl feugiat pretium in in odio. Fusce +a scelerisque turpis, sed ultricies enim. Phasellus a libero quis nulla +accumsan facilisis eget vitae ex. Etiam et urna nec est tempor tempor +id vel leo. + +Nulla facilisi. Orci varius natoque penatibus et magnis dis parturient +montes, nascetur ridiculus mus. Maecenas accumsan ligula urna, nec +consequat elit euismod vitae. Nulla varius leo at euismod vehicula. Nunc +at felis eget ex vehicula luctus. Praesent vitae nulla eget nisl mattis +sagittis at eget nunc. Ut ipsum ipsum, egestas a elementum quis, elementum +eu mi. + +Nulla ligula dui, suscipit sit amet commodo non, maximus a metus. Proin +pretium eu augue nec dapibus. Praesent eget commodo neque. Donec iaculis +ullamcorper est, ultricies consequat nisl vehicula in. Ut pulvinar +tortor sed eros venenatis malesuada. Integer feugiat massa dolor, sit +amet cursus neque aliquam ac. Curabitur quis tincidunt enim. Maecenas +lobortis lacus non dui dignissim ullamcorper. Ut malesuada ac augue quis +eleifend. Sed convallis orci neque, non rutrum purus vestibulum ut. Sed +eu sem sagittis, finibus leo sed, vestibulum dolor. Vivamus felis purus, +commodo eu accumsan vitae, egestas sed lorem. + +Suspendisse eros neque, eleifend non ultrices quis, iaculis quis +mauris. Phasellus pharetra arcu in quam iaculis, vel faucibus nunc +convallis. Suspendisse potenti. Quisque egestas lacinia tempor. Integer id +tincidunt lacus. Fusce laoreet eros vitae libero eleifend, quis sagittis +eros viverra. Sed laoreet urna est, a congue magna convallis euismod. Ut +sit amet nunc nibh. Maecenas pharetra interdum tortor nec bibendum. Nunc +viverra pretium augue, ac venenatis nibh placerat nec. Nulla tempor libero +urna, a lobortis lectus maximus nec. Suspendisse potenti. Proin feugiat +volutpat pharetra. Donec mollis sed metus ut hendrerit. Pellentesque +quis efficitur nunc, id imperdiet purus. + +Aliquam at ante et mauris sodales placerat. Phasellus eget mi +diam. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aenean +a magna id quam congue auctor. Nullam faucibus aliquet ullamcorper. Nam +sodales pellentesque massa eget auctor. Pellentesque tempor vestibulum +lobortis. Donec consectetur cursus quam in bibendum. + +Cras tempor lacus vehicula dolor vestibulum commodo. Duis sed nunc +tristique, vulputate libero id, aliquam lacus. Phasellus libero mi, +dictum ac mattis vitae, hendrerit a urna. Fusce accumsan ex pellentesque +purus euismod ultricies. Nam vitae metus nec est cursus mattis. Sed +sagittis luctus nunc a gravida. Pellentesque euismod aliquet ante, +eu pharetra neque ultricies id. Nulla vitae felis eu mauris convallis +imperdiet. Aenean sagittis, enim at sagittis suscipit, tellus nulla +vulputate mauris, nec mattis justo sem nec purus. + +Praesent erat nisl, hendrerit eget mattis condimentum, sollicitudin +vel ex. Orci varius natoque penatibus et magnis dis parturient montes, +nascetur ridiculus mus. Sed rhoncus malesuada ipsum. Praesent tincidunt +bibendum diam, vitae suscipit nulla tincidunt a. Praesent porta +scelerisque erat vel varius. Donec fringilla purus dignissim purus +blandit pulvinar. In maximus lobortis feugiat. Mauris ac nunc at mi +aliquam iaculis finibus ac nunc. Aliquam sit amet tempor urna. Quisque +vitae tincidunt nunc. Quisque sit amet eros sit amet nulla ullamcorper +ornare. Integer quis tristique lorem. Vivamus in augue erat. + +Aliquam erat volutpat. Sed ac augue ultrices, lobortis nisl nec, vehicula +leo. Quisque condimentum quis enim vitae faucibus. Curabitur nec libero +sed risus euismod aliquet. Phasellus purus massa, blandit et enim finibus, +tincidunt commodo erat. Suspendisse nec condimentum velit. Praesent luctus +eleifend erat in feugiat. Phasellus pharetra neque ipsum, iaculis placerat +lorem fringilla vitae. Curabitur accumsan, quam eu aliquet elementum, +risus mauris fermentum magna, vitae auctor lacus nisi vitae massa. Donec +ornare nec est ut euismod. Suspendisse nec mi nisl. Nulla imperdiet et +diam vitae semper. Donec tempus quis massa sed suscipit. Suspendisse +laoreet posuere ipsum varius feugiat. + +Nullam gravida magna vitae erat tristique mattis. Nullam tempus +commodo ex, sed egestas nisi euismod eu. Cras scelerisque quis lectus in +vestibulum. Orci varius natoque penatibus et magnis dis parturient montes, +nascetur ridiculus mus. Fusce eget blandit sapien. Nunc ut gravida arcu, +eu placerat enim. Morbi molestie ligula ut blandit faucibus. + +Nulla tristique ligula nec magna porttitor dapibus. Sed id ante sit amet +quam placerat vestibulum. Sed pellentesque est odio, sit amet ornare purus +ornare quis. Vestibulum tempus neque non felis semper rutrum. Fusce a +tincidunt massa, a faucibus velit. Nam leo nisi, pretium eget nisl vel, +placerat vehicula quam. Cras placerat, est sed finibus pulvinar, neque +turpis aliquet magna, convallis bibendum lorem felis in est. + +Etiam maximus blandit lacus at egestas. Fusce fringilla lectus vel enim +porttitor varius. Ut sapien metus, pharetra sit amet quam vitae, efficitur +viverra enim. Sed enim magna, viverra quis dui at, euismod aliquam +elit. Donec posuere, dolor eget pretium semper, nibh sapien tincidunt +diam, id elementum odio nunc eu purus. Sed nec felis id turpis tempor +sollicitudin. Morbi eu iaculis lacus. In vel tincidunt velit. Fusce nec +vestibulum felis. Nam ut ligula quam. Phasellus nulla nibh, consectetur +sit amet mi sit amet, pretium bibendum dui. Maecenas facilisis blandit +justo sed blandit. Nunc eleifend nulla vel ante accumsan mattis. Morbi +varius gravida nisl et tempus. + +Ut eu ultrices sapien. Aliquam non tortor sed risus volutpat +egestas. Proin cursus, dolor nec rutrum ullamcorper, felis felis vehicula +metus, vitae ullamcorper orci nisi feugiat mi. Nunc tincidunt interdum +mattis. Fusce rhoncus feugiat dolor, sit amet ullamcorper libero mollis +in. Vestibulum ac libero ac metus eleifend pulvinar. Vestibulum sodales +dui malesuada ex viverra, quis convallis sapien tincidunt. Praesent +sagittis augue id interdum fermentum. + +In est nulla, elementum convallis sapien eget, pharetra auctor +quam. Phasellus neque quam, tincidunt at congue eu, tincidunt eu +augue. Class aptent taciti sociosqu ad litora torquent per conubia +nostra, per inceptos himenaeos. Pellentesque id nulla neque. In +pretium elementum ullamcorper. Donec ornare mi ut turpis commodo +facilisis. Integer porttitor euismod augue, eget malesuada elit. Quisque +a justo nisi. Aliquam accumsan fermentum eros id vestibulum. Integer +id elementum massa, a mollis lorem. Fusce sed dui sed ipsum tristique +tempor. Integer fermentum eu dui a euismod. Nullam varius justo sed +sem accumsan finibus. Vestibulum aliquam velit eu arcu pulvinar, eget +eleifend erat sagittis. + +Fusce fermentum quam vitae sapien scelerisque molestie. Praesent egestas +ante elit, elementum aliquet justo pellentesque nec. Pellentesque +suscipit nisl eu neque tempor, interdum volutpat velit hendrerit. Nullam +id fringilla ligula. Nunc at ultrices tortor, quis ornare augue. Etiam +a lacinia orci. Cras ut dui nec tellus finibus laoreet. Vivamus +tincidunt, lorem sit amet sollicitudin blandit, quam ipsum blandit nisi, +sed hendrerit massa nibh ut eros. Nam laoreet diam vitae dignissim +tincidunt. Duis vel lorem turpis. diff --git a/testdocs/numbers.txt b/testdocs/numbers.txt new file mode 100644 index 0000000..bcd5f06 --- /dev/null +++ b/testdocs/numbers.txt @@ -0,0 +1,1001 @@ +10000000 +10000001 +10000002 +10000003 +10000004 +10000005 +10000006 +10000007 +10000008 +10000009 +10000010 +10000011 +10000012 +10000013 +10000014 +10000015 +10000016 +10000017 +10000018 +10000019 +10000020 +10000021 +10000022 +10000023 +10000024 +10000025 +10000026 +10000027 +10000028 +10000029 +10000030 +10000031 +10000032 +10000033 +10000034 +10000035 +10000036 +10000037 +10000038 +10000039 +10000040 +10000041 +10000042 +10000043 +10000044 +10000045 +10000046 +10000047 +10000048 +10000049 +10000050 +10000051 +10000052 +10000053 +10000054 +10000055 +10000056 +10000057 +10000058 +10000059 +10000060 +10000061 +10000062 +10000063 +10000064 +10000065 +10000066 +10000067 +10000068 +10000069 +10000070 +10000071 +10000072 +10000073 +10000074 +10000075 +10000076 +10000077 +10000078 +10000079 +10000080 +10000081 +10000082 +10000083 +10000084 +10000085 +10000086 +10000087 +10000088 +10000089 +10000090 +10000091 +10000092 +10000093 +10000094 +10000095 +10000096 +10000097 +10000098 +10000099 +10000100 +10000101 +10000102 +10000103 +10000104 +10000105 +10000106 +10000107 +10000108 +10000109 +10000110 +10000111 +10000112 +10000113 +10000114 +10000115 +10000116 +10000117 +10000118 +10000119 +10000120 +10000121 +10000122 +10000123 +10000124 +10000125 +10000126 +10000127 +10000128 +10000129 +10000130 +10000131 +10000132 +10000133 +10000134 +10000135 +10000136 +10000137 +10000138 +10000139 +10000140 +10000141 +10000142 +10000143 +10000144 +10000145 +10000146 +10000147 +10000148 +10000149 +10000150 +10000151 +10000152 +10000153 +10000154 +10000155 +10000156 +10000157 +10000158 +10000159 +10000160 +10000161 +10000162 +10000163 +10000164 +10000165 +10000166 +10000167 +10000168 +10000169 +10000170 +10000171 +10000172 +10000173 +10000174 +10000175 +10000176 +10000177 +10000178 +10000179 +10000180 +10000181 +10000182 +10000183 +10000184 +10000185 +10000186 +10000187 +10000188 +10000189 +10000190 +10000191 +10000192 +10000193 +10000194 +10000195 +10000196 +10000197 +10000198 +10000199 +10000200 +10000201 +10000202 +10000203 +10000204 +10000205 +10000206 +10000207 +10000208 +10000209 +10000210 +10000211 +10000212 +10000213 +10000214 +10000215 +10000216 +10000217 +10000218 +10000219 +10000220 +10000221 +10000222 +10000223 +10000224 +10000225 +10000226 +10000227 +10000228 +10000229 +10000230 +10000231 +10000232 +10000233 +10000234 +10000235 +10000236 +10000237 +10000238 +10000239 +10000240 +10000241 +10000242 +10000243 +10000244 +10000245 +10000246 +10000247 +10000248 +10000249 +10000250 +10000251 +10000252 +10000253 +10000254 +10000255 +10000256 +10000257 +10000258 +10000259 +10000260 +10000261 +10000262 +10000263 +10000264 +10000265 +10000266 +10000267 +10000268 +10000269 +10000270 +10000271 +10000272 +10000273 +10000274 +10000275 +10000276 +10000277 +10000278 +10000279 +10000280 +10000281 +10000282 +10000283 +10000284 +10000285 +10000286 +10000287 +10000288 +10000289 +10000290 +10000291 +10000292 +10000293 +10000294 +10000295 +10000296 +10000297 +10000298 +10000299 +10000300 +10000301 +10000302 +10000303 +10000304 +10000305 +10000306 +10000307 +10000308 +10000309 +10000310 +10000311 +10000312 +10000313 +10000314 +10000315 +10000316 +10000317 +10000318 +10000319 +10000320 +10000321 +10000322 +10000323 +10000324 +10000325 +10000326 +10000327 +10000328 +10000329 +10000330 +10000331 +10000332 +10000333 +10000334 +10000335 +10000336 +10000337 +10000338 +10000339 +10000340 +10000341 +10000342 +10000343 +10000344 +10000345 +10000346 +10000347 +10000348 +10000349 +10000350 +10000351 +10000352 +10000353 +10000354 +10000355 +10000356 +10000357 +10000358 +10000359 +10000360 +10000361 +10000362 +10000363 +10000364 +10000365 +10000366 +10000367 +10000368 +10000369 +10000370 +10000371 +10000372 +10000373 +10000374 +10000375 +10000376 +10000377 +10000378 +10000379 +10000380 +10000381 +10000382 +10000383 +10000384 +10000385 +10000386 +10000387 +10000388 +10000389 +10000390 +10000391 +10000392 +10000393 +10000394 +10000395 +10000396 +10000397 +10000398 +10000399 +10000400 +10000401 +10000402 +10000403 +10000404 +10000405 +10000406 +10000407 +10000408 +10000409 +10000410 +10000411 +10000412 +10000413 +10000414 +10000415 +10000416 +10000417 +10000418 +10000419 +10000420 +10000421 +10000422 +10000423 +10000424 +10000425 +10000426 +10000427 +10000428 +10000429 +10000430 +10000431 +10000432 +10000433 +10000434 +10000435 +10000436 +10000437 +10000438 +10000439 +10000440 +10000441 +10000442 +10000443 +10000444 +10000445 +10000446 +10000447 +10000448 +10000449 +10000450 +10000451 +10000452 +10000453 +10000454 +10000455 +10000456 +10000457 +10000458 +10000459 +10000460 +10000461 +10000462 +10000463 +10000464 +10000465 +10000466 +10000467 +10000468 +10000469 +10000470 +10000471 +10000472 +10000473 +10000474 +10000475 +10000476 +10000477 +10000478 +10000479 +10000480 +10000481 +10000482 +10000483 +10000484 +10000485 +10000486 +10000487 +10000488 +10000489 +10000490 +10000491 +10000492 +10000493 +10000494 +10000495 +10000496 +10000497 +10000498 +10000499 +10000500 +10000501 +10000502 +10000503 +10000504 +10000505 +10000506 +10000507 +10000508 +10000509 +10000510 +10000511 +10000512 +10000513 +10000514 +10000515 +10000516 +10000517 +10000518 +10000519 +10000520 +10000521 +10000522 +10000523 +10000524 +10000525 +10000526 +10000527 +10000528 +10000529 +10000530 +10000531 +10000532 +10000533 +10000534 +10000535 +10000536 +10000537 +10000538 +10000539 +10000540 +10000541 +10000542 +10000543 +10000544 +10000545 +10000546 +10000547 +10000548 +10000549 +10000550 +10000551 +10000552 +10000553 +10000554 +10000555 +10000556 +10000557 +10000558 +10000559 +10000560 +10000561 +10000562 +10000563 +10000564 +10000565 +10000566 +10000567 +10000568 +10000569 +10000570 +10000571 +10000572 +10000573 +10000574 +10000575 +10000576 +10000577 +10000578 +10000579 +10000580 +10000581 +10000582 +10000583 +10000584 +10000585 +10000586 +10000587 +10000588 +10000589 +10000590 +10000591 +10000592 +10000593 +10000594 +10000595 +10000596 +10000597 +10000598 +10000599 +10000600 +10000601 +10000602 +10000603 +10000604 +10000605 +10000606 +10000607 +10000608 +10000609 +10000610 +10000611 +10000612 +10000613 +10000614 +10000615 +10000616 +10000617 +10000618 +10000619 +10000620 +10000621 +10000622 +10000623 +10000624 +10000625 +10000626 +10000627 +10000628 +10000629 +10000630 +10000631 +10000632 +10000633 +10000634 +10000635 +10000636 +10000637 +10000638 +10000639 +10000640 +10000641 +10000642 +10000643 +10000644 +10000645 +10000646 +10000647 +10000648 +10000649 +10000650 +10000651 +10000652 +10000653 +10000654 +10000655 +10000656 +10000657 +10000658 +10000659 +10000660 +10000661 +10000662 +10000663 +10000664 +10000665 +10000666 +10000667 +10000668 +10000669 +10000670 +10000671 +10000672 +10000673 +10000674 +10000675 +10000676 +10000677 +10000678 +10000679 +10000680 +10000681 +10000682 +10000683 +10000684 +10000685 +10000686 +10000687 +10000688 +10000689 +10000690 +10000691 +10000692 +10000693 +10000694 +10000695 +10000696 +10000697 +10000698 +10000699 +10000700 +10000701 +10000702 +10000703 +10000704 +10000705 +10000706 +10000707 +10000708 +10000709 +10000710 +10000711 +10000712 +10000713 +10000714 +10000715 +10000716 +10000717 +10000718 +10000719 +10000720 +10000721 +10000722 +10000723 +10000724 +10000725 +10000726 +10000727 +10000728 +10000729 +10000730 +10000731 +10000732 +10000733 +10000734 +10000735 +10000736 +10000737 +10000738 +10000739 +10000740 +10000741 +10000742 +10000743 +10000744 +10000745 +10000746 +10000747 +10000748 +10000749 +10000750 +10000751 +10000752 +10000753 +10000754 +10000755 +10000756 +10000757 +10000758 +10000759 +10000760 +10000761 +10000762 +10000763 +10000764 +10000765 +10000766 +10000767 +10000768 +10000769 +10000770 +10000771 +10000772 +10000773 +10000774 +10000775 +10000776 +10000777 +10000778 +10000779 +10000780 +10000781 +10000782 +10000783 +10000784 +10000785 +10000786 +10000787 +10000788 +10000789 +10000790 +10000791 +10000792 +10000793 +10000794 +10000795 +10000796 +10000797 +10000798 +10000799 +10000800 +10000801 +10000802 +10000803 +10000804 +10000805 +10000806 +10000807 +10000808 +10000809 +10000810 +10000811 +10000812 +10000813 +10000814 +10000815 +10000816 +10000817 +10000818 +10000819 +10000820 +10000821 +10000822 +10000823 +10000824 +10000825 +10000826 +10000827 +10000828 +10000829 +10000830 +10000831 +10000832 +10000833 +10000834 +10000835 +10000836 +10000837 +10000838 +10000839 +10000840 +10000841 +10000842 +10000843 +10000844 +10000845 +10000846 +10000847 +10000848 +10000849 +10000850 +10000851 +10000852 +10000853 +10000854 +10000855 +10000856 +10000857 +10000858 +10000859 +10000860 +10000861 +10000862 +10000863 +10000864 +10000865 +10000866 +10000867 +10000868 +10000869 +10000870 +10000871 +10000872 +10000873 +10000874 +10000875 +10000876 +10000877 +10000878 +10000879 +10000880 +10000881 +10000882 +10000883 +10000884 +10000885 +10000886 +10000887 +10000888 +10000889 +10000890 +10000891 +10000892 +10000893 +10000894 +10000895 +10000896 +10000897 +10000898 +10000899 +10000900 +10000901 +10000902 +10000903 +10000904 +10000905 +10000906 +10000907 +10000908 +10000909 +10000910 +10000911 +10000912 +10000913 +10000914 +10000915 +10000916 +10000917 +10000918 +10000919 +10000920 +10000921 +10000922 +10000923 +10000924 +10000925 +10000926 +10000927 +10000928 +10000929 +10000930 +10000931 +10000932 +10000933 +10000934 +10000935 +10000936 +10000937 +10000938 +10000939 +10000940 +10000941 +10000942 +10000943 +10000944 +10000945 +10000946 +10000947 +10000948 +10000949 +10000950 +10000951 +10000952 +10000953 +10000954 +10000955 +10000956 +10000957 +10000958 +10000959 +10000960 +10000961 +10000962 +10000963 +10000964 +10000965 +10000966 +10000967 +10000968 +10000969 +10000970 +10000971 +10000972 +10000973 +10000974 +10000975 +10000976 +10000977 +10000978 +10000979 +10000980 +10000981 +10000982 +10000983 +10000984 +10000985 +10000986 +10000987 +10000988 +10000989 +10000990 +10000991 +10000992 +10000993 +10000994 +10000995 +10000996 +10000997 +10000998 +10000999 +10001000 diff --git a/testdocs/sherlock.txt b/testdocs/sherlock.txt new file mode 100644 index 0000000..dcc6bd2 --- /dev/null +++ b/testdocs/sherlock.txt @@ -0,0 +1,128457 @@ +The Project Gutenberg EBook of The Adventures of Sherlock Holmes +by Sir Arthur Conan Doyle +(#15 in our series by Sir Arthur Conan Doyle) + +Copyright laws are changing all over the world. Be sure to check the +copyright laws for your country before downloading or redistributing +this or any other Project Gutenberg eBook. + +This header should be the first thing seen when viewing this Project +Gutenberg file. Please do not remove it. Do not change or edit the +header without written permission. + +Please read the "legal small print," and other information about the +eBook and Project Gutenberg at the bottom of this file. Included is +important information about your specific rights and restrictions in +how the file may be used. You can also find out about how to make a +donation to Project Gutenberg, and how to get involved. + + +**Welcome To The World of Free Plain Vanilla Electronic Texts** + +**eBooks Readable By Both Humans and By Computers, Since 1971** + +*****These eBooks Were Prepared By Thousands of Volunteers!***** + + +Title: The Adventures of Sherlock Holmes + +Author: Sir Arthur Conan Doyle + +Release Date: March, 1999 [EBook #1661] +[Most recently updated: November 29, 2002] + +Edition: 12 + +Language: English + +Character set encoding: ASCII + +*** START OF THE PROJECT GUTENBERG EBOOK, THE ADVENTURES OF SHERLOCK HOLMES *** + + + + +(Additional editing by Jose Menendez) + + + +THE ADVENTURES OF +SHERLOCK HOLMES + +BY + +SIR ARTHUR CONAN DOYLE + +CONTENTS + +I. A Scandal in Bohemia +II. The Red-Headed League +III. A Case of Identity +IV. The Boscombe Valley Mystery +V. The Five Orange Pips +VI. The Man with the Twisted Lip +VII. The Adventure of the Blue Carbuncle +VIII. The Adventure of the Speckled Band +IX. The Adventure of the Engineer's Thumb +X. The Adventure of the Noble Bachelor +XI. The Adventure of the Beryl Coronet +XII. The Adventure of the Copper Beeches + + +ADVENTURE I. A SCANDAL IN BOHEMIA + +I. + + +To Sherlock Holmes she is always the woman. I have seldom heard him mention her under any other name. In his eyes she eclipses and predominates the whole of her sex. It was not that he felt any emotion akin to love for Irene Adler. All emotions, and that one particularly, were abhorrent to his cold, precise but admirably balanced mind. He was, I take it, the most perfect reasoning and observing machine that the world has seen, but as a lover he would have placed himself in a false position. He never spoke of the softer passions, save with a gibe and a sneer. They were admirable things for the observer--excellent for drawing the veil from men's motives and actions. But for the trained reasoner to admit such intrusions into his own delicate and finely adjusted temperament was to introduce a distracting factor which might throw a doubt upon all his mental results. Grit in a sensitive instrument, or a crack in one of his own high-power lenses, would not be more disturbing than a strong emotion in a nature such as his. And yet there was but one woman to him, and that woman was the late Irene Adler, of dubious and questionable memory. + +I had seen little of Holmes lately. My marriage had drifted us away from each other. My own complete happiness, and the home-centred interests which rise up around the man who first finds himself master of his own establishment, were sufficient to absorb all my attention, while Holmes, who loathed every form of society with his whole Bohemian soul, remained in our lodgings in Baker Street, buried among his old books, and alternating from week to week between cocaine and ambition, the drowsiness of the drug, and the fierce energy of his own keen nature. He was still, as ever, deeply attracted by the study of crime, and occupied his immense faculties and extraordinary powers of observation in following out those clues, and clearing up those mysteries which had been abandoned as hopeless by the official police. From time to time I heard some vague account of his doings: of his summons to Odessa in the case of the Trepoff murder, of his clearing up of the singular tragedy of the Atkinson brothers at Trincomalee, and finally of the mission which he had accomplished so delicately and successfully for the reigning family of Holland. Beyond these signs of his activity, however, which I merely shared with all the readers of the daily press, I knew little of my former friend and companion. + +One night--it was on the twentieth of March, 1888--I was returning from a journey to a patient (for I had now returned to civil practice), when my way led me through Baker Street. As I passed the well-remembered door, which must always be associated in my mind with my wooing, and with the dark incidents of the Study in Scarlet, I was seized with a keen desire to see Holmes again, and to know how he was employing his extraordinary powers. His rooms were brilliantly lit, and, even as I looked up, I saw his tall, spare figure pass twice in a dark silhouette against the blind. He was pacing the room swiftly, eagerly, with his head sunk upon his chest and his hands clasped behind him. To me, who knew his every mood and habit, his attitude and manner told their own story. He was at work again. He had risen out of his drug-created dreams and was hot upon the scent of some new problem. I rang the bell and was shown up to the chamber which had formerly been in part my own. + +His manner was not effusive. It seldom was; but he was glad, I think, to see me. With hardly a word spoken, but with a kindly eye, he waved me to an armchair, threw across his case of cigars, and indicated a spirit case and a gasogene in the corner. Then he stood before the fire and looked me over in his singular introspective fashion. + +"Wedlock suits you," he remarked. "I think, Watson, that you have put on seven and a half pounds since I saw you." + +"Seven!" I answered. + +"Indeed, I should have thought a little more. Just a trifle more, I fancy, Watson. And in practice again, I observe. You did not tell me that you intended to go into harness." + +"Then, how do you know?" + +"I see it, I deduce it. How do I know that you have been getting yourself very wet lately, and that you have a most clumsy and careless servant girl?" + +"My dear Holmes," said I, "this is too much. You would certainly have been burned, had you lived a few centuries ago. It is true that I had a country walk on Thursday and came home in a dreadful mess, but as I have changed my clothes I can't imagine how you deduce it. As to Mary Jane, she is incorrigible, and my wife has given her notice, but there, again, I fail to see how you work it out." + +He chuckled to himself and rubbed his long, nervous hands together. + +"It is simplicity itself," said he; "my eyes tell me that on the inside of your left shoe, just where the firelight strikes it, the leather is scored by six almost parallel cuts. Obviously they have been caused by someone who has very carelessly scraped round the edges of the sole in order to remove crusted mud from it. Hence, you see, my double deduction that you had been out in vile weather, and that you had a particularly malignant boot-slitting specimen of the London slavey. As to your practice, if a gentleman walks into my rooms smelling of iodoform, with a black mark of nitrate of silver upon his right forefinger, and a bulge on the right side of his top-hat to show where he has secreted his stethoscope, I must be dull, indeed, if I do not pronounce him to be an active member of the medical profession." + +I could not help laughing at the ease with which he explained his process of deduction. "When I hear you give your reasons," I remarked, "the thing always appears to me to be so ridiculously simple that I could easily do it myself, though at each successive instance of your reasoning I am baffled until you explain your process. And yet I believe that my eyes are as good as yours." + +"Quite so," he answered, lighting a cigarette, and throwing himself down into an armchair. "You see, but you do not observe. The distinction is clear. For example, you have frequently seen the steps which lead up from the hall to this room." + +"Frequently." + +"How often?" + +"Well, some hundreds of times." + +"Then how many are there?" + +"How many? I don't know." + +"Quite so! You have not observed. And yet you have seen. That is just my point. Now, I know that there are seventeen steps, because I have both seen and observed. By the way, since you are interested in these little problems, and since you are good enough to chronicle one or two of my trifling experiences, you may be interested in this." He threw over a sheet of thick, pink-tinted notepaper which had been lying open upon the table. "It came by the last post," said he. "Read it aloud." + +The note was undated, and without either signature or address. + +"There will call upon you to-night, at a quarter to eight o'clock," it said, "a gentleman who desires to consult you upon a matter of the very deepest moment. Your recent services to one of the royal houses of Europe have shown that you are one who may safely be trusted with matters which are of an importance which can hardly be exaggerated. This account of you we have from all quarters received. Be in your chamber then at that hour, and do not take it amiss if your visitor wear a mask." + +"This is indeed a mystery," I remarked. "What do you imagine that it means?" + +"I have no data yet. It is a capital mistake to theorise before one has data. Insensibly one begins to twist facts to suit theories, instead of theories to suit facts. But the note itself. What do you deduce from it?" + +I carefully examined the writing, and the paper upon which it was written. + +"The man who wrote it was presumably well to do," I remarked, endeavouring to imitate my companion's processes. "Such paper could not be bought under half a crown a packet. It is peculiarly strong and stiff." + +"Peculiar--that is the very word," said Holmes. "It is not an English paper at all. Hold it up to the light." + +I did so, and saw a large "E" with a small "g," a "P," and a large "G" with a small "t" woven into the texture of the paper. + +"What do you make of that?" asked Holmes. + +"The name of the maker, no doubt; or his monogram, rather." + +"Not at all. The 'G' with the small 't' stands for 'Gesellschaft,' which is the German for 'Company.' It is a customary contraction like our 'Co.' 'P,' of course, stands for 'Papier.' Now for the 'Eg.' Let us glance at our Continental Gazetteer." He took down a heavy brown volume from his shelves. "Eglow, Eglonitz--here we are, Egria. It is in a German-speaking country--in Bohemia, not far from Carlsbad. 'Remarkable as being the scene of the death of Wallenstein, and for its numerous glass-factories and paper-mills.' Ha, ha, my boy, what do you make of that?" His eyes sparkled, and he sent up a great blue triumphant cloud from his cigarette. + +"The paper was made in Bohemia," I said. + +"Precisely. And the man who wrote the note is a German. Do you note the peculiar construction of the sentence--'This account of you we have from all quarters received.' A Frenchman or Russian could not have written that. It is the German who is so uncourteous to his verbs. It only remains, therefore, to discover what is wanted by this German who writes upon Bohemian paper and prefers wearing a mask to showing his face. And here he comes, if I am not mistaken, to resolve all our doubts." + +As he spoke there was the sharp sound of horses' hoofs and grating wheels against the curb, followed by a sharp pull at the bell. Holmes whistled. + +"A pair, by the sound," said he. "Yes," he continued, glancing out of the window. "A nice little brougham and a pair of beauties. A hundred and fifty guineas apiece. There's money in this case, Watson, if there is nothing else." + +"I think that I had better go, Holmes." + +"Not a bit, Doctor. Stay where you are. I am lost without my Boswell. And this promises to be interesting. It would be a pity to miss it." + +"But your client--" + +"Never mind him. I may want your help, and so may he. Here he comes. Sit down in that armchair, Doctor, and give us your best attention." + +A slow and heavy step, which had been heard upon the stairs and in the passage, paused immediately outside the door. Then there was a loud and authoritative tap. + +"Come in!" said Holmes. + +A man entered who could hardly have been less than six feet six inches in height, with the chest and limbs of a Hercules. His dress was rich with a richness which would, in England, be looked upon as akin to bad taste. Heavy bands of astrakhan were slashed across the sleeves and fronts of his double-breasted coat, while the deep blue cloak which was thrown over his shoulders was lined with flame-coloured silk and secured at the neck with a brooch which consisted of a single flaming beryl. Boots which extended halfway up his calves, and which were trimmed at the tops with rich brown fur, completed the impression of barbaric opulence which was suggested by his whole appearance. He carried a broad-brimmed hat in his hand, while he wore across the upper part of his face, extending down past the cheekbones, a black vizard mask, which he had apparently adjusted that very moment, for his hand was still raised to it as he entered. From the lower part of the face he appeared to be a man of strong character, with a thick, hanging lip, and a long, straight chin suggestive of resolution pushed to the length of obstinacy. + +"You had my note?" he asked with a deep harsh voice and a strongly marked German accent. "I told you that I would call." He looked from one to the other of us, as if uncertain which to address. + +"Pray take a seat," said Holmes. "This is my friend and colleague, Dr. Watson, who is occasionally good enough to help me in my cases. Whom have I the honour to address?" + +"You may address me as the Count Von Kramm, a Bohemian nobleman. I understand that this gentleman, your friend, is a man of honour and discretion, whom I may trust with a matter of the most extreme importance. If not, I should much prefer to communicate with you alone." + +I rose to go, but Holmes caught me by the wrist and pushed me back into my chair. "It is both, or none," said he. "You may say before this gentleman anything which you may say to me." + +The Count shrugged his broad shoulders. "Then I must begin," said he, "by binding you both to absolute secrecy for two years; at the end of that time the matter will be of no importance. At present it is not too much to say that it is of such weight it may have an influence upon European history." + +"I promise," said Holmes. + +"And I." + +"You will excuse this mask," continued our strange visitor. "The august person who employs me wishes his agent to be unknown to you, and I may confess at once that the title by which I have just called myself is not exactly my own." + +"I was aware of it," said Holmes dryly. + +"The circumstances are of great delicacy, and every precaution has to be taken to quench what might grow to be an immense scandal and seriously compromise one of the reigning families of Europe. To speak plainly, the matter implicates the great House of Ormstein, hereditary kings of Bohemia." + +"I was also aware of that," murmured Holmes, settling himself down in his armchair and closing his eyes. + +Our visitor glanced with some apparent surprise at the languid, lounging figure of the man who had been no doubt depicted to him as the most incisive reasoner and most energetic agent in Europe. Holmes slowly reopened his eyes and looked impatiently at his gigantic client. + +"If your Majesty would condescend to state your case," he remarked, "I should be better able to advise you." + +The man sprang from his chair and paced up and down the room in uncontrollable agitation. Then, with a gesture of desperation, he tore the mask from his face and hurled it upon the ground. "You are right," he cried; "I am the King. Why should I attempt to conceal it?" + +"Why, indeed?" murmured Holmes. "Your Majesty had not spoken before I was aware that I was addressing Wilhelm Gottsreich Sigismond von Ormstein, Grand Duke of Cassel-Felstein, and hereditary King of Bohemia." + +"But you can understand," said our strange visitor, sitting down once more and passing his hand over his high white forehead, "you can understand that I am not accustomed to doing such business in my own person. Yet the matter was so delicate that I could not confide it to an agent without putting myself in his power. I have come incognito from Prague for the purpose of consulting you." + +"Then, pray consult," said Holmes, shutting his eyes once more. + +"The facts are briefly these: Some five years ago, during a lengthy visit to Warsaw, I made the acquaintance of the well-known adventuress, Irene Adler. The name is no doubt familiar to you." + +"Kindly look her up in my index, Doctor," murmured Holmes without opening his eyes. For many years he had adopted a system of docketing all paragraphs concerning men and things, so that it was difficult to name a subject or a person on which he could not at once furnish information. In this case I found her biography sandwiched in between that of a Hebrew rabbi and that of a staff-commander who had written a monograph upon the deep-sea fishes. + +"Let me see!" said Holmes. "Hum! Born in New Jersey in the year 1858. Contralto--hum! La Scala, hum! Prima donna Imperial Opera of Warsaw--yes! Retired from operatic stage--ha! Living in London--quite so! Your Majesty, as I understand, became entangled with this young person, wrote her some compromising letters, and is now desirous of getting those letters back." + +"Precisely so. But how--" + +"Was there a secret marriage?" + +"None." + +"No legal papers or certificates?" + +"None." + +"Then I fail to follow your Majesty. If this young person should produce her letters for blackmailing or other purposes, how is she to prove their authenticity?" + +"There is the writing." + +"Pooh, pooh! Forgery." + +"My private note-paper." + +"Stolen." + +"My own seal." + +"Imitated." + +"My photograph." + +"Bought." + +"We were both in the photograph." + +"Oh, dear! That is very bad! Your Majesty has indeed committed an indiscretion." + +"I was mad--insane." + +"You have compromised yourself seriously." + +"I was only Crown Prince then. I was young. I am but thirty now." + +"It must be recovered." + +"We have tried and failed." + +"Your Majesty must pay. It must be bought." + +"She will not sell." + +"Stolen, then." + +"Five attempts have been made. Twice burglars in my pay ransacked her house. Once we diverted her luggage when she travelled. Twice she has been waylaid. There has been no result." + +"No sign of it?" + +"Absolutely none." + +Holmes laughed. "It is quite a pretty little problem," said he. + +"But a very serious one to me," returned the King reproachfully. + +"Very, indeed. And what does she propose to do with the photograph?" + +"To ruin me." + +"But how?" + +"I am about to be married." + +"So I have heard." + +"To Clotilde Lothman von Saxe-Meningen, second daughter of the King of Scandinavia. You may know the strict principles of her family. She is herself the very soul of delicacy. A shadow of a doubt as to my conduct would bring the matter to an end." + +"And Irene Adler?" + +"Threatens to send them the photograph. And she will do it. I know that she will do it. You do not know her, but she has a soul of steel. She has the face of the most beautiful of women, and the mind of the most resolute of men. Rather than I should marry another woman, there are no lengths to which she would not go--none." + +"You are sure that she has not sent it yet?" + +"I am sure." + +"And why?" + +"Because she has said that she would send it on the day when the betrothal was publicly proclaimed. That will be next Monday." + +"Oh, then we have three days yet," said Holmes with a yawn. "That is very fortunate, as I have one or two matters of importance to look into just at present. Your Majesty will, of course, stay in London for the present?" + +"Certainly. You will find me at the Langham under the name of the Count Von Kramm." + +"Then I shall drop you a line to let you know how we progress." + +"Pray do so. I shall be all anxiety." + +"Then, as to money?" + +"You have carte blanche." + +"Absolutely?" + +"I tell you that I would give one of the provinces of my kingdom to have that photograph." + +"And for present expenses?" + +The King took a heavy chamois leather bag from under his cloak and laid it on the table. + +"There are three hundred pounds in gold and seven hundred in notes," he said. + +Holmes scribbled a receipt upon a sheet of his note-book and handed it to him. + +"And Mademoiselle's address?" he asked. + +"Is Briony Lodge, Serpentine Avenue, St. John's Wood." + +Holmes took a note of it. "One other question," said he. "Was the photograph a cabinet?" + +"It was." + +"Then, good-night, your Majesty, and I trust that we shall soon have some good news for you. And good-night, Watson," he added, as the wheels of the royal brougham rolled down the street. "If you will be good enough to call to-morrow afternoon at three o'clock I should like to chat this little matter over with you." + +II. + + +At three o'clock precisely I was at Baker Street, but Holmes had not yet returned. The landlady informed me that he had left the house shortly after eight o'clock in the morning. I sat down beside the fire, however, with the intention of awaiting him, however long he might be. I was already deeply interested in his inquiry, for, though it was surrounded by none of the grim and strange features which were associated with the two crimes which I have already recorded, still, the nature of the case and the exalted station of his client gave it a character of its own. Indeed, apart from the nature of the investigation which my friend had on hand, there was something in his masterly grasp of a situation, and his keen, incisive reasoning, which made it a pleasure to me to study his system of work, and to follow the quick, subtle methods by which he disentangled the most inextricable mysteries. So accustomed was I to his invariable success that the very possibility of his failing had ceased to enter into my head. + +It was close upon four before the door opened, and a drunken-looking groom, ill-kempt and side-whiskered, with an inflamed face and disreputable clothes, walked into the room. Accustomed as I was to my friend's amazing powers in the use of disguises, I had to look three times before I was certain that it was indeed he. With a nod he vanished into the bedroom, whence he emerged in five minutes tweed-suited and respectable, as of old. Putting his hands into his pockets, he stretched out his legs in front of the fire and laughed heartily for some minutes. + +"Well, really!" he cried, and then he choked and laughed again until he was obliged to lie back, limp and helpless, in the chair. + +"What is it?" + +"It's quite too funny. I am sure you could never guess how I employed my morning, or what I ended by doing." + +"I can't imagine. I suppose that you have been watching the habits, and perhaps the house, of Miss Irene Adler." + +"Quite so; but the sequel was rather unusual. I will tell you, however. I left the house a little after eight o'clock this morning in the character of a groom out of work. There is a wonderful sympathy and freemasonry among horsey men. Be one of them, and you will know all that there is to know. I soon found Briony Lodge. It is a bijou villa, with a garden at the back, but built out in front right up to the road, two stories. Chubb lock to the door. Large sitting-room on the right side, well furnished, with long windows almost to the floor, and those preposterous English window fasteners which a child could open. Behind there was nothing remarkable, save that the passage window could be reached from the top of the coach-house. I walked round it and examined it closely from every point of view, but without noting anything else of interest. + +"I then lounged down the street and found, as I expected, that there was a mews in a lane which runs down by one wall of the garden. I lent the ostlers a hand in rubbing down their horses, and received in exchange twopence, a glass of half-and-half, two fills of shag tobacco, and as much information as I could desire about Miss Adler, to say nothing of half a dozen other people in the neighbourhood in whom I was not in the least interested, but whose biographies I was compelled to listen to." + +"And what of Irene Adler?" I asked. + +"Oh, she has turned all the men's heads down in that part. She is the daintiest thing under a bonnet on this planet. So say the Serpentine-mews, to a man. She lives quietly, sings at concerts, drives out at five every day, and returns at seven sharp for dinner. Seldom goes out at other times, except when she sings. Has only one male visitor, but a good deal of him. He is dark, handsome, and dashing, never calls less than once a day, and often twice. He is a Mr. Godfrey Norton, of the Inner Temple. See the advantages of a cabman as a confidant. They had driven him home a dozen times from Serpentine-mews, and knew all about him. When I had listened to all they had to tell, I began to walk up and down near Briony Lodge once more, and to think over my plan of campaign. + +"This Godfrey Norton was evidently an important factor in the matter. He was a lawyer. That sounded ominous. What was the relation between them, and what the object of his repeated visits? Was she his client, his friend, or his mistress? If the former, she had probably transferred the photograph to his keeping. If the latter, it was less likely. On the issue of this question depended whether I should continue my work at Briony Lodge, or turn my attention to the gentleman's chambers in the Temple. It was a delicate point, and it widened the field of my inquiry. I fear that I bore you with these details, but I have to let you see my little difficulties, if you are to understand the situation." + +"I am following you closely," I answered. + +"I was still balancing the matter in my mind when a hansom cab drove up to Briony Lodge, and a gentleman sprang out. He was a remarkably handsome man, dark, aquiline, and moustached--evidently the man of whom I had heard. He appeared to be in a great hurry, shouted to the cabman to wait, and brushed past the maid who opened the door with the air of a man who was thoroughly at home. + +"He was in the house about half an hour, and I could catch glimpses of him in the windows of the sitting-room, pacing up and down, talking excitedly, and waving his arms. Of her I could see nothing. Presently he emerged, looking even more flurried than before. As he stepped up to the cab, he pulled a gold watch from his pocket and looked at it earnestly, 'Drive like the devil,' he shouted, 'first to Gross & Hankey's in Regent Street, and then to the Church of St. Monica in the Edgeware Road. Half a guinea if you do it in twenty minutes!' + +"Away they went, and I was just wondering whether I should not do well to follow them when up the lane came a neat little landau, the coachman with his coat only half-buttoned, and his tie under his ear, while all the tags of his harness were sticking out of the buckles. It hadn't pulled up before she shot out of the hall door and into it. I only caught a glimpse of her at the moment, but she was a lovely woman, with a face that a man might die for. + +" 'The Church of St. Monica, John,' she cried, 'and half a sovereign if you reach it in twenty minutes.' + +"This was quite too good to lose, Watson. I was just balancing whether I should run for it, or whether I should perch behind her landau when a cab came through the street. The driver looked twice at such a shabby fare, but I jumped in before he could object. 'The Church of St. Monica,' said I, 'and half a sovereign if you reach it in twenty minutes.' It was twenty-five minutes to twelve, and of course it was clear enough what was in the wind. + +"My cabby drove fast. I don't think I ever drove faster, but the others were there before us. The cab and the landau with their steaming horses were in front of the door when I arrived. I paid the man and hurried into the church. There was not a soul there save the two whom I had followed and a surpliced clergyman, who seemed to be expostulating with them. They were all three standing in a knot in front of the altar. I lounged up the side aisle like any other idler who has dropped into a church. Suddenly, to my surprise, the three at the altar faced round to me, and Godfrey Norton came running as hard as he could towards me. + +" 'Thank God,' he cried. 'You'll do. Come! Come!' + +" 'What then?' I asked. + +" 'Come, man, come, only three minutes, or it won't be legal.' + +"I was half-dragged up to the altar, and before I knew where I was I found myself mumbling responses which were whispered in my ear, and vouching for things of which I knew nothing, and generally assisting in the secure tying up of Irene Adler, spinster, to Godfrey Norton, bachelor. It was all done in an instant, and there was the gentleman thanking me on the one side and the lady on the other, while the clergyman beamed on me in front. It was the most preposterous position in which I ever found myself in my life, and it was the thought of it that started me laughing just now. It seems that there had been some informality about their license, that the clergyman absolutely refused to marry them without a witness of some sort, and that my lucky appearance saved the bridegroom from having to sally out into the streets in search of a best man. The bride gave me a sovereign, and I mean to wear it on my watch chain in memory of the occasion." + +"This is a very unexpected turn of affairs," said I; "and what then?" + +"Well, I found my plans very seriously menaced. It looked as if the pair might take an immediate departure, and so necessitate very prompt and energetic measures on my part. At the church door, however, they separated, he driving back to the Temple, and she to her own house. 'I shall drive out in the park at five as usual,' she said as she left him. I heard no more. They drove away in different directions, and I went off to make my own arrangements." + +"Which are?" + +"Some cold beef and a glass of beer," he answered, ringing the bell. "I have been too busy to think of food, and I am likely to be busier still this evening. By the way, Doctor, I shall want your co-operation." + +"I shall be delighted." + +"You don't mind breaking the law?" + +"Not in the least." + +"Nor running a chance of arrest?" + +"Not in a good cause." + +"Oh, the cause is excellent!" + +"Then I am your man." + +"I was sure that I might rely on you." + +"But what is it you wish?" + +"When Mrs. Turner has brought in the tray I will make it clear to you. Now," he said as he turned hungrily on the simple fare that our landlady had provided, "I must discuss it while I eat, for I have not much time. It is nearly five now. In two hours we must be on the scene of action. Miss Irene, or Madame, rather, returns from her drive at seven. We must be at Briony Lodge to meet her." + +"And what then?" + +"You must leave that to me. I have already arranged what is to occur. There is only one point on which I must insist. You must not interfere, come what may. You understand?" + +"I am to be neutral?" + +"To do nothing whatever. There will probably be some small unpleasantness. Do not join in it. It will end in my being conveyed into the house. Four or five minutes afterwards the sitting-room window will open. You are to station yourself close to that open window." + +"Yes." + +"You are to watch me, for I will be visible to you." + +"Yes." + +"And when I raise my hand--so--you will throw into the room what I give you to throw, and will, at the same time, raise the cry of fire. You quite follow me?" + +"Entirely." + +"It is nothing very formidable," he said, taking a long cigar-shaped roll from his pocket. "It is an ordinary plumber's smoke-rocket, fitted with a cap at either end to make it self-lighting. Your task is confined to that. When you raise your cry of fire, it will be taken up by quite a number of people. You may then walk to the end of the street, and I will rejoin you in ten minutes. I hope that I have made myself clear?" + +"I am to remain neutral, to get near the window, to watch you, and at the signal to throw in this object, then to raise the cry of fire, and to wait you at the corner of the street." + +"Precisely." + +"Then you may entirely rely on me." + +"That is excellent. I think, perhaps, it is almost time that I prepare for the new role I have to play." + +He disappeared into his bedroom and returned in a few minutes in the character of an amiable and simple-minded Nonconformist clergyman. His broad black hat, his baggy trousers, his white tie, his sympathetic smile, and general look of peering and benevolent curiosity were such as Mr. John Hare alone could have equalled. It was not merely that Holmes changed his costume. His expression, his manner, his very soul seemed to vary with every fresh part that he assumed. The stage lost a fine actor, even as science lost an acute reasoner, when he became a specialist in crime. + +It was a quarter past six when we left Baker Street, and it still wanted ten minutes to the hour when we found ourselves in Serpentine Avenue. It was already dusk, and the lamps were just being lighted as we paced up and down in front of Briony Lodge, waiting for the coming of its occupant. The house was just such as I had pictured it from Sherlock Holmes' succinct description, but the locality appeared to be less private than I expected. On the contrary, for a small street in a quiet neighbourhood, it was remarkably animated. There was a group of shabbily dressed men smoking and laughing in a corner, a scissors-grinder with his wheel, two guardsmen who were flirting with a nurse-girl, and several well-dressed young men who were lounging up and down with cigars in their mouths. + +"You see," remarked Holmes, as we paced to and fro in front of the house, "this marriage rather simplifies matters. The photograph becomes a double-edged weapon now. The chances are that she would be as averse to its being seen by Mr. Godfrey Norton, as our client is to its coming to the eyes of his princess. Now the question is, Where are we to find the photograph?" + +"Where, indeed?" + +"It is most unlikely that she carries it about with her. It is cabinet size. Too large for easy concealment about a woman's dress. She knows that the King is capable of having her waylaid and searched. Two attempts of the sort have already been made. We may take it, then, that she does not carry it about with her." + +"Where, then?" + +"Her banker or her lawyer. There is that double possibility. But I am inclined to think neither. Women are naturally secretive, and they like to do their own secreting. Why should she hand it over to anyone else? She could trust her own guardianship, but she could not tell what indirect or political influence might be brought to bear upon a business man. Besides, remember that she had resolved to use it within a few days. It must be where she can lay her hands upon it. It must be in her own house." + +"But it has twice been burgled." + +"Pshaw! They did not know how to look." + +"But how will you look?" + +"I will not look." + +"What then?" + +"I will get her to show me." + +"But she will refuse." + +"She will not be able to. But I hear the rumble of wheels. It is her carriage. Now carry out my orders to the letter." + +As he spoke the gleam of the sidelights of a carriage came round the curve of the avenue. It was a smart little landau which rattled up to the door of Briony Lodge. As it pulled up, one of the loafing men at the corner dashed forward to open the door in the hope of earning a copper, but was elbowed away by another loafer, who had rushed up with the same intention. A fierce quarrel broke out, which was increased by the two guardsmen, who took sides with one of the loungers, and by the scissors-grinder, who was equally hot upon the other side. A blow was struck, and in an instant the lady, who had stepped from her carriage, was the centre of a little knot of flushed and struggling men, who struck savagely at each other with their fists and sticks. Holmes dashed into the crowd to protect the lady; but, just as he reached her, he gave a cry and dropped to the ground, with the blood running freely down his face. At his fall the guardsmen took to their heels in one direction and the loungers in the other, while a number of better dressed people, who had watched the scuffle without taking part in it, crowded in to help the lady and to attend to the injured man. Irene Adler, as I will still call her, had hurried up the steps; but she stood at the top with her superb figure outlined against the lights of the hall, looking back into the street. + +"Is the poor gentleman much hurt?" she asked. + +"He is dead," cried several voices. + +"No, no, there's life in him!" shouted another. "But he'll be gone before you can get him to hospital." + +"He's a brave fellow," said a woman. "They would have had the lady's purse and watch if it hadn't been for him. They were a gang, and a rough one, too. Ah, he's breathing now." + +"He can't lie in the street. May we bring him in, marm?" + +"Surely. Bring him into the sitting-room. There is a comfortable sofa. This way, please!" + +Slowly and solemnly he was borne into Briony Lodge and laid out in the principal room, while I still observed the proceedings from my post by the window. The lamps had been lit, but the blinds had not been drawn, so that I could see Holmes as he lay upon the couch. I do not know whether he was seized with compunction at that moment for the part he was playing, but I know that I never felt more heartily ashamed of myself in my life than when I saw the beautiful creature against whom I was conspiring, or the grace and kindliness with which she waited upon the injured man. And yet it would be the blackest treachery to Holmes to draw back now from the part which he had intrusted to me. I hardened my heart, and took the smoke-rocket from under my ulster. After all, I thought, we are not injuring her. We are but preventing her from injuring another. + +Holmes had sat up upon the couch, and I saw him motion like a man who is in need of air. A maid rushed across and threw open the window. At the same instant I saw him raise his hand and at the signal I tossed my rocket into the room with a cry of "Fire!" The word was no sooner out of my mouth than the whole crowd of spectators, well dressed and ill--gentlemen, ostlers, and servant maids--joined in a general shriek of "Fire!" Thick clouds of smoke curled through the room and out at the open window. I caught a glimpse of rushing figures, and a moment later the voice of Holmes from within assuring them that it was a false alarm. Slipping through the shouting crowd I made my way to the corner of the street, and in ten minutes was rejoiced to find my friend's arm in mine, and to get away from the scene of uproar. He walked swiftly and in silence for some few minutes until we had turned down one of the quiet streets which lead towards the Edgeware Road. + +"You did it very nicely, Doctor," he remarked. "Nothing could have been better. It is all right." + +"You have the photograph?" + +"I know where it is." + +"And how did you find out?" + +"She showed me, as I told you she would." + +"I am still in the dark." + +"I do not wish to make a mystery," said he, laughing. "The matter was perfectly simple. You, of course, saw that everyone in the street was an accomplice. They were all engaged for the evening." + +"I guessed as much." + +"Then, when the row broke out, I had a little moist red paint in the palm of my hand. I rushed forward, fell down, clapped my hand to my face, and became a piteous spectacle. It is an old trick." + +"That also I could fathom." + +"Then they carried me in. She was bound to have me in. What else could she do? And into her sitting-room, which was the very room which I suspected. It lay between that and her bedroom, and I was determined to see which. They laid me on a couch, I motioned for air, they were compelled to open the window, and you had your chance." + +"How did that help you?" + +"It was all-important. When a woman thinks that her house is on fire, her instinct is at once to rush to the thing which she values most. It is a perfectly overpowering impulse, and I have more than once taken advantage of it. In the case of the Darlington Substitution Scandal it was of use to me, and also in the Arnsworth Castle business. A married woman grabs at her baby; an unmarried one reaches for her jewel-box. Now it was clear to me that our lady of to-day had nothing in the house more precious to her than what we are in quest of. She would rush to secure it. The alarm of fire was admirably done. The smoke and shouting were enough to shake nerves of steel. She responded beautifully. The photograph is in a recess behind a sliding panel just above the right bell-pull. She was there in an instant, and I caught a glimpse of it as she half drew it out. When I cried out that it was a false alarm, she replaced it, glanced at the rocket, rushed from the room, and I have not seen her since. I rose, and, making my excuses, escaped from the house. I hesitated whether to attempt to secure the photograph at once; but the coachman had come in, and as he was watching me narrowly, it seemed safer to wait. A little over-precipitance may ruin all." + +"And now?" I asked. + +"Our quest is practically finished. I shall call with the King to-morrow, and with you, if you care to come with us. We will be shown into the sitting-room to wait for the lady, but it is probable that when she comes she may find neither us nor the photograph. It might be a satisfaction to his Majesty to regain it with his own hands." + +"And when will you call?" + +"At eight in the morning. She will not be up, so that we shall have a clear field. Besides, we must be prompt, for this marriage may mean a complete change in her life and habits. I must wire to the King without delay." + +We had reached Baker Street and had stopped at the door. He was searching his pockets for the key when someone passing said: + +"Good-night, Mister Sherlock Holmes." + +There were several people on the pavement at the time, but the greeting appeared to come from a slim youth in an ulster who had hurried by. + +"I've heard that voice before," said Holmes, staring down the dimly lit street. "Now, I wonder who the deuce that could have been." + +III. + + +I slept at Baker Street that night, and we were engaged upon our toast and coffee in the morning when the King of Bohemia rushed into the room. + +"You have really got it!" he cried, grasping Sherlock Holmes by either shoulder and looking eagerly into his face. + +"Not yet." + +"But you have hopes?" + +"I have hopes." + +"Then, come. I am all impatience to be gone." + +"We must have a cab." + +"No, my brougham is waiting." + +"Then that will simplify matters." We descended and started off once more for Briony Lodge. + +"Irene Adler is married," remarked Holmes. + +"Married! When?" + +"Yesterday." + +"But to whom?" + +"To an English lawyer named Norton." + +"But she could not love him." + +"I am in hopes that she does." + +"And why in hopes?" + +"Because it would spare your Majesty all fear of future annoyance. If the lady loves her husband, she does not love your Majesty. If she does not love your Majesty, there is no reason why she should interfere with your Majesty's plan." + +"It is true. And yet--! Well! I wish she had been of my own station! What a queen she would have made!" He relapsed into a moody silence, which was not broken until we drew up in Serpentine Avenue. + +The door of Briony Lodge was open, and an elderly woman stood upon the steps. She watched us with a sardonic eye as we stepped from the brougham. + +"Mr. Sherlock Holmes, I believe?" said she. + +"I am Mr. Holmes," answered my companion, looking at her with a questioning and rather startled gaze. + +"Indeed! My mistress told me that you were likely to call. She left this morning with her husband by the 5:15 train from Charing Cross for the Continent." + +"What!" Sherlock Holmes staggered back, white with chagrin and surprise. "Do you mean that she has left England?" + +"Never to return." + +"And the papers?" asked the King hoarsely. "All is lost." + +"We shall see." He pushed past the servant and rushed into the drawing-room, followed by the King and myself. The furniture was scattered about in every direction, with dismantled shelves and open drawers, as if the lady had hurriedly ransacked them before her flight. Holmes rushed at the bell-pull, tore back a small sliding shutter, and, plunging in his hand, pulled out a photograph and a letter. The photograph was of Irene Adler herself in evening dress, the letter was superscribed to "Sherlock Holmes, Esq. To be left till called for." My friend tore it open, and we all three read it together. It was dated at midnight of the preceding night and ran in this way: + +"MY DEAR MR. SHERLOCK HOLMES,--You really did it very well. You took me in completely. Until after the alarm of fire, I had not a suspicion. But then, when I found how I had betrayed myself, I began to think. I had been warned against you months ago. I had been told that, if the King employed an agent, it would certainly be you. And your address had been given me. Yet, with all this, you made me reveal what you wanted to know. Even after I became suspicious, I found it hard to think evil of such a dear, kind old clergyman. But, you know, I have been trained as an actress myself. Male costume is nothing new to me. I often take advantage of the freedom which it gives. I sent John, the coachman, to watch you, ran upstairs, got into my walking clothes, as I call them, and came down just as you departed. + +"Well, I followed you to your door, and so made sure that I was really an object of interest to the celebrated Mr. Sherlock Holmes. Then I, rather imprudently, wished you good-night, and started for the Temple to see my husband. + +"We both thought the best resource was flight, when pursued by so formidable an antagonist; so you will find the nest empty when you call to-morrow. As to the photograph, your client may rest in peace. I love and am loved by a better man than he. The King may do what he will without hindrance from one whom he has cruelly wronged. I keep it only to safeguard myself, and to preserve a weapon which will always secure me from any steps which he might take in the future. I leave a photograph which he might care to possess; and I remain, dear Mr. Sherlock Holmes, + + +"Very truly yours, +"IRENE NORTON, nee ADLER." + +"What a woman--oh, what a woman!" cried the King of Bohemia, when we had all three read this epistle. "Did I not tell you how quick and resolute she was? Would she not have made an admirable queen? Is it not a pity that she was not on my level?" + +"From what I have seen of the lady, she seems, indeed, to be on a very different level to your Majesty," said Holmes coldly. "I am sorry that I have not been able to bring your Majesty's business to a more successful conclusion." + +"On the contrary, my dear sir," cried the King; "nothing could be more successful. I know that her word is inviolate. The photograph is now as safe as if it were in the fire." + +"I am glad to hear your Majesty say so." + +"I am immensely indebted to you. Pray tell me in what way I can reward you. This ring--" He slipped an emerald snake ring from his finger and held it out upon the palm of his hand. + +"Your Majesty has something which I should value even more highly," said Holmes. + +"You have but to name it." + +"This photograph!" + +The King stared at him in amazement. + +"Irene's photograph!" he cried. "Certainly, if you wish it." + +"I thank your Majesty. Then there is no more to be done in the matter. I have the honour to wish you a very good morning." He bowed, and, turning away without observing the hand which the King had stretched out to him, he set off in my company for his chambers. + +And that was how a great scandal threatened to affect the kingdom of Bohemia, and how the best plans of Mr. Sherlock Holmes were beaten by a woman's wit. He used to make merry over the cleverness of women, but I have not heard him do it of late. And when he speaks of Irene Adler, or when he refers to her photograph, it is always under the honourable title of the woman. + +ADVENTURE II. THE RED-HEADED LEAGUE + + +I had called upon my friend, Mr. Sherlock Holmes, one day in the autumn of last year and found him in deep conversation with a very stout, florid-faced, elderly gentleman with fiery red hair. With an apology for my intrusion, I was about to withdraw when Holmes pulled me abruptly into the room and closed the door behind me. + +"You could not possibly have come at a better time, my dear Watson," he said cordially. + +"I was afraid that you were engaged." + +"So I am. Very much so." + +"Then I can wait in the next room." + +"Not at all. This gentleman, Mr. Wilson, has been my partner and helper in many of my most successful cases, and I have no doubt that he will be of the utmost use to me in yours also." + +The stout gentleman half rose from his chair and gave a bob of greeting, with a quick little questioning glance from his small fat-encircled eyes. + +"Try the settee," said Holmes, relapsing into his armchair and putting his fingertips together, as was his custom when in judicial moods. "I know, my dear Watson, that you share my love of all that is bizarre and outside the conventions and humdrum routine of everyday life. You have shown your relish for it by the enthusiasm which has prompted you to chronicle, and, if you will excuse my saying so, somewhat to embellish so many of my own little adventures." + +"Your cases have indeed been of the greatest interest to me," I observed. + +"You will remember that I remarked the other day, just before we went into the very simple problem presented by Miss Mary Sutherland, that for strange effects and extraordinary combinations we must go to life itself, which is always far more daring than any effort of the imagination." + +"A proposition which I took the liberty of doubting." + +"You did, Doctor, but none the less you must come round to my view, for otherwise I shall keep on piling fact upon fact on you until your reason breaks down under them and acknowledges me to be right. Now, Mr. Jabez Wilson here has been good enough to call upon me this morning, and to begin a narrative which promises to be one of the most singular which I have listened to for some time. You have heard me remark that the strangest and most unique things are very often connected not with the larger but with the smaller crimes, and occasionally, indeed, where there is room for doubt whether any positive crime has been committed. As far as I have heard, it is impossible for me to say whether the present case is an instance of crime or not, but the course of events is certainly among the most singular that I have ever listened to. Perhaps, Mr. Wilson, you would have the great kindness to recommence your narrative. I ask you not merely because my friend Dr. Watson has not heard the opening part but also because the peculiar nature of the story makes me anxious to have every possible detail from your lips. As a rule, when I have heard some slight indication of the course of events, I am able to guide myself by the thousands of other similar cases which occur to my memory. In the present instance I am forced to admit that the facts are, to the best of my belief, unique." + +The portly client puffed out his chest with an appearance of some little pride and pulled a dirty and wrinkled newspaper from the inside pocket of his greatcoat. As he glanced down the advertisement column, with his head thrust forward and the paper flattened out upon his knee, I took a good look at the man and endeavoured, after the fashion of my companion, to read the indications which might be presented by his dress or appearance. + +I did not gain very much, however, by my inspection. Our visitor bore every mark of being an average commonplace British tradesman, obese, pompous, and slow. He wore rather baggy grey shepherd's check trousers, a not over-clean black frock-coat, unbuttoned in the front, and a drab waistcoat with a heavy brassy Albert chain, and a square pierced bit of metal dangling down as an ornament. A frayed top-hat and a faded brown overcoat with a wrinkled velvet collar lay upon a chair beside him. Altogether, look as I would, there was nothing remarkable about the man save his blazing red head, and the expression of extreme chagrin and discontent upon his features. + +Sherlock Holmes' quick eye took in my occupation, and he shook his head with a smile as he noticed my questioning glances. "Beyond the obvious facts that he has at some time done manual labour, that he takes snuff, that he is a Freemason, that he has been in China, and that he has done a considerable amount of writing lately, I can deduce nothing else." + +Mr. Jabez Wilson started up in his chair, with his forefinger upon the paper, but his eyes upon my companion. + +"How, in the name of good-fortune, did you know all that, Mr. Holmes?" he asked. "How did you know, for example, that I did manual labour. It's as true as gospel, for I began as a ship's carpenter." + +"Your hands, my dear sir. Your right hand is quite a size larger than your left. You have worked with it, and the muscles are more developed." + +"Well, the snuff, then, and the Freemasonry?" + +"I won't insult your intelligence by telling you how I read that, especially as, rather against the strict rules of your order, you use an arc-and-compass breastpin." + +"Ah, of course, I forgot that. But the writing?" + +"What else can be indicated by that right cuff so very shiny for five inches, and the left one with the smooth patch near the elbow where you rest it upon the desk?" + +"Well, but China?" + +"The fish that you have tattooed immediately above your right wrist could only have been done in China. I have made a small study of tattoo marks and have even contributed to the literature of the subject. That trick of staining the fishes' scales of a delicate pink is quite peculiar to China. When, in addition, I see a Chinese coin hanging from your watch-chain, the matter becomes even more simple." + +Mr. Jabez Wilson laughed heavily. "Well, I never!" said he. "I thought at first that you had done something clever, but I see that there was nothing in it after all." + +"I begin to think, Watson," said Holmes, "that I make a mistake in explaining. 'Omne ignotum pro magnifico,' you know, and my poor little reputation, such as it is, will suffer shipwreck if I am so candid. Can you not find the advertisement, Mr. Wilson?" + +"Yes, I have got it now," he answered with his thick red finger planted halfway down the column. "Here it is. This is what began it all. You just read it for yourself, sir." + +I took the paper from him and read as follows: + +"TO THE RED-HEADED LEAGUE: On account of the bequest of the late Ezekiah Hopkins, of Lebanon, Pennsylvania, U. S. A., there is now another vacancy open which entitles a member of the League to a salary of $4 a week for purely nominal services. All red-headed men who are sound in body and mind and above the age of twenty-one years, are eligible. Apply in person on Monday, at eleven o'clock, to Duncan Ross, at the offices of the League, 7 Pope's Court, Fleet Street." + +"What on earth does this mean?" I ejaculated after I had twice read over the extraordinary announcement. + +Holmes chuckled and wriggled in his chair, as was his habit when in high spirits. "It is a little off the beaten track, isn't it?" said he. "And now, Mr. Wilson, off you go at scratch and tell us all about yourself, your household, and the effect which this advertisement had upon your fortunes. You will first make a note, Doctor, of the paper and the date." + +"It is The Morning Chronicle of April 27, 1890. Just two months ago." + +"Very good. Now, Mr. Wilson?" + +"Well, it is just as I have been telling you, Mr. Sherlock Holmes," said Jabez Wilson, mopping his forehead; "I have a small pawnbroker's business at Coburg Square, near the City. It's not a very large affair, and of late years it has not done more than just give me a living. I used to be able to keep two assistants, but now I only keep one; and I would have a job to pay him but that he is willing to come for half wages so as to learn the business." + +"What is the name of this obliging youth?" asked Sherlock Holmes. + +"His name is Vincent Spaulding, and he's not such a youth, either. It's hard to say his age. I should not wish a smarter assistant, Mr. Holmes; and I know very well that he could better himself and earn twice what I am able to give him. But, after all, if he is satisfied, why should I put ideas in his head?" + +"Why, indeed? You seem most fortunate in having an employe who comes under the full market price. It is not a common experience among employers in this age. I don't know that your assistant is not as remarkable as your advertisement." + +"Oh, he has his faults, too," said Mr. Wilson. "Never was such a fellow for photography. Snapping away with a camera when he ought to be improving his mind, and then diving down into the cellar like a rabbit into its hole to develop his pictures. That is his main fault, but on the whole he's a good worker. There's no vice in him." + +"He is still with you, I presume?" + +"Yes, sir. He and a girl of fourteen, who does a bit of simple cooking and keeps the place clean--that's all I have in the house, for I am a widower and never had any family. We live very quietly, sir, the three of us; and we keep a roof over our heads and pay our debts, if we do nothing more. + +"The first thing that put us out was that advertisement. Spaulding, he came down into the office just this day eight weeks, with this very paper in his hand, and he says: + +" 'I wish to the Lord, Mr. Wilson, that I was a red-headed man.' + +" 'Why that?' I asks. + +" 'Why,' says he, 'here's another vacancy on the League of the Red-headed Men. It's worth quite a little fortune to any man who gets it, and I understand that there are more vacancies than there are men, so that the trustees are at their wits' end what to do with the money. If my hair would only change colour, here's a nice little crib all ready for me to step into.' + +" 'Why, what is it, then?' I asked. You see, Mr. Holmes, I am a very stay-at-home man, and as my business came to me instead of my having to go to it, I was often weeks on end without putting my foot over the door-mat. In that way I didn't know much of what was going on outside, and I was always glad of a bit of news. + +" 'Have you never heard of the League of the Red-headed Men?' he asked with his eyes open. + +" 'Never.' + +" 'Why, I wonder at that, for you are eligible yourself for one of the vacancies.' + +" 'And what are they worth?' I asked. + +" 'Oh, merely a couple of hundred a year, but the work is slight, and it need not interfere very much with one's other occupations.' + +"Well, you can easily think that that made me prick up my ears, for the business has not been over good for some years, and an extra couple of hundred would have been very handy. + +" 'Tell me all about it,' said I. + +" 'Well,' said he, showing me the advertisement, 'you can see for yourself that the League has a vacancy, and there is the address where you should apply for particulars. As far as I can make out, the League was founded by an American millionaire, Ezekiah Hopkins, who was very peculiar in his ways. He was himself red-headed, and he had a great sympathy for all red-headed men; so, when he died, it was found that he had left his enormous fortune in the hands of trustees, with instructions to apply the interest to the providing of easy berths to men whose hair is of that colour. From all I hear it is splendid pay and very little to do.' + +" 'But,' said I, 'there would be millions of red-headed men who would apply.' + +" 'Not so many as you might think,' he answered. 'You see it is really confined to Londoners, and to grown men. This American had started from London when he was young, and he wanted to do the old town a good turn. Then, again, I have heard it is no use your applying if your hair is light red, or dark red, or anything but real bright, blazing, fiery red. Now, if you cared to apply, Mr. Wilson, you would just walk in; but perhaps it would hardly be worth your while to put yourself out of the way for the sake of a few hundred pounds.' + +"Now, it is a fact, gentlemen, as you may see for yourselves, that my hair is of a very full and rich tint, so that it seemed to me that if there was to be any competition in the matter I stood as good a chance as any man that I had ever met. Vincent Spaulding seemed to know so much about it that I thought he might prove useful, so I just ordered him to put up the shutters for the day and to come right away with me. He was very willing to have a holiday, so we shut the business up and started off for the address that was given us in the advertisement. + +"I never hope to see such a sight as that again, Mr. Holmes. From north, south, east, and west every man who had a shade of red in his hair had tramped into the city to answer the advertisement. Fleet Street was choked with red-headed folk, and Pope's Court looked like a coster's orange barrow. I should not have thought there were so many in the whole country as were brought together by that single advertisement. Every shade of colour they were--straw, lemon, orange, brick, Irish-setter, liver, clay; but, as Spaulding said, there were not many who had the real vivid flame-coloured tint. When I saw how many were waiting, I would have given it up in despair; but Spaulding would not hear of it. How he did it I could not imagine, but he pushed and pulled and butted until he got me through the crowd, and right up to the steps which led to the office. There was a double stream upon the stair, some going up in hope, and some coming back dejected; but we wedged in as well as we could and soon found ourselves in the office." + +"Your experience has been a most entertaining one," remarked Holmes as his client paused and refreshed his memory with a huge pinch of snuff. "Pray continue your very interesting statement." + +"There was nothing in the office but a couple of wooden chairs and a deal table, behind which sat a small man with a head that was even redder than mine. He said a few words to each candidate as he came up, and then he always managed to find some fault in them which would disqualify them. Getting a vacancy did not seem to be such a very easy matter, after all. However, when our turn came the little man was much more favourable to me than to any of the others, and he closed the door as we entered, so that he might have a private word with us. + +" 'This is Mr. Jabez Wilson,' said my assistant, 'and he is willing to fill a vacancy in the League.' + +" 'And he is admirably suited for it,' the other answered. 'He has every requirement. I cannot recall when I have seen anything so fine.' He took a step backward, cocked his head on one side, and gazed at my hair until I felt quite bashful. Then suddenly he plunged forward, wrung my hand, and congratulated me warmly on my success. + +" 'It would be injustice to hesitate,' said he. 'You will, however, I am sure, excuse me for taking an obvious precaution.' With that he seized my hair in both his hands, and tugged until I yelled with the pain. 'There is water in your eyes,' said he as he released me. 'I perceive that all is as it should be. But we have to be careful, for we have twice been deceived by wigs and once by paint. I could tell you tales of cobbler's wax which would disgust you with human nature.' He stepped over to the window and shouted through it at the top of his voice that the vacancy was filled. A groan of disappointment came up from below, and the folk all trooped away in different directions until there was not a red-head to be seen except my own and that of the manager. + +" 'My name,' said he, 'is Mr. Duncan Ross, and I am myself one of the pensioners upon the fund left by our noble benefactor. Are you a married man, Mr. Wilson? Have you a family?' + +"I answered that I had not. + +"His face fell immediately. + +" 'Dear me!' he said gravely, 'that is very serious indeed! I am sorry to hear you say that. The fund was, of course, for the propagation and spread of the red-heads as well as for their maintenance. It is exceedingly unfortunate that you should be a bachelor.' + +"My face lengthened at this, Mr. Holmes, for I thought that I was not to have the vacancy after all; but after thinking it over for a few minutes he said that it would be all right. + +" 'In the case of another,' said he, 'the objection might be fatal, but we must stretch a point in favour of a man with such a head of hair as yours. When shall you be able to enter upon your new duties?' + +" 'Well, it is a little awkward, for I have a business already,' said I. + +" 'Oh, never mind about that, Mr. Wilson!' said Vincent Spaulding. 'I should be able to look after that for you.' + +" 'What would be the hours?' I asked. + +" 'Ten to two.' + +"Now a pawnbroker's business is mostly done of an evening, Mr. Holmes, especially Thursday and Friday evening, which is just before pay-day; so it would suit me very well to earn a little in the mornings. Besides, I knew that my assistant was a good man, and that he would see to anything that turned up. + +" 'That would suit me very well,' said I. 'And the pay?' + +" 'Is $4 a week.' + +" 'And the work?' + +" 'Is purely nominal.' + +" 'What do you call purely nominal?' + +" 'Well, you have to be in the office, or at least in the building, the whole time. If you leave, you forfeit your whole position forever. The will is very clear upon that point. You don't comply with the conditions if you budge from the office during that time.' + +" 'It's only four hours a day, and I should not think of leaving,' said I. + +" 'No excuse will avail,' said Mr. Duncan Ross; 'neither sickness nor business nor anything else. There you must stay, or you lose your billet.' + +" 'And the work?' + +" 'Is to copy out the Encyclopaedia Britannica. There is the first volume of it in that press. You must find your own ink, pens, and blotting-paper, but we provide this table and chair. Will you be ready to-morrow?' + +" 'Certainly,' I answered. + +" 'Then, good-bye, Mr. Jabez Wilson, and let me congratulate you once more on the important position which you have been fortunate enough to gain.' He bowed me out of the room and I went home with my assistant, hardly knowing what to say or do, I was so pleased at my own good fortune. + +"Well, I thought over the matter all day, and by evening I was in low spirits again; for I had quite persuaded myself that the whole affair must be some great hoax or fraud, though what its object might be I could not imagine. It seemed altogether past belief that anyone could make such a will, or that they would pay such a sum for doing anything so simple as copying out the Encyclopaedia Britannica. Vincent Spaulding did what he could to cheer me up, but by bedtime I had reasoned myself out of the whole thing. However, in the morning I determined to have a look at it anyhow, so I bought a penny bottle of ink, and with a quill-pen, and seven sheets of foolscap paper, I started off for Pope's Court. + +"Well, to my surprise and delight, everything was as right as possible. The table was set out ready for me, and Mr. Duncan Ross was there to see that I got fairly to work. He started me off upon the letter A, and then he left me; but he would drop in from time to time to see that all was right with me. At two o'clock he bade me good-day, complimented me upon the amount that I had written, and locked the door of the office after me. + +"This went on day after day, Mr. Holmes, and on Saturday the manager came in and planked down four golden sovereigns for my week's work. It was the same next week, and the same the week after. Every morning I was there at ten, and every afternoon I left at two. By degrees Mr. Duncan Ross took to coming in only once of a morning, and then, after a time, he did not come in at all. Still, of course, I never dared to leave the room for an instant, for I was not sure when he might come, and the billet was such a good one, and suited me so well, that I would not risk the loss of it. + +"Eight weeks passed away like this, and I had written about Abbots and Archery and Armour and Architecture and Attica, and hoped with diligence that I might get on to the B's before very long. It cost me something in foolscap, and I had pretty nearly filled a shelf with my writings. And then suddenly the whole business came to an end." + +"To an end?" + +"Yes, sir. And no later than this morning. I went to my work as usual at ten o'clock, but the door was shut and locked, with a little square of cardboard hammered on to the middle of the panel with a tack. Here it is, and you can read for yourself." + +He held up a piece of white cardboard about the size of a sheet of note-paper. It read in this fashion: + + +THE RED-HEADED LEAGUE + +IS + +DISSOLVED. + +October 9, 1890. + + +Sherlock Holmes and I surveyed this curt announcement and the rueful face behind it, until the comical side of the affair so completely overtopped every other consideration that we both burst out into a roar of laughter. + +"I cannot see that there is anything very funny," cried our client, flushing up to the roots of his flaming head. "If you can do nothing better than laugh at me, I can go elsewhere." + +"No, no," cried Holmes, shoving him back into the chair from which he had half risen. "I really wouldn't miss your case for the world. It is most refreshingly unusual. But there is, if you will excuse my saying so, something just a little funny about it. Pray what steps did you take when you found the card upon the door?" + +"I was staggered, sir. I did not know what to do. Then I called at the offices round, but none of them seemed to know anything about it. Finally, I went to the landlord, who is an accountant living on the ground floor, and I asked him if he could tell me what had become of the Red-headed League. He said that he had never heard of any such body. Then I asked him who Mr. Duncan Ross was. He answered that the name was new to him. + +" 'Well,' said I, 'the gentleman at No. 4.' + +" 'What, the red-headed man?' + +" 'Yes.' + +" 'Oh,' said he, 'his name was William Morris. He was a solicitor and was using my room as a temporary convenience until his new premises were ready. He moved out yesterday.' + +" 'Where could I find him?' + +" 'Oh, at his new offices. He did tell me the address. Yes, 17 King Edward Street, near St. Paul's.' + +"I started off, Mr. Holmes, but when I got to that address it was a manufactory of artificial knee-caps, and no one in it had ever heard of either Mr. William Morris or Mr. Duncan Ross." + +"And what did you do then?" asked Holmes. + +"I went home to Saxe-Coburg Square, and I took the advice of my assistant. But he could not help me in any way. He could only say that if I waited I should hear by post. But that was not quite good enough, Mr. Holmes. I did not wish to lose such a place without a struggle, so, as I had heard that you were good enough to give advice to poor folk who were in need of it, I came right away to you." + +"And you did very wisely," said Holmes. "Your case is an exceedingly remarkable one, and I shall be happy to look into it. From what you have told me I think that it is possible that graver issues hang from it than might at first sight appear." + +"Grave enough!" said Mr. Jabez Wilson. "Why, I have lost four pound a week." + +"As far as you are personally concerned," remarked Holmes, "I do not see that you have any grievance against this extraordinary league. On the contrary, you are, as I understand, richer by some $30, to say nothing of the minute knowledge which you have gained on every subject which comes under the letter A. You have lost nothing by them." + +"No, sir. But I want to find out about them, and who they are, and what their object was in playing this prank--if it was a prank--upon me. It was a pretty expensive joke for them, for it cost them two and thirty pounds." + +"We shall endeavour to clear up these points for you. And, first, one or two questions, Mr. Wilson. This assistant of yours who first called your attention to the advertisement--how long had he been with you?" + +"About a month then." + +"How did he come?" + +"In answer to an advertisement." + +"Was he the only applicant?" + +"No, I had a dozen." + +"Why did you pick him?" + +"Because he was handy and would come cheap." + +"At half wages, in fact." + +"Yes." + +"What is he like, this Vincent Spaulding?" + +"Small, stout-built, very quick in his ways, no hair on his face, though he's not short of thirty. Has a white splash of acid upon his forehead." + +Holmes sat up in his chair in considerable excitement. "I thought as much," said he. "Have you ever observed that his ears are pierced for earrings?" + +"Yes, sir. He told me that a gipsy had done it for him when he was a lad." + +"Hum!" said Holmes, sinking back in deep thought. "He is still with you?" + +"Oh, yes, sir; I have only just left him." + +"And has your business been attended to in your absence?" + +"Nothing to complain of, sir. There's never very much to do of a morning." + +"That will do, Mr. Wilson. I shall be happy to give you an opinion upon the subject in the course of a day or two. To-day is Saturday, and I hope that by Monday we may come to a conclusion." + +"Well, Watson," said Holmes when our visitor had left us, "what do you make of it all?" + +"I make nothing of it," I answered frankly. "It is a most mysterious business." + +"As a rule," said Holmes, "the more bizarre a thing is the less mysterious it proves to be. It is your commonplace, featureless crimes which are really puzzling, just as a commonplace face is the most difficult to identify. But I must be prompt over this matter." + +"What are you going to do, then?" I asked. + +"To smoke," he answered. "It is quite a three pipe problem, and I beg that you won't speak to me for fifty minutes." He curled himself up in his chair, with his thin knees drawn up to his hawk-like nose, and there he sat with his eyes closed and his black clay pipe thrusting out like the bill of some strange bird. I had come to the conclusion that he had dropped asleep, and indeed was nodding myself, when he suddenly sprang out of his chair with the gesture of a man who has made up his mind and put his pipe down upon the mantelpiece. + +"Sarasate plays at the St. James's Hall this afternoon," he remarked. "What do you think, Watson? Could your patients spare you for a few hours?" + +"I have nothing to do to-day. My practice is never very absorbing." + +"Then put on your hat and come. I am going through the City first, and we can have some lunch on the way. I observe that there is a good deal of German music on the programme, which is rather more to my taste than Italian or French. It is introspective, and I want to introspect. Come along!" + +We travelled by the Underground as far as Aldersgate; and a short walk took us to Saxe-Coburg Square, the scene of the singular story which we had listened to in the morning. It was a poky, little, shabby-genteel place, where four lines of dingy two-storied brick houses looked out into a small railed-in enclosure, where a lawn of weedy grass and a few clumps of faded laurel bushes made a hard fight against a smoke-laden and uncongenial atmosphere. Three gilt balls and a brown board with "JABEZ WILSON" in white letters, upon a corner house, announced the place where our red-headed client carried on his business. Sherlock Holmes stopped in front of it with his head on one side and looked it all over, with his eyes shining brightly between puckered lids. Then he walked slowly up the street, and then down again to the corner, still looking keenly at the houses. Finally he returned to the pawnbroker's, and, having thumped vigorously upon the pavement with his stick two or three times, he went up to the door and knocked. It was instantly opened by a bright-looking, clean-shaven young fellow, who asked him to step in. + +"Thank you," said Holmes, "I only wished to ask you how you would go from here to the Strand." + +"Third right, fourth left," answered the assistant promptly, closing the door. + +"Smart fellow, that," observed Holmes as we walked away. "He is, in my judgment, the fourth smartest man in London, and for daring I am not sure that he has not a claim to be third. I have known something of him before." + +"Evidently," said I, "Mr. Wilson's assistant counts for a good deal in this mystery of the Red-headed League. I am sure that you inquired your way merely in order that you might see him." + +"Not him." + +"What then?" + +"The knees of his trousers." + +"And what did you see?" + +"What I expected to see." + +"Why did you beat the pavement?" + +"My dear doctor, this is a time for observation, not for talk. We are spies in an enemy's country. We know something of Saxe-Coburg Square. Let us now explore the parts which lie behind it." + +The road in which we found ourselves as we turned round the corner from the retired Saxe-Coburg Square presented as great a contrast to it as the front of a picture does to the back. It was one of the main arteries which conveyed the traffic of the City to the north and west. The roadway was blocked with the immense stream of commerce flowing in a double tide inward and outward, while the footpaths were black with the hurrying swarm of pedestrians. It was difficult to realise as we looked at the line of fine shops and stately business premises that they really abutted on the other side upon the faded and stagnant square which we had just quitted. + +"Let me see," said Holmes, standing at the corner and glancing along the line, "I should like just to remember the order of the houses here. It is a hobby of mine to have an exact knowledge of London. There is Mortimer's, the tobacconist, the little newspaper shop, the Coburg branch of the City and Suburban Bank, the Vegetarian Restaurant, and McFarlane's carriage-building depot. That carries us right on to the other block. And now, Doctor, we've done our work, so it's time we had some play. A sandwich and a cup of coffee, and then off to violin-land, where all is sweetness and delicacy and harmony, and there are no red-headed clients to vex us with their conundrums." + +My friend was an enthusiastic musician, being himself not only a very capable performer but a composer of no ordinary merit. All the afternoon he sat in the stalls wrapped in the most perfect happiness, gently waving his long, thin fingers in time to the music, while his gently smiling face and his languid, dreamy eyes were as unlike those of Holmes the sleuth-hound, Holmes the relentless, keen-witted, ready-handed criminal agent, as it was possible to conceive. In his singular character the dual nature alternately asserted itself, and his extreme exactness and astuteness represented, as I have often thought, the reaction against the poetic and contemplative mood which occasionally predominated in him. The swing of his nature took him from extreme languor to devouring energy; and, as I knew well, he was never so truly formidable as when, for days on end, he had been lounging in his armchair amid his improvisations and his black-letter editions. Then it was that the lust of the chase would suddenly come upon him, and that his brilliant reasoning power would rise to the level of intuition, until those who were unacquainted with his methods would look askance at him as on a man whose knowledge was not that of other mortals. When I saw him that afternoon so enwrapped in the music at St. James's Hall I felt that an evil time might be coming upon those whom he had set himself to hunt down. + +"You want to go home, no doubt, Doctor," he remarked as we emerged. + +"Yes, it would be as well." + +"And I have some business to do which will take some hours. This business at Coburg Square is serious." + +"Why serious?" + +"A considerable crime is in contemplation. I have every reason to believe that we shall be in time to stop it. But to-day being Saturday rather complicates matters. I shall want your help to-night." + +"At what time?" + +"Ten will be early enough." + +"I shall be at Baker Street at ten." + +"Very well. And, I say, Doctor, there may be some little danger, so kindly put your army revolver in your pocket." He waved his hand, turned on his heel, and disappeared in an instant among the crowd. + +I trust that I am not more dense than my neighbours, but I was always oppressed with a sense of my own stupidity in my dealings with Sherlock Holmes. Here I had heard what he had heard, I had seen what he had seen, and yet from his words it was evident that he saw clearly not only what had happened but what was about to happen, while to me the whole business was still confused and grotesque. As I drove home to my house in Kensington I thought over it all, from the extraordinary story of the red-headed copier of the Encyclopaedia down to the visit to Saxe-Coburg Square, and the ominous words with which he had parted from me. What was this nocturnal expedition, and why should I go armed? Where were we going, and what were we to do? I had the hint from Holmes that this smooth-faced pawnbroker's assistant was a formidable man--a man who might play a deep game. I tried to puzzle it out, but gave it up in despair and set the matter aside until night should bring an explanation. + +It was a quarter-past nine when I started from home and made my way across the Park, and so through Oxford Street to Baker Street. Two hansoms were standing at the door, and as I entered the passage I heard the sound of voices from above. On entering his room, I found Holmes in animated conversation with two men, one of whom I recognised as Peter Jones, the official police agent, while the other was a long, thin, sad-faced man, with a very shiny hat and oppressively respectable frock-coat. + +"Ha! Our party is complete," said Holmes, buttoning up his pea-jacket and taking his heavy hunting crop from the rack. "Watson, I think you know Mr. Jones, of Scotland Yard? Let me introduce you to Mr. Merryweather, who is to be our companion in to-night's adventure." + +"We're hunting in couples again, Doctor, you see," said Jones in his consequential way. "Our friend here is a wonderful man for starting a chase. All he wants is an old dog to help him to do the running down." + +"I hope a wild goose may not prove to be the end of our chase," observed Mr. Merryweather gloomily. + +"You may place considerable confidence in Mr. Holmes, sir," said the police agent loftily. "He has his own little methods, which are, if he won't mind my saying so, just a little too theoretical and fantastic, but he has the makings of a detective in him. It is not too much to say that once or twice, as in that business of the Sholto murder and the Agra treasure, he has been more nearly correct than the official force." + +"Oh, if you say so, Mr. Jones, it is all right," said the stranger with deference. "Still, I confess that I miss my rubber. It is the first Saturday night for seven-and-twenty years that I have not had my rubber." + +"I think you will find," said Sherlock Holmes, "that you will play for a higher stake to-night than you have ever done yet, and that the play will be more exciting. For you, Mr. Merryweather, the stake will be some $30,000; and for you, Jones, it will be the man upon whom you wish to lay your hands." + +"John Clay, the murderer, thief, smasher, and forger. He's a young man, Mr. Merryweather, but he is at the head of his profession, and I would rather have my bracelets on him than on any criminal in London. He's a remarkable man, is young John Clay. His grandfather was a royal duke, and he himself has been to Eton and Oxford. His brain is as cunning as his fingers, and though we meet signs of him at every turn, we never know where to find the man himself. He'll crack a crib in Scotland one week, and be raising money to build an orphanage in Cornwall the next. I've been on his track for years and have never set eyes on him yet." + +"I hope that I may have the pleasure of introducing you to-night. I've had one or two little turns also with Mr. John Clay, and I agree with you that he is at the head of his profession. It is past ten, however, and quite time that we started. If you two will take the first hansom, Watson and I will follow in the second." + +Sherlock Holmes was not very communicative during the long drive and lay back in the cab humming the tunes which he had heard in the afternoon. We rattled through an endless labyrinth of gas-lit streets until we emerged into Farrington Street. + +"We are close there now," my friend remarked. "This fellow Merryweather is a bank director, and personally interested in the matter. I thought it as well to have Jones with us also. He is not a bad fellow, though an absolute imbecile in his profession. He has one positive virtue. He is as brave as a bulldog and as tenacious as a lobster if he gets his claws upon anyone. Here we are, and they are waiting for us." + +We had reached the same crowded thoroughfare in which we had found ourselves in the morning. Our cabs were dismissed, and, following the guidance of Mr. Merryweather, we passed down a narrow passage and through a side door, which he opened for us. Within there was a small corridor, which ended in a very massive iron gate. This also was opened, and led down a flight of winding stone steps, which terminated at another formidable gate. Mr. Merryweather stopped to light a lantern, and then conducted us down a dark, earth-smelling passage, and so, after opening a third door, into a huge vault or cellar, which was piled all round with crates and massive boxes. + +"You are not very vulnerable from above," Holmes remarked as he held up the lantern and gazed about him. + +"Nor from below," said Mr. Merryweather, striking his stick upon the flags which lined the floor. "Why, dear me, it sounds quite hollow!" he remarked, looking up in surprise. + +"I must really ask you to be a little more quiet!" said Holmes severely. "You have already imperilled the whole success of our expedition. Might I beg that you would have the goodness to sit down upon one of those boxes, and not to interfere?" + +The solemn Mr. Merryweather perched himself upon a crate, with a very injured expression upon his face, while Holmes fell upon his knees upon the floor and, with the lantern and a magnifying lens, began to examine minutely the cracks between the stones. A few seconds sufficed to satisfy him, for he sprang to his feet again and put his glass in his pocket. + +"We have at least an hour before us," he remarked, "for they can hardly take any steps until the good pawnbroker is safely in bed. Then they will not lose a minute, for the sooner they do their work the longer time they will have for their escape. We are at present, Doctor--as no doubt you have divined--in the cellar of the City branch of one of the principal London banks. Mr. Merryweather is the chairman of directors, and he will explain to you that there are reasons why the more daring criminals of London should take a considerable interest in this cellar at present." + +"It is our French gold," whispered the director. "We have had several warnings that an attempt might be made upon it." + +"Your French gold?" + +"Yes. We had occasion some months ago to strengthen our resources and borrowed for that purpose 30,000 napoleons from the Bank of France. It has become known that we have never had occasion to unpack the money, and that it is still lying in our cellar. The crate upon which I sit contains 2,000 napoleons packed between layers of lead foil. Our reserve of bullion is much larger at present than is usually kept in a single branch office, and the directors have had misgivings upon the subject." + +"Which were very well justified," observed Holmes. "And now it is time that we arranged our little plans. I expect that within an hour matters will come to a head. In the meantime Mr. Merryweather, we must put the screen over that dark lantern." + +"And sit in the dark?" + +"I am afraid so. I had brought a pack of cards in my pocket, and I thought that, as we were a partie carree, you might have your rubber after all. But I see that the enemy's preparations have gone so far that we cannot risk the presence of a light. And, first of all, we must choose our positions. These are daring men, and though we shall take them at a disadvantage, they may do us some harm unless we are careful. I shall stand behind this crate, and do you conceal yourselves behind those. Then, when I flash a light upon them, close in swiftly. If they fire, Watson, have no compunction about shooting them down." + +I placed my revolver, cocked, upon the top of the wooden case behind which I crouched. Holmes shot the slide across the front of his lantern and left us in pitch darkness--such an absolute darkness as I have never before experienced. The smell of hot metal remained to assure us that the light was still there, ready to flash out at a moment's notice. To me, with my nerves worked up to a pitch of expectancy, there was something depressing and subduing in the sudden gloom, and in the cold dank air of the vault. + +"They have but one retreat," whispered Holmes. "That is back through the house into Saxe-Coburg Square. I hope that you have done what I asked you, Jones?" + +"I have an inspector and two officers waiting at the front door." + +"Then we have stopped all the holes. And now we must be silent and wait." + +What a time it seemed! From comparing notes afterwards it was but an hour and a quarter, yet it appeared to me that the night must have almost gone, and the dawn be breaking above us. My limbs were weary and stiff, for I feared to change my position; yet my nerves were worked up to the highest pitch of tension, and my hearing was so acute that I could not only hear the gentle breathing of my companions, but I could distinguish the deeper, heavier in-breath of the bulky Jones from the thin, sighing note of the bank director. From my position I could look over the case in the direction of the floor. Suddenly my eyes caught the glint of a light. + +At first it was but a lurid spark upon the stone pavement. Then it lengthened out until it became a yellow line, and then, without any warning or sound, a gash seemed to open and a hand appeared, a white, almost womanly hand, which felt about in the centre of the little area of light. For a minute or more the hand, with its writhing fingers, protruded out of the floor. Then it was withdrawn as suddenly as it appeared, and all was dark again save the single lurid spark which marked a chink between the stones. + +Its disappearance, however, was but momentary. With a rending, tearing sound, one of the broad, white stones turned over upon its side and left a square, gaping hole, through which streamed the light of a lantern. Over the edge there peeped a clean-cut, boyish face, which looked keenly about it, and then, with a hand on either side of the aperture, drew itself shoulder-high and waist-high, until one knee rested upon the edge. In another instant he stood at the side of the hole and was hauling after him a companion, lithe and small like himself, with a pale face and a shock of very red hair. + +"It's all clear," he whispered. "Have you the chisel and the bags? Great Scott! Jump, Archie, jump, and I'll swing for it!" + +Sherlock Holmes had sprung out and seized the intruder by the collar. The other dived down the hole, and I heard the sound of rending cloth as Jones clutched at his skirts. The light flashed upon the barrel of a revolver, but Holmes' hunting crop came down on the man's wrist, and the pistol clinked upon the stone floor. + +"It's no use, John Clay," said Holmes blandly. "You have no chance at all." + +"So I see," the other answered with the utmost coolness. "I fancy that my pal is all right, though I see you have got his coat-tails." + +"There are three men waiting for him at the door," said Holmes. + +"Oh, indeed! You seem to have done the thing very completely. I must compliment you." + +"And I you," Holmes answered. "Your red-headed idea was very new and effective." + +"You'll see your pal again presently," said Jones. "He's quicker at climbing down holes than I am. Just hold out while I fix the derbies." + +"I beg that you will not touch me with your filthy hands," remarked our prisoner as the handcuffs clattered upon his wrists. "You may not be aware that I have royal blood in my veins. Have the goodness, also, when you address me always to say 'sir' and 'please.' " + +"All right," said Jones with a stare and a snigger. "Well, would you please, sir, march upstairs, where we can get a cab to carry your Highness to the police-station?" + +"That is better," said John Clay serenely. He made a sweeping bow to the three of us and walked quietly off in the custody of the detective. + +"Really, Mr. Holmes," said Mr. Merryweather as we followed them from the cellar, "I do not know how the bank can thank you or repay you. There is no doubt that you have detected and defeated in the most complete manner one of the most determined attempts at bank robbery that have ever come within my experience." + +"I have had one or two little scores of my own to settle with Mr. John Clay," said Holmes. "I have been at some small expense over this matter, which I shall expect the bank to refund, but beyond that I am amply repaid by having had an experience which is in many ways unique, and by hearing the very remarkable narrative of the Red-headed League." + +"You see, Watson," he explained in the early hours of the morning as we sat over a glass of whisky and soda in Baker Street, "it was perfectly obvious from the first that the only possible object of this rather fantastic business of the advertisement of the League, and the copying of the Encyclopaedia, must be to get this not over-bright pawnbroker out of the way for a number of hours every day. It was a curious way of managing it, but, really, it would be difficult to suggest a better. The method was no doubt suggested to Clay's ingenious mind by the colour of his accomplice's hair. The $4 a week was a lure which must draw him, and what was it to them, who were playing for thousands? They put in the advertisement, one rogue has the temporary office, the other rogue incites the man to apply for it, and together they manage to secure his absence every morning in the week. From the time that I heard of the assistant having come for half wages, it was obvious to me that he had some strong motive for securing the situation." + +"But how could you guess what the motive was?" + +"Had there been women in the house, I should have suspected a mere vulgar intrigue. That, however, was out of the question. The man's business was a small one, and there was nothing in his house which could account for such elaborate preparations, and such an expenditure as they were at. It must, then, be something out of the house. What could it be? I thought of the assistant's fondness for photography, and his trick of vanishing into the cellar. The cellar! There was the end of this tangled clue. Then I made inquiries as to this mysterious assistant and found that I had to deal with one of the coolest and most daring criminals in London. He was doing something in the cellar--something which took many hours a day for months on end. What could it be, once more? I could think of nothing save that he was running a tunnel to some other building. + +"So far I had got when we went to visit the scene of action. I surprised you by beating upon the pavement with my stick. I was ascertaining whether the cellar stretched out in front or behind. It was not in front. Then I rang the bell, and, as I hoped, the assistant answered it. We have had some skirmishes, but we had never set eyes upon each other before. I hardly looked at his face. His knees were what I wished to see. You must yourself have remarked how worn, wrinkled, and stained they were. They spoke of those hours of burrowing. The only remaining point was what they were burrowing for. I walked round the corner, saw the City and Suburban Bank abutted on our friend's premises, and felt that I had solved my problem. When you drove home after the concert I called upon Scotland Yard and upon the chairman of the bank directors, with the result that you have seen." + +"And how could you tell that they would make their attempt to-night?" I asked. + +"Well, when they closed their League offices that was a sign that they cared no longer about Mr. Jabez Wilson's presence--in other words, that they had completed their tunnel. But it was essential that they should use it soon, as it might be discovered, or the bullion might be removed. Saturday would suit them better than any other day, as it would give them two days for their escape. For all these reasons I expected them to come to-night." + +"You reasoned it out beautifully," I exclaimed in unfeigned admiration. "It is so long a chain, and yet every link rings true." + +"It saved me from ennui," he answered, yawning. "Alas! I already feel it closing in upon me. My life is spent in one long effort to escape from the commonplaces of existence. These little problems help me to do so." + +"And you are a benefactor of the race," said I. + +He shrugged his shoulders. "Well, perhaps, after all, it is of some little use," he remarked. " 'L'homme c'est rien--l'oeuvre c'est tout,' as Gustave Flaubert wrote to George Sand." + +ADVENTURE III. A CASE OF IDENTITY + + +"My dear fellow," said Sherlock Holmes as we sat on either side of the fire in his lodgings at Baker Street, "life is infinitely stranger than anything which the mind of man could invent. We would not dare to conceive the things which are really mere commonplaces of existence. If we could fly out of that window hand in hand, hover over this great city, gently remove the roofs, and peep in at the queer things which are going on, the strange coincidences, the plannings, the cross-purposes, the wonderful chains of events, working through generations, and leading to the most outre results, it would make all fiction with its conventionalities and foreseen conclusions most stale and unprofitable." + +"And yet I am not convinced of it," I answered. "The cases which come to light in the papers are, as a rule, bald enough, and vulgar enough. We have in our police reports realism pushed to its extreme limits, and yet the result is, it must be confessed, neither fascinating nor artistic." + +"A certain selection and discretion must be used in producing a realistic effect," remarked Holmes. "This is wanting in the police report, where more stress is laid, perhaps, upon the platitudes of the magistrate than upon the details, which to an observer contain the vital essence of the whole matter. Depend upon it, there is nothing so unnatural as the commonplace." + +I smiled and shook my head. "I can quite understand your thinking so." I said. "Of course, in your position of unofficial adviser and helper to everybody who is absolutely puzzled, throughout three continents, you are brought in contact with all that is strange and bizarre. But here"--I picked up the morning paper from the ground--"let us put it to a practical test. Here is the first heading upon which I come. 'A husband's cruelty to his wife.' There is half a column of print, but I know without reading it that it is all perfectly familiar to me. There is, of course, the other woman, the drink, the push, the blow, the bruise, the sympathetic sister or landlady. The crudest of writers could invent nothing more crude." + +"Indeed, your example is an unfortunate one for your argument," said Holmes, taking the paper and glancing his eye down it. "This is the Dundas separation case, and, as it happens, I was engaged in clearing up some small points in connection with it. The husband was a teetotaler, there was no other woman, and the conduct complained of was that he had drifted into the habit of winding up every meal by taking out his false teeth and hurling them at his wife, which, you will allow, is not an action likely to occur to the imagination of the average story-teller. Take a pinch of snuff, Doctor, and acknowledge that I have scored over you in your example." + +He held out his snuffbox of old gold, with a great amethyst in the centre of the lid. Its splendour was in such contrast to his homely ways and simple life that I could not help commenting upon it. + +"Ah," said he, "I forgot that I had not seen you for some weeks. It is a little souvenir from the King of Bohemia in return for my assistance in the case of the Irene Adler papers." + +"And the ring?" I asked, glancing at a remarkable brilliant which sparkled upon his finger. + +"It was from the reigning family of Holland, though the matter in which I served them was of such delicacy that I cannot confide it even to you, who have been good enough to chronicle one or two of my little problems." + +"And have you any on hand just now?" I asked with interest. + +"Some ten or twelve, but none which present any feature of interest. They are important, you understand, without being interesting. Indeed, I have found that it is usually in unimportant matters that there is a field for the observation, and for the quick analysis of cause and effect which gives the charm to an investigation. The larger crimes are apt to be the simpler, for the bigger the crime the more obvious, as a rule, is the motive. In these cases, save for one rather intricate matter which has been referred to me from Marseilles, there is nothing which presents any features of interest. It is possible, however, that I may have something better before very many minutes are over, for this is one of my clients, or I am much mistaken." + +He had risen from his chair and was standing between the parted blinds gazing down into the dull neutral-tinted London street. Looking over his shoulder, I saw that on the pavement opposite there stood a large woman with a heavy fur boa round her neck, and a large curling red feather in a broad-brimmed hat which was tilted in a coquettish Duchess of Devonshire fashion over her ear. From under this great panoply she peeped up in a nervous, hesitating fashion at our windows, while her body oscillated backward and forward, and her fingers fidgeted with her glove buttons. Suddenly, with a plunge, as of the swimmer who leaves the bank, she hurried across the road, and we heard the sharp clang of the bell. + +"I have seen those symptoms before," said Holmes, throwing his cigarette into the fire. "Oscillation upon the pavement always means an affaire de coeur. She would like advice, but is not sure that the matter is not too delicate for communication. And yet even here we may discriminate. When a woman has been seriously wronged by a man she no longer oscillates, and the usual symptom is a broken bell wire. Here we may take it that there is a love matter, but that the maiden is not so much angry as perplexed, or grieved. But here she comes in person to resolve our doubts." + +As he spoke there was a tap at the door, and the boy in buttons entered to announce Miss Mary Sutherland, while the lady herself loomed behind his small black figure like a full-sailed merchant-man behind a tiny pilot boat. Sherlock Holmes welcomed her with the easy courtesy for which he was remarkable, and, having closed the door and bowed her into an armchair, he looked her over in the minute and yet abstracted fashion which was peculiar to him. + +"Do you not find," he said, "that with your short sight it is a little trying to do so much typewriting?" + +"I did at first," she answered, "but now I know where the letters are without looking." Then, suddenly realising the full purport of his words, she gave a violent start and looked up, with fear and astonishment upon her broad, good-humoured face. "You've heard about me, Mr. Holmes," she cried, "else how could you know all that?" + +"Never mind," said Holmes, laughing; "it is my business to know things. Perhaps I have trained myself to see what others overlook. If not, why should you come to consult me?" + +"I came to you, sir, because I heard of you from Mrs. Etherege, whose husband you found so easy when the police and everyone had given him up for dead. Oh, Mr. Holmes, I wish you would do as much for me. I'm not rich, but still I have a hundred a year in my own right, besides the little that I make by the machine, and I would give it all to know what has become of Mr. Hosmer Angel." + +"Why did you come away to consult me in such a hurry?" asked Sherlock Holmes, with his finger-tips together and his eyes to the ceiling. + +Again a startled look came over the somewhat vacuous face of Miss Mary Sutherland. "Yes, I did bang out of the house," she said, "for it made me angry to see the easy way in which Mr. Windibank--that is, my father--took it all. He would not go to the police, and he would not go to you, and so at last, as he would do nothing and kept on saying that there was no harm done, it made me mad, and I just on with my things and came right away to you." + +"Your father," said Holmes, "your stepfather, surely, since the name is different." + +"Yes, my stepfather. I call him father, though it sounds funny, too, for he is only five years and two months older than myself." + +"And your mother is alive?" + +"Oh, yes, mother is alive and well. I wasn't best pleased, Mr. Holmes, when she married again so soon after father's death, and a man who was nearly fifteen years younger than herself. Father was a plumber in the Tottenham Court Road, and he left a tidy business behind him, which mother carried on with Mr. Hardy, the foreman; but when Mr. Windibank came he made her sell the business, for he was very superior, being a traveller in wines. They got $4700 for the goodwill and interest, which wasn't near as much as father could have got if he had been alive." + +I had expected to see Sherlock Holmes impatient under this rambling and inconsequential narrative, but, on the contrary, he had listened with the greatest concentration of attention. + +"Your own little income," he asked, "does it come out of the business?" + +"Oh, no, sir. It is quite separate and was left me by my uncle Ned in Auckland. It is in New Zealand stock, paying 4 1/4 per cent. Two thousand five hundred pounds was the amount, but I can only touch the interest." + +"You interest me extremely," said Holmes. "And since you draw so large a sum as a hundred a year, with what you earn into the bargain, you no doubt travel a little and indulge yourself in every way. I believe that a single lady can get on very nicely upon an income of about $60." + +"I could do with much less than that, Mr. Holmes, but you understand that as long as I live at home I don't wish to be a burden to them, and so they have the use of the money just while I am staying with them. Of course, that is only just for the time. Mr. Windibank draws my interest every quarter and pays it over to mother, and I find that I can do pretty well with what I earn at typewriting. It brings me twopence a sheet, and I can often do from fifteen to twenty sheets in a day." + +"You have made your position very clear to me," said Holmes. "This is my friend, Dr. Watson, before whom you can speak as freely as before myself. Kindly tell us now all about your connection with Mr. Hosmer Angel." + +A flush stole over Miss Sutherland's face, and she picked nervously at the fringe of her jacket. "I met him first at the gasfitters' ball," she said. "They used to send father tickets when he was alive, and then afterwards they remembered us, and sent them to mother. Mr. Windibank did not wish us to go. He never did wish us to go anywhere. He would get quite mad if I wanted so much as to join a Sunday-school treat. But this time I was set on going, and I would go; for what right had he to prevent? He said the folk were not fit for us to know, when all father's friends were to be there. And he said that I had nothing fit to wear, when I had my purple plush that I had never so much as taken out of the drawer. At last, when nothing else would do, he went off to France upon the business of the firm, but we went, mother and I, with Mr. Hardy, who used to be our foreman, and it was there I met Mr. Hosmer Angel." + +"I suppose," said Holmes, "that when Mr. Windibank came back from France he was very annoyed at your having gone to the ball." + +"Oh, well, he was very good about it. He laughed, I remember, and shrugged his shoulders, and said there was no use denying anything to a woman, for she would have her way." + +"I see. Then at the gasfitters' ball you met, as I understand, a gentleman called Mr. Hosmer Angel." + +"Yes, sir. I met him that night, and he called next day to ask if we had got home all safe, and after that we met him--that is to say, Mr. Holmes, I met him twice for walks, but after that father came back again, and Mr. Hosmer Angel could not come to the house any more." + +"No?" + +"Well, you know father didn't like anything of the sort. He wouldn't have any visitors if he could help it, and he used to say that a woman should be happy in her own family circle. But then, as I used to say to mother, a woman wants her own circle to begin with, and I had not got mine yet." + +"But how about Mr. Hosmer Angel? Did he make no attempt to see you?" + +"Well, father was going off to France again in a week, and Hosmer wrote and said that it would be safer and better not to see each other until he had gone. We could write in the meantime, and he used to write every day. I took the letters in in the morning, so there was no need for father to know." + +"Were you engaged to the gentleman at this time?" + +"Oh, yes, Mr. Holmes. We were engaged after the first walk that we took. Hosmer--Mr. Angel--was a cashier in an office in Leadenhall Street--and--" + +"What office?" + +"That's the worst of it, Mr. Holmes, I don't know." + +"Where did he live, then?" + +"He slept on the premises." + +"And you don't know his address?" + +"No--except that it was Leadenhall Street." + +"Where did you address your letters, then?" + +"To the Leadenhall Street Post Office, to be left till called for. He said that if they were sent to the office he would be chaffed by all the other clerks about having letters from a lady, so I offered to typewrite them, like he did his, but he wouldn't have that, for he said that when I wrote them they seemed to come from me, but when they were typewritten he always felt that the machine had come between us. That will just show you how fond he was of me, Mr. Holmes, and the little things that he would think of." + +"It was most suggestive," said Holmes. "It has long been an axiom of mine that the little things are infinitely the most important. Can you remember any other little things about Mr. Hosmer Angel?" + +"He was a very shy man, Mr. Holmes. He would rather walk with me in the evening than in the daylight, for he said that he hated to be conspicuous. Very retiring and gentlemanly he was. Even his voice was gentle. He'd had the quinsy and swollen glands when he was young, he told me, and it had left him with a weak throat, and a hesitating, whispering fashion of speech. He was always well dressed, very neat and plain, but his eyes were weak, just as mine are, and he wore tinted glasses against the glare." + +"Well, and what happened when Mr. Windibank, your stepfather, returned to France?" + +"Mr. Hosmer Angel came to the house again and proposed that we should marry before father came back. He was in dreadful earnest and made me swear, with my hands on the Testament, that whatever happened I would always be true to him. Mother said he was quite right to make me swear, and that it was a sign of his passion. Mother was all in his favour from the first and was even fonder of him than I was. Then, when they talked of marrying within the week, I began to ask about father; but they both said never to mind about father, but just to tell him afterwards, and mother said she would make it all right with him. I didn't quite like that, Mr. Holmes. It seemed funny that I should ask his leave, as he was only a few years older than me; but I didn't want to do anything on the sly, so I wrote to father at Bordeaux, where the company has its French offices, but the letter came back to me on the very morning of the wedding." + +"It missed him, then?" + +"Yes, sir; for he had started to England just before it arrived." + +"Ha! that was unfortunate. Your wedding was arranged, then, for the Friday. Was it to be in church?" + +"Yes, sir, but very quietly. It was to be at St. Saviour's, near King's Cross, and we were to have breakfast afterwards at the St. Pancras Hotel. Hosmer came for us in a hansom, but as there were two of us he put us both into it and stepped himself into a four-wheeler, which happened to be the only other cab in the street. We got to the church first, and when the four-wheeler drove up we waited for him to step out, but he never did, and when the cabman got down from the box and looked there was no one there! The cabman said that he could not imagine what had become of him, for he had seen him get in with his own eyes. That was last Friday, Mr. Holmes, and I have never seen or heard anything since then to throw any light upon what became of him." + +"It seems to me that you have been very shamefully treated," said Holmes. + +"Oh, no, sir! He was too good and kind to leave me so. Why, all the morning he was saying to me that, whatever happened, I was to be true; and that even if something quite unforeseen occurred to separate us, I was always to remember that I was pledged to him, and that he would claim his pledge sooner or later. It seemed strange talk for a wedding-morning, but what has happened since gives a meaning to it." + +"Most certainly it does. Your own opinion is, then, that some unforeseen catastrophe has occurred to him?" + +"Yes, sir. I believe that he foresaw some danger, or else he would not have talked so. And then I think that what he foresaw happened." + +"But you have no notion as to what it could have been?" + +"None." + +"One more question. How did your mother take the matter?" + +"She was angry, and said that I was never to speak of the matter again." + +"And your father? Did you tell him?" + +"Yes; and he seemed to think, with me, that something had happened, and that I should hear of Hosmer again. As he said, what interest could anyone have in bringing me to the doors of the church, and then leaving me? Now, if he had borrowed my money, or if he had married me and got my money settled on him, there might be some reason, but Hosmer was very independent about money and never would look at a shilling of mine. And yet, what could have happened? And why could he not write? Oh, it drives me half-mad to think of it, and I can't sleep a wink at night." She pulled a little handkerchief out of her muff and began to sob heavily into it. + +"I shall glance into the case for you," said Holmes, rising, "and I have no doubt that we shall reach some definite result. Let the weight of the matter rest upon me now, and do not let your mind dwell upon it further. Above all, try to let Mr. Hosmer Angel vanish from your memory, as he has done from your life." + +"Then you don't think I'll see him again?" + +"I fear not." + +"Then what has happened to him?" + +"You will leave that question in my hands. I should like an accurate description of him and any letters of his which you can spare." + +"I advertised for him in last Saturday's Chronicle," said she. "Here is the slip and here are four letters from him." + +"Thank you. And your address?" + +"No. 31 Lyon Place, Camberwell." + +"Mr. Angel's address you never had, I understand. Where is your father's place of business?" + +"He travels for Westhouse & Marbank, the great claret importers of Fenchurch Street." + +"Thank you. You have made your statement very clearly. You will leave the papers here, and remember the advice which I have given you. Let the whole incident be a sealed book, and do not allow it to affect your life." + +"You are very kind, Mr. Holmes, but I cannot do that. I shall be true to Hosmer. He shall find me ready when he comes back." + +For all the preposterous hat and the vacuous face, there was something noble in the simple faith of our visitor which compelled our respect. She laid her little bundle of papers upon the table and went her way, with a promise to come again whenever she might be summoned. + +Sherlock Holmes sat silent for a few minutes with his fingertips still pressed together, his legs stretched out in front of him, and his gaze directed upward to the ceiling. Then he took down from the rack the old and oily clay pipe, which was to him as a counsellor, and, having lit it, he leaned back in his chair, with the thick blue cloud-wreaths spinning up from him, and a look of infinite languor in his face. + +"Quite an interesting study, that maiden," he observed. "I found her more interesting than her little problem, which, by the way, is rather a trite one. You will find parallel cases, if you consult my index, in Andover in '77, and there was something of the sort at The Hague last year. Old as is the idea, however, there were one or two details which were new to me. But the maiden herself was most instructive." + +"You appeared to read a good deal upon her which was quite invisible to me," I remarked. + +"Not invisible but unnoticed, Watson. You did not know where to look, and so you missed all that was important. I can never bring you to realise the importance of sleeves, the suggestiveness of thumb-nails, or the great issues that may hang from a boot-lace. Now, what did you gather from that woman's appearance? Describe it." + +"Well, she had a slate-coloured, broad-brimmed straw hat, with a feather of a brickish red. Her jacket was black, with black beads sewn upon it, and a fringe of little black jet ornaments. Her dress was brown, rather darker than coffee colour, with a little purple plush at the neck and sleeves. Her gloves were greyish and were worn through at the right forefinger. Her boots I didn't observe. She had small round, hanging gold earrings, and a general air of being fairly well-to-do in a vulgar, comfortable, easy-going way." + +Sherlock Holmes clapped his hands softly together and chuckled. + +" 'Pon my word, Watson, you are coming along wonderfully. You have really done very well indeed. It is true that you have missed everything of importance, but you have hit upon the method, and you have a quick eye for colour. Never trust to general impressions, my boy, but concentrate yourself upon details. My first glance is always at a woman's sleeve. In a man it is perhaps better first to take the knee of the trouser. As you observe, this woman had plush upon her sleeves, which is a most useful material for showing traces. The double line a little above the wrist, where the typewritist presses against the table, was beautifully defined. The sewing-machine, of the hand type, leaves a similar mark, but only on the left arm, and on the side of it farthest from the thumb, instead of being right across the broadest part, as this was. I then glanced at her face, and, observing the dint of a pince-nez at either side of her nose, I ventured a remark upon short sight and typewriting, which seemed to surprise her." + +"It surprised me." + +"But, surely, it was obvious. I was then much surprised and interested on glancing down to observe that, though the boots which she was wearing were not unlike each other, they were really odd ones; the one having a slightly decorated toe-cap, and the other a plain one. One was buttoned only in the two lower buttons out of five, and the other at the first, third, and fifth. Now, when you see that a young lady, otherwise neatly dressed, has come away from home with odd boots, half-buttoned, it is no great deduction to say that she came away in a hurry." + +"And what else?" I asked, keenly interested, as I always was, by my friend's incisive reasoning. + +"I noted, in passing, that she had written a note before leaving home but after being fully dressed. You observed that her right glove was torn at the forefinger, but you did not apparently see that both glove and finger were stained with violet ink. She had written in a hurry and dipped her pen too deep. It must have been this morning, or the mark would not remain clear upon the finger. All this is amusing, though rather elementary, but I must go back to business, Watson. Would you mind reading me the advertised description of Mr. Hosmer Angel?" + +I held the little printed slip to the light. + +"Missing," it said, "on the morning of the fourteenth, a gentleman named Hosmer Angel. About five ft. seven in. in height; strongly built, sallow complexion, black hair, a little bald in the centre, bushy, black side-whiskers and moustache; tinted glasses, slight infirmity of speech. Was dressed, when last seen, in black frock-coat faced with silk, black waistcoat, gold Albert chain, and grey Harris tweed trousers, with brown gaiters over elastic-sided boots. Known to have been employed in an office in Leadenhall Street. Anybody bringing--" + +"That will do," said Holmes. "As to the letters," he continued, glancing over them, "they are very commonplace. Absolutely no clue in them to Mr. Angel, save that he quotes Balzac once. There is one remarkable point, however, which will no doubt strike you." + +"They are typewritten," I remarked. + +"Not only that, but the signature is typewritten. Look at the neat little 'Hosmer Angel' at the bottom. There is a date, you see, but no superscription except Leadenhall Street, which is rather vague. The point about the signature is very suggestive--in fact, we may call it conclusive." + +"Of what?" + +"My dear fellow, is it possible you do not see how strongly it bears upon the case?" + +"I cannot say that I do unless it were that he wished to be able to deny his signature if an action for breach of promise were instituted." + +"No, that was not the point. However, I shall write two letters, which should settle the matter. One is to a firm in the City, the other is to the young lady's stepfather, Mr. Windibank, asking him whether he could meet us here at six o'clock to-morrow evening. It is just as well that we should do business with the male relatives. And now, Doctor, we can do nothing until the answers to those letters come, so we may put our little problem upon the shelf for the interim." + +I had had so many reasons to believe in my friend's subtle powers of reasoning and extraordinary energy in action that I felt that he must have some solid grounds for the assured and easy demeanour with which he treated the singular mystery which he had been called upon to fathom. Once only had I known him to fail, in the case of the King of Bohemia and of the Irene Adler photograph; but when I looked back to the weird business of the Sign of Four, and the extraordinary circumstances connected with the Study in Scarlet, I felt that it would be a strange tangle indeed which he could not unravel. + +I left him then, still puffing at his black clay pipe, with the conviction that when I came again on the next evening I would find that he held in his hands all the clues which would lead up to the identity of the disappearing bridegroom of Miss Mary Sutherland. + +A professional case of great gravity was engaging my own attention at the time, and the whole of next day I was busy at the bedside of the sufferer. It was not until close upon six o'clock that I found myself free and was able to spring into a hansom and drive to Baker Street, half afraid that I might be too late to assist at the denouement of the little mystery. I found Sherlock Holmes alone, however, half asleep, with his long, thin form curled up in the recesses of his armchair. A formidable array of bottles and test-tubes, with the pungent cleanly smell of hydrochloric acid, told me that he had spent his day in the chemical work which was so dear to him. + +"Well, have you solved it?" I asked as I entered. + +"Yes. It was the bisulphate of baryta." + +"No, no, the mystery!" I cried. + +"Oh, that! I thought of the salt that I have been working upon. There was never any mystery in the matter, though, as I said yesterday, some of the details are of interest. The only drawback is that there is no law, I fear, that can touch the scoundrel." + +"Who was he, then, and what was his object in deserting Miss Sutherland?" + +The question was hardly out of my mouth, and Holmes had not yet opened his lips to reply, when we heard a heavy footfall in the passage and a tap at the door. + +"This is the girl's stepfather, Mr. James Windibank," said Holmes. "He has written to me to say that he would be here at six. Come in!" + +The man who entered was a sturdy, middle-sized fellow, some thirty years of age, clean-shaven, and sallow-skinned, with a bland, insinuating manner, and a pair of wonderfully sharp and penetrating grey eyes. He shot a questioning glance at each of us, placed his shiny top-hat upon the sideboard, and with a slight bow sidled down into the nearest chair. + +"Good-evening, Mr. James Windibank," said Holmes. "I think that this typewritten letter is from you, in which you made an appointment with me for six o'clock?" + +"Yes, sir. I am afraid that I am a little late, but I am not quite my own master, you know. I am sorry that Miss Sutherland has troubled you about this little matter, for I think it is far better not to wash linen of the sort in public. It was quite against my wishes that she came, but she is a very excitable, impulsive girl, as you may have noticed, and she is not easily controlled when she has made up her mind on a point. Of course, I did not mind you so much, as you are not connected with the official police, but it is not pleasant to have a family misfortune like this noised abroad. Besides, it is a useless expense, for how could you possibly find this Hosmer Angel?" + +"On the contrary," said Holmes quietly; "I have every reason to believe that I will succeed in discovering Mr. Hosmer Angel." + +Mr. Windibank gave a violent start and dropped his gloves. "I am delighted to hear it," he said. + +"It is a curious thing," remarked Holmes, "that a typewriter has really quite as much individuality as a man's handwriting. Unless they are quite new, no two of them write exactly alike. Some letters get more worn than others, and some wear only on one side. Now, you remark in this note of yours, Mr. Windibank, that in every case there is some little slurring over of the 'e,' and a slight defect in the tail of the 'r.' There are fourteen other characteristics, but those are the more obvious." + +"We do all our correspondence with this machine at the office, and no doubt it is a little worn," our visitor answered, glancing keenly at Holmes with his bright little eyes. + +"And now I will show you what is really a very interesting study, Mr. Windibank," Holmes continued. "I think of writing another little monograph some of these days on the typewriter and its relation to crime. It is a subject to which I have devoted some little attention. I have here four letters which purport to come from the missing man. They are all typewritten. In each case, not only are the 'e's' slurred and the 'r's' tailless, but you will observe, if you care to use my magnifying lens, that the fourteen other characteristics to which I have alluded are there as well." + +Mr. Windibank sprang out of his chair and picked up his hat. "I cannot waste time over this sort of fantastic talk, Mr. Holmes," he said. "If you can catch the man, catch him, and let me know when you have done it." + +"Certainly," said Holmes, stepping over and turning the key in the door. "I let you know, then, that I have caught him!" + +"What! where?" shouted Mr. Windibank, turning white to his lips and glancing about him like a rat in a trap. + +"Oh, it won't do--really it won't," said Holmes suavely. "There is no possible getting out of it, Mr. Windibank. It is quite too transparent, and it was a very bad compliment when you said that it was impossible for me to solve so simple a question. That's right! Sit down and let us talk it over." + +Our visitor collapsed into a chair, with a ghastly face and a glitter of moisture on his brow. "It--it's not actionable," he stammered. + +"I am very much afraid that it is not. But between ourselves, Windibank, it was as cruel and selfish and heartless a trick in a petty way as ever came before me. Now, let me just run over the course of events, and you will contradict me if I go wrong." + +The man sat huddled up in his chair, with his head sunk upon his breast, like one who is utterly crushed. Holmes stuck his feet up on the corner of the mantelpiece and, leaning back with his hands in his pockets, began talking, rather to himself, as it seemed, than to us. + +"The man married a woman very much older than himself for her money," said he, "and he enjoyed the use of the money of the daughter as long as she lived with them. It was a considerable sum, for people in their position, and the loss of it would have made a serious difference. It was worth an effort to preserve it. The daughter was of a good, amiable disposition, but affectionate and warm-hearted in her ways, so that it was evident that with her fair personal advantages, and her little income, she would not be allowed to remain single long. Now her marriage would mean, of course, the loss of a hundred a year, so what does her stepfather do to prevent it? He takes the obvious course of keeping her at home and forbidding her to seek the company of people of her own age. But soon he found that that would not answer forever. She became restive, insisted upon her rights, and finally announced her positive intention of going to a certain ball. What does her clever stepfather do then? He conceives an idea more creditable to his head than to his heart. With the connivance and assistance of his wife he disguised himself, covered those keen eyes with tinted glasses, masked the face with a moustache and a pair of bushy whiskers, sunk that clear voice into an insinuating whisper, and doubly secure on account of the girl's short sight, he appears as Mr. Hosmer Angel, and keeps off other lovers by making love himself." + +"It was only a joke at first," groaned our visitor. "We never thought that she would have been so carried away." + +"Very likely not. However that may be, the young lady was very decidedly carried away, and, having quite made up her mind that her stepfather was in France, the suspicion of treachery never for an instant entered her mind. She was flattered by the gentleman's attentions, and the effect was increased by the loudly expressed admiration of her mother. Then Mr. Angel began to call, for it was obvious that the matter should be pushed as far as it would go if a real effect were to be produced. There were meetings, and an engagement, which would finally secure the girl's affections from turning towards anyone else. But the deception could not be kept up forever. These pretended journeys to France were rather cumbrous. The thing to do was clearly to bring the business to an end in such a dramatic manner that it would leave a permanent impression upon the young lady's mind and prevent her from looking upon any other suitor for some time to come. Hence those vows of fidelity exacted upon a Testament, and hence also the allusions to a possibility of something happening on the very morning of the wedding. James Windibank wished Miss Sutherland to be so bound to Hosmer Angel, and so uncertain as to his fate, that for ten years to come, at any rate, she would not listen to another man. As far as the church door he brought her, and then, as he could go no farther, he conveniently vanished away by the old trick of stepping in at one door of a four-wheeler and out at the other. I think that was the chain of events, Mr. Windibank!" + +Our visitor had recovered something of his assurance while Holmes had been talking, and he rose from his chair now with a cold sneer upon his pale face. + +"It may be so, or it may not, Mr. Holmes," said he, "but if you are so very sharp you ought to be sharp enough to know that it is you who are breaking the law now, and not me. I have done nothing actionable from the first, but as long as you keep that door locked you lay yourself open to an action for assault and illegal constraint." + +"The law cannot, as you say, touch you," said Holmes, unlocking and throwing open the door, "yet there never was a man who deserved punishment more. If the young lady has a brother or a friend, he ought to lay a whip across your shoulders. By Jove!" he continued, flushing up at the sight of the bitter sneer upon the man's face, "it is not part of my duties to my client, but here's a hunting crop handy, and I think I shall just treat myself to--" He took two swift steps to the whip, but before he could grasp it there was a wild clatter of steps upon the stairs, the heavy hall door banged, and from the window we could see Mr. James Windibank running at the top of his speed down the road. + +"There's a cold-blooded scoundrel!" said Holmes, laughing, as he threw himself down into his chair once more. "That fellow will rise from crime to crime until he does something very bad, and ends on a gallows. The case has, in some respects, been not entirely devoid of interest." + +"I cannot now entirely see all the steps of your reasoning," I remarked. + +"Well, of course it was obvious from the first that this Mr. Hosmer Angel must have some strong object for his curious conduct, and it was equally clear that the only man who really profited by the incident, as far as we could see, was the stepfather. Then the fact that the two men were never together, but that the one always appeared when the other was away, was suggestive. So were the tinted spectacles and the curious voice, which both hinted at a disguise, as did the bushy whiskers. My suspicions were all confirmed by his peculiar action in typewriting his signature, which, of course, inferred that his handwriting was so familiar to her that she would recognise even the smallest sample of it. You see all these isolated facts, together with many minor ones, all pointed in the same direction." + +"And how did you verify them?" + +"Having once spotted my man, it was easy to get corroboration. I knew the firm for which this man worked. Having taken the printed description. I eliminated everything from it which could be the result of a disguise--the whiskers, the glasses, the voice, and I sent it to the firm, with a request that they would inform me whether it answered to the description of any of their travellers. I had already noticed the peculiarities of the typewriter, and I wrote to the man himself at his business address asking him if he would come here. As I expected, his reply was typewritten and revealed the same trivial but characteristic defects. The same post brought me a letter from Westhouse & Marbank, of Fenchurch Street, to say that the description tallied in every respect with that of their employe, James Windibank. Voila tout!" + +"And Miss Sutherland?" + +"If I tell her she will not believe me. You may remember the old Persian saying, 'There is danger for him who taketh the tiger cub, and danger also for whoso snatches a delusion from a woman.' There is as much sense in Hafiz as in Horace, and as much knowledge of the world." + +ADVENTURE IV. THE BOSCOMBE VALLEY MYSTERY + + +We were seated at breakfast one morning, my wife and I, when the maid brought in a telegram. It was from Sherlock Holmes and ran in this way: + +"Have you a couple of days to spare? Have just been wired for from the west of England in connection with Boscombe Valley tragedy. Shall be glad if you will come with me. Air and scenery perfect. Leave Paddington by the 11:15." + +"What do you say, dear?" said my wife, looking across at me. "Will you go?" + +"I really don't know what to say. I have a fairly long list at present." + +"Oh, Anstruther would do your work for you. You have been looking a little pale lately. I think that the change would do you good, and you are always so interested in Mr. Sherlock Holmes' cases." + +"I should be ungrateful if I were not, seeing what I gained through one of them," I answered. "But if I am to go, I must pack at once, for I have only half an hour." + +My experience of camp life in Afghanistan had at least had the effect of making me a prompt and ready traveller. My wants were few and simple, so that in less than the time stated I was in a cab with my valise, rattling away to Paddington Station. Sherlock Holmes was pacing up and down the platform, his tall, gaunt figure made even gaunter and taller by his long grey travelling-cloak and close-fitting cloth cap. + +"It is really very good of you to come, Watson," said he. "It makes a considerable difference to me, having someone with me on whom I can thoroughly rely. Local aid is always either worthless or else biassed. If you will keep the two corner seats I shall get the tickets." + +We had the carriage to ourselves save for an immense litter of papers which Holmes had brought with him. Among these he rummaged and read, with intervals of note-taking and of meditation, until we were past Reading. Then he suddenly rolled them all into a gigantic ball and tossed them up onto the rack. + +"Have you heard anything of the case?" he asked. + +"Not a word. I have not seen a paper for some days." + +"The London press has not had very full accounts. I have just been looking through all the recent papers in order to master the particulars. It seems, from what I gather, to be one of those simple cases which are so extremely difficult." + +"That sounds a little paradoxical." + +"But it is profoundly true. Singularity is almost invariably a clue. The more featureless and commonplace a crime is, the more difficult it is to bring it home. In this case, however, they have established a very serious case against the son of the murdered man." + +"It is a murder, then?" + +"Well, it is conjectured to be so. I shall take nothing for granted until I have the opportunity of looking personally into it. I will explain the state of things to you, as far as I have been able to understand it, in a very few words. + +"Boscombe Valley is a country district not very far from Ross, in Herefordshire. The largest landed proprietor in that part is a Mr. John Turner, who made his money in Australia and returned some years ago to the old country. One of the farms which he held, that of Hatherley, was let to Mr. Charles McCarthy, who was also an ex-Australian. The men had known each other in the colonies, so that it was not unnatural that when they came to settle down they should do so as near each other as possible. Turner was apparently the richer man, so McCarthy became his tenant but still remained, it seems, upon terms of perfect equality, as they were frequently together. McCarthy had one son, a lad of eighteen, and Turner had an only daughter of the same age, but neither of them had wives living. They appear to have avoided the society of the neighbouring English families and to have led retired lives, though both the McCarthys were fond of sport and were frequently seen at the race-meetings of the neighbourhood. McCarthy kept two servants--a man and a girl. Turner had a considerable household, some half-dozen at the least. That is as much as I have been able to gather about the families. Now for the facts. + +"On June 3rd, that is, on Monday last, McCarthy left his house at Hatherley about three in the afternoon and walked down to the Boscombe Pool, which is a small lake formed by the spreading out of the stream which runs down the Boscombe Valley. He had been out with his serving-man in the morning at Ross, and he had told the man that he must hurry, as he had an appointment of importance to keep at three. From that appointment he never came back alive. + +"From Hatherley Farmhouse to the Boscombe Pool is a quarter of a mile, and two people saw him as he passed over this ground. One was an old woman, whose name is not mentioned, and the other was William Crowder, a game-keeper in the employ of Mr. Turner. Both these witnesses depose that Mr. McCarthy was walking alone. The game-keeper adds that within a few minutes of his seeing Mr. McCarthy pass he had seen his son, Mr. James McCarthy, going the same way with a gun under his arm. To the best of his belief, the father was actually in sight at the time, and the son was following him. He thought no more of the matter until he heard in the evening of the tragedy that had occurred. + +"The two McCarthys were seen after the time when William Crowder, the game-keeper, lost sight of them. The Boscombe Pool is thickly wooded round, with just a fringe of grass and of reeds round the edge. A girl of fourteen, Patience Moran, who is the daughter of the lodge-keeper of the Boscombe Valley estate, was in one of the woods picking flowers. She states that while she was there she saw, at the border of the wood and close by the lake, Mr. McCarthy and his son, and that they appeared to be having a violent quarrel. She heard Mr. McCarthy the elder using very strong language to his son, and she saw the latter raise up his hand as if to strike his father. She was so frightened by their violence that she ran away and told her mother when she reached home that she had left the two McCarthys quarrelling near Boscombe Pool, and that she was afraid that they were going to fight. She had hardly said the words when young Mr. McCarthy came running up to the lodge to say that he had found his father dead in the wood, and to ask for the help of the lodge-keeper. He was much excited, without either his gun or his hat, and his right hand and sleeve were observed to be stained with fresh blood. On following him they found the dead body stretched out upon the grass beside the pool. The head had been beaten in by repeated blows of some heavy and blunt weapon. The injuries were such as might very well have been inflicted by the butt-end of his son's gun, which was found lying on the grass within a few paces of the body. Under these circumstances the young man was instantly arrested, and a verdict of 'wilful murder' having been returned at the inquest on Tuesday, he was on Wednesday brought before the magistrates at Ross, who have referred the case to the next Assizes. Those are the main facts of the case as they came out before the coroner and the police-court." + +"I could hardly imagine a more damning case," I remarked. "If ever circumstantial evidence pointed to a criminal it does so here." + +"Circumstantial evidence is a very tricky thing," answered Holmes thoughtfully. "It may seem to point very straight to one thing, but if you shift your own point of view a little, you may find it pointing in an equally uncompromising manner to something entirely different. It must be confessed, however, that the case looks exceedingly grave against the young man, and it is very possible that he is indeed the culprit. There are several people in the neighbourhood, however, and among them Miss Turner, the daughter of the neighbouring landowner, who believe in his innocence, and who have retained Lestrade, whom you may recollect in connection with the Study in Scarlet, to work out the case in his interest. Lestrade, being rather puzzled, has referred the case to me, and hence it is that two middle-aged gentlemen are flying westward at fifty miles an hour instead of quietly digesting their breakfasts at home." + +"I am afraid," said I, "that the facts are so obvious that you will find little credit to be gained out of this case." + +"There is nothing more deceptive than an obvious fact," he answered, laughing. "Besides, we may chance to hit upon some other obvious facts which may have been by no means obvious to Mr. Lestrade. You know me too well to think that I am boasting when I say that I shall either confirm or destroy his theory by means which he is quite incapable of employing, or even of understanding. To take the first example to hand, I very clearly perceive that in your bedroom the window is upon the right-hand side, and yet I question whether Mr. Lestrade would have noted even so self-evident a thing as that." + +"How on earth--" + +"My dear fellow, I know you well. I know the military neatness which characterises you. You shave every morning, and in this season you shave by the sunlight; but since your shaving is less and less complete as we get farther back on the left side, until it becomes positively slovenly as we get round the angle of the jaw, it is surely very clear that that side is less illuminated than the other. I could not imagine a man of your habits looking at himself in an equal light and being satisfied with such a result. I only quote this as a trivial example of observation and inference. Therein lies my metier, and it is just possible that it may be of some service in the investigation which lies before us. There are one or two minor points which were brought out in the inquest, and which are worth considering." + +"What are they?" + +"It appears that his arrest did not take place at once, but after the return to Hatherley Farm. On the inspector of constabulary informing him that he was a prisoner, he remarked that he was not surprised to hear it, and that it was no more than his deserts. This observation of his had the natural effect of removing any traces of doubt which might have remained in the minds of the coroner's jury." + +"It was a confession," I ejaculated. + +"No, for it was followed by a protestation of innocence." + +"Coming on the top of such a damning series of events, it was at least a most suspicious remark." + +"On the contrary," said Holmes, "it is the brightest rift which I can at present see in the clouds. However innocent he might be, he could not be such an absolute imbecile as not to see that the circumstances were very black against him. Had he appeared surprised at his own arrest, or feigned indignation at it, I should have looked upon it as highly suspicious, because such surprise or anger would not be natural under the circumstances, and yet might appear to be the best policy to a scheming man. His frank acceptance of the situation marks him as either an innocent man, or else as a man of considerable self-restraint and firmness. As to his remark about his deserts, it was also not unnatural if you consider that he stood beside the dead body of his father, and that there is no doubt that he had that very day so far forgotten his filial duty as to bandy words with him, and even, according to the little girl whose evidence is so important, to raise his hand as if to strike him. The self-reproach and contrition which are displayed in his remark appear to me to be the signs of a healthy mind rather than of a guilty one." + +I shook my head. "Many men have been hanged on far slighter evidence," I remarked. + +"So they have. And many men have been wrongfully hanged." + +"What is the young man's own account of the matter?" + +"It is, I am afraid, not very encouraging to his supporters, though there are one or two points in it which are suggestive. You will find it here, and may read it for yourself." + +He picked out from his bundle a copy of the local Herefordshire paper, and having turned down the sheet he pointed out the paragraph in which the unfortunate young man had given his own statement of what had occurred. I settled myself down in the corner of the carriage and read it very carefully. It ran in this way: + +"Mr. James McCarthy, the only son of the deceased, was then called and gave evidence as follows: 'I had been away from home for three days at Bristol, and had only just returned upon the morning of last Monday, the 3rd. My father was absent from home at the time of my arrival, and I was informed by the maid that he had driven over to Ross with John Cobb, the groom. Shortly after my return I heard the wheels of his trap in the yard, and, looking out of my window, I saw him get out and walk rapidly out of the yard, though I was not aware in which direction he was going. I then took my gun and strolled out in the direction of the Boscombe Pool, with the intention of visiting the rabbit warren which is upon the other side. On my way I saw William Crowder, the game-keeper, as he had stated in his evidence; but he is mistaken in thinking that I was following my father. I had no idea that he was in front of me. When about a hundred yards from the pool I heard a cry of "Cooee!" which was a usual signal between my father and myself. I then hurried forward, and found him standing by the pool. He appeared to be much surprised at seeing me and asked me rather roughly what I was doing there. A conversation ensued which led to high words and almost to blows, for my father was a man of a very violent temper. Seeing that his passion was becoming ungovernable, I left him and returned towards Hatherley Farm. I had not gone more than 150 yards, however, when I heard a hideous outcry behind me, which caused me to run back again. I found my father expiring upon the ground, with his head terribly injured. I dropped my gun and held him in my arms, but he almost instantly expired. I knelt beside him for some minutes, and then made my way to Mr. Turner's lodge-keeper, his house being the nearest, to ask for assistance. I saw no one near my father when I returned, and I have no idea how he came by his injuries. He was not a popular man, being somewhat cold and forbidding in his manners, but he had, as far as I know, no active enemies. I know nothing further of the matter.' + +"The Coroner: Did your father make any statement to you before he died? + +"Witness: He mumbled a few words, but I could only catch some allusion to a rat. + +"The Coroner: What did you understand by that? + +"Witness: It conveyed no meaning to me. I thought that he was delirious. + +"The Coroner: What was the point upon which you and your father had this final quarrel? + +"Witness: I should prefer not to answer. + +"The Coroner: I am afraid that I must press it. + +"Witness: It is really impossible for me to tell you. I can assure you that it has nothing to do with the sad tragedy which followed. + +"The Coroner: That is for the court to decide. I need not point out to you that your refusal to answer will prejudice your case considerably in any future proceedings which may arise. + +"Witness: I must still refuse. + +"The Coroner: I understand that the cry of 'Cooee' was a common signal between you and your father? + +"Witness: It was. + +"The Coroner: How was it, then, that he uttered it before he saw you, and before he even knew that you had returned from Bristol? + +"Witness (with considerable confusion): I do not know. + +"A Juryman: Did you see nothing which aroused your suspicions when you returned on hearing the cry and found your father fatally injured? + +"Witness: Nothing definite. + +"The Coroner: What do you mean? + +"Witness: I was so disturbed and excited as I rushed out into the open, that I could think of nothing except of my father. Yet I have a vague impression that as I ran forward something lay upon the ground to the left of me. It seemed to me to be something grey in colour, a coat of some sort, or a plaid perhaps. When I rose from my father I looked round for it, but it was gone. + +" 'Do you mean that it disappeared before you went for help?' + +" 'Yes, it was gone.' + +" 'You cannot say what it was?' + +" 'No, I had a feeling something was there.' + +" 'How far from the body?' + +" 'A dozen yards or so.' + +" 'And how far from the edge of the wood?' + +" 'About the same.' + +" 'Then if it was removed it was while you were within a dozen yards of it?' + +" 'Yes, but with my back towards it.' + +"This concluded the examination of the witness." + +"I see," said I as I glanced down the column, "that the coroner in his concluding remarks was rather severe upon young McCarthy. He calls attention, and with reason, to the discrepancy about his father having signalled to him before seeing him, also to his refusal to give details of his conversation with his father, and his singular account of his father's dying words. They are all, as he remarks, very much against the son." + +Holmes laughed softly to himself and stretched himself out upon the cushioned seat. "Both you and the coroner have been at some pains," said he, "to single out the very strongest points in the young man's favour. Don't you see that you alternately give him credit for having too much imagination and too little? Too little, if he could not invent a cause of quarrel which would give him the sympathy of the jury; too much, if he evolved from his own inner consciousness anything so outre as a dying reference to a rat, and the incident of the vanishing cloth. No, sir, I shall approach this case from the point of view that what this young man says is true, and we shall see whither that hypothesis will lead us. And now here is my pocket Petrarch, and not another word shall I say of this case until we are on the scene of action. We lunch at Swindon, and I see that we shall be there in twenty minutes." + +It was nearly four o'clock when we at last, after passing through the beautiful Stroud Valley, and over the broad gleaming Severn, found ourselves at the pretty little country-town of Ross. A lean, ferret-like man, furtive and sly-looking, was waiting for us upon the platform. In spite of the light brown dustcoat and leather-leggings which he wore in deference to his rustic surroundings, I had no difficulty in recognising Lestrade, of Scotland Yard. With him we drove to the Hereford Arms where a room had already been engaged for us. + +"I have ordered a carriage," said Lestrade as we sat over a cup of tea. "I knew your energetic nature, and that you would not be happy until you had been on the scene of the crime." + +"It was very nice and complimentary of you," Holmes answered. "It is entirely a question of barometric pressure." + +Lestrade looked startled. "I do not quite follow," he said. + +"How is the glass? Twenty-nine, I see. No wind, and not a cloud in the sky. I have a caseful of cigarettes here which need smoking, and the sofa is very much superior to the usual country hotel abomination. I do not think that it is probable that I shall use the carriage to-night." + +Lestrade laughed indulgently. "You have, no doubt, already formed your conclusions from the newspapers," he said. "The case is as plain as a pikestaff, and the more one goes into it the plainer it becomes. Still, of course, one can't refuse a lady, and such a very positive one, too. She has heard of you, and would have your opinion, though I repeatedly told her that there was nothing which you could do which I had not already done. Why, bless my soul! here is her carriage at the door." + +He had hardly spoken before there rushed into the room one of the most lovely young women that I have ever seen in my life. Her violet eyes shining, her lips parted, a pink flush upon her cheeks, all thought of her natural reserve lost in her overpowering excitement and concern. + +"Oh, Mr. Sherlock Holmes!" she cried, glancing from one to the other of us, and finally, with a woman's quick intuition, fastening upon my companion, "I am so glad that you have come. I have driven down to tell you so. I know that James didn't do it. I know it, and I want you to start upon your work knowing it, too. Never let yourself doubt upon that point. We have known each other since we were little children, and I know his faults as no one else does; but he is too tender-hearted to hurt a fly. Such a charge is absurd to anyone who really knows him." + +"I hope we may clear him, Miss Turner," said Sherlock Holmes. "You may rely upon my doing all that I can." + +"But you have read the evidence. You have formed some conclusion? Do you not see some loophole, some flaw? Do you not yourself think that he is innocent?" + +"I think that it is very probable." + +"There, now!" she cried, throwing back her head and looking defiantly at Lestrade. "You hear! He gives me hopes." + +Lestrade shrugged his shoulders. "I am afraid that my colleague has been a little quick in forming his conclusions," he said. + +"But he is right. Oh! I know that he is right. James never did it. And about his quarrel with his father, I am sure that the reason why he would not speak about it to the coroner was because I was concerned in it." + +"In what way?" asked Holmes. + +"It is no time for me to hide anything. James and his father had many disagreements about me. Mr. McCarthy was very anxious that there should be a marriage between us. James and I have always loved each other as brother and sister; but of course he is young and has seen very little of life yet, and--and--well, he naturally did not wish to do anything like that yet. So there were quarrels, and this, I am sure, was one of them." + +"And your father?" asked Holmes. "Was he in favour of such a union?" + +"No, he was averse to it also. No one but Mr. McCarthy was in favour of it." A quick blush passed over her fresh young face as Holmes shot one of his keen, questioning glances at her. + +"Thank you for this information," said he. "May I see your father if I call to-morrow?" + +"I am afraid the doctor won't allow it." + +"The doctor?" + +"Yes, have you not heard? Poor father has never been strong for years back, but this has broken him down completely. He has taken to his bed, and Dr. Willows says that he is a wreck and that his nervous system is shattered. Mr. McCarthy was the only man alive who had known dad in the old days in Victoria." + +"Ha! In Victoria! That is important." + +"Yes, at the mines." + +"Quite so; at the gold-mines, where, as I understand, Mr. Turner made his money." + +"Yes, certainly." + +"Thank you, Miss Turner. You have been of material assistance to me." + +"You will tell me if you have any news to-morrow. No doubt you will go to the prison to see James. Oh, if you do, Mr. Holmes, do tell him that I know him to be innocent." + +"I will, Miss Turner." + +"I must go home now, for dad is very ill, and he misses me so if I leave him. Good-bye, and God help you in your undertaking." She hurried from the room as impulsively as she had entered, and we heard the wheels of her carriage rattle off down the street. + +"I am ashamed of you, Holmes," said Lestrade with dignity after a few minutes' silence. "Why should you raise up hopes which you are bound to disappoint? I am not over-tender of heart, but I call it cruel." + +"I think that I see my way to clearing James McCarthy," said Holmes. "Have you an order to see him in prison?" + +"Yes, but only for you and me." + +"Then I shall reconsider my resolution about going out. We have still time to take a train to Hereford and see him to-night?" + +"Ample." + +"Then let us do so. Watson, I fear that you will find it very slow, but I shall only be away a couple of hours." + +I walked down to the station with them, and then wandered through the streets of the little town, finally returning to the hotel, where I lay upon the sofa and tried to interest myself in a yellow-backed novel. The puny plot of the story was so thin, however, when compared to the deep mystery through which we were groping, and I found my attention wander so continually from the action to the fact, that I at last flung it across the room and gave myself up entirely to a consideration of the events of the day. Supposing that this unhappy young man's story were absolutely true, then what hellish thing, what absolutely unforeseen and extraordinary calamity could have occurred between the time when he parted from his father, and the moment when, drawn back by his screams, he rushed into the glade? It was something terrible and deadly. What could it be? Might not the nature of the injuries reveal something to my medical instincts? I rang the bell and called for the weekly county paper, which contained a verbatim account of the inquest. In the surgeon's deposition it was stated that the posterior third of the left parietal bone and the left half of the occipital bone had been shattered by a heavy blow from a blunt weapon. I marked the spot upon my own head. Clearly such a blow must have been struck from behind. That was to some extent in favour of the accused, as when seen quarrelling he was face to face with his father. Still, it did not go for very much, for the older man might have turned his back before the blow fell. Still, it might be worth while to call Holmes' attention to it. Then there was the peculiar dying reference to a rat. What could that mean? It could not be delirium. A man dying from a sudden blow does not commonly become delirious. No, it was more likely to be an attempt to explain how he met his fate. But what could it indicate? I cudgelled my brains to find some possible explanation. And then the incident of the grey cloth seen by young McCarthy. If that were true the murderer must have dropped some part of his dress, presumably his overcoat, in his flight, and must have had the hardihood to return and to carry it away at the instant when the son was kneeling with his back turned not a dozen paces off. What a tissue of mysteries and improbabilities the whole thing was! I did not wonder at Lestrade's opinion, and yet I had so much faith in Sherlock Holmes' insight that I could not lose hope as long as every fresh fact seemed to strengthen his conviction of young McCarthy's innocence. + +It was late before Sherlock Holmes returned. He came back alone, for Lestrade was staying in lodgings in the town. + +"The glass still keeps very high," he remarked as he sat down. "It is of importance that it should not rain before we are able to go over the ground. On the other hand, a man should be at his very best and keenest for such nice work as that, and I did not wish to do it when fagged by a long journey. I have seen young McCarthy." + +"And what did you learn from him?" + +"Nothing." + +"Could he throw no light?" + +"None at all. I was inclined to think at one time that he knew who had done it and was screening him or her, but I am convinced now that he is as puzzled as everyone else. He is not a very quick-witted youth, though comely to look at and, I should think, sound at heart." + +"I cannot admire his taste," I remarked, "if it is indeed a fact that he was averse to a marriage with so charming a young lady as this Miss Turner." + +"Ah, thereby hangs a rather painful tale. This fellow is madly, insanely, in love with her, but some two years ago, when he was only a lad, and before he really knew her, for she had been away five years at a boarding-school, what does the idiot do but get into the clutches of a barmaid in Bristol and marry her at a registry office? No one knows a word of the matter, but you can imagine how maddening it must be to him to be upbraided for not doing what he would give his very eyes to do, but what he knows to be absolutely impossible. It was sheer frenzy of this sort which made him throw his hands up into the air when his father, at their last interview, was goading him on to propose to Miss Turner. On the other hand, he had no means of supporting himself, and his father, who was by all accounts a very hard man, would have thrown him over utterly had he known the truth. It was with his barmaid wife that he had spent the last three days in Bristol, and his father did not know where he was. Mark that point. It is of importance. Good has come out of evil, however, for the barmaid, finding from the papers that he is in serious trouble and likely to be hanged, has thrown him over utterly and has written to him to say that she has a husband already in the Bermuda Dockyard, so that there is really no tie between them. I think that that bit of news has consoled young McCarthy for all that he has suffered." + +"But if he is innocent, who has done it?" + +"Ah! who? I would call your attention very particularly to two points. One is that the murdered man had an appointment with someone at the pool, and that the someone could not have been his son, for his son was away, and he did not know when he would return. The second is that the murdered man was heard to cry 'Cooee!' before he knew that his son had returned. Those are the crucial points upon which the case depends. And now let us talk about George Meredith, if you please, and we shall leave all minor matters until to-morrow." + +There was no rain, as Holmes had foretold, and the morning broke bright and cloudless. At nine o'clock Lestrade called for us with the carriage, and we set off for Hatherley Farm and the Boscombe Pool. + +"There is serious news this morning," Lestrade observed. "It is said that Mr. Turner, of the Hall, is so ill that his life is despaired of." + +"An elderly man, I presume?" said Holmes. + +"About sixty; but his constitution has been shattered by his life abroad, and he has been in failing health for some time. This business has had a very bad effect upon him. He was an old friend of McCarthy's, and, I may add, a great benefactor to him, for I have learned that he gave him Hatherley Farm rent free." + +"Indeed! That is interesting," said Holmes. + +"Oh, yes! In a hundred other ways he has helped him. Everybody about here speaks of his kindness to him." + +"Really! Does it not strike you as a little singular that this McCarthy, who appears to have had little of his own, and to have been under such obligations to Turner, should still talk of marrying his son to Turner's daughter, who is, presumably, heiress to the estate, and that in such a very cocksure manner, as if it were merely a case of a proposal and all else would follow? It is the more strange, since we know that Turner himself was averse to the idea. The daughter told us as much. Do you not deduce something from that?" + +"We have got to the deductions and the inferences," said Lestrade, winking at me. "I find it hard enough to tackle facts, Holmes, without flying away after theories and fancies." + +"You are right," said Holmes demurely; "you do find it very hard to tackle the facts." + +"Anyhow, I have grasped one fact which you seem to find it difficult to get hold of," replied Lestrade with some warmth. + +"And that is--" + +"That McCarthy senior met his death from McCarthy junior and that all theories to the contrary are the merest moonshine." + +"Well, moonshine is a brighter thing than fog," said Holmes, laughing. "But I am very much mistaken if this is not Hatherley Farm upon the left." + +"Yes, that is it." It was a widespread, comfortable-looking building, two-storied, slate-roofed, with great yellow blotches of lichen upon the grey walls. The drawn blinds and the smokeless chimneys, however, gave it a stricken look, as though the weight of this horror still lay heavy upon it. We called at the door, when the maid, at Holmes' request, showed us the boots which her master wore at the time of his death, and also a pair of the son's, though not the pair which he had then had. Having measured these very carefully from seven or eight different points, Holmes desired to be led to the court-yard, from which we all followed the winding track which led to Boscombe Pool. + +Sherlock Holmes was transformed when he was hot upon such a scent as this. Men who had only known the quiet thinker and logician of Baker Street would have failed to recognise him. His face flushed and darkened. His brows were drawn into two hard black lines, while his eyes shone out from beneath them with a steely glitter. His face was bent downward, his shoulders bowed, his lips compressed, and the veins stood out like whipcord in his long, sinewy neck. His nostrils seemed to dilate with a purely animal lust for the chase, and his mind was so absolutely concentrated upon the matter before him that a question or remark fell unheeded upon his ears, or, at the most, only provoked a quick, impatient snarl in reply. Swiftly and silently he made his way along the track which ran through the meadows, and so by way of the woods to the Boscombe Pool. It was damp, marshy ground, as is all that district, and there were marks of many feet, both upon the path and amid the short grass which bounded it on either side. Sometimes Holmes would hurry on, sometimes stop dead, and once he made quite a little detour into the meadow. Lestrade and I walked behind him, the detective indifferent and contemptuous, while I watched my friend with the interest which sprang from the conviction that every one of his actions was directed towards a definite end. + +The Boscombe Pool, which is a little reed-girt sheet of water some fifty yards across, is situated at the boundary between the Hatherley Farm and the private park of the wealthy Mr. Turner. Above the woods which lined it upon the farther side we could see the red, jutting pinnacles which marked the site of the rich landowner's dwelling. On the Hatherley side of the pool the woods grew very thick, and there was a narrow belt of sodden grass twenty paces across between the edge of the trees and the reeds which lined the lake. Lestrade showed us the exact spot at which the body had been found, and, indeed, so moist was the ground, that I could plainly see the traces which had been left by the fall of the stricken man. To Holmes, as I could see by his eager face and peering eyes, very many other things were to be read upon the trampled grass. He ran round, like a dog who is picking up a scent, and then turned upon my companion. + +"What did you go into the pool for?" he asked. + +"I fished about with a rake. I thought there might be some weapon or other trace. But how on earth--" + +"Oh, tut, tut! I have no time! That left foot of yours with its inward twist is all over the place. A mole could trace it, and there it vanishes among the reeds. Oh, how simple it would all have been had I been here before they came like a herd of buffalo and wallowed all over it. Here is where the party with the lodge-keeper came, and they have covered all tracks for six or eight feet round the body. But here are three separate tracks of the same feet." He drew out a lens and lay down upon his waterproof to have a better view, talking all the time rather to himself than to us. "These are young McCarthy's feet. Twice he was walking, and once he ran swiftly, so that the soles are deeply marked and the heels hardly visible. That bears out his story. He ran when he saw his father on the ground. Then here are the father's feet as he paced up and down. What is this, then? It is the butt-end of the gun as the son stood listening. And this? Ha, ha! What have we here? Tiptoes! tiptoes! Square, too, quite unusual boots! They come, they go, they come again--of course that was for the cloak. Now where did they come from?" He ran up and down, sometimes losing, sometimes finding the track until we were well within the edge of the wood and under the shadow of a great beech, the largest tree in the neighbourhood. Holmes traced his way to the farther side of this and lay down once more upon his face with a little cry of satisfaction. For a long time he remained there, turning over the leaves and dried sticks, gathering up what seemed to me to be dust into an envelope and examining with his lens not only the ground but even the bark of the tree as far as he could reach. A jagged stone was lying among the moss, and this also he carefully examined and retained. Then he followed a pathway through the wood until he came to the highroad, where all traces were lost. + +"It has been a case of considerable interest," he remarked, returning to his natural manner. "I fancy that this grey house on the right must be the lodge. I think that I will go in and have a word with Moran, and perhaps write a little note. Having done that, we may drive back to our luncheon. You may walk to the cab, and I shall be with you presently." + +It was about ten minutes before we regained our cab and drove back into Ross, Holmes still carrying with him the stone which he had picked up in the wood. + +"This may interest you, Lestrade," he remarked, holding it out. "The murder was done with it." + +"I see no marks." + +"There are none." + +"How do you know, then?" + +"The grass was growing under it. It had only lain there a few days. There was no sign of a place whence it had been taken. It corresponds with the injuries. There is no sign of any other weapon." + +"And the murderer?" + +"Is a tall man, left-handed, limps with the right leg, wears thick-soled shooting-boots and a grey cloak, smokes Indian cigars, uses a cigar-holder, and carries a blunt pen-knife in his pocket. There are several other indications, but these may be enough to aid us in our search." + +Lestrade laughed. "I am afraid that I am still a sceptic," he said. "Theories are all very well, but we have to deal with a hard-headed British jury." + +"Nous verrons," answered Holmes calmly. "You work your own method, and I shall work mine. I shall be busy this afternoon, and shall probably return to London by the evening train." + +"And leave your case unfinished?" + +"No, finished." + +"But the mystery?" + +"It is solved." + +"Who was the criminal, then?" + +"The gentleman I describe." + +"But who is he?" + +"Surely it would not be difficult to find out. This is not such a populous neighbourhood." + +Lestrade shrugged his shoulders. "I am a practical man," he said, "and I really cannot undertake to go about the country looking for a left-handed gentleman with a game leg. I should become the laughing-stock of Scotland Yard." + +"All right," said Holmes quietly. "I have given you the chance. Here are your lodgings. Good-bye. I shall drop you a line before I leave." + +Having left Lestrade at his rooms, we drove to our hotel, where we found lunch upon the table. Holmes was silent and buried in thought with a pained expression upon his face, as one who finds himself in a perplexing position. + +"Look here, Watson," he said when the cloth was cleared "just sit down in this chair and let me preach to you for a little. I don't know quite what to do, and I should value your advice. Light a cigar and let me expound." + +"Pray do so." + +"Well, now, in considering this case there are two points about young McCarthy's narrative which struck us both instantly, although they impressed me in his favour and you against him. One was the fact that his father should, according to his account, cry 'Cooee!' before seeing him. The other was his singular dying reference to a rat. He mumbled several words, you understand, but that was all that caught the son's ear. Now from this double point our research must commence, and we will begin it by presuming that what the lad says is absolutely true." + +"What of this 'Cooee!' then?" + +"Well, obviously it could not have been meant for the son. The son, as far as he knew, was in Bristol. It was mere chance that he was within earshot. The 'Cooee!' was meant to attract the attention of whoever it was that he had the appointment with. But 'Cooee' is a distinctly Australian cry, and one which is used between Australians. There is a strong presumption that the person whom McCarthy expected to meet him at Boscombe Pool was someone who had been in Australia." + +"What of the rat, then?" + +Sherlock Holmes took a folded paper from his pocket and flattened it out on the table. "This is a map of the Colony of Victoria," he said. "I wired to Bristol for it last night." He put his hand over part of the map. "What do you read?" + +"ARAT," I read. + +"And now?" He raised his hand. + +"BALLARAT." + +"Quite so. That was the word the man uttered, and of which his son only caught the last two syllables. He was trying to utter the name of his murderer. So and so, of Ballarat." + +"It is wonderful!" I exclaimed. + +"It is obvious. And now, you see, I had narrowed the field down considerably. The possession of a grey garment was a third point which, granting the son's statement to be correct, was a certainty. We have come now out of mere vagueness to the definite conception of an Australian from Ballarat with a grey cloak." + +"Certainly." + +"And one who was at home in the district, for the pool can only be approached by the farm or by the estate, where strangers could hardly wander." + +"Quite so." + +"Then comes our expedition of to-day. By an examination of the ground I gained the trifling details which I gave to that imbecile Lestrade, as to the personality of the criminal." + +"But how did you gain them?" + +"You know my method. It is founded upon the observation of trifles." + +"His height I know that you might roughly judge from the length of his stride. His boots, too, might be told from their traces." + +"Yes, they were peculiar boots." + +"But his lameness?" + +"The impression of his right foot was always less distinct than his left. He put less weight upon it. Why? Because he limped--he was lame." + +"But his left-handedness." + +"You were yourself struck by the nature of the injury as recorded by the surgeon at the inquest. The blow was struck from immediately behind, and yet was upon the left side. Now, how can that be unless it were by a left-handed man? He had stood behind that tree during the interview between the father and son. He had even smoked there. I found the ash of a cigar, which my special knowledge of tobacco ashes enables me to pronounce as an Indian cigar. I have, as you know, devoted some attention to this, and written a little monograph on the ashes of 140 different varieties of pipe, cigar, and cigarette tobacco. Having found the ash, I then looked round and discovered the stump among the moss where he had tossed it. It was an Indian cigar, of the variety which are rolled in Rotterdam." + +"And the cigar-holder?" + +"I could see that the end had not been in his mouth. Therefore he used a holder. The tip had been cut off, not bitten off, but the cut was not a clean one, so I deduced a blunt pen-knife." + +"Holmes," I said, "you have drawn a net round this man from which he cannot escape, and you have saved an innocent human life as truly as if you had cut the cord which was hanging him. I see the direction in which all this points. The culprit is--" + +"Mr. John Turner," cried the hotel waiter, opening the door of our sitting-room, and ushering in a visitor. + +The man who entered was a strange and impressive figure. His slow, limping step and bowed shoulders gave the appearance of decrepitude, and yet his hard, deep-lined, craggy features, and his enormous limbs showed that he was possessed of unusual strength of body and of character. His tangled beard, grizzled hair, and outstanding, drooping eyebrows combined to give an air of dignity and power to his appearance, but his face was of an ashen white, while his lips and the corners of his nostrils were tinged with a shade of blue. It was clear to me at a glance that he was in the grip of some deadly and chronic disease. + +"Pray sit down on the sofa," said Holmes gently. "You had my note?" + +"Yes, the lodge-keeper brought it up. You said that you wished to see me here to avoid scandal." + +"I thought people would talk if I went to the Hall." + +"And why did you wish to see me?" He looked across at my companion with despair in his weary eyes, as though his question was already answered. + +"Yes," said Holmes, answering the look rather than the words. "It is so. I know all about McCarthy." + +The old man sank his face in his hands. "God help me!" he cried. "But I would not have let the young man come to harm. I give you my word that I would have spoken out if it went against him at the Assizes." + +"I am glad to hear you say so," said Holmes gravely. + +"I would have spoken now had it not been for my dear girl. It would break her heart--it will break her heart when she hears that I am arrested." + +"It may not come to that," said Holmes. + +"What?" + +"I am no official agent. I understand that it was your daughter who required my presence here, and I am acting in her interests. Young McCarthy must be got off, however." + +"I am a dying man," said old Turner. "I have had diabetes for years. My doctor says it is a question whether I shall live a month. Yet I would rather die under my own roof than in a gaol." + +Holmes rose and sat down at the table with his pen in his hand and a bundle of paper before him. "Just tell us the truth," he said. "I shall jot down the facts. You will sign it, and Watson here can witness it. Then I could produce your confession at the last extremity to save young McCarthy. I promise you that I shall not use it unless it is absolutely needed." + +"It's as well," said the old man; "it's a question whether I shall live to the Assizes, so it matters little to me, but I should wish to spare Alice the shock. And now I will make the thing clear to you; it has been a long time in the acting, but will not take me long to tell. + +"You didn't know this dead man, McCarthy. He was a devil incarnate. I tell you that. God keep you out of the clutches of such a man as he. His grip has been upon me these twenty years, and he has blasted my life. I'll tell you first how I came to be in his power. + +"It was in the early '60's at the diggings. I was a young chap then, hot-blooded and reckless, ready to turn my hand at anything; I got among bad companions, took to drink, had no luck with my claim, took to the bush, and in a word became what you would call over here a highway robber. There were six of us, and we had a wild, free life of it, sticking up a station from time to time, or stopping the wagons on the road to the diggings. Black Jack of Ballarat was the name I went under, and our party is still remembered in the colony as the Ballarat Gang. + +"One day a gold convoy came down from Ballarat to Melbourne, and we lay in wait for it and attacked it. There were six troopers and six of us, so it was a close thing, but we emptied four of their saddles at the first volley. Three of our boys were killed, however, before we got the swag. I put my pistol to the head of the wagon-driver, who was this very man McCarthy. I wish to the Lord that I had shot him then, but I spared him, though I saw his wicked little eyes fixed on my face, as though to remember every feature. We got away with the gold, became wealthy men, and made our way over to England without being suspected. There I parted from my old pals and determined to settle down to a quiet and respectable life. I bought this estate, which chanced to be in the market, and I set myself to do a little good with my money, to make up for the way in which I had earned it. I married, too, and though my wife died young she left me my dear little Alice. Even when she was just a baby her wee hand seemed to lead me down the right path as nothing else had ever done. In a word, I turned over a new leaf and did my best to make up for the past. All was going well when McCarthy laid his grip upon me. + +"I had gone up to town about an investment, and I met him in Regent Street with hardly a coat to his back or a boot to his foot. + +" 'Here we are, Jack,' says he, touching me on the arm; 'we'll be as good as a family to you. There's two of us, me and my son, and you can have the keeping of us. If you don't--it's a fine, law-abiding country is England, and there's always a policeman within hail.' + +"Well, down they came to the west country, there was no shaking them off, and there they have lived rent free on my best land ever since. There was no rest for me, no peace, no forgetfulness; turn where I would, there was his cunning, grinning face at my elbow. It grew worse as Alice grew up, for he soon saw I was more afraid of her knowing my past than of the police. Whatever he wanted he must have, and whatever it was I gave him without question, land, money, houses, until at last he asked a thing which I could not give. He asked for Alice. + +"His son, you see, had grown up, and so had my girl, and as I was known to be in weak health, it seemed a fine stroke to him that his lad should step into the whole property. But there I was firm. I would not have his cursed stock mixed with mine; not that I had any dislike to the lad, but his blood was in him, and that was enough. I stood firm. McCarthy threatened. I braved him to do his worst. We were to meet at the pool midway between our houses to talk it over. + +"When I went down there I found him talking with his son, so I smoked a cigar and waited behind a tree until he should be alone. But as I listened to his talk all that was black and bitter in me seemed to come uppermost. He was urging his son to marry my daughter with as little regard for what she might think as if she were a slut from off the streets. It drove me mad to think that I and all that I held most dear should be in the power of such a man as this. Could I not snap the bond? I was already a dying and a desperate man. Though clear of mind and fairly strong of limb, I knew that my own fate was sealed. But my memory and my girl! Both could be saved if I could but silence that foul tongue. I did it, Mr. Holmes. I would do it again. Deeply as I have sinned, I have led a life of martyrdom to atone for it. But that my girl should be entangled in the same meshes which held me was more than I could suffer. I struck him down with no more compunction than if he had been some foul and venomous beast. His cry brought back his son; but I had gained the cover of the wood, though I was forced to go back to fetch the cloak which I had dropped in my flight. That is the true story, gentlemen, of all that occurred." + +"Well, it is not for me to judge you," said Holmes as the old man signed the statement which had been drawn out. "I pray that we may never be exposed to such a temptation." + +"I pray not, sir. And what do you intend to do?" + +"In view of your health, nothing. You are yourself aware that you will soon have to answer for your deed at a higher court than the Assizes. I will keep your confession, and if McCarthy is condemned I shall be forced to use it. If not, it shall never be seen by mortal eye; and your secret, whether you be alive or dead, shall be safe with us." + +"Farewell, then," said the old man solemnly. "Your own deathbeds, when they come, will be the easier for the thought of the peace which you have given to mine." Tottering and shaking in all his giant frame, he stumbled slowly from the room. + +"God help us!" said Holmes after a long silence. "Why does fate play such tricks with poor, helpless worms? I never hear of such a case as this that I do not think of Baxter's words, and say, 'There, but for the grace of God, goes Sherlock Holmes.' " + +James McCarthy was acquitted at the Assizes on the strength of a number of objections which had been drawn out by Holmes and submitted to the defending counsel. Old Turner lived for seven months after our interview, but he is now dead; and there is every prospect that the son and daughter may come to live happily together in ignorance of the black cloud which rests upon their past. + +ADVENTURE V. THE FIVE ORANGE PIPS + + +When I glance over my notes and records of the Sherlock Holmes cases between the years '82 and '90, I am faced by so many which present strange and interesting features that it is no easy matter to know which to choose and which to leave. Some, however, have already gained publicity through the papers, and others have not offered a field for those peculiar qualities which my friend possessed in so high a degree, and which it is the object of these papers to illustrate. Some, too, have baffled his analytical skill, and would be, as narratives, beginnings without an ending, while others have been but partially cleared up, and have their explanations founded rather upon conjecture and surmise than on that absolute logical proof which was so dear to him. There is, however, one of these last which was so remarkable in its details and so startling in its results that I am tempted to give some account of it in spite of the fact that there are points in connection with it which never have been, and probably never will be, entirely cleared up. + +The year '87 furnished us with a long series of cases of greater or less interest, of which I retain the records. Among my headings under this one twelve months I find an account of the adventure of the Paradol Chamber, of the Amateur Mendicant Society, who held a luxurious club in the lower vault of a furniture warehouse, of the facts connected with the loss of the British barque Sophy Anderson, of the singular adventures of the Grice Patersons in the island of Uffa, and finally of the Camberwell poisoning case. In the latter, as may be remembered, Sherlock Holmes was able, by winding up the dead man's watch, to prove that it had been wound up two hours before, and that therefore the deceased had gone to bed within that time--a deduction which was of the greatest importance in clearing up the case. All these I may sketch out at some future date, but none of them present such singular features as the strange train of circumstances which I have now taken up my pen to describe. + +It was in the latter days of September, and the equinoctial gales had set in with exceptional violence. All day the wind had screamed and the rain had beaten against the windows, so that even here in the heart of great, hand-made London we were forced to raise our minds for the instant from the routine of life and to recognise the presence of those great elemental forces which shriek at mankind through the bars of his civilisation, like untamed beasts in a cage. As evening drew in, the storm grew higher and louder, and the wind cried and sobbed like a child in the chimney. Sherlock Holmes sat moodily at one side of the fireplace cross-indexing his records of crime, while I at the other was deep in one of Clark Russell's fine sea-stories until the howl of the gale from without seemed to blend with the text, and the splash of the rain to lengthen out into the long swash of the sea waves. My wife was on a visit to her mother's, and for a few days I was a dweller once more in my old quarters at Baker Street. + +"Why," said I, glancing up at my companion, "that was surely the bell. Who could come to-night? Some friend of yours, perhaps?" + +"Except yourself I have none," he answered. "I do not encourage visitors." + +"A client, then?" + +"If so, it is a serious case. Nothing less would bring a man out on such a day and at such an hour. But I take it that it is more likely to be some crony of the landlady's." + +Sherlock Holmes was wrong in his conjecture, however, for there came a step in the passage and a tapping at the door. He stretched out his long arm to turn the lamp away from himself and towards the vacant chair upon which a newcomer must sit. + +"Come in!" said he. + +The man who entered was young, some two-and-twenty at the outside, well-groomed and trimly clad, with something of refinement and delicacy in his bearing. The streaming umbrella which he held in his hand, and his long shining waterproof told of the fierce weather through which he had come. He looked about him anxiously in the glare of the lamp, and I could see that his face was pale and his eyes heavy, like those of a man who is weighed down with some great anxiety. + +"I owe you an apology," he said, raising his golden pince-nez to his eyes. "I trust that I am not intruding. I fear that I have brought some traces of the storm and rain into your snug chamber." + +"Give me your coat and umbrella," said Holmes. "They may rest here on the hook and will be dry presently. You have come up from the south-west, I see." + +"Yes, from Horsham." + +"That clay and chalk mixture which I see upon your toe caps is quite distinctive." + +"I have come for advice." + +"That is easily got." + +"And help." + +"That is not always so easy." + +"I have heard of you, Mr. Holmes. I heard from Major Prendergast how you saved him in the Tankerville Club scandal." + +"Ah, of course. He was wrongfully accused of cheating at cards." + +"He said that you could solve anything." + +"He said too much." + +"That you are never beaten." + +"I have been beaten four times--three times by men, and once by a woman." + +"But what is that compared with the number of your successes?" + +"It is true that I have been generally successful." + +"Then you may be so with me." + +"I beg that you will draw your chair up to the fire and favour me with some details as to your case." + +"It is no ordinary one." + +"None of those which come to me are. I am the last court of appeal." + +"And yet I question, sir, whether, in all your experience, you have ever listened to a more mysterious and inexplicable chain of events than those which have happened in my own family." + +"You fill me with interest," said Holmes. "Pray give us the essential facts from the commencement, and I can afterwards question you as to those details which seem to me to be most important." + +The young man pulled his chair up and pushed his wet feet out towards the blaze. + +"My name," said he, "is John Openshaw, but my own affairs have, as far as I can understand, little to do with this awful business. It is a hereditary matter; so in order to give you an idea of the facts, I must go back to the commencement of the affair. + +"You must know that my grandfather had two sons--my uncle Elias and my father Joseph. My father had a small factory at Coventry, which he enlarged at the time of the invention of bicycling. He was a patentee of the Openshaw unbreakable tire, and his business met with such success that he was able to sell it and to retire upon a handsome competence. + +"My uncle Elias emigrated to America when he was a young man and became a planter in Florida, where he was reported to have done very well. At the time of the war he fought in Jackson's army, and afterwards under Hood, where he rose to be a colonel. When Lee laid down his arms my uncle returned to his plantation, where he remained for three or four years. About 1869 or 1870 he came back to Europe and took a small estate in Sussex, near Horsham. He had made a very considerable fortune in the States, and his reason for leaving them was his aversion to the negroes, and his dislike of the Republican policy in extending the franchise to them. He was a singular man, fierce and quick-tempered, very foul-mouthed when he was angry, and of a most retiring disposition. During all the years that he lived at Horsham, I doubt if ever he set foot in the town. He had a garden and two or three fields round his house, and there he would take his exercise, though very often for weeks on end he would never leave his room. He drank a great deal of brandy and smoked very heavily, but he would see no society and did not want any friends, not even his own brother. + +"He didn't mind me; in fact, he took a fancy to me, for at the time when he saw me first I was a youngster of twelve or so. This would be in the year 1878, after he had been eight or nine years in England. He begged my father to let me live with him and he was very kind to me in his way. When he was sober he used to be fond of playing backgammon and draughts with me, and he would make me his representative both with the servants and with the tradespeople, so that by the time that I was sixteen I was quite master of the house. I kept all the keys and could go where I liked and do what I liked, so long as I did not disturb him in his privacy. There was one singular exception, however, for he had a single room, a lumber-room up among the attics, which was invariably locked, and which he would never permit either me or anyone else to enter. With a boy's curiosity I have peeped through the keyhole, but I was never able to see more than such a collection of old trunks and bundles as would be expected in such a room. + +"One day--it was in March, 1883--a letter with a foreign stamp lay upon the table in front of the colonel's plate. It was not a common thing for him to receive letters, for his bills were all paid in ready money, and he had no friends of any sort. 'From India!' said he as he took it up, 'Pondicherry postmark! What can this be?' Opening it hurriedly, out there jumped five little dried orange pips, which pattered down upon his plate. I began to laugh at this, but the laugh was struck from my lips at the sight of his face. His lip had fallen, his eyes were protruding, his skin the colour of putty, and he glared at the envelope which he still held in his trembling hand, 'K. K. K.!' he shrieked, and then, 'My God, my God, my sins have overtaken me!' + +" 'What is it, uncle?' I cried. + +" 'Death,' said he, and rising from the table he retired to his room, leaving me palpitating with horror. I took up the envelope and saw scrawled in red ink upon the inner flap, just above the gum, the letter K three times repeated. There was nothing else save the five dried pips. What could be the reason of his overpowering terror? I left the breakfast-table, and as I ascended the stair I met him coming down with an old rusty key, which must have belonged to the attic, in one hand, and a small brass box, like a cashbox, in the other. + +" 'They may do what they like, but I'll checkmate them still,' said he with an oath. 'Tell Mary that I shall want a fire in my room to-day, and send down to Fordham, the Horsham lawyer.' + +"I did as he ordered, and when the lawyer arrived I was asked to step up to the room. The fire was burning brightly, and in the grate there was a mass of black, fluffy ashes, as of burned paper, while the brass box stood open and empty beside it. As I glanced at the box I noticed, with a start, that upon the lid was printed the treble K which I had read in the morning upon the envelope. + +" 'I wish you, John,' said my uncle, 'to witness my will. I leave my estate, with all its advantages and all its disadvantages, to my brother, your father, whence it will, no doubt, descend to you. If you can enjoy it in peace, well and good! If you find you cannot, take my advice, my boy, and leave it to your deadliest enemy. I am sorry to give you such a two-edged thing, but I can't say what turn things are going to take. Kindly sign the paper where Mr. Fordham shows you.' + +"I signed the paper as directed, and the lawyer took it away with him. The singular incident made, as you may think, the deepest impression upon me, and I pondered over it and turned it every way in my mind without being able to make anything of it. Yet I could not shake off the vague feeling of dread which it left behind, though the sensation grew less keen as the weeks passed and nothing happened to disturb the usual routine of our lives. I could see a change in my uncle, however. He drank more than ever, and he was less inclined for any sort of society. Most of his time he would spend in his room, with the door locked upon the inside, but sometimes he would emerge in a sort of drunken frenzy and would burst out of the house and tear about the garden with a revolver in his hand, screaming out that he was afraid of no man, and that he was not to be cooped up, like a sheep in a pen, by man or devil. When these hot fits were over, however, he would rush tumultuously in at the door and lock and bar it behind him, like a man who can brazen it out no longer against the terror which lies at the roots of his soul. At such times I have seen his face, even on a cold day, glisten with moisture, as though it were new raised from a basin. + +"Well, to come to an end of the matter, Mr. Holmes, and not to abuse your patience, there came a night when he made one of those drunken sallies from which he never came back. We found him, when we went to search for him, face downward in a little green-scummed pool, which lay at the foot of the garden. There was no sign of any violence, and the water was but two feet deep, so that the jury, having regard to his known eccentricity, brought in a verdict of 'suicide.' But I, who knew how he winced from the very thought of death, had much ado to persuade myself that he had gone out of his way to meet it. The matter passed, however, and my father entered into possession of the estate, and of some $14,000, which lay to his credit at the bank." + +"One moment," Holmes interposed, "your statement is, I foresee, one of the most remarkable to which I have ever listened. Let me have the date of the reception by your uncle of the letter, and the date of his supposed suicide." + +"The letter arrived on March 10, 1883. His death was seven weeks later, upon the night of May 2nd." + +"Thank you. Pray proceed." + +"When my father took over the Horsham property, he, at my request, made a careful examination of the attic, which had been always locked up. We found the brass box there, although its contents had been destroyed. On the inside of the cover was a paper label, with the initials of K. K. K. repeated upon it, and 'Letters, memoranda, receipts, and a register' written beneath. These, we presume, indicated the nature of the papers which had been destroyed by Colonel Openshaw. For the rest, there was nothing of much importance in the attic save a great many scattered papers and note-books bearing upon my uncle's life in America. Some of them were of the war time and showed that he had done his duty well and had borne the repute of a brave soldier. Others were of a date during the reconstruction of the Southern states, and were mostly concerned with politics, for he had evidently taken a strong part in opposing the carpet-bag politicians who had been sent down from the North. + +"Well, it was the beginning of '84 when my father came to live at Horsham, and all went as well as possible with us until the January of '85. On the fourth day after the new year I heard my father give a sharp cry of surprise as we sat together at the breakfast-table. There he was, sitting with a newly opened envelope in one hand and five dried orange pips in the outstretched palm of the other one. He had always laughed at what he called my cock-and-bull story about the colonel, but he looked very scared and puzzled now that the same thing had come upon himself. + +" 'Why, what on earth does this mean, John?' he stammered. + +"My heart had turned to lead. 'It is K. K. K.,' said I. + +"He looked inside the envelope. 'So it is,' he cried. 'Here are the very letters. But what is this written above them?' + +" 'Put the papers on the sundial,' I read, peeping over his shoulder. + +" 'What papers? What sundial?' he asked. + +" 'The sundial in the garden. There is no other,' said I; 'but the papers must be those that are destroyed.' + +" 'Pooh!' said he, gripping hard at his courage. 'We are in a civilised land here, and we can't have tomfoolery of this kind. Where does the thing come from?' + +" 'From Dundee,' I answered, glancing at the postmark. + +" 'Some preposterous practical joke,' said he. 'What have I to do with sundials and papers? I shall take no notice of such nonsense.' + +" 'I should certainly speak to the police,' I said. + +" 'And be laughed at for my pains. Nothing of the sort.' + +" 'Then let me do so?' + +" 'No, I forbid you. I won't have a fuss made about such nonsense.' + +"It was in vain to argue with him, for he was a very obstinate man. I went about, however, with a heart which was full of forebodings. + +"On the third day after the coming of the letter my father went from home to visit an old friend of his, Major Freebody, who is in command of one of the forts upon Portsdown Hill. I was glad that he should go, for it seemed to me that he was farther from danger when he was away from home. In that, however, I was in error. Upon the second day of his absence I received a telegram from the major, imploring me to come at once. My father had fallen over one of the deep chalk-pits which abound in the neighbourhood, and was lying senseless, with a shattered skull. I hurried to him, but he passed away without having ever recovered his consciousness. He had, as it appears, been returning from Fareham in the twilight, and as the country was unknown to him, and the chalk-pit unfenced, the jury had no hesitation in bringing in a verdict of 'death from accidental causes.' Carefully as I examined every fact connected with his death, I was unable to find anything which could suggest the idea of murder. There were no signs of violence, no footmarks, no robbery, no record of strangers having been seen upon the roads. And yet I need not tell you that my mind was far from at ease, and that I was well-nigh certain that some foul plot had been woven round him. + +"In this sinister way I came into my inheritance. You will ask me why I did not dispose of it? I answer, because I was well convinced that our troubles were in some way dependent upon an incident in my uncle's life, and that the danger would be as pressing in one house as in another. + +"It was in January, '85, that my poor father met his end, and two years and eight months have elapsed since then. During that time I have lived happily at Horsham, and I had begun to hope that this curse had passed away from the family, and that it had ended with the last generation. I had begun to take comfort too soon, however; yesterday morning the blow fell in the very shape in which it had come upon my father." + +The young man took from his waistcoat a crumpled envelope, and turning to the table he shook out upon it five little dried orange pips. + +"This is the envelope," he continued. "The postmark is London--eastern division. Within are the very words which were upon my father's last message: 'K. K. K.'; and then 'Put the papers on the sundial.' " + +"What have you done?" asked Holmes. + +"Nothing." + +"Nothing?" + +"To tell the truth"--he sank his face into his thin, white hands--"I have felt helpless. I have felt like one of those poor rabbits when the snake is writhing towards it. I seem to be in the grasp of some resistless, inexorable evil, which no foresight and no precautions can guard against." + +"Tut! tut!" cried Sherlock Holmes. "You must act, man, or you are lost. Nothing but energy can save you. This is no time for despair." + +"I have seen the police." + +"Ah!" + +"But they listened to my story with a smile. I am convinced that the inspector has formed the opinion that the letters are all practical jokes, and that the deaths of my relations were really accidents, as the jury stated, and were not to be connected with the warnings." + +Holmes shook his clenched hands in the air. "Incredible imbecility!" he cried. + +"They have, however, allowed me a policeman, who may remain in the house with me." + +"Has he come with you to-night?" + +"No. His orders were to stay in the house." + +Again Holmes raved in the air. + +"Why did you come to me," he cried, "and, above all, why did you not come at once?" + +"I did not know. It was only to-day that I spoke to Major Prendergast about my troubles and was advised by him to come to you." + +"It is really two days since you had the letter. We should have acted before this. You have no further evidence, I suppose, than that which you have placed before us--no suggestive detail which might help us?" + +"There is one thing," said John Openshaw. He rummaged in his coat pocket, and, drawing out a piece of discoloured, blue-tinted paper, he laid it out upon the table. "I have some remembrance," said he, "that on the day when my uncle burned the papers I observed that the small, unburned margins which lay amid the ashes were of this particular colour. I found this single sheet upon the floor of his room, and I am inclined to think that it may be one of the papers which has, perhaps, fluttered out from among the others, and in that way has escaped destruction. Beyond the mention of pips, I do not see that it helps us much. I think myself that it is a page from some private diary. The writing is undoubtedly my uncle's." + +Holmes moved the lamp, and we both bent over the sheet of paper, which showed by its ragged edge that it had indeed been torn from a book. It was headed, "March, 1869," and beneath were the following enigmatical notices: + +"4th. Hudson came. Same old platform. + +"7th. Set the pips on McCauley, Paramore, and + + John Swain, of St. Augustine. + +"9th. McCauley cleared. + +"10th. John Swain cleared. + +"12th. Visited Paramore. All well." + +"Thank you!" said Holmes, folding up the paper and returning it to our visitor. "And now you must on no account lose another instant. We cannot spare time even to discuss what you have told me. You must get home instantly and act." + +"What shall I do?" + +"There is but one thing to do. It must be done at once. You must put this piece of paper which you have shown us into the brass box which you have described. You must also put in a note to say that all the other papers were burned by your uncle, and that this is the only one which remains. You must assert that in such words as will carry conviction with them. Having done this, you must at once put the box out upon the sundial, as directed. Do you understand?" + +"Entirely." + +"Do not think of revenge, or anything of the sort, at present. I think that we may gain that by means of the law; but we have our web to weave, while theirs is already woven. The first consideration is to remove the pressing danger which threatens you. The second is to clear up the mystery and to punish the guilty parties." + +"I thank you," said the young man, rising and pulling on his overcoat. "You have given me fresh life and hope. I shall certainly do as you advise." + +"Do not lose an instant. And, above all, take care of yourself in the meanwhile, for I do not think that there can be a doubt that you are threatened by a very real and imminent danger. How do you go back?" + +"By train from Waterloo." + +"It is not yet nine. The streets will be crowded, so I trust that you may be in safety. And yet you cannot guard yourself too closely." + +"I am armed." + +"That is well. To-morrow I shall set to work upon your case." + +"I shall see you at Horsham, then?" + +"No, your secret lies in London. It is there that I shall seek it." + +"Then I shall call upon you in a day, or in two days, with news as to the box and the papers. I shall take your advice in every particular." He shook hands with us and took his leave. Outside the wind still screamed and the rain splashed and pattered against the windows. This strange, wild story seemed to have come to us from amid the mad elements--blown in upon us like a sheet of sea-weed in a gale--and now to have been reabsorbed by them once more. + +Sherlock Holmes sat for some time in silence, with his head sunk forward and his eyes bent upon the red glow of the fire. Then he lit his pipe, and leaning back in his chair he watched the blue smoke-rings as they chased each other up to the ceiling. + +"I think, Watson," he remarked at last, "that of all our cases we have had none more fantastic than this." + +"Save, perhaps, the Sign of Four." + +"Well, yes. Save, perhaps, that. And yet this John Openshaw seems to me to be walking amid even greater perils than did the Sholtos." + +"But have you," I asked, "formed any definite conception as to what these perils are?" + +"There can be no question as to their nature," he answered. + +"Then what are they? Who is this K. K. K., and why does he pursue this unhappy family?" + +Sherlock Holmes closed his eyes and placed his elbows upon the arms of his chair, with his finger-tips together. "The ideal reasoner," he remarked, "would, when he had once been shown a single fact in all its bearings, deduce from it not only all the chain of events which led up to it but also all the results which would follow from it. As Cuvier could correctly describe a whole animal by the contemplation of a single bone, so the observer who has thoroughly understood one link in a series of incidents should be able to accurately state all the other ones, both before and after. We have not yet grasped the results which the reason alone can attain to. Problems may be solved in the study which have baffled all those who have sought a solution by the aid of their senses. To carry the art, however, to its highest pitch, it is necessary that the reasoner should be able to utilise all the facts which have come to his knowledge; and this in itself implies, as you will readily see, a possession of all knowledge, which, even in these days of free education and encyclopaedias, is a somewhat rare accomplishment. It is not so impossible, however, that a man should possess all knowledge which is likely to be useful to him in his work, and this I have endeavoured in my case to do. If I remember rightly, you on one occasion, in the early days of our friendship, defined my limits in a very precise fashion." + +"Yes," I answered, laughing. "It was a singular document. Philosophy, astronomy, and politics were marked at zero, I remember. Botany variable, geology profound as regards the mud-stains from any region within fifty miles of town, chemistry eccentric, anatomy unsystematic, sensational literature and crime records unique, violin-player, boxer, swordsman, lawyer, and self-poisoner by cocaine and tobacco. Those, I think, were the main points of my analysis." + +Holmes grinned at the last item. "Well," he said, "I say now, as I said then, that a man should keep his little brain-attic stocked with all the furniture that he is likely to use, and the rest he can put away in the lumber-room of his library, where he can get it if he wants it. Now, for such a case as the one which has been submitted to us to-night, we need certainly to muster all our resources. Kindly hand me down the letter K of the American Encyclopaedia which stands upon the shelf beside you. Thank you. Now let us consider the situation and see what may be deduced from it. In the first place, we may start with a strong presumption that Colonel Openshaw had some very strong reason for leaving America. Men at his time of life do not change all their habits and exchange willingly the charming climate of Florida for the lonely life of an English provincial town. His extreme love of solitude in England suggests the idea that he was in fear of someone or something, so we may assume as a working hypothesis that it was fear of someone or something which drove him from America. As to what it was he feared, we can only deduce that by considering the formidable letters which were received by himself and his successors. Did you remark the postmarks of those letters?" + +"The first was from Pondicherry, the second from Dundee, and the third from London." + +"From East London. What do you deduce from that?" + +"They are all seaports. That the writer was on board of a ship." + +"Excellent. We have already a clue. There can be no doubt that the probability--the strong probability--is that the writer was on board of a ship. And now let us consider another point. In the case of Pondicherry, seven weeks elapsed between the threat and its fulfilment, in Dundee it was only some three or four days. Does that suggest anything?" + +"A greater distance to travel." + +"But the letter had also a greater distance to come." + +"Then I do not see the point." + +"There is at least a presumption that the vessel in which the man or men are is a sailing-ship. It looks as if they always send their singular warning or token before them when starting upon their mission. You see how quickly the deed followed the sign when it came from Dundee. If they had come from Pondicherry in a steamer they would have arrived almost as soon as their letter. But, as a matter of fact, seven weeks elapsed. I think that those seven weeks represented the difference between the mail-boat which brought the letter and the sailing vessel which brought the writer." + +"It is possible." + +"More than that. It is probable. And now you see the deadly urgency of this new case, and why I urged young Openshaw to caution. The blow has always fallen at the end of the time which it would take the senders to travel the distance. But this one comes from London, and therefore we cannot count upon delay." + +"Good God!" I cried. "What can it mean, this relentless persecution?" + +"The papers which Openshaw carried are obviously of vital importance to the person or persons in the sailing-ship. I think that it is quite clear that there must be more than one of them. A single man could not have carried out two deaths in such a way as to deceive a coroner's jury. There must have been several in it, and they must have been men of resource and determination. Their papers they mean to have, be the holder of them who it may. In this way you see K. K. K. ceases to be the initials of an individual and becomes the badge of a society." + +"But of what society?" + +"Have you never--" said Sherlock Holmes, bending forward and sinking his voice--"have you never heard of the Ku Klux Klan?" + +"I never have." + +Holmes turned over the leaves of the book upon his knee. "Here it is," said he presently: + +" 'Ku Klux Klan. A name derived from the fanciful resemblance to the sound produced by cocking a rifle. This terrible secret society was formed by some ex-Confederate soldiers in the Southern states after the Civil War, and it rapidly formed local branches in different parts of the country, notably in Tennessee, Louisiana, the Carolinas, Georgia, and Florida. Its power was used for political purposes, principally for the terrorising of the negro voters and the murdering and driving from the country of those who were opposed to its views. Its outrages were usually preceded by a warning sent to the marked man in some fantastic but generally recognised shape--a sprig of oak-leaves in some parts, melon seeds or orange pips in others. On receiving this the victim might either openly abjure his former ways, or might fly from the country. If he braved the matter out, death would unfailingly come upon him, and usually in some strange and unforeseen manner. So perfect was the organisation of the society, and so systematic its methods, that there is hardly a case upon record where any man succeeded in braving it with impunity, or in which any of its outrages were traced home to the perpetrators. For some years the organisation flourished in spite of the efforts of the United States government and of the better classes of the community in the South. Eventually, in the year 1869, the movement rather suddenly collapsed, although there have been sporadic outbreaks of the same sort since that date.' + +"You will observe," said Holmes, laying down the volume, "that the sudden breaking up of the society was coincident with the disappearance of Openshaw from America with their papers. It may well have been cause and effect. It is no wonder that he and his family have some of the more implacable spirits upon their track. You can understand that this register and diary may implicate some of the first men in the South, and that there may be many who will not sleep easy at night until it is recovered." + +"Then the page we have seen--" + +"Is such as we might expect. It ran, if I remember right, 'sent the pips to A, B, and C'--that is, sent the society's warning to them. Then there are successive entries that A and B cleared, or left the country, and finally that C was visited, with, I fear, a sinister result for C. Well, I think, Doctor, that we may let some light into this dark place, and I believe that the only chance young Openshaw has in the meantime is to do what I have told him. There is nothing more to be said or to be done to-night, so hand me over my violin and let us try to forget for half an hour the miserable weather and the still more miserable ways of our fellow men." + +It had cleared in the morning, and the sun was shining with a subdued brightness through the dim veil which hangs over the great city. Sherlock Holmes was already at breakfast when I came down. + +"You will excuse me for not waiting for you," said he; "I have, I foresee, a very busy day before me in looking into this case of young Openshaw's." + +"What steps will you take?" I asked. + +"It will very much depend upon the results of my first inquiries. I may have to go down to Horsham, after all." + +"You will not go there first?" + +"No, I shall commence with the City. Just ring the bell and the maid will bring up your coffee." + +As I waited, I lifted the unopened newspaper from the table and glanced my eye over it. It rested upon a heading which sent a chill to my heart. + +"Holmes," I cried, "you are too late." + +"Ah!" said he, laying down his cup, "I feared as much. How was it done?" He spoke calmly, but I could see that he was deeply moved. + +"My eye caught the name of Openshaw, and the heading 'Tragedy Near Waterloo Bridge.' Here is the account: + +" 'Between nine and ten last night Police-Constable Cook, of the H Division, on duty near Waterloo Bridge, heard a cry for help and a splash in the water. The night, however, was extremely dark and stormy, so that, in spite of the help of several passers-by, it was quite impossible to effect a rescue. The alarm, however, was given, and, by the aid of the water-police, the body was eventually recovered. It proved to be that of a young gentleman whose name, as it appears from an envelope which was found in his pocket, was John Openshaw, and whose residence is near Horsham. It is conjectured that he may have been hurrying down to catch the last train from Waterloo Station, and that in his haste and the extreme darkness he missed his path and walked over the edge of one of the small landing-places for river steamboats. The body exhibited no traces of violence, and there can be no doubt that the deceased had been the victim of an unfortunate accident, which should have the effect of calling the attention of the authorities to the condition of the riverside landing-stages.' " + +We sat in silence for some minutes, Holmes more depressed and shaken than I had ever seen him. + +"That hurts my pride, Watson," he said at last. "It is a petty feeling, no doubt, but it hurts my pride. It becomes a personal matter with me now, and, if God sends me health, I shall set my hand upon this gang. That he should come to me for help, and that I should send him away to his death--!" He sprang from his chair and paced about the room in uncontrollable agitation, with a flush upon his sallow cheeks and a nervous clasping and unclasping of his long thin hands. + +"They must be cunning devils," he exclaimed at last. "How could they have decoyed him down there? The Embankment is not on the direct line to the station. The bridge, no doubt, was too crowded, even on such a night, for their purpose. Well, Watson, we shall see who will win in the long run. I am going out now!" + +"To the police?" + +"No; I shall be my own police. When I have spun the web they may take the flies, but not before." + +All day I was engaged in my professional work, and it was late in the evening before I returned to Baker Street. Sherlock Holmes had not come back yet. It was nearly ten o'clock before he entered, looking pale and worn. He walked up to the sideboard, and tearing a piece from the loaf he devoured it voraciously, washing it down with a long draught of water. + +"You are hungry," I remarked. + +"Starving. It had escaped my memory. I have had nothing since breakfast." + +"Nothing?" + +"Not a bite. I had no time to think of it." + +"And how have you succeeded?" + +"Well." + +"You have a clue?" + +"I have them in the hollow of my hand. Young Openshaw shall not long remain unavenged. Why, Watson, let us put their own devilish trade-mark upon them. It is well thought of!" + +"What do you mean?" + +He took an orange from the cupboard, and tearing it to pieces he squeezed out the pips upon the table. Of these he took five and thrust them into an envelope. On the inside of the flap he wrote "S. H. for J. O." Then he sealed it and addressed it to "Captain James Calhoun, Barque Lone Star, Savannah, Georgia." + +"That will await him when he enters port," said he, chuckling. "It may give him a sleepless night. He will find it as sure a precursor of his fate as Openshaw did before him." + +"And who is this Captain Calhoun?" + +"The leader of the gang. I shall have the others, but he first." + +"How did you trace it, then?" + +He took a large sheet of paper from his pocket, all covered with dates and names. + +"I have spent the whole day," said he, "over Lloyd's registers and files of the old papers, following the future career of every vessel which touched at Pondicherry in January and February in '83. There were thirty-six ships of fair tonnage which were reported there during those months. Of these, one, the Lone Star, instantly attracted my attention, since, although it was reported as having cleared from London, the name is that which is given to one of the states of the Union." + +"Texas, I think." + +"I was not and am not sure which; but I knew that the ship must have an American origin." + +"What then?" + +"I searched the Dundee records, and when I found that the barque Lone Star was there in January, '85, my suspicion became a certainty. I then inquired as to the vessels which lay at present in the port of London." + +"Yes?" + +"The Lone Star had arrived here last week. I went down to the Albert Dock and found that she had been taken down the river by the early tide this morning, homeward bound to Savannah. I wired to Gravesend and learned that she had passed some time ago, and as the wind is easterly I have no doubt that she is now past the Goodwins and not very far from the Isle of Wight." + +"What will you do, then?" + +"Oh, I have my hand upon him. He and the two mates, are as I learn, the only native-born Americans in the ship. The others are Finns and Germans. I know, also, that they were all three away from the ship last night. I had it from the stevedore who has been loading their cargo. By the time that their sailing-ship reaches Savannah the mail-boat will have carried this letter, and the cable will have informed the police of Savannah that these three gentlemen are badly wanted here upon a charge of murder." + +There is ever a flaw, however, in the best laid of human plans, and the murderers of John Openshaw were never to receive the orange pips which would show them that another, as cunning and as resolute as themselves, was upon their track. Very long and very severe were the equinoctial gales that year. We waited long for news of the Lone Star of Savannah, but none ever reached us. We did at last hear that somewhere far out in the Atlantic a shattered stern-post of a boat was seen swinging in the trough of a wave, with the letters "L. S." carved upon it, and that is all which we shall ever know of the fate of the Lone Star. + +ADVENTURE VI. THE MAN WITH THE TWISTED LIP + + +Isa Whitney, brother of the late Elias Whitney, D.D., Principal of the Theological College of St. George's, was much addicted to opium. The habit grew upon him, as I understand, from some foolish freak when he was at college; for having read De Quincey's description of his dreams and sensations, he had drenched his tobacco with laudanum in an attempt to produce the same effects. He found, as so many more have done, that the practice is easier to attain than to get rid of, and for many years he continued to be a slave to the drug, an object of mingled horror and pity to his friends and relatives. I can see him now, with yellow, pasty face, drooping lids, and pin-point pupils, all huddled in a chair, the wreck and ruin of a noble man. + +One night--it was in June, '89--there came a ring to my bell, about the hour when a man gives his first yawn and glances at the clock. I sat up in my chair, and my wife laid her needle-work down in her lap and made a little face of disappointment. + +"A patient!" said she. "You'll have to go out." + +I groaned, for I was newly come back from a weary day. + +We heard the door open, a few hurried words, and then quick steps upon the linoleum. Our own door flew open, and a lady, clad in some dark-coloured stuff, with a black veil, entered the room. + +"You will excuse my calling so late," she began, and then, suddenly losing her self-control, she ran forward, threw her arms about my wife's neck, and sobbed upon her shoulder. "Oh, I'm in such trouble!" she cried; "I do so want a little help." + +"Why," said my wife, pulling up her veil, "it is Kate Whitney. How you startled me, Kate! I had not an idea who you were when you came in." + +"I didn't know what to do, so I came straight to you." That was always the way. Folk who were in grief came to my wife like birds to a light-house. + +"It was very sweet of you to come. Now, you must have some wine and water, and sit here comfortably and tell us all about it. Or should you rather that I sent James off to bed?" + +"Oh, no, no! I want the doctor's advice and help, too. It's about Isa. He has not been home for two days. I am so frightened about him!" + +It was not the first time that she had spoken to us of her husband's trouble, to me as a doctor, to my wife as an old friend and school companion. We soothed and comforted her by such words as we could find. Did she know where her husband was? Was it possible that we could bring him back to her? + +It seems that it was. She had the surest information that of late he had, when the fit was on him, made use of an opium den in the farthest east of the City. Hitherto his orgies had always been confined to one day, and he had come back, twitching and shattered, in the evening. But now the spell had been upon him eight-and-forty hours, and he lay there, doubtless among the dregs of the docks, breathing in the poison or sleeping off the effects. There he was to be found, she was sure of it, at the Bar of Gold, in Upper Swandam Lane. But what was she to do? How could she, a young and timid woman, make her way into such a place and pluck her husband out from among the ruffians who surrounded him? + +There was the case, and of course there was but one way out of it. Might I not escort her to this place? And then, as a second thought, why should she come at all? I was Isa Whitney's medical adviser, and as such I had influence over him. I could manage it better if I were alone. I promised her on my word that I would send him home in a cab within two hours if he were indeed at the address which she had given me. And so in ten minutes I had left my armchair and cheery sitting-room behind me, and was speeding eastward in a hansom on a strange errand, as it seemed to me at the time, though the future only could show how strange it was to be. + +But there was no great difficulty in the first stage of my adventure. Upper Swandam Lane is a vile alley lurking behind the high wharves which line the north side of the river to the east of London Bridge. Between a slop-shop and a gin-shop, approached by a steep flight of steps leading down to a black gap like the mouth of a cave, I found the den of which I was in search. Ordering my cab to wait, I passed down the steps, worn hollow in the centre by the ceaseless tread of drunken feet; and by the light of a flickering oil-lamp above the door I found the latch and made my way into a long, low room, thick and heavy with the brown opium smoke, and terraced with wooden berths, like the forecastle of an emigrant ship. + +Through the gloom one could dimly catch a glimpse of bodies lying in strange fantastic poses, bowed shoulders, bent knees, heads thrown back, and chins pointing upward, with here and there a dark, lack-lustre eye turned upon the newcomer. Out of the black shadows there glimmered little red circles of light, now bright, now faint, as the burning poison waxed or waned in the bowls of the metal pipes. The most lay silent, but some muttered to themselves, and others talked together in a strange, low, monotonous voice, their conversation coming in gushes, and then suddenly tailing off into silence, each mumbling out his own thoughts and paying little heed to the words of his neighbour. At the farther end was a small brazier of burning charcoal, beside which on a three-legged wooden stool there sat a tall, thin old man, with his jaw resting upon his two fists, and his elbows upon his knees, staring into the fire. + +As I entered, a sallow Malay attendant had hurried up with a pipe for me and a supply of the drug, beckoning me to an empty berth. + +"Thank you. I have not come to stay," said I. "There is a friend of mine here, Mr. Isa Whitney, and I wish to speak with him." + +There was a movement and an exclamation from my right, and peering through the gloom, I saw Whitney, pale, haggard, and unkempt, staring out at me. + +"My God! It's Watson," said he. He was in a pitiable state of reaction, with every nerve in a twitter. "I say, Watson, what o'clock is it?" + +"Nearly eleven." + +"Of what day?" + +"Of Friday, June 19th." + +"Good heavens! I thought it was Wednesday. It is Wednesday. What d'you want to frighten a chap for?" He sank his face onto his arms and began to sob in a high treble key. + +"I tell you that it is Friday, man. Your wife has been waiting this two days for you. You should be ashamed of yourself!" + +"So I am. But you've got mixed, Watson, for I have only been here a few hours, three pipes, four pipes--I forget how many. But I'll go home with you. I wouldn't frighten Kate--poor little Kate. Give me your hand! Have you a cab?" + +"Yes, I have one waiting." + +"Then I shall go in it. But I must owe something. Find what I owe, Watson. I am all off colour. I can do nothing for myself." + +I walked down the narrow passage between the double row of sleepers, holding my breath to keep out the vile, stupefying fumes of the drug, and looking about for the manager. As I passed the tall man who sat by the brazier I felt a sudden pluck at my skirt, and a low voice whispered, "Walk past me, and then look back at me." The words fell quite distinctly upon my ear. I glanced down. They could only have come from the old man at my side, and yet he sat now as absorbed as ever, very thin, very wrinkled, bent with age, an opium pipe dangling down from between his knees, as though it had dropped in sheer lassitude from his fingers. I took two steps forward and looked back. It took all my self-control to prevent me from breaking out into a cry of astonishment. He had turned his back so that none could see him but I. His form had filled out, his wrinkles were gone, the dull eyes had regained their fire, and there, sitting by the fire and grinning at my surprise, was none other than Sherlock Holmes. He made a slight motion to me to approach him, and instantly, as he turned his face half round to the company once more, subsided into a doddering, loose-lipped senility. + +"Holmes!" I whispered, "what on earth are you doing in this den?" + +"As low as you can," he answered; "I have excellent ears. If you would have the great kindness to get rid of that sottish friend of yours I should be exceedingly glad to have a little talk with you." + +"I have a cab outside." + +"Then pray send him home in it. You may safely trust him, for he appears to be too limp to get into any mischief. I should recommend you also to send a note by the cabman to your wife to say that you have thrown in your lot with me. If you will wait outside, I shall be with you in five minutes." + +It was difficult to refuse any of Sherlock Holmes' requests, for they were always so exceedingly definite, and put forward with such a quiet air of mastery. I felt, however, that when Whitney was once confined in the cab my mission was practically accomplished; and for the rest, I could not wish anything better than to be associated with my friend in one of those singular adventures which were the normal condition of his existence. In a few minutes I had written my note, paid Whitney's bill, led him out to the cab, and seen him driven through the darkness. In a very short time a decrepit figure had emerged from the opium den, and I was walking down the street with Sherlock Holmes. For two streets he shuffled along with a bent back and an uncertain foot. Then, glancing quickly round, he straightened himself out and burst into a hearty fit of laughter. + +"I suppose, Watson," said he, "that you imagine that I have added opium-smoking to cocaine injections, and all the other little weaknesses on which you have favoured me with your medical views." + +"I was certainly surprised to find you there." + +"But not more so than I to find you." + +"I came to find a friend." + +"And I to find an enemy." + +"An enemy?" + +"Yes; one of my natural enemies, or, shall I say, my natural prey. Briefly, Watson, I am in the midst of a very remarkable inquiry, and I have hoped to find a clue in the incoherent ramblings of these sots, as I have done before now. Had I been recognised in that den my life would not have been worth an hour's purchase; for I have used it before now for my own purposes, and the rascally Lascar who runs it has sworn to have vengeance upon me. There is a trap-door at the back of that building, near the corner of Paul's Wharf, which could tell some strange tales of what has passed through it upon the moonless nights." + +"What! You do not mean bodies?" + +"Ay, bodies, Watson. We should be rich men if we had $1000 for every poor devil who has been done to death in that den. It is the vilest murder-trap on the whole riverside, and I fear that Neville St. Clair has entered it never to leave it more. But our trap should be here." He put his two forefingers between his teeth and whistled shrilly--a signal which was answered by a similar whistle from the distance, followed shortly by the rattle of wheels and the clink of horses' hoofs. + +"Now, Watson," said Holmes, as a tall dog-cart dashed up through the gloom, throwing out two golden tunnels of yellow light from its side lanterns. "You'll come with me, won't you?" + +"If I can be of use." + +"Oh, a trusty comrade is always of use; and a chronicler still more so. My room at The Cedars is a double-bedded one." + +"The Cedars?" + +"Yes; that is Mr. St. Clair's house. I am staying there while I conduct the inquiry." + +"Where is it, then?" + +"Near Lee, in Kent. We have a seven-mile drive before us." + +"But I am all in the dark." + +"Of course you are. You'll know all about it presently. Jump up here. All right, John; we shall not need you. Here's half a crown. Look out for me to-morrow, about eleven. Give her her head. So long, then!" + +He flicked the horse with his whip, and we dashed away through the endless succession of sombre and deserted streets, which widened gradually, until we were flying across a broad balustraded bridge, with the murky river flowing sluggishly beneath us. Beyond lay another dull wilderness of bricks and mortar, its silence broken only by the heavy, regular footfall of the policeman, or the songs and shouts of some belated party of revellers. A dull wrack was drifting slowly across the sky, and a star or two twinkled dimly here and there through the rifts of the clouds. Holmes drove in silence, with his head sunk upon his breast, and the air of a man who is lost in thought, while I sat beside him, curious to learn what this new quest might be which seemed to tax his powers so sorely, and yet afraid to break in upon the current of his thoughts. We had driven several miles, and were beginning to get to the fringe of the belt of suburban villas, when he shook himself, shrugged his shoulders, and lit up his pipe with the air of a man who has satisfied himself that he is acting for the best. + +"You have a grand gift of silence, Watson," said he. "It makes you quite invaluable as a companion. 'Pon my word, it is a great thing for me to have someone to talk to, for my own thoughts are not over-pleasant. I was wondering what I should say to this dear little woman to-night when she meets me at the door." + +"You forget that I know nothing about it." + +"I shall just have time to tell you the facts of the case before we get to Lee. It seems absurdly simple, and yet, somehow I can get nothing to go upon. There's plenty of thread, no doubt, but I can't get the end of it into my hand. Now, I'll state the case clearly and concisely to you, Watson, and maybe you can see a spark where all is dark to me." + +"Proceed, then." + +"Some years ago--to be definite, in May, 1884--there came to Lee a gentleman, Neville St. Clair by name, who appeared to have plenty of money. He took a large villa, laid out the grounds very nicely, and lived generally in good style. By degrees he made friends in the neighbourhood, and in 1887 he married the daughter of a local brewer, by whom he now has two children. He had no occupation, but was interested in several companies and went into town as a rule in the morning, returning by the 5:14 from Cannon Street every night. Mr. St. Clair is now thirty-seven years of age, is a man of temperate habits, a good husband, a very affectionate father, and a man who is popular with all who know him. I may add that his whole debts at the present moment, as far as we have been able to ascertain, amount to $88 10s., while he has $220 standing to his credit in the Capital and Counties Bank. There is no reason, therefore, to think that money troubles have been weighing upon his mind. + +"Last Monday Mr. Neville St. Clair went into town rather earlier than usual, remarking before he started that he had two important commissions to perform, and that he would bring his little boy home a box of bricks. Now, by the merest chance, his wife received a telegram upon this same Monday, very shortly after his departure, to the effect that a small parcel of considerable value which she had been expecting was waiting for her at the offices of the Aberdeen Shipping Company. Now, if you are well up in your London, you will know that the office of the company is in Fresno Street, which branches out of Upper Swandam Lane, where you found me to-night. Mrs. St. Clair had her lunch, started for the City, did some shopping, proceeded to the company's office, got her packet, and found herself at exactly 4:35 walking through Swandam Lane on her way back to the station. Have you followed me so far?" + +"It is very clear." + +"If you remember, Monday was an exceedingly hot day, and Mrs. St. Clair walked slowly, glancing about in the hope of seeing a cab, as she did not like the neighbourhood in which she found herself. While she was walking in this way down Swandam Lane, she suddenly heard an ejaculation or cry, and was struck cold to see her husband looking down at her and, as it seemed to her, beckoning to her from a second-floor window. The window was open, and she distinctly saw his face, which she describes as being terribly agitated. He waved his hands frantically to her, and then vanished from the window so suddenly that it seemed to her that he had been plucked back by some irresistible force from behind. One singular point which struck her quick feminine eye was that although he wore some dark coat, such as he had started to town in, he had on neither collar nor necktie. + +"Convinced that something was amiss with him, she rushed down the steps--for the house was none other than the opium den in which you found me to-night--and running through the front room she attempted to ascend the stairs which led to the first floor. At the foot of the stairs, however, she met this Lascar scoundrel of whom I have spoken, who thrust her back and, aided by a Dane, who acts as assistant there, pushed her out into the street. Filled with the most maddening doubts and fears, she rushed down the lane and, by rare good-fortune, met in Fresno Street a number of constables with an inspector, all on their way to their beat. The inspector and two men accompanied her back, and in spite of the continued resistance of the proprietor, they made their way to the room in which Mr. St. Clair had last been seen. There was no sign of him there. In fact, in the whole of that floor there was no one to be found save a crippled wretch of hideous aspect, who, it seems, made his home there. Both he and the Lascar stoutly swore that no one else had been in the front room during the afternoon. So determined was their denial that the inspector was staggered, and had almost come to believe that Mrs. St. Clair had been deluded when, with a cry, she sprang at a small deal box which lay upon the table and tore the lid from it. Out there fell a cascade of children's bricks. It was the toy which he had promised to bring home. + +"This discovery, and the evident confusion which the cripple showed, made the inspector realise that the matter was serious. The rooms were carefully examined, and results all pointed to an abominable crime. The front room was plainly furnished as a sitting-room and led into a small bedroom, which looked out upon the back of one of the wharves. Between the wharf and the bedroom window is a narrow strip, which is dry at low tide but is covered at high tide with at least four and a half feet of water. The bedroom window was a broad one and opened from below. On examination traces of blood were to be seen upon the windowsill, and several scattered drops were visible upon the wooden floor of the bedroom. Thrust away behind a curtain in the front room were all the clothes of Mr. Neville St. Clair, with the exception of his coat. His boots, his socks, his hat, and his watch--all were there. There were no signs of violence upon any of these garments, and there were no other traces of Mr. Neville St. Clair. Out of the window he must apparently have gone for no other exit could be discovered, and the ominous bloodstains upon the sill gave little promise that he could save himself by swimming, for the tide was at its very highest at the moment of the tragedy. + +"And now as to the villains who seemed to be immediately implicated in the matter. The Lascar was known to be a man of the vilest antecedents, but as, by Mrs. St. Clair's story, he was known to have been at the foot of the stair within a very few seconds of her husband's appearance at the window, he could hardly have been more than an accessory to the crime. His defence was one of absolute ignorance, and he protested that he had no knowledge as to the doings of Hugh Boone, his lodger, and that he could not account in any way for the presence of the missing gentleman's clothes. + +"So much for the Lascar manager. Now for the sinister cripple who lives upon the second floor of the opium den, and who was certainly the last human being whose eyes rested upon Neville St. Clair. His name is Hugh Boone, and his hideous face is one which is familiar to every man who goes much to the City. He is a professional beggar, though in order to avoid the police regulations he pretends to a small trade in wax vestas. Some little distance down Threadneedle Street, upon the left-hand side, there is, as you may have remarked, a small angle in the wall. Here it is that this creature takes his daily seat, cross-legged with his tiny stock of matches on his lap, and as he is a piteous spectacle a small rain of charity descends into the greasy leather cap which lies upon the pavement beside him. I have watched the fellow more than once before ever I thought of making his professional acquaintance, and I have been surprised at the harvest which he has reaped in a short time. His appearance, you see, is so remarkable that no one can pass him without observing him. A shock of orange hair, a pale face disfigured by a horrible scar, which, by its contraction, has turned up the outer edge of his upper lip, a bulldog chin, and a pair of very penetrating dark eyes, which present a singular contrast to the colour of his hair, all mark him out from amid the common crowd of mendicants and so, too, does his wit, for he is ever ready with a reply to any piece of chaff which may be thrown at him by the passers-by. This is the man whom we now learn to have been the lodger at the opium den, and to have been the last man to see the gentleman of whom we are in quest." + +"But a cripple!" said I. "What could he have done single-handed against a man in the prime of life?" + +"He is a cripple in the sense that he walks with a limp; but in other respects he appears to be a powerful and well-nurtured man. Surely your medical experience would tell you, Watson, that weakness in one limb is often compensated for by exceptional strength in the others." + +"Pray continue your narrative." + +"Mrs. St. Clair had fainted at the sight of the blood upon the window, and she was escorted home in a cab by the police, as her presence could be of no help to them in their investigations. Inspector Barton, who had charge of the case, made a very careful examination of the premises, but without finding anything which threw any light upon the matter. One mistake had been made in not arresting Boone instantly, as he was allowed some few minutes during which he might have communicated with his friend the Lascar, but this fault was soon remedied, and he was seized and searched, without anything being found which could incriminate him. There were, it is true, some blood-stains upon his right shirt-sleeve, but he pointed to his ring-finger, which had been cut near the nail, and explained that the bleeding came from there, adding that he had been to the window not long before, and that the stains which had been observed there came doubtless from the same source. He denied strenuously having ever seen Mr. Neville St. Clair and swore that the presence of the clothes in his room was as much a mystery to him as to the police. As to Mrs. St. Clair's assertion that she had actually seen her husband at the window, he declared that she must have been either mad or dreaming. He was removed, loudly protesting, to the police-station, while the inspector remained upon the premises in the hope that the ebbing tide might afford some fresh clue. + +"And it did, though they hardly found upon the mud-bank what they had feared to find. It was Neville St. Clair's coat, and not Neville St. Clair, which lay uncovered as the tide receded. And what do you think they found in the pockets?" + +"I cannot imagine." + +"No, I don't think you would guess. Every pocket stuffed with pennies and half-pennies--421 pennies and 270 half-pennies. It was no wonder that it had not been swept away by the tide. But a human body is a different matter. There is a fierce eddy between the wharf and the house. It seemed likely enough that the weighted coat had remained when the stripped body had been sucked away into the river." + +"But I understand that all the other clothes were found in the room. Would the body be dressed in a coat alone?" + +"No, sir, but the facts might be met speciously enough. Suppose that this man Boone had thrust Neville St. Clair through the window, there is no human eye which could have seen the deed. What would he do then? It would of course instantly strike him that he must get rid of the tell-tale garments. He would seize the coat, then, and be in the act of throwing it out, when it would occur to him that it would swim and not sink. He has little time, for he has heard the scuffle downstairs when the wife tried to force her way up, and perhaps he has already heard from his Lascar confederate that the police are hurrying up the street. There is not an instant to be lost. He rushes to some secret hoard, where he has accumulated the fruits of his beggary, and he stuffs all the coins upon which he can lay his hands into the pockets to make sure of the coat's sinking. He throws it out, and would have done the same with the other garments had not he heard the rush of steps below, and only just had time to close the window when the police appeared." + +"It certainly sounds feasible." + +"Well, we will take it as a working hypothesis for want of a better. Boone, as I have told you, was arrested and taken to the station, but it could not be shown that there had ever before been anything against him. He had for years been known as a professional beggar, but his life appeared to have been a very quiet and innocent one. There the matter stands at present, and the questions which have to be solved--what Neville St. Clair was doing in the opium den, what happened to him when there, where is he now, and what Hugh Boone had to do with his disappearance--are all as far from a solution as ever. I confess that I cannot recall any case within my experience which looked at the first glance so simple and yet which presented such difficulties." + +While Sherlock Holmes had been detailing this singular series of events, we had been whirling through the outskirts of the great town until the last straggling houses had been left behind, and we rattled along with a country hedge upon either side of us. Just as he finished, however, we drove through two scattered villages, where a few lights still glimmered in the windows. + +"We are on the outskirts of Lee," said my companion. "We have touched on three English counties in our short drive, starting in Middlesex, passing over an angle of Surrey, and ending in Kent. See that light among the trees? That is The Cedars, and beside that lamp sits a woman whose anxious ears have already, I have little doubt, caught the clink of our horse's feet." + +"But why are you not conducting the case from Baker Street?" I asked. + +"Because there are many inquiries which must be made out here. Mrs. St. Clair has most kindly put two rooms at my disposal, and you may rest assured that she will have nothing but a welcome for my friend and colleague. I hate to meet her, Watson, when I have no news of her husband. Here we are. Whoa, there, whoa!" + +We had pulled up in front of a large villa which stood within its own grounds. A stable-boy had run out to the horse's head, and springing down, I followed Holmes up the small, winding gravel-drive which led to the house. As we approached, the door flew open, and a little blonde woman stood in the opening, clad in some sort of light mousseline de soie, with a touch of fluffy pink chiffon at her neck and wrists. She stood with her figure outlined against the flood of light, one hand upon the door, one half-raised in her eagerness, her body slightly bent, her head and face protruded, with eager eyes and parted lips, a standing question. + +"Well?" she cried, "well?" And then, seeing that there were two of us, she gave a cry of hope which sank into a groan as she saw that my companion shook his head and shrugged his shoulders. + +"No good news?" + +"None." + +"No bad?" + +"No." + +"Thank God for that. But come in. You must be weary, for you have had a long day." + +"This is my friend, Dr. Watson. He has been of most vital use to me in several of my cases, and a lucky chance has made it possible for me to bring him out and associate him with this investigation." + +"I am delighted to see you," said she, pressing my hand warmly. "You will, I am sure, forgive anything that may be wanting in our arrangements, when you consider the blow which has come so suddenly upon us." + +"My dear madam," said I, "I am an old campaigner, and if I were not I can very well see that no apology is needed. If I can be of any assistance, either to you or to my friend here, I shall be indeed happy." + +"Now, Mr. Sherlock Holmes," said the lady as we entered a well-lit dining-room, upon the table of which a cold supper had been laid out, "I should very much like to ask you one or two plain questions, to which I beg that you will give a plain answer." + +"Certainly, madam." + +"Do not trouble about my feelings. I am not hysterical, nor given to fainting. I simply wish to hear your real, real opinion." + +"Upon what point?" + +"In your heart of hearts, do you think that Neville is alive?" + +Sherlock Holmes seemed to be embarrassed by the question. "Frankly, now!" she repeated, standing upon the rug and looking keenly down at him as he leaned back in a basket-chair. + +"Frankly, then, madam, I do not." + +"You think that he is dead?" + +"I do." + +"Murdered?" + +"I don't say that. Perhaps." + +"And on what day did he meet his death?" + +"On Monday." + +"Then perhaps, Mr. Holmes, you will be good enough to explain how it is that I have received a letter from him to-day." + +Sherlock Holmes sprang out of his chair as if he had been galvanised. + +"What!" he roared. + +"Yes, to-day." She stood smiling, holding up a little slip of paper in the air. + +"May I see it?" + +"Certainly." + +He snatched it from her in his eagerness, and smoothing it out upon the table he drew over the lamp and examined it intently. I had left my chair and was gazing at it over his shoulder. The envelope was a very coarse one and was stamped with the Gravesend postmark and with the date of that very day, or rather of the day before, for it was considerably after midnight. + +"Coarse writing," murmured Holmes. "Surely this is not your husband's writing, madam." + +"No, but the enclosure is." + +"I perceive also that whoever addressed the envelope had to go and inquire as to the address." + +"How can you tell that?" + +"The name, you see, is in perfectly black ink, which has dried itself. The rest is of the greyish colour, which shows that blotting-paper has been used. If it had been written straight off, and then blotted, none would be of a deep black shade. This man has written the name, and there has then been a pause before he wrote the address, which can only mean that he was not familiar with it. It is, of course, a trifle, but there is nothing so important as trifles. Let us now see the letter. Ha! there has been an enclosure here!" + +"Yes, there was a ring. His signet-ring." + +"And you are sure that this is your husband's hand?" + +"One of his hands." + +"One?" + +"His hand when he wrote hurriedly. It is very unlike his usual writing, and yet I know it well." + +" 'Dearest do not be frightened. All will come well. There is a huge error which it may take some little time to rectify. Wait in patience.--NEVILLE.' Written in pencil upon the fly-leaf of a book, octavo size, no water-mark. Hum! Posted to-day in Gravesend by a man with a dirty thumb. Ha! And the flap has been gummed, if I am not very much in error, by a person who had been chewing tobacco. And you have no doubt that it is your husband's hand, madam?" + +"None. Neville wrote those words." + +"And they were posted to-day at Gravesend. Well, Mrs. St. Clair, the clouds lighten, though I should not venture to say that the danger is over." + +"But he must be alive, Mr. Holmes." + +"Unless this is a clever forgery to put us on the wrong scent. The ring, after all, proves nothing. It may have been taken from him." + +"No, no; it is, it is his very own writing!" + +"Very well. It may, however, have been written on Monday and only posted to-day." + +"That is possible." + +"If so, much may have happened between." + +"Oh, you must not discourage me, Mr. Holmes. I know that all is well with him. There is so keen a sympathy between us that I should know if evil came upon him. On the very day that I saw him last he cut himself in the bedroom, and yet I in the dining-room rushed upstairs instantly with the utmost certainty that something had happened. Do you think that I would respond to such a trifle and yet be ignorant of his death?" + +"I have seen too much not to know that the impression of a woman may be more valuable than the conclusion of an analytical reasoner. And in this letter you certainly have a very strong piece of evidence to corroborate your view. But if your husband is alive and able to write letters, why should he remain away from you?" + +"I cannot imagine. It is unthinkable." + +"And on Monday he made no remarks before leaving you?" + +"No." + +"And you were surprised to see him in Swandam Lane?" + +"Very much so." + +"Was the window open?" + +"Yes." + +"Then he might have called to you?" + +"He might." + +"He only, as I understand, gave an inarticulate cry?" + +"Yes." + +"A call for help, you thought?" + +"Yes. He waved his hands." + +"But it might have been a cry of surprise. Astonishment at the unexpected sight of you might cause him to throw up his hands?" + +"It is possible." + +"And you thought he was pulled back?" + +"He disappeared so suddenly." + +"He might have leaped back. You did not see anyone else in the room?" + +"No, but this horrible man confessed to having been there, and the Lascar was at the foot of the stairs." + +"Quite so. Your husband, as far as you could see, had his ordinary clothes on?" + +"But without his collar or tie. I distinctly saw his bare throat." + +"Had he ever spoken of Swandam Lane?" + +"Never." + +"Had he ever showed any signs of having taken opium?" + +"Never." + +"Thank you, Mrs. St. Clair. Those are the principal points about which I wished to be absolutely clear. We shall now have a little supper and then retire, for we may have a very busy day to-morrow." + +A large and comfortable double-bedded room had been placed at our disposal, and I was quickly between the sheets, for I was weary after my night of adventure. Sherlock Holmes was a man, however, who, when he had an unsolved problem upon his mind, would go for days, and even for a week, without rest, turning it over, rearranging his facts, looking at it from every point of view until he had either fathomed it or convinced himself that his data were insufficient. It was soon evident to me that he was now preparing for an all-night sitting. He took off his coat and waistcoat, put on a large blue dressing-gown, and then wandered about the room collecting pillows from his bed and cushions from the sofa and armchairs. With these he constructed a sort of Eastern divan, upon which he perched himself cross-legged, with an ounce of shag tobacco and a box of matches laid out in front of him. In the dim light of the lamp I saw him sitting there, an old briar pipe between his lips, his eyes fixed vacantly upon the corner of the ceiling, the blue smoke curling up from him, silent, motionless, with the light shining upon his strong-set aquiline features. So he sat as I dropped off to sleep, and so he sat when a sudden ejaculation caused me to wake up, and I found the summer sun shining into the apartment. The pipe was still between his lips, the smoke still curled upward, and the room was full of a dense tobacco haze, but nothing remained of the heap of shag which I had seen upon the previous night. + +"Awake, Watson?" he asked. + +"Yes." + +"Game for a morning drive?" + +"Certainly." + +"Then dress. No one is stirring yet, but I know where the stable-boy sleeps, and we shall soon have the trap out." He chuckled to himself as he spoke, his eyes twinkled, and he seemed a different man to the sombre thinker of the previous night. + +As I dressed I glanced at my watch. It was no wonder that no one was stirring. It was twenty-five minutes past four. I had hardly finished when Holmes returned with the news that the boy was putting in the horse. + +"I want to test a little theory of mine," said he, pulling on his boots. "I think, Watson, that you are now standing in the presence of one of the most absolute fools in Europe. I deserve to be kicked from here to Charing Cross. But I think I have the key of the affair now." + +"And where is it?" I asked, smiling. + +"In the bathroom," he answered. "Oh, yes, I am not joking," he continued, seeing my look of incredulity. "I have just been there, and I have taken it out, and I have got it in this Gladstone bag. Come on, my boy, and we shall see whether it will not fit the lock." + +We made our way downstairs as quietly as possible, and out into the bright morning sunshine. In the road stood our horse and trap, with the half-clad stable-boy waiting at the head. We both sprang in, and away we dashed down the London Road. A few country carts were stirring, bearing in vegetables to the metropolis, but the lines of villas on either side were as silent and lifeless as some city in a dream. + +"It has been in some points a singular case," said Holmes, flicking the horse on into a gallop. "I confess that I have been as blind as a mole, but it is better to learn wisdom late than never to learn it at all." + +In town the earliest risers were just beginning to look sleepily from their windows as we drove through the streets of the Surrey side. Passing down the Waterloo Bridge Road we crossed over the river, and dashing up Wellington Street wheeled sharply to the right and found ourselves in Bow Street. Sherlock Holmes was well known to the force, and the two constables at the door saluted him. One of them held the horse's head while the other led us in. + +"Who is on duty?" asked Holmes. + +"Inspector Bradstreet, sir." + +"Ah, Bradstreet, how are you?" A tall, stout official had come down the stone-flagged passage, in a peaked cap and frogged jacket. "I wish to have a quiet word with you, Bradstreet." "Certainly, Mr. Holmes. Step into my room here." It was a small, office-like room, with a huge ledger upon the table, and a telephone projecting from the wall. The inspector sat down at his desk. + +"What can I do for you, Mr. Holmes?" + +"I called about that beggarman, Boone--the one who was charged with being concerned in the disappearance of Mr. Neville St. Clair, of Lee." + +"Yes. He was brought up and remanded for further inquiries." + +"So I heard. You have him here?" + +"In the cells." + +"Is he quiet?" + +"Oh, he gives no trouble. But he is a dirty scoundrel." + +"Dirty?" + +"Yes, it is all we can do to make him wash his hands, and his face is as black as a tinker's. Well, when once his case has been settled, he will have a regular prison bath; and I think, if you saw him, you would agree with me that he needed it." + +"I should like to see him very much." + +"Would you? That is easily done. Come this way. You can leave your bag." + +"No, I think that I'll take it." + +"Very good. Come this way, if you please." He led us down a passage, opened a barred door, passed down a winding stair, and brought us to a whitewashed corridor with a line of doors on each side. + +"The third on the right is his," said the inspector. "Here it is!" He quietly shot back a panel in the upper part of the door and glanced through. + +"He is asleep," said he. "You can see him very well." + +We both put our eyes to the grating. The prisoner lay with his face towards us, in a very deep sleep, breathing slowly and heavily. He was a middle-sized man, coarsely clad as became his calling, with a coloured shirt protruding through the rent in his tattered coat. He was, as the inspector had said, extremely dirty, but the grime which covered his face could not conceal its repulsive ugliness. A broad wheal from an old scar ran right across it from eye to chin, and by its contraction had turned up one side of the upper lip, so that three teeth were exposed in a perpetual snarl. A shock of very bright red hair grew low over his eyes and forehead. + +"He's a beauty, isn't he?" said the inspector. + +"He certainly needs a wash," remarked Holmes. "I had an idea that he might, and I took the liberty of bringing the tools with me." He opened the Gladstone bag as he spoke, and took out, to my astonishment, a very large bath-sponge. + +"He! he! You are a funny one," chuckled the inspector. + +"Now, if you will have the great goodness to open that door very quietly, we will soon make him cut a much more respectable figure." + +"Well, I don't know why not," said the inspector. "He doesn't look a credit to the Bow Street cells, does he?" He slipped his key into the lock, and we all very quietly entered the cell. The sleeper half turned, and then settled down once more into a deep slumber. Holmes stooped to the water-jug, moistened his sponge, and then rubbed it twice vigorously across and down the prisoner's face. + +"Let me introduce you," he shouted, "to Mr. Neville St. Clair, of Lee, in the county of Kent." + +Never in my life have I seen such a sight. The man's face peeled off under the sponge like the bark from a tree. Gone was the coarse brown tint! Gone, too, was the horrid scar which had seamed it across, and the twisted lip which had given the repulsive sneer to the face! A twitch brought away the tangled red hair, and there, sitting up in his bed, was a pale, sad-faced, refined-looking man, black-haired and smooth-skinned, rubbing his eyes and staring about him with sleepy bewilderment. Then suddenly realising the exposure, he broke into a scream and threw himself down with his face to the pillow. + +"Great heavens!" cried the inspector, "it is, indeed, the missing man. I know him from the photograph." + +The prisoner turned with the reckless air of a man who abandons himself to his destiny. "Be it so," said he. "And pray what am I charged with?" + +"With making away with Mr. Neville St.-- Oh, come, you can't be charged with that unless they make a case of attempted suicide of it," said the inspector with a grin. "Well, I have been twenty-seven years in the force, but this really takes the cake." + +"If I am Mr. Neville St. Clair, then it is obvious that no crime has been committed, and that, therefore, I am illegally detained." + +"No crime, but a very great error has been committed," said Holmes. "You would have done better to have trusted you wife." + +"It was not the wife; it was the children," groaned the prisoner. "God help me, I would not have them ashamed of their father. My God! What an exposure! What can I do?" + +Sherlock Holmes sat down beside him on the couch and patted him kindly on the shoulder. + +"If you leave it to a court of law to clear the matter up," said he, "of course you can hardly avoid publicity. On the other hand, if you convince the police authorities that there is no possible case against you, I do not know that there is any reason that the details should find their way into the papers. Inspector Bradstreet would, I am sure, make notes upon anything which you might tell us and submit it to the proper authorities. The case would then never go into court at all." + +"God bless you!" cried the prisoner passionately. "I would have endured imprisonment, ay, even execution, rather than have left my miserable secret as a family blot to my children. + +"You are the first who have ever heard my story. My father was a schoolmaster in Chesterfield, where I received an excellent education. I travelled in my youth, took to the stage, and finally became a reporter on an evening paper in London. One day my editor wished to have a series of articles upon begging in the metropolis, and I volunteered to supply them. There was the point from which all my adventures started. It was only by trying begging as an amateur that I could get the facts upon which to base my articles. When an actor I had, of course, learned all the secrets of making up, and had been famous in the green-room for my skill. I took advantage now of my attainments. I painted my face, and to make myself as pitiable as possible I made a good scar and fixed one side of my lip in a twist by the aid of a small slip of flesh-coloured plaster. Then with a red head of hair, and an appropriate dress, I took my station in the business part of the city, ostensibly as a match-seller but really as a beggar. For seven hours I plied my trade, and when I returned home in the evening I found to my surprise that I had received no less than 26s. 4d. + +"I wrote my articles and thought little more of the matter until, some time later, I backed a bill for a friend and had a writ served upon me for $25. I was at my wit's end where to get the money, but a sudden idea came to me. I begged a fortnight's grace from the creditor, asked for a holiday from my employers, and spent the time in begging in the City under my disguise. In ten days I had the money and had paid the debt. + +"Well, you can imagine how hard it was to settle down to arduous work at $2 a week when I knew that I could earn as much in a day by smearing my face with a little paint, laying my cap on the ground, and sitting still. It was a long fight between my pride and the money, but the dollars won at last, and I threw up reporting and sat day after day in the corner which I had first chosen, inspiring pity by my ghastly face and filling my pockets with coppers. Only one man knew my secret. He was the keeper of a low den in which I used to lodge in Swandam Lane, where I could every morning emerge as a squalid beggar and in the evenings transform myself into a well-dressed man about town. This fellow, a Lascar, was well paid by me for his rooms, so that I knew that my secret was safe in his possession. + +"Well, very soon I found that I was saving considerable sums of money. I do not mean that any beggar in the streets of London could earn $700 a year--which is less than my average takings--but I had exceptional advantages in my power of making up, and also in a facility of repartee, which improved by practice and made me quite a recognised character in the City. All day a stream of pennies, varied by silver, poured in upon me, and it was a very bad day in which I failed to take $2. + +"As I grew richer I grew more ambitious, took a house in the country, and eventually married, without anyone having a suspicion as to my real occupation. My dear wife knew that I had business in the City. She little knew what. + +"Last Monday I had finished for the day and was dressing in my room above the opium den when I looked out of my window and saw, to my horror and astonishment, that my wife was standing in the street, with her eyes fixed full upon me. I gave a cry of surprise, threw up my arms to cover my face, and, rushing to my confidant, the Lascar, entreated him to prevent anyone from coming up to me. I heard her voice downstairs, but I knew that she could not ascend. Swiftly I threw off my clothes, pulled on those of a beggar, and put on my pigments and wig. Even a wife's eyes could not pierce so complete a disguise. But then it occurred to me that there might be a search in the room, and that the clothes might betray me. I threw open the window, reopening by my violence a small cut which I had inflicted upon myself in the bedroom that morning. Then I seized my coat, which was weighted by the coppers which I had just transferred to it from the leather bag in which I carried my takings. I hurled it out of the window, and it disappeared into the Thames. The other clothes would have followed, but at that moment there was a rush of constables up the stair, and a few minutes after I found, rather, I confess, to my relief, that instead of being identified as Mr. Neville St. Clair, I was arrested as his murderer. + +"I do not know that there is anything else for me to explain. I was determined to preserve my disguise as long as possible, and hence my preference for a dirty face. Knowing that my wife would be terribly anxious, I slipped off my ring and confided it to the Lascar at a moment when no constable was watching me, together with a hurried scrawl, telling her that she had no cause to fear." + +"That note only reached her yesterday," said Holmes. + +"Good God! What a week she must have spent!" + +"The police have watched this Lascar," said Inspector Bradstreet, "and I can quite understand that he might find it difficult to post a letter unobserved. Probably he handed it to some sailor customer of his, who forgot all about it for some days." + +"That was it," said Holmes, nodding approvingly; "I have no doubt of it. But have you never been prosecuted for begging?" + +"Many times; but what was a fine to me?" + +"It must stop here, however," said Bradstreet. "If the police are to hush this thing up, there must be no more of Hugh Boone." + +"I have sworn it by the most solemn oaths which a man can take." + +"In that case I think that it is probable that no further steps may be taken. But if you are found again, then all must come out. I am sure, Mr. Holmes, that we are very much indebted to you for having cleared the matter up. I wish I knew how you reach your results." + +"I reached this one," said my friend, "by sitting upon five pillows and consuming an ounce of shag. I think, Watson, that if we drive to Baker Street we shall just be in time for breakfast." + +VII. THE ADVENTURE OF THE BLUE CARBUNCLE + + +I had called upon my friend Sherlock Holmes upon the second morning after Christmas, with the intention of wishing him the compliments of the season. He was lounging upon the sofa in a purple dressing-gown, a pipe-rack within his reach upon the right, and a pile of crumpled morning papers, evidently newly studied, near at hand. Beside the couch was a wooden chair, and on the angle of the back hung a very seedy and disreputable hard-felt hat, much the worse for wear, and cracked in several places. A lens and a forceps lying upon the seat of the chair suggested that the hat had been suspended in this manner for the purpose of examination. + +"You are engaged," said I; "perhaps I interrupt you." + +"Not at all. I am glad to have a friend with whom I can discuss my results. The matter is a perfectly trivial one"--he jerked his thumb in the direction of the old hat--"but there are points in connection with it which are not entirely devoid of interest and even of instruction." + +I seated myself in his armchair and warmed my hands before his crackling fire, for a sharp frost had set in, and the windows were thick with the ice crystals. "I suppose," I remarked, "that, homely as it looks, this thing has some deadly story linked on to it--that it is the clue which will guide you in the solution of some mystery and the punishment of some crime." + +"No, no. No crime," said Sherlock Holmes, laughing. "Only one of those whimsical little incidents which will happen when you have four million human beings all jostling each other within the space of a few square miles. Amid the action and reaction of so dense a swarm of humanity, every possible combination of events may be expected to take place, and many a little problem will be presented which may be striking and bizarre without being criminal. We have already had experience of such." + +"So much so," I remarked, "that of the last six cases which I have added to my notes, three have been entirely free of any legal crime." + +"Precisely. You allude to my attempt to recover the Irene Adler papers, to the singular case of Miss Mary Sutherland, and to the adventure of the man with the twisted lip. Well, I have no doubt that this small matter will fall into the same innocent category. You know Peterson, the commissionaire?" + +"Yes." + +"It is to him that this trophy belongs." + +"It is his hat." + +"No, no, he found it. Its owner is unknown. I beg that you will look upon it not as a battered billycock but as an intellectual problem. And, first, as to how it came here. It arrived upon Christmas morning, in company with a good fat goose, which is, I have no doubt, roasting at this moment in front of Peterson's fire. The facts are these: about four o'clock on Christmas morning, Peterson, who, as you know, is a very honest fellow, was returning from some small jollification and was making his way homeward down Tottenham Court Road. In front of him he saw, in the gaslight, a tallish man, walking with a slight stagger, and carrying a white goose slung over his shoulder. As he reached the corner of Goodge Street, a row broke out between this stranger and a little knot of roughs. One of the latter knocked off the man's hat, on which he raised his stick to defend himself and, swinging it over his head, smashed the shop window behind him. Peterson had rushed forward to protect the stranger from his assailants; but the man, shocked at having broken the window, and seeing an official-looking person in uniform rushing towards him, dropped his goose, took to his heels, and vanished amid the labyrinth of small streets which lie at the back of Tottenham Court Road. The roughs had also fled at the appearance of Peterson, so that he was left in possession of the field of battle, and also of the spoils of victory in the shape of this battered hat and a most unimpeachable Christmas goose." + +"Which surely he restored to their owner?" + +"My dear fellow, there lies the problem. It is true that 'For Mrs. Henry Baker' was printed upon a small card which was tied to the bird's left leg, and it is also true that the initials 'H. B.' are legible upon the lining of this hat, but as there are some thousands of Bakers, and some hundreds of Henry Bakers in this city of ours, it is not easy to restore lost property to any one of them." + +"What, then, did Peterson do?" + +"He brought round both hat and goose to me on Christmas morning, knowing that even the smallest problems are of interest to me. The goose we retained until this morning, when there were signs that, in spite of the slight frost, it would be well that it should be eaten without unnecessary delay. Its finder has carried it off, therefore, to fulfil the ultimate destiny of a goose, while I continue to retain the hat of the unknown gentleman who lost his Christmas dinner." + +"Did he not advertise?" + +"No." + +"Then, what clue could you have as to his identity?" + +"Only as much as we can deduce." + +"From his hat?" + +"Precisely." + +"But you are joking. What can you gather from this old battered felt?" + +"Here is my lens. You know my methods. What can you gather yourself as to the individuality of the man who has worn this article?" + +I took the tattered object in my hands and turned it over rather ruefully. It was a very ordinary black hat of the usual round shape, hard and much the worse for wear. The lining had been of red silk, but was a good deal discoloured. There was no maker's name; but, as Holmes had remarked, the initials "H. B." were scrawled upon one side. It was pierced in the brim for a hat-securer, but the elastic was missing. For the rest, it was cracked, exceedingly dusty, and spotted in several places, although there seemed to have been some attempt to hide the discoloured patches by smearing them with ink. + +"I can see nothing," said I, handing it back to my friend. + +"On the contrary, Watson, you can see everything. You fail, however, to reason from what you see. You are too timid in drawing your inferences." + +"Then, pray tell me what it is that you can infer from this hat?" + +He picked it up and gazed at it in the peculiar introspective fashion which was characteristic of him. "It is perhaps less suggestive than it might have been," he remarked, "and yet there are a few inferences which are very distinct, and a few others which represent at least a strong balance of probability. That the man was highly intellectual is of course obvious upon the face of it, and also that he was fairly well-to-do within the last three years, although he has now fallen upon evil days. He had foresight, but has less now than formerly, pointing to a moral retrogression, which, when taken with the decline of his fortunes, seems to indicate some evil influence, probably drink, at work upon him. This may account also for the obvious fact that his wife has ceased to love him." + +"My dear Holmes!" + +"He has, however, retained some degree of self-respect," he continued, disregarding my remonstrance. "He is a man who leads a sedentary life, goes out little, is out of training entirely, is middle-aged, has grizzled hair which he has had cut within the last few days, and which he anoints with lime-cream. These are the more patent facts which are to be deduced from his hat. Also, by the way, that it is extremely improbable that he has gas laid on in his house." + +"You are certainly joking, Holmes." + +"Not in the least. Is it possible that even now, when I give you these results, you are unable to see how they are attained?" + +"I have no doubt that I am very stupid, but I must confess that I am unable to follow you. For example, how did you deduce that this man was intellectual?" + +For answer Holmes clapped the hat upon his head. It came right over the forehead and settled upon the bridge of his nose. "It is a question of cubic capacity," said he; "a man with so large a brain must have something in it." + +"The decline of his fortunes, then?" + +"This hat is three years old. These flat brims curled at the edge came in then. It is a hat of the very best quality. Look at the band of ribbed silk and the excellent lining. If this man could afford to buy so expensive a hat three years ago, and has had no hat since, then he has assuredly gone down in the world." + +"Well, that is clear enough, certainly. But how about the foresight and the moral retrogression?" + +Sherlock Holmes laughed. "Here is the foresight," said he putting his finger upon the little disc and loop of the hat-securer. "They are never sold upon hats. If this man ordered one, it is a sign of a certain amount of foresight, since he went out of his way to take this precaution against the wind. But since we see that he has broken the elastic and has not troubled to replace it, it is obvious that he has less foresight now than formerly, which is a distinct proof of a weakening nature. On the other hand, he has endeavoured to conceal some of these stains upon the felt by daubing them with ink, which is a sign that he has not entirely lost his self-respect." + +"Your reasoning is certainly plausible." + +"The further points, that he is middle-aged, that his hair is grizzled, that it has been recently cut, and that he uses lime-cream, are all to be gathered from a close examination of the lower part of the lining. The lens discloses a large number of hair-ends, clean cut by the scissors of the barber. They all appear to be adhesive, and there is a distinct odour of lime-cream. This dust, you will observe, is not the gritty, grey dust of the street but the fluffy brown dust of the house, showing that it has been hung up indoors most of the time, while the marks of moisture upon the inside are proof positive that the wearer perspired very freely, and could therefore, hardly be in the best of training." + +"But his wife--you said that she had ceased to love him." + +"This hat has not been brushed for weeks. When I see you, my dear Watson, with a week's accumulation of dust upon your hat, and when your wife allows you to go out in such a state, I shall fear that you also have been unfortunate enough to lose your wife's affection." + +"But he might be a bachelor." + +"Nay, he was bringing home the goose as a peace-offering to his wife. Remember the card upon the bird's leg." + +"You have an answer to everything. But how on earth do you deduce that the gas is not laid on in his house?" + +"One tallow stain, or even two, might come by chance; but when I see no less than five, I think that there can be little doubt that the individual must be brought into frequent contact with burning tallow--walks upstairs at night probably with his hat in one hand and a guttering candle in the other. Anyhow, he never got tallow-stains from a gas-jet. Are you satisfied?" + +"Well, it is very ingenious," said I, laughing; "but since, as you said just now, there has been no crime committed, and no harm done save the loss of a goose, all this seems to be rather a waste of energy." + +Sherlock Holmes had opened his mouth to reply, when the door flew open, and Peterson, the commissionaire, rushed into the apartment with flushed cheeks and the face of a man who is dazed with astonishment. + +"The goose, Mr. Holmes! The goose, sir!" he gasped. + +"Eh? What of it, then? Has it returned to life and flapped off through the kitchen window?" Holmes twisted himself round upon the sofa to get a fairer view of the man's excited face. + +"See here, sir! See what my wife found in its crop!" He held out his hand and displayed upon the centre of the palm a brilliantly scintillating blue stone, rather smaller than a bean in size, but of such purity and radiance that it twinkled like an electric point in the dark hollow of his hand. + +Sherlock Holmes sat up with a whistle. "By Jove, Peterson!" said he, "this is treasure trove indeed. I suppose you know what you have got?" + +"A diamond, sir? A precious stone. It cuts into glass as though it were putty." + +"It's more than a precious stone. It is the precious stone." + +"Not the Countess of Morcar's blue carbuncle!" I ejaculated. + +"Precisely so. I ought to know its size and shape, seeing that I have read the advertisement about it in The Times every day lately. It is absolutely unique, and its value can only be conjectured, but the reward offered of $1000 is certainly not within a twentieth part of the market price." + +"A thousand pounds! Great Lord of mercy!" The commissionaire plumped down into a chair and stared from one to the other of us. + +"That is the reward, and I have reason to know that there are sentimental considerations in the background which would induce the Countess to part with half her fortune if she could but recover the gem." + +"It was lost, if I remember aright, at the Hotel Cosmopolitan," I remarked. + +"Precisely so, on December 22nd, just five days ago. John Horner, a plumber, was accused of having abstracted it from the lady's jewel-case. The evidence against him was so strong that the case has been referred to the Assizes. I have some account of the matter here, I believe." He rummaged amid his newspapers, glancing over the dates, until at last he smoothed one out, doubled it over, and read the following paragraph: + +"Hotel Cosmopolitan Jewel Robbery. John Horner, 26, plumber, was brought up upon the charge of having upon the 22nd inst., abstracted from the jewel-case of the Countess of Morcar the valuable gem known as the blue carbuncle. James Ryder, upper-attendant at the hotel, gave his evidence to the effect that he had shown Horner up to the dressing-room of the Countess of Morcar upon the day of the robbery in order that he might solder the second bar of the grate, which was loose. He had remained with Horner some little time, but had finally been called away. On returning, he found that Horner had disappeared, that the bureau had been forced open, and that the small morocco casket in which, as it afterwards transpired, the Countess was accustomed to keep her jewel, was lying empty upon the dressing-table. Ryder instantly gave the alarm, and Horner was arrested the same evening; but the stone could not be found either upon his person or in his rooms. Catherine Cusack, maid to the Countess, deposed to having heard Ryder's cry of dismay on discovering the robbery, and to having rushed into the room, where she found matters as described by the last witness. Inspector Bradstreet, B division, gave evidence as to the arrest of Horner, who struggled frantically, and protested his innocence in the strongest terms. Evidence of a previous conviction for robbery having been given against the prisoner, the magistrate refused to deal summarily with the offence, but referred it to the Assizes. Horner, who had shown signs of intense emotion during the proceedings, fainted away at the conclusion and was carried out of court." + +"Hum! So much for the police-court," said Holmes thoughtfully, tossing aside the paper. "The question for us now to solve is the sequence of events leading from a rifled jewel-case at one end to the crop of a goose in Tottenham Court Road at the other. You see, Watson, our little deductions have suddenly assumed a much more important and less innocent aspect. Here is the stone; the stone came from the goose, and the goose came from Mr. Henry Baker, the gentleman with the bad hat and all the other characteristics with which I have bored you. So now we must set ourselves very seriously to finding this gentleman and ascertaining what part he has played in this little mystery. To do this, we must try the simplest means first, and these lie undoubtedly in an advertisement in all the evening papers. If this fail, I shall have recourse to other methods." + +"What will you say?" + +"Give me a pencil and that slip of paper. Now, then: 'Found at the corner of Goodge Street, a goose and a black felt hat. Mr. Henry Baker can have the same by applying at 6:30 this evening at 221B, Baker Street.' That is clear and concise." + +"Very. But will he see it?" + +"Well, he is sure to keep an eye on the papers, since, to a poor man, the loss was a heavy one. He was clearly so scared by his mischance in breaking the window and by the approach of Peterson that he thought of nothing but flight, but since then he must have bitterly regretted the impulse which caused him to drop his bird. Then, again, the introduction of his name will cause him to see it, for everyone who knows him will direct his attention to it. Here you are, Peterson, run down to the advertising agency and have this put in the evening papers." + +"In which, sir?" + +"Oh, in the Globe, Star, Pall Mall, St. James's, Evening News, Standard, Echo, and any others that occur to you." + +"Very well, sir. And this stone?" + +"Ah, yes, I shall keep the stone. Thank you. And, I say, Peterson, just buy a goose on your way back and leave it here with me, for we must have one to give to this gentleman in place of the one which your family is now devouring." + +When the commissionaire had gone, Holmes took up the stone and held it against the light. "It's a bonny thing," said he. "Just see how it glints and sparkles. Of course it is a nucleus and focus of crime. Every good stone is. They are the devil's pet baits. In the larger and older jewels every facet may stand for a bloody deed. This stone is not yet twenty years old. It was found in the banks of the Amoy River in southern China and is remarkable in having every characteristic of the carbuncle, save that it is blue in shade instead of ruby red. In spite of its youth, it has already a sinister history. There have been two murders, a vitriol-throwing, a suicide, and several robberies brought about for the sake of this forty-grain weight of crystallised charcoal. Who would think that so pretty a toy would be a purveyor to the gallows and the prison? I'll lock it up in my strong box now and drop a line to the Countess to say that we have it." + +"Do you think that this man Horner is innocent?" + +"I cannot tell." + +"Well, then, do you imagine that this other one, Henry Baker, had anything to do with the matter?" + +"It is, I think, much more likely that Henry Baker is an absolutely innocent man, who had no idea that the bird which he was carrying was of considerably more value than if it were made of solid gold. That, however, I shall determine by a very simple test if we have an answer to our advertisement." + +"And you can do nothing until then?" + +"Nothing." + +"In that case I shall continue my professional round. But I shall come back in the evening at the hour you have mentioned, for I should like to see the solution of so tangled a business." + +"Very glad to see you. I dine at seven. There is a woodcock, I believe. By the way, in view of recent occurrences, perhaps I ought to ask Mrs. Hudson to examine its crop." + +I had been delayed at a case, and it was a little after half-past six when I found myself in Baker Street once more. As I approached the house I saw a tall man in a Scotch bonnet with a coat which was buttoned up to his chin waiting outside in the bright semicircle which was thrown from the fanlight. Just as I arrived the door was opened, and we were shown up together to Holmes' room. + +"Mr. Henry Baker, I believe," said he, rising from his armchair and greeting his visitor with the easy air of geniality which he could so readily assume. "Pray take this chair by the fire, Mr. Baker. It is a cold night, and I observe that your circulation is more adapted for summer than for winter. Ah, Watson, you have just come at the right time. Is that your hat, Mr. Baker?" + +"Yes, sir, that is undoubtedly my hat." + +He was a large man with rounded shoulders, a massive head, and a broad, intelligent face, sloping down to a pointed beard of grizzled brown. A touch of red in nose and cheeks, with a slight tremor of his extended hand, recalled Holmes' surmise as to his habits. His rusty black frock-coat was buttoned right up in front, with the collar turned up, and his lank wrists protruded from his sleeves without a sign of cuff or shirt. He spoke in a slow staccato fashion, choosing his words with care, and gave the impression generally of a man of learning and letters who had had ill-usage at the hands of fortune. + +"We have retained these things for some days," said Holmes, "because we expected to see an advertisement from you giving your address. I am at a loss to know now why you did not advertise." + +Our visitor gave a rather shamefaced laugh. "Shillings have not been so plentiful with me as they once were," he remarked. "I had no doubt that the gang of roughs who assaulted me had carried off both my hat and the bird. I did not care to spend more money in a hopeless attempt at recovering them." + +"Very naturally. By the way, about the bird, we were compelled to eat it." + +"To eat it!" Our visitor half rose from his chair in his excitement. + +"Yes, it would have been of no use to anyone had we not done so. But I presume that this other goose upon the sideboard, which is about the same weight and perfectly fresh, will answer your purpose equally well?" + +"Oh, certainly, certainly," answered Mr. Baker with a sigh of relief. + +"Of course, we still have the feathers, legs, crop, and so on of your own bird, so if you wish--" + +The man burst into a hearty laugh. "They might be useful to me as relics of my adventure," said he, "but beyond that I can hardly see what use the disjecta membra of my late acquaintance are going to be to me. No, sir, I think that, with your permission, I will confine my attentions to the excellent bird which I perceive upon the sideboard." + +Sherlock Holmes glanced sharply across at me with a slight shrug of his shoulders. + +"There is your hat, then, and there your bird," said he. "By the way, would it bore you to tell me where you got the other one from? I am somewhat of a fowl fancier, and I have seldom seen a better grown goose." + +"Certainly, sir," said Baker, who had risen and tucked his newly gained property under his arm. "There are a few of us who frequent the Alpha Inn, near the Museum--we are to be found in the Museum itself during the day, you understand. This year our good host, Windigate by name, instituted a goose club, by which, on consideration of some few pence every week, we were each to receive a bird at Christmas. My pence were duly paid, and the rest is familiar to you. I am much indebted to you, sir, for a Scotch bonnet is fitted neither to my years nor my gravity." With a comical pomposity of manner he bowed solemnly to both of us and strode off upon his way. + +"So much for Mr. Henry Baker," said Holmes when he had closed the door behind him. "It is quite certain that he knows nothing whatever about the matter. Are you hungry, Watson?" + +"Not particularly." + +"Then I suggest that we turn our dinner into a supper and follow up this clue while it is still hot." + +"By all means." + +It was a bitter night, so we drew on our ulsters and wrapped cravats about our throats. Outside, the stars were shining coldly in a cloudless sky, and the breath of the passers-by blew out into smoke like so many pistol shots. Our footfalls rang out crisply and loudly as we swung through the doctors' quarter, Wimpole Street, Harley Street, and so through Wigmore Street into Oxford Street. In a quarter of an hour we were in Bloomsbury at the Alpha Inn, which is a small public-house at the corner of one of the streets which runs down into Holborn. Holmes pushed open the door of the private bar and ordered two glasses of beer from the ruddy-faced, white-aproned landlord. + +"Your beer should be excellent if it is as good as your geese," said he. + +"My geese!" The man seemed surprised. + +"Yes. I was speaking only half an hour ago to Mr. Henry Baker, who was a member of your goose club." + +"Ah! yes, I see. But you see, sir, them's not our geese." + +"Indeed! Whose, then?" + +"Well, I got the two dozen from a salesman in Covent Garden." + +"Indeed? I know some of them. Which was it?" + +"Breckinridge is his name." + +"Ah! I don't know him. Well, here's your good health landlord, and prosperity to your house. Good-night." + +"Now for Mr. Breckinridge," he continued, buttoning up his coat as we came out into the frosty air. "Remember, Watson that though we have so homely a thing as a goose at one end of this chain, we have at the other a man who will certainly get seven years' penal servitude unless we can establish his innocence. It is possible that our inquiry may but confirm his guilt; but, in any case, we have a line of investigation which has been missed by the police, and which a singular chance has placed in our hands. Let us follow it out to the bitter end. Faces to the south, then, and quick march!" + +We passed across Holborn, down Endell Street, and so through a zigzag of slums to Covent Garden Market. One of the largest stalls bore the name of Breckinridge upon it, and the proprietor a horsey-looking man, with a sharp face and trim side-whiskers was helping a boy to put up the shutters. + +"Good-evening. It's a cold night," said Holmes. + +The salesman nodded and shot a questioning glance at my companion. + +"Sold out of geese, I see," continued Holmes, pointing at the bare slabs of marble. + +"Let you have five hundred to-morrow morning." + +"That's no good." + +"Well, there are some on the stall with the gas-flare." + +"Ah, but I was recommended to you." + +"Who by?" + +"The landlord of the Alpha." + +"Oh, yes; I sent him a couple of dozen." + +"Fine birds they were, too. Now where did you get them from?" + +To my surprise the question provoked a burst of anger from the salesman. + +"Now, then, mister," said he, with his head cocked and his arms akimbo, "what are you driving at? Let's have it straight, now." + +"It is straight enough. I should like to know who sold you the geese which you supplied to the Alpha." + +"Well then, I shan't tell you. So now!" + +"Oh, it is a matter of no importance; but I don't know why you should be so warm over such a trifle." + +"Warm! You'd be as warm, maybe, if you were as pestered as I am. When I pay good money for a good article there should be an end of the business; but it's 'Where are the geese?' and 'Who did you sell the geese to?' and 'What will you take for the geese?' One would think they were the only geese in the world, to hear the fuss that is made over them." + +"Well, I have no connection with any other people who have been making inquiries," said Holmes carelessly. "If you won't tell us the bet is off, that is all. But I'm always ready to back my opinion on a matter of fowls, and I have a fiver on it that the bird I ate is country bred." + +"Well, then, you've lost your fiver, for it's town bred," snapped the salesman. + +"It's nothing of the kind." + +"I say it is." + +"I don't believe it." + +"D'you think you know more about fowls than I, who have handled them ever since I was a nipper? I tell you, all those birds that went to the Alpha were town bred." + +"You'll never persuade me to believe that." + +"Will you bet, then?" + +"It's merely taking your money, for I know that I am right. But I'll have a sovereign on with you, just to teach you not to be obstinate." + +The salesman chuckled grimly. "Bring me the books, Bill," said he. + +The small boy brought round a small thin volume and a great greasy-backed one, laying them out together beneath the hanging lamp. + +"Now then, Mr. Cocksure," said the salesman, "I thought that I was out of geese, but before I finish you'll find that there is still one left in my shop. You see this little book?" + +"Well?" + +"That's the list of the folk from whom I buy. D'you see? Well, then, here on this page are the country folk, and the numbers after their names are where their accounts are in the big ledger. Now, then! You see this other page in red ink? Well, that is a list of my town suppliers. Now, look at that third name. Just read it out to me." + +"Mrs. Oakshott, 117, Brixton Road--249," read Holmes. + +"Quite so. Now turn that up in the ledger." + +Holmes turned to the page indicated. "Here you are, 'Mrs. Oakshott, 117, Brixton Road, egg and poultry supplier.' " + +"Now, then, what's the last entry?" + +" 'December 22nd. Twenty-four geese at 7s. 6d.' " + +"Quite so. There you are. And underneath?" + +" 'Sold to Mr. Windigate of the Alpha, at 12s.' " + +"What have you to say now?" + +Sherlock Holmes looked deeply chagrined. He drew a sovereign from his pocket and threw it down upon the slab, turning away with the air of a man whose disgust is too deep for words. A few yards off he stopped under a lamp-post and laughed in the hearty, noiseless fashion which was peculiar to him. + +"When you see a man with whiskers of that cut and the 'Pink 'un' protruding out of his pocket, you can always draw him by a bet," said he. "I daresay that if I had put $100 down in front of him, that man would not have given me such complete information as was drawn from him by the idea that he was doing me on a wager. Well, Watson, we are, I fancy, nearing the end of our quest, and the only point which remains to be determined is whether we should go on to this Mrs. Oakshott to-night, or whether we should reserve it for to-morrow. It is clear from what that surly fellow said that there are others besides ourselves who are anxious about the matter, and I should--" + +His remarks were suddenly cut short by a loud hubbub which broke out from the stall which we had just left. Turning round we saw a little rat-faced fellow standing in the centre of the circle of yellow light which was thrown by the swinging lamp, while Breckinridge, the salesman, framed in the door of his stall, was shaking his fists fiercely at the cringing figure. + +"I've had enough of you and your geese," he shouted. "I wish you were all at the devil together. If you come pestering me any more with your silly talk I'll set the dog at you. You bring Mrs. Oakshott here and I'll answer her, but what have you to do with it? Did I buy the geese off you?" + +"No; but one of them was mine all the same," whined the little man. + +"Well, then, ask Mrs. Oakshott for it." + +"She told me to ask you." + +"Well, you can ask the King of Proosia, for all I care. I've had enough of it. Get out of this!" He rushed fiercely forward, and the inquirer flitted away into the darkness. + +"Ha! this may save us a visit to Brixton Road," whispered Holmes. "Come with me, and we will see what is to be made of this fellow." Striding through the scattered knots of people who lounged round the flaring stalls, my companion speedily overtook the little man and touched him upon the shoulder. He sprang round, and I could see in the gas-light that every vestige of colour had been driven from his face. + +"Who are you, then? What do you want?" he asked in a quavering voice. + +"You will excuse me," said Holmes blandly, "but I could not help overhearing the questions which you put to the salesman just now. I think that I could be of assistance to you." + +"You? Who are you? How could you know anything of the matter?" + +"My name is Sherlock Holmes. It is my business to know what other people don't know." + +"But you can know nothing of this?" + +"Excuse me, I know everything of it. You are endeavouring to trace some geese which were sold by Mrs. Oakshott, of Brixton Road, to a salesman named Breckinridge, by him in turn to Mr. Windigate, of the Alpha, and by him to his club, of which Mr. Henry Baker is a member." + +"Oh, sir, you are the very man whom I have longed to meet," cried the little fellow with outstretched hands and quivering fingers. "I can hardly explain to you how interested I am in this matter." + +Sherlock Holmes hailed a four-wheeler which was passing. "In that case we had better discuss it in a cosy room rather than in this wind-swept market-place," said he. "But pray tell me, before we go farther, who it is that I have the pleasure of assisting." + +The man hesitated for an instant. "My name is John Robinson," he answered with a sidelong glance. + +"No, no; the real name," said Holmes sweetly. "It is always awkward doing business with an alias." + +A flush sprang to the white cheeks of the stranger. "Well then," said he, "my real name is James Ryder." + +"Precisely so. Head attendant at the Hotel Cosmopolitan. Pray step into the cab, and I shall soon be able to tell you everything which you would wish to know." + +The little man stood glancing from one to the other of us with half-frightened, half-hopeful eyes, as one who is not sure whether he is on the verge of a windfall or of a catastrophe. Then he stepped into the cab, and in half an hour we were back in the sitting-room at Baker Street. Nothing had been said during our drive, but the high, thin breathing of our new companion, and the claspings and unclaspings of his hands, spoke of the nervous tension within him. + +"Here we are!" said Holmes cheerily as we filed into the room. "The fire looks very seasonable in this weather. You look cold, Mr. Ryder. Pray take the basket-chair. I will just put on my slippers before we settle this little matter of yours. Now, then! You want to know what became of those geese?" + +"Yes, sir." + +"Or rather, I fancy, of that goose. It was one bird, I imagine in which you were interested--white, with a black bar across the tail." + +Ryder quivered with emotion. "Oh, sir," he cried, "can you tell me where it went to?" + +"It came here." + +"Here?" + +"Yes, and a most remarkable bird it proved. I don't wonder that you should take an interest in it. It laid an egg after it was dead--the bonniest, brightest little blue egg that ever was seen. I have it here in my museum." + +Our visitor staggered to his feet and clutched the mantelpiece with his right hand. Holmes unlocked his strong-box and held up the blue carbuncle, which shone out like a star, with a cold, brilliant, many-pointed radiance. Ryder stood glaring with a drawn face, uncertain whether to claim or to disown it. + +"The game's up, Ryder," said Holmes quietly. "Hold up, man, or you'll be into the fire! Give him an arm back into his chair, Watson. He's not got blood enough to go in for felony with impunity. Give him a dash of brandy. So! Now he looks a little more human. What a shrimp it is, to be sure!" + +For a moment he had staggered and nearly fallen, but the brandy brought a tinge of colour into his cheeks, and he sat staring with frightened eyes at his accuser. + +"I have almost every link in my hands, and all the proofs which I could possibly need, so there is little which you need tell me. Still, that little may as well be cleared up to make the case complete. You had heard, Ryder, of this blue stone of the Countess of Morcar's?" + +"It was Catherine Cusack who told me of it," said he in a crackling voice. + +"I see--her ladyship's waiting-maid. Well, the temptation of sudden wealth so easily acquired was too much for you, as it has been for better men before you; but you were not very scrupulous in the means you used. It seems to me, Ryder, that there is the making of a very pretty villain in you. You knew that this man Horner, the plumber, had been concerned in some such matter before, and that suspicion would rest the more readily upon him. What did you do, then? You made some small job in my lady's room--you and your confederate Cusack--and you managed that he should be the man sent for. Then, when he had left, you rifled the jewel-case, raised the alarm, and had this unfortunate man arrested. You then--" + +Ryder threw himself down suddenly upon the rug and clutched at my companion's knees. "For God's sake, have mercy!" he shrieked. "Think of my father! Of my mother! It would break their hearts. I never went wrong before! I never will again. I swear it. I'll swear it on a Bible. Oh, don't bring it into court! For Christ's sake, don't!" + +"Get back into your chair!" said Holmes sternly. "It is very well to cringe and crawl now, but you thought little enough of this poor Horner in the dock for a crime of which he knew nothing." + +"I will fly, Mr. Holmes. I will leave the country, sir. Then the charge against him will break down." + +"Hum! We will talk about that. And now let us hear a true account of the next act. How came the stone into the goose, and how came the goose into the open market? Tell us the truth, for there lies your only hope of safety." + +Ryder passed his tongue over his parched lips. "I will tell you it just as it happened, sir," said he. "When Horner had been arrested, it seemed to me that it would be best for me to get away with the stone at once, for I did not know at what moment the police might not take it into their heads to search me and my room. There was no place about the hotel where it would be safe. I went out, as if on some commission, and I made for my sister's house. She had married a man named Oakshott, and lived in Brixton Road, where she fattened fowls for the market. All the way there every man I met seemed to me to be a policeman or a detective; and, for all that it was a cold night, the sweat was pouring down my face before I came to the Brixton Road. My sister asked me what was the matter, and why I was so pale; but I told her that I had been upset by the jewel robbery at the hotel. Then I went into the back yard and smoked a pipe and wondered what it would be best to do. + +"I had a friend once called Maudsley, who went to the bad, and has just been serving his time in Pentonville. One day he had met me, and fell into talk about the ways of thieves, and how they could get rid of what they stole. I knew that he would be true to me, for I knew one or two things about him; so I made up my mind to go right on to Kilburn, where he lived, and take him into my confidence. He would show me how to turn the stone into money. But how to get to him in safety? I thought of the agonies I had gone through in coming from the hotel. I might at any moment be seized and searched, and there would be the stone in my waistcoat pocket. I was leaning against the wall at the time and looking at the geese which were waddling about round my feet, and suddenly an idea came into my head which showed me how I could beat the best detective that ever lived. + +"My sister had told me some weeks before that I might have the pick of her geese for a Christmas present, and I knew that she was always as good as her word. I would take my goose now, and in it I would carry my stone to Kilburn. There was a little shed in the yard, and behind this I drove one of the birds--a fine big one, white, with a barred tail. I caught it, and prying its bill open, I thrust the stone down its throat as far as my finger could reach. The bird gave a gulp, and I felt the stone pass along its gullet and down into its crop. But the creature flapped and struggled, and out came my sister to know what was the matter. As I turned to speak to her the brute broke loose and fluttered off among the others. + +" 'Whatever were you doing with that bird, Jem?' says she. + +" 'Well,' said I, 'you said you'd give me one for Christmas, and I was feeling which was the fattest.' + +" 'Oh,' says she, 'we've set yours aside for you--Jem's bird, we call it. It's the big white one over yonder. There's twenty-six of them, which makes one for you, and one for us, and two dozen for the market.' + +" 'Thank you, Maggie,' says I; 'but if it is all the same to you, I'd rather have that one I was handling just now.' + +" 'The other is a good three pound heavier,' said she, 'and we fattened it expressly for you.' + +" 'Never mind. I'll have the other, and I'll take it now,' said I. + +" 'Oh, just as you like,' said she, a little huffed. 'Which is it you want, then?' + +" 'That white one with the barred tail, right in the middle of the flock.' + +" 'Oh, very well. Kill it and take it with you.' + +"Well, I did what she said, Mr. Holmes, and I carried the bird all the way to Kilburn. I told my pal what I had done, for he was a man that it was easy to tell a thing like that to. He laughed until he choked, and we got a knife and opened the goose. My heart turned to water, for there was no sign of the stone, and I knew that some terrible mistake had occurred. I left the bird, rushed back to my sister's, and hurried into the back yard. There was not a bird to be seen there. + +" 'Where are they all, Maggie?' I cried. + +" 'Gone to the dealer's, Jem.' + +" 'Which dealer's?' + +" 'Breckinridge, of Covent Garden.' + +" 'But was there another with a barred tail?' I asked, 'the same as the one I chose?' + +" 'Yes, Jem; there were two barred-tailed ones, and I could never tell them apart.' + +"Well, then, of course I saw it all, and I ran off as hard as my feet would carry me to this man Breckinridge; but he had sold the lot at once, and not one word would he tell me as to where they had gone. You heard him yourselves to-night. Well, he has always answered me like that. My sister thinks that I am going mad. Sometimes I think that I am myself. And now--and now I am myself a branded thief, without ever having touched the wealth for which I sold my character. God help me! God help me!" He burst into convulsive sobbing, with his face buried in his hands. + +There was a long silence, broken only by his heavy breathing and by the measured tapping of Sherlock Holmes' finger-tips upon the edge of the table. Then my friend rose and threw open the door. + +"Get out!" said he. + +"What, sir! Oh, Heaven bless you!" + +"No more words. Get out!" + +And no more words were needed. There was a rush, a clatter upon the stairs, the bang of a door, and the crisp rattle of running footfalls from the street. + +"After all, Watson," said Holmes, reaching up his hand for his clay pipe, "I am not retained by the police to supply their deficiencies. If Horner were in danger it would be another thing; but this fellow will not appear against him, and the case must collapse. I suppose that I am commuting a felony, but it is just possible that I am saving a soul. This fellow will not go wrong again; he is too terribly frightened. Send him to gaol now, and you make him a gaol-bird for life. Besides, it is the season of forgiveness. Chance has put in our way a most singular and whimsical problem, and its solution is its own reward. If you will have the goodness to touch the bell, Doctor, we will begin another investigation, in which, also a bird will be the chief feature." + +VIII. THE ADVENTURE OF THE SPECKLED BAND + + +On glancing over my notes of the seventy odd cases in which I have during the last eight years studied the methods of my friend Sherlock Holmes, I find many tragic, some comic, a large number merely strange, but none commonplace; for, working as he did rather for the love of his art than for the acquirement of wealth, he refused to associate himself with any investigation which did not tend towards the unusual, and even the fantastic. Of all these varied cases, however, I cannot recall any which presented more singular features than that which was associated with the well-known Surrey family of the Roylotts of Stoke Moran. The events in question occurred in the early days of my association with Holmes, when we were sharing rooms as bachelors in Baker Street. It is possible that I might have placed them upon record before, but a promise of secrecy was made at the time, from which I have only been freed during the last month by the untimely death of the lady to whom the pledge was given. It is perhaps as well that the facts should now come to light, for I have reasons to know that there are widespread rumours as to the death of Dr. Grimesby Roylott which tend to make the matter even more terrible than the truth. + +It was early in April in the year '83 that I woke one morning to find Sherlock Holmes standing, fully dressed, by the side of my bed. He was a late riser, as a rule, and as the clock on the mantelpiece showed me that it was only a quarter-past seven, I blinked up at him in some surprise, and perhaps just a little resentment, for I was myself regular in my habits. + +"Very sorry to knock you up, Watson," said he, "but it's the common lot this morning. Mrs. Hudson has been knocked up, she retorted upon me, and I on you." + +"What is it, then--a fire?" + +"No; a client. It seems that a young lady has arrived in a considerable state of excitement, who insists upon seeing me. She is waiting now in the sitting-room. Now, when young ladies wander about the metropolis at this hour of the morning, and knock sleepy people up out of their beds, I presume that it is something very pressing which they have to communicate. Should it prove to be an interesting case, you would, I am sure, wish to follow it from the outset. I thought, at any rate, that I should call you and give you the chance." + +"My dear fellow, I would not miss it for anything." + +I had no keener pleasure than in following Holmes in his professional investigations, and in admiring the rapid deductions, as swift as intuitions, and yet always founded on a logical basis with which he unravelled the problems which were submitted to him. I rapidly threw on my clothes and was ready in a few minutes to accompany my friend down to the sitting-room. A lady dressed in black and heavily veiled, who had been sitting in the window, rose as we entered. + +"Good-morning, madam," said Holmes cheerily. "My name is Sherlock Holmes. This is my intimate friend and associate, Dr. Watson, before whom you can speak as freely as before myself. Ha! I am glad to see that Mrs. Hudson has had the good sense to light the fire. Pray draw up to it, and I shall order you a cup of hot coffee, for I observe that you are shivering." + +"It is not cold which makes me shiver," said the woman in a low voice, changing her seat as requested. + +"What, then?" + +"It is fear, Mr. Holmes. It is terror." She raised her veil as she spoke, and we could see that she was indeed in a pitiable state of agitation, her face all drawn and grey, with restless frightened eyes, like those of some hunted animal. Her features and figure were those of a woman of thirty, but her hair was shot with premature grey, and her expression was weary and haggard. Sherlock Holmes ran her over with one of his quick, all-comprehensive glances. + +"You must not fear," said he soothingly, bending forward and patting her forearm. "We shall soon set matters right, I have no doubt. You have come in by train this morning, I see." + +"You know me, then?" + +"No, but I observe the second half of a return ticket in the palm of your left glove. You must have started early, and yet you had a good drive in a dog-cart, along heavy roads, before you reached the station." + +The lady gave a violent start and stared in bewilderment at my companion. + +"There is no mystery, my dear madam," said he, smiling. "The left arm of your jacket is spattered with mud in no less than seven places. The marks are perfectly fresh. There is no vehicle save a dog-cart which throws up mud in that way, and then only when you sit on the left-hand side of the driver." + +"Whatever your reasons may be, you are perfectly correct," said she. "I started from home before six, reached Leatherhead at twenty past, and came in by the first train to Waterloo. Sir, I can stand this strain no longer; I shall go mad if it continues. I have no one to turn to--none, save only one, who cares for me, and he, poor fellow, can be of little aid. I have heard of you, Mr. Holmes; I have heard of you from Mrs. Farintosh, whom you helped in the hour of her sore need. It was from her that I had your address. Oh, sir, do you not think that you could help me, too, and at least throw a little light through the dense darkness which surrounds me? At present it is out of my power to reward you for your services, but in a month or six weeks I shall be married, with the control of my own income, and then at least you shall not find me ungrateful." + +Holmes turned to his desk and, unlocking it, drew out a small case-book, which he consulted. + +"Farintosh," said he. "Ah yes, I recall the case; it was concerned with an opal tiara. I think it was before your time, Watson. I can only say, madam, that I shall be happy to devote the same care to your case as I did to that of your friend. As to reward, my profession is its own reward; but you are at liberty to defray whatever expenses I may be put to, at the time which suits you best. And now I beg that you will lay before us everything that may help us in forming an opinion upon the matter." + +"Alas!" replied our visitor, "the very horror of my situation lies in the fact that my fears are so vague, and my suspicions depend so entirely upon small points, which might seem trivial to another, that even he to whom of all others I have a right to look for help and advice looks upon all that I tell him about it as the fancies of a nervous woman. He does not say so, but I can read it from his soothing answers and averted eyes. But I have heard, Mr. Holmes, that you can see deeply into the manifold wickedness of the human heart. You may advise me how to walk amid the dangers which encompass me." + +"I am all attention, madam." + +"My name is Helen Stoner, and I am living with my stepfather, who is the last survivor of one of the oldest Saxon families in England, the Roylotts of Stoke Moran, on the western border of Surrey." + +Holmes nodded his head. "The name is familiar to me," said he. + +"The family was at one time among the richest in England, and the estates extended over the borders into Berkshire in the north, and Hampshire in the west. In the last century, however, four successive heirs were of a dissolute and wasteful disposition, and the family ruin was eventually completed by a gambler in the days of the Regency. Nothing was left save a few acres of ground, and the two-hundred-year-old house, which is itself crushed under a heavy mortgage. The last squire dragged out his existence there, living the horrible life of an aristocratic pauper; but his only son, my stepfather, seeing that he must adapt himself to the new conditions, obtained an advance from a relative, which enabled him to take a medical degree and went out to Calcutta, where, by his professional skill and his force of character, he established a large practice. In a fit of anger, however, caused by some robberies which had been perpetrated in the house, he beat his native butler to death and narrowly escaped a capital sentence. As it was, he suffered a long term of imprisonment and afterwards returned to England a morose and disappointed man. + +"When Dr. Roylott was in India he married my mother, Mrs. Stoner, the young widow of Major-General Stoner, of the Bengal Artillery. My sister Julia and I were twins, and we were only two years old at the time of my mother's re-marriage. She had a considerable sum of money--not less than $1000 a year--and this she bequeathed to Dr. Roylott entirely while we resided with him, with a provision that a certain annual sum should be allowed to each of us in the event of our marriage. Shortly after our return to England my mother died--she was killed eight years ago in a railway accident near Crewe. Dr. Roylott then abandoned his attempts to establish himself in practice in London and took us to live with him in the old ancestral house at Stoke Moran. The money which my mother had left was enough for all our wants, and there seemed to be no obstacle to our happiness. + +"But a terrible change came over our stepfather about this time. Instead of making friends and exchanging visits with our neighbours, who had at first been overjoyed to see a Roylott of Stoke Moran back in the old family seat, he shut himself up in his house and seldom came out save to indulge in ferocious quarrels with whoever might cross his path. Violence of temper approaching to mania has been hereditary in the men of the family, and in my stepfather's case it had, I believe, been intensified by his long residence in the tropics. A series of disgraceful brawls took place, two of which ended in the police-court, until at last he became the terror of the village, and the folks would fly at his approach, for he is a man of immense strength, and absolutely uncontrollable in his anger. + +"Last week he hurled the local blacksmith over a parapet into a stream, and it was only by paying over all the money which I could gather together that I was able to avert another public exposure. He had no friends at all save the wandering gipsies, and he would give these vagabonds leave to encamp upon the few acres of bramble-covered land which represent the family estate, and would accept in return the hospitality of their tents, wandering away with them sometimes for weeks on end. He has a passion also for Indian animals, which are sent over to him by a correspondent, and he has at this moment a cheetah and a baboon, which wander freely over his grounds and are feared by the villagers almost as much as their master. + +"You can imagine from what I say that my poor sister Julia and I had no great pleasure in our lives. No servant would stay with us, and for a long time we did all the work of the house. She was but thirty at the time of her death, and yet her hair had already begun to whiten, even as mine has." + +"Your sister is dead, then?" + +"She died just two years ago, and it is of her death that I wish to speak to you. You can understand that, living the life which I have described, we were little likely to see anyone of our own age and position. We had, however, an aunt, my mother's maiden sister, Miss Honoria Westphail, who lives near Harrow, and we were occasionally allowed to pay short visits at this lady's house. Julia went there at Christmas two years ago, and met there a half-pay major of marines, to whom she became engaged. My stepfather learned of the engagement when my sister returned and offered no objection to the marriage; but within a fortnight of the day which had been fixed for the wedding, the terrible event occurred which has deprived me of my only companion." + +Sherlock Holmes had been leaning back in his chair with his eyes closed and his head sunk in a cushion, but he half opened his lids now and glanced across at his visitor. + +"Pray be precise as to details," said he. + +"It is easy for me to be so, for every event of that dreadful time is seared into my memory. The manor-house is, as I have already said, very old, and only one wing is now inhabited. The bedrooms in this wing are on the ground floor, the sitting-rooms being in the central block of the buildings. Of these bedrooms the first is Dr. Roylott's, the second my sister's, and the third my own. There is no communication between them, but they all open out into the same corridor. Do I make myself plain?" + +"Perfectly so." + +"The windows of the three rooms open out upon the lawn. That fatal night Dr. Roylott had gone to his room early, though we knew that he had not retired to rest, for my sister was troubled by the smell of the strong Indian cigars which it was his custom to smoke. She left her room, therefore, and came into mine, where she sat for some time, chatting about her approaching wedding. At eleven o'clock she rose to leave me, but she paused at the door and looked back. + +" 'Tell me, Helen,' said she, 'have you ever heard anyone whistle in the dead of the night?' + +" 'Never,' said I. + +" 'I suppose that you could not possibly whistle, yourself, in your sleep?' + +" 'Certainly not. But why?' + +" 'Because during the last few nights I have always, about three in the morning, heard a low, clear whistle. I am a light sleeper, and it has awakened me. I cannot tell where it came from--perhaps from the next room, perhaps from the lawn. I thought that I would just ask you whether you had heard it.' + +" 'No, I have not. It must be those wretched gipsies in the plantation.' + +" 'Very likely. And yet if it were on the lawn, I wonder that you did not hear it also.' + +" 'Ah, but I sleep more heavily than you.' + +" 'Well, it is of no great consequence, at any rate.' She smiled back at me, closed my door, and a few moments later I heard her key turn in the lock." + +"Indeed," said Holmes. "Was it your custom always to lock yourselves in at night?" + +"Always." + +"And why?" + +"I think that I mentioned to you that the doctor kept a cheetah and a baboon. We had no feeling of security unless our doors were locked." + +"Quite so. Pray proceed with your statement." + +"I could not sleep that night. A vague feeling of impending misfortune impressed me. My sister and I, you will recollect, were twins, and you know how subtle are the links which bind two souls which are so closely allied. It was a wild night. The wind was howling outside, and the rain was beating and splashing against the windows. Suddenly, amid all the hubbub of the gale, there burst forth the wild scream of a terrified woman. I knew that it was my sister's voice. I sprang from my bed, wrapped a shawl round me, and rushed into the corridor. As I opened my door I seemed to hear a low whistle, such as my sister described, and a few moments later a clanging sound, as if a mass of metal had fallen. As I ran down the passage, my sister's door was unlocked, and revolved slowly upon its hinges. I stared at it horror-stricken, not knowing what was about to issue from it. By the light of the corridor-lamp I saw my sister appear at the opening, her face blanched with terror, her hands groping for help, her whole figure swaying to and fro like that of a drunkard. I ran to her and threw my arms round her, but at that moment her knees seemed to give way and she fell to the ground. She writhed as one who is in terrible pain, and her limbs were dreadfully convulsed. At first I thought that she had not recognised me, but as I bent over her she suddenly shrieked out in a voice which I shall never forget, 'Oh, my God! Helen! It was the band! The speckled band!' There was something else which she would fain have said, and she stabbed with her finger into the air in the direction of the doctor's room, but a fresh convulsion seized her and choked her words. I rushed out, calling loudly for my stepfather, and I met him hastening from his room in his dressing-gown. When he reached my sister's side she was unconscious, and though he poured brandy down her throat and sent for medical aid from the village, all efforts were in vain, for she slowly sank and died without having recovered her consciousness. Such was the dreadful end of my beloved sister." + +"One moment," said Holmes, "are you sure about this whistle and metallic sound? Could you swear to it?" + +"That was what the county coroner asked me at the inquiry. It is my strong impression that I heard it, and yet, among the crash of the gale and the creaking of an old house, I may possibly have been deceived." + +"Was your sister dressed?" + +"No, she was in her night-dress. In her right hand was found the charred stump of a match, and in her left a match-box." + +"Showing that she had struck a light and looked about her when the alarm took place. That is important. And what conclusions did the coroner come to?" + +"He investigated the case with great care, for Dr. Roylott's conduct had long been notorious in the county, but he was unable to find any satisfactory cause of death. My evidence showed that the door had been fastened upon the inner side, and the windows were blocked by old-fashioned shutters with broad iron bars, which were secured every night. The walls were carefully sounded, and were shown to be quite solid all round, and the flooring was also thoroughly examined, with the same result. The chimney is wide, but is barred up by four large staples. It is certain, therefore, that my sister was quite alone when she met her end. Besides, there were no marks of any violence upon her." + +"How about poison?" + +"The doctors examined her for it, but without success." + +"What do you think that this unfortunate lady died of, then?" + +"It is my belief that she died of pure fear and nervous shock, though what it was that frightened her I cannot imagine." + +"Were there gipsies in the plantation at the time?" + +"Yes, there are nearly always some there." + +"Ah, and what did you gather from this allusion to a band--a speckled band?" + +"Sometimes I have thought that it was merely the wild talk of delirium, sometimes that it may have referred to some band of people, perhaps to these very gipsies in the plantation. I do not know whether the spotted handkerchiefs which so many of them wear over their heads might have suggested the strange adjective which she used." + +Holmes shook his head like a man who is far from being satisfied. + +"These are very deep waters," said he; "pray go on with your narrative." + +"Two years have passed since then, and my life has been until lately lonelier than ever. A month ago, however, a dear friend, whom I have known for many years, has done me the honour to ask my hand in marriage. His name is Armitage--Percy Armitage--the second son of Mr. Armitage, of Crane Water, near Reading. My stepfather has offered no opposition to the match, and we are to be married in the course of the spring. Two days ago some repairs were started in the west wing of the building, and my bedroom wall has been pierced, so that I have had to move into the chamber in which my sister died, and to sleep in the very bed in which she slept. Imagine, then, my thrill of terror when last night, as I lay awake, thinking over her terrible fate, I suddenly heard in the silence of the night the low whistle which had been the herald of her own death. I sprang up and lit the lamp, but nothing was to be seen in the room. I was too shaken to go to bed again, however, so I dressed, and as soon as it was daylight I slipped down, got a dog-cart at the Crown Inn, which is opposite, and drove to Leatherhead, from whence I have come on this morning with the one object of seeing you and asking your advice." + +"You have done wisely," said my friend. "But have you told me all?" + +"Yes, all." + +"Miss Roylott, you have not. You are screening your stepfather." + +"Why, what do you mean?" + +For answer Holmes pushed back the frill of black lace which fringed the hand that lay upon our visitor's knee. Five little livid spots, the marks of four fingers and a thumb, were printed upon the white wrist. + +"You have been cruelly used," said Holmes. + +The lady coloured deeply and covered over her injured wrist. "He is a hard man," she said, "and perhaps he hardly knows his own strength." + +There was a long silence, during which Holmes leaned his chin upon his hands and stared into the crackling fire. + +"This is a very deep business," he said at last. "There are a thousand details which I should desire to know before I decide upon our course of action. Yet we have not a moment to lose. If we were to come to Stoke Moran to-day, would it be possible for us to see over these rooms without the knowledge of your stepfather?" + +"As it happens, he spoke of coming into town to-day upon some most important business. It is probable that he will be away all day, and that there would be nothing to disturb you. We have a housekeeper now, but she is old and foolish, and I could easily get her out of the way." + +"Excellent. You are not averse to this trip, Watson?" + +"By no means." + +"Then we shall both come. What are you going to do yourself?" + +"I have one or two things which I would wish to do now that I am in town. But I shall return by the twelve o'clock train, so as to be there in time for your coming." + +"And you may expect us early in the afternoon. I have myself some small business matters to attend to. Will you not wait and breakfast?" + +"No, I must go. My heart is lightened already since I have confided my trouble to you. I shall look forward to seeing you again this afternoon." She dropped her thick black veil over her face and glided from the room. + +"And what do you think of it all, Watson?" asked Sherlock Holmes, leaning back in his chair. + +"It seems to me to be a most dark and sinister business." + +"Dark enough and sinister enough." + +"Yet if the lady is correct in saying that the flooring and walls are sound, and that the door, window, and chimney are impassable, then her sister must have been undoubtedly alone when she met her mysterious end." + +"What becomes, then, of these nocturnal whistles, and what of the very peculiar words of the dying woman?" + +"I cannot think." + +"When you combine the ideas of whistles at night, the presence of a band of gipsies who are on intimate terms with this old doctor, the fact that we have every reason to believe that the doctor has an interest in preventing his stepdaughter's marriage, the dying allusion to a band, and, finally, the fact that Miss Helen Stoner heard a metallic clang, which might have been caused by one of those metal bars that secured the shutters falling back into its place, I think that there is good ground to think that the mystery may be cleared along those lines." + +"But what, then, did the gipsies do?" + +"I cannot imagine." + +"I see many objections to any such theory." + +"And so do I. It is precisely for that reason that we are going to Stoke Moran this day. I want to see whether the objections are fatal, or if they may be explained away. But what in the name of the devil!" + +The ejaculation had been drawn from my companion by the fact that our door had been suddenly dashed open, and that a huge man had framed himself in the aperture. His costume was a peculiar mixture of the professional and of the agricultural, having a black top-hat, a long frock-coat, and a pair of high gaiters, with a hunting-crop swinging in his hand. So tall was he that his hat actually brushed the cross bar of the doorway, and his breadth seemed to span it across from side to side. A large face, seared with a thousand wrinkles, burned yellow with the sun, and marked with every evil passion, was turned from one to the other of us, while his deep-set, bile-shot eyes, and his high, thin, fleshless nose, gave him somewhat the resemblance to a fierce old bird of prey. + +"Which of you is Holmes?" asked this apparition. + +"My name, sir; but you have the advantage of me," said my companion quietly. + +"I am Dr. Grimesby Roylott, of Stoke Moran." + +"Indeed, Doctor," said Holmes blandly. "Pray take a seat." + +"I will do nothing of the kind. My stepdaughter has been here. I have traced her. What has she been saying to you?" + +"It is a little cold for the time of the year," said Holmes. + +"What has she been saying to you?" screamed the old man furiously. + +"But I have heard that the crocuses promise well," continued my companion imperturbably. + +"Ha! You put me off, do you?" said our new visitor, taking a step forward and shaking his hunting-crop. "I know you, you scoundrel! I have heard of you before. You are Holmes, the meddler." + +My friend smiled. + +"Holmes, the busybody!" + +His smile broadened. + +"Holmes, the Scotland Yard Jack-in-office!" + +Holmes chuckled heartily. "Your conversation is most entertaining," said he. "When you go out close the door, for there is a decided draught." + +"I will go when I have said my say. Don't you dare to meddle with my affairs. I know that Miss Stoner has been here. I traced her! I am a dangerous man to fall foul of! See here." He stepped swiftly forward, seized the poker, and bent it into a curve with his huge brown hands. + +"See that you keep yourself out of my grip," he snarled, and hurling the twisted poker into the fireplace he strode out of the room. + +"He seems a very amiable person," said Holmes, laughing. "I am not quite so bulky, but if he had remained I might have shown him that my grip was not much more feeble than his own." As he spoke he picked up the steel poker and, with a sudden effort, straightened it out again. + +"Fancy his having the insolence to confound me with the official detective force! This incident gives zest to our investigation, however, and I only trust that our little friend will not suffer from her imprudence in allowing this brute to trace her. And now, Watson, we shall order breakfast, and afterwards I shall walk down to Doctors' Commons, where I hope to get some data which may help us in this matter." + +It was nearly one o'clock when Sherlock Holmes returned from his excursion. He held in his hand a sheet of blue paper, scrawled over with notes and figures. + +"I have seen the will of the deceased wife," said he. "To determine its exact meaning I have been obliged to work out the present prices of the investments with which it is concerned. The total income, which at the time of the wife's death was little short of $1100, is now, through the fall in agricultural prices, not more than $750. Each daughter can claim an income of $250, in case of marriage. It is evident, therefore, that if both girls had married, this beauty would have had a mere pittance, while even one of them would cripple him to a very serious extent. My morning's work has not been wasted, since it has proved that he has the very strongest motives for standing in the way of anything of the sort. And now, Watson, this is too serious for dawdling, especially as the old man is aware that we are interesting ourselves in his affairs; so if you are ready, we shall call a cab and drive to Waterloo. I should be very much obliged if you would slip your revolver into your pocket. An Eley's No. 2 is an excellent argument with gentlemen who can twist steel pokers into knots. That and a tooth-brush are, I think, all that we need." + +At Waterloo we were fortunate in catching a train for Leatherhead, where we hired a trap at the station inn and drove for four or five miles through the lovely Surrey lanes. It was a perfect day, with a bright sun and a few fleecy clouds in the heavens. The trees and wayside hedges were just throwing out their first green shoots, and the air was full of the pleasant smell of the moist earth. To me at least there was a strange contrast between the sweet promise of the spring and this sinister quest upon which we were engaged. My companion sat in the front of the trap, his arms folded, his hat pulled down over his eyes, and his chin sunk upon his breast, buried in the deepest thought. Suddenly, however, he started, tapped me on the shoulder, and pointed over the meadows. + +"Look there!" said he. + +A heavily timbered park stretched up in a gentle slope, thickening into a grove at the highest point. From amid the branches there jutted out the grey gables and high roof-tree of a very old mansion. + +"Stoke Moran?" said he. + +"Yes, sir, that be the house of Dr. Grimesby Roylott," remarked the driver. + +"There is some building going on there," said Holmes; "that is where we are going." + +"There's the village," said the driver, pointing to a cluster of roofs some distance to the left; "but if you want to get to the house, you'll find it shorter to get over this stile, and so by the foot-path over the fields. There it is, where the lady is walking." + +"And the lady, I fancy, is Miss Stoner," observed Holmes, shading his eyes. "Yes, I think we had better do as you suggest." + +We got off, paid our fare, and the trap rattled back on its way to Leatherhead. + +"I thought it as well," said Holmes as we climbed the stile, "that this fellow should think we had come here as architects, or on some definite business. It may stop his gossip. Good-afternoon, Miss Stoner. You see that we have been as good as our word." + +Our client of the morning had hurried forward to meet us with a face which spoke her joy. "I have been waiting so eagerly for you," she cried, shaking hands with us warmly. "All has turned out splendidly. Dr. Roylott has gone to town, and it is unlikely that he will be back before evening." + +"We have had the pleasure of making the doctor's acquaintance," said Holmes, and in a few words he sketched out what had occurred. Miss Stoner turned white to the lips as she listened. + +"Good heavens!" she cried, "he has followed me, then." + +"So it appears." + +"He is so cunning that I never know when I am safe from him. What will he say when he returns?" + +"He must guard himself, for he may find that there is someone more cunning than himself upon his track. You must lock yourself up from him to-night. If he is violent, we shall take you away to your aunt's at Harrow. Now, we must make the best use of our time, so kindly take us at once to the rooms which we are to examine." + +The building was of grey, lichen-blotched stone, with a high central portion and two curving wings, like the claws of a crab, thrown out on each side. In one of these wings the windows were broken and blocked with wooden boards, while the roof was partly caved in, a picture of ruin. The central portion was in little better repair, but the right-hand block was comparatively modern, and the blinds in the windows, with the blue smoke curling up from the chimneys, showed that this was where the family resided. Some scaffolding had been erected against the end wall, and the stone-work had been broken into, but there were no signs of any workmen at the moment of our visit. Holmes walked slowly up and down the ill-trimmed lawn and examined with deep attention the outsides of the windows. + +"This, I take it, belongs to the room in which you used to sleep, the centre one to your sister's, and the one next to the main building to Dr. Roylott's chamber?" + +"Exactly so. But I am now sleeping in the middle one." + +"Pending the alterations, as I understand. By the way, there does not seem to be any very pressing need for repairs at that end wall." + +"There were none. I believe that it was an excuse to move me from my room." + +"Ah! that is suggestive. Now, on the other side of this narrow wing runs the corridor from which these three rooms open. There are windows in it, of course?" + +"Yes, but very small ones. Too narrow for anyone to pass through." + +"As you both locked your doors at night, your rooms were unapproachable from that side. Now, would you have the kindness to go into your room and bar your shutters?" + +Miss Stoner did so, and Holmes, after a careful examination through the open window, endeavoured in every way to force the shutter open, but without success. There was no slit through which a knife could be passed to raise the bar. Then with his lens he tested the hinges, but they were of solid iron, built firmly into the massive masonry. "Hum!" said he, scratching his chin in some perplexity, "my theory certainly presents some difficulties. No one could pass these shutters if they were bolted. Well, we shall see if the inside throws any light upon the matter." + +A small side door led into the whitewashed corridor from which the three bedrooms opened. Holmes refused to examine the third chamber, so we passed at once to the second, that in which Miss Stoner was now sleeping, and in which her sister had met with her fate. It was a homely little room, with a low ceiling and a gaping fireplace, after the fashion of old country-houses. A brown chest of drawers stood in one corner, a narrow white-counterpaned bed in another, and a dressing-table on the left-hand side of the window. These articles, with two small wicker-work chairs, made up all the furniture in the room save for a square of Wilton carpet in the centre. The boards round and the panelling of the walls were of brown, worm-eaten oak, so old and discoloured that it may have dated from the original building of the house. Holmes drew one of the chairs into a corner and sat silent, while his eyes travelled round and round and up and down, taking in every detail of the apartment. + +"Where does that bell communicate with?" he asked at last pointing to a thick bell-rope which hung down beside the bed, the tassel actually lying upon the pillow. + +"It goes to the housekeeper's room." + +"It looks newer than the other things?" + +"Yes, it was only put there a couple of years ago." + +"Your sister asked for it, I suppose?" + +"No, I never heard of her using it. We used always to get what we wanted for ourselves." + +"Indeed, it seemed unnecessary to put so nice a bell-pull there. You will excuse me for a few minutes while I satisfy myself as to this floor." He threw himself down upon his face with his lens in his hand and crawled swiftly backward and forward, examining minutely the cracks between the boards. Then he did the same with the wood-work with which the chamber was panelled. Finally he walked over to the bed and spent some time in staring at it and in running his eye up and down the wall. Finally he took the bell-rope in his hand and gave it a brisk tug. + +"Why, it's a dummy," said he. + +"Won't it ring?" + +"No, it is not even attached to a wire. This is very interesting. You can see now that it is fastened to a hook just above where the little opening for the ventilator is." + +"How very absurd! I never noticed that before." + +"Very strange!" muttered Holmes, pulling at the rope. "There are one or two very singular points about this room. For example, what a fool a builder must be to open a ventilator into another room, when, with the same trouble, he might have communicated with the outside air!" + +"That is also quite modern," said the lady. + +"Done about the same time as the bell-rope?" remarked Holmes. + +"Yes, there were several little changes carried out about that time." + +"They seem to have been of a most interesting character--dummy bell-ropes, and ventilators which do not ventilate. With your permission, Miss Stoner, we shall now carry our researches into the inner apartment." + +Dr. Grimesby Roylott's chamber was larger than that of his step-daughter, but was as plainly furnished. A camp-bed, a small wooden shelf full of books, mostly of a technical character, an armchair beside the bed, a plain wooden chair against the wall, a round table, and a large iron safe were the principal things which met the eye. Holmes walked slowly round and examined each and all of them with the keenest interest. + +"What's in here?" he asked, tapping the safe. + +"My stepfather's business papers." + +"Oh! you have seen inside, then?" + +"Only once, some years ago. I remember that it was full of papers." + +"There isn't a cat in it, for example?" + +"No. What a strange idea!" + +"Well, look at this!" He took up a small saucer of milk which stood on the top of it. + +"No; we don't keep a cat. But there is a cheetah and a baboon." + +"Ah, yes, of course! Well, a cheetah is just a big cat, and yet a saucer of milk does not go very far in satisfying its wants, I daresay. There is one point which I should wish to determine." He squatted down in front of the wooden chair and examined the seat of it with the greatest attention. + +"Thank you. That is quite settled," said he, rising and putting his lens in his pocket. "Hullo! Here is something interesting!" + +The object which had caught his eye was a small dog lash hung on one corner of the bed. The lash, however, was curled upon itself and tied so as to make a loop of whipcord. + +"What do you make of that, Watson?" + +"It's a common enough lash. But I don't know why it should be tied." + +"That is not quite so common, is it? Ah, me! it's a wicked world, and when a clever man turns his brains to crime it is the worst of all. I think that I have seen enough now, Miss Stoner, and with your permission we shall walk out upon the lawn." + +I had never seen my friend's face so grim or his brow so dark as it was when we turned from the scene of this investigation. We had walked several times up and down the lawn, neither Miss Stoner nor myself liking to break in upon his thoughts before he roused himself from his reverie. + +"It is very essential, Miss Stoner," said he, "that you should absolutely follow my advice in every respect." + +"I shall most certainly do so." + +"The matter is too serious for any hesitation. Your life may depend upon your compliance." + +"I assure you that I am in your hands." + +"In the first place, both my friend and I must spend the night in your room." + +Both Miss Stoner and I gazed at him in astonishment. + +"Yes, it must be so. Let me explain. I believe that that is the village inn over there?" + +"Yes, that is the Crown." + +"Very good. Your windows would be visible from there?" + +"Certainly." + +"You must confine yourself to your room, on pretence of a headache, when your stepfather comes back. Then when you hear him retire for the night, you must open the shutters of your window, undo the hasp, put your lamp there as a signal to us, and then withdraw quietly with everything which you are likely to want into the room which you used to occupy. I have no doubt that, in spite of the repairs, you could manage there for one night." + +"Oh, yes, easily." + +"The rest you will leave in our hands." + +"But what will you do?" + +"We shall spend the night in your room, and we shall investigate the cause of this noise which has disturbed you." + +"I believe, Mr. Holmes, that you have already made up your mind," said Miss Stoner, laying her hand upon my companion's sleeve. + +"Perhaps I have." + +"Then, for pity's sake, tell me what was the cause of my sister's death." + +"I should prefer to have clearer proofs before I speak." + +"You can at least tell me whether my own thought is correct, and if she died from some sudden fright." + +"No, I do not think so. I think that there was probably some more tangible cause. And now, Miss Stoner, we must leave you for if Dr. Roylott returned and saw us our journey would be in vain. Good-bye, and be brave, for if you will do what I have told you, you may rest assured that we shall soon drive away the dangers that threaten you." + +Sherlock Holmes and I had no difficulty in engaging a bedroom and sitting-room at the Crown Inn. They were on the upper floor, and from our window we could command a view of the avenue gate, and of the inhabited wing of Stoke Moran Manor House. At dusk we saw Dr. Grimesby Roylott drive past, his huge form looming up beside the little figure of the lad who drove him. The boy had some slight difficulty in undoing the heavy iron gates, and we heard the hoarse roar of the doctor's voice and saw the fury with which he shook his clinched fists at him. The trap drove on, and a few minutes later we saw a sudden light spring up among the trees as the lamp was lit in one of the sitting-rooms. + +"Do you know, Watson," said Holmes as we sat together in the gathering darkness, "I have really some scruples as to taking you to-night. There is a distinct element of danger." + +"Can I be of assistance?" + +"Your presence might be invaluable." + +"Then I shall certainly come." + +"It is very kind of you." + +"You speak of danger. You have evidently seen more in these rooms than was visible to me." + +"No, but I fancy that I may have deduced a little more. I imagine that you saw all that I did." + +"I saw nothing remarkable save the bell-rope, and what purpose that could answer I confess is more than I can imagine." + +"You saw the ventilator, too?" + +"Yes, but I do not think that it is such a very unusual thing to have a small opening between two rooms. It was so small that a rat could hardly pass through." + +"I knew that we should find a ventilator before ever we came to Stoke Moran." + +"My dear Holmes!" + +"Oh, yes, I did. You remember in her statement she said that her sister could smell Dr. Roylott's cigar. Now, of course that suggested at once that there must be a communication between the two rooms. It could only be a small one, or it would have been remarked upon at the coroner's inquiry. I deduced a ventilator." + +"But what harm can there be in that?" + +"Well, there is at least a curious coincidence of dates. A ventilator is made, a cord is hung, and a lady who sleeps in the bed dies. Does not that strike you?" + +"I cannot as yet see any connection." + +"Did you observe anything very peculiar about that bed?" + +"No." + +"It was clamped to the floor. Did you ever see a bed fastened like that before?" + +"I cannot say that I have." + +"The lady could not move her bed. It must always be in the same relative position to the ventilator and to the rope--or so we may call it, since it was clearly never meant for a bell-pull." + +"Holmes," I cried, "I seem to see dimly what you are hinting at. We are only just in time to prevent some subtle and horrible crime." + +"Subtle enough and horrible enough. When a doctor does go wrong he is the first of criminals. He has nerve and he has knowledge. Palmer and Pritchard were among the heads of their profession. This man strikes even deeper, but I think, Watson, that we shall be able to strike deeper still. But we shall have horrors enough before the night is over; for goodness' sake let us have a quiet pipe and turn our minds for a few hours to something more cheerful." + +About nine o'clock the light among the trees was extinguished, and all was dark in the direction of the Manor House. Two hours passed slowly away, and then, suddenly, just at the stroke of eleven, a single bright light shone out right in front of us. + +"That is our signal," said Holmes, springing to his feet; "it comes from the middle window." + +As we passed out he exchanged a few words with the landlord, explaining that we were going on a late visit to an acquaintance, and that it was possible that we might spend the night there. A moment later we were out on the dark road, a chill wind blowing in our faces, and one yellow light twinkling in front of us through the gloom to guide us on our sombre errand. + +There was little difficulty in entering the grounds, for unrepaired breaches gaped in the old park wall. Making our way among the trees, we reached the lawn, crossed it, and were about to enter through the window when out from a clump of laurel bushes there darted what seemed to be a hideous and distorted child, who threw itself upon the grass with writhing limbs and then ran swiftly across the lawn into the darkness. + +"My God!" I whispered; "did you see it?" + +Holmes was for the moment as startled as I. His hand closed like a vice upon my wrist in his agitation. Then he broke into a low laugh and put his lips to my ear. + +"It is a nice household," he murmured. "That is the baboon." + +I had forgotten the strange pets which the doctor affected. There was a cheetah, too; perhaps we might find it upon our shoulders at any moment. I confess that I felt easier in my mind when, after following Holmes' example and slipping off my shoes, I found myself inside the bedroom. My companion noiselessly closed the shutters, moved the lamp onto the table, and cast his eyes round the room. All was as we had seen it in the daytime. Then creeping up to me and making a trumpet of his hand, he whispered into my ear again so gently that it was all that I could do to distinguish the words: + +"The least sound would be fatal to our plans." + +I nodded to show that I had heard. + +"We must sit without light. He would see it through the ventilator." + +I nodded again. + +"Do not go asleep; your very life may depend upon it. Have your pistol ready in case we should need it. I will sit on the side of the bed, and you in that chair." + +I took out my revolver and laid it on the corner of the table. + +Holmes had brought up a long thin cane, and this he placed upon the bed beside him. By it he laid the box of matches and the stump of a candle. Then he turned down the lamp, and we were left in darkness. + +How shall I ever forget that dreadful vigil? I could not hear a sound, not even the drawing of a breath, and yet I knew that my companion sat open-eyed, within a few feet of me, in the same state of nervous tension in which I was myself. The shutters cut off the least ray of light, and we waited in absolute darkness. + +From outside came the occasional cry of a night-bird, and once at our very window a long drawn catlike whine, which told us that the cheetah was indeed at liberty. Far away we could hear the deep tones of the parish clock, which boomed out every quarter of an hour. How long they seemed, those quarters! Twelve struck, and one and two and three, and still we sat waiting silently for whatever might befall. + +Suddenly there was the momentary gleam of a light up in the direction of the ventilator, which vanished immediately, but was succeeded by a strong smell of burning oil and heated metal. Someone in the next room had lit a dark-lantern. I heard a gentle sound of movement, and then all was silent once more, though the smell grew stronger. For half an hour I sat with straining ears. Then suddenly another sound became audible--a very gentle, soothing sound, like that of a small jet of steam escaping continually from a kettle. The instant that we heard it, Holmes sprang from the bed, struck a match, and lashed furiously with his cane at the bell-pull. + +"You see it, Watson?" he yelled. "You see it?" + +But I saw nothing. At the moment when Holmes struck the light I heard a low, clear whistle, but the sudden glare flashing into my weary eyes made it impossible for me to tell what it was at which my friend lashed so savagely. I could, however, see that his face was deadly pale and filled with horror and loathing. He had ceased to strike and was gazing up at the ventilator when suddenly there broke from the silence of the night the most horrible cry to which I have ever listened. It swelled up louder and louder, a hoarse yell of pain and fear and anger all mingled in the one dreadful shriek. They say that away down in the village, and even in the distant parsonage, that cry raised the sleepers from their beds. It struck cold to our hearts, and I stood gazing at Holmes, and he at me, until the last echoes of it had died away into the silence from which it rose. + +"What can it mean?" I gasped. + +"It means that it is all over," Holmes answered. "And perhaps, after all, it is for the best. Take your pistol, and we will enter Dr. Roylott's room." + +With a grave face he lit the lamp and led the way down the corridor. Twice he struck at the chamber door without any reply from within. Then he turned the handle and entered, I at his heels, with the cocked pistol in my hand. + +It was a singular sight which met our eyes. On the table stood a dark-lantern with the shutter half open, throwing a brilliant beam of light upon the iron safe, the door of which was ajar. Beside this table, on the wooden chair, sat Dr. Grimesby Roylott clad in a long grey dressing-gown, his bare ankles protruding beneath, and his feet thrust into red heelless Turkish slippers. Across his lap lay the short stock with the long lash which we had noticed during the day. His chin was cocked upward and his eyes were fixed in a dreadful, rigid stare at the corner of the ceiling. Round his brow he had a peculiar yellow band, with brownish speckles, which seemed to be bound tightly round his head. As we entered he made neither sound nor motion. + +"The band! the speckled band!" whispered Holmes. + +I took a step forward. In an instant his strange headgear began to move, and there reared itself from among his hair the squat diamond-shaped head and puffed neck of a loathsome serpent. + +"It is a swamp adder!" cried Holmes; "the deadliest snake in India. He has died within ten seconds of being bitten. Violence does, in truth, recoil upon the violent, and the schemer falls into the pit which he digs for another. Let us thrust this creature back into its den, and we can then remove Miss Stoner to some place of shelter and let the county police know what has happened." + +As he spoke he drew the dog-whip swiftly from the dead man's lap, and throwing the noose round the reptile's neck he drew it from its horrid perch and, carrying it at arm's length, threw it into the iron safe, which he closed upon it. + +Such are the true facts of the death of Dr. Grimesby Roylott, of Stoke Moran. It is not necessary that I should prolong a narrative which has already run to too great a length by telling how we broke the sad news to the terrified girl, how we conveyed her by the morning train to the care of her good aunt at Harrow, of how the slow process of official inquiry came to the conclusion that the doctor met his fate while indiscreetly playing with a dangerous pet. The little which I had yet to learn of the case was told me by Sherlock Holmes as we travelled back next day. + +"I had," said he, "come to an entirely erroneous conclusion which shows, my dear Watson, how dangerous it always is to reason from insufficient data. The presence of the gipsies, and the use of the word 'band,' which was used by the poor girl, no doubt, to explain the appearance which she had caught a hurried glimpse of by the light of her match, were sufficient to put me upon an entirely wrong scent. I can only claim the merit that I instantly reconsidered my position when, however, it became clear to me that whatever danger threatened an occupant of the room could not come either from the window or the door. My attention was speedily drawn, as I have already remarked to you, to this ventilator, and to the bell-rope which hung down to the bed. The discovery that this was a dummy, and that the bed was clamped to the floor, instantly gave rise to the suspicion that the rope was there as a bridge for something passing through the hole and coming to the bed. The idea of a snake instantly occurred to me, and when I coupled it with my knowledge that the doctor was furnished with a supply of creatures from India, I felt that I was probably on the right track. The idea of using a form of poison which could not possibly be discovered by any chemical test was just such a one as would occur to a clever and ruthless man who had had an Eastern training. The rapidity with which such a poison would take effect would also, from his point of view, be an advantage. It would be a sharp-eyed coroner, indeed, who could distinguish the two little dark punctures which would show where the poison fangs had done their work. Then I thought of the whistle. Of course he must recall the snake before the morning light revealed it to the victim. He had trained it, probably by the use of the milk which we saw, to return to him when summoned. He would put it through this ventilator at the hour that he thought best, with the certainty that it would crawl down the rope and land on the bed. It might or might not bite the occupant, perhaps she might escape every night for a week, but sooner or later she must fall a victim. + +"I had come to these conclusions before ever I had entered his room. An inspection of his chair showed me that he had been in the habit of standing on it, which of course would be necessary in order that he should reach the ventilator. The sight of the safe, the saucer of milk, and the loop of whipcord were enough to finally dispel any doubts which may have remained. The metallic clang heard by Miss Stoner was obviously caused by her stepfather hastily closing the door of his safe upon its terrible occupant. Having once made up my mind, you know the steps which I took in order to put the matter to the proof. I heard the creature hiss as I have no doubt that you did also, and I instantly lit the light and attacked it." + +"With the result of driving it through the ventilator." + +"And also with the result of causing it to turn upon its master at the other side. Some of the blows of my cane came home and roused its snakish temper, so that it flew upon the first person it saw. In this way I am no doubt indirectly responsible for Dr. Grimesby Roylott's death, and I cannot say that it is likely to weigh very heavily upon my conscience." + +IX. THE ADVENTURE OF THE ENGINEER'S THUMB + + +Of all the problems which have been submitted to my friend, Mr. Sherlock Holmes, for solution during the years of our intimacy, there were only two which I was the means of introducing to his notice--that of Mr. Hatherley's thumb, and that of Colonel Warburton's madness. Of these the latter may have afforded a finer field for an acute and original observer, but the other was so strange in its inception and so dramatic in its details that it may be the more worthy of being placed upon record, even if it gave my friend fewer openings for those deductive methods of reasoning by which he achieved such remarkable results. The story has, I believe, been told more than once in the newspapers, but, like all such narratives, its effect is much less striking when set forth en bloc in a single half-column of print than when the facts slowly evolve before your own eyes, and the mystery clears gradually away as each new discovery furnishes a step which leads on to the complete truth. At the time the circumstances made a deep impression upon me, and the lapse of two years has hardly served to weaken the effect. + +It was in the summer of '89, not long after my marriage, that the events occurred which I am now about to summarise. I had returned to civil practice and had finally abandoned Holmes in his Baker Street rooms, although I continually visited him and occasionally even persuaded him to forgo his Bohemian habits so far as to come and visit us. My practice had steadily increased, and as I happened to live at no very great distance from Paddington Station, I got a few patients from among the officials. One of these, whom I had cured of a painful and lingering disease, was never weary of advertising my virtues and of endeavouring to send me on every sufferer over whom he might have any influence. + +One morning, at a little before seven o'clock, I was awakened by the maid tapping at the door to announce that two men had come from Paddington and were waiting in the consulting-room. I dressed hurriedly, for I knew by experience that railway cases were seldom trivial, and hastened downstairs. As I descended, my old ally, the guard, came out of the room and closed the door tightly behind him. + +"I've got him here," he whispered, jerking his thumb over his shoulder; "he's all right." + +"What is it, then?" I asked, for his manner suggested that it was some strange creature which he had caged up in my room. + +"It's a new patient," he whispered. "I thought I'd bring him round myself; then he couldn't slip away. There he is, all safe and sound. I must go now, Doctor; I have my dooties, just the same as you." And off he went, this trusty tout, without even giving me time to thank him. + +I entered my consulting-room and found a gentleman seated by the table. He was quietly dressed in a suit of heather tweed with a soft cloth cap which he had laid down upon my books. Round one of his hands he had a handkerchief wrapped, which was mottled all over with bloodstains. He was young, not more than five-and-twenty, I should say, with a strong, masculine face; but he was exceedingly pale and gave me the impression of a man who was suffering from some strong agitation, which it took all his strength of mind to control. + +"I am sorry to knock you up so early, Doctor," said he, "but I have had a very serious accident during the night. I came in by train this morning, and on inquiring at Paddington as to where I might find a doctor, a worthy fellow very kindly escorted me here. I gave the maid a card, but I see that she has left it upon the side-table." + +I took it up and glanced at it. "Mr. Victor Hatherley, hydraulic engineer, 16A, Victoria Street (3rd floor)." That was the name, style, and abode of my morning visitor. "I regret that I have kept you waiting," said I, sitting down in my library-chair. "You are fresh from a night journey, I understand, which is in itself a monotonous occupation." + +"Oh, my night could not be called monotonous," said he, and laughed. He laughed very heartily, with a high, ringing note, leaning back in his chair and shaking his sides. All my medical instincts rose up against that laugh. + +"Stop it!" I cried; "pull yourself together!" and I poured out some water from a caraffe. + +It was useless, however. He was off in one of those hysterical outbursts which come upon a strong nature when some great crisis is over and gone. Presently he came to himself once more, very weary and pale-looking. + +"I have been making a fool of myself," he gasped. + +"Not at all. Drink this." I dashed some brandy into the water, and the colour began to come back to his bloodless cheeks. + +"That's better!" said he. "And now, Doctor, perhaps you would kindly attend to my thumb, or rather to the place where my thumb used to be." + +He unwound the handkerchief and held out his hand. It gave even my hardened nerves a shudder to look at it. There were four protruding fingers and a horrid red, spongy surface where the thumb should have been. It had been hacked or torn right out from the roots. + +"Good heavens!" I cried, "this is a terrible injury. It must have bled considerably." + +"Yes, it did. I fainted when it was done, and I think that I must have been senseless for a long time. When I came to I found that it was still bleeding, so I tied one end of my handkerchief very tightly round the wrist and braced it up with a twig." + +"Excellent! You should have been a surgeon." + +"It is a question of hydraulics, you see, and came within my own province." + +"This has been done," said I, examining the wound, "by a very heavy and sharp instrument." + +"A thing like a cleaver," said he. + +"An accident, I presume?" + +"By no means." + +"What! a murderous attack?" + +"Very murderous indeed." + +"You horrify me." + +I sponged the wound, cleaned it, dressed it, and finally covered it over with cotton wadding and carbolised bandages. He lay back without wincing, though he bit his lip from time to time. + +"How is that?" I asked when I had finished. + +"Capital! Between your brandy and your bandage, I feel a new man. I was very weak, but I have had a good deal to go through." + +"Perhaps you had better not speak of the matter. It is evidently trying to your nerves." + +"Oh, no, not now. I shall have to tell my tale to the police; but, between ourselves, if it were not for the convincing evidence of this wound of mine, I should be surprised if they believed my statement, for it is a very extraordinary one, and I have not much in the way of proof with which to back it up; and, even if they believe me, the clues which I can give them are so vague that it is a question whether justice will be done." + +"Ha!" cried I, "if it is anything in the nature of a problem which you desire to see solved, I should strongly recommend you to come to my friend, Mr. Sherlock Holmes, before you go to the official police." + +"Oh, I have heard of that fellow," answered my visitor, "and I should be very glad if he would take the matter up, though of course I must use the official police as well. Would you give me an introduction to him?" + +"I'll do better. I'll take you round to him myself." + +"I should be immensely obliged to you." + +"We'll call a cab and go together. We shall just be in time to have a little breakfast with him. Do you feel equal to it?" + +"Yes; I shall not feel easy until I have told my story." + +"Then my servant will call a cab, and I shall be with you in an instant." I rushed upstairs, explained the matter shortly to my wife, and in five minutes was inside a hansom, driving with my new acquaintance to Baker Street. + +Sherlock Holmes was, as I expected, lounging about his sitting-room in his dressing-gown, reading the agony column of The Times and smoking his before-breakfast pipe, which was composed of all the plugs and dottles left from his smokes of the day before, all carefully dried and collected on the corner of the mantelpiece. He received us in his quietly genial fashion, ordered fresh rashers and eggs, and joined us in a hearty meal. When it was concluded he settled our new acquaintance upon the sofa, placed a pillow beneath his head, and laid a glass of brandy and water within his reach. + +"It is easy to see that your experience has been no common one, Mr. Hatherley," said he. "Pray, lie down there and make yourself absolutely at home. Tell us what you can, but stop when you are tired and keep up your strength with a little stimulant." + +"Thank you," said my patient. "but I have felt another man since the doctor bandaged me, and I think that your breakfast has completed the cure. I shall take up as little of your valuable time as possible, so I shall start at once upon my peculiar experiences." + +Holmes sat in his big armchair with the weary, heavy-lidded expression which veiled his keen and eager nature, while I sat opposite to him, and we listened in silence to the strange story which our visitor detailed to us. + +"You must know," said he, "that I am an orphan and a bachelor, residing alone in lodgings in London. By profession I am a hydraulic engineer, and I have had considerable experience of my work during the seven years that I was apprenticed to Venner & Matheson, the well-known firm, of Greenwich. Two years ago, having served my time, and having also come into a fair sum of money through my poor father's death, I determined to start in business for myself and took professional chambers in Victoria Street. + +"I suppose that everyone finds his first independent start in business a dreary experience. To me it has been exceptionally so. During two years I have had three consultations and one small job, and that is absolutely all that my profession has brought me. My gross takings amount to $27 10s. Every day, from nine in the morning until four in the afternoon, I waited in my little den, until at last my heart began to sink, and I came to believe that I should never have any practice at all. + +"Yesterday, however, just as I was thinking of leaving the office, my clerk entered to say there was a gentleman waiting who wished to see me upon business. He brought up a card, too, with the name of 'Colonel Lysander Stark' engraved upon it. Close at his heels came the colonel himself, a man rather over the middle size, but of an exceeding thinness. I do not think that I have ever seen so thin a man. His whole face sharpened away into nose and chin, and the skin of his cheeks was drawn quite tense over his outstanding bones. Yet this emaciation seemed to be his natural habit, and due to no disease, for his eye was bright, his step brisk, and his bearing assured. He was plainly but neatly dressed, and his age, I should judge, would be nearer forty than thirty. + +" 'Mr. Hatherley?' said he, with something of a German accent. 'You have been recommended to me, Mr. Hatherley, as being a man who is not only proficient in his profession but is also discreet and capable of preserving a secret.' + +"I bowed, feeling as flattered as any young man would at such an address. 'May I ask who it was who gave me so good a character?' + +" 'Well, perhaps it is better that I should not tell you that just at this moment. I have it from the same source that you are both an orphan and a bachelor and are residing alone in London.' + +" 'That is quite correct,' I answered; 'but you will excuse me if I say that I cannot see how all this bears upon my professional qualifications. I understand that it was on a professional matter that you wished to speak to me?' + +" 'Undoubtedly so. But you will find that all I say is really to the point. I have a professional commission for you, but absolute secrecy is quite essential--absolute secrecy, you understand, and of course we may expect that more from a man who is alone than from one who lives in the bosom of his family.' + +" 'If I promise to keep a secret,' said I, 'you may absolutely depend upon my doing so.' + +"He looked very hard at me as I spoke, and it seemed to me that I had never seen so suspicious and questioning an eye. + +" 'Do you promise, then?' said he at last. + +" 'Yes, I promise.' + +" 'Absolute and complete silence before, during, and after? No reference to the matter at all, either in word or writing?' + +" 'I have already given you my word.' + +" 'Very good.' He suddenly sprang up, and darting like lightning across the room he flung open the door. The passage outside was empty. + +" 'That's all right,' said he, coming back. 'I know that clerks are sometimes curious as to their master's affairs. Now we can talk in safety.' He drew up his chair very close to mine and began to stare at me again with the same questioning and thoughtful look. + +"A feeling of repulsion, and of something akin to fear had begun to rise within me at the strange antics of this fleshless man. Even my dread of losing a client could not restrain me from showing my impatience. + +" 'I beg that you will state your business, sir,' said I; 'my time is of value.' Heaven forgive me for that last sentence, but the words came to my lips. + +" 'How would fifty guineas for a night's work suit you?' he asked. + +" 'Most admirably.' + +" 'I say a night's work, but an hour's would be nearer the mark. I simply want your opinion about a hydraulic stamping machine which has got out of gear. If you show us what is wrong we shall soon set it right ourselves. What do you think of such a commission as that?' + +" 'The work appears to be light and the pay munificent.' + +" 'Precisely so. We shall want you to come to-night by the last train.' + +" 'Where to?' + +" 'To Eyford, in Berkshire. It is a little place near the borders of Oxfordshire, and within seven miles of Reading. There is a train from Paddington which would bring you there at about 11:15.' + +" 'Very good.' + +" 'I shall come down in a carriage to meet you.' + +" 'There is a drive, then?' + +" 'Yes, our little place is quite out in the country. It is a good seven miles from Eyford Station.' + +" 'Then we can hardly get there before midnight. I suppose there would be no chance of a train back. I should be compelled to stop the night.' + +" 'Yes, we could easily give you a shake-down.' + +" 'That is very awkward. Could I not come at some more convenient hour?' + +" 'We have judged it best that you should come late. It is to recompense you for any inconvenience that we are paying to you, a young and unknown man, a fee which would buy an opinion from the very heads of your profession. Still, of course, if you would like to draw out of the business, there is plenty of time to do so.' + +"I thought of the fifty guineas, and of how very useful they would be to me. 'Not at all,' said I, 'I shall be very happy to accommodate myself to your wishes. I should like, however, to understand a little more clearly what it is that you wish me to do.' + +" 'Quite so. It is very natural that the pledge of secrecy which we have exacted from you should have aroused your curiosity. I have no wish to commit you to anything without your having it all laid before you. I suppose that we are absolutely safe from eavesdroppers?' + +" 'Entirely.' + +" 'Then the matter stands thus. You are probably aware that fuller's-earth is a valuable product, and that it is only found in one or two places in England?' + +" 'I have heard so.' + +" 'Some little time ago I bought a small place--a very small place--within ten miles of Reading. I was fortunate enough to discover that there was a deposit of fuller's-earth in one of my fields. On examining it, however, I found that this deposit was a comparatively small one, and that it formed a link between two very much larger ones upon the right and left--both of them, however, in the grounds of my neighbours. These good people were absolutely ignorant that their land contained that which was quite as valuable as a gold-mine. Naturally, it was to my interest to buy their land before they discovered its true value, but unfortunately I had no capital by which I could do this. I took a few of my friends into the secret, however, and they suggested that we should quietly and secretly work our own little deposit and that in this way we should earn the money which would enable us to buy the neighbouring fields. This we have now been doing for some time, and in order to help us in our operations we erected a hydraulic press. This press, as I have already explained, has got out of order, and we wish your advice upon the subject. We guard our secret very jealously, however, and if it once became known that we had hydraulic engineers coming to our little house, it would soon rouse inquiry, and then, if the facts came out, it would be good-bye to any chance of getting these fields and carrying out our plans. That is why I have made you promise me that you will not tell a human being that you are going to Eyford to-night. I hope that I make it all plain?' + +" 'I quite follow you,' said I. 'The only point which I could not quite understand was what use you could make of a hydraulic press in excavating fuller's-earth, which, as I understand, is dug out like gravel from a pit.' + +" 'Ah!' said he carelessly, 'we have our own process. We compress the earth into bricks, so as to remove them without revealing what they are. But that is a mere detail. I have taken you fully into my confidence now, Mr. Hatherley, and I have shown you how I trust you.' He rose as he spoke. 'I shall expect you, then, at Eyford at 11:15.' + +" 'I shall certainly be there.' + +" 'And not a word to a soul.' He looked at me with a last long, questioning gaze, and then, pressing my hand in a cold, dank grasp, he hurried from the room. + +"Well, when I came to think it all over in cool blood I was very much astonished, as you may both think, at this sudden commission which had been intrusted to me. On the one hand, of course, I was glad, for the fee was at least tenfold what I should have asked had I set a price upon my own services, and it was possible that this order might lead to other ones. On the other hand, the face and manner of my patron had made an unpleasant impression upon me, and I could not think that his explanation of the fuller's-earth was sufficient to explain the necessity for my coming at midnight, and his extreme anxiety lest I should tell anyone of my errand. However, I threw all fears to the winds, ate a hearty supper, drove to Paddington, and started off, having obeyed to the letter the injunction as to holding my tongue. + +"At Reading I had to change not only my carriage but my station. However, I was in time for the last train to Eyford, and I reached the little dim-lit station after eleven o'clock. I was the only passenger who got out there, and there was no one upon the platform save a single sleepy porter with a lantern. As I passed out through the wicket gate, however, I found my acquaintance of the morning waiting in the shadow upon the other side. Without a word he grasped my arm and hurried me into a carriage, the door of which was standing open. He drew up the windows on either side, tapped on the wood-work, and away we went as fast as the horse could go." + +"One horse?" interjected Holmes. + +"Yes, only one." + +"Did you observe the colour?" + +"Yes, I saw it by the side-lights when I was stepping into the carriage. It was a chestnut." + +"Tired-looking or fresh?" + +"Oh, fresh and glossy." + +"Thank you. I am sorry to have interrupted you. Pray continue your most interesting statement." + +"Away we went then, and we drove for at least an hour. Colonel Lysander Stark had said that it was only seven miles, but I should think, from the rate that we seemed to go, and from the time that we took, that it must have been nearer twelve. He sat at my side in silence all the time, and I was aware, more than once when I glanced in his direction, that he was looking at me with great intensity. The country roads seem to be not very good in that part of the world, for we lurched and jolted terribly. I tried to look out of the windows to see something of where we were, but they were made of frosted glass, and I could make out nothing save the occasional bright blur of a passing light. Now and then I hazarded some remark to break the monotony of the journey, but the colonel answered only in monosyllables, and the conversation soon flagged. At last, however, the bumping of the road was exchanged for the crisp smoothness of a gravel-drive, and the carriage came to a stand. Colonel Lysander Stark sprang out, and, as I followed after him, pulled me swiftly into a porch which gaped in front of us. We stepped, as it were, right out of the carriage and into the hall, so that I failed to catch the most fleeting glance of the front of the house. The instant that I had crossed the threshold the door slammed heavily behind us, and I heard faintly the rattle of the wheels as the carriage drove away. + +"It was pitch dark inside the house, and the colonel fumbled about looking for matches and muttering under his breath. Suddenly a door opened at the other end of the passage, and a long, golden bar of light shot out in our direction. It grew broader, and a woman appeared with a lamp in her hand, which she held above her head, pushing her face forward and peering at us. I could see that she was pretty, and from the gloss with which the light shone upon her dark dress I knew that it was a rich material. She spoke a few words in a foreign tongue in a tone as though asking a question, and when my companion answered in a gruff monosyllable she gave such a start that the lamp nearly fell from her hand. Colonel Stark went up to her, whispered something in her ear, and then, pushing her back into the room from whence she had come, he walked towards me again with the lamp in his hand. + +" 'Perhaps you will have the kindness to wait in this room for a few minutes,' said he, throwing open another door. It was a quiet, little, plainly furnished room, with a round table in the centre, on which several German books were scattered. Colonel Stark laid down the lamp on the top of a harmonium beside the door. 'I shall not keep you waiting an instant,' said he, and vanished into the darkness. + +"I glanced at the books upon the table, and in spite of my ignorance of German I could see that two of them were treatises on science, the others being volumes of poetry. Then I walked across to the window, hoping that I might catch some glimpse of the country-side, but an oak shutter, heavily barred, was folded across it. It was a wonderfully silent house. There was an old clock ticking loudly somewhere in the passage, but otherwise everything was deadly still. A vague feeling of uneasiness began to steal over me. Who were these German people, and what were they doing living in this strange, out-of-the-way place? And where was the place? I was ten miles or so from Eyford, that was all I knew, but whether north, south, east, or west I had no idea. For that matter, Reading, and possibly other large towns, were within that radius, so the place might not be so secluded, after all. Yet it was quite certain, from the absolute stillness, that we were in the country. I paced up and down the room, humming a tune under my breath to keep up my spirits and feeling that I was thoroughly earning my fifty-guinea fee. + +"Suddenly, without any preliminary sound in the midst of the utter stillness, the door of my room swung slowly open. The woman was standing in the aperture, the darkness of the hall behind her, the yellow light from my lamp beating upon her eager and beautiful face. I could see at a glance that she was sick with fear, and the sight sent a chill to my own heart. She held up one shaking finger to warn me to be silent, and she shot a few whispered words of broken English at me, her eyes glancing back, like those of a frightened horse, into the gloom behind her. + +" 'I would go,' said she, trying hard, as it seemed to me, to speak calmly; 'I would go. I should not stay here. There is no good for you to do.' + +" 'But, madam,' said I, 'I have not yet done what I came for. I cannot possibly leave until I have seen the machine.' + +" 'It is not worth your while to wait,' she went on. 'You can pass through the door; no one hinders.' And then, seeing that I smiled and shook my head, she suddenly threw aside her constraint and made a step forward, with her hands wrung together. 'For the love of Heaven!' she whispered, 'get away from here before it is too late!' + +"But I am somewhat headstrong by nature, and the more ready to engage in an affair when there is some obstacle in the way. I thought of my fifty-guinea fee, of my wearisome journey, and of the unpleasant night which seemed to be before me. Was it all to go for nothing? Why should I slink away without having carried out my commission, and without the payment which was my due? This woman might, for all I knew, be a monomaniac. With a stout bearing, therefore, though her manner had shaken me more than I cared to confess, I still shook my head and declared my intention of remaining where I was. She was about to renew her entreaties when a door slammed overhead, and the sound of several footsteps was heard upon the stairs. She listened for an instant, threw up her hands with a despairing gesture, and vanished as suddenly and as noiselessly as she had come. + +"The newcomers were Colonel Lysander Stark and a short thick man with a chinchilla beard growing out of the creases of his double chin, who was introduced to me as Mr. Ferguson. + +" 'This is my secretary and manager,' said the colonel. 'By the way, I was under the impression that I left this door shut just now. I fear that you have felt the draught.' + +" 'On the contrary,' said I, 'I opened the door myself because I felt the room to be a little close.' + +"He shot one of his suspicious looks at me. 'Perhaps we had better proceed to business, then,' said he. 'Mr. Ferguson and I will take you up to see the machine.' + +" 'I had better put my hat on, I suppose.' + +" 'Oh, no, it is in the house.' + +" 'What, you dig fuller's-earth in the house?' + +" 'No, no. This is only where we compress it. But never mind that. All we wish you to do is to examine the machine and to let us know what is wrong with it.' + +"We went upstairs together, the colonel first with the lamp, the fat manager and I behind him. It was a labyrinth of an old house, with corridors, passages, narrow winding staircases, and little low doors, the thresholds of which were hollowed out by the generations who had crossed them. There were no carpets and no signs of any furniture above the ground floor, while the plaster was peeling off the walls, and the damp was breaking through in green, unhealthy blotches. I tried to put on as unconcerned an air as possible, but I had not forgotten the warnings of the lady, even though I disregarded them, and I kept a keen eye upon my two companions. Ferguson appeared to be a morose and silent man, but I could see from the little that he said that he was at least a fellow-countryman. + +"Colonel Lysander Stark stopped at last before a low door, which he unlocked. Within was a small, square room, in which the three of us could hardly get at one time. Ferguson remained outside, and the colonel ushered me in. + +" 'We are now,' said he, 'actually within the hydraulic press, and it would be a particularly unpleasant thing for us if anyone were to turn it on. The ceiling of this small chamber is really the end of the descending piston, and it comes down with the force of many tons upon this metal floor. There are small lateral columns of water outside which receive the force, and which transmit and multiply it in the manner which is familiar to you. The machine goes readily enough, but there is some stiffness in the working of it, and it has lost a little of its force. Perhaps you will have the goodness to look it over and to show us how we can set it right.' + +"I took the lamp from him, and I examined the machine very thoroughly. It was indeed a gigantic one, and capable of exercising enormous pressure. When I passed outside, however, and pressed down the levers which controlled it, I knew at once by the whishing sound that there was a slight leakage, which allowed a regurgitation of water through one of the side cylinders. An examination showed that one of the india-rubber bands which was round the head of a driving-rod had shrunk so as not quite to fill the socket along which it worked. This was clearly the cause of the loss of power, and I pointed it out to my companions, who followed my remarks very carefully and asked several practical questions as to how they should proceed to set it right. When I had made it clear to them, I returned to the main chamber of the machine and took a good look at it to satisfy my own curiosity. It was obvious at a glance that the story of the fuller's-earth was the merest fabrication, for it would be absurd to suppose that so powerful an engine could be designed for so inadequate a purpose. The walls were of wood, but the floor consisted of a large iron trough, and when I came to examine it I could see a crust of metallic deposit all over it. I had stooped and was scraping at this to see exactly what it was when I heard a muttered exclamation in German and saw the cadaverous face of the colonel looking down at me. + +" 'What are you doing there?' he asked. + +"I felt angry at having been tricked by so elaborate a story as that which he had told me. 'I was admiring your fuller's-earth,' said I; 'I think that I should be better able to advise you as to your machine if I knew what the exact purpose was for which it was used.' + +"The instant that I uttered the words I regretted the rashness of my speech. His face set hard, and a baleful light sprang up in his grey eyes. + +" 'Very well,' said he, 'you shall know all about the machine.' He took a step backward, slammed the little door, and turned the key in the lock. I rushed towards it and pulled at the handle, but it was quite secure, and did not give in the least to my kicks and shoves. 'Hullo!' I yelled. 'Hullo! Colonel! Let me out!' + +"And then suddenly in the silence I heard a sound which sent my heart into my mouth. It was the clank of the levers and the swish of the leaking cylinder. He had set the engine at work. The lamp still stood upon the floor where I had placed it when examining the trough. By its light I saw that the black ceiling was coming down upon me, slowly, jerkily, but, as none knew better than myself, with a force which must within a minute grind me to a shapeless pulp. I threw myself, screaming, against the door, and dragged with my nails at the lock. I implored the colonel to let me out, but the remorseless clanking of the levers drowned my cries. The ceiling was only a foot or two above my head, and with my hand upraised I could feel its hard, rough surface. Then it flashed through my mind that the pain of my death would depend very much upon the position in which I met it. If I lay on my face the weight would come upon my spine, and I shuddered to think of that dreadful snap. Easier the other way, perhaps; and yet, had I the nerve to lie and look up at that deadly black shadow wavering down upon me? Already I was unable to stand erect, when my eye caught something which brought a gush of hope back to my heart. + +"I have said that though the floor and ceiling were of iron, the walls were of wood. As I gave a last hurried glance around, I saw a thin line of yellow light between two of the boards, which broadened and broadened as a small panel was pushed backward. For an instant I could hardly believe that here was indeed a door which led away from death. The next instant I threw myself through, and lay half-fainting upon the other side. The panel had closed again behind me, but the crash of the lamp, and a few moments afterwards the clang of the two slabs of metal, told me how narrow had been my escape. + +"I was recalled to myself by a frantic plucking at my wrist, and I found myself lying upon the stone floor of a narrow corridor, while a woman bent over me and tugged at me with her left hand, while she held a candle in her right. It was the same good friend whose warning I had so foolishly rejected. + +" 'Come! come!' she cried breathlessly. 'They will be here in a moment. They will see that you are not there. Oh, do not waste the so-precious time, but come!' + +"This time, at least, I did not scorn her advice. I staggered to my feet and ran with her along the corridor and down a winding stair. The latter led to another broad passage, and just as we reached it we heard the sound of running feet and the shouting of two voices, one answering the other from the floor on which we were and from the one beneath. My guide stopped and looked about her like one who is at her wit's end. Then she threw open a door which led into a bedroom, through the window of which the moon was shining brightly. + +" 'It is your only chance,' said she. 'It is high, but it may be that you can jump it.' + +"As she spoke a light sprang into view at the further end of the passage, and I saw the lean figure of Colonel Lysander Stark rushing forward with a lantern in one hand and a weapon like a butcher's cleaver in the other. I rushed across the bedroom, flung open the window, and looked out. How quiet and sweet and wholesome the garden looked in the moonlight, and it could not be more than thirty feet down. I clambered out upon the sill, but I hesitated to jump until I should have heard what passed between my saviour and the ruffian who pursued me. If she were ill-used, then at any risks I was determined to go back to her assistance. The thought had hardly flashed through my mind before he was at the door, pushing his way past her; but she threw her arms round him and tried to hold him back. + +" 'Fritz! Fritz!' she cried in English, 'remember your promise after the last time. You said it should not be again. He will be silent! Oh, he will be silent!' + +" 'You are mad, Elise!' he shouted, struggling to break away from her. 'You will be the ruin of us. He has seen too much. Let me pass, I say!' He dashed her to one side, and, rushing to the window, cut at me with his heavy weapon. I had let myself go, and was hanging by the hands to the sill, when his blow fell. I was conscious of a dull pain, my grip loosened, and I fell into the garden below. + +"I was shaken but not hurt by the fall; so I picked myself up and rushed off among the bushes as hard as I could run, for I understood that I was far from being out of danger yet. Suddenly, however, as I ran, a deadly dizziness and sickness came over me. I glanced down at my hand, which was throbbing painfully, and then, for the first time, saw that my thumb had been cut off and that the blood was pouring from my wound. I endeavoured to tie my handkerchief round it, but there came a sudden buzzing in my ears, and next moment I fell in a dead faint among the rose-bushes. + +"How long I remained unconscious I cannot tell. It must have been a very long time, for the moon had sunk, and a bright morning was breaking when I came to myself. My clothes were all sodden with dew, and my coat-sleeve was drenched with blood from my wounded thumb. The smarting of it recalled in an instant all the particulars of my night's adventure, and I sprang to my feet with the feeling that I might hardly yet be safe from my pursuers. But to my astonishment, when I came to look round me, neither house nor garden were to be seen. I had been lying in an angle of the hedge close by the highroad, and just a little lower down was a long building, which proved, upon my approaching it, to be the very station at which I had arrived upon the previous night. Were it not for the ugly wound upon my hand, all that had passed during those dreadful hours might have been an evil dream. + +"Half dazed, I went into the station and asked about the morning train. There would be one to Reading in less than an hour. The same porter was on duty, I found, as had been there when I arrived. I inquired of him whether he had ever heard of Colonel Lysander Stark. The name was strange to him. Had he observed a carriage the night before waiting for me? No, he had not. Was there a police-station anywhere near? There was one about three miles off. + +"It was too far for me to go, weak and ill as I was. I determined to wait until I got back to town before telling my story to the police. It was a little past six when I arrived, so I went first to have my wound dressed, and then the doctor was kind enough to bring me along here. I put the case into your hands and shall do exactly what you advise." + +We both sat in silence for some little time after listening to this extraordinary narrative. Then Sherlock Holmes pulled down from the shelf one of the ponderous commonplace books in which he placed his cuttings. + +"Here is an advertisement which will interest you," said he. "It appeared in all the papers about a year ago. Listen to this: 'Lost, on the 9th inst., Mr. Jeremiah Hayling, aged twenty-six, a hydraulic engineer. Left his lodgings at ten o'clock at night, and has not been heard of since. Was dressed in,' etc., etc. Ha! That represents the last time that the colonel needed to have his machine overhauled, I fancy." + +"Good heavens!" cried my patient. "Then that explains what the girl said." + +"Undoubtedly. It is quite clear that the colonel was a cool and desperate man, who was absolutely determined that nothing should stand in the way of his little game, like those out-and-out pirates who will leave no survivor from a captured ship. Well, every moment now is precious, so if you feel equal to it we shall go down to Scotland Yard at once as a preliminary to starting for Eyford." + +Some three hours or so afterwards we were all in the train together, bound from Reading to the little Berkshire village. There were Sherlock Holmes, the hydraulic engineer, Inspector Bradstreet, of Scotland Yard, a plain-clothes man, and myself. Bradstreet had spread an ordnance map of the county out upon the seat and was busy with his compasses drawing a circle with Eyford for its centre. + +"There you are," said he. "That circle is drawn at a radius of ten miles from the village. The place we want must be somewhere near that line. You said ten miles, I think, sir." + +"It was an hour's good drive." + +"And you think that they brought you back all that way when you were unconscious?" + +"They must have done so. I have a confused memory, too, of having been lifted and conveyed somewhere." + +"What I cannot understand," said I, "is why they should have spared you when they found you lying fainting in the garden. Perhaps the villain was softened by the woman's entreaties." + +"I hardly think that likely. I never saw a more inexorable face in my life." + +"Oh, we shall soon clear up all that," said Bradstreet. "Well, I have drawn my circle, and I only wish I knew at what point upon it the folk that we are in search of are to be found." + +"I think I could lay my finger on it," said Holmes quietly. + +"Really, now!" cried the inspector, "you have formed your opinion! Come, now, we shall see who agrees with you. I say it is south, for the country is more deserted there." + +"And I say east," said my patient. + +"I am for west," remarked the plain-clothes man. "There are several quiet little villages up there." + +"And I am for north," said I, "because there are no hills there, and our friend says that he did not notice the carriage go up any." + +"Come," cried the inspector, laughing; "it's a very pretty diversity of opinion. We have boxed the compass among us. Who do you give your casting vote to?" + +"You are all wrong." + +"But we can't all be." + +"Oh, yes, you can. This is my point." He placed his finger in the centre of the circle. "This is where we shall find them." + +"But the twelve-mile drive?" gasped Hatherley. + +"Six out and six back. Nothing simpler. You say yourself that the horse was fresh and glossy when you got in. How could it be that if it had gone twelve miles over heavy roads?" + +"Indeed, it is a likely ruse enough," observed Bradstreet thoughtfully. "Of course there can be no doubt as to the nature of this gang." + +"None at all," said Holmes. "They are coiners on a large scale, and have used the machine to form the amalgam which has taken the place of silver." + +"We have known for some time that a clever gang was at work," said the inspector. "They have been turning out half-crowns by the thousand. We even traced them as far as Reading, but could get no farther, for they had covered their traces in a way that showed that they were very old hands. But now, thanks to this lucky chance, I think that we have got them right enough." + +But the inspector was mistaken, for those criminals were not destined to fall into the hands of justice. As we rolled into Eyford Station we saw a gigantic column of smoke which streamed up from behind a small clump of trees in the neighbourhood and hung like an immense ostrich feather over the landscape. + +"A house on fire?" asked Bradstreet as the train steamed off again on its way. + +"Yes, sir!" said the station-master. + +"When did it break out?" + +"I hear that it was during the night, sir, but it has got worse, and the whole place is in a blaze." + +"Whose house is it?" + +"Dr. Becher's." + +"Tell me," broke in the engineer, "is Dr. Becher a German, very thin, with a long, sharp nose?" + +The station-master laughed heartily. "No, sir, Dr. Becher is an Englishman, and there isn't a man in the parish who has a better-lined waistcoat. But he has a gentleman staying with him, a patient, as I understand, who is a foreigner, and he looks as if a little good Berkshire beef would do him no harm." + +The station-master had not finished his speech before we were all hastening in the direction of the fire. The road topped a low hill, and there was a great widespread whitewashed building in front of us, spouting fire at every chink and window, while in the garden in front three fire-engines were vainly striving to keep the flames under. + +"That's it!" cried Hatherley, in intense excitement. "There is the gravel-drive, and there are the rose-bushes where I lay. That second window is the one that I jumped from." + +"Well, at least," said Holmes, "you have had your revenge upon them. There can be no question that it was your oil-lamp which, when it was crushed in the press, set fire to the wooden walls, though no doubt they were too excited in the chase after you to observe it at the time. Now keep your eyes open in this crowd for your friends of last night, though I very much fear that they are a good hundred miles off by now." + +And Holmes' fears came to be realised, for from that day to this no word has ever been heard either of the beautiful woman, the sinister German, or the morose Englishman. Early that morning a peasant had met a cart containing several people and some very bulky boxes driving rapidly in the direction of Reading, but there all traces of the fugitives disappeared, and even Holmes' ingenuity failed ever to discover the least clue as to their whereabouts. + +The firemen had been much perturbed at the strange arrangements which they had found within, and still more so by discovering a newly severed human thumb upon a window-sill of the second floor. About sunset, however, their efforts were at last successful, and they subdued the flames, but not before the roof had fallen in, and the whole place been reduced to such absolute ruin that, save some twisted cylinders and iron piping, not a trace remained of the machinery which had cost our unfortunate acquaintance so dearly. Large masses of nickel and of tin were discovered stored in an out-house, but no coins were to be found, which may have explained the presence of those bulky boxes which have been already referred to. + +How our hydraulic engineer had been conveyed from the garden to the spot where he recovered his senses might have remained forever a mystery were it not for the soft mould, which told us a very plain tale. He had evidently been carried down by two persons, one of whom had remarkably small feet and the other unusually large ones. On the whole, it was most probable that the silent Englishman, being less bold or less murderous than his companion, had assisted the woman to bear the unconscious man out of the way of danger. + +"Well," said our engineer ruefully as we took our seats to return once more to London, "it has been a pretty business for me! I have lost my thumb and I have lost a fifty-guinea fee, and what have I gained?" + +"Experience," said Holmes, laughing. "Indirectly it may be of value, you know; you have only to put it into words to gain the reputation of being excellent company for the remainder of your existence." + +X. THE ADVENTURE OF THE NOBLE BACHELOR + + +The Lord St. Simon marriage, and its curious termination, have long ceased to be a subject of interest in those exalted circles in which the unfortunate bridegroom moves. Fresh scandals have eclipsed it, and their more piquant details have drawn the gossips away from this four-year-old drama. As I have reason to believe, however, that the full facts have never been revealed to the general public, and as my friend Sherlock Holmes had a considerable share in clearing the matter up, I feel that no memoir of him would be complete without some little sketch of this remarkable episode. + +It was a few weeks before my own marriage, during the days when I was still sharing rooms with Holmes in Baker Street, that he came home from an afternoon stroll to find a letter on the table waiting for him. I had remained indoors all day, for the weather had taken a sudden turn to rain, with high autumnal winds, and the Jezail bullet which I had brought back in one of my limbs as a relic of my Afghan campaign throbbed with dull persistence. With my body in one easy-chair and my legs upon another, I had surrounded myself with a cloud of newspapers until at last, saturated with the news of the day, I tossed them all aside and lay listless, watching the huge crest and monogram upon the envelope upon the table and wondering lazily who my friend's noble correspondent could be. + +"Here is a very fashionable epistle," I remarked as he entered. "Your morning letters, if I remember right, were from a fish-monger and a tide-waiter." + +"Yes, my correspondence has certainly the charm of variety," he answered, smiling, "and the humbler are usually the more interesting. This looks like one of those unwelcome social summonses which call upon a man either to be bored or to lie." + +He broke the seal and glanced over the contents. + +"Oh, come, it may prove to be something of interest, after all." + +"Not social, then?" + +"No, distinctly professional." + +"And from a noble client?" + +"One of the highest in England." + +"My dear fellow, I congratulate you." + +"I assure you, Watson, without affectation, that the status of my client is a matter of less moment to me than the interest of his case. It is just possible, however, that that also may not be wanting in this new investigation. You have been reading the papers diligently of late, have you not?" + +"It looks like it," said I ruefully, pointing to a huge bundle in the corner. "I have had nothing else to do." + +"It is fortunate, for you will perhaps be able to post me up. I read nothing except the criminal news and the agony column. The latter is always instructive. But if you have followed recent events so closely you must have read about Lord St. Simon and his wedding?" + +"Oh, yes, with the deepest interest." + +"That is well. The letter which I hold in my hand is from Lord St. Simon. I will read it to you, and in return you must turn over these papers and let me have whatever bears upon the matter. This is what he says: + +" 'MY DEAR MR. SHERLOCK HOLMES:--Lord Backwater tells me that I may place implicit reliance upon your judgment and discretion. I have determined, therefore, to call upon you and to consult you in reference to the very painful event which has occurred in connection with my wedding. Mr. Lestrade, of Scotland Yard, is acting already in the matter, but he assures me that he sees no objection to your co-operation, and that he even thinks that it might be of some assistance. I will call at four o'clock in the afternoon, and, should you have any other engagement at that time, I hope that you will postpone it, as this matter is of paramount importance. Yours faithfully, + + +" 'ST. SIMON.' + +"It is dated from Grosvenor Mansions, written with a quill pen, and the noble lord has had the misfortune to get a smear of ink upon the outer side of his right little finger," remarked Holmes as he folded up the epistle. + +"He says four o'clock. It is three now. He will be here in an hour." + +"Then I have just time, with your assistance, to get clear upon the subject. Turn over those papers and arrange the extracts in their order of time, while I take a glance as to who our client is." He picked a red-covered volume from a line of books of reference beside the mantelpiece. "Here he is," said he, sitting down and flattening it out upon his knee. " 'Lord Robert Walsingham de Vere St. Simon, second son of the Duke of Balmoral.' Hum! 'Arms: Azure, three caltrops in chief over a fess sable. Born in 1846.' He's forty-one years of age, which is mature for marriage. Was Under-Secretary for the colonies in a late administration. The Duke, his father, was at one time Secretary for Foreign Affairs. They inherit Plantagenet blood by direct descent, and Tudor on the distaff side. Ha! Well, there is nothing very instructive in all this. I think that I must turn to you Watson, for something more solid." + +"I have very little difficulty in finding what I want," said I, "for the facts are quite recent, and the matter struck me as remarkable. I feared to refer them to you, however, as I knew that you had an inquiry on hand and that you disliked the intrusion of other matters." + +"Oh, you mean the little problem of the Grosvenor Square furniture van. That is quite cleared up now--though, indeed, it was obvious from the first. Pray give me the results of your newspaper selections." + +"Here is the first notice which I can find. It is in the personal column of the Morning Post, and dates, as you see, some weeks back: 'A marriage has been arranged,' it says, 'and will, if rumour is correct, very shortly take place, between Lord Robert St. Simon, second son of the Duke of Balmoral, and Miss Hatty Doran, the only daughter of Aloysius Doran. Esq., of San Francisco, Cal., U.S.A.' That is all." + +"Terse and to the point," remarked Holmes, stretching his long, thin legs towards the fire. + +"There was a paragraph amplifying this in one of the society papers of the same week. Ah, here it is: 'There will soon be a call for protection in the marriage market, for the present free-trade principle appears to tell heavily against our home product. One by one the management of the noble houses of Great Britain is passing into the hands of our fair cousins from across the Atlantic. An important addition has been made during the last week to the list of the prizes which have been borne away by these charming invaders. Lord St. Simon, who has shown himself for over twenty years proof against the little god's arrows, has now definitely announced his approaching marriage with Miss Hatty Doran, the fascinating daughter of a California millionaire. Miss Doran, whose graceful figure and striking face attracted much attention at the Westbury House festivities, is an only child, and it is currently reported that her dowry will run to considerably over the six figures, with expectancies for the future. As it is an open secret that the Duke of Balmoral has been compelled to sell his pictures within the last few years, and as Lord St. Simon has no property of his own save the small estate of Birchmoor, it is obvious that the Californian heiress is not the only gainer by an alliance which will enable her to make the easy and common transition from a Republican lady to a British peeress.' " + +"Anything else?" asked Holmes, yawning. + +"Oh, yes; plenty. Then there is another note in the Morning Post to say that the marriage would be an absolutely quiet one, that it would be at St. George's, Hanover Square, that only half a dozen intimate friends would be invited, and that the party would return to the furnished house at Lancaster Gate which has been taken by Mr. Aloysius Doran. Two days later--that is, on Wednesday last--there is a curt announcement that the wedding had taken place, and that the honeymoon would be passed at Lord Backwater's place, near Petersfield. Those are all the notices which appeared before the disappearance of the bride." + +"Before the what?" asked Holmes with a start. + +"The vanishing of the lady." + +"When did she vanish, then?" + +"At the wedding breakfast." + +"Indeed. This is more interesting than it promised to be; quite dramatic, in fact." + +"Yes; it struck me as being a little out of the common." + +"They often vanish before the ceremony, and occasionally during the honeymoon; but I cannot call to mind anything quite so prompt as this. Pray let me have the details." + +"I warn you that they are very incomplete." + +"Perhaps we may make them less so." + +"Such as they are, they are set forth in a single article of a morning paper of yesterday, which I will read to you. It is headed, 'Singular Occurrence at a Fashionable Wedding': + +" 'The family of Lord Robert St. Simon has been thrown into the greatest consternation by the strange and painful episodes which have taken place in connection with his wedding. The ceremony, as shortly announced in the papers of yesterday, occurred on the previous morning; but it is only now that it has been possible to confirm the strange rumours which have been so persistently floating about. In spite of the attempts of the friends to hush the matter up, so much public attention has now been drawn to it that no good purpose can be served by affecting to disregard what is a common subject for conversation. + +" 'The ceremony, which was performed at St. George's, Hanover Square, was a very quiet one, no one being present save the father of the bride, Mr. Aloysius Doran, the Duchess of Balmoral, Lord Backwater, Lord Eustace and Lady Clara St. Simon (the younger brother and sister of the bridegroom), and Lady Alicia Whittington. The whole party proceeded afterwards to the house of Mr. Aloysius Doran, at Lancaster Gate, where breakfast had been prepared. It appears that some little trouble was caused by a woman, whose name has not been ascertained, who endeavoured to force her way into the house after the bridal party, alleging that she had some claim upon Lord St. Simon. It was only after a painful and prolonged scene that she was ejected by the butler and the footman. The bride, who had fortunately entered the house before this unpleasant interruption, had sat down to breakfast with the rest, when she complained of a sudden indisposition and retired to her room. Her prolonged absence having caused some comment, her father followed her, but learned from her maid that she had only come up to her chamber for an instant, caught up an ulster and bonnet, and hurried down to the passage. One of the footmen declared that he had seen a lady leave the house thus apparelled, but had refused to credit that it was his mistress, believing her to be with the company. On ascertaining that his daughter had disappeared, Mr. Aloysius Doran, in conjunction with the bridegroom, instantly put themselves in communication with the police, and very energetic inquiries are being made, which will probably result in a speedy clearing up of this very singular business. Up to a late hour last night, however, nothing had transpired as to the whereabouts of the missing lady. There are rumours of foul play in the matter, and it is said that the police have caused the arrest of the woman who had caused the original disturbance, in the belief that, from jealousy or some other motive, she may have been concerned in the strange disappearance of the bride.' " + +"And is that all?" + +"Only one little item in another of the morning papers, but it is a suggestive one." + +"And it is--" + +"That Miss Flora Millar, the lady who had caused the disturbance, has actually been arrested. It appears that she was formerly a danseuse at the Allegro, and that she has known the bridegroom for some years. There are no further particulars, and the whole case is in your hands now--so far as it has been set forth in the public press." + +"And an exceedingly interesting case it appears to be. I would not have missed it for worlds. But there is a ring at the bell, Watson, and as the clock makes it a few minutes after four, I have no doubt that this will prove to be our noble client. Do not dream of going, Watson, for I very much prefer having a witness, if only as a check to my own memory." + +"Lord Robert St. Simon," announced our page-boy, throwing open the door. A gentleman entered, with a pleasant, cultured face, high-nosed and pale, with something perhaps of petulance about the mouth, and with the steady, well-opened eye of a man whose pleasant lot it had ever been to command and to be obeyed. His manner was brisk, and yet his general appearance gave an undue impression of age, for he had a slight forward stoop and a little bend of the knees as he walked. His hair, too, as he swept off his very curly-brimmed hat, was grizzled round the edges and thin upon the top. As to his dress, it was careful to the verge of foppishness, with high collar, black frock-coat, white waistcoat, yellow gloves, patent-leather shoes, and light-coloured gaiters. He advanced slowly into the room, turning his head from left to right, and swinging in his right hand the cord which held his golden eyeglasses. + +"Good-day, Lord St. Simon," said Holmes, rising and bowing. "Pray take the basket-chair. This is my friend and colleague, Dr. Watson. Draw up a little to the fire, and we will talk this matter over." + +"A most painful matter to me, as you can most readily imagine, Mr. Holmes. I have been cut to the quick. I understand that you have already managed several delicate cases of this sort, sir, though I presume that they were hardly from the same class of society." + +"No, I am descending." + +"I beg pardon." + +"My last client of the sort was a king." + +"Oh, really! I had no idea. And which king?" + +"The King of Scandinavia." + +"What! Had he lost his wife?" + +"You can understand," said Holmes suavely, "that I extend to the affairs of my other clients the same secrecy which I promise to you in yours." + +"Of course! Very right! very right! I'm sure I beg pardon. As to my own case, I am ready to give you any information which may assist you in forming an opinion." + +"Thank you. I have already learned all that is in the public prints, nothing more. I presume that I may take it as correct--this article, for example, as to the disappearance of the bride." + +Lord St. Simon glanced over it. "Yes, it is correct, as far as it goes." + +"But it needs a great deal of supplementing before anyone could offer an opinion. I think that I may arrive at my facts most directly by questioning you." + +"Pray do so." + +"When did you first meet Miss Hatty Doran?" + +"In San Francisco, a year ago." + +"You were travelling in the States?" + +"Yes." + +"Did you become engaged then?" + +"No." + +"But you were on a friendly footing?" + +"I was amused by her society, and she could see that I was amused." + +"Her father is very rich?" + +"He is said to be the richest man on the Pacific slope." + +"And how did he make his money?" + +"In mining. He had nothing a few years ago. Then he struck gold, invested it, and came up by leaps and bounds." + +"Now, what is your own impression as to the young lady's--your wife's character?" + +The nobleman swung his glasses a little faster and stared down into the fire. "You see, Mr. Holmes," said he, "my wife was twenty before her father became a rich man. During that time she ran free in a mining camp and wandered through woods or mountains, so that her education has come from Nature rather than from the schoolmaster. She is what we call in England a tomboy, with a strong nature, wild and free, unfettered by any sort of traditions. She is impetuous--volcanic, I was about to say. She is swift in making up her mind and fearless in carrying out her resolutions. On the other hand, I would not have given her the name which I have the honour to bear"--he gave a little stately cough--"had I not thought her to be at bottom a noble woman. I believe that she is capable of heroic self-sacrifice and that anything dishonourable would be repugnant to her." + +"Have you her photograph?" + +"I brought this with me." He opened a locket and showed us the full face of a very lovely woman. It was not a photograph but an ivory miniature, and the artist had brought out the full effect of the lustrous black hair, the large dark eyes, and the exquisite mouth. Holmes gazed long and earnestly at it. Then he closed the locket and handed it back to Lord St. Simon. + +"The young lady came to London, then, and you renewed your acquaintance?" + +"Yes, her father brought her over for this last London season. I met her several times, became engaged to her, and have now married her." + +"She brought, I understand, a considerable dowry?" + +"A fair dowry. Not more than is usual in my family." + +"And this, of course, remains to you, since the marriage is a fait accompli?" + +"I really have made no inquiries on the subject." + +"Very naturally not. Did you see Miss Doran on the day before the wedding?" + +"Yes." + +"Was she in good spirits?" + +"Never better. She kept talking of what we should do in our future lives." + +"Indeed! That is very interesting. And on the morning of the wedding?" + +"She was as bright as possible--at least until after the ceremony." + +"And did you observe any change in her then?" + +"Well, to tell the truth, I saw then the first signs that I had ever seen that her temper was just a little sharp. The incident however, was too trivial to relate and can have no possible bearing upon the case." + +"Pray let us have it, for all that." + +"Oh, it is childish. She dropped her bouquet as we went towards the vestry. She was passing the front pew at the time, and it fell over into the pew. There was a moment's delay, but the gentleman in the pew handed it up to her again, and it did not appear to be the worse for the fall. Yet when I spoke to her of the matter, she answered me abruptly; and in the carriage, on our way home, she seemed absurdly agitated over this trifling cause." + +"Indeed! You say that there was a gentleman in the pew. Some of the general public were present, then?" + +"Oh, yes. It is impossible to exclude them when the church is open." + +"This gentleman was not one of your wife's friends?" + +"No, no; I call him a gentleman by courtesy, but he was quite a common-looking person. I hardly noticed his appearance. But really I think that we are wandering rather far from the point." + +"Lady St. Simon, then, returned from the wedding in a less cheerful frame of mind than she had gone to it. What did she do on re-entering her father's house?" + +"I saw her in conversation with her maid." + +"And who is her maid?" + +"Alice is her name. She is an American and came from California with her." + +"A confidential servant?" + +"A little too much so. It seemed to me that her mistress allowed her to take great liberties. Still, of course, in America they look upon these things in a different way." + +"How long did she speak to this Alice?" + +"Oh, a few minutes. I had something else to think of." + +"You did not overhear what they said?" + +"Lady St. Simon said something about 'jumping a claim.' She was accustomed to use slang of the kind. I have no idea what she meant." + +"American slang is very expressive sometimes. And what did your wife do when she finished speaking to her maid?" + +"She walked into the breakfast-room." + +"On your arm?" + +"No, alone. She was very independent in little matters like that. Then, after we had sat down for ten minutes or so, she rose hurriedly, muttered some words of apology, and left the room. She never came back." + +"But this maid, Alice, as I understand, deposes that she went to her room, covered her bride's dress with a long ulster, put on a bonnet, and went out." + +"Quite so. And she was afterwards seen walking into Hyde Park in company with Flora Millar, a woman who is now in custody, and who had already made a disturbance at Mr. Doran's house that morning." + +"Ah, yes. I should like a few particulars as to this young lady, and your relations to her." + +Lord St. Simon shrugged his shoulders and raised his eyebrows. "We have been on a friendly footing for some years--I may say on a very friendly footing. She used to be at the Allegro. I have not treated her ungenerously, and she had no just cause of complaint against me, but you know what women are, Mr. Holmes. Flora was a dear little thing, but exceedingly hot-headed and devotedly attached to me. She wrote me dreadful letters when she heard that I was about to be married, and, to tell the truth, the reason why I had the marriage celebrated so quietly was that I feared lest there might be a scandal in the church. She came to Mr. Doran's door just after we returned, and she endeavoured to push her way in, uttering very abusive expressions towards my wife, and even threatening her, but I had foreseen the possibility of something of the sort, and I had two police fellows there in private clothes, who soon pushed her out again. She was quiet when she saw that there was no good in making a row." + +"Did your wife hear all this?" + +"No, thank goodness, she did not." + +"And she was seen walking with this very woman afterwards?" + +"Yes. That is what Mr. Lestrade, of Scotland Yard, looks upon as so serious. It is thought that Flora decoyed my wife out and laid some terrible trap for her." + +"Well, it is a possible supposition." + +"You think so, too?" + +"I did not say a probable one. But you do not yourself look upon this as likely?" + +"I do not think Flora would hurt a fly." + +"Still, jealousy is a strange transformer of characters. Pray what is your own theory as to what took place?" + +"Well, really, I came to seek a theory, not to propound one. I have given you all the facts. Since you ask me, however, I may say that it has occurred to me as possible that the excitement of this affair, the consciousness that she had made so immense a social stride, had the effect of causing some little nervous disturbance in my wife." + +"In short, that she had become suddenly deranged?" + +"Well, really, when I consider that she has turned her back--I will not say upon me, but upon so much that many have aspired to without success--I can hardly explain it in any other fashion." + +"Well, certainly that is also a conceivable hypothesis," said Holmes, smiling. "And now, Lord St. Simon, I think that I have nearly all my data. May I ask whether you were seated at the breakfast-table so that you could see out of the window?" + +"We could see the other side of the road and the Park." + +"Quite so. Then I do not think that I need to detain you longer. I shall communicate with you." + +"Should you be fortunate enough to solve this problem," said our client, rising. + +"I have solved it." + +"Eh? What was that?" + +"I say that I have solved it." + +"Where, then, is my wife?" + +"That is a detail which I shall speedily supply." + +Lord St. Simon shook his head. "I am afraid that it will take wiser heads than yours or mine," he remarked, and bowing in a stately, old-fashioned manner he departed. + +"It is very good of Lord St. Simon to honour my head by putting it on a level with his own," said Sherlock Holmes, laughing. "I think that I shall have a whisky and soda and a cigar after all this cross-questioning. I had formed my conclusions as to the case before our client came into the room." + +"My dear Holmes!" + +"I have notes of several similar cases, though none, as I remarked before, which were quite as prompt. My whole examination served to turn my conjecture into a certainty. Circumstantial evidence is occasionally very convincing, as when you find a trout in the milk, to quote Thoreau's example." + +"But I have heard all that you have heard." + +"Without, however, the knowledge of pre-existing cases which serves me so well. There was a parallel instance in Aberdeen some years back, and something on very much the same lines at Munich the year after the Franco-Prussian War. It is one of these cases--but, hullo, here is Lestrade! Good-afternoon, Lestrade! You will find an extra tumbler upon the sideboard, and there are cigars in the box." + +The official detective was attired in a pea-jacket and cravat, which gave him a decidedly nautical appearance, and he carried a black canvas bag in his hand. With a short greeting he seated himself and lit the cigar which had been offered to him. + +"What's up, then?" asked Holmes with a twinkle in his eye. "You look dissatisfied." + +"And I feel dissatisfied. It is this infernal St. Simon marriage case. I can make neither head nor tail of the business." + +"Really! You surprise me." + +"Who ever heard of such a mixed affair? Every clue seems to slip through my fingers. I have been at work upon it all day." + +"And very wet it seems to have made you," said Holmes laying his hand upon the arm of the pea-jacket. + +"Yes, I have been dragging the Serpentine." + +"In heaven's name, what for?" + +"In search of the body of Lady St. Simon." + +Sherlock Holmes leaned back in his chair and laughed heartily. + +"Have you dragged the basin of Trafalgar Square fountain?" he asked. + +"Why? What do you mean?" + +"Because you have just as good a chance of finding this lady in the one as in the other." + +Lestrade shot an angry glance at my companion. "I suppose you know all about it," he snarled. + +"Well, I have only just heard the facts, but my mind is made up." + +"Oh, indeed! Then you think that the Serpentine plays no part in the matter?" + +"I think it very unlikely." + +"Then perhaps you will kindly explain how it is that we found this in it?" He opened his bag as he spoke, and tumbled onto the floor a wedding-dress of watered silk, a pair of white satin shoes and a bride's wreath and veil, all discoloured and soaked in water. "There," said he, putting a new wedding-ring upon the top of the pile. "There is a little nut for you to crack, Master Holmes." + +"Oh, indeed!" said my friend, blowing blue rings into the air. "You dragged them from the Serpentine?" + +"No. They were found floating near the margin by a park-keeper. They have been identified as her clothes, and it seemed to me that if the clothes were there the body would not be far off." + +"By the same brilliant reasoning, every man's body is to be found in the neighbourhood of his wardrobe. And pray what did you hope to arrive at through this?" + +"At some evidence implicating Flora Millar in the disappearance." + +"I am afraid that you will find it difficult." + +"Are you, indeed, now?" cried Lestrade with some bitterness. "I am afraid, Holmes, that you are not very practical with your deductions and your inferences. You have made two blunders in as many minutes. This dress does implicate Miss Flora Millar." + +"And how?" + +"In the dress is a pocket. In the pocket is a card-case. In the card-case is a note. And here is the very note." He slapped it down upon the table in front of him. "Listen to this: 'You will see me when all is ready. Come at once. F. H. M.' Now my theory all along has been that Lady St. Simon was decoyed away by Flora Millar, and that she, with confederates, no doubt, was responsible for her disappearance. Here, signed with her initials, is the very note which was no doubt quietly slipped into her hand at the door and which lured her within their reach." + +"Very good, Lestrade," said Holmes, laughing. "You really are very fine indeed. Let me see it." He took up the paper in a listless way, but his attention instantly became riveted, and he gave a little cry of satisfaction. "This is indeed important," said he. + +"Ha! you find it so?" + +"Extremely so. I congratulate you warmly." + +Lestrade rose in his triumph and bent his head to look. "Why," he shrieked, "you're looking at the wrong side!" + +"On the contrary, this is the right side." + +"The right side? You're mad! Here is the note written in pencil over here." + +"And over here is what appears to be the fragment of a hotel bill, which interests me deeply." + +"There's nothing in it. I looked at it before," said Lestrade. " 'Oct. 4th, rooms 8s., breakfast 2s. 6d., cocktail 1s., lunch 2s. 6d., glass sherry, 8d.' I see nothing in that." + +"Very likely not. It is most important, all the same. As to the note, it is important also, or at least the initials are, so I congratulate you again." + +"I've wasted time enough," said Lestrade, rising. "I believe in hard work and not in sitting by the fire spinning fine theories. Good-day, Mr. Holmes, and we shall see which gets to the bottom of the matter first." He gathered up the garments, thrust them into the bag, and made for the door. + +"Just one hint to you, Lestrade," drawled Holmes before his rival vanished; "I will tell you the true solution of the matter. Lady St. Simon is a myth. There is not, and there never has been, any such person." + +Lestrade looked sadly at my companion. Then he turned to me, tapped his forehead three times, shook his head solemnly, and hurried away. + +He had hardly shut the door behind him when Holmes rose to put on his overcoat. "There is something in what the fellow says about outdoor work," he remarked, "so I think, Watson, that I must leave you to your papers for a little." + +It was after five o'clock when Sherlock Holmes left me, but I had no time to be lonely, for within an hour there arrived a confectioner's man with a very large flat box. This he unpacked with the help of a youth whom he had brought with him, and presently, to my very great astonishment, a quite epicurean little cold supper began to be laid out upon our humble lodging-house mahogany. There were a couple of brace of cold woodcock, a pheasant, a pate de foie gras pie with a group of ancient and cobwebby bottles. Having laid out all these luxuries, my two visitors vanished away, like the genii of the Arabian Nights, with no explanation save that the things had been paid for and were ordered to this address. + +Just before nine o'clock Sherlock Holmes stepped briskly into the room. His features were gravely set, but there was a light in his eye which made me think that he had not been disappointed in his conclusions. + +"They have laid the supper, then," he said, rubbing his hands. + +"You seem to expect company. They have laid for five." + +"Yes, I fancy we may have some company dropping in," said he. "I am surprised that Lord St. Simon has not already arrived. Ha! I fancy that I hear his step now upon the stairs." + +It was indeed our visitor of the afternoon who came bustling in, dangling his glasses more vigorously than ever, and with a very perturbed expression upon his aristocratic features. + +"My messenger reached you, then?" asked Holmes. + +"Yes, and I confess that the contents startled me beyond measure. Have you good authority for what you say?" + +"The best possible." + +Lord St. Simon sank into a chair and passed his hand over his forehead. + +"What will the Duke say," he murmured, "when he hears that one of the family has been subjected to such humiliation?" + +"It is the purest accident. I cannot allow that there is any humiliation." + +"Ah, you look on these things from another standpoint." + +"I fail to see that anyone is to blame. I can hardly see how the lady could have acted otherwise, though her abrupt method of doing it was undoubtedly to be regretted. Having no mother, she had no one to advise her at such a crisis." + +"It was a slight, sir, a public slight," said Lord St. Simon, tapping his fingers upon the table. + +"You must make allowance for this poor girl, placed in so unprecedented a position." + +"I will make no allowance. I am very angry indeed, and I have been shamefully used." + +"I think that I heard a ring," said Holmes. "Yes, there are steps on the landing. If I cannot persuade you to take a lenient view of the matter, Lord St. Simon, I have brought an advocate here who may be more successful." He opened the door and ushered in a lady and gentleman. "Lord St. Simon," said he "allow me to introduce you to Mr. and Mrs. Francis Hay Moulton. The lady, I think, you have already met." + +At the sight of these newcomers our client had sprung from his seat and stood very erect, with his eyes cast down and his hand thrust into the breast of his frock-coat, a picture of offended dignity. The lady had taken a quick step forward and had held out her hand to him, but he still refused to raise his eyes. It was as well for his resolution, perhaps, for her pleading face was one which it was hard to resist. + +"You're angry, Robert," said she. "Well, I guess you have every cause to be." + +"Pray make no apology to me," said Lord St. Simon bitterly. + +"Oh, yes, I know that I have treated you real bad and that I should have spoken to you before I went; but I was kind of rattled, and from the time when I saw Frank here again I just didn't know what I was doing or saying. I only wonder I didn't fall down and do a faint right there before the altar." + +"Perhaps, Mrs. Moulton, you would like my friend and me to leave the room while you explain this matter?" + +"If I may give an opinion," remarked the strange gentleman, "we've had just a little too much secrecy over this business already. For my part, I should like all Europe and America to hear the rights of it." He was a small, wiry, sunburnt man, clean-shaven, with a sharp face and alert manner. + +"Then I'll tell our story right away," said the lady. "Frank here and I met in '84, in McQuire's camp, near the Rockies, where Pa was working a claim. We were engaged to each other, Frank and I; but then one day father struck a rich pocket and made a pile, while poor Frank here had a claim that petered out and came to nothing. The richer Pa grew the poorer was Frank; so at last Pa wouldn't hear of our engagement lasting any longer, and he took me away to 'Frisco. Frank wouldn't throw up his hand, though; so he followed me there, and he saw me without Pa knowing anything about it. It would only have made him mad to know, so we just fixed it all up for ourselves. Frank said that he would go and make his pile, too, and never come back to claim me until he had as much as Pa. So then I promised to wait for him to the end of time and pledged myself not to marry anyone else while he lived. 'Why shouldn't we be married right away, then,' said he, 'and then I will feel sure of you; and I won't claim to be your husband until I come back?' Well, we talked it over, and he had fixed it all up so nicely, with a clergyman all ready in waiting, that we just did it right there; and then Frank went off to seek his fortune, and I went back to Pa. + +"The next I heard of Frank was that he was in Montana, and then he went prospecting in Arizona, and then I heard of him from New Mexico. After that came a long newspaper story about how a miners' camp had been attacked by Apache Indians, and there was my Frank's name among the killed. I fainted dead away, and I was very sick for months after. Pa thought I had a decline and took me to half the doctors in 'Frisco. Not a word of news came for a year and more, so that I never doubted that Frank was really dead. Then Lord St. Simon came to 'Frisco, and we came to London, and a marriage was arranged, and Pa was very pleased, but I felt all the time that no man on this earth would ever take the place in my heart that had been given to my poor Frank. + +"Still, if I had married Lord St. Simon, of course I'd have done my duty by him. We can't command our love, but we can our actions. I went to the altar with him with the intention to make him just as good a wife as it was in me to be. But you may imagine what I felt when, just as I came to the altar rails, I glanced back and saw Frank standing and looking at me out of the first pew. I thought it was his ghost at first; but when I looked again there he was still, with a kind of question in his eyes, as if to ask me whether I were glad or sorry to see him. I wonder I didn't drop. I know that everything was turning round, and the words of the clergyman were just like the buzz of a bee in my ear. I didn't know what to do. Should I stop the service and make a scene in the church? I glanced at him again, and he seemed to know what I was thinking, for he raised his finger to his lips to tell me to be still. Then I saw him scribble on a piece of paper, and I knew that he was writing me a note. As I passed his pew on the way out I dropped my bouquet over to him, and he slipped the note into my hand when he returned me the flowers. It was only a line asking me to join him when he made the sign to me to do so. Of course I never doubted for a moment that my first duty was now to him, and I determined to do just whatever he might direct. + +"When I got back I told my maid, who had known him in California, and had always been his friend. I ordered her to say nothing, but to get a few things packed and my ulster ready. I know I ought to have spoken to Lord St. Simon, but it was dreadful hard before his mother and all those great people. I just made up my mind to run away and explain afterwards. I hadn't been at the table ten minutes before I saw Frank out of the window at the other side of the road. He beckoned to me and then began walking into the Park. I slipped out, put on my things, and followed him. Some woman came talking something or other about Lord St. Simon to me--seemed to me from the little I heard as if he had a little secret of his own before marriage also--but I managed to get away from her and soon overtook Frank. We got into a cab together, and away we drove to some lodgings he had taken in Gordon Square, and that was my true wedding after all those years of waiting. Frank had been a prisoner among the Apaches, had escaped, came on to 'Frisco, found that I had given him up for dead and had gone to England, followed me there, and had come upon me at last on the very morning of my second wedding." + +"I saw it in a paper," explained the American. "It gave the name and the church but not where the lady lived." + +"Then we had a talk as to what we should do, and Frank was all for openness, but I was so ashamed of it all that I felt as if I should like to vanish away and never see any of them again--just sending a line to Pa, perhaps, to show him that I was alive. It was awful to me to think of all those lords and ladies sitting round that breakfast-table and waiting for me to come back. So Frank took my wedding-clothes and things and made a bundle of them, so that I should not be traced, and dropped them away somewhere where no one could find them. It is likely that we should have gone on to Paris to-morrow, only that this good gentleman, Mr. Holmes, came round to us this evening, though how he found us is more than I can think, and he showed us very clearly and kindly that I was wrong and that Frank was right, and that we should be putting ourselves in the wrong if we were so secret. Then he offered to give us a chance of talking to Lord St. Simon alone, and so we came right away round to his rooms at once. Now, Robert, you have heard it all, and I am very sorry if I have given you pain, and I hope that you do not think very meanly of me." + +Lord St. Simon had by no means relaxed his rigid attitude, but had listened with a frowning brow and a compressed lip to this long narrative. + +"Excuse me," he said, "but it is not my custom to discuss my most intimate personal affairs in this public manner." + +"Then you won't forgive me? You won't shake hands before I go?" + +"Oh, certainly, if it would give you any pleasure." He put out his hand and coldly grasped that which she extended to him. + +"I had hoped," suggested Holmes, "that you would have joined us in a friendly supper." + +"I think that there you ask a little too much," responded his Lordship. "I may be forced to acquiesce in these recent developments, but I can hardly be expected to make merry over them. I think that with your permission I will now wish you all a very good-night." He included us all in a sweeping bow and stalked out of the room. + +"Then I trust that you at least will honour me with your company," said Sherlock Holmes. "It is always a joy to meet an American, Mr. Moulton, for I am one of those who believe that the folly of a monarch and the blundering of a minister in far-gone years will not prevent our children from being some day citizens of the same world-wide country under a flag which shall be a quartering of the Union Jack with the Stars and Stripes." + +"The case has been an interesting one," remarked Holmes when our visitors had left us, "because it serves to show very clearly how simple the explanation may be of an affair which at first sight seems to be almost inexplicable. Nothing could be more natural than the sequence of events as narrated by this lady, and nothing stranger than the result when viewed, for instance, by Mr. Lestrade of Scotland Yard." + +"You were not yourself at fault at all, then?" + +"From the first, two facts were very obvious to me, the one that the lady had been quite willing to undergo the wedding ceremony, the other that she had repented of it within a few minutes of returning home. Obviously something had occurred during the morning, then, to cause her to change her mind. What could that something be? She could not have spoken to anyone when she was out, for she had been in the company of the bridegroom. Had she seen someone, then? If she had, it must be someone from America because she had spent so short a time in this country that she could hardly have allowed anyone to acquire so deep an influence over her that the mere sight of him would induce her to change her plans so completely. You see we have already arrived, by a process of exclusion, at the idea that she might have seen an American. Then who could this American be, and why should he possess so much influence over her? It might be a lover; it might be a husband. Her young womanhood had, I knew, been spent in rough scenes and under strange conditions. So far I had got before I ever heard Lord St. Simon's narrative. When he told us of a man in a pew, of the change in the bride's manner, of so transparent a device for obtaining a note as the dropping of a bouquet, of her resort to her confidential maid, and of her very significant allusion to claim-jumping--which in miners' parlance means taking possession of that which another person has a prior claim to--the whole situation became absolutely clear. She had gone off with a man, and the man was either a lover or was a previous husband--the chances being in favour of the latter." + +"And how in the world did you find them?" + +"It might have been difficult, but friend Lestrade held information in his hands the value of which he did not himself know. The initials were, of course, of the highest importance, but more valuable still was it to know that within a week he had settled his bill at one of the most select London hotels." + +"How did you deduce the select?" + +"By the select prices. Eight shillings for a bed and eightpence for a glass of sherry pointed to one of the most expensive hotels. There are not many in London which charge at that rate. In the second one which I visited in Northumberland Avenue, I learned by an inspection of the book that Francis H. Moulton, an American gentleman, had left only the day before, and on looking over the entries against him, I came upon the very items which I had seen in the duplicate bill. His letters were to be forwarded to 226 Gordon Square; so thither I travelled, and being fortunate enough to find the loving couple at home, I ventured to give them some paternal advice and to point out to them that it would be better in every way that they should make their position a little clearer both to the general public and to Lord St. Simon in particular. I invited them to meet him here, and, as you see, I made him keep the appointment." + +"But with no very good result," I remarked. "His conduct was certainly not very gracious." + +"Ah, Watson," said Holmes, smiling, "perhaps you would not be very gracious either, if, after all the trouble of wooing and wedding, you found yourself deprived in an instant of wife and of fortune. I think that we may judge Lord St. Simon very mercifully and thank our stars that we are never likely to find ourselves in the same position. Draw your chair up and hand me my violin, for the only problem we have still to solve is how to while away these bleak autumnal evenings." + +XI. THE ADVENTURE OF THE BERYL CORONET + + +"Holmes," said I as I stood one morning in our bow-window looking down the street, "here is a madman coming along. It seems rather sad that his relatives should allow him to come out alone." + +My friend rose lazily from his armchair and stood with his hands in the pockets of his dressing-gown, looking over my shoulder. It was a bright, crisp February morning, and the snow of the day before still lay deep upon the ground, shimmering brightly in the wintry sun. Down the centre of Baker Street it had been ploughed into a brown crumbly band by the traffic, but at either side and on the heaped-up edges of the foot-paths it still lay as white as when it fell. The grey pavement had been cleaned and scraped, but was still dangerously slippery, so that there were fewer passengers than usual. Indeed, from the direction of the Metropolitan Station no one was coming save the single gentleman whose eccentric conduct had drawn my attention. + +He was a man of about fifty, tall, portly, and imposing, with a massive, strongly marked face and a commanding figure. He was dressed in a sombre yet rich style, in black frock-coat, shining hat, neat brown gaiters, and well-cut pearl-grey trousers. Yet his actions were in absurd contrast to the dignity of his dress and features, for he was running hard, with occasional little springs, such as a weary man gives who is little accustomed to set any tax upon his legs. As he ran he jerked his hands up and down, waggled his head, and writhed his face into the most extraordinary contortions. + +"What on earth can be the matter with him?" I asked. "He is looking up at the numbers of the houses." + +"I believe that he is coming here," said Holmes, rubbing his hands. + +"Here?" + +"Yes; I rather think he is coming to consult me professionally. I think that I recognise the symptoms. Ha! did I not tell you?" As he spoke, the man, puffing and blowing, rushed at our door and pulled at our bell until the whole house resounded with the clanging. + +A few moments later he was in our room, still puffing, still gesticulating, but with so fixed a look of grief and despair in his eyes that our smiles were turned in an instant to horror and pity. For a while he could not get his words out, but swayed his body and plucked at his hair like one who has been driven to the extreme limits of his reason. Then, suddenly springing to his feet, he beat his head against the wall with such force that we both rushed upon him and tore him away to the centre of the room. Sherlock Holmes pushed him down into the easy-chair and, sitting beside him, patted his hand and chatted with him in the easy, soothing tones which he knew so well how to employ. + +"You have come to me to tell your story, have you not?" said he. "You are fatigued with your haste. Pray wait until you have recovered yourself, and then I shall be most happy to look into any little problem which you may submit to me." + +The man sat for a minute or more with a heaving chest, fighting against his emotion. Then he passed his handkerchief over his brow, set his lips tight, and turned his face towards us. + +"No doubt you think me mad?" said he. + +"I see that you have had some great trouble," responded Holmes. + +"God knows I have!--a trouble which is enough to unseat my reason, so sudden and so terrible is it. Public disgrace I might have faced, although I am a man whose character has never yet borne a stain. Private affliction also is the lot of every man; but the two coming together, and in so frightful a form, have been enough to shake my very soul. Besides, it is not I alone. The very noblest in the land may suffer unless some way be found out of this horrible affair." + +"Pray compose yourself, sir," said Holmes, "and let me have a clear account of who you are and what it is that has befallen you." + +"My name," answered our visitor, "is probably familiar to your ears. I am Alexander Holder, of the banking firm of Holder & Stevenson, of Threadneedle Street." + +The name was indeed well known to us as belonging to the senior partner in the second largest private banking concern in the City of London. What could have happened, then, to bring one of the foremost citizens of London to this most pitiable pass? We waited, all curiosity, until with another effort he braced himself to tell his story. + +"I feel that time is of value," said he; "that is why I hastened here when the police inspector suggested that I should secure your co-operation. I came to Baker Street by the Underground and hurried from there on foot, for the cabs go slowly through this snow. That is why I was so out of breath, for I am a man who takes very little exercise. I feel better now, and I will put the facts before you as shortly and yet as clearly as I can. + +"It is, of course, well known to you that in a successful banking business as much depends upon our being able to find remunerative investments for our funds as upon our increasing our connection and the number of our depositors. One of our most lucrative means of laying out money is in the shape of loans, where the security is unimpeachable. We have done a good deal in this direction during the last few years, and there are many noble families to whom we have advanced large sums upon the security of their pictures, libraries, or plate. + +"Yesterday morning I was seated in my office at the bank when a card was brought in to me by one of the clerks. I started when I saw the name, for it was that of none other than--well, perhaps even to you I had better say no more than that it was a name which is a household word all over the earth--one of the highest, noblest, most exalted names in England. I was overwhelmed by the honour and attempted, when he entered, to say so, but he plunged at once into business with the air of a man who wishes to hurry quickly through a disagreeable task. + +" 'Mr. Holder,' said he, 'I have been informed that you are in the habit of advancing money.' + +" 'The firm does so when the security is good.' I answered. + +" 'It is absolutely essential to me,' said he, 'that I should have $50,000 at once. I could, of course, borrow so trifling a sum ten times over from my friends, but I much prefer to make it a matter of business and to carry out that business myself. In my position you can readily understand that it is unwise to place one's self under obligations.' + +" 'For how long, may I ask, do you want this sum?' I asked. + +" 'Next Monday I have a large sum due to me, and I shall then most certainly repay what you advance, with whatever interest you think it right to charge. But it is very essential to me that the money should be paid at once.' + +" 'I should be happy to advance it without further parley from my own private purse,' said I, 'were it not that the strain would be rather more than it could bear. If, on the other hand, I am to do it in the name of the firm, then in justice to my partner I must insist that, even in your case, every businesslike precaution should be taken.' + +" 'I should much prefer to have it so,' said he, raising up a square, black morocco case which he had laid beside his chair. 'You have doubtless heard of the Beryl Coronet?' + +" 'One of the most precious public possessions of the empire,' said I. + +" 'Precisely.' He opened the case, and there, imbedded in soft, flesh-coloured velvet, lay the magnificent piece of jewellery which he had named. 'There are thirty-nine enormous beryls,' said he, 'and the price of the gold chasing is incalculable. The lowest estimate would put the worth of the coronet at double the sum which I have asked. I am prepared to leave it with you as my security.' + +"I took the precious case into my hands and looked in some perplexity from it to my illustrious client. + +" 'You doubt its value?' he asked. + +" 'Not at all. I only doubt--' + +" 'The propriety of my leaving it. You may set your mind at rest about that. I should not dream of doing so were it not absolutely certain that I should be able in four days to reclaim it. It is a pure matter of form. Is the security sufficient?' + +" 'Ample.' + +" 'You understand, Mr. Holder, that I am giving you a strong proof of the confidence which I have in you, founded upon all that I have heard of you. I rely upon you not only to be discreet and to refrain from all gossip upon the matter but, above all, to preserve this coronet with every possible precaution because I need not say that a great public scandal would be caused if any harm were to befall it. Any injury to it would be almost as serious as its complete loss, for there are no beryls in the world to match these, and it would be impossible to replace them. I leave it with you, however, with every confidence, and I shall call for it in person on Monday morning.' + +"Seeing that my client was anxious to leave, I said no more but, calling for my cashier, I ordered him to pay over fifty $1000 notes. When I was alone once more, however, with the precious case lying upon the table in front of me, I could not but think with some misgivings of the immense responsibility which it entailed upon me. There could be no doubt that, as it was a national possession, a horrible scandal would ensue if any misfortune should occur to it. I already regretted having ever consented to take charge of it. However, it was too late to alter the matter now, so I locked it up in my private safe and turned once more to my work. + +"When evening came I felt that it would be an imprudence to leave so precious a thing in the office behind me. Bankers' safes had been forced before now, and why should not mine be? If so, how terrible would be the position in which I should find myself! I determined, therefore, that for the next few days I would always carry the case backward and forward with me, so that it might never be really out of my reach. With this intention, I called a cab and drove out to my house at Streatham, carrying the jewel with me. I did not breathe freely until I had taken it upstairs and locked it in the bureau of my dressing-room. + +"And now a word as to my household, Mr. Holmes, for I wish you to thoroughly understand the situation. My groom and my page sleep out of the house, and may be set aside altogether. I have three maid-servants who have been with me a number of years and whose absolute reliability is quite above suspicion. Another, Lucy Parr, the second waiting-maid, has only been in my service a few months. She came with an excellent character, however, and has always given me satisfaction. She is a very pretty girl and has attracted admirers who have occasionally hung about the place. That is the only drawback which we have found to her, but we believe her to be a thoroughly good girl in every way. + +"So much for the servants. My family itself is so small that it will not take me long to describe it. I am a widower and have an only son, Arthur. He has been a disappointment to me, Mr. Holmes--a grievous disappointment. I have no doubt that I am myself to blame. People tell me that I have spoiled him. Very likely I have. When my dear wife died I felt that he was all I had to love. I could not bear to see the smile fade even for a moment from his face. I have never denied him a wish. Perhaps it would have been better for both of us had I been sterner, but I meant it for the best. + +"It was naturally my intention that he should succeed me in my business, but he was not of a business turn. He was wild, wayward, and, to speak the truth, I could not trust him in the handling of large sums of money. When he was young he became a member of an aristocratic club, and there, having charming manners, he was soon the intimate of a number of men with long purses and expensive habits. He learned to play heavily at cards and to squander money on the turf, until he had again and again to come to me and implore me to give him an advance upon his allowance, that he might settle his debts of honour. He tried more than once to break away from the dangerous company which he was keeping, but each time the influence of his friend, Sir George Burnwell, was enough to draw him back again. + +"And, indeed, I could not wonder that such a man as Sir George Burnwell should gain an influence over him, for he has frequently brought him to my house, and I have found myself that I could hardly resist the fascination of his manner. He is older than Arthur, a man of the world to his finger-tips, one who had been everywhere, seen everything, a brilliant talker, and a man of great personal beauty. Yet when I think of him in cold blood, far away from the glamour of his presence, I am convinced from his cynical speech and the look which I have caught in his eyes that he is one who should be deeply distrusted. So I think, and so, too, thinks my little Mary, who has a woman's quick insight into character. + +"And now there is only she to be described. She is my niece; but when my brother died five years ago and left her alone in the world I adopted her, and have looked upon her ever since as my daughter. She is a sunbeam in my house--sweet, loving, beautiful, a wonderful manager and housekeeper, yet as tender and quiet and gentle as a woman could be. She is my right hand. I do not know what I could do without her. In only one matter has she ever gone against my wishes. Twice my boy has asked her to marry him, for he loves her devotedly, but each time she has refused him. I think that if anyone could have drawn him into the right path it would have been she, and that his marriage might have changed his whole life; but now, alas! it is too late--forever too late! + +"Now, Mr. Holmes, you know the people who live under my roof, and I shall continue with my miserable story. + +"When we were taking coffee in the drawing-room that night after dinner, I told Arthur and Mary my experience, and of the precious treasure which we had under our roof, suppressing only the name of my client. Lucy Parr, who had brought in the coffee, had, I am sure, left the room; but I cannot swear that the door was closed. Mary and Arthur were much interested and wished to see the famous coronet, but I thought it better not to disturb it. + +" 'Where have you put it?' asked Arthur. + +" 'In my own bureau.' + +" 'Well, I hope to goodness the house won't be burgled during the night.' said he. + +" 'It is locked up,' I answered. + +" 'Oh, any old key will fit that bureau. When I was a youngster I have opened it myself with the key of the box-room cupboard.' + +"He often had a wild way of talking, so that I thought little of what he said. He followed me to my room, however, that night with a very grave face. + +" 'Look here, dad,' said he with his eyes cast down, 'can you let me have $200?' + +" 'No, I cannot!' I answered sharply. 'I have been far too generous with you in money matters.' + +" 'You have been very kind,' said he, 'but I must have this money, or else I can never show my face inside the club again.' + +" 'And a very good thing, too!' I cried. + +" 'Yes, but you would not have me leave it a dishonoured man,' said he. 'I could not bear the disgrace. I must raise the money in some way, and if you will not let me have it, then I must try other means.' + +"I was very angry, for this was the third demand during the month. 'You shall not have a farthing from me,' I cried, on which he bowed and left the room without another word. + +"When he was gone I unlocked my bureau, made sure that my treasure was safe, and locked it again. Then I started to go round the house to see that all was secure--a duty which I usually leave to Mary but which I thought it well to perform myself that night. As I came down the stairs I saw Mary herself at the side window of the hall, which she closed and fastened as I approached. + +" 'Tell me, dad,' said she, looking, I thought, a little disturbed, 'did you give Lucy, the maid, leave to go out to-night?' + +" 'Certainly not.' + +" 'She came in just now by the back door. I have no doubt that she has only been to the side gate to see someone, but I think that it is hardly safe and should be stopped.' + +" 'You must speak to her in the morning, or I will if you prefer it. Are you sure that everything is fastened?' + +" 'Quite sure, dad.' + +" 'Then, good-night.' I kissed her and went up to my bedroom again, where I was soon asleep. + +"I am endeavouring to tell you everything, Mr. Holmes, which may have any bearing upon the case, but I beg that you will question me upon any point which I do not make clear." + +"On the contrary, your statement is singularly lucid." + +"I come to a part of my story now in which I should wish to be particularly so. I am not a very heavy sleeper, and the anxiety in my mind tended, no doubt, to make me even less so than usual. About two in the morning, then, I was awakened by some sound in the house. It had ceased ere I was wide awake, but it had left an impression behind it as though a window had gently closed somewhere. I lay listening with all my ears. Suddenly, to my horror, there was a distinct sound of footsteps moving softly in the next room. I slipped out of bed, all palpitating with fear, and peeped round the corner of my dressing-room door. + +" 'Arthur!' I screamed, 'you villain! you thief! How dare you touch that coronet?' + +"The gas was half up, as I had left it, and my unhappy boy, dressed only in his shirt and trousers, was standing beside the light, holding the coronet in his hands. He appeared to be wrenching at it, or bending it with all his strength. At my cry he dropped it from his grasp and turned as pale as death. I snatched it up and examined it. One of the gold corners, with three of the beryls in it, was missing. + +" 'You blackguard!' I shouted, beside myself with rage. 'You have destroyed it! You have dishonoured me forever! Where are the jewels which you have stolen?' + +" 'Stolen!' he cried. + +" 'Yes, thief!' I roared, shaking him by the shoulder. + +" 'There are none missing. There cannot be any missing,' said he. + +" 'There are three missing. And you know where they are. Must I call you a liar as well as a thief? Did I not see you trying to tear off another piece?' + +" 'You have called me names enough,' said he, 'I will not stand it any longer. I shall not say another word about this business, since you have chosen to insult me. I will leave your house in the morning and make my own way in the world.' + +" 'You shall leave it in the hands of the police!' I cried half-mad with grief and rage. 'I shall have this matter probed to the bottom.' + +" 'You shall learn nothing from me,' said he with a passion such as I should not have thought was in his nature. 'If you choose to call the police, let the police find what they can.' + +"By this time the whole house was astir, for I had raised my voice in my anger. Mary was the first to rush into my room, and, at the sight of the coronet and of Arthur's face, she read the whole story and, with a scream, fell down senseless on the ground. I sent the house-maid for the police and put the investigation into their hands at once. When the inspector and a constable entered the house, Arthur, who had stood sullenly with his arms folded, asked me whether it was my intention to charge him with theft. I answered that it had ceased to be a private matter, but had become a public one, since the ruined coronet was national property. I was determined that the law should have its way in everything. + +" 'At least,' said he, 'you will not have me arrested at once. It would be to your advantage as well as mine if I might leave the house for five minutes.' + +" 'That you may get away, or perhaps that you may conceal what you have stolen,' said I. And then, realising the dreadful position in which I was placed, I implored him to remember that not only my honour but that of one who was far greater than I was at stake; and that he threatened to raise a scandal which would convulse the nation. He might avert it all if he would but tell me what he had done with the three missing stones. + +" 'You may as well face the matter,' said I; 'you have been caught in the act, and no confession could make your guilt more heinous. If you but make such reparation as is in your power, by telling us where the beryls are, all shall be forgiven and forgotten.' + +" 'Keep your forgiveness for those who ask for it,' he answered, turning away from me with a sneer. I saw that he was too hardened for any words of mine to influence him. There was but one way for it. I called in the inspector and gave him into custody. A search was made at once not only of his person but of his room and of every portion of the house where he could possibly have concealed the gems; but no trace of them could be found, nor would the wretched boy open his mouth for all our persuasions and our threats. This morning he was removed to a cell, and I, after going through all the police formalities, have hurried round to you to implore you to use your skill in unravelling the matter. The police have openly confessed that they can at present make nothing of it. You may go to any expense which you think necessary. I have already offered a reward of $1000. My God, what shall I do! I have lost my honour, my gems, and my son in one night. Oh, what shall I do!" + +He put a hand on either side of his head and rocked himself to and fro, droning to himself like a child whose grief has got beyond words. + +Sherlock Holmes sat silent for some few minutes, with his brows knitted and his eyes fixed upon the fire. + +"Do you receive much company?" he asked. + +"None save my partner with his family and an occasional friend of Arthur's. Sir George Burnwell has been several times lately. No one else, I think." + +"Do you go out much in society?" + +"Arthur does. Mary and I stay at home. We neither of us care for it." + +"That is unusual in a young girl." + +"She is of a quiet nature. Besides, she is not so very young. She is four-and-twenty." + +"This matter, from what you say, seems to have been a shock to her also." + +"Terrible! She is even more affected than I." + +"You have neither of you any doubt as to your son's guilt?" + +"How can we have when I saw him with my own eyes with the coronet in his hands." + +"I hardly consider that a conclusive proof. Was the remainder of the coronet at all injured?" + +"Yes, it was twisted." + +"Do you not think, then, that he might have been trying to straighten it?" + +"God bless you! You are doing what you can for him and for me. But it is too heavy a task. What was he doing there at all? If his purpose were innocent, why did he not say so?" + +"Precisely. And if it were guilty, why did he not invent a lie? His silence appears to me to cut both ways. There are several singular points about the case. What did the police think of the noise which awoke you from your sleep?" + +"They considered that it might be caused by Arthur's closing his bedroom door." + +"A likely story! As if a man bent on felony would slam his door so as to wake a household. What did they say, then, of the disappearance of these gems?" + +"They are still sounding the planking and probing the furniture in the hope of finding them." + +"Have they thought of looking outside the house?" + +"Yes, they have shown extraordinary energy. The whole garden has already been minutely examined." + +"Now, my dear sir," said Holmes. "is it not obvious to you now that this matter really strikes very much deeper than either you or the police were at first inclined to think? It appeared to you to be a simple case; to me it seems exceedingly complex. Consider what is involved by your theory. You suppose that your son came down from his bed, went, at great risk, to your dressing-room, opened your bureau, took out your coronet, broke off by main force a small portion of it, went off to some other place, concealed three gems out of the thirty-nine, with such skill that nobody can find them, and then returned with the other thirty-six into the room in which he exposed himself to the greatest danger of being discovered. I ask you now, is such a theory tenable?" + +"But what other is there?" cried the banker with a gesture of despair. "If his motives were innocent, why does he not explain them?" + +"It is our task to find that out," replied Holmes; "so now, if you please, Mr. Holder, we will set off for Streatham together, and devote an hour to glancing a little more closely into details." + +My friend insisted upon my accompanying them in their expedition, which I was eager enough to do, for my curiosity and sympathy were deeply stirred by the story to which we had listened. I confess that the guilt of the banker's son appeared to me to be as obvious as it did to his unhappy father, but still I had such faith in Holmes' judgment that I felt that there must be some grounds for hope as long as he was dissatisfied with the accepted explanation. He hardly spoke a word the whole way out to the southern suburb, but sat with his chin upon his breast and his hat drawn over his eyes, sunk in the deepest thought. Our client appeared to have taken fresh heart at the little glimpse of hope which had been presented to him, and he even broke into a desultory chat with me over his business affairs. A short railway journey and a shorter walk brought us to Fairbank, the modest residence of the great financier. + +Fairbank was a good-sized square house of white stone, standing back a little from the road. A double carriage-sweep, with a snow-clad lawn, stretched down in front to two large iron gates which closed the entrance. On the right side was a small wooden thicket, which led into a narrow path between two neat hedges stretching from the road to the kitchen door, and forming the tradesmen's entrance. On the left ran a lane which led to the stables, and was not itself within the grounds at all, being a public, though little used, thoroughfare. Holmes left us standing at the door and walked slowly all round the house, across the front, down the tradesmen's path, and so round by the garden behind into the stable lane. So long was he that Mr. Holder and I went into the dining-room and waited by the fire until he should return. We were sitting there in silence when the door opened and a young lady came in. She was rather above the middle height, slim, with dark hair and eyes, which seemed the darker against the absolute pallor of her skin. I do not think that I have ever seen such deadly paleness in a woman's face. Her lips, too, were bloodless, but her eyes were flushed with crying. As she swept silently into the room she impressed me with a greater sense of grief than the banker had done in the morning, and it was the more striking in her as she was evidently a woman of strong character, with immense capacity for self-restraint. Disregarding my presence, she went straight to her uncle and passed her hand over his head with a sweet womanly caress. + +"You have given orders that Arthur should be liberated, have you not, dad?" she asked. + +"No, no, my girl, the matter must be probed to the bottom." + +"But I am so sure that he is innocent. You know what woman's instincts are. I know that he has done no harm and that you will be sorry for having acted so harshly." + +"Why is he silent, then, if he is innocent?" + +"Who knows? Perhaps because he was so angry that you should suspect him." + +"How could I help suspecting him, when I actually saw him with the coronet in his hand?" + +"Oh, but he had only picked it up to look at it. Oh, do, do take my word for it that he is innocent. Let the matter drop and say no more. It is so dreadful to think of our dear Arthur in prison!" + +"I shall never let it drop until the gems are found--never, Mary! Your affection for Arthur blinds you as to the awful consequences to me. Far from hushing the thing up, I have brought a gentleman down from London to inquire more deeply into it." + +"This gentleman?" she asked, facing round to me. + +"No, his friend. He wished us to leave him alone. He is round in the stable lane now." + +"The stable lane?" She raised her dark eyebrows. "What can he hope to find there? Ah! this, I suppose, is he. I trust, sir, that you will succeed in proving, what I feel sure is the truth, that my cousin Arthur is innocent of this crime." + +"I fully share your opinion, and I trust, with you, that we may prove it," returned Holmes, going back to the mat to knock the snow from his shoes. "I believe I have the honour of addressing Miss Mary Holder. Might I ask you a question or two?" + +"Pray do, sir, if it may help to clear this horrible affair up." + +"You heard nothing yourself last night?" + +"Nothing, until my uncle here began to speak loudly. I heard that, and I came down." + +"You shut up the windows and doors the night before. Did you fasten all the windows?" + +"Yes." + +"Were they all fastened this morning?" + +"Yes." + +"You have a maid who has a sweetheart? I think that you remarked to your uncle last night that she had been out to see him?" + +"Yes, and she was the girl who waited in the drawing-room, and who may have heard uncle's remarks about the coronet." + +"I see. You infer that she may have gone out to tell her sweetheart, and that the two may have planned the robbery." + +"But what is the good of all these vague theories," cried the banker impatiently, "when I have told you that I saw Arthur with the coronet in his hands?" + +"Wait a little, Mr. Holder. We must come back to that. About this girl, Miss Holder. You saw her return by the kitchen door, I presume?" + +"Yes; when I went to see if the door was fastened for the night I met her slipping in. I saw the man, too, in the gloom." + +"Do you know him?" + +"Oh, yes! he is the green-grocer who brings our vegetables round. His name is Francis Prosper." + +"He stood," said Holmes, "to the left of the door--that is to say, farther up the path than is necessary to reach the door?" + +"Yes, he did." + +"And he is a man with a wooden leg?" + +Something like fear sprang up in the young lady's expressive black eyes. "Why, you are like a magician," said she. "How do you know that?" She smiled, but there was no answering smile in Holmes' thin, eager face. + +"I should be very glad now to go upstairs," said he. "I shall probably wish to go over the outside of the house again. Perhaps I had better take a look at the lower windows before I go up." + +He walked swiftly round from one to the other, pausing only at the large one which looked from the hall onto the stable lane. This he opened and made a very careful examination of the sill with his powerful magnifying lens. "Now we shall go upstairs," said he at last. + +The banker's dressing-room was a plainly furnished little chamber, with a grey carpet, a large bureau, and a long mirror. Holmes went to the bureau first and looked hard at the lock. + +"Which key was used to open it?" he asked. + +"That which my son himself indicated--that of the cupboard of the lumber-room." + +"Have you it here?" + +"That is it on the dressing-table." + +Sherlock Holmes took it up and opened the bureau. + +"It is a noiseless lock," said he. "It is no wonder that it did not wake you. This case, I presume, contains the coronet. We must have a look at it." He opened the case, and taking out the diadem he laid it upon the table. It was a magnificent specimen of the jeweller's art, and the thirty-six stones were the finest that I have ever seen. At one side of the coronet was a cracked edge, where a corner holding three gems had been torn away. + +"Now, Mr. Holder," said Holmes, "here is the corner which corresponds to that which has been so unfortunately lost. Might I beg that you will break it off." + +The banker recoiled in horror. "I should not dream of trying," said he. + +"Then I will." Holmes suddenly bent his strength upon it, but without result. "I feel it give a little," said he; "but, though I am exceptionally strong in the fingers, it would take me all my time to break it. An ordinary man could not do it. Now, what do you think would happen if I did break it, Mr. Holder? There would be a noise like a pistol shot. Do you tell me that all this happened within a few yards of your bed and that you heard nothing of it?" + +"I do not know what to think. It is all dark to me." + +"But perhaps it may grow lighter as we go. What do you think, Miss Holder?" + +"I confess that I still share my uncle's perplexity." + +"Your son had no shoes or slippers on when you saw him?" + +"He had nothing on save only his trousers and shirt." + +"Thank you. We have certainly been favoured with extraordinary luck during this inquiry, and it will be entirely our own fault if we do not succeed in clearing the matter up. With your permission, Mr. Holder, I shall now continue my investigations outside." + +He went alone, at his own request, for he explained that any unnecessary footmarks might make his task more difficult. For an hour or more he was at work, returning at last with his feet heavy with snow and his features as inscrutable as ever. + +"I think that I have seen now all that there is to see, Mr. Holder," said he; "I can serve you best by returning to my rooms." + +"But the gems, Mr. Holmes. Where are they?" + +"I cannot tell." + +The banker wrung his hands. "I shall never see them again!" he cried. "And my son? You give me hopes?" + +"My opinion is in no way altered." + +"Then, for God's sake, what was this dark business which was acted in my house last night?" + +"If you can call upon me at my Baker Street rooms to-morrow morning between nine and ten I shall be happy to do what I can to make it clearer. I understand that you give me carte blanche to act for you, provided only that I get back the gems, and that you place no limit on the sum I may draw." + +"I would give my fortune to have them back." + +"Very good. I shall look into the matter between this and then. Good-bye; it is just possible that I may have to come over here again before evening." + +It was obvious to me that my companion's mind was now made up about the case, although what his conclusions were was more than I could even dimly imagine. Several times during our homeward journey I endeavoured to sound him upon the point, but he always glided away to some other topic, until at last I gave it over in despair. It was not yet three when we found ourselves in our rooms once more. He hurried to his chamber and was down again in a few minutes dressed as a common loafer. With his collar turned up, his shiny, seedy coat, his red cravat, and his worn boots, he was a perfect sample of the class. + +"I think that this should do," said he, glancing into the glass above the fireplace. "I only wish that you could come with me, Watson, but I fear that it won't do. I may be on the trail in this matter, or I may be following a will-o'-the-wisp, but I shall soon know which it is. I hope that I may be back in a few hours." He cut a slice of beef from the joint upon the sideboard, sandwiched it between two rounds of bread, and thrusting this rude meal into his pocket he started off upon his expedition. + +I had just finished my tea when he returned, evidently in excellent spirits, swinging an old elastic-sided boot in his hand. He chucked it down into a corner and helped himself to a cup of tea. + +"I only looked in as I passed," said he. "I am going right on." + +"Where to?" + +"Oh, to the other side of the West End. It may be some time before I get back. Don't wait up for me in case I should be late." + +"How are you getting on?" + +"Oh, so so. Nothing to complain of. I have been out to Streatham since I saw you last, but I did not call at the house. It is a very sweet little problem, and I would not have missed it for a good deal. However, I must not sit gossiping here, but must get these disreputable clothes off and return to my highly respectable self." + +I could see by his manner that he had stronger reasons for satisfaction than his words alone would imply. His eyes twinkled, and there was even a touch of colour upon his sallow cheeks. He hastened upstairs, and a few minutes later I heard the slam of the hall door, which told me that he was off once more upon his congenial hunt. + +I waited until midnight, but there was no sign of his return, so I retired to my room. It was no uncommon thing for him to be away for days and nights on end when he was hot upon a scent, so that his lateness caused me no surprise. I do not know at what hour he came in, but when I came down to breakfast in the morning there he was with a cup of coffee in one hand and the paper in the other, as fresh and trim as possible. + +"You will excuse my beginning without you, Watson," said he, "but you remember that our client has rather an early appointment this morning." + +"Why, it is after nine now," I answered. "I should not be surprised if that were he. I thought I heard a ring." + +It was, indeed, our friend the financier. I was shocked by the change which had come over him, for his face which was naturally of a broad and massive mould, was now pinched and fallen in, while his hair seemed to me at least a shade whiter. He entered with a weariness and lethargy which was even more painful than his violence of the morning before, and he dropped heavily into the armchair which I pushed forward for him. + +"I do not know what I have done to be so severely tried," said he. "Only two days ago I was a happy and prosperous man, without a care in the world. Now I am left to a lonely and dishonoured age. One sorrow comes close upon the heels of another. My niece, Mary, has deserted me." + +"Deserted you?" + +"Yes. Her bed this morning had not been slept in, her room was empty, and a note for me lay upon the hall table. I had said to her last night, in sorrow and not in anger, that if she had married my boy all might have been well with him. Perhaps it was thoughtless of me to say so. It is to that remark that she refers in this note: + +" 'MY DEAREST UNCLE:--I feel that I have brought trouble upon you, and that if I had acted differently this terrible misfortune might never have occurred. I cannot, with this thought in my mind, ever again be happy under your roof, and I feel that I must leave you forever. Do not worry about my future, for that is provided for; and, above all, do not search for me, for it will be fruitless labour and an ill-service to me. In life or in death, I am ever your loving + + +" 'MARY.' + +"What could she mean by that note, Mr. Holmes? Do you think it points to suicide?" + +"No, no, nothing of the kind. It is perhaps the best possible solution. I trust, Mr. Holder, that you are nearing the end of your troubles." + +"Ha! You say so! You have heard something, Mr. Holmes; you have learned something! Where are the gems?" + +"You would not think $1000 apiece an excessive sum for them?" + +"I would pay ten." + +"That would be unnecessary. Three thousand will cover the matter. And there is a little reward, I fancy. Have you your check-book? Here is a pen. Better make it out for $4000." + +With a dazed face the banker made out the required check. Holmes walked over to his desk, took out a little triangular piece of gold with three gems in it, and threw it down upon the table. + +With a shriek of joy our client clutched it up. + +"You have it!" he gasped. "I am saved! I am saved!" + +The reaction of joy was as passionate as his grief had been, and he hugged his recovered gems to his bosom. + +"There is one other thing you owe, Mr. Holder," said Sherlock Holmes rather sternly. + +"Owe!" He caught up a pen. "Name the sum, and I will pay it." + +"No, the debt is not to me. You owe a very humble apology to that noble lad, your son, who has carried himself in this matter as I should be proud to see my own son do, should I ever chance to have one." + +"Then it was not Arthur who took them?" + +"I told you yesterday, and I repeat to-day, that it was not." + +"You are sure of it! Then let us hurry to him at once to let him know that the truth is known." + +"He knows it already. When I had cleared it all up I had an interview with him, and finding that he would not tell me the story, I told it to him, on which he had to confess that I was right and to add the very few details which were not yet quite clear to me. Your news of this morning, however, may open his lips." + +"For heaven's sake, tell me, then, what is this extraordinary mystery!" + +"I will do so, and I will show you the steps by which I reached it. And let me say to you, first, that which it is hardest for me to say and for you to hear: there has been an understanding between Sir George Burnwell and your niece Mary. They have now fled together." + +"My Mary? Impossible!" + +"It is unfortunately more than possible; it is certain. Neither you nor your son knew the true character of this man when you admitted him into your family circle. He is one of the most dangerous men in England--a ruined gambler, an absolutely desperate villain, a man without heart or conscience. Your niece knew nothing of such men. When he breathed his vows to her, as he had done to a hundred before her, she flattered herself that she alone had touched his heart. The devil knows best what he said, but at least she became his tool and was in the habit of seeing him nearly every evening." + +"I cannot, and I will not, believe it!" cried the banker with an ashen face. + +"I will tell you, then, what occurred in your house last night. Your niece, when you had, as she thought, gone to your room, slipped down and talked to her lover through the window which leads into the stable lane. His footmarks had pressed right through the snow, so long had he stood there. She told him of the coronet. His wicked lust for gold kindled at the news, and he bent her to his will. I have no doubt that she loved you, but there are women in whom the love of a lover extinguishes all other loves, and I think that she must have been one. She had hardly listened to his instructions when she saw you coming downstairs, on which she closed the window rapidly and told you about one of the servants' escapade with her wooden-legged lover, which was all perfectly true. + +"Your boy, Arthur, went to bed after his interview with you but he slept badly on account of his uneasiness about his club debts. In the middle of the night he heard a soft tread pass his door, so he rose and, looking out, was surprised to see his cousin walking very stealthily along the passage until she disappeared into your dressing-room. Petrified with astonishment, the lad slipped on some clothes and waited there in the dark to see what would come of this strange affair. Presently she emerged from the room again, and in the light of the passage-lamp your son saw that she carried the precious coronet in her hands. She passed down the stairs, and he, thrilling with horror, ran along and slipped behind the curtain near your door, whence he could see what passed in the hall beneath. He saw her stealthily open the window, hand out the coronet to someone in the gloom, and then closing it once more hurry back to her room, passing quite close to where he stood hid behind the curtain. + +"As long as she was on the scene he could not take any action without a horrible exposure of the woman whom he loved. But the instant that she was gone he realised how crushing a misfortune this would be for you, and how all-important it was to set it right. He rushed down, just as he was, in his bare feet, opened the window, sprang out into the snow, and ran down the lane, where he could see a dark figure in the moonlight. Sir George Burnwell tried to get away, but Arthur caught him, and there was a struggle between them, your lad tugging at one side of the coronet, and his opponent at the other. In the scuffle, your son struck Sir George and cut him over the eye. Then something suddenly snapped, and your son, finding that he had the coronet in his hands, rushed back, closed the window, ascended to your room, and had just observed that the coronet had been twisted in the struggle and was endeavouring to straighten it when you appeared upon the scene." + +"Is it possible?" gasped the banker. + +"You then roused his anger by calling him names at a moment when he felt that he had deserved your warmest thanks. He could not explain the true state of affairs without betraying one who certainly deserved little enough consideration at his hands. He took the more chivalrous view, however, and preserved her secret." + +"And that was why she shrieked and fainted when she saw the coronet," cried Mr. Holder. "Oh, my God! what a blind fool I have been! And his asking to be allowed to go out for five minutes! The dear fellow wanted to see if the missing piece were at the scene of the struggle. How cruelly I have misjudged him!" + +"When I arrived at the house," continued Holmes, "I at once went very carefully round it to observe if there were any traces in the snow which might help me. I knew that none had fallen since the evening before, and also that there had been a strong frost to preserve impressions. I passed along the tradesmen's path, but found it all trampled down and indistinguishable. Just beyond it, however, at the far side of the kitchen door, a woman had stood and talked with a man, whose round impressions on one side showed that he had a wooden leg. I could even tell that they had been disturbed, for the woman had run back swiftly to the door, as was shown by the deep toe and light heel marks, while Wooden-leg had waited a little, and then had gone away. I thought at the time that this might be the maid and her sweetheart, of whom you had already spoken to me, and inquiry showed it was so. I passed round the garden without seeing anything more than random tracks, which I took to be the police; but when I got into the stable lane a very long and complex story was written in the snow in front of me. + +"There was a double line of tracks of a booted man, and a second double line which I saw with delight belonged to a man with naked feet. I was at once convinced from what you had told me that the latter was your son. The first had walked both ways, but the other had run swiftly, and as his tread was marked in places over the depression of the boot, it was obvious that he had passed after the other. I followed them up and found they led to the hall window, where Boots had worn all the snow away while waiting. Then I walked to the other end, which was a hundred yards or more down the lane. I saw where Boots had faced round, where the snow was cut up as though there had been a struggle, and, finally, where a few drops of blood had fallen, to show me that I was not mistaken. Boots had then run down the lane, and another little smudge of blood showed that it was he who had been hurt. When he came to the highroad at the other end, I found that the pavement had been cleared, so there was an end to that clue. + +"On entering the house, however, I examined, as you remember, the sill and framework of the hall window with my lens, and I could at once see that someone had passed out. I could distinguish the outline of an instep where the wet foot had been placed in coming in. I was then beginning to be able to form an opinion as to what had occurred. A man had waited outside the window; someone had brought the gems; the deed had been overseen by your son; he had pursued the thief; had struggled with him; they had each tugged at the coronet, their united strength causing injuries which neither alone could have effected. He had returned with the prize, but had left a fragment in the grasp of his opponent. So far I was clear. The question now was, who was the man and who was it brought him the coronet? + +"It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. Now, I knew that it was not you who had brought it down, so there only remained your niece and the maids. But if it were the maids, why should your son allow himself to be accused in their place? There could be no possible reason. As he loved his cousin, however, there was an excellent explanation why he should retain her secret--the more so as the secret was a disgraceful one. When I remembered that you had seen her at that window, and how she had fainted on seeing the coronet again, my conjecture became a certainty. + +"And who could it be who was her confederate? A lover evidently, for who else could outweigh the love and gratitude which she must feel to you? I knew that you went out little, and that your circle of friends was a very limited one. But among them was Sir George Burnwell. I had heard of him before as being a man of evil reputation among women. It must have been he who wore those boots and retained the missing gems. Even though he knew that Arthur had discovered him, he might still flatter himself that he was safe, for the lad could not say a word without compromising his own family. + +"Well, your own good sense will suggest what measures I took next. I went in the shape of a loafer to Sir George's house, managed to pick up an acquaintance with his valet, learned that his master had cut his head the night before, and, finally, at the expense of six shillings, made all sure by buying a pair of his cast-off shoes. With these I journeyed down to Streatham and saw that they exactly fitted the tracks." + +"I saw an ill-dressed vagabond in the lane yesterday evening," said Mr. Holder. + +"Precisely. It was I. I found that I had my man, so I came home and changed my clothes. It was a delicate part which I had to play then, for I saw that a prosecution must be avoided to avert scandal, and I knew that so astute a villain would see that our hands were tied in the matter. I went and saw him. At first, of course, he denied everything. But when I gave him every particular that had occurred, he tried to bluster and took down a life-preserver from the wall. I knew my man, however, and I clapped a pistol to his head before he could strike. Then he became a little more reasonable. I told him that we would give him a price for the stones he held--$1000 apiece. That brought out the first signs of grief that he had shown. 'Why, dash it all!' said he, 'I've let them go at six hundred for the three!' I soon managed to get the address of the receiver who had them, on promising him that there would be no prosecution. Off I set to him, and after much chaffering I got our stones at $1000 apiece. Then I looked in upon your son, told him that all was right, and eventually got to my bed about two o'clock, after what I may call a really hard day's work." + +"A day which has saved England from a great public scandal," said the banker, rising. "Sir, I cannot find words to thank you, but you shall not find me ungrateful for what you have done. Your skill has indeed exceeded all that I have heard of it. And now I must fly to my dear boy to apologise to him for the wrong which I have done him. As to what you tell me of poor Mary, it goes to my very heart. Not even your skill can inform me where she is now." + +"I think that we may safely say," returned Holmes, "that she is wherever Sir George Burnwell is. It is equally certain, too, that whatever her sins are, they will soon receive a more than sufficient punishment." + +XII. THE ADVENTURE OF THE COPPER BEECHES + + +"To the man who loves art for its own sake," remarked Sherlock Holmes, tossing aside the advertisement sheet of the Daily Telegraph, "it is frequently in its least important and lowliest manifestations that the keenest pleasure is to be derived. It is pleasant to me to observe, Watson, that you have so far grasped this truth that in these little records of our cases which you have been good enough to draw up, and, I am bound to say, occasionally to embellish, you have given prominence not so much to the many causes celebres and sensational trials in which I have figured but rather to those incidents which may have been trivial in themselves, but which have given room for those faculties of deduction and of logical synthesis which I have made my special province." + +"And yet," said I, smiling, "I cannot quite hold myself absolved from the charge of sensationalism which has been urged against my records." + +"You have erred, perhaps," he observed, taking up a glowing cinder with the tongs and lighting with it the long cherry-wood pipe which was wont to replace his clay when he was in a disputatious rather than a meditative mood--"you have erred perhaps in attempting to put colour and life into each of your statements instead of confining yourself to the task of placing upon record that severe reasoning from cause to effect which is really the only notable feature about the thing." + +"It seems to me that I have done you full justice in the matter," I remarked with some coldness, for I was repelled by the egotism which I had more than once observed to be a strong factor in my friend's singular character. + +"No, it is not selfishness or conceit," said he, answering, as was his wont, my thoughts rather than my words. "If I claim full justice for my art, it is because it is an impersonal thing--a thing beyond myself. Crime is common. Logic is rare. Therefore it is upon the logic rather than upon the crime that you should dwell. You have degraded what should have been a course of lectures into a series of tales." + +It was a cold morning of the early spring, and we sat after breakfast on either side of a cheery fire in the old room at Baker Street. A thick fog rolled down between the lines of dun-coloured houses, and the opposing windows loomed like dark, shapeless blurs through the heavy yellow wreaths. Our gas was lit and shone on the white cloth and glimmer of china and metal, for the table had not been cleared yet. Sherlock Holmes had been silent all the morning, dipping continuously into the advertisement columns of a succession of papers until at last, having apparently given up his search, he had emerged in no very sweet temper to lecture me upon my literary shortcomings. + +"At the same time," he remarked after a pause, during which he had sat puffing at his long pipe and gazing down into the fire, "you can hardly be open to a charge of sensationalism, for out of these cases which you have been so kind as to interest yourself in, a fair proportion do not treat of crime, in its legal sense, at all. The small matter in which I endeavoured to help the King of Bohemia, the singular experience of Miss Mary Sutherland, the problem connected with the man with the twisted lip, and the incident of the noble bachelor, were all matters which are outside the pale of the law. But in avoiding the sensational, I fear that you may have bordered on the trivial." + +"The end may have been so," I answered, "but the methods I hold to have been novel and of interest." + +"Pshaw, my dear fellow, what do the public, the great unobservant public, who could hardly tell a weaver by his tooth or a compositor by his left thumb, care about the finer shades of analysis and deduction! But, indeed, if you are trivial. I cannot blame you, for the days of the great cases are past. Man, or at least criminal man, has lost all enterprise and originality. As to my own little practice, it seems to be degenerating into an agency for recovering lost lead pencils and giving advice to young ladies from boarding-schools. I think that I have touched bottom at last, however. This note I had this morning marks my zero-point, I fancy. Read it!" He tossed a crumpled letter across to me. + +It was dated from Montague Place upon the preceding evening, and ran thus: + +"DEAR MR. HOLMES:--I am very anxious to consult you as to whether I should or should not accept a situation which has been offered to me as governess. I shall call at half-past ten to-morrow if I do not inconvenience you. Yours faithfully, + + +"VIOLET HUNTER." + +"Do you know the young lady?" I asked. + +"Not I." + +"It is half-past ten now." + +"Yes, and I have no doubt that is her ring." + +"It may turn out to be of more interest than you think. You remember that the affair of the blue carbuncle, which appeared to be a mere whim at first, developed into a serious investigation. It may be so in this case, also." + +"Well, let us hope so. But our doubts will very soon be solved, for here, unless I am much mistaken, is the person in question." + +As he spoke the door opened and a young lady entered the room. She was plainly but neatly dressed, with a bright, quick face, freckled like a plover's egg, and with the brisk manner of a woman who has had her own way to make in the world. + +"You will excuse my troubling you, I am sure," said she, as my companion rose to greet her, "but I have had a very strange experience, and as I have no parents or relations of any sort from whom I could ask advice, I thought that perhaps you would be kind enough to tell me what I should do." + +"Pray take a seat, Miss Hunter. I shall be happy to do anything that I can to serve you." + +I could see that Holmes was favourably impressed by the manner and speech of his new client. He looked her over in his searching fashion, and then composed himself, with his lids drooping and his finger-tips together, to listen to her story. + +"I have been a governess for five years," said she, "in the family of Colonel Spence Munro, but two months ago the colonel received an appointment at Halifax, in Nova Scotia, and took his children over to America with him, so that I found myself without a situation. I advertised, and I answered advertisements, but without success. At last the little money which I had saved began to run short, and I was at my wit's end as to what I should do. + +"There is a well-known agency for governesses in the West End called Westaway's, and there I used to call about once a week in order to see whether anything had turned up which might suit me. Westaway was the name of the founder of the business, but it is really managed by Miss Stoper. She sits in her own little office, and the ladies who are seeking employment wait in an anteroom, and are then shown in one by one, when she consults her ledgers and sees whether she has anything which would suit them. + +"Well, when I called last week I was shown into the little office as usual, but I found that Miss Stoper was not alone. A prodigiously stout man with a very smiling face and a great heavy chin which rolled down in fold upon fold over his throat sat at her elbow with a pair of glasses on his nose, looking very earnestly at the ladies who entered. As I came in he gave quite a jump in his chair and turned quickly to Miss Stoper. + +" 'That will do,' said he; 'I could not ask for anything better. Capital! capital!' He seemed quite enthusiastic and rubbed his hands together in the most genial fashion. He was such a comfortable-looking man that it was quite a pleasure to look at him. + +" 'You are looking for a situation, miss?' he asked. + +" 'Yes, sir.' + +" 'As governess?' + +" 'Yes, sir.' + +" 'And what salary do you ask?' + +" 'I had $4 a month in my last place with Colonel Spence Munro.' + +" 'Oh, tut, tut! sweating--rank sweating!' he cried, throwing his fat hands out into the air like a man who is in a boiling passion. 'How could anyone offer so pitiful a sum to a lady with such attractions and accomplishments?' + +" 'My accomplishments, sir, may be less than you imagine,' said I. 'A little French, a little German, music, and drawing--' + +" 'Tut, tut!' he cried. 'This is all quite beside the question. The point is, have you or have you not the bearing and deportment of a lady? There it is in a nutshell. If you have not, you are not fitted for the rearing of a child who may some day play a considerable part in the history of the country. But if you have why, then, how could any gentleman ask you to condescend to accept anything under the three figures? Your salary with me, madam, would commence at $100 a year.' + +"You may imagine, Mr. Holmes, that to me, destitute as I was, such an offer seemed almost too good to be true. The gentleman, however, seeing perhaps the look of incredulity upon my face, opened a pocket-book and took out a note. + +" 'It is also my custom,' said he, smiling in the most pleasant fashion until his eyes were just two little shining slits amid the white creases of his face, 'to advance to my young ladies half their salary beforehand, so that they may meet any little expenses of their journey and their wardrobe.' + +"It seemed to me that I had never met so fascinating and so thoughtful a man. As I was already in debt to my tradesmen, the advance was a great convenience, and yet there was something unnatural about the whole transaction which made me wish to know a little more before I quite committed myself. + +" 'May I ask where you live, sir?' said I. + +" 'Hampshire. Charming rural place. The Copper Beeches, five miles on the far side of Winchester. It is the most lovely country, my dear young lady, and the dearest old country-house.' + +" 'And my duties, sir? I should be glad to know what they would be.' + +" 'One child--one dear little romper just six years old. Oh, if you could see him killing cockroaches with a slipper! Smack! smack! smack! Three gone before you could wink!' He leaned back in his chair and laughed his eyes into his head again. + +"I was a little startled at the nature of the child's amusement, but the father's laughter made me think that perhaps he was joking. + +" 'My sole duties, then,' I asked, 'are to take charge of a single child?' + +" 'No, no, not the sole, not the sole, my dear young lady,' he cried. 'Your duty would be, as I am sure your good sense would suggest, to obey any little commands my wife might give, provided always that they were such commands as a lady might with propriety obey. You see no difficulty, heh?' + +" 'I should be happy to make myself useful.' + +" 'Quite so. In dress now, for example. We are faddy people, you know--faddy but kind-hearted. If you were asked to wear any dress which we might give you, you would not object to our little whim. Heh?' + +" 'No,' said I, considerably astonished at his words. + +" 'Or to sit here, or sit there, that would not be offensive to you?' + +" 'Oh, no.' + +" 'Or to cut your hair quite short before you come to us?' + +"I could hardly believe my ears. As you may observe, Mr. Holmes, my hair is somewhat luxuriant, and of a rather peculiar tint of chestnut. It has been considered artistic. I could not dream of sacrificing it in this offhand fashion. + +" 'I am afraid that that is quite impossible,' said I. He had been watching me eagerly out of his small eyes, and I could see a shadow pass over his face as I spoke. + +" 'I am afraid that it is quite essential,' said he. 'It is a little fancy of my wife's, and ladies' fancies, you know, madam, ladies' fancies must be consulted. And so you won't cut your hair?' + +" 'No, sir, I really could not,' I answered firmly. + +" 'Ah, very well; then that quite settles the matter. It is a pity, because in other respects you would really have done very nicely. In that case, Miss Stoper, I had best inspect a few more of your young ladies.' + +"The manageress had sat all this while busy with her papers without a word to either of us, but she glanced at me now with so much annoyance upon her face that I could not help suspecting that she had lost a handsome commission through my refusal. + +" 'Do you desire your name to be kept upon the books?' she asked. + +" 'If you please, Miss Stoper.' + +" 'Well, really, it seems rather useless, since you refuse the most excellent offers in this fashion,' said she sharply. 'You can hardly expect us to exert ourselves to find another such opening for you. Good-day to you, Miss Hunter.' She struck a gong upon the table, and I was shown out by the page. + +"Well, Mr. Holmes, when I got back to my lodgings and found little enough in the cupboard, and two or three bills upon the table. I began to ask myself whether I had not done a very foolish thing. After all, if these people had strange fads and expected obedience on the most extraordinary matters, they were at least ready to pay for their eccentricity. Very few governesses in England are getting $100 a year. Besides, what use was my hair to me? Many people are improved by wearing it short and perhaps I should be among the number. Next day I was inclined to think that I had made a mistake, and by the day after I was sure of it. I had almost overcome my pride so far as to go back to the agency and inquire whether the place was still open when I received this letter from the gentleman himself. I have it here and I will read it to you: + + +" 'The Copper Beeches, near Winchester. + +" 'DEAR MISS HUNTER:--Miss Stoper has very kindly given me your address, and I write from here to ask you whether you have reconsidered your decision. My wife is very anxious that you should come, for she has been much attracted by my description of you. We are willing to give $30 a quarter, or $120 a year, so as to recompense you for any little inconvenience which our fads may cause you. They are not very exacting, after all. My wife is fond of a particular shade of electric blue and would like you to wear such a dress indoors in the morning. You need not, however, go to the expense of purchasing one, as we have one belonging to my dear daughter Alice (now in Philadelphia), which would, I should think, fit you very well. Then, as to sitting here or there, or amusing yourself in any manner indicated, that need cause you no inconvenience. As regards your hair, it is no doubt a pity, especially as I could not help remarking its beauty during our short interview, but I am afraid that I must remain firm upon this point, and I only hope that the increased salary may recompense you for the loss. Your duties, as far as the child is concerned, are very light. Now do try to come, and I shall meet you with the dog-cart at Winchester. Let me know your train. Yours faithfully, + + +" 'JEPHRO RUCASTLE.' + +"That is the letter which I have just received, Mr. Holmes, and my mind is made up that I will accept it. I thought, however, that before taking the final step I should like to submit the whole matter to your consideration." + +"Well, Miss Hunter, if your mind is made up, that settles the question," said Holmes, smiling. + +"But you would not advise me to refuse?" + +"I confess that it is not the situation which I should like to see a sister of mine apply for." + +"What is the meaning of it all, Mr. Holmes?" + +"Ah, I have no data. I cannot tell. Perhaps you have yourself formed some opinion?" + +"Well, there seems to me to be only one possible solution. Mr. Rucastle seemed to be a very kind, good-natured man. Is it not possible that his wife is a lunatic, that he desires to keep the matter quiet for fear she should be taken to an asylum, and that he humours her fancies in every way in order to prevent an outbreak?" + +"That is a possible solution--in fact, as matters stand, it is the most probable one. But in any case it does not seem to be a nice household for a young lady." + +"But the money, Mr. Holmes, the money!" + +"Well, yes, of course the pay is good--too good. That is what makes me uneasy. Why should they give you $120 a year, when they could have their pick for $40? There must be some strong reason behind." + +"I thought that if I told you the circumstances you would understand afterwards if I wanted your help. I should feel so much stronger if I felt that you were at the back of me." + +"Oh, you may carry that feeling away with you. I assure you that your little problem promises to be the most interesting which has come my way for some months. There is something distinctly novel about some of the features. If you should find yourself in doubt or in danger--" + +"Danger! What danger do you foresee?" + +Holmes shook his head gravely. "It would cease to be a danger if we could define it," said he. "But at any time, day or night, a telegram would bring me down to your help." + +"That is enough." She rose briskly from her chair with the anxiety all swept from her face. "I shall go down to Hampshire quite easy in my mind now. I shall write to Mr. Rucastle at once, sacrifice my poor hair to-night, and start for Winchester to-morrow." With a few grateful words to Holmes she bade us both good-night and bustled off upon her way. + +"At least," said I as we heard her quick, firm steps descending the stairs, "she seems to be a young lady who is very well able to take care of herself." + +"And she would need to be," said Holmes gravely. "I am much mistaken if we do not hear from her before many days are past." + +It was not very long before my friend's prediction was fulfilled. A fortnight went by, during which I frequently found my thoughts turning in her direction and wondering what strange side-alley of human experience this lonely woman had strayed into. The unusual salary, the curious conditions, the light duties, all pointed to something abnormal, though whether a fad or a plot, or whether the man were a philanthropist or a villain, it was quite beyond my powers to determine. As to Holmes, I observed that he sat frequently for half an hour on end, with knitted brows and an abstracted air, but he swept the matter away with a wave of his hand when I mentioned it. "Data! data! data!" he cried impatiently. "I can't make bricks without clay." And yet he would always wind up by muttering that no sister of his should ever have accepted such a situation. + +The telegram which we eventually received came late one night just as I was thinking of turning in and Holmes was settling down to one of those all-night chemical researches which he frequently indulged in, when I would leave him stooping over a retort and a test-tube at night and find him in the same position when I came down to breakfast in the morning. He opened the yellow envelope, and then, glancing at the message, threw it across to me. + +"Just look up the trains in Bradshaw," said he, and turned back to his chemical studies. + +The summons was a brief and urgent one. + +"Please be at the Black Swan Hotel at Winchester at midday to-morrow," it said. "Do come! I am at my wit's end. + + +"HUNTER." + +"Will you come with me?" asked Holmes, glancing up. + +"I should wish to." + +"Just look it up, then." + +"There is a train at half-past nine," said I, glancing over my Bradshaw. "It is due at Winchester at 11:30." + +"That will do very nicely. Then perhaps I had better postpone my analysis of the acetones, as we may need to be at our best in the morning." + +By eleven o'clock the next day we were well upon our way to the old English capital. Holmes had been buried in the morning papers all the way down, but after we had passed the Hampshire border he threw them down and began to admire the scenery. It was an ideal spring day, a light blue sky, flecked with little fleecy white clouds drifting across from west to east. The sun was shining very brightly, and yet there was an exhilarating nip in the air, which set an edge to a man's energy. All over the countryside, away to the rolling hills around Aldershot, the little red and grey roofs of the farm-steadings peeped out from amid the light green of the new foliage. + +"Are they not fresh and beautiful?" I cried with all the enthusiasm of a man fresh from the fogs of Baker Street. + +But Holmes shook his head gravely. + +"Do you know, Watson," said he, "that it is one of the curses of a mind with a turn like mine that I must look at everything with reference to my own special subject. You look at these scattered houses, and you are impressed by their beauty. I look at them, and the only thought which comes to me is a feeling of their isolation and of the impunity with which crime may be committed there." + +"Good heavens!" I cried. "Who would associate crime with these dear old homesteads?" + +"They always fill me with a certain horror. It is my belief, Watson, founded upon my experience, that the lowest and vilest alleys in London do not present a more dreadful record of sin than does the smiling and beautiful countryside." + +"You horrify me!" + +"But the reason is very obvious. The pressure of public opinion can do in the town what the law cannot accomplish. There is no lane so vile that the scream of a tortured child, or the thud of a drunkard's blow, does not beget sympathy and indignation among the neighbours, and then the whole machinery of justice is ever so close that a word of complaint can set it going, and there is but a step between the crime and the dock. But look at these lonely houses, each in its own fields, filled for the most part with poor ignorant folk who know little of the law. Think of the deeds of hellish cruelty, the hidden wickedness which may go on, year in, year out, in such places, and none the wiser. Had this lady who appeals to us for help gone to live in Winchester, I should never have had a fear for her. It is the five miles of country which makes the danger. Still, it is clear that she is not personally threatened." + +"No. If she can come to Winchester to meet us she can get away." + +"Quite so. She has her freedom." + +"What can be the matter, then? Can you suggest no explanation?" + +"I have devised seven separate explanations, each of which would cover the facts as far as we know them. But which of these is correct can only be determined by the fresh information which we shall no doubt find waiting for us. Well, there is the tower of the cathedral, and we shall soon learn all that Miss Hunter has to tell." + +The Black Swan is an inn of repute in the High Street, at no distance from the station, and there we found the young lady waiting for us. She had engaged a sitting-room, and our lunch awaited us upon the table. + +"I am so delighted that you have come," she said earnestly. "It is so very kind of you both; but indeed I do not know what I should do. Your advice will be altogether invaluable to me." + +"Pray tell us what has happened to you." + +"I will do so, and I must be quick, for I have promised Mr. Rucastle to be back before three. I got his leave to come into town this morning, though he little knew for what purpose." + +"Let us have everything in its due order." Holmes thrust his long thin legs out towards the fire and composed himself to listen. + +"In the first place, I may say that I have met, on the whole, with no actual ill-treatment from Mr. and Mrs. Rucastle. It is only fair to them to say that. But I cannot understand them, and I am not easy in my mind about them." + +"What can you not understand?" + +"Their reasons for their conduct. But you shall have it all just as it occurred. When I came down, Mr. Rucastle met me here and drove me in his dog-cart to the Copper Beeches. It is, as he said, beautifully situated, but it is not beautiful in itself, for it is a large square block of a house, whitewashed, but all stained and streaked with damp and bad weather. There are grounds round it, woods on three sides, and on the fourth a field which slopes down to the Southampton highroad, which curves past about a hundred yards from the front door. This ground in front belongs to the house, but the woods all round are part of Lord Southerton's preserves. A clump of copper beeches immediately in front of the hall door has given its name to the place. + +"I was driven over by my employer, who was as amiable as ever, and was introduced by him that evening to his wife and the child. There was no truth, Mr. Holmes, in the conjecture which seemed to us to be probable in your rooms at Baker Street. Mrs. Rucastle is not mad. I found her to be a silent, pale-faced woman, much younger than her husband, not more than thirty, I should think, while he can hardly be less than forty-five. From their conversation I have gathered that they have been married about seven years, that he was a widower, and that his only child by the first wife was the daughter who has gone to Philadelphia. Mr. Rucastle told me in private that the reason why she had left them was that she had an unreasoning aversion to her stepmother. As the daughter could not have been less than twenty, I can quite imagine that her position must have been uncomfortable with her father's young wife. + +"Mrs. Rucastle seemed to me to be colourless in mind as well as in feature. She impressed me neither favourably nor the reverse. She was a nonentity. It was easy to see that she was passionately devoted both to her husband and to her little son. Her light grey eyes wandered continually from one to the other, noting every little want and forestalling it if possible. He was kind to her also in his bluff, boisterous fashion, and on the whole they seemed to be a happy couple. And yet she had some secret sorrow, this woman. She would often be lost in deep thought, with the saddest look upon her face. More than once I have surprised her in tears. I have thought sometimes that it was the disposition of her child which weighed upon her mind, for I have never met so utterly spoiled and so ill-natured a little creature. He is small for his age, with a head which is quite disproportionately large. His whole life appears to be spent in an alternation between savage fits of passion and gloomy intervals of sulking. Giving pain to any creature weaker than himself seems to be his one idea of amusement, and he shows quite remarkable talent in planning the capture of mice, little birds, and insects. But I would rather not talk about the creature, Mr. Holmes, and, indeed, he has little to do with my story." + +"I am glad of all details," remarked my friend, "whether they seem to you to be relevant or not." + +"I shall try not to miss anything of importance. The one unpleasant thing about the house, which struck me at once, was the appearance and conduct of the servants. There are only two, a man and his wife. Toller, for that is his name, is a rough, uncouth man, with grizzled hair and whiskers, and a perpetual smell of drink. Twice since I have been with them he has been quite drunk, and yet Mr. Rucastle seemed to take no notice of it. His wife is a very tall and strong woman with a sour face, as silent as Mrs. Rucastle and much less amiable. They are a most unpleasant couple, but fortunately I spend most of my time in the nursery and my own room, which are next to each other in one corner of the building. + +"For two days after my arrival at the Copper Beeches my life was very quiet; on the third, Mrs. Rucastle came down just after breakfast and whispered something to her husband. + +" 'Oh, yes,' said he, turning to me, 'we are very much obliged to you, Miss Hunter, for falling in with our whims so far as to cut your hair. I assure you that it has not detracted in the tiniest iota from your appearance. We shall now see how the electric-blue dress will become you. You will find it laid out upon the bed in your room, and if you would be so good as to put it on we should both be extremely obliged.' + +"The dress which I found waiting for me was of a peculiar shade of blue. It was of excellent material, a sort of beige, but it bore unmistakable signs of having been worn before. It could not have been a better fit if I had been measured for it. Both Mr. and Mrs. Rucastle expressed a delight at the look of it, which seemed quite exaggerated in its vehemence. They were waiting for me in the drawing-room, which is a very large room, stretching along the entire front of the house, with three long windows reaching down to the floor. A chair had been placed close to the central window, with its back turned towards it. In this I was asked to sit, and then Mr. Rucastle, walking up and down on the other side of the room, began to tell me a series of the funniest stories that I have ever listened to. You cannot imagine how comical he was, and I laughed until I was quite weary. Mrs. Rucastle, however, who has evidently no sense of humour, never so much as smiled, but sat with her hands in her lap, and a sad, anxious look upon her face. After an hour or so, Mr. Rucastle suddenly remarked that it was time to commence the duties of the day, and that I might change my dress and go to little Edward in the nursery. + +"Two days later this same performance was gone through under exactly similar circumstances. Again I changed my dress, again I sat in the window, and again I laughed very heartily at the funny stories of which my employer had an immense repertoire, and which he told inimitably. Then he handed me a yellow-backed novel, and moving my chair a little sideways, that my own shadow might not fall upon the page, he begged me to read aloud to him. I read for about ten minutes, beginning in the heart of a chapter, and then suddenly, in the middle of a sentence, he ordered me to cease and to change my dress. + +"You can easily imagine, Mr. Holmes, how curious I became as to what the meaning of this extraordinary performance could possibly be. They were always very careful, I observed, to turn my face away from the window, so that I became consumed with the desire to see what was going on behind my back. At first it seemed to be impossible, but I soon devised a means. My hand-mirror had been broken, so a happy thought seized me, and I concealed a piece of the glass in my handkerchief. On the next occasion, in the midst of my laughter, I put my handkerchief up to my eyes, and was able with a little management to see all that there was behind me. I confess that I was disappointed. There was nothing. At least that was my first impression. At the second glance, however, I perceived that there was a man standing in the Southampton Road, a small bearded man in a grey suit, who seemed to be looking in my direction. The road is an important highway, and there are usually people there. This man, however, was leaning against the railings which bordered our field and was looking earnestly up. I lowered my handkerchief and glanced at Mrs. Rucastle to find her eyes fixed upon me with a most searching gaze. She said nothing, but I am convinced that she had divined that I had a mirror in my hand and had seen what was behind me. She rose at once. + +" 'Jephro,' said she, 'there is an impertinent fellow upon the road there who stares up at Miss Hunter.' + +" 'No friend of yours, Miss Hunter?' he asked. + +" 'No, I know no one in these parts.' + +" 'Dear me! How very impertinent! Kindly turn round and motion to him to go away.' + +" 'Surely it would be better to take no notice.' + +" 'No, no, we should have him loitering here always. Kindly turn round and wave him away like that.' + +"I did as I was told, and at the same instant Mrs. Rucastle drew down the blind. That was a week ago, and from that time I have not sat again in the window, nor have I worn the blue dress, nor seen the man in the road." + +"Pray continue," said Holmes. "Your narrative promises to be a most interesting one." + +"You will find it rather disconnected, I fear, and there may prove to be little relation between the different incidents of which I speak. On the very first day that I was at the Copper Beeches, Mr. Rucastle took me to a small outhouse which stands near the kitchen door. As we approached it I heard the sharp rattling of a chain, and the sound as of a large animal moving about. + +" 'Look in here!' said Mr. Rucastle, showing me a slit between two planks. 'Is he not a beauty?' + +"I looked through and was conscious of two glowing eyes, and of a vague figure huddled up in the darkness. + +" 'Don't be frightened,' said my employer, laughing at the start which I had given. 'It's only Carlo, my mastiff. I call him mine, but really old Toller, my groom, is the only man who can do anything with him. We feed him once a day, and not too much then, so that he is always as keen as mustard. Toller lets him loose every night, and God help the trespasser whom he lays his fangs upon. For goodness' sake don't you ever on any pretext set your foot over the threshold at night, for it's as much as your life is worth.' + +"The warning was no idle one, for two nights later I happened to look out of my bedroom window about two o'clock in the morning. It was a beautiful moonlight night, and the lawn in front of the house was silvered over and almost as bright as day. I was standing, rapt in the peaceful beauty of the scene, when I was aware that something was moving under the shadow of the copper beeches. As it emerged into the moonshine I saw what it was. It was a giant dog, as large as a calf, tawny tinted, with hanging jowl, black muzzle, and huge projecting bones. It walked slowly across the lawn and vanished into the shadow upon the other side. That dreadful sentinel sent a chill to my heart which I do not think that any burglar could have done. + +"And now I have a very strange experience to tell you. I had, as you know, cut off my hair in London, and I had placed it in a great coil at the bottom of my trunk. One evening, after the child was in bed, I began to amuse myself by examining the furniture of my room and by rearranging my own little things. There was an old chest of drawers in the room, the two upper ones empty and open, the lower one locked. I had filled the first two with my linen, and as I had still much to pack away I was naturally annoyed at not having the use of the third drawer. It struck me that it might have been fastened by a mere oversight, so I took out my bunch of keys and tried to open it. The very first key fitted to perfection, and I drew the drawer open. There was only one thing in it, but I am sure that you would never guess what it was. It was my coil of hair. + +"I took it up and examined it. It was of the same peculiar tint, and the same thickness. But then the impossibility of the thing obtruded itself upon me. How could my hair have been locked in the drawer? With trembling hands I undid my trunk, turned out the contents, and drew from the bottom my own hair. I laid the two tresses together, and I assure you that they were identical. Was it not extraordinary? Puzzle as I would, I could make nothing at all of what it meant. I returned the strange hair to the drawer, and I said nothing of the matter to the Rucastles as I felt that I had put myself in the wrong by opening a drawer which they had locked. + +"I am naturally observant, as you may have remarked, Mr. Holmes, and I soon had a pretty good plan of the whole house in my head. There was one wing, however, which appeared not to be inhabited at all. A door which faced that which led into the quarters of the Tollers opened into this suite, but it was invariably locked. One day, however, as I ascended the stair, I met Mr. Rucastle coming out through this door, his keys in his hand, and a look on his face which made him a very different person to the round, jovial man to whom I was accustomed. His cheeks were red, his brow was all crinkled with anger, and the veins stood out at his temples with passion. He locked the door and hurried past me without a word or a look. + +"This aroused my curiosity, so when I went out for a walk in the grounds with my charge, I strolled round to the side from which I could see the windows of this part of the house. There were four of them in a row, three of which were simply dirty, while the fourth was shuttered up. They were evidently all deserted. As I strolled up and down, glancing at them occasionally, Mr. Rucastle came out to me, looking as merry and jovial as ever. + +" 'Ah!' said he, 'you must not think me rude if I passed you without a word, my dear young lady. I was preoccupied with business matters.' + +"I assured him that I was not offended. 'By the way,' said I, 'you seem to have quite a suite of spare rooms up there, and one of them has the shutters up.' + +"He looked surprised and, as it seemed to me, a little startled at my remark. + +" 'Photography is one of my hobbies,' said he. 'I have made my dark room up there. But, dear me! what an observant young lady we have come upon. Who would have believed it? Who would have ever believed it?' He spoke in a jesting tone, but there was no jest in his eyes as he looked at me. I read suspicion there and annoyance, but no jest. + +"Well, Mr. Holmes, from the moment that I understood that there was something about that suite of rooms which I was not to know, I was all on fire to go over them. It was not mere curiosity, though I have my share of that. It was more a feeling of duty--a feeling that some good might come from my penetrating to this place. They talk of woman's instinct; perhaps it was woman's instinct which gave me that feeling. At any rate, it was there, and I was keenly on the lookout for any chance to pass the forbidden door. + +"It was only yesterday that the chance came. I may tell you that, besides Mr. Rucastle, both Toller and his wife find something to do in these deserted rooms, and I once saw him carrying a large black linen bag with him through the door. Recently he has been drinking hard, and yesterday evening he was very drunk; and when I came upstairs there was the key in the door. I have no doubt at all that he had left it there. Mr. and Mrs. Rucastle were both downstairs, and the child was with them, so that I had an admirable opportunity. I turned the key gently in the lock, opened the door, and slipped through. + +"There was a little passage in front of me, unpapered and uncarpeted, which turned at a right angle at the farther end. Round this corner were three doors in a line, the first and third of which were open. They each led into an empty room, dusty and cheerless, with two windows in the one and one in the other, so thick with dirt that the evening light glimmered dimly through them. The centre door was closed, and across the outside of it had been fastened one of the broad bars of an iron bed, padlocked at one end to a ring in the wall, and fastened at the other with stout cord. The door itself was locked as well, and the key was not there. This barricaded door corresponded clearly with the shuttered window outside, and yet I could see by the glimmer from beneath it that the room was not in darkness. Evidently there was a skylight which let in light from above. As I stood in the passage gazing at the sinister door and wondering what secret it might veil, I suddenly heard the sound of steps within the room and saw a shadow pass backward and forward against the little slit of dim light which shone out from under the door. A mad, unreasoning terror rose up in me at the sight, Mr. Holmes. My overstrung nerves failed me suddenly, and I turned and ran--ran as though some dreadful hand were behind me clutching at the skirt of my dress. I rushed down the passage, through the door, and straight into the arms of Mr. Rucastle, who was waiting outside. + +" 'So,' said he, smiling, 'it was you, then. I thought that it must be when I saw the door open.' + +" 'Oh, I am so frightened!' I panted. + +" 'My dear young lady! my dear young lady!'--you cannot think how caressing and soothing his manner was--'and what has frightened you, my dear young lady?' + +"But his voice was just a little too coaxing. He overdid it. I was keenly on my guard against him. + +" 'I was foolish enough to go into the empty wing,' I answered. 'But it is so lonely and eerie in this dim light that I was frightened and ran out again. Oh, it is so dreadfully still in there!' + +" 'Only that?' said he, looking at me keenly. + +" 'Why, what did you think?' I asked. + +" 'Why do you think that I lock this door?' + +" 'I am sure that I do not know.' + +" 'It is to keep people out who have no business there. Do you see?' He was still smiling in the most amiable manner. + +" 'I am sure if I had known--' + +" 'Well, then, you know now. And if you ever put your foot over that threshold again'--here in an instant the smile hardened into a grin of rage, and he glared down at me with the face of a demon--'I'll throw you to the mastiff.' + +"I was so terrified that I do not know what I did. I suppose that I must have rushed past him into my room. I remember nothing until I found myself lying on my bed trembling all over. Then I thought of you, Mr. Holmes. I could not live there longer without some advice. I was frightened of the house, of the man, of the woman, of the servants, even of the child. They were all horrible to me. If I could only bring you down all would be well. Of course I might have fled from the house, but my curiosity was almost as strong as my fears. My mind was soon made up. I would send you a wire. I put on my hat and cloak, went down to the office, which is about half a mile from the house, and then returned, feeling very much easier. A horrible doubt came into my mind as I approached the door lest the dog might be loose, but I remembered that Toller had drunk himself into a state of insensibility that evening, and I knew that he was the only one in the household who had any influence with the savage creature, or who would venture to set him free. I slipped in in safety and lay awake half the night in my joy at the thought of seeing you. I had no difficulty in getting leave to come into Winchester this morning, but I must be back before three o'clock, for Mr. and Mrs. Rucastle are going on a visit, and will be away all the evening, so that I must look after the child. Now I have told you all my adventures, Mr. Holmes, and I should be very glad if you could tell me what it all means, and, above all, what I should do." + +Holmes and I had listened spellbound to this extraordinary story. My friend rose now and paced up and down the room, his hands in his pockets, and an expression of the most profound gravity upon his face. + +"Is Toller still drunk?" he asked. + +"Yes. I heard his wife tell Mrs. Rucastle that she could do nothing with him." + +"That is well. And the Rucastles go out to-night?" + +"Yes." + +"Is there a cellar with a good strong lock?" + +"Yes, the wine-cellar." + +"You seem to me to have acted all through this matter like a very brave and sensible girl, Miss Hunter. Do you think that you could perform one more feat? I should not ask it of you if I did not think you a quite exceptional woman." + +"I will try. What is it?" + +"We shall be at the Copper Beeches by seven o'clock, my friend and I. The Rucastles will be gone by that time, and Toller will, we hope, be incapable. There only remains Mrs. Toller, who might give the alarm. If you could send her into the cellar on some errand, and then turn the key upon her, you would facilitate matters immensely." + +"I will do it." + +"Excellent! We shall then look thoroughly into the affair. Of course there is only one feasible explanation. You have been brought there to personate someone, and the real person is imprisoned in this chamber. That is obvious. As to who this prisoner is, I have no doubt that it is the daughter, Miss Alice Rucastle, if I remember right, who was said to have gone to America. You were chosen, doubtless, as resembling her in height, figure, and the colour of your hair. Hers had been cut off, very possibly in some illness through which she has passed, and so, of course, yours had to be sacrificed also. By a curious chance you came upon her tresses. The man in the road was undoubtedly some friend of hers--possibly her fiance--and no doubt, as you wore the girl's dress and were so like her, he was convinced from your laughter, whenever he saw you, and afterwards from your gesture, that Miss Rucastle was perfectly happy, and that she no longer desired his attentions. The dog is let loose at night to prevent him from endeavouring to communicate with her. So much is fairly clear. The most serious point in the case is the disposition of the child." + +"What on earth has that to do with it?" I ejaculated. + +"My dear Watson, you as a medical man are continually gaining light as to the tendencies of a child by the study of the parents. Don't you see that the converse is equally valid. I have frequently gained my first real insight into the character of parents by studying their children. This child's disposition is abnormally cruel, merely for cruelty's sake, and whether he derives this from his smiling father, as I should suspect, or from his mother, it bodes evil for the poor girl who is in their power." + +"I am sure that you are right, Mr. Holmes," cried our client. "A thousand things come back to me which make me certain that you have hit it. Oh, let us lose not an instant in bringing help to this poor creature." + +"We must be circumspect, for we are dealing with a very cunning man. We can do nothing until seven o'clock. At that hour we shall be with you, and it will not be long before we solve the mystery." + +We were as good as our word, for it was just seven when we reached the Copper Beeches, having put up our trap at a wayside public-house. The group of trees, with their dark leaves shining like burnished metal in the light of the setting sun, were sufficient to mark the house even had Miss Hunter not been standing smiling on the door-step. + +"Have you managed it?" asked Holmes. + +A loud thudding noise came from somewhere downstairs. "That is Mrs. Toller in the cellar," said she. "Her husband lies snoring on the kitchen rug. Here are his keys, which are the duplicates of Mr. Rucastle's." + +"You have done well indeed!" cried Holmes with enthusiasm. "Now lead the way, and we shall soon see the end of this black business." + +We passed up the stair, unlocked the door, followed on down a passage, and found ourselves in front of the barricade which Miss Hunter had described. Holmes cut the cord and removed the transverse bar. Then he tried the various keys in the lock, but without success. No sound came from within, and at the silence Holmes' face clouded over. + +"I trust that we are not too late," said he. "I think, Miss Hunter, that we had better go in without you. Now, Watson, put your shoulder to it, and we shall see whether we cannot make our way in." + +It was an old rickety door and gave at once before our united strength. Together we rushed into the room. It was empty. There was no furniture save a little pallet bed, a small table, and a basketful of linen. The skylight above was open, and the prisoner gone. + +"There has been some villainy here," said Holmes; "this beauty has guessed Miss Hunter's intentions and has carried his victim off." + +"But how?" + +"Through the skylight. We shall soon see how he managed it." He swung himself up onto the roof. "Ah, yes," he cried, "here's the end of a long light ladder against the eaves. That is how he did it." + +"But it is impossible," said Miss Hunter; "the ladder was not there when the Rucastles went away." + +"He has come back and done it. I tell you that he is a clever and dangerous man. I should not be very much surprised if this were he whose step I hear now upon the stair. I think, Watson, that it would be as well for you to have your pistol ready." + +The words were hardly out of his mouth before a man appeared at the door of the room, a very fat and burly man, with a heavy stick in his hand. Miss Hunter screamed and shrunk against the wall at the sight of him, but Sherlock Holmes sprang forward and confronted him. + +"You villain!" said he, "where's your daughter?" + +The fat man cast his eyes round, and then up at the open skylight. + +"It is for me to ask you that," he shrieked, "you thieves! Spies and thieves! I have caught you, have I? You are in my power. I'll serve you!" He turned and clattered down the stairs as hard as he could go. + +"He's gone for the dog!" cried Miss Hunter. + +"I have my revolver," said I. + +"Better close the front door," cried Holmes, and we all rushed down the stairs together. We had hardly reached the hall when we heard the baying of a hound, and then a scream of agony, with a horrible worrying sound which it was dreadful to listen to. An elderly man with a red face and shaking limbs came staggering out at a side door. + +"My God!" he cried. "Someone has loosed the dog. It's not been fed for two days. Quick, quick, or it'll be too late!" + +Holmes and I rushed out and round the angle of the house, with Toller hurrying behind us. There was the huge famished brute, its black muzzle buried in Rucastle's throat, while he writhed and screamed upon the ground. Running up, I blew its brains out, and it fell over with its keen white teeth still meeting in the great creases of his neck. With much labour we separated them and carried him, living but horribly mangled, into the house. We laid him upon the drawing-room sofa, and having dispatched the sobered Toller to bear the news to his wife, I did what I could to relieve his pain. We were all assembled round him when the door opened, and a tall, gaunt woman entered the room. + +"Mrs. Toller!" cried Miss Hunter. + +"Yes, miss. Mr. Rucastle let me out when he came back before he went up to you. Ah, miss, it is a pity you didn't let me know what you were planning, for I would have told you that your pains were wasted." + +"Ha!" said Holmes, looking keenly at her. "It is clear that Mrs. Toller knows more about this matter than anyone else." + +"Yes, sir, I do, and I am ready enough to tell what I know." + +"Then, pray, sit down, and let us hear it for there are several points on which I must confess that I am still in the dark." + +"I will soon make it clear to you," said she; "and I'd have done so before now if I could ha' got out from the cellar. If there's police-court business over this, you'll remember that I was the one that stood your friend, and that I was Miss Alice's friend too. + +"She was never happy at home, Miss Alice wasn't, from the time that her father married again. She was slighted like and had no say in anything, but it never really became bad for her until after she met Mr. Fowler at a friend's house. As well as I could learn, Miss Alice had rights of her own by will, but she was so quiet and patient, she was, that she never said a word about them but just left everything in Mr. Rucastle's hands. He knew he was safe with her; but when there was a chance of a husband coming forward, who would ask for all that the law would give him, then her father thought it time to put a stop on it. He wanted her to sign a paper, so that whether she married or not, he could use her money. When she wouldn't do it, he kept on worrying her until she got brain-fever, and for six weeks was at death's door. Then she got better at last, all worn to a shadow, and with her beautiful hair cut off; but that didn't make no change in her young man, and he stuck to her as true as man could be." + +"Ah," said Holmes, "I think that what you have been good enough to tell us makes the matter fairly clear, and that I can deduce all that remains. Mr. Rucastle then, I presume, took to this system of imprisonment?" + +"Yes, sir." + +"And brought Miss Hunter down from London in order to get rid of the disagreeable persistence of Mr. Fowler." + +"That was it, sir." + +"But Mr. Fowler being a persevering man, as a good seaman should be, blockaded the house, and having met you succeeded by certain arguments, metallic or otherwise, in convincing you that your interests were the same as his." + +"Mr. Fowler was a very kind-spoken, free-handed gentleman," said Mrs. Toller serenely. + +"And in this way he managed that your good man should have no want of drink, and that a ladder should be ready at the moment when your master had gone out." + +"You have it, sir, just as it happened." + +"I am sure we owe you an apology, Mrs. Toller," said Holmes, "for you have certainly cleared up everything which puzzled us. And here comes the country surgeon and Mrs. Rucastle, so I think, Watson, that we had best escort Miss Hunter back to Winchester, as it seems to me that our locus standi now is rather a questionable one." + +And thus was solved the mystery of the sinister house with the copper beeches in front of the door. Mr. Rucastle survived, but was always a broken man, kept alive solely through the care of his devoted wife. They still live with their old servants, who probably know so much of Rucastle's past life that he finds it difficult to part from them. Mr. Fowler and Miss Rucastle were married, by special license, in Southampton the day after their flight, and he is now the holder of a government appointment in the island of Mauritius. As to Miss Violet Hunter, my friend Holmes, rather to my disappointment, manifested no further interest in her when once she had ceased to be the centre of one of his problems, and she is now the head of a private school at Walsall, where I believe that she has met with considerable success. + +*** END OF THE PROJECT GUTENBERG EBOOK, THE ADVENTURES OF SHERLOCK HOLMES *** + +This file should be named advsh12h.htm or advsh12h.zip +Corrected EDITIONS of our eBooks get a new NUMBER, advsh13h.txt +VERSIONS based on separate sources get new LETTER, advsh12ah.txt + +Project Gutenberg eBooks are often created from several printed +editions, all of which are confirmed as Public Domain in the US +unless a copyright notice is included. Thus, we usually do not +keep eBooks in compliance with any particular paper edition. + +We are now trying to release all our eBooks one year in advance +of the official release dates, leaving time for better editing. +Please be encouraged to tell us about any error or corrections, +even years after the official publication date. + +Please note neither this listing nor its contents are final til +midnight of the last day of the month of any such announcement. +The official release date of all Project Gutenberg eBooks is at +Midnight, Central Time, of the last day of the stated month. A +preliminary version may often be posted for suggestion, comment +and editing by those who wish to do so. + +Most people start at our Web sites at: +http://gutenberg.net or +http://promo.net/pg + +These Web sites include award-winning information about Project +Gutenberg, including how to donate, how to help produce our new +eBooks, and how to subscribe to our email newsletter (free!). + + +Those of you who want to download any eBook before announcement +can get to them as follows, and just download by date. This is +also a good way to get them instantly upon announcement, as the +indexes our cataloguers produce obviously take a while after an +announcement goes out in the Project Gutenberg Newsletter. + +http://www.ibiblio.org/gutenberg/etext04 or +ftp://ftp.ibiblio.org/pub/docs/books/gutenberg/etext03 + +Or /etext03, 02, 01, 00, 99, 98, 97, 96, 95, 94, 93, 92, 92, 91 or 90 + +Just search by the first five letters of the filename you want, +as it appears in our Newsletters. + + +Information about Project Gutenberg (one page) + +We produce about two million dollars for each hour we work. The +time it takes us, a rather conservative estimate, is fifty hours +to get any eBook selected, entered, proofread, edited, copyright +searched and analyzed, the copyright letters written, etc. Our +projected audience is one hundred million readers. If the value +per text is nominally estimated at one dollar then we produce $2 +million dollars per hour in 2002 as we release over 100 new text +files per month: 1240 more eBooks in 2001 for a total of 4000+ +We are already on our way to trying for 2000 more eBooks in 2002 +If they reach just 1-2% of the world's population then the total +will reach over half a trillion eBooks given away by year's end. + +The Goal of Project Gutenberg is to Give Away 1 Trillion eBooks! +This is ten thousand titles each to one hundred million readers, +which is only about 4% of the present number of computer users. + +Here is the briefest record of our progress (* means estimated): + +eBooks Year Month + + 1 1971 July + 10 1991 January + 100 1994 January + 1000 1997 August + 1500 1998 October + 2000 1999 December + 2500 2000 December + 3000 2001 November + 4000 2001 October/November + 6000 2002 December* + 9000 2003 November* +10000 2004 January* + + +The Project Gutenberg Literary Archive Foundation has been created +to secure a future for Project Gutenberg into the next millennium. + +We need your donations more than ever! + +As of February, 2002, contributions are being solicited from people +and organizations in: Alabama, Alaska, Arkansas, Connecticut, +Delaware, District of Columbia, Florida, Georgia, Hawaii, Illinois, +Indiana, Iowa, Kansas, Kentucky, Louisiana, Maine, Massachusetts, +Michigan, Mississippi, Missouri, Montana, Nebraska, Nevada, New +Hampshire, New Jersey, New Mexico, New York, North Carolina, Ohio, +Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina, South +Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West +Virginia, Wisconsin, and Wyoming. + +We have filed in all 50 states now, but these are the only ones +that have responded. + +As the requirements for other states are met, additions to this list +will be made and fund raising will begin in the additional states. +Please feel free to ask to check the status of your state. + +In answer to various questions we have received on this: + +We are constantly working on finishing the paperwork to legally +request donations in all 50 states. If your state is not listed and +you would like to know if we have added it since the list you have, +just ask. + +While we cannot solicit donations from people in states where we are +not yet registered, we know of no prohibition against accepting +donations from donors in these states who approach us with an offer to +donate. + +International donations are accepted, but we don't know ANYTHING about +how to make them tax-deductible, or even if they CAN be made +deductible, and don't have the staff to handle it even if there are +ways. + +Donations by check or money order may be sent to: + +Project Gutenberg Literary Archive Foundation +PMB 113 +1739 University Ave. +Oxford, MS 38655-4109 + +Contact us if you want to arrange for a wire transfer or payment +method other than by check or money order. + +The Project Gutenberg Literary Archive Foundation has been approved by +the US Internal Revenue Service as a 501(c)(3) organization with EIN +[Employee Identification Number] 64-622154. Donations are +tax-deductible to the maximum extent permitted by law. As fund-raising +requirements for other states are met, additions to this list will be +made and fund-raising will begin in the additional states. + +We need your donations more than ever! + +You can get up to date donation information online at: + +http://www.gutenberg.net/donation.html + + +*** + +If you can't reach Project Gutenberg, +you can always email directly to: + +Michael S. Hart + +Prof. Hart will answer or forward your message. + +We would prefer to send you information by email. + + +**The Legal Small Print** + + +(Three Pages) + +***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN EBOOKS**START*** +Why is this "Small Print!" statement here? You know: lawyers. +They tell us you might sue us if there is something wrong with +your copy of this eBook, even if you got it for free from +someone other than us, and even if what's wrong is not our +fault. So, among other things, this "Small Print!" statement +disclaims most of our liability to you. It also tells you how +you may distribute copies of this eBook if you want to. + +*BEFORE!* YOU USE OR READ THIS EBOOK +By using or reading any part of this PROJECT GUTENBERG-tm +eBook, you indicate that you understand, agree to and accept +this "Small Print!" statement. If you do not, you can receive +a refund of the money (if any) you paid for this eBook by +sending a request within 30 days of receiving it to the person +you got it from. If you received this eBook on a physical +medium (such as a disk), you must return it with your request. + +ABOUT PROJECT GUTENBERG-TM EBOOKS +This PROJECT GUTENBERG-tm eBook, like most PROJECT GUTENBERG-tm eBooks, +is a "public domain" work distributed by Professor Michael S. Hart +through the Project Gutenberg Association (the "Project"). +Among other things, this means that no one owns a United States copyright +on or for this work, so the Project (and you!) can copy and +distribute it in the United States without permission and +without paying copyright royalties. Special rules, set forth +below, apply if you wish to copy and distribute this eBook +under the "PROJECT GUTENBERG" trademark. + +Please do not use the "PROJECT GUTENBERG" trademark to market +any commercial products without permission. + +To create these eBooks, the Project expends considerable +efforts to identify, transcribe and proofread public domain +works. Despite these efforts, the Project's eBooks and any +medium they may be on may contain "Defects". Among other +things, Defects may take the form of incomplete, inaccurate or +corrupt data, transcription errors, a copyright or other +intellectual property infringement, a defective or damaged +disk or other eBook medium, a computer virus, or computer +codes that damage or cannot be read by your equipment. + +LIMITED WARRANTY; DISCLAIMER OF DAMAGES +But for the "Right of Replacement or Refund" described below, +[1] Michael Hart and the Foundation (and any other party you may +receive this eBook from as a PROJECT GUTENBERG-tm eBook) disclaims +all liability to you for damages, costs and expenses, including +legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR +UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT, +INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE +OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE +POSSIBILITY OF SUCH DAMAGES. + +If you discover a Defect in this eBook within 90 days of +receiving it, you can receive a refund of the money (if any) +you paid for it by sending an explanatory note within that +time to the person you received it from. If you received it +on a physical medium, you must return it with your note, and +such person may choose to alternatively give you a replacement +copy. If you received it electronically, such person may +choose to alternatively give you a second opportunity to +receive it electronically. + +THIS EBOOK IS OTHERWISE PROVIDED TO YOU "AS-IS". NO OTHER +WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS +TO THE EBOOK OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT +LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A +PARTICULAR PURPOSE. + +Some states do not allow disclaimers of implied warranties or +the exclusion or limitation of consequential damages, so the +above disclaimers and exclusions may not apply to you, and you +may have other legal rights. + +INDEMNITY +You will indemnify and hold Michael Hart, the Foundation, +and its trustees and agents, and any volunteers associated +with the production and distribution of Project Gutenberg-tm +texts harmless, from all liability, cost and expense, including +legal fees, that arise directly or indirectly from any of the +following that you do or cause: [1] distribution of this eBook, +[2] alteration, modification, or addition to the eBook, +or [3] any Defect. + +DISTRIBUTION UNDER "PROJECT GUTENBERG-tm" +You may distribute copies of this eBook electronically, or by +disk, book or any other medium if you either delete this +"Small Print!" and all other references to Project Gutenberg, +or: + +[1] Only give exact copies of it. Among other things, this + requires that you do not remove, alter or modify the + eBook or this "small print!" statement. You may however, + if you wish, distribute this eBook in machine readable + binary, compressed, mark-up, or proprietary form, + including any form resulting from conversion by word + processing or hypertext software, but only so long as + *EITHER*: + + [*] The eBook, when displayed, is clearly readable, and + does *not* contain characters other than those + intended by the author of the work, although tilde + (~), asterisk (*) and underline (_) characters may + be used to convey punctuation intended by the + author, and additional characters may be used to + indicate hypertext links; OR + + [*] The eBook may be readily converted by the reader at + no expense into plain ASCII, EBCDIC or equivalent + form by the program that displays the eBook (as is + the case, for instance, with most word processors); + OR + + [*] You provide, or agree to also provide on request at + no additional cost, fee or expense, a copy of the + eBook in its original plain ASCII form (or in EBCDIC + or other equivalent proprietary form). + +[2] Honor the eBook refund and replacement provisions of this + "Small Print!" statement. + +[3] Pay a trademark license fee to the Foundation of 20% of the + gross profits you derive calculated using the method you + already use to calculate your applicable taxes. If you + don't derive profits, no royalty is due. Royalties are + payable to "Project Gutenberg Literary Archive Foundation" + the 60 days following each date you prepare (or were + legally required to prepare) your annual (or equivalent + periodic) tax return. Please contact us beforehand to + let us know your plans and to work out the details. + +WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO? +Project Gutenberg is dedicated to increasing the number of +public domain and licensed works that can be freely distributed +in machine readable form. + +The Project gratefully accepts contributions of money, time, +public domain materials, or royalty free copyright licenses. +Money should be paid to the: +"Project Gutenberg Literary Archive Foundation." + +If you are interested in contributing scanning equipment or +software or other items, please contact Michael Hart at: +hart@pobox.com + +[Portions of this eBook's header and trailer may be reprinted only +when distributed free of all fees. Copyright (C) 2001, 2002 by +Michael S. Hart. Project Gutenberg is a TradeMark and may not be +used in any sales of Project Gutenberg eBooks or other materials be +they hardware or software or any other related product without +express permission.] + +*END THE SMALL PRINT! FOR PUBLIC DOMAIN EBOOKS*Ver.02/11/02*END* + + + +The Project Gutenberg EBook of History of the United States +by Charles A. Beard and Mary R. Beard + +This eBook is for the use of anyone anywhere at no cost and with +almost no restrictions whatsoever. You may copy it, give it away or +re-use it under the terms of the Project Gutenberg License included +with this eBook or online at www.gutenberg.net + + +Title: History of the United States + +Author: Charles A. Beard and Mary R. Beard + +Release Date: October 28, 2005 [EBook #16960] + +Language: English + +Character set encoding: ISO-8859-1 + +*** START OF THIS PROJECT GUTENBERG EBOOK HISTORY OF THE UNITED STATES *** + + + + +Produced by Curtis Weyant, M and the Online Distributed +Proofreading Team at http://www.pgdp.net + + + + + + + +HISTORY + +OF THE + +UNITED STATES + + +BY + + +CHARLES A. BEARD + +AND + +MARY R. BEARD + + + +New York + +THE MACMILLAN COMPANY + +1921 + +_All rights reserved_ + +COPYRIGHT, 1921, + +BY THE MACMILLAN COMPANY. + + +Set up and electrotyped. Published March, 1921. + + + + +Norwood Press + +J.S. Cushing Co.--Berwick & Smith Co. + +NORWOOD, MASS., U.S.A. + + + + +PREFACE + + +As things now stand, the course of instruction in American history in +our public schools embraces three distinct treatments of the subject. +Three separate books are used. First, there is the primary book, which +is usually a very condensed narrative with emphasis on biographies and +anecdotes. Second, there is the advanced text for the seventh or eighth +grade, generally speaking, an expansion of the elementary book by the +addition of forty or fifty thousand words. Finally, there is the high +school manual. This, too, ordinarily follows the beaten path, giving +fuller accounts of the same events and characters. To put it bluntly, we +do not assume that our children obtain permanent possessions from their +study of history in the lower grades. If mathematicians followed the +same method, high school texts on algebra and geometry would include the +multiplication table and fractions. + +There is, of course, a ready answer to the criticism advanced above. It +is that teachers have learned from bitter experience how little history +their pupils retain as they pass along the regular route. No teacher of +history will deny this. Still it is a standing challenge to existing +methods of historical instruction. If the study of history cannot be +made truly progressive like the study of mathematics, science, and +languages, then the historians assume a grave responsibility in adding +their subject to the already overloaded curriculum. If the successive +historical texts are only enlarged editions of the first text--more +facts, more dates, more words--then history deserves most of the sharp +criticism which it is receiving from teachers of science, civics, and +economics. + +In this condition of affairs we find our justification for offering a +new high school text in American history. Our first contribution is one +of omission. The time-honored stories of exploration and the +biographies of heroes are left out. We frankly hold that, if pupils know +little or nothing about Columbus, Cortes, Magellan, or Captain John +Smith by the time they reach the high school, it is useless to tell the +same stories for perhaps the fourth time. It is worse than useless. It +is an offense against the teachers of those subjects that are +demonstrated to be progressive in character. + +In the next place we have omitted all descriptions of battles. Our +reasons for this are simple. The strategy of a campaign or of a single +battle is a highly technical, and usually a highly controversial, matter +about which experts differ widely. In the field of military and naval +operations most writers and teachers of history are mere novices. To +dispose of Gettysburg or the Wilderness in ten lines or ten pages is +equally absurd to the serious student of military affairs. Any one who +compares the ordinary textbook account of a single Civil War campaign +with the account given by Ropes, for instance, will ask for no further +comment. No youth called upon to serve our country in arms would think +of turning to a high school manual for information about the art of +warfare. The dramatic scene or episode, so useful in arousing the +interest of the immature pupil, seems out of place in a book that +deliberately appeals to boys and girls on the very threshold of life's +serious responsibilities. + +It is not upon negative features, however, that we rest our case. It is +rather upon constructive features. + +_First._ We have written a topical, not a narrative, history. We have +tried to set forth the important aspects, problems, and movements of +each period, bringing in the narrative rather by way of illustration. + +_Second._ We have emphasized those historical topics which help to +explain how our nation has come to be what it is to-day. + +_Third._ We have dwelt fully upon the social and economic aspects of our +history, especially in relation to the politics of each period. + +_Fourth._ We have treated the causes and results of wars, the problems +of financing and sustaining armed forces, rather than military strategy. +These are the subjects which belong to a history for civilians. These +are matters which civilians can understand--matters which they must +understand, if they are to play well their part in war and peace. + +_Fifth._ By omitting the period of exploration, we have been able to +enlarge the treatment of our own time. We have given special attention +to the history of those current questions which must form the subject +matter of sound instruction in citizenship. + +_Sixth._ We have borne in mind that America, with all her unique +characteristics, is a part of a general civilization. Accordingly we +have given diplomacy, foreign affairs, world relations, and the +reciprocal influences of nations their appropriate place. + +_Seventh._ We have deliberately aimed at standards of maturity. The +study of a mere narrative calls mainly for the use of the memory. We +have aimed to stimulate habits of analysis, comparison, association, +reflection, and generalization--habits calculated to enlarge as well as +inform the mind. We have been at great pains to make our text clear, +simple, and direct; but we have earnestly sought to stretch the +intellects of our readers--to put them upon their mettle. Most of them +will receive the last of their formal instruction in the high school. +The world will soon expect maturity from them. Their achievements will +depend upon the possession of other powers than memory alone. The +effectiveness of their citizenship in our republic will be measured by +the excellence of their judgment as well as the fullness of their +information. + + C.A.B. + M.R.B. + + NEW YORK CITY, + February 8, 1921. + + + + +=A SMALL LIBRARY IN AMERICAN HISTORY= + + +_=SINGLE VOLUMES:=_ + +BASSETT, J.S. _A Short History of the United States_ +ELSON, H.W. _History of the United States of America_ + + +_=SERIES:=_ + +"EPOCHS OF AMERICAN HISTORY," EDITED BY A.B. HART + +HART, A.B. _Formation of the Union_ +THWAITES, R.G. _The Colonies_ +WILSON, WOODROW. _Division and Reunion_ + +"RIVERSIDE SERIES," EDITED BY W.E. DODD + +BECKER, C.L. _Beginnings of the American People_ +DODD, W.E. _Expansion and Conflict_ +JOHNSON, A. _Union and Democracy_ +PAXSON, F.L. _The New Nation_ + + + + +CONTENTS + + +PART I. THE COLONIAL PERIOD + +CHAPTER PAGE + I. THE GREAT MIGRATION TO AMERICA 1 + The Agencies of American Colonization 2 + The Colonial Peoples 6 + The Process of Colonization 12 + + II. COLONIAL AGRICULTURE, INDUSTRY, AND COMMERCE 20 + The Land and the Westward Movement 20 + Industrial and Commercial Development 28 + + III. SOCIAL AND POLITICAL PROGRESS 38 + The Leadership of the Churches 39 + Schools and Colleges 43 + The Colonial Press 46 + The Evolution in Political Institutions 48 + + IV. THE DEVELOPMENT OF COLONIAL NATIONALISM 56 + Relations with the Indians and the French 57 + The Effects of Warfare on the Colonies 61 + Colonial Relations with the British Government 64 + Summary of Colonial Period 73 + + +PART II. CONFLICT AND INDEPENDENCE + + V. THE NEW COURSE IN BRITISH IMPERIAL POLICY 77 + George III and His System 77 + George III's Ministers and Their Colonial Policies 79 + Colonial Resistance Forces Repeal 83 + Resumption of British Revenue and Commercial Policies 87 + Renewed Resistance in America 90 + Retaliation by the British Government 93 + From Reform to Revolution in America 95 + + VI. THE AMERICAN REVOLUTION 99 + Resistance and Retaliation 99 + American Independence 101 + The Establishment of Government and the New Allegiance 108 + Military Affairs 116 + The Finances of the Revolution 125 + The Diplomacy of the Revolution 127 + Peace at Last 132 + Summary of the Revolutionary Period 135 + + +PART III. FOUNDATIONS OF THE UNION AND NATIONAL POLITICS + + VII. THE FORMATION OF THE CONSTITUTION 139 + The Promise and the Difficulties of America 139 + The Calling of a Constitutional Convention 143 + The Framing of the Constitution 146 + The Struggle over Ratification 157 + + VIII. THE CLASH OF POLITICAL PARTIES 162 + The Men and Measures of the New Government 162 + The Rise of Political Parties 168 + Foreign Influences and Domestic Politics 171 + + IX. THE JEFFERSONIAN REPUBLICANS IN POWER 186 + Republican Principles and Policies 186 + The Republicans and the Great West 188 + The Republican War for Commercial Independence 193 + The Republicans Nationalized 201 + The National Decisions of Chief Justice Marshall 208 + Summary of Union and National Politics 212 + + +PART IV. THE WEST AND JACKSONIAN DEMOCRACY + + X. THE FARMERS BEYOND THE APPALACHIANS 217 + Preparation for Western Settlement 217 + The Western Migration and New States 221 + The Spirit of the Frontier 228 + The West and the East Meet 230 + + XI. JACKSONIAN DEMOCRACY 238 + The Democratic Movement in the East 238 + The New Democracy Enters the Arena 244 + The New Democracy at Washington 250 + The Rise of the Whigs 260 + The Interaction of American and European Opinion 265 + + XII. THE MIDDLE BORDER AND THE GREAT WEST 271 + The Advance of the Middle Border 271 + On to the Pacific--Texas and the Mexican War 276 + The Pacific Coast and Utah 284 + Summary of Western Development and National Politics 292 + + +PART V. SECTIONAL CONFLICT AND RECONSTRUCTION + + XIII. THE RISE OF THE INDUSTRIAL SYSTEM 295 + The Industrial Revolution 296 + The Industrial Revolution and National Politics 307 + + XIV. THE PLANTING SYSTEM AND NATIONAL POLITICS 316 + Slavery--North and South 316 + Slavery in National Politics 324 + The Drift of Events toward the Irrepressible Conflict 332 + + XV. THE CIVIL WAR AND RECONSTRUCTION 344 + The Southern Confederacy 344 + The War Measures of the Federal Government 350 + The Results of the Civil War 365 + Reconstruction in the South 370 + Summary of the Sectional Conflict 375 + + +PART VI. NATIONAL GROWTH AND WORLD POLITICS + + XVI. THE POLITICAL AND ECONOMIC EVOLUTION OF THE SOUTH 379 + The South at the Close of the War 379 + The Restoration of White Supremacy 382 + The Economic Advance of the South 389 + + XVII. BUSINESS ENTERPRISE AND THE REPUBLICAN PARTY 401 + Railways and Industry 401 + The Supremacy of the Republican Party (1861-1885) 412 + The Growth of Opposition to Republican Rule 417 + +XVIII. THE DEVELOPMENT OF THE GREAT WEST 425 + The Railways as Trail Blazers 425 + The Evolution of Grazing and Agriculture 431 + Mining and Manufacturing in the West 436 + The Admission of New States 440 + The Influence of the Far West on National Life 443 + + XIX. DOMESTIC ISSUES BEFORE THE COUNTRY (1865-1897) 451 + The Currency Question 452 + The Protective Tariff and Taxation 459 + The Railways and Trusts 460 + The Minor Parties and Unrest 462 + The Sound Money Battle of 1896 466 + Republican Measures and Results 472 + + XX. AMERICA A WORLD POWER (1865-1900) 477 + American Foreign Relations (1865-1898) 478 + Cuba and the Spanish War 485 + American Policies in the Philippines and the Orient 497 + Summary of National Growth and World Politics 504 + + +PART VII. PROGRESSIVE DEMOCRACY AND THE WORLD WAR + + XXI. THE EVOLUTION OF REPUBLICAN POLICIES (1901-1913) 507 + Foreign Affairs 508 + Colonial Administration 515 + The Roosevelt Domestic Policies 519 + Legislative and Executive Activities 523 + The Administration of President Taft 527 + Progressive Insurgency and the Election of 1912 530 + + XXII. THE SPIRIT OF REFORM IN AMERICA 536 + An Age of Criticism 536 + Political Reforms 538 + Measures of Economic Reform 546 + +XXIII. THE NEW POLITICAL DEMOCRACY 554 + The Rise of the Woman Movement 555 + The National Struggle for Woman Suffrage 562 + + XXIV. INDUSTRIAL DEMOCRACY 570 + Cooperation between Employers and Employees 571 + The Rise and Growth of Organized Labor 575 + The Wider Relations of Organized Labor 577 + Immigration and Americanization 582 + + XXV. PRESIDENT WILSON AND THE WORLD WAR 588 + Domestic Legislation 588 + Colonial and Foreign Policies 592 + The United States and the European War 596 + The United States at War 604 + The Settlement at Paris 612 + Summary of Democracy and the World War 620 + +APPENDIX 627 + +A TOPICAL SYLLABUS 645 + +INDEX 655 + + + + +MAPS + + + PAGE +The Original Grants (color map) _Facing_ 4 + +German and Scotch-Irish Settlements 8 + +Distribution of Population in 1790 27 + +English, French, and Spanish Possessions in America, 1750 + (color map) _Facing_ 59 + +The Colonies at the Time of the Declaration of Independence + (color map) _Facing_ 108 + +North America according to the Treaty of 1783 + (color map) _Facing_ 134 + +The United States in 1805 (color map) _Facing_ 193 + +Roads and Trails into Western Territory (color map) _Facing_ 224 + +The Cumberland Road 233 + +Distribution of Population in 1830 235 + +Texas and the Territory in Dispute 282 + +The Oregon Country and the Disputed Boundary 285 + +The Overland Trails 287 + +Distribution of Slaves in Southern States 323 + +The Missouri Compromise 326 + +Slave and Free Soil on the Eve of the Civil War 335 + +The United States in 1861 (color map) _Facing_ 345 + +Railroads of the United States in 1918 405 + +The United States in 1870 (color map) _Facing_ 427 + +The United States in 1912 (color map) _Facing_ 443 + +American Dominions in the Pacific (color map) _Facing_ 500 + +The Caribbean Region (color map) _Facing_ 592 + +Battle Lines of the Various Years of the World War 613 + +Europe in 1919 (color map) _Between_ 618-619 + + "THE NATIONS OF THE WEST" (popularly called "The + Pioneers"), designed by A. Stirling Calder and modeled by + Mr. Calder, F.G.R. Roth, and Leo Lentelli, topped the Arch + of the Setting Sun at the Panama-Pacific Exposition held at + San Francisco in 1915. Facing the Court of the Universe + moves a group of men and women typical of those who have + made our civilization. From left to right appear the + French-Canadian, the Alaskan, the Latin-American, the + German, the Italian, the Anglo-American, and the American + Indian, squaw and warrior. In the place of honor in the + center of the group, standing between the oxen on the tongue + of the prairie schooner, is a figure, beautiful and almost + girlish, but strong, dignified, and womanly, the Mother of + To-morrow. Above the group rides the Spirit of Enterprise, + flanked right and left by the Hopes of the Future in the + person of two boys. The group as a whole is beautifully + symbolic of the westward march of American civilization. + +[Illustration: _Photograph by Cardinell-Vincent Co., San Francisco_ + +"THE NATIONS OF THE WEST"] + + + + +HISTORY OF THE UNITED STATES + + + + +PART I. THE COLONIAL PERIOD + + + + +CHAPTER I + +THE GREAT MIGRATION TO AMERICA + + +The tide of migration that set in toward the shores of North America +during the early years of the seventeenth century was but one phase in +the restless and eternal movement of mankind upon the surface of the +earth. The ancient Greeks flung out their colonies in every direction, +westward as far as Gaul, across the Mediterranean, and eastward into +Asia Minor, perhaps to the very confines of India. The Romans, supported +by their armies and their government, spread their dominion beyond the +narrow lands of Italy until it stretched from the heather of Scotland to +the sands of Arabia. The Teutonic tribes, from their home beyond the +Danube and the Rhine, poured into the empire of the Caesars and made the +beginnings of modern Europe. Of this great sweep of races and empires +the settlement of America was merely a part. And it was, moreover, only +one aspect of the expansion which finally carried the peoples, the +institutions, and the trade of Europe to the very ends of the earth. + +In one vital point, it must be noted, American colonization differed +from that of the ancients. The Greeks usually carried with them +affection for the government they left behind and sacred fire from the +altar of the parent city; but thousands of the immigrants who came to +America disliked the state and disowned the church of the mother +country. They established compacts of government for themselves and set +up altars of their own. They sought not only new soil to till but also +political and religious liberty for themselves and their children. + + +THE AGENCIES OF AMERICAN COLONIZATION + +It was no light matter for the English to cross three thousand miles of +water and found homes in the American wilderness at the opening of the +seventeenth century. Ships, tools, and supplies called for huge outlays +of money. Stores had to be furnished in quantities sufficient to sustain +the life of the settlers until they could gather harvests of their own. +Artisans and laborers of skill and industry had to be induced to risk +the hazards of the new world. Soldiers were required for defense and +mariners for the exploration of inland waters. Leaders of good judgment, +adept in managing men, had to be discovered. Altogether such an +enterprise demanded capital larger than the ordinary merchant or +gentleman could amass and involved risks more imminent than he dared to +assume. Though in later days, after initial tests had been made, wealthy +proprietors were able to establish colonies on their own account, it was +the corporation that furnished the capital and leadership in the +beginning. + +=The Trading Company.=--English pioneers in exploration found an +instrument for colonization in companies of merchant adventurers, which +had long been employed in carrying on commerce with foreign countries. +Such a corporation was composed of many persons of different ranks of +society--noblemen, merchants, and gentlemen--who banded together for a +particular undertaking, each contributing a sum of money and sharing in +the profits of the venture. It was organized under royal authority; it +received its charter, its grant of land, and its trading privileges from +the king and carried on its operations under his supervision and +control. The charter named all the persons originally included in the +corporation and gave them certain powers in the management of its +affairs, including the right to admit new members. The company was in +fact a little government set up by the king. When the members of the +corporation remained in England, as in the case of the Virginia Company, +they operated through agents sent to the colony. When they came over the +seas themselves and settled in America, as in the case of Massachusetts, +they became the direct government of the country they possessed. The +stockholders in that instance became the voters and the governor, the +chief magistrate. + +[Illustration: JOHN WINTHROP, GOVERNOR OF THE MASSACHUSETTS BAY +COMPANY] + +Four of the thirteen colonies in America owed their origins to the +trading corporation. It was the London Company, created by King James I, +in 1606, that laid during the following year the foundations of Virginia +at Jamestown. It was under the auspices of their West India Company, +chartered in 1621, that the Dutch planted the settlements of the New +Netherland in the valley of the Hudson. The founders of Massachusetts +were Puritan leaders and men of affairs whom King Charles I incorporated +in 1629 under the title: "The governor and company of the Massachusetts +Bay in New England." In this case the law did but incorporate a group +drawn together by religious ties. "We must be knit together as one man," +wrote John Winthrop, the first Puritan governor in America. Far to the +south, on the banks of the Delaware River, a Swedish commercial company +in 1638 made the beginnings of a settlement, christened New Sweden; it +was destined to pass under the rule of the Dutch, and finally under the +rule of William Penn as the proprietary colony of Delaware. + +In a certain sense, Georgia may be included among the "company +colonies." It was, however, originally conceived by the moving spirit, +James Oglethorpe, as an asylum for poor men, especially those imprisoned +for debt. To realize this humane purpose, he secured from King George +II, in 1732, a royal charter uniting several gentlemen, including +himself, into "one body politic and corporate," known as the "Trustees +for establishing the colony of Georgia in America." In the structure of +their organization and their methods of government, the trustees did not +differ materially from the regular companies created for trade and +colonization. Though their purposes were benevolent, their transactions +had to be under the forms of law and according to the rules of business. + +=The Religious Congregation.=--A second agency which figured largely in +the settlement of America was the religious brotherhood, or +congregation, of men and women brought together in the bonds of a common +religious faith. By one of the strange fortunes of history, this +institution, founded in the early days of Christianity, proved to be a +potent force in the origin and growth of self-government in a land far +away from Galilee. "And the multitude of them that believed were of one +heart and of one soul," we are told in the Acts describing the Church at +Jerusalem. "We are knit together as a body in a most sacred covenant of +the Lord ... by virtue of which we hold ourselves strictly tied to all +care of each other's good and of the whole," wrote John Robinson, a +leader among the Pilgrims who founded their tiny colony of Plymouth in +1620. The Mayflower Compact, so famous in American history, was but a +written and signed agreement, incorporating the spirit of obedience to +the common good, which served as a guide to self-government until +Plymouth was annexed to Massachusetts in 1691. + +[Illustration: THE ORIGINAL GRANTS] + +Three other colonies, all of which retained their identity until the eve +of the American Revolution, likewise sprang directly from the +congregations of the faithful: Rhode Island, Connecticut, and New +Hampshire, mainly offshoots from Massachusetts. They were founded by +small bodies of men and women, "united in solemn covenants with the +Lord," who planted their settlements in the wilderness. Not until many a +year after Roger Williams and Anne Hutchinson conducted their followers +to the Narragansett country was Rhode Island granted a charter of +incorporation (1663) by the crown. Not until long after the congregation +of Thomas Hooker from Newtown blazed the way into the Connecticut River +Valley did the king of England give Connecticut a charter of its own +(1662) and a place among the colonies. Half a century elapsed before the +towns laid out beyond the Merrimac River by emigrants from Massachusetts +were formed into the royal province of New Hampshire in 1679. + +Even when Connecticut was chartered, the parchment and sealing wax of +the royal lawyers did but confirm rights and habits of self-government +and obedience to law previously established by the congregations. The +towns of Hartford, Windsor, and Wethersfield had long lived happily +under their "Fundamental Orders" drawn up by themselves in 1639; so had +the settlers dwelt peacefully at New Haven under their "Fundamental +Articles" drafted in the same year. The pioneers on the Connecticut +shore had no difficulty in agreeing that "the Scriptures do hold forth a +perfect rule for the direction and government of all men." + +=The Proprietor.=--A third and very important colonial agency was the +proprietor, or proprietary. As the name, associated with the word +"property," implies, the proprietor was a person to whom the king +granted property in lands in North America to have, hold, use, and enjoy +for his own benefit and profit, with the right to hand the estate down +to his heirs in perpetual succession. The proprietor was a rich and +powerful person, prepared to furnish or secure the capital, collect the +ships, supply the stores, and assemble the settlers necessary to found +and sustain a plantation beyond the seas. Sometimes the proprietor +worked alone. Sometimes two or more were associated like partners in the +common undertaking. + +Five colonies, Maryland, Pennsylvania, New Jersey, and the Carolinas, +owe their formal origins, though not always their first settlements, nor +in most cases their prosperity, to the proprietary system. Maryland, +established in 1634 under a Catholic nobleman, Lord Baltimore, and +blessed with religious toleration by the act of 1649, flourished under +the mild rule of proprietors until it became a state in the American +union. New Jersey, beginning its career under two proprietors, Berkeley +and Carteret, in 1664, passed under the direct government of the crown +in 1702. Pennsylvania was, in a very large measure, the product of the +generous spirit and tireless labors of its first proprietor, the leader +of the Friends, William Penn, to whom it was granted in 1681 and in +whose family it remained until 1776. The two Carolinas were first +organized as one colony in 1663 under the government and patronage of +eight proprietors, including Lord Clarendon; but after more than half a +century both became royal provinces governed by the king. + +[Illustration: WILLIAM PENN, PROPRIETOR OF PENNSYLVANIA] + + +THE COLONIAL PEOPLES + +=The English.=--In leadership and origin the thirteen colonies, except +New York and Delaware, were English. During the early days of all, save +these two, the main, if not the sole, current of immigration was from +England. The colonists came from every walk of life. They were men, +women, and children of "all sorts and conditions." The major portion +were yeomen, or small land owners, farm laborers, and artisans. With +them were merchants and gentlemen who brought their stocks of goods or +their fortunes to the New World. Scholars came from Oxford and +Cambridge to preach the gospel or to teach. Now and then the son of an +English nobleman left his baronial hall behind and cast his lot with +America. The people represented every religious faith--members of the +Established Church of England; Puritans who had labored to reform that +church; Separatists, Baptists, and Friends, who had left it altogether; +and Catholics, who clung to the religion of their fathers. + +New England was almost purely English. During the years between 1629 and +1640, the period of arbitrary Stuart government, about twenty thousand +Puritans emigrated to America, settling in the colonies of the far +North. Although minor additions were made from time to time, the greater +portion of the New England people sprang from this original stock. +Virginia, too, for a long time drew nearly all her immigrants from +England alone. Not until the eve of the Revolution did other +nationalities, mainly the Scotch-Irish and Germans, rival the English in +numbers. + +The populations of later English colonies--the Carolinas, New York, +Pennsylvania, and Georgia--while receiving a steady stream of +immigration from England, were constantly augmented by wanderers from +the older settlements. New York was invaded by Puritans from New England +in such numbers as to cause the Anglican clergymen there to lament that +"free thinking spreads almost as fast as the Church." North Carolina was +first settled toward the northern border by immigrants from Virginia. +Some of the North Carolinians, particularly the Quakers, came all the +way from New England, tarrying in Virginia only long enough to learn how +little they were wanted in that Anglican colony. + +=The Scotch-Irish.=--Next to the English in numbers and influence were +the Scotch-Irish, Presbyterians in belief, English in tongue. Both +religious and economic reasons sent them across the sea. Their Scotch +ancestors, in the days of Cromwell, had settled in the north of Ireland +whence the native Irish had been driven by the conqueror's sword. There +the Scotch nourished for many years enjoying in peace their own form of +religion and growing prosperous in the manufacture of fine linen and +woolen cloth. Then the blow fell. Toward the end of the seventeenth +century their religious worship was put under the ban and the export of +their cloth was forbidden by the English Parliament. Within two decades +twenty thousand Scotch-Irish left Ulster alone, for America; and all +during the eighteenth century the migration continued to be heavy. +Although no exact record was kept, it is reckoned that the Scotch-Irish +and the Scotch who came directly from Scotland, composed one-sixth of +the entire American population on the eve of the Revolution. + +[Illustration: SETTLEMENTS OF GERMAN AND SCOTCH-IRISH +IMMIGRANTS] + +These newcomers in America made their homes chiefly in New Jersey, +Pennsylvania, Maryland, Virginia, and the Carolinas. Coming late upon +the scene, they found much of the land immediately upon the seaboard +already taken up. For this reason most of them became frontier people +settling the interior and upland regions. There they cleared the land, +laid out their small farms, and worked as "sturdy yeomen on the soil," +hardy, industrious, and independent in spirit, sharing neither the +luxuries of the rich planters nor the easy life of the leisurely +merchants. To their agriculture they added woolen and linen +manufactures, which, flourishing in the supple fingers of their tireless +women, made heavy inroads upon the trade of the English merchants in +the colonies. Of their labors a poet has sung: + + "O, willing hands to toil; + Strong natures tuned to the harvest-song and bound to the kindly soil; + Bold pioneers for the wilderness, defenders in the field." + +=The Germans.=--Third among the colonists in order of numerical +importance were the Germans. From the very beginning, they appeared in +colonial records. A number of the artisans and carpenters in the first +Jamestown colony were of German descent. Peter Minuit, the famous +governor of New Motherland, was a German from Wesel on the Rhine, and +Jacob Leisler, leader of a popular uprising against the provincial +administration of New York, was a German from Frankfort-on-Main. The +wholesale migration of Germans began with the founding of Pennsylvania. +Penn was diligent in searching for thrifty farmers to cultivate his +lands and he made a special effort to attract peasants from the Rhine +country. A great association, known as the Frankfort Company, bought +more than twenty thousand acres from him and in 1684 established a +center at Germantown for the distribution of German immigrants. In old +New York, Rhinebeck-on-the-Hudson became a similar center for +distribution. All the way from Maine to Georgia inducements were offered +to the German farmers and in nearly every colony were to be found, in +time, German settlements. In fact the migration became so large that +German princes were frightened at the loss of so many subjects and +England was alarmed by the influx of foreigners into her overseas +dominions. Yet nothing could stop the movement. By the end of the +colonial period, the number of Germans had risen to more than two +hundred thousand. + +The majority of them were Protestants from the Rhine region, and South +Germany. Wars, religious controversies, oppression, and poverty drove +them forth to America. Though most of them were farmers, there were also +among them skilled artisans who contributed to the rapid growth of +industries in Pennsylvania. Their iron, glass, paper, and woolen mills, +dotted here and there among the thickly settled regions, added to the +wealth and independence of the province. + +[Illustration: _From an old print_ + +A GLIMPSE OF OLD GERMANTOWN] + +Unlike the Scotch-Irish, the Germans did not speak the language of the +original colonists or mingle freely with them. They kept to themselves, +built their own schools, founded their own newspapers, and published +their own books. Their clannish habits often irritated their neighbors +and led to occasional agitations against "foreigners." However, no +serious collisions seem to have occurred; and in the days of the +Revolution, German soldiers from Pennsylvania fought in the patriot +armies side by side with soldiers from the English and Scotch-Irish +sections. + +=Other Nationalities.=--Though the English, the Scotch-Irish, and the +Germans made up the bulk of the colonial population, there were other +racial strains as well, varying in numerical importance but contributing +their share to colonial life. + +From France came the Huguenots fleeing from the decree of the king which +inflicted terrible penalties upon Protestants. + +From "Old Ireland" came thousands of native Irish, Celtic in race and +Catholic in religion. Like their Scotch-Irish neighbors to the north, +they revered neither the government nor the church of England imposed +upon them by the sword. How many came we do not know, but shipping +records of the colonial period show that boatload after boatload left +the southern and eastern shores of Ireland for the New World. +Undoubtedly thousands of their passengers were Irish of the native +stock. This surmise is well sustained by the constant appearance of +Celtic names in the records of various colonies. + +[Illustration:_From an old print_ + +OLD DUTCH FORT AND ENGLISH CHURCH NEAR ALBANY] + +The Jews, then as ever engaged in their age-long battle for religious +and economic toleration, found in the American colonies, not complete +liberty, but certainly more freedom than they enjoyed in England, +France, Spain, or Portugal. The English law did not actually recognize +their right to live in any of the dominions, but owing to the easy-going +habits of the Americans they were allowed to filter into the seaboard +towns. The treatment they received there varied. On one occasion the +mayor and council of New York forbade them to sell by retail and on +another prohibited the exercise of their religious worship. Newport, +Philadelphia, and Charleston were more hospitable, and there large +Jewish colonies, consisting principally of merchants and their families, +flourished in spite of nominal prohibitions of the law. + +Though the small Swedish colony in Delaware was quickly submerged +beneath the tide of English migration, the Dutch in New York continued +to hold their own for more than a hundred years after the English +conquest in 1664. At the end of the colonial period over one-half of the +170,000 inhabitants of the province were descendants of the original +Dutch--still distinct enough to give a decided cast to the life and +manners of New York. Many of them clung as tenaciously to their mother +tongue as they did to their capacious farmhouses or their Dutch ovens; +but they were slowly losing their identity as the English pressed in +beside them to farm and trade. + +The melting pot had begun its historic mission. + + +THE PROCESS OF COLONIZATION + +Considered from one side, colonization, whatever the motives of the +emigrants, was an economic matter. It involved the use of capital to pay +for their passage, to sustain them on the voyage, and to start them on +the way of production. Under this stern economic necessity, Puritans, +Scotch-Irish, Germans, and all were alike laid. + +=Immigrants Who Paid Their Own Way.=--Many of the immigrants to America +in colonial days were capitalists themselves, in a small or a large way, +and paid their own passage. What proportion of the colonists were able +to finance their voyage across the sea is a matter of pure conjecture. +Undoubtedly a very considerable number could do so, for we can trace the +family fortunes of many early settlers. Henry Cabot Lodge is authority +for the statement that "the settlers of New England were drawn from the +country gentlemen, small farmers, and yeomanry of the mother +country.... Many of the emigrants were men of wealth, as the old lists +show, and all of them, with few exceptions, were men of property and +good standing. They did not belong to the classes from which emigration +is usually supplied, for they all had a stake in the country they left +behind." Though it would be interesting to know how accurate this +statement is or how applicable to the other colonies, no study has as +yet been made to gratify that interest. For the present it is an +unsolved problem just how many of the colonists were able to bear the +cost of their own transfer to the New World. + +=Indentured Servants.=--That at least tens of thousands of immigrants +were unable to pay for their passage is established beyond the shadow of +a doubt by the shipping records that have come down to us. The great +barrier in the way of the poor who wanted to go to America was the cost +of the sea voyage. To overcome this difficulty a plan was worked out +whereby shipowners and other persons of means furnished the passage +money to immigrants in return for their promise, or bond, to work for a +term of years to repay the sum advanced. This system was called +indentured servitude. + +It is probable that the number of bond servants exceeded the original +twenty thousand Puritans, the yeomen, the Virginia gentlemen, and the +Huguenots combined. All the way down the coast from Massachusetts to +Georgia were to be found in the fields, kitchens, and workshops, men, +women, and children serving out terms of bondage generally ranging from +five to seven years. In the proprietary colonies the proportion of bond +servants was very high. The Baltimores, Penns, Carterets, and other +promoters anxiously sought for workers of every nationality to till +their fields, for land without labor was worth no more than land in the +moon. Hence the gates of the proprietary colonies were flung wide open. +Every inducement was offered to immigrants in the form of cheap land, +and special efforts were made to increase the population by importing +servants. In Pennsylvania, it was not uncommon to find a master with +fifty bond servants on his estate. It has been estimated that two-thirds +of all the immigrants into Pennsylvania between the opening of the +eighteenth century and the outbreak of the Revolution were in bondage. +In the other Middle colonies the number was doubtless not so large; but +it formed a considerable part of the population. + +The story of this traffic in white servants is one of the most striking +things in the history of labor. Bondmen differed from the serfs of the +feudal age in that they were not bound to the soil but to the master. +They likewise differed from the negro slaves in that their servitude had +a time limit. Still they were subject to many special disabilities. It +was, for instance, a common practice to impose on them penalties far +heavier than were imposed upon freemen for the same offense. A free +citizen of Pennsylvania who indulged in horse racing and gambling was +let off with a fine; a white servant guilty of the same unlawful conduct +was whipped at the post and fined as well. + +The ordinary life of the white servant was also severely restricted. A +bondman could not marry without his master's consent; nor engage in +trade; nor refuse work assigned to him. For an attempt to escape or +indeed for any infraction of the law, the term of service was extended. +The condition of white bondmen in Virginia, according to Lodge, "was +little better than that of slaves. Loose indentures and harsh laws put +them at the mercy of their masters." It would not be unfair to add that +such was their lot in all other colonies. Their fate depended upon the +temper of their masters. + +Cruel as was the system in many ways, it gave thousands of people in the +Old World a chance to reach the New--an opportunity to wrestle with fate +for freedom and a home of their own. When their weary years of servitude +were over, if they survived, they might obtain land of their own or +settle as free mechanics in the towns. For many a bondman the gamble +proved to be a losing venture because he found himself unable to rise +out of the state of poverty and dependence into which his servitude +carried him. For thousands, on the contrary, bondage proved to be a real +avenue to freedom and prosperity. Some of the best citizens of America +have the blood of indentured servants in their veins. + +=The Transported--Involuntary Servitude.=--In their anxiety to secure +settlers, the companies and proprietors having colonies in America +either resorted to or connived at the practice of kidnapping men, women, +and children from the streets of English cities. In 1680 it was +officially estimated that "ten thousand persons were spirited away" to +America. Many of the victims of the practice were young children, for +the traffic in them was highly profitable. Orphans and dependents were +sometimes disposed of in America by relatives unwilling to support them. +In a single year, 1627, about fifteen hundred children were shipped to +Virginia. + +In this gruesome business there lurked many tragedies, and very few +romances. Parents were separated from their children and husbands from +their wives. Hundreds of skilled artisans--carpenters, smiths, and +weavers--utterly disappeared as if swallowed up by death. A few thus +dragged off to the New World to be sold into servitude for a term of +five or seven years later became prosperous and returned home with +fortunes. In one case a young man who was forcibly carried over the sea +lived to make his way back to England and establish his claim to a +peerage. + +Akin to the kidnapped, at least in economic position, were convicts +deported to the colonies for life in lieu of fines and imprisonment. The +Americans protested vigorously but ineffectually against this practice. +Indeed, they exaggerated its evils, for many of the "criminals" were +only mild offenders against unduly harsh and cruel laws. A peasant +caught shooting a rabbit on a lord's estate or a luckless servant girl +who purloined a pocket handkerchief was branded as a criminal along with +sturdy thieves and incorrigible rascals. Other transported offenders +were "political criminals"; that is, persons who criticized or opposed +the government. This class included now Irish who revolted against +British rule in Ireland; now Cavaliers who championed the king against +the Puritan revolutionists; Puritans, in turn, dispatched after the +monarchy was restored; and Scotch and English subjects in general who +joined in political uprisings against the king. + +=The African Slaves.=--Rivaling in numbers, in the course of time, the +indentured servants and whites carried to America against their will +were the African negroes brought to America and sold into slavery. When +this form of bondage was first introduced into Virginia in 1619, it was +looked upon as a temporary necessity to be discarded with the increase +of the white population. Moreover it does not appear that those planters +who first bought negroes at the auction block intended to establish a +system of permanent bondage. Only by a slow process did chattel slavery +take firm root and become recognized as the leading source of the labor +supply. In 1650, thirty years after the introduction of slavery, there +were only three hundred Africans in Virginia. + +The great increase in later years was due in no small measure to the +inordinate zeal for profits that seized slave traders both in Old and in +New England. Finding it relatively easy to secure negroes in Africa, +they crowded the Southern ports with their vessels. The English Royal +African Company sent to America annually between 1713 and 1743 from five +to ten thousand slaves. The ship owners of New England were not far +behind their English brethren in pushing this extraordinary traffic. + +As the proportion of the negroes to the free white population steadily +rose, and as whole sections were overrun with slaves and slave traders, +the Southern colonies grew alarmed. In 1710, Virginia sought to curtail +the importation by placing a duty of $5 on each slave. This effort was +futile, for the royal governor promptly vetoed it. From time to time +similar bills were passed, only to meet with royal disapproval. South +Carolina, in 1760, absolutely prohibited importation; but the measure +was killed by the British crown. As late as 1772, Virginia, not daunted +by a century of rebuffs, sent to George III a petition in this vein: +"The importation of slaves into the colonies from the coast of Africa +hath long been considered as a trade of great inhumanity and under its +present encouragement, we have too much reason to fear, will endanger +the very existence of Your Majesty's American dominions.... Deeply +impressed with these sentiments, we most humbly beseech Your Majesty to +remove all those restraints on Your Majesty's governors of this colony +which inhibit their assenting to such laws as might check so very +pernicious a commerce." + +All such protests were without avail. The negro population grew by leaps +and bounds, until on the eve of the Revolution it amounted to more than +half a million. In five states--Maryland, Virginia, the two Carolinas, +and Georgia--the slaves nearly equalled or actually exceeded the whites +in number. In South Carolina they formed almost two-thirds of the +population. Even in the Middle colonies of Delaware and Pennsylvania +about one-fifth of the inhabitants were from Africa. To the North, the +proportion of slaves steadily diminished although chattel servitude was +on the same legal footing as in the South. In New York approximately one +in six and in New England one in fifty were negroes, including a few +freedmen. + +The climate, the soil, the commerce, and the industry of the North were +all unfavorable to the growth of a servile population. Still, slavery, +though sectional, was a part of the national system of economy. Northern +ships carried slaves to the Southern colonies and the produce of the +plantations to Europe. "If the Northern states will consult their +interest, they will not oppose the increase in slaves which will +increase the commodities of which they will become the carriers," said +John Rutledge, of South Carolina, in the convention which framed the +Constitution of the United States. "What enriches a part enriches the +whole and the states are the best judges of their particular interest," +responded Oliver Ellsworth, the distinguished spokesman of Connecticut. + +=References= + +E. Charming, _History of the United States_, Vols. I and II. + +J.A. Doyle, _The English Colonies in America_ (5 vols.). + +J. Fiske, _Old Virginia and Her Neighbors_ (2 vols.). + +A.B. Faust, _The German Element in the United States_ (2 vols.). + +H.J. Ford, _The Scotch-Irish in America_. + +L. Tyler, _England in America_ (American Nation Series). + +R. Usher, _The Pilgrims and Their History_. + + +=Questions= + +1. America has been called a nation of immigrants. Explain why. + +2. Why were individuals unable to go alone to America in the beginning? +What agencies made colonization possible? Discuss each of them. + +3. Make a table of the colonies, showing the methods employed in their +settlement. + +4. Why were capital and leadership so very important in early +colonization? + +5. What is meant by the "melting pot"? What nationalities were +represented among the early colonists? + +6. Compare the way immigrants come to-day with the way they came in +colonial times. + +7. Contrast indentured servitude with slavery and serfdom. + +8. Account for the anxiety of companies and proprietors to secure +colonists. + +9. What forces favored the heavy importation of slaves? + +10. In what way did the North derive advantages from slavery? + + +=Research Topics= + +=The Chartered Company.=--Compare the first and third charters of +Virginia in Macdonald, _Documentary Source Book of American History_, +1606-1898, pp. 1-14. Analyze the first and second Massachusetts charters +in Macdonald, pp. 22-84. Special reference: W.A.S. Hewins, _English +Trading Companies_. + +=Congregations and Compacts for Self-government.=--A study of the +Mayflower Compact, the Fundamental Orders of Connecticut and the +Fundamental Articles of New Haven in Macdonald, pp. 19, 36, 39. +Reference: Charles Borgeaud, _Rise of Modern Democracy_, and C.S. +Lobingier, _The People's Law_, Chaps. I-VII. + +=The Proprietary System.=--Analysis of Penn's charter of 1681, in +Macdonald, p. 80. Reference: Lodge, _Short History of the English +Colonies in America_, p. 211. + +=Studies of Individual Colonies.=--Review of outstanding events in +history of each colony, using Elson, _History of the United States_, pp. +55-159, as the basis. + +=Biographical Studies.=--John Smith, John Winthrop, William Penn, Lord +Baltimore, William Bradford, Roger Williams, Anne Hutchinson, Thomas +Hooker, and Peter Stuyvesant, using any good encyclopedia. + +=Indentured Servitude.=--In Virginia, Lodge, _Short History_, pp. 69-72; +in Pennsylvania, pp. 242-244. Contemporary account in Callender, +_Economic History of the United States_, pp. 44-51. Special reference: +Karl Geiser, _Redemptioners and Indentured Servants_ (Yale Review, X, +No. 2 Supplement). + +=Slavery.=--In Virginia, Lodge, _Short History_, pp. 67-69; in the +Northern colonies, pp. 241, 275, 322, 408, 442. + +=The People of the Colonies.=--Virginia, Lodge, _Short History_, pp. +67-73; New England, pp. 406-409, 441-450; Pennsylvania, pp. 227-229, +240-250; New York, pp. 312-313, 322-335. + + + + +CHAPTER II + +COLONIAL AGRICULTURE, INDUSTRY, AND COMMERCE + +THE LAND AND THE WESTWARD MOVEMENT + + +=The Significance of Land Tenure.=--The way in which land may be +acquired, held, divided among heirs, and bought and sold exercises a +deep influence on the life and culture of a people. The feudal and +aristocratic societies of Europe were founded on a system of landlordism +which was characterized by two distinct features. In the first place, +the land was nearly all held in great estates, each owned by a single +proprietor. In the second place, every estate was kept intact under the +law of primogeniture, which at the death of a lord transferred all his +landed property to his eldest son. This prevented the subdivision of +estates and the growth of a large body of small farmers or freeholders +owning their own land. It made a form of tenantry or servitude +inevitable for the mass of those who labored on the land. It also +enabled the landlords to maintain themselves in power as a governing +class and kept the tenants and laborers subject to their economic and +political control. If land tenure was so significant in Europe, it was +equally important in the development of America, where practically all +the first immigrants were forced by circumstances to derive their +livelihood from the soil. + +=Experiments in Common Tillage.=--In the New World, with its broad +extent of land awaiting the white man's plow, it was impossible to +introduce in its entirety and over the whole area the system of lords +and tenants that existed across the sea. So it happened that almost +every kind of experiment in land tenure, from communism to feudalism, +was tried. In the early days of the Jamestown colony, the land, though +owned by the London Company, was tilled in common by the settlers. No +man had a separate plot of his own. The motto of the community was: +"Labor and share alike." All were supposed to work in the fields and +receive an equal share of the produce. At Plymouth, the Pilgrims +attempted a similar experiment, laying out the fields in common and +distributing the joint produce of their labor with rough equality among +the workers. + +In both colonies the communistic experiments were failures. Angry at the +lazy men in Jamestown who idled their time away and yet expected regular +meals, Captain John Smith issued a manifesto: "Everyone that gathereth +not every day as much as I do, the next day shall be set beyond the +river and forever banished from the fort and live there or starve." Even +this terrible threat did not bring a change in production. Not until +each man was given a plot of his own to till, not until each gathered +the fruits of his own labor, did the colony prosper. In Plymouth, where +the communal experiment lasted for five years, the results were similar +to those in Virginia, and the system was given up for one of separate +fields in which every person could "set corn for his own particular." +Some other New England towns, refusing to profit by the experience of +their Plymouth neighbor, also made excursions into common ownership and +labor, only to abandon the idea and go in for individual ownership of +the land. "By degrees it was seen that even the Lord's people could not +carry the complicated communist legislation into perfect and wholesome +practice." + +=Feudal Elements in the Colonies--Quit Rents, Manors, and +Plantations.=--At the other end of the scale were the feudal elements of +land tenure found in the proprietary colonies, in the seaboard regions +of the South, and to some extent in New York. The proprietor was in fact +a powerful feudal lord, owning land granted to him by royal charter. He +could retain any part of it for his personal use or dispose of it all in +large or small lots. While he generally kept for himself an estate of +baronial proportions, it was impossible for him to manage directly any +considerable part of the land in his dominion. Consequently he either +sold it in parcels for lump sums or granted it to individuals on +condition that they make to him an annual payment in money, known as +"quit rent." In Maryland, the proprietor sometimes collected as high as +$9000 (equal to about $500,000 to-day) in a single year from this +source. In Pennsylvania, the quit rents brought a handsome annual +tribute into the exchequer of the Penn family. In the royal provinces, +the king of England claimed all revenues collected in this form from the +land, a sum amounting to $19,000 at the time of the Revolution. The quit +rent,--"really a feudal payment from freeholders,"--was thus a material +source of income for the crown as well as for the proprietors. Wherever +it was laid, however, it proved to be a burden, a source of constant +irritation; and it became a formidable item in the long list of +grievances which led to the American Revolution. + +Something still more like the feudal system of the Old World appeared in +the numerous manors or the huge landed estates granted by the crown, the +companies, or the proprietors. In the colony of Maryland alone there +were sixty manors of three thousand acres each, owned by wealthy men and +tilled by tenants holding small plots under certain restrictions of +tenure. In New York also there were many manors of wide extent, most of +which originated in the days of the Dutch West India Company, when +extensive concessions were made to patroons to induce them to bring over +settlers. The Van Rensselaer, the Van Cortlandt, and the Livingston +manors were so large and populous that each was entitled to send a +representative to the provincial legislature. The tenants on the New +York manors were in somewhat the same position as serfs on old European +estates. They were bound to pay the owner a rent in money and kind; they +ground their grain at his mill; and they were subject to his judicial +power because he held court and meted out justice, in some instances +extending to capital punishment. + +The manors of New York or Maryland were, however, of slight consequence +as compared with the vast plantations of the Southern seaboard--huge +estates, far wider in expanse than many a European barony and tilled by +slaves more servile than any feudal tenants. It must not be forgotten +that this system of land tenure became the dominant feature of a large +section and gave a decided bent to the economic and political life of +America. + +[Illustration: SOUTHERN PLANTATION MANSION] + +=The Small Freehold.=--In the upland regions of the South, however, and +throughout most of the North, the drift was against all forms of +servitude and tenantry and in the direction of the freehold; that is, +the small farm owned outright and tilled by the possessor and his +family. This was favored by natural circumstances and the spirit of the +immigrants. For one thing, the abundance of land and the scarcity of +labor made it impossible for the companies, the proprietors, or the +crown to develop over the whole continent a network of vast estates. In +many sections, particularly in New England, the climate, the stony soil, +the hills, and the narrow valleys conspired to keep the farms within a +moderate compass. For another thing, the English, Scotch-Irish, and +German peasants, even if they had been tenants in the Old World, did not +propose to accept permanent dependency of any kind in the New. If they +could not get freeholds, they would not settle at all; thus they forced +proprietors and companies to bid for their enterprise by selling land in +small lots. So it happened that the freehold of modest proportions +became the cherished unit of American farmers. The people who tilled the +farms were drawn from every quarter of western Europe; but the freehold +system gave a uniform cast to their economic and social life in America. + +[Illustration: _From an old print_ + +A NEW ENGLAND FARMHOUSE] + +=Social Effects of Land Tenure.=--Land tenure and the process of western +settlement thus developed two distinct types of people engaged in the +same pursuit--agriculture. They had a common tie in that they both +cultivated the soil and possessed the local interest and independence +which arise from that occupation. Their methods and their culture, +however, differed widely. + +The Southern planter, on his broad acres tilled by slaves, resembled the +English landlord on his estates more than he did the colonial farmer who +labored with his own hands in the fields and forests. He sold his rice +and tobacco in large amounts directly to English factors, who took his +entire crop in exchange for goods and cash. His fine clothes, +silverware, china, and cutlery he bought in English markets. Loving the +ripe old culture of the mother country, he often sent his sons to Oxford +or Cambridge for their education. In short, he depended very largely for +his prosperity and his enjoyment of life upon close relations with the +Old World. He did not even need market towns in which to buy native +goods, for they were made on his own plantation by his own artisans who +were usually gifted slaves. + +The economic condition of the small farmer was totally different. His +crops were not big enough to warrant direct connection with English +factors or the personal maintenance of a corps of artisans. He needed +local markets, and they sprang up to meet the need. Smiths, hatters, +weavers, wagon-makers, and potters at neighboring towns supplied him +with the rough products of their native skill. The finer goods, bought +by the rich planter in England, the small farmer ordinarily could not +buy. His wants were restricted to staples like tea and sugar, and +between him and the European market stood the merchant. His community +was therefore more self-sufficient than the seaboard line of great +plantations. It was more isolated, more provincial, more independent, +more American. The planter faced the Old East. The farmer faced the New +West. + +=The Westward Movement.=--Yeoman and planter nevertheless were alike in +one respect. Their land hunger was never appeased. Each had the eye of +an expert for new and fertile soil; and so, north and south, as soon as +a foothold was secured on the Atlantic coast, the current of migration +set in westward, creeping through forests, across rivers, and over +mountains. Many of the later immigrants, in their search for cheap +lands, were compelled to go to the border; but in a large part the path +breakers to the West were native Americans of the second and third +generations. Explorers, fired by curiosity and the lure of the +mysterious unknown, and hunters, fur traders, and squatters, following +their own sweet wills, blazed the trail, opening paths and sending back +stories of the new regions they traversed. Then came the regular +settlers with lawful titles to the lands they had purchased, sometimes +singly and sometimes in companies. + +In Massachusetts, the westward movement is recorded in the founding of +Springfield in 1636 and Great Barrington in 1725. By the opening of the +eighteenth century the pioneers of Connecticut had pushed north and west +until their outpost towns adjoined the Hudson Valley settlements. In New +York, the inland movement was directed by the Hudson River to Albany, +and from that old Dutch center it radiated in every direction, +particularly westward through the Mohawk Valley. New Jersey was early +filled to its borders, the beginnings of the present city of New +Brunswick being made in 1681 and those of Trenton in 1685. In +Pennsylvania, as in New York, the waterways determined the main lines of +advance. Pioneers, pushing up through the valley of the Schuylkill, +spread over the fertile lands of Berks and Lancaster counties, laying +out Reading in 1748. Another current of migration was directed by the +Susquehanna, and, in 1726, the first farmhouse was built on the bank +where Harrisburg was later founded. Along the southern tier of counties +a thin line of settlements stretched westward to Pittsburgh, reaching +the upper waters of the Ohio while the colony was still under the Penn +family. + +In the South the westward march was equally swift. The seaboard was +quickly occupied by large planters and their slaves engaged in the +cultivation of tobacco and rice. The Piedmont Plateau, lying back from +the coast all the way from Maryland to Georgia, was fed by two streams +of migration, one westward from the sea and the other southward from the +other colonies--Germans from Pennsylvania and Scotch-Irish furnishing +the main supply. "By 1770, tide-water Virginia was full to overflowing +and the 'back country' of the Blue Ridge and the Shenandoah was fully +occupied. Even the mountain valleys ... were claimed by sturdy pioneers. +Before the Declaration of Independence, the oncoming tide of +home-seekers had reached the crest of the Alleghanies." + +[Illustration: DISTRIBUTION OF POPULATION, 1790] + +Beyond the mountains pioneers had already ventured, harbingers of an +invasion that was about to break in upon Kentucky and Tennessee. As +early as 1769 that mighty Nimrod, Daniel Boone, curious to hunt +buffaloes, of which he had heard weird reports, passed through the +Cumberland Gap and brought back news of a wonderful country awaiting the +plow. A hint was sufficient. Singly, in pairs, and in groups, settlers +followed the trail he had blazed. A great land corporation, the +Transylvania Company, emulating the merchant adventurers of earlier +times, secured a huge grant of territory and sought profits in quit +rents from lands sold to farmers. By the outbreak of the Revolution +there were several hundred people in the Kentucky region. Like the older +colonists, they did not relish quit rents, and their opposition wrecked +the Transylvania Company. They even carried their protests into the +Continental Congress in 1776, for by that time they were our "embryo +fourteenth colony." + + +INDUSTRIAL AND COMMERCIAL DEVELOPMENT + +Though the labor of the colonists was mainly spent in farming, there was +a steady growth in industrial and commercial pursuits. Most of the +staple industries of to-day, not omitting iron and textiles, have their +beginnings in colonial times. Manufacturing and trade soon gave rise to +towns which enjoyed an importance all out of proportion to their +numbers. The great centers of commerce and finance on the seaboard +originated in the days when the king of England was "lord of these +dominions." + +[Illustration: DOMESTIC INDUSTRY: DIPPING TALLOW CANDLES] + +=Textile Manufacture as a Domestic Industry.=--Colonial women, in +addition to sharing every hardship of pioneering, often the heavy labor +of the open field, developed in the course of time a national industry +which was almost exclusively their own. Wool and flax were raised in +abundance in the North and South. "Every farm house," says Coman, the +economic historian, "was a workshop where the women spun and wove the +serges, kerseys, and linsey-woolseys which served for the common wear." +By the close of the seventeenth century, New England manufactured cloth +in sufficient quantities to export it to the Southern colonies and to +the West Indies. As the industry developed, mills were erected for the +more difficult process of dyeing, weaving, and fulling, but carding and +spinning continued to be done in the home. The Dutch of New Netherland, +the Swedes of Delaware, and the Scotch-Irish of the interior "were not +one whit behind their Yankee neighbors." + +The importance of this enterprise to British economic life can hardly be +overestimated. For many a century the English had employed their fine +woolen cloth as the chief staple in a lucrative foreign trade, and the +government had come to look upon it as an object of special interest and +protection. When the colonies were established, both merchants and +statesmen naturally expected to maintain a monopoly of increasing value; +but before long the Americans, instead of buying cloth, especially of +the coarser varieties, were making it to sell. In the place of +customers, here were rivals. In the place of helpless reliance upon +English markets, here was the germ of economic independence. + +If British merchants had not discovered it in the ordinary course of +trade, observant officers in the provinces would have conveyed the news +to them. Even in the early years of the eighteenth century the royal +governor of New York wrote of the industrious Americans to his home +government: "The consequence will be that if they can clothe themselves +once, not only comfortably, but handsomely too, without the help of +England, they who already are not very fond of submitting to government +will soon think of putting in execution designs they have long harboured +in their breasts. This will not seem strange when you consider what sort +of people this country is inhabited by." + +=The Iron Industry.=--Almost equally widespread was the art of iron +working--one of the earliest and most picturesque of colonial +industries. Lynn, Massachusetts, had a forge and skilled artisans within +fifteen years after the founding of Boston. The smelting of iron began +at New London and New Haven about 1658; in Litchfield county, +Connecticut, a few years later; at Great Barrington, Massachusetts, in +1731; and near by at Lenox some thirty years after that. New Jersey had +iron works at Shrewsbury within ten years after the founding of the +colony in 1665. Iron forges appeared in the valleys of the Delaware and +the Susquehanna early in the following century, and iron masters then +laid the foundations of fortunes in a region destined to become one of +the great iron centers of the world. Virginia began iron working in the +year that saw the introduction of slavery. Although the industry soon +lapsed, it was renewed and flourished in the eighteenth century. +Governor Spotswood was called the "Tubal Cain" of the Old Dominion +because he placed the industry on a firm foundation. Indeed it seems +that every colony, except Georgia, had its iron foundry. Nails, wire, +metallic ware, chains, anchors, bar and pig iron were made in large +quantities; and Great Britain, by an act in 1750, encouraged the +colonists to export rough iron to the British Islands. + +=Shipbuilding.=--Of all the specialized industries in the colonies, +shipbuilding was the most important. The abundance of fir for masts, oak +for timbers and boards, pitch for tar and turpentine, and hemp for rope +made the way of the shipbuilder easy. Early in the seventeenth century a +ship was built at New Amsterdam, and by the middle of that century +shipyards were scattered along the New England coast at Newburyport, +Salem, New Bedford, Newport, Providence, New London, and New Haven. +Yards at Albany and Poughkeepsie in New York built ships for the trade +of that colony with England and the Indies. Wilmington and Philadelphia +soon entered the race and outdistanced New York, though unable to equal +the pace set by New England. While Maryland, Virginia, and South +Carolina also built ships, Southern interest was mainly confined to the +lucrative business of producing ship materials: fir, cedar, hemp, and +tar. + +=Fishing.=--The greatest single economic resource of New England outside +of agriculture was the fisheries. This industry, started by hardy +sailors from Europe, long before the landing of the Pilgrims, flourished +under the indomitable seamanship of the Puritans, who labored with the +net and the harpoon in almost every quarter of the Atlantic. "Look," +exclaimed Edmund Burke, in the House of Commons, "at the manner in +which the people of New England have of late carried on the whale +fishery. Whilst we follow them among the tumbling mountains of ice and +behold them penetrating into the deepest frozen recesses of Hudson's Bay +and Davis's Straits, while we are looking for them beneath the arctic +circle, we hear that they have pierced into the opposite region of polar +cold, that they are at the antipodes and engaged under the frozen +serpent of the south.... Nor is the equinoctial heat more discouraging +to them than the accumulated winter of both poles. We know that, whilst +some of them draw the line and strike the harpoon on the coast of +Africa, others run the longitude and pursue their gigantic game along +the coast of Brazil. No sea but what is vexed by their fisheries. No +climate that is not witness to their toils. Neither the perseverance of +Holland nor the activity of France nor the dexterous and firm sagacity +of English enterprise ever carried this most perilous mode of hard +industry to the extent to which it has been pushed by this recent +people." + +The influence of the business was widespread. A large and lucrative +European trade was built upon it. The better quality of the fish caught +for food was sold in the markets of Spain, Portugal, and Italy, or +exchanged for salt, lemons, and raisins for the American market. The +lower grades of fish were carried to the West Indies for slave +consumption, and in part traded for sugar and molasses, which furnished +the raw materials for the thriving rum industry of New England. These +activities, in turn, stimulated shipbuilding, steadily enlarging the +demand for fishing and merchant craft of every kind and thus keeping the +shipwrights, calkers, rope makers, and other artisans of the seaport +towns rushed with work. They also increased trade with the mother +country for, out of the cash collected in the fish markets of Europe and +the West Indies, the colonists paid for English manufactures. So an +ever-widening circle of American enterprise centered around this single +industry, the nursery of seamanship and the maritime spirit. + +=Oceanic Commerce and American Merchants.=--All through the eighteenth +century, the commerce of the American colonies spread in every direction +until it rivaled in the number of people employed, the capital engaged, +and the profits gleaned, the commerce of European nations. A modern +historian has said: "The enterprising merchants of New England developed +a network of trade routes that covered well-nigh half the world." This +commerce, destined to be of such significance in the conflict with the +mother country, presented, broadly speaking, two aspects. + +On the one side, it involved the export of raw materials and +agricultural produce. The Southern colonies produced for shipping, +tobacco, rice, tar, pitch, and pine; the Middle colonies, grain, flour, +furs, lumber, and salt pork; New England, fish, flour, rum, furs, shoes, +and small articles of manufacture. The variety of products was in fact +astounding. A sarcastic writer, while sneering at the idea of an +American union, once remarked of colonial trade: "What sort of dish will +you make? New England will throw in fish and onions. The middle states, +flax-seed and flour. Maryland and Virginia will add tobacco. North +Carolina, pitch, tar, and turpentine. South Carolina, rice and indigo, +and Georgia will sprinkle the whole composition with sawdust. Such an +absurd jumble will you make if you attempt to form a union among such +discordant materials as the thirteen British provinces." + +On the other side, American commerce involved the import trade, +consisting principally of English and continental manufactures, tea, and +"India goods." Sugar and molasses, brought from the West Indies, +supplied the flourishing distilleries of Massachusetts, Rhode Island, +and Connecticut. The carriage of slaves from Africa to the Southern +colonies engaged hundreds of New England's sailors and thousands of +pounds of her capital. + +The disposition of imported goods in the colonies, though in part +controlled by English factors located in America, employed also a large +and important body of American merchants like the Willings and Morrises +of Philadelphia; the Amorys, Hancocks, and Faneuils of Boston; and the +Livingstons and Lows of New York. In their zeal and enterprise, they +were worthy rivals of their English competitors, so celebrated for +world-wide commercial operations. Though fully aware of the advantages +they enjoyed in British markets and under the protection of the British +navy, the American merchants were high-spirited and mettlesome, ready to +contend with royal officers in order to shield American interests +against outside interference. + +[Illustration: THE DUTCH WEST INDIA WAREHOUSE IN NEW AMSTERDAM +(NEW YORK CITY)] + +Measured against the immense business of modern times, colonial commerce +seems perhaps trivial. That, however, is not the test of its +significance. It must be considered in relation to the growth of English +colonial trade in its entirety--a relation which can be shown by a few +startling figures. The whole export trade of England, including that to +the colonies, was, in 1704, $6,509,000. On the eve of the American +Revolution, namely, in 1772, English exports to the American colonies +alone amounted to $6,024,000; in other words, almost as much as the +whole foreign business of England two generations before. At the first +date, colonial trade was but one-twelfth of the English export business; +at the second date, it was considerably more than one-third. In 1704, +Pennsylvania bought in English markets goods to the value of $11,459; in +1772 the purchases of the same colony amounted to $507,909. In short, +Pennsylvania imports increased fifty times within sixty-eight years, +amounting in 1772 to almost the entire export trade of England to the +colonies at the opening of the century. The American colonies were +indeed a great source of wealth to English merchants. + +=Intercolonial Commerce.=--Although the bad roads of colonial times made +overland transportation difficult and costly, the many rivers and +harbors along the coast favored a lively water-borne trade among the +colonies. The Connecticut, Hudson, Delaware, and Susquehanna rivers in +the North and the many smaller rivers in the South made it possible for +goods to be brought from, and carried to, the interior regions in little +sailing vessels with comparative ease. Sloops laden with manufactures, +domestic and foreign, collected at some city like Providence, New York, +or Philadelphia, skirted the coasts, visited small ports, and sailed up +the navigable rivers to trade with local merchants who had for exchange +the raw materials which they had gathered in from neighboring farms. +Larger ships carried the grain, live stock, cloth, and hardware of New +England to the Southern colonies, where they were traded for tobacco, +leather, tar, and ship timber. From the harbors along the Connecticut +shores there were frequent sailings down through Long Island Sound to +Maryland, Virginia, and the distant Carolinas. + +=Growth of Towns.=--In connection with this thriving trade and industry +there grew up along the coast a number of prosperous commercial centers +which were soon reckoned among the first commercial towns of the whole +British empire, comparing favorably in numbers and wealth with such +ports as Liverpool and Bristol. The statistical records of that time are +mainly guesses; but we know that Philadelphia stood first in size among +these towns. Serving as the port of entry for Pennsylvania, Delaware, +and western Jersey, it had drawn within its borders, just before the +Revolution, about 25,000 inhabitants. Boston was second in rank, with +somewhat more than 20,000 people. New York, the "commercial capital of +Connecticut and old East Jersey," was slightly smaller than Boston, but +growing at a steady rate. The fourth town in size was Charleston, South +Carolina, with about 10,000 inhabitants. Newport in Rhode Island, a +center of rum manufacture and shipping, stood fifth, with a population +of about 7000. Baltimore and Norfolk were counted as "considerable +towns." In the interior, Hartford in Connecticut, Lancaster and York in +Pennsylvania, and Albany in New York, with growing populations and +increasing trade, gave prophecy of an urban America away from the +seaboard. The other towns were straggling villages. Williamsburg, +Virginia, for example, had about two hundred houses, in which dwelt a +dozen families of the gentry and a few score of tradesmen. Inland county +seats often consisted of nothing more than a log courthouse, a prison, +and one wretched inn to house judges, lawyers, and litigants during the +sessions of the court. + +The leading towns exercised an influence on colonial opinion all out of +proportion to their population. They were the centers of wealth, for one +thing; of the press and political activity, for another. Merchants and +artisans could readily take concerted action on public questions arising +from their commercial operations. The towns were also centers for news, +gossip, religious controversy, and political discussion. In the market +places the farmers from the countryside learned of British policies and +laws, and so, mingling with the townsmen, were drawn into the main +currents of opinion which set in toward colonial nationalism and +independence. + + +=References= + +J. Bishop, _History of American Manufactures_ (2 vols.). + +E.L. Bogart, _Economic History of the United States_. + +P.A. Bruce, _Economic History of Virginia_ (2 vols.). + +E. Semple, _American History and Its Geographical Conditions_. + +W. Weeden, _Economic and Social History of New England_. (2 vols.). + + +=Questions= + +1. Is land in your community parceled out into small farms? Contrast the +system in your community with the feudal system of land tenure. + +2. Are any things owned and used in common in your community? Why did +common tillage fail in colonial times? + +3. Describe the elements akin to feudalism which were introduced in the +colonies. + +4. Explain the success of freehold tillage. + +5. Compare the life of the planter with that of the farmer. + +6. How far had the western frontier advanced by 1776? + +7. What colonial industry was mainly developed by women? Why was it very +important both to the Americans and to the English? + +8. What were the centers for iron working? Ship building? + +9. Explain how the fisheries affected many branches of trade and +industry. + +10. Show how American trade formed a vital part of English business. + +11. How was interstate commerce mainly carried on? + +12. What were the leading towns? Did they compare in importance with +British towns of the same period? + + +=Research Topics= + +=Land Tenure.=--Coman, _Industrial History_ (rev. ed.), pp. 32-38. +Special reference: Bruce, _Economic History of Virginia_, Vol. I, Chap. +VIII. + +=Tobacco Planting in Virginia.=--Callender, _Economic History of the +United States_, pp. 22-28. + +=Colonial Agriculture.=--Coman, pp. 48-63. Callender, pp. 69-74. +Reference: J.R.H. Moore, _Industrial History of the American People_, +pp. 131-162. + +=Colonial Manufactures.=--Coman, pp. 63-73. Callender, pp. 29-44. +Special reference: Weeden, _Economic and Social History of New England_. + +=Colonial Commerce.=--Coman, pp. 73-85. Callender, pp. 51-63, 78-84. +Moore, pp. 163-208. Lodge, _Short History of the English Colonies_, pp. +409-412, 229-231, 312-314. + + + + +Chapter III + +SOCIAL AND POLITICAL PROGRESS + + +Colonial life, crowded as it was with hard and unremitting toil, left +scant leisure for the cultivation of the arts and sciences. There was +little money in private purses or public treasuries to be dedicated to +schools, libraries, and museums. Few there were with time to read long +and widely, and fewer still who could devote their lives to things that +delight the eye and the mind. And yet, poor and meager as the +intellectual life of the colonists may seem by way of comparison, heroic +efforts were made in every community to lift the people above the plane +of mere existence. After the first clearings were opened in the forests +those efforts were redoubled, and with lengthening years told upon the +thought and spirit of the land. The appearance, during the struggle with +England, of an extraordinary group of leaders familiar with history, +political philosophy, and the arts of war, government, and diplomacy +itself bore eloquent testimony to the high quality of the American +intellect. No one, not even the most critical, can run through the +writings of distinguished Americans scattered from Massachusetts to +Georgia--the Adamses, Ellsworth, the Morrises, the Livingstons, +Hamilton, Franklin, Washington, Madison, Marshall, Henry, the Randolphs, +and the Pinckneys--without coming to the conclusion that there was +something in American colonial life which fostered minds of depth and +power. Women surmounted even greater difficulties than the men in the +process of self-education, and their keen interest in public issues is +evident in many a record like the _Letters_ of Mrs. John Adams to her +husband during the Revolution; the writings of Mrs. Mercy Otis Warren, +the sister of James Otis, who measured her pen with the British +propagandists; and the patriot newspapers founded and managed by women. + + +THE LEADERSHIP OF THE CHURCHES + +In the intellectual life of America, the churches assumed a role of high +importance. There were abundant reasons for this. In many of the +colonies--Maryland, Pennsylvania, and New England--the religious impulse +had been one of the impelling motives in stimulating immigration. In all +the colonies, the clergy, at least in the beginning, formed the only +class with any leisure to devote to matters of the spirit. They preached +on Sundays and taught school on week days. They led in the discussion of +local problems and in the formation of political opinion, so much of +which was concerned with the relation between church and state. They +wrote books and pamphlets. They filled most of the chairs in the +colleges; under clerical guidance, intellectual and spiritual, the +Americans received their formal education. In several of the provinces +the Anglican Church was established by law. In New England the Puritans +were supreme, notwithstanding the efforts of the crown to overbear their +authority. In the Middle colonies, particularly, the multiplication of +sects made the dominance of any single denomination impossible; and in +all of them there was a growing diversity of faith, which promised in +time a separation of church and state and freedom of opinion. + +=The Church of England.=--Virginia was the stronghold of the English +system of church and state. The Anglican faith and worship were +prescribed by law, sustained by taxes imposed on all, and favored by the +governor, the provincial councilors, and the richest planters. "The +Established Church," says Lodge, "was one of the appendages of the +Virginia aristocracy. They controlled the vestries and the ministers, +and the parish church stood not infrequently on the estate of the +planter who built and managed it." As in England, Catholics and +Protestant Dissenters were at first laid under heavy disabilities. Only +slowly and on sufferance were they admitted to the province; but when +once they were even covertly tolerated, they pressed steadily in, until, +by the Revolution, they outnumbered the adherents of the established +order. + +The Church was also sanctioned by law and supported by taxes in the +Carolinas after 1704, and in Georgia after that colony passed directly +under the crown in 1754--this in spite of the fact that the majority of +the inhabitants were Dissenters. Against the protests of the Catholics +it was likewise established in Maryland. In New York, too, +notwithstanding the resistance of the Dutch, the Established Church was +fostered by the provincial officials, and the Anglicans, embracing about +one-fifteenth of the population, exerted an influence all out of +proportion to their numbers. + +Many factors helped to enhance the power of the English Church in the +colonies. It was supported by the British government and the official +class sent out to the provinces. Its bishops and archbishops in England +were appointed by the king, and its faith and service were set forth by +acts of Parliament. Having its seat of power in the English monarchy, it +could hold its clergy and missionaries loyal to the crown and so +counteract to some extent the independent spirit that was growing up in +America. The Church, always a strong bulwark of the state, therefore had +a political role to play here as in England. Able bishops and far-seeing +leaders firmly grasped this fact about the middle of the eighteenth +century and redoubled their efforts to augment the influence of the +Church in provincial affairs. Unhappily for their plans they failed to +calculate in advance the effect of their methods upon dissenting +Protestants, who still cherished memories of bitter religious conflicts +in the mother country. + +=Puritanism in New England.=--If the established faith made for imperial +unity, the same could not be said of Puritanism. The Plymouth Pilgrims +had cast off all allegiance to the Anglican Church and established a +separate and independent congregation before they came to America. The +Puritans, essaying at first the task of reformers within the Church, +soon after their arrival in Massachusetts, likewise flung off their yoke +of union with the Anglicans. In each town a separate congregation was +organized, the male members choosing the pastor, the teachers, and the +other officers. They also composed the voters in the town meeting, where +secular matters were determined. The union of church and government was +thus complete, and uniformity of faith and life prescribed by law and +enforced by civil authorities; but this worked for local autonomy +instead of imperial unity. + +The clergy became a powerful class, dominant through their learning and +their fearful denunciations of the faithless. They wrote the books for +the people to read--the famous Cotton Mather having three hundred and +eighty-three books and pamphlets to his credit. In cooperation with the +civil officers they enforced a strict observance of the Puritan +Sabbath--a day of rest that began at six o'clock on Saturday evening and +lasted until sunset on Sunday. All work, all trading, all amusement, and +all worldly conversation were absolutely prohibited during those hours. +A thoughtless maid servant who for some earthly reason smiled in church +was in danger of being banished as a vagabond. Robert Pike, a devout +Puritan, thinking the sun had gone to rest, ventured forth on horseback +one Sunday evening and was luckless enough to have a ray of light strike +him through a rift in the clouds. The next day he was brought into court +and fined for "his ungodly conduct." With persons accused of witchcraft +the Puritans were still more ruthless. When a mania of persecution swept +over Massachusetts in 1692, eighteen people were hanged, one was pressed +to death, many suffered imprisonment, and two died in jail. + +Just about this time, however, there came a break in the uniformity of +Puritan rule. The crown and church in England had long looked upon it +with disfavor, and in 1684 King Charles II annulled the old charter of +the Massachusetts Bay Company. A new document issued seven years later +wrested from the Puritans of the colony the right to elect their own +governor and reserved the power of appointment to the king. It also +abolished the rule limiting the suffrage to church members, substituting +for it a simple property qualification. Thus a royal governor and an +official family, certain to be Episcopalian in faith and monarchist in +sympathies, were forced upon Massachusetts; and members of all religious +denominations, if they had the required amount of property, were +permitted to take part in elections. By this act in the name of the +crown, the Puritan monopoly was broken down in Massachusetts, and that +province was brought into line with Connecticut, Rhode Island, and New +Hampshire, where property, not religious faith, was the test for the +suffrage. + +=Growth of Religious Toleration.=--Though neither the Anglicans of +Virginia nor the Puritans of Massachusetts believed in toleration for +other denominations, that principle was strictly applied in Rhode +Island. There, under the leadership of Roger Williams, liberty in +matters of conscience was established in the beginning. Maryland, by +granting in 1649 freedom to those who professed to believe in Jesus +Christ, opened its gates to all Christians; and Pennsylvania, true to +the tenets of the Friends, gave freedom of conscience to those "who +confess and acknowledge the one Almighty and Eternal God to be the +creator, upholder, and ruler of the World." By one circumstance or +another, the Middle colonies were thus early characterized by diversity +rather than uniformity of opinion. Dutch Protestants, Huguenots, +Quakers, Baptists, Presbyterians, New Lights, Moravians, Lutherans, +Catholics, and other denominations became too strongly intrenched and +too widely scattered to permit any one of them to rule, if it had +desired to do so. There were communities and indeed whole sections where +one or another church prevailed, but in no colony was a legislature +steadily controlled by a single group. Toleration encouraged diversity, +and diversity, in turn, worked for greater toleration. + +The government and faith of the dissenting denominations conspired with +economic and political tendencies to draw America away from the English +state. Presbyterians, Quakers, Baptists, and Puritans had no hierarchy +of bishops and archbishops to bind them to the seat of power in London. +Neither did they look to that metropolis for guidance in interpreting +articles of faith. Local self-government in matters ecclesiastical +helped to train them for local self-government in matters political. The +spirit of independence which led Dissenters to revolt in the Old World, +nourished as it was amid favorable circumstances in the New World, made +them all the more zealous in the defense of every right against +authority imposed from without. + + +SCHOOLS AND COLLEGES + +=Religion and Local Schools.=--One of the first cares of each Protestant +denomination was the education of the children in the faith. In this +work the Bible became the center of interest. The English version was +indeed the one book of the people. Farmers, shopkeepers, and artisans, +whose life had once been bounded by the daily routine of labor, found in +the Scriptures not only an inspiration to religious conduct, but also a +book of romance, travel, and history. "Legend and annal," says John +Richard Green, "war-song and psalm, state-roll and biography, the mighty +voices of prophets, the parables of Evangelists, stories of mission +journeys, of perils by sea and among the heathen, philosophic arguments, +apocalyptic visions, all were flung broadcast over minds unoccupied for +the most part by any rival learning.... As a mere literary monument, the +English version of the Bible remains the noblest example of the English +tongue." It was the King James version just from the press that the +Pilgrims brought across the sea with them. + +For the authority of the Established Church was substituted the +authority of the Scriptures. The Puritans devised a catechism based upon +their interpretation of the Bible, and, very soon after their arrival in +America, they ordered all parents and masters of servants to be diligent +in seeing that their children and wards were taught to read religious +works and give answers to the religious questions. Massachusetts was +scarcely twenty years old before education of this character was +declared to be compulsory, and provision was made for public schools +where those not taught at home could receive instruction in reading and +writing. + +[Illustration: A PAGE FROM A FAMOUS SCHOOLBOOK + + + A In ADAM'S Fall + We sinned all. + + B Heaven to find, + The Bible Mind. + + C Christ crucify'd + For sinners dy'd. + + D The Deluge drown'd + The Earth around. + + E ELIJAH hid + by Ravens fed. + + F The judgment made + FELIX afraid.] + + + +Outside of New England the idea of compulsory education was not regarded +with the same favor; but the whole land was nevertheless dotted with +little schools kept by "dames, itinerant teachers, or local parsons." +Whether we turn to the life of Franklin in the North or Washington in +the South, we read of tiny schoolhouses, where boys, and sometimes +girls, were taught to read and write. Where there were no schools, +fathers and mothers of the better kind gave their children the rudiments +of learning. Though illiteracy was widespread, there is evidence to show +that the diffusion of knowledge among the masses was making steady +progress all through the eighteenth century. + +=Religion and Higher Learning.=--Religious motives entered into the +establishment of colleges as well as local schools. Harvard, founded in +1636, and Yale, opened in 1718, were intended primarily to train +"learned and godly ministers" for the Puritan churches of New England. +To the far North, Dartmouth, chartered in 1769, was designed first as a +mission to the Indians and then as a college for the sons of New England +farmers preparing to preach, teach, or practice law. The College of New +Jersey, organized in 1746 and removed to Princeton eleven years later, +was sustained by the Presbyterians. Two colleges looked to the +Established Church as their source of inspiration and support: William +and Mary, founded in Virginia in 1693, and King's College, now Columbia +University, chartered by King George II in 1754, on an appeal from the +New York Anglicans, alarmed at the growth of religious dissent and the +"republican tendencies" of the age. Two colleges revealed a drift away +from sectarianism. Brown, established in Rhode Island in 1764, and the +Philadelphia Academy, forerunner of the University of Pennsylvania, +organized by Benjamin Franklin, reflected the spirit of toleration by +giving representation on the board of trustees to several religious +sects. It was Franklin's idea that his college should prepare young men +to serve in public office as leaders of the people and ornaments to +their country. + +=Self-education in America.=--Important as were these institutions of +learning, higher education was by no means confined within their walls. +Many well-to-do families sent their sons to Oxford or Cambridge in +England. Private tutoring in the home was common. In still more families +there were intelligent children who grew up in the great colonial school +of adversity and who trained themselves until, in every contest of mind +and wit, they could vie with the sons of Harvard or William and Mary or +any other college. Such, for example, was Benjamin Franklin, whose +charming autobiography, in addition to being an American classic, is a +fine record of self-education. His formal training in the classroom was +limited to a few years at a local school in Boston; but his +self-education continued throughout his life. He early manifested a zeal +for reading, and devoured, he tells us, his father's dry library on +theology, Bunyan's works, Defoe's writings, Plutarch's _Lives_, Locke's +_On the Human Understanding_, and innumerable volumes dealing with +secular subjects. His literary style, perhaps the best of his time, +Franklin acquired by the diligent and repeated analysis of the +_Spectator_. In a life crowded with labors, he found time to read widely +in natural science and to win single-handed recognition at the hands of +European savants for his discoveries in electricity. By his own efforts +he "attained an acquaintance" with Latin, Italian, French, and Spanish, +thus unconsciously preparing himself for the day when he was to speak +for all America at the court of the king of France. + +Lesser lights than Franklin, educated by the same process, were found +all over colonial America. From this fruitful source of native ability, +self-educated, the American cause drew great strength in the trials of +the Revolution. + + +THE COLONIAL PRESS + +=The Rise of the Newspaper.=--The evolution of American democracy into a +government by public opinion, enlightened by the open discussion of +political questions, was in no small measure aided by a free press. That +too, like education, was a matter of slow growth. A printing press was +brought to Massachusetts in 1639, but it was put in charge of an +official censor and limited to the publication of religious works. Forty +years elapsed before the first newspaper appeared, bearing the curious +title, _Public Occurrences Both Foreign and Domestic_, and it had not +been running very long before the government of Massachusetts suppressed +it for discussing a political question. + +Publishing, indeed, seemed to be a precarious business; but in 1704 +there came a second venture in journalism, _The Boston News-Letter_, +which proved to be a more lasting enterprise because it refrained from +criticizing the authorities. Still the public interest languished. When +Franklin's brother, James, began to issue his _New England Courant_ +about 1720, his friends sought to dissuade him, saying that one +newspaper was enough for America. Nevertheless he continued it; and his +confidence in the future was rewarded. In nearly every colony a gazette +or chronicle appeared within the next thirty years or more. Benjamin +Franklin was able to record in 1771 that America had twenty-five +newspapers. Boston led with five. Philadelphia had three: two in English +and one in German. + +=Censorship and Restraints on the Press.=--The idea of printing, +unlicensed by the government and uncontrolled by the church, was, +however, slow in taking form. The founders of the American colonies had +never known what it was to have the free and open publication of books, +pamphlets, broadsides, and newspapers. When the art of printing was +first discovered, the control of publishing was vested in clerical +authorities. After the establishment of the State Church in England in +the reign of Elizabeth, censorship of the press became a part of royal +prerogative. Printing was restricted to Oxford, Cambridge, and London; +and no one could publish anything without previous approval of the +official censor. When the Puritans were in power, the popular party, +with a zeal which rivaled that of the crown, sought, in turn, to silence +royalist and clerical writers by a vigorous censorship. After the +restoration of the monarchy, control of the press was once more placed +in royal hands, where it remained until 1695, when Parliament, by +failing to renew the licensing act, did away entirely with the official + +censorship. By that time political parties were so powerful and so +active and printing presses were so numerous that official review of all +published matter became a sheer impossibility. + +In America, likewise, some troublesome questions arose in connection +with freedom of the press. The Puritans of Massachusetts were no less +anxious than King Charles or the Archbishop of London to shut out from +the prying eyes of the people all literature "not mete for them to +read"; and so they established a system of official licensing for +presses, which lasted until 1755. In the other colonies where there was +more diversity of opinion and publishers could set up in business with +impunity, they were nevertheless constantly liable to arrest for +printing anything displeasing to the colonial governments. In 1721 the +editor of the _Mercury_ in Philadelphia was called before the +proprietary council and ordered to apologize for a political article, +and for a later offense of a similar character he was thrown into jail. +A still more famous case was that of Peter Zenger, a New York publisher, +who was arrested in 1735 for criticising the administration. Lawyers who +ventured to defend the unlucky editor were deprived of their licenses to +practice, and it became necessary to bring an attorney all the way from +Philadelphia. By this time the tension of feeling was high, and the +approbation of the public was forthcoming when the lawyer for the +defense exclaimed to the jury that the very cause of liberty itself, not +that of the poor printer, was on trial! The verdict for Zenger, when it +finally came, was the signal for an outburst of popular rejoicing. +Already the people of King George's province knew how precious a thing +is the freedom of the press. + +Thanks to the schools, few and scattered as they were, and to the +vigilance of parents, a very large portion, perhaps nearly one-half, of +the colonists could read. Through the newspapers, pamphlets, and +almanacs that streamed from the types, the people could follow the +course of public events and grasp the significance of political +arguments. An American opinion was in the process of making--an +independent opinion nourished by the press and enriched by discussions +around the fireside and at the taverns. When the day of resistance to +British rule came, government by opinion was at hand. For every person +who could hear the voice of Patrick Henry and Samuel Adams, there were a +thousand who could see their appeals on the printed page. Men who had +spelled out their letters while poring over Franklin's _Poor Richard's +Almanac_ lived to read Thomas Paine's thrilling call to arms. + + +THE EVOLUTION IN POLITICAL INSTITUTIONS + +Two very distinct lines of development appeared in colonial politics. +The one, exalting royal rights and aristocratic privileges, was the +drift toward provincial government through royal officers appointed in +England. The other, leading toward democracy and self-government, was +the growth in the power of the popular legislative assembly. Each +movement gave impetus to the other, with increasing force during the +passing years, until at last the final collision between the two ideals +of government came in the war of independence. + +=The Royal Provinces.=--Of the thirteen English colonies eight were +royal provinces in 1776, with governors appointed by the king. Virginia +passed under the direct rule of the crown in 1624, when the charter of +the London Company was annulled. The Massachusetts Bay corporation lost +its charter in 1684, and the new instrument granted seven years later +stripped the colonists of the right to choose their chief executive. In +the early decades of the eighteenth century both the Carolinas were +given the provincial instead of the proprietary form. New Hampshire, +severed from Massachusetts in 1679, and Georgia, surrendered by the +trustees in 1752, went into the hands of the crown. New York, +transferred to the Duke of York on its capture from the Dutch in 1664, +became a province when he took the title of James II in 1685. New +Jersey, after remaining for nearly forty years under proprietors, was +brought directly under the king in 1702. Maryland, Pennsylvania, and +Delaware, although they retained their proprietary character until the +Revolution, were in some respects like the royal colonies, for their +governors were as independent of popular choice as were the appointees +of King George. Only two colonies, Rhode Island and Connecticut, +retained full self-government on the eve of the Revolution. They alone +had governors and legislatures entirely of their own choosing. + +The chief officer of the royal province was the governor, who enjoyed +high and important powers which he naturally sought to augment at every +turn. He enforced the laws and, usually with the consent of a council, +appointed the civil and military officers. He granted pardons and +reprieves; he was head of the highest court; he was commander-in-chief +of the militia; he levied troops for defense and enforced martial law in +time of invasion, war, and rebellion. In all the provinces, except +Massachusetts, he named the councilors who composed the upper house of +the legislature and was likely to choose those who favored his claims. +He summoned, adjourned, and dissolved the popular assembly, or the lower +house; he laid before it the projects of law desired by the crown; and +he vetoed measures which he thought objectionable. Here were in America +all the elements of royal prerogative against which Hampden had +protested and Cromwell had battled in England. + +[Illustration: THE ROYAL GOVERNOR'S PALACE AT NEW BERNE] + +The colonial governors were generally surrounded by a body of +office-seekers and hunters for land grants. Some of them were noblemen +of broken estates who had come to America to improve their fortunes. The +pretensions of this circle grated on colonial nerves, and privileges +granted to them, often at the expense of colonists, did much to deepen +popular antipathy to the British government. Favors extended to +adherents of the Established Church displeased Dissenters. The +reappearance of this formidable union of church and state, from which +they had fled, stirred anew the ancient wrath against that combination. + +=The Colonial Assembly.=--Coincident with the drift toward +administration through royal governors was the second and opposite +tendency, namely, a steady growth in the practice of self-government. +The voters of England had long been accustomed to share in taxation and +law-making through representatives in Parliament, and the idea was early +introduced in America. Virginia was only twelve years old (1619) when +its first representative assembly appeared. As the towns of +Massachusetts multiplied and it became impossible for all the members of +the corporation to meet at one place, the representative idea was +adopted, in 1633. The river towns of Connecticut formed a representative +system under their "Fundamental Orders" of 1639, and the entire colony +was given a royal charter in 1662. Generosity, as well as practical +considerations, induced such proprietors as Lord Baltimore and William +Penn to invite their colonists to share in the government as soon as any +considerable settlements were made. Thus by one process or another every +one of the colonies secured a popular assembly. + +It is true that in the provision for popular elections, the suffrage was +finally restricted to property owners or taxpayers, with a leaning +toward the freehold qualification. In Virginia, the rural voter had to +be a freeholder owning at least fifty acres of land, if there was no +house on it, or twenty-five acres with a house twenty-five feet square. +In Massachusetts, the voter for member of the assembly under the charter +of 1691 had to be a freeholder of an estate worth forty shillings a year +at least or of other property to the value of forty pounds sterling. In +Pennsylvania, the suffrage was granted to freeholders owning fifty acres +or more of land well seated, twelve acres cleared, and to other persons +worth at least fifty pounds in lawful money. + +Restrictions like these undoubtedly excluded from the suffrage a very +considerable number of men, particularly the mechanics and artisans of +the towns, who were by no means content with their position. +Nevertheless, it was relatively easy for any man to acquire a small +freehold, so cheap and abundant was land; and in fact a large proportion +of the colonists were land owners. Thus the assemblies, in spite of the +limited suffrage, acquired a democratic tone. + +The popular character of the assemblies increased as they became engaged +in battles with the royal and proprietary governors. When called upon by +the executive to make provision for the support of the administration, +the legislature took advantage of the opportunity to make terms in the +interest of the taxpayers. It made annual, not permanent, grants of +money to pay official salaries and then insisted upon electing a +treasurer to dole it out. Thus the colonists learned some of the +mysteries of public finance, as well as the management of rapacious +officials. The legislature also used its power over money grants to +force the governor to sign bills which he would otherwise have vetoed. + +=Contests between Legislatures and Governors.=--As may be imagined, many +and bitter were the contests between the royal and proprietary governors +and the colonial assemblies. Franklin relates an amusing story of how +the Pennsylvania assembly held in one hand a bill for the executive to +sign and, in the other hand, the money to pay his salary. Then, with sly +humor, Franklin adds: "Do not, my courteous reader, take pet at our +proprietary constitution for these our bargain and sale proceedings in +legislation. It is a happy country where justice and what was your own +before can be had for ready money. It is another addition to the value +of money and of course another spur to industry. Every land is not so +blessed." + +It must not be thought, however, that every governor got off as easily +as Franklin's tale implies. On the contrary, the legislatures, like +Caesar, fed upon meat that made them great and steadily encroached upon +executive prerogatives as they tried out and found their strength. If +we may believe contemporary laments, the power of the crown in America +was diminishing when it was struck down altogether. In New York, the +friends of the governor complained in 1747 that "the inhabitants of +plantations are generally educated in republican principles; upon +republican principles all is conducted. Little more than a shadow of +royal authority remains in the Northern colonies." "Here," echoed the +governor of South Carolina, the following year, "levelling principles +prevail; the frame of the civil government is unhinged; a governor, if +he would be idolized, must betray his trust; the people have got their +whole administration in their hands; the election of the members of the +assembly is by ballot; not civil posts only, but all ecclesiastical +preferments, are in the disposal or election of the people." + +Though baffled by the "levelling principles" of the colonial assemblies, +the governors did not give up the case as hopeless. Instead they evolved +a system of policy and action which they thought could bring the +obstinate provincials to terms. That system, traceable in their letters +to the government in London, consisted of three parts: (1) the royal +officers in the colonies were to be made independent of the legislatures +by taxes imposed by acts of Parliament; (2) a British standing army was +to be maintained in America; (3) the remaining colonial charters were to +be revoked and government by direct royal authority was to be enlarged. + +Such a system seemed plausible enough to King George III and to many +ministers of the crown in London. With governors, courts, and an army +independent of the colonists, they imagined it would be easy to carry +out both royal orders and acts of Parliament. This reasoning seemed both +practical and logical. Nor was it founded on theory, for it came fresh +from the governors themselves. It was wanting in one respect only. It +failed to take account of the fact that the American people were growing +strong in the practice of self-government and could dispense with the +tutelage of the British ministry, no matter how excellent it might be or +how benevolent its intentions. + + +=References= + +A.M. Earle, _Home Life in Colonial Days_. + +A.L. Cross, _The Anglican Episcopate and the American Colonies_ (Harvard +Studies). + +E.G. Dexter, _History of Education in the United States_. + +C.A. Duniway, _Freedom of the Press in Massachusetts_. + +Benjamin Franklin, _Autobiography_. + +E.B. Greene, _The Provincial Governor_ (Harvard Studies). + +A.E. McKinley, _The Suffrage Franchise in the Thirteen English Colonies_ +(Pennsylvania University Studies). + +M.C. Tyler, _History of American Literature during the Colonial Times_ +(2 vols.). + + +=Questions= + +1. Why is leisure necessary for the production of art and literature? +How may leisure be secured? + +2. Explain the position of the church in colonial life. + +3. Contrast the political roles of Puritanism and the Established +Church. + +4. How did diversity of opinion work for toleration? + +5. Show the connection between religion and learning in colonial times. + +6. Why is a "free press" such an important thing to American democracy? + +7. Relate some of the troubles of early American publishers. + +8. Give the undemocratic features of provincial government. + +9. How did the colonial assemblies help to create an independent +American spirit, in spite of a restricted suffrage? + +10. Explain the nature of the contests between the governors and the +legislatures. + + +=Research Topics= + +=Religious and Intellectual Life.=--Lodge, _Short History of the English +Colonies_: (1) in New England, pp. 418-438, 465-475; (2) in Virginia, +pp. 54-61, 87-89; (3) in Pennsylvania, pp. 232-237, 253-257; (4) in New +York, pp. 316-321. Interesting source materials in Hart, _American +History Told by Contemporaries_, Vol. II, pp. 255-275, 276-290. + +=The Government of a Royal Province, Virginia.=--Lodge, pp. 43-50. +Special Reference: E.B. Greene, _The Provincial Governor_ (Harvard +Studies). + +=The Government of a Proprietary Colony, Pennsylvania.=--Lodge, pp. +230-232. + +=Government in New England.=--Lodge, pp. 412-417. + +=The Colonial Press.=--Special Reference: G.H. Payne, _History of +Journalism in the United States_ (1920). + +=Colonial Life in General.=--John Fiske, _Old Virginia and Her +Neighbors_, Vol. II, pp. 174-269; Elson, _History of the United States_, +pp. 197-210. + +=Colonial Government in General.=--Elson, pp. 210-216. + + + + +CHAPTER IV + +THE DEVELOPMENT OF COLONIAL NATIONALISM + + +It is one of the well-known facts of history that a people loosely +united by domestic ties of a political and economic nature, even a +people torn by domestic strife, may be welded into a solid and compact +body by an attack from a foreign power. The imperative call to common +defense, the habit of sharing common burdens, the fusing force of common +service--these things, induced by the necessity of resisting outside +interference, act as an amalgam drawing together all elements, except, +perhaps, the most discordant. The presence of the enemy allays the most +virulent of quarrels, temporarily at least. "Politics," runs an old +saying, "stops at the water's edge." + +This ancient political principle, so well understood in diplomatic +circles, applied nearly as well to the original thirteen American +colonies as to the countries of Europe. The necessity for common +defense, if not equally great, was certainly always pressing. Though it +has long been the practice to speak of the early settlements as founded +in "a wilderness," this was not actually the case. From the earliest +days of Jamestown on through the years, the American people were +confronted by dangers from without. All about their tiny settlements +were Indians, growing more and more hostile as the frontier advanced and +as sharp conflicts over land aroused angry passions. To the south and +west was the power of Spain, humiliated, it is true, by the disaster to +the Armada, but still presenting an imposing front to the British +empire. To the north and west were the French, ambitious, energetic, +imperial in temper, and prepared to contest on land and water the +advance of British dominion in America. + + +RELATIONS WITH THE INDIANS AND THE FRENCH + +=Indian Affairs.=--It is difficult to make general statements about the +relations of the colonists to the Indians. The problem was presented in +different shape in different sections of America. It was not handled +according to any coherent or uniform plan by the British government, +which alone could speak for all the provinces at the same time. Neither +did the proprietors and the governors who succeeded one another, in an +irregular train, have the consistent policy or the matured experience +necessary for dealing wisely with Indian matters. As the difficulties +arose mainly on the frontiers, where the restless and pushing pioneers +were making their way with gun and ax, nearly everything that happened +was the result of chance rather than of calculation. A personal quarrel +between traders and an Indian, a jug of whisky, a keg of gunpowder, the +exchange of guns for furs, personal treachery, or a flash of bad temper +often set in motion destructive forces of the most terrible character. + +On one side of the ledger may be set innumerable generous records--of +Squanto and Samoset teaching the Pilgrims the ways of the wilds; of +Roger Williams buying his lands from the friendly natives; or of William +Penn treating with them on his arrival in America. On the other side of +the ledger must be recorded many a cruel and bloody conflict as the +frontier rolled westward with deadly precision. The Pequots on the +Connecticut border, sensing their doom, fell upon the tiny settlements +with awful fury in 1637 only to meet with equally terrible punishment. A +generation later, King Philip, son of Massasoit, the friend of the +Pilgrims, called his tribesmen to a war of extermination which brought +the strength of all New England to the field and ended in his own +destruction. In New York, the relations with the Indians, especially +with the Algonquins and the Mohawks, were marked by periodic and +desperate wars. Virginia and her Southern neighbors suffered as did New +England. In 1622 Opecacano, a brother of Powhatan, the friend of the +Jamestown settlers, launched a general massacre; and in 1644 he +attempted a war of extermination. In 1675 the whole frontier was ablaze. +Nathaniel Bacon vainly attempted to stir the colonial governor to put up +an adequate defense and, failing in that plea, himself headed a revolt +and a successful expedition against the Indians. As the Virginia +outposts advanced into the Kentucky country, the strife with the natives +was transferred to that "dark and bloody ground"; while to the +southeast, a desperate struggle with the Tuscaroras called forth the +combined forces of the two Carolinas and Virginia. + +[Illustration: _From an old print._ + +VIRGINIANS DEFENDING THEMSELVES AGAINST THE INDIANS] + +From such horrors New Jersey and Delaware were saved on account of their +geographical location. Pennsylvania, consistently following a policy of +conciliation, was likewise spared until her western vanguard came into +full conflict with the allied French and Indians. Georgia, by clever +negotiations and treaties of alliance, managed to keep on fair terms +with her belligerent Cherokees and Creeks. But neither diplomacy nor +generosity could stay the inevitable conflict as the frontier advanced, +especially after the French soldiers enlisted the Indians in their +imperial enterprises. It was then that desultory fighting became general +warfare. + +[Illustration: ENGLISH, FRENCH, AND SPANISH POSSESSIONS IN AMERICA, +1750] + +=Early Relations with the French.=--During the first decades of French +exploration and settlement in the St. Lawrence country, the English +colonies, engrossed with their own problems, gave little or no thought +to their distant neighbors. Quebec, founded in 1608, and Montreal, in +1642, were too far away, too small in population, and too slight in +strength to be much of a menace to Boston, Hartford, or New York. It was +the statesmen in France and England, rather than the colonists in +America, who first grasped the significance of the slowly converging +empires in North America. It was the ambition of Louis XIV of France, +rather than the labors of Jesuit missionaries and French rangers, that +sounded the first note of colonial alarm. + +Evidence of this lies in the fact that three conflicts between the +English and the French occurred before their advancing frontiers met on +the Pennsylvania border. King William's War (1689-1697), Queen Anne's +War (1701-1713), and King George's War (1744-1748) owed their origins +and their endings mainly to the intrigues and rivalries of European +powers, although they all involved the American colonies in struggles +with the French and their savage allies. + +=The Clash in the Ohio Valley.=--The second of these wars had hardly +closed, however, before the English colonists themselves began to be +seriously alarmed about the rapidly expanding French dominion in the +West. Marquette and Joliet, who opened the Lake region, and La Salle, +who in 1682 had gone down the Mississippi to the Gulf, had been followed +by the builders of forts. In 1718, the French founded New Orleans, thus +taking possession of the gateway to the Mississippi as well as the St. +Lawrence. A few years later they built Fort Niagara; in 1731 they +occupied Crown Point; in 1749 they formally announced their dominion +over all the territory drained by the Ohio River. Having asserted this +lofty claim, they set out to make it good by constructing in the years +1752-1754 Fort Le Boeuf near Lake Erie, Fort Venango on the upper +waters of the Allegheny, and Fort Duquesne at the junction of the +streams forming the Ohio. Though they were warned by George Washington, +in the name of the governor of Virginia, to keep out of territory "so +notoriously known to be property of the crown of Great Britain," the +French showed no signs of relinquishing their pretensions. + +[Illustration: _From an old print_ + +BRADDOCK'S RETREAT] + +=The Final Phase--the French and Indian War.=--Thus it happened that the +shot which opened the Seven Years' War, known in America as the French +and Indian War, was fired in the wilds of Pennsylvania. There began the +conflict that spread to Europe and even Asia and finally involved +England and Prussia, on the one side, and France, Austria, Spain, and +minor powers on the other. On American soil, the defeat of Braddock in +1755 and Wolfe's exploit in capturing Quebec four years later were the +dramatic features. On the continent of Europe, England subsidized +Prussian arms to hold France at bay. In India, on the banks of the +Ganges, as on the banks of the St. Lawrence, British arms were +triumphant. Well could the historian write: "Conquests equaling in +rapidity and far surpassing in magnitude those of Cortes and Pizarro had +been achieved in the East." Well could the merchants of London declare +that under the administration of William Pitt, the imperial genius of +this world-wide conflict, commerce had been "united with and made to +flourish by war." + +From the point of view of the British empire, the results of the war +were momentous. By the peace of 1763, Canada and the territory east of +the Mississippi, except New Orleans, passed under the British flag. The +remainder of the Louisiana territory was transferred to Spain and French +imperial ambitions on the American continent were laid to rest. In +exchange for Havana, which the British had seized during the war, Spain +ceded to King George the colony of Florida. Not without warrant did +Macaulay write in after years that Pitt "was the first Englishman of his +time; and he had made England the first country in the world." + + +THE EFFECTS OF WARFARE ON THE COLONIES + +The various wars with the French and the Indians, trivial in detail as +they seem to-day, had a profound influence on colonial life and on the +destiny of America. Circumstances beyond the control of popular +assemblies, jealous of their individual powers, compelled cooperation +among them, grudging and stingy no doubt, but still cooperation. The +American people, more eager to be busy in their fields or at their +trades, were simply forced to raise and support armies, to learn the +arts of warfare, and to practice, if in a small theater, the science of +statecraft. These forces, all cumulative, drove the colonists, so +tenaciously provincial in their habits, in the direction of nationalism. + +=The New England Confederation.=--It was in their efforts to deal with +the problems presented by the Indian and French menace that the +Americans took the first steps toward union. Though there were many +common ties among the settlers of New England, it required a deadly +fear of the Indians to produce in 1643 the New England Confederation, +composed of Massachusetts, Plymouth, Connecticut, and New Haven. The +colonies so united were bound together in "a firm and perpetual league +of friendship and amity for offense and defense, mutual service and +succor, upon all just occasions." They made provision for distributing +the burdens of wars among the members and provided for a congress of +commissioners from each colony to determine upon common policies. For +some twenty years the Confederation was active and it continued to hold +meetings until after the extinction of the Indian peril on the immediate +border. + +Virginia, no less than Massachusetts, was aware of the importance of +intercolonial cooperation. In the middle of the seventeenth century, the +Old Dominion began treaties of commerce and amity with New York and the +colonies of New England. In 1684 delegates from Virginia met at Albany +with the agents of New York and Massachusetts to discuss problems of +mutual defense. A few years later the Old Dominion cooperated loyally +with the Carolinas in defending their borders against Indian forays. + +=The Albany Plan of Union.=--An attempt at a general colonial union was +made in 1754. On the suggestion of the Lords of Trade in England, a +conference was held at Albany to consider Indian relations, to devise +measures of defense against the French, and to enter into "articles of +union and confederation for the general defense of his Majesty's +subjects and interests in North America as well in time of peace as of +war." New Hampshire, Massachusetts, Connecticut, Rhode Island, New York, +Pennsylvania, and Maryland were represented. After a long discussion, a +plan of union, drafted mainly, it seems, by Benjamin Franklin, was +adopted and sent to the colonies and the crown for approval. The +colonies, jealous of their individual rights, refused to accept the +scheme and the king disapproved it for the reason, Franklin said, that +it had "too much weight in the democratic part of the constitution." +Though the Albany union failed, the document is still worthy of study +because it forecast many of the perplexing problems that were not solved +until thirty-three years afterward, when another convention of which +also Franklin was a member drafted the Constitution of the United +States. + +[Illustration: BENJAMIN FRANKLIN] + +=The Military Education of the Colonists.=--The same wars that showed +the provincials the meaning of union likewise instructed them in the art +of defending their institutions. Particularly was this true of the last +French and Indian conflict, which stretched all the way from Maine to +the Carolinas and made heavy calls upon them all for troops. The answer, +it is admitted, was far from satisfactory to the British government and +the conduct of the militiamen was far from professional; but thousands +of Americans got a taste, a strong taste, of actual fighting in the +field. Men like George Washington and Daniel Morgan learned lessons that +were not forgotten in after years. They saw what American militiamen +could do under favorable circumstances and they watched British regulars +operating on American soil. "This whole transaction," shrewdly remarked +Franklin of Braddock's campaign, "gave us Americans the first suspicion +that our exalted ideas of the prowess of British regular troops had not +been well founded." It was no mere accident that the Virginia colonel +who drew his sword under the elm at Cambridge and took command of the +army of the Revolution was the brave officer who had "spurned the +whistle of bullets" at the memorable battle in western Pennsylvania. + +=Financial Burdens and Commercial Disorder.=--While the provincials were +learning lessons in warfare they were also paying the bills. All the +conflicts were costly in treasure as in blood. King Philip's war left +New England weak and almost bankrupt. The French and Indian struggle was +especially expensive. The twenty-five thousand men put in the field by +the colonies were sustained only by huge outlays of money. Paper +currency streamed from the press and debts were accumulated. Commerce +was driven from its usual channels and prices were enhanced. When the +end came, both England and America were staggering under heavy +liabilities, and to make matters worse there was a fall of prices +accompanied by a commercial depression which extended over a period of +ten years. It was in the midst of this crisis that measures of taxation +had to be devised to pay the cost of the war, precipitating the quarrel +which led to American independence. + +=The Expulsion of French Power from North America.=--The effects of the +defeat administered to France, as time proved, were difficult to +estimate. Some British statesmen regarded it as a happy circumstance +that the colonists, already restive under their administration, had no +foreign power at hand to aid them in case they struck for independence. +American leaders, on the other hand, now that the soldiers of King Louis +were driven from the continent, thought that they had no other country +to fear if they cast off British sovereignty. At all events, France, +though defeated, was not out of the sphere of American influence; for, +as events proved, it was the fortunate French alliance negotiated by +Franklin that assured the triumph of American arms in the War of the +Revolution. + + +COLONIAL RELATIONS WITH THE BRITISH GOVERNMENT + +It was neither the Indian wars nor the French wars that finally brought +forth American nationality. That was the product of the long strife +with the mother country which culminated in union for the war of +independence. The forces that created this nation did not operate in the +colonies alone. The character of the English sovereigns, the course of +events in English domestic politics, and English measures of control +over the colonies--executive, legislative, and judicial--must all be +taken into account. + +=The Last of the Stuarts.=--The struggles between Charles I (1625-49) +and the parliamentary party and the turmoil of the Puritan regime +(1649-60) so engrossed the attention of Englishmen at home that they had +little time to think of colonial policies or to interfere with colonial +affairs. The restoration of the monarchy in 1660, accompanied by +internal peace and the increasing power of the mercantile classes in the +House of Commons, changed all that. In the reign of Charles II +(1660-85), himself an easy-going person, the policy of regulating trade +by act of Parliament was developed into a closely knit system and +powerful agencies to supervise the colonies were created. At the same +time a system of stricter control over the dominions was ushered in by +the annulment of the old charter of Massachusetts which conferred so +much self-government on the Puritans. + +Charles' successor, James II, a man of sterner stuff and jealous of his +authority in the colonies as well as at home, continued the policy thus +inaugurated and enlarged upon it. If he could have kept his throne, he +would have bent the Americans under a harsh rule or brought on in his +dominions a revolution like that which he precipitated at home in 1688. +He determined to unite the Northern colonies and introduce a more +efficient administration based on the pattern of the royal provinces. He +made a martinet, Sir Edmund Andros, governor of all New England, New +York, and New Jersey. The charter of Massachusetts, annulled in the last +days of his brother's reign, he continued to ignore, and that of +Connecticut would have been seized if it had not been spirited away and +hidden, according to tradition, in a hollow oak. + +For several months, Andros gave the Northern colonies a taste of +ill-tempered despotism. He wrung quit rents from land owners not +accustomed to feudal dues; he abrogated titles to land where, in his +opinion, they were unlawful; he forced the Episcopal service upon the +Old South Church in Boston; and he denied the writ of _habeas corpus_ to +a preacher who denounced taxation without representation. In the middle +of his arbitrary course, however, his hand was stayed. The news came +that King James had been dethroned by his angry subjects, and the people +of Boston, kindling a fire on Beacon Hill, summoned the countryside to +dispose of Andros. The response was prompt and hearty. The hated +governor was arrested, imprisoned, and sent back across the sea under +guard. + +The overthrow of James, followed by the accession of William and Mary +and by assured parliamentary supremacy, had an immediate effect in the +colonies. The new order was greeted with thanksgiving. Massachusetts was +given another charter which, though not so liberal as the first, +restored the spirit if not the entire letter of self-government. In the +other colonies where Andros had been operating, the old course of +affairs was resumed. + +=The Indifference of the First Two Georges.=--On the death in 1714 of +Queen Anne, the successor of King William, the throne passed to a +Hanoverian prince who, though grateful for English honors and revenues, +was more interested in Hanover than in England. George I and George II, +whose combined reigns extended from 1714 to 1760, never even learned to +speak the English language, at least without an accent. The necessity of +taking thought about colonial affairs bored both of them so that the +stoutest defender of popular privileges in Boston or Charleston had no +ground to complain of the exercise of personal prerogatives by the king. +Moreover, during a large part of this period, the direction of affairs +was in the hands of an astute leader, Sir Robert Walpole, who betrayed +his somewhat cynical view of politics by adopting as his motto: "Let +sleeping dogs lie." He revealed his appreciation of popular sentiment +by exclaiming: "I will not be the minister to enforce taxes at the +expense of blood." Such kings and such ministers were not likely to +arouse the slumbering resistance of the thirteen colonies across the +sea. + +=Control of the Crown over the Colonies.=--While no English ruler from +James II to George III ventured to interfere with colonial matters +personally, constant control over the colonies was exercised by royal +officers acting under the authority of the crown. Systematic supervision +began in 1660, when there was created by royal order a committee of the +king's council to meet on Mondays and Thursdays of each week to consider +petitions, memorials, and addresses respecting the plantations. In 1696 +a regular board was established, known as the "Lords of Trade and +Plantations," which continued, until the American Revolution, to +scrutinize closely colonial business. The chief duties of the board were +to examine acts of colonial legislatures, to recommend measures to those +assemblies for adoption, and to hear memorials and petitions from the +colonies relative to their affairs. + +The methods employed by this board were varied. All laws passed by +American legislatures came before it for review as a matter of routine. +If it found an act unsatisfactory, it recommended to the king the +exercise of his veto power, known as the royal disallowance. Any person +who believed his personal or property rights injured by a colonial law +could be heard by the board in person or by attorney; in such cases it +was the practice to hear at the same time the agent of the colony so +involved. The royal veto power over colonial legislation was not, +therefore, a formal affair, but was constantly employed on the +suggestion of a highly efficient agency of the crown. All this was in +addition to the powers exercised by the governors in the royal +provinces. + +=Judicial Control.=--Supplementing this administrative control over the +colonies was a constant supervision by the English courts of law. The +king, by virtue of his inherent authority, claimed and exercised high +appellate powers over all judicial tribunals in the empire. The right +of appeal from local courts, expressly set forth in some charters, was, +on the eve of the Revolution, maintained in every colony. Any subject in +England or America, who, in the regular legal course, was aggrieved by +any act of a colonial legislature or any decision of a colonial court, +had the right, subject to certain regulations, to carry his case to the +king in council, forcing his opponent to follow him across the sea. In +the exercise of appellate power, the king in council acting as a court +could, and frequently did, declare acts of colonial legislatures duly +enacted and approved, null and void, on the ground that they were +contrary to English law. + +=Imperial Control in Operation.=--Day after day, week after week, year +after year, the machinery for political and judicial control over +colonial affairs was in operation. At one time the British governors in +the colonies were ordered not to approve any colonial law imposing a +duty on European goods imported in English vessels. Again, when North +Carolina laid a tax on peddlers, the council objected to it as +"restrictive upon the trade and dispersion of English manufactures +throughout the continent." At other times, Indian trade was regulated in +the interests of the whole empire or grants of lands by a colonial +legislature were set aside. Virginia was forbidden to close her ports to +North Carolina lest there should be retaliation. + +In short, foreign and intercolonial trade were subjected to a control +higher than that of the colony, foreshadowing a day when the +Constitution of the United States was to commit to Congress the power to +regulate interstate and foreign commerce and commerce with the Indians. +A superior judicial power, towering above that of the colonies, as the +Supreme Court at Washington now towers above the states, kept the +colonial legislatures within the metes and bounds of established law. In +the thousands of appeals, memorials, petitions, and complaints, and the +rulings and decisions upon them, were written the real history of +British imperial control over the American colonies. + +So great was the business before the Lords of Trade that the colonies +had to keep skilled agents in London to protect their interests. As +common grievances against the operation of this machinery of control +arose, there appeared in each colony a considerable body of men, with +the merchants in the lead, who chafed at the restraints imposed on their +enterprise. Only a powerful blow was needed to weld these bodies into a +common mass nourishing the spirit of colonial nationalism. When to the +repeated minor irritations were added general and sweeping measures of +Parliament applying to every colony, the rebound came in the Revolution. + +=Parliamentary Control over Colonial Affairs.=--As soon as Parliament +gained in power at the expense of the king, it reached out to bring the +American colonies under its sway as well. Between the execution of +Charles I and the accession of George III, there was enacted an immense +body of legislation regulating the shipping, trade, and manufactures of +America. All of it, based on the "mercantile" theory then prevalent in +all countries of Europe, was designed to control the overseas +plantations in such a way as to foster the commercial and business +interests of the mother country, where merchants and men of finance had +got the upper hand. According to this theory, the colonies of the +British empire should be confined to agriculture and the production of +raw materials, and forced to buy their manufactured goods of England. + +_The Navigation Acts._--In the first rank among these measures of +British colonial policy must be placed the navigation laws framed for +the purpose of building up the British merchant marine and navy--arms so +essential in defending the colonies against the Spanish, Dutch, and +French. The beginning of this type of legislation was made in 1651 and +it was worked out into a system early in the reign of Charles II +(1660-85). + +The Navigation Acts, in effect, gave a monopoly of colonial commerce to +British ships. No trade could be carried on between Great Britain and +her dominions save in vessels built and manned by British subjects. No +European goods could be brought to America save in the ships of the +country that produced them or in English ships. These laws, which were +almost fatal to Dutch shipping in America, fell with severity upon the +colonists, compelling them to pay higher freight rates. The adverse +effect, however, was short-lived, for the measures stimulated +shipbuilding in the colonies, where the abundance of raw materials gave +the master builders of America an advantage over those of the mother +country. Thus the colonists in the end profited from the restrictive +policy written into the Navigation Acts. + +_The Acts against Manufactures._--The second group of laws was +deliberately aimed to prevent colonial industries from competing too +sharply with those of England. Among the earliest of these measures may +be counted the Woolen Act of 1699, forbidding the exportation of woolen +goods from the colonies and even the woolen trade between towns and +colonies. When Parliament learned, as the result of an inquiry, that New +England and New York were making thousands of hats a year and sending +large numbers annually to the Southern colonies and to Ireland, Spain, +and Portugal, it enacted in 1732 a law declaring that "no hats or felts, +dyed or undyed, finished or unfinished" should be "put upon any vessel +or laden upon any horse or cart with intent to export to any place +whatever." The effect of this measure upon the hat industry was almost +ruinous. A few years later a similar blow was given to the iron +industry. By an act of 1750, pig and bar iron from the colonies were +given free entry to England to encourage the production of the raw +material; but at the same time the law provided that "no mill or other +engine for slitting or rolling of iron, no plating forge to work with a +tilt hammer, and no furnace for making steel" should be built in the +colonies. As for those already built, they were declared public +nuisances and ordered closed. Thus three important economic interests of +the colonists, the woolen, hat, and iron industries, were laid under the +ban. + +_The Trade Laws._--The third group of restrictive measures passed by the +British Parliament related to the sale of colonial produce. An act of +1663 required the colonies to export certain articles to Great Britain +or to her dominions alone; while sugar, tobacco, and ginger consigned to +the continent of Europe had to pass through a British port paying custom +duties and through a British merchant's hands paying the usual +commission. At first tobacco was the only one of the "enumerated +articles" which seriously concerned the American colonies, the rest +coming mainly from the British West Indies. In the course of time, +however, other commodities were added to the list of enumerated +articles, until by 1764 it embraced rice, naval stores, copper, furs, +hides, iron, lumber, and pearl ashes. This was not all. The colonies +were compelled to bring their European purchases back through English +ports, paying duties to the government and commissions to merchants +again. + +_The Molasses Act._--Not content with laws enacted in the interest of +English merchants and manufacturers, Parliament sought to protect the +British West Indies against competition from their French and Dutch +neighbors. New England merchants had long carried on a lucrative trade +with the French islands in the West Indies and Dutch Guiana, where sugar +and molasses could be obtained in large quantities at low prices. Acting +on the protests of English planters in the Barbadoes and Jamaica, +Parliament, in 1733, passed the famous Molasses Act imposing duties on +sugar and molasses imported into the colonies from foreign +countries--rates which would have destroyed the American trade with the +French and Dutch if the law had been enforced. The duties, however, were +not collected. The molasses and sugar trade with the foreigners went on +merrily, smuggling taking the place of lawful traffic. + +=Effect of the Laws in America.=--As compared with the strict monopoly +of her colonial trade which Spain consistently sought to maintain, the +policy of England was both moderate and liberal. Furthermore, the +restrictive laws were supplemented by many measures intended to be +favorable to colonial prosperity. The Navigation Acts, for example, +redounded to the advantage of American shipbuilders and the producers +of hemp, tar, lumber, and ship stores in general. Favors in British +ports were granted to colonial producers as against foreign competitors +and in some instances bounties were paid by England to encourage +colonial enterprise. Taken all in all, there is much justification in +the argument advanced by some modern scholars to the effect that the +colonists gained more than they lost by British trade and industrial +legislation. Certainly after the establishment of independence, when +free from these old restrictions, the Americans found themselves +handicapped by being treated as foreigners rather than favored traders +and the recipients of bounties in English markets. + +Be that as it may, it appears that the colonists felt little irritation +against the mother country on account of the trade and navigation laws +enacted previous to the close of the French and Indian war. Relatively +few were engaged in the hat and iron industries as compared with those +in farming and planting, so that England's policy of restricting America +to agriculture did not conflict with the interests of the majority of +the inhabitants. The woolen industry was largely in the hands of women +and carried on in connection with their domestic duties, so that it was +not the sole support of any considerable number of people. + +As a matter of fact, moreover, the restrictive laws, especially those +relating to trade, were not rigidly enforced. Cargoes of tobacco were +boldly sent to continental ports without even so much as a bow to the +English government, to which duties should have been paid. Sugar and +molasses from the French and Dutch colonies were shipped into New +England in spite of the law. Royal officers sometimes protested against +smuggling and sometimes connived at it; but at no time did they succeed +in stopping it. Taken all in all, very little was heard of "the galling +restraints of trade" until after the French war, when the British +government suddenly entered upon a new course. + + +SUMMARY OF THE COLONIAL PERIOD + +In the period between the landing of the English at Jamestown, Virginia, +in 1607, and the close of the French and Indian war in 1763--a period of +a century and a half--a new nation was being prepared on this continent +to take its place among the powers of the earth. It was an epoch of +migration. Western Europe contributed emigrants of many races and +nationalities. The English led the way. Next to them in numerical +importance were the Scotch-Irish and the Germans. Into the melting pot +were also cast Dutch, Swedes, French, Jews, Welsh, and Irish. Thousands +of negroes were brought from Africa to till Southern fields or labor as +domestic servants in the North. + +Why did they come? The reasons are various. Some of them, the Pilgrims +and Puritans of New England, the French Huguenots, Scotch-Irish and +Irish, and the Catholics of Maryland, fled from intolerant governments +that denied them the right to worship God according to the dictates of +their consciences. Thousands came to escape the bondage of poverty in +the Old World and to find free homes in America. Thousands, like the +negroes from Africa, were dragged here against their will. The lure of +adventure appealed to the restless and the lure of profits to the +enterprising merchants. + +How did they come? In some cases religious brotherhoods banded together +and borrowed or furnished the funds necessary to pay the way. In other +cases great trading companies were organized to found colonies. Again it +was the wealthy proprietor, like Lord Baltimore or William Penn, who +undertook to plant settlements. Many immigrants were able to pay their +own way across the sea. Others bound themselves out for a term of years +in exchange for the cost of the passage. Negroes were brought on account +of the profits derived from their sale as slaves. + +Whatever the motive for their coming, however, they managed to get +across the sea. The immigrants set to work with a will. They cut down +forests, built houses, and laid out fields. They founded churches, +schools, and colleges. They set up forges and workshops. They spun and +wove. They fashioned ships and sailed the seas. They bartered and +traded. Here and there on favorable harbors they established centers of +commerce--Boston, Providence, New York, Philadelphia, Baltimore, and +Charleston. As soon as a firm foothold was secured on the shore line +they pressed westward until, by the close of the colonial period, they +were already on the crest of the Alleghanies. + +Though they were widely scattered along a thousand miles of seacoast, +the colonists were united in spirit by many common ties. The major +portion of them were Protestants. The language, the law, and the +literature of England furnished the basis of national unity. Most of the +colonists were engaged in the same hard task; that of conquering a +wilderness. To ties of kinship and language were added ties created by +necessity. They had to unite in defense; first, against the Indians and +later against the French. They were all subjects of the same +sovereign--the king of England. The English Parliament made laws for +them and the English government supervised their local affairs, their +trade, and their manufactures. Common forces assailed them. Common +grievances vexed them. Common hopes inspired them. + +Many of the things which tended to unite them likewise tended to throw +them into opposition to the British Crown and Parliament. Most of them +were freeholders; that is, farmers who owned their own land and tilled +it with their own hands. A free soil nourished the spirit of freedom. +The majority of them were Dissenters, critics, not friends, of the +Church of England, that stanch defender of the British monarchy. Each +colony in time developed its own legislature elected by the voters; it +grew accustomed to making laws and laying taxes for itself. Here was a +people learning self-reliance and self-government. The attempts to +strengthen the Church of England in America and the transformation of +colonies into royal provinces only fanned the spirit of independence +which they were designed to quench. + +Nevertheless, the Americans owed much of their prosperity to the +assistance of the government that irritated them. It was the protection +of the British navy that prevented Holland, Spain, and France from +wiping out their settlements. Though their manufacture and trade were +controlled in the interests of the mother country, they also enjoyed +great advantages in her markets. Free trade existed nowhere upon the +earth; but the broad empire of Britain was open to American ships and +merchandise. It could be said, with good reason, that the disadvantages +which the colonists suffered through British regulation of their +industry and trade were more than offset by the privileges they enjoyed. +Still that is somewhat beside the point, for mere economic advantage is +not necessarily the determining factor in the fate of peoples. A +thousand circumstances had helped to develop on this continent a nation, +to inspire it with a passion for independence, and to prepare it for a +destiny greater than that of a prosperous dominion of the British +empire. The economists, who tried to prove by logic unassailable that +America would be richer under the British flag, could not change the +spirit of Patrick Henry, Samuel Adams, Benjamin Franklin, or George +Washington. + + +=References= + +G.L. Beer, _Origin of the British Colonial System_ and _The Old Colonial +System_. + +A. Bradley, _The Fight for Canada in North America_. + +C.M. Andrews, _Colonial Self-Government_ (American Nation Series). + +H. Egerton, _Short History of British Colonial Policy_. + +F. Parkman, _France and England in North America_ (12 vols.). + +R. Thwaites, _France in America_ (American Nation Series). + +J. Winsor, _The Mississippi Valley_ and _Cartier to Frontenac_. + + +=Questions= + +1. How would you define "nationalism"? + +2. Can you give any illustrations of the way that war promotes +nationalism? + +3. Why was it impossible to establish and maintain a uniform policy in +dealing with the Indians? + +4. What was the outcome of the final clash with the French? + +5. Enumerate the five chief results of the wars with the French and the +Indians. Discuss each in detail. + +6. Explain why it was that the character of the English king mattered to +the colonists. + +7. Contrast England under the Stuarts with England under the +Hanoverians. + +8. Explain how the English Crown, Courts, and Parliament controlled the +colonies. + +9. Name the three important classes of English legislation affecting the +colonies. Explain each. + +10. Do you think the English legislation was beneficial or injurious to +the colonies? Why? + + +=Research Topics= + +=Rise of French Power in North America.=--Special reference: Francis +Parkman, _Struggle for a Continent_. + +=The French and Indian Wars.=--Special reference: W.M. Sloane, _French +War and the Revolution_, Chaps. VI-IX. Parkman, _Montcalm and Wolfe_, +Vol. II, pp. 195-299. Elson, _History of the United States_, pp. +171-196. + +=English Navigation Acts.=--Macdonald, _Documentary Source Book_, pp. +55, 72, 78, 90, 103. Coman, _Industrial History_, pp. 79-85. + +=British Colonial Policy.=--Callender, _Economic History of the United +States_, pp. 102-108. + +=The New England Confederation.=--Analyze the document in Macdonald, +_Source Book_, p. 45. Special reference: Fiske, _Beginnings of New +England_, pp. 140-198. + +=The Administration of Andros.=--Fiske, _Beginnings_, pp. 242-278. + +=Biographical Studies.=--William Pitt and Sir Robert Walpole. Consult +Green, _Short History of England_, on their policies, using the index. + + + + +PART II. CONFLICT AND INDEPENDENCE + + + + +CHAPTER V + +THE NEW COURSE IN BRITISH IMPERIAL POLICY + + +On October 25, 1760, King George II died and the British crown passed to +his young grandson. The first George, the son of the Elector of Hanover +and Sophia the granddaughter of James I, was a thorough German who never +even learned to speak the language of the land over which he reigned. +The second George never saw England until he was a man. He spoke English +with an accent and until his death preferred his German home. During +their reign, the principle had become well established that the king did +not govern but acted only through ministers representing the majority in +Parliament. + + +GEORGE III AND HIS SYSTEM + +=The Character of the New King.=--The third George rudely broke the +German tradition of his family. He resented the imputation that he was a +foreigner and on all occasions made a display of his British sympathies. +To the draft of his first speech to Parliament, he added the popular +phrase: "Born and educated in this country, I glory in the name of +Briton." Macaulay, the English historian, certainly of no liking for +high royal prerogative, said of George: "The young king was a born +Englishman. All his tastes and habits, good and bad, were English. No +portion of his subjects had anything to reproach him with.... His age, +his appearance, and all that was known of his character conciliated +public favor. He was in the bloom of youth; his person and address were +pleasing; scandal imputed to him no vice; and flattery might without +glaring absurdity ascribe to him many princely virtues." + +Nevertheless George III had been spoiled by his mother, his tutors, and +his courtiers. Under their influence he developed high and mighty +notions about the sacredness of royal authority and his duty to check +the pretensions of Parliament and the ministers dependent upon it. His +mother had dinned into his ears the slogan: "George, be king!" Lord +Bute, his teacher and adviser, had told him that his honor required him +to take an active part in the shaping of public policy and the making of +laws. Thus educated, he surrounded himself with courtiers who encouraged +him in the determination to rule as well as reign, to subdue all +parties, and to place himself at the head of the nation and empire. + +[Illustration: _From an old print._ + +GEORGE III] + +=Political Parties and George III.=--The state of the political parties +favored the plans of the king to restore some of the ancient luster of +the crown. The Whigs, who were composed mainly of the smaller +freeholders, merchants, inhabitants of towns, and Protestant +non-conformists, had grown haughty and overbearing through long +continuance in power and had as a consequence raised up many enemies in +their own ranks. Their opponents, the Tories, had by this time given up +all hope of restoring to the throne the direct Stuart line; but they +still cherished their old notions about divine right. With the +accession of George III the coveted opportunity came to them to rally +around the throne again. George received his Tory friends with open +arms, gave them offices, and bought them seats in the House of Commons. + +=The British Parliamentary System.=--The peculiarities of the British +Parliament at the time made smooth the way for the king and his allies +with their designs for controlling the entire government. In the first +place, the House of Lords was composed mainly of hereditary nobles whose +number the king could increase by the appointment of his favorites, as +of old. Though the members of the House of Commons were elected by +popular vote, they did not speak for the mass of English people. Great +towns like Leeds, Manchester, and Birmingham, for example, had no +representatives at all. While there were about eight million inhabitants +in Great Britain, there were in 1768 only about 160,000 voters; that is +to say, only about one in every ten adult males had a voice in the +government. Many boroughs returned one or more members to the Commons +although they had merely a handful of voters or in some instances no +voters at all. Furthermore, these tiny boroughs were often controlled by +lords who openly sold the right of representation to the highest bidder. +The "rotten-boroughs," as they were called by reformers, were a public +scandal, but George III readily made use of them to get his friends into +the House of Commons. + + +GEORGE III'S MINISTERS AND THEIR COLONIAL POLICIES + +=Grenville and the War Debt.=--Within a year after the accession of +George III, William Pitt was turned out of office, the king treating him +with "gross incivility" and the crowds shouting "Pitt forever!" The +direction of affairs was entrusted to men enjoying the king's +confidence. Leadership in the House of Commons fell to George Grenville, +a grave and laborious man who for years had groaned over the increasing +cost of government. + +The first task after the conclusion of peace in 1763 was the adjustment +of the disordered finances of the kingdom. The debt stood at the highest +point in the history of the country. More revenue was absolutely +necessary and Grenville began to search for it, turning his attention +finally to the American colonies. In this quest he had the aid of a +zealous colleague, Charles Townshend, who had long been in public +service and was familiar with the difficulties encountered by royal +governors in America. These two men, with the support of the entire +ministry, inaugurated in February, 1763, "a new system of colonial +government. It was announced by authority that there were to be no more +requisitions from the king to the colonial assemblies for supplies, but +that the colonies were to be taxed instead by act of Parliament. +Colonial governors and judges were to be paid by the Crown; they were to +be supported by a standing army of twenty regiments; and all the +expenses of this force were to be met by parliamentary taxation." + +=Restriction of Paper Money (1763).=--Among the many complaints filed +before the board of trade were vigorous protests against the issuance of +paper money by the colonial legislatures. The new ministry provided a +remedy in the act of 1763, which declared void all colonial laws +authorizing paper money or extending the life of outstanding bills. This +law was aimed at the "cheap money" which the Americans were fond of +making when specie was scarce--money which they tried to force on their +English creditors in return for goods and in payment of the interest and +principal of debts. Thus the first chapter was written in the long +battle over sound money on this continent. + +=Limitation on Western Land Sales.=--Later in the same year (1763) +George III issued a royal proclamation providing, among other things, +for the government of the territory recently acquired by the treaty of +Paris from the French. One of the provisions in this royal decree +touched frontiersmen to the quick. The contests between the king's +officers and the colonists over the disposition of western lands had +been long and sharp. The Americans chafed at restrictions on +settlement. The more adventurous were continually moving west and +"squatting" on land purchased from the Indians or simply seized without +authority. To put an end to this, the king forbade all further purchases +from the Indians, reserving to the crown the right to acquire such lands +and dispose of them for settlement. A second provision in the same +proclamation vested the power of licensing trade with the Indians, +including the lucrative fur business, in the hands of royal officers in +the colonies. These two limitations on American freedom and enterprise +were declared to be in the interest of the crown and for the +preservation of the rights of the Indians against fraud and abuses. + +=The Sugar Act of 1764.=--King George's ministers next turned their +attention to measures of taxation and trade. Since the heavy debt under +which England was laboring had been largely incurred in the defense of +America, nothing seemed more reasonable to them than the proposition +that the colonies should help to bear the burden which fell so heavily +upon the English taxpayer. The Sugar Act of 1764 was the result of this +reasoning. There was no doubt about the purpose of this law, for it was +set forth clearly in the title: "An act for granting certain duties in +the British colonies and plantations in America ... for applying the +produce of such duties ... towards defraying the expenses of defending, +protecting and securing the said colonies and plantations ... and for +more effectually preventing the clandestine conveyance of goods to and +from the said colonies and plantations and improving and securing the +trade between the same and Great Britain." The old Molasses Act had been +prohibitive; the Sugar Act of 1764 was clearly intended as a revenue +measure. Specified duties were laid upon sugar, indigo, calico, silks, +and many other commodities imported into the colonies. The enforcement +of the Molasses Act had been utterly neglected; but this Sugar Act had +"teeth in it." Special precautions as to bonds, security, and +registration of ship masters, accompanied by heavy penalties, promised +a vigorous execution of the new revenue law. + +The strict terms of the Sugar Act were strengthened by administrative +measures. Under a law of the previous year the commanders of armed +vessels stationed along the American coast were authorized to stop, +search, and, on suspicion, seize merchant ships approaching colonial +ports. By supplementary orders, the entire British official force in +America was instructed to be diligent in the execution of all trade and +navigation laws. Revenue collectors, officers of the army and navy, and +royal governors were curtly ordered to the front to do their full duty +in the matter of law enforcement. The ordinary motives for the discharge +of official obligations were sharpened by an appeal to avarice, for +naval officers who seized offenders against the law were rewarded by +large prizes out of the forfeitures and penalties. + +=The Stamp Act (1765).=--The Grenville-Townshend combination moved +steadily towards its goal. While the Sugar Act was under consideration +in Parliament, Grenville announced a plan for a stamp bill. The next +year it went through both Houses with a speed that must have astounded +its authors. The vote in the Commons stood 205 in favor to 49 against; +while in the Lords it was not even necessary to go through the formality +of a count. As George III was temporarily insane, the measure received +royal assent by a commission acting as a board of regency. Protests of +colonial agents in London were futile. "We might as well have hindered +the sun's progress!" exclaimed Franklin. Protests of a few opponents in +the Commons were equally vain. The ministry was firm in its course and +from all appearances the Stamp Act hardly roused as much as a languid +interest in the city of London. In fact, it is recorded that the fateful +measure attracted less notice than a bill providing for a commission to +act for the king when he was incapacitated. + +The Stamp Act, like the Sugar Act, declared the purpose of the British +government to raise revenue in America "towards defraying the expenses +of defending, protecting, and securing the British colonies and +plantations in America." It was a long measure of more than fifty +sections, carefully planned and skillfully drawn. By its provisions +duties were imposed on practically all papers used in legal +transactions,--deeds, mortgages, inventories, writs, bail bonds,--on +licenses to practice law and sell liquor, on college diplomas, playing +cards, dice, pamphlets, newspapers, almanacs, calendars, and +advertisements. The drag net was closely knit, for scarcely anything +escaped. + +=The Quartering Act (1765).=--The ministers were aware that the Stamp +Act would rouse opposition in America--how great they could not +conjecture. While the measure was being debated, a friend of General +Wolfe, Colonel Barre, who knew America well, gave them an ominous +warning in the Commons. "Believe me--remember I this day told you so--" +he exclaimed, "the same spirit of freedom which actuated that people at +first will accompany them still ... a people jealous of their liberties +and who will vindicate them, if ever they should be violated." The +answer of the ministry to a prophecy of force was a threat of force. +Preparations were accordingly made to dispatch a larger number of +soldiers than usual to the colonies, and the ink was hardly dry on the +Stamp Act when Parliament passed the Quartering Act ordering the +colonists to provide accommodations for the soldiers who were to enforce +the new laws. "We have the power to tax them," said one of the ministry, +"and we will tax them." + + +COLONIAL RESISTANCE FORCES REPEAL + +=Popular Opposition.=--The Stamp Act was greeted in America by an +outburst of denunciation. The merchants of the seaboard cities took the +lead in making a dignified but unmistakable protest, agreeing not to +import British goods while the hated law stood upon the books. Lawyers, +some of them incensed at the heavy taxes on their operations and others +intimidated by patriots who refused to permit them to use stamped +papers, joined with the merchants. Aristocratic colonial Whigs, who had +long grumbled at the administration of royal governors, protested +against taxation without their consent, as the Whigs had done in old +England. There were Tories, however, in the colonies as in England--many +of them of the official class--who denounced the merchants, lawyers, and +Whig aristocrats as "seditious, factious and republican." Yet the +opposition to the Stamp Act and its accompanying measure, the Quartering +Act, grew steadily all through the summer of 1765. + +In a little while it was taken up in the streets and along the +countryside. All through the North and in some of the Southern colonies, +there sprang up, as if by magic, committees and societies pledged to +resist the Stamp Act to the bitter end. These popular societies were +known as Sons of Liberty and Daughters of Liberty: the former including +artisans, mechanics, and laborers; and the latter, patriotic women. Both +groups were alike in that they had as yet taken little part in public +affairs. Many artisans, as well as all the women, were excluded from the +right to vote for colonial assemblymen. + +While the merchants and Whig gentlemen confined their efforts chiefly to +drafting well-phrased protests against British measures, the Sons of +Liberty operated in the streets and chose rougher measures. They stirred +up riots in Boston, New York, Philadelphia, and Charleston when attempts +were made to sell the stamps. They sacked and burned the residences of +high royal officers. They organized committees of inquisition who by +threats and intimidation curtailed the sale of British goods and the use +of stamped papers. In fact, the Sons of Liberty carried their operations +to such excesses that many mild opponents of the stamp tax were +frightened and drew back in astonishment at the forces they had +unloosed. The Daughters of Liberty in a quieter way were making a very +effective resistance to the sale of the hated goods by spurring on +domestic industries, their own particular province being the manufacture +of clothing, and devising substitutes for taxed foods. They helped to +feed and clothe their families without buying British goods. + +=Legislative Action against the Stamp Act.=--Leaders in the colonial +assemblies, accustomed to battle against British policies, supported the +popular protest. The Stamp Act was signed on March 22, 1765. On May 30, +the Virginia House of Burgesses passed a set of resolutions declaring +that the General Assembly of the colony alone had the right to lay taxes +upon the inhabitants and that attempts to impose them otherwise were +"illegal, unconstitutional, and unjust." It was in support of these +resolutions that Patrick Henry uttered the immortal challenge: "Caesar +had his Brutus, Charles I his Cromwell, and George III...." Cries of +"Treason" were calmly met by the orator who finished: "George III may +profit by their example. If that be treason, make the most of it." + +[Illustration: PATRICK HENRY] + +=The Stamp Act Congress.=--The Massachusetts Assembly answered the call +of Virginia by inviting the colonies to elect delegates to a Congress to +be held in New York to discuss the situation. Nine colonies responded +and sent representatives. The delegates, while professing the warmest +affection for the king's person and government, firmly spread on record +a series of resolutions that admitted of no double meaning. They +declared that taxes could not be imposed without their consent, given +through their respective colonial assemblies; that the Stamp Act showed +a tendency to subvert their rights and liberties; that the recent trade +acts were burdensome and grievous; and that the right to petition the +king and Parliament was their heritage. They thereupon made "humble +supplication" for the repeal of the Stamp Act. + +The Stamp Act Congress was more than an assembly of protest. It marked +the rise of a new agency of government to express the will of America. +It was the germ of a government which in time was to supersede the +government of George III in the colonies. It foreshadowed the Congress +of the United States under the Constitution. It was a successful attempt +at union. "There ought to be no New England men," declared Christopher +Gadsden, in the Stamp Act Congress, "no New Yorkers known on the +Continent, but all of us Americans." + +=The Repeal of the Stamp Act and the Sugar Act.=--The effect of American +resistance on opinion in England was telling. Commerce with the colonies +had been effectively boycotted by the Americans; ships lay idly swinging +at the wharves; bankruptcy threatened hundreds of merchants in London, +Bristol, and Liverpool. Workingmen in the manufacturing towns of England +were thrown out of employment. The government had sown folly and was +reaping, in place of the coveted revenue, rebellion. + +Perplexed by the storm they had raised, the ministers summoned to the +bar of the House of Commons, Benjamin Franklin, the agent for +Pennsylvania, who was in London. "Do you think it right," asked +Grenville, "that America should be protected by this country and pay no +part of the expenses?" The answer was brief: "That is not the case; the +colonies raised, clothed, and paid during the last war twenty-five +thousand men and spent many millions." Then came an inquiry whether the +colonists would accept a modified stamp act. "No, never," replied +Franklin, "never! They will never submit to it!" It was next suggested +that military force might compel obedience to law. Franklin had a ready +answer. "They cannot force a man to take stamps.... They may not find a +rebellion; they may, indeed, make one." + +The repeal of the Stamp Act was moved in the House of Commons a few days +later. The sponsor for the repeal spoke of commerce interrupted, debts +due British merchants placed in jeopardy, Manchester industries closed, +workingmen unemployed, oppression instituted, and the loss of the +colonies threatened. Pitt and Edmund Burke, the former near the close +of his career, the latter just beginning his, argued cogently in favor +of retracing the steps taken the year before. Grenville refused. +"America must learn," he wailed, "that prayers are not to be brought to +Caesar through riot and sedition." His protests were idle. The Commons +agreed to the repeal on February 22, 1766, amid the cheers of the +victorious majority. It was carried through the Lords in the face of +strong opposition and, on March 18, reluctantly signed by the king, now +restored to his right mind. + +In rescinding the Stamp Act, Parliament did not admit the contention of +the Americans that it was without power to tax them. On the contrary, it +accompanied the repeal with a Declaratory Act. It announced that the +colonies were subordinate to the crown and Parliament of Great Britain; +that the king and Parliament therefore had undoubted authority to make +laws binding the colonies in all cases whatsoever; and that the +resolutions and proceedings of the colonists denying such authority were +null and void. + +The repeal was greeted by the colonists with great popular +demonstrations. Bells were rung; toasts to the king were drunk; and +trade resumed its normal course. The Declaratory Act, as a mere paper +resolution, did not disturb the good humor of those who again cheered +the name of King George. Their confidence was soon strengthened by the +news that even the Sugar Act had been repealed, thus practically +restoring the condition of affairs before Grenville and Townshend +inaugurated their policy of "thoroughness." + + +RESUMPTION OF BRITISH REVENUE AND COMMERCIAL POLICIES + +=The Townshend Acts (1767).=--The triumph of the colonists was brief. +Though Pitt, the friend of America, was once more prime minister, and +seated in the House of Lords as the Earl of Chatham, his severe illness +gave to Townshend and the Tory party practical control over Parliament. +Unconvinced by the experience with the Stamp Act, Townshend brought +forward and pushed through both Houses of Parliament three measures, +which to this day are associated with his name. First among his +restrictive laws was that of June 29, 1767, which placed the enforcement +of the collection of duties and customs on colonial imports and exports +in the hands of British commissioners appointed by the king, resident in +the colonies, paid from the British treasury, and independent of all +control by the colonists. The second measure of the same date imposed a +tax on lead, glass, paint, tea, and a few other articles imported into +the colonies, the revenue derived from the duties to be applied toward +the payment of the salaries and other expenses of royal colonial +officials. A third measure was the Tea Act of July 2, 1767, aimed at the +tea trade which the Americans carried on illegally with foreigners. This +law abolished the duty which the East India Company had to pay in +England on tea exported to America, for it was thought that English tea +merchants might thus find it possible to undersell American tea +smugglers. + +=Writs of Assistance Legalized by Parliament.=--Had Parliament been +content with laying duties, just as a manifestation of power and right, +and neglected their collection, perhaps little would have been heard of +the Townshend Acts. It provided, however, for the strict, even the +harsh, enforcement of the law. It ordered customs officers to remain at +their posts and put an end to smuggling. In the revenue act of June 29, +1767, it expressly authorized the superior courts of the colonies to +issue "writs of assistance," empowering customs officers to enter "any +house, warehouse, shop, cellar, or other place in the British colonies +or plantations in America to search for and seize" prohibited or +smuggled goods. + +The writ of assistance, which was a general search warrant issued to +revenue officers, was an ancient device hateful to a people who +cherished the spirit of personal independence and who had made actual +gains in the practice of civil liberty. To allow a "minion of the law" +to enter a man's house and search his papers and premises, was too much +for the emotions of people who had fled to America in a quest for +self-government and free homes, who had braved such hardships to +establish them, and who wanted to trade without official interference. + +The writ of assistance had been used in Massachusetts in 1755 to prevent +illicit trade with Canada and had aroused a violent hostility at that +time. In 1761 it was again the subject of a bitter controversy which +arose in connection with the application of a customs officer to a +Massachusetts court for writs of assistance "as usual." This application +was vainly opposed by James Otis in a speech of five hours' duration--a +speech of such fire and eloquence that it sent every man who heard it +away "ready to take up arms against writs of assistance." Otis denounced +the practice as an exercise of arbitrary power which had cost one king +his head and another his throne, a tyrant's device which placed the +liberty of every man in jeopardy, enabling any petty officer to work +possible malice on any innocent citizen on the merest suspicion, and to +spread terror and desolation through the land. "What a scene," he +exclaimed, "does this open! Every man, prompted by revenge, ill-humor, +or wantonness to inspect the inside of his neighbor's house, may get a +writ of assistance. Others will ask it from self-defense; one arbitrary +exertion will provoke another until society is involved in tumult and +blood." He did more than attack the writ itself. He said that Parliament +could not establish it because it was against the British constitution. +This was an assertion resting on slender foundation, but it was quickly +echoed by the people. Then and there James Otis sounded the call to +America to resist the exercise of arbitrary power by royal officers. +"Then and there," wrote John Adams, "the child Independence was born." +Such was the hated writ that Townshend proposed to put into the hands of +customs officers in his grim determination to enforce the law. + +=The New York Assembly Suspended.=--In the very month that Townshend's +Acts were signed by the king, Parliament took a still more drastic step. +The assembly of New York, protesting against the "ruinous and +insupportable" expense involved, had failed to make provision for the +care of British troops in accordance with the terms of the Quartering +Act. Parliament therefore suspended the assembly until it promised to +obey the law. It was not until a third election was held that compliance +with the Quartering Act was wrung from the reluctant province. In the +meantime, all the colonies had learned on how frail a foundation their +representative bodies rested. + + +RENEWED RESISTANCE IN AMERICA + +=The Massachusetts Circular (1768).=--Massachusetts, under the +leadership of Samuel Adams, resolved to resist the policy of renewed +intervention in America. At his suggestion the assembly adopted a +Circular Letter addressed to the assemblies of the other colonies +informing them of the state of affairs in Massachusetts and roundly +condemning the whole British program. The Circular Letter declared that +Parliament had no right to lay taxes on Americans without their consent +and that the colonists could not, from the nature of the case, be +represented in Parliament. It went on shrewdly to submit to +consideration the question as to whether any people could be called free +who were subjected to governors and judges appointed by the crown and +paid out of funds raised independently. It invited the other colonies, +in the most temperate tones, to take thought about the common +predicament in which they were all placed. + +[Illustration: _From an old print._ + +SAMUEL ADAMS] + +=The Dissolution of Assemblies.=--The governor of Massachusetts, hearing +of the Circular Letter, ordered the assembly to rescind its appeal. On +meeting refusal, he promptly dissolved it. The Maryland, Georgia, and +South Carolina assemblies indorsed the Circular Letter and were also +dissolved at once. The Virginia House of Burgesses, thoroughly aroused, +passed resolutions on May 16, 1769, declaring that the sole right of +imposing taxes in Virginia was vested in its legislature, asserting anew +the right of petition to the crown, condemning the transportation of +persons accused of crimes or trial beyond the seas, and beseeching the +king for a redress of the general grievances. The immediate dissolution +of the Virginia assembly, in its turn, was the answer of the royal +governor. + +=The Boston Massacre.=--American opposition to the British authorities +kept steadily rising as assemblies were dissolved, the houses of +citizens searched, and troops distributed in increasing numbers among +the centers of discontent. Merchants again agreed not to import British +goods, the Sons of Liberty renewed their agitation, and women set about +the patronage of home products still more loyally. + +On the night of March 5, 1770, a crowd on the streets of Boston began to +jostle and tease some British regulars stationed in the town. Things +went from bad to worse until some "boys and young fellows" began to +throw snowballs and stones. Then the exasperated soldiers fired into the +crowd, killing five and wounding half a dozen more. The day after the +"massacre," a mass meeting was held in the town and Samuel Adams was +sent to demand the withdrawal of the soldiers. The governor hesitated +and tried to compromise. Finding Adams relentless, the governor yielded +and ordered the regulars away. + +The Boston Massacre stirred the country from New Hampshire to Georgia. +Popular passions ran high. The guilty soldiers were charged with murder. +Their defense was undertaken, in spite of the wrath of the populace, by +John Adams and Josiah Quincy, who as lawyers thought even the worst + +offenders entitled to their full rights in law. In his speech to the +jury, however, Adams warned the British government against its course, +saying, that "from the nature of things soldiers quartered in a populous +town will always occasion two mobs where they will prevent one." Two of +the soldiers were convicted and lightly punished. + +=Resistance in the South.=--The year following the Boston Massacre some +citizens of North Carolina, goaded by the conduct of the royal governor, +openly resisted his authority. Many were killed as a result and seven +who were taken prisoners were hanged as traitors. A little later royal +troops and local militia met in a pitched battle near Alamance River, +called the "Lexington of the South." + +=The _Gaspee_ Affair and the Virginia Resolutions of 1773.=--On sea as +well as on land, friction between the royal officers and the colonists +broke out into overt acts. While patrolling Narragansett Bay looking for +smugglers one day in 1772, the armed ship, _Gaspee_, ran ashore and was +caught fast. During the night several men from Providence boarded the +vessel and, after seizing the crew, set it on fire. A royal commission, +sent to Rhode Island to discover the offenders and bring them to +account, failed because it could not find a single informer. The very +appointment of such a commission aroused the patriots of Virginia to +action; and in March, 1773, the House of Burgesses passed a resolution +creating a standing committee of correspondence to develop cooperation +among the colonies in resistance to British measures. + +=The Boston Tea Party.=--Although the British government, finding the +Townshend revenue act a failure, repealed in 1770 all the duties except +that on tea, it in no way relaxed its resolve to enforce the other +commercial regulations it had imposed on the colonies. Moreover, +Parliament decided to relieve the British East India Company of the +financial difficulties into which it had fallen partly by reason of the +Tea Act and the colonial boycott that followed. In 1773 it agreed to +return to the Company the regular import duties, levied in England, on +all tea transshipped to America. A small impost of three pence, to be +collected in America, was left as a reminder of the principle laid down +in the Declaratory Act that Parliament had the right to tax the +colonists. + +This arrangement with the East India Company was obnoxious to the +colonists for several reasons. It was an act of favoritism for one +thing, in the interest of a great monopoly. For another thing, it +promised to dump on the American market, suddenly, an immense amount of +cheap tea and so cause heavy losses to American merchants who had large +stocks on hand. It threatened with ruin the business of all those who +were engaged in clandestine trade with the Dutch. It carried with it an +irritating tax of three pence on imports. In Charleston, Annapolis, New +York, and Boston, captains of ships who brought tea under this act were +roughly handled. One night in December, 1773, a band of Boston citizens, +disguised as Indians, boarded the hated tea ships and dumped the cargo +into the harbor. This was serious business, for it was open, flagrant, +determined violation of the law. As such the British government viewed +it. + + +RETALIATION BY THE BRITISH GOVERNMENT + +=Reception of the News of the Tea Riot.=--The news of the tea riot in +Boston confirmed King George in his conviction that there should be no +soft policy in dealing with his American subjects. "The die is cast," he +stated with evident satisfaction. "The colonies must either triumph or +submit.... If we take the resolute part, they will undoubtedly be very +meek." Lord George Germain characterized the tea party as "the +proceedings of a tumultuous and riotous rabble who ought, if they had +the least prudence, to follow their mercantile employments and not +trouble themselves with politics and government, which they do not +understand." This expressed, in concise form, exactly the sentiments of +Lord North, who had then for three years been the king's chief minister. +Even Pitt, Lord Chatham, was prepared to support the government in +upholding its authority. + +=The Five Intolerable Acts.=--Parliament, beginning on March 31, 1774, +passed five stringent measures, known in American history as the five +"intolerable acts." They were aimed at curing the unrest in America. The +_first_ of them was a bill absolutely shutting the port of Boston to +commerce with the outside world. The _second_, following closely, +revoked the Massachusetts charter of 1691 and provided furthermore that +the councilors should be appointed by the king, that all judges should +be named by the royal governor, and that town meetings (except to elect +certain officers) could not be held without the governor's consent. A +_third_ measure, after denouncing the "utter subversion of all lawful +government" in the provinces, authorized royal agents to transfer to +Great Britain or to other colonies the trials of officers or other +persons accused of murder in connection with the enforcement of the law. +The _fourth_ act legalized the quartering of troops in Massachusetts +towns. The _fifth_ of the measures was the Quebec Act, which granted +religious toleration to the Catholics in Canada, extended the boundaries +of Quebec southward to the Ohio River, and established, in this western +region, government by a viceroy. + +The intolerable acts went through Parliament with extraordinary +celerity. There was an opposition, alert and informed; but it was +ineffective. Burke spoke eloquently against the Boston port bill, +condemning it roundly for punishing the innocent with the guilty, and +showing how likely it was to bring grave consequences in its train. He +was heard with respect and his pleas were rejected. The bill passed both +houses without a division, the entry "unanimous" being made upon their +journals although it did not accurately represent the state of opinion. +The law destroying the charter of Massachusetts passed the Commons by a +vote of three to one; and the third intolerable act by a vote of four to +one. The triumph of the ministry was complete. "What passed in Boston," +exclaimed the great jurist, Lord Mansfield, "is the overt act of High +Treason proceeding from our over lenity and want of foresight." The +crown and Parliament were united in resorting to punitive measures. + +In the colonies the laws were received with consternation. To the +American Protestants, the Quebec Act was the most offensive. That +project they viewed not as an act of grace or of mercy but as a direct +attempt to enlist French Canadians on the side of Great Britain. The +British government did not grant religious toleration to Catholics +either at home or in Ireland and the Americans could see no good motive +in granting it in North America. The act was also offensive because +Massachusetts, Connecticut, and Virginia had, under their charters, +large claims in the territory thus annexed to Quebec. + +To enforce these intolerable acts the military arm of the British +government was brought into play. The commander-in-chief of the armed +forces in America, General Gage, was appointed governor of +Massachusetts. Reinforcements were brought to the colonies, for now King +George was to give "the rebels," as he called them, a taste of strong +medicine. The majesty of his law was to be vindicated by force. + + +FROM REFORM TO REVOLUTION IN AMERICA + +=The Doctrine of Natural Rights.=--The dissolution of assemblies, the +destruction of charters, and the use of troops produced in the colonies +a new phase in the struggle. In the early days of the contest with the +British ministry, the Americans spoke of their "rights as Englishmen" +and condemned the acts of Parliament as unlawful, as violating the +principles of the English constitution under which they all lived. When +they saw that such arguments had no effect on Parliament, they turned +for support to their "natural rights." The latter doctrine, in the form +in which it was employed by the colonists, was as English as the +constitutional argument. John Locke had used it with good effect in +defense of the English revolution in the seventeenth century. American +leaders, familiar with the writings of Locke, also took up his thesis in +the hour of their distress. They openly declared that their rights did +not rest after all upon the English constitution or a charter from the +crown. "Old Magna Carta was not the beginning of all things," retorted +Otis when the constitutional argument failed. "A time may come when +Parliament shall declare every American charter void, but the natural, +inherent, and inseparable rights of the colonists as men and as citizens +would remain and whatever became of charters can never be abolished +until the general conflagration." Of the same opinion was the young and +impetuous Alexander Hamilton. "The sacred rights of mankind," he +exclaimed, "are not to be rummaged for among old parchments or musty +records. They are written as with a sunbeam in the whole volume of human +destiny by the hand of divinity itself, and can never be erased or +obscured by mortal power." + +Firm as the American leaders were in the statement and defense of their +rights, there is every reason for believing that in the beginning they +hoped to confine the conflict to the realm of opinion. They constantly +avowed that they were loyal to the king when protesting in the strongest +language against his policies. Even Otis, regarded by the loyalists as a +firebrand, was in fact attempting to avert revolution by winning +concessions from England. "I argue this cause with the greater +pleasure," he solemnly urged in his speech against the writs of +assistance, "as it is in favor of British liberty ... and as it is in +opposition to a kind of power, the exercise of which in former periods +cost one king of England his head and another his throne." + +=Burke Offers the Doctrine of Conciliation.=--The flooding tide of +American sentiment was correctly measured by one Englishman at least, +Edmund Burke, who quickly saw that attempts to restrain the rise of +American democracy were efforts to reverse the processes of nature. He +saw how fixed and rooted in the nature of things was the American +spirit--how inevitable, how irresistible. He warned his countrymen that +there were three ways of handling the delicate situation--and only +three. One was to remove the cause of friction by changing the spirit of +the colonists--an utter impossibility because that spirit was grounded +in the essential circumstances of American life. The second was to +prosecute American leaders as criminals; of this he begged his +countrymen to beware lest the colonists declare that "a government +against which a claim of liberty is tantamount to high treason is a +government to which submission is equivalent to slavery." The third and +right way to meet the problem, Burke concluded, was to accept the +American spirit, repeal the obnoxious measures, and receive the colonies +into equal partnership. + +=Events Produce the Great Decision.=--The right way, indicated by Burke, +was equally impossible to George III and the majority in Parliament. To +their narrow minds, American opinion was contemptible and American +resistance unlawful, riotous, and treasonable. The correct way, in their +view, was to dispatch more troops to crush the "rebels"; and that very +act took the contest from the realm of opinion. As John Adams said: +"Facts are stubborn things." Opinions were unseen, but marching soldiers +were visible to the veriest street urchin. "Now," said Gouverneur +Morris, "the sheep, simple as they are, cannot be gulled as heretofore." +It was too late to talk about the excellence of the British +constitution. If any one is bewildered by the controversies of modern +historians as to why the crisis came at last, he can clarify his +understanding by reading again Edmund Burke's stately oration, _On +Conciliation with America_. + + +=References= + +G.L. Beer, _British Colonial Policy_ (1754-63). + +E. Channing, _History of the United States_, Vol. III. + +R. Frothingham, _Rise of the Republic_. + +G.E. Howard, _Preliminaries of the Revolution_ (American Nation Series). + +J.K. Hosmer, _Samuel Adams_. + +J.T. Morse, _Benjamin Franklin_. + +M.C. Tyler, _Patrick Henry_. + +J.A. Woodburn (editor), _The American Revolution_ (Selections from the +English work by Lecky). + + +=Questions= + +1. Show how the character of George III made for trouble with the +colonies. + +2. Explain why the party and parliamentary systems of England favored +the plans of George III. + +3. How did the state of English finances affect English policy? + +4. Enumerate five important measures of the English government affecting +the colonies between 1763 and 1765. Explain each in detail. + +5. Describe American resistance to the Stamp Act. What was the outcome? + +6. Show how England renewed her policy of regulation in 1767. + +7. Summarize the events connected with American resistance. + +8. With what measures did Great Britain retaliate? + +9. Contrast "constitutional" with "natural" rights. + +10. What solution did Burke offer? Why was it rejected? + + +=Research Topics= + +=Powers Conferred on Revenue Officers by Writs of Assistance.=--See a +writ in Macdonald, _Source Book_, p. 109. + +=The Acts of Parliament Respecting America.=--Macdonald, pp. 117-146. +Assign one to each student for report and comment. + +=Source Studies on the Stamp Act.=--Hart, _American History Told by +Contemporaries_, Vol. II, pp. 394-412. + +=Source Studies of the Townshend Acts.=--Hart, Vol. II, pp. 413-433. + +=American Principles.=--Prepare a table of them from the Resolutions of +the Stamp Act Congress and the Massachusetts Circular. Macdonald, pp. +136-146. + +=An English Historian's View of the Period.=--Green, _Short History of +England_, Chap. X. + +=English Policy Not Injurious to America.=--Callender, _Economic +History_, pp. 85-121. + +=A Review of English Policy.=--Woodrow Wilson, _History of the American +People_, Vol. II, pp. 129-170. + +=The Opening of the Revolution.=--Elson, _History of the United States_, +pp. 220-235. + + + + +CHAPTER VI + +THE AMERICAN REVOLUTION + + +RESISTANCE AND RETALIATION + +=The Continental Congress.=--When the news of the "intolerable acts" +reached America, every one knew what strong medicine Parliament was +prepared to administer to all those who resisted its authority. The +cause of Massachusetts became the cause of all the colonies. Opposition +to British policy, hitherto local and spasmodic, now took on a national +character. To local committees and provincial conventions was added a +Continental Congress, appropriately called by Massachusetts on June 17, +1774, at the instigation of Samuel Adams. The response to the summons +was electric. By hurried and irregular methods delegates were elected +during the summer, and on September 5 the Congress duly assembled in +Carpenter's Hall in Philadelphia. Many of the greatest men in America +were there--George Washington and Patrick Henry from Virginia and John +and Samuel Adams from Massachusetts. Every shade of opinion was +represented. Some were impatient with mild devices; the majority favored +moderation. + +The Congress drew up a declaration of American rights and stated in +clear and dignified language the grievances of the colonists. It +approved the resistance to British measures offered by Massachusetts and +promised the united support of all sections. It prepared an address to +King George and another to the people of England, disavowing the idea of +independence but firmly attacking the policies pursued by the British +government. + +=The Non-Importation Agreement.=--The Congress was not content, however, +with professions of faith and with petitions. It took one revolutionary +step. It agreed to stop the importation of British goods into America, +and the enforcement of this agreement it placed in the hands of local +"committees of safety and inspection," to be elected by the qualified +voters. The significance of this action is obvious. Congress threw +itself athwart British law. It made a rule to bind American citizens and +to be carried into effect by American officers. It set up a state within +the British state and laid down a test of allegiance to the new order. +The colonists, who up to this moment had been wavering, had to choose +one authority or the other. They were for the enforcement of the +non-importation agreement or they were against it. They either bought +English goods or they did not. In the spirit of the toast--"May Britain +be wise and America be free"--the first Continental Congress adjourned +in October, having appointed the tenth of May following for the meeting +of a second Congress, should necessity require. + +=Lord North's "Olive Branch."=--When the news of the action of the +American Congress reached England, Pitt and Burke warmly urged a repeal +of the obnoxious laws, but in vain. All they could wring from the prime +minister, Lord North, was a set of "conciliatory resolutions" proposing +to relieve from taxation any colony that would assume its share of +imperial defense and make provision for supporting the local officers of +the crown. This "olive branch" was accompanied by a resolution assuring +the king of support at all hazards in suppressing the rebellion and by +the restraining act of March 30, 1775, which in effect destroyed the +commerce of New England. + +=Bloodshed at Lexington and Concord (April 19, 1775).=--Meanwhile the +British authorities in Massachusetts relaxed none of their efforts in +upholding British sovereignty. General Gage, hearing that military +stores had been collected at Concord, dispatched a small force to seize +them. By this act he precipitated the conflict he had sought to avoid. +At Lexington, on the road to Concord, occurred "the little thing" that +produced "the great event." An unexpected collision beyond the thought +or purpose of any man had transferred the contest from the forum to the +battle field. + +=The Second Continental Congress.=--Though blood had been shed and war +was actually at hand, the second Continental Congress, which met at +Philadelphia in May, 1775, was not yet convinced that conciliation was +beyond human power. It petitioned the king to interpose on behalf of the +colonists in order that the empire might avoid the calamities of civil +war. On the last day of July, it made a temperate but firm answer to +Lord North's offer of conciliation, stating that the proposal was +unsatisfactory because it did not renounce the right to tax or repeal +the offensive acts of Parliament. + +=Force, the British Answer.=--Just as the representatives of America +were about to present the last petition of Congress to the king on +August 23, 1775, George III issued a proclamation of rebellion. This +announcement declared that the colonists, "misled by dangerous and +ill-designing men," were in a state of insurrection; it called on the +civil and military powers to bring "the traitors to justice"; and it +threatened with "condign punishment the authors, perpetrators, and +abettors of such traitorous designs." It closed with the usual prayer: +"God, save the king." Later in the year, Parliament passed a sweeping +act destroying all trade and intercourse with America. Congress was +silent at last. Force was also America's answer. + + +AMERICAN INDEPENDENCE + +=Drifting into War.=--Although the Congress had not given up all hope of +reconciliation in the spring and summer of 1775, it had firmly resolved +to defend American rights by arms if necessary. It transformed the +militiamen who had assembled near Boston, after the battle of Lexington, +into a Continental army and selected Washington as commander-in-chief. +It assumed the powers of a government and prepared to raise money, wage +war, and carry on diplomatic relations with foreign countries. + +[Illustration: _From an old print_ + +SPIRIT OF 1776] + +Events followed thick and fast. On June 17, the American militia, by +the stubborn defense of Bunker Hill, showed that it could make British +regulars pay dearly for all they got. On July 3, Washington took command +of the army at Cambridge. In January, 1776, after bitter disappointments +in drumming up recruits for its army in England, Scotland, and Ireland, +the British government concluded a treaty with the Landgrave of +Hesse-Cassel in Germany contracting, at a handsome figure, for thousands +of soldiers and many pieces of cannon. This was the crowning insult to +America. Such was the view of all friends of the colonies on both sides +of the water. Such was, long afterward, the judgment of the conservative +historian Lecky: "The conduct of England in hiring German mercenaries to +subdue the essentially English population beyond the Atlantic made +reconciliation hopeless and independence inevitable." The news of this +wretched transaction in German soldiers had hardly reached America +before there ran all down the coast the thrilling story that Washington +had taken Boston, on March 17, 1776, compelling Lord Howe to sail with +his entire army for Halifax. + +=The Growth of Public Sentiment in Favor of Independence.=--Events were +bearing the Americans away from their old position under the British +constitution toward a final separation. Slowly and against their +desires, prudent and honorable men, who cherished the ties that united +them to the old order and dreaded with genuine horror all thought of +revolution, were drawn into the path that led to the great decision. In +all parts of the country and among all classes, the question of the hour +was being debated. "American independence," as the historian Bancroft +says, "was not an act of sudden passion nor the work of one man or one +assembly. It had been discussed in every part of the country by farmers +and merchants, by mechanics and planters, by the fishermen along the +coast and the backwoodsmen of the West; in town meetings and from the +pulpit; at social gatherings and around the camp fires; in county +conventions and conferences or committees; in colonial congresses and +assemblies." + +[Illustration: _From an old print_ + +THOMAS PAINE] + +=Paine's "Commonsense."=--In the midst of this ferment of American +opinion, a bold and eloquent pamphleteer broke in upon the hesitating +public with a program for absolute independence, without fears and +without apologies. In the early days of 1776, Thomas Paine issued the +first of his famous tracts, "Commonsense," a passionate attack upon the +British monarchy and an equally passionate plea for American liberty. +Casting aside the language of petition with which Americans had hitherto +addressed George III, Paine went to the other extreme and assailed him +with many a violent epithet. He condemned monarchy itself as a system +which had laid the world "in blood and ashes." Instead of praising the +British constitution under which colonists had been claiming their +rights, he brushed it aside as ridiculous, protesting that it was "owing +to the constitution of the people, not to the constitution of the +government, that the Crown is not as oppressive in England as in +Turkey." + +Having thus summarily swept away the grounds of allegiance to the old +order, Paine proceeded relentlessly to an argument for immediate +separation from Great Britain. There was nothing in the sphere of +practical interest, he insisted, which should bind the colonies to the +mother country. Allegiance to her had been responsible for the many wars +in which they had been involved. Reasons of trade were not less weighty +in behalf of independence. "Our corn will fetch its price in any market +in Europe and our imported goods must be paid for, buy them where we +will." As to matters of government, "it is not in the power of Britain +to do this continent justice; the business of it will soon be too +weighty and intricate to be managed with any tolerable degree of +convenience by a power so distant from us and so very ignorant of us." + +There is accordingly no alternative to independence for America. +"Everything that is right or natural pleads for separation. The blood of +the slain, the weeping voice of nature cries ''tis time to part.' ... +Arms, the last resort, must decide the contest; the appeal was the +choice of the king and the continent hath accepted the challenge.... The +sun never shone on a cause of greater worth. 'Tis not the affair of a +city, a county, a province or a kingdom, but of a continent.... 'Tis not +the concern of a day, a year or an age; posterity is involved in the +contest and will be more or less affected to the end of time by the +proceedings now. Now is the seed-time of Continental union, faith, and +honor.... O! ye that love mankind! Ye that dare oppose not only the +tyranny, but the tyrant, stand forth.... Let names of Whig and Tory be +extinct. Let none other be heard among us than those of a good citizen, +an open and resolute friend, and a virtuous supporter of the rights of +mankind and of the free and independent states of America." As more than +100,000 copies were scattered broadcast over the country, patriots +exclaimed with Washington: "Sound doctrine and unanswerable reason!" + +=The Drift of Events toward Independence.=--Official support for the +idea of independence began to come from many quarters. On the tenth of +February, 1776, Gadsden, in the provincial convention of South Carolina, +advocated a new constitution for the colony and absolute independence +for all America. The convention balked at the latter but went half way +by abolishing the system of royal administration and establishing a +complete plan of self-government. A month later, on April 12, the +neighboring state of North Carolina uttered the daring phrase from which +others shrank. It empowered its representatives in the Congress to +concur with the delegates of the other colonies in declaring +independence. Rhode Island, Massachusetts, and Virginia quickly +responded to the challenge. The convention of the Old Dominion, on May +15, instructed its delegates at Philadelphia to propose the independence +of the United Colonies and to give the assent of Virginia to the act of +separation. When the resolution was carried the British flag on the +state house was lowered for all time. + +Meanwhile the Continental Congress was alive to the course of events +outside. The subject of independence was constantly being raised. "Are +we rebels?" exclaimed Wyeth of Virginia during a debate in February. +"No: we must declare ourselves a free people." Others hesitated and +spoke of waiting for the arrival of commissioners of conciliation. "Is +not America already independent?" asked Samuel Adams a few weeks later. +"Why not then declare it?" Still there was uncertainty and delegates +avoided the direct word. A few more weeks elapsed. At last, on May 10, +Congress declared that the authority of the British crown in America +must be suppressed and advised the colonies to set up governments of +their own. + +[Illustration: _From an old print_ + +THOMAS JEFFERSON READING HIS DRAFT OF THE DECLARATION OF +INDEPENDENCE TO THE COMMITTEE OF CONGRESS] + +=Independence Declared.=--The way was fully prepared, therefore, when, +on June 7, the Virginia delegation in the Congress moved that "these +united colonies are and of right ought to be free and independent +states." A committee was immediately appointed to draft a formal +document setting forth the reasons for the act, and on July 2 all the +states save New York went on record in favor of severing their political +connection with Great Britain. Two days later, July 4, Jefferson's draft +of the Declaration of Independence, changed in some slight particulars, +was adopted. The old bell in Independence Hall, as it is now known, rang +out the glad tidings; couriers swiftly carried the news to the uttermost +hamlet and farm. A new nation announced its will to have a place among +the powers of the world. + +To some documents is given immortality. The Declaration of Independence +is one of them. American patriotism is forever associated with it; but +patriotism alone does not make it immortal. Neither does the vigor of +its language or the severity of its indictment give it a secure place in +the records of time. The secret of its greatness lies in the simple fact +that it is one of the memorable landmarks in the history of a political +ideal which for three centuries has been taking form and spreading +throughout the earth, challenging kings and potentates, shaking down +thrones and aristocracies, breaking the armies of irresponsible power on +battle fields as far apart as Marston Moor and Chateau-Thierry. That +ideal, now so familiar, then so novel, is summed up in the simple +sentence: "Governments derive their just powers from the consent of the +governed." + +Written in a "decent respect for the opinions of mankind," to set forth +the causes which impelled the American colonists to separate from +Britain, the Declaration contained a long list of "abuses and +usurpations" which had induced them to throw off the government of King +George. That section of the Declaration has passed into "ancient" +history and is seldom read. It is the part laying down a new basis for +government and giving a new dignity to the common man that has become a +household phrase in the Old World as in the New. + +In the more enduring passages there are four fundamental ideas which, +from the standpoint of the old system of government, were the essence of +revolution: (1) all men are created equal and are endowed by their +Creator with certain unalienable rights including life, liberty, and the +pursuit of happiness; (2) the purpose of government is to secure these +rights; (3) governments derive their just powers from the consent of the +governed; (4) whenever any form of government becomes destructive of +these ends it is the right of the people to alter or abolish it and +institute new government, laying its foundations on such principles and +organizing its powers in such form as to them shall seem most likely to +effect their safety and happiness. Here was the prelude to the historic +drama of democracy--a challenge to every form of government and every +privilege not founded on popular assent. + + +THE ESTABLISHMENT OF GOVERNMENT AND THE NEW ALLEGIANCE + +=The Committees of Correspondence.=--As soon as debate had passed into +armed resistance, the patriots found it necessary to consolidate their +forces by organizing civil government. This was readily effected, for +the means were at hand in town meetings, provincial legislatures, and +committees of correspondence. The working tools of the Revolution were +in fact the committees of correspondence--small, local, unofficial +groups of patriots formed to exchange views and create public sentiment. +As early as November, 1772, such a committee had been created in Boston +under the leadership of Samuel Adams. It held regular meetings, sent +emissaries to neighboring towns, and carried on a campaign of education +in the doctrines of liberty. + +[Illustration: THE COLONIES OF NORTH AMERICA AT THE TIME OF THE +DECLARATION OF INDEPENDENCE] + +Upon local organizations similar in character to the Boston committee +were built county committees and then the larger colonial committees, +congresses, and conventions, all unofficial and representing the +revolutionary elements. Ordinarily the provincial convention was merely +the old legislative assembly freed from all royalist sympathizers and +controlled by patriots. Finally, upon these colonial assemblies was +built the Continental Congress, the precursor of union under the +Articles of Confederation and ultimately under the Constitution of the +United States. This was the revolutionary government set up within the +British empire in America. + +=State Constitutions Framed.=--With the rise of these new assemblies of +the people, the old colonial governments broke down. From the royal +provinces the governor, the judges, and the high officers fled in haste, +and it became necessary to substitute patriot authorities. The appeal to +the colonies advising them to adopt a new form of government for +themselves, issued by the Congress in May, 1776, was quickly acted upon. +Before the expiration of a year, Virginia, New Jersey, Pennsylvania, +Delaware, Maryland, Georgia, and New York had drafted new constitutions +as states, not as colonies uncertain of their destinies. Connecticut and +Rhode Island, holding that their ancient charters were equal to their +needs, merely renounced their allegiance to the king and went on as +before so far as the form of government was concerned. South Carolina, +which had drafted a temporary plan early in 1776, drew up a new and more +complete constitution in 1778. Two years later Massachusetts with much +deliberation put into force its fundamental law, which in most of its +essential features remains unchanged to-day. + +The new state constitutions in their broad outlines followed colonial +models. For the royal governor was substituted a governor or president +chosen usually by the legislature; but in two instances, New York and +Massachusetts, by popular vote. For the provincial council there was +substituted, except in Georgia, a senate; while the lower house, or +assembly, was continued virtually without change. The old property +restriction on the suffrage, though lowered slightly in some states, was +continued in full force to the great discontent of the mechanics thus +deprived of the ballot. The special qualifications, laid down in several +constitutions, for governors, senators, and representatives, indicated +that the revolutionary leaders were not prepared for any radical +experiments in democracy. The protests of a few women, like Mrs. John +Adams of Massachusetts and Mrs. Henry Corbin of Virginia, against a +government which excluded them from political rights were treated as +mild curiosities of no significance, although in New Jersey women were +allowed to vote for many years on the same terms as men. + +By the new state constitutions the signs and symbols of royal power, of +authority derived from any source save "the people," were swept aside +and republican governments on an imposing scale presented for the first +time to the modern world. Copies of these remarkable documents prepared +by plain citizens were translated into French and widely circulated in +Europe. There they were destined to serve as a guide and inspiration to +a generation of constitution-makers whose mission it was to begin the +democratic revolution in the Old World. + +=The Articles of Confederation.=--The formation of state constitutions +was an easy task for the revolutionary leaders. They had only to build +on foundations already laid. The establishment of a national system of +government was another matter. There had always been, it must be +remembered, a system of central control over the colonies, but Americans +had had little experience in its operation. When the supervision of the +crown of Great Britain was suddenly broken, the patriot leaders, +accustomed merely to provincial statesmanship, were poorly trained for +action on a national stage. + +Many forces worked against those who, like Franklin, had a vision of +national destiny. There were differences in economic interest--commerce +and industry in the North and the planting system of the South. There +were contests over the apportionment of taxes and the quotas of troops +for common defense. To these practical difficulties were added local +pride, the vested rights of state and village politicians in their +provincial dignity, and the scarcity of men with a large outlook upon +the common enterprise. + +Nevertheless, necessity compelled them to consider some sort of +federation. The second Continental Congress had hardly opened its work +before the most sagacious leaders began to urge the desirability of a +permanent connection. As early as July, 1775, Congress resolved to go +into a committee of the whole on the state of the union, and Franklin, +undaunted by the fate of his Albany plan of twenty years before, again +presented a draft of a constitution. Long and desultory debates followed +and it was not until late in 1777 that Congress presented to the states +the Articles of Confederation. Provincial jealousies delayed +ratification, and it was the spring of 1781, a few months before the +surrender of Cornwallis at Yorktown, when Maryland, the last of the +states, approved the Articles. This plan of union, though it was all +that could be wrung from the reluctant states, provided for neither a +chief executive nor a system of federal courts. It created simply a +Congress of delegates in which each state had an equal voice and gave it +the right to call upon the state legislatures for the sinews of +government--money and soldiers. + +=The Application of Tests of Allegiance.=--As the successive steps were +taken in the direction of independent government, the patriots devised +and applied tests designed to discover who were for and who were against +the new nation in the process of making. When the first Continental +Congress agreed not to allow the importation of British goods, it +provided for the creation of local committees to enforce the rules. Such +agencies were duly formed by the choice of men favoring the scheme, all +opponents being excluded from the elections. Before these bodies those +who persisted in buying British goods were summoned and warned or +punished according to circumstances. As soon as the new state +constitutions were put into effect, local committees set to work in the +same way to ferret out all who were not outspoken in their support of +the new order of things. + +[Illustration: MOBBING THE TORIES] + +These patriot agencies, bearing different names in different sections, +were sometimes ruthless in their methods. They called upon all men to +sign the test of loyalty, frequently known as the "association test." +Those who refused were promptly branded as outlaws, while some of the +more dangerous were thrown into jail. The prison camp in Connecticut at +one time held the former governor of New Jersey and the mayor of New +York. Thousands were black-listed and subjected to espionage. The +black-list of Pennsylvania contained the names of nearly five hundred +persons of prominence who were under suspicion. Loyalists or Tories who +were bold enough to speak and write against the Revolution were +suppressed and their pamphlets burned. In many places, particularly in +the North, the property of the loyalists was confiscated and the +proceeds applied to the cause of the Revolution. + +The work of the official agencies for suppression of opposition was +sometimes supplemented by mob violence. A few Tories were hanged without +trial, and others were tarred and feathered. One was placed upon a cake +of ice and held there "until his loyalty to King George might cool." +Whole families were driven out of their homes to find their way as best +they could within the British lines or into Canada, where the British +government gave them lands. Such excesses were deplored by Washington, +but they were defended on the ground that in effect a civil war, as well +as a war for independence, was being waged. + +=The Patriots and Tories.=--Thus, by one process or another, those who +were to be citizens of the new republic were separated from those who +preferred to be subjects of King George. Just what proportion of the +Americans favored independence and what share remained loyal to the +British monarchy there is no way of knowing. The question of revolution +was not submitted to popular vote, and on the point of numbers we have +conflicting evidence. On the patriot side, there is the testimony of a +careful and informed observer, John Adams, who asserted that two-thirds +of the people were for the American cause and not more than one-third +opposed the Revolution at all stages. + +On behalf of the loyalists, or Tories as they were popularly known, +extravagant claims were made. Joseph Galloway, who had been a member of +the first Continental Congress and had fled to England when he saw its +temper, testified before a committee of Parliament in 1779 that not +one-fifth of the American people supported the insurrection and that +"many more than four-fifths of the people prefer a union with Great +Britain upon constitutional principles to independence." At the same +time General Robertson, who had lived in America twenty-four years, +declared that "more than two-thirds of the people would prefer the +king's government to the Congress' tyranny." In an address to the king +in that year a committee of American loyalists asserted that "the number +of Americans in his Majesty's army exceeded the number of troops +enlisted by Congress to oppose them." + +=The Character of the Loyalists.=--When General Howe evacuated Boston, +more than a thousand people fled with him. This great company, according +to a careful historian, "formed the aristocracy of the province by +virtue of their official rank; of their dignified callings and +professions; of their hereditary wealth and of their culture." The act +of banishment passed by Massachusetts in 1778, listing over 300 Tories, +"reads like the social register of the oldest and noblest families of +New England," more than one out of five being graduates of Harvard +College. The same was true of New York and Philadelphia; namely, that +the leading loyalists were prominent officials of the old order, +clergymen and wealthy merchants. With passion the loyalists fought +against the inevitable or with anguish of heart they left as refugees +for a life of uncertainty in Canada or the mother country. + +=Tories Assail the Patriots.=--The Tories who remained in America joined +the British army by the thousands or in other ways aided the royal +cause. Those who were skillful with the pen assailed the patriots in +editorials, rhymes, satires, and political catechisms. They declared +that the members of Congress were "obscure, pettifogging attorneys, +bankrupt shopkeepers, outlawed smugglers, etc." The people and their +leaders they characterized as "wretched banditti ... the refuse and +dregs of mankind." The generals in the army they sneered at as "men of +rank and honor nearly on a par with those of the Congress." + +=Patriot Writers Arouse the National Spirit.=--Stung by Tory taunts, +patriot writers devoted themselves to creating and sustaining a public +opinion favorable to the American cause. Moreover, they had to combat +the depression that grew out of the misfortunes in the early days of the +war. A terrible disaster befell Generals Arnold and Montgomery in the +winter of 1775 as they attempted to bring Canada into the revolution--a +disaster that cost 5000 men; repeated calamities harassed Washington in +1776 as he was defeated on Long Island, driven out of New York City, and +beaten at Harlem Heights and White Plains. These reverses were almost +too great for the stoutest patriots. + +Pamphleteers, preachers, and publicists rose, however, to meet the needs +of the hour. John Witherspoon, provost of the College of New Jersey, +forsook the classroom for the field of political controversy. The poet, +Philip Freneau, flung taunts of cowardice at the Tories and celebrated +the spirit of liberty in many a stirring poem. Songs, ballads, plays, +and satires flowed from the press in an unending stream. Fast days, +battle anniversaries, celebrations of important steps taken by Congress +afforded to patriotic clergymen abundant opportunities for sermons. +"Does Mr. Wiberd preach against oppression?" anxiously inquired John +Adams in a letter to his wife. The answer was decisive. "The clergy of +every denomination, not excepting the Episcopalian, thunder and lighten +every Sabbath. They pray for Boston and Massachusetts. They thank God +most explicitly and fervently for our remarkable successes. They pray +for the American army." + +Thomas Paine never let his pen rest. He had been with the forces of +Washington when they retreated from Fort Lee and were harried from New +Jersey into Pennsylvania. He knew the effect of such reverses on the +army as well as on the public. In December, 1776, he made a second great +appeal to his countrymen in his pamphlet, "The Crisis," the first part +of which he had written while defeat and gloom were all about him. This +tract was a cry for continued support of the Revolution. "These are the +times that try men's souls," he opened. "The summer soldier and the +sunshine patriot will, in this crisis, shrink from the service of his +country; but he that stands it now deserves the love and thanks of men +and women." Paine laid his lash fiercely on the Tories, branding every +one as a coward grounded in "servile, slavish, self-interested fear." He +deplored the inadequacy of the militia and called for a real army. He +refuted the charge that the retreat through New Jersey was a disaster +and he promised victory soon. "By perseverance and fortitude," he +concluded, "we have the prospect of a glorious issue; by cowardice and +submission the sad choice of a variety of evils--a ravaged country, a +depopulated city, habitations without safety and slavery without +hope.... Look on this picture and weep over it." His ringing call to +arms was followed by another and another until the long contest was +over. + + +MILITARY AFFAIRS + +=The Two Phases of the War.=--The war which opened with the battle of +Lexington, on April 19, 1775, and closed with the surrender of +Cornwallis at Yorktown on October 19, 1781, passed through two distinct +phases--the first lasting until the treaty of alliance with France, in +1778, and the second until the end of the struggle. During the first +phase, the war was confined mainly to the North. The outstanding +features of the contest were the evacuation of Boston by the British, +the expulsion of American forces from New York and their retreat through +New Jersey, the battle of Trenton, the seizure of Philadelphia by the +British (September, 1777), the invasion of New York by Burgoyne and his +capture at Saratoga in October, 1777, and the encampment of American +forces at Valley Forge for the terrible winter of 1777-78. + +The final phase of the war, opening with the treaty of alliance with +France on February 6, 1778, was confined mainly to the Middle states, +the West, and the South. In the first sphere of action the chief events +were the withdrawal of the British from Philadelphia, the battle of +Monmouth, and the inclosure of the British in New York by deploying +American forces from Morristown, New Jersey, up to West Point. In the +West, George Rogers Clark, by his famous march into the Illinois +country, secured Kaskaskia and Vincennes and laid a firm grip on the +country between the Ohio and the Great Lakes. In the South, the second +period opened with successes for the British. They captured Savannah, +conquered Georgia, and restored the royal governor. In 1780 they seized +Charleston, administered a crushing defeat to the American forces under +Gates at Camden, and overran South Carolina, though meeting reverses at +Cowpens and King's Mountain. Then came the closing scenes. Cornwallis +began the last of his operations. He pursued General Greene far into +North Carolina, clashed with him at Guilford Court House, retired to the +coast, took charge of British forces engaged in plundering Virginia, and +fortified Yorktown, where he was penned up by the French fleet from the +sea and the combined French and American forces on land. + +=The Geographical Aspects of the War.=--For the British the theater of +the war offered many problems. From first to last it extended from +Massachusetts to Georgia, a distance of almost a thousand miles. It was +nearly three thousand miles from the main base of supplies and, though +the British navy kept the channel open, transports were constantly +falling prey to daring privateers and fleet American war vessels. The +sea, on the other hand, offered an easy means of transportation between +points along the coast and gave ready access to the American centers of +wealth and population. Of this the British made good use. Though early +forced to give up Boston, they seized New York and kept it until the end +of the war; they took Philadelphia and retained it until threatened by +the approach of the French fleet; and they captured and held both +Savannah and Charleston. Wars, however, are seldom won by the conquest +of cities. + +Particularly was this true in the case of the Revolution. Only a small +portion of the American people lived in towns. Countrymen back from the +coast were in no way dependent upon them for a livelihood. They lived on +the produce of the soil, not upon the profits of trade. This very fact +gave strength to them in the contest. Whenever the British ventured far +from the ports of entry, they encountered reverses. Burgoyne was forced +to surrender at Saratoga because he was surrounded and cut off from his +base of supplies. As soon as the British got away from Charleston, they +were harassed and worried by the guerrilla warriors of Marion, Sumter, +and Pickens. Cornwallis could technically defeat Greene at Guilford far +in the interior; but he could not hold the inland region he had invaded. +Sustained by their own labor, possessing the interior to which their +armies could readily retreat, supplied mainly from native resources, the +Americans could not be hemmed in, penned up, and destroyed at one fell +blow. + +=The Sea Power.=--The British made good use of their fleet in cutting +off American trade, but control of the sea did not seriously affect the +United States. As an agricultural country, the ruin of its commerce was +not such a vital matter. All the materials for a comfortable though +somewhat rude life were right at hand. It made little difference to a +nation fighting for existence, if silks, fine linens, and chinaware were +cut off. This was an evil to which submission was necessary. + +Nor did the brilliant exploits of John Paul Jones and Captain John Barry +materially change the situation. They demonstrated the skill of American +seamen and their courage as fighting men. They raised the rates of +British marine insurance, but they did not dethrone the mistress of the +seas. Less spectacular, and more distinctive, were the deeds of the +hundreds of privateers and minor captains who overhauled British supply +ships and kept British merchantmen in constant anxiety. Not until the +French fleet was thrown into the scale, were the British compelled to +reckon seriously with the enemy on the sea and make plans based upon the +possibilities of a maritime disaster. + +=Commanding Officers.=--On the score of military leadership it is +difficult to compare the contending forces in the revolutionary contest. +There is no doubt that all the British commanders were men of experience +in the art of warfare. Sir William Howe had served in America during the +French War and was accounted an excellent officer, a strict +disciplinarian, and a gallant gentleman. Nevertheless he loved ease, +society, and good living, and his expulsion from Boston, his failure to +overwhelm Washington by sallies from his comfortable bases at New York +and Philadelphia, destroyed every shred of his military reputation. John +Burgoyne, to whom was given the task of penetrating New York from +Canada, had likewise seen service in the French War both in America and +Europe. He had, however, a touch of the theatrical in his nature and +after the collapse of his plans and the surrender of his army in 1777, +he devoted his time mainly to light literature. Sir Henry Clinton, who +directed the movement which ended in the capture of Charleston in 1780, +had "learned his trade on the continent," and was regarded as a man of +discretion and understanding in military matters. Lord Cornwallis, whose +achievements at Camden and Guilford were blotted out by his surrender at +Yorktown, had seen service in the Seven Years' War and had undoubted +talents which he afterward displayed with great credit to himself in +India. Though none of them, perhaps, were men of first-rate ability, +they all had training and experience to guide them. + +[Illustration: GEORGE WASHINGTON] + +The Americans had a host in Washington himself. He had long been +interested in military strategy and had tested his coolness under fire +during the first clashes with the French nearly twenty years before. He +had no doubts about the justice of his cause, such as plagued some of +the British generals. He was a stern but reasonable disciplinarian. He +was reserved and patient, little given to exaltation at success or +depression at reverses. In the dark hour of the Revolution, "what held +the patriot forces together?" asks Beveridge in his _Life of John +Marshall_. Then he answers: "George Washington and he alone. Had he +died or been seriously disabled, the Revolution would have ended.... +Washington was the soul of the American cause. Washington was the +government. Washington was the Revolution." The weakness of Congress in +furnishing men and supplies, the indolence of civilians, who lived at +ease while the army starved, the intrigues of army officers against him +such as the "Conway cabal," the cowardice of Lee at Monmouth, even the +treason of Benedict Arnold, while they stirred deep emotions in his +breast and aroused him to make passionate pleas to his countrymen, did +not shake his iron will or his firm determination to see the war through +to the bitter end. The weight of Washington's moral force was +immeasurable. + +Of the generals who served under him, none can really be said to have +been experienced military men when the war opened. Benedict Arnold, the +unhappy traitor but brave and daring soldier, was a druggist, book +seller, and ship owner at New Haven when the news of Lexington called +him to battle. Horatio Gates was looked upon as a "seasoned soldier" +because he had entered the British army as a youth, had been wounded at +Braddock's memorable defeat, and had served with credit during the Seven +Years' War; but he was the most conspicuous failure of the Revolution. +The triumph over Burgoyne was the work of other men; and his crushing +defeat at Camden put an end to his military pretensions. Nathanael +Greene was a Rhode Island farmer and smith without military experience +who, when convinced that war was coming, read Caesar's _Commentaries_ and +took up the sword. Francis Marion was a shy and modest planter of South +Carolina whose sole passage at arms had been a brief but desperate brush +with the Indians ten or twelve years earlier. Daniel Morgan, one of the +heroes of Cowpens, had been a teamster with Braddock's army and had seen +some fighting during the French and Indian War, but his military +knowledge, from the point of view of a trained British officer, was +negligible. John Sullivan was a successful lawyer at Durham, New +Hampshire, and a major in the local militia when duty summoned him to +lay down his briefs and take up the sword. Anthony Wayne was a +Pennsylvania farmer and land surveyor who, on hearing the clash of arms, +read a few books on war, raised a regiment, and offered himself for +service. Such is the story of the chief American military leaders, and +it is typical of them all. Some had seen fighting with the French and +Indians, but none of them had seen warfare on a large scale with regular +troops commanded according to the strategy evolved in European +experience. Courage, native ability, quickness of mind, and knowledge of +the country they had in abundance, and in battles such as were fought +during the Revolution all those qualities counted heavily in the +balance. + +=Foreign Officers in American Service.=--To native genius was added +military talent from beyond the seas. Baron Steuben, well schooled in +the iron regime of Frederick the Great, came over from Prussia, joined +Washington at Valley Forge, and day after day drilled and manoeuvered the +men, laughing and cursing as he turned raw countrymen into regular +soldiers. From France came young Lafayette and the stern De Kalb, from +Poland came Pulaski and Kosciusko;--all acquainted with the arts of war +as waged in Europe and fitted for leadership as well as teaching. +Lafayette came early, in 1776, in a ship of his own, accompanied by +several officers of wide experience, and remained loyally throughout the +war sharing the hardships of American army life. Pulaski fell at the +siege of Savannah and De Kalb at Camden. Kosciusko survived the American +war to defend in vain the independence of his native land. To these +distinguished foreigners, who freely threw in their lot with American +revolutionary fortunes, was due much of that spirit and discipline which +fitted raw recruits and temperamental militiamen to cope with a military +power of the first rank. + +=The Soldiers.=--As far as the British soldiers were concerned their +annals are short and simple. The regulars from the standing army who +were sent over at the opening of the contest, the recruits drummed up +by special efforts at home, and the thousands of Hessians bought +outright by King George presented few problems of management to the +British officers. These common soldiers were far away from home and +enlisted for the war. Nearly all of them were well disciplined and many +of them experienced in actual campaigns. The armies of King George +fought bravely, as the records of Bunker Hill, Brandywine, and Monmouth +demonstrate. Many a man and subordinate officer and, for that matter, +some of the high officers expressed a reluctance at fighting against +their own kin; but they obeyed orders. + +The Americans, on the other hand, while they fought with grim +determination, as men fighting for their homes, were lacking in +discipline and in the experience of regular troops. When the war broke +in upon them, there were no common preparations for it. There was no +continental army; there were only local bands of militiamen, many of +them experienced in fighting but few of them "regulars" in the military +sense. Moreover they were volunteers serving for a short time, +unaccustomed to severe discipline, and impatient at the restraints +imposed on them by long and arduous campaigns. They were continually +leaving the service just at the most critical moments. "The militia," +lamented Washington, "come in, you cannot tell how; go, you cannot tell +where; consume your provisions; exhaust your stores; and leave you at +last at a critical moment." + +Again and again Washington begged Congress to provide for an army of +regulars enlisted for the war, thoroughly trained and paid according to +some definite plan. At last he was able to overcome, in part at least, +the chronic fear of civilians in Congress and to wring from that +reluctant body an agreement to grant half pay to all officers and a +bonus to all privates who served until the end of the war. Even this +scheme, which Washington regarded as far short of justice to the +soldiers, did not produce quick results. It was near the close of the +conflict before he had an army of well-disciplined veterans capable of +meeting British regulars on equal terms. + +Though there were times when militiamen and frontiersmen did valiant and +effective work, it is due to historical accuracy to deny the +time-honored tradition that a few minutemen overwhelmed more numerous +forces of regulars in a seven years' war for independence. They did +nothing of the sort. For the victories of Bennington, Trenton, Saratoga, +and Yorktown there were the defeats of Bunker Hill, Long Island, White +Plains, Germantown, and Camden. Not once did an army of militiamen +overcome an equal number of British regulars in an open trial by battle. +"To bring men to be well acquainted with the duties of a soldier," wrote +Washington, "requires time.... To expect the same service from raw and +undisciplined recruits as from veteran soldiers is to expect what never +did and perhaps never will happen." + +=How the War Was Won.=--Then how did the American army win the war? For +one thing there were delays and blunders on the part of the British +generals who, in 1775 and 1776, dallied in Boston and New York with +large bodies of regular troops when they might have been dealing +paralyzing blows at the scattered bands that constituted the American +army. "Nothing but the supineness or folly of the enemy could have saved +us," solemnly averred Washington in 1780. Still it is fair to say that +this apparent supineness was not all due to the British generals. The +ministers behind them believed that a large part of the colonists were +loyal and that compromise would be promoted by inaction rather than by a +war vigorously prosecuted. Victory by masterly inactivity was obviously +better than conquest, and the slighter the wounds the quicker the +healing. Later in the conflict when the seasoned forces of France were +thrown into the scale, the Americans themselves had learned many things +about the practical conduct of campaigns. All along, the British were +embarrassed by the problem of supplies. Their troops could not forage +with the skill of militiamen, as they were in unfamiliar territory. The +long oversea voyages were uncertain at best and doubly so when the +warships of France joined the American privateers in preying on supply +boats. + +The British were in fact battered and worn down by a guerrilla war and +outdone on two important occasions by superior forces--at Saratoga and +Yorktown. Stern facts convinced them finally that an immense army, which +could be raised only by a supreme effort, would be necessary to subdue +the colonies if that hazardous enterprise could be accomplished at all. +They learned also that America would then be alienated, fretful, and the +scene of endless uprisings calling for an army of occupation. That was a +price which staggered even Lord North and George III. Moreover, there +were forces of opposition at home with which they had to reckon. + +=Women and the War.=--At no time were the women of America indifferent +to the struggle for independence. When it was confined to the realm of +opinion they did their part in creating public sentiment. Mrs. Elizabeth +Timothee, for example, founded in Charleston, in 1773, a newspaper to +espouse the cause of the province. Far to the north the sister of James +Otis, Mrs. Mercy Warren, early begged her countrymen to rest their case +upon their natural rights, and in influential circles she urged the +leaders to stand fast by their principles. While John Adams was tossing +about with uncertainty at the Continental Congress, his wife was writing +letters to him declaring her faith in "independency." + +When the war came down upon the country, women helped in every field. In +sustaining public sentiment they were active. Mrs. Warren with a +tireless pen combatted loyalist propaganda in many a drama and satire. +Almost every revolutionary leader had a wife or daughter who rendered +service in the "second line of defense." Mrs. Washington managed the +plantation while the General was at the front and went north to face the +rigors of the awful winter at Valley Forge--an inspiration to her +husband and his men. The daughter of Benjamin Franklin, Mrs. Sarah +Bache, while her father was pleading the American cause in France, set +the women of Pennsylvania to work sewing and collecting supplies. Even +near the firing line women were to be found, aiding the wounded, hauling +powder to the front, and carrying dispatches at the peril of their +lives. + +In the economic sphere, the work of women was invaluable. They harvested +crops without enjoying the picturesque title of "farmerettes" and they +canned and preserved for the wounded and the prisoners of war. Of their +labor in spinning and weaving it is recorded: "Immediately on being cut +off from the use of English manufactures, the women engaged within their +own families in manufacturing various kinds of cloth for domestic use. +They thus kept their households decently clad and the surplus of their +labors they sold to such as chose to buy rather than make for +themselves. In this way the female part of families by their industry +and strict economy frequently supported the whole domestic circle, +evincing the strength of their attachment and the value of their +service." + +For their war work, women were commended by high authorities on more +than one occasion. They were given medals and public testimonials even +as in our own day. Washington thanked them for their labors and paid +tribute to them for the inspiration and material aid which they had +given to the cause of independence. + + +THE FINANCES OF THE REVOLUTION + +When the Revolution opened, there were thirteen little treasuries in +America but no common treasury, and from first to last the Congress was +in the position of a beggar rather than a sovereign. Having no authority +to lay and collect taxes directly and knowing the hatred of the +provincials for taxation, it resorted mainly to loans and paper money to +finance the war. "Do you think," boldly inquired one of the delegates, +"that I will consent to load my constituents with taxes when we can send +to the printer and get a wagon load of money, one quire of which will +pay for the whole?" + +=Paper Money and Loans.=--Acting on this curious but appealing political +economy, Congress issued in June, 1776, two million dollars in bills of +credit to be redeemed by the states on the basis of their respective +populations. Other issues followed in quick succession. In all about +$241,000,000 of continental paper was printed, to which the several +states added nearly $210,000,000 of their own notes. Then came +interest-bearing bonds in ever increasing quantities. Several millions +were also borrowed from France and small sums from Holland and Spain. In +desperation a national lottery was held, producing meager results. The +property of Tories was confiscated and sold, bringing in about +$16,000,000. Begging letters were sent to the states asking them to +raise revenues for the continental treasury, but the states, burdened +with their own affairs, gave little heed. + +=Inflation and Depreciation.=--As paper money flowed from the press, it +rapidly declined in purchasing power until in 1779 a dollar was worth +only two or three cents in gold or silver. Attempts were made by +Congress and the states to compel people to accept the notes at face +value; but these were like attempts to make water flow uphill. +Speculators collected at once to fatten on the calamities of the +republic. Fortunes were made and lost gambling on the prices of public +securities while the patriot army, half clothed, was freezing at Valley +Forge. "Speculation, peculation, engrossing, forestalling," exclaimed +Washington, "afford too many melancholy proofs of the decay of public +virtue. Nothing, I am convinced, but the depreciation of our currency +... aided by stock jobbing and party dissensions has fed the hopes of +the enemy." + +=The Patriot Financiers.=--To the efforts of Congress in financing the +war were added the labors of private citizens. Hayn Solomon, a merchant +of Philadelphia, supplied members of Congress, including Madison, +Jefferson, and Monroe, and army officers, like Lee and Steuben, with +money for their daily needs. All together he contributed the huge sum of +half a million dollars to the American cause and died broken in purse, +if not in spirit, a British prisoner of war. Another Philadelphia +merchant, Robert Morris, won for himself the name of the "patriot +financier" because he labored night and day to find the money to meet +the bills which poured in upon the bankrupt government. When his own +funds were exhausted, he borrowed from his friends. Experienced in the +handling of merchandise, he created agencies at important points to +distribute supplies to the troops, thus displaying administrative as +well as financial talents. + +[Illustration: ROBERT MORRIS] + +Women organized "drives" for money, contributed their plate and their +jewels, and collected from door to door. Farmers took worthless paper in +return for their produce, and soldiers saw many a pay day pass without +yielding them a penny. Thus by the labors and sacrifices of citizens, +the issuance of paper money, lotteries, the floating of loans, +borrowings in Europe, and the impressment of supplies, the Congress +staggered through the Revolution like a pauper who knows not how his +next meal is to be secured but is continuously relieved at a crisis by a +kindly fate. + + +THE DIPLOMACY OF THE REVOLUTION + +When the full measure of honor is given to the soldiers and sailors and +their commanding officers, the civilians who managed finances and +supplies, the writers who sustained the American spirit, and the women +who did well their part, there yet remains the duty of recognizing the +achievements of diplomacy. The importance of this field of activity was +keenly appreciated by the leaders in the Continental Congress. They were +fairly well versed in European history. They knew of the balance of +power and the sympathies, interests, and prejudices of nations and their +rulers. All this information they turned to good account, in opening +relations with continental countries and seeking money, supplies, and +even military assistance. For the transaction of this delicate business, +they created a secret committee on foreign correspondence as early as +1775 and prepared to send agents abroad. + +=American Agents Sent Abroad.=--Having heard that France was inclining a +friendly ear to the American cause, the Congress, in March, 1776, sent a +commissioner to Paris, Silas Deane of Connecticut, often styled the +"first American diplomat." Later in the year a form of treaty to be +presented to foreign powers was drawn up, and Franklin, Arthur Lee, and +Deane were selected as American representatives at the court of "His +Most Christian Majesty the King of France." John Jay of New York was +chosen minister to Spain in 1779; John Adams was sent to Holland the +same year; and other agents were dispatched to Florence, Vienna, and +Berlin. The representative selected for St. Petersburg spent two +fruitless years there, "ignored by the court, living in obscurity and +experiencing nothing but humiliation and failure." Frederick the Great, +king of Prussia, expressed a desire to find in America a market for +Silesian linens and woolens, but, fearing England's command of the sea, +he refused to give direct aid to the Revolutionary cause. + +=Early French Interest.=--The great diplomatic triumph of the Revolution +was won at Paris, and Benjamin Franklin was the hero of the occasion, +although many circumstances prepared the way for his success. Louis +XVI's foreign minister, Count de Vergennes, before the arrival of any +American representative, had brought to the attention of the king the +opportunity offered by the outbreak of the war between England and her +colonies. He showed him how France could redress her grievances and +"reduce the power and greatness of England"--the empire that in 1763 had +forced upon her a humiliating peace "at the price of our possessions, +of our commerce, and our credit in the Indies, at the price of Canada, +Louisiana, Isle Royale, Acadia, and Senegal." Equally successful in +gaining the king's interest was a curious French adventurer, +Beaumarchais, a man of wealth, a lover of music, and the author of two +popular plays, "Figaro" and "The Barber of Seville." These two men had +already urged upon the king secret aid for America before Deane appeared +on the scene. Shortly after his arrival they made confidential +arrangements to furnish money, clothing, powder, and other supplies to +the struggling colonies, although official requests for them were +officially refused by the French government. + +=Franklin at Paris.=--When Franklin reached Paris, he was received only +in private by the king's minister, Vergennes. The French people, +however, made manifest their affection for the "plain republican" in +"his full dress suit of spotted Manchester velvet." He was known among +men of letters as an author, a scientist, and a philosopher of +extraordinary ability. His "Poor Richard" had thrice been translated +into French and was scattered in numerous editions throughout the +kingdom. People of all ranks--ministers, ladies at court, philosophers, +peasants, and stable boys--knew of Franklin and wished him success in +his mission. The queen, Marie Antoinette, fated to lose her head in a +revolution soon to follow, played with fire by encouraging "our dear +republican." + +For the king of France, however, this was more serious business. England +resented the presence of this "traitor" in Paris, and Louis had to be +cautious about plunging into another war that might also end +disastrously. Moreover, the early period of Franklin's sojourn in Paris +was a dark hour for the American Revolution. Washington's brilliant +exploit at Trenton on Christmas night, 1776, and the battle with +Cornwallis at Princeton had been followed by the disaster at Brandywine, +the loss of Philadelphia, the defeat at Germantown, and the retirement +to Valley Forge for the winter of 1777-78. New York City and +Philadelphia--two strategic ports--were in British hands; the Hudson +and Delaware rivers were blocked; and General Burgoyne with his British +troops was on his way down through the heart of northern New York, +cutting New England off from the rest of the colonies. No wonder the +king was cautious. Then the unexpected happened. Burgoyne, hemmed in +from all sides by the American forces, his flanks harried, his foraging +parties beaten back, his supplies cut off, surrendered on October 17, +1777, to General Gates, who had superseded General Schuyler in time to +receive the honor. + +=Treaties of Alliance and Commerce (1778).=--News of this victory, +placed by historians among the fifteen decisive battles of the world, +reached Franklin one night early in December while he and some friends +sat gloomily at dinner. Beaumarchais, who was with him, grasped at once +the meaning of the situation and set off to the court at Versailles with +such haste that he upset his coach and dislocated his arm. The king and +his ministers were at last convinced that the hour had come to aid the +Revolution. Treaties of commerce and alliance were drawn up and signed +in February, 1778. The independence of the United States was recognized +by France and an alliance was formed to guarantee that independence. +Combined military action was agreed upon and Louis then formally +declared war on England. Men who had, a few short years before, fought +one another in the wilderness of Pennsylvania or on the Plains of +Abraham, were now ranged side by side in a war on the Empire that Pitt +had erected and that George III was pulling down. + +=Spain and Holland Involved.=--Within a few months, Spain, remembering +the steady decline of her sea power since the days of the Armada and +hoping to drive the British out of Gibraltar, once more joined the +concert of nations against England. Holland, a member of a league of +armed neutrals formed in protest against British searches on the high +seas, sent her fleet to unite with the forces of Spain, France, and +America to prey upon British commerce. To all this trouble for England +was added the danger of a possible revolt in Ireland, where the spirit +of independence was flaming up. + +=The British Offer Terms to America.=--Seeing the colonists about to be +joined by France in a common war on the English empire, Lord North +proposed, in February, 1778, a renewal of negotiations. By solemn +enactment, Parliament declared its intention not to exercise the right +of imposing taxes within the colonies; at the same time it authorized +the opening of negotiations through commissioners to be sent to America. +A truce was to be established, pardons granted, objectionable laws +suspended, and the old imperial constitution, as it stood before the +opening of hostilities, restored to full vigor. It was too late. Events +had taken the affairs of America out of the hands of British +commissioners and diplomats. + +=Effects of French Aid.=--The French alliance brought ships of war, +large sums of gold and silver, loads of supplies, and a considerable +body of trained soldiers to the aid of the Americans. Timely as was this +help, it meant no sudden change in the fortunes of war. The British +evacuated Philadelphia in the summer following the alliance, and +Washington's troops were encouraged to come out of Valley Forge. They +inflicted a heavy blow on the British at Monmouth, but the treasonable +conduct of General Charles Lee prevented a triumph. The recovery of +Philadelphia was offset by the treason of Benedict Arnold, the loss of +Savannah and Charleston (1780), and the defeat of Gates at Camden. + +The full effect of the French alliance was not felt until 1781, when +Cornwallis went into Virginia and settled at Yorktown. Accompanied by +French troops Washington swept rapidly southward and penned the British +to the shore while a powerful French fleet shut off their escape by sea. +It was this movement, which certainly could not have been executed +without French aid, that put an end to all chance of restoring British +dominion in America. It was the surrender of Cornwallis at Yorktown that +caused Lord North to pace the floor and cry out: "It is all over! It is +all over!" What might have been done without the French alliance lies +hidden from mankind. What was accomplished with the help of French +soldiers, sailors, officers, money, and supplies, is known to all the +earth. "All the world agree," exultantly wrote Franklin from Paris to +General Washington, "that no expedition was ever better planned or +better executed. It brightens the glory that must accompany your name to +the latest posterity." Diplomacy as well as martial valor had its +reward. + + +PEACE AT LAST + +=British Opposition to the War.=--In measuring the forces that led to +the final discomfiture of King George and Lord North, it is necessary to +remember that from the beginning to the end the British ministry at home +faced a powerful, informed, and relentless opposition. There were +vigorous protests, first against the obnoxious acts which precipitated +the unhappy quarrel, then against the way in which the war was waged, +and finally against the futile struggle to retain a hold upon the +American dominions. Among the members of Parliament who thundered +against the government were the first statesmen and orators of the land. +William Pitt, Earl of Chatham, though he deplored the idea of American +independence, denounced the government as the aggressor and rejoiced in +American resistance. Edmund Burke leveled his heavy batteries against +every measure of coercion and at last strove for a peace which, while +giving independence to America, would work for reconciliation rather +than estrangement. Charles James Fox gave the colonies his generous +sympathy and warmly championed their rights. Outside of the circle of +statesmen there were stout friends of the American cause like David +Hume, the philosopher and historian, and Catherine Macaulay, an author +of wide fame and a republican bold enough to encourage Washington in +seeing it through. + +Against this powerful opposition, the government enlisted a whole army +of scribes and journalists to pour out criticism on the Americans and +their friends. Dr. Samuel Johnson, whom it employed in this business, +was so savage that even the ministers had to tone down his pamphlets +before printing them. Far more weighty was Edward Gibbon, who was in +time to win fame as the historian of the _Decline and Fall of the Roman +Empire_. He had at first opposed the government; but, on being given a +lucrative post, he used his sharp pen in its support, causing his +friends to ridicule him in these lines: + + "King George, in a fright + Lest Gibbon should write + The story of England's disgrace, + Thought no way so sure + His pen to secure + As to give the historian a place." + +=Lord North Yields.=--As time wore on, events bore heavily on the side +of the opponents of the government's measures. They had predicted that +conquest was impossible, and they had urged the advantages of a peace +which would in some measure restore the affections of the Americans. +Every day's news confirmed their predictions and lent support to their +arguments. Moreover, the war, which sprang out of an effort to relieve +English burdens, made those burdens heavier than ever. Military expenses +were daily increasing. Trade with the colonies, the greatest single +outlet for British goods and capital, was paralyzed. The heavy debts due +British merchants in America were not only unpaid but postponed into an +indefinite future. Ireland was on the verge of revolution. The French +had a dangerous fleet on the high seas. In vain did the king assert in +December, 1781, that no difficulties would ever make him consent to a +peace that meant American independence. Parliament knew better, and on +February 27, 1782, in the House of Commons was carried an address to the +throne against continuing the war. Burke, Fox, the younger Pitt, Barre, +and other friends of the colonies voted in the affirmative. Lord North +gave notice then that his ministry was at an end. The king moaned: +"Necessity made me yield." + +In April, 1782, Franklin received word from the English government that +it was prepared to enter into negotiations leading to a settlement. This +was embarrassing. In the treaty of alliance with France, the United +States had promised that peace should be a joint affair agreed to by +both nations in open conference. Finding France, however, opposed to +some of their claims respecting boundaries and fisheries, the American +commissioners conferred with the British agents at Paris without +consulting the French minister. They actually signed a preliminary peace +draft before they informed him of their operations. When Vergennes +reproached him, Franklin replied that they "had been guilty of +neglecting _bienseance_ [good manners] but hoped that the great work +would not be ruined by a single indiscretion." + +=The Terms of Peace (1783).=--The general settlement at Paris in 1783 +was a triumph for America. England recognized the independence of the +United States, naming each state specifically, and agreed to boundaries +extending from the Atlantic to the Mississippi and from the Great Lakes +to the Floridas. England held Canada, Newfoundland, and the West Indies +intact, made gains in India, and maintained her supremacy on the seas. +Spain won Florida and Minorca but not the coveted Gibraltar. France +gained nothing important save the satisfaction of seeing England humbled +and the colonies independent. + +The generous terms secured by the American commission at Paris called +forth surprise and gratitude in the United States and smoothed the way +for a renewal of commercial relations with the mother country. At the +same time they gave genuine anxiety to European diplomats. "This federal +republic is born a pigmy," wrote the Spanish ambassador to his royal +master. "A day will come when it will be a giant; even a colossus +formidable to these countries. Liberty of conscience and the facility +for establishing a new population on immense lands, as well as the +advantages of the new government, will draw thither farmers and artisans +from all the nations. In a few years we shall watch with grief the +tyrannical existence of the same colossus." + +[Illustration: NORTH AMERICA ACCORDING TO THE TREATY OF 1783] + + +SUMMARY OF THE REVOLUTIONARY PERIOD + +The independence of the American colonies was foreseen by many European +statesmen as they watched the growth of their population, wealth, and +power; but no one could fix the hour of the great event. Until 1763 the +American colonists lived fairly happily under British dominion. There +were collisions from time to time, of course. Royal governors clashed +with stiff-necked colonial legislatures. There were protests against the +exercise of the king's veto power in specific cases. Nevertheless, on +the whole, the relations between America and the mother country were +more amicable in 1763 than at any period under the Stuart regime which +closed in 1688. + +The crash, when it came, was not deliberately willed by any one. It was +the product of a number of forces that happened to converge about 1763. +Three years before, there had come to the throne George III, a young, +proud, inexperienced, and stubborn king. For nearly fifty years his +predecessors, Germans as they were in language and interest, had allowed +things to drift in England and America. George III decided that he would +be king in fact as well as in name. About the same time England brought +to a close the long and costly French and Indian War and was staggering +under a heavy burden of debt and taxes. The war had been fought partly +in defense of the American colonies and nothing seemed more reasonable +to English statesmen than the idea that the colonies should bear part of +the cost of their own defense. At this juncture there came into +prominence, in royal councils, two men bent on taxing America and +controlling her trade, Grenville and Townshend. The king was willing, +the English taxpayers were thankful for any promise of relief, and +statesmen were found to undertake the experiment. England therefore set +out upon a new course. She imposed taxes upon the colonists, regulated +their trade and set royal officers upon them to enforce the law. This +action evoked protests from the colonists. They held a Stamp Act +Congress to declare their rights and petition for a redress of +grievances. Some of the more restless spirits rioted in the streets, +sacked the houses of the king's officers, and tore up the stamped paper. + +Frightened by uprising, the English government drew back and repealed +the Stamp Act. Then it veered again and renewed its policy of +interference. Interference again called forth American protests. +Protests aroused sharper retaliation. More British regulars were sent +over to keep order. More irritating laws were passed by Parliament. +Rioting again appeared: tea was dumped in the harbor of Boston and +seized in the harbor of Charleston. The British answer was more force. +The response of the colonists was a Continental Congress for defense. An +unexpected and unintended clash of arms at Lexington and Concord in the +spring of 1775 brought forth from the king of England a proclamation: +"The Americans are rebels!" + +The die was cast. The American Revolution had begun. Washington was made +commander-in-chief. Armies were raised, money was borrowed, a huge +volume of paper currency was issued, and foreign aid was summoned. +Franklin plied his diplomatic arts at Paris until in 1778 he induced +France to throw her sword into the balance. Three years later, +Cornwallis surrendered at Yorktown. In 1783, by the formal treaty of +peace, George III acknowledged the independence of the United States. +The new nation, endowed with an imperial domain stretching from the +Atlantic Ocean to the Mississippi River, began its career among the +sovereign powers of the earth. + +In the sphere of civil government, the results of the Revolution were +equally remarkable. Royal officers and royal authorities were driven +from the former dominions. All power was declared to be in the people. +All the colonies became states, each with its own constitution or plan +of government. The thirteen states were united in common bonds under the +Articles of Confederation. A republic on a large scale was instituted. +Thus there was begun an adventure in popular government such as the +world had never seen. Could it succeed or was it destined to break down +and be supplanted by a monarchy? The fate of whole continents hung upon +the answer. + + +=References= + +J. Fiske, _The American Revolution_ (2 vols.). + +H. Lodge, _Life of Washington_ (2 vols.). + +W. Sumner, _The Financier and the Finances of the American Revolution_. + +O. Trevelyan, _The American Revolution_ (4 vols.). A sympathetic account +by an English historian. + +M.C. Tyler, _Literary History of the American Revolution_ (2 vols.). + +C.H. Van Tyne, _The American Revolution_ (American Nation Series) and +_The Loyalists in the American Revolution_. + + +=Questions= + +1. What was the non-importation agreement? By what body was it adopted? +Why was it revolutionary in character? + +2. Contrast the work of the first and second Continental Congresses. + +3. Why did efforts at conciliation fail? + +4. Trace the growth of American independence from opinion to the sphere +of action. + +5. Why is the Declaration of Independence an "immortal" document? + +6. What was the effect of the Revolution on colonial governments? On +national union? + +7. Describe the contest between "Patriots" and "Tories." + +8. What topics are considered under "military affairs"? Discuss each in +detail. + +9. Contrast the American forces with the British forces and show how the +war was won. + +10. Compare the work of women in the Revolutionary War with their labors +in the World War (1917-18). + +11. How was the Revolution financed? + +12. Why is diplomacy important in war? Describe the diplomatic triumph +of the Revolution. + +13. What was the nature of the opposition in England to the war? + +14. Give the events connected with the peace settlement; the terms of +peace. + + +=Research Topics= + +=The Spirit of America.=--Woodrow Wilson, _History of the American +People_, Vol. II, pp. 98-126. + +=American Rights.=--Draw up a table showing all the principles laid down +by American leaders in (1) the Resolves of the First Continental +Congress, Macdonald, _Documentary Source Book_, pp. 162-166; (2) the +Declaration of the Causes and the Necessity of Taking Up Arms, +Macdonald, pp. 176-183; and (3) the Declaration of Independence. + +=The Declaration of Independence.=--Fiske, _The American Revolution_, +Vol. I, pp. 147-197. Elson, _History of the United States_, pp. 250-254. + +=Diplomacy and the French Alliance.=--Hart, _American History Told by +Contemporaries_, Vol. II, pp. 574-590. Fiske, Vol. II, pp. 1-24. +Callender, _Economic History of the United States_, pp. 159-168; Elson, +pp. 275-280. + +=Biographical Studies.=--Washington, Franklin, Samuel Adams, Patrick +Henry, Thomas Jefferson--emphasizing the peculiar services of each. + +=The Tories.=--Hart, _Contemporaries_, Vol. II, pp. 470-480. + +=Valley Forge.=--Fiske, Vol. II, pp. 25-49. + +=The Battles of the Revolution.=--Elson, pp. 235-317. + +=An English View of the Revolution.=--Green, _Short History of England_, +Chap. X, Sect. 2. + +=English Opinion and the Revolution.=--Trevelyan, _The American +Revolution_, Vol. III (or Part 2, Vol. II), Chaps. XXIV-XXVII. + + + + +PART III. THE UNION AND NATIONAL POLITICS + + + + +CHAPTER VII + +THE FORMATION OF THE CONSTITUTION + + +THE PROMISE AND THE DIFFICULTIES OF AMERICA + +The rise of a young republic composed of thirteen states, each governed +by officials popularly elected under constitutions drafted by "the plain +people," was the most significant feature of the eighteenth century. The +majority of the patriots whose labors and sacrifices had made this +possible naturally looked upon their work and pronounced it good. Those +Americans, however, who peered beneath the surface of things, saw that +the Declaration of Independence, even if splendidly phrased, and paper +constitutions, drawn by finest enthusiasm "uninstructed by experience," +could not alone make the republic great and prosperous or even free. All +around them they saw chaos in finance and in industry and perils for the +immediate future. + +=The Weakness of the Articles of Confederation.=--The government under +the Articles of Confederation had neither the strength nor the resources +necessary to cope with the problems of reconstruction left by the war. +The sole organ of government was a Congress composed of from two to +seven members from each state chosen as the legislature might direct and +paid by the state. In determining all questions, each state had one +vote--Delaware thus enjoying the same weight as Virginia. There was no +president to enforce the laws. Congress was given power to select a +committee of thirteen--one from each state--to act as an executive body +when it was not in session; but this device, on being tried out, proved +a failure. There was no system of national courts to which citizens and +states could appeal for the protection of their rights or through which +they could compel obedience to law. The two great powers of government, +military and financial, were withheld. Congress, it is true, could +authorize expenditures but had to rely upon the states for the payment +of contributions to meet its bills. It could also order the +establishment of an army, but it could only request the states to supply +their respective quotas of soldiers. It could not lay taxes nor bring +any pressure to bear upon a single citizen in the whole country. It +could act only through the medium of the state governments. + +=Financial and Commercial Disorders.=--In the field of public finance, +the disorders were pronounced. The huge debt incurred during the war was +still outstanding. Congress was unable to pay either the interest or the +principal. Public creditors were in despair, as the market value of +their bonds sank to twenty-five or even ten cents on the dollar. The +current bills of Congress were unpaid. As some one complained, there was +not enough money in the treasury to buy pen and ink with which to record +the transactions of the shadow legislature. The currency was in utter +chaos. Millions of dollars in notes issued by Congress had become mere +trash worth a cent or two on the dollar. There was no other expression +of contempt so forceful as the popular saying: "not worth a +Continental." To make matters worse, several of the states were pouring +new streams of paper money from the press. Almost the only good money in +circulation consisted of English, French, and Spanish coins, and the +public was even defrauded by them because money changers were busy +clipping and filing away the metal. Foreign commerce was unsettled. The +entire British system of trade discrimination was turned against the +Americans, and Congress, having no power to regulate foreign commerce, +was unable to retaliate or to negotiate treaties which it could enforce. +Domestic commerce was impeded by the jealousies of the states, which +erected tariff barriers against their neighbors. The condition of the +currency made the exchange of money and goods extremely difficult, and, +as if to increase the confusion, backward states enacted laws hindering +the prompt collection of debts within their borders--an evil which +nothing but a national system of courts could cure. + +=Congress in Disrepute.=--With treaties set at naught by the states, the +laws unenforced, the treasury empty, and the public credit gone, the +Congress of the United States fell into utter disrepute. It called upon +the states to pay their quotas of money into the treasury, only to be +treated with contempt. Even its own members looked upon it as a solemn +futility. Some of the ablest men refused to accept election to it, and +many who did take the doubtful honor failed to attend the sessions. +Again and again it was impossible to secure a quorum for the transaction +of business. + +=Troubles of the State Governments.=--The state governments, free to +pursue their own course with no interference from without, had almost as +many difficulties as the Congress. They too were loaded with +revolutionary debts calling for heavy taxes upon an already restive +population. Oppressed by their financial burdens and discouraged by the +fall in prices which followed the return of peace, the farmers of +several states joined in a concerted effort and compelled their +legislatures to issue large sums of paper money. The currency fell in +value, but nevertheless it was forced on unwilling creditors to square +old accounts. + +In every part of the country legislative action fluctuated violently. +Laws were made one year only to be repealed the next and reenacted the +third year. Lands were sold by one legislature and the sales were +canceled by its successor. Uncertainty and distrust were the natural +consequences. Men of substance longed for some power that would forbid +states to issue bills of credit, to make paper money legal tender in +payment of debts, or to impair the obligation of contracts. Men heavily +in debt, on the other hand, urged even more drastic action against +creditors. + +So great did the discontent of the farmers in New Hampshire become in +1786 that a mob surrounded the legislature, demanding a repeal of the +taxes and the issuance of paper money. It was with difficulty that an +armed rebellion was avoided. In Massachusetts the malcontents, under the +leadership of Daniel Shays, a captain in the Revolutionary army, +organized that same year open resistance to the government of the state. +Shays and his followers protested against the conduct of creditors in +foreclosing mortgages upon the debt-burdened farmers, against the +lawyers for increasing the costs of legal proceedings, against the +senate of the state the members of which were apportioned among the +towns on the basis of the amount of taxes paid, against heavy taxes, and +against the refusal of the legislature to issue paper money. They seized +the towns of Worcester and Springfield and broke up the courts of +justice. All through the western part of the state the revolt spread, +sending a shock of alarm to every center and section of the young +republic. Only by the most vigorous action was Governor Bowdoin able to +quell the uprising; and when that task was accomplished, the state +government did not dare to execute any of the prisoners because they had +so many sympathizers. Moreover, Bowdoin and several members of the +legislature who had been most zealous in their attacks on the insurgents +were defeated at the ensuing election. The need of national assistance +for state governments in times of domestic violence was everywhere +emphasized by men who were opposed to revolutionary acts. + +=Alarm over Dangers to the Republic.=--Leading American citizens, +watching the drift of affairs, were slowly driven to the conclusion that +the new ship of state so proudly launched a few years before was +careening into anarchy. "The facts of our peace and independence," wrote +a friend of Washington, "do not at present wear so promising an +appearance as I had fondly painted in my mind. The prejudices, +jealousies, and turbulence of the people at times almost stagger my +confidence in our political establishments; and almost occasion me to +think that they will show themselves unworthy of the noble prize for +which we have contended." + +Washington himself was profoundly discouraged. On hearing of Shays's +rebellion, he exclaimed: "What, gracious God, is man that there should +be such inconsistency and perfidiousness in his conduct! It is but the +other day that we were shedding our blood to obtain the constitutions +under which we now live--constitutions of our own choice and making--and +now we are unsheathing our sword to overturn them." The same year he +burst out in a lament over rumors of restoring royal government. "I am +told that even respectable characters speak of a monarchical government +without horror. From thinking proceeds speaking. Hence to acting is +often but a single step. But how irresistible and tremendous! What a +triumph for our enemies to verify their predictions! What a triumph for +the advocates of despotism to find that we are incapable of governing +ourselves!" + +=Congress Attempts Some Reforms.=--The Congress was not indifferent to +the events that disturbed Washington. On the contrary it put forth many +efforts to check tendencies so dangerous to finance, commerce, +industries, and the Confederation itself. In 1781, even before the +treaty of peace was signed, the Congress, having found out how futile +were its taxing powers, carried a resolution of amendment to the +Articles of Confederation, authorizing the levy of a moderate duty on +imports. Yet this mild measure was rejected by the states. Two years +later the Congress prepared another amendment sanctioning the levy of +duties on imports, to be collected this time by state officers and +applied to the payment of the public debt. This more limited proposal, +designed to save public credit, likewise failed. In 1786, the Congress +made a third appeal to the states for help, declaring that they had been +so irregular and so negligent in paying their quotas that further +reliance upon that mode of raising revenues was dishonorable and +dangerous. + + +THE CALLING OF A CONSTITUTIONAL CONVENTION + +=Hamilton and Washington Urge Reform.=--The attempts at reform by the +Congress were accompanied by demand for, both within and without that +body, a convention to frame a new plan of government. In 1780, the +youthful Alexander Hamilton, realizing the weakness of the Articles, so +widely discussed, proposed a general convention for the purpose of +drafting a new constitution on entirely different principles. With +tireless energy he strove to bring his countrymen to his view. +Washington, agreeing with him on every point, declared, in a circular +letter to the governors, that the duration of the union would be short +unless there was lodged somewhere a supreme power "to regulate and +govern the general concerns of the confederated republic." The governor +of Massachusetts, disturbed by the growth of discontent all about him, +suggested to the state legislature in 1785 the advisability of a +national convention to enlarge the powers of the Congress. The +legislature approved the plan, but did not press it to a conclusion. + +[Illustration: ALEXANDER HAMILTON] + +=The Annapolis Convention.=--Action finally came from the South. The +Virginia legislature, taking things into its own hands, called a +conference of delegates at Annapolis to consider matters of taxation and +commerce. When the convention assembled in 1786, it was found that only +five states had taken the trouble to send representatives. The leaders +were deeply discouraged, but the resourceful Hamilton, a delegate from +New York, turned the affair to good account. He secured the adoption of +a resolution, calling upon the Congress itself to summon another +convention, to meet at Philadelphia. + +=A National Convention Called (1787).=--The Congress, as tardy as ever, +at last decided in February, 1787, to issue the call. Fearing drastic +changes, however, it restricted the convention to "the sole and express +purpose of revising the Articles of Confederation." Jealous of its own +powers, it added that any alterations proposed should be referred to the +Congress and the states for their approval. + +Every state in the union, except Rhode Island, responded to this call. +Indeed some of the states, having the Annapolis resolution before them, +had already anticipated the Congress by selecting delegates before the +formal summons came. Thus, by the persistence of governors, +legislatures, and private citizens, there was brought about the +long-desired national convention. In May, 1787, it assembled in +Philadelphia. + +=The Eminent Men of the Convention.=--On the roll of that memorable +convention were fifty-five men, at least half of whom were acknowledged +to be among the foremost statesmen and thinkers in America. Every field +of statecraft was represented by them: war and practical management in +Washington, who was chosen president of the convention; diplomacy in +Franklin, now old and full of honor in his own land as well as abroad; +finance in Alexander Hamilton and Robert Morris; law in James Wilson of +Pennsylvania; the philosophy of government in James Madison, called the +"father of the Constitution." They were not theorists but practical men, +rich in political experience and endowed with deep insight into the +springs of human action. Three of them had served in the Stamp Act +Congress: Dickinson of Delaware, William Samuel Johnson of Connecticut, +and John Rutledge of South Carolina. Eight had been signers of the +Declaration of Independence: Read of Delaware, Sherman of Connecticut, +Wythe of Virginia, Gerry of Massachusetts, Franklin, Robert Morris, +George Clymer, and James Wilson of Pennsylvania. All but twelve had at +some time served in the Continental Congress and eighteen were members +of that body in the spring of 1787. Washington, Hamilton, Mifflin, and +Charles Pinckney had been officers in the Revolutionary army. Seven of +the delegates had gained political experience as governors of states. +"The convention as a whole," according to the historian Hildreth, +"represented in a marked manner the talent, intelligence, and +especially the conservative sentiment of the country." + + +THE FRAMING OF THE CONSTITUTION + +=Problems Involved.=--The great problems before the convention were nine +in number: (1) Shall the Articles of Confederation be revised or a new +system of government constructed? (2) Shall the government be founded on +states equal in power as under the Articles or on the broader and deeper +foundation of population? (3) What direct share shall the people have in +the election of national officers? (4) What shall be the qualifications +for the suffrage? (5) How shall the conflicting interests of the +commercial and the planting states be balanced so as to safeguard the +essential rights of each? (6) What shall be the form of the new +government? (7) What powers shall be conferred on it? (8) How shall the +state legislatures be restrained from their attacks on property rights +such as the issuance of paper money? (9) Shall the approval of all the +states be necessary, as under the Articles, for the adoption and +amendment of the Constitution? + +=Revision of the Articles or a New Government?=--The moment the first +problem was raised, representatives of the small states, led by William +Paterson of New Jersey, were on their feet. They feared that, if the +Articles were overthrown, the equality and rights of the states would be +put in jeopardy. Their protest was therefore vigorous. They cited the +call issued by the Congress in summoning the convention which +specifically stated that they were assembled for "the sole and express +purpose of revising the Articles of Confederation." They cited also +their instructions from their state legislatures, which authorized them +to "revise and amend" the existing scheme of government, not to make a +revolution in it. To depart from the authorization laid down by the +Congress and the legislatures would be to exceed their powers, they +argued, and to betray the trust reposed in them by their countrymen. + +To their contentions, Randolph of Virginia replied: "When the salvation +of the republic is at stake, it would be treason to our trust not to +propose what we find necessary." Hamilton, reminding the delegates that +their work was still subject to the approval of the states, frankly said +that on the point of their powers he had no scruples. With the issue +clear, the convention cast aside the Articles as if they did not exist +and proceeded to the work of drawing up a new constitution, "laying its +foundations on such principles and organizing its powers in such form" +as to the delegates seemed "most likely to affect their safety and +happiness." + +=A Government Founded on States or on People?--The +Compromise.=--Defeated in their attempt to limit the convention to a +mere revision of the Articles, the spokesmen of the smaller states +redoubled their efforts to preserve the equality of the states. The +signal for a radical departure from the Articles on this point was given +early in the sessions when Randolph presented "the Virginia plan." He +proposed that the new national legislature consist of two houses, the +members of which were to be apportioned among the states according to +their wealth or free white population, as the convention might decide. +This plan was vehemently challenged. Paterson of New Jersey flatly +avowed that neither he nor his state would ever bow to such tyranny. As +an alternative, he presented "the New Jersey plan" calling for a +national legislature of one house representing states as such, not +wealth or people--a legislature in which all states, large or small, +would have equal voice. Wilson of Pennsylvania, on behalf of the more +populous states, took up the gauntlet which Paterson had thrown down. It +was absurd, he urged, for 180,000 men in one state to have the same +weight in national counsels as 750,000 men in another state. "The +gentleman from New Jersey," he said, "is candid. He declares his opinion +boldly.... I will be equally candid.... I will never confederate on his +principles." So the bitter controversy ran on through many exciting +sessions. + +Greek had met Greek. The convention was hopelessly deadlocked and on the +verge of dissolution, "scarce held together by the strength of a hair," +as one of the delegates remarked. A crash was averted only by a +compromise. Instead of a Congress of one house as provided by the +Articles, the convention agreed upon a legislature of two houses. In the +Senate, the aspirations of the small states were to be satisfied, for +each state was given two members in that body. In the formation of the +House of Representatives, the larger states were placated, for it was +agreed that the members of that chamber were to be apportioned among the +states on the basis of population, counting three-fifths of the slaves. + +=The Question of Popular Election.=--The method of selecting federal +officers and members of Congress also produced an acrimonious debate +which revealed how deep-seated was the distrust of the capacity of the +people to govern themselves. Few there were who believed that no branch +of the government should be elected directly by the voters; still fewer +were there, however, who desired to see all branches so chosen. One or +two even expressed a desire for a monarchy. The dangers of democracy +were stressed by Gerry of Massachusetts: "All the evils we experience +flow from an excess of democracy. The people do not want virtue but are +the dupes of pretended patriots.... I have been too republican +heretofore but have been taught by experience the danger of a leveling +spirit." To the "democratic licentiousness of the state legislatures," +Randolph sought to oppose a "firm senate." To check the excesses of +popular government Charles Pinckney of South Carolina declared that no +one should be elected President who was not worth $100,000 and that high +property qualifications should be placed on members of Congress and +judges. Other members of the convention were stoutly opposed to such +"high-toned notions of government." Franklin and Wilson, both from +Pennsylvania, vigorously championed popular election; while men like +Madison insisted that at least one part of the government should rest on +the broad foundation of the people. + +Out of this clash of opinion also came compromise. One branch, the House +of Representatives, it was agreed, was to be elected directly by the +voters, while the Senators were to be elected indirectly by the state +legislatures. The President was to be chosen by electors selected as the +legislatures of the states might determine, and the judges of the +federal courts, supreme and inferior, by the President and the Senate. + +=The Question of the Suffrage.=--The battle over the suffrage was sharp +but brief. Gouverneur Morris proposed that only land owners should be +permitted to vote. Madison replied that the state legislatures, which +had made so much trouble with radical laws, were elected by freeholders. +After the debate, the delegates, unable to agree on any property +limitations on the suffrage, decided that the House of Representatives +should be elected by voters having the "qualifications requisite for +electors of the most numerous branch of the state legislature." Thus +they accepted the suffrage provisions of the states. + +=The Balance between the Planting and the Commercial States.=--After the +debates had gone on for a few weeks, Madison came to the conclusion that +the real division in the convention was not between the large and the +small states but between the planting section founded on slave labor and +the commercial North. Thus he anticipated by nearly three-quarters of a +century "the irrepressible conflict." The planting states had neither +the free white population nor the wealth of the North. There were, +counting Delaware, six of them as against seven commercial states. +Dependent for their prosperity mainly upon the sale of tobacco, rice, +and other staples abroad, they feared that Congress might impose +restraints upon their enterprise. Being weaker in numbers, they were +afraid that the majority might lay an unfair burden of taxes upon them. + +_Representation and Taxation._--The Southern members of the convention +were therefore very anxious to secure for their section the largest +possible representation in Congress, and at the same time to restrain +the taxing power of that body. Two devices were thought adapted to these +ends. One was to count the slaves as people when apportioning +representatives among the states according to their respective +populations; the other was to provide that direct taxes should be +apportioned among the states, in proportion not to their wealth but to +the number of their free white inhabitants. For obvious reasons the +Northern delegates objected to these proposals. Once more a compromise +proved to be the solution. It was agreed that not all the slaves but +three-fifths of them should be counted for both purposes--representation +and direct taxation. + +_Commerce and the Slave Trade._--Southern interests were also involved +in the project to confer upon Congress the power to regulate interstate +and foreign commerce. To the manufacturing and trading states this was +essential. It would prevent interstate tariffs and trade jealousies; it +would enable Congress to protect American manufactures and to break +down, by appropriate retaliations, foreign discriminations against +American commerce. To the South the proposal was menacing because +tariffs might interfere with the free exchange of the produce of +plantations in European markets, and navigation acts might confine the +carrying trade to American, that is Northern, ships. The importation of +slaves, moreover, it was feared might be heavily taxed or immediately +prohibited altogether. + +The result of this and related controversies was a debate on the merits +of slavery. Gouverneur Morris delivered his mind and heart on that +subject, denouncing slavery as a nefarious institution and the curse of +heaven on the states in which it prevailed. Mason of Virginia, a +slaveholder himself, was hardly less outspoken, saying: "Slavery +discourages arts and manufactures. The poor despise labor when performed +by slaves. They prevent the migration of whites who really strengthen +and enrich a country." + +The system, however, had its defenders. Representatives from South +Carolina argued that their entire economic life rested on slave labor +and that the high death rate in the rice swamps made continuous +importation necessary. Ellsworth of Connecticut took the ground that +the convention should not meddle with slavery. "The morality or wisdom +of slavery," he said, "are considerations belonging to the states. What +enriches a part enriches the whole." To the future he turned an +untroubled face: "As population increases, poor laborers will be so +plenty as to render slaves useless. Slavery in time will not be a speck +in our country." Virginia and North Carolina, already overstocked with +slaves, favored prohibiting the traffic in them; but South Carolina was +adamant. She must have fresh supplies of slaves or she would not +federate. + +So it was agreed that, while Congress might regulate foreign trade by +majority vote, the importation of slaves should not be forbidden before +the lapse of twenty years, and that any import tax should not exceed $10 +a head. At the same time, in connection with the regulation of foreign +trade, it was stipulated that a two-thirds vote in the Senate should be +necessary in the ratification of treaties. A further concession to the +South was made in the provision for the return of runaway slaves--a +provision also useful in the North, where indentured servants were about +as troublesome as slaves in escaping from their masters. + +=The Form of the Government.=--As to the details of the frame of +government and the grand principles involved, the opinion of the +convention ebbed and flowed, decisions being taken in the heat of +debate, only to be revoked and taken again. + +_The Executive._--There was general agreement that there should be an +executive branch; for reliance upon Congress to enforce its own laws and +treaties had been a broken reed. On the character and functions of the +executive, however, there were many views. The New Jersey plan called +for a council selected by the Congress; the Virginia plan provided that +the executive branch should be chosen by the Congress but did not state +whether it should be composed of one or several persons. On this matter +the convention voted first one way and then another; finally it agreed +on a single executive chosen indirectly by electors selected as the +state legislatures might decide, serving for four years, subject to +impeachment, and endowed with regal powers in the command of the army +and the navy and in the enforcement of the laws. + +_The Legislative Branch--Congress._--After the convention had made the +great compromise between the large and small commonwealths by giving +representation to states in the Senate and to population in the House, +the question of methods of election had to be decided. As to the House +of Representatives it was readily agreed that the members should be +elected by direct popular vote. There was also easy agreement on the +proposition that a strong Senate was needed to check the "turbulence" of +the lower house. Four devices were finally selected to accomplish this +purpose. In the first place, the Senators were not to be chosen directly +by the voters but by the legislatures of the states, thus removing their +election one degree from the populace. In the second place, their term +was fixed at six years instead of two, as in the case of the House. In +the third place, provision was made for continuity by having only +one-third of the members go out at a time while two-thirds remained in +service. Finally, it was provided that Senators must be at least thirty +years old while Representatives need be only twenty-five. + +_The Judiciary._--The need for federal courts to carry out the law was +hardly open to debate. The feebleness of the Articles of Confederation +was, in a large measure, attributed to the want of a judiciary to hold +states and individuals in obedience to the laws and treaties of the +union. Nevertheless on this point the advocates of states' rights were +extremely sensitive. They looked with distrust upon judges appointed at +the national capital and emancipated from local interests and +traditions; they remembered with what insistence they had claimed +against Britain the right of local trial by jury and with what +consternation they had viewed the proposal to make colonial judges +independent of the assemblies in the matter of their salaries. +Reluctantly they yielded to the demand for federal courts, consenting at +first only to a supreme court to review cases heard in lower state +courts and finally to such additional inferior courts as Congress might +deem necessary. + +_The System of Checks and Balances._--It is thus apparent that the +framers of the Constitution, in shaping the form of government, arranged +for a distribution of power among three branches, executive, +legislative, and judicial. Strictly speaking we might say four branches, +for the legislature, or Congress, was composed of two houses, elected in +different ways, and one of them, the Senate, was made a check on the +President through its power of ratifying treaties and appointments. "The +accumulation of all powers, legislative, executive, and judicial, in the +same hands," wrote Madison, "whether of one, a few, or many, and whether +hereditary, self-appointed, or elective, may justly be pronounced the +very definition of tyranny." The devices which the convention adopted to +prevent such a centralization of authority were exceedingly ingenious +and well calculated to accomplish the purposes of the authors. + +The legislature consisted of two houses, the members of which were to be +apportioned on a different basis, elected in different ways, and to +serve for different terms. A veto on all its acts was vested in a +President elected in a manner not employed in the choice of either +branch of the legislature, serving for four years, and subject to +removal only by the difficult process of impeachment. After a law had +run the gantlet of both houses and the executive, it was subject to +interpretation and annulment by the judiciary, appointed by the +President with the consent of the Senate and serving for life. Thus it +was made almost impossible for any political party to get possession of +all branches of the government at a single popular election. As Hamilton +remarked, the friends of good government considered "every institution +calculated to restrain the excess of law making and to keep things in +the same state in which they happen to be at any given period as more +likely to do good than harm." + +=The Powers of the Federal Government.=--On the question of the powers +to be conferred upon the new government there was less occasion for a +serious dispute. Even the delegates from the small states agreed with +those from Massachusetts, Pennsylvania, and Virginia that new powers +should be added to those intrusted to Congress by the Articles of +Confederation. The New Jersey plan as well as the Virginia plan +recognized this fact. Some of the delegates, like Hamilton and Madison, +even proposed to give Congress a general legislative authority covering +all national matters; but others, frightened by the specter of +nationalism, insisted on specifying each power to be conferred and +finally carried the day. + +_Taxation and Commerce._--There were none bold enough to dissent from +the proposition that revenue must be provided to pay current expenses +and discharge the public debt. When once the dispute over the +apportionment of direct taxes among the slave states was settled, it was +an easy matter to decide that Congress should have power to lay and +collect taxes, duties, imposts, and excises. In this way the national +government was freed from dependence upon stubborn and tardy +legislatures and enabled to collect funds directly from citizens. There +were likewise none bold enough to contend that the anarchy of state +tariffs and trade discriminations should be longer endured. When the +fears of the planting states were allayed and the "bargain" over the +importation of slaves was reached, the convention vested in Congress the +power to regulate foreign and interstate commerce. + +_National Defense._--The necessity for national defense was realized, +though the fear of huge military establishments was equally present. The +old practice of relying on quotas furnished by the state legislatures +was completely discredited. As in the case of taxes a direct authority +over citizens was demanded. Congress was therefore given full power to +raise and support armies and a navy. It could employ the state militia +when desirable; but it could at the same time maintain a regular army +and call directly upon all able-bodied males if the nature of a crisis +was thought to require it. + +_The "Necessary and Proper" Clause._--To the specified power vested in +Congress by the Constitution, the advocates of a strong national +government added a general clause authorizing it to make all laws +"necessary and proper" for carrying into effect any and all of the +enumerated powers. This clause, interpreted by that master mind, Chief +Justice Marshall, was later construed to confer powers as wide as the +requirements of a vast country spanning a continent and taking its place +among the mighty nations of the earth. + +=Restraints on the States.=--Framing a government and endowing it with +large powers were by no means the sole concern of the convention. Its +very existence had been due quite as much to the conduct of the state +legislatures as to the futilities of a paralyzed Continental Congress. +In every state, explains Marshall in his _Life of Washington_, there was +a party of men who had "marked out for themselves a more indulgent +course. Viewing with extreme tenderness the case of the debtor, their +efforts were unceasingly directed to his relief. To exact a faithful +compliance with contracts was, in their opinion, a harsh measure which +the people could not bear. They were uniformly in favor of relaxing the +administration of justice, of affording facilities for the payment of +debts, or of suspending their collection, and remitting taxes." + +The legislatures under the dominance of these men had enacted paper +money laws enabling debtors to discharge their obligations more easily. +The convention put an end to such practices by providing that no state +should emit bills of credit or make anything but gold or silver legal +tender in the payment of debts. The state legislatures had enacted laws +allowing men to pay their debts by turning over to creditors land or +personal property; they had repealed the charter of an endowed college +and taken the management from the hands of the lawful trustees; and they +had otherwise interfered with the enforcement of private agreements. The +convention, taking notice of such matters, inserted a clause forbidding +states "to impair the obligation of contracts." The more venturous of +the radicals had in Massachusetts raised the standard of revolt against +the authorities of the state. The convention answered by a brief +sentence to the effect that the President of the United States, to be +equipped with a regular army, would send troops to suppress domestic +insurrections whenever called upon by the legislature or, if it was not +in session, by the governor of the state. To make sure that the +restrictions on the states would not be dead letters, the federal +Constitution, laws, and treaties were made the supreme law of the land, +to be enforced whenever necessary by a national judiciary and executive +against violations on the part of any state authorities. + +=Provisions for Ratification and Amendment.=--When the frame of +government had been determined, the powers to be vested in it had been +enumerated, and the restrictions upon the states had been written into +the bond, there remained three final questions. How shall the +Constitution be ratified? What number of states shall be necessary to +put it into effect? How shall it be amended in the future? + +On the first point, the mandate under which the convention was sitting +seemed positive. The Articles of Confederation were still in effect. +They provided that amendments could be made only by unanimous adoption +in Congress and the approval of all the states. As if to give force to +this provision of law, the call for the convention had expressly stated +that all alterations and revisions should be reported to Congress for +adoption or rejection, Congress itself to transmit the document +thereafter to the states for their review. + +To have observed the strict letter of the law would have defeated the +purposes of the delegates, because Congress and the state legislatures +were openly hostile to such drastic changes as had been made. Unanimous +ratification, as events proved, would have been impossible. Therefore +the delegates decided that the Constitution should be sent to Congress +with the recommendation that it, in turn, transmit the document, not to +the state legislatures, but to conventions held in the states for the +special object of deciding upon ratification. This process was followed. +It was their belief that special conventions would be more friendly than +the state legislatures. + +The convention was equally positive in dealing with the problem of the +number of states necessary to establish the new Constitution. Attempts +to change the Articles had failed because amendment required the +approval of every state and there was always at least one recalcitrant +member of the union. The opposition to a new Constitution was +undoubtedly formidable. Rhode Island had even refused to take part in +framing it, and her hostility was deep and open. So the convention cast +aside the provision of the Articles of Confederation which required +unanimous approval for any change in the plan of government; it decreed +that the new Constitution should go into effect when ratified by nine +states. + +In providing for future changes in the Constitution itself the +convention also thrust aside the old rule of unanimous approval, and +decided that an amendment could be made on a two-thirds vote in both +houses of Congress and ratification by three-fourths of the states. This +change was of profound significance. Every state agreed to be bound in +the future by amendments duly adopted even in case it did not approve +them itself. America in this way set out upon the high road that led +from a league of states to a nation. + + +THE STRUGGLE OVER RATIFICATION + +On September 17, 1787, the Constitution, having been finally drafted in +clear and simple language, a model to all makers of fundamental law, was +adopted. The convention, after nearly four months of debate in secret +session, flung open the doors and presented to the Americans the +finished plan for the new government. Then the great debate passed to +the people. + +=The Opposition.=--Storms of criticism at once descended upon the +Constitution. "Fraudulent usurpation!" exclaimed Gerry, who had refused +to sign it. "A monster" out of the "thick veil of secrecy," declaimed a +Pennsylvania newspaper. "An iron-handed despotism will be the result," +protested a third. "We, 'the low-born,'" sarcastically wrote a fourth, +"will now admit the 'six hundred well-born' immediately to establish +this most noble, most excellent, and truly divine constitution." The +President will become a king; Congress will be as tyrannical as +Parliament in the old days; the states will be swallowed up; the rights +of the people will be trampled upon; the poor man's justice will be lost +in the endless delays of the federal courts--such was the strain of the +protests against ratification. + +[Illustration: AN ADVERTISEMENT OF _The Federalist_] + +=Defense of the Constitution.=--Moved by the tempest of opposition, +Hamilton, Madison, and Jay took up their pens in defense of the +Constitution. In a series of newspaper articles they discussed and +expounded with eloquence, learning, and dignity every important clause +and provision of the proposed plan. These papers, afterwards collected +and published in a volume known as _The Federalist_, form the finest +textbook on the Constitution that has ever been printed. It takes its +place, moreover, among the wisest and weightiest treatises on government +ever written in any language in any time. Other men, not so gifted, were +no less earnest in their support of ratification. In private +correspondence, editorials, pamphlets, and letters to the newspapers, +they urged their countrymen to forget their partisanship and accept a +Constitution which, in spite of any defects great or small, was the +only guarantee against dissolution and warfare at home and dishonor and +weakness abroad. + +[Illustration: CELEBRATING THE RATIFICATION] + +=The Action of the State Conventions.=--Before the end of the year, +1787, three states had ratified the Constitution: Delaware and New +Jersey unanimously and Pennsylvania after a short, though savage, +contest. Connecticut and Georgia followed early the next year. Then came +the battle royal in Massachusetts, ending in ratification in February by +the narrow margin of 187 votes to 168. In the spring came the news that +Maryland and South Carolina were "under the new roof." On June 21, New +Hampshire, where the sentiment was at first strong enough to defeat the +Constitution, joined the new republic, influenced by the favorable +decision in Massachusetts. Swift couriers were sent to carry the news to +New York and Virginia, where the question of ratification was still +undecided. Nine states had accepted it and were united, whether more saw +fit to join or not. + +Meanwhile, however, Virginia, after a long and searching debate, had +given her approval by a narrow margin, leaving New York as the next seat +of anxiety. In that state the popular vote for the delegates to the +convention had been clearly and heavily against ratification. Events +finally demonstrated the futility of resistance, and Hamilton by good +judgment and masterly arguments was at last able to marshal a majority +of thirty to twenty-seven votes in favor of ratification. + +The great contest was over. All the states, except North Carolina and +Rhode Island, had ratified. "The sloop Anarchy," wrote an ebullient +journalist, "when last heard from was ashore on Union rocks." + +=The First Election.=--In the autumn of 1788, elections were held to +fill the places in the new government. Public opinion was overwhelmingly +in favor of Washington as the first President. Yielding to the +importunities of friends, he accepted the post in the spirit of public +service. On April 30, 1789, he took the oath of office at Federal Hall +in New York City. "Long live George Washington, President of the United +States!" cried Chancellor Livingston as soon as the General had kissed +the Bible. The cry was caught by the assembled multitude and given back. +A new experiment in popular government was launched. + + +=References= + +M. Farrand, _The Framing of the Constitution of the United States_. + +P.L. Ford, _Essays on the Constitution of the United States_. + +_The Federalist_ (in many editions). + +G. Hunt, _Life of James Madison_. + +A.C. McLaughlin, _The Confederation and the Constitution_ (American +Nation Series). + + +=Questions= + +1. Account for the failure of the Articles of Confederation. + +2. Explain the domestic difficulties of the individual states. + +3. Why did efforts at reform by the Congress come to naught? + +4. Narrate the events leading up to the constitutional convention. + +5. Who were some of the leading men in the convention? What had been +their previous training? + +6. State the great problems before the convention. + +7. In what respects were the planting and commercial states opposed? +What compromises were reached? + +8. Show how the "check and balance" system is embodied in our form of +government. + +9. How did the powers conferred upon the federal government help cure +the defects of the Articles of Confederation? + +10. In what way did the provisions for ratifying and amending the +Constitution depart from the old system? + +11. What was the nature of the conflict over ratification? + + +=Research Topics= + +=English Treatment of American Commerce.=--Callender, _Economic History +of the United States_, pp. 210-220. + +=Financial Condition of the United States.=--Fiske, _Critical Period of +American History_, pp. 163-186. + +=Disordered Commerce.=--Fiske, pp. 134-162. + +=Selfish Conduct of the States.=--Callender, pp. 185-191. + +=The Failure of the Confederation.=--Elson, _History of the United +States_, pp. 318-326. + +=Formation of the Constitution.=--(1) The plans before the convention, +Fiske, pp. 236-249; (2) the great compromise, Fiske, pp. 250-255; (3) +slavery and the convention, Fiske, pp. 256-266; and (4) the frame of +government, Fiske, pp. 275-301; Elson, pp. 328-334. + +=Biographical Studies.=--Look up the history and services of the leaders +in the convention in any good encyclopedia. + +=Ratification of the Constitution.=--Hart, _History Told by +Contemporaries_, Vol. III, pp. 233-254; Elson, pp. 334-340. + +=Source Study.=--Compare the Constitution and Articles of Confederation +under the following heads: (1) frame of government; (2) powers of +Congress; (3) limits on states; and (4) methods of amendment. Every line +of the Constitution should be read and re-read in the light of the +historical circumstances set forth in this chapter. + + + + +CHAPTER VIII + +THE CLASH OF POLITICAL PARTIES + + +THE MEN AND MEASURES OF THE NEW GOVERNMENT + +=Friends of the Constitution in Power.=--In the first Congress that +assembled after the adoption of the Constitution, there were eleven +Senators, led by Robert Morris, the financier, who had been delegates to +the national convention. Several members of the House of +Representatives, headed by James Madison, had also been at Philadelphia +in 1787. In making his appointments, Washington strengthened the new +system of government still further by a judicious selection of +officials. He chose as Secretary of the Treasury, Alexander Hamilton, +who had been the most zealous for its success; General Knox, head of the +War Department, and Edmund Randolph, the Attorney-General, were likewise +conspicuous friends of the experiment. Every member of the federal +judiciary whom Washington appointed, from the Chief Justice, John Jay, +down to the justices of the district courts, had favored the +ratification of the Constitution; and a majority of them had served as +members of the national convention that framed the document or of the +state ratifying conventions. Only one man of influence in the new +government, Thomas Jefferson, the Secretary of State, was reckoned as a +doubter in the house of the faithful. He had expressed opinions both for +and against the Constitution; but he had been out of the country acting +as the minister at Paris when the Constitution was drafted and ratified. + +=An Opposition to Conciliate.=--The inauguration of Washington amid the +plaudits of his countrymen did not set at rest all the political turmoil +which had been aroused by the angry contest over ratification. "The +interesting nature of the question," wrote John Marshall, "the equality +of the parties, the animation produced inevitably by ardent debate had a +necessary tendency to embitter the dispositions of the vanquished and to +fix more deeply in many bosoms their prejudices against a plan of +government in opposition to which all their passions were enlisted." The +leaders gathered around Washington were well aware of the excited state +of the country. They saw Rhode Island and North Carolina still outside +of the union.[1] They knew by what small margins the Constitution had +been approved in the great states of Massachusetts, Virginia, and New +York. They were equally aware that a majority of the state conventions, +in yielding reluctant approval to the Constitution, had drawn a number +of amendments for immediate submission to the states. + +=The First Amendments--a Bill of Rights.=--To meet the opposition, +Madison proposed, and the first Congress adopted, a series of amendments +to the Constitution. Ten of them were soon ratified and became in 1791 a +part of the law of the land. These amendments provided, among other +things, that Congress could make no law respecting the establishment of +religion, abridging the freedom of speech or of the press or the right +of the people peaceably to assemble and petition the government for a +redress of grievances. They also guaranteed indictment by grand jury and +trial by jury for all persons charged by federal officers with serious +crimes. To reassure those who still feared that local rights might be +invaded by the federal government, the tenth amendment expressly +provided that the powers not delegated to the United States by the +Constitution, nor prohibited by it to the states, are reserved to the +states respectively or to the people. Seven years later, the eleventh +amendment was written in the same spirit as the first ten, after a +heated debate over the action of the Supreme Court in permitting a +citizen to bring a suit against "the sovereign state" of Georgia. The +new amendment was designed to protect states against the federal +judiciary by forbidding it to hear any case in which a state was sued by +a citizen. + +=Funding the National Debt.=--Paper declarations of rights, however, +paid no bills. To this task Hamilton turned all his splendid genius. At +the very outset he addressed himself to the problem of the huge public +debt, daily mounting as the unpaid interest accumulated. In a _Report on +Public Credit_ under date of January 9, 1790, one of the first and +greatest of American state papers, he laid before Congress the outlines +of his plan. He proposed that the federal government should call in all +the old bonds, certificates of indebtedness, and other promises to pay +which had been issued by the Congress since the beginning of the +Revolution. These national obligations, he urged, should be put into one +consolidated debt resting on the credit of the United States; to the +holders of the old paper should be issued new bonds drawing interest at +fixed rates. This process was called "funding the debt." Such a +provision for the support of public credit, Hamilton insisted, would +satisfy creditors, restore landed property to its former value, and +furnish new resources to agriculture and commerce in the form of credit +and capital. + +=Assumption and Funding of State Debts.=--Hamilton then turned to the +obligations incurred by the several states in support of the Revolution. +These debts he proposed to add to the national debt. They were to be +"assumed" by the United States government and placed on the same secure +foundation as the continental debt. This measure he defended not merely +on grounds of national honor. It would, as he foresaw, give strength to +the new national government by making all public creditors, men of +substance in their several communities, look to the federal, rather than +the state government, for the satisfaction of their claims. + +=Funding at Face Value.=--On the question of the terms of consolidation, +assumption, and funding, Hamilton had a firm conviction. That millions +of dollars' worth of the continental and state bonds had passed out of +the hands of those who had originally subscribed their funds to the +support of the government or had sold supplies for the Revolutionary +army was well known. It was also a matter of common knowledge that a +very large part of these bonds had been bought by speculators at ruinous +figures--ten, twenty, and thirty cents on the dollar. Accordingly, it +had been suggested, even in very respectable quarters, that a +discrimination should be made between original holders and speculative +purchasers. Some who held this opinion urged that the speculators who +had paid nominal sums for their bonds should be reimbursed for their +outlays and the original holders paid the difference; others said that +the government should "scale the debt" by redeeming, not at full value +but at a figure reasonably above the market price. Against the +proposition Hamilton set his face like flint. He maintained that the +government was honestly bound to redeem every bond at its face value, +although the difficulty of securing revenue made necessary a lower rate +of interest on a part of the bonds and the deferring of interest on +another part. + +=Funding and Assumption Carried.=--There was little difficulty in +securing the approval of both houses of Congress for the funding of the +national debt at full value. The bill for the assumption of state debts, +however, brought the sharpest division of opinions. To the Southern +members of Congress assumption was a gross violation of states' rights, +without any warrant in the Constitution and devised in the interest of +Northern speculators who, anticipating assumption and funding, had +bought up at low prices the Southern bonds and other promises to pay. +New England, on the other hand, was strongly in favor of assumption; +several representatives from that section were rash enough to threaten a +dissolution of the union if the bill was defeated. To this dispute was +added an equally bitter quarrel over the location of the national +capital, then temporarily at New York City. + +[Illustration: FIRST UNITED STATES BANK AT PHILADELPHIA] + +A deadlock, accompanied by the most surly feelings on both sides, +threatened the very existence of the young government. Washington and +Hamilton were thoroughly alarmed. Hearing of the extremity to which the +contest had been carried and acting on the appeal from the Secretary of +the Treasury, Jefferson intervened at this point. By skillful management +at a good dinner he brought the opposing leaders together; and thus once +more, as on many other occasions, peace was purchased and the union +saved by compromise. The bargain this time consisted of an exchange of +votes for assumption in return for votes for the capital. Enough +Southern members voted for assumption to pass the bill, and a majority +was mustered in favor of building the capital on the banks of the +Potomac, after locating it for a ten-year period at Philadelphia to +satisfy Pennsylvania members. + +=The United States Bank.=--Encouraged by the success of his funding and +assumption measures, Hamilton laid before Congress a project for a great +United States Bank. He proposed that a private corporation be chartered +by Congress, authorized to raise a capital stock of $10,000,000 +(three-fourths in new six per cent federal bonds and one-fourth in +specie) and empowered to issue paper currency under proper safeguards. +Many advantages, Hamilton contended, would accrue to the government from +this institution. The price of the government bonds would be increased, +thus enhancing public credit. A national currency would be created of +uniform value from one end of the land to the other. The branches of the +bank in various cities would make easy the exchange of funds so vital to +commercial transactions on a national scale. Finally, through the issue +of bank notes, the money capital available for agriculture and industry +would be increased, thus stimulating business enterprise. Jefferson +hotly attacked the bank on the ground that Congress had no power +whatever under the Constitution to charter such a private corporation. +Hamilton defended it with great cogency. Washington, after weighing all +opinions, decided in favor of the proposal. In 1791 the bill +establishing the first United States Bank for a period of twenty years +became a law. + +=The Protective Tariff.=--A third part of Hamilton's program was the +protection of American industries. The first revenue act of 1789, though +designed primarily to bring money into the empty treasury, declared in +favor of the principle. The following year Washington referred to the +subject in his address to Congress. Thereupon Hamilton was instructed to +prepare recommendations for legislative action. The result, after a +delay of more than a year, was his _Report on Manufactures_, another +state paper worthy, in closeness of reasoning and keenness of +understanding, of a place beside his report on public credit. Hamilton +based his argument on the broadest national grounds: the protective +tariff would, by encouraging the building of factories, create a home +market for the produce of farms and plantations; by making the United +States independent of other countries in times of peace, it would double +its security in time of war; by making use of the labor of women and +children, it would turn to the production of goods persons otherwise +idle or only partly employed; by increasing the trade between the North +and South it would strengthen the links of union and add to political +ties those of commerce and intercourse. The revenue measure of 1792 bore +the impress of these arguments. + + +THE RISE OF POLITICAL PARTIES + +=Dissensions over Hamilton's Measures.=--Hamilton's plans, touching +deeply as they did the resources of individuals and the interests of the +states, awakened alarm and opposition. Funding at face value, said his +critics, was a government favor to speculators; the assumption of state +debts was a deep design to undermine the state governments; Congress had +no constitutional power to create a bank; the law creating the bank +merely allowed a private corporation to make paper money and lend it at +a high rate of interest; and the tariff was a tax on land and labor for +the benefit of manufacturers. + +Hamilton's reply to this bill of indictment was simple and +straightforward. Some rascally speculators had profited from the funding +of the debt at face value, but that was only an incident in the +restoration of public credit. In view of the jealousies of the states it +was a good thing to reduce their powers and pretensions. The +Constitution was not to be interpreted narrowly but in the full light of +national needs. The bank would enlarge the amount of capital so sorely +needed to start up American industries, giving markets to farmers and +planters. The tariff by creating a home market and increasing +opportunities for employment would benefit both land and labor. Out of +such wise policies firmly pursued by the government, he concluded, were +bound to come strength and prosperity for the new government at home, +credit and power abroad. This view Washington fully indorsed, adding +the weight of his great name to the inherent merits of the measures +adopted under his administration. + +=The Sharpness of the Partisan Conflict.=--As a result of the clash of +opinion, the people of the country gradually divided into two parties: +Federalists and Anti-Federalists, the former led by Hamilton, the latter +by Jefferson. The strength of the Federalists lay in the cities--Boston, +Providence, Hartford, New York, Philadelphia, Charleston--among the +manufacturing, financial, and commercial groups of the population who +were eager to extend their business operations. The strength of the +Anti-Federalists lay mainly among the debt-burdened farmers who feared +the growth of what they called "a money power" and planters in all +sections who feared the dominance of commercial and manufacturing +interests. The farming and planting South, outside of the few towns, +finally presented an almost solid front against assumption, the bank, +and the tariff. The conflict between the parties grew steadily in +bitterness, despite the conciliatory and engaging manner in which +Hamilton presented his cause in his state papers and despite the +constant efforts of Washington to soften the asperity of the +contestants. + +=The Leadership and Doctrines of Jefferson.=--The party dispute had not +gone far before the opponents of the administration began to look to +Jefferson as their leader. Some of Hamilton's measures he had approved, +declaring afterward that he did not at the time understand their +significance. Others, particularly the bank, he fiercely assailed. More +than once, he and Hamilton, shaking violently with anger, attacked each +other at cabinet meetings, and nothing short of the grave and dignified +pleas of Washington prevented an early and open break between them. In +1794 it finally came. Jefferson resigned as Secretary of State and +retired to his home in Virginia to assume, through correspondence and +negotiation, the leadership of the steadily growing party of opposition. + +Shy and modest in manner, halting in speech, disliking the turmoil of +public debate, and deeply interested in science and philosophy, +Jefferson was not very well fitted for the strenuous life of political +contest. Nevertheless, he was an ambitious and shrewd negotiator. He was +also by honest opinion and matured conviction the exact opposite of +Hamilton. The latter believed in a strong, active, "high-toned" +government, vigorously compelling in all its branches. Jefferson looked +upon such government as dangerous to the liberties of citizens and +openly avowed his faith in the desirability of occasional popular +uprisings. Hamilton distrusted the people. "Your people is a great +beast," he is reported to have said. Jefferson professed his faith in +the people with an abandon that was considered reckless in his time. + +On economic matters, the opinions of the two leaders were also +hopelessly at variance. Hamilton, while cherishing agriculture, desired +to see America a great commercial and industrial nation. Jefferson was +equally set against this course for his country. He feared the +accumulation of riches and the growth of a large urban working class. +The mobs of great cities, he said, are sores on the body politic; +artisans are usually the dangerous element that make revolutions; +workshops should be kept in Europe and with them the artisans with their +insidious morals and manners. The only substantial foundation for a +republic, Jefferson believed to be agriculture. The spirit of +independence could be kept alive only by free farmers, owning the land +they tilled and looking to the sun in heaven and the labor of their +hands for their sustenance. Trusting as he did in the innate goodness of +human nature when nourished on a free soil, Jefferson advocated those +measures calculated to favor agriculture and to enlarge the rights of +persons rather than the powers of government. Thus he became the +champion of the individual against the interference of the government, +and an ardent advocate of freedom of the press, freedom of speech, and +freedom of scientific inquiry. It was, accordingly, no mere factious +spirit that drove him into opposition to Hamilton. + +=The Whisky Rebellion.=--The political agitation of the Anti-Federalists +was accompanied by an armed revolt against the government in 1794. The +occasion for this uprising was another of Hamilton's measures, a law +laying an excise tax on distilled spirits, for the purpose of increasing +the revenue needed to pay the interest on the funded debt. It so +happened that a very considerable part of the whisky manufactured in the +country was made by the farmers, especially on the frontier, in their +own stills. The new revenue law meant that federal officers would now +come into the homes of the people, measure their liquor, and take the +tax out of their pockets. All the bitterness which farmers felt against +the fiscal measures of the government was redoubled. In the western +districts of Pennsylvania, Virginia, and North Carolina, they refused to +pay the tax. In Pennsylvania, some of them sacked and burned the houses +of the tax collectors, as the Revolutionists thirty years before had +mobbed the agents of King George sent over to sell stamps. They were in +a fair way to nullify the law in whole districts when Washington called +out the troops to suppress "the Whisky Rebellion." Then the movement +collapsed; but it left behind a deep-seated resentment which flared up +in the election of several obdurate Anti-Federalist Congressmen from the +disaffected regions. + + +FOREIGN INFLUENCES AND DOMESTIC POLITICS + +=The French Revolution.=--In this exciting period, when all America was +distracted by partisan disputes, a storm broke in Europe--the +epoch-making French Revolution--which not only shook the thrones of the +Old World but stirred to its depths the young republic of the New World. +The first scene in this dramatic affair occurred in the spring of 1789, +a few days after Washington was inaugurated. The king of France, Louis +XVI, driven into bankruptcy by extravagance and costly wars, was forced +to resort to his people for financial help. Accordingly he called, for +the first time in more than one hundred fifty years, a meeting of the +national parliament, the "Estates General," composed of representatives +of the "three estates"--the clergy, nobility, and commoners. Acting +under powerful leaders, the commoners, or "third estate," swept aside +the clergy and nobility and resolved themselves into a national +assembly. This stirred the country to its depths. + +[Illustration: _From an old print_ + +LOUIS XVI IN THE HANDS OF THE MOB] + +Great events followed in swift succession. On July 14, 1789, the +Bastille, an old royal prison, symbol of the king's absolutism, was +stormed by a Paris crowd and destroyed. On the night of August 4, the +feudal privileges of the nobility were abolished by the national +assembly amid great excitement. A few days later came the famous +Declaration of the Rights of Man, proclaiming the sovereignty of the +people and the privileges of citizens. In the autumn of 1791, Louis XVI +was forced to accept a new constitution for France vesting the +legislative power in a popular assembly. Little disorder accompanied +these startling changes. To all appearances a peaceful revolution had +stripped the French king of his royal prerogatives and based the +government of his country on the consent of the governed. + +=American Influence in France.=--In undertaking their great political +revolt the French had been encouraged by the outcome of the American +Revolution. Officers and soldiers, who had served in the American war, +reported to their French countrymen marvelous tales. At the frugal table +of General Washington, in council with the unpretentious Franklin, or at +conferences over the strategy of war, French noblemen of ancient lineage +learned to respect both the talents and the simple character of the +leaders in the great republican commonwealth beyond the seas. Travelers, +who had gone to see the experiment in republicanism with their own eyes, +carried home to the king and ruling class stories of an astounding +system of popular government. + +On the other hand the dalliance with American democracy was regarded by +French conservatives as playing with fire. "When we think of the false +ideas of government and philanthropy," wrote one of Lafayette's aides, +"which these youths acquired in America and propagated in France with so +much enthusiasm and such deplorable success--for this mania of imitation +powerfully aided the Revolution, though it was not the sole cause of +it--we are bound to confess that it would have been better, both for +themselves and for us, if these young philosophers in red-heeled shoes +had stayed at home in attendance on the court." + +=Early American Opinion of the French Revolution.=--So close were the +ties between the two nations that it is not surprising to find every +step in the first stages of the French Revolution greeted with applause +in the United States. "Liberty will have another feather in her cap," +exultantly wrote a Boston editor. "In no part of the globe," soberly +wrote John Marshall, "was this revolution hailed with more joy than in +America.... But one sentiment existed." The main key to the Bastille, +sent to Washington as a memento, was accepted as "a token of the +victory gained by liberty." Thomas Paine saw in the great event "the +first ripe fruits of American principles transplanted into Europe." +Federalists and Anti-Federalists regarded the new constitution of France +as another vindication of American ideals. + +=The Reign of Terror.=--While profuse congratulations were being +exchanged, rumors began to come that all was not well in France. Many +noblemen, enraged at the loss of their special privileges, fled into +Germany and plotted an invasion of France to overthrow the new system of +government. Louis XVI entered into negotiations with his brother +monarchs on the continent to secure their help in the same enterprise, +and he finally betrayed to the French people his true sentiments by +attempting to escape from his kingdom, only to be captured and taken +back to Paris in disgrace. + +A new phase of the revolution now opened. The working people, excluded +from all share in the government by the first French constitution, +became restless, especially in Paris. Assembling on the Champs de Mars, +a great open field, they signed a petition calling for another +constitution giving them the suffrage. When told to disperse, they +refused and were fired upon by the national guard. This "massacre," as +it was called, enraged the populace. A radical party, known as +"Jacobins," then sprang up, taking its name from a Jacobin monastery in +which it held its sessions. In a little while it became the master of +the popular convention convoked in September, 1792. The monarchy was +immediately abolished and a republic established. On January 21, 1793, +Louis was sent to the scaffold. To the war on Austria, already raging, +was added a war on England. Then came the Reign of Terror, during which +radicals in possession of the convention executed in large numbers +counter-revolutionists and those suspected of sympathy with the +monarchy. They shot down peasants who rose in insurrection against their +rule and established a relentless dictatorship. Civil war followed. +Terrible atrocities were committed on both sides in the name of liberty, +and in the name of monarchy. To Americans of conservative temper it now +seemed that the Revolution, so auspiciously begun, had degenerated into +anarchy and mere bloodthirsty strife. + +=Burke Summons the World to War on France.=--In England, Edmund Burke +led the fight against the new French principles which he feared might +spread to all Europe. In his _Reflections on the French Revolution_, +written in 1790, he attacked with terrible wrath the whole program of +popular government; he called for war, relentless war, upon the French +as monsters and outlaws; he demanded that they be reduced to order by +the restoration of the king to full power under the protection of the +arms of European nations. + +=Paine's Defense of the French Revolution.=--To counteract the campaign +of hate against the French, Thomas Paine replied to Burke in another of +his famous tracts, _The Rights of Man_, which was given to the American +public in an edition containing a letter of approval from Jefferson. +Burke, said Paine, had been mourning about the glories of the French +monarchy and aristocracy but had forgotten the starving peasants and the +oppressed people; had wept over the plumage and neglected the dying +bird. Burke had denied the right of the French people to choose their +own governors, blandly forgetting that the English government in which +he saw final perfection itself rested on two revolutions. He had boasted +that the king of England held his crown in contempt of the democratic +societies. Paine answered: "If I ask a man in America if he wants a +king, he retorts and asks me if I take him for an idiot." To the charge +that the doctrines of the rights of man were "new fangled," Paine +replied that the question was not whether they were new or old but +whether they were right or wrong. As to the French disorders and +difficulties, he bade the world wait to see what would be brought forth +in due time. + +=The Effect of the French Revolution on American Politics.=--The course +of the French Revolution and the controversies accompanying it, +exercised a profound influence on the formation of the first political +parties in America. The followers of Hamilton, now proud of the name +"Federalists," drew back in fright as they heard of the cruel deeds +committed during the Reign of Terror. They turned savagely upon the +revolutionists and their friends in America, denouncing as "Jacobin" +everybody who did not condemn loudly enough the proceedings of the +French Republic. A Massachusetts preacher roundly assailed "the +atheistical, anarchical, and in other respects immoral principles of the +French Republicans"; he then proceeded with equal passion to attack +Jefferson and the Anti-Federalists, whom he charged with spreading false +French propaganda and betraying America. "The editors, patrons, and +abettors of these vehicles of slander," he exclaimed, "ought to be +considered and treated as enemies to their country.... Of all traitors +they are the most aggravatedly criminal; of all villains, they are the +most infamous and detestable." + +The Anti-Federalists, as a matter of fact, were generally favorable to +the Revolution although they deplored many of the events associated with +it. Paine's pamphlet, indorsed by Jefferson, was widely read. Democratic +societies, after the fashion of French political clubs, arose in the +cities; the coalition of European monarchs against France was denounced +as a coalition against the very principles of republicanism; and the +execution of Louis XVI was openly celebrated at a banquet in +Philadelphia. Harmless titles, such as "Sir," "the Honorable," and "His +Excellency," were decried as aristocratic and some of the more excited +insisted on adopting the French title, "Citizen," speaking, for example, +of "Citizen Judge" and "Citizen Toastmaster." Pamphlets in defense of +the French streamed from the press, while subsidized newspapers kept the +propaganda in full swing. + +=The European War Disturbs American Commerce.=--This battle of wits, or +rather contest in calumny, might have gone on indefinitely in America +without producing any serious results, had it not been for the war +between England and France, then raging. The English, having command of +the seas, claimed the right to seize American produce bound for French +ports and to confiscate American ships engaged in carrying French goods. +Adding fuel to a fire already hot enough, they began to search American +ships and to carry off British-born sailors found on board American +vessels. + +=The French Appeal for Help.=--At the same time the French Republic +turned to the United States for aid in its war on England and sent over +as its diplomatic representative "Citizen" Genet, an ardent supporter of +the new order. On his arrival at Charleston, he was greeted with fervor +by the Anti-Federalists. As he made his way North, he was wined and +dined and given popular ovations that turned his head. He thought the +whole country was ready to join the French Republic in its contest with +England. Genet therefore attempted to use the American ports as the base +of operations for French privateers preying on British merchant ships; +and he insisted that the United States was in honor bound to help France +under the treaty of 1778. + +=The Proclamation of Neutrality and the Jay Treaty.=--Unmoved by the + +rising tide of popular sympathy for France, Washington took a firm +course. He received Genet coldly. The demand that the United States aid +France under the old treaty of alliance he answered by proclaiming the +neutrality of America and warning American citizens against hostile acts +toward either France or England. When Genet continued to hold meetings, +issue manifestoes, and stir up the people against England, Washington +asked the French government to recall him. This act he followed up by +sending the Chief Justice, John Jay, on a pacific mission to England. + +The result was the celebrated Jay treaty of 1794. By its terms Great +Britain agreed to withdraw her troops from the western forts where they +had been since the war for independence and to grant certain slight +trade concessions. The chief sources of bitterness--the failure of the +British to return slaves carried off during the Revolution, the seizure +of American ships, and the impressment of sailors--were not touched, +much to the distress of everybody in America, including loyal +Federalists. Nevertheless, Washington, dreading an armed conflict with +England, urged the Senate to ratify the treaty. The weight of his +influence carried the day. + +At this, the hostility of the Anti-Federalists knew no bounds. Jefferson +declared the Jay treaty "an infamous act which is really nothing more +than an alliance between England and the Anglo-men of this country, +against the legislature and the people of the United States." Hamilton, +defending it with his usual courage, was stoned by a mob in New York and +driven from the platform with blood streaming from his face. Jay was +burned in effigy. Even Washington was not spared. The House of +Representatives was openly hostile. To display its feelings, it called +upon the President for the papers relative to the treaty negotiations, +only to be more highly incensed by his flat refusal to present them, on +the ground that the House did not share in the treaty-making power. + +=Washington Retires from Politics.=--Such angry contests confirmed the +President in his slowly maturing determination to retire at the end of +his second term in office. He did not believe that a third term was +unconstitutional or improper; but, worn out by his long and arduous +labors in war and in peace and wounded by harsh attacks from former +friends, he longed for the quiet of his beautiful estate at Mount +Vernon. + +In September, 1796, on the eve of the presidential election, Washington +issued his Farewell Address, another state paper to be treasured and +read by generations of Americans to come. In this address he directed +the attention of the people to three subjects of lasting interest. He +warned them against sectional jealousies. He remonstrated against the +spirit of partisanship, saying that in government "of the popular +character, in government purely elective, it is a spirit not to be +encouraged." He likewise cautioned the people against "the insidious +wiles of foreign influence," saying: "Europe has a set of primary +interests which to us have none or a very remote relation. Hence she +must be engaged in frequent controversies, the causes of which are +essentially foreign to our concerns. Hence, therefore, it would be +unwise in us to implicate ourselves, by artificial ties, in the ordinary +vicissitudes of her politics or the ordinary combinations and collisions +of her friendships or enmities.... Why forego the advantages of so +peculiar a situation?... It is our true policy to steer clear of +permanent alliances with any portion of the foreign world.... Taking +care always to keep ourselves, by suitable establishments, on a +respectable defensive posture, we may safely trust to temporary +alliances for extraordinary emergencies." + +=The Campaign of 1796--Adams Elected.=--On hearing of the retirement of +Washington, the Anti-Federalists cast off all restraints. In honor of +France and in opposition to what they were pleased to call the +monarchical tendencies of the Federalists, they boldly assumed the name +"Republican"; the term "Democrat," then applied only to obscure and +despised radicals, had not come into general use. They selected +Jefferson as their candidate for President against John Adams, the +Federalist nominee, and carried on such a spirited campaign that they +came within four votes of electing him. + +The successful candidate, Adams, was not fitted by training or opinion +for conciliating a determined opposition. He was a reserved and studious +man. He was neither a good speaker nor a skillful negotiator. In one of +his books he had declared himself in favor of "government by an +aristocracy of talents and wealth"--an offense which the Republicans +never forgave. While John Marshall found him "a sensible, plain, candid, +good-tempered man," Jefferson could see in him nothing but a "monocrat" +and "Anglo-man." Had it not been for the conduct of the French +government, Adams would hardly have enjoyed a moment's genuine +popularity during his administration. + +=The Quarrel with France.=--The French Directory, the executive +department established under the constitution of 1795, managed, however, +to stir the anger of Republicans and Federalists alike. It regarded the +Jay treaty as a rebuke to France and a flagrant violation of obligations +solemnly registered in the treaty of 1778. Accordingly it refused to +receive the American minister, treated him in a humiliating way, and +finally told him to leave the country. Overlooking this affront in his +anxiety to maintain peace, Adams dispatched to France a commission of +eminent men with instructions to reach an understanding with the French +Republic. On their arrival, they were chagrined to find, instead of a +decent reception, an indirect demand for an apology respecting the past +conduct of the American government, a payment in cash, and an annual +tribute as the price of continued friendship. When the news of this +affair reached President Adams, he promptly laid it before Congress, +referring to the Frenchmen who had made the demands as "Mr. X, Mr. Y, +and Mr. Z." + +This insult, coupled with the fact that French privateers, like the +British, were preying upon American commerce, enraged even the +Republicans who had been loudest in the profession of their French +sympathies. They forgot their wrath over the Jay treaty and joined with +the Federalists in shouting: "Millions for defense, not a cent for +tribute!" Preparations for war were made on every hand. Washington was +once more called from Mount Vernon to take his old position at the head +of the army. Indeed, fighting actually began upon the high seas and went +on without a formal declaration of war until the year 1800. By that time +the Directory had been overthrown. A treaty was readily made with +Napoleon, the First Consul, who was beginning his remarkable career as +chief of the French Republic, soon to be turned into an empire. + +=Alien and Sedition Laws.=--Flushed with success, the Federalists +determined, if possible, to put an end to radical French influence in +America and to silence Republican opposition. They therefore passed two +drastic laws in the summer of 1798: the Alien and Sedition Acts. + +The first of these measures empowered the President to expel from the +country or to imprison any alien whom he regarded as "dangerous" or "had +reasonable grounds to suspect" of "any treasonable or secret +machinations against the government." + +The second of the measures, the Sedition Act, penalized not only those +who attempted to stir up unlawful combinations against the government +but also every one who wrote, uttered, or published "any false, +scandalous, and malicious writing ... against the government of the +United States or either House of Congress, or the President of the +United States, with intent to defame said government ... or to bring +them or either of them into contempt or disrepute." This measure was +hurried through Congress in spite of the opposition and the clear +provision in the Constitution that Congress shall make no law abridging +the freedom of speech or of the press. Even many Federalists feared the +consequences of the action. Hamilton was alarmed when he read the bill, +exclaiming: "Let us not establish a tyranny. Energy is a very different +thing from violence." John Marshall told his friends in Virginia that, +had he been in Congress, he would have opposed the two bills because he +thought them "useless" and "calculated to create unnecessary discontents +and jealousies." + +The Alien law was not enforced; but it gave great offense to the Irish +and French whose activities against the American government's policy +respecting Great Britain put them in danger of prison. The Sedition law, +on the other hand, was vigorously applied. Several editors of Republican +newspapers soon found themselves in jail or broken by ruinous fines for +their caustic criticisms of the Federalist President and his policies. +Bystanders at political meetings, who uttered sentiments which, though +ungenerous and severe, seem harmless enough now, were hurried before +Federalist judges and promptly fined and imprisoned. Although the +prosecutions were not numerous, they aroused a keen resentment. The +Republicans were convinced that their political opponents, having +saddled upon the country Hamilton's fiscal system and the British +treaty, were bent on silencing all censure. The measures therefore had +exactly the opposite effect from that which their authors intended. +Instead of helping the Federalist party, they made criticism of it more +bitter than ever. + +=The Kentucky and Virginia Resolutions.=--Jefferson was quick to take +advantage of the discontent. He drafted a set of resolutions declaring +the Sedition law null and void, as violating the federal Constitution. +His resolutions were passed by the Kentucky legislature late in 1798, +signed by the governor, and transmitted to the other states for their +consideration. Though receiving unfavorable replies from a number of +Northern states, Kentucky the following year reaffirmed its position and +declared that the nullification of all unconstitutional acts of Congress +was the rightful remedy to be used by the states in the redress of +grievances. It thus defied the federal government and announced a +doctrine hostile to nationality and fraught with terrible meaning for +the future. In the neighboring state of Virginia, Madison led a movement +against the Alien and Sedition laws. He induced the legislature to pass +resolutions condemning the acts as unconstitutional and calling upon the +other states to take proper means to preserve their rights and the +rights of the people. + +=The Republican Triumph in 1800.=--Thus the way was prepared for the +election of 1800. The Republicans left no stone unturned in their +efforts to place on the Federalist candidate, President Adams, all the +odium of the Alien and Sedition laws, in addition to responsibility for +approving Hamilton's measures and policies. The Federalists, divided in +councils and cold in their affection for Adams, made a poor campaign. +They tried to discredit their opponents with epithets of "Jacobins" and +"Anarchists"--terms which had been weakened by excessive use. When the +vote was counted, it was found that Adams had been defeated; while the +Republicans had carried the entire South and New York also and secured +eight of the fifteen electoral votes cast by Pennsylvania. "Our beloved +Adams will now close his bright career," lamented a Federalist +newspaper. "Sons of faction, demagogues and high priests of anarchy, now +you have cause to triumph!" + +[Illustration: _An old cartoon_ + +A QUARREL BETWEEN A FEDERALIST AND A REPUBLICAN IN THE HOUSE OF +REPRESENTATIVES] + +Jefferson's election, however, was still uncertain. By a curious +provision in the Constitution, presidential electors were required to +vote for two persons without indicating which office each was to fill, +the one receiving the highest number of votes to be President and the +candidate standing next to be Vice President. It so happened that Aaron +Burr, the Republican candidate for Vice President, had received the same +number of votes as Jefferson; as neither had a majority the election was +thrown into the House of Representatives, where the Federalists held the +balance of power. Although it was well known that Burr was not even a +candidate for President, his friends and many Federalists began +intriguing for his election to that high office. Had it not been for the +vigorous action of Hamilton the prize might have been snatched out of +Jefferson's hands. Not until the thirty-sixth ballot on February 17, +1801, was the great issue decided in his favor.[2] + + +=References= + +J.S. Bassett, _The Federalist System_ (American Nation Series). + +C.A. Beard, _Economic Origins of Jeffersonian Democracy_. + +H. Lodge, _Alexander Hamilton_. + +J.T. Morse, _Thomas Jefferson_. + + +=Questions= + +1. Who were the leaders in the first administration under the +Constitution? + +2. What step was taken to appease the opposition? + +3. Enumerate Hamilton's great measures and explain each in detail. + +4. Show the connection between the parts of Hamilton's system. + +5. Contrast the general political views of Hamilton and Jefferson. + +6. What were the important results of the "peaceful" French Revolution +(1789-92)? + +7. Explain the interaction of opinion between France and the United +States. + +8. How did the "Reign of Terror" change American opinion? + +9. What was the Burke-Paine controversy? + +10. Show how the war in Europe affected American commerce and involved +America with England and France. + +11. What were American policies with regard to each of those countries? + +12. What was the outcome of the Alien and Sedition Acts? + + +=Research Topics= + +=Early Federal Legislation.=--Coman, _Industrial History of the United +States_, pp. 133-156; Elson, _History of the United States_, pp. +341-348. + +=Hamilton's Report on Public Credit.=--Macdonald, _Documentary Source +Book_, pp. 233-243. + +=The French Revolution.=--Robinson and Beard, _Development of Modern +Europe_, Vol. I, pp. 224-282; Elson, pp. 351-354. + +=The Burke-Paine Controversy.=--Make an analysis of Burke's _Reflections +on the French Revolution_ and Paine's _Rights of Man_. + +=The Alien and Sedition Acts.=--Macdonald, _Documentary Source Book_, +pp. 259-267; Elson, pp. 367-375. + +=Kentucky and Virginia Resolutions.=--Macdonald, pp. 267-278. + +=Source Studies.=--Materials in Hart, _American History Told by +Contemporaries_, Vol. III, pp. 255-343. + +=Biographical Studies.=--Alexander Hamilton, John Adams, Thomas +Jefferson, and Albert Gallatin. + +=The Twelfth Amendment.=--Contrast the provision in the original +Constitution with the terms of the Amendment. _See_ Appendix. + +FOOTNOTES: + +[1] North Carolina ratified in November, 1789, and Rhode Island in May, +1790. + +[2] To prevent a repetition of such an unfortunate affair, the twelfth +amendment of the Constitution was adopted in 1804, changing slightly the +method of electing the President. + + + + +CHAPTER IX + +THE JEFFERSONIAN REPUBLICANS IN POWER + + +REPUBLICAN PRINCIPLES AND POLICIES + +=Opposition to Strong Central Government.=--Cherishing especially the +agricultural interest, as Jefferson said, the Republicans were in the +beginning provincial in their concern and outlook. Their attachment to +America was, certainly, as strong as that of Hamilton; but they regarded +the state, rather than the national government, as the proper center of +power and affection. Indeed, a large part of the rank and file had been +among the opponents of the Constitution in the days of its adoption. +Jefferson had entertained doubts about it and Monroe, destined to be the +fifth President, had been one of the bitter foes of ratification. The +former went so far in the direction of local autonomy that he exalted +the state above the nation in the Kentucky resolutions of 1798, +declaring the Constitution to be a mere compact and the states competent +to interpret and nullify federal law. This was provincialism with a +vengeance. "It is jealousy, not confidence, which prescribes limited +constitutions," wrote Jefferson for the Kentucky legislature. Jealousy +of the national government, not confidence in it--this is the ideal that +reflected the provincial and agricultural interest. + +=Republican Simplicity.=--Every act of the Jeffersonian party during its +early days of power was in accord with the ideals of government which it +professed. It had opposed all pomp and ceremony, calculated to give +weight and dignity to the chief executive of the nation, as symbols of +monarchy and high prerogative. Appropriately, therefore, Jefferson's +inauguration on March 4, 1801, the first at the new capital at +Washington, was marked by extreme simplicity. In keeping with this +procedure he quit the practice, followed by Washington and Adams, of +reading presidential addresses to Congress in joint assembly and adopted +in its stead the plan of sending his messages in writing--a custom that +was continued unbroken until 1913 when President Wilson returned to the +example set by the first chief magistrate. + +=Republican Measures.=--The Republicans had complained of a great +national debt as the source of a dangerous "money power," giving +strength to the federal government; accordingly they began to pay it off +as rapidly as possible. They had held commerce in low esteem and looked +upon a large navy as a mere device to protect it; consequently they +reduced the number of warships. They had objected to excise taxes, +particularly on whisky; these they quickly abolished, to the intense +satisfaction of the farmers. They had protested against the heavy cost +of the federal government; they reduced expenses by discharging hundreds +of men from the army and abolishing many offices. + +They had savagely criticized the Sedition law and Jefferson refused to +enforce it. They had been deeply offended by the assault on freedom of +speech and press and they promptly impeached Samuel Chase, a justice of +the Supreme Court, who had been especially severe in his attacks upon +offenders under the Sedition Act. Their failure to convict Justice Chase +by a narrow margin was due to no lack of zeal on their part but to the +Federalist strength in the Senate where the trial was held. They had +regarded the appointment of a large number of federal judges during the +last hours of Adams' administration as an attempt to intrench +Federalists in the judiciary and to enlarge the sphere of the national +government. Accordingly, they at once repealed the act creating the new +judgeships, thus depriving the "midnight appointees" of their posts. +They had considered the federal offices, civil and military, as sources +of great strength to the Federalists and Jefferson, though committed to +the principle that offices should be open to all and distributed +according to merit, was careful to fill most of the vacancies as they +occurred with trusted Republicans. To his credit, however, it must be +said that he did not make wholesale removals to find room for party +workers. + +The Republicans thus hewed to the line of their general policy of +restricting the weight, dignity, and activity of the national +government. Yet there were no Republicans, as the Federalists asserted, +prepared to urge serious modifications in the Constitution. "If there be +any among us who wish to dissolve this union or to change its republican +form," wrote Jefferson in his first inaugural, "let them stand +undisturbed as monuments of the safety with which error of opinion may +be tolerated where reason is left free to combat it." After reciting the +fortunate circumstances of climate, soil, and isolation which made the +future of America so full of promise, Jefferson concluded: "A wise and +frugal government which shall restrain men from injuring one another, +shall leave them otherwise free to regulate their own pursuits of +industry and improvement and shall not take from the mouth of labour the +bread it has earned. This is the sum of good government; and this is +necessary to close the circle of our felicities." + +In all this the Republicans had not reckoned with destiny. In a few +short years that lay ahead it was their fate to double the territory of +the country, making inevitable a continental nation; to give the +Constitution a generous interpretation that shocked many a Federalist; +to wage war on behalf of American commerce; to reestablish the hated +United States Bank; to enact a high protective tariff; to see their +Federalist opponents in their turn discredited as nullifiers and +provincials; to announce high national doctrines in foreign affairs; and +to behold the Constitution exalted and defended against the pretensions +of states by a son of old Virginia, John Marshall, Chief Justice of the +Supreme Court of the United States. + + +THE REPUBLICANS AND THE GREAT WEST + +=Expansion and Land Hunger.=--The first of the great measures which +drove the Republicans out upon this new national course--the purchase +of the Louisiana territory--was the product of circumstances rather than +of their deliberate choosing. It was not the lack of land for his +cherished farmers that led Jefferson to add such an immense domain to +the original possessions of the United States. In the Northwest +territory, now embracing Ohio, Indiana, Illinois, Michigan, Wisconsin, +and a portion of Minnesota, settlements were mainly confined to the +north bank of the Ohio River. To the south, in Kentucky and Tennessee, +where there were more than one hundred thousand white people who had +pushed over the mountains from Virginia and the Carolinas, there were +still wide reaches of untilled soil. The Alabama and Mississippi regions +were vast Indian frontiers of the state of Georgia, unsettled and almost +unexplored. Even to the wildest imagination there seemed to be territory +enough to satisfy the land hunger of the American people for a century +to come. + +=The Significance of the Mississippi River.=--At all events the East, +then the center of power, saw no good reason for expansion. The planters +of the Carolinas, the manufacturers of Pennsylvania, the importers of +New York, the shipbuilders of New England, looking to the seaboard and +to Europe for trade, refinements, and sometimes their ideas of +government, were slow to appreciate the place of the West in national +economy. The better educated the Easterners were, the less, it seems, +they comprehended the destiny of the nation. Sons of Federalist fathers +at Williams College, after a long debate decided by a vote of fifteen to +one that the purchase of Louisiana was undesirable. + +On the other hand, the pioneers of Kentucky, Ohio, and Tennessee, +unlearned in books, saw with their own eyes the resources of the +wilderness. Many of them had been across the Mississippi and had beheld +the rich lands awaiting the plow of the white man. Down the great river +they floated their wheat, corn, and bacon to ocean-going ships bound for +the ports of the seaboard or for Europe. The land journeys over the +mountain barriers with bulky farm produce, they knew from experience, +were almost impossible, and costly at best. Nails, bolts of cloth, tea, +and coffee could go or come that way, but not corn and bacon. A free +outlet to the sea by the Mississippi was as essential to the pioneers of +the Kentucky region as the harbor of Boston to the merchant princes of +that metropolis. + +=Louisiana under Spanish Rule.=--For this reason they watched with deep +solicitude the fortunes of the Spanish king to whom, at the close of the +Seven Years' War, had fallen the Louisiana territory stretching from New +Orleans to the Rocky Mountains. While he controlled the mouth of the +Mississippi there was little to fear, for he had neither the army nor +the navy necessary to resist any invasion of American trade. Moreover, +Washington had been able, by the exercise of great tact, to secure from +Spain in 1795 a trading privilege through New Orleans which satisfied +the present requirements of the frontiersmen even if it did not allay +their fears for the future. So things stood when a swift succession of +events altered the whole situation. + +=Louisiana Transferred to France.=--In July, 1802, a royal order from +Spain instructed the officials at New Orleans to close the port to +American produce. About the same time a disturbing rumor, long current, +was confirmed--Napoleon had coerced Spain into returning Louisiana to +France by a secret treaty signed in 1800. "The scalers of the Alps and +conquerors of Venice" now looked across the sea for new scenes of +adventure. The West was ablaze with excitement. A call for war ran +through the frontier; expeditions were organized to prevent the landing +of the French; and petitions for instant action flooded in upon +Jefferson. + +=Jefferson Sees the Danger.=--Jefferson, the friend of France and sworn +enemy of England, compelled to choose in the interest of America, never +winced. "The cession of Louisiana and the Floridas by Spain to France," +he wrote to Livingston, the American minister in Paris, "works sorely on +the United States. It completely reverses all the political relations of +the United States and will form a new epoch in our political course.... +There is on the globe one single spot, the possessor of which is our +natural and habitual enemy. It is New Orleans through which the produce +of three-eighths of our territory must pass to market.... France, +placing herself in that door, assumes to us an attitude of defiance. +Spain might have retained it quietly for years. Her pacific +dispositions, her feeble state would induce her to increase our +facilities there.... Not so can it ever be in the hands of France.... +The day that France takes possession of New Orleans fixes the sentence +which is to restrain her forever within her low water mark.... It seals +the union of the two nations who in conjunction can maintain exclusive +possession of the ocean. From that moment we must marry ourselves to the +British fleet and nation.... This is not a state of things we seek or +desire. It is one which this measure, if adopted by France, forces on us +as necessarily as any other cause by the laws of nature brings on its +necessary effect." + +=Louisiana Purchased.=--Acting on this belief, but apparently seeing +only the Mississippi outlet at stake, Jefferson sent his friend, James +Monroe, to France with the power to buy New Orleans and West Florida. +Before Monroe arrived, the regular minister, Livingston, had already +convinced Napoleon that it would be well to sell territory which might +be wrested from him at any moment by the British sea power, especially +as the war, temporarily stopped by the peace of Amiens, was once more +raging in Europe. Wise as he was in his day, Livingston had at first no +thought of buying the whole Louisiana country. He was simply dazed when +Napoleon offered to sell the entire domain and get rid of the business +altogether. Though staggered by the proposal, he and Monroe decided to +accept. On April 30, they signed the treaty of cession, agreeing to pay +$11,250,000 in six per cent bonds and to discharge certain debts due +French citizens, making in all approximately fifteen millions. Spain +protested, Napoleon's brother fumed, French newspapers objected; but the +deed was done. + +=Jefferson and His Constitutional Scruples.=--When the news of this +extraordinary event reached the United States, the people were filled +with astonishment, and no one was more surprised than Jefferson himself. +He had thought of buying New Orleans and West Florida for a small sum, +and now a vast domain had been dumped into the lap of the nation. He was +puzzled. On looking into the Constitution he found not a line +authorizing the purchase of more territory and so he drafted an +amendment declaring "Louisiana, as ceded by France,--a part of the +United States." He had belabored the Federalists for piling up a big +national debt and he could hardly endure the thought of issuing more +bonds himself. + +In the midst of his doubts came the news that Napoleon might withdraw +from the bargain. Thoroughly alarmed by that, Jefferson pressed the +Senate for a ratification of the treaty. He still clung to his original +idea that the Constitution did not warrant the purchase; but he lamely +concluded: "If our friends shall think differently, I shall certainly +acquiesce with satisfaction; confident that the good sense of our +country will correct the evil of construction when it shall produce ill +effects." Thus the stanch advocate of "strict interpretation" cut loose +from his own doctrine and intrusted the construction of the Constitution +to "the good sense" of his countrymen. + +=The Treaty Ratified.=--This unusual transaction, so favorable to the +West, aroused the ire of the seaboard Federalists. Some denounced it as +unconstitutional, easily forgetting Hamilton's masterly defense of the +bank, also not mentioned in the Constitution. Others urged that, if "the +howling wilderness" ever should be settled, it would turn against the +East, form new commercial connections, and escape from federal control. +Still others protested that the purchase would lead inevitably to the +dominance of a "hotch potch of wild men from the Far West." Federalists, +who thought "the broad back of America" could readily bear Hamilton's +consolidated debt, now went into agonies over a bond issue of less than +one-sixth of that amount. But in vain. Jefferson's party with a high +hand carried the day. The Senate, after hearing the Federalist protest, +ratified the treaty. In December, 1803, the French flag was hauled down +from the old government buildings in New Orleans and the Stars and +Stripes were hoisted as a sign that the land of Coronado, De Soto, +Marquette, and La Salle had passed forever to the United States. + +[Illustration: THE UNITED STATES IN 1805] + +By a single stroke, the original territory of the United States was more +than doubled. While the boundaries of the purchase were uncertain, it is +safe to say that the Louisiana territory included what is now Arkansas, +Missouri, Iowa, Oklahoma, Kansas, Nebraska, South Dakota, and large +portions of Louisiana, Minnesota, North Dakota, Colorado, Montana, and +Wyoming. The farm lands that the friends of "a little America" on the +seacoast declared a hopeless wilderness were, within a hundred years, +fully occupied and valued at nearly seven billion dollars--almost five +hundred times the price paid to Napoleon. + +=Western Explorations.=--Having taken the fateful step, Jefferson wisely +began to make the most of it. He prepared for the opening of the new +country by sending the Lewis and Clark expedition to explore it, +discover its resources, and lay out an overland route through the +Missouri Valley and across the Great Divide to the Pacific. The story of +this mighty exploit, which began in the spring of 1804 and ended in the +autumn of 1806, was set down with skill and pains in the journal of +Lewis and Clark; when published even in a short form, it invited the +forward-looking men of the East to take thought about the western +empire. At the same time Zebulon Pike, in a series of journeys, explored +the sources of the Mississippi River and penetrated the Spanish +territories of the far Southwest. Thus scouts and pioneers continued the +work of diplomats. + + +THE REPUBLICAN WAR FOR COMMERCIAL INDEPENDENCE + +=The English and French Blockades.=--In addition to bringing Louisiana +to the United States, the reopening of the European War in 1803, after a +short lull, renewed in an acute form the commercial difficulties that +had plagued the country all during the administrations of Washington and +Adams. The Republicans were now plunged into the hornets' nest. The +party whose ardent spirits had burned Jay in effigy, stoned Hamilton for +defending his treaty, jeered Washington's proclamation of neutrality, +and spoken bitterly of "timid traders," could no longer take refuge in +criticism. It had to act. + +Its troubles took a serious turn in 1806. England, in a determined +effort to bring France to her knees by starvation, declared the coast of +Europe blockaded from Brest to the mouth of the Elbe River. Napoleon +retaliated by his Berlin Decree of November, 1806, blockading the +British Isles--a measure terrifying to American ship owners whose +vessels were liable to seizure by any French rover, though Napoleon had +no navy to make good his proclamation. Great Britain countered with a +still more irritating decree--the Orders in Council of 1807. It modified +its blockade, but in so doing merely authorized American ships not +carrying munitions of war to complete their voyage to the Continent, on +condition of their stopping at a British port, securing a license, and +paying a tax. This, responded Napoleon, was the height of insolence, and +he denounced it as a gross violation of international law. He then +closed the circle of American troubles by issuing his Milan Decree of +December, 1807. This order declared that any ship which complied with +the British rules would be subject to seizure and confiscation by French +authorities. + +=The Impressment of Seamen.=--That was not all. Great Britain, in dire +need of men for her navy, adopted the practice of stopping American +ships, searching them, and carrying away British-born sailors found on +board. British sailors were so badly treated, so cruelly flogged for +trivial causes, and so meanly fed that they fled in crowds to the +American marine. In many cases it was difficult to tell whether seamen +were English or American. They spoke the same language, so that language +was no test. Rovers on the deep and stragglers in the ports of both +countries, they frequently had no papers to show their nativity. +Moreover, Great Britain held to the old rule--"Once an Englishman, +always an Englishman"--a doctrine rejected by the United States in +favor of the principle that a man could choose the nation to which he +would give allegiance. British sea captains, sometimes by mistake, and +often enough with reckless indifference, carried away into servitude in +their own navy genuine American citizens. The process itself, even when +executed with all the civilities of law, was painful enough, for it +meant that American ships were forced to "come to," and compelled to +rest submissively under British guns until the searching party had pried +into records, questioned seamen, seized and handcuffed victims. Saints +could not have done this work without raising angry passions, and only +saints could have endured it with patience and fortitude. + +Had the enactment of the scenes been confined to the high seas and +knowledge of them to rumors and newspaper stories, American resentment +might not have been so intense; but many a search and seizure was made +in sight of land. British and French vessels patrolled the coasts, +firing on one another and chasing one another in American waters within +the three-mile limit. When, in the summer of 1807, the American frigate +_Chesapeake_ refused to surrender men alleged to be deserters from King +George's navy, the British warship _Leopard_ opened fire, killing three +men and wounding eighteen more--an act which even the British ministry +could hardly excuse. If the French were less frequently the offenders, +it was not because of their tenderness about American rights but because +so few of their ships escaped the hawk-eyed British navy to operate in +American waters. + +=The Losses in American Commerce.=--This high-handed conduct on the part +of European belligerents was very injurious to American trade. By their +enterprise, American shippers had become the foremost carriers on the +Atlantic Ocean. In a decade they had doubled the tonnage of American +merchant ships under the American flag, taking the place of the French +marine when Britain swept that from the seas, and supplying Britain with +the sinews of war for the contest with the Napoleonic empire. The +American shipping engaged in foreign trade embraced 363,110 tons in +1791; 669,921 tons in 1800; and almost 1,000,000 tons in 1810. Such was +the enterprise attacked by the British and French decrees. American +ships bound for Great Britain were liable to be captured by French +privateers which, in spite of the disasters of the Nile and Trafalgar, +ranged the seas. American ships destined for the Continent, if they +failed to stop at British ports and pay tribute, were in great danger of +capture by the sleepless British navy and its swarm of auxiliaries. +American sea captains who, in fear of British vengeance, heeded the +Orders in Council and paid the tax were almost certain to fall a prey to +French vengeance, for the French were vigorous in executing the Milan +Decree. + +=Jefferson's Policy.=--The President's dilemma was distressing. Both the +belligerents in Europe were guilty of depredations on American commerce. +War on both of them was out of the question. War on France was +impossible because she had no territory on this side of the water which +could be reached by American troops and her naval forces had been +shattered at the battles of the Nile and Trafalgar. War on Great +Britain, a power which Jefferson's followers feared and distrusted, was +possible but not inviting. Jefferson shrank from it. A man of peace, he +disliked war's brazen clamor; a man of kindly spirit, he was startled at +the death and destruction which it brought in its train. So for the +eight years Jefferson steered an even course, suggesting measure after +measure with a view to avoiding bloodshed. He sent, it is true, +Commodore Preble in 1803 to punish Mediterranean pirates preying upon +American commerce; but a great war he evaded with passionate +earnestness, trying in its place every other expedient to protect +American rights. + +=The Embargo and Non-intercourse Acts.=--In 1806, Congress passed and +Jefferson approved a non-importation act closing American ports to +certain products from British dominions--a measure intended as a club +over the British government's head. This law, failing in its purpose, +Jefferson proposed and Congress adopted in December, 1807, the Embargo +Act forbidding all vessels to leave American harbors for foreign ports. +France and England were to be brought to terms by cutting off their +supplies. + +The result of the embargo was pathetic. England and France refused to +give up search and seizure. American ship owners who, lured by huge +profits, had formerly been willing to take the risk were now restrained +by law to their home ports. Every section suffered. The South and West +found their markets for cotton, rice, tobacco, corn, and bacon +curtailed. Thus they learned by bitter experience the national +significance of commerce. Ship masters, ship builders, longshoremen, and +sailors were thrown out of employment while the prices of foreign goods +doubled. Those who obeyed the law were ruined; violators of the law +smuggled goods into Canada and Florida for shipment abroad. + +Jefferson's friends accepted the medicine with a wry face as the only +alternative to supine submission or open war. His opponents, without +offering any solution of their own, denounced it as a contemptible plan +that brought neither relief nor honor. Beset by the clamor that arose on +all sides, Congress, in the closing days of Jefferson's administration, +repealed the Embargo law and substituted a Non-intercourse act +forbidding trade with England and France while permitting it with other +countries--a measure equally futile in staying the depredations on +American shipping. + +=Jefferson Retires in Favor of Madison.=--Jefferson, exhausted by +endless wrangling and wounded, as Washington had been, by savage +criticism, welcomed March 4, 1809. His friends urged him to "stay by the +ship" and accept a third term. He declined, saying that election for +life might result from repeated reelection. In following Washington's +course and defending it on principle, he set an example to all his +successors, making the "third term doctrine" a part of American +unwritten law. + +His intimate friend, James Madison, to whom he turned over the burdens +of his high office was, like himself, a man of peace. Madison had been a +leader since the days of the Revolution, but in legislative halls and +council chambers, not on the field of battle. Small in stature, +sensitive in feelings, studious in habits, he was no man for the rough +and tumble of practical politics. He had taken a prominent and +distinguished part in the framing and the adoption of the Constitution. +He had served in the first Congress as a friend of Hamilton's measures. +Later he attached himself to Jefferson's fortunes and served for eight +years as his first counselor, the Secretary of State. The principles of +the Constitution, which he had helped to make and interpret, he was now +as President called upon to apply in one of the most perplexing moments +in all American history. In keeping with his own traditions and +following in the footsteps of Jefferson, he vainly tried to solve the +foreign problem by negotiation. + +=The Trend of Events.=--Whatever difficulties Madison had in making up +his mind on war and peace were settled by events beyond his own control. +In the spring of 1811, a British frigate held up an American ship near +the harbor of New York and impressed a seaman alleged to be an American +citizen. Burning with resentment, the captain of the _President_, an +American warship, acting under orders, poured several broadsides into +the _Little Belt_, a British sloop, suspected of being the guilty party. +The British also encouraged the Indian chief Tecumseh, who welded +together the Indians of the Northwest under British protection and gave +signs of restlessness presaging a revolt. This sent a note of alarm +along the frontier that was not checked even when, in November, +Tecumseh's men were badly beaten at Tippecanoe by William Henry +Harrison. The Indians stood in the way of the advancing frontier, and it +seemed to the pioneers that, without support from the British in Canada, +the Red Men would soon be subdued. + +=Clay and Calhoun.=--While events were moving swiftly and rumors were +flying thick and fast, the mastery of the government passed from the +uncertain hands of Madison to a party of ardent young men in Congress, +dubbed "Young Republicans," under the leadership of two members destined +to be mighty figures in American history: Henry Clay of Kentucky and +John C. Calhoun of South Carolina. The former contended, in a flair of +folly, that "the militia of Kentucky alone are competent to place +Montreal and Upper Canada at your feet." The latter with a light heart +spoke of conquering Canada in a four weeks' campaign. "It must not be +inferred," says Channing, "that in advocating conquest, the Westerners +were actuated merely by desire for land; they welcomed war because they + +thought it would be the easiest way to abate Indian troubles. The +savages were supported by the fur-trading interests that centred at +Quebec and London.... The Southerners on their part wished for Florida +and they thought that the conquest of Canada would obviate some Northern +opposition to this acquisition of slave territory." While Clay and +Calhoun, spokesmen of the West and South, were not unmindful of what +Napoleon had done to American commerce, they knew that their followers +still remembered with deep gratitude the aid of the French in the war +for independence and that the embers of the old hatred for George III, +still on the throne, could be readily blown into flame. + +=Madison Accepts War as Inevitable.=--The conduct of the British +ministers with whom Madison had to deal did little to encourage him in +adhering to the policy of "watchful waiting." One of them, a high Tory, +believed that all Americans were alike "except that a few are less +knaves than others" and his methods were colored by his belief. On the +recall of this minister the British government selected another no less +high and mighty in his principles and opinions. So Madison became +thoroughly discouraged about the outcome of pacific measures. When the +pressure from Congress upon him became too heavy, he gave way, signing +on June 18, 1812, the declaration of war on Great Britain. In +proclaiming hostilities, the administration set forth the causes which +justified the declaration; namely, the British had been encouraging the +Indians to attack American citizens on the frontier; they had ruined +American trade by blockades; they had insulted the American flag by +stopping and searching our ships; they had illegally seized American +sailors and driven them into the British navy. + +=The Course of the War.=--The war lasted for nearly three years without +bringing victory to either side. The surrender of Detroit by General +Hull to the British and the failure of the American invasion of Canada +were offset by Perry's victory on Lake Erie and a decisive blow +administered to British designs for an invasion of New York by way of +Plattsburgh. The triumph of Jackson at New Orleans helped to atone for +the humiliation suffered in the burning of the Capitol by the British. +The stirring deeds of the _Constitution_, the _United States_, and the +_Argus_ on the seas, the heroic death of Lawrence and the victories of a +hundred privateers furnished consolation for those who suffered from the +iron blockade finally established by the British government when it came +to appreciate the gravity of the situation. While men love the annals of +the sea, they will turn to the running battles, the narrow escapes, and +the reckless daring of American sailors in that naval contest with Great +Britain. + +All this was exciting but it was inconclusive. In fact, never was a +government less prepared than was that of the United States in 1812. It +had neither the disciplined troops, the ships of war, nor the supplies +required by the magnitude of the military task. It was fortune that +favored the American cause. Great Britain, harassed, worn, and +financially embarrassed by nearly twenty years of fighting in Europe, +was in no mood to gather her forces for a titanic effort in America even +after Napoleon was overthrown and sent into exile at Elba in the spring +of 1814. War clouds still hung on the European horizon and the conflict +temporarily halted did again break out. To be rid of American anxieties +and free for European eventualities, England was ready to settle with +the United States, especially as that could be done without conceding +anything or surrendering any claims. + +=The Treaty of Peace.=--Both countries were in truth sick of a war that +offered neither glory nor profit. Having indulged in the usual +diplomatic skirmishing, they sent representatives to Ghent to discuss +terms of peace. After long negotiations an agreement was reached on +Christmas eve, 1814, a few days before Jackson's victory at New Orleans. +When the treaty reached America the people were surprised to find that +it said nothing about the seizure of American sailors, the destruction +of American trade, the searching of American ships, or the support of +Indians on the frontier. Nevertheless, we are told, the people "passed +from gloom to glory" when the news of peace arrived. The bells were +rung; schools were closed; flags were displayed; and many a rousing +toast was drunk in tavern and private home. The rejoicing could +continue. With Napoleon definitely beaten at Waterloo in June, 1815, +Great Britain had no need to impress sailors, search ships, and +confiscate American goods bound to the Continent. Once more the terrible +sea power sank into the background and the ocean was again white with +the sails of merchantmen. + + +THE REPUBLICANS NATIONALIZED + +=The Federalists Discredited.=--By a strange turn of fortune's wheel, +the party of Hamilton, Washington, Adams, the party of the grand nation, +became the party of provincialism and nullification. New England, +finding its shipping interests crippled in the European conflict and +then penalized by embargoes, opposed the declaration of war on Great +Britain, which meant the completion of the ruin already begun. In the +course of the struggle, the Federalist leaders came perilously near to +treason in their efforts to hamper the government of the United States; +and in their desperation they fell back upon the doctrine of +nullification so recently condemned by them when it came from Kentucky. +The Senate of Massachusetts, while the war was in progress, resolved +that it was waged "without justifiable cause," and refused to approve +military and naval projects not connected with "the defense of our +seacoast and soil." A Boston newspaper declared that the union was +nothing but a treaty among sovereign states, that states could decide +for themselves the question of obeying federal law, and that armed +resistance under the banner of a state would not be rebellion or +treason. The general assembly of Connecticut reminded the administration +at Washington that "the state of Connecticut is a free, sovereign, and +independent state." Gouverneur Morris, a member of the convention which +had drafted the Constitution, suggested the holding of another +conference to consider whether the Northern states should remain in the +union. + +[Illustration: _From an old cartoon_ + +NEW ENGLAND JUMPING INTO THE HANDS OF GEORGE III] + +In October, 1814, a convention of delegates from Connecticut, +Massachusetts, Rhode Island, and certain counties of New Hampshire and +Vermont was held at Hartford, on the call of Massachusetts. The counsels +of the extremists were rejected but the convention solemnly went on +record to the effect that acts of Congress in violation of the +Constitution are void; that in cases of deliberate, dangerous, and +palpable infractions the state is duty bound to interpose its authority +for the protection of its citizens; and that when emergencies occur the +states must be their own judges and execute their own decisions. Thus +New England answered the challenge of Calhoun and Clay. Fortunately its +actions were not as rash as its words. The Hartford convention merely +proposed certain amendments to the Constitution and adjourned. At the +close of the war, its proposals vanished harmlessly; but the men who +made them were hopelessly discredited. + +=The Second United States Bank.=--In driving the Federalists towards +nullification and waging a national war themselves, the Republicans lost +all their old taint of provincialism. Moreover, in turning to measures +of reconstruction called forth by the war, they resorted to the national +devices of the Federalists. In 1816, they chartered for a period of +twenty years a second United States Bank--the institution which +Jefferson and Madison once had condemned as unsound and +unconstitutional. The Constitution remained unchanged; times and +circumstances had changed. Calhoun dismissed the vexed question of +constitutionality with a scant reference to an ancient dispute, while +Madison set aside his scruples and signed the bill. + +=The Protective Tariff of 1816.=--The Republicans supplemented the Bank +by another Federalist measure--a high protective tariff. Clay viewed it +as the beginning of his "American system" of protection. Calhoun +defended it on national principles. For this sudden reversal of policy +the young Republicans were taunted by some of their older party +colleagues with betraying the "agricultural interest" that Jefferson had +fostered; but Calhoun refused to listen to their criticisms. "When the +seas are open," he said, "the produce of the South may pour anywhere +into the markets of the Old World.... What are the effects of a war with +a maritime power--with England? Our commerce annihilated ... our +agriculture cut off from its accustomed markets, the surplus of the +farmer perishes on his hands.... The recent war fell with peculiar +pressure on the growers of cotton and tobacco and the other great +staples of the country; and the same state of things will recur in the +event of another war unless prevented by the foresight of this body.... +When our manufactures are grown to a certain perfection, as they soon +will be under the fostering care of the government, we shall no longer +experience these evils." With the Republicans nationalized, the +Federalist party, as an organization, disappeared after a crushing +defeat in the presidential campaign of 1816. + +=Monroe and the Florida Purchase.=--To the victor in that political +contest, James Monroe of Virginia, fell two tasks of national +importance, adding to the prestige of the whole country and deepening +the sense of patriotism that weaned men away from mere allegiance to +states. The first of these was the purchase of Florida from Spain. The +acquisition of Louisiana let the Mississippi flow "unvexed to the sea"; +but it left all the states east of the river cut off from the Gulf, +affording them ground for discontent akin to that which had moved the +pioneers of Kentucky to action a generation earlier. The uncertainty as +to the boundaries of Louisiana gave the United States a claim to West +Florida, setting on foot a movement for occupation. The Florida swamps +were a basis for Indian marauders who periodically swept into the +frontier settlements, and hiding places for runaway slaves. Thus the +sanction of international law was given to punitive expeditions into +alien territory. + +The pioneer leaders stood waiting for the signal. It came. President +Monroe, on the occasion of an Indian outbreak, ordered General Jackson +to seize the offenders, in the Floridas, if necessary. The high-spirited +warrior, taking this as a hint that he was to occupy the coveted region, +replied that, if possession was the object of the invasion, he could +occupy the Floridas within sixty days. Without waiting for an answer to +this letter, he launched his expedition, and in the spring of 1818 was +master of the Spanish king's domain to the south. + +There was nothing for the king to do but to make the best of the +inevitable by ceding the Floridas to the United States in return for +five million dollars to be paid to American citizens having claims +against Spain. On Washington's birthday, 1819, the treaty was signed. It +ceded the Floridas to the United States and defined the boundary between +Mexico and the United States by drawing a line from the mouth of the +Sabine River in a northwesterly direction to the Pacific. On this +occasion even Monroe, former opponent of the Constitution, forgot to +inquire whether new territory could be constitutionally acquired and +incorporated into the American union. The Republicans seemed far away +from the days of "strict construction." And Jefferson still lived! + +=The Monroe Doctrine.=--Even more effective in fashioning the national +idea was Monroe's enunciation of the famous doctrine that bears his +name. The occasion was another European crisis. During the Napoleonic +upheaval and the years of dissolution that ensued, the Spanish colonies +in America, following the example set by their English neighbors in +1776, declared their independence. Unable to conquer them alone, the +king of Spain turned for help to the friendly powers of Europe that +looked upon revolution and republics with undisguised horror. + +_The Holy Alliance._--He found them prepared to view his case with +sympathy. Three of them, Austria, Prussia, and Russia, under the +leadership of the Czar, Alexander I, in the autumn of 1815, had entered +into a Holy Alliance to sustain by reciprocal service the autocratic +principle in government. Although the effusive, almost maudlin, language +of the treaty did not express their purpose explicitly, the Alliance was +later regarded as a mere union of monarchs to prevent the rise and +growth of popular government. + +The American people thought their worst fears confirmed when, in 1822, a +conference of delegates from Russia, Austria, Prussia, and France met at +Verona to consider, among other things, revolutions that had just broken +out in Spain and Italy. The spirit of the conference is reflected in the +first article of the agreement reached by the delegates: "The high +contracting powers, being convinced that the system of representative +government is equally incompatible with the monarchical principle and +the maxim of the sovereignty of the people with the divine right, +mutually engage in the most solemn manner to use all their efforts to +put an end to the system of representative government in whatever +country it may exist in Europe and to prevent its being introduced in +those countries where it is not yet known." The Czar, who incidentally +coveted the west coast of North America, proposed to send an army to aid +the king of Spain in his troubles at home, thus preparing the way for +intervention in Spanish America. It was material weakness not want of +spirit, that prevented the grand union of monarchs from making open war +on popular government. + +_The Position of England._--Unfortunately, too, for the Holy Alliance, +England refused to cooperate. English merchants had built up a large +trade with the independent Latin-American colonies and they protested +against the restoration of Spanish sovereignty, which meant a renewal of +Spain's former trade monopoly. Moreover, divine right doctrines had been +laid to rest in England and the representative principle thoroughly +established. Already there were signs of the coming democratic flood +which was soon to carry the first reform bill of 1832, extending the +suffrage, and sweep on to even greater achievements. British statesmen, +therefore, had to be cautious. In such circumstances, instead of +cooperating with the autocrats of Russia, Austria, and Prussia, they +turned to the minister of the United States in London. The British prime +minister, Canning, proposed that the two countries join in declaring +their unwillingness to see the Spanish colonies transferred to any other +power. + +_Jefferson's Advice._--The proposal was rejected; but President Monroe +took up the suggestion with Madison and Jefferson as well as with his +Secretary of State, John Quincy Adams. They favored the plan. Jefferson +said: "One nation, most of all, could disturb us in this pursuit [of +freedom]; she now offers to lead, aid, and accompany us in it. By +acceding to her proposition we detach her from the bands, bring her +mighty weight into the scale of free government and emancipate a +continent at one stroke.... With her on our side we need not fear the +whole world. With her then we should most sedulously cherish a cordial +friendship." + +_Monroe's Statement of the Doctrine._--Acting on the advice of trusted +friends, President Monroe embodied in his message to Congress, on +December 2, 1823, a statement of principles now famous throughout the +world as the Monroe Doctrine. To the autocrats of Europe he announced +that he would regard "any attempt on their part to extend their system +to any portion of this hemisphere as dangerous to our peace and safety." +While he did not propose to interfere with existing colonies dependent +on European powers, he ranged himself squarely on the side of those that +had declared their independence. Any attempt by a European power to +oppress them or control their destiny in any manner he characterized as +"a manifestation of an unfriendly disposition toward the United States." +Referring in another part of his message to a recent claim which the +Czar had made to the Pacific coast, President Monroe warned the Old +World that "the American continents, by the free and independent +condition which they have assumed and maintained, are henceforth not to +be considered as subjects for future colonization by any European +powers." The effect of this declaration was immediate and profound. Men +whose political horizon had been limited to a community or state were +led to consider their nation as a great power among the sovereignties of +the earth, taking its part in shaping their international relations. + +=The Missouri Compromise.=--Respecting one other important measure of +this period, the Republicans also took a broad view of their obligations +under the Constitution; namely, the Missouri Compromise. It is true, +they insisted on the admission of Missouri as a slave state, balanced +against the free state of Maine; but at the same time they assented to +the prohibition of slavery in the Louisiana territory north of the line +36 o 30'. During the debate on the subject an extreme view had been +presented, to the effect that Congress had no constitutional warrant for +abolishing slavery in the territories. The precedent of the Northwest +Ordinance, ratified by Congress in 1789, seemed a conclusive answer from +practice to this contention; but Monroe submitted the issue to his +cabinet, which included Calhoun of South Carolina, Crawford of Georgia, +and Wirt of Virginia, all presumably adherents to the Jeffersonian +principle of strict construction. He received in reply a unanimous +verdict to the effect that Congress did have the power to prohibit +slavery in the territories governed by it. Acting on this advice he +approved, on March 6, 1820, the bill establishing freedom north of the +compromise line. This generous interpretation of the powers of Congress +stood for nearly forty years, until repudiated by the Supreme Court in +the Dred Scott case. + + +THE NATIONAL DECISIONS OF CHIEF JUSTICE MARSHALL + +=John Marshall, the Nationalist.=--The Republicans in the lower ranges +of state politics, who did not catch the grand national style of their +leaders charged with responsibilities in the national field, were +assisted in their education by a Federalist from the Old Dominion, John +Marshall, who, as Chief Justice of the Supreme Court of the United +States from 1801 to 1835, lost no occasion to exalt the Constitution +above the claims of the provinces. No differences of opinion as to his +political views have ever led even his warmest opponents to deny his +superb abilities or his sincere devotion to the national idea. All will +likewise agree that for talents, native and acquired, he was an ornament +to the humble democracy that brought him forth. His whole career was +American. Born on the frontier of Virginia, reared in a log cabin, +granted only the barest rudiments of education, inured to hardship and +rough life, he rose by masterly efforts to the highest judicial honor +America can bestow. + +On him the bitter experience of the Revolution and of later days made a +lasting impression. He was no "summer patriot." He had been a soldier in +the Revolutionary army. He had suffered with Washington at Valley Forge. +He had seen his comrades in arms starving and freezing because the +Continental Congress had neither the power nor the inclination to force +the states to do their full duty. To him the Articles of Confederation +were the symbol of futility. Into the struggle for the formation of the +Constitution and its ratification in Virginia he had thrown himself with +the ardor of a soldier. Later, as a member of Congress, a representative +to France, and Secretary of State, he had aided the Federalists in +establishing the new government. When at length they were driven from +power in the executive and legislative branches of the government, he +was chosen for their last stronghold, the Supreme Court. By historic +irony he administered the oath of office to his bitterest enemy, Thomas +Jefferson; and, long after the author of the Declaration of Independence +had retired to private life, the stern Chief Justice continued to +announce the old Federalist principles from the Supreme Bench. + +[Illustration: JOHN MARSHALL] + +=Marbury _vs._ Madison--An Act of Congress Annulled.=--He had been in +his high office only two years when he laid down for the first time in +the name of the entire Court the doctrine that the judges have the power +to declare an act of Congress null and void when in their opinion it +violates the Constitution. This power was not expressly conferred on the +Court. Though many able men held that the judicial branch of the +government enjoyed it, the principle was not positively established +until 1803 when the case of Marbury _vs._ Madison was decided. In +rendering the opinion of the Court, Marshall cited no precedents. He +sought no foundations for his argument in ancient history. He rested it +on the general nature of the American system. The Constitution, ran his +reasoning, is the supreme law of the land; it limits and binds all who +act in the name of the United States; it limits the powers of Congress +and defines the rights of citizens. If Congress can ignore its +limitations and trespass upon the rights of citizens, Marshall argued, +then the Constitution disappears and Congress is supreme. Since, +however, the Constitution is supreme and superior to Congress, it is the +duty of judges, under their oath of office, to sustain it against +measures which violate it. Therefore, from the nature of the American +constitutional system the courts must declare null and void all acts +which are not authorized. "A law repugnant to the Constitution," he +closed, "is void and the courts as well as other departments are bound +by that instrument." From that day to this the practice of federal and +state courts in passing upon the constitutionality of laws has remained +unshaken. + +This doctrine was received by Jefferson and many of his followers with +consternation. If the idea was sound, he exclaimed, "then indeed is our +Constitution a complete _felo de se_ [legally, a suicide]. For, +intending to establish three departments, coordinate and independent +that they might check and balance one another, it has given, according +to this opinion, to one of them alone the right to prescribe rules for +the government of the others, and to that one, too, which is unelected +by and independent of the nation.... The Constitution, on this +hypothesis, is a mere thing of wax in the hands of the judiciary which +they may twist and shape into any form they please. It should be +remembered, as an axiom of eternal truth in politics, that whatever +power in any government is independent, is absolute also.... A judiciary +independent of a king or executive alone is a good thing; but +independence of the will of the nation is a solecism, at least in a +republican government." But Marshall was mighty and his view prevailed, +though from time to time other men, clinging to Jefferson's opinion, +likewise opposed the exercise by the Courts of the high power of passing +upon the constitutionality of acts of Congress. + +=Acts of State Legislatures Declared Unconstitutional.=--Had Marshall +stopped with annulling an act of Congress, he would have heard less +criticism from Republican quarters; but, with the same firmness, he set +aside acts of state legislatures as well, whenever, in his opinion, they +violated the federal Constitution. In 1810, in the case of Fletcher +_vs._ Peck, he annulled an act of the Georgia legislature, informing the +state that it was not sovereign, but "a part of a large empire, ... a +member of the American union; and that union has a constitution ... +which imposes limits to the legislatures of the several states." In the +case of McCulloch _vs._ Maryland, decided in 1819, he declared void an +act of the Maryland legislature designed to paralyze the branches of the +United States Bank established in that state. In the same year, in the +still more memorable Dartmouth College case, he annulled an act of the +New Hampshire legislature which infringed upon the charter received by +the college from King George long before. That charter, he declared, was +a contract between the state and the college, which the legislature +under the federal Constitution could not impair. Two years later he +stirred the wrath of Virginia by summoning her to the bar of the Supreme +Court to answer in a case in which the validity of one of her laws was +involved and then justified his action in a powerful opinion rendered in +the case of Cohens _vs._ Virginia. + +All these decisions aroused the legislatures of the states. They passed +sheaves of resolutions protesting and condemning; but Marshall never +turned and never stayed. The Constitution of the United States, he +fairly thundered at them, is the supreme law of the land; the Supreme +Court is the proper tribunal to pass finally upon the validity of the +laws of the states; and "those sovereignties," far from possessing the +right of review and nullification, are irrevocably bound by the +decisions of that Court. This was strong medicine for the authors of the +Kentucky and Virginia Resolutions and for the members of the Hartford +convention; but they had to take it. + +=The Doctrine of Implied Powers.=--While restraining Congress in the +Marbury case and the state legislatures in a score of cases, Marshall +also laid the judicial foundation for a broad and liberal view of the +Constitution as opposed to narrow and strict construction. In McCulloch +_vs._ Maryland, he construed generously the words "necessary and proper" +in such a way as to confer upon Congress a wide range of "implied +powers" in addition to their express powers. That case involved, among +other things, the question whether the act establishing the second +United States Bank was authorized by the Constitution. Marshall answered +in the affirmative. Congress, ran his reasoning, has large powers over +taxation and the currency; a bank is of appropriate use in the exercise +of these enumerated powers; and therefore, though not absolutely +necessary, a bank is entirely proper and constitutional. "With respect +to the means by which the powers that the Constitution confers are to be +carried into execution," he said, Congress must be allowed the +discretion which "will enable that body to perform the high duties +assigned to it, in the manner most beneficial to the people." In short, +the Constitution of the United States is not a strait jacket but a +flexible instrument vesting in Congress the powers necessary to meet +national problems as they arise. In delivering this opinion Marshall +used language almost identical with that employed by Lincoln when, +standing on the battle field of a war waged to preserve the nation, he +said that "a government of the people, by the people, for the people +shall not perish from the earth." + + +SUMMARY OF THE UNION AND NATIONAL POLITICS + +During the strenuous period between the establishment of American +independence and the advent of Jacksonian democracy the great American +experiment was under the direction of the men who had launched it. All +the Presidents in that period, except John Quincy Adams, had taken part +in the Revolution. James Madison, the chief author of the Constitution, +lived until 1836. This age, therefore, was the "age of the fathers." It +saw the threatened ruin of the country under the Articles of +Confederation, the formation of the Constitution, the rise of political +parties, the growth of the West, the second war with England, and the +apparent triumph of the national spirit over sectionalism. + +The new republic had hardly been started in 1783 before its troubles +began. The government could not raise money to pay its debts or running +expenses; it could not protect American commerce and manufactures +against European competition; it could not stop the continual issues of +paper money by the states; it could not intervene to put down domestic +uprisings that threatened the existence of the state governments. +Without money, without an army, without courts of law, the union under +the Articles of Confederation was drifting into dissolution. Patriots, +who had risked their lives for independence, began to talk of monarchy +again. Washington, Hamilton, and Madison insisted that a new +constitution alone could save America from disaster. + +By dint of much labor the friends of a new form of government induced +the Congress to call a national convention to take into account the +state of America. In May, 1787, it assembled at Philadelphia and for +months it debated and wrangled over plans for a constitution. The small +states clamored for equal rights in the union. The large states vowed +that they would never grant it. A spirit of conciliation, fair play, and +compromise saved the convention from breaking up. In addition, there +were jealousies between the planting states and the commercial states. +Here, too, compromises had to be worked out. Some of the delegates +feared the growth of democracy and others cherished it. These factions +also had to be placated. At last a plan of government was drafted--the +Constitution of the United States--and submitted to the states for +approval. Only after a long and acrimonious debate did enough states +ratify the instrument to put it into effect. On April 30, 1789, George +Washington was inaugurated first President. + +The new government proceeded to fund the old debt of the nation, assume +the debts of the states, found a national bank, lay heavy taxes to pay +the bills, and enact laws protecting American industry and commerce. +Hamilton led the way, but he had not gone far before he encountered +opposition. He found a formidable antagonist in Jefferson. In time two +political parties appeared full armed upon the scene: the Federalists +and the Republicans. For ten years they filled the country with +political debate. In 1800 the Federalists were utterly vanquished by the +Republicans with Jefferson in the lead. + +By their proclamations of faith the Republicans favored the states +rather than the new national government, but in practice they added +immensely to the prestige and power of the nation. They purchased +Louisiana from France, they waged a war for commercial independence +against England, they created a second United States Bank, they enacted +the protective tariff of 1816, they declared that Congress had power to +abolish slavery north of the Missouri Compromise line, and they spread +the shield of the Monroe Doctrine between the Western Hemisphere and +Europe. + +Still America was a part of European civilization. Currents of opinion +flowed to and fro across the Atlantic. Friends of popular government in +Europe looked to America as the great exemplar of their ideals. Events +in Europe reacted upon thought in the United States. The French +Revolution exerted a profound influence on the course of political +debate. While it was in the stage of mere reform all Americans favored +it. When the king was executed and a radical democracy set up, American +opinion was divided. When France fell under the military dominion of +Napoleon and preyed upon American commerce, the United States made ready +for war. + +The conduct of England likewise affected American affairs. In 1793 war +broke out between England and France and raged with only a slight +intermission until 1815. England and France both ravaged American +commerce, but England was the more serious offender because she had +command of the seas. Though Jefferson and Madison strove for peace, the +country was swept into war by the vehemence of the "Young Republicans," +headed by Clay and Calhoun. + +When the armed conflict was closed, one in diplomacy opened. The +autocratic powers of Europe threatened to intervene on behalf of Spain +in her attempt to recover possession of her Latin-American colonies. +Their challenge to America brought forth the Monroe Doctrine. The powers +of Europe were warned not to interfere with the independence or the +republican policies of this hemisphere or to attempt any new +colonization in it. It seemed that nationalism was to have a peaceful +triumph over sectionalism. + + +=References= + +H. Adams, _History of the United States, 1800-1817_ (9 vols.). + +K.C. Babcock, _Rise of American Nationality_ (American Nation Series). + +E. Channing, _The Jeffersonian System_ (Same Series). + +D.C. Gilman, _James Monroe_. + +W. Reddaway, _The Monroe Doctrine_. + +T. Roosevelt, _Naval War of 1812_. + + +=Questions= + +1. What was the leading feature of Jefferson's political theory? + +2. Enumerate the chief measures of his administration. + +3. Were the Jeffersonians able to apply their theories? Give the +reasons. + + +4. Explain the importance of the Mississippi River to Western farmers. + +5. Show how events in Europe forced the Louisiana Purchase. + +6. State the constitutional question involved in the Louisiana Purchase. + +7. Show how American trade was affected by the European war. + +8. Compare the policies of Jefferson and Madison. + +9. Why did the United States become involved with England rather than +with France? + +10. Contrast the causes of the War of 1812 with the results. + +11. Give the economic reasons for the attitude of New England. + +12. Give five "nationalist" measures of the Republicans. Discuss each in +detail. + +13. Sketch the career of John Marshall. + +14. Discuss the case of Marbury _vs._ Madison. + +15. Summarize Marshall's views on: (_a_) states' rights; and (_b_) a +liberal interpretation of the Constitution. + + +=Research Topics= + +=The Louisiana Purchase.=--Text of Treaty in Macdonald, _Documentary +Source Book_, pp. 279-282. Source materials in Hart, _American History +Told by Contemporaries_, Vol. III, pp. 363-384. Narrative, Henry Adams, +_History of the United States_, Vol. II, pp. 25-115; Elson, _History of +the United States_, pp. 383-388. + +=The Embargo and Non-Intercourse Acts.=--Macdonald, pp. 282-288; Adams, +Vol. IV, pp. 152-177; Elson, pp. 394-405. + +=Congress and the War of 1812.=--Adams, Vol. VI, pp. 113-198; Elson, pp. +408-450. + +=Proposals of the Hartford Convention.=--Macdonald, pp. 293-302. + +=Manufactures and the Tariff of 1816.=--Coman, _Industrial History of +the United States_, pp. 184-194. + +=The Second United States Bank.=--Macdonald, pp. 302-306. + +=Effect of European War on American Trade.=--Callender, _Economic +History of the United States_, pp. 240-250. + +=The Monroe Message.=--Macdonald, pp. 318-320. + +=Lewis and Clark Expedition.=--R.G. Thwaites, _Rocky Mountain +Explorations_, pp. 92-187. Schafer, _A History of the Pacific Northwest_ +(rev. ed.), pp. 29-61. + + + + +PART IV. THE WEST AND JACKSONIAN DEMOCRACY + + + + +CHAPTER X + +THE FARMERS BEYOND THE APPALACHIANS + + +The nationalism of Hamilton was undemocratic. The democracy of Jefferson +was, in the beginning, provincial. The historic mission of uniting +nationalism and democracy was in the course of time given to new leaders +from a region beyond the mountains, peopled by men and women from all +sections and free from those state traditions which ran back to the +early days of colonization. The voice of the democratic nationalism +nourished in the West was heard when Clay of Kentucky advocated his +American system of protection for industries; when Jackson of Tennessee +condemned nullification in a ringing proclamation that has taken its +place among the great American state papers; and when Lincoln of +Illinois, in a fateful hour, called upon a bewildered people to meet the +supreme test whether this was a nation destined to survive or to perish. +And it will be remembered that Lincoln's party chose for its banner that +earlier device--Republican--which Jefferson had made a sign of power. +The "rail splitter" from Illinois united the nationalism of Hamilton +with the democracy of Jefferson, and his appeal was clothed in the +simple language of the people, not in the sonorous rhetoric which +Webster learned in the schools. + + +PREPARATION FOR WESTERN SETTLEMENT + +=The West and the American Revolution.=--The excessive attention devoted +by historians to the military operations along the coast has obscured +the role played by the frontier in the American Revolution. The action +of Great Britain in closing western land to easy settlement in 1763 was +more than an incident in precipitating the war for independence. +Americans on the frontier did not forget it; when Indians were employed +by England to defend that land, zeal for the patriot cause set the +interior aflame. It was the members of the western vanguard, like Daniel +Boone, John Sevier, and George Rogers Clark, who first understood the +value of the far-away country under the guns of the English forts, where +the Red Men still wielded the tomahawk and the scalping knife. It was +they who gave the East no rest until their vision was seen by the +leaders on the seaboard who directed the course of national policy. It +was one of their number, a seasoned Indian fighter, George Rogers Clark, +who with aid from Virginia seized Kaskaskia and Vincennes and secured +the whole Northwest to the union while the fate of Washington's army was +still hanging in the balance. + +=Western Problems at the End of the Revolution.=--The treaty of peace, +signed with Great Britain in 1783, brought the definite cession of the +coveted territory west to the Mississippi River, but it left unsolved +many problems. In the first place, tribes of resentful Indians in the +Ohio region, even though British support was withdrawn at last, had to +be reckoned with; and it was not until after the establishment of the +federal Constitution that a well-equipped army could be provided to +guarantee peace on the border. In the second place, British garrisons +still occupied forts on Lake Erie pending the execution of the terms of +the treaty of 1783--terms which were not fulfilled until after the +ratification of the Jay treaty twelve years later. In the third place, +Virginia, Connecticut, and Massachusetts had conflicting claims to the +land in the Northwest based on old English charters and Indian treaties. +It was only after a bitter contest that the states reached an agreement +to transfer their rights to the government of the United States, +Virginia executing her deed of cession on March 1, 1784. In the fourth +place, titles to lands bought by individuals remained uncertain in the +absence of official maps and records. To meet this last situation, +Congress instituted a systematic survey of the Ohio country, laying it +out into townships, sections of 640 acres each, and quarter sections. In +every township one section of land was set aside for the support of +public schools. + +=The Northwest Ordinance.=--The final problem which had to be solved +before settlement on a large scale could be begun was that of governing +the territory. Pioneers who looked with hungry eyes on the fertile +valley of the Ohio could hardly restrain their impatience. Soldiers of +the Revolution, who had been paid for their services in land warrants +entitling them to make entries in the West, called for action. + +Congress answered by passing in 1787 the famous Northwest Ordinance +providing for temporary territorial government to be followed by the +creation of a popular assembly as soon as there were five thousand free +males in any district. Eventual admission to the union on an equal +footing with the original states was promised to the new territories. +Religious freedom was guaranteed. The safeguards of trial by jury, +regular judicial procedure, and _habeas corpus_ were established, in order +that the methods of civilized life might take the place of the +rough-and-ready justice of lynch law. During the course of the debate on +the Ordinance, Congress added the sixth article forbidding slavery and +involuntary servitude. + +This Charter of the Northwest, so well planned by the Congress under the +Articles of Confederation, was continued in force by the first Congress +under the Constitution in 1789. The following year its essential +provisions, except the ban on slavery, were applied to the territory +south of the Ohio, ceded by North Carolina to the national government, +and in 1798 to the Mississippi territory, once held by Georgia. Thus it +was settled for all time that "the new colonies were not to be exploited +for the benefit of the parent states (any more than for the benefit of +England) but were to be autonomous and coordinate commonwealths." This +outcome, bitterly opposed by some Eastern leaders who feared the triumph +of Western states over the seaboard, completed the legal steps necessary +by way of preparation for the flood of settlers. + +=The Land Companies, Speculators, and Western Land Tenure.=--As in the +original settlement of America, so in the opening of the West, great +companies and single proprietors of large grants early figured. In 1787 +the Ohio Land Company, a New England concern, acquired a million and a +half acres on the Ohio and began operations by planting the town of +Marietta. A professional land speculator, J.C. Symmes, secured a million +acres lower down where the city of Cincinnati was founded. Other +individuals bought up soldiers' claims and so acquired enormous holdings +for speculative purposes. Indeed, there was such a rush to make fortunes +quickly through the rise in land values that Washington was moved to cry +out against the "rage for speculating in and forestalling of land on the +North West of the Ohio," protesting that "scarce a valuable spot within +any tolerable distance of it is left without a claimant." He therefore +urged Congress to fix a reasonable price for the land, not "too +exorbitant and burdensome for real occupiers, but high enough to +discourage monopolizers." + +Congress, however, was not prepared to use the public domain for the +sole purpose of developing a body of small freeholders in the West. It +still looked upon the sale of public lands as an important source of +revenue with which to pay off the public debt; consequently it thought +more of instant income than of ultimate results. It placed no limit on +the amount which could be bought when it fixed the price at $2 an acre +in 1796, and it encouraged the professional land operator by making the +first installment only twenty cents an acre in addition to the small +registration and survey fee. On such terms a speculator with a few +thousand dollars could get possession of an enormous plot of land. If he +was fortunate in disposing of it, he could meet the installments, which +were spread over a period of four years, and make a handsome profit for +himself. Even when the credit or installment feature was abolished in +1821 and the price of the land lowered to a cash price of $1.75 an acre, +the opportunity for large speculative purchases continued to attract +capital to land ventures. + +=The Development of the Small Freehold.=--The cheapness of land and the +scarcity of labor, nevertheless, made impossible the triumph of the huge +estate with its semi-servile tenantry. For about $45 a man could get a +farm of 160 acres on the installment plan; another payment of $80 was +due in forty days; but a four-year term was allowed for the discharge of +the balance. With a capital of from two to three hundred dollars a +family could embark on a land venture. If it had good crops, it could +meet the deferred payments. It was, however, a hard battle at best. Many +a man forfeited his land through failure to pay the final installment; +yet in the end, in spite of all the handicaps, the small freehold of a +few hundred acres at most became the typical unit of Western +agriculture, except in the planting states of the Gulf. Even the lands +of the great companies were generally broken up and sold in small lots. + +The tendency toward moderate holdings, so favored by Western conditions, +was also promoted by a clause in the Northwest Ordinance declaring that +the land of any person dying intestate--that is, without any will +disposing of it--should be divided equally among his descendants. +Hildreth says of this provision: "It established the important +republican principle, not then introduced into all the states, of the +equal distribution of landed as well as personal property." All these +forces combined made the wide dispersion of wealth, in the early days of +the nineteenth century, an American characteristic, in marked contrast +with the European system of family prestige and vast estates based on +the law of primogeniture. + + +THE WESTERN MIGRATION AND NEW STATES + +=The People.=--With government established, federal arms victorious over +the Indians, and the lands surveyed for sale, the way was prepared for +the immigrants. They came with a rush. Young New Englanders, weary of +tilling the stony soil of their native states, poured through New York +and Pennsylvania, some settling on the northern bank of the Ohio but +most of them in the Lake region. Sons and daughters of German farmers in +Pennsylvania and many a redemptioner who had discharged his bond of +servitude pressed out into Ohio, Kentucky, Tennessee, or beyond. From +the exhausted fields and the clay hills of the Southern states came +pioneers of English and Scotch-Irish descent, the latter in great +numbers. Indeed one historian of high authority has ventured to say that +"the rapid expansion of the United States from a coast strip to a +continental area is largely a Scotch-Irish achievement." While native +Americans of mixed stocks led the way into the West, it was not long +before immigrants direct from Europe, under the stimulus of company +enterprise, began to filter into the new settlements in increasing +numbers. + +The types of people were as various as the nations they represented. +Timothy Flint, who published his entertaining _Recollections_ in 1826, +found the West a strange mixture of all sorts and conditions of people. +Some of them, he relates, had been hunters in the upper world of the +Mississippi, above the falls of St. Anthony. Some had been still farther +north, in Canada. Still others had wandered from the South--the Gulf of +Mexico, the Red River, and the Spanish country. French boatmen and +trappers, Spanish traders from the Southwest, Virginia planters with +their droves of slaves mingled with English, German, and Scotch-Irish +farmers. Hunters, forest rangers, restless bordermen, and squatters, +like the foaming combers of an advancing tide, went first. Then followed +the farmers, masters of the ax and plow, with their wives who shared +every burden and hardship and introduced some of the features of +civilized life. The hunters and rangers passed on to new scenes; the +home makers built for all time. + +=The Number of Immigrants.=--There were no official stations on the +frontier to record the number of immigrants who entered the West during +the decades following the American Revolution. But travelers of the time +record that every road was "crowded" with pioneers and their families, +their wagons and cattle; and that they were seldom out of the sound of +the snapping whip of the teamster urging forward his horses or the crack +of the hunter's rifle as he brought down his evening meal. "During the +latter half of 1787," says Coman, "more than nine hundred boats floated +down the Ohio carrying eighteen thousand men, women, and children, and +twelve thousand horses, sheep, and cattle, and six hundred and fifty +wagons." Other lines of travel were also crowded and with the passing +years the flooding tide of home seekers rose higher and higher. + +=The Western Routes.=--Four main routes led into the country beyond the +Appalachians. The Genesee road, beginning at Albany, ran almost due west +to the present site of Buffalo on Lake Erie, through a level country. In +the dry season, wagons laden with goods could easily pass along it into +northern Ohio. A second route, through Pittsburgh, was fed by three +eastern branches, one starting at Philadelphia, one at Baltimore, and +another at Alexandria. A third main route wound through the mountains +from Alexandria to Boonesboro in Kentucky and then westward across the +Ohio to St. Louis. A fourth, the most famous of them all, passed through +the Cumberland Gap and by branches extended into the Cumberland valley +and the Kentucky country. + +Of these four lines of travel, the Pittsburgh route offered the most +advantages. Pioneers, no matter from what section they came, when once +they were on the headwaters of the Ohio and in possession of a flatboat, +could find a quick and easy passage into all parts of the West and +Southwest. Whether they wanted to settle in Ohio, Kentucky, or western +Tennessee they could find their way down the drifting flood to their +destination or at least to some spot near it. Many people from the South +as well as the Northern and Middle states chose this route; so it came +about that the sons and daughters of Virginia and the Carolinas mingled +with those of New York, Pennsylvania, and New England in the settlement +of the Northwest territory. + +=The Methods of Travel into the West.=--Many stories giving exact +descriptions of methods of travel into the West in the early days have +been preserved. The country was hardly opened before visitors from the +Old World and from the Eastern states, impelled by curiosity, made their +way to the very frontier of civilization and wrote books to inform or +amuse the public. One of them, Gilbert Imlay, an English traveler, has +given us an account of the Pittsburgh route as he found it in 1791. "If +a man ... " he writes, "has a family or goods of any sort to remove, his +best way, then, would be to purchase a waggon and team of horses to +carry his property to Redstone Old Fort or to Pittsburgh, according as +he may come from the Northern or Southern states. A good waggon will +cost, at Philadelphia, about $10 ... and the horses about $12 each; they +would cost something more both at Baltimore and Alexandria. The waggon +may be covered with canvass, and if it is the choice of the people, they +may sleep in it of nights with the greatest safety. But if they dislike +that, there are inns of accommodation the whole distance on the +different roads.... The provisions I would purchase in the same manner +[that is, from the farmers along the road]; and by having two or three +camp kettles and stopping every evening when the weather is fine upon +the brink of some rivulet and by kindling a fire they may soon dress +their own food.... This manner of journeying is so far from being +disagreeable that in a fine season it is extremely pleasant." The +immigrant once at Pittsburgh or Wheeling could then buy a flatboat of a +size required for his goods and stock, and drift down the current to his +journey's end. + +[Illustration: ROADS AND TRAILS INTO THE WESTERN TERRITORY] + +=The Admission of Kentucky and Tennessee.=--When the eighteenth century +drew to a close, Kentucky had a population larger than Delaware, Rhode +Island, or New Hampshire. Tennessee claimed 60,000 inhabitants. In 1792 +Kentucky took her place as a state beside her none too kindly parent, +Virginia. The Eastern Federalists resented her intrusion; but they took +some consolation in the admission of Vermont because the balance of +Eastern power was still retained. + +As if to assert their independence of old homes and conservative ideas +the makers of Kentucky's first constitution swept aside the landed +qualification on the suffrage and gave the vote to all free white males. +Four years later, Kentucky's neighbor to the south, Tennessee, followed +this step toward a wider democracy. After encountering fierce opposition +from the Federalists, Tennessee was accepted as the sixteenth state. + +=Ohio.=--The door of the union had hardly opened for Tennessee when +another appeal was made to Congress, this time from the pioneers in +Ohio. The little posts founded at Marietta and Cincinnati had grown into +flourishing centers of trade. The stream of immigrants, flowing down the +river, added daily to their numbers and the growing settlements all +around poured produce into their markets to be exchanged for "store +goods." After the Indians were disposed of in 1794 and the last British +soldier left the frontier forts under the terms of the Jay treaty of +1795, tiny settlements of families appeared on Lake Erie in the "Western +Reserve," a region that had been retained by Connecticut when she +surrendered her other rights in the Northwest. + +At the close of the century, Ohio, claiming a population of more than +50,000, grew discontented with its territorial status. Indeed, two years +before the enactment of the Northwest Ordinance, squatters in that +region had been invited by one John Emerson to hold a convention after +the fashion of the men of Hartford, Windsor, and Wethersfield in old +Connecticut and draft a frame of government for themselves. This true +son of New England declared that men "have an undoubted right to pass +into every vacant country and there to form their constitution and that +from the confederation of the whole United States Congress is not +empowered to forbid them." This grand convention was never held because +the heavy hand of the government fell upon the leaders; but the spirit +of John Emerson did not perish. In November, 1802, a convention chosen +by voters, assembled under the authority of Congress at Chillicothe, +drew up a constitution. It went into force after a popular ratification. +The roll of the convention bore such names as Abbot, Baldwin, Cutler, +Huntington, Putnam, and Sargent, and the list of counties from which +they came included Adams, Fairfield, Hamilton, Jefferson, Trumbull, and +Washington, showing that the new America in the West was peopled and led +by the old stock. In 1803 Ohio was admitted to the union. + +=Indiana and Illinois.=--As in the neighboring state, the frontier in +Indiana advanced northward from the Ohio, mainly under the leadership, +however, of settlers from the South--restless Kentuckians hoping for +better luck in a newer country and pioneers from the far frontiers of +Virginia and North Carolina. As soon as a tier of counties swinging +upward like the horns of the moon against Ohio on the east and in the +Wabash Valley on the west was fairly settled, a clamor went up for +statehood. Under the authority of an act of Congress in 1816 the +Indianians drafted a constitution and inaugurated their government at +Corydon. "The majority of the members of the convention," we are told by +a local historian, "were frontier farmers who had a general idea of what +they wanted and had sense enough to let their more erudite colleagues +put it into shape." + +Two years later, the pioneers of Illinois, also settled upward from the +Ohio, like Indiana, elected their delegates to draft a constitution. +Leadership in the convention, quite properly, was taken by a man born in +New York and reared in Tennessee; and the constitution as finally +drafted "was in its principal provisions a copy of the then existing +constitutions of Kentucky, Ohio, and Indiana.... Many of the articles +are exact copies in wording although differently arranged and +numbered." + +=Louisiana, Mississippi, and Alabama.=--Across the Mississippi to the +far south, clearing and planting had gone on with much bustle and +enterprise. The cotton and sugar lands of Louisiana, opened by French +and Spanish settlers, were widened in every direction by planters with +their armies of slaves from the older states. New Orleans, a good market +and a center of culture not despised even by the pioneer, grew apace. In +1810 the population of lower Louisiana was over 75,000. The time had +come, said the leaders of the people, to fulfill the promise made to +France in the treaty of cession; namely, to grant to the inhabitants of +the territory statehood and the rights of American citizens. Federalists +from New England still having a voice in Congress, if somewhat weaker, +still protested in tones of horror. "I am compelled to declare it as my +deliberate opinion," pronounced Josiah Quincy in the House of +Representatives, "that if this bill [to admit Louisiana] passes, the +bonds of this Union are virtually dissolved ... that as it will be the +right of all, so it will be the duty of some [states] to prepare +definitely for a separation; amicably if they can, violently if they +must.... It is a death blow to the Constitution. It may afterwards +linger; but lingering, its fate will, at no very distant period, be +consummated." Federalists from New York like those from New England had +their doubts about the wisdom of admitting Western states; but the party +of Jefferson and Madison, having the necessary majority, granted the +coveted statehood to Louisiana in 1812. + +When, a few years later, Mississippi and Alabama knocked at the doors of +the union, the Federalists had so little influence, on account of their +conduct during the second war with England, that spokesmen from the +Southwest met a kindlier reception at Washington. Mississippi, in 1817, +and Alabama, in 1819, took their places among the United States of +America. Both of them, while granting white manhood suffrage, gave their +constitutions the tone of the old East by providing landed +qualifications for the governor and members of the legislature. + +=Missouri.=--Far to the north in the Louisiana purchase, a new +commonwealth was rising to power. It was peopled by immigrants who came +down the Ohio in fleets of boats or crossed the Mississippi from +Kentucky and Tennessee. Thrifty Germans from Pennsylvania, hardy farmers +from Virginia ready to work with their own hands, freemen seeking +freemen's homes, planters with their slaves moving on from worn-out +fields on the seaboard, came together in the widening settlements of the +Missouri country. Peoples from the North and South flowed together, +small farmers and big planters mingling in one community. When their +numbers had reached sixty thousand or more, they precipitated a contest +over their admission to the union, "ringing an alarm bell in the night," +as Jefferson phrased it. The favorite expedient of compromise with +slavery was brought forth in Congress once more. Maine consequently was +brought into the union without slavery and Missouri with slavery. At the +same time there was drawn westward through the rest of the Louisiana +territory a line separating servitude from slavery. + + +THE SPIRIT OF THE FRONTIER + +=Land Tenure and Liberty.=--Over an immense western area there developed +an unbroken system of freehold farms. In the Gulf states and the lower +Mississippi Valley, it is true, the planter with his many slaves even +led in the pioneer movement; but through large sections of Tennessee and +Kentucky, as well as upper Georgia and Alabama, and all throughout the +Northwest territory the small farmer reigned supreme. In this immense +dominion there sprang up a civilization without caste or class--a body +of people all having about the same amount of this world's goods and +deriving their livelihood from one source: the labor of their own hands +on the soil. The Northwest territory alone almost equaled in area all +the original thirteen states combined, except Georgia, and its system of +agricultural economy was unbroken by plantations and feudal estates. "In +the subdivision of the soil and the great equality of condition," as +Webster said on more than one occasion, "lay the true basis, most +certainly, of popular government." There was the undoubted source of +Jacksonian democracy. + +[Illustration: A LOG CABIN--LINCOLN'S BIRTHPLACE] + +=The Characteristics of the Western People.=--Travelers into the +Northwest during the early years of the nineteenth century were agreed +that the people of that region were almost uniformly marked by the +characteristics common to an independent yeomanry. A close observer thus +recorded his impressions: "A spirit of adventurous enterprise, a +willingness to go through any hardship to accomplish an object.... +Independence of thought and action. They have felt the influence of +these principles from their childhood. Men who can endure anything; that +have lived almost without restraint, free as the mountain air or as the +deer and the buffalo of their forests, and who know they are Americans +all.... An apparent roughness which some would deem rudeness of +manner.... Where there is perfect equality in a neighborhood of people +who know little about each other's previous history or ancestry but +where each is lord of the soil he cultivates. Where a log cabin is all +that the best of families can expect to have for years and of course can +possess few of the external decorations which have so much influence in +creating a diversity of rank in society. These circumstances have laid +the foundation for that equality of intercourse, simplicity of manners, +want of deference, want of reserve, great readiness to make +acquaintances, freedom of speech, indisposition to brook real or +imaginary insults which one witnesses among people of the West." + +This equality, this independence, this rudeness so often described by +the traveler as marking a new country, were all accentuated by the +character of the settlers themselves. Traces of the fierce, unsociable, +eagle-eyed, hard-drinking hunter remained. The settlers who followed the +hunter were, with some exceptions, soldiers of the Revolutionary army, +farmers of the "middling order," and mechanics from the towns,--English, +Scotch-Irish, Germans,--poor in possessions and thrown upon the labor of +their own hands for support. Sons and daughters from well-to-do Eastern +homes sometimes brought softer manners; but the equality of life and the +leveling force of labor in forest and field soon made them one in spirit +with their struggling neighbors. Even the preachers and teachers, who +came when the cabins were raised in the clearings and rude churches and +schoolhouses were built, preached sermons and taught lessons that +savored of the frontier, as any one may know who reads Peter +Cartwright's _A Muscular Christian_ or Eggleston's _The Hoosier +Schoolmaster_. + + +THE WEST AND THE EAST MEET + +=The East Alarmed.=--A people so independent as the Westerners and so +attached to local self-government gave the conservative East many a rude +shock, setting gentlemen in powdered wigs and knee breeches agog with +the idea that terrible things might happen in the Mississippi Valley. +Not without good grounds did Washington fear that "a touch of a feather +would turn" the Western settlers away from the seaboard to the +Spaniards; and seriously did he urge the East not to neglect them, lest +they be "drawn into the arms of, or be dependent upon foreigners." +Taking advantage of the restless spirit in the Southwest, Aaron Burr, +having disgraced himself by killing Alexander Hamilton in a duel, laid +wild plans, if not to bring about a secession in that region, at least +to build a state of some kind out of the Spanish dominions adjoining +Louisiana. Frightened at such enterprises and fearing the dominance of +the West, the Federalists, with a few conspicuous exceptions, opposed +equality between the sections. Had their narrow views prevailed, the +West, with its new democracy, would have been held in perpetual tutelage +to the seaboard or perhaps been driven into independence as the thirteen +colonies had been not long before. + +=Eastern Friends of the West.=--Fortunately for the nation, there were +many Eastern leaders, particularly from the South, who understood the +West, approved its spirit, and sought to bring the two sections together +by common bonds. Washington kept alive and keen the zeal for Western +advancement which he acquired in his youth as a surveyor. He never grew +tired of urging upon his Eastern friends the importance of the lands +beyond the mountains. He pressed upon the governor of Virginia a project +for a wagon road connecting the seaboard with the Ohio country and was +active in a movement to improve the navigation of the Potomac. He +advocated strengthening the ties of commerce. "Smooth the roads," he +said, "and make easy the way for them, and then see what an influx of +articles will be poured upon us; how amazingly our exports will be +increased by them; and how amply we shall be compensated for any trouble +and expense we may encounter to effect it." Jefferson, too, was +interested in every phase of Western development--the survey of lands, +the exploration of waterways, the opening of trade, and even the +discovery of the bones of prehistoric animals. Robert Fulton, the +inventor of the steamboat, was another man of vision who for many years +pressed upon his countrymen the necessity of uniting East and West by a +canal which would cement the union, raise the value of the public lands, +and extend the principles of confederate and republican government. + +=The Difficulties of Early Transportation.=--Means of communication +played an important part in the strategy of all those who sought to +bring together the seaboard and the frontier. The produce of the +West--wheat, corn, bacon, hemp, cattle, and tobacco--was bulky and the +cost of overland transportation was prohibitive. In the Eastern market, +"a cow and her calf were given for a bushel of salt, while a suit of +'store clothes' cost as much as a farm." In such circumstances, the +inhabitants of the Mississippi Valley were forced to ship their produce +over a long route by way of New Orleans and to pay high freight rates +for everything that was brought across the mountains. Scows of from five +to fifty tons were built at the towns along the rivers and piloted down +the stream to the Crescent City. In a few cases small ocean-going +vessels were built to transport goods to the West Indies or to the +Eastern coast towns. Salt, iron, guns, powder, and the absolute +essentials which the pioneers had to buy mainly in Eastern markets were +carried over narrow wagon trails that were almost impassable in the +rainy season. + +=The National Road.=--To far-sighted men, like Albert Gallatin, "the +father of internal improvements," the solution of this problem was the +construction of roads and canals. Early in Jefferson's administration, +Congress dedicated a part of the proceeds from the sale of lands to +building highways from the headwaters of the navigable waters emptying +into the Atlantic to the Ohio River and beyond into the Northwest +territory. In 1806, after many misgivings, it authorized a great +national highway binding the East and the West. The Cumberland Road, as +it was called, began in northwestern Maryland, wound through southern +Pennsylvania, crossed the narrow neck of Virginia at Wheeling, and then +shot almost straight across Ohio, Indiana, and Illinois, into Missouri. +By 1817, stagecoaches were running between Washington and Wheeling; by +1833 contractors had carried their work to Columbus, Ohio, and by 1852, +to Vandalia, Illinois. Over this ballasted road mail and passenger +coaches could go at high speed, and heavy freight wagons proceed in +safety at a steady pace. + +[Illustration: THE CUMBERLAND ROAD] + +=Canals and Steamboats.=--A second epoch in the economic union of the +East and West was reached with the opening of the Erie Canal in 1825, +offering an all-water route from New York City to the Great Lakes and +the Mississippi Valley. Pennsylvania, alarmed by the advantages +conferred on New York by this enterprise, began her system of canals and +portages from Philadelphia to Pittsburgh, completing the last link in +1834. In the South, the Chesapeake and Ohio Company, chartered in 1825, +was busy with a project to connect Georgetown and Cumberland when +railways broke in upon the undertaking before it was half finished. +About the same time, Ohio built a canal across the state, affording +water communication between Lake Erie and the Ohio River through a rich +wheat belt. Passengers could now travel by canal boat into the West with +comparative ease and comfort, if not at a rapid speed, and the bulkiest +of freight could be easily handled. Moreover, the rate charged for +carrying goods was cut by the Erie Canal from $32 a ton per hundred +miles to $1. New Orleans was destined to lose her primacy in the +Mississippi Valley. + +The diversion of traffic to Eastern markets was also stimulated by +steamboats which appeared on the Ohio about 1810, three years after +Fulton had made his famous trip on the Hudson. It took twenty men to +sail and row a five-ton scow up the river at a speed of from ten to +twenty miles a day. In 1825, Timothy Flint traveled a hundred miles a +day on the new steamer _Grecian_ "against the whole weight of the +Mississippi current." Three years later the round trip from Louisville +to New Orleans was cut to eight days. Heavy produce that once had to +float down to New Orleans could be carried upstream and sent to the East +by way of the canal systems. + +[Illustration: _From an old print_ + +AN EARLY MISSISSIPPI STEAMBOAT] + +Thus the far country was brought near. The timid no longer hesitated at +the thought of the perilous journey. All routes were crowded with +Western immigrants. The forests fell before the ax like grain before the +sickle. Clearings scattered through the woods spread out into a great +mosaic of farms stretching from the Southern Appalachians to Lake +Michigan. The national census of 1830 gave 937,000 inhabitants to Ohio; +343,000 to Indiana; 157,000 to Illinois; 687,000 to Kentucky; and +681,000 to Tennessee. + +[Illustration: DISTRIBUTION OF POPULATION, 1830] + +With the increase in population and the growth of agriculture came +political influence. People who had once petitioned Congress now sent +their own representatives. Men who had hitherto accepted without +protests Presidents from the seaboard expressed a new spirit of dissent +in 1824 by giving only three electoral votes for John Quincy Adams; and +four years later they sent a son of the soil from Tennessee, Andrew +Jackson, to take Washington's chair as chief executive of the +nation--the first of a long line of Presidents from the Mississippi +basin. + + +=References= + +W.G. Brown, _The Lower South in American History_. + +B.A. Hinsdale, _The Old North West_ (2 vols.). + +A.B. Hulbert, _Great American Canals_ and _The Cumberland Road_. + +T. Roosevelt, _Thomas H. Benton_. + +P.J. Treat, _The National Land System_ (1785-1820). + +F.J. Turner, _Rise of the New West_ (American Nation Series). + +J. Winsor, _The Westward Movement_. + + +=Questions= + +1. How did the West come to play a role in the Revolution? + +2. What preparations were necessary to settlement? + +3. Give the principal provisions of the Northwest Ordinance. + +4. Explain how freehold land tenure happened to predominate in the West. + +5. Who were the early settlers in the West? What routes did they take? +How did they travel? + +6. Explain the Eastern opposition to the admission of new Western +states. Show how it was overcome. + +7. Trace a connection between the economic system of the West and the +spirit of the people. + +8. Who were among the early friends of Western development? + +9. Describe the difficulties of trade between the East and the West. + +10. Show how trade was promoted. + + +=Research Topics= + +=Northwest Ordinance.=--Analysis of text in Macdonald, _Documentary +Source Book_. Roosevelt, _Winning of the West_, Vol. V, pp. 5-57. + +=The West before the Revolution.=--Roosevelt, Vol. I. + +=The West during the Revolution.=--Roosevelt, Vols. II and III. + +=Tennessee.=--Roosevelt, Vol. V, pp. 95-119 and Vol. VI, pp. 9-87. + +=The Cumberland Road.=--A.B. Hulbert, _The Cumberland Road_. + +=Early Life in the Middle West.=--Callender, _Economic History of the +United States_, pp. 617-633; 636-641. + +=Slavery in the Southwest.=--Callender, pp. 641-652. + +=Early Land Policy.=--Callender, pp. 668-680. + +=Westward Movement of Peoples.=--Roosevelt, Vol. IV, pp. 7-39. + +Lists of books dealing with the early history of Western states are +given in Hart, Channing, and Turner, _Guide to the Study and Reading of +American History_ (rev. ed.), pp. 62-89. + +=Kentucky.=--Roosevelt, Vol. IV, pp. 176-263. + + + + +CHAPTER XI + +JACKSONIAN DEMOCRACY + + +The New England Federalists, at the Hartford convention, prophesied that +in time the West would dominate the East. "At the adoption of the +Constitution," they said, "a certain balance of power among the original +states was considered to exist, and there was at that time and yet is +among those parties a strong affinity between their great and general +interests. By the admission of these [new] states that balance has been +materially affected and unless the practice be modified must ultimately +be destroyed. The Southern states will first avail themselves of their +new confederates to govern the East, and finally the Western states, +multiplied in number, and augmented in population, will control the +interests of the whole." Strangely enough the fulfillment of this +prophecy was being prepared even in Federalist strongholds by the rise +of a new urban democracy that was to make common cause with the farmers +beyond the mountains. + + +THE DEMOCRATIC MOVEMENT IN THE EAST + +=The Aristocratic Features of the Old Order.=--The Revolutionary +fathers, in setting up their first state constitutions, although they +often spoke of government as founded on the consent of the governed, did +not think that consistency required giving the vote to all adult males. +On the contrary they looked upon property owners as the only safe +"depositary" of political power. They went back to the colonial +tradition that related taxation and representation. This, they argued, +was not only just but a safeguard against the "excesses of democracy." + +In carrying their theory into execution they placed taxpaying or +property qualifications on the right to vote. Broadly speaking, these +limitations fell into three classes. Three states, Pennsylvania (1776), +New Hampshire (1784), and Georgia (1798), gave the ballot to all who +paid taxes, without reference to the value of their property. Three, +Virginia, Delaware, and Rhode Island, clung firmly to the ancient +principles that only freeholders could be intrusted with electoral +rights. Still other states, while closely restricting the suffrage, +accepted the ownership of other things as well as land in fulfillment of +the requirements. In Massachusetts, for instance, the vote was granted +to all men who held land yielding an annual income of three pounds or +possessed other property worth sixty pounds. + +The electors thus enfranchised, numerous as they were, owing to the wide +distribution of land, often suffered from a very onerous disability. In +many states they were able to vote only for persons of wealth because +heavy property qualifications were imposed on public officers. In New +Hampshire, the governor had to be worth five hundred pounds, one-half in +land; in Massachusetts, one thousand pounds, all freehold; in Maryland, +five thousand pounds, one thousand of which was freehold; in North +Carolina, one thousand pounds freehold; and in South Carolina, ten +thousand pounds freehold. A state senator in Massachusetts had to be the +owner of a freehold worth three hundred pounds or personal property +worth six hundred pounds; in New Jersey, one thousand pounds' worth of +property; in North Carolina, three hundred acres of land; in South +Carolina, two thousand pounds freehold. For members of the lower house +of the legislature lower qualifications were required. + +In most of the states the suffrage or office holding or both were +further restricted by religious provisions. No single sect was powerful +enough to dominate after the Revolution, but, for the most part, +Catholics and Jews were either disfranchised or excluded from office. +North Carolina and Georgia denied the ballot to any one who was not a +Protestant. Delaware withheld it from all who did not believe in the +Trinity and the inspiration of the Scriptures. Massachusetts and +Maryland limited it to Christians. Virginia and New York, advanced for +their day, made no discrimination in government on account of religious +opinion. + +=The Defense of the Old Order.=--It must not be supposed that property +qualifications were thoughtlessly imposed at the outset or considered of +little consequence in practice. In the beginning they were viewed as +fundamental. As towns grew in size and the number of landless citizens +increased, the restrictions were defended with even more vigor. In +Massachusetts, the great Webster upheld the rights of property in +government, saying: "It is entirely just that property should have its +due weight and consideration in political arrangements.... The +disastrous revolutions which the world has witnessed, those political +thunderstorms and earthquakes which have shaken the pillars of society +to their deepest foundations, have been revolutions against property." +In Pennsylvania, a leader in local affairs cried out against a plan to +remove the taxpaying limitation on the suffrage: "What does the delegate +propose? To place the vicious vagrant, the wandering Arabs, the Tartar +hordes of our large cities on the level with the virtuous and good man?" +In Virginia, Jefferson himself had first believed in property +qualifications and had feared with genuine alarm the "mobs of the great +cities." It was near the end of the eighteenth century before he +accepted the idea of manhood suffrage. Even then he was unable to +convince the constitution-makers of his own state. "It is not an idle +chimera of the brain," urged one of them, "that the possession of land +furnishes the strongest evidence of permanent, common interest with, and +attachment to, the community.... It is upon this foundation I wish to +place the right of suffrage. This is the best general standard which can +be resorted to for the purpose of determining whether the persons to be +invested with the right of suffrage are such persons as could be, +consistently with the safety and well-being of the community, intrusted +with the exercise of that right." + +=Attacks on the Restricted Suffrage.=--The changing circumstances of +American life, however, soon challenged the rule of those with property. +Prominent among the new forces were the rising mercantile and business +interests. Where the freehold qualification was applied, business men +who did not own land were deprived of the vote and excluded from office. +In New York, for example, the most illiterate farmer who had one hundred +pounds' worth of land could vote for state senator and governor, while +the landless banker or merchant could not. It is not surprising, +therefore, to find business men taking the lead in breaking down +freehold limitations on the suffrage. The professional classes also were +interested in removing the barriers which excluded many of them from +public affairs. It was a schoolmaster, Thomas Dorr, who led the popular +uprising in Rhode Island which brought the exclusive rule by freeholders +to an end. + +In addition to the business and professional classes, the mechanics of +the towns showed a growing hostility to a system of government that +generally barred them from voting or holding office. Though not +numerous, they had early begun to exercise an influence on the course of +public affairs. They had led the riots against the Stamp Act, overturned +King George's statue, and "crammed stamps down the throats of +collectors." When the state constitutions were framed they took a lively +interest, particularly in New York City and Philadelphia. In June, 1776, +the "mechanicks in union" in New York protested against putting the new +state constitution into effect without their approval, declaring that +the right to vote on the acceptance or rejection of a fundamental law +"is the birthright of every man to whatever state he may belong." Though +their petition was rejected, their spirit remained. When, a few years +later, the federal Constitution was being framed, the mechanics watched +the process with deep concern; they knew that one of its main objects +was to promote trade and commerce, affecting directly their daily bread. +During the struggle over ratification, they passed resolutions approving +its provisions and they often joined in parades organized to stir up +sentiment for the Constitution, even though they could not vote for +members of the state conventions and so express their will directly. +After the organization of trade unions they collided with the courts of +law and thus became interested in the election of judges and lawmakers. + +Those who attacked the old system of class rule found a strong moral +support in the Declaration of Independence. Was it not said that all men +are created equal? Whoever runs may read. Was it not declared that +governments derive their just power from the consent of the governed? +That doctrine was applied with effect to George III and seemed +appropriate for use against the privileged classes of Massachusetts or +Virginia. "How do the principles thus proclaimed," asked the +non-freeholders of Richmond, in petitioning for the ballot, "accord with +the existing regulation of the suffrage? A regulation which, instead of +the equality nature ordains, creates an odious distinction between +members of the same community ... and vests in a favored class, not in +consideration of their public services but of their private possessions, +the highest of all privileges." + +=Abolition of Property Qualifications.=--By many minor victories rather +than by any spectacular triumphs did the advocates of manhood suffrage +carry the day. Slight gains were made even during the Revolution or +shortly afterward. In Pennsylvania, the mechanics, by taking an active +part in the contest over the Constitution of 1776, were able to force +the qualification down to the payment of a small tax. Vermont came into +the union in 1792 without any property restrictions. In the same year +Delaware gave the vote to all men who paid taxes. Maryland, reckoned one +of the most conservative of states, embarked on the experiment of +manhood suffrage in 1809; and nine years later, Connecticut, equally +conservative, decided that all taxpayers were worthy of the ballot. + +Five states, Massachusetts, New York, Virginia, Rhode Island, and North +Carolina, remained obdurate while these changes were going on around +them; finally they had to yield themselves. The last struggle in +Massachusetts took place in the constitutional convention of 1820. There +Webster, in the prime of his manhood, and John Adams, in the closing +years of his old age, alike protested against such radical innovations +as manhood suffrage. Their protests were futile. The property test was +abolished and a small tax-paying qualification was substituted. New York +surrendered the next year and, after trying some minor restrictions for +five years, went completely over to white manhood suffrage in 1826. +Rhode Island clung to her freehold qualification through thirty years of +agitation. Then Dorr's Rebellion, almost culminating in bloodshed, +brought about a reform in 1843 which introduced a slight tax-paying +qualification as an alternative to the freehold. Virginia and North +Carolina were still unconvinced. The former refused to abandon ownership +of land as the test for political rights until 1850 and the latter until +1856. Although religious discriminations and property qualifications for +office holders were sometimes retained after the establishment of +manhood suffrage, they were usually abolished along with the monopoly of +government enjoyed by property owners and taxpayers. + +[Illustration: THOMAS DORR AROUSING HIS FOLLOWERS] + +At the end of the first quarter of the nineteenth century, the white +male industrial workers and the mechanics of the Northern cities, at +least, could lay aside the petition for the ballot and enjoy with the +free farmer a voice in the government of their common country. +"Universal democracy," sighed Carlyle, who was widely read in the United +States, "whatever we may think of it has declared itself the inevitable +fact of the days in which we live; and he who has any chance to instruct +or lead in these days must begin by admitting that ... Where no +government is wanted, save that of the parish constable, as in America +with its boundless soil, every man being able to find work and +recompense for himself, democracy may subsist; not elsewhere." Amid the +grave misgivings of the first generation of statesmen, America was +committed to the great adventure, in the populous towns of the East as +well as in the forests and fields of the West. + + +THE NEW DEMOCRACY ENTERS THE ARENA + +The spirit of the new order soon had a pronounced effect on the +machinery of government and the practice of politics. The enfranchised +electors were not long in demanding for themselves a larger share in +administration. + +=The Spoils System and Rotation in Office.=--First of all they wanted +office for themselves, regardless of their fitness. They therefore +extended the system of rewarding party workers with government +positions--a system early established in several states, notably New +York and Pennsylvania. Closely connected with it was the practice of +fixing short terms for officers and making frequent changes in +personnel. "Long continuance in office," explained a champion of this +idea in Pennsylvania in 1837, "unfits a man for the discharge of its +duties, by rendering him arbitrary and aristocratic, and tends to beget, +first life office, and then hereditary office, which leads to the +destruction of free government." The solution offered was the historic +doctrine of "rotation in office." At the same time the principle of +popular election was extended to an increasing number of officials who +had once been appointed either by the governor or the legislature. Even +geologists, veterinarians, surveyors, and other technical officers were +declared elective on the theory that their appointment "smacked of +monarchy." + +=Popular Election of Presidential Electors.=--In a short time the spirit +of democracy, while playing havoc with the old order in state +government, made its way upward into the federal system. The framers of +the Constitution, bewildered by many proposals and unable to agree on +any single plan, had committed the choice of presidential electors to +the discretion of the state legislatures. The legislatures, in turn, +greedy of power, early adopted the practice of choosing the electors +themselves; but they did not enjoy it long undisturbed. Democracy, +thundering at their doors, demanded that they surrender the privilege to +the people. Reluctantly they yielded, sometimes granting popular +election and then withdrawing it. The drift was inevitable, and the +climax came with the advent of Jacksonian democracy. In 1824, Vermont, +New York, Delaware, South Carolina, Georgia, and Louisiana, though some +had experimented with popular election, still left the choice of +electors with the legislature. Eight years later South Carolina alone +held to the old practice. Popular election had become the final word. +The fanciful idea of an electoral college of "good and wise men," +selected without passion or partisanship by state legislatures acting as +deliberative bodies, was exploded for all time; the election of the +nation's chief magistrate was committed to the tempestuous methods of +democracy. + +=The Nominating Convention.=--As the suffrage was widened and the +popular choice of presidential electors extended, there arose a violent +protest against the methods used by the political parties in nominating +candidates. After the retirement of Washington, both the Republicans and +the Federalists found it necessary to agree upon their favorites before +the election, and they adopted a colonial device--the pre-election +caucus. The Federalist members of Congress held a conference and +selected their candidate, and the Republicans followed the example. In +a short time the practice of nominating by a "congressional caucus" +became a recognized institution. The election still remained with the +people; but the power of picking candidates for their approval passed +into the hands of a small body of Senators and Representatives. + + +A reaction against this was unavoidable. To friends of "the plain +people," like Andrew Jackson, it was intolerable, all the more so +because the caucus never favored him with the nomination. More +conservative men also found grave objections to it. They pointed out +that, whereas the Constitution intended the President to be an +independent officer, he had now fallen under the control of a caucus of +congressmen. The supremacy of the legislative branch had been obtained +by an extra-legal political device. To such objections were added +practical considerations. In 1824, when personal rivalry had taken the +place of party conflicts, the congressional caucus selected as the +candidate, William H. Crawford, of Georgia, a man of distinction but no +great popularity, passing by such an obvious hero as General Jackson. +The followers of the General were enraged and demanded nothing short of +the death of "King Caucus." Their clamor was effective. Under their +attacks, the caucus came to an ignominious end. + +In place of it there arose in 1831 a new device, the national nominating +convention, composed of delegates elected by party voters for the sole +purpose of nominating candidates. Senators and Representatives were +still prominent in the party councils, but they were swamped by hundreds +of delegates "fresh from the people," as Jackson was wont to say. In +fact, each convention was made up mainly of office holders and office +seekers, and the new institution was soon denounced as vigorously as +King Caucus had been, particularly by statesmen who failed to obtain a +nomination. Still it grew in strength and by 1840 was firmly +established. + +=The End of the Old Generation.=--In the election of 1824, the +representatives of the "aristocracy" made their last successful stand. +Until then the leadership by men of "wealth and talents" had been +undisputed. There had been five Presidents--Washington, John Adams, +Jefferson, Madison, and Monroe--all Eastern men brought up in prosperous +families with the advantages of culture which come from leisure and the +possession of life's refinements. None of them had ever been compelled +to work with his hands for a livelihood. Four of them had been +slaveholders. Jefferson was a philosopher, learned in natural science, a +master of foreign languages, a gentleman of dignity and grace of manner, +notwithstanding his studied simplicity. Madison, it was said, was armed +"with all the culture of his century." Monroe was a graduate of William +and Mary, a gentleman of the old school. Jefferson and his three +successors called themselves Republicans and professed a genuine faith +in the people but they were not "of the people" themselves; they were +not sons of the soil or the workshop. They were all men of "the grand + +old order of society" who gave finish and style even to popular +government. + +Monroe was the last of the Presidents belonging to the heroic epoch of +the Revolution. He had served in the war for independence, in the +Congress under the Articles of Confederation, and in official capacity +after the adoption of the Constitution. In short, he was of the age that +had wrought American independence and set the government afloat. With +his passing, leadership went to a new generation; but his successor, +John Quincy Adams, formed a bridge between the old and the new in that +he combined a high degree of culture with democratic sympathies. +Washington had died in 1799, preceded but a few months by Patrick Henry +and followed in four years by Samuel Adams. Hamilton had been killed in +a duel with Burr in 1804. Thomas Jefferson and John Adams were yet alive +in 1824 but they were soon to pass from the scene, reconciled at last, +full of years and honors. Madison was in dignified retirement, destined +to live long enough to protest against the doctrine of nullification +proclaimed by South Carolina before death carried him away at the ripe +old age of eighty-five. + +=The Election of John Quincy Adams (1824).=--The campaign of 1824 marked +the end of the "era of good feeling" inaugurated by the collapse of the +Federalist party after the election of 1816. There were four leading +candidates, John Quincy Adams, Andrew Jackson, Henry Clay, and W.H. +Crawford. The result of the election was a division of the electoral +votes into four parts and no one received a majority. Under the +Constitution, therefore, the selection of President passed to the House +of Representatives. Clay, who stood at the bottom of the poll, threw his +weight to Adams and assured his triumph, much to the chagrin of +Jackson's friends. They thought, with a certain justification, that +inasmuch as the hero of New Orleans had received the largest electoral +vote, the House was morally bound to accept the popular judgment and +make him President. Jackson shook hands cordially with Adams on the day +of the inauguration, but never forgave him for being elected. + +While Adams called himself a Republican in politics and often spoke of +"the rule of the people," he was regarded by Jackson's followers as "an +aristocrat." He was not a son of the soil. Neither was he acquainted at +first hand with the labor of farmers and mechanics. He had been educated +at Harvard and in Europe. Like his illustrious father, John Adams, he +was a stern and reserved man, little given to seeking popularity. +Moreover, he was from the East and the frontiersmen of the West regarded +him as a man "born with a silver spoon in his mouth." Jackson's +supporters especially disliked him because they thought their hero +entitled to the presidency. Their anger was deepened when Adams +appointed Clay to the office of Secretary of State; and they set up a +cry that there had been a "deal" by which Clay had helped to elect Adams +to get office for himself. + +Though Adams conducted his administration with great dignity and in a +fine spirit of public service, he was unable to overcome the opposition +which he encountered on his election to office or to win popularity in +the West and South. On the contrary, by advocating government assistance +in building roads and canals and public grants in aid of education, +arts, and sciences, he ran counter to the current which had set in +against appropriations of federal funds for internal improvements. By +signing the Tariff Bill of 1828, soon known as the "Tariff of +Abominations," he made new enemies without adding to his friends in New +York, Pennsylvania, and Ohio where he sorely needed them. Handicapped by +the false charge that he had been a party to a "corrupt bargain" with +Clay to secure his first election; attacked for his advocacy of a high +protective tariff; charged with favoring an "aristocracy of +office-holders" in Washington on account of his refusal to discharge +government clerks by the wholesale, Adams was retired from the White +House after he had served four years. + +=The Triumph of Jackson in 1828.=--Probably no candidate for the +presidency ever had such passionate popular support as Andrew Jackson +had in 1828. He was truly a man of the people. Born of poor parents in +the upland region of South Carolina, schooled in poverty and adversity, +without the advantages of education or the refinements of cultivated +leisure, he seemed the embodiment of the spirit of the new American +democracy. Early in his youth he had gone into the frontier of Tennessee +where he soon won a name as a fearless and intrepid Indian fighter. On +the march and in camp, he endeared himself to his men by sharing their +hardships, sleeping on the ground with them, and eating parched corn +when nothing better could be found for the privates. From local +prominence he sprang into national fame by his exploit at the battle of +New Orleans. His reputation as a military hero was enhanced by the +feeling that he had been a martyr to political treachery in 1824. The +farmers of the West and South claimed him as their own. The mechanics of +the Eastern cities, newly enfranchised, also looked upon him as their +friend. Though his views on the tariff, internal improvements, and other +issues before the country were either vague or unknown, he was readily +elected President. + +The returns of the electoral vote in 1828 revealed the sources of +Jackson's power. In New England, he received but one ballot, from +Maine; he had a majority of the electors in New York and all of them in +Pennsylvania; and he carried every state south of Maryland and beyond +the Appalachians. Adams did not get a single electoral vote in the South +and West. The prophecy of the Hartford convention had been fulfilled. + +[Illustration: ANDREW JACKSON] + +When Jackson took the oath of office on March 4, 1829, the government of +the United States entered into a new era. Until this time the +inauguration of a President--even that of Jefferson, the apostle of +simplicity--had brought no rude shock to the course of affairs at the +capital. Hitherto the installation of a President meant that an +old-fashioned gentleman, accompanied by a few servants, had driven to +the White House in his own coach, taken the oath with quiet dignity, +appointed a few new men to the higher posts, continued in office the +long list of regular civil employees, and begun his administration with +respectable decorum. Jackson changed all this. When he was inaugurated, +men and women journeyed hundreds of miles to witness the ceremony. Great +throngs pressed into the White House, "upset the bowls of punch, broke +the glasses, and stood with their muddy boots on the satin-covered +chairs to see the people's President." If Jefferson's inauguration was, +as he called it, the "great revolution," Jackson's inauguration was a +cataclysm. + + +THE NEW DEMOCRACY AT WASHINGTON + +=The Spoils System.=--The staid and respectable society of Washington +was disturbed by this influx of farmers and frontiersmen. To speak of +politics became "bad form" among fashionable women. The clerks and +civil servants of the government who had enjoyed long and secure tenure +of office became alarmed at the clamor of new men for their positions. +Doubtless the major portion of them had opposed the election of Jackson +and looked with feelings akin to contempt upon him and his followers. +With a hunter's instinct, Jackson scented his prey. Determined to have +none but his friends in office, he made a clean sweep, expelling old +employees to make room for men "fresh from the people." This was a new +custom. Other Presidents had discharged a few officers for engaging in +opposition politics. They had been careful in making appointments not to +choose inveterate enemies; but they discharged relatively few men on +account of their political views and partisan activities. + +By wholesale removals and the frank selection of officers on party +grounds--a practice already well intrenched in New York--Jackson +established the "spoils system" at Washington. The famous slogan, "to +the victor belong the spoils of victory," became the avowed principle of +the national government. Statesmen like Calhoun denounced it; poets like +James Russell Lowell ridiculed it; faithful servants of the government +suffered under it; but it held undisturbed sway for half a century +thereafter, each succeeding generation outdoing, if possible, its +predecessor in the use of public office for political purposes. If any +one remarked that training and experience were necessary qualifications +for important public positions, he met Jackson's own profession of +faith: "The duties of any public office are so simple or admit of being +made so simple that any man can in a short time become master of them." + +=The Tariff and Nullification.=--Jackson had not been installed in power +very long before he was compelled to choose between states' rights and +nationalism. The immediate occasion of the trouble was the tariff--a +matter on which Jackson did not have any very decided views. His mind +did not run naturally to abstruse economic questions; and owing to the +divided opinion of the country it was "good politics" to be vague and +ambiguous in the controversy. Especially was this true, because the +tariff issue was threatening to split the country into parties again. + +_The Development of the Policy of "Protection."_--The war of 1812 and +the commercial policies of England which followed it had accentuated the +need for American economic independence. During that conflict, the +United States, cut off from English manufactures as during the +Revolution, built up home industries to meet the unusual call for iron, +steel, cloth, and other military and naval supplies as well as the +demands from ordinary markets. Iron foundries and textile mills sprang +up as in the night; hundreds of business men invested fortunes in +industrial enterprises so essential to the military needs of the +government; and the people at large fell into the habit of buying +American-made goods again. As the London _Times_ tersely observed of the +Americans, "their first war with England made them independent; their +second war made them formidable." + +In recognition of this state of affairs, the tariff of 1816 was +designed: _first_, to prevent England from ruining these "infant +industries" by dumping the accumulated stores of years suddenly upon +American markets; and, _secondly_, to enlarge in the manufacturing +centers the demand for American agricultural produce. It accomplished +the purposes of its framers. It kept in operation the mills and furnaces +so recently built. It multiplied the number of industrial workers and +enhanced the demand for the produce of the soil. It brought about +another very important result. It turned the capital and enterprise of +New England from shipping to manufacturing, and converted her statesmen, +once friends of low tariffs, into ardent advocates of protection. + +In the early years of the nineteenth century, the Yankees had bent their +energies toward building and operating ships to carry produce from +America to Europe and manufactures from Europe to America. For this +reason, they had opposed the tariff of 1816 calculated to increase +domestic production and cut down the carrying trade. Defeated in their +efforts, they accepted the inevitable and turned to manufacturing. Soon +they were powerful friends of protection for American enterprise. As the +money invested and the labor employed in the favored industries +increased, the demand for continued and heavier protection grew apace. +Even the farmers who furnished raw materials, like wool, flax, and hemp, +began to see eye to eye with the manufacturers. So the textile interests +of New England, the iron masters of Connecticut, New Jersey, and +Pennsylvania, the wool, hemp, and flax growers of Ohio, Kentucky, and +Tennessee, and the sugar planters of Louisiana developed into a +formidable combination in support of a high protective tariff. + +_The Planting States Oppose the Tariff._--In the meantime, the cotton +states on the seaboard had forgotten about the havoc wrought during the +Napoleonic wars when their produce rotted because there were no ships to +carry it to Europe. The seas were now open. The area devoted to cotton +had swiftly expanded as Alabama, Mississippi, and Louisiana were opened +up. Cotton had in fact become "king" and the planters depended for their +prosperity, as they thought, upon the sale of their staple to English +manufacturers whose spinning and weaving mills were the wonder of the +world. Manufacturing nothing and having to buy nearly everything except +farm produce and even much of that for slaves, the planters naturally +wanted to purchase manufactures in the cheapest market, England, where +they sold most of their cotton. The tariff, they contended, raised the +price of the goods they had to buy and was thus in fact a tribute laid +on them for the benefit of the Northern mill owners. + +_The Tariff of Abominations._--They were overborne, however, in 1824 and +again in 1828 when Northern manufacturers and Western farmers forced +Congress to make an upward revision of the tariff. The Act of 1828 known +as "the Tariff of Abominations," though slightly modified in 1832, was +"the straw which broke the camel's back." Southern leaders turned in +rage against the whole system. The legislatures of Virginia, North +Carolina, South Carolina, Georgia, and Alabama denounced it; a general +convention of delegates held at Augusta issued a protest of defiance +against it; and South Carolina, weary of verbal battles, decided to +prevent its enforcement. + +_South Carolina Nullifies the Tariff._--The legislature of that state, +on October 26, 1832, passed a bill calling for a state convention which +duly assembled in the following month. In no mood for compromise, it +adopted the famous Ordinance of Nullification after a few days' debate. +Every line of this document was clear and firm. The tariff, it opened, +gives "bounties to classes and individuals ... at the expense and to the +injury and oppression of other classes and individuals"; it is a +violation of the Constitution of the United States and therefore null +and void; its enforcement in South Carolina is unlawful; if the federal +government attempts to coerce the state into obeying the law, "the +people of this state will thenceforth hold themselves absolved from all +further obligations to maintain or preserve their political connection +with the people of the other states and will forthwith proceed to +organize a separate government and do all other acts and things which +sovereign and independent states may of right do." + +_Southern States Condemn Nullification._--The answer of the country to +this note of defiance, couched in the language used in the Kentucky +resolutions and by the New England Federalists during the war of 1812, +was quick and positive. The legislatures of the Southern states, while +condemning the tariff, repudiated the step which South Carolina had +taken. Georgia responded: "We abhor the doctrine of nullification as +neither a peaceful nor a constitutional remedy." Alabama found it +"unsound in theory and dangerous in practice." North Carolina replied +that it was "revolutionary in character, subversive of the Constitution +of the United States." Mississippi answered: "It is disunion by +force--it is civil war." Virginia spoke more softly, condemning the +tariff and sustaining the principle of the Virginia resolutions but +denying that South Carolina could find in them any sanction for her +proceedings. + +_Jackson Firmly Upholds the Union._--The eyes of the country were turned +upon Andrew Jackson. It was known that he looked with no friendly +feelings upon nullification, for, at a Jefferson dinner in the spring of +1830 while the subject was in the air, he had with laconic firmness +announced a toast: "Our federal union; it must be preserved." When two +years later the open challenge came from South Carolina, he replied that +he would enforce the law, saying with his frontier directness: "If a +single drop of blood shall be shed there in opposition to the laws of +the United States, I will hang the first man I can lay my hands on +engaged in such conduct upon the first tree that I can reach." He made +ready to keep his word by preparing for the use of military and naval +forces in sustaining the authority of the federal government. Then in a +long and impassioned proclamation to the people of South Carolina he +pointed out the national character of the union, and announced his +solemn resolve to preserve it by all constitutional means. Nullification +he branded as "incompatible with the existence of the union, +contradicted expressly by the letter of the Constitution, unauthorized +by its spirit, inconsistent with every principle on which it was +founded, and destructive of the great objects for which it was formed." + +_A Compromise._--In his messages to Congress, however, Jackson spoke the +language of conciliation. A few days before issuing his proclamation he +suggested that protection should be limited to the articles of domestic +manufacture indispensable to safety in war time, and shortly afterward +he asked for new legislation to aid him in enforcing the laws. With two +propositions before it, one to remove the chief grounds for South +Carolina's resistance and the other to apply force if it was continued, +Congress bent its efforts to avoid a crisis. On February 12, 1833, +Henry Clay laid before the Senate a compromise tariff bill providing for +the gradual reduction of the duties until by 1842 they would reach the +level of the law which Calhoun had supported in 1816. About the same +time the "force bill," designed to give the President ample authority in +executing the law in South Carolina, was taken up. After a short but +acrimonious debate, both measures were passed and signed by President +Jackson on the same day, March 2. Looking upon the reduction of the +tariff as a complete vindication of her policy and an undoubted victory, +South Carolina rescinded her ordinance and enacted another nullifying +the force bill. + +[Illustration: _From an old print._ + +DANIEL WEBSTER] + +_The Webster-Hayne Debate._--Where the actual victory lay in this +quarrel, long the subject of high dispute, need not concern us to-day. +Perhaps the chief result of the whole affair was a clarification of the +issue between the North and the South--a definite statement of the +principles for which men on both sides were years afterward to lay down +their lives. On behalf of nationalism and a perpetual union, the stanch +old Democrat from Tennessee had, in his proclamation on nullification, +spoken a language that admitted of only one meaning. On behalf of +nullification, Senator Hayne, of South Carolina, a skilled lawyer and +courtly orator, had in a great speech delivered in the Senate in +January, 1830, set forth clearly and cogently the doctrine that the +union is a compact among sovereign states from which the parties may +lawfully withdraw. It was this address that called into the arena +Daniel Webster, Senator from Massachusetts, who, spreading the mantle +of oblivion over the Hartford convention, delivered a reply to Hayne +that has been reckoned among the powerful orations of all time--a plea +for the supremacy of the Constitution and the national character of the +union. + +=The War on the United States Bank.=--If events forced the issue of +nationalism and nullification upon Jackson, the same could not be said +of his attack on the bank. That institution, once denounced by every +true Jeffersonian, had been reestablished in 1816 under the +administration of Jefferson's disciple, James Madison. It had not been +in operation very long, however, before it aroused bitter opposition, +especially in the South and the West. Its notes drove out of circulation +the paper currency of unsound banks chartered by the states, to the +great anger of local financiers. It was accused of favoritism in making +loans, of conferring special privileges upon politicians in return for +their support at Washington. To all Jackson's followers it was "an +insidious money power." One of them openly denounced it as an +institution designed "to strengthen the arm of wealth and counterpoise +the influence of extended suffrage in the disposition of public +affairs." + +This sentiment President Jackson fully shared. In his first message to +Congress he assailed the bank in vigorous language. He declared that its +constitutionality was in doubt and alleged that it had failed to +establish a sound and uniform currency. If such an institution was +necessary, he continued, it should be a public bank, owned and managed +by the government, not a private concern endowed with special privileges +by it. In his second and third messages, Jackson came back to the +subject, leaving the decision, however, to "an enlightened people and +their representatives." + +Moved by this frank hostility and anxious for the future, the bank +applied to Congress for a renewal of its charter in 1832, four years +before the expiration of its life. Clay, with his eye upon the +presidency and an issue for the campaign, warmly supported the +application. Congress, deeply impressed by his leadership, passed the +bill granting the new charter, and sent the open defiance to Jackson. +His response was an instant veto. The battle was on and it raged with +fury until the close of his second administration, ending in the +destruction of the bank, a disordered currency, and a national panic. + +In his veto message, Jackson attacked the bank as unconstitutional and +even hinted at corruption. He refused to assent to the proposition that +the Supreme Court had settled the question of constitutionality by the +decision in the McCulloch case. "Each public officer," he argued, "who +takes an oath to support the Constitution, swears that he will support +it as he understands it, not as it is understood by others." + +Not satisfied with his veto and his declaration against the bank, +Jackson ordered the Secretary of the Treasury to withdraw the government +deposits which formed a large part of the institution's funds. This +action he followed up by an open charge that the bank had used money +shamefully to secure the return of its supporters to Congress. The +Senate, stung by this charge, solemnly resolved that Jackson had +"assumed upon himself authority and power not conferred by the +Constitution and laws, but in derogation of both." + +The effects of the destruction of the bank were widespread. When its +charter expired in 1836, banking was once more committed to the control +of the states. The state legislatures, under a decision rendered by the +Supreme Court after the death of Marshall, began to charter banks under +state ownership and control, with full power to issue paper money--this +in spite of the provision in the Constitution that states shall not +issue bills of credit or make anything but gold and silver coin legal +tender in the payment of debts. Once more the country was flooded by +paper currency of uncertain value. To make matters worse, Jackson +adopted the practice of depositing huge amounts of government funds in +these banks, not forgetting to render favors to those institutions which +supported him in politics--"pet banks," as they were styled at the +time. In 1837, partially, though by no means entirely, as a result of +the abolition of the bank, the country was plunged into one of the most +disastrous panics which it ever experienced. + +=Internal Improvements Checked.=--The bank had presented to Jackson a +very clear problem--one of destruction. Other questions were not so +simple, particularly the subject of federal appropriations in aid of +roads and other internal improvements. Jefferson had strongly favored +government assistance in such matters, but his administration was +followed by a reaction. Both Madison and Monroe vetoed acts of Congress +appropriating public funds for public roads, advancing as their reason +the argument that the Constitution authorized no such laws. Jackson, +puzzled by the clamor on both sides, followed their example without +making the constitutional bar absolute. Congress, he thought, might +lawfully build highways of a national and military value, but he +strongly deprecated attacks by local interests on the federal treasury. + +=The Triumph of the Executive Branch.=--Jackson's reelection in 1832 +served to confirm his opinion that he was the chosen leader of the +people, freed and instructed to ride rough shod over Congress and even +the courts. No President before or since ever entertained in times of +peace such lofty notions of executive prerogative. The entire body of +federal employees he transformed into obedient servants of his wishes, a +sign or a nod from him making and undoing the fortunes of the humble and +the mighty. His lawful cabinet of advisers, filling all of the high +posts in the government, he treated with scant courtesy, preferring +rather to secure his counsel and advice from an unofficial body of +friends and dependents who, owing to their secret methods and back +stairs arrangements, became known as "the kitchen cabinet." Under the +leadership of a silent, astute, and resourceful politician, Amos +Kendall, this informal gathering of the faithful both gave and carried +out decrees and orders, communicating the President's lightest wish or +strictest command to the uttermost part of the country. Resolutely and +in the face of bitter opposition Jackson had removed the deposits from +the United States Bank. When the Senate protested against this arbitrary +conduct, he did not rest until it was forced to expunge the resolution +of condemnation; in time one of his lieutenants with his own hands was +able to tear the censure from the records. When Chief Justice Marshall +issued a decree against Georgia which did not suit him, Jackson, +according to tradition, blurted out that Marshall could go ahead and +enforce his own orders. To the end he pursued his willful way, finally +even choosing his own successor. + + +THE RISE OF THE WHIGS + +=Jackson's Measures Arouse Opposition.=--Measures so decided, policies +so radical, and conduct so high-handed could not fail to arouse against +Jackson a deep and exasperated opposition. The truth is the conduct of +his entire administration profoundly disturbed the business and finances +of the country. It was accompanied by conditions similar to those which +existed under the Articles of Confederation. A paper currency, almost as +unstable and irritating as the worthless notes of revolutionary days, +flooded the country, hindering the easy transaction of business. The use +of federal funds for internal improvements, so vital to the exchange of +commodities which is the very life of industry, was blocked by executive +vetoes. The Supreme Court, which, under Marshall, had held refractory +states to their obligations under the Constitution, was flouted; states' +rights judges, deliberately selected by Jackson for the bench, began to +sap and undermine the rulings of Marshall. The protective tariff, under +which the textile industry of New England, the iron mills of +Pennsylvania, and the wool, flax, and hemp farms of the West had +flourished, had received a severe blow in the compromise of 1833 which +promised a steady reduction of duties. To cap the climax, Jackson's +party, casting aside the old and reputable name of Republican, boldly +chose for its title the term "Democrat," throwing down the gauntlet to +every conservative who doubted the omniscience of the people. All these +things worked together to evoke an opposition that was sharp and +determined. + +[Illustration: AN OLD CARTOON RIDICULING CLAY'S TARIFF AND INTERNAL +IMPROVEMENT PROGRAM] + +=Clay and the National Republicans.=--In this opposition movement, +leadership fell to Henry Clay, a son of Kentucky, rather than to Daniel +Webster of Massachusetts. Like Jackson, Clay was born in a home haunted +by poverty. Left fatherless early and thrown upon his own resources, he +went from Virginia into Kentucky where by sheer force of intellect he +rose to eminence in the profession of law. Without the martial gifts or +the martial spirit of Jackson, he slipped more easily into the social +habits of the East at the same time that he retained his hold on the +affections of the boisterous West. Farmers of Ohio, Indiana, and +Kentucky loved him; financiers of New York and Philadelphia trusted him. +He was thus a leader well fitted to gather the forces of opposition +into union against Jackson. + +Around Clay's standard assembled a motley collection, representing every +species of political opinion, united by one tie only--hatred for "Old +Hickory." Nullifiers and less strenuous advocates of states' rights were +yoked with nationalists of Webster's school; ardent protectionists were +bound together with equally ardent free traders, all fraternizing in one +grand confusion of ideas under the title of "National Republicans." Thus +the ancient and honorable term selected by Jefferson and his party, now +abandoned by Jacksonian Democracy, was adroitly adopted to cover the +supporters of Clay. The platform of the party, however, embraced all the +old Federalist principles: protection for American industry; internal +improvements; respect for the Supreme Court; resistance to executive +tyranny; and denunciation of the spoils system. Though Jackson was +easily victorious in 1832, the popular vote cast for Clay should have +given him some doubts about the faith of "the whole people" in the +wisdom of his "reign." + +=Van Buren and the Panic of 1837.=--Nothing could shake the General's +superb confidence. At the end of his second term he insisted on +selecting his own successor; at a national convention, chosen by party +voters, but packed with his office holders and friends, he nominated +Martin Van Buren of New York. Once more he proved his strength by +carrying the country for the Democrats. With a fine flourish, he +attended the inauguration of Van Buren and then retired, amid the +applause and tears of his devotees, to the Hermitage, his home in +Tennessee. + +Fortunately for him, Jackson escaped the odium of a disastrous panic +which struck the country with terrible force in the following summer. +Among the contributory causes of this crisis, no doubt, were the +destruction of the bank and the issuance of the "specie circular" of + +1836 which required the purchasers of public lands to pay for them in +coin, instead of the paper notes of state banks. Whatever the dominating +cause, the ruin was widespread. Bank after bank went under; boom towns +in the West collapsed; Eastern mills shut down; and working people in +the industrial centers, starving from unemployment, begged for relief. +Van Buren braved the storm, offering no measure of reform or assistance +to the distracted people. He did seek security for government funds by +suggesting the removal of deposits from private banks and the +establishment of an independent treasury system, with government +depositaries for public funds, in several leading cities. This plan was +finally accepted by Congress in 1840. + +Had Van Buren been a captivating figure he might have lived down the +discredit of the panic unjustly laid at his door; but he was far from +being a favorite with the populace. Though a man of many talents, he +owed his position to the quiet and adept management of Jackson rather +than to his own personal qualities. The men of the frontier did not care +for him. They suspected that he ate from "gold plate" and they could not +forgive him for being an astute politician from New York. Still the +Democratic party, remembering Jackson's wishes, renominated him +unanimously in 1840 and saw him go down to utter defeat. + +=The Whigs and General Harrison.=--By this time, the National +Republicans, now known as Whigs--a title taken from the party of +opposition to the Crown in England, had learned many lessons. Taking a +leaf out of the Democratic book, they nominated, not Clay of Kentucky, +well known for his views on the bank, the tariff, and internal +improvements, but a military hero, General William Henry Harrison, a man +of uncertain political opinions. Harrison, a son of a Virginia signer of +the Declaration of Independence, sprang into public view by winning a +battle more famous than important, "Tippecanoe"--a brush with the +Indians in Indiana. He added to his laurels by rendering praiseworthy +services during the war of 1812. When days of peace returned he was +rewarded by a grateful people with a seat in Congress. Then he retired +to quiet life in a little village near Cincinnati. Like Jackson he was +held to be a son of the South and the West. Like Jackson he was a +military hero, a lesser light, but still a light. Like Old Hickory he +rode into office on a tide of popular feeling against an Eastern man +accused of being something of an aristocrat. His personal popularity was +sufficient. The Whigs who nominated him shrewdly refused to adopt a +platform or declare their belief in anything. When some Democrat +asserted that Harrison was a backwoodsman whose sole wants were a jug of +hard cider and a log cabin, the Whigs treated the remark not as an +insult but as proof positive that Harrison deserved the votes of Jackson +men. The jug and the cabin they proudly transformed into symbols of the +campaign, and won for their chieftain 234 electoral votes, while Van +Buren got only sixty. + +=Harrison and Tyler.=--The Hero of Tippecanoe was not long to enjoy the +fruits of his victory. The hungry horde of Whig office seekers descended +upon him like wolves upon the fold. If he went out they waylaid him; if +he stayed indoors, he was besieged; not even his bed chamber was spared. +He was none too strong at best and he took a deep cold on the day of his +inauguration. Between driving out Democrats and appeasing Whigs, he fell +mortally ill. Before the end of a month he lay dead at the capitol. + +Harrison's successor, John Tyler, the Vice President, whom the Whigs had +nominated to catch votes in Virginia, was more of a Democrat than +anything else, though he was not partisan enough to please anybody. The +Whigs railed at him because he would not approve the founding of another +United States Bank. The Democrats stormed at him for refusing, until +near the end of his term, to sanction the annexation of Texas, which had +declared its independence of Mexico in 1836. His entire administration, +marked by unseemly wrangling, produced only two measures of importance. +The Whigs, flushed by victory, with the aid of a few protectionist +Democrats, enacted, in 1842, a new tariff law destroying the compromise +which had brought about the truce between the North and the South, in +the days of nullification. The distinguished leader of the Whigs, Daniel +Webster, as Secretary of State, in negotiation with Lord Ashburton +representing Great Britain, settled the long-standing dispute between +the two countries over the Maine boundary. A year after closing this +chapter in American diplomacy, Webster withdrew to private life, leaving +the President to endure alone the buffets of political fortune. + +To the end, the Whigs regarded Tyler as a traitor to their cause; but +the judgment of history is that it was a case of the biter bitten. They +had nominated him for the vice presidency as a man of views acceptable +to Southern Democrats in order to catch their votes, little reckoning +with the chances of his becoming President. Tyler had not deceived them +and, thoroughly soured, he left the White House in 1845 not to appear in +public life again until the days of secession, when he espoused the +Southern confederacy. Jacksonian Democracy, with new leadership, serving +a new cause--slavery--was returned to power under James K. Polk, a +friend of the General from Tennessee. A few grains of sand were to run +through the hour glass before the Whig party was to be broken and +scattered as the Federalists had been more than a generation before. + + +THE INTERACTION OF AMERICAN AND EUROPEAN OPINION + +=Democracy in England and France.=--During the period of Jacksonian +Democracy, as in all epochs of ferment, there was a close relation +between the thought of the New World and the Old. In England, the +successes of the American experiment were used as arguments in favor of +overthrowing the aristocracy which George III had manipulated with such +effect against America half a century before. In the United States, on +the other hand, conservatives like Chancellor Kent, the stout opponent +of manhood suffrage in New York, cited the riots of the British working +classes as a warning against admitting the same classes to a share in +the government of the United States. Along with the agitation of opinion +went epoch-making events. In 1832, the year of Jackson's second +triumph, the British Parliament passed its first reform bill, which +conferred the ballot--not on workingmen as yet--but on mill owners and +shopkeepers whom the landlords regarded with genuine horror. The initial +step was thus taken in breaking down the privileges of the landed +aristocracy and the rich merchants of England. + +About the same time a popular revolution occurred in France. The Bourbon +family, restored to the throne of France by the allied powers after +their victory over Napoleon in 1815, had embarked upon a policy of +arbitrary government. To use the familiar phrase, they had learned +nothing and forgotten nothing. Charles X, who came to the throne in +1824, set to work with zeal to undo the results of the French +Revolution, to stifle the press, restrict the suffrage, and restore the +clergy and the nobility to their ancient rights. His policy encountered +equally zealous opposition and in 1830 he was overthrown. The popular +party, under the leadership of Lafayette, established, not a republic as +some of the radicals had hoped, but a "liberal" middle-class monarchy +under Louis Philippe. This second French Revolution made a profound +impression on Americans, convincing them that the whole world was moving +toward democracy. The mayor, aldermen, and citizens of New York City +joined in a great parade to celebrate the fall of the Bourbons. Mingled +with cheers for the new order in France were hurrahs for "the people's +own, Andrew Jackson, the Hero of New Orleans and President of the United +States!" + +=European Interest in America.=--To the older and more settled +Europeans, the democratic experiment in America was either a menace or +an inspiration. Conservatives viewed it with anxiety; liberals with +optimism. Far-sighted leaders could see that the tide of democracy was +rising all over the world and could not be stayed. Naturally the country +that had advanced furthest along the new course was the place in which +to find arguments for and against proposals that Europe should make +experiments of the same character. + +=De Tocqueville's _Democracy in America_.=--In addition to the casual +traveler there began to visit the United States the thoughtful observer +bent on finding out what manner of nation this was springing up in the +wilderness. Those who looked with sympathy upon the growing popular +forces of England and France found in the United States, in spite of +many blemishes and defects, a guarantee for the future of the people's +rule in the Old World. One of these, Alexis de Tocqueville, a French +liberal of mildly democratic sympathies, made a journey to this country +in 1831; he described in a very remarkable volume, _Democracy in +America_, the grand experiment as he saw it. On the whole he was +convinced. After examining with a critical eye the life and labor of the +American people, as well as the constitutions of the states and the +nation, he came to the conclusion that democracy with all its faults was +both inevitable and successful. Slavery he thought was a painful +contrast to the other features of American life, and he foresaw what +proved to be the irrepressible conflict over it. He believed that +through blundering the people were destined to learn the highest of all +arts, self-government on a grand scale. The absence of a leisure class, +devoted to no calling or profession, merely enjoying the refinements of +life and adding to its graces--the flaw in American culture that gave +deep distress to many a European leader--de Tocqueville thought a +necessary virtue in the republic. "Amongst a democratic people where +there is no hereditary wealth, every man works to earn a living, or has +worked, or is born of parents who have worked. A notion of labor is +therefore presented to the mind on every side as the necessary, natural, +and honest condition of human existence." It was this notion of a +government in the hands of people who labored that struck the French +publicist as the most significant fact in the modern world. + +=Harriet Martineau's Visit to America.=--This phase of American life +also profoundly impressed the brilliant English writer, Harriet +Martineau. She saw all parts of the country, the homes of the rich and +the log cabins of the frontier; she traveled in stagecoaches, canal +boats, and on horseback; and visited sessions of Congress and auctions +at slave markets. She tried to view the country impartially and the +thing that left the deepest mark on her mind was the solidarity of the +people in one great political body. "However various may be the tribes +of inhabitants in those states, whatever part of the world may have been +their birthplace, or that of their fathers, however broken may be their +language, however servile or noble their employments, however exalted or +despised their state, all are declared to be bound together by equal +political obligations.... In that self-governing country all are held to +have an equal interest in the principles of its institutions and to be +bound in equal duty to watch their workings." Miss Martineau was also +impressed with the passion of Americans for land ownership and +contrasted the United States favorably with England where the tillers of +the soil were either tenants or laborers for wages. + +=Adverse Criticism.=--By no means all observers and writers were +convinced that America was a success. The fastidious traveler, Mrs. +Trollope, who thought the English system of church and state was ideal, +saw in the United States only roughness and ignorance. She lamented the +"total and universal want of manners both in males and females," adding +that while "they appear to have clear heads and active intellects," +there was "no charm, no grace in their conversation." She found +everywhere a lack of reverence for kings, learning, and rank. Other +critics were even more savage. The editor of the _Foreign Quarterly_ +petulantly exclaimed that the United States was "a brigand +confederation." Charles Dickens declared the country to be "so maimed +and lame, so full of sores and ulcers that her best friends turn from +the loathsome creature in disgust." Sydney Smith, editor of the +_Edinburgh Review_, was never tired of trying his caustic wit at the +expense of America. "Their Franklins and Washingtons and all the other +sages and heroes of their revolution were born and bred subjects of the +king of England," he observed in 1820. "During the thirty or forty +years of their independence they have done absolutely nothing for the +sciences, for the arts, for literature, or even for the statesmanlike +studies of politics or political economy.... In the four quarters of the +globe who reads an American book? Or goes to an American play? Or looks +at an American picture or statue?" To put a sharp sting into his taunt +he added, forgetting by whose authority slavery was introduced and +fostered: "Under which of the old tyrannical governments of Europe is +every sixth man a slave whom his fellow creatures may buy and sell?" + +Some Americans, while resenting the hasty and often superficial +judgments of European writers, winced under their satire and took +thought about certain particulars in the indictments brought against +them. The mass of the people, however, bent on the great experiment, +gave little heed to carping critics who saw the flaws and not the +achievements of our country--critics who were in fact less interested in +America than in preventing the rise and growth of democracy in Europe. + + +=References= + +J.S. Bassett, _Life of Andrew Jackson_. + +J.W. Burgess, _The Middle Period_. + +H. Lodge, _Daniel Webster_. + +W. Macdonald, _Jacksonian Democracy_ (American Nation Series). + +Ostrogorski, _Democracy and the Organization of Political Parties_, Vol. +II. + +C.H. Peck, _The Jacksonian Epoch_. + +C. Schurz, _Henry Clay_. + + +=Questions= + +1. By what devices was democracy limited in the first days of our +Republic? + +2. On what grounds were the limitations defended? Attacked? + +3. Outline the rise of political democracy in the United States. + +4. Describe three important changes in our political system. + +5. Contrast the Presidents of the old and the new generations. + +6. Account for the unpopularity of John Adams' administration. + +7. What had been the career of Andrew Jackson before 1829? + +8. Sketch the history of the protective tariff and explain the theory +underlying it. + +9. Explain the growth of Southern opposition to the tariff. + +10. Relate the leading events connected with nullification in South +Carolina. + +11. State Jackson's views and tell the outcome of the controversy. + +12. Why was Jackson opposed to the bank? How did he finally destroy it? + +13. The Whigs complained of Jackson's "executive tyranny." What did they +mean? + +14. Give some of the leading events in Clay's career. + +15. How do you account for the triumph of Harrison in 1840? + +16. Why was Europe especially interested in America at this period? Who +were some of the European writers on American affairs? + + +=Research Topics= + +=Jackson's Criticisms of the Bank.=--Macdonald, _Documentary Source +Book_, pp. 320-329. + +=Financial Aspects of the Bank Controversy.=--Dewey, _Financial History +of the United States_, Sections 86-87; Elson, _History of the United +States_, pp. 492-496. + +=Jackson's View of the Union.=--See his proclamation on nullification in +Macdonald, pp. 333-340. + +=Nullification.=--McMaster, _History of the People of the United +States_, Vol. VI, pp. 153-182; Elson, pp. 487-492. + +=The Webster-Hayne Debate.=--Analyze the arguments. Extensive extracts +are given in Macdonald's larger three-volume work, _Select Documents of +United States History, 1776-1761_, pp. 239-260. + +=The Character of Jackson's Administration.=--Woodrow Wilson, _History +of the American People_, Vol. IV, pp. 1-87; Elson, pp. 498-501. + +=The People in 1830.=--From contemporary writings in Hart, _American +History Told by Contemporaries_, Vol. III, pp. 509-530. + +=Biographical Studies.=--Andrew Jackson, J.Q. Adams, Henry Clay, Daniel +Webster, J.C. Calhoun, and W.H. Harrison. + + + + +CHAPTER XII + +THE MIDDLE BORDER AND THE GREAT WEST + + +"We shall not send an emigrant beyond the Mississippi in a hundred +years," exclaimed Livingston, the principal author of the Louisiana +purchase. When he made this astounding declaration, he doubtless had +before his mind's eye the great stretches of unoccupied lands between +the Appalachians and the Mississippi. He also had before him the history +of the English colonies, which told him of the two centuries required to +settle the seaboard region. To practical men, his prophecy did not seem +far wrong; but before the lapse of half that time there appeared beyond +the Mississippi a tier of new states, reaching from the Gulf of Mexico +to the southern boundary of Minnesota, and a new commonwealth on the +Pacific Ocean where American emigrants had raised the Bear flag of +California. + + +THE ADVANCE OF THE MIDDLE BORDER + +=Missouri.=--When the middle of the nineteenth century had been reached, +the Mississippi River, which Daniel Boone, the intrepid hunter, had +crossed during Washington's administration "to escape from civilization" +in Kentucky, had become the waterway for a vast empire. The center of +population of the United States had passed to the Ohio Valley. Missouri, +with its wide reaches of rich lands, low-lying, level, and fertile, well +adapted to hemp raising, had drawn to its borders thousands of planters +from the old Southern states--from Virginia and the Carolinas as well as +from Kentucky and Tennessee. When the great compromise of 1820-21 +admitted her to the union, wearing "every jewel of sovereignty," as a +florid orator announced, migratory slave owners were assured that their +property would be safe in Missouri. Along the western shore of the +Mississippi and on both banks of the Missouri to the uttermost limits of +the state, plantations tilled by bondmen spread out in broad expanses. +In the neighborhood of Jefferson City the slaves numbered more than a +fourth of the population. + +Into this stream of migration from the planting South flowed another +current of land-tilling farmers; some from Kentucky, Tennessee, and +Mississippi, driven out by the onrush of the planters buying and +consolidating small farms into vast estates; and still more from the +East and the Old World. To the northwest over against Iowa and to the +southwest against Arkansas, these yeomen laid out farms to be tilled by +their own labor. In those regions the number of slaves seldom rose above +five or six per cent of the population. The old French post, St. Louis, +enriched by the fur trade of the Far West and the steamboat traffic of +the river, grew into a thriving commercial city, including among its +seventy-five thousand inhabitants in 1850 nearly forty thousand +foreigners, German immigrants from Pennsylvania and Europe being the +largest single element. + +=Arkansas.=--Below Missouri lay the territory of Arkansas, which had +long been the paradise of the swarthy hunter and the restless +frontiersman fleeing from the advancing borders of farm and town. In +search of the life, wild and free, where the rifle supplied the game and +a few acres of ground the corn and potatoes, they had filtered into the +territory in an unending drift, "squatting" on the land. Without so much +as asking the leave of any government, territorial or national, they +claimed as their own the soil on which they first planted their feet. +Like the Cherokee Indians, whom they had as neighbors, whose very +customs and dress they sometimes adopted, the squatters spent their days +in the midst of rough plenty, beset by chills, fevers, and the ills of +the flesh, but for many years unvexed by political troubles or the +restrictions of civilized life. + +Unfortunately for them, however, the fertile valleys of the Mississippi +and Arkansas were well adapted to the cultivation of cotton and tobacco +and their sylvan peace was soon broken by an invasion of planters. The +newcomers, with their servile workers, spread upward in the valley +toward Missouri and along the southern border westward to the Red River. +In time the slaves in the tier of counties against Louisiana ranged from +thirty to seventy per cent of the population. This marked the doom of +the small farmer, swept Arkansas into the main current of planting +politics, and led to a powerful lobby at Washington in favor of +admission to the union, a boon granted in 1836. + +=Michigan.=--In accordance with a well-established custom, a free state +was admitted to the union to balance a slave state. In 1833, the people +of Michigan, a territory ten times the size of Connecticut, announced +that the time had come for them to enjoy the privileges of a +commonwealth. All along the southern border the land had been occupied +largely by pioneers from New England, who built prim farmhouses and +adopted the town-meeting plan of self-government after the fashion of +the old home. The famous post of Detroit was growing into a flourishing +city as the boats plying on the Great Lakes carried travelers, settlers, +and freight through the narrows. In all, according to the census, there +were more than ninety thousand inhabitants in the territory; so it was +not without warrant that they clamored for statehood. Congress, busy as +ever with politics, delayed; and the inhabitants of Michigan, unable to +restrain their impatience, called a convention, drew up a constitution, +and started a lively quarrel with Ohio over the southern boundary. The +hand of Congress was now forced. Objections were made to the new +constitution on the ground that it gave the ballot to all free white +males, including aliens not yet naturalized; but the protests were +overborne in a long debate. The boundary was fixed, and Michigan, though +shorn of some of the land she claimed, came into the union in 1837. + +=Wisconsin.=--Across Lake Michigan to the west lay the territory of +Wisconsin, which shared with Michigan the interesting history of the +Northwest, running back into the heroic days when French hunters and +missionaries were planning a French empire for the great monarch, Louis +XIV. It will not be forgotten that the French rangers of the woods, the +black-robed priests, prepared for sacrifice, even to death, the trappers +of the French agencies, and the French explorers--Marquette, Joliet, and +Menard--were the first white men to paddle their frail barks through the +northern waters. They first blazed their trails into the black forests +and left traces of their work in the names of portages and little +villages. It was from these forests that Red Men in full war paint +journeyed far to fight under the _fleur-de-lis_ of France when the +soldiers of King Louis made their last stand at Quebec and Montreal +against the imperial arms of Britain. It was here that the British flag +was planted in 1761 and that the great Pontiac conspiracy was formed two +years later to overthrow British dominion. + +When, a generation afterward, the Stars and Stripes supplanted the Union +Jack, the French were still almost the only white men in the region. +They were soon joined by hustling Yankee fur traders who did battle +royal against British interlopers. The traders cut their way through +forest trails and laid out the routes through lake and stream and over +portages for the settlers and their families from the states "back +East." It was the forest ranger who discovered the water power later +used to turn the busy mills grinding the grain from the spreading farm +lands. In the wake of the fur hunters, forest men, and farmers came +miners from Kentucky, Tennessee, and Missouri crowding in to exploit the +lead ores of the northwest, some of them bringing slaves to work their +claims. Had it not been for the gold fever of 1849 that drew the +wielders of pick and shovel to the Far West, Wisconsin would early have +taken high rank among the mining regions of the country. + +From a favorable point of vantage on Lake Michigan, the village of +Milwaukee, a center for lumber and grain transport and a place of entry +for Eastern goods, grew into a thriving city. It claimed twenty thousand +inhabitants, when in 1848 Congress admitted Wisconsin to the union. +Already the Germans, Irish, and Scandinavians had found their way into +the territory. They joined Americans from the older states in clearing +forests, building roads, transforming trails into highways, erecting +mills, and connecting streams with canals to make a network of routes +for the traffic that poured to and from the Great Lakes. + +=Iowa and Minnesota.=--To the southwest of Wisconsin beyond the +Mississippi, where the tall grass of the prairies waved like the sea, +farmers from New England, New York, and Ohio had prepared Iowa for +statehood. A tide of immigration that might have flowed into Missouri +went northward; for freemen, unaccustomed to slavery and slave markets, +preferred the open country above the compromise line. With incredible +swiftness, they spread farms westward from the Mississippi. With Yankee +ingenuity they turned to trading on the river, building before 1836 +three prosperous centers of traffic: Dubuque, Davenport, and Burlington. +True to their old traditions, they founded colleges and academies that +religion and learning might be cherished on the frontier as in the +states from which they came. Prepared for self-government, the Iowans +laid siege to the door of Congress and were admitted to the union in +1846. + +Above Iowa, on the Mississippi, lay the territory of Minnesota--the home +of the Dakotas, the Ojibways, and the Sioux. Like Michigan and +Wisconsin, it had been explored early by the French scouts, and the +first white settlement was the little French village of Mendota. To the +people of the United States, the resources of the country were first +revealed by the historic journey of Zebulon Pike in 1805 and by American +fur traders who were quick to take advantage of the opportunity to ply +their arts of hunting and bartering in fresh fields. In 1839 an +American settlement was planted at Marina on the St. Croix, the outpost +of advancing civilization. Within twenty years, the territory, boasting +a population of 150,000, asked for admission to the union. In 1858 the +plea was granted and Minnesota showed her gratitude three years later by +being first among the states to offer troops to Lincoln in the hour of +peril. + + +ON TO THE PACIFIC--TEXAS AND THE MEXICAN WAR + +=The Uniformity of the Middle West.=--There was a certain monotony about +pioneering in the Northwest and on the middle border. As the long +stretches of land were cleared or prepared for the plow, they were laid +out like checkerboards into squares of forty, eighty, one hundred sixty, +or more acres, each the seat of a homestead. There was a striking +uniformity also about the endless succession of fertile fields spreading +far and wide under the hot summer sun. No majestic mountains relieved +the sweep of the prairie. Few monuments of other races and antiquity +were there to awaken curiosity about the region. No sonorous bells in +old missions rang out the time of day. The chaffering Red Man bartering +blankets and furs for powder and whisky had passed farther on. The +population was made up of plain farmers and their families engaged in +severe and unbroken labor, chopping down trees, draining fever-breeding +swamps, breaking new ground, and planting from year to year the same +rotation of crops. Nearly all the settlers were of native American stock +into whose frugal and industrious lives the later Irish and German +immigrants fitted, on the whole, with little friction. Even the Dutch +oven fell before the cast-iron cooking stove. Happiness and sorrow, +despair and hope were there, but all encompassed by the heavy tedium of +prosaic sameness. + +[Illustration: SANTA BARBARA MISSION] + +=A Contrast in the Far West and Southwest.=--As George Rogers Clark and +Daniel Boone had stirred the snug Americans of the seaboard to seek +their fortunes beyond the Appalachians, so now Kit Carson, James Bowie, +Sam Houston, Davy Crockett, and John C. Fremont were to lead the way +into a new land, only a part of which was under the American flag. The +setting for this new scene in the westward movement was thrown out in a +wide sweep from the headwaters of the Mississippi to the banks of the +Rio Grande; from the valleys of the Sabine and Red rivers to Montana and +the Pacific slope. In comparison with the middle border, this region +presented such startling diversities that only the eye of faith could +foresee the unifying power of nationalism binding its communities with +the older sections of the country. What contrasts indeed! The blue grass +region of Kentucky or the rich, black soil of Illinois--the painted +desert, the home of the sage brush and the coyote! The level prairies of +Iowa--the mighty Rockies shouldering themselves high against the +horizon! The long bleak winters of Wisconsin--California of endless +summer! The log churches of Indiana or Illinois--the quaint missions of +San Antonio, Tucson, and Santa Barbara! The little state of +Delaware--the empire of Texas, one hundred and twenty times its area! +And scattered about through the Southwest were signs of an ancient +civilization--fragments of four-and five-story dwellings, ruined dams, +aqueducts, and broken canals, which told of once prosperous peoples +who, by art and science, had conquered the aridity of the desert and +lifted themselves in the scale of culture above the savages of the +plain. + +The settlers of this vast empire were to be as diverse in their origins +and habits as those of the colonies on the coast had been. Americans of +English, Irish, and Scotch-Irish descent came as usual from the Eastern +states. To them were added the migratory Germans as well. Now for the +first time came throngs of Scandinavians. Some were to make their homes +on quiet farms as the border advanced against the setting sun. Others +were to be Indian scouts, trappers, fur hunters, miners, cowboys, Texas +planters, keepers of lonely posts on the plain and the desert, stage +drivers, pilots of wagon trains, pony riders, fruit growers, "lumber +jacks," and smelter workers. One common bond united them--a passion for +the self-government accorded to states. As soon as a few thousand +settlers came together in a single territory, there arose a mighty shout +for a position beside the staid commonwealths of the East and the South. +Statehood meant to the pioneers self-government, dignity, and the right +to dispose of land, minerals, and timber in their own way. In the quest +for this local autonomy there arose many a wordy contest in Congress, +each of the political parties lending a helping hand in the admission of +a state when it gave promise of adding new congressmen of the "right +political persuasion," to use the current phrase. + +=Southern Planters and Texas.=--While the farmers of the North found the +broad acres of the Western prairies stretching on before them apparently +in endless expanse, it was far different with the Southern planters. +Ever active in their search for new fields as they exhausted the virgin +soil of the older states, the restless subjects of King Cotton quickly +reached the frontier of Louisiana. There they paused; but only for a +moment. The fertile land of Texas just across the boundary lured them on +and the Mexican republic to which it belonged extended to them a more +than generous welcome. Little realizing the perils lurking in a +"peaceful penetration," the authorities at Mexico City opened wide the +doors and made large grants of land to American contractors, who agreed +to bring a number of families into Texas. The omnipresent Yankee, in the +person of Moses Austin of Connecticut, hearing of this good news in the +Southwest, obtained a grant in 1820 to settle three hundred Americans +near Bexar--a commission finally carried out to the letter by his son +and celebrated in the name given to the present capital of the state of +Texas. Within a decade some twenty thousand Americans had crossed the +border. + +=Mexico Closes the Door.=--The government of Mexico, unaccustomed to +such enterprise and thoroughly frightened by its extent, drew back in +dismay. Its fears were increased as quarrels broke out between the +Americans and the natives in Texas. Fear grew into consternation when +efforts were made by President Jackson to buy the territory for the +United States. Mexico then sought to close the flood gates. It stopped +all American colonization schemes, canceled many of the land grants, put +a tariff on farming implements, and abolished slavery. These barriers +were raised too late. A call for help ran through the western border of +the United States. The sentinels of the frontier answered. Davy +Crockett, the noted frontiersman, bear hunter, and backwoods politician; +James Bowie, the dexterous wielder of the knife that to this day bears +his name; and Sam Houston, warrior and pioneer, rushed to the aid of +their countrymen in Texas. Unacquainted with the niceties of diplomacy, +impatient at the formalities of international law, they soon made it +known that in spite of Mexican sovereignty they would be their own +masters. + +=The Independence of Texas Declared.=--Numbering only about one-fourth +of the population in Texas, they raised the standard of revolt in 1836 +and summoned a convention. Following in the footsteps of their +ancestors, they issued a declaration of independence signed mainly by +Americans from the slave states. Anticipating that the government of +Mexico would not quietly accept their word of defiance as final, they +dispatched a force to repel "the invading army," as General Houston +called the troops advancing under the command of Santa Ana, the Mexican +president. A portion of the Texan soldiers took their stand in the +Alamo, an old Spanish mission in the cottonwood trees in the town of San +Antonio. Instead of obeying the order to blow up the mission and retire, +they held their ground until they were completely surrounded and cut off +from all help. Refusing to surrender, they fought to the bitter end, the +last man falling a victim to the sword. Vengeance was swift. Within +three months General Houston overwhelmed Santa Ana at the San Jacinto, +taking him prisoner of war and putting an end to all hopes for the +restoration of Mexican sovereignty over Texas. + +The Lone Star Republic, with Houston at the head, then sought admission +to the United States. This seemed at first an easy matter. All that was +required to bring it about appeared to be a treaty annexing Texas to the +union. Moreover, President Jackson, at the height of his popularity, had +a warm regard for General Houston and, with his usual sympathy for rough +and ready ways of doing things, approved the transaction. Through an +American representative in Mexico, Jackson had long and anxiously +labored, by means none too nice, to wring from the Mexican republic the +cession of the coveted territory. When the Texans took matters into +their own hands, he was more than pleased; but he could not marshal the +approval of two-thirds of the Senators required for a treaty of +annexation. Cautious as well as impetuous, Jackson did not press the +issue; he went out of office in 1837 with Texas uncertain as to her +future. + +=Northern Opposition to Annexation.=--All through the North the +opposition to annexation was clear and strong. Anti-slavery agitators +could hardly find words savage enough to express their feelings. +"Texas," exclaimed Channing in a letter to Clay, "is but the first step +of aggression. I trust indeed that Providence will beat back and humble +our cupidity and ambition. I now ask whether as a people we are +prepared to seize on a neighboring territory for the end of extending +slavery? I ask whether as a people we can stand forth in the sight of +God, in the sight of nations, and adopt this atrocious policy? Sooner +perish! Sooner be our name blotted out from the record of nations!" +William Lloyd Garrison called for the secession of the Northern states +if Texas was brought into the union with slavery. John Quincy Adams +warned his countrymen that they were treading in the path of the +imperialism that had brought the nations of antiquity to judgment and +destruction. Henry Clay, the Whig candidate for President, taking into +account changing public sentiment, blew hot and cold, losing the state +of New York and the election of 1844 by giving a qualified approval of +annexation. In the same campaign, the Democrats boldly demanded the +"Reannexation of Texas," based on claims which the United States once +had to Spanish territory beyond the Sabine River. + +=Annexation.=--The politicians were disposed to walk very warily. Van +Buren, at heart opposed to slavery extension, refused to press the issue +of annexation. Tyler, a pro-slavery Democrat from Virginia, by a strange +fling of fortune carried into office as a nominal Whig, kept his mind +firmly fixed on the idea of reelection and let the troublesome matter +rest until the end of his administration was in sight. He then listened +with favor to the voice of the South. Calhoun stated what seemed to be a +convincing argument: All good Americans have their hearts set on the +Constitution; the admission of Texas is absolutely essential to the +preservation of the union; it will give a balance of power to the South +as against the North growing with incredible swiftness in wealth and +population. Tyler, impressed by the plea, appointed Calhoun to the +office of Secretary of State in 1844, authorizing him to negotiate the +treaty of annexation--a commission at once executed. This scheme was +blocked in the Senate where the necessary two-thirds vote could not be +secured. Balked but not defeated, the advocates of annexation drew up a +joint resolution which required only a majority vote in both houses, +and in February of the next year, just before Tyler gave way to Polk, +they pushed it through Congress. So Texas, amid the groans of Boston and +the hurrahs of Charleston, folded up her flag and came into the union. + +[Illustration: TEXAS AND THE TERRITORY IN DISPUTE] + +=The Mexican War.=--The inevitable war with Mexico, foretold by the +abolitionists and feared by Henry Clay, ensued, the ostensible cause +being a dispute over the boundaries of the new state. The Texans claimed +all the lands down to the Rio Grande. The Mexicans placed the border of +Texas at the Nueces River and a line drawn thence in a northerly +direction. President Polk, accepting the Texan view of the controversy, +ordered General Zachary Taylor to move beyond the Nueces in defense of +American sovereignty. This act of power, deemed by the Mexicans an +invasion of their territory, was followed by an attack on our troops. + +President Polk, not displeased with the turn of events, announced that +American blood had been "spilled on American soil" and that war existed +"by the act of Mexico." Congress, in a burst of patriotic fervor, +brushed aside the protests of those who deplored the conduct of the +government as wanton aggression on a weaker nation and granted money and +supplies to prosecute the war. The few Whigs in the House of +Representatives, who refused to vote in favor of taking up arms, +accepted the inevitable with such good grace as they could command. All +through the South and the West the war was popular. New England +grumbled, but gave loyal, if not enthusiastic, support to a conflict +precipitated by policies not of its own choosing. Only a handful of firm +objectors held out. James Russell Lowell, in his _Biglow Papers_, flung +scorn and sarcasm to the bitter end. + +=The Outcome of the War.=--The foregone conclusion was soon reached. +General Taylor might have delivered the fatal thrust from northern +Mexico if politics had not intervened. Polk, anxious to avoid raising up +another military hero for the Whigs to nominate for President, decided +to divide the honors by sending General Scott to strike a blow at the +capital, Mexico City. The deed was done with speed and pomp and two +heroes were lifted into presidential possibilities. In the Far West a +third candidate was made, John C. Fremont, who, in cooperation with +Commodores Sloat and Stockton and General Kearney, planted the Stars and +Stripes on the Pacific slope. + +In February, 1848, the Mexicans came to terms, ceding to the victor +California, Arizona, New Mexico, and more--a domain greater in extent +than the combined areas of France and Germany. As a salve to the wound, +the vanquished received fifteen million dollars in cash and the +cancellation of many claims held by American citizens. Five years later, +through the negotiations of James Gadsden, a further cession of lands +along the southern border of Arizona and New Mexico was secured on +payment of ten million dollars. + +=General Taylor Elected President.=--The ink was hardly dry upon the +treaty that closed the war before "rough and ready" General Taylor, a +slave owner from Louisiana, "a Whig," as he said, "but not an ultra +Whig," was put forward as the Whig candidate for President. He himself +had not voted for years and he was fairly innocent in matters political. +The tariff, the currency, and internal improvements, with a magnificent +gesture he referred to the people's representatives in Congress, +offering to enforce the laws as made, if elected. Clay's followers +mourned. Polk stormed but could not win even a renomination at the hands +of the Democrats. So it came about that the hero of Buena Vista, +celebrated for his laconic order, "Give 'em a little more grape, Captain +Bragg," became President of the United States. + + +THE PACIFIC COAST AND UTAH + +=Oregon.=--Closely associated in the popular mind with the contest about +the affairs of Texas was a dispute with Great Britain over the +possession of territory in Oregon. In their presidential campaign of +1844, the Democrats had coupled with the slogan, "The Reannexation of +Texas," two other cries, "The Reoccupation of Oregon," and "Fifty-four +Forty or Fight." The last two slogans were founded on American +discoveries and explorations in the Far Northwest. Their appearance in +politics showed that the distant Oregon country, larger in area than New +England, New York, and Pennsylvania combined, was at last receiving from +the nation the attention which its importance warranted. + +_Joint Occupation and Settlement._--Both England and the United States +had long laid claim to Oregon and in 1818 they had agreed to occupy the +territory jointly--a contract which was renewed ten years later for an +indefinite period. Under this plan, citizens of both countries were free +to hunt and settle anywhere in the region. The vanguard of British fur +traders and Canadian priests was enlarged by many new recruits, with +Americans not far behind them. John Jacob Astor, the resourceful New +York merchant, sent out trappers and hunters who established a trading +post at Astoria in 1811. Some twenty years later, American +missionaries--among them two very remarkable men, Jason Lee and Marcus +Whitman--were preaching the gospel to the Indians. + +Through news from the fur traders and missionaries, Eastern farmers +heard of the fertile lands awaiting their plows on the Pacific slope; +those with the pioneering spirit made ready to take possession of the +new country. In 1839 a band went around by Cape Horn. Four years later a +great expedition went overland. The way once broken, others followed +rapidly. As soon as a few settlements were well established, the +pioneers held a mass meeting and agreed upon a plan of government. "We, +the people of Oregon territory," runs the preamble to their compact, +"for the purposes of mutual protection and to secure peace and +prosperity among ourselves, agree to adopt the following laws and +regulations until such time as the United States of America extend their +jurisdiction over us." Thus self-government made its way across the +Rocky Mountains. + +[Illustration: THE OREGON COUNTRY AND THE DISPUTED BOUNDARY] + +_The Boundary Dispute with England Adjusted._--By this time it was +evident that the boundaries of Oregon must be fixed. Having made the +question an issue in his campaign, Polk, after his election in 1844, +pressed it upon the attention of the country. In his inaugural address +and his first message to Congress he reiterated the claim of the +Democratic platform that "our title to the whole territory of Oregon is +clear and unquestionable." This pretension Great Britain firmly +rejected, leaving the President a choice between war and compromise. + +Polk, already having the contest with Mexico on his hands, sought and +obtained a compromise. The British government, moved by a hint from the +American minister, offered a settlement which would fix the boundary at +the forty-ninth parallel instead of "fifty-four forty," and give it +Vancouver Island. Polk speedily chose this way out of the dilemma. +Instead of making the decision himself, however, and drawing up a +treaty, he turned to the Senate for "counsel." As prearranged with party +leaders, the advice was favorable to the plan. The treaty, duly drawn in +1846, was ratified by the Senate after an acrimonious debate. "Oh! +mountain that was delivered of a mouse," exclaimed Senator Benton, "thy +name shall be fifty-four forty!" Thirteen years later, the southern part +of the territory was admitted to the union as the state of Oregon, +leaving the northern and eastern sections in the status of a territory. + +=California.=--With the growth of the northwestern empire, dedicated by +nature to freedom, the planting interests might have been content, had +fortune not wrested from them the fair country of California. Upon this +huge territory they had set their hearts. The mild climate and fertile +soil seemed well suited to slavery and the planters expected to extend +their sway to the entire domain. California was a state of more than +155,000 square miles--about seventy times the size of the state of +Delaware. It could readily be divided into five or six large states, if +that became necessary to preserve the Southern balance of power. + +_Early American Relations with California._--Time and tide, it seems, +were not on the side of the planters. Already Americans of a far +different type were invading the Pacific slope. Long before Polk ever +dreamed of California, the Yankee with his cargo of notions had been +around the Horn. Daring skippers had sailed out of New England harbors +with a variety of goods, bent their course around South America to +California, on to China and around the world, trading as they went and +leaving pots, pans, woolen cloth, guns, boots, shoes, salt fish, naval +stores, and rum in their wake. "Home from Californy!" rang the cry in +many a New England port as a good captain let go his anchor on his +return from the long trading voyage in the Pacific. + +[Illustration: THE OVERLAND TRAILS] + +_The Overland Trails._--Not to be outdone by the mariners of the deep, +western scouts searched for overland routes to the Pacific. Zebulon +Pike, explorer and pathfinder, by his expedition into the Southwest +during Jefferson's administration, had discovered the resources of New +Spain and had shown his countrymen how easy it was to reach Santa Fe +from the upper waters of the Arkansas River. Not long afterward, traders +laid open the route, making Franklin, Missouri, and later Fort +Leavenworth the starting point. Along the trail, once surveyed, poured +caravans heavily guarded by armed men against marauding Indians. Sand +storms often wiped out all signs of the route; hunger and thirst did +many a band of wagoners to death; but the lure of the game and the +profits at the end kept the business thriving. Huge stocks of cottons, +glass, hardware, and ammunition were drawn almost across the continent +to be exchanged at Santa Fe for furs, Indian blankets, silver, and +mules; and many a fortune was made out of the traffic. + +_Americans in California._--Why stop at Santa Fe? The question did not +long remain unanswered. In 1829, Ewing Young broke the path to Los +Angeles. Thirteen years later Fremont made the first of his celebrated +expeditions across plain, desert, and mountain, arousing the interest of +the entire country in the Far West. In the wake of the pathfinders went +adventurers, settlers, and artisans. By 1847, more than one-fifth of the +inhabitants in the little post of two thousand on San Francisco Bay were +from the United States. The Mexican War, therefore, was not the +beginning but the end of the American conquest of California--a conquest +initiated by Americans who went to till the soil, to trade, or to follow +some mechanical pursuit. + +_The Discovery of Gold._--As if to clinch the hold on California already +secured by the friends of free soil, there came in 1848 the sudden +discovery of gold at Sutter's Mill in the Sacramento Valley. When this +exciting news reached the East, a mighty rush began to California, over +the trails, across the Isthmus of Panama, and around Cape Horn. Before +two years had passed, it is estimated that a hundred thousand people, in +search of fortunes, had arrived in California--mechanics, teachers, +doctors, lawyers, farmers, miners, and laborers from the four corners of +the earth. + +[Illustration: _From an old print_ + +SAN FRANCISCO IN 1849] + +_California a Free State._--With this increase in population there +naturally resulted the usual demand for admission to the union. Instead +of waiting for authority from Washington, the Californians held a +convention in 1849 and framed their constitution. With impatience, the +delegates brushed aside the plea that "the balance of power between the +North and South" required the admission of their state as a slave +commonwealth. Without a dissenting voice, they voted in favor of freedom +and boldly made their request for inclusion among the United States. +President Taylor, though a Southern man, advised Congress to admit the +applicant. Robert Toombs of Georgia vowed to God that he preferred +secession. Henry Clay, the great compromiser, came to the rescue and in +1850 California was admitted as a free state. + +=Utah.=--On the long road to California, in the midst of forbidding and +barren wastes, a religious sect, the Mormons, had planted a colony +destined to a stormy career. Founded in 1830 under the leadership of +Joseph Smith of New York, the sect had suffered from many cruel buffets +of fortune. From Ohio they had migrated into Missouri where they were +set upon and beaten. Some of them were murdered by indignant neighbors. +Harried out of Missouri, they went into Illinois only to see their +director and prophet, Smith, first imprisoned by the authorities and +then shot by a mob. Having raised up a cloud of enemies on account of +both their religious faith and their practice of allowing a man to have +more than one wife, they fell in heartily with the suggestion of a new +leader, Brigham Young, that they go into the Far West beyond the plains +of Kansas--into the forlorn desert where the wicked would cease from +troubling and the weary could be at rest, as they read in the Bible. In +1847, Young, with a company of picked men, searched far and wide until +he found a suitable spot overlooking the Salt Lake Valley. Returning to +Illinois, he gathered up his followers, now numbering several thousand, +and in one mighty wagon caravan they all went to their distant haven. + +_Brigham Young and His Economic System._--In Brigham Young the Mormons +had a leader of remarkable power who gave direction to the redemption of +the arid soil, the management of property, and the upbuilding of +industry. He promised them to make the desert blossom as the rose, and +verily he did it. He firmly shaped the enterprise of the colony along +co-operative lines, holding down the speculator and profiteer with one +hand and giving encouragement to the industrious poor with the other. +With the shrewdness befitting a good business man, he knew how to draw +the line between public and private interest. Land was given outright to +each family, but great care was exercised in the distribution so that +none should have great advantage over another. The purchase of supplies +and the sale of produce were carried on through a cooperative store, the +profits of which went to the common good. Encountering for the first +time in the history of the Anglo-Saxon race the problem of aridity, the +Mormons surmounted the most perplexing obstacles with astounding skill. +They built irrigation works by cooperative labor and granted water +rights to all families on equitable terms. + +_The Growth of Industries._--Though farming long remained the major +interest of the colony, the Mormons, eager to be self-supporting in +every possible way, bent their efforts also to manufacturing and later +to mining. Their missionaries, who hunted in the highways and byways of +Europe for converts, never failed to stress the economic advantages of +the sect. "We want," proclaimed President Young to all the earth, "a +company of woolen manufacturers to come with machinery and take the wool +from the sheep and convert it into the best clothes. We want a company +of potters; we need them; the clay is ready and the dishes wanted.... We +want some men to start a furnace forthwith; the iron, coal, and molders +are waiting.... We have a printing press and any one who can take good +printing and writing paper to the Valley will be a blessing to +themselves and the church." Roads and bridges were built; millions were +spent in experiments in agriculture and manufacturing; missionaries at a +huge cost were maintained in the East and in Europe; an army was kept +for defense against the Indians; and colonies were planted in the +outlying regions. A historian of Deseret, as the colony was called by +the Mormons, estimated in 1895 that by the labor of their hands the +people had produced nearly half a billion dollars in wealth since the +coming of the vanguard. + +_Polygamy Forbidden._--The hope of the Mormons that they might forever +remain undisturbed by outsiders was soon dashed to earth, for hundreds +of farmers and artisans belonging to other religious sects came to +settle among them. In 1850 the colony was so populous and prosperous +that it was organized into a territory of the United States and brought +under the supervision of the federal government. Protests against +polygamy were raised in the colony and at the seat of authority three +thousand miles away at Washington. The new Republican party in 1856 +proclaimed it "the right and duty of Congress to prohibit in the +Territories those twin relics of barbarism, polygamy and slavery." In +due time the Mormons had to give up their marriage practices which were +condemned by the common opinion of all western civilization; but they +kept their religious faith. Monuments to their early enterprise are seen +in the Temple and the Tabernacle, the irrigation works, and the great +wealth of the Church. + + +SUMMARY OF WESTERN DEVELOPMENT AND NATIONAL POLITICS + +While the statesmen of the old generation were solving the problems of +their age, hunters, pioneers, and home seekers were preparing new +problems beyond the Alleghanies. The West was rising in population and +wealth. Between 1783 and 1829, eleven states were added to the original +thirteen. All but two were in the West. Two of them were in the +Louisiana territory beyond the Mississippi. Here the process of +colonization was repeated. Hardy frontier people cut down the forests, +built log cabins, laid out farms, and cut roads through the wilderness. +They began a new civilization just as the immigrants to Virginia or +Massachusetts had done two centuries earlier. + +Like the seaboard colonists before them, they too cherished the spirit +of independence and power. They had not gone far upon their course +before they resented the monopoly of the presidency by the East. In 1829 +they actually sent one of their own cherished leaders, Andrew Jackson, +to the White House. Again in 1840, in 1844, in 1848, and in 1860, the +Mississippi Valley could boast that one of its sons had been chosen for +the seat of power at Washington. Its democratic temper evoked a cordial +response in the towns of the East where the old aristocracy had been put +aside and artisans had been given the ballot. + +For three decades the West occupied the interest of the nation. Under +Jackson's leadership, it destroyed the second United States Bank. When +he smote nullification in South Carolina, it gave him cordial support. +It approved his policy of parceling out government offices among party +workers--"the spoils system" in all its fullness. On only one point did +it really dissent. The West heartily favored internal improvements, the +appropriation of federal funds for highways, canals, and railways. +Jackson had misgivings on this question and awakened sharp criticism by +vetoing a road improvement bill. + +From their point of vantage on the frontier, the pioneers pressed on +westward. They pushed into Texas, created a state, declared their +independence, demanded a place in the union, and precipitated a war with +Mexico. They crossed the trackless plain and desert, laying out trails +to Santa Fe, to Oregon, and to California. They were upon the scene when +the Mexican War brought California under the Stars and Stripes. They had +laid out their farms in the Willamette Valley when the slogan +"Fifty-Four Forty or Fight" forced a settlement of the Oregon boundary. +California and Oregon were already in the union when there arose the +Great Civil War testing whether this nation or any nation so conceived +and so dedicated could long endure. + + +=References= + +G.P. Brown, _Westward Expansion_ (American Nation Series). + + +K. Coman, _Economic Beginnings of the Far West_ (2 vols.). + +F. Parkman, _California and the Oregon Trail_. + +R.S. Ripley, _The War with Mexico_. + +W.C. Rives, _The United States and Mexico, 1821-48_ (2 vols.). + + +=Questions= + +1. Give some of the special features in the history of Missouri, +Arkansas, Michigan, Wisconsin, Iowa, and Minnesota. + +2. Contrast the climate and soil of the Middle West and the Far West. + +3. How did Mexico at first encourage American immigration? + +4. What produced the revolution in Texas? Who led in it? + +5. Narrate some of the leading events in the struggle over annexation to +the United States. + +6. What action by President Polk precipitated war? + +7. Give the details of the peace settlement with Mexico. + +8. What is meant by the "joint occupation" of Oregon? + +9. How was the Oregon boundary dispute finally settled? + +10. Compare the American "invasion" of California with the migration +into Texas. + +11. Explain how California became a free state. + +12. Describe the early economic policy of the Mormons. + + +=Research Topics= + +=The Independence of Texas.=--McMaster, _History of the People of the +United States_, Vol. VI, pp. 251-270. Woodrow Wilson, _History of the +American People_, Vol. IV, pp. 102-126. + +=The Annexation of Texas.=--McMaster, Vol. VII. The passages on +annexation are scattered through this volume and it is an exercise in +ingenuity to make a connected story of them. Source materials in Hart, +_American History Told by Contemporaries_, Vol. III, pp. 637-655; Elson, +_History of the United States_, pp. 516-521, 526-527. + +=The War with Mexico.=--Elson, pp. 526-538. + +=The Oregon Boundary Dispute.=--Schafer, _History of the Pacific +Northwest_ (rev. ed.), pp. 88-104; 173-185. + +=The Migration to Oregon.=--Schafer, pp. 105-172. Coman, _Economic +Beginnings of the Far West_, Vol. II, pp. 113-166. + +=The Santa Fe Trail.=--Coman, _Economic Beginnings_, Vol. II, pp. 75-93. + +=The Conquest of California.=--Coman, Vol. II, pp. 297-319. + +=Gold in California.=--McMaster, Vol. VII, pp. 585-614. + +=The Mormon Migration.=--Coman, Vol. II, pp. 167-206. + +=Biographical Studies.=--Fremont, Generals Scott and Taylor, Sam +Houston, and David Crockett. + +=The Romance of Western Exploration.=--J.G. Neihardt, _The Splendid +Wayfaring_. J.G. Neihardt, _The Song of Hugh Glass_. + + + + +PART V. SECTIONAL CONFLICT AND RECONSTRUCTION + + + + +CHAPTER XIII + +THE RISE OF THE INDUSTRIAL SYSTEM + + +If Jefferson could have lived to see the Stars and Stripes planted on +the Pacific Coast, the broad empire of Texas added to the planting +states, and the valley of the Willamette waving with wheat sown by +farmers from New England, he would have been more than fortified in his +faith that the future of America lay in agriculture. Even a stanch old +Federalist like Gouverneur Morris or Josiah Quincy would have mournfully +conceded both the prophecy and the claim. Manifest destiny never seemed +more clearly written in the stars. + +As the farmers from the Northwest and planters from the Southwest poured +in upon the floor of Congress, the party of Jefferson, christened anew +by Jackson, grew stronger year by year. Opponents there were, no doubt, +disgruntled critics and Whigs by conviction; but in 1852 Franklin +Pierce, the Democratic candidate for President, carried every state in +the union except Massachusetts, Vermont, Kentucky, and Tennessee. This +victory, a triumph under ordinary circumstances, was all the more +significant in that Pierce was pitted against a hero of the Mexican War, +General Scott, whom the Whigs, hoping to win by rousing the martial +ardor of the voters, had nominated. On looking at the election returns, +the new President calmly assured the planters that "the general +principle of reduction of duties with a view to revenue may now be +regarded as the settled policy of the country." With equal confidence, +he waved aside those agitators who devoted themselves "to the supposed +interests of the relatively few Africans in the United States." Like a +watchman in the night he called to the country: "All's well." + +The party of Hamilton and Clay lay in the dust. + + +THE INDUSTRIAL REVOLUTION + +As pride often goeth before a fall, so sanguine expectation is sometimes +the symbol of defeat. Jackson destroyed the bank. Polk signed the tariff +bill of 1846 striking an effective blow at the principle of protection +for manufactures. Pierce promised to silence the abolitionists. His +successor was to approve a drastic step in the direction of free trade. +Nevertheless all these things left untouched the springs of power that +were in due time to make America the greatest industrial nation on the +earth; namely, vast national resources, business enterprise, inventive +genius, and the free labor supply of Europe. Unseen by the thoughtless, +unrecorded in the diaries of wiseacres, rarely mentioned in the speeches +of statesmen, there was swiftly rising such a tide in the affairs of +America as Jefferson and Hamilton never dreamed of in their little +philosophies. + +=The Inventors.=--Watt and Boulton experimenting with steam in England, +Whitney combining wood and steel into a cotton gin, Fulton and Fitch +applying the steam engine to navigation, Stevens and Peter Cooper trying +out the "iron horse" on "iron highways," Slater building spinning mills +in Pawtucket, Howe attaching the needle to the flying wheel, Morse +spanning a continent with the telegraph, Cyrus Field linking the markets +of the new world with the old along the bed of the Atlantic, McCormick +breaking the sickle under the reaper--these men and a thousand more were +destroying in a mighty revolution of industry the world of the +stagecoach and the tallow candle which Washington and Franklin had +inherited little changed from the age of Caesar. Whitney was to make +cotton king. Watt and Fulton were to make steel and steam masters of the +world. Agriculture was to fall behind in the race for supremacy. + +=Industry Outstrips Planting.=--The story of invention, that tribute to +the triumph of mind over matter, fascinating as a romance, need not be +treated in detail here. The effects of invention on social and political +life, multitudinous and never-ending, form the very warp and woof of +American progress from the days of Andrew Jackson to the latest hour. +Neither the great civil conflict--the clash of two systems--nor the +problems of the modern age can be approached without an understanding of +the striking phases of industrialism. + +[Illustration: A NEW ENGLAND MILL BUILT IN 1793] + +First and foremost among them was the uprush of mills managed by +captains of industry and manned by labor drawn from farms, cities, and +foreign lands. For every planter who cleared a domain in the Southwest +and gathered his army of bondmen about him, there rose in the North a +magician of steam and steel who collected under his roof an army of free +workers. + +In seven league boots this new giant strode ahead of the Southern giant. +Between 1850 and 1859, to use dollars and cents as the measure of +progress, the value of domestic manufactures including mines and +fisheries rose from $1,019,106,616 to $1,900,000,000, an increase of +eighty-six per cent in ten years. In this same period the total +production of naval stores, rice, sugar, tobacco, and cotton, the +staples of the South, went only from $165,000,000, in round figures, to +$204,000,000. At the halfway point of the century, the capital invested +in industry, commerce, and cities far exceeded the value of all the farm +land between the Atlantic and the Pacific; thus the course of economy +had been reversed in fifty years. Tested by figures of production, King +Cotton had shriveled by 1860 to a petty prince in comparison, for each +year the captains of industry turned out goods worth nearly twenty times +all the bales of cotton picked on Southern plantations. Iron, boots and +shoes, and leather goods pouring from Northern mills surpassed in value +the entire cotton output. + +=The Agrarian West Turns to Industry.=--Nor was this vast enterprise +confined to the old Northeast where, as Madison had sagely remarked, +commerce was early dominant. "Cincinnati," runs an official report in +1854, "appears to be a great central depot for ready-made clothing and +its manufacture for the Western markets may be said to be one of the +great trades of that city." There, wrote another traveler, "I heard the +crack of the cattle driver's whip and the hum of the factory: the West +and the East meeting." Louisville and St. Louis were already famous for +their clothing trades and the manufacture of cotton bagging. Five +hundred of the two thousand woolen mills in the country in 1860 were in +the Western states. Of the output of flour and grist mills, which almost +reached in value the cotton crop of 1850, the Ohio Valley furnished a +rapidly growing share. The old home of Jacksonian democracy, where +Federalists had been almost as scarce as monarchists, turned slowly +backward, as the needle to the pole, toward the principle of protection +for domestic industry, espoused by Hamilton and defended by Clay. + +=The Extension of Canals and Railways.=--As necessary to mechanical +industry as steel and steam power was the great market, spread over a +wide and diversified area and knit together by efficient means of +transportation. This service was supplied to industry by the steamship, +which began its career on the Hudson in 1807; by the canals, of which +the Erie opened in 1825 was the most noteworthy; and by the railways, +which came into practical operation about 1830. + +[Illustration: _From an old print_ + +AN EARLY RAILWAY] + +With sure instinct the Eastern manufacturer reached out for the markets +of the Northwest territory where free farmers were producing annually +staggering crops of corn, wheat, bacon, and wool. The two great canal +systems--the Erie connecting New York City with the waterways of the +Great Lakes and the Pennsylvania chain linking Philadelphia with the +headwaters of the Ohio--gradually turned the tide of trade from New +Orleans to the Eastern seaboard. The railways followed the same paths. +By 1860, New York had rail connections with Chicago and St. Louis, one +of the routes running through the Hudson and Mohawk valleys and along +the Great Lakes, the other through Philadelphia and Pennsylvania and +across the rich wheat fields of Ohio, Indiana, and Illinois. Baltimore, +not to be outdone by her two rivals, reached out over the mountains for +the Western trade and in 1857 had trains running into St. Louis. + +In railway enterprise the South took more interest than in canals, and +the friends of that section came to its aid. To offset the magnet +drawing trade away from the Mississippi Valley, lines were built from +the Gulf to Chicago, the Illinois Central part of the project being a +monument to the zeal and industry of a Democrat, better known in +politics than in business, Stephen A. Douglas. The swift movement of +cotton and tobacco to the North or to seaports was of common concern to +planters and manufacturers. Accordingly lines were flung down along the +Southern coast, linking Richmond, Charleston, and Savannah with the +Northern markets. Other lines struck inland from the coast, giving a +rail outlet to the sea for Raleigh, Columbia, Atlanta, Chattanooga, +Nashville, and Montgomery. Nevertheless, in spite of this enterprise, +the mileage of all the Southern states in 1860 did not equal that of +Ohio, Indiana, and Illinois combined. + +=Banking and Finance.=--Out of commerce and manufactures and the +construction and operation of railways came such an accumulation of +capital in the Northern states as merchants of old never imagined. The +banks of the four industrial states of Massachusetts, Connecticut, New +York, and Pennsylvania in 1860 had funds greater than the banks in all +the other states combined. New York City had become the money market of +America, the center to which industrial companies, railway promoters, +farmers, and planters turned for capital to initiate and carry on their +operations. The banks of Louisiana, South Carolina, Georgia, and +Virginia, it is true, had capital far in excess of the banks of the +Northwest; but still they were relatively small compared with the +financial institutions of the East. + +=The Growth of the Industrial Population.=--A revolution of such +magnitude in industry, transport, and finance, overturning as it did the +agrarian civilization of the old Northwest and reaching out to the very +borders of the country, could not fail to bring in its train +consequences of a striking character. Some were immediate and obvious. +Others require a fullness of time not yet reached to reveal their +complete significance. Outstanding among them was the growth of an +industrial population, detached from the land, concentrated in cities, +and, to use Jefferson's phrase, dependent upon "the caprices and +casualties of trade" for a livelihood. This was a result, as the great +Virginian had foreseen, which flowed inevitably from public and private +efforts to stimulate industry as against agriculture. + +[Illustration: LOWELL, MASSACHUSETTS, IN 1838, AN EARLY INDUSTRIAL +TOWN] + +It was estimated in 1860, on the basis of the census figures, that +mechanical production gave employment to 1,100,000 men and 285,000 +women, making, if the average number of dependents upon them be +reckoned, nearly six million people or about one-sixth of the population +of the country sustained from manufactures. "This," runs the official +record, "was exclusive of the number engaged in the production of many +of the raw materials and of the food for manufacturers; in the +distribution of their products, such as merchants, clerks, draymen, +mariners, the employees of railroads, expresses, and steamboats; of +capitalists, various artistic and professional classes, as well as +carpenters, bricklayers, painters, and the members of other mechanical +trades not classed as manufactures. It is safe to assume, then, that +one-third of the whole population is supported, directly, or indirectly, +by manufacturing industry." Taking, however, the number of persons +directly supported by manufactures, namely about six millions, reveals +the astounding fact that the white laboring population, divorced from +the soil, already exceeded the number of slaves on Southern farms and +plantations. + +_Immigration._--The more carefully the rapid growth of the industrial +population is examined, the more surprising is the fact that such an +immense body of free laborers could be found, particularly when it is +recalled to what desperate straits the colonial leaders were put in +securing immigrants,--slavery, indentured servitude, and kidnapping +being the fruits of their necessities. The answer to the enigma is to be +found partly in European conditions and partly in the cheapness of +transportation after the opening of the era of steam navigation. Shrewd +observers of the course of events had long foreseen that a flood of +cheap labor was bound to come when the way was made easy. Some, among +them Chief Justice Ellsworth, went so far as to prophesy that white +labor would in time be so abundant that slavery would disappear as the +more costly of the two labor systems. The processes of nature were aided +by the policies of government in England and Germany. + +_The Coming of the Irish._--The opposition of the Irish people to the +English government, ever furious and irrepressible, was increased in the +mid forties by an almost total failure of the potato crop, the main +support of the peasants. Catholic in religion, they had been compelled +to support a Protestant church. Tillers of the soil by necessity, they +were forced to pay enormous tributes to absentee landlords in England +whose claim to their estates rested upon the title of conquest and +confiscation. Intensely loyal to their race, the Irish were subjected in +all things to the Parliament at London, in which their small minority of +representatives had little influence save in holding a balance of power +between the two contending English parties. To the constant political +irritation, the potato famine added physical distress beyond +description. In cottages and fields and along the highways the victims +of starvation lay dead by the hundreds, the relief which charity +afforded only bringing misery more sharply to the foreground. Those who +were fortunate enough to secure passage money sought escape to America. +In 1844 the total immigration into the United States was less than +eighty thousand; in 1850 it had risen by leaps and bounds to more than +three hundred thousand. Between 1820 and 1860 the immigrants from the +United Kingdom numbered 2,750,000, of whom more than one-half were +Irish. It has been said with a touch of exaggeration that the American +canals and railways of those days were built by the labor of Irishmen. + +_The German Migration._--To political discontent and economic distress, +such as was responsible for the coming of the Irish, may likewise be +traced the source of the Germanic migration. The potato blight that fell +upon Ireland visited the Rhine Valley and Southern Germany at the same +time with results as pitiful, if less extensive. The calamity inflicted +by nature was followed shortly by another inflicted by the despotic +conduct of German kings and princes. In 1848 there had occurred +throughout Europe a popular uprising in behalf of republics and +democratic government. For a time it rode on a full tide of success. +Kings were overthrown, or compelled to promise constitutional +government, and tyrannical ministers fled from their palaces. Then came +reaction. Those who had championed the popular cause were imprisoned, +shot, or driven out of the land. Men of attainments and distinction, +whose sole offense was opposition to the government of kings and +princes, sought an asylum in America, carrying with them to the land of +their adoption the spirit of liberty and democracy. In 1847 over fifty +thousand Germans came to America, the forerunners of a migration that +increased, almost steadily, for many years. The record of 1860 showed +that in the previous twenty years nearly a million and a half had found +homes in the United States. Far and wide they scattered, from the mills +and shops of the seacoast towns to the uttermost frontiers of Wisconsin +and Minnesota. + +_The Labor of Women and Children._--If the industries, canals, and +railways of the country were largely manned by foreign labor, still +important native sources must not be overlooked; above all, the women +and children of the New England textile districts. Spinning and weaving, +by a tradition that runs far beyond the written records of mankind, +belonged to women. Indeed it was the dexterous housewives, spinsters, +and boys and girls that laid the foundations of the textile industry in +America, foundations upon which the mechanical revolution was built. As +the wheel and loom were taken out of the homes to the factories operated +by water power or the steam engine, the women and, to use Hamilton's +phrase, "the children of tender years," followed as a matter of course. +"The cotton manufacture alone employs six thousand persons in Lowell," +wrote a French observer in 1836; "of this number nearly five thousand +are young women from seventeen to twenty-four years of age, the +daughters of farmers from the different New England states." It was not +until after the middle of the century that foreign lands proved to be +the chief source from which workers were recruited for the factories of +New England. It was then that the daughters of the Puritans, outdone by +the competition of foreign labor, both of men and women, left the +spinning jenny and the loom to other hands. + +=The Rise of Organized Labor.=--The changing conditions of American +life, marked by the spreading mill towns of New England, New York, and +Pennsylvania and the growth of cities like Buffalo, Cincinnati, +Louisville, St. Louis, Detroit, and Chicago in the West, naturally +brought changes, as Jefferson had prophesied, in "manners and morals." A +few mechanics, smiths, carpenters, and masons, widely scattered through +farming regions and rural villages, raise no such problems as tens of +thousands of workers collected in one center in daily intercourse, +learning the power of cooperation and union. + +Even before the coming of steam and machinery, in the "good old days" of +handicrafts, laborers in many trades--printers, shoemakers, carpenters, +for example--had begun to draw together in the towns for the advancement +of their interests in the form of higher wages, shorter days, and +milder laws. The shoemakers of Philadelphia, organized in 1794, +conducted a strike in 1799 and held together until indicted seven years +later for conspiracy. During the twenties and thirties, local labor +unions sprang up in all industrial centers and they led almost +immediately to city federations of the several crafts. + +As the thousands who were dependent upon their daily labor for their +livelihood mounted into the millions and industries spread across the +continent, the local unions of craftsmen grew into national craft +organizations bound together by the newspapers, the telegraph, and the +railways. Before 1860 there were several such national trade unions, +including the plumbers, printers, mule spinners, iron molders, and stone +cutters. All over the North labor leaders arose--men unknown to general +history but forceful and resourceful characters who forged links binding +scattered and individual workers into a common brotherhood. An attempt +was even made in 1834 to federate all the crafts into a permanent +national organization; but it perished within three years through lack +of support. Half a century had to elapse before the American Federation +of Labor was to accomplish this task. + +All the manifestations of the modern labor movement had appeared, in +germ at least, by the time the mid-century was reached: unions, labor +leaders, strikes, a labor press, a labor political program, and a labor +political party. In every great city industrial disputes were a common +occurrence. The papers recorded about four hundred in two years, +1853-54, local affairs but forecasting economic struggles in a larger +field. The labor press seems to have begun with the founding of the +_Mechanics' Free Press_ in Philadelphia in 1828 and the establishment of +the New York _Workingman's Advocate_ shortly afterward. These +semi-political papers were in later years followed by regular trade +papers designed to weld together and advance the interests of particular +crafts. Edited by able leaders, these little sheets with limited +circulation wielded an enormous influence in the ranks of the workers. + +=Labor and Politics.=--As for the political program of labor, the main +planks were clear and specific: the abolition of imprisonment for debt, +manhood suffrage in states where property qualifications still +prevailed, free and universal education, laws protecting the safety and +health of workers in mills and factories, abolition of lotteries, repeal +of laws requiring militia service, and free land in the West. + +Into the labor papers and platforms there sometimes crept a note of +hostility to the masters of industry, a sign of bitterness that excited +little alarm while cheap land in the West was open to the discontented. +The Philadelphia workmen, in issuing a call for a local convention, +invited "all those of our fellow citizens who live by their own labor +and none other." In Newcastle county, Delaware, the association of +working people complained in 1830: "The poor have no laws; the laws are +made by the rich and of course for the rich." Here and there an +extremist went to the length of advocating an equal division of wealth +among all the people--the crudest kind of communism. + +Agitation of this character produced in labor circles profound distrust +of both Whigs and Democrats who talked principally about tariffs and +banks; it resulted in attempts to found independent labor parties. In +Philadelphia, Albany, New York City, and New England, labor candidates +were put up for elections in the early thirties and in a few cases were +victorious at the polls. "The balance of power has at length got into +the hands of the working people, where it properly belongs," +triumphantly exclaimed the _Mechanics' Free Press_ of Philadelphia in +1829. But the triumph was illusory. Dissensions appeared in the labor +ranks. The old party leaders, particularly of Tammany Hall, the +Democratic party organization in New York City, offered concessions to +labor in return for votes. Newspapers unsparingly denounced "trade union +politicians" as "demagogues," "levellers," and "rag, tag, and bobtail"; +and some of them, deeming labor unrest the sour fruit of manhood +suffrage, suggested disfranchisement as a remedy. Under the influence +of concessions and attacks the political fever quickly died away, and +the end of the decade left no remnant of the labor political parties. +Labor leaders turned to a task which seemed more substantial and +practical, that of organizing workingmen into craft unions for the +definite purpose of raising wages and reducing hours. + + +THE INDUSTRIAL REVOLUTION AND NATIONAL POLITICS + +=Southern Plans for Union with the West.=--It was long the design of +Southern statesmen like Calhoun to hold the West and the South together +in one political party. The theory on which they based their hope was +simple. Both sections were agricultural--the producers of raw materials +and the buyers of manufactured goods. The planters were heavy purchasers +of Western bacon, pork, mules, and grain. The Mississippi River and its +tributaries formed the natural channel for the transportation of heavy +produce southward to the plantations and outward to Europe. Therefore, +ran their political reasoning, the interests of the two sections were +one. By standing together in favor of low tariffs, they could buy their +manufactures cheaply in Europe and pay for them in cotton, tobacco, and +grain. The union of the two sections under Jackson's management seemed +perfect. + +=The East Forms Ties with the West.=--Eastern leaders were not blind to +the ambitions of Southern statesmen. On the contrary, they also +recognized the importance of forming strong ties with the agrarian West +and drawing the produce of the Ohio Valley to Philadelphia and New York. +The canals and railways were the physical signs of this economic union, +and the results, commercial and political, were soon evident. By the +middle of the century, Southern economists noted the change, one of +them, De Bow, lamenting that "the great cities of the North have +severally penetrated the interior with artificial lines until they have +taken from the open and untaxed current of the Mississippi the commerce +produced on its borders." To this writer it was an astounding thing to +behold "the number of steamers that now descend the upper Mississippi +River, loaded to the guards with produce, as far as the mouth of the +Illinois River and then turn up that stream with their cargoes to be +shipped to New York _via_ Chicago. The Illinois canal has not only swept +the whole produce along the line of the Illinois River to the East, but +it is drawing the products of the upper Mississippi through the same +channel; thus depriving New Orleans and St. Louis of a rich portion of +their former trade." + +If to any shippers the broad current of the great river sweeping down to +New Orleans offered easier means of physical communication to the sea +than the canals and railways, the difference could be overcome by the +credit which Eastern bankers were able to extend to the grain and +produce buyers, in the first instance, and through them to the farmers +on the soil. The acute Southern observer just quoted, De Bow, admitted +with evident regret, in 1852, that "last autumn, the rich regions of +Ohio, Indiana, and Illinois were flooded with the local bank notes of +the Eastern States, advanced by the New York houses on produce to be +shipped by way of the canals in the spring.... These moneyed facilities +enable the packer, miller, and speculator to hold on to their produce +until the opening of navigation in the spring and they are no longer +obliged, as formerly, to hurry off their shipments during the winter by +the way of New Orleans in order to realize funds by drafts on their +shipments. The banking facilities at the East are doing as much to draw +trade from us as the canals and railways which Eastern capital is +constructing." Thus canals, railways, and financial credit were swiftly +forging bonds of union between the old home of Jacksonian Democracy in +the West and the older home of Federalism in the East. The nationalism +to which Webster paid eloquent tribute became more and more real with +the passing of time. The self-sufficiency of the pioneer was broken down +as he began to watch the produce markets of New York and Philadelphia +where the prices of corn and hogs fixed his earnings for the year. + +=The West and Manufactures.=--In addition to the commercial bonds +between the East and the West there was growing up a common interest in +manufactures. As skilled white labor increased in the Ohio Valley, the +industries springing up in the new cities made Western life more like +that of the industrial East than like that of the planting South. +Moreover, the Western states produced some important raw materials for +American factories, which called for protection against foreign +competition, notably, wool, hemp, and flax. As the South had little or +no foreign competition in cotton and tobacco, the East could not offer +protection for her raw materials in exchange for protection for +industries. With the West, however, it became possible to establish +reciprocity in tariffs; that is, for example, to trade a high rate on +wool for a high rate on textiles or iron. + +=The South Dependent on the North.=--While East and West were drawing +together, the distinctions between North and South were becoming more +marked; the latter, having few industries and producing little save raw +materials, was being forced into the position of a dependent section. As +a result of the protective tariff, Southern planters were compelled to +turn more and more to Northern mills for their cloth, shoes, hats, hoes, +plows, and machinery. Nearly all the goods which they bought in Europe +in exchange for their produce came overseas to Northern ports, whence +transshipments were made by rail and water to Southern points of +distribution. Their rice, cotton, and tobacco, in as far as they were +not carried to Europe in British bottoms, were transported by Northern +masters. In these ways, a large part of the financial operations +connected with the sale of Southern produce and the purchase of goods in +exchange passed into the hands of Northern merchants and bankers who, +naturally, made profits from their transactions. Finally, Southern +planters who wanted to buy more land and more slaves on credit borrowed +heavily in the North where huge accumulations made the rates of interest +lower than the smaller banks of the South could afford. + +=The South Reckons the Cost of Economic Dependence.=--As Southern +dependence upon Northern capital became more and more marked, Southern +leaders began to chafe at what they regarded as restraints laid upon +their enterprise. In a word, they came to look upon the planter as a +tribute-bearer to the manufacturer and financier. "The South," +expostulated De Bow, "stands in the attitude of feeding ... a vast +population of [Northern] merchants, shipowners, capitalists, and others +who, without claims on her progeny, drink up the life blood of her +trade.... Where goes the value of our labor but to those who, taking +advantage of our folly, ship for us, buy for us, sell to us, and, after +turning our own capital to their profitable account, return laden with +our money to enjoy their easily earned opulence at home." + +Southern statisticians, not satisfied with generalities, attempted to +figure out how great was this tribute in dollars and cents. They +estimated that the planters annually lent to Northern merchants the full +value of their exports, a hundred millions or more, "to be used in the +manipulation of foreign imports." They calculated that no less than +forty millions all told had been paid to shipowners in profits. They +reckoned that, if the South were to work up her own cotton, she would +realize from seventy to one hundred millions a year that otherwise went +North. Finally, to cap the climax, they regretted that planters spent +some fifteen millions a year pleasure-seeking in the alluring cities and +summer resorts of the North. + +=Southern Opposition to Northern Policies.=--Proceeding from these +premises, Southern leaders drew the logical conclusion that the entire +program of economic measures demanded in the North was without exception +adverse to Southern interests and, by a similar chain of reasoning, +injurious to the corn and wheat producers of the West. Cheap labor +afforded by free immigration, a protective tariff raising prices of +manufactures for the tiller of the soil, ship subsidies increasing the +tonnage of carrying trade in Northern hands, internal improvements +forging new economic bonds between the East and the West, a national +banking system giving strict national control over the currency as a +safeguard against paper inflation--all these devices were regarded in +the South as contrary to the planting interest. They were constantly +compared with the restrictive measures by which Great Britain more than +half a century before had sought to bind American interests. + +As oppression justified a war for independence once, statesmen argued, +so it can justify it again. "It is curious as it is melancholy and +distressing," came a broad hint from South Carolina, "to see how +striking is the analogy between the colonial vassalage to which the +manufacturing states have reduced the planting states and that which +formerly bound the Anglo-American colonies to the British empire.... +England said to her American colonies: 'You shall not trade with the +rest of the world for such manufactures as are produced in the mother +country.' The manufacturing states say to their Southern colonies: 'You +shall not trade with the rest of the world for such manufactures as we +produce.'" The conclusion was inexorable: either the South must control +the national government and its economic measures, or it must declare, +as America had done four score years before, its political and economic +independence. As Northern mills multiplied, as railways spun their +mighty web over the face of the North, and as accumulated capital rose +into the hundreds of millions, the conviction of the planters and their +statesmen deepened into desperation. + +=Efforts to Start Southern Industries Fail.=--A few of them, seeing the +predominance of the North, made determined efforts to introduce +manufactures into the South. To the leaders who were averse to secession +and nullification this seemed the only remedy for the growing disparity +in the power of the two sections. Societies for the encouragement of +mechanical industries were formed, the investment of capital was sought, +and indeed a few mills were built on Southern soil. The results were +meager. The natural resources, coal and water power, were abundant; but +the enterprise for direction and the skilled labor were wanting. The +stream of European immigration flowed North and West, not South. The +Irish or German laborer, even if he finally made his home in a city, had +before him, while in the North, the alternative of a homestead on +Western land. To him slavery was a strange, if not a repelling, +institution. He did not take to it kindly nor care to fix his home where +it flourished. While slavery lasted, the economy of the South was +inevitably agricultural. While agriculture predominated, leadership with +equal necessity fell to the planting interest. While the planting +interest ruled, political opposition to Northern economy was destined to +grow in strength. + +=The Southern Theory of Sectionalism.=--In the opinion of the statesmen +who frankly represented the planting interest, the industrial system was +its deadly enemy. Their entire philosophy of American politics was +summed up in a single paragraph by McDuffie, a spokesman for South +Carolina: "Owing to the federative character of our government, the +great geographical extent of our territory, and the diversity of the +pursuits of our citizens in different parts of the union, it has so +happened that two great interests have sprung up, standing directly +opposed to each other. One of these consists of those manufactures which +the Northern and Middle states are capable of producing but which, owing +to the high price of labor and the high profits of capital in those +states, cannot hold competition with foreign manufactures without the +aid of bounties, directly or indirectly given, either by the general +government or by the state governments. The other of these interests +consists of the great agricultural staples of the Southern states which +can find a market only in foreign countries and which can be +advantageously sold only in exchange for foreign manufactures which come +in competition with those of the Northern and Middle states.... These +interests then stand diametrically and irreconcilably opposed to each +other. The interest, the pecuniary interest of the Northern +manufacturer, is directly promoted by every increase of the taxes +imposed upon Southern commerce; and it is unnecessary to add that the +interest of the Southern planter is promoted by every diminution of +taxes imposed upon the productions of their industry. If, under these +circumstances, the manufacturers were clothed with the power of imposing +taxes, at their pleasure, upon the foreign imports of the planter, no +doubt would exist in the mind of any man that it would have all the +characteristics of an absolute and unqualified despotism." The economic +soundness of this reasoning, a subject of interesting speculation for +the economist, is of little concern to the historian. The historical +point is that this opinion was widely held in the South and with the +progress of time became the prevailing doctrine of the planting +statesmen. + +Their antagonism was deepened because they also became convinced, on +what grounds it is not necessary to inquire, that the leaders of the +industrial interest thus opposed to planting formed a consolidated +"aristocracy of wealth," bent upon the pursuit and attainment of +political power at Washington. "By the aid of various associated +interests," continued McDuffie, "the manufacturing capitalists have +obtained a complete and permanent control over the legislation of +Congress on this subject [the tariff].... Men confederated together upon +selfish and interested principles, whether in pursuit of the offices or +the bounties of the government, are ever more active and vigilant than +the great majority who act from disinterested and patriotic impulses. +Have we not witnessed it on this floor, sir? Who ever knew the tariff +men to divide on any question affecting their confederated interests?... +The watchword is, stick together, right or wrong upon every question +affecting the common cause. Such, sir, is the concert and vigilance and +such the combinations by which the manufacturing party, acting upon the +interests of some and the prejudices of others, have obtained a decided +and permanent control over public opinion in all the tariff states." +Thus, as the Southern statesman would have it, the North, in matters +affecting national policies, was ruled by a "confederated interest" +which menaced the planting interest. As the former grew in magnitude and +attached to itself the free farmers of the West through channels of +trade and credit, it followed as night the day that in time the planters +would be overshadowed and at length overborne in the struggle of giants. +Whether the theory was sound or not, Southern statesmen believed it and +acted upon it. + + +=References= + +M. Beard, _Short History of the American Labor Movement_. + +E.L. Bogart, _Economic History of the United States_. + +J.R. Commons, _History of Labour in the United States_ (2 vols.). + +E.R. Johnson, _American Railway Transportation_. + +C.D. Wright, _Industrial Evolution of the United States_. + + +=Questions= + +1. What signs pointed to a complete Democratic triumph in 1852? + +2. What is the explanation of the extraordinary industrial progress of +America? + +3. Compare the planting system with the factory system. + +4. In what sections did industry flourish before the Civil War? Why? + +5. Show why transportation is so vital to modern industry and +agriculture. + +6. Explain how it was possible to secure so many people to labor in +American industries. + +7. Trace the steps in the rise of organized labor before 1860. + +8. What political and economic reforms did labor demand? + +9. Why did the East and the South seek closer ties with the West? + +10. Describe the economic forces which were drawing the East and the +West together. + +11. In what way was the South economically dependent upon the North? + +12 State the national policies generally favored in the North and +condemned in the South. + +13. Show how economic conditions in the South were unfavorable to +industry. + +14. Give the Southern explanation of the antagonism between the North +and the South. + + +=Research Topics= + +=The Inventions.=--Assign one to each student. Satisfactory accounts are +to be found in any good encyclopedia, especially the Britannica. + +=River and Lake Commerce.=--Callender, _Economic History of the United +States_, pp. 313-326. + +=Railways and Canals.=--Callender, pp. 326-344; 359-387. Coman, +_Industrial History of the United States_, pp. 216-225. + +=The Growth of Industry, 1815-1840.=--Callender, pp. 459-471. From 1850 +to 1860, Callender, pp. 471-486. + +=Early Labor Conditions.=--Callender, pp. 701-718. + +=Early Immigration.=--Callender, pp. 719-732. + +=Clay's Home Market Theory of the Tariff.=--Callender, pp. 498-503. + +=The New England View of the Tariff.=--Callender, pp. 503-514. + + + + +CHAPTER XIV + +THE PLANTING SYSTEM AND NATIONAL POLITICS + + +James Madison, the father of the federal Constitution, after he had +watched for many days the battle royal in the national convention of +1787, exclaimed that the contest was not between the large and the small +states, but between the commercial North and the planting South. From +the inauguration of Washington to the election of Lincoln the sectional +conflict, discerned by this penetrating thinker, exercised a profound +influence on the course of American politics. It was latent during the +"era of good feeling" when the Jeffersonian Republicans adopted +Federalist policies; it flamed up in the contest between the Democrats +and Whigs. Finally it raged in the angry political quarrel which +culminated in the Civil War. + + +SLAVERY--NORTH AND SOUTH + +=The Decline of Slavery in the North.=--At the time of the adoption of +the Constitution, slavery was lawful in all the Northern states except +Massachusetts. There were almost as many bondmen in New York as in +Georgia. New Jersey had more than Delaware or Tennessee, indeed nearly +as many as both combined. All told, however, there were only about forty +thousand in the North as against nearly seven hundred thousand in the +South. Moreover, most of the Northern slaves were domestic servants, not +laborers necessary to keep mills going or fields under cultivation. + +There was, in the North, a steadily growing moral sentiment against the +system. Massachusetts abandoned it in 1780. In the same year, +Pennsylvania provided for gradual emancipation. New Hampshire, where +there had been only a handful, Connecticut with a few thousand +domestics, and New Jersey early followed these examples. New York, in +1799, declared that all children born of slaves after July 4 of that +year should be free, though held for a term as apprentices; and in 1827 +it swept away the last vestiges of slavery. So with the passing of the +generation that had framed the Constitution, chattel servitude +disappeared in the commercial states, leaving behind only such +discriminations as disfranchisement or high property qualifications on +colored voters. + +=The Growth of Northern Sentiment against Slavery.=--In both sections of +the country there early existed, among those more or less +philosophically inclined, a strong opposition to slavery on moral as +well as economic grounds. In the constitutional convention of 1787, +Gouverneur Morris had vigorously condemned it and proposed that the +whole country should bear the cost of abolishing it. About the same time +a society for promoting the abolition of slavery, under the presidency +of Benjamin Franklin, laid before Congress a petition that serious +attention be given to the emancipation of "those unhappy men who alone +in this land of freedom are degraded into perpetual bondage." When +Congress, acting on the recommendations of President Jefferson, provided +for the abolition of the foreign slave trade on January 1, 1808, several +Northern members joined with Southern members in condemning the system +as well as the trade. Later, colonization societies were formed to +encourage the emancipation of slaves and their return to Africa. James +Madison was president and Henry Clay vice president of such an +organization. + +The anti-slavery sentiment of which these were the signs was +nevertheless confined to narrow circles and bore no trace of bitterness. + +"We consider slavery your calamity, not your crime," wrote a +distinguished Boston clergyman to his Southern brethren, "and we will +share with you the burden of putting an end to it. We will consent that +the public lands shall be appropriated to this object.... I deprecate +everything which sows discord and exasperating sectional animosities." + +=Uncompromising Abolition.=--In a little while the spirit of generosity +was gone. Just as Jacksonian Democracy rose to power there appeared a +new kind of anti-slavery doctrine--the dogmatism of the abolition +agitator. For mild speculation on the evils of the system was +substituted an imperious and belligerent demand for instant +emancipation. If a date must be fixed for its appearance, the year 1831 +may be taken when William Lloyd Garrison founded in Boston his +anti-slavery paper, _The Liberator_. With singleness of purpose and +utter contempt for all opposing opinions and arguments, he pursued his +course of passionate denunciation. He apologized for having ever +"assented to the popular but pernicious doctrine of gradual abolition." +He chose for his motto: "Immediate and unconditional emancipation!" He +promised his readers that he would be "harsh as truth and uncompromising +as justice"; that he would not "think or speak or write with +moderation." Then he flung out his defiant call: "I am in earnest--I +will not equivocate--I will not excuse--I will not retreat a single +inch--and I will be heard.... + + 'Such is the vow I take, so help me God.'" + +Though Garrison complained that "the apathy of the people is enough to +make every statue leap from its pedestal," he soon learned how alive the +masses were to the meaning of his propaganda. Abolition orators were +stoned in the street and hissed from the platform. Their meeting places +were often attacked and sometimes burned to the ground. Garrison himself +was assaulted in the streets of Boston, finding refuge from the angry +mob behind prison bars. Lovejoy, a publisher in Alton, Illinois, for his +willingness to give abolition a fair hearing, was brutally murdered; his +printing press was broken to pieces as a warning to all those who +disturbed the nation's peace of mind. The South, doubly frightened by a +slave revolt in 1831 which ended in the murder of a number of men, +women, and children, closed all discussion of slavery in that section. +"Now," exclaimed Calhoun, "it is a question which admits of neither +concession nor compromise." + +As the opposition hardened, the anti-slavery agitation gathered in force +and intensity. Whittier blew his blast from the New England hills: + + "No slave-hunt in our borders--no pirate on our strand; + No fetters in the Bay State--no slave upon our land." + +Lowell, looking upon the espousal of a great cause as the noblest aim of +his art, ridiculed and excoriated bondage in the South. Those +abolitionists, not gifted as speakers or writers, signed petitions +against slavery and poured them in upon Congress. The flood of them was +so continuous that the House of Representatives, forgetting its +traditions, adopted in 1836 a "gag rule" which prevented the reading of +appeals and consigned them to the waste basket. Not until the Whigs were +in power nearly ten years later was John Quincy Adams able, after a +relentless campaign, to carry a motion rescinding the rule. + +How deep was the impression made upon the country by this agitation for +immediate and unconditional emancipation cannot be measured. If the +popular vote for those candidates who opposed not slavery, but its +extension to the territories, be taken as a standard, it was slight +indeed. In 1844, the Free Soil candidate, Birney, polled 62,000 votes +out of over a million and a half; the Free Soil vote of the next +campaign went beyond a quarter of a million, but the increase was due to +the strength of the leader, Martin Van Buren; four years afterward it +receded to 156,000, affording all the outward signs for the belief that +the pleas of the abolitionist found no widespread response among the +people. Yet the agitation undoubtedly ran deeper than the ballot box. +Young statesmen of the North, in whose hands the destiny of frightful +years was to lie, found their indifference to slavery broken and their +consciences stirred by the unending appeal and the tireless reiteration. +Charles Sumner afterward boasted that he read the _Liberator_ two years +before Wendell Phillips, the young Boston lawyer who cast aside his +profession to take up the dangerous cause. + +=Early Southern Opposition to Slavery.=--In the South, the sentiment +against slavery was strong; it led some to believe that it would also +come to an end there in due time. Washington disliked it and directed in +his will that his own slaves should be set free after the death of his +wife. Jefferson, looking into the future, condemned the system by which +he also lived, saying: "Can the liberties of a nation be thought secure +when we have removed their only firm basis, a conviction in the minds of +the people that their liberties are the gift of God? Are they not to be +violated but with His wrath? Indeed I tremble for my country when I +reflect that God is just; that His justice cannot sleep forever." Nor +did Southern men confine their sentiments to expressions of academic +opinion. They accepted in 1787 the Ordinance which excluded slavery from +the Northwest territory forever and also the Missouri Compromise, which +shut it out of a vast section of the Louisiana territory. + +=The Revolution in the Slave System.=--Among the representatives of +South Carolina and Georgia, however, the anti-slavery views of +Washington and Jefferson were by no means approved; and the drift of +Southern economy was decidedly in favor of extending and perpetuating, +rather than abolishing, the system of chattel servitude. The invention +of the cotton gin and textile machinery created a market for cotton +which the planters, with all their skill and energy, could hardly +supply. Almost every available acre was brought under cotton culture as +the small farmers were driven steadily from the seaboard into the +uplands or to the Northwest. + +The demand for slaves to till the swiftly expanding fields was enormous. +The number of bondmen rose from 700,000 in Washington's day to more than +three millions in 1850. At the same time slavery itself was transformed. +Instead of the homestead where the same family of masters kept the same +families of slaves from generation to generation, came the plantation +system of the Far South and Southwest where masters were ever moving and +ever extending their holdings of lands and slaves. This in turn reacted +on the older South where the raising of slaves for the market became a +regular and highly profitable business. + +[Illustration: _From an old print_ + +JOHN C. CALHOUN] + +=Slavery Defended as a Positive Good.=--As the abolition agitation +increased and the planting system expanded, apologies for slavery became +fainter and fainter in the South. Then apologies were superseded by +claims that slavery was a beneficial scheme of labor control. Calhoun, +in a famous speech in the Senate in 1837, sounded the new note by +declaring slavery "instead of an evil, a good--a positive good." His +reasoning was as follows: in every civilized society one portion of the +community must live on the labor of another; learning, science, and the +arts are built upon leisure; the African slave, kindly treated by his +master and mistress and looked after in his old age, is better off than +the free laborers of Europe; and under the slave system conflicts +between capital and labor are avoided. The advantages of slavery in this +respect, he concluded, "will become more and more manifest, if left +undisturbed by interference from without, as the country advances in +wealth and numbers." + +=Slave Owners Dominate Politics.=--The new doctrine of Calhoun was +eagerly seized by the planters as they came more and more to overshadow +the small farmers of the South and as they beheld the menace of +abolition growing upon the horizon. It formed, as they viewed matters, a +moral defense for their labor system--sound, logical, invincible. It +warranted them in drawing together for the protection of an institution +so necessary, so inevitable, so beneficent. + +Though in 1850 the slave owners were only about three hundred and fifty +thousand in a national population of nearly twenty million whites, they +had an influence all out of proportion to their numbers. They were knit +together by the bonds of a common interest. They had leisure and wealth. +They could travel and attend conferences and conventions. Throughout the +South and largely in the North, they had the press, the schools, and the +pulpits on their side. They formed, as it were, a mighty union for the +protection and advancement of their common cause. Aided by those +mechanics and farmers of the North who stuck by Jacksonian Democracy +through thick and thin, the planters became a power in the federal +government. "We nominate Presidents," exultantly boasted a Richmond +newspaper; "the North elects them." + +This jubilant Southern claim was conceded by William H. Seward, a +Republican Senator from New York, in a speech describing the power of +slavery in the national government. "A party," he said, "is in one sense +a joint stock association, in which those who contribute most direct the +action and management of the concern.... The slaveholders, contributing +in an overwhelming proportion to the strength of the Democratic party, +necessarily dictate and prescribe its policy." He went on: "The +slaveholding class has become the governing power in each of the +slaveholding states and it practically chooses thirty of the sixty-two +members of the Senate, ninety of the two hundred and thirty-three +members of the House of Representatives, and one hundred and five of the +two hundred and ninety-five electors of President and Vice-President of +the United States." Then he considered the slave power in the Supreme +Court. "That tribunal," he exclaimed, "consists of a chief justice and +eight associate justices. Of these, five were called from slave states +and four from free states. The opinions and bias of each of them were +carefully considered by the President and Senate when he was appointed. +Not one of them was found wanting in soundness of politics, according to +the slaveholder's exposition of the Constitution." Such was the Northern +view of the planting interest that, from the arena of national politics, +challenged the whole country in 1860. + +[Illustration: DISTRIBUTION OF SLAVES IN THE SOUTHERN STATES] + + +SLAVERY IN NATIONAL POLITICS + +=National Aspects of Slavery.=--It may be asked why it was that slavery, +founded originally on state law and subject to state government, was +drawn into the current of national affairs. The answer is simple. There +were, in the first place, constitutional reasons. The Congress of the +United States had to make all needful rules for the government of the +territories, the District of Columbia, the forts and other property +under national authority; so it was compelled to determine whether +slavery should exist in the places subject to its jurisdiction. Upon +Congress was also conferred the power of admitting new states; whenever +a territory asked for admission, the issue could be raised as to whether +slavery should be sanctioned or excluded. Under the Constitution, +provision was made for the return of runaway slaves; Congress had the +power to enforce this clause by appropriate legislation. Since the +control of the post office was vested in the federal government, it had +to face the problem raised by the transmission of abolition literature +through the mails. Finally citizens had the right of petition; it +inheres in all free government and it is expressly guaranteed by the +first amendment to the Constitution. It was therefore legal for +abolitionists to present to Congress their petitions, even if they asked +for something which it had no right to grant. It was thus impossible, +constitutionally, to draw a cordon around the slavery issue and confine +the discussion of it to state politics. + +There were, in the second place, economic reasons why slavery was +inevitably drawn into the national sphere. It was the basis of the +planting system which had direct commercial relations with the North and +European countries; it was affected by federal laws respecting tariffs, +bounties, ship subsidies, banking, and kindred matters. The planters of +the South, almost without exception, looked upon the protective tariff +as a tribute laid upon them for the benefit of Northern industries. As +heavy borrowers of money in the North, they were generally in favor of +"easy money," if not paper currency, as an aid in the repayment of their +debts. This threw most of them into opposition to the Whig program for a +United States Bank. All financial aids to American shipping they stoutly +resisted, preferring to rely upon the cheaper service rendered by +English shippers. Internal improvements, those substantial ties that +were binding the West to the East and turning the traffic from New +Orleans to Philadelphia and New York, they viewed with alarm. Free +homesteads from the public lands, which tended to overbalance the South +by building free states, became to them a measure dangerous to their +interests. Thus national economic policies, which could not by any twist +or turn be confined to state control, drew the slave system and its +defenders into the political conflict that centered at Washington. + +=Slavery and the Territories--the Missouri Compromise (1820).=--Though +men continually talked about "taking slavery out of politics," it could +not be done. By 1818 slavery had become so entrenched and the +anti-slavery sentiment so strong, that Missouri's quest for admission +brought both houses of Congress into a deadlock that was broken only by +compromise. The South, having half the Senators, could prevent the +admission of Missouri stripped of slavery; and the North, powerful in +the House of Representatives, could keep Missouri with slavery out of +the union indefinitely. An adjustment of pretensions was the last +resort. Maine, separated from the parent state of Massachusetts, was +brought into the union with freedom and Missouri with bondage. At the +same time it was agreed that the remainder of the vast Louisiana +territory north of the parallel of 36 o 30' should be, like the old +Northwest, forever free; while the southern portion was left to slavery. +In reality this was an immense gain for liberty. The area dedicated to +free farmers was many times greater than that left to the planters. The +principle was once more asserted that Congress had full power to prevent +slavery in the territories. + +[Illustration: THE MISSOURI COMPROMISE] + +=The Territorial Question Reopened by the Wilmot Proviso.=--To the +Southern leaders, the annexation of Texas and the conquest of Mexico +meant renewed security to the planting interest against the increasing +wealth and population of the North. Texas, it was said, could be divided +into four slave states. The new territories secured by the treaty of +peace with Mexico contained the promise of at least three more. Thus, as +each new free soil state knocked for admission into the union, the +South could demand as the price of its consent a new slave state. No +wonder Southern statesmen saw, in the annexation of Texas and the +conquest of Mexico, slavery and King Cotton triumphant--secure for all +time against adverse legislation. Northern leaders were equally +convinced that the Southern prophecy was true. Abolitionists and +moderate opponents of slavery alike were in despair. Texas, they +lamented, would fasten slavery upon the country forevermore. "No living +man," cried one, "will see the end of slavery in the United States!" + +It so happened, however, that the events which, it was thought, would +secure slavery let loose a storm against it. A sign appeared first on +August 6, 1846, only a few months after war was declared on Mexico. On +that day, David Wilmot, a Democrat from Pennsylvania, introduced into +the House of Representatives a resolution to the effect that, as an +express and fundamental condition to the acquisition of any territory +from the republic of Mexico, slavery should be forever excluded from +every part of it. "The Wilmot Proviso," as the resolution was popularly +called, though defeated on that occasion, was a challenge to the South. + +The South answered the challenge. Speaking in the House of +Representatives, Robert Toombs of Georgia boldly declared: "In the +presence of the living God, if by your legislation you seek to drive us +from the territories of California and New Mexico ... I am for +disunion." South Carolina announced that the day for talk had passed and +the time had come to join her sister states "in resisting the +application of the Wilmot Proviso at any and all hazards." A conference, +assembled at Jackson, Mississippi, in the autumn of 1849, called a +general convention of Southern states to meet at Nashville the following +summer. The avowed purpose was to arrest "the course of aggression" and, +if that was not possible, to provide "in the last resort for their +separate welfare by the formation of a compact and union that will +afford protection to their liberties and rights." States that had +spurned South Carolina's plea for nullification in 1832 responded to +this new appeal with alacrity--an augury of the secession to come. + +[Illustration: _From an old print._ + +HENRY CLAY] + +=The Great Debate of 1850.=--The temper of the country was white hot +when Congress convened in December, 1849. It was a memorable session, +memorable for the great men who took part in the debates and memorable +for the grand Compromise of 1850 which it produced. In the Senate sat +for the last time three heroic figures: Webster from the North, Calhoun +from the South, and Clay from a border state. For nearly forty years +these three had been leaders of men. All had grown old and gray in +service. Calhoun was already broken in health and in a few months was to +be borne from the political arena forever. Clay and Webster had but two +more years in their allotted span. + +Experience, learning, statecraft--all these things they now marshaled in +a mighty effort to solve the slavery problem. On January 29, 1850, Clay +offered to the Senate a compromise granting concessions to both sides; +and a few days later, in a powerful oration, he made a passionate appeal +for a union of hearts through mutual sacrifices. Calhoun relentlessly +demanded the full measure of justice for the South: equal rights in the +territories bought by common blood; the return of runaway slaves as +required by the Constitution; the suppression of the abolitionists; and +the restoration of the balance of power between the North and the South. +Webster, in his notable "Seventh of March speech," condemned the Wilmot +Proviso, advocated a strict enforcement of the fugitive slave law, +denounced the abolitionists, and made a final plea for the Constitution, +union, and liberty. This was the address which called forth from +Whittier the poem, "Ichabod," deploring the fall of the mighty one whom +he thought lost to all sense of faith and honor. + +=The Terms of the Compromise of 1850.=--When the debates were closed, +the results were totaled in a series of compromise measures, all of +which were signed in September, 1850, by the new President, Millard +Fillmore, who had taken office two months before on the death of Zachary +Taylor. By these acts the boundaries of Texas were adjusted and the +territory of New Mexico created, subject to the provision that all or +any part of it might be admitted to the union "with or without slavery +as their constitution may provide at the time of their admission." The +Territory of Utah was similarly organized with the same conditions as to +slavery, thus repudiating the Wilmot Proviso without guaranteeing +slavery to the planters. California was admitted as a free state under a +constitution in which the people of the territory had themselves +prohibited slavery. + +The slave trade was abolished in the District of Columbia, but slavery +itself existed as before at the capital of the nation. This concession +to anti-slavery sentiment was more than offset by a fugitive slave law, +drastic in spirit and in letter. It placed the enforcement of its terms +in the hands of federal officers appointed from Washington and so +removed it from the control of authorities locally elected. It provided +that masters or their agents, on filing claims in due form, might +summarily remove their escaped slaves without affording their "alleged +fugitives" the right of trial by jury, the right to witness, the right +to offer any testimony in evidence. Finally, to "put teeth" into the +act, heavy penalties were prescribed for all who obstructed or assisted +in obstructing the enforcement of the law. Such was the Great Compromise +of 1850. + +[Illustration: AN OLD CARTOON REPRESENTING WEBSTER "STEALING CLAY'S +THUNDER"] + +=The Pro-slavery Triumph in the Election of 1852.=--The results of the +election of 1852 seemed to show conclusively that the nation was weary +of slavery agitation and wanted peace. Both parties, Whigs and +Democrats, endorsed the fugitive slave law and approved the Great +Compromise. The Democrats, with Franklin Pierce as their leader, swept +the country against the war hero, General Winfield Scott, on whom the +Whigs had staked their hopes. Even Webster, broken with grief at his +failure to receive the nomination, advised his friends to vote for +Pierce and turned away from politics to meditate upon approaching death. +The verdict of the voters would seem to indicate that for the time +everybody, save a handful of disgruntled agitators, looked upon Clay's +settlement as the last word. "The people, especially the business men of +the country," says Elson, "were utterly weary of the agitation and they +gave their suffrages to the party that promised them rest." The Free +Soil party, condemning slavery as "a sin against God and a crime against +man," and advocating freedom for the territories, failed to carry a +single state. In fact it polled fewer votes than it had four years +earlier--156,000 as against nearly 3,000,000, the combined vote of the +Whigs and Democrats. It is not surprising, therefore, that President +Pierce, surrounded in his cabinet by strong Southern sympathizers, could +promise to put an end to slavery agitation and to crush the abolition +movement in the bud. + +=Anti-slavery Agitation Continued.=--The promise was more difficult to +fulfill than to utter. In fact, the vigorous execution of one measure +included in the Compromise--the fugitive slave law--only made matters +worse. Designed as security for the planters, it proved a powerful +instrument in their undoing. Slavery five hundred miles away on a +Louisiana plantation was so remote from the North that only the +strongest imagination could maintain a constant rage against it. "Slave +catching," "man hunting" by federal officers on the streets of +Philadelphia, New York, Boston, Chicago, or Milwaukee and in the hamlets +and villages of the wide-stretching farm lands of the North was another +matter. It brought the most odious aspects of slavery home to thousands +of men and women who would otherwise have been indifferent to the +system. Law-abiding business men, mechanics, farmers, and women, when +they saw peaceful negroes, who had resided in their neighborhoods +perhaps for years, torn away by federal officers and carried back to +bondage, were transformed into enemies of the law. They helped slaves to +escape; they snatched them away from officers who had captured them; +they broke open jails and carried fugitives off to Canada. + +Assistance to runaway slaves, always more or less common in the North, +was by this time organized into a system. Regular routes, known as +"underground railways," were laid out across the free states into +Canada, and trusted friends of freedom maintained "underground stations" +where fugitives were concealed in the daytime between their long night +journeys. Funds were raised and secret agents sent into the South to +help negroes to flee. One negro woman, Harriet Tubman, "the Moses of her +people," with headquarters at Philadelphia, is accredited with nineteen +invasions into slave territory and the emancipation of three hundred +negroes. Those who worked at this business were in constant peril. One +underground operator, Calvin Fairbank, spent nearly twenty years in +prison for aiding fugitives from justice. Yet perils and prisons did not +stay those determined men and women who, in obedience to their +consciences, set themselves to this lawless work. + +[Illustration: HARRIET BEECHER STOWE] + +From thrilling stories of adventure along the underground railways came +some of the scenes and themes of the novel by Harriet Beecher Stowe, +"Uncle Tom's Cabin," published two years after the Compromise of 1850. +Her stirring tale set forth the worst features of slavery in vivid word +pictures that caught and held the attention of millions of readers. +Though the book was unfair to the South and was denounced as a hideous +distortion of the truth, it was quickly dramatized and played in every +city and town throughout the North. Topsy, Little Eva, Uncle Tom, the +fleeing slave, Eliza Harris, and the cruel slave driver, Simon Legree, +with his baying blood hounds, became living specters in many a home that +sought to bar the door to the "unpleasant and irritating business of +slavery agitation." + + +THE DRIFT OF EVENTS TOWARD THE IRREPRESSIBLE CONFLICT + +=Repeal of the Missouri Compromise.=--To practical men, after all, the +"rub-a-dub" agitation of a few abolitionists, an occasional riot over +fugitive slaves, and the vogue of a popular novel seemed of slight or +transient importance. They could point with satisfaction to the election +returns of 1852; but their very security was founded upon shifting +sands. The magnificent triumph of the pro-slavery Democrats in 1852 +brought a turn in affairs that destroyed the foundations under their +feet. Emboldened by their own strength and the weakness of their +opponents, they now dared to repeal the Missouri Compromise. The leader +in this fateful enterprise was Stephen A. Douglas, Senator from +Illinois, and the occasion for the deed was the demand for the +organization of territorial government in the regions west of Iowa and +Missouri. + +Douglas, like Clay and Webster before him, was consumed by a strong +passion for the presidency, and, to reach his goal, it was necessary to +win the support of the South. This he undoubtedly sought to do when he +introduced on January 4, 1854, a bill organizing the Nebraska territory +on the principle of the Compromise of 1850; namely, that the people in +the territory might themselves decide whether they would have slavery or +not. Unwittingly the avalanche was started. + +After a stormy debate, in which important amendments were forced on +Douglas, the Kansas-Nebraska Bill became a law on May 30, 1854. The +measure created two territories, Kansas and Nebraska, and provided that +they, or territories organized out of them, could come into the union as +states "with or without slavery as their constitutions may prescribe at +the time of their admission." Not content with this, the law went on to +declare the Missouri Compromise null and void as being inconsistent with +the principle of non-intervention by Congress with slavery in the states +and territories. Thus by a single blow the very heart of the continent, +dedicated to freedom by solemn agreement, was thrown open to slavery. A +desperate struggle between slave owners and the advocates of freedom was +the outcome in Kansas. + +If Douglas fancied that the North would receive the overthrow of the +Missouri Compromise in the same temper that it greeted Clay's +settlement, he was rapidly disillusioned. A blast of rage, terrific in +its fury, swept from Maine to Iowa. Staid old Boston hanged him in +effigy with an inscription--"Stephen A. Douglas, author of the infamous +Nebraska bill: the Benedict Arnold of 1854." City after city burned him +in effigy until, as he himself said, he could travel from the Atlantic +coast to Chicago in the light of the fires. Thousands of Whigs and +Free-soil Democrats deserted their parties which had sanctioned or at +least tolerated the Kansas-Nebraska Bill, declaring that the startling +measure showed an evident resolve on the part of the planters to rule +the whole country. A gage of defiance was thrown down to the +abolitionists. An issue was set even for the moderate and timid who had +been unmoved by the agitation over slavery in the Far South. That issue +was whether slavery was to be confined within its existing boundaries or +be allowed to spread without interference, thereby placing the free +states in the minority and surrendering the federal government wholly to +the slave power. + +=The Rise of the Republican Party.=--Events of terrible significance, +swiftly following, drove the country like a ship before a gale straight +into civil war. The Kansas-Nebraska Bill rent the old parties asunder +and called into being the Republican party. While that bill was pending +in Congress, many Northern Whigs and Democrats had come to the +conclusion that a new party dedicated to freedom in the territories must +follow the repeal of the Missouri Compromise. Several places claim to be +the original home of the Republican party; but historians generally +yield it to Wisconsin. At Ripon in that state, a mass meeting of Whigs +and Democrats assembled in February, 1854, and resolved to form a new +party if the Kansas-Nebraska Bill should pass. At a second meeting a +fusion committee representing Whigs, Free Soilers, and Democrats was +formed and the name Republican--the name of Jefferson's old party--was +selected. All over the country similar meetings were held and political +committees were organized. + +When the presidential campaign of 1856 began the Republicans entered the +contest. After a preliminary conference in Pittsburgh in February, they +held a convention in Philadelphia at which was drawn up a platform +opposing the extension of slavery to the territories. John C. Fremont, +the distinguished explorer, was named for the presidency. The results +of the election were astounding as compared with the Free-soil failure +of the preceding election. Prominent men like Longfellow, Washington +Irving, William Cullen Bryant, Ralph Waldo Emerson, and George William +Curtis went over to the new party and 1,341,264 votes were rolled up for +"free labor, free speech, free men, free Kansas, and Fremont." +Nevertheless the victory of the Democrats was decisive. Their candidate, +James Buchanan of Pennsylvania, was elected by a majority of 174 to 114 +electoral votes. + +[Illustration: SLAVE AND FREE SOIL ON EVE OF CIVIL WAR] + +=The Dred Scott Decision (1857).=--In his inaugural, Buchanan vaguely +hinted that in a forthcoming decision the Supreme Court would settle one +of the vital questions of the day. This was a reference to the Dred +Scott case then pending. Scott was a slave who had been taken by his +master into the upper Louisiana territory, where freedom had been +established by the Missouri Compromise, and then carried back into his +old state of Missouri. He brought suit for his liberty on the ground +that his residence in the free territory made him free. This raised the +question whether the law of Congress prohibiting slavery north of 36 o +30' was authorized by the federal Constitution or not. The Court might +have avoided answering it by saying that even though Scott was free in +the territory, he became a slave again in Missouri by virtue of the law +of that state. The Court, however, faced the issue squarely. It held +that Scott had not been free anywhere and that, besides, the Missouri +Compromise violated the Constitution and was null and void. + +The decision was a triumph for the South. It meant that Congress after +all had no power to abolish slavery in the territories. Under the decree +of the highest court in the land, that could be done only by an +amendment to the Constitution which required a two-thirds vote in +Congress and the approval of three-fourths of the states. Such an +amendment was obviously impossible--the Southern states were too +numerous; but the Republicans were not daunted. "We know," said Lincoln, +"the Court that made it has often overruled its own decisions and we +shall do what we can to have it overrule this." Legislatures of Northern +states passed resolutions condemning the decision and the Republican +platform of 1860 characterized the dogma that the Constitution carried +slavery into the territories as "a dangerous political heresy at +variance with the explicit provisions of that instrument itself ... with +legislative and judicial precedent ... revolutionary in tendency and +subversive of the peace and harmony of the country." + +=The Panic of 1857.=--In the midst of the acrimonious dispute over the +Dred Scott decision, came one of the worst business panics which ever +afflicted the country. In the spring and summer of 1857, fourteen +railroad corporations, including the Erie, Michigan Central, and the +Illinois Central, failed to meet their obligations; banks and insurance +companies, some of them the largest and strongest institutions in the +North, closed their doors; stocks and bonds came down in a crash on the +markets; manufacturing was paralyzed; tens of thousands of working +people were thrown out of employment; "hunger meetings" of idle men were +held in the cities and banners bearing the inscription, "We want +bread," were flung out. In New York, working men threatened to invade +the Council Chamber to demand "work or bread," and the frightened mayor +called for the police and soldiers. For this distressing state of +affairs many remedies were offered; none with more zeal and persistence +than the proposal for a higher tariff to take the place of the law of +March, 1857, a Democratic measure making drastic reductions in the rates +of duty. In the manufacturing districts of the North, the panic was +ascribed to the "Democratic assault on business." So an old issue was +again vigorously advanced, preparatory to the next presidential +campaign. + +=The Lincoln-Douglas Debates.=--The following year the interest of the +whole country was drawn to a series of debates held in Illinois by +Lincoln and Douglas, both candidates for the United States Senate. In +the course of his campaign Lincoln had uttered his trenchant saying that +"a house divided against itself cannot stand. I believe this government +cannot endure permanently half slave and half free." At the same time he +had accused Douglas, Buchanan, and the Supreme Court of acting in +concert to make slavery national. This daring statement arrested the +attention of Douglas, who was making his campaign on the doctrine of +"squatter sovereignty;" that is, the right of the people of each +territory "to vote slavery up or down." After a few long-distance shots +at each other, the candidates agreed to meet face to face and discuss +the issues of the day. Never had such crowds been seen at political +meetings in Illinois. Farmers deserted their plows, smiths their forges, +and housewives their baking to hear "Honest Abe" and "the Little Giant." + +The results of the series of debates were momentous. Lincoln clearly +defined his position. The South, he admitted, was entitled under the +Constitution to a fair, fugitive slave law. He hoped that there might be +no new slave states; but he did not see how Congress could exclude the +people of a territory from admission as a state if they saw fit to adopt +a constitution legalizing the ownership of slaves. He favored the +gradual abolition of slavery in the District of Columbia and the total +exclusion of it from the territories of the United States by act of +Congress. + +Moreover, he drove Douglas into a hole by asking how he squared +"squatter sovereignty" with the Dred Scott decision; how, in other +words, the people of a territory could abolish slavery when the Court +had declared that Congress, the superior power, could not do it under +the Constitution? To this baffling question Douglas lamely replied that +the inhabitants of a territory, by "unfriendly legislation," might make +property in slaves insecure and thus destroy the institution. This +answer to Lincoln's query alienated many Southern Democrats who believed +that the Dred Scott decision settled the question of slavery in the +territories for all time. Douglas won the election to the Senate; but +Lincoln, lifted into national fame by the debates, beat him in the +campaign for President two years later. + +=John Brown's Raid.=--To the abolitionists the line of argument pursued +by Lincoln, including his proposal to leave slavery untouched in the +states where it existed, was wholly unsatisfactory. One of them, a grim +and resolute man, inflamed by a hatred for slavery in itself, turned +from agitation to violence. "These men are all talk; what is needed is +action--action!" So spoke John Brown of New York. During the sanguinary +struggle in Kansas he hurried to the frontier, gun and dagger in hand, +to help drive slave owners from the free soil of the West. There he +committed deeds of such daring and cruelty that he was outlawed and a +price put upon his head. Still he kept on the path of "action." Aided by +funds from Northern friends, he gathered a small band of his followers +around him, saying to them: "If God be for us, who can be against us?" +He went into Virginia in the autumn of 1859, hoping, as he explained, +"to effect a mighty conquest even though it be like the last victory of +Samson." He seized the government armory at Harper's Ferry, declared +free the slaves whom he found, and called upon them to take up arms in +defense of their liberty. His was a hope as forlorn as it was desperate. +Armed forces came down upon him and, after a hard battle, captured him. +Tried for treason, Brown was condemned to death. The governor of +Virginia turned a deaf ear to pleas for clemency based on the ground +that the prisoner was simply a lunatic. "This is a beautiful country," +said the stern old Brown glancing upward to the eternal hills on his way +to the gallows, as calmly as if he were returning home from a long +journey. "So perish all such enemies of Virginia. All such enemies of +the Union. All such foes of the human race," solemnly announced the +executioner as he fulfilled the judgment of the law. + +The raid and its grim ending deeply moved the country. Abolitionists +looked upon Brown as a martyr and tolled funeral bells on the day of his +execution. Longfellow wrote in his diary: "This will be a great day in +our history; the date of a new revolution as much needed as the old +one." Jefferson Davis saw in the affair "the invasion of a state by a +murderous gang of abolitionists bent on inciting slaves to murder +helpless women and children"--a crime for which the leader had met a +felon's death. Lincoln spoke of the raid as absurd, the deed of an +enthusiast who had brooded over the oppression of a people until he +fancied himself commissioned by heaven to liberate them--an attempt +which ended in "little else than his own execution." To Republican +leaders as a whole, the event was very embarrassing. They were taunted +by the Democrats with responsibility for the deed. Douglas declared his +"firm and deliberate conviction that the Harper's Ferry crime was the +natural, logical, inevitable result of the doctrines and teachings of +the Republican party." So persistent were such attacks that the +Republicans felt called upon in 1860 to denounce Brown's raid "as among +the gravest of crimes." + +=The Democrats Divided.=--When the Democratic convention met at +Charleston in the spring of 1860, a few months after Brown's execution, +it soon became clear that there was danger ahead. Between the extreme +slavery advocates of the Far South and the so-called pro-slavery +Democrats of the Douglas type, there was a chasm which no appeals to +party loyalty could bridge. As the spokesman of the West, Douglas knew +that, while the North was not abolitionist, it was passionately set +against an extension of slavery into the territories by act of Congress; +that squatter sovereignty was the mildest kind of compromise acceptable +to the farmers whose votes would determine the fate of the election. +Southern leaders would not accept his opinion. Yancey, speaking for +Alabama, refused to palter with any plan not built on the proposition +that slavery was in itself right. He taunted the Northern Democrats with +taking the view that slavery was wrong, but that they could not do +anything about it. That, he said, was the fatal error--the cause of all +discord, the source of "Black Republicanism," as well as squatter +sovereignty. The gauntlet was thus thrown down at the feet of the +Northern delegates: "You must not apologize for slavery; you must +declare it right; you must advocate its extension." The challenge, so +bluntly put, was as bluntly answered. "Gentlemen of the South," +responded a delegate from Ohio, "you mistake us. You mistake us. We will +not do it." + +For ten days the Charleston convention wrangled over the platform and +balloted for the nomination of a candidate. Douglas, though in the lead, +could not get the two-thirds vote required for victory. For more than +fifty times the roll of the convention was called without a decision. +Then in sheer desperation the convention adjourned to meet later at +Baltimore. When the delegates again assembled, their passions ran as +high as ever. The division into two irreconcilable factions was +unchanged. Uncompromising delegates from the South withdrew to Richmond, +nominated John C. Breckinridge of Kentucky for President, and put forth +a platform asserting the rights of slave owners in the territories and +the duty of the federal government to protect them. The delegates who +remained at Baltimore nominated Douglas and endorsed his doctrine of +squatter sovereignty. + +=The Constitutional Union Party.=--While the Democratic party was being +disrupted, a fragment of the former Whig party, known as the +Constitutional Unionists, held a convention at Baltimore and selected +national candidates: John Bell from Tennessee and Edward Everett from +Massachusetts. A melancholy interest attached to this assembly. It was +mainly composed of old men whose political views were those of Clay and +Webster, cherished leaders now dead and gone. In their platform they +sought to exorcise the evil spirit of partisanship by inviting their +fellow citizens to "support the Constitution of the country, the union +of the states, and the enforcement of the laws." The party that +campaigned on this grand sentiment only drew laughter from the Democrats +and derision from the Republicans and polled less than one-fourth the +votes. + +=The Republican Convention.=--With the Whigs definitely forced into a +separate group, the Republican convention at Chicago was fated to be +sectional in character, although five slave states did send delegates. +As the Democrats were split, the party that had led a forlorn hope four +years before was on the high road to success at last. New and powerful +recruits were found. The advocates of a high protective tariff and the +friends of free homesteads for farmers and workingmen mingled with +enthusiastic foes of slavery. While still firm in their opposition to +slavery in the territories, the Republicans went on record in favor of a +homestead law granting free lands to settlers and approved customs +duties designed "to encourage the development of the industrial +interests of the whole country." The platform was greeted with cheers +which, according to the stenographic report of the convention, became +loud and prolonged as the protective tariff and homestead planks were +read. + +Having skillfully drawn a platform to unite the North in opposition to +slavery and the planting system, the Republicans were also adroit in +their selection of a candidate. The tariff plank might carry +Pennsylvania, a Democratic state; but Ohio, Indiana, and Illinois were +equally essential to success at the polls. The southern counties of +these states were filled with settlers from Virginia, North Carolina, +and Kentucky who, even if they had no love for slavery, were no friends +of abolition. Moreover, remembering the old fight on the United States +Bank in Andrew Jackson's day, they were suspicious of men from the East. +Accordingly, they did not favor the candidacy of Seward, the leading +Republican statesman and "favorite son" of New York. + +After much trading and discussing, the convention came to the conclusion +that Abraham Lincoln of Illinois was the most "available" candidate. He +was of Southern origin, born in Kentucky in 1809, a fact that told +heavily in the campaign in the Ohio Valley. He was a man of the soil, +the son of poor frontier parents, a pioneer who in his youth had labored +in the fields and forests, celebrated far and wide as "honest Abe, the +rail-splitter." It was well-known that he disliked slavery, but was no +abolitionist. He had come dangerously near to Seward's radicalism in his +"house-divided-against-itself" speech but he had never committed himself +to the reckless doctrine that there was a "higher law" than the +Constitution. Slavery in the South he tolerated as a bitter fact; +slavery in the territories he opposed with all his strength. Of his +sincerity there could be no doubt. He was a speaker and writer of +singular power, commanding, by the use of simple and homely language, +the hearts and minds of those who heard him speak or read his printed +words. He had gone far enough in his opposition to slavery; but not too +far. He was the man of the hour! Amid lusty cheers from ten thousand +throats, Lincoln was nominated for the presidency by the Republicans. In +the ensuing election, he carried all the free states except New Jersey. + + +=References= + +P.E. Chadwick, _Causes of the Civil War_ (American Nation Series). + +W.E. Dodd, _Statesmen of the Old South_. + +E. Engle, _Southern Sidelights_ (Sympathetic account of the Old South). + +A.B. Hart, _Slavery and Abolition_ (American Nation Series). + +J.F. Rhodes, _History of the United States_, Vols. I and II. + +T.C. Smith, _Parties and Slavery_ (American Nation Series). + + +=Questions= + +1. Trace the decline of slavery in the North and explain it. + +2. Describe the character of early opposition to slavery. + +3. What was the effect of abolition agitation? + +4. Why did anti-slavery sentiment practically disappear in the South? + +5. On what grounds did Calhoun defend slavery? + +6. Explain how slave owners became powerful in politics. + +7. Why was it impossible to keep the slavery issue out of national +politics? + +8. Give the leading steps in the long controversy over slavery in the +territories. + +9. State the terms of the Compromise of 1850 and explain its failure. + +10. What were the startling events between 1850 and 1860? + +11. Account for the rise of the Republican party. What party had used +the title before? + +12. How did the Dred Scott decision become a political issue? + +13. What were some of the points brought out in the Lincoln-Douglas +debates? + +14. Describe the party division in 1860. + +15. What were the main planks in the Republican platform? + + +=Research Topics= + +=The Extension of Cotton Planting.=--Callender, _Economic History of the +United States_, pp. 760-768. + +=Abolition Agitation.=--McMaster, _History of the People of the United +States_, Vol. VI, pp. 271-298. + +=Calhoun's Defense of Slavery.=--Harding, _Select Orations Illustrating +American History_, pp. 247-257. + +=The Compromise of 1850.=--Clay's speech in Harding, _Select Orations_, +pp. 267-289. The compromise laws in Macdonald, _Documentary Source Book +of American History_, pp. 383-394. Narrative account in McMaster, Vol. +VIII, pp. 1-55; Elson, _History of the United States_, pp. 540-548. + +=The Repeal of the Missouri Compromise.=--McMaster, Vol. VIII, pp. +192-231; Elson, pp. 571-582. + +=The Dred Scott Case.=--McMaster, Vol. VIII, pp. 278-282. Compare the +opinion of Taney and the dissent of Curtis in Macdonald, _Documentary +Source Book_, pp. 405-420; Elson, pp. 595-598. + +=The Lincoln-Douglas Debates.=--Analysis of original speeches in +Harding, _Select Orations_ pp. 309-341; Elson, pp. 598-604. + +=Biographical Studies.=--Calhoun, Clay, Webster, A.H. Stephens, Douglas, +W.H. Seward, William Lloyd Garrison, Wendell Phillips, and Harriet +Beecher Stowe. + + + + +CHAPTER XV + +THE CIVIL WAR AND RECONSTRUCTION + + +"The irrepressible conflict is about to be visited upon us through the +Black Republican nominee and his fanatical, diabolical Republican +party," ran an appeal to the voters of South Carolina during the +campaign of 1860. If that calamity comes to pass, responded the governor +of the state, the answer should be a declaration of independence. In a +few days the suspense was over. The news of Lincoln's election came +speeding along the wires. Prepared for the event, the editor of the +Charleston _Mercury_ unfurled the flag of his state amid wild cheers +from an excited throng in the streets. Then he seized his pen and wrote: +"The tea has been thrown overboard; the revolution of 1860 has been +initiated." The issue was submitted to the voters in the choice of +delegates to a state convention called to cast off the yoke of the +Constitution. + + +THE SOUTHERN CONFEDERACY + +=Secession.=--As arranged, the convention of South Carolina assembled in +December and without a dissenting voice passed the ordinance of +secession withdrawing from the union. Bells were rung exultantly, the +roar of cannon carried the news to outlying counties, fireworks lighted +up the heavens, and champagne flowed. The crisis so long expected had +come at last; even the conservatives who had prayed that they might +escape the dreadful crash greeted it with a sigh of relief. + +[Illustration: THE UNITED STATES IN 1861 + +The border states (in purple) remained loyal.] + +South Carolina now sent forth an appeal to her sister states--states +that had in Jackson's day repudiated nullification as leading to "the +dissolution of the union." The answer that came this time was in a +different vein. A month had hardly elapsed before five other +states--Florida, Georgia, Alabama, Mississippi, and Louisiana--had +withdrawn from the union. In February, Texas followed. Virginia, +hesitating until the bombardment of Fort Sumter forced a conclusion, +seceded in April; but fifty-five of the one hundred and forty-three +delegates dissented, foreshadowing the creation of the new state of West +Virginia which Congress admitted to the union in 1863. In May, North +Carolina, Arkansas, and Tennessee announced their independence. + +=Secession and the Theories of the Union.=--In severing their relations +with the union, the seceding states denied every point in the Northern +theory of the Constitution. That theory, as every one knows, was +carefully formulated by Webster and elaborated by Lincoln. According to +it, the union was older than the states; it was created before the +Declaration of Independence for the purpose of common defense. The +Articles of Confederation did but strengthen this national bond and the +Constitution sealed it forever. The federal government was not a +creature of state governments. It was erected by the people and derived +its powers directly from them. "It is," said Webster, "the people's +Constitution, the people's government; made for the people; made by the +people; and answerable to the people. The people of the United States +have declared that this Constitution shall be the supreme law." When a +state questions the lawfulness of any act of the federal government, it +cannot nullify that act or withdraw from the union; it must abide by the +decision of the Supreme Court of the United States. The union of these +states is perpetual, ran Lincoln's simple argument in the first +inaugural; the federal Constitution has no provision for its own +termination; it can be destroyed only by some action not provided for in +the instrument itself; even if it is a compact among all the states the +consent of all must be necessary to its dissolution; therefore no state +can lawfully get out of the union and acts of violence against the +United States are insurrectionary or revolutionary. This was the system +which he believed himself bound to defend by his oath of office +"registered in heaven." + +All this reasoning Southern statesmen utterly rejected. In their opinion +the thirteen original states won their independence as separate and +sovereign powers. The treaty of peace with Great Britain named them all +and acknowledged them "to be free, sovereign, and independent states." +The Articles of Confederation very explicitly declared that "each state +retains its sovereignty, freedom, and independence." The Constitution +was a "league of nations" formed by an alliance of thirteen separate +powers, each one of which ratified the instrument before it was put into +effect. They voluntarily entered the union under the Constitution and +voluntarily they could leave it. Such was the constitutional doctrine of +Hayne, Calhoun, and Jefferson Davis. In seceding, the Southern states +had only to follow legal methods, and the transaction would be correct +in every particular. So conventions were summoned, elections were held, +and "sovereign assemblies of the people" set aside the Constitution in +the same manner as it had been ratified nearly four score years before. +Thus, said the Southern people, the moral judgment was fulfilled and the +letter of the law carried into effect. + +[Illustration: JEFFERSON DAVIS] + +=The Formation of the Confederacy.=--Acting on the call of Mississippi, +a congress of delegates from the seceded states met at Montgomery, +Alabama, and on February 8, 1861, adopted a temporary plan of union. It +selected, as provisional president, Jefferson Davis of Mississippi, a +man well fitted by experience and moderation for leadership, a graduate +of West Point, who had rendered distinguished service on the field of +battle in the Mexican War, in public office, and as a member of +Congress. + +In March, a permanent constitution of the Confederate states was +drafted. It was quickly ratified by the states; elections were held in +November; and the government under it went into effect the next year. +This new constitution, in form, was very much like the famous instrument +drafted at Philadelphia in 1787. It provided for a President, a Senate, +and a House of Representatives along almost identical lines. In the +powers conferred upon them, however, there were striking differences. +The right to appropriate money for internal improvements was expressly +withheld; bounties were not to be granted from the treasury nor import +duties so laid as to promote or foster any branch of industry. The +dignity of the state, if any might be bold enough to question it, was +safeguarded in the opening line by the declaration that each acted "in +its sovereign and independent character" in forming the Southern union. + +=Financing the Confederacy.=--No government ever set out upon its career +with more perplexing tasks in front of it. The North had a monetary +system; the South had to create one. The North had a scheme of taxation +that produced large revenues from numerous sources; the South had to +formulate and carry out a financial plan. Like the North, the +Confederacy expected to secure a large revenue from customs duties, +easily collected and little felt among the masses. To this expectation +the blockade of Southern ports inaugurated by Lincoln in April, 1861, +soon put an end. Following the precedent set by Congress under the +Articles of Confederation, the Southern Congress resorted to a direct +property tax apportioned among the states, only to meet the failure that +might have been foretold. + +The Confederacy also sold bonds, the first issue bringing into the +treasury nearly all the specie available in the Southern banks. This +specie by unhappy management was early sent abroad to pay for supplies, +sapping the foundations of a sound currency system. Large amounts of +bonds were sold overseas, commanding at first better terms than those +of the North in the markets of London, Paris, and Amsterdam, many an +English lord and statesman buying with enthusiasm and confidence to +lament within a few years the proofs of his folly. The difficulties of +bringing through the blockade any supplies purchased by foreign bond +issues, however, nullified the effect of foreign credit and forced the +Confederacy back upon the device of paper money. In all approximately +one billion dollars streamed from the printing presses, to fall in value +at an alarming rate, reaching in January, 1863, the astounding figure of +fifty dollars in paper money for one in gold. Every known device was +used to prevent its depreciation, without result. To the issues of the +Confederate Congress were added untold millions poured out by the states +and by private banks. + +=Human and Material Resources.=--When we measure strength for strength +in those signs of power--men, money, and supplies--it is difficult to +see how the South was able to embark on secession and war with such +confidence in the outcome. In the Confederacy at the final reckoning +there were eleven states in all, to be pitted against twenty-two; a +population of nine millions, nearly one-half servile, to be pitted +against twenty-two millions; a land without great industries to produce +war supplies and without vast capital to furnish war finances, joined in +battle with a nation already industrial and fortified by property worth +eleven billion dollars. Even after the Confederate Congress authorized +conscription in 1862, Southern man power, measured in numbers, was +wholly inadequate to uphold the independence which had been declared. +How, therefore, could the Confederacy hope to sustain itself against + +such a combination of men, money, and materials as the North could +marshal? + +=Southern Expectations.=--The answer to this question is to be found in +the ideas that prevailed among Southern leaders. First of all, they +hoped, in vain, to carry the Confederacy up to the Ohio River; and, with +the aid of Missouri, to gain possession of the Mississippi Valley, the +granary of the nation. In the second place, they reckoned upon a large +and continuous trade with Great Britain--the exchange of cotton for war +materials. They likewise expected to receive recognition and open aid +from European powers that looked with satisfaction upon the breakup of +the great American republic. In the third place, they believed that +their control over several staples so essential to Northern industry +would enable them to bring on an industrial crisis in the manufacturing +states. "I firmly believe," wrote Senator Hammond, of South Carolina, in +1860, "that the slave-holding South is now the controlling power of the +world; that no other power would face us in hostility. Cotton, rice, +tobacco, and naval stores command the world; and we have the sense to +know it and are sufficiently Teutonic to carry it out successfully. The +North without us would be a motherless calf, bleating about, and die of +mange and starvation." + +There were other grounds for confidence. Having seized all of the +federal military and naval supplies in the South, and having left the +national government weak in armed power during their possession of the +presidency, Southern leaders looked to a swift war, if it came at all, +to put the finishing stroke to independence. "The greasy mechanics of +the North," it was repeatedly said, "will not fight." As to disparity in +numbers they drew historic parallels. "Our fathers, a mere handful, +overcame the enormous power of Great Britain," a saying of ex-President +Tyler, ran current to reassure the doubtful. Finally, and this point +cannot be too strongly emphasized, the South expected to see a weakened +and divided North. It knew that the abolitionists and the Southern +sympathizers were ready to let the Confederate states go in peace; that +Lincoln represented only a little more than one-third the voters of the +country; and that the vote for Douglas, Bell, and Breckinridge meant a +decided opposition to the Republicans and their policies. + +=Efforts at Compromise.=--Republican leaders, on reviewing the same +facts, were themselves uncertain as to the outcome of a civil war and +made many efforts to avoid a crisis. Thurlow Weed, an Albany journalist +and politician who had done much to carry New York for Lincoln, proposed +a plan for extending the Missouri Compromise line to the Pacific. +Jefferson Davis, warning his followers that a war if it came would be +terrible, was prepared to accept the offer; but Lincoln, remembering his +campaign pledges, stood firm as a rock against it. His followers in +Congress took the same position with regard to a similar settlement +suggested by Senator Crittenden of Kentucky. + +Though unwilling to surrender his solemn promises respecting slavery in +the territories, Lincoln was prepared to give to Southern leaders a +strong guarantee that his administration would not interfere directly or +indirectly with slavery in the states. Anxious to reassure the South on +this point, the Republicans in Congress proposed to write into the +Constitution a declaration that no amendment should ever be made +authorizing the abolition of or interference with slavery in any state. +The resolution, duly passed, was sent forth on March 4, 1861, with the +approval of Lincoln; it was actually ratified by three states before the +storm of war destroyed it. By the irony of fate the thirteenth amendment +was to abolish, not guarantee, slavery. + + +THE WAR MEASURES OF THE FEDERAL GOVERNMENT + +=Raising the Armies.=--The crisis at Fort Sumter, on April 12-14, 1861, +forced the President and Congress to turn from negotiations to problems +of warfare. Little did they realize the magnitude of the task before +them. Lincoln's first call for volunteers, issued on April 15, 1861, +limited the number to 75,000, put their term of service at three months, +and prescribed their duty as the enforcement of the law against +combinations too powerful to be overcome by ordinary judicial process. +Disillusionment swiftly followed. The terrible defeat of the Federals at +Bull Run on July 21 revealed the serious character of the task before +them; and by a series of measures Congress put the entire man power of +the country at the President's command. Under these acts, he issued new +calls for volunteers. Early in August, 1862, he ordered a draft of +militiamen numbering 300,000 for nine months' service. The results were +disappointing--ominous--for only about 87,000 soldiers were added to the +army. Something more drastic was clearly necessary. + +In March, 1863, Lincoln signed the inevitable draft law; it enrolled in +the national forces liable to military duty all able-bodied male +citizens and persons of foreign birth who had declared their intention +to become citizens, between the ages of twenty and forty-five +years--with exemptions on grounds of physical weakness and dependency. +From the men enrolled were drawn by lot those destined to active +service. Unhappily the measure struck a mortal blow at the principle of +universal liability by excusing any person who found a substitute for +himself or paid into the war office a sum, not exceeding three hundred +dollars, to be fixed by general order. This provision, so crass and so +obviously favoring the well-to-do, sowed seeds of bitterness which +sprang up a hundredfold in the North. + +[Illustration: THE DRAFT RIOTS IN NEW YORK CITY] + +The beginning of the drawings under the draft act in New York City, on +Monday, July 13, 1863, was the signal for four days of rioting. In the +course of this uprising, draft headquarters were destroyed; the office +of the _Tribune_ was gutted; negroes were seized, hanged, and shot; the +homes of obnoxious Unionists were burned down; the residence of the +mayor of the city was attacked; and regular battles were fought in the +streets between the rioters and the police. Business stopped and a large +part of the city passed absolutely into the control of the mob. Not +until late the following Wednesday did enough troops arrive to restore +order and enable the residents of the city to resume their daily +activities. At least a thousand people had been killed or wounded and +more than a million dollars' worth of damage done to property. The draft +temporarily interrupted by this outbreak was then resumed and carried +out without further trouble. + +The results of the draft were in the end distinctly disappointing to the +government. The exemptions were numerous and the number who preferred +and were able to pay $300 rather than serve exceeded all expectations. +Volunteering, it is true, was stimulated, but even that resource could +hardly keep the thinning ranks of the army filled. With reluctance +Congress struck out the $300 exemption clause, but still favored the +well-to-do by allowing them to hire substitutes if they could find them. +With all this power in its hands the administration was able by January, +1865, to construct a union army that outnumbered the Confederates two to +one. + +=War Finance.=--In the financial sphere the North faced immense +difficulties. The surplus in the treasury had been dissipated by 1861 +and the tariff of 1857 had failed to produce an income sufficient to +meet the ordinary expenses of the government. Confronted by military and +naval expenditures of appalling magnitude, rising from $35,000,000 in +the first year of the war to $1,153,000,000 in the last year, the +administration had to tap every available source of income. The duties +on imports were increased, not once but many times, producing huge +revenues and also meeting the most extravagant demands of the +manufacturers for protection. Direct taxes were imposed on the states +according to their respective populations, but the returns were +meager--all out of proportion to the irritation involved. Stamp taxes +and taxes on luxuries, occupations, and the earnings of corporations +were laid with a weight that, in ordinary times, would have drawn forth +opposition of ominous strength. The whole gamut of taxation was run. +Even a tax on incomes and gains by the year, the first in the history of +the federal government, was included in the long list. + +Revenues were supplemented by bond issues, mounting in size and interest +rate, until in October, at the end of the war, the debt stood at +$2,208,000,000. The total cost of the war was many times the money value +of all the slaves in the Southern states. To the debt must be added +nearly half a billion dollars in "greenbacks"--paper money issued by +Congress in desperation as bond sales and revenues from taxes failed to +meet the rising expenditures. This currency issued at par on +questionable warrant from the Constitution, like all such paper, quickly +began to decline until in the worst fortunes of 1864 one dollar in gold +was worth nearly three in greenbacks. + +=The Blockade of Southern Ports.=--Four days after his call for +volunteers, April 19, 1861, President Lincoln issued a proclamation +blockading the ports of the Southern Confederacy. Later the blockade was +extended to Virginia and North Carolina, as they withdrew from the +union. Vessels attempting to enter or leave these ports, if they +disregarded the warnings of a blockading ship, were to be captured and +brought as prizes to the nearest convenient port. To make the order +effective, immediate steps were taken to increase the naval forces, +depleted by neglect, until the entire coast line was patrolled with such +a number of ships that it was a rare captain who ventured to run the +gantlet. The collision between the _Merrimac_ and the _Monitor_ in +March, 1862, sealed the fate of the Confederacy. The exploits of the +union navy are recorded in the falling export of cotton: $202,000,000 in +1860; $42,000,000 in 1861; and $4,000,000 in 1862. + +The deadly effect of this paralysis of trade upon Southern war power may +be readily imagined. Foreign loans, payable in cotton, could be +negotiated but not paid off. Supplies could be purchased on credit but +not brought through the drag net. With extreme difficulty could the +Confederate government secure even paper for the issue of money and +bonds. Publishers, in despair at the loss of supplies, were finally +driven to the use of brown wrapping paper and wall paper. As the +railways and rolling stock wore out, it became impossible to renew them +from England or France. Unable to export their cotton, planters on the +seaboard burned it in what were called "fires of patriotism." In their +lurid light the fatal weakness of Southern economy stood revealed. + +[Illustration: A BLOCKADE RUNNER] + +=Diplomacy.=--The war had not advanced far before the federal government +became involved in many perplexing problems of diplomacy in Europe. The +Confederacy early turned to England and France for financial aid and for +recognition as an independent power. Davis believed that the industrial +crisis created by the cotton blockade would in time literally compel +Europe to intervene in order to get this essential staple. The crisis +came as he expected but not the result. Thousands of English textile +workers were thrown out of employment; and yet, while on the point of +starvation, they adopted resolutions favoring the North instead of +petitioning their government to aid the South by breaking the blockade. + +With the ruling classes it was far otherwise. Napoleon III, the Emperor +of the French, was eager to help in disrupting the American republic; if +he could have won England's support, he would have carried out his +designs. As it turned out he found plenty of sympathy across the Channel +but not open and official cooperation. According to the eminent +historian, Rhodes, "four-fifths of the British House of Lords and most +members of the House of Commons were favorable to the Confederacy and +anxious for its triumph." Late in 1862 the British ministers, thus +sustained, were on the point of recognizing the independence of the +Confederacy. Had it not been for their extreme caution, for the constant +and harassing criticism by English friends of the United States--like +John Bright--and for the victories of Vicksburg and Gettysburg, both + +England and France would have doubtless declared the Confederacy to be +one of the independent powers of the earth. + +[Illustration: JOHN BRIGHT] + +While stopping short of recognizing its independence, England and France +took several steps that were in favor of the South. In proclaiming +neutrality, they early accepted the Confederates as "belligerents" and +accorded them the rights of people at war--a measure which aroused anger +in the North at first but was later admitted to be sound. Otherwise +Confederates taken in battle would have been regarded as "rebels" or +"traitors" to be hanged or shot. Napoleon III proposed to Russia in 1861 +a coalition of powers against the North, only to meet a firm refusal. +The next year he suggested intervention to Great Britain, encountering +this time a conditional rejection of his plans. In 1863, not daunted by +rebuffs, he offered his services to Lincoln as a mediator, receiving in +reply a polite letter declining his proposal and a sharp resolution from +Congress suggesting that he attend to his own affairs. + +In both England and France the governments pursued a policy of +friendliness to the Confederate agents. The British ministry, with +indifference if not connivance, permitted rams and ships to be built in +British docks and allowed them to escape to play havoc under the +Confederate flag with American commerce. One of them, the _Alabama_, +built in Liverpool by a British firm and paid for by bonds sold in +England, ran an extraordinary career and threatened to break the +blockade. The course followed by the British government, against the +protests of the American minister in London, was later regretted. By an +award of a tribunal of arbitration at Geneva in 1872, Great Britain was +required to pay the huge sum of $15,500,000 to cover the damages wrought +by Confederate cruisers fitted out in England. + +[Illustration: WILLIAM H. SEWARD] + +In all fairness it should be said that the conduct of the North +contributed to the irritation between the two countries. Seward, the +Secretary of State, was vindictive in dealing with Great Britain; had it +not been for the moderation of Lincoln, he would have pursued a course +verging in the direction of open war. The New York and Boston papers +were severe in their attacks on England. Words were, on one occasion at +least, accompanied by an act savoring of open hostility. In November, +1861, Captain Wilkes, commanding a union vessel, overhauled the British +steamer _Trent_, and carried off by force two Confederate agents, Mason +and Slidell, sent by President Davis to represent the Confederacy at +London and Paris respectively. This was a clear violation of the right +of merchant vessels to be immune from search and impressment; and, in +answer to the demand of Great Britain for the release of the two men, +the United States conceded that it was in the wrong. It surrendered the +two Confederate agents to a British vessel for safe conduct abroad, and +made appropriate apologies. + +=Emancipation.=--Among the extreme war measures adopted by the Northern +government must be counted the emancipation of the slaves in the states +in arms against the union. This step was early and repeatedly suggested +to Lincoln by the abolitionists; but was steadily put aside. He knew +that the abolitionists were a mere handful, that emancipation might +drive the border states into secession, and that the Northern soldiers +had enlisted to save the union. Moreover, he had before him a solemn +resolution passed by Congress on July 22, 1861, declaring the sole +purpose of the war to be the salvation of the union and disavowing any +intention of interfering with slavery. + +The federal government, though pledged to the preservation of slavery, +soon found itself beaten back upon its course and out upon a new tack. +Before a year had elapsed, namely on April 10, 1862, Congress resolved +that financial aid should be given to any state that might adopt gradual +emancipation. Six days later it abolished slavery in the District of +Columbia. Two short months elapsed. On June 19, 1862, it swept slavery +forever from the territories of the United States. Chief Justice Taney +still lived, the Dred Scott decision stood as written in the book, but +the Constitution had been re-read in the light of the Civil War. The +drift of public sentiment in the North was being revealed. + +While these measures were pending in Congress, Lincoln was slowly making +up his mind. By July of that year he had come to his great decision. +Near the end of that month he read to his cabinet the draft of a +proclamation of emancipation; but he laid it aside until a military +achievement would make it something more than an idle gesture. In +September, the severe check administered to Lee at Antietam seemed to +offer the golden opportunity. On the 22d, the immortal document was +given to the world announcing that, unless the states in arms returned +to the union by January 1, 1863, the fatal blow at their "peculiar +institution" would be delivered. Southern leaders treated it with slight +regard, and so on the date set the promise was fulfilled. The +proclamation was issued as a war measure, adopted by the President as +commander-in-chief of the armed forces, on grounds of military +necessity. It did not abolish slavery. It simply emancipated slaves in +places then in arms against federal authority. Everywhere else slavery, +as far as the Proclamation was concerned, remained lawful. + +[Illustration: ABRAHAM LINCOLN] + +To seal forever the proclamation of emancipation, and to extend freedom +to the whole country, Congress, in January, 1865, on the urgent +recommendation of Lincoln, transmitted to the states the thirteenth +amendment, abolishing slavery throughout the United States. By the end +of 1865 the amendment was ratified. The house was not divided against +itself; it did not fall; it was all free. + +=The Restraint of Civil Liberty.=--As in all great wars, particularly +those in the nature of a civil strife, it was found necessary to use +strong measures to sustain opinion favorable to the administration's +military policies and to frustrate the designs of those who sought to +hamper its action. Within two weeks of his first call for volunteers, +Lincoln empowered General Scott to suspend the writ of _habeas corpus_ +along the line of march between Philadelphia and Washington and thus to +arrest and hold without interference from civil courts any one whom he +deemed a menace to the union. At a later date the area thus ruled by +military officers was extended by executive proclamation. By an act of +March 3, 1863, Congress, desiring to lay all doubts about the +President's power, authorized him to suspend the writ throughout the +United States or in any part thereof. It also freed military officers +from the necessity of surrendering to civil courts persons arrested +under their orders, or even making answers to writs issued from such +courts. In the autumn of that year the President, acting under the terms +of this law, declared this ancient and honorable instrument for the +protection of civil liberties, the _habeas corpus_, suspended throughout +the length and breadth of the land. The power of the government was also +strengthened by an act defining and punishing certain conspiracies, +passed on July 31, 1861--a measure which imposed heavy penalties on +those who by force, intimidation, or threat interfered with the +execution of the law. + +Thus doubly armed, the military authorities spared no one suspected of +active sympathy with the Southern cause. Editors were arrested and +imprisoned, their papers suspended, and their newsboys locked up. Those +who organized "peace meetings" soon found themselves in the toils of the +law. Members of the Maryland legislature, the mayor of Baltimore, and +local editors suspected of entertaining secessionist opinions, were +imprisoned on military orders although charged with no offense, and were +denied the privilege of examination before a civil magistrate. A Vermont +farmer, too outspoken in his criticism of the government, found himself +behind the bars until the government, in its good pleasure, saw fit to +release him. These measures were not confined to the theater of war nor +to the border states where the spirit of secession was strong enough to +endanger the cause of union. They were applied all through the Northern +states up to the very boundaries of Canada. Zeal for the national cause, +too often supplemented by a zeal for persecution, spread terror among +those who wavered in the singleness of their devotion to the union. + +These drastic operations on the part of military authorities, so foreign +to the normal course of civilized life, naturally aroused intense and +bitter hostility. Meetings of protest were held throughout the country. +Thirty-six members of the House of Representatives sought to put on +record their condemnation of the suspension of the _habeas corpus_ act, +only to meet a firm denial by the supporters of the act. Chief Justice +Taney, before whom the case of a man arrested under the President's +military authority was brought, emphatically declared, in a long and +learned opinion bristling with historical examples, that the President +had no power to suspend the writ of _habeas corpus_. In Congress and +out, Democrats, abolitionists, and champions of civil liberty denounced +Lincoln and his Cabinet in unsparing terms. Vallandigham, a Democratic +leader of Ohio, afterward banished to the South for his opposition to +the war, constantly applied to Lincoln the epithet of "Caesar." Wendell +Phillips saw in him "a more unlimited despot than the world knows this +side of China." + +Sensitive to such stinging thrusts and no friend of wanton persecution, +Lincoln attempted to mitigate the rigors of the law by paroling many +political prisoners. The general policy, however, he defended in homely +language, very different in tone and meaning from the involved reasoning +of the lawyers. "Must I shoot a simple-minded soldier boy who deserts, +while I must not touch a hair of the wily agitator who induces him to +desert?" he asked in a quiet way of some spokesmen for those who +protested against arresting people for "talking against the war." This +summed up his philosophy. He was engaged in a war to save the union, and +all measures necessary and proper to accomplish that purpose were +warranted by the Constitution which he had sworn to uphold. + +=Military Strategy--North and South.=--The broad outlines of military +strategy followed by the commanders of the opposing forces are clear +even to the layman who cannot be expected to master the details of a +campaign or, for that matter, the maneuvers of a single great battle. +The problem for the South was one of defense mainly, though even for +defense swift and paralyzing strokes at the North were later deemed +imperative measures. The problem of the North was, to put it baldly, one +of invasion and conquest. Southern territory had to be invaded and +Southern armies beaten on their own ground or worn down to exhaustion +there. + +In the execution of this undertaking, geography, as usual, played a +significant part in the disposition of forces. The Appalachian ranges, +stretching through the Confederacy to Northern Alabama, divided the +campaigns into Eastern and Western enterprises. Both were of signal +importance. Victory in the East promised the capture of the Confederate +capital of Richmond, a stroke of moral worth, hardly to be +overestimated. Victory in the West meant severing the Confederacy and +opening the Mississippi Valley down to the Gulf. + +As it turned out, the Western forces accomplished their task first, +vindicating the military powers of union soldiers and shaking the +confidence of opposing commanders. In February, 1862, Grant captured +Fort Donelson on the Tennessee River, rallied wavering unionists in +Kentucky, forced the evacuation of Nashville, and opened the way for two +hundred miles into the Confederacy. At Shiloh, Murfreesboro, Vicksburg, +Chickamauga, Chattanooga, desperate fighting followed and, in spite of +varying fortunes, it resulted in the discomfiture and retirement of +Confederate forces to the Southeast into Georgia. By the middle of 1863, +the Mississippi Valley was open to the Gulf, the initiative taken out of +the hands of Southern commanders in the West, and the way prepared for +Sherman's final stroke--the march from Atlanta to the sea--a maneuver +executed with needless severity in the autumn of 1864. + +[Illustration: GENERAL ULYSSES S. GRANT] + +[Illustration: GENERAL ROBERT E. LEE] + +For the almost unbroken succession of achievements in the West by +Generals Grant, Sherman, Thomas, and Hooker against Albert Sidney +Johnston, Bragg, Pemberton, and Hood, the union forces in the East +offered at first an almost equally unbroken series of misfortunes and +disasters. Far from capturing Richmond, they had been thrown on the +defensive. General after general--McClellan, Pope, Burnside, Hooker, and +Meade--was tried and found wanting. None of them could administer a +crushing defeat to the Confederate troops and more than once the union +soldiers were beaten in a fair battle. They did succeed, however, in +delivering a severe check to advancing Confederates under General Robert +E. Lee, first at Antietam in September, 1862, and then at Gettysburg in +July, 1863--checks reckoned as victories though in each instance the +Confederates escaped without demoralization. Not until the beginning of +the next year, when General Grant, supplied with almost unlimited men +and munitions, began his irresistible hammering at Lee's army, did the +final phase of the war commence. The pitiless drive told at last. +General Lee, on April 9, 1865, seeing the futility of further conflict, +surrendered an army still capable of hard fighting, at Appomattox, not +far from the capital of the Confederacy. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +THE FEDERAL MILITARY HOSPITAL AT GETTYSBURG] + +=Abraham Lincoln.=--The services of Lincoln to the cause of union defy +description. A judicial scrutiny of the war reveals his thought and +planning in every part of the varied activity that finally crowned +Northern arms with victory. Is it in the field of diplomacy? Does +Seward, the Secretary of State, propose harsh and caustic measures +likely to draw England's sword into the scale? Lincoln counsels +moderation. He takes the irritating message and with his own hand +strikes out, erases, tones down, and interlines, exchanging for words +that sting and burn the language of prudence and caution. Is it a matter +of compromise with the South, so often proposed by men on both sides +sick of carnage? Lincoln is always ready to listen and turns away only +when he is invited to surrender principles essential to the safety of +the union. Is it high strategy of war, a question of the general best +fitted to win Gettysburg--Hooker, Sedgwick, or Meade? Lincoln goes in +person to the War Department in the dead of night to take counsel with +his Secretary and to make the fateful choice. + +Is it a complaint from a citizen, deprived, as he believes, of his civil +liberties unjustly or in violation of the Constitution? Lincoln is ready +to hear it and anxious to afford relief, if warrant can be found for it. +Is a mother begging for the life of a son sentenced to be shot as a +deserter? Lincoln hears her petition, and grants it even against the +protests made by his generals in the name of military discipline. Do +politicians sow dissensions in the army and among civilians? Lincoln +grandly waves aside their petty personalities and invites them to think +of the greater cause. Is it a question of securing votes to ratify the +thirteenth amendment abolishing slavery? Lincoln thinks it not beneath +his dignity to traffic and huckster with politicians over the trifling +jobs asked in return by the members who hold out against him. Does a New +York newspaper call him an ignorant Western boor? Lincoln's reply is a +letter to a mother who has given her all--her sons on the field of +battle--and an address at Gettysburg, both of which will live as long as +the tongue in which they were written. These are tributes not only to +his mastery of the English language but also to his mastery of all those +sentiments of sweetness and strength which are the finest flowers of +culture. + +Throughout the entire span of service, however, Lincoln was beset by +merciless critics. The fiery apostles of abolition accused him of +cowardice when he delayed the bold stroke at slavery. Anti-war Democrats +lashed out at every step he took. Even in his own party he found no +peace. Charles Sumner complained: "Our President is now dictator, +_imperator_--whichever you like; but how vain to have the power of a +god and not to use it godlike." Leaders among the Republicans sought to +put him aside in 1864 and place Chase in his chair. "I hope we may never +have a worse man," was Lincoln's quiet answer. + +Wide were the dissensions in the North during that year and the +Republicans, while selecting Lincoln as their candidate again, cast off +their old name and chose the simple title of the "Union party." +Moreover, they selected a Southern man, Andrew Johnson, of Tennessee, to +be associated with him as candidate for Vice President. This combination +the Northern Democrats boldly confronted with a platform declaring that +"after four years of failure to restore the union by the experiment of +war, during which, under the pretence of military necessity or war power +higher than the Constitution, the Constitution itself has been +disregarded in every part and public liberty and private right alike +trodden down ... justice, humanity, liberty, and public welfare demand +that immediate efforts be made for a cessation of hostilities, to the +end that peace may be restored on the basis of the federal union of the +states." It is true that the Democratic candidate, General McClellan, +sought to break the yoke imposed upon him by the platform, saying that +he could not look his old comrades in the face and pronounce their +efforts vain; but the party call to the nation to repudiate Lincoln and +his works had gone forth. The response came, giving Lincoln 2,200,000 +votes against 1,800,000 for his opponent. The bitter things said about +him during the campaign, he forgot and forgave. When in April, 1865, he +was struck down by the assassin's hand, he above all others in +Washington was planning measures of moderation and healing. + + +THE RESULTS OF THE CIVIL WAR + +There is a strong and natural tendency on the part of writers to stress +the dramatic and heroic aspects of war; but the long judgment of history +requires us to include all other significant phases as well. Like every +great armed conflict, the Civil War outran the purposes of those who +took part in it. Waged over the nature of the union, it made a +revolution in the union, changing public policies and constitutional +principles and giving a new direction to agriculture and industry. + +=The Supremacy of the Union.=--First and foremost, the war settled for +all time the long dispute as to the nature of the federal system. The +doctrine of state sovereignty was laid to rest. Men might still speak of +the rights of states and think of their commonwealths with affection, +but nullification and secession were destroyed. The nation was supreme. + +=The Destruction of the Slave Power.=--Next to the vindication of +national supremacy was the destruction of the planting aristocracy of +the South--that great power which had furnished leadership of undoubted +ability and had so long contested with the industrial and commercial +interests of the North. The first paralyzing blow at the planters was +struck by the abolition of slavery. The second and third came with the +fourteenth (1868) and fifteenth (1870) amendments, giving the ballot to +freedmen and excluding from public office the Confederate +leaders--driving from the work of reconstruction the finest talents of +the South. As if to add bitterness to gall and wormwood, the fourteenth +amendment forbade the United States or any state to pay any debts +incurred in aid of the Confederacy or in the emancipation of the +slaves--plunging into utter bankruptcy the Southern financiers who had +stripped their section of capital to support their cause. So the +Southern planters found themselves excluded from public office and ruled +over by their former bondmen under the tutelage of Republican leaders. +Their labor system was wrecked and their money and bonds were as +worthless as waste paper. The South was subject to the North. That which +neither the Federalists nor the Whigs had been able to accomplish in the +realm of statecraft was accomplished on the field of battle. + + +=The Triumph of Industry.=--The wreck of the planting system was +accompanied by a mighty upswing of Northern industry which made the old +Whigs of Massachusetts and Pennsylvania stare in wonderment. The demands +of the federal government for manufactured goods at unrestricted prices +gave a stimulus to business which more than replaced the lost markets of +the South. Between 1860 and 1870 the number of manufacturing +establishments increased 79.6 per cent as against 14.2 for the previous +decade; while the number of persons employed almost doubled. There was +no doubt about the future of American industry. + +=The Victory for the Protective Tariff.=--Moreover, it was henceforth to +be well protected. For many years before the war the friends of +protection had been on the defensive. The tariff act of 1857 imposed +duties so low as to presage a tariff for revenue only. The war changed +all that. The extraordinary military expenditures, requiring heavy taxes +on all sources, justified tariffs so high that a follower of Clay or +Webster might well have gasped with astonishment. After the war was over +the debt remained and both interest and principal had to be paid. +Protective arguments based on economic reasoning were supported by a +plain necessity for revenue which admitted no dispute. + +=A Liberal Immigration Policy.=--Linked with industry was the labor +supply. The problem of manning industries became a pressing matter, and +Republican leaders grappled with it. In the platform of the Union party +adopted in 1864 it was declared "that foreign immigration, which in the +past has added so much to the wealth, the development of resources, and +the increase of power to this nation--the asylum of the oppressed of all +nations--should be fostered and encouraged by a liberal and just +policy." In that very year Congress, recognizing the importance of the +problem, passed a measure of high significance, creating a bureau of +immigration, and authorizing a modified form of indentured labor, by +making it legal for immigrants to pledge their wages in advance to pay +their passage over. Though the bill was soon repealed, the practice +authorized by it was long continued. The cheapness of the passage +shortened the term of service; but the principle was older than the +days of William Penn. + +=The Homestead Act of 1862.=--In the immigration measure guaranteeing a +continuous and adequate labor supply, the manufacturers saw an offset to +the Homestead Act of 1862 granting free lands to settlers. The Homestead +law they had resisted in a long and bitter congressional battle. +Naturally, they had not taken kindly to a scheme which lured men away +from the factories or enabled them to make unlimited demands for higher +wages as the price of remaining. Southern planters likewise had feared +free homesteads for the very good reason that they only promised to add +to the overbalancing power of the North. + +In spite of the opposition, supporters of a liberal land policy made +steady gains. Free-soil Democrats,--Jacksonian farmers and +mechanics,--labor reformers, and political leaders, like Stephen A. +Douglas of Illinois and Andrew Johnson of Tennessee, kept up the +agitation in season and out. More than once were they able to force a +homestead bill through the House of Representatives only to have it +blocked in the Senate where Southern interests were intrenched. Then, +after the Senate was won over, a Democratic President, James Buchanan, +vetoed the bill. Still the issue lived. The Republicans, strong among +the farmers of the Northwest, favored it from the beginning and pressed +it upon the attention of the country. Finally the manufacturers yielded; +they received their compensation in the contract labor law. In 1862 +Congress provided for the free distribution of land in 160-acre lots +among men and women of strong arms and willing hearts ready to build +their serried lines of homesteads to the Rockies and beyond. + +=Internal Improvements.=--If farmers and manufacturers were early +divided on the matter of free homesteads, the same could hardly be said +of internal improvements. The Western tiller of the soil was as eager +for some easy way of sending his produce to market as the manufacturer +was for the same means to transport his goods to the consumer on the +farm. While the Confederate leaders were writing into their +constitution a clause forbidding all appropriations for internal +improvements, the Republican leaders at Washington were planning such +expenditures from the treasury in the form of public land grants to +railways as would have dazed the authors of the national road bill half +a century earlier. + +=Sound Finance--National Banking.=--From Hamilton's day to Lincoln's, +business men in the East had contended for a sound system of national +currency. The experience of the states with paper money, painfully +impressive in the years before the framing of the Constitution, had been +convincing to those who understood the economy of business. The +Constitution, as we have seen, bore the signs of this experience. States +were forbidden to emit bills of credit: paper money, in short. This +provision stood clear in the document; but judicial ingenuity had +circumvented it in the age of Jacksonian Democracy. The states had +enacted and the Supreme Court, after the death of John Marshall, had +sustained laws chartering banking companies and authorizing them to +issue paper money. So the country was beset by the old curse, the banks +of Western and Southern states issuing reams of paper notes to help +borrowers pay their debts. + +In dealing with war finances, the Republicans attacked this ancient +evil. By act of Congress in 1864, they authorized a series of national +banks founded on the credit of government bonds and empowered to issue +notes. The next year they stopped all bank paper sent forth under the +authority of the states by means of a prohibitive tax. In this way, by +two measures Congress restored federal control over the monetary system +although it did not reestablish the United States Bank so hated by +Jacksonian Democracy. + +=Destruction of States' Rights by Fourteenth Amendment.=--These acts and +others not cited here were measures of centralization and consolidation +at the expense of the powers and dignity of the states. They were all of +high import, but the crowning act of nationalism was the fourteenth +amendment which, among other things, forbade states to "deprive any +person of life, liberty or property without due process of law." The +immediate occasion, though not the actual cause of this provision, was +the need for protecting the rights of freedmen against hostile +legislatures in the South. The result of the amendment, as was +prophesied in protests loud and long from every quarter of the +Democratic party, was the subjection of every act of state, municipal, +and county authorities to possible annulment by the Supreme Court at +Washington. The expected happened. + +Few negroes ever brought cases under the fourteenth amendment to the +attention of the courts; but thousands of state laws, municipal +ordinances, and acts of local authorities were set aside as null and +void under it. Laws of states regulating railway rates, fixing hours of +labor in bakeshops, and taxing corporations were in due time to be +annulled as conflicting with an amendment erroneously supposed to be +designed solely for the protection of negroes. As centralized power over +tariffs, railways, public lands, and other national concerns went to +Congress, so centralized power over the acts of state and local +authorities involving an infringement of personal and property rights +was conferred on the federal judiciary, the apex of which was the +Supreme Court at Washington. Thus the old federation of "independent +states," all equal in rights and dignity, each wearing the "jewel of +sovereignty" so celebrated in Southern oratory, had gone the way of all +flesh under the withering blasts of Civil War. + + +RECONSTRUCTION IN THE SOUTH + +=Theories about the Position of the Seceded States.=--On the morning of +April 9, 1865, when General Lee surrendered his army to General Grant, +eleven states stood in a peculiar relation to the union now declared +perpetual. Lawyers and political philosophers were much perturbed and +had been for some time as to what should be done with the members of the +former Confederacy. Radical Republicans held that they were "conquered +provinces" at the mercy of Congress, to be governed under such laws as +it saw fit to enact and until in its wisdom it decided to readmit any or +all of them to the union. Men of more conservative views held that, as +the war had been waged by the North on the theory that no state could +secede from the union, the Confederate states had merely attempted to +withdraw and had failed. The corollary of this latter line of argument +was simple: "The Southern states are still in the union and it is the +duty of the President, as commander-in-chief, to remove the federal +troops as soon as order is restored and the state governments ready to +function once more as usual." + +=Lincoln's Proposal.=--Some such simple and conservative form of +reconstruction had been suggested by Lincoln in a proclamation of +December 8, 1863. He proposed pardon and a restoration of property, +except in slaves, to nearly all who had "directly or by implication +participated in the existing rebellion," on condition that they take an +oath of loyalty to the union. He then announced that when, in any of the +states named, a body of voters, qualified under the law as it stood +before secession and equal in number to one-tenth the votes cast in +1860, took the oath of allegiance, they should be permitted to +reestablish a state government. Such a government, he added, should be +recognized as a lawful authority and entitled to protection under the +federal Constitution. With reference to the status of the former slaves +Lincoln made it clear that, while their freedom must be recognized, he +would not object to any legislation "which may yet be consistent as a +temporary arrangement with their present condition as a laboring, +landless, and homeless class." + +=Andrew Johnson's Plan--His Impeachment.=--Lincoln's successor, Andrew +Johnson, the Vice President, soon after taking office, proposed to +pursue a somewhat similar course. In a number of states he appointed +military governors, instructing them at the earliest possible moment to +assemble conventions, chosen "by that portion of the people of the said +states who are loyal to the United States," and proceed to the +organization of regular civil government. Johnson, a Southern man and a +Democrat, was immediately charged by the Republicans with being too +ready to restore the Southern states. As the months went by, the +opposition to his measures and policies in Congress grew in size and +bitterness. The contest resulted in the impeachment of Johnson by the +House of Representatives in March, 1868, and his acquittal by the Senate +merely because his opponents lacked one vote of the two-thirds required +for conviction. + +=Congress Enacts "Reconstruction Laws."=--In fact, Congress was in a +strategic position. It was the law-making body, and it could, moreover, +determine the conditions under which Senators and Representatives from +the South were to be readmitted. It therefore proceeded to pass a series +of reconstruction acts--carrying all of them over Johnson's veto. These +measures, the first of which became a law on March 2, 1867, betrayed an +animus not found anywhere in Lincoln's plans or Johnson's proclamations. + +They laid off the ten states--the whole Confederacy with the exception +of Tennessee--still outside the pale, into five military districts, each +commanded by a military officer appointed by the President. They ordered +the commanding general to prepare a register of voters for the election +of delegates to conventions chosen for the purpose of drafting new +constitutions. Such voters, however, were not to be, as Lincoln had +suggested, loyal persons duly qualified under the law existing before +secession but "the male citizens of said state, twenty-one years old and +upward, of whatever race, color, or previous condition, ... except such +as may be disfranchised for participation in the rebellion or for felony +at common law." This was the death knell to the idea that the leaders of +the Confederacy and their white supporters might be permitted to share +in the establishment of the new order. Power was thus arbitrarily thrust +into the hands of the newly emancipated male negroes and the handful of +whites who could show a record of loyalty. That was not all. Each state +was, under the reconstruction acts, compelled to ratify the fourteenth +amendment to the federal Constitution as a price of restoration to the +union. + +The composition of the conventions thus authorized may be imagined. +Bondmen without the asking and without preparation found themselves the +governing power. An army of adventurers from the North, "carpet baggers" +as they were called, poured in upon the scene to aid in +"reconstruction." Undoubtedly many men of honor and fine intentions gave +unstinted service, but the results of their deliberations only +aggravated the open wound left by the war. Any number of political +doctors offered their prescriptions; but no effective remedy could be +found. Under measures admittedly open to grave objections, the Southern +states were one after another restored to the union by the grace of +Congress, the last one in 1870. Even this grudging concession of the +formalities of statehood did not mean a full restoration of honors and +privileges. The last soldier was not withdrawn from the last Southern +capital until 1877, and federal control over elections long remained as +a sign of congressional supremacy. + +=The Status of the Freedmen.=--Even more intricate than the issues +involved in restoring the seceded states to the union was the question +of what to do with the newly emancipated slaves. That problem, often put +to abolitionists before the war, had become at last a real concern. The +thirteenth amendment abolishing slavery had not touched it at all. It +declared bondmen free, but did nothing to provide them with work or +homes and did not mention the subject of political rights. All these +matters were left to the states, and the legislatures of some of them, +by their famous "black codes," restored a form of servitude under the +guise of vagrancy and apprentice laws. Such methods were in fact partly +responsible for the reaction that led Congress to abandon Lincoln's +policies and undertake its own program of reconstruction. + +Still no extensive effort was made to solve by law the economic problems +of the bondmen. Radical abolitionists had advocated that the slaves when +emancipated should be given outright the fields of their former +masters; but Congress steadily rejected the very idea of confiscation. +The necessity of immediate assistance it recognized by creating in 1865 +the Freedmen's Bureau to take care of refugees. It authorized the issue +of food and clothing to the destitute and the renting of abandoned and +certain other lands under federal control to former slaves at reasonable +rates. But the larger problem of the relation of the freedmen to the +land, it left to the slow working of time. + +Against sharp protests from conservative men, particularly among the +Democrats, Congress did insist, however, on conferring upon the freedmen +certain rights by national law. These rights fell into broad divisions, +civil and political. By an act passed in 1866, Congress gave to former +slaves the rights of white citizens in the matter of making contracts, +giving testimony in courts, and purchasing, selling, and leasing +property. As it was doubtful whether Congress had the power to enact +this law, there was passed and submitted to the states the fourteenth +amendment which gave citizenship to the freedmen, assured them of the +privileges and immunities of citizens of the United States, and declared +that no state should deprive any person of his life, liberty, or +property without due process of law. Not yet satisfied, Congress +attempted to give social equality to negroes by the second civil rights +bill of 1875 which promised to them, among other things, the full and +equal enjoyment of inns, theaters, public conveyances, and places of +amusement--a law later declared unconstitutional by the Supreme Court. + +The matter of political rights was even more hotly contested; but the +radical Republicans, like Charles Sumner, asserted that civil rights +were not secure unless supported by the suffrage. In this same +fourteenth amendment they attempted to guarantee the ballot to all negro +men, leaving the women to take care of themselves. The amendment +declared in effect that when any state deprived adult male citizens of +the right to vote, its representation in Congress should be reduced in +the proportion such persons bore to the voting population. + +This provision having failed to accomplish its purpose, the fifteenth +amendment was passed and ratified, expressly declaring that no citizen +should be deprived of the right to vote "on account of race, color, or +previous condition of servitude." To make assurance doubly secure, +Congress enacted in 1870, 1872, and 1873 three drastic laws, sometimes +known as "force bills," providing for the use of federal authorities, +civil and military, in supervising elections in all parts of the Union. +So the federal government, having destroyed chattel slavery, sought by +legal decree to sweep away all its signs and badges, civil, social, and +political. Never, save perhaps in some of the civil conflicts of Greece +or Rome, had there occurred in the affairs of a nation a social +revolution so complete, so drastic, and far-reaching in its results. + + +SUMMARY OF THE SECTIONAL CONFLICT + +Just as the United States, under the impetus of Western enterprise, +rounded out the continental domain, its very existence as a nation was +challenged by a fratricidal conflict between two sections. This storm +had been long gathering upon the horizon. From the very beginning in +colonial times there had been a marked difference between the South and +the North. The former by climate and soil was dedicated to a planting +system--the cultivation of tobacco, rice, cotton, and sugar cane--and in +the course of time slave labor became the foundation of the system. The +North, on the other hand, supplemented agriculture by commerce, trade, +and manufacturing. Slavery, though lawful, did not flourish there. An +abundant supply of free labor kept the Northern wheels turning. + +This difference between the two sections, early noted by close +observers, was increased with the advent of the steam engine and the +factory system. Between 1815 and 1860 an industrial revolution took +place in the North. Its signs were gigantic factories, huge aggregations +of industrial workers, immense cities, a flourishing commerce, and +prosperous banks. Finding an unfavorable reception in the South, the new +industrial system was confined mainly to the North. By canals and +railways New York, Boston, and Philadelphia were linked with the +wheatfields of Ohio, Indiana, and Illinois. A steel net wove North and +Northwest together. A commercial net supplemented it. Western trade was +diverted from New Orleans to the East and Eastern credit sustained +Western enterprise. + +In time, the industrial North and the planting South evolved different +ideas of political policy. The former looked with favor on protective +tariffs, ship subsidies, a sound national banking system, and internal +improvements. The farmers of the West demanded that the public domain be +divided up into free homesteads for farmers. The South steadily swung +around to the opposite view. Its spokesmen came to regard most of these +policies as injurious to the planting interests. + +The economic questions were all involved in a moral issue. The Northern +states, in which slavery was of slight consequence, had early abolished +the institution. In the course of a few years there appeared +uncompromising advocates of universal emancipation. Far and wide the +agitation spread. The South was thoroughly frightened. It demanded +protection against the agitators, the enforcement of its rights in the +case of runaway slaves, and equal privileges for slavery in the new +territories. + +With the passing years the conflict between the two sections increased +in bitterness. It flamed up in 1820 and was allayed by the Missouri +compromise. It took on the form of a tariff controversy and +nullification in 1832. It appeared again after the Mexican war when the +question of slavery in the new territories was raised. Again +compromise--the great settlement of 1850--seemed to restore peace, only +to prove an illusion. A series of startling events swept the country +into war: the repeal of the Missouri compromise in 1854, the rise of the +Republican party pledged to the prohibition of slavery in the +territories, the Dred Scott decision of 1857, the Lincoln-Douglas +debates, John Brown's raid, the election of Lincoln, and secession. + +The Civil War, lasting for four years, tested the strength of both North +and South, in leadership, in finance, in diplomatic skill, in material +resources, in industry, and in armed forces. By the blockade of Southern +ports, by an overwhelming weight of men and materials, and by relentless +hammering on the field of battle, the North was victorious. + +The results of the war were revolutionary in character. Slavery was +abolished and the freedmen given the ballot. The Southern planters who +had been the leaders of their section were ruined financially and almost +to a man excluded from taking part in political affairs. The union was +declared to be perpetual and the right of a state to secede settled by +the judgment of battle. Federal control over the affairs of states, +counties, and cities was established by the fourteenth amendment. The +power and prestige of the federal government were enhanced beyond +imagination. The North was now free to pursue its economic policies: a +protective tariff, a national banking system, land grants for railways, +free lands for farmers. Planting had dominated the country for nearly a +generation. Business enterprise was to take its place. + + +=References= + +NORTHERN ACCOUNTS + +J.K. Hosmer, _The Appeal to Arms_ and _The Outcome of the Civil War_ +(American Nation Series). + +J. Ropes, _History of the Civil War_ (best account of military +campaigns). + +J.F. Rhodes, _History of the United States_, Vols. III, IV, and V. + +J.T. Morse, _Abraham Lincoln_ (2 vols.). + + +SOUTHERN ACCOUNTS + +W.E. Dodd, _Jefferson Davis_. + +Jefferson Davis, _Rise and Fall of the Confederate Government_. + +E. Pollard, _The Lost Cause_. + +A.H. Stephens, _The War between the States_. + + +=Questions= + +1. Contrast the reception of secession in 1860 with that given to +nullification in 1832. + +2. Compare the Northern and Southern views of the union. + +3. What were the peculiar features of the Confederate constitution? + +4. How was the Confederacy financed? + +5. Compare the resources of the two sections. + +6. On what foundations did Southern hopes rest? + +7. Describe the attempts at a peaceful settlement. + +8. Compare the raising of armies for the Civil War with the methods +employed in the World War. (See below, chapter XXV.) + +9. Compare the financial methods of the government in the two wars. + +10. Explain why the blockade was such a deadly weapon. + +11. Give the leading diplomatic events of the war. + +12. Trace the growth of anti-slavery sentiment. + +13. What measures were taken to restrain criticism of the government? + +14. What part did Lincoln play in all phases of the war? + +15. State the principal results of the war. + +16. Compare Lincoln's plan of reconstruction with that adopted by +Congress. + +17. What rights did Congress attempt to confer upon the former slaves? + + +=Research Topics= + +=Was Secession Lawful?=--The Southern view by Jefferson Davis in +Harding, _Select Orations Illustrating American History_, pp. 364-369. +Lincoln's view, Harding, pp. 371-381. + +=The Confederate Constitution.=--Compare with the federal Constitution +in Macdonald, _Documentary Source Book_, pp. 424-433 and pp. 271-279. + +=Federal Legislative Measures.=--Prepare a table and brief digest of the +important laws relating to the war. Macdonald, pp. 433-482. + +=Economic Aspects of the War.=--Coman, _Industrial History of the United +States_, pp. 279-301. Dewey, _Financial History of the United States_, +Chaps. XII and XIII. Tabulate the economic measures of Congress in +Macdonald. + +=Military Campaigns.=--The great battles are fully treated in Rhodes, +_History of the Civil War_, and teachers desiring to emphasize military +affairs may assign campaigns to members of the class for study and +report. A briefer treatment in Elson, _History of the United States_, +pp. 641-785. + +=Biographical Studies.=--Lincoln, Davis, Lee, Grant, Sherman, and other +leaders in civil and military affairs, with reference to local "war +governors." + +=English and French Opinion of the War.=--Rhodes, _History of the United +States_, Vol. IV, pp. 337-394. + +=The South during the War.=--Rhodes, Vol. V, pp. 343-382. + +=The North during the War.=--Rhodes, Vol. V, pp. 189-342. + +=Reconstruction Measures.=--Macdonald, _Source Book_, pp. 500-511; +514-518; 529-530; Elson, pp. 786-799. + +=The Force Bills.=--Macdonald, pp. 547-551; 554-564. + + + + +PART VI. NATIONAL GROWTH AND WORLD POLITICS + + + + +CHAPTER XVI + +THE POLITICAL AND ECONOMIC EVOLUTION OF THE SOUTH + + +The outcome of the Civil War in the South was nothing short of a +revolution. The ruling class, the law, and the government of the old +order had been subverted. To political chaos was added the havoc wrought +in agriculture, business, and transportation by military operations. And +as if to fill the cup to the brim, the task of reconstruction was +committed to political leaders from another section of the country, +strangers to the life and traditions of the South. + + +THE SOUTH AT THE CLOSE OF THE WAR + +=A Ruling Class Disfranchised.=--As the sovereignty of the planters had +been the striking feature of the old regime, so their ruin was the +outstanding fact of the new. The situation was extraordinary. The +American Revolution was carried out by people experienced in the arts of +self-government, and at its close they were free to follow the general +course to which they had long been accustomed. The French Revolution +witnessed the overthrow of the clergy and the nobility; but middle +classes who took their places had been steadily rising in intelligence +and wealth. + +The Southern Revolution was unlike either of these cataclysms. It was +not brought about by a social upheaval, but by an external crisis. It +did not enfranchise a class that sought and understood power, but +bondmen who had played no part in the struggle. Moreover it struck down +a class equipped to rule. The leading planters were almost to a man +excluded from state and federal offices, and the fourteenth amendment +was a bar to their return. All civil and military places under the +authority of the United States and of the states were closed to every +man who had taken an oath to support the Constitution as a member of +Congress, as a state legislator, or as a state or federal officer, and +afterward engaged in "insurrection or rebellion," or "given aid and +comfort to the enemies" of the United States. This sweeping provision, +supplemented by the reconstruction acts, laid under the ban most of the +talent, energy, and spirit of the South. + +=The Condition of the State Governments.=--The legislative, executive, +and judicial branches of the state governments thus passed into the +control of former slaves, led principally by Northern adventurers or +Southern novices, known as "Scalawags." The result was a carnival of +waste, folly, and corruption. The "reconstruction" assembly of South +Carolina bought clocks at $480 apiece and chandeliers at $650. To +purchase land for former bondmen the sum of $800,000 was appropriated; +and swamps bought at seventy-five cents an acre were sold to the state +at five times the cost. In the years between 1868 and 1873, the debt of +the state rose from about $5,800,000 to $24,000,000, and millions of the +increase could not be accounted for by the authorities responsible for +it. + +=Economic Ruin--Urban and Rural.=--No matter where Southern men turned +in 1865 they found devastation--in the towns, in the country, and along +the highways. Atlanta, the city to which Sherman applied the torch, lay +in ashes; Nashville and Chattanooga had been partially wrecked; Richmond +and Augusta had suffered severely from fires. Charleston was described +by a visitor as "a city of ruins, of desolation, of vacant houses, of +rotten wharves, of deserted warehouses, of weed gardens, of miles of +grass-grown streets.... How few young men there are, how generally the +young women are dressed in black! The flower of their proud aristocracy +is buried on scores of battle fields." + +Those who journeyed through the country about the same time reported +desolation equally widespread and equally pathetic. An English traveler +who made his way along the course of the Tennessee River in 1870 wrote: +"The trail of war is visible throughout the valley in burnt-up gin +houses, ruined bridges, mills, and factories ... and large tracts of +once cultivated land are stripped of every vestige of fencing. The +roads, long neglected, are in disorder and, having in many places become +impassable, new tracks have been made through the woods and fields +without much respect to boundaries." Many a great plantation had been +confiscated by the federal authorities while the owner was in +Confederate service. Many more lay in waste. In the wake of the armies +the homes of rich and poor alike, if spared the torch, had been +despoiled of the stock and seeds necessary to renew agriculture. + +=Railways Dilapidated.=--Transportation was still more demoralized. This +is revealed in the pages of congressional reports based upon first-hand +investigations. One eloquent passage illustrates all the rest. From +Pocahontas to Decatur, Alabama, a distance of 114 miles, we are told, +the railroad was "almost entirely destroyed, except the road bed and +iron rails, and they were in a very bad condition--every bridge and +trestle destroyed, cross-ties rotten, buildings burned, water tanks +gone, tracks grown up in weeds and bushes, not a saw mill near the line +and the labor system of the country gone. About forty miles of the track +were burned, the cross-ties entirely destroyed, and the rails bent and +twisted in such a manner as to require great labor to straighten and a +large portion of them requiring renewal." + +=Capital and Credit Destroyed.=--The fluid capital of the South, money +and credit, was in the same prostrate condition as the material capital. +The Confederate currency, inflated to the bursting point, had utterly +collapsed and was as worthless as waste paper. The bonds of the +Confederate government were equally valueless. Specie had nearly +disappeared from circulation. The fourteenth amendment to the federal +Constitution had made all "debts, obligations, and claims" incurred in +aid of the Confederate cause "illegal and void." Millions of dollars +owed to Northern creditors before the war were overdue and payment was +pressed upon the debtors. Where such debts were secured by mortgages on +land, executions against the property could be obtained in federal +courts. + + +THE RESTORATION OF WHITE SUPREMACY + +=Intimidation.=--In both politics and economics, the process of +reconstruction in the South was slow and arduous. The first battle in +the political contest for white supremacy was won outside the halls of +legislatures and the courts of law. It was waged, in the main, by secret +organizations, among which the Ku Klux Klan and the White Camelia were +the most prominent. The first of these societies appeared in Tennessee +in 1866 and held its first national convention the following year. It +was in origin a social club. According to its announcement, its objects +were "to protect the weak, the innocent, and the defenceless from the +indignities, wrongs, and outrages of the lawless, the violent, and the +brutal; and to succor the suffering, especially the widows and orphans +of the Confederate soldiers." The whole South was called "the Empire" +and was ruled by a "Grand Wizard." Each state was a realm and each +county a province. In the secret orders there were enrolled over half a +million men. + +The methods of the Ku Klux and the White Camelia were similar. Solemn +parades of masked men on horses decked in long robes were held, +sometimes in the daytime and sometimes at the dead of night. Notices +were sent to obnoxious persons warning them to stop certain practices. +If warning failed, something more convincing was tried. Fright was the +emotion most commonly stirred. A horseman, at the witching hour of +midnight, would ride up to the house of some offender, lift his head +gear, take off a skull, and hand it to the trembling victim with the +request that he hold it for a few minutes. Frequently violence was +employed either officially or unofficially by members of the Klan. Tar +and feathers were freely applied; the whip was sometimes laid on +unmercifully, and occasionally a brutal murder was committed. Often the +members were fired upon from bushes or behind trees, and swift +retaliation followed. So alarming did the clashes become that in 1870 +Congress forbade interference with electors or going in disguise for the +purpose of obstructing the exercise of the rights enjoyed under federal +law. + +In anticipation of such a step on the part of the federal government, +the Ku Klux was officially dissolved by the "Grand Wizard" in 1869. +Nevertheless, the local societies continued their organization and +methods. The spirit survived the national association. "On the whole," +says a Southern writer, "it is not easy to see what other course was +open to the South.... Armed resistance was out of the question. And yet +there must be some control had of the situation.... If force was denied, +craft was inevitable." + +=The Struggle for the Ballot Box.=--The effects of intimidation were +soon seen at elections. The freedman, into whose inexperienced hand the +ballot had been thrust, was ordinarily loath to risk his head by the +exercise of his new rights. He had not attained them by a long and +laborious contest of his own and he saw no urgent reason why he should +battle for the privilege of using them. The mere show of force, the mere +existence of a threat, deterred thousands of ex-slaves from appearing at +the polls. Thus the whites steadily recovered their dominance. Nothing +could prevent it. Congress enacted force bills establishing federal +supervision of elections and the Northern politicians protested against +the return of former Confederates to practical, if not official, power; +but all such opposition was like resistance to the course of nature. + +=Amnesty for Southerners.=--The recovery of white supremacy in this way +was quickly felt in national councils. The Democratic party in the North +welcomed it as a sign of its return to power. The more moderate +Republicans, anxious to heal the breach in American unity, sought to +encourage rather than to repress it. So it came about that amnesty for +Confederates was widely advocated. Yet it must be said that the struggle +for the removal of disabilities was stubborn and bitter. Lincoln, with +characteristic generosity, in the midst of the war had issued a general +proclamation of amnesty to nearly all who had been in arms against the +Union, on condition that they take an oath of loyalty; but Johnson, +vindictive toward Southern leaders and determined to make "treason +infamous," had extended the list of exceptions. Congress, even more +relentless in its pursuit of Confederates, pushed through the fourteenth +amendment which worked the sweeping disabilities we have just described. + +To appeals for comprehensive clemency, Congress was at first adamant. In +vain did men like Carl Schurz exhort their colleagues to crown their +victory in battle with a noble act of universal pardon and oblivion. +Congress would not yield. It would grant amnesty in individual cases; +for the principle of proscription it stood fast. When finally in 1872, +seven years after the surrender at Appomattox, it did pass the general +amnesty bill, it insisted on certain exceptions. Confederates who had +been members of Congress just before the war, or had served in other +high posts, civil or military, under the federal government, were still +excluded from important offices. Not until the summer of 1898, when the +war with Spain produced once more a union of hearts, did Congress relent +and abolish the last of the disabilities imposed on the Confederates. + +=The Force Bills Attacked and Nullified.=--The granting of amnesty +encouraged the Democrats to redouble their efforts all along the line. +In 1874 they captured the House of Representatives and declared war on +the "force bills." As a Republican Senate blocked immediate repeal, they +resorted to an ingenious parliamentary trick. To the appropriation bill +for the support of the army they attached a "rider," or condition, to +the effect that no troops should be used to sustain the Republican +government in Louisiana. The Senate rejected the proposal. A deadlock +ensued and Congress adjourned without making provision for the army. +Satisfied with the technical victory, the Democrats let the army bill +pass the next session, but kept up their fight on the force laws until +they wrung from President Hayes a measure forbidding the use of United +States troops in supervising elections. The following year they again +had recourse to a rider on the army bill and carried it through, putting +an end to the use of money for military control of elections. The +reconstruction program was clearly going to pieces, and the Supreme +Court helped along the process of dissolution by declaring parts of the +laws invalid. In 1878 the Democrats even won a majority in the Senate +and returned to power a large number of men once prominent in the +Confederate cause. + +The passions of the war by this time were evidently cooling. A new +generation of men was coming on the scene. The supremacy of the whites +in the South, if not yet complete, was at least assured. Federal +marshals, their deputies, and supervisors of elections still possessed +authority over the polls, but their strength had been shorn by the +withdrawal of United States troops. The war on the remaining remnants of +the "force bills" lapsed into desultory skirmishing. When in 1894 the +last fragment was swept away, the country took little note of the fact. +The only task that lay before the Southern leaders was to write in the +constitutions of their respective states the provisions of law which +would clinch the gains so far secured and establish white supremacy +beyond the reach of outside intervention. + +=White Supremacy Sealed by New State Constitutions.=--The impetus to +this final step was given by the rise of the Populist movement in the +South, which sharply divided the whites and in many communities threw +the balance of power into the hands of the few colored voters who +survived the process of intimidation. Southern leaders now devised new +constitutions so constructed as to deprive negroes of the ballot by law. +Mississippi took the lead in 1890; South Carolina followed five years +later; Louisiana, in 1898; North Carolina, in 1900; Alabama and +Maryland, in 1901; and Virginia, in 1902. + +The authors of these measures made no attempt to conceal their purposes. +"The intelligent white men of the South," said Governor Tillman, "intend +to govern here." The fifteenth amendment to the federal Constitution, +however, forbade them to deprive any citizen of the right to vote on +account of race, color, or previous condition of servitude. This made +necessary the devices of indirection. They were few, simple, and +effective. The first and most easily administered was the ingenious +provision requiring each prospective voter to read a section of the +state constitution or "understand and explain it" when read to him by +the election officers. As an alternative, the payment of taxes or the +ownership of a small amount of property was accepted as a qualification +for voting. Southern leaders, unwilling to disfranchise any of the poor +white men who had stood side by side with them "in the dark days of +reconstruction," also resorted to a famous provision known as "the +grandfather clause." This plan admitted to the suffrage any man who did +not have either property or educational qualifications, provided he had +voted on or before 1867 or was the son or grandson of any such person. + +The devices worked effectively. Of the 147,000 negroes in Mississippi +above the age of twenty-one, only about 8600 registered under the +constitution of 1890. Louisiana had 127,000 colored voters enrolled in +1896; under the constitution drafted two years later the registration +fell to 5300. An analysis of the figures for South Carolina in 1900 +indicates that only about one negro out of every hundred adult males of +that race took part in elections. Thus was closed this chapter of +reconstruction. + +=The Supreme Court Refuses to Intervene.=--Numerous efforts were made to +prevail upon the Supreme Court of the United States to declare such laws +unconstitutional; but the Court, usually on technical grounds, avoided +coming to a direct decision on the merits of the matter. In one case +the Court remarked that it could not take charge of and operate the +election machinery of Alabama; it concluded that "relief from a great +political wrong, if done as alleged, by the people of a state and by the +state itself, must be given by them, or by the legislative and executive +departments of the government of the United States." Only one of the +several schemes employed, namely, the "grandfather clause," was held to +be a violation of the federal Constitution. This blow, effected in 1915 +by the decision in the Oklahoma and Maryland cases, left, however, the +main structure of disfranchisement unimpaired. + +=Proposals to Reduce Southern Representation in Congress.=--These +provisions excluding thousands of male citizens from the ballot did not, +in express terms, deprive any one of the vote on account of race or +color. They did not, therefore, run counter to the letter of the +fifteenth amendment; but they did unquestionably make the states which +adopted them liable to the operations of the fourteenth amendment. The +latter very explicitly provides that whenever any state deprives adult +male citizens of the right to vote (except in certain minor cases) the +representation of the state in Congress shall be reduced in the +proportion which such number of disfranchised citizens bears to the +whole number of male citizens over twenty-one years of age. + +Mindful of this provision, those who protested against disfranchisement +in the South turned to the Republican party for relief, asking for +action by the political branches of the federal government as the +Supreme Court had suggested. The Republicans responded in their platform +of 1908 by condemning all devices designed to deprive any one of the +ballot for reasons of color alone; they demanded the enforcement in +letter and spirit of the fourteenth as well as all other amendments. +Though victorious in the election, the Republicans refrained from +reopening the ancient contest; they made no attempt to reduce Southern +representation in the House. Southern leaders, while protesting against +the declarations of their opponents, were able to view them as idle +threats in no way endangering the security of the measures by which +political reconstruction had been undone. + +=The Solid South.=--Out of the thirty-year conflict against "carpet-bag +rule" there emerged what was long known as the "solid South"--a South +that, except occasionally in the border states, never gave an electoral +vote to a Republican candidate for President. Before the Civil War, the +Southern people had been divided on political questions. Take, for +example, the election of 1860. In all the fifteen slave states the +variety of opinion was marked. In nine of them--Delaware, Virginia, +Tennessee, Missouri, Maryland, Louisiana, Kentucky, Georgia, and +Arkansas--the combined vote against the representative of the extreme +Southern point of view, Breckinridge, constituted a safe majority. In +each of the six states which were carried by Breckinridge, there was a +large and powerful minority. In North Carolina Breckinridge's majority +over Bell and Douglas was only 849 votes. Equally astounding to those +who imagine the South united in defense of extreme views in 1860 was the +vote for Bell, the Unionist candidate, who stood firmly for the +Constitution and silence on slavery. In every Southern state Bell's vote +was large. In Virginia, Kentucky, Missouri, and Tennessee it was greater +than that received by Breckinridge; in Georgia, it was 42,000 against +51,000; in Louisiana, 20,000 against 22,000; in Mississippi, 25,000 +against 40,000. + +The effect of the Civil War upon these divisions was immediate and +decisive, save in the border states where thousands of men continued to +adhere to the cause of Union. In the Confederacy itself nearly all +dissent was silenced by war. Men who had been bitter opponents joined +hands in defense of their homes; when the armed conflict was over they +remained side by side working against "Republican misrule and negro +domination." By 1890, after Northern supremacy was definitely broken, +they boasted that there were at least twelve Southern states in which no +Republican candidate for President could win a single electoral vote. + +=Dissent in the Solid South.=--Though every one grew accustomed to speak +of the South as "solid," it did not escape close observers that in a +number of Southern states there appeared from time to time a fairly +large body of dissenters. In 1892 the Populists made heavy inroads upon +the Democratic ranks. On other occasions, the contests between factions +within the Democratic party over the nomination of candidates revealed +sharp differences of opinion. In some places, moreover, there grew up a +Republican minority of respectable size. For example, in Georgia, Mr. +Taft in 1908 polled 41,000 votes against 72,000 for Mr. Bryan; in North +Carolina, 114,000 against 136,000; in Tennessee, 118,000 against +135,000; in Kentucky, 235,000 against 244,000. In 1920, Senator Harding, +the Republican candidate, broke the record by carrying Tennessee as well +as Kentucky, Oklahoma, and Maryland. + + +THE ECONOMIC ADVANCE OF THE SOUTH + +=The Break-up of the Great Estates.=--In the dissolution of chattel +slavery it was inevitable that the great estate should give way before +the small farm. The plantation was in fact founded on slavery. It was +continued and expanded by slavery. Before the war the prosperous +planter, either by inclination or necessity, invested his surplus in +more land to add to his original domain. As his slaves increased in +number, he was forced to increase his acreage or sell them, and he +usually preferred the former, especially in the Far South. Still another +element favored the large estate. Slave labor quickly exhausted the soil +and of its own force compelled the cutting of the forests and the +extension of the area under cultivation. Finally, the planter took a +natural pride in his great estate; it was a sign of his prowess and his +social prestige. + +In 1865 the foundations of the planting system were gone. It was +difficult to get efficient labor to till the vast plantations. The +planters themselves were burdened with debts and handicapped by lack of +capital. Negroes commonly preferred tilling plots of their own, rented +or bought under mortgage, to the more irksome wage labor under white +supervision. The land hunger of the white farmer, once checked by the +planting system, reasserted itself. Before these forces the plantation +broke up. The small farm became the unit of cultivation in the South as +in the North. Between 1870 and 1900 the number of farms doubled in every +state south of the line of the Potomac and Ohio rivers, except in +Arkansas and Louisiana. From year to year the process of breaking up +continued, with all that it implied in the creation of land-owning +farmers. + +=The Diversification of Crops.=--No less significant was the concurrent +diversification of crops. Under slavery, tobacco, rice, and sugar were +staples and "cotton was king." These were standard crops. The methods of +cultivation were simple and easily learned. They tested neither the +skill nor the ingenuity of the slaves. As the returns were quick, they +did not call for long-time investments of capital. After slavery was +abolished, they still remained the staples, but far-sighted +agriculturists saw the dangers of depending upon a few crops. The mild +climate all the way around the coast from Virginia to Texas and the +character of the alluvial soil invited the exercise of more imagination. +Peaches, oranges, peanuts, and other fruits and vegetables were found to +grow luxuriantly. Refrigeration for steamships and freight cars put the +markets of great cities at the doors of Southern fruit and vegetable +gardeners. The South, which in planting days had relied so heavily upon +the Northwest for its foodstuffs, began to battle for independence. +Between 1880 and the close of the century the value of its farm crops +increased from $660,000,000 to $1,270,000,000. + +=The Industrial and Commercial Revolution.=--On top of the radical +changes in agriculture came an industrial and commercial revolution. The +South had long been rich in natural resources, but the slave system had +been unfavorable to their development. Rivers that would have turned +millions of spindles tumbled unheeded to the seas. Coal and iron beds +lay unopened. Timber was largely sacrificed in clearing lands for +planting, or fell to earth in decay. Southern enterprise was consumed in +planting. Slavery kept out the white immigrants who might have supplied +the skilled labor for industry. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +STEEL MILLS--BIRMINGHAM, ALABAMA] + +After 1865, achievement and fortune no longer lay on the land alone. As +soon as the paralysis of the war was over, the South caught the +industrial spirit that had conquered feudal Europe and the agricultural +North. In the development of mineral wealth, enormous strides were +taken. Iron ore of every quality was found, the chief beds being in +Virginia, West Virginia, Tennessee, Kentucky, North Carolina, Georgia, +Alabama, Arkansas, and Texas. Five important coal basins were uncovered: +in Virginia, North Carolina, the Appalachian chain from Maryland to +Northern Alabama, Kentucky, Arkansas, and Texas. Oil pools were found +in Kentucky, Tennessee, and Texas. Within two decades, 1880 to 1900, the +output of mineral wealth multiplied tenfold: from ten millions a year to +one hundred millions. The iron industries of West Virginia and Alabama +began to rival those of Pennsylvania. Birmingham became the Pittsburgh +and Atlanta the Chicago of the South. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +A SOUTHERN COTTON MILL IN A COTTON FIELD] + +In other lines of industry, lumbering and cotton manufacturing took a +high rank. The development of Southern timber resources was in every +respect remarkable, particularly in Louisiana, Arkansas, and +Mississippi. At the end of the first decade of the twentieth century, +primacy in lumber had passed from the Great Lakes region to the South. +In 1913 eight Southern states produced nearly four times as much lumber +as the Lake states and twice as much as the vast forests of Washington +and Oregon. + +The development of the cotton industry, in the meantime, was similarly +astounding. In 1865 cotton spinning was a negligible matter in the +Southern states. In 1880 they had one-fourth of the mills of the +country. At the end of the century they had one-half the mills, the two +Carolinas taking the lead by consuming more than one-third of their +entire cotton crop. Having both the raw materials and the power at hand, +they enjoyed many advantages over the New England rivals, and at the +opening of the new century were outstripping the latter in the +proportion of spindles annually put into operation. Moreover, the cotton +planters, finding a market at the neighboring mills, began to look +forward to a day when they would be somewhat emancipated from absolute +dependence upon the cotton exchanges of New York, New Orleans, and +Liverpool. + +Transportation kept pace with industry. In 1860, the South had about ten +thousand miles of railway. By 1880 the figure had doubled. During the +next twenty years over thirty thousand miles were added, most of the +increase being in Texas. About 1898 there opened a period of +consolidation in which scores of short lines were united, mainly under +the leadership of Northern capitalists, and new through service opened +to the North and West. Thus Southern industries were given easy outlets +to the markets of the nation and brought within the main currents of +national business enterprise. + +=The Social Effects of the Economic Changes.=--As long as the slave +system lasted and planting was the major interest, the South was bound +to be sectional in character. With slavery gone, crops diversified, +natural resources developed, and industries promoted, the social order +of the ante-bellum days inevitably dissolved; the South became more and +more assimilated to the system of the North. In this process several +lines of development are evident. + +In the first place we see the steady rise of the small farmer. Even in +the old days there had been a large class of white yeomen who owned no +slaves and tilled the soil with their own hands, but they labored under +severe handicaps. They found the fertile lands of the coast and river +valleys nearly all monopolized by planters, and they were by the force +of circumstances driven into the uplands where the soil was thin and the +crops were light. Still they increased in numbers and zealously worked +their freeholds. + +The war proved to be their opportunity. With the break-up of the +plantations, they managed to buy land more worthy of their plows. By +intelligent labor and intensive cultivation they were able to restore +much of the worn-out soil to its original fertility. In the meantime +they rose with their prosperity in the social and political scale. It +became common for the sons of white farmers to enter the professions, +while their daughters went away to college and prepared for teaching. +Thus a more democratic tone was given to the white society of the South. +Moreover the migration to the North and West, which had formerly carried +thousands of energetic sons and daughters to search for new homesteads, +was materially reduced. The energy of the agricultural population went +into rehabilitation. + +The increase in the number of independent farmers was accompanied by the +rise of small towns and villages which gave diversity to the life of the +South. Before 1860 it was possible to travel through endless stretches +of cotton and tobacco. The social affairs of the planter's family +centered in the homestead even if they were occasionally interrupted by +trips to distant cities or abroad. Carpentry, bricklaying, and +blacksmithing were usually done by slaves skilled in simple handicrafts. +Supplies were bought wholesale. In this way there was little place in +plantation economy for villages and towns with their stores and +mechanics. + +The abolition of slavery altered this. Small farms spread out where +plantations had once stood. The skilled freedmen turned to agriculture +rather than to handicrafts; white men of a business or mechanical bent +found an opportunity to serve the needs of their communities. So local +merchants and mechanics became an important element in the social +system. In the county seats, once dominated by the planters, business +and professional men assumed the leadership. + +Another vital outcome of this revolution was the transference of a large +part of planting enterprise to business. Mr. Bruce, a Southern historian +of fine scholarship, has summed up this process in a single telling +paragraph: "The higher planting class that under the old system gave so +much distinction to rural life has, so far as it has survived at all, +been concentrated in the cities. The families that in the time of +slavery would have been found only in the country are now found, with a +few exceptions, in the towns. The transplantation has been practically +universal. The talent, the energy, the ambition that formerly sought +expression in the management of great estates and the control of hosts +of slaves, now seek a field of action in trade, in manufacturing +enterprises, or in the general enterprises of development. This was for +the ruling class of the South the natural outcome of the great economic +revolution that followed the war." + +As in all other parts of the world, the mechanical revolution was +attended by the growth of a population of industrial workers dependent +not upon the soil but upon wages for their livelihood. When Jefferson +Davis was inaugurated President of the Southern Confederacy, there were +approximately only one hundred thousand persons employed in Southern +manufactures as against more than a million in Northern mills. Fifty +years later, Georgia and Alabama alone had more than one hundred and +fifty thousand wage-earners. Necessarily this meant also a material +increase in urban population, although the wide dispersion of cotton +spinning among small centers prevented the congestion that had +accompanied the rise of the textile industry in New England. In 1910, +New Orleans, Atlanta, Memphis, Nashville, and Houston stood in the same +relation to the New South that Cincinnati, Chicago, Cleveland, and +Detroit had stood to the New West fifty years before. The problems of +labor and capital and municipal administration, which the earlier +writers boasted would never perplex the planting South, had come in full +force. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +A GLIMPSE OF MEMPHIS, TENNESSEE] + +=The Revolution in the Status of the Slaves.=--No part of Southern +society was so profoundly affected by the Civil War and economic +reconstruction as the former slaves. On the day of emancipation, they +stood free, but empty-handed, the owners of no tools or property, the +masters of no trade and wholly inexperienced in the arts of self-help +that characterized the whites in general. They had never been accustomed +to looking out for themselves. The plantation bell had called them to +labor and released them. Doles of food and clothing had been regularly +made in given quantities. They did not understand wages, ownership, +renting, contracts, mortgages, leases, bills, or accounts. + +When they were emancipated, four courses were open to them. They could +flee from the plantation to the nearest town or city, or to the distant +North, to seek a livelihood. Thousands of them chose this way, +overcrowding cities where disease mowed them down. They could remain +where they, were in their cabins and work for daily wages instead of +food, clothing, and shelter. This second course the major portion of +them chose; but, as few masters had cash to dispense, the new relation +was much like the old, in fact. It was still one of barter. The planter +offered food, clothing, and shelter; the former slaves gave their labor +in return. That was the best that many of them could do. + +A third course open to freedmen was that of renting from the former +master, paying him usually with a share of the produce of the land. This +way a large number of them chose. It offered them a chance to become +land owners in time and it afforded an easier life, the renter being, to +a certain extent at least, master of his own hours of labor. The final +and most difficult path was that to ownership of land. Many a master +helped his former slaves to acquire small holdings by offering easy +terms. The more enterprising and the more fortunate who started life as +renters or wage-earners made their way upward to ownership in so many +cases that by the end of the century, one-fourth of the colored laborers +on the land owned the soil they tilled. + +In the meantime, the South, though relatively poor, made relatively +large expenditures for the education of the colored population. By the +opening of the twentieth century, facilities were provided for more than +one-half of the colored children of school age. While in many respects +this progress was disappointing, its significance, to be appreciated, +must be derived from a comparison with the total illiteracy which +prevailed under slavery. + +In spite of all that happened, however, the status of the negroes in the +South continued to give a peculiar character to that section of the +country. They were almost entirely excluded from the exercise of the +suffrage, especially in the Far South. Special rooms were set aside for +them at the railway stations and special cars on the railway lines. In +the field of industry calling for technical skill, it appears, from the +census figures, that they lost ground between 1890 and 1900--a condition +which their friends ascribed to discriminations against them in law and +in labor organizations and their critics ascribed to their lack of +aptitude. Whatever may be the truth, the fact remained that at the +opening of the twentieth century neither the hopes of the emancipators +nor the fears of their opponents were realized. The marks of the +"peculiar institution" were still largely impressed upon Southern +society. + +The situation, however, was by no means unchanging. On the contrary +there was a decided drift in affairs. For one thing, the proportion of +negroes in the South had slowly declined. By 1900 they were in a +majority in only two states, South Carolina and Mississippi. In +Arkansas, Virginia, West Virginia, and North Carolina the proportion of +the white population was steadily growing. The colored migration +northward increased while the westward movement of white farmers which +characterized pioneer days declined. At the same time a part of the +foreign immigration into the United States was diverted southward. As +the years passed these tendencies gained momentum. The already huge +colored quarters in some Northern cities were widely expanded, as whole +counties in the South were stripped of their colored laborers. The race +question, in its political and economic aspects, became less and less +sectional, more and more national. The South was drawn into the main +stream of national life. The separatist forces which produced the +cataclysm of 1861 sank irresistibly into the background. + + +=References= + +H.W. Grady, _The New South_ (1890). + +H.A. Herbert, _Why the Solid South_. + +W.G. Brown, _The Lower South_. + +E.G. Murphy, _Problems of the Present South_. + +B.T. Washington, _The Negro Problem_; _The Story of the Negro_; _The +Future of the Negro_. + +A.B. Hart, _The Southern South_ and R.S. Baker, _Following the Color +Line_ (two works by Northern writers). + +T.N. Page, _The Negro, the Southerner's Problem_. + + +=Questions= + +1. Give the three main subdivisions of the chapter. + +2. Compare the condition of the South in 1865 with that of the North. +Compare with the condition of the United States at the close of the +Revolutionary War. At the close of the World War in 1918. + +3. Contrast the enfranchisement of the slaves with the enfranchisement +of white men fifty years earlier. + +4. What was the condition of the planters as compared with that of the +Northern manufacturers? + +5. How does money capital contribute to prosperity? Describe the plight +of Southern finance. + +6. Give the chief steps in the restoration of white supremacy. + +7. Do you know of any other societies to compare with the Ku Klux Klan? + +8. Give Lincoln's plan for amnesty. What principles do you think should +govern the granting of amnesty? + +9. How were the "Force bills" overcome? + +10. Compare the fourteenth and fifteenth amendments with regard to the +suffrage provisions. + +11. Explain how they may be circumvented. + +12. Account for the Solid South. What was the situation before 1860? + +13. In what ways did Southern agriculture tend to become like that of +the North? What were the social results? + +14. Name the chief results of an "industrial revolution" in general. In +the South, in particular. + +15. What courses were open to freedmen in 1865? + +16. Give the main features in the economic and social status of the +colored population in the South. + +17. Explain why the race question is national now, rather than +sectional. + + + +=Research Topics= + +=Amnesty for Confederates.=--Study carefully the provisions of the +fourteenth amendment in the Appendix. Macdonald, _Documentary Source +Book of American History_, pp. 470 and 564. A plea for amnesty in +Harding, _Select Orations Illustrating American History_, pp. 467-488. + +=Political Conditions in the South in 1868.=--Dunning, _Reconstruction, +Political and Economic_ (American Nation Series), pp. 109-123; Hart, +_American History Told by Contemporaries_, Vol. IV, pp. 445-458, +497-500; Elson, _History of the United States_, pp. 799-805. + +=Movement for White Supremacy.=--Dunning, _Reconstruction_, pp. 266-280; +Paxson, _The New Nation_ (Riverside Series), pp. 39-58; Beard, _American +Government and Politics_, pp. 454-457. + +=The Withdrawal of Federal Troops from the South.=--Sparks, _National +Development_ (American Nation Series), pp. 84-102; Rhodes, _History of +the United States_, Vol. VIII, pp. 1-12. + +=Southern Industry.=--Paxson, _The New Nation_, pp. 192-207; T.M. Young, +_The American Cotton Industry_, pp. 54-99. + +=The Race Question.=--B.T. Washington, _Up From Slavery_ (sympathetic +presentation); A.H. Stone, _Studies in the American Race Problem_ +(coldly analytical); Hart, _Contemporaries_, Vol. IV, pp. 647-649, +652-654, 663-669. + + + + +CHAPTER XVII + +BUSINESS ENTERPRISE AND THE REPUBLICAN PARTY + + +If a single phrase be chosen to characterize American life during the +generation that followed the age of Douglas and Lincoln, it must be +"business enterprise"--the tremendous, irresistible energy of a virile +people, mounting in numbers toward a hundred million and applied without +let or hindrance to the developing of natural resources of unparalleled +richness. The chief goal of this effort was high profits for the +captains of industry, on the one hand; and high wages for the workers, +on the other. Its signs, to use the language of a Republican orator in +1876, were golden harvest fields, whirling spindles, turning wheels, +open furnace doors, flaming forges, and chimneys filled with eager fire. +The device blazoned on its shield and written over its factory doors was +"prosperity." A Republican President was its "advance agent." Released +from the hampering interference of the Southern planters and the +confusing issues of the slavery controversy, business enterprise sprang +forward to the task of winning the entire country. Then it flung its +outposts to the uttermost parts of the earth--Europe, Africa, and the +Orient--where were to be found markets for American goods and natural +resources for American capital to develop. + + +RAILWAYS AND INDUSTRY + +=The Outward Signs of Enterprise.=--It is difficult to comprehend all +the multitudinous activities of American business energy or to appraise +its effects upon the life and destiny of the American people; for beyond +the horizon of the twentieth century lie consequences as yet undreamed +of in our poor philosophy. Statisticians attempt to record its +achievements in terms of miles of railways built, factories opened, men +and women employed, fortunes made, wages paid, cities founded, rivers +spanned, boxes, bales, and tons produced. Historians apply standards of +comparison with the past. Against the slow and leisurely stagecoach, +they set the swift express, rushing from New York to San Francisco in +less time than Washington consumed in his triumphal tour from Mt. Vernon +to New York for his first inaugural. Against the lazy sailing vessel +drifting before a genial breeze, they place the turbine steamer crossing +the Atlantic in five days or the still swifter airplane, in fifteen +hours. For the old workshop where a master and a dozen workmen and +apprentices wrought by hand, they offer the giant factory where ten +thousand persons attend the whirling wheels driven by steam. They write +of the "romance of invention" and the "captains of industry." + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +A CORNER IN THE BETHLEHEM STEEL WORKS] + +=The Service of the Railway.=--All this is fitting in its way. Figures +and contrasts cannot, however, tell the whole story. Take, for example, +the extension of railways. It is easy to relate that there were 30,000 +miles in 1860; 166,000 in 1890; and 242,000 in 1910. It is easy to show +upon the map how a few straggling lines became a perfect mesh of closely +knitted railways; or how, like the tentacles of a great monster, the few +roads ending in the Mississippi Valley in 1860 were extended and +multiplied until they tapped every wheat field, mine, and forest beyond +the valley. All this, eloquent of enterprise as it truly is, does not +reveal the significance of railways for American life. It does not +indicate how railways made a continental market for American goods; nor +how they standardized the whole country, giving to cities on the +advancing frontier the leading features of cities in the old East; nor +how they carried to the pioneer the comforts of civilization; nor yet +how in the West they were the forerunners of civilization, the makers of +homesteads, the builders of states. + +=Government Aid for Railways.=--Still the story is not ended. The +significant relation between railways and politics must not be +overlooked. The bounty of a lavish government, for example, made +possible the work of railway promoters. By the year 1872 the Federal +government had granted in aid of railways 155,000,000 acres of land--an +area estimated as almost equal to Pennsylvania, New York, Connecticut, +Rhode Island, Massachusetts, Maine, New Hampshire, and Vermont. The +Union Pacific Company alone secured from the federal government a free +right of way through the public domain, twenty sections of land with +each mile of railway, and a loan up to fifty millions of dollars secured +by a second mortgage on the company's property. More than half of the +northern tier of states lying against Canada from Lake Michigan to the +Pacific was granted to private companies in aid of railways and wagon +roads. About half of New Mexico, Arizona, and California was also given +outright to railway companies. These vast grants from the federal +government were supplemented by gifts from the states in land and by +subscriptions amounting to more than two hundred million dollars. The +history of these gifts and their relation to the political leaders that +engineered them would alone fill a large and interesting volume. + +=Railway Fortunes and Capital.=--Out of this gigantic railway promotion, +the first really immense American fortunes were made. Henry Adams, the +grandson of John Quincy Adams, related that his grandfather on his +mother's side, Peter Brooks, on his death in 1849, left a fortune of two +million dollars, "supposed to be the largest estate in Boston," then one +of the few centers of great riches. Compared with the opulence that +sprang out of the Union Pacific, the Northern Pacific, the Southern +Pacific, with their subsidiary and component lines, the estate of Peter +Brooks was a poor man's heritage. + +The capital invested in these railways was enormous beyond the +imagination of the men of the stagecoach generation. The total debt of +the United States incurred in the Revolutionary War--a debt which those +of little faith thought the country could never pay--was reckoned at a +figure well under $75,000,000. When the Union Pacific Railroad was +completed, there were outstanding against it $27,000,000 in first +mortgage bonds, $27,000,000 in second mortgage bonds held by the +government, $10,000,000 in income bonds, $10,000,000 in land grant +bonds, and, on top of that huge bonded indebtedness, $36,000,000 in +stock--making $110,000,000 in all. If the amount due the United States +government be subtracted, still there remained, in private hands, stocks +and bonds exceeding in value the whole national debt of Hamilton's +day--a debt that strained all the resources of the Federal government in +1790. Such was the financial significance of the railways. + +[Illustration: RAILROADS OF THE UNITED STATES IN 1918] + +=Growth and Extension of Industry.=--In the field of manufacturing, +mining, and metal working, the results of business enterprise far +outstripped, if measured in mere dollars, the results of railway +construction. By the end of the century there were about ten billion +dollars invested in factories alone and five million wage-earners +employed in them; while the total value of the output, fourteen billion +dollars, was fifteen times the figure for 1860. In the Eastern states +industries multiplied. In the Northwest territory, the old home of +Jacksonian Democracy, they overtopped agriculture. By the end of the +century, Ohio had almost reached and Illinois had surpassed +Massachusetts in the annual value of manufacturing output. + +That was not all. Untold wealth in the form of natural resources was +discovered in the South and West. Coal deposits were found in the +Appalachians stretching from Pennsylvania down to Alabama, in Michigan, +in the Mississippi Valley, and in the Western mountains from North +Dakota to New Mexico. In nearly every coal-bearing region, iron was also +discovered and the great fields of Michigan, Wisconsin, and Minnesota +soon rivaled those of the Appalachian area. Copper, lead, gold, and +silver in fabulous quantities were unearthed by the restless prospectors +who left no plain or mountain fastness unexplored. Petroleum, first +pumped from the wells of Pennsylvania in the summer of 1859, made new +fortunes equaling those of trade, railways, and land speculation. It +scattered its riches with an especially lavish hand through Oklahoma, +Texas, and California. + +=The Trust--an Instrument of Industrial Progress.=--Business enterprise, +under the direction of powerful men working single-handed, or of small +groups of men pooling their capital for one or more undertakings, had +not advanced far before there appeared upon the scene still mightier +leaders of even greater imagination. New constructive genius now brought +together and combined under one management hundreds of concerns or +thousands of miles of railways, revealing the magic strength of +cooperation on a national scale. Price-cutting in oil, threatening ruin +to those engaged in the industry, as early as 1879, led a number of +companies in Cleveland, Pittsburgh, and Philadelphia to unite in +price-fixing. Three years later a group of oil interests formed a close +organization, placing all their stocks in the hands of trustees, among +whom was John D. Rockefeller. The trustees, in turn, issued +certificates representing the share to which each participant was +entitled; and took over the management of the entire business. Such was +the nature of the "trust," which was to play such an unique role in the +progress of America. + +The idea of combination was applied in time to iron and steel, copper, +lead, sugar, cordage, coal, and other commodities, until in each field +there loomed a giant trust or corporation, controlling, if not most of +the output, at least enough to determine in a large measure the prices +charged to consumers. With the passing years, the railways, mills, +mines, and other business concerns were transferred from individual +owners to corporations. At the end of the nineteenth century, the whole +face of American business was changed. Three-fourths of the output from +industries came from factories under corporate management and only +one-fourth from individual and partnership undertakings. + +[Illustration: JOHN D. ROCKEFELLER] + +=The Banking Corporation.=--Very closely related to the growth of +business enterprise on a large scale was the system of banking. In the +old days before banks, a person with savings either employed them in his +own undertakings, lent them to a neighbor, or hid them away where they +set no industry in motion. Even in the early stages of modern business, +it was common for a manufacturer to rise from small beginnings by +financing extensions out of his own earnings and profits. This state of +affairs was profoundly altered by the growth of the huge corporations +requiring millions and even billions of capital. The banks, once an +adjunct to business, became the leaders in business. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +WALL STREET, NEW YORK CITY] + +It was the banks that undertook to sell the stocks and bonds issued by +new corporations and trusts and to supply them with credit to carry on +their operations. Indeed, many of the great mergers or combinations in +business were initiated by magnates in the banking world with millions +and billions under their control. Through their connections with one +another, the banks formed a perfect network of agencies gathering up the +pennies and dollars of the masses as well as the thousands of the rich +and pouring them all into the channels of business and manufacturing. +In this growth of banking on a national scale, it was inevitable that a +few great centers, like Wall Street in New York or State Street in +Boston, should rise to a position of dominance both in concentrating the +savings and profits of the nation and in financing new as well as old +corporations. + +=The Significance of the Corporation.=--The corporation, in fact, became +the striking feature of American business life, one of the most +marvelous institutions of all time, comparable in wealth and power and +the number of its servants with kingdoms and states of old. The effect +of its rise and growth cannot be summarily estimated; but some special +facts are obvious. It made possible gigantic enterprises once entirely +beyond the reach of any individual, no matter how rich. It eliminated +many of the futile and costly wastes of competition in connection with +manufacture, advertising, and selling. It studied the cheapest methods +of production and shut down mills that were poorly equipped or +disadvantageously located. It established laboratories for research in +industry, chemistry, and mechanical inventions. Through the sale of +stocks and bonds, it enabled tens of thousands of people to become +capitalists, if only in a small way. The corporation made it possible +for one person to own, for instance, a $50 share in a million dollar +business concern--a thing entirely impossible under a regime of +individual owners and partnerships. + +There was, of course, another side to the picture. Many of the +corporations sought to become monopolies and to make profits, not by +economies and good management, but by extortion from purchasers. +Sometimes they mercilessly crushed small business men, their +competitors, bribed members of legislatures to secure favorable laws, +and contributed to the campaign funds of both leading parties. Wherever +a trust approached the position of a monopoly, it acquired a dominion +over the labor market which enabled it to break even the strongest trade +unions. In short, the power of the trust in finance, in manufacturing, +in politics, and in the field of labor control can hardly be measured. + +=The Corporation and Labor.=--In the development of the corporation +there was to be observed a distinct severing of the old ties between +master and workmen, which existed in the days of small industries. For +the personal bond between the owner and the employees was substituted a +new relation. "In most parts of our country," as President Wilson once +said, "men work, not for themselves, not as partners in the old way in +which they used to work, but generally as employees--in a higher or +lower grade--of great corporations." The owner disappeared from the +factory and in his place came the manager, representing the usually +invisible stockholders and dependent for his success upon his ability to +make profits for the owners. Hence the term "soulless corporation," +which was to exert such a deep influence on American thinking about +industrial relations. + +=Cities and Immigration.=--Expressed in terms of human life, this era of +unprecedented enterprise meant huge industrial cities and an immense +labor supply, derived mainly from European immigration. Here, too, +figures tell only a part of the story. In Washington's day nine-tenths +of the American people were engaged in agriculture and lived in the +country; in 1890 more than one-third of the population dwelt in towns of +2500 and over; in 1920 more than half of the population lived in towns +of over 2500. In forty years, between 1860 and 1900, Greater New York +had grown from 1,174,000 to 3,437,000; San Francisco from 56,000 to +342,000; Chicago from 109,000 to 1,698,000. The miles of city tenements +began to rival, in the number of their residents, the farm homesteads of +the West. The time so dreaded by Jefferson had arrived. People were +"piled upon one another in great cities" and the republic of small +farmers had passed away. + +To these industrial centers flowed annually an ever-increasing tide of +immigration, reaching the half million point in 1880; rising to +three-quarters of a million three years later; and passing the million +mark in a single year at the opening of the new century. Immigration was +as old as America but new elements now entered the situation. In the +first place, there were radical changes in the nationality of the +newcomers. The migration from Northern Europe--England, Ireland, +Germany, and Scandinavia--diminished; that from Italy, Russia, and +Austria-Hungary increased, more than three-fourths of the entire number +coming from these three lands between the years 1900 and 1910. These +later immigrants were Italians, Poles, Magyars, Czechs, Slovaks, +Russians, and Jews, who came from countries far removed from the +language and the traditions of England whence came the founders of +America. + +In the second place, the reception accorded the newcomers differed from +that given to the immigrants in the early days. By 1890 all the free +land was gone. They could not, therefore, be dispersed widely among the +native Americans to assimilate quickly and unconsciously the habits and +ideas of American life. On the contrary, they were diverted mainly to +the industrial centers. There they crowded--nay, overcrowded--into +colonies of their own where they preserved their languages, their +newspapers, and their old-world customs and views. + +So eager were American business men to get an enormous labor supply that +they asked few questions about the effect of this "alien invasion" upon +the old America inherited from the fathers. They even stimulated the +invasion artificially by importing huge armies of foreigners under +contract to work in specified mines and mills. There seemed to be no +limit to the factories, forges, refineries, and railways that could be +built, to the multitudes that could be employed in conquering a +continent. As for the future, that was in the hands of Providence! + +=Business Theories of Politics.=--As the statesmen of Hamilton's school +and the planters of Calhoun's had their theories of government and +politics, so the leaders in business enterprise had theirs. It was +simple and easily stated. "It is the duty of the government," they +urged, "to protect American industry against foreign competition by +means of high tariffs on imported goods, to aid railways by generous +grants of land, to sell mineral and timber lands at low prices to +energetic men ready to develop them, and then to leave the rest to the +initiative and drive of individuals and companies." All government +interference with the management, prices, rates, charges, and conduct of +private business they held to be either wholly pernicious or intolerably +impertinent. Judging from their speeches and writings, they conceived +the nation as a great collection of individuals, companies, and labor +unions all struggling for profits or high wages and held together by a +government whose principal duty was to keep the peace among them and +protect industry against the foreign manufacturer. Such was the +political theory of business during the generation that followed the +Civil War. + + +THE SUPREMACY OF THE REPUBLICAN PARTY (1861-85) + +=Business Men and Republican Policies.=--Most of the leaders in industry +gravitated to the Republican ranks. They worked in the North and the +Republican party was essentially Northern. It was moreover--at least so +far as the majority of its members were concerned--committed to +protective tariffs, a sound monetary and banking system, the promotion +of railways and industry by land grants, and the development of internal +improvements. It was furthermore generous in its immigration policy. It +proclaimed America to be an asylum for the oppressed of all countries +and flung wide the doors for immigrants eager to fill the factories, man +the mines, and settle upon Western lands. In a word the Republicans +stood for all those specific measures which favored the enlargement and +prosperity of business. At the same time they resisted government +interference with private enterprise. They did not regulate railway +rates, prosecute trusts for forming combinations, or prevent railway +companies from giving lower rates to some shippers than to others. To +sum it up, the political theories of the Republican party for three +decades after the Civil War were the theories of American +business--prosperous and profitable industries for the owners and "the +full dinner pail" for the workmen. Naturally a large portion of those +who flourished under its policies gave their support to it, voted for +its candidates, and subscribed to its campaign funds. + +=Sources of Republican Strength in the North.=--The Republican party was +in fact a political organization of singular power. It originated in a +wave of moral enthusiasm, having attracted to itself, if not the +abolitionists, certainly all those idealists, like James Russell Lowell +and George William Curtis, who had opposed slavery when opposition was +neither safe nor popular. To moral principles it added practical +considerations. Business men had confidence in it. Workingmen, who +longed for the independence of the farmer, owed to its indulgent land +policy the opportunity of securing free homesteads in the West. The +immigrant, landing penniless on these shores, as a result of the same +beneficent system, often found himself in a little while with an estate +as large as many a baronial domain in the Old World. Under a Republican +administration, the union had been saved. To it the veterans of the war +could turn with confidence for those rewards of service which the +government could bestow: pensions surpassing in liberality anything that +the world had ever seen. Under a Republican administration also the +great debt had been created in the defense of the union, and to the +Republican party every investor in government bonds could look for the +full and honorable discharge of the interest and principal. The spoils +system, inaugurated by Jacksonian Democracy, in turn placed all the +federal offices in Republican hands, furnishing an army of party workers +to be counted on for loyal service in every campaign. + +Of all these things Republican leaders made full and vigorous use, +sometimes ascribing to the party, in accordance with ancient political +usage, merits and achievements not wholly its own. Particularly was this +true in the case of saving the union. "When in the economy of +Providence, this land was to be purged of human slavery ... the +Republican party came into power," ran a declaration in one platform. +"The Republican party suppressed a gigantic rebellion, emancipated four +million slaves, decreed the equal citizenship of all, and established +universal suffrage," ran another. As for the aid rendered by the +millions of Northern Democrats who stood by the union and the tens of +thousands of them who actually fought in the union army, the Republicans +in their zeal were inclined to be oblivious. They repeatedly charged the +Democratic party "with being the same in character and spirit as when it +sympathized with treason." + +=Republican Control of the South.=--To the strength enjoyed in the +North, the Republicans for a long time added the advantages that came +from control over the former Confederate states where the newly +enfranchised negroes, under white leadership, gave a grateful support to +the party responsible for their freedom. In this branch of politics, +motives were so mixed that no historian can hope to appraise them all at +their proper values. On the one side of the ledger must be set the +vigorous efforts of the honest and sincere friends of the freedmen to +win for them complete civil and political equality, wiping out not only +slavery but all its badges of misery and servitude. On the same side +must be placed the labor of those who had valiantly fought in forum and +field to save the union and who regarded continued Republican supremacy +after the war as absolutely necessary to prevent the former leaders in +secession from coming back to power. At the same time there were +undoubtedly some men of the baser sort who looked on politics as a game +and who made use of "carpet-bagging" in the South to win the spoils that +might result from it. At all events, both by laws and presidential acts, +the Republicans for many years kept a keen eye upon the maintenance of +their dominion in the South. Their declaration that neither the law nor +its administration should admit any discrimination in respect of +citizens by reason of race, color, or previous condition of servitude +appealed to idealists and brought results in elections. Even South +Carolina, where reposed the ashes of John C. Calhoun, went Republican in +1872 by a vote of three to one! + +Republican control was made easy by the force bills described in a +previous chapter--measures which vested the supervision of elections in +federal officers appointed by Republican Presidents. These drastic +measures, departing from American tradition, the Republican authors +urged, were necessary to safeguard the purity of the ballot, not merely +in the South where the timid freedman might readily be frightened from +using it; but also in the North, particularly in New York City, where it +was claimed that fraud was regularly practiced by Democratic leaders. + +The Democrats, on their side, indignantly denied the charges, replying +that the force bills were nothing but devices created by the Republicans +for the purpose of securing their continued rule through systematic +interference with elections. Even the measures of reconstruction were +deemed by Democratic leaders as thinly veiled schemes to establish +Republican power throughout the country. "Nor is there the slightest +doubt," exclaimed Samuel J. Tilden, spokesman of the Democrats in New +York and candidate for President in 1876, "that the paramount object and +motive of the Republican party is by these means to secure itself +against a reaction of opinion adverse to it in our great populous +Northern commonwealths.... When the Republican party resolved to +establish negro supremacy in the ten states in order to gain to itself +the representation of those states in Congress, it had to begin by +governing the people of those states by the sword.... The next was the +creation of new electoral bodies for those ten states, in which, by +exclusions, by disfranchisements and proscriptions, by control over +registration, by applying test oaths ... by intimidation and by every +form of influence, three million negroes are made to predominate over +four and a half million whites." + +=The War as a Campaign Issue.=--Even the repeal of force bills could not +allay the sectional feelings engendered by the war. The Republicans +could not forgive the men who had so recently been in arms against the +union and insisted on calling them "traitors" and "rebels." The +Southerners, smarting under the reconstruction acts, could regard the +Republicans only as political oppressors. The passions of the war had +been too strong; the distress too deep to be soon forgotten. The +generation that went through it all remembered it all. For twenty +years, the Republicans, in their speeches and platforms, made "a +straight appeal to the patriotism of the Northern voters." They +maintained that their party, which had saved the union and emancipated +the slaves, was alone worthy of protecting the union and uplifting the +freedmen. + +Though the Democrats, especially in the North, resented this policy and +dubbed it with the expressive but inelegant phrase, "waving the bloody +shirt," the Republicans refused to surrender a slogan which made such a +ready popular appeal. As late as 1884, a leader expressed the hope that +they might "wring one more President from the bloody shirt." They +refused to let the country forget that the Democratic candidate, Grover +Cleveland, had escaped military service by hiring a substitute; and they +made political capital out of the fact that he had "insulted the +veterans of the Grand Army of the Republic" by going fishing on +Decoration Day. + +=Three Republican Presidents.=--Fortified by all these elements of +strength, the Republicans held the presidency from 1869 to 1885. The +three Presidents elected in this period, Grant, Hayes, and Garfield, had +certain striking characteristics in common. They were all of origin +humble enough to please the most exacting Jacksonian Democrat. They had +been generals in the union army. Grant, next to Lincoln, was regarded as +the savior of the Constitution. Hayes and Garfield, though lesser lights +in the military firmament, had honorable records duly appreciated by +veterans of the war, now thoroughly organized into the Grand Army of the +Republic. It is true that Grant was not a politician and had never voted +the Republican ticket; but this was readily overlooked. Hayes and +Garfield on the other hand were loyal party men. The former had served +in Congress and for three terms as governor of his state. The latter had +long been a member of the House of Representatives and was Senator-elect +when he received the nomination for President. + +All of them possessed, moreover, another important asset, which was not +forgotten by the astute managers who led in selecting candidates. All +of them were from Ohio--though Grant had been in Illinois when the +summons to military duties came--and Ohio was a strategic state. It lay +between the manufacturing East and the agrarian country to the West. +Having growing industries and wool to sell it benefited from the +protective tariff. Yet being mainly agricultural still, it was not + +without sympathy for the farmers who showed low tariff or free trade +tendencies. Whatever share the East had in shaping laws and framing +policies, it was clear that the West was to have the candidates. This +division in privileges--not uncommon in political management--was always +accompanied by a judicious selection of the candidate for Vice +President. With Garfield, for example, was associated a prominent New +York politician, Chester A. Arthur, who, as fate decreed, was destined +to more than three years' service as chief magistrate, on the +assassination of his superior in office. + +=The Disputed Election of 1876.=--While taking note of the long years of +Republican supremacy, it must be recorded that grave doubts exist in the +minds of many historians as to whether one of the three Presidents, +Hayes, was actually the victor in 1876 or not. His Democratic opponent, +Samuel J. Tilden, received a popular plurality of a quarter of a million +and had a plausible claim to a majority of the electoral vote. At all +events, four states sent in double returns, one set for Tilden and +another for Hayes; and a deadlock ensued. Both parties vehemently +claimed the election and the passions ran so high that sober men did not +shrink from speaking of civil war again. Fortunately, in the end, the +counsels of peace prevailed. Congress provided for an electoral +commission of fifteen men to review the contested returns. The +Democrats, inspired by Tilden's moderation, accepted the judgment in +favor of Hayes even though they were not convinced that he was really +entitled to the office. + + +THE GROWTH OF OPPOSITION TO REPUBLICAN RULE + +=Abuses in American Political Life.=--During their long tenure of +office, the Republicans could not escape the inevitable consequences of +power; that is, evil practices and corrupt conduct on the part of some +who found shelter within the party. For that matter neither did the +Democrats manage to avoid such difficulties in those states and cities +where they had the majority. In New York City, for instance, the local +Democratic organization, known as Tammany Hall, passed under the sway of +a group of politicians headed by "Boss" Tweed. He plundered the city +treasury until public-spirited citizens, supported by Samuel J. Tilden, +the Democratic leader of the state, rose in revolt, drove the ringleader +from power, and sent him to jail. In Philadelphia, the local Republican +bosses were guilty of offenses as odious as those committed by New York +politicians. Indeed, the decade that followed the Civil War was marred +by so many scandals in public life that one acute editor was moved to +inquire: "Are not all the great communities of the Western World growing +more corrupt as they grow in wealth?" + +In the sphere of national politics, where the opportunities were +greater, betrayals of public trust were even more flagrant. One +revelation after another showed officers, high and low, possessed with +the spirit of peculation. Members of Congress, it was found, accepted +railway stock in exchange for votes in favor of land grants and other +concessions to the companies. In the administration as well as the +legislature the disease was rife. Revenue officers permitted whisky +distillers to evade their taxes and received heavy bribes in return. A +probe into the post-office department revealed the malodorous "star +route frauds"--the deliberate overpayment of certain mail carriers whose +lines were indicated in the official record by asterisks or stars. Even +cabinet officers did not escape suspicion, for the trail of the serpent +led straight to the door of one of them. + +In the lower ranges of official life, the spoils system became more +virulent as the number of federal employees increased. The holders of +offices and the seekers after them constituted a veritable political +army. They crowded into Republican councils, for the Republicans, being +in power, could alone dispense federal favors. They filled positions in +the party ranging from the lowest township committee to the national +convention. They helped to nominate candidates and draft platforms and +elbowed to one side the busy citizen, not conversant with party +intrigues, who could only give an occasional day to political matters. +Even the Civil Service Act of 1883, wrung from a reluctant Congress two +years after the assassination of Garfield, made little change for a long +time. It took away from the spoilsmen a few thousand government +positions, but it formed no check on the practice of rewarding party +workers from the public treasury. + +On viewing this state of affairs, many a distinguished citizen became +profoundly discouraged. James Russell Lowell, for example, thought he +saw a steady decline in public morals. In 1865, hearing of Lee's +surrender, he had exclaimed: "There is something magnificent in having a +country to love!" Ten years later, when asked to write an ode for the +centennial at Philadelphia in 1876, he could think only of a biting +satire on the nation: + + "Show your state legislatures; show your Rings; + And challenge Europe to produce such things + As high officials sitting half in sight + To share the plunder and fix things right. + If that don't fetch her, why, you need only + To show your latest style in martyrs,--Tweed: + She'll find it hard to hide her spiteful tears + At such advance in one poor hundred years." + +When his critics condemned him for this "attack upon his native land," +Lowell replied in sadness: "These fellows have no notion of what love of +country means. It was in my very blood and bones. If I am not an +American who ever was?... What fills me with doubt and dismay is the +degradation of the moral tone. Is it or is it not a result of democracy? +Is ours a 'government of the people, by the people, for the people,' or +a Kakistocracy [a government of the worst], rather for the benefit of +knaves at the cost of fools?" + +=The Reform Movement in Republican Ranks.=--The sentiments expressed by +Lowell, himself a Republican and for a time American ambassador to +England, were shared by many men in his party. Very soon after the close +of the Civil War some of them began to protest vigorously against the +policies and conduct of their leaders. In 1872, the dissenters, calling +themselves Liberal Republicans, broke away altogether, nominated a +candidate of their own, Horace Greeley, and put forward a platform +indicting the Republican President fiercely enough to please the most +uncompromising Democrat. They accused Grant of using "the powers and +opportunities of his high office for the promotion of personal ends." +They charged him with retaining "notoriously corrupt and unworthy men in +places of power and responsibility." They alleged that the Republican +party kept "alive the passions and resentments of the late civil war to +use them for their own advantages," and employed the "public service of +the government as a machinery of corruption and personal influence." + +It was not apparent, however, from the ensuing election that any +considerable number of Republicans accepted the views of the Liberals. +Greeley, though indorsed by the Democrats, was utterly routed and died +of a broken heart. The lesson of his discomfiture seemed to be that +independent action was futile. So, at least, it was regarded by most men +of the rising generation like Henry Cabot Lodge, of Massachusetts, and +Theodore Roosevelt, of New York. Profiting by the experience of Greeley +they insisted in season and out that reformers who desired to rid the +party of abuses should remain loyal to it and do their work "on the +inside." + +=The Mugwumps and Cleveland Democracy in 1884.=--Though aided by +Republican dissensions, the Democrats were slow in making headway +against the political current. They were deprived of the energetic and +capable leadership once afforded by the planters, like Calhoun, Davis, +and Toombs; they were saddled by their opponents with responsibility for +secession; and they were stripped of the support of the prostrate +South. Not until the last Southern state was restored to the union, not +until a general amnesty was wrung from Congress, not until white +supremacy was established at the polls, and the last federal soldier +withdrawn from Southern capitals did they succeed in capturing the +presidency. + +The opportune moment for them came in 1884 when a number of +circumstances favored their aspirations. The Republicans, leaving the +Ohio Valley in their search for a candidate, nominated James G. Blaine +of Maine, a vigorous and popular leader but a man under fire from the +reformers in his own party. The Democrats on their side were able to +find at this juncture an able candidate who had no political enemies in +the sphere of national politics, Grover Cleveland, then governor of New +York and widely celebrated as a man of "sterling honesty." At the same +time a number of dissatisfied Republicans openly espoused the Democratic +cause,--among them Carl Schurz, George William Curtis, Henry Ward +Beecher, and William Everett, men of fine ideals and undoubted +integrity. Though the "regular" Republicans called them "Mugwumps" and +laughed at them as the "men milliners, the dilettanti, and carpet +knights of politics," they had a following that was not to be despised. + +The campaign which took place that year was one of the most savage in +American history. Issues were thrust into the background. The tariff, +though mentioned, was not taken seriously. Abuse of the opposition was +the favorite resource of party orators. The Democrats insisted that "the +Republican party so far as principle is concerned is a reminiscence. In +practice it is an organization for enriching those who control its +machinery." For the Republican candidate, Blaine, they could hardly find +words to express their contempt. The Republicans retaliated in kind. +They praised their own good works, as of old, in saving the union, and +denounced the "fraud and violence practiced by the Democracy in the +Southern states." Seeing little objectionable in the public record of +Cleveland as mayor of Buffalo and governor of New York, they attacked +his personal character. Perhaps never in the history of political +campaigns did the discussions on the platform and in the press sink to +so low a level. Decent people were sickened. Even hot partisans shrank +from their own words when, after the election, they had time to reflect +on their heedless passions. Moreover, nothing was decided by the +balloting. Cleveland was elected, but his victory was a narrow one. A +change of a few hundred votes in New York would have sent his opponent +to the White House instead. + +=Changing Political Fortunes (1888-96).=--After the Democrats had +settled down to the enjoyment of their hard-earned victory, President +Cleveland in his message of 1887 attacked the tariff as "vicious, +inequitable, and illogical"; as a system of taxation that laid a burden +upon "every consumer in the land for the benefit of our manufacturers." +Business enterprise was thoroughly alarmed. The Republicans +characterized the tariff message as a free-trade assault upon the +industries of the country. Mainly on that issue they elected in 1888 +Benjamin Harrison of Indiana, a shrewd lawyer, a reticent politician, a +descendant of the hero of Tippecanoe, and a son of the old Northwest. +Accepting the outcome of the election as a vindication of their +principles, the Republicans, under the leadership of William McKinley in +the House of Representatives, enacted in 1890 a tariff law imposing the +highest duties yet laid in our history. To their utter surprise, +however, they were instantly informed by the country that their program +was not approved. That very autumn they lost in the congressional +elections, and two years later they were decisively beaten in the +presidential campaign, Cleveland once more leading his party to victory. + + +=References= + +L.H. Haney, _Congressional History of Railways_ (2 vols.). + +J.P. Davis, _Union Pacific Railway_. + +J.M. Swank, _History of the Manufacture of Iron_. + +M.T. Copeland, _The Cotton Manufacturing Industry in the United States_ +(Harvard Studies). + +E.W. Bryce, _Progress of Invention in the Nineteenth Century_. + +Ida Tarbell, _History of the Standard Oil Company_ (Critical). + +G.H. Montague, _Rise and Progress of the Standard Oil Company_ +(Friendly). + +H.P. Fairchild, _Immigration_, and F.J. Warne, _The Immigrant Invasion_ +(Both works favor exclusion). + +I.A. Hourwich, _Immigration_ (Against exclusionist policies). + +J.F. Rhodes, _History of the United States, 1877-1896_, Vol. VIII. + +Edward Stanwood, _A History of the Presidency_, Vol. I, for the +presidential elections of the period. + + +=Questions= + +1. Contrast the state of industry and commerce at the close of the Civil +War with its condition at the close of the Revolutionary War. + +2. Enumerate the services rendered to the nation by the railways. + +3. Explain the peculiar relation of railways to government. + +4. What sections of the country have been industrialized? + +5. How do you account for the rise and growth of the trusts? Explain +some of the economic advantages of the trust. + +6. Are the people in cities more or less independent than the farmers? +What was Jefferson's view? + +7. State some of the problems raised by unrestricted immigration. + +8. What was the theory of the relation of government to business in this +period? Has it changed in recent times? + +9. State the leading economic policies sponsored by the Republican +party. + +10. Why were the Republicans especially strong immediately after the +Civil War? + +11. What illustrations can you give showing the influence of war in +American political campaigns? + +12. Account for the strength of middle-western candidates. + +13. Enumerate some of the abuses that appeared in American political +life after 1865. + +14. Sketch the rise and growth of the reform movement. + +15. How is the fluctuating state of public opinion reflected in the +elections from 1880 to 1896? + + +=Research Topics= + +=Invention, Discovery, and Transportation.=--Sparks, _National +Development_ (American Nation Series), pp. 37-67; Bogart, _Economic +History of the United States_, Chaps. XXI, XXII, and XXIII. + +=Business and Politics.=--Paxson, _The New Nation_ (Riverside Series), +pp. 92-107; Rhodes, _History of the United States_, Vol. VII, pp. 1-29, +64-73, 175-206; Wilson, _History of the American People_, Vol. IV, pp. +78-96. + +=Immigration.=--Coman, _Industrial History of the United States_ (2d +ed.), pp. 369-374; E.L. Bogart, _Economic History of the United States_, +pp. 420-422, 434-437; Jenks and Lauck, _Immigration Problems_, Commons, +_Races and Immigrants_. + +=The Disputed Election of 1876.=--Haworth, _The United States in Our Own +Time_, pp. 82-94; Dunning, _Reconstruction, Political and Economic_ +(American Nation Series), pp. 294-341; Elson, _History of the United +States_, pp. 835-841. + +=Abuses in Political Life.=--Dunning, _Reconstruction_, pp. 281-293; see +criticisms in party platforms in Stanwood, _History of the Presidency_, +Vol. I; Bryce, _American Commonwealth_ (1910 ed.), Vol. II, pp. 379-448; +136-167. + +=Studies of Presidential Administrations.=--(_a_) Grant, (_b_) Hayes, +(_c_) Garfield-Arthur, (_d_) Cleveland, and (_e_) Harrison, in Haworth, +_The United States in Our Own Time_, or in Paxson, _The New Nation_ +(Riverside Series), or still more briefly in Elson. + +=Cleveland Democracy.=--Haworth, _The United States_, pp. 164-183; +Rhodes, _History of the United States_, Vol. VIII, pp. 240-327; Elson, +pp. 857-887. + +=Analysis of Modern Immigration Problems.=--_Syllabus in History_ (New +York State, 1919), pp. 110-112. + + + + +CHAPTER XVIII + +THE DEVELOPMENT OF THE GREAT WEST + + +At the close of the Civil War, Kansas and Texas were sentinel states on +the middle border. Beyond the Rockies, California, Oregon, and Nevada +stood guard, the last of them having been just admitted to furnish +another vote for the fifteenth amendment abolishing slavery. Between the +near and far frontiers lay a vast reach of plain, desert, plateau, and +mountain, almost wholly undeveloped. A broad domain, extending from +Canada to Mexico, and embracing the regions now included in Washington, +Idaho, Wyoming, Montana, Utah, Arizona, New Mexico, the Dakotas, and +Oklahoma, had fewer than half a million inhabitants. It was laid out +into territories, each administered under a governor appointed by the +President and Senate and, as soon as there was the requisite number of +inhabitants, a legislature elected by the voters. No railway line +stretched across the desert. St. Joseph on the Missouri was the terminus +of the Eastern lines. It required twenty-five days for a passenger to +make the overland journey to California by the stagecoach system, +established in 1858, and more than ten days for the swift pony express, +organized in 1860, to carry a letter to San Francisco. Indians still +roamed the plain and desert and more than one powerful tribe disputed +the white man's title to the soil. + + +THE RAILWAYS AS TRAIL BLAZERS + +=Opening Railways to the Pacific.=--A decade before the Civil War the +importance of rail connection between the East and the Pacific Coast had +been recognized. Pressure had already been brought to bear on Congress +to authorize the construction of a line and to grant land and money in +its aid. Both the Democrats and Republicans approved the idea, but it +was involved in the slavery controversy. Indeed it was submerged in it. +Southern statesmen wanted connections between the Gulf and the Pacific +through Texas, while Northerners stood out for a central route. + +The North had its way during the war. Congress, by legislation initiated +in 1862, provided for the immediate organization of companies to build a +line from the Missouri River to California and made grants of land and +loans of money to aid in the enterprise. The Western end, the Central +Pacific, was laid out under the supervision of Leland Stanford. It was +heavily financed by the Mormons of Utah and also by the state +government, the ranchmen, miners, and business men of California; and it +was built principally by Chinese labor. The Eastern end, the Union +Pacific, starting at Omaha, was constructed mainly by veterans of the +Civil War and immigrants from Ireland and Germany. In 1869 the two +companies met near Ogden in Utah and the driving of the last spike, +uniting the Atlantic and the Pacific, was the occasion of a great +demonstration. + +Other lines to the Pacific were projected at the same time; but the +panic of 1873 checked railway enterprise for a while. With the revival +of prosperity at the end of that decade, construction was renewed with +vigor and the year 1883 marked a series of railway triumphs. In February +trains were running from New Orleans through Houston, San Antonio, and +Yuma to San Francisco, as a result of a union of the Texas Pacific with +the Southern Pacific and its subsidiary corporations. In September the +last spike was driven in the Northern Pacific at Helena, Montana. Lake +Superior was connected with Puget Sound. The waters explored by Joliet +and Marquette were joined to the waters plowed by Sir Francis Drake +while he was searching for a route around the world. That same year also +a third line was opened to the Pacific by way of the Atchison, Topeka +and Santa Fe, making connections through Albuquerque and Needles with +San Francisco. The fondest hopes of railway promoters seemed to be +realized. + +[Illustration: UNITED STATES IN 1870] + +=Western Railways Precede Settlement.=--In the Old World and on our +Atlantic seaboard, railways followed population and markets. In the Far +West, railways usually preceded the people. Railway builders planned +cities on paper before they laid tracks connecting them. They sent +missionaries to spread the gospel of "Western opportunity" to people in +the Middle West, in the Eastern cities, and in Southern states. Then +they carried their enthusiastic converts bag and baggage in long trains +to the distant Dakotas and still farther afield. So the development of +the Far West was not left to the tedious processes of time. It was +pushed by men of imagination--adventurers who made a romance of +money-making and who had dreams of empire unequaled by many kings of the +past. + +These empire builders bought railway lands in huge tracts; they got more +from the government; they overcame every obstacle of canon, mountain, +and stream with the aid of science; they built cities according to the +plans made by the engineers. Having the towns ready and railway and +steamboat connections formed with the rest of the world, they carried +out the people to use the railways, the steamships, the houses, and the +land. It was in this way that "the frontier speculator paved the way for +the frontier agriculturalist who had to be near a market before he could +farm." The spirit of this imaginative enterprise, which laid out +railways and towns in advance of the people, is seen in an advertisement +of that day: "This extension will run 42 miles from York, northeast +through the Island Lake country, and will have five good North Dakota +towns. The stations on the line will be well equipped with elevators and +will be constructed and ready for operation at the commencement of the +grain season. Prospective merchants have been active in securing +desirable locations at the different towns on the line. There are still +opportunities for hotels, general merchandise, hardware, furniture, and +drug stores, etc." + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +A TOWN ON THE PRAIRIE] + +Among the railway promoters and builders in the West, James J. Hill, +of the Great Northern and allied lines, was one of the most forceful +figures. He knew that tracks and trains were useless without passengers +and freight; without a population of farmers and town dwellers. He +therefore organized publicity in the Virginias, Iowa, Ohio, Indiana, +Illinois, Wisconsin, and Nebraska especially. He sent out agents to tell +the story of Western opportunity in this vein: "You see your children +come out of school with no chance to get farms of their own because the +cost of land in your older part of the country is so high that you can't +afford to buy land to start your sons out in life around you. They have +to go to the cities to make a living or become laborers in the mills or +hire out as farm hands. There is no future for them there. If you are +doing well where you are and can safeguard the future of your children +and see them prosper around you, don't leave here. But if you want +independence, if you are renting your land, if the money-lender is +carrying you along and you are running behind year after year, you can +do no worse by moving.... You farmers talk of free trade and protection +and what this or that political party will do for you. Why don't you +vote a homestead for yourself? That is the only thing Uncle Sam will +ever give you. Jim Hill hasn't an acre of land to sell you. We are not +in the real estate business. We don't want you to go out West and make a +failure of it because the rates at which we haul you and your goods make +the first transaction a loss.... We must have landless men for a manless +land." + +Unlike steamship companies stimulating immigration to get the fares, +Hill was seeking permanent settlers who would produce, manufacture, and +use the railways as the means of exchange. Consequently he fixed low +rates and let his passengers take a good deal of live stock and +household furniture free. By doing this he made an appeal that was +answered by eager families. In 1894 the vanguard of home seekers left +Indiana in fourteen passenger coaches, filled with men, women, and +children, and forty-eight freight cars carrying their household goods +and live stock. In the ten years that followed, 100,000 people from the +Middle West and the South, responding to his call, went to the Western +country where they brought eight million acres of prairie land under +cultivation. + +When Hill got his people on the land, he took an interest in everything +that increased the productivity of their labor. Was the output of food +for his freight cars limited by bad drainage on the farms? Hill then +interested himself in practical ways of ditching and tiling. Were +farmers hampered in hauling their goods to his trains by bad roads? In +that case, he urged upon the states the improvement of highways. Did the +traffic slacken because the food shipped was not of the best quality? +Then live stock must be improved and scientific farming promoted. Did +the farmers need credit? Banks must be established close at hand to +advance it. In all conferences on scientific farm management, +conservation of natural resources, banking and credit in relation to +agriculture and industry, Hill was an active participant. His was the +long vision, seeing in conservation and permanent improvements the +foundation of prosperity for the railways and the people. + +Indeed, he neglected no opportunity to increase the traffic on the +lines. He wanted no empty cars running in either direction and no wheat +stored in warehouses for the lack of markets. So he looked to the Orient +as well as to Europe as an outlet for the surplus of the farms. He sent +agents to China and Japan to discover what American goods and produce +those countries would consume and what manufactures they had to offer to +Americans in exchange. To open the Pacific trade he bought two ocean +monsters, the _Minnesota_ and the _Dakota_, thus preparing for +emergencies West as well as East. When some Japanese came to the United +States on their way to Europe to buy steel rails, Hill showed them how +easy it was for them to make their purchase in this country and ship by +way of American railways and American vessels. So the railway builder +and promoter, who helped to break the virgin soil of the prairies, lived +through the pioneer epoch and into the age of great finance. Before he +died he saw the wheat fields of North Dakota linked with the spinning +jennies of Manchester and the docks of Yokohama. + + +THE EVOLUTION OF GRAZING AND AGRICULTURE + +=The Removal of the Indians.=--Unlike the frontier of New England in +colonial days or that of Kentucky later, the advancing lines of home +builders in the Far West had little difficulty with warlike natives. +Indian attacks were made on the railway construction gangs; General +Custer had his fatal battle with the Sioux in 1876 and there were minor +brushes; but they were all of relatively slight consequence. The former +practice of treating with the Indians as independent nations was +abandoned in 1871 and most of them were concentrated in reservations +where they were mainly supported by the government. The supervision of +their affairs was vested in a board of commissioners created in 1869 and +instructed to treat them as wards of the nation--a trust which +unfortunately was often betrayed. A further step in Indian policy was +taken in 1887 when provision was made for issuing lands to individual +Indians, thus permitting them to become citizens and settle down among +their white neighbors as farmers or cattle raisers. The disappearance of +the buffalo, the main food supply of the wild Indians, had made them +more tractable and more willing to surrender the freedom of the hunter +for the routine of the reservation, ranch, or wheat field. + +=The Cowboy and Cattle Ranger.=--Between the frontier of farms and the +mountains were plains and semi-arid regions in vast reaches suitable for +grazing. As soon as the railways were open into the Missouri Valley, +affording an outlet for stock, there sprang up to the westward cattle +and sheep raising on an immense scale. The far-famed American cowboy was +the hero in this scene. Great herds of cattle were bred in Texas; with +the advancing spring and summer seasons, they were driven northward +across the plains and over the buffalo trails. In a single year, 1884, +it is estimated that nearly one million head of cattle were moved out of +Texas to the North by four thousand cowboys, supplied with 30,000 +horses and ponies. + +During the two decades from 1870 to 1890 both the cattle men and the +sheep raisers had an almost free run of the plains, using public lands +without paying for the privilege and waging war on one another over the +possession of ranges. At length, however, both had to go, as the +homesteaders and land companies came and fenced in the plain and desert +with endless lines of barbed wire. Already in 1893 a writer familiar +with the frontier lamented the passing of the picturesque days: "The +unique position of the cowboys among the Americans is jeopardized in a +thousand ways. Towns are growing up on their pasture lands; irrigation +schemes of a dozen sorts threaten to turn bunch-grass scenery into +farm-land views; farmers are pre-empting valleys and the sides of +waterways; and the day is not far distant when stock-raising must be +done mainly in small herds, with winter corrals, and then the cowboy's +days will end. Even now his condition disappoints those who knew him +only half a dozen years ago. His breed seems to have deteriorated and +his ranks are filling with men who work for wages rather than for the +love of the free life and bold companionship that once tempted men into +that calling. Splendid Cheyenne saddles are less and less numerous in +the outfits; the distinctive hat that made its way up from Mexico may or +may not be worn; all the civil authorities in nearly all towns in the +grazing country forbid the wearing of side arms; nobody shoots up these +towns any more. The fact is the old simon-pure cowboy days are gone +already." + +=Settlement under the Homestead Act of 1862.=--Two factors gave a +special stimulus to the rapid settlement of Western lands which swept +away the Indians and the cattle rangers. The first was the policy of the +railway companies in selling large blocks of land received from the +government at low prices to induce immigration. The second was the +operation of the Homestead law passed in 1862. This measure practically +closed the long controversy over the disposition of the public domain +that was suitable for agriculture. It provided for granting, without any +cost save a small registration fee, public lands in lots of 160 acres +each to citizens and aliens who declared their intention of becoming +citizens. The one important condition attached was that the settler +should occupy the farm for five years before his title was finally +confirmed. Even this stipulation was waived in the case of the Civil War +veterans who were allowed to count their term of military service as a +part of the five years' occupancy required. As the soldiers of the +Revolutionary and Mexican wars had advanced in great numbers to the +frontier in earlier days, so now veterans led in the settlement of the +middle border. Along with them went thousands of German, Irish, and +Scandinavian immigrants, fresh from the Old World. Between 1867 and +1874, 27,000,000 acres were staked out in quarter-section farms. In +twenty years (1860-80), the population of Nebraska leaped from 28,000 to +almost half a million; Kansas from 100,000 to a million; Iowa from +600,000 to 1,600,000; and the Dakotas from 5000 to 140,000. + +=The Diversity of Western Agriculture.=--In soil, produce, and +management, Western agriculture presented many contrasts to that of the +East and South. In the region of arable and watered lands the typical +American unit--the small farm tilled by the owner--appeared as usual; +but by the side of it many a huge domain owned by foreign or Eastern +companies and tilled by hired labor. Sometimes the great estate took the +shape of the "bonanza farm" devoted mainly to wheat and corn and +cultivated on a large scale by machinery. Again it assumed the form of +the cattle ranch embracing tens of thousands of acres. Again it was a +vast holding of diversified interest, such as the Santa Anita ranch near +Los Angeles, a domain of 60,000 acres "cultivated in a glorious sweep of +vineyards and orange and olive orchards, rich sheep and cattle pastures +and horse ranches, their life and customs handed down from the Spanish +owners of the various ranches which were swept into one estate." + +=Irrigation.=--In one respect agriculture in the Far West was unique. In +a large area spreading through eight states, Montana, Idaho, Wyoming, +Utah, Colorado, Nevada, Arizona, New Mexico, and parts of adjoining +states, the rainfall was so slight that the ordinary crops to which the +American farmer was accustomed could not be grown at all. The Mormons +were the first Anglo-Saxons to encounter aridity, and they were baffled +at first; but they studied it and mastered it by magnificent irrigation +systems. As other settlers poured into the West the problem of the +desert was attacked with a will, some of them replying to the +commiseration of Eastern farmers by saying that it was easier to scoop +out an irrigation ditch than to cut forests and wrestle with stumps and +stones. Private companies bought immense areas at low prices, built +irrigation works, and disposed of their lands in small plots. Some +ranchers with an instinct for water, like that of the miner for metal, +sank wells into the dry sand and were rewarded with gushers that "soused +the thirsty desert and turned its good-for-nothing sand into +good-for-anything loam." The federal government came to the aid of the +arid regions in 1894 by granting lands to the states to be used for +irrigation purposes. In this work Wyoming took the lead with a law which +induced capitalists to invest in irrigation and at the same time +provided for the sale of the redeemed lands to actual settlers. Finally +in 1902 the federal government by its liberal Reclamation Act added its +strength to that of individuals, companies, and states in conquering +"arid America." + +"Nowhere," writes Powell, a historian of the West, in his picturesque +_End of the Trail_, "has the white man fought a more courageous fight or +won a more brilliant victory than in Arizona. His weapons have been the +transit and the level, the drill and the dredge, the pick and the spade; +and the enemy which he has conquered has been the most stubborn of all +foes--the hostile forces of Nature.... The story of how the white man +within the space of less than thirty years penetrated, explored, and +mapped this almost unknown region; of how he carried law, order, and +justice into a section which had never had so much as a speaking +acquaintance with any one of the three before; of how, realizing the +necessity for means of communication, he built highways of steel across +this territory from east to west and from north to south; of how, +undismayed by the savageness of the countenance which the desert turned +upon him, he laughed and rolled up his sleeves, and spat upon his hands, +and slashed the face of the desert with canals and irrigating ditches, +and filled those ditches with water brought from deep in the earth or +high in the mountains; and of how, in the conquered and submissive soil, +he replaced the aloe with alfalfa, the mesquite with maize, the cactus +with cotton, forms one of the most inspiring chapters in our history. It +is one of the epics of civilization, this reclamation of the Southwest, +and its heroes, thank God, are Americans. + +"Other desert regions have been redeemed by irrigation--Egypt, for +example, and Mesopotamia and parts of the Sudan--but the people of all +those regions lay stretched out in the shade of a convenient palm, +metaphorically speaking, and waited for some one with more energy than +themselves to come along and do the work. But the Arizonians, mindful of +the fact that God, the government, and Carnegie help those who help +themselves, spent their days wielding the pick and shovel, and their +evenings in writing letters to Washington with toil-hardened hands. +After a time the government was prodded into action and the great dams +at Laguna and Roosevelt are the result. Then the people, organizing +themselves into cooperative leagues and water-users' associations, took +up the work of reclamation where the government left off; it is to these +energetic, persevering men who have drilled wells, plowed fields, and +dug ditches through the length and breadth of that great region which +stretches from Yuma to Tucson, that the metamorphosis of Arizona is +due." + +The effect of irrigation wherever introduced was amazing. Stretches of +sand and sagebrush gave way to fertile fields bearing crops of wheat, +corn, fruits, vegetables, and grass. Huge ranches grazed by browsing +sheep were broken up into small plots. The cowboy and ranchman vanished. +In their place rose the prosperous community--a community unlike the +township of Iowa or the industrial center of the East. Its intensive +tillage left little room for hired labor. Its small holdings drew +families together in village life rather than dispersing them on the +lonely plain. Often the development of water power in connection with +irrigation afforded electricity for labor-saving devices and lifted many +a burden that in other days fell heavily upon the shoulders of the +farmer and his family. + + +MINING AND MANUFACTURING IN THE WEST + +=Mineral Resources.=--In another important particular the Far West +differed from the Mississippi Valley states. That was in the +predominance of mining over agriculture throughout a vast section. +Indeed it was the minerals rather than the land that attracted the +pioneers who first opened the country. The discovery of gold in +California in 1848 was the signal for the great rush of prospectors, +miners, and promoters who explored the valleys, climbed the hills, +washed the sands, and dug up the soil in their feverish search for gold, +silver, copper, coal, and other minerals. In Nevada and Montana the +development of mineral resources went on all during the Civil War. Alder +Gulch became Virginia City in 1863; Last Chance Gulch was named Helena +in 1864; and Confederate Gulch was christened Diamond City in 1865. At +Butte the miners began operations in 1864 and within five years had +washed out eight million dollars' worth of gold. Under the gold they +found silver; under silver they found copper. + +Even at the end of the nineteenth century, after agriculture was well +advanced and stock and sheep raising introduced on a large scale, +minerals continued to be the chief source of wealth in a number of +states. This was revealed by the figures for 1910. The gold, silver, +iron, and copper of Colorado were worth more than the wheat, corn, and +oats combined; the copper of Montana sold for more than all the cereals +and four times the price of the wheat. The interest of Nevada was also +mainly mining, the receipts from the mineral output being $43,000,000 or +more than one-half the national debt of Hamilton's day. The yield of the +mines of Utah was worth four or five times the wheat crop; the coal of +Wyoming brought twice as much as the great wool clip; the minerals of +Arizona were totaled at $43,000,000 as against a wool clip reckoned at +$1,200,000; while in Idaho alone of this group of states did the wheat +crop exceed in value the output of the mines. + +[Illustration: _Photograph from Underwood and Underwood, N.Y._ + +LOGGING] + +=Timber Resources.=--The forests of the great West, unlike those of the +Ohio Valley, proved a boon to the pioneers rather than a foe to be +attacked. In Ohio and Indiana, for example, the frontier line of +homemakers had to cut, roll, and burn thousands of trees before they +could put out a crop of any size. Beyond the Mississippi, however, +there were all ready for the breaking plow great reaches of almost +treeless prairie, where every stick of timber was precious. In the other +parts, often rough and mountainous, where stood primeval forests of the +finest woods, the railroads made good use of the timber. They consumed +acres of forests themselves in making ties, bridge timbers, and +telegraph poles, and they laid a heavy tribute upon the forests for +their annual upkeep. The surplus trees, such as had burdened the +pioneers of the Northwest Territory a hundred years before, they carried +off to markets on the east and west coasts. + +=Western Industries.=--The peculiar conditions of the Far West +stimulated a rise of industries more rapid than is usual in new country. +The mining activities which in many sections preceded agriculture called +for sawmills to furnish timber for the mines and smelters to reduce and +refine ores. The ranches supplied sheep and cattle for the packing +houses of Kansas City as well as Chicago. The waters of the Northwest +afforded salmon for 4000 cases in 1866 and for 1,400,000 cases in 1916. +The fruits and vegetables of California brought into existence +innumerable canneries. The lumber industry, starting with crude sawmills +to furnish rough timbers for railways and mines, ended in specialized +factories for paper, boxes, and furniture. As the railways preceded +settlement and furnished a ready outlet for local manufactures, so they +encouraged the early establishment of varied industries, thus creating a +state of affairs quite unlike that which obtained in the Ohio Valley in +the early days before the opening of the Erie Canal. + +=Social Effects of Economic Activities.=--In many respects the social +life of the Far West also differed from that of the Ohio Valley. The +treeless prairies, though open to homesteads, favored the great estate +tilled in part by tenant labor and in part by migratory seasonal labor, +summoned from all sections of the country for the harvests. The mineral +resources created hundreds of huge fortunes which made the accumulations +of eastern mercantile families look trivial by comparison. Other +millionaires won their fortunes in the railway business and still more +from the cattle and sheep ranges. In many sections the "cattle king," as +he was called, was as dominant as the planter had been in the old South. +Everywhere in the grazing country he was a conspicuous and important +person. He "sometimes invested money in banks, in railroad stocks, or in +city property.... He had his rating in the commercial reviews and could +hobnob with bankers, railroad presidents, and metropolitan merchants.... +He attended party caucuses and conventions, ran for the state +legislature, and sometimes defeated a lawyer or metropolitan 'business +man' in the race for a seat in Congress. In proportion to their numbers, +the ranchers ... have constituted a highly impressive class." + +Although many of the early capitalists of the great West, especially +from Nevada, spent their money principally in the East, others took +leadership in promoting the sections in which they had made their +fortunes. A railroad pioneer, General Palmer, built his home at Colorado +Springs, founded the town, and encouraged local improvements. Denver +owed its first impressive buildings to the civic patriotism of Horace +Tabor, a wealthy mine owner. Leland Stanford paid his tribute to +California in the endowment of a large university. Colonel W.F. Cody, +better known as "Buffalo Bill," started his career by building a "boom +town" which collapsed, and made a large sum of money supplying buffalo +meat to construction hands (hence his popular name). By his famous Wild +West Show, he increased it to a fortune which he devoted mainly to the +promotion of a western reclamation scheme. + +While the Far West was developing this vigorous, aggressive leadership +in business, a considerable industrial population was springing up. Even +the cattle ranges and hundreds of farms were conducted like factories in +that they were managed through overseers who hired plowmen, harvesters, +and cattlemen at regular wages. At the same time there appeared other +peculiar features which made a lasting impression on western economic +life. Mining, lumbering, and fruit growing, for instance, employed +thousands of workers during the rush months and turned them out at other +times. The inevitable result was an army of migratory laborers wandering +from camp to camp, from town to town, and from ranch to ranch, without +fixed homes or established habits of life. From this extraordinary +condition there issued many a long and lawless conflict between capital +and labor, giving a distinct color to the labor movement in whole +sections of the mountain and coast states. + + +THE ADMISSION OF NEW STATES + +=The Spirit of Self-Government.=--The instinct of self-government was +strong in the western communities. In the very beginning, it led to the +organization of volunteer committees, known as "vigilantes," to suppress +crime and punish criminals. As soon as enough people were settled +permanently in a region, they took care to form a more stable kind of +government. An illustration of this process is found in the Oregon +compact made by the pioneers in 1843, the spirit of which is reflected +in an editorial in an old copy of the _Rocky Mountain News_: "We claim +that any body or community of American citizens which from any cause or +under any circumstances is cut off from or from isolation is so situated +as not to be under any active and protecting branch of the central +government, have a right, if on American soil, to frame a government and +enact such laws and regulations as may be necessary for their own +safety, protection, and happiness, always with the condition precedent, +that they shall, at the earliest moment when the central government +shall extend an effective organization and laws over them, give it their +unqualified support and obedience." + +People who turned so naturally to the organization of local +administration were equally eager for admission to the union as soon as +any shadow of a claim to statehood could be advanced. As long as a +region was merely one of the territories of the United States, the +appointment of the governor and other officers was controlled by +politics at Washington. Moreover the disposition of land, mineral +rights, forests, and water power was also in the hands of national +leaders. Thus practical considerations were united with the spirit of +independence in the quest for local autonomy. + +=Nebraska and Colorado.=--Two states, Nebraska and Colorado, had little +difficulty in securing admission to the union. The first, Nebraska, had +been organized as a territory by the famous Kansas-Nebraska bill which +did so much to precipitate the Civil War. Lying to the north of Kansas, +which had been admitted in 1861, it escaped the invasion of slave owners +from Missouri and was settled mainly by farmers from the North. Though +it claimed a population of only 67,000, it was regarded with kindly +interest by the Republican Congress at Washington and, reduced to its +present boundaries, it received the coveted statehood in 1867. + +This was hardly accomplished before the people of Colorado to the +southwest began to make known their demands. They had been organized +under territorial government in 1861 when they numbered only a handful; +but within ten years the aspect of their affairs had completely changed. +The silver and gold deposits of the Leadville and Cripple Creek regions +had attracted an army of miners and prospectors. The city of Denver, +founded in 1858 and named after the governor of Kansas whence came many +of the early settlers, had grown from a straggling camp of log huts into +a prosperous center of trade. By 1875 it was reckoned that the +population of the territory was not less than one hundred thousand; the +following year Congress, yielding to the popular appeal, made Colorado a +member of the American union. + +=Six New States (1889-1890).=--For many years there was a deadlock in +Congress over the admission of new states. The spell was broken in 1889 +under the leadership of the Dakotas. For a long time the Dakota +territory, organized in 1861, had been looked upon as the home of the +powerful Sioux Indians whose enormous reservation blocked the advance of +the frontier. The discovery of gold in the Black Hills, however, marked +their doom. Even before Congress could open their lands to prospectors, +pioneers were swarming over the country. Farmers from the adjoining +Minnesota and the Eastern states, Scandinavians, Germans, and Canadians, +came in swelling waves to occupy the fertile Dakota lands, now famous +even as far away as the fjords of Norway. Seldom had the plow of man cut +through richer soil than was found in the bottoms of the Red River +Valley, and it became all the more precious when the opening of the +Northern Pacific in 1883 afforded a means of transportation east and +west. The population, which had numbered 135,000 in 1880, passed the +half million mark before ten years had elapsed. + +Remembering that Nebraska had been admitted with only 67,000 +inhabitants, the Dakotans could not see why they should be kept under +federal tutelage. At the same time Washington, far away on the Pacific +Coast, Montana, Idaho, and Wyoming, boasting of their populations and +their riches, put in their own eloquent pleas. But the members of +Congress were busy with politics. The Democrats saw no good reason for +admitting new Republican states until after their defeat in 1888. Near +the end of their term the next year they opened the door for North and +South Dakota, Washington, and Montana. In 1890, a Republican Congress +brought Idaho and Wyoming into the union, the latter with woman +suffrage, which had been granted twenty-one years before. + +=Utah.=--Although Utah had long presented all the elements of a +well-settled and industrious community, its admission to the union was +delayed on account of popular hostility to the practice of polygamy. The +custom, it is true, had been prohibited by act of Congress in 1862; but +the law had been systematically evaded. In 1882 Congress made another +and more effective effort to stamp out polygamy. Five years later it +even went so far as to authorize the confiscation of the property of the +Mormon Church in case the practice of plural marriages was not stopped. +Meanwhile the Gentile or non-Mormon population was steadily increasing +and the leaders in the Church became convinced that the battle +against the sentiment of the country was futile. At last in 1896 Utah +was admitted as a state under a constitution which forbade plural +marriages absolutely and forever. Horace Greeley, who visited Utah in +1859, had prophesied that the Pacific Railroad would work a revolution +in the land of Brigham Young. His prophecy had come true. + +[Illustration: THE UNITED STATES IN 1912] + +=Rounding out the Continent.=--Three more territories now remained out +of the Union. Oklahoma, long an Indian reservation, had been opened for +settlement to white men in 1889. The rush upon the fertile lands of this +region, the last in the history of America, was marked by all the frenzy +of the final, desperate chance. At a signal from a bugle an army of men +with families in wagons, men and women on horseback and on foot, burst +into the territory. During the first night a city of tents was raised at +Guthrie and Oklahoma City. In ten days wooden houses rose on the plains. +In a single year there were schools, churches, business blocks, and +newspapers. Within fifteen years there was a population of more than +half a million. To the west, Arizona with a population of about 125,000 +and New Mexico with 200,000 inhabitants joined Oklahoma in asking for +statehood. Congress, then Republican, looked with reluctance upon the +addition of more Democratic states; but in 1907 it was literally +compelled by public sentiment and a sense of justice to admit Oklahoma. +In 1910 the House of Representatives went to the Democrats and within +two years Arizona and New Mexico were "under the roof." So the +continental domain was rounded out. + + +THE INFLUENCE OF THE FAR WEST ON NATIONAL LIFE + +=The Last of the Frontier.=--When Horace Greeley made his trip west in +1859 he thus recorded the progress of civilization in his journal: + + "May 12th, Chicago.--Chocolate and morning journals last + seen on the hotel breakfast table. + + 23rd, Leavenworth (Kansas).--Room bells and bath tubs make + their final appearance. + + 26th, Manhattan.--Potatoes and eggs last recognized among + the blessings that 'brighten as they take their flight.' + + 27th, Junction City.--Last visitation of a boot-black, with + dissolving views of a board bedroom. Beds bid us good-by." + +[Illustration: _Copyright by Panama-California Exposition_ + +THE CANADIAN BUILDING AT THE PANAMA-CALIFORNIA INTERNATIONAL +EXPOSITION, SAN DIEGO, 1915] + +Within thirty years travelers were riding across that country in Pullman +cars and enjoying at the hotels all the comforts of a standardized +civilization. The "wild west" was gone, and with it that frontier of +pioneers and settlers who had long given such a bent and tone to +American life and had "poured in upon the floor of Congress" such a long +line of "backwoods politicians," as they were scornfully styled. + +=Free Land and Eastern Labor.=--It was not only the picturesque features +of the frontier that were gone. Of far more consequence was the +disappearance of free lands with all that meant for American labor. For +more than a hundred years, any man of even moderate means had been able +to secure a homestead of his own and an independent livelihood. For a +hundred years America had been able to supply farms to as many +immigrants as cared to till the soil. Every new pair of strong arms +meant more farms and more wealth. Workmen in Eastern factories, mines, +or mills who did not like their hours, wages, or conditions of labor, +could readily find an outlet to the land. Now all that was over. By +about 1890 most of the desirable land available under the Homestead act +had disappeared. American industrial workers confronted a new situation. + +=Grain Supplants King Cotton.=--In the meantime a revolution was taking +place in agriculture. Until 1860 the chief staples sold by America were +cotton and tobacco. With the advance of the frontier, corn and wheat +supplanted them both in agrarian economy. The West became the granary of +the East and of Western Europe. The scoop shovel once used to handle +grain was superseded by the towering elevator, loading and unloading +thousands of bushels every hour. The refrigerator car and ship made the +packing industry as stable as the production of cotton or corn, and gave +an immense impetus to cattle raising and sheep farming. So the meat of +the West took its place on the English dinner table by the side of bread +baked from Dakotan wheat. + +=Aid in American Economic Independence.=--The effects of this economic +movement were manifold and striking. Billions of dollars' worth of +American grain, dairy produce, and meat were poured into European +markets where they paid off debts due money lenders and acquired +capital to develop American resources. Thus they accelerated the +progress of American financiers toward national independence. The +country, which had timidly turned to the Old World for capital in +Hamilton's day and had borrowed at high rates of interest in London in +Lincoln's day, moved swiftly toward the time when it would be among the +world's first bankers and money lenders itself. Every grain of wheat and +corn pulled the balance down on the American side of the scale. + +=Eastern Agriculture Affected.=--In the East as well as abroad the +opening of the western granary produced momentous results. The +agricultural economy of that part of the country was changed in many +respects. Whole sections of the poorest land went almost out of +cultivation, the abandoned farms of the New England hills bearing solemn +witness to the competing power of western wheat fields. Sheep and cattle +raising, as well as wheat and corn production, suffered at least a +relative decline. Thousands of farmers cultivating land of the lower +grade were forced to go West or were driven to the margin of +subsistence. Even the herds that supplied Eastern cities with milk were +fed upon grain brought halfway across the continent. + +=The Expansion of the American Market.=--Upon industry as well as +agriculture, the opening of vast food-producing regions told in a +thousand ways. The demand for farm machinery, clothing, boots, shoes, +and other manufactures gave to American industries such a market as even +Hamilton had never foreseen. Moreover it helped to expand far into the +Mississippi Valley the industrial area once confined to the Northern +seaboard states and to transform the region of the Great Lakes into an +industrial empire. Herein lies the explanation of the growth of +mid-western cities after 1865. Chicago, with its thirty-five railways, +tapped every locality of the West and South. To the railways were added +the water routes of the Lakes, thus creating a strategic center for +industries. Long foresight carried the McCormick reaper works to +Chicago before 1860. From Troy, New York, went a large stove plant. That +was followed by a shoe factory from Massachusetts. The packing industry +rose as a matter of course at a point so advantageous for cattle raisers +and shippers and so well connected with Eastern markets. + +To the opening of the Far West also the Lake region was indebted for a +large part of that water-borne traffic which made it "the Mediterranean +basin of North America." The produce of the West and the manufactures of +the East poured through it in an endless stream. The swift growth of +shipbuilding on the Great Lakes helped to compensate for the decline of +the American marine on the high seas. In response to this stimulus +Detroit could boast that her shipwrights were able to turn out a ten +thousand ton Leviathan for ore or grain about "as quickly as carpenters +could put up an eight-room house." Thus in relation to the Far West the +old Northwest territory--the wilderness of Jefferson's time--had taken +the position formerly occupied by New England alone. It was supplying +capital and manufactures for a vast agricultural empire West and South. + +=America on the Pacific.=--It has been said that the Mediterranean Sea +was the center of ancient civilization; that modern civilization has +developed on the shores of the Atlantic; and that the future belongs to +the Pacific. At any rate, the sweep of the United States to the shores +of the Pacific quickly exercised a powerful influence on world affairs +and it undoubtedly has a still greater significance for the future. + +Very early regular traffic sprang up between the Pacific ports and the +Hawaiian Islands, China, and Japan. Two years before the adjustment of +the Oregon controversy with England, namely in 1844, the United States +had established official and trading relations with China. Ten years +later, four years after the admission of California to the union, the +barred door of Japan was forced open by Commodore Perry. The commerce +which had long before developed between the Pacific ports and Hawaii, +China, and Japan now flourished under official care. In 1865 a ship +from Honolulu carried sugar, molasses, and fruits from Hawaii to the +Oregon port of Astoria. The next year a vessel from Hongkong brought +rice, mats, and tea from China. An era of lucrative trade was opened. +The annexation of Hawaii in 1898, the addition of the Philippines at the +same time, and the participation of American troops in the suppression +of the Boxer rebellion in Peking in 1900, were but signs and symbols of +American power on the Pacific. + +[Illustration: _From an old print_ + +COMMODORE PERRY'S MEN MAKING PRESENTS TO THE JAPANESE] + +=Conservation and the Land Problem.=--The disappearance of the frontier +also brought new and serious problems to the governments of the states +and the nation. The people of the whole United States suddenly were +forced to realize that there was a limit to the rich, new land to +exploit and to the forests and minerals awaiting the ax and the pick. +Then arose in America the questions which had long perplexed the +countries of the Old World--the scientific use of the soils and +conservation of natural resources. Hitherto the government had followed +the easy path of giving away arable land and selling forest and mineral +lands at low prices. Now it had to face far more difficult and complex +problems. It also had to consider questions of land tenure again, +especially if the ideal of a nation of home-owning farmers was to be +maintained. While there was plenty of land for every man or woman who +wanted a home on the soil, it made little difference if single landlords +or companies got possession of millions of acres, if a hundred men in +one western river valley owned 17,000,000 acres; but when the good land +for small homesteads was all gone, then was raised the real issue. At +the opening of the twentieth century the nation, which a hundred years +before had land and natural resources apparently without limit, was +compelled to enact law after law conserving its forests and minerals. +Then it was that the great state of California, on the very border of +the continent, felt constrained to enact a land settlement measure +providing government assistance in an effort to break up large holdings +into small lots and to make it easy for actual settlers to acquire small +farms. America was passing into a new epoch. + + +=References= + +Henry Inman, _The Old Santa Fe Trail_. + +R.I. Dodge, _The Plains of the Great West_ (1877). + +C.H. Shinn, _The Story of the Mine_. + +Cy Warman, _The Story of the Railroad_. + +Emerson Hough, _The Story of the Cowboy_. + +H.H. Bancroft is the author of many works on the West but his writings +will be found only in the larger libraries. + +Joseph Schafer, _History of the Pacific Northwest_ (ed. 1918). + +T.H. Hittel, _History of California_ (4 vols.). + +W.H. Olin, _American Irrigation Farming_. + +W.E. Smythe, _The Conquest of Arid America_. + +H.A. Millis, _The American-Japanese Problem_. + +E.S. Meany, _History of the State of Washington_. + +H.K. Norton, _The Story of California_. + + +=Questions= + +1. Name the states west of the Mississippi in 1865. + +2. In what manner was the rest of the western region governed? + +3. How far had settlement been carried? + +4. What were the striking physical features of the West? + +5. How was settlement promoted after 1865? + +6. Why was admission to the union so eagerly sought? + +7. Explain how politics became involved in the creation of new states. + +8. Did the West rapidly become like the older sections of the country? + +9. What economic peculiarities did it retain or develop? + +10. How did the federal government aid in western agriculture? + +11. How did the development of the West affect the East? The South? + +12. What relation did the opening of the great grain areas of the West +bear to the growth of America's commercial and financial power? + +13. State some of the new problems of the West. + +14. Discuss the significance of American expansion to the Pacific Ocean. + + +=Research Topics= + +=The Passing of the Wild West.=--Haworth, _The United States in Our Own +Times_, pp. 100-124. + +=The Indian Question.=--Sparks, _National Development_ (American Nation +Series), pp. 265-281. + +=The Chinese Question.=--Sparks, _National Development_, pp. 229-250; +Rhodes, _History of the United States_, Vol. VIII, pp. 180-196. + +=The Railway Age.=--Schafer, _History of the Pacific Northwest_, pp. +230-245; E.V. Smalley, _The Northern Pacific Railroad_; Paxson, _The New +Nation_ (Riverside Series), pp. 20-26, especially the map on p. 23, and +pp. 142-148. + +=Agriculture and Business.=--Schafer, _Pacific Northwest_, pp. 246-289. + +=Ranching in the Northwest.=--Theodore Roosevelt, _Ranch Life_, and +_Autobiography_, pp. 103-143. + +=The Conquest of the Desert.=--W.E. Smythe, _The Conquest of Arid +America_. + +=Studies of Individual Western States.=--Consult any good encyclopedia. + + + + +CHAPTER XIX + +DOMESTIC ISSUES BEFORE THE COUNTRY (1865-1897) + + +For thirty years after the Civil War the leading political parties, +although they engaged in heated presidential campaigns, were not sharply +and clearly opposed on many matters of vital significance. During none +of that time was there a clash of opinion over specific issues such as +rent the country in 1800 when Jefferson rode a popular wave to victory, +or again in 1828 when Jackson's western hordes came sweeping into power. +The Democrats, who before 1860 definitely opposed protective tariffs, +federal banking, internal improvements, and heavy taxes, now spoke +cautiously on all these points. The Republicans, conscious of the fact +that they had been a minority of the voters in 1860 and warned by the +early loss of the House of Representatives in 1874, also moved with +considerable prudence among the perplexing problems of the day. Again +and again the votes in Congress showed that no clear line separated all +the Democrats from all the Republicans. There were Republicans who +favored tariff reductions and "cheap money." There were Democrats who +looked with partiality upon high protection or with indulgence upon the +contraction of the currency. Only on matters relating to the coercion of +the South was the division between the parties fairly definite; this +could be readily accounted for on practical as well as sentimental +grounds. + +After all, the vague criticisms and proposals that found their way into +the political platforms did but reflect the confusion of mind prevailing +in the country. The fact that, out of the eighteen years between 1875 +and 1893, the Democrats held the House of Representatives for fourteen +years while the Republicans had every President but one showed that the +voters, like the politicians, were in a state of indecision. Hayes had a +Democratic House during his entire term and a Democratic Senate for two +years of the four. Cleveland was confronted by a belligerent Republican +majority in the Senate during his first administration; and at the same +time was supported by a Democratic majority in the House. Harrison was +sustained by continuous Republican successes in Senatorial elections; +but in the House he had the barest majority from 1889 to 1891 and lost +that altogether at the election held in the middle of his term. The +opinion of the country was evidently unsettled and fluctuating. It was +still distracted by memories of the dead past and uncertain as to the +trend of the future. + + +THE CURRENCY QUESTION + +Nevertheless these years of muddled politics and nebulous issues proved +to be a period in which social forces were gathering for the great +campaign of 1896. Except for three new features--the railways, the +trusts, and the trade unions--the subjects of debate among the people +were the same as those that had engaged their attention since the +foundation of the republic: the currency, the national debt, banking, +the tariff, and taxation. + +=Debtors and the Fall in Prices.=--For many reasons the currency +question occupied the center of interest. As of old, the farmers and +planters of the West and South were heavily in debt to the East for +borrowed money secured by farm mortgages; and they counted upon the sale +of cotton, corn, wheat, and hogs to meet interest and principal when +due. During the war, the Western farmers had been able to dispose of +their produce at high prices and thus discharge their debts with +comparative ease; but after the war prices declined. Wheat that sold at +two dollars a bushel in 1865 brought sixty-four cents twenty years +later. The meaning of this for the farmers in debt--and nearly +three-fourths of them were in that class--can be shown by a single +illustration. A thousand-dollar mortgage on a Western farm could be paid +off by five hundred bushels of wheat when prices were high; whereas it +took about fifteen hundred bushels to pay the same debt when wheat was +at the bottom of the scale. For the farmer, it must be remembered, wheat +was the measure of his labor, the product of his toil under the summer +sun; and in its price he found the test of his prosperity. + +=Creditors and Falling Prices.=--To the bondholders or creditors, on the +other hand, falling prices were clear gain. If a fifty-dollar coupon on +a bond bought seventy or eighty bushels of wheat instead of twenty or +thirty, the advantage to the owner of the coupon was obvious. Moreover +the advantage seemed to him entirely just. Creditors had suffered heavy +losses when the Civil War carried prices skyward while the interest +rates on their old bonds remained stationary. For example, if a man had +a $1000 bond issued before 1860 and paying interest at five per cent, he +received fifty dollars a year from it. Before the war each dollar would +buy a bushel of wheat; in 1865 it would only buy half a bushel. When +prices--that is, the cost of living--began to go down, creditors +therefore generally regarded the change with satisfaction as a return to +normal conditions. + +=The Cause of Falling Prices.=--The fall in prices was due, no doubt, to +many factors. Among them must be reckoned the discontinuance of +government buying for war purposes, labor-saving farm machinery, +immigration, and the opening of new wheat-growing regions. The currency, +too, was an element in the situation. Whatever the cause, the +discontented farmers believed that the way to raise prices was to issue +more money. They viewed it as a case of supply and demand. If there was +a small volume of currency in circulation, prices would be low; if there +was a large volume, prices would be high. Hence they looked with favor +upon all plans to increase the amount of money in circulation. First +they advocated more paper notes--greenbacks--and then they turned to +silver as the remedy. The creditors, on the other hand, naturally +approved the reduction of the volume of currency. They wished to see the +greenbacks withdrawn from circulation and gold--a metal more limited in +volume than silver--made the sole basis of the national monetary system. + +=The Battle over the Greenbacks.=--The contest between these factions +began as early as 1866. In that year, Congress enacted a law authorizing +the Treasury to withdraw the greenbacks from circulation. The paper +money party set up a shrill cry of protest, and kept up the fight until, +in 1878, it forced Congress to provide for the continuous re-issue of +the legal tender notes as they came into the Treasury in payment of +taxes and other dues. Then could the friends of easy money rejoice: + + "Thou, Greenback, 'tis of thee + Fair money of the free, + Of thee we sing." + +=Resumption of Specie Payment.=--There was, however, another side to +this victory. The opponents of the greenbacks, unable to stop the +circulation of paper, induced Congress to pass a law in 1875 providing +that on and after January 1, 1879, "the Secretary of the Treasury shall +redeem in coin the United States legal tender notes then outstanding on +their presentation at the office of the Assistant Treasurer of the +United States in the City of New York in sums of not less than fifty +dollars." "The way to resume," John Sherman had said, "is to resume." +When the hour for redemption arrived, the Treasury was prepared with a +large hoard of gold. "On the appointed day," wrote the assistant +secretary, "anxiety reigned in the office of the Treasury. Hour after +hour passed; no news from New York. Inquiry by wire showed that all was +quiet. At the close of the day this message came: '$135,000 of notes +presented for coin--$400,000 of gold for notes.' That was all. +Resumption was accomplished with no disturbance. By five o'clock the +news was all over the land, and the New York bankers were sipping their +tea in absolute safety." + +=The Specie Problem--the Parity of Gold and Silver.=--Defeated in their +efforts to stop "the present suicidal and destructive policy of +contraction," the advocates of an abundant currency demanded an increase +in the volume of silver in circulation. This precipitated one of the +sharpest political battles in American history. The issue turned on +legal as well as economic points. The Constitution gave Congress the +power to coin money and it forbade the states to make anything but gold +and silver legal tender in the payment of debts. It evidently +contemplated the use of both metals in the currency system. Such, at +least, was the view of many eminent statesmen, including no less a +personage than James G. Blaine. The difficulty, however, lay in +maintaining gold and silver coins on a level which would permit them to +circulate with equal facility. Obviously, if the gold in a gold dollar +exceeds the value of the silver in a silver dollar on the open market, +men will hoard gold money and leave silver money in circulation. When, +for example, Congress in 1792 fixed the ratio of the two metals at one +to fifteen--one ounce of gold declared worth fifteen of silver--it was +soon found that gold had been undervalued. When again in 1834 the ratio +was put at one to sixteen, it was found that silver was undervalued. +Consequently the latter metal was not brought in for coinage and silver +almost dropped out of circulation. Many a silver dollar was melted down +by silverware factories. + +=Silver Demonetized in 1873.=--So things stood in 1873. At that time, +Congress, in enacting a mintage law, discontinued the coinage of the +standard silver dollar, then practically out of circulation. This act +was denounced later by the friends of silver as "the crime of '73," a +conspiracy devised by the money power and secretly carried out. This +contention the debates in Congress do not seem to sustain. In the course +of the argument on the mint law it was distinctly said by one speaker at +least: "This bill provides for the making of changes in the legal tender +coin of the country and for substituting as legal tender, coin of only +one metal instead of two as heretofore." + +=The Decline in the Value of Silver.=--Absorbed in the greenback +controversy, the people apparently did not appreciate, at the time, the +significance of the "demonetization" of silver; but within a few years +several events united in making it the center of a political storm. +Germany, having abandoned silver in 1871, steadily increased her demand +for gold. Three years later, the countries of the Latin Union followed +this example, thus helping to enhance the price of the yellow metal. All +the while, new silver lodes, discovered in the Far West, were pouring +into the market great streams of the white metal, bearing down the +price. Then came the resumption of specie payment, which, in effect, +placed the paper money on a gold basis. Within twenty years silver was +worth in gold only about half the price of 1870. + +That there had been a real decline in silver was denied by the friends +of that metal. They alleged that gold had gone up because it had been +given a monopoly in the coinage markets of civilized governments. This +monopoly, they continued, was the fruit of a conspiracy against the +people conceived by the bankers of the world. Moreover, they went on, +the placing of the greenbacks on a gold basis had itself worked a +contraction of the currency; it lowered the prices of labor and produce +to the advantage of the holders of long-term investments bearing a fixed +rate of interest. When wheat sold at sixty-four cents a bushel, their +search for relief became desperate, and they at last concentrated their +efforts on opening the mints of the government for the free coinage of +silver at the ratio of sixteen to one. + +=Republicans and Democrats Divided.=--On this question both Republicans +and Democrats were divided, the line being drawn between the East on the +one hand and the South and West on the other, rather than between the +two leading parties. So trusted a leader as James G. Blaine avowed, in a +speech delivered in the Senate in 1878, that, as the Constitution +required Congress to make both gold and silver the money of the land, +the only question left was that of fixing the ratio between them. He +affirmed, moreover, the main contention of the silver faction that a +reopening of the government mints of the world to silver would bring it +up to its old relation with gold. He admitted also that their most +ominous warnings were well founded, saying: "I believe the struggle now +going on in this country and in other countries for a single gold +standard would, if successful, produce widespread disaster throughout +the commercial world. The destruction of silver as money and the +establishment of gold as the sole unit of value must have a ruinous +effect on all forms of property, except those investments which yield a +fixed return." + +This was exactly the concession that the silver party wanted. +"Three-fourths of the business enterprises of this country are conducted +on borrowed capital," said Senator Jones, of Nevada. "Three-fourths of +the homes and farms that stand in the names of the actual occupants have +been bought on time and a very large proportion of them are mortgaged +for the payment of some part of the purchase money. Under the operation +of a shrinkage in the volume of money, this enormous mass of borrowers, +at the maturity of their respective debts, though nominally paying no +more than the amount borrowed, with interest, are in reality, in the +amount of the principal alone, returning a percentage of value greater +than they received--more in equity than they contracted to pay.... In +all discussions of the subject the creditors attempt to brush aside the +equities involved by sneering at the debtors." + +=The Silver Purchase Act (1878).=--Even before the actual resumption of +specie payment, the advocates of free silver were a power to be reckoned +with, particularly in the Democratic party. They had a majority in the +House of Representatives in 1878 and they carried a silver bill through +that chamber. Blocked by the Republican Senate they accepted a +compromise in the Bland-Allison bill, which provided for huge monthly +purchases of silver by the government for coinage into dollars. So +strong was the sentiment that a two-thirds majority was mustered after +President Hayes vetoed the measure. + +The effect of this act, as some had anticipated, was disappointing. It +did not stay silver on its downward course. Thereupon the silver faction +pressed through Congress in 1886 a bill providing for the issue of paper +certificates based on the silver accumulated in the Treasury. Still +silver continued to fall. Then the advocates of inflation declared that +they would be content with nothing short of free coinage at the ratio of +sixteen to one. If the issue had been squarely presented in 1890, there +is good reason for believing that free silver would have received a +majority in both houses of Congress; but it was not presented. + +=The Sherman Silver Purchase Act and the Bond Sales.=--Republican +leaders, particularly from the East, stemmed the silver tide by a +diversion of forces. They passed the Sherman Act of 1890 providing for +large monthly purchases of silver and for the issue of notes redeemable +in gold or silver at the discretion of the Secretary of the Treasury. In +a clause of superb ambiguity they announced that it was "the established +policy of the United States to maintain the two metals on a parity with +each other upon the present legal ratio or such other ratio as may be +provided by law." For a while silver was buoyed up. Then it turned once +more on its downward course. In the meantime the Treasury was in a sad +plight. To maintain the gold reserve, President Cleveland felt compelled +to sell government bonds; and to his dismay he found that as soon as the +gold was brought in at the front door of the Treasury, notes were +presented for redemption and the gold was quickly carried out at the +back door. Alarmed at the vicious circle thus created, he urged upon +Congress the repeal of the Sherman Silver Purchase Act. For this he was +roundly condemned by many of his own followers who branded his conduct +as "treason to the party"; but the Republicans, especially from the +East, came to his rescue and in 1893 swept the troublesome sections of +the law from the statute book. The anger of the silver faction knew no +bounds, and the leaders made ready for the approaching presidential +campaign. + + +THE PROTECTIVE TARIFF AND TAXATION + +=Fluctuation in Tariff Policy.=--As each of the old parties was divided +on the currency question, it is not surprising that there was some +confusion in their ranks over the tariff. Like the silver issue, the +tariff tended to align the manufacturing East against the agricultural +West and South rather than to cut directly between the two parties. +Still the Republicans on the whole stood firmly by the rates imposed +during the Civil War. If we except the reductions of 1872 which were +soon offset by increases, we may say that those rates were substantially +unchanged for nearly twenty years. When a revision was brought about, +however, it was initiated by Republican leaders. Seeing a huge surplus +of revenue in the Treasury in 1883, they anticipated popular clamor by +revising the tariff on the theory that it ought to be reformed by its +friends rather than by its enemies. On the other hand, it was the +Republicans also who enacted the McKinley tariff bill of 1890, which +carried protection to its highest point up to that time. + +The Democrats on their part were not all confirmed free traders or even +advocates of tariff for revenue only. In Cleveland's first +administration they did attack the protective system in the House, where +they had a majority, and in this they were vigorously supported by the +President. The assault, however, proved to be a futile gesture for it +was blocked by the Republicans in the Senate. When, after the sweeping +victory of 1892, the Democrats in the House again attempted to bring +down the tariff by the Wilson bill of 1894, they were checkmated by +their own party colleagues in the upper chamber. In the end they were +driven into a compromise that looked more like a McKinley than a Calhoun +tariff. The Republicans taunted them with being "babes in the woods." +President Cleveland was so dissatisfied with the bill that he refused to +sign it, allowing it to become a law, on the lapse of ten days, without +his approval. + +=The Income Tax of 1894.=--The advocates of tariff reduction usually +associated with their proposal a tax on incomes. The argument which +they advanced in support of their program was simple. Most of the +industries, they said, are in the East and the protective tariff which +taxes consumers for the benefit of manufacturers is, in effect, a +tribute laid upon the rest of the country. As an offset they offered a +tax on large incomes; this owing to the heavy concentration of rich +people in the East, would fall mainly upon the beneficiaries of +protection. "We propose," said one of them, "to place a part of the +burden upon the accumulated wealth of the country instead of placing it +all upon the consumption of the people." In this spirit the sponsors of +the Wilson tariff bill laid a tax upon all incomes of $4000 a year or +more. + +In taking this step, the Democrats encountered opposition in their own +party. Senator Hill, of New York, turned fiercely upon them, exclaiming: +"The professors with their books, the socialists with their schemes, the +anarchists with their bombs are all instructing the people in the ... +principles of taxation." Even the Eastern Republicans were hardly as +savage in their denunciation of the tax. But all this labor was wasted. +The next year the Supreme Court of the United States declared the income +tax to be a direct tax, and therefore null and void because it was laid +on incomes wherever found and not apportioned among the states according +to population. The fact that four of the nine judges dissented from this +decision was also an index to the diversity of opinion that divided both +parties. + + +THE RAILWAYS AND TRUSTS + +=The Grangers and State Regulation.=--The same uncertainty about the +railways and trusts pervaded the ranks of the Republicans and Democrats. +As to the railways, the first firm and consistent demand for their +regulation came from the West. There the farmers, in the early +seventies, having got control in state legislatures, particularly in +Iowa, Wisconsin, and Illinois, enacted drastic laws prescribing the +maximum charges which companies could make for carrying freight and +passengers. The application of these measures, however, was limited +because the state could not fix the rates for transporting goods and +passengers beyond its own borders. The power of regulating interstate +commerce, under the Constitution, belonged to Congress. + +=The Interstate Commerce Act of 1887.=--Within a few years, the movement +which had been so effective in western legislatures appeared at +Washington in the form of demands for the federal regulation of +interstate rates. In 1887, the pressure became so strong that Congress +created the interstate commerce commission and forbade many abuses on +the part of railways; such as discriminating in charges between one +shipper and another and granting secret rebates to favored persons. This +law was a significant beginning; but it left the main question of +rate-fixing untouched, much to the discontent of farmers and shippers. + +=The Sherman Anti-Trust Law of 1890.=--As in the case of the railways, +attacks upon the trusts were first made in state legislatures, where it +became the fashion to provide severe penalties for those who formed +monopolies and "conspired to enhance prices." Republicans and Democrats +united in the promotion of measures of this kind. As in the case of the +railways also, the movement to curb the trusts soon had spokesmen at +Washington. Though Blaine had declared that "trusts were largely a +private affair with which neither the President nor any private citizen +had any particular right to interfere," it was a Republican Congress +that enacted in 1890 the first measure--the Sherman Anti-Trust +Law--directed against great combinations in business. This act declared +illegal "every contract, combination in the form of trust or otherwise, +or conspiracy in restraint of trade and commerce among the several +states or with foreign nations." + +=The Futility of the Anti-Trust Law.=--Whether the Sherman law was +directed against all combinations or merely those which placed an +"unreasonable restraint" on trade and competition was not apparent. +Senator Platt of Connecticut, a careful statesman of the old school, +averred: "The questions of whether the bill would be operative, of how +it would operate, or whether it was within the power of Congress to +enact it, have been whistled down the wind in this Senate as idle talk +and the whole effort has been to get some bill headed: 'A bill to punish +trusts,' with which to go to the country." Whatever its purpose, its +effect upon existing trusts and upon the formation of new combinations +was negligible. It was practically unenforced by President Harrison and +President Cleveland, in spite of the constant demand for harsh action +against "monopolies." It was patent that neither the Republicans nor the +Democrats were prepared for a war on the trusts to the bitter end. + + +THE MINOR PARTIES AND UNREST + +=The Demands of Dissenting Parties.=--From the election of 1872, when +Horace Greeley made his ill-fated excursion into politics, onward, there +appeared in each presidential campaign one, and sometimes two or more +parties, stressing issues that appealed mainly to wage-earners and +farmers. Whether they chose to call themselves Labor Reformers, +Greenbackers, or Anti-monopolists, their slogans and their platforms all +pointed in one direction. Even the Prohibitionists, who in 1872 started +on their career with a single issue, the abolition of the liquor +traffic, found themselves making declarations of faith on other matters +and hopelessly split over the money question in 1896. + +A composite view of the platforms put forth by the dissenting parties +from the administration of Grant to the close of Cleveland's second term +reveals certain notions common to them all. These included among many +others: the earliest possible payment of the national debt; regulation +of the rates of railways and telegraph companies; repeal of the specie +resumption act of 1875; the issue of legal tender notes by the +government convertible into interest-bearing obligations on demand; +unlimited coinage of silver as well as gold; a graduated inheritance +tax; legislation to take from "land, railroad, money, and other gigantic +corporate monopolies ... the powers they have so corruptly and unjustly +usurped"; popular or direct election of United States Senators; woman +suffrage; and a graduated income tax, "placing the burden of government +on those who can best afford to pay instead of laying it on the farmers +and producers." + +=Criticism of the Old Parties.=--To this long program of measures the +reformers added harsh and acrid criticism of the old parties and +sometimes, it must be said, of established institutions of government. +"We denounce," exclaimed the Labor party in 1888, "the Democratic and +Republican parties as hopelessly and shamelessly corrupt and by reason +of their affiliation with monopolies equally unworthy of the suffrages +of those who do not live upon public plunder." "The United States +Senate," insisted the Greenbackers, "is a body composed largely of +aristocratic millionaires who according to their own party papers +generally purchased their elections in order to protect the great +monopolies which they represent." Indeed, if their platforms are to be +accepted at face value, the Greenbackers believed that the entire +government had passed out of the hands of the people. + +=The Grangers.=--This unsparing, not to say revolutionary, criticism of +American political life, appealed, it seems, mainly to farmers in the +Middle West. Always active in politics, they had, before the Civil War, +cast their lot as a rule with one or the other of the leading parties. +In 1867, however, there grew up among them an association known as the +"Patrons of Husbandry," which was destined to play a large role in the +partisan contests of the succeeding decades. This society, which +organized local lodges or "granges" on principles of secrecy and +fraternity, was originally designed to promote in a general way the +interests of the farmers. Its political bearings were apparently not +grasped at first by its promoters. Yet, appealing as it did to the most +active and independent spirits among the farmers and gathering to itself +the strength that always comes from organization, it soon found itself +in the hands of leaders more or less involved in politics. Where a few +votes are marshaled together in a democracy, there is power. + +=The Greenback Party.=--The first extensive activity of the Grangers was +connected with the attack on the railways in the Middle West which +forced several state legislatures to reduce freight and passenger rates +by law. At the same time, some leaders in the movement, no doubt +emboldened by this success, launched in 1876 a new political party, +popularly known as the Greenbackers, favoring a continued re-issue of +the legal tenders. The beginnings were disappointing; but two years +later, in the congressional elections, the Greenbackers swept whole +sections of the country. Their candidates polled more than a million +votes and fourteen of them were returned to the House of +Representatives. To all outward signs a new and formidable party had +entered the lists. + +The sanguine hopes of the leaders proved to be illusory. The quiet +operations of the resumption act the following year, a revival of +industry from a severe panic which had set in during 1873, the Silver +Purchase Act, and the re-issue of Greenbacks cut away some of the +grounds of agitation. There was also a diversion of forces to the silver +faction which had a substantial support in the silver mine owners of the +West. At all events the Greenback vote fell to about 300,000 in the +election of 1880. A still greater drop came four years later and the +party gave up the ghost, its sponsors returning to their former +allegiance or sulking in their tents. + +=The Rise of the Populist Party.=--Those leaders of the old parties who +now looked for a happy future unvexed by new factions were doomed to +disappointment. The funeral of the Greenback party was hardly over +before there arose two other political specters in the agrarian +sections: the National Farmers' Alliance and Industrial Union, +particularly strong in the South and West; and the Farmers' Alliance, +operating in the North. By 1890 the two orders claimed over three +million members. As in the case of the Grangers many years before, the +leaders among them found an easy way into politics. In 1892 they held a +convention, nominated a candidate for President, and adopted the name of +"People's Party," from which they were known as Populists. Their +platform, in every line, breathed a spirit of radicalism. They declared +that "the newspapers are largely subsidized or muzzled; public opinion +silenced; business prostrate; our homes covered with mortgages; and the +land concentrating in the hands of capitalists.... The fruits of the +toil of millions are boldly stolen to build up colossal fortunes for a +few." Having delivered this sweeping indictment, the Populists put +forward their remedies: the free coinage of silver, a graduated income +tax, postal savings banks, and government ownership of railways and +telegraphs. At the same time they approved the initiative, referendum, +and popular election of Senators, and condemned the use of federal +troops in labor disputes. On this platform, the Populists polled over a +million votes, captured twenty-two presidential electors, and sent a +powerful delegation to Congress. + +=Industrial Distress Augments Unrest.=--The four years intervening +between the campaign of 1892 and the next presidential election brought +forth many events which aggravated the ill-feeling expressed in the +portentous platform of Populism. Cleveland, a consistent enemy of free +silver, gave his powerful support to the gold standard and insisted on +the repeal of the Silver Purchase Act, thus alienating an increasing +number of his own party. In 1893 a grave industrial crisis fell upon the +land: banks and business houses went into bankruptcy with startling +rapidity; factories were closed; idle men thronged the streets hunting +for work; and the prices of wheat and corn dropped to a ruinous level. +Labor disputes also filled the crowded record. A strike at the Pullman +car works in Chicago spread to the railways. Disorders ensued. President +Cleveland, against the protests of the governor of Illinois, John P. +Altgeld, dispatched troops to the scene of action. The United States +district court at Chicago issued an injunction forbidding the president +of the Railway Union, Eugene V. Debs, or his assistants to interfere +with the transmission of the mails or interstate commerce in any form. +For refusing to obey the order, Debs was arrested and imprisoned. With +federal troops in possession of the field, with their leader in jail, +the strikers gave up the battle, defeated but not subdued. To cap the +climax the Supreme Court of the United States, the following year (1895) +declared null and void the income tax law just enacted by Congress, thus +fanning the flames of Populist discontent all over the West and South. + + +THE SOUND MONEY BATTLE OF 1896 + +=Conservative Men Alarmed.=--Men of conservative thought and leaning in +both parties were by this time thoroughly disturbed. They looked upon +the rise of Populism and the growth of labor disputes as the signs of a +revolutionary spirit, indeed nothing short of a menace to American +institutions and ideals. The income tax law of 1894, exclaimed the +distinguished New York advocate, Joseph H. Choate, in an impassioned +speech before the Supreme Court, "is communistic in its purposes and +tendencies and is defended here upon principles as communistic, +socialistic--what shall I call them--populistic as ever have been +addressed to any political assembly in the world." Mr. Justice Field in +the name of the Court replied: "The present assault upon capital is but +the beginning. It will be but the stepping stone to others larger and +more sweeping till our political conditions will become a war of the +poor against the rich." In declaring the income tax unconstitutional, he +believed that he was but averting greater evils lurking under its guise. +As for free silver, nearly all conservative men were united in calling +it a measure of confiscation and repudiation; an effort of the debtors +to pay their obligations with money worth fifty cents on the dollar; the +climax of villainies openly defended; a challenge to law, order, and +honor. + +=The Republicans Come Out for the Gold Standard.=--It was among the +Republicans that this opinion was most widely shared and firmly held. It +was they who picked up the gauge thrown down by the Populists, though a +host of Democrats, like Cleveland and Hill of New York, also battled +against the growing Populist defection in Democratic ranks. When the +Republican national convention assembled in 1896, the die was soon +cast; a declaration of opposition to free silver save by international +agreement was carried by a vote of eight to one. The Republican party, +to use the vigorous language of Mr. Lodge, arrayed itself against "not +only that organized failure, the Democratic party, but all the wandering +forces of political chaos and social disorder ... in these bitter times +when the forces of disorder are loose and the wreckers with their false +lights gather at the shore to lure the ship of state upon the rocks." +Yet it is due to historic truth to state that McKinley, whom the +Republicans nominated, had voted in Congress for the free coinage of +silver, was widely known as a bimetallist, and was only with difficulty +persuaded to accept the unequivocal indorsement of the gold standard +which was pressed upon him by his counselors. Having accepted it, +however, he proved to be a valiant champion, though his major interest +was undoubtedly in the protective tariff. To him nothing was more +reprehensible than attempts "to array class against class, 'the classes +against the masses,' section against section, labor against capital, +'the poor against the rich,' or interest against interest." Such was the +language of his acceptance speech. The whole program of Populism he now +viewed as a "sudden, dangerous, and revolutionary assault upon law and +order." + +=The Democratic Convention at Chicago.=--Never, save at the great +disruption on the eve of the Civil War, did a Democratic national +convention display more feeling than at Chicago in 1896. From the +opening prayer to the last motion before the house, every act, every +speech, every scene, every resolution evoked passions and sowed +dissensions. Departing from long party custom, it voted down in anger a +proposal to praise the administration of the Democratic President, +Cleveland. When the platform with its radical planks, including free +silver, was reported, a veritable storm broke. Senator Hill, trembling +with emotion, protested against the departure from old tests of +Democratic allegiance; against principles that must drive out of the +party men who had grown gray in its service; against revolutionary, +unwise, and unprecedented steps in the history of the party. Senator +Vilas of Wisconsin, in great fervor, avowed that there was no difference +in principle between the free coinage of silver--"the confiscation of +one-half of the credits of the nation for the benefit of debtors"--and +communism itself--"a universal distribution of property." In the triumph +of that cause he saw the beginning of "the overthrow of all law, all +justice, all security and repose in the social order." + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +WILLIAM J. BRYAN IN 1898] + +=The Crown of Thorns Speech.=--The champions of free silver replied in +strident tones. They accused the gold advocates of being the aggressors +who had assailed the labor and the homes of the people. William Jennings +Bryan, of Nebraska, voiced their sentiments in a memorable oration. He +declared that their cause "was as holy as the cause of liberty--the +cause of humanity." He exclaimed that the contest was between the idle +holders of idle capital and the toiling millions. Then he named those +for whom he spoke--the wage-earner, the country lawyer, the small +merchant, the farmer, and the miner. "The man who is employed for wages +is as much a business man as his employer. The attorney in a country +town is as much a business man as the corporation counsel in a great +metropolis. The merchant at the cross roads store is as much a business +man as the merchant of New York. The farmer ... is as much a business +man as the man who goes upon the board of trade and bets upon the price +of grain. The miners who go a thousand feet into the earth or climb two +thousand feet upon the cliffs ... are as much business men as the few +financial magnates who in a back room corner the money of the world.... +It is for these that we speak. We do not come as aggressors. Ours is not +a war of conquest. We are fighting in defense of our homes, our +families, and our posterity. We have petitioned and our petitions have +been scorned. We have entreated and our entreaties have been +disregarded. We have begged and they have mocked when our calamity came. +We beg no longer; we entreat no more; we petition no more. We defy +them.... We shall answer their demands for a gold standard by saying to +them, 'You shall not press upon the brow of labor this crown of thorns. +You shall not crucify mankind upon a cross of gold.'" + +=Bryan Nominated.=--In all the history of national conventions never had +an orator so completely swayed a multitude; not even Yancey in his +memorable plea in the Charleston convention of 1860 when, with grave and +moving eloquence, he espoused the Southern cause against the impending +fates. The delegates, after cheering Mr. Bryan until they could cheer no +more, tore the standards from the floor and gathered around the Nebraska +delegation to renew the deafening applause. The platform as reported was +carried by a vote of two to one and the young orator from the West, +hailed as America's Tiberius Gracchus, was nominated as the Democratic +candidate for President. The South and West had triumphed over the East. +The division was sectional, admittedly sectional--the old combination of +power which Calhoun had so anxiously labored to build up a century +earlier. The Gold Democrats were repudiated in terms which were clear to +all. A few, unable to endure the thought of voting the Republican +ticket, held a convention at Indianapolis where, with the sanction of +Cleveland, they nominated candidates of their own and endorsed the gold +standard in a forlorn hope. + +=The Democratic Platform.=--It was to the call from Chicago that the +Democrats gave heed and the Republicans made answer. The platform on +which Mr. Bryan stood, unlike most party manifestoes, was explicit in +its language and its appeal. It denounced the practice of allowing +national banks to issue notes intended to circulate as money on the +ground that it was "in derogation of the Constitution," recalling +Jackson's famous attack on the Bank in 1832. It declared that tariff +duties should be laid "for the purpose of revenue"--Calhoun's doctrine. +In demanding the free coinage of silver, it recurred to the practice +abandoned in 1873. The income tax came next on the program. The platform +alleged that the law of 1894, passed by a Democratic Congress, was "in +strict pursuance of the uniform decisions of the Supreme Court for +nearly a hundred years," and then hinted that the decision annulling the +law might be reversed by the same body "as it may hereafter be +constituted." + +The appeal to labor voiced by Mr. Bryan in his "crown of thorns" speech +was reinforced in the platform. "As labor creates the wealth of the +country," ran one plank, "we demand the passage of such laws as may be +necessary to protect it in all its rights." Referring to the recent +Pullman strike, the passions of which had not yet died away, the +platform denounced "arbitrary interference by federal authorities in +local affairs as a violation of the Constitution of the United States +and a crime against free institutions." A special objection was lodged +against "government by injunction as a new and highly dangerous form of +oppression by which federal judges, in contempt of the laws of states +and rights of citizens, become at once legislators, judges, and +executioners." The remedy advanced was a federal law assuring trial by +jury in all cases of contempt in labor disputes. Having made this +declaration of faith, the Democrats, with Mr. Bryan at the head, raised +their standard of battle. + +=The Heated Campaign.=--The campaign which ensued outrivaled in the +range of its educational activities and the bitterness of its tone all +other political conflicts in American history, not excepting the fateful +struggle of 1860. Immense sums of money were contributed to the funds of +both parties. Railway, banking, and other corporations gave generously +to the Republicans; the silver miners, less lavishly but with the same +anxiety, supported the Democrats. The country was flooded with +pamphlets, posters, and handbills. Every public forum, from the great +auditoriums of the cities to the "red schoolhouses" on the countryside, +was occupied by the opposing forces. + +Mr. Bryan took the stump himself, visiting all parts of the country in +special trains and addressing literally millions of people in the open +air. Mr. McKinley chose the older and more formal plan. He received +delegations at his home in Canton and discussed the issues of the +campaign from his front porch, leaving to an army of well-organized +orators the task of reaching the people in their home towns. Parades, +processions, and monster demonstrations filled the land with politics. +Whole states were polled in advance by the Republicans and the doubtful +voters personally visited by men equipped with arguments and literature. +Manufacturers, frightened at the possibility of disordered public +credit, announced that they would close their doors if the Democrats won +the election. Men were dismissed from public and private places on +account of their political views, one eminent college president being +forced out for advocating free silver. The language employed by +impassioned and embittered speakers on both sides roused the public to a +state of frenzy, once more showing the lengths to which men could go in +personal and political abuse. + +=The Republican Victory.=--The verdict of the nation was decisive. +McKinley received 271 of the 447 electoral votes, and 7,111,000 popular +votes as against Bryan's 6,509,000. The congressional elections were +equally positive although, on account of the composition of the Senate, +the "hold-over" Democrats and Populists still enjoyed a power out of +proportion to their strength as measured at the polls. Even as it was, +the Republicans got full control of both houses--a dominion of the +entire government which they were to hold for fourteen years--until the +second half of Mr. Taft's administration, when they lost possession of +the House of Representatives. The yoke of indecision was broken. The +party of sound finance and protective tariffs set out upon its lease of +power with untroubled assurance. + + +REPUBLICAN MEASURES AND RESULTS + +=The Gold Standard and the Tariff.=--Yet strange as it may seem, the +Republicans did not at once enact legislation making the gold dollar the +standard for the national currency. Not until 1900 did they take that +positive step. In his first inaugural President McKinley, as if still +uncertain in his own mind or fearing a revival of the contest just +closed, placed the tariff, not the money question, in the forefront. +"The people have decided," he said, "that such legislation should be had +as will give ample protection and encouragement to the industries and +development of our country." Protection for American industries, +therefore, he urged, is the task before Congress. "With adequate revenue +secured, but not until then, we can enter upon changes in our fiscal +laws." As the Republicans had only forty-six of the ninety Senators, and +at least four of them were known advocates of free silver, the +discretion exercised by the President in selecting the tariff for +congressional debate was the better part of valor. + +Congress gave heed to the warning. Under the direction of Nelson P. +Dingley, whose name was given to the bill, a tariff measure levying the +highest rates yet laid in the history of American imposts was prepared +and driven through the House of Representatives. The opposition +encountered in the Senate, especially from the West, was overcome by +concessions in favor of that section; but the duties on sugar, tin, +steel, lumber, hemp, and in fact all of the essential commodities +handled by combinations and trusts, were materially raised. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +PRESIDENT MCKINLEY AND HIS CABINET] + +=Growth of Combinations.=--The years that followed the enactment of the +Dingley law were, whatever the cause, the most prosperous the country +had witnessed for many a decade. Industries of every kind were soon +running full blast; labor was employed; commerce spread more swiftly +than ever to the markets of the world. Coincident with this progress was +the organization of the greatest combinations and trusts the world had +yet seen. In 1899 the smelters formed a trust with a capital of +$65,000,000; in the same year the Standard Oil Company with a capital of +over one hundred millions took the place of the old trust; and the +Copper Trust was incorporated under the laws of New Jersey, its par +value capital being fixed shortly afterward at $175,000,000. A year +later the National Sugar Refining Company, of New Jersey, started with a +capital of $90,000,000, adopting the policy of issuing to the +stockholders no public statement of its earnings or financial condition. +Before another twelvemonth had elapsed all previous corporate financing +was reduced to small proportions by the flotation of the United States +Steel Corporation with a capital of more than a billion dollars, an +enterprise set in motion by the famous Morgan banking house of New York. + +In nearly all these gigantic undertakings, the same great leaders in +finance were more or less intimately associated. To use the language of +an eminent authority: "They are all allied and intertwined by their +various mutual interests. For instance, the Pennsylvania Railroad +interests are on the one hand allied with the Vanderbilts and on the +other with the Rockefellers. The Vanderbilts are closely allied with the +Morgan group.... Viewed as a whole we find the dominating influences in +the trusts to be made up of a network of large and small capitalists, +many allied to one another by ties of more or less importance, but all +being appendages to or parts of the greater groups which are themselves +dependent on and allied with the two mammoth or Rockefeller and Morgan +groups. These two mammoth groups jointly ... constitute the heart of the +business and commercial life of the nation." Such was the picture of +triumphant business enterprise drawn by a financier within a few years +after the memorable campaign of 1896. + +America had become one of the first workshops of the world. It was, by +virtue of the closely knit organization of its business and finance, one +of the most powerful and energetic leaders in the struggle of the giants +for the business of the earth. The capital of the Steel Corporation +alone was more than ten times the total national debt which the apostles +of calamity in the days of Washington and Hamilton declared the nation +could never pay. American industry, filling domestic markets to +overflowing, was ready for new worlds to conquer. + + +=References= + +F.W. Taussig, _Tariff History of the United States_. + +J.L. Laughlin, _Bimetallism in the United States_. + +A.B. Hepburn, _History of Coinage and Currency in the United States_. + +E.R.A. Seligman, _The Income Tax_. + +S.J. Buck, _The Granger Movement_ (Harvard Studies). + +F.H. Dixon, _State Railroad Control_. + +H.R. Meyer, _Government Regulation of Railway Rates_. + +W.Z. Ripley (editor), _Trusts, Pools, and Corporations_. + +R.T. Ely, _Monopolies and Trusts_. + +J.B. Clark, _The Control of Trusts_. + + +=Questions= + +1. What proof have we that the political parties were not clearly +divided over issues between 1865 and 1896? + +2. Why is a fall in prices a loss to farmers and a gain to holders of +fixed investments? + +3. Explain the theory that the quantity of money determines the prices +of commodities. + +4. Why was it difficult, if not impossible, to keep gold and silver at a +parity? + +5. What special conditions favored a fall in silver between 1870 and +1896? + +6. Describe some of the measures taken to raise the value of silver. + +7. Explain the relation between the tariff and the income tax in 1894. + +8. How did it happen that the farmers led in regulating railway rates? + +9. Give the terms of the Sherman Anti-Trust Act. What was its immediate +effect? + +10. Name some of the minor parties. Enumerate the reforms they +advocated. + +11. Describe briefly the experiments of the farmers in politics. + +12. How did industrial conditions increase unrest? + +13. Why were conservative men disturbed in the early nineties? + +14. Explain the Republican position in 1896. + +15. Give Mr. Bryan's doctrines in 1896. Enumerate the chief features of +the Democratic platform. + +16. What were the leading measures adopted by the Republicans after +their victory in 1896? + + +=Research Topics= + +=Greenbacks and Resumption.=--Dewey, _Financial History of the United +States_ (6th ed.), Sections 122-125, 154, and 378; MacDonald, +_Documentary Source Book of American History_, pp. 446, 566; Hart, +_American History Told by Contemporaries_, Vol. IV, pp. 531-533; Rhodes, +_History of the United States_, Vol. VIII, pp. 97-101. + +=Demonetization and Coinage of Silver.=--Dewey, _Financial History_, +Sections 170-173, 186, 189, 194; MacDonald, _Documentary Source Book_, +pp. 174, 573, 593, 595; Hart, _Contemporaries_, Vol. IV, pp. 529-531; +Rhodes, _History_, Vol. VIII, pp. 93-97. + +=Free Silver and the Campaign of 1896.=--Dewey, _National Problems_ +(American Nation Series), pp. 220-237, 314-328; Hart, _Contemporaries_, +Vol. IV, pp. 533-538. + +=Tariff Revision.=--Dewey, _Financial History_, Sections 167, 180, 181, +187, 192, 196; Hart, _Contemporaries_, Vol. IV, pp. 518-525; Rhodes, +_History_, Vol. VIII, pp. 168-179, 346-351, 418-422. + +=Federal Regulation of Railways.=--Dewey, _National Problems_, pp. +91-111; MacDonald, _Documentary Source Book_, pp. 581-590; Hart, +_Contemporaries_, Vol. IV, pp. 521-523; Rhodes, _History_, Vol. VIII, +pp. 288-292. + +=The Rise and Regulation of Trusts.=--Dewey, _National Problems_, pp. +188-202; MacDonald, _Documentary Source Book_, pp. 591-593. + +=The Grangers and Populism.=--Paxson, _The New Nation_ (Riverside +Series), pp. 20-37, 177-191, 208-223. + +=General Analysis of Domestic Problems.=--_Syllabus in History_ (New +York State, 1920), pp. 137-142. + + + + +CHAPTER XX + +AMERICA A WORLD POWER (1865-1900) + + +It has now become a fashion, sanctioned by wide usage and by eminent +historians, to speak of America, triumphant over Spain and possessed of +new colonies, as entering the twentieth century in the role of "a world +power," for the first time. Perhaps at this late day, it is useless to +protest against the currency of the idea. Nevertheless, the truth is +that from the fateful moment in March, 1775, when Edmund Burke unfolded +to his colleagues in the British Parliament the resources of an +invincible America, down to the settlement at Versailles in 1919 closing +the drama of the World War, this nation has been a world power, +influencing by its example, by its institutions, by its wealth, trade, +and arms the course of international affairs. And it should be said also +that neither in the field of commercial enterprise nor in that of +diplomacy has it been wanting in spirit or ingenuity. + +When John Hay, Secretary of State, heard that an American citizen, +Perdicaris, had been seized by Raisuli, a Moroccan bandit, in 1904, he +wired his brusque message: "We want Perdicaris alive or Raisuli dead." +This was but an echo of Commodore Decatur's equally characteristic +answer, "Not a minute," given nearly a hundred years before to the +pirates of Algiers begging for time to consider whether they would cease +preying upon American merchantmen. Was it not as early as 1844 that the +American commissioner, Caleb Cushing, taking advantage of the British +Opium War on China, negotiated with the Celestial Empire a successful +commercial treaty? Did he not then exultantly exclaim: "The laws of the +Union follow its citizens and its banner protects them even within the +domain of the Chinese Empire"? Was it not almost half a century before +the battle of Manila Bay in 1898, that Commodore Perry with an adequate +naval force "gently coerced Japan into friendship with us," leading all +the nations of the earth in the opening of that empire to the trade of +the Occident? Nor is it inappropriate in this connection to recall the +fact that the Monroe Doctrine celebrates in 1923 its hundredth +anniversary. + + +AMERICAN FOREIGN RELATIONS (1865-98) + +=French Intrigues in Mexico Blocked.=--Between the war for the union and +the war with Spain, the Department of State had many an occasion to +present the rights of America among the powers of the world. Only a +little while after the civil conflict came to a close, it was called +upon to deal with a dangerous situation created in Mexico by the +ambitions of Napoleon III. During the administration of Buchanan, Mexico +had fallen into disorder through the strife of the Liberal and the +Clerical parties; the President asked for authority to use American +troops to bring to a peaceful haven "a wreck upon the ocean, drifting +about as she is impelled by different factions." Our own domestic crisis +then intervened. + +Observing the United States heavily involved in its own problems, the +great powers, England, France, and Spain, decided in the autumn of 1861 +to take a hand themselves in restoring order in Mexico. They entered +into an agreement to enforce the claims of their citizens against Mexico +and to protect their subjects residing in that republic. They invited +the United States to join them, and, on meeting a polite refusal, they +prepared for a combined military and naval demonstration on their own +account. In the midst of this action England and Spain, discovering the +sinister purposes of Napoleon, withdrew their troops and left the field +to him. + +The French Emperor, it was well known, looked with jealousy upon the +growth of the United States and dreamed of establishing in the Western +hemisphere an imperial power to offset the American republic. +Intervention to collect debts was only a cloak for his deeper designs. +Throwing off that guise in due time, he made the Archduke Maximilian, a +brother of the ruler of Austria, emperor in Mexico, and surrounded his +throne by French soldiers, in spite of all protests. + +This insolent attack upon the Mexican republic, deeply resented in the +United States, was allowed to drift in its course until 1865. At that +juncture General Sheridan was dispatched to the Mexican border with a +large armed force; General Grant urged the use of the American army to +expel the French from this continent. The Secretary of State, Seward, +counseled negotiation first, and, applying the Monroe Doctrine, was able +to prevail upon Napoleon III to withdraw his troops. Without the support +of French arms, the sham empire in Mexico collapsed like a house of +cards and the unhappy Maximilian, the victim of French ambition and +intrigue, met his death at the hands of a Mexican firing squad. + +=Alaska Purchased.=--The Mexican affair had not been brought to a close +before the Department of State was busy with negotiations which resulted +in the purchase of Alaska from Russia. The treaty of cession, signed on +March 30, 1867, added to the United States a domain of nearly six +hundred thousand square miles, a territory larger than Texas and nearly +three-fourths the size of the Louisiana purchase. Though it was a +distant colony separated from our continental domain by a thousand miles +of water, no question of "imperialism" or "colonization foreign to +American doctrines" seems to have been raised at the time. The treaty +was ratified promptly by the Senate. The purchase price, $7,200,000, was +voted by the House of Representatives after the display of some +resentment against a system that compelled it to appropriate money to +fulfill an obligation which it had no part in making. Seward, who +formulated the treaty, rejoiced, as he afterwards said, that he had kept +Alaska out of the hands of England. + +=American Interest in the Caribbean.=--Having achieved this diplomatic +triumph, Seward turned to the increase of American power in another +direction. He negotiated, with Denmark, a treaty providing for the +purchase of the islands of St. John and St. Thomas in the West Indies, +strategic points in the Caribbean for sea power. This project, long +afterward brought to fruition by other men, was defeated on this +occasion by the refusal of the Senate to ratify the treaty. Evidently it +was not yet prepared to exercise colonial dominion over other races. + +Undaunted by the misadventure in Caribbean policies, President Grant +warmly advocated the acquisition of Santo Domingo. This little republic +had long been in a state of general disorder. In 1869 a treaty of +annexation was concluded with its president. The document Grant +transmitted to the Senate with his cordial approval, only to have it +rejected. Not at all changed in his opinion by the outcome of his +effort, he continued to urge the subject of annexation. Even in his last +message to Congress he referred to it, saying that time had only proved +the wisdom of his early course. The addition of Santo Domingo to the +American sphere of protection was the work of a later generation. The +State Department, temporarily checked, had to bide its time. + +=The _Alabama_ Claims Arbitrated.=--Indeed, it had in hand a far more +serious matter, a vexing issue that grew out of Civil War diplomacy. The +British government, as already pointed out in other connections, had +permitted Confederate cruisers, including the famous _Alabama_, built in +British ports, to escape and prey upon the commerce of the Northern +states. This action, denounced at the time by our government as a grave +breach of neutrality as well as a grievous injury to American citizens, +led first to remonstrances and finally to repeated claims for damages +done to American ships and goods. For a long time Great Britain was +firm. Her foreign secretary denied all obligations in the premises, +adding somewhat curtly that "he wished to say once for all that Her +Majesty's government disclaimed any responsibility for the losses and +hoped that they had made their position perfectly clear." Still +President Grant was not persuaded that the door of diplomacy, though +closed, was barred. Hamilton Fish, his Secretary of State, renewed the +demand. Finally he secured from the British government in 1871 the +treaty of Washington providing for the arbitration not merely of the +_Alabama_ and other claims but also all points of serious controversy +between the two countries. + +The tribunal of arbitration thus authorized sat at Geneva in +Switzerland, and after a long and careful review of the arguments on +both sides awarded to the United States the lump sum of $15,500,000 to +be distributed among the American claimants. The damages thus allowed +were large, unquestionably larger than strict justice required and it is +not surprising that the decision excited much adverse comment in +England. Nevertheless, the prompt payment by the British government +swept away at once a great cloud of ill-feeling in America. Moreover, +the spectacle of two powerful nations choosing the way of peaceful +arbitration to settle an angry dispute seemed a happy, if illusory, omen +of a modern method for avoiding the arbitrament of war. + +=Samoa.=--If the Senate had its doubts at first about the wisdom of +acquiring strategic points for naval power in distant seas, the same +could not be said of the State Department or naval officers. In 1872 +Commander Meade, of the United States navy, alive to the importance of +coaling stations even in mid-ocean, made a commercial agreement with the +chief of Tutuila, one of the Samoan Islands, far below the equator, in +the southern Pacific, nearer to Australia than to California. This +agreement, providing among other things for our use of the harbor of +Pago Pago as a naval base, was six years later changed into a formal +treaty ratified by the Senate. + +Such enterprise could not escape the vigilant eyes of England and +Germany, both mindful of the course of the sea power in history. The +German emperor, seizing as a pretext a quarrel between his consul in the +islands and a native king, laid claim to an interest in the Samoan +group. England, aware of the dangers arising from German outposts in the +southern seas so near to Australia, was not content to stand aside. So +it happened that all three countries sent battleships to the Samoan +waters, threatening a crisis that was fortunately averted by friendly +settlement. If, as is alleged, Germany entertained a notion of +challenging American sea power then and there, the presence of British +ships must have dispelled that dream. + +The result of the affair was a tripartite agreement by which the three +powers in 1889 undertook a protectorate over the islands. But joint +control proved unsatisfactory. There was constant friction between the +Germans and the English. The spheres of authority being vague and open +to dispute, the plan had to be abandoned at the end of ten years. +England withdrew altogether, leaving to Germany all the islands except +Tutuila, which was ceded outright to the United States. Thus one of the +finest harbors in the Pacific, to the intense delight of the American +navy, passed permanently under American dominion. Another triumph in +diplomacy was set down to the credit of the State Department. + +=Cleveland and the Venezuela Affair.=--In the relations with South +America, as well as in those with the distant Pacific, the diplomacy of +the government at Washington was put to the test. For some time it had +been watching a dispute between England and Venezuela over the western +boundary of British Guiana and, on an appeal from Venezuela, it had +taken a lively interest in the contest. In 1895 President Cleveland saw +that Great Britain would yield none of her claims. After hearing the +arguments of Venezuela, his Secretary of State, Richard T. Olney, in a +note none too conciliatory, asked the British government whether it was +willing to arbitrate the points in controversy. This inquiry he +accompanied by a warning to the effect that the United States could not +permit any European power to contest its mastery in this hemisphere. +"The United States," said the Secretary, "is practically sovereign on +this continent and its fiat is law upon the subjects to which it +confines its interposition.... Its infinite resources, combined with its +isolated position, render it master of the situation and practically +invulnerable against any or all other powers." + +The reply evoked from the British government by this strong statement +was firm and clear. The Monroe Doctrine, it said, even if not so widely +stretched by interpretation, was not binding in international law; the +dispute with Venezuela was a matter of interest merely to the parties +involved; and arbitration of the question was impossible. This response +called forth President Cleveland's startling message of 1895. He asked +Congress to create a commission authorized to ascertain by researches +the true boundary between Venezuela and British Guiana. He added that it +would be the duty of this country "to resist by every means in its +power, as a willful aggression upon its rights and interests, the +appropriation by Great Britain of any lands or the exercise of +governmental jurisdiction over any territory which, after investigation, +we have determined of right belongs to Venezuela." The serious character +of this statement he thoroughly understood. He declared that he was +conscious of his responsibilities, intimating that war, much as it was +to be deplored, was not comparable to "a supine submission to wrong and +injustice and the consequent loss of national self-respect and honor." + +[Illustration: GROVER CLEVELAND] + +The note of defiance which ran through this message, greeted by shrill +cries of enthusiasm in many circles, was viewed in other quarters as a +portent of war. Responsible newspapers in both countries spoke of an +armed settlement of the dispute as inevitable. Congress created the +commission and appropriated money for the investigation; a body of +learned men was appointed to determine the merits of the conflicting +boundary claims. The British government, deaf to the clamor of the +bellicose section of the London press, deplored the incident, +courteously replied in the affirmative to a request for assistance in +the search for evidence, and finally agreed to the proposition that the +issue be submitted to arbitration. The outcome of this somewhat perilous +dispute contributed not a little to Cleveland's reputation as "a +sterling representative of the true American spirit." This was not +diminished when the tribunal of arbitration found that Great Britain was +on the whole right in her territorial claims against Venezuela. + +=The Annexation of Hawaii.=--While engaged in the dangerous Venezuela +controversy, President Cleveland was compelled by a strange turn in +events to consider the annexation of the Hawaiian Islands in the +mid-Pacific. For more than half a century American missionaries had been +active in converting the natives to the Christian faith and enterprising +American business men had been developing the fertile sugar plantations. +Both the Department of State and the Navy Department were fully +conscious of the strategic relation of the islands to the growth of sea +power and watched with anxiety any developments likely to bring them +under some other Dominion. + +The country at large was indifferent, however, until 1893, when a +revolution, headed by Americans, broke out, ending in the overthrow of +the native government, the abolition of the primitive monarchy, and the +retirement of Queen Liliuokalani to private life. This crisis, a +repetition of the Texas affair in a small theater, was immediately +followed by a demand from the new Hawaiian government for annexation to +the United States. President Harrison looked with favor on the proposal, +negotiated the treaty of annexation, and laid it before the Senate for +approval. There it still rested when his term of office was brought to a +close. + +Harrison's successor, Cleveland, it was well known, had doubts about the +propriety of American action in Hawaii. For the purpose of making an +inquiry into the matter, he sent a special commissioner to the islands. +On the basis of the report of his agent, Cleveland came to the +conclusion that "the revolution in the island kingdom had been +accomplished by the improper use of the armed forces of the United +States and that the wrong should be righted by a restoration of the +queen to her throne." Such being his matured conviction, though the +facts upon which he rested it were warmly controverted, he could do +nothing but withdraw the treaty from the Senate and close the incident. + +To the Republicans this sharp and cavalier disposal of their plans, +carried out in a way that impugned the motives of a Republican +President, was nothing less than "a betrayal of American interests." In +their platform of 1896 they made clear their position: "Our foreign +policy should be at all times firm, vigorous, and dignified and all our +interests in the Western hemisphere carefully watched and guarded. The +Hawaiian Islands should be controlled by the United States and no +foreign power should be permitted to interfere with them." There was no +mistaking this view of the issue. As the vote in the election gave +popular sanction to Republican policies, Congress by a joint resolution, +passed on July 6, 1898, annexed the islands to the United States and +later conferred upon them the ordinary territorial form of government. + + +CUBA AND THE SPANISH WAR + +=Early American Relations with Cuba.=--The year that brought Hawaii +finally under the American flag likewise drew to a conclusion another +long controversy over a similar outpost in the Atlantic, one of the last +remnants of the once glorious Spanish empire--the island of Cuba. + +For a century the Department of State had kept an anxious eye upon this +base of power, knowing full well that both France and England, already +well established in the West Indies, had their attention also fixed upon +Cuba. In the administration of President Fillmore they had united in +proposing to the United States a tripartite treaty guaranteeing Spain in +her none too certain ownership. This proposal, squarely rejected, +furnished the occasion for a statement of American policy which stood +the test of all the years that followed; namely, that the affair was one +between Spain and the United States alone. + +In that long contest in the United States for the balance of power +between the North and South, leaders in the latter section often thought +of bringing Cuba into the union to offset the free states. An +opportunity to announce their purposes publicly was afforded in 1854 by +a controversy over the seizure of an American ship by Cuban authorities. +On that occasion three American ministers abroad, stationed at Madrid, +Paris, and London respectively, held a conference and issued the +celebrated "Ostend Manifesto." They united in declaring that Cuba, by +her geographical position, formed a part of the United States, that +possession by a foreign power was inimical to American interests, and +that an effort should be made to purchase the island from Spain. In case +the owner refused to sell, they concluded, with a menacing flourish, "by +every law, human and divine, we shall be justified in wresting it from +Spain if we possess the power." This startling proclamation to the world +was promptly disowned by the United States government. + +[Illustration: _=An old cartoon.=_ + +A SIGHT TOO BAD + +_Struggling Cuba._ "You must be awfully near-sighted, Mr. President, not +to recognize me." _U.S.G._ "No, I am far-sighted: for I can recognize +France."] + +=Revolutions in Cuba.=--For nearly twenty years afterwards the Cuban +question rested. Then it was revived in another form during President +Grant's administrations, when the natives became engaged in a +destructive revolt against Spanish officials. For ten years--1868-78--a +guerrilla warfare raged in the island. American citizens, by virtue of +their ancient traditions of democracy, naturally sympathized with a war +for independence and self-government. Expeditions to help the insurgents +were fitted out secretly in American ports. Arms and supplies were +smuggled into Cuba. American soldiers of fortune joined their ranks. The +enforcement of neutrality against the friends of Cuban independence, no +pleasing task for a sympathetic President, the protection of American +lives and property in the revolutionary area, and similar matters kept +our government busy with Cuba for a whole decade. + +A brief lull in Cuban disorders was followed in 1895 by a renewal of the +revolutionary movement. The contest between the rebels and the Spanish +troops, marked by extreme cruelty and a total disregard for life and +property, exceeded all bounds of decency, and once more raised the old +questions that had tormented Grant's administration. Gomez, the leader +of the revolt, intent upon provoking American interference, laid waste +the land with fire and sword. By a proclamation of November 6, 1895, he +ordered the destruction of sugar plantations and railway connections and +the closure of all sugar factories. The work of ruin was completed by +the ruthless Spanish general, Weyler, who concentrated the inhabitants +from rural regions into military camps, where they died by the hundreds +of disease and starvation. Stories of the atrocities, bad enough in +simple form, became lurid when transmuted into American news and deeply +moved the sympathies of the American people. Sermons were preached about +Spanish misdeeds; orators demanded that the Cubans be sustained "in +their heroic struggle for independence"; newspapers, scouting the +ordinary forms of diplomatic negotiation, spurned mediation and demanded +intervention and war if necessary. + +[Illustration: _Underwood and Underwood, N.Y._ + +CUBAN REVOLUTIONISTS] + +=President Cleveland's Policy.=--Cleveland chose the way of peace. He +ordered the observance of the rule of neutrality. He declined to act on +a resolution of Congress in favor of giving to the Cubans the rights of +belligerents. Anxious to bring order to the distracted island, he +tendered to Spain the good offices of the United States as mediator in +the contest--a tender rejected by the Spanish government with the broad +hint that President Cleveland might be more vigorous in putting a stop +to the unlawful aid in money, arms, and supplies, afforded to the +insurgents by American sympathizers. Thereupon the President returned to +the course he had marked out for himself, leaving "the public nuisance" +to his successor, President McKinley. + +=Republican Policies.=--The Republicans in 1897 found themselves in a +position to employ that "firm, vigorous, and dignified" foreign policy +which they had approved in their platform. They had declared: "The +government of Spain having lost control of Cuba and being unable to + +protect the property or lives of resident American citizens or to comply +with its treaty obligations, we believe that the government of the +United States should actively use its influence and good offices to +restore peace and give independence to the island." The American +property in Cuba to which the Republicans referred in their platform +amounted by this time to more than fifty million dollars; the commerce +with the island reached more than one hundred millions annually; and the +claims of American citizens against Spain for property destroyed totaled +sixteen millions. To the pleas of humanity which made such an effective +appeal to the hearts of the American people, there were thus added +practical considerations of great weight. + +=President McKinley Negotiates.=--In the face of the swelling tide of +popular opinion in favor of quick, drastic, and positive action, +McKinley chose first the way of diplomacy. A short time after his +inauguration he lodged with the Spanish government a dignified protest +against its policies in Cuba, thus opening a game of thrust and parry +with the suave ministers at Madrid. The results of the exchange of +notes were the recall of the obnoxious General Weyler, the appointment +of a governor-general less bloodthirsty in his methods, a change in the +policy of concentrating civilians in military camps, and finally a +promise of "home rule" for Cuba. There is no doubt that the Spanish +government was eager to avoid a war that could have but one outcome. The +American minister at Madrid, General Woodford, was convinced that firm +and patient pressure would have resulted in the final surrender of Cuba +by the Spanish government. + +=The De Lome and the _Maine_ Incidents.=--Such a policy was defeated by +events. In February, 1898, a private letter written by Senor de Lome, +the Spanish ambassador at Washington, expressing contempt for the +President of the United States, was filched from the mails and passed +into the hands of a journalist, William R. Hearst, who published it to +the world. In the excited state of American opinion, few gave heed to +the grave breach of diplomatic courtesy committed by breaking open +private correspondence. The Spanish government was compelled to recall +De Lome, thus officially condemning his conduct. + +At this point a far more serious crisis put the pacific relations of the +two negotiating countries in dire peril. On February 15, the battleship +_Maine_, riding in the harbor of Havana, was blown up and sunk, carrying +to death two officers and two hundred and fifty-eight members of the +crew. This tragedy, ascribed by the American public to the malevolence +of Spanish officials, profoundly stirred an already furious nation. +When, on March 21, a commission of inquiry reported that the ill-fated +ship had been blown up by a submarine mine which had in turn set off +some of the ship's magazines, the worst suspicions seemed confirmed. If +any one was inclined to be indifferent to the Cuban war for +independence, he was now met by the vehement cry: "Remember the +_Maine_!" + +=Spanish Concessions.=--Still the State Department, under McKinley's +steady hand, pursued the path of negotiation, Spain proving more pliable +and more ready with promises of reform in the island. Early in April, +however, there came a decided change in the tenor of American diplomacy. +On the 4th, McKinley, evidently convinced that promises did not mean +performances, instructed our minister at Madrid to warn the Spanish +government that as no effective armistice had been offered to the +Cubans, he would lay the whole matter before Congress. This decision, +every one knew, from the temper of Congress, meant war--a prospect which +excited all the European powers. The Pope took an active interest in the +crisis. France and Germany, foreseeing from long experience in world +politics an increase of American power and prestige through war, sought +to prevent it. Spain, hopeless and conscious of her weakness, at last +dispatched to the President a note promising to suspend hostilities, to +call a Cuban parliament, and to grant all the autonomy that could be +reasonably asked. + +=President McKinley Calls for War.=--For reasons of his own--reasons +which have never yet been fully explained--McKinley ignored the final +program of concessions presented by Spain. At the very moment when his +patient negotiations seemed to bear full fruit, he veered sharply from +his course and launched the country into the war by sending to Congress +his militant message of April 11, 1898. Without making public the last +note he had received from Spain, he declared that he was brought to the +end of his effort and the cause was in the hands of Congress. Humanity, +the protection of American citizens and property, the injuries to +American commerce and business, the inability of Spain to bring about +permanent peace in the island--these were the grounds for action that +induced him to ask for authority to employ military and naval forces in +establishing a stable government in Cuba. They were sufficient for a +public already straining at the leash. + +=The Resolution of Congress.=--There was no doubt of the outcome when +the issue was withdrawn from diplomacy and placed in charge of Congress. +Resolutions were soon introduced into the House of Representatives +authorizing the President to employ armed force in securing peace and +order in the island and "establishing by the free action of the people +thereof a stable and independent government of their own." To the form +and spirit of this proposal the Democrats and Populists took exception. +In the Senate, where they were stronger, their position had to be +reckoned with by the narrow Republican majority. As the resolution +finally read, the independence of Cuba was recognized; Spain was called +upon to relinquish her authority and withdraw from the island; and the +President was empowered to use force to the extent necessary to carry +the resolutions into effect. Furthermore the United States disclaimed +"any disposition or intention to exercise sovereignty, jurisdiction, or +control over said island except for the pacification thereof." Final +action was taken by Congress on April 19, 1898, and approved by the +President on the following day. + +=War and Victory.=--Startling events then followed in swift succession. +The navy, as a result in no small measure of the alertness of Theodore +Roosevelt, Assistant Secretary of the Department, was ready for the +trial by battle. On May 1, Commodore Dewey at Manila Bay shattered the +Spanish fleet, marking the doom of Spanish dominion in the Philippines. +On July 3, the Spanish fleet under Admiral Cervera, in attempting to +escape from Havana, was utterly destroyed by American forces under +Commodore Schley. On July 17, Santiago, invested by American troops +under General Shafter and shelled by the American ships, gave up the +struggle. On July 25 General Miles landed in Porto Rico. On August 13, +General Merritt and Admiral Dewey carried Manila by storm. The war was +over. + +=The Peace Protocol.=--Spain had already taken cognizance of stern +facts. As early as July 26, 1898, acting through the French ambassador, +M. Cambon, the Madrid government approached President McKinley for a +statement of the terms on which hostilities could be brought to a close. +After some skirmishing Spain yielded reluctantly to the ultimatum. On +August 12, the preliminary peace protocol was signed, stipulating that +Cuba should be free, Porto Rico ceded to the United States, and Manila +occupied by American troops pending the formal treaty of peace. On +October 1, the commissioners of the two countries met at Paris to bring +about the final settlement. + +=Peace Negotiations.=--When the day for the first session of the +conference arrived, the government at Washington apparently had not made +up its mind on the final disposition of the Philippines. Perhaps, before +the battle of Manila Bay, not ten thousand people in the United States +knew or cared where the Philippines were. Certainly there was in the +autumn of 1898 no decided opinion as to what should be done with the +fruits of Dewey's victory. President McKinley doubtless voiced the +sentiment of the people when he stated to the peace commissioners on the +eve of their departure that there had originally been no thought of +conquest in the Pacific. + +The march of events, he added, had imposed new duties on the country. +"Incidental to our tenure in the Philippines," he said, "is the +commercial opportunity to which American statesmanship cannot be +indifferent. It is just to use every legitimate means for the +enlargement of American trade." On this ground he directed the +commissioners to accept not less than the cession of the island of +Luzon, the chief of the Philippine group, with its harbor of Manila. It +was not until the latter part of October that he definitely instructed +them to demand the entire archipelago, on the theory that the occupation +of Luzon alone could not be justified "on political, commercial, or +humanitarian grounds." This departure from the letter of the peace +protocol was bitterly resented by the Spanish agents. It was with +heaviness of heart that they surrendered the last sign of Spain's +ancient dominion in the far Pacific. + +=The Final Terms of Peace.=--The treaty of peace, as finally agreed +upon, embraced the following terms: the independence of Cuba; the +cession of Porto Rico, Guam, and the Philippines to the United States; +the settlement of claims filed by the citizens of both countries; the +payment of twenty million dollars to Spain by the United States for the +Philippines; and the determination of the status of the inhabitants of +the ceded territories by Congress. The great decision had been made. Its +issue was in the hands of the Senate where the Democrats and the +Populists held the balance of power under the requirement of the +two-thirds vote for ratification. + +=The Contest in America over the Treaty of Peace.=--The publication of +the treaty committing the United States to the administration of distant +colonies directed the shifting tides of public opinion into two distinct +channels: support of the policy and opposition to it. The trend in +Republican leadership, long in the direction marked out by the treaty, +now came into the open. Perhaps a majority of the men highest in the +councils of that party had undergone the change of heart reflected in +the letters of John Hay, Secretary of State. In August of 1898 he had +hinted, in a friendly letter to Andrew Carnegie, that he sympathized +with the latter's opposition to "imperialism"; but he had added quickly: +"The only question in my mind is how far it is now possible for us to +withdraw from the Philippines." In November of the same year he wrote to +Whitelaw Reid, one of the peace commissioners at Paris: "There is a wild +and frantic attack now going on in the press against the whole +Philippine transaction. Andrew Carnegie really seems to be off his +head.... But all this confusion of tongues will go its way. The country +will applaud the resolution that has been reached and you will return in +the role of conquering heroes with your 'brows bound with oak.'" + +Senator Beveridge of Indiana and Senator Platt of Connecticut, accepting +the verdict of history as the proof of manifest destiny, called for +unquestioning support of the administration in its final step. "Every +expansion of our territory," said the latter, "has been in accordance +with the irresistible law of growth. We could no more resist the +successive expansions by which we have grown to be the strongest nation +on earth than a tree can resist its growth. The history of territorial +expansion is the history of our nation's progress and glory. It is a +matter to be proud of, not to lament. We should rejoice that Providence +has given us the opportunity to extend our influence, our institutions, +and our civilization into regions hitherto closed to us, rather than +contrive how we can thwart its designs." + +This doctrine was savagely attacked by opponents of McKinley's policy, +many a stanch Republican joining with the majority of Democrats in +denouncing the treaty as a departure from the ideals of the republic. +Senator Vest introduced in the Senate a resolution that "under the +Constitution of the United States, no power is given to the federal +Government to acquire territory to be held and governed permanently as +colonies." Senator Hoar, of Massachusetts, whose long and honorable +career gave weight to his lightest words, inveighed against the whole +procedure and to the end of his days believed that the new drift into +rivalry with European nations as a colonial power was fraught with +genuine danger. "Our imperialistic friends," he said, "seem to have +forgotten the use of the vocabulary of liberty. They talk about giving +good government. 'We shall give them such a government as we think they +are fitted for.' 'We shall give them a better government than they had +before.' Why, Mr. President, that one phrase conveys to a free man and a +free people the most stinging of insults. In that little phrase, as in a +seed, is contained the germ of all despotism and of all tyranny. +Government is not a gift. Free government is not to be given by all the +blended powers of earth and heaven. It is a birthright. It belongs, as +our fathers said, and as their children said, as Jefferson said, and as +President McKinley said, to human nature itself." + +The Senate, more conservative on the question of annexation than the +House of Representatives composed of men freshly elected in the stirring +campaign of 1896, was deliberate about ratification of the treaty. The +Democrats and Populists were especially recalcitrant. Mr. Bryan hurried +to Washington and brought his personal influence to bear in favor of +speedy action. Patriotism required ratification, it was said in one +quarter. The country desires peace and the Senate ought not to delay, it +was urged in another. Finally, on February 6, 1899, the requisite +majority of two-thirds was mustered, many a Senator who voted for the +treaty, however, sharing the misgivings of Senator Hoar as to the +"dangers of imperialism." Indeed at the time, the Senators passed a +resolution declaring that the policy to be adopted in the Philippines +was still an open question, leaving to the future, in this way, the +possibility of retracing their steps. + +=The Attitude of England.=--The Spanish war, while accomplishing the +simple objects of those who launched the nation on that course, like all +other wars, produced results wholly unforeseen. In the first place, it +exercised a profound influence on the drift of opinion among European +powers. In England, sympathy with the United States was from the first +positive and outspoken. "The state of feeling here," wrote Mr. Hay, then +ambassador in London, "is the best I have ever known. From every quarter +the evidences of it come to me. The royal family by habit and tradition +are most careful not to break the rules of strict neutrality, but even +among them I find nothing but hearty kindness and--so far as is +consistent with propriety--sympathy. Among the political leaders on both +sides I find not only sympathy but a somewhat eager desire that 'the +other fellows' shall not seem more friendly." + +Joseph Chamberlain, the distinguished Liberal statesman, thinking no +doubt of the continental situation, said in a political address at the +very opening of the war that the next duty of Englishmen "is to +establish and maintain bonds of permanent unity with our kinsmen across +the Atlantic.... I even go so far as to say that, terrible as war may +be, even war would be cheaply purchased if, in a great and noble cause, +the Stars and Stripes and the Union Jack should wave together over an +Anglo-Saxon alliance." To the American ambassador he added +significantly that he did not "care a hang what they say about it on the +continent," which was another way of expressing the hope that the +warning to Germany and France was sufficient. This friendly English +opinion, so useful to the United States when a combination of powers to +support Spain was more than possible, removed all fears as to the +consequences of the war. Henry Adams, recalling days of humiliation in +London during the Civil War, when his father was the American +ambassador, coolly remarked that it was "the sudden appearance of +Germany as the grizzly terror" that "frightened England into America's +arms"; but the net result in keeping the field free for an easy triumph +of American arms was none the less appreciated in Washington where, +despite outward calm, fears of European complications were never absent. + + +AMERICAN POLICIES IN THE PHILIPPINES AND THE ORIENT + +=The Filipino Revolt against American Rule.=--In the sphere of domestic +politics, as well as in the field of foreign relations, the outcome of +the Spanish war exercised a marked influence. It introduced at once +problems of colonial administration and difficulties in adjusting trade +relations with the outlying dominions. These were furthermore +complicated in the very beginning by the outbreak of an insurrection +against American sovereignty in the Philippines. The leader of the +revolt, Aguinaldo, had been invited to join the American forces in +overthrowing Spanish dominion, and he had assumed, apparently without +warrant, that independence would be the result of the joint operations. +When the news reached him that the American flag had been substituted +for the Spanish flag, his resentment was keen. In February, 1899, there +occurred a slight collision between his men and some American soldiers. +The conflict thus begun was followed by serious fighting which finally +dwindled into a vexatious guerrilla warfare lasting three years and +costing heavily in men and money. Atrocities were committed by the +native insurrectionists and, sad to relate, they were repaid in kind; +it was argued in defense of the army that the ordinary rules of warfare +were without terror to men accustomed to fighting like savages. In vain +did McKinley assure the Filipinos that the institutions and laws +established in the islands would be designed "not for our satisfaction +or for the expression of our theoretical views, but for the happiness, +peace, and prosperity of the people of the Philippine Islands." Nothing +short of military pressure could bring the warring revolutionists to +terms. + +=Attacks on Republican "Imperialism."=--The Filipino insurrection, +following so quickly upon the ratification of the treaty with Spain, +moved the American opponents of McKinley's colonial policies to redouble +their denunciation of what they were pleased to call "imperialism." +Senator Hoar was more than usually caustic in his indictment of the new +course. The revolt against American rule did but convince him of the +folly hidden in the first fateful measures. Everywhere he saw a +conspiracy of silence and injustice. "I have failed to discover in the +speeches, public or private, of the advocates of this war," he contended +in the Senate, "or in the press which supports it and them, a single +expression anywhere of a desire to do justice to the people of the +Philippine Islands, or of a desire to make known to the people of the +United States the truth of the case.... The catchwords, the cries, the +pithy and pregnant phrases of which their speech is full, all mean +dominion. They mean perpetual dominion.... There is not one of these +gentlemen who will rise in his place and affirm that if he were a +Filipino he would not do exactly as the Filipinos are doing; that he +would not despise them if they were to do otherwise. So much at least +they owe of respect to the dead and buried history--the dead and buried +history so far as they can slay and bury it--of their country." In the +way of practical suggestions, the Senator offered as a solution of the +problem: the recognition of independence, assistance in establishing +self-government, and an invitation to all powers to join in a guarantee +of freedom to the islands. + +=The Republican Answer.=--To McKinley and his supporters, engaged in a +sanguinary struggle to maintain American supremacy, such talk was more +than quixotic; it was scarcely short of treasonable. They pointed out +the practical obstacles in the way of uniform self-government for a +collection of seven million people ranging in civilization from the most +ignorant hill men to the highly cultivated inhabitants of Manila. The +incidents of the revolt and its repression, they admitted, were painful +enough; but still nothing as compared with the chaos that would follow +the attempt of a people who had never had experience in such matters to +set up and sustain democratic institutions. They preferred rather the +gradual process of fitting the inhabitants of the islands for +self-government. This course, in their eyes, though less poetic, was +more in harmony with the ideals of humanity. Having set out upon it, +they pursued it steadfastly to the end. First, they applied force +without stint to the suppression of the revolt. Then they devoted such +genius for colonial administration as they could command to the +development of civil government, commerce, and industry. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +A PHILIPPINE HOME] + +=The Boxer Rebellion in China.=--For a nation with a world-wide trade, +steadily growing, as the progress of home industries redoubled the zeal +for new markets, isolation was obviously impossible. Never was this +clearer than in 1900 when a native revolt against foreigners in China, +known as the Boxer uprising, compelled the United States to join with +the powers of Europe in a military expedition and a diplomatic +settlement. The Boxers, a Chinese association, had for some time carried +on a campaign of hatred against all aliens in the Celestial empire, +calling upon the natives to rise in patriotic wrath and drive out the +foreigners who, they said, "were lacerating China like tigers." In the +summer of 1900 the revolt flamed up in deeds of cruelty. Missionaries +and traders were murdered in the provinces; foreign legations were +stoned; the German ambassador, one of the most cordially despised +foreigners, was killed in the streets of Peking; and to all appearances +a frightful war of extermination had begun. In the month of June nearly +five hundred men, women, and children, representing all nations, were +besieged in the British quarters in Peking under constant fire of +Chinese guns and in peril of a terrible death. + +=Intervention in China.=--Nothing but the arrival of armed forces, made +up of Japanese, Russian, British, American, French, and German soldiers +and marines, prevented the destruction of the beleaguered aliens. When +once the foreign troops were in possession of the Chinese capital, +diplomatic questions of the most delicate character arose. For more than +half a century, the imperial powers of Europe had been carving up the +Chinese empire, taking to themselves territory, railway concessions, +mining rights, ports, and commercial privileges at the expense of the +huge but helpless victim. The United States alone among the great +nations, while as zealous as any in the pursuit of peaceful trade, had +refrained from seizing Chinese territory or ports. Moreover, the +Department of State had been urging European countries to treat China +with fairness, to respect her territorial integrity, and to give her +equal trading privileges with all nations. + +=The American Policy of the "Open Door."=--In the autumn of 1899, +Secretary Hay had addressed to London, Berlin, Rome, Paris, Tokyo, and +St. Petersburg his famous note on the "open door" policy in China. In +this document he proposed that existing treaty ports and vested +interests of the several foreign countries should be respected; that +the Chinese government should be permitted to extend its tariffs to all +ports held by alien powers except the few free ports; and that there +should be no discrimination in railway and port charges among the +citizens of foreign countries operating in the empire. To these +principles the governments addressed by Mr. Hay, finally acceded with +evident reluctance. + +[Illustration: AMERICAN DOMINIONS IN THE PACIFIC] + +On this basis he then proposed the settlement that had to follow the +Boxer uprising. "The policy of the Government of the United States," he +said to the great powers, in the summer of 1900, "is to seek a solution +which may bring about permanent safety and peace to China, preserve +Chinese territorial and administrative entity, protect all rights +guaranteed to friendly powers by treaty and international law, and +safeguard for the world the principle of equal and impartial trade with +all parts of the Chinese empire." This was a friendly warning to the +world that the United States would not join in a scramble to punish the +Chinese by carving out more territory. "The moment we acted," said Mr. +Hay, "the rest of the world paused and finally came over to our ground; +and the German government, which is generally brutal but seldom silly, +recovered its senses, and climbed down off its perch." + +In taking this position, the Secretary of State did but reflect the +common sense of America. "We are, of course," he explained, "opposed to +the dismemberment of that empire and we do not think that the public +opinion of the United States would justify this government in taking +part in the great game of spoliation now going on." Heavy damages were +collected by the European powers from China for the injuries inflicted +upon their citizens by the Boxers; but the United States, finding the +sum awarded in excess of the legitimate claims, returned the balance in +the form of a fund to be applied to the education of Chinese students in +American universities. "I would rather be, I think," said Mr. Hay, "the +dupe of China than the chum of the Kaiser." By pursuing a liberal +policy, he strengthened the hold of the United States upon the +affections of the Chinese people and, in the long run, as he remarked +himself, safeguarded "our great commercial interests in that Empire." + +=Imperialism in the Presidential Campaign of 1900.=--It is not strange +that the policy pursued by the Republican administration in disposing of +the questions raised by the Spanish War became one of the first issues +in the presidential campaign of 1900. Anticipating attacks from every +quarter, the Republicans, in renominating McKinley, set forth their +position in clear and ringing phrases: "In accepting by the treaty of +Paris the just responsibility of our victories in the Spanish War the +President and Senate won the undoubted approval of the American people. +No other course was possible than to destroy Spain's sovereignty +throughout the West Indies and in the Philippine Islands. That course +created our responsibility, before the world and with the unorganized +population whom our intervention had freed from Spain, to provide for +the maintenance of law and order, and for the establishment of good +government and for the performance of international obligations. Our +authority could not be less than our responsibility, and wherever +sovereign rights were extended it became the high duty of the government +to maintain its authority, to put down armed insurrection, and to confer +the blessings of liberty and civilization upon all the rescued peoples. +The largest measure of self-government consistent with their welfare and +our duties shall be secured to them by law." To give more strength to +their ticket, the Republican convention, in a whirlwind of enthusiasm, +nominated for the vice presidency, against his protest, Theodore +Roosevelt, the governor of New York and the hero of the Rough Riders, so +popular on account of their Cuban campaign. + +The Democrats, as expected, picked up the gauntlet thrown down with such +defiance by the Republicans. Mr. Bryan, whom they selected as their +candidate, still clung to the currency issue; but the main emphasis, +both of the platform and the appeal for votes, was on the "imperialistic +program" of the Republican administration. The Democrats denounced the +treatment of Cuba and Porto Rico and condemned the Philippine policy in +sharp and vigorous terms. "As we are not willing," ran the platform, "to +surrender our civilization or to convert the Republic into an empire, we +favor an immediate declaration of the Nation's purpose to give to the +Filipinos, first, a stable form of government; second, independence; +third, protection from outside interference.... The greedy commercialism +which dictated the Philippine policy of the Republican administration +attempts to justify it with the plea that it will pay, but even this +sordid and unworthy plea fails when brought to the test of facts. The +war of 'criminal aggression' against the Filipinos entailing an annual +expense of many millions has already cost more than any possible profit +that could accrue from the entire Philippine trade for years to come.... +We oppose militarism. It means conquest abroad and intimidation and +oppression at home. It means the strong arm which has ever been fatal to +free institutions. It is what millions of our citizens have fled from in +Europe. It will impose upon our peace-loving people a large standing +army, an unnecessary burden of taxation, and would be a constant menace +to their liberties." Such was the tenor of their appeal to the voters. + +With the issues clearly joined, the country rejected the Democratic +candidate even more positively than four years before. The popular vote +cast for McKinley was larger and that cast for Bryan smaller than in the +silver election. Thus vindicated at the polls, McKinley turned with +renewed confidence to the development of the policies he had so far +advanced. But fate cut short his designs. In the September following his +second inauguration, he was shot by an anarchist while attending the +Buffalo exposition. "What a strange and tragic fate it has been of +mine," wrote the Secretary of State, John Hay, on the day of the +President's death, "to stand by the bier of three of my dearest friends, +Lincoln, Garfield, and McKinley, three of the gentlest of men, all risen +to the head of the state and all done to death by assassins." On +September 14, 1901, the Vice President, Theodore Roosevelt, took up the +lines of power that had fallen from the hands of his distinguished +chief, promising to continue "absolutely unbroken" the policies he had +inherited. + + +SUMMARY OF NATIONAL GROWTH AND WORLD POLITICS + +The economic aspects of the period between 1865 and 1900 may be readily +summed up: the recovery of the South from the ruin of the Civil War, the +extension of the railways, the development of the Great West, and the +triumph of industry and business enterprise. In the South many of the +great plantations were broken up and sold in small farms, crops were +diversified, the small farming class was raised in the scale of social +importance, the cotton industry was launched, and the coal, iron, +timber, and other resources were brought into use. In the West the free +arable land was practically exhausted by 1890 under the terms of the +Homestead Act; gold, silver, copper, coal and other minerals were +discovered in abundance; numerous rail connections were formed with the +Atlantic seaboard; the cowboy and the Indian were swept away before a +standardized civilization of electric lights and bathtubs. By the end of +the century the American frontier had disappeared. The wild, primitive +life so long associated with America was gone. The unity of the nation +was established. + +In the field of business enterprise, progress was most marked. The +industrial system, which had risen and flourished before the Civil War, +grew into immense proportions and the industrial area was extended from +the Northeast into all parts of the country. Small business concerns +were transformed into huge corporations. Individual plants were merged +under the management of gigantic trusts. Short railway lines were +consolidated into national systems. The industrial population of +wage-earners rose into the tens of millions. The immigration of aliens +increased by leaps and bounds. The cities overshadowed the country. The +nation that had once depended upon Europe for most of its manufactured +goods became a competitor of Europe in the markets of the earth. + +In the sphere of politics, the period witnessed the recovery of white +supremacy in the South; the continued discussion of the old questions, +such as the currency, the tariff, and national banking; and the +injection of new issues like the trusts and labor problems. As of old, +foreign affairs were kept well at the front. Alaska was purchased from +Russia; attempts were made to extend American influence in the Caribbean +region; a Samoan island was brought under the flag; and the Hawaiian +islands were annexed. The Monroe Doctrine was applied with vigor in the +dispute between Venezuela and Great Britain. + +Assistance was given to the Cubans in their revolutionary struggle +against Spain and thus there was precipitated a war which ended in the +annexation of Porto Rico and the Philippines. American influence in the +Pacific and the Orient was so enlarged as to be a factor of great weight +in world affairs. Thus questions connected with foreign and "imperial" +policies were united with domestic issues to make up the warp and woof +of politics. In the direction of affairs, the Republicans took the +leadership, for they held the presidency during all the years, except +eight, between 1865 and 1900. + + +=References= + +J.W. Foster, _A Century of American Diplomacy_; _American Diplomacy in +the Orient_. + +W.F. Reddaway, _The Monroe Doctrine_. + +J.H. Latane, _The United States and Spanish America_. + +A.C. Coolidge, _United States as a World Power_. + +A.T. Mahan, _Interest of the United States in the Sea Power_. + +F.E. Chadwick, _Spanish-American War_. + +D.C. Worcester, _The Philippine Islands and Their People_. + +M.M. Kalaw, _Self-Government in the Philippines_. + +L.S. Rowe, _The United States and Porto Rico_. + +F.E. Chadwick, _The Relations of the United States and Spain_. + +W.R. Shepherd, _Latin America_; _Central and South America_. + + +=Questions= + +1. Tell the story of the international crisis that developed soon after +the Civil War with regard to Mexico. + +2. Give the essential facts relating to the purchase of Alaska. + +3. Review the early history of our interest in the Caribbean. + +4. Amid what circumstances was the Monroe Doctrine applied in +Cleveland's administration? + +5. Give the causes that led to the war with Spain. + +6. Tell the leading events in that war. + +7. What was the outcome as far as Cuba was concerned? The outcome for +the United States? + +8. Discuss the attitude of the Filipinos toward American sovereignty in +the islands. + +9. Describe McKinley's colonial policy. + +10. How was the Spanish War viewed in England? On the Continent? + +11. Was there a unified American opinion on American expansion? + +12. Was this expansion a departure from our traditions? + +13. What events led to foreign intervention in China? + +14. Explain the policy of the "open door." + + +=Research Topics= + +=Hawaii and Venezuela.=--Dewey, _National Problems_ (American Nation +Series), pp. 279-313; Macdonald, _Documentary Source Book_, pp. 600-602; +Hart, _American History Told by Contemporaries_, Vol. IV, pp. 612-616. + +=Intervention in Cuba.=--Latane, _America as a World Power_ (American +Nation Series), pp. 3-28; Macdonald, _Documentary Source Book_, pp. +597-598; Roosevelt, _Autobiography_, pp. 223-277; Haworth, _The United +States in Our Own Time_, pp. 232-256; Hart, _Contemporaries_, Vol. IV, +pp. 573-578. + +=The War with Spain.=--Elson, _History of the United States_, pp. +889-896. + +=Terms of Peace with Spain.=--Latane, pp. 63-81; Macdonald, pp. 602-608; +Hart, _Contemporaries_, Vol. IV, pp. 588-590. + +=The Philippine Insurrection.=--Latane, pp. 82-99. + +=Imperialism as a Campaign Issue.=--Latane, pp. 120-132; Haworth, pp. +257-277; Hart, _Contemporaries_, Vol. IV, pp. 604-611. + +=Biographical Studies.=--William McKinley, M.A. Hanna, John Hay; +Admirals, George Dewey, W.T. Sampson, and W.S. Schley; and Generals, +W.R. Shafter, Joseph Wheeler, and H.W. Lawton. + +=General Analysis of American Expansion.=--_Syllabus in History_ (New +York State, 1920), pp. 142-147. + + + + +PART VII. PROGRESSIVE DEMOCRACY AND THE WORLD WAR + + + + +CHAPTER XXI + +THE EVOLUTION OF REPUBLICAN POLICIES (1901-13) + + +=The Personality and Early Career of Roosevelt.=--On September 14, 1901, +when Theodore Roosevelt took the oath of office, the presidency passed +to a new generation and a leader of a new type recalling, if comparisons +must be made, Andrew Jackson rather than any Republican predecessor. +Roosevelt was brusque, hearty, restless, and fond of action--"a young +fellow of infinite dash and originality," as John Hay remarked of him; +combining the spirit of his old college, Harvard, with the breezy +freedom of the plains; interested in everything--a new species of game, +a new book, a diplomatic riddle, or a novel theory of history or +biology. Though only forty-three years old he was well versed in the art +of practical politics. Coming upon the political scene in the early +eighties, he had associated himself with the reformers in the Republican +party; but he was no Mugwump. From the first he vehemently preached the +doctrine of party loyalty; if beaten in the convention, he voted the +straight ticket in the election. For twenty years he adhered to this +rule and during a considerable portion of that period he held office as +a spokesman of his party. He served in the New York legislature, as head +of the metropolitan police force, as federal civil service commissioner +under President Harrison, as assistant secretary of the navy under +President McKinley, and as governor of the Empire state. Political +managers of the old school spoke of him as "brilliant but erratic"; they +soon found him equal to the shrewdest in negotiation and action. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +ROOSEVELT TALKING TO THE ENGINEER OF A RAILROAD TRAIN] + + +FOREIGN AFFAIRS + +=The Panama Canal.=--The most important foreign question confronting +President Roosevelt on the day of his inauguration, that of the Panama +Canal, was a heritage from his predecessor. The idea of a water route +across the isthmus, long a dream of navigators, had become a living +issue after the historic voyage of the battleship _Oregon_ around South +America during the Spanish War. But before the United States could act +it had to undo the Clayton-Bulwer treaty, made with Great Britain in +1850, providing for the construction of the canal under joint +supervision. This was finally effected by the Hay-Pauncefote treaty of +1901 authorizing the United States to proceed alone, on condition that +there should be no discriminations against other nations in the matter +of rates and charges. + +This accomplished, it was necessary to decide just where the canal +should be built. One group in Congress favored the route through +Nicaragua; in fact, two official commissions had already approved that +location. Another group favored cutting the way through Panama after +purchasing the rights of the old French company which, under the +direction of De Lesseps, the hero of the Suez Canal, had made a costly +failure some twenty years before. After a heated argument over the +merits of the two plans, preference was given to the Panama route. As +the isthmus was then a part of Colombia, President Roosevelt proceeded +to negotiate with the government at Bogota a treaty authorizing the +United States to cut a canal through its territory. The treaty was +easily framed, but it was rejected by the Colombian senate, much to the +President's exasperation. "You could no more make an agreement with the +Colombian rulers," he exclaimed, "than you could nail jelly to a wall." +He was spared the necessity by a timely revolution. On November 3, 1903, +Panama renounced its allegiance to Colombia and three days later the +United States recognized its independence. + +[Illustration: _Courtesy of Panama Canal, Washington, D.C._ + +DEEPEST EXCAVATED PORTION OF PANAMA CANAL, SHOWING GOLD HILL ON +RIGHT AND CONTRACTOR'S HILL ON LEFT. JUNE, 1913] + +This amazing incident was followed shortly by the signature of a treaty +between Panama and the United States in which the latter secured the +right to construct the long-discussed canal, in return for a guarantee +of independence and certain cash payments. The rights and property of +the French concern were then bought, and the final details settled. A +lock rather than a sea-level canal was agreed upon. Construction by the +government directly instead of by private contractors was adopted. +Scientific medicine was summoned to stamp out the tropical diseases +that had made Panama a plague spot. Finally, in 1904, as the President +said, "the dirt began to fly." After surmounting formidable +difficulties--engineering, labor, and sanitary--the American forces in +1913 joined the waters of the Atlantic and the Pacific. Nearly eight +thousand miles were cut off the sea voyage from New York to San +Francisco. If any were inclined to criticize President Roosevelt for +the way in which he snapped off negotiations with Colombia and +recognized the Panama revolutionists, their attention was drawn to the +magnificent outcome of the affair. Notwithstanding the treaty with Great +Britain, Congress passed a tolls bill discriminating in rates in favor +of American ships. It was only on the urgent insistence of President +Wilson that the measure was later repealed. + +=The Conclusion of the Russo-Japanese War.=--The applause which greeted +the President's next diplomatic stroke was unmarred by censure of any +kind. In the winter of 1904 there broke out between Japan and Russia a +terrible conflict over the division of spoils in Manchuria. The fortunes +of war were with the agile forces of Nippon. In this struggle, it seems, +President Roosevelt's sympathies were mainly with the Japanese, although +he observed the proprieties of neutrality. At all events, Secretary Hay +wrote in his diary on New Year's Day, 1905, that the President was +"quite firm in his view that we cannot permit Japan to be robbed a +second time of her victory," referring to the fact that Japan, ten years +before, after defeating China on the field of battle, had been forced by +Russia, Germany, and France to forego the fruits of conquest. + +Whatever the President's personal feelings may have been, he was aware +that Japan, despite her triumphs over Russia, was staggering under a +heavy burden of debt. At a suggestion from Tokyo, he invited both +belligerents in the summer of 1905 to join in a peace conference. The +celerity of their reply was aided by the pressure of European bankers, +who had already come to a substantial agreement that the war must stop. +After some delay, Portsmouth, New Hampshire, was chosen as the meeting +place for the spokesmen of the two warring powers. Roosevelt presided +over the opening ceremonies with fine urbanity, thoroughly enjoying the +justly earned honor of being for the moment at the center of the world's +interest. He had the satisfaction of seeing the conference end in a +treaty of peace and amity. + +=The Monroe Doctrine Applied to Germany.=--Less spectacular than the +Russo-Japanese settlement but not less important was a diplomatic +passage-at-arms with Germany over the Monroe Doctrine. This clash grew +out of the inability or unwillingness of the Venezuelan government to +pay debts due foreign creditors. Having exhausted their patience in +negotiations, England and Germany, in December 1901, sent battleships to +establish what they characterized as "a peaceful blockade" of Venezuelan +ports. Their action was followed by the rupture of diplomatic relations; +there was a possibility that war and the occupation of Venezuelan +territory might result. + +While unwilling to stand between a Latin-American country and its +creditors, President Roosevelt was determined that debt collecting +should not be made an excuse for European countries to seize territory. +He therefore urged arbitration of the dispute, winning the assent of +England and Italy. Germany, with a somewhat haughty air, refused to take +the milder course. The President, learning of this refusal, called the +German ambassador to the White House and informed him in very precise +terms that, unless the Imperial German Government consented to +arbitrate, Admiral Dewey would be ordered to the scene with instructions +to prevent Germany from seizing any Venezuelan territory. A week passed +and no answer came from Berlin. Not baffled, the President again took +the matter up with the ambassador, this time with even more firmness; he +stated in language admitting of but one meaning that, unless within +forty-eight hours the Emperor consented to arbitration, American +battleships, already coaled and cleared, would sail for Venezuelan +waters. The hint was sufficient. The Kaiser accepted the proposal and +the President, with the fine irony of diplomacy, complimented him +publicly on "being so stanch an advocate of arbitration." In terms of +the Monroe Doctrine this action meant that the United States, while not +denying the obligations of debtors, would not permit any move on the +part of European powers that might easily lead to the temporary or +permanent occupation of Latin-American territory. + +=The Santo Domingo Affair.=--The same issue was involved in a +controversy over Santo Domingo which arose in 1904. The Dominican +republic, like Venezuela, was heavily in debt, and certain European +countries declared that, unless the United States undertook to look +after the finances of the embarrassed debtor, they would resort to armed +coercion. What was the United States to do? The danger of having some +European power strongly intrenched in Santo Domingo was too imminent to +be denied. President Roosevelt acted with characteristic speed, and +notwithstanding strong opposition in the Senate was able, in 1907, to +effect a treaty arrangement which placed Dominican finances under +American supervision. + +In the course of the debate over this settlement, a number of +interesting questions arose. It was pertinently asked whether the +American navy should be used to help creditors collect their debts +anywhere in Latin-America. It was suggested also that no sanction should +be given to the practice among European governments of using armed force +to collect private claims. Opponents of President Roosevelt's policy, +and they were neither few nor insignificant, urged that such matters +should be referred to the Hague Court or to special international +commissions for arbitration. To this the answer was made that the United +States could not surrender any question coming under the terms of the +Monroe Doctrine to the decision of an international tribunal. The +position of the administration was very clearly stated by President +Roosevelt himself. "The country," he said, "would certainly decline to +go to war to prevent a foreign government from collecting a just debt; +on the other hand, it is very inadvisable to permit any foreign power to +take possession, even temporarily, of the customs houses of an American +republic in order to enforce the payment of its obligations; for such a +temporary occupation might turn into a permanent occupation. The only +escape from these alternatives may at any time be that we must +ourselves undertake to bring about some arrangement by which so much as +possible of a just obligation shall be paid." The Monroe Doctrine was +negative. It denied to European powers a certain liberty of operation in +this hemisphere. The positive obligations resulting from its application +by the United States were points now emphasized and developed. + +=The Hague Conference.=--The controversies over Latin-American relations +and his part in bringing the Russo-Japanese War to a close naturally +made a deep impression upon Roosevelt, turning his mind in the direction +of the peaceful settlement of international disputes. The subject was +moreover in the air. As if conscious of impending calamity, the +statesmen of the Old World, to all outward signs at least, seemed +searching for a way to reduce armaments and avoid the bloody and costly +trial of international causes by the ancient process of battle. It was +the Czar, Nicholas II, fated to die in one of the terrible holocausts +which he helped to bring upon mankind, who summoned the delegates of the +nations in the first Hague Peace Conference in 1899. The conference did +nothing to reduce military burdens or avoid wars but it did recognize +the right of friendly nations to offer the services of mediation to +countries at war and did establish a Court at the Hague for the +arbitration of international disputes. + +Encouraged by this experiment, feeble as it was, President Roosevelt in +1904 proposed a second conference, yielding to the Czar the honor of +issuing the call. At this great international assembly, held at the +Hague in 1907, the representatives of the United States proposed a plan +for the compulsory arbitration of certain matters of international +dispute. This was rejected with contempt by Germany. Reduction of +armaments, likewise proposed in the conference, was again deferred. In +fact, nothing was accomplished beyond agreement upon certain rules for +the conduct of "civilized warfare," casting a somewhat lurid light upon +the "pacific" intentions of most of the powers assembled. + +=The World Tour of the Fleet.=--As if to assure the world then that the +United States placed little reliance upon the frail reed of peace +conferences, Roosevelt the following year (1908) made an imposing +display of American naval power by sending a fleet of sixteen +battleships on a tour around the globe. On his own authority, he ordered +the ships to sail out of Hampton Roads and circle the earth by way of +the Straits of Magellan, San Francisco, Australia, the Philippines, +China, Japan, and the Suez Canal. This enterprise was not, as some +critics claimed, a "mere boyish flourish." President Roosevelt knew how +deep was the influence of sea power on the fate of nations. He was aware +that no country could have a wide empire of trade and dominion without +force adequate to sustain it. The voyage around the world therefore +served a double purpose. It interested his own country in the naval +program of the government, and it reminded other powers that the +American giant, though quiet, was not sleeping in the midst of +international rivalries. + + +COLONIAL ADMINISTRATION + +=A Constitutional Question Settled.=--In colonial administration, as in +foreign policy, President Roosevelt advanced with firm step in a path +already marked out. President McKinley had defined the principles that +were to control the development of Porto Rico and the Philippines. The +Republican party had announced a program of pacification, gradual +self-government, and commercial improvement. The only remaining question +of importance, to use the popular phrase,--"Does the Constitution follow +the flag?"--had been answered by the Supreme Court of the United States. +Although it was well known that the Constitution did not contemplate the +government of dependencies, such as the Philippines and Porto Rico, the +Court, by generous and ingenious interpretations, found a way for +Congress to apply any reasonable rules required by the occasion. + +=Porto Rico.=--The government of Porto Rico was a relatively simple +matter. It was a single island with a fairly homogeneous population +apart from the Spanish upper class. For a time after military occupation +in 1898, it was administered under military rule. This was succeeded by +the establishment of civil government under the "organic act" passed by +Congress in 1900. The law assured to the Porto Ricans American +protection but withheld American citizenship--a boon finally granted in +1917. It provided for a governor and six executive secretaries appointed +by the President with the approval of the Senate; and for a legislature +of two houses--one elected by popular native vote, and an upper chamber +composed of the executive secretaries and five other persons appointed +in the same manner. Thus the United States turned back to the provincial +system maintained by England in Virginia or New York in old colonial +days. The natives were given a voice in their government and the power +of initiating laws; but the final word both in law-making and +administration was vested in officers appointed in Washington. Such was +the plan under which the affairs of Porto Rico were conducted by +President Roosevelt. It lasted until the new organic act of 1917. + +[Illustration: _Photograph from Underwood and Underwood, N.Y._ + +A SUGAR MILL, PORTO RICO] + +=The Philippines.=--The administration of the Philippines presented far +more difficult questions. The number of islands, the variety of +languages and races, the differences in civilization all combined to +challenge the skill of the government. Moreover, there was raging in +1901 a stubborn revolt against American authority, which had to be +faced. Following the lines laid down by President McKinley, the +evolution of American policy fell into three stages. At first the +islands were governed directly by the President under his supreme +military power. In 1901 a civilian commission, headed by William Howard +Taft, was selected by the President and charged with the government of +the provinces in which order had been restored. Six years later, under +the terms of an organic act, passed by Congress in 1902, the third stage +was reached. The local government passed into the hands of a governor +and commission, appointed by the President and Senate, and a +legislature--one house elected by popular vote and an upper chamber + +composed of the commission. This scheme, like that obtaining in Porto +Rico, remained intact until a Democratic Congress under President +Wilson's leadership carried the colonial administration into its fourth +phase by making both houses elective. Thus, by the steady pursuit of a +liberal policy, self-government was extended to the dependencies; but it +encouraged rather than extinguished the vigorous movement among the +Philippine natives for independence. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +MR TAFT IN THE PHILIPPINES] + +=Cuban Relations.=--Within the sphere of colonial affairs, Cuba, though +nominally independent, also presented problems to the government at +Washington. In the fine enthusiasm that accompanied the declaration of +war on Spain, Congress, unmindful of practical considerations, +recognized the independence of Cuba and disclaimed "any disposition or +intention to exercise sovereignty, jurisdiction, or control over said +island except for the pacification thereof." In the settlement that +followed the war, however, it was deemed undesirable to set the young +republic adrift upon the stormy sea of international politics without a +guiding hand. Before withdrawing American troops from the island, +Congress, in March, 1901, enacted, and required Cuba to approve, a +series of restrictions known as the Platt amendment, limiting her power +to incur indebtedness, securing the right of the United States to +intervene whenever necessary to protect life and property, and reserving +to the United States coaling stations at certain points to be agreed +upon. The Cubans made strong protests against what they deemed +"infringements of their sovereignty"; but finally with good grace +accepted their fate. Even when in 1906 President Roosevelt landed +American troops in the island to quell a domestic dissension, they +acquiesced in the action, evidently regarding it as a distinct warning +that they should learn to manage their elections in an orderly manner. + + +THE ROOSEVELT DOMESTIC POLICIES + +=Social Questions to the Front.=--From the day of his inauguration to +the close of his service in 1909, President Roosevelt, in messages, +speeches, and interviews, kept up a lively and interesting discussion of +trusts, capital, labor, poverty, riches, lawbreaking, good citizenship, +and kindred themes. Many a subject previously touched upon only by +representatives of the minor and dissenting parties, he dignified by a +careful examination. That he did this with any fixed design or policy in +mind does not seem to be the case. He admitted himself that when he +became President he did not have in hand any settled or far-reaching +plan of social betterment. He did have, however, serious convictions on +general principles. "I was bent upon making the government," he wrote, +"the most efficient possible instrument in helping the people of the +United States to better themselves in every way, politically, socially, +and industrially. I believed with all my heart in real and +thorough-going democracy and I wished to make the democracy industrial +as well as political, although I had only partially formulated the +method I believed we should follow." It is thus evident at least that he +had departed a long way from the old idea of the government as nothing +but a great policeman keeping order among the people in a struggle over +the distribution of the nation's wealth and resources. + +=Roosevelt's View of the Constitution.=--Equally significant was +Roosevelt's attitude toward the Constitution and the office of +President. He utterly repudiated the narrow construction of our national +charter. He held that the Constitution "should be treated as the +greatest document ever devised by the wit of man to aid a people in +exercising every power necessary for its own betterment, not as a +strait-jacket cunningly fashioned to strangle growth." He viewed the +presidency as he did the Constitution. Strict constructionists of the +Jeffersonian school, of whom there were many on occasion even in the +Republican party, had taken a view that the President could do nothing +that he was not specifically authorized by the Constitution to do. +Roosevelt took exactly the opposite position. It was his opinion that it +was not only the President's right but his duty "to do anything that the +needs of the nation demanded unless such action was forbidden by the +Constitution or the laws." He went on to say that he acted "for the +common well-being of all our people whenever and in whatever manner was +necessary, unless prevented by direct constitutional or legislative +prohibition." + +=The Trusts and Railways.=--To the trust question, Roosevelt devoted +especial attention. This was unavoidable. By far the larger part of the +business of the country was done by corporations as distinguished from +partnerships and individual owners. The growth of these gigantic +aggregations of capital had been the leading feature in American +industrial development during the last two decades of the nineteenth +century. In the conquest of business by trusts and "the resulting +private fortunes of great magnitude," the Populists and the Democrats +had seen a grievous danger to the republic. "Plutocracy has taken the +place of democracy; the tariff breeds trusts; let us destroy therefore +the tariff and the trusts"--such was the battle cry which had been taken +up by Bryan and his followers. + +President Roosevelt countered vigorously. He rejected the idea that the +trusts were the product of the tariff or of governmental action of any +kind. He insisted that they were the outcome of "natural economic +forces": (1) destructive competition among business men compelling them +to avoid ruin by cooperation in fixing prices; (2) the growth of markets +on a national scale and even international scale calling for vast +accumulations of capital to carry on such business; (3) the possibility +of immense savings by the union of many plants under one management. In +the corporation he saw a new stage in the development of American +industry. Unregulated competition he regarded as "the source of evils +which all men concede must be remedied if this civilization of ours is +to survive." The notion, therefore, that these immense business concerns +should be or could be broken up by a decree of law, Roosevelt considered +absurd. + +At the same time he proposed that "evil trusts" should be prevented from +"wrong-doing of any kind"; that is, punished for plain swindling, for +making agreements to limit output, for refusing to sell to customers who +dealt with rival firms, and for conspiracies with railways to ruin +competitors by charging high freight rates and for similar abuses. +Accordingly, he proposed, not the destruction of the trusts, but their +regulation by the government. This, he contended, would preserve the +advantages of business on a national scale while preventing the evils +that accompanied it. The railway company he declared to be a public +servant. "Its rates should be just to and open to all shippers alike." +So he answered those who thought that trusts and railway combinations +were private concerns to be managed solely by their owners without let +or hindrance and also those who thought trusts and railway combinations +could be abolished by tariff reduction or criminal prosecution. + +=The Labor Question.=--On the labor question, then pressing to the front +in public interest, President Roosevelt took advanced ground for his +time. He declared that the working-man, single-handed and empty-handed, +threatened with starvation if unemployed, was no match for the employer +who was able to bargain and wait. This led him, accordingly, to accept +the principle of the trade union; namely, that only by collective +bargaining can labor be put on a footing to measure its strength equally +with capital. While he severely arraigned labor leaders who advocated +violence and destructive doctrines, he held that "the organization of +labor into trade unions and federations is necessary, is beneficent, and +is one of the greatest possible agencies in the attainment of a true +industrial, as well as a true political, democracy in the United +States." The last resort of trade unions in labor disputes, the strike, +he approved in case negotiations failed to secure "a fair deal." + +He thought, however, that labor organizations, even if wisely managed, +could not solve all the pressing social questions of the time. The aid +of the government at many points he believed to be necessary to +eliminate undeserved poverty, industrial diseases, unemployment, and the +unfortunate consequences of industrial accidents. In his first message +of 1901, for instance, he urged that workers injured in industry should +have certain and ample compensation. From time to time he advocated +other legislation to obtain what he called "a larger measure of social +and industrial justice." + +=Great Riches and Taxation.=--Even the challenge of the radicals, such +as the Populists, who alleged that "the toil of millions is boldly +stolen to build up colossal fortunes for a few"--challenges which his +predecessors did not consider worthy of notice--President Roosevelt +refused to let pass without an answer. In his first message he denied +the truth of the common saying that the rich were growing richer and the +poor were growing poorer. He asserted that, on the contrary, the average +man, wage worker, farmer, and small business man, was better off than +ever before in the history of our country. That there had been abuses in +the accumulation of wealth he did not pretend to ignore, but he believed +that even immense fortunes, on the whole, represented positive benefits +conferred upon the country. Nevertheless he felt that grave dangers to +the safety and the happiness of the people lurked in great inequalities +of wealth. In 1906 he wrote that he wished it were in his power to +prevent the heaping up of enormous fortunes. The next year, to the +astonishment of many leaders in his own party, he boldly announced in a +message to Congress that he approved both income and inheritance taxes, +then generally viewed as Populist or Democratic measures. He even took +the stand that such taxes should be laid in order to bring about a more +equitable distribution of wealth and greater equality of opportunity +among citizens. + + +LEGISLATIVE AND EXECUTIVE ACTIVITIES + +=Economic Legislation.=--When President Roosevelt turned from the field +of opinion he found himself in a different sphere. Many of his views +were too advanced for the members of his party in Congress, and where +results depended upon the making of new laws, his progress was slow. +Nevertheless, in his administrations several measures were enacted that +bore the stamp of his theories, though it could hardly be said that he +dominated Congress to the same degree as did some other Presidents. The +Hepburn Railway Act of 1906 enlarged the interstate commerce commission; +it extended the commission's power over oil pipe lines, express +companies, and other interstate carriers; it gave the commission the +right to reduce rates found to be unreasonable and discriminatory; it +forbade "midnight tariffs," that is, sudden changes in rates favoring +certain shippers; and it prohibited common carriers from transporting +goods owned by themselves, especially coal, except for their own proper +use. Two important pure food and drug laws, enacted during the same +year, were designed to protect the public against diseased meats and +deleterious foods and drugs. A significant piece of labor legislation +was an act of the same Congress making interstate railways liable to +damages for injuries sustained by their employees. When this measure was +declared unconstitutional by the Supreme Court it was reenacted with the +objectionable clauses removed. A second installment of labor legislation +was offered in the law of 1908 limiting the hours of railway employees +engaged as trainmen or telegraph operators. + +[Illustration: _Courtesy United States Reclamation Service._ + +THE ROOSEVELT DAM, PHOENIX, ARIZONA] + +=Reclamation and Conservation.=--The open country--the deserts, the +forests, waterways, and the public lands--interested President Roosevelt +no less than railway and industrial questions. Indeed, in his first +message to Congress he placed the conservation of natural resources +among "the most vital internal problems" of the age, and forcibly +emphasized an issue that had been discussed in a casual way since +Cleveland's first administration. The suggestion evoked an immediate +response in Congress. Under the leadership of Senator Newlands, of +Nevada, the Reclamation Act of 1902 was passed, providing for the +redemption of the desert areas of the West. The proceeds from the sale +of public lands were dedicated to the construction of storage dams and +sluiceways to hold water and divert it as needed to the thirsty sands. +Furthermore it was stipulated that the rents paid by water users should +go into a reclamation fund to continue the good work forever. +Construction was started immediately under the terms of the law. Within +seventeen years about 1,600,000 acres had been reclaimed and more than a +million were actually irrigated. In the single year 1918, the crops of +the irrigated districts were valued at approximately $100,000,000. + +In his first message, also, President Roosevelt urged the transfer of +all control over national forests to trained men in the Bureau of +Forestry--a recommendation carried out in 1907 when the Forestry Service +was created. In every direction noteworthy advances were made in the +administration of the national domain. The science of forestry was +improved and knowledge of the subject spread among the people. Lands in +the national forest available for agriculture were opened to settlers. +Water power sites on the public domain were leased for a term of years +to private companies instead of being sold outright. The area of the +national forests was enlarged from 43 million acres to 194 million acres +by presidential proclamation--more than 43 million acres being added in +one year, 1907. The men who turned sheep and cattle to graze on the +public lands were compelled to pay a fair rental, much to their +dissatisfaction. Fire prevention work was undertaken in the forests on a +large scale, reducing the appalling, annual destruction of timber. +Millions of acres of coal land, such as the government had been +carelessly selling to mining companies at low figures, were withdrawn +from sale and held until Congress was prepared to enact laws for the +disposition of them in the public interest. Prosecutions were +instituted against men who had obtained public lands by fraud and vast +tracts were recovered for the national domain. An agitation was begun +which bore fruit under the administrations of Taft and Wilson in laws +reserving to the federal government the ownership of coal, water power, +phosphates, and other natural resources while authorizing corporations +to develop them under leases for a period of years. + +=The Prosecution of the Trusts.=--As an executive, President Roosevelt +was also a distinct "personality." His discrimination between "good" and +"bad" trusts led him to prosecute some of them with vigor. On his +initiative, the Northern Securities Company, formed to obtain control of +certain great western railways, was dissolved by order of the Supreme +Court. Proceedings were instituted against the American Tobacco Company +and the Standard Oil Company as monopolies in violation of the Sherman +Anti-Trust law. The Sugar Trust was found guilty of cheating the New +York customs house and some of the minor officers were sent to prison. +Frauds in the Post-office Department were uncovered and the offenders +brought to book. In fact hardly a week passed without stirring news of +"wrong doers" and "malefactors" haled into federal courts. + +=The Great Coal Strike.=--The Roosevelt theory that the President could +do anything for public welfare not forbidden by the Constitution and the +laws was put to a severe test in 1902. A strike of the anthracite coal +miners, which started in the summer, ran late into the autumn. +Industries were paralyzed for the want of coal; cities were threatened +with the appalling menace of a winter without heat. Governors and mayors +were powerless and appealed for aid. The mine owners rejected the +demands of the men and refused to permit the arbitration of the points +in dispute, although John Mitchell, the leader of the miners, repeatedly +urged it. After observing closely the course affairs, President +Roosevelt made up his mind that the situation was intolerable. He +arranged to have the federal troops, if necessary, take possession of +the mines and operate them until the strike could be settled. He then +invited the contestants to the White House and by dint of hard labor +induced them to accept, as a substitute or compromise, arbitration by a +commission which he appointed. Thus, by stepping outside the +Constitution and acting as the first citizen of the land, President +Roosevelt averted a crisis of great magnitude. + +=The Election of 1904.=--The views and measures which he advocated with +such vigor aroused deep hostility within as well as without his party. +There were rumors of a Republican movement to defeat his nomination in +1904 and it was said that the "financial and corporation interests" were +in arms against him. A prominent Republican paper in New York City +accused him of having "stolen Mr. Bryan's thunder," by harrying the +trusts and favoring labor unions. When the Republican convention +assembled in Chicago, however, the opposition disappeared and Roosevelt +was nominated by acclamation. + +This was the signal for a change on the part of Democratic leaders. They +denounced the President as erratic, dangerous, and radical and decided +to assume the moderate role themselves. They put aside Mr. Bryan and +selected as their candidate, Judge Alton B. Parker, of New York, a man + +who repudiated free silver and made a direct appeal for the conservative +vote. The outcome of the reversal was astounding. Judge Parker's vote +fell more than a million below that cast for Bryan in 1900; of the 476 +electoral votes he received only 140. Roosevelt, in addition to sweeping +the Republican sections, even invaded Democratic territory, carrying the +state of Missouri. Thus vindicated at the polls, he became more +outspoken than ever. His leadership in the party was so widely +recognized that he virtually selected his own successor. + + +THE ADMINISTRATION OF PRESIDENT TAFT + +=The Campaign of 1908.=--Long before the end of his elective term, +President Roosevelt let it be known that he favored as his successor, +William Howard Taft, of Ohio, his Secretary of War. To attain this end +he used every shred of his powerful influence. When the Republican +convention assembled, Mr. Taft easily won the nomination. Though the +party platform was conservative in tone, he gave it a progressive tinge +by expressing his personal belief in the popular election of United +States Senators, an income tax, and other liberal measures. President +Roosevelt announced his faith in the Republican candidate and appealed +to the country for his election. + +The turn in Republican affairs now convinced Mr. Bryan that the signs +were propitious for a third attempt to win the presidency. The disaster +to Judge Parker had taught the party that victory did not lie in a +conservative policy. With little difficulty, therefore, the veteran +leader from Nebraska once more rallied the Democrats around his +standard, won the nomination, and wrote a platform vigorously attacking +the tariff, trusts, and monopolies. Supported by a loyal following, he +entered the lists, only to meet another defeat. Though he polled almost +a million and a half more votes than did Judge Parker in 1904, the palm +went to Mr. Taft. + +=The Tariff Revision and Party Dissensions.=--At the very beginning of +his term, President Taft had to face the tariff issue. He had met it in +the campaign. Moved by the Democratic demand for a drastic reduction, he +had expressed opinions which were thought to imply a "downward +revision." The Democrats made much of the implication and the +Republicans from the Middle West rejoiced in it. Pressure was coming +from all sides. More than ten years had elapsed since the enactment of +the Dingley bill and the position of many industries had been altered +with the course of time. Evidently the day for revision--at best a +thankless task--had arrived. Taft accepted the inevitable and called +Congress in a special session. Until the midsummer of 1909, Republican +Senators and Representatives wrangled over tariff schedules, the +President making little effort to influence their decisions. When on +August 5 the Payne-Aldrich bill became a law, a breach had been made in +Republican ranks. Powerful Senators from the Middle West had spoken +angrily against many of the high rates imposed by the bill. They had +even broken with their party colleagues to vote against the entire +scheme of tariff revision. + +=The Income Tax Amendment.=--The rift in party harmony was widened by +another serious difference of opinion. During the debate on the tariff +bill, there was a concerted movement to include in it an income tax +provision--this in spite of the decision of the Supreme Court in 1895 +declaring it unconstitutional. Conservative men were alarmed by the +evident willingness of some members to flout a solemn decree of that +eminent tribunal. At the same time they saw a powerful combination of +Republicans and Democrats determined upon shifting some of the burden of +taxation to large incomes. In the press of circumstances, a compromise +was reached. The income tax bill was dropped for the present; but +Congress passed the sixteenth amendment to the Constitution, authorizing +taxes upon incomes from whatever source they might be derived, without +reference to any apportionment among the states on the basis of +population. The states ratified the amendment and early in 1913 it was +proclaimed. + +=President Taft's Policies.=--After the enactment of the tariff bill, +Taft continued to push forward with his legislative program. He +recommended, and Congress created, a special court of commerce with +jurisdiction, among other things, over appeals from the interstate +commerce commission, thus facilitating judicial review of the railway +rates fixed and the orders issued by that body. This measure was quickly +followed by an act establishing a system of postal savings banks in +connection with the post office--a scheme which had long been opposed by +private banks. Two years later, Congress defied the lobby of the express +companies and supplemented the savings banks with a parcels post system, +thus enabling the American postal service to catch up with that of other +progressive nations. With a view to improving the business +administration of the federal government, the President obtained from +Congress a large appropriation for an economy and efficiency commission +charged with the duty of inquiring into wasteful and obsolete methods +and recommending improved devices and practices. The chief result of +this investigation was a vigorous report in favor of a national budget +system, which soon found public backing. + +President Taft negotiated with England and France general treaties +providing for the arbitration of disputes which were "justiciable" in +character even though they might involve questions of "vital interest +and national honor." They were coldly received in the Senate and so +amended that Taft abandoned them altogether. A tariff reciprocity +agreement with Canada, however, he forced through Congress in the face +of strong opposition from his own party. After making a serious breach +in Republican ranks, he was chagrined to see the whole scheme come to +naught by the overthrow of the Liberals in the Canadian elections of +1911. + +=Prosecution of the Trusts.=--The party schism was even enlarged by what +appeared to be the successful prosecution of several great combinations. +In two important cases, the Supreme Court ordered the dissolution of the +Standard Oil Company and the American Tobacco Company on the ground that +they violated the Sherman Anti-Trust law. In taking this step Chief +Justice White was at some pains to state that the law did not apply to +combinations which did not "unduly" restrain trade. His remark, +construed to mean that the Court would not interfere with corporations +as such, became the subject of a popular outcry against the President +and the judges. + + +PROGRESSIVE INSURGENCY AND THE ELECTION OF 1912 + +=Growing Dissensions.=--All in all, Taft's administration from the first +day had been disturbed by party discord. High words had passed over the +tariff bill and disgruntled members of Congress could not forget them. +To differences over issues were added quarrels between youth and old +age. In the House of Representatives there developed a group of young +"insurgent" Republicans who resented the dominance of the Speaker, +Joseph G. Cannon, and other members of the "old guard," as they named +the men of long service and conservative minds. In 1910, the insurgents +went so far as to join with the Democrats in a movement to break the +Speaker's sway by ousting him from the rules committee and depriving him +of the power to appoint its members. The storm was brewing. In the +autumn of that year the Democrats won a clear majority in the House of +Representatives and began an open battle with President Taft by +demanding an immediate downward revision of the tariff. + +=The Rise of the Progressive Republicans.=--Preparatory to the campaign +of 1912, the dissenters within the Republican party added the prefix +"Progressive" to their old title and began to organize a movement to +prevent the renomination of Mr. Taft. As early as January 21, 1911, they +formed a Progressive Republican League at the home of Senator La +Follette of Wisconsin and launched an attack on the Taft measures and +policies. In October they indorsed Mr. La Follette as "the logical +Republican candidate" and appealed to the party for support. The +controversy over the tariff had grown into a formidable revolt against +the occupant of the White House. + +=Roosevelt in the Field.=--After looking on for a while, ex-President +Roosevelt took a hand in the fray. Soon after his return in 1910 from a +hunting trip in Africa and a tour in Europe, he made a series of +addresses in which he formulated a progressive program. In a speech in +Kansas, he favored regulation of the trusts, a graduated income tax +bearing heavily on great fortunes, tariff revision schedule by schedule, +conservation of natural resources, labor legislation, the direct +primary, and the recall of elective officials. In an address before the +Ohio state constitutional convention in February, 1912, he indorsed the +initiative and referendum and announced a doctrine known as the "recall +of judicial decisions." This was a new and radical note in American +politics. An ex-President of the United States proposed that the people +at the polls should have the right to reverse the decision of a judge +who set aside any act of a state legislature passed in the interests of +social welfare. The Progressive Republicans, impressed by these +addresses, turned from La Follette to Roosevelt and on February 24, +induced him to come out openly as a candidate against Taft for the +Republican nomination. + +=The Split in the Republican Party.=--The country then witnessed the +strange spectacle of two men who had once been close companions engaged +in a bitter rivalry to secure a majority of the delegates to the +Republican convention to be held at Chicago. When the convention +assembled, about one-fourth of the seats were contested, the delegates +for both candidates loudly proclaiming the regularity of their election. +In deciding between the contestants the national committee, after the +usual hearings, settled the disputes in such a way that Taft received a +safe majority. After a week of negotiation, Roosevelt and his followers +left the Republican party. Most of his supporters withdrew from the +convention and the few who remained behind refused to answer the roll +call. Undisturbed by this formidable bolt, the regular Republicans went +on with their work. They renominated Mr. Taft and put forth a platform +roundly condemning such Progressive doctrines as the recall of judges. + +=The Formation of the Progressive Party.=--The action of the Republicans +in seating the Taft delegates was vigorously denounced by Roosevelt. He +declared that the convention had no claim to represent the voters of the +Republican party; that any candidate named by it would be "the +beneficiary of a successful fraud"; and that it would be deeply +discreditable to any man to accept the convention's approval under such +circumstances. The bitterness of his followers was extreme. On July 8, a +call went forth for a "Progressive" convention to be held in Chicago on +August 5. The assembly which duly met on that day was a unique political +conference. Prominence was given to women delegates, and "politicians" +were notably absent. Roosevelt himself, who was cheered as a conquering +hero, made an impassioned speech setting forth his "confession of +faith." He was nominated by acclamation; Governor Hiram Johnson of +California was selected as his companion candidate for Vice President. +The platform endorsed such political reforms as woman suffrage, direct +primaries, the initiative, referendum, and recall, popular election of +United States Senators, and the short ballot. It favored a program of +social legislation, including the prohibition of child labor and minimum +wages for women. It approved the regulation, rather than the +dissolution, of the trusts. Like apostles in a new and lofty cause, the +Progressives entered a vigorous campaign for the election of their +distinguished leader. + +=Woodrow Wilson and the Election of 1912.=--With the Republicans +divided, victory loomed up before the Democrats. Naturally, a terrific +contest over the nomination occurred at their convention in Baltimore. +Champ Clark, Speaker of the House of Representatives, and Governor +Woodrow Wilson, of New Jersey, were the chief contestants. After tossing +to and fro for seven long, hot days, and taking forty-six ballots, the +delegates, powerfully influenced by Mr. Bryan, finally decided in favor +of the governor. As a professor, a writer on historical and political +subjects, and the president of Princeton University, Mr. Wilson had +become widely known in public life. As the governor of New Jersey he had +attracted the support of the progressives in both parties. With grim +determination he had "waged war on the bosses," and pushed through the +legislature measures establishing direct primaries, regulating public +utilities, and creating a system of workmen's compensation in +industries. During the presidential campaign that followed Governor +Wilson toured the country and aroused great enthusiasm by a series of +addresses later published under the title of _The New Freedom_. He +declared that "the government of the United States is at present the +foster child of the special interests." He proposed to free the country +by breaking the dominance of "the big bankers, the big manufacturers, +the big masters of commerce, the heads of railroad corporations and of +steamship corporations." + +In the election Governor Wilson easily secured a majority of the +electoral votes, and his party, while retaining possession of the House +of Representatives, captured the Senate as well. The popular verdict, +however, indicated a state of confusion in the country. The combined +Progressive and Republican vote exceeded that of the Democrats by +1,300,000. The Socialists, with Eugene V. Debs as their candidate again, +polled about 900,000 votes, more than double the number received four +years before. Thus, as the result of an extraordinary upheaval the +Republicans, after holding the office of President for sixteen years, +passed out of power, and the government of the country was intrusted to +the Democrats under the leadership of a man destined to be one of the +outstanding figures of the modern age, Woodrow Wilson. + + +=General References= + +J.B. Bishop, _Theodore Roosevelt and His Time_ (2 vols.). + +Theodore Roosevelt, _Autobiography_; _New Nationalism_; _Progressive +Principles_. + +W.H. Taft, _Popular Government_. + +Walter Weyl, _The New Democracy_. + +H. Croly, _The Promise of American Life_. + +J.B. Bishop, _The Panama Gateway_. + +J.B. Scott, _The Hague Peace Conferences_. + +W.B. Munro (ed.), _Initiative, Referendum, and Recall_. + +C.R. Van Hise, _The Conservation of Natural Resources_. + +Gifford Pinchot, _The Fight for Conservation_. + +W.F. Willoughby, _Territories and Dependencies of the United States_ +(1905). + + +=Research Topics= + +=Roosevelt and "Big Business."=--Haworth, _The United States in Our Own +Time_, pp. 281-289; F.A. Ogg, _National Progress_ (American Nation +Series), pp. 40-75; Paxson, _The New Nation_ (Riverside Series), pp. +293-307. + +=Our Insular Possessions.=--Elson, _History of the United States_, pp. +896-904. + +=Latin-American Relations.=--Haworth, pp. 294-299; Ogg, pp. 254-257. + +=The Panama Canal.=--Haworth, pp. 300-309; Ogg, pp. 266-277; Paxson, pp. +286-292; Elson, pp. 906-911. + +=Conservation.=--Haworth, pp. 331-334; Ogg, pp. 96-115; Beard, _American +Government and Politics_ (3d ed.), pp. 401-416. + +=Republican Dissensions under Taft's Administration.=--Haworth, pp. +351-360; Ogg, pp. 167-186; Paxson, pp. 324-342; Elson, pp. 916-924. + +=The Campaign of 1912.=--Haworth, pp. 360-379; Ogg, pp. 187-208. + + +=Questions= + +1. Compare the early career of Roosevelt with that of some other +President. + +2. Name the chief foreign and domestic questions of the Roosevelt-Taft +administrations. + +3. What international complications were involved in the Panama Canal +problem? + +4. Review the Monroe Doctrine. Discuss Roosevelt's applications of it. + +5. What is the strategic importance of the Caribbean to the United +States? + +6. What is meant by the sea power? Trace the voyage of the fleet around +the world and mention the significant imperial and commercial points +touched. + +7. What is meant by the question: "Does the Constitution follow the +flag?" + +8. Trace the history of self-government in Porto Rico. In the +Philippines. + +9. What is Cuba's relation to the United States? + +10. What was Roosevelt's theory of our Constitution? + +11. Give Roosevelt's views on trusts, labor, taxation. + +12. Outline the domestic phases of Roosevelt's administrations. + +13. Account for the dissensions under Taft. + +14. Trace the rise of the Progressive movement. + +15. What was Roosevelt's progressive program? + +16. Review Wilson's early career and explain the underlying theory of +_The New Freedom_. + + + + +CHAPTER XXII + +THE SPIRIT OF REFORM IN AMERICA + + +AN AGE OF CRITICISM + +=Attacks on Abuses in American Life.=--The crisis precipitated by the +Progressive uprising was not a sudden and unexpected one. It had been +long in preparation. The revolt against corruption in politics which +produced the Liberal Republican outbreak in the seventies and the +Mugwump movement of the eighties was followed by continuous criticism of +American political and economic development. From 1880 until his death +in 1892, George William Curtis, as president of the Civil Service Reform +Association, kept up a running fire upon the abuses of the spoils +system. James Bryce, an observant English scholar and man of affairs, in +his great work, _The American Commonwealth_, published in 1888, by +picturing fearlessly the political rings and machines which dominated +the cities, gave the whole country a fresh shock. Six years later Henry +D. Lloyd, in a powerful book entitled _Wealth against Commonwealth_, +attacked in scathing language certain trusts which had destroyed their +rivals and bribed public officials. In 1903 Miss Ida Tarbell, an author +of established reputation in the historical field, gave to the public an +account of the Standard Oil Company, revealing the ruthless methods of +that corporation in crushing competition. About the same time Lincoln +Steffens exposed the sordid character of politics in several +municipalities in a series of articles bearing the painful heading: _The +Shame of the Cities_. The critical spirit appeared in almost every form; +in weekly and monthly magazines, in essays and pamphlets, in editorials +and news stories, in novels like Churchill's _Coniston_ and Sinclair's +_The Jungle_. It became so savage and so wanton that the opening years +of the twentieth century were well named "the age of the muckrakers." + +=The Subjects of the Criticism.=--In this outburst of invective, nothing +was spared. It was charged that each of the political parties had fallen +into the hands of professional politicians who devoted their time to +managing conventions, making platforms, nominating candidates, and +dictating to officials; in return for their "services" they sold offices +and privileges. It was alleged that mayors and councils had bargained +away for private benefit street railway and other franchises. It was +asserted that many powerful labor unions were dominated by men who +blackmailed employers. Some critics specialized in descriptions of the +poverty, slums, and misery of great cities. Others took up "frenzied +finance" and accused financiers of selling worthless stocks and bonds to +an innocent public. Still others professed to see in the accumulations +of millionaires the downfall of our republic. + +=The Attack on "Invisible Government."=--Some even maintained that the +control of public affairs had passed from the people to a sinister +minority called "the invisible government." So eminent and conservative +a statesman as the Hon. Elihu Root lent the weight of his great name to +such an imputation. Speaking of his native state, New York, he said: +"What is the government of this state? What has it been during the forty +years of my acquaintance with it? The government of the Constitution? +Oh, no; not half the time or half way.... From the days of Fenton and +Conkling and Arthur and Cornell and Platt, from the days of David B. +Hill down to the present time, the government of the state has presented +two different lines of activity: one, of the constitutional and +statutory officers of the state and the other of the party leaders; they +call them party bosses. They call the system--I don't coin the +phrase--the system they call 'invisible government.' For I don't know +how many years Mr. Conkling was the supreme ruler in this state. The +governor did not count, the legislature did not count, comptrollers and +secretaries of state and what not did not count. It was what Mr. +Conkling said, and in a great outburst of public rage he was pulled +down. Then Mr. Platt ruled the state; for nigh upon twenty years he +ruled it. It was not the governor; it was not the legislature; it was +Mr. Platt. And the capital was not here [in Albany]; it was at 49 +Broadway; Mr. Platt and his lieutenants. It makes no difference what +name you give, whether you call it Fenton or Conkling or Cornell or +Arthur or Platt or by the names of men now living. The ruler of the +state during the greater part of the forty years of my acquaintance with +the state government has not been any man authorized by the constitution +or by law.... The party leader is elected by no one, accountable to no +one, bound by no oath of office, removable by no one." + +=The Nation Aroused.=--With the spirit of criticism came also the spirit +of reform. The charges were usually exaggerated; often wholly false; but +there was enough truth in them to warrant renewed vigilance on the part +of American democracy. President Roosevelt doubtless summed up the +sentiment of the great majority of citizens when he demanded the +punishment of wrong-doers in 1907, saying: "It makes not a particle of +difference whether these crimes are committed by a capitalist or by a +laborer, by a leading banker or manufacturer or railroad man or by a +leading representative of a labor union. Swindling in stocks, corrupting +legislatures, making fortunes by the inflation of securities, by +wrecking railroads, by destroying competitors through rebates--these +forms of wrong-doing in the capitalist are far more infamous than any +ordinary form of embezzlement or forgery." The time had come, he added, +to stop "muckraking" and proceed to the constructive work of removing +the abuses that had grown up. + + +POLITICAL REFORMS + +=The Public Service.=--It was a wise comprehension of the needs of +American democracy that led the friends of reform to launch and to +sustain for more than half a century a movement to improve the public +service. On the one side they struck at the spoils system; at the right +of the politicians to use public offices as mere rewards for partisan +work. The federal civil service act of 1883 opened the way to reform by +establishing five vital principles in law: (1) admission to office, not +on the recommendation of party workers, but on the basis of competitive +examinations; (2) promotion for meritorious service of the government +rather than of parties; (3) no assessment of office holders for campaign +funds; (4) permanent tenure during good behavior; and (5) no dismissals +for political reasons. The act itself at first applied to only 14,000 +federal offices, but under the constant pressure from the reformers it +was extended until in 1916 it covered nearly 300,000 employees out of an +executive force of approximately 414,000. While gaining steadily at +Washington, civil service reformers carried their agitation into the +states and cities. By 1920 they were able to report ten states with +civil service commissions and the merit system well intrenched in more +than three hundred municipalities. + +In excluding spoilsmen from public office, the reformers were, in a +sense, engaged in a negative work: that of "keeping the rascals out." +But there was a second and larger phase to their movement, one +constructive in character: that of getting skilled, loyal, and efficient +servants into the places of responsibility. Everywhere on land and sea, +in town and country, new burdens were laid upon public officers. They +were called upon to supervise the ships sailing to and from our ports; +to inspect the water and milk supplies of our cities; to construct and +operate great public works, such as the Panama and Erie canals; to +regulate the complicated rates of railway companies; to safeguard health +and safety in a thousand ways; to climb the mountains to fight forest +fires; and to descend into the deeps of the earth to combat the deadly +coal gases that assail the miners. In a word, those who labored to +master the secrets and the powers of nature were summoned to the aid of +the government: chemists, engineers, architects, nurses, surgeons, +foresters--the skilled in all the sciences, arts, and crafts. + +Keeping rascals out was no task at all compared with the problem of +finding competent people for all the technical offices. "Now," said the +reformers, "we must make attractive careers in the government work for +the best American talent; we must train those applying for admission and +increase the skill of those already in positions of trust; we must see +to it that those entering at the bottom have a chance to rise to the +top; in short, we must work for a government as skilled and efficient as +it is strong, one commanding all the wisdom and talent of America that +public welfare requires." + +=The Australian Ballot.=--A second line of attack on the political +machines was made in connection with the ballot. In the early days +elections were frequently held in the open air and the poll was taken by +a show of hands or by the enrollment of the voters under names of their +favorite candidates. When this ancient practice was abandoned in favor +of the printed ballot, there was still no secrecy about elections. Each +party prepared its own ballot, often of a distinctive color, containing +the names of its candidates. On election day, these papers were handed +out to the voters by party workers. Any one could tell from the color of +the ballot dropped into the box, or from some mark on the outside of the +folded ballot, just how each man voted. Those who bought votes were sure +that their purchases were "delivered." Those who intimidated voters +could know when their intimidation was effective. In this way the party +ballot strengthened the party machine. + +As a remedy for such abuses, reformers, learning from the experience of +Australia, urged the adoption of the "Australian ballot." That ballot, +though it appeared in many forms, had certain constant features. It was +official, that is, furnished by the government, not by party workers; it +contained the names of all candidates of all parties; it was given out +only in the polling places; and it was marked in secret. The first state +to introduce it was Massachusetts. The year was 1888. Before the end of +the century it had been adopted by nearly all the states in the union. +The salutary effect of the reform in reducing the amount of cheating +and bribery in elections was beyond all question. + +=The Direct Primary.=--In connection with the uprising against machine +politics, came a call for the abolition of the old method of nominating +candidates by conventions. These time-honored party assemblies, which +had come down from the days of Andrew Jackson, were, it was said, merely +conclaves of party workers, sustained by the spoils system, and +dominated by an inner circle of bosses. The remedy offered in this case +was again "more democracy," namely, the abolition of the party +convention and the adoption of the direct primary. Candidates were no +longer to be chosen by secret conferences. Any member of a party was to +be allowed to run for any office, to present his name to his party by +securing signatures to a petition, and to submit his candidacy to his +fellow partisans at a direct primary--an election within the party. In +this movement Governor La Follette of Wisconsin took the lead and his +state was the first in the union to adopt the direct primary for +state-wide purposes. The idea spread, rapidly in the West, more slowly +in the East. The public, already angered against "the bosses," grasped +eagerly at it. Governor Hughes in New York pressed it upon the unwilling +legislature. State after state accepted it until by 1918 Rhode Island, +Delaware, Connecticut, and New Mexico were the only states that had not +bowed to the storm. Still the results were disappointing and at that +very time the pendulum was beginning to swing backward. + +=Popular Election of Federal Senators.=--While the movement for direct +primaries was still advancing everywhere, a demand for the popular +election of Senators, usually associated with it, swept forward to +victory. Under the original Constitution, it had been expressly provided +that Senators should be chosen by the legislatures of the states. In +practice this rule transferred the selection of Senators to secret +caucuses of party members in the state legislatures. In connection with +these caucuses there had been many scandals, some direct proofs of +brazen bribery and corruption, and dark hints besides. The Senate was +called by its detractors "a millionaires' club" and it was looked upon +as the "citadel of conservatism." The prescription in this case was +likewise "more democracy"--direct election of Senators by popular vote. + +This reform was not a new idea. It had been proposed in Congress as +early as 1826. President Johnson, an ardent advocate, made it the +subject of a special message in 1868 Not long afterward it appeared in +Congress. At last in 1893, the year after the great Populist upheaval, +the House of Representatives by the requisite two-thirds vote +incorporated it in an amendment to the federal Constitution. Again and +again it passed the House; but the Senate itself was obdurate. Able +Senators leveled their batteries against it. Mr. Hoar of Massachusetts +declared that it would transfer the seat of power to the "great cities +and masses of population"; that it would "overthrow the whole scheme of +the Senate and in the end the whole scheme of the national Constitution +as designed and established by the framers of the Constitution and the +people who adopted it." + +Failing in the Senate, advocates of popular election made a rear assault +through the states. They induced state legislatures to enact laws +requiring the nomination of candidates for the Senate by the direct +primary, and then they bound the legislatures to abide by the popular +choice. Nevada took the lead in 1899. Shortly afterward Oregon, by the +use of the initiative and referendum, practically bound legislators to +accept the popular nominee and the country witnessed the spectacle of a +Republican legislature "electing" a Democrat to represent the state in +the Senate at Washington. By 1910 three-fourths of the states had +applied the direct primary in some form to the choice of Senators. Men +selected by that method began to pour in upon the floors of Congress; +finally in 1912 the two-thirds majority was secured for an amendment to +the federal Constitution providing for the popular election of Senators. +It was quickly ratified by the states. The following year it was +proclaimed in effect. + +=The Initiative and Referendum.=--As a corrective for the evils which +had grown up in state legislatures there arose a demand for the +introduction of a Swiss device known as the initiative and referendum. +The initiative permits any one to draw up a proposed bill; and, on +securing a certain number of signatures among the voters, to require the +submission of the measure to the people at an election. If the bill thus +initiated receives a sufficient majority, it becomes a law. The +referendum allows citizens who disapprove any act passed by the +legislature to get up a petition against it and thus bring about a +reference of the measure to the voters at the polls for approval or +rejection. These two practices constitute a form of "direct government." + +These devices were prescribed "to restore the government to the people." +The Populists favored them in their platform of 1896. Mr. Bryan, two +years later, made them a part of his program, and in the same year South +Dakota adopted them. In 1902 Oregon, after a strenuous campaign, added a +direct legislation amendment to the state constitution. Within ten years +all the Southwestern, Mountain, and Pacific states, except Texas and +Wyoming, had followed this example. To the east of the Mississippi, +however, direct legislation met a chilly reception. By 1920 only five +states in this section had accepted it: Maine, Massachusetts, Ohio, +Michigan, and Maryland, the last approving the referendum only. + +=The Recall.=--Executive officers and judges, as well as legislatures, +had come in for their share of criticism, and it was proposed that they +should likewise be subjected to a closer scrutiny by the public. For +this purpose there was advanced a scheme known as the recall--which +permitted a certain percentage of the voters to compel any officer, at +any time during his term, to go before the people at a new election. +This feature of direct government, tried out first in the city of Los +Angeles, was extended to state-wide uses in Oregon in 1908. It failed, +however, to capture popular imagination to the same degree as the +initiative and referendum. At the end of ten years' agitation, only ten +states, mainly in the West, had adopted it for general purposes, and +four of them did not apply it to the judges of the courts. Still it was +extensively acclaimed in cities and incorporated into hundreds of +municipal laws and charters. + +As a general proposition, direct government in all its forms was +bitterly opposed by men of a conservative cast of mind. It was denounced +by Senator Henry Cabot Lodge as "nothing less than a complete revolution +in the fabric of our government and in the fundamental principles upon +which that government rests." In his opinion, it promised to break down +the representative principle and "undermine and overthrow the bulwarks +of ordered liberty and individual freedom." Mr. Taft shared Mr. Lodge's +views and spoke of direct government with scorn. "Votes," he exclaimed, +"are not bread ... referendums do not pay rent or furnish houses, +recalls do not furnish clothes, initiatives do not supply employment or +relieve inequalities of condition or of opportunity." + +=Commission Government for Cities.=--In the restless searching out of +evils, the management of cities early came under critical scrutiny. City +government, Mr. Bryce had remarked, was the one conspicuous failure in +America. This sharp thrust, though resented by some, was accepted as a +warning by others. Many prescriptions were offered by doctors of the +body politic. Chief among them was the idea of simplifying the city +government so that the light of public scrutiny could shine through it. +"Let us elect only a few men and make them clearly responsible for the +city government!" was the new cry in municipal reform. So, many city +councils were reduced in size; one of the two houses, which several +cities had adopted in imitation of the federal government, was +abolished; and in order that the mayor could be held to account, he was +given the power to appoint all the chief officials. This made the mayor, +in some cases, the only elective city official and gave the voters a +"short ballot" containing only a few names--an idea which some proposed +to apply also to the state government. + +A further step in the concentration of authority was taken in Galveston, +Texas, where the people, looking upon the ruin of their city wrought by +the devastating storm of 1901, and confronted by the difficult problems +of reconstruction, felt the necessity for a more businesslike management +of city affairs and instituted a new form of local administration. They +abolished the old scheme of mayor and council and vested all power in +five commissioners, one of whom, without any special prerogatives, was +assigned to the office of "mayor president." In 1908, the commission +form of government, as it was soon characterized, was adopted by Des +Moines, Iowa. The attention of all municipal reformers was drawn to it +and it was hailed as the guarantee of a better day. By 1920, more than +four hundred cities, including Memphis, Spokane, Birmingham, Newark, and +Buffalo, had adopted it. Still the larger cities like New York and +Chicago kept their boards of aldermen. + +=The City Manager Plan.=--A few years' experience with commission +government revealed certain patent defects. The division of the work +among five men was frequently found to introduce dissensions and +irresponsibility. Commissioners were often lacking in the technical +ability required to manage such difficult matters as fire and police +protection, public health, public works, and public utilities. Some one +then proposed to carry over into city government an idea from the +business world. In that sphere the stockholders of each corporation +elect the directors and the directors, in turn, choose a business +manager to conduct the affairs of the company. It was suggested that the +city commissioners, instead of attempting to supervise the details of +the city administration, should select a manager to do this. The scheme +was put into effect in Sumter, South Carolina, in 1912. Like the +commission plan, it became popular. Within eight years more than one +hundred and fifty towns and cities had adopted it. Among the larger +municipalities were Dayton, Springfield (Ohio), Akron, Kalamazoo, and +Phoenix. It promised to create a new public service profession, that of +city manager. + + +MEASURES OF ECONOMIC REFORM + +=The Spirit of American Reform.=--The purification of the ballot, the +restriction of the spoils system, the enlargement of direct popular +control over the organs of government were not the sole answers made by +the reformers to the critics of American institutions. Nor were they the +most important. In fact, they were regarded not as ends in themselves, +but as means to serve a wider purpose. That purpose was the promotion of +the "general welfare." The concrete objects covered by that broad term +were many and varied; but they included the prevention of extortion by +railway and other corporations, the protection of public health, the +extension of education, the improvement of living conditions in the +cities, the elimination of undeserved poverty, the removal of gross +inequalities in wealth, and more equality of opportunity. + +All these things involved the use of the powers of government. Although +a few clung to the ancient doctrine that the government should not +interfere with private business at all, the American people at large +rejected that theory as vigorously as they rejected the doctrines of an +extreme socialism which exalts the state above the individual. Leaders +representing every shade of opinion proclaimed the government an +instrument of common welfare to be used in the public interest. "We must +abandon definitely," said Roosevelt, "the _laissez-faire_ theory of +political economy and fearlessly champion a system of increased +governmental control, paying no attention to the cries of worthy people +who denounce this as socialistic." This view was shared by Mr. Taft, who +observed: "Undoubtedly the government can wisely do much more ... to +relieve the oppressed, to create greater equality of opportunity, to +make reasonable terms for labor in employment, and to furnish vocational +education." He was quick to add his caution that "there is a line beyond +which the government cannot go with any good practical results in +seeking to make men and society better." + +=The Regulation of Railways.=--The first attempts to use the government +in a large way to control private enterprise in the public interest were +made by the Northwestern states in the decade between 1870 and 1880. +Charges were advanced by the farmers, particularly those organized into +Granges, that the railways extorted the highest possible rates for +freight and passengers, that favoritism was shown to large shippers, +that fraudulent stocks and bonds were sold to the innocent public. It +was claimed that railways were not like other enterprises, but were +"quasi-public" concerns, like the roads and ferries, and thus subject to +government control. Accordingly laws were enacted bringing the railroads +under state supervision. In some cases the state legislature fixed the +maximum rates to be charged by common carriers, and in other cases +commissions were created with the power to establish the rates after an +investigation. This legislation was at first denounced in the East as +nothing less than the "confiscation" of the railways in the interest of +the farmers. Attempts to have the Supreme Court of the United States +declare it unconstitutional were made without avail; still a principle +was finally laid down to the effect that in fixing rates state +legislatures and commissions must permit railway companies to earn a +"fair" return on the capital invested. + +In a few years the Granger spirit appeared in Congress. An investigation +revealed a long list of abuses committed by the railways against +shippers and travelers. The result was the interstate commerce act of +1887, which created the Interstate Commerce Commission, forbade +discriminations in rates, and prohibited other objectionable practices +on the part of railways. This measure was loosely enforced and the +abuses against which it was directed continued almost unabated. A demand +for stricter control grew louder and louder. Congress was forced to +heed. In 1903 it enacted the Elkins law, forbidding railways to charge +rates other than those published, and laid penalties upon the officers +and agents of companies, who granted secret favors to shippers, and upon +shippers who accepted them. Three years later a still more drastic step +was taken by the passage of the Hepburn act. The Interstate Commerce +Commission was authorized, upon complaint of some party aggrieved, and +after a public hearing, to determine whether just and reasonable rates +had been charged by the companies. In effect, the right to fix freight +and passenger rates was taken out of the hands of the owners of the +railways engaged in interstate commerce and vested in the hands of the +Interstate Commerce Commission. Thus private property to the value of +$20,000,000,000 or more was declared to be a matter of public concern +and subject to government regulation in the common interest. + +=Municipal Utilities.=--Similar problems arose in connection with the +street railways, electric light plants, and other utilities in the great +cities. In the beginning the right to construct such undertakings was +freely, and often corruptly, granted to private companies by city +councils. Distressing abuses arose in connection with such practices. +Many grants or franchises were made perpetual, or perhaps for a term of +999 years. The rates charged and services rendered were left largely to +the will of the companies holding the franchises. Mergers or unions of +companies were common and the public was deluged with stocks and bonds +of doubtful value; bankruptcies were frequent. The connection between +the utility companies and the politicians was, to say the least, not +always in the public interest. + +American ingenuity was quick to devise methods for eliminating such +evils. Three lines of progress were laid out by the reformers. One group +proposed that such utilities should be subject to municipal or state +regulation, that the formation of utility companies should be under +public control, and that the issue of stocks and bonds must be approved +by public authority. In some cases state, and in other cases municipal, +commissions were created to exercise this great power over "quasi-public +corporations." Wisconsin, by laws enacted in 1907, put all heat, light, +water works, telephone, and street railway companies under the +supervision of a single railway commission. Other states followed this +example rapidly. By 1920 the principle of public control over municipal +utilities was accepted in nearly every section of the union. + +A second line of reform appeared in the "model franchise" for utility +corporations. An illustration of this tendency was afforded by the +Chicago street railway settlement of 1906. The total capital of the +company was fixed at a definite sum, its earnings were agreed upon, and +the city was given the right to buy and operate the system if it desired +to do so. In many states, about the same time, it was provided that no +franchises to utility companies could run more than twenty-five years. + +A third group of reformers were satisfied with nothing short of +municipal ownership. They proposed to drive private companies entirely +out of the field and vest the ownership and management of municipal +plants in the city itself. This idea was extensively applied to electric +light and water works plants, but to street railways in only a few +cities, including San Francisco and Seattle. In New York the subways are +owned by the city but leased for operation. + +=Tenement House Control.=--Among the other pressing problems of the +cities was the overcrowding in houses unfit for habitation. An inquiry +in New York City made under the authority of the state in 1902 revealed +poverty, misery, slums, dirt, and disease almost beyond imagination. The +immediate answer was the enactment of a tenement house law prescribing +in great detail the size of the rooms, the air space, the light and the +sanitary arrangement for all new buildings. An immense improvement +followed and the idea was quickly taken up in other states having large +industrial centers. In 1920 New York made a further invasion of the +rights of landlords by assuring to the public "reasonable rents" for +flats and apartments. + +=Workmen's Compensation.=--No small part of the poverty in cities was +due to the injury of wage-earners while at their trade. Every year the +number of men and women killed or wounded in industry mounted higher. +Under the old law, the workman or his family had to bear the loss unless +the employer had been guilty of some extraordinary negligence. Even in +that case an expensive lawsuit was usually necessary to recover +"damages." In short, although employers insured their buildings and +machinery against necessary risks from fire and storm, they allowed +their employees to assume the heavy losses due to accidents. The +injustice of this, though apparent enough now, was once not generally +recognized. It was said to be unfair to make the employer pay for +injuries for which he was not personally responsible; but the argument +was overborne. + +[Illustration: AN EAST SIDE STREET IN NEW YORK] + +About 1910 there set in a decided movement in the direction of lifting +the burden of accidents from the unfortunate victims. In the first +place, laws were enacted requiring employers to pay damages in certain +amounts according to the nature of the case, no matter how the accident +occurred, as long as the injured person was not guilty of willful +negligence. By 1914 more than one-half the states had such laws. In the +second place, there developed schemes of industrial insurance in the +form of automatic grants made by state commissions to persons injured in +industries, the funds to be provided by the employers or the state or by +both. By 1917 thirty-six states had legislation of this type. + +=Minimum Wages and Mothers' Pensions.=--Another source of poverty, +especially among women and children, was found to be the low wages paid +for their labor. Report after report showed this. In 1912 Massachusetts +took a significant step in the direction of declaring the minimum wages +which might be paid to women and children. Oregon, the following year, +created a commission with power to prescribe minimum wages in certain +industries, based on the cost of living, and to enforce the rates fixed. +Within a short time one-third of the states had legislation of this +character. To cut away some of the evils of poverty and enable widows to +keep their homes intact and bring up their children, a device known as +mothers' pensions became popular during the second decade of the +twentieth century. At the opening of 1913 two states, Colorado and +Illinois, had laws authorizing the payment from public funds of definite +sums to widows with children. Within four years, thirty-five states had +similar legislation. + +=Taxation and Great Fortunes.=--As a part of the campaign waged against +poverty by reformers there came a demand for heavy taxes upon great +fortunes, particularly taxes upon inheritances or estates passing to +heirs on the decease of the owners. Roosevelt was an ardent champion of +this type of taxation and dwelt upon it at length in his message to +Congress in 1907. "Such a tax," he said, "would help to preserve a +measurable equality of opportunity for the people of the generations +growing to manhood.... Our aim is to recognize what Lincoln pointed out: +the fact that there are some respects in which men are obviously not +equal; but also to insist that there should be equality of self-respect +and of mutual respect, an equality of rights before the law, and at +least an approximate equality in the conditions under which each man +obtains the chance to show the stuff that is in him when compared with +his fellows." + +The spirit of the new age was, therefore, one of reform, not of +revolution. It called for no evolutionary or utopian experiments, but +for the steady and progressive enactment of measures aimed at admitted +abuses and designed to accomplish tangible results in the name of public +welfare. + + +=General References= + +J. Bryce, _The American Commonwealth_. + +R.C. Brooks, _Corruption in American Life_. + +E.A. Ross, _Changing America_. + +P.L. Haworth, _America in Ferment_. + +E.R.A. Seligman, _The Income Tax_. + +W.Z. Ripley, _Railroads: Rates and Regulation_. + +E.S. Bradford, _Commission Government in American Cities_. + +H.R. Seager, _A Program of Social Reform_. + +C. Zueblin, _American Municipal Progress_. + +W.E. Walling, _Progressivism and After_. + +_The American Year Book_ (an annual publication which contains reviews +of reform legislation). + + +=Research Topics= + +="The Muckrakers."=--Paxson, _The New Nation_ (Riverside Series), pp. +309-323. + +=Civil Service Reform.=--Beard, _American Government and Politics_ (3d +ed.), pp. 222-230; Ogg, _National Progress_ (American Nation Series), +pp. 135-142. + +=Direct Government.=--Beard, _American Government_, pp. 461-473; Ogg, +pp. 160-166. + +=Popular Election of Senators.=--Beard, _American Government_, pp. +241-244; Ogg, pp. 149-150. + +=Party Methods.=--Beard, _American Government_, pp. 656-672. + +=Ballot Reform.=--Beard, _American Government_, pp. 672-705. + +=Social and Economic Legislation.=--Beard, _American Government_, pp. +721-752. + + +=Questions= + +1. Who were some of the critics of abuses in American life? + +2. What particular criticisms were advanced? + +3. How did Elihu Root define "invisible government"? + +4. Discuss the use of criticism as an aid to progress in a democracy. + +5. Explain what is meant by the "merit system" in the civil service. +Review the rise of the spoils system. + +6. Why is the public service of increasing importance? Give some of its +new problems. + +7. Describe the Australian ballot and the abuses against which it is +directed. + +8. What are the elements of direct government? Sketch their progress in +the United States. + +9. Trace the history of popular election of Senators. + +10. Explain the direct primary. Commission government. The city manager +plan. + +11. How does modern reform involve government action? On what theory is +it justified? + +12. Enumerate five lines of recent economic reform. + + + + +CHAPTER XXIII + +THE NEW POLITICAL DEMOCRACY + + +=Women in Public Affairs.=--The social legislation enacted in response +to the spirit of reform vitally affected women in the home and in +industry and was promoted by their organizations. Where they did not +lead, they were affiliated with movements for social improvement. No +cause escaped their attention; no year passed without widening the range +of their interests. They served on committees that inquired into the +problems of the day; they appeared before legislative assemblies to +advocate remedies for the evils they discovered. By 1912 they were a +force to be reckoned with in national politics. In nine states complete +and equal suffrage had been established, and a widespread campaign for a +national suffrage amendment was in full swing. On every hand lay +evidences that their sphere had been broadened to include public +affairs. This was the culmination of forces that had long been +operating. + +=A New Emphasis in History.=--A movement so deeply affecting important +interests could not fail to find a place in time in the written record +of human progress. History often began as a chronicle of kings and +queens, knights and ladies, written partly to amuse and partly to +instruct the classes that appeared in its pages. With the growth of +commerce, parliaments, and international relations, politics and +diplomacy were added to such chronicles of royal and princely doings. +After the rise of democracy, industry, and organized labor, the +transactions of everyday life were deemed worthy of a place in the pages +of history. In each case history was rewritten and the past rediscovered +in the light of the new age. So it will be with the rise and growth of +women's political power. The history of their labor, their education, +their status in society, their influence on the course of events will be +explored and given its place in the general record. + +It will be a history of change. The superior position which women enjoy +in America to-day is the result of a slow evolution from an almost +rightless condition in colonial times. The founders of America brought +with them the English common law. Under that law, a married woman's +personal property--jewels, money, furniture, and the like--became her +husband's property; the management of her lands passed into his control. +Even the wages she earned, if she worked for some one else, belonged to +him. Custom, if not law, prescribed that women should not take part in +town meetings or enter into public discussions of religious questions. +Indeed it is a far cry from the banishment of Anne Hutchinson from +Massachusetts in 1637, for daring to dispute with the church fathers, to +the political conventions of 1920 in which women sat as delegates, made +nominating speeches, and served on committees. In the contrast between +these two scenes may be measured the change in the privileges of women +since the landing of the Pilgrims. The account of this progress is a +narrative of individual effort on the part of women, of organizations +among them, of generous aid from sympathetic men in the long agitation +for the removal of civil and political disabilities. It is in part also +a narrative of irresistible economic change which drew women into +industry, created a leisure class, gave women wages and incomes, and +therewith economic independence. + + +THE RISE OF THE WOMAN MOVEMENT + +=Protests of Colonial Women.=--The republican spirit which produced +American independence was of slow and steady growth. It did not spring +up full-armed in a single night. It was, on the contrary, nourished +during a long period of time by fireside discussions as well as by +debates in the public forum. Women shared that fireside sifting of +political principles and passed on the findings of that scrutiny in +letters to their friends, newspaper articles, and every form of written +word. How widespread was this potent, though not spectacular force, is +revealed in the collections of women's letters, articles, songs, dramas, +and satirical "skits" on English rule that have come down to us. In this +search into the reasons of government, some women began to take thought +about laws that excluded them from the ballot. Two women at least left +their protests on record. Abigail, the ingenious and witty wife of John +Adams, wrote to her husband, in March, 1776, that women objected "to all +arbitrary power whether of state or males" and demanded political +privileges in the new order then being created. Hannah Lee Corbin, the +sister of "Lighthorse" Harry Lee, protested to her brother against the +taxation of women without representation. + +[Illustration: ABIGAIL ADAMS] + +=The Stir among European Women.=--Ferment in America, in the case of +women as of men, was quickened by events in Europe. In 1792, Mary +Wollstonecraft published in England the _Vindication of the Rights of +Women_--a book that was destined to serve the cause of liberty among +women as the writings of Locke and Paine had served that of men. The +specific grievances which stirred English women were men's invasion of +women's industries, such as spinning and weaving; the denial of equal +educational opportunities; and political disabilities. In France also +the great Revolution raised questionings about the status of women. The +rights of "citizenesses" as well as the rights of "citizens" were +examined by the boldest thinkers. This in turn reacted upon women in the +United States. + +=Leadership in America.=--The origins of the American woman movement are +to be found in the writings of a few early intellectual leaders. During +the first decades of the nineteenth century, books, articles, and +pamphlets about women came in increasing numbers from the press. Lydia +Maria Child wrote a history of women; Margaret Fuller made a critical +examination of the status of women in her time; and Mrs. Elizabeth Ellet +supplemented the older histories by showing what an important part women +had played in the American Revolution. + +=The Struggle for Education.=--Along with criticism, there was carried +on a constructive struggle for better educational facilities for women +who had been from the beginning excluded from every college in the +country. In this long battle, Emma Willard and Mary Lyon led the way; +the former founded a seminary at Troy, New York; and the latter made the +beginnings of Mount Holyoke College in Massachusetts. Oberlin College in +Ohio, established in 1833, opened its doors to girls and from it were +graduated young students to lead in the woman movement. Sarah J. Hale, +who in 1827 became the editor of a "Ladies' Magazine," published in +Boston, conducted a campaign for equal educational opportunities which +helped to bear fruit in the founding of Vassar College shortly after the +Civil War. + +=The Desire to Effect Reforms.=--As they came to study their own history +and their own part in civilization, women naturally became deeply +interested in all the controversies going on around them. The temperance +question made a special appeal to them and they organized to demand the +right to be heard on it. In 1846 the "Daughters of Temperance" formed a +secret society favoring prohibition. They dared to criticize the +churches for their indifference and were so bold as to ask that +drunkenness be made a ground for divorce. + +The slavery issue even more than temperance called women into public +life. The Grimke sisters of South Carolina emancipated their bondmen, +and one of these sisters, exiled from Charleston for her "Appeal to the +Christian Women of the South," went North to work against the slavery +system. In 1837 the National Women's Anti-Slavery Convention met in New +York; seventy-one women delegates represented eight states. Three years +later eight American women, five of them in Quaker costume, attended the +World Anti-Slavery Convention in London, much to the horror of the men, +who promptly excluded them from the sessions on the ground that it was +not fitting for women to take part in such meetings. + +In other spheres of activity, especially social service, women steadily +enlarged their interest. Nothing human did they consider alien to them. +They inveighed against cruel criminal laws and unsanitary prisons. They +organized poor relief and led in private philanthropy. Dorothea Dix +directed the movement that induced the New York legislature to establish +in 1845 a separate asylum for the criminal insane. In the same year +Sarah G. Bagley organized the Lowell Female Reform Association for the +purpose of reducing the long hours of labor for women, safeguarding "the +constitutions of future generations." Mrs. Eliza Woodson Farnham, matron +in Sing Sing penitentiary, was known throughout the nation for her +social work, especially prison reform. Wherever there were misery and +suffering, women were preparing programs of relief. + +=Freedom of Speech for Women.=--In the advancement of their causes, of +whatever kind, women of necessity had to make public appeals and take +part in open meetings. Here they encountered difficulties. The +appearance of women on the platform was new and strange. Naturally it +was widely resented. Antoinette Brown, although she had credentials as a +delegate, was driven off the platform of a temperance convention in New +York City simply because she was a woman. James Russell Lowell, editor +of the "Atlantic Monthly," declined a poem from Julia Ward Howe on the +theory that no woman could write a poem; but he added on second thought +that he might consider an article in prose. Nathaniel Hawthorne, +another editor, even objected to something in prose because to him "all +ink-stained women were equally detestable." To the natural resentment +against their intrusion into new fields was added that aroused by their +ideas and methods. As temperance reformers, they criticized in a caustic +manner those who would not accept their opinions. As opponents of +slavery they were especially bitter. One of their conventions, held at +Philadelphia in 1833, passed a resolution calling on all women to leave +those churches that would not condemn every form of human bondage. This +stirred against them many of the clergy who, accustomed to having women +sit silent during services, were in no mood to treat such a revolt +leniently. Then came the last straw. Women decided that they would +preach--out of the pulpit first, and finally in it. + +=Women in Industry.=--The period of this ferment was also the age of the +industrial revolution in America, the rise of the factory system, and +the growth of mill towns. The labor of women was transferred from the +homes to the factories. Then arose many questions: the hours of labor, +the sanitary conditions of the mills, the pressure of foreign +immigration on native labor, the wages of women as compared with those +of men, and the right of married women to their own earnings. Labor +organizations sprang up among working women. The mill girls of Lowell, +Massachusetts, mainly the daughters of New England farmers, published a +magazine, "The Lowell Offering." So excellent were their writings that +the French statesman, Thiers, carried a copy of their paper into the +Chamber of Deputies to show what working women could achieve in a +republic. As women were now admittedly earning their own way in the +world by their own labor, they began to talk of their "economic +independence." + +=The World Shaken by Revolution.=--Such was the quickening of women's +minds in 1848 when the world was startled once more by a revolution in +France which spread to Germany, Poland, Austria, Hungary, and Italy. +Once more the people of the earth began to explore the principles of +democracy and expound human rights. Women, now better educated and more +"advanced" in their ideas, played a role of still greater importance in +that revolution. They led in agitations and uprisings. They suffered +from reaction and persecution. From their prison in France, two of them +who had been jailed for too much insistence on women's rights exchanged +greetings with American women who were raising the same issue here. By +this time the women had more supporters among the men. Horace Greeley, +editor of the New York _Tribune_, though he afterwards recanted, used +his powerful pen in their behalf. Anti-slavery leaders welcomed their +aid and repaid them by urging the enfranchisement of women. + +=The Woman's Rights Convention of 1848.=--The forces, moral and +intellectual, which had been stirring among women, crystallized a few +months after the outbreak of the European revolution in the first +Woman's Rights Convention in the history of America. It met at Seneca +Falls, New York, in 1848, on the call of Lucretia Mott, Martha Wright, +Elizabeth Cady Stanton, and Mary Ann McClintock, three of them Quakers. +Accustomed to take part in church meetings with men, the Quakers +naturally suggested that men as well as women be invited to attend the +convention. Indeed, a man presided over the conference, for that +position seemed too presumptuous even for such stout advocates of +woman's rights. + +The deliberations of the Seneca Falls convention resulted in a +Declaration of Rights modeled after the Declaration of Independence. For +example, the preamble began: "When in the course of human events it +becomes necessary for one portion of the family of man to assume among +the people of the earth a position different from that which they have +hitherto occupied...." So also it closed: "Such has been the patient +suffering of women under this government and such is now the necessity +which constrains them to demand the equal station to which they are +entitled." Then followed the list of grievances, the same number which +had been exhibited to George III in 1776. Especially did they assail the +disabilities imposed upon them by the English common law imported into +America--the law which denied married women their property, their wages, +and their legal existence as separate persons. All these grievances they +recited to "a candid world." The remedies for the evils which they +endured were then set forth in detail. They demanded "equal rights" in +the colleges, trades, and professions; equal suffrage; the right to +share in all political offices, honors, and emoluments; the right to +complete equality in marriage, including equal guardianship of the +children; and for married women the right to own property, to keep +wages, to make contracts, to transact business, and to testify in the +courts of justice. In short, they declared women to be persons as men +are persons and entitled to all the rights and privileges of human +beings. Such was the clarion call which went forth to the world in +1848--to an amused and contemptuous world, it must be admitted--but to a +world fated to heed and obey. + +=The First Gains in Civil Liberty.=--The convention of 1848 did not make +political enfranchisement the leading issue. Rather did it emphasize the +civil disabilities of women which were most seriously under discussion +at the time. Indeed, the New York legislature of that very year, as the +result of a twelve years' agitation, passed the Married Woman's Property +Act setting aside the general principles of the English common law as +applied to women and giving them many of the "rights of man." California +and Wisconsin followed in 1850; Massachusetts in 1854; and Kansas in +1859. Other states soon fell into line. Women's earnings and +inheritances were at last their own in some states at least. In a little +while laws were passed granting women rights as equal guardians of their +children and permitting them to divorce their husbands on the grounds of +cruelty and drunkenness. + +By degrees other steps were taken. The Woman's Medical College of +Pennsylvania was founded in 1850, and the Philadelphia School of Design +for Women three years later. In 1852 the American Women's Educational +Association was formed to initiate an agitation for enlarged +educational opportunities for women. Other colleges soon emulated the +example of Oberlin: the University of Utah in 1850; Hillsdale College in +Michigan in 1855; Baker University in Kansas in 1858; and the University +of Iowa in 1860. New trades and professions were opened to women and old +prejudices against their activities and demands slowly gave way. + + +THE NATIONAL STRUGGLE FOR WOMAN SUFFRAGE + +=The Beginnings of Organization.=--As women surmounted one obstacle +after another, the agitation for equal suffrage came to the front. If +any year is to be fixed as the date of its beginning, it may very well +be 1850, when the suffragists of Ohio urged the state constitutional +convention to confer the vote upon them. With apparent spontaneity there +were held in the same year state suffrage conferences in Indiana, +Pennsylvania, and Massachusetts; and connections were formed among the +leaders of these meetings. At the same time the first national suffrage +convention was held in Worcester, Massachusetts, on the call of +eighty-nine leading men and women representing six states. Accounts of +the convention were widely circulated in this country and abroad. +English women,--for instance, Harriet Martineau,--sent words of +appreciation for the work thus inaugurated. It inspired a leading +article in the "Westminster Review," which deeply interested the +distinguished economist, John Stuart Mill. Soon he was the champion of +woman suffrage in the British Parliament and the author of a powerful +tract _The Subjection of Women_, widely read throughout the +English-speaking world. Thus do world movements grow. Strange to relate +the women of England were enfranchised before the adoption of the +federal suffrage amendment in America. + +The national suffrage convention of 1850 was followed by an +extraordinary outburst of agitation. Pamphlets streamed from the press. +Petitions to legislative bodies were drafted, signed, and presented. +There were addresses by favorite orators like Garrison, Phillips, and +Curtis, and lectures and poems by men like Emerson, Longfellow, and +Whittier. In 1853 the first suffrage paper was founded by the wife of a +member of Congress from Rhode Island. By this time the last barrier to +white manhood suffrage in the North had been swept away and the woman's +movement was gaining momentum every year. + +=The Suffrage Movement Checked by the Civil War.=--Advocates of woman +suffrage believed themselves on the high road to success when the Civil +War engaged the energies and labors of the nation. Northern women became +absorbed in the struggle to preserve the union. They held no suffrage +conventions for five years. They transformed their associations into +Loyalty Leagues. They banded together to buy only domestic goods when +foreign imports threatened to ruin American markets. They rolled up +monster petitions in favor of the emancipation of slaves. In hospitals, +in military prisons, in agriculture, and in industry they bore their +full share of responsibility. Even when the New York legislature took +advantage of their unguarded moments and repealed the law giving the +mother equal rights with the father in the guardianship of children, +they refused to lay aside war work for agitation. As in all other wars, +their devotion was unstinted and their sacrifices equal to the +necessities of the hour. + +=The Federal Suffrage Amendment.=--Their plans and activities, when the +war closed, were shaped by events beyond their control. The emancipation +of the slaves and their proposed enfranchisement made prominent the +question of a national suffrage for the first time in our history. +Friends of the colored man insisted that his civil liberties would not +be safe unless he was granted the right to vote. The woman suffragists +very pertinently asked why the same principle did not apply to women. +The answer which they received was negative. The fourteenth amendment to +the federal Constitution, adopted in 1868, definitely put women aside by +limiting the scope of its application, so far as the suffrage was +concerned, to the male sex. In making manhood suffrage national, +however, it nationalized the issue. + +This was the signal for the advocates of woman suffrage. In March, 1869, +their proposed amendment was introduced in Congress by George W. Julian +of Indiana. It provided that no citizen should be deprived of the vote +on account of sex, following the language of the fifteenth amendment +which forbade disfranchisement on account of race. Support for the +amendment, coming from many directions, led the suffragists to believe +that their case was hopeful. In their platform of 1872, for example, the +Republicans praised the women for their loyal devotion to freedom, +welcomed them to spheres of wider usefulness, and declared that the +demand of any class of citizens for additional rights deserved +"respectful consideration." + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +SUSAN B. ANTHONY] + +Experience soon demonstrated, however, that praise was not the ballot. +Indeed the suffragists already had realized that a tedious contest lay +before them. They had revived in 1866 their regular national convention. +They gave the name of "The Revolution" to their paper, edited by +Elizabeth Cady Stanton and Susan B. Anthony. They formed a national +suffrage association and organized annual pilgrimages to Congress to +present their claims. Such activities bore some results. Many eminent +congressmen were converted to their cause and presented it ably to their +colleagues of both chambers. Still the subject was ridiculed by the +newspapers and looked upon as freakish by the masses. + +=The State Campaigns.=--Discouraged by the outcome of the national +campaign, suffragists turned to the voters of the individual states and +sought the ballot at their hands. Gains by this process were painfully +slow. Wyoming, it is true, while still a territory, granted suffrage to +women in 1869 and continued it on becoming a state twenty years later, +in spite of strong protests in Congress. In 1893 Colorado established +complete political equality. In Utah, the third suffrage state, the +cause suffered many vicissitudes. Women were enfranchised by the +territorial legislature; they were deprived of the ballot by Congress in +1887; finally in 1896 on the admission of Utah to the union they +recovered their former rights. During the same year, 1896, Idaho +conferred equal suffrage upon the women. This was the last suffrage +victory for more than a decade. + +=The Suffrage Cause in Congress.=--In the midst of the meager gains +among the states there were occasional flurries of hope for immediate +action on the federal amendment. Between 1878 and 1896 the Senate +committee reported the suffrage resolution by a favorable majority on +five different occasions. During the same period, however, there were +nine unfavorable reports and only once did the subject reach the point +of a general debate. At no time could anything like the required +two-thirds vote be obtained. + +=The Changing Status of Women.=--While the suffrage movement was +lagging, the activities of women in other directions were steadily +multiplying. College after college--Vassar, Bryn Mawr, Smith, Wellesley, +to mention a few--was founded to give them the advantages of higher +education. Other institutions, especially the state universities of the +West, opened their doors to women, and women were received into the +professions of law and medicine. By the rapid growth of public high +schools in which girls enjoyed the same rights as boys, education was +extended still more widely. The number of women teachers increased by +leaps and bounds. + +Meanwhile women were entering nearly every branch of industry and +business. How many of them worked at gainful occupations before 1870 we +do not know; but from that year forward we have the records of the +census. Between 1870 and 1900 the proportion of women in the professions +rose from less than two per cent to more than ten per cent; in trade and +transportation from 24.8 per cent to 43.2 per cent; and in manufacturing +from 13 to 19 per cent. In 1910, there were over 8,000,000 women +gainfully employed as compared with 30,000,000 men. When, during the war +on Germany, the government established the principle of equal pay for +equal work and gave official recognition to the value of their services +in industry, it was discovered how far women had traveled along the road +forecast by the leaders of 1848. + +=The Club Movement among Women.=--All over the country women's societies +and clubs were started to advance this or that reform or merely to study +literature, art, and science. In time these women's organizations of all +kinds were federated into city, state, and national associations and +drawn into the consideration of public questions. Under the leadership +of Frances Willard they made temperance reform a vital issue. They took +an interest in legislation pertaining to prisons, pure food, public +health, and municipal government, among other things. At their sessions +and conferences local, state, and national issues were discussed until +finally, it seems, everything led to the quest of the franchise. By +solemn resolution in 1914 the National Federation of Women's Clubs, +representing nearly two million club women, formally endorsed woman +suffrage. In the same year the National Education Association, speaking +for the public school teachers of the land, added its seal of approval. + +=State and National Action.=--Again the suffrage movement was in full +swing in the states. Washington in 1910, California in 1911, Oregon, +Kansas, and Arizona in 1912, Nevada and Montana in 1914 by popular vote +enfranchised their women. Illinois in 1913 conferred upon them the right +to vote for President of the United States. The time had arrived for a +new movement. A number of younger suffragists sought to use the votes of +women in the equal suffrage states to compel one or both of the national +political parties to endorse and carry through Congress the federal +suffrage amendment. Pressure then came upon Congress from every +direction: from the suffragists who made a straight appeal on the +grounds of justice; and from the suffragists who besought the women of +the West to vote against candidates for President, who would not approve +the federal amendment. In 1916, for the first time, a leading +presidential candidate, Mr. Charles E. Hughes, speaking for the +Republicans, endorsed the federal amendment and a distinguished +ex-President, Roosevelt, exerted a powerful influence to keep it an +issue in the campaign. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +CONFERENCE OF MEN AND WOMEN DELEGATES AT A NATIONAL CONVENTION IN +1920] + +=National Enfranchisement.=--After that, events moved rapidly. The great +state of New York adopted equal suffrage in 1917. Oklahoma, South +Dakota, and Michigan swung into line the following year; several other +states, by legislative action, gave women the right to vote for +President. In the meantime the suffrage battle at Washington grew +intense. Appeals and petitions poured in upon Congress and the +President. Militant suffragists held daily demonstrations in Washington. +On September 30, 1918, President Wilson, who, two years before, had +opposed federal action and endorsed suffrage by state adoption only, +went before Congress and urged the passage of the suffrage amendment to +the Constitution. In June, 1919, the requisite two-thirds vote was +secured; the resolution was carried and transmitted to the states for +ratification. On August 28, 1920, the thirty-sixth state, Tennessee, +approved the amendment, making three-fourths of the states as required +by the Constitution. Thus woman suffrage became the law of the land. A +new political democracy had been created. The age of agitation was +closed and the epoch of responsible citizenship opened. + + +=General References= + +Edith Abbott, _Women in Industry_. + +C.P. Gilman, _Woman and Economics_. + +I.H. Harper, _Life and Work of Susan B. Anthony_. + +E.R. Hecker, _Short History of Woman's Rights_. + +S.B. Anthony and I.H. Harper, _History of Woman Suffrage_ (4 vols.). + +J.W. Taylor, _Before Vassar Opened_. + +A.H. Shaw, _The Story of a Pioneer_. + + +=Research Topics= + +=The Rise of the Woman Suffrage Movement.=--McMaster, _History of the +People of the United States_, Vol. VIII, pp. 116-121; K. Porter, +_History of Suffrage in the United States_, pp. 135-145. + +=The Development of the Suffrage Movement.=--Porter, pp. 228-254; Ogg, +_National Progress_ (American Nation Series), pp. 151-156 and p. 382. + +=Women's Labor in the Colonial Period.=--E. Abbott, _Women in Industry_, +pp. 10-34. + +=Women and the Factory System.=--Abbott, pp. 35-62. + +=Early Occupations for Women.=--Abbott, pp. 63-85. + +=Women's Wages.=--Abbott, pp. 262-316. + + +=Questions= + +1. Why were women involved in the reform movements of the new century? + +2. What is history? What determines the topics that appear in written +history? + +3. State the position of women under the old common law. + +4. What part did women play in the intellectual movement that preceded +the American Revolution? + +5. Explain the rise of the discussion of women's rights. + +6. What were some of the early writings about women? + +7. Why was there a struggle for educational opportunities? + +8. How did reform movements draw women into public affairs and what were +the chief results? + +9. Show how the rise of the factory affected the life and labor of +women. + +10. Why is the year 1848 an important year in the woman movement? +Discuss the work of the Seneca Falls convention. + +11. Enumerate some of the early gains in civil liberty for women. + +12. Trace the rise of the suffrage movement. Show the effect of the +Civil War. + +13. Review the history of the federal suffrage amendment. + +14. Summarize the history of the suffrage in the states. + + + + +CHAPTER XXIV + +INDUSTRIAL DEMOCRACY + + +=The New Economic Age.=--The spirit of criticism and the measures of +reform designed to meet it, which characterized the opening years of the +twentieth century, were merely the signs of a new age. The nation had +definitely passed into industrialism. The number of city dwellers +employed for wages as contrasted with the farmers working on their own +land was steadily mounting. The free land, once the refuge of restless +workingmen of the East and the immigrants from Europe, was a thing of +the past. As President Roosevelt later said in speaking of the great +coal strike, "a few generations ago, the American workman could have +saved money, gone West, and taken up a homestead. Now the free lands +were gone. In earlier days, a man who began with a pick and shovel might +come to own a mine. That outlet was now closed as regards the immense +majority.... The majority of men who earned wages in the coal industry, +if they wished to progress at all, were compelled to progress not by +ceasing to be wage-earners but by improving the conditions under which +all the wage-earners of the country lived and worked." + +The disappearance of the free land, President Roosevelt went on to say, +also produced "a crass inequality in the bargaining relation of the +employer and the individual employee standing alone. The great +coal-mining and coal-carrying companies which employed their tens of +thousands could easily dispense with the services of any particular +miner. The miner, on the other hand, however expert, could not dispense +with the companies. He needed a job; his wife and children would starve +if he did not get one.... Individually the miners were impotent when +they sought to enter a wage contract with the great companies; they +could make fair terms only by uniting into trade unions to bargain +collectively." It was of this state of affairs that President Taft spoke +when he favored the modification of the common law "so as to put +employees of little power and means on a level with their employers in +adjusting and agreeing upon their mutual obligations." + +John D. Rockefeller, Jr., on the side of the great captains of industry, +recognized the same facts. He said: "In the early days of the +development of industry, the employer and capital investor were +frequently one. Daily contact was had between him and his employees, who +were his friends and neighbors.... Because of the proportions which +modern industry has attained, employers and employees are too often +strangers to each other.... Personal relations can be revived only +through adequate representation of the employees. Representation is a +principle which is fundamentally just and vital to the successful +conduct of industry.... It is not consistent for us as Americans to +demand democracy in government and practice autocracy in industry.... +With the developments what they are in industry to-day, there is sure to +come a progressive evolution from aristocratic single control, whether +by capital, labor, or the state, to democratic, cooperative control by +all three." + + +COOPERATION BETWEEN EMPLOYERS AND EMPLOYEES + +=Company Unions.=--The changed economic life described by the three +eminent men just quoted was acknowledged by several great companies and +business concerns. All over the country decided efforts were made to +bridge the gulf which industry and the corporation had created. Among +the devices adopted was that of the "company union." In one of the +Western lumber mills, for example, all the employees were invited to +join a company organization; they held monthly meetings to discuss +matters of common concern; they elected a "shop committee" to confer +with the representatives of the company; and periodically the agents of +the employers attended the conferences of the men to talk over matters +of mutual interest. The function of the shop committee was to consider +wages, hours, safety rules, sanitation, recreation and other problems. +Whenever any employee had a grievance he took it up with the foreman +and, if it was not settled to his satisfaction, he brought it before the +shop committee. If the members of the shop committee decided in favor of +the man with a grievance, they attempted to settle the matter with the +company's agents. All these things failing, the dispute was transferred +to a grand meeting of all the employees with the employers' +representatives, in common council. A deadlock, if it ensued from such a +conference, was broken by calling in impartial arbitrators selected by +both sides from among citizens outside the mill. Thus the employees were +given a voice in all decisions affecting their work and welfare; rights +and grievances were treated as matters of mutual interest rather than +individual concern. Representatives of trade unions from outside, +however, were rigidly excluded from all negotiations between employers +and the employees. + +=Profit-sharing.=--Another proposal for drawing capital and labor +together was to supplement the wage system by other ties. Sometimes lump +sums were paid to employees who remained in a company's service for a +definite period of years. Again they were given a certain percentage of +the annual profits. In other instances, employees were allowed to buy +stock on easy terms and thus become part owners in the concern. This +last plan was carried so far by a large soap manufacturing company that +the employees, besides becoming stockholders, secured the right to elect +representatives to serve on the board of directors who managed the +entire business. So extensive had profit-sharing become by 1914 that the +Federal Industrial Relations Committee, appointed by the President, +deemed it worthy of a special study. Though opposed by regular trade +unions, it was undoubtedly growing in popularity. + +=Labor Managers and Welfare Work.=--Another effort of employers to meet +the problems of the new age appeared in the appointment of specialists, +known as employment managers, whose task it was to study the relations +existing between masters and workers and discover practical methods for +dealing with each grievance as it arose. By 1918, hundreds of big +companies had recognized this modern "profession" and universities were +giving courses of instruction on the subject to young men and women. In +that year a national conference of employment managers was held at +Rochester, New York. The discussion revealed a wide range of duties +assigned to managers, including questions of wages, hours, sanitation, +rest rooms, recreational facilities, and welfare work of every kind +designed to make the conditions in mills and factories safer and more +humane. Thus it was evident that hundreds of employers had abandoned the +old idea that they were dealing merely with individual employees and +that their obligations ended with the payment of any wages they saw fit +to fix. In short, they were seeking to develop a spirit of cooperation +to take the place of competition and enmity; and to increase the +production of commodities by promoting the efficiency and happiness of +the producers. + + +THE RISE AND GROWTH OF ORGANIZED LABOR + +=The American Federation of Labor.=--Meanwhile a powerful association of +workers representing all the leading trades and crafts, organized into +unions of their own, had been built up outside the control of employers. +This was the American Federation of Labor, a nation-wide union of +unions, founded in 1886 on the basis of beginnings made five years +before. At the time of its establishment it had approximately 150,000 +members. Its growth up to the end of the century was slow, for the total +enrollment in 1900 was only 300,000. At that point the increase became +marked. The membership reached 1,650,000 in 1904 and more than 3,000,000 +in 1919. To be counted in the ranks of organized labor were several +strong unions, friendly to the Federation, though not affiliated with +it. Such, for example, were the Railway Brotherhoods with more than half +a million members. By the opening of 1920 the total strength of +organized labor was put at about 4,000,000 members, meaning, if we +include their families, that nearly one-fifth of the people of the +United States were in some positive way dependent upon the operations of +trade unions. + +=Historical Background.=--This was the culmination of a long and +significant history. Before the end of the eighteenth century, the +skilled workmen--printers, shoemakers, tailors, and carpenters--had, as +we have seen, formed local unions in the large cities. Between 1830 and +1860, several aggressive steps were taken in the American labor +movement. For one thing, the number of local unions increased by leaps +and bounds in all the industrial towns. For another, there was +established in every large manufacturing city a central labor body +composed of delegates from the unions of the separate trades. In the +local union the printers or the cordwainers, for example, considered +only their special trade problems. In the central labor union, printers, +cordwainers, iron molders, and other craftsmen considered common +problems and learned to cooperate with one another in enforcing the +demands of each craft. A third step was the federation of the unions of +the same craftsmen in different cities. The printers of New York, +Philadelphia, Boston, and other towns, for instance, drew together and +formed a national trade union of printers built upon the local unions of +that craft. By the eve of the Civil War there were four or five powerful +national unions of this character. The expansion of the railway made +travel and correspondence easier and national conventions possible even +for workmen of small means. About 1834 an attempt was made to federate +the unions of all the different crafts into a national organization; but +the effort was premature. + +_The National Labor Union._--The plan which failed in 1834 was tried +again in the sixties. During the war, industries and railways had +flourished as never before; prices had risen rapidly; the demand for +labor had increased; wages had mounted slowly, but steadily. Hundreds of +new local unions had been founded and eight or ten national trade unions +had sprung into being. The time was ripe, it seemed, for a national +consolidation of all labor's forces; and in 1866, the year after the +surrender of General Lee at Appomattox, the "National Labor Union" was +formed at Baltimore under the leadership of an experienced organizer, +W.H. Sylvis of the iron molders. The purpose of the National Labor Union +was not merely to secure labor's standard demands touching hours, wages, +and conditions of work or to maintain the gains already won. It leaned +toward political action and radical opinions. Above all, it sought to +eliminate the conflict between capital and labor by making workingmen +the owners of shops through the formation of cooperative industries. For +six years the National Labor Union continued to hold conferences and +carry on its propaganda; but most of the cooperative enterprises failed, +political dissensions arose, and by 1872 the experiment had come to an +end. + +_The Knights of Labor._--While the National Labor Union was +experimenting, there grew up in the industrial world a more radical +organization known as the "Noble Order of the Knights of Labor." It was +founded in Philadelphia in 1869, first as a secret society with rituals, +signs, and pass words; "so that no spy of the boss can find his way into +the lodge room to betray his fellows," as the Knights put it. In form +the new organization was simple. It sought to bring all laborers, +skilled and unskilled, men and women, white and colored, into a mighty +body of local and national unions without distinction of trade or craft. +By 1885, ten years after the national organization was established, it +boasted a membership of over 700,000. In philosophy, the Knights of +Labor were socialistic, for they advocated public ownership of the +railways and other utilities and the formation of cooperative societies +to own and manage stores and factories. + +As the Knights were radical in spirit and their strikes, numerous and +prolonged, were often accompanied by violence, the organization alarmed +employers and the general public, raising up against itself a vigorous +opposition. Weaknesses within, as well as foes from without, started the +Knights on the path to dissolution. They waged more strikes than they +could carry on successfully; their cooperative experiments failed as +those of other labor groups before them had failed; and the rank and +file could not be kept in line. The majority of the members wanted +immediate gains in wages or the reduction of hours; when their hopes +were not realized they drifted away from the order. The troubles were +increased by the appearance of the American Federation of Labor, a still +mightier organization composed mainly of skilled workers who held +strategic positions in industry. When they failed to secure the +effective support of the Federation in their efforts to organize the +unskilled, the employers closed in upon them; then the Knights declined +rapidly in power. By 1890 they were a negligible factor and in a short +time they passed into the limbo of dead experiments. + +=The Policies of the American Federation.=--Unlike the Knights of Labor, +the American Federation of Labor sought, first of all, to be very +practical in its objects and methods. It avoided all kinds of +socialistic theories and attended strictly to the business of organizing +unions for the purpose of increasing wages, shortening hours, and +improving working conditions for its members. It did not try to include +everybody in one big union but brought together the employees of each +particular craft whose interests were clearly the same. To prepare for +strikes and periods of unemployment, it raised large funds by imposing +heavy dues and created a benefit system to hold men loyally to the +union. In order to permit action on a national scale, it gave the +superior officers extensive powers over local unions. + +While declaring that employers and employees had much in common, the +Federation strongly opposed company unions. Employers, it argued, were +affiliated with the National Manufacturers' Association or with similar +employers' organizations; every important industry was now national in +scope; and wages and hours, in view of competition with other shops, +could not be determined in a single factory, no matter how amicable +might be the relations of the company and its workers in that particular +plant. For these reasons, the Federation declared company unions and +local shop committees inherently weak; it insisted that hours, wages, +and other labor standards should be fixed by general trade agreements +applicable to all the plants of a given industry, even if subject to +local modifications. + +At the same time, the Federation, far from deliberately antagonizing +employers, sought to enlist their cooperation and support. It affiliated +with the National Civic Federation, an association of business men, +financiers, and professional men, founded in 1900 to promote friendly +relations in the industrial world. In brief, the American Federation of +Labor accepted the modern industrial system and, by organization within +it, endeavored to secure certain definite terms and conditions for trade +unionists. + + +THE WIDER RELATIONS OF ORGANIZED LABOR + +=The Socialists.=--The trade unionism "pure and simple," espoused by the +American Federation of Labor, seemed to involve at first glance nothing +but businesslike negotiations with employers. In practice it did not +work out that way. The Federation was only six years old when a new +organization, appealing directly for the labor vote--namely, the +Socialist Labor Party--nominated a candidate for President, launched +into a national campaign, and called upon trade unionists to desert the +older parties and enter its fold. + +The socialistic idea, introduced into national politics in 1892, had +been long in germination. Before the Civil War, a number of reformers, +including Nathaniel Hawthorne, Horace Greeley, and Wendell Phillips, +deeply moved by the poverty of the great industrial cities, had +earnestly sought relief in the establishment of cooperative or +communistic colonies. They believed that people should go into the +country, secure land and tools, own them in common so that no one could +profit from exclusive ownership, and produce by common labor the food +and clothing necessary for their support. For a time this movement +attracted wide interest, but it had little vitality. Nearly all the +colonies failed. Selfishness and indolence usually disrupted the best of +them. + +In the course of time this "Utopian" idea was abandoned, and another set +of socialist doctrines, claiming to be more "scientific," appeared +instead. The new school of socialists, adopting the principles of a +German writer and agitator, Karl Marx, appealed directly to workingmen. +It urged them to unite against the capitalists, to get possession of the +machinery of government, and to introduce collective or public ownership +of railways, land, mines, mills, and other means of production. The +Marxian socialists, therefore, became political. They sought to organize +labor and to win elections. Like the other parties they put forward +candidates and platforms. The Socialist Labor party in 1892, for +example, declared in favor of government ownership of utilities, free +school books, woman suffrage, heavy income taxes, and the referendum. +The Socialist party, founded in 1900, with Eugene V. Debs, the leader of +the Pullman strike, as its candidate, called for public ownership of all +trusts, monopolies, mines, railways; and the chief means of production. +In the course of time the vote of the latter organization rose to +considerable proportions, reaching almost a million in 1912. It declined +four years later and then rose in 1920 to about the same figure. + +In their appeal for votes, the socialists of every type turned first to +labor. At the annual conventions of the American Federation of Labor +they besought the delegates to endorse socialism. The president of the +Federation, Samuel Gompers, on each occasion took the floor against +them. He repudiated socialism and the socialists, on both theoretical +and practical grounds. He opposed too much public ownership, declaring +that the government was as likely as any private employer to oppress +labor. The approval of socialism, he maintained, would split the +Federation on the rock of politics, weaken it in its fight for higher +wages and shorter hours, and prejudice the public against it. At every +turn he was able to vanquish the socialists in the Federation, although +he could not prevent it from endorsing public ownership of the railways +at the convention of 1920. + +=The Extreme Radicals.=--Some of the socialists, defeated in their +efforts to capture organized labor and seeing that the gains in +elections were very meager, broke away from both trade unionism and +politics. One faction, the Industrial Workers of the World, founded in +1905, declared themselves opposed to all capitalists, the wages system, +and craft unions. They asserted that the "working class and the +employing class have nothing in common" and that trade unions only +pitted one set of workers against another set. They repudiated all +government ownership and the government itself, boldly proclaiming their +intention to unite all employees into one big union and seize the +railways, mines, and mills of the country. This doctrine, so +revolutionary in tone, called down upon the extremists the condemnation +of the American Federation of Labor as well as of the general public. At +its convention in 1919, the Federation went on record as "opposed to +Bolshevism, I.W.W.-ism, and the irresponsible leadership that encourages +such a policy." It announced its "firm adherence to American ideals." + +=The Federation and Political Issues.=--The hostility of the Federation +to the socialists did not mean, however, that it was indifferent to +political issues or political parties. On the contrary, from time to +time, at its annual conventions, it endorsed political and social +reforms, such as the initiative, referendum, and recall, the abolition +of child labor, the exclusion of Oriental labor, old-age pensions, and +government ownership. Moreover it adopted the policy of "rewarding +friends and punishing enemies" by advising members to vote for or +against candidates according to their stand on the demands of organized +labor. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +SAMUEL GOMPERS AND OTHER LABOR LEADERS] + +This policy was pursued with especial zeal in connection with disputes +over the use of injunctions in labor controversies. An injunction is a +bill or writ issued by a judge ordering some person or corporation to do +or to refrain from doing something. For example, a judge may order a +trade union to refrain from interfering with non-union men or to +continue at work handling goods made by non-union labor; and he may fine +or imprison those who disobey his injunction, the penalty being +inflicted for "contempt of court." This ancient legal device came into +prominence in connection with nation-wide railway strikes in 1877. It +was applied with increasing frequency after its effective use against +Eugene V. Debs in the Pullman strike of 1894. + +Aroused by the extensive use of the writ, organized labor demanded that +the power of judges to issue injunctions in labor disputes be limited by +law. Representatives of the unions sought support from the Democrats and +the Republicans; they received from the former very specific and cordial +endorsement. In 1896 the Democratic platform denounced "government by +injunction as a new and highly dangerous form of oppression." Mr. +Gompers, while refusing to commit the Federation to Democratic politics, +privately supported Mr. Bryan. In 1908, he came out openly and boasted +that eighty per cent of the votes of the Federation had been cast for +the Democratic candidate. Again in 1912 the same policy was pursued. The +reward was the enactment in 1914 of a federal law exempting trade unions +from prosecution as combinations in restraint of trade, limiting the use +of the injunction in labor disputes, and prescribing trial by jury in +case of contempt of court. This measure was hailed by Mr. Gompers as the +"Magna Carta of Labor" and a vindication of his policy. As a matter of +fact, however, it did not prevent the continued use of injunctions +against trade unions. Nevertheless Mr. Gompers was unshaken in his +conviction that organized labor should not attempt to form an +independent political party or endorse socialist or other radical +economic theories. + +=Organized Labor and the Public.=--Besides its relations to employers, +radicals within its own ranks, and political questions, the Federation +had to face responsibilities to the general public. With the passing of +time these became heavy and grave. While industries were small and +conflicts were local in character, a strike seldom affected anybody but +the employer and the employees immediately involved in it. When, +however, industries and trade unions became organized on a national +scale and a strike could paralyze a basic enterprise like coal mining or +railways, the vital interests of all citizens were put in jeopardy. +Moreover, as increases in wages and reductions in hours often added +directly to the cost of living, the action of the unions affected the +well-being of all--the food, clothing, and shelter of the whole people. + +For the purpose of meeting the issue raised by this state of affairs, it +was suggested that employers and employees should lay their disputes +before commissions of arbitration for decision and settlement. President +Cleveland, in a message of April 2, 1886, proposed such a method for +disposing of industrial controversies, and two years later Congress +enacted a voluntary arbitration law applicable to the railways. The +principle was extended in 1898 and again in 1913, and under the +authority of the federal government many contentions in the railway +world were settled by arbitration. + +The success of such legislation induced some students of industrial +questions to urge that unions and employers should be compelled to +submit all disputes to official tribunals of arbitration. Kansas +actually passed such a law in 1920. Congress in the Esch-Cummins railway +bill of the same year created a federal board of nine members to which +all railway controversies, not settled by negotiation, must be +submitted. Strikes, however, were not absolutely forbidden. Generally +speaking, both employers and employees opposed compulsory adjustments +without offering any substitute in case voluntary arbitration should not +be accepted by both parties to a dispute. + + +IMMIGRATION AND AMERICANIZATION + +=The Problems of Immigration.=--From its very inception, the American +Federation of Labor, like the Knights of Labor before it, was confronted +by numerous questions raised by the ever swelling tide of aliens coming +to our shores. In its effort to make each trade union all-inclusive, it +had to wrestle with a score or more languages. When it succeeded in +thoroughly organizing a craft, it often found its purposes defeated by +an influx of foreigners ready to work for lower wages and thus undermine +the foundations of the union. + +At the same time, persons outside the labor movement began to be +apprehensive as they contemplated the undoubted evil, as well as the +good, that seemed to be associated with the "alien invasion." They saw +whole sections of great cities occupied by people speaking foreign +tongues, reading only foreign newspapers, and looking to the Old World +alone for their ideas and their customs. They witnessed an expanding +army of total illiterates, men and women who could read and write no +language at all; while among those aliens who could read few there were +who knew anything of American history, traditions, and ideals. Official +reports revealed that over twenty per cent of the men of the draft army +during the World War could not read a newspaper or write a letter home. +Perhaps most alarming of all was the discovery that thousands of alien +men are in the United States only on a temporary sojourn, solely to make +money and return home with their savings. These men, willing to work for +low wages and live in places unfit for human beings, have no stake in +this country and do not care what becomes of it. + +=The Restriction of Immigration.=--In all this there was, strictly +speaking, no cause for surprise. Since the foundation of our republic +the policy of the government had been to encourage the coming of the +alien. For nearly one hundred years no restraining act was passed by +Congress, while two important laws positively encouraged it; namely, the +homestead act of 1862 and the contract immigration law of 1864. Not +until American workingmen came into open collision with cheap Chinese +labor on the Pacific Coast did the federal government spread the first +measure of limitation on the statute books. After the discovery of gold, +and particularly after the opening of the railway construction era, a +horde of laborers from China descended upon California. Accustomed to +starvation wages and indifferent to the conditions of living, they +threatened to cut the American standard to the point of subsistence. By +1876 the protest of American labor was loud and long and both the +Republicans and the Democrats gave heed to it. In 1882 Congress enacted +a law prohibiting the admission of Chinese laborers to the United States +for a term of ten years--later extended by legislation. In a little +while the demand arose for the exclusion of the Japanese as well. In +this case no exclusion law was passed; but an understanding was reached +by which Japan agreed not to issue passports to her laborers authorizing +them to come to the United States. By act of Congress in 1907 the +President was empowered to exclude any laborers who, having passports to +Canada, Hawaii, or Mexico, attempted to enter our country. + +These laws and agreements, however, did not remove all grounds for the +agitation of the subject. They were difficult to enforce and it was +claimed by residents of the Coast that in spite of federal authority +Oriental laborers were finding their way into American ports. Moreover, +several Western states, anxious to preserve the soil for American +ownership, enacted laws making it impossible for Chinese and Japanese to +buy land outright; and in other ways they discriminated against +Orientals. Such proceedings placed the federal government in an +embarrassing position. By treaty it had guaranteed specific rights to +Japanese citizens in the United States, and the government at Tokyo +contended that the state laws just cited violated the terms of the +international agreement. The Western states were fixed in their +determination to control Oriental residents; Japan was equally +persistent in asking that no badge of inferiority be attached to her +citizens. Subjected to pressure on both sides, the federal government +sought a way out of the deadlock. + +Having embarked upon the policy of restriction in 1882, Congress readily +extended it. In that same year it barred paupers, criminals, convicts, +and the insane. Three years later, mainly owing to the pressure of the +Knights of Labor, it forbade any person, company, or association to +import aliens under contract. By an act of 1887, the contract labor +restriction was made even more severe. In 1903, anarchists were excluded +and the bureau of immigration was transferred from the Treasury +Department to the Department of Commerce and Labor, in order to provide +for a more rigid execution of the law. In 1907 the classes of persons +denied admission were widened to embrace those suffering from physical +and mental defects and otherwise unfit for effective citizenship. When +the Department of Labor was established in 1913 the enforcement of the +law was placed in the hands of the Secretary of Labor, W.B. Wilson, who +was a former leader in the American Federation of Labor. + +=The Literacy Test.=--Still the advocates of restriction were not +satisfied. Still organized labor protested and demanded more protection +against the competition of immigrants. In 1917 it won a thirty-year +battle in the passage of a bill excluding "all aliens over sixteen years +of age, physically capable of reading, who cannot read the English +language or some other language or dialect, including Hebrew or +Yiddish." Even President Wilson could not block it, for a two-thirds +vote to overcome his veto was mustered in Congress. + +This act, while it served to exclude illiterates, made no drastic cut in +the volume of immigration. Indeed a material reduction was resolutely +opposed in many quarters. People of certain nationalities already in the +United States objected to every barrier that shut out their own kinsmen. +Some Americans of the old stock still held to the idea that the United +States should continue to be an asylum for "the oppressed of the earth." +Many employers looked upon an increased labor supply as the means of +escaping what they called "the domination of trade unions." In the babel +of countless voices, the discussion of these vital matters went on in +town and country. + +=Americanization.=--Intimately connected with the subject of immigration +was a call for the "Americanization" of the alien already within our +gates. The revelation of the illiteracy in the army raised the cry and +the demand was intensified when it was found that many of the leaders +among the extreme radicals were foreign in birth and citizenship. +Innumerable programs for assimilating the alien to American life were +drawn up, and in 1919 a national conference on the subject was held in +Washington under the auspices of the Department of the Interior. All +were agreed that the foreigner should be taught to speak and write the +language and understand the government of our country. Congress was +urged to lend aid in this vast undertaking. America, as ex-President +Roosevelt had said, was to find out "whether it was a nation or a +boarding-house." + + +=General References= + +J.R. Commons and Associates, _History of Labor in the United States_ (2 +vols.). + +Samuel Gompers, _Labor and the Common Welfare_. + +W.E. Walling, _Socialism as It Is_. + +W.E. Walling (and Others), _The Socialism of Today_. + +R.T. Ely, _The Labor Movement in America_. + +T.S. Adams and H. Sumner, _Labor Problems_. + +J.G. Brooks, _American Syndicalism_ and _Social Unrest_. + +P.F. Hall, _Immigration and Its Effects on the United States_. + + +=Research Topics= + +=The Rise of Trade Unionism.=--Mary Beard, _Short History of the +American Labor Movement_, pp. 10-18, 47-53, 62-79; Carlton, _Organized +Labor in American History_, pp. 11-44. + +=Labor and Politics.=--Beard, _Short History_, pp. 33-46, 54-61, +103-112; Carlton, pp. 169-197; Ogg, _National Progress_ (American Nation +Series), pp. 76-85. + +=The Knights of Labor.=--Beard, _Short History_, pp. 116-126; Dewey, +_National Problems_ (American Nation Series), pp. 40-49. + +=The American Federation of Labor--Organization and Policies.=--Beard, +_Short History_, pp. 86-112. + +=Organized Labor and the Socialists.=--Beard, _Short History_, pp. +126-149. + +=Labor and the Great War.=--Carlton, pp. 282-306; Beard, _Short +History_, pp. 150-170. + + +=Questions= + +1. What are the striking features of the new economic age? + +2. Give Mr. Rockefeller's view of industrial democracy. + +3. Outline the efforts made by employers to establish closer relations +with their employees. + +4. Sketch the rise and growth of the American Federation of Labor. + +5. How far back in our history does the labor movement extend? + +6. Describe the purposes and outcome of the National Labor Union and the +Knights of Labor. + +7. State the chief policies of the American Federation of Labor. + +8. How does organized labor become involved with outside forces? + +9. Outline the rise of the socialist movement. How did it come into +contact with the American Federation? + +10. What was the relation of the Federation to the extreme radicals? To +national politics? To the public? + +11. Explain the injunction. + +12. Why are labor and immigration closely related? + +13. Outline the history of restrictions on immigration. + +14. What problems arise in connection with the assimilation of the alien +to American life? + + + + +CHAPTER XXV + +PRESIDENT WILSON AND THE WORLD WAR + + +"The welfare, the happiness, the energy, and the spirit of the men and +women who do the daily work in our mines and factories, on our +railroads, in our offices and ports of trade, on our farms, and on the +sea are the underlying necessity of all prosperity." Thus spoke Woodrow +Wilson during his campaign for election. In this spirit, as President, +he gave the signal for work by summoning Congress in a special session +on April 7, 1913. He invited the cooperation of all "forward-looking +men" and indicated that he would assume the role of leadership. As an +evidence of his resolve, he appeared before Congress in person to read +his first message, reviving the old custom of Washington and Adams. Then +he let it be known that he would not give his party any rest until it +fulfilled its pledges to the country. When Democratic Senators balked at +tariff reductions, they were sharply informed that the party had +plighted its word and that no excuses or delays would be tolerated. + + +DOMESTIC LEGISLATION + +=Financial Measures.=--Under this spirited leadership Congress went to +work, passing first the Underwood tariff act of 1913, which made a +downward revision in the rates of duty, fixing them on the average about +twenty-six per cent lower than the figures of 1907. The protective +principle was retained, but an effort was made to permit a moderate +element of foreign competition. As a part of the revenue act Congress +levied a tax on incomes as authorized by the sixteenth amendment to the +Constitution. The tax which roused such party passions twenty years +before was now accepted as a matter of course. + +Having disposed of the tariff, Congress took up the old and vexatious +currency question and offered a new solution in the form of the federal +reserve law of December, 1913. This measure, one of the most interesting +in the history of federal finance, embraced four leading features. In +the first place, it continued the prohibition on the issuance of notes +by state banks and provided for a national currency. In the second +place, it put the new banking system under the control of a federal +reserve board composed entirely of government officials. To prevent the +growth of a "central money power," it provided, in the third place, for +the creation of twelve federal reserve banks, one in each of twelve +great districts into which the country is divided. All local national +banks were required and certain other banks permitted to become members +of the new system and share in its control. Finally, with a view to +expanding the currency, a step which the Democrats had long urged upon +the country, the issuance of paper money, under definite safeguards, was +authorized. + +Mindful of the agricultural interest, ever dear to the heart of +Jefferson's followers, the Democrats supplemented the reserve law by the +Farm Loan Act of 1916, creating federal agencies to lend money on farm +mortgages at moderate rates of interest. Within a year $20,000,000 had +been lent to farmers, the heaviest borrowing being in nine Western and +Southern states, with Texas in the lead. + +=Anti-trust Legislation.=--The tariff and currency laws were followed by +three significant measures relative to trusts. Rejecting utterly the +Progressive doctrine of government regulation, President Wilson +announced that it was the purpose of the Democrats "to destroy monopoly +and maintain competition as the only effective instrument of business +liberty." The first step in this direction, the Clayton Anti-trust Act, +carried into great detail the Sherman law of 1890 forbidding and +penalizing combinations in restraint of interstate and foreign trade. In +every line it revealed a determined effort to tear apart the great +trusts and to put all business on a competitive basis. Its terms were +reinforced in the same year by a law creating a Federal Trade Commission +empowered to inquire into the methods of corporations and lodge +complaints against concerns "using any unfair method of competition." In +only one respect was the severity of the Democratic policy relaxed. An +act of 1918 provided that the Sherman law should not apply to companies +engaged in export trade, the purpose being to encourage large +corporations to enter foreign commerce. + +The effect of this whole body of anti-trust legislation, in spite of +much labor on it, remained problematical. Very few combinations were +dissolved as a result of it. Startling investigations were made into +alleged abuses on the part of trusts; but it could hardly be said that +huge business concerns had lost any of their predominance in American +industry. + +=Labor Legislation.=--By no mere coincidence, the Clayton Anti-trust law +of 1914 made many concessions to organized labor. It declared that "the +labor of a human being is not a commodity or an article of commerce," +and it exempted unions from prosecution as "combinations in restraint of +trade." It likewise defined and limited the uses which the federal +courts might make of injunctions in labor disputes and guaranteed trial +by jury to those guilty of disobedience (see p. 581). + +The Clayton law was followed the next year by the Seamen's Act giving +greater liberty of contract to American sailors and requiring an +improvement of living conditions on shipboard. This was such a drastic +law that shipowners declared themselves unable to meet foreign +competition under its terms, owing to the low labor standards of other +countries. + +Still more extraordinary than the Seamen's Act was the Adamson law of +1916 fixing a standard eight-hour work-day for trainmen on railroads--a +measure wrung from Congress under a threat of a great strike by the four +Railway Brotherhoods. This act, viewed by union leaders as a triumph, +called forth a bitter denunciation of "trade union domination," but it +was easier to criticize than to find another solution of the problem. + +Three other laws enacted during President Wilson's administration were +popular in the labor world. One of them provided compensation for +federal employees injured in the discharge of their duties. Another +prohibited the labor of children under a certain age in the industries +of the nation. A third prescribed for coal miners in Alaska an +eight-hour day and modern safeguards for life and health. There were +positive proofs that organized labor had obtained a large share of power +in the councils of the country. + +=Federal and State Relations.=--If the interference of the government +with business and labor represented a departure from the old idea of +"the less government the better," what can be said of a large body of +laws affecting the rights of states? The prohibition of child labor +everywhere was one indication of the new tendency. Mr. Wilson had once +declared such legislation unconstitutional; the Supreme Court declared +it unconstitutional; but Congress, undaunted, carried it into effect +under the guise of a tax on goods made by children below the age limit. +There were other indications of the drift. Large sums of money were +appropriated by Congress in 1916 to assist the states in building and +maintaining highways. The same year the Farm Loan Act projected the +federal government into the sphere of local money lending. In 1917 +millions of dollars were granted to states in aid of vocational +education, incidentally imposing uniform standards throughout the +country. Evidently the government was no longer limited to the duties of +the policeman. + +=The Prohibition Amendment.=--A still more significant form of +intervention in state affairs was the passage, in December, 1917, of an +amendment to the federal Constitution establishing national prohibition +of the manufacture and sale of intoxicating liquors as beverages. This +was the climax of a historical movement extending over half a century. +In 1872, a National Prohibition party, launched three years before, +nominated its first presidential candidate and inaugurated a campaign of +agitation. Though its vote was never large, the cause for which it +stood found increasing favor among the people. State after state by +popular referendum abolished the liquor traffic within its borders. By +1917 at least thirty-two of the forty-eight were "dry." When the federal +amendment was submitted for approval, the ratification was surprisingly +swift. In a little more than a year, namely, on January 16, 1919, it was +proclaimed. Twelve months later the amendment went into effect. + + +COLONIAL AND FOREIGN POLICIES + +=The Philippines and Porto Rico.=--Independence for the Philippines and +larger self-government for Porto Rico had been among the policies of the +Democratic party since the campaign of 1900. President Wilson in his +annual messages urged upon Congress more autonomy for the Filipinos and +a definite promise of final independence. The result was the Jones +Organic Act for the Philippines passed in 1916. This measure provided +that the upper as well as the lower house of the Philippine legislature +should be elected by popular vote, and declared it to be the intention +of the United States to grant independence "as soon as a stable +government can be established." This, said President Wilson on signing +the bill, is "a very satisfactory advance in our policy of extending to +them self-government and control of their own affairs." The following +year Congress, yielding to President Wilson's insistence, passed a new + +organic act for Porto Rico, making both houses of the legislature +elective and conferring American citizenship upon the inhabitants of the +island. + +[Illustration: THE CARIBBEAN REGION] + +=American Power in the Caribbean.=--While extending more self-government +to its dominions, the United States enlarged its sphere of influence in +the Caribbean. The supervision of finances in Santo Domingo, inaugurated +in Roosevelt's administration, was transformed into a protectorate under +Wilson. In 1914 dissensions in the republic led to the landing of +American marines to "supervise" the elections. Two years later, an +officer in the American navy, with authority from Washington, placed +the entire republic "in a state of military occupation." He proceeded to +suspend the government and laws of the country, exile the president, +suppress the congress, and substitute American military authority. In +1919 a consulting board of four prominent Dominicans was appointed to +aid the American military governor; but it resigned the next year after +making a plea for the restoration of independence to the republic. For +all practical purposes, it seemed, the sovereignty of Santo Domingo had +been transferred to the United States. + +In the neighboring republic of Haiti, a similar state of affairs +existed. In the summer of 1915 a revolution broke out there--one of a +long series beginning in 1804--and our marines were landed to restore +order. Elections were held under the supervision of American officers, +and a treaty was drawn up placing the management of Haitian finances and +the local constabulary under American authority. In taking this action, +our Secretary of State was careful to announce: "The United States +government has no purpose of aggression and is entirely disinterested in +promoting this protectorate." Still it must be said that there were +vigorous protests on the part of natives and American citizens against +the conduct of our agents in the island. In 1921 President Wilson was +considering withdrawal. + +In line with American policy in the West Indian waters was the purchase +in 1917 of the Danish Islands just off the coast of Porto Rico. The +strategic position of the islands, especially in relation to Haiti and +Porto Rico, made them an object of American concern as early as 1867, +when a treaty of purchase was negotiated only to be rejected by the +Senate of the United States. In 1902 a second arrangement was made, but +this time it was defeated by the upper house of the Danish parliament. +The third treaty brought an end to fifty years of bargaining and the +Stars and Stripes were raised over St. Croix, St. Thomas, St. John, and +numerous minor islands scattered about in the neighborhood. "It would be +suicidal," commented a New York newspaper, "for America, on the +threshold of a great commercial expansion in South America, to suffer a +Heligoland, or a Gibraltar, or an Aden to be erected by her rivals at +the mouth of her Suez." On the mainland American power was strengthened +by the establishment of a protectorate over Nicaragua in 1916. + +=Mexican Relations.=--The extension of American enterprise southward +into Latin America, of which the operations in the Caribbean regions +were merely one phase, naturally carried Americans into Mexico to +develop the natural resources of that country. Under the iron rule of +General Porfirio Diaz, established in 1876 and maintained with only a +short break until 1911, Mexico had become increasingly attractive to our +business men. On the invitation of President Diaz, they had invested +huge sums in Mexican lands, oil fields, and mines, and had laid the +foundations of a new industrial order. The severe regime instituted by +Diaz, however, stirred popular discontent. The peons, or serfs, demanded +the break-up of the great estates, some of which had come down from the +days of Cortez. Their clamor for "the restoration of the land to the +people could not be silenced." In 1911 Diaz was forced to resign and +left the country. + +Mexico now slid down the path to disorder. Revolutions and civil +commotions followed in swift succession. A liberal president, Madero, +installed as the successor to Diaz, was deposed in 1913 and brutally +murdered. Huerta, a military adventurer, hailed for a time as another +"strong man," succeeded Madero whose murder he was accused of +instigating. Although Great Britain and nearly all the powers of Europe +accepted the new government as lawful, the United States steadily +withheld recognition. In the meantime Mexico was torn by insurrections +under the leadership of Carranza, a friend of Madero, Villa, a bandit of +generous pretensions, and Zapata, a radical leader of the peons. Without +the support of the United States, Huerta was doomed. + +In the summer of 1914, the dictator resigned and fled from the capital, +leaving the field to Carranza. For six years the new president, +recognized by the United States, held a precarious position which he +vigorously strove to strengthen against various revolutionary movements. +At length in 1920, he too was deposed and murdered, and another military +chieftain, Obregon, installed in power. + +These events right at our door could not fail to involve the government +of the United States. In the disorders many American citizens lost their +lives. American property was destroyed and land owned by Americans was +confiscated. A new Mexican constitution, in effect nationalizing the +natural resources of the country, struck at the rights of foreign +investors. Moreover the Mexican border was in constant turmoil. Even in +the last days of his administration, Mr. Taft felt compelled to issue a +solemn warning to the Mexican government protesting against the +violation of American rights. + +President Wilson, soon after his inauguration, sent a commissioner to +Mexico to inquire into the situation. Although he declared a general +policy of "watchful waiting," he twice came to blows with Mexican +forces. In 1914 some American sailors at Tampico were arrested by a +Mexican officer; the Mexican government, although it immediately +released the men, refused to make the required apology for the incident. +As a result President Wilson ordered the landing of American forces at +Vera Cruz and the occupation of the city. A clash of arms followed in +which several Americans were killed. War seemed inevitable, but at this +juncture the governments of Argentina, Brazil, and Chile tendered their +good offices as mediators. After a few weeks of negotiation, during +which Huerta was forced out of power, American forces were withdrawn +from Vera Cruz and the incident closed. + +In 1916 a second break in amicable relations occurred. In the spring of +that year a band of Villa's men raided the town of Columbus, New Mexico, +killing several citizens and committing robberies. A punitive expedition +under the command of General Pershing was quickly sent out to capture +the offenders. Against the protests of President Carranza, American +forces penetrated deeply into Mexico without effecting the object of +the undertaking. This operation lasted until January, 1917, when the +imminence of war with Germany led to the withdrawal of the American +soldiers. Friendly relations were resumed with the Mexican government +and the policy of "watchful waiting" was continued. + + +THE UNITED STATES AND THE EUROPEAN WAR + +=The Outbreak of the War.=--In the opening days of August, 1914, the +age-long jealousies of European nations, sharpened by new imperial +ambitions, broke out in another general conflict such as had shaken the +world in the days of Napoleon. On June 28, the heir to the +Austro-Hungarian throne was assassinated at Serajevo, the capital of +Bosnia, an Austrian province occupied mainly by Serbs. With a view to +stopping Serbian agitation for independence, Austria-Hungary laid the +blame for this incident on the government of Serbia and made humiliating +demands on that country. Germany at once proposed that the issue should +be regarded as "an affair which should be settled solely between +Austria-Hungary and Serbia"; meaning that the small nation should be +left to the tender mercies of a great power. Russia refused to take this +view. Great Britain proposed a settlement by mediation. Germany backed +up Austria to the limit. To use the language of the German authorities: +"We were perfectly aware that a possible warlike attitude of +Austria-Hungary against Serbia might bring Russia upon the field and +that it might therefore involve us in a war, in accordance with our +duties as allies. We could not, however, in these vital interests of +Austria-Hungary which were at stake, advise our ally to take a yielding +attitude not compatible with his dignity nor deny him our assistance." +That made the war inevitable. + +Every day of the fateful August, 1914, was crowded with momentous +events. On the 1st, Germany declared war on Russia. On the 2d, the +Germans invaded the little duchy of Luxemburg and notified the King of +Belgium that they were preparing to violate the neutrality of his realm +on their way to Paris. On the same day, Great Britain, anxiously +besought by the French government, promised the aid of the British navy +if German warships made hostile demonstrations in the Channel. August +3d, the German government declared war on France. The following day, +Great Britain demanded of Germany respect for Belgian neutrality and, +failing to receive the guarantee, broke off diplomatic relations. On the +5th, the British prime minister announced that war had opened between +England and Germany. The storm now broke in all its pitiless fury. + +=The State of American Opinion.=--Although President Wilson promptly +proclaimed the neutrality of the United States, the sympathies of a +large majority of the American people were without doubt on the side of +Great Britain and France. To them the invasion of the little kingdom of +Belgium and the horrors that accompanied German occupation were odious +in the extreme. Moreover, they regarded the German imperial government +as an autocratic power wielded in the interest of an ambitious military +party. The Kaiser, William II, and the Crown Prince were the symbols of +royal arrogance. On the other hand, many Americans of German descent, in +memory of their ties with the Fatherland, openly sympathized with the +Central Powers; and many Americans of Irish descent, recalling their +long and bitter struggle for home rule in Ireland, would have regarded +British defeat as a merited redress of ancient grievances. + +Extremely sensitive to American opinion, but ill informed about it, the +German government soon began systematic efforts to present its cause to +the people of the United States in the most favorable light possible. +Dr. Bernhard Dernburg, the former colonial secretary of the German +empire, was sent to America as a special agent. For months he filled the +newspapers, magazines, and periodicals with interviews, articles, and +notes on the justice of the Teutonic cause. From a press bureau in New +York flowed a stream of pamphlets, leaflets, and cartoons. A magazine, +"The Fatherland," was founded to secure "fair play for Germany and +Austria." Several professors in American universities, who had received +their training in Germany, took up the pen in defense of the Central +Empires. The German language press, without exception it seems, the +National German Alliance, minor German societies, and Lutheran churches +came to the support of the German cause. Even the English language +papers, though generally favorable to the Entente Allies, opened their +columns in the interest of equal justice to the spokesmen for all the +contending powers of Europe. + +Before two weeks had elapsed the controversy had become so intense that +President Wilson (August 18, 1914) was moved to caution his countrymen +against falling into angry disputes. "Every man," he said, "who really +loves America will act and speak in the true spirit of neutrality which +is the spirit of impartiality and fairness and friendliness to all +concerned.... We must be impartial in thought as well as in action, must +put a curb upon our sentiments as well as upon every transaction that +might be construed as a preference of one party to the struggle before +another." + +=The Clash over American Trade.=--As in the time of the Napoleonic wars, +the conflict in Europe raised fundamental questions respecting rights of +Americans trading with countries at peace as well as those at war. On +this point there existed on August 1, 1914, a fairly definite body of +principles by which nations were bound. Among them the following were of +vital significance. In the first place, it was recognized that an enemy +merchant ship caught on the high seas was a legitimate prize of war +which might be seized and confiscated. In the second place, it was +agreed that "contraband of war" found on an enemy or neutral ship was a +lawful prize; any ship suspected of carrying it was liable to search and +if caught with forbidden goods was subject to seizure. In the third +place, international law prescribed that a peaceful merchant ship, +whether belonging to an enemy or to a neutral country, should not be +destroyed or sunk without provision for the safety of crew and +passengers. In the fourth place, it was understood that a belligerent +had the right, if it could, to blockade the ports of an enemy and +prevent the ingress and egress of all ships; but such a blockade, to be +lawful, had to be effective. + +These general principles left undetermined two important matters: "What +is an effective blockade?" and "What is contraband of war?" The task of +answering these questions fell to Great Britain as mistress of the seas. +Although the German submarines made it impossible for her battleships to +maintain a continuous patrol of the waters in front of blockaded ports, + +she declared the blockade to be none the less "effective" because her +navy was supreme. As to contraband of war Great Britain put such a broad +interpretation upon the term as to include nearly every important +article of commerce. Early in 1915 she declared even cargoes of grain +and flour to be contraband, defending the action on the ground that the +German government had recently taken possession of all domestic stocks +of corn, wheat, and flour. + +A new question arose in connection with American trade with the neutral +countries surrounding Germany. Great Britain early began to intercept +ships carrying oil, gasoline, and copper--all war materials of prime +importance--on the ground that they either were destined ultimately to +Germany or would release goods for sale to Germans. On November 2, 1914, +the English government announced that the Germans wore sowing mines in +open waters and that therefore the whole of the North Sea was a military +zone. Ships bound for Denmark, Norway, and Sweden were ordered to come +by the English Channel for inspection and sailing directions. In effect, +Americans were now licensed by Great Britain to trade in certain +commodities and in certain amounts with neutral countries. + +Against these extraordinary measures, the State Department at Washington +lodged pointed objections, saying: "This government is reluctantly +forced to the conclusion that the present policy of His Majesty's +government toward neutral ships and cargoes exceeds the manifest +necessity of a belligerent and constitutes restrictions upon the rights +of American citizens on the high seas, which are not justified by the +rules of international law or required under the principle of +self-preservation." + +=Germany Begins the Submarine Campaign.=--Germany now announced that, on +and after February 18, 1915, the whole of the English Channel and the +waters around Great Britain would be deemed a war zone and that every +enemy ship found therein would be destroyed. The German decree added +that, as the British admiralty had ordered the use of neutral flags by +English ships in time of distress, neutral vessels would be in danger of +destruction if found in the forbidden area. It was clear that Germany +intended to employ submarines to destroy shipping. A new factor was thus +introduced into naval warfare, one not provided for in the accepted laws +of war. A warship overhauling a merchant vessel could easily take its +crew and passengers on board for safe keeping as prescribed by +international law; but a submarine ordinarily could do nothing of the +sort. Of necessity the lives and the ships of neutrals, as well as of +belligerents, were put in mortal peril. This amazing conduct Germany +justified on the ground that it was mere retaliation against Great +Britain for her violations of international law. + +The response of the United States to the ominous German order was swift +and direct. On February 10, 1915, it warned Germany that if her +commanders destroyed American lives and ships in obedience to that +decree, the action would "be very hard indeed to reconcile with the +friendly relations happily subsisting between the two governments." The +American note added that the German imperial government would be held to +"strict accountability" and all necessary steps would be taken to +safeguard American lives and American rights. This was firm and clear +language, but the only response which it evoked from Germany was a +suggestion that, if Great Britain would allow food supplies to pass +through the blockade, the submarine campaign would be dropped. + +=Violations of American Rights.=--Meanwhile Germany continued to ravage +shipping on the high seas. On January 28, a German raider sank the +American ship, _William P. Frye_, in the South Atlantic; on March 28, a +British ship, the _Falaba_, was sunk by a submarine and many on board, +including an American citizen, were killed; and on April 28, a German +airplane dropped bombs on the American steamer _Cushing_. On the morning +of May 1, 1915, Americans were astounded to see in the newspapers an +advertisement, signed by the German Imperial Embassy, warning travelers +of the dangers in the war zone and notifying them that any who ventured +on British ships into that area did so at their own risk. On that day, +the _Lusitania_, a British steamer, sailed from New York for Liverpool. +On May 7, without warning, the ship was struck by two torpedoes and in a +few minutes went down by the bow, carrying to death 1153 persons +including 114 American men, women, and children. A cry of horror ran +through the country. The German papers in America and a few American +people argued that American citizens had been duly warned of the danger +and had deliberately taken their lives into their own hands; but the +terrible deed was almost universally condemned by public opinion. + +=The _Lusitania_ Notes.=--On May 14, the Department of State at +Washington made public the first of three famous notes on the +_Lusitania_ case. It solemnly informed the German government that "no +warning that an unlawful and inhumane act will be committed can possibly +be accepted as an excuse or palliation for that act or as an abatement +of the responsibility for its commission." It called upon the German +government to disavow the act, make reparation as far as possible, and +take steps to prevent "the recurrence of anything so obviously +subversive of the principles of warfare." The note closed with a clear +caution to Germany that the government of the United States would not +"omit any word or any act necessary to the performance of its sacred +duty of maintaining the rights of the United States and its citizens and +of safeguarding their free exercise and enjoyment." The die was cast; +but Germany in reply merely temporized. + +In a second note, made public on June 11, the position of the United +States was again affirmed. William Jennings Bryan, the Secretary of +State, had resigned because the drift of President Wilson's policy was +not toward mediation but the strict maintenance of American rights, if +need be, by force of arms. The German reply was still evasive and German +naval commanders continued their course of sinking merchant ships. In a +third and final note of July 21, 1915, President Wilson made it clear to +Germany that he meant what he said when he wrote that he would maintain +the rights of American citizens. Finally after much discussion and +shifting about, the German ambassador on September 1, 1915, sent a brief +note to the Secretary of State: "Liners will not be sunk by our +submarines without warning and without safety of the lives of +non-combatants, provided the liners do not try to escape or offer +resistance." Editorially, the New York _Times_ declared: "It is a +triumph not only of diplomacy but of reason, of humanity, of justice, +and of truth." The Secretary of State saw in it "a recognition of the +fundamental principles for which we have contended." + +=The Presidential Election of 1916.=--In the midst of this crisis came +the presidential campaign. On the Republican side everything seemed to +depend upon the action of the Progressives. If the breach created in +1912 could be closed, victory was possible; if not, defeat was certain. +A promise of unity lay in the fact that the conventions of the +Republicans and Progressives were held simultaneously in Chicago. The +friends of Roosevelt hoped that both parties would select him as their +candidate; but this hope was not realized. The Republicans chose, and +the Progressives accepted, Charles E. Hughes, an associate justice of +the federal Supreme Court who, as governor of New York, had won a +national reputation by waging war on "machine politicians." + +In the face of the clamor for expressions of sympathy with one or the +other of the contending powers of Europe, the Republicans chose a middle +course, declaring that they would uphold all American rights "at home +and abroad, by land and by sea." This sentiment Mr. Hughes echoed in his +acceptance speech. By some it was interpreted to mean a firmer policy in +dealing with Great Britain; by others, a more vigorous handling of the +submarine menace. The Democrats, on their side, renominated President +Wilson by acclamation, reviewed with pride the legislative achievements +of the party, and commended "the splendid diplomatic victories of our +great President who has preserved the vital interests of our government +and its citizens and kept us out of war." + +In the election which ensued President Wilson's popular vote exceeded +that cast for Mr. Hughes by more than half a million, while his +electoral vote stood 277 to 254. The result was regarded, and not +without warrant, as a great personal triumph for the President. He had +received the largest vote yet cast for a presidential candidate. The +Progressive party practically disappeared, and the Socialists suffered a +severe set-back, falling far behind the vote of 1912. + +=President Wilson Urges Peace upon the Warring Nations.=--Apparently +convinced that his pacific policies had been profoundly approved by his +countrymen, President Wilson, soon after the election, addressed "peace +notes" to the European belligerents. On December 16, the German Emperor +proposed to the Allied Powers that they enter into peace negotiations, a +suggestion that was treated as a mere political maneuver by the opposing +governments. Two days later President Wilson sent a note to the warring +nations asking them to avow "the terms upon which war might be +concluded." To these notes the Central Powers replied that they were +ready to meet their antagonists in a peace conference; and Allied Powers +answered by presenting certain conditions precedent to a satisfactory +settlement. On January 22, 1917, President Wilson in an address before +the Senate, declared it to be a duty of the United States to take part +in the establishment of a stable peace on the basis of certain +principles. These were, in short: "peace without victory"; the right of +nationalities to freedom and self-government; the independence of +Poland; freedom of the seas; the reduction of armaments; and the +abolition of entangling alliances. The whole world was discussing the +President's remarkable message, when it was dumbfounded to hear, on +January 31, that the German ambassador at Washington had announced the +official renewal of ruthless submarine warfare. + + +THE UNITED STATES AT WAR + +=Steps toward War.=--Three days after the receipt of the news that the +German government intended to return to its former submarine policy, +President Wilson severed diplomatic relations with the German empire. At +the same time he explained to Congress that he desired no conflict with +Germany and would await an "overt act" before taking further steps to +preserve American rights. "God grant," he concluded, "that we may not be +challenged to defend them by acts of willful injustice on the part of +the government of Germany." Yet the challenge came. Between February 26 +and April 2, six American merchant vessels were torpedoed, in most cases +without any warning and without regard to the loss of American lives. +President Wilson therefore called upon Congress to answer the German +menace. The reply of Congress on April 6 was a resolution, passed with +only a few dissenting votes, declaring the existence of a state of war +with Germany. Austria-Hungary at once severed diplomatic relations with +the United States; but it was not until December 7 that Congress, acting +on the President's advice, declared war also on that "vassal of the +German government." + +=American War Aims.=--In many addresses at the beginning and during the +course of the war, President Wilson stated the purposes which actuated +our government in taking up arms. He first made it clear that it was a +war of self-defense. "The military masters of Germany," he exclaimed, +"denied us the right to be neutral." Proof of that lay on every hand. +Agents of the German imperial government had destroyed American lives +and American property on the high seas. They had filled our communities +with spies. They had planted bombs in ships and munition works. They had +fomented divisions among American citizens. + +Though assailed in many ways and compelled to resort to war, the United +States sought no material rewards. "The world must be made safe for +democracy. Its peace must be planted upon the tested foundations of +political liberty. We have no selfish ends to serve. We desire no +conquest, no dominion. We seek no indemnities for ourselves." + +In a very remarkable message read to Congress on January 8, 1918, +President Wilson laid down his famous "fourteen points" summarizing the +ideals for which we were fighting. They included open treaties of peace, +openly arrived at; absolute freedom of navigation upon the seas; the +removal, as far as possible, of trade barriers among nations; reduction +of armaments; adjustment of colonial claims in the interest of the +populations concerned; fair and friendly treatment of Russia; the +restoration of Belgium; righting the wrong done to France in 1871 in the +matter of Alsace-Lorraine; adjustment of Italian frontiers along the +lines of nationality; more liberty for the peoples of Austria-Hungary; +the restoration of Serbia and Rumania; the readjustment of the Turkish +Empire; an independent Poland; and an association of nations to afford +mutual guarantees to all states great and small. On a later occasion +President Wilson elaborated the last point, namely, the formation of a +league of nations to guarantee peace and establish justice among the +powers of the world. Democracy, the right of nations to determine their +own fate, a covenant of enduring peace--these were the ideals for which +the American people were to pour out their blood and treasure. + +=The Selective Draft.=--The World War became a war of nations. The +powers against which we were arrayed had every able-bodied man in +service and all their resources, human and material, thrown into the +scale. For this reason, President Wilson summoned the whole people of +the United States to make every sacrifice necessary for victory. +Congress by law decreed that the national army should be chosen from all +male citizens and males not enemy aliens who had declared their +intention of becoming citizens. By the first act of May 18, 1917, it +fixed the age limits at twenty-one to thirty-one inclusive. Later, in +August, 1918, it extended them to eighteen and forty-five. From the men +of the first group so enrolled were chosen by lot the soldiers for the +World War who, with the regular army and the national guard, formed the +American Expeditionary Force upholding the American cause on the +battlefields of Europe. "The whole nation," said the President, "must be +a team in which each man shall play the part for which he is best +fitted." + +=Liberty Loans and Taxes.=--In order that the military and naval forces +should be stinted in no respect, the nation was called upon to place its +financial resources at the service of the government. Some urged the +"conscription of wealth as well as men," meaning the support of the war +out of taxes upon great fortunes; but more conservative counsels +prevailed. Four great Liberty Loans were floated, all the agencies of +modern publicity being employed to enlist popular interest. The first +loan had four and a half million subscribers; the fourth more than +twenty million. Combined with loans were heavy taxes. A progressive tax +was laid upon incomes beginning with four per cent on incomes in the +lower ranges and rising to sixty-three per cent of that part of any +income above $2,000,000. A progressive tax was levied upon inheritances. +An excess profits tax was laid upon all corporations and partnerships, +rising in amount to sixty per cent of the net income in excess of +thirty-three per cent on the invested capital. "This," said a +distinguished economist, "is the high-water mark in the history of +taxation. Never before in the annals of civilization has an attempt been +made to take as much as two-thirds of a man's income by taxation." + +=Mobilizing Material Resources.=--No stone was left unturned to provide +the arms, munitions, supplies, and transportation required in the +gigantic undertaking. Between the declaration of war and the armistice, +Congress enacted law after law relative to food supplies, raw materials, +railways, mines, ships, forests, and industrial enterprises. No power +over the lives and property of citizens, deemed necessary to the +prosecution of the armed conflict, was withheld from the government. The +farmer's wheat, the housewife's sugar, coal at the mines, labor in the +factories, ships at the wharves, trade with friendly countries, the +railways, banks, stores, private fortunes--all were mobilized and laid +under whatever obligations the government deemed imperative. Never was a +nation more completely devoted to a single cause. + +A law of August 10, 1917, gave the President power to fix the prices of +wheat and coal and to take almost any steps necessary to prevent +monopoly and excessive prices. By a series of measures, enlarging the +principles of the shipping act of 1916, ships and shipyards were brought +under public control and the government was empowered to embark upon a +great ship-building program. In December, 1917, the government assumed +for the period of the war the operation of the railways under a +presidential proclamation which was elaborated in March, 1918, by act of +Congress. In the summer of 1918 the express, telephone, and telegraph +business of the entire country passed under government control. By war +risk insurance acts allowances were made for the families of enlisted +men, compensation for injuries was provided, death benefits were +instituted, and a system of national insurance was established in the +interest of the men in service. Never before in the history of the +country had the government taken such a wise and humane view of its +obligations to those who served on the field of battle or on the seas. + +=The Espionage and Sedition Acts.=--By the Espionage law of June 15, +1917, and the amending law, known as the Sedition act, passed in May of +the following year, the government was given a drastic power over the +expression of opinion. The first measure penalized those who conveyed +information to a foreign country to be used to the injury of the United +States; those who made false statements designed to interfere with the +military or naval forces of the United States; those who attempted to +stir up insubordination or disloyalty in the army and navy; and those +who willfully obstructed enlistment. The Sedition act was still more +severe and sweeping in its terms. It imposed heavy penalties upon any +person who used "abusive language about the government or institutions +of the country." It authorized the dismissal of any officer of the +government who committed "disloyal acts" or uttered "disloyal language," +and empowered the Postmaster General to close the mails to persons +violating the law. This measure, prepared by the Department of Justice, +encountered vigorous opposition in the Senate, where twenty-four +Republicans and two Democrats voted against it. Senator Johnson of +California denounced it as a law "to suppress the freedom of the press +in the United States and to prevent any man, no matter who he is, from +expressing legitimate criticism concerning the present government." The +constitutionality of the acts was attacked; but they were sustained by +the Supreme Court and stringently enforced. + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +THE LAUNCHING OF A SHIP AT THE GREAT NAVAL YARDS, NEWARK, N.J.] + +=Labor and the War.=--In view of the restlessness of European labor +during the war and especially the proletarian revolution in Russia in +November, 1917, some anxiety was early expressed as to the stand which +organized labor might take in the United States. It was, however, soon +dispelled. Samuel Gompers, speaking for the American Federation of +Labor, declared that "this is labor's war," and pledged the united +support of all the unions. There was some dissent. The Socialist party +denounced the war as a capitalist quarrel; but all the protests combined +were too slight to have much effect. American labor leaders were sent to +Europe to strengthen the wavering ranks of trade unionists in war-worn +England, France, and Italy. Labor was given representation on the +important boards and commissions dealing with industrial questions. +Trade union standards were accepted by the government and generally +applied in industry. The Department of Labor became one of the powerful +war centers of the nation. In a memorable address to the American +Federation of Labor, President Wilson assured the trade unionists that +labor conditions should not be made unduly onerous by the war and +received in return a pledge of loyalty from the Federation. Recognition +of labor's contribution to winning the war was embodied in the treaty of +peace, which provided for a permanent international organization to +promote the world-wide effort of labor to improve social conditions. +"The league of nations has for its object the establishment of universal +peace," runs the preamble to the labor section of the treaty, "and such +a peace can be established only if it is based upon social justice.... +The failure of any nation to adopt humane conditions of labor is an +obstacle in the way of other nations which desire to improve the +conditions in their own countries." + +=The American Navy in the War.=--As soon as Congress declared war the +fleet was mobilized, American ports were thrown open to the warships of +the Allies, immediate provision was made for increasing the number of +men and ships, and a contingent of war vessels was sent to cooperate +with the British and French in their life-and-death contest with +submarines. Special effort was made to stimulate the production of +"submarine chasers" and "scout cruisers" to be sent to the danger zone. +Convoys were provided to accompany the transports conveying soldiers to +France. Before the end of the war more than three hundred American +vessels and 75,000 officers and men were operating in European waters. +Though the German fleet failed to come out and challenge the sea power +of the Allies, the battleships of the United States were always ready to +do their full duty in such an event. As things turned out, the service +of the American navy was limited mainly to helping in the campaign that +wore down the submarine menace to Allied shipping. + +=The War in France.=--Owing to the peculiar character of the warfare in +France, it required a longer time for American military forces to get +into action; but there was no unnecessary delay. Soon after the +declaration of war, steps were taken to give military assistance to the +Allies. The regular army was enlarged and the troops of the national +guard were brought into national service. On June 13, General John J. +Pershing, chosen head of the American Expeditionary Forces, reached +Paris and began preparations for the arrival of our troops. In June, the +vanguard of the army reached France. A slow and steady stream followed. +As soon as the men enrolled under the draft were ready, it became a +flood. During the period of the war the army was enlarged from about +190,000 men to 3,665,000, of whom more than 2,000,000 were in France +when the armistice was signed. + +Although American troops did not take part on a large scale until the +last phase of the war in 1918, several battalions of infantry were in +the trenches by October, 1917, and had their first severe encounter with +the Germans early in November. In January, 1918, they took over a part +of the front line as an American sector. In March, General Pershing +placed our forces at the disposal of General Foch, commander-in-chief of +the Allied armies. The first division, which entered the Montdidier +salient in April, soon was engaged with the enemy, "taking with splendid +dash the town of Cantigny and all other objectives, which were organized +and held steadfastly against vicious counter attacks and galling +artillery fire." + +[Illustration: _Copyright by Underwood and Underwood, N.Y._ + +TROOPS RETURNING FROM FRANCE] + +When the Germans launched their grand drives toward the Marne and Paris, +in June and July, 1918, every available man was placed at General Foch's +command. At Belleau Wood, at Chateau-Thierry, and other points along the +deep salient made by the Germans into the French lines, American +soldiers distinguished themselves by heroic action. They also played an +important role in the counter attack that "smashed" the salient and +drove the Germans back. + +In September, American troops, with French aid, "wiped out" the German +salient at St. Mihiel. By this time General Pershing was ready for the +great American drive to the northeast in the Argonne forest, while he +also cooperated with the British in the assault on the Hindenburg line. +In the Meuse-Argonne battle, our soldiers encountered some of the most +severe fighting of the war and pressed forward steadily against the most +stubborn resistance from the enemy. On the 6th of November, reported +General Pershing, "a division of the first corps reached a point on the +Meuse opposite Sedan, twenty-five miles from our line of departure. The +strategical goal which was our highest hope was gained. We had cut the +enemy's main line of communications and nothing but a surrender or an +armistice could save his army from complete disaster." Five days later +the end came. On the morning of November 11, the order to cease firing +went into effect. The German army was in rapid retreat and +demoralization had begun. The Kaiser had abdicated and fled into +Holland. The Hohenzollern dreams of empire were shattered. In the +fifty-second month, the World War, involving nearly every civilized +nation on the globe, was brought to a close. More than 75,000 American +soldiers and sailors had given their lives. More than 250,000 had been +wounded or were missing or in German prison camps. + +[Illustration: WESTERN BATTLE LINES OF THE VARIOUS YEARS OF THE +WORLD WAR] + + +THE SETTLEMENT AT PARIS + +=The Peace Conference.=--On January 18, 1919, a conference of the Allied +and Associated Powers assembled to pronounce judgment upon the German +empire and its defeated satellites: Austria-Hungary, Bulgaria, and +Turkey. It was a moving spectacle. Seventy-two delegates spoke for +thirty-two states. The United States, Great Britain, France, Italy, and +Japan had five delegates each. Belgium, Brazil, and Serbia were each +assigned three. Canada, Australia, South Africa, India, China, Greece, +Hedjaz, Poland, Portugal, Rumania, Siam, and Czechoslovakia were +allotted two apiece. The remaining states of New Zealand, Bolivia, Cuba, +Ecuador, Guatemala, Haiti, Honduras, Liberia, Nicaragua, Panama, Peru, +and Uruguay each had one delegate. President Wilson spoke in person for +the United States. England, France, and Italy were represented by their +premiers: David Lloyd George, Georges Clemenceau, and Vittorio Orlando. + +[Illustration: PREMIERS LLOYD GEORGE, ORLANDO AND CLEMENCEAU AND +PRESIDENT WILSON AT PARIS] + +=The Supreme Council.=--The real work of the settlement was first +committed to a Supreme Council of ten representing the United States, +Great Britain, France, Italy, and Japan. This was later reduced to five +members. Then Japan dropped out and finally Italy, leaving only +President Wilson and the Premiers, Lloyd George and Clemenceau, the +"Big Three," who assumed the burden of mighty decisions. On May 6, their +work was completed and in a secret session of the full conference the +whole treaty of peace was approved, though a few of the powers made +reservations or objections. The next day the treaty was presented to the +Germans who, after prolonged protests, signed on the last day of grace, +June 28. This German treaty was followed by agreements with Austria, +Hungary, Bulgaria, and Turkey. Collectively these great documents formed +the legal basis of the general European settlement. + +=The Terms of the Settlement.=--The combined treaties make a huge +volume. The German treaty alone embraces about 80,000 words. +Collectively they cover an immense range of subjects which may be +summarized under five heads: (1) The territorial settlement in Europe; +(2) the destruction of German military power; (3) reparations for +damages done by Germany and her allies; (4) the disposition of German +colonies and protectorates; and (5) the League of Nations. + +Germany was reduced by the cession of Alsace-Lorraine to France and the +loss of several other provinces. Austria-Hungary was dissolved and +dismembered. Russia was reduced by the creation of new states on the +west. Bulgaria was stripped of her gains in the recent Balkan wars. +Turkey was dismembered. Nine new independent states were created: +Poland, Finland, Lithuania, Latvia, Esthonia, Ukraine, Czechoslovakia, +Armenia, and Hedjaz. Italy, Greece, Rumania, and Serbia were enlarged by +cessions of territory and Serbia was transformed into the great state of +Jugoslavia. + +The destruction of German military power was thorough. The entire navy, +with minor exceptions, was turned over to the Allied and Associated +Powers; Germany's total equipment for the future was limited to six +battleships and six light cruisers, with certain small vessels but no +submarines. The number of enlisted men and officers for the army was +fixed at not more than 100,000; the General Staff was dissolved; and the +manufacture of munitions restricted. + +Germany was compelled to accept full responsibility for all damages; to +pay five billion dollars in cash and goods, and to make certain other +payments which might be ordered from time to time by an inter-allied +reparations commission. She was also required to deliver to Belgium, +France, and Italy, millions of tons of coal every year for ten years; +while by way of additional compensation to France the rich coal basin of +the Saar was placed under inter-allied control to be exploited under +French administration for a period of at least fifteen years. Austria +and the other associates of Germany were also laid under heavy +obligations to the victors. Damages done to shipping by submarines and +other vessels were to be paid for on the basis of ton for ton. + +The disposition of the German colonies and the old Ottoman empire +presented knotty problems. It was finally agreed that the German +colonies and Turkish provinces which were in a backward stage of +development should be placed under the tutelage of certain powers acting +as "mandatories" holding them in "a sacred trust of civilization." An +exception to the mandatory principle arose in the case of German rights +in Shantung, all of which were transferred directly to Japan. It was +this arrangement that led the Chinese delegation to withhold their +signatures from the treaty. + +=The League of Nations.=--High among the purposes which he had in mind +in summoning the nation to arms, President Wilson placed the desire to +put an end to war. All through the United States the people spoke of the +"war to end war." No slogan called forth a deeper response from the +public. The President himself repeatedly declared that a general +association of nations must be formed to guard the peace and protect all +against the ambitions of the few. "As I see it," he said in his address +on opening the Fourth Liberty Loan campaign, "the constitution of the +League of Nations and the clear definition of its objects must be a +part, in a sense the most essential part, of the peace settlement +itself." + +Nothing was more natural, therefore, than Wilson's insistence at Paris +upon the formation of an international association. Indeed he had gone +to Europe in person largely to accomplish that end. Part One of the +treaty with Germany, the Covenant of the League of Nations, was due to +his labors more than to any other influence. Within the League thus +created were to be embraced all the Allied and Associated Powers and +nearly all the neutrals. By a two-thirds vote of the League Assembly the +excluded nations might be admitted. + +The agencies of the League of Nations were to be three in number: (1) a +permanent secretariat located at Geneva; (2) an Assembly consisting of +one delegate from each country, dominion, or self-governing colony +(including Canada, Australia, South Africa, New Zealand, and India); (3) +and a Council consisting of representatives of the United States, Great +Britain, France, Italy, and Japan, and four other representatives +selected by the Assembly from time to time. + +The duties imposed on the League and the obligations accepted by its +members were numerous and important. The Council was to take steps to +formulate a scheme for the reduction of armaments and to submit a plan +for the establishment of a permanent Court of International Justice. The +members of the League (Article X) were to respect and preserve as +against external aggression the territorial integrity and existing +political independence of all the associated nations. They were to +submit to arbitration or inquiry by the Council all disputes which could +not be adjusted by diplomacy and in no case to resort to war until three +months after the award. Should any member disregard its covenants, its +action would be considered an act of war against the League, which would +accordingly cut off the trade and business of the hostile member and +recommend through the Council to the several associated governments the +military measures to be taken. In case the decision in any arbitration +of a dispute was unanimous, the members of the League affected by it +were to abide by it. + +Such was the settlement at Paris and such was the association of nations +formed to promote the peace of the world. They were quickly approved by +most of the powers, and the first Assembly of the League of Nations met +at Geneva late in 1920. + +=The Treaty in the United States.=--When the treaty was presented to the +United States Senate for approval, a violent opposition appeared. In +that chamber the Republicans had a slight majority and a two-thirds vote +was necessary for ratification. The sentiment for and against the treaty +ran mainly along party lines; but the Republicans were themselves +divided. The major portion, known as "reservationists," favored +ratification with certain conditions respecting American rights; while a +small though active minority rejected the League of Nations in its +entirety, announcing themselves to be "irreconcilables." The grounds of +this Republican opposition lay partly in the terms of peace imposed on +Germany and partly in the Covenant of the League of Nations. Exception +was taken to the clauses which affected the rights of American citizens +in property involved in the adjustment with Germany, but the burden of +criticism was directed against the League. Article X guaranteeing +against external aggression the political independence and territorial +integrity of the members of the League was subjected to a specially +heavy fire; while the treatment accorded to China and the sections +affecting American internal affairs were likewise attacked as "unjust +and dangerous." As an outcome of their deliberations, the Republicans +proposed a long list of reservations which touched upon many of the +vital parts of the treaty. These were rejected by President Wilson as +amounting in effect to a "nullification of the treaty." As a deadlock +ensued the treaty was definitely rejected, owing to the failure of its +sponsors to secure the requisite two-thirds vote. + +[Illustration: EUROPE] + +=The League of Nations in the Campaign of 1920.=--At this juncture the +presidential campaign of 1920 opened. The Republicans, while condemning +the terms of the proposed League, endorsed the general idea of an +international agreement to prevent war. Their candidate, Senator +Warren G. Harding of Ohio, maintained a similar position without saying +definitely whether the League devised at Paris could be recast in such a +manner as to meet his requirements. The Democrats, on the other hand, +while not opposing limitations clarifying the obligations of the United +States, demanded "the immediate ratification of the treaty without +reservations which would impair its essential integrity." The Democratic +candidate, Governor James M. Cox, of Ohio, announced his firm conviction +that the United States should "go into the League," without closing the +door to mild reservations; he appealed to the country largely on that +issue. The election of Senator Harding, in an extraordinary "landslide," +coupled with the return of a majority of Republicans to the Senate, made +uncertain American participation in the League of Nations. + +=The United States and International Entanglements.=--Whether America +entered the League or not, it could not close its doors to the world and +escape perplexing international complications. It had ever-increasing +financial and commercial connections with all other countries. Our +associates in the recent war were heavily indebted to our government. +The prosperity of American industries depended to a considerable extent +upon the recovery of the impoverished and battle-torn countries of +Europe. + +There were other complications no less specific. The United States was +compelled by force of circumstances to adopt a Russian policy. The +government of the Czar had been overthrown by a liberal revolution, +which in turn had been succeeded by an extreme, communist +"dictatorship." The Bolsheviki, or majority faction of the socialists, +had obtained control of the national council of peasants, workingmen, +and soldiers, called the soviet, and inaugurated a radical regime. They +had made peace with Germany in March, 1918. Thereupon the United States +joined England, France, and Japan in an unofficial war upon them. After +the general settlement at Paris in 1919, our government, while +withdrawing troops from Siberia and Archangel, continued in its refusal +to recognize the Bolshevists or to permit unhampered trade with them. +President Wilson repeatedly denounced them as the enemies of +civilization and undertook to lay down for all countries the principles +which should govern intercourse with Russia. + +Further international complications were created in connection with the +World War, wholly apart from the terms of peace or the League of +Nations. The United States had participated in a general European +conflict which changed the boundaries of countries, called into being +new nations, and reduced the power and territories of the vanquished. +Accordingly, it was bound to face the problem of how far it was prepared +to cooperate with the victors in any settlement of Europe's +difficulties. By no conceivable process, therefore, could America be +disentangled from the web of world affairs. Isolation, if desirable, had +become impossible. Within three hundred years from the founding of the +tiny settlements at Jamestown and Plymouth, America, by virtue of its +institutions, its population, its wealth, and its commerce, had become +first among the nations of the earth. By moral obligations and by +practical interests its fate was thus linked with the destiny of all +mankind. + + +SUMMARY OF DEMOCRACY AND THE WORLD WAR + +The astounding industrial progress that characterized the period +following the Civil War bequeathed to the new generation many perplexing +problems connected with the growth of trusts and railways, the +accumulation of great fortunes, the increase of poverty in the +industrial cities, the exhaustion of the free land, and the acquisition +of dominions in distant seas. As long as there was an abundance of land +in the West any able-bodied man with initiative and industry could +become an independent farmer. People from the cities and immigrants from +Europe had always before them that gateway to property and prosperity. +When the land was all gone, American economic conditions inevitably +became more like those of Europe. + +Though the new economic questions had been vigorously debated in many +circles before his day, it was President Roosevelt who first discussed +them continuously from the White House. The natural resources of the +country were being exhausted; he advocated their conservation. Huge +fortunes were being made in business creating inequalities in +opportunity; he favored reducing them by income and inheritance taxes. +Industries were disturbed by strikes; he pressed arbitration upon +capital and labor. The free land was gone; he declared that labor was in +a less favorable position to bargain with capital and therefore should +organize in unions for collective bargaining. There had been wrong-doing +on the part of certain great trusts; those responsible should be +punished. + +The spirit of reform was abroad in the land. The spoils system was +attacked. It was alleged that the political parties were dominated by +"rings and bosses." The United States Senate was called "a millionaires' +club." Poverty and misery were observed in the cities. State +legislatures and city governments were accused of corruption. + +In answer to the charges, remedies were proposed and adopted. Civil +service reform was approved. The Australian ballot, popular election of +Senators, the initiative, referendum, and recall, commission and city +manager plans for cities, public regulation of railways, compensation +for those injured in industries, minimum wages for women and children, +pensions for widows, the control of housing in the cities--these and a +hundred other reforms were adopted and tried out. The national watchword +became: "America, Improve Thyself." + +The spirit of reform broke into both political parties. It appeared in +many statutes enacted by Congress under President Taft's leadership. It +disrupted the Republicans temporarily in 1912 when the Progressive party +entered the field. It led the Democratic candidate in that year, +Governor Wilson, to make a "progressive appeal" to the voters. It +inspired a considerable program of national legislation under President +Wilson's two administrations. + +In the age of change, four important amendments to the federal +constitution, the first in more than forty years, were adopted. The +sixteenth empowered Congress to lay an income tax. The seventeenth +assured popular election of Senators. The eighteenth made prohibition +national. The nineteenth, following upon the adoption of woman suffrage +in many states, enfranchised the women of the nation. + +In the sphere of industry, equally great changes took place. The major +portion of the nation's business passed into the hands of corporations. +In all the leading industries of the country labor was organized into +trade unions and federated in a national organization. The power of +organized capital and organized labor loomed upon the horizon. Their +struggles, their rights, and their place in the economy of the nation +raised problems of the first magnitude. + +While the country was engaged in a heated debate upon its domestic +issues, the World War broke out in Europe in 1914. As a hundred years +before, American rights upon the high seas became involved at once. They +were invaded on both sides; but Germany, in addition to assailing +American ships and property, ruthlessly destroyed American lives. She +set at naught the rules of civilized warfare upon the sea. Warnings from +President Wilson were without avail. Nothing could stay the hand of the +German war party. + +After long and patient negotiations, President Wilson in 1917 called +upon the nation to take up arms against an assailant that had in effect +declared war upon America. The answer was swift and firm. The national +resources, human and material, were mobilized. The navy was enlarged, a +draft army created, huge loans floated, heavy taxes laid, and the spirit +of sacrifice called forth in a titanic struggle against an autocratic +power that threatened to dominate Europe and the World. + +In the end, American financial, naval, and military assistance counted +heavily in the scale. American sailors scoured the seas searching for +the terrible submarines. American soldiers took part in the last great +drives that broke the might of Germany's army. Such was the nation's +response to the President's summons to arms in a war "for democracy" and +"to end war." + +When victory crowned the arms of the powers united against Germany, +President Wilson in person took part in the peace council. He sought to +redeem his pledge to end wars by forming a League of Nations to keep the +peace. In the treaty drawn at the close of the war the first part was a +covenant binding the nations in a permanent association for the +settlement of international disputes. This treaty, the President offered +to the United States Senate for ratification and to his country for +approval. + +Once again, as in the days of the Napoleonic wars, the people seriously +discussed the place of America among the powers of the earth. The Senate +refused to ratify the treaty. World politics then became an issue in the +campaign of 1920. Though some Americans talked as if the United States +could close its doors and windows against all mankind, the victor in the +election, Senator Harding, of Ohio, knew better. The election returns +were hardly announced before he began to ask the advice of his +countrymen on the pressing theme that would not be downed: "What part +shall America--first among the nations of the earth in wealth and +power--assume at the council table of the world?" + + +=General References= + +Woodrow Wilson, _The New Freedom_. + +C.L. Jones, _The Caribbean Interests of the United States_. + +H.P. Willis, _The Federal Reserve_. + +C.W. Barron, _The Mexican Problem_ (critical toward Mexico). + +L.J. de Bekker, _The Plot against Mexico_ (against American +intervention). + +Theodore Roosevelt, _America and the World War_. + +E.E. Robinson and V.J. West, _The Foreign Policy of Woodrow Wilson_. + +J.S. Bassett, _Our War with Germany_. + +Carlton J.H. Hayes, _A Brief History of the Great War_. + +J.B. McMaster, _The United States in the World War_. + + +=Research Topics= + +=President Wilson's First Term.=--Elson, _History of the United States_, +pp. 925-941. + +=The Underwood Tariff Act.=--Ogg, _National Progress_ (The American +Nation Series), pp. 209-226. + +=The Federal Reserve System.=--Ogg, pp. 228-232. + +=Trust and Labor Legislation.=--Ogg, pp. 232-236. + +=Legislation Respecting the Territories.=--Ogg, pp. 236-245. + +=American Interests in the Caribbean.=--Ogg, pp. 246-265. + +=American Interests in the Pacific.=--Ogg, pp. 304-324. + +=Mexican Affairs.=--Haworth, pp. 388-395; Ogg, pp. 284-304. + +=The First Phases of the European War.=--Haworth, pp. 395-412; Ogg, pp. +325-343. + +=The Campaign of 1916.=--Haworth, pp. 412-418; Ogg, pp. 364-383. + +=America Enters the War.=--Haworth, pp. 422-440; pp. 454-475. Ogg, pp. +384-399; Elson, pp. 951-970. + +=Mobilizing the Nation.=--Haworth, pp. 441-453. + +=The Peace Settlement.=--Haworth, pp. 475-497; Elson, pp. 971-982. + + +=Questions= + +1. Enumerate the chief financial measures of the Wilson administration. +Review the history of banks and currency and give the details of the +Federal reserve law. + +2. What was the Wilson policy toward trusts? Toward labor? + +3. Review again the theory of states' rights. How has it fared in recent +years? + +4. What steps were taken in colonial policies? In the Caribbean? + +5. Outline American-Mexican relations under Wilson. + +6. How did the World War break out in Europe? + +7. Account for the divided state of opinion in America. + +8. Review the events leading up to the War of 1812. Compare them with +the events from 1914 to 1917. + +9. State the leading principles of international law involved and show +how they were violated. + +10. What American rights were assailed in the submarine campaign? + +11. Give Wilson's position on the _Lusitania_ affair. + +12. How did the World War affect the presidential campaign of 1916? + +13. How did Germany finally drive the United States into war? + +14. State the American war aims given by the President. + +15. Enumerate the measures taken by the government to win the war. + +16. Review the part of the navy in the war. The army. + +17. How were the terms of peace formulated? + +18. Enumerate the principal results of the war. + +19. Describe the League of Nations. + +20. Trace the fate of the treaty in American politics. + +21. Can there be a policy of isolation for America? + + + + +APPENDIX + +CONSTITUTION OF THE UNITED STATES + + +We the people of the United States, in order to form a more +perfect union, establish justice, insure domestic tranquillity, provide +for the common defence, promote the general welfare, and secure the +blessings of liberty to ourselves and our posterity, do ordain and +establish this Constitution for the United States of America. + + +ARTICLE I + +SECTION 1. All legislative powers herein granted shall be vested in a +Congress of the United States, which shall consist of a Senate and House +of Representatives. + + +SECTION 2. 1. The House of Representatives shall be composed of members +chosen every second year by the people of the several States, and the +electors in each State shall have the qualifications requisite for +electors of the most numerous branch of the State legislature. + +2. No person shall be a representative who shall not have attained to +the age of twenty-five years, and been seven years a citizen of the +United States, and who shall not, when elected, be an inhabitant of that +State in which he shall be chosen. + +3. Representatives and direct taxes[3] shall be apportioned among the +several States which may be included within this Union, according to +their respective numbers, which shall be determined by adding to the +whole number of free persons, including those bound to service for a +term of years, and excluding Indians not taxed, three-fifths of all +other persons.[3] The actual enumeration shall be made within three +years after the first meeting of the Congress of the United States, and +within every subsequent term of ten years, in such manner as they shall +by law direct. The number of representatives shall not exceed one for +every thirty thousand, but each State shall have at least one +representative; and until such enumeration shall be made, the State of +New Hampshire shall be entitled to choose three, Massachusetts eight, +Rhode Island and Providence Plantations one, Connecticut five, New York +six, New Jersey four, Pennsylvania eight, Delaware one, Maryland six, +Virginia ten, North Carolina five, South Carolina five, and Georgia +three. + +4. When vacancies happen in the representation from any State, the +executive authority thereof shall issue writs of election to fill such +vacancies. + +5. The House of Representatives shall choose their speaker and other +officers; and shall have the sole power of impeachment. + + +SECTION 3. 1. The Senate of the United States shall be composed of two +senators from each State, chosen by the legislature thereof, for six +years; and each senator shall have one vote.[4] + +2. Immediately after they shall be assembled in consequence of the first +election, they shall be divided as equally as may be into three classes. +The seats of the senators of the first class shall be vacated at the +expiration of the second year, of the second class at the expiration of +the fourth year, and of the third class at the expiration of the sixth +year, so that one-third may be chosen every second year; and if +vacancies happen by resignation, or otherwise, during the recess of the +legislature of any State, the executive thereof may make temporary +appointments until the next meeting of the legislature, which shall then +fill such vacancies.[5] + +3. No person shall be a senator who shall not have attained to the age +of thirty years, and been nine years a citizen of the United States, and +who shall not, when elected, be an inhabitant of that State for which he +shall be chosen. + +4. The Vice-President of the United States shall be President of the +Senate, but shall have no vote, unless they be equally divided. + +5. The Senate shall choose their other officers, and also a President +_pro tempore_, in the absence of the Vice-President, or when he shall +exercise the office of President of the United States. + +6. The Senate shall have the sole power to try all impeachments. When +sitting for that purpose, they shall be on oath or affirmation. When the +President of the United States is tried, the chief justice shall +preside: And no person shall be convicted without the concurrence of +two-thirds of the members present. + +7. Judgment in cases of impeachment shall not extend further than to +removal from office, and disqualification to hold and enjoy any office +of honor, trust, or profit under the United States: but the party +convicted shall nevertheless be liable and subject to indictment, trial, +judgment, and punishment, according to law. + + +SECTION 4. 1. The times, places, and manner of holding elections for +senators and representatives, shall be prescribed in each State by the +legislature thereof; but the Congress may at any time by law make or +alter such regulations, except as to the places of choosing senators. + +2. The Congress shall assemble at least once in every year, and such +meeting shall be on the first Monday in December, unless they shall by +law appoint a different day. + + +SECTION 5. 1. Each House shall be the judge of the elections, returns +and qualifications of its own members, and a majority of each shall +constitute a quorum to do business; but a smaller number may adjourn +from day to day, and may be authorized to compel the attendance of +absent members, in such manner, and under such penalties as each House +may provide. + +2. Each House may determine the rules of its proceedings, punish its +members for disorderly behaviour, and, with the concurrence of +two-thirds, expel a member. + +3. Each House shall keep a journal of its proceedings, and from time to +time publish the same, excepting such parts as may in their judgment +require secrecy; and the yeas and nays of the members of either House on +any question shall, at the desire of one-fifth of those present, be +entered on the journal. + +4. Neither House, during the session of Congress, shall, without the +consent of the other, adjourn for more than three days, nor to any other +place than that in which the two Houses shall be sitting. + + +SECTION 6. 1. The senators and representatives shall receive a +compensation for their services, to be ascertained by law, and paid out +of the Treasury of the United States. They shall in all cases, except +treason, felony, and breach of the peace, be privileged from arrest +during their attendance at the sessions of their respective Houses, and +in going to and returning from the same; and, for any speech or debate +in either House, they shall not be questioned in any other place. + +2. No senator or representative shall, during the time for which he was +elected, be appointed to any civil office under the authority of the +United States, which shall have been created, or the emoluments whereof +shall have been increased during such time; and no person, holding any +office under the United States, shall be a member of either House during +his continuance in office. + + +SECTION 7. 1. All bills for raising revenue shall originate in the House +of Representatives; but the Senate may propose or concur with amendments +as on other bills. + +2. Every bill, which shall have passed the House of Representatives; and +the Senate, shall, before it become a law, be presented to the President +of the United States; if he approve he shall sign it, but if not he +shall return it with his objections to that House, in which it shall +have originated, who shall enter the objections at large on their +journal, and proceed to reconsider it. If after such reconsideration +two-thirds of that House shall agree to pass the bill, it shall be sent, +together with the objections, to the other House, by which it shall +likewise be reconsidered, and if approved by two-thirds of that House, +it shall become a law. But in all such cases the votes of both Houses +shall be determined by yeas and nays, and the names of the persons +voting for and against the bill shall be entered on the journal of each +House respectively. If any bill shall not be returned by the President +within ten days (Sundays excepted) after it shall have been presented to +him, the same shall be a law, in like manner as if he had signed it, +unless the Congress by their adjournment prevent its return, in which +case it shall not be a law. + +3. Every order, resolution, or vote to which the concurrence of the +Senate and House of Representatives may be necessary (except on a +question of adjournment) shall be presented to the President of the +United States and before the same shall take effect, shall be approved +by him, or being disapproved by him, shall be repassed by two-thirds of +the Senate and House of Representatives, according to the rules and +limitations prescribed in the case of a bill. + + +SECTION 8. The Congress shall have power: 1. To lay and collect taxes, +duties, imposts, and excises, to pay the debts and provide for the +common defence and general welfare of the United States; but all duties, +imposts, and excises shall be uniform throughout the United States; + +2. To borrow money on the credit of the United States; + +3. To regulate commerce with foreign nations, and among the several +States, and with the Indian tribes; + +4. To establish an uniform rule of naturalization, and uniform laws on +the subject of bankruptcies throughout the United States; + +5. To coin money, regulate the value thereof, and of foreign coin, and +fix the standard of weights and measures; + +6. To provide for the punishment of counterfeiting the securities and +current coin of the United States; + +7. To establish post offices and post roads; + +8. To promote the progress of science and useful arts by securing for +limited times to authors and inventors the exclusive right to their +respective writings and discoveries; + +9. To constitute tribunals inferior to the Supreme Court; + +10. To define and punish piracies and felonies committed on the high +seas, and offences against the law of nations; + +11. To declare war, grant letters of marque and reprisal, and make rules +concerning captures on land and water; + +12. To raise and support armies, but no appropriation of money to that +use shall be for a longer term than two years; + +13. To provide and maintain a navy; + +14. To make rules for the government and regulation of the land and +naval forces; + +15. To provide for calling forth the militia to execute the laws of the +Union, suppress insurrections, and repel invasions; + +16. To provide for organizing, arming, and disciplining the militia, +and for governing such part of them as may be employed in the service +of the United States, reserving to the States respectively the +appointment of the officers, and the authority of training the militia +according to the discipline prescribed by Congress. + +17. To exercise exclusive legislation in all cases whatsoever, over such +district (not exceeding ten miles square) as may, by cession of +particular States and the acceptance of Congress, become the seat of the +government of the United States, and to exercise like authority over all +places purchased by the consent of the legislature of the State in which +the same shall be, for the erection of forts, magazines, arsenals, +dock-yards, and other needful buildings;--and + +18. To make all laws which shall be necessary and proper for carrying +into execution the foregoing powers, and all other powers vested by this +Constitution in the government of the United States, or in any +department or officer thereof. + + +SECTION 9. 1. The migration or importation of such persons as any of the +States now existing shall think proper to admit, shall not be prohibited +by the Congress prior to the year one thousand eight hundred and eight, +but a tax or duty may be imposed on such importation, not exceeding ten +dollars for each person. + +2. The privilege of the writ of _habeas corpus_ shall not be suspended, +unless when in cases of rebellion or invasion the public safety may +require it. + +3. No bill of attainder or _ex post facto_ law shall be passed. + +4. No capitation, or other direct, tax shall be laid, unless in +proportion to the census or enumeration hereinbefore directed to be +taken.[6] + +5. No tax or duty shall be laid on articles exported from any State. + +6. No preference shall be given by any regulation of commerce or revenue +to the ports of one State over those of another: nor shall vessels bound +to, or from, one State, be obliged to enter, clear, or pay duties in +another. + +7. No money shall be drawn from the Treasury, but in consequence of +appropriations made by law; and a regular statement and account of the +receipts and expenditures of all public money shall be published from +time to time. + +8. No title of nobility shall be granted by the United States; and no +person, holding any office of profit or trust under them, shall, without +the consent of the Congress, accept of any present, emolument, office, +or title, of any kind whatever, from any king, prince, or foreign State. + + +SECTION 10. 1. No State shall enter into any treaty, alliance, or +confederation; grant letters of marque and reprisal; coin money; emit +bills of credit; make anything but gold and silver coin a tender in +payment of debts; pass any bill of attainder, _ex post facto_ law, or +law impairing the obligation of contracts, or grant any title of +nobility. + +2. No State shall, without the consent of the Congress, lay any imposts +or duties on imports or exports, except what may be absolutely necessary +for executing its inspection laws: and the net produce of all duties and +imposts, laid by any State on imports or exports, shall be for the use +of the Treasury of the United States; and all such laws shall be subject +to the revision and control of the Congress. + +3. No State shall, without the consent of Congress, lay any duty of +tonnage, keep troops, or ships of war in time of peace, enter into any +agreement or compact with another State, or with a foreign power, or +engage in war unless actually invaded, or in such imminent danger as +will not admit of delay. + + +ARTICLE II + +SECTION 1. 1. The executive power shall be vested in a President of the +United States of America. He shall hold his office during the term of +four years, and, together with the Vice-President, chosen for the same +term, be elected, as follows: + +2. Each State shall appoint, in such manner as the legislature thereof +may direct, a number of electors, equal to the whole number of senators +and representatives to which the State may be entitled in the Congress; +but no senator or representative, or person holding an office of trust +or profit under the United States, shall be appointed an elector.[7] The +electors shall meet in their respective States, and vote by ballot for +two persons, of whom one at least shall not be an inhabitant of the same +State with themselves. And they shall make a list of all the persons +voted for, and of the number of votes for each; which list they shall +sign and certify, and transmit sealed to the seat of the government of +the United States, directed to the president of the Senate. The +President of the Senate shall, in the presence of the Senate and House +of Representatives, open all the certificates, and the votes shall then +be counted. The person having the greatest number of votes shall be the +President, if such number be a majority of the whole number of electors +appointed; and if there be more than one who have such majority, and +have an equal number of votes, then the House of Representatives shall +immediately choose by ballot one of them for President; and if no person +have a majority, then from the five highest on the list the said House +shall in like manner choose the President. But in choosing the +President, the votes shall be taken by States, the representation from +each State having one vote; a quorum for this purpose shall consist of a +member or members from two-thirds of the States and a majority of all +the States shall be necessary to a choice. In every case, after the +choice of the President, the person having the greatest number of votes +of the electors shall be the Vice-President. But if there should remain +two or more who have equal votes, the Senate shall choose from them by +ballot the Vice-President.[8] + +3. The Congress may determine the time of choosing the electors, and the +day on which they shall give their votes; which day shall be the same +throughout the United States. + +4. No person except a natural born citizen, or a citizen of the United +States, at the time of the adoption of this Constitution, shall be +eligible to the office of President; neither shall any person be +eligible to that office who shall not have attained to the age of +thirty-five years, and been fourteen years a resident within the United +States. + +5. In case of the removal of the President from office, or of his death, +resignation, or inability to discharge the powers and duties of the said +office, the same shall devolve on the Vice-President, and the Congress +may by law provide for the case of removal, death, resignation, or +inability both of the President and Vice-President, declaring what +officer shall then act as President, and such officer shall act +accordingly, until the disability be removed, or a President shall be +elected. + +6. The President shall, at stated times, receive for his services a +compensation, which shall neither be increased nor diminished during the +period for which he shall have been elected, and he shall not receive +within that period any other emolument from the United States, or any of +them. + +7. Before he enter on the execution of his office, he shall take the +following oath or affirmation:--"I do solemnly swear (or affirm) that I +will faithfully execute the office of President of the United States, +and will to the best of my ability, preserve, protect, and defend the +Constitution of the United States." + + +SECTION 2. 1. The President shall be commander-in-chief of the army and +navy of the United States, and of the militia of the several States, +when called into the actual service of the United States; he may require +the opinion, in writing, of the principal officer in each of the +executive departments, upon any subject relating to the duties of their +respective offices, and he shall have power to grant reprieves and +pardons for offences against the United States, except in cases of +impeachment. + +2. He shall have power, by and with the advice and consent of the +Senate, to make treaties, provided two-thirds of the senators present +concur; and he shall nominate, and by and with the advice and consent of +the Senate, shall appoint ambassadors, other public ministers and +consuls, judges of the Supreme Court, and all other officers of the +United States, whose appointments are not herein otherwise provided for, +and which shall be established by law: but the Congress may by law vest +the appointment of such inferior officers, as they think proper, in the +President alone, in the courts of law, or in the heads of departments. + +3. The President shall have power to fill all vacancies that may happen +during the recess of the Senate, by granting commissions which shall +expire at the end of their next session. + + +SECTION 3. He shall from time to time give to the Congress information +on the state of the Union, and recommend to their consideration such +measures as he shall judge necessary and expedient; he may, on +extraordinary occasions, convene both Houses, or either of them, and in +case of disagreement between them, with respect to the time of +adjournment, he may adjourn them to such time as he shall think proper; +he shall receive ambassadors and other public ministers; he shall take +care that the laws be faithfully executed, and shall commission all the +officers of the United States. + + +SECTION 4. The President, Vice-President, and all civil officers of the +United States shall be removed from office on impeachment for, and +conviction of, treason, bribery, or other high crimes and misdemeanors. + + +ARTICLE III + +SECTION 1. The judicial power of the United States shall be vested in +one Supreme Court, and in such inferior courts as the Congress may from +time to time ordain and establish. The judges, both of the Supreme and +inferior courts, shall hold their offices during good behaviour, and +shall, at stated times, receive for their services a compensation, which +shall not be diminished during their continuance in office. + + +SECTION 2. 1. The judicial power shall extend to all cases, in law and +equity, arising under this Constitution, the laws of the United States, +and treaties made, or which shall be made, under their authority;--to +all cases affecting ambassadors, other public ministers and consuls;--to +all cases of admiralty and maritime jurisdiction;--to controversies to +which the United States shall be a party;--to controversies between two +or more States;--between a State and citizens of another +State;[9]--between citizens of different States;--between citizens of +the same State claiming lands under grants of different States;--and +between a State, or the citizens thereof, and foreign States, citizens, +or subjects. + +2. In all cases affecting ambassadors, other public ministers and +consuls and those in which a State shall be a party, the Supreme Court +shall have original jurisdiction. In all the other cases before +mentioned, the Supreme Court shall have appellate jurisdiction, both as +to law and fact, with such exceptions and under such regulations as the +Congress shall make. + +3. The trial of all crimes, except in cases of impeachment, shall be by +jury; and such trial shall be held in the State where the said crimes +shall have been committed; but when not committed within any State, the +trial shall be at such place or places as the Congress may by law have +directed. + + +SECTION 3. 1. Treason against the United States shall consist only in +levying war against them, or in adhering to their enemies, giving them +aid and comfort. No person shall be convicted of treason unless on the +testimony of two witnesses to the same overt act, or on confession in +open court. + +2. The Congress shall have power to declare the punishment of treason, +but no attainder of treason shall work corruption of blood or forfeiture +except during the life of the person attainted. + + +ARTICLE IV + +SECTION 1. Full faith and credit shall be given in each State to the +public acts, records, and judicial proceedings of every other State. And +the Congress may by general laws prescribe the manner in which such +acts, records, and proceedings shall be proved, and the effect thereof. + + +SECTION 2. 1. The citizens of each State shall be entitled to all +privileges and immunities of citizens in the several States. + +2. A person charged in any State with treason, felony, or other crime, +who shall flee from justice, and be found in another State, shall on +demand of the executive authority of the State from which he fled, be +delivered up, to be removed to the State having jurisdiction of the +crime. + +3. No person held to service or labor in one State, under the laws +thereof, escaping into another, shall, in consequence of any law or +regulation therein, be discharged from such service or labor, but shall +be delivered up on claim of the party to whom such service or labor may +be due. + + +SECTION 3. 1. New States may be admitted by the Congress into this +Union; but no new State shall be formed or erected within the +jurisdiction of any other State; nor any State be formed by the junction +of two or more States, or parts of States, without the consent of the +legislatures of the States concerned as well as of the Congress. + +2. The Congress shall have power to dispose of and make all needful +rules and regulations respecting the territory or other property +belonging to the United States; and nothing in this Constitution shall +be so construed as to prejudice any claims, of the United States, or of +any particular State. + + +SECTION 4. The United States shall guarantee to every State in this +Union a republican form of government, and shall protect each of them +against invasion; and on application of the legislature, or of the +executive (when the legislature cannot be convened), against domestic +violence. + + +ARTICLE V + +The Congress, whenever two-thirds of both Houses shall deem it +necessary, shall propose amendments to this Constitution, or, on the +application of the legislatures of two-thirds of the several States, +shall call a convention for proposing amendments, which, in either case, +shall be valid to all intents and purposes as part of this Constitution, +when ratified by the legislatures of three-fourths of the several +States, or by conventions in three-fourths thereof, as the one or the +other mode of ratification may be proposed by the Congress; provided +that no amendment which may be made prior to the year one thousand eight +hundred and eight shall in any manner affect the first and fourth +clauses in the ninth Section of the first article; and that no State, +without its consent, shall be deprived of its equal suffrage in the +Senate. + + +ARTICLE VI + +1. All debts contracted and engagements entered into, before the +adoption of this Constitution, shall be as valid against the United +States under this Constitution, as under the Confederation. + +2. This Constitution and the laws of the United States which shall be +made in pursuance thereof and all treaties made, or which shall be made, +under the authority of the United States, shall be the supreme law of +the land; and the judges in every State shall be bound thereby, anything +in the Constitution or laws of any State to the contrary +notwithstanding. + +3. The senators and representatives before mentioned, and the members of +the several State legislatures, and all executive and judicial officers, +both of the United States and of the several States, shall be bound by +oath or affirmation to support this Constitution; but no religious test +shall ever be required as a qualification to any office or public trust +under the United States. + + +ARTICLE VII + +The ratification of the conventions of nine States shall be sufficient +for the establishment of this Constitution between the States so +ratifying the same. + +Done in Convention by the unanimous consent of the States present the +seventeenth day of September in the year of our Lord one thousand seven +hundred and eighty-seven and of the independence of the United States of +America the twelfth. In witness whereof we have hereunto subscribed our +names, + + G^O. WASHINGTON-- + Presidt. and Deputy from Virginia + +[and thirty-eight members from all the States except Rhode Island.] + + * * * * * + + +Articles in addition to, and amendment of, the Constitution of the +United States of America, proposed by Congress, and ratified by the +legislatures of the several States pursuant to the fifth article of the +original Constitution. + + +ARTICLE I[10] + +Congress shall make no law respecting an establishment of religion, or +prohibiting the free exercise thereof; or abridging the freedom of +speech, or of the press; or the right of the people peaceably to +assemble, and to petition the government for a redress of grievances. + + +ARTICLE II + +A well regulated militia, being necessary to the security of a free +State, the right of the people to keep and bear arms shall not be +infringed. + + +ARTICLE III + +No soldier shall, in time of peace, be quartered in any house, without +the consent of the owner, nor in time of war, but in a manner to be +prescribed by law. + + +ARTICLE IV + +The right of the people to be secure in their persons, houses, papers, +and effects, against unreasonable searches and seizures, shall not be +violated, and no warrants shall issue, but upon probable cause, +supported by oath or affirmation, and particularly describing the place +to be searched, and the persons or things to be seized. + + +ARTICLE V + +No person shall be held to answer for a capital, or otherwise infamous +crime, unless on a presentment or indictment of a grand jury, except in +cases arising in the land or naval forces, or in the militia, when in +actual service in time of war or public danger; nor shall any person be +subject for the same offence to be twice put in jeopardy of life or +limb; nor shall be compelled in any criminal case to be a witness +against himself; nor be deprived of life, liberty, or property, without +due process of law; nor shall private property be taken for public use, +without just compensation. + + +ARTICLE VI + +In all criminal prosecutions, the accused shall enjoy the right to a +speedy and public trial, by an impartial jury of the State and district +wherein the crime shall have been committed, which district shall have +been previously ascertained by law, and to be informed of the nature and +cause of the accusation; to be confronted with the witnesses against +him; to have compulsory process for obtaining witnesses in his favor, +and to have the assistance of counsel for his defence. + + +ARTICLE VII + +In suits at common law, where the value in controversy shall exceed +twenty dollars, the right of trial by jury shall be preserved, and no +fact tried by a jury shall be otherwise reexamined in any court of the +United States, than according to the rules of the common law. + + +ARTICLE VIII + +Excessive bail shall not be required, nor excessive fines imposed, nor +cruel and unusual punishments inflicted. + + +ARTICLE IX + +The enumeration in the Constitution, of certain rights, shall not be +construed to deny or disparage others retained by the people. + + +ARTICLE X + +The powers not delegated to the United States by the Constitution, nor +prohibited by it to the States, are reserved to the States respectively, +or to the people. + + +ARTICLE XI[11] + +The judicial power of the United States shall not be construed to extend +to any suit in law or equity, commenced or prosecuted against one of the +United States by citizens of another State, or by citizens or subjects +of any foreign State. + + +ARTICLE XII[12] + +The electors shall meet in their respective States, and vote by ballot +for President and Vice-President, one of whom at least shall not be an +inhabitant of the same State with themselves; they shall name in their +ballots the person voted for as President, and in distinct ballots the +person voted for as Vice-President, and they shall make distinct lists +of all persons voted for as President, and of all persons voted for as +Vice-President, and of the number of votes for each, which lists they +shall sign and certify, and transmit sealed to the seat of the +government of the United States, directed to the President of the +Senate;--The President of the Senate shall, in presence of the Senate +and House of Representatives, open all the certificates and the votes +shall then be counted;--The person having the greatest number of votes +for President, shall be the President, if such number be a majority of +the whole number of electors appointed; and if no person have such +majority, then from the persons having the highest numbers not exceeding +three on the list of those voted for as President, the House of +Representatives shall choose immediately, by ballot, the President. But +in choosing the President, the votes shall be taken by States, the +representation from each State having one vote; a quorum for this +purpose shall consist of a member or members from two-thirds of the +States, and a majority of all the States shall be necessary to a choice. +And if the House of Representatives shall not choose a President +whenever the right of choice shall devolve upon them, before the fourth +day of March next following, then the Vice-President shall act as +President, as in the case of the death or other constitutional +disability of the President. The person having the greatest number of +votes as Vice-President, shall be the Vice-President, if such number be +a majority of the whole number of electors appointed, and if no person +have a majority, then from the two highest members on the list, the +Senate shall choose the Vice-President; a quorum for the purpose shall +consist of two-thirds of the whole number of senators, and a majority of +the whole number shall be necessary to a choice. But no person +constitutionally ineligible to the office of President shall be eligible +to that of Vice-President of the United States. + + +ARTICLE XIII[13] + +SECTION 1. Neither slavery nor involuntary servitude, except as a +punishment for crime whereof the party shall have been duly convicted, +shall exist within the United States, or any place subject to their +jurisdiction. + +SECTION 2. Congress shall have power to enforce this article by +appropriate legislation. + + +ARTICLE XIV[14] + +SECTION 1. All persons born or naturalized in the United States, and +subject to the jurisdiction thereof, are citizens of the United States +and of the State wherein they reside. No State shall make or enforce any +law which shall abridge the privileges or immunities of citizens of the +United States; nor shall any State deprive any person of life, liberty, +or property without due process of law; nor deny to any person within +its jurisdiction the equal protection of the laws. + +SECTION 2. Representatives shall be apportioned among the several States +according to their respective numbers, counting the whole number of +persons in each State, excluding Indians not taxed. But when the right +to vote at any election for the choice of electors for President and +Vice-President of the United States, representatives in Congress, the +executive and judicial officers of a State, or the members of the +legislature thereof, is denied to any of the male inhabitants of such +State, being twenty-one years of age, and citizens of the United States, +or in any way abridged, except for participation in rebellion or other +crime, the basis of representation therein shall be reduced in the +proportion which the number of such male citizens shall bear to the +whole number of male citizens twenty-one years of age in such State. + +SECTION 3. No person shall be a senator or representative in Congress, +or elector of President and Vice-President, or hold any office, civil or +military, under the United States, or under any State, who, having +previously taken an oath, as a member of Congress, or as an officer of +the United States, or as a member of any State legislature, or as an +executive or judicial officer of any State, to support the Constitution +of the United States, shall have engaged in insurrection or rebellion +against the same, or given aid or comfort to the enemies thereof. But +Congress may by two-thirds vote of each House, remove such disability. + +SECTION 4. The validity of the public debt of the United States, +authorized by law, including debts incurred for payment of pensions and +bounties for services in suppressing insurrection or rebellion, shall +not be questioned. But neither the United States nor any State shall +assume or pay any debt or obligation incurred in aid of insurrection or +rebellion against the United States, or any claim for the loss or +emancipation of any slave; but all such debts, obligations, and claims +shall be held illegal and void. + +SECTION 5. The Congress shall have power to enforce, by appropriate +legislation, the provisions of this article. + + +ARTICLE XV[15] + +SECTION 1. The right of citizens of the United States to vote shall not +be denied or abridged by the United States or by any State on account of +race, color, or previous condition of servitude. + +SECTION 2. The Congress shall have power to enforce this article by +appropriate legislation. + + +ARTICLE XVI[16] + +The Congress shall have power to lay and collect taxes on incomes, from +whatever source derived, without apportionment among the several States, +and without regard to any census or enumeration. + + +ARTICLE XVII[17] + +The Senate of the United States shall be composed of two senators from +each State, elected by the people thereof, for six years; and each +senator shall have one vote. The electors in each State shall have the +qualifications requisite for electors of the most numerous branch of the +State legislature. + +When vacancies happen in the representation of any State in the Senate, +the executive authority of each State shall issue writs of election to +fill such vacancies: _Provided_ that the legislature of any State may +empower the executive thereof to make temporary appointments until the +people fill the vacancies by election as the legislature may direct. + +This amendment shall not be so construed as to effect the election or +term of any senator chosen before it becomes valid as part of the +Constitution. + + +ARTICLE XVIII[18] + +SECTION 1. After one year from the ratification of this article the +manufacture, sale, or transportation of intoxicating liquors within, the +importation thereof into, or the exportation thereof from the United +States and all territory subject to the jurisdiction thereof for +beverage purposes is hereby prohibited. + +SECTION 2. The Congress and the several States shall have concurrent +power to enforce this article by appropriate legislation. + +SECTION 3. This article shall be inoperative unless it shall have been +ratified as an amendment to the Constitution by the legislatures of the +several States, as provided in the Constitution, within seven years from +the date of the submission hereof to the States by the Congress. + + +ARTICLE XIX[19] + +The right of citizens of the United States to vote shall not be denied +or abridged by the United States or any State on account of sex. + +The Congress shall have power to enforce this article by appropriate +legislation. + + + +POPULATION OF THE UNITED STATES, BY STATES: 1920, 1910, 1900 + ++---------------------+--------------------------------------------+ +| STATES | POPULATION | ++ +--------------+--------------+--------------+ +| | 1920 | 1910 | 1900 | ++---------------------+--------------+--------------+--------------+ +|United States | 105,708,771 | 91,972,266 | 75,994,575 | ++---------------------+--------------+--------------+--------------+ +|Alabama | 2,348,174 | 2,138,093 | 1,828,697 | +|Arizona | 333,903 | 204,354 | 122,931 | +|Arkansas | 1,752,204 | 1,574,449 | 1,311,564 | +|California | 3,426,861 | 2,377,549 | 1,485,053 | +|Colorado | 939,629 | 799,024 | 539,700 | +|Connecticut | 1,380,631 | 1,114,756 | 908,420 | +|Delaware | 223,003 | 202,322 | 184,735 | +|District of Columbia | 437,571 | 331,069 | 278,718 | +|Florida | 968,470 | 752,619 | 528,542 | +|Georgia | 2,895,832 | 2,609,121 | 2,216,331 | +|Idaho | 431,866 | 325,594 | 161,772 | +|Illinois | 6,485,280 | 5,638,591 | 4,821,550 | +|Indiana | 2,930,390 | 2,700,876 | 2,516,462 | +|Iowa | 2,404,021 | 2,224,771 | 2,231,853 | +|Kansas | 1,769,257 | 1,690,949 | 1,470,495 | +|Kentucky | 2,416,630 | 2,289,905 | 2,147,174 | +|Louisiana | 1,798,509 | 1,656,388 | 1,381,625 | +|Maine | 768,014 | 742,371 | 694,466 | +|Maryland | 1,449,661 | 1,295,346 | 1,188,044 | +|Massachusetts | 3,852,356 | 3,366,416 | 2,805,346 | +|Michigan | 3,668,412 | 2,810,173 | 2,420,982 | +|Minnesota | 2,387,125 | 2,075,708 | 1,751,394 | +|Mississippi | 1,790,618 | 1,797,114 | 1,551,270 | +|Missouri | 3,404,055 | 3,293,335 | 3,106,665 | +|Montana | 548,889 | 376,053 | 243,329 | +|Nebraska | 1,296,372 | 1,192,214 | 1,066,300 | +|Nevada | 77,407 | 81,875 | 42,335 | +|New Hampshire | 443,407 | 430,572 | 411,588 | +|New Jersey | 3,155,900 | 2,537,167 | 1,883,669 | +|New Mexico | 360,350 | 327,301 | 195,310 | +|New York | 10,384,829 | 9,113,614 | 7,268,894 | +|North Carolina | 2,559,123 | 2,206,287 | 1,893,810 | +|North Dakota | 645,680 | 577,056 | 319,146 | +|Ohio | 5,759,394 | 4,767,121 | 4,157,545 | +|Oklahoma | 2,028,283 | 1,657,155 | 790,391 | +|Oregon | 783,389 | 672,765 | 413,536 | +|Pennsylvania | 8,720,017 | 7,665,111 | 6,302,115 | +|Rhode Island | 604,397 | 542,610 | 428,556 | +|South Carolina | 1,683,724 | 1,515,400 | 1,340,316 | +|South Dakota | 636,547 | 583,888 | 401,570 | +|Tennessee | 2,337,885 | 2,184,789 | 2,020,616 | +|Texas | 4,663,228 | 3,896,542 | 3,048,710 | +|Utah | 449,396 | 373,351 | 276,749 | +|Vermont | 352,428 | 355,956 | 343,641 | +|Virginia | 2,309,187 | 2,061,612 | 1,854,184 | +|Washington | 1,356,621 | 1,141,990 | 518,103 | +|West Virginia | 1,463,701 | 1,221,119 | 958,800 | +|Wisconsin | 2,632,067 | 2,333,860 | 2,069,042 | +|Wyoming | 194,402 | 145,965 | 92,531 | ++---------------------+--------------+--------------+--------------+ + +FOOTNOTES: + +[3] Partly superseded by the 14th Amendment, p. 639. + +[4] See the 17th Amendment, p. 641. + +[5] _Ibid._, p. 641. + +[6] See the 16th Amendment, p. 640. + +[7] The following paragraph was in force only from 1788 to 1803. + +[8] Superseded by the 12th Amendment, p. 638. + +[9] See the 11th Amendment, p. 638. + +[10] First ten amendments proposed by Congress, Sept. 25, 1789. +Proclaimed to be in force Dec. 15, 1791. + +[11] Proposed Sept. 5, 1794. Declared in force January 8, 1798. + +[12] Adopted in 1804. + +[13] Adopted in 1865. + +[14] Adopted in 1868. + +[15] Proposed February 27, 1869. Declared in force March 30, 1870. + +[16] Passed July, 1909; proclaimed February 25, 1913. + +[17] Passed May, 1912, in lieu of paragraph one, Section 3, Article I, +of the Constitution and so much of paragraph two of the same Section as +relates to the filling of vacancies; proclaimed May 31, 1913. + +[18] Ratified January 16, 1919. + +[19] Ratified August 26, 1920. + + + + +APPENDIX + +TABLE OF PRESIDENTS + +NAME STATE PARTY YEAR IN VICE-PRESIDENT + OFFICE +1 George Washington Va. Fed. 1789-1797 John Adams +2 John Adams Mass. Fed. 1797-1801 Thomas Jefferson +3 Thomas Jefferson Va. Rep. 1801-1809 Aaron Burr + George Clinton +4 James Madison Va. Rep. 1809-1817 George Clinton + Elbridge Gerry +5 James Monroe Va. Rep. 1817-1825 Daniel D. Tompkins +6 John Q. Adams Mass. Rep. 1825-1829 John C. Calhoun +7 Andrew Jackson Tenn. Dem. 1829-1837 John C. Calhoun + Martin Van Buren +8 Martin Van Buren N.Y. Dem. 1837-1841 Richard M. Johnson +9 Wm. H. Harrison Ohio Whig 1841-1841 John Tyler +10 John Tyler[20] Va. Whig 1841-1845 +11 James K. Polk Tenn. Dem. 1845-1849 George M. Dallas +12 Zachary Taylor La. Whig 1849-1850 Millard Fillmore +13 Millard Fillmore[20] N.Y. Whig 1850-1853 +14 Franklin Pierce N.H. Dem. 1853-1857 William R. King +15 James Buchanan Pa. Dem. 1857-1861 J.C. Breckinridge +16 Abraham Lincoln Ill. Rep. 1861-1865 Hannibal Hamlin + Andrew Johnson +17 Andrew Johnson[20] Tenn. Rep. 1865-1869 +18 Ulysses S. Grant Ill. Rep. 1869-1877 Schuyler Colfax + Henry Wilson +19 Rutherford B. Hayes Ohio Rep. 1877-1881 Wm. A. Wheeler +20 James A. Garfield Ohio Rep. 1881-1881 Chester A. Arthur +21 Chester A. Arthur[20] N.Y. Rep. 1881-1885 +22 Grover Cleveland N.Y. Dem. 1885-1889 Thomas A. Hendricks +23 Benjamin Harrison Ind. Rep. 1889-1893 Levi P. Morton +24 Grover Cleveland N.Y. Dem. 1893-1897 Adlai E. Stevenson +25 William McKinley Ohio Rep. 1897-1901 Garrett A. Hobart + Theodore Roosevelt +26 Theodore Roosevelt[20]N.Y. Rep. 1901-1909 Chas. W. Fairbanks +27 William H. Taft Ohio Rep. 1909-1913 James S. Sherman +28 Woodrow Wilson N.J. Dem. 1913-1921 Thomas R. Marshall +29 Warren G. Harding Ohio Rep. 1921- Calvin Coolidge + + +FOOTNOTES: + +[20] Promoted from the vice-presidency on the death of the president. + +POPULATION OF THE OUTLYING POSSESSIONS: 1920 AND 1910 + +----------------------------------------+--------------+--------------- + AREA | 1920 | 1910 +----------------------------------------+--------------+--------------- +United States with outlying possessions |117,857,509 | 101,146,530 + +--------------+--------------- +Continental United States |105,708,771 | 91,972,266 +Outlying Possessions | 12,148,738 | 9,174,264 + +--------------|--------------- + Alaska | 54,899 | 64,356 + American Samoa | 8,056 | 7,251[21] + Guam | 13,275 | 11,806 + Hawaii | 255,912 | 191,909 + Panama Canal Zone | 22,858 | 62,810[21] + Porto Rico | 1,299,809 | 1,118,012 + Military and naval, etc., service | | + abroad | 117,238 | 55,608 + Philippine Islands |10,350,640[22]| 7,635,426[23] + Virgin Islands of the United States | 26,051[24]| 27,086[25] +----------------------------------------+--------------+--------------- + +FOOTNOTES: + +[21] Population in 1912. + +[22] Population in 1918. + +[23] Population in 1903. + +[24] Population in 1917. + +[25] Population in 1911. + + + + +A TOPICAL SYLLABUS + +As a result of a wholesome reaction against the purely chronological +treatment of history, there is now a marked tendency in the direction of +a purely topical handling of the subject. The topical method, however, +may also be pushed too far. Each successive stage of any topic can be +understood only in relation to the forces of the time. For that reason, +the best results are reached when there is a combination of the +chronological and the topical methods. It is therefore suggested that +the teacher first follow the text closely and then review the subject +with the aid of this topical syllabus. The references are to pages. + + +=Immigration= + + I. Causes: religious (1-2, 4-11, 302), economic (12-17, 302-303), + and political (302-303). + II. Colonial immigration. + 1. Diversified character: English, Scotch-Irish, Irish, Jews, + Germans and other peoples (6-12). + 2. Assimilation to an American type; influence of the land + system (23-25, 411). + 3. Enforced immigration: indentured servitude, slavery, etc. + (13-17). + III. Immigration between 1789-1890. + 1. Nationalities: English, Irish, Germans, and Scandinavians + (278, 302-303). + 2. Relations to American life (432-433, 445). + IV. Immigration and immigration questions after 1890. + 1. Change in nationalities (410-411). + 2. Changes in economic opportunities (411). + 3. Problems of congestion and assimilation (410). + 4. Relations to labor and illiteracy (582-586). + 5. Oriental immigration (583). + 6. The restriction of immigration (583-585). + +=Expansion of the United States= + + I. Territorial growth. + 1. Territory of the United States in 1783 (134 and color map). + 2. Louisiana purchase, 1803 (188-193 and color map). + 3. Florida purchase, 1819 (204). + 4. Annexation of Texas, 1845 (278-281). + 5. Acquisition of Arizona, New Mexico, California, and other + territory at close of Mexican War, 1848 (282-283). + 6. The Gadsden purchase, 1853 (283). + 7. Settlement of the Oregon boundary question, 1846 (284-286). + 8. Purchase of Alaska from Russia, 1867 (479). + 9. Acquisition of Tutuila in Samoan group, 1899 (481-482). + 10. Annexation of Hawaii, 1898 (484). + 11. Acquisition of Porto Rico, the Philippines, and Guam at + close of Spanish War, 1898 (493-494). + 12. Acquisition of Panama Canal strip, 1904 (508-510). + 13. Purchase of Danish West Indies, 1917 (593). + 14. Extension of protectorate over Haiti, Santo Domingo, and + Nicaragua (593-594). + II. Development of colonial self-government. + 1. Hawaii (485). + 2. Philippines (516-518). + 3. Porto Rico (515-516). + III. Sea power. + 1. In American Revolution (118). + 2. In the War of 1812 (193-201). + 3. In the Civil War (353-354). + 4. In the Spanish-American War (492). + 5. In the Caribbean region (512-519). + 6. In the Pacific (447-448, 481). + 7. The role of the American navy (515). + +=The Westward Advance of the People= + + I. Beyond the Appalachians. + 1. Government and land system (217-231). + 2. The routes (222-224). + 3. The settlers (221-223, 228-230). + 4. Relations with the East (230-236). + II. Beyond the Mississippi. + 1. The lower valley (271-273). + 2. The upper valley (275-276). + III. Prairies, plains, and desert. + 1. Cattle ranges and cowboys (276-278, 431-432). + 2. The free homesteads (432-433). + 3. Irrigation (434-436, 523-525). + IV. The Far West. + 1. Peculiarities of the West (433-440). + 2. The railways (425-431). + 3. Relations to the East and Europe (443-447). + 4. American power in the Pacific (447-449). + +=The Wars of American History= + + I. Indian wars (57-59). + II. Early colonial wars: King William's, Queen Anne's, and King + George's (59). + III. French and Indian War (Seven Years' War), 1754-1763 (59-61). + IV. Revolutionary War, 1775-1783 (99-135). + V. The War of 1812, 1812-1815 (193-201). + VI. The Mexican War, 1845-1848 (276-284). + VII. The Civil War, 1861-1865 (344-375). + VIII. The Spanish War, 1898 (485-497). + IX. The World War, 1914-1918 [American participation, 1917-1918] + (596-625). + +=Government= + + I. Development of the American system of government. + 1. Origin and growth of state government. + _a._ The trading corporation (2-4), religious congregation + (4-5), and proprietary system (5-6). + _b._ Government of the colonies (48-53). + _c._ Formation of the first state constitutions (108-110). + _d._ The admission of new states (_see_ Index under each + state). + _e._ Influence of Jacksonian Democracy (238-247). + _f._ Growth of manhood suffrage (238-244). + _g._ Nullification and state sovereignty (180-182, 251-257). + _h._ The doctrine of secession (345-346). + _i._ Effects of the Civil War on position of states (366, + 369-375). + _j._ Political reform--direct government--initiative, + referendum, and recall (540-544). + 2. Origin and growth of national government. + _a._ British imperial control over the colonies (64-72). + _b._ Attempts at intercolonial union--New England + Confederation, Albany plan (61-62). + _c._ The Stamp Act Congress (85-86). + _d._ The Continental Congresses (99-101). + _e._ The Articles of Confederation (110-111, 139-143). + _f._ The formation of the federal Constitution (143-160). + _g._ Development of the federal Constitution. + (1) Amendments 1-11--rights of persons and states (163). + (2) Twelfth amendment--election of President (184, note). + (3) Amendments 13-15--Civil War settlement (358, 366, 369, + 370, 374, 375). + (4) Sixteenth amendment--income tax (528-529). + (5) Seventeenth amendment--election of Senators (541-542). + (6) Eighteenth amendment--prohibition (591-592). + (7) Nineteenth amendment--woman suffrage (563-568). + 3. Development of the suffrage. + _a._ Colonial restrictions (51-52). + _b._ Provisions of the first state constitutions + (110, 238-240). + _c._ Position under federal Constitution of 1787 (149). + _d._ Extension of manhood suffrage (241-244). + _e._ Extension and limitation of negro suffrage (373-375, + 382-387). + _f._ Woman suffrage (560-568). + II. Relation of government to economic and social welfare. + 1. Debt and currency. + _a._ Colonial paper money (80). + _b._ Revolutionary currency and debt (125-127). + _c._ Disorders under Articles of Confederation (140-141). + _d._ Powers of Congress under the Constitution to coin money + (_see_ Constitution in the Appendix). + _e._ First United States bank notes (167). + _f._ Second United States bank notes (257). + _g._ State bank notes (258). + _h._ Civil War greenbacks and specie payment (352-353, 454). + _i._ The Civil War debt (252). + _j._ Notes of National Banks under act of 1864 (369). + _k._ Demonetization of silver and silver legislation + (452-458). + _l._ The gold standard (472). + _m._ The federal reserve notes (589). + _n._ Liberty bonds (606). + 2. Banking systems. + _a._ The first United States bank (167). + _b._ The second United States bank--origin and destruction + (203, 257-259). + _c._ United States treasury system (263). + _d._ State banks (258). + _e._ The national banking system of 1864 (369). + _f._ Services of banks (407-409). + _g._ Federal reserve system (589). + 3. The tariff. + _a._ British colonial system (69-72). + _b._ Disorders under Articles of Confederation (140). + _c._ The first tariff under the Constitution (150, 167-168). + _d._ Development of the tariff, 1816-1832 (252-254). + _f._ Tariff and nullification (254-256). + _g._ Development to the Civil War--attitude of South and West + (264, 309-314, 357). + _h._ Republicans and Civil War tariffs (352, 367). + _i._ Revival of the tariff controversy under Cleveland (422). + _j._ Tariff legislation after 1890--McKinley bill (422), + Wilson bill (459), Dingley bill (472), Payne-Aldrich bill + (528), Underwood bill (588). + 4. Foreign and domestic commerce and transportation + (_see_ Tariff, Immigration, and Foreign Relations). + _a._ British imperial regulations (69-72). + _b._ Confusion under Articles of Confederation (140). + _c._ Provisions of federal Constitution (150). + _d._ Internal improvements--aid to roads, canals, etc. + (230-236). + _e._ Aid to railways (403). + _f._ Service of railways (402). + _g._ Regulation of railways (460-461, 547-548). + _h._ Control of trusts and corporations (461-462, 589-590). + 5. Land and natural resources. + _a._ British control over lands (80). + _b._ Early federal land measures (219-221). + _c._ The Homestead act (368, 432-445). + _d._ Irrigation and reclamation (434-436, 523-525). + _e._ Conservation of natural resources (523-526). + 6. Legislation advancing human rights and general welfare + (_see_ Suffrage). + _a._ Abolition of slavery: civil and political rights of + negroes (357-358, 373-375). + _b._ Extension of civil and political rights to women + (554-568). + _c._ Legislation relative to labor conditions (549-551, + 579-581, 590-591). + _d._ Control of public utilities (547-549). + _e._ Social reform and the war on poverty (549-551). + _f._ Taxation and equality of opportunity (551-552). + +=Political Parties and Political Issues= + + I. The Federalists _versus_ the Anti-Federalists [Jeffersonian + Republicans] from about 1790 to about 1816 (168-208, 201-203). + 1. Federalist leaders: Hamilton, John Adams, John Marshall, + Robert Morris. + 2. Anti-Federalist leaders: Jefferson, Madison, Monroe. + 3. Issues: funding the debt, assumption of state debts, first + United States bank, taxation, tariff, strong central + government _versus_ states' rights, and the Alien and + Sedition acts. + II. Era of "Good Feeling" from about 1816 to about 1824, a period + of no organized party opposition (248). + III. The Democrats [former Jeffersonian Republicans] _versus_ the + Whigs [or National Republicans] from about 1832 to 1856 + (238-265, 276-290, 324-334). + 1. Democratic leaders: Jackson, Van Buren, Calhoun, Benton. + + 2. Whig leaders: Webster and Clay. + 3. Issues: second United States bank, tariff, nullification, + Texas, internal improvements, and disposition of Western + lands. + IV. The Democrats _versus_ the Republicans from about 1856 to the + present time (334-377, 388-389, 412-422, 451-475, 489-534, + 588-620). + 1. Democratic leaders: Jefferson Davis, Tilden, Cleveland, + Bryan, and Wilson. + 2. Republican leaders: Lincoln, Blaine, McKinley, Roosevelt. + 3. Issues: Civil War and reconstruction, currency, tariff, + taxation, trusts, railways, foreign policies, imperialism, + labor questions, and policies with regard to land and + conservation. + V. Minor political parties. + 1. Before the Civil War: Free Soil (319) and Labor Parties + (306-307). + 2. Since the Civil War: Greenback (463-464), Populist (464), + Liberal Republican (420), Socialistic (577-579), Progressive + (531-534, 602-603). + +=The Economic Development of the United States= + + I. The land and natural resources. + 1. The colonial land system: freehold, plantation, and manor + (20-25). + 2. Development of the freehold in the West (220-221, 228-230). + 3. The Homestead act and its results (368, 432-433). + 4. The cattle range and cowboy (431-432). + 5. Disappearance of free land (443-445). + 6. Irrigation and reclamation (434-436). + 7. Movement for the conservation of resources (523-526). + II. Industry. + 1. The rise of local and domestic industries (28-32). + 2. British restrictions on American enterprise (67-69, 70-72). + 3. Protective tariffs (see above, 648-649). + 4. Development of industry previous to the Civil War (295-307). + 5. Great progress of industry after the war (401-406). + 6. Rise and growth of trusts and combinations (406-412, + 472-474). + III. Commerce and transportation. + 1. Extent of colonial trade and commerce (32-35). + 2. British regulation (69-70). + 3. Effects of the Revolution and the Constitution + (139-140, 154). + 4. Growth of American shipping (195-196). + 5. Waterways and canals (230-236). + 6. Rise and extension of the railway system (298-300). + 7. Growth of American foreign trade (445-449). + IV. Rise of organized labor. + 1. Early phases before the Civil War: local unions, city + federations, and national unions in specific trades + (304-307). + 2. The National Trade Union, 1866-1872 (574-575). + 3. The Knights of Labor (575-576). + 4. The American Federation of Labor (573-574). + _a._ Policies of the Federation (576-577). + _b._ Relations to politics (579-581). + _c._ Contests with socialists and radicals (577-579). + _d._ Problems of immigration (582-585). + 5. The relations of capital and labor. + _a._ The corporation and labor (410, 570-571). + _b._ Company unions and profit-sharing (571-572). + _c._ Welfare work (573). + _d._ Strikes (465, 526, 580-581). + _e._ Arbitration (581-582). + +=American Foreign Relations= + + I. Colonial period. + 1. Indian relations (57-59). + 2. French relations (59-61). + II. Period of conflict and independence. + 1. Relations with Great Britain (77-108, 116-125, 132-135). + 2. Establishment of connections with European powers (128). + 3. The French alliance of 1778 (128-130). + 4. Assistance of Holland and Spain (130). + III. Relations with Great Britain since 1783. + 1. Commercial settlement in Jay treaty of 1794 (177-178). + 2. Questions arising out of European wars [1793-1801] + (176-177, 180). + 3. Blockade and embargo problems (193-199). + 4. War of 1812 (199-201). + 5. Monroe Doctrine and Holy Alliance (205-207). + 6. Maine boundary--Webster-Ashburton treaty (265). + 7. Oregon boundary (284-286). + 8. Attitude of Great Britain during Civil War (354-355). + 9. Arbitration of _Alabama_ claims (480-481). + 10. The Samoan question (481-482) + 11. The Venezuelan question (482-484). + 12. British policy during Spanish-American War (496-497). + 13. Controversy over blockade, 1914-1917 (598-600). + 14. The World War (603-620). + IV. Relations with France. + 1. The colonial wars (59-61). + 2. The French alliance of 1778 (128-130). + 3. Controversies over the French Revolution (128-130). + 4. Commercial questions arising out of the European wars + (176-177, 180, 193-199). + 5. Attitude of Napoleon III toward the Civil War (354-355). + 6. The Mexican entanglement (478-479). + 7. The World War (596-620). + V. Relations with Germany. + 1. Negotiations with Frederick, king of Prussia (128). + 2. The Samoan controversy (481-482). + 3. Spanish-American War (491). + 4. The Venezuelan controversy (512). + 5. The World War (596-620). + VI. Relations with the Orient. + 1. Early trading connections (486-487). + 2. The opening of China (447). + 3. The opening of Japan (448). + 4. The Boxer rebellion and the "open door" policy (499-502). + 5. Roosevelt and the close of the Russo-Japanese War (511). + 6. The Oriental immigration question (583-584). + VII. The United States and Latin America. + 1. Mexican relations. + _a._ Mexican independence and the Monroe Doctrine (205-207). + _b._ Mexico and French intervention--policy of the United + States (478-479). + _c._ The overthrow of Diaz (1911) and recent questions + (594-596). + 2. Cuban relations. + _a._ Slavery and the "Ostend Manifesto" (485-486). + _b._ The revolutionary period, 1867-1877 (487). + _c._ The revival of revolution (487-491). + _d._ American intervention and the Spanish War (491-496). + _e._ The Platt amendment and American protection (518-519). + 3. Caribbean and other relations. + _a._ Acquisition of Porto Rico (493). + _b._ The acquisition of the Panama Canal strip (508-510). + _c._ Purchase of Danish West Indies (593). + _d._ Venezuelan controversies (482-484, 512). + _e._ Extension of protectorate over Haiti, Santo Domingo, + and Nicaragua (513-514, 592-594). + + + + +INDEX + + +Abolition, 318, 331 + +Adams, Abigail, 556 + +Adams, John, 97, 128, 179ff. + +Adams, J.Q., 247, 319 + +Adams, Samuel, 90, 99, 108 + +Adamson law, 590 + +Aguinaldo, 497 + +Alabama, admission, 227 + +_Alabama_ claims, 480 + +Alamance, battle, 92 + +Alamo, 280 + +Alaska, purchase, 479 + +Albany, plan of union, 62 + +Algonquins, 57 + +Alien law, 180 + +Amendment, method of, 156 + +Amendments to federal Constitution: first eleven, 163 + twelfth, 184, note + thirteenth, 358 + fourteenth, 366, 369, 387 + fifteenth, 358 + sixteenth, 528 + seventeenth, 542 + eighteenth, 591 + nineteenth, 563ff. + +American expeditionary force, 610 + +American Federation of Labor, 573, 608 + +Americanization, 585 + +Amnesty, for Confederates, 383 + +Andros, 65 + +Annapolis, convention, 144 + +Antietam, 357 + +Anti-Federalists, 169 + +Anti-slavery. _See_ Abolition + +Anthony, Susan, 564 + +Appomattox, 363 + +Arbitration: international, 480, 514, 617 + labor disputes, 582 + +Arizona, admission, 443 + +Arkansas, admission, 272 + +Arnold, Benedict, 114, 120 + +Articles of Confederation, 110, 139ff., 146 + +Ashburton, treaty, 265 + +Assembly, colonial, 49ff., 89ff. + +Assumption, 164ff. + +Atlanta, 361 + +Australian ballot, 540 + + +Bacon, Nathaniel, 58 + +Ballot: Australian, 540 + short, 544 + +Baltimore, Lord, 6 + +Bank: first U.S., 167 + second, 203, 257ff. + +Banking system: state, 300 + U.S. national, 369 + services of, 407 + _See also_ Federal reserve + +Barry, John, 118 + +Bastille, 172 + +Bell, John, 341 + +Belleau Wood, 611 + +Berlin decree, 194 + +Blockade: by England and France, 193ff. + Southern ports, 353 + law and practice in 1914, 598ff. + +Bond servants, 13ff. + +Boone, Daniel, 28, 218 + +Boston: massacre, 91 + evacuation, 116 + port bill, 94 + +Bowdoin, Governor, 142 + +Boxer rebellion, 499 + +Brandywine, 129 + +Breckinridge, J.C., 340 + +Bright, John, 355 + +Brown, John, 338 + +Brown University, 45 + +Bryan, W.J., 468ff., 495, 502, 503, 527 + +Buchanan, James, 335, 368 + +Budget system, 529 + +Bull Run, 350 + +Bunker Hill, 102 + +Burgoyne, General, 116, 118, 130 + +Burke, Edmund, 87, 96ff., 132, 175 + +Burr, Aaron, 183, 231 + +Business. _See_ Industry + + +Calhoun, J.C., 198ff., 203, 208, 281, 321, 328 + +California, 286ff. + +Canada, 61, 114, 530 + +Canals, 233, 298, 508 + +Canning, British premier, 206 + +Cannon, J.G., 530 + +Cantigny, 611 + +Caribbean, 479 + +Carpet baggers, 373 + +Cattle ranger, 431ff. + +Caucus, 245 + +Censorship. _See_ Newspapers + +Charles I, 3 + +Charles II, 65 + +Charleston, 36, 116 + +Charters, colonial, 2ff., 41 + +Chase, Justice, 187 + +Chateau-Thierry, 611 + +Checks and balances, 153 + +_Chesapeake_, the, 195 + +Chickamauga, 361 + +Child labor law, 591 + +China, 447, 499ff. + +Chinese labor, 583 + +Churches, colonial, 39ff., 42, 43 + +Cities, 35, 36, 300ff., 395, 410, 544 + +City manager plan, 545 + +Civil liberty, 358ff., 561 + +Civil service, 419, 536, 538ff. + +Clarendon, Lord, 6 + +Clark, G.R., 116, 218 + +Clay, Henry, 198, 203, 248, 261, 328 + +Clayton anti-trust act, 489 + +Clergy. _See_ Churches + +Cleveland, Grover, 421, 465, 482, 484, 489, 582 + +Clinton, Sir Henry, 119 + +Colorado, admission, 441 + +Combination. _See_ Trusts + +Commerce, colonial, 33ff. + disorders after 1781, 140 + Constitutional provisions on, 154 + Napoleonic wars, 176, 193ff. + domestic growth of, 307 + congressional regulation of, 460ff., 547 + _See also_ Trusts and Railways + +Commission government, 544 + +Committees of correspondence, 108 + +_Commonsense_, pamphlet, 103 + +Communism, colonial, 20f. + +Company, trading, 2f. + +Compromises: of Constitution, 148, 150, 151 + Missouri, 325, 332 + of 1850, 328ff. + Crittenden, 350 + +Conciliation, with England, 131 + +Concord, battle, 100 + +Confederacy, Southern, 346ff. + +Confederation: New England, 61f. + _See also_ Articles of + +Congregation, religious, 4 + +Congress: stamp act, 85 + continental, 99ff. + under Articles, 139f. + under Constitution, 152 + powers of, 153 + +Connecticut: founded, 4ff. + self-government, 49 + _See also_ Suffrage + constitutions, state + +Conservation, 523ff. + +Constitution: formation of, 143ff. + _See also_ Amendment + +_Constitution_, the, 200 + +Constitutions, state, 109ff., 238ff., 385ff. + +Constitutional union party, 340 + +Contract labor law, 584 + +Convention: 1787, 144ff. + nominating, 405 + +Convicts, colonial, 15 + +Conway Cabal, 120 + +Cornwallis, General, 116, 119, 131 + +Corporation and labor, 571. _See also_ Trusts + +Cotton. _See_ Planting system + +Cowboy, 431ff. + +Cowpens, battle, 116 + +Cox, J.M., 619 + +_Crisis, The_, pamphlet, 115 + +Crittenden Compromise, 350 + +Cuba, 485ff., 518 + +Cumberland Gap, 223 + +Currency. _See_ Banking + + +Danish West Indies, purchased, 593 + +Dartmouth College, 45 + +Daughters of liberty, 84 + +Davis, Jefferson, 346ff. + +Deane, Silas, 128 + +Debs, E.V., 465, 534 + +Debt, national, 164ff. + +Decatur, Commodore, 477 + +Declaration of Independence, 101ff. + +Defense, national, 154 + +De Kalb, 121 + +Delaware, 3, 49 + +De Lome affair, 490 + +Democratic party, name assumed, 260 + _See also_ Anti-Federalists + +Dewey, Admiral, 492 + +Diplomacy: of the Revolution, 127ff. + Civil War, 354 + +Domestic industry, 28 + +Donelson, Fort, 361 + +Dorr Rebellion, 243 + +Douglas, Stephen A., 333, 337, 368 + +Draft: Civil War, 351 + World War, 605 + +Draft riots, 351 + +Dred Scott case, 335, 338 + +Drug act, 523 + +Duquesne, Fort, 60 + +Dutch, 3, 12 + + +East India Company, 93 + +Education, 43ff., 557, 591 + +Electors, popular election of, 245 + +Elkins law, 547 + +Emancipation, 357ff. + +Embargo acts, 186ff. + +England: Colonial policy of, 64ff. + Revolutionary War, 99ff. + Jay treaty, 177 + War of 1812, 198ff. + Monroe Doctrine, 206 + Ashburton treaty, 265 + Civil War, 354 + _Alabama_ claims, 480 + Samoa, 481 + Venezuela question, 482 + Spanish War, 496 + World War, 596ff. + +Erie Canal, 233 + +Esch-Cummins bill, 582 + +Espionage act, 607 + +Excess profits tax, 606 + +Executive, federal, plans for, 151 + +Expunging resolution, 260 + + +Farm loan act, 589 + +Federal reserve act, 589 + +Federal trade commission, 590 + +_Federalist_, the, 158 + +Federalists, 168ff., 201ff. + +Feudal elements in colonies, 21f. + +Filipino revolt. _See_ Philippines + +Fillmore, President, 485 + +Finances: colonial, 64 + revolutionary, 125ff. + disorders, 140 + Civil War, 347, 352ff. + World War, 606 + _See also_ Banking + +Fishing industry, 31 + +Fleet, world tour, 515 + +Florida, 134, 204 + +Foch, General, 611 + +Food and fuel law, 607 + +Force bills, 384 ff., 375 + +Forests, national, 525ff. + +Fourteen points, 605 + +Fox, C.J., 132 + +France: colonization, 59ff. + French and Indian War, 60ff. + American Revolution, 116, 123, 128ff. + French Revolution, 165ff. + Quarrel with, 180 + Napoleonic wars, 193ff. + Louisiana purchase, 190 + French Revolution of 1830, 266 + Civil War, 354 + Mexican affair, 478 + World War, 596ff. + +Franchises, utility, 548 + +Franklin, Benjamin, 45, 62, 82, 86, 128, 134 + +Freedmen. _See_ Negro + +Freehold. _See_ Land + +Free-soil party, 319 + +Fremont, J.C., 288, 334 + +French. _See_ France + +Friends, the, 5 + +Frontier. _See_ Land + +Fugitive slave act, 329 + +Fulton, Robert, 231, 234 + +Fundamental articles, 5 + +Fundamental orders, 5 + + +Gage, General, 95, 100 + +Garfield, President, 416 + +Garrison, William Lloyd, 318 + +_Gaspee_, the, 92 + +Gates, General, 116, 120, 131 + +Genet, 177 + +George I, 66 + +George II, 4, 66, 82 + +George III, 77ff. + +Georgia: founded, 4 + royal province, 49 + state constitution, 109 + _See also_ Secession + +Germans: colonial immigration, 9ff. + in Revolutionary War, 102ff. + later immigration, 303 + +Germany: Samoa, 481 + Venezuela affair, 512 + World War, 596f. + +Gerry, Elbridge, 148 + +Gettysburg, 362 + +Gibbon, Edward, 133 + +Gold: discovery, 288 + standard, 466, 472 + +Gompers, Samuel, 573, 608 + +Governor, royal, 49ff. + +Grandfather clause, 386f. + +Grangers, 460ff. + +Grant, General, 361, 416, 480, 487 + +Great Britain. _See_ England + +Greeley, Horace, 420 + +Greenbacks, 454ff. + +Greenbackers, 462ff. + +Greene, General, 117, 120 + +Grenville, 79ff. + +Guilford, battle, 117 + + +Habeas corpus, 358 + +Hague conferences, 514 + +Haiti, 593 + +Hamilton, Alexander, 95, 143, 158, 162, 168ff., 231 + +Harding, W.G., 389, 619 + +Harlem Heights, battle, 114 + +Harper's Ferry, 339 + +Harrison, Benjamin, 422, 484 + +Harrison, W.H., 198, 263f. + +Hartford convention, 201ff., 238 + +Harvard, 44 + +Hawaii, 484f. + +Hay, John, 477, 500ff. + +Hayne, Robert, 256 + +Hays, President, 416f. + +Henry, Patrick, 85 + +Hepburn act, 523 + +Hill, James J., 429 + +Holland, 130 + +Holy Alliance, 205 + +Homestead act, 368, 432 + +Hooker, Thomas, 5 + +Houston, Sam, 279ff. + +Howe, General, 118 + +Hughes, Charles E., 602 + +Huguenots, 10 + +Hume, David, 132 + +Hutchinson, Anne, 5 + + +Idaho, admission, 442 + +Income tax, 459, 466, 528, 588, 606 + +Inheritance tax, 606 + +Illinois, admission, 226 + +Illiteracy, 585 + +Immigration: colonial, 1-17 + before Civil War, 302, 367 + after Civil War, 410ff. + problems of, 582ff. + +Imperialism, 494ff., 498f., 502ff. + +Implied powers, 212 + +Impressment of seamen, 194 + +Indentured servants, 13f. + +Independence, Declaration of, 107 + +Indiana, admission, 226 + +Indians, 57ff., 81, 431 + +Industry: colonial, 28ff. + growth of, 296ff. + during Civil War, 366 + after 1865, 390ff., 401ff., 436ff., 559 + _See also_ Trusts + +Initiative, the, 543 + +Injunction, 465, 580 + +Internal improvements, 260, 368 + +Interstate commerce act, 461, 529 + +Intolerable acts, 93 + +Invisible government, 537 + +Iowa, admission, 275 + +Irish, 11, 302 + +Iron. _See_ Industry + +Irrigation, 434ff., 523ff. + + +Jackson, Andrew, 201, 204, 246, 280 + +Jacobins, 174 + +James I, 3 + +James II, 65 + +Jamestown, 3, 21 + +Japan, relations with, 447, 511, 583 + +Jay, John, 128, 158, 177 + +Jefferson, Thomas: Declaration of Independence, 107 + Secretary of State, 162ff. + political leader, 169 + as President, 183ff. + Monroe Doctrine, 206, 231 + +Jews, migration of, 11 + +Johnson, Andrew, 365, 368, 371f. + +Johnson, Samuel, 132 + +Joliet, 59 + +Jones, John Paul, 118 + +Judiciary: British system, 67 + federal, 152 + + +Kansas, admission, 441 + +Kansas-Nebraska bill, 333 + +Kentucky: admission, 224 + Resolutions, 182 + +King George's War, 59 + +King Philip's War, 57 + +King William's War, 59 + +King's College (Columbia), 45 + +Knights of Labor, 575ff. + +Kosciusko, 121 + +Ku Klux Klan, 382 + + +Labor: rise of organized, 304 + parties, 462ff. + question, 521 + American Federation, 573ff. + legislation, 590 + World War, 608ff. + +Lafayette, 121 + +La Follette, Senator, 531 + +Land: tenure 20ff. + sales restricted, 80 + Western survey, 219 + federal sales policy, 220 + Western tenure, 228 + disappearance of free, 445 + new problems, 449 + _See also_ Homestead act + +La Salle, 59 + +Lawrence, Captain, 200 + +League of Nations, 616ff. + +Le Boeuf, Fort, 59 + +Lee, General Charles, 131 + +Lee, R.E., 357 + +Lewis and Clark expedition, 193 + +Lexington, battle, 100 + +Liberal Republicans, 420 + +Liberty loan, 606 + +Lincoln: Mexican War, 282 + Douglas debates, 336f. + election, 341 + Civil War, 344ff. + reconstruction, 371 + +Literacy test, 585 + +Livingston, R.R., 191 + +Locke, John, 95 + +London Company, 3 + +Long Island, battle, 114 + +Lords of trade, 67ff. + +Louis XVI, 171ff. + +Louisiana: ceded to Spain, 61 + purchase, 190ff. + admission, 227 + +Loyalists. _See_ Tories + +_Lusitania_, the, 601ff. + + +McClellan, General, 362, 365 + +McCulloch _vs._ Maryland, 211 + +McKinley, William, 422, 467ff., 489ff. + +Macaulay, Catherine, 132 + +Madison, James, 158, 197ff. + +Maine, 325 + +_Maine_, the, 490 + +Manila Bay, battle, 492 + +Manors, colonial, 22 + +Manufactures. _See_ Industry + +Marbury _vs._ Madison, 209 + +Marietta, 220 + +Marion, Francis, 117, 120 + +Marquette, 59 + +Marshall, John, 208ff. + +Martineau, Harriet, 267 + +Maryland, founded, 6, 49, 109, 239, 242 + +Massachusetts: founded, 3ff. + _See also_ Immigration, Royal province, Industry, Revolutionary War, + Constitutions, state, Suffrage, Commerce, and Industry + +Massachusetts Bay Company, 3 + founded, 3ff. + _See also_ Immigration, Royal province + +_Mayflower_ compact, 4 + +Mercantile theory, 69 + +Merchants. _See_ Commerce + +_Merrimac_, the, 353 + +Meuse-Argonne, battle, 612 + +Mexico: and Texas, 278ff. + later relations, 594f. + +Michigan, admission, 273 + +Midnight appointees, 187 + +Milan Decree, 194 + +Militia, Revolutionary War, 122 + +Minimum wages, 551 + +Minnesota, admission, 275 + +Mississippi River, and West, 189f. + +Missouri Compromise, 207, 227, 271, 325, 332 + +Molasses act, 71 + +Money, paper, 80, 126, 155, 369 + +_Monitor_, the, 353 + +Monroe, James, 204ff., 191 + +Monroe Doctrine, 205, 512 + +Montana, admission, 442 + +Montgomery, General, 114 + +Morris, Robert, 127 + +Mothers' pensions, 551 + +Mohawks, 57 + +Muckraking, 536f. + +Mugwumps, 420 + +Municipal ownership, 549 + + +Napoleon I, 190 + +Napoleon III: Civil War, 354f. + Mexico, 477 + +National Labor Union, 574 + +National road, 232 + +Nationalism, colonial, 56ff. + +Natural rights, 95 + +Navigation acts, 69 + +Navy: in Revolution, 188 + War of 1812, 195 + Civil War, 353 + World War, 610. + _See also_ Sea Power + +Nebraska, admission, 441 + +Negro: Civil rights, 370ff. + in agriculture, 393ff. + status of, 396ff. + _See also_ Slavery + +New England: colonial times, 6ff., 35, 40ff. + _See also_ Industry, Suffrage, Commerce, and Wars + +New Hampshire: founded, 4ff. + _See also_ Immigration, Royal province, Suffrage, and Constitutions, + state + +New Jersey, founded, 6. + _See also_ Immigration, Royal province, Suffrage, and + Constitutions, state + +Newlands, Senator, 524 + +New Mexico, admission, 443 + +New Orleans, 59, 190 + battle, 201 + +Newspapers, colonial, 46ff. + +New York: founded by Dutch, 3 + transferred to English, 49 + _See also_ Dutch, Immigration, Royal province, Commerce, Suffrage, + and Constitutions, state + +New York City, colonial, 36 + +Niagara, Fort, 59 + +Nicaragua protectorate, 594 + +Non-intercourse act, 196ff. + +Non-importation, 84ff., 99 + +North, Lord, 100, 131, 133 + +North Carolina: founded, 6. + _See also_ Royal province, Immigration, Suffrage, and Constitutions, + state + +North Dakota, admission, 442 + +Northwest Ordinance, 219 + +Nullification, 182, 251ff. + + +Oglethorpe, James, 3 + +Ohio, admission, 225 + +Oklahoma, admission, 443 + +Open door policy, 500 + +Oregon, 284ff. + +Ostend Manifesto, 486 + +Otis, James, 88, 95f. + + +Pacific, American influence, 447 + +Paine, Thomas, 103, 115, 175 + +Panama Canal, 508ff. + +Panics: 1837, 262 + 1857, 336 + 1873, 464 + 1893, 465 + +Parcel post, 529 + +Parker, A.B., 527 + +Parties: rise of, 168ff. + Federalists, 169ff. + Anti-Federalists (Jeffersonian Republicans), 169ff. + Democrats, 260 + Whigs, 260ff. + Republicans, 334ff. + Liberal Republicans, 420 + Constitutional union, 340 + minor parties, 462ff. + +Paterson, William, 196ff. + +Penn, William, 6 + +Pennsylvania: founded, 6 + _See also_ Penn, Germans, Immigration, Industry, Revolutionary War, + Constitutions, state, Suffrage + +Pennsylvania University, 45 + +Pensions, soldiers and sailors, 413, 607 + mothers', 551 + +Pequots, 57 + +Perry, O.H., 200 + +Pershing, General, 610 + +Philadelphia, 36, 116 + +Philippines, 492ff., 516ff., 592 + +Phillips, Wendell, 320 + +Pierce, Franklin, 295, 330 + +Pike, Z., 193, 287 + +Pilgrims, 4 + +Pinckney, Charles, 148 + +Pitt, William, 61, 79, 87, 132 + +Planting system, 22f., 25, 149, 389, 393ff. + +Plymouth, 4, 21 + +Polk, J.K., 265, 285f. + +Polygamy, 290f. + +Populist party, 464 + +Porto Rico, 515, 592 + +Postal savings bank, 529 + +Preble, Commodore, 196 + +Press. _See_ Newspapers + +Primary, direct, 541 + +Princeton, battle, 129 + University, 45 + +Profit sharing, 572 + +Progressive party, 531f. + +Prohibition, 591f. + +Proprietary colonies, 3, 6 + +Provinces, royal, 49ff. + +Public service, 538ff. + +Pulaski, 121 + +Pullman strike, 465 + +Pure food act, 523 + +Puritans, 3, 7, 40ff. + + +Quakers, 6ff. + +Quartering act, 83 + +Quebec act, 94 + +Queen Anne's War, 59 + +Quit rents, 21f. + + +Radicals, 579 + +Railways, 298, 402, 425, 460ff., 547, 621 + +Randolph, Edmund, 146, 147, 162 + +Ratification, of Constitution, 156ff. + +Recall, 543 + +Reclamation, 523ff. + +Reconstruction, 370ff. + +Referendum, the, 543 + +Reign of terror, 174 + +Republicans: Jeffersonian, 179 + rise of present party, 334ff. + supremacy of, 412ff. + _See also_ McKinley, Roosevelt, and Taft + +Resumption, 454 + +Revolution: American, 99ff. + French, 171ff. + Russian, 619 + +Rhode Island: founded, 4ff. + self-government, 49 + _See also_ Suffrage + +Roosevelt, Theodore, 492, 500ff., 531, 570 + +Royal province, 49ff. + +Russia, 205, 207, 355, 479, 619 + +Russo-Japanese War, 511f. + + +Saint Mihiel, 612 + +Samoa, 481 + +San Jacinto, 280 + +Santa Fe trail, 287 + +Santo Domingo, 480, 513, 592 + +Saratoga, battle, 116, 130 + +Savannah, 116, 131 + +Scandinavians, 278 + +Schools. _See_ Education + +Scott, General, 283, 330 + +Scotch-Irish, 7ff. + +Seamen's act, 590 + +Sea power: American Revolution, 118 + Napoleonic wars, 193ff. + Civil War, 353 + Caribbean, 593 + Pacific, 447 + World War, 610ff. + +Secession, 344ff. + +Sedition: act of 1798, 180ff., 187 + of 1918, 608 + +Senators, popular election, 527, 541ff. + +Seven Years' War, 60ff. + +Sevier, John, 218 + +Seward, W.H., 322, 342 + +Shafter, General, 492 + +Shays's rebellion, 142 + +Sherman, General, 361 + +Sherman: anti-trust law, 461 + silver act, 458 + +Shiloh, 361 + +Shipping. _See_ Commerce + +Shipping act, 607 + +Silver, free, 455ff. + +Slavery: colonial, 16f. + trade, 150 + in Northwest, 219 + decline in North, 316f. + growth in South, 320ff. + and the Constitution, 324 + and territories, 325ff. + compromises, 350 + abolished, 357ff. + +Smith, Joseph, 290 + +Socialism, 577ff. + +Solid South, 388 + +Solomon, Hayn, 126 + +Sons of liberty, 82 + +South: economic and political views, 309ff. + _See also_ Slavery and Planting system, and Reconstruction + +South Carolina: founded, 6 + nullification, 253ff. + _See also_ Constitutions, state, Suffrage, Slavery, and Secession + +South Dakota, 442 + +Spain: and Revolution, 130 + Louisiana, 190 + Monroe Doctrine, 205 + Spanish War, 490ff. + +Spoils system, 244, 250, 418, 536ff. + +Stamp act, 82ff. + +Stanton, Elizabeth Cady, 564 + +States: disorders under Articles of Confederation, 141 + constitutions, federal limits on, 155 + position after Civil War, 366ff. + _See also_ Suffrage, Nullification, and Secession + +Steamboat, 234 + +Stowe, H.B., 332 + +Strikes: of 1877, 581 + Pullman, 581 + coal, 526 + _See also_ Labor + +Submarine campaign, 600ff. + +Suffrage: colonial, 42, 51 + first state constitutions, 239 + White manhood, 242 + Negro, 374ff., 385f. + Woman, 110, 562ff. + +Sugar act, 81 + +Sumner, Charles, 319 + +Sumter, Fort, 350 + +Swedes, 3, 13 + + +Taft, W.H., 527ff. + +Tammany Hall, 306, 418 + +Taney, Chief Justice, 357 + +Tariff: first, 167 + of 1816, 203 + development of, 251ff. + abominations, 249, 253 + nullification, 251 + of 1842, 264 + Southern views of, 309ff. + of 1857, 337 + Civil War, 367 + Wilson bill, 459 + McKinley bill, 422 + Dingley bill, 472 + Payne-Aldrich, 528 + Underwood, 588 + +Taxation: and representation, 149 + and Constitution, 154 + Civil War, 353 + and wealth, 522, 551 + and World War, 606 + +Tea act, 88 + +Tea party, 92 + +Tenement house reform, 549 + +Tennessee, 28, 224 + +Territories, Northwest, 219 + South of the Ohio, 219 + _See also_ Slavery and Compromise + +Texas, 278ff. + +Tippecanoe, battle, 198 + +Tocqueville, 267 + +Toleration, religious, 42 + +Tories, colonial, 84 + in Revolution, 112 + +Townshend acts, 80, 87 + +Trade, colonial, 70 + legislation, 70. _See_ Commerce + +Transylvania company, 28 + +Treasury, independent, 263 + +Treaties, of 1763, 61 + alliance with France, 177 + of 1783 with England, 134 + Jay, 177, 218 + Louisiana purchase, 191f. + of 1815, 201 + Ashburton, 265 + of 1848 with Mexico, 283 + Washington with England, 481 + with Spain, 492 + Versailles (1919), 612ff. + +Trenton, battle, 116 + +Trollope, Mrs., 268 + +Trusts, 405ff., 461, 472ff., 521, 526, 530 + +Tweed, W.M., 418 + +Tyler, President, 264ff., 281, 349 + + +"Uncle Tom's Cabin," 332 + +Union party, 365 + +Unions. _See_ Labor + +Utah, 290ff., 329, 442 + +Utilities, municipal, 548 + + +Vallandigham, 360 + +Valley Forge, 116, 129 + +Van Buren, Martin, 262 + +Venango, Fort, 59 + +Venezuela, 482ff., 512 + +Vermont, 223 + +Vicksburg, 361 + +Virginia: founded, 3. + _See also_ Royal province, Constitutions, state, Planting system, + Slavery, Secession, and Immigration + + +Walpole, Sir Robert, 66 + +Wars: colonial, 57ff. + Revolutionary, 99ff. + of 1812, 199ff. + Mexican, 282ff. + Civil, 344ff. + Spanish, 490ff. + World, 596ff. + +Washington: warns French, 60 + in French war, 63 + commander-in-chief, 101ff. + and movement for Constitution, 142ff. + as President, 166ff. + Farewell Address, 178 + +Washington City, 166 + +Washington State, 442 + +Webster, 256, 265, 328 + +Welfare work, 573 + +Whigs: English, 78 + colonial, 83 + rise of party, 260ff., 334, 340 + +Whisky Rebellion, 171 + +White Camelia, 382 + +White Plains, battle, 114 + +Whitman, Marcus, 284 + +William and Mary College, 45 + +Williams, Roger, 5, 42 + +Wilmot Proviso, 326 + +Wilson, James, 147 + +Wilson, Woodrow, election, 533f. + administrations, 588ff. + +Winthrop, John, 3 + +Wisconsin, admission, 274 + +Witchcraft, 41 + +Wollstonecraft, Mary, 556 + +Women: colonial, 28 + Revolutionary War, 124 + labor, 305 + education and civil rights, 554ff. + suffrage, 562ff. + +Workmen's compensation, 549 + +Writs of assistance, 88 + +Wyoming, admission, 442 + + +X, Y, Z affair, 180 + + +Yale, 44 + +Young, Brigham, 290 + + +Zenger, Peter, 48 + + * * * * * + +Printed in the United States of America. + + * * * * * + +[Transcriber's notes: + +Punctuation normalized in all _Underwood and Underwood, N.Y._ + +Superscripted letters are denoted with a caret. For example, G^O +WASHINGTON. + +Period added after Mass on verso page. Original read "Mass, U.S.A." + +Chapter I, page 19, period added to pp. 55-159 and pp. 242-244. + +Chapter IV, page 61 cooperation changed to cooperation twice to match +rest of text usage. Also on page 620. + +Chapter VI, page 121 changed maneuvered to manoevered. + +Chapter VIII, page 185, period added to "Vol." Original read "Vol III," + +Chapter X, page 219, changed coordinate to coordinate to reflect rest of +text usage. + +Chapter X, page 234, Italicized habeus corpus to match rest of text. + +Chapter XI, page 257 changed reestablished to reestablished to conform +to rest of text usage. + +Chapter XI, page 259 changed reelection to reelection + +Chapter XII, page 269 added period after "Vol" Vol. II + +Chapter XII, page 270. Title of work reads "_Selected Documents of +United States History, 1776-1761_". Research shows the document does +have this title. + +Chapter XV, page 351. changed "bout" to "about". "for only about" + +Chapter XVI, page 385. changed "provisons" to "provisions". + +Chapter XX, page 478. changed "aniversary" to "anniversary". + +Chapter XXIV, page 579 word "on" changed to "one" "five commissioners, +one of whom," + +Topical Syllabus. Missing periods added to normalize punctuation in +entries such as on page 648 (4) Sixteenth Amendment--income tax +(528-529). + +Appendix, page 631, comma changed to semi-colon on "bills of credit;" to +match rest of list. Also on "obligation of contracts;" + +Index, page 657, changed "Freesoil" to Free-soil to match rest of text +usage. + +Index, page 660, space removed from "396 ff." changed to "status of, +396ff." + +Index, Page 662, added comma to States: disorders under Articles of +Constitution, 141] + + + + + +End of the Project Gutenberg EBook of History of the United States +by Charles A. Beard and Mary R. Beard + +*** END OF THIS PROJECT GUTENBERG EBOOK HISTORY OF THE UNITED STATES *** + +***** This file should be named 16960-8.txt or 16960-8.zip ***** +This and all associated files of various formats will be found in: + http://www.gutenberg.org/1/6/9/6/16960/ + +Produced by Curtis Weyant, M and the Online Distributed +Proofreading Team at http://www.pgdp.net + + +Updated editions will replace the previous one--the old editions +will be renamed. + +Creating the works from public domain print editions means that no +one owns a United States copyright in these works, so the Foundation +(and you!) can copy and distribute it in the United States without +permission and without paying copyright royalties. Special rules, +set forth in the General Terms of Use part of this license, apply to +copying and distributing Project Gutenberg-tm electronic works to +protect the PROJECT GUTENBERG-tm concept and trademark. Project +Gutenberg is a registered trademark, and may not be used if you +charge for the eBooks, unless you receive specific permission. If you +do not charge anything for copies of this eBook, complying with the +rules is very easy. You may use this eBook for nearly any purpose +such as creation of derivative works, reports, performances and +research. They may be modified and printed and given away--you may do +practically ANYTHING with public domain eBooks. Redistribution is +subject to the trademark license, especially commercial +redistribution. + + + +*** START: FULL LICENSE *** + +THE FULL PROJECT GUTENBERG LICENSE +PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK + +To protect the Project Gutenberg-tm mission of promoting the free +distribution of electronic works, by using or distributing this work +(or any other work associated in any way with the phrase "Project +Gutenberg"), you agree to comply with all the terms of the Full Project +Gutenberg-tm License (available with this file or online at +http://gutenberg.net/license). + + +Section 1. General Terms of Use and Redistributing Project Gutenberg-tm +electronic works + +1.A. By reading or using any part of this Project Gutenberg-tm +electronic work, you indicate that you have read, understand, agree to +and accept all the terms of this license and intellectual property +(trademark/copyright) agreement. If you do not agree to abide by all +the terms of this agreement, you must cease using and return or destroy +all copies of Project Gutenberg-tm electronic works in your possession. +If you paid a fee for obtaining a copy of or access to a Project +Gutenberg-tm electronic work and you do not agree to be bound by the +terms of this agreement, you may obtain a refund from the person or +entity to whom you paid the fee as set forth in paragraph 1.E.8. + +1.B. "Project Gutenberg" is a registered trademark. It may only be +used on or associated in any way with an electronic work by people who +agree to be bound by the terms of this agreement. There are a few +things that you can do with most Project Gutenberg-tm electronic works +even without complying with the full terms of this agreement. See +paragraph 1.C below. There are a lot of things you can do with Project +Gutenberg-tm electronic works if you follow the terms of this agreement +and help preserve free future access to Project Gutenberg-tm electronic +works. See paragraph 1.E below. + +1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation" +or PGLAF), owns a compilation copyright in the collection of Project +Gutenberg-tm electronic works. Nearly all the individual works in the +collection are in the public domain in the United States. If an +individual work is in the public domain in the United States and you are +located in the United States, we do not claim a right to prevent you from +copying, distributing, performing, displaying or creating derivative +works based on the work as long as all references to Project Gutenberg +are removed. Of course, we hope that you will support the Project +Gutenberg-tm mission of promoting free access to electronic works by +freely sharing Project Gutenberg-tm works in compliance with the terms of +this agreement for keeping the Project Gutenberg-tm name associated with +the work. You can easily comply with the terms of this agreement by +keeping this work in the same format with its attached full Project +Gutenberg-tm License when you share it without charge with others. + +1.D. The copyright laws of the place where you are located also govern +what you can do with this work. Copyright laws in most countries are in +a constant state of change. If you are outside the United States, check +the laws of your country in addition to the terms of this agreement +before downloading, copying, displaying, performing, distributing or +creating derivative works based on this work or any other Project +Gutenberg-tm work. The Foundation makes no representations concerning +the copyright status of any work in any country outside the United +States. + +1.E. Unless you have removed all references to Project Gutenberg: + +1.E.1. The following sentence, with active links to, or other immediate +access to, the full Project Gutenberg-tm License must appear prominently +whenever any copy of a Project Gutenberg-tm work (any work on which the +phrase "Project Gutenberg" appears, or with which the phrase "Project +Gutenberg" is associated) is accessed, displayed, performed, viewed, +copied or distributed: + +This eBook is for the use of anyone anywhere at no cost and with +almost no restrictions whatsoever. You may copy it, give it away or +re-use it under the terms of the Project Gutenberg License included +with this eBook or online at www.gutenberg.net + +1.E.2. If an individual Project Gutenberg-tm electronic work is derived +from the public domain (does not contain a notice indicating that it is +posted with permission of the copyright holder), the work can be copied +and distributed to anyone in the United States without paying any fees +or charges. If you are redistributing or providing access to a work +with the phrase "Project Gutenberg" associated with or appearing on the +work, you must comply either with the requirements of paragraphs 1.E.1 +through 1.E.7 or obtain permission for the use of the work and the +Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or +1.E.9. + +1.E.3. If an individual Project Gutenberg-tm electronic work is posted +with the permission of the copyright holder, your use and distribution +must comply with both paragraphs 1.E.1 through 1.E.7 and any additional +terms imposed by the copyright holder. Additional terms will be linked +to the Project Gutenberg-tm License for all works posted with the +permission of the copyright holder found at the beginning of this work. + +1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm +License terms from this work, or any files containing a part of this +work or any other work associated with Project Gutenberg-tm. + +1.E.5. Do not copy, display, perform, distribute or redistribute this +electronic work, or any part of this electronic work, without +prominently displaying the sentence set forth in paragraph 1.E.1 with +active links or immediate access to the full terms of the Project +Gutenberg-tm License. + +1.E.6. You may convert to and distribute this work in any binary, +compressed, marked up, nonproprietary or proprietary form, including any +word processing or hypertext form. However, if you provide access to or +distribute copies of a Project Gutenberg-tm work in a format other than +"Plain Vanilla ASCII" or other format used in the official version +posted on the official Project Gutenberg-tm web site (www.gutenberg.net), +you must, at no additional cost, fee or expense to the user, provide a +copy, a means of exporting a copy, or a means of obtaining a copy upon +request, of the work in its original "Plain Vanilla ASCII" or other +form. Any alternate format must include the full Project Gutenberg-tm +License as specified in paragraph 1.E.1. + +1.E.7. Do not charge a fee for access to, viewing, displaying, +performing, copying or distributing any Project Gutenberg-tm works +unless you comply with paragraph 1.E.8 or 1.E.9. + +1.E.8. You may charge a reasonable fee for copies of or providing +access to or distributing Project Gutenberg-tm electronic works provided +that + +- You pay a royalty fee of 20% of the gross profits you derive from + the use of Project Gutenberg-tm works calculated using the method + you already use to calculate your applicable taxes. The fee is + owed to the owner of the Project Gutenberg-tm trademark, but he + has agreed to donate royalties under this paragraph to the + Project Gutenberg Literary Archive Foundation. Royalty payments + must be paid within 60 days following each date on which you + prepare (or are legally required to prepare) your periodic tax + returns. Royalty payments should be clearly marked as such and + sent to the Project Gutenberg Literary Archive Foundation at the + address specified in Section 4, "Information about donations to + the Project Gutenberg Literary Archive Foundation." + +- You provide a full refund of any money paid by a user who notifies + you in writing (or by e-mail) within 30 days of receipt that s/he + does not agree to the terms of the full Project Gutenberg-tm + License. You must require such a user to return or + destroy all copies of the works possessed in a physical medium + and discontinue all use of and all access to other copies of + Project Gutenberg-tm works. + +- You provide, in accordance with paragraph 1.F.3, a full refund of any + money paid for a work or a replacement copy, if a defect in the + electronic work is discovered and reported to you within 90 days + of receipt of the work. + +- You comply with all other terms of this agreement for free + distribution of Project Gutenberg-tm works. + +1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm +electronic work or group of works on different terms than are set +forth in this agreement, you must obtain permission in writing from +both the Project Gutenberg Literary Archive Foundation and Michael +Hart, the owner of the Project Gutenberg-tm trademark. Contact the +Foundation as set forth in Section 3 below. + +1.F. + +1.F.1. Project Gutenberg volunteers and employees expend considerable +effort to identify, do copyright research on, transcribe and proofread +public domain works in creating the Project Gutenberg-tm +collection. Despite these efforts, Project Gutenberg-tm electronic +works, and the medium on which they may be stored, may contain +"Defects," such as, but not limited to, incomplete, inaccurate or +corrupt data, transcription errors, a copyright or other intellectual +property infringement, a defective or damaged disk or other medium, a +computer virus, or computer codes that damage or cannot be read by +your equipment. + +1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right +of Replacement or Refund" described in paragraph 1.F.3, the Project +Gutenberg Literary Archive Foundation, the owner of the Project +Gutenberg-tm trademark, and any other party distributing a Project +Gutenberg-tm electronic work under this agreement, disclaim all +liability to you for damages, costs and expenses, including legal +fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT +LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE +PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE +TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE +LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR +INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH +DAMAGE. + +1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a +defect in this electronic work within 90 days of receiving it, you can +receive a refund of the money (if any) you paid for it by sending a +written explanation to the person you received the work from. If you +received the work on a physical medium, you must return the medium with +your written explanation. The person or entity that provided you with +the defective work may elect to provide a replacement copy in lieu of a +refund. If you received the work electronically, the person or entity +providing it to you may choose to give you a second opportunity to +receive the work electronically in lieu of a refund. If the second copy +is also defective, you may demand a refund in writing without further +opportunities to fix the problem. + +1.F.4. Except for the limited right of replacement or refund set forth +in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER +WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE. + +1.F.5. Some states do not allow disclaimers of certain implied +warranties or the exclusion or limitation of certain types of damages. +If any disclaimer or limitation set forth in this agreement violates the +law of the state applicable to this agreement, the agreement shall be +interpreted to make the maximum disclaimer or limitation permitted by +the applicable state law. The invalidity or unenforceability of any +provision of this agreement shall not void the remaining provisions. + +1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the +trademark owner, any agent or employee of the Foundation, anyone +providing copies of Project Gutenberg-tm electronic works in accordance +with this agreement, and any volunteers associated with the production, +promotion and distribution of Project Gutenberg-tm electronic works, +harmless from all liability, costs and expenses, including legal fees, +that arise directly or indirectly from any of the following which you do +or cause to occur: (a) distribution of this or any Project Gutenberg-tm +work, (b) alteration, modification, or additions or deletions to any +Project Gutenberg-tm work, and (c) any Defect you cause. + + +Section 2. Information about the Mission of Project Gutenberg-tm + +Project Gutenberg-tm is synonymous with the free distribution of +electronic works in formats readable by the widest variety of computers +including obsolete, old, middle-aged and new computers. It exists +because of the efforts of hundreds of volunteers and donations from +people in all walks of life. + +Volunteers and financial support to provide volunteers with the +assistance they need, is critical to reaching Project Gutenberg-tm's +goals and ensuring that the Project Gutenberg-tm collection will +remain freely available for generations to come. In 2001, the Project +Gutenberg Literary Archive Foundation was created to provide a secure +and permanent future for Project Gutenberg-tm and future generations. +To learn more about the Project Gutenberg Literary Archive Foundation +and how your efforts and donations can help, see Sections 3 and 4 +and the Foundation web page at http://www.pglaf.org. + + +Section 3. Information about the Project Gutenberg Literary Archive +Foundation + +The Project Gutenberg Literary Archive Foundation is a non profit +501(c)(3) educational corporation organized under the laws of the +state of Mississippi and granted tax exempt status by the Internal +Revenue Service. The Foundation's EIN or federal tax identification +number is 64-6221541. Its 501(c)(3) letter is posted at +http://pglaf.org/fundraising. Contributions to the Project Gutenberg +Literary Archive Foundation are tax deductible to the full extent +permitted by U.S. federal laws and your state's laws. + +The Foundation's principal office is located at 4557 Melan Dr. S. +Fairbanks, AK, 99712., but its volunteers and employees are scattered +throughout numerous locations. Its business office is located at +809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email +business@pglaf.org. Email contact links and up to date contact +information can be found at the Foundation's web site and official +page at http://pglaf.org + +For additional contact information: + Dr. Gregory B. Newby + Chief Executive and Director + gbnewby@pglaf.org + + +Section 4. Information about Donations to the Project Gutenberg +Literary Archive Foundation + +Project Gutenberg-tm depends upon and cannot survive without wide +spread public support and donations to carry out its mission of +increasing the number of public domain and licensed works that can be +freely distributed in machine readable form accessible by the widest +array of equipment including outdated equipment. Many small donations +($1 to $5,000) are particularly important to maintaining tax exempt +status with the IRS. + +The Foundation is committed to complying with the laws regulating +charities and charitable donations in all 50 states of the United +States. Compliance requirements are not uniform and it takes a +considerable effort, much paperwork and many fees to meet and keep up +with these requirements. We do not solicit donations in locations +where we have not received written confirmation of compliance. To +SEND DONATIONS or determine the status of compliance for any +particular state visit http://pglaf.org + +While we cannot and do not solicit contributions from states where we +have not met the solicitation requirements, we know of no prohibition +against accepting unsolicited donations from donors in such states who +approach us with offers to donate. + +International donations are gratefully accepted, but we cannot make +any statements concerning tax treatment of donations received from +outside the United States. U.S. laws alone swamp our small staff. + +Please check the Project Gutenberg Web pages for current donation +methods and addresses. Donations are accepted in a number of other +ways including including checks, online payments and credit card +donations. To donate, please visit: http://pglaf.org/donate + + +Section 5. General Information About Project Gutenberg-tm electronic +works. + +Professor Michael S. Hart is the originator of the Project Gutenberg-tm +concept of a library of electronic works that could be freely shared +with anyone. For thirty years, he produced and distributed Project +Gutenberg-tm eBooks with only a loose network of volunteer support. + + +Project Gutenberg-tm eBooks are often created from several printed +editions, all of which are confirmed as Public Domain in the U.S. +unless a copyright notice is included. Thus, we do not necessarily +keep eBooks in compliance with any particular paper edition. + + +Most people start at our Web site which has the main PG search facility: + + http://www.gutenberg.net + +This Web site includes information about Project Gutenberg-tm, +including how to make donations to the Project Gutenberg Literary +Archive Foundation, how to help produce our new eBooks, and how to +subscribe to our email newsletter to hear about new eBooks. +Project Gutenberg's Manual of Surgery, by Alexis Thomson and Alexander Miles + +This eBook is for the use of anyone anywhere at no cost and with +almost no restrictions whatsoever. You may copy it, give it away or +re-use it under the terms of the Project Gutenberg License included +with this eBook or online at www.gutenberg.org + + +Title: Manual of Surgery + Volume First: General Surgery. Sixth Edition. + +Author: Alexis Thomson and Alexander Miles + +Release Date: March 4, 2006 [EBook #17921] + +Language: English + +Character set encoding: ISO-8859-1 + +*** START OF THIS PROJECT GUTENBERG EBOOK MANUAL OF SURGERY *** + + + + +Produced by Jonathan Ingram, Laura Wisewell and the Online +Distributed Proofreading Team at http://www.pgdp.net + + + + + ++--------------------------------------------------------------------+ +| | +| Transcriber's note: The original text used the apothecaries' | +| symbols here rendered as [ounce] and [dram]. The substitutions | +| used for other special characters, such as the oe ligature, are | +| standard. All the special characters are preserved in the UTF-8 | +| and HTML versions of this text. | +| | +| In addition, a number of printing errors have been corrected. | +| These are marked in the HTML version only. | +| | ++--------------------------------------------------------------------+ + + + + + OXFORD MEDICAL PUBLICATIONS + + + + MANUAL OF SURGERY + + + + BY + + ALEXIS THOMSON, F.R.C.S.Ed. + _PROFESSOR OF SURGERY, UNIVERSITY OF EDINBURGH_ + SURGEON EDINBURGH ROYAL INFIRMARY + + AND + + ALEXANDER MILES, F.R.C.S.Ed. + SURGEON EDINBURGH ROYAL INFIRMARY + + + VOLUME FIRST + GENERAL SURGERY + + + _SIXTH EDITION REVISED_ + _WITH 169 ILLUSTRATIONS_ + + + + LONDON + HENRY FROWDE and HODDER & STOUGHTON + THE _LANCET_ BUILDING + 1 & 2 BEDFORD STREET, STRAND, W.C.2 + + + + + + + First Edition 1904 + Second Edition 1907 + Third Edition 1909 + Fourth Edition 1911 + " " Second Impression 1913 + Fifth Edition 1915 + " " Second Impression 1919 + Sixth Edition 1921 + + + + PRINTED IN GREAT BRITAIN BY + MORRISON AND GIBB LTD., EDINBURGH + + + + +PREFACE TO SIXTH EDITION + + +Much has happened since this Manual was last revised, and many surgical +lessons have been learned in the hard school of war. Some may yet have +to be unlearned, and others have but little bearing on the problems +presented to the civilian surgeon. Save in its broadest principles, the +surgery of warfare is a thing apart from the general surgery of civil +life, and the exhaustive literature now available on every aspect of it +makes it unnecessary that it should receive detailed consideration in a +manual for students. In preparing this new edition, therefore, we have +endeavoured to incorporate only such additions to our knowledge and +resources as our experience leads us to believe will prove of permanent +value in civil practice. + +For the rest, the text has been revised, condensed, and in places +rearranged; a number of old illustrations have been discarded, and a +greater number of new ones added. Descriptions of operative procedures +have been omitted from the _Manual_, as they are to be found in the +companion volume on _Operative Surgery_, the third edition of which +appeared some months ago. + +We have retained the Basle anatomical nomenclature, as extended +experience has confirmed our preference for it. For the convenience of +readers who still employ the old terms, these are given in brackets +after the new. + +This edition of the _Manual_ appears in three volumes; the first being +devoted to General Surgery, the other two to Regional Surgery. This +arrangement has enabled us to deal in a more consecutive manner than +hitherto with the surgery of the Extremities, including Fractures and +Dislocations. + +We have once more to express our thanks to colleagues in the Edinburgh +School and to other friends for aiding us in providing new +illustrations, and for other valuable help, as well as to our publishers +for their generosity in the matter of illustrations. + +EDINBURGH, + _March_ 1921. + + + + +CONTENTS + + + PAGE + CHAPTER I + REPAIR 1 + + CHAPTER II + CONDITIONS WHICH INTERFERE WITH REPAIR 17 + + CHAPTER III + INFLAMMATION 31 + + CHAPTER IV + SUPPURATION 45 + + CHAPTER V + ULCERATION AND ULCERS 68 + + CHAPTER VI + GANGRENE 86 + + CHAPTER VII + BACTERIAL AND OTHER WOUND INFECTIONS 107 + + CHAPTER VIII + TUBERCULOSIS 133 + + CHAPTER IX + SYPHILIS 146 + + CHAPTER X + TUMOURS 181 + + CHAPTER XI + INJURIES 218 + + CHAPTER XII + METHODS OF WOUND TREATMENT 241 + + CHAPTER XIII + CONSTITUTIONAL EFFECTS OF INJURIES 249 + + CHAPTER XIV + THE BLOOD VESSELS 258 + + CHAPTER XV + THE LYMPH VESSELS AND GLANDS 321 + + CHAPTER XVI + THE NERVES 342 + + CHAPTER XVII + SKIN AND SUBCUTANEOUS TISSUES 376 + + CHAPTER XVIII + THE MUSCLES, TENDONS, AND TENDON SHEATHS 405 + + CHAPTER XIX + THE BURSAE 426 + + CHAPTER XX + DISEASES OF BONE 434 + + CHAPTER XXI + DISEASES OF JOINTS 501 + + INDEX 547 + + + + +LIST OF ILLUSTRATIONS + + + FIG. PAGE + + 1. Ulcer of Back of Hand grafted from Abdominal Wall 15 + + 2. Staphylococcus aureus in Pus from case of Osteomyelitis 25 + + 3. Streptococci in Pus from case of Diffuse Cellulitis 26 + + 4. Bacillus coli communis in Pus from Abdominal Abscess 27 + + 5. Fraenkel's Pneumococci in Pus from Empyema following 28 + Pneumonia + + 6. Passive Hyperaemia of Hand and Forearm induced by Bier's 37 + Bandage + + 7. Passive Hyperaemia of Finger induced by Klapp's Suction 38 + Bell + + 8. Passive Hyperaemia induced by Klapp's Suction Bell for 39 + Inflammation of Inguinal Gland + + 9. Diagram of various forms of Whitlow 56 + + 10. Charts of Acute Sapraemia 61 + + 11. Chart of Hectic Fever 62 + + 12. Chart of Septicaemia followed by Pyaemia 63 + + 13. Chart of Pyaemia following on Acute Osteomyelitis 65 + + 14. Leg Ulcers associated with Varicose Veins 71 + + 15. Perforating Ulcers of Sole of Foot 74 + + 16. Bazin's Disease in a girl aet. 16 75 + + 17. Syphilitic Ulcers in region of Knee 76 + + 18. Callous Ulcer showing thickened edges 78 + + 19. Tibia and Fibula, showing changes due to Chronic Ulcer of 80 + Leg + + 20. Senile Gangrene of the Foot 89 + + 21. Embolic Gangrene of Hand and Arm 92 + + 22. Gangrene of Terminal Phalanx of Index-Finger 100 + + 23. Cancrum Oris 103 + + 24. Acute Bed Sores over right Buttock 104 + + 25. Chart of Erysipelas occurring in a wound 108 + + 26. Bacillus of Tetanus 113 + + 27. Bacillus of Anthrax 120 + + 28. Malignant Pustule third day after infection 122 + + 29. Malignant Pustule fourteen days after infection 122 + + 30. Colony of Actinomyces 126 + + 31. Actinomycosis of Maxilla 128 + + 32. Mycetoma, or Madura Foot 130 + + 33. Tubercle bacilli 134 + + 34. Tuberculous Abscess in Lumbar Region 141 + + 35. Tuberculous Sinus injected through its opening in the 144 + Forearm with Bismuth Paste + + 36. Spirochaete pallida 147 + + 37. Spirochaeta refrigerans from scraping of Vagina 148 + + 38. Primary Lesion on Thumb, with Secondary Eruption on 154 + Forearm + + 39. Syphilitic Rupia 159 + + 40. Ulcerating Gumma of Lips 169 + + 41. Ulceration in inherited Syphilis 170 + + 42. Tertiary Syphilitic Ulceration in region of Knee and on 171 + both Thumbs + + 43. Facies of Inherited Syphilis 174 + + 44. Facies of Inherited Syphilis 175 + + 45. Subcutaneous Lipoma 185 + + 46. Pedunculated Lipoma of Buttock 186 + + 47. Diffuse Lipomatosis of Neck 187 + + 48. Zanthoma of Hands 188 + + 49. Zanthoma of Buttock 189 + + 50. Chondroma growing from Infra-Spinous Fossa of Scapula 190 + + 51. Chondroma of Metacarpal Bone of Thumb 190 + + 52. Cancellous Osteoma of Lower End of Femur 192 + + 53. Myeloma of Shaft of Humerus 195 + + 54. Fibro-myoma of Uterus 196 + + 55. Recurrent Sarcoma of Sciatic Nerve 198 + + 56. Sarcoma of Arm fungating 199 + + 57. Carcinoma of Breast 206 + + 58. Epithelioma of Lip 209 + + 59. Dermoid Cyst of Ovary 213 + + 60. Carpal Ganglion in a woman aet. 25 215 + + 61. Ganglion on lateral aspect of Knee 216 + + 62. Radiogram showing pellets embedded in Arm 228 + + 63. Cicatricial Contraction following Severe Burn 236 + + 64. Genealogical Tree of Haemophilic Family 278 + + 65. Radiogram showing calcareous degeneration of Arteries 284 + + 66. Varicose Vein with Thrombosis 289 + + 67. Extensive Varix of Internal Saphena System on Left Leg 291 + + 68. Mixed Naevus of Nose 296 + + 69. Cirsoid Aneurysm of Forehead 299 + + 70. Cirsoid Aneurysm of Orbit and Face 300 + + 71. Radiogram of Aneurysm of Aorta 303 + + 72. Sacculated Aneurysm of Abdominal Aorta 304 + + 73. Radiogram of Innominate Aneurysm after Treatment by 309 + Moore-Corradi method + + 74. Thoracic Aneurysm threatening to rupture 313 + + 75. Innominate Aneurysm in a woman 315 + + 76. Congenital Cystic Tumour or Hygroma of Axilla 328 + + 77. Tuberculous Cervical Gland with Abscess formation 331 + + 78. Mass of Tuberculous Glands removed from Axilla 333 + + 79. Tuberculous Axillary Glands 335 + + 80. Chronic Hodgkin's Disease in boy aet. 11 337 + + 81. Lymphadenoma in a woman aet. 44 338 + + 82. Lympho Sarcoma removed from Groin 339 + + 83. Cancerous Glands in Neck, secondary to Epithelioma of Lip 341 + + 84. Stump Neuromas of Sciatic Nerve 345 + + 85. Stump Neuromas, showing changes at ends of divided Nerves 354 + + 86. Diffuse Enlargement of Nerves in generalised 356 + Neuro-Fibromatosis + + 87. Plexiform Neuroma of small Sciatic Nerve 357 + + 88. Multiple Neuro-Fibromas of Skin (Molluscum fibrosum) 358 + + 89. Elephantiasis Neuromatosa in a woman aet. 28 359 + + 90. Drop-Wrist following Fracture of Shaft of Humerus 365 + + 91. To illustrate the Loss of Sensation produced by Division 367 + of the Median Nerve + + 92. To illustrate Loss of Sensation produced by Complete 368 + Division of Ulnar Nerve + + 93. Callosities and Corns on Sole of Foot 377 + + 94. Ulcerated Chilblains on Fingers 378 + + 95. Carbuncle on Back of Neck 381 + + 96. Tuberculous Elephantiasis 383 + + 97. Elephantiasis in a woman aet. 45 387 + + 98. Elephantiasis of Penis and Scrotum 388 + + 99. Multiple Sebaceous Cysts or Wens 390 + + 100. Sebaceous Horn growing from Auricle 392 + + 101. Paraffin Epithelioma 394 + + 102. Rodent Cancer of Inner Canthus 395 + + 103. Rodent Cancer with destruction of contents of Orbit 396 + + 104. Diffuse Melanotic Cancer of Lymphatics of Skin 398 + + 105. Melanotic Cancer of Forehead with Metastasis in Lymph 399 + Glands + + 106. Recurrent Keloid 401 + + 107. Subungual Exostosis 403 + + 108. Avulsion of Tendon 410 + + 109. Volkmann's Ischaemic Contracture 414 + + 110. Ossification in Tendon of Ilio-psoas Muscle 417 + + 111. Radiogram of Calcification and Ossification in Biceps and 418 + Triceps + + 112. Ossification in Muscles of Trunk in generalised Ossifying 419 + Myositis + + 113. Hydrops of Prepatellar Bursa 427 + + 114. Section through Gouty Bursa 428 + + 115. Tuberculous Disease of Sub-Deltoid Bursa 429 + + 116. Great Enlargement of the Ischial Bursa 431 + + 117. Gouty Disease of Bursae 432 + + 118. Shaft of the Femur after Acute Osteomyelitis 444 + + 119. Femur and Tibia showing results of Acute Osteomyelitis 445 + + 120. Segment of Tibia resected for Brodie's Abscess 449 + + 121. Radiogram of Brodie's Abscess in Lower End of Tibia 451 + + 122. Sequestrum of Femur after Amputation 453 + + 123. New Periosteal Bone on Surface of Femur from Amputation 454 + Stump + + 124. Tuberculous Osteomyelitis of Os Magnum 456 + + 125. Tuberculous Disease of Tibia 457 + + 126. Diffuse Tuberculous Osteomyelitis of Right Tibia 458 + + 127. Advanced Tuberculous Disease in Region of Ankle 459 + + 128. Tuberculous Dactylitis 460 + + 129. Shortening of Middle Finger of Adult, the result of 461 + Tuberculous Dactylitis in Childhood + + 130. Syphilitic Disease of Skull 463 + + 131. Syphilitic Hyperostosis and Sclerosis of Tibia 464 + + 132. Sabre-blade Deformity of Tibia 467 + + 133. Skeleton of Rickety Dwarf 470 + + 134. Changes in the Skull resulting from Ostitis Deformans 474 + + 135. Cadaver, illustrating the alterations in the Lower Limbs 475 + resulting from Ostitis Deformans + + 136. Osteomyelitis Fibrosa affecting Femora 476 + + 137. Radiogram of Upper End of Femur in Osteomyelitis Fibrosa 478 + + 138. Radiogram of Right Knee showing Multiple Exostoses 482 + + 139. Multiple Exostoses of Limbs 483 + + 140. Multiple Cartilaginous Exostoses 484 + + 141. Multiple Cartilaginous Exostoses 486 + + 142. Multiple Chondromas of Phalanges and Metacarpals 488 + + 143. Skiagram of Multiple Chondromas 489 + + 144. Multiple Chondromas in Hand 490 + + 145. Radiogram of Myeloma of Humerus 492 + + 146. Periosteal Sarcoma of Femur 493 + + 147. Periosteal Sarcoma of Humerus 493 + + 148. Chondro-Sarcoma of Scapula 494 + + 149. Central Sarcoma of Femur invading Knee Joint 495 + + 150. Osseous Shell of Osteo-Sarcoma of Femur 495 + + 151. Radiogram of Osteo-Sarcoma of Femur 496 + + 152. Radiogram of Chondro-Sarcoma of Humerus 497 + + 153. Epitheliomatus Ulcer of Leg invading Tibia 499 + + 154. Osseous Ankylosis of Femur and Tibia 503 + + 155. Osseous Ankylosis of Knee 504 + + 156. Caseating focus in Upper End of Fibula 513 + + 157. Arthritis Deformans of Elbow 525 + + 158. Arthritis Deformans of Knee 526 + + 159. Hypertrophied Fringes of Synovial Membrane of Knee 527 + + 160. Arthritis Deformans of Hands 529 + + 161. Arthritis Deformans of several Joints 530 + + 162. Bones of Knee in Charcot's Disease 533 + + 163. Charcot's Disease of Left Knee 534 + + 164. Charcot's Disease of both Ankles: front view 535 + + 165. Charcot's Disease of both Ankles: back view 536 + + 166. Radiogram of Multiple Loose Bodies in Knee-joint 540 + + 167. Loose Body from Knee-joint 541 + + 168. Multiple partially ossified Chondromas of Synovial 542 + Membrane from Shoulder-joint + + 169. Multiple Cartilaginous Loose Bodies from Knee-joint 543 + + + + +MANUAL OF SURGERY + + + + +CHAPTER I + +REPAIR + + +Introduction--Process of repair--Healing by primary union--Granulation + tissue--Cicatricial tissue--Modifications of process of + repair--Repair in individual tissues--Transplantation or grafting + of tissues--Conditions--Sources of grafts--Grafting of individual + tissues--Methods. + + +INTRODUCTION + +To prolong human life and to alleviate suffering are the ultimate +objects of scientific medicine. The two great branches of the healing +art--Medicine and Surgery--are so intimately related that it is +impossible to draw a hard-and-fast line between them, but for +convenience Surgery may be defined as "the art of treating lesions and +malformations of the human body by manual operations, mediate and +immediate." To apply his art intelligently and successfully, it is +essential that the surgeon should be conversant not only with the normal +anatomy and physiology of the body and with the various pathological +conditions to which it is liable, but also with the nature of the +process by which repair of injured or diseased tissues is effected. +Without this knowledge he is unable to recognise such deviations from +the normal as result from mal-development, injury, or disease, or +rationally to direct his efforts towards the correction or removal of +these. + + +PROCESS OF REPAIR + +The process of repair in living tissue depends upon an inherent power +possessed by vital cells of reacting to the irritation caused by injury +or disease. The cells of the damaged tissues, under the influence of +this irritation, undergo certain proliferative changes, which are +designed to restore the normal structure and configuration of the part. +The process by which this restoration is effected is essentially the +same in all tissues, but the extent to which different tissues can carry +the recuperative process varies. Simple structures, such as skin, +cartilage, bone, periosteum, and tendon, for example, have a high power +of regeneration, and in them the reparative process may result in almost +perfect restitution to the normal. More complex structures, on the other +hand, such as secreting glands, muscle, and the tissues of the central +nervous system, are but imperfectly restored, simple cicatricial +connective tissue taking the place of what has been lost or destroyed. +Any given tissue can be replaced only by tissue of a similar kind, and +in a damaged part each element takes its share in the reparative process +by producing new material which approximates more or less closely to the +normal according to the recuperative capacity of the particular tissue. +The normal process of repair may be interfered with by various +extraneous agencies, the most important of which are infection by +disease-producing micro-organisms, the presence of foreign substances, +undue movement of the affected part, and improper applications and +dressings. The effect of these agencies is to delay repair or to prevent +the individual tissues carrying the process to the furthest degree of +which they are capable. + +In the management of wounds and other diseased conditions the main +object of the surgeon is to promote the natural reparative process by +preventing or eliminating any factor by which it may be disturbed. + +#Healing by Primary Union.#--The most favourable conditions for the +progress of the reparative process are to be found in a clean-cut wound +of the integument, which is uncomplicated by loss of tissue, by the +presence of foreign substances, or by infection with disease-producing +micro-organisms, and its edges are in contact. Such a wound in virtue of +the absence of infection is said to be _aseptic_, and under these +conditions healing takes place by what is called "primary union"--the +"healing by first intention" of the older writers. + +#Granulation Tissue.#--The essential and invariable medium of repair in +all structures is an elementary form of new tissue known as _granulation +tissue_, which is produced in the damaged area in response to the +irritation caused by injury or disease. The vital reaction induced by +such irritation results in dilatation of the vessels of the part, +emigration of leucocytes, transudation of lymph, and certain +proliferative changes in the fixed tissue cells. These changes are +common to the processes of inflammation and repair; no hard-and-fast +line can be drawn between these processes, and the two may go on +together. It is, however, only when the proliferative changes have come +to predominate that the reparative process is effectively established by +the production of healthy granulation tissue. + +_Formation of Granulation Tissue._--When a wound is made in the +integument under aseptic conditions, the passage of the knife through +the tissues is immediately followed by an oozing of blood, which soon +coagulates on the cut surfaces. In each of the divided vessels a clot +forms, and extends as far as the nearest collateral branch; and on the +surface of the wound there is a microscopic layer of bruised and +devitalised tissue. If the wound is closed, the narrow space between its +edges is occupied by blood-clot, which consists of red and white +corpuscles mixed with a quantity of fibrin, and this forms a temporary +uniting medium between the divided surfaces. During the first twelve +hours, the minute vessels in the vicinity of the wound dilate, and from +them lymph exudes and leucocytes migrate into the tissues. In from +twenty-four to thirty-six hours, the capillaries of the part adjacent to +the wound begin to throw out minute buds and fine processes, which +bridge the gap and form a firmer, but still temporary, connection +between the two sides. Each bud begins in the wall of the capillary as a +small accumulation of granular protoplasm, which gradually elongates +into a filament containing a nucleus. This filament either joins with a +neighbouring capillary or with a similar filament, and in time these +become hollow and are filled with blood from the vessels that gave them +origin. In this way a series of young _capillary loops_ is formed. + +The spaces between these loops are filled by cells of various kinds, the +most important being the _fibroblasts_, which are destined to form +cicatricial fibrous tissue. These fibroblasts are large irregular +nucleated cells derived mainly from the proliferation of the fixed +connective-tissue cells of the part, and to a less extent from the +lymphocytes and other mononuclear cells which have migrated from the +vessels. Among the fibroblasts, larger multi-nucleated cells--_giant +cells_--are sometimes found, particularly when resistant substances, +such as silk ligatures or fragments of bone, are embedded in the +tissues, and their function seems to be to soften such substances +preliminary to their being removed by the phagocytes. Numerous +_polymorpho-nuclear leucocytes_, which have wandered from the vessels, +are also present in the spaces. These act as phagocytes, their function +being to remove the red corpuscles and fibrin of the original clot, and +this performed, they either pass back into the circulation in virtue of +their amoeboid movement, or are themselves eaten up by the growing +fibroblasts. Beyond this phagocytic action, they do not appear to play +any direct part in the reparative process. These young capillary loops, +with their supporting cells and fluids, constitute granulation tissue, +which is usually fully formed in from three to five days, after which it +begins to be replaced by cicatricial or scar tissue. + +_Formation of Cicatricial Tissue._--The transformation of this temporary +granulation tissue into scar tissue is effected by the fibroblasts, +which become elongated and spindle-shaped, and produce in and around +them a fine fibrillated material which gradually increases in quantity +till it replaces the cell protoplasm. In this way white fibrous tissue +is formed, the cells of which are arranged in parallel lines and +eventually become grouped in bundles, constituting fully formed white +fibrous tissue. In its growth it gradually obliterates the capillaries, +until at the end of two, three, or four weeks both vessels and cells +have almost entirely disappeared, and the original wound is occupied by +cicatricial tissue. In course of time this tissue becomes consolidated, +and the cicatrix undergoes a certain amount of contraction--_cicatricial +contraction_. + +_Healing of Epidermis._--While these changes are taking place in the +deeper parts of the wound, the surface is being covered over by +_epidermis_ growing in from the margins. Within twelve hours the cells +of the rete Malpighii close to the cut edge begin to sprout on to the +surface of the wound, and by their proliferation gradually cover the +granulations with a thin pink pellicle. As the epithelium increases in +thickness it assumes a bluish hue and eventually the cells become +cornified and the epithelium assumes a greyish-white colour. + +_Clinical Aspects._--So long as the process of repair is not complicated +by infection with micro-organisms, there is no interference with the +general health of the patient. The temperature remains normal; the +circulatory, gastro-intestinal, nervous, and other functions are +undisturbed; locally, the part is cool, of natural colour and free from +pain. + +#Modifications of the Process of Repair.#--The process of repair by +primary union, above described, is to be looked upon as the type of all +reparative processes, such modifications as are met with depending +merely upon incidental differences in the conditions present, such as +loss of tissue, infection by micro-organisms, etc. + +_Repair after Loss or Destruction of Tissue._--When the edges of a wound +cannot be approximated either because tissue has been lost, for example +in excising a tumour or because a drainage tube or gauze packing has +been necessary, a greater amount of granulation tissue is required to +fill the gap, but the process is essentially the same as in the ideal +method of repair. + +The raw surface is first covered by a layer of coagulated blood and +fibrin. An extensive new formation of capillary loops and fibroblasts +takes place towards the free surface, and goes on until the gap is +filled by a fine velvet-like mass of granulation tissue. This +granulation tissue is gradually replaced by young cicatricial tissue, +and the surface is covered by the ingrowth of epithelium from the edges. + +This modification of the reparative process can be best studied +clinically in a recent wound which has been packed with gauze. When the +plug is introduced, the walls of the cavity consist of raw tissue with +numerous oozing blood vessels. On removing the packing on the fifth or +sixth day, the surface is found to be covered with minute, red, +papillary granulations, which are beginning to fill up the cavity. At +the edges the epithelium has proliferated and is covering over the newly +formed granulation tissue. As lymph and leucocytes escape from the +exposed surface there is a certain amount of serous or sero-purulent +discharge. On examining the wound at intervals of a few days, it is +found that the granulation tissue gradually increases in amount till the +gap is completely filled up, and that coincidently the epithelium +spreads in and covers over its surface. In course of time the epithelium +thickens, and as the granulation tissue is slowly replaced by young +cicatricial tissue, which has a peculiar tendency to contract and so to +obliterate the blood vessels in it, the scar that is left becomes +smooth, pale, and depressed. This method of healing is sometimes spoken +of as "healing by granulation"--although, as we have seen, it is by +granulation that all repair takes place. + +_Healing by Union of two Granulating Surfaces._--In gaping wounds union +is sometimes obtained by bringing the two surfaces into apposition after +each has become covered with healthy granulations. The exudate on the +surfaces causes them to adhere, capillary loops pass from one to the +other, and their final fusion takes place by the further development of +granulation and cicatricial tissue. + +_Reunion of Parts entirely Separated from the Body._--Small portions of +tissue, such as the end of a finger, the tip of the nose or a portion of +the external ear, accidentally separated from the body, if accurately +replaced and fixed in position, occasionally adhere by primary union. + +In the course of operations also, portions of skin, fascia, or bone, or +even a complete joint may be transplanted, and unite by primary union. + +_Healing under a Scab._--When a small superficial wound is exposed to +the air, the blood and serum exuded on its surface may dry and form a +hard crust or _scab_, which serves to protect the surface from external +irritation in the same way as would a dry pad of sterilised gauze. Under +this scab the formation of granulation tissue, its transformation into +cicatricial tissue, and the growth of epithelium on the surface, go on +until in the course of time the crust separates, leaving a scar. + +_Healing by Blood-clot._--In subcutaneous wounds, for example tenotomy, +in amputation wounds, and in wounds made in excising tumours or in +operating upon bones, the space left between the divided tissues becomes +filled with blood-clot, which acts as a temporary scaffolding in which +granulation tissue is built up. Capillary loops grow into the coagulum, +and migrated leucocytes from the adjacent blood vessels destroy the red +corpuscles, and are in turn disposed of by the developing fibroblasts, +which by their growth and proliferation fill up the gap with young +connective tissue. It will be evident that this process only differs +from healing by primary union in the _amount_ of blood-clot that is +present. + +_Presence of a Foreign Body._--When an aseptic foreign body is present +in the tissues, _e.g._ a piece of unabsorbable chromicised catgut, the +healing process may be modified. After primary union has taken place the +scar may broaden, become raised above the surface, and assume a +bluish-brown colour; the epidermis gradually thins and gives way, +revealing the softened portion of catgut, which can be pulled out in +pieces, after which the wound rapidly heals and resumes a normal +appearance. + + +REPAIR IN INDIVIDUAL TISSUES + +_Skin and Connective Tissue._--The mode of regeneration of these tissues +under aseptic conditions has already been described as the type of ideal +repair. In highly vascular parts, such as the face, the reparative +process goes on with great rapidity, and even extensive wounds may be +firmly united in from three to five days. Where the anastomosis is less +free the process is more prolonged. The more highly organised elements +of the skin, such as the hair follicles, the sweat and sebaceous glands, +are imperfectly reproduced; hence the scar remains smooth, dry, and +hairless. + +_Epithelium._--Epithelium is only reproduced from pre-existing +epithelium, and, as a rule, from one of a similar type, although +metaplastic transformation of cells of one kind of epithelium into +another kind can take place. Thus a granulating surface may be covered +entirely by the ingrowing of the cutaneous epithelium from the margins; +or islets, originating in surviving cells of sebaceous glands or sweat +glands, or of hair follicles, may spring up in the centre of the raw +area. Such islets may also be due to the accidental transference of +loose epithelial cells from the edges. Even the fluid from a blister, in +virtue of the isolated cells of the rete Malpighii which it contains, is +capable of starting epithelial growth on a granulating surface. Hairs +and nails may be completely regenerated if a sufficient amount of the +hair follicles or of the nail matrix has escaped destruction. The +epithelium of a mucous membrane is regenerated in the same way as that +on a cutaneous surface. + +Epithelial cells have the power of living for some time after being +separated from their normal surroundings, and of growing again when once +more placed in favourable circumstances. On this fact the practice of +skin grafting is based (p. 11). + +_Cartilage._--When an articular cartilage is divided by incision or by +being implicated in a fracture involving the articular end of a bone, it +is repaired by ordinary cicatricial fibrous tissue derived from the +proliferating cells of the perichondrium. Cartilage being a non-vascular +tissue, the reparative process goes on slowly, and it may be many weeks +before it is complete. + +It is possible for a metaplastic transformation of connective-tissue +cells into cartilage cells to take place, the characteristic hyaline +matrix being secreted by the new cells. This is sometimes observed as an +intermediary stage in the healing of fractures, especially in young +bones. It may also take place in the regeneration of lost portions of +cartilage, provided the new tissue is so situated as to constitute part +of a joint and to be subjected to pressure by an opposing cartilaginous +surface. This is illustrated by what takes place after excision of +joints where it is desired to restore the function of the articulation. +By carrying out movements between the constituent parts, the fibrous +tissue covering the ends of the bones becomes moulded into shape, its +cells take on the characters of cartilage cells, and, forming a matrix, +so develop a new cartilage. + +Conversely, it is observed that when articular cartilage is no longer +subjected to pressure by an opposing cartilage, it tends to be +transformed into fibrous tissue, as may be seen in deformities attended +with displacement of articular surfaces, such as hallux valgus and +club-foot. + +After fractures of costal cartilage or of the cartilages of the larynx +the cicatricial tissue may be ultimately replaced by bone. + +_Tendons._--When a tendon is divided, for example by subcutaneous +tenotomy, the end nearer the muscle fibres is drawn away from the other, +leaving a gap which is speedily filled by blood-clot. In the course of a +few days this clot becomes permeated by granulation tissue, the +fibroblasts of which are derived from the sheath of the tendon, the +surrounding connective tissue, and probably also from the divided ends +of the tendon itself. These fibroblasts ultimately develop into typical +tendon cells, and the fibres which they form constitute the new tendon +fibres. Under aseptic conditions repair is complete in from two to three +weeks. In the course of the reparative process the tendon and its sheath +may become adherent, which leads to impaired movement and stiffness. If +the ends of an accidentally divided tendon are at once brought into +accurate apposition and secured by sutures, they unite directly with a +minimum amount of scar tissue, and function is perfectly restored. + +_Muscle._--Unstriped muscle does not seem to be capable of being +regenerated to any but a moderate degree. If the ends of a divided +striped muscle are at once brought into apposition by stitches, primary +union takes place with a minimum of intervening fibrous tissue. The +nuclei of the muscle fibres in close proximity to this young cicatricial +tissue proliferate, and a few new muscle fibres may be developed, but +any gross loss of muscular tissue is replaced by a fibrous cicatrix. It +would appear that portions of muscle transplanted from animals to fill +up gaps in human muscle are similarly replaced by fibrous tissue. When a +muscle is paralysed from loss of its nerve supply and undergoes complete +degeneration, it is not capable of being regenerated, even should the +integrity of the nerve be restored, and so its function is permanently +lost. + +_Secretory Glands._--The regeneration of secretory glands is usually +incomplete, cicatricial tissue taking the place of the glandular +substance which has been destroyed. In wounds of the liver, for example, +the gap is filled by fibrous tissue, but towards the periphery of the + +wound the liver cells proliferate and a certain amount of regeneration +takes place. In the kidney also, repair mainly takes place by +cicatricial tissue, and although a few collecting tubules may be +reformed, no regeneration of secreting tissue takes place. After the +operation of decapsulation of the kidney a new capsule is formed, and +during the process young blood vessels permeate the superficial parts +of the kidney and temporarily increase its blood supply, but in the +consolidation of the new fibrous tissue these vessels are ultimately +obliterated. This does not prove that the operation is useless, as the +temporary improvement of the circulation in the kidney may serve to tide +the patient over a critical period of renal insufficiency. + +_Stomach and Intestine._--Provided the peritoneal surfaces are +accurately apposed, wounds of the stomach and intestine heal with great +rapidity. Within a few hours the peritoneal surfaces are glued together +by a thin layer of fibrin and leucocytes, which is speedily organised +and replaced by fibrous tissue. Fibrous tissue takes the place of the +muscular elements, which are not regenerated. The mucous lining is +restored by ingrowth from the margins, and there is evidence that some +of the secreting glands may be reproduced. + +Hollow viscera, like the oesophagus and urinary bladder, in so far +as they are not covered by peritoneum, heal less rapidly. + +_Nerve Tissues._--There is no trustworthy evidence that regeneration of +the tissues of the brain or spinal cord in man ever takes place. Any +loss of substance is replaced by cicatricial tissue. + +The repair of _Bone_, _Blood Vessels_, and _Peripheral Nerves_ is more +conveniently considered in the chapters dealing with these structures. + +#Rate of Healing.#--While the rate at which wounds heal is remarkably +constant there are certain factors that influence it in one direction or +the other. Healing is more rapid when the edges are in contact, when +there is a minimum amount of blood-clot between them, when the patient +is in normal health and the vitality of the tissues has not been +impaired. Wounds heal slightly more quickly in the young than in the +old, although the difference is so small that it can only be +demonstrated by the most careful observations. + +Certain tissues take longer to heal than others: for example, a fracture +of one of the larger long bones takes about six weeks to unite, and +divided nerve trunks take much longer--about a year. + +Wounds of certain parts of the body heal more quickly than others: those +of the scalp, face, and neck, for example, heal more quickly than those +over the buttock or sacrum, probably because of their greater +vascularity. + +The extent of the wound influences the rate of healing; it is only + +natural that a long and deep wound should take longer to heal than a +short and superficial one, because there is so much more work to be +done in the conversion of blood-clot into granulation tissue, and this +again into scar tissue that will be strong enough to stand the strain on +the edges of the wound. + + +THE TRANSPLANTATION OR GRAFTING OF TISSUES + +Conditions are not infrequently met with in which healing is promoted +and restoration of function made possible by the transference of a +portion of tissue from one part of the body to another; the tissue +transferred is known as the _graft_ or the _transplant_. The simplest +example of grafting is the transplantation of skin. + +In order that the graft may survive and have a favourable chance of +"taking," as it is called, the transplanted tissue must retain its +vitality until it has formed an organic connection with the tissue in +which it is placed, so that it may derive the necessary nourishment from +its new bed. When these conditions are fulfilled the tissues of the +graft continue to proliferate, producing new tissue elements to replace +those that are lost and making it possible for the graft to become +incorporated with the tissue with which it is in contact. + +Dead tissue, on the other hand, can do neither of these things; it is +only capable of acting as a model, or, at the most, as a scaffolding for +such mobile tissue elements as may be derived from, the parent tissue +with which the graft is in contact: a portion of sterilised marine +sponge, for example, may be observed to become permeated with +granulation tissue when it is embedded in the tissues. + +A successful graft of living tissue is not only capable of regeneration, +but it acquires a system of lymph and blood vessels, so that in time it +bleeds when cut into, and is permeated by new nerve fibres spreading in +from the periphery towards the centre. + +It is instructive to associate the period of survival of the different +tissues of the body after death, with their capacity of being used for +grafting purposes; the higher tissues such as those of the central +nervous system and highly specialised glandular tissues like those of +the kidney lose their vitality quickly after death and are therefore +useless for grafting; connective tissues, on the other hand, such as +fat, cartilage, and bone retain their vitality for several hours after +death, so that when they are transplanted, they readily "take" and do +all that is required of them: the same is true of the skin and its +appendages. + +_Sources of Grafts._--It is convenient to differentiate between +_autoplastic_ grafts, that is those derived from the same individual; +_homoplastic_ grafts, derived from another animal of the same species; +and _heteroplastic_ grafts, derived from an animal of another species. +Other conditions being equal, the prospects of success are greatest with +autoplastic grafts, and these are therefore preferred whenever possible. + +There are certain details making for success that merit attention: the +graft must not be roughly handled or allowed to dry, or be subjected to +chemical irritation; it must be brought into accurate contact with the +new soil, no blood-clot intervening between the two, no movement of the +one upon the other should be possible and all infection must be +excluded; it will be observed that these are exactly the same conditions +that permit of the primary healing of wounds, with which of course the +healing of grafts is exactly comparable. + +_Preservation of Tissues for Grafting._--It was at one time believed +that tissues might be taken from the operating theatre and kept in cold +storage until they were required. It is now agreed that tissues which +have been separated from the body for some time inevitably lose their +vitality, become incapable of regeneration, and are therefore unsuited +for grafting purposes. If it is intended to preserve a portion of tissue +for future grafting, it should be embedded in the subcutaneous tissue of +the abdominal wall until it is wanted; this has been carried out with +portions of costal cartilage and of bone. + + +INDIVIDUAL TISSUES AS GRAFTS + +#The Blood# lends itself in an ideal manner to transplantation, or, as +it has long been called, _transfusion_. Being always a homoplastic +transfer, the new blood is not always tolerated by the old, in which +case biochemical changes occur, resulting in haemolysis, which +corresponds to the disintegration of other unsuccessful homoplastic +grafts. (See article on Transfusion, _Op. Surg._, p. 37.) + +#The Skin.#--The skin was the first tissue to be used for grafting +purposes, and it is still employed with greater frequency than any +other, as lesions causing defects of skin are extremely common and +without the aid of grafts are tedious in healing. + +Skin grafts may be applied to a raw surface or to one that is covered +with granulations. + +_Skin grafting of raw surfaces_ is commonly indicated after operations +for malignant disease in which considerable areas of skin must be +sacrificed, and after accidents, such as avulsion of the scalp by +machinery. + +_Skin grafting of granulating surfaces_ is chiefly employed to promote +healing in the large defects of skin caused by severe burns; the +grafting is carried out when the surface is covered by a uniform layer +of healthy granulations and before the inevitable contraction of scar +tissue makes itself manifest. Before applying the grafts it is usual to +scrape away the granulations until the young fibrous tissue underneath +is exposed, but, if the granulations are healthy and can be rendered +aseptic, the grafts may be placed on them directly. + +If it is decided to scrape away the granulations, the oozing must be +arrested by pressure with a pad of gauze, a sheet of dental rubber or +green protective is placed next the raw surface to prevent the gauze +adhering and starting the bleeding afresh when it is removed. + +#Methods of Skin-Grafting.#--Two methods are employed: one in which the +epidermis is mainly or exclusively employed--epidermis or epithelial +grafting; the other, in which the graft consists of the whole thickness +of the true skin--cutis-grafting. + +_Epidermis or Epithelial Grafting._--The method introduced by the late +Professor Thiersch of Leipsic is that almost universally practised. It +consists in transplanting strips of epidermis shaved from the surface of +the skin, the razor passing through the tips of the papillae, which +appear as tiny red points yielding a moderate ooze of blood. + +The strips are obtained from the front and lateral aspects of the thigh +or upper arm, the skin in those regions being pliable and comparatively +free from hairs. + +They are cut with a sharp hollow-ground razor or with Thiersch's +grafting knife, the blade of which is rinsed in alcohol and kept +moistened with warm saline solution. The cutting is made easier if the +skin is well stretched and kept flat and perfectly steady, the +operator's left hand exerting traction on the skin behind, the hands of +the assistant on the skin in front, one above and the other below the +seat of operation. To ensure uniform strips being cut, the razor is kept +parallel with the surface and used with a short, rapid, sawing movement, +so that, with a little practice, grafts six or eight inches long by one +or two inches broad can readily be cut. The patient is given a general +anaesthetic, or regional anaesthesia is obtained by injections of a +solution of one per cent. novocain into the line of the lateral and +middle cutaneous nerves; the disinfection of the skin is carried out on +the usual lines, any chemical agent being finally got rid of, however, +by means of alcohol followed by saline solution. + +The strips of epidermis wrinkle up on the knife and are directly +transferred to the surface, for which they should be made to form a +complete carpet, slightly overlapping the edges of the area and of one +another; some blunt instrument is used to straighten out the strips, +which are then subjected to firm pressure with a pad of gauze to express +blood and air-bells and to ensure accurate contact, for this must be as +close as that between a postage stamp and the paper to which it is +affixed. + +As a dressing for the grafted area and of that also from which the +grafts have been taken, gauze soaked in _liquid paraffin_--the patent +variety known as _ambrine_ is excellent--appears to be the best; the +gauze should be moistened every other day or so with fresh paraffin, so +that, at the end of a week, when the grafts should have united, the +gauze can be removed without risk of detaching them. _Dental wax_ is +another useful type of dressing; as is also _picric acid_ solution. Over +the gauze, there is applied a thick layer of cotton wool, and the whole +dressing is kept in place by a firmly applied bandage, and in the case +of the limbs some form of splint should be added to prevent movement. + +A dressing may be dispensed with altogether, the grafts being protected +by a wire cage such as is used after vaccination, but they tend to dry +up and come to resemble a scab. + +When the grafts have healed, it is well to protect them from injury and +to prevent them drying up and cracking by the liberal application of +lanoline or vaseline. + +The new skin is at first insensitive and is fixed to the underlying +connective tissue or bone, but in course of time (from six weeks +onwards) sensation returns and the formation of elastic tissue beneath +renders the skin pliant and movable so that it can be pinched up between +the finger and thumb. + +_Reverdin's_ method consists in planting out pieces of skin not bigger +than a pin-head over a granulating surface. It is seldom employed. + +_Grafts of the Cutis Vera._--Grafts consisting of the entire thickness +of the true skin were specially advocated by Wolff and are often +associated with his name. They should be cut oval or spindle-shaped, to +facilitate the approximation of the edges of the resulting wound. The +graft should be cut to the exact size of the surface it is to cover; +Gillies believes that tension of the graft favours its taking. These +grafts may be placed either on a fresh raw surface or on healthy +granulations. It is sometimes an advantage to stitch them in position, +especially on the face. The dressing and the after-treatment are the +same as in epidermis grafting. + +There is a degree of uncertainty about the graft retaining its vitality +long enough to permit of its deriving the necessary nourishment from its +new surroundings; in a certain number of cases the flap dies and is +thrown off as a slough--moist or dry according to the presence or +absence of septic infection. + +The technique for cutis-grafting must be without a flaw, and the asepsis +absolute; there must not only be a complete absence of movement, but +there must be no traction on the flap that will endanger its blood +supply. + +Owing to the uncertainty in the results of cutis-grafting the +_two-stage_ or _indirect method_ has been introduced, and its almost +uniform success has led to its sphere of application being widely +extended. The flap is raised as in the direct method but is left +attached at one of its margins for a period ranging from 14 to 21 days +until its blood supply from its new bed is assured; the detachment is +then made complete. The blood supply of the proposed flap may influence +its selection and the way in which it is fashioned; for example, a flap +cut from the side of the head to fill a defect in the cheek, having in +its margin of attachment or pedicle the superficial temporal artery, is +more likely to take than a flap cut with its base above. + +Another modification is to raise the flap but leave it connected at both +ends like the piers of a bridge; this method is well suited to defects +of skin on the dorsum of the fingers, hand and forearm, the bridge of +skin is raised from the abdominal wall and the hand is passed beneath it +and securely fixed in position; after an interval of 14 to 21 days, when +the flap is assured of its blood supply, the piers of the bridge are +divided (Fig. 1). With undermining it is usually easy to bring the +edges of the gap in the abdominal wall together, even in children; the +skin flap on the dorsum of the hand appears rather thick and +prominent--almost like the pad of a boxing-glove--for some time, but +the restoration of function in the capacity to flex the fingers is +gratifying in the extreme. + +[Illustration: FIG. 1.--Ulcer of back of Hand covered by flap of skin +raised from anterior abdominal wall. The lateral edges of the flap are +divided after the graft has adhered.] + +The indirect element of this method of skin-grafting may be carried +still further by transferring the flap of skin first to one part of the +body and then, after it has taken, transferring it to a third part. +Gillies has especially developed this method in the remedying of +deformities of the face caused by gunshot wounds and by petrol burns in +air-men. A rectangular flap of skin is marked out in the neck and chest, +the lateral margins of the flap are raised sufficiently to enable them +to be brought together so as to form a tube of skin: after the +circulation has been restored, the lower end of the tube is detached and +is brought up to the lip or cheek, or eyelid, where it is wanted; when +this end has derived its new blood supply, the other end is detached +from the neck and brought up to where it is wanted. In this way, skin +from the chest may be brought up to form a new forehead and eyelids. + +Grafts of _mucous membrane_ are used to cover defects in the lip, cheek, +and conjunctiva. The technique is similar to that employed in +skin-grafting; the sources of mucous membrane are limited and the +element of septic infection cannot always be excluded. + +_Fat._--Adipose tissue has a low vitality, but it is easily retained and +it readily lends itself to transplantation. Portions of fat are often +obtainable at operations--from the omentum, for example, otherwise the +subcutaneous fat of the buttock is the most accessible; it may be +employed to fill up cavities of all kinds in order to obtain more rapid +and sounder healing and also to remedy deformity, as in filling up a +depression in the cheek or forehead. It is ultimately converted into +ordinary connective tissue _pari passu_ with the absorption of the fat. + +The _fascia lata of the thigh_ is widely and successfully used as a +graft to fill defects in the dura mater, and interposed between the +bones of a joint--if the articular cartilage has been destroyed--to +prevent the occurrence of ankylosis. + +The _peritoneum_ of hydrocele and hernial sacs and of the omentum +readily lends itself to transplantation. + +_Cartilage and bone_, next to skin, are the tissues most frequently +employed for grafting purposes; their sphere of action is so extensive +and includes so much of technical detail in their employment, that they +will be considered later with the surgery of the bones and joints and +with the methods of re-forming the nose. + +_Tendons and blood vessels_ readily lend themselves to transplantation +and will also be referred to later. + +_Muscle and nerve_, on the other hand, do not retain their vitality when +severed from their surroundings and do not functionate as grafts except +for their connective-tissue elements, which it goes without saying are +more readily obtainable from other sources. + +Portions of the _ovary_ and of the _thyreoid_ have been successfully +transplanted into the subcutaneous cellular tissue of the abdominal wall +by Tuffier and others. In these new surroundings, the ovary or thyreoid +is vascularised and has been shown to functionate, but there is not +sufficient regeneration of the essential tissue elements to "carry on"; +the secreting tissue is gradually replaced by connective tissue and the +special function comes to an end. Even such temporary function may, +however, tide a patient over a difficult period. + + + + +CHAPTER II + +CONDITIONS WHICH INTERFERE WITH REPAIR + + +SURGICAL BACTERIOLOGY + +Want of rest--Irritation--Unhealthy tissues--Pathogenic bacteria. + SURGICAL BACTERIOLOGY--General characters of + bacteria--Classification of bacteria--Conditions of bacterial + life--Pathogenic powers of bacteria--Results of bacterial + growth--Death of bacteria--Immunity--Antitoxic sera--Identification + of bacteria--Pyogenic bacteria. + +In the management of wounds and other surgical conditions it is +necessary to eliminate various extraneous influences which tend to delay +or arrest the natural process of repair. + +Of these, one of the most important is undue movement of the affected +part. "The first and great requisite for the restoration of injured +parts is _rest_," said John Hunter; and physiological and mechanical +rest as the chief of natural therapeutic agents was the theme of John +Hilton's classical work--_Rest and Pain_. In this connection it must be +understood that "rest" implies more than the mere state of physical +repose: all physiological as well as mechanical function must be +prevented as far as is possible. For instance, the constituent bones of +a joint affected with tuberculosis must be controlled by splints or +other appliances so that no movement can take place between them, and +the limb may not be used for any purpose; physiological rest may be +secured to an inflamed colon by making an artificial anus in the caecum; +the activity of a diseased kidney may be diminished by regulating the +quantity and quality of the fluids taken by the patient. + +Another source of interference with repair in wounds is _irritation_, +either by mechanical agents such as rough, unsuitable dressings, +bandages, or ill-fitting splints; or by chemical agents in the form of +strong lotions or other applications. + +An _unhealthy or devitalised condition of the patient's tissues_ also +hinders the reparative process. Bruised or lacerated skin heals less +kindly than skin cut with a smooth, sharp instrument; and persistent + +venous congestion of a part, such as occurs, for example, in the leg +when the veins are varicose, by preventing the access of healthy blood, +tends to delay the healing of open wounds. The existence of grave +constitutional disease, such as Bright's disease, diabetes, syphilis, +scurvy, or alcoholism, also impedes healing. + +Infection by disease-producing micro-organisms or _pathogenic bacteria_ +is, however, the most potent factor in disturbing the natural process of +repair in wounds. + + +SURGICAL BACTERIOLOGY + +The influence of micro-organisms in the causation of disease, and the +role played by them in interfering with the natural process of repair, +are so important that the science of applied bacteriology has now come +to dominate every department of surgery, and it is from the standpoint +of bacteriology that nearly all surgical questions have to be +considered. + +The term _sepsis_ as now used in clinical surgery no longer retains its +original meaning as synonymous with "putrefaction," but is employed to +denote all conditions in which bacterial infection has taken place, and +more particularly those in which pyogenic bacteria are present. In the +same way the term _aseptic_ conveys the idea of freedom from all forms +of bacteria, putrefactive or otherwise; and the term _antiseptic_ is +used to denote a power of counteracting bacteria and their products. + +#General Characters of Bacteria.#--A _bacterium_ consists of a finely +granular mass of protoplasm, enclosed in a thin gelatinous envelope. +Many forms are motile--some in virtue of fine thread-like flagella, and +others through contractility of the protoplasm. The great majority +multiply by simple fission, each parent cell giving rise to two daughter +cells, and this process goes on with extraordinary rapidity. Other +varieties, particularly bacilli, are propagated by the formation of +_spores_. A spore is a minute mass of protoplasm surrounded by a dense, +tough membrane, developed in the interior of the parent cell. Spores are +remarkable for their tenacity of life, and for the resistance they offer +to the action of heat and chemical germicides. + +Bacteria are most conveniently classified according to their shape. Thus +we recognise (1) those that are globular--_cocci_; (2) those that +resemble a rod--_bacilli_; (3) the spiral or wavy forms--_spirilla_. + +_Cocci_ or _micrococci_ are minute round bodies, averaging about 1 u in +diameter. The great majority are non-motile. They multiply by fission; +and when they divide in such a way that the resulting cells remain in +pairs, are called _diplococci_, of which the bacteria of gonorrhoea and +pneumonia are examples (Fig. 5). When they divide irregularly, and form +grape-like bunches, they are known as _staphylococci_, and to this + +variety the commonest pyogenic or pus-forming organisms belong (Fig. 2). +When division takes place only in one axis, so that long chains are +formed, the term _streptococcus_ is applied (Fig. 3). Streptococci are +met with in erysipelas and various other inflammatory and suppurative +processes of a spreading character. + +_Bacilli_ are rod-shaped bacteria, usually at least twice as long as +they are broad (Fig. 4). Some multiply by fission, others by +sporulation. Some forms are motile, others are non-motile. Tuberculosis, +tetanus, anthrax, and many other surgical diseases are due to different +forms of bacilli. + +_Spirilla_ are long, slender, thread-like cells, more or less spiral or +wavy. Some move by a screw-like contraction of the protoplasm, some by +flagellae. The spirochaete associated with syphilis (Fig. 36) is the most +important member of this group. + +#Conditions of Bacterial Life.#--Bacteria require for their growth and +development a suitable food-supply in the form of proteins, +carbohydrates, and salts of calcium and potassium which they break up +into simpler elements. An alkaline medium favours bacterial growth; and +moisture is a necessary condition; spores, however, can survive the want +of water for much longer periods than fully developed bacteria. The +necessity for oxygen varies in different species. Those that require +oxygen are known as _aerobic bacilli_ or _aerobes_; those that cannot +live in the presence of oxygen are spoken of as _anaerobes_. The great +majority of bacteria, however, while they prefer to have oxygen, are +able to live without it, and are called _facultative anaerobes_. + +The most suitable temperature for bacterial life is from 95 o to 102 o F., +roughly that of the human body. Extreme or prolonged cold paralyses but +does not kill micro-organisms. Few, however, survive being raised to a +temperature of 134 1/2 o F. Boiling for ten to twenty minutes will kill all +bacteria, and the great majority of spores. Steam applied in an +autoclave under a pressure of two atmospheres destroys even the most +resistant spores in a few minutes. Direct sunlight, electric light, or +even diffuse daylight, is inimical to the growth of bacteria, as are +also Rontgen rays and radium emanations. + +#Pathogenic Properties of Bacteria.#--We are now only concerned with +pathogenic bacteria--that is, bacteria capable of producing disease in +the human subject. This capacity depends upon two sets of factors--(1) +certain features peculiar to the invading bacteria, and (2) others +peculiar to the host. Many bacteria have only the power of living upon +dead matter, and are known as _saphrophytes_. Such as do nourish in +living tissue are, by distinction, known as _parasites_. The power a +given parasitic micro-organism has of multiplying in the body and giving +rise to disease is spoken of as its _virulence_, and this varies not +only with different species, but in the same species at different times +and under varying circumstances. The actual number of organisms +introduced is also an important factor in determining their pathogenic +power. Healthy tissues can resist the invasion of a certain number of +bacteria of a given species, but when that number is exceeded, the +organisms get the upper hand and disease results. When the organisms +gain access directly to the blood-stream, as a rule they produce their +effects more certainly and with greater intensity than when they are +introduced into the tissues. + +Further, the virulence of an organism is modified by the condition of +the patient into whose tissues it is introduced. So long as a person is +in good health, the tissues are able to resist the attacks of moderate +numbers of most bacteria. Any lowering of the vitality of the +individual, however, either locally or generally, at once renders him +more susceptible to infection. Thus bruised or torn tissue is much more +liable to infection with pus-producing organisms than tissues clean-cut +with a knife; also, after certain diseases, the liability to infection +by the organisms of diphtheria, pneumonia, or erysipelas is much +increased. Even such slight depression of vitality as results from +bodily fatigue, or exposure to cold and damp, may be sufficient to turn +the scale in the battle between the tissues and the bacteria. Age is an +important factor in regard to the action of certain bacteria. Young +subjects are attacked by diphtheria, tuberculosis, acute osteomyelitis, +and some other diseases with greater frequency and severity than those +of more advanced years. + +In different races, localities, environment, and seasons, the pathogenic +powers of certain organisms, such as those of erysipelas, diphtheria, +and acute osteomyelitis, vary considerably. + +There is evidence that a _mixed infection_--that is, the introduction of +more than one species of organism, for example, the tubercle bacillus +and a pyogenic staphylococcus--increases the severity of the resulting +disease. If one of the varieties gain the ascendancy, the poisons +produced by the others so devitalise the tissue cells, and diminish +their power of resistance, that the virulence of the most active +organisms is increased. On the other hand, there is reason to believe +that the products of certain organisms antagonise one another--for +example, an attack of erysipelas may effect the cure of a patch of +tuberculous lupus. + +Lastly, in patients suffering from chronic wasting diseases, bacteria +may invade the internal organs by the blood-stream in enormous numbers +and with great rapidity, during the period of extreme debility which +shortly precedes death. The discovery of such collections of organisms +on post-mortem examination may lead to erroneous conclusions being drawn +as to the cause of death. + +#Results of Bacterial Growth.#--Some organisms, such as those of tetanus +and erysipelas, and certain of the pyogenic bacteria, show little +tendency to pass far beyond the point at which they gain an entrance to +the body. Others, on the contrary--for example, the tubercle bacillus +and the organism of acute osteomyelitis--although frequently remaining +localised at the seat of inoculation, tend to pass to distant parts, +lodging in the capillaries of joints, bones, kidney, or lungs, and there +producing their deleterious effects. + +In the human subject, multiplication in the blood-stream does not occur +to any great extent. In some general acute pyogenic infections, such as +osteomyelitis, cellulitis, etc., pure cultures of staphylococci or of +streptococci may be obtained from the blood. In pneumococcal and typhoid +infections, also, the organisms may be found in the blood. + +It is by the vital changes they bring about in the parts where they +settle that micro-organisms disturb the health of the patient. In +deriving nourishment from the complex organic compounds in which they +nourish, the organisms evolve, probably by means of a ferment, certain +chemical products of unknown composition, but probably colloidal in +nature, and known as _toxins_. When these poisons are absorbed into the +general circulation they give rise to certain groups of symptoms--such +as rise of temperature, associated circulatory and respiratory +derangements, interference with the gastro-intestinal functions and also +with those of the nervous system--which go to make up the condition +known as blood-poisoning, toxaemia, or _bacterial intoxication_. In +addition to this, certain bacteria produce toxins that give rise to +definite and distinct groups of symptoms--such as the convulsions of +tetanus, or the paralyses that follow diphtheria. + +_Death of Bacteria._--Under certain circumstances, it would appear that +the accumulation of the toxic products of bacterial action tends to +interfere with the continued life and growth of the organisms +themselves, and in this way the natural cure of certain diseases is +brought about. Outside the body, bacteria may be killed by starvation, +by want of moisture, by being subjected to high temperature, or by the +action of certain chemical agents of which carbolic acid, the +perchloride and biniodide of mercury, and various chlorine preparations +are the most powerful. + +#Immunity.#--Some persons are insusceptible to infection by certain +diseases, from which they are said to enjoy a _natural immunity_. In +many acute diseases one attack protects the patient, for a time at +least, from a second attack--_acquired immunity_. + +_Phagocytosis._--In the production of immunity the leucocytes and +certain other cells play an important part in virtue of the power they +possess of ingesting bacteria and of destroying them by a process of +intra-cellular digestion. To this process Metchnikoff gave the name of +_phagocytosis_, and he recognised two forms of _phagocytes_: (1) the +_microphages_, which are the polymorpho-nuclear leucocytes of the blood; +and (2) the _macrophages_, which include the larger hyaline leucocytes, +endothelial cells, and connective-tissue corpuscles. + +During the process of phagocytosis, the polymorpho-nuclear leucocytes in +the circulating blood increase greatly in numbers (_leucocytosis_), as +well as in their phagocytic action, and in the course of destroying the +bacteria they produce certain ferments which enter the blood serum. +These are known as _opsonins_ or _alexins_, and they act on the bacteria +by a process comparable to narcotisation, and render them an easy prey +for the phagocytes. + +_Artificial or Passive Immunity._--A form of immunity can be induced by +the introduction of protective substances obtained from an animal which +has been actively immunised. The process by which passive immunity is +acquired depends upon the fact that as a result of the reaction between +the specific virus of a particular disease (the _antigen_) and the +tissues of the animal attacked, certain substances--_antibodies_--are +produced, which when transferred to the body of a susceptible animal +protect it against that disease. The most important of these antibodies +are the _antitoxins_. From the study of the processes by which immunity +is secured against the effects of bacterial action the serum and vaccine +methods of treating certain infective diseases have been evolved. The +_serum treatment_ is designed to furnish the patient with a sufficiency +of antibodies to neutralise the infection. The anti-diphtheritic and the +anti-tetanic act by neutralising the specific toxins of the +disease--_antitoxic serums_; the anti-streptcoccic and the serum for +anthrax act upon the bacteria--_anti-bacterial serums_. + +A _polyvalent_ serum, that is, one derived from an animal which has been +immunised by numerous strains of the organism derived from various +sources, is much more efficacious than when a single strain has been +used. + +_Clinical Use of Serums._--Every precaution must be taken to prevent +organismal contamination of the serum or of the apparatus by means of +which it is injected. Syringes are so made that they can be sterilised +by boiling. The best situations for injection are under the skin of the +abdomen, the thorax, or the buttock, and the skin should be purified at +the seat of puncture. If the bulk of the full dose is large, it should +be divided and injected into different parts of the body, not more than +20 c.c. being injected at one place. The serum may be introduced +directly into a vein, or into the spinal canal, _e.g._ anti-tetanic +serum. The immunity produced by injections of antitoxic sera lasts only +for a comparatively short time, seldom longer than a few weeks. + +_"Serum Disease" and Anaphylaxis._--It is to be borne in mind that some +patients exhibit a supersensitiveness with regard to protective sera, an +injection being followed in a few days by the appearance of an +urticarial or erythematous rash, pain and swelling of the joints, and a +variable degree of fever. These symptoms, to which the name _serum +disease_ is applied, usually disappear in the course of a few days. + +The term _anaphylaxis_ is applied to an allied condition of +supersensitiveness which appears to be induced by the injection of +certain substances, including toxins and sera, that are capable of +acting as antigens. When a second injection is given after an interval +of some days, if anaphylaxis has been established by the first dose, the +patient suddenly manifests toxic symptoms of the nature of profound +shock which may even prove fatal. The conditions which render a person +liable to develop anaphylaxis and the mechanism by which it is +established are as yet imperfectly understood. + +_Vaccine Treatment._--The vaccine treatment elaborated by A. E. Wright +consists in injecting, while the disease is still active, specially +prepared dead cultures of the causative organisms, and is based on the +fact that these "vaccines" render the bacteria in the tissues less able +to resist the attacks of the phagocytes. The method is most successful +when the vaccine is prepared from organisms isolated from the patient +himself, _autogenous vaccine_, but when this is impracticable, or takes +a considerable time, laboratory-prepared polyvalent _stock vaccines_ may +be used. + +_Clinical Use of Vaccines._--Vaccines should not be given while a +patient is in a negative phase, as a certain amount of the opsonin in +the blood is used up in neutralising the substances injected, and this +may reduce the opsonic index to such an extent that the vaccines +themselves become dangerous. As a rule, the propriety of using a vaccine +can be determined from the general condition of the patient. The initial +dose should always be a small one, particularly if the disease is acute, +and the subsequent dosage will be regulated by the effect produced. If +marked constitutional disturbance with rise of temperature follows the +use of a vaccine, it indicates a negative phase, and calls for a +diminution in the next dose. If, on the other hand, the local as well as +the general condition of the patient improves after the injection, it +indicates a positive phase, and the original dose may be repeated or +even increased. Vaccines are best introduced subcutaneously, a part +being selected which is not liable to pressure, as there is sometimes +considerable local reaction. Repeated doses may be necessary at +intervals of a few days. + +The vaccine treatment has been successfully employed in various +tuberculous lesions, in pyogenic infections such as acne, boils, +sycosis, streptococcal, pneumococcal, and gonococcal conditions, in +infections of the accessory air sinuses, and in other diseases caused by +bacteria. + + +PYOGENIC BACTERIA + +From the point of view of the surgeon the most important varieties of +micro-organisms are those that cause inflammation and suppuration--the +_pyogenic bacteria_. This group includes a great many species, and these +are so widely distributed that they are to be met with under all +conditions of everyday life. + +The nature of the inflammatory and suppurative processes will be +considered in detail later; suffice it here to say that they are brought +about by the action of one or other of the organisms that we have now to +consider. + +It is found that the _staphylococci_, which cluster into groups, tend to +produce localised lesions; while the chain-forms--_streptococci_--give +rise to diffuse, spreading conditions. Many varieties of pyogenic +bacteria have now been differentiated, the best known being the +staphylococcus aureus, the streptococcus, and the bacillus coli +communis. + +[Illustration: FIG. 2.--Staphylococcus aureus in Pus from case of +Osteomyelitis. x 1000 diam. Gram's stain.] + +_Staphylococcus Aureus._--This is the commonest organism found in +localised inflammatory and suppurative conditions. It varies greatly in +its virulence, and is found in such widely different conditions as skin +pustules, boils, carbuncles, and some acute inflammations of bone. As +seen by the microscope it occurs in grape-like clusters, fission of the +individual cells taking place irregularly (Fig. 2). When grown in +artificial media, the colonies assume an orange-yellow colour--hence the +name _aureus_. It is of high vitality and resists more prolonged +exposure to high temperatures than most non-sporing bacteria. It is +capable of lying latent in the tissues for long periods, for example, in +the marrow of long bones, and of again becoming active and causing a +fresh outbreak of suppuration. This organism is widely distributed: it +is found on the skin, in the mouth, and in other situations in the body, +and as it is present in the dust of the air and on all objects upon +which dust has settled, it is a continual source of infection unless +means are taken to exclude it from wounds. + +The _staphylococcus albus_ is much less common than the aureus, but has +the same properties and characters, save that its growth on artificial +media assumes a white colour. It is the common cause of stitch +abscesses, the skin being its normal habitat. + +[Illustration: FIG. 3.--Streptococci in Pus from an acute abscess in +subcutaneous tissue. x 1000 diam. Gram's stain.] + +_Streptococcus Pyogenes._--This organism also varies greatly in its +virulence; in some instances--for example in erysipelas--it causes a +sharp attack of acute spreading inflammation, which soon subsides +without showing any tendency to end in suppuration; under other +conditions it gives rise to a generalised infection which rapidly proves +fatal. The streptococcus has less capacity of liquefying the tissues +than the staphylococcus, so that pus formation takes place more slowly. +At the same time its products are very potent in destroying the tissues +in their vicinity, and so interfering with the exudation of leucocytes +which would otherwise exercise their protective influence. Streptococci +invade the lymph spaces, and are associated with acute spreading +conditions such as phlegmonous or erysipelatous inflammations and +suppurations, lymphangitis and suppuration in lymph glands, and +inflammation of serous and synovial membranes, also with a form of +pneumonia which is prone to follow on severe operations in the mouth and +throat. Streptococci are also concerned in the production of spreading +gangrene and pyaemia. + +Division takes place in one axis, so that chains of varying length are +formed (Fig. 3). It is less easily cultivated by artificial media than +the staphylococcus; it forms a whitish growth. + +[Illustration: FIG. 4.--Bacillus coli communis in Urine, from a case of +Cystitis. x 1000 diam. Leishman's stain.] + +_Bacillus Coli Communis._--This organism, which is a normal inhabitant +of the intestinal tract, shows a great tendency to invade any organ or +tissue whose vitality is lowered. It is causatively associated with such +conditions as peritonitis and peritoneal suppuration resulting from +strangulated hernia, appendicitis, or perforation in any part of the +alimentary canal. In cystitis, pyelitis, abscess of the kidney, +suppuration in the bile-ducts or liver, and in many other abdominal +conditions, it plays a most important part. The discharge from wounds +infected by this organism has usually a foetid, or even a faecal odour, +and often contains gases resulting from putrefaction. + +It is a small rod-shaped organism with short flagellae, which render it +motile (Fig. 4). It closely resembles the typhoid bacillus, but is +distinguished from it by its behaviour in artificial culture media. + +[Illustration: FIG. 5.--Fraenkel's Pneumococci in Pus from Empyema +following Pneumonia. x 100 diam. Stained with Muir's capsule stain.] + +_Pneumo-bacteria._--Two forms of organism associated with +pneumonia--_Fraenkel's pneumococcus_ (one of the diplococci) (Fig. 5) +and _Friedlander's pneumo-bacillus_ (a short rod-shaped form)--are +frequently met with in inflammations of the serous and synovial +membranes, in suppuration in the liver, and in various other +inflammatory and suppurative conditions. + +_Bacillus Typhosus._--This organism has been found in pure culture in +suppurative conditions of bone, of cellular tissue, and of internal +organs, especially during convalescence from typhoid fever. Like the +staphylococcus, it is capable of lying latent in the tissues for long +periods. + +_Other Pyogenic Bacteria._--It is not necessary to do more than name +some of the other organisms that are known to be pyogenic, such as the +bacillus pyocyaneus, which is found in green and blue pus, the +micrococcus tetragenus, the gonococcus, actinomyces, the glanders +bacillus, and the tubercle bacillus. Most of these will receive further +mention in connection with the diseases to which they give rise. + +#Leucocytosis.#--Most bacterial diseases, as well as certain other +pathological conditions, are associated with an increase in the number +of leucocytes in the blood throughout the circulatory system. This +condition of the blood, which is known as _leucocytosis_, is believed to +be due to an excessive output and rapid formation of leucocytes by the +bone marrow, and it probably has as its object the arrest and +destruction of the invading organisms or toxins. To increase the +resisting power of the system to pathogenic organisms, an artificial +leucocytosis may be induced by subcutaneous injection of a solution of +nucleinate of soda (16 minims of a 5 per cent. solution). + +The _normal_ number of leucocytes per cubic millimetre varies in +different individuals, and in the same individual under different +conditions, from 5000 to 10,000: 7500 is a normal average, and anything +above 12,000 is considered abnormal. When leucocytosis is present, the +number may range from 12,000 to 30,000 or even higher; 40,000 is looked +upon as a high degree of leucocytosis. According to Ehrlich, the +following may be taken as the standard proportion of the various forms +of leucocytes in normal blood: polynuclear neutrophile leucocytes, 70 to +72 per cent.; lymphocytes, 22 to 25 per cent.; eosinophile cells, 2 to 4 +per cent.; large mononuclear and transitional leucocytes, 2 to 4 per +cent.; mast-cells, 0.5 to 2 per cent. + +In estimating the clinical importance of a leucocytosis, it is not +sufficient merely to count the aggregate number of leucocytes present. A +differential count must be made to determine which variety of cells is +in excess. In the majority of surgical affections it is chiefly the +granular polymorpho-nuclear neutrophile leucocytes that are in excess +(_ordinary leucocytosis_). In some cases, and particularly in parasitic +diseases such as trichiniasis and hydatid disease, the eosinophile +leucocytes also show a proportionate increase (_eosinophilia_). The term +_lymphocytosis_ is applied when there is an increase in the number of +circulating lymphocytes, as occurs, for example, in lymphatic leucaemia, +and in certain cases of syphilis. + +Leucocytosis is met with in nearly all acute infective diseases, and in +acute pyogenic inflammatory affections, particularly in those attended +with suppuration. In exceptionally acute septic conditions the extreme +virulence of the toxins may prevent the leucocytes reacting, and +leucocytosis may be absent. The absence of leucocytosis in a disease in +which it is usually present is therefore to be looked upon as a grave +omen, particularly when the general symptoms are severe. In some cases +of malignant disease the number of leucocytes is increased to 15,000 or +20,000. A few hours after a severe haemorrhage also there is usually a +leucocytosis of from 15,000 to 30,000, which lasts for three or four +days (Lyon). In cases of haemorrhage the leucocytosis is increased by +infusion of fluids into the circulation. After all operations there is +at least a transient leucocytosis (_post-operative leucocytosis_) +(F. I. Dawson). + +The leucocytosis begins soon after the infection manifests itself--for +example, by shivering, rigor, or rise of temperature. The number of +leucocytes rises somewhat rapidly, increases while the condition is +progressing, and remains high during the febrile period, but there is no +constant correspondence between the number of leucocytes and the height +of the temperature. The arrest of the inflammation and its resolution +are accompanied by a fall in the number of leucocytes, while the +occurrence of suppuration is attended with a further increase in their +number. + +In interpreting the "blood count," it is to be kept in mind that a +_physiological leucocytosis_ occurs within three or four hours of taking +a meal, especially one rich in proteins, from 1500 to 2000 being added +to the normal number. In this _digestion leucocytosis_ the increase is +chiefly in the polynuclear neutrophile leucocytes. Immediately before +and after delivery, particularly in primiparae, there is usually a +moderate degree of leucocytosis. If the labour is normal and the +puerperium uncomplicated, the number of leucocytes regains the normal in +about a week. Lactation has no appreciable effect on the number of +leucocytes. In new-born infants the leucocyte count is abnormally high, +ranging from 15,000 to 20,000. In children under one year of age, the +normal average is from 10,000 to 20,000. + +_Absence of Leucocytosis--Leucopenia._--In certain infective diseases +the number of leucocytes in the circulating blood is abnormally +low--3000 or 4000--and this condition is known as _leucopenia_. It +occurs in typhoid fever, especially in the later stages of the disease, +in tuberculous lesions unaccompanied by suppuration, in malaria, and in +most cases of uncomplicated influenza. The occurrence of leucocytosis in +any of these conditions is to be looked upon as an indication that a +mixed infection has taken place, and that some suppurative process is +present. + +The absence of leucocytosis in some cases of virulent septic poisoning +has already been referred to. + +It will be evident that too much reliance must not be placed upon a +single observation, particularly in emergency cases. Whenever possible, +a series of observations should be made, the blood being examined about +four hours after meals, and about the same hour each day. + +The clinical significance of the blood count in individual diseases will +be further referred to. + +_The Iodine or Glycogen Reaction._--The leucocyte count may be +supplemented by staining films of the blood with a watery solution of +iodine and potassium iodide. In all advancing purulent conditions, in +septic poisonings, in pneumonia, and in cancerous growths associated +with ulceration, a certain number of the polynuclear leucocytes are +stained a brown or reddish-brown colour, due to the action of the iodine +on some substance in the cells of the nature of glycogen. This reaction +is absent in serous effusions, in unmixed tuberculous infections, in +uncomplicated typhoid fever, and in the early stages of cancerous +growths. + + + + +CHAPTER III + +INFLAMMATION + + +Definition--Nature of inflammation from surgical point of + view--Sequence of changes in bacterial inflammation--Clinical + aspects of inflammation--General principles of treatment--Chronic + inflammation. + +Inflammation may be defined as the series of vital changes that occurs +in the tissues in response to irritation. These changes represent the +reaction of the tissue elements to the irritant, and constitute the +attempt made by nature to arrest or to limit its injurious effects, and +to repair the damage done by it. + +The phenomena which characterise the inflammatory reaction can be +induced by any form of irritation--such, for example, as mechanical +injury, the application of heat or of chemical substances, or the action +of pathogenic bacteria and their toxins--and they are essentially +similar in kind whatever the irritant may be. The extent to which the +process may go, however, and its effects on the part implicated and on +the system as a whole, vary with different irritants and with the +intensity and duration of their action. A mechanical, a thermal, or a +chemical irritant, acting alone, induces a degree of reaction directly +proportionate to its physical properties, and so long as it does not +completely destroy the vitality of the part involved, the changes in the +tissues are chiefly directed towards repairing the damage done to the +part, and the inflammatory reaction is not only compatible with the +occurrence of ideal repair, but may be looked upon as an integral step +in the reparative process. + +The irritation caused by infection with bacteria, on the other hand, is +cumulative, as the organisms not only multiply in the tissues, but in +addition produce chemical poisons (toxins) which aggravate the +irritative effects. The resulting reaction is correspondingly +progressive, and has as its primary object the expulsion of the irritant +and the limitation of its action. If the natural protective effort is +successful, the resulting tissue changes subserve the process of repair, +but if the bacteria gain the upper hand in the struggle, the +inflammatory reaction becomes more intense, certain of the tissue +elements succumb, and the process for the time being is a destructive +one. During the stage of bacterial inflammation, reparative processes +are in abeyance, and it is only after the inflammation has been allayed, +either by natural means or by the aid of the surgeon, that repair takes +place. + +In applying the antiseptic principle to the treatment of wounds, our +main object is to exclude or to eliminate the bacterial factor, and so +to prevent the inflammatory reaction going beyond the stage in which it +is protective, and just in proportion as we succeed in attaining this +object, do we favour the occurrence of ideal repair. + +#Sequence of Changes in Bacterial Inflammation.#--As the form of +inflammation with which we are most concerned is that due to the action +of bacteria, in describing the process by which the protective influence +of the inflammatory reaction is brought into play, we shall assume the +presence of a bacterial irritant. + +The introduction of a colony of micro-organisms is quickly followed by +an accumulation of wandering cells, and proliferation of +connective-tissue cells in the tissues at the site of infection. The +various cells are attracted to the bacteria by a peculiar chemical or +biological power known as _chemotaxis_, which seems to result from +variations in the surface tension of different varieties of cells, +probably caused by some substance produced by the micro-organisms. +Changes in the blood vessels then ensue, the arteries becoming dilated +and the rate of the current in them being for a time increased--_active +hyperaemia_. Soon, however, the rate of the blood flow becomes slower +than normal, and in course of time the current may cease (_stasis_), and +the blood in the vessels may even coagulate (_thrombosis_). Coincidently +with these changes in the vessels, the leucocytes in the blood of the +inflamed part rapidly increase in number, and they become viscous and +adhere to the vessel wall, where they may accumulate in large numbers. +In course of time the leucocytes pass through the vessel +wall--_emigration of leucocytes_--and move towards the seat of +infection, giving rise to a marked degree of _local leucocytosis_. +Through the openings by which the leucocytes have escaped from the +vessels, red corpuscles may be passively extruded--_diapedesis of red +corpuscles_. These processes are accompanied by changes in the +endothelium of the vessel walls, which result in an increased formation +of lymph, which transudes into the meshes of the connective tissue +giving rise to an _inflammatory oedema_, or, if the inflammation is on a +free surface, forming an _inflammatory exudate_. The quantity and +characters of this exudate vary in different parts of the body, and +according to the nature, virulence, and location of the organisms +causing the inflammation. Thus it may be _serous_, as in some forms of +synovitis; _sero-fibrinous_, as in certain varieties of peritonitis, the +fibrin tending to limit the spread of the inflammation by forming +adhesions; _croupous_, when it coagulates on a free surface and forms a +false membrane, as in diphtheria; _haemorrhagic_ when mixed with blood; +or _purulent_, when suppuration has occurred. The protective effects of +the inflammatory reaction depend for the most part upon the transudation +of lymph and the emigration of leucocytes. The lymph contains the +opsonins which act on the bacteria and render them less able to resist +the attack of the phagocytes, as well as the various protective +antibodies which neutralise the toxins. The polymorph leucocytes are the +principal agents in the process of phagocytosis (p. 22), and together +with the other forms of phagocytes they ingest and destroy the bacteria. + +If the attempt to repel the invading organisms is successful, the +irritant effects are overcome, the inflammation is arrested, and +_resolution_ is said to take place. + +Certain of the vascular and cellular changes are now utilised to restore +the condition to the normal, and _repair_ ensues after the manner +already described. In certain situations, notably in tendon sheaths, in +the cavities of joints, and in the interior of serous cavities, for +example the pleura and peritoneum, the restoration to the normal is not +perfect, adhesions forming between the opposing surfaces. + +If, however, the reaction induced by the infection is insufficient to +check the growth and spread of the organisms, or to inhibit their toxin +production, local necrosis of tissue may take place, either in the form +of suppuration or of gangrene, or the toxins absorbed into the +circulation may produce blood-poisoning, which may even prove fatal. + +#Clinical Aspects of Inflammation.#--It must clearly be understood that +inflammation is not to be looked upon as a disease in itself, but rather +as an evidence of some infective process going on in the tissues in +which it occurs, and of an effort on the part of these tissues to +overcome the invading organisms and their products. The chief danger to +the patient lies, not in the reactive changes that constitute the +inflammatory process, but in the fact that he is liable to be poisoned +by the toxins of the bacteria at work in the inflamed area. + +Since the days of Celsus (first century A.D.), heat, redness, swelling, +and pain have been recognised as cardinal signs of inflammation, and to +these may be added, interference with function in the inflamed part, and +general constitutional disturbance. Variations in these signs and +symptoms depend upon the acuteness of the condition, the nature of the +causative organism and of the tissue attacked, the situation of the part +in relation to the surface, and other factors. + +The _heat_ of the inflamed part is to be attributed to the increased +quantity of blood present in it, and the more superficial the affected +area the more readily is the local increase of temperature detected by +the hand. This clinical point is best tested by placing the palm of the +hand and fingers for a few seconds alternately over an uninflamed and an +inflamed area, otherwise under similar conditions as to coverings and +exposure. In this way even slight differences may be recognised. + +_Redness_, similarly, is due to the increased afflux of blood to the +inflamed part. The shade of colour varies with the stage of the +inflammation, being lighter and brighter in the early, hyperaemic stages, +and darker and duskier when the blood flow is slowed or when stasis has +occurred and the oxygenation of the blood is defective. In the +thrombotic stage the part may assume a purplish hue. + +The _swelling_ is partly due to the increased amount of blood in the +affected part and to the accumulation of leucocytes and proliferated +tissue cells, but chiefly to the exudate in the connective +tissue--_inflammatory oedema_. The more open the structure of the tissue +of the part, the greater is the amount of swelling--witness the marked +degree of oedema that occurs in such parts as the scrotum or the eyelids. + +_Pain_ is a symptom seldom absent in inflammation. _Tenderness_--that +is, pain elicited on pressure--is one of the most valuable diagnostic +signs we possess, and is often present before pain is experienced by the +patient. That the area of tenderness corresponds to the area of +inflammation is almost an axiom of surgery. Pain and tenderness are due +to the irritation of nerve filaments of the part, rendered all the more +sensitive by the abnormal conditions of their blood supply. In +inflammatory conditions of internal organs, for example the abdominal +viscera, the pain is frequently referred to other parts, usually to an +area supplied by branches from the same segment of the cord as that +supplying the inflamed part. + +For purposes of diagnosis, attention should be paid to the terms in +which the patient describes his pain. For example, the pain caused by +an inflammation of the skin is usually described as of a _burning_ or +_itching_ character; that of inflammation in dense tissues like +periosteum or bone, or in encapsuled organs, as _dull_, _boring_, or +_aching_. When inflammation is passing on to suppuration the pain +assumes a _throbbing_ character, and as the pus reaches the surface, or +"points," as it is called, sharp, _darting_, or _lancinating_ pains are +experienced. Inflammation involving a nerve-trunk may cause a _boring_ +or a _tingling_ pain; while the implication of a serous membrane such as +the pleura or peritoneum gives rise to a pain of a sharp, _stabbing_ +character. + +_Interference with the function_ of the inflamed part is always present +to a greater or less extent. + +#Constitutional Disturbances.#--Under the term constitutional +disturbances are included the presence of fever or elevation of +temperature; certain changes in the pulse rate and the respiration; +gastro-intestinal and urinary disturbances; and derangements of the +central nervous system. These are all due to the absorption of toxins +into the general circulation. + +_Temperature._--A marked rise of temperature is one of the most constant +and important concomitants of acute inflammatory conditions, and the +temperature chart forms a fairly reliable index of the state of the +patient. The toxins interfere with the nerve-centres in the medulla that +regulate the balance between the production and the loss of body heat. + +Clinically the temperature is estimated by means of a self-registering +thermometer placed, for from one to five minutes, in close contact with +the skin in the axilla, or in the mouth. Sometimes the thermometer is +inserted into the rectum, where, however, the temperature is normally +3/4 o F. higher than in the axilla. + +_In health_ the temperature of the body is maintained at a mean of about +98.4 o F. (37 o C.) by the heat-regulating mechanism. It varies from hour +to hour even in health, reaching its maximum between four and eight in +the evening, when it may rise to 99 o F., and is at its lowest between +four and six in the morning, when it may be about 97 o F. + +The temperature is more easily disturbed in children than in adults, and +may become markedly elevated (104 o or 105 o F.) from comparatively slight +causes; in the aged it is less liable to change, so that a rise to 103 o +or 104 o F. is to be looked upon as indicating a high state of fever. + +A sudden rise of temperature is usually associated with a feeling of +chilliness down the back and in the limbs, which may be so marked that +the patient shivers violently, while the skin becomes cold, pale, and +shrivelled--_cutis anserina_. This is a nervous reaction due to a want +of correspondence between the internal and the surface temperature of +the body, and is known clinically as a _rigor_. When the temperature +rises gradually the chill is usually slight and may be unobserved. Even +during the cold stage, however, the internal temperature is already +raised, and by the time the chill has passed off its maximum has been +reached. + +The _pulse_ is always increased in frequency, and usually varies +directly with the height of the temperature. _Respiration_ is more +active during the progress of an inflammation; and bronchial catarrh is +common apart from any antecedent respiratory disease. + +_Gastro-intestinal disturbances_ take the form of loss of appetite, +vomiting, diminished secretion of the alimentary juices, and weakening +of the peristalsis of the bowel, leading to thirst, dry, furred tongue, +and constipation. Diarrhoea is sometimes present. The _urine_ is usually +scanty, of high specific gravity, rich in nitrogenous substances, +especially urea and uric acid, and in calcium salts, while sodium +chloride is deficient. Albumin and hyaline casts may be present in cases +of severe inflammation with high temperature. The significance of +general _leucocytosis_ has already been referred to. + +#General Principles of Treatment.#--The capacity of the inflammatory +reaction for dealing with bacterial infections being limited, it often +becomes necessary for the surgeon to aid the natural defensive +processes, as well as to counteract the local and general effects of the +reaction, and to relieve symptoms. + +The ideal means of helping the tissues is by removing the focus of +infection, and when this can be done, as for example in a carbuncle or +an anthrax pustule, the infected area may be completely excised. When +the focus is not sufficiently limited to admit of this, the infected +tissue may be scraped away with the sharp spoon, or destroyed by +caustics or by the actual cautery. If this is inadvisable, the organisms +may be attacked by strong antiseptics, such as pure carbolic acid. + +Moist dressings favour the removal of bacteria by promoting the escape +of the inflammatory exudate, in which they are washed out. + +#Artificial Hyperaemia.#--When such direct means as the above are +impracticable, much can be done to aid the tissues in their struggle by +improving the condition of the circulation in the inflamed area, so as +to ensure that a plentiful supply of fresh arterial blood reaches it. +The beneficial effects of _hot fomentations and poultices_ depend on +their causing a dilatation of the vessels, and so inducing a hyperaemia +in the affected area. It has been shown experimentally that repeated, +short applications of moist heat (not exceeding 106 o F.) are more +efficacious than continuous application. It is now believed that the +so-called _counter-irritants_--mustard, iodine, cantharides, actual +cautery--act in the same way; and the method of treating erysipelas by +applying a strong solution of iodine around the affected area is based +on the same principle. + +[Illustration: FIG. 6.--Passive Hyperaemia of Hand and Forearm induced by +Bier's Bandage.] + +While these and similar methods have long been employed in the treatment +of inflammatory conditions, it is only within comparatively recent years +that their mode of action has been properly understood, and to August +Bier belongs the credit of having put the treatment of inflammation on a +scientific and rational basis. Recognising the "beneficent intention" of +the inflammatory reaction, and the protective action of the leucocytosis +which accompanies the hyperaemic stages of the process, Bier was led to +study the effects of increasing the hyperaemia by artificial means. As a +result of his observations, he has formulated a method of treatment +which consists in inducing an artificial hyperaemia in the inflamed area, +either by obstructing the venous return from the part (_passive +hyperaemia_), or by stimulating the arterial flow through it (_active +hyperaemia_). + +_Bier's Constricting Bandage._--To induce a _passive hyperaemia_ in a +limb, an elastic bandage is applied some distance above the inflamed +area sufficiently tightly to obstruct the venous return from the distal +parts without arresting in any way the inflow of arterial blood (Fig. 6). +If the constricting band is correctly applied, the parts beyond +become swollen and oedematous, and assume a bluish-red hue, but they +retain their normal temperature, the pulse is unchanged, and there is no +pain. If the part becomes blue, cold, or painful, or if any existing +pain is increased, the band has been applied too tightly. The hyperaemia +is kept up from twenty to twenty-two hours out of the twenty-four, and +in the intervals the limb is elevated to get rid of the oedema and to +empty it of impure blood, and so make room for a fresh supply of healthy +blood when the bandage is re-applied. As the inflammation subsides, the +period during which the band is kept on each day is diminished; but the +treatment should be continued for some days after all signs of +inflammation have subsided. + +This method of treating acute inflammatory conditions necessitates +close supervision until the correct degree of tightness of the band has +been determined. + +[Illustration: FIG. 7.--Passive Hyperaemia of Finger induced by Klapp's +Suction Bell.] + +_Klapp's Suction Bells._--In inflammatory conditions to which the +constricting band cannot be applied, as for example an acute mastitis, a +bubo in the groin, or a boil on the neck, the affected area may be +rendered hyperaemic by an appropriately shaped glass bell applied over it +and exhausted by means of a suction-pump, the rarefaction of the air in +the bell determining a flow of blood into the tissues enclosed within it +(Figs. 7 and 8). The edge of the bell is smeared with vaseline, and the +suction applied for from five to ten minutes at a time, with a +corresponding interval between the applications. Each sitting lasts for +from half an hour to an hour, and the treatment may be carried out once +or twice a day according to circumstances. This apparatus acts in the +same way as the old-fashioned _dry cup_, and is more convenient and +equally efficacious. + +[Illustration: FIG. 8.--Passive Hyperaemia induced by Klapp's Suction +Bell for Inflammation of Inguinal Gland.] + +_Active hyperaemia_ is induced by the local application of heat, +particularly by means of hot air. It has not proved so useful in acute +inflammation as passive hyperaemia, but is of great value in hastening +the absorption of inflammatory products and in overcoming adhesions and +stiffness in tendons and joints. + +_General Treatment._--The patient should be kept at rest, preferably in +bed, to diminish the general tissue waste; and the diet should be +restricted to fluids, such as milk, beef-tea, meat juices or gruel, and +these may be rendered more easily assimilable by artificial digestion if +necessary. To counteract the general effect of toxins absorbed into +the circulation, specific antitoxic sera are employed in certain forms +of infection, such as diphtheria, streptococcal septicaemia, and tetanus. +In other forms of infection, vaccines are employed to increase the +opsonic power of the blood. When such means are not available, the +circulating toxins may to some extent be diluted by giving plenty of +bland fluids by the mouth or normal salt solution by the rectum. + +The elimination of the toxins is promoted by securing free action of the +emunctories. A saline purge, such as half an ounce of sulphate of +magnesium in a small quantity of water, ensures a free evacuation of the +bowels. The kidneys are flushed by such diluent drinks as equal parts of +milk and lime water, or milk with a dram of liquor calcis saccharatus +added to each tumblerful. Barley-water and "Imperial drink," which +consists of a dram and a half of cream of tartar added to a pint of +boiling water and sweetened with sugar after cooling, are also useful +and non-irritating diuretics. The skin may be stimulated by Dover's +powder (10 grains) or liquor ammoniae acetatis in three-dram doses every +four hours. + +Various drugs administered internally, such as quinine, salol, +salicylate of iron, and others, have a reputation, more or less +deserved, as internal antiseptics. + +Weakness of the heart, as indicated by the condition of the pulse, is +treated by the use of such drugs as digitalis, strophanthus, or +strychnin, according to circumstances. + +Gastro-intestinal disturbances are met by ordinary medical means. +Vomiting, for example, can sometimes be checked by effervescing drinks, +such as citrate of caffein, or by dilute hydrocyanic acid and bismuth. +In severe cases, and especially when the vomited matter resembles +coffee-grounds from admixture with altered blood--the so-called +post-operative haematemesis--the best means of arresting the vomiting is +by washing out the stomach. Thirst is relieved by rectal injections of +saline solution. The introduction of saline solution into the veins or +by the rectum is also useful in diluting and hastening the elimination +of circulating toxins. + +In surgical inflammations, as a rule, nothing is gained by lowering the +temperature, unless at the same time the cause is removed. When severe +or prolonged pyrexia becomes a source of danger, the use of hot or cold +sponging, or even the cold bath, is preferable to the administration of +drugs. + +_Relief of Symptoms._--For the relief of _pain_, rest is essential. The +inflamed part should be placed in a splint or other appliance which will +prevent movement, and steps must be taken to reduce its functional +activity as far as possible. Locally, warm and moist dressings, such as +a poultice or fomentation, may be used. To make a fomentation, a piece +of flannel or lint is wrung out of very hot water or antiseptic lotion +and applied under a sheet of mackintosh. Fomentations should be renewed +as often as they cool. An ordinary india-rubber bag filled with hot +water and fixed over the fomentation, by retaining the heat, obviates +the necessity of frequently changing the application. The addition of a +few drops of laudanum sprinkled on the flannel has a soothing effect. +Lead and opium lotion is a useful, soothing application employed as a +fomentation. We prefer the application of lint soaked in a 10 per cent. +aqueous or glycerine solution of ichthyol, or smeared with ichthyol +ointment (1 in 3). Belladonna and glycerine, equal parts, may be used. + +Dry cold obtained by means of icebags, or by Leiter's lead tubes through +which a continuous stream of ice-cold water is kept flowing, is +sometimes soothing to the patient, but when the vessels in the inflamed +part are greatly congested its use is attended with considerable risk, +as it not only contracts the arterioles supplying the part, but also +diminishes the outflow of venous blood, and so may determine gangrene of +tissues already devitalised. + +A milder form of employing cold is by means of evaporating lotions: a +thin piece of lint or gauze is applied over the inflamed part and kept +constantly moist with the lotion, the dressing being left freely exposed +to allow of continuous evaporation. A useful evaporating lotion is made +up as follows: take of chloride of ammonium, half an ounce; rectified +spirit, one ounce; and water, seven ounces. + +The administration of opiates may be necessary for the relief of pain. + +The accumulation of an excessive amount of inflammatory exudate may +endanger the vitality of the tissues by pressing on the blood vessels to +such an extent as to cause stasis, and by concentrating the local action +of the toxins. Under such conditions the tension should be relieved and +the exudate with its contained toxins removed by making an incision into +the inflamed tissues, and applying a suction bell. When the exudate has +collected in a synovial cavity, such as a joint or bursa, it may be +withdrawn by means of a trocar and cannula. There are other methods of +withdrawing blood and exudate from an inflamed area, for example by +leeches or wet-cupping, but they are seldom employed now. + +Before applying leeches the part must be thoroughly cleansed, and if +the leech is slow to bite, may be smeared with cream. The leech is +retained in position under an inverted wine-glass or wide test-tube till +it takes hold. After it has sucked its fill it usually drops off, having +withdrawn a dram or a dram and a half of blood. If it be desirable to +withdraw more blood, hot fomentations should be applied to the bite. As +it is sometimes necessary to employ considerable pressure to stop the +bleeding, leeches should, if possible, be applied over a bone which will +furnish the necessary resistance. The use of styptics may be called for. + +_Wet-cupping_ has almost entirely been superseded by the use of Klapp's +suction bells. + +_General blood-letting_ consists in opening a superficial vein +(venesection) and allowing from eight to ten ounces of blood to flow +from it. It is seldom used in the treatment of surgical forms of +inflammation. + +_Counter-irritants._--In deep-seated inflammations, counter-irritants +are sometimes employed in the form of mustard leaves or blisters, +according to the degree of irritation required. A mustard leaf or +plaster should not be left on longer than ten or fifteen minutes, unless +it is desired to produce a blister. Blistering may be produced by a +_cantharides plaster_, or by painting with _liquor epispasticus_. The +plaster should be left on from eight to ten hours, and if it has failed +to raise a blister, a hot fomentation should be applied to the part. +_Liquor epispasticus_, alone or mixed with equal parts of collodion, is +painted on the part with a brush. Several paintings are often required +before a blister is raised. The preliminary removal of the natural +grease from the skin favours the action of these applications. + +The treatment of inflammation in special tissues and organs will be +considered in the sections devoted to regional surgery. + +#Chronic Inflammation.#--A variety of types of chronic and subacute +inflammation are met with which, owing to ignorance of their causations, +cannot at present be satisfactorily classified. + +The best defined group is that of the _granulomata_, which includes such +important diseases as tuberculosis and syphilis, and in which different +types of chronic inflammation are caused by infection with a specific +organism, all having the common character, however, that abundant +granulation tissue is formed in which cellular changes are more in +evidence than changes in the blood vessels, and in which the subsequent +degeneration and necrosis of the granulation tissue results in the +breaking down and destruction of the tissue in which it is formed. +Another group is that in which chronic inflammation is due to mild or +attenuated forms of pyogenic infection affecting especially the lymph +glands and the bone marrow. In the glands of the groin, for example, +associated with various forms of irritation about the external genitals, +different types of _chronic lymphadenitis_ are met with; they do not +frankly suppurate as do the acute types, but are attended with a +hyperplasia of the tissue elements which results in enlargement of the +affected glands of a persistent, and sometimes of a relapsing character. +Similar varieties of _osteomyelitis_ are met with that do not, like the +acute forms, go on to suppuration or to death of bone, but result in +thickening of the bone affected, both on the surface and in the +interior, resulting in obliteration of the medullary canal. + +A third group of chronic inflammations are those that begin as an acute +pyogenic inflammation, which, instead of resolving completely, persists +in a chronic form. It does so apparently because there is some factor +aiding the organisms and handicapping the tissues, such as the presence +of a foreign body, a piece of glass or metal, or a piece of dead bone; +in these circumstances the inflammation persists in a chronic form, +attended with the formation of fibrous tissue, and, in the case of bone, +with the formation of new bone in excess. It will be evident that in +this group, chronic inflammation and repair are practically +interchangeable terms. + +There are other groups of chronic inflammation, the origin of which +continues to be the subject of controversy. Reference is here made to +the chronic inflammations of the synovial membrane of joints, of tendon +sheaths and of bursae--_chronic synovitis_, _teno-synovitis_ and +_bursitis_; of the fibrous tissues of joints--chronic forms of +_arthritis_; of the blood vessels--chronic forms of _endarteritis_ and +of _phlebitis_ and of the peripheral nerves--_neuritis_. Also in the +breast and in the prostate, with the waning of sexual life there may +occur a formation of fibrous tissue--chronic _interstitial mastitis_, +_chronic prostatitis_, having analogies with the chronic interstitial +inflammations of internal organs like the kidney--_chronic interstitial +nephritis_; and in the breast and prostate, as in the kidney, the +formation of fibrous tissue leads to changes in the secreting epithelium +resulting in the formation of cysts. + +Lastly, there are still other types of chronic inflammation attended +with the formation of fibrous tissue on such a liberal scale as to +suggest analogies with new growths. The best known of these are the +systematic forms of fibromatosis met with in the central nervous system +and in the peripheral nerves--_neuro-fibromatosis_; in the submucous +coat of the stomach--_gastric fibromatosis_; and in the +colon--_intestinal fibromatosis_. + +These conditions will be described with the tissues and organs in which +they occur. + +In the _treatment of chronic inflammations_, pending further knowledge +as to their causation, and beyond such obvious indications as to help +the tissues by removing a foreign body or a piece of dead bone, there +are employed--empirically--a number of procedures such as the induction +of hyperaemia, exposure to the X-rays, and the employment of blisters, +cauteries, and setons. Vaccines may be had recourse to in those of +bacterial origin. + + + + +CHAPTER IV + +SUPPURATION + + +Definition--Pus--_Varieties_--Acute circumscribed abscess--_Acute + suppuration in a wound_--_Acute Suppuration in a mucous + membrane_--Diffuse cellulitis and diffuse suppuration-- + _Whitlow_--_Suppurative cellulitis in different situations_--Chronic + suppuration--Sinus, Fistula--Constitutional manifestations of + pyogenic infection--_Sapraemia_--_Septicaemia_--_Pyaemia_. + +Suppuration, or the formation of pus, is one of the results of the +action of bacteria on the tissues. The invading organism is usually one +of the staphylococci, less frequently a streptococcus, and still less +frequently one of the other bacteria capable of producing pus, such as +the bacillus coli communis, the gonococcus, the pneumococcus, or the +typhoid bacillus. + +So long as the tissues are in a healthy condition they are able to +withstand the attacks of moderate numbers of pyogenic bacteria of +ordinary virulence, but when devitalised by disease, by injury, or by +inflammation due to the action of other pathogenic organisms, +suppuration ensues. + +It would appear, for example, that pyogenic organisms can pass through +the healthy urinary tract without doing any damage, but if the pelvis of +the kidney, the ureter, or the bladder is the seat of stone, they give +rise to suppuration. Similarly, a calculus in one of the salivary ducts +frequently results in an abscess forming in the floor of the mouth. When +the lumen of a tubular organ, such as the appendix or the Fallopian tube +is blocked also, the action of pyogenic organisms is favoured and +suppuration ensues. + +#Pus.#--The fluid resulting from the process of suppuration is known +as _pus_. In its typical form it is a yellowish creamy substance, of +alkaline reaction, with a specific gravity of about 1030, and it has a +peculiar mawkish odour. If allowed to stand in a test-tube it does not +coagulate, but separates into two layers: the upper, transparent, +straw-coloured fluid, the _liquor puris_ or pus serum, closely +resembling blood serum in its composition, but containing less protein +and more cholestrol; it also contains leucin, tyrosin, and certain +albumoses which prevent coagulation. + +The layer at the bottom of the tube consists for the most part of +polymorph leucocytes, and proliferated connective tissue and endothelial +cells (_pus corpuscles_). Other forms of leucocytes may be present, +especially in long-standing suppurations; and there are usually some red +corpuscles, dead bacteria, fat cells and shreds of tissue, cholestrol +crystals, and other detritus in the deposit. + +If a film of fresh pus is examined under the microscope, the pus cells +are seen to have a well-defined rounded outline, and to contain a finely +granular protoplasm and a multi-partite nucleus; if still warm, the +cells may exhibit amoeboid movement. In stained films the nuclei take the +stain well. In older pus cells the outline is irregular, the protoplasm +coarsely granular, and the nuclei disintegrated, no longer taking the +stain. + +_Variations from Typical Pus._--Pus from old-standing sinuses is often +watery in consistence (ichorous), with few cells. Where the granulations +are vascular and bleed easily, it becomes sanious from admixture with +red corpuscles; while, if a blood-clot be broken down and the debris +mixed with the pus, it contains granules of blood pigment and is said to +be "grumous." The _odour_ of pus varies with the different bacteria +producing it. Pus due to ordinary pyogenic cocci has a mawkish odour; +when putrefactive organisms are present it has a putrid odour; when it +forms in the vicinity of the intestinal canal it usually contains the +bacillus coli communis and has a faecal odour. + +The _colour_ of pus also varies: when due to one or other of the +varieties of the bacillus pyocyaneus, it is usually of a blue or green +colour; when mixed with bile derivatives or altered blood pigment, it +may be of a bright orange colour. In wounds inflicted with rough iron +implements from which rust is deposited, the pus often presents the same +colour. + +The pus may form and collect within a circumscribed area, constituting a +localised _abscess_; or it may infiltrate the tissues over a wide +area--_diffuse suppuration_. + + +ACUTE CIRCUMSCRIBED ABSCESS + +Any tissue of the body may be the seat of an acute abscess, and there +are many routes by which the bacteria may gain access to the affected +area. For example: an abscess in the integument or subcutaneous +cellular tissue usually results from infection by organisms which have +entered through a wound or abrasion of the surface, or along the ducts +of the skin; an abscess in the breast from organisms which have passed +along the milk ducts opening on the nipple, or along the lymphatics +which accompany these. An abscess in a lymph gland is usually due to +infection passing by way of the lymph channels from the area of skin or +mucous membrane drained by them. Abscesses in internal organs, such as +the kidney, liver, or brain, usually result from organisms carried in +the blood-stream from some focus of infection elsewhere in the body. + +A knowledge of the possible avenues of infection is of clinical +importance, as it may enable the source of a given abscess to be traced +and dealt with. In suppuration in the Fallopian tube (pyosalpynx), for +example, the fact that the most common origin of the infection is in the +genital passage, leads to examination for vaginal discharge; and if none +is present, the abscess is probably due to infection carried in the +blood-stream from some primary focus about the mouth, such as a gumboil +or an infective sore throat. + +The exact location of an abscess also may furnish a key to its source; +in axillary abscess, for example, if the suppuration is in the lymph +glands the infection has come through the afferent lymphatics; if in the +cellular tissue, it has spread from the neck or chest wall; if in the +hair follicles, it is a local infection through the skin. + +#Formation of an Abscess.#--When pyogenic bacteria are introduced into +the tissue there ensues an inflammatory reaction, which is characterised +by dilatation of the blood vessels, exudation of large numbers of +leucocytes, and proliferation of connective-tissue cells. These +wandering cells soon accumulate round the focus of infection, and form a +protective barrier which tends to prevent the spread of the organisms +and to restrict their field of action. Within the area thus +circumscribed the struggle between the bacteria and the phagocytes takes +place, and in the process toxins are formed by the organisms, a certain +number of the leucocytes succumb, and, becoming degenerated, set free +certain proteolytic enzymes or ferments. The toxins cause +coagulation-necrosis of the tissue cells with which they come in +contact, the ferments liquefy the exudate and other albuminous +substances, and in this way _pus_ is formed. + +If the bacteria gain the upper hand, this process of liquefaction which +is characteristic of suppuration, extends into the surrounding tissues, +the protective barrier of leucocytes is broken down, and the +suppurative process spreads. A fresh accession of leucocytes, however, +forms a new barrier, and eventually the spread is arrested, and the +collection of pus so hemmed in constitutes an _abscess_. + +Owing to the swelling and condensation of the parts around, the pus thus +formed is under considerable pressure, and this causes it to burrow +along the lines of least resistance. In the case of a subcutaneous +abscess the pus usually works its way towards the surface, and "points," +as it is called. Where it approaches the surface the skin becomes soft +and thin, and eventually sloughs, allowing the pus to escape. + +An abscess forming in the deeper planes is prevented from pointing +directly to the surface by the firm fasciae and other fibrous structures. +The pus therefore tends to burrow along the line of the blood vessels +and in the connective-tissue septa, till it either finds a weak spot or +causes a portion of fascia to undergo necrosis and so reaches the +surface. Accordingly, many abscess cavities resulting from deep-seated +suppuration are of irregular shape, with pouches and loculi in various +directions--an arrangement which interferes with their successful +treatment by incision and drainage. + +The relief of tension which follows the bursting of an abscess, the +removal of irritation by the escape of pus, and the casting off of +bacteria and toxins, allow the tissues once more to assert themselves, +and a process of repair sets in. The walls of the abscess fall in; +granulation tissue grows into the space and gradually fills it; and +later this is replaced by cicatricial tissue. As a result of the +subsequent contraction of the cicatricial tissue, the scar is usually +depressed below the level of the surrounding skin surface. + +If an abscess is prevented from healing--for example, by the presence of +a foreign body or a piece of necrosed bone--a sinus results, and from it +pus escapes until the foreign body is removed. + +#Clinical Features of an Acute Circumscribed Abscess.#--In the initial +stages the usual symptoms of inflammation are present. Increased +elevation of temperature, with or without a rigor, progressive +leucocytosis, and sweating, mark the transition between inflammation and +suppuration. An increasing leucocytosis is evidence that a suppurative +process is spreading. + +The local symptoms vary with the seat of the abscess. When it is +situated superficially--for example, in the breast tissue--the affected +area is hot, the redness of inflammation gives place to a dusky purple +colour, with a pale, sometimes yellow, spot where the pus is near the +surface. The swelling increases in size, the firm brawny centre becomes +soft, projects as a cone beyond the level of the rest of the swollen +area, and is usually surrounded by a zone of induration. + +By gently palpating with the finger-tips over the softened area, a fluid +wave may be detected--_fluctuation_--and when present this is a certain +indication of the existence of fluid in the swelling. Its recognition, +however, is by no means easy, and various fallacies are to be guarded +against in applying this test clinically. When, for example, the walls +of the abscess are thick and rigid, or when its contents are under +excessive tension, the fluid wave cannot be elicited. On the other hand, +a sensation closely resembling fluctuation may often be recognised in +oedematous tissues, in certain soft, solid tumours such as fatty tumours +or vascular sarcomata, in aneurysm, and in a muscle when it is palpated +in its transverse axis. + +When pus has formed in deeper parts, and before it has reached the +surface, oedema of the overlying skin is frequently present, and the skin +pits on pressure. + +With the formation of pus the continuous burning or boring pain of +inflammation assumes a throbbing character, with occasional sharp, +lancinating twinges. Should doubt remain as to the presence of pus, +recourse may be had to the use of an exploring needle. + +_Differential Diagnosis of Acute Abscess._--A practical difficulty which +frequently arises is to decide whether or not pus has actually formed. +It may be accepted as a working rule in practice that when an acute +inflammation has lasted for four or five days without showing signs of +abatement, suppuration has almost certainly occurred. In deep-seated +suppuration, marked oedema of the skin and the occurrence of rigors and +sweating may be taken to indicate the formation of pus. + +There are cases on record where rapidly growing sarcomatous and +angiomatous tumours, aneurysms, and the bruises that occur in +haemophylics, have been mistaken for acute abscesses and incised, with +disastrous results. + +#Treatment of Acute Abscesses.#--The dictum of John Bell, "Where there +is pus, let it out," summarises the treatment of abscess. The extent and +situation of the incision and the means taken to drain the cavity, +however, vary with the nature, site, and relations of the abscess. In a +superficial abscess, for example a bubo, or an abscess in the breast or +face where a disfiguring scar is undesirable, a small puncture should be +made where the pus threatens to point, and a Klapp's suction bell be +applied as already described (p. 39). A drain is not necessary, and in +the intervals between the applications of the bell the part is covered +with a moist antiseptic dressing. + +In abscesses deeply placed, as for example under the gluteal or pectoral +muscles, one or more incisions should be made, and the cavity drained by +glass or rubber tubes or by strips of rubber tissue. + +The wound should be dressed the next day, and the tube shortened, in the +case of a rubber tube, by cutting off a portion of its outer end. On the +second day or later, according to circumstances, the tube is removed, +and after this the dressing need not be repeated oftener than every +second or third day. + +Where pus has formed in relation to important structures--as, for +example, in the deeper planes of the neck--_Hilton's method_ of opening +the abscess may be employed. An incision is made through the skin and +fascia, a grooved director is gently pushed through the deeper tissues +till pus escapes along its groove, and then the track is widened by +passing in a pair of dressing forceps and expanding the blades. A tube, +or strip of rubber tissue, is introduced, and the subsequent treatment +carried out as in other abscesses. When the drain lies in proximity to a +large blood vessel, care must be taken not to leave it in position long +enough to cause ulceration of the vessel wall by pressure. + +In some abscesses, such as those in the vicinity of the anus, the cavity +should be laid freely open in its whole extent, stuffed with iodoform or +bismuth gauze, and treated by the open method. + +It is seldom advisable to wash out an abscess cavity, and squeezing out +the pus is also to be avoided, lest the protective zone be broken down +and the infection be diffused into the surrounding tissues. + +The importance of taking precautions against further infection in +opening an abscess can scarcely be exaggerated, and the rapidity with +which healing occurs when the access of fresh bacteria is prevented is +in marked contrast to what occurs when such precautions are neglected +and further infection is allowed to take place. + +_Acute Suppuration in a Wound._--If in the course of an operation +infection of the wound has occurred, a marked inflammatory reaction soon +manifests itself, and the same changes as occur in the formation of an +acute abscess take place, modified, however, by the fact that the pus +can more readily reach the surface. In from twenty-four to forty-eight +hours the patient is conscious of a sensation of chilliness, or may +even have a rigor. At the same time he feels generally out of sorts, +with impaired appetite, headache, and it may be looseness of the bowels. +His temperature rises to 100 o or 101 o F., and the pulse quickens to 100 +or 110. + +On exposing the wound it is found that the parts for some distance +around are red, glazed, and oedematous. The discoloration and swelling +are most intense in the immediate vicinity of the wound, the edges of +which are everted and moist. Any stitches that may have been introduced +are tight, and the deep ones may be cutting into the tissues. There is +heat, and a constant burning or throbbing pain, which is increased by +pressure. If the stitches be cut, pus escapes, the wound gapes, and its +surfaces are found to be inflamed and covered with pus. + +The open method is the only safe means of treating such wounds. The +infected surface may be sponged over with pure carbolic acid, the excess +of which is washed off with absolute alcohol, and the wound either +drained by tubes or packed with iodoform gauze. The practice of scraping +such surfaces with the sharp spoon, squeezing or even of washing them +out with antiseptic lotions, is attended with the risk of further +diffusing the organisms in the tissue, and is only to be employed under +exceptional circumstances. Continuous irrigation of infected wounds or +their immersion in antiseptic baths is sometimes useful. The free +opening up of the wound is almost immediately followed by a fall in the +temperature. The surrounding inflammation subsides, the discharge of pus +lessens, and healing takes place by the formation of granulation +tissue--the so-called "healing by second intention." + +Wound infection may take place from _catgut_ which has not been +efficiently prepared. The local and general reactions may be slight, +and, as a rule, do not appear for seven or eight days after the +operation, and, it may be, not till after the skin edges have united. +The suppuration is strictly localised to the part of the wound where +catgut was employed for stitches or ligatures, and shows little tendency +to spread. The infected part, however, is often long of healing. The +irritation in these cases is probably due to toxins in the catgut and +not to bacteria. + +When suppuration occurs in connection with buried sutures of +unabsorbable materials, such as silk, silkworm gut, or silver wire, it +is apt to persist till the foreign material is cast off or removed. + +Suppuration may occur in the track of a skin stitch, producing a _stitch +abscess_. The infection may arise from the material used, especially +catgut or silk, or, more frequently perhaps, from the growth of +staphylococcus albus from the skin of the patient when this has been +imperfectly disinfected. The formation of pus under these conditions may +not be attended with any of the usual signs of suppuration, and beyond +some induration around the wound and a slight tenderness on pressure +there may be nothing to suggest the presence of an abscess. + +_Acute Suppuration of a Mucous Membrane._--When pyogenic organisms gain +access to a mucous membrane, such as that of the bladder, urethra, or +middle ear, the usual phenomena of acute inflammation and suppuration +ensue, followed by the discharge of pus on the free surface. It would +appear that the most marked changes take place in the submucous tissue, +causing the covering epithelium in places to die and leave small +superficial ulcers, for example in gonorrhoeal urethritis, the +cicatricial contraction of the scar subsequently leading to the +formation of stricture. When mucous glands are present in the membrane, +the pus is mixed with mucus--_muco-pus_. + + +DIFFUSE CELLULITIS AND DIFFUSE SUPPURATION + +Cellulitis is an acute affection resulting from the introduction of some +organism--commonly the _streptococcus pyogenes_--into the cellular +connective tissue of the integument, intermuscular septa, tendon +sheaths, or other structures. Infection always takes place through a +breach of the surface, although this may be superficial and +insignificant, such as a pin-prick, a scratch, or a crack under a nail, +and the wound may have been healed for some time before the inflammation +becomes manifest. The cellulitis, also, may develop at some distance +from the seat of inoculation, the organisms having travelled by the +lymphatics. + +The virulence of the organisms, the loose, open nature of the tissues in +which they develop, and the free lymphatic circulation by means of which +they are spread, account for the diffuse nature of the process. +Sometimes numbers of cocci are carried for a considerable distance from +the primary area before they are arrested in the lymphatics, and thus +several patches of inflammation may appear with healthy areas between. + +The pus infiltrates the meshes of the cellular tissue, there is +sloughing of considerable portions of tissue of low vitality, such as +fat, fascia, or tendon, and if the process continues for some time +several collections of pus may form. + +_Clinical Features._--The reaction in cases of diffuse cellulitis is +severe, and is usually ushered in by a distinct chill or even a rigor, +while the temperature rises to 103 o, 104 o, or 105 o F. The pulse is +proportionately increased in frequency, and is small, feeble, and often +irregular. The face is flushed, the tongue dry and brown, and the +patient may become delirious, especially during the night. Leucocytosis +is present in cases of moderate severity; but in severe cases the +virulence of the toxins prevents reaction taking place, and leucocytosis +is absent. + +The local manifestations vary with the relation of the seat of the +inflammation to the surface. When the superficial cellular tissue is +involved, the skin assumes a dark bluish-red colour, is swollen, +oedematous, and the seat of burning pain. To the touch it is firm, hot, +and tender. When the primary focus is in the deeper tissues, the +constitutional disturbance is aggravated, while the local signs are +delayed, and only become prominent when pus forms and approaches the +surface. It is not uncommon for blebs containing dark serous fluid to +form on the skin. The infection frequently spreads along the line of the +main lymph vessels of the part (_septic lymphangitis_) and may reach the +lymph glands (_septic lymphadenitis_). + +With the formation of pus the skin becomes soft and boggy at several +points, and eventually breaks, giving exit to a quantity of thick +grumous discharge. Sometimes several small collections under the skin +fuse, and an abscess is formed in which fluctuation can be detected. +Occasionally gases are evolved in the tissues, giving rise to emphysema. +It is common for portions of fascia, ligaments, or tendons to slough, +and this may often be recognised clinically by a peculiar crunching or +grating sensation transmitted to the fingers on making firm pressure on +the part. + +If it is not let out by incision, the pus, travelling along the lines of +least resistance, tends to point at several places on the surface, or to +open into joints or other cavities. + +_Prognosis._--The occurrence of _septicaemia_ is the most serious risk, +and it is in cases of diffuse suppurative cellulitis that this form of +blood-poisoning assumes its most aggravated forms. The toxins of the +streptococci are exceedingly virulent, and induce local death of tissue +so rapidly that the protective emigration of leucocytes fails to take +place. In some cases the passage of masses of free cocci in the +lymphatics, or of infective emboli in the blood vessels, leads to the +formation of _pyogenic abscesses_ in vital organs, such as the brain, +lungs, liver, kidneys, or other viscera. _Haemorrhage_ from erosion of +arterial or venous trunks may take place and endanger life. + +_Treatment._--The treatment of diffuse cellulitis depends to a large +extent on the situation and extent of the affected area, and on the +stage of the process. + +_In the limbs_, for example, where the application of a constricting +band is practicable, Bier's method of inducing passive hyperaemia yields +excellent results. If pus is formed, one or more small incisions are +made and a light moist dressing placed over the wounds to absorb the +discharge, but no drain is inserted. The whole of the inflamed area +should be covered with gauze wrung out of a 1 in 10 solution of ichthyol +in glycerine. The dressing is changed as often as necessary, and in the +intervals when the band is off, gentle active and passive movements +should be carried out to prevent the formation of adhesions. After +incisions have been made, we have found the _immersion_ of the limb, for +a few hours at a time, in a water-bath containing warm boracic lotion or +eusol a useful adjuvant to the passive hyperaemia. + +_Continuous irrigation_ of the part by a slow, steady stream of lotion, +at the body temperature, such as eusol, or Dakin's solution, or boracic +acid, or frequent washing with peroxide of hydrogen, has been found of +value. + +A suitably arranged splint adds to the comfort of the patient; and the +limb should be placed in the attitude which, in the event of stiffness +resulting, will least interfere with its usefulness. The elbow, for +example, should be flexed to a little less than a right angle; at the +wrist, the hand should be dorsiflexed and the fingers flexed slightly +towards the palm. + +Massage, passive movement, hot and cold douching, and other measures, +may be necessary to get rid of the chronic oedema, adhesions of tendons, +and stiffness of joints which sometimes remain. + +In situations where a constricting band cannot be applied, for example, +on the trunk or the neck, Klapp's suction bells may be used, small +incisions being made to admit of the escape of pus. + +If these measures fail or are impracticable, it may be necessary to make +one or more free incisions, and to insert drainage-tubes, portions of +rubber dam, or iodoform worsted. + +The general treatment of toxaemia must be carried out, and in cases due +to infection by streptococci, anti-streptococcic serum may be used. + +In a few cases, amputation well above the seat of disease, by removing +the source of toxin production, offers the only means of saving the +patient. + + +WHITLOW + +The clinical term whitlow is applied to an acute infection, usually +followed by suppuration, commonly met with in the fingers, less +frequently in the toes. The point of infection is often trivial--a +pin-prick, a puncture caused by a splinter of wood, a scratch, or even +an imperceptible lesion of the skin. + +Several varieties of whitlow are recognised, but while it is convenient +to describe them separately, it is to be clearly understood that +clinically they merge one into another, and it is not always possible to +determine in which connective-tissue plane a given infection has +originated. + +_Initial Stage._--Attention is usually first attracted to the condition +by a sensation of tightness in the finger and tenderness when the part +is squeezed or knocked against anything. In the course of a few hours +the part becomes red and swollen; there is continuous pain, which soon +assumes a throbbing character, particularly when the hand is dependent, +and may be so severe as to prevent sleep, and the patient may feel +generally out of sorts. + +If a constricting band is applied at this stage, the infection can +usually be checked and the occurrence of suppuration prevented. If this +fails, or if the condition is allowed to go untreated, the inflammatory +reaction increases and terminates in suppuration, giving rise to one or +other of the forms of whitlow to be described. + +_The Purulent Blister._--In the most superficial variety, pus forms +between the rete Malpighii and the stratum corneum of the skin, the +latter being raised as a blister in which fluctuation can be detected +(Fig. 9, a). This is commonly met with in the palm of the hand of +labouring men who have recently resumed work after a spell of idleness. +When the blister forms near the tip of the finger, the pus burrows under +the nail--which corresponds to the stratum corneum--raising it from its +bed. + +There is some local heat and discoloration, and considerable pain and +tenderness, but little or no constitutional disturbance. Superficial +lymphangitis may extend a short distance up the forearm. By clipping +away the raised epidermis, and if necessary the nail, the pus is allowed +to escape, and healing speedily takes place. + +_Whitlow at the Nail Fold._--This variety, which is met with among those +who handle septic material, occurs in the sulcus between the nail and +the skin, and is due to the introduction of infective matter at the root +of the nail (Fig. 9, b). A small focus of suppuration forms under the +nail, with swelling and redness of the nail fold, causing intense pain +and discomfort, interfering with sleep, and producing a constitutional +reaction out of all proportion to the local lesion. + +To allow the pus to escape, it is necessary, under local anaesthesia, to +cut away the nail fold as well as the portion of nail in the infected +area, or, it may be, to remove the nail entirely. If only a small +opening is made in the nail it is apt to be blocked by granulations. + +[Illustration: FIG. 9.--Diagram of various forms of Whitlow. + a = Purulent blister. + b = Suppuration at nail fold. + c = Subcutaneous whitlow. + d = Whitlow in sheath of flexor tendon (e). ] + +_Subcutaneous Whitlow._--In this variety the infection manifests itself +as a cellulitis of the pulp of the finger (Fig. 9, c), which sometimes +spreads towards the palm of the hand. The finger becomes red, swollen, +and tense; there is severe throbbing pain, which is usually worst at +night and prevents sleep, and the part is extremely tender on pressure. +When the palm is invaded there may be marked oedema of the back of the +hand, the dense integument of the palm preventing the swelling from +appearing on the front. The pus may be under such tension that +fluctuation cannot be detected. The patient is usually able to flex the +finger to a certain extent without increasing the pain--a point which +indicates that the tendon sheaths have not been invaded. The +suppurative process may, however, spread to the tendon sheaths, or even +to the bone. Sometimes the excessive tension and virulent toxins induce +actual gangrene of the distal part, or even of the whole finger. There +is considerable constitutional disturbance, the temperature often +reaching 101 o or 102 o F. + +The treatment consists in applying a constriction band and making an +incision over the centre of the most tender area, care being taken to +avoid opening the tendon sheath lest the infection be conveyed to it. +Moist dressings should be employed while the suppuration lasts. Carbolic +fomentations, however, are to be avoided on account of the risk of +inducing gangrene. + +_Whitlow of the Tendon Sheaths._--In this form the main incidence of the +infection is on the sheaths of the flexor tendons, but it is not always +possible to determine whether it started there or spread thither from +the subcutaneous cellular tissue (Fig. 9, d). In some cases both +connective tissue planes are involved. The affected finger becomes red, +painful, and swollen, the swelling spreading to the dorsum. The +involvement of the tendon sheath is usually indicated by the patient +being unable to flex the finger, and by the pain being increased when he +attempts to do so. On account of the anatomical arrangement of the +tendon sheaths, the process may spread into the forearm--directly in the +case of the thumb and little finger, and after invading the palm in the +case of the other fingers--and there give rise to a diffuse cellulitis +which may result in sloughing of fasciae and tendons. When the infection +spreads into the common flexor sheath under the transverse carpal +(anterior annular) ligament, it is not uncommon for the intercarpal and +wrist joints to become implicated. Impaired movement of tendons and +joints is, therefore, a common sequel to this variety of whitlow. + +The _treatment_ consists in inducing passive hyperaemia by Bier's method, +and, if this is done early, suppuration may be avoided. If pus forms, +small incisions are made, under local anaesthesia, to relieve the tension +in the sheath and to diminish the risk of the tendons sloughing. No form +of drain should be inserted. In the fingers the incisions should be made +in the middle line, and in the palm they should be made over the +metacarpal bones to avoid the digital vessels and nerves. If pus has +spread under the transverse carpal ligament, the incision must be made +above the wrist. Passive movements and massage must be commenced as +early as possible and be perseveringly employed to diminish the +formation of adhesions and resulting stiffness. + +_Subperiosteal Whitlow._--This form is usually an extension of the +subcutaneous or of the thecal variety, but in some cases the +inflammation begins in the periosteum--usually of the terminal phalanx. +It may lead to necrosis of a portion or even of the entire phalanx. This +is usually recognised by the persistence of suppuration long after the +acute symptoms have passed off, and by feeling bare bone with the probe. +In such cases one or more of the joints are usually implicated also, and +lateral mobility and grating may be elicited. Recovery does not take +place until the dead bone is removed, and the usefulness of the finger +is often seriously impaired by fibrous or bony ankylosis of the +interphalangeal joints. This may render amputation advisable when a +stiff finger is likely to interfere with the patient's occupation. + + +SUPPURATIVE CELLULITIS IN DIFFERENT SITUATIONS + +_Cellulitis of the forearm_ is usually a sequel to one of the deeper +varieties of whitlow. + +In the _region of the elbow-joint_, cellulitis is common around the +olecranon. It may originate as an inflammation of the olecranon bursa, +or may invade the bursa secondarily. In exceptional cases the +elbow-joint is also involved. + +Cellulitis of the _axilla_ may originate in suppuration in the lymph +glands, following an infected wound of the hand, or it may spread from a +septic wound on the chest wall or in the neck. In some cases it is +impossible to discover the primary seat of infection. A firm, brawny +swelling forms in the armpit and extends on to the chest wall. It is +attended with great pain, which is increased on moving the arm, and +there is marked constitutional disturbance. When suppuration occurs, its +spread is limited by the attachments of the axillary fascia, and the pus +tends to burrow on to the chest wall beneath the pectoral muscles, and +upwards towards the shoulder-joint, which may become infected. When the +pus forms in the axillary space, the treatment consists in making free +incisions, which should be placed on the thoracic side of the axilla to +avoid the axillary vessels and nerves. If the pus spreads on to the +chest wall, the abscess should be opened below the clavicle by Hilton's +method, and a counter opening may be made in the axilla. + +Cellulitis of the _sole of the foot_ may follow whitlow of the toes. + +In the _region of the ankle_ cellulitis is not common; but _around the +knee_ it frequently occurs in relation to the prepatellar bursa and to +the popliteal lymph glands, and may endanger the knee-joint. It is also +met with in the _groin_ following on inflammation and suppuration of the +inguinal glands, and cases are recorded in which the sloughing process +has implicated the femoral vessels and led to secondary haemorrhage. + +Cellulitis of the scalp, orbit, neck, pelvis, and perineum will be +considered with the diseases of these regions. + + +CHRONIC SUPPURATION + +While it is true that a chronic pyogenic abscess is sometimes met +with--for example, in the breast and in the marrow of long bones--in the +great majority of instances the formation of a chronic or cold abscess +is the result of the action of the tubercle bacillus. It is therefore +more convenient to study this form of suppuration with tuberculosis +(p. 139). + + +SINUS AND FISTULA + +#Sinus.#--A sinus is a track leading from a focus of suppuration to a +cutaneous or mucous surface. It usually represents the path by which the +discharge escapes from an abscess cavity that has been prevented from +closing completely, either from mechanical causes or from the persistent +formation of discharge which must find an exit. A sinus is lined by +granulation tissue, and when it is of long standing the opening may be +dragged below the level of the surrounding skin by contraction of the +scar tissue around it. As a sinus will persist until the obstacle to +closure of the original abscess is removed, it is necessary that this +should be sought for. It may be a foreign body, such as a piece of dead +bone, an infected ligature, or a bullet, acting mechanically or by +keeping up discharge, and if the body is removed the sinus usually +heals. The presence of a foreign body is often suggested by a mass of +redundant granulations at the mouth of the sinus. If a sinus passes +through a muscle, the repeated contractions tend to prevent healing +until the muscle is kept at rest by a splint, or put out of action by +division of its fibres. The sinuses associated with empyema are +prevented from healing by the rigidity of the chest wall, and will only +close after an operation which admits of the cavity being obliterated. +In any case it is necessary to disinfect the track, and, it may be, to +remove the unhealthy granulations lining it, by means of the sharp +spoon, or to excise it bodily. To encourage healing from the bottom the +cavity should be packed with bismuth or iodoform gauze. The healing of +long and tortuous sinuses is often hastened by the injection of Beck's +bismuth paste (p. 145). If disfigurement is likely to follow from +cicatricial contraction--for example, in a sinus over the lower jaw +associated with a carious tooth--the sinus should be excised and the raw +surfaces approximated with stitches. + +The _tuberculous sinus_ is described under Tuberculosis. + +A #fistula# is an abnormal canal passing from a mucous surface to the +skin or to another mucous surface. Fistulae resulting from suppuration +usually occur near the natural openings of mucous canals--for example, +on the cheek, as a salivary fistula; beside the inner angle of the eye, +as a lacrymal fistula; near the ear, as a mastoid fistula; or close to +the anus, as a fistula-in-ano. Intestinal fistulae are sometimes met with +in the abdominal wall after strangulated hernia, operations for +appendicitis, tuberculous peritonitis, and other conditions. In the +perineum, fistulae frequently complicate stricture of the urethra. + +Fistulae also occur between the bladder and vagina (_vesico-vaginal +fistula_), or between the bladder and the rectum (_recto-vesical +fistula_). + +The _treatment_ of these various forms of fistula will be described in +the sections dealing with the regions in which they occur. + +_Congenital fistulae_, such as occur in the neck from imperfect closure +of branchial clefts, or in the abdomen from unobliterated foetal ducts +such as the urachus or Meckel's diverticulum, will be described in their +proper places. + + +CONSTITUTIONAL MANIFESTATIONS OF PYOGENIC INFECTION + +We have here to consider under the terms Sapraemia, Septicaemia, and +Pyaemia certain general effects of pyogenic infection, which, although +their clinical manifestations may vary, are all associated with the +action of the same forms of bacteria. They may occur separately or in +combination, or one may follow on and merge into another. + +#Sapraemia#, or septic intoxication, is the name applied to a form of +poisoning resulting from the absorption into the blood of the toxic +products of pyogenic bacteria. These products, which are of the nature +of alkaloids, act immediately on their entrance into the circulation, +and produce effects in direct proportion to the amount absorbed. As the +toxins are gradually eliminated from the body the symptoms abate, and if +no more are introduced they disappear. Sapraemia in these respects, +therefore, is comparable to poisoning by any other form of alkaloid, +such as strychnin or morphin. + +_Clinical Features._--The symptoms of sapraemia seldom manifest +themselves within twenty-four hours of an operation or injury, because +it takes some time for the bacteria to produce a sufficient dose of +their poisons. The onset of the condition is marked by a feeling of +chilliness, sometimes amounting to a rigor, and a rise of temperature to +102 o, 103 o, or 104 o F., with morning remissions (Fig. 10). The heart's +action is markedly depressed, and the pulse is soft and compressible. +The appetite is lost, the tongue dry and covered with a thin +brownish-red fur, so that it has the appearance of "dried beef." The +urine is scanty and loaded with urates. In severe cases diarrhoea and +vomiting of dark coffee-ground material are often prominent features. +Death is usually impending when the skin becomes cold and clammy, the +mucous membranes livid, the pulse feeble and fluttering, the discharges +involuntary, and when a low form of muttering delirium is present. + +[Illustration: FIG. 10.--Charts of Acute sapraemia from (a) case of +crushed foot, and (b) case of incomplete abortion.] + +A local form of septic infection is always present--it may be an +abscess, an infected compound fracture, or an infection of the cavity of +the uterus, for example, from a retained portion of placenta. + +_Treatment._--The first indication is the immediate and complete removal +of the infected material. The wound must be freely opened, all +blood-clot, discharge, or necrosed tissue removed, and the area +disinfected by washing with sterilised salt solution, peroxide of +hydrogen, or eusol. Stronger lotions are to be avoided as being likely +to depress the tissues, and so interfere with protective phagocytosis. +On account of its power of neutralising toxins, iodoform is useful in +these cases, and is best employed by packing the wound with iodoform +gauze, and treating it by the open method, if this is possible. + +The general treatment is carried out on the same lines as for other +infective conditions. + +#Chronic sapraemia or Hectic Fever.#--Hectic fever differs from acute +sapraemia merely in degree. It usually occurs in connection with +tuberculous conditions, such as bone or joint disease, psoas abscess, or +empyema, which have opened externally, and have thereby become infected +with pyogenic organisms. It is gradual in its development, and is of a +mild type throughout. + +[Illustration: FIG. 11.--Chart of Hectic Fever.] + +The pulse is small, feeble, and compressible, and the temperature rises +in the afternoon or evening to 102 o or 103 o F. (Fig. 11), the cheeks +becoming characteristically flushed. In the early morning the +temperature falls to normal or below it, and the patient breaks into a +profuse perspiration, which leaves him pale, weak, and exhausted. He +becomes rapidly and markedly emaciated, even although in some cases the +appetite remains good and is even voracious. + +The poisons circulating in the blood produce _waxy degeneration_ in +certain viscera, notably the liver, spleen, kidneys, and intestines. The +process begins in the arterial walls, and spreads thence to the +connective-tissue structures, causing marked enlargement of the affected +organs. Albuminuria, ascites, oedema of the lower limbs, clubbing of the +fingers, and diarrhoea are among the most prominent symptoms of this +condition. + +The _prognosis_ in hectic fever depends on the completeness with which +the further absorption of toxins can be prevented. In many cases this +can only be effected by an operation which provides for free drainage, +and, if possible, the removal of infected tissues. The resulting wound +is best treated by the open method. Even advanced waxy degeneration does +not contra-indicate this line of treatment, as the diseased organs +usually recover if the focus from which absorption of toxic material is +taking place is completely eradicated. + +[Illustration: FIG. 12.--Chart of case of Septicaemia followed by +Pyaemia.] + +#Septicaemia.#--This form of blood-poisoning is the result of the action +of pyogenic bacteria, which not only produce their toxins at the primary +seat of infection, but themselves enter the blood-stream and are carried +to other parts, where they settle and produce further effects. + +_Clinical Features._--There may be an incubation period of some hours +between the infection and the first manifestation of acute septicaemia. +In such conditions as acute osteomyelitis or acute peritonitis, we see +the most typical clinical pictures of this condition. The onset is +marked by a chill, or a rigor, which may be repeated, while the +temperature rises to 103 o or 104 o F., although in very severe cases the +temperature may remain subnormal throughout, the virulence of the toxins +preventing reaction. It is in the general appearance of the patient and +in the condition of the pulse that we have our best guides as to the +severity of the condition. If the pulse remains firm, full, and regular, +and does not exceed 110 or even 120, while the temperature is moderately +raised, the outlook is hopeful; but when the pulse becomes small and +compressible, and reaches 130 or more, especially if at the same time +the temperature is low, a grave prognosis is indicated. The tongue is +often dry and coated with a black crust down the centre, while the sides +are red. It is a good omen when the tongue becomes moist again. Thirst +is most distressing, especially in septicaemia of intestinal origin. +Persistent vomiting of dark-brown material is often present, and +diarrhoea with blood-stained stools is not uncommon. The urine is small +in amount, and contains a large proportion of urates. As the poisons +accumulate, the respiration becomes shallow and laboured, the face of a +dull ashy grey, the nose pinched, and the skin cold and clammy. +Capillary haemorrhages sometimes take place in the skin or mucous +membranes; and in a certain proportion of cases cutaneous eruptions +simulating those of scarlet fever or measles appear, and are apt to lead +to errors in diagnosis. In other cases there is slight jaundice. The +mental state is often one of complete apathy, the patient failing to +realise the gravity of his condition; sometimes there is delirium. + +The _prognosis_ is always grave, and depends on the possibility of +completely eradicating the focus of infection, and on the reserve force +the patient has to carry him over the period during which he is +eliminating the poison already circulating in his blood. + +The _treatment_ is carried out on the same lines as in sapraemia, but it +is less likely to be successful owing to the organisms having entered +the circulation. When possible, the primary focus of infection should be +dealt with. + +#Pyaemia# is a form of blood-poisoning characterised by the development +of secondary foci of suppuration in different parts of the body. Toxins +are thus introduced into the blood, not only at the primary seat of +infection, but also from each of these metastatic collections. Like +septicaemia, this condition is due to pyogenic bacteria, the +_streptococcus pyogenes_ being the commonest organism found. The primary +infection is usually in a wound--for example, a compound fracture--but +cases occur in which the point of entrance of the bacteria is not +discoverable. The dissemination of the organisms takes place through the +medium of infected emboli which form in a thrombosed vein in the +vicinity of the original lesion, and, breaking loose, are carried +thence in the blood-stream. These emboli lodge in the minute vessels of +the lungs, spleen, liver, kidneys, pleura, brain, synovial membranes, or +cellular tissue, and the bacteria they contain give rise to secondary +foci of suppuration. Secondary abscesses are thus formed in those parts, +and these in turn may be the starting-point of new emboli which give +rise to fresh areas of pus formation. The organs above named are the +commonest situations of pyaemic abscesses, but these may also occur in +the bone marrow, the substance of muscles, the heart and pericardium, +lymph glands, subcutaneous tissue, or, in fact, in any tissue of the +body. Organisms circulating in the blood are prone to lodge on the +valves of the heart and give rise to endocarditis. + +[Illustration: FIG. 13.--Chart of Pyaemia following on Acute +Osteomyelitis.] + +_Clinical Features._--Before antiseptic surgery was practised, pyaemia +was a common complication of wounds. In the present day it is not only +infinitely less common, but appears also to be of a less severe type. +Its rarity and its mildness may be related as cause and effect, because +it was formerly found that pyaemia contracted from a pyaemic patient was +more virulent than that from other sources. + +In contrast with sapraemia and septicaemia, pyaemia is late of developing, +and it seldom begins within a week of the primary infection. The first +sign is a feeling of chilliness, or a violent rigor lasting for perhaps +half an hour, during which time the temperature rises to 103 o, 104 o, or +105 o F. In the course of an hour it begins to fall again, and the +patient breaks into a profuse sweat. The temperature may fall several +degrees, but seldom reaches the normal. In a few days there is a second +rigor with rise of temperature, and another remission, and such attacks +may be repeated at diminishing intervals during the course of the +illness (Figs. 12 and 13). The pulse is soft, and tends to remain +abnormally rapid even when the temperature falls nearly to normal. + +The face is flushed, and wears a drawn, anxious expression, and the eyes +are bright. A characteristic sweetish odour, which has been compared to +that of new-mown hay, can be detected in the breath and may pervade the +patient. The appetite is lost; there may be sickness and vomiting and +profuse diarrhoea; and the patient emaciates rapidly. The skin is +continuously hot, and has often a peculiar pungent feel. Patches of +erythema sometimes appear scattered over the body. The skin may assume a +dull sallow or earthy hue, or a bright yellow icteric tint may appear. +The conjunctivae also may be yellow. In the latter stages of the disease +the pulse becomes small and fluttering; the tongue becomes dry and +brown; sordes collect on the teeth; and a low muttering form of delirium +supervenes. + +Secondary infection of the parotid gland frequently occurs, and gives +rise to a suppurative parotitis. This condition is associated with +severe pain, gradually extending from behind the angle of the jaw on to +the face. There is also swelling over the gland, and eventually +suppuration and sloughing of the gland tissue and overlying skin. + +Secondary abscesses in the lymph glands, subcutaneous tissue, or joints +are often so insidious and painless in their development that they are +only discovered accidentally. When the abscess is evacuated, healing +often takes place with remarkable rapidity, and with little impairment +of function. + +The general symptoms may be simulated by an attack of malaria. + +_Prognosis._--The prognosis in acute pyaemia is much less hopeless than +it once was, a considerable proportion of the patients recovering. In +acute cases the disease proves fatal in ten days or a fortnight, death +being due to toxaemia. Chronic cases often run a long course, lasting for +weeks or even months, and prove fatal from exhaustion and waxy disease +following on prolonged suppuration. + +_Treatment._--In such conditions as compound fractures and severe +lacerated wounds, much can be done to avert the conditions which lead to +pyaemia, by applying a Bier's constricting bandage as soon as there is +evidence of infection having taken place, or even if there is reason to +suspect that the wound is not aseptic. + +If sepsis is already established, and evidence of general infection is +present, the wound should be opened up sufficiently to admit of thorough +disinfection and drainage, and the constricting bandage applied to aid +the defensive processes going on in the tissues. If these measures fail, +amputation of the limb may be the only means of preventing further +dissemination of infective material from the primary source of +infection. + +Attempts have been made to interrupt the channel along which the +infective emboli spread, by ligating or resecting the main vein of the +affected part, but this is seldom feasible except in the case of the +internal jugular vein for infection of the transverse sinus. + +Secondary abscesses must be aspirated or opened and drained whenever +possible. + +The general treatment is conducted on the same lines as on other forms +of pyogenic infection. + + + + +CHAPTER V + +ULCERATION AND ULCERS + + +Definitions--Clinical examination of an ulcer--The healing + sore.--Classification of ulcers--A. According to cause: + _Traumatism_, _Imperfect circulation_, _Imperfect nerve-supply_, + _Constitutional causes_--B. According to condition: _Healing_, + _Stationary_, _Spreading_.--Treatment. + +The process of _ulceration_ may be defined as the molecular or cellular +death of tissue taking place on a free surface. It is essentially of the +same nature as the process of suppuration, only that the purulent +discharge, instead of collecting in a closed cavity and forming an +abscess, at once escapes on the surface. + +An _ulcer_ is an open wound or sore in which there are present certain +conditions tending to prevent it undergoing the natural process of +repair. Of these, one of the most important is the presence of +pathogenic bacteria, which by their action not only prevent healing, but +so irritate and destroy the tissues as to lead to an actual increase in +the size of the sore. Interference with the nutrition of a part by oedema +or chronic venous congestion may impede healing; as may also induration +of the surrounding area, by preventing the contraction which is such an +important factor in repair. Defective innervation, such as occurs in +injuries and diseases of the spinal cord, also plays an important part +in delaying repair. In certain constitutional conditions, too--for +example, Bright's disease, diabetes, or syphilis--the vitiated state of +the tissues is an impediment to repair. Mechanical causes, such as +unsuitable dressings or ill-fitting appliances, may also act in the same +direction. + +#Clinical Examination of an Ulcer.#--In examining any ulcer, we +observe--(1) Its _base_ or _floor_, noting the presence or absence of +granulations, their disposition, size, colour, vascularity, and whether +they are depressed or elevated in relation to the surrounding parts. (2) +The _discharge_ as to quantity, consistence, colour, composition, and +odour. (3) The _edges_, noting particularly whether or not the marginal +epithelium is attempting to grow over the surface; also their shape, +regularity, thickness, and whether undermined or overlapping, everted or +depressed. (4) The _surrounding tissues_, as to whether they are +congested, oedematous, inflamed, indurated, or otherwise. (5) Whether or +not there is _pain_ or tenderness in the raw surface or its +surroundings. (6) The _part of the body_ on which it occurs, because +certain ulcers have special seats of election--for example, the varicose +ulcer in the lower third of the leg, the perforating ulcer on the sole +of the foot, and so on. + +#The Healing Sore.#--If a portion of skin be excised aseptically, and no +attempt made to close the wound, the raw surface left is soon covered +over with a layer of coagulated blood and lymph. In the course of a few +days this is replaced by the growth of _granulations_, which are of +uniform size, of a pinkish-red colour, and moist with a slight serous +exudate containing a few dead leucocytes. They grow until they reach the +level of the surrounding skin, and so fill the gap with a fine velvety +mass of granulation tissue. At the edges, the young epithelium may be +seen spreading in over the granulations as a fine bluish-white pellicle, +which gradually covers the sore, becoming paler in colour as it +thickens, and eventually forming the smooth, non-vascular covering of +the cicatrix. There is no pain, and the surrounding parts are healthy. + +This may be used as a type with which to compare the ulcers seen at the +bedside, so that we may determine how far, and in what particulars, +these differ from the type; and that we may in addition recognise the +conditions that have to be counteracted before the characters of the +typical healing sore are assumed. + +For purposes of contrast we may indicate the characters of an open sore +in which bacterial infection with pathogenic bacteria has taken place. +The layer of coagulated blood and lymph becomes liquefied and is thrown +off, and instead of granulations being formed, the tissues exposed on +the floor of the ulcer are destroyed by the bacterial toxins, with the +formation of minute sloughs and a quantity of pus. + +The discharge is profuse, thin, acrid, and offensive, and consists of +pus, broken-down blood-clot, and sloughs. The edges are inflamed, +irregular, and ragged, showing no sign of growing epithelium--on the +contrary, the sore may be actually increasing in area by the +breaking-down of the tissues at its margins. The surrounding parts are +hot, red, swollen, and oedematous; and there is pain and tenderness both +in the sore itself and in the parts around. + +#Classification of Ulcers.#--The nomenclature of ulcers is much involved +and gives rise to great confusion, chiefly for the reason that no one +basis of classification has been adopted. Thus some ulcers are named +according to the causes at work in producing or maintaining them--for +example, the traumatic, the septic, and the varicose ulcer; some from +the constitutional element present, as the gouty and the diabetic ulcer; +and others according to the condition in which they happen to be when +seen by the surgeon, such as the weak, the inflamed, and the callous +ulcer. + +So long as we retain these names it will be impossible to find a single +basis for classification; and yet many of the terms are so descriptive +and so generally understood that it is undesirable to abolish them. We +must therefore remain content with a clinical arrangement of ulcers,--it +cannot be called a classification,--considering any given ulcer from two +points of view: first its _cause_, and second its _present condition_. +This method of studying ulcers has the practical advantage that it +furnishes us with the main indications for treatment as well as for +diagnosis: the cause must be removed, and the condition so modified as +to convert the ulcer into an aseptic healing sore. + +A. #Arrangement of Ulcers according to their Cause.#--Although any given +ulcer may be due to a combination of causes, it is convenient to +describe the following groups: + +_Ulcers due to Traumatism._--Traumatism in the form of a _crush_ or +_bruise_ is a frequent cause of ulcer formation, acting either by +directly destroying the skin, or by so diminishing its vitality that it +is rendered a suitable soil for bacteria. If these gain access, in the +course of a few days the damaged area of skin becomes of a greyish +colour, blebs form on it, and it undergoes necrosis, leaving an +unhealthy raw surface when the slough separates. + +_Heat_ and _prolonged exposure to the Rontgen rays_ or _to radium +emanations_ act in a similar way. + +The _pressure_ of improperly padded splints or other appliances may so +far interfere with the circulation of the part pressed upon, that the +skin sloughs, leaving an open sore. This is most liable to occur in +patients who suffer from some nerve lesion--such as anterior +poliomyelitis, or injury of the spinal cord or nerve-trunks. +Splint-pressure sores are usually situated over bony prominences, such +as the malleoli, the condyles of the femur or humerus, the head of the +fibula, the dorsum of the foot, or the base of the fifth metatarsal +bone. On removing the splint, the skin of the part pressed upon is found +to be of a red or pink colour, with a pale grey patch in the centre, +which eventually sloughs and leaves an ulcer. Certain forms of +_bed-sore_ are also due to prolonged pressure. + +Pressure sores are also known to have been produced artificially by +malingerers and hysterical subjects. + +[Illustration: FIG. 14.--Leg Ulcers associated with Varicose Veins and +Pigmentation of the Skin.] + +_Ulcers due to Imperfect Circulation._--Imperfect circulation is an +important causative factor in ulceration, especially when it is the +_venous return_ that is defective. This is best illustrated in the +so-called _leg ulcer_, which occurs most frequently on the front and +medial aspect of the lower third of the leg. At this point the +anastomosis between the superficial and deep veins of the leg is less +free than elsewhere, so that the extra stress thrown upon the surface +veins interferes with the nutrition of the skin (Hilton). The importance +of imperfect venous return in the causation of such ulcers is evidenced +by the fact that as soon as the condition of the circulation is improved +by confining the patient to bed and elevating the limb, the ulcer begins +to heal, even although all methods of local treatment have hitherto +proved ineffectual. In a considerable number of cases, but by no means +in all, this form of ulcer is associated with the presence of varicose +veins, and in such cases it is spoken of as the _varicose ulcer_ (Fig. 14). +The presence of varicose veins is frequently associated with a +diffuse brownish or bluish pigmentation of the skin of the lower third +of the leg, or with an obstinate form of dermatitis (_varicose eczema_), +and the scratching or rubbing of the part is liable to cause a breach of +the surface and permit of infection which leads to ulceration. Varicose +ulcers may also originate from the bursting of a small peri-phlebitic +abscess. + +Varicose veins in immediate relation to the base of a large chronic +ulcer usually become thrombosed, and in time are reduced to fibrous +cords, and therefore in such cases haemorrhage is not a common +complication. In smaller and more superficial ulcers, however, the +destructive process is liable to implicate the wall of the vessel before +the occurrence of thrombosis, and to lead to profuse and it may be +dangerous bleeding. + +These ulcers are at first small and superficial, but from want of care, +from continued standing or walking, or from injudicious treatment, they +gradually become larger and deeper. They are not infrequently multiple, +and this, together with their depth, may lead to their being mistaken +for ulcers due to syphilis. The base of the ulcer is covered with +imperfectly formed, soft, oedematous granulations, which give off a thin +sero-purulent discharge. The edges are slightly inflamed, and show no +evidence of healing. The parts around are usually pigmented and slightly +oedematous, and as a rule there is little pain. This variety of ulcer is +particularly prone to pass into the condition known as callous. + +In _anaemic_ patients, especially young girls, ulcers are occasionally +met with which have many of the clinical characters of those associated +with imperfect venous return. They are slow to heal, and tend to pass +into the condition known as weak. + +_Ulcers due to Interference with Nerve-Supply._--Any interference with +the nerve-supply of the superficial tissues predisposes to ulceration. +For example, _trophic_ ulcers are liable to occur in injuries or +diseases of the spinal cord, in cerebral paralysis, in limbs weakened by +poliomyelitis, in ascending or peripheral neuritis, or after injuries of +nerve-trunks. + +The _acute bed-sore_ is a rapidly progressing form of ulceration, often +amounting to gangrene, of portions of skin exposed to pressure when +their trophic nerve-supply has been interfered with. + +[Illustration: FIG. 15.--Perforating Ulcers of Sole of Foot. + +(From Photograph lent by Sir Montagu Cotterill.)] + +The _perforating ulcer of the foot_ is a peculiar type of sore which +occurs in association with the different forms of peripheral neuritis, +and with various lesions of the brain and spinal cord, such as general +paralysis, locomotor ataxia, or syringo-myelia (Fig. 15). It also occurs +in patients suffering from glycosuria, and is usually associated with +arterio-sclerosis--local or general. Perforating ulcer is met with most +frequently under the head of the metatarsal bone of the great toe. A +callosity forms and suppuration occurs under it, the pus escaping +through a small hole in the centre. The process slowly and gradually +spreads deeper and deeper, till eventually the bone or joint is reached, +and becomes implicated in the destructive process--hence the term +"perforating ulcer." The flexor tendons are sometimes destroyed, the toe +being dorsiflexed by the unopposed extensors. The depth of the track +being so disproportionate to its superficial area, the condition closely +simulates a tuberculous sinus, for which it is liable to be mistaken. +The raw surface is absolutely insensitive, so that the probe can be +freely employed without the patient even being aware of it or suffering +the least discomfort--a significant fact in diagnosis. The cavity is +filled with effete and decomposing epidermis, which has a most offensive +odour. The chronic and intractable character of the ulcer is due to +interference with the trophic nerve-supply of the parts, and to the fact +that the epithelium of the skin grows in and lines the track leading +down to the deepest part of the ulcer and so prevents closure. While +they are commonest on the sole of the foot and other parts subjected to +pressure, perforating ulcers are met with on the sides and dorsum of the +foot and toes, on the hands, and on other parts where no pressure has +been exerted. + +The _tuberculous ulcer_, so often seen in the neck, in the vicinity of +joints, or over the ribs and sternum, usually results from the bursting +through the skin of a tuberculous abscess. The base is soft, pale, and +covered with feeble granulations and grey shreddy sloughs. The edges are +of a dull blue or purple colour, and gradually thin out towards their +free margins, and in addition are characteristically undermined, so that +a probe can be passed for some distance between the floor of the ulcer +and the thinned-out edges. Thin, devitalised tags of skin often stretch +from side to side of the ulcer. The outline is irregular; small +perforations often occur through the skin, and a thin, watery discharge, +containing grey shreds of tuberculous debris, escapes. + +_Bazin's Disease._--This term is applied to an affection of the skin and +subcutaneous tissue which bears certain resemblances to tuberculosis. It +is met with almost exclusively between the knee and the ankle, and it +usually affects both legs. It is commonest in girls of delicate +constitution, in whose family history there is evidence of a tuberculous +taint. The patient often presents other lesions of a tuberculous +character, notably enlarged cervical glands, and phlyctenular +ophthalmia. The tubercle bacillus has rarely been found, but we have +always observed characteristic epithelioid cells and giant cells in +sections made from the edge or floor of the ulcer. + +[Illustration: FIG. 16.--Bazin's Disease in a girl aet. 16.] + +The condition begins by the formation in the skin and subcutaneous +tissue of dusky or livid nodules of induration, which soften and +ulcerate, forming small open sores with ragged and undermined edges, not +unlike those resulting from the breaking down of superficial syphilitic +gummata (Fig. 16). Fresh crops of nodules appear in the neighbourhood of +the ulcers, and in turn break down. While in the nodular stage the +affection is sometimes painful, but with the formation of the ulcer the +pain subsides. + +The disease runs a chronic course, and may slowly extend over a wide +area in spite of the usual methods of treatment. After lasting for some +months, or even years, however, it may eventually undergo spontaneous +cure. The most satisfactory treatment is to excise the affected tissues +and fill the gap with skin-grafts. + +[Illustration: FIG. 17.--Syphilitic Ulcers in region of Knee, showing +punched-out appearance and raised indurated edges.] + +The _syphilitic ulcer_ is usually formed by the breaking down of a +cutaneous or subcutaneous gumma in the tertiary stage of syphilis. When +the gummatous tissue is first exposed by the destruction of the skin or +mucous membrane covering it, it appears as a tough greyish slough, +compared to "wash leather," which slowly separates and leaves a more or +less circular, deep, punched-out gap which shows a few feeble unhealthy +granulations and small sloughs on its floor. The edges are raised and +indurated; and the discharge is thick, glairy, and peculiarly offensive. +The parts around the ulcer are congested and of a dark brown colour. +There are usually several such ulcers together, and as they tend to heal +at one part while they spread at another, the affected area assumes a +sinuous or serpiginous outline. Syphilitic ulcers may be met with in any +part of the body, but are most frequent in the upper part of the leg +(Fig. 17), especially around the knee-joint in women, and over the ribs +and sternum. On healing, they usually leave a depressed and adherent +cicatrix. + +The _scorbutic ulcer_ occurs in patients suffering from scurvy, and is +characterised by its prominent granulations, which show a marked +tendency to bleed, with the formation of clots, which dry and form a +spongy crust on the surface. + +In _gouty_ patients small ulcers which are exceedingly irritable and +painful are liable to occur. + +_Ulcers associated with Malignant Disease._--Cancer and sarcoma when +situated in the subcutaneous tissue may destroy the overlying skin so +that the substance of the tumour is exposed. The fungating masses thus +produced are sometimes spoken of as malignant ulcers, but as they are +essentially different in their nature from all other forms of ulcers, +and call for totally different treatment, it is best to consider them +along with the tumours with which they are associated. Rodent ulcer, +which is one form of cancer of the skin, will be discussed with new +growths of the skin. + +B. #Arrangement of Ulcers according to their Condition.#--Having arrived +at an opinion as to the cause of a given ulcer, and placed it in one or +other of the preceding groups, the next question to ask is, In what +condition do I find this ulcer at the present moment? + +Any ulcer is in one of three states--healing, stationary, or spreading; +although it is not uncommon to find healing going on at one part while +the destructive process is extending at another. + +_The Healing Condition._--The process of healing in an ulcer has already +been studied, and we have learned that it takes place by the formation +of granulation tissue, which becomes converted into connective tissue, +and is covered over by epithelium growing in from the edges. + +Those ulcers which are _stationary_--that is, neither healing nor +spreading--may be in one of several conditions. + +_The Weak Condition._--Any ulcer may get into a weak state from +receiving a blood supply which is defective either in quantity or in +quality. The granulations are small and smooth, and of a pale yellow or +grey colour, the discharge is small in amount, and consists of thin +serum and a few pus cells, and as this dries on the edges it forms scabs +which interfere with the growth of epithelium. + +Should the part become oedematous, either from general causes, such as +heart or kidney disease, or from local causes, such as varicose veins, +the granulations share in the oedema, and there is an abundant serous +discharge. + +The excessive use of moist dressings leads to a third variety of weak +ulcer--namely, one in which the granulations become large, soft, pale, +and flabby, projecting beyond the level of the skin and overlapping the +edges, which become pale and sodden. The term "proud flesh" is popularly +applied to such redundant granulations. + +[Illustration: FIG. 18.--Callous Ulcer, showing thickened edges and +indurated swelling of surrounding parts.] + +_The Callous Condition._--This condition is usually met with in ulcers +on the lower third of the leg, and is often associated with the presence +of varicose veins. It is chiefly met with in hospital practice. The want +of healing is mainly due to impeded venous return and to oedema and +induration of the surrounding skin and cellular tissues (Fig. 18). The +induration results from coagulation and partial organisation of the +inflammatory effusion, and prevents the necessary contraction of the +sore. The base of a callous ulcer lies at some distance below the level +of the swollen, thickened, and white edges, and presents a glazed +appearance, such granulations as are present being unhealthy and +irregular. The discharge is usually watery, and cakes in the dressing. +When from neglect and want of cleanliness the ulcer becomes inflamed, +there is considerable pain, and the discharge is purulent and often +offensive. + +The prolonged hyperaemia of the tissues in relation to a callous ulcer of +the leg often leads to changes in the underlying bones. The periosteum +is abnormally thick and vascular, the superficial layers of the bone +become injected and porous, and the bones, as a whole, are thickened. In +the macerated bone "the surface is covered with irregular, +stalactite-like processes or foliaceous masses, which, to a certain +extent, follow the line of attachment of the interosseous membrane and +of the intermuscular septa" (Cathcart) (Fig. 19). When the whole +thickness of the soft tissues is destroyed by the ulcerative process, +the area of bone that comes to form the base of the ulcer projects as a +flat, porous node, which in its turn may be eroded. These changes as +seen in the macerated specimen are often mistaken for disease +originating in the bone. + +[Illustration: FIG. 19.--Tibia and Fibula, showing changes due to +chronic ulcer of leg.] + +The _irritable condition_ is met with in ulcers which occur, as a rule, +just above the external malleolus in women of neurotic temperament. They +are small in size and have prominent granulations, and by the aid of a +probe points of excessive tenderness may be discovered. These, Hilton +believed, correspond to exposed nerve filaments. + +_Ulcers which are spreading_ may be met with in one of several +conditions. + +_The Inflamed Condition._--Any ulcer may become acutely inflamed from +the access of fresh organisms, aided by mechanical irritation from +trauma, ill-fitting splints or bandages, or want of rest, or from +chemical irritants, such as strong antiseptics. The best clinical +example of an inflamed ulcer is the venereal soft sore. The base of the +ulcer becomes red and angry-looking, the granulations disappear, and a +copious discharge of thin yellow pus, mixed with blood, escapes. Sloughs +of granulation tissue or of connective tissue may form. The edges become +red, ragged, and everted, and the ulcer increases in size by spreading +into the inflamed and oedematous surrounding tissues. Such ulcers are +frequently multiple. Pain is a constant symptom, and is often severe, +and there is usually some constitutional disturbance. + +The _phagedaenic condition_ is the result of an ulcer being infected with +specially virulent bacteria. It occurs in syphilitic ulcers, and rapidly +leads to a widespread destruction of tissue. It is also met with in the +throat in some cases of scarlet fever, and may give rise to fatal +haemorrhage by ulcerating into large blood vessels. All the local and +constitutional signs of a severe septic infection are present. + +#Treatment of Ulcers.#--An ulcer is not only an immediate cause of +suffering to the patient, crippling and incapacitating him for his work, +but is a distinct and constant menace to his health: the prolonged +discharge reduces his strength; the open sore is a possible source of +infection by the organisms of suppuration, erysipelas, or other specific +diseases; phlebitis, with formation of septic emboli, leading to pyaemia, +is liable to occur; and in old persons it is not uncommon for ulcers of +long standing to become the seat of cancer. In addition, the offensive +odour of many ulcers renders the patient a source of annoyance and +discomfort to others. The primary object of treatment in any ulcer is to +bring it into the condition of a healing sore. When this has been +effected, nature will do the rest, provided extraneous sources of +irritation are excluded. + +Steps must be taken to facilitate the venous return from the ulcerated +part, and to ensure that a sufficient supply of fresh, healthy blood +reaches it. The septic element must be eliminated by disinfecting the +ulcer and its surroundings, and any other sources of irritation must be +removed. + +If the patient's health is below par, good nourishing food, tonics, and +general hygienic treatment are indicated. + +_Management of a Healing Sore._--Perhaps the best dressing for a healing +sore is a layer of Lister's perforated oiled-silk protective, which is +made to cover the raw surface and the skin for about a quarter of an +inch beyond the margins of the sore. Over this three or four thicknesses +of sterilised gauze, wrung out of eusol, creolin, or sterilised water, +are applied, and covered by a pad of absorbent wool. As far as possible +the part should be kept at rest, and the position should be adjusted so +as to favour the circulation in the affected area. + +The dressing may be renewed at intervals, and care must be taken to +avoid any rough handling of the sore. Any discharge that lies on the +surface should be removed by a gentle stream of lotion rather than by +wiping. The area round the sore should be cleansed before the fresh +dressing is applied. + +In some cases, healing goes on more rapidly under a dressing of weak +boracic ointment (one-quarter the strength of the pharmacopoeial +preparation). The growth of epithelium may be stimulated by a 6 to 8 per +cent. ointment of scarlet-red. + +Dusting powders and poultice dressings are best avoided in the treatment +of healing sores. + +In extensive ulcers resulting from recent burns, if the granulations are +healthy and aseptic, skin-grafts may safely be placed on them directly. +If, however, their asepticity cannot be relied upon, it is necessary to +scrape away the superficial layer of the granulations, the young fibrous +tissue underneath being conserved, as it is sufficiently vascular to +nourish the grafts placed on it. + +#Treatment of Special Varieties of Ulcers.#--Before beginning to treat a +given ulcer, two questions have to be answered--first, What are the +causative conditions present? and second, In what condition do I find +the ulcer?--in other words, In what particulars does it differ from a +healthy healing sore? + +If the cause is a local one, it must be removed; if a constitutional +one, means must be taken to counteract it. This done, the condition of +the ulcer must be so modified as to bring it into the state of a healing +sore, after which it will be managed on the lines already laid down. + +#Treatment in relation to the Cause of the Ulcer.#--_Traumatic +Group._--The _prophylaxis_ of these ulcers consists in excluding +bacteria, by cleansing crushed or bruised parts, and applying sterilised +dressings and properly adjusted splints. If there is reason to fear that +the disinfection has not been complete, a Bier's constricting bandage +should be applied for some hours each day. These measures will often +prevent a grossly injured portion of skin dying, and will ensure +asepticity should it do so. In the event of the skin giving way, the +same form of dressing should be continued till the slough has separated +and a healthy granulating surface is formed. The protective dressing +appropriate to a healing sore is then substituted. _Pressure sores_ are +treated on the same lines. + +The treatment of ulcers caused by _burns and scalds_ will be described +later. + +In _ulcers of the leg due to interference with the venous return_, the +primary indication is to elevate the limb in order to facilitate the +flow of the blood in the veins, and so admit of fresh blood reaching the +part. The limb may be placed on pillows, or the foot of the bed raised +on blocks, so that the ulcer lies on a higher level than the heart. +Should varicose veins be present, the question of operative treatment +must be considered. + +When an _imperfect nerve supply_ is the main factor underlying ulcer +formation, prophylaxis is the chief consideration. In patients suffering +from spinal injuries or diseases, cerebral paralysis, or affections of +the peripheral nerves, all sources of irritation, such as ill-fitting +splints, tight bandages, moist applications, and hot bottles, should be +avoided. Any part liable to pressure, from the position of the patient +or otherwise, must be carefully protected by pads of wool, air-cushions, +or water-bags, and must be kept absolutely dry. The skin should be +hardened by daily applications of methylated spirit. + +Should an ulcer form in spite of these precautions, the mildest +antiseptics must be employed for bathing and dressing it, and as far as +possible all dressings should be dry. + +The _perforating ulcer_ of the foot calls for special treatment. To +avoid pressure on the sole of the foot, the patient must be confined to +bed. As the main local obstacle to healing is the down-growth of +epithelium along the sides of the ulcer, this must be removed by the +knife or sharp spoon. The base also should be excised, and any bone +which may have become involved should be gouged away, so as to leave a +healthy and vascular surface. The cavity thus formed is stuffed with +bismuth or iodoform gauze and encouraged to heal from the bottom. As the +parts are insensitive an anaesthetic is not required. After the ulcer has +healed, the patient should wear in his boot a thick felt sole with a +hole cut out opposite the situation of the cicatrix. When a joint has +been opened into, the difficulty of thoroughly getting rid of all +unhealthy and infected granulations is so great that amputation may be +advisable, but it is to be remembered that ulceration may recur in the +stump if pressure is put upon it. The treatment of any nervous disease +or glycosuria which may coexist is, of course, indicated. + +Exposure of the plantar nerves by an incision behind the medial +malleolus, and subjecting them to forcible stretching, has been employed +by Chipault and others in the treatment of perforating ulcers of the +foot. + +The ulcer that forms in relation to callosities on the sole of the foot +is treated by paring away all the thickened skin, after softening it +with soda fomentations, removing the unhealthy granulations, and +applying stimulating dressings. + +_Treatment of Ulcers due to Constitutional Causes._--When ulcers are +associated with such diseases as tuberculosis, syphilis, diabetes, +Bright's disease, scurvy, or gout, these must receive appropriate +treatment. + +The local treatment of the _tuberculous ulcer_ calls for special +mention. If the ulcer is of limited extent and situated on an exposed +part of the body, the most satisfactory method is complete removal, by +means of the knife, scissors, or sharp spoon, of the ulcerated surface +and of all the infected area around it, so as to leave a healthy surface +from which granulations may spring up. Should the raw surface left be +likely to result in an unsightly scar or in cicatricial contraction, +skin-grafting should be employed. + +For extensive ulcers on the limbs, the chest wall, or on other covered +parts, or when operative treatment is contra-indicated, the use of +tuberculin and exposure to the Rontgen rays have proved beneficial. The +induction of passive hyperaemia, by Bier's or by Klapp's apparatus, +should also be used, either alone or supplementary to other measures. + +No ulcerative process responds so readily to medicinal treatment as the +_syphilitic ulcer_ does to the intra-venous administration of arsenical +preparations of the "606" or "914" groups or to full doses of iodide of +potassium and mercury, and the local application of black wash. When the +ulceration has lasted for a long time, however, and is widespread and +deep, the duration of treatment is materially shortened by a thorough +scraping with the sharp spoon. + +#Treatment in relation to the Condition of the Ulcer.#--_Ulcers in a +weak condition._--If the weak condition of the ulcer is due to anaemia +or kidney disease, these affections must first be treated. Locally, the +imperfect granulations should be scraped away, and some stimulating +agent applied to the raw surface to promote the growth of healthy +granulations. For this purpose the sore may be covered with gauze +smeared with a 6 to 8 per cent. ointment of scarlet-red, the surrounding +parts being protected from the irritant action of the scarlet-red by a +layer of vaseline. A dressing of gauze moistened with eusol or of +boracic lint wrung out of red lotion (2 grains of sulphate of zinc, and +10 minims of compound tincture of lavender, to an ounce of water), and +covered with a layer of gutta-percha tissue, is also useful. + +When the condition has resulted from the prolonged use of moist +dressings, these must be stopped, the redundant granulations clipped +away with scissors, the surface rubbed with silver nitrate or sulphate +of copper (blue-stone), and dry dressings applied. + +When the ulcer has assumed the characters of a healing sore, skin-grafts +may be applied to hasten cicatrisation. + +_Ulcers in a callous condition_ call for treatment in three +directions--(1) The infective element must be eliminated. When the ulcer +is foul, relays of charcoal poultices (three parts of linseed meal to +one of charcoal), maintained for thirty-six to forty-eight hours, are +useful as a preliminary step. The base of the ulcer and the thickened +edges should then be freely scraped with a sharp spoon, and the +resulting raw surface sponged over with undiluted carbolic acid or +iodine, after which an antiseptic dressing is applied, and changed daily +till healthy granulations appear. (2) The venous return must be +facilitated by elevation of the limb and massage. (3) The induration of +the surrounding parts must be got rid of before contraction of the sore +is possible. For this purpose the free application of blisters, as first +recommended by Syme, leaves little to be desired. Liquor epispasticus +painted over the parts, or a large fly-blister (emplastrum cantharidis) +applied all round the ulcer, speedily disperses the inflammatory +products which cause the induration. The use of elastic pressure or of +strapping, of hot-air baths, or the making of multiple incisions in the +skin around the ulcer, fulfils the same object. + +As soon as the ulcer assumes the characters of a healing sore, it should +be covered with skin-grafts, which furnish a much better cicatrix than +that which forms when the ulcer is allowed to heal without such aid. + +A more radical method of treatment consists in excising the whole +ulcer, including its edges and about a quarter of an inch of the +surrounding tissue, as well as the underlying fibrous tissue, and +grafting the raw surface. + +_Ambulatory Treatment._--When the circumstances of the patient forbid +his lying up in bed, the healing of the ulcer is much delayed. He should +be instructed to take every possible opportunity of placing the limb in +an elevated position, and must constantly wear a firm bandage of +_elastic webbing_. This webbing is porous and admits of evaporation of +the skin and wound secretions--an advantage it has over Martin's rubber +bandage. The bandage should extend from the toes to well above the knee, +and should always be applied while the patient is in the recumbent +position with the leg elevated, preferably before getting out of bed in +the morning. Additional support is given to the veins if the bandage is +applied as a figure of eight. + +We have found the following method satisfactory in out-patient +practice. The patient lying on a couch, the limb is raised about +eighteen inches and kept in this position for five minutes--till the +excess of blood has left it. With the limb still raised, the ulcer with +the surrounding skin is covered with a layer, about half an inch thick, +of finely powdered boracic acid, and the leg, from foot to knee, +excluding the sole, is enveloped in a thick layer of wood-wool wadding. +This is held in position by ordinary cotton bandages, painted over with +liquid starch; while the starch is drying the limb is kept elevated. +With this appliance the patient may continue to work, and the dressing +does not require to be changed oftener than once in three or four weeks +(W. G. Richardson). + +When an ulcer becomes acutely _inflamed_ as a result of superadded +infection, antiseptic measures are employed to overcome the infection, +and ichthyol or other soothing applications may be used to allay the +pain. + +The _phagedaenic ulcer_ calls for more energetic means of disinfection; +the whole of the affected surface is touched with the actual cautery at +a white heat, or is painted with pure carbolic acid. Relays of charcoal +poultices are then applied until the spread of the disease is arrested. + +For the _irritable ulcer_ the most satisfactory treatment is complete +excision and subsequent skin-grafting. + + + + +CHAPTER VI + +GANGRENE + + +Definition--Types: _Dry_, _Moist_--Varieties--Gangrene primarily due to + interference with circulation: _Senile gangrene_; _Embolic + gangrene_; _Gangrene following ligation of arteries_; _Gangrene + from mechanical causes_; _Gangrene from heat, chemical agents, and + cold_; _Diabetic gangrene_; _Gangrene associated with spasm of + blood vessels_; _Raynaud's disease_; _Angio-sclerotic gangrene_; + _Gangrene from ergot_. Bacterial varieties of gangrene. + _Pathology_--clinical varieties--_Acute infective gangrene_; + _Malignant oedema_; _Acute emphysematous_ or _gas gangrene_; + _Cancrum oris_, _etc_. Bed-sores: _Acute_; _chronic_. + +Gangrene or mortification is the process by which a portion of tissue +dies _en masse_, as distinguished from the molecular or cellular death +which constitutes ulceration. The dead portion is known as a _slough_. + +In this chapter we shall confine our attention to the process as it +affects the limbs and superficial parts, leaving gangrene of the viscera +to be described in regional surgery. + + +TYPES OF GANGRENE + +Two distinct types of gangrene are met with, which, from their most +obvious point of difference, are known respectively as _dry_ and +_moist_, and there are several clinical varieties of each type. + +Speaking generally, it may be said that dry gangrene is essentially due +to a simple _interference with the blood supply_ of a part; while the +main factor in the production of moist gangrene is _bacterial +infection_. + +The cardinal signs of gangrene are: change in the colour of the part, +coldness, loss of sensation and motor power, and, lastly, loss of +pulsation in the arteries. + +#Dry Gangrene# or #Mummification# is a comparatively slow form of local +death due, as a rule, to a diminution in the arterial blood supply of +the affected part, resulting from such causes as the gradual narrowing +of the lumen of the arteries by disease of their coats, or the blocking +of the main vessel by an embolus. + +As the fluids in the tissues are lost by evaporation the part becomes +dry and shrivelled, and as the skin is usually intact, infection does +not take place, or if it does, the want of moisture renders the part an +unsuitable soil, and the organisms do not readily find a footing. Any +spread of the process that may take place is chiefly influenced by the +anatomical distribution of the blocked arteries, and is arrested as soon +as it reaches an area rich in anastomotic vessels. The dead portion is +then cast off, the irritation resulting from the contact of the dead +with the still living tissue inducing the formation of granulations on +the proximal side of the junction, and these by slowly eating into the +dead portion produce a furrow--the _line of demarcation_--which +gradually deepens until complete separation is effected. As the muscles +and bones have a richer blood supply than the integument, the death of +skin and subcutaneous tissues extends higher than that of muscles and +bone, with the result that the stump left after spontaneous separation +is conical, the end of the bone projecting beyond the soft parts. + +_Clinical Features._--The part undergoing mortification becomes colder +than normal, the temperature falling to that of the surrounding +atmosphere. In many instances, but not in all, the onset of the process +is accompanied by severe neuralgic pain in the part, probably due to +anaemia of the nerves, to neuritis, or to the irritation of the exposed +axis cylinders by the dead and dying tissues around them. This pain soon +ceases and gives place to a complete loss of sensation. The dead part +becomes dry, horny, shrivelled, and semi-transparent--at first of a dark +brown, but finally of a black colour, from the dissemination of blood +pigment throughout the tissues. There is no putrefaction, and therefore +no putrid odour; and the condition being non-infective, there is not +necessarily any constitutional disturbance. In itself, therefore, dry +gangrene does not involve immediate risk to life; the danger lies in the +fact that the breach of surface at the line of demarcation furnishes a +possible means of entrance for bacteria, which may lead to infective +complications. + +#Moist Gangrene# is an acute process, the dead part retaining its fluids +and so affording a favourable soil for the development of bacteria. The +action of the organisms and their toxins on the adjacent tissues leads +to a rapid and wide spread of the process. The skin becomes moist and +macerated, and bullae, containing dark-coloured fluid or gases, form +under the epidermis. The putrefactive gases evolved cause the skin to +become emphysematous and crepitant and produce an offensive odour. The +tissues assume a greenish-black colour from the formation in them of a +sulphide of iron resulting from decomposition of the blood pigment. +Under certain conditions the dead part may undergo changes resembling +more closely those of ordinary post-mortem decomposition. Owing to its +nature the spread of the gangrene is seldom arrested by the natural +protective processes, and it usually continues until the condition +proves fatal from the absorption of toxins into the circulation. + +The _clinical features_ vary in the different varieties of moist +gangrene, but the local results of bacterial action and the +constitutional disturbance associated with toxin absorption are present +in all; the prognosis therefore is grave in the extreme. + +From what has been said, it will be gathered that in dry gangrene there +is no urgent call for operation to save the patient's life, the primary +indication being to prevent the access of bacteria to the dead part, and +especially to the surface exposed at the line of demarcation. In moist +gangrene, on the contrary, organisms having already obtained a footing, +immediate removal of the dead and dying tissues, as a rule, offers the +only hope of saving life. + + +VARIETIES OF GANGRENE + +#Varieties of Gangrene essentially due to Interference with the +Circulation# + +While the varieties of gangrene included in this group depend primarily +on interference with the circulation, it is to be borne in mind that the +clinical course of the affection may be profoundly influenced by +superadded infection with micro-organisms. Although the bacteria do not +play the most important part in producing tissue necrosis, their + +subsequent introduction is an accident of such importance that it may +change the whole aspect of affairs and convert a dry form of gangrene +into one of the moist type. Moreover, the low state of vitality of the +tissues, and the extreme difficulty of securing and maintaining asepsis, +make it a sequel of great frequency. + +#Senile Gangrene.#--Senile gangrene is the commonest example of local +death produced by a _gradual_ diminution in the quantity of blood +passing through the parts, as a result of arterio-sclerosis or other +chronic disease of the arteries leading to diminution of their calibre. +It is the most characteristic example of the dry type of gangrene. As +the term indicates, it occurs in old persons, but the patient's age is +to be reckoned by the condition of his arteries rather than by the +number of his years. Thus the vessels of a comparatively young man who +has suffered from syphilis and been addicted to alcohol are more liable +to atheromatous degeneration leading to this form of gangrene than are +those of a much older man who has lived a regular and abstemious life. +This form of gangrene is much more common in men than in women. While it +usually attacks only one foot, it is not uncommon for the other foot to +be affected after an interval, and in some cases it is bilateral from +the outset. It must clearly be understood that any form of gangrene may + +occur in old persons, the term senile being here restricted to that +variety which results from arterio-sclerosis. + +[Illustration: FIG. 20.--Senile Gangrene of the Foot, showing line of +demarcation.] + +_Clinical Features._--The commonest seat of the disease is in the toes, +especially the great toe, whence it spreads up the foot to the heel, or +even to the leg (Fig. 20). There is often a history of some slight +injury preceding its onset. The vitality of the tissues is so low that +the balance between life and death may be turned by the most trivial +injury, such as a cut while paring a toe-nail or a corn, a blister +caused by an ill-fitting shoe or the contact of a hot-bottle. In some +cases the actual gangrene is determined by thrombosis of the popliteal +or tibial arteries, which are already narrowed by obliterating +endarteritis. + +It is common to find that the patient has been troubled for a long time +before the onset of definite signs of gangrene, with cold feet, with +tingling and loss of feeling, or a peculiar sensation as if walking on +cotton wool. + +The first evidence of the death of the part varies in different cases. +Sometimes a dark-blue spot appears on the medial side of the great toe +and gradually increases in size; or a blister containing blood-stained +fluid may form. Streaks or patches of dark-blue mottling appear higher +up on the foot or leg. In other cases a small sore surrounded by a +congested areola forms in relation to the nail and refuses to heal. Such +sores on the toes of old persons are always to be looked upon with +suspicion and treated with the greatest care; and the urine should be +examined for sugar. There is often severe, deep-seated pain of a +neuralgic character, with cramps in the limb, and these may persist long +after a line of demarcation has formed. The dying part loses sensibility +to touch and becomes cold and shrivelled. + +All the physical appearances and clinical symptoms associated with dry +gangrene supervene, and the dead portion is delimited by a line of +demarcation. If this forms slowly and irregularly it indicates a very +unsatisfactory condition of the circulation; while, if it forms quickly +and decidedly, the presumption is that the circulation in the parts +above is fairly good. The separation of the dead part is always attended +with the risk of infection taking place, and should this occur, the +temperature rises and other evidences of toxaemia appear. + +_Prophylaxis._--The toes and feet of old people, the condition of whose +circulation predisposes them to gangrene, should be protected from +slight injuries such as may be received while paring nails, cutting +corns, or wearing ill-fitting boots. The patient should also be warned +of the risk of exposure to cold, the use of hot-bottles, and of placing +the feet near a fire. Attempts have been made to improve the peripheral +circulation by establishing an anastomosis between the main artery of a +limb and its companion vein, so that arterial blood may reach the +peripheral capillaries--reversal of the circulation--but the clinical +results have proved disappointing. (See _Op. Surg._, p. 29.) + +_Treatment._--When there is evidence that gangrene has occurred, the +first indication is to prevent infection by purifying the part, and +after careful drying to wrap it in a thick layer of absorbent and +antiseptic wool, retained in place by a loosely applied bandage. A +slight degree of elevation of the limb is an advantage, but it must not +be sufficient to diminish the amount of blood entering the part. +Hot-bottles are to be used with the utmost caution. As absolute dryness +is essential, ointments or other greasy dressings are to be avoided, as +they tend to prevent evaporation from the skin. Opium should be given +freely to alleviate pain. Stimulation is to be avoided, and the patient +should be carefully dieted. + +When the gangrene is limited to the toes in old and feeble patients, +some surgeons advocate the expectant method of treatment, waiting for a +line of demarcation to form and allowing the dead part to be separated. +This takes place so slowly, however, that it necessitates the patient +being laid up for many weeks, or even months; and we agree with the +majority in advising early amputation. + +In this connection it is worthy of note that there are certain points at +which gangrene naturally tends to become arrested--namely, at the highly +vascular areas in the neighbourhood of joints. Thus gangrene of the +great toe often stops when it reaches the metatarso-phalangeal joint; or +if it trespasses this limit it may be arrested either at the +tarso-metatarsal or at the ankle joint. If these be passed, it usually +spreads up the leg to just below the knee before signs of arrestment +appear. Further, it is seen from pathological specimens that the spread +is greater on the dorsal than on the plantar aspect, and that the death +of skin and subcutaneous tissues extends higher than that of bone and +muscle. + +These facts furnish us with indications as to the seat and method of +amputation. Experience has proved that in senile gangrene of the lower +extremity the most reliable and satisfactory results are obtained by +amputating in the region of the knee, care being taken to perform the +operation so as to leave the prepatellar anastomosis intact by retaining +the patella in the anterior flap. The most satisfactory operation in +these cases is Gritti's supra-condylar amputation. Haemorrhage is easily +controlled by digital pressure, and the use of a tourniquet should be +dispensed with, as the constriction of the limb is liable to interfere +with the vitality of the flaps. + +When the tibial vessels can be felt pulsating at the ankle it may be +justifiable, if the patient urgently desires it, to amputate lower than +the knee; but there is considerable risk of gangrene recurring in the +stump and necessitating a second operation. + +That amputation for senile gangrene performed between the ankle and the +knee seldom succeeds, is explained by the fact that the vascular +obstruction is usually in the upper part of the posterior tibial artery, +and the operation is therefore performed through tissues with an +inadequate blood supply. It is not uncommon, indeed, on amputating above +the knee, to find even the popliteal artery plugged by a clot. This +should be removed at the amputation by squeezing the vessel from above +downward by a "milking" movement, or by "catheterising the artery" with +the aid of a cannula with a terminal aperture. + +It is to be borne in mind that the object of amputation in these cases +is merely to remove the gangrenous part, and so relieve the patient of +the discomfort and the risks from infection which its presence involves. +While it is true that in many of these patients the operation is borne +remarkably well, it must be borne in mind that those who suffer from +senile gangrene are of necessity bad lives, and a guarded opinion should +be expressed as to the prospects of survival. The possibility of the +disease developing in the other limb has already been referred to. + +[Illustration: FIG. 21.--Embolic Gangrene of Hand and Arm.] + +#Embolic Gangrene# (Fig. 21).--This is the most typical form of gangrene +resulting from the _sudden_ occlusion of the main artery of a part, +whether by the impaction of an embolus or the formation of a thrombus in +its lumen, when the collateral circulation is not sufficiently free to +maintain the vitality of the tissues. + +There is sudden pain at the site of impaction of the embolus, and the +pulses beyond are lost. The limb becomes cold, numb, insensitive, and +powerless. It is often pale at first--hence the term "white gangrene" +sometimes applicable to the early appearances, which closely resemble +those presented by the limb of a corpse. + +If the part is aseptic it shrivels, and presents the ordinary features +of dry gangrene. It is liable, however, especially in the lower +extremity and when the veins also are obstructed, to become infected and +to assume the characters of the moist type. + +The extent of the gangrene depends upon the site of impaction of the +embolus, thus if the _abdominal aorta_ becomes suddenly occluded by an +embolus at its bifurcation, the obstruction of the iliacs and femorals +induces symmetrical gangrene of both extremities as high as the inguinal +ligaments. When gangrene follows occlusion of the _external iliac_ or of +the _femoral artery_ above the origin of its deep branch, the death of +the limb extends as high as the middle or upper third of the thigh. When +the _femoral_ below the origin of its deep branch or the _popliteal +artery_ is obstructed, the veins remaining pervious, the anastomosis +through the profunda is sufficient to maintain the vascular supply, and +gangrene does not necessarily follow. The rupture of a popliteal +aneurysm, however, by compressing the vein and the articular branches, +usually determines gangrene. When an embolus becomes impacted at the +_bifurcation of the popliteal_, if gangrene ensues it usually spreads +well up the leg. + +When the _axillary artery_ is the seat of embolic impaction, and +gangrene ensues, the process usually reaches the middle of the upper +arm. Gangrene following the blocking of the _brachial_ at its +bifurcation usually extends as far as the junction of the lower and +middle thirds of the forearm. + +Gangrene due to thrombosis or embolism is sometimes met with in patients +recovering from typhus, typhoid, or other fevers, such as that +associated with child-bed. It occurs in peripheral parts, such as the +toes, fingers, nose, or ears. + +_Treatment._--The general treatment of embolic gangrene is the same as +that for the senile form. Success has followed opening the artery and +removing the embolus. The artery is exposed at the seat of impaction +and, having been clamped above and below, a longitudinal opening is made +and the clot carefully extracted with the aid of forceps; it is +sometimes unexpectedly long (one recorded from the femoral artery +measured nearly 34 inches); the wound in the artery is then sewn up with +fine silk soaked in paraffin. When amputation is indicated, it must be +performed sufficiently high to ensure a free vascular supply to the +flaps. + +#Gangrene following Ligation of Arteries.#--After the ligation of an +artery in its continuity--for example, in the treatment of aneurysm--the +limb may for some days remain in a condition verging on gangrene, the +distal parts being cold, devoid of sensation, and powerless. As the +collateral circulation is established, the vitality of the tissues is +gradually restored and these symptoms pass off. In some cases, +however,--and especially in the lower extremity--gangrene ensues and +presents the same characters as those resulting from embolism. It tends +to be of the dry type. The occlusion of the vein as well as the artery +is not found to increase the risk of gangrene. + +#Gangrene from Mechanical Constriction of the Vessels of the part.#--The +application of a bandage or plaster-of-Paris case too tightly, or of a +tourniquet for too long a time, has been known to lead to death of the +part beyond; but such cases are rare, as are also those due to the +pressure of a fractured bone or of a tumour on a large artery or vein. +When gangrene occurs from such causes, it tends to be of the moist type. + +Much commoner is it to meet with localised areas of necrosis due to the +excessive _pressure of splints_ over bony prominences, such as the +lateral malleolus, the medial condyle of the humerus, or femur, or over +the dorsum of the foot. This is especially liable to occur when the +nutrition of the skin is depressed by any interference with its +nerve-supply, such as follows injuries to the spine or peripheral +nerves, disease of the brain, or acute anterior poliomyelitis. When the +splint is removed the skin pressed upon is found to be of a pale yellow +or grey colour, and is surrounded by a ring of hyperaemia. If protected +from infection, the clinical course is that of dry gangrene. + +Bed-sores, which are closely allied to pressure sores, will be described +at the end of this chapter. + +When a localised portion of tissue, for example, a piece of skin, is so +severely _crushed_ or _bruised_ that its blood vessels are occluded and +its structure destroyed, it dies, and, if not infected with bacteria, +dries up, and the shrivelled brown skin is slowly separated by the +growth of granulation tissue beneath and around it. + +Fingers, toes, or even considerable portions of limbs may in the same +way be suddenly destroyed by severe trauma, and undergo mummification. +If organisms gain access, typical moist gangrene may ensue, or changes +similar to those of ordinary post-mortem decomposition may take place. + +_Treatment._--The first indication is to exclude bacteria by purifying +the damaged part and its surroundings, and applying dry, non-irritating +dressings. + +When these measures are successful, dry gangrene ensues. The raw surface +left after the separation of the dead skin may be allowed to heal by +granulation, or may be covered by skin-grafts. In the case of a finger +or a limb it is not necessary to wait until spontaneous separation takes +place, as this is often a slow process. When a well-marked line of +demarcation has formed, amputation may be performed just sufficiently +far above it to enable suitable flaps to be made. + +The end of a stump, after spontaneous separation of the gangrenous +portion, requires to be trimmed, sufficient bone being removed to permit +of the soft parts coming together. + +If moist gangrene supervenes, amputation must be performed without +delay, and at a higher level. + +#Gangrene from Heat, Chemical Agents, and Cold.#--Severe #burns# and +#scalds# may be followed by necrosis of tissue. So long as the parts are +kept absolutely dry--as, for example, by the picric acid method of +treatment--the grossly damaged portions of tissue undergo dry gangrene; +but when wet or oily dressings are applied and organisms gain access, +moist gangrene follows. + +Strong #chemical agents#, such as caustic potash, nitric or sulphuric +acid, may also induce local tissue necrosis, the general appearances of +the lesions produced being like those of severe burns. The resulting +sloughs are slow to separate, and leave deep punched-out cavities which +are long of healing. + +#Carbolic Gangrene.#--Carbolic acid, even in comparatively weak +solution, is liable to induce dry gangrene when applied as a fomentation +to a finger, especially in women and children. Thrombosis occurs in the +blood vessels of the part, which at first is pale and soft, but later +becomes dark and leathery. On account of the anaesthetic action of +carbolic acid, the onset of the process is painless, and the patient +does not realise his danger. A line of demarcation soon forms, but the +dead part separates very slowly. + +#Gangrene from Frost-bite.#--It is difficult to draw the line between +the third degree of chilblain and the milder forms of true frost-bite; +the difference is merely one of degree. Frost-bite affects chiefly the +toes and fingers--especially the great toe and the little finger--the +ears, and the nose. In this country it is seldom seen except in members +of the tramp class, who, in addition to being exposed to cold by +sleeping in the open air, are ill-fed and generally debilitated. The +condition usually manifests itself after the parts, having been +subjected to extreme cold, are brought into warm surroundings. The first +symptom is numbness in the part, followed by a sense of weight, +tingling, and finally by complete loss of sensation. The part attacked +becomes white and bleached-looking, feels icy cold, and is insensitive +to touch. Either immediately, or, it may be, not for several days, it +becomes discoloured and swollen, and finally contracts and shrivels. +Above the dead area the limb may be the seat of excruciating pain. The +dead portion is cast off, as in other forms of dry gangrene, by the +formation of a line of demarcation. + +To prevent the occurrence of gangrene from frost-bite it is necessary to +avoid the sudden application of heat. The patient should be placed in a +cold room, and the part rubbed with snow, or put in a cold bath, and +have light friction applied to it. As the circulation is restored the +general surroundings and the local applications are gradually made +warmer. Elevation of the part, wrapping it in cotton wool, and removal +to a warmer room, are then permissible, and stimulants and warm drinks +may be given with caution. When by these means the occurrence of +gangrene is averted, recovery ensues, its onset being indicated by the +white parts assuming a livid red hue and becoming the seat of an acute +burning sensation. + +A condition known as _Trench feet_ was widely prevalent amongst the +troops in France during the European War. Although allied to frost-bite, +cold appears to play a less important part in its causation than +humidity and constriction of the limbs producing ischaemia of the feet. +Changes were found in the endothelium of the blood vessels, the axis +cylinders of nerves, and the muscles. The condition does not occur in +civil life. + +#Diabetic Gangrene.#--This form of gangrene is prone to occur in persons +over fifty years of age who suffer from glycosuria. The arteries are +often markedly diseased. In some cases the existence of the glycosuria +is unsuspected before the onset of the gangrene, and it is only on +examining the urine that the cause of the condition is discovered. The +gangrenous process seldom begins as suddenly as that associated with +embolism, and, like senile gangrene, which it may closely simulate in +its early stages, it not infrequently begins after a slight injury to +one of the toes. It but rarely, however, assumes the dry, shrivelling +type, as a rule being attended with swelling, oedema, and dusky redness +of the foot, and severe pain. According to Paget, the dead part remains +warm longer than in other forms of senile gangrene; there is a greater +tendency for patches of skin at some distance from the primary seat of +disease to become gangrenous, and for the death of tissue to extend +upwards in the subcutaneous planes, leaving the overlying skin +unaffected. The low vitality of the tissues favours the growth of +bacteria, and if these gain access, the gangrene assumes the characters +of the moist type and spreads rapidly. + +The rules for amputation are the same as those governing the treatment +of senile gangrene, the level at which the limb is removed depending +upon whether the gangrene is of the dry or moist type. The general +treatment for diabetes must, of course, be employed whether amputation +is performed or not. Paget recommended that the dietetic treatment +should not be so rigid as in uncomplicated diabetes, and that opium +should be given freely. + +The _prognosis_ even after amputation is unfavourable. In many cases the +patient dies with symptoms of diabetic coma within a few days of the +operation; or, if he survives this, he may eventually succumb to +diabetes. In others there is sloughing of the flaps and death results +from toxaemia. Occasionally the other limb becomes gangrenous. On the +other hand, the glycosuria may diminish or may even disappear after +amputation. + +#Gangrene associated with Spasm of Blood Vessels.#--#Raynaud's Disease#, +or symmetrical gangrene, is supposed to be due to spasm of the +arterioles, resulting from peripheral neuritis. It occurs oftenest in +women, between the ages of eighteen and thirty, who are the subjects of +uterine disorders, anaemia, or chlorosis. Cold is an aggravating factor, +as the disease is commonest during the winter months. The digits of both +hands or the toes of both feet are simultaneously attacked, and the +disease seldom spreads beyond the phalanges or deeper than the skin. + +The first evidence is that the fingers become cold, white, and +insensitive to touch and pain. These attacks of _local syncope_ recur at +varying intervals for months or even years. They last for a few minutes +or even for some hours, and as they pass off the parts become hyperaemic +and painful. + +A more advanced stage of the disease is known as _local asphyxia_. The +circulation through the fingers becomes exceedingly sluggish, and the +parts assume a dull, livid hue. There is swelling and burning or +shooting pain. This may pass off in a few days, or may increase in +severity, with the formation of bullae, and end in dry gangrene. As a +rule, the slough which forms is comparatively small and superficial, +but it may take some months to separate. The condition tends to recur in +successive winters. + +The _treatment_ consists in remedying any nervous or uterine disorder +that may be present, keeping the parts warm by wrapping them in cotton +wool, and in the use of hot-air or electric baths, the parts being +immersed in water through which a constant current is passed. When +gangrene occurs, it is treated on the same lines as other forms of dry +gangrene, but if amputation is called for it is only with a view to +removing the dead part. + +#Angio-sclerotic Gangrene.#--A form of gangrene due to _angio-sclerosis_ +is occasionally met with in young persons, even in children. It bears +certain analogies to Raynaud's disease in that spasm of the vessels +plays a part in determining the local death. + +The main arteries are narrowed by hyperplastic endarteritis followed by +thrombosis, and similar changes are found in the veins. The condition is +usually met with in the feet, but the upper extremity may be affected, +and is attended with very severe pain, rendering sleep impossible. + +The patient is liable to sudden attacks of numbness, tingling and +weakness of the limbs which pass off with rest--_intermittent +claudication_. During these attacks the large arteries--femoral, +brachial, and subclavian--can be felt as firm cords, while pulsation is +lost in the peripheral vessels. Gangrene eventually ensues, is attended +with great pain and runs a slow course. It is treated on the same lines +as Raynaud's disease. + +#Gangrene from Ergot.#--Gangrene may occur from interference with blood +supply, the result of tetanic contraction of the minute vessels, such as +results in ill-nourished persons who eat large quantities of coarse rye +bread contaminated with the _claviceps purpurea_ and containing the +ergot of rye. It has also occurred in the fingers of patients who have +taken ergot medicinally over long periods. The gangrene, which attacks +the toes, fingers, ears, or nose, is preceded by formication, numbness, +and pains in the parts to be affected, and is of the dry variety. + +In this country it is usually met with in sailors off foreign ships, +whose dietary largely consists of rye bread. Trivial injuries may be the +starting-point, the anaesthesia produced by the ergotin preventing the +patient taking notice of them. Alcoholism is a potent predisposing +cause. + +As it is impossible to predict how far the process will spread, it is +advisable to wait for the formation of a line of demarcation before +operating, and then to amputate immediately above the dead part. + + +BACTERIAL VARIETIES OF GANGRENE + +The acute bacillary forms of gangrene all assume the moist type from the +first, and, spreading rapidly, result in extensive necrosis of tissue, +and often end fatally. + +The infection is usually a mixed one in which anaerobic bacteria +predominate. The anaerobe most constantly present is the _bacillus +aerogenes capsulatus_, usually in association with other anaerobes, and +sometimes with pyogenic diplo- and streptococci. According to the mode of +action of the associated organisms and the combined effects of their +toxins on the tissues, the gangrenous process presents different +pathological and clinical features. Some combinations, for example, +result in a rapidly spreading cellulitis with early necrosis of +connective tissue accompanied by thrombosis throughout the capillary and +venous circulation of the parts implicated; other combinations cause +great oedema of the part, and others again lead to the formation of gases +in the tissues, particularly in the muscles. + +These different effects do not appear to be due to a specific action of +any one of the organisms present, but to the combined effect of a +particular group living in symbiosis. + +According as the cellulitic, the oedematous, or the gaseous +characteristics predominate, the clinical varieties of bacillary +gangrene may be separately described, but it must be clearly understood +that they frequently overlap and cannot always be distinguished from one +another. + +#Clinical Varieties of Bacillary Gangrene.#--#Acute infective gangrene# +is the form most commonly met with in civil practice. It may follow such +trivial injuries as a pin-prick or a scratch, the signs of acute +cellulitis rapidly giving place to those of a spreading gangrene. Or it +may ensue on a severe railway, machinery, or street accident, when +lacerated and bruised tissues are contaminated with gross dirt. Often +within a few hours of the injury the whole part rapidly becomes painful, +swollen, oedematous, and tense. The skin is at first glazed, and perhaps +paler than normal, but soon assumes a dull red or purplish hue, and +bullae form on the surface. Putrefactive gases may be evolved in the +tissues, and their presence is indicated by emphysematous crackling when +the part is handled. The spread of the disease is so rapid that its +progress is quite visible from hour to hour, and may be traced by the +occurrence of red lines along the course of the lymphatics of the limb. +In the most acute cases the death of the affected part takes place so +rapidly that the local changes indicative of gangrene have not time to +occur, and the fact that the part is dead may be overlooked. + +[Illustration: FIG. 22.--Gangrene of Terminal Phalanx of Index-Finger, +following cellulitis of hand resulting from a scratch on the palm of the +hand.] + +Rigors may occur, but the temperature is not necessarily raised--indeed, +it is sometimes subnormal. The pulse is small, feeble, rapid, and +irregular. Unless amputation is promptly performed, death usually +follows within thirty-six or forty-eight hours. Even early operation +does not always avert the fatal issue, because the quantity of toxin +absorbed and its extreme virulence are often more than even a robust +subject can outlive. + +_Treatment._--Every effort must be made to purify all such wounds as are +contaminated by earth, street dust, stable refuse, or other forms of +gross dirt. Devitalised and contaminated tissue is removed with the +knife or scissors and the wound purified with antiseptics of the +chlorine group or with hydrogen peroxide. If there is a reasonable +prospect that infection has been overcome, the wound may be at once +sutured, but if this is doubtful it is left open and packed or +irrigated. + +When acute gangrene has set in no treatment short of amputation is of +any avail, and the sooner this is done, the greater is the hope of +saving the patient. The limb must be amputated well beyond the apparent +limits of the infected area, and stringent precautions must be taken to +avoid discharge from the already gangrenous area reaching the operation +wound. An assistant or nurse, who is to take no other part in the +operation, is told off to carry out the preliminary purification, and to +hold the limb during the operation. + +#Malignant Oedema.#--This form of acute gangrene has been defined as +"a spreading inflammatory oedema attended with emphysema, and ultimately +followed by gangrene of the skin and adjacent parts." The predominant +organism is the _bacillus of malignant oedema_ or _vibrion septique_ of +Pasteur, which is found in garden soil, dung, and various putrefying +substances. It is anaerobic, and occurs as long, thick rods with +somewhat rounded ends and several laterally placed flagella. Spores, +which have a high power of resistance, form in the centre of the rods, +and bulge out the sides so as to give the organisms a spindle-shaped +outline. Other pathogenic organisms are also present and aid the +specific bacillus in its action. + +At the bedside it is difficult, if not impossible, to distinguish it +from acute infective gangrene. Both follow on the same kinds of injury +and run an exceedingly rapid course. In malignant oedema, however, the +incidence of the disease is mainly on the superficial parts, which +become oedematous and emphysematous, and acquire a marbled appearance +with the veins clearly outlined. Early disappearance of sensation is a +particularly grave symptom. Bullae form on the skin, and the tissues +have "a peculiar heavy but not putrid odour." The constitutional effects +are extremely severe, and death may ensue within a few hours. + +#Acute Emphysematous# or #Gas Gangrene# was prevalent in certain areas +at various periods during the European War. It follows infection of +lacerated wounds with the _bacillus aerogenes capsulatus_, usually in +combination with other anaerobes, and its main incidence is on the +muscles, which rapidly become infiltrated with gas that spreads +throughout the whole extent of the muscle, disintegrating its fibres and +leading to necrosis. The gangrenous process spreads with appalling +rapidity, the limb becoming enormously swollen, painful, and crepitant +or even tympanitic. Patches of coppery or purple colour appear on the +skin, and bullae containing blood-stained serum form on the surface. The +toxaemia is profound, and the face and lips assume a characteristic +cyanosis. The condition is attended with a high mortality. Only in the +early stages and when the infection is limited are local measures +successful in arresting the spread; in more severe cases amputation is +the only means of saving life. + +#Cancrum Oris# or #Noma#.--This disease is believed to be due to a +specific bacillus, which occurs in long delicate rods, and is chiefly +found at the margin of the gangrenous area. It is prone to attack +unhealthy children from two to five years of age, especially during +their convalescence from such diseases as measles, scarlet fever, or +typhoid, but may attack adults when they are debilitated. It is most +common in the mouth, but sometimes occurs on the vulva. In the mouth it +begins as an ulcerative stomatitis, more especially affecting the gums +or inner aspect of the cheek. The child lies prostrated, and from the +open mouth foul-smelling saliva, streaked with blood, escapes; the face +is of an ashy-grey colour, the lips dark and swollen. On the inner +aspect of the cheek is a deeply ulcerated surface, with sloughy shreds +of dark-brown or black tissue covering its base; the edges are +irregular, firm, and swollen, and the surrounding mucous membrane is +infiltrated and oedematous. In the course of a few hours a dark spot +appears on the outer aspect of the cheek, and rapidly increases in size; +towards the centre it is black, shading off through blue and grey into a +dark-red area which extends over the cheek (Fig. 23). The tissue +implicated is at first firm and indurated, but as it loses its vitality +it becomes doughy and sodden. Finally a slough forms, and, when it +separates, the cheek is perforated. + +Meanwhile the process spreads inside the mouth, and the gums, the floor +of the mouth, or even the jaws, may become gangrenous and the teeth fall +out. The constitutional disturbance is severe, the temperature raised, +and the pulse feeble and rapid. + +The extremely foetid odour which pervades the room or even the house the +patient occupies, is usually sufficient to suggest the diagnosis of +cancrum oris. The odour must not be mistaken for that due to +decomposition of sordes on the teeth and gums of a debilitated patient. + +The _prognosis_ is always grave in the extreme, the main risks being +general toxaemia and septic pneumonia. When recovery takes place there is +serious deformity, and considerable portions of the jaws may be lost by +necrosis. + +[Illustration: FIG. 23.--Cancrum oris. + +(From a photograph lent by Sir George T. Beatson.)] + +_Treatment._--The only satisfactory treatment is thorough removal under +an anaesthetic of all the sloughy tissue, with the surrounding zone in +which the organisms are active. This is most efficiently accomplished by +the knife or scissors, cutting until the tissue bleeds freely, after +which the raw surface is painted with undiluted carbolic acid and +dressed with iodoform gauze. It may be necessary to remove large pieces +of bone when the necrotic process has implicated the jaws. The mouth +must be constantly sprayed with peroxide of hydrogen, and washed out +with a disinfectant and deodorant lotion, such as Condy's fluid. The +patient's general condition calls for free stimulation. + +The deformity resulting from these necessarily heroic measures is not so +great as might be expected, and can be further diminished by plastic +operations, which should be undertaken before cicatricial contraction +has occurred. + + +BED-SORES + +Bed-sores are most frequently met with in old and debilitated patients, +or in those whose tissues are devitalised by acute or chronic diseases +associated with stagnation of blood in the peripheral veins. Any +interference with the nerve-supply of the skin, whether from injury or +disease of the central nervous system or of the peripheral nerves, +strongly predisposes to the formation of bed-sores. Prolonged and +excessive pressure over a bony prominence, especially if the parts be +moist with skin secretions, urine, or wound discharges, determines the +formation of a sore. Excoriations, which may develop into true +bed-sores, sometimes form where two skin surfaces remain constantly +apposed, as in the region of the scrotum or labium, under pendulous +mammae, or between fingers or toes confined in a splint. + +[Illustration: FIG. 24.--Acute Bed-Sores over Right Buttock.] + +_Clinical Features._--Two clinical varieties are met with--the acute +and the chronic bed-sore. + +The _acute_ bed-sore usually occurs over the sacrum or buttock. It +develops rapidly after spinal injuries and in the course of certain +brain diseases. The part affected becomes red and congested, while the +surrounding parts are oedematous and swollen, blisters form, and the skin +loses its vitality (Fig. 24). + +In advanced cases of general paralysis of the insane, a peculiar form of +acute bed-sore beginning as a blister, and passing on to the formation +of a black, dry eschar, which slowly separates, occurs on such parts as +the medial side of the knee, the angle of the scapula, and the heel. + +The _chronic_ bed-sore begins as a dusky reddish purple patch, which +gradually becomes darker till it is almost black. The parts around are +oedematous, and a blister may form. This bursts and exposes the papillae +of the skin, which are of a greenish hue. A tough greyish-black slough +forms, and is slowly separated. It is not uncommon for the gangrenous +area to continue to spread both in width and in depth till it reaches +the periosteum or bone. Bed-sores over the sacrum sometimes implicate +the vertebral canal and lead to spinal meningitis, which usually proves +fatal. + +In old and debilitated patients the septic absorption taking place from +a bed-sore often proves a serious complication of other surgical +conditions. From this cause, for example, old people may succumb during +the treatment of a fractured thigh. + +The granulating surface left on the separation of the slough tends to +heal comparatively rapidly. + +_Prevention of Bed-sores._--The first essential in the prevention of +bed-sores is the regular changing of the patient's position, so that no +one part of the body is continuously pressed upon for any length of +time. Ring-pads of wool, air-cushions, or water-beds are necessary to +remove pressure from prominent parts. Absolute dryness of the skin is +all-important. At least once a day, the sacrum, buttocks, +shoulder-blades, heels, elbows, malleoli, or other parts exposed to +pressure, must be sponged with soap and water, thoroughly dried, and +then rubbed with methylated spirit, which is allowed to dry on the skin. +Dusting the part with boracic acid powder not only keeps it dry, but +prevents the development of bacteria in the skin secretions. + +In operation cases, care must be taken that irritating chemicals used to +purify the skin do not collect under the patient and remain in contact +with the skin of the sacrum and buttocks during the time he is on the +operating-table. There is reason to believe that the so-called +"post-operation bed-sore" may be due to such causes. A similar result +has been known to follow soiling of the sheets by the escape of a +turpentine enema. + +_Treatment._--Once a bed-sore has formed, every effort must be made to +prevent its spread. Alcohol is used to cleanse the broken surface, and +dry absorbent dressings are applied and frequently changed. It is +sometimes found necessary to employ moist or oily substances, such as +boracic poultices, eucalyptus ointment, or balsam of Peru, to facilitate +the separation of sloughs, or to promote the growth of granulations. In +patients who are not extremely debilitated the slough may be excised, +the raw surface scraped, and then painted with iodine. + +Skin-grafting is sometimes useful in covering in the large raw surface +left after separation or removal of sloughs. + + + + +CHAPTER VII + +BACTERIAL AND OTHER WOUND INFECTIONS + + +_Erysipelas_--_Diphtheria_--_Tetanus_--_Hydrophobia_--_Anthrax_-- + _Glanders_--_Actinomycosis_--_Mycetoma_--_Delhi + boil_--_Chigoe_--_Poisoning by insects_--_Snake-bites_. + + +ERYSIPELAS + +Erysipelas, popularly known as "rose," is an acute spreading infective +disease of the skin or of a mucous membrane due to the action of a +streptococcus. Infection invariably takes place through an abrasion of +the surface, although this may be so slight that it escapes observation +even when sought for. The streptococci are found most abundantly in the +lymph spaces just beyond the swollen margin of the inflammatory area, +and in the serous blebs which sometimes form on the surface. + +#Clinical Features.#--_Facial erysipelas_ is the commonest clinical +variety, infection usually occurring through some slight abrasion in the +region of the mouth or nose, or from an operation wound in this area. +From this point of origin the inflammation may spread all over the face +and scalp as far back as the nape of the neck. It stops, however, at the +chin, and never extends on to the front of the neck. There is great +oedema of the face, the eyes becoming closed up, and the features +unrecognisable. The inflammation may spread to the meninges, the +intracranial venous sinuses, the eye, or the ear. In some cases the +erysipelas invades the mucous membrane of the mouth, and spreads to the +fauces and larynx, setting up an oedema of the glottis which may prove +dangerous to life. + +Erysipelas occasionally attacks an operation wound that has become +septic; and it may accompany septic infection of the genital tract in +puerperal women, or the separation of the umbilical cord in infants +(_erysipelas neonatorum_). After an incubation period, which varies from +fifteen to sixty hours, the patient complains of headache, pains in the +back and limbs, loss of appetite, nausea, and frequently there is +vomiting. He has a chill or slight rigor, initiating a rise of +temperature to 103 o, 104 o, or 105 o F.; and a full bounding pulse of +about 100 (Fig. 25). The tongue is foul, the breath heavy, and, as a +rule, the bowels are constipated. There is frequently albuminuria, and +occasionally nocturnal delirium. A moderate degree of leucocytosis +(15,000 to 20,000) is usually present. + +Around the seat of inoculation a diffuse red patch forms, varying in hue +from a bright scarlet to a dull brick-red. The edges are slightly raised +above the level of the surrounding skin, as may readily be recognised by +gently stroking the part from the healthy towards the affected area. The +skin is smooth, tense, and glossy, and presents here and there blisters +filled with serous fluid. The local temperature is raised, and the part +is the seat of a burning sensation and is tender to the touch, the most +tender area being the actively spreading zone which lies about half an +inch beyond the red margin. + +[Illustration: FIG. 25.--Chart of Erysipelas occurring in a wound.] + +The disease tends to spread spasmodically and irregularly, and the +direction and extent of its progress may be recognised by mapping out +the peripheral zone of tenderness. Red streaks appear along the lines of +the superficial lymph vessels, and the deep lymphatics may sometimes be +palpated as firm, tender cords. The neighbouring glands, also, are +generally enlarged and tender. + +The disease lasts for from two or three days to as many weeks, and +relapses are frequent. Spontaneous resolution usually takes place, but +the disease may prove fatal from absorption of toxins, involvement of +the brain or meninges, or from general streptococcal infection. + +#Complications.#--_Diffuse suppurative cellulitis_ is the most serious +local complication, and results from a mixed infection with other +pyogenic bacteria. Small _localised superficial abscesses_ may form +during the convalescent stage. They are doubtless due to the action of +skin bacteria, which attack the tissues devitalised by the erysipelas. A +persistent form of _oedema_ sometimes remains after recurrent attacks of +erysipelas, especially when they affect the face or the lower extremity, +a condition which is referred to with elephantiasis. + +#Treatment.#--The first indication is to endeavour to arrest the spread +of the process. We have found that by painting with linimentum iodi, a +ring half an inch broad, about an inch in front of the peripheral tender +zone--not the red margin--an artificial leucocytosis is produced, and +the advancing streptococci are thereby arrested. Several coats of the +iodine are applied, one after the other, and this is repeated daily for +several days, even although the erysipelas has not overstepped the ring. +Success depends upon using the liniment of iodine (the tincture is not +strong enough), and in applying it well in front of the disease. To +allay pain the most useful local applications are ichthyol ointment (1 +in 6), or lead and opium fomentations. + +The general treatment consists in attending to the emunctories, in +administrating quinine in small--two-grain--doses every four hours, or +salicylate of iron (2-5 gr. every three hours), and in giving plenty of +fluid nourishment. It is worthy of note that the anti-streptococcic +serum has proved of less value in the treatment of erysipelas than might +have been expected, probably because the serum is not made from the +proper strain of streptococcus. + +It is not necessary to isolate cases of erysipelas, provided the usual +precautions against carrying infection from one patient to another are +rigidly carried out. + + +DIPHTHERIA + +Diphtheria is an acute infective disease due to the action of a specific +bacterium, the _bacillus diphtheriae_ or _Klebs-Loffler bacillus_. The +disease is usually transmitted from one patient to another, but it may +be contracted from cats, fowls, or through the milk of infected cows. +Cases have occurred in which the surgeon has carried the infection from +one patient to another through neglect of antiseptic precautions. The +incubation period varies from two to seven days. + +#Clinical Features.#--In _pharyngeal diphtheria_, on the first or +second day of the disease, redness and swelling of the mucous membrane +of the pharynx, tonsils, and palate are well marked, and small, circular +greenish or grey patches of false membrane, composed of necrosed +epithelium, fibrin, leucocytes, and red blood corpuscles, begin to +appear. These rapidly increase in area and thickness, till they coalesce +and form a complete covering to the parts. In the pharynx the false +membrane is less adherent to the surface than it is when the disease +affects the air-passages. The diphtheritic process may spread from the +pharynx to the nasal cavities, causing blocking of the nares, with a +profuse ichorous discharge from the nostrils, and sometimes severe +epistaxis. The infection may spread along the nasal duct to the +conjunctiva. The middle ear also may become involved by spread along the +auditory (Eustachian) tube. + +The lymph glands behind the angle of the jaw enlarge and become tender, +and may suppurate from superadded infection. There is pain on +swallowing, and often earache; and the patient speaks with a nasal +accent. He becomes weak and anaemic, and loses his appetite. There is +often albuminuria. Leucocytosis is usually well marked before the +injection of antitoxin; after the injection there is usually a +diminution in the number of leucocytes. The false membrane may separate +and be cast off, after which the patient gradually recovers. Death may +take place from gradual failure of the heart's action or from syncope +during some slight exertion. + +_Laryngeal Diphtheria._--The disease may arise in the larynx, although, +as a rule, it spreads thence from the pharynx. It first manifests itself +by a short, dry, croupy cough, and hoarseness of the voice. The first +difficulty in breathing usually takes place during the night, and once +it begins, it rapidly gets worse. Inspiration becomes noisy, sometimes +stridulous or metallic or sibilant, and there is marked indrawing of the +epigastrium and lower intercostal spaces. The hoarseness becomes more +marked, the cough more severe, and the patient restless. The difficulty +of breathing occurs in paroxysms, which gradually increase in frequency +and severity, until at length the patient becomes asphyxiated. The +duration of the disease varies from a few hours to four or five days. + +After the acute symptoms have passed off, various localised +paralyses may develop, affecting particularly the nerves of the palatal +and orbital muscles, less frequently the lower limbs. + +#Diagnosis.#--The finding of the Klebs-Loffler bacillus is the only +conclusive evidence of the disease. The bacillus may be obtained by +swabbing the throat with a piece of aseptic--not antiseptic--cotton wool +or clean linen rag held in a pair of forceps, and rotated so as to +entangle portions of the false membrane or exudate. The swab thus +obtained is placed in a test-tube, previously sterilised by having had +some water boiled in it, and sent to a laboratory for investigation. To +identify the bacillus a piece of the membrane from the swab is rubbed on +a cover glass, dried, and stained with methylene blue or other basic +stain; or cultures may be made on agar or other suitable medium. When a +bacteriological examination is impossible, or when the clinical features +do not coincide with the results obtained, the patient should always be +treated on the assumption that he suffers from diphtheria. So much doubt +exists as to the real nature of membranous croup and its relationship to +true diphtheria, that when the diagnosis between the two is uncertain +the safest plan is to treat the case as one of diphtheria. + +In children, diphtheria may occur on the vulva, vagina, prepuce, or +glans penis, and give rise to difficulty in diagnosis, which is only +cleared up by demonstration of the bacillus. + +#Treatment.#--An attempt may be made to destroy or to counteract the +organisms by swabbing the throat with strong antiseptic solutions, such +as 1 in 1000 corrosive sublimate or 1 in 30 carbolic acid, or by +spraying with peroxide of hydrogen. + +The antitoxic serum is our sheet-anchor in the treatment of diphtheria, +and recourse should be had to its use as early as possible. + +Difficulty of swallowing may be met by the use of a stomach tube passed +either through the mouth or nose. When this is impracticable, nutrient +enemata are called for. + +In laryngeal diphtheria, the interference with respiration may call for +intubation of the larynx, or tracheotomy, but the antitoxin treatment +has greatly diminished the number of cases in which it becomes necessary +to have recourse to these measures. + +Intubation consists in introducing through the mouth into the larynx a +tube which allows the patient to breathe freely during the period while +the membrane is becoming separated and thrown off. This is best done +with the apparatus of O'Dwyer; but when this instrument is not +available, a simple gum-elastic catheter with a terminal opening (as +suggested by Macewen and Annandale) may be employed. + +When intubation is impracticable, the operation of tracheotomy is +called for if the patient's life is endangered by embarrassment of +respiration. Unless the patient is in hospital with skilled assistance +available, tracheotomy is the safer of the two procedures. + + +TETANUS + +Tetanus is a disease resulting from infection of a wound by a specific +micro-organism, the _bacillus tetani_, and characterised by increased +reflex excitability, hypertonus, and spasm of one or more groups of +voluntary muscles. + +_Etiology and Morbid Anatomy._--The tetanus bacillus, which is a perfect +anaerobe, is widely distributed in nature and can be isolated from +garden earth, dung-heaps, and stable refuse. It is a slender rod-shaped +bacillus, with a single large spore at one end giving it the shape of a +drum-stick (Fig. 26). The spores, which are the active agents in +producing tetanus, are highly resistant to chemical agents, retain their +vitality in a dry condition, and even survive boiling for five minutes. + +The organism does not readily establish itself in the human body, and +seems to flourish best when it finds a nidus in necrotic tissue and is +accompanied by aerobic organisms, which, by using up the oxygen in the +tissues, provide for it a suitable environment. The presence of a +foreign body in the wound seems to favour its action. The infection is +for all practical purposes a local one, the symptoms of the disease +being due to the toxins produced in the wound of infection acting upon +the central nervous system. + +The toxin acts principally on the nerve centres in the spinal medulla, +to which it travels from the focus of infection by way of the nerve +fibres supplying the voluntary muscles. Its first effect on the motor +ganglia of the cord is to render them hypersensitive, so that they are +excited by mild stimuli, which under ordinary conditions would produce +no reaction. As the toxin accumulates the reflex arc is affected, with +the result that when a stimulus reaches the ganglia a motor discharge +takes place, which spreads by ascending and descending collaterals to +the reflex apparatus of the whole cord. As the toxin spreads it causes +both motor hyper-tonus and hyper-excitability, which accounts for the +tonic contraction and the clonic spasms characteristic of tetanus. + +[Illustration: FIG. 26.--Bacillus of Tetanus from scraping of a wound of +finger, x 1000 diam. Basic fuchsin stain.] + +#Clinical Varieties of Tetanus.#--_Acute_ or _Fulminating +Tetanus_.--This variety is characterised by the shortness of the +incubation period, the rapidity of its progress, the severity of its +symptoms, and its all but universally fatal issue in spite of +treatment, death taking place in from one to four days. The +characteristic symptoms may appear within three or four days of the +infliction of the wound, but the incubation period may extend to three +weeks, and the wound may be quite healed before the disease declares +itself--_delayed tetanus_. Usually, however, the wound is inflamed and +suppurating, with ragged and sloughy edges. A slight feverish attack may +mark the onset of the tetanic condition, or the patient may feel +perfectly well until the spasms begin. If careful observations be made, +it may be found that the muscles in the immediate neighbourhood of the +wound are the first to become contracted; but in the majority of +instances the patient's first complaint is of pain and stiffness in the +muscles of mastication, notably the masseter, so that he has difficulty +in opening the mouth--hence the popular name "lock-jaw." The muscles of +expression soon share in the rigidity, and the face assumes a taut, +mask-like aspect. The angles of the mouth may be retracted, producing a +grinning expression known as the _risus sardonicus_. + +The next muscles to become stiff and painful are those of the neck, +especially the sterno-mastoid and trapezius. The patient is inclined to +attribute the pain and stiffness to exposure to cold or rheumatism. At +an early stage the diaphragm and the muscles of the anterior abdominal +wall become contracted; later the muscles of the back and thorax are +involved; and lastly those of the limbs. Although this is the typical +order of involvement of the different groups of muscles, it is not +always adhered to. + +To this permanent tonic contraction of the muscles there are soon added +clonic spasms. These spasms are at first slight and transient, with +prolonged intervals between the attacks, but rapidly tend to become more +frequent, more severe, and of longer duration, until eventually the +patient simply passes out of one seizure into another. + +The distribution of the spasms varies in different cases: in some it is +confined to particular groups of muscles, such as those of the neck, +back, abdominal walls, or limbs; in others all these groups are +simultaneously involved. + +When the muscles of the back become spasmodically contracted, the body +is raised from the bed, sometimes to such an extent that the patient +rests only on his heels and occiput--the position of _opisthotonos_. +Lateral arching of the body from excessive action of the muscles on one +side--_pleurosthotonos_--is not uncommon, the arching usually taking +place towards the side on which the wound of infection exists. Less +frequently the body is bent forward so that the knees and chin almost +meet (_emprosthotonos_). Sometimes all the muscles simultaneously become +rigid, so that the body assumes a statuesque attitude (_orthotonos_). +When the thoracic muscles, including the diaphragm, are thrown into +spasm, the patient experiences a distressing sensation as if he were +gripped in a vice, and has extreme difficulty in getting breath. Between +the attacks the limbs are kept rigidly extended. The clonic spasms may +be so severe as to rupture muscles or even to fracture one of the long +bones. + +As time goes on, the clonic exacerbations become more and more frequent, +and the slightest external stimulus, such as the feeling of the pulse, a +whisper in the room, a noise in the street, a draught of cold air, the +effort to swallow, a question addressed to the patient or his attempt to +answer, is sufficient to determine an attack. The movements are so +forcible and so continuous that the nurse has great difficulty in +keeping the bedclothes on the patient, or even in keeping him in bed. + +The general condition of the patient is pitiful in the extreme. He is +fully conscious of the gravity of the disease, and his mind remains +clear to the end. The suffering induced by the cramp-like spasms of the +muscles keeps him in a constant state of fearful apprehension of the +next seizure, and he is unable to sleep until he becomes utterly +exhausted. + +The temperature is moderately raised (100 o to 102 o F.), or may remain +normal throughout. Shortly before death very high temperatures (110 o F.) +have been recorded, and it has been observed that the thermometer +sometimes continues to rise after death, and may reach as high as +112 o F. or more. + +The pulse corresponds with the febrile condition. It is accelerated +during the spasms, and may become exceedingly rapid and feeble before +death, probably from paralysis of the vagus. Sudden death from cardiac +paralysis or from cardiac spasm is not uncommon. + +The respiration is affected in so far as the spasms of the respiratory +muscles produce dyspnoea, and a feeling of impending suffocation which +adds to the horrors of the disease. + +One of the most constant symptoms is a copious perspiration, the patient +being literally bathed in sweat. The urine is diminished in quantity, +but as a rule is normal in composition; as in other acute infective +conditions, albumen and blood may be present. Retention of urine may +result from spasm of the urethral muscles, and necessitate the use of +the catheter. + +The fits may cease some time before death, or, on the other hand, death +may occur during a paroxysm from fixation of the diaphragm and arrest of +respiration. + +_Differential Diagnosis._--There is little difficulty, as a rule, in +diagnosing a case of fulminating tetanus, but there are several +conditions with which it may occasionally be confused. In _strychnin +poisoning_, for example, the spasms come on immediately after the +patient has taken a toxic dose of the drug; they are clonic in +character, but the muscles are relaxed between the fits. If the dose is +not lethal, the spasms soon cease. In _hydrophobia_ a history of having +been bitten by a rabid animal is usually forthcoming; the spasms, which +are clonic in character, affect chiefly the muscles of respiration and +deglutition, and pass off entirely in the intervals between attacks. +Certain cases of _haemorrhage into the lateral ventricles_ of the brain +also simulate tetanus, but an analysis of the symptoms will prevent +errors in diagnosis. _Cerebro-spinal meningitis_ and _basal meningitis_ +present certain superficial resemblances to tetanus, but there is no +trismus, and the spasms chiefly affect the muscles of the neck and +back. _Hysteria and catalepsy_ may assume characters resembling those +of tetanus, but there is little difficulty in distinguishing between +these diseases. Lastly, in the _tetany_ of children, or that following +operations on the thyreoid gland, the spasms are of a jerking character, +affect chiefly the hands and fingers, and yield to medicinal treatment. + +#Chronic Tetanus.#--The difference between this and acute tetanus is +mainly one of degree. Its incubation period is longer, it is more slow +and insidious in its progress, and it never reaches the same degree of +severity. Trismus is the most marked and constant form of spasm; and +while the trunk muscles may be involved, those of respiration as a rule +escape. Every additional day the patient lives adds to the probability +of his ultimate recovery. When the disease does prove fatal, it is from +exhaustion, and not from respiratory or cardiac spasm. The usual +duration is from six to ten weeks. + +#Delayed Tetanus.#--During the European War acute tetanus occasionally +developed many weeks or even months after a patient had been injured, +and when the original wound had completely healed. It usually followed +some secondary operation, _e.g._, for the removal of a foreign body, or +the breaking down of adhesions, which aroused latent organisms. + +#Local Tetanus.#--This term is applied to a form of the disease in which +the hypertonus and spasms are localised to the muscles in the vicinity +of the wound. It usually occurs in patients who have had prophylactic +injections of anti-tetanic serum, the toxins entering the blood being +probably neutralised by the antibodies in circulation, while those +passing along the motor nerves are unaffected. + +When it occurs in the _limbs_, attention is usually directed to the fact +by pain accompanying the spasms; the muscles are found to be hard and +there are frequent twitchings of the limb. A characteristic reflex is +present in the lower extremity, namely, extension of the foot and leg +when the sole is tickled. + +_Cephalic Tetanus_ is another localised variety which follows injury in +the distribution of the facial nerve. It is characterised by the +occurrence on the same side as the injury, of facial spasm, rapidly +followed by more or less complete paralysis of the muscles of +expression, with unilateral trismus and difficulty in swallowing. Other +cranial nerves, particularly the oculomotor and the hypoglossal, may +also be implicated. A remarkable feature of this condition is that +although the muscles are irresponsive to ordinary physiological stimuli, +they are thrown into spasm by the abnormal impulses of tetanus. + +_Trismus._--This term is used to denote a form of tetanic spasm limited +to the muscles of mastication. It is really a mild form of chronic +tetanus, and the prognosis is favourable. It must not be confused with +the fixation of the jaw sometimes associated with a wisdom-tooth +gumboil, with tonsillitis, or with affections of the temporo-mandibular +articulation. + +_Tetanus neonatorum_ is a form of tetanus occurring in infants of about +a week old. Infection takes place through the umbilicus, and manifests +itself clinically by spasms of the muscles of mastication. It is almost +invariably fatal within a few days. + +_Prophylaxis._--Experience in the European War has established the +fact that the routine injection of anti-tetanic serum to all patients +with lacerated and contaminated wounds greatly reduces the frequency of +tetanus. The sooner the serum is given after the injury, the more +certain is its effect; within twenty-four hours 1500 units injected +subcutaneously is sufficient for the initial dose; if a longer period +has elapsed, 2000 to 3000 units should be given intra-muscularly, as +this ensures more rapid absorption. A second injection is given a week +after the first. + +The wound must be purified in the usual way, and all instruments and +appliances used for operations on tetanic patients must be immediately +sterilised by prolonged boiling. + +_Treatment._--When tetanus has developed the main indications are to +prevent the further production of toxins in the wound, and to neutralise +those that have been absorbed into the nervous system. Thorough +purification with antiseptics, excision of devitalised tissues, and +drainage of the wound are first carried out. To arrest the absorption of +toxins intra-muscular injections of 10,000 units of serum are given +daily into the muscles of the affected limb, or directly into the nerve +trunks leading from the focus of infection, in the hope of "blocking" +the nerves with antitoxin and so preventing the passage of toxins +towards the spinal cord. + +To neutralise the toxins that have already reached the spinal cord, 5000 +units should be injected intra-thecally daily for four or five days, the +foot of the bed being raised to enable the serum to reach the upper +parts of the cord. + +The quantity of toxin circulating in the blood is so small as to be +practically negligible, and the risk of anaphylactic shock attending +intra-venous injection outweighs any benefit likely to follow this +procedure. + +Baccelli recommends the injection of 20 c.c. of a 1 in 100 solution of +carbolic acid into the subcutaneous tissues every four hours during the +period that the contractions persist. Opinions vary as to the +efficiency of this treatment. The intra-thecal injection of 10 c.c. of a +15 per cent. solution of magnesium sulphate has proved beneficial in +alleviating the severity of the spasms, but does not appear to have a +curative effect. + +To conserve the patient's strength by preventing or diminishing the +severity of the spasms, he should be placed in a quiet room, and every +form of disturbance avoided. Sedatives, such as bromides, paraldehyde, +or opium, must be given in large doses. Chloral is perhaps the best, and +the patient should rarely have less than 150 grains in twenty-four +hours. When he is unable to swallow, it should be given by the rectum. +The administration of chloroform is of value in conserving the strength +of the patient, by abolishing the spasms, and enabling the attendants to +administer nourishment or drugs either through a stomach tube or by the +rectum. Extreme elevation of temperature is met by tepid sponging. It is +necessary to use the catheter if retention of urine occurs. + + +HYDROPHOBIA + +Hydrophobia is an acute infective disease following on the bite of a +rabid animal. It most commonly follows the bite or lick of a rabid dog +or cat. The virus appears to be communicated through the saliva of the +animal, and to show a marked affinity for nerve tissues; and the disease +is most likely to develop when the patient is infected on the face or +other uncovered part, or in a part richly endowed with nerves. + +A dog which has bitten a person should on no account be killed until its +condition has been proved one way or the other. Should rabies develop +and its destruction become necessary, the head and spinal cord should be +retained and forwarded, packed in ice, to a competent observer. Much +anxiety to the person bitten and to his friends would be avoided if +these rules were observed, because in many cases it will be shown that +the animal did not after all suffer from rabies, and that the patient +consequently runs no risk. If, on the other hand, rabies is proved to be +present, the patient should be submitted to the Pasteur treatment. + +_Clinical Features._--There is almost always a history of the patient +having been bitten or licked by an animal supposed to suffer from +rabies. The incubation period averages about forty days, but varies from +a fortnight to seven or eight months, and is shorter in young than in +old persons. The original wound has long since healed, and beyond a +slight itchiness or pain shooting along the nerves of the part, shows no +sign of disturbance. A few days of general malaise, with chills and +giddiness precede the onset of the acute manifestations, which affect +chiefly the muscles of deglutition and respiration. One of the earliest +signs is that the patient has periodically a sudden catch in his +breathing "resembling what often occurs when a person goes into a cold +bath." This is due to spasm of the diaphragm, and is frequently +accompanied by a loud-sounding hiccough, likened by the laity to the +barking of a dog. Difficulty in swallowing fluids may be the first +symptom. + +The spasms rapidly spread to all the muscles of deglutition and +respiration, so that the patient not only has the greatest difficulty in +swallowing, but has a constant sense of impending suffocation. To add to +his distress, a copious secretion of viscid saliva fills his mouth. Any +voluntary effort, as well as all forms of external stimuli, only serve +to aggravate the spasms which are always induced by the attempt to +swallow fluid, or even by the sound of running water. + +The temperature is raised; the pulse is small, rapid, and intermittent; +and the urine may contain sugar and albumen. + +The mind may remain clear to the end, or the patient may have delusions, +supposing himself to be surrounded by terrifying forms. There is always +extreme mental agitation and despair, and the sufferer is in constant +fear of his impending fate. Happily the inevitable issue is not long +delayed, death usually occurring in from two to four days from the +onset. The symptoms of the disease are so characteristic that there is +no difficulty in diagnosis. The only condition with which it is liable +to be confused is the variety of cephalic tetanus in which the muscles +of deglutition are specially involved--the so-called tetanus +hydrophobicus. + +_Prophylaxis._--The bite of an animal suspected of being rabid should be +cauterised at once by means of the actual or Paquelin cautery, or by a +strong chemical escharotic such as pure carbolic acid, after which +antiseptic dressings are applied. + +It is, however, to Pasteur's _preventive inoculation_ that we must look +for our best hope of averting the onset of symptoms. "It may now be +taken as established that a grave responsibility rests on those +concerned if a person bitten by a mad animal is not subjected to the +Pasteur treatment" (Muir and Ritchie). + +This method is based on the fact that the long incubation period of the +disease admits of the patient being inoculated with a modified virus +producing a mild attack, which protects him from the natural disease. + +_Treatment._--When the symptoms have once developed they can only be +palliated. The patient must be kept absolutely quiet and free from all +sources of irritation. The spasms may be diminished by means of chloral +and bromides, or by chloroform inhalation. + + +ANTHRAX + +Anthrax is a comparatively rare disease, communicable to man from +certain of the lower animals, such as sheep, oxen, horses, deer, and +other herbivora. In animals it is characterised by symptoms of acute +general poisoning, and, from the fact that it produces a marked +enlargement of the spleen, is known in veterinary surgery as "splenic +fever." + +The _bacillus anthracis_ (Fig. 27), the largest of the known pathogenic +bacteria, occurs in groups or in chains made up of numerous bacilli, +each bacillus measuring from 6 to 8 u in length. The organisms are found +in enormous numbers throughout the bodies of animals that have died of +anthrax, and are readily recognised and cultivated. Sporulation only +takes place outside the body, probably because free oxygen is necessary +to the process. In the spore-free condition, the organisms are readily +destroyed by ordinary germicides, and by the gastric juice. The spores, +on the other hand, have a high degree of resistance. Not only do they +remain viable in the dry state for long periods, even up to a year, but +they survive boiling for five minutes, and must be subjected to dry heat +at 140 o C. for several hours before they are destroyed. + +[Illustration: FIG. 27.--Bacillus of Anthrax in section of skin, from a +case of malignant pustule; shows vesicle containing bacilli. x 400 diam. +Gram's stain.] + +_Clinical Varieties of Anthrax._--In man, anthrax may manifest itself in +one of three clinical forms. + +It may be transmitted by means of spores or bacilli directly from a +diseased animal to those who, by their occupation or otherwise, are +brought into contact with it--for example, shepherds, butchers, +veterinary surgeons, or hide-porters. Infection may occur on the face by +the use of a shaving-brush contaminated by spores. The path of infection +is usually through an abrasion of the skin, and the primary +manifestations are local, constituting what is known as _the malignant +pustule_. + +In other cases the disease is contracted through the inhalation of the +dried spores into the respiratory passages. This occurs oftenest in +those who work amongst wool, fur, and rags, and a form of acute +pneumonia of great virulence ensues. This affection is known as +_wool-sorter's disease_, and is almost universally fatal. + +There is reason to believe that infection may also take place by means +of spores ingested into the alimentary canal in meat or milk derived +from diseased animals, or in infected water. + +#Clinical Features of Malignant Pustule.#--We shall here confine +ourselves to the consideration of the local lesion as it occurs in the +skin--_the malignant pustule_. + +The point of infection is usually on an uncovered part of the body, such +as the face, hands, arms, or back of the neck, and the wound may be +exceedingly minute. After an incubation period varying from a few hours +to several days, a reddish nodule resembling a small boil appears at the +seat of inoculation, the immediately surrounding skin becomes swollen +and indurated, and over the indurated area there appear a number of +small vesicles containing serum, which at first is clear but soon +becomes blood-stained (Fig. 28). Coincidently the subcutaneous tissue +for a considerable distance around becomes markedly oedematous, and the +skin red and tense. Within a few hours, blood is extravasated in the +centre of the indurated area, the blisters burst, and a dark brown or +black eschar, composed of necrosed skin and subcutaneous tissue and +altered blood, forms (Fig. 29). Meanwhile the induration extends, fresh +vesicles form and in turn burst, and the eschar increases in size. The +neighbouring lymph glands soon become swollen and tender. The affected +part is hot and itchy, but the patient does not complain of great pain. +There is a moderate degree of constitutional disturbance, with headache, +nausea, and sometimes shivering. + +If the infection becomes generalised--_anthracaemia_--the temperature +rises to 103 o or 104 o F., the pulse becomes feeble and rapid, and other +signs of severe blood-poisoning appear: vomiting, diarrhoea, pains in the +limbs, headache and delirium, and the condition proves fatal in from +five to eight days. + +_Differential Diagnosis._--When the malignant pustule is fully +developed, the central slough with the surrounding vesicles and the +widespread oedema are characteristic. The bacillus can be obtained from +the peripheral portion of the slough, from the blisters, and from the +adjacent lymph vessels and glands. The occupation of the patient may +suggest the possibility of anthrax infection. + +[Illustration: FIG. 28.--Malignant Pustule, third day after infection +with Anthrax, showing great oedema of upper extremity and pectoral region +(cf. Fig. 29).] + +[Illustration: FIG. 29.--Malignant Pustule, fourteen days after +infection, showing black eschar in process of separation. The oedema has +largely disappeared. Treated by Sclavo's serum (cf. Fig. 28).] + +_Prophylaxis._--Any wound suspected of being infected with anthrax +should at once be cauterised with caustic potash, the actual cautery, or +pure carbolic acid. + +_Treatment._--The best results hitherto obtained have followed the use +of the anti-anthrax serum introduced by Sclavo. The initial dose is 40 +c.c., and if the serum is given early in the disease, the beneficial +effects are manifest in a few hours. Favourable results have also +followed the use of pyocyanase, a vaccine prepared from the bacillus +pyocyaneus. + +By some it is recommended that the local lesion should be freely +excised; others advocate cauterisation of the affected part with solid +caustic potash till all the indurated area is softened. Graf has had +excellent results by the latter method in a large series of cases, the +oedema subsiding in about twenty-four hours and the constitutional +symptoms rapidly improving. Wolff and Wiewiorowski, on the other hand, +have had equally good results by simply protecting the local lesion with +a mild antiseptic dressing, and relying upon general treatment. + +The general treatment consists in feeding and stimulating the patient as +freely as possible. Quinine, in 5 to 10 grain doses every four hours, +and powdered ipecacuanha, in 40 to 60 grain doses every four hours, have +also been employed with apparent benefit. + + +GLANDERS + +Glanders is due to the action of a specific bacterium, the _bacillus +mallei_, which resembles the tubercle bacillus, save that it is somewhat +shorter and broader, and does not stain by Gram's method. It requires +higher temperatures for its cultivation than the tubercle bacillus, and +its growth on potato is of a characteristic chocolate-brown colour, with +a greenish-yellow ring at the margin of the growth. The bacillus mallei +retains its vitality for long periods under ordinary conditions, but is +readily killed by heat and chemical agents. It does not form spores. + +_Clinical Features._--Both in the lower animals and in man the bacillus +gives rise to two distinct types of disease--_acute glanders_, and +_chronic glanders_ or _farcy_. + +Acute Glanders is most commonly met with in the horse and in other +equine animals, horned cattle being immune. It affects the septum of the +nose and adjacent parts, firm, translucent, greyish nodules containing +lymphoid and epithelioid cells appearing in the mucous membrane. These +nodules subsequently break down in the centre, forming irregular +ulcers, which are attended with profuse discharge, and marked +inflammatory swelling. The cervical lymph glands, as well as the lungs, +spleen, and liver, may be the seat of secondary nodules. + +_In man_, acute glanders is commoner than the chronic variety. Infection +always takes place through an abraded surface, and usually on one of the +uncovered parts of the body--most commonly the skin of the hands, arms, +or face; or on the mucous membrane of the mouth, nose, or eye. The +disease has been acquired by accidental inoculation in the course of +experimental investigations in the laboratory, and proved fatal. The +incubation period is from three to five days. + +The _local_ manifestations are pain and swelling in the region of the +infected wound, with inflammatory redness around it and along the lines +of the superficial lymphatics. In the course of a week, small, firm +nodules appear, and are rapidly transformed into pustules. These may +occur on the face and in the vicinity of joints, and may be mistaken for +the eruption of small-pox. + +After breaking down, these pustules give rise to irregular ulcers, which +by their confluence lead to extensive destruction of skin. Sometimes the +nasal mucous membrane becomes affected, and produces a discharge--at +first watery, but later sanious and purulent. Necrosis of the bones of +the nose may take place, in which case the discharge becomes peculiarly +offensive. In nearly every case metastatic abscesses form in different +parts of the body, such as the lungs, joints, or muscles. + +During the development of the disease the patient feels ill, complains +of headache and pains in the limbs, the temperature rises to 104 o or +even to 106 o F., and assumes a pyaemic type. The pulse becomes rapid and +weak. The tongue is dry and brown. There is profuse sweating, +albuminuria, and often insomnia with delirium. Death may take place +within a week, but more frequently occurs during the second or third +week. + +_Differential Diagnosis._--There is nothing characteristic in the site +of the primary lesion in man, and the condition may, during the early +stages, be mistaken for a boil or carbuncle, or for any acute +inflammatory condition. Later, the disease may simulate acute articular +rheumatism, or may manifest all the symptoms of acute septicaemia or +pyaemia. The diagnosis is established by the recognition of the bacillus. +Veterinary surgeons attach great importance to the mallein test as a +means of diagnosis in animals, but in the human subject its use is +attended with considerable risk and is not to be recommended. + +_Treatment._--Excision of the primary nodule, followed by the +application of the thermo-cautery and sponging with pure carbolic acid, +should be carried out, provided the condition is sufficiently limited to +render complete removal practicable. + +When secondary abscesses form in accessible situations, they must be +incised, disinfected, and drained. The general treatment is carried out +on the same lines as in other acute infective diseases. + +#Chronic Glanders.#--_In the horse_ the chronic form of glanders is +known as _farcy_, and follows infection through an abrasion of the skin, +involving chiefly the superficial lymph vessels and glands. The +lymphatics become indurated and nodular, constituting what veterinarians +call _farcy pipes_ and _farcy buds_. + +_In man_ also the clinical features of the chronic variety of the +disease are somewhat different from those of the acute form. Here, too, +infection takes place through a broken cutaneous surface, and leads to a +superficial lymphangitis with nodular thickening of the lymphatics +(_farcy buds_). The neighbouring glands soon become swollen and +indurated. The primary lesion meanwhile inflames, suppurates, and, after +breaking down, leaves a large, irregular ulcer with thickened edges and +a foul, purulent or bloody discharge. The glands break down in the same +way, and lead to wide destruction of skin, and the resulting sinuses and +ulcers are exceedingly intractable. Secondary deposits in the +subcutaneous tissue, the muscles, and other parts, are not uncommon, and +the nasal mucous membrane may become involved. The disease often runs a +chronic course, extending to four or five months, or even longer. +Recovery takes place in about 50 per cent. of cases, but the +convalescence is prolonged, and at any time the disease may assume the +characters of the acute variety and speedily prove fatal. + +The _differential diagnosis_ is often difficult, especially in the +chronic nodules, in which it may be impossible to demonstrate the +bacillus. The ulcerated lesions of farcy have to be distinguished from +those of tubercle, syphilis, and other forms of infective granuloma. + +_Treatment._--Limited areas of disease should be completely excised. The +general condition of the patient must be improved by tonics, good food, +and favourable hygienic surroundings. In some cases potassium iodide +acts beneficially. + + +ACTINOMYCOSIS + +Actinomycosis is a chronic disease due to the action of an organism +somewhat higher in the vegetable scale than ordinary bacteria--the +_streptothrix actinomyces_ or _ray fungus_. + +[Illustration: FIG. 30.--Section of Actinomycosis Colony in Pus from +Abscess of Liver, showing filaments and clubs of streptothrix +actinomyces. x 400 diam. Gram's stain.] + +_Etiology and Morbid Anatomy._--The actinomyces, which has never been +met with outside the body, gives rise in oxen, horses, and other animals +to tumour-like masses composed of granulation tissue; and in man to +chronic suppurative processes which may result in a condition resembling +chronic pyaemia. The actinomyces is more complex in structure than other +pathogenic organisms, and occurs in the tissues in the form of small, +round, semi-translucent bodies, about the size of a pin-head or less, +and consisting of colonies of the fungus. On account of their yellow +tint they are spoken of as "sulphur grains." Each colony is made up of a +series of thin, interlacing, and branching _filaments_, some of which +are broken up so as to form masses or chains of _cocci_; and around the +periphery of the colony are elongated, pear-shaped, hyaline, _club-like +bodies_ (Fig. 30). + +Infection is believed to be conveyed by the husks of cereals, especially +barley; and the organism has been found adhering to particles of grain +embedded in the tissues of animals suffering from the disease. In the +human subject there is often a history of exposure to infection from +such sources, and the disease is said to be most common during the +harvesting months. + +Around each colony of actinomyces is a zone of granulation tissue in +which suppuration usually occurs, so that the fungus comes to lie in a +bath of greenish-yellow pus. As the process spreads these purulent foci +become confluent and form abscess cavities. When metastasis takes place, +as it occasionally does, the fungus is transmitted by the blood vessels, +as in pyaemia. + +_Clinical features._--In man the disease may be met with in the skin, +the organisms gaining access through an abrasion, and spreading by the +formation of new nodules in the same way as tuberculosis. + +The region of the mouth and jaws is one of the commonest sites of +surgical actinomycosis. Infection takes place, as a rule, along the side +of a carious tooth, and spreads to the lower jaw. A swelling is slowly +and insidiously developed, but when the loose connective tissue of the +neck becomes infiltrated, the spread is more rapid. The whole region +becomes infiltrated and swollen, and the skin ultimately gives way and +free suppuration occurs, resulting in the formation of sinuses. The +characteristic greenish-grey or yellow granules are seen in the pus, and +when examined microscopically reveal the colonies of actinomyces. + +Less frequently the maxilla becomes affected, and the disease may spread +to the base of the skull and brain. The vertebrae may become involved by +infection taking place through the pharynx or oesophagus, and leading to +a condition simulating tuberculous disease of the spine. When it +implicates the intestinal canal and its accessory glands, the lungs, +pleura, and bronchial tubes, or the brain, the disease is not amenable +to surgical treatment. + +_Differential Diagnosis._--The conditions likely to be mistaken for +surgical actinomycosis are sarcoma, tubercle, and syphilis. In the early +stages the differential diagnosis is exceedingly difficult. In many +cases it is only possible when suppuration has occurred and the fungus +can be demonstrated. + +The slow destruction of the affected tissue by suppuration, the absence +of pain, tenderness, and redness, simulate tuberculosis, but the absence +of glandular involvement helps to distinguish it. + +Syphilitic lesions are liable to be mistaken for actinomycosis, all the +more that in both diseases improvement follows the administration of +iodides. When it affects the lower jaw, in its early stages, +actinomycosis may closely simulate a periosteal sarcoma. + +[Illustration: FIG. 31.--Actinomycosis of Maxilla. The disease spread to +opposite side; finally implicated base of skull, and proved fatal. +Treated by radium. + +(Mr. D. P. D. Wilkie's case.)] + +The recognition of the fungus is the crucial point in diagnosis. + +_Prognosis._--Spontaneous cure rarely occurs. When the disease +implicates internal organs, it is almost always fatal. On external parts +the destructive process gradually spreads, and the patient eventually +succumbs to superadded septic infection. When, from its situation, the +primary focus admits of removal, the prognosis is more favourable. + +_Treatment._--The surgical treatment is early and free removal of the +affected tissues, after which the wound is cauterised by the actual +cautery, and sponged over with pure carbolic acid. The cavity is packed +with iodoform gauze, no attempt being made to close the wound. + +Success has attended the use of a vaccine prepared from cultures of the +organism; and the X-rays and radium, combined with the administration of +iodides in large doses, or with intra-muscular injections of a 10 per +cent. solution of cacodylate of soda, have proved of benefit. + +MYCETOMA, OR MADURA FOOT.--Mycetoma is a chronic disease due to +an organism resembling that of actinomycosis, but not identical with it. +It is endemic in certain tropical countries, and is most frequently met +with in India. Infection takes place through an abrasion of the skin, +and the disease usually occurs on the feet of adult males who work +barefooted in the fields. + +_Clinical Features._--The disease begins on the foot as an indurated +patch, which becomes discoloured and permeated by black or yellow +nodules containing the organism. These nodules break down by +suppuration, and numerous minute abscesses lined by granulation tissues +are thus formed. In the pus are found yellow particles likened to +fish-roe, or black pigmented granules like gunpowder. Sinuses form, and +the whole foot becomes greatly swollen and distorted by flattening of +the sole and dorsiflexion of the toes. Areas of caries or necrosis occur +in the bones, and the disease gradually extends up the leg (Fig. 32). +There is but little pain, and no glandular involvement or constitutional +disturbance. The disease runs a prolonged course, sometimes lasting for +twenty or thirty years. Spontaneous cure never takes place, and the risk +to life is that of prolonged suppuration. + +If the disease is localised, it may be removed by the knife or sharp +spoon, and the part afterwards cauterised. As a rule, amputation well +above the disease is the best line of treatment. Unlike actinomycosis, +this disease does not appear to be benefited by iodides. + +[Illustration: FIG. 32.--Mycetoma, or Madura Foot. (Museum of Royal +College of Surgeons, Edinburgh.)] + +DELHI BOIL.--_Synonyms_--Aleppo boil, Biskra button, Furunculus +orientalis, Natal sore. + +Delhi boil is a chronic inflammatory disease, most commonly met with in +India, especially towards the end of the wet season. The disease occurs +oftenest on the face, and is believed to be due to an organism, although +this has not been demonstrated. The infection is supposed to be conveyed +through water used for washing, or by the bites of insects. + +_Clinical Features._--A red spot, resembling the mark of a mosquito +bite, appears on the affected part, and is attended with itching. After +becoming papular and increasing to the size of a pea, desquamation takes +place, leaving a dull-red surface, over which in the course of several +weeks there develops a series of small yellowish-white spots, from which +serum exudes, and, drying, forms a thick scab. Under this scab the skin +ulcerates, leaving small oval sores with sharply bevelled edges, and an +uneven floor covered with yellow or sanious pus. These sores vary in +number from one to forty or fifty. They may last for months and then +heal spontaneously, or may continue to spread until arrested by suitable +treatment. There is no enlargement of adjacent glands, and but little +inflammatory reaction in the surrounding tissues; nor is there any +marked constitutional disturbance. Recovery is often followed by +cicatricial contraction leading to deformity of the face. + +The _treatment_ consists in destroying the original papule by the actual +cautery, acid nitrate of mercury, or pure carbolic acid. The ulcers +should be scraped with the sharp spoon, and cauterised. + +CHIGOE.--Chigoe or jigger results from the introduction of the +eggs of the sand-flea (_Pulex penetrans_) into the tissues. It occurs in +tropical Africa, South America, and the West Indies. The impregnated +female flea remains attached to the part till the eggs mature, when by +their irritation they cause localised inflammation with pustules or +vesicles on the surface. Children are most commonly attacked, +particularly about the toe-nails and on the scrotum. The treatment +consists in picking out the insect with a blunt needle, special care +being taken not to break it up. The puncture is then cauterised. The +application of essential oils to the feet acts as a preventive. + +POISONING BY INSECTS.--The bites of certain insects, such as +mosquitoes, midges, different varieties of flies, wasps, and spiders, +may be followed by serious complications. The effects are mainly due to +the injection of an irritant acid secretion, the exact nature of which +has not been ascertained. + +The local lesion is a puncture, surrounded by a zone of hyperaemia, +wheals, or vesicles, and is associated with burning sensations and +itching which usually pass off in a few hours, but may recur at +intervals, especially when the patient is warm in bed. Scratching also +reproduces the local signs and symptoms. Where the connective tissue is +loose--for example, in the eyelid or scrotum--there is often +considerable swelling; and in the mouth and fauces this may lead to +oedema of the glottis, which may prove fatal. + +The _treatment_ consists in the local application of dilute alkalies +such as ammonia water, solutions of carbonate or bicarbonate of soda, or +sal-volatile. Weak carbolic lotions, or lead and opium lotion, are +useful in allaying the local irritation. One of the best means of +neutralising the poison is to apply to the sting a drop of a mixture +containing equal parts of pure carbolic acid and liquor ammoniae. + +Free stimulation is called for when severe constitutional symptoms are +present. + +SNAKE-BITES.--We are here only concerned with the injuries +inflicted by the venomous varieties of snakes, the most important of +which are the hooded snakes of India, the rattle-snakes of America, the +horned snakes of Africa, the viper of Europe, and the adder of the +United Kingdom. + +While the virulence of these creatures varies widely, they are all +capable of producing in a greater or less degree symptoms of acute +poisoning in man and other animals. By means of two recurved fangs +attached to the upper jaw, and connected by a duct with poison-secreting +glands, they introduce into their prey a thick, transparent, yellowish +fluid, of acid reaction, probably of the nature of an albumose, and +known as the _venom_. + +The _clinical features_ resulting from the injection of the venom vary +directly in intensity with the amount of the poison introduced, and the +rapidity with which it reaches the circulating blood, being most marked +when it immediately enters a large vein. The poison is innocuous when +taken into the stomach. + +_Locally_ the snake inflicts a double wound, passing vertically into the +subcutaneous tissue; the edges of the punctures are ecchymosed, and the +adjacent vessels the seat of thrombosis. Immediately there is intense +pain, and considerable swelling with congestion, which tends to spread +towards the trunk. Extensive gangrene may ensue. There is no special +involvement of the lymphatics. + +The _general symptoms_ may come on at once if the snake is a +particularly venomous one, or not for some hours if less virulent. In +the majority of viper or adder bites the constitutional disturbance is +slight and transient, if it appears at all. Snake-bites in children are +particularly dangerous. + +The patient's condition is one of profound shock with faintness, +giddiness, dimness of sight, and a feeling of great terror. The pupils +dilate, the skin becomes moist with a clammy sweat, and nausea with +vomiting, sometimes of blood, ensues. High fever, cramps, loss of +sensation, haematuria, and melaena are among the other symptoms that may +be present. The pulse becomes feeble and rapid, the respiratory nerve +centres are profoundly depressed, and delirium followed by coma usually +precedes the fatal issue, which may take place in from five to +forty-eight hours. If the patient survives for two days the prognosis is +favourable. + +_Treatment._--A broad ligature should be tied tightly round the limb +above the seat of infection, to prevent the poison passing into the +general circulation, and bleeding from the wound should be encouraged. +The application of an elastic bandage from above downward to empty the +blood out of the infected portion of the limb has been recommended. The +whole of the bite should at once be excised, and crystals of +permanganate of potash rubbed into the wound until it is black, or +peroxide of hydrogen applied with the object of destroying the poison by +oxidation. + +The general treatment consists in free stimulation with whisky, brandy, +ammonia, digitalis, etc. Hypodermic injections of strychnin in doses +sufficiently large to produce a slight degree of poisoning by the drug +are particularly useful. The most rational treatment, when it is +available, is the use of the _antivenin_ introduced by Fraser and +Calmette. + + + + +CHAPTER VIII + +TUBERCULOSIS + + +Tubercle bacillus--Methods of infection--Inherited and acquired + predisposition--Relationship of tuberculosis to injury--Human and + bovine tuberculosis--Action of the bacillus upon the + tissues--Tuberculous granulation tissue--Natural cure--Recrudescence + of the disease--THE TUBERCULOUS ABSCESS--Contents and wall of the + abscess--Tuberculous sinuses. + +Tuberculosis occurs more frequently in some situations than in others; +it is common, for example, in lymph glands, in bones and joints, in the +peritoneum, the intestine, the kidney, prostate and testis, and in the +skin and subcutaneous cellular tissue; it is seldom met with in the +breast or in muscles, and it rarely affects the ovary, the pancreas, the +parotid, or the thyreoid. + +_Tubercle bacilli_ vary widely in their virulence, and they are more +tenacious of life than the common pyogenic bacteria. In a dry state, for +example, they can retain their vitality for months; and they can also +survive immersion in water for prolonged periods. They resist the action +of the products of putrefaction for a considerable time, and are not +destroyed by digestive processes in the stomach and intestine. They may +be killed in a few minutes by boiling, or by exposure to steam under +pressure, or by immersion for less than a minute in 1 in 20 carbolic +lotion. + +#Methods of Infection.#--In marked contrast to what obtains in the +infective diseases that have already been described, tuberculosis rarely +results from the _infection of a wound_. In exceptional instances, +however, this does occur, and in illustration of the fact may be cited +the case of a servant who cut her finger with a broken spittoon +containing the sputum of her consumptive master; the wound subsequently +showed evidence of tuberculous infection, which ultimately spread up +along the lymph vessels of the arm. Pathologists, too, whose hands, +before the days of rubber gloves, were frequently exposed to the contact +of tuberculous tissues and pus, were liable to suffer from a form of +tuberculosis of the skin of the finger, known as _anatomical tubercle_. +Slight wounds of the feet in children who go about barefoot in towns +sometimes become infected with tubercle. Operation wounds made with +instruments contaminated with tuberculous material have also been known +to become infected. It is highly probable that the common form of +tuberculosis of the skin known as "lupus" arises by direct infection +from without. + +[Illustration: FIG. 33.--Tubercle Bacilli in caseous material +x 1000 diam. Z. Neilsen stain.] + +In the vast majority of cases the tubercle bacillus gains entrance to +the body by way of the mucous surfaces, the organisms being either +inhaled or swallowed; those inhaled are mostly derived from the human +subject, those swallowed, from cattle. Bacilli, whether inhaled or +swallowed, are especially apt to lodge about the pharynx and pass to the +pharyngeal lymphoid tissue and tonsils, and by way of the lymph vessels +to the glands. The glands most frequently infected in this way are the +cervical glands, and those within the cavity of the chest--particularly +the bronchial glands at the root of the lung. From these, infection +extends at any later period in life to the bones, joints, and internal +organs. + +There is reason to believe that the organisms may lie in a dormant +condition for an indefinite period in these glands, and only become +active long afterwards, when some depression of the patient's health +produces conditions which favour their growth. When the organisms become +active in this way, the tuberculous tissue undergoes softening and +disintegration, and the infective material, by bursting into an adjacent +vein, may enter the blood-stream, in which it is carried to distant +parts of the body. In this way a _general tuberculosis_ may be set up, +or localised foci of tuberculosis may develop in the tissues in which +the organisms lodge. Many tuberculous patients are to be regarded as +possessing in their bronchial glands, or elsewhere, an internal store of +bacilli, to which the disease for which advice is sought owes its +origin, and from which similar outbreaks of tuberculosis may originate +in the future. + +_The alimentary mucous membrane_, especially that of the lower ileum and +caecum, is exposed to infection by swallowed sputum and by food +materials, such as milk, containing tubercle bacilli. The organisms may +lodge in the mucous membrane and cause tuberculous ulceration, or they +may be carried through the wall of the bowel into the lacteals, along +which they pass to the mesenteric glands where they become arrested and +give rise to tuberculous disease. + +#Relationship of Tuberculosis to Trauma.#--Any tissue whose vitality has +been lowered by injury or disease furnishes a favourable nidus for the +lodgment and growth of tubercle bacilli. The injury or disease, however, +is to be looked upon as determining the _localisation_ of the +tuberculous lesion rather than as an essential factor in its causation. +In a person, for example, in whose blood tubercle bacilli are +circulating and reaching every tissue and organ of the body, the +occurrence of tuberculous disease in a particular part may be determined +by the depression of the tissues resulting from an injury of that part. +There can be no doubt that excessive movement and jarring of a limb +aggravates tuberculous disease of a joint; also that an injury may light +up a focus that has been long quiescent, but we do not agree with +those--Da Costa, for example--who maintain that injury may be a +determining cause of tuberculosis. The question is not one of mere +academic interest, but one that may raise important issues in the law +courts. + +#Human and Bovine Tuberculosis.#--The frequency of the bovine bacillus +in the abdominal and in the glandular and osseous tuberculous lesions of +children would appear to justify the conclusion that the disease is +transmissible from the ox to the human subject, and that the milk of +tuberculous cows is probably a common vehicle of transmission. + +#Changes in the Tissues following upon the successful Lodgment of +Tubercle Bacilli.#--The action of the bacilli on the tissues results in +the formation of granulation tissue comprising characteristic tissue +elements and with a marked tendency to undergo caseation. + +The recognition of the characteristic elements, with or without +caseation, is usually sufficient evidence of the tuberculous nature of +any portion of tissue examined for diagnostic purposes. The recognition +of the bacillus itself by appropriate methods of staining makes the +diagnosis a certainty; but as it is by no means easy to identify the +organism in many forms of surgical tuberculosis, it may be necessary to +have recourse to experimental inoculation of susceptible animals such as +guinea-pigs. + +The changes subsequent to the formation of tuberculous granulation +tissue are liable to many variations. It must always be borne in mind +that although the bacilli have effected a lodgment and have inaugurated +disease, the relation between them and the tissues remains one of mutual +antagonism; which of them is to gain and keep the upper hand in the +conflict depends on their relative powers of resistance. + +If the tissues prevail, there ensues a process of repair. In the +immediate vicinity of the area of infection young connective tissue, and +later, fibrous tissue, is formed. This may replace the tuberculous +tissue and bring about repair--a fibrous cicatrix remaining to mark the +scene of the previous contest. Scars of this nature are frequently +discovered at the apex of the lung after death in persons who have at +one time suffered from pulmonary phthisis. Under other circumstances, +the tuberculous tissue that has undergone caseation, or even +calcification, is only encapsulated by the new fibrous tissue, like a +foreign body. Although this may be regarded as a victory for the +tissues, the cure, if such it may be called, is not necessarily a +permanent one, for at any subsequent period, if the part affected is +disturbed by injury or through some other influence, the encapsulated +tubercle may again become active and get the upper hand of the tissues, +and there results a relapse or recrudescence of the disease. This +_tendency to relapse_ after apparent cure is a notable feature of +tuberculous disease as it is met with in the spine, or in the +hip-joint, and it necessitates a prolonged course of treatment to give +the best chance of a lasting cure. + +If, however, at the inauguration of the tuberculous disease the bacilli +prevail, the infection tends to spread into the tissues surrounding +those originally infected, and more and more tuberculous granulation +tissue is formed. Finally the tuberculous tissue breaks down and +liquefies, resulting in the formation of a cold abscess. In their +struggle with the tissues, tubercle bacilli receive considerable support +and assistance from any pyogenic organisms that may be present. A +tuberculous infection may exhibit its aggressive qualities in a more +serious manner by sending off detachments of bacilli, which are carried +by the lymphatics to the nearest glands, or by the blood-stream to more +distant, and it may be to all, parts of the body. When the infection is +thus generalised, the condition is called _general tuberculosis_. +Considering the extraordinary frequency of localised forms of surgical +tuberculosis, general dissemination of the disease is rare. + +#The clinical features# of surgical tuberculosis will be described with +the individual tissues and organs, as they vary widely according to the +situation of the lesion. + +#The general treatment# consists in combating the adverse influences +that have been mentioned as increasing the liability to tuberculous +infection. Within recent years the value of the "open-air" treatment has +been widely recognised. An open-air life, even in the centre of a city, +may be followed by marked improvement, especially in the hospital class +of patient, whose home surroundings tend to favour the progress of the +disease. The purer air of places away from centres of population is +still better; and, according to the idiosyncrasies of the individual +patient, mountain air or that of the sea coast may be preferred. In view +of the possible discomforts and gastric disturbance which may attend a +sea-voyage, this should be recommended to patients suffering from +tuberculous lesions with more caution than has hitherto been exercised. +The diet must be a liberal one, and should include those articles which +are at the same time easily digested and nourishing, especially proteids +and fats; milk obtained from a reliable source and underdone +butcher-meat are among the best. When the ordinary nourishment taken is +insufficient, it may be supplemented by such articles as malt extract, +stout, and cod-liver oil. The last is specially beneficial in patients +who do not take enough fat in other forms. It is noteworthy that many +tuberculous patients show an aversion to fat. + +For _the use of tuberculin in diagnosis_ and for _the vaccine treatment +of tuberculosis_ the reader is referred to text-books on medicine. + +In addition to increasing the resisting power of the patient, it is +important to enable the fluids of the body, so altered, to come into +contact with the tuberculous focus. One of the obstacles to this is that +the focus is often surrounded by tissues or fluids which have been +almost entirely deprived of bactericidal substances. In the case of +caseated glands in the neck, for example, it is obvious that the removal +of this inert material is necessary before the tissues can be irrigated +with fluids of high bactericidal value. Again, in tuberculous ascites +the abdominal cavity is filled with a fluid practically devoid of +anti-bacterial substances, so that the bacilli are able to thrive and +work their will on the tissues. When the stagnant fluid is got rid of by +laparotomy, the parts are immediately douched with lymph charged with +protective substances, the bactericidal power of which may be many times +that of the fluid displaced. + +It is probable that the beneficial influence of _counter-irritants_, +such as blisters, and exposure to the _Finsen light_ and other forms of +_rays_, is to be attributed in part to the increased flow of blood to +the infected tissues. + +_Artificial Hyperaemia._--As has been explained, the induction of +hyperaemia by the method devised by Bier, constitutes one of our most +efficient means of combating bacterial infection. The treatment of +tuberculosis on this plan has been proved by experience to be a valuable +addition to our therapeutic measures, and the simplicity of its +application has led to its being widely adopted in practice. It results +in an increase in the reactive changes around the tuberculous focus, an +increase in the immigration of leucocytes, and infiltration with the +lymphocytes. + +The constricting bandage should be applied at some distance above the +seat of infection; for instance, in disease of the wrist, it is put on +above the elbow, and it must not cause pain either where it is applied +or in the diseased part. The bandage is only applied for a few hours +each day, either two hours at a time or twice a day for one hour, and, +while it is on, all dressings are removed save a piece of sterile gauze +over any wound or sinus that may be present. The process of cure takes a +long time--nine or even twelve months in the case of a severe joint +affection. + +In cases in which a constricting bandage is inapplicable, for example, +in cold abscesses, tuberculous glands or tendon sheaths, Klapp's suction +bell is employed. The cup is applied for five minutes at a time and then +taken off for three minutes, and this is repeated over a period of +about three-quarters of an hour. The pus is allowed to escape by a small +incision, and no packing or drain should be introduced. + +It has been found that tuberculous lesions tend to undergo cure +when the infected tissues are exposed to the rays of the +sun--_heliotherapy_--therefore whenever practicable this therapeutic +measure should be had recourse to. + +Since the introduction of the methods of treatment described above, and +especially by their employment at an early stage in the disease, the +number of cases of tuberculosis requiring operative interference has +greatly diminished. There are still circumstances, however, in which an +operation is required; for example, in disease of the lymph glands for +the removal of inert masses of caseous material, in disease of bone for +the removal of sequestra, or in disease of joints to improve the +function of the limb. It is to be understood, however, that operative +treatment must always be preceded by and combined with other therapeutic +measures. + + +TUBERCULOUS ABSCESS + +The caseation of tuberculous granulation tissue and its liquefaction is +a slow and insidious process, and is unattended with the classical signs +of inflammation--hence the terms "cold" and "chronic" applied to the +tuberculous abscess. + +In a cold abscess, such as that which results from tuberculous disease +of the vertebrae, the clinical appearances are those of a soft, fluid +swelling without heat, redness, pain, or fever. When toxic symptoms are +present, they are usually due to a mixed infection. + +A tuberculous abscess results from the disintegration and liquefaction +of tuberculous granulation tissue which has undergone caseation. Fluid +and cells from the adjacent blood vessels exude into the cavity, and +lead to variations in the character of its contents. In some cases the +contents consist of a clear amber-coloured fluid, in which are suspended +fragments of caseated tissue; in others, of a white material like +cream-cheese. From the addition of a sufficient number of leucocytes, +the contents may resemble the pus of an ordinary abscess. + +The wall of the abscess is lined with tuberculous granulation tissue, +the inner layers of which are undergoing caseation and disintegration, +and present a shreddy appearance; the outer layers consist of +tuberculous tissue which has not yet undergone caseation. The abscess +tends to increase in size by progressive liquefaction of the inner +layers, caseation of the outer layers, and the further invasion of the +surrounding tissues by tubercle bacilli. In this way a tuberculous +abscess is capable of indefinite extension and increase in size until it +reaches a free surface and ruptures externally. The direction in which +it spreads is influenced by the anatomical arrangement of the tissues, +and possibly to some extent by gravity, and the abscess may reach the +surface at a considerable distance from its seat of origin. The best +illustration of this is seen in the psoas abscess, which may originate +in the dorsal vertebrae, extend downwards within the sheath of the psoas +muscle, and finally appear in the thigh. + +#Clinical Features.#--The insidious development of the tuberculous +abscess is one of its characteristic features. The swelling may attain a +considerable size without the patient being aware of its existence, and, +as a matter of fact, it is often discovered accidentally. The absence of +toxaemia is to be associated with the incapacity of the wall of the +abscess to permit of absorption; this is shown also by the fact that +when even a large quantity of iodoform is inserted into the cavity of +the abscess, there are no symptoms of poisoning. The abscess varies in +size from a small cherry to a cavity containing several pints of pus. +Its shape also varies; it is usually that of a flattened sphere, but it +may present pockets or burrows running in various directions. Sometimes +it is hour-glass or dumb-bell shaped, as is well illustrated in the +region of the groin in disease of the spine or pelvis, where there may +be a large sac occupying the venter ilii, and a smaller one in the +thigh, the two communicating by a narrow channel under Poupart's +ligament. By pressing with the fingers the pus may be displaced from one +compartment to the other. The usual course of events is that the abscess +progresses slowly, and finally reaches a free surface--generally the +skin. As it does so there may be some pain, redness, and local elevation +of temperature. Fluctuation becomes evident and superficial, and the +skin becomes livid and finally gives way. If the case is left to nature, +the discharge of pus continues, and the track opening on the skin +remains as a _sinus_. The persistence of suppuration is due to the +presence in the wall of the abscess and of the sinus, of tuberculous +granulation tissue, which, so long as it remains, continues to furnish +discharge, and so prevents healing. Sooner or later pyogenic organisms +gain access to the sinus, and through it to the wall of the abscess. +They tend further to depress the resisting power of the tissues, and +thereby aggravate and perpetuate the tuberculous disease. This +superadded infection with pyogenic organisms exposes the patient to the +further risks of septic intoxication, especially in the form of hectic +fever and septicaemia, and increases the liability to general +tuberculosis, and to waxy degeneration of the internal organs. The mixed +infection is chiefly responsible for the pyrexia, sweating, and +emaciation which the laity associate with consumptive disease. A +tuberculous abscess may in one or other of these ways be a cause of +death. + +_Residual abscess_ is the name given to an abscess that makes its +appearance months, or even years, after the apparent cure of tuberculous +disease--as, for example, in the hip-joint or spine. It is called +residual because it has its origin in the remains of the original +disease. + +[Illustration: FIG. 34.--Tuberculous Abscess in right lumbar region in a +woman aged thirty.] + +#Diagnosis.#--A cold abscess is to be diagnosed from a syphilitic gumma, +a cyst, and from lipoma and other soft tumours. The differential +diagnosis of these affections will be considered later; it is often made +easier by recognising the presence of a lesion that is likely to cause a +cold abscess, such as tuberculous disease of the spine or of the +sacro-iliac joint. When it is about to burst externally, it may be +difficult to distinguish a tuberculous abscess from one due to infection +with pyogenic organisms. Even when the abscess is opened, the +appearances of the pus may not supply the desired information, and it +may be necessary to submit it to bacteriological examination. When the +pus is found to be sterile, it is usually safe to assume that the +condition is tuberculous, as in other forms of suppuration the causative +organisms can usually be recognised. Experimental inoculation will +establish a definite diagnosis, but it implies a delay of two to three +weeks. + +#Treatment.#--The tuberculous abscess may recede and disappear under +general treatment. Many surgeons advise that so long as the abscess is +quiescent it should be left alone. All agree, however, that if it shows +a tendency to spread, to increase in size, or to approach the skin or a +mucous membrane, something should be done to avoid the danger of its +bursting and becoming infected with pyogenic organisms. Simple +evacuation of the abscess by a hollow needle may suffice, or bismuth or +iodoform may be introduced after withdrawal of the contents. + +_Evacuation of the Abscess and Injection of Iodoform._--The iodoform is +employed in the form of a 10 per cent. solution in ether or the same +proportion suspended in glycerin. Either form becomes sterile soon after +it is prepared. Its curative effects would appear to depend upon the +liberation of iodine, which restrains the activity of the bacilli, and +upon its capacity for irritating the tissues and so inducing a +protective leucocytosis, and also of stimulating the formation of scar +tissue. An anaesthetic is rarely called for, except in children. The +abscess is first evacuated by means of a large trocar and cannula +introduced obliquely through the overlying soft parts, avoiding any part +where the skin is thin or red. If the cannula becomes blocked with +caseous material, it may be cleared with a probe, or a small quantity of +saline solution is forced in by the syringe. The iodoform is injected by +means of a glass-barrelled syringe, which is firmly screwed on to the +cannula. The amount injected varies with the size of the abscess and the +age of the patient; it may be said to range from two or three drams in +the case of children to several ounces in large abscesses in adults. The +cannula is withdrawn, the puncture is closed by a Michel's clip, and a +dressing applied so as to exert a certain amount of compression. If the +abscess fills up again, the procedure should be repeated; in doing so, +the contents show the coloration due to liberated iodine. When the +contents are semi-solid, and cannot be withdrawn even through a large +cannula, an incision must be made, and, after the cavity has been +emptied, the iodoform is introduced through a short rubber tube attached +to the syringe. Experience has shown that even large abscesses, such as +those associated with spinal disease, may be cured by iodoform +injection, and this even when rupture of the abscess on the skin surface +has appeared to be imminent. + +Another method of treatment which is less popular now than it used to +be, and which is chiefly applicable in abscesses of moderate size, is by +_incision of the abscess and removal of the tuberculous tissue in its +wall_ with the sharp spoon. An incision is made which will give free +access to the interior of the abscess, so that outlying pockets or +recesses may not be overlooked. After removal of the pus, the wall of +the abscess is scraped with the Volkmann spoon or with Barker's flushing +spoon, to get rid of the tuberculous tissue with which it is lined. In +using the spoon, care must be taken that its sharp edge does not +perforate the wall of a vein or other important structure. Any debris +which may adhere to the walls is removed by rubbing with dry gauze. The +oozing of blood is arrested by packing the cavity for a few minutes with +gauze. After the packing is removed, iodoform powder is rubbed into the +raw surface. The soft parts divided by the incision are sutured in +layers so as to ensure primary union. If, on the other hand, there is +fear of a mixed infection, especially in abscesses near the rectum or +anus, it is safer to treat it by the open method, packing the cavity +with iodoform worsted or bismuth gauze, which is renewed at intervals of +a week or ten days as the cavity heals from the bottom. + +Another method is to incise the abscess, cleanse the cavity with gauze, +irrigate with Carrel-Dakin solution and pack with gauze smeared with the +dilute non-toxic B.I.P.P. (bismuth and iodoform 2 parts, vaseline 12 +parts, hard paraffin, sufficient to give the consistence of butter). The +wound is closed with "bipped" silk sutures; one of these--the "waiting +suture"--is left loose to permit of withdrawal of the gauze after +forty-eight hours; the waiting suture is then tied, and delayed primary +union is thus effected. + +When the skin over the abscess is red, thin, and about to give way, as +is frequently the case when the abscess is situated in the subcutaneous +cellular tissue, any skin which is undermined and infected with tubercle +should be removed with the scissors at the same time that the abscess is +dealt with. + +In abscesses treated by the open method, when the cavity has become +lined with healthy granulations, it may be closed by secondary suture, +or, if the granulating surface is flush with the skin, healing may be +hastened by skin-grafting. + +If the tuberculous abscess has burst and left a _sinus_, this is apt to +persist because of the presence of tuberculous tissue in its wall, and +of superadded pyogenic infection, or because it serves as an avenue for +the escape of discharge from a focus of tubercle in a bone or a lymph +gland. + +[Illustration: FIG. 35.--Tuberculous Sinus injected through its opening +in the forearm with bismuth paste. + +(Mr. Pirie Watson's case--Radiogram by Dr. Hope Fowler.)] + +The treatment varies with the conditions present, and must include +measures directed to the lesion from which the sinus has originated. The +extent and direction of any given sinus may be demonstrated by the use +of the probe, or, more accurately, by injecting the sinus with a paste +consisting of white vaseline containing 10 to 30 per cent. of bismuth +subcarbonate, and following its track with the X-rays (Fig. 35). + +It was found by Beck of Chicago that the injection of bismuth paste is +frequently followed by healing of the sinus, and that, if one injection +fails to bring about a cure, repeating the injection every second day +may be successful. Some caution must be observed in this treatment, as +symptoms of poisoning have been observed to follow its use. If they +manifest themselves, an injection of warm olive oil should be given; the +oil, left in for twelve hours or so, forms an emulsion with the bismuth, +which can be withdrawn by aspiration. Iodoform suspended in glycerin may +be employed in a similar manner. When these and other non-operative +measures fail, and the whole track of the sinus is accessible, it should +be laid open, scraped, and packed with bismuth or iodoform gauze until +it heals from the bottom. + +The _tuberculous ulcer_ is described in the chapter on ulcers. + + + + +CHAPTER IX + +SYPHILIS + + +Definition.--Virus.--ACQUIRED SYPHILIS--Primary period: + _Incubation, primary chancre, glandular enlargement_; + _Extra-genital chancres_--Treatment--Secondary period: _General + symptoms, skin affections, mucous patches, affections of bones, + joints, eyes_, etc.--Treatment: _Salvarsan_--_Methods of + administering mercury_--Syphilis and marriage--Intermediate + stage--_Reminders_--Tertiary period: _General symptoms_, + _gummata_, _tertiary ulcers_, _tertiary lesions of skin, mucous + membrane, bones, joints_, etc.--Second attacks.--INHERITED + SYPHILIS--Transmission--_Clinical features in infancy, in later + life_--Contagiousness--Treatment. + +Syphilis is an infective disease due to the entrance into the body of a +specific virus. It is nearly always communicated from one individual to +another by contact infection, the discharge from a syphilitic lesion +being the medium through which the virus is transmitted, and the seat of +inoculation is almost invariably a surface covered by squamous +epithelium. The disease was unknown in Europe before the year 1493, when +it was introduced into Spain by Columbus' crew, who were infected in +Haiti, where the disease had been endemic from time immemorial (Bloch). + +The granulation tissue which forms as a result of the reaction of the +tissues to the presence of the virus is chiefly composed of lymphocytes +and plasma cells, along with an abundant new formation of capillary +blood vessels. Giant cells are not uncommon, but the endothelioid cells, +which are so marked a feature of tuberculous granulation tissue, are +practically absent. + +When syphilis is communicated from one individual to another by contact +infection, the condition is spoken of as _acquired syphilis_, and the +first visible sign of the disease appears at the site of inoculation, +and is known as _the primary lesion_. Those who have thus acquired the +disease may transmit it to their offspring, who are then said to suffer +from _inherited syphilis_. + +#The Virus of Syphilis.#--The cause of syphilis, whether acquired or +inherited, is the organism, described by Schaudinn and Hoffman, in 1905, +under the name of _spirochaeta pallida_ or _spironema pallidum_. It is a +delicate, thread-like spirilla, in length averaging from 8 to 10 u and +in width about 0.25 u, and is distinguished from other spirochaetes by +its delicate shape, its dead-white appearance, together with its closely +twisted spiral form, with numerous undulations (10 to 26), which are +perfectly regular, and are characteristic in that they remain the same +during rest and in active movement (Fig. 36). In a fresh specimen, such +as a scraping from a hard chancre suspended in a little salt solution, +it shows active movements. The organism is readily destroyed by heat, +and perishes in the absence of moisture. It has been proved +experimentally that it remains infective only up to six hours after its +removal from the body. Noguchi has succeeded in obtaining pure cultures +from the infected tissues of the rabbit. + +[Illustration: FIG. 36.--Spirochaeta pallida from scraping of hard +Chancre of Prepuce. x 1000 diam. Burri method.] + +The spirochaete may be recognised in films made by scraping the deeper +parts of the primary lesion, from papules on the skin, or from blisters +artificially raised on lesions of the skin or on the immediately +adjacent portion of healthy skin. It is readily found in the mucous +patches and condylomata of the secondary period. It is best stained by +Giemsa's method, and its recognition is greatly aided by the use of the +ultra-microscope. + +The spirochaete has been demonstrated in every form of syphilitic lesion, +and has been isolated from the blood--with difficulty--and from lymph +withdrawn by a hollow needle from enlarged lymph glands. The saliva of +persons suffering from syphilitic lesions of the mouth also contains the +organism. + +[Illustration: FIG. 37.--Spirochaeta refrigerans from scraping of Vagina. +x 1000 diam. Burri method.] + +In tertiary lesions there is greater difficulty in demonstrating the +spirochaete, but small numbers have been found in the peripheral parts of +gummata and in the thickened patches in syphilitic disease of the aorta. +Noguchi and Moore have discovered the spirochaete in the brain in a +number of cases of general paralysis of the insane. The spirochaete may +persist in the body for a long time after infection; its presence has +been demonstrated as long as sixteen years after the original +acquisition of the disease. + +In inherited syphilis the spirochaete is present in enormous numbers +throughout all the organs and fluids of the body. + +Considerable interest attaches to the observations of Metchnikoff, Roux, +and Neisser, who have succeeded in conveying syphilis to the chimpanzee +and other members of the ape tribe, obtaining primary and secondary +lesions similar to those observed in man, and also containing the +spirochaete. In animals the disease has been transmitted by material from +all kinds of syphilitic lesions, including even the blood in the +secondary and tertiary stages of the disease. The primary lesion is in +the form of an indurated papule, in every respect resembling the +corresponding lesion in man, and associated with enlargement and +induration of the lymph glands. The primary lesion usually appears about +thirty days after inoculation, to be followed, in about half the cases, +by secondary manifestations, which are usually of a mild character; in +no instance has any tertiary lesion been observed. The severity of the +affection amongst apes would appear to be in proportion to the nearness +of the relationship of the animal to the human subject. The eye of the +rabbit is also susceptible to inoculation from syphilitic lesions; the +material in a finely divided state is introduced into the anterior +chamber of the eye. + +Attempts to immunise against the disease have so far proved negative, +but Metchnikoff has shown that the inunction of the part inoculated with +an ointment containing 33 per cent. of calomel, within one hour of +infection, suffices to neutralise the virus in man, and up to eighteen +hours in monkeys. He recommends the adoption of this procedure in the +prophylaxis of syphilis. + +Noguchi has made an emulsion of dead spirochaetes which he calls +_luetin_, and which gives a specific reaction resembling that of +tuberculin in tuberculosis, a papule or a pustule forming at the site of +the intra-dermal injection. It is said to be most efficacious in the +tertiary and latent forms of syphilis, which are precisely those forms +in which the diagnosis is surrounded with difficulties. + + +ACQUIRED SYPHILIS + +In the vast majority of cases, infection takes place during the congress +of the sexes. Delicate, easily abraded surfaces are then brought into +contact, and the discharge from lesions containing the virus is placed +under favourable conditions for conveying the disease from one person to +the other. In the male the possibility of infection taking place is +increased if the virus is retained under cover of a long and tight +prepuce, and if there are abrasions on the surface with which it comes +in contact. The frequency with which infection takes place on the +genitals during sexual intercourse warrants syphilis being considered a +venereal disease, although there are other ways in which it may be +contracted. + +Some of these imply direct contact--such, for example, as kissing, the +digital examination of syphilitic patients by doctors or nurses, or +infection of the surgeon's fingers while operating upon a syphilitic +patient. In suckling, a syphilitic wet nurse may infect a healthy +infant, or a syphilitic infant may infect a healthy wet nurse. In other +cases the infection is by indirect contact, the virus being conveyed +through the medium of articles contaminated by a syphilitic +patient--such, for example, as surgical instruments, tobacco pipes, wind +instruments, table utensils, towels, or underclothing. Physiological +secretions, such as saliva, milk, or tears, are not capable of +communicating the disease unless contaminated by discharge from a +syphilitic sore. While the saliva itself is innocuous, it can be, and +often is, contaminated by the discharge from mucous patches or other +syphilitic lesions in the mouth and throat, and is then a dangerous +medium of infection. Unless these extra-genital sources of infection are +borne in mind, there is a danger of failing to recognise the primary +lesion of syphilis in unusual positions, such as the lip, finger, or +nipple. When the disease is thus acquired by innocent transfer, it is +known as _syphilis insontium_. + +#Stages or Periods of Syphilis.#--Following the teaching of Ricord, it +is customary to divide the life-history of syphilis into three periods +or stages, referred to, for convenience, as primary, secondary, and +tertiary. This division is to some extent arbitrary and artificial, as +the different stages overlap one another, and the lesions of one stage +merge insensibly into those of another. Wide variations are met with in +the manifestations of the secondary stage, and histologically there is +no valid distinction to be drawn between secondary and tertiary lesions. + +_The primary period_ embraces the interval that elapses between the +initial infection and the first constitutional manifestations,--roughly, +from four to eight weeks,--and includes the period of incubation, the +development of the primary sore, and the enlargement of the nearest +lymph glands. + +_The secondary period_ varies in duration from one to two years, during +which time the patient is liable to suffer from manifestations which are +for the most part superficial in character, affecting the skin and its +appendages, the mucous membranes, and the lymph glands. + +_The tertiary period_ has no time-limit except that it follows upon the +secondary, so that during the remainder of his life the patient is +liable to suffer from manifestations which may affect the deeper tissues +and internal organs as well as the skin and mucous membranes. + +#Primary Syphilis.#--_The period of incubation_ represents the interval +that elapses between the occurrence of infection and the appearance of +the primary lesion at the site of inoculation. Its limits may be stated +as varying from two to six weeks, with an average of from twenty-one to +twenty-eight days. While the disease is incubating, there is nothing to +show that infection has occurred. + +_The Primary Lesion._--The incubation period having elapsed, there +appears at the site of inoculation a circumscribed area of infiltration +which represents the reaction of the tissues to the entrance of the +virus. The first appearance is that of a sharply defined papule, rarely +larger than a split pea. Its surface is at first smooth and shiny, but +as necrosis of the tissue elements takes place in the centre, it becomes +concave, and in many cases the epithelium is shed, and an ulcer is +formed. Such an ulcer has an elevated border, sharply cut edges, an +indurated base, and exudes a scanty serous discharge; its surface is at +first occupied by yellow necrosed tissue, but in time this is replaced +by smooth, pale-pink granulation tissue; finally, epithelium may spread +over the surface, and the ulcer heals. As a rule, the patient suffers +little discomfort, and may even be ignorant of the existence of the +lesion, unless, as a result of exposure to mechanical or septic +irritation, ulceration ensues, and the sore becomes painful and tender, +and yields a purulent discharge. The primary lesion may persist until +the secondary manifestations make their appearance, that is, for several +weeks. + +It cannot be emphasised too strongly that the induration of the primary +lesion, which has obtained for it the name of "hard chancre," is its +most important characteristic. It is best appreciated when the sore is +grasped from side to side between the finger and thumb. The sensation on +grasping it has been aptly compared to that imparted by a nodule of +cartilage, or by a button felt through a layer of cloth. The evidence +obtained by touch is more valuable than that obtained by inspection, a +fact which is made use of in the recognition of _concealed +chancres_--that is, those which are hidden by a tight prepuce. The +induration is due not only to the dense packing of the connective-tissue +spaces with lymphocytes and plasma cells, but also to the formation of +new connective-tissue elements. It is most marked in chancres situated +in the furrow between the glans and the prepuce. + +_In the male_, the primary lesion specially affects certain +_situations_, and the appearances vary with these: (1) On the inner +aspect of the prepuce, and in the fold between the prepuce and the +glans; in the latter situation the induration imparts a "collar-like" +rigidity to the prepuce, which is most apparent when it is rolled back +over the corona. (2) At the orifice of the prepuce the primary lesion +assumes the form of multiple linear ulcers or fissures, and as each of +these is attended with infiltration, the prepuce cannot be pulled +back--a condition known as _syphilitic phimosis_. (3) On the glans penis +the infiltration may be so superficial that it resembles a layer of +parchment, but if it invades the cavernous tissue there is a dense mass +of induration. (4) On the external aspect of the prepuce or on the skin +of the penis itself. (5) At either end of the torn fraenum, in the form +of a diamond-shaped ulcer raised above the surroundings. (6) In relation +to the meatus and canal of the urethra, in either of which situations +the swelling and induration may lead to narrowing of the urethra, so +that the urine is passed with pain and difficulty and in a minute +stream; stricture results only in the exceptional cases in which the +chancre has ulcerated and caused destruction of tissue. A chancre within +the orifice of the urethra is rare, and, being concealed from view, it +can only be recognised by the discharge from the meatus and by the +induration felt between the finger and thumb on palpating the urethra. + +_In the female_, the primary lesion is not so typical or so easily +recognised as in men; it is usually met with on the labia; the +induration is rarely characteristic and does not last so long. The +primary lesion may take the form of condylomata. Indurated oedema, with +brownish-red or livid discoloration of one or both labia, is diagnostic +of syphilis. + +The hard chancre is usually solitary, but sometimes there are two or +more; when there are several, they are individually smaller than the +solitary chancre. + +It is the exception for a hard chancre to leave a visible scar, hence, +in examining patients with a doubtful history of syphilis, little +reliance can be placed on the presence or absence of a scar on the +genitals. When the primary lesion has taken the form of an open ulcer +with purulent discharge, or has sloughed, there is a permanent scar. + +_Infection of the adjacent lymph glands_ is usually found to have taken +place by the time the primary lesion has acquired its characteristic +induration. Several of the glands along Poupart's ligament, on one or on +both sides, become enlarged, rounded, and indurated; they are usually +freely movable, and are rarely sensitive unless there is superadded +septic infection. The term _bullet-bubo_ has been applied to them, and +their presence is of great value in diagnosis. In a certain number of +cases, one of the main _lymph vessels_ on the dorsum of the penis is +transformed into a fibrous cord easily recognisable on palpation, and +when grasped between the fingers appears to be in size and consistence +not unlike the vas deferens. + +_Concealed chancre_ is the term applied when one or more chancres are +situated within the sac of a prepuce which cannot be retracted. If the +induration is well marked, the chancre can be palpated through the +prepuce, and is tender on pressure. As under these conditions it is +impossible for the patient to keep the parts clean, septic infection +becomes a prominent feature, the prepuce is oedematous and inflamed, and +there is an abundant discharge of pus from its orifice. It occasionally +happens that the infection assumes a virulent character and causes +sloughing of the prepuce--a condition known as _phagedaena_. The +discharge is then foul and blood-stained, and the prepuce becomes of a +dusky red or purple colour, and may finally slough, exposing the glans. + +_Extra-genital or Erratic Chancres_ (Fig. 38).--Erratic chancre is the +term applied by Jonathan Hutchinson to the primary lesion of syphilis +when it appears on parts of the body other than the genitals. It differs +in some respects from the hard chancre as met with on the penis; it is +usually larger, the induration is more diffused, and the enlarged glands +are softer and more sensitive. The glands in nearest relation to the +sore are those first affected, for example, the epitrochlear or axillary +glands in chancre of the finger; the submaxillary glands in chancre of +the lip or mouth; or the pre-auricular gland in chancre of the eyelid or +forehead. In consequence of their divergence from the typical chancre, +and of their being often met with in persons who, from age, +surroundings, or moral character, are unlikely subjects of venereal +disease, the true nature of erratic chancres is often overlooked until +the persistence of the lesion, its want of resemblance to anything else, +or the onset of constitutional symptoms, determines the diagnosis of +syphilis. A solitary, indolent sore occurring on the lip, eyelid, +finger, or nipple, which does not heal but tends to increase in size, +and is associated with induration and enlargement of the adjacent +glands, is most likely to be the primary lesion of syphilis. + +[Illustration: FIG. 38.--Primary Lesion on Thumb, with Secondary +Eruption on Forearm.[1]] + +[1] From _A System of Syphilis_, vol. ii., edited by D'Arcy Power and +J. Keogh Murphy, Oxford Medical Publications. + +#The Soft Sore, Soft Chancre, or Chancroid.#--The differential diagnosis +of syphilis necessitates the consideration of the _soft sore_, _soft +chancre_, or _chancroid_, which is also a common form of venereal +disease, and is due to infection with a virulent pus-forming bacillus, +first described by Ducrey in 1889. Ducrey's bacillus occurs in the form +of minute oval rods measuring about 1.5 u in length, which stain readily +with any basic aniline dye, but are quickly decolorised by Gram's +method. They are found mixed with other organisms in the purulent +discharge from the sore, and are chiefly arranged in small groups or in +short chains. Soft sores are always contracted by direct contact from +another individual, and the incubation period is a short one of from two +to five days. They are usually situated in the vicinity of the fraenum, +and, in women, about the labia minora or fourchette; they probably +originate in abrasions in these situations. They appear as pustules, +which are rapidly converted into small, acutely inflamed ulcers with +sharply cut, irregular margins, which bleed easily and yield an abundant +yellow purulent discharge. They are devoid of the induration of +syphilis, are painful, and nearly always multiple, reproducing +themselves in successive crops by auto-inoculation. Soft sores are often +complicated by phimosis and balanitis, and they frequently lead to +infection of the glands in the groin. The resulting bubo is ill-defined, +painful, and tender, and suppuration occurs in about one-fourth of the +cases. The overlying skin becomes adherent and red, and suppuration +takes place either in the form of separate foci in the interior of the +individual glands, or around them; in the latter case, on incision, the +glands are found lying bathed in pus. Ducrey's bacillus is found in pure +culture in the pus. Sometimes other pyogenic organisms are superadded. +After the bubo has been opened the wound may take on the characters of a +soft sore. + +_Treatment._--Soft sores heal rapidly when kept clean. If concealed +under a tight prepuce, an incision should be made along the dorsum to +give access to the sores. They should be washed with eusol, and dusted +with a mixture of one part iodoform and two parts boracic or salicylic +acid, or, when the odour of iodoform is objected to, of equal parts of +boracic acid and carbonate of zinc. Immersion of the penis in a bath of +eusol for some hours daily is useful. The sore is then covered with a +piece of gauze kept in position by drawing the prepuce over it, or by a +few turns of a narrow bandage. Sublimed sulphur frequently rubbed into +the sore is recommended by C. H. Mills. If the sores spread in spite of +this, they should be painted with cocaine and then cauterised. When the +glands in the groin are infected, the patient must be confined to bed, +and a dressing impregnated with ichthyol and glycerin (10 per cent.) +applied; the repeated use of a suction bell is of great service. +Harrison recommends aspiration of a bubonic abscess, followed by +injection of 1 in 20 solution of tincture of iodine into the cavity; +this is in turn aspirated, and then 1 or 2 c.c. of the solution injected +and left in. This is repeated as often as the cavity refills. It is +sometimes necessary to let the pus out by one or more small incisions +and continue the use of the suction bell. + +_Diagnosis of Primary Syphilis._--In cases in which there is a history +of an incubation period of from three to five weeks, when the sore is +indurated, persistent, and indolent, and attended with bullet-buboes in +the groin, the diagnosis of primary syphilis is not difficult. Owing, +however, to the great importance of instituting treatment at the +earliest possible stage of the infection, an effort should be made to +establish the diagnosis without delay by demonstrating the spirochaete. +Before any antiseptic is applied, the margin of the suspected sore is +rubbed with gauze, and the serum that exudes on pressure is collected +in a capillary tube and sent to a pathologist for microscopical +examination. A better specimen can sometimes be obtained by puncturing +an enlarged lymph gland with a hypodermic needle, injecting a few minims +of sterile saline solution and then aspirating the blood-stained fluid. + +The Wassermann test must not be relied upon for diagnosis in the early +stage, as it does not appear until the disease has become generalised +and the secondary manifestations are about to begin. The practice of +waiting in doubtful cases before making a diagnosis until secondary +manifestations appear is to be condemned. + +Extra-genital chancres, _e.g._ sores on the fingers of doctors or +nurses, are specially liable to be overlooked, if the possibility of +syphilis is not kept in mind. + +It is important to bear in mind _the possibility of a patient having +acquired a mixed infection_ with the virus of soft chancre, which will +manifest itself a few days after infection, and the virus of syphilis, +which shows itself after an interval of several weeks. This occurrence +was formerly the source of much confusion in diagnosis, and it was +believed at one time that syphilis might result from soft sores, but it +is now established that syphilis does not follow upon soft sores unless +the virus of syphilis has been introduced at the same time. The +practitioner must be on his guard, therefore, when a patient asks his +advice concerning a venereal sore which has appeared within a few days +of exposure to infection. Such a patient is naturally anxious to know +whether he has contracted syphilis or not, but neither a positive nor a +negative answer can be given--unless the spirochaete can be identified. + +Syphilis is also to be diagnosed from _epithelioma_, the common form of +cancer of the penis. It is especially in elderly patients with a tight +prepuce that the induration of syphilis is liable to be mistaken for +that associated with epithelioma. In difficult cases the prepuce must be +slit open. + +Difficulty may occur in the diagnosis of primary syphilis from _herpes_, +as this may appear as late as ten days after connection; it commences as +a group of vesicles which soon burst and leave shallow ulcers with a +yellow floor; these disappear quickly on the use of an antiseptic +dusting powder. + +Apprehensive patients who have committed sexual indiscretions are apt to +regard as syphilitic any lesion which happens to be located on the +penis--for example, acne pustules, eczema, psoriasis papules, boils, +balanitis, or venereal warts. + +_The local treatment_ of the primary sore consists in attempting to +destroy the organisms _in situ_. An ointment made up of calomel 33 +parts, lanoline 67 parts, and vaseline 10 parts (Metchnikoff's cream) is +rubbed into the sore several times a day. If the surface is unbroken, it +may be dusted lightly with a powder composed of equal parts of calomel +and carbonate of zinc. A gauze dressing is applied, and the penis and +scrotum should be supported against the abdominal wall by a triangular +handkerchief or bathing-drawers; if there is inflammatory oedema the +patient should be confined to bed. + +In _concealed chancres_ with phimosis, the sac of the prepuce should be +slit up along the dorsum to admit of the ointment being applied. If +phagedaena occurs, the prepuce must be slit open along the dorsum, or if +sloughing, cut away, and the patient should have frequent sitz baths of +weak sublimate lotion. When the chancre is within the meatus, iodoform +bougies are inserted into the urethra, and the urine should be rendered +bland by drinking large quantities of fluid. + +General treatment is considered on p. 149. + +#Secondary Syphilis.#--The following description of secondary syphilis +is based on the average course of the disease in untreated cases. The +onset of constitutional symptoms occurs from six to twelve weeks after +infection, and the manifestations are the result of the entrance of the +virus into the general circulation, and its being carried to all parts +of the body. The period during which the patient is liable to suffer +from secondary symptoms ranges from six months to two years. + +In some cases the general health is not disturbed; in others the patient +is feverish and out of sorts, losing appetite, becoming pale and anaemic, +complaining of lassitude, incapacity for exertion, headache, and pains +of a rheumatic type referred to the bones. There is a moderate degree of +leucocytosis, but the increase is due not to the polymorpho-nuclear +leucocytes but to lymphocytes. In isolated cases the temperature rises +to 101 o or 102 o F. and the patient loses flesh. The lymph glands, +particularly those along the posterior border of the sterno-mastoid, +become enlarged and slightly tender. The hair comes out, eruptions +appear on the skin and mucous membranes, and the patient may suffer from +sore throat and affections of the eyes. The local lesions are to be +regarded as being of the nature of reactions against accumulations of +the parasite, lymphocytes and plasma cells being the elements chiefly +concerned in the reactive process. + +_Affections of the Skin_ are among the most constant manifestations. An +evanescent macular rash, not unlike that of measles--_roseola_--is the +first to appear, usually in from six to eight weeks from the date of +infection; it is widely diffused over the trunk, and the original dull +rose-colour soon fades, leaving brownish stains, which in time +disappear. It is usually followed by a _papular eruption_, the +individual papules being raised above the surface of the skin, smooth or +scaly, and as they are due to infiltration of the skin they are more +persistent than the roseoles. They vary in size and distribution, being +sometimes small, hard, polished, and closely aggregated like lichen, +sometimes as large as a shilling-piece, with an accumulation of scales +on the surface like that seen in psoriasis. The co-existence of scaly +papules and faded roseoles is very suggestive of syphilis. + +Other types of eruption are less common, and are met with from the third +month onwards. A _pustular_ eruption, not unlike that of acne, is +sometimes a prominent feature, but is not characteristic of syphilis +unless it affects the scalp and forehead and is associated with the +remains of the papular eruption. The term _ecthyma_ is applied when the +pustules are of large size, and, after breaking on the surface, give +rise to superficial ulcers; the discharge from the ulcer often dries up +and forms a scab or crust which is continually added to from below as +the ulcer extends in area and depth. The term _rupia_ is applied when +the crusts are prominent, dark in colour, and conical in shape, roughly +resembling the shell of a limpet. If the crust is detached, a sharply +defined ulcer is exposed, and when this heals it leaves a scar which is +usually circular, thin, white, shining like satin, and the surrounding +skin is darkly pigmented; in the case of deep ulcers, the scar is +depressed and adherent (Fig. 39). + +[Illustration: FIG. 39.--Syphilitic Rupia, showing the limpet-shaped +crusts or scabs.] + +In the later stages there may occur a form of creeping or _spreading +ulceration of the skin_ of the face, groin, or scrotum, healing at one +edge and spreading at another like tuberculous lupus, but distinguished +from this by its more rapid progress and by the pigmentation of the +scar. + +_Condylomata_ are more characteristic of syphilis than any other type of +skin lesion. They are papules occurring on those parts of the body where +the skin is habitually moist, and especially where two skin surfaces are +in contact. They are chiefly met with on the external genitals, +especially in women, around the anus, beneath large pendulous mammae, +between the toes, and at the angles of the mouth, and in these +situations their development is greatly favoured by neglect of +cleanliness. They present the appearance of well-defined circular or +ovoid areas in which the skin is thickened and raised above the surface; +they are covered with a white sodden epidermis, and furnish a scanty but +very infective discharge. Under the influence of irritation and want of +rest, as at the anus or at the angle of the mouth, they are apt to +become fissured and superficially ulcerated, and the discharge then +becomes abundant and may crust on the surface, forming yellow scabs. At +the angle of the mouth the condylomatous patches may spread to the +cheek, and when they ulcerate may leave fissure-like scars radiating +from the mouth--an appearance best seen in inherited syphilis (Fig. 44). + +_The Appendages of the Skin._--The _hair_ loses its gloss, becomes dry +and brittle, and readily falls out, either as an exaggeration of the +normal shedding of the hair, or in scattered areas over the scalp +(_syphilitic alopoecia_). The hair is not re-formed in the scars which +result from ulcerated lesions of the scalp. The _nail-folds_ +occasionally present a pustular eruption and superficial ulceration, to +which the name _syphilitic onychia_ has been applied; more commonly the +nails become brittle and ragged, and they may even be shed. + +_The Mucous Membranes_, and especially those of the _mouth_ and +_throat_, suffer from lesions similar to those met with on the skin. On +a mucous surface the papular eruption assumes the form of _mucous +patches_, which are areas with a congested base covered with a thin +white film of sodden epithelium like wet tissue-paper. They are best +seen on the inner aspect of the cheeks, the soft palate, uvula, pillars +of the fauces, and tonsils. In addition to mucous patches, there may be +a number of small, _superficial, kidney-shaped ulcers_, especially along +the margins of the tongue and on the tonsils. In the absence of mucous +patches and ulcers, the sore throat may be characterised by a bluish +tinge of the inflamed mucous membrane and a thin film of shed epithelium +on the surface. Sometimes there is an elongated sinuous film which has +been likened to the track of a snail. In the _larynx_ the presence of +congestion, oedema, and mucous patches may be the cause of persistent +hoarseness. The _tongue_ often presents a combination of lesions, +including ulcers, patches where the papillae are absent, fissures, and +raised white papules resembling warts, especially towards the centre of +the dorsum. These lesions are specially apt to occur in those who smoke, +drink undiluted alcohol or spirits, or eat hot condiments to excess, or +who have irregular, sharp-cornered teeth. At a later period, and in +those who are broken down in health from intemperance or other cause, +the sore throat may take the form of rapidly spreading, penetrating +ulcers in the soft palate and pillars of the fauces, which may lead to +extensive destruction of tissue, with subsequent scars and deformity +highly characteristic of previous syphilis. + +In the _Bones_, lesions occur which assume the clinical features of an +evanescent periostitis, the patient complaining of nocturnal pains over +the frontal bone, sternum, tibiae, and ulnae, and localised tenderness on +tapping over these bones. + +In the _Joints_, a serous synovitis or hydrops may occur, chiefly in the +knee, on one or on both sides. + +_The Affections of the Eyes_, although fortunately rare, are of great +importance because of the serious results which may follow if they are +not recognised and treated. _Iritis_ is the commonest of these, and may +occur in one or in both eyes, one after the other, from three to eight +months after infection. The patient complains of impairment of sight and +of frontal or supraorbital pain. The eye waters and is hypersensitive, +the iris is discoloured and reacts sluggishly to light, and there is a +zone of ciliary congestion around the cornea. The appearance of minute +white nodules or flakes of lymph at the margin of the pupil is +especially characteristic of syphilitic iritis. When adhesions have +formed between the iris and the structures in relation to it, the pupil +dilates irregularly under atropin. Although complete recovery is to be +expected under early and energetic treatment, if neglected, _iritis_ may +result in occlusion of the pupil and permanent impairment or loss of +sight. + +The other lesions of the eye are much rarer, and can only be discovered +on ophthalmoscopic examination. + +The virus of syphilis exerts a special influence upon the _Blood +Vessels_, exciting a proliferation of the endothelial lining which +results in narrowing of their lumen, _endarteritis_, and a perivascular +infiltration in the form of accumulations of plasma cells around the +vessels and in the lymphatics that accompany them. + +In the _Brain_, in the later periods of secondary and in tertiary +syphilis, changes occur as a result of the narrowing of the lumen of the +arteries, or of their complete obliteration by thrombosis. By +interfering with the nutrition of those parts of the brain supplied by +the affected arteries, these lesions give rise to clinical features of +which severe headache and paralysis are the most prominent. + +Affections of the _Spinal Cord_ are extremely rare, but paraplegia from +myelitis has been observed. + +Lastly, attention must be directed to the remarkable variations observed +in different patients. Sometimes the virulent character of the disease +can only be accounted for by an idiosyncrasy of the patient. +Constitutional symptoms, particularly pyrexia and anaemia, are most often +met with in young women. Patients over forty years of age have greater +difficulty in overcoming the infection than younger adults. Malarial and +other infections, and the conditions attending life in tropical +countries, from the debility which they cause, tend to aggravate and +prolong the disease, which then assumes the characters of what has been +called _malignant syphilis_. All chronic ailments have a similar +influence, and alcoholic intemperance is universally regarded as a +serious aggravating factor. + +_Diagnosis of Secondary Syphilis._--A routine examination should be made +of the parts of the body which are most often affected in this +disease--the scalp, mouth, throat, posterior cervical glands, and the +trunk, the patient being stripped and examined by daylight. Among the +_diagnostic features of the skin affections_ the following may be +mentioned: They are frequently, and sometimes to a marked degree, +symmetrical; more than one type of eruption--papules and pustules, for +example--are present at the same time; there is little itching; they are +at first a dull-red colour, but later present a brown pigmentation which +has been likened to the colour of raw ham; they exhibit a predilection +for those parts of the forehead and neck which are close to the roots of +the hair; they tend to pass off spontaneously; and they disappear +rapidly under treatment. + +#Serum Diagnosis--Wassermann Reaction.#--Wassermann found that if an +extract of syphilitic liver rich in spirochaetes is mixed with the serum +from a syphilitic patient, a large amount of complement is fixed. The +application of the test is highly complicated and can only be carried +out by an expert pathologist. For the purpose he is supplied with from 5 +c.c. to 10 c.c. of the patient's blood, withdrawn under aseptic +conditions from the median basilic vein by means of a serum syringe, and +transferred to a clean and dry glass tube. There is abundant evidence +that the Wassermann test is a reliable means of establishing a diagnosis +of syphilis. + +A definitely positive reaction can usually be obtained between the +fifteenth and thirtieth day after the appearance of the primary lesion, +and as time goes on it becomes more marked. During the secondary period +the reaction is practically always positive. In the tertiary stage also +it is positive except in so far as it is modified by the results of +treatment. In para-syphilitic lesions such as general paralysis and +tabes a positive reaction is almost always present. In inherited +syphilis the reaction is positive in every case. A positive reaction may +be present in other diseases, for example, frambesia, trypanosomiasis, +and leprosy. + +As the presence of the reaction is an evidence of the activity of the +spirochaetes, repeated applications of the test furnish a valuable means +of estimating the efficacy of treatment. The object aimed at is to +change a persistently positive reaction to a permanently negative one. + +#Treatment of Syphilis.#--In the treatment of syphilis the two main +objects are to maintain the general health at the highest possible +standard, and to introduce into the system therapeutic agents which will +inhibit or destroy the invading parasite. + +The second of these objects has been achieved by the researches of +Ehrlich, who, in conjunction with his pupil, Hata, has built up a +compound, the dihydrochloride of dioxydiamido-arseno-benzol, popularly +known as salvarsan or "606." Other preparations, such as kharsivan, +arseno-billon, and diarsenol, are chemically equivalent to salvarsan, +containing from 27 to 31 per cent. of arsenic, and are equally +efficient. The full dose is 0.6 grm. All these members of the "606" +group form an acid solution when dissolved in water, and must be +rendered alkaline before being injected. As subcutaneous and +intra-muscular injections cause considerable pain, and may cause +sloughing of the tissues, "606" preparations must be injected +intravenously. Ehrlich has devised a preparation--neo-salvarsan, or +"914," which is more easily prepared and forms a neutral solution. It +contains from 18 to 20 per cent. of arsenic. Neo-kharsivan, +novo-arseno-billon, and neo-diarsenol belong to the "914" group, the +full dosage of which is 0.9 grm. As subcutaneous and intra-muscular +injections of the "914" group are not painful, and even more efficient +than intravenous injections, the administration is simpler. + +Galyl, luargol, and other preparations act in the same way as the "606" +and "914" groups. + +The "606" preparations may be introduced into the veins by injection or +by means of an apparatus which allows the solution to flow in by +gravity. The left median basilic vein is selected, and a platino-iridium +needle with a short point and a bore larger than that of the ordinary +hypodermic syringe is used. The needle is passed for a few millimetres +along the vein, and the solution is then slowly introduced; before +withdrawing the needle some saline is run in to diminish the risk of +thrombosis. + +The "914" preparations may be injected either into the subcutaneous +tissue of the buttock or into the substance of the gluteus muscle. The +part is then massaged for a few minutes, and the massage is repeated +daily for a few days. + +No hard-and-fast rules can be laid down as to what constitutes a +complete course of treatment. Harrison recommends as a _minimum_ course +of one of the "914" preparations in _early primary cases_ an initial +dose of 0.45 grm. given intra-muscularly or into the deep subcutaneous +tissue; the same dose a week later; 0.6 grm. the following week; then +miss a week and give 9.6 grms. on two successive weeks; then miss two +weeks and give 0.6 grm. on two more successive weeks. + +When a _positive Wassermann reaction_ is present before treatment is +commenced, the above course is prolonged as follows: for three weeks is +given a course of potassium iodide, after which four more weekly +injections of 0.6 grm. of "914" are given. + +With each injection of "914" after the first, throughout the whole +course 1 grain of mercury is injected intra-muscularly. + +In the course of a few hours, there is usually some indisposition, with +a feeling of chilliness and slight rise of temperature; these symptoms +pass off within twenty-four hours, and in a few days there is a decided +improvement of health. Three or four days after an intra-muscular +injection there may be pain and stiffness in the gluteal region. + +These preparations are the most efficient therapeutic agents that have +yet been employed in the treatment of syphilis. + +The manifestations of the disease disappear with remarkable rapidity. +Observations show that the spirochaetes lose their capacity for movement +within an hour or two of the administration, and usually disappear +altogether in from twenty-four to thirty-six hours. Wassermann's +reaction usually yields a negative result in from three weeks to two +months, but later may again become positive. Subsequent doses of the +arsenical preparation are therefore usually indicated, and should be +given in from 7 to 21 days according to the dose. + +When syphilis occurs in a _pregnant woman_, she should be given in the +early months an ordinary course of "914," followed by 10-grain doses of +potassium iodide twice daily. The injections may be repeated two months +later, and during the remainder of the pregnancy 2-grain mercury pills +are given twice daily (A. Campbell). The presence of albumen in the +urine contra-indicates arsenical treatment. + +It need scarcely be pointed out that the use of powerful drugs like +"606" and "914" is not free from risk; it may be mentioned that each +dose contains nearly three grains of arsenic. Before the administration +the patient must be overhauled; its administration is contra-indicated +in the presence of disease of the heart and blood vessels, especially a +combination of syphilitic aortitis and sclerosis of the coronary +arteries, with degeneration of the heart muscle; in affections of the +central nervous system, especially advanced paralysis, and in such +disturbances of metabolism as are associated with diabetes and Bright's +disease. Its use is not contra-indicated in any lesion of active +syphilis. + +The administration is controlled by the systematic examination of the +urine for arsenic. + +_The Administration of Mercury._--The success of the arsenical +preparations has diminished the importance of mercury in the treatment +of syphilis, but it is still used to supplement the effect of the +injections. The amount of mercury to be given in any case must be +proportioned to the idiosyncrasies of the patient, and it is advisable, +before commencing the treatment, to test his urine and record his +body-weight. The small amount of mercury given at the outset is +gradually increased. If the body-weight falls, or if the gums become +sore and the breath foul, the mercury should be stopped for a time. If +salivation occurs, the drinking of hot water and the taking of hot baths +should be insisted upon, and half-dram doses of the alkaline sulphates +prescribed. + +_Methods of Administering Mercury._--(1) _By the Mouth._--This was for +long the most popular method in this country, the preparation usually +employed being grey powder, in pills or tablets, each of which contains +one grain of the powder. Three of these are given daily in the first +instance, and the daily dose is increased to five or even seven grains +till the standard for the individual patient is arrived at. As the grey +powder alone sometimes causes irritation of the bowels, it should be +combined with iron, as in the following formula: Hydrarg. c. cret. gr. 1; +ferri sulph. exsiccat. gr. 1 or 2. + +(2) _By Inunction._--Inunction consists in rubbing into the pores of the +skin an ointment composed of equal parts of 20 per cent. oleate of +mercury and lanolin. Every night after a hot bath, a dram of the +ointment (made up by the chemist in paper packets) is rubbed for fifteen +minutes into the skin where it is soft and comparatively free from +hairs. When the patient has been brought under the influence of the +mercury, inunction may be replaced by one of the other methods, of +administering the drug. + +(3) _By Intra-muscular Injection._--This consists in introducing the +drug by means of a hypodermic syringe into the substance of the gluteal +muscles. The syringe is made of glass, and has a solid glass piston; the +needle of platino-iridium should be 5 cm. long and of a larger calibre +than the ordinary hypodermic needle. The preparation usually employed +consists of: metallic mercury or calomel 1 dram, lanolin and olive oil +each 2 drams; it must be warmed to allow of its passage through the +needle. Five minims--containing one grain of metallic mercury--represent +a dose, and this is injected into the muscles above and behind the great +trochanter once a week. The contents of the syringe are slowly +expressed, and, after withdrawing the needle, gentle massage of the +buttock should be employed. Four courses each of ten injections are +given the first year, three courses of the same number during the second +and third years, and two courses during the fourth year (Lambkin). + +_The General Health._--The patient must lead a regular life and +cultivate the fresh-air habit, which is as beneficial in syphilis as in +tuberculosis. Anaemia, malaria, and other sources of debility must +receive appropriate treatment. The diet should be simple and easily +digested, and should include a full supply of milk. Alcohol is +prohibited. The excretory organs are encouraged to act by the liberal +drinking of hot water between meals, say five or six tumblerfuls in the +twenty-four hours. The functions of the skin are further aided by +frequent hot baths, and by the wearing of warm underclothing. While the +patient should avoid exposure to cold, and taxing his energies by undue +exertion, he should be advised to take exercise in the open air. On +account of the liability to lesions of the mouth and throat, he should +use tobacco in moderation, his teeth should be thoroughly overhauled by +the dentist, and he should brush them after every meal, using an +antiseptic tooth powder or wash. The mouth and throat should be rinsed +out night and morning with a solution of chlorate of potash and alum, or +with peroxide of hydrogen. + +_Treatment of the Local Manifestations._--_The skin lesions_ are treated +on the same lines as similar eruptions of other origin. As local +applications, preparations of mercury are usually selected, notably the +ointments of the red oxide of mercury, ammoniated mercury, or oleate of +mercury (5 per cent.), or the mercurial plaster introduced by Unna. In +the treatment of condylomata the greatest attention must be paid to +cleanliness and dryness. After washing and drying the affected patches, +they are dusted with a powder consisting of equal parts of calomel and +carbonate of zinc; and apposed skin surfaces, such as the nates or +labia, are separated by sublimate wool. In the ulcers of later secondary +syphilis, crusts are got rid of in the first instance by means of a +boracic poultice, after which a piece of lint or gauze cut to the size +of the ulcer and soaked in black wash is applied and covered with +oil-silk. If the ulcer tends to spread in area or in depth, it should be +scraped with a sharp spoon, and painted over with acid nitrate of +mercury, or a local hyperaemia may be induced by Klapp's suction +apparatus. + +_In lesions of the mouth and throat_, the teeth should be attended to; +the best local application is a solution of chromic acid--10 grains to +the ounce--painted on with a brush once daily. If this fails, the +lesions may be dusted with calomel the last thing at night. For deep +ulcers of the throat the patient should gargle frequently with chlorine +water or with perchloride of mercury (1 in 2000); if the ulcer continues +to spread it should be painted with acid nitrate of mercury. + +In the treatment of _iritis_ the eyes are shaded from the light and +completely rested, and the pupil is well dilated by atropin to prevent +adhesions. If there is much pain, a blister may be applied to the +temple. + +_The Relations of Syphilis to Marriage._--Before the introduction of the +Ehrlich-Hata treatment no patient was allowed to marry until three years +had elapsed after the disappearance of the last manifestation. While +marriage might be entered upon under these conditions without risk of +the husband infecting the wife, the possibility of his conveying the +disease to the offspring cannot be absolutely excluded. It is +recommended, as a precautionary measure, to give a further mercurial +course of two or three months' duration before marriage, and an +intravenous injection of an arsenical preparation. + +#Intermediate Stage.#--After the dying away of the secondary +manifestations and before the appearance of tertiary lesions, the +patient may present certain symptoms which Hutchinson called +_reminders_. These usually consist of relapses of certain of the +affections of the skin, mouth, or throat, already described. In the +skin, they may assume the form of peeling patches in the palms, or may +appear as spreading and confluent circles of a scaly papular eruption, +which if neglected may lead to the formation of fissures and superficial +ulcers. Less frequently there is a relapse of the eye affections, or of +paralytic symptoms from disease of the cerebral arteries. + +#Tertiary Syphilis.#--While the manifestations of primary and secondary +syphilis are common, those of the tertiary period are by comparison +rare, and are observed chiefly in those who have either neglected +treatment or who have had their powers of resistance lowered by +privation, by alcoholic indulgence, or by tropical disease. + +It is to be borne in mind that in a certain proportion of men and in a +larger proportion of women, the patient has no knowledge of having +suffered from syphilis. Certain slight but important signs may give the +clue in a number of cases, such as irregularity of the pupils or failure +to react to light, abnormality of the reflexes, and the discovery of +patches of leucoplakia on the tongue, cheek, or palate. + +The _general character of tertiary manifestations_ may be stated as +follows: They attack by preference the tissues derived from the +mesoblastic layer of the embryo--the cellular tissue, bones, muscles, +and viscera. They are often localised to one particular tissue or organ, +such, for example, as the subcutaneous cellular tissue, the bones, or +the liver, and they are rarely symmetrical. They are usually aggressive +and persistent, with little tendency to natural cure, and they may be +dangerous to life, because of the destructive changes produced in such +organs as the brain or the larynx. They are remarkably amenable to +treatment if instituted before the stage which is attended with +destruction of tissue is reached. Early tertiary lesions may be +infective, and the disease may be transmitted by the discharges from +them; but the later the lesions the less is the risk of their containing +an infective virus. + +The most prominent feature of tertiary syphilis consists in the +formation of granulation tissue, and this takes place on a scale +considerably larger than that observed in lesions of the secondary +period. The granulation tissue frequently forms a definite swelling or +tumour-like mass (syphiloma), which, from its peculiar elastic +consistence, is known as a _gumma_. In its early stages a gumma is a +firm, semi-translucent greyish or greyish-red mass of tissue; later it +becomes opaque, yellow, and caseous, with a tendency to soften and +liquefy. The gumma does harm by displacing and replacing the normal +tissue elements of the part affected, and by involving these in the +degenerative changes, of the nature of caseation and necrosis, which +produce the destructive lesions of the skin, mucous membranes, and +internal organs. This is true not only of the circumscribed gumma, but +of the condition known as _gummatous infiltration_ or _syphilitic +cirrhosis_, in which the granulation tissue is diffused throughout the +connective-tissue framework of such organs as the tongue or liver. Both +the gummatous lesions and the fibrosis of tertiary syphilis are directly +excited by the spirochaetes. + +The life-history of an untreated gumma varies with its environment. When +protected from injury and irritation in the substance of an internal +organ such as the liver, it may become encapsulated by fibrous tissue, +and persist in this condition for an indefinite period, or it may be +absorbed and leave in its place a fibrous cicatrix. In the interior of a +long bone it may replace the rigid framework of the shaft to such an +extent as to lead to pathological fracture. If it is near the surface of +the body--as, for example, in the subcutaneous or submucous cellular +tissue, or in the periosteum of a superficial bone, such as the palate, +the skull, or the tibia--the tissue of which it is composed is apt to +undergo necrosis, in which the overlying skin or mucous membrane +frequently participates, the result being an ulcer--the tertiary +syphilitic ulcer (Figs. 40 and 41). + +_Tertiary Lesions of the Skin and Subcutaneous Cellular Tissue._--The +clinical features of a _subcutaneous gumma_ are those of an indolent, +painless, elastic swelling, varying in size from a pea to an almond or +walnut. After a variable period it usually softens in the centre, the +skin over it becomes livid and dusky, and finally separates as a slough, +exposing the tissue of the gumma, which sometimes appears as a mucoid, +yellowish, honey-like substance, more frequently as a sodden, caseated +tissue resembling wash-leather. The caseated tissue of a gumma differs +from that of a tuberculous lesion in being tough and firm, of a buff +colour like wash-leather, or whitish, like boiled fish. The degenerated +tissue separates slowly and gradually, and in untreated cases may be +visible for weeks in the floor of the ulcer. + +[Illustration: FIG. 40.--Ulcerating Gumma of Lips. + +(From a photograph lent by Dr. Stopford Taylor and Dr. R. W. Mackenna.)] + +_The tertiary ulcer_ may be situated anywhere, but is most frequently +met with on the leg, especially in the region of the knee (Fig. 42) and +over the calf. There may be one or more ulcers, and also scars of +antecedent ulcers. The edges are sharply cut, as if punched out; the +margins are rounded in outline, firm, and congested; the base is +occupied by gummatous tissue, or, if this has already separated and +sloughed out, by unhealthy granulations and a thick purulent discharge. +When the ulcer has healed it leaves a scar which is depressed, and if +over a bone, is adherent to it. The features of the tertiary ulcer, +however, are not always so characteristic as the above description would +imply. It is to be diagnosed from the "leg ulcer," which occurs almost +exclusively on the lower third of the leg; from Bazin's disease (p. 74); +from the ulcers that result from certain forms of malignant disease, +such as rodent cancer, and from those met with in chronic glanders. + +_Gummatous Infiltration of the Skin_ ("Syphilitic Lupus").--This is a +lesion, met with chiefly on the face and in the region of the external +genitals, in which the skin becomes infiltrated with granulation tissue +so that it is thickened, raised above the surface, and of a brownish-red +colour. It appears as isolated nodules, which may fuse together; the +epidermis becomes scaly and is shed, giving rise to superficial ulcers +which are usually covered by crusted discharge. The disease tends to +spread, creeping over the skin with a serpiginous, crescentic, or +horse-shoe margin, while the central portion may heal and leave a scar. +From the fact of its healing in the centre while it spreads at the +margin, it may resemble tuberculous disease of the skin. It can usually +be differentiated by observing that the infiltration is on a larger +scale; the progress is much more rapid, involving in the course of +months an area which in the case of tuberculosis would require as many +years; the scars are sounder and are less liable to break down again; +and the disease rapidly yields to anti-syphilitic treatment. + +[Illustration: FIG. 41.--Ulceration of nineteen year's duration +in a woman aet. 24, the subject of inherited syphilis, showing active +ulceration, cicatricial contraction, and sabre-blade deformity of +tibiae.] + +_Tertiary lesions of mucous membrane and of the submucous cellular +tissue_ are met with chiefly in the tongue, nose, throat, larynx, and +rectum. They originate as gummata or as gummatous infiltrations, which +are liable to break down and lead to the formation of ulcers which may +prove locally destructive, and, in such situations as the larynx, even +dangerous to life. In the tongue the tertiary ulcer may prove the +starting-point of cancer; and in the larynx or rectum the healing of the +ulcer may lead to cicatricial stenosis. + +Tertiary lesions of the _bones and joints_, of the _muscles_, and of the +_internal organs_, will be described under these heads. The part played +by syphilis in the production of disease of arteries and of aneurysm +will be referred to along with diseases of blood vessels. + +[Illustration: FIG. 42.--Tertiary Syphilitic Ulceration in region of +Knee and on both Thumbs of woman aet. 37.] + +_Treatment._--The most valuable drugs for the treatment of the +manifestations of the tertiary period are the arsenical preparations and +the iodides of sodium and potassium. On account of their depressing +effects, the latter are frequently prescribed along with carbonate of +ammonium. The dose is usually a matter of experiment in each individual +case; 5 grains three times a day may suffice, or it may be necessary to +increase each dose to 20 or 25 grains. The symptoms of iodism which may +follow from the smaller doses usually disappear on giving a larger +amount of the drug. It should be taken after meals, with abundant water +or other fluid, especially if given in tablet form. It is advisable to +continue the iodides for from one to three months after the lesions for +which they are given have cleared up. If the potassium salt is not +tolerated, it may be replaced by the ammonium or sodium iodide. + +_Local Treatment._--The absorption of a subcutaneous gumma is often +hastened by the application of a fly-blister. When a gumma has broken on +the surface and caused an ulcer, this is treated on general principles, +with a preference, however, for applications containing mercury or +iodine, or both. If a wet dressing is required to cleanse the ulcer, +black wash may be used; if a powder to promote dryness, one containing +iodoform; if an ointment is indicated, the choice lies between the red +oxide of mercury or the dilute nitrate of mercury ointment, and one +consisting of equal parts of lanolin and vaselin with 2 per cent. of +iodine. Deep ulcers, and obstinate lesions of the bones, larynx, and +other parts may be treated by excision or scraping with the sharp spoon. + +#Second Attacks of Syphilis.#--Instances of re-infection of syphilis +have been recorded with greater frequency since the more general +introduction of arsenical treatment. A remarkable feature in such cases +is the shortness of the interval between the original infection and the +alleged re-infection; in a recent series of twenty-eight cases, this +interval was less than a year. Another feature of interest is that when +patients in the tertiary stage of syphilis are inoculated with the virus +from lesions from these in the primary and secondary stage lesions of +the tertiary type are produced. + +Reference may be made to the #relapsing false indurated chancre#, +described by Hutchinson and by Fournier, as it may be the source of +difficulty in diagnosis. A patient who has had an infecting chancre one +or more years before, may present a slightly raised induration on the +penis at or close to the site of his original sore. This relapsed +induration is often so like that of a primary chancre that it is +impossible to distinguish between them, except by the history. If there +has been a recent exposure to venereal infection, it is liable to be +regarded as the primary lesion of a second attack of syphilis, but the +further progress shows that neither bullet-buboes nor secondary +manifestations develop. These facts, together with the disappearance of +the induration under treatment, make it very likely that the lesion is +really gummatous in character. + + +INHERITED SYPHILIS + +One of the most striking features of syphilis is that it may be +transmitted from infected parents to their offspring, the children +exhibiting the manifestations that characterise the acquired form of the +disease. + +The more recent the syphilis in the parent, the greater is the risk of +the disease being communicated to the offspring; so that if either +parent suffers from secondary syphilis the infection is almost +inevitably transmitted. + +While it is certain that either parent may be responsible for +transmitting the disease to the next generation, the method of +transmission is not known. In the case of a syphilitic mother it is most +probable that the infection is conveyed to the foetus by the placental +circulation. In the case of a syphilitic father, it is commonly believed +that the infection is conveyed to the ovum through the seminal fluid at +the moment of conception. If a series of children, one after the other, +suffer from inherited syphilis, it is almost invariably the case that +the mother has been infected. + +In contrast to the acquired form, inherited syphilis is remarkable for +the absence of any primary stage, the infection being a general one from +the outset. The spirochaete is demonstrated in incredible numbers in the +liver, spleen, lung, and other organs, and in the nasal secretion, and, +from any of these, successful inoculations in monkeys can readily be +made. The manifestations differ in degree rather than in kind from those +of the acquired disease; the difference is partly due to the fact that +the virus is attacking developing instead of fully formed tissues. + +The virus exercises an injurious influence on the foetus, which in many +cases dies during the early months of intra-uterine life, so that +miscarriage results, and this may take place in repeated pregnancies, +the date at which the miscarriage occurs becoming later as the virus in +the mother becomes attenuated. Eventually a child is carried to full +term, and it may be still-born, or, if born alive, may suffer from +syphilitic manifestations. It is difficult to explain such vagaries of +syphilitic inheritance as the infection of one twin and the escape of +the other. + +_Clinical Features._--We are not here concerned with the severe forms of +the disease which prove fatal, but with the milder forms in which the +infant is apparently healthy when born, but after from two to six weeks +begins to show evidence of the syphilitic taint. + +The usual phenomena are that the child ceases to thrive, becomes thin +and sallow, and suffers from eruptions on the skin and mucous membranes. +There is frequently a condition known as _snuffles_, in which the nasal +passages are obstructed by an accumulation of thin muco-purulent +discharge which causes the breathing to be noisy. It usually begins +within a month after birth and before the eruptions on the skin appear. +When long continued it is liable to interfere with the development of +the nasal bones, so that when the child grows up there results a +condition known as the "saddle-nose" deformity (Figs. 43 and 44). + +[Illustration: FIG. 43.--Facies of Inherited Syphilis. + +(From Dr. Byrom Bramwell's _Atlas of Clinical Medicine_.)] + +_Affections of the Skin._--Although all types of skin affection are met +with in the inherited disease, the most important is a _papular_ +eruption, the papules being of large size, with a smooth shining top and +of a reddish-brown colour. It affects chiefly the buttocks and thighs, +the genitals, and other parts which are constantly moist. It is +necessary to distinguish this specific eruption from a form of eczema +which occurs in these situations in non-syphilitic children, the points +that characterise the syphilitic condition being the infiltration of the +skin and the coppery colour of the eruption. At the anus the papules +acquire the characters of _condylomata_, also at the angles of the +mouth, where they often ulcerate and leave radiating scars. + +_Affections of the Mucous Membranes._--The inflammation of the nasal +mucous membrane that causes snuffles has already been referred to. There +may be mucous patches in the mouth, or a stomatitis which is of +importance, because it results in interference with the development of +the permanent teeth. The mucous membrane of the larynx may be the seat +of mucous patches or of catarrh, and as a result the child's cry is +hoarse. + +_Affections of the Bones._--Swellings at the ends of the long bones, due +to inflammation at the epiphysial junctions, are most often observed at +the upper end of the humerus and in the bones in the region of the +elbow. Partial displacement and mobility at the ossifying junction may +be observed. The infant cries when the part is touched; and as it does +not move the limb voluntarily, the condition is spoken of as _the +pseudo-paralysis of syphilis_. Recovery takes place under +anti-syphilitic treatment and immobilisation of the limb. + +Diffuse thickening of the shafts of the long bones, due to a deposit of +new bone by the periosteum, is sometimes met with. + +[Illustration: FIG. 44.--Facies of Inherited Syphilis.] + +The conditions of the skull known as Parrot's nodes or bosses, and +craniotabes, were formerly believed to be characteristic of inherited +syphilis, but they are now known to occur, particularly in rickety +children, from other causes. The _bosses_ result from the heaping up of +new spongy bone beneath the pericranium, and they may be grouped +symmetrically around the anterior fontanelle, or may extend along either +side of the sagittal suture, which appears as a deep groove--the +"natiform skull." The bosses disappear in time, but the skull may remain +permanently altered in shape, the frontal and parietal eminences +appearing unduly prominent. The term _craniotabes_ is applied when the +bone becomes thin and soft, reverting to its original membranous +condition, so that the affected areas dimple under the finger like +parchment or thin cardboard; its localisation in the posterior parts of +the skull suggests that the disappearance of the osseous tissue is +influenced by the pressure of the head on the pillow. Craniotabes is +recovered from as the child improves in health. + +Between the ages of three and six months, certain other phenomena may be +met with, such as _effusion into the joints_, especially the knees; +_iritis_, in one or in both eyes, and enlargement of the spleen and +liver. + +In the majority of cases the child recovers from these early +manifestations, especially when efficiently treated, and may enjoy an +indefinite period of good health. On the other hand, when it attains the +age of from two to four years, it may begin to manifest lesions which +correspond to those of the tertiary period of acquired syphilis. + +#Later Lesions.#--In the skin and subcutaneous tissue, the later +manifestations may take the form of localised gummata, which tend to +break down and form ulcers, on the leg for example, or of a spreading +gummatous infiltration which is also liable to ulcerate, leaving +disfiguring scars, especially on the face. The palate and fauces may be +destroyed by ulceration. In the nose, especially when the ulcerative +process is associated with a putrid discharge--ozaena--the destruction of +tissue may be considerable and result in unsightly deformity. The entire +palatal portions of the upper jaws, the vomer, turbinate, and other +bones bounding the nasal and oral cavities, may disappear, so that on +looking into the mouth the base of the skull is readily seen. Gummatous +disease is frequently observed also in the flat bones of the skull, in +the bones of the hand, as syphilitic dactylitis, and in the bones of the +forearm and leg. When the tibia is affected the disease is frequently +bilateral, and may assume the form of gummatous ulcers and sinuses. In +later years the tibia may present alterations in shape resulting from +antecedent gummatous disease--for example, nodular thickenings of the +shaft, flattening of the crest, or a more uniform increase in thickness +and length of the shaft of the bone, which, when it is curved in +addition, is described as the "sabre-blade" deformity. Among lesions of +the viscera, mention should be made of gumma of the testis, which causes +the organ to become enlarged, uneven, and indurated. This has even been +observed in infants a few months old. + +Occasionally a syphilitic child suffers from a succession of these +gummatous lesions with resulting ill-health, and, it may be, waxy +disease of the internal organs; on the other hand, it may recover and +present no further manifestations of the inherited taint. + +_Affections of the Eyes._--At or near puberty there is frequently +observed an affection of the eyes, known as _chronic interstitial +keratitis_, the relationship of which to inherited syphilis was first +established by Hutchinson. It occurs between the ages of six and sixteen +years, and usually affects one eye before the other. It commences as a +diffuse haziness or steaminess near the centre of the cornea, and as it +spreads the entire cornea assumes the appearance of ground glass. The +chief complaint is of dimness of sight, which may almost amount to +blindness, but there is little pain or photophobia; a certain amount of +conjunctival and ciliary congestion is usually present, and there may be +_iritis_ in addition. The cornea, or parts of it, may become of a deep +pink or salmon colour from the formation in it of new blood vessels. The +affection may last for from eighteen months to two years. Complete +recovery usually takes place, but slight opacities, especially in the +site of former salmon patches, may persist, and the disease occasionally +relapses. _Choroiditis_ and _retinitis_ may also occur, and leave +permanent changes easily recognised on examination with the +ophthalmoscope. + +Among the rarer and more serious lesions of the inherited disease may be +mentioned gummatous disease in the _larynx and trachea_, attended with +ulceration and resulting in stenosis; and lesions of the _nervous +system_ which may result in convulsions, paralysis, or dementia. + +In a limited number of cases, about the period of puberty there may +develop _deafness_, which is usually bilateral and may become absolute. + +_Changes in the Permanent Teeth._--These affect specially the upper +central incisors, which are dwarfed and stand somewhat apart in the gum, +with their free edges converging towards one another. They are tapering +or peg-shaped, and present at their cutting margin a deep semilunar +notch. These appearances are commonly associated with the name of +Hutchinson, who first described them. Affecting as they do the +permanent teeth, they are not available for diagnosis until the child is +over eight years of age. Henry Moon drew attention to a change in the +first molars; these are reduced in size and dome-shaped through dwarfing +of the central tubercle of each cusp. + +#Diagnosis of Inherited Syphilis.#--When there is a typical eruption on +the buttocks and snuffles there is no difficulty in recognising the +disease. When, however, the rash is scanty or is obscured by co-existing +eczema, most reliance should be placed on the distribution of the +eruption, on the brown stains which are left after it has passed off, on +the presence of condylomata, and of fissuring and scarring at the angles +of the mouth. The history of the mother relative to repeated +miscarriages and still-born children may afford confirmatory evidence. +In doubtful cases, the diagnosis may be aided by the Wassermann test and +by noting the therapeutic effects of grey powder, which, in syphilitic +infants, usually effects a marked and rapid improvement both in the +symptoms and in the general health. + +While a considerable number of syphilitic children grow up without +showing any trace of their syphilitic inheritance, the majority retain +throughout life one or more of the following characteristics, which may +therefore be described as _permanent signs of the inherited disease_: +Dwarfing of stature from interference with growth at the epiphysial +junctions; the forehead low and vertical, and the parietal and frontal +eminences unduly prominent; the bridge of the nose sunken and rounded; +radiating scars at the angles of the mouth; perforation or destruction +of the hard palate; Hutchinson's teeth; opacities of the cornea from +antecedent keratitis; alterations in the fundus oculi from choroiditis; +deafness; depressed scars or nodes on the bones from previous gummata; +"sabre-blade" or other deformity of the tibiae. + +#The Contagiousness of Inherited Syphilis.#--In 1837, Colles of Dublin +stated his belief that, while a syphilitic infant may convey the disease +to a healthy wet nurse, it is incapable of infecting its own mother if +nursed by her, even although she may never have shown symptoms of the +disease. This doctrine, which is known as _Colles' law_, is generally +accepted in spite of the alleged occurrence of occasional exceptions. +The older the child, the less risk there is of its communicating the +disease to others, until eventually the tendency dies out altogether, as +it does in the tertiary period of acquired syphilis. It should be +added, however, that the contagiousness of inherited syphilis is denied +by some observers, who affirm that, when syphilitic infants prove +infective, the disease has been really acquired at or soon after birth. + +There is general agreement that the subjects of inherited syphilis +cannot transmit the disease by inheritance to their offspring, and that, +although they very rarely acquire the disease _de novo_, it is possible +for them to do so. + +#Prognosis of Inherited Syphilis.#--Although inherited syphilis is +responsible for a large but apparently diminishing mortality in infancy, +the subjects of this disease may grow up to be as strong and healthy as +their neighbours. Hutchinson insisted on the fact that there is little +bad health in the general community that can be attributed to inherited +syphilis. + +#Treatment.#--Arsenical injections are as beneficial in the inherited as +in the acquired disease. An infant the subject of inherited syphilis +should, if possible, be nursed by its mother, and failing this it should +be fed by hand. In infants at the breast, the drug may be given to the +mother; in others, it is administered in the same manner as already +described--only in smaller doses. On the first appearance of syphilitic +manifestations it should be given 0.05 grm, novarsenbillon, injected +into the deep subcutaneous tissues every week for six weeks, followed by +one year's mercurial inunction--a piece of mercurial ointment the size +of a pea being inserted under the infant's binder. In older children the +dose is proportionately increased. The general health should be improved +in every possible direction; considerable benefit may be derived from +the use of cod-liver oil, and from preparations containing iron and +calcium. Surgical interference may be required in the destructive +gummatous lesions of the nose, throat, larynx, and bones, either with +the object of arresting the spread of the disease, or of removing or +alleviating the resulting deformities. In children suffering from +keratitis, the eyes should be protected from the light by smoked or +coloured glasses, and the pupils should be dilated with atropin from +time to time, especially in cases complicated with iritis. + +#Acquired Syphilis in Infants and Young Children.#--When syphilis is met +with in infants and young children, it is apt to be taken for granted +that the disease has been inherited. It is possible, however, for them +to acquire the disease--as, for example, while passing through the +maternal passages during birth, through being nursed or kissed by +infected women, or through the rite of circumcision. The risk of +infection which formerly existed by the arm-to-arm method of +vaccination has been abolished by the use of calf lymph. + +The clinical features of the acquired disease in infants and young +children are similar to those observed in the adult, with a tendency, +however, to be more severe, probably because the disease is often late +in being recognised and treated. + + + + +CHAPTER X + +TUMOURS[2] + + +Definition--Etiology--General characters of innocent and malignant + tumours. CLASSIFICATION OF TUMOURS: I. Connective-tissue tumours: + (1) _Innocent_: _Lipoma_, _Xanthoma_, _Chondroma_, _Osteoma_, + _Odontoma_, _Fibroma_, _Myxoma_, _Endothelioma_, etc.; (2) + _Malignant_: _Sarcoma_--II. Epithelial tumours: (1) _Innocent_: + _Papilloma_, _Adenoma_, _Cystic Adenoma_; (2) _Malignant_: + _Epithelioma_, _Glandular Cancer_, _Rodent Cancer_, _Melanotic + Cancer_--III. Dermoids--IV. Teratoma. Cysts: _Retention_, + _Exudation_, _Implantation_, _Parasitic_, _Lymphatic or Serous_. + Ganglion. + +[2] For the histology of tumours the reader is referred to a text-book +of pathology. + +A tumour or neoplasm is a localised swelling composed of newly formed +tissue which fulfils no physiological function. Tumours increase in size +quite independently of the growth of the body, and there is no natural +termination to their growth. They are to be distinguished from such +over-growths as are of the nature of simple hypertrophy or local +giantism, and also from inflammatory swellings, which usually develop +under the influence of a definite cause, have a natural termination, and +tend to disappear when the cause ceases to act. + +The _etiology of tumours_ is imperfectly understood. Various factors, +acting either singly or in combination, may be concerned in their +development. Certain tumours, for example, are the result of some +congenital malformation of the particular tissue from which they take +origin. This would appear to be the case in many tumours of blood +vessels (angioma), of cartilage (chondroma), of bone (osteoma), and of +secreting gland tissue (adenoma). The theory that tumours originate from +foetal residues or "rests," is associated with the name of Cohnheim. +These rests are supposed to be undifferentiated embryonic cells which +remain embedded amongst fully formed tissue elements, and lie dormant +until they are excited into active growth and give rise to a tumour. +This mode of origin is illustrated by the development of dermoids from +sequestrated portions of epidermis. + +Among the local factors concerned in the development of tumours, +reference must be made to the influence of irritation. This is probably +an important agent in the causation of many of the tumours met with in +the skin and in mucous membranes--for example, cancer of the skin, of +the lip, and of the tongue. The part played by injury is doubtful. It +not infrequently happens that the development of a tumour is preceded by +an injury of the part in which it grows, but it does not necessarily +follow that the injury and the tumour are related as cause and effect. +It is possible that an injury may stimulate into active growth +undifferentiated tissue elements or "rests," and so determine the growth +of a tumour, or that it may alter the characters of a tumour which +already exists, causing it to grow more rapidly. + +The popular belief that there is some constitutional peculiarity +concerned in the causation of tumours is largely based on the fact that +certain forms of new growth--for example, cancer--are known to occur +with undue frequency in certain families. The same influence is more +striking in the case of certain innocent tumours--particularly multiple +osteomas and lipomas--which are hereditary in the same sense as +supernumerary or webbed fingers, and appear in members of the same +family through several generations. + + +INNOCENT AND MALIGNANT TUMOURS + +For clinical purposes, tumours are arbitrarily divided into two +classes--the innocent and the malignant. The outstanding difference +between them is, that while the evil effects of innocent tumours are +entirely local and depend for their severity on the environment of the +growth, malignant tumours wherever situated, in addition to producing +similar local effects, injure the general health and ultimately cause +death. + +_Innocent_, benign, or simple tumours present a close structural +resemblance to the normal tissues of the body. They grow slowly, and are +usually definitely circumscribed by a fibrous capsule, from which they +are easily enucleated, and they do not tend to recur after removal. In +their growth they merely push aside and compress adjacent parts, and +they present no tendency to ulcerate and bleed unless the overlying skin +or mucous membrane is injured. Although usually solitary, some are +multiple from the outset--for example, fatty, fibrous, and bony tumours, +warts, and fibroid tumours of the uterus. They produce no constitutional +disturbance. They only threaten life when growing in the vicinity of +vital organs, and then only in virtue of their situation--for example, +death may result from an innocent tumour in the air-passage causing +suffocation, in the intestine causing obstruction of the bowels, or in +the vertebral canal causing pressure on the spinal medulla. + +_Malignant tumours_ usually show a marked departure from the structure +and arrangement of the normal tissues of the body. Although the cells of +which they are composed are derived from normal tissue cells, they tend +to take on a lower, more vegetative form; they may be regarded as +parasites living at the expense of the organism, multiplying +indefinitely and destroying everything with which they come in contact. + +Malignant tumours grow more rapidly than innocent tumours, and tend to +infiltrate their surroundings by sending out prolongations or offshoots; +they are therefore liable to recur after an operation which is +restricted to the removal of the main tumour. They are not encapsulated, +although they may appear to be circumscribed by condensation of the +surrounding tissues; they are rarely multiple at the outset, but show a +marked tendency to spread to other parts of the body. Fragments of the +parent tumour may become separated and be carried off in the lymph or +blood-stream and deposited in other parts of the body, where they give +rise to secondary growths. Malignant tumours tend to invade and destroy +the overlying skin or mucous membrane, and thus give rise to bleeding +ulcers; if the tumour tissue protrudes through the gap in the skin, it +is said to _fungate_. In course of time they give rise to a condition of +ill-health or _cachexia_, the patient becoming pale, sallow, feverish, +and emaciated, probably as a result of chronic poisoning from the +absorption of toxic products from the tumour. They ultimately destroy +life, it may be by their local effects, such as ulceration and +haemorrhage, by favouring the entrance of septic infection, by +interfering with the function of organs which are essential to life, by +cachexia, or by a combination of these effects. + +The situation of a malignant tumour exercises considerable influence on +the rapidity, as well as on the mode, in which it causes death. Some +cancers, such as that known as "rodent," show malignant features which +are entirely local, while others, such as melanotic cancer, exhibit a +malignancy characterised by rapid generalisation of growths throughout +the body. Tumours that are structurally alike may show variations in +malignancy, according to their situation and to the age of the patient, +as well as to other factors which are as yet unknown. + +In attempting to arrive at a conclusion as to the innocence or +malignancy of any tumour, too much reliance must not be placed on its +histological features; its situation, rate of growth, and other clinical +features must also be taken into consideration. It cannot be too +emphatically stated that there is no hard-and-fast line between innocent +and malignant growths; there is an indefinite transition from one to the +other. The possibility of the transformation of a benign into a +malignant tumour must be admitted. Such a transformation implies a +change in the structure of the growth, and has been observed especially +in fibrous and cartilaginous tumours, in tumours of the thyreoid gland, +and in uterine fibroids. The alteration in character may take place +under the influence of injury, prolonged or repeated irritation, +incomplete removal of the benign tumour by operation, or the altered +physiological conditions of the tissues which attend upon advancing +years. + +After a tumour has been removed by operation it should as a routine +measure be subjected to microscopical examination; the results are often +instructive and sometimes other than what was expected. + +#Varieties of Tumours.#--In the following description, tumours are +classified on an anatomical basis, taking in order first the +connective-tissue group and subsequently those that originate in +epithelium. + + +INNOCENT CONNECTIVE-TISSUE TUMOURS + +#Lipoma.#--A lipoma is composed of fat resembling that normally present +in the body. The commonest variety is the _subcutaneous lipoma_, which +grows from the subcutaneous fat, and forms a soft, irregularly lobulated +tumour (Fig. 45). The fat is arranged in lobules separated by +connective-tissue septa, which are continuous with the capsule +surrounding the tumour and with the overlying skin, which becomes +dimpled or puckered when an attempt is made to pinch it up. As the fat +is almost fluid at the body temperature, fluctuation can usually be +detected. These tumours vary greatly in size, occur at all ages, grow +slowly, and, while generally solitary, are sometimes multiple. They are +most commonly met with on the shoulder, buttock, or back. In certain +situations, such as the thigh and perineum, they tend to become +pedunculated (Fig. 46). + +A fatty tumour is to be diagnosed from a cold abscess and from a cyst. +The distinguishing features of the lipoma are the tacking down and +dimpling of the overlying skin, the lobulation of the tumour, which is +recognised when it is pressed upon with the flat of the hand, and, more +reliable than either of these, the mobility, the tumour slipping away +when pressed upon at its margin. + +[Illustration: FIG. 45.--Subcutaneous Lipoma showing lobulation.] + +The prognosis is more favourable than in any other tumour as it never +changes its characters; the only reasons for its removal by operation +are its unsightliness and its probable increase in size in the course of +years. The operation consists in dividing the skin and capsule over the +tumour and shelling it out. Care must be taken that none of the outlying +lobules are left behind. If the overlying skin is damaged or closely +adherent, it should be removed along with the tumour. + +[Illustration: FIG. 46.--Pedunculated Lipoma of Buttock of forty years' +duration in a woman aet. 68.] + +_Multiple subcutaneous lipomas_ are frequently symmetrical, and in a +certain group of cases, met with chiefly in women, pain is a prominent +symptom, hence the term _adiposis dolorosa_ (Dercum). These multiple +tumours show little or no tendency to increase in size, and the pain +which attends their development does not persist. + +In the neck, axilla, and pubes a diffuse overgrowth of the subcutaneous +fat is sometimes met with, forming symmetrical tumour-like masses, known +as _diffuse lipoma_. As this is not, strictly speaking, a tumour, the +term _diffuse lipomatosis_ is to be preferred. A similar condition was +described by Jonathan Hutchinson as being met with in the domestic +animals. If causing disfigurement, the mass of fat may be removed by +operation. + +[Illustration: FIG. 47.--Diffuse Lipomatosis of Neck.] + +_Lipoma in other Situations._--The _periosteal lipoma_ is usually +congenital, and is most often met with in the hand; it forms a +projecting lobulated tumour, which, when situated in the palm, resembles +an angioma or a lymphangioma. The _subserous lipoma_ arises from the +extra-peritoneal fat in the posterior abdominal wall, in which case it +tends to grow forwards between the layers of the mesentery and to give +rise to an abdominal tumour; or it may grow from the extra-peritoneal +fat in the anterior abdominal wall and protrude from one of the hernial +openings or through an abnormal opening in the parietes, constituting a +_fatty hernia_. A _subsynovial lipoma_ grows from the fat surrounding +the synovial membrane of a joint, and projects into its interior, giving +rise to the symptoms of loose body. Lipomas are also met with growing +from the adipose connective tissue _between or in the substance of +muscles_, and, when situated beneath the deep fascia, such as the fascia +lata of the thigh, the characteristic signs are obscured and a +differential diagnosis is difficult. It may be differentiated from a +cold abscess by puncture with an exploring needle. + +[Illustration: FIG. 48.--Zanthoma of Hands in a girl aet. 14, showing +multiple subcutaneous tumours (cf. Fig. 49). + +(Sir H. J. Stiles' case.)] + +#Zanthoma# is a rare but interesting form of tumour, composed of a +fibrous and fatty tissue, containing a granular orange-yellow pigment, +resembling that of the corpus luteum. It originates in the corium and +presents two clinical varieties. In the first of these, it occurs in the +form of raised yellow patches, usually in the skin of the eyelids of +persons after middle life, and in many instances is associated with +chronic jaundice; the patches are often symmetrical, and as they +increase in size they tend to fuse with another. + +The second form occurs in children and adolescents; it may affect +several generations of the same family, and is often multiple, there +being a combination of thickened yellow patches of skin and projecting +tumours, some of which may attain a considerable size (Figs. 48 and 49). +On section, the tumour tissue presents a brilliant orange or saffron +colour. + +There is no indication for removing the tumours unless for the deformity +which they cause; exposure to the X-rays is to be preferred to +operation. + +[Illustration: FIG. 49.--Zanthoma showing Subcutaneous Tumours on +Buttocks. From same patient as Fig. 48.] + +#Chondroma.#--A chondroma is mainly composed of cartilage. Processes of +vascular connective tissue pass in between the nodules of cartilage +composing the tumour from the fibrous capsule which surrounds it. On +section it is of a greyish-blue colour and semi-translucent. The tumour +is firm and elastic in consistence, but certain portions may be densely +hard from calcification or ossification, while other portions may be +soft and fluctuating as a result of myxomatous degeneration and +liquefaction. These tumours grow slowly and painlessly, and may surround +nerves and arteries without injuring them. They may cause a deep hollow +in the bone from which they originate. All intermediate forms between +the innocent chondroma and the malignant chondro-sarcoma are met with. +Chondroma may occur in a multiple form, especially in relation to the +phalanges and metacarpal bones. When growing in the interior of a bone +it causes a spindle-shaped enlargement of the shaft, which in the case +of a phalanx or metacarpal bone may resemble the dactylitis resulting +from tubercle or syphilis. A chondroma appears as a clear area in a +skiagram. + +A _skiagram_ of a bone in which there is a chondroma shows a clear +rounded area in the position of the tumour, which must be differentiated +from similar clear areas due to other kinds of tumour, especially the +myeloma; when it has undergone calcification or ossification, it gives a +shadow as dark as bone. + +[Illustration: FIG. 50.--Chondroma growing from infraspinous fossa of +Scapula.] + +[Illustration: FIG. 51.--Chondroma of Metacarpal Bone of Thumb.] + +_Treatment._--In view of the unstable quality of the chondroma, +especially of its liability to become malignant, it should be removed as +soon as it is recognised. In those projecting from the surface of a +bone, both the tumour and its capsule should be removed. If in the +interior, a sufficient amount of the cortex should be removed to allow +of the tumour being scraped out, and care must be taken that no nodules +of cartilage are left behind. In multiple chondromas of the hand, when +the fingers are crippled and useless, exposure to the X-rays should be +given a trial, and in extreme cases the question of amputation may have +to be considered. When a cartilaginous tumour takes on active growth, it +must be treated as malignant. + +The chondromas that are met with at the ends of the long bones in +children and young adults form a group by themselves. They are usually +related to the epiphysial cartilage, and it was suggested by Virchow +that they take origin from islands of cartilage which have not been used +up in the process of ossification. They are believed to occur more +frequently in those who have suffered from rickets. They have no +malignant tendencies and tend to undergo ossification concurrently with +the epiphysial cartilage from which they take origin, and constitute +what are known as _cartilaginous exostoses_. These are sometimes met +with in a multiple form, and may occur in several generations of the +same family. They are considered in greater detail in the chapter +dealing with tumours of bone. + +Minute nodules of cartilage sometimes form in the synovial membrane of +joints and lining of tendon sheaths and bursae: they tend to become +detached from the membrane and constitute loose bodies; they also +undergo a variable amount of calcification and ossification, so as to be +visible in skiagrams. They are further considered with loose bodies in +joints. + +Cartilaginous tumours in the parotid, submaxillary gland, and testicle +belong to a class of "mixed tumours" that will be referred to later. + +#Osteoma.#--The true osteoma is composed of bony tissue, and originates +from the skeleton. Two varieties are recognised--the spongy or +cancellous, and the ivory or compact. The _spongy_ or _cancellous +osteoma_ is really an ossified chondroma, and is met with at the ends of +the long bones (Fig. 52). From the fact that it projects from the +surface of the bone it is often spoken of as an _exostosis_. It grows +slowly, and rarely causes any discomfort unless it presses upon a +nerve-trunk or upon a bursa which has developed over it. The Rontgen +rays show a dark shadow corresponding to the ossified portion of the +tumour, and continuous with that of the bone from which it is growing +(Fig. 138). Operative interference is only indicated when the tumour is +giving rise to inconvenience. It is then removed, its base or neck being +divided by means of the chisel. The multiple variety of osteoma is +considered with the diseases of bone. + +The bony outgrowth from the terminal phalanx of the great toe--known as +the _subungual exostosis_--is described and figured on p. 404. Bony +projections or "spurs" sometimes occur on the under surface of the +calcaneus, and, projecting downwards and forwards from the greater +process, cause pain on putting the heel to the ground. + +[Illustration: FIG. 52.--Cancellous Osteoma of lower end of Femur.] + +The _ivory_ or _compact osteoma_ is composed of dense bone, and usually +grows from the skull. It is generally sessile and solitary, and may grow +into the interior of the skull, into the frontal sinus, into the cavity +of the orbit or nose, or may fill up the external auditory meatus, +causing most unsightly deformity and interference with sight, breathing, +and hearing. + +Bony formations occur in _muscles and tendons_, especially at their +points of attachment to the skeleton, and are known as false exostoses; +they are described with the diseases of muscles. + +#Odontoma.#--An odontoma is composed of dental tissues in varying +proportions and different degrees of development, arising from +tooth-germs or from teeth still in process of growth (Bland Sutton). +Odontomas resemble teeth in so far that during their development they +remain hidden below the mucous membrane and give no evidence of their +existence. There then succeeds, usually between the twentieth and +twenty-fifth years, an eruptive stage, which is often attended with +suppuration, and this may be the means of drawing attention to the +tumour. Following Bland Sutton, several varieties of odontoma may be +distinguished according to the part of the tooth-germ concerned in their +formation. + +The _epithelial odontoma_ is derived from persistent portions of the +epithelium of the enamel organ, and constitutes a multilocular cystic +tumour which is chiefly met with in the mandible. The cystic spaces of +the tumour contain a brownish glairy fluid. These tumours have been +described by Eve under the name of multilocular cystic epithelial +tumours of the jaw. + +The _follicular odontoma_, also known as a _dentigerous cyst_, is +derived from the distension of a tooth follicle. It constitutes a cyst +containing a viscid fluid, and an imperfectly formed tooth is often +found embedded in its wall. The cyst usually forms in relation to one of +the permanent molars, and may attain considerable dimensions. + +The _fibrous odontoma_ is the result of an overgrowth of fibrous tissue +surrounding the tooth sac, which encapsulates the tooth and prevents its +eruption. The thickened tooth sac is usually mistaken for a fibrous +tumour, until, after removal, the tooth is recognised in its interior. + +_Composite Odontoma._--This is a convenient term to apply to certain +hard dental tumours which are met with in the jaws, and consist of +enamel, dentine, and cement. The tumour is to be regarded as being +derived from an abnormal growth of all the elements of a tooth germ, or +of two or more tooth germs, indiscriminately fused with one another. It +may appear in childhood, and form a smooth unyielding tumour, often of +considerable size, replacing the corresponding permanent tooth. It may +cause a purulent discharge, and in some cases it has been extruded after +sloughing of the overlying soft parts. Many examples of this variety of +odontoma, growing in the nasal cavity or in the maxillary sinus, have +been erroneously regarded as osteomas even after removal. + +On section, the tumour is usually laminated, and is seen to consist +mainly of dentine with a partial covering of enamel and cement. + +_Diagnosis._--Odontomas are often only diagnosed after removal. When +attended with suppuration, the condition has been mistaken for disease +of the jaw. Fibrous odontomas have been mistaken for sarcoma, and +portions of the maxilla removed unnecessarily. Any circumscribed tumour +of the jaw, particularly when met with in a young adult, should suggest +the possibility of an odontoma. Skiagrams often give useful information +both for diagnosis and for treatment. + +_Treatment._--The solid varieties of odontoma can usually be shelled out +after dividing the overlying soft parts. In the follicular variety, it +is usually sufficient to excise a portion of the wall, scrape out the +interior, and remove any tooth that may be present. The cavity is then +packed and allowed to heal from the bottom. + +#Fibroma.#--A fibroma is a tumour composed of fibrous connective tissue. +A distinction may be made between the _soft fibroma_, which is +comparatively rich in cells and blood vessels, and in which the fibres +are arranged loosely; and the _hard fibroma_, which is composed of +closely packed bundles of fibres often arranged in a concentric fashion +around the blood vessels. The cut surface of the soft fibroma presents a +pinkish-white, fleshy appearance, resembling the slowly growing forms of +sarcoma; that of a hard fibroma presents a dry, glistening appearance, +aptly compared to watered silk. The soft variety grows much more rapidly +than the hard. In certain fibromas--in those, for example, which grow +from the periosteum of the base of the skull and project into the +naso-pharynx--the blood vessels are dilated into sinuses and have no +proper sheaths; they therefore tend to remain open when divided, and to +bleed excessively. Transition forms between soft fibroma and sarcoma are +met with, so that in operating for their removal it is safer to take +away the capsule along with the tumour, and the patient should be kept +under observation in view of the risk of recurrence. + +The skin--especially the skin of the buttock--is one of the favourite +seats of fibroma, and it may occur in a multiple form. It is met with +also in the subcutaneous and intermuscular cellular tissue, and in the +abdominal wall, where it sometimes attains considerable dimensions. +Various forms of fibroma are met with in the mamma and are described +with diseases of that organ. The fibrous overgrowths in the skin, known +as _keloid_ and _molluscum fibrosum_, and those met with in the _sheaths +of nerves_, are described elsewhere. Fibroid tumours of the uterus are +described with myoma. + +_Diffuse fibroma_ or _Fibromatosis_, analogous to lipomatosis, is met +with in the connective tissue of the skin and sheaths of nerves, and +constitutes one form of neuro-fibromatosis; a similar change is also met +with in the stomach and colon. + +#Myxoma.#--A myxoma is composed of tissue of a soft gelatinous, +semifluid consistence. The pure myxoma is extremely rare, and +clinically resembles the lipoma. Myxomatous tissue is, however, +frequently found in other connective-tissue tumours as a result of +degeneration, for example, in cartilaginous tumours and in sarcomas. +Myxomatous tissue is also a prominent constituent of the "innocent +parotid tumour." Mucous polypus of the nose, which is often described as +a myxoma, is merely a pendulous process of oedematous mucous membrane. + +[Illustration: FIG. 53.--Myeloma of Shaft of Humerus, causing +pathological fracture. (Mr. J. W. Struthers' case.) + +(The unusual site of the tumour is to be noted.)] + +#Myeloma.#--A myeloma is composed of large multinuclear giant cells +surrounded by round and spindle cells. The cut surface of the tumour +presents a deep red or maroon colour. While occasionally met with in +tendon sheaths and bursae, and is then of an orange-yellow colour, the +myeloma occurs most frequently in the cancellous tissue at the ends of +the long bones, its favourite site being the upper end of the tibia. +Although formerly classified as a sarcoma, it is the exception for it to +present malignant features, and it can usually be extirpated by local +measures without fear of recurrence. The diagnosis, X-ray appearances, +and the method of removal are considered with the diseases of bone. +Sometimes the myeloma is met with in multiple form in the skeleton, in +association with an unusual form of protein in the urine (Bence Jones). + +#Myoma.#--A myoma is composed of non-striped muscle fibres. A pure myoma +is very rare, and is met with in organs possessed of non-striped muscle, +such as the stomach, intestine, urinary bladder, and prostate. In the +uterus, which is the most common situation, these tumours contain a +considerable admixture of fibrous tissue, and are known as _fibroids_ or +_fibro-myomas_. They present on section a fasciculated appearance, which +may resemble that of a section of balls of cotton (Fig. 54). They are +encapsulated and vascular, frequently attain a large size, and may be +single or multiple. While they may occasion neither inconvenience nor +suffering, they frequently give rise to profuse haemorrhage from the +uterus, and may cause serious symptoms by pressing injuriously on the +ureters or the intestine, or by complicating pregnancy and parturition. + +The #Rhabdomyoma# is an extremely rare form of tumour, met with in the +kidney, uterus, and testicle. It contains striped muscle fibres, and is +supposed to originate from a residue of muscular tissue which has become +sequestrated during development. + +[Illustration: FIG. 54.--Fibro-myoma of Uterus. + +(Anatomical Museum, University of Edinburgh.)] + +#Glioma.#--A glioma is a tumour composed of neuroglia. It is met with +exclusively in the central nervous system, retina, and optic nerve. It +is a slowly growing, soft, ill-defined tumour, which displaces the +adjacent nerve centres and nerve tracts, and is liable to become the +seat of haemorrhage and thus to give rise to pressure symptoms resembling +apoplexy. The glioma of the retina tends to grow into the vitreous +humour and to perforate the globe. It is usually of the nature of a +glio-sarcoma and is highly malignant. + +#Endotheliomas# take origin from the endothelium of lymph vessels and +blood vessels, and serous cavities. They show great variation in type, +partly because of the number of different kinds of endothelium from +which they are derived, and partly because the new connective tissue +which is formed is liable to undergo transformation into other tissues. +They may be soft or hard, solid or cystic, diffuse or circumscribed; +they grow very slowly, and are almost always innocent, although +recurrence has been occasionally observed. Cases of multiple +endotheliomata of the skin have recently been described by Wise. + +_Angioma_, _lymphangioma_, and _neuroma_ are described with the disease +of the individual tissues. + + +MALIGNANT CONNECTIVE-TISSUE TUMOURS--SARCOMA + +The term sarcoma is applied to any connective-tissue tumour which +exhibits malignant characters. The essential structural feature is the +predominance of the cellular elements over the intercellular substance +or stroma, in which respect a sarcoma resembles the connective tissue of +the embryo. The typical sarcoma consists chiefly of immature or +embryonic connective tissue. It most frequently originates from fascia, +intermuscular connective tissue, periosteum, bone-marrow, and skin, and +forms a rounded or nodulated tumour which appears to be encapsulated, +but the capsule merely consists of the condensed surrounding tissues, +and usually contains sarcomatous elements. The consistence of the tumour +depends on the nature and amount of the stroma, and on the presence of +degenerative changes. The softer medullary forms are composed almost +exclusively of cells; while the harder forms--such as the fibro-, +chondro-, and osteo-sarcoma--are provided with an abundant stroma and +are relatively poor in cells. Degenerative changes may produce areas of +softening or liquefaction which result in the formation of cystic +cavities in the interior of the tumour. The colour depends on the amount +of blood in the tumour, and on the presence of the products of +degeneration. + +The blood vessels are usually represented by mere chinks or spaces +between the cells. This peculiarity accounts for the facility with which +haemorrhage takes place into the substance of the tumour, the persistence +of the bleeding when it is incised or ulcerates through the skin, and +the readiness with which the sarcomatous cells are carried off and +infect distant parts through the blood-stream. Sarcomas are devoid of +lymphatics, and unless originating in lymphatic structures--for example, +in the tonsil--they rarely infect the lymph glands. Minute portions of +the tumour grow into the small veins, and, becoming detached, are +transported by the blood-current to distant organs, where they are +arrested in the capillaries and give rise to secondary growths. These +are most frequently situated in the lungs, except when the primary +growth lies within the territory of the portal circulation, in which +case they occur in the liver. The secondary growths closely resemble the +parent tumour. Sarcoma may invade an adjacent vein on such a scale that +if the invading portion becomes detached it may constitute a dangerous +embolus. This may be observed in sarcoma of the kidney, the growth +taking place along the renal vein until it projects into the vena cava. + +[Illustration: FIG. 55.--Recurrent Sarcoma of Sciatic Nerve in a woman +aet. 27. Recurrence twenty months after removal of primary growth.] + +In its growth, a sarcoma compresses and destroys neighbouring parts, +surrounds vessels and nerves, and may lead to destruction of the skin, +either by invading it, or more commonly by causing sloughing from +pressure. Inflammatory and suppurative changes may take place as a +result of pyogenic infection following upon sloughing of the overlying +skin or upon an exploratory incision. Once the skin is broken the tumour +fungates through the opening. Sarcomas vary in malignancy, especially as +regards rapidity of growth and capacity for dissemination. Certain of +them, such as the so-called "recurrent fibroid of Paget," grow +comparatively slowly, and are only malignant in the sense that they tend +to recur locally after removal; others--especially the more cellular +ones--grow with extreme rapidity, and are early disseminated throughout +the body, resembling in these respects the most malignant forms of +cancer. They are usually solitary in the first instance, although +primary multiple growths are occasionally met with in the skin and in +the bones. + +Many varieties of sarcoma are recognised, according to its structural +peculiarities. Thus, in virtue of the size and character of the cells, +we have the _small round-celled_ and the _large round-celled_ sarcoma, +the _small_ and the _large spindle-celled_, the _giant-celled_ and the +_mixed-celled_ sarcoma. The _lympho-sarcoma_ presents a structure +similar to that of lymph-follicular tissue, and the _alveolar sarcoma_ +an arrangement of cells in alveoli resembling that seen in cancers. When +there is a considerable amount of intercellular fibrous tissue, the +tumour is called a _fibro-sarcoma_. + +[Illustration: FIG. 56.--Fungating Sarcoma of Arm. + +(Dr. J. M'Watt's case.)] + +The term _lymphangio-sarcoma_ is applied when the cells of the tumour +are derived from the endothelium of lymph spaces and vessels. The +_angio-sarcomas_ are those in which blood vessels form a prominent +element in the structure of the tumour. They are sometimes derived from +innocent angiomas, and they may be so vascular as to pulsate and on +auscultation yield a blowing murmur like an aneurysm. The +_glio-sarcoma_, _myxo-sarcoma_, _chondro-sarcoma_, and _myo-sarcoma_ are +mixed forms which usually develop in pre-existing innocent tumours. The +_osteo-sarcoma_ is characterised by the formation in the tumour of bone, +the medullary spaces being occupied by sarcomatous cells in place of +marrow. The _osteoid sarcoma_ is characterised by the formation of a +tissue resembling bone but deficient in lime salts, and the _petrifying +sarcoma_ by the formation of calcified areas in the stroma. These +varieties, although met with chiefly in the bones, may occur in soft +tissues such as muscle, and in such organs as the mamma. The pigmented +varieties include the _chloroma_, which is of a light-green colour, and +the _melanotic sarcoma_, which is brown or black. The _psammoma_ is a +sarcoma containing a material resembling sand; it is chiefly met with in +the membranes of the brain. The _chordoma_ is a rare form of tumour +originating from the remains of the notochord in the region of the +spheno-occipital synchondrosis or in the sacro-coccygeal region. + +_Diagnosis of Sarcoma._--A sarcoma is to be differentiated from an +inflammatory swelling such as results from tubercle, actinomycosis, or +syphilis, from an innocent tumour, and from a cancer. The points on +which the diagnosis is founded are discussed with the different tissues +and organs. + +_Treatment._--The removal of the tumour by operation is the most +reliable method of treatment; in order to be successful it must be +undertaken before dissemination has taken place, and a considerable area +of healthy tissue beyond the apparent margin of the growth must be +removed, and in tumours near the surface of the body, the overlying skin +also. + +In order to prevent recurrence, a tube of _radium_, to which a silk +thread is attached, is inserted into the space from which the tumour was +removed; the thread is brought out at the drain-opening, and at the end +of a week or ten days the tube of radium is removed by pulling on the +thread. Radium causes a reaction in the tissues attended with exudation +from the vessels, for the escape of which provision must be made. If +radium is not available, the affected area is repeatedly exposed to the +action of the _X-rays_ as soon as the wound has healed. The employment +of these measures has diminished to a remarkable degree the recurrence +of sarcoma after operation. + +It will readily be understood that the less thoroughly or radically the +growth has been removed, the more do we depend upon radium or the X-rays +for bringing about a permanent cure, and that in advanced cases of +sarcoma and in cases in which, on account of their anatomical situation, +removal by operation is necessarily incomplete, the prospect of cure is +still more dependent on the use of radium or of the X-rays. Finally, +there are cases in which removal by operation is impossible, the +so-called _inoperable sarcoma_; a tube of radium, to which a silk thread +is attached, is inserted into the substance of the tumour, either +through an opening made by a large trocar, or, when necessary, by open +dissection. A second tube of radium is placed upon the skin over the +tumour and is secured there by a stitch or by a strip of plaster, thus +securing a cross-fire action of the radium rays, both from within and +without, as this is found to be much more efficacious in destroying or +inhibiting the cellular elements of the growth. The tubes of radium are +left _in situ_ for from eight to fourteen days, according to the power +of the radium employed, but are moved about every second day or so in +order that every part of the tumour may be efficiently radiated. If the +tumour shrinks in size after the use of radium and becomes operable, it +should be removed before time is given it to resume its growth. It will +depend upon the subsequent course of the disease, whether or not a +second, or it may be even a third, application of radium will be +required. + +Where neither radium nor X-rays is available or applicable, recourse may +be had to the injection of Coley's fluid, a preparation containing the +mixed toxins of the streptococcus of erysipelas and the bacillus +prodigiosus; or of selenium. + + +EPITHELIAL TUMOURS + +An excessive and erratic growth of epithelium is the essential and +distinguishing feature of these tumours. The innocent forms are the +papilloma and the adenoma; the malignant, the carcinoma or cancer. + +#Papilloma.#--A papilloma is a tumour which projects from a cutaneous or +mucous surface, and consists of a central axis of vascular fibrous +tissue with a covering of epithelium resembling that of the surface from +which the tumour grows. In the papillomas of the skin--commonly known as +_warts_--the covering consists of epidermis; in those growing from +mucous surfaces it consists of the epithelium covering the mucous +membrane. When the surface epithelium projects as filiform processes, +the tumour is called a _villous papilloma_, the best-known example of +which is met with in the urinary bladder. Papillomatous growths are +also met with in the larynx, in the ducts of the breast, and in the +interior of certain cystic tumours of the breast and of the ovary. +Although papillomas are primarily innocent, they may become the +starting-point of cancer, especially in persons past middle life and if +the papilloma has been subjected to irritation and has ulcerated. The +clinical features and treatment of the various forms of papilloma are +considered with the individual tissues and organs. + +#Adenoma.#--An adenoma is a tumour constructed on the type of, and +growing in connection with, a secreting gland. In the substance of such +glands as the mamma, parotid, thyreoid, and prostate, adenomas are met +with as encapsulated tumours. When they originate from the glands of the +skin or of a mucous membrane, they tend to project from the surface, and +form pedunculated tumours or polypi. + +Adenomas may be single or multiple, and they vary greatly in size. The +tumour is seldom composed entirely of gland tissue; it usually contains +a considerable proportion of fibrous tissue, and is then called a +_fibro-adenoma_. When it contains myxomatous tissue it is called a +_myxo-adenoma_, and when the gland spaces of the tumour become distended +with accumulated secretion, a _cystic adenoma_, the best examples of +which are met with in the mamma and ovary. A characteristic feature of +the cystic variety is the tendency the tumour tissue exhibits to project +into the interior of the cysts, constituting what are known as +_intracystic growths_. They are essentially innocent, but intracystic +growths, especially in the mamma of women over fifty, should be regarded +with suspicion and therefore should be removed on radical lines. +Transition forms between adenoma and carcinoma are also met with in the +rectum and large intestine, and these should be treated on the same +lines as cancer. + + +CARCINOMA OR CANCER + +A cancer is a malignant tumour which originates in epithelium. The +cancer cells are derived by proliferation from already existing +epithelium, and they invade the sub-epithelial connective tissue in the +form of simple or branching columns. These columns are enclosed in +spaces--termed alveoli--which are probably dilated lymph spaces, and +which communicate freely with the lymph vessels. The cells composing the +columns and filling the alveoli vary with the character of the +epithelium in which the cancer originates. The malignancy of cancer +depends on the tendency which the epithelium has of invading the tissues +in its neighbourhood, and on the capacity of the cells, when +transported elsewhere by the lymph or blood-stream, of giving rise to +secondary growths. + +Cancer may arise on any surface covered by epithelium or in any of the +secreting glands of the body, but it is much more common in some +situations than in others. It is frequently met with, for example, in +the skin, in the stomach and large intestine, in the breast, the uterus, +and the external genitals; less frequently in the gall-bladder, larynx, +thyreoid, prostate, and urinary bladder. + +Tissues appear to be most liable to cancer when, having attained +maturity, they enter upon the phase of decadence or involution, and this +phase is reached by different tissues at different periods. It is not so +much, therefore, the age of the person in whom it occurs, as the age of +the tissue in which it arises, that determines the maximum incidence of +cancer. Cancer of the stomach appears and attains a maximum frequency +earlier than cancer of the skin; cancer of the uterus and mamma is more +frequent towards the decline of reproductive activity than in the later +years of life; rectal cancer is not infrequently met with during the +second and third decades. There is evidence that the irritation caused +by alcohol and tobacco plays a part in the causation of cancer, in the +fact that a large proportion of those who become the subjects of cancer +of the mouth are excessive drinkers and smokers. + +A cancer may appear as a papillary growth on a mucous or a skin surface, +as a nodule in the substance of an organ, or as a diffuse thickening of +a tubular organ such as the stomach or intestine. The absence of +definition in cancerous tumours explains the difficulty of completely +removing them by surgical measures, and has led to the practice of +complete extirpation of cancerous organs wherever this is possible. The +boundaries of the affected organ, moreover, are frequently transgressed +by the disease, and the epithelial infiltration implicates the +surrounding parts. In cancer of the breast, for example, the disease +often extends to the adjacent skin, fat, and muscle; in cancer of the +lip or tongue, to the mandible; in cancer of the uterus or intestine, to +the investing peritoneum. + +In addition to its tendency to infiltrate adjacent tissues and organs, +cancer is also liable to give rise to _secondary growths_. These are +most often met with in the nearest lymph glands; those in the neck, for +example, becoming infected from cancer of the lip, tongue, or throat; +those in the axilla, from cancer of the breast; those along the +curvatures of the stomach, from cancer of the pylorus; and those in the +groin, from cancer of the external genitals. In lymph vessels the cancer +cells may merely accumulate so as to fill the lumen and form indurated +cords, or they may proliferate and give rise to secondary nodules along +the course of the vessels. When the lymphatic network in the skin is +diffusely infected, the appearance is either that of a multitude of +secondary nodules or of a diffuse thickening, so that the skin comes to +resemble coarse leather. On the wall of the chest this condition is +known as _cancer en cuirasse_. Although the cancer cells constantly +attack the walls of the adjacent veins and spread into their interior at +a comparatively early period, secondary growths due to dissemination by +the blood-stream rarely show themselves clinically until late in the +course of the disease. It is probable that many of the cancer cells +which are carried away in the blood or lymph stream undergo necrosis and +fail to give rise to secondary growths. Secondary growths present a +faithful reproduction of the structure of the primary tumour. Apart from +the lymph glands, the chief seats of secondary growths are the liver, +lungs, serous membranes, and bone marrow. + +It is generally believed that the secondary growths in cancer that +develop at a distance from the primary tumour, those, for example, in +the medullary canal of the femur or in the diploe of the skull occurring +in advanced cases of cancer of the breast, are the result of +dissemination of cancer cells by way of the blood-stream and are to be +regarded as emboli. Sampson Handley disagrees with this view; he +believes that the dissemination is accomplished in a more subtle way, +namely, by the actual growth of cancer cells along the finer vessels of +the lymph plexuses that ramify in the deep fascia, a method of spread +which he calls _permeation_. It is maintained also that permeation +occurs as readily against the lymph stream as with it. He compares the +spread of cancer to that of an invisible annular ringworm. The growing +edge extends in a wider and wider circle, within which a healing process +may occur, so that the area of permeation is a ring, rather than a disc. +Healing occurs by a process of "peri-lymphatic fibrosis," but as the +natural process of healing may fail at isolated points, nodules of +cancer appear, which, although apparently separate from the primary +growth, have developed in continuity with it, peri-lymphatic fibrosis +having destroyed the cancer chain connecting the nodule with the primary +growth. This centrifugal spread of cancer is clearly seen in the +distribution of the subcutaneous secondary nodules so frequently met +with in the late stages of mammary cancer. The area within which the +secondary nodules occur is a circle of continually increasing diameter +with the primary growth in the centre. + +In the rare cases in which the skin of the greater part of the body is +affected, the nodules rarely appear below the level of the deltoid or +the middle third of the thigh, the patient dying before the spread can +reach the distal portions of the limbs. + +Handley argues against the embolic origin of the metastases in the bones +because of the rarity of these in the bones of the distal parts of the +limbs, because of the fact that secondary cancer of the femur nearly +always commences in the upper third of the shaft, which harmonises with +the intimate connection of the deep fascia with the periosteum over the +great trochanter, thus favouring invasion of the bone marrow when +permeation has spread thus far. He claims support for the permeation +theory from the fact that the humerus is rarely involved below the +insertion of the deltoid, and that spontaneous fracture of the femur is +three times more common on the side on which the breast cancer is +situated. + +The tumour tissue may undergo necrosis, and when the overlying skin or +mucous membrane gives way an ulcer is formed. The margins of a +_cancerous ulcer_ (Fig. 57) are made up of tumour tissue which has not +broken down. Usually they are irregular, nodularly thickened or +indurated; sometimes they are raised and crater-like. The floor of the +ulcer is smooth and glazed, or occupied by necrosed tissue, and the +discharge is watery and blood-stained, and as a result of putrefactive +changes may become offensive. Haemorrhage is rarely a prominent feature, +but discharge of blood may constitute a symptom of considerable +diagnostic importance in cancer of internal organs such as the rectum, +the bladder, or the uterus. + +[Illustration: FIG. 57.--Carcinoma of Breast with Cancerous Ulcer.] + +_The Contagiousness of Cancer._--A limited number of cases are on record +in which a cancer appears to have been transferred by contact, as from +the lower to the upper lip, from one labium majus to the other, from the +tongue to the cheek, and from one vocal cord to the other; these being +all examples of cancer involving surfaces which are constantly or +frequently in contact. The transference of cancer from one human being +to another, whether by accident, as in the case of a surgeon wounding +his finger while operating for cancer, or by the deliberate introduction +of a portion of cancerous tumour into the tissues, has never been known +to occur. It is by no means infrequent, however, that when recurrence +takes place after an operation for the removal of cancer, the recurrent +nodules make their appearance in the main scar or in the scars of +stitches in its neighbourhood. In the lower animals the grafting of +cancer only succeeds in animals of the same species; for example, a +cancer taken from a mouse will not grow in the tissues of a rat, but +only in a mouse of the same variety as that from which the graft was +taken. + +While cancer cannot be regarded as either contagious or infectious, it +is important to bear in mind the possibility of infection of a wound +with cancer when operating for the disease. A cancer should not be cut +into unless this is essential for purposes of diagnosis, and the wound +made for exploration should be tightly closed by stitches before the +curative operation is proceeded with; the instruments used for the +exploration must not be used again until they have been boiled. The +greatest care should be taken that a cancer which has softened or broken +down is not opened into during the operation. + +Investigations regarding the cause of cancer have been prosecuted with +great energy during recent years, but as yet without positive result. It +is recognised that there are a number of conditions which favour the +development of cancer, such as prolonged irritation, and a considerable +number of cases have been recorded in which cancer of the skin of the +hands has followed prolonged and repeated exposure to the Rontgen rays. + +_The Alleged Increase of Cancer._--Regarding the alleged increase of +cancer, it may be pointed out that it is impossible to ascertain how +much of the apparent increase is due to more accurate diagnosis and +improved registration. It is probable also that some increase has taken +place in consequence of the increased average duration of life; a larger +proportion of persons now reach the age at which cancer is frequent. + +_The prognosis_ largely depends on the variety of cancer and on its +situation. Certain varieties--such as the atrophic cancer of the breast +which occurs in old people, and some forms of cancer in the rectum--are +so indolent in their progress that they can scarcely be said to shorten +life; while others--such as the softer varieties of mammary cancer +occurring in young women--are among the most malignant of tumours. The +mode in which cancer causes death depends to a large extent upon its +situation. In the gullet, for example, it usually causes death by +starvation; in the larynx or thyreoid, by suffocation; in the intestine, +by obstruction of the bowels; in the uterus, prostate, and bladder, by +haemorrhage or by implication of the ureters and kidneys. Independently +of their situation, however, cancers frequently cause death by giving +rise to a progressive impairment of health known as the _cancerous +cachexia_, a condition which is due to the continued absorption of +poisonous products from the tumour. The patient loses appetite, becomes +emaciated, pale, and feverish, and gradually loses strength until he +dies. In many cases, especially those in which ulceration has occurred, +the addition of pyogenic infection may also be concerned in the failure +of health. + +_Treatment._--Removal by surgical means affords the best prospect of +cure. If carcinomatous disease is to be rooted out, its mode of spread +by means of the lymph vessels must be borne in mind, and as this occurs +at an early stage, and is not evident on examination, a wide area must +be included in the operation. The organ from which the original growth +springs should, if practicable, be altogether removed, because its lymph +vessels generally communicate freely with each other, and secondary +deposits have probably already taken place in various parts of it. In +addition, the nearest chain of lymph glands must also be removed, even +though they may not be noticeably enlarged, and in some cases--in cancer +of the breast, for example--the intervening lymph vessels should be +removed at the same time. + +The treatment of cancer by other than operative methods has received a +great deal of attention within recent years, and many agents have been +put to the test, _e.g._ colloidal suspensions of selenium, but without +any positive results. Most benefit has resulted from the use of radium +and of the X-rays, and one or other should be employed as a routine +measure after every operation for cancer. + +It has been demonstrated that cancer cells are more sensitive to radium +and to the Rontgen rays than the normal cells of the body, and are more +easily killed. The effect varies a good deal with the nature and seat of +the tumour. In rodent cancers of the skin, for example, both radium and +X-ray treatment are very successful, and are to be preferred to +operation because they yield a better cosmetic result. While small +epitheliomas of the skin may be cured by means of the rays, they are not +so amenable as rodent cancers. + +Cancers of mucous membranes are less amenable to ray treatment because +they are less circumscribed and are difficult of access. In cancers +under the skin, the Rontgen rays are less efficient; if radium is +employed, the tube containing it should be inserted into the substance +of the tumour after the method described in connection with sarcoma--and +another tube should be placed on the overlying skin. + +In the employment of X-rays and of radium in the treatment of cancer, +experience is required, not only to obtain the maximum effect of the +rays, but to avoid damage to the adjacent and overlying tissues. + +Ray treatment is not to be looked upon as a rival but as a powerful +supplement to the operative treatment of cancer. + + +VARIETIES OF CANCER + +The varieties of cancer are distinguished according to the character and +arrangement of the epithelial cells. + +The _squamous epithelial cancer_ or _epithelioma_ originates from a +surface covered by squamous epithelium, such as the skin, or the mucous +membrane of the mouth, gullet, or larynx. The cancer cells retain the +characters of squamous epithelium, and, being confined within the lymph +spaces of the sub-epithelial connective tissue, become compressed and +undergo a horny change. This results in the formation of concentrically +laminated masses known as cell nests. + +The clinical features are those of a slowly growing indurated tumour, +which nearly always ulcerates; there is a characteristic induration of +the edges and floor of the ulcer, and its surface is often covered with +warty or cauliflower-like outgrowths (Fig. 58). The infection of the +lymph glands is early and constant, and constitutes the most dangerous +feature of the disease; the secondary growths in the glands exhibit the +characteristic induration, and may themselves break down and lead to the +formation of ulcers. + +[Illustration: FIG. 58.--Epithelioma of Lip.] + +Epithelioma frequently originates in long-standing ulcers or sinuses, +and in scars, and probably results from the displacement and +sequestration of epithelial cells during the process of cicatrisation. + +The _columnar epithelial cancer_ or _columnar epithelioma_ originates in +mucous membranes covered with columnar epithelium, and is chiefly met +with in the stomach and intestine. As it resembles an adenoma in +structure it is sometimes described as a _malignant adenoma_. Its +malignancy is shown by the proliferating epithelium invading the other +coats of the stomach or intestine, and by the development of secondary +growths. + +_Glandular carcinoma_ originates in organs such as the breast, and in +the glands of mucous membranes and skin. The epithelial cells are not +arranged on any definite plan, but are closely packed in irregularly +shaped alveoli. If the alveoli are large and the intervening stroma is +scanty and delicate, the tumour is soft and brain-like, and is described +as a _medullary_ or _encephaloid cancer_. If the alveoli are small and +the intervening stroma is abundant and composed of dense fibrous tissue, +the tumour is hard, and is known as a _scirrhous cancer_--a form which +is most frequently met with in the breast. If the cells undergo +degeneration and absorption and the stroma contracts, the tumour becomes +still harder, and tends to shrink and to draw in the surrounding parts, +leading, in the breast, to retraction of the nipple and overlying skin, +and in the stomach and colon to narrowing of the lumen. When the cells +of the tumour undergo colloid degeneration, a _colloid cancer_ results; +if the degeneration is complete, as may occur in the breast, the +malignancy is thereby greatly diminished; if only partial, as is more +common in rectal cancer, the malignancy is not appreciably affected. +Melanin pigment is formed in relation to the cells and stroma of certain +epithelial tumours, giving rise to _melanotic cancer_, one of the most +malignant of all new growths. Cyst-like spaces may form in the tumour by +the accumulation of the secretion of the epithelial cells, or as a +result of their degeneration--_cystic carcinoma_. This is met with +chiefly in the breast and ovary, and the tumour resembles the cystic +adenoma, but it tends to infect its surroundings and gives rise to +secondary growths. + +_Rodent cancer_ originates in the glands of the skin, and presents a +special tendency to break down and ulcerate on the surface (Figs. 102 +and 103). It almost never infects the lymph glands. + + +DERMOIDS + +A dermoid is a tumour containing skin or mucous membrane, occurring in a +situation where these tissues are not met under normal conditions. + +The _skin dermoid_, or _derma-cyst_ as it has been called by Askanazy, +arises from a portion of epiblast, which has become sequestrated during +the process of coalescence of two cutaneous surfaces in development. +This form is therefore most frequently met with on the face and neck in +the situations which correspond to the various clefts and fissures of +the embryo. It occurs also on the trunk in situations where the lateral +halves of the body coalesce during development. Such a dermoid usually +takes the form of a globular cyst, the wall of which consists of skin, +and the contents of turbid fluid containing desquamated epithelium, fat +droplets, cholestrol crystals, and detached hairs. Delicate hairs may +also be found projecting from the epithelial lining of the cyst. + +Faulty coalescence of the cutaneous covering of the back occurs most +frequently over the lower sacral vertebrae, giving rise to small +congenital recesses, known as post-anal dimples and coccygeal sinuses. +These recesses are lined with skin, which is furnished with hairs, +sebaceous and sweat glands. If the external orifice becomes occluded, +there results a dermoid cyst. + +_Tubulo-dermoids_ arise from embryonic ducts and passages that are +normally obliterated at birth, for example, _lingual dermoids_ develop +in relation to the thyreo-glossal duct; _rectal and post-rectal_ +dermoids to the post-anal gut; and _branchial dermoids_ in relation to +the branchial clefts. Tubulo-dermoids present the same structure as skin +dermoids, save that mucous membrane takes the place of skin in the wall +of the cyst, and the contents consist of the pent-up secretion of mucous +glands. + +_Clinical Features._--Although dermoids are of congenital origin, they +are rarely evident at birth, and may not give rise to visible tumours +until puberty, when the skin and its appendages become more active, or +not till adult life. Superficial dermoids, such as those met with at the +outer angle of the orbit, form rounded, definitely limited tumours over +which the skin is freely movable. They are usually adherent to the +deeper parts, and when situated over the skull may be lodged in a +depression or actual gap in the bone. Sometimes the cyst becomes +infected and suppurates, and finally ruptures on the surface. This may +lead to a natural cure, or a persistent sinus may form. Dermoids more +deeply placed, such as those within the thorax, or those situated +between the rectum and sacrum, give rise to difficulty in diagnosis, +even with the help of the X-rays, and their nature is seldom recognised +until the escape of the contents--particularly hairs--supplies the clue. +The literature of dermoid cysts is full of accounts of puzzling tumours +met with in all sorts of situations. + +The treatment is to remove the cyst. When it is impossible to remove the +whole of the lining membrane by dissection, the portion that is left +should be destroyed with the cautery. + +_Ovarian Dermoids._--Dermoids are not uncommon in the ovary (Fig. 59). +They usually take the form of unilocular or multilocular cysts, the +wall of which contains skin, mucous membrane, hair follicles, sebaceous, +sweat, and mucous glands, nails, teeth, nipples, and mammary glands. The +cavity of the cyst usually contains a pultaceous mixture of shed +epithelium, fluid fat, and hair. If the cyst ruptures, the epithelial +elements are diffused over the peritoneum, and may give rise to +secondary dermoids. + +[Illustration: FIG. 59.--Dermoid Cyst of Ovary showing Teeth in its +interior.] + +The ovarian dermoid appears clinically as an abdominal or pelvic tumour +provided with a pedicle; if the pedicle becomes twisted, the tumour +undergoes strangulation, an event which is attended with urgent +symptoms, not unlike those of strangulated hernia. + +The treatment consists in removing the tumour by laparotomy. + +#Teratoma.#--A teratoma is believed to result from partial dichotomy or +cleavage of the trunk axis of the embryo, and is found exclusively in +connection with the skull and vertebral column. It may take the form of +a monstrosity such as conjoined twins or a parasitic foetus, but more +commonly it is met with as an irregularly shaped tumour, usually growing +from the sacrum. On dissection, such a tumour is found to contain a +curious mixture of tissues--bones, skin, and portions of viscera, such +as the intestine or liver. The question of the removal of the tumour +requires to be considered in relation to the conditions present in each +individual case. + + +CYSTS[3] + +[3] Cysts which form in relation to new-growths have been considered +with tumours. + +Cysts are rounded sacs, the wall being composed of fibrous tissue lined +by epithelium or endothelium; the contents are fluid or semi-solid, and +vary in character according to the tissue in which the cyst has +originated. + +_Retention and Exudation Cysts._--_Retention cysts_ develop when the +duct of a secreting gland is partly obstructed; the secretion +accumulates, and the gland and its duct become distended into a cyst. +They are met with in the mamma and in the salivary glands. Sebaceous +cysts or wens are described with diseases of the skin. _Exudation cysts_ +arise from the distension of cavities which are not provided with +excretory ducts, such as those in the thyreoid. + +_Implantation cysts_ are caused by the accidental transference of +portions of the epidermis into the underlying connective tissue, as may +occur in wounds by needles, awls, forks, or thorns. The implanted +epidermis proliferates and forms a small cyst. They are met with chiefly +on the palmar aspect of the fingers, and vary in size from a split pea +to a cherry. The treatment consists in removing them by dissection. + +_Parasitic cysts_ are produced by the growth within the tissues of +cyst-forming parasites, the best known being the taenia echinococcus, +which gives rise to the _hydatid cyst_. The liver is by far the most +common site of hydatid cysts in the human subject. + +With regard to the further life-history of hydatids, the living elements +of the cyst may die and degenerate, or the cyst may increase in size +until it ruptures. As a result of pyogenic infection the cyst may be +converted into an abscess. + +The _clinical features_ of hydatids vary so much with their situation +and size, that they are best discussed with the individual organs. In +general it may be said that there is a slow formation of a globular, +elastic, fluctuating, painless swelling. Fluctuation is detected when +the cyst approaches the surface, and it is then also that percussion +may elicit the "hydatid thrill" or fremitus. This thrill is not often +obtainable, and in any case is not pathognomonic of hydatids, as it may +be elicited in ascites and in other abdominal cysts. Pressure of the +cyst upon adjacent structures, and the occurrence of suppuration, are +attended with characteristic clinical features. + +The _diagnosis_ of hydatids will be considered with the individual +organs. The disease is more common in certain parts of Australia and in +Shetland and Iceland than in countries where the association of dogs in +the domestic life of the inhabitants is less intimate. Pfeiler, who has +worked at the _serum diagnosis of hydatid disease_, regards the +complement deviation method as the most reliable; he believes that a +positive reaction may almost be regarded as absolutely diagnostic of an +echinococcal lesion. + +The _treatment_ is to excise the cyst completely, or to inject into it a +1 per cent. solution of formalin. In operating upon hydatids the utmost +care must be taken to avoid leakage of the contents of the cyst, as +these may readily disseminate the infection. + +A _blood cyst_ or haematoma results from the encapsulation of +extravasated blood in the tissues, from haemorrhage taking place into a +preformed cyst, or from the saccular pouching of a varicose vein. + +A _lymph cyst_ usually results from a contusion in which the skin is +forcibly displaced from the subjacent tissues, and lymph vessels are +thereby torn across. The cyst is usually situated between the skin and +fascia, and contains clear or blood-stained serum. At first it is lax +and fluctuates readily, later it becomes larger and more tense. The +treatment consists in drawing off the contents through a hollow needle +and applying firm pressure. Apart from injury, lymph cysts are met with +as the result of the distension of lymph spaces and vessels +(_lymphangiectasis_); and in lymphangiomas, of which the best-known +example is the cystic hygroma or hydrocele of the neck. + + +GANGLION + +This term is applied to a cyst filled with a clear colourless jelly or +colloid material, met with in the vicinity of a joint or tendon sheath. + +The commonest variety--the _carpal ganglion_--popularly known as a +sprained sinew--is met with as a smooth, rounded, or oval swelling on +the dorsal aspect of the carpus, usually towards its radial side (Fig. 60). +It is situated over one of the intercarpal or other joints in this +region, and may be connected with one or other of the extensor tendons. +The skin and fascia are movable over the cyst. The cyst varies in size +from a pea to a pigeon's egg, and usually attains its maximum size +within a few months and then remains stationary. It becomes tense and +prominent when the hand is flexed towards the palm. Its appearance is +usually ascribed to some strain of the wrist--for example, in girls +learning gymnastics. It may cause no symptoms or it may interfere with +the use of the hand, especially in grasping movements and when the hand +is dorsiflexed. In girls it may give rise to pain which shoots up the +arm. Ganglia are also met with on the dorsum of the metacarpus and on +the palmar aspect of the wrist. + +[Illustration: FIG. 60.--Carpal Ganglion in a woman aet. 25.] + +The _tarsal ganglion_ is situated on the dorsum of the foot over one or +other of the intertarsal joints. It is usually smaller, flatter, and +more tense than that met with over the wrist, so that it is sometimes +mistaken for a bony tumour. It rarely causes symptoms, unless so +situated as to be pressed upon by the boot. + +_Ganglia in the region of the knee_ are usually situated over the +interval between the femur and tibia, most often on the lateral aspect +of the joint in front of the tendon of the biceps (Fig. 61). The +swelling, which may attain the size of half a walnut, is tense and hard +when the knee is extended, and becomes softer and more prominent when it +is flexed. They are met with in young adults who follow laborious +occupations or who indulge in athletics, and they cause stiffness, +discomfort, and impairment of the use of the limb. A ganglion is +sometimes met with on the median aspect of the head of the metatarsal +bone of the great toe and may be the cause of considerable suffering; it +is indistinguishable from the thickened and enlarged bursa so commonly +present in this situation in the condition known as bunion. + +[Illustration: FIG. 61.--Ganglion on lateral aspect of Knee in a young +woman.] + +Ganglionic cysts are met with in other situations than those mentioned, +but they are so rare as not to require separate description. + +Ganglia are to be diagnosed by their situation and physical characters; +enlarged bursae, synovial cysts, and new-growths are the swellings most +likely to be mistaken for them. The diagnosis is sometimes only cleared +up by withdrawing the clear, jelly-like contents through a hollow +needle. + +_Pathological Anatomy._--The wall of the cyst is composed of fibrous +tissue closely adherent to or fused with the surrounding tissues, so +that it cannot be shelled out. There is no endothelial lining, and the +fibrous tissue of the wall is in immediate contact with the colloid +material in the interior, which appears to be derived by a process of +degeneration from the surrounding connective tissue. In the region of +the knee the ganglion is usually multilocular, and consists of a +meshwork of fibrous tissue, the meshes of which are occupied by colloid +material. + +It is often stated that a ganglion originates from a hernial protrusion +of the synovial membrane of a joint or tendon sheath. We have not been +able to demonstrate any communication between the cavity of the cyst +and that of an adjacent tendon sheath or joint. It is possible, however, +that the cyst may originate from a minute portion of synovial membrane +being protruded and strangulated so that it becomes disconnected from +that to which it originally belonged; it may then degenerate and give +rise to colloid material, which accumulates and forms a cyst. Ledderhose +and others regard ganglia as entirely new formations in the +peri-articular tissues, resulting from colloid degeneration of the +fibrous tissue of the capsular ligament, occurring at first in numerous +small areas which later coalesce. Ganglia are probably, therefore, of +the nature of degeneration cysts arising in the capsule of joints, in +tendons, and in their sheaths. + +_Treatment._--A ganglion can usually be got rid of by a modification of +the old-fashioned seton. The skin and cyst wall are transfixed by a +stout needle carrying a double thread of silkworm gut; some of the +colourless jelly escapes from the punctures; the ends of the thread are +tied and cut short, and a dressing is applied. A week later the threads +are removed and the minute punctures are sealed with collodion. The +action of the threads is to convert the cyst wall into granulation +tissue, which undergoes the usual conversion into scar tissue. If the +cyst re-forms, it should be removed by open dissection under local +anaesthesia. Puncture with a tenotomy knife and scraping the interior, +and the injection of irritants, are alternative, but less satisfactory, +methods of treatment. + +_Ganglia_ in the substance of _tendons_ are rare. The diagnosis rests on +the observation that the small tumour is cystic, and that it follows the +movements of the tendon. The cyst is at first multiple, but the +partitions disappear, and the spaces are thrown into one. The tendon is +so weakened that it readily ruptures. The best treatment is to resect +the affected segment of tendon. + +The so-called "compound palmar ganglion" is a tuberculous disease of the +tendon sheaths, and is described with diseases of tendon sheaths. + + + + +CHAPTER XI + +INJURIES + + +CONTUSIONS--WOUNDS: _Varieties_--WOUNDS BY FIREARMS AND + EXPLOSIVES: _Pistol-shot wounds_; _Wounds by sporting guns_; + _Wounds by rifle bullets_; _Wounds received in warfare_; _Shell + wounds_. _Embedded foreign bodies_--BURNS AND + SCALDS--INJURIES PRODUCED BY ELECTRICITY: _X-ray and + radium_; _Electrical burns_; _Lightning stroke_. + + +CONTUSIONS + +A contusion or bruise is a laceration of the subcutaneous soft tissues, +without solution of continuity of the skin. When the integument gives +way at the same time, a _contused-wound_ results. Bruising occurs when +force is applied to a part by means of a blunt object, whether as a +direct blow, a crush, or a grazing form of violence. If the force acts +at right angles to the part, it tends to produce localised lesions which +extend deeply; while, if it acts obliquely, it gives rise to lesions +which are more diffuse, but comparatively superficial. It is well to +remember that those who suffer from scurvy, or haemophilia (bleeders), +and fat and anaemic females, are liable to be bruised by comparatively +trivial injuries. + +_Clinical Features._--The less severe forms of contusion are associated +with _ecchymosis_, numerous minute and discrete punctate haemorrhages +being scattered through the superficial layers of the skin, which is +slightly oedematous. The effused blood is soon reabsorbed. + +The more severe forms are attended with _extravasation_, the +extravasated blood being widely diffused through the cellular tissue of +the part, especially where this is loose and lax, as in the region of +the orbit, the scrotum and perineum, and on the chest wall. A blue or +bluish-black discoloration occurs in patches, varying in size and depth +with the degree of force which produced the injury, and in shape with +the instrument employed. It is most intense in regions where the skin is +naturally thin and pigmented. In parts where the extravasated blood is +only separated from the oxygen of the air by a thin layer of epidermis +or by a mucous membrane, it retains its bright arterial colour. These +points are often well illustrated in cases of black eye, where the blood +effused under the conjunctiva is bright red, while that in the eyelids +is almost black. In severe contusions associated with great tension of +the skin--for example, over the front of the tibia or around the +ankle--blisters often form on the surface and constitute a possible +avenue of infection. When deeply situated, the blood tends to spread +along the lines of least resistance, partly under the influence of +gravity, passing under fasciae, between muscles, along the sheaths of +vessels, or in connective-tissue spaces, so that it may only reach the +surface after some time, and at a considerable distance from the seat of +injury. This fact is sometimes of importance in diagnosis, as, for +example, in certain fractures of the base of the skull, where +discoloration appears under the conjunctiva or behind the mastoid +process some days after the accident. + +Blood extravasated deeply in the tissues gives rise to a firm, +resistant, doughy swelling, in which there may be elicited on deep +palpation a peculiar sensation, not unlike the crepitus of fracture. + +It frequently happens that, from the tearing of lymph vessels, serous +fluid is extravasated, and a _lymphatic_ or _serous cyst_ may form. + +In all contusions accompanied by extravasation, there is marked swelling +of the area involved, as well as pain and tenderness. The temperature +may rise to 101 o F., or, in the large extravasations that occur in +bleeders, even higher--a form of aseptic fever. The degree of shock is +variable, but sudden syncope frequently results from severe bruises of +the testicle, abdomen, or head, and occasionally marked nervous +depression follows these injuries. + +Contusion of muscles or nerves may produce partial atrophy and paresis, +as is often seen after injuries in the region of the shoulder. + +In alcoholic or other debilitated patients, suppuration is liable to +ensue in bruised parts, infection taking place from cocci circulating in +the blood, or through the overlying skin. + +_Terminations of Contusions._--The usual termination is a complete +return to the normal, some of the extravasated blood being organised, +but most of it being reabsorbed. During the process characteristic +alterations in the colour of the effused blood take place as a result of +changes in the blood pigment. In from twenty-four to forty-eight hours +the margins of the blue area become of a violet hue, and as time goes on +the discoloured area increases in size, and becomes successively green, +yellow, and lemon-coloured at its margins, the central part being the +last to change. The rate at which this play of colours proceeds is so +variable, and depends on so many circumstances, that no time-limits can +be laid down. During the disintegration of the effused blood the +adjacent lymph glands may become enlarged, and on dissection may be +found to be pigmented. Sometimes the blood persists as a collection of +fluid with a newly formed connective-tissue capsule, constituting a +_haematoma_ or _blood cyst_, more often met with in the scalp than in +other parts. + +The impairment of the blood supply of the skin may lead to the formation +of _blisters_, or to _necrosis_. Death of skin is more liable to occur +in bleeders, and when the slough separates the blood-clot is exposed and +the reparative changes go on extremely slowly. _Suppuration_ may occur +and lead to the formation of an abscess as a result of direct infection +from the skin or through the circulation. + +_Treatment._--If the patient is seen immediately after the accident, +elevation of the part, and firm pressure applied by means of a thick pad +of cotton wool and an elastic bandage, are useful in preventing effusion +of blood. Ice-bags and evaporating lotions are to be used with caution, +as they are liable to lower the vitality of the damaged tissues and lead +to necrosis of the skin. + +When extravasation has already taken place, massage is the most speedy +and efficacious means of dispersing the effused blood. The part should +be massaged several times a day, unless the presence of blebs or +abrasions of the skin prevents this being done. When this is the case, +the use of antiseptic dressings is called for to prevent infection and +to promote healing, after which massage is employed. + +When the tension caused by the extravasated blood threatens the vitality +of the skin, incisions may be made, if asepsis can be assured. The blood +from a haematoma may be withdrawn by an exploring needle, and the +puncture sealed with collodion. Infective complications must be looked +for and dealt with on general principles. + + +WOUNDS + +A wound is a solution in the continuity of the skin or mucous membrane +and of the underlying tissues, caused by violence. + +Three varieties of wounds are described: incised, punctured, and +contused and lacerated. + +#Incised Wounds.#--Typical examples of incised wounds are those made by +the surgeon in the course of an operation, wounds accidentally inflicted +by cutting instruments, and suicidal cut-throat wounds. It should be +borne in mind in connection with medico-legal inquiries, that wounds of +soft parts that closely overlie a bone, such as the skull, the tibia, or +the patella, although, inflicted by a blunt instrument, may have all the +appearances of incised wounds. + +_Clinical Features._--One of the characteristic features of an incised +wound is its tendency to gape. This is evident in long skin wounds, and +especially when the cut runs across the part, or when it extends deeply +enough to divide muscular fibres at right angles to their long axis. The +gaping of a wound, further, is more marked when the underlying tissues +are in a state of tension--as, for example, in inflamed parts. Incised +wounds in the palm of the hand, the sole of the foot, or the scalp, +however, have little tendency to gape, because of the close attachment +of the skin to the underlying fascia. + +Incised wounds, especially in inflamed tissues, tend to bleed profusely; +and when a vessel is only partly divided and is therefore unable to +contract, it continues to bleed longer than when completely cut across. + +The _special risks_ of incised wounds are: (1) division of large blood +vessels, leading to profuse haemorrhage; (2) division of nerve-trunks, +resulting in motor and sensory disturbances; and (3) division of tendons +or muscles, interfering with movement. + +_Treatment._--If haemorrhage is still going on, it must be arrested by +pressure, torsion, or ligature, as the accumulation of blood in a wound +interferes with union. If necessary, the wound should be purified by +washing with saline solution or eusol, and the surrounding skin painted +with iodine, after which the edges are approximated by sutures. The raw +surfaces must be brought into accurate apposition, care being taken that +no inversion of the cutaneous surface takes place. In extensive and deep +wounds, to ensure more complete closure and to prevent subsequent +stretching of the scar, it is advisable to unite the different +structures--muscles, fasciae, and subcutaneous tissue--by separate series +of _buried sutures_ of catgut or other absorbable material. For the +approximation of the skin edges, stitches of horse-hair, fishing-gut, or +fine silk are the most appropriate. These _stitches of coaptation_ may +be interrupted or continuous. In small superficial wounds on exposed +parts, stitch marks may be avoided by approximating the edges with +strips of gauze fixed in position by collodion, or by subcutaneous +sutures of fine catgut. Where the skin is loose, as, for example, in the +neck, on the limbs, or in the scrotum, the use of Michel's clips is +advantageous in so far as these bring the deep surfaces of the skin into +accurate apposition, are introduced with comparatively little pain, and +leave only a slight mark if removed within forty-eight hours. + +When there is any difficulty in bringing the edges of the wound into +apposition, a few interrupted _relaxation stitches_ may be introduced +wide of the margins, to take the strain off the coaptation stitches. +Stout silk, fishing-gut, or silver wire may be employed for this +purpose. When the tension is extreme, Lister's button suture may be +employed. The tension is relieved and death of skin prevented by scoring +it freely with a sharp knife. Relaxation stitches should be removed in +four or five days, and stitches of coaptation in from seven to ten days. +On the face and neck, wounds heal rapidly, and stitches may be removed +in two or three days, thus diminishing the marks they leave. + +_Drainage._--In wounds in which no cavity has been left, and in which +there is no reason to suspect infection, drainage is unnecessary. When, +however, the deeper parts of an extensive wound cannot be brought into +accurate apposition, and especially when there is any prospect of oozing +of blood or serum--as in amputation stumps or after excision of the +breast--drainage is indicated. It is a wise precaution also to insert +drainage tubes into wounds in fat patients when there is the slightest +reason to suspect the presence of infection. Glass or rubber tubes are +the best drains; but where it is desirable to leave little mark, a few +strands of horse-hair, or a small roll of rubber, form a satisfactory +substitute. Except when infection occurs, the drain is removed in from +one to four days and the opening closed with a Michel's clip or a +suture. + +#Punctured Wounds.#--Punctured wounds are produced by narrow, pointed +instruments, and the sharper and smoother the instrument the more does +the resulting injury resemble an incised wound; while from more rounded +and rougher instruments the edges of the wound are more or less contused +or lacerated. The depth of punctured wounds greatly exceeds their width, +and the damage to subcutaneous parts is usually greater than that to the +skin. When the instrument transfixes a part, the edges of the wound of +entrance may be inverted, and those of the exit wound everted. If the +instrument is a rough one, these conditions may be reversed by its +sudden withdrawal. + +Punctured wounds neither gape nor bleed much. Even when a large vessel +is implicated, the bleeding usually takes place into the tissues rather +than externally. + +The _risks_ incident to this class of wounds are: (1) the extreme +difficulty, especially when a dense fascia has been perforated, of +rendering them aseptic, on account of the uncertainty as to their depth, +and of the way in which the surface wound closes on the withdrawal of +the instrument; (2) different forms of aneurysm may result from the +puncture of a large vessel; (3) perforation of a joint, or of a serous +cavity, such as the abdomen, thorax, or skull, materially adds to the +danger. + +_Treatment._--The first indication is to purify the whole extent of the +wound, and to remove any foreign body or blood-clot that may be in it. +It is usually necessary to enlarge the wound, freely dividing injured +fasciae, paring away bruised tissues, and purifying the whole +wound-surface. Any blood vessel that is punctured should be cut across +and tied; and divided muscles, tendons, or nerves must be sutured. After +haemorrhage has been arrested, iodoform and bismuth paste is rubbed into +the raw surface, and the wound closed. If there is any reason to doubt +the asepticity of the wound, it is better treated by the open method, +and a Bier's bandage should be applied. + +#Contused and Lacerated Wounds.#--These may be considered together, as +they so occur in practice. They are produced by crushing, biting, or +tearing forms of violence--such as result from machinery accidents, +firearms, or the bites of animals. In addition to the irregular wound of +the integument, there is always more or less bruising of the parts +beneath and around, and the subcutaneous lesions are much wider than +appears on the surface. + +Wounds of this variety usually gape considerably, especially when there +is much laceration of the skin. It is not uncommon to have considerable +portions of skin, muscle, or tendon completely torn away. + +Haemorrhage is seldom a prominent feature, as the crushing or tearing of +the vessel wall leads to the obliteration of the lumen. + +The _special risks_ of these wounds are: (1) Sloughing of the bruised +tissues, especially when attempts to sterilise the wound have not been +successful. (2) Reactionary haemorrhage after the initial shock has +passed off. (3) Secondary haemorrhage as a result of infective processes +ensuing in the wound. (4) Loss of muscle or tendon, interfering with +motion. (5) Cicatricial contraction. (6) Gangrene, which may follow +occlusion of main vessels, or virulent infective processes. (7) It is +not uncommon to have particles of carbon embedded in the tissues after +lacerated wounds, leaving unsightly, pigmented scars. This is often seen +in coal-miners, and in those injured by firearms, and is to be prevented +by removing all gross dirt from the edges of the wound. + +_Treatment._--In severe wounds of this class implicating the +extremities, the most important question that arises is whether or not +the limb can be saved. In examining the limb, attention should first be +directed to the state of the main blood vessels, in order to determine +if the vascular supply of the part beyond the lesion is sufficient to +maintain its vitality. Amputation is usually called for if there is +complete absence of pulsation in the distal arteries and if the part +beyond is cold. If at the same time important nerve-trunks are +lacerated, so that the function of the limb would be seriously impaired, +it is not worth running the risk of attempting to save it. If, in +addition, there is extensive destruction of large muscular masses or of +important tendons, or comminution of the bones, amputation is usually +imperative. Stripping of large areas of skin is not in itself a reason +for removing a limb, as much can be done by skin grafting, but when it +is associated with other lesions it favours amputation. In considering +these points, it must be borne in mind that the damage to the deeper +tissues is always more extensive than appears on the surface, and that +in many cases it is only possible to estimate the real extent of the +injury by administering an anaesthetic and exploring the wound. In +doubtful cases the possibility of rendering the parts aseptic will often +decide the question for or against amputation. If thorough purification +is accomplished, the success which attends conservative measures is +often remarkable. It is permissible to run an amount of risk to save an +upper extremity which would be unjustifiable in the case of a lower +limb. The age and occupation of the patient must also be taken into +account. + +It having been decided to try and save the limb, the question is only +settled for the moment; it may have to be reconsidered from day to day, +or even from hour to hour, according to the progress of the case. + +When it is decided to make the attempt to save the limb, the wound must +be thoroughly purified. All bruised tissue in which gross dirt has +become engrained should be cut away with knife or scissors. The raw +surface is then cleansed with eusol, washed with sterilised salt +solution followed by methylated spirit, and rubbed all over with "bipp" +paste. If the purification is considered satisfactory the wound may be +closed, otherwise it is left open, freely drained or packed with gauze, +and the limb is immobilised by suitable splints. + + +WOUNDS BY FIREARMS AND EXPLOSIVES + +It is not necessary here to do more than indicate the general characters +of wounds produced by modern weapons. For further details the reader is +referred to works on military surgery. Experience has shown that the +nature and severity of the injuries sustained in warfare vary widely in + +different campaigns, and even in different fields of the same campaign. +Slight variations in the size, shape, and weight of rifle bullets, for +example, may profoundly modify the lesions they produce: witness the +destructive effect of the pointed bullet compared with that of the +conical form previously used. The conditions under which the fighting is +carried on also influence the wounds. Those sustained in the open, +long-range fighting of the South African campaign of 1899-1902 were very +different from those met with in the entrenched warfare in France in +1914-1918. It has been found also that the infective complications are +greatly influenced by the terrain in which the fighting takes place. In +the dry, sandy, uncultivated veldt of South Africa, bullet wounds seldom +became infected, while those sustained in the highly manured fields of +Belgium were almost invariably contaminated with putrefactive organisms, +and gaseous gangrene and tetanus were common complications. It has been +found also that wounds inflicted in naval engagements present different +characters from those sustained on land. Many other factors, such as the +physical and mental condition of the men, the facilities for affording +first aid, and the transport arrangements, also play a part in +determining the nature and condition of the wounds that have to be dealt +with by military surgeons. + +Whatever the nature of the weapon concerned, the wound is of the +_punctured, contused, and lacerated_ variety. Its severity depends on +the size, shape, and velocity of the missile, the range at which the +weapon is discharged, and the part of the body struck. + +Shock is a prominent feature, but its degree, as well as the time of its +onset, varies with the extent and seat of the injury, and with the +mental state of the patient when wounded. We have observed pronounced +shock in children after being shot even when no serious injury was +sustained. At the moment of injury the patient experiences a sensation +which is variously described as being like the lash of a whip, a blow +with a stick, or an electric shock. There is not much pain at first, but +later it may become severe, and is usually associated with intense +thirst, especially when much blood has been lost. + +In all forms of wounds sustained in warfare, septic infection +constitutes the main risk, particularly that resulting from +streptococci. The presence of anaerobic organisms introduces the +additional danger of gaseous forms of gangrene. + +The earlier the wound is disinfected the greater is the possibility of +diminishing this risk. If cleansing is carried out within the first six +hours the chance of eliminating sepsis is good; with every succeeding +six hours it diminishes, until after twenty-four hours it is seldom +possible to do more than mitigate sepsis. (J. T. Morrison.) + +The presence of a metallic foreign body having been determined and its +position localised by means of the X-rays, all devitalised and +contaminated tissue is excised, the foreign material, _e.g._, a missile, +fragments of clothing, gravel and blood-clot, removed, the wound +purified with antiseptics and closed or drained according to +circumstances. + +#Pistol-shot Wounds.#--Wounds inflicted by pistols, revolvers, and small +air-guns are of frequent occurrence in civil practice, the weapon being +discharged usually by accident, but frequently with suicidal, and +sometimes with homicidal intent. + +With all calibres and at all ranges, except actual contact, the wound of +entrance is smaller than the bullet. If the weapon is discharged within +a foot of the body, the skin surrounding the wound is usually stained +with powder and burned, and the hair singed. At ranges varying from six +inches to thirty feet, grains of powder may be found embedded in the +skin or lying loose on the surface, the greater the range the wider +being the area of spread. When black powder is used, the embedded grains +usually leave a permanent bluish-black tattooing of the skin. When the +weapon is placed in contact with the skin, the subcutaneous tissues are +lacerated over an area of two or three inches around the opening made by +the bullet and smoke and powder-staining and scorching are more marked +than at longer ranges. + +When the bullet perforates, the exit wound is usually larger and more +extensively lacerated than the wound of entrance. Its margins are as a +rule everted, and it shows no marks of flame, smoke, or powder. These +features are common to all perforations caused by bullets. + +Pistol wounds only produce dangerous effects when fired at close range, +and when the cavities of the skull, the thorax, or the abdomen are +implicated. In the abdomen a lethal injury may readily be caused even by +pistols of the "toy" order. These injuries will be described with +regional surgery. + +Pistol-shot wounds of _joints_ and _soft parts_ are seldom of serious +import apart from the risk of haemorrhage and of infection. + +_Treatment._--The treatment of wounds of the soft parts consists in +purifying the wounds of entrance and exit and the surrounding skin, and +in providing for drainage if this is indicated. + +There being no urgency for the removal of the bullet, time should be +taken to have it localised by the X-rays, preferably by stereoscopic +plates. In some cases it is not necessary to remove the bullet. + +#Wounds by Sporting Guns.#--In the common sporting or scatter gun, with +which accidents so commonly occur during the shooting season, the charge +of small shot or pellets leave the muzzle of the gun as a solid mass +which makes a single ragged wound having much the appearance of that +caused by a single bullet. At a distance of from four to five feet from +the muzzle the pellets begin to disperse so that there are separate +punctures around the main central wound. As the range increases, these +outlying punctures make a wider and wider pattern, until at a distance +of from eighteen to twenty feet from the muzzle, the scattering is +complete, there is no longer any central wound, and each individual +pellet makes its own puncture. From these elementary data, it is usually +possible, from the features of the wound, to arrive at an approximately +accurate conclusion regarding the range at which the gun was discharged, +and this may have an important bearing on the question of accident, +suicide, or murder. + +As regards the effects on the tissues at close range, that is, within a +few feet, there is widespread laceration and disruption; if a bone is +struck it is shattered, and portions of bone may be displaced or even +driven out through the exit wound. + +When the charge impinges over one of the large cavities of the body, the +shot may scatter widely through the contained viscera, and there is +often no exit wound. In the thorax, for example, if a rib is struck, the +charge and possibly fragments of bone, will penetrate the pleura, and be +dispersed throughout the lung; in the head, the skull may be shattered +and the brain torn up; and in the abdomen, the hollow viscera may be +perforated in many places and the solid organs lacerated. + +On covered parts the clothing, by deflecting the shot, influences the +size and shape of the wound; the entrance wound is increased in size and +more ragged, and portions of the clothes may be driven into the tissues. + +[Illustration: FIG. 62.--Radiogram showing Pellets embedded in Arm. + +(Mr. J. W. Dowden's case.)] + +A charge of small shot is much more destructive to blood vessels, +tendons, and ligaments than a single bullet, which in many cases pushes +such structures aside without dividing them. In the abdomen and chest, +also, the damage done by a full charge of shot is much more extensive +than that inflicted by a single bullet, the deflection of the pellets +leading to a greater number of perforations of the intestine and more +widespread laceration of solid viscera. + +When the charge impinges on one of the extremities at close range, we +often have the opportunity of observing that the exit wound is larger, +more ragged than that of entrance, and that its edges are everted; the +extensive tearing and bruising of all the tissues, including the bones, +and the marked tendency to early and progressive septic infection, +render amputation compulsory in the majority of such cases. + +At a range of from twenty to thirty feet, although the scatter is +complete, the pellets are still close together, so that if they +encounter the shaft of a long bone, even the femur, they fracture the +bone across, often along with some longitudinal splintering. + +Individual pellets striking the shafts of long bones become flattened or +distorted, and when cancellated bone is struck they become embedded in +it (Fig. 62). + +The skin, when it is closely peppered with shot, is liable to lose its +vitality, and with the addition of a little sepsis, readily necroses and +comes away as a slough. + +When the shot have diverged so as to strike singly, they seldom do much +harm, but fatal damage may be done to the brain or to the aorta, or the +eye may be seriously injured by a single pellet. + +Small shot fired at longer ranges--over about a hundred and fifty +feet--usually go through the skin, but seldom pierce the fascia, and lie +embedded in the subcutaneous tissue, from which they can readily be +extracted. + +The wad of the cartridge behaves erratically: so long as it remains flat +it goes off with the rest of the charge, and is often buried in the +wound; but if it curls up or turns on its side, it is usually deflected +and flies clear of the shot. It may make a separate wound. + +Wounds from sporting guns are to be _treated_ on the usual lines, the +early efforts being directed to the alleviation of shock and the +prevention of septic infection. There is rarely any urgency in the +removal of pellets from the tissues. + +#Wounds by Rifle Bullets.#--The vast majority of wounds inflicted by +rifle bullets are met with in the field during active warfare, and fall +to be treated by military surgeons. They occasionally occur +accidentally, however, during range practice for example, and may then +come under the notice of the civil surgeon. + +It is only necessary here to consider the effects of modern small-bore +rifle or machine-gun bullets. + +The trajectory is practically flat up to 675 yards. In destructive +effect there is not much difference between the various high velocity +bullets used in different armies; they will kill up to a distance of two +miles. The hard covering is employed to enable the bullet to take the +grooves in the rifle, and to prevent it stripping as it passes through +the barrel. It also increases the penetrating power of the missile, but +diminishes its "stopping" power, unless a vital part or a long bone is +struck. By removing the covering from the point of the bullet, as is +done in the Dum-Dum bullet, or by splitting the end, the bullet is made +to expand or "mushroom" when it strikes the body, and its stopping power +is thereby greatly increased, the resulting wound being much more +severe. These "soft-nosed" expanding bullets are to be distinguished +from "explosive" bullets which contain substances which detonate on +impact. High velocity bullets are unlikely to lodge in the body unless +spent, or pulled up by a sandbag, or metal buckle on a belt, or a book +in the pocket, or the core and the case separating--"stripping" of the +bullet. Spent shot may merely cause bruising of the surface, or they may +pass through the skin and lodge in the subcutaneous tissue, or may even +damage some deeper structure such as a nerve trunk. + +A blank cartridge fired at close range may cause a severe wound, and, if +charged with black powder, may leave a permanent bluish-black +pigmentation of the skin. + +The lesions of individual tissues--bones, nerves, blood vessels--are +considered with these. + +#Treatment of Gunshot Wounds under War Conditions.#--It is only +necessary to indicate briefly the method of dealing with gunshot wounds +in warfare as practised in the European War. + +1. _On the Field._--Haemorrhage is arrested in the limbs by an improvised +tourniquet; in the head by a pad and bandage; in the thorax or abdomen +by packing if necessary, but this should be avoided if possible, as it +favours septic infection. If a limb is all but detached it should be +completely severed. A full dose of morphin is given hypodermically. The +ampoule of iodine carried by the wounded man is broken, and its contents +are poured over and around the wound, after which the field dressing is +applied. In extensive wounds, the "shell-dressing" carried by the +stretcher bearers is preferred. All bandages are applied loosely to +allow for subsequent swelling. The fragments of fractured bones are +immobilised by some form of emergency splint. + +2. _At the Advanced Dressing Station_, after the patient has had a +liberal allowance of warm fluid nourishment, such as soup or tea, a full +dose of anti-tetanic serum is injected. The tourniquet is removed and +the wound inspected. Urgent amputations are performed. Moribund patients +are detained lest they die _en route_. + +3. _In the Field Ambulance or Casualty Clearing Station_ further +measures are employed for the relief of shock, and urgent operations are +performed, such as amputation for gangrene, tracheotomy for dyspnoea, or +laparotomy for perforated or lacerated intestine. In the majority of +cases the main object is to guard against infection; the skin is +disinfected over a wide area and surrounded with towels; damaged tissue, +especially muscle, is removed with the knife or scissors, and foreign +bodies are extracted. Torn blood vessels, and, if possible, nerves and +tendons are repaired. The wound is then partly closed, provision being +made for free drainage, or some special method of irrigation, such as +that of Carrel, is adopted. Sometimes the wound is treated with bismuth, +iodoform, and paraffin paste (B.I.P.P.) and sutured. + +4. _In the Base Hospital or Hospital Ship_ various measures may be +called for according to the progress of the wound and the condition of +the patient. + +#Shell Wounds and Wounds produced by Explosions.#--It is convenient to +consider together the effects of the bursting of shells fired from heavy +ordnance and those resulting in the course of blasting operations from +the discharge of dynamite or other explosives, or from the bursting of +steam boilers or pipes, the breaking of machinery, and similar accidents +met with in civil practice. + +Wounds inflicted by shell fragments and shrapnel bullets tend to be +extensive in area, and show great contusion, laceration, and destruction +of the tissues. The missiles frequently lodge and carry portions of the +clothing and, it may be, articles from the man's pocket, with them. +Shell wounds are attended with a considerable degree of shock. On +account of the wide area of contusion which surrounds the actual wound +produced by shell fragments, amputation, when called for, should be +performed some distance above the torn tissues, as there is considerable +risk of sloughing of the flaps. + +Wounds produced by dynamite explosions and the bursting of boilers have +the same general characters as shell wounds. Fragments of stone, coal, +or metal may lodge in the tissues, and favour the occurrence of +infective complications. + +All such injuries are to be treated on the general principles governing +contused and lacerated wounds. + + +EMBEDDED FOREIGN BODIES + +In the course of many operations foreign substances are introduced into +the tissues and intentionally left there, for example, suture and +ligature materials, steel or aluminium plates, silver wire or ivory pegs +used to secure the fixation of bones, or solid paraffin employed to +correct deformities. Other substances, such as gauze, drainage tubes, +or metal instruments, may be unintentionally left in a wound. + +Foreign bodies may also lodge in accidentally inflicted wounds, for +example, bullets, needles, splinters of wood, or fragments of clothing. +The needles of hypodermic syringes sometimes break and a portion remains +embedded in the tissues. As a result of explosions, particles of carbon, +in the form of coal-dust or gunpowder, or portions of shale, may lodge +in a wound. + +The embedded foreign body at first acts as an irritant, and induces a +reaction in the tissues in which it lodges, in the form of hyperaemia, +local leucocytosis, proliferation of fibroblasts, and the formation of +granulation tissue. The subsequent changes depend upon whether or not +the wound is infected with pyogenic bacteria. If it is so infected, +suppuration ensues, a sinus forms, and persists until the foreign body +is either cast out or removed. + +If the wound is aseptic, the fate of the foreign body varies with its +character. A substance that is absorbable, such as catgut or fine silk, +is surrounded and permeated by the phagocytes, which soften and +disintegrate it, the debris being gradually absorbed in much the same +manner as a fibrinous exudate. Minute bodies that are not capable of +being absorbed, such as particles of carbon, or of pigment used in +tattooing, are taken up by the phagocytes, and in course of time +removed. Larger bodies, such as needles or bullets, which are not +capable of being destroyed by the phagocytes, become encapsulated. In +the granulation tissue by which they are surrounded large multinuclear +giant-cells appear ("_foreign-body giant-cells_") and attach themselves +to the foreign body, the fibroblasts proliferate and a capsule of scar +tissue is eventually formed around the body. The tissues of the capsule +may show evidence of iron pigmentation. Sometimes fluid accumulates +around a foreign body within its capsule, constituting a cyst. + +Substances like paraffin, strands of silk used to bridge a gap in a +tendon, or portions of calcined bone, instead of being encapsulated, are +gradually permeated and eventually replaced by new connective tissue. + +Embedded bodies may remain in the tissues for an indefinite period +without giving rise to inconvenience. At any time, however, they may +cause trouble, either as a result of infective complications, or by +inducing the formation of a mass of inflammatory tissue around them, +which may simulate a gumma, a tuberculous focus, or a sarcoma. This +latter condition may give rise to difficulties in diagnosis, +particularly if there is no history forthcoming of the entrance of the +foreign body. The ignorance of patients regarding the possible lodgment +in the tissues of a foreign body--even of considerable size--is +remarkable. In such cases the X-rays will reveal the presence of the +foreign body if it is sufficiently opaque to cast a shadow. The heavy, +lead-containing varieties of glass throw very definite shadows little +inferior in sharpness and definition to those of metal; almost all the +ordinary forms of commercial glass also may be shown up by the X-rays. + +Foreign bodies encapsulated in the peritoneal cavity are specially +dangerous, as the proximity of the intestine furnishes a constant +possibility of infection. + +The question of removal of the foreign body must be decided according to +the conditions present in individual cases; in searching for a foreign +body in the tissues, unless it has been accurately located, a general +anaesthetic is to be preferred. + + +BURNS AND SCALDS + +The distinction between a burn which results from the action of dry heat +on the tissues of the body and a scald which results from the action of +moist heat, has no clinical significance. + +In young and debilitated subjects hot poultices may produce injuries of +the nature of burns. In old people with enfeebled circulation mere +exposure to a strong fire may cause severe degrees of burning, the +clothes covering the part being uninjured. This may also occur about the +feet, legs, or knees of persons while intoxicated who have fallen asleep +before the fire. + +The damage done to the tissues by strong caustics, such as fuming nitric +acid, sulphuric acid, caustic potash, nitrate of silver, or arsenical +paste, presents pathological and clinical features almost identical with +those resulting from heat. Electricity and the Rontgen rays also produce +lesions of the nature of burns. + +_Pathology of Burns._--Much discussion has taken place regarding the +explanation of the rapidly fatal issue in extensive superficial burns. +On post-mortem examination the lesions found in these cases are: (1) +general hyperaemia of all the organs of the abdominal, thoracic, and +cerebro-spinal cavities; (2) marked leucocytosis, with destruction of +red corpuscles, setting free haemoglobin which lodges in the epithelial +cells of the tubules of the kidneys; (3) minute thrombi and +extravasations throughout the tissues of the body; (4) degeneration of +the ganglion cells of the solar plexus; (5) oedema and degeneration of +the lymphoid tissue throughout the body; (6) cloudy swelling of the +liver and kidneys, and softening and enlargement of the spleen. Bardeen +suggests that these morbid phenomena correspond so closely to those met +with where the presence of a toxin is known to produce them, that in all +probability death is similarly due to the action of some poison produced +by the action of heat on the skin and on the proteins of the blood. + +#Clinical Features--Local Phenomena.#--The most generally accepted +classification of burns is that of Dupuytren, which is based upon the +depth of the lesion. Six degrees are thus, recognised: (1) hyperaemia or +erythema; (2) vesication; (3) partial destruction of the true skin; (4) +total destruction of the true skin; (5) charring of muscles; (6) +charring of bones. + +It must be observed, however, that burns met with at the bedside always +illustrate more than one of these degrees, the deeper forms always being +associated with those less deep, and the clinical picture is made up of +the combined characters of all. A burn is classified in terms of its +most severe portion. It is also to be remarked that the extent and +severity of a burn usually prove to be greater than at first sight +appears. + +_Burns of the first degree_ are associated with erythema of the skin, +due to hyperaemia of its blood vessels, and result from scorching by +flame, from contact with solids or fluids below 212 o F., or from +exposure to the sun's rays. They are characterised clinically by acute +pain, redness, transitory swelling from oedema, and subsequent +desquamation of the surface layers of the epidermis. A special form of +pigmentation of the skin is seen on the front of the legs of women from +exposure to the heat of the fire. + +_Burns of Second Degree--Vesication of the Skin._--These are +characterised by the occurrence of vesicles or blisters which are +scattered over the hyperaemic area, and contain a clear yellowish or +brownish fluid. On removing the raised epidermis, the congested and +highly sensitive papillae of the skin are exposed. Unna has found that +pyogenic bacteria are invariably present in these blisters. Burns of the +second degree leave no scar but frequently a persistent discoloration. +In rare instances the burned area becomes the seat of a peculiar +overgrowth of fibrous tissue of the nature of keloid (p 401). + +_Burns of Third Degree--Partial Destruction of the Skin._--The epidermis +and papillae are destroyed in patches, leaving hard, dry, and insensitive +sloughs of a yellow or black colour. The pain in these burns is +intense, but passes off during the first or second day, to return again, +however, when, about the end of a week, the sloughs separate and expose +the nerve filaments of the underlying skin. Granulations spring up to +fill the gap, and are rapidly covered by epithelium, derived partly from +the margins and partly from the remains of skin glands which have not +been completely destroyed. These latter appear on the surface of the +granulations as small bluish islets which gradually increase in size, +become of a greyish-white colour, and ultimately blend with one another +and with the edges. The resulting cicatrix may be slightly depressed, +but otherwise exhibits little tendency to contract and cause deformity. + +_Burns of Fourth Degree--Total Destruction of the Skin._--These follow +the more prolonged action of any form of intense heat. Large, black, dry +eschars are formed, surrounded by a zone of intense congestion. Pain is +less severe, and is referred to the parts that have been burned to a +less degree. Infection is liable to occur and to lead to wide +destruction of the surrounding skin. The amount of granulation tissue +necessary to fill the gap is therefore great; and as the epithelial +covering can only be derived from the margins--the skin glands being +completely destroyed--the healing process is slow. The resulting scars +are irregular, deep and puckered, and show a great tendency to contract. +Keloid frequently develops in such cicatrices. When situated in the +region of the face, neck, or flexures of joints, much deformity and +impairment of function may result (Fig. 63). + +[Illustration: FIG. 63.--Cicatricial Contraction following Severe Burn.] + +In _burns of the fifth degree_ the lesion extends through the +subcutaneous tissue and involves the muscles; while in those of the +_sixth degree_ it passes still more deeply and implicates the bones. +These burns are comparatively limited in area, as they are usually +produced by prolonged contact with hot metal or caustics. Burns of the +fifth and sixth degrees are met with in epileptics or intoxicated +persons who fall into the fire. Large blood vessels, nerve-trunks, +joints, or serous cavities may be implicated. + +#General Phenomena.#--It is customary to divide the clinical history of +a severe burn into three periods; but it is to be observed that the +features characteristic of the periods have been greatly modified since +burns have been treated on the same lines as other wounds. + +_The first period_ lasts for from thirty-six to forty-eight hours, +during which time the patient remains in a more or less profound state +of _shock_, and there is a remarkable absence of pain. When shock is +absent or little marked, however, the amount of suffering may be great. +When the injury proves fatal during this period, death is due to shock, +probably aggravated by the absorption of poisonous substances produced +in the burned tissues. In fatal cases there is often evidence of +cerebral congestion and oedema. + +The _second period_ begins when the shock passes off, and lasts till the +sloughs separate. The outstanding feature of this period is _toxaemia_, +manifested by fever, the temperature rising to 102 o, 103 o, or 104 o F., +and congestive or inflammatory conditions of internal organs, giving +rise to such clinical complications as bronchitis, broncho-pneumonia, or +pleurisy--especially in burns of the thorax; or meningitis and +cerebritis, when the neck or head is the seat of the burn. Intestinal +catarrh associated with diarrhoea is not uncommon; and ulceration of the +duodenum leading to perforation has been met with in a few cases. These +phenomena are much more prominent when bacterial infection has taken +place, and it seems probable that they are to be attributed chiefly to +the infection, as they have become less frequent and less severe since +burns have been treated like other breaches of the surface. Albuminuria +is a fairly constant symptom in severe burns, and is associated with +congestion of the kidneys. In burns implicating the face, neck, mouth, +or pharynx, oedema of the glottis is a dangerous complication, entailing +as it does the risk of suffocation. + +The _third period_ begins when the sloughs separate, usually between +the seventh and fourteenth days, and lasts till the wound heals, its +duration depending upon the size, depth, and asepticity of the raw area. +The chief causes of death during this period are toxin absorption in any +of its forms; waxy disease of the liver, kidneys, or intestine; less +commonly erysipelas, tetanus, or other diseases due to infection by +specific organisms. We have seen nothing to substantiate the belief that +duodenal ulcers are liable to perforate during the third period. + +The _prognosis_ in burns depends on (1) the superficial extent, and, to +a much less degree, the depth of the injury. When more than one-third of +the entire surface of the body is involved, even in a mild degree, the +prognosis is grave. (2) The situation of the burn is important. Burns +over the serous cavities--abdomen, thorax, or skull--are, other things +being equal, much more dangerous than burns of the limbs. The risk of +oedema of the glottis in burns about the neck and mouth has already been +referred to. (3) Children are more liable to succumb to shock during the +early period, but withstand prolonged suppuration better than adults. +(4) When the patient survives the shock, the presence or absence of +infection is the all-important factor in prognosis. + +#Treatment.#--The _general treatment_ consists in combating the shock. +When pain is severe, morphin must be injected. + +_Local Treatment._--The local treatment must be carried out on +antiseptic lines, a general anaesthetic being administered, if necessary, +to enable the purification to be carried out thoroughly. After carefully +removing the clothing, the whole of the burned area is gently, but +thoroughly, cleansed with peroxide of hydrogen or warm boracic lotion, +followed by sterilised saline solution. As pyogenic bacteria are +invariably found in the blisters of burns, these must be opened and the +raised epithelium removed. + +The dressings subsequently applied should meet the following +indications: the relief of pain; the prevention of sepsis; and the +promotion of cicatrisation. + +An application which satisfactorily fulfils these requirements is +_picric acid_. Pads of lint or gauze are lightly wrung out of a solution +made up of picric acid, 1 1/2 drams; absolute alcohol, 3 ounces; +distilled water, 40 ounces, and applied over the whole of the reddened +area. These are covered with antiseptic wool, _without_ any waterproof +covering, and retained in position by a many-tailed bandage. The +dressing should be changed once or twice a week, under the guidance of +the temperature chart, any portion of the original dressing which +remains perfectly dry being left undisturbed. The value of a general +anaesthetic in dressing extensive burns, especially in children, can +scarcely be overestimated. + +Picric acid yields its best results in superficial burns, and it is +useful as _a primary dressing_ in all. As soon as the sloughs separate +and a granulating surface forms, the ordinary treatment for a healing +sore is instituted. Any slough under which pus has collected should be +cut away with scissors to permit of free drainage. + +An occlusive dressing of melted _paraffin_ has also been employed. A +useful preparation consists of: Paraffin molle 25 per cent., paraffin +durum 67 per cent., olive oil 5 per cent., oil of eucalyptus 2 per +cent., and beta-naphthol 1/4 per cent. It has a melting point of 48 o C. +It is also known as _Ambrine_ and _Burnol_. After the burned area has +been cleansed and thoroughly dried, it is sponged or painted with the +melted paraffin, and before solidification takes place a layer of +sterilised gauze is applied and covered with a second coating of +paraffin. Further coats of paraffin are applied every other day to +prevent the gauze sticking to the skin. + +An alternative method of treating extensive burns is by immersing the +part, or even the whole body when the trunk is affected, in a bath of +boracic lotion kept at the body temperature, the lotion being frequently +renewed. + +If a burn is already infected when first seen, it is to be treated on +the same principles as govern the treatment of other infected wounds. + +All moist or greasy applications, such as Carron oil, carbolic oil and +ointments, and all substances like collodion and dry powders, which +retain discharges, entirely fail to meet the indications for the +rational treatment of burns, and should be abandoned. + +Skin-grafting is of great value in hastening healing after extensive +burns, and in preventing cicatricial contraction. The _deformities_ +which are so liable to develop from contraction of the cicatrices are +treated on general principles. In the region of the face, neck, and +flexures of joints (Fig. 63), where they are most marked, the contracted +bands may be divided and the parts stretched, the raw surface left being +covered by Thiersch grafts or by flaps of skin raised from adjacent +surfaces or from other parts of the body (Fig. 1). + + +INJURIES PRODUCED BY ELECTRICITY + +#Injuries produced by Exposure to X-Rays and Radium.#--In the routine +treatment of disease by radiations, injury is sometimes done to the +tissues, even when the greatest care is exercised as to dosage and +frequency of application. Robert Knox describes the following +ill-effects. + +_Acute dermatitis_ varying in degree from a slight erythema to deep +ulceration or even necrosis of skin. When ulcers form they are extremely +painful and slow to heal. When hair-bearing areas are affected, +epilation may occur without destroying the hair follicles and the hairs +are reproduced, but if the reaction is excessive permanent alopecia may +result. + +_Chronic dermatitis_, which results from persistence of the acute form, +is most intractable and may assume malignant characters. X-ray warts are +a late manifestation of chronic dermatitis and may become malignant. + +Among the _late manifestations_ are neuritis, telangiectasis, and a +painful and intractable form of ulceration, any of which may come on +months or even years after the cessation of exposure. _Sterility_ may be +induced in X-ray workers who are imperfectly protected from the effects +of the rays. + +#Electrical burns# usually occur in those who are engaged in industrial +undertakings where powerful electrical currents are employed. + +The lesions--which vary from a slight superficial scorching to complete +charring of parts--are most evident at the points of entrance and exit +of the current, the intervening tissues apparently escaping injury. + +The more superficial degrees of electrical burns differ from those +produced by heat in being almost painless, and in healing very slowly, +although as a rule they remain dry and aseptic. + +The more severe forms are attended with a considerable degree of shock, +which is not only more profound, but also lasts much longer than the +shock in an ordinary burn of corresponding severity. The parts at the +point of entrance of the current are charred to a greater or lesser +depth. The eschar is at first dry and crisp, and is surrounded by a zone +of pallor. For the first thirty-six to forty-eight hours there is +comparatively little suffering, but at the end of that time the parts +become exceedingly painful. In a majority of cases, in spite of careful +purification, a slow form of moist gangrene sets in, and the slough +spreads both in area and in depth, until the muscles and often the +large blood vessels and nerves are exposed. A line of demarcation +eventually forms, but the sloughs are exceedingly slow to separate, +taking from three to five times as long as in an ordinary burn, and +during the process of separation there is considerable risk of secondary +haemorrhage from erosion of large vessels. + +_Treatment._--Electrical burns are treated on the same lines as ordinary +burns, by thorough purification and the application of dry dressings, +with a view to avoiding the onset of moist gangrene. After granulations +have formed, skin-grafting is of value in hastening healing. + +#Lightning-stroke.#--In a large proportion of cases lightning-stroke +proves instantly fatal. In non-fatal cases the patient suffers from a +profound degree of shock, and there may or may not be any external +evidence of injury. In the mildest cases red spots or wheals--closely +resembling those of urticaria--may appear on the body, but they usually +fade again in the course of twenty-four hours. Sometimes large patches +of skin are scorched or stained, the discoloured area showing an +arborescent appearance. In other cases the injured skin becomes dry and +glazed, resembling parchment. Appearances are occasionally met with +corresponding to those of a superficial burn produced by heat. The chief +difference from ordinary burns is the extreme slowness with which +healing takes place. Localised paralysis of groups of muscles, or even +of a whole limb, may follow any degree of lightning-stroke. Treatment is +mainly directed towards combating the shock, the surface-lesions being +treated on the same lines as ordinary burns. + + + + +CHAPTER XII + +METHODS OF WOUND TREATMENT + + +Varieties of wounds--Modes of infection--Lister's work--Means taken to + prevent infection of wounds: _heat_; _chemical antiseptics_; + _disinfection of hands_; _preparation of skin of patient_; + _instruments_; _ligatures_; _dressings_--Means taken to combat + infection: _purification_; _open-wound method_. + +The surgeon is called upon to treat two distinct classes of wounds: (1) +those resulting from injury or disease in which _the skin is already +broken_, or in which a communication with a mucous surface exists; and +(2) those that he himself makes _through intact skin_, no infected +mucous surface being involved. + +Infection by bacteria must be assumed to have taken place in all wounds +made in any other way than by the knife of the surgeon operating through +unbroken skin. On this assumption the modern system of wound treatment +is based. Pathogenic bacteria are so widely distributed, that in the +ordinary circumstances of everyday life, no matter how trivial a wound +may be, or how short a time it may remain exposed, the access of +organisms to it is almost certain unless preventive measures are +employed. + +It cannot be emphasised too strongly that rigid precautions are to be +taken to exclude fresh infection, not only in dealing with wounds that +are free of organisms, but equally in the management of wounds and other +lesions that are already infected. Any laxity in our methods which +admits of fresh organisms reaching an infected wound adds materially to +the severity of the infective process and consequently to the patient's +risk. + +There are many ways in which accidental infection may occur. Take, for +example, the case of a person who receives a cut on the face by being +knocked down in a carriage accident on the street. Organisms may be +introduced to such a wound from the shaft or wheel by which he was +struck, from the ground on which he lay, from any portion of his +clothing that may have come in contact with the wound, or from his own +skin. Or, again, the hands of those who render first aid, the water used +to bathe the wound, the handkerchief or other extemporised dressing +applied to it, may be the means of conveying bacterial infection. Should +the wound open on a mucous surface, such as the mouth or nasal cavity, +the organisms constantly present in such situations are liable to prove +agents of infection. + +Even after the patient has come under professional care the risks of his +wound becoming infected are not past, because the hands of the doctor, +his instruments, dressings, or other appliances may all, unless +purified, become the sources of infection. + +In the case of an operation carried out through unbroken skin, organisms +may be introduced into the wound from the patient's own skin, from the +hands of the surgeon or his assistants, through the medium of +contaminated instruments, swabs, ligature or suture materials, or other +things used in the course of the operation, or from the dressings +applied to the wound. + +Further, bacteria may gain access to devitalised tissues by way of the +blood-stream, being carried hither from some infected area elsewhere in +the body. + +_The Antiseptic System of Surgery._--Those who only know the surgical +conditions of to-day can scarcely realise the state of matters which +existed before the introduction of the antiseptic system by Joseph +Lister in 1867. In those days few wounds escaped the ravages of pyogenic +and other bacteria, with the result that suppuration ensued after most +operations, and such diseases as erysipelas, pyaemia, and "hospital +gangrene" were of everyday occurrence. The mortality after compound +fractures, amputations, and many other operations was appalling, and +death from blood-poisoning frequently followed even the most trivial +operations. An operation was looked upon as a last resource, and the +inherent risk from blood-poisoning seemed to have set an impassable +barrier to the further progress of surgery. To the genius of Lister we +owe it that this barrier was removed. Having satisfied himself that the +septic process was due to bacterial infection, he devised a means of +preventing the access of organisms to wounds or of counteracting their +effects. Carbolic acid was the first antiseptic agent he employed, and +by its use in compound fractures he soon obtained results such as had +never before been attained. The principle was applied to other +conditions with like success, and so profoundly has it affected the +whole aspect of surgical pathology, that many of the infective diseases +with which surgeons formerly had to deal are now all but unknown. The +broad principles upon which Lister founded his system remain unchanged, +although the methods employed to put them into practice have been +modified. + +#Means taken to Prevent Infection of Wounds.#--The avenues by which +infective agents may gain access to surgical wounds are so numerous and +so wide, that it requires the greatest care and the most watchful +attention on the part of the surgeon to guard them all. It is only by +constant practice and patient attention to technical details in the +operating room and at the bedside, that the carrying out of surgical +manipulations in such a way as to avoid bacterial infection will become +an instinctive act and a second nature. It is only possible here to +indicate the chief directions in which danger lies, and to describe the +means most generally adopted to avoid it. + +To prevent infection, it is essential that everything which comes into +contact with a wound should be sterilised or disinfected, and to ensure +the best results it is necessary that the efficiency of our methods of +sterilisation should be periodically tested. The two chief agencies at +our disposal are heat and chemical antiseptics. + +#Sterilisation by Heat.#--The most reliable, and at the same time the +most convenient and generally applicable, means of sterilisation is by +heat. All bacteria and spores are completely destroyed by being +subjected for fifteen minutes to _saturated circulating steam_ at a +temperature of 130 o to 145 o C. (= 266 o to 293 o F.). The articles to be +sterilised are enclosed in a perforated tin casket, which is placed in a +specially constructed steriliser, such as that of Schimmelbusch. This +apparatus is so arranged that the steam circulates under a pressure of +from two to three atmospheres, and permeates everything contained in it. +Objects so sterilised are dry when removed from the steriliser. This +method is specially suitable for appliances which are not damaged by +steam, such, for example, as gauze swabs, towels, aprons, gloves, and +metal instruments; it is essential that the efficiency of the steriliser +be tested from time to time by a self-registering thermometer or other +means. + +The best substitute for circulating steam is _boiling_. The articles are +placed in a "fish-kettle steriliser" and boiled for fifteen minutes in a +1 per cent. solution of washing soda. + +To prevent contamination of objects that have been sterilised they must +on no account be touched by any one whose hands have not been +disinfected and protected by sterilised gloves. + +#Sterilisation by Chemical Agents.#--For the purification of the skin of +the patient, the hands of the surgeon, and knives and other instruments +that are damaged by heat, recourse must be had to chemical agents. +These, however, are less reliable than heat, and are open to certain +other objections. + +#Disinfection of the Hands.#--It is now generally recognised that one of +the most likely sources of wound infection is the hands of the surgeon +and his assistants. It is only by carefully studying to avoid all +contact with infective matter that the hands can be kept surgically +pure, and that this source of wound infection can be reduced to a +minimum. The risk of infection from this source has further been greatly +reduced by the systematic use of rubber gloves by house-surgeons, +dressers, and nurses. The habitual use of gloves has also been adopted +by the great majority of surgeons; the minority, who find they are +handicapped by wearing gloves as a routine measure, are obliged to do so +when operating in infective cases or dressing infected wounds, and in +making rectal and vaginal examinations. + +The gloves may be sterilised by steam, and are then put on dry, or by +boiling, in which case they are put on wet. The gauntlet of the glove +should overlap and confine the end of the sleeve of the sterilised +overall, and the gloved hands are rinsed in lotion before and at +frequent intervals during the operation. The hands are sterilised before +putting on the gloves, preferably by a method which dehydrates the skin. +Cotton gloves may be worn by the surgeon when tying ligatures, or +between operations, and by the anaesthetist during operations on the +head, neck, and chest. + +The first step in the disinfection of the hands is the mechanical +removal of gross surface dirt and loose epithelium by soap, a stream of +running water as hot as can be borne, and a loofah or nail-brush, that +has been previously sterilised by heat. The nails should be cut down +till there is no sulcus between the nail edge and the pulp of the finger +in which organisms may lodge. They are next washed for three minutes in +methylated spirit to dehydrate the skin, and then for two or three +minutes in 70 per cent. sublimate or biniodide alcohol (1 in 1000). +Finally, the hands are rubbed with dry sterilised gauze. + +#Preparation of the Skin of the Patient.#--In the purification of the +skin of the patient before operation, reliance is to be placed chiefly +in the mechanical removal of dirt and grease by the same means as are +taken for the cleansing of the surgeon's hands. Hair-covered parts +should be shaved. The skin is then dehydrated by washing with methylated +spirit, followed by 70 per cent. sublimate or biniodide alcohol (1 in +1000). This is done some hours before the operation, and the part is +then covered with pads of dry sterilised gauze or a sterilised towel. +Immediately before the operation the skin is again purified in the same +way. + +The _iodine method_ of disinfecting the skin introduced by Grossich is +simple, and equally efficient. The day before operation the skin, after +being washed with soap and water, is shaved, dehydrated by means of +methylated spirit, and then painted with a 5 per cent. solution of +iodine in rectified spirit. The painting with iodine is repeated just +before the operation commences, and again after it is completed. The +final application is omitted in the case of children. In emergency +operations the skin is shaved dry and dehydrated with spirit, after +which the iodine is applied as described above. The staining of the skin +is an advantage, as it enables the operator to recognise the area that +has been prepared. + +If any acne pustules or infected sinuses are present, they should be +destroyed or purified by means of the thermo-cautery or pure carbolic +acid, after the patient is anaesthetised. + +#Appliances used at Operation.#--_Instruments_ that are not damaged by +heat must be boiled in a fish-kettle or other suitable steriliser for +fifteen minutes in a 1 per cent. solution of cresol or washing soda. +Just before the operation begins they are removed in the tray of the +steriliser and placed on a sterilised towel within reach of the surgeon +or his assistant. Knives and instruments that are liable to be damaged +by heat should be purified by being soaked in pure cresol for a few +minutes, or in 1 in 20 carbolic for at least an hour. + +_Pads of Gauze_ sterilised by compressed circulating steam have almost +entirely superseded marine sponges for operative purposes. To avoid the +risk of leaving swabs in the peritoneal cavity, large square pads of +gauze, to one corner of which a piece of strong tape about a foot long +is securely stitched, should be employed. They should be removed from +the caskets in which they are sterilised by means of sterilised forceps, +and handed direct to the surgeon. The assistant who attends to the swabs +should wear sterilised gloves. + +_Ligatures and Sutures._--To avoid the risk of implanting infective +matter in a wound by means of the materials used for ligatures and +sutures, great care must be taken in their preparation. + +_Catgut._--The following methods of preparing catgut have proved +satisfactory: (1) The gut is soaked in juniper oil for at least a month; +the juniper oil is then removed by ether and alcohol, and the gut +preserved in 1 in 1000 solution of corrosive sublimate in alcohol +(Kocher). (2) The gut is placed in a brass receiver and boiled for +three-quarters of an hour in a solution consisting of 85 per cent. +absolute alcohol, 10 per cent. water, and 5 per cent. carbolic acid, and +is then stored in 90 per cent. alcohol. (3) Cladius recommends that the +catgut, just as it is bought from the dealers, be loosely rolled on a +spool, and then immersed in a solution of--iodine, 1 part; iodide of +potassium, 1 part; distilled water, 100 parts. At the end of eight days +it is ready for use. Moschcowitz has found that the tensile strength of +catgut so prepared is increased if it is kept dry in a sterile vessel, +instead of being left indefinitely in the iodine solution. If +Salkindsohn's formula is used--tincture of iodine, 1 part; proof spirit, +15 parts--the gut can be kept permanently in the solution without +becoming brittle. To avoid contamination from the hands, catgut should +be removed from the bottle with aseptic forceps and passed direct to the +surgeon. Any portion unused should be thrown away. + +_Silk_ is prepared by being soaked for twelve hours in ether, for other +twelve in alcohol, and then boiled for ten minutes in 1 in 1000 +sublimate solution. It is then wound on spools with purified hands +protected by sterilised gloves, and kept in absolute alcohol. Before an +operation the silk is again boiled for ten minutes in the same solution, +and is used directly from this (Kocher). Linen thread is sterilised in +the same way as silk. + +Fishing-gut and silver wire, as well as the needles, should be boiled +along with the instruments. Horse-hair and fishing-gut may be sterilised +by prolonged immersion in 1 in 20 carbolic, or in the iodine solutions +employed to sterilise catgut. + +The field of operation is surrounded by sterilised towels, clipped to +the edges of the wound, and securely fixed in position so that no +contamination may take place from the surroundings. + +The surgeon and his assistants, including the anaesthetist, wear +overalls sterilised by steam. To avoid the risk of infection from dust, +scurf, or drops of perspiration falling from the head, the surgeon and +his assistants may wear sterilised cotton caps. To obviate the risk of +infection taking place by drops of saliva projected from the mouth in +talking or coughing in the vicinity of a wound, a simple mask may be +worn. + +The risk of infection from the _air_ is now known to be very small, so +long as there is no excess of floating dust. All sweeping, dusting, and +disturbing of curtains, blinds, or furniture must therefore be avoided +before or during an operation. + +It has been shown that the presence of spectators increases the number +of organisms in the atmosphere. In teaching clinics, therefore, the risk +from air infection is greater than in private practice. + +To facilitate primary union, all haemorrhage should be arrested, and the +accumulation of fluid in the wound prevented. When much oozing is +anticipated, a glass or rubber drainage-tube is inserted through a small +opening specially made for the purpose. In aseptic wounds the tube may +be removed in from twenty-four to forty-eight hours, and where it is +important to avoid a scar, the opening should be closed with a Michel's +clip; in infected wounds the tube must remain as long as the discharge +continues. + +The fascia and skin should be brought into accurate apposition by +sutures. If any cavity exists in the deeper part of the wound it should +be obliterated by buried sutures, or by so adjusting the dressing as to +bring its walls into apposition. + +If these precautions have been successful, the wound will heal under the +original dressing, which need not be interfered with for from seven to +ten days, according to the nature of the case. + +#Dressings.#--_Gauze_, sterilised by heat, is almost universally +employed for the dressing of wounds. _Double cyanide gauze_ may be used +in such regions as the neck, axilla, or groin, where complete +sterilisation of the skin is difficult to attain, and where it is +desirable to leave the dressing undisturbed for ten days or more. +_Iodoform_ or _bismuth gauze_ is of special value for the packing of +wounds treated by the open method. + +One variety or another of _wool_, rendered absorbent by the extraction +of its fat, and sterilised by heat, forms a part of almost every +surgical dressing, and various antiseptic agents may be added to it. Of +these, corrosive sublimate is the most generally used. Wood-wool +dressings are more highly and more uniformly absorbent than cotton +wools. As evaporation takes place through wool dressings, the discharge +becomes dried, and so forms an unfavourable medium for bacterial growth. + +Pads of _sphagnum moss_, sterilised by heat, are highly absorbent, and +being economical are used when there is much discharge, and in cases +where a leakage of urine has to be soaked up. + +#Means adopted to combat Infection.#--As has already been indicated, the +same antiseptic precautions are to be taken in dealing with infected as +with aseptic wounds. + +In _recent injuries_ such as result from railway or machinery accidents, +with bruising and crushing of the tissues and grinding of gross dirt +into the wounds, the scissors must be freely used to remove the tissues +that have been devitalised or impregnated with foreign material. +Hair-covered parts should be shaved and the surrounding skin painted +with iodine. Crushed and contaminated portions of bone should be +chiselled away. Opinions differ as to the benefit derived from washing +such wounds with chemical antiseptics, which are liable to devitalise +the tissues with which they come in contact, and so render them less +able to resist the action of any organisms that may remain in them. All +are agreed, however, that free washing with normal salt solution is +useful in mechanically cleansing the injured parts. Peroxide of hydrogen +sprayed over such wounds is also beneficial in virtue of its oxidising +properties. Efficient drainage must be provided, and stitches should be +used sparingly, if at all. + +The best way in which to treat such wounds is by the _open method_. This +consists in packing the wound with iodoform or bismuth gauze, which is +left in position as long as it adheres to the raw surface. The packing +may be renewed at intervals until the wound is filled by granulations; +or, in the course of a few days when it becomes evident that the +infection has been overcome, _secondary_ sutures may be introduced and +the edges drawn together, provision being made at the ends for further +packing or for drainage-tubes. + +If earth or street dirt has entered the wound, the surface may with +advantage be painted over with pure carbolic acid, as virulent +organisms, such as those of tetanus or spreading gangrene, are liable to +be present. Prophylactic injection of tetanus antitoxin may be +indicated. + + + + +CHAPTER XIII + +CONSTITUTIONAL EFFECTS OF INJURIES + + +SYNCOPE--SHOCK--COLLAPSE--FAT EMBOLISM--TRAUMATIC ASPHYXIA--DELIRIUM + IN SURGICAL PATIENTS: _Delirium in general_; _Delirium tremens_; + _Traumatic delirium_. + + +SYNCOPE, SHOCK, AND COLLAPSE + +Syncope, shock, and collapse are clinical conditions which, although +depending on different causes, bear a superficial resemblance to one +another. + +#Syncope or Fainting.#--Syncope is the result of a suddenly produced +anaemia of the brain from temporary weakening or arrest of the heart's +action. In surgical practice, this condition is usually observed in +nervous persons who have been subjected to pain, as in the reduction of +a dislocation or the incision of a whitlow; or in those who have rapidly +lost a considerable quantity of blood. It may also follow the sudden +withdrawal of fluid from a large cavity, as in tapping an abdomen for +ascites, or withdrawing fluid from the pleural cavity. Syncope sometimes +occurs also during the administration of a general anaesthetic, +especially if there is a tendency to sickness and the patient is not +completely under. During an operation the onset of syncope is often +recognised by the cessation of oozing from the divided vessels before +the general symptoms become manifest. + +_Clinical Features._--When a person is about to faint he feels giddy, +has surging sounds in his ears, and haziness of vision; he yawns, +becomes pale and sick, and a free flow of saliva takes place into the +mouth. The pupils dilate; the pulse becomes small and almost +imperceptible; the respirations shallow and hurried; consciousness +gradually fades away, and he falls in a heap on the floor. + +Sometimes vomiting ensues before the patient completely loses +consciousness, and the muscular exertion entailed may ward off the +actual faint. This is frequently seen in threatened syncopal attacks +during chloroform administration. + +Recovery begins in a few seconds, the patient sighing or gasping, or, it +may be, vomiting; the strength of the pulse gradually increases, and +consciousness slowly returns. In some cases, however, syncope is fatal. + +_Treatment._--The head should at once be lowered--in imitation of +nature's method--to encourage the flow of blood to the brain, the +patient, if necessary, being held up by the heels. All tight clothing, +especially round the neck or chest, must be loosened. The heart may be +stimulated reflexly by dashing cold water over the face or chest, or by +rubbing the face vigorously with a rough towel. The application of +volatile substances, such as ammonia or smelling-salts, to the nose; the +administration by the mouth of sal-volatile, whisky or brandy, and the +intra-muscular injection of ether, are the most speedily efficacious +remedies. In severe cases the application of hot cloths over the heart, +or of the faradic current over the line of the phrenic nerve, just above +the clavicle, may be called for. + +#Surgical Shock.#--The condition known as surgical shock may be looked +upon as a state of profound exhaustion of the mechanism that exists in +the body for the transformation of energy. This mechanism consists of +(1) the _brain_, which, through certain special centres, regulates all +vital activity; (2) the _adrenal glands_, the secretion of +which--adrenalin--acting as a stimulant of the sympathetic system, so +controls the tone of the blood vessels as to maintain efficient +oxidation of the tissues; and (3) _the liver_, which stores and delivers +glycogen as it is required by the muscles, and in addition, deals with +the by-products of metabolism. + +Crile and his co-workers have shown that in surgical shock histological +changes occur in the cells of the brain, the adrenals, and the liver, +and that these are identical, whatever be the cause that leads to the +exhaustion of the energy-transforming mechanism. These changes vary in +degree, and range from slight alterations in the structure of the +protoplasm to complete disorganisation of the cell elements. + +The influences which contribute to bring about this form of exhaustion +that we call shock are varied, and include such emotional states as +fear, anxiety, or worry, physical injury and toxic infection, and the +effects of these factors are augmented by anything that tends to lower +the vitality, such as loss of blood, exposure, insufficient food, loss +of sleep or antecedent illness. + +Any one or any combination of these influences may cause shock, but the +most potent, and the one which most concerns the surgeon, is physical +injury, _e.g._, a severe accident or an operation (_traumatic shock_). +This is usually associated with some emotional disturbance, such as fear +or anxiety (_emotional shock_), or with haemorrhage; and may be followed +by septic infection (_toxic shock_). + +The exaggerated afferent impulses reaching the brain as a result of +trauma, inhibit the action of the nuclei in the region of the fourth +ventricle and cerebellum which maintain the muscular tone, with the +result that the muscular tone is diminished and there is a marked fall +in the arterial blood pressure. The capillaries dilate--the blood +stagnating in them and giving off its oxygen and transuding its fluid +elements into the tissues--with the result that an insufficient quantity +of oxygenated blood reaches the heart to enable it to maintain an +efficient circulation. As the sarco-lactic acid liberated in the muscles +is not oxygenated a condition of acidosis ensues. + +The more highly the injured part is endowed with sensory nerves the more +marked is the shock; a crush of the hand, for example, is attended with +a more intense degree of shock than a correspondingly severe crush of +the foot; and injuries of such specially innervated parts as the testis, +the urethra, the face, or the spinal cord, are associated with severe +degrees, as are also those of parts innervated from the sympathetic +system, such as the abdominal or thoracic viscera. It is to be borne in +mind that a state of general anaesthesia does not prevent injurious +impulses reaching the brain and causing shock during an operation. If +the main nerves of the part are "blocked" by injection of a local +anaesthetic, however, the central nervous system is protected from these +impulses. + +While the aged frequently manifest but few signs of shock, they have a +correspondingly feeble power of recovery; and while many young children +suffer little, even after severe operations, others with much less cause +succumb to shock. + +When the injured person's mind is absorbed with other matters than his +own condition,--as, for example, during the heat of a battle or in the +excitement of a railway accident or a conflagration,--even severe +injuries may be unattended by pain or shock at the time, although when +the period of excitement is over, the severity of the shock is all the +greater. The same thing is observed in persons injured while under the +influence of alcohol. + +_Clinical Features._--The patient is in a state of prostration. He is +roused from his condition of indifference with difficulty, but answers +questions intelligently, if only in a whisper. The face is pale, beads +of sweat stand out on the brow, the features are drawn, the eyes +sunken, and the cheeks hollow. The lips and ears are pallid; the skin of +the body of a greyish colour, cold, and clammy. The pulse is rapid, +fluttering, and often all but imperceptible at the wrist; the +respiration is irregular, shallow, and sighing; and the temperature may +fall to 96 o F. or even lower. The mouth is parched, and the patient +complains of thirst. There is little sensibility to pain. + +Except in very severe cases, shock tends towards recovery within a few +hours, the _reaction_, as it is called, being often ushered in by +vomiting. The colour improves; the pulse becomes full and bounding; the +respiration deeper and more regular; the temperature rises to 100 o F. or +higher; and the patient begins to take notice of his surroundings. The +condition of neurasthenia which sometimes follows an operation may be +associated with the degenerative changes in nerve cells described by +Crile. + +In certain cases the symptoms of traumatic shock blend with those +resulting from toxin absorption, and it is difficult to estimate the +relative importance of the two factors in the causation of the +condition. The conditions formerly known as "delayed shock" and +"prostration with excitement" are now generally recognised to be due to +toxaemia. + +_Question of Operating during Shock._--Most authorities agree that +operations should only be undertaken during profound shock when they are +imperatively demanded for the arrest of haemorrhage, the prevention of +infection of serous cavities, or for the relief of pain which is +producing or intensifying the condition. + +_Prevention of Operation Shock._--In the preparation of a patient for +operation, drastic purgation and prolonged fasting must be avoided, and +about half an hour before a severe operation a pint of saline solution +should be slowly introduced into the rectum; this is repeated, if +necessary, during the operation, and at its conclusion. The +operating-room must be warm--not less than 70 o F.--and the patient +should be wrapped in cotton wool and blankets, and surrounded by +hot-bottles. All lotions used must be warm (100 o F.); and the operation +should be completed as speedily and as bloodlessly as possible. The +element of fear may to some extent be eliminated by the preliminary +administration of such drugs as scopolamin or morphin, and with a view +to preventing the passage of exciting afferent impulses, Crile advocates +"blocking" of the nerves by the injection of a 1 per cent. solution of +novocaine into their substance on the proximal side of the field of +operation. To prevent after-pain in abdominal wounds he recommends +injecting the edges with quinine and urea hydrochlorate before suturing, +the resulting anaesthesia lasting for twenty-four to forty-eight hours. +To these preventive measures the term _anoci-association_ has been +applied. In selecting an anaesthetic, it may be borne in mind that +chloroform lowers the blood pressure more than ether does, and that with +spinal anaesthesia there is no lowering of the blood pressure. + +_Treatment._--A patient suffering from shock should be placed in the +recumbent position, with the foot of the bed raised to facilitate the +return circulation in the large veins, and so to increase the flow of +blood to the brain. His bed should be placed near a large fire, and the +patient himself surrounded by cotton wool and blankets and hot-bottles. +If he has lost much blood, the limbs should be wrapped in cotton wool +and firmly bandaged from below upwards, to conserve as much of the +circulating blood as possible in the trunk and head. If the shock is +moderate in degree, as soon as the patient has been put to bed, about a +pint of saline solution should be introduced into the rectum, and 10 to +15 minims of adrenalin chloride (1 in 1000) may with advantage be added +to the fluid. The injection should be repeated every two hours until the +circulation is sufficiently restored. In severe cases, especially when +associated with haemorrhage, transfusion of whole blood from a compatible +donor, is the most efficient means (_Op. Surg._, p. 37). Cardiac +stimulants such as strychnin, digitalin, or strophanthin are +contra-indicated in shock, as they merely exhaust the already impaired +vaso-motor centre. + +Artificial respiration may be useful in tiding a patient over the +critical period of shock, especially at the end of a severe operation. + +Failing this, the introduction of saline solution at a temperature of +about 105 o F. into a vein or into the subcutaneous tissue is useful +where much blood has been lost (p. 276). Two or three pints may be +injected into a vein, or smaller quantities under the skin. + +Thirst is best met by giving small quantities of warm water by the +mouth, or by the introduction of saline solution into the rectum. Ice +only relieves thirst for a short time, and as it is liable to induce +flatulence should be avoided, especially in abdominal cases. Dryness of +the tongue may be relieved by swabbing the mouth with a mixture of +glycerine and lemon juice. + +If severe pain calls for the use of morphin, 1/120th grain of atropin +should be added, or heroin alone may be given in doses of 1/24th to +1/12th grain. + +#Collapse# is a clinical condition which comes on more insidiously than +shock, and which does not attain its maximum degree of severity for +several hours. It is met with in the course of severe illnesses, +especially such as are associated with the loss of large quantities of +fluid from the body--for example, by severe diarrhoea, notably in Asiatic +cholera; by persistent vomiting; or by profuse sweating, as in some +cases of heat-stroke. Severe degrees of collapse follow sudden and +profuse loss of blood. + +Collapse often follows upon shock--for example, in intestinal +perforations, or after abdominal operations complicated by peritonitis, +especially if there is vomiting, as in cases of obstruction high up in +the intestine. The symptoms of collapse are aggravated if toxin +absorption is superadded to the loss of fluid. + +The _clinical features_ of this condition are practically the same as +those of shock; and it is treated on the same lines. + +FAT EMBOLISM.--After various injuries and operations, but +especially such as implicate the marrow of long bones--for example, +comminuted fractures, osteotomies, resections of joints, or the forcible +correction of deformities--fluid fat may enter the circulation in +variable quantity. In the vast majority of cases no ill effects follow, +but when the quantity is large or when the absorption is long continued +certain symptoms ensue, either immediately, or more frequently not for +two or three days. These are mostly referable to the lungs and brain. + +In the lung the fat collects in the minute blood vessels and produces +venous congestion and oedema, and sometimes pneumonia. Dyspnoea, with +cyanosis, a persistent cough and frothy or blood-stained sputum, a +feeble pulse and low temperature, are the chief symptoms. + +When the fat lodges in the capillaries of the brain, the pulse becomes +small, rapid, and irregular, delirium followed by coma ensues, and the +condition is usually rapidly fatal. + +Fat is usually to be detected in the urine, even in mild cases. + +The _treatment_ consists in tiding the patient over the acute stage of +his illness, until the fat is eliminated from the blood vessels. + +TRAUMATIC ASPHYXIA OR TRAUMATIC CYANOSIS.--This term has been +applied to a condition which results when the thorax is so forcibly +compressed that respiration is mechanically arrested for several +minutes. It has occurred from being crushed in a struggling crowd, or +under a fall of masonry, and in machinery accidents. When the patient is +released, the face and the neck as low down as the level of the +clavicles present an intense coloration, varying from deep purple to +blue-black. The affected area is sharply defined, and on close +inspection the appearance is found to be due to the presence of +countless minute reddish-blue or black spots, with small areas or +streaks of normal skin between them. The punctate nature of the +coloration is best recognised towards the periphery of the affected +area--at the junction of the brow with the hairy scalp, and where the +dark patch meets the normal skin of the chest (Beach and Cobb). Pressure +over the skin does not cause the colour to disappear as in ordinary +cyanosis. It has been shown by Wright of Boston, that the coloration is +due to stasis from mechanical over-distension of the veins and +capillaries; actual extravasation into the tissues is exceptional. The +sharply defined distribution of the coloration is attributed to the +absence of functionating valves in the veins of the head and neck, so +that when the increased intra-thoracic pressure is transmitted to these +veins they become engorged. Under the conjunctivae there are +extravasations of bright red blood; and sublingual haematoma has been +observed (Beatson). + +The discoloration begins to fade within a few hours, and after the +second or third day it disappears, without showing any of the chromatic +changes which characterise a bruise. The sub-conjunctival ecchymosis, +however, persists for several weeks and disappears like other +extravasations. Apart from combating the shock, or dealing with +concomitant injuries, no treatment is called for. + + +DELIRIUM IN SURGICAL PATIENTS + +Delirium is a temporary disturbance of mind which occurs in the course +of certain diseases, and sometimes after injuries or operations. It may +be associated with any of the acute pyogenic infections; with +erysipelas, especially when it affects the head or face; or with chronic +infective diseases of the urinary organs. In the various forms of +meningitis also, and in some cases of injury to the head, it is common; +and it is sometimes met with after severe haemorrhage, and in cases of +poisoning by such drugs as iodoform, cocain, or alcohol. Delirium may +also, of course, be a symptom of insanity. + +Often there is merely incoherent muttering regarding past incidents or +occupations, or about absent friends; or the condition may assume the +form of excitement, of dementia, or of melancholia; and the symptoms are +usually worst at night. + +#Delirium Tremens# is seen in persons addicted to alcohol, who, as the +result of accident or operation, are suddenly compelled to lie in bed. +Although oftenest met with in habitual drunkards or chronic tipplers, it +is by no means uncommon in moderate drinkers, and has even been seen in +children. + +_Clinical Features._--The delirium, which has been aptly described as +being of a "busy" character, usually manifests itself within a few days +of the patient being laid up. For two or three days he refuses food, is +depressed, suspicious, sleepless and restless, demanding to be allowed +up. Then he begins to mutter incoherently, to pull off the bedclothes, +and to attempt to get out of bed. There is general muscular tremor, most +marked in the tongue, the lips, and the hands. The patient imagines that +he sees all sorts of horrible beings around him, and is sometimes +greatly distressed because of rats, mice, beetles, or snakes, which he +fancies are crawling over him. The pulse is soft, rapid, and +compressible; the temperature is only moderately raised (100 o-101 o F.), +and as a rule there is profuse sweating. The digestion is markedly +impaired, and there is often vomiting. Patients in this condition are +peculiarly insensitive to pain, and may even walk about with a fractured +leg without apparent discomfort. + +In most cases the symptoms begin to pass off in three or four days; the +patient sleeps, the hallucinations and tremors cease, and he gradually +recovers. In other cases the temperature rises, the pulse becomes rapid, +and death results from exhaustion. + +The main indication in _treatment_ is to secure sleep, and this is done +by the administration of bromides, chloral, or paraldehyde, or of one or +other of the drugs of which sulphonal, trional, and veronal are +examples. Heroin in doses of from 1/24th to 1/12th grain is often of +service. Morphin must be used with great caution. In some cases hyoscin +(1/200 grain) injected hypodermically is found efficacious when all +other means have failed, but this drug must be used with great +discrimination. The patient must be encouraged to take plenty of easily +digested fluid food, supplemented, if necessary, by nutrient enemata and +saline infusions. + +In the early stage a brisk mercurial purge is often of value. Alcohol +should be withheld, unless failing of the pulse strongly indicates its +use, and then it should be given along with the food. + +A delirious patient must be constantly watched by a trained attendant or +other competent person, lest he get out of bed and do harm to himself or +others. Mechanical restraint is often necessary, but must be avoided if +possible, as it is apt to increase the excitement and exhaust the +patient. On account of the extreme restlessness, there is often great +difficulty in carrying out the proper treatment of the primary surgical +condition, and considerable modifications in splints and other +appliances are often rendered necessary. + +A form of delirium, sometimes spoken of as #Traumatic Delirium#, may +follow on severe injuries or operations in persons of neurotic +temperament, or in those whose nervous system is exhausted by overwork. +It is met with apart from alcoholic intemperance. This form of delirium +seems to be specially prone to ensue on operations on the face, the +thyreoid gland, or the genito-urinary organs. The symptoms appear in +from two to five days after the operation, and take the form of +restlessness, sleeplessness, low incoherent muttering, and picking at +the bedclothes. It is not necessarily attended by fever or by muscular +tremors. The patient may show hysterical symptoms. This condition is +probably to be regarded as a form of insanity, as it is liable to merge +into mania or melancholia. + +The _treatment_ is carried out on the same lines as that of delirium +tremens. + + + + +CHAPTER XIV + +THE BLOOD VESSELS + + +Anatomy--INJURIES OF ARTERIES: _Varieties_--INJURIES OF + VEINS: _Air Embolism_--Repair of blood vessels and natural + arrest of haemorrhage--HAEMORRHAGE: _Varieties_; + _Prevention_; _Arrest_--Constitutional effects of + haemorrhage--Haemophilia--DISEASES OF BLOOD VESSELS: + Thrombosis; Embolism--Arteritis: _Varieties_; + Arterio-sclerosis--Thrombo-phlebitis--Phlebitis: + _Varieties_--VARIX--ANGIOMATA--Naevus: _Varieties_; + _Electrolysis_--Cirsoid aneurysm--ANEURYSM: _Varieties_; + _Methods of treatment_--ANEURYSMS OF INDIVIDUAL ARTERIES. + +#Surgical Anatomy.#--An _artery_ has three coats: an internal coat--the +_tunica intima_--made up of a single layer of endothelial cells lining +the lumen; outside of this a layer of delicate connective tissue; and +still farther out a dense tissue composed of longitudinally arranged +elastic fibres--the internal elastic lamina. The tunica intima is easily +ruptured. The middle coat, or _tunica media_, consists of non-striped +muscular fibres, arranged for the most part concentrically round the +vessel. In this coat also there is a considerable proportion of elastic +tissue, especially in the larger vessels. The thickness of the vessel +wall depends chiefly on the development of the muscular coat. The +external coat, or _tunica externa_, is composed of fibrous tissue, +containing, especially in vessels of medium calibre, some yellow elastic +fibres in its deeper layers. + +In most parts of the body the arteries lie in a sheath of connective +tissue, from which fine fibrous processes pass to the tunica externa. +The connection, however, is not a close one, and the artery when divided +transversely is capable of retracting for a considerable distance within +its sheath. In some of the larger arteries the sheath assumes the form +of a definite membrane. + +The arteries are nourished by small vessels--the _vasa vasorum_--which +ramify chiefly in the outer coat. They are also well supplied with +nerves, which regulate the size of the lumen by inducing contraction or +relaxation of the muscular coat. + +The _veins_ are constructed on the same general plan as the arteries, +the individual coats, however, being thinner. The inner coat is less +easily ruptured, and the middle coat contains a smaller proportion of +muscular tissue. In one important point veins differ structurally from +arteries--namely, in being provided with valves which prevent reflux of +the blood. These valves are composed of semilunar folds of the tunica +intima strengthened by an addition of connective tissue. Each valve +usually consists of two semilunar flaps attached to opposite sides of +the vessel wall, each flap having a small sinus on its cardiac side. +The distension of these sinuses with blood closes the valve and +prevents regurgitation. Valves are absent from the superior and inferior +venae cavae, the portal vein and its tributaries, the hepatic, renal, +uterine, and spermatic veins, and from the veins in the lower part of +the rectum. They are ill-developed or absent also in the iliac and +common femoral veins--a fact which has an important bearing on the +production of varix in the veins of the lower extremity. + +The wall of _capillaries_ consists of a single layer of endothelial +cells. + + +HAEMORRHAGE + +Various terms are employed in relation to haemorrhage, according to its +seat, its origin, the time at which it occurs, and other circumstances. + +The term _external haemorrhage_ is employed when the blood escapes on the +surface; when the bleeding takes place into the tissues or into a cavity +it is spoken of as _internal_. The blood may infiltrate the connective +tissue, constituting an _extravasation_ of blood; or it may collect in a +space or cavity and form a _haematoma_. + +The coughing up of blood from the lungs is known as _haemoptysis_; +vomiting of blood from the stomach, as _haematemesis_; the passage of +black-coloured stools due to the presence of blood altered by digestion, +as _melaena_; and the passage of bloody urine, as _haematuria_. + +Haemorrhage is known as arterial, venous, or capillary, according to the +nature of the vessel from which it takes place. + +In _arterial_ haemorrhage the blood is bright red in colour, and escapes +from the cardiac end of the divided vessel in pulsating jets +synchronously with the systole of the heart. In vascular parts--for +example the face--both ends of a divided artery bleed freely. The blood +flowing from an artery may be dark in colour if the respiration is +impeded. When the heart's action is weak and the blood tension low the +flow may appear to be continuous and not in jets. The blood from a +divided artery at the bottom of a deep wound, escapes on the surface in +a steady flow. + +_Venous_ bleeding is not pulsatile, but occurs in a continuous stream, +which, although both ends of the vessel may bleed, is more copious from +the distal end. The blood is dark red under ordinary conditions, but may +be purplish, or even black, if the respiration is interfered with. When +one of the large veins in the neck is wounded, the effects of +respiration produce a rise and fall in the stream which may resemble +arterial pulsation. + +In _capillary_ haemorrhage, red blood escapes from numerous points on the +surface of the wound in a steady ooze. This form of bleeding is serious +in those who are the subjects of haemophilia. + + +INJURIES OF ARTERIES + +The following description of the injuries of arteries refers to the +larger, named trunks. The injuries of smaller, unnamed vessels are +included in the consideration of wounds and contusions. + +#Contusion.#--An artery may be contused by a blow or crush, or by the +oblique impact of a bullet. The bruising of the vessel wall, especially +if it is diseased, may result in the formation of a thrombus which +occludes the lumen temporarily or even permanently, and in rare cases +may lead to gangrene of the limb beyond. + +#Subcutaneous Rupture.#--An artery may be ruptured subcutaneously by a +blow or crush, or by a displaced fragment of bone. This injury has been +produced also during attempts to reduce dislocations, especially those +of old standing at the shoulder. It is most liable to occur when the +vessels are diseased. The rupture may be incomplete or complete. + +_Incomplete Subcutaneous Rupture._--In the majority of cases the rupture +is incomplete--the inner and middle coats being torn, while the outer +remains intact. The middle coat contracts and retracts, and the +internal, because of its elasticity, curls up in the interior of the +vessel, forming a valvular obstruction to the blood-flow. In most cases +this results in the formation of a thrombus which occludes the vessel. +In some cases the blood-pressure gradually distends the injured segment +of the vessel wall and leads to the formation of an aneurysm. + +The pulsation in the vessels beyond the seat of rupture is arrested--for +a time at least--owing to the occlusion of the vessel, and the limb +becomes cold and powerless. The pulsation seldom returns within five or +six weeks of the injury, if indeed it is not permanently arrested, but, +as a rule, a collateral circulation is rapidly established, sufficient +to nourish the parts beyond. If the pulsation returns within a week of +the injury, the presumption is that the occlusion was due to pressure +from without--for example, by haemorrhage into the sheath or the pressure +of a fragment of bone. + +_Complete Subcutaneous Rupture._--When the rupture is complete, all the +coats of the vessel are torn and the blood escapes into the surrounding +tissues. If the original injury is attended with much shock, the +bleeding may not take place until the period of reaction. Rupture of the +popliteal artery in association with fracture of the femur, or of the +axillary or brachial artery with fracture of the humerus or dislocation +of the shoulder, are familiar examples of this injury. + +Like incomplete rupture, this lesion is accompanied by loss of pulsation +and power, and by coldness of the limb beyond; a tense and excessively +painful swelling rapidly appears in the region of the injury, and, where +the cellular tissue is loose, may attain a considerable size. The +pressure of the effused blood occludes the veins and leads to congestion +and oedema of the limb beyond. The interference with the circulation, and +the damage to the tissues, may be so great that gangrene ensues. + +_Treatment._--When an artery has been contused or ruptured, the limb +must be placed in the most favourable condition for restoration of the +circulation. The skin is disinfected and the limb wrapped in cotton wool +to conserve its heat, and elevated to such an extent as to promote the +venous return without at the same time interfering with the inflow of +blood. A careful watch must be kept on the state of nutrition of the +limb, lest gangrene occurs. + +If no complications supervene, the swelling subsides, and recovery may +be complete in six or eight weeks. If the extravasation is great and the +skin threatens to give way, or if the vitality of the limb is seriously +endangered, it is advisable to expose the injured vessel, and, after +clearing away the clots, to attempt to suture the rent in the artery, +or, if torn across, to join the ends after paring the bruised edges. If +this is impracticable, a ligature is applied above and below the +rupture. If gangrene ensues, amputation must be performed. + +These descriptions apply to the larger arteries of the extremities. A +good illustration of subcutaneous rupture of the arteries of the head is +afforded by the tearing of the middle meningeal artery caused by the +application of blunt violence to the skull; and of the arteries of the +trunk--caused by the tearing of the renal artery in rupture of the +kidney. + +#Open Wounds of Arteries--Laceration.#--Laceration of large arteries is +a common complication of machinery and railway accidents. The violence +being usually of a tearing, twisting, or crushing nature, such injuries +are seldom associated with much haemorrhage, as torn or crushed vessels +quickly become occluded by contraction and retraction of their coats and +by the formation of a clot. A whole limb even may be avulsed from the +body with comparatively little loss of blood. The risk in such cases is +secondary haemorrhage resulting from pyogenic infection. + +The _treatment_ is that applicable to all wounds, with, in addition, the +ligation of the lacerated vessels. + +#Punctured wounds# of blood vessels may result from stabs, or they may +be accidentally inflicted in the course of an operation. + +The division of the coats of the vessel being incomplete, the natural +haemostasis that results from curling up of the intima and contraction of +the media, fails to take place, and bleeding goes on into the +surrounding tissues, and externally. If the sheath of the vessel is not +widely damaged, the gradually increasing tension of the extravasated +blood retained within it may ultimately arrest the haemorrhage. A clot +then forms between the lips of the wound in the vessel wall and projects +for a short distance into the lumen, without, however, materially +interfering with the flow through the vessel. The organisation of this +clot results in the healing of the wound in the vessel wall. + +In other cases the blood escapes beyond the sheath and collects in the +surrounding tissues, and a traumatic aneurysm results. Secondary +haemorrhage may occur if the wound becomes infected. + +The _treatment_ consists in enlarging the external wound to permit of +the damaged vessel being ligated above and below the puncture. In some +cases it may be possible to suture the opening in the vessel wall. When +circumstances prevent these measures being taken, the bleeding may be +arrested by making firm pressure over the wound with a pad; but this +procedure is liable to be followed by the formation of an aneurysm. + +_Minute puncture of arteries_ such as frequently occur in the hypodermic +administration of drugs and in the use of exploring needles, are not +attended with any escape of blood, chiefly because of the elastic recoil +of the arterial wall; a tiny thrombus of platelets and thrombus forms at +the point where the intima is punctured. + +#Incised Wounds.#--We here refer only to such incised wounds as partly +divide the vessel wall. + +Longitudinal wounds show little tendency to gape, and are therefore not +attended with much bleeding. They usually heal rapidly, but, like +punctured wounds, are liable to be followed by the formation of an +aneurysm. + +When, however, the incision in the vessel wall is oblique or transverse, +the retraction of the muscular coat causes the opening to gape, with the +result that there is haemorrhage, which, even in comparatively small +arteries, may be so profuse as to prove dangerous. When the associated +wound in the soft parts is valvular the haemorrhage is arrested and an +aneurysm may develop. + +When a large arterial trunk, such as the external iliac, the femoral, +the common carotid, the brachial, or the popliteal, has been partly +divided, for example, in the course of an operation, the opening should +be closed with sutures--_arteriorrhaphy_. The circulation being +controlled by a tourniquet, or the artery itself occluded by a clamp, +fine silk or catgut stitches are passed through the outer and middle +coats after the method of Lembert, a fine, round needle being employed. +The sheath of the vessel or an adjacent fascia should be stitched +over the line of suture in the vessel wall. If infection be excluded, +there is little risk of thrombosis or secondary haemorrhage; and even if +thrombosis should develop at the point of suture, the artery is +obstructed gradually, and the establishment of a collateral circulation +takes place better than after ligation. In the case of smaller trunks, +or when suture is impracticable, the artery should be tied above and +below the opening, and divided between the ligatures. + +#Gunshot Wounds of Blood Vessels.#--In the majority of cases injuries of +large vessels are associated with an external wound; the profusion of +the bleeding indicates the size of the damaged vessel, and the colour of +the blood and the nature of the flow denote whether an artery or a vein +is implicated. + +When an artery is wounded a firm _haematoma_ may form, with an expansile +pulsation and a palpable thrill--whether such a haematoma remains +circumscribed or becomes diffuse depends upon the density or laxity of +the tissues around it. In course of time a _traumatic arterial aneurysm_ +may develop from such a haematoma. + +When an artery and its companion vein are injured simultaneously an +_arterio-venous aneurysm_ (p. 310) may develop. This frequently takes +place without the formation of a haematoma as the arterial blood finds +its way into the vein and so does not escape into the tissues. Even if a +haematoma forms it seldom assumes a great size. In time a swelling is +recognised, with a palpable thrill and a systolic bruit, loudest at the +level of the communication and accompanied by a continuous venous hum. + +If leakage occurs into the tissues, the extravasated blood may occlude +the vein by pressure, and the symptoms of arterial aneurysm replace +those of the arterio-venous form, the systolic bruit persisting, while +the venous hum disappears. + +_Gangrene_ may ensue if the blood supply is seriously interfered with, +or the signs of _ischaemia_ may develop; the muscles lose their +elasticity, become hard and paralysed, and anaesthesia of the "glove" or +"stocking" type, with other alterations of sensation ensue. Apart from +ischaemia, _reflex paralysis_ of motion and sensation of a transient kind +may follow injury of a large vessel. + +_Treatment_ is carried out on the same lines as for similar injuries due +to other causes. + + +INJURIES OF VEINS + +Veins are subject to the same forms of injury as arteries, and the +results are alike in both, such variations as occur being dependent +partly on the difference in their anatomical structure, and partly on +the conditions of the circulation through them. + +#Subcutaneous rupture# of veins occur most frequently in association +with fractures and in the reduction of dislocations. The veins most +commonly ruptured are the popliteal, the axillary, the femoral, and the +subclavian. On account of the smaller amount of elastic and muscular +tissue in the wall of a vein, the contraction and retraction of its +walls are less than in an artery, and so bleeding may continue for a +longer period. On the other hand, owing to the lower blood-pressure the +outflow goes on more slowly, and the gradually increasing pressure +produced by the extravasated blood is usually sufficient to arrest the +haemorrhage before it becomes serious. As an aid in diagnosing the source +of the bleeding, it should be remembered that the rupture of a vein does +not affect the pulsation in the limb beyond. The risks are practically +the same as when an artery is ruptured, excepting that of aneurysm, and +the treatment is carried out on the same lines, but it is seldom +necessary to operate for the purpose of applying a ligature to the +injured vein. + +#Wounds# of veins--punctured and incised--frequently occur in the course +of operations; for example, in the removal of tumours or diseased glands +from the neck, the axilla, or the groin. They are also met with as a +result of accidental stabs and of suicidal or homicidal injuries. The +haemorrhage from a large vein so damaged is usually profuse, but it is +more readily controlled by external pressure than that from an artery. +When a vein is merely punctured, the bleeding may be arrested by +pressure with a pad of gauze, or by a lateral ligature--that is, picking +up the margins of the rent in the wall and securing them with a +ligature without occluding the lumen. In the large veins, such as the +internal jugular, the femoral, or the axillary, it is usually possible +to suture the opening in the wall. This does not necessarily result in +thrombosis in the vessel, or in obliteration of its lumen. + +When an _artery and vein are simultaneously wounded_, the features +peculiar to each are present in greater or less degree. In the limbs +gangrene may ensue, especially if the wound is infected. Punctured and +gun-shot wounds implicating both artery and vein are liable to be +followed by the development of arterio-venous aneurysm. + +#Entrance of Air into Veins--Air Embolism.#--This serious, though +fortunately rare, accident is apt to occur in the course of operations +in the region of the thorax, neck, or axilla, if a large vein is opened +and fails to collapse on account of the rigidity of its walls, its +incorporation in a dense fascia, or from traction being made upon it. If +the wound in a vein is thus held open, the negative pressure during +inspiration sucks air into the right side of the heart. This is +accompanied by a hissing or gurgling sound, and with the next expiration +some frothy blood escapes from the wound. The patient instantly becomes +pale, the pupils dilate, respiration becomes laboured, and although the +heart may continue to beat forcibly, the peripheral pulse is weak, and +may even be imperceptible. On auscultating the heart, a churning sound +may be heard. Death may result in a few minutes; or the heart may slowly +regain its power and recovery take place. + +_Prevention._--In operations in the "dangerous area"--as the region of +the root of the neck is called in this connection--care must be taken +not to cut or divide any vein before it has been secured by forceps, and +to apply ligatures securely and at once. Deep wounds in this region +should be kept filled with normal salt solution. Immediately a cut is +recognised in a vein, a finger should be placed over the vessel on the +cardiac side of the wound, and kept there until the opening is secured. + +_Treatment._--Little can be done after the air has actually entered the +vein beyond endeavouring to maintain the heart's action by hypodermic +injections of ether or strychnin and the application of mustard or hot +cloths over the chest. The head at the same time should be lowered to +prevent syncope. Attempts to withdraw the air by suction, and the +employment of artificial respiration, have proved futile, and are, by +some, considered dangerous. In a desperate case massage of the heart +might be tried. + + +THE NATURAL ARREST OF HAEMORRHAGE AND THE REPAIR OF BLOOD +VESSELS + +#Primary Haemorrhage.#--The term primary haemorrhage is applied to the +bleeding which follows immediately on the wounding of a blood vessel. +The natural process by which such haemorrhage is arrested varies with the +character of the wound in the vessel and may be modified by accidental +circumstances. + +(a) _Repair of completely divided Artery._--When an artery is +_completely_ divided, the circular fibres of the muscular coat contract, +so that the lumen of the cut ends is diminished, and at the same time +each segment retracts within its sheath in virtue of the recoil of the +elastic elements in its walls, the tunica intima curls up in the +interior of the vessel, and the tunica externa collapses over the cut +ends. The blood that escapes from the injured vessel fills the +interstices of the tissues, and, coagulating, forms a clot which +temporarily arrests the bleeding. That part of the clot which lies +between the divided ends of the vessel and in the cellular tissue +outside, is known as the _external clot_, while the portion which +projects into the lumen of the vessel is known as the _internal clot_, +and it usually extends as far as the nearest collateral branch. These +processes constitute what is known as the _temporary arrest of +haemorrhage_, which, it will be observed, is effected by the contraction +and retraction of the divided artery and by clotting. + +The _permanent arrest_ takes place by the transformation of the clot +into scar tissue. The internal clot plays the most important part in the +process; it becomes invaded by leucocytes and proliferating endothelial +and connective-tissue cells, and new blood vessels permeate the mass, +which is thus converted into granulation tissue. This is ultimately +replaced by fibrous tissue, which permanently occludes the end of the +vessel. Concurrently and by the same process the external clot is +converted into scar tissue. + +If a divided artery is _ligated at its cut end_, the tension of the +ligature is usually sufficient to rupture the inner and middle coats, +which curl up within the lumen, the outer coat alone being held in the +grasp of the ligature. An internal clot forms and, becoming organised, +permanently occludes the vessel as above described. The ligature and the +small portion of vessel beyond it are subsequently absorbed. + +In course of time the collateral branches of the vessel above and below +the level of section enlarge and their inter-communication becomes more +free, so that even when large trunks have been divided the vascular +supply of the parts beyond may be completely restored. This is known as +the development of the _collateral circulation_. + +_Imperfect Collateral Circulation._--While the development of the +collateral circulation after the ligation or obstruction from other +cause of a main arterial trunk may be sufficient to prevent gangrene of +the limb, it may be insufficient for its adequate nourishment; it may be +cold, bluish in colour, and there may be necrosis of the skin over bony +points; this is notably the case in the lower extremity after ligation +of the femoral or popliteal artery, when patches of skin may die over +the prominence of the heel, the balls of the toes, the projecting base +of the fifth metatarsal and the external malleolus. + +If, during the period of reaction, the blood-pressure rises + +considerably, the occluding clot at the divided end of the vessel may be +washed away or the ligature displaced, permitting of fresh bleeding +taking place--_reactionary_ or _intermediary haemorrhage_ (p. 272). + +In the event of the wound becoming infected with pyogenic organisms, the +occluding blood-clot or the young fibrous tissue may become +disintegrated in the suppurative process, and the bleeding start +afresh--_secondary haemorrhage_ (p. 273). + +(b) If an artery is only _partly cut across_, the divided fibres of +the tunica muscularis contract and those of the tunica externa retract, +with the result that a more or less circular hole is formed in the wall +of the vessel, from which free bleeding takes place, as the conditions +are unfavourable for the formation of an occluding clot. Even if a clot +does form, when the blood-pressure rises it is readily displaced, +leading to reactionary haemorrhage. Should the wound become infected, +secondary haemorrhage is specially liable to occur. A further risk +attends this form of injury, in that the intra-vascular tension may in +time lead to gradual stretching of the scar tissue which closes the gap +in the vessel wall, with the result that a localised dilatation or +diverticulum forms, constituting a _traumatic aneurysm_. + +(c) When the injury merely takes the form of a _puncture_ or _small +incision_ a blood-clot forms between the edges, becomes organised, and +is converted into cicatricial tissue which seals the aperture. Such +wounds may also be followed by reactionary or secondary haemorrhage, or +later by the formation of a traumatic aneurysm. + +_Conditions which influence the Natural Arrest of Haemorrhage._--The +natural arrest of bleeding is favoured by tearing or crushing of the +vessel walls, owing to the contraction and retraction of the coats and +the tendency of blood to coagulate when in contact with damaged tissue. +Hence the primary haemorrhage following lacerated wounds is seldom +copious. The occurrence of syncope or of profound shock also helps to +stop bleeding by reducing the force of the heart's action. + +On the other hand, there are conditions which retard the natural arrest. +When, for example, a vessel is only partly divided, the contraction and +retraction of the muscular coat, instead of diminishing the calibre of +the artery, causes the wound in the vessel to gape; by completing the +division of the vessel under these circumstances the bleeding can often +be arrested. In certain situations, also, the arteries are so intimately +connected with their sheaths, that when cut across they were unable to +retract and contract--for example, in the scalp, in the penis, and in +bones--and copious bleeding may take place from comparatively small +vessels. This inability of the vessels to contract and retract is met +with also in inflamed and oedematous parts and in scar tissue. Arteries +divided in the substance of a muscle also sometimes bleed unduly. Any +increase in the force of the heart's action, such as may result from +exertion, excitement, or over-stimulation, also interferes with the +natural arrest. Lastly, in bleeders, there are conditions which +interfere with the natural arrest of haemorrhage. + +#Repair of a Vessel ligated in its Continuity.#--When a ligature is +applied to an artery it should be pulled sufficiently tight to occlude +the lumen without causing rupture of its coats. It often happens, +however, that the compression causes rupture of the inner and middle +coats, so that only the outer coat remains in the grasp of the ligature. +While this weakens the wall of the vessel, it has the advantage of +hastening coagulation, by bringing the blood into contact with damaged +tissue. Whether the inner and middle coats are ruptured or not, blood +coagulates both above and below the ligature, the proximal clot being +longer and broader than that on the distal side. In small arteries these +clots extend as far as the nearest collateral branch, but in the larger +trunks their length varies. The permanent occlusion of those portions of +the vessel occupied by clot is brought about by the formation of +granulation tissue, and its replacement by cicatricial tissue, so that +the occluded segment of the vessel is represented by a fibrous cord. In +this process the coagulum only plays a passive role by forming a +scaffolding on which the granulation tissue is built up. The ligature +surrounding the vessel, and the elements of the clot, are ultimately +absorbed. + +#Repair of Veins.#--The process of repair in veins is the same as that +in arteries, but the thrombosed area may become canalised and the +circulation through the vessel be re-established. + + +HAEMORRHAGE IN SURGICAL OPERATIONS + +The management of the haemorrhage which accompanies an operation includes +(a) preventive measures, and (b) the arrest of the bleeding. + +#Prevention of Haemorrhage.#--Whenever possible, haemorrhage should be +controlled by _digital compression_ of the main artery supplying the +limb rather than by a tourniquet. If efficiently applied compression +reduces the immediate loss of blood to a minimum, and the bleeding from +small vessels that follows the removal of the tourniquet is avoided. +Further, the pressure of a tourniquet has been shown to be a material +factor in producing shock. + +In selecting a point at which to apply digital compression, it is +essential that the vessel should be lying over a bone which will furnish +the necessary resistance. The common carotid, for example, is pressed +backward and medially against the transverse process (carotid tubercle) +of the sixth cervical vertebra; the temporal against the temporal +process (zygoma) in front of the ear; and the facial against the +mandible at the anterior edge of the masseter. + +In the upper extremity, the subclavian is pressed against the first rib +by making pressure downwards and backwards in the hollow above the +clavicle; the axillary and brachial by pressing against the shaft of the +humerus. + +In the lower extremity, the femoral is controlled by pressing in a +direction backward and slightly upward against the brim of the pelvis, +midway between the symphysis pubis and the anterior superior iliac +spine. + +The abdominal aorta may be compressed against the bodies of the lumbar +vertebrae opposite the umbilicus, if the spine is arched well forwards +over a pillow or sand-bag, or by the method suggested by Macewen, in +which the patient's spine is arched forwards by allowing the lower +extremities and pelvis to hang over the end of the table, while the +assistant, standing on a stool, applies his closed fist over the +abdominal aorta and compresses it against the vertebral column. +Momburg recommends an elastic cord wound round the body between the +iliac crest and the lower border of the ribs, but this procedure has +caused serious damage to the intestine. + +When digital compression is not available, the most convenient and +certain means of preventing haemorrhage--say in an amputation--is by the +use of some form of _tourniquet_, such as the elastic tube of Esmarch or +of Foulis, or an elastic bandage, or the screw tourniquet of Petit. +Before applying any of these it is advisable to empty the limb of blood. +This is best done after the manner suggested by Lister: the limb is held +vertical for three or four minutes; the veins are thus emptied by +gravitation, and they collapse, and as a physiological result of this +the arteries reflexly contract, so that the quantity of blood entering +the limb is reduced to a minimum. With the limb still elevated the +tourniquet is firmly applied, a part being selected where the vessel can +be pressed directly against a bone, and where there is no risk of +exerting injurious pressure on the nerve-trunks. The tourniquet should +be applied over several layers of gauze or lint to protect the skin, and +the first turn of the tourniquet must be rapidly and tightly applied to +arrest completely the arterial flow, otherwise the veins only are +obstructed and the limb becomes congested. In the lower extremity the +best place to apply a tourniquet is the middle third of the thigh; in +the upper extremity, in the middle of the arm. A tourniquet should never +be applied tighter or left on longer than is absolutely necessary. + +The screw tourniquet of Petit is to be preferred when it is desired to +intermit the flow through the main artery as in operations for aneurysm. + +When a tourniquet cannot conveniently be applied, or when its presence +interferes with the carrying out of the operation--as, for example, in +amputations at the hip or shoulder--the haemorrhage may be controlled by +preliminary ligation of the main artery above the seat of operation--for +instance, the external iliac or the subclavian. For such contingencies +also the steel skewers used by Spence and Wyeth, or a special clamp or +forceps, such as that suggested by Lynn Thomas, may be employed. In the +case of vessels which it is undesirable to occlude permanently, such as +the common carotid, the temporary application of a ligature or clamp is +useful. + +#Arrest of Haemorrhage.#--_Ligature._--This is the best means of securing +the larger vessels. The divided vessel having been caught with forceps +as near to its cut end as possible, a ligature of catgut or silk is tied +round it. When there is difficulty in applying a ligature securely, for +example in a dense tissue like the scalp or periosteum, or in a friable +tissue like the thyreoid gland or the mesentery, a stitch should be +passed so as to surround the bleeding vessel a short distance from its +end, in this way ensuring a better hold and preventing the ligature from +slipping. + +If the haemorrhage is from a partly divided vessel, this should be +completely cut across to enable its walls to contract and retract, and +to facilitate the application of forceps and ligatures. + +_Torsion._--This method is seldom employed except for comparatively +small vessels, but it is applicable to even the largest arteries. In +employing torsion, the end of the vessel is caught with forceps, and the +terminal portion twisted round several times. The object is to tear the +inner and middle coats so that they curl up inside the lumen, while the +outer fibrous coat is twisted into a cord which occludes the end of the +vessel. + +_Forci-pressure._--Bleeding from the smallest arteries and from +arterioles can usually be arrested by firmly squeezing them for a few +minutes with artery forceps. It is usually found that on the removal of +the forceps at the end of an operation no further haemorrhage takes +place. By the use of specially strong clamps, such as the angiotribes of +Doyen, large trunks may be occluded by pressure. + +_Cautery._--The actual cautery or Paquelin's thermo-cautery is seldom +employed to arrest haemorrhage, but is frequently useful in preventing +it, as, for example, in the removal of piles, or in opening the bowel in +colostomy. It is used at a dull-red heat, which sears the divided ends +of the vessel and so occludes the lumen. A bright-red or a white heat +cuts the vessel across without occluding it. The separation of the +slough produced by the charring of the tissues is sometimes attended +with secondary bleeding. + +_Haemostatics_ or _Styptics_.--The local application of haemostatics is +seldom to be recommended. In the treatment of epistaxis or bleeding from +the nose, of haemorrhage from the socket of a tooth, and sometimes from +ulcerating or granulating surfaces, however, they may be useful. All +clots must be removed and the drug applied directly to the bleeding +surface. Adrenalin and turpentine are the most useful drugs for this +purpose. + +Haemorrhage from bone, for example the skull, may be arrested by means of +Horsley's aseptic plastic wax. To stop persistent oozing from soft +tissues, Horsley successfully applied a portion of living vascular +tissue, such as a fragment of muscle, which readily adheres to the +oozing surface and yields elements that cause coagulation of the blood +by thrombo-kinetic processes. When examined after two or three days the +muscle has been found to be closely adherent and undergoing +organisation. + +#Arrest of Accidental Haemorrhage.#--The most efficient means of +temporarily controlling haemorrhage is by pressure applied with the +finger, or with a pad of gauze, directly over the bleeding point. While +this is maintained an assistant makes digital pressure, or applies a +tourniquet, over the main vessel of the limb on the proximal side of the +bleeding point. A useful _emergency tourniquet_ may be improvised by +folding a large handkerchief _en cravatte_, with a cork or piece of wood +in the fold to act as a pad. The handkerchief is applied round the +limb, with the pad over the main artery, and the ends knotted on the +lateral aspect of the limb. With a strong piece of wood the handkerchief +is wound up like a Spanish windlass, until sufficient pressure is +exerted to arrest the bleeding. + +When haemorrhage is taking place from a number of small vessels, its +arrest may be effected by elevation of the bleeding part, particularly +if it is a limb. By this means the force of the circulation is +diminished and the formation of coagula favoured. Similarly, in wounds +of the hand or forearm, or of the foot or leg, bleeding may be arrested +by placing a pad in the flexure and acutely flexing the limb at the +elbow or knee respectively. + +#Reactionary Haemorrhage.#--Reactionary or intermediary haemorrhage +is really a recurrence of primary bleeding. As the name indicates, it +occurs during the period of reaction--that is, within the first twelve +hours after an operation or injury. It may be due to the increase in the +blood-pressure that accompanies reaction displacing clots which have +formed in the vessels, or causing vessels to bleed which did not bleed +during the operation; to the slipping of a ligature; or to the giving +way of a grossly damaged portion of the vessel wall. In the scrotum, the +relaxation of the dartos during the first few hours after operation +occasionally leads to reactionary haemorrhage. + +As a rule, reactionary haemorrhage takes place from small vessels as a +result of the displacement of occluding clots, and in many cases the +haemorrhage stops when the bandages and soaked dressings are removed. If +not, it is usually sufficient to remove the clots and apply firm +pressure, and in the case of a limb to elevate it. Should the haemorrhage +recur, the wound must be reopened, and ligatures applied to the bleeding +vessels. Douching the wound with hot sterilised water (about 110 o F.), +and plugging it tightly with gauze, are often successful in arresting +capillary oozing. When the bleeding is more copious, it is usually due +to a ligature having slipped from a large vessel such as the external +jugular vein after operations in the neck, and the wound must be opened +up and the vessel again secured. The internal administration of heroin +or morphin, by keeping the patient quiet, may prove useful in preventing +the recurrence of haemorrhage. + +#Secondary Haemorrhage.#--The term secondary haemorrhage refers to +bleeding that is delayed in its onset and is due to pyogenic infection +of the tissues around an artery. The septic process causes softening and +erosion of the wall of the artery so that it gives way under the +pressure of the contained blood. The leakage may occur in drops, or as a +rush of blood, according to the extent of the erosion, the size of the +artery concerned, and the relations of the erosion to the surrounding +tissues. When met with as a complication of a wound there is an +interval--usually a week to ten days--between the receipt of the wound +and the first haemorrhage, this time being required for the extension of +the septic process to the wall of the artery and the consequent erosion +of its coats. When secondary haemorrhage occurs apart from a wound, there +is a similar septic process attacking the wall of the artery from the +outside; for example in sloughing sore-throat, the separation of a +slough may implicate the wall of an artery and be followed by serious +and it may be fatal haemorrhage. The mechanical pressure of a fragment of +bone or of a rubber drainage tube upon the vessel may aid the septic +process in causing erosion of the artery. In pre-Listerian days, the +silk ligature around the artery likewise favoured the changes that lead +to secondary haemorrhage, and the interesting observation was often made, +that when the collateral circulation was well established, the leakage +occurred on the _distal_ side of the ligature. While it may happen that +the initial haemorrhage is rapidly fatal, as for example when the +external carotid or one of its branches suddenly gives way, it is quite +common to have one, two or more _warning haemorrhages_ before the leakage +on a large scale, which is rapidly fatal. + +The _appearances of the wound_ in cases complicated by secondary +haemorrhage are only characteristic in so far that while obviously +infected, there is an absence of all reaction; instead of frankly +suppurating, there is little or no discharge and the surrounding +cellular tissue and the limb beyond are oedematous and pit on pressure. + +The _general symptoms_ of septic poisoning in cases of secondary +haemorrhage vary widely in severity: they may be so slight that the +general health is scarcely affected and the convalescence from an +operation, for example, may be apparently normal except that the wound +does not heal satisfactorily. For example, a patient may be recovering +from an operation such as the removal of an epithelioma of the mouth, +pharynx or larynx and the associated lymph glands in the neck, and be +able to be up and going about his room, when, suddenly, without warning +and without obvious cause, a rush of blood occurs from the mouth or the +incompletely healed wound in the neck, causing death within a few +minutes. + +On the other hand, the toxaemia may be of a profound type associated with +marked pallor and progressive failure of strength, which, of itself, +even when the danger from haemorrhage has been overcome, may have a fatal +termination. The _prognosis_ therefore in cases of secondary haemorrhage +can never be other than uncertain and unfavourable; the danger from loss +of blood _per se_ is less when the artery concerned is amenable to +control by surgical measures. + +_Treatment._--The treatment of secondary haemorrhage includes the use of +local measures to arrest the bleeding, the employment of general +measures to counteract the accompanying toxaemia, and when the loss of +blood has been considerable, the treatment of the bloodless state. + +_Local Measures to arrest the Haemorrhage._--The occurrence of even +slight haemorrhages from a septic wound in the vicinity of a large blood +vessel is to be taken seriously; it is usually necessary to _open up the +wound_, clear out the clots and infected tissues with a sharp spoon, +disinfect the walls of the cavity with eusol or hydrogen peroxide, and +_pack_ it carefully but not too tightly with gauze impregnated with some +antiseptic, such as "bipp," so that, if the bleeding does not recur, it +may be left undisturbed for several days. The packing should if possible +be brought into actual contact with the leaking point in the vessel, and +so arranged as to make pressure on the artery above the erosion. The +dressings and bandage are then applied, with the limb in the attitude +that will diminish the force of the stream through the main artery, for +example, flexion at the elbow in haemorrhage from the deep palmar arch. +Other measures for combating the local sepsis, such as the irrigation +method of Carrel, may be considered. + +If the wound involves one of the extremities, it may be useful; and it +imparts confidence to the nurse, and, it may be, to the patient, if a +Petit's tourniquet is loosely applied above the wound, which the nurse +is instructed to tighten up in the event of bleeding taking place. + +_Ligation of the Artery._--If the haemorrhage recurs in spite of packing +the wound, or if it is serious from the outset and likely to be critical +if repeated, ligation of the artery itself or of the trunk from which it +springs, at a selected spot higher up, should be considered. This is +most often indicated in wounds of the extremities. + +As examples of proximal ligation for secondary haemorrhage may be cited +ligation of the hypogastric artery for haemorrhage in the buttock, of the +common iliac for haemorrhage in the thigh, of the brachial in the upper +arm for haemorrhage from the deep palmar arch, and of the posterior +tibial behind the medial malleolus for haemorrhage from the sole of the +foot. + +_Amputation_ is the last resource, and should be decided upon if the +haemorrhage recurs after proximal ligation, or if this has been followed +by gangrene of the limb; it should also be considered if the nature of +the wound and the virulence of the sepsis would of themselves justify +removal of the limb. Every surgeon can recall cases in which a timely +amputation has been the means of saving life. + +The _counteraction of the toxaemia_ and the _treatment of the bloodless +state_, are carried out on the usual lines. + +#Haemorrhage of Toxic Origin.#--Mention must also be made of haemorrhages +which depend upon infective or toxic conditions and in which no gross +lesion of the vessels can be discovered. The bleeding occurs as an +oozing, which may be comparatively slight and unimportant, or by its +persistence may become serious. It takes place into the superficial +layers of the skin, from mucous membranes, and into the substance of +such organs as the pancreas. Haemorrhage from the stomach and intestine, +attended with a brown or black discoloration of the vomit and of the +stools, is one of the best known examples: it is not uncommonly met with +in infective conditions originating in the appendix, intestine, +gall-bladder, and other abdominal organs. Haemorrhage from the mucous +membrane of the stomach after abdominal operations--apparently also due +to toxic causes and not to the operation--gives rise to the so-called +_post-operative haematemesis_. + +#Constitutional Effects of Haemorrhage.#--The severity of the symptoms +resulting from haemorrhage depends as much on the rapidity with which the +bleeding takes place as on the amount of blood lost. The sudden loss of +a large quantity, whether from an open wound or into a serous +cavity--for example, after rupture of the liver or spleen--is attended +with marked pallor of the surface of the body and coldness of the skin, +especially of the face, feet, and hands. The skin is moist with a cold, +clammy sweat, and beads of perspiration stand out on the forehead. The +pulse becomes feeble, soft, and rapid, and the patient is dull and +listless, and complains of extreme thirst. The temperature is usually +sub-normal; and the respiration rapid, shallow, and sighing in +character. Abnormal visual sensations, in the form of flashes of light +or spots before the eyes; and rushing, buzzing, or ringing sounds in the +ears, are often complained of. + +In extreme cases, phenomena which have been aptly described as those of +"air-hunger" ensue. On account of the small quantity of blood +circulating through the body, and the diminished haemoglobin content of +the blood, the tissues are imperfectly oxygenated, and the patient +becomes extremely restless, gasping for breath, constantly throwing +about his arms and baring his chest in the vain attempt to breath more +freely. Faintness and giddiness are marked features. The diminished +supply of oxygen to the brain and to the muscles produces muscular +twitchings, and sometimes convulsions. Finally the pupils dilate, the +sphincters relax, and death ensues. + +Young children stand the loss of blood badly, but they quickly recover, +as the regeneration of blood takes place rapidly. In old people also, +and especially when they are fat, the loss of blood is badly borne, and +the ill effects last longer. Women, on the whole, stand loss of blood +better than men, and in them the blood is more rapidly re-formed. A few +hours after a severe haemorrhage there is usually a leucocytosis of from +15,000 to 30,000. + +#Treatment of the Bloodless State.#--The patient should be placed in a +warm, well-ventilated room, and the foot of the bed elevated. Cardiac +stimulants, such as strychnin or alcohol, must be judiciously +administered, over-stimulation being avoided. The inhalation of oxygen +has been found useful in relieving the urgent symptoms of dyspnoea. + +The blood may be emptied from the limbs into the vessels of the trunk, +where it is more needed, by holding them vertically in the air for a few +minutes, and then applying a firm elastic bandage over a layer of cotton +wool, from the periphery towards the trunk. + +_Introduction of Fluids into the Circulation._--The most valuable +measure for maintaining the circulation, however, is by transfusion of +blood (_Op. Surg._, p. 37). If this is not immediately available the +introduction of from one to three pints of physiological salt +solution (a teaspoonful of common salt to a pint of water) into a vein, +or a 6 per cent. solution of gum acacia, is a useful expedient. The +solution is sterilised by boiling, and cooled to a temperature of about +105 o F. The addition of 5 to 10 minims of adrenalin solution (1 in 1000) +is advantageous in raising the blood-pressure (_Op. Surg._, p. 565). + +When the intra-venous method is not available, one or two pints of +saline solution with adrenalin should be slowly introduced into the +rectum, by means of a long rubber tube and a filler. Satisfactory, +although less rapidly obtained results follow the introduction of saline +solution into the cellular tissue--for example, under the mamma, into +the axilla, or under the skin of the back. + +If the patient can retain fluids taken by the mouth--such as hot coffee, +barley water, or soda water--these should be freely given, unless the +injury necessitates operative treatment under a general anaesthetic. + +Transfusion of blood is most valuable as _a preliminary to operation_ in +patients who are bloodless as a result of haemorrhage from gastric and +duodenal ulcers, and in bleeders. + + +HAEMOPHILIA + +The term haemophilia is applied to an inherited disease which renders the +patient liable to serious haemorrhage from even the most trivial +injuries; and the subjects of it are popularly known as "bleeders." + +The cause of the disease and its true nature are as yet unknown. There +is no proof of any structural defect in the blood vessels, and beyond +the fact that there is a diminution in the number of blood-plates, it +has not been demonstrated that there is any alteration in the +composition of the blood. + +The affection is in a marked degree hereditary, all the branches of an +affected family being liable to suffer. Its mode of transmission to +individuals, moreover, is characteristic: the male members of the stock +alone suffer from the affection in its typical form, while the tendency +is transmitted through the female line. Thus the daughters of a father +who is a bleeder, whilst they do not themselves suffer from the disease, +transmit the tendency to their male offspring. The sons, on the other +hand, neither suffer themselves nor transmit the disease to their +children (Fig. 64). The female members of a haemophilic stock are often +very prolific, and there is usually a predominance of daughters in their +families. + + +FIG 64.--Genealogical Tree of a Haemophilic Family. + +Great-Great-Grandmother Great-Great-Grandfather +Mrs D. (Lancashire) F M (History not known + .| | as to bleeding) + .| | + .+----------+-------+ + ............| + .| + ....| + .+---------+--------+ + Great-Grandmother .| | | + (Married three .F MB MB + times) .| + .| + .| + By First Husband .| By Second By Third + ..............| Husband Husband + +-----------+------------+----------+-------+-------+-----------+------+ + | .| | | +-------+-----------+------+ + M .F F F | | +------+ + | .| | | MB F Died in No +Died Grandmother | | | Childbed Family + aet. .| | +-----------+ +----+--- + 70 .| +------+ |had family | | + .| | | |but history| | + .| MB MB |not known | MB + .| + .| + .|............................. ++-----+----------+------------+------------+------------+-------------+ +| | | | |. | | +| | | | |. | | +M M M MB F. F F + | |. | | + | Mother +--+--+---+--+--+ | + +----+ |. | | | | | | | + | | |. M M MB F F F | + M F |. | + Not Married |. +---+---+---+---+ + |. | | | | | + |. MB M MB M M + .............|. + +-----+-----+-----+-----+-----+ + | .| .| | | | + | .|* .|* | | | + M MB MB F F F + + +F = Females. M = Males (not bleeders). MB = Males (bleeders) + + ** the patients observed by the authors. The dotted line shows the + transmission of the disease to our patients through four + generations. + + +The disease is met with in boys who are otherwise healthy, and usually +manifests itself during the first few years of life. In rare instances +profuse haemorrhage takes place when the umbilical cord separates. As a +rule the first evidence is the occurrence of long-continued and +uncontrollable bleeding from a comparatively slight injury, such as the +scratch of a pin, the extraction of a tooth, or after the operation of +circumcision. The blood oozes slowly from the capillaries; at first it +appears normal, but after flowing for some days, or it may be weeks, it +becomes pale, thin, and watery, and shows less and less tendency to +coagulate. + +Female members of haemophilia families sometimes show a tendency to +excessive haemorrhage, but they seldom manifest the characteristic +features met with in the male members. + +Sometimes the haemorrhage takes place apparently spontaneously from the +gums, the nasal or the intestinal mucous membrane. In other cases the +bleeding occurs into the cellular tissue under the skin or mucous +membrane, producing large areas of ecchymosis and discoloration. One of +the commonest manifestations of the disease is the occurrence of +haemorrhage into the cavities of the large joints, especially the knee, +elbow, or hip. The patient suffers repeatedly from such haemorrhages, the +determining injury being often so slight as to have passed unobserved. + +There is evidence that the tendency to bleed is greater at certain times +than at others--in some cases showing almost a cyclical +character--although nothing is known as to the cause of the variation. + +After a severe haemorrhage into the cellular tissue or into a joint, the +patient becomes pale and anaemic, the temperature may rise to 102 o or +103 o F., the pulse become small and rapid, and haemic murmurs are +sometimes developed over the heart and large arteries. The swelling is +tense, fluctuating, and hot, and there is considerable pain and +tenderness. + +In exceptional cases, blisters form over the seat of the effusion, or +the skin may even slough, and the clinical features may therefore come +to simulate closely those of an acute suppurative condition. When the +skin sloughs, an ulcer is formed with altered blood-clot in its floor +like that seen in scurvy, and there is a remarkable absence of any +attempt at healing. + +The acute symptoms gradually subside, and the blood is slowly absorbed, +the discoloration of the skin passing through the same series of changes +as occur after an ordinary bruise. The patients seldom manifest the +symptoms of the bloodless state, and the blood is rapidly regenerated. + +The _diagnosis_ is easy if the patient or his friends are aware of the +family tendency to haemorrhage and inform the doctor of it, but they are +often sensitive and reticent regarding the fact, and it may only be +elicited after close investigation. From the history it is usually easy +to exclude scurvy and purpura. Repeated haemorrhages into a joint may +result in appearances which closely simulate those of tuberculous +disease. Recent haemorrhages into the cellular tissue often present +clinical features closely resembling those of acute cellulitis or +osteomyelitis. A careful examination, however, may reveal ecchymoses on +other parts of the body which give a clue to the nature of the +condition, and may prevent the disastrous consequences that may follow +incision. + +These patients usually succumb sooner or later to haemorrhage, although +they often survive several severe attacks. After middle life the +tendency to bleed appears to diminish. + +_Treatment._--As a rule the ordinary means of arresting haemorrhage are +of little avail. From among the numerous means suggested, the following +may be mentioned: The application to the bleeding point of gauze soaked +in a 1 in 1000 solution of adrenalin; prolonged inhalation of oxygen; +freezing the part with a spray of ethyl-chloride; one or more +subcutaneous injections of gelatin--5 ounces of a 2 1/2 per cent. +solution of white gelatin in normal salt solution being injected at a +temperature of about 100 o F.; the injection of pituitary extract. The +application of a pad of gauze soaked in the blood of a normal person +sometimes arrests the bleeding. + +To prevent bleeding in haemophilics, intra-venous or subcutaneous +injections of fresh blood serum, taken from the human subject, the +sheep, the dog, or the horse, have proved useful. If fresh serum is not +available, anti-diphtheritic or anti-tetanic serum or trade +preparations, such as hemoplastin, may be employed. We have removed the +appendix and amputated through the thigh in haemophilic subjects without +excessive loss of blood after a course of fresh sheep's serum given by +the mouth over a period of several weeks. + +The chloride and lactate of calcium, and extract of thymus gland have +been employed to increase the coagulability of the blood. The patient +should drink large quantities of milk, which also increases the +coagulability of the blood. Monro has observed remarkable results from +the hypodermic injection of emetin hydrochloride in 1/2-grain doses. + + +THROMBOSIS AND EMBOLISM + +The processes known as thrombosis and embolism are so intimately +associated with the diseases of blood vessels that it is convenient to +define these terms in the first instance. + +#Thrombosis.#--The term _thrombus_ is applied to a clot of blood formed +in the interior of the heart or of a blood vessel, and the process by +which such a clot forms is known as _thrombosis_. It would appear that +slowing or stagnation of the blood-stream, and interference with the +integrity of the lining membrane of the vessel wall, are the most +important factors determining the formation of the clot. Alterations in +the blood itself, such as occur, for example, in certain toxaemias, also +favour coagulation. When the thrombus is formed slowly, it consists of +white blood cells with a small proportion of fibrin, and, being +deposited in successive layers, has a distinctly laminated appearance on +section. It is known as a _white thrombus_ or laminated clot, and is +often met with in the sac of an aneurysm (Fig. 72). When rapidly formed +in a vessel in which the blood is almost stagnant--as, for example, in a +pouched varicose vein--the blood coagulates _en masse_, and the clot +consists of all the elements of the blood, constituting a _red thrombus_ +(Fig. 66). Sometimes the thrombus is _mixed_--a red thrombus being +deposited on a white one, it may be in alternate layers. + +When aseptic, a thrombus may become detached and be carried off in the +blood-stream as an embolus; it may become organised; or it may +degenerate and undergo calcification. Occasionally a small thrombus +situated behind a valve in a varicose vein or in the terminal end of a +dilated vein--for example in a pile--undergoes calcification, and is +then spoken of as a _phlebolith_; it gives a shadow with the X-rays. + +When infected with pyogenic bacteria, the thrombus becomes converted +into pus and a localised abscess forms; or portions of the thrombus may +be carried as emboli in the circulation to distant parts, where they +give rise to secondary foci of suppuration--pyaemic abscesses. + +#Embolism.#--The term _embolus_ is applied to any body carried along in +the circulation and ultimately becoming impacted in a blood vessel. This +occurrence is known as _embolism_. The commonest forms of embolus are +portions of thrombi or of fibrinous formations on the valves of the +heart, the latter being usually infected with micro-organisms. + +Embolism plays an important part in determining one form of gangrene, as +has already been described. Infective emboli are the direct cause of the +secondary abscesses that occur in pyaemia; and they are sometimes +responsible for the formation of aneurysm. + +Portions of malignant tumours also may form emboli, and their impaction +in the vessels may lead to the development of secondary growths in +distant parts of the body. + +Fat and air embolism have already been referred to. + + +ARTERITIS + +_Pyogenic._--Non-suppurative inflammation of the coats of an artery may +so soften the wall of the vessel as to lead to aneurysmal dilatation. It +is not uncommon in children, and explains the occurrence of aneurysm in +young subjects. + +When suppuration occurs, the vessel wall becomes disintegrated and gives +way, leading to secondary haemorrhage. If the vessel ruptures into an +abscess cavity, dangerous bleeding may occur when the abscess bursts or +is opened. + +_Syphilitic._--The inflammation associated with syphilis results in +thickening of the tunica intima, whereby the lumen of the vessel becomes +narrowed, or even obliterated--_endarteritis obliterans_. The middle +coat usually escapes, but the tunica externa is generally thickened. +These changes cause serious interference with the nutrition of the parts +supplied by the affected arteries. In large trunks, by diminishing the +elasticity of the vessel wall, they are liable to lead to the formation +of aneurysm. + +Changes in the arterial walls closely resembling those of syphilitic +arteritis are sometimes met with in _tuberculous_ lesions. + +#Arterio-sclerosis# or #Chronic Arteritis#.--These terms are applied to +certain changes which result in narrowing of the lumen and loss of +elasticity in the arteries. The condition may affect the whole vascular +system or may be confined to particular areas. In the smaller arteries +there is more or less uniform thickening of the tunica intima from +proliferation of the endothelium and increase in the connective tissue +in the elastic lamina--a form of obliterative endarteritis. The +narrowing of the vessels may be sufficient to determine gangrene in the +extremities. In course of time, particularly in the larger arteries, +this new tissue undergoes degeneration, at first of a fatty nature, but +progressing in the direction of calcification, and this is followed by +the deposit of lime salts in the young connective tissue and the +formation of calcareous plates or rings over a considerable area of the +vessel wall. To this stage in the process the term _atheroma_ is +applied. The endothelium over these plates often disappears, leaving +them exposed to the blood-stream. + +Changes of a similar kind sometimes occur in the middle coat, the lime +salts being deposited among the muscle fibres in concentric rings. + +The primary cause of arterio-sclerosis is not definitely known, but its +almost constant occurrence, to a greater or less degree, in the aged +suggests that it is of the nature of a senile degeneration. It is +favoured by anything which throws excessive strain on the vessel walls, +such as heavy muscular work; by chronic alcoholism and syphilis; or by +such general diseases as tend to raise the blood-pressure--for example, +chronic Bright's disease or gout. It occurs with greater frequency and +with greater severity in men than in women. + +Atheromatous degeneration is most common in the large arterial trunks, +and the changes are most marked at the arch of the aorta, opposite the +flexures of joints, at the mouths of large branches, and at parts where +the vessel lies in contact with bone. The presence of diseased patches +in the wall of an artery diminishes its elasticity and favours +aneurysmal dilatation. Such a vessel also is liable to be ruptured by +external violence and so give rise to traumatic aneurysm. Thrombosis is +liable to occur when calcareous plates are exposed in the lumen of the +vessel by destruction of the endothelium, and this predisposes to +embolism. Arterio-sclerosis also interferes with the natural arrest of +haemorrhage, and by rendering the vessels brittle, makes it difficult to +secure them by ligature. In advanced cases the accessible arteries--such +as the radial, the temporal or the femoral--may be felt as firm, +tortuous cords, which are sometimes so hard that they have been aptly +compared to "pipe-stems." The pulse is smaller and less compressible +than normal, and the vessel moves bodily with each pulsation. It must be +borne in mind, however, that the condition of the radial artery may fail +to afford a clue to that of the larger arteries. Calcified arteries are +readily identified in skiagrams (Fig. 65). + +[Illustration: FIG. 65.--Radiogram showing Calcareous Degeneration +(Atheroma) of Arteries.] + +We have met with a chronic form of arterial degeneration in elderly +women, affecting especially the great vessels at the root of the neck, +in which the artery is remarkably attenuated and dilated, and so friable +that the wall readily tears when seized with an artery-forceps, +rendering ligation of the vessel in the ordinary way well-nigh +impossible. Matas suggests infolding the wall of the vessel with +interrupted sutures that do not pierce the intima, and wrapping it +round with a strip of peritoneum or omentum. + +The most serious form of arterial _thrombosis_ is that met with _in the +abdominal aorta_, which is attended with violent pains in the lower +limbs, rapidly followed by paralysis and arrest of the circulation. + + +THROMBO-PHLEBITIS AND THROMBOSIS IN VEINS + +#Thrombosis# is more common in veins than in arteries, because slowing +of the blood-stream and irritation of the endothelium of the vessel wall +are, owing to the conditions of the venous circulation, more readily +induced in veins. + +Venous thrombosis may occur from purely mechanical causes--as, for +example, when the wall of a vein is incised, or the vessel included in a +ligature, or when it is bruised or crushed by a fragment of a broken +bone or by a bandage too tightly applied. Under these conditions +thrombosis is essentially a reparative process, and has already been +considered in relation to the repair of blood vessels. + +In other cases thrombosis is associated with certain constitutional +diseases--gout, for example; the endothelium of the veins undergoing +changes--possibly the result of irritation by abnormal constituents in +the blood--which favour the formation of thrombi. + +Under these various conditions the formation of a thrombus is not +necessarily associated with the action of bacteria, although in any +of them this additional factor may be present. + +The most common cause of venous thrombosis, however, is inflammation of +the wall of the vein--phlebitis. + +#Phlebitis.#--Various forms of phlebitis are met with, but for practical +purposes they may be divided into two groups--one in which there is a +tendency to the formation of a thrombus; the other in which the +infective element predominates. + +In surgical patients, the _thrombotic form_ is almost invariably met +with in the lower extremity, and usually occurs in those who are +debilitated and anaemic, and who are confined to bed for prolonged +periods--for example, during the treatment of fractures of the leg or +pelvis, or after such operations as herniotomy, prostatectomy, or +appendectomy. + +_Clinical Features._--The most typical example of this form of phlebitis +is that so frequently met with in the great saphena vein, especially +when it is varicose. The onset of the attack is indicated by a sudden +pain in the lower limb--sometimes below, sometimes above the knee. This +initial pain may be associated with shivering or even with a rigor, and +the temperature usually rises one or two degrees. There is swelling and +tenderness along the line of the affected vein, and the skin over it is +a dull-red or purple colour. The swollen vein may be felt as a firm +cord, with bead-like enlargements in the position of the valves. The +patient experiences a feeling of stiffness and tightness throughout the +limb. There is often oedema of the leg and foot, especially when the limb +is in the dependent position. The acute symptoms pass off in a few days, +but the swelling and tenderness of the vein and the oedema of the limb +may last for many weeks. + +When the deep veins--iliac, femoral, popliteal--are involved, there is +great swelling of the whole limb, which is of a firm almost "wooden" +consistence, and of a pale-white colour; the oedema may be so great that +it is impossible to feel the affected vein until the swelling has +subsided. This is most often seen in puerperal women, and is known as +_phlegmasia alba dolens_. + +_Treatment._--The patient must be placed at absolute rest, with the foot +of the bed raised on blocks 10 or 12 inches high, and the limb +immobilised by sand-bags or splints. It is necessary to avoid handling +the parts, lest the clot be displaced and embolism occur. To avoid +frequent movement of the limb, the necessary dressings should be kept in +position by means of a many-tailed rather than a roller bandage. + +To relieve the pain, warm fomentations or lead and opium lotion should +be applied. Later, ichthyol-glycerin, or glycerin and belladonna, may be +substituted. + +When, at the end of three weeks, the danger of embolism is past, +douching and gentle massage may be employed to disperse the oedema; and +when the patient gets up he should wear a supporting elastic bandage. + +The _infective_ form usually begins as a peri-phlebitis arising in +connection with some focus of infection in the adjacent tissues. The +elements of the vessel wall are destroyed by suppuration, and the +thrombus in its lumen becomes infected with pyogenic bacteria and +undergoes softening. + +_Occlusion of the inferior vena cava_ as a result of infective +thrombosis is a well-known condition, the thrombosis extending into the +main trunk from some of its tributaries, either from the femoral or +iliac veins below or from the hepatic veins above. + +Portions of the softened thrombus are liable to become detached and to +enter the circulating blood, in which they are carried as emboli. These +may lodge in distant parts, and give rise to secondary foci of +suppuration--pyaemic abscesses. + +_Clinical Features._--Infective phlebitis is most frequently met with in +the transverse sinus as a sequel to chronic suppuration in the mastoid +antrum and middle ear. It also occurs in relation to the peripheral +veins, but in these it can seldom be recognised as a separate entity, +being merged in the general infective process from which it takes +origin. Its occurrence may be inferred, if in the course of a +suppurative lesion there is a sudden rise of temperature, with pain, +redness, and swelling along the line of a venous trunk, and a rapidly +developed oedema of the limb, with pitting of the skin on pressure. In +rare cases a localised abscess forms in the vein and points towards the +surface. + +_Treatment._--Attention must be directed towards the condition with +which the phlebitis is associated. Ligation of the vein on the cardiac +side of the thrombus with a view to preventing embolism is seldom +feasible in the peripheral veins, although, as will be pointed out +later, the jugular vein is ligated with this object in cases of +phlebitis of the transverse sinus. + + +VARIX--VARICOSE VEINS + +The term varix is applied to a condition in which veins are so altered +in structure that they remain permanently dilated, and are at the same +time lengthened and tortuous. Two types are met with: one in which +dilatation of a large superficial vein and its tributaries is the most +obvious feature; the other, in which bunches of distended and tortuous +vessels develop at one or more points in the course of a vein, a +condition to which Virchow applied the term _angioma racemosum venosum_. +The two types may occur in combination. + +Any vein in the body may become varicose, but the condition is rare +except in the veins of the lower extremity, in the veins of the +spermatic cord (varicocele), and in the veins of the anal canal +(haemorrhoids). + +We are here concerned with varix as it occurs in the veins of the lower +extremity. + +_Etiology._--Considerable difference of opinion exists as to the +essential cause of varix. The weight of evidence is in favour of the +view that, when dilatation is the predominant element, it results from a +congenital deficiency in the number, size, and strength of the valves of +the affected veins, and in an inherent weakness in the vessel walls. +The _angioma racemosum venosum_ is probably also due to a congenital +alteration in the structure of the vessels, and is allied to tumours of +blood vessels. The view that varix is congenital in origin, as was first +suggested by Virchow, is supported by the fact that in a large +proportion of cases the condition is hereditary; not only may several +members of the same family in succeeding generations suffer from varix, +but it is often found that the same vein, or segment of a vein, is +involved in all of them. The frequent occurrence of varix in youth is +also an indication of its congenital origin. + +In the majority of cases it is only when some exciting factor comes into +operation that the clinical phenomena associated with varix appear. The +most common exciting cause is increased pressure within the veins, and +this may be produced in a variety of ways. In certain diseases of the +heart, lungs, and liver, for example, the venous pressure may be so +raised as to cause a localised dilatation of such veins as are +congenitally weak. The direct pressure of a tumour, or of the gravid +uterus on the large venous trunks in the pelvis, may so obstruct the +flow as to distend the veins of the lower extremity. It is a common +experience in women that the signs of varix date from an antecedent +pregnancy. The importance of the wearing of tight garters as a factor in +the production of varicose veins has been exaggerated, although it must +be admitted that this practice is calculated to aggravate the condition +when it is once established. It has been proved experimentally that the +backward pressure in the veins may be greatly increased by straining, a +fact which helps to explain the frequency with which varicosity occurs +in the lower limbs of athletes and of those whose occupation involves +repeated and violent muscular efforts. There is reason to believe, +moreover, that a sudden strain may, by rupturing the valves and so +rendering them incompetent, induce varicosity independently of any +congenital defect. Prolonged standing or walking, by allowing gravity to +act on the column of blood in the veins of the lower limbs, is also an +important determining factor in the production of varix. + +Thrombosis of the deep veins--in the leg, for example--may induce marked +dilatation of the superficial veins, by throwing an increased amount of +work upon them. This is to be looked upon rather as a compensatory +hypertrophy of the superficial vessels than as a true varix. + +_Morbid Anatomy._--In the lower extremity the varicosity most commonly +affects the vessels of the great saphena system; less frequently those +of the small saphena system. Sometimes both systems are involved, and +large communicating branches may develop between the two. + +The essential lesion is the absence or deficiency of valves, so that +they are incompetent and fail to support the column of blood which bears +back upon them. Normally the valves in the femoral and iliac veins and +in the inferior vena cava are imperfectly developed, so that in the +erect posture the great saphena receives a large share of the backward +pressure of the column of venous blood. + +The whole length of the vein may be affected, but as a rule the disease +is confined to one or more segments, which are not only dilated, but are +also increased in length, so that they become convoluted. The adjacent +loops of the convoluted vein are often bound together by fibrous tissue. +All the coats are thickened, chiefly by an increased development of +connective tissue, and in some cases changes similar to those of +arterio-sclerosis occur. The walls of varicose veins are often +exceedingly brittle. In some cases the thickening is uniform, and in +others it is irregular, so that here and there thin-walled sacs or +pouches project from the side of the vein. These pouches vary in size +from a bean to a hen's egg, the larger forms being called _venous +cysts_, and being most commonly met with in the region of the saphenous +opening and of the opening in the popliteal fascia. Such pouches, being +exposed to injury, are frequently the seat of thrombosis (Fig. 66). + +[Illustration: FIG. 66.--Thrombosis in Tortuous and Pouched Great +Saphena Vein, in longitudinal section.] + +_Clinical Features._--Varix is most frequently met with between puberty +and the age of thirty, and the sexes appear to suffer about equally. + +The amount of discomfort bears no direct proportion to the extent of +the varicosity. It depends rather upon the degree of pressure in the +veins, as is shown by the fact that it is relieved by elevation of the +limb. When the whole length of the main trunk of the great saphena is +implicated, the pressure in the vein is high and the patient suffers a +good deal of pain and discomfort. When, on the contrary, the upper part +of the saphena and its valves are intact, and only the more distal veins +are involved, the pressure is not so high and there is comparatively +little suffering. The usual complaint is of a sense of weight and +fulness in the limb after standing or walking, sometimes accompanied by +actual pain, from which relief is at once obtained by raising the limb. +Cramp-like pains in the muscles are often associated with varix of the +deep veins. + +The dilated and tortuous vein can be readily seen and felt when the +patient is examined in the upright posture. In advanced cases, bead-like +swellings are sometimes to be detected over the position of the valves, +and, on running the fingers along the course of the vessel, a firm +ridge, due to periphlebitis, may be detected on each side of the vein. +When the limb is oedematous, the outline of the veins is obscured, but +they can be identified on palpation as gutter-like tracks. When large +veins are implicated, a distinct impulse on coughing may be seen to pass +down as far as the knee; and if the vessel is sharply percussed a fluid +wave may be detected passing both up and down the vein. + +If the patient is placed on a couch and the limb elevated, the veins are +emptied, and if pressure is then made over the region of the saphenous +opening and the patient allowed to stand up, so long as the great +saphena system alone is involved, the veins fill again very slowly from +below. If the small saphena system also is involved, and if +communicating branches are dilated, the veins fill up from below more +rapidly. When the pressure over the saphenous opening is removed, the +blood rapidly rushes into the varicose vessels from above; this is known +as Trendelenburg's test. + +The most marked dilatation usually occurs on the medial side of the +limb, between the middle of the thigh and the middle of the calf, the +arrangement of the veins showing great variety (Fig. 67). + +There are usually one or more bunches of enlarged and tortuous veins in +the region of the knee. Frequently a large branch establishes a +communication between the systems of the great and small saphenous veins +in the region of the popliteal space, or across the front of the upper +part of the tibia. The superficial position of this last branch and its +proximity to the bone render it liable to injury. + +[Illustration: FIG. 67.--Extensive Varix of Internal Saphena System on +Left Leg, of many years' standing.] + +The small veins of the skin of the ankle and foot often show as fine +blue streaks arranged in a stellate or arborescent manner, especially in +women who have borne children. + +_Complications._--When the varix is of long standing, the skin in the +lower part of the leg sometimes assumes a mahogany-brown or bluish hue, +as a result of the _deposit of blood pigment_ in the tissues, and this +is frequently a precursor of ulceration. + +_Chronic dermatitis_ (_varicose eczema_) is often met with in the lower +part of the leg, and is due to interference with the nutrition of the +skin. The incompetence of the valves allows the pressure in the varicose +veins to equal that in the arterioles, so that the capillary circulation +is impeded. From the same cause the blood in the deep veins is enabled +to enter the superficial veins, where the backward pressure is so great +that the blood flows down again, and so a vicious circle is established. +The blood therefore loses more and more of its oxygen, and so fails to +nourish the tissues. + +The _ulcer_ of the leg associated with varicose veins has already been +described. + +_Haemorrhage_ may take place from a varicose vein as a result of a wound +or of ulceration of its wall. Increased intra-venous pressure produced +by severe muscular strain may determine rupture of a vein exposed in the +floor of an ulcer. If the limb is dependent, the incompetency of the +valves permits of rapid and copious bleeding, which may prove fatal, +particularly if the patient is intoxicated when the rupture takes place +and no means are taken to arrest the haemorrhage. The bleeding may be +arrested at once by elevating the limb, or by applying pressure directly +over the bleeding point. + +_Phlebitis and thrombosis_ are common sequelae of varix, and may prove +dangerous, either by spreading into the large venous trunks or by giving +rise to emboli. The larger the varix the greater is the tendency for a +thrombus to spread upwards and to involve the deep veins. Thrombi +usually originate in venous cysts or pouches, and at acute bends on the +vessel, especially when these are situated in the vicinity of the knee, +and are subjected to repeated injuries--for example in riding. +Phleboliths sometimes form in such pouches, and may be recognised in a +radiogram. In a certain proportion of cases, especially in elderly +people, the occurrence of thrombosis leads to cure of the condition by +the thrombus becoming organised and obliterating the vein. + +_Treatment._--At best the treatment of varicose veins is only +palliative, as it is obviously impossible to restore to the vessels +their normal structure. The patient must avoid wearing anything, such as +a garter, which constricts the limb, and any obvious cause of direct +pressure on the pelvic veins, such as a tumour, persistent +constipation, or an ill-fitting truss, should be removed. Cardiac, +renal, or pulmonary causes of venous congestion must also be treated, +and the functions of the liver regulated. Severe forms of muscular +exertion and prolonged standing or walking are to be avoided, and the +patient may with benefit rest the limb in an elevated position for a few +hours each day. To support the distended vessels, a closely woven silk +or worsted stocking, or a light and porous form of elastic bandage, +applied as a puttee, should be worn. These appliances should be put on +before the patient leaves his bed in the morning, and should only be +removed after he lies down at night. In this way the vessels are never +allowed to become dilated. Elastic stockings, and bandages made entirely +of india-rubber, are to be avoided. In early and mild cases these +measures are usually sufficient to relieve the patient's discomfort. + +_Operative Treatment._--In aggravated cases, when the patient is +suffering pain, when his occupation is interfered with by repeated +attacks of phlebitis, or when there are large pouches on the veins, +operative treatment is called for. The younger the patient the clearer +is the indication to operate. It may be necessary to operate to enable a +patient to enter one of the public services, even although no symptoms +are present. The presence of an ulcer does not contra-indicate +operation; the ulcer should be excised, and the raw surface covered with +skin grafts, before dealing with the veins. + +The _operation of Trendelenburg_ is especially appropriate to cases in +which the trunk of the great saphena vein in the thigh is alone +involved. It consists in exposing three or four inches of the vein in +its upper part, applying a ligature at the upper and lower ends of the +exposed portion, and, after tying all tributary branches, resecting this +portion of the vein. + +The procedure of C. H. Mayo is adapted to cases in which it is desirable +to remove longer segments of the veins. It consists in the employment of +special instruments known as "ring-enucleators" or "vein-strippers," by +means of which long portions of the vein are removed through +comparatively small incisions. + +An alternative procedure consists in avulsing segments of the vein by +means of Babcock's stylet, which consists of a flexible steel rod, 30 +inches in length, with acorn-shaped terminals. The instrument is passed +along the lumen of the segment to be dealt with, and a ligature applied +around the vein above the bulbous end of the stylet enables nearly the +whole length of the great saphena vein to be dragged out in one piece. +These methods are not suitable when the veins are brittle, when there +are pouches or calcareous deposits in their walls, or where there has +been periphlebitis binding the coils together. + +Mitchell of Belfast advises exposing the varices at numerous points by +half-inch incisions, and, after clamping the vein between two pairs of +forceps, cutting it across and twisting out the segments of the vein +between adjacent incisions. The edges of the incisions are sutured; and +the limb is firmly bandaged from below upwards, and kept in an elevated +position. We have employed this method with satisfactory results. + +The treatment of the complications of varix has already been considered. + + +ANGIOMA[4] + +[4] In the description of angiomas we have followed the teaching of the +late John Duncan. + +Tumours of blood vessels may be divided, according to the nature of the +vessels of which they are composed, into the capillary, the venous, and +the arterial angiomas. + + +CAPILLARY ANGIOMA + +The most common form of capillary angioma is the naevus or congenital +telangiectasis. + +#Naevus.#--A naevus is a collection of dilated capillaries, the afferent +arterioles and the efferent venules of which often share in the +dilatation. Little is known regarding the _etiology_ of naevi beyond the +fact that they are of congenital origin. They often escape notice until +the child is some days old, but attention is usually drawn to them +within a fortnight of birth. For practical purposes the most useful +classification of naevi is into the cutaneous, the subcutaneous, and the +mixed forms. + +_The cutaneous naevus_, "mother's mark," or "port-wine stain," consists +of an aggregation of dilated capillaries in the substance of the skin. +On stretching the skin the vessels can be seen to form a fine network, +or to run in leashes parallel to one another. A dilated arteriole or a +vein winding about among the capillaries may sometimes be detected. +These naevi occur on any part of the body, but they are most frequently +met with on the face. They may be multiple, and vary greatly in size, +some being no bigger than a pin-head, while others cover large areas of +the body. In colour they present every tint from purple to brilliant +red; in the majority there is a considerable dash of blue, especially in +cold weather. + +Unlike the other forms of naevi, the cutaneous variety shows little +tendency to disappear, and it is especially persistent when associated +with overgrowth of the epidermis and of the hairs--_naevoid mole_. + +The _treatment_ of the cutaneous naevus is unsatisfactory, owing to the +difficulty of removing the naevus without leaving a scar which is even +more disfiguring. Very small naevi may be destroyed by a fine pointed +Paquelin thermo-cautery, or by escharotics, such as nitric acid. For +larger naevi, radium and solidified carbon dioxide ("CO_2 snow") may be +used. The extensive port-wine stains so often met with on the face are +best left alone. + +The _subcutaneous naevus_ is comparatively rare. It constitutes a +well-defined, localised tumour, which may possess a distinct capsule, +especially when it has ceased to grow or is retrogressing. On section, +it presents the appearance of a finely reticulated sponge. + +Although it may be noticed at, or within a few days of, birth, a +subcutaneous naevus is often overlooked, especially when on a covered +part of the body, and may not be discovered till the patient is some +years old. It forms a rounded, lobulated swelling, seldom of large size +and yielding a sensation like that of a sponge; the skin over it is +normal, or may exhibit a bluish tinge, especially in cold weather. In +some cases the tumour is diminished by pressing the blood out of it, but +slowly fills again when the pressure is relaxed, and it swells up when +the child struggles or cries. From a cold abscess it is diagnosed by the +history and progress of the swelling and by the absence of fluctuation. +When situated over one of the hernial openings, it closely simulates a +hernia; and when it occurs in the middle line of the face, head, or +back, it may be mistaken for such other congenital conditions as +meningocele or spina bifida. When other means fail, the use of an +exploring needle clears up the diagnosis. + +_Mixed Naevus._--As its name indicates, the mixed naevus partakes of the +characters of the other two varieties; that is, it is a subcutaneous +naevus with involvement of the skin. + +It is frequently met with on the face and head, but may occur on any +part of the body. It also affects parts covered by mucous membrane, such +as the cheek, tongue, and soft palate. The swelling is rounded or +lobulated, and projects beyond the level of its surroundings. Sometimes +the skin is invaded by the naevoid tissue over the whole extent of the +tumour, sometimes only over a limited area. Frequently the margin only +is of a bright-red colour, while the skin in the centre resembles a +cicatrix. The swelling is reduced by steady pressure, and increases in +size and becomes tense when the child cries. + +[Illustration: FIG. 68.--Mixed Naevus of Nose which was subsequently +cured by Electrolysis.] + +_Prognosis._--The rate of growth of the subcutaneous and mixed forms of +naevi varies greatly. They sometimes increase rapidly, especially during +the first few months of life; after this they usually grow at the same +rate as the child, or more slowly. There is a decided tendency to +disappearance of these varieties, fully 50 per cent. undergoing natural +cure by a process of obliteration, similar to the obliteration of +vessels in cicatricial tissue. This usually begins about the period of +the first dentition, sometimes at the second dentition, and sometimes at +puberty. On the other hand, an increased activity of growth may be shown +at these periods. The onset of natural cure is recognised by the tumour +becoming firmer and less compressible, and, in the mixed variety, by the +colour becoming less bright. Injury, infection, or ulceration of the +overlying skin may initiate the curative process. + +Towards adult life the spaces in a subcutaneous naevus may become greatly +enlarged, leading to the formation of a cavernous angioma. + +_Treatment._--In view of the frequency with which subcutaneous and mixed +naevi disappear spontaneously, interference is only called for when the +growth of the tumour is out of proportion to that of the child, or when, +from its situation--for example in the vicinity of the eye--any marked +increase in its size would render it less amenable to treatment. + +The methods of treatment most generally applicable are the use of radium +and carbon dioxide snow, igni-puncture, electrolysis, and excision. + +For naevi situated on exposed parts, where it is desirable to avoid a +scar, the use of _radium_ is to be preferred. The tube of radium is +applied at intervals to different parts of the naevus, the duration and +frequency of the applications varying with the strength of the +emanations and the reaction produced. The object aimed at is to induce +obliteration of the naevoid tissue by cicatricial contraction without +destroying the overlying skin. _Carbon-dioxide snow_ may be employed in +the same manner, but the results are inferior to those obtained by +radium. + +_Igni-puncture_ consists in making a number of punctures at different +parts of the naevus with a fine-pointed thermo-cautery, with the object +of starting at each point a process of cicatrisation which extends +throughout the naevoid tissue and so obliterates the vessels. + +_Electrolysis_ acts by decomposing the blood and tissues into their +constituent elements--oxygen and acids appearing at the positive, +hydrogen and bases at the negative electrode. These substances and gases +being given off in a nascent condition, at once enter into new +combinations with anything in the vicinity with which they have a +chemical affinity. In the naevus the practical result of this reaction is +that at the positive pole nitric acid, and at the negative pole caustic +potash, both in a state of minute subdivision, make their appearance. +The effect on the tissues around the positive pole, therefore, is +equivalent to that of an acid cauterisation, and on those round the +negative pole, to an alkaline cauterisation. + +As the process is painful, a general anaesthetic is necessary. The +current used should be from 20 to 80 milliamperes, gradually increasing +from zero, without shock; three to six large Bunsen cells give a +sufficient current, and no galvanometer is required. Steel needles, +insulated with vulcanite to within an eighth of an inch of their points, +are the best. Both poles are introduced into the naevus, the positive +being kept fixed at one spot, while the negative is moved about so as to +produce a number of different tracks of cauterisation. On no account +must either pole be allowed to come in contact with the skin, lest a +slough be formed. The duration of the sitting is determined by the +effect produced, as indicated by the hardening of the tumour, the +average duration being from fifteen to twenty minutes. If pallor of the +skin appears, it indicates that the needles are too near the surface, or +that the blood supply to the integument is being cut off, and is an +indication to stop. To cauterise the track and so prevent bleeding, the +needles should be slowly withdrawn while the current is flowing. When +the skin is reached the current is turned off. The punctures are covered +with collodion. Six or eight weeks should be allowed to elapse before +repeating the procedure. From two to eight or ten sittings may be +necessary, according to the size and character of the naevus. + +_Excision_ is to be preferred for naevi of moderate size situated on +covered parts of the body, where a scar is of no importance. Its chief +advantages over electrolysis are that a single operation is sufficient, +and that the cure is speedy and certain. The operation is attended with +much less haemorrhage than might be expected. + +#Cavernous Angioma.#--This form of angioma consists of a series of large +blood spaces which are usually derived from the dilatation of the +capillaries of a subcutaneous naevus. The spaces come to communicate +freely with one another by the disappearance of adjacent capillary +walls. While the most common situation is in the subcutaneous tissue, a +cavernous angioma is sometimes met with in internal organs. It may +appear at any age from early youth to middle life, and is of slow growth +and may become stationary. The swelling is rounded or oval, there is no +pulsation or bruit, and the tumour is but slightly compressible. The +treatment consists in dissecting it out. + +#Aneurysm by Anastomosis# is the name applied to a vascular tumour in +which the arteries, veins, and capillaries are all involved. It is met +with chiefly on the upper part of the trunk, the neck, and the scalp. It +tends gradually to increase in size, and may, after many years, attain +an enormous size. The tumour is ill-defined, and varies in consistence. +It is pulsatile, and a systolic bruit or a "thrilling" murmur may be +heard over it. The chief risk is haemorrhage from injury or ulceration. + +[Illustration: FIG. 69.--Cirsoid Aneurysm of Forehead in a boy aet. 10. + +(Mr. J. W. Dowden's case.)] + +The _treatment_ is conducted on the same lines as for naevus. When +electrolysis is employed, it should be directed towards the afferent +vessels; and if it fails to arrest the flow through these, it is useless +to persist with it. In some cases ligation of the afferent vessels has +been successful. + +#Arterial Angioma# or #Cirsoid Aneurysm#.--This is composed of the +enlarged branches of an arterial trunk. It originates in the smaller +branches of an artery--usually the temporal--and may spread to the main +trunk, and may even involve branches of other trunks with which the +affected artery anastomoses. + +The condition is probably congenital in origin, though its appearance is +frequently preceded by an injury. It almost invariably occurs in the +scalp, and is usually met with in adolescent young adults. + +The affected vessels slowly increase in size, and become tortuous, with +narrowings and dilatations here and there. Grooves and gutters are +frequently found in the bone underlying the dilated vessels. + +There is a constant loud bruit in the tumour, which greatly troubles the +patient and may interfere with sleep. There is no tendency either to +natural cure or to rupture, but severe and even fatal haemorrhage may +follow a wound of the dilated vessels. + +[Illustration: FIG. 70.--Cirsoid Aneurysm of Orbit and Face, which +developed after a blow on the Orbit with a cricket ball. + +(From a photograph lent by Sir Montagu Cotterill.)] + +The condition may be treated by excision or by electrolysis. In excision +the haemorrhage is controlled by an elastic tourniquet applied +horizontally round the head, or by ligation of the feeding trunks. In +large tumours the bleeding is formidable. In many cases electrolysis is +to be preferred, and is performed in the same way as for naevus. The +positive pole is placed in the centre of the tumour, while the negative +is introduced into the main affluents one after another. + + +ANEURYSM + +An aneurysm is a sac communicating with an artery, and containing fluid +or coagulated blood. + +Two types are met with--the pathological and the traumatic. It is +convenient to describe in this section also certain conditions in which +there is an abnormal communication between an artery and a +vein--arterio-venous aneurysm. + + +PATHOLOGICAL ANEURYSM + +In this class are included such dilatations as result from weakening of +the arterial coats, combined, in most cases, with a loss of elasticity +in the walls and increase in the arterial tension due to +arterio-sclerosis. In some cases the vessel wall is softened by +arteritis--especially the embolic form--so that it yields before the +pressure of the blood. + +Repeated and sudden raising of the arterial tension, as a result, for +example, of violent muscular efforts or of excessive indulgence in +alcohol, plays an important part in the causation of aneurysm. These +factors probably explain the comparative frequency of aneurysm in those +who follow such arduous occupations as soldiers, sailors, +dock-labourers, and navvies. In these classes the condition usually +manifests itself between the ages of thirty and fifty--that is, when the +vessels are beginning to degenerate, although the heart is still +vigorous and the men are hard at work. The comparative immunity of women +may also be explained by the less severe muscular strain involved by +their occupations and recreations. + +Syphilis plays an important part in the production of aneurysm, probably +by predisposing the patient to arterio-sclerosis and atheroma, and +inducing an increase in the vascular tension in the peripheral vessels, +from loss of elasticity of the vessel wall and narrowing of the lumen as +a result of syphilitic arteritis. It is a striking fact that aneurysm is +seldom met with in women who have not suffered from syphilis. + +#Varieties--Fusiform Aneurysm.#--When the _whole circumference_ of an +artery has been weakened, the tension of the blood causes the walls to +dilate uniformly, so that a fusiform or tubular aneurysm results. All +the coats of the vessel are stretched and form the sac of the aneurysm, +and the affected portion is not only dilated but is also increased in +length. This form is chiefly met with in the arch of the aorta, but may +occur in any of the main arterial trunks. As the sac of the aneurysm +includes all three coats, and as the inner and outer coats are usually +thickened by the deposit in them of connective tissue, this variety +increases in size slowly and seldom gives rise to urgent symptoms. + +As a rule a fusiform aneurysm contains fluid blood, but when the intima +is roughened by disease, especially in the form of calcareous plates, +shreds of clot may adhere to it. + +It has little tendency to natural cure, although this is occasionally +effected by the emerging artery becoming occluded by a clot; it has also +little tendency to rupture. + +#Sacculated Aneurysm.#--When a _limited area_ of the vessel wall is +weakened--for example by atheroma or by other form of arteritis--this +portion yields before the pressure of the blood, and a sacculated +aneurysm results. The internal and middle coats being already damaged, +or, it may be, destroyed, by the primary disease, the stress falls on +the external coat, which in the majority of cases constitutes the sac. +To withstand the pressure the external coat becomes thickened, and as +the aneurysm increases in size it forms adhesions to surrounding +tissues, so that fasciae, tendons, nerves, and other structures may be +found matted together in its wall. The wall is further strengthened by +the deposit on its inner aspect of blood-clot, which may eventually +become organised. + +The contents of the sac consist of fluid blood and a varying amount of +clot which is deposited in concentric layers on the inner aspect of the +sac, where it forms a pale, striated, firm mass, which constitutes a +laminated clot. Near the blood-current the clot is soft, red, and +friable (Fig. 72). The laminated clot not only strengthens the sac, +enabling it to resist the blood-pressure and so prevent rupture, but, if +it increases sufficiently to fill the cavity, may bring about cure. The +principle upon which all methods of treatment are based is to imitate +nature in producing such a clot. + +Sacculated aneurysm, as compared with the fusiform variety, tends to +rupture and also to cure by the formation of laminated clot; natural +cure is sometimes all but complete when extension and rupture occur and +cause death. + +An aneurysm is said to be _diffused_ when the sac ruptures and the blood +escapes into the cellular tissue. + +#Clinical Features of Aneurysm.#--Surgically, the sacculated is by far +the most important variety. The outstanding feature is the existence in +the line of an artery of a globular swelling, which pulsates. The +pulsation is of an expansile character, which is detected by observing +that when both hands are placed over the swelling they are separated +with each beat of the heart. If the main artery be compressed on the +cardiac side of the swelling, the pulsation is arrested and the tumour +becomes smaller and less tense, and it may be still further reduced in +size by gentle pressure being made over it so as to empty it of fluid +blood. On allowing the blood again to flow through the artery, the +pulsation returns at once, but several beats are required before the sac +regains its former size. In most cases a distinct thrill is felt on +placing the hand over the swelling, and a blowing, systolic murmur may +be heard with the stethoscope. It is to be borne in mind that +occasionally, when the interchange of blood between an aneurysm and the +artery from which it arises is small, pulsation and bruit may be slight +or even absent. This is also the case when the sac contains a +considerable quantity of clot. When it becomes filled with +clot--_consolidated aneurysm_--these signs disappear, and the clinical +features are those of a solid tumour lying in contact with an artery, +and transmitting its pulsation. + +A comparison of the pulse in the artery beyond the seat of the aneurysm +with that in the corresponding artery on the healthy side, shows that on +the affected side the wave is smaller in volume, and delayed in time. A +pulse tracing shows that the normal impulse and dicrotic waves are lost, +and that the force and rapidity of the tidal wave are diminished. + +[Illustration: FIG. 71.--Radiogram of Aneurysm of Aorta, showing +laminated clot and erosion of bodies of vertebrae. The intervertebral +discs are intact.] + +An aneurysm exerts pressure on the surrounding structures, which are +usually thickened and adherent to it and to one another. Adjacent veins +may be so compressed that congestion and oedema of the parts beyond are +produced. Pain, disturbances of sensation, and muscular paralyses may +result from pressure on nerves. Such bones as the sternum and vertebrae +undergo erosion and are absorbed by the gradually increasing pressure of +the aneurysm. Cartilage, on the other hand, being elastic, yields before +the pressure, so that the intervertebral discs or the costal cartilages +may escape while the adjacent bones are destroyed (Fig. 71). The skin +over the tumour becomes thinned and stretched, until finally a slough +forms, and when it separates haemorrhage takes place. + +[Illustration: FIG. 72.--Sacculated Aneurysm of Abdominal Aorta nearly +filled with laminated clot. Note greater density of clot towards +periphery.] + +In the progress of an aneurysm towards rupture, timely clotting may +avert death for the moment, but while extension in one direction has +been arrested there is apt to be extension in another, with imminence of +rupture, or it may be again postponed. + +#Differential Diagnosis.#--The diagnosis is to be made from other +pulsatile swellings. Pulsation is sometimes transmitted from a large +artery to a tumour, a mass of enlarged lymph glands, or an inflammatory +swelling which lies in its vicinity, but the pulsation is not +expansile--a most important point in differential diagnosis. Such +swellings may, by appropriate manipulation, be moved from the artery and +the pulsation ceases, and compression of the artery on the cardiac side +of the swelling, although it arrests the pulsation, does not produce any +diminution in the size or tension of the swelling, and when the pressure +is removed the pulsation is restored immediately. + +Fluid swellings overlying an artery, such as cysts, abscesses, or +enlarged bursae, may closely simulate aneurysm. An apparent expansion may +accompany the pulsation, but careful examination usually enables this to +be distinguished from the true expansion of an aneurysm. Compression of +the artery makes no difference in the size or tension of the swelling. + +Vascular tumours, such as sarcoma and goitre, may yield an expansile +pulsation and a soft, whifling bruit, but they differ from an aneurysm +in that they are not diminished in size by compression of the main +artery, nor can they be emptied by pressure. + +The exaggerated pulsation sometimes observed in the abdominal aorta, the +"pulsating aorta" seen in women, should not be mistaken for aneurysm. + +#Prognosis.#--When _natural cure_ occurs it is usually brought about by +the formation of laminated clot, which gradually increases in amount +till it fills the sac. Sometimes a portion of the clot in the sac is +separated and becomes impacted as an embolus in the artery beyond, +leading to thrombosis which first occludes the artery and then extends +into the sac. + +The progress of natural cure is indicated by the aneurysm becoming +smaller, firmer, less expansile, and less compressible; the murmur and +thrill diminish and the pressure effects become less marked. When the +cure is complete the expansile pulsation is lost, and there remains a +firm swelling attached to the vessel (_consolidated aneurysm_). While +these changes are taking place the collateral arteries become enlarged, +and an anastomotic circulation is established. + +An aneurysm may prove _fatal_ by exerting pressure on important +structures, by causing syncope, by rupture, or from the occurrence of +suppuration. _Pressure_ symptoms are usually most serious from aneurysms +situated in the neck, thorax, or skull. Sudden fatal _syncope_ is not +infrequent in cases of aneurysm of the thoracic aorta. + +_Rupture_ may take place through the skin, on a mucous or serous +surface, or into the cellular tissue. The first haemorrhage is often +slight and stops naturally, but it soon recurs, and is so profuse, +especially when the blood escapes externally, that it rapidly proves +fatal. When the bleeding takes place into the cellular tissue, the +aneurysm is said to become _diffused_, and the extravasated blood +spreads widely through the tissues, exerting great pressure on the +surrounding structures. + +The _clinical features_ associated with rupture are sudden and severe +pain in the part, and the patient becomes pale, cold, and faint. If a +comparatively small escape of blood takes place into the tissues, the +sudden alteration in the size, shape, and tension of the aneurysm, +together with loss of pulsation, may be the only local signs. When the +bleeding is profuse, however, the parts beyond the aneurysm become +greatly swollen, livid, and cold, and the pulse beyond is completely +lost. The arrest of the blood supply may result in gangrene. Sometimes +the pressure of the extravasated blood causes the skin to slough and, +later, give way, and fatal haemorrhage results. + +The _treatment_ is carried out on the same lines as for a ruptured +artery (p. 261), it being remembered, however, that the artery is +diseased and does not lend itself to reconstructive procedures. + +_Suppuration_ may occur in the vicinity of an aneurysm, and the aneurysm +may burst into the abscess which forms, so that when the latter points +the pus is mixed with broken-down blood-clot, and finally free +haemorrhage takes place. It has more than once happened that a surgeon +has incised such an abscess without having recognised its association +with aneurysm, with tragic results. + +#Treatment.#--In treating an aneurysm, the indications are to imitate +Nature's method of cure by means of laminated clot. + +_Constitutional treatment_ consists in taking measures to reduce the +arterial tension and to diminish the force of the heart's action. The +patient must be kept in bed. A dry and non-stimulating diet is +indicated, the quantity being gradually reduced till it is just +sufficient to maintain nutrition. Saline purges are employed to reduce +the vascular tension. The benefit derived from potassium iodide +administered in full doses, as first recommended by George W. Balfour, +probably depends on its depressing action on the heart and its +therapeutic benefit in syphilis. Pain or restlessness may call for the +use of opiates, of which heroin is the most efficient. + +_Local Treatment._--When constitutional treatment fails, local measures +must be adopted, and many methods are available. + +#Endo-aneurysmorrhaphy.#--The operation devised by Rudolf Matas in 1888 +aims at closing the opening between the sac and its feeding artery, and +in addition, folding the wall of the sac in such a way as to leave no +vacant space. If there is marked disease of the vessel, Matas' operation +is not possible and recourse is then had to ligation of the artery just +above the sac. + +_Extirpation of the Sac--The Old Operation._--The procedure which goes +by this name consists in exposing the aneurysm, incising the sac, +clearing out the clots, and ligating the artery above and below the sac. +This method is suitable to sacculated aneurysm of the limbs, so long as +they are circumscribed and free from complications. It has been +successfully practised also in aneurysm of the subclavian, carotid, and +external iliac arteries. It is not applicable to cases in which there is +such a degree of atheroma as would interfere with the successful +ligation of the artery. The continuity of the artery may be restored by +grafting into the gap left after excision of the sac a segment of the +great saphena vein. + +_Ligation of the Artery._--The object of tying the artery is to diminish +or to arrest the flow of blood through the aneurysm so that the blood +coagulates both in the sac and in the feeding artery. The ligature may +be applied on the cardiac side of the aneurysm--proximal ligation, or to +the artery beyond--distal ligation. + +_Proximal Ligation._--The ligature may be applied immediately above the +sac (Anel, 1710) or at a distance above (John Hunter, 1785). The +_Hunterian operation_ ensures that the ligature is applied to a part of +the artery that is presumably healthy and where relations are +undisturbed by the proximity of the sac; the best example is the +ligation of the superficial femoral artery in Scarpa's triangle or in +Hunter's canal for popliteal aneurysm; it is on record that Syme +performed this operation with cure of the aneurysm on thirty-nine +occasions. + +It is to be noted that the Hunterian ligature does not aim at +_arresting_ the flow of blood through the sac, but is designed so to +diminish its volume and force as to favour the deposition within the sac +of laminated clot. The development of the collateral circulation which +follows upon ligation of the artery at a distance above the sac may be +attended with just that amount of return stream which favours the +deposit of laminated clot, and consequently the cure of the aneurysm; +the return stream may, however, be so forcible as to prevent coagulation +of the blood in the sac, or only to allow of the formation of a red +thrombus which may in its turn be dispersed so that pulsation in the sac +recurs. This does not necessarily imply failure to cure, as the +recurrent pulsation may only be temporary; the formation of laminated +clot may ultimately take place and lead to consolidation of the +aneurysm. + +The least desirable result of the Hunterian ligature is met with in +cases where, owing to widespread arterial disease, the collateral +circulation does not develop and gangrene of the limb supervenes. + +_Anel's ligature_ is only practised as part of the operation which deals +with the sac directly. + +_Distal Ligation._--The tying of the artery beyond the sac, or of its +two branches where it bifurcates (Brasdor, 1760, and Wardrop, 1825), may +arrest or only diminish the flow of blood through the sac. It is less +successful than the proximal ligature, and is therefore restricted to +aneurysms so situated as not to be amenable to other methods; for +example, in aneurysm of the common carotid near its origin, the artery +may be ligated near its bifurcation, or in aneurysm of the innominate +artery, the carotid and subclavian arteries are tied at the seat of +election. + +_Compression._--Digital compression of the feeding artery has been given +up except as a preparation for operations on the sac with a view to +favouring the development of a collateral circulation. + +_Macewen's acupuncture or "needling"_ consists in passing one or more +fine, highly tempered steel needles through the tissues overlying the +aneurysm, and through its outer wall. The needles are made to touch the +opposite wall of the sac, and the pulsation of the aneurysm imparts a +movement to them which causes them to scarify the inner surface of the +sac. White thrombus forms on the rough surface produced, and leads to +further coagulation. The needles may be left in position for some hours, +being shifted from time to time, the projecting ends being surrounded +with sterile gauze. + +The _Moore-Corradi method_ consists in introducing through the wall of +the aneurysm a hollow insulated needle, through the lumen of which from +10 to 20 feet of highly drawn silver or other wire is passed into the +sac, where it coils up into an open meshwork (Fig. 73). The positive +pole of a galvanic battery is attached to the wire, and the negative +pole placed over the patient's back. A current, varying in strength from +20 to 70 milliamperes, is allowed to flow for about an hour. The hollow +needle is then withdrawn, but the wire is left _in situ_. The results +are somewhat similar to those obtained by needling, but the clot formed +on the large coil of wire is more extensive. + +[Illustration: FIG. 73.--Radiogram of Innominate Aneurysm after +treatment by the Moore-Corradi method. Two feet of finely drawn silver +wire were introduced. The patient, a woman, aet. 47, lived for ten months +after operation, free from pain (cf. Fig. 75).] + +Colt's method of wiring has been mainly used in the treatment of +abdominal aneurysm; gilt wire in the form of a wisp is introduced +through the cannula and expands into an umbrella shape. + +_Subcutaneous Injections of Gelatin._--Three or four ounces of a 2 per +cent. solution of white gelatin in sterilised water, at a temperature of +about 100 o F., are injected into the subcutaneous tissue of the abdomen +every two, three, or four days. In the course of a fortnight or three +weeks improvement may begin. The clot which forms is liable to soften +and be absorbed, but a repetition of the injection has in several cases +established a permanent cure. + +_Amputation of the limb_ is indicated in cases complicated by +suppuration, by secondary haemorrhage after excision or ligation, or by +gangrene. Amputation at the shoulder was performed by Fergusson in a +case of subclavian aneurysm, as a means of arresting the blood-flow +through the sac. + + +TRAUMATIC ANEURYSM + +The essential feature of a traumatic aneurysm is that it is produced by +some form of injury which divides all the coats of the artery. The walls +of the injured vessel are presumably healthy, but they form no part of +the sac of the aneurysm. The sac consists of the condensed and thickened +tissues around the artery. + +The injury to the artery may be a subcutaneous one such as a tear by a +fragment of bone: much more commonly it is a punctured wound from a stab +or from a bullet. + +The aneurysm usually forms soon after the injury is inflicted; the blood +slowly escapes into the surrounding tissues, gradually displacing and +condensing them, until they form a sac enclosing the effused blood. + +Less frequently a traumatic aneurysm forms some considerable time after +the injury, from gradual stretching of the fibrous cicatrix by which the +wound in the wall of the artery has been closed. The gradual stretching +of this cicatrix results in condensation of the surrounding structures +which form the sac, on the inner aspect of which laminated clot is +deposited. + +A traumatic aneurysm is almost always sacculated, and, so long as it +remains circumscribed, has the same characters as a pathological +sacculated aneurysm, with the addition that there is a scar in the +overlying skin. A traumatic aneurysm is liable to become diffuse--a +change which, although attended with considerable risk of gangrene, has +sometimes been the means of bringing about a cure. + +The treatment is governed by the same principles as apply to the +pathological varieties, but as the walls of the artery are not diseased, +operative measures dealing with the sac and the adjacent segment of the +affected artery are to be preferred. + + +ARTERIO-VENOUS ANEURYSM + +An abnormal communication between an artery and a vein constitutes an +arterio-venous aneurysm. Two varieties are recognised--one in which the +communication is direct--_aneurysmal varix_; the other in which the +vein communicates with the artery through the medium of a sac--_varicose +aneurysm_. + +Either variety may result from pathological causes, but in the majority +of cases they are traumatic in origin, being due to such injuries as +stabs, punctured wounds, and gun-shot injuries which involve both artery +and vein. In former times the most common situation was at the bend of +the elbow, the brachial artery being accidentally punctured in +blood-letting from the median basilic vein. Arterio-venous aneurysm is a +frequent result of injuries by modern high-velocity bullets--for +example, in the neck or groin. + +In _aneurysmal varix_ the higher blood pressure in the artery forces +arterial blood into the vein, which near the point of communication with +the artery tends to become dilated, and to form a thick-walled sac, +beyond which the vessel and its tributaries are distended and tortuous. +The clinical features resemble those associated with varicose veins, but +the entrance of arterial blood into the dilated veins causes them to +pulsate, and produces in them a vibratory thrill and a loud murmur. In +those at the groin, the distension of the veins may be so great that +they look like sinuses running through the muscles, a feature that must +be taken into account in any operation. + +As the condition tends to remain stationary, the support of an elastic +bandage is all that is required; but when the condition progresses and +causes serious inconvenience, it may be necessary to cut down and expose +the communication between the artery and vein, and, after separating the +vessels, to close the opening in each by suture; this may be difficult +or impossible if the parts are matted from former suppuration. If it is +impossible thus to obliterate the communication, the artery should be +ligated above and below the point of communication; although the risk of +gangrene is considerable unless means are taken to develop the +collateral circulation beforehand (Makins). + +_Varicose aneurysm_ usually develops in relation to a traumatic +aneurysm, the sac becoming adherent to an adjacent vein, and ultimately +opening into it. In this way a communication between the artery and the +vein is established, and the clinical features are those of a +combination of aneurysm and aneurysmal varix. + +As there is little tendency to spontaneous cure, and as the aneurysm is +liable to increase in size and finally to rupture, operative treatment +is usually called for. This is carried out on the same lines as for +aneurysmal varix, and at the same time incising the sac, turning out the +clots, and ligating any branches which open into the sac. If it can be +avoided, the vein should not be ligated. + + +ANEURYSMS OF INDIVIDUAL ARTERIES + +#Thoracic Aneurysm.#--All varieties of aneurysm occur in the aorta, the +fusiform being the most common, although a sacculated aneurysm +frequently springs from a fusiform dilatation. + +The _clinical features_ depend chiefly on the direction in which the +aneurysm enlarges, and are not always well marked even when the sac is +of considerable size. They consist in a pulsatile swelling--sometimes in +the supra-sternal notch, but usually towards the right side of the +sternum--with an increased area of dulness on percussion. With the +X-rays a dark shadow is seen corresponding to the sac. Pain is usually a +prominent symptom, and is largely referable to the pressure of the +aneurysm on the vertebrae or the sternum, causing erosion of these bones. +Pressure on the thoracic veins and on the air-passage causes cyanosis +and dyspnoea. When the oesophagus is pressed upon, the patient may have +difficulty in swallowing. The left recurrent nerve may be stretched or +pressed upon as it hooks round the arch of the aorta, and hoarseness of +the voice and a characteristic "brassy" cough may result from paralysis +of the muscles of the larynx which it supplies. The vagus, the phrenic, +and the spinal nerves may also be pressed upon. When the aneurysm is on +the transverse part of the arch, the trachea is pulled down with each +beat of the heart--a clinical phenomena known as the "tracheal tug." +Aneurysm of the descending aorta may, after eroding the bodies of the +vertebrae (Fig. 71) and posterior portions of the ribs, form a swelling +in the back to the left of the spine. + +Inasmuch as obliteration of the sac and the feeding artery is out of the +question, surgical treatment is confined to causing coagulation of the +blood in an extension or pouching of the sac, which, making its way +through the parietes of the chest, threatens to rupture externally. This +may be achieved by Macewen's needles or by the introduction of wire into +the sac. We have had cases under observation in which the treatment +referred to has been followed by such an amount of improvement that the +patient has been able to resume a laborious occupation for one or more +years. Christopher Heath found that improvement followed ligation of the +left common carotid in aneurysm of the transverse part of the aortic +arch. + +[Illustration: FIG. 74.--Thoracic Aneurysm, threatening to rupture +externally, but prevented from doing so by Macewen's needling. The +needles were left in for forty-eight hours.] + +#Abdominal Aneurysm.#--Aneurysm is much less frequent in the abdominal +than in the thoracic aorta. While any of the large branches in the +abdomen may be affected, the most common seats are in the aorta itself, +just above the origin of the coeliac artery and at the bifurcation. + +The _clinical features_ vary with the site of the aneurysm and with its +rapidity and direction of growth. A smooth, rounded swelling, which +exhibits expansile pulsation, forms, usually towards the left of the +middle line. It may extend upwards under cover of the ribs, downwards +towards the pelvis, or backward towards the loin. On palpation a +systolic thrill may be detected, but the presence of a murmur is neither +constant nor characteristic. Pain is usually present; it may be +neuralgic in character, or may simulate renal colic. When the aneurysm +presses on the vertebrae and erodes them, the symptoms simulate those of +spinal caries, particularly if, as sometimes happens, symptoms of +compression paraplegia ensue. In its growth the swelling may press upon +and displace the adjacent viscera, and so interfere with their +functions. + +The _diagnosis_ has to be made from solid or cystic tumours overlying +the artery; from a "pulsating aorta"; and from spinal caries; much help +is obtained by the use of the X-rays. + +The condition usually proves fatal, either by the aneurysm bursting into +the peritoneal cavity, or by slow leakage into the retro-peritoneal +tissue. + +The Moore-Corradi method has been successfully employed, access to the +sac having been obtained by opening the abdomen. Ligation of the aorta +has so far been unsuccessful, but in one case operated upon by Keen the +patient survived forty-eight days. + +#Innominate aneurysm# may be of the fusiform or of the sacculated +variety, and is frequently associated with pouching of the aorta. It +usually grows upwards and laterally, projecting above the sternum and +right clavicle, which may be eroded or displaced (Fig. 75). Symptoms of +pressure on the structures in the neck, similar to those produced by +aortic aneurysm, occur. The pulses in the right upper extremity and in +the right carotid and its branches are diminished and delayed. Pressure +on the right brachial plexus causes shooting pain down the arm and +muscular paresis on that side. Vaso-motor disturbances and contraction +of the pupil on the right side may result from pressure on the +sympathetic. Death may take place from rupture, or from pressure on the +air-passage. + +[Illustration: FIG. 75.--Innominate Aneurysm in a woman, aet. 47, eight +months after treatment by Moore-Corradi method (cf. Fig. 73).] + +The available methods of treatment are ligation of the right common +carotid and third part of the right subclavian (Wardrop's operation), of +which a number of successful cases have been recorded. Those most +suitable for ligation are cases in which the aneurysm is circumscribed +and globular (Sheen). If ligation is found to be impracticable, the +Moore-Corradi method or Macewen's needling may be tried. + +#Carotid Aneurysms.#--Aneurysm of the _common carotid_ is more frequent +on the right than on the left side, and is usually situated either at +the root of the neck or near the bifurcation. It is the aneurysm most +frequently met with in women. From its position the swelling is liable +to press on the vagus, recurrent and sympathetic nerves, on the +air-passage, and on the oesophagus, giving rise to symptoms referable to +such pressure. There may be cerebral symptoms from interference with the +blood supply of the brain. + +Aneurysm near the origin has to be diagnosed from subclavian, +innominate, and aortic aneurysm, and from other swellings--solid or +fluid--met with in the neck. It is often difficult to determine with +precision the trunk from which an aneurysm at the root of the neck +originates, and not infrequently more than one vessel shares in the +dilatation. A careful consideration of the position in which the +swelling first appeared, of the direction in which it has progressed, of +its pressure effects, and of the condition of the pulses beyond, may +help in distinguishing between aortic, innominate, carotid, and +subclavian aneurysms. Skiagraphy is also of assistance in recognising +the vessel involved. + +Tumours of the thyreoid, enlarged lymph glands, and fatty and +sarcomatous tumours can usually be distinguished from aneurysm by the +history of the swelling and by physical examination. Cystic tumours and +abscesses in the neck are sometimes more difficult to differentiate on +account of the apparently expansile character of the pulsation +transmitted to them. The fact that compression of the vessel does not +affect the size and tension of these fluid swellings is useful in +distinguishing them from aneurysm. + +_Treatment._--Digital compression of the vessel against the transverse +process of the sixth cervical vertebra--the "carotid tubercle"--has been +successfully employed in the treatment of aneurysm near the bifurcation. +Proximal ligation in the case of high aneurysms, or distal ligation in +those situated at the root of the neck, is more certain. Extirpation of +the sac is probably the best method of treatment, especially in those of +traumatic origin. These operations are attended with considerable risk +of hemiplegia from interference with the blood supply of the brain. + +The _external carotid_ and the cervical portion of the _internal +carotid_ are seldom the primary seat of aneurysm, although they are +liable to be implicated by the upward spread of an aneurysm at the +bifurcation of the common trunk. In addition to the ordinary signs of +aneurysm, the clinical manifestations are chiefly referable to pressure +on the pharynx and larynx, and on the hypoglossal nerve. Aneurysm of the +internal carotid is of special importance on account of the way in which +it bulges into the pharynx in the region of the tonsil, in some cases +closely simulating a tonsillar abscess. Cases are on record in which +such an aneurysm has been mistaken for an abscess and incised, with +disastrous results. + +_Aneurysmal varix_ may occur in the neck as a result of stabs or bullet +wounds. The communication is usually between the common carotid artery +and the internal jugular vein. The resulting interference with the +cerebral circulation causes headache, giddiness, and other brain +symptoms, and a persistent loud murmur is usually a source of annoyance +to the patient and may be sufficient indication for operative treatment. + +#Intracranial aneurysm# involves the internal carotid and its branches, +or the basilar artery, and appears to be more frequently associated with +syphilis and with valvular disease of the heart than are external +aneurysms. It gives rise to symptoms similar to those of other +intracranial tumours, and there is sometimes a loud murmur. It usually +proves fatal by rupture, and intracranial haemorrhage. The treatment is +to ligate the common carotid or the vertebral artery in the neck, +according to the seat of the aneurysm. + +#Orbital Aneurysm.#--The term pulsating exophthalmos is employed to +embrace a number of pathological conditions, including aneurysm, in +which the chief symptoms are pulsation in the orbit and protrusion of +the eyeball. There may be, in addition, congestion and oedema of the +eyelids, and a distinct thrill and murmur, which can be controlled by +compression of the common carotid in the neck. Varying degrees of ocular +paralysis and of interference with vision may also be present. + +These symptoms are due, in the majority of cases, to an aneurysmal varix +of the internal carotid artery and cavernous sinus, which is often +traumatic in origin, being produced either by fracture of the base of +the skull or by a punctured wound of the orbit. In other cases they are +due to aneurysm of the ophthalmic artery, to thrombosis of the cavernous +sinus, and, in rare instances, to cirsoid aneurysm. + +If compression of the common carotid is found to arrest the pulsation, +ligation of this vessel is indicated. + +#Subclavian Aneurysm.#--Subclavian aneurysm is usually met with in men +who follow occupations involving constant use of the shoulder--for +example, dock-porters and coal-heavers. It is more common on the right +side. + +The aneurysm usually springs from the third part of the artery, and +appears as a tense, rounded, pulsatile swelling just above the clavicle +and to the outer side of the sterno-mastoid muscle. It occasionally +extends towards the thorax, where it may become adherent to the pleura. +The radial pulse on the same side is small and delayed. Congestion and +oedema of the arm, with pain, numbness, and muscular weakness, may result +from pressure on the veins and nerves as they pass under the clavicle; +and pressure on the phrenic nerve may induce hiccough. The aneurysm is +of slow growth, and occasionally undergoes spontaneous cure. + +The conditions most likely to be mistaken for it are a soft, rapidly +growing sarcoma, and a normal artery raised on a cervical rib. + +On account of the relations of the artery and of its branches, treatment +is attended with greater difficulty and danger in subclavian than in +almost any other form of external aneurysm. The available operative +measures are proximal ligation of the innominate, and distal ligation. +In some cases it has been found necessary to combine distal ligation +with amputation at the shoulder-joint, to prevent the collateral +circulation maintaining the flow through the aneurysm. Matas' operation +has been successfully performed by Hogarth Pringle. + +#Axillary Aneurysm.#--This is usually met with in the right arm of +labouring men and sailors, and not infrequently follows an injury in the +region of the shoulder. The vessel may be damaged by the head of a +dislocated humerus or in attempts to reduce the dislocation, by the +fragments of a fractured bone, or by a stab or cut. Sometimes the vein +also is injured and an arterio-venous aneurysm established. + +Owing to the laxity of the tissues, it increases rapidly, and it may +soon attain a large size, filling up the axilla, and displacing the +clavicle upwards. This renders compression of the third part of the +subclavian difficult or impossible. It may extend beneath the clavicle +into the neck, or, extending inwards may form adhesions to the chest +wall, and, after eroding the ribs, to the pleura. + +The usual symptoms of aneurysm are present, and the pressure effects on +the veins and nerves are similar to those produced by an aneurysm of the +subclavian. Intra-thoracic complications, such as pleurisy or pneumonia, +are not infrequent when there are adhesions to the chest wall and +pleura. Rupture may take place externally, into the shoulder-joint, or +into the pleura. + +Extirpation of the sac is the operation of choice, but, if this is +impracticable, ligation of the third part of the subclavian may be had +recourse to. + +#Brachial aneurysm# usually occurs at the bend of the elbow, is of +traumatic origin, and is best treated by excision of the sac. + +_Aneurysmal varix_, which was frequently met with in this situation in +the days of the barber-surgeons,--usually as a result of the artery +having been accidentally wounded while performing venesection of the +median basilic vein,--may be treated, according to the amount of +discomfort it causes, by a supporting bandage, or by ligation of the +artery above and below the point of communication. + +Aneurysms of the vessels of the #forearm and hand# call for no special +mention; they are almost invariably traumatic, and are treated by +excision of the sac. + +#Inguinal Aneurysm# (_Aneurysm of the Iliac and Femoral +Arteries_).--Aneurysms appearing in the region of Poupart's ligament may +have their origin in the external or common iliac arteries or in the +upper part of the femoral. On account of the tension of the fascia lata, +they tend to spread upwards towards the abdomen, and, to a less extent, +downwards into the thigh. Sometimes a constriction occurs across the +sac at the level of Poupart's ligament. + +The pressure exerted on the nerves and veins of the lower extremity +causes pain, congestion, and oedema of the limb. Rupture may take place +externally, or into the cellular tissue of the iliac fossa. + +These aneurysms have to be diagnosed from pulsating sarcoma growing from +the pelvic bones, and from an abscess or a mass of enlarged lymph glands +overlying the artery and transmitting its pulsation. + +The method of treatment that has met with most success is ligation of +the common or external iliac, reached either by reflecting the +peritoneum from off the iliac fossa (extra-peritoneal operation), or by +going through the peritoneal cavity (trans-peritoneal operation). + +#Gluteal Aneurysm.#--An aneurysm in the buttock may arise from the +superior or from the inferior gluteal artery, but by the time it forms a +salient swelling it is seldom possible to recognise by external +examination in which vessel it takes origin. The special symptoms to +which it gives rise are pain down the limb from pressure on the sciatic +nerve, and interference with the movements at the hip. + +Ligation of the hypogastric (internal iliac) by the trans-peritoneal +route is the most satisfactory method of treatment. Extirpation of the +sac is difficult and dangerous, especially when the aneurysm has spread +into the pelvis. + +#Femoral Aneurysm.#--Aneurysm of the femoral artery beyond the origin of +the profunda branch is usually traumatic in origin, and is more common +in Scarpa's triangle than in Hunter's canal. Any of the methods already +described is available for their treatment--the choice lying between +Matas' operation and ligation of the external iliac. + +Aneurysm of the _profunda femoris_ is distinguished from that of the +main trunk by the fact that the pulses beyond are, in the former, +unaffected, and by the normal artery being felt pulsating over or +alongside the sac. + +In _aneurysmal varix_, a not infrequent result of a bullet wound or a +stab, the communication with the vein may involve the main trunk of the +femoral artery. Should operative interference become necessary as a +result of progressive increase in size of the tumour, or progressive +distension of the veins of the limb, an attempt should be made to +separate the vessels concerned and to close the opening in each by +suture. If this is impracticable, the artery is tied above and below the +communication; gangrene of the limb may supervene, and we have observed +a case in which the gangrene extended up to the junction of the middle +and lower thirds of the thigh, and in which recovery followed upon +amputation of the thigh. + +#Popliteal Aneurysm.#--This is the most common surgical aneurysm, and is +not infrequently met with in both limbs. It is generally due to disease +of the artery, and repeated slight strains, which are so liable to occur +at the knee, play an important part in its formation. In former times it +was common in post-boys, from the repeated flexion and extension of the +knee in riding. + +The aneurysm is usually of the sacculated variety, and may spring from +the front or from the back of the vessel. It may exert pressure on the +bones and ligaments of the joint, and it has been known to rupture into +the articulation. The pain, stiffness, and effusion into the joint which +accompany these changes often lead to an erroneous diagnosis of joint +disease. The sac may press upon the popliteal artery or vein and their +branches, causing congestion and oedema of the leg, and lead to gangrene. +Pressure on the tibial and common peroneal nerves gives rise to severe +pain, muscular cramp, and weakness of the leg. + +The differential diagnosis is to be made from abscess, bursal cyst, +enlarged glands, and sarcoma, especially pulsating sarcoma of one of the +bones entering into the knee joint. + +The choice of operation lies between ligation of the femoral artery in +Hunter's canal, and Matas' operation of aneurysmo-arteriorrhaphy. The +success which attends the Hunterian operation is evidenced by the fact +that Syme performed it thirty-seven times without a single failure. If +it fails, the old operation should be considered, but it is a more +serious operation, and one which is more liable to be followed by +gangrene of the limb. Experience shows that ligation of the vein, or +even the removal of a portion of it, is not necessarily followed by +gangrene. The risk of gangrene is diminished by a course of digital +compression of the femoral artery, before operating on the aneurysm. + +_Aneurysmal varix_ is sometimes met with in the region of the popliteal +space. It is characterised by the usual symptoms, and is treated by +palliative measures, or by ligation of the artery above and below the +point of communication. + +_Aneurysm_ in the #leg and foot# is rare. It is almost always traumatic, +and is treated by excision of the sac. + + + + +CHAPTER XV + +THE LYMPH VESSELS AND GLANDS + + +Anatomy and Physiology--INJURIES OF LYMPH VESSELS--_Wounds of + thoracic duct_--DISEASES OF LYMPH VESSELS--Lymphangitis: + _Varieties_--Lymphangiectasis--Filarial + disease--Lymphangioma--DISEASES OF LYMPH + GLANDS--Lymphadenitis: _Septic_; _Tuberculous_; + _Syphilitic_--Lymphadenoma--Leucocythaemia--TUMOURS. + +#Surgical Anatomy and Physiology.#--Lymph is essentially blood plasma, +which has passed through the walls of capillaries. After bathing +and nourishing the tissues, it is collected by lymph vessels, which +return it to the blood stream by way of the thoracic duct. These lymph +vessels take origin in the lymph spaces of the tissues and in the +walls of serous cavities, and they usually run alongside blood +vessels--_perivascular lymph vessels_. They have a structure similar to +that of veins, but are more abundantly provided with valves. Along the +course of the lymph trunks are the _lymph glands_, which possess a +definite capsule and are composed of a reticulated connective tissue, +the spaces of which are packed with leucocytes. The glands act as +filters, arresting not only inert substances, such as blood pigment +circulating in the lymph, but also living elements, such as cancer cells +or bacteria. As it passes through a gland the lymph is brought into +intimate contact with the leucocytes, and in bacterial infections there +is always a struggle between the organisms and the leucocytes, so that +the glands may be looked upon as an important line of defence, retarding +or preventing the passage of bacteria and their products into the +general circulation. The infective agent, moreover, in order to reach +the blood stream, must usually overcome the resistance of several +glands. + +Lymph glands are, for the most part, arranged in groups or chains, such +as those in the axilla, neck, and groin. In any given situation they +vary in number and size in different individuals, and fresh glands may +be formed on comparatively slight stimulus, and disappear when the +stimulus is withdrawn. The best-known example of this is the increase in +the number of glands in the axilla which takes place during lactation; +when this function ceases, many of the glands become involuted and are +transformed into fat, and in the event of a subsequent lactation they +are again developed. After glands have been removed by operation, new +ones may be formed. + +The following are the more important groups of glands, and the areas +drained by them in the head and neck and in the extremities. + +#Head and Neck.#--_The anterior auricular (parotid and pre-auricular) +glands_ lie beneath the parotid fascia in front of the ear, and some +are partly embedded in the substance of the parotid gland; they drain +the parts about the temple, cheek, eyelids, and auricle, and are +frequently the seat of tuberculous disease. _The occipital gland_, +situated over the origin of the trapezius from the superior curved line, +drains the top and back of the head; it is rarely infected. _The +posterior auricular (mastoid) glands_ lie over the mastoid process, and +drain the side of the head and auricle. These three groups pour their +lymph into the superficial cervical glands. _The submaxillary_--two to +six in number--lie along the lower order of the mandible from the +symphysis to the angle, the posterior ones (paramandibular) being +closely connected with the submaxillary salivary gland. They receive +lymph from the face, lips, floor of the mouth, gums, teeth, anterior +part of tongue, and the alae nasi, and from the pre-auricular glands. The +lymph passes from them into the deeper cervical glands. They are +frequently infected with tubercle, with epithelioma which has spread to +them from the mouth, and also with pyogenic organisms. _The submental +glands_ lie in or close to the median line between the anterior bellies +of the digastric muscles, and receive lymph from the lips. It is rare +for them to be the seat of tubercle, but in epithelioma of the lower lip +and floor of the mouth they are infected at an early stage of the +disease. _The supra-hyoid gland_ lies a little farther back, immediately +above the hyoid bone, and receives lymph from the tongue. _The +superficial cervical (external jugular) glands_, when present, lie along +the external jugular vein, and receives lymph from the occipital and +auricular glands and from the auricle. _The sterno-mastoid +glands_--glandulae concatinatae--form a chain along the posterior edge of +the sterno-mastoid muscle, some of them lying beneath the muscle. They +are commonly enlarged in secondary syphilis. _The superior deep cervical +(internal jugular) glands_--from six to twenty in number--form a +continuous chain along the internal jugular vein, beneath the +sterno-mastoid muscle. They drain the various groups of glands which lie +nearer the surface, also the interior of the skull, the larynx, trachea, +thyreoid, and lower part of the pharynx, and pour their lymph into the +main trunks at the root of the neck. Belonging to this group is one +large gland (the tonsillar gland) which lies behind the posterior belly +of the digastric, and rests in the angle between the internal jugular +and common facial veins. It is commonly enlarged in affections of the +tonsil and posterior part of the tongue. In the same group are three or +four glands which lie entirely under cover of the upper end of the +sterno-mastoid muscle, and surround the accessory nerve before it +perforates the muscle. The deep cervical glands are commonly infected by +tubercle and also by epithelioma secondary to disease in the tongue or +throat. _The inferior deep cervical (supra-clavicular) glands_ lie in +the posterior triangle, above the clavicle. They receive lymph from the +lowest cervical glands, from the upper part of the chest wall, and from +the highest axillary glands. They are frequently infected in cancer of +the breast; those on the left side also in cancer of the stomach. The +removal of diseased supra-clavicular glands is not to be lightly +undertaken, as difficulties are liable to ensue in connection with the +thoracic duct, the pleura, or the junction of the subclavian and +internal jugular veins. _The retro-pharyngeal glands_ lie on each side +of the median line upon the rectus capitis anticus major muscle and in +front of the pre-vertebral layer of the cervical fascia. They receive +part of the lymph from the posterior wall of the pharynx, the interior +of the nose and its accessory cavities, the auditory (Eustachian) tube, +and the tympanum. When they are infected with pyogenic organisms or +with tubercle bacilli, they may lead to the formation of one form of +retro-pharyngeal abscess. + +#Upper Extremity.#--_The epi-trochlear and cubital glands_ vary in +number, that most commonly present lying about an inch and a half above +the medial epi-condyle, and other and smaller glands may lie along the +medial (internal) bicipital groove or at the bend of the elbow. They +drain the ulnar side of the hand and forearm, and pour their lymph into +the axillary group. The epi-trochlear gland is sometimes enlarged in +syphilis. _The axillary glands_ are arranged in groups: a central group +lies embedded in the axillary fascia and fat, and is often related to an +opening in it; a posterior or subscapular group lies along the line of +the subscapular vessels; anterior or pectoral groups lie behind the +pectoralis minor, along the medial side of the axillary vein, and an +inter-pectoral group, between the two pectoral muscles. The axillary +glands receive lymph from the arm, mamma, and side of the chest, and +pass it on into the lowest cervical glands and the main lymph trunk. +They are frequently the seat of pyogenic, tuberculous, and cancerous +infection, and their complete removal is an essential part of the +operation for cancer of the breast. + +#Lower Extremity.#--_The popliteal glands_ include one superficial gland +at the termination of the small saphenous vein, and several deeper ones +in relation to the popliteal vessels. They receive lymph from the toes +and foot, and transmit it to the inguinal glands. _The femoral glands_ +lie vertically along the upper part of the great saphenous vein, and +receive lymph from the leg and foot; from them the lymph passes to the +deep inguinal and external iliac glands. The femoral glands often +participate in pyogenic infections entering through the skin of the toes +and sole of the foot. _The superficial inguinal glands_ lie along the +inguinal (Poupart's) ligament, and receive lymph from the external +genitals, anus, perineum, buttock, and anterior abdominal wall. The +lymph passes on to the deep inguinal and external iliac glands. The +superficial glands through their relations to the genitals are +frequently the subject of venereal infection, and also of epithelioma +when this disease affects the genitals or anus; they are rarely the seat +of tuberculosis. _The deep inguinal glands_ lie on the medial side of +the femoral vein, and sometimes within the femoral canal. They receive +lymph from the deep lymphatics of the lower limb, and some of the +efferent vessels from the femoral and superficial inguinal glands. The +lymph then passes on through the femoral canal to the external iliac +glands. The extension of malignant disease, whether cancer or sarcoma, +can often be traced along these deeper lymphatics into the pelvis, and +as the obstruction to the flow of lymph increases there is a +corresponding increase in the swollen dropsical condition of the lower +limb on the same side. + +The glands of the _thorax_ and _abdomen_ will be considered with the +surgery of these regions. + + +INJURIES OF LYMPH VESSELS + +Lymph vessels are divided in all wounds, and the lymph that escapes from +them is added to any discharge that may be present. In injuries of +larger trunks the lymph may escape in considerable quantity as a +colourless, watery fluid--_lymphorrhagia_; and the opening through which +it escapes is known as a _lymphatic fistula_. This has been observed +chiefly after extensive operation for the removal of malignant glands in +the groin where there already exists a considerable degree of +obstruction to the lymph stream, and in such cases the lymph, including +that which has accumulated in the vessels of the limb, may escape in +such abundance as to soak through large dressings and delay healing. +Ultimately new lymph channels are formed, so that at the end of from +four to six weeks the discharge of lymph ceases and the wound heals. + +_Lymphatic Oedema._--When the lymphatic return from a limb has been +seriously interfered with,--as, for example, when the axillary contents +has been completely cleared out in operating for cancer of the +breast,--a condition of lymphatic oedema may result, the arm becoming +swollen, tight, and heavy. + +Various degrees of the conditions are met with; in the severe forms, +there is pain, as well as incapacity of the limb. As in ordinary oedema, +the condition is relieved by elevation of the limb, but not nearly to +the same degree; in time the tissues become so hard and tense as +scarcely to pit on pressure; this is in part due to the formation of new +connective tissue and hypertrophy of the skin; in advanced cases there +is a gradual transition into one form of elephantiasis. + +Handley has devised a method of treatment--_lymphangioplasty_--the +object of which is to drain the lymph by embedding a number of silk +threads in the subcutaneous cellular tissue. + +#Wounds of the Thoracic Duct.#--The thoracic duct usually opens at the +angle formed by the junction of the left internal jugular and subclavian +veins, but it may open into either of these vessels by one or by several +channels, or the duct may be double throughout its course. There is a +smaller duct on the right side--the right lymphatic duct. The duct or +ducts may be displaced by a tumour or a mass of enlarged glands, and may +be accidentally wounded in dissections at the root of the neck; jets of +milky fluid--chyle--may at once escape from it. The jets are rhythmical +and coincide with expiration. The injury may, however, not be observed +at the time of operation, but later through the dressings being soaked +with chyle--_chylorrhoea_. If the wound involves the only existing main +duct and all the chyle escapes, the patient suffers from intense thirst, +emaciation, and weakness, and may die of inanition; but if, as is +usually the case, only one of several collateral channels is implicated, +the loss of chyle may be of little moment, as the discharge usually +ceases. If the wound heals so that the chyle is prevented from escaping, +a fluctuating swelling may form beneath the scar; in course of time it +gradually disappears. + +An attempt should be made to close the wound in the duct by means of a +fine suture; failing this, the duct must be occluded by a ligature as if +it were a bleeding artery. The tissues are then stitched over it and the +skin wound accurately closed, so as to obtain primary union, firm +pressure being applied by dressings and an elastic webbing bandage. Even +if the main duct is obliterated, a collateral circulation is usually +established. A wound of the right lymphatic duct is of less importance. + +_Subcutaneous rupture of the thoracic duct_ may result from a crush of +the thorax. The chyle escapes and accumulates in the cellular tissue of +the posterior mediastinum, behind the peritoneum, in the pleural cavity +(_chylo-thorax_), or in the peritoneal cavity (_chylous ascites_). There +are physical signs of fluid in one or other of these situations, but, as +a rule, the nature of the lesion is only recognised when chyle is +withdrawn by the exploring needle. + + +DISEASES OF LYMPH VESSELS + +#Lymphangitis.#--Inflammation of peripheral lymph vessels usually +results from some primary source of pyogenic infection in the skin. This +may be a wound or a purulent blister, and the streptococcus pyogenes is +the organism most frequently present. _Septic_ lymphangitis is commonly +met with in those who, from the nature of their occupation, handle +infective material. A _gonococcal_ form has been observed in those +suffering from gonorrhoea. + +The inflammation affects chiefly the walls of the vessels, and is +attended with clotting of the lymph. There is also some degree of +inflammation of the surrounding cellular tissue--_peri-lymphangitis_. +One or more abscesses may form along the course of the vessels, or a +spreading cellulitis may supervene. + +The _clinical features_ resemble those of other pyogenic infections, and +there are wavy red lines running from the source of infection towards +the nearest lymph glands. These correspond to the inflamed vessels, and +are the seat of burning pain and tenderness. The associated glands are +enlarged and painful. In severe cases the symptoms merge into those of +septicaemia. When the deep lymph vessels alone are involved, the +superficial red lines are absent, but the limb becomes greatly swollen +and pits on pressure. + +In cases of extensive lymphangitis, especially when there are repeated +attacks, the vessels are obliterated by the formation of new connective +tissue and a persistent solid oedema results, culminating in one form of +elephantiasis. + +_Treatment._--The primary source of infection is dealt with on the usual +lines. If the lymphangitis affects an extremity, Bier's elastic bandage +is applied, and if suppuration occurs, the pus is let out through one or +more small incisions; in other parts of the body Klapp's suction bells +are employed. An autogenous vaccine may be prepared and injected. When +the condition has subsided, the limb is massaged and evenly bandaged to +promote the disappearance of oedema. + +_Tuberculous Lymphangitis._--Although lymph vessels play an important +role in the spread of tuberculosis, the clinical recognition of the +disease in them is exceptional. The infection spreads upwards along the +superficial lymphatics, which become nodularly thickened; at one or more +points, larger, peri-lymphangitic nodules may form and break down into +abscesses and ulcers; the nearest group of glands become infected at an +early stage. When the disease is widely distributed throughout the +lymphatics of the limb, it becomes swollen and hard--a condition +illustrated by lupus elephantiasis. + +_Syphilitic lymphangitis_ is observed in cases of primary syphilis, in +which the vessels of the dorsum of the penis can be felt as indurated +cords. + +In addition to acting as channels for the conveyance of bacterial +infection, _lymph vessels frequently convey the cells of malignant +tumours_, and especially cancer, from the seat of the primary disease to +the nearest lymph glands, and they may themselves become the seat of +cancerous growth forming nodular cords. The permeation of cancer by way +of the lymphatics, described by Sampson Handley, has already been +referred to. + +#Lymphangiectasis# is a dilated or varicose condition of lymph vessels. +It is met with as a congenital affection in the tongue and lips, or it +may be acquired as the result of any condition which is attended with +extensive obliteration or blocking of the main lymph trunks. An +interesting type of lymphangiectasis is that which results from the +presence of the _filaria Bancrofti_ in the vessels, and is observed +chiefly in the groin, spermatic cord, and scrotum of persons who have +lived in the tropics. + +_Filarial disease in the lymphatics of the groin_ appears as a soft, +doughy swelling, varying in size from a walnut to a cocoa-nut; it may +partly disappear on pressure and when the patient lies down. + +The patient gives a history of feverish attacks of the nature of +lymphangitis during which the swelling becomes painful and tender. These +attacks may show a remarkable periodicity, and each may be followed by +an increase in the size of the swelling, which may extend along the +inguinal canal into the abdomen, or down the spermatic cord into the +scrotum. On dissection, the swelling is found to be made up of dilated, +tortuous, and thickened lymph vessels in which the parent worm is +sometimes found, and of greatly enlarged lymph glands which have +undergone fibrosis, with giant-cell formation and eosinophile +aggregations. The fluid in the dilated vessels is either clear or +turbid, in the latter case resembling chyle. The affection is frequently +bilateral, and may be associated with lymph scrotum, with elephantiasis, +and with chyluria. + +The _diagnosis_ is to be made from such other swellings in the groin as +hernia, lipoma, or cystic pouching of the great saphenous vein. It is +confirmed by finding the recently dead or dying worms in the inflamed +lymph glands. + +_Treatment._--When the disease is limited to the groin or scrotum, +excision may bring about a permanent cure, but it may result in the +formation of lymphatic sinuses and only afford temporary relief. + +#Lymphangioma.#--A lymphangioma is a swelling composed of a series of +cavities and channels filled with lymph and freely communicating with +one another. The cavities result either from the new formation of lymph +spaces or vessels, or from the dilatation of those which already exist; +their walls are composed of fibro-areolar tissue lined by endothelium +and strengthened by non-striped muscle. They are rarely provided with a +definite capsule, and frequently send prolongations of their substance +between and into muscles and other structures in their vicinity. They +are of congenital origin and usually make their appearance at or shortly +after birth. When the tumour is made up of a meshwork of caverns and +channels, it is called a _cavernous lymphangioma_; when it is composed +of one or more cysts, it is called a _cystic lymphangioma_. It is +probable that the cysts are derived from the caverns by breaking down +and absorption of the intervening septa, as transition forms between the +cavernous and cystic varieties are sometimes met with. + +The _cavernous lymphangioma_ appears as an ill-defined, soft swelling, +presenting many of the characters of a subcutaneous haemangioma, but it +is not capable of being emptied by pressure, it does not become tense +when the blood pressure is raised, as in crying, and if the tumour is +punctured, it yields lymph instead of blood. It also resembles a lipoma, +especially the congenital variety which grows from the periosteum, and +the differential diagnosis between these is rarely completed until the +swelling is punctured or explored by operation. If treatment is called +for, it is carried out on the same lines as for haemangioma, by means of +electrolysis, igni-puncture, or excision. Complete excision is rarely +possible because of the want of definition and encapsulation, but it is +not necessary for cure, as the parts that remain undergo cicatrisation. + +[Illustration: FIG. 76.--Congenital Cystic Tumour or Hygroma of Axilla. + +(From a photograph lent by Dr. Lediard.)] + +The _cystic lymphangioma_, _lymphatic cyst_, or _congenital cystic +hygroma_ is most often met with in the neck--_hydrocele of the neck_; it +is situated beneath the deep fascia, and projects either in front of or +behind the sterno-mastoid muscle. It may attain a large size, the +overlying skin and cyst wall may be so thin as to be translucent, and it +has been known to cause serious impairment of respiration through +pressing on the trachea. In the axilla also the cystic tumour may attain +a considerable size (Fig. 76); less frequent situations are the groin, +and the floor of the mouth, where it constitutes one form of ranula. + +The nature of these swellings is to be recognised by their situation, by +their having existed from infancy, and, if necessary, by drawing off +some of the contents of the cyst through a fine needle. They are usually +remarkably indolent, persisting often for a long term of years without +change, and, like the haemangioma, they sometimes undergo spontaneous +cicatrisation and cure. Sometimes the cystic tumour becomes infected and +forms an abscess--another, although less desirable, method of cure. +Those situated in the neck are most liable to suppurate, probably +because of pyogenic organisms being brought to them by the lymphatics +taking origin in the scalp, ear, or throat. + +If operative interference is called for, the cysts may be tapped and +injected with iodine, or excised; the operation for removal may entail a +considerable dissection amongst the deeper structures at the root of the +neck, and should not be lightly undertaken; parts left behind may be +induced to cicatrise by inserting a tube of radium and leaving it for a +few days. + +Lymphangiomas are met with in the abdomen in the form of _omental +cysts_. + + +DISEASES OF LYMPH GLANDS + +#Lymphadenitis.#--Inflammation of lymph glands results from the advent +of an irritant, usually bacterial or toxic, brought to the glands by the +afferent lymph vessels. These vessels may share in the inflammation and +be the seat of lymphangitis, or they may show no evidence of the passage +of the noxa. It is exceptional for the irritant to reach the gland +through the blood-stream. + +A strain or other form of trauma is sometimes blamed for the onset of +lymphadenitis, especially in the glands of the groin (bubo), but it is +usually possible to discover some source of pyogenic infection which is +responsible for the mischief, or to obtain a history of some antecedent +infection such as gonorrhoea. It is possible for gonococci to lie latent +in the inguinal glands for long periods, and only give rise to +lymphadenitis if the glands be subsequently subjected to injury. The +glands most frequently affected are those in the neck, axilla, and +groin. + +The characters of the lymphadenitis vary with the nature of the +irritant. Sometimes it is mild and evanescent, as in the glandular +enlargement in the neck which attends tonsillitis and other forms of +sore throat. Sometimes it is more persistent, as in the enlargement +that is associated with adenoids, hypertrophied tonsils, carious teeth, +eczema of the scalp, and otorrhoea; and it is possible that this indolent +enlargement predisposes to tuberculous infection. A similar enlargement +is met with in the axilla in cases of chronic interstitial mastitis, and +in the groin as a result of chronic irritation about the external +genitals, such as balanitis. + +Sometimes the lymphadenitis is of an acute character, and the tendency +is towards the formation of an abscess. This is illustrated in the +axillary glands as a result of infected wounds of the fingers; in the +femoral glands in infected wounds or purulent blisters on the foot; in +the inguinal glands in gonorrhoea and soft sore; and in the cervical +glands in the severer forms of sore throat associated with diphtheria +and scarlet fever. The most acute suppurations result from infection +with streptococci. + +Superficial glands, when inflamed and suppurating, become enlarged, +tender, fixed, and matted to one another. In the glands of the groin the +suppurative process is often remarkably sluggish; purulent foci form in +the interior of individual glands, and some time may elapse before the +pus erupts through their respective capsules. In the deeply placed +cervical glands, especially in cases of streptococcal throat infections, +the suppuration rapidly involves the surrounding cellular tissue, and +the clinical features are those of an acute cellulitis and deeply seated +abscess. When this is incised the necrosed glands may be found lying in +the pus, and on bacteriological examination are found to be swarming +with streptococci. In suppuration of the axillary glands the abscess may +be quite superficial, or it may be deeply placed beneath the strong +fascia and pectoral muscles, according to the group of glands involved. + +The _diagnosis_ of septic lymphadenitis is usually easy. The indolent +enlargements are not always to be distinguished, however, from +commencing tuberculous disease, except by the use of the tuberculin +test, and by the fact that they usually disappear on removing the +peripheral source of irritation. + +_Treatment._--The first indication is to discover and deal with the +source of infection, and in the indolent forms of lymphadenitis this +will usually be followed by recovery. In the acute forms following on +pyogenic infection, the best results are obtained from the hyperaemic +treatment carried out by means of suction bells. If suppuration is not +thereby prevented, or if it has already taken place, each separate +collection of pus is punctured with a narrow-bladed knife and the use of +the suction bell is persevered with. If there is a large periglandular +abscess, as is often the case, in the neck and axilla, the opening may +require to be made by Hilton's method, and it may be necessary to insert +a drainage-tube. + +[Illustration: FIG. 77.--Tuberculous Cervical Gland with abscess +formation in subcutaneous cellular tissue, in a boy aet. 10.] + +#Tuberculous Disease of Glands.#--This is a disease of great frequency +and importance. The tubercle bacilli usually gain access to the gland +through the afferent lymph vessels, which convey them from some lesion +of the surface within the area drained by them. Tuberculous infection +may supervene in glands that are already enlarged as a result of chronic +septic irritation. While any of the glands in the body may be affected, +the disease is most often met with in the cervical groups which derive +their lymph from the mouth, nose, throat, and ear. + +_The appearance of the glands on section_ varies with the stage of the +disease. In the early stages the gland is enlarged, it may be to many +times its natural size, is normal in appearance and consistence, and as +there is no peri-adenitis it is easily shelled out from its +surroundings. On microscopical examination, however, there is evidence +of infection in the shape of bacilli and of characteristic giant and +epithelioid cells. At a later stage, the gland tissue is studded with +minute yellow foci which tend to enlarge and in time to become +confluent, so that the whole gland is ultimately converted into a +caseous mass. This caseous material is surrounded by the thickened +capsule which, as a result of peri-adenitis, tends to become adherent to +and fused with surrounding structures, and particularly with layers of +fascia and with the walls of veins. The caseated tissue often remains +unchanged for long periods; it may become calcified, but more frequently +it breaks down and liquefies. + +#Tuberculous disease in the cervical glands# is a common accompaniment +or sequel of adenoids, enlarged tonsils, carious teeth, pharyngitis, +middle-ear disease, and conjunctivitis. These lesions afford the bacilli +a chance of entry into the lymph vessels, in which they are carried to +the glands, where they give rise to disease. + +The enlargement may affect only one gland, usually below the angle of +the mandible, and remain confined to it, the gland reaching the size of +a hazel-nut, and being ovoid, firm, and painless. More commonly the +disease affects several glands, on one or on both sides of the neck. +When the disease commences in the pre-auricular or submaxillary glands, +it tends to spread to those along the carotid sheath: when the posterior +auricular and occipital glands are first involved, the spread is to +those along the posterior border of the sterno-mastoid. In many cases +all the chains in front of, beneath, and behind this muscle are +involved, the enlarged glands extending from the mastoid to the +clavicle. They are at first discrete and movable, and may even vary in +size from time to time; but with the addition of peri-adenitis they +become fixed and matted together, forming lobulated or nodular masses +(Fig. 78). They become adherent not only to one another, but also to the +structures in their vicinity,--and notably to the internal jugular +vein,--a point of importance in regard to their removal by operation. + +At any stage the disease may be arrested and the glands remain for long +periods without further change. It is possible that the tuberculous +tissue may undergo cicatrisation. More commonly suppuration ensues, and +a cold abscess forms, but if there is a mixed infection, the pyogenic +factor being usually derived from the throat, it may take on active +features. + +[Illustration: FIG. 78.--Mass of Tuberculous Glands removed from Axilla +(cf. Fig. 79).] + +The transition from the solid to the liquefied stage is attended with +pain and tenderness in the gland, which at the same time becomes fixed +and globular, and finally fluctuation can be elicited. + +If left to itself, the softened tubercle erupts through the capsule of +the gland and infects the cellular tissue. The cervical fascia is +perforated and a cold abscess, often much larger than the gland from +which it took origin, forms between the fascia and the overlying skin. +The further stages--reddening, undermining of skin and external rupture, +with the formation of ulcers and sinuses--have been described with +tuberculous abscess. The ulcers and sinuses persist indefinitely, or +they heal and then break out again; sometimes the skin becomes infected, +and a condition like lupus spreads over a considerable area. Spontaneous +healing finally takes place after the caseous tubercle has been +extruded; the resulting scars are extremely unsightly, being puckered or +bridled, or hypertrophied like keloid. + +While the disease is most common in childhood and youth, it may be met +with even in advanced life; and although often associated with impaired +health and unhealthy surroundings, it may affect those who are +apparently robust and are in affluent circumstances. + +_Diagnosis._--The chief importance lies in differentiating tuberculous +disease from lympho-sarcoma and from lymphadenoma, and this is usually +possible from the history and from the nature of the enlargement. Signs +of liquefaction and suppuration support the diagnosis of tubercle. If +any doubt remains, one of the glands should be removed and submitted to +microscopical examination. Other forms of sarcoma, and the enlargement +of an accessory thyreoid, are less likely to be confused with +tuberculous glands. Calcified tuberculous glands give definite shadows +with the X-rays. + +Enlargement of the cervical glands from secondary cancer may simulate +tuberculosis, but is differentiated by its association with cancer in +the mouth or throat, and by the characteristic, stone-like induration of +epithelioma. + +The cold abscess which results from tuberculous glands is to be +distinguished from that due to disease in the cervical spine, +retro-pharyngeal abscess, as well as from congenital and other cystic +swellings in the neck. + +_Prognosis._--Next to lupus, glandular disease is of all tuberculous +lesions the least dangerous to life; but while it is the rule to recover +from tuberculous disease of glands with or without an operation, it is +unfortunately quite common for such persons to become the subjects of +tuberculosis in other parts of the body at any subsequent period of +life. + +_Treatment._--There is considerable difference of opinion regarding the +treatment of glandular tuberculosis. Some authorities, impressed with +the undoubted possibility of natural cure, are satisfied with promoting +this by measures directed towards improving the general health, by the +prolonged administration of tuberculin, and by repeated exposures to the +X-rays and to sunlight. Others again, influenced by the risk of +extension of the disease and by the destruction of tissue and +disfigurement caused by breaking down of the tuberculous tissue and +mixed infection, advocate the removal of the glands by operation. + +The conditions vary widely in different cases, and the treatment should +be adapted to the individual requirements. If the disease remains +confined to the glands originally infected and there are no signs of +breaking down, "expectant measures" may be persevered with. + +[Illustration: FIG. 79.--Tuberculous Axillary Glands (cf. Fig. 78).] + +If, on the other hand, the disease exhibits aggressive tendencies, the +question of operation should be considered. The undesirable results of +the breaking down and liquefaction of the diseased gland may be avoided +by the timely withdrawal of the fluid contents through a hollow needle. + +_The excision of tuberculous glands_ is often a difficult operation, +because of the number and deep situation of the glands to be removed, +and of the adhesions to surrounding structures. The skin incision must +be sufficiently extensive to give access to the whole of the affected +area, and to avoid disfigurement should, whenever possible, be made in +the line of the natural creases of the skin. In exposing the glands the +common facial and other venous trunks may require to be clamped and +tied. Care must be taken not to injure the important nerves, +particularly the accessory, the vagus, and the phrenic. The +inframaxillary branches of the facial, the hypoglossal and its +descending branches, and the motor branches of the deep cervical plexus, +are also liable to be injured. The dissection is rendered easier and is +attended with less risk of injury to the nerves, if the patient is +placed in the sitting posture so as to empty the veins, and, instead of +a knife, the conical scissors of Mayo are employed. When the glands are +extensively affected on both sides of the neck, it is advisable to allow +an interval to elapse rather than to operate on both sides at one +sitting. (_Op. Surg._, p. 189.) + +If the tonsils are enlarged they should not be removed at the same time, +as, by so doing, there is a risk of pyogenic infection from the throat +being carried to the wound in the neck, but they should be removed, +after an interval, to prevent relapse of disease in the glands. + +_When the skin is broken_ and caseous tuberculous tissue is exposed, +healing is promoted by cutting away diseased skin, removing the +granulation tissue with the spoon, scraping sinuses, and packing the +cavity with iodoform worsted and treating it by the open method and +secondary suture if necessary. Exposure to the sunshine on the seashore +and to the X-rays is often beneficial in these cases. + +#Tuberculous disease in the axillary glands# may be a result of +extension from those in the neck, from the mamma, ribs, or sternum, or +more rarely from the upper extremity. We have seen it from an infected +wound of a finger. In some cases no source of infection is discoverable. +The individual glands attain a considerable size, and they fuse together +to form a large tumour which fills up the axillary space. The disease +progresses more rapidly than it does in the cervical glands, and almost +always goes on to suppuration with the formation of sinuses. +Conservative measures need not be considered, as the only satisfactory +treatment is excision, and that without delay. + +#Tuberculous disease in the glands of the groin# is comparatively rare. +We have chiefly observed it in the femoral glands as a result of +inoculation tubercle on the toes or sole of the foot. The affected +glands nearly always break down and suppurate, and after destroying the +overlying skin give rise to fungating ulcers. The treatment consists in +excising the glands and the affected skin. The dissection may be +attended with troublesome haemorrhage from the numerous veins that +converge towards the femoral trunk. + +Tuberculous disease in the _mesenteric_ and _bronchial glands_ is +described with the surgery of regions. + +#Syphilitic Disease of Glands.#--Enlargement of lymph glands is a +prominent feature of acquired syphilis, especially in the form of the +indolent or bullet-bubo which accompanies the primary lesion, and the +general enlargement of glands that occurs in secondary syphilis. +Gummatous disease in glands is extremely rare; the affected gland +rapidly enlarges to the size of a walnut, and may then persist for a +long period without further change; if it breaks down, the overlying +skin is destroyed and the caseated tissue of the gumma exposed. + +#Lymphadenoma.#--_Hodgkin's Disease_ (Pseudo-leukaemia of German +authors).--This is a rare disease, the origin of which is as yet +unknown, but analogy would suggest that it is due to infection with a +slowly growing micro-organism. It is chiefly met with in young subjects, +and is characterised by a painless enlargement of a particular group of +glands, most commonly those in the cervical region (Fig. 80). + +[Illustration: FIG. 80.--Chronic Hodgkin's Disease in a boy aet. 11.] + +The glands are usually larger than in tuberculosis, and they remain +longer discrete and movable; they are firm in consistence, and on +section present a granular appearance due to overgrowth of the +connective-tissue framework. In time the glandular masses may form +enormous projecting tumours, the swelling being added to by lymphatic +oedema of the overlying cellular tissue and skin. + +The enlargement spreads along the chain of glands to those above the +clavicle, to those in the axilla, and to those of the opposite side +(Fig. 81). Later, the glands in the groin become enlarged, and it is +probable that the infection has spread from the neck along the +mediastinal, bronchial, retro-peritoneal, and mesenteric glands, and has +branched off to the iliac and inguinal groups. + +Two clinical types are recognised, one in which the disease progresses +slowly and remains confined to the cervical glands for two or more +years; the other, in which the disease is more rapidly disseminated and +causes death in from twelve to eighteen months. + +[Illustration: FIG. 81.--Lymphadenoma (Hodgkin's Disease) affecting left +side of neck and left axilla, in a woman aet. 44. Three years' duration.] + +In the acute form, the health suffers, there is fever, and the glands +may vary in size with variations in the temperature; the blood presents +the characters met with in secondary anaemia. The spleen, liver, testes, +and mammae may be enlarged; the glandular swellings press on important +structures, such as the trachea, oesophagus, or great veins, and symptoms +referable to such pressure manifest themselves. + +_Diagnosis._--Considerable difficulty attends the diagnosis of +lymphadenoma at an early stage. The negative results of tuberculin tests +may assist in the differentiation from tuberculous disease, but the more +certain means of excising one of the suspected glands and submitting it +to microscopical examination should be had recourse to. The sections +show proliferation of endothelial cells, the formation of numerous giant +cells quite unlike those of tuberculosis and a progressive fibrosis. +Lympho-sarcoma can usually be differentiated by the rapid assumption of +the local features of malignant disease, and in a gland removed for +examination, a predominance of small round cells with scanty protoplasm. +The enlargement associated with leucocythaemia is differentiated by the +characteristic changes in the blood. + +_Treatment._--In the acute form of lymphadenoma, treatment is of little +avail. Arsenic may be given in full doses either by the mouth or by +subcutaneous injection; the intravenous administration of neo-salvarsan +may be tried. Exposure to the X-rays and to radium has been more +successful than any other form of treatment. Excision of glands, +although sometimes beneficial, seldom arrests the progress of the +disease. The ease and rapidity with which large masses of glands may be +shelled out is in remarkable contrast to what is observed in tuberculous +disease. Surgical interference may give relief when important structures +are being pressed upon--tracheotomy, for example, may be required where +life is threatened by asphyxia. + +#Leucocythaemia.#--This is a disease of the blood and of the +blood-forming organs, in which there is a great increase in the number, +and an alteration of the character, of the leucocytes present in the +blood. It may simulate lymphadenoma, because, in certain forms of the +disease, the lymph glands, especially those in the neck, axilla, and +groin, are greatly enlarged. + + +TUMOURS OF LYMPH GLANDS + +#Primary Tumours.#--_Lympho-sarcoma_, which may be regarded as a sarcoma +starting in a lymph gland, appears in the neck, axilla, or groin as a +rapidly growing tumour consisting of one enlarged gland with numerous +satellites. As the tumour increases in size, the sarcomatous tissue +erupts through the capsule of the gland, and infiltrates the surrounding +tissues, whereby it becomes fixed to these and to the skin. + +[Illustration: FIG. 82.--Lympho-Sarcoma removed from Groin. It will be +observed that there is one large central parent tumour surrounded by +satellites.] + +The prognosis is grave in the extreme, and the only hope is in early +excision, followed by the use of radium and X-rays. We have observed a +case of lympho-sarcoma above the clavicle, in which excision of all that +was removable, followed by the insertion of a tube of radium for ten +days, was followed by a disappearance of the disease over a period which +extended to nearly five years, when death resulted from a tumour in the +mediastinum. In a second case in which the growth was in the groin, the +patient, a young man, remained well for over two years and was then lost +sight of. + +#Secondary Tumours.#--Next to tuberculosis, _secondary cancer_ is the +most common disease of lymph glands. In the neck it is met with in +association with epithelioma of the lip, tongue, or fauces. The glands +form tumours of variable size, and are often larger than the primary +growth, the characters of which they reproduce. The glands are at first +movable, but soon become fixed both to each other and to their +surroundings; when fixed to the mandible they form a swelling of +bone-like hardness; in time they soften, liquefy, and burst through the +skin, forming foul, fungating ulcers. A similar condition is met with in +the groin from epithelioma of the penis, scrotum, or vulva. In cancer of +the breast, the infection of the axillary glands is an important +complication. + +In _pigmented_ or _melanotic cancers_ of the skin, the glands are early +infected and increase rapidly, so that, when the primary growth is still +of small size--as, for example, on the sole of the foot--the femoral +glands may already constitute large pigmented tumours. + +[Illustration: FIG. 83.--Cancerous Glands in Neck secondary to +Epithelioma of Lip. + +(Mr. G. L. Chiene's case.)] + +The implication of the glands in other forms of cancer will be +considered with regional surgery. + +_Secondary sarcoma_ is seldom met with in the lymph glands except when +the primary growth is a lympho-sarcoma and is situated in the tonsil, +thyreoid, or testicle. + + + + +CHAPTER XVI + +THE NERVES + + +Anatomy--INJURIES OF NERVES: Changes in nerves after division; + Repair and its modifications; Clinical features; _Primary and + secondary suture_--SUBCUTANEOUS INJURIES OF + NERVES--DISEASES: _Neuritis_; _Tumours_--Surgery of + the individual nerves: _Brachial neuralgia_; _Sciatica_; + _Trigeminal neuralgia_. + +#Anatomy.#--A nerve-trunk is made up of a variable number of bundles of +nerve fibres surrounded and supported by a framework of connective +tissue. The nerve fibres are chiefly of the medullated type, and they +run without interruption from a nerve cell or _neuron_ in the brain or +spinal medulla to their peripheral terminations in muscle, skin, and +secretory glands. + +Each nerve fibre consists of a number of nerve fibrils collected into a +central bundle--the axis cylinder--which is surrounded by an envelope, +the neurolemma or sheath of Schwann. Between the neurolemma and the axis +cylinder is the medullated sheath, composed of a fatty substance known +as myelin. This medullated sheath is interrupted at the nodes of +Ranvier, and in each internode is a nucleus lying between the myelin and +the neurolemma. The axis cylinder is the essential conducting structure +of the nerve, while the neurolemma and the myelin act as insulating +agents. The axis cylinder depends for its nutrition on the central +neuron with which it is connected, and from which it originally +developed, and it degenerates if it is separated from its neuron. + +The connective-tissue framework of a nerve-trunk consists of the +_perineurium_, or general sheath, which surrounds all the bundles; the +_epineurium_, surrounding individual groups of bundles; and the +_endoneurium_, a delicate connective tissue separating the individual +nerve fibres. The blood vessels and lymphatics run in these +connective-tissue sheaths. + +According to Head and his co-workers, Sherren and Rivers, the afferent +fibres in the peripheral nerves can be divided into three systems:-- + +1. Those which subserve _deep sensibility_ and conduct the impulses +produced by pressure as well as those which enable the patient to +recognise the position of a joint on passive movement (joint-sensation), +and the kinaesthetic sense, which recognises that active contraction of +the muscle is taking place (active muscle-sensation). The fibres of this +system run with the motor nerves, and pass to muscles, tendons, and +joints. Even division of both the ulnar and the median nerves above the +wrist produces little loss of deep sensibility, unless the tendons are +also cut through. The failure to recognise this form of sensibility has +been largely responsible for the conflicting statements as to the +sensory phenomena following operations for the repair of divided nerves. + +2. Those which subserve _protopathic_ sensibility--that is, are capable +of responding to painful cutaneous stimuli and to the extremes of heat +and cold. These also endow the hairs with sensibility to pain. They are +the first to regenerate after division. + +3. Those which subserve _epicritic_ sensibility, the most highly +specialised, capable of appreciating light touch, _e.g._ with a wisp of +cotton wool, as a well-localised sensation, and the finer grades of +temperature, called cool and warm (72 o-104 o F.), and of discriminating +as separate the points of a pair of compasses 2 cms. apart. These are +the last to regenerate. + +A nerve also exerts a trophic influence on the tissues in which it is +distributed. + +The researches of Stoffel on the minute anatomy of the larger nerves, +and the disposition in them of the bundles of nerve fibres supplying +different groups of muscles, have opened up what promises to be a +fruitful field of clinical investigation and therapeutics. He has shown +that in the larger nerve-trunks the nerve bundles for special groups of +muscles are not, as was formerly supposed, arranged irregularly and +fortuitously, but that on the contrary the nerve fibres to a particular +group of muscles have a typical and practically constant position within +the nerve. + +In the large nerve-trunks of the limbs he has worked out the exact +position of the bundles for the various groups of muscles, so that in a +cross section of a particular nerve the component bundles can be +labelled as confidently and accurately as can be the cortical areas in +the brain. In the living subject, by using a fine needle-like electrode +and a very weak galvanic current, he has been able to differentiate the +nerve bundles for the various groups of muscles. In several cases of +spastic paralysis he succeeded in picking out in the nerve-trunk of the +affected limb the nerve bundles supplying the spastic muscles, and, by +resecting portions of them, in relieving the spasm. In a case of spastic +contracture of the pronator muscles of the forearm, for example, an +incision is made along the line of the median nerve above the bend of +the elbow. At the lateral side of the median nerve, where it lies in +contact with the biceps muscle, is situated a well-defined and easily +isolated bundle of fibres which supplies the pronator teres, the flexor +carpi radialis, and the palmaris longus muscles. On incising the sheath +of the nerve this bundle can be readily dissected up and its identity +confirmed by stimulating it with a very weak galvanic current. An inch +or more of the bundle is then resected. + + +INJURIES OF NERVES + +Nerves are liable to be cut or torn across, bruised, compressed, +stretched, or torn away from their connections with the spinal medulla. + +#Complete Division of a Mixed Nerve.#--Complete division is a common +result of accidental wounds, especially above the wrist, where the +ulnar, median, and radial nerves are frequently cut across, and in +gun-shot injuries. + +_Changes in Structure and Function._--The mere interruption of the +continuity of a nerve results in degeneration of its fibres, the myelin +being broken up into droplets and absorbed, while the axis cylinders +swell up, disintegrate, and finally disappear. Both the conducting and +the insulating elements are thus lost. The degeneration in the central +end of the divided nerve is usually limited to the immediate proximity +of the lesion, and does not even involve all the nerve fibres. In the +distal end, it extends throughout the entire peripheral distribution of +the nerve, and appears to be due to the cutting off of the fibres from +their trophic nerve cells in the spinal medulla. Immediate suturing of +the ends does not affect the degeneration of the distal segment. The +peripheral end undergoes complete degeneration in from six weeks to two +months. + +The physiological effects of complete division are that the muscles +supplied by the nerve are immediately paralysed, the area to which it +furnishes the sole cutaneous supply becomes insensitive, and the other +structures, including tendons, bones, and joints, lose sensation, and +begin to atrophy from loss of the trophic influence. + +#Nerves divided in Amputation.#--In the case of nerves divided in an +amputation, there is an active, although necessarily abortive, attempt +at regeneration, which results in the formation of bulbous swellings at +the cut ends of the nerves. When there has been suppuration, and +especially if the nerves have been cut so as to be exposed in the wound, +these bulbous swellings may attain an abnormal size, and are then known +as "amputation" or "stump neuromas" (Fig. 84). + +When the nerves in a stump have not been cut sufficiently short, they +may become involved in the cicatrix, and it may be necessary, on account +of pain, to free them from their adhesions, and to resect enough of the +terminal portions to prevent them again becoming adherent. When this is +difficult, a portion may be resected from each of the nerve-trunks at a +higher level; and if this fails to give relief, a fresh amputation may +be performed. When there is agonising pain dependent upon an ascending +neuritis, it may be necessary to resect the corresponding posterior +nerve roots within the vertebral canal. + +[Illustration: FIG. 84.--Stump Neuromas of Sciatic Nerve, excised forty +years after the original amputation by Mr. A. G. Miller.] + +#Other Injuries of Nerves.#--_Contusion_ of a nerve-trunk is attended +with extravasation of blood into the connective-tissue sheaths, and is +followed by degeneration of the contused nerve fibres. Function is +usually restored, the conducting paths being re-established by the +formation of new nerve fibres. + +When a nerve is _torn across_ or badly _crushed_--as, for example, by a +fractured bone--the changes are similar to those in a divided nerve, and +the ultimate result depends on the amount of separation between the ends +and the possibility of the young axis cylinders bridging the gap. + +_Involvement of Nerves in Scar Tissue._--Pressure or traction may be +exerted upon a nerve by contracting scar tissue, or a process of +neuritis or perineuritis may be induced. + +When terminal filaments are involved in a scar, it is best to dissect +out the scar, and along with it the ends of the nerves pressed upon. +When a nerve-trunk, such as the sciatic, is involved in cicatricial +tissue, the nerve must be exposed and freed from its surroundings +(_neurolysis_), and then stretched so as to tear any adhesions that may +be present above or below the part exposed. It may be advisable to +displace the liberated nerve from its original position so as to +minimise the risk of its incorporation in the scar of the original wound +or in that resulting from the operation--for example, the radial nerve +may be buried in the substance of the triceps, or it may be surrounded +by a segment of vein or portion of fat-bearing fascia. + +_Injuries of nerves resulting from_ #gun-shot wounds# include: (1) those +in which the nerve is directly damaged by the bullet, and (2) those in +which the nerve-trunk is involved secondarily either by scar tissue in +its vicinity or by callus following fracture of an adjacent bone. The +primary injuries include contusion, partial or complete division, and +perforation of the nerve-trunk. One of the most constant symptoms is the +early occurrence of severe neuralgic pain, and this is usually +associated with marked hyperaesthesia. + +#Regeneration.#--_Process of Repair when the Ends are in Contact._--_If +the wound is aseptic_, and the ends of the divided nerve are sutured or +remain in contact, they become united, and the conducting paths are +re-established by a regeneration of nerve fibres. There is a difference +of opinion as to the method of regeneration. The Wallerian doctrine is +that the axis cylinders in the central end grow downwards, and enter the +nerve sheaths of the distal portion, and continue growing until they +reach the peripheral terminations in muscle and skin, and in course of +time acquire a myelin sheath; the cells of the neurolemma multiply and +form long chains in both ends of the nerve, and are believed to provide +for the nourishment and support of the actively lengthening axis +cylinders. Another view is that the formation of new axis cylinders is +not confined to the central end, but that it goes on also in the +peripheral segment, in which, however, the new axis cylinders do not +attain maturity until continuity with the central end has been +re-established. + +_If the wound becomes infected_ and suppuration occurs, the young nerve +fibres are destroyed and efficient regeneration is prevented; the +formation of scar tissue also may constitute a permanent obstacle to new +nerve fibres bridging the gap. + +_When the ends are not in contact_, reunion of the divided nerve fibres +does not take place whether the wound is infected or not. At the +proximal end there forms a bulbous swelling, which becomes adherent to +the scar tissue. It consists of branching axis cylinders running in all +directions, these having failed to reach the distal end because of the +extent of the gap. The peripheral end is completely degenerated, and is +represented by a fibrous cord, the cut end of which is often slightly +swollen or bulbous, and is also incorporated with the scar tissue of +the wound. + +#Clinical Features.#--The symptoms resulting from division and non-union +of a nerve-trunk necessarily vary with the functions of the affected +nerve. The following description refers to a mixed sensori-motor trunk, +such as the median or radial (musculo-spiral) nerve. + +_Sensory Phenomena._--Superficial touch is tested by means of a wisp of +cotton wool stroked gently across the skin; the capacity of +discriminating two points as separate, by a pair of blunt-pointed +compasses; the sensation of pressure, by means of a pencil or other +blunt object; of pain, by pricking or scratching with a needle; and of +sensibility to heat and cold, by test-tubes containing water at +different temperatures. While these tests are being carried out, the +patient's eyes are screened off. + +After division of a nerve containing sensory fibres, there is an area of +absolute cutaneous insensibility to touch (anaesthesia), to pain +(analgesia), and to all degrees of temperature--_loss of protopathic +sensibility_; surrounded by an area in which there is loss of sensation +to light touch, inability to recognise minor differences of temperature +(72 o-104 o F.), and to appreciate as separate impressions the contact of +the two points of a compass--_loss of epicritic sensibility_ (Head and +Sherren) (Figs. 91, 92). + +_Motor Phenomena._--There is immediate and complete loss of voluntary +power in the muscles supplied by the divided nerve. The muscles rapidly +waste, and within from three to five days, they cease to react to the +faradic current. When tested with the galvanic current, it is found that +a stronger current must be used to call forth contraction than in a +healthy muscle, and the contraction appears first at the closing of the +circuit when the anode is used as the testing electrode. The loss of +excitability to the interrupted current, and the specific alteration in +the type of contraction with the constant current, is known as the +_reaction of degeneration_. After a few weeks all electric excitability +is lost. The paralysed muscles undergo fatty degeneration, which attains +its maximum three or four months after the division of the nerve. +Further changes may take place, and result in the transformation of the +muscle into fibrous tissue, which by undergoing shortening may cause +deformity known as _paralytic contracture_. + +_Vaso-motor Phenomena._--In the majority of cases there is an initial +rise in the temperature of the part (2 o to 3 o F.), with redness and +increased vascularity. This is followed by a fall in the local +temperature, which may amount to 8 o or 10 o F., the parts becoming pale +and cold. Sometimes the hyperaemia resulting from vaso-motor paralysis is +more persistent, and is associated with swelling of the parts from +oedema--the so-called _angio-neurotic oedema_. The vascularity varies with +external influences, and in cold weather the parts present a bluish +appearance. + +_Trophic Phenomena._--Owing to the disappearance of the subcutaneous +fat, the skin is smooth and thin, and may be abnormally dry. The hair is +harsh, dry, and easily shed. The nails become brittle and furrowed, or +thick and curved, and the ends of the fingers become club-shaped. Skin +eruptions, especially in the form of blisters, occur, or there may be +actual ulcers of the skin, especially in winter. In aggravated cases the +tips of the fingers disappear from progressive ulceration, and in the +sole of the foot a perforating ulcer may develop. Arthropathies are +occasionally met with, the joints becoming the seat of a painless +effusion or hydrops, which is followed by fibrous thickening of the +capsular and other ligaments, and terminates in stiffness and fibrous +ankylosis. In this way the fingers are seriously crippled and deformed. + +#Treatment of Divided Nerves.#--The treatment consists in approximating +the divided ends of the nerve and placing them under the most favourable +conditions for repair, and this should be done at the earliest possible +opportunity. (_Op. Surg._, pp. 45, 46.) + +#Primary Suture.#--The reunion of a recently divided nerve is spoken of +as primary suture, and for its success asepsis is essential. As the +suturing of the ends of the nerve is extremely painful, an anaesthetic is +required. + +When the wound is healed and while waiting for the restoration of +function, measures are employed to maintain the nutrition of the damaged +nerve and of the parts supplied by it. The limb is exercised, massaged, +and douched, and protected from cold and other injurious influences. The +nutrition of the paralysed muscles is further improved by electricity. +The galvanic current is employed, using at first a mild current of not +more than 5 milliamperes for about ten minutes, the current being made +to flow downwards in the course of the nerve, with the positive +electrode applied to the spine, and the negative over the affected nerve +near its termination. It is an advantage to have a metronome in the +circuit whereby the current is opened and closed automatically at +intervals, so as to cause contraction of the muscles. + +_The results_ of primary suture, when it has been performed under +favourable conditions, are usually satisfactory. In a series of cases +investigated by Head and Sherren, the period between the operation and +the first return of sensation averaged 65 days. According to Purves +Stewart protopathic sensation commences to appear in about six weeks and +is completely restored in six months; electric sensation and motor power +reappear together in about six months, and restoration is complete in a +year. When sensation returns, the area of insensibility to pain steadily +diminishes and disappears; sensibility to extremes of temperature +appears soon after; and last of all, after a considerable interval, +there is simultaneous return of appreciation of light touch, moderate +degrees of temperature, and the points of a compass. + +A clinical means of estimating how regeneration in a divided nerve is +progressing has been described by Tinel. He found that a tingling +sensation, similar to that experienced in the foot, when it is +recovering from the "sleeping" condition induced by prolonged pressure +on the sciatic nerve from sitting on a hard bench, can be elicited on +percussing over _growing_ axis cylinders. Tapping over the proximal end +of a _newly divided nerve_, _e.g._ the common peroneal behind the head +of the fibula, produces no tingling, but when in about three weeks +axis cylinders begin to grow in the proximal end-bulb, local tingling is +induced by tapping there. The downward growth of the axis cylinders can +be traced by tapping over the distal segment of the nerve, the tingling +sensation being elicited as far down as the young axis cylinders have +reached. When the regeneration of the axis cylinders is complete, +tapping no longer causes tingling. It usually takes about one hundred +days for this stage to be reached. + +Tinel's sign is present before voluntary movement, muscular tone, or the +normal electrical reactions reappear. + +In cases of complete nerve paralysis that have not been operated upon, +the tingling test is helpful in determining whether or not regeneration +is taking place. Its detection may prevent an unnecessary operation +being performed. + +Primary suture should not be attempted so long as the wound shows signs +of infection, as it is almost certain to end in failure. The ends should +be sutured, however, as soon as the wound is aseptic or has healed. + +#Secondary Suture.#--The term secondary suture is applied to the +operation of stitching the ends of the divided nerve after the wound has +healed. + +_Results of Secondary Suture._--When secondary suture has been performed +under favourable conditions, the prognosis is good, but a longer time is +required for restoration of function than after primary suture. Purves +Stewart says protopathic sensation is sometimes observed much earlier +than in primary suture, because partial regeneration of axis cylinders +in the peripheral segment has already taken place. Sensation is +recovered first, but it seldom returns before three or four months. +There then follows an improvement or disappearance of any trophic +disturbances that may be present. Recovery of motion may be deferred for +long periods--rather because of the changes in the muscles than from +want of conductivity in the nerve--and if the muscles have undergone +complete degeneration, it may never take place at all. While waiting for +recovery, every effort should be made to maintain the nutrition of the +damaged nerve, and of the parts which it supplies. + +When suture is found to be impossible, recourse must be had to other +methods, known as nerve bridging and nerve implantation. + +#Incomplete Division of a Mixed Nerve.#--The effects of partial division +of a mixed nerve vary according to the destination of the nerve bundles +that have been interrupted. Within their area of distribution the +paralysis is as complete as if the whole trunk had been cut across. The +uninjured nerve-bundles continue to transmit impulses with the result +that there is a _dissociated paralysis_ within the distribution of the +affected nerve, some muscles continuing to act and to respond normally +to electric stimulation, while others behave as if the whole nerve-trunk +had been severed. + +In addition to vasomotor and trophic changes, there is often severe pain +of a burning kind (_causalgia_ or _thermalgia_) which comes on about a +fortnight after the injury and causes intense and continuous suffering +which may last for months. Paroxysms of pain may be excited by the +slightest touch or by heat, and the patient usually learns for himself +that the constant application of cold wet cloths allays the pain. The +thermalgic area sweats profusely. + +Operative treatment is indicated where there is no sign of improvement +within three months, when recovery is arrested before complete +restoration of function is attained, or when thermalgic pain is +excessive. + +#Subcutaneous Injuries of Nerves.#--Several varieties of subcutaneous +injuries of nerves are met with. One of the best known is the +compression paralysis of the nerves of the upper arm which results from +sleeping with the arm resting on the back of a chair or the edge of a +table--the so-called "drunkard's palsy"; and from the pressure of a +crutch in the axilla--"crutch paralysis." In some of these injuries, +notably "drunkard's palsy," the disability appears to be due not to +damage of the nerve, but to overstretching of the extensors of the wrist +and fingers (Jones). A similar form of paralysis is sometimes met with +from the pressure of a tourniquet, from tight bandages or splints, from +the pressure exerted by a dislocated bone or by excessive callus, and +from hyper-extension of the arm during anaesthesia. + +In all these forms there is impaired sensation, rarely amounting to +anaesthesia, marked muscular wasting, and diminution or loss of voluntary +motor power, while--and this is a point of great importance--the normal +electrical reactions are preserved. There may also develop trophic +changes such as blisters, superficial ulcers, and clubbing of the tips +of the fingers. The prognosis is usually favourable, as recovery is the +rule within from one to three months. If, however, neuritis supervenes, +the electrical reactions are altered, the muscles degenerate, and +recovery may be retarded or may fail to take place. + +Injuries which act abruptly or instantaneously are illustrated in the +crushing of a nerve by the sudden displacement of a sharp-edged fragment +of bone, as may occur in comminuted fractures of the humerus. The +symptoms include perversion or loss of sensation, motor paralysis, and +atrophy of muscles, which show the reaction of degeneration from the +eighth day onwards. The presence of the reaction of degeneration +influences both the prognosis and the treatment, for it implies a lesion +which is probably incapable of spontaneous recovery, and which can only +be remedied by operation. + +The _treatment_ varies with the cause and nature of the lesion. When, +for example, a displaced bone or a mass of callus is pressing upon the +nerve, steps must be taken to relieve the pressure, by operation if +necessary. When there is reason to believe that the nerve is severely +crushed or torn across, it should be exposed by incision, and, after +removal of the damaged ends, should be united by sutures. When it is +impossible to make a definite diagnosis as to the state of the nerve, it +is better to expose it by operation, and thus learn the exact state of +affairs without delay; in the event of the nerve being torn, the ends +should be united by sutures. + +#Dislocation of Nerves.#--This injury, which resembles the dislocation +of tendons from their grooves, is seldom met with except in the ulnar +nerve at the elbow, and is described with injuries of that nerve. + + +DISEASES OF NERVES + +#Traumatic Neuritis.#--This consists in an overgrowth of the +connective-tissue framework of a nerve, which causes irritation and +pressure upon the nerve fibres, sometimes resulting in their +degeneration. It may originate in connection with a wound in the +vicinity of a nerve, as, for example, when the brachial nerves are +involved in scar tissue subsequent to an operation for clearing out the +axilla for cancer; or in contusion and compression of a nerve--for +example, by the pressure of the head of the humerus in a dislocation of +the shoulder. Some weeks or months after the injury, the patient +complains of increasing hyperaesthesia and of neuralgic pains in the +course of the nerve. The nerve is very sensitive to pressure, and, if +superficial, may be felt to be swollen. The associated muscles are +wasted and weak, and are subject to twitchings. There are also trophic +disturbances. It is rare to have complete sensory and motor paralysis. +The disease is commonest in the nerves of the upper extremity, and the +hand may become crippled and useless. + +_Treatment._--Any constitutional condition which predisposes to +neuritis, such as gout, diabetes, or syphilis, must receive appropriate +treatment. The symptoms may be relieved by rest and by soothing +applications, such as belladonna, ichthyol, or menthol, by the use of +hot-air and electric baths, and in obstinate cases by blistering or by +the application of Corrigan's button. When such treatment fails the +nerve may be stretched, or, in the case of a purely sensory trunk, a +portion may be excised. Local causes, such as involvement of the nerve +in a scar or in adhesions, may afford indications for operative +treatment. + +#Multiple Peripheral Neuritis.#--Although this disease mainly comes +under the cognizance of the physician, it may be attended with phenomena +which call for surgical interference. In this country it is commonly due +to alcoholism, but it may result from diabetes or from chronic poisoning +with lead or arsenic, or from bacterial infections and intoxications +such as occur in diphtheria, gonorrhoea, syphilis, leprosy, typhoid, +influenza, beri-beri, and many other diseases. + +It is, as a rule, widely distributed throughout the peripheral nerves, +but the distribution frequently varies with the cause--the alcoholic +form, for example, mainly affecting the legs, the diphtheritic form the +soft palate and pharynx, and that associated with lead poisoning the +forearms. The essential lesion is a degeneration of the conducting +fibres of the affected nerves, and the prominent symptoms are the result +of this. In alcoholic neuritis there is great tenderness of the muscles. +When the legs are affected the patient may be unable to walk, and the +toes may droop and the heel be drawn up, resulting in one variety of pes +equino-varus. Pressure sores and perforating ulcer of the foot are the +most important trophic phenomena. + +Apart from the medical _treatment_, measures must be taken to prevent +deformity, especially when the legs are affected. The bedclothes are +supported by a cage, and the foot maintained at right angles to the leg +by sand-bags or splints. When the disease is subsiding, the nutrition of +the damaged nerves and muscles should be maintained by massage, baths, +passive movements, and the use of the galvanic current. When deformity +has been allowed to take place, operative measures may be required for +its correction. + + +NEUROMA[5] + +[5] We have followed the classification adopted by Alexis Thomson in his +work _On Neuroma, and Neuro-fibromatosis_ (Edinburgh: 1900). + +Neuroma is a clinical term applied to all tumours, irrespective of their +structure, which have their seat in nerves. + +A tumour composed of newly formed nerve tissue is spoken of as a #true +neuroma#; when ganglionic cells are present in addition to nerve fibres, +the name _ganglionic neuroma_ is applied. These tumours are rare, and +are chiefly met with in the main cords or abdominal plexuses of the +sympathetic system of children or young adults. They are quite +insensitive, and their removal is only called for if they cause pain or +show signs of malignancy. + +A #false neuroma# is an overgrowth of the sheath of a nerve. This +overgrowth may result in the formation of a circumscribed tumour, or may +take the form of a diffuse fibromatosis. + +_The circumscribed or solitary tumour_ grows from the sheath of a nerve +which is otherwise healthy, and it may be innocent or malignant. + +_The innocent_ form is usually fibrous or myxomatous, and is definitely +encapsulated. It may become cystic as a result of haemorrhage or of +myxomatous degeneration. It grows very slowly, is usually elliptical in +shape, and the solid form is rarely larger than a hazel-nut. The nerve +fibres may be spread out all round the tumour, or may run only on one +side of it. When subcutaneous and related to the smaller unnamed +cutaneous nerves, it is known as a _painful subcutaneous nodule_ or +_tubercle_. It is chiefly met with about the ankle, and most often in +women. It is remarkably sensitive, even gentle handling causing intense +pain, which usually radiates to the periphery of the nerve affected. +When related to a deeper, named nerve-trunk, it is known as a +_trunk-neuroma_. It is usually less sensitive than the "subcutaneous +nodule," and rarely gives rise to motor symptoms unless it involves the +nerve roots where they pass through bony canals. + +A trunk-neuroma is recognised clinically by its position in the line of +a nerve, by the fact that it is movable in the transverse axis of the +nerve but not in its long axis, and by being unduly painful and +sensitive. + +[Illustration: FIG. 85.--Amputation Stump of Upper Arm, showing bulbous +thickening of the ends of the nerves, embedded in scar tissue at the +apex of the stamp.] + +_Treatment._--If the tumour causes suffering it should be removed, +preferably by shelling it out from the investing nerve sheath or +capsule. In the subcutaneous nodule the nerve is rarely recognisable, +and is usually sacrificed. When removal of the tumour is incomplete, a +tube of radium should be inserted into the cavity, to prevent recurrence +of the tumour in a malignant form. + +_The malignant neuroma_ is a sarcoma growing from the sheath of a nerve. +It has the same characters and clinical features as the innocent +variety, only it grows more rapidly, and by destroying the nerve fibres +causes motor symptoms--jerkings followed by paralysis. The sarcoma tends +to spread along the lymph spaces in the long axis of the nerve, as well +as to implicate the surrounding tissues, and it is liable to give rise +to secondary growths. The malignant neuroma is met with chiefly in the +sciatic and other large nerves of the limbs. + +The _treatment_ is conducted on the same lines as sarcoma in other +situations; the insertion of a tube of radium after removal of the +tumour diminishes the tendency to recurrence; a portion of the +nerve-trunk being sacrificed, means must be taken to bridge the gap. In +inoperable cases it may be possible to relieve pain by excising a +portion of the nerve above the tumour, or, when this is impracticable, +by resecting the posterior nerve roots and their ganglia within the +vertebral canal. + +The so-called _amputation neuroma_ has already been referred to (p. 344). + +_Diffuse or Generalised Neuro-Fibromatosis--Recklinghausen's +Disease._--These terms are now used to include what were formerly known +as "multiple neuromata," as well as certain other overgrowths related to +nerves. The essential lesion is an overgrowth of the endoneural +connective tissue throughout the nerves of both the cerebro-spinal and +sympathetic systems. The nerves are diffusely and unequally thickened, +so that small twigs may become enlarged to the size of the median, while +at irregular intervals along their course the connective-tissue +overgrowth is exaggerated so as to form tumour-like swellings similar to +the trunk-neuroma already described. The tumours, which vary greatly in +size and number--as many as a thousand have been counted in one +case--are enclosed in a capsule derived from the perineurium. The +fibromatosis may also affect the cranial nerves, the ganglia on the +posterior nerve roots, the nerves within the vertebral canal, and the +sympathetic nerves and ganglia, as well as the continuations of the +motor nerves within the muscles. The nerve fibres, although mechanically +displaced and dissociated by the overgrown endoneurium, undergo no +structural change except when compressed in passing through a bony +canal. + +The disease probably originates before birth, although it may not make +its appearance till adolescence or even till adult life. It is sometimes +met with in several members of one family. It is recognised clinically +by the presence of multiple tumours in the course of the nerves, and +sometimes by palpable enlargement of the superficial nerve-trunks +(Fig. 86). The tumours resemble the solitary trunk-neuroma, are usually +quite insensitive, and many of them are unknown to the patient. As a +result of injury or other exciting cause, however, one or other tumour +may increase in size and become extremely sensitive; the pain is then +agonising; it is increased by handling, and interferes with sleep. In +these conditions, a malignant transformation of the fibroma into sarcoma +is to be suspected. Motor disturbances are exceptional, unless in the +case of tumours within the vertebral canal, which press on the spinal +medulla and cause paraplegia. + +[Illustration: FIG. 86.--Diffuse enlargement of Nerves in generalised +Neuro-fibromatosis. + +(After R. W. Smith.)] + +Neuro-fibromatosis is frequently accompanied by _pigmentation of the +skin_ in the form of brown spots or patches scattered over the trunk. + +The disease is often stationary for long periods. In progressive cases +the patient becomes exhausted, and usually dies of some intercurrent +affection, particularly phthisis. The treatment is restricted to +relieving symptoms and complications; removal of one of the tumours is +to be strongly deprecated. + +In a considerable proportion of cases one of the multiple tumours takes +on the characters of a malignant growth ("secondary malignant neuroma," +Garre). This malignant transformation may follow upon injury, or on an +unsuccessful attempt to remove the tumour. The features are those of a +rapidly growing sarcoma involving a nerve-trunk, with agonising pain +and muscular cramps, followed by paralysis from destruction of the +nerve fibres. The removal of the tumour is usually followed by +recurrence, so that high amputation is the only treatment to be +recommended. Metastasis to internal organs is exceptional. + +[Illustration: FIG. 87.--Plexiform Neuroma of small Sciatic Nerve, from +a girl aet. 16. + +(Mr. Annandale's case.)] + +There are other types of neuro-fibromatosis which require brief mention. + +_The plexiform neuroma_ (Fig. 87) is a fibromatosis confined to the +distribution of one or more contiguous nerves or of a plexus of nerves, +and it may occur either by itself or along with multiple tumours of the +nerve-trunks and with pigmentation of the skin. The clinical features +are those of an ill-defined swelling composed of a number of tortuous, +convoluted cords, lying in a loose areolar tissue and freely movable on +one another. It is rarely the seat of pain or tenderness. It most often +appears in the early years of life, sometimes in relation to a pigmented +or hairy mole. It is of slow growth, may remain stationary for long +periods, and has little or no tendency to become malignant. It is +usually subcutaneous, and is frequently situated on the head or neck in +the distribution of the trigeminal or superficial cervical nerves. There +is no necessity for its removal, but this may be indicated because of +disfigurement, especially on the face or scalp or because its bulk +interferes with function. When involving the ophthalmic division of the +trigeminus, for example, it may cause enlargement of the upper lid and +proptosis, with danger to the function of the globe. The results of +excision are usually satisfactory, even if the removal is not complete. + +[Illustration: FIG. 88.--Multiple Neuro-fibromas of Skin (Molluscum +fibrosum, or Recklinghausen's disease).] + +_The cutaneous neuro-fibroma_ or _molluscum fibrosum_ has been shown by +Recklinghausen to be a soft fibroma related to the terminal filaments of +one of the cutaneous nerves (Fig. 88). The disease appears in the form +of multiple, soft, projecting tumours, scattered all over the body, +except the palms of the hands and soles of the feet. The tumours are of +all sizes, some being no larger than a pin's head, whilst many are as +big as a filbert and a few even larger. Many are sessile and others are +distinctly pedunculated, but all are covered with skin. They are mobile, +soft to the touch, and of the consistence of firm fat. In exceptional +cases one of the skin tumours may attain an enormous size and cause a +hideous deformity, hanging down by its own weight in lobulated or folded +masses (pachy-dermatocele). The treatment consists in removing the +larger swellings. In some cases molluscum fibrosum is associated with +pigmentation of the skin and with multiple tumours of the nerve-trunks. +The small multiple tumours rarely call for interference. + +[Illustration: FIG. 89.--Elephantiasis Neuromatosa in a woman aet. 28] + +_Elephantiasis neuromatosa_ is the name applied by Virchow to a +condition in which a limb is swollen and misshapen as a result of the +extension of a neuro-fibromatosis to the skin and subcutaneous cellular +tissue of the extremity as a whole (Fig. 89). It usually begins in early +life without apparent cause, and it may be associated with multiple +tumours of the nerve-trunks. The inconvenience caused by the bulk and +weight of the limb may justify its removal. + + +SURGERY OF THE INDIVIDUAL NERVES[6] + +[6] We desire here to acknowledge our indebtedness to Mr. James +Sherren's work on _Injuries of Nerves and their Treatment_. + +#The Brachial Plexus.#--Lesions of the brachial plexus may be divided +into those above the clavicle and those below that bone. + +In the #supra-clavicular injuries#, the violence applied to the head or +shoulder causes over-stretching of the anterior branches (primary +divisions) of the cervical nerves, the fifth, or the fifth and sixth +being those most liable to suffer. Sometimes the traction is exerted +upon the plexus from below, as when a man in falling from a height +endeavours to save himself by clutching at some projection, and the +lesion then mainly affects the first dorsal nerve. There is tearing of +the nerve sheaths, with haemorrhage, but in severe cases partial or +complete severance of nerve fibres may occur and these give way at +different levels. During the healing process an excess of fibrous tissue +is formed, which may interfere with regeneration. + +_Post-anaesthetic paralysis_ occurs in patients in whom, during the +course of an operation, the arm is abducted and rotated laterally or +extended above the head, causing over-stretching of the plexus, +especially of the fifth, or fifth and sixth, anterior branches. + +A _cervical rib_ may damage the plexus by direct pressure, the part +usually affected being the medial cord, which is made up of fibres from +the eighth cervical and first dorsal nerves. + +When a lesion of the plexus complicates a _fracture of the clavicle_, +the nerve injury is due, not to pressure on or laceration of the nerves +by fragments of bone, but to the violence causing the fracture, and this +is usually applied to the point of the shoulder. + +Penetrating _wounds_, apart from those met with in military practice, +are rare. + +In the #infra-clavicular injuries#, the lesion most often results from +the pressure of the dislocated head of the humerus; occasionally from +attempts made to reduce the dislocation by the heel-in-the-axilla +method, or from fracture of the upper end of the humerus or of the neck +of the scapula. The whole plexus may suffer, but more frequently the +medial cord is alone implicated. + +_Clinical Features._--Three types of lesion result from indirect +violence: the whole plexus; the upper-arm type; and the lower-arm type. + +_When the whole plexus is involved_, sensibility is lost over the entire +forearm and hand and over the lateral surface of the arm in its distal +two-thirds. All the muscles of the arm, forearm, and hand are paralysed, +and, as a rule, also the pectorals and spinati, but the rhomboids and +serratus anterior escape. There is paralysis of the sympathetic fibres +to the eye and orbit, with narrowing of the palpebral fissure, recession +of the globe, and the pupil is slow to dilate when shaded from the +light. + +The _upper-arm type_--Erb-Duchenne paralysis--is that most frequently +met with, and it is due to a lesion of the fifth anterior branch, or, it +may be, also of the sixth. The position of the upper limb is typical: +the arm and forearm hang close to the side, with the forearm extended +and pronated; the deltoid, spinati, biceps, brachialis, and supinators +are paralysed, and in some cases the radial extensors of the wrist and +the pronator teres are also affected. The patient is unable to supinate +the forearm or to abduct the arm, and in most cases to flex the forearm. +He may, however, regain some power of flexing the forearm when it is +fully pronated, the extensors of the wrist becoming feeble flexors of +the elbow. There is, as a rule, no loss of sensibility, but complaint +may be made of tickling and of pins-and-needles over the lateral aspect +of the arm. The abnormal position of the limb may persist although the +muscles regain the power of voluntary movement, and as the condition +frequently follows a fall on the shoulder, great care is necessary in +diagnosis, as the condition is apt to be attributed to an injury to the +axillary (circumflex) nerve. + +The _lower-arm type_ of paralysis, associated with the name of Klumpke, +is usually due to over-stretching of the plexus, and especially affects +the anterior branch of the first dorsal nerve. In typical cases all the +intrinsic muscles of the hand are affected, and the hand assumes the +claw shape. Sensibility is usually altered over the medial side of the +arm and forearm, and there is paralysis of the sympathetic. + +_Infra-clavicular injuries_, as already stated, are most often produced +by a sub-coracoid dislocation of the humerus; the medial cord is that +most frequently injured, and the muscles paralysed are those supplied by +the ulnar nerve, with, in addition, those intrinsic muscles of the hand +supplied by the median. Sensibility is affected over the medial surface +of the forearm and ulnar area of the hand. Injury of the lateral and +posterior cords is very rare. + +_Treatment_ is carried out on the lines already laid down for nerve +injuries in general. It is impossible to diagnose between complete and +incomplete rupture of the nerve cords, until sufficient time has elapsed +to allow of the establishment of the reaction of degeneration. If this +is present at the end of fourteen days, operation should not be delayed. +Access to the cords of the plexus is obtained by a dissection similar to +that employed for the subclavian artery, and the nerves are sought for +as they emerge from under cover of the scalenus anterior, and are then +traced until the seat of injury is found. In the case of the first +dorsal nerve, it may be necessary temporarily to resect the clavicle. +The usual after-treatment must be persisted in until recovery ensues, +and care must be taken that the paralysed muscles do not become +over-stretched. The prognosis is less favourable in the supra-clavicular +lesions than in those below the clavicle, which nearly always recover +without surgical intervention. + +In the _brachial birth-paralysis_ met with in infants, the lesion is due +to over-stretching of the plexus, and is nearly always of the +Erb-Duchenne type. The injury is usually unilateral, it occurs with +almost equal frequency in breech and in vertex presentations, and the +left arm is more often affected than the right. The lesion is seldom +recognised at birth. The first symptom noticed is tenderness in the +supra-clavicular region, the child crying when this part is touched or +the arm is moved. The attitude may be that of the Erb-Duchenne type, or +the whole of the muscles of the upper limb may be flaccid, and the arm +hangs powerless. A considerable proportion of the cases recover +spontaneously. The arm is to be kept at rest, with the affected muscles +relaxed, and, as soon as tenderness has disappeared, daily massage and +passive movements are employed. The reaction of degeneration can rarely +be satisfactorily tested before the child is three months old, but if it +is present, an operation should be performed. After operation, the +shoulder should be elevated so that no traction is exerted on the +affected cords. + +#The long thoracic nerve# (nerve of Bell), which supplies the serratus +anterior, is rarely injured. In those whose occupation entails carrying +weights upon the shoulder it may be contused, and the resulting +paralysis of the serratus is usually combined with paralysis of the +lower part of the trapezius, the branches from the third and fourth +cervical nerves which supply this muscle also being exposed to pressure +as they pass across the root of the neck. There is complaint of pain +above the clavicle, and winging of the scapula; the patient is unable to +raise the arm in front of the body above the level of the shoulder or to +perform any forward pushing movements; on attempting either of these the +winging of the scapula is at once increased. If the scapula is compared +with that on the sound side, it is seen that, in addition to the lower +angle being more prominent, the spine is more horizontal and the lower +angle nearer the middle line. The majority of these cases recover if the +limb is placed at absolute rest, the elbow supported, and massage and +galvanism persevered with. If the paralysis persists, the sterno-costal +portion of the pectoralis major may be transplanted to the lower angle +of the scapula. + +The long thoracic nerve may be cut across while clearing out the axilla +in operating for cancer of the breast. The displacement of the scapula +is not so marked as in the preceding type, and the patient is able to +perform pushing movements below the level of the shoulder. If the +reaction of degeneration develops, an operation may be performed, the +ends of the nerve being sutured, or the distal end grafted into the +posterior cord of the brachial plexus. + +#The Axillary (Circumflex) Nerve.#--In the majority of cases in which +paralysis of the deltoid follows upon an injury of the shoulder, it is +due to a lesion of the fifth cervical nerve, as has already been +described in injuries of the brachial plexus. The axillary nerve itself +as it passes round the neck of the humerus is most liable to be injured +from the pressure of a crutch, or of the head of the humerus in +sub-glenoid dislocation, or in fracture of the neck of the scapula or of +the humerus. In miners, who work for long periods lying on the side, the +muscle may be paralysed by direct pressure on the terminal filaments of +the nerve, and the nerve may also be involved as a result of disease in +the sub-deltoid bursa. + +The deltoid is wasted, and the acromion unduly prominent. In recent +cases paralysis of the muscle is easily detected. In cases of long +standing it is not so simple, because other muscles, the spinati, the +clavicular fibres of the pectoral and the serratus, take its place and +elevate the arm; there is always loss of sensation on the lateral aspect +of the shoulder. There is rarely any call for operative treatment, as +the paralysis is usually compensated for by other muscles. + +When the _supra-scapular nerve_ is contused or stretched in injuries of +the shoulder, the spinati muscles are paralysed and wasted, the spine of +the scapula is unduly prominent, and there is impairment in the power of +abducting the arm and rotating it laterally. + +The _musculo-cutaneous nerve_ is very rarely injured; when cut across, +there is paralysis of the coraco-brachialis, biceps, and part of the +brachialis, but no movements are abolished, the forearm being flexed, in +the pronated position, by the brachio-radialis and long radial extensor +of the wrist; in the supinated position, by that portion of the +brachialis supplied by the radial nerve. Supination is feebly performed +by the supinator muscle. Protopathic and epicritic sensibility are lost +over the radial side of the forearm. + +#Radial (Musculo-Spiral) Nerve.#--From its anatomical relationships this +trunk is more exposed to injury than any other nerve in the body. It is +frequently compressed against the humerus in sleeping with the arm +resting on the back of a chair, especially in the deep sleep of +alcoholic intoxication (drunkard's palsy). It may be pressed upon by a +crutch in the axilla, by the dislocated head of the humerus, or by +violent compression of the arm, as when an elastic tourniquet is applied +too tightly. The most serious and permanent injuries of this nerve are +associated with fractures of the humerus, especially those from direct +violence attended with comminution of the bone. The nerve may be crushed +or torn by one of the fragments at the time of the injury, or at a later +period may be compressed by callus. + +_Clinical Features._--Immediately after the injury it is impossible to +tell whether the nerve is torn across or merely compressed. The patient +may complain of numbness and tingling in the distribution of the +superficial branch of the nerve, but it is a striking fact, that so long +as the nerve is divided below the level at which it gives off the dorsal +cutaneous nerve of the forearm (external cutaneous branch), there is no +loss of sensation. When it is divided above the origin of the dorsal +cutaneous branch, or when the dorsal branch of the musculo-cutaneous +nerve is also divided, there is a loss of sensibility on the dorsum +of the hand. + +The motor symptoms predominate, the muscles affected being the extensors +of the wrist and fingers, and the supinators. There is a characteristic +"drop-wrist"; the wrist is flexed and pronated, and the patient is +unable to dorsiflex the wrist or fingers (Fig. 90). If the hand and +proximal phalanges are supported, the second and third phalanges may be +partly extended by the interossei and lumbricals. There is also +considerable impairment of power in the muscles which antagonise those +that are paralysed, so that the grasp of the hand is feeble, and the +patient almost loses the use of it; in some cases this would appear to +be due to the median nerve having been injured at the same time. + +[Illustration: FIG. 90.--Drop-wrist following Fracture of Shaft of +Humerus.] + +If the lesion is high up, as it is, for example, in crutch paralysis, +the triceps and anconeus may also suffer. + +_Treatment._--The slighter forms of injury by compression recover under +massage, douching, and electricity. If there is drop-wrist, the hand and +forearm are placed on a palmar splint, with the hand dorsiflexed to +nearly a right angle, and this position is maintained until voluntary +dorsiflexion at the wrist returns to the normal. Recovery is sometimes +delayed for several months. + +In the more severe injuries associated with fracture of the humerus and +attended with the reaction of degeneration, it is necessary to cut down +upon the nerve and free it from the pressure of a fragment of bone or +from callus or adhesions. If the nerve is torn across, the ends must be +sutured, and if this is impossible owing to loss of tissue, the gap may +be bridged by a graft taken from the superficial branch of the radial +nerve, or the ends may be implanted into the median. + +Finally, in cases in which the paralysis is permanent and incurable, the +disability may be relieved by operation. A fascial graft can be employed +to act as a ligament permanently extending the wrist; it is attached to +the third and fourth metacarpal bones distally and to the radius or ulna +proximally. The flexor carpi radialis can then be joined up with the +extensor digitorum communis by passing its tendon through an aperture in +the interosseous membrane, or better still, through the pronator +quadratus, as there is less likelihood of the formation of adhesions +when the tendon passes through muscle than through interosseous +membrane. The palmaris longus is anastomosed with the abductor pollicis +longus (extensor ossis metacarpi pollicis), thus securing a fair amount +of abduction of the thumb. The flexor carpi ulnaris may also be +anastomosed with the common extensor of the fingers. The extensors of +the wrist may be shortened, so as to place the hand in the position of +dorsal flexion, and thus improve the attitude and grasp of the hand. + +_The superficial branch of the radial_ (radial nerve) _and the deep +branch_ (posterior interosseous), apart from suffering in lesions of the +radial, are liable to be contused or torn is dislocation of the head of +the radius, and in fracture of the neck of the bone. The deep branch may +be divided as it passes through the supinator in operations on old +fractures and dislocations in the region of the elbow. Division of the +superficial branch in the upper two-thirds of the forearm produces no +loss of sensibility; division in the lower third after the nerve has +become associated with branches from the musculo-cutaneous is followed +by a loss of sensibility on the radial side of the hand and thumb. Wounds +on the dorsal surface of the wrist and forearm are often followed by +loss of sensibility over a larger area, because the musculo-cutaneous +nerve is divided as well, and some of the fibres of the lower lateral +cutaneous branch of the radial. + +[Illustration: FIG. 91.--To illustrate the Loss of Sensation produced by +Division of the Median Nerve. The area of complete cutaneous +insensibility is shaded black. The parts insensitive to light touch and +to intermediate degrees of temperature are enclosed within the dotted +line. + +(After Head and Sherren.)] + +#The Median Nerve# is most frequently injured in wounds made by broken +glass in the region of the wrist. It may also be injured in fractures of +the lower end of the humerus, in fractures of both bones of the forearm, +and as a result of pressure by splints. After _division at the elbow_, +there is impairment of mobility which affects the thumb, and to a less +extent the index finger: the terminal phalanx of the thumb cannot be +flexed owing to the paralysis of the flexor pollicis longus, and the +index can only be flexed at its metacarpo-phalangeal joint by the +interosseous muscles attached to it. Pronation of the forearm is feeble, +and is completed by the weight of the hand. After _division at the +wrist_, the abductor-opponens group of muscles and the two lateral +lumbricals only are affected; the abduction of the thumb can be feebly +imitated by the short extensor and the long abductor (ext. ossis +metacarpi pollicis), while opposition may be simulated by contraction of +the long flexor and the short abductor of the thumb; the paralysis of +the two medial lumbricals produces no symptoms that can be recognised. +It is important to remember that when the median nerve is divided at the +wrist, deep touch can be appreciated over the whole of the area +supplied by the nerve; the injury, therefore, is liable to be over +looked. If, however, the tendons are divided as well as the nerve, there +is insensibility to deep touch. The areas of epicritic and of +protopathic insensibility are illustrated in Fig. 91. The division of +the nerve at the elbow, or even at the axilla, does not increase the +extent of the loss of epicritic or protopathic sensibility, but usually +affects deep sensibility. + +[Illustration: FIG. 92.--To illustrate Loss of Sensation produced by +complete Division of Ulnar Nerve. Loss of all forms of cutaneous +sensibility is represented by the shaded area. The parts insensitive to +light touch and to intermediate degrees of heat and cold are enclosed +within the dotted line. + +(Head and Sherren.)] + +#The Ulnar Nerve.#--The most common injury of this nerve is its division +in transverse accidental wounds just above the wrist. In the arm it may +be contused, along with the radial, in crutch paralysis; in the region +of the elbow it may be injured in fractures or dislocations, or it may +be accidentally divided in the operation for excising the elbow-joint. + +When it is injured _at or above the elbow_, there is paralysis of the +flexor carpi ulnaris, the ulnar half of the flexor digitorum profundus, +all the interossei, the two medial lumbricals, and the adductors of the +thumb. The hand assumes a characteristic attitude: the index and middle +fingers are extended at the metacarpo-phalangeal joints owing to +paralysis of the interosseous muscles attached to them; the little and +ring fingers are hyper-extended at these joints in consequence of the +paralysis of the lumbricals; all the fingers are flexed at the +inter-phalangeal joints, the flexion being most marked in the little and +ring fingers--claw-hand or _main en griffe_. On flexing the wrist, the +hand is tilted to the radial side, but the paralysis of the flexor carpi +ulnaris is often compensated for by the action of the palmaris longus. +The little and ring fingers can be flexed to a slight degree by the +slips of the flexor sublimis attached to them and supplied by the median +nerve; flexion of the terminal phalanx of the little finger is almost +impossible. Adduction and abduction movements of the fingers are lost. +Adduction of the thumb is carried out, not by the paralysed adductor +pollicis, but the movement may be simulated by the long flexor and +extensor muscles of the thumb. Epicritic sensibility is lost over the +little finger, the ulnar half of the ring finger, and that part of the +palm and dorsum of the hand to the ulnar side of a line drawn +longitudinally through the ring finger and continued upwards. +Protopathic sensibility is lost over an area which varies in different +cases. Deep sensibility is usually lost over an area almost as extensive +as that of protopathic insensibility. + +When the nerve is _divided at the wrist_, the adjacent tendons are also +frequently severed. If divided below the point at which its dorsal +branch is given off, the sensory paralysis is much less marked, and the +injury is therefore liable to be overlooked until the wasting of muscles +and typical _main en griffe_ ensue. The loss of sensibility after +division of the nerve before the dorsal branch is given off resembles +that after division at the elbow, except that in uncomplicated cases +deep sensibility is usually retained. If the tendons are divided as +well, however, deep touch is also lost. + +Care must be taken in all these injuries to prevent deformity; a splint +must be worn, at least during the night, until the muscles regain their +power of voluntary movement, and then exercises should be instituted. + +#Dislocation of the ulnar nerve# at the elbow results from sudden and +violent flexion of the joint, the muscular effort causing stretching or +laceration of the fascia that holds the nerve in its groove; it is +predisposed to if the groove is shallow as a result of imperfect +development of the medial condyle of the humerus, and by cubitus valgus. + +The nerve slips forward, and may be felt lying on the medial aspect of +the condyle. It may retain this position, or it may slip backwards and +forwards with the movements of the arm. The symptoms at the time of the +displacement are some disability at the elbow, and pain and tingling +along the nerve, which are exaggerated by movement and by pressure. The +symptoms may subside altogether, or a neuritis may develop, with severe +pain shooting up the nerve. + +The dislocated nerve is easily replaced, but is difficult to retain in +position. In recent cases the arm may be placed in the extended position +with a pad over the condyle, care being taken to avoid pressure on the +nerve. Failing relief, it is better to make a bed for the nerve by +dividing the deep fascia behind the medial condyle and to stitch the +edges of the fascia over the nerve. This operation has been successful +in all the recorded cases. + +#The Sciatic Nerve.#--When this nerve is compressed, as by sitting on a +fence, there is tingling and powerlessness in the limb as a whole, known +as "sleeping" of the limb, but these phenomena are evanescent. _Injuries +to the great sciatic nerve_ are rare except in war. Partial division is +more common than complete, and it is noteworthy that the fibres destined +for the peroneal nerve are more often and more severely injured than +those for the tibial (internal popliteal). After complete division, all +the muscles of the leg are paralysed; if the section is in the upper +part of the thigh, the hamstrings are also paralysed. The limb is at +first quite powerless, but the patient usually recovers sufficiently to +be able to walk with a little support, and although the hamstrings are +paralysed the knee can be flexed by the sartorius and gracilis. The +chief feature is drop-foot. There is also loss of sensation below the +knee except along the course of the long saphenous nerve on the medial +side of the leg and foot. Sensibility to deep touch is only lost over a +comparatively small area on the dorsum of the foot. + +#The Common Peroneal (external popliteal) nerve# is exposed to injury +where it winds round the neck of the fibula, because it is superficial +and lies against the unyielding bone. It may be compressed by a +tourniquet, or it may be bruised or torn in fractures of the upper end +of the bone. It has been divided in accidental wounds,--by a scythe, for +example,--in incising for cellulitis, and in performing subcutaneous +tenotomy of the biceps tendon. Cases have been observed of paralysis of +the nerve as a result of prolonged acute flexion of the knee in certain +occupations. + +When the nerve is divided, the most obvious result is "drop-foot"; the +patient is unable to dorsiflex the foot and cannot lift his toes off the +ground, so that in walking he is obliged to jerk the foot forwards and +laterally. The loss of sensibility depends upon whether the nerve is +divided above or below the origin of the large cutaneous branch which +comes off just before it passes round the neck of the fibula. In course +of time the foot becomes inverted and the toes are pointed--pes +equino-varus--and trophic sores are liable to form. + +#The Tibial (internal popliteal) nerve# is rarely injured. + +#The Cranial nerves# are considered with affections of the head and neck +(Vol. II.). + + +NEURALGIA + +The term neuralgia is applied clinically to any pain which follows the +course of a nerve, and is not referable to any discoverable cause. It +should not be applied to pain which results from pressure on a nerve by +a tumour, a mass of callus, an aneurysm, or by any similar gross lesion. +We shall only consider here those forms of neuralgia which are amenable +to surgical treatment. + +#Brachial Neuralgia.#--The pain is definitely located in the +distribution of one of the branches or nerve roots, is often +intermittent, and is usually associated with tingling and disturbance of +tactile sensation. The root of the neck should be examined to exclude +pressure as the cause of the pain by a cervical rib, a tumour, or an +aneurysm. When medical treatment fails, the nerve-trunks may be injected +with saline solution or recourse may be had to operative measures, the +affected cords being exposed and stretched through an incision in the +posterior triangle of the neck. If this fails to give relief, the more +serious operation of resecting the posterior roots of the affected +nerves within the vertebral canal may be considered. + +_Neuralgia of the sciatic nerve_--#sciatica#--is the most common form of +neuralgia met with in surgical practice. + +It is chiefly met with in adults of gouty or rheumatic tendencies who +suffer from indigestion, constipation, and oxaluria--in fact, the same +type of patients who are liable to lumbago, and the two affections are +frequently associated. In hospital practice it is commonly met with in +coal-miners and others who assume a squatting position at work. The +onset of the pain may follow over-exertion and exposure to cold and wet, +especially in those who do not take regular exercise. Any error of diet +or indulgence in beer or wine may contribute to its development. + +The essential symptom is paroxysmal or continuous pain along the course +of the nerve in the buttock, thigh, or leg. It may be comparatively +slight, or it may be so severe as to prevent sleep. It is aggravated by +movement, so that the patient walks lame or is obliged to lie up. It is +aggravated also by any movement which tends to put the nerve on the +stretch, as in bending down to put on the shoes, such movements also +causing tingling down the nerve, and sometimes numbness in the foot. +This may be demonstrated by flexing the thigh on the abdomen, the knee +being kept extended; there is no pain if the same manoeuvre is repeated +with the knee flexed. The nerve is sensitive to pressure, the most +tender points being its emergence from the greater sciatic foramen, the +hollow between the trochanter and the ischial tuberosity, and where the +common peroneal nerve winds round the neck of the fibula. The muscles of +the thigh are often wasted and are liable to twitch. + +The clinical features vary a good deal in different cases; the affection +is often obstinate, and may last for many weeks or even months. + +In the sciatica that results from neuritis and perineuritis, there is +marked tenderness on pressure due to the involvement of the nerve +filaments in the sheath of the nerve, and there may be patches of +cutaneous anaesthesia, loss of tendon reflexes, localised wasting of +muscles, and vaso-motor and trophic changes. The presence of the +reaction of degeneration confirms the diagnosis of neuritis. In +long-standing cases the pain and discomfort may lead to a postural +scoliosis (_ischias-scoliotica_). + +_Diagnosis._--Pain referred along the course of the sciatic nerve on one +side, or, as is sometimes the case, on both sides, is a symptom of +tumours of the uterus, the rectum, or the pelvic bones. It may result +also from the pressure of an abscess or an aneurysm either inside the +pelvis or in the buttock, and is sometimes associated with disease of +the spinal medulla, such as tabes. Gluteal fibrositis may be mistaken +for sciatica. It is also necessary to exclude such conditions as disease +in the hip or sacro-iliac joint, especially tuberculous disease and +arthritis deformans, before arriving at a diagnosis of sciatica. A +digital examination of the rectum or vagina is of great value in +excluding intra-pelvic tumours. + +_Treatment_ is both general and local. Any constitutional tendency, such +as gout or rheumatism, must be counteracted, and indigestion, oxaluria, +and constipation should receive appropriate treatment. In acute cases +the patient is confined to bed between blankets, the limb is wrapped in +thermogene wool, and the knee is flexed over a pillow; in some cases +relief is experienced from the use of a long splint, or slinging the leg +in a Salter's cradle. A rubber hot-bottle may be applied over the seat +of greatest pain. The bowels should be well opened by castor oil or by +calomel followed by a saline. Salicylate of soda in full doses, or +aspirin, usually proves effectual in relieving pain, but when this is +very intense it may call for injections of heroin or morphin. Potassium +iodide is of benefit in chronic cases. + +Relief usually results from bathing, douching, and massage, and from +repeated gentle stretching of the nerve. This may be carried out by +passive movements of the limb--the hip being flexed while the knee is +kept extended; and by active movements--the patient flexing the limb at +the hip, the knee being maintained in the extended position. These +exercises, which may be preceded by massage, are carried out night and +morning, and should be practised systematically by those who are liable +to sciatica. + +Benefit has followed the injection into the nerve itself, or into the +tissues surrounding it, of normal saline solution; from 70-100 c.c. are +injected at one time. If the pain recurs, the injection may require to +be repeated on many occasions at different points up and down the nerve. +Needling or acupuncture consists in piercing the nerve at intervals in +the buttock and thigh with long steel needles. Six or eight needles are +inserted and left in position for from fifteen to thirty minutes. + +In obstinate and severe cases the nerve may be _forcibly stretched_. +This may be done bloodlessly by placing the patient on his back with the +hip flexed to a right angle, and then gradually extending the knee until +it is in a straight line with the thigh (Billroth). A general anaesthetic +is usually required. A more effectual method is to expose the nerve +through an incision at the fold of the buttock, and forcibly pull upon +it. This operation is most successful when the pain is due to the nerve +being involved in adhesions. + +#Trigeminal Neuralgia.#--A severe form of epileptiform neuralgia occurs +in the branches of the fifth nerve, and is one of the most painful +affections to which human flesh is liable. So far as its pathology is +known, it is believed to be due to degenerative changes in the semilunar +(Gasserian) ganglion. It is met with in adults, is almost invariably +unilateral, and develops without apparent cause. The pain, which occurs +in paroxysms, is at first of moderate severity, but gradually becomes +agonising. In the early stages the paroxysms occur at wide intervals, +but later they recur with such frequency as to be almost continuous. +They are usually excited by some trivial cause, such as moving the jaws +in eating or speaking, touching the face as in washing, or exposure to a +draught of cold air. Between the paroxysms the patient is free from +pain, but is in constant terror of its return, and the face wears an +expression of extreme suffering and anxiety. When the paroxysm is +accompanied by twitching of the facial muscles, it is called _spasmodic +tic_. + +The skin of the affected area may be glazed and red, or may be pale and +moist with inspissated sweat, the patient not daring to touch or wash +it. + +There is excessive tenderness at the points of emergence of the +different branches on the face, and pressure over one or other of these +points may excite a paroxysm. In typical cases the patient is unable to +take any active part in life. The attempt to eat is attended with such +severe pain that he avoids taking food. In some cases the suffering is +so great that the patient only obtains sleep by the use of hypnotics, +and he is often on the verge of suicide. + +_Diagnosis._--There is seldom any difficulty in recognising the disease. +It is important, however, to exclude the hysterical form of neuralgia, +which is characterised by its occurrence earlier in life, by the pain +varying in situation, being frequently bilateral, and being more often +constant than paroxysmal. + +_Treatment._--Before having recourse to the measures described below, it +is advisable to give a thorough trial to the medical measures used in +the treatment of neuralgia. + +_The Injection of Alcohol into the Nerve._--The alcohol acts by +destroying the nerve fibres, and must be brought into direct contact +with them; if the nerve has been properly struck the injection is +followed by complete anaesthesia in the distribution of the nerve. The +relief may last for from six months to three years; if the pain returns, +the injection may be repeated. The strength of the alcohol should be 85 +per cent., and the amount injected about 2 c.c.; a general, or +preferably a local, anaesthetic (novocain) should be employed +(Schlosser); the needle is 8 cm. long, and 0.7 mm. in diameter. The +severe pain which the alcohol causes may be lessened, after the needle +has penetrated to the necessary depth, by passing a few cubic +centimetres of a 2 per cent. solution of _novocain-suprarenin_ through +it before the alcohol is injected. The treatment by injection of alcohol +is superior to the resection of branches of the nerve, for though +relapses occur after the treatment with alcohol, renewed freedom from +pain may be obtained by its repetition. The ophthalmic division should +not, however, be treated in this manner, for the alcohol may escape into +the orbit and endanger other nerves in this region. Harris recommends +the injection of alcohol into the semilunar ganglion. + +_Operative Treatment._--This consists in the removal of the affected +nerve or nerves, either by resection--_neurectomy_; or by a combination +of resection with twisting or tearing of the nerve from its central +connections--_avulsion_. To prevent the regeneration of the nerve after +these operations, the canal of exit through the bone should be +obliterated; this is best accomplished by a silver screw-nail driven +home by an ordinary screw-driver (Charles H. Mayo). + +When the neuralgia involves branches of two or of all three trunks, or +when it has recurred after temporary relief following resection of +individual branches, the _removal of the semilunar ganglion_, along with +the main trunks of the maxillary and mandibular divisions, should be +considered. + +The operation is a difficult and serious one, but the results are +satisfactory so far as the cure of the neuralgia is concerned. There is +little or no disability from the unilateral paralysis of the muscles of +mastication; but on account of the insensitiveness of the cornea, the +eye must be protected from irritation, especially during the first month +or two after the operation; this may be done by fixing a large +watch-glass around the edge of the orbit with adhesive plaster. + +If the ophthalmic branch is not involved, neither it nor the ganglion +should be interfered with; the maxillary and mandibular divisions should +be divided within the skull, and the foramen rotundum and foramen ovale +obliterated. + + + + +CHAPTER XVII + +THE SKIN AND SUBCUTANEOUS TISSUE + + +Structure of skin--_Blisters_--_Callosities_--_Corns_--_Chilblains_ + --_Boils_--_Carbuncle_--_Abscess_--_Veldt sores_--Tuberculosis of + skin: _Inoculation tubercle_--_Lupus_: _Varieties_--Sporotrichosis + --Elephantiasis--Sebaceous cysts or wens--Moles--Horns--New growths: + _Fibroma_; _Papilloma_; _Adenoma_; _Epithelioma_; _Rodent cancer_; + _Melanotic cancer_; _Sarcoma_--AFFECTIONS OF CICATRICES--_Varieties + of scars_--_Keloid_--_Tumours_--AFFECTIONS OF NAILS. + +#Structure of Skin.#--The skin is composed of a superficial cellular +layer--the epidermis, and the corium or true skin. The _epidermis_ is +differentiated from without inwards into the stratum corneum, the +stratum lucidum, the stratum granulosum, and the rete Malpighii or +germinal layer, from which all the others are developed. The _corium_ or +_true skin_ consists of connective tissue, in which ramify the blood +vessels, lymphatics, and nerves. That part of the corium immediately +adjoining the epidermis is known as the papillary portion, and contains +the terminal loops of the cutaneous blood vessels and the terminations +of the cutaneous nerves. The deeper portion of the true skin is known as +the reticular portion, and is largely composed of adipose tissue. + +#Blisters# result from the exudation of serous fluid beneath the horny +layer of the epidermis. The fluid may be clear, as in the blisters of a +recent burn, or blood-stained, as in the blisters commonly accompanying +fractures of the leg. It may become purulent as a result of infection, +and this may be the starting-point of lymphangitis or cellulitis. + +The skin should be disinfected and the blisters punctured. When +infected, the separated horny layer must be cut away with scissors to +allow of the necessary purification. + +#Callosities# are prominent, indurated masses of the horny layer of the +epidermis, where it has been exposed to prolonged friction and pressure. +They occur on the fingers and hand as a result of certain occupations +and sports, but are most common under the balls of the toes or heel. A +bursa may form beneath a callosity, and if it becomes inflamed may cause +considerable suffering; if suppuration ensues, a sinus may form, +resembling a perforating ulcer of the foot. + +The _treatment_ of callosities on the foot consists in removing pressure +by wearing properly fitting boots, and in applying a ring pad around the +callosity; another method is to fit a sock of spongiopilene with a hole +cut out opposite the callosity. After soaking in hot water, the +overgrown horny layer is pared away, and the part painted daily with a +saturated solution of salicylic acid in flexile collodion. + +[Illustration: FIG. 93.--Callosities and Corns on the Sole and Plantar +Aspect of the Toes in a woman who was also the subject of flat-foot.] + +#Corns.#--A corn is a localised overgrowth of the horny layer of the +epidermis, which grows downwards, pressing upon and displacing the +sensitive papillae of the corium. Corns are due to the friction and +pressure of ill-fitting boots, and are met with chiefly on the toes and +sole of the foot. A corn is usually hard, dry, and white; but it may be +sodden from moisture, as in "soft corns" between the toes. A bursa may +form beneath a corn, and if inflamed constitutes one form of bunion. +When suppuration takes place in relation to a corn, there is great pain +and disability, and it may prove the starting-point of lymphangitis. + +The _treatment_ consists in the wearing of properly fitting boots and +stockings, and, if the symptoms persist, the corn should be removed. +This is done after the manner of chiropodists by digging out the corn +with a suitably shaped knife. A more radical procedure is to excise, +under local anaesthesia, the portion of skin containing the corn and +the underlying bursa. The majority of so-called corn solvents consist of +a solution of salicylic acid in collodion; if this is painted on daily, +the epidermis dies and can then be pared away. The unskilful paring of +corns may determine the occurrence of senile gangrene in those who are +predisposed to it by disease of the arteries. + +[Illustration: FIG. 94.--Ulcerated Chilblains on Fingers of a Child.] + +#Chilblains.#--Chilblain or _erythema pernio_ is a vascular disturbance +resulting from the alternate action of cold and heat on the distal parts +of the body. Chilblains are met with chiefly on the fingers and toes in +children and anaemic girls. In the mild form there is a sensation of +burning and itching, the part becomes swollen, of a dusky red colour, +and the skin is tense and shiny. In more severe cases the burning and +itching are attended with pain, and the skin becomes of a violet or +wine-red colour. There is a third degree, closely approaching +frost-bite, in which the skin tends to blister and give way, leaving an +indolent raw surface popularly known as a "broken chilblain." + +Those liable to chilblains should take open-air exercise, nourishing +food, cod-liver oil, and tonics. Woollen stockings and gloves should be +worn in cold weather, and sudden changes of temperature avoided. The +symptoms may be relieved by ichthyol ointment, glycerin and belladonna, +or a mixture of Venice turpentine, castor oil, and collodion applied on +lint which is wrapped round the toe. Another favourite application is +one of equal parts of tincture of capsicum and compound liniment of +camphor, painted over the area night and morning. Balsam of Peru or +resin ointment spread on gauze should be applied to broken chilblains. +The most effective treatment is Bier's bandage applied for about six +hours twice daily; it can be worn while the patient is following his +occupation; in chronic cases this may be supplemented with hot-air +baths. + +#Boils and Carbuncles.#--These result from infection with the +staphylococcus aureus, which enters the orifices of the ducts of the +skin under the influence of friction and pressure, as was demonstrated +by the well-known experiment of Garre, who produced a crop of pustules +and boils on his own forearm by rubbing in a culture of the +staphylococcus aureus. + +A #boil# results when the infection is located in a hair follicle or +sebaceous gland. A hard, painful, conical swelling develops, to which, +so long as the skin retains its normal appearance, the term "blind +boil" is applied. Usually, however, the skin becomes red, and after a +time breaks, giving exit to a drop or two of thick pus. After an +interval of from six to ten days a soft white slough is discharged; this +is known as the "core," and consists of the necrosed hair follicle or +sebaceous gland. After the separation of the core the boil heals +rapidly, leaving a small depressed scar. + +Boils are most frequently met with on the back of the neck and the +buttocks, and on other parts where the skin is coarse and thick and is +exposed to friction and pressure. The occurrence of a number or a +succession of boils is due to spread of the infection, the cocci from +the original boil obtaining access to adjacent hair follicles. The +spread of boils may be unwittingly promoted by the use of a domestic +poultice or the wearing of infected underclothing. + +While boils are frequently met with in debilitated persons, and +particularly in those suffering from diabetes or Bright's disease, they +also occur in those who enjoy vigorous health. They seldom prove +dangerous to life except in diabetic subjects, but when they occur on +the face there is a risk of lymphatic and of general pyogenic infection. +Boils may be differentiated from syphilitic lesions of the skin by +their acute onset and progress, and by the absence of other evidence of +syphilis; and from the malignant or anthrax pustule by the absence of +the central black eschar and of the circumstances which attend upon +anthrax infection. + +_Treatment._--The skin of the affected area should be painted with +iodine, and a Klapp's suction bell applied thrice daily. If pus forms, +the skin is frozen with ethyl-chloride and a small incision made, after +which the application of the suction bell is persevered with. The +further treatment consists in the use of diluted boracic or resin +ointment. In multiple boils on the trunk and limbs, lysol or boracic +baths are of service; the underclothing should be frequently changed, +and that which is discarded must be disinfected. In patients with +recurrence of boils about the neck, re-infection frequently takes place +from the scalp, to which therefore treatment should be directed. + +Any impaired condition of health should be corrected; when, there is +sugar or albumen in the urine the conditions on which these depend must +receive appropriate treatment. When there are successive crops of boils, +recourse should be had to vaccines. In refractory cases benefit has +followed the subcutaneous injection of lipoid solution containing tin. + +#Carbuncle# may be looked upon as an aggregation of boils, and is +characterised by a densely hard base and a brownish-red discoloration of +the skin. It is usually about the size of a crown-piece, but it may +continue to enlarge until it attains the size of a dinner-plate. The +patient is ill and feverish, and the pain may be so severe as to prevent +sleep. As time goes on several points of suppuration appear, and when +these burst there are formed a number of openings in the skin, giving it +a cribriform appearance; these openings exude pus. The different +openings ultimately fuse and the large adherent greyish-white slough is +exposed. The separation of the slough is a tedious process, and the +patient may become exhausted by pain, discharge, and toxin absorption. +When the slough is finally thrown off, a deep gap is left, which takes a +long time to heal. A large carbuncle is a grave disease, especially in a +weakly person suffering from diabetes or chronic alcoholism; we have on +several occasions seen diabetic coma supervene and the patient die +without recovering consciousness. In the majority of cases the patient +is laid aside for several months. It is most common in male adults over +forty years of age, and is usually situated on the back between the +shoulders. When it occurs on the face or anterior part of the neck it is +especially dangerous, because of the greater risk of dissemination of +the infection. + +A carbuncle is to be differentiated from an ulcerated gumma and from +anthrax pustule. + +[Illustration: FIG. 95.--Carbuncle of seventeen days' duration in a +woman aet. 57.] + +_Treatment._--Pain is relieved by full doses of opium or codein, and +these drugs are specially indicated when sugar is present in the urine. +Vaccines may be given a trial. The diet should be liberal and easily +digested, and strychnin and other stimulants may be of service. Locally +the treatment is carried out on the same lines as for boils. + +In some cases it is advisable to excise the carbuncle or to make +incisions across it in different directions, so that the resulting wound +presents a stellate appearance. + +#Acute Abscesses of the Skin and Subcutaneous Tissue in Young +Children.#--In young infants, abscesses are not infrequently met with +scattered over the trunk and limbs, and are probably the result of +infection of the sebaceous glands from dirty underclothing. The +abscesses should be opened, and the further spread of infection +prevented by cleansing of the skin and by the use of clean under-linen. +Similar abscesses are met with on the scalp in association with eczema, +impetigo, and pediculosis. + +#Veldt Sore.#--This sore usually originates in an abrasion of the +epidermis, such as a sun blister, the bite of an insect, or a scratch. A +pustule forms and bursts, and a brownish-yellow scab forms over it. When +this is removed, an ulcer is left which has little tendency to heal. +These sores are most common about the hands, arms, neck, and feet, and +are most apt to occur in those who have had no opportunities of washing, +and who have lived for a long time on tinned foods. + +#Tuberculosis of the Skin.#--Interest attaches chiefly to the primary +forms of tuberculosis of the skin in which the bacilli penetrate from +without--inoculation tubercle and lupus. + +#Inoculation Tubercle.#--The appearances vary with the conditions under +which the inoculation takes place. As observed on the fingers of adults, +the affection takes the form of an indolent painless swelling, the +epidermis being red and glazed, or warty, and irregularly fissured. +Sometimes the epidermis gives way, forming an ulcer with flabby +granulations. The infection rarely spreads to the lymphatics, but we +have seen inoculation tubercle of the index-finger followed by a large +cold abscess on the median side of the upper arm and by a huge mass of +breaking down glands in the axilla. + +In children who run about barefooted in towns, tubercle may be +inoculated into wounds in the sole or about the toes, and although the +local appearances may not be characteristic, the nature of the infection +is revealed by its tendency to spread up the limb along the lymph +vessels, giving rise to abscesses and fungating ulcers in relation to +the femoral glands. + +#Tuberculous Lupus.#--This is an extremely chronic affection of the +skin. It rarely extends to the lymph glands, and of all tuberculous +lesions is the least dangerous to life. The commonest form of +lupus--_lupus vulgaris_--usually commences in childhood or youth, and is +most often met with on the nose or cheek. The early and typical +appearance is that of brownish-yellow or pink nodules in the skin, about +the size of hemp seed. Healing frequently occurs in the centre of the +affected area while the disease continues to extend at the margin. + +When there is actual destruction of tissue and ulceration--the so-called +"_lupus excedens_" or "_ulcerans_"--healing is attended with +cicatricial contraction, which may cause unsightly deformity. When the +cheek is affected, the lower eyelid may be drawn down and everted; when +the lips are affected, the mouth may be distorted or seriously +diminished in size. When the nose is attacked, both the skin and mucous +surfaces are usually involved, and the nasal orifices may be narrowed or +even obliterated; sometimes the soft parts, including the cartilages, +are destroyed, leaving only the bones covered by tightly stretched scar +tissue. + +The disease progresses slowly, healing in some places and spreading at +others. The patient complains of a burning sensation, but little of +pain, and is chiefly concerned about the disfigurement. Nothing is more +characteristic of lupus than the appearance of fresh nodules in parts +which have already healed. In the course of years large tracts of the +face and neck may become affected. From the lips it may spread to the +gum and palate, giving to the mucous membrane the appearance of a +raised, bright-red, papillary or villous surface. When the disease +affects the gums, the teeth may become loose and fall out. + +[Illustration: FIG. 96.--Tuberculous Elephantiasis in a woman aet. 35.] + +On parts of the body other than the face, the disease is even more +chronic, and is often attended with a considerable production of dense +fibrous tissue--the so-called _fibroid lupus_. Sometimes there is a +warty thickening of the epidermis--_lupus verrucosus_. In the fingers +and toes it may lead to a progressive destruction of tissue like that +observed in leprosy, and from the resulting loss of portions of the +digits it has been called _lupus mutilans_. In the lower extremity a +remarkable form of the disease is sometimes met with, to which the term +_lupus elephantiasis_ (Fig. 96) has been applied. It commences as an +ordinary lupus of the toes or dorsum of the foot, from which the +tuberculous infection spreads to the lymph vessels, and the limb as a +whole becomes enormously swollen and unshapely. + +Finally, a long-standing lupus, especially on the cheek, may become the +seat of epithelioma--_lupus epithelioma_--usually of the exuberant or +cauliflower type, which, like other epitheliomas that originate in scar +tissue, presents little tendency to infect the lymphatics. + +The _diagnosis_ of lupus is founded on the chronic progress and long +duration, and the central scarring with peripheral extension of the +disease. On the face it is most liable to be confused with syphilis and +with rodent cancer. The syphilitic lesion belongs to the tertiary +period, and although presenting a superficial resemblance to +tuberculosis, its progress is more rapid, so that within a few months it +may involve an area of skin as wide as would be affected by lupus in as +many years. Further, it readily yields to anti-syphilitic treatment. In +cases of tertiary syphilis in which the nose is destroyed, it will be +noticed that the bones have suffered most, while in lupus the +destruction of tissue involves chiefly the soft parts. + +Rodent cancer is liable to be mistaken for lupus, because it affects the +same parts of the face; it is equally chronic, and may partly heal. It +begins later in life, however, the margin of the ulcer is more sharply +defined, and often presents a "rolled" appearance. + +_Treatment._--When the disease is confined to a limited area, the most +rapid and certain cure is obtained by _excision_; larger areas are +scraped with the sharp spoon. The _ray treatment_ includes the use of +luminous, Rontgen, or radium rays, and possesses the advantage of being +comparatively painless and of being followed by the least amount of +scarring and deformity. + +Encouraging results have also been obtained by the application of carbon +dioxide snow. + +#Multiple subcutaneous tuberculous nodules# are met with chiefly in +children. They are indolent and painless, and rarely attract attention +until they break down and form abscesses, which are usually about the +size of a cherry, and when these burst sinuses or ulcers result. If the +overlying skin is still intact, the best treatment is excision. If the +abscess has already infected the skin, each focus should be scraped and +packed. + +#Sporotrichosis# is a mycotic infection due to the sporothrix Shenkii. +It presents so many features resembling syphilis and tubercle that it is +frequently mistaken for one or other of these affections. It occurs +chiefly in males between fifteen and forty-five, who are farmers, fruit +and vegetable dealers, or florists. There is usually a history of trauma +of the nature of a scratch or a cut, and after a long incubation period +there develop a series of small, hard, round nodules in the skin and +subcutaneous tissue which, without pain or temperature, soften into +cold abscesses and leave indolent ulcers or sinuses. The infection is +of slow progress and follows the course of the lymphatics. From the +gelatinous pus the organism is cultivated without difficulty, and this +is the essential step in arriving at a diagnosis. The disease yields in +a few weeks to full doses of iodide of potassium. + +#Elephantiasis.#--This term is applied to an excessive enlargement of a +part depending upon an overgrowth of the skin and subcutaneous cellular +tissue, and it may result from a number of causes, acting independently +or in combination. The condition is observed chiefly in the extremities +and in the external organs of generation. + +_Elephantiasis from Lymphatic or Venous Obstruction._--Of this the +best-known example is _tropical elephantiasis_ (E. arabum), which is +endemic in Samoa, Barbadoes, and other places. It attacks the lower +extremity or the genitals in either sex (Figs. 97, 98). The disease is +usually ushered in with fever, and signs of lymphangitis in the part +affected. After a number of such attacks, the lymph vessels appear to +become obliterated, and the skin and subcutaneous cellular tissue, being +bathed in stagnant lymph--which possibly contains the products of +streptococci--take on an overgrowth, which continues until the part +assumes gigantic proportions. In certain cases the lymph trunks have +been found to be blocked with the parent worms of the filaria Bancrofti. +Cases of elephantiasis of the lower extremity are met with in this +country in which there are no filarial parasites in the lymph vessels, +and these present features closely resembling the tropical variety, and +usually follow upon repeated attacks of lymphangitis or erysipelas. + +The part affected is enormously increased in size, and causes +inconvenience from its bulk and weight. In contrast to ordinary dropsy, +there is no pitting on pressure, and the swelling does not disappear on +elevation of the limb. The skin becomes rough and warty, and may hang +down in pendulous folds. Blisters form on the surface and yield an +abundant exudate of clear lymph. From neglect of cleanliness, the skin +becomes the seat of eczema or even of ulceration attended with foul +discharge. + +Samson Handley has sought to replace the blocked lymph vessels by +burying in the subcutaneous tissue of the swollen part a number of stout +silk threads--_lymphangioplasty_. By their capillary action they drain +the lymph to a healthy region above, and thus enable it to enter the +circulation. It has been more successful in the face and upper limb than +in the lower extremity. If the tissues are infected with pus organisms, +a course of vaccines should precede the operation. + +[Illustration: FIG. 97.--Elephantiasis in a woman aet. 45.] + +A similar type of elephantiasis may occur after extirpation of the lymph +glands in the axilla or groin; in the leg in long-standing standing +varix and phlebitis with chronic ulcer; in the arm as a result of +extensive cancerous disease of the lymphatics in the axilla secondarily +to cancer of the breast; and in extensive tuberculous disease of the +lymphatics. The last-named is chiefly observed in the lower limb in +young adult women, and from its following upon lupus of the toes or foot +it has been called _lupus elephantiasis_. The tuberculous infection +spreads slowly up the limb by way of the lymph vessels, and as these are +obliterated the skin and cellular tissues become hypertrophied, and the +surface is studded over with fungating tuberculous masses of a livid +blue colour. As the more severe forms of the disease may prove dangerous +to life by pyogenic complications inducing gangrene of the limb, the +question of amputation may have to be considered. + +[Illustration: FIG. 98.--Elephantiasis of Penis and Scrotum in native of +Demerara. + +(Mr. Annandale's case.)] + +Belonging to this group also is a form of _congenital elephantiasis_ +resulting from the circular constriction of a limb _in utero_ by +amniotic bands. + +_Elephantiasis occurring apart from lymphatic or venous obstruction_ is +illustrated by _elephantiasis nervorum_, in which there is an overgrowth +of the skin and cellular tissue of an extremity in association with +neuro-fibromatosis of the cutaneous nerves (Fig. 89); and by +_elephantiasis Graecorum_--a form of leprosy in which the skin of the +face becomes the seat of tumour-like masses consisting of leprous +nodules. It is also illustrated by _elephantiasis involving the scrotum_ +as a result of prolonged irritation by the urine in cases in which the +penis has been amputated and the urine has infiltrated the scrotal +tissues over a period of years. + +#Sebaceous Cysts.#--Atheromatous cysts or wens are formed in relation to +the sebaceous glands and hair follicles. They are commonly met with in +adults, on the scalp (Fig. 99), face, neck, back, and external genitals. +Sometimes they are multiple, and they may be met with in several members +of the same family. They are smooth, rounded, or discoid cysts, varying +in size from a split-pea to a Tangerine orange. In consistence they are +firm and elastic, or fluctuating, and are incorporated with the +overlying skin, but movable on the deeper structures. The orifice of the +partly blocked sebaceous follicle is sometimes visible, and the contents +of the cyst can be squeezed through the opening. The wall of the cyst is +composed of a connective-tissue capsule lined by stratified squamous +epithelium. The contents consist of accumulated epithelial cells, and +are at first dry and pearly white in appearance, but as a result of +fatty degeneration they break down into a greyish-yellow pultaceous and +semi-fluid material having a peculiar stale odour. It is probable that +the decomposition of the contents is the result of the presence of +bacteria, and that from the surgical point of view they should be +regarded as infective. A sebaceous cyst may remain indefinitely without +change, or may slowly increase in size, the skin over it becoming +stretched and closely adherent to the cyst wall as a result of friction +and pressure. The contents may ooze from the orifice of the duct and dry +on the skin surface, leading to the formation of a sebaceous horn +(Fig. 100). As a result of injury the cyst may undergo sudden +enlargement from haemorrhage into its interior. + +Recurrent attacks of inflammation frequently occur, especially in wens +of the face and scalp. Suppuration may ensue and be followed by cure of +the cyst, or an offensive fungating ulcer forms which may be mistaken +for epithelioma. True cancerous transformation is rare. + +Wens are to be _diagnosed_ from dermoids, from fatty tumours, and from +cold abscesses. Dermoids usually appear before adult life, and as they +nearly always lie beneath the fascia, the skin is movable over them. A +fatty tumour is movable, and is often lobulated. The confusion with a +cold abscess is most likely to occur in wens of the neck or back, and it +may be impossible without the use of an exploring needle to +differentiate between them. + +[Illustration: FIG. 99.--Multiple Sebaceous Cysts or Wens; the larger +ones are of many years' duration.] + +_Treatment._--The removal of wens is to be recommended while they are +small and freely movable, as they are then easily shelled out after +incising the overlying skin; sometimes splitting the cyst makes its +removal easier. Local anaesthesia is to be preferred. It is important +that none of the cyst wall be left behind. In large and adherent wens an +ellipse of skin is removed along with the cyst. When inflamed, it may be +impossible to dissect out the cyst, and the wall should be destroyed +with carbolic acid, the resulting wound being treated by the open +method. + +#Moles.#--The term mole is applied to a pigmented, and usually hairy, +patch of skin, present at or appearing shortly after birth. The colour +varies from brown to black, according to the amount of melanin pigment +present. The lesion consists in an overgrowth of epidermis which often +presents an alveolar arrangement. Moles vary greatly in size: some are +mere dots, others are as large as the palm of the hand, and occasionally +a mole covers half the face. In addition to being unsightly, they bleed +freely when abraded, are liable to ulcerate from friction and pressure, +and occasionally become the starting-point of melanotic cancer. Rodent +cancer sometimes originates in the slightly pigmented moles met with on +the face. Overgrowths in relation to the cutaneous nerves, especially +the plexiform neuroma, occasionally originate in pigmented moles. Soldau +believes that the pigmentation and overgrowth of the epidermis in moles +are associated with, and probably result from, a fibromatosis of the +cutaneous nerves. + +_Treatment._--The quickest way to get rid of a mole is to excise it; if +the edges of the gap cannot be brought together with sutures, recourse +should be had to grafting. In large hairy moles of the face whose size +forbids excision, radium or the X-rays should be employed. Excellent +results have been obtained by refrigeration with solid carbon dioxide. +In children and women with delicate skin, applications of from ten to +thirty seconds suffice. In persons with coarse skin an application of +one minute may be necessary, and it may have to be repeated. + +#Horns.#--The _sebaceous_ horn results from the accumulation of the +dried contents of a wen on the surface of the skin: the sebaceous +material after drying up becomes cornified, and as fresh material is +added to the base the horn increases in length (Fig. 100). The _wart_ +horn grows from a warty papilloma of the skin. _Cicatrix_ horns are +formed by the heaping up of epidermis in the scars that result from +burns. _Nail_ horns are overgrown nails (keratomata of the nail bed), +and are met with chiefly in the great toe of elderly bedridden patients. +If an ulcer forms at the base of a horn, it may prove the starting-point +of epithelioma, and for this reason, as well as for others, horns should +be removed. + +[Illustration: FIG. 100.--Sebaceous Horn growing from Auricle. + +(Dr. Kenneth Maclachan's case.)] + +#New Growths in the Skin and Subcutaneous Tissue.#--The _Angioma_ has +been described with diseases of blood vessels. _Fibroma._--Various types +of fibroma occur in the skin. A soft pedunculated fibroma, about the +size of a pea, is commonly met with, especially on the neck and trunk; +it is usually solitary, and is easily removed with scissors. The +multiple, soft fibroma known as _molluscum fibrosum_, which depends upon +a neuro-fibromatosis of the cutaneous nerves, is described with the +tumours of nerves. Hard fibromas occurring singly or in groups may be +met with, especially in the skin of the buttock, and may present a local +malignancy, recurring after removal like the "recurrent fibroid" of +Paget. The "painful subcutaneous nodule" is a solitary fibroma related +to one of the cutaneous nerves. The hard fibroma known as _keloid_ is +described with the affections of scars. + +#Papilloma.#--The _common wart_ or verruca is an outgrowth of the +surface epidermis. It may be sessile or pedunculated hard or soft. The +surface may be smooth, or fissured and foliated like a cauliflower, or +it may be divided up into a number of spines. Warts are met with chiefly +on the hands, and are often multiple, occurring in clusters or in +successive crops. Multiple warts appear to result from some contagion, +the nature of which is unknown; they sometimes occur in an epidemic form +among school-children, and show a remarkable tendency to disappear +spontaneously. The solitary flat-topped wart which occurs on the face +of old people may, if irritated, become the seat of epithelioma. A warty +growth of the epidermis is a frequent accompaniment of moles and of that +variety of lupus known as _lupus verrucosus_. + +_Treatment._--In the multiple warts of children the health should be +braced up by a change to the seaside. A dusting-powder, consisting of +boracic acid with 5 per cent. salicylic acid, may be rubbed into the +hands after washing and drying. The persistent warts of young adults +should be excised after freezing with chloride of ethyl. When cutting is +objected to, they may be painted night and morning with salicylic +collodion, the epidermis being dehydrated with alcohol before each +application. + +_Venereal warts_ occur on the genitals of either sex, and may form large +cauliflower-like masses on the inner surface of the prepuce or of the +labia majora. Although frequently co-existing with gonorrhoea or +syphilis, they occur independently of these diseases, being probably +acquired by contact with another individual suffering from warts +(C. W. Cathcart). They give rise to considerable irritation and +suffering, and when cleanliness is neglected there may be an offensive +discharge. + +In the female, the cauliflower-like masses are dissected from the labia; +in the male, the prepuce is removed and the warts on the glans are +snipped off with scissors. In milder cases, the warts usually disappear +if the parts are kept absolutely dry and clean. A useful dusting-powder +is one consisting of calamine and 5 per cent. salicylic acid; the +exsiccated sulphate of iron, in the form of a powder, may be employed in +cases which resist this treatment. + +#Adenoma.#--This is a comparatively rare tumour growing from the glands +of the skin. One variety, known as the "tomato tumour," which apparently +originates from _the sweat glands_, is met with on the scalp and face in +women past middle life. These growths are often multiple; the individual +tumours vary in size, and the skin, which is almost devoid of hairs, is +glistening and tightly stretched over them. A similar tumour may occur +on the nose. The _sebaceous adenoma_, which originates from the +sebaceous glands, forms a projecting tumour on the face or scalp, and +when the skin is irritated it may ulcerate and fungate. The treatment +consists in the removal of the tumour along with the overlying skin. + +The exuberant masses on the nose known as "rhinophyma," "lipoma nasi," +or "potato nose" are of the nature of sebaceous adenoma, and are removed +by shaving them off with a knife until the normal shape of the nose is +restored Healing takes place with remarkable rapidity. + +#Cancer.#--There are several types of primary cancer of the skin, the +most important being squamous epithelioma, rodent cancer, and melanotic +cancer. + +[Illustration: FIG. 101.--Paraffin Epithelioma.] + +#Epithelioma# occurs in a variety of forms. When originating in a small +ulcer or wart-for example on the face in old people--it presents the +features of a chronic indurated ulcer. A more exuberant and rapidly +growing form of epithelial cancer, described by Hutchinson as the +_crateriform ulcer_, commences on the face as a small red pimple which +rapidly develops into an elevated mass shaped like a bee-hive, and +breaks down in the centre. Epithelioma may develop anywhere on the body +in relation to long-standing ulcers, especially that resulting from a +burn or from lupus; this form usually presents an exuberant outgrowth of +epidermis not unlike a cauliflower. An interesting example of +epithelioma has been described by Neve of Kashmir. The natives in that +province are in the habit of carrying a fire-basket suspended from the +waist, which often burns the skin and causes a chronic ulcer, and many +of these ulcers become the seat of epithelioma, due, in Neve's opinion, +to the actual contact of the sooty pan with the skin. + +The term _trade epithelioma_ has been applied to that form met with in +those who follow certain occupations, such as paraffin workers and +chimney-sweeps. The most recent member of this group is the _X-ray +carcinoma_, which is met with in those who are constantly exposed to the +irritation of the X-rays; there is first a chronic dermatitis with warty +overgrowth of the surface epithelium, pigmentation, and the formation of +fissures and warts. The trade epithelioma varies a good deal in +malignancy, but it tends to cause death in the same manner as other +epitheliomas. + +Epithelial cancer has also been observed in those who have taken arsenic +over long periods for medicinal purposes. + +[Illustration: FIG. 102.--Rodent Cancer of Inner Canthus.] + +#Rodent Cancer# (Rodent Ulcer).--This is a cancer originating in the +sweat glands or sebaceous follicles, or in the foetal residues of +cutaneous glands. The cells are small and closely packed together in +alveoli or in reticulated columns; cell nests are rare. It is remarkably +constant in its seat of origin, being nearly always located on the +lateral aspect of the nose or in the vicinity of the lower eyelid +(Fig. 102). It is rare on the trunk or limbs. It commences as a small +flattened nodule in the skin, the epidermis over it being stretched and +shining. The centre becomes depressed, while the margins extend in the +form of an elevated ridge. Sooner or later the epidermis gives way in +the centre, exposing a smooth raw surface devoid of granulations. + +[Illustration: FIG. 103.--Rodent Cancer of fifteen years' duration, +which has destroyed the contents of the Orbit. + +(Sir Montagu Cotterill's case)] + +The margin, while in parts irregular, is typically represented by a +well-defined "rolled" border which consists of the peripheral portion of +the cancer that has not broken down. The central ulcer may temporarily +heal. There is itching but little pain, and the condition progresses +extremely slowly; rodent cancers which have existed for many years are +frequently met with. The disease attacks and destroys every structure +with which it comes in contact, such as the eyelids, the walls of the +nasal cavities, and the bones of the face; hence it may produce the most +hideous deformities (Fig. 103). The patient may succumb to haemorrhage or +to infective complications such as erysipelas or meningitis. + +Secondary growths in the lymph glands, while not unknown, are extremely +rare. We have only seen them once--in a case of rodent cancer in the +groin. + +_Diagnosis._--Lupus is the disease most often mistaken for rodent +cancer. Lupus usually begins earlier in life, it presents apple-jelly +nodules, and lacks the rounded, elevated border. Syphilitic lesions +progress more rapidly, and also lack the characteristic margin. The +differentiation from squamous epithelioma is of considerable importance, +as the latter affection spreads more rapidly, involves the lymph glands +early, and is much more dangerous to life. + +_Treatment._--In rodent cancers of limited size--say less than one inch +in diameter--free excision is the most rapid and certain method of +treatment. The alternative is the application of radium or of the +Rontgen rays, which, although requiring many exposures, results in cure +with the minimum of disfigurement. If the cancer already covers an +extensive area, or has invaded the cavity of the orbit or nose, radium +or X-rays yield the best results. The effect is soon shown by the +ingrowth of healthy epithelium from the surrounding skin, and at the +same time the discharge is lessened. Good results are also reported from +the application of carbon dioxide snow, especially when this follows +upon a course of X-ray treatment. + +#Paget's disease# of the nipple is an epithelioma occurring in women +over forty years of age: a similar form of epithelioma is sometimes met +with at the umbilicus or on the genitals. + +#Melanotic Cancer.#--Under this head are included all new growths which +contain an excess of melanin pigment. Many of these were formerly +described as melanotic sarcoma. They nearly always originate in a +pigmented mole which has been subjected to irritation. The primary +growth may remain so small that its presence is not even suspected, or +it may increase in size, ulcerate, and fungate. The amount of pigment +varies: when small in amount the growth is brown, when abundant it is a +deep black. The most remarkable feature is the rapidity with which the +disease becomes disseminated along the lymphatics, the first evidence of +which is an enlargement of the lymph glands. As the primary growth is +often situated on the sole of the foot or in the matrix of the nail of +the great toe, the femoral and inguinal glands become enlarged in +succession, forming tumours much larger than the primary growth. +Sometimes the dissemination involves the lymph vessels of the limb, +forming a series of indurated pigmented cords and nodules (Fig. 104). +Lastly, the dissemination may be universal throughout the body, and this +usually occurs at a comparatively early stage. The secondary growths are +deeply pigmented, being usually of a coal-black colour, and melanin +pigment may be present in the urine. When recurrence takes place in or +near the scar left by the operation, the cancer nodules are not +necessarily pigmented. + +[Illustration: FIG. 104.--Diffuse Melanotic Cancer of Lymphatics of Skin +secondary to a Growth in the Sole of the Foot.] + +To extirpate the disease it is necessary to excise the tumour, with a +zone of healthy skin around it and a somewhat large zone of the +underlying subcutaneous tissue and deep fascia. Hogarth Pringle +recommends that a broad strip of subcutaneous fascia up to and including +the nearest anatomical group of glands should be removed with the tumour +in one continuous piece. + +#Secondary Cancer of the Skin.#--Cancer may spread to the skin from a +subjacent growth by direct continuity or by way of the lymphatics. Both +of these processes are so well illustrated in cases of mammary cancer +that they will be described in relation to that disease. + +#Sarcoma# of various types is met with in the skin. The fibroma, after +excision, may recur as a fibro-sarcoma. The alveolar sarcoma commences +as a hard lump and increases in size until the epidermis gives way and +an ulcer is formed. + +[Illustration: FIG. 105.--Melanotic Cancer of Forehead with Metastases +in Lymph Vessels and Glands. + +(Mr. D. P. D. Wilkie's case.)] + +A number of fresh tumours may spring up around the original growth. +Sometimes the primary growth appears in the form of multiple nodules +which tend to become confluent. Excision, unless performed early, is of +little avail, and in any case should be followed up by exposure to +radium. + + +AFFECTIONS OF CICATRICES + +A cicatrix or scar consists of closely packed bundles of white fibres +covered by epidermis; the skin glands and hair follicles are usually +absent. The size, shape, and level of the cicatrix depend upon the +conditions which preceded healing. + +A healthy scar, when recently formed, has a smooth, glossy surface of a +pinkish colour, which tends to become whiter as a result of obliteration +of the blood vessels concerned in its formation. + +_Weak Scars._--A scar is said to be weak when it readily breaks down as +a result of irritation or pressure. The scars resulting from severe +burns and those over amputation stumps are especially liable to break +down from trivial causes. The treatment is to excise the weak portion of +the scar and bring the edges of the gap together. + +_Contracted scars_ frequently cause deformity either by displacing +parts, such as the eyelid or lip, or by fixing parts and preventing the +normal movements--for example, a scar on the flexor aspect of a joint +may prevent extension of the forearm (Fig. 63). These are treated by +dividing the scar, correcting the deformity, and filling up the gap with +epithelial grafts, or with a flap of the whole thickness of the skin. +When deformity results from _depression of a scar_, as is not uncommon +after the healing of a sinus, the treatment is to excise the scar. +Depressed scars may be raised by the injection of paraffin into the +subcutaneous tissue. + +_Painful Scars._--Pain in relation to a scar is usually due to nerve +fibres being compressed or stretched in the cicatricial tissue; and in +some cases to ascending neuritis. The treatment consists in excising the +scar or in stretching or excising a portion of the nerve affected. + +_Pigmented or Discoloured Scars._--The best-known examples are the blue +coloration which results from coal-dust or gunpowder, the brown scars +resulting from chronic ulcer with venous congestion of the leg, and the +variously coloured scars caused by tattooing. The only satisfactory +method of getting rid of the coloration is to excise the scar; the edges +are brought together by sutures, or the raw surface is covered with +skin-grafts according to the size of the gap. + +_Hypertrophied Scars._--Scars occasionally broaden out and become +prominent, and on exposed parts this may prove a source of +disappointment after operations such as those for goitre or tuberculous +glands in the neck. There is sometimes considerable improvement from +exposure to the X-rays. + +_Keloid._--This term is applied to an overgrowth of scar tissue which +extends beyond the area of the original wound, and the name is derived +from the fact that this extension occurs in the form of radiating +processes, suggesting the claws of a crab. It is essentially a fibroma +or new growth of fibrous tissue, which commences in relation to the +walls of the smaller blood vessels; the bundles of fibrous tissue are +for the most part parallel with the surface, and the epidermis is +tightly stretched over them. It is more frequent in the negro and in +those who are, or have been, the subjects of tuberculous disease. + +[Illustration: FIG. 106.--Recurrent Keloid in scar left by operation for +tuberculous glands in a girl aet. 7.] + +Keloid may attack scars of any kind, such as those resulting from +leech-bites, acne pustules, boils or blisters; those resulting from +operation or accidental wounds; and the scars resulting from burns, +especially when situated over the sternum, appear to be specially +liable. The scar becomes more and more conspicuous, is elevated above +the surface, of a pinkish or brownish-pink pink colour, and sends out +irregular prolongations around its margins. The patient may complain of +itching and burning, and of great sensitiveness of the scar, even to +contact with the clothing. + +There is a natural hesitation to excise keloid because of the fear of +its returning in the new scar. The application of radium is, so far as +we know, the only means of preventing such return. The irritation +associated with keloid may be relieved by the application of salicylic +collodion or of salicylic and creosote plaster. + +_Epithelioma_ is liable to attack scars in old people, especially those +which result from burns sustained early in childhood and have never +really healed. From the absence of lymphatics in scar tissue, the +disease does not spread to the glands until it has invaded the tissues +outside the scar; the prognosis is therefore better than in epithelioma +in general. It should be excised widely; in the lower extremity when +there is also extensive destruction of tissue from an antecedent chronic +ulcer or osteomyelitis, it may be better to amputate the limb. + + +AFFECTION OF THE NAILS + +_Injuries._--When a nail is contused or crushed, blood is extravasated +beneath it, and the nail is usually shed, a new one growing in its +place. A splinter driven underneath the nail causes great pain, and if +organisms are carried in along with it, may give rise to infective +complications. The free edge of the nail should be clipped away to allow +of the removal of the foreign body and the necessary disinfection. + +_Trophic Changes._--The growth of the nails may be interfered with in +any disturbance of the general health. In nerve lesions, such as a +divided nerve-trunk, the nails are apt to suffer, becoming curved, +brittle, or furrowed, or they may be shed. + +_Onychia_ is the term applied to an infection of the soft parts around +the nail or of the matrix beneath it. The commonest form of onychia has +already been referred to with whitlow. There is a superficial variety +resulting from the extension of a purulent blister beneath the nail +lifting it up from its bed, the pus being visible through the nail. The +nail as well as the raised horny layer of the epidermis should be +removed. A deeper and more troublesome onychia results from infection at +the nail-fold; the infection spreads slowly beneath the fold until it +reaches the matrix, and a drop or two of pus forms beneath the nail, +usually in the region of the lunule. This affection entails a +disability of the finger which may last for weeks unless it is properly +treated. Treatment by hyperaemia, using a suction bell, should first be +tried, and, failing improvement, the nail-fold and lunule should be +frozen, and a considerable portion removed with the knife; if only a +small portion of the nail is removed, the opening is blocked by +granulations springing from the matrix. A new nail is formed, but it is +liable to be misshapen. + +_Tuberculous onychia_ is met with in children and adolescents. It +appears as a livid or red swelling at the root of the nail and spreading +around its margins. The epidermis, which is thin and shiny, gives way, +and the nail is usually shed. + +[Illustration: FIG. 107.--Subungual Exostosis growing from Distal +Phalanx of Great Toe, showing Ulceration of Skin and Displacement of +Nail. + +_a._ Surface view. _b._ On section.] + +_Syphilitic_ affections of the nails assume various aspects. A primary +chancre at the edge of the nail may be mistaken for a whitlow, +especially if it is attended with much pain. Other forms of onychia +occur during secondary syphilis simultaneously with the skin eruptions, +and may prove obstinate and lead to shedding of the nails. They also +occur in inherited syphilis. In addition to general treatment, an +ointment containing 5 per cent. of oleate of mercury should be applied +locally. + +_Ingrowing Toe-nail._--This is more accurately described as an +overgrowth of the soft tissues along the edge of the nail. It is most +frequently met with in the great toe in young adults with flat-foot +whose feet perspire freely, who wear ill-fitting shoes, and who cut +their toe-nails carelessly or tear them with their fingers. Where the +soft tissues are pressed against the edge of the nail, the skin gives +way and there is the formation of exuberant granulations and of +discharge which is sometimes foetid. The affection is a painful one and +may unfit the patient for work. In mild cases the condition may be +remedied by getting rid of contributing causes and by disinfecting the +skin and nail; the nail is cut evenly, and the groove between it and the +skin packed with an antiseptic dusting-powder, such as boracic acid. In +more severe cases it may be necessary to remove an ellipse of tissue +consisting of the edge of the nail, together with the subjacent matrix +and the redundant nail-fold. + +_Subungual exostosis_ is an osteoma growing from the terminal phalanx of +the great toe (Fig. 107). It raises the nail and may be accompanied by +ulceration of the skin over the most prominent part of the growth. The +soft parts, including the nail, should be reflected towards the dorsum +in the form of a flap, the base of the exostosis divided with the +chisel, and the exostosis removed. + +_Malignant disease_ in relation to the nails is rare. Squamous +epithelioma and melanotic cancer are the forms met with. Treatment +consists in amputating the digit concerned, and in removing the +associated lymph glands. + + + + +CHAPTER XVIII + +THE MUSCLES, TENDONS, AND TENDON SHEATHS + + +INJURIES: _Contusion_; _Sprain_; _Rupture_--Hernia of + muscle--Dislocation of tendons--Wounds--Avulsion of tendon. + DISEASES OF MUSCLE AND OF TENDONS: _Atrophy_; _"Muscular + rheumatism"_--_Fibrositis_; _Contracture_; _Myositis_; + _Calcification and Ossification_; _Tumours_. DISEASES OF TENDON + SHEATHS: _Teno-synovitis_. + + +INJURIES + +#Contusion of Muscle.#--Contusion of muscle, which consists in bruising +of its fibres and blood vessels, may be due to violence acting from +without, as in a blow, a kick, or a fall; or from within, as by the +displacement of bone in a fracture or dislocation. + +The symptoms are those common to all contusions, and the patient +complains of severe pain on attempting to use the muscle, and maintains +an attitude which relaxes it. If the sheath of the muscle also is torn, +there is subcutaneous ecchymosis, and the accumulation of blood may +result in the formation of a haematoma. + +Restoration of function is usually complete; but when the nerve +supplying the muscle is bruised at the same time, as may occur in the +deltoid, wasting and loss of function may be persistent. In exceptional +cases the process of repair may be attended with the formation of bone +in the substance of the muscle, and this may likewise impair its +function. + +A contused muscle should be placed at rest and supported by cotton wool +and a bandage; after an interval, massage and appropriate exercises are +employed. + +#Sprain and Partial Rupture of Muscle.#--This lesion consists in +overstretching and partial rupture of the fibres of a muscle or its +aponeurosis. It is of common occurrence in athletes and in those who +follow laborious occupations. It may follow upon a single or repeated +effort--especially in those who are out of training. Familiar examples +of muscular sprain are the "labourer's" or "golfer's back," affecting +the latissimus dorsi or the sacrospinalis (erector spinae); the +"tennis-player's elbow," and the "sculler's sprain," affecting the +muscles and ligaments about the elbow; the "angler's elbow," affecting +the common origin of the extensors and supinators; the "sprinter's +sprain," affecting the flexors of the hip; and the "jumper's and +dancer's sprain," affecting the muscles of the calf. The patient +complains of pain, often sudden in onset, of tenderness on pressure, and +of inability to carry out the particular movement by which the sprain +was produced. The disability varies in different cases, and it may +incapacitate the patient from following his occupation or sport for +weeks or, if imperfectly treated, even for months. + +The _treatment_ consists in resting the muscle from the particular +effort concerned in the production of the sprain, in gently exercising +it in other directions, in the use of massage, and the induction of +hyperaemia by means of heat. In neglected cases, that is, where the +muscle has not been exercised, the patient shrinks from using it and the +disablement threatens to be permanent; it is sometimes said that +adhesions have formed and that these interfere with the recovery of +function. The condition may be overcome by graduated movements or by a +sudden forcible movement under an anaesthetic. These cases afford a +fruitful field for the bone-setter. + +#Rupture of Muscle or Tendon.#--A muscle or a tendon may be ruptured in +its continuity or torn from its attachment to bone. The site of rupture +in individual muscles is remarkably constant, and is usually at the +junction of the muscular and tendinous portions. When rupture takes +place through the belly of a muscle, the ends retract, the amount of +retraction depending on the length of the muscle, and the extent of its +attachment to adjacent aponeurosis or bone. The biceps in the arm, and +the sartorius in the thigh, furnish examples of muscles in which the +separation between the ends may be considerable. + +The gap in the muscle becomes filled with blood, and this in time is +replaced by connective tissue, which forms a bond of union between the +ends. When the space is considerable the connecting medium consists of +fibrous tissue, but when the ends are in contact it contains a number of +newly formed muscle fibres. In the process of repair, one or both ends +of the muscle or tendon may become fixed by adhesions to adjacent +structures, and if the distal portion of a muscle is deprived of its +nerve supply it may undergo degeneration and so have its function +impaired. + +Rupture of a muscle or tendon is usually the result of a sudden, and +often involuntary, movement. As examples may be cited the rupture of +the quadriceps extensor in attempting to regain the balance when falling +backwards; of the gastrocnemius, plantaris, or tendo-calcaneus in +jumping or dancing; of the adductors of the thigh in gripping a horse +when it swerves--"rider's sprain"; of the abdominal muscles in vomiting, +and of the biceps in sudden movements of the arm. Sometimes the effort +is one that would scarcely be thought likely to rupture a muscle, as in +the case recorded by Pagenstecher, where a professional athlete, while +sitting at table, ruptured his biceps in a sudden effort to catch a +falling glass. It would appear that the rupture is brought about not so +much by the contraction of the muscle concerned, as by the contraction +of the antagonistic muscles taking place before that of the muscle which +undergoes rupture is completed. The violent muscular contractions of +epilepsy, tetanus, or delirium rarely cause rupture. + +The _clinical features_ are usually characteristic. The patient +experiences a sudden pain, with the sensation of being struck with a +whip, and of something giving way; sometimes a distant snap is heard. +The limb becomes powerless. At the seat of rupture there is tenderness +and swelling, and there may be ecchymosis. As the swelling subsides, a +gap may be felt between the retracted ends, and this becomes wider when +the muscle is thrown into contraction. If untreated, a hard, fibrous +cord remains at the seat of rupture. + +_Treatment._--The ends are approximated by placing the limb in an +attitude which relaxes the muscle, and the position is maintained by +bandages, splints, or special apparatus. When it is impossible thus to +approximate the ends satisfactorily, the muscle or tendon is exposed by +incision, and the ends brought into accurate contact by catgut sutures. +This operation of primary suture yields the most satisfactory results, +and is most successful when it is done within five or six days of the +accident. Secondary suture after an interval of months is rendered +difficult by the retraction of the ends and by their adhesion to +adjacent structures. + +_Rupture of the biceps of the arm_ may involve the long or the short +head, or the belly of the muscle. Most interest attaches to rupture of +the long tendon of origin. There is pain and tenderness in front of the +upper end of the humerus, the patient is unable to abduct or to elevate +the arm, and he may be unable to flex the elbow when the forearm is +supinated. The long axis of the muscle, instead of being parallel with +the humerus, inclines downwards and outwards. When the patient is asked +to contract the muscle, its belly is seen to be drawn towards the +elbow. + +The _adductor longus_ may be ruptured, or torn from the pubes, by a +violent effort to adduct the limb. A swelling forms in the upper and +medial part of the thigh, which becomes smaller and harder when the +muscle is thrown into contraction. + +The _quadriceps femoris_ is usually ruptured close to its insertion into +the patella, in the attempt to avoid falling backwards. The injury is +sometimes bilateral. The injured limb is rendered useless for +progression, as it suddenly gives way whenever the knee is flexed. +Treatment is conducted on the same lines as in transverse fracture of +the patella; in the majority of cases the continuity of the quadriceps +should be re-established by suture within five or six days of the +accident. + +The _tendo calcaneus_ (Achillis) is comparatively easily ruptured, and +the symptoms are sometimes so slight that the nature of the injury may +be overlooked. The limb should be put up with the knee flexed and the +toes pointed. This may be effected by attaching one end of an elastic +band to the heel of a slipper, and securing the other to the lower third +of the thigh. If this is not sufficient to bring the ends into +apposition they should be approximated by an open operation. + +The _plantaris_ is not infrequently ruptured from trivial causes, such +as a sudden movement in boxing, tennis, or hockey. A sharp stinging pain +like the stroke of a whip is felt in the calf; there is marked +tenderness at the seat of rupture, and the patient is unable to raise +the heel without pain. The injury is of little importance, and if the +patient does not raise the heel from the ground in walking, it is +recovered from in a couple of weeks or so, without it being necessary to +lay him up. + +#Hernia of Muscle.#--This is a rare condition, in which, owing to the +fascia covering a muscle becoming stretched or torn, the muscular +substance is protruded through the rent. It has been observed chiefly in +the adductor longus. An oval swelling forms in the upper part of the +thigh, is soft and prominent when the muscle is relaxed, less prominent +when it is passively extended, and disappears when the muscle is thrown +into contraction. It is liable to be mistaken, according to its +situation, for a tumour, a cyst, a pouched vein, or a femoral or +obturator hernia. Treatment is only called for when it is causing +inconvenience, the muscle being exposed by a suitable incision, the +herniated portion excised, and the rent in the sheath closed by sutures. + +#Dislocation of Tendons.#--Tendons which run in grooves may be displaced +as a result of rupture of the confining sheath. This injury is met with +chiefly in the tendons at the ankle and in the long tendon of the +biceps. + +Dislocation of the _peronei tendons_ may occur, for example, from a +violent twist of the foot. There is severe pain and considerable +swelling on the lateral aspect of the ankle; the peroneus longus by +itself, or together with the brevis, can be felt on the lateral aspect +or in front of the lateral malleolus; the patient is unable to move the +foot. By a little manipulation the tendons are replaced in their +grooves, and are retained there by a series of strips of plaster. At the +end of three weeks massage and exercises are employed. + +In other cases there is no history of injury, but whenever the foot is +everted the tendon of the peroneus longus is liable to be jerked +forwards out of its groove, sometimes with an audible snap. The patient +suffers pain and is disabled until the tendon is replaced. Reduction is +easy, but as the displacement tends to recur, an operation is required +to fix the tendon in its place. An incision is made over the tendon; if +the sheath is slack or torn, it is tightened up or closed with catgut +sutures; or an artificial sheath is made by raising up a quadrilateral +flap of periosteum from the lateral aspect of the fibula, and stitching +it over the tendon. + +Similarly the _tibialis posterior_ may be displaced over the medial +malleolus as a result of inversion of the foot. + +The _long tendon of the biceps_ may be dislocated laterally--or more +frequently medially--as a result of violent or repeated rotation +movements of the arm, such as are performed in wringing clothes. The +patient is aware of the displacement taking place, and is unable to +extend the forearm until the displaced tendon has been reduced by +abducting the arm. In recurrent cases the patient may be able to +dislocate the tendon at will, but the disability is so inconsiderable +that there is rarely any occasion for interference. + +#Wounds of Muscles and Tendons.#--When a muscle is cut across in a +wound, its ends should be brought together with sutures. If the ends are +allowed to retract, and especially if the wound suppurates, they become +united by scar tissue and fixed to bone or other adjacent structure. In +a limb this interferes with the functions of the muscle; in the +abdominal wall the scar tissue may stretch, and so favour the +development of a ventral hernia. + +Tendons may be cut across accidentally, especially in those wounds so +commonly met with above the wrist as a result, for example, of the hand +being thrust through a pane of glass. It is essential that the ends +should be sutured to each other, and as the proximal end is retracted +the original wound may require to be enlarged in an upward direction. +When primary suture has been omitted, or has failed in consequence of +suppuration, the separated ends of the tendon become adherent to +adjacent structures, and the function of the associated muscle is +impaired or lost. Under these conditions the operation of secondary +suture is indicated. + +A free incision is necessary to discover and isolate the ends of the +tendon; if the interval is too wide to admit of their being approximated +by sutures, means must be taken to lengthen the tendon, or one from some +other part may be inserted in the gap. A new sheath may be provided for +the tendon by resecting a portion of the great saphenous vein. + +_Injuries of the tendons of the fingers_ are comparatively common. One +of the best known is the partial or complete rupture of the aponeurosis +of the extensor tendon close to its insertion into the terminal +phalanx--_drop-_ or _mallet-finger_. This may result from comparatively +slight violence, such as striking the tip of the extended finger against +an object, or the violence may be more severe, as in attempting to catch +a cricket ball or in falling. The terminal phalanx is flexed towards the +palm and the patient is unable to extend it. The treatment consists in +putting up the finger with the middle joint strongly flexed. In +neglected cases, a perfect functional result can only be obtained by +operation; under a local anaesthetic, the ruptured tendon is exposed and +is sutured to the base of the phalanx, which may be drilled for the +passage of the sutures. + +_Subcutaneous rupture_ of one or other _of the digital tendons_ in the +hand or at the wrist can be remedied only by operation. When some time +has elapsed since the accident, the proximal end may be so retracted +that it cannot be brought down into contact with the distal end, in +which case a slip may be taken from an adjacent tendon; in the case of +one of the extensors of the thumb, the extensor carpi radialis longus +may be detached from its insertion and stitched to the distal end of the +tendon of the thumb. + +Subcutaneous _rupture of the tendon of the extensor pollicis longus_ at +the wrist takes place just after its emergence from beneath the annular +ligament; the actual rupture may occur painlessly, more frequently a +sharp pain is felt over the back of the wrist. The prominence of the +tendon, which normally forms the ulnar border of the snuff-box, +disappears. This lesion is chiefly met with in drummer-boys and is the +cause of drummer's palsy. The only chance of restoring function is in +uniting the ruptured tendon by open operation. + +[Illustration: FIG. 108.--Avulsion of Tendon with Terminal Phalanx of +Thumb. + +(Surgical Museum, University of Edinburgh.)] + +_Avulsion of Tendons._--This is a rare injury, in which the tendons of a +finger or toe are torn from their attachments along with a portion of +the digit concerned. In the hand, it is usually brought about by the +fingers being caught in the reins of a runaway horse, or being seized in +a horse's teeth, or in machinery. It is usually the terminal phalanx +that is separated, and with it the tendon of the deep flexor, which +ruptures at its junction with the belly of the muscle (Fig. 108). The +treatment consists in disinfecting the wound, closing the tendon-sheath, +and trimming the mutilated finger so as to provide a useful stump. + + +DISEASES OF MUSCLES AND TENDONS + +_Congenital absence_ of muscles is sometimes met with, usually in +association with other deformities. The pectoralis major, for example, +may be absent on one or on both sides, without, however, causing any +disability, as other muscles enlarge and take on its functions. + +_Atrophy of Muscle._--Simple atrophy, in which the muscle elements are +merely diminished in size without undergoing any structural alteration, +is commonly met with as a result of disuse, as when a patient is +confined to bed for a long period. + +In cases of joint disease, the muscles acting on the joint become +atrophied more rapidly than is accounted for by disuse alone, and this +is attributed to an interference with the trophic innervation of the +muscles reflected from centres in the spinal medulla. It is more marked +in the extensor than in the flexor groups of muscles. Those affected +become soft and flaccid, exhibit tremors on attempted movement, and +their excitability to the faradic current is diminished. + +_Neuropathic atrophy_ is associated with lesions of the nervous system. +It is most pronounced in lesions of the motor nerve-trunks, probably +because vaso-motor and trophic fibres are involved as well as those that +are purely motor in function. It is attended with definite structural +alterations, the muscle elements first undergoing fatty degeneration, +and then being absorbed, and replaced to a large extent by ordinary +connective tissue and fat. At a certain stage the muscles exhibit the +reaction of degeneration. In the common form of paralysis resulting from +poliomyelitis, many fibres undergo fatty degeneration and are replaced +by fat, while at the same time there is a regeneration of muscle fibres. + +#Fibrositis# or "#Muscular Rheumatism#."--This clinical term is applied +to a group of affections of which lumbago is the best-known example. The +group includes lumbago, stiff-neck, and pleurodynia--conditions which +have this in common, that sudden and severe pain is excited by movement +of the affected part. The lesion consists in inflammatory hyperplasia of +the connective tissue; the new tissue differs from normal fibrous tissue +in its tendency to contract, in being swollen, painful and tender on +pressure, and in the fact that it can be massaged away (Stockman). It +would appear to involve mainly the fibrous tissue of muscles, although +it may extend from this to aponeuroses, ligaments, periosteum, and the +sheaths of nerves. The term _fibrositis_ was applied to it by Gowers in +1904. + +In _lumbago_--_lumbo-sacral fibrositis_--the pain is usually located +over the sacrum, the sacro-iliac joint, or the aponeurosis of the lumbar +muscles on one or both sides. The amount of tenderness varies, and so +long as the patient is still he is free from pain. The slightest +attempt to alter his position, however, is attended by pain, which may +be so severe as to render him helpless for the moment. The pain is most +marked on rising from the stooping or sitting posture, and may extend +down the back of the hip, especially if, as is commonly the case, +lumbago and gluteal fibrosis coexist. Once a patient has suffered from +lumbago, it is liable to recur, and an attack may be determined by +errors of diet, changes of weather, exposure to cold or unwonted +exertion. It is met with chiefly in male adults, and is most apt to +occur in those who are gouty or are the subjects of oxaluric dyspepsia. + +_Gluteal fibrositis_ usually follows exposure to wet, and affects the +gluteal muscles, particularly the medius, and their aponeurotic +coverings. When the condition has lasted for some time, indurated +strands or nodules can be detected on palpating the relaxed muscles. The +patient complains of persistent aching and stiffness over the buttock, +and sometimes extending down the lateral aspect of the thigh. The pain +is aggravated by such movements as bring the affected muscles into +action. It is not referred to the line of the sciatic nerve, nor is +there tenderness on pressing over the nerve, or sensations of tingling +or numbness in the leg or foot. + +If untreated, the morbid process may implicate the sheath of the sciatic +nerve and cause genuine sciatic neuralgia (Llewellyn and Jones). A +similar condition may implicate the fascia lata of the thigh, or the +calf muscles and their aponeuroses--_crural fibrositis_. + +In _painful stiff-neck_, or "rheumatic torticollis," the pain is located +in one side of the neck, and is excited by some inadvertent movement. +The head is held stiffly on one side as in wry-neck, the patient +contracting the sterno-mastoid. There may be tenderness over the +vertebral spines or in the lines of the cervical nerves, and the +sterno-mastoid may undergo atrophy. This affection is more often met +with in children. + +In _pleurodynia_--_intercostal fibrositis_--the pain is in the line of +the intercostal nerves, and is excited by movement of the chest, as in +coughing, or by any bodily exertion. There is often marked tenderness. + +A similar affection is met with in the _shoulder and arm_--_brachial +fibrositis_--especially on waking from sleep. There is acute pain on +attempting to abduct the arm, and there may be localised tenderness in +the region of the axillary nerve. + +_Treatment._--The general treatment is concerned with the diet, +attention to the stomach, bowels, and kidneys and with the correction +of any gouty tendencies that may be present. Remedies such as +salicylates are given for the relief of pain, and for this purpose drugs +of the aspirin type are to be preferred, and these may be followed by +large doses of iodide of potassium. Great benefit is derived from +massage, and from the induction of hyperaemia by means of heat. Cupping +or needling, or, in exceptional cases, hypodermic injections of +antipyrin or morphin, may be called for. To prevent relapses of lumbago, +the patient must take systematic exercises of all kinds, especially such +as bring out the movements of the vertebral column and hip-joints. + +[Illustration: FIG. 109.--Volkmann's Ischaemic Contracture. When the +wrist is flexed to a right angle it is possible to extend the fingers. + +(Photographs lent by Mr. Lawford Knaggs)] + +#Contracture of Muscles.#--Permanent shortening of muscles results from +the prolonged approximation of their points of attachment, or from +structural changes in their substance produced by injury or by disease. +It is a frequent accompaniment and sometimes a cause of deformities, in +the treatment of which lengthening of the shortened muscles or their +tendons may be an essential step. + +#Myositis.#--_Ischaemic Myositis._--Volkmann was the first to describe a +form of myositis followed by contracture, resulting from interference +with the arterial blood supply. It is most frequently observed in the +flexor muscles of the forearm in children and young persons under +treatment for fractures in the region of the elbow, the splints and +bandages causing compression of the blood vessels. There is considerable +effusion of blood, the skin is tense, and the muscles, vessels, and +nerves are compressed; this is further increased if the elbow is flexed +and splints and tight bandages are applied. The muscles acquire a +board-like hardness and no longer contract under the will, and passive +motion is painful and restricted. Slight contracture of the fingers is +usually the first sign of the malady; in time the muscles undergo +further contraction, and this brings about a claw-like deformity of the +hand. The affected muscles usually show the reaction of degeneration. In +severe cases the median and ulnar nerves are also the seat of +cicatricial changes (ischaemic neuritis). + +By means of splints, the interphalangeal, metacarpo-phalangeal, and +wrist joints should be gradually extended until the deformity is +over-corrected (R. Jones). Murphy advises resection of the radius and +ulna sufficient to admit of dorsiflexion of the joints and lengthening +of the flexor tendons. + +Various forms of _pyogenic_ infection are met with in muscle, most +frequently in relation to pyaemia and to typhoid fever. These may result +in overgrowth of the connective-tissue framework of the muscle and +degeneration of its fibres, or in suppuration and the formation of one +or more abscesses in the muscle substance. Repair may be associated with +contracture. + +A _gonorrhoeal_ form of myositis is sometimes met with; it is painful, +but rarely goes on to suppuration. + +In the early secondary period of _syphilis_, the muscles may be the seat +of dull, aching, nocturnal pains, especially in the neck and back. +_Syphilitic contracture_ is a condition which has been observed chiefly +in the later secondary period; the biceps of the arm and the hamstrings +in the thigh are the muscles more commonly affected. The striking +feature is a gradually increasing difficulty of extending the limb at +the elbow or knee, and progressive flexion of the joint. The affected +muscle is larger and firmer than normal, and its electric excitability +is diminished. In tertiary syphilis, individual muscles may become the +seat of interstitial myositis or of gummata, and these affections +readily yield to anti-syphilitic remedies. + +_Tuberculous disease_ in muscle, while usually due to extension from +adjacent tissues, is sometimes the result of a primary infection through +the blood-stream. Tuberculous nodules are found disseminated throughout +the muscle; the surrounding tissues are indurated, and central caseation +may take place and lead to abscess formation and sinuses. We have +observed this form of tuberculous disease in the gastrocnemius and in +the psoas--in the latter muscle apart from tuberculous disease in the +vertebrae. + +#Tendinitis.#--German authors describe an inflammation of tendon as +distinguished from inflammation of its sheath, and give it the name +tendinitis. It is met with most frequently in the tendo-calcaneus in +gouty and rheumatic subjects who have overstrained the tendon, +especially during cold and damp weather. There is localised pain which +is aggravated by walking, and the tendon is sensitive and swollen from a +little above its insertion to its junction with the muscle. Gouty +nodules may form in its substance. Constitutional measures, massage, and +douching should be employed, and the tendon should be protected from +strain. + +#Calcification and Ossification in Muscles, Tendons, and +Fasciae.#--_Myositis ossificans._--Ossifications in muscles, tendons, +fasciae, and ligaments, in those who are the subjects of arthritis +deformans, are seldom recognised clinically, but are frequently met with +in dissecting-rooms and museums. Similar localised ossifications are met +with in Charcot's disease of joints, and in fractures which have +repaired with exuberant callus. The new bone may be in the form of +spicules, plates, or irregular masses, which, when connected with a +bone, are called _false exostoses_ (Fig. 110). + +[Illustration: FIG. 110.--Ossification in Tendon of Ilio-psoas Muscle.] + +_Traumatic Ossification in Relation to Muscle._--Various forms of +ossification are met with in muscle as the result of a single or of +repeated injury. Ossification in the crureus or vastus lateralis muscle +has been frequently observed as a result of a kick from a horse. Within +a week or two a swelling appears at the site of injury, and becomes +progressively harder until its consistence is that of bone. If the mass +of new bone moves with the affected muscle, it causes little +inconvenience. If, as is commonly the case, it is fixed to the femur, +the action of the muscle is impaired, and the patient complains of pain +and difficulty in flexing the knee. A skiagram shows the extent of the +mass and its relationship to the femur. The treatment consists in +excising the bony mass. + +Difficulty may arise in differentiating such a mass of bone from +sarcoma; the ossification in muscle is uniformly hard, while the sarcoma +varies in consistence at different parts, and the X-ray picture shows a +clear outline of the bone in the vicinity of the ossification in +muscle, whereas in sarcoma the involvement of the bone is shown by +indentations and irregularity in its contour. + +A similar ossification has been observed in relation to the insertion of +the brachialis muscle as a sequel of dislocation of the elbow. After +reduction of the dislocation, the range of movement gradually diminishes +and a hard swelling appears in front of the lower end of the humerus. +The lump continues to increase in size and in three to four weeks the +disability becomes complete. A radiogram shows a shadow in the muscle, +attached at one part as a rule to the coronoid process. During the next +three or four months, the lump in front of the elbow remains stationary +in size; a gradual decrease then ensues, but the swelling persists, as a +rule, for several years. + +[Illustration: FIG. 111.--Calcification and Ossification in Biceps and +Triceps. + +(From a radiogram lent by Dr. C. A. Adair Dighton.)] + +Ossification in the adductor longus was first described by Billroth +under the name of "rider's bone." It follows bruising and partial +rupture of the muscle, and has been observed chiefly in cavalry +soldiers. If it causes inconvenience the bone may be removed by +operation. + +Ossification in the deltoid and pectoral muscles has been observed in +foot-soldiers in the German army, and has received the name of +"drill-bone"; it is due to bruising of the muscle by the recoil of the +rifle. + +_Progressive Ossifying Myositis._--This is a rare and interesting +disease, in which the muscles, tendons, and fasciae throughout the body +become the seat of ossification. It affects almost exclusively the male +sex, and usually begins in childhood or youth, sometimes after an +injury, sometimes without apparent cause. The muscles of the back, +especially the trapezius and latissimus, are the first to be affected, +and the initial complaint is limitation of movement. + +[Illustration: FIG. 112.--Ossification in Muscles of Trunk in a case of +generalised Ossifying Myositis. + +(Photograph lent by Dr. Rustomjee.)] + +The affected muscles show swellings which are rounded or oval, firm and +elastic, sharply defined, without tenderness and without discoloration +of the overlying skin. Skiagrams show that a considerable deposit of +lime salts may precede the formation of bone, as is seen in Fig. 111. In +course of time the vertebral column becomes rigid, the head is bent +forward, the hips are flexed, and abduction and other movements of the +arms are limited. The disease progresses by fits and starts, until all +the striped muscles of the body are replaced by bone, and all movements, +even those of the jaws, are abolished. The subjects of this disease +usually succumb to pulmonary tuberculosis. + +There is no means of arresting the disease, and surgical treatment is +restricted to the removal or division of any mass of bone that +interferes with an important movement. + +A remarkable feature of this disease is the frequent presence of a +deformity of the great toe, which usually takes the form of hallux +valgus, the great toe coming to lie beneath the second one; the +shortening is usually ascribed to absence of the first phalanx, but it +has been shown to depend also on a synostosis and imperfect development +of the phalanges. A similar deformity of the thumb is sometimes met +with. + +Microscopical examination of the muscles shows that, prior to the +deposition of lime salts and the formation of bone, there occurs a +proliferation of the intra-muscular connective tissue and a gradual +replacement and absorption of the muscle fibres. The bone is spongy in +character, and its development takes place along similar lines to those +observed in ossification from the periosteum. + +#Tumours of Muscle.#--With the exception of congenital varieties, such +as the rhabdomyoma, tumours of muscle grow from the connective-tissue +framework and not from the muscle fibres. Innocent tumours, such as the +fibroma, lipoma, angioma, and neuro-fibroma, are rare. Malignant tumours +may be primary in the muscle, or may result from extension from adjacent +growths--for example, implication of the pectoral muscle in cancer of +the breast--or they may be derived from tumours situated elsewhere. The +diagnosis of an intra-muscular tumour is made by observing that the +swelling is situated beneath the deep fascia, that it becomes firm and +fixed when the muscle contracts, and that, when the muscle is relaxed, +it becomes softer, and can be moved in the transverse axis of the +muscle, but not in its long axis. + +Clinical interest attaches to that form of slowly growing +fibro-sarcoma--_the recurrent fibroid of Paget_--which is most +frequently met with in the muscles of the abdominal wall. A rarer +variety is the ossifying chondro-sarcoma, which undergoes ossification +to such an extent as to be visible in skiagrams. + +In primary sarcoma the treatment consists in removing the muscle. In the +limbs, the function of the muscle that is removed may be retained by +transplanting an adjacent muscle in its place. + +_Hydatid cysts_ of muscle resemble those developing in other tissues. + + +DISEASES OF TENDON SHEATHS + +Tendon sheaths have the same structure and function as the synovial +membranes of joints, and are liable to the same diseases. Apart from the +tendon sheaths displayed in anatomical dissections, there is a loose +peritendinous and perimuscular cellular tissue which is subject to the +same pathological conditions as the tendon sheaths proper. + +#Teno-synovitis.#--The toxic or infective agent is conveyed to the +tendon sheaths through the blood-stream, as in the gouty, gonorrhoeal, +and tuberculous varieties, or is introduced directly through a wound, as +in the common pyogenic form of teno-synovitis. + +_Teno-synovitis Crepitans._--In the simple or traumatic form of +teno-synovitis, although the most prominent etiological factor is a +strain or over-use of the tendon, there would appear to be some other, +probably a toxic, factor in its production, otherwise the affection +would be much more common than it is: only a small proportion of those +who strain or over-use their tendons become the subjects of +teno-synovitis. The opposed surfaces of the tendon and its sheath are +covered with fibrinous lymph, so that there is friction when they move +on one another. + +The _clinical features_ are pain on movement, tenderness on pressure +over the affected tendon, and a sensation of crepitation or friction +when the tendon is moved in its sheath. The crepitation may be soft like +the friction of snow, or may resemble the creaking of new +leather--"saddle-back creaking." There may be swelling in the long axis +of the tendon, and redness and oedema of the skin. If there is an +effusion of fluid into the sheath, the swelling is more marked and +crepitation is absent. There is little tendency to the formation of +adhesions. + +In the upper extremity, the sheath of the long tendon of the biceps may +be affected, but the condition is most common in the tendons about the +wrist, particularly in the extensors of the thumb, and it is most +frequently met with in those who follow occupations which involve +prolonged use or excessive straining of these tendons--for example, +washerwomen or riveters. It also occurs as a result of excessive +piano-playing, fencing, or rowing. + +At the ankle it affects the peronei, the extensor digitorum longus, or +the tibialis anterior. It is most often met with in relation to the +tendo-calcaneus--_Achillo-dynia_--and results from the pressure of +ill-fitting boots or from the excessive use and strain of the tendon in +cycling, walking, or dancing. There is pain in raising the heel from the +ground, and creaking can be felt on palpation. + +The _treatment_ consists in putting the affected tendon at rest, and +with this object a splint may be helpful; the usual remedies for +inflammation are indicated: Bier's hyperaemia, lead and opium +fomentations, and ichthyol and glycerine. The affection readily subsides +under treatment, but is liable to relapse on a repetition of the +exciting cause. + +_Gouty Teno-synovitis._--A deposit of urate of soda beneath the +endothelial covering of tendons or of that lining their sheaths is +commonly met with in gouty subjects. The accumulation of urates may +result in the formation of visible nodular swellings, varying in size +from a pea to a cherry, attached to the tendon and moving with it. They +may be merely unsightly, or they may interfere with the use of the +tendon. Recurrent attacks of inflammation are prone to occur. We have +removed such gouty masses with satisfactory results. + +_Suppurative Teno-synovitis._--This form usually follows upon infected +wounds of the fingers--especially of the thumb or little finger--and is +a frequent sequel to whitlow; it may also follow amputation of a finger. +Once the infection has gained access to the sheath, it tends to spread, +and may reach the palm or even the forearm, being then associated with +cellulitis. In moderately acute cases the tendon and its sheath become +covered with granulations, which subsequently lead to the formation of +adhesions; while in more acute cases the tendon sloughs. The pus may +burst into the cellular tissue outside the sheath, and the suppuration +is liable to spread to neighbouring sheaths or to adjacent bones or +joints--for example, those of the wrist. + +The _treatment_ consists in inducing hyperaemia and making small +incisions for the escape of pus. The site of incision is determined by +the point of greatest tenderness on pressure. After the inflammation has +subsided, active and passive movements are employed to prevent the +formation of adhesions between the tendon and its sheath. If the tendon +sloughs, the dead portion should be cut away, as its separation is +extremely slow and is attended with prolonged suppuration. + +_Gonorrhoeal Teno-synovitis._--This is met with especially in the tendon +sheaths about the wrist and ankle. It may occur in a mild form, with +pain, impairment of movement, and oedema, and sometimes an elongated, +fluctuating swelling, the result of serous effusion into the sheath. +This condition may alternate with a gonorrhoeal affection of one of the +larger joints. It may subside under rest and soothing applications, but +is liable to relapse. In the more severe variety the skin is red, and +the swelling partakes of the characters of a phlegmon with threatening +suppuration; it may result in crippling from adhesions. Even if pus +forms in the sheath, the tendon rarely sloughs. The treatment consists +in inducing hyperaemia by Bier's method; and a vaccine may be employed +with satisfactory results. + +#Tuberculous Disease of Tendon Sheaths.#--This is a comparatively common +affection, and is analogous to tuberculous disease of the synovial +membrane of joints. It may originate in the sheath, or may spread to it +from an adjacent bone. + +The commonest form--hydrops--is that in which the synovial sheath is +distended with a viscous fluid, and the fibrinous material on the free +surface becomes detached and is moulded into melon-seed bodies by the +movement of the tendon. The sheath itself is thickened by the growth of +tuberculous granulation tissue. The bodies are smooth and of a +dull-white colour, and vary greatly in size and shape. There may be an +overgrowth of the fatty fringes of the synovial sheath, a condition +described as "arborescent lipoma." + +The _clinical features_ vary with the tendon sheath affected. In the +common flexor sheath of the hand an hour-glass-shaped swelling is +formed, bulging above and below the transverse carpal (anterior annular) +ligament--formerly known as _compound palmar ganglion_. There is little +or no pain, but the fingers tend to be stiff and weak, and to become +flexed. On palpation, it is usually possible to displace the contents of +the sheath from one compartment to the other, and this may yield +fluctuation, and, what is more characteristic, a peculiar soft crepitant +sensation from the movement of the melon-seed bodies. In the sheath of +the peronei or other tendons about the ankle, the swelling is +sausage-shaped, and is constricted opposite the annular ligament. + +The onset and progress of the affection are most insidious, and the +condition may remain stationary for long periods. It is aggravated by +use or strain of the tendons involved. In exceptional cases the skin is +thinned and gives way, resulting in the formation of a sinus. + +_Treatment._--In the common flexor sheath of the palm, an attempt may be +made to cure the condition by removing the contents through a small +incision and filling the cavity with iodoform glycerine, followed by the +use of Bier's bandage. If this fails, the distended sheath is laid open, +the contents removed, the wall scraped, and the wound closed. + +A less common form of tuberculous disease is that in which the sheath +becomes the seat of _a diffuse tuberculous thickening_, not unlike the +white swelling met with in joints, and with a similar tendency to +caseation. A painless swelling of an elastic character forms in relation +to the tendon sheath. It is hour-glass-shaped in the common flexor +sheath of the palm, elongated or sausage-shaped in the extensors of the +wrist and in the tendons at the ankle. The tuberculous granulation +tissue is liable to break down and lead to the formation of a cold +abscess and sinuses, and in our experience is often associated with +disease in an adjacent bone or joint. In the peronei tendons, for +example, it may result from disease of the fibula or of the ankle-joint. + +When conservative measures fail, excision of the affected sheath should +be performed; the whole of the diseased area being exposed by free +incision of the overlying soft parts, the sheath is carefully isolated +from the surrounding tissues and is cut across above and below. Any +tuberculous tissue on the tendon itself is removed with a sharp spoon. +Associated bone or joint lesions are dealt with at the same time. In the +after-treatment the functions of the tendons must be preserved by +voluntary and passive movements. + +#Syphilitic Affections of Tendon Sheaths.#--These closely resemble the +syphilitic affections of the synovial membrane of joints. During the +secondary period the lesion usually consists in effusion into the +sheath; gummata are met with during the tertiary period. + +Arborescent lipoma has been found in the sheaths of tendons about the +wrist and ankle, sometimes in a multiple and symmetrical form, +unattended by symptoms and disappearing under anti-syphilitic treatment. + +#Tumours of Tendon Sheaths.#--Innocent tumours, such as _lipoma_, +_fibroma_, and _myxoma_, are rare. Special mention should be made of the +_myeloma_ which is met with at the wrist or ankle as an elongated +swelling of slow development, or over the phalanx of a finger as a small +rounded swelling. The tumour tissue, when exposed by dissection, is of a +chocolate or chamois-yellow colour, and consists almost entirely of +giant cells. The treatment consists in dissecting the tumour tissue off +the tendons, and this is usually successful in bringing about a +permanent cure. + +All varieties of _sarcoma_ are met with, but their origin from tendon +sheaths is not associated with special features. + + + + +CHAPTER XIX + +THE BURSAE + + +Anatomy--Normal and adventitious bursae--Injuries: Bursal + haematoma--DISEASES: Infective bursitis; Traumatic or trade + bursitis; Bursal hydrops; Solid bursal tumour; Gonorrhoeal and + suppurative forms of bursitis; Tuberculous and syphilitic + disease--Tumours--_Diseases of individual bursae in the upper and + lower extremities_. + +A bursa is a closed sac lined by endothelium and containing synovia. +Some are normally present--for instance, that between the skin and the +patella, and that between the aponeurosis of the gluteus maximus and the +great trochanter. _Adventitious bursae_ are developed as a result of +abnormal pressure--for example, over the tarsal bones in cases of +club-foot. + +#Injuries of Bursae.#--As a result of contusion, especially in bleeders, +haemorrhage may occur into the cavity of a bursa and give rise to a +_bursal haematoma_. Such a haematoma may mask a fracture of the bone +beneath--for example, fracture of the olecranon. + +#Diseases of Bursae.#--The lining membrane of bursae resembles that of +joints and tendon sheaths, and is liable to the same forms of disease. + +#Infective bursitis# frequently follows abrasions, scratches, and wounds +of the skin over the prepatellar or olecranon bursa, and in neglected +cases the infection transgresses the wall of the bursa and gives rise to +a spreading cellulitis. + +#Traumatic or Trade Bursitis.#--This term may be conveniently applied to +those affections of bursae which result from repeated slight traumatism +incident to particular occupations. The most familiar examples of these +are the enlargement of the prepatellar bursa met with in housemaids--the +"housemaid's knee" (Fig. 113); the enlargement of the olecranon +bursa--"miner's elbow"; and of the ischial bursa--"weaver's" or +"tailor's bottom" (Fig. 116). These affections are characterised by an +effusion of fluid into the sac of the bursa with thickening of its +lining membrane. While friction and pressure are the most evident +factors in their production, it is probable that there is also some +toxic agent concerned, otherwise these affections would be much more +common than they are. Of the countless housemaids in whom the +prepatellar bursa is subjected to friction and pressure, only a small +proportion become the subjects of housemaid's knee. + +_Clinical Features._--As these are best illustrated in the different +varieties of prepatellar bursitis, it is convenient to take this as the +type. In a number of cases the inflammation is acute and the patient is +unable to use the limb; the part is hot, swollen, and tender, and +fluctuation can be detected in the bursa. In the majority the condition +is chronic, and the chief feature is the gradual accumulation of fluid +constituting the _bursal hydrops_ or _hygroma_. When the affection has +lasted some time, or has frequently relapsed, the wall of the bursa +becomes thickened by fibrous tissue, which may be deposited irregularly, +so that septa, bands, or fringes are formed, not unlike those met with +in arthritis deformans. These fringes may be detached and form loose +bodies like those met with in joints; less frequently there are +fibrinous bodies of the melon-seed type, sometimes moulded into circular +discs like wafers. The presence of irregular thickenings of the wall, or +of loose bodies, may be recognised on palpation, especially in +superficial bursae, if the sac is not tensely filled with fluid. The +thickening of the wall may take place in a uniform and concentric +fashion, resulting in the formation of a fibrous tumour--_the solid +bursal tumour_--a small cavity remaining in the centre which serves to +distinguish it from a new growth or neoplasm. + +[Illustration: FIG. 113.--Hydrops of Prepatellar Bursa in a housemaid.] + +The _treatment_ varies according to the variety and stage of the +affection. In recent cases the symptoms subside under rest and the +application of fomentations. Hydrops may be got rid of by blistering, +by tapping, or by incision and drainage. When the wall is thickened, the +most satisfactory treatment is to excise the bursa; the overlying skin +being reflected in the shape of a horse-shoe flap or being removed along +with the bursa. + +#Other Diseases of Bursae# are associated with _gonorrhoeal infection_, +and with _rheumatism_, especially that following scarlet fever, and are +apt to be persistent or to relapse after apparent cure. In the _gouty_ +form, urate of soda is deposited in the wall of the bursa, and may +result in the formation of chalky tumours, sometimes of considerable +size (Fig. 114). + +[Illustration: FIG. 114.--Section through Bursa over external malleolus, +showing deposit of urate of soda. (Cf. Fig. 117.)] + +_Tuberculous disease_ of bursae closely resembles that of tendon sheaths. +It may occur as an independent affection, or may be associated with +disease in an adjacent bone or joint. It is met with chiefly in the +prepatellar and subdeltoid bursae, or in one of the bursae over the great +trochanter. The clinical features are those of an indolent hydrops, with +or without melon-seed bodies, or of uniform thickening of the wall of +the bursa; the tuberculous granulation tissue may break down into a cold +abscess, and give rise to sinuses. The best treatment is to excise the +affected bursa, or, when this is impracticable, to lay it freely open, +remove the tuberculous tissue with the sharp spoon or knife, and treat +the cavity by the open method. + +_Syphilitic disease_ is rarely recognised except in the form of bursal +and peri-bursal gummata in front of the knee-joint. + +_New growths_ include the fibroma, the myxoma, the myeloma or +giant-celled tumour, and various forms of sarcoma. + +#Diseases of Individual Bursae.#--The _olecranon bursa_ is frequently +the seat of pyogenic infection and of traumatic or trade bursitis, the +latter being known as "miner's" or "student's elbow." + +[Illustration: FIG. 115.--Tuberculous Disease of Sub-deltoid Bursa. + +(From a photograph lent by Sir George T. Beatson.)] + +The _sub-deltoid_ or _sub-acromial bursa_, which usually presents a +single cavity and does not normally communicate with the shoulder-joint, +is indispensable in abduction and rotation of the humerus. When the arm +is abducted, the fixed lower part or floor of the bursa is carried under +the acromion, and the upper part or roof is rolled up in the same +direction, hence tenderness over the inflamed bursa may disappear when +the arm is abducted (Dawbarn's sign). It is liable to traumatic +affections from a fall on the shoulder, pressure, or over-use of the +limb. Pain, located commonly at the insertion of the deltoid, is a +constant symptom and is especially annoying at night, the patient being +unable to get into a comfortable position. Tenderness may be elicited +over the anatomical limits of the bursa, and is usually most marked over +the great tuberosity, just external to the inter-tubercular (bicipital) +groove. When adhesions are present, abduction beyond 10 degrees is +impossible. Demonstrable effusion is not uncommon, but is disguised by +the overlying tissues. If left to himself, the patient tends to maintain +the limb in the "sling position," and resists movements in the direction +of abduction and rotation. In the treatment of this affection the arm +should be maintained at a right angle to the body, the arm being rotated +medially (Codman). When pain does not prevent it, movements of the arm +and massage are persevered with. In neglected cases, when adhesions have +formed and the shoulder is fixed, it may be necessary to break down the +adhesions under an anaesthetic. + +The bursa is also liable to infective conditions, such as acute +rheumatism, gonorrhoea, suppuration, or tubercle. In tuberculous disease +a large fluctuating swelling may form and acquire the characters of a +cold abscess (Fig. 115). + +The bursa underneath the tendon of the _subscapularis_ muscle when +inflamed causes alteration in the attitude of the shoulder and +impairment of its movements. + +An adventitious bursa forms over the _acromion_ process in porters and +others who carry weights on the shoulder, and may be the seat of +traumatic bursitis. + +The bursa under the _tendon of insertion of the biceps_, when the seat +of disease, is attended with pain and swelling about a finger's breadth +below the bend of the elbow; there is pain and difficulty in effecting +the combined movement of flexion and supination, slight limitation of +extension, and restriction of pronation. + +In the lower extremity, a large number of normal and adventitious bursae +are met with and may be the seat of bursitis. That over the _tuberosity +of the ischium_, when enlarged as a trade disease, is known as +"weaver's" or "tailor's bottom." It may form a fluctuating swelling of +great size, projecting on the buttock and extending down the thigh, and +causing great inconvenience in sitting (Fig. 116). It sometimes contains +a number of loose bodies. + +There are two bursae over the _great trochanter_, one superficial to, the +other beneath the aponeurosis of the gluteus maximus; the latter is not +infrequently infected by tuberculous disease that has spread from the +trochanter. + +The bursa _between the psoas muscle and the capsule of the hip-joint_ +may be the seat of tuberculous disease, and give rise to clinical +features not unlike those of disease of the hip-joint. The limb is +flexed, abducted and rotated out; there is a swelling in the upper part +of Scarpa's triangle, but the movements are not restricted in directions +which do not entail putting the ilio-psoas muscle on the stretch. + +Cartilaginous and partly ossified loose bodies may accumulate in the +ilio-psoas bursa and distend it, both in a downward direction towards +the hip-joint, with which it communicates, and upwards, projecting +towards the abdomen. + +The bursa beneath the quadriceps extensor--_subcrural bursa_--usually +communicates with the knee-joint and shares in its diseases. When shut +off from the joint it may suffer independently, and when distended with +fluid forms a horse-shoe swelling above the patella. + +In front of the patella and its ligament is the _prepatellar bursa_, +which may have one, two, or three compartments, usually communicating +with one another. It is the seat of the affection known as "housemaid's +knee," which is very common and is sometimes bilateral, and, less +frequently, of tuberculous disease which usually originates in the +patella. + +[Illustration: FIG. 116.--Great Enlargement of the Ischial Bursa. + +(Mr. Scot-Skirving's case.)] + +The bursa _between the ligamentum patellae and the tibia_ is rarely the +seat of disease. When it is, there is pain and tenderness referred to +the ligament, the patient is unable to extend the limb completely, the +tuberosity of the tibia is apparently enlarged, and there is a +fluctuating swelling on either side of the ligament, most marked in the +extended position of the limb. + +Of the numerous bursae in the popliteal space, that _between the +semi-membranosus and the medial head of the gastrocnemius_ is most +frequently the seat of disease, which is usually of the nature of a +simple hydrops, forming a fluctuating egg-or sausage-shaped swelling at +the medial side of the popliteal space. It is flaccid in the flexed, and +tense in the extended position. As a rule it causes little +inconvenience, and may be left alone. Otherwise it should be dissected +out, and if, as is frequently the case, there is a communication with +the knee-joint, this should be closed with sutures. + +[Illustration: FIG. 117.--Gouty Disease of Bursae in a tailor. The bursal +tumours were almost entirely composed of urate of soda. (Cf. Fig. 114.)] + +An adventitious bursa may form over the _lateral malleolus_, especially +in tailors, giving rise to the condition known as "tailor's ankle" +(Fig. 117). + +The bursa _between the tendo-calcaneus (Achillis) and the upper part of +the calcaneus_ may become inflamed--especially as a result of +post-scarlatinal rheumatism or gonorrhoea. The affection is known as +Achillo-bursitis. There is severe pain in the region of the insertion of +the tendo-calcaneus, the movements at the ankle-joint are restricted, +and the patient may be unable to walk. There is a tender swelling on +either side of the tendon. When, in spite of palliative treatment, the +affection persists or relapses, it is best to excise the bursa. The +tendo-calcaneus is detached from the calcaneus, the bursa dissected out, +and the tendon replaced. If there is a bony projection from the +calcaneus, it should be shaved off with the chisel. + +The bursa that is sometimes met with on the under aspect of the +calcaneus--_the subcalcanean bursa_--when inflamed, gives rise to pain +and tenderness in the sole of the foot. This affection may be associated +with a spinous projection from the bone, which is capable of being +recognised in a skiagram. The soft parts of the heel are turned forwards +as a flap, the bursa is dissected out, and the projection of bone, if +present, is removed. + +The enlargement of adventitious bursae over the head of the first +metatarsal in hallux valgus; over the tarsus, metatarsus, and digits in +the different forms of club-foot; over the angular projection in Pott's +disease of the spine; over the end of the bone in amputation stumps, and +over hard tumours such as chondroma and osteoma, are described +elsewhere. + + + + +CHAPTER XX + +DISEASES OF BONE + + +Anatomy and physiology--Regeneration of bone--Transplantation of bone. + DISEASES OF BONE--Definition of terms--Pyogenic diseases: + _Acute osteomyelitis and periostitis_; _Chronic and relapsing + osteomyelitis_; _Abscess of bone_--Tuberculous disease--Syphilitic + disease--Hydatids; Rickets; Osteomalacia--Ostitis deformans of + Paget--Osteomyelitis fibrosa--Affections of bones in diseases of + the nervous system--Fragilitas ossium--Tumours and cysts of bone. + +#Surgical Anatomy.#--During the period of growth, a long bone such as +the tibia consists of a shaft or _diaphysis_, and two extremities or +_epiphyses_. So long as growth continues there intervenes between the +shaft and each of the epiphyses a disc of actively growing +cartilage--_the epiphysial cartilage_; and at the junction of this +cartilage with the shaft is a zone of young, vascular, spongy bone known +as the _metaphysis_ or _epiphysial junction_. The shaft is a cylinder of +compact bone enclosing the medullary canal, which is filled with yellow +marrow. The extremities, which include the ossifying junctions, consist +of spongy bone, the spaces of which are filled with red marrow. The +articular aspect of the epiphysis is invested with a thick layer of +hyaline cartilage, known as the _articular cartilage_, which would +appear to be mainly nourished from the synovia. + +The external investment--the _periosteum_--is thick and vascular during +the period of growth, but becomes thin and less vascular when the +skeleton has attained maturity. Except where muscles are attached it is +easily separated from the bone; at the extremities it is intimately +connected with the epiphysial cartilage and with the epiphysis, and at +the margin of the latter it becomes continuous with the capsule of the +adjacent joint. It consists of two layers, an outer fibrous and an inner +cellular layer; the cells, which are called osteoblasts, are continuous +with those lining the Haversian canals and the medullary cavity. + +The arrangement of the _blood vessels_ determines to some extent the +incidence of disease in bone. The nutrient artery, after entering the +medullary canal through a special foramen in the cortex, bifurcates, and +one main division runs towards each of the extremities, and terminates +at the ossifying junction in a series of capillary loops projected +against the epiphysial cartilage. This arrangement favours the lodgment +of any organisms that may be circulating in the blood, and partly +accounts for the frequency with which diseases of bacterial origin +develop in the region of the ossifying junction. The diaphysis is also +nourished by numerous blood vessels from the periosteum, which penetrate +the cortex through the Haversian canals and anastomose with those +derived from the nutrient artery. The epiphyses are nourished by a +separate system of blood vessels, derived from the arteries which supply +the adjacent joint. The veins of the marrow are of large calibre and are +devoid of valves. + +The _nerves_ enter the marrow along with the arteries, and, being +derived from the sympathetic system, are probably chiefly concerned with +the innervation of the blood vessels, but they are also capable of +transmitting sensory impulses, as pain is a prominent feature of many +bone affections. + +It has long been believed that _the function of the periosteum_ is to +form new bone, but this view has been questioned by Sir William Macewen, +who maintains that its chief function is to limit the formation of new +bone. His experimental observations appear to show that new bone is +exclusively formed by the cellular elements or osteoblasts: these are +found on the surface of the bone, lining the Haversian canals and in the +marrow. We believe that it will avoid confusion in the study of the +diseases of bone if the osteoblasts on the surface of the bone are still +regarded as forming the deeper layer of the periosteum. + +The formation of new bone by the osteoblasts may be _defective_ as a +result of physiological conditions, such as old age and disease of a +part, and defective formation is often associated with atrophy, or more +strictly speaking, absorption, of the existing bone, as is well seen in +the edentulous jaw and in the neck of the femur of a person advanced in +years. Defective formation associated with atrophy is also illustrated +in the bones of the lower limbs of persons who are unable to stand or +walk, and in the distal portion of a bone which is the seat of an +ununited fracture. The same combination is seen in an exaggerated degree +in the bones of limbs that are paralysed; in the case of adults, atrophy +of bone predominates; in children and adolescents, defective formation +is the more prominent feature, and the affected bones are attenuated, +smooth on the surface, and abnormally light. + +On the other hand, the formation of new bone may be _exaggerated_, the +osteoblasts being excited to abnormal activity by stimuli of different +kinds: for example, the secretion of certain glandular organs, such as +the pituitary and thyreoid; the diluted toxins of certain +micro-organisms, such as the staphylococcus aureus and the spirochaete of +syphilis; a condition of hyperaemia, such as that produced artificially +by the application of a Bier's bandage or that which accompanies a +chronic leg-ulcer. + +The new bone is laid down on the surface, in the Haversian canals, or +in the cancellous spaces and medullary canal, or in all three +situations. The new bone on the surface sometimes takes the form of a +diffuse _encrustation_ of porous or spongy bone as in secondary +syphilis, sometimes as a uniform increase in the girth of the +bone--_hyperostosis_, sometimes as a localised heaping up of bone or +_node_, and sometimes in the form of spicules, spoken of as +_osteophytes_. When the new bone is laid down in the Haversian canals, +cancellous spaces and medulla, the bone becomes denser and heavier, and +is said to be _sclerosed_; in extreme instances this may result in +obliteration of the medullary canal. Hyperostosis and sclerosis are +frequently met with in combination, a condition that is well illustrated +in the femur and tibia in tertiary syphilis; if the subject of this +condition is confined to bed for several months before his death, the +sclerosis may be undone, and rarefaction may even proceed beyond the +normal, the bone becoming lighter and richer in fat, although retaining +its abnormal girth. + +The _function of the epiphysial cartilage_ is to provide for the growth +of the shaft in length. While all epiphysial cartilages contribute to +this result, certain of them functionate more actively and for a longer +period than others. Those at the knee, for example, contribute more to +the length of limb than do those at the hip or ankle, and they are also +the last to unite. In the upper limb the more active epiphyses are at +the shoulder and wrist, and these also are the last to unite. + +The activity of the epiphysial cartilage may be modified as a result of +disease. In rickets, for example, the formation of new bone may take +place unequally, and may go on more rapidly in one half of the disc than +in the other, with the result that the axis of the shaft comes to +deviate from the normal, giving rise to knock-knee or bow-knee. In +bacterial diseases originating in the marrow, if the epiphysial junction +is directly involved in the destructive process, its bone-forming +functions may be retarded or abolished, and the subsequent growth of the +bone be seriously interfered with. On the other hand, if it is not +directly involved but is merely influenced by the proximity of an +infective focus, its bone-forming functions may be stimulated by the +diluted toxins and the growth of the bone in length exaggerated. In +paralysed limbs the growth from the epiphyses is usually little short of +the normal. The result of interference with growth is more injurious in +the lower than in the upper limb, because, from the functional point of +view, it is essential that the lower extremities should be approximately +of equal length. In the forearm or leg, where there are two parallel +bones, if the growth of one is arrested the continued growth of the +other results in a deviation of the hand or foot to one side. + +In certain diseases, such as rickets and inherited syphilis, and in +developmental anomalies such as achondroplasia, _dwarfing_ of the +skeleton results from defective growth of bone at the ossifying +junctions. Conversely, excessive growth of bone at the ossifying +junctions results in abnormal height of the skeleton or _giantism_ as a +result, for example, of increased activity of the pituitary in +adolescents, and in eunuchs who have been castrated in childhood or +adolescence; in the latter, union of the epiphyses at the ends of the +long bones is delayed beyond the usual period at which the skeleton +attains maturity. + +#Regeneration of Bone.#--When bone has been lost or destroyed as a +result of injury or disease, it is capable of being reproduced, the +extent to which regeneration takes place varying under different +conditions. The chief part in the regeneration of bone is played by the +osteoblasts in the adjacent marrow and in the deeper layer of the +periosteum. The shaft of a long bone may be reproduced after having been +destroyed by disease or removed by operation. The flat bones of the +skull and the bones of the face, which are primarily developed in +membrane, have little capacity of regeneration; hence, when bone has +been lost or removed in these situations, there results a permanent +defect. + +Wounds or defects in articular cartilage are repaired by fibrous or +osseous tissue derived from the subjacent cancellous spaces. + +_Transplantation of Bone--Bone-grafting._--Clinical experience is +conclusive that a portion of bone which has been completely detached +from its surroundings--for example, a trephine circle, or a flap of bone +detached with the saw, or the loose fragments in a compound +fracture--may become, if replaced in position, firmly and permanently +incorporated with the surrounding bone. Embedded foreign bodies, on the +other hand, such as ivory pegs or decalcified bone, exhibit, on removal +after a sufficient interval, evidence of having been eroded, in the +shape of worm-eaten depressions and perforations, and do not become +united or fused to the surrounding bone. It follows from this that the +implanting of living bone is to be preferred to the implanting of dead +bone or of foreign material. We believe that transplanted living bone +when placed under favourable conditions survives and becomes +incorporated with the bone with which it is in contact, and does not +merely act as a scaffolding. We believe also that the retention of the +periosteum on the graft is not essential, but, by favouring the +establishment of vascular connections, it contributes to the survival of +the graft and the success of the transplantation. Macewen maintains that +bone grafts "take" better if broken up into small fragments; we regard +this as unnecessary. Bone grafts yield better functional results when +they are immovably fixed to the adjacent bone by suture, pegs, or +plates. As in all grafting procedures, asepsis is essential. + +Transplanted bone retains its vitality when embedded in the soft parts, +but is gradually absorbed and replaced by fibrous tissue. + + +DISEASES OF BONE + +The morbid processes met with in bone originate in the same way and lead +to the same results as do similar processes in other tissues. The +structural peculiarities of bone, however, and the important changes +which take place in the skeleton during the period of growth, modify +certain of the clinical and pathological features. + +_Definition of Terms._--Any diseased process that affects the periosteum +is spoken of as _periostitis_; the term _osteomyelitis_ is employed when +it is located in the marrow. The term _epiphysitis_ has been applied to +an inflammatory process in two distinct situations--namely, the +ossifying nucleus in the epiphysis, and the ossifying junction or +metaphysis between the epiphysial cartilage and the diaphysis. We shall +restrict the term to inflammation in the first of these situations. +Inflammation at the ossifying junction is included under the term +osteomyelitis. + +The term _rarefying ostitis_ is applied to any process that is attended +with excessive absorption of the framework of a bone, whereby it becomes +more porous or spongy than it was before, a condition known as +_osteoporosis_. + +The term _caries_ is employed to indicate any diseased process +associated with crumbling away of the trabecular framework of a bone. It +may be considered as the equivalent of ulceration or molecular +destruction in the soft parts. The carious process is preceded by the +formation of granulation tissue in the marrow or periosteum, which eats +away and replaces the bone in contact with it. The subsequent +degeneration and death of the granulation tissue under the necrotic +influence of bacterial toxins results in disintegration and crumbling +away of the trabecular framework of the portion of bone affected. +Clinically, carious bone yields a soft grating sensation under the +pressure of the probe. The macerated bone presents a rough, eroded +surface. + +The term _dry caries_ (_caries sicca_) is applied to that variety which +is unattended with suppuration. + +_Necrosis_ is the term applied to the death of a tangible portion of +bone, and the dead portion when separated is called a _sequestrum_. The +term _exfoliation_ is sometimes employed to indicate the separation or +throwing off of a superficial sequestrum. The edges and deep surface of +the sequestrum present a serrated or worm-eaten appearance due to the +process of erosion by which the dead bone has been separated from the +living. + + +BACTERIAL DISEASES + +The most important diseases in this group are the pyogenic, the +tuberculous, and the syphilitic. + +PYOGENIC DISEASES OF BONE.--These diseases result from +infection with pyogenic organisms, and two varieties or types are +recognised according to whether the organisms concerned reach their seat +of action by way of the blood-stream, or through an infection of the +soft parts in contact with the bone. + + +INFECTIONS THROUGH THE BLOOD-STREAM + +#Diseases caused by the Staphylococcus Aureus.#--As the majority of +pyogenic diseases are due to infection with the staphylococcus aureus, +these will be described first. + +#Acute osteomyelitis# is a suppurative process beginning in the marrow +and tending to spread to the periosteum. The disease is common in +children, but is rare after the skeleton has attained maturity. Boys are +affected more often than girls, in the proportion of three to one, +probably because they are more liable to exposure, to injury, and to +violent exertion. + +_Etiology._--Staphylococci gain access to the blood-stream in various +ways, it may be through the skin or through a mucous surface. + +Such conditions as, for example, a blow, some extra exertion such as a +long walk, or exposure to cold, as in wading, may act as localising +factors. + +The long bones are chiefly affected, and the commonest sites are: either +end of the tibia and the lower end of the femur; the other bones of the +skeleton are affected in rare instances. + +_Pathology._--The disease commences and is most intense in the marrow of +the ossifying junction at one end of the diaphysis; it may commence at +both ends simultaneously--_bipolar osteomyelitis_; or, commencing at one +end, may spread to the other. + +The changes observed are those of intense engorgement of the marrow, +going on to greenish-yellow purulent infiltration. Where the process is +most advanced--that is, at the ossifying junction--there are evidences +of absorption of the framework of the bone; the marrow spaces and +Haversian canals undergo enlargement and become filled with +greenish-yellow pus. This rarefaction of the spongy bone is the earliest +change seen with the X-rays. + +The process may remain localised to the ossifying junction, but usually +spreads along the medullary canal for a varying distance, and also +extends to the periosteum by way of the enlarged Haversian canals. The +pus accumulates under the periosteum and lifts it up from the bone. The +extent of spread in the medullary canal and beneath the periosteum is in +close correspondence. The periosteum of the diaphysis is easily +separated--hence the facility with which the pus spreads along the +shaft; but in the region of the ossifying junction it is raised with +difficulty because of its intimate connection with the epiphysial +cartilage. Less frequently there is more than one collection of pus +under the periosteum, each being derived from a focus of suppuration in +the subjacent marrow. The pus perforates the periosteum, and makes its +way to the surface by the easiest anatomical route, and discharges +externally, forming one or more sinuses through which fresh infection +may take place. The infection may spread to the adjacent joint, either +directly through the epiphysis and articular cartilage, or along the +deep layer of the periosteum and its continuation--the capsular +ligament. When the epiphysis is intra-articular, as, for example, in the +head of the femur, the pus when it reaches the surface of the bone +necessarily erupts directly into the joint. + +While the occurrence of purely periosteal suppuration is regarded as +possible, we are of opinion that the embolic form of staphylococcal +osteomyelitis always originates in the marrow. + +The portion of the diaphysis which has sustained the action of the +concentrated toxins has its vitality further impaired as a result of the +stripping of the periosteum and thrombosis of the blood vessels of the +marrow, so that _necrosis_ of bone is one of the most striking results +of the disease, and as this takes place rapidly, that is, in a day or +two, the term _acute necrosis_, formerly applied to the disease, was +amply justified. + +When there is marked rarefaction of the bone at the ossifying junction, +the epiphysis is liable to be separated--_epiphysiolysis_. The +separation usually takes place through the young bone of the ossifying +junction, and the surfaces of the diaphysis and epiphysis are opposed to +each other by irregular eroded surfaces bathed in pus. The separated +epiphysis may be kept in place by the periosteum, but when this has been +detached by the formation of pus beneath it, the epiphysis is liable to +be displaced by muscular action or by some movement of the limb, or it +is the diaphysis that is displaced, for example, the lower end of the +diaphysis of the femur may be projected into the popliteal space. + +The epiphysial cartilage usually continues its bone-forming functions, +but when it has been seriously damaged or displaced, the further growth +of the bone in length may be interfered with. Sometimes the separated +and displaced epiphysis dies and constitutes a sequestrum. + +The adjacent joint may become filled at an early stage with a serous +effusion, which may be sterile. When the cocci gain access to the joint, +the lesion assumes the characters of a purulent arthritis, which, from +its frequency during the earlier years of life, has been called _the +acute arthritis of infants_. + +Separation of an epiphysis nearly always results in infection and +destruction of the adjacent joint. + +Osteomyelitis is rare in the bones of the carpus and tarsus, and the +associated joints are usually infected from the outset. In flat bones, +such as the skull, the scapula, or the ilium, suppuration usually occurs +on both aspects of the bone as well as in the marrow. + +_Clinical Features._--The constitutional symptoms, which are due to the +associated toxaemia, vary considerably in different cases. In mild cases +they may be so slight as to escape recognition. In exceptionally severe +cases the patient may succumb before there are obvious signs of the +localisation of the staphylococci in the bone marrow. In average cases +the temperature rises rapidly with a rigor and runs an irregular course +with morning remissions, there is marked general illness accompanied by +headache, vomiting, and sometimes delirium. + +The local manifestations are pain and tenderness in relation to one of +the long bones; the pain may be so severe as to prevent sleep and to +cause the child to cry out. Tenderness on pressure over the bone is the +most valuable diagnostic sign. At a later stage there is an ill-defined +swelling in the region of the ossifying junction, with oedema of the +overlying skin and dilatation of the superficial veins. + +The swelling appears earlier and is more definite in superficial bones +such as the tibia, than in those more deeply placed such as the upper +end of the femur. It may be less evident to the eye than to the fingers, +and is best appreciated by gently stroking the bone from the middle of +its shaft towards the end. The maximum thickening and tenderness usually +correspond to the junction of the diaphysis with the epiphysis, and the +swelling tails off gradually along the shaft. As time goes on there is +redness of the skin, especially over a superficial bone, such as the +tibia, the swelling becomes softer, and gives evidence of fluctuation. +This stage may be reached at the end of twenty-four hours, or not for +some days. + +Suppuration spreads towards the surface, until, some days later, the +skin sloughs and pus escapes, after which the fever usually remits and +the pain and other symptoms are relieved. The pus may contain blood and +droplets of fat derived from the marrow, and in some cases minute +particles of bone are present also. The presence of fat and bony +particles in the pus confirms the medullary origin of the suppuration. + +If an incision is made, the periosteum is found to be raised from the +bone; the extent of the bare bone will be found to correspond fairly +accurately with the extent of the lesion in the marrow. + +_Local Complications._--The adjacent joint may exhibit symptoms which +vary from those of a simple effusion to those of a purulent _arthritis_. +The joint symptoms may count for little in the clinical picture, or, as +in the case of the hip, may so predominate as to overshadow those of the +bone lesion from which they originated. + +_Separation and displacement of the epiphysis_ usually reveals itself by +an alteration in the attitude of the limb; it is nearly always +associated with suppuration in the adjacent joint. + +When _pathological fracture_ of the shaft occurs, as it may do, from +some muscular effort or strain, it is attended with the usual signs of +fracture. + +_Dislocation_ of the adjacent joint has been chiefly observed at the +hip; it may result from effusion into the joint and stretching of the +ligaments, or may be the sequel of a purulent arthritis; the signs of +dislocation are not so obvious as might be expected, but it is attended +with an alteration in the attitude of the limb, and the displacement of +the head of the bone is readily shown in a skiagram. + +_General Complications._--In some cases a _multiplicity of lesions_ in +the bones and joints imparts to the disease the features of pyaemia. The +occurrence of endocarditis, as indicated by alterations in the heart +sounds and the development of murmurs, may cause widespread infective +embolism, and metastatic suppurations in the kidneys, heart-wall, and +lungs, as well as in other bones and joints than those primarily +affected. The secondary suppurations are liable to be overlooked unless +sought for, as they are rarely attended with much pain. + +In these multiple forms of osteomyelitis the toxaemic symptoms +predominate; the patient is dull and listless, or he may be restless and +talkative, or actually delirious. The tongue is dry and coated, the lips +and teeth are covered with sordes, the motions are loose and offensive, +and may be passed involuntarily. The temperature is remittent and +irregular, the pulse small and rapid, and the urine may contain blood +and albumen. Sometimes the skin shows erythematous and purpuric rashes, +and the patient may cry out as in meningitis. The post-mortem +appearances are those of pyaemia. + +_Differential Diagnosis._--Acute osteomyelitis is to be diagnosed from +infections of the soft parts, such as erysipelas and cellulitis, and, in +the case of the tibia, from erythema nodosum. Tenderness localised to +the ossifying junction is the most valuable diagnostic sign of +osteomyelitis. + +When there is early and pronounced general intoxication, there is likely +to be confusion with other acute febrile illnesses, such as scarlet +fever. In all febrile conditions in children and adolescents, the +ossifying junctions of the long bones should be examined for areas of +pain and tenderness. + +Osteomyelitis has many features in common with acute articular +rheumatism, and some authorities believe them to be different forms of +the same disease (Kocher). In acute rheumatism, however, the joint +symptoms predominate, there is an absence of suppuration, and the pains +and temperature yield to salicylates. + +The _prognosis_ varies with the type of the disease, with its +location--the vertebrae, skull, pelvis, and lower jaw being specially +unfavourable--with the multiplicity of the lesions, and with the +development of endocarditis and internal metastases. + +_Treatment._--This is carried out on the same lines as in other pyogenic +infections. + +In the earliest stages of the disease, the induction of hyperaemia is +indicated, and should be employed until the diagnosis is definitely +established, and in the meantime preparations for operation should be +made. An incision is made down to and through the periosteum, and +whether pus is found or not, the bone should be opened in the vicinity +of the ossifying junction by means of a drill, gouge, or trephine. If +pus is found, the opening in the bone is extended along the shaft as far +as the periosteum has been separated, and the infected marrow is removed +with the spoon. The cavity is then lightly packed with rubber dam, or, +as recommended by Bier, the skin edges are brought together by sutures +which are loosely tied to afford sufficient space between them for the +exit of discharge, and the hyperaemic treatment is continued. + +When there is widespread suppuration in the marrow, and the shaft is +extensively bared of periosteum and appears likely to die, it may be +resected straight away or after an interval of a day or two. Early +resection of the shaft is also indicated if the opening of the medullary +canal is not followed by relief of symptoms. In the leg and forearm, the +unaffected bone maintains the length and contour of the limb; in the +case of the femur and humerus, extension with weight and pulley along +with some form of moulded gutter splint is employed with a similar +object. + +Amputation of the limb is reserved for grave cases, in which life is +endangered by toxaemia, which is attributed to the primary lesion. It may +be called for later if the limb is likely to be useless, as, for +example, when the whole shaft of the bone is dead without the formation +of a new case, when the epiphyses are separated and displaced, and the +joints are disorganised. + +Flat bones, such as the skull or ilium, must be trephined and the pus +cleared out from both aspects of the bone. In the vertebrae, operative +interference is usually restricted to opening and draining the +associated abscess. + +#Nature's Effort at Repair.#--_In cases which are left to nature_, and +in which necrosis of bone has occurred, those portions of the periosteum +and marrow which have retained their vitality resume their osteogenetic +functions, often to an exaggerated degree. Where the periosteum has been +lifted up by an accumulation of pus, or is in contact with bone that is +dead, it proceeds to form new bone with great activity, so that the dead +shaft becomes surrounded by a sheath or case of new bone, known as the +_involucrum_ (Fig. 118). Where the periosteum has been perforated by pus +making its way to the surface, there are defects or holes in the +involucrum, called _cloacae_. As these correspond more or less in +position to the sinuses in the skin, in passing a probe down one of the +sinuses it usually passes through a cloaca and strikes the dead bone +lying in the interior. If the periosteum has been extensively +destroyed, new bone may only be formed in patches, or not at all. The +dead bone is separated from the living by the agency of granulation +tissue with its usual complements of phagocytes and osteoclasts, so that +the sequestrum presents along its margins and on its deep surface a +pitted, grooved, and worm-eaten appearance, except on the periosteal +aspect, which is unaltered. Ultimately the dead bone becomes loose and +lies in a cavity a little larger than itself; the wall of the cavity is +formed by the new case, lined with granulation tissue. The separation of +the sequestrum takes place more rapidly in the spongy bone of the +ossifying junction than in the compact bone of the shaft. + +When foci of suppuration have been scattered up and down the medullary +cavity, and the bone has died in patches, several sequestra may be +included by the new case; each portion of dead bone is slowly separated, +and comes to lie in a cavity lined by granulations. + +Even at a distance from the actual necrosis there is formation of new +bone by the marrow; the medullary canal is often obliterated, and the +bone becomes heavier and denser--sclerosis; and the new bone which is +deposited on the original shaft results in an increase in the girth of +the bone--hyperostosis. + +[Illustration: FIG. 118.--Shaft of Femur after Acute Osteomyelitis. The +shaft has undergone extensive necrosis, and a shell of new bone has been +formed by the periosteum.] + +_Pathological fracture_ of the shaft may occur at the site of necrosis, +when the new case is incapable of resisting the strain put upon it, and +is most frequently met with in the shaft of the femur. Short of +fracture, there may be bending or curving of the new case, and this +results in deformity and shortening of the limb (Fig. 119). + +The _extrusion of a sequestrum_ may occur, provided there is a cloaca +large enough to allow of its escape, but the surgeon has usually to +interfere by performing the operation of sequestrectomy. Displacement or +partial extrusion of the dead bone may cause complications, as when a +sequestrum derived from the trigone of the femur perforates the +popliteal artery or the cavity of the knee-joint, or a sequestrum of the +pelvis perforates the wall of the urinary bladder. + +The extent to which bone which has been lost is reproduced varies in +different parts of the skeleton: while the long bones, the scapula, the +mandible, and other bones which are developed in cartilage are almost +completely re-formed, bones which are entirely developed in membrane, +such as the flat bones of the skull and the maxilla, are not reproduced. + +[Illustration: FIG. 119.--Femur and Tibia showing results of Acute +Osteomyelitis affecting Trigone of Femur; sequestrum partly surrounded +by new case; backward displacement of lower epiphysis and implication of +knee-joint.] + +It may be instructive to describe _the X-ray appearances of a long bone +that has passed through an attack of acute osteomyelitis_ severe enough +to have caused necrosis of part of the diaphysis. The shadow of the dead +bone is seen in the position of the original shaft which it represents; +it is of the same shape and density as the original shaft, while its +margins present an irregular contour from the erosion concerned in its +separation. The sequestrum is separated from the living bone by a clear +zone which corresponds to the layer of granulations lining the cavity in +which it lies. This clear zone separating the shadow of the dead bone +from that of the living bone by which it is surrounded is conclusive +evidence of a sequestrum. The medullary canal in the vicinity of the +sequestrum being obliterated, is represented by a shadow of varying +density, continuous with that of the surrounding bone. The shadow of the +new case or involucrum with its wavy contour is also in evidence, with +its openings or cloacae, and is mainly responsible for the increase in +the diameter of the bone. + +The skiagram may also show separation and displacement of the adjacent +epiphysis and destruction of the articular surfaces or dislocation of +the joint. + +_Sequelae of Acute Suppurative Osteomyelitis._--The commonest sequel is +the presence of a sequestrum with one or more discharging sinuses; owing +to the abundant formation of scar tissue these sinuses have rigid edges +which are usually depressed and adherent to the bone. + +_The Recognition and Removal of Sequestra._--So long as there is dead +bone there will be suppuration from the granulations lining the cavity +in which it lies, and a discharge of pus from the sinuses, so that the +mere persistence of discharge after an attack of osteomyelitis, is +presumptive evidence of the occurrence of necrosis. Where there are one +or more sinuses, the passage of a probe which strikes bare bone affords +corroboration of the view that the bone has perished. When the dead bone +has been separated from the living, the X-rays yield the most exact +information. + +The traditional practice is to wait until the dead bone is entirely +separated before undertaking an operation for its removal, from fear, on +the one hand, of leaving portions behind which may keep up the +discharge, and, on the other, of removing more bone than is necessary. +This practice need not be adhered to, as by operating at an earlier +stage healing is greatly hastened. If it is decided to wait for +separation of the dead bone, drainage should be improved, and the +infective element combated by the induction of hyperaemia. + +_The operation_ for the removal of the dead bone (_sequestrectomy_) +consists in opening up the periosteum and the new case sufficiently to +allow of the removal of all the dead bone, including the most minute +sequestra. The limb having been rendered bloodless, existing sinuses are +enlarged, but if these are inconveniently situated--for example, in the +centre of the popliteal space in necrosis of the femoral trigone--it is +better to make a fresh wound down to the bone on that aspect of the +limb which affords best access, and which entails the least injury of +the soft parts. The periosteum, which is thick and easily separable, is +raised from the new case with an elevator, and with the chisel or gouge +enough of the new bone is taken away to allow of the removal of the +sequestrum. Care must be taken not to leave behind any fragment of dead +bone, as this will interfere with healing, and may determine a relapse +of suppuration. + +The dead bone having been removed, the lining granulations are scraped +away with a spoon, and the cavity is disinfected. + +There are different ways of dealing with a _bone cavity_. It may be +packed with gauze (impregnated with "bipp" or with iodoform), which is +changed at intervals until healing takes place from the bottom; it may +be filled with a flap of bone and periosteum raised from the vicinity, +or with bone grafts; or the wall of bone on one side of the cavity may +be chiselled through at its base, so that it can be brought into contact +with the opposite wall. The method of filling bone cavities devised by +Mosetig-Moorhof, consists in disinfecting and drying the cavity by a +current of hot air, and filling it with a mixture of powdered iodoform +(60 parts) and oil of sesame and spermaceti (each 40 parts), which is +fluid at a temperature of 112 o F.; the soft parts are then brought +together without drainage. As the cavity fills up with new bone the +iodoform is gradually absorbed. Iodoform gives a dark shadow with the +X-rays, so that the process of its absorption can be followed in +skiagrams taken at intervals. + +These procedures may be carried out at the same time as the sequestrum +is removed, or after an interval. In all of them, asepsis is essential +for success. + +The _deformities_ resulting from osteomyelitis are more marked the +earlier in life the disease occurs. Even under favourable conditions, +and with the continuous effort at reconstruction of the bone by Nature's +method, the return to normal is often far from perfect, and there +usually remains a variable amount of hyperostosis and sclerosis and +sometimes curving of the bone. Under less favourable conditions, the +late results of osteomyelitis may be more serious. _Shortening_ is not +uncommon from interference with growth at the ossifying junction. +_Exaggerated growth_ in the length of a bone is rare, and has been +observed chiefly in the bones of the leg. Where there are two parallel +bones--as in the leg, for example--the growth of the diseased bone may +be impaired, and the other continuing its normal growth becomes +disproportionately long; less frequently the growth of the diseased +bone is exaggerated, and it becomes the longer of the two. In either +case, the longer bone becomes curved. An _obliquity_ of the bone may +result when one half of the epiphysial cartilage is destroyed and the +other half continues to form bone, giving rise to such deformities as +knock-knee and club-hand. + +Deformity may also result from vicious union of a pathological fracture, +permanent displacement of an epiphysis, contracture, ankylosis, or +dislocation of the adjacent joint. + +#Relapsing Osteomyelitis.#--As the term indicates, the various forms of +relapsing osteomyelitis date back to an antecedent attack, and their +occurrence depends on the capacity of staphylococci to lie latent in the +marrow. + +Relapse may take place within a few months of the original attack, or +not for many years. Cases are sometimes met with in which relapses recur +at regular intervals for several years, the tendency, however, being for +the attacks to become milder as the virulence of the organisms becomes +more and more attenuated. + +_Clinical Features._--Osteomyelitis in a patient over twenty-five is +nearly always of the relapsing variety. In some cases the bone becomes +enlarged, with pain and tenderness on pressure; in others there are the +usual phenomena which attend suppuration, but the pus is slow in coming +to the surface, and the constitutional symptoms are slight. The pus may +escape by new channels, or one of the old sinuses may re-open. +Radiograms usually furnish useful information as to the condition of the +bone, both as it is altered by the original attack and by the changes +that attend the relapse of the infective process. + +_Treatment._--In cases of thickening of the bone with persistent and +severe pain, if relief is not afforded by the repeated application of +blisters, the thickened periosteum should be incised, and the bone +opened up with the chisel or trephine. In cases attended with +suppuration, the swelling is incised and drained, and if there is a +sequestrum, it must be removed. + +#Circumscribed Abscess of Bone--"Brodie's Abscess."#--The most important +form of relapsing osteomyelitis is the circumscribed abscess of bone +first described by Benjamin Brodie. It is usually met with in young +adults, but we have met with it in patients over fifty. Several years +may intervene between the original attack of osteomyelitis and the onset +of symptoms of abscess. + +_Morbid Anatomy._[7]--The abscess is nearly always situated in the +central axis of the bone in the region of the ossifying junction, +although cases are occasionally met with in which it lies nearer the +middle of the shaft. In exceptional cases there is more than one abscess +(Fig. 120). The tibia is the bone most commonly affected, but the lower +end of the femur, or either end of the humerus, may be the seat of the +abscess. In the quiescent stage the lesion is represented by a small +cavity in the bone, filled with clear serum, and lined by a fibrous +membrane which is engaged in forming bone. Around the cavity the bone is +sclerosed, and the medullary canal is obliterated. When the infection +becomes active, the contents of the cavity are transformed into a +greenish-yellow pus from which the staphylococcus can be isolated, and +the cavity is lined by a thin film of granulation tissue which erodes +the surrounding bone and so causes the abscess to increase in size. If +the erosion proceeds uniformly, the cavity is spherical or oval; if it +is more active at some points than others, diverticula or tunnels are +formed, and one of these may finally erupt through the shell of the bone +or into an adjacent joint. Small irregular sequestra are occasionally +found within the abscess cavity. In long-standing cases it is common to +find extensive obliteration of the medullary canal, and a considerable +increase in the girth of the bone. + +[7] Alexis Thomson, _Edin. Med. Journ._, 1906. + +[Illustration: FIG. 120.--Segment of Tibia resected for Brodie's +Abscess. The specimen shows two separate abscesses in the centre of the +shaft, the lower one quiescent, the upper one active and increasing in +size.] + +The size of the abscess ranges from that of a cherry to that of a +walnut, but specimens in museums show that, if left to Nature, the +abscess may attain much greater dimensions. + +The affected bone is not only thicker and heavier than normal, but may +also be curved or otherwise deformed as a result of the original attack +of osteomyelitis. + +The _clinical features_ are almost exclusively local. Pain, due to +tension within the abscess, is the dominant symptom. At first it is +vague and difficult to localise, later it is referred to the interior of +the bone, and is described as "boring." It is aggravated by use of the +limb, and there are often, especially during the night, exacerbations in +which the pain becomes excruciating. In the early stages there are +periods of days or weeks during which the symptoms abate, but as the +abscess increases these become shorter, until the patient is hardly ever +free from pain. Localised tenderness can almost always be elicited by +percussion, or by compressing the bone between the fingers and thumb. +The pain induced by the traction of muscles attached to the bone, or by +the weight of the body, may interfere with the function of the limb, and +in the lower extremity cause a limp in walking. The limb may be disabled +from _involvement of the adjacent joint_, in which there may be an +intermittent hydrops which comes and goes coincidently with +exacerbations of pain; or the abscess may perforate the joint and set up +an acute arthritis. + +The _diagnosis_ of Brodie's abscess from other affections met with at +the ends of long bones, and particularly from tuberculosis, syphilis, +and new growths, is made by a consideration of the previous history, +especially with reference to an antecedent attack of osteomyelitis. When +the adjacent joint is implicated, the surgeon may be misled by the +patient referring all the symptoms to the joint. + +The X-ray picture is usually diagnostic chiefly because all the lesions +which are liable to be confused with Brodie's abscess--gumma, tubercle, +myeloma, chondroma, and sarcoma--give a well-marked central clear area; +the sclerosis around Brodie's abscess gives a dense shadow in which the +central clear area is either not seen at all or only faintly (Fig. 121). + +_Treatment._--If an abscess is suspected, there should be no hesitation +in exploring the interior of the bone. It is exposed by a suitable +incision; the periosteum is reflected and the bone is opened up by a +trephine or chisel, and the presence of an abscess may be at once +indicated by the escape of pus. If, owing to the small size of the +abscess or the density of the bone surrounding it, the pus is not +reached by this procedure, the bone should be drilled in different +directions. + +[Illustration: FIG. 121.--Radiogram of Brodie's Abscess in Lower End of +Tibia.] + +#Other Forms of Acute Osteomyelitis.#--Among the less severe forms of +osteomyelitis resulting from the action of attenuated organisms are the +_serous_ variety, in which an effusion of serous fluid forms under the +periosteum; and _growth fever_, in which the child complains of vague +evanescent pains (growing pains), and of feeling tired and disinclined +to play; there may be some rise of temperature in the evening. + +Infection with the _staphylococcus albus_, the _streptococcus_, or the +_pneumococcus_ also causes a mild form of osteomyelitis which may go on +to suppuration. + +_Necrosis without suppuration_, described by Paget under the name "quiet +necrosis," is a rare disease, and would appear to be associated with an +attenuated form of staphylococcal infection (Tavel). It occurs in +adults, being met with up to the age of fifty or sixty, and is +characterised by the insidious development of a swelling which involves +a considerable extent of a long bone. The pain varies in intensity, and +may be continuous or intermittent, and there is tenderness on pressure. +The shaft is increased in girth as a result of its being surrounded by a +new case of bone. The resemblance to sarcoma may be very close, but the +swelling is not as defined as in sarcoma, nor does it ever assume the +characteristic "leg of mutton" shape. In both diseases there is a +tendency to pathological fracture. It is difficult also in the absence +of skiagrams to differentiate the condition from syphilitic and from +tuberculous disease. If the diagnosis is not established after +examination with the X-rays, an exploratory incision should be made; if +dead bone is found, it is removed. + +In typhoid fever the bone marrow is liable to be invaded by _the typhoid +bacillus_, which may set up osteomyelitis soon after its lodgment, or it +may lie latent for a considerable period before doing so. The lesions +may be single or multiple, they involve the marrow or the periosteum or +both, and they may or may not be attended with suppuration. They are +most commonly met with in the tibia and in the ribs at the +costo-chondral junctions. + +The bone lesions usually occur during the seventh or eighth week of the +fever, but have been known to occur much later. The chief complaint is +of vague pains, at first referred to several bones, later becoming +localised in one; they are aggravated by movement, or by handling the +bone, and are worst at night. There is redness and oedema of the +overlying soft parts, and swelling with vague fluctuation, and on +incision there escapes a yellow creamy pus, or a brown syrupy fluid +containing the typhoid bacillus in pure culture. Necrosis is +exceptional. + +When the abscess develops slowly, the condition resembles tuberculous +disease, from which it may be diagnosed by the history of typhoid fever, +and by obtaining a positive Widal reaction. + +The prognosis is favourable, but recovery is apt to be slow, and relapse +is not uncommon. + +It is usually sufficient to incise the periosteum, but when the disease +occurs in a rib it may be necessary to resect a portion of bone. + +#Pyogenic Osteomyelitis due to Spread of Infection from the Soft +Parts.#--There still remain those forms of osteomyelitis which result +from infection through a wound involving the bone--for example, compound +fractures, gun-shot injuries, osteotomies, amputations, resections, or +operations for un-united fracture. In all of these the marrow is exposed +to infection by such organisms as are present in the wound. A similar +form of osteomyelitis may occur apart from a wound--for example, +infection may spread to the jaws from lesions of the mouth; to the +skull, from lesions of the scalp or of the cranial bones +themselves--such as a syphilitic gumma or a sarcoma which has fungated +externally; or to the petrous temporal, from suppuration in the middle +ear. + +The most common is an osteomyelitis commencing in the marrow exposed in +a wound infected with pyogenic organisms. In amputation stumps, +fungating granulations protrude from the sawn end of the bone, and if +necrosis takes place, the sequestrum is annular, affecting the +cross-section of the bone at the saw-line; or tubular, extending up the +shaft, and tapering off above. The periosteum is more easily detached, +is thicker than normal, and is actively engaged in forming bone. In the +macerated specimen, the new bone presents a characteristic coral-like +appearance, and may be perforated by cloacae (Fig. 122). + +[Illustration: FIG. 122.--Tubular Sequestrum resulting from Septic +Osteomyelitis in Amputation Stump.] + +Like other pyogenic infections, it may terminate in pyaemia, as a result +of septic phlebitis in the marrow. + +The _clinical features_ of osteomyelitis in _an amputation stump_ are +those of ordinary pyogenic infection; the involvement of the bone may be +suspected from the clinical course, the absence of improvement from +measures directed towards overcoming the sepsis in the soft parts, and +the persistence of suppuration in spite of free drainage, but it is not +recognised unless the bone is exposed by opening up the stump or the +changes in the bone are shown by the X-rays. The first change is due to +the deposit of new bone on the periosteal surface; later, there is the +shadow of the sequestrum. + +Healing does not take place until the sequestrum is extruded or removed +by operation. + +_In compound fractures_, if a fragment dies and forms a sequestrum, it +is apt to be walled in by new bone; the sinuses continue to discharge +until the sequestrum is removed. Even after healing has taken place, +relapse is liable to occur, especially in gun-shot injuries. Months or +years afterwards, the bone may become painful and tender. The symptoms +may subside under rest and elevation of the limb and the application of +a compress, or an abscess forms and bursts with comparatively little +suffering. The contents may be clear yellow serum or watery pus; +sometimes a small spicule of bone is discharged. Valuable information, +both for diagnosis and treatment, is afforded by skiagrams. + +[Illustration: FIG. 123.--New Periosteal Bone on surface of Femur from +Amputation Stump. Osteomyelitis supervened on the amputation, and +resulted in necrosis at the sawn section of the bone. (Anatomical +Museum, University of Edinburgh.)] + + +TUBERCULOUS DISEASE + +The tuberculous diseases of bone result from infection of the marrow or +periosteum by tubercle bacilli conveyed through the arteries; it is +exceedingly rare for tubercle to appear in bone as a primary infection, +the bacilli being usually derived from some pre-existing focus in the +bronchial glands or elsewhere. According to the observations of John +Fraser, 60 per cent. of the cases of bone and joint tubercle in children +are due to the bovine bacillus, 37 per cent. to the human variety, and +in 3 per cent. both types are present. + +Tuberculous disease in bone is characterised by its insidious onset and +slow progress, and by the frequency with which it is associated with +disease of the adjacent joint. + +#Periosteal tuberculosis# is met with in the ribs, sternum, vertebral +column, skull, and less frequently in the long bones of the limbs. It +may originate in the periosteum, or may spread thence from the marrow, +or from synovial membrane. + +_In superficial bones_, such as the sternum, the formation of +tuberculous granulation tissue in the deeper layer of the periosteum, +and its subsequent caseation and liquefaction, is attended by the +insidious development of a doughy swelling, which is not as a rule +painful, although tender on pressure. While the swelling often remains +quiescent for some time, it tends to increase in size, to become boggy +or fluctuating, and to assume the characters of a cold abscess. The pus +perforates the fibrous layer of the periosteum, invading and infecting +the overlying soft parts, its spread being influenced by the anatomical +arrangement of the tissues. The size of the abscess affords no +indication of the extent of the bone lesion from which it originates. As +the abscess reaches the surface, the skin becomes of a dusky red or +livid colour, is gradually thinned out, and finally sloughs, forming a +sinus. A probe passed into the sinus strikes carious bone. Small +sequestra may be found embedded in the granulation tissue. The sinus +persists as long as any active tubercle remains in the tissues, and is +apt to form an avenue for pyogenic infection. + +_In deeply seated bones_, such as the upper end of the femur, the +formation of a cold abscess in the soft parts is often the first +evidence of the disease. + +_Diagnosis._--Before the stage of cold abscess is reached, the localised +swelling is to be differentiated from a gumma, from chronic forms of +staphylococcal osteomyelitis, from enlarged bursa or ganglion, from +sub-periosteal lipoma, and from sarcoma. Most difficulty is met with in +relation to periosteal sarcoma, which must be differentiated either by +the X-ray appearances or by an exploratory incision. + +_X-ray appearances in periosteal tubercle_: the surface of the cortical +bone in the area of disease is roughened and irregular by erosion, and +in the vicinity there may be a deposit of new bone on the surface, +particularly if a sinus is present and mixed infection has occurred; in +_syphilis_ the shadow of the bone is denser as a result of sclerosis, +and there is usually more new bone on the surface--hyperostosis; in +_periosteal sarcoma_ there is greater erosion and consequently greater +irregularity in the contour of the cortical bone, and frequently there +is evidence of formation of bone in the form of characteristic spicules +projecting from the surface at a right angle. + +The early recognition of periosteal lesions in the articular ends of +bones is of importance, as the disease, if left to itself, is liable to +spread to the adjacent joint. + +The _treatment_ is that of tuberculous lesions in general; if +conservative measures fail, the choice lies between the injection of +iodoform, and removal of the infected tissues with the sharp spoon. In +the ribs it is more satisfactory to remove the diseased portion of bone +along with the wall of the associated abscess or sinus. If all the +tubercle has been removed and there is no pyogenic infection, the wound +is stitched up with the object of obtaining primary union; otherwise it +is treated by the open method. + +#Tuberculous Osteomyelitis.#--Tuberculous lesions in the marrow occur as +isolated or as multiple foci of granulation tissue, which replace the +marrow and erode the trabeculae of bone in the vicinity (Fig. 124). The +individual focus varies in size from a pea to a walnut. The changes that +ensue resemble in character those in other tissues, and the extent of +the destruction varies according to the way in which the tubercle +bacillus and the marrow interact upon one another. The granulation +tissue may undergo caseation and liquefaction, or may become +encapsulated by fibrous tissue--"encysted tubercle." + +[Illustration: FIG. 124.--Tuberculous Osteomyelitis of Os Magnum, +excised from a boy aet. 8. Note well-defined caseous focus, with several +minute foci in surrounding marrow.] + +Sometimes the tuberculous granulation tissue spreads in the marrow, +assuming the characters of a diffuse infiltration--diffuse tuberculous +osteomyelitis. The trabecular framework of the bone undergoes erosion +and absorption--rarefying ostitis--and either disappears altogether or +only irregular fragments or sequestra of microscopic dimensions remain +in the area affected. Less frequently the trabecular framework is added +to by the formation of new bone, resulting in a remarkable degree of +sclerosis, and if, following upon this, there is caseation of the +tubercle and death of the affected portion of bone, there results a +sequestrum often of considerable size and characteristic shape, which, +because of the sclerosis and surrounding endarteritis, is exceedingly +slow in separating. When the sequestrum involves an articular surface it +is often wedge-shaped; in other situations it is rounded or truncated +and lies in the long axis of the medullary canal (Fig. 125). Finally, +the sequestrum lies loose in a cavity lined by tuberculous granulation +tissue, and is readily identified in a radiogram. This type of sclerosis +preceding death of the bone is highly characteristic of tuberculosis. + +[Illustration: FIG. 125.--Tuberculous Disease of Child's Tibia, +showing sequestrum in medullary cavity, and increase in girth from +excess of new bone.] + +_Clinical Features._--As a rule, it is only in superficially placed +bones, such as the tibia, ulna, clavicle, mandible, or phalanges, that +tuberculous disease in the marrow gives rise to signs sufficiently +definite to allow of its clinical recognition. In the vertebrae, or in +the bones of deeply seated joints, such as the hip or shoulder, the +existence of tuberculous lesions in the marrow can only be inferred from +indirect signs--such, for example, as rigidity and curvature in the case +of the spine, or from the symptoms of grave and persistent joint-disease +in the case of the hip or shoulder. + +With few exceptions, tuberculous disease in the interior of a bone does +not reveal its presence until by extension it reaches one or other of +the surfaces of the bone. In the shaft of a long bone its eruption on +the periosteal surface is usually followed by the formation of a cold +abscess in the overlying soft parts. When situated in the articular ends +of bones, the disease more often erupts in relation to the reflection of +the synovial membrane or directly on the articular surface--in either +case giving rise to disease of the joint (Fig. 156). + +[Illustration: Fig. 126.--Diffuse Tuberculous Osteomyelitis of Right +Tibia. + +(Photograph lent by Sir H. J. Stiles.)] + +#Diffuse Tuberculous Osteomyelitis in the shaft of a long bone# is +comparatively rare, and has been observed chiefly in the tibia and the +ulna in children (Fig. 126). It commences at the growing extremity of +the diaphysis, and spreads along the medulla to a variable extent; it is +attended by the formation of vascular and porous bone on the surface, +which causes thickening of the diaphysis; this is most marked at the +ossifying junction and tapers off along the shaft. The infection not +only spreads along the medulla, but it invades the spongy bone +surrounding this, and then the cortical bone, and is only prevented from +reaching the soft parts by the new bone formed by the periosteum. The +bone is replaced by granulation tissue, and disappears, or part of it +may become sclerosed and in time form a sequestrum. In the macerated +specimen, the sequestrum appears small in proportion to the large cavity +in which it lies. All these changes are revealed in a good skiagram, +which not only confirms the diagnosis, but, in many instances, +demonstrates the extent of the disease, the presence or absence of a +sequestrum, and the amount of new bone on the surface. Finally the +periosteum gives way, and an abscess forms in the soft parts; and if +left to itself ruptures externally, leaving a sinus. The most +satisfactory _treatment_ is to resect sub-periosteally the diseased +portion of the diaphysis. + +_In cancellous bones, such as those of the tarsus_, there is a similar +caseous infiltration in the marrow, and this may be attended with the +formation of a sequestrum either in the interior of the bone or +involving its outer shell, as shown in Fig. 127. The situation and +extent of the disease are shown in X-ray photographs. After the +tuberculous granulation tissue erupts through the cortex of the bone, it +gives rise to a cold abscess or infects adjacent joints or tendon +sheaths. + +[Illustration: FIG. 127.--Advanced Tuberculous Disease in region of +Ankle. The ankle-joint is ankylosed, and there is a large sequestrum in +the calcaneus. + +(Specimen in Anatomical Museum, University of Edinburgh.)] + +If an exact diagnosis is made at an early stage of the disease--and this +is often possible with the aid of X-rays--the affected bone is excised +sub-periosteally or its interior is cleared out with the sharp spoon and +gouge, the latter procedure being preferred in the case of the +_calcaneus_ to conserve the stability of the heel. When several bones +and joints are simultaneously affected, and there are sinuses with +mixed infection, amputation is usually indicated, especially in adults. + +#Tuberculous dactylitis# is the name applied to a diffuse form of the +disease as it affects the phalanges, metacarpal or metatarsal bones. The +lesion presents, on a small scale, all the anatomical changes that have +been described as occurring in the medulla of the tibia or ulna, and +they are easily followed in skiagrams. A periosteal type of dactylitis +is also met with. + +The _clinical features_ are those of a spindle-shaped swelling of a +finger or toe, indolent, painless, and interfering but little with the +function of the digit. Recovery may eventually occur without +suppuration, but it is common to have the formation of a cold abscess, +which bursts and forms one or more sinuses. It may be difficult to +differentiate tuberculous dactylitis from the enlargement of the +phalanges in inherited syphilis (syphilitic dactylitis), especially when +the tuberculous lesion occurs in a child who is the subject of inherited +syphilis. + +[Illustration: FIG. 128.--Tuberculous Dactylitis.] + +In the syphilitic lesion, skiagrams usually show a more abundant +formation of new bone, but in many cases the doubt is only cleared up by +observing the results of the tuberculin test or the effects of +anti-syphilitic treatment. + +Sarcoma of a phalanx or metacarpal bone may closely resemble a +dactylitis both clinically and in skiagrams, but it is rare. + +_Treatment._--Recovery under conservative measures is not uncommon, and +the functional results are usually better than those following upon +operative treatment, although in either case the affected finger is +liable to be dwarfed (Fig. 129). The finger should be immobilised in a +splint, and a Bier's bandage applied to the upper arm. Operative +interference is indicated if a cold abscess develops, if there is a +persistent sinus, or if a sequestrum has formed, a point upon which +information is obtained by examination with the X-rays. When a toe is +affected, amputation is the best treatment, but in the case of a finger +it is rarely called for. In the case of a metacarpal or metatarsal bone, +sub-periosteal resection is the procedure of choice, saving the +articular ends if possible. + +[Illustration: FIG. 129.--Shortening of Middle Finger of Adult, the +result of Tuberculous Dactylitis in childhood.] + + +SYPHILITIC DISEASE + +Syphilitic affections of bone may be met with at any period of the +disease, but the graver forms occur in the tertiary stage of acquired +and inherited syphilis. The virus is carried by the blood-stream to all +parts of the skeleton, but the local development of the disease appears +to be influenced by a predisposition on the part of individual bones. + +Syphilitic diseases of bone are much less common in practice than those +due to pyogenic and tuberculous infectious, and they show a marked +predilection for the tibia, sternum, and skull. They differ from +tuberculous affections in the frequency with which they attack the +shafts of bones rather than the articular ends, and in the comparative +rarity of joint complications. + +_Evanescent periostitis_ is met with in acquired syphilis during the +period of the early skin eruptions. The patient complains, especially at +night, of pains over the frontal bone, ribs, sternum, tibiae, or ulnae. +Localised tenderness is elicited on pressure, and there is slight +swelling, which, however, rarely amounts to what may be described as a +_periosteal node_. + +In the later stages of acquired syphilis, _gummatous periostitis and +osteomyelitis_ occur, and are characterised by the formation in the +periosteum and marrow of circumscribed gummata or of a diffuse gummatous +infiltration. The framework of the bone is rarefied in the area +immediately involved, and sclerosed in the parts beyond. If the +gummatous tissue degenerates and breaks down, and especially if the +overlying skin is perforated and septic infection is superadded, the +bone disintegrates and exhibits the condition known as _syphilitic +caries_; sometimes a portion of bone has its blood supply so far +interfered with that it dies--_syphilitic necrosis_. Syphilitic +sequestra are heavier and denser than normal bone, because sclerosis +usually precedes death of the bone. The bones especially affected by +gummatous disease are: the skull, the septum of the nose, the nasal +bones, palate, sternum, femur, tibia, and the bones of the forearm. + +_In the bones of the skull_, gummata may form in the peri-cranium, +diploe, or dura mater. An isolated gumma forms a firm elastic swelling, +shading off into the surroundings. In the macerated bone there is a +depression or an actual perforation of the calvaria; multiple gummata +tend to fuse with one another at their margins, giving the appearance of +a combination of circles: these sometimes surround an area of bone and +cut it off from its blood supply (Fig. 130). If the overlying skin is +destroyed and septic infection superadded, such an isolated area of bone +is apt to die and furnish a sequestrum; the separation of the dead bone +is extremely slow, partly from the want of vascularity in the sclerosed +bone round about, and partly from the density of the sequestrum. In +exceptional cases the necrosis involves the entire vertical plate of the +frontal bone. Pus is formed between the bone and the dura (suppurative +pachymeningitis), and this may be followed by cerebral abscess or by +pyaemia. Gummatous disease in the wall of the orbit may cause +displacement of the eye and paralysis of the ocular muscles. + +[Illustration: FIG. 130.--Syphilitic Disease of Skull, showing a +sequestrum in process of separation.] + +On the inner surface of the skull, the formation of gummatous tissue may +cause pressure on the brain and give rise to intense pain in the head, +Jacksonian epilepsy, or paralysis, the symptoms varying with the seat +and extent of the disease. The cranial nerves may be pressed upon at the +base, especially at their points of exit, and this gives rise to +symptoms of irritation or paralysis in the area of distribution of the +nerves affected. + +_In the septum of the nose, the nasal bones, and the hard palate_, +gummatous disease causes ulceration, which, beginning in the mucous +membrane, spreads to the bones, and being complicated with septic +infection leads to caries and necrosis. In the nose, the disease is +attended with stinking discharge (ozoena), the extrusion of portions of +dead bone, and subsequently with deformity characterised by loss of the +bridge of the nose; in the palate, it is common to have a perforation, +so that the air escapes through the nose in speaking, giving to the +voice a characteristic nasal tone. + +_Syphilitic disease of the tibia_ may be taken as the type of the +affection as it occurs _in the long bones_. Gummatous disease in the +periosteum may be localised and result in the formation of a +well-defined node, or the whole shaft may become the seat of an +irregular nodular enlargement (Fig. 132). If the bone is macerated, it +is found to be heavier and bulkier than normal; there is diffuse +sclerosis with obliteration of the medullary canal, and the surface is +uneven from heaping up of new bone--hyperostosis (Fig. 131). If a +periosteal gumma breaks down and invades the skin, a syphilitic ulcer is +formed with carious bone at the bottom. A central gumma may eat away the +surrounding bone to such an extent that the shaft undergoes pathological +fracture. In the rare cases in which it attacks the articular end of a +long bone, gummatous disease may implicate the adjacent joint and give +rise to syphilitic arthritis. + +[Illustration: FIG. 131.--Syphilitic Hyperostosis and Sclerosis of +Tibia, on section and on surface view.] + +_Clinical Features._--There is severe boring pain--as if a gimlet were +being driven into the bone. It is worst at night, preventing sleep, and +has been ascribed to compression of the nerves in the narrowed Haversian +canals. + +The _periosteal gumma_ appears as a smooth, circumscribed swelling which +is soft and elastic in the centre and firm at the margins, and shades +off into the surrounding bone. The gumma may be completely absorbed or +it may give place to a hard node. In some cases the gumma softens in the +centre, the skin becomes adherent, thin, and red, and finally gives way. +The opening in the skin persists as a sinus, or develops into a typical +ulcer with irregular, crescentic margins; in either case a probe reveals +the presence of carious bone or of a sequestrum. The health may be +impaired as a result of mixed infection, and the absorption of toxins +and waxy degeneration in the viscera may ultimately be induced. + +A _central gumma_ in a long bone may not reveal its presence until it +erupts through the shell and reaches the periosteal surface or invades +an adjacent joint. Sometimes the first manifestation is a fracture of +the bone produced by slight violence. + +In radiograms the appearance of syphilitic bones is usually +characteristic. When there is hyperostosis and sclerosis, the shaft +appears denser and broader than normal, and the contour is uneven or +wavy. When there is a central gumma, the shadow is interrupted by a +rounded clear area, like that of a chondroma or myeloma, but there is +sclerosis round about. + +_Diagnosis._--The conditions most liable to be mistaken for syphilitic +disease of bone are chronic staphylococcal osteomyelitis, tuberculosis, +and sarcoma; and the diagnosis is to be made by the history and progress +of the disease, the result of examination with the X-rays, and the +results of specific tests and treatment. + +_Treatment._--The general health is to be improved by open air, by +nourishing food, and by the administration of cod-liver oil, iron, and +arsenic. Anti-syphilitic remedies should be given, and if they are +administered before there is any destruction of tissue, the benefit +derived from them is usually marked. + +Radiograms show the rapid absorption of the new bone both on the surface +and in the marrow, and are of value in establishing the therapeutic +diagnosis. + +In certain cases, and particularly when there are destructive changes in +the bone complicated with pyogenic infection, specific remedies have +little effect. In cases of persistent or relapsing gummatous disease +with ulceration of skin, it is often necessary to remove the diseased +soft parts with the sharp spoon and scissors, and to gouge or chisel +away the unhealthy bone, on the same lines as in tuberculous disease. +When hyperostosis and sclerosis of the bone is attended with severe pain +which does not yield to blistering, the periosteum may be incised and +the sclerosed bone perforated with a drill or trephine. + +#Lesions of Bone in Inherited Syphilis.#--_Craniotabes_, in which the +flat bones of the skull undergo absorption in patches, was formerly +regarded as syphilitic, but it is now known to result from prolonged +malnutrition from any cause. _Bossing of the skull_ resulting in the +formation of Parrot's nodes is also being withdrawn from the category of +syphilitic affections. The lesions in infancy--epiphysitis, bossing of +the skull, and craniotabes--have been referred to in the chapter on +inherited syphilis. + +_Epiphysitis or Syphilitic Perichondritis._--The first of these terms is +misleading, because the lesion involves the ossifying junction and the +shaft of the bone, and the epiphysis only indirectly. The young bone is +replaced by granulation tissue, so that large clear areas are seen with +the X-rays. The symptoms are referred to the joint, because it is there +that the muscles are inserted and drag on the perichondrium when +movement occurs; swelling is most marked in the vicinity of the joint, +and it may be added to by effusion into the synovial cavity. The baby, +usually under six months, is noticed to be feverish and fretful and to +cry when touched. The mother discovers that the pain is caused by moving +a particular limb, usually the arm, as the humerus, radius, and ulna are +the bones most commonly affected; the limb, moreover, hangs useless at +the side as if paralysed, and the condition was formerly described as +_syphilitic pseudo-paralysis_. + +The lesions met with later correspond to those of the tertiary period of +the acquired disease, but as they affect bones which are still actively +growing, the effects are more striking. Gummatous disease may come and +go over periods of many years, with the result that the external +appearance and architectural arrangement of a long bone come to be +profoundly altered. In the tibia, for example, the shaft is bowed +forward in a gentle curve, which is compared to the curve of a +sabre--"sabre-blade" deformity (Fig. 132). The diffuse thickening all +round the bone obscures the sharp margins so that the bone becomes +circular in section and the anterior and mesial edges are blunted, and +the comparison to a cucumber is deserved. In some cases the tibia is +actually increased in length as well as in girth. + +[Illustration: FIG. 132.--Sabre-blade Deformity of Left Tibia in +Inherited Syphilis. + +(From a photograph lent by Sir George T. Beatson.)] + +The contrast between the grossly enlarged and misshapen tibia and the +normal or even attenuated fibula is a striking one. + +_Treatment_ is carried out on lines similar to those recommended in the +acquired disease. When curving of the tibia causes disability in +walking, the bone may be straightened by a cuneiform resection. + +_Syphilitic dactylitis_ is met with chiefly in children. It may affect +any of the fingers or toes, but is commonest in the first phalanx of the +index-finger or of the thumb. Several fingers may be attacked at the +same time or in succession. The lesion consists in a gummatous +infiltration of the soft parts surrounding the phalanx, or a gummatous +osteomyelitis, but there is practically no tendency to break down and +discharge, or to the formation of a sequestrum as is so common in +tuberculous dactylitis. + +The finger becomes the seat of a swelling, which is more evident on the +dorsal aspect, and, according to the distribution and extent of the +disease, it is acorn-shaped, fusiform, or cylindrical. It is firm and +elastic, and usually painless. The movements are impaired, especially if +the joints are involved. In its early stages the disease is amenable to +anti-syphilitic treatment, and complete recovery is the rule. + + +HYDATID DISEASE + +This rare disease results from the lodgment of the embryos of the taenia +echinoccus, which are conveyed to the marrow by the blood-stream. The +cysts are small, usually about the size of a pin-head, and they are +present in enormous numbers scattered throughout the marrow. The parts +of the skeleton most often affected are the articular ends of the long +bones, the bodies of the vertebrae, and the pelvis. + +As the cysts increase in number and in size, the framework of the bone +is gradually absorbed, and there result excavations or cavities. The +marrow and spongy bone first disappear, the compact tissue then becomes +thin, and pathological fracture may result. The bone becomes expanded, +and the cysts may escape through perforations into the surrounding +cellular tissue, and when thus freed from confinement may attain +considerable dimensions. Suppuration from superadded pyogenic infection +may be attended with extensive necrosis, and lead to disorganisation of +the adjacent joint. + +_Clinical Features._--The patient complains of deep-seated pains. In +superficial bones, such as the tibia, there is enlargement, and it may +be possible to recognise egg-shell crackling, or unequal consistence of +the bone, which is hard in some parts, and doughy and elastic in others. +The disease may pursue an indolent course during months or years until +some complication occurs, such as suppuration or fracture. With the +occurrence of suppuration the disease becomes more active, and abscesses +may form in the soft parts and in the adjacent joint. In the vertebral +column, hydatids give rise to angular deformity and paraplegia. In the +pelvis, there is usually great enlargement of the bones, and when +suppuration occurs it is apt to infect the hip-joint and to terminate +fatally. + +Examination with the X-rays shows the characteristic excavations of the +bone caused by the cysts. The disease is liable to be mistaken for +central tumour, gumma, tuberculosis, or abscess of bone. + +The _treatment_ consists in thorough eradication of the parasite by +operation. The bone is laid open and scraped or resected according to +the extent of the disease, and the raw surfaces swabbed with 1 per cent. +formalin. In advanced cases complicated with spontaneous fracture or +with suppuration, amputation affords the best chance of recovery. + +The lesions in the bones resulting from _actinomycosis_ and from +_mycetoma_, have been described with these diseases. + + +CONSTITUTIONAL DISEASES ATTENDED WITH LESIONS IN THE BONES + +These include rickets, scurvy-rickets, osteomalacia, ostitis deformans, +osteomyelitis fibrosa, fragilitas ossium, and diseases of the nervous +system. + + +RICKETS + +Rickets or rachitis is a constitutional disease associated with +disturbance of nutrition, and attended with changes in the skeleton. +The disease is most common and most severe among the children of the +poorer classes in large cities, who are improperly fed and are brought +up in unhealthy surroundings. There is evidence that the most important +factors in the causation of rickets are ill-health of the mother during +pregnancy, and the administration to the child after its birth of food +which is defective in animal fat, proteids, and salts of lime, or which +contains these in such a form that they are not readily assimilated. The +occurrence of the disease is favoured, and its features are aggravated, +by imperfect oxygenation of the blood as the result of a deficiency of +fresh air and sunlight, want of exercise, and by other conditions which +prevail in the slums of large towns. + +_Pathological Anatomy._--The most striking feature is the softness +(malacia) of the bones, due to excessive absorption of osseous tissue, +and the formation of an imperfectly calcified tissue at the sites of +ossification. The affected bones lose their rigidity, so that they are +bent under the weight of the body, by the traction of muscles, and by +other mechanical forces. + +The _periosteum_ is thick and vascular, and when detached carries with +it plates and spicules of soft porous bone. The new bone may be so +abundant that it forms a thick crust on the surface, and in the flat +bones of the skull this may be heaped up in the form of bosses or ridges +resembling those ascribed to inherited syphilis. + +In the epiphysial cartilages and at the ossifying junctions, all the +processes concerned in ossification, excepting the deposition of lime +salts, occur to an exaggerated degree. The cartilage of the epiphysial +disc proliferates actively and irregularly, so that it becomes softer, +thicker, and wider, and gives rise to a visible swelling, best seen at +the lower end of the radius and lower end of the tibia, and at the +costo-chondral junctions where the series of beaded swellings is known +as the "rickety rosary." + +The ossifying zone is increased in depth; the marrow is abnormally +vascular; and the new bone that is formed is imperfectly calcified. The +result is that the bones may never attain their normal length, and they +remain stunted throughout life as in rickety dwarfs (Fig. 133), or the +shafts may grow unequally and come to deviate from their normal axes as +in knock-knee and bow-knee. + +[Illustration: FIG. 133.--Skeleton of Rickety Dwarf, known as +"Bowed Joseph," leader of the Meal Riots in Edinburgh, who died in 1780. + +(Anatomical Museum, University of Edinburgh.)] + +These changes are well brought out in skiagrams; instead of the +well-defined narrow line which represents the epiphysial cartilage, +there is an ill-defined, blurred zone of considerable depth. + +In the shafts of the long bones, owing to the excessive absorption of +bone, the cortex becomes porous, the spongy bone is rarefied, and the +bones readily bend or break under mechanical influences. When the +disease is arrested, a process of repair sets in which often results in +the bones becoming denser and heavier than normal. In the flat bones of +the skull, the absorption may result in the entire disappearance of +areas of bone, leaving a membrane which dimples like thin cardboard +under the pressure of the finger--a condition known as _craniotabes_. + +_Changes in the Skeleton before the Child is able to walk._--The +fontanelles remain open until the end of the second year or longer, and +the frontal and parietal eminences are unduly prominent. There is +sometimes hydrocephalus, and the head is characteristically enlarged. +The jaws are altered so that while the upper jaw is contracted into the +shape of a #V#, the lower jaw is square instead of rounded in outline, +and the teeth do not oppose one another. In the _thorax_, the chief +feature may be the beading at the costo-chondral junctions, principally +of the fifth and sixth ribs or its walls may be contracted, +particularly if respiration is interfered with as a result of bronchial +catarrh or adenoids. The contraction may take the form of a vertical +groove on each side, or of a horizontal groove at the level of the upper +end of the xiphi-sternum; when the sternum and cartilages form a +projection in front, the deformity is known as "pigeon-breast." + +The _spine_ may be curved backwards--_kyphosis_--throughout its +whole extent or only in one part; or it may be curved to one +side--_scoliosis_. + +In the _limbs_, the prominent features are the deficient growth in +length of the long bones, the enlargements at the epiphysial junctions, +and the bending, and occasional greenstick fracture, of the shafts. The +degree of enlargement of the epiphysial junctions is directly +proportionate to the amount of movement to which the bone is subjected +(John Thomson). The curves at this stage depend on the attitude of the +child while sitting or being carried--for example, the arm bones become +bent in children who paddle about the floor with the aid of their arms; +and in a child who lies on its back with the lower limbs everted, the +weight of the limb may lead to curvature of the neck of the femur--coxa +vara. The clavicle or humerus may sustain greenstick fracture from the +child being lifted by the arms; the femur, by a fall. From the extreme +laxity of the ligaments, the joints can be moved beyond the normal +limits, and the child is often observed to twist its limbs into abnormal +attitudes. + +_In Children who have walked._--In these children the most important +deformities occur in the spine, pelvis, and lower extremities, and +result for the most part from yielding of the softened bones under the +weight of the body. Scoliosis is the usual type of spinal curvature, and +in extreme cases it may lead to a pronounced form of hump-back. The +pelvis may remain small (_justo-minor pelvis_), or it may be contracted +in the sagittal plane (_flat pelvis_); when the bones are unusually +soft, the acetabular portions are pushed inwards by the femora bearing +the weight of the body, and the pelvis assumes the shape of a trefoil, +as in the malacia of women. The shaft of the femur is curved forwards +and laterally; the bones of the leg laterally as in bow-leg, or +forwards, or forwards and laterally just above the ankle. The +deformities at the knee (genu valgum, genu varum, and genu recurvatum), +and at the hip (coxa vara), will be described in the volume dealing with +the Extremities. + +The majority of cases seen in surgical practice suffer from the +deformities resulting from rickets rather than from the active disease. +The examination of a large series of children at different ages shows +that the deformities become less and less frequent with each year. Those +who recover may ultimately show no trace of rickets, and this is +especially true of children who grow at the average rate; in those, +however, in whom growth is retarded, especially from the fifth to the +seventh year, the deformities are apt to be permanent. It may be noted +that the scoliosis due to rickets has little tendency towards recovery. + +_Treatment._--The treatment of the disease consists in regulating the +diet, improving the surroundings, and preventing deformity. Phosphorus +in doses of 100th grain may be given dissolved in cod-liver oil, and +preparations of iron and lime may be added with advantage. To avoid +those postures which predispose to deformities, the child should lie as +much as possible. In the well-to-do classes this is readily accomplished +by the aid of a nurse and the use of a perambulator. In hospital +out-patients the child is kept off its feet by the use of a light wooden +splint applied to the lateral aspect of each lower extremity, and +extending from the pelvis to 6 inches beyond the sole. + +When deformities are already present, the treatment depends upon whether +or not there is any prospect of the bone straightening naturally. Under +five years of age this may, as a rule, be confidently expected; the +child should be kept off its feet, and the limbs bathed and massaged. In +children of five or six and upwards, the prospect of natural +straightening is a diminishing one, and it is more satisfactory to +correct the deformity by operation. In rickety curvature of the spine, +the child should lie on a firm mattress, or, to allow of its being taken +into the open air, upon a double Thomas' splint extending from the +occiput to the heels; the muscles acting on the trunk should be braced +up by massage and appropriate exercises. + +#Late Rickets# or #Rachitis Adolescentium# is met with at any age from +nine to seventeen, and is generally believed to be due to a +recrudescence of rickets which had been present in childhood. The +disease is not attended with any disturbance of the general health; the +pathological changes are the same as in infantile rickets, but are for +the most part confined to the ossifying junctions, especially those +which are most active during adolescence, for example at the knee-joint. +The patient is easily tired, complains of pain in the bones, and, unless +care is taken, deformity is liable to ensue. There can be no doubt that +adolescent rickets plays an important part in the production of the +deformities which occur at or near puberty, especially knock-knee and +bow-knee. + +#Scurvy-Rickets# or #Infantile Scurvy#.--This disease, described by +Barlow and Cheadle, is met with in infants under two years who have been +brought up upon sterilised or condensed milk and other proprietary +foods, and is most common in the well-to-do classes. The haemorrhages, +which are so characteristic of the disease, are usually preceded for +some weeks by a cachectic condition, with listlessness and debility and +disinclination for movement. Very commonly the child ceases to move one +of his lower limbs--pseudo-paralysis--and screams if it is touched; a +swelling is found over one of the bones, usually the femur, accompanied +by exquisite tenderness; the skin is tense and shiny, and there may be +some oedema. These symptoms are due to a sub-periosteal haemorrhage, and +associated with this there may be crepitus from separation of an +epiphysis, rarely from fracture of the shaft of the bone. X-ray +photographs show enlargement of the bone, the periosteum being raised +from the shaft and new bone formed in relation to it. Haemorrhages also +occur into the skin, presenting the appearance of bruises, into the +orbit and conjunctiva, and from the mucous membranes. + +The _treatment_ consists in correcting the errors in diet. The infant +should have a wet nurse or a plentiful supply of cow's milk in its +natural state. Anti-scorbutics in the form of orange, lemon, or grape +juice, and of potatoes bruised down in milk, may be given. + +#Osteomalacia.#--The term osteomalacia includes a group of conditions, +closely allied to rickets, in which the bones of adults become soft and +yielding, so that they are unduly liable to bend or break. + +One form occurs in _pregnant and puerperal women_, affecting most +commonly the pelvis and lumbar vertebrae, but sometimes the entire +skeleton. The lime salts are absorbed, the bones lose their rigidity and +bend under the weight of the body and other mechanical influences, with +the result that gross deformities are produced, particularly in the +pelvis, the lumbar spine, and the hip-joints. + +_Neuropathic_ forms occur in certain chronic diseases of the brain and +cord; in some cases the bones lose their lime salts and bend, in others +they become brittle. + +_Osteomalacia associated with New Growths in the Skeleton._--When +_secondary cancer_ is widely distributed throughout the skeleton, it is +associated with softening of the bones, as a result of which they +readily bend or break, and after death are easily cut with a knife. In +the disease known as _multiple myeloma_, the interior of the ribs, +sternum, and bodies of the vertebrae is occupied by a reddish gelatinous +pulp, the structure of which resembles sarcoma; the bones are reduced to +a mere shell, and may break on the slightest pressure; the urine +contains albumose, a substance resembling albumen but coagulating at a +comparatively low temperature (140 o F.), and the coagulum is +re-dissolved on boiling, and it is readily precipitated by hydrochloric +acid (Bence-Jones). + +#Ostitis Deformans--Paget's Disease of Bone.#--This rare disease was +first described by Sir James Paget in 1877. In the early stages, the +marrow is transformed into a vascular connective tissue; its bone-eating +functions are exaggerated, and the framework of the bone becomes +rarefied, so that it bends under pressure as in osteomalacia. In course +of time, however, new bone is formed in great abundance; it is at first +devoid of lime salts, but later becomes calcified, so that the bones +regain their rigidity. This formation of new bone is much in excess of +the normal, the bones become large and bulky, their surfaces rough and +uneven, their texture sclerosed in parts, and the medullary canal is +frequently obliterated. These changes are well brought out in X-ray +photographs. The curving of the long bones, which is such a striking +feature of the disease, may be associated with actual lengthening, and +the changes are sometimes remarkably symmetrical (Fig. 135). The bones +forming the cranium may be enormously thickened, the sutures are +obliterated, the distinction into tables and diploe is lost, and, while +the general texture is finely porous, there may be areas as dense as +ivory (Fig. 134). + +[Illustration: FIG. 134.--Changes in the Skull resulting from Ostitis +Deformans. + +(Anatomical Museum, University of Edinburgh.)] + +_Clinical Features._--The disease is usually met with in persons over +fifty years of age. It is insidious in its onset, and, the patient's +attention may be first attracted by the occurrence of vague pains in the +back or limbs; by the enlargement and bending of such bones as the tibia +or femur; or by a gradual increase in the size of the head, +necessitating the wearing of larger hats. When the condition is fully +developed, the attitude and general appearance are eminently +characteristic. The height is diminished, and, owing to the curving of +the lower limbs and spine, the arms appear unnaturally long; the head +and upper part of the spine are bent forwards; the legs are held apart, +slightly flexed at the knees, and are rotated out as well as curved; the +whole appearance suggests that of one of the large anthropoid apes. The +muscles of the limbs may waste to such an extent as to leave the large, +curved, misshapen bones covered only by the skin (Fig. 135). In the +majority of cases the bones of the lower extremities are much earlier +and more severely affected than those of the upper extremity, but the +capacity of walking is usually maintained even in the presence of great +deformity. In a case observed by Byrom Bramwell, the patient suffered +from a succession of fractures over a period of years. + +[Illustration: FIG. 135.--Cadaver, illustrating the alterations in the +Lower Limbs resulting from Ostitis Deformans.] + +The disease may last for an indefinite period, the general health +remaining long unaffected. In a considerable number of the recorded +cases one of the bones became the seat of sarcoma. + +#Osteomyelitis Fibrosa.#--This comparatively rare disease, which was +first described by Recklinghausen, presents many interesting features. +Because of its causing deformities of the bones and an undue liability +to fracture, and being chiefly met with in adolescents, it is regarded +by some authors as a juvenile form of Paget's disease. It may be +diffused throughout the skeleton--we have seen it in the skull and in +the bones of the extremities--or it may be confined to a single bone, +usually the femur, or, what is more remarkable, the condition may affect +a portion only of the shaft of a long bone and be sharply defined from +the normal bone in contact with it. + +[Illustration: FIG. 136.--Osteomyelitis Fibrosa affecting Femora in a +man aet. 19. The curving of the bones is due to multiple fractures.] + +On longitudinal section of a long bone during the active stage of the +disease, the marrow is seen to be replaced by a vascular young +connective tissue which encroaches on the surrounding spongy bone, +reducing it to the slenderest proportions; the formation of bone from +the periosteum does not keep pace with the absorption and replacement +going on in the interior, and the cortex may be reduced to a thin shell +of imperfectly calcified bone which can be cut with a knife. The young +connective tissue which replaces the marrow is not unlike that seen in +osteomalacia; it is highly vascular and may show haemorrhages of various +date; there are abundant giant cells of the myeloma type, and +degeneration and liquefaction of tissue may result in the formation of +cysts, which, when they constitute a prominent feature, are responsible +for the name--_osteomyelitis fibrosa cystica_--sometimes applied to the +condition. + +It would appear that most of the recorded cases of _cysts of bone_ owe +their origin to this disease, while the abundance of giant cells with +occasional islands of cartilage in the wall of such cysts is responsible +for the view formerly held that they owed their origin to the +liquefaction of a solid tumour, such as a myeloma, a chondroma, or even +a sarcoma. Although the tissue elements in this disease resemble those +of a new growth arising in the marrow, they differ in their arrangement +and in their method of growth; there is no tendency to erupt through the +cortex of the bone, to invade the soft parts, or to give rise to +secondary growths. + +_Clinical Features._--The onset of the disease is insidious, and +attention is usually first directed to it by the occurrence of fracture +of the shaft of one of the long bones--usually the femur--from violence +that would be insufficient to break a healthy bone. Apart from fracture, +the great increase in the size of one of the long bones and its uneven +contour are sufficiently remarkable to suggest examination with the +X-rays, by means of which the condition is at once recognised. A +systematic examination of the other long bones will often reveal the +presence of the disease at a stage before the bone is altered +externally. + +Symmetrical bossing of the skull was present in the case shown in +Figs. 136 and 137, and there were also scattered patches of brown +pigmentation of the skin of the face, neck, and trunk, similar to those +met with in generalised neuro-fibromatosis. Apart from fracture, the +disease is recognised by the thickening and usually also by the curving +of the shafts of the long bones. It is easy to understand the curvature +of bones that have passed through a soft stage and also of those that +have been broken and badly united, but it is difficult to account for +the curvatures that have no such cause; for example, we have seen +marked curve of the radius in a forearm of which the ulna was quite +straight. The curvature probably resulted from exaggerated growth in +length. + +[Illustration: FIG. 137.--Radiogram of Upper End of Femur showing +appearances in Osteomyelitis Fibrosa.] + +The X-ray appearances vary with the stage of the malady, not estimated +in time, for the condition is chronic and may become stationary, but +according to whether it is progressive or undergoing repair. The shadow +of the bone presents a poor contrast to the soft parts, and no trace of +its original architecture; in extreme cases the shadow of the femur +resembles an unevenly filled sausage (Fig. 137); there is no cortical +layer, the interior shows no trabecular structure, and some of the many +clear areas are probably cysts. The condition extends right up to the +articular cartilage, or, in the case of adolescent bones, up to the +epiphysial cartilage. + +_Prognosis._--The condition does not appear to affect the general +health. The future is concerned with the local conditions, and, +especially in the case of the femur, with its liability to fracture; so +far as we know there is no time limit to this. + +_Treatment_ is confined to protecting the affected bone--usually the +femur--from injury. Operative treatment may be required for lameness due +to a badly united fracture. + +#Neuropathic Atrophy of Bone.#--The conditions included under this +heading occur in association with diseases of the nervous system. + +Most importance attaches to the fragility of the bones met with in +general paralysis of the insane, locomotor ataxia, and other chronic +diseases of the brain and spinal cord. The bones are liable to be +fractured by forces which would be insufficient to break a healthy bone. +In _locomotor ataxia_ the fractures affect especially the bones of the +lower extremity, and may occur before there are any definite nerve +symptoms, but they are more often met with in the ataxic stage, when the +abrupt and uncontrolled movements of the limbs may play a part in their +causation. They may be unattended with pain, and may fail to unite; when +repair does take place, it is sometimes attended with an excessive +formation of callus. Joint lesions of the nature of Charcot's disease +may occur simultaneously with the alterations in the bones. In +_syringomyelia_ pathological fracture is not so frequent as in locomotor +ataxia; it is more likely to occur in the bones of the upper extremity, +and especially in the humerus. In some cases of _epilepsy_ the bones +break when the patient falls in a fit, and there is usually an +exaggerated amount of comminution. + +In these affections the bones present no histological or chemical +alterations, and the X-ray shadow does not differ from the normal. It is +maintained, therefore, that the disposition to fracture does not depend +upon a fragility of the bone, but on the loss of the muscular sense and +of common sensation in the bones, as a result of which there is an +inability properly to throw the muscles into action and dispose the +limbs so as to place them under the most favourable conditions to meet +external violence. + +#Osteogenesis Imperfecta#, #Fragilitas Ossium#, or #Congenital +Osteopsathyrosis#.--These terms are used to describe a condition in +which an undue fragility of the bones dates from intra-uterine life. It +may occur in several members of the same family. In severe cases, +intra-uterine fractures occur, and during parturition fresh fractures +are almost sure to be produced, so that at birth there is a combination +of recent fractures and old fractures united and partly united, with +bendings and thickenings of the bones. Large areas of the cranial vault +may remain membranous. + +After birth the predisposition to fracture continues, the bones are +easily broken, the fractures are attended with little or no pain, the +crepitus is soft, and although union may take place, it may be delayed +and be attended with excess of callus. Cases have been observed in which +a child has sustained over a hundred fractures. + +The bones show a feeble shadow with the X-rays, and appear thin and +atrophied; the medullary canal is increased at the expense of the +cortex. + +In young infants in whom multiple fractures occur the prognosis as to +life is unfavourable, and no satisfactory treatment of the disease has +been formulated. If the patient survives, the tendency to fracture +gradually disappears. + +#Hypertrophic Pulmonary Osteo-Arthropathy.#--This condition, which was +described by Marie in 1890, is secondary to disease in the chest, such +as chronic phthisis, empyema, bronchiectasis, or sarcoma of the lung. + +There is symmetrical enlargement and deformity of the hands and feet; +the shafts of the bones are thickened, and the soft tissues of the +terminal segments of the digits hypertrophied. The fingers come to +resemble drum-sticks, and the thumb the clapper of a bell. The nails are +convex, and incurved at their free ends, suggesting a resemblance to the +beak of a parrot. There is also enlargement of the lower ends of the +bones of the forearm and leg, and effusion into the wrist and +ankle-joints. Skiagrams of the hands and feet show a deposit of new bone +along the shafts of the phalanges. + + +TUMOURS OF BONE + +New growths which originate in the skeleton are spoken of as _primary +tumours_; those which invade the bones, either by metastasis from other +parts of the body or by spread from adjacent tissues, as _secondary_. A +tumour of bone may grow from the cellular elements of the periosteum, +the marrow, or the epiphysial cartilage. + +Primary tumours are of the connective-tissue type, and are usually +solitary, although certain forms, such as the chondroma, may be multiple +from the outset. + +_Periosteal tumours_ are at first situated on one side of the bone, but +as they grow they tend to surround it completely. Innocent periosteal +tumours retain the outer fibrous layer as a capsule. Malignant tumours +tend to perforate the periosteal capsule and invade the soft parts. + +_Central_ or _medullary tumours_ as they increase in size replace the +surrounding bone, and simultaneously new bone is formed on the surface; +as this is in its turn absorbed, further bone is formed beneath the +periosteum, so that in time the bone is increased in girth, and is said +to be "expanded" by the growth in its interior. + +#Primary Tumours--Osteoma.#--When the tumour projects from the surface +of a bone it is called an _exostosis_. When growing from bones developed +in membrane, such as the flat bones of the skull, it is usually dense +like ivory, and the term _ivory exostosis_ is employed. When derived +from hyaline cartilage--for example, at the ends of the long bones--it +is known as a _cartilaginous exostosis_. This is invested with a cap of +cartilage from which it continues to grow until the skeleton attains +maturity. + +An exostosis forms a rounded or mushroom-shaped tumour of limited size, +which may be either sessile or pedunculated, and its surface is smooth +or nodulated (Figs. 138 and 139). A cartilaginous exostosis in the +vicinity of a joint may be invested with a synovial sac or bursa--the +so-called _exostosis bursata_. The bursa may be derived from the +synovial membrane of the adjacent joint with which its cavity sometimes +communicates, or it may be of adventitious origin; when it is the seat +of bursitis and becomes distended with fluid, it may mask the underlying +exostosis, which then requires a radiogram for its demonstration. + +[Illustration: FIG. 138.--Radiogram of Right Knee showing Multiple +Exostoses.] + +_Clinically_, the osteoma forms a hard, indolent tumour attached to a +bone. The symptoms to which it gives rise depend on its situation. In +the vicinity of a joint, it may interfere with movement; on the medial +side of the knee it may incapacitate the patient from riding. When +growing from the dorsum of the terminal phalanx of the great +toe--_subungual exostosis_--it displaces the nail, and may project +through its matrix at the point of the toe, while the soft parts over it +may be ulcerated from pressure (Fig. 107). It incapacitates the patient +from wearing a boot. When it presses on a nerve-trunk it causes pains +and cramps. In the orbit it displaces the eyeball; in the nasal fossae +and in the external auditory meatus it causes obstruction, which may be +attended with ulceration and discharge. In the skull it may project +from the outer table, forming a smooth rounded swelling, or it may +project from the inner table and press upon the brain. + +The diagnosis is to be made by the slow growth of the tumour, its +hardness, and by the shadow which it presents with the X-rays (Fig. 138). + +An osteoma which does not cause symptoms may be left alone, as it ceases +to grow when the skeleton is mature and has no tendency to change its +benign character. If causing symptoms, it is removed by dividing the +neck or base of the tumour with a chisel, care being taken to remove the +whole of the overlying cartilage. The dense varieties met with in the +bones of the skull present greater difficulties; if it is necessary to +remove them, the base or neck of the tumour is perforated in many +directions with highly tempered drills rotated by some form of engine, +and the division is completed with the chisel. + +[Illustration: FIG. 139.--Multiple Exotoses of both limbs. + +(Photograph lent by Sir George T. Beatson.)] + +#Multiple Exostoses.#--This disease, which, by custom, is still placed +in the category of tumours, is to be regarded as a disorder of growth, +dating from intra-uterine life and probably due to a disturbance in the +function of the glands of internal secretion, the thyreoid being the one +which is most likely to be at fault (Arthur Keith). The disorder of +growth is confined to those elements of the skeleton where a core of +bone formed in cartilage comes to be encased in a sheath of bone formed +beneath the periosteum. To indicate this abnormality the name +_diaphysial aclasis_ has been employed by Arthur Keith at the suggestion +of Morley Roberts. + +Bones formed entirely in cartilage are exempt, namely, the tarsal and +carpal bones, the epiphyses of the long bones, the sternum, and the +bodies of the vertebrae. Bones formed entirely in membrane, that is, +those of the face and of the cranial vault, are also exempt. The +disorder mainly affects the ossifying junctions of the long bones of the +extremities, the vertebral border of the scapula, and the cristal border +of the ilium. + +_Clinically_ the disease is attended with the gradual and painless +development during childhood or adolescence of a number of tumours or +irregular projections of bone, at the ends of the long bones, the +vertebral border of the scapula, and the cristal border of the ilium. +They exhibit a rough symmetry; they rarely attain any size; and they +usually cease growing when the skeleton attains maturity--the conversion +of cartilage into bone being then completed. While they originate from +the ossifying junctions of the long bones, they tend, as the shaft +increases in length, to project from the surface of the bone at some +distance from the ossifying junction and to "point" away from it. They +may cause symptoms by "locking" the adjacent joint or by pressing upon +nerve-trunks or blood vessels. + +In a considerable proportion of cases, the disturbance of growth is +further manifested by dwarfing of the long bones; these are not only +deficient in length but are sometimes also curved and misshapen, which +accounts for the condition being occasionally confused with the +disturbances of growth resulting from rickets. In about one-third of the +recorded cases there is a dislocation of the head of the radius on one +or on both sides, a result of unequal growth between the bones of the +forearm. + +[Illustration: FIG. 140.--Multiple Cartilaginous Exostoses in a +man aet. 27. The scapular tumour projecting above the right clavicle has +taken on active growth and pressed injuriously on the cords of the +brachial plexus.] + +In early adult life, one of the tumours, instead of undergoing +ossification, may take on active growth and exhibit the features of a +chondro-sarcoma, pressing injuriously upon adjacent structures (Fig. 140) +and giving rise later to metastases in the lungs. + +The _X-ray appearances_ of the bones affected are of a striking +character; apart from the outgrowths of bone or "tumours" there is +evident a widespread alteration in the internal architecture of the +bones, which suggests analogies with other disturbances of ossification +such as achondroplasia and osteomyelitis fibrosa. The condition is one +that runs in families, sometimes through several generations; we have +more than once seen a father and son together in the hospital +waiting-room. + +As regards _treatment_, there is no indication for surgical interference +except when one or other tumour is a source of disability as by pressing +upon a nerve-trunk or by locking a joint, in which case it is easily +removed by chiselling through its neck. + +[Illustration: FIG. 141.--Multiple Cartilaginous Exostoses in a +man aet. 27, the same as in Fig. 140.] + +_Diffuse Osteoma, Leontiasis Ossea._--This rare affection was described +by Virchow, and named leontiasis ossea because of the disfigurement to +which it gives rise. It usually commences in adolescence as a diffuse +overgrowth first of one and then of both maxillae; these bones are +enlarged in all directions and project on the face, and the nasal fossae +and the maxillary and frontal sinuses become filled up with bone, which +encroaches also on the orbital cavities. In addition to the hideous +deformity, the patient suffers from blocking of the nose, loss of smell, +and protrusion of the eyes, sometimes followed by loss of sight. The +condition is liable to spread to the zygomatic and frontal bones, the +vault of the skull, and to the mandible. The base of the skull is not +affected. The disease is of slow progress and may become arrested; life +may be prolonged for many years, or may be terminated by brain +complications or by intercurrent affections. In certain cases it is +possible to remove some of the more disfiguring of the bony masses. + +A less aggressive form, confined to the maxilla on one side, is +sometimes met with, and, in a case of this variety under our own +observation, the disfigurement, which was the only subject of complaint, +was removed, after reflecting the soft parts, by paring away the excess +of bone; this is easily done as the bone is spongy, and at an early +stage, imperfectly calcified. + +A remarkable form of _unilateral hypertrophy and diffuse osteoma of the +skull_, following the distribution of the fifth nerve, has seen +described by Jonathan Hutchinson and Alexis Thomson. + +#Chondroma.#--Cartilaginous tumours, apart from those giving rise to +multiple exostoses, grow from the long bones and from the scapula, +ilium, ribs, or jaws. They usually project from the surface of the bone, +and may attain an enormous size; sometimes they grow in the interior of +a bone, the so-called _enchondroma_. + +The hyaline cartilage composing the tumour frequently undergoes +myxomatous degeneration, resulting in the formation of a glairy, +semi-fluid jelly, and if this change takes place throughout the tumour +it comes to resemble a cyst. On the other hand, the cartilage may +undergo calcification or ossification. The most important transition of +all is that into sarcoma, the so-called _malignant chondroma_ or +_chondro-sarcoma_, which is associated with rapid increase in size, +and parts of the tumour may be carried off in the blood-stream and give +rise to secondary growths, especially in the lungs. + +Cases have been met with in which certain parts of the skeleton--only +those developed in cartilage--were so uniformly permeated with cartilage +that the condition has been described as a "chondromatosis" and is +regarded as dating from an early period of foetal life. Unlike the +condition known as multiple cartilaginous exostoses, it is a malignant +disease. + +[Illustration: FIG. 142.--Multiple Chondromas of Phalanges and +Metacarpals in a boy aet. 10 (cf. Fig. 143).] + +The chondroma is met with as a slowly growing tumour which is specially +common in the bones of the hand, often in a multiple form (Figs. 142 and +144). The surface is smooth or lobulated, and in consistence the tumour +may be dense and elastic like normal cartilage, or may present areas of +softening, or of bony hardness. The skin moves freely over it, except in +relation to the bones of the fingers, where it may become adherent and +ulcerate, simulating the appearance of a malignant tumour. Large tumours +growing from the bones of the extremities may implicate the main +vessels and nerves, either surrounding them or pressing on them. + +Portions of a chondroma, which have undergone calcification or +ossification, throw a dark shadow with the X-rays; unaltered cartilage +and myxomatous tissue appear as clear areas. + +[Illustration: FIG. 143.--Skiagram of Multiple Chondromas shown +in Fig. 142.] + +_Treatment._--It is necessary to remove the whole tumour, and in +chondromas growing from the surface of the bone, especially if they are +pedunculated, this is comparatively easy. When a bone, such as the +scapula or mandible, is involved, it is better to excise the bone, or at +least the part of it which bears the tumour. In the case of central +tumours the shell of bone is removed over an area sufficient to allow of +the enucleation of the tumour, or the affected portion of bone is +resected. Should there be evidence of malignancy, such as increased rate +of growth, a tube of radium should be inserted, and in advanced cases +with destruction of tissue, amputation may be called for. + +[Illustration: FIG. 144.--Multiple Chondromas in Hand of boy aet. 8] + +In multiple chondromas of the hand in young subjects, it was formerly +the custom to amputate the limb; an attempt should be made to avoid this +by shelling out the larger tumours individually, and persevering with +the application of the X-rays or of radium to inhibit the growth of the +smaller ones. + +Chondromas springing from the pelvic bones usually arise in the region +of the sacro-iliac joint; they project into the pelvis and press on the +bladder and rectum, and on the sciatic and obturator nerves; sometimes +also on the iliac veins, causing oedema of the legs. They are liable to +take on malignant characters, and rarely lend themselves to complete +removal by operation. + +#Fibroma# is met with chiefly as a periosteal growth in relation to the +mouth and pharynx, the _simple epulis_ of the alveolar margin and the +_naso-pharyngeal polypus_ being the most common examples. We have met +with a fibroma in the interior of the lower end of the femur of an +adult, causing expansion of the bone with decided increase in girth and +liability to pathological fracture; it is possible that this represents +the cured stage of osteomyelitis fibrosa. + +_Myxoma_, _lipoma_, and _angioma_ of bone are all rare. + +#Myeloma.#--The myeloid tumour, which is sometimes classified with the +sarcomas, contains as its chief elements large giant cells, like those +normally present in the marrow. On section these tumours present a +brownish-red or chocolate colour, and, being highly vascular, are liable +to haemorrhages, and therefore also to pigmentation, and to the formation +of blood cysts. Sometimes the arterial vessels are so dilated as to +impart to the tumour an aneurysmal pulsation and bruit. The enlargement +or "expansion" of the bone results in the cortex being represented by a +thin shell of bone, which may crackle on pressure--parchment or +egg-shell crackling. + +The myeloma is most often met with between the ages of twenty-five and +forty in the upper end of the tibia or lower end of the femur. It grows +slowly and causes little pain, and may long escape recognition unless an +examination is made with the X-rays. Although these tumours have been +known to give rise to metastases, they are, as a rule, innocent and are +to be treated as such. When located in the shaft of a long bone, +pathological fracture is liable to occur. + +_Diagnosis and X-ray Appearances of Myeloma._--The early diagnosis of +myeloma is made with the aid of the X-rays: the typical appearance is +that of a rounded or oval clear area bounded by a shell of bone of +diminishing thickness (Fig. 145). The inflammatory lesions at the ends +of the long bones--tubercle, syphilitic gumma, and Brodie's abscess, +that resemble myeloma, are all attended with the formation of new bone +in greater or lesser amount. The myeloma is also to be diagnosed from +chondroma, from sarcoma, and from osteomyelitis fibrosa cystica. + +[Illustration: FIG. 145.--Radiogram of Myeloma of Humerus. + +(Mr. J. W. Struthers' case.)] + +_Treatment._--In early cases the cortex is opened up to give free access +to the tumour tissue, which is scraped out with the spoon. Bloodgood +advises the use of Esmarch's tourniquet, and that the curetting be +followed by painting with pure carbolic acid and then rinsing with +alcohol; a rod of bone is inserted to fill the gap. In advanced cases +the segment of bone is resected and a portion of the tibia or fibula +from the other limb inserted into the gap; a tube of radium should also +be introduced. + +The coexistence of diffuse myelomatosis of the skeleton and albumosuria +(Bence-Jones) is referred to on p. 474. Myeloma occurs in the jaws, +taking origin in the marrow or from the periosteum of the alveolar +process, and is described elsewhere. + +#Sarcoma# and #endothelioma# are the commonest tumours of bone, and +present wide variations in structure and in clinical features. +Structurally, two main groups may be differentiated: (1) the soft, +rapidly growing cellular tumours, and (2) those containing fully formed +fibrous tissue, cartilage, or bone. + +(1) The _soft cellular tumours_ are composed mainly of spindle or round +cells; they grow from the marrow of the spongy ends or from the +periosteum of the long bones, the diploe of the skull, the pelvis, +vertebrae, and jaws. As they grow they may cause little alteration in the +contour of the bone, but they eat away its framework and replace it, so +that the continuity of the bone is maintained only by tumour tissue, and +pathological fracture is a frequent result. The small round-celled +sarcomas are among the most malignant tumours of bone, growing with +great rapidity, and at an early stage giving rise to secondary growths. + +(2) The second group includes the _fibro-_, _osteo-_, and +_chondro-sarcomas_, and combinations of these; in all of them fully +formed tissues or attempts at fully formed tissues predominate over the +cellular elements. They grow chiefly from the deeper layer of the +periosteum, and at first form a projection on the surface, but later +tend to surround the bone (Fig. 150), and to invade its interior, +filling up the marrow spaces with a white, bone-like substance; in the +flat bones of the skull they may traverse the diploe and erupt on the +inner table. The tumour tissue next the shaft consists of a dense, +white, homogeneous material, from which there radiate into the softer +parts of the tumour, spicules, needles, and plates, often exhibiting a +fan-like arrangement (Fig. 151). The peripheral portion consists of soft +sarcomatous tissue, which invades the overlying soft parts. The +articular cartilage long resists destruction. The ossifying sarcoma is +met with most often in the femur and tibia, less frequently in the +humerus, skull, pelvis, and jaws. In the long bones it may grow from the +shaft, while the chondro-sarcoma more often originates at the +extremities. Sometimes they are multiple, several tumours appearing +simultaneously or one after another. Secondary growths are met with +chiefly in the lungs, metastasis taking place by way of the veins. + +[Illustration: FIG. 146.--Periosteal Sarcoma of Femur in a young +subject.] + +[Illustration: FIG. 147.--Periosteal Sarcoma of Humerus, after +maceration. + +(Anatomical Museum, University of Edinburgh.)] + +_Clinical Features._--Sarcoma is usually met with before the age of +thirty, and is comparatively common in children. Males suffer oftener +than females, in the proportion of two to one. + +In _periosteal sarcoma_ the presence of a swelling is usually the first +symptom; the tumour is fusiform, firm, and regular in outline, and when +it occurs near the end of a long bone the limb frequently assumes a +characteristic "leg of mutton" shape (Fig. 146). The surface may be +uniform or bossed, the consistence varies at different parts, and the +swelling gradually tapers off along the shaft. On firm pressure, fine +crepitation may be felt from crushing of the delicate framework of new +bone. + +[Illustration: FIG. 148.--Chondro-Sarcoma of Scapula in a man aet. 63; +removal of the scapula was followed two years later by metastases and +death.] + +In _central sarcoma_ pain is the first symptom, and it is usually +constant, dull, and aching; is not obviously increased by use of the +limb, but is often worse at night. Swelling occurs late, and is due to +expansion of the bone; it is fusiform or globular, and is at first +densely hard, but in time there may be parchment-like or egg-shell +crackling from yielding of the thin shell. The swelling may pulsate, and +a bruit may be heard over it. In advanced cases it may be impossible to +differentiate between a periosteal and a central tumour, either +clinically or after the specimen has been laid open. + +Pathological fracture is more common in central tumours, and sometimes +is the first sign that calls attention to the condition. Consolidation +rarely takes place, although there is often an attempt at union by the +formation of cartilaginous callus. + +[Illustration: FIG. 149.--Central Sarcoma of Lower End of Femur, +invading the knee-joint. + +(Museum of Royal College of Surgeons, Edinburgh.)] + +[Illustration: FIG. 150.--Osseous Shell of Osteo-Sarcoma of Upper Third +of Femur, after maceration.] + +The soft parts over the tumour for a long time preserve their normal +appearance; or they become oedematous, and the subcutaneous venous +network is evident through the skin. Elevation of the temperature over +the tumour, which may amount to two degrees or more, is a point of +diagnostic significance, as it suggests an inflammatory lesion. + +The adjacent joint usually remains intact, although its movements may be +impaired by the bulk of the tumour or by effusion into the cavity. + +Enlargement of the neighbouring lymph glands does not necessarily imply +that they have become infected with sarcoma for the enlargement may +disappear after removal of the primary growth; actual infection of the +glands, however, does sometimes occur, and in them the histological +structure of the parent tumour is reproduced. + +To obtain a reasonable prospect of cure, the _diagnosis_ must be made at +an early stage. Great reliance is to be placed on information gained by +examination with the X-rays. + +[Illustration: FIG. 151.--Radiogram of Osteo-Sarcoma of Upper Third +of Femur.] + +_X-ray Appearances._--In periosteal tumours that do not ossify, there is +merely erosion of bone, and the shadow is not unlike that given by +caries; in ossifying tumours, the arrangement of the new bone on the +surface is characteristic, and when it takes the form of spicules at +right angles to the shaft, it is pathognomic. + +In soft central tumours, there is disappearance of bone shadow in the +area of the tumour, while above and below or around this, the shadow is +that of normal bone right up to the clear area. In many respects the +X-ray appearances resemble those of myeloma. In tumours in which there +is a considerable amount of imperfectly formed new bone, this gives a +shadow which barely replaces that of the original bone, in parts it may +even add to it--the resulting picture differing widely in different +cases; but it is usually possible to differentiate it from that caused +by bacterial infections of the bone and from lesions of the adjacent +joint. + +[Illustration: FIG. 152.--Radiogram of Chondro-Sarcoma of Upper End of +Humerus in a woman aet. 29.] + +Skiagraphy is not only of assistance in differentiating new growths from +other diseases of bone, but may also yield information as to the +situation and nature of the tumour, which may have important bearings on +its treatment by operation. + +When fracture of a long bone takes place in an adolescent or young adult +from comparatively slight violence, disease of the bone should be +suspected and an X-ray examination made. + +In difficult cases the final appeal is to exploratory incision and +microscopical examination of a portion of the tumour; this should be +done when the major operation has been arranged for, the surgeon waiting +until the examination is completed. + +The _prognosis_ varies widely. In general, it may be said that +periosteal tumours are less favourable than central ones, because they +are more liable to give rise to metastases. Permanent cures are +unfortunately the exception. + +_Treatment._--When one of the bones of a limb is involved, the usual +practice has been to perform amputation well above the growth, and this +may still be recommended as a routine procedure. There are reasons, +however, which may be urged against its continuance. High amputation is +unnecessary in the more benign sarcomas, and in the more malignant forms +is usually unavailing to prevent a fatal issue either from local +recurrence or from metastases in the lungs or elsewhere. Following +the lead of Mikulicz, a considerable number of permanent cures have been +obtained by resecting the portion of bone which is the seat of the +tumour, and substituting for it a corresponding portion from the tibia +or fibula of the other limb. In a cellular sarcoma of the humerus of a +boy we resected the shaft and inserted his fibula ten years ago, and he +shows no sign of recurrence. When resection is impracticable, a +subcapsular enucleation is performed, followed by the insertion of +radium. + +#Pulsating Haematoma# or #Aneurysm of Bone#.--A limited number of these +are innocent cavernous tumours dating from a congenital angioma. The +majority would appear to be the result of changes in a sarcoma, +endothelioma, or myeloma. The tumour tissue largely disappears, while +the vessels and vascular spaces undergo a remarkable development. The +tumour may come to be represented by one large blood-containing space +communicating with the arteries of the limb; the walls of the space +consist of the remains of the original tumour, plus a shell of bone of +varying thickness. The most common seats of the condition are the lower +end of the femur, the upper end of the tibia, and the bones of the +pelvis. + +The _clinical features_ are those of a pulsating tumour of slow +development, and as in true aneurysm, the pulsation and bruit disappear +on compression of the main artery. The origin of the tumour from bone +may be revealed by the presence of egg-shell crackling, and by +examination with the X-rays. + +If the condition is believed to be innocent, the treatment is the same +as for aneurysm--preferably by ligation of the main artery; if +malignant, it is the same as for sarcoma. + +#Secondary Tumours of Bone.#--These embrace two groups of new growth, +those which give rise to secondary growths in the marrow of bones and +those which spread to bone by direct continuity. + +_Metastatic Tumours._--Excepting certain cancers which give rise to +metastases by lymphatic permeation (Handley), the common metastases +arising in the bone-marrow reach their destination through the +blood-stream. + +[Illustration: FIG. 153.--Epitheliomatous Ulcer of Leg with direct +extension to Tibia. + +(Lord Lister's specimen. Anatomical Museum, University of Edinburgh.)] + +Secondary cancer is a comparatively common disease, and, as in +metastases in other tissues, the secondary growths resemble the parent +tumour. The soft forms grow rapidly, and eat away the bone, without +altering its shape or form. In slowly growing forms there may be +considerable formation of imperfectly formed bone, often deficient in +lime salts; this condition may be widely diffused throughout the +skeleton, and, as it is associated with softening and bending of the +bones, it is known as _cancerous osteomalacia_. Secondary cancer of bone +is attended with pain, or it suddenly attracts notice by the occurrence +of pathological fracture--as, for example, in the shaft of the femur or +humerus. In the vertebrae, it is attended with a painful form of +paraplegia, which may involve the lower or all four extremities. On the +other hand, the disease may show itself clinically as a tumour of bone, +which may attain a considerable size, and may be mistaken for a sarcoma, +unless the existence of the primary cancer is discovered. + +The cancers most liable to give rise to metastasis in bone are those of +the breast, liver, uterus, prostate, colon, and rectum; hyper-nephroma +of the kidney may also give rise to metastases in bone. + +_Secondary tumours derived from the thyreoid gland_ require special +mention, because they are peculiar in that neither the primary growth in +the thyreoid nor the secondary growth in the bones is necessarily +malignant. They are therefore amenable to operative treatment. + +_Secondary sarcoma_, whether derived from a primary growth in the bone +or in the soft parts, is much rarer than secondary cancer. Its removal +by operation is usually contra-indicated, but we have known of cases +terminating fatally in which the _section_ revealed only one metastasis, +the removal of which would have benefited the patient. + +In all of these conditions, examination of the bones with the X-rays +gives valuable information and often disclose unsuspected metastases. + +_Cancer of Bone resulting from Direct Extension from Soft Parts._--In +this group there are also two clinical types. The first is met with in +relation to _epithelioma of a mucous surface_--for example, the palate, +tongue, gums, antrum, frontal sinus, auditory meatus, or middle ear. +They will be described under these special regions. + +The second type is met with in relation to _epithelioma occurring in a +sinus_, the sequel of suppurative osteomyelitis, compound fracture, or +tuberculous disease. The patient has usually had a discharging sinus for +a great number of years: we have known it to last as many as fifty. The +epithelioma originates at the skin orifice of the sinus, and spreads to +the bone and into its interior, where the progress of the cancer is +resisted by dense bone, which obliterates the medullary canal. Although +its progress is slow, the infiltration of the bone is usually more +extensive than appears externally. It is recognised clinically by the +characteristic cauliflower growth at the orifice of the sinus, and by +the offensive nature of the discharge. A similar epithelioma may arise +in connection with a _chronic ulcer of the leg_. The cancer may infect +the femoral lymph glands. The operative treatment is influenced by the +extent of the disease in the soft parts overlying the bone, and consists +in wide removal of the diseased tissues and resection of the bone, or in +amputation. + +#Cysts of Bone.#--With the exception of hydatid cysts, cysts in the +interior of bone are the result of the liquefaction of solid tissue; +this may be that of chondroma, myeloma, or sarcoma, but more commonly of +the marrow in osteomyelitis fibrosa. + + + + +CHAPTER XXI + +DISEASES OF JOINTS + + +Definition of terms--Ankylosis. DISEASES: Errors of + development--Bacterial diseases: _Pyogenic_; _Gonorrhoeal_; + _Tuberculous_; _Syphilitic_; _Acute rheumatism_--Diseases + associated with certain constitutional conditions: _Gout_; _Chronic + articular rheumatism_; _Arthritis deformans_; + _Haemophilia_--Diseases associated with affections of the nervous + system: _Neuro-arthropathies_; _Charcot's disease_--Hysterical or + mimetic affections of joints--Tumours and cysts--Loose bodies. + +#Definition of Terms.#--The term _synovitis_ is applied to any reaction +which affects the synovial membrane of a joint. It is usually associated +with effusion of fluid, and this may be serous, sero-fibrinous, or +purulent. As the term synovitis merely refers to the tissue involved, it +should always be used with an adjective--such as gouty, gonorrhoeal, or +tuberculous--which indicates its pathological nature. + +The terms _hydrops_, _hydrarthrosis_, and _chronic serous synovitis_ are +synonymous, and are employed when a serous effusion into the joint is +the prominent clinical feature. Hydrops may occur apart from +disease--for example, in the knee-joint from repeated sprains, or when +there is a loose body in the joint--but is met with chiefly in the +chronic forms of synovitis which result from gonorrhoea, tuberculosis, +syphilis, arthritis deformans, or arthropathies of nerve origin. + +_Arthritis_ is the term applied when not only the synovial membrane but +the articular surfaces, and it may be also the ends of the bones, are +involved, and it is necessary to prefix a qualifying adjective which +indicates its nature. When effusion is present, it may be serous, as in +arthritis deformans, or sero-fibrinous or purulent, as in certain forms +of pyogenic and tuberculous arthritis. Wasting of the muscles, +especially the extensors, in the vicinity of the joint is a constant +accompaniment of arthritis. On account of the involvement of the +articular surfaces, arthritis is apt to be followed by ankylosis. + +The term _empyema_ is sometimes employed to indicate that the cavity of +the joint contains pus. This is observed chiefly in chronic disease of +pyogenic or tuberculous origin, and is usually attended with the +formation of abscesses outside the joint. + +_Ulceration of cartilage_ and _caries of the articular surfaces_ are +common accompaniments of the more serious and progressive forms of joint +disease, especially those of bacterial origin. The destruction of +cartilage may be secondary to disease of the synovial membrane or of the +subjacent bone. When the disease begins as a synovitis, the synovial +membrane spreads over the articular surface, fuses with the cartilage +and eats into it, causing defects or holes which are spoken of as +ulcers. When the disease begins in the bone, the marrow is converted +into granulation tissue, which eats into the cartilage and separates it +from the bone. Following on the destruction of the cartilage, the +articular surface of the bone undergoes disintegration, a condition +spoken of as _caries of the articular surface_. The occurrence of +ulceration of cartilage and of articular caries is attended with the +clinical signs of fixation of the joint from involuntary muscular +contraction, wasting of muscles, and starting pains. These _starting +pains_ are the result of sudden involuntary movements of the joint. They +occur most frequently as the patient is dropping off to sleep; the +muscles becoming relaxed, the sensitive ulcerated surfaces jar on one +another, which causes sudden reflex contraction of the muscles, and the +resulting movement being attended with severe pain, wakens the patient +with a start. Advanced articular caries is usually associated with some +abnormal attitude and with shortening of the limb. It may be possible to +feel the bony surfaces grate upon one another. When all its constituent +elements are damaged or destroyed, a joint is said to be _disorganised_. +Should recovery take place, repair is usually attended with union of the +opposing articular surfaces either by fibrous tissue or by bone. + +#Conditions of Impaired Mobility of Joints.#--There are four conditions +of impaired mobility in joints: rigidity, contracture, ankylosis, and +locking. _Rigidity_ is the fixation of a joint by involuntary +contraction of muscles, and is of value as a sign of disease in +deep-seated joints, such as the hip. It disappears under anaesthesia. + +_Contracture_ is the term applied when the fixation is due to permanent +shortening of the soft parts around a joint--muscles, tendons, +ligaments, fasciae, or skin. As the structures on the flexor aspect are +more liable to undergo such shortening, contracture is nearly always +associated with flexion. Contracture may result from disease of the +joint, or from conditions outside it--for example, disease in one of +the adjacent bones, or lesions of the nerves. + +_Ankylosis_ is the term applied when impaired mobility results from +changes involving the articular surfaces. It is frequently combined with +contracture. Three anatomical varieties of ankylosis are +recognised--(a) The _fibrous_, in which there are adhesions between +the opposing surfaces, which may be in the form of loose isolated bands +of fibrous tissue, or may bind the bones so closely together as to +obliterate the cavity of the joint. The resulting stiffness, therefore, +varies from a mere restriction of the normal range of movement, up to a +close union of the bones which prevents movement. Fibrous ankylosis may +follow upon injury, especially dislocation or fracture implicating a +joint, or it may result from any form of arthritis. (b) _Cartilaginous +ankylosis_ implies the fusion of two apposed cartilaginous surfaces. It +is often found between the patella and the trochlear surface of the +femur in tuberculous disease of the knee. The fusion of the +cartilaginous surfaces is preceded by the spreading of a vascular +connective tissue, derived from the synovial membrane, over the +articular cartilage. Clinically, it is associated with absolute +immobility, (c) _Bony ankylosis_ or _synostosis_ is an osseous union +between articulating surfaces (Figs. 154 and 155). It may follow upon +fibrous or cartilaginous ankylosis, or may result from the fusion of two +articular surfaces which have lost their cartilage and become covered +with granulations. In the majority of cases it is to be regarded as a +reparative process, presenting analogies with the union of fracture. + +[Illustration: FIG. 154.--Osseous Ankylosis of Femur and Tibia in +position of flexion.] + +The term _arthritis ossificans_ has been applied by Joseph Griffiths to +a condition in which the articular surfaces become fused without evident +cause. + +The occurrence of ankylosis in a joint before the skeleton has attained +maturity does not appear to impair the growth in length of the bones +affected; ankylosis of the temporo-maxillary joints, however, greatly +impairs the growth of the mandible. When there is arrest of growth +accompanying ankylosis, it usually depends on changes in the ossifying +junctions caused by the original disease. + +To differentiate by manipulation between muscular fixation and +ankylosis, it may be necessary to anaesthetise the patient. The nature +and extent of ankylosis may be learned by skiagraphy; in osseous +ankylosis the shadow of the two bones is a continuous one. In fibrous as +contrasted with osseous ankylosis mobility may be elicited, although +only to a limited extent; while in osseous ankylosis the joint is +rigidly fixed, and attempts to move it are painless. + +[Illustration: FIG. 155.--Osseous Ankylosis of Knee in the flexed +position following upon Tuberculous Arthritis. + +(Anatomical Museum, University of Edinburgh.)] + +The _treatment_ is influenced by the nature of the original lesion, the +variety of the ankylosis, and the attitude of the joint. When there is +restriction of movement due to fibrous adhesions, these may be elongated +or ruptured. Elongation of the adhesions may be effected by +manipulations, exercises, and the use of special forms of +apparatus--such as the application of weights to the limb. It may be +necessary to administer an anaesthetic before rupturing strong fibrous +adhesions, and this procedure must be carried out with caution, in view +of such risks as fracture of the bone--which is often rarefied--or +separation of an epiphysis. There is also the risk of fat embolism, and +of re-starting the original disease. The giving way of adhesions may be +attended with an audible crack; and the procedure is often followed by +considerable pain and effusion into the joint, which necessitate rest +for some days before exercises and manipulations can be resumed. + +_Operative treatment_ may be called for in cases in which the bones are +closely bound to one another by fibrous or by osseous tissue. + +_Arthrolysis_, which consists in opening the joint and dividing the +fibrous adhesions, is almost inevitably followed by their reunion. + +_Arthroplasty._--Murphy of Chicago devised this operation for restoring +movement to an ankylosed joint. It consists in transplanting between the +bones a flap of fat-bearing tissue, from which a bursal cavity lined +with endothelium and containing a fluid rich in mucin is ultimately +formed. + +Arthroplasty is most successful in ankylosis following upon injury; when +the ankylosis results from some infective condition such as tuberculosis +or gonorrhoea, it is liable to result in failure either because of a +fresh outbreak of the infection or because the ankylosis recurs. + +When arthroplasty is impracticable, and a movable joint is desired--for +example at the elbow--a considerable amount of bone, and it may be also +of periosteum and capsular ligament, is resected to allow of the +formation of a false joint. + +When bony ankylosis has occurred with the joint in an undesirable +attitude--for example flexion at the hip or knee--it can sometimes be +remedied by osteotomy or by a wedge-shaped resection of the bone, with +or without such additional division of the contracted soft parts as will +permit of the limb being placed in the attitude desired. + +Bony ankylosis of the joints of a finger, whether the result of injury +or disease, is difficult to remedy by any operative procedure, for while +it is possible to restore mobility, the new joint is apt to be +flail-like. + +_Locking._--A joint is said to lock when its movements are abruptly +arrested by the coming together of bony outgrowths around the joint. It +is best illustrated in arthritis deformans of the hip in which new bone +formed round the rim of the acetabulum mechanically arrests the +excursions of the head of the femur. The new bone, which limits the +movements, is readily demonstrated in skiagrams; it may be removed by +operative means. Locking of joints is more often met with as a result of +injuries, especially in fractures occurring in the region of the elbow. +In certain injuries of the semilunar menisci of the knee, also, the +joint is liable to a variety of locking, which differs, however, in many +respects from that described above. + +#Errors of Development.#--These include congenital dislocations and +other deformities of intra-uterine origin, such as abnormal laxity of +joints, absence, displacement, or defective growth of one or other of +the essential constituents of a joint. The more important of these are +described along with the surgery of the Extremities. + + +DISEASES OF JOINTS + +#Bacterial Diseases.#--In most bacterial diseases the organisms are +carried to the joint in the blood-stream, and they lodge either in the +synovial membrane or in one of the bones, whence the disease +subsequently spreads to the other structures of the joint. Organisms may +also be introduced through accidental wounds. It has been shown +experimentally that joints are among the most susceptible parts of the +body to infection, and this would appear to be due to the viscid +character of the synovial fluid, which protects organisms from +bactericidal agents in the tissues and fluids. + + +PYOGENIC DISEASES + +The commoner pyogenic diseases are the result of infection of one or +other of the joint structures with _staphylococci_ or _streptococci_, +which may be demonstrated in the exudate in the joint and in the +substance of the synovial membrane. The mode of infection is the same as +in the pyogenic diseases of bone, the metastasis occurring most +frequently from the mucous membrane of the pharynx (J. B. Murphy). The +localisation of the infection in a particular joint is determined by +injury, exposure to cold, antecedent disease of the joint, or other +factors, the nature of which is not always apparent. + +The effects on the joint vary in severity. In the milder forms, there is +engorgement and infiltration of the synovial membrane, and an effusion +into the cavity of the joint of serous fluid mixed with flakes of +fibrin--_serous synovitis_. In more severe infections the exudate +consists of pus mixed with fibrin, and, it may be, red blood +corpuscles--_purulent_ or _suppurative synovitis_; the synovial membrane +and the ligaments are softened, and the surface of the membrane presents +granulations resembling those on an ulcer; foci of suppuration may +develop in the peri-articular cellular tissue and result in abscesses. +In _acute arthritis_, all the structures of the joint are involved; the +articular cartilage is invaded by granulation tissue derived from the +synovial membrane, and from the marrow of the subjacent bone; it +presents a worm-eaten or ulcerated appearance, or it may undergo +necrosis and separate, exposing the subjacent bone and leading to +disintegration of the osseous trabeculae--_caries_. With the destruction +of the ligaments, the stability of the joint is lost, and it becomes +disorganised. + +The _clinical features_ vary with the extent of the infection. When +this is confined to the synovial and peri-synovial tissues--_acute +serous_ and _purulent synovitis_--there is the usual general reaction, +associated with pyrexia and great pain in the joint. The part is hot and +swollen, the swelling assuming the shape of the distended synovial sac, +fluctuation can usually be elicited, and the joint is held in the flexed +position. + +When the joint is infected by extension from the surrounding cellular +tissue, the joint lesion may not be recognised at an early stage because +of the swollen condition of the limb, and because there are already +symptoms of toxaemia. We have observed a case in which both the hip and +knee joints were infected from the cellular tissue. + +If the infection involves all the joint structures--_acute +arthritis_--the general and local phenomena are intensified, the +temperature rises quickly, often with a rigor, and remains high; the +patient looks ill, and is either unable to sleep or the sleep is +disturbed by starting pains. The joint is held rigid in the flexed +position, and the least attempt at movement causes severe pain; the +slightest jar--even the shaking of the bed--may cause agony. The joint +is hot, tensely distended, and there may be oedema of the peri-articular +tissues or of the limb as a whole. If the pus perforates the joint +capsule, there are signs of abscess or of diffuse suppuration in the +cellular tissue. The final disorganisation of the joint is indicated by +abnormal mobility and grating of the articular surfaces, or by +spontaneous displacement of the bones, and this may amount to +dislocation. In the acute arthritis of infants, the epiphysis concerned +may be separated and displaced. + +When the _joint is infected through an external wound_, the anatomical +features are similar to those observed when the infection has reached +the joint by the blood-stream, but the destructive changes tend to be +more severe and are more likely to result in disorganisation. + +The _terminations_ vary with the gravity of the infection and with the +stage at which treatment is instituted. In the milder forms recovery is +the rule, with more or less complete restoration of function. In more +severe forms the joint may be permanently damaged as a result of fibrous +or bony ankylosis, or from displacement or dislocation. From changes in +the peri-articular structures there may be contracture in an undesirable +position, and in young subjects the growth of the limb may be interfered +with. The persistence of sinuses is usually due to disease in one or +other of the adjacent bones. In the most severe forms, and especially +when several joints are involved, death may result from toxaemia. + +The _treatment_ is carried out on the same principles as in other +pyogenic infections. The limb is immobilised in such an attitude that +should stiffness occur there will be the least interference with +function. Extension by weight and pulley is the most valuable means of +allaying muscular spasm and relieving intra-articular tension and of +counteracting the tendency to flexion; as much as 15 or 20 pounds may be +required to relieve the pain. + +The induction of hyperaemia is sometimes remarkably efficacious in +relieving pain and in arresting the progress of the infection. If the +fluid in the joint is in sufficient quantity to cause tension, if it +persists, or if there is reason to suspect that it is purulent, it +should be withdrawn without delay; an exploring syringe usually +suffices, the skin being punctured with a tenotomy knife, and, as +practised by Murphy, 5 to 15 c.c. of a 2 per cent. solution of formalin +in glycerin are injected and the wound is closed. In virulent infections +the injection may be repeated in twenty-four hours. Drainage by tube or +otherwise is to be condemned (Murphy). A vaccine may be prepared from +the fluid in the joint and injected into the subcutaneous cellular +tissue. + +Suppuration in the peri-articular soft parts or in one of the adjacent +bones must be looked for and dealt with. + +When convalescence is established, attention is directed to the +restoration of the functions of the limb, and to the prevention of +stiffness and deformity by movements and massage, and the use of hot-air +and other baths. + +At a later stage, and especially in neglected cases, operative and other +measures may be required for deformity or ankylosis. + + +#Metastatic Forms of Pyogenic Infection# + +In #pyaemia#, one or more joints may fill with pus without marked +symptoms or signs, and if the pus is aspirated without delay the joint +often recovers without impairment of function. + +In #typhoid fever#, joint lesions result from infection with the typhoid +bacillus alone or along with pyogenic organisms, and run their course +with or without suppuration; there is again a remarkable absence of +symptoms, and attention may only be called to the condition by the +occurrence of dislocation. + +Joint lesions are comparatively common in #scarlet fever#, and were +formerly described as scarlatinal rheumatism. The most frequent clinical +type is that of a serous synovitis, occurring within a week or ten days +from the onset of the fever. Its favourite seat is in the hand and +wrist, the sheaths of the extensor tendons as well as the synovial +membrane of the joints being involved. It does not tend to migrate to +other joints, and rarely lasts longer than a few days. It is probably +due to the specific virus of scarlet fever. + +At a later stage, especially in children and in cases in which the +throat lesion is severe, an arthritis is sometimes observed that is +believed to be a metastasis from the throat; it may be acute and +suppurative, affect several joints, and exhibit a septicaemic or pyaemic +character. + +The joints of the lower extremity are especially apt to suffer; the +child is seriously ill, is delirious at night, develops bed-sores over +the sacrum and, it may happen that, not being expected to recover, the +legs are allowed to assume contracture deformities with ankylosis or +dislocation at the hip and flexion ankylosis at the knees; should the +child survive, the degree of crippling may be pitiable in the extreme; +prolonged orthopaedic treatment and a series of operations--arthroplasty, +osteotomies, and resections--may be required to restore even a limited +capacity of locomotion. + +#Pneumococcal affections of joints#, the result of infection with the +pneumococcus of Fraenkel, are being met with in increasing numbers. The +local lesion varies from a _synovitis_ with infiltration of the synovial +membrane and effusion of serum or pus, to an _acute arthritis_ with +erosion of cartilage, caries of the articular surfaces, and +disorganisation of the joint. The knee is most frequently affected, but +several joints may suffer at the same time. In most cases the joint +affection makes its appearance a few days after the commencement of a +pneumonia, but in a number of instances, especially among children, the +lung is not specially involved, and the condition is an indication of a +generalised pneumococcal infection, which may manifest itself by +endocarditis, empyema, meningitis, or peritonitis, and frequently has a +fatal termination. The differential diagnosis from other forms of +pyogenic infection is established by bacteriological examination of the +fluid withdrawn from the joint. The treatment is carried out on the same +lines as in other pyogenic infections, considerable reliance being +placed on the use of autogenous vaccines. + +In #measles#, #diphtheria#, #smallpox#, #influenza#, and #dysentery#, +similar joint lesions may occur. + +The joint lesions which accompany #acute rheumatism# or "rheumatic +fever" are believed to be due to a diplococcus. In the course of a +general illness in which there is moderate pyrexia and profuse sweating, +some of the larger joints, and not infrequently the smaller ones also, +become swollen and extremely sensitive, so that the sufferer lies in bed +helpless, dreading the slightest movement. From day to day fresh joints +are attacked, while those first affected subside, often with great +rapidity. Affections of the heart-valves and of the pericardium are +commonly present. On recovery from the acute illness, it may be found +that the joints have entirely recovered, but in a small proportion of +cases certain of them remain stiff and pass into the crippled condition +described under chronic rheumatism. There is no call for operative +interference. + +#Gonococcal Affections of Joints.#--These include all forms of joint +lesion occurring in association with gonorrhoeal urethritis, +vulvo-vaginitis, or gonorrhoeal ophthalmia. They may develop at any stage +of the urethritis, but are most frequently met with from the eighteenth +to the twenty-second day after the primary infection, when the organisms +have reached the posterior urethra; they have been observed, however, +after the discharge has ceased. There is no connection between the +severity of the gonorrhoea and the incidence of joint disease. In women, +the gonorrhoeal nature of the discharge must be established by +bacteriological examination. + +As a complication of ophthalmia, the joint lesions are met with in +infants, and occur more commonly towards the end of the second or during +the third week. + +The gonococcus is carried to the joint in the blood-stream and is first +deposited in the synovial membrane, in the tissues of which it can +usually be found; it may be impossible to find it in the exudate within +the joint. The joint lesions may be the only evidence of metastasis, or +they may be part of a general infection involving the endocardium, +pleura, and tendon sheaths. + +The joints most frequently affected are the knee, elbow, ankle, wrist, +and fingers. Usually two or more joints are affected. + +Several clinical types are differentiated. (1) A _dry poly-arthritis_ +met with in the joints and tendon sheaths of the wrist and hand, +formerly described as gonorrhoeal rheumatism, which in some cases is +trifling and evanescent, and in others is persistent and progressive, +and results in stiffness of the affected joints and permanent crippling +of the hand and fingers. + +(2) The commonest type is a _chronic synovitis_ or _hydrops_, in which +the joint--very often the knee--becomes filled with a serous or +sero-fibrinous exudate. There are no reactive changes in the synovial +membrane, cellular tissue, or skin, nor is there any fever or +disturbance of health. The movements are free except in so far as they +are restricted by the amount of fluid in the joint. It usually subsides +in two or three weeks under rest, but tends to relapse. + +(3) An _acute synovitis_ with peri-articular phlegmon is most often met +with in the elbow, but it occurs also in the knee and ankle. There is a +sudden onset of severe pain and swelling in and around the joint, with +considerable fever and disturbance of health. The slightest movement +causes pain, and the part is sensitive to touch. The skin is hot and +tense, and in the case of the elbow may be red and fiery as in +erysipelas. + +The deposit of fibrin on the synovial membrane and on the articular +surfaces may lead to the formation of adhesions, sometimes in the form +of isolated bands, sometimes in the form of a close fibrous union +between the bones. + +(4) A _suppurative arthritis_, like that caused by ordinary pus +microbes, may be the result of gonococcal infection alone or of a mixed +infection. Usually only one joint is affected, but the condition may be +multiple. The articular cartilages are destroyed, the ends of the bones +are covered with granulations, extra-articular abscesses form, and +complete osseous ankylosis results. + +The _diagnosis_ is often missed because the possibility of gonorrhoea is +not suspected. + +The denial of the disease by the patient is not always to be relied +upon, especially in the case of women, as they may be ignorant of its +presence. The chief points in the differential diagnosis from acute +articular rheumatism are, that the gonorrhoeal affection is more often +confined to one or two joints, has little tendency to wander from joint +to joint, and its progress is not appreciably influenced by salicylates, +although these drugs may relieve pain. The conclusive point is the +recognition of a gonorrhoeal discharge or of threads in the urine. + +The disease may persist or may relapse, and the patient may be laid up +for weeks or months, and may finally be crippled in one or in several +joints. + +The _treatment_--besides that of the urethral disease or of the +ophthalmia--consists in rest until all pain and sensitiveness have +disappeared. The pain is relieved by salicylates, but most benefit +follows weight extension, the induction of hyperaemia by the rubber +bandage and hot-air baths; if the joint is greatly distended, the fluid +may be withdrawn by a needle and syringe. Detoxicated vaccines should be +given from the first, and in afebrile cases the injection of a foreign +protein, such as anti-typhoid vaccine, is beneficial (Harrison). + +Murphy has found benefit from the introduction into the joint, in the +early stages, of from 5 to 15 c.c. of a 2 per cent. solution of formalin +in glycerin. This may be repeated within a week, the patient being kept +in bed with light weight extension. In the chronic hydrops the fluid is +withdrawn, and about an ounce of a 1 per cent. solution of protargol +injected; the patient should be warned of the marked reaction which +follows. + +After all symptoms have settled down, but not till then, for fear of +exciting relapse or metastasis, the joint is massaged and exercised. +Stiffness from adhesions is most intractable, and may, in spite of every +attention, terminate in ankylosis even in cases where there has been no +suppuration. Forcible breaking down of adhesions under anaesthesia is +not recommended, as it is followed by great suffering and the adhesions +re-form. Operation for ankylosis--arthroplasty--should not be +undertaken, as the ankylosis recurs. + + +TUBERCULOUS DISEASE + +Tuberculous disease of joints results from bacillary infection through +the arteries. The disease may commence in the synovial membrane or in +the marrow of one of the adjacent bones, and the relative frequency of +these two seats of infection has been the subject of considerable +difference of opinion. The traditional view of Konig is that in the knee +and most of the larger joints the disease arises in the bone and in the +synovial membrane in about equal proportion, and that in the hip the +number of cases beginning in the bones is about five times greater than +that originating in the membrane. This estimate, so far as the actual +frequency of bone lesions is concerned, has been generally accepted, but +recent observers, notably John Fraser, do not accept the presence of +bone lesions as necessarily proving that the disease commenced in the +bones; he maintains, and we think with good grounds, that in many cases +the disease having commenced in the synovial membrane, slowly spreads to +the bone by way of the blood vessels and lymphatics, and gives rise to +lesions in the marrow. + +#Morbid Anatomy.#--Tuberculous disease in the articular end of a long +bone may give rise to _reactive changes_ in the adjacent joint, +characterised by effusion and by the extension of the synovial membrane +over the articular surfaces. This may result in the formation of +adhesions which obliterate the cavity of the joint or divide it into +compartments. These lesions are comparatively common, and are not +necessarily due to actual tuberculous infection of the joint. + +The _infection of the joint_ by tubercle originating in the adjacent +bone may take place at the periphery, the osseous focus reaching the +surface of the bone at the site of reflection of the synovial membrane, +and the infection which begins at this point then spreads to the rest of +the membrane. Or it may take place in the central area, by the +projection of tuberculous granulation tissue into the joint following +upon erosion of the cartilage (Fig. 156). + +[Illustration: FIG. 156.--Section of Upper End of Fibula, showing +caseating focus in marrow, erupting on articular surface and infecting +joint.] + +_Changes in the Synovial Membrane._--In the majority of cases there is a +_diffuse thickening of the synovial membrane_, due to the formation of +granulation tissue, or of young connective tissue, in its substance. +This new tissue is arranged in two layers--the outer composed of fully +formed connective or fibrous tissue, the inner of embryonic tissue, +usually permeated with miliary tubercles. On opening the joint, these +tubercles may be seen on the surface of the membrane, or the surface may +be covered with a layer of fibrinous or caseating tissue. Where there is +greater resistance on the part of the tissues, there is active formation +of young connective tissue which circumscribes or encapsulates the +tubercles, so that they remain embedded in the substance of the +membrane, and are only seen on cutting into it. + +The thickened synovial membrane is projected into the cavity of the +joint, filling up its pouches and recesses, and spreading over the +surface of the articular cartilage "like ivy growing on a wall." +Wherever the synovial tissue covers the cartilage it becomes adherent to +and fused with it. The morbid process may be arrested at this stage, and +fibrous adhesions form between the opposing articular surfaces, or it +may progress, in which case further changes occur, resulting in +destruction of the articular cartilage and exposure of the subjacent +bone. + +In rare instances the synovial membrane presents nodular masses or +lumps, resembling the tuberculous tumours met with in the brain; they +project into the cavity of the joint, are often pedunculated, and may +give rise to the symptoms of loose body. The fringes of synovial +membrane may also undergo a remarkable development, like that observed +in arthritis deformans, and described as arborescent lipoma. Both these +types are almost exclusively met with in the knee. + +_The Contents of Tuberculous Joints._--In a large proportion of cases of +synovial tuberculosis the joint is entirely filled up by the diffuse +thickening of the synovial membrane. In a small number there is an +abundant serous exudate, and with this there may be a considerable +formation of fibrin, covering the surface of the membrane and floating +in the fluid as flakes or masses; under the influence of movement it may +assume the shape of melon-seed bodies. More rarely the joint contains +pus, and the surface of the synovial membrane resembles the wall of a +cold abscess. + +_Ulceration and Necrosis of Cartilage._--The synovial tissue covering +the cartilage causes pitting and perforation of the cartilage and makes +its way through it, and often spreads widely between it and the +subjacent bone; the cartilage may be detached in portions of +considerable size. It may be similarly ulcerated or detached as a result +of disease in the bone. + +_Caries of Articular Surfaces._--Tuberculous infiltration of the marrow +in the surface cancelli breaks up the spongy framework of the bone into +minute irregular fragments, so that it disintegrates or crumbles +away--caries. When there is an absence of caseation and suppuration, the +condition is called _caries sicca_. + +The pressure of the articular surfaces against one another favours the +progress of ulceration of cartilage and of articular caries. These +processes are usually more advanced in the areas most exposed to +pressure--for example, in the hip-joint, on the superior aspect of the +head of the femur, and on the posterior and upper segment of the +acetabulum. + +The occurrence of _pathological dislocation_ is due to softening and +stretching of the ligaments which normally retain the bones in position, +and to some factor causing displacement, which may be the accumulation +of fluid or of granulations in the joint, the involuntary contraction of +muscles, or some movement or twist of the limb. The occurrence of +dislocation is also favoured by destructive changes in the bones. + +_Peri-articular tubercle and abscess_ may result from the spread of +disease from the bone or joint into the surrounding tissues, either +directly or by way of the lymphatics. A peri-articular abscess may +spread in several directions, sometimes invading tendon sheaths or +bursae, and finally reaching the skin surface by tortuous sinuses. + +Reactive changes in the vicinity of tuberculous joints are of common +occurrence, and play a considerable part in the production of what is +clinically known as _white swelling_. New connective tissue forms in the +peri-articular fat and between muscles and tendons. It may be tough and +fibrous, or soft, vascular, and oedematous, and the peri-articular fat +becomes swollen and gelatinous, constituting a layer of considerable +thickness. The fat disappears and is replaced by a mucoid effusion +between the fibrous bundles of connective tissue. This is what was +formerly known as _gelatinous degeneration_ of the synovial membrane. In +the case of the wrist the newly formed connective tissue may fix the +tendons in their sheaths, interfering with the movements of the fingers. +In relation to the bones also there may be reactive changes, resulting +in the formation of spicules of new bone on the periosteal surfaces and +at the attachment of the capsular and other ligaments; these are only +met with where pyogenic infection has been superadded. + +_Terminations and Sequelae._--A natural process of cure may occur at any +stage, the tuberculous tissue being replaced by scar tissue. Recovery is +apt to be attended with impairment of movement due to adhesions, +ankylosis, or contracture of the peri-articular structures. Caseous foci +in the interior of the bones may become encapsulated, and a cure be thus +effected, or they may be the cause of a relapse of the disease at a +later date. Interference with growth is comparatively common, and may +involve only the epiphysial junctions in the immediate vicinity of the +joint affected, or those of all the bones of the limb. This is well seen +in adults who have suffered from severe disease of the hip in +childhood--the entire limb, including the foot, being shorter and +smaller than the corresponding parts of the opposite side. + +Atrophic conditions are also met with, the bones undergoing fatty +atrophy, so that in extreme cases they may be cut with a knife or be +easily fractured. These atrophic conditions are most marked in bedridden +patients, and are largely due to disuse of the limb; they are recovered +from if it is able to resume its functions. + +#Clinical Features.#--These vary with the different anatomical forms of +the disease, and with the joint affected. + +Sometimes the disease is ushered in by a febrile attack attended with +pains in several joints--described by John Duncan as _tuberculous +arthritic fever_. This is liable to be mistaken for rheumatic fever, +from which, however, it differs in that there is no real migration from +joint to joint; there is an absence of sweating and of cardiac +complications; and no benefit follows the administration of salicylates. + +In exceptional cases, tuberculous joint disease follows an acute course +resembling that of the pyogenic arthritis of infants. This has been +observed in children, especially in the knee, the lesion being in the +synovial membrane, and attended with an accumulation of pus in the +joint. If promptly treated by incision and drainage, recovery is rapid, +and free movement of the joint, may be preserved. + +The onset and early stages of tuberculous disease, however, are more +often insidious, and are attended with so few symptoms that the disease +may have obtained a considerable hold before it attracts notice. It is +not uncommon for patients or their friends to attribute the condition to +injury, as it often first attracts attention after some slight trauma or +excessive use of the limb. The symptoms usually subside under rest, only +to relapse again with use of the limb. + +The initial local symptoms may be due to the presence of a focus in the +neighbouring bone, perhaps causing neuralgic pains in the joint, or +weakness, tiredness, stiffness, and inability to use the limb, these +symptoms improving with rest and being aggravated by exertion. + +It is rarely possible by external examination to recognise deep-seated +osseous foci in the vicinity of joints; but if they are near the surface +in a superficial bone--such as the head of the tibia--there may be local +thickening of the periosteum, oedema, pain, and tenderness on pressure +and on percussion. + +_X-ray Appearances of Tuberculous Joints._--Gross lesions such as +caseous foci in the marrow of the adjacent bone show as clear areas with +an ill-defined margin; a sclerosed focus gives a denser shadow than the +surrounding bone, and a sequestrum presents a dark shadow of irregular +contour, and a clear interval between it and the surrounding bone. + +Caries of the articular surface imparts a woolly appearance or irregular +contour in place of the well-defined outline of the articular end of the +bone. In bony ankylosis the shadow of the two bones is a continuous one, +the joint interval having been filled up. The minor changes are best +appreciated on comparison with the normal joint of the other limb. + +_Wasting of muscles_ is a constant accompaniment of tuberculous joint +disease. It is to be attributed partly to want of use, but chiefly to +reflex interference with the trophic innervation of the muscles. It is +specially well seen in the extensor and adductor muscles of the thigh in +disease of the knee, and in the deltoid in disease of the shoulder. The +muscles become soft and flaccid, they exhibit tremors on attempted +movement, and their excitability to the faradic current is diminished. +The muscular tissue may be largely replaced by fat. + +_Impairment of the normal movements_ is one of the most valuable +diagnostic signs, particularly in deeply seated joints such as the +shoulder, hip, and spine. It is due to a protective contraction of the +muscles around the joint, designed to prevent movement. This muscular +fixation disappears under anaesthesia. + +_Abnormal attitudes of the limb_ occur earlier, and are more pronounced +in cases in which pain and other irritative symptoms of articular +disease are well marked, and are best illustrated by the attitudes +assumed in disease of the hip. They are due to reflex or involuntary +contraction of the muscles acting on the joint, with the object of +placing it in the attitude of greatest ease; they also disappear under +anaesthesia. With the lapse of time they not only become exaggerated, but +may become permanent from ankylosis or from contracture of the soft +parts round the joint. + +_Startings at night_ are to be regarded as an indication that there is +progressive disease involving the articular surfaces. + +_The formation of extra-articular abscess_ may take place early, or it +may not occur till long after the disease has subsided. The abscess may +develop so insidiously that it does not attract attention until it has +attained considerable size, especially when associated with disease of +the spine, pelvis, or hip. The position of the abscess in relation to +different joints is fairly constant and is determined by the anatomical +relationships of the capsule and synovial membrane to the surrounding +tissues. The bursae and tendon sheaths in the vicinity may influence the +direction of spread of the abscess and the situation of resulting +sinuses. When the abscess is allowed to burst, or is opened and becomes +infected with pyogenic bacteria, there is not only the risk of +aggravation of the disease and persistent suppuration, but there is a +greater liability to general tuberculosis. + +The sinuses may be so tortuous that a probe cannot be passed to the +primary focus of disease, and their course and disposition can only be +demonstrated by injecting the sinuses with an emulsion of bismuth and +taking X-ray photographs. + +Tuberculous infection of the lymph glands of the limb is exceptional, +but may follow upon infection of the skin around the orifice of a sinus. + +A slight rise of temperature in the evening may be induced in quiescent +joint lesions by injury or by movement of the joint under anaesthesia, or +by the fatigue of a railway journey. When sinuses have formed and become +infected with pyogenic bacteria, there may be a diurnal variation in the +temperature of the type known as hectic fever (Fig. 11). + +_Relative Frequency of Tuberculous Disease in Different +Joints._--Hospital statistics show that joints are affected in the +following order of frequency: Spine, knee, hip, ankle and tarsus, elbow, +wrist, shoulder. The hip and spine are most often affected in childhood +and youth, the shoulder and wrist in adults; the knee, ankle, and elbow +show little age preference. + +_Clinical Variations of Tuberculous Joint Disease._--The above +description applies to tuberculous joint disease in general; it must be +modified to include special manifestations or varieties. + +When the main incidence of the infection affects the synovial membrane, +the clinical picture may assume the form of a _hydrops_, or of an +_empyema_ in which the joint is filled with pus. More common than either +of these is the well-known _white swelling_ or _tumor albus_ (Wiseman, +1676) which is the clinical manifestation of diffuse thickening of the +synovial membrane along with mucoid degeneration of the peri-synovial +cellular tissue. It is well seen in joints which are superficial--such +as the knee, ankle, elbow, and wrist. The swelling, which is the first +and most prominent clinical feature, develops gradually and painlessly, +obliterating the bony prominences by filling up the natural hollows. It +appears greater to the eye than is borne out by measurement, being +thrown into relief by the wasting of the muscles above and below the +joint. In the early stage the swelling is elastic, doughy, and +non-sensitive, and corresponds to the superficial area of the synovial +membrane involved, and there is comparatively little complaint on the +part of the patient, because the articular surfaces and ligaments are +still intact. There may be a feeling of weight in the limb, and in the +case of the knee and ankle the patient tires on walking and drags the +leg with more or less of a limp. Movements of the joint are permitted, +but are limited in range. The disability is increased by use and +exertion, but, for a time at least, it improves under rest. + +If the disease is not arrested, there follow the symptoms and signs of +involvement of the articular surfaces. + +_Influence of Tuberculous Joint Disease on the General +Health._--Experience shows that the early stages of tuberculous joint +disease are compatible with the appearance of good health. As a rule, +however, and especially if there is mixed infection, the health suffers, +the appetite is impaired, the patient is easily tired, and there may be +some loss of weight. + +#Treatment.#--In addition to the general treatment of tuberculosis, +local measures are employed. These may be described under two heads--the +conservative and the operative. + +_Conservative treatment_ is almost always to be employed in the first +instance, as by it a larger proportion of cures is obtained with a +smaller mortality and with better functional results than by operation. + +_Treatment by rest_ implies the immobilisation of the diseased limb +until pain and tenderness have disappeared. The attitude in which the +limb is immobilised should be that in which, in the event of subsequent +stiffness, it will be most serviceable to the patient. Immobilisation +may be secured by bandages, splints, extension, or other apparatus. +_Extension_ with weight and pulley is of value in securing rest, +especially in disease of the hip or knee; it eliminates muscular spasm, +relieves pain and startings at night, and prevents abnormal attitudes of +the limb. If, when the patient first comes under observation, the limb +is in a deformed attitude which does not readily yield to extension, the +deformity should be corrected under an anaesthetic. + +_The induction of hyperaemia_ is often helpful, the rubber bandage or the +hot-air chamber being employed for an hour or so morning and evening. + +_Injection of Iodoform._--This is carried out on the same lines as have +been described for tuberculous abscess. After the fluid contents of the +joint are withdrawn, the iodoform is injected; and this may require to +be repeated in a month or six weeks. + +After the injection of iodoform there is usually considerable reaction, +attended with fever (101 o F.), headache, and malaise, and considerable +pain and swelling of the joint. In some cases there is sickness, and +there may be blood pigment in the urine. The severity of these phenomena +diminishes with each subsequent injection. + +The use of Scott's dressing and of blisters and of the actual cautery +has largely gone out of fashion, but the cautery may still be employed +with benefit for the relief of pain in cases in which ulceration of +cartilage is a prominent feature. + +The application of the X-rays has proved beneficial in synovial lesions +in superficial joints such as the wrist or elbow; prolonged exposures +are made at fortnightly intervals, and on account of the cicatricial +contraction which attends upon recovery, the joint must be kept in good +position. + +Conservative treatment is only abandoned if improvement does not show +itself after a thorough trial, or if the disease relapses after apparent +cure. + +_Operative Treatment._--Other things being equal, operation is more +often indicated in adults than in children, because after the age of +twenty there is less prospect of recovery under conservative treatment, +there is more tendency for the disease to relapse and to invade the +internal organs, and there is no fear of interfering with the growth of +the bones. The state of the general health may necessitate operation as +the most rapid method of removing the disease. The social status of the +patient must also be taken into account; the bread-winner, under +existing social conditions, may be unable to give up his work for a +sufficient time to give conservative measures a fair trial. + +The _local conditions_ which decide for or against operation are +differently regarded by different surgeons, but it may be said in +general terms that operative interference is indicated in cases in which +the disease continues to progress in spite of a fair trial of +conservative measures; in cases unsuited for conservative +treatment--that is to say, where there are severe bone lesions. +Operative interference is indicated also when the functional result will +be better than that likely to be obtained by conservative measures, as +is often the case in the knee and elbow. Cold abscesses should, if +possible, be dealt with before operating on the joint. + +In many cases the extent of the operation can only be decided after +exploration. The aim is to remove all the disease with the least +impairment of function and the minimum sacrifice of healthy tissue. The +more open the method of operating the better, so that all parts of the +joint may be available for inspection. The methods of Kocher, which +permit of dislocating the joint, are specially to be recommended, as +this procedure affords the freest possible access. Diseased synovial +membrane is removed with the scissors or knife. If the cartilages are +sound, and if a movable joint is aimed at, they may be left; but if +ankylosis is desired, they must be removed. Localised disease of the +cartilage should be removed with the spoon or gouge, and the bone +beneath investigated. If the articular surface is extensively diseased, +a thin slice of bone should be removed, and if foci in the marrow are +then revealed, it is better to gouge them out than to remove further +slices of bone, as this involves sacrifice of the cortex and periosteum. + +Operative treatment of deformities resulting from tuberculous joint +disease has almost entirely replaced reduction by force; the contracted +soft parts are divided, and the bone is resected. + +_Amputation_ for tuberculous joint disease has become one of the rare +operations of surgery, and is only justified when less radical measures +have failed and the condition of the limb is affecting the general +health. Amputation is more frequently called for in persons past middle +life who are the subjects of pulmonary tuberculosis. + + +SYPHILITIC DISEASE + +Syphilitic affections of joints are comparatively rare. As in +tuberculosis, the disease may be first located in the synovial membrane, +or it may spread to the joint from one of the bones. + +In #acquired syphilis#, at an early stage and before the skin eruptions +appear, one of the large joints, such as the shoulder or knee, may be +the seat of pain--_arthralgia_--which is worse at night. In the +secondary stage, a _synovitis_ with serous effusion is not uncommon, and +may affect several joints. Syphilitic _hydrops_ is met with almost +exclusively in the knee; it is frequently bilateral, and is insidious in +its onset and progress, the patient usually being able to go about. + +In the _tertiary stage_ the joint lesions are persistent and +destructive, and result from the formation of gummata, either in the +deeper layers of the synovial membrane or in the adjacent bone or +periosteum. + +_Peri-synovial_ and _peri-bursal gummata_ are met with in relation to +the knee-joint of middle-aged adults, especially women. They are usually +multiple, develop slowly, and are rarely sensitive or painful. One or +more of the gummata may break down and give rise to tertiary ulcers. The +co-existence of indolent swellings, ulcers, and depressed scars in the +vicinity of the knee is characteristic of tertiary syphilis. + +The disease spreads throughout the capsule and synovial membrane, which +becomes diffusely thickened and infiltrated with granulation tissue +which eats into and replaces the articular cartilage. Clinically, the +condition resembles tuberculous disease of the synovial membrane, for +which it is probably frequently mistaken, but in the syphilitic +affection the swelling is nodular and uneven, and the subjective +symptoms are slight, mobility is little impaired, and yet the deformity +is considerable. + +_Syphilitic osteo-arthritis_ results from a gumma in the periosteum or +marrow of one of the adjacent bones. There is gradual enlargement of one +of the bones, the patient complains of pains, which are worst at night. +The disease may extend to the synovial membrane and be attended with +effusion into the joint, or it may erupt on the periosteal surface and +invade the skin, forming one or more sinuses. The further progress is +complicated by the occurrence of pyogenic infection leading to necrosis +of bone, in the knee-joint, for example, the patella or one of the +condyles of the femur or tibia, may furnish a sequestrum. In such cases, +anti-syphilitic treatment must be supplemented by operation for the +removal of the diseased tissues. In the knee, excision is rarely +necessary; but in the elbow it may be called for to obtain a movable +joint. + +In #inherited syphilis# the earliest joint affections are those in which +there is an effusion into the joint, especially the knee or elbow; and +in exceptional cases pyogenic infection may be superadded, and pus form +in the joint. + +In older children, a gummatous synovitis is met with of which the most +striking features are: its insidious development, its chronic course, +symmetrical distribution, freedom from pain, the free mobility of the +joint, its tendency to relapse, and its association with other +syphilitic stigmata, especially in the eyes. The knees are the joints +most frequently affected, and the condition usually yields readily to +anti-syphilitic treatment without impairment of function. + + +JOINT DISEASES ACCOMPANYING CERTAIN CONSTITUTIONAL CONDITIONS + +#Gout.#--_Arthritis Urica._--One of the manifestations of gout is that +certain joints are liable to attacks of inflammation associated with the +deposit of a chalk-like material composed of sodium biurate, chiefly in +the matrix of the articular cartilage, it may be in streaks or patches +towards the central area of the joint, or throughout the entire extent +of the cartilage, which appears as if it had been painted over with +plaster of Paris. As a result of this uratic infiltration, the cartilage +loses its vitality and crumbles away, leading to the formation of what +are known as gouty ulcers, and these may extend through the cartilage +and invade the bone. The deposit of urates in the synovial membrane is +attended with effusion into the joint and the formation of adhesions, +while in the ligaments and peri-articular structures it leads to the +formation of scar tissue. The metatarso-phalangeal joint of the great +toe, on one or on both sides, is that most frequently affected. The +disease is met with in men after middle life, and while common enough in +England and Ireland, is almost unknown in hospital practice in Scotland. + +The _clinical features_ are characteristic. There is a sudden onset of +excruciating pain, usually during the early hours of the morning, the +joint becomes swollen, red, and glistening, with engorgement of the +veins and some fever and disturbance of health and temper. In the course +of a week or ten days there is a gradual return to the normal. Such +attacks may recur only once a year or they may be more frequent; the +successive attacks tend to become less acute but last longer, and the +local phenomena persist, the joint remaining permanently swollen and +stiff. Masses of chalk form in and around the joint, and those in the +subcutaneous tissue may break through the skin, forming indolent ulcers +with exposure of the chalky masses (_tophi_). The hands may become +seriously crippled, especially when the tendon sheaths and bursae also +are affected; the crippling resembles that resulting from arthritis +deformans but it differs in not being symmetrical. + +The local _treatment_ consists in employing soothing applications and a +Bier's bandage for two or three hours twice daily while the symptoms are +acute; later, hot-air baths, massage, and exercises are indicated. It is +remarkable how completely even the most deformed joints may recover +their function. Dietetic and medicinal treatment must also be employed. + +#Chronic Rheumatism.#--This term is applied to a condition which +sometimes follows upon acute articular rheumatism in persons presenting +a family tendency to acute rheumatism or to inflammations of serous +membranes, and manifesting other evidence of the rheumatic taint, such +as chorea or rheumatic nodules. + +The changes in the joints involve almost exclusively the synovial +membrane and the ligaments; they consist in cellular infiltration and +exudation, resulting in the formation of new connective tissue which +encroaches on the cavity of the joint and gives rise to adhesions, and +by contracting causes stiffness and deformity. The articular cartilages +may subsequently be transformed into connective tissue, with consequent +fibrous ankylosis and obliteration of the joint. The bones are affected +only in so far as they undergo fatty atrophy from disuse of the limb, or +alteration in their configuration as a result of partial dislocation. +Osseous ankylosis may occur, especially in the small joints of the hand +and foot. + +The disease is generally poly-articular and may be met with in childhood +and youth as well as in adult life. In some cases pain is so severe that +the patient resists the least attempt at movement. In others, the +joints, although stiff, can be moved but exhibit pronounced crackings. +When there is much connective tissue formed in relation to the synovial +membrane, the joint is swollen, and as the muscles waste above and +below, the swelling is spindle-shaped. Subacute exacerbations occur from +time to time, with fever and aggravation of the local symptoms and +implication of other joints. After repeated recurrences, there is +ankylosis with deformity, the patient becoming a helpless cripple. On +account of the tendency to visceral complications, the tenure of life is +uncertain. + +From the nature of the disease, _treatment_ is for the most part +palliative. Salicylates are only of service during the exacerbations +attended with pyrexia. The application of soda fomentations, turpentine +cloths, or electric or hot-air baths may be useful. Improvement may +result from the general and local therapeutics available at such places +as Bath, Buxton, Harrogate, Strathpeffer, Wiesbaden, or Aix. In selected +cases, a certain measure of success has followed operative interference, +which consists in a modified excision. The deformities resulting from +chronic rheumatism are but little amenable to surgical treatment, and +forcible attempts to remedy stiffness or deformity are to be avoided. + +#Arthritis Deformans# (_Osteo-arthritis, Rheumatoid Arthritis, Rheumatic +Gout, Malum Senile, Traumatic or Mechanical Arthritis_).--Under the term +arthritis deformans, which was first employed by Virchow, it is +convenient to include a number of joint affections which have many +anatomical and clinical features in common. + +The disease is widely distributed in the animal kingdom, both in +domestic species and in wild animals in the natural state such as the +larger carnivora and the gorilla; evidence of it has also been found in +the bones of animals buried with prehistoric man. + +The morbid changes in the joints present a remarkable combination of +atrophy and degeneration on the one hand and overgrowth on the other, +indicating a profound disturbance of nutrition in the joint structures. +The nature of this disturbance and its etiology are imperfectly known. +By many writers it is believed to depend upon some form of +auto-intoxication, the toxins being absorbed from the gastro-intestinal +tract, and those who suffer are supposed to possess what has been called +an "arthritic diathesis." + +The localisation of the disease in a particular joint may be determined +by several factors, of which trauma appears to be the most important. +The condition is frequently observed to follow, either directly or after +an interval, upon a lesion which involves gross injury of the joint or +of one of the neighbouring bones. It occurs with greater frequency after +repeated minor injuries affecting the joint and its vicinity, such as +sprains and contusions, and particularly those sustained in laborious +occupations. This connection between trauma and arthritis deformans led +Arbuthnot Lane to apply to it the term _traumatic_ or _trade arthritis_. + +The traumatic or strain factor in the production of the disease may be +manifested in a less obvious fashion. In the lower extremity, for +example, _any condition which disturbs the static equilibrium of the +limb as a whole_ would appear to predispose to the disease in one or +other of the joints. The static equilibrium may be disturbed by such +deformities as flat-foot or knock-knee, and badly united fractures of +the lower extremity. In hallux valgus, the metatarso-phalangeal joint of +the great toe undergoes changes characteristic of arthritis deformans. + +A number of cases have been recorded in which arthritis deformans has +followed upon antecedent disease of the joint, such as pyogenic or +gonorrhoeal synovitis, upon repeated haemorrhages into the knee-joint in +bleeders, and in unreduced dislocations in which a new joint has been +established. + +[Illustration: FIG. 157.--Arthritis Deformans of Elbow, showing +destruction of articular surfaces and masses of new bone around the +articular margins. + +(Anatomical Museum, University of Edinburgh.)] + +Lastly, Poncet and other members of the Lyons school regard arthritis +deformans as due to an attenuated form of tuberculous infection, and +draw attention to the fact that a tuberculous family history is often +met with in the subjects of the disease. + +[Illustration: FIG. 158.--Arthritis Deformans of Knee, showing +eburnation and grooving of articular surfaces. + +(Anatomical Museum, University of Edinburgh.)] + +_Morbid Anatomy._--The commonest type is that in which the articular +surfaces undergo degenerative changes. The primary change involves the +articular cartilage, which becomes softened and fibrillated and is worn +away until the subjacent bone is exposed. If the bone is rarefied, the +enlarged cancellous spaces are opened into and an eroded and worm-eaten +appearance is brought about; with further use of the joint, the bone is +worn away, so that in a ball-and-socket joint like the hip, the head of +the femur and the acetabulum are markedly altered in size and shape. +More commonly, the bone exposed as a result of disappearance of the +cartilage is denser than normal, and under the influence of the +movements of the joint, becomes smooth and polished--a change described +as _eburnation_ of the articular surfaces (Fig. 158). In hinge-joints +such as the knee and elbow, the influence of movement is shown by a +series of parallel grooves corresponding to the lines of friction +(Fig. 158). + +[Illustration: FIG. 159.--Hypertrophied Fringes of Synovial Membrane in +Arthritis Deformans of Knee. + +(Museum of Royal College of Surgeons, Edinburgh.)] + +While these degenerative changes are gradually causing destruction of +the articular surfaces, reparative and hypertrophic changes are taking +place at the periphery. Along the line of the junction between the +cartilage and synovial membrane, the proliferation of tissue leads to +the formation of nodules or masses of cartilage--_ecchondroses_--which +are subsequently converted into bone (Fig. 157). Gross alterations in +the ends of the bone are thus brought about which can be recognised +clinically and in skiagrams, and which tend to restrict the normal range +of movement. The extension of the ossification into the synovial +reflection and capsular ligament adds a collar or "lip" of new bone, +known as "lipping" of the articular margins, and also into other +ligaments, insertions of tendons and intermuscular septa giving rise to +bony outgrowths or osteophytes not unlike those met with in the +neuro-arthropathies. + +Proliferative changes in the synovial membrane are attended with +increased vascularity and thickening of the membrane and an enlargement +of its villi and fringes. When the fatty fringes are developed to an +exaggerated degree, the condition is described as an _arborescent +lipoma_ (Fig. 159). Individual fringes may attain the size of a hazel +nut, and the fibro-fatty tissue of which they are composed may be +converted into cartilage and bone; such a body may remain attached by a +narrow pedicle or stalk, or this may be torn across and the body becomes +loose and, unless confined in a recess of the joint, it wanders about +and may become impacted between the articular surfaces. These changes in +the synovial membrane are often associated with an abundant exudate or +hydrops. These degenerative and hypertrophic changes, while usually +attended with marked restriction of movement and sometimes by "locking" +of the joint, practically never result in ankylosis. + +The _ankylosing type_ of chronic arthritis is fortunately much rarer +than those described above, and is chiefly met with in the joints of the +fingers and toes and in those of the vertebral column. The synovial +membrane proliferates, grows over the cartilage, and replaces it, and +when two such articular surfaces are in contact they tend to adhere, +thus obliterating the joint, cavity, and resulting in fibrous or bony +ankylosis. The changes progress slowly and, before they result in +ankylosis, various sub-luxations and dislocations may occur with +distortion and deformity which, in the case of the fingers, is extremely +disabling and unsightly (Fig. 160). + +_Clinical Features._--It is usually observed that in patients who are +still young the tendency is for the disease to advance with considerable +rapidity, so that in the course of months it may cause crippling of +several joints. The course of the disease as met with in persons past +middle life is more chronic; it begins insidiously, and many years may +pass before there is pronounced disability. The earliest symptom is +stiffness, especially in the morning after rest, which passes off +temporarily with use of the limb. As time goes on, the range of movement +becomes restricted, and crackings occur. This stage of the disease may +be prolonged indefinitely; if it progresses, stiffness becomes more +pronounced, certain movements are lost, others develop in abnormal +directions, and deformed attitudes add to the disablement. The disease +is compatible with long life, but not with any active occupation, hence +those of the hospital class who suffer from it tend to accumulate in +workhouse infirmaries. + +_Hydrops_ is most marked in the knee, and may affect also the adjacent +bursae. As the joint becomes distended with fluid, the ligaments are +stretched, the limb becomes weak and unstable, and the patient complains +of a feeling of weight, of insecurity, and of tiredness. Pain is +occasional and evanescent, and is usually the result of some extra +exertion, or exposure to cold and wet. This form of the disease is +extremely chronic, and may last for an indefinite number of years. It is +to be diagnosed from the other forms of hydrops already considered--the +purely traumatic, the pyogenic, gonorrhoeal, tuberculous, and +syphilitic--and from that associated with Charcot's disease. + +_Hypertrophied fringes and pedunculated or loose bodies_ often co-exist +with hydrops, and give rise to characteristic clinical features, +particularly in the knee. The fringes, especially when they assume the +type of the arborescent lipoma, project into the cavity of the joint, +filling up its recesses and distending its capsule so that the joint is +swollen and slightly flexed. Pain is not a prominent feature, and the +patient may walk fairly well. On grasping the joint while it is being +actively flexed and extended, the fringes may be felt moving under the +fingers. Symptoms from impaction of a loose body are exceptional. + +[Illustration: FIG. 160.--Arthritis Deformans of Hands, showing +symmetry of lesions, ulnar deviation of fingers, and nodular thickening +at inter-phalangeal joints.] + +_The dry form of arthritis deformans_, although specially common in the +knee, is met with in other joints, either as a mon-articular or +poly-articular disease; and it is also met with in the joints of the +spine and of the fingers as well as in the temporo-mandibular joint. In +the joints of the fingers the disease is remarkably symmetrical, and +tends to assume a nodular type (Heberden's nodes) (Fig. 160); in younger +subjects it assumes a more painful and progressive fusiform type +(Fig. 161). In the larger joints the subjective symptoms usually precede + +any palpable evidence of disease, the patient complaining of stiffness, +crackings, and aching, aggravated by changes in the weather. The +roughness due to fibrillation of the articular cartilages causes coarse +friction on moving the joint, or, in the knee, on moving the patella on +the condyles of the femur. It may be months or even years before the +lipping and other hypertrophic changes in the ends of the bones are +recognisable, and before the joint assumes the deformed features which +the name of the disease suggests. + +The capsular ligament, except in hydrops, is the seat of +connective-tissue overgrowth, and tends to become contracted and rigid. +Intra-articular ligaments, such as the ligamentum teres in the hip, are +usually worn away and disappear. The surrounding muscles undergo +atrophy, tendons become adherent to their sheaths and may be ossified, +and the sheaths of nerves may be involved by the cicatricial changes in +the surrounding tissues. + +_The X-ray appearances of arthritis deformans_ necessarily vary with the +type of the disease and the joint affected; in the joints of the fingers +there is a narrowing of the spaces between the articular ends of the +bones as a result of absorption of the articular cartilage, and +rarefaction of the cancellous tissue in the vicinity of the joints; in +the larger joints there is "lipping" of the articular margins, +osteophytes, and other evidence of abnormal ossification in and around +the joint. Eburnation of the articular surfaces is shown by increase in +the density of the shadow of the bone in the areas affected. + +[Illustration: FIG. 161.--Arthritis Deformans affecting several +Joints, in a boy aet. 10. + +(Dr. Dickson's case.)] + +_Treatment._--Treatment is for the most part limited to the relief of +symptoms. On no account should the affected joints be kept at rest by +means of splints or other apparatus. Active movements and exercises of +all kinds are to be persevered with. When pain is a prominent feature, +it may be relieved either by douches of iodine and hot water (tincture +of iodine 1 oz. to the quart), or by the application of lint saturated +with a lotion made up of chloral hydrate, gr. v, glycerin [dram]j, water +[ounce]j, and covered with oil-silk. Strain and over-use of the joint +and sudden changes of temperature are to be avoided. The induction of +hyperaemia by means of massage, the elastic bandage, and hot-air baths is +often of service. Operative interference is indicated when the disease +is of a severe type, when it is mon-articular, and when the general +condition of the patient is otherwise favourable. Excision has been +practised with success in the hip, knee, elbow, and temporo-mandibular +joints. Limitation of movement and locking at the hip-joint when due to +new bone round the edge of the acetabulum may be greatly relieved by +removal of the bone--a procedure known as _cheilotomy_. Loose bodies and +hypertrophied fringes if causing symptoms may also be removed by +operation. + +When stiffness and grating on movement are prominent features we have +found the injection of from half to one ounce of sterilised white +vaseline afford decided relief. + +The patient should be nourished well, and there need be no restriction +in the diet such as is required in gouty patients, so long as the +digestion is not impaired. Benefit is also derived from the +administration of cod-liver oil, and of tonics, such as strychnin, +arsenic, and iron, and in some cases of iodide of potassium. Luff +recommends the administration over long periods of guaiacol carbonate, +in cachets beginning with doses of 5-10 grs. and increased to 15-20 grs. +thrice daily. A course of treatment at one of the reputed spas--Aix, +Bath, Buxton, Gastein, Harrogate, Strathpeffer, Wiesbaden, Wildbad--is +often beneficial. + +In some cases benefit has followed the prolonged internal administration +of liquid paraffin. + +On the assumption that the condition is the result of an +auto-intoxication from the intestinal tract, saline purges and +irrigation of the colon are indicated, and Arbuthnot Lane claims to have +brought about improvement by short-circuiting or by resecting the colon. + +Residence in a warm and dry climate, with an open-air life, has been +known to arrest the disease when other measures have failed to give +relief. + +The application of radium and the ingestion of radio-active waters have +also been recommended. + +#Haemophilic# or #Bleeder's Joint#.--This is a rare but characteristic +affection met with chiefly in the knee-joint of boys who are the +subjects of haemophilia. After some trivial injury, or even without +apparent cause, a haemorrhage takes place into the joint. The joint is +tensely swollen, cannot be completely extended, and is so painful that +the patient is obliged to lie up. The temperature is often raised (101 o +to 102 o F.), especially if there are also haemorrhages elsewhere. The +blood in the joint is slowly re-absorbed, and by the end of a fortnight +or so, the symptoms completely disappear. As a rule these attacks are +repeated; the pain attending them diminishes, but the joint becomes the +seat of permanent changes: the synovial membrane is thickened, +abnormally vascular, and coloured brown from the deposit of blood +pigment; on its surface, and in parts of the articular cartilage, there +is a deposit of rust-coloured fibrin; there may be extensive adhesions, +and in some cases changes occur like those observed in arthritis +deformans with erosion and ulceration of the cartilage and a form of dry +caries of the articular surfaces, which may terminate in ankylosis. + +As the swelling of the joint is associated with wasting of the muscles, +with stiffness, and with flexion, the condition closely resembles +tuberculous disease of the synovial membrane. From errors in diagnosis +such joints have been operated upon, with disastrous results due to +haemorrhage. + +The treatment of a recent haemorrhage consists in securing absolute rest +and applying elastic compression. The introduction of blood-serum (10-15 +c.c.) into a vein may assist in arresting the haemorrhage; +anti-diphtheritic serum is that most readily obtainable. + +After an interval, measures should be adopted to promote the absorption +of blood and to prevent stiffness and flexion; these include massage, +movements, and extension with weight and pulley. + + +JOINT DISEASES ASSOCIATED WITH LESIONS OF THE NERVOUS SYSTEM: +NEURO-ARTHROPATHIES + +_In Lesions of Peripheral Nerves._--In the hand, and more rarely in the +foot, when one or other of the main nerve-trunks has been divided or +compressed, the joints may become swollen and painful and afterwards +become stiff and deformed. Bony ankylosis has been observed. + +_In Affections of the Spinal Medulla._--In myelitis, progressive +muscular atrophy, poliomyelitis, insular sclerosis, and in traumatic +lesions, joint affections are occasionally met with. + +The occurrence of joint lesions in _locomotor ataxia_ (tabes dorsalis) +was first described by Charcot in 1868--hence the term "Charcot's +disease" applied to them. Although they usually develop in the ataxic +stage, one or more years after the initial spinal symptoms, they may +appear before there is any evidence of tabes. The onset is frequently +determined by some injury. The joints of the lower extremity are most +commonly affected, and the disease is bilateral in a considerable +proportion of cases--both knees or both hips, for instance, being +implicated. + +Among the theories suggested in explanation of these arthropathies the +most recent is that by Babinski and Barre, which traces the condition to +vascular lesions of a syphilitic type in the articular arteries. + +The first symptom is usually a swelling of the joint and its vicinity. +There is no redness or heat and no pain on movement. The peri-articular +swelling, unlike ordinary oedema, scarcely pits even on firm pressure. + +[Illustration: FIG. 162.--Bones of Knee-joint in advanced stage of +Charcot's Disease. The medial part of the head of the tibia has +disappeared. + +(Anatomical Museum, University of Edinburgh).] + +In mild cases this condition of affairs may persist for months; in +severe cases destructive changes ensue with remarkable rapidity. The +joint becomes enormously swollen, loses its normal contour, and the ends +of the bones become irregularly deformed (Fig. 162). Sometimes, and +especially in the knee, the clinical features are those of an enormous +hydrops with fibrinous and other loose bodies and hypertrophied +fringes--and great oedema of the peri-articular tissues (Fig. 163). The +joint is wobbly or flail-like from stretching and destruction of the +controlling ligaments, and is devoid of sensation. In other cases, +wearing down and total disappearance of the ends of the bones is the +prominent feature, attended with flail-like movements and with coarse +grating. Dislocation is observed chiefly at the hip, and is rather a +gross displacement with unnatural mobility than a typical dislocation, +and it is usually possible to move the bones freely upon one another and +to reduce the displacement. A striking feature is the extensive +formation of new bone in the capsular ligament and surrounding muscles. +The enormous swelling and its rapid development may suggest the growth +of a malignant tumour. The most useful factor in diagnosis is the entire +absence of pain, of tenderness, and of common sensibility. The freedom +with which a tabetic patient will allow his disorganised joint to be +handled requires to be seen to be appreciated. + +[Illustration: FIG. 163.--Charcot's Disease of Left Knee. The joint is +distended with fluid and the whole limb is oedematous.] + +The rapidity of the destructive changes in certain cases of tabes, and +the entire absence of joint lesions in others, would favour the view +that special parts of the spinal medulla must be implicated in the +former group. + +In _syringomyelia_, joint affections (gliomatous arthropathies) are more +frequent than in tabes, and they usually involve the upper extremity in +correspondence with the seat of the spinal lesion, which usually affects +the lower cervical and upper thoracic segments. Except that the joint +disease is seldom symmetrical, it closely resembles the arthropathy of +tabes. The completeness of the analgesia of the articular structures +and of the overlying soft parts is illustrated by the fact that in one +case the patient himself was in the habit of letting out the fluid from +his elbow with the aid of a pair of scissors, and that in another the +joint was painlessly excised without an anaesthetic. + +[Illustration: FIG. 164.--Charcot's Disease of both Ankles: front view. +Man, aet. 32.] + +The disease may become arrested or may go on to complete +disorganisation; suppuration may ensue from infection through a breach +of the surface, and in rare cases the joint has become the seat of +tuberculosis. + +[Illustration: FIG. 165.--Charcot's Disease of both Ankles: back view. +Man, aet. 32.] + +_Treatment_, in addition to that of the nerve lesion underlying the +arthropathy, consists in supporting and protecting the joint by means of +bandages, splints, and other apparatus. In the lower extremity, the use +of crutches is helpful in taking the strain off the affected limb. When +there is much distension of the joint, considerable relief follows upon +withdrawal of fluid. The best possible result being rigid ankylosis in a +good position, it may be advisable to bring this about artificially by +arthrodesis or resection. Operation is indicated when only one joint is +affected and when the cord lesion is such as will permit of the patient +using the limb. The wounds heal well, but the victims of tabes are +unfavourable subjects for operative interference, on account of their +liability to intercurrent complications. When the limb is quite useless, +amputation may be the best course. + +_In cerebral lesions_ attended with hemiplegia, joint affections, +characterised by evanescent pain, redness, and swelling, are +occasionally met with. The secondary changes in joints which are the +seat of paralytic contracture are considered with the surgery of the +Extremities. + +In cases of _hysteria_ and other _functional affections of the +nervous system_, an intermittent neuropathic hydrops has been +observed--especially in the knee. Without apparent cause, the joint +fills with fluid and its movements become restricted, and after from two +to eight days the swelling subsides and the joint returns to normal. A +remarkable feature of the condition is that the effusion into the joint +recurs at regular intervals, it may be over a period of years. Psychic +conditions have been known to induce attacks, and sometimes to abort +them or even to cause their disappearance. Hence it has been recommended +that treatment by suggestion should be employed along with tonic doses +of quinine and arsenic. + + +HYSTERICAL OR MIMETIC JOINT AFFECTIONS + +Under this heading, Sir Benjamin Brodie, in 1822, described an affection +of joints, characterised by the prominence of subjective symptoms and +the absence of pathological changes. Although most frequently met with +in young women with an impressionable nervous system, and especially +among those in good social circumstances, it occurs occasionally in men. +The onset may be referred to injury or exposure to cold, or may be +associated with some disturbance of the emotions or of the generative +organs; or the condition may be an involuntary imitation of the symptoms +of organic joint disease presented by a relative or friend. + +It is characteristic that the symptoms develop abruptly without +satisfactory cause, that they are exaggerated and wanting in harmony +with one another, and that they do not correspond with the features of +any of the known forms of organic disease. In some cases the only +complaint is of severe pain; more often this is associated with +excessive tenderness and with impairment of the functions of the joint. +On examination the joint presents a normal appearance, but the skin +over it is remarkably sensitive. A light touch is more likely to excite +pain than deep and firm pressure. Stiffness is a variable feature--in +some cases amounting to absolute rigidity, so that no ordinary force +will elicit movement. It is characteristic of this, as of other +neuroses, that the symptoms come and go without sufficient cause. When +the patient's attention is diverted, the pain and stiffness may +disappear. There is no actual swelling of the joint, although there may +be an appearance of this from wasting of the muscles above and below. If +the joint is kept rigid for long periods, secondary contracture may +occur--in the knee with flexion, in the hip with flexion and adduction. + +The _diagnosis_ is often a matter of considerable difficulty, and the +condition is liable to be mistaken for such organic lesions as a +tuberculous or pyogenic focus in the bone close to the joint. + +The greatest difficulty is met with in the knee and hip, where the +condition may closely simulate tuberculous disease. The use of the +Rontgen rays, or examination of the joint under anaesthesia, is helpful. + +The _local treatment_ consists chiefly in improving the nutrition of the +affected limb by means of massage, exercises, baths, and electricity. +Splints are to be avoided. In refractory cases, benefit may follow the +application of blisters or of Corrigan's button. The general condition +of the patient must be treated on the same lines as in other neuroses. +The Weir-Mitchell treatment may have to be employed in obstinate cases, +the patient being secluded from her friends and placed in charge of a +nurse. Complete recovery is the rule, but when the muscles are weak and +wasted from prolonged disuse, a considerable time may elapse before the +limb returns to normal. + + +TUMOURS AND CYSTS + +New growths taking origin in the synovial membrane are rare, and are not +usually diagnosed before operation. They are attended with exudation +into the joint, and in the case of _sarcoma_ the fluid is usually +blood-stained. If the tumour projects in a polypoidal manner into the +joint, it may cause symptoms of loose body. One or two cases have been +recorded in which a _cartilaginous tumour_ growing from the synovial +membrane has erupted through the joint capsule and infiltrated the +adjoining muscles. _Multiple cartilaginous tumours_ forming loose bodies +are described on p. 544. + +_Cysts of joints_ constitute an ill-defined group which includes ganglia +formed in relation to the capsular ligament. Cystic distension of bursae +which communicate with the joint is most often met with in the region of +the knee in cases of long-standing hydrops. It was suggested by Morrant +Baker that cystic swellings may result from the hernial protrusion of +the synovial membrane between the stretched fibres of the capsular +ligament, and the name "Baker's cysts" has been applied to these. + +In the majority of cases, cysts in relation to joints give rise to +little inconvenience and may be left alone. If interfered with at all, +they should be excised. + + +LOOSE BODIES + +It is convenient to describe the varieties of loose bodies under two +heads: those composed of fibrin, and those composed of organised +connective tissue. + +#Fibrinous Loose Bodies# (Corpora oryzoidea).--These are homogeneous or +concentrically laminated masses of fibrin, sometimes resembling rice +grains, melon seeds, or adhesive wafers, sometimes quite irregular in +shape. Usually they are present in large numbers, but sometimes there is +only one, and it may attain considerable dimensions. They are not +peculiar to joints, for they are met with in tendon sheaths and bursae, +and their origin from synovial membrane may be accepted as proved. They +occur in tuberculosis, arthritis deformans, and in Charcot's disease, +and their presence is almost invariably associated with an effusion of +fluid into the joint. While they may result from the coagulation of +fibrin-forming elements in the exudate, their occurrence in tuberculous +hydrops would appear to be the result of coagulation necrosis, or of +fibrinous degeneration of the surface layer of the diseased synovial +membrane. However formed, their shape is the result of mechanical +influences, and especially of the movement of the joint. + +_Clinically_, loose bodies composed of fibrin constitute an unimportant +addition to the features of the disease with which they are associated. +They never give rise to the classical symptoms associated with impaction +of a loose body between the articular surfaces. Their presence may be +recognised, especially in the knee, by the crepitating sensation +imparted to the fingers of the hand grasping the joint while it is +flexed and extended by the patient. + +The _treatment_ is directed towards the disease underlying the hydrops. +If it is desired to empty the joint, this is best done by open +incision. + +[Illustration: FIG. 166.--Radiogram of Multiple Loose Bodies in +Knee-joint and Semi-membranosus Bursa in a man aet. 38. + +(Mr. J. W. Dowden's case.)] + +#Bodies composed of Organised Connective Tissue.#--These are +comparatively common in joints that are already the seat of some chronic +disease, such as arthritis deformans, Charcot's arthropathy, or synovial +tuberculosis. They take origin almost exclusively from an erratic +overgrowth of the fringes of the synovial membrane, and may consist +entirely of fat, the arborescent lipoma (Fig. 159) being the most +pronounced example of this variety. Fibrous tissue or cartilage may +form in one or more of the fatty fringes and give rise to hard nodular +masses, which may attain a considerable size, and in course of time may +undergo ossification. + +Like other hypertrophies on a free surface, they tend to become +pedunculated, and so acquire a limited range of movement. The pedicle +may give way and the body become free. In this condition it may wander +about the joint, or lie snugly in one of its recesses until disturbed by +some sudden movement. A loose body free in a joint is capable of growth, +deriving the necessary nutriment from the surrounding fluid. The size +and number of the bodies vary widely. Single specimens have been known +to attain the size of the patella. The smaller varieties may number +considerably over a hundred. + +[Illustration: FIG. 167.--Loose Body from Knee-joint of man aet. 25. +Natural size. + +a = Convex surface. b = Concave surface.] + +In arthritis deformans a rarer type of loose body is met with, a portion +of the lipping of one of the articular margins being detached by injury. +In Charcot's disease, bodies composed of bone are formed in relation to +the capsular and other ligaments, and may be made to grate upon one +another. + +The _clinical features_ in this group are mainly those of the disease +which has given rise to the loose bodies, and it is exceptional to meet +with symptoms from impaction of the body between the articular surfaces. +Treatment is to be directed towards the primary disease in the joint, as +well as to the removal of the loose bodies. + +[Illustration: FIG. 168.--Multiple partially ossified Chondromas of +Synovial Membrane, from Shoulder-joint, the seat of arthritis deformans, +from a man aet. 35.] + +_Loose Bodies in Joints which are otherwise healthy._--It is in joints +otherwise healthy that loose bodies causing the classical symptoms and +calling for operative treatment are most frequently met with. They occur +chiefly in the knee and elbow of healthy males under the age of thirty. +The complaint may be of vague pains, of occasional cracking on moving +the joint, or of impairment of function--usually an inability to extend +or flex the joint completely. In many cases a clear account is given of +the symptoms which arise when the body is impacted between the articular +surfaces, namely, sudden onset of intense sickening pain, loss of power +in the limb and locking of the joint, followed by effusion and other +accompaniments of a severe sprain. On some particular movement, the +body is disengaged, the locking disappears, and recovery takes place. +Attacks of this kind may recur at irregular intervals, during a period +of many years. On examining the joint, it is usually found to contain +fluid, and there may be points of special tenderness corresponding to +the ligaments that have been overstretched. In cases in which there has +been recurrent attacks of locking, the ligaments become slack, the joint +is wobbly, and the quadriceps is wasted. The patient himself, or the +surgeon, may discover the loose body and feel it roll beneath his +fingers, especially if it is lodged in the supra-patellar pouch in the +knee, or on one or other side of the olecranon in the elbow. In most +instances the patient has carefully observed his own symptoms, and is +aware not only of the existence of the loose body, but of its erratic +appearance at different parts of the joint. This feature serves to +differentiate the lesions from a torn medial meniscus in which the pain +and tenderness are always in the same spot. As the body usually contains +bone, it is recognisable in a skiagram. + +[Illustration: FIG. 169.--Multiple Cartilaginous Loose Bodies from +Knee-joint.] + +There are two methods of _removing the body_; the first and simpler +method is applicable when the body can be palpated, usually in the +supra-patellar pouch; it is preferably transfixed by a needle and can +then be removed through a small incision; otherwise, the joint must be +freely opened and explored, firstly to find the body and further to +remove it. + +The characters of this type of loose body are remarkably constant. It is +usually solitary, about the size of a bean or almond, concavo-convex in +shape, the convex aspect being smooth like an articular surface, the +concave aspect uneven and nodulated and showing reparative changes, +healing over of the raw surface, and the new formation of fibrous +tissue, hyaline cartilage and bone, the necessary nutriment being +derived from the synovial fluid (Fig. 167). The body is sometimes found +to be lodged in a defect or excavation in one of the articular surfaces, +usually the medial condyle of the femur, from which it is readily +shelled out by means of an elevator. It presents on section a layer of +articular cartilage on the convex aspect and a variable thickness of +spongy bone beneath this. + +The origin of these bodies is one of the most debated questions in +surgical pathology; they obviously consist of a portion of the articular +surface of one of the bones, but how this is detached still remains a +mystery; some maintain that it is purely traumatic; Konig regards them +as portions of the articular surface which have been detached by a +morbid process which he calls "osteochondritis dessicans." + +_Multiple Chondromas and Osteomas of the Synovial Membrane._--In this +rare type of loose body, the surface of the synovial membrane is studded +with small sessile or pedunculated tumours composed of pure hyaline +cartilage, or of bone, or of transition stages between cartilage and +bone. They are pearly white in colour, pitted and nodular on the +surface, rarely larger than a pea, although when compressed they may +cake into masses of considerable size. With the movements of the joint +many of the tumours become detached and lie in the serous exudate +excited by their presence. They are found also in the diverticula of the +synovial membrane, in the shoulder in the downward prolongation along +the tendon of the biceps, in the hip in the bursal extension beneath the +psoas. + +The patient complains of increasing disability of the limb, movements of +the joint becoming more and more restricted and painful. There is +swelling corresponding to the distended capsule of the joint, and on +palpation the bodies moving under the fingers yield a sensation as of +grains of rice shifting in a bag. If the bodies are so numerous as to be +tightly packed together, the impression is that of a plastic mass having +the shape of the synovial sac. The stiffness and the cracking on +movement may suggest arthritis deformans, but the X-ray appearances make +the diagnosis an easy one. We have observed two cases of this affection +in the knee-joint of adult women, one in the shoulder-joint of an adult +male (Fig. 168), and Caird has observed one in the hip. The treatment +consists in opening the joint by free incision and removing the bodies. + +_Displacement of the menisci_ of the knee is referred to with injuries +of that joint. + + + + +INDEX + + + Abdominal aneurysm, 313 + aorta, compression of, 269 + embolus of, 93 + + Abscess, 46 + acute circumscribed, 46 + of bone, 448 + Brodie's, 448 + chronic, 139 + cold, 139 + embolic, 66 + formation of, 47 + Hilton's method of opening, 50 + pointing of, 48 + pyaemic, 287 + residual, 141 + of skin, multiple, 382 + stitch, 51 + treatment of, 49 + tuberculous, 139, 141 + peri-articular, 514, 517 + + Achillo-bursitis, 432 + + Achillo-dynia, 422 + + Acidosis, 251 + + Acromion bursa, 429 + + Actinomycosis, 126 + + Active hyperaemia, 39 + + Acupuncture in aneurysm, 308 + + Acute arthritis of infants, 440 + necrosis of bone, 439 + + Adductor longus muscle, rupture of, 408 + + Adenoma, 202 + malignant, 209 + sebaceous, 393 + of skin, 393 + varieties of, 202 + + Adiposus dolorosa, 186 + + Aerobes, 19 + + Air embolism, 265 + hunger, 276 + + Albumosuria, 195, 474, 492 + + Aleppo boil, 129 + + Alexins, 22 + + Ambrine, 13, 238 + + Amputation neuroma, 344 + + Anaerobes, 19 + + Anaesthesia, after nerve injuries, 347 + + Analgesia, 347 + + Anaphylaxis, 23 + + Anatomical tubercle, 134 + + Anatomy. _See_ Surgical Anatomy + + Anel's operation for aneurysm, 307 + + Aneurysm, 300. _See also_ Individual Arteries + abdominal, 313 + acupuncture in, 308 + amputation in, 310 + by anastomosis, 298 + Anel's operation for, 307, 310 + arterio-venous, 263 + axillary, 318 + of bone, 498 + brachial, 318 + Brasdor's operation for, 308 + cirsoid, 299 + Colt's method of wiring for, 309 + compression for, 308 + consolidated, 304, 305 + differential diagnosis of, 305 + diffused, 302 + digital compression in, 308 + excision of, 307 + of forearm and hand, 318 + fusiform, 301 + gelatin injections in, 309 + Hunter's operation for, 307 + iliac, 318 + of individual arteries, 312 + inguinal, 318 + innominate, 314 + intracranial, 316 + of leg and foot, 320 + ligation of artery for, 307 + Macewen's acupuncture for, 308 + Matas' operation for, 307 + Moore-Corradi method, 308 + natural cure of, 305 + old operation for, 307 + of ophthalmic artery, 317 + orbital, 317 + pathological, 301 + pulse in, 304 + rupture of, 306 + sacculated, 302 + suppuration in, 306 + thoracic, 312 + traumatic, 263, 310 + treatment of, 306 + varicose, 311 + Wardrop's operation for, 308 + X-rays in diagnosis of, 304 + + Aneurysmal varix, 311, 316, 318, 319, 320 + + Angioma, 284 + arterial, 299 + capillary, 294 + cavernous, 297 + racemosum venosum, 287 + venous, 294 + + Angio-neurotic oedema, 348 + sarcoma, 199 + + Angler's elbow, 406 + + Ankle, cellulitis of, 58 + + Ankylosis of joints, 503. _See also_ Individual Joints + + Anoci-association, 253 + + Anthracaemia, 121 + + Anthrax, 119 + + Anti-bacterial sera, 23 + -diphtheritic serum, 111 + -streptococcic serum, 23, 109 + -tetanic serum, 117 + + Antibodies, 22 + + Antigens, 22 + + Antiseptics, 242 + + Antitoxic sera, 23 + + Antitoxins, 22 + + Antivenin, 132 + + Aorta, abdominal, compression of, 269 + aneurysm of, 313 + embolism of, 93 + ligation of, 314 + pulsating, 305, 314 + + Arborescent lipoma, 423 + + Arseno-billon, 163 + + Arteries, anatomy of, 258 + compression of individual, 269 + contusion of, 260 + digital compression of, 269 + gangrene following ligation of, 94 + gunshot wounds of, 263 + + Arteries, ligation of, for aneurysm, 307 + punctured wounds of, 262 + repair of, 266, 268 + rupture of, 260 + wounds of, 261, 262 + + Arterio-sclerosis, 282 + + Arterio-venous aneurysm, 310 + + Arteritis, varieties of, 282 + + Arthritis, 501. _See also_ Individual Joints + acute, 506 + of infants, 440 + deformans, 524 + gonococcal, 510 + neuropathic, 532 + ossificans, 503 + pneumococcal, 509 + pyogenic, 506 + rheumatic, 523 + rheumatoid, 524 + septic, 506 + scarlatinal, 508 + trade, 525 + traumatic, 524 + tuberculous, 512 + urica, 522 + + Arthrolysis, 505 + + Arthropathies, 532 + gliomatous, 534 + + Arthroplasty, 505 + + Articular caries, 502, 514 + + Artificial hyperaemia, 39 + + Ascites, chylous, 325 + + Asepsis, 18 + + Asphyxia, local, 97 + traumatic, 254 + + Atheroma, 283 + + Avulsion of nerves, 375 + of tendons, 411 + + Axilla, cellulitis of, 58 + hygroma of, 328 + + Axillary aneurysm, 318 + artery, embolus of, 93 + lymph glands, 336 + nerve, injuries of, 363 + + + Bacilli, 19 + + Bacillus aerogenes capsulatus, 99 + anthracis, 119 + coli communis, 27 + diphtheriae 109 + drum-stick, 112 + of Ducrey, 154 + of glanders, 123 + Klebs-Loffler, 109 + of malignant oedema, 101 + mallei, 123 + pyocyaneus, 29 + of soft sore, 154 + of tetanus, 112 + tubercle, 133 + typhosus, 29, 452 + + Bacteria, death of, 21 + general characters of, 18 + pathogenic properties of, 19 + pyogenic, 24, 29 + + Bacterial intoxication, 21 + + Bacteriology, surgical, 17 + + Baker's cysts, 539 + + Bazin's disease, 74, 169 + + Beck's paste in sinuses, 145 + + Bed-sores, 73, 103 + + Bence-Jones on albumosuria, 195, 474, 492 + + Biceps, bursa under, 430 + dislocation of long tendon of, 409 + rupture of, 407 + + Bier's artificial hyperaemia, 38 + + B.I.P.P., 143 + + Birth palsies, 362 + + Biskra button, 129 + + Bismuth gauze, 247 + injections in sinuses, 145 + + Bites of animals, 223 + + Black eye, 219 + + Bleeder's joint, 531 + + Bleeders, 277 + bruises in, 218 + + Blisters, 376 + purulent, 55 + + Blocking of nerves for shock, 252 + + Blood, count, 30 + cysts, 214, 220 + transfusion of, 11, 253 + + Blood vessels. _See_ Arteries and Veins + + Bloodless state, treatment of, 276 + + Blood letting, general, 42 + + Boil, 379 + Aleppo, 129 + Delhi, 129 + + Bone. _See also_ Individual Bones + abscess of, 448 + aneurysm of, 498 + angioma of, 491 + atrophy of, 479 + bacterial diseases of, 438 + Brodie's abscess of, 448 + cancer of, secondary, 499 + caries of, 437, 438 + changes in ulcers of leg, 79 + chondroma of, 487 + cysts of, 477, 500 + diseases of, 434 + due to staphylococcus aureus, 438 + endothelioma of, 492 + exostoses of, 191, 481 + fibroma of, 491 + fragility of, 479 + grafting, 16, 436 + gumma of, 464 + hydatid disease of, 467 + hyperostosis, 435, 464 + hypertrophic pulmonary osteo-arthropathy, 480 + hypertrophy of, 435 + lipoma of, 491 + lipping of, 527 + malacia of, 473 + marrow, function of, 434 + myeloma of, 491 + myxoma of, 491 + necrosis of, 438 + neuropathic atrophy of, 479 + osteoma of, 481 + osteomalacia of, 473 + osteomyelitis of, 65, 437, 438, 451, 453, 473 + fibrosa, 476 + osteoporosis of, 437 + osteopsathyrosis, 479 + ostitis deformans, 474 + Paget's disease of, 474 + periosteum, function of, 435 + periostitis, 437 + pulsating haematoma of, 498 + pyogenic diseases of, 438 + regeneration of, 436 + rickety affections of, 468 + sarcoma of, 492 + sclerosis of, 435 + scurvy affecting, 473 + secondary tumours of, 499 + surgical anatomy of, 434 + staphylococcal diseases of, 438 + syphilitic diseases of, 461, 465 + transplantation of, 436 + tuberculous diseases of, 454 + tumours of, 480 + malignant, 492, 499 + metastatic, 499 + thyreoid, 500 + typhoid, infection of, 452 + X-ray appearances in diseases of, 445, 455, 485, 491, 496 + + Bovine tuberculosis, 136 + + Brachial aneurysm, 318 + artery, embolus of, 93 + compression of, 269 + birth-paralysis, 362 + fibrositis, 413 + neuralgia, 371 + plexus, lesions of, 360 + + Brain, joint affections in lesions of, 537 + syphilitic lesions of, 161 + + Branchial dermoids, 211 + + Brasdor's operation for aneurysm, 308 + + Brodie's abscess, 448 + + Bruises, 218 + + Bubo, 329 + bullet, 153 + of soft sores, 155 + + Bullet bubo, 153 + + Bullets, embedded, 231 + varieties of, 230 + + Burnol, 238 + + Burns, 233 + classification, of, 234 + electrical, 239 + pathology of, 233 + by X-rays, 239 + + Bursae. _See also_ Individual Bursae + adventitious, 426 + affections of, 426 + individual, 428 + diseases of, 426, 428 + haematoma of, 426 + hydrops of, 427 + hygroma of, 423 + inflammation of, 426 + injuries of, 426 + loose bodies in, 427 + syphilis of, 428 + tuberculosis of, 428 + tumours of, 427, 428 + + + Cachexia, cancerous, 207 + + Calcanean bursa, 432 + + Calcification in arteries, 282 + in muscles, 416 + in tuberculosis, 136 + + Callosities, 376 + + Callous ulcers, 79, 84 + + Cancer, 202 + arsenic, 395 + of bone, 499 + cachexia in, 207 + chimney-sweep's, 395 + colloid, 210 + columnar epithelial, 209 + contagiousness of, 205 + cystic, 210 + definition of, 202 + degeneration of, 205 + encephaloid, 210 + _en cuirasse_, 204 + glandular, 210 + glandular infection in, 203 + increase of, 207 + of lymph glands, 340 + medullary, 210 + melanotic, 210, 341, 397 + paraffin, 395 + pigmented, 210 + radium treatment of, 208 + rodent, 210, 395 + scirrhous, 210 + of skin, 394 + spread of, 204 + squamous epithelial, 208 + ulceration of, 205 + varieties of, 208 + X-ray, 208 + + Cancrum oris, 102 + + Cantharides plaster, 42 + + Capillaries, anatomy of, 258 + + Capillary angioma, 294 + loops, 3 + + Carbolic gangrene, 95 + + Carbon-dioxide snow, 297 + + Carbuncle, 380 + + Carcinoma. _See_ Cancer + + Caries, 437, 438 + of articular surfaces, 502, 514 + sicca, 438 + syphilitic, 462 + tuberculous, 455 + + Carotid aneurysm, 314 + artery, compression of, 269 + tubercle, 269 + + Carpal ganglion, 214 + + Carron oil, 238 + + Cartilage, grafting of, 16 + repair of, 7 + ulceration of, 502, 514 + + Cartilaginous exostosis, 191, 481 + + Caseation in tuberculosis, 136 + + Catalepsy, 116 + + Catgut, infection by, 51 + preparation of, 245 + + Cautery in haemorrhage, 271 + + Cavernous angioma, 298 + lymphangioma, 327 + + Cellulitis, 52 + in different situations, 58 + diffuse, 52 + + Cephalic or Kopf tetanus, 116 + + Cerebro-spinal meningitis, 115 + + Cervical adenitis, 332 + rib, 360 + + Chalk stones in gouty joints, 523 + + Chancre, concealed, 152, 153, 157 + erratic, 153 + extra-genital, 153 + hard, 151 + meatal, 152 + multiple, 152 + relapsing false indurated, 172 + soft, 154 + urethral, 152 + + Chancroid, 154 + + Charcoal poultice, 84 + + Charcot's disease, 533 + + Cheloid. _See_ Keloid + + Chemiotaxis, 32 + + Chigoe, 130 + + Chilblain, 378 + + Chimney-sweep's cancer, 395 + + Chloroma, 200 + + Chondroma, 189, 487 + multiple, 544 + + Chondromatosis, 488 + + Chondro-sarcoma, 189, 200, 487 + + Chordoma, 200 + + Choroiditis, syphilitic, 177 + + Chylorrhoea, 325 + + Chylo-thorax, 325 + + Chylous ascites, 325 + + Cicatrices, varieties of, 400 + + Cicatricial contraction, 4 + tissue, 4 + + Circumflex nerve. _See_ Axillary Nerve + + Cirsoid aneurysm, 299 + + Claw-hand, 369 + + Cloacae in bone, 443 + + Cocci, 18 + + Coeliac artery, aneurysm of, 313 + + Coley's fluid, 201 + + Collapse, 254 + + Collateral circulation, 267 + + Colles' law, 178 + + Colloid cancer, 210 + + Common peroneal nerve, 370 + + Compound palmar ganglion, 217, 423 + + Condylomata, 158, 174 + + Congenital fistulas, 60 + telangiectasis, 294 + + Connective tissue, repair of, 6 + + Contracture of joints, 502 + of muscles, 415 + paralytic, 347 + + Contusions, 218 + + Cornea, syphilitic ulceration of, 177 + + Corns, 377 + + Corpora oryzoidea, 539 + + Counter-irritants, 37, 42 + + Craniotabes, 175, 176, 465 + + Crural fibrositis, 413 + + Crutch paralysis, 351 + + Cupping dry, 39 + wet, 42 + + Cutis anserina, 36 + + Cyanosis, traumatic, 254 + + Cyst, 212 + atheromatous, 389 + Baker's, 539 + blood 214, 220 + of bone, 477, 500 + dentigerous, 193 + derma, 210 + exudation, 212 + ganglionic, 215 + haemorrhagic, 220 + hydatid, 213 + implantation, 212 + of joints, 538 + lymph, 214 + lymphatic, 219, 328 + omental, 329 + parasitic, 213 + retention, 212 + sebaceous, 212, 389 + serous, 219 + venous, 289 + + Cystic adenoma, 202 + carcinoma, 210 + hygroma of neck, 328 + lymphangioma, 327, 328 + + + Dactylitis, syphilitic, 176, 460, 466 + tuberculous, 460 + + Dancer's sprain, 406 + + Deafness, syphilitic, 178 + + Deformities. _See_ Individual Regions + + Delhi boil, 129 + + Delirium, in surgical patients, 255 + traumatic, 257 + + Delirium tremens, 256 + + Dentigerous cyst, 193 + + Dercum on adiposus dolorosa, 186 + + Derma-cysts, 210 + + Dermatitis, 239, 292 + + Dermoids, 210 + + Diabetic gangrene, 96 + + Diarsenol, 163 + + Diapedesis of red corpuscles, 32 + + Diaphysial aclasis, 483 + + Diffuse aneurysm, 302 + cellulitis, 52 + fibromatosis, 194 + lipomatosis, 187 + neuro-fibromatosis, 355 + osteoma, 485 + suppuration, 52 + + Diphtheria, 109 + antitoxin in, 111 + intubation in, 111 + + Diplococci, 19 + + Dislocation of nerves, 351, 369 + pathological, 514 + of tendons, 408 + + Double cyanide gauze, 247 + + Drainage of wounds, 222 + + Dressings, surgical, 247 + + Drill-bone, 418 + + Drop-finger, 411 + -foot, 370 + -wrist, 365 + + Drunkard's palsy, 351, 364 + + Duchenne's paralysis, 361 + + Ducrey's bacillus, 154 + + Duodenum, ulceration of, in burns, 236 + + Dwarf, rickety, 469 + syphilitic, 178 + + + Eburnation of articular surfaces, 557 + + Ecchondroses, 527 + + Ecchymosis, 218 + + Echinococcus, 213 + + Echthyma, 158 + + Eczema, varicose, 292 + + Elbow, angler's, 406 + cellulitis of, 58 + tennis, 406 + + Electricity, injuries by, 239 + + Electrolysis in angioma, 297 + + Elephantiasis, varieties of, 360, 384, 386 + + Embolism, 281 + air, 265 + + Embolism, fat, 254 + of individual arteries, 93 + + Embolus, 281 + + Emigration of leucocytes, 32 + + Emotional shock, 251 + + Emphysema, 99, 102 + + Emprosthotonos, 214 + + Empyema of joints, 501, 518 + + Encephaloid cancer, 210 + + Endarteritis obliterans, 282 + syphilitic, 161 + + Endo-aneurysmorrhaphy, 307 + + Endothelioma, 196 + of bone, 492 + + Epicritic sensibility of nerves, 343 + + Epidermis, grafting, 12 + repair of, 4 + + Epiphysial cartilage, 434 + junction, 434 + in rickets, 469 + + Epiphysiolysis, 440 + + Epiphysitis, 437 + syphilitic, 465 + + Epithelial tumours, 201 + + Epithelioma, 208 + chimney-sweep's, 395 + lupus, 384 + paraffin, 395 + in scars, 402 + sinus, 500 + of skin, 394 + trade, 395 + varieties of, 208 + X-ray, 395 + + Epithelium grafting, 12 + repair of, 6 + + Epulis, 491 + + Erb's paralysis, 361 + + Erysipelas, varieties of, 107 + + Erythema pernio, 378 + nodosum, 442 + + Evaporating lotions, 41 + + Exfoliation, 438 + + Exophthalmos, pulsating, 317 + + Exostosis, 191, 481 + bursata, 481 + cancellous, 481 + cartilaginous, 191, 481 + false, 192 + ivory, 481 + multiple, 483 + spongy, 191, 481 + subungual, 191, 404, 481 + + Explosives, wounds by, 231 + + External iliac artery, embolus of, 93 + + External popliteal nerve. _See_ Common Peroneal Nerve + + Extravasation of blood, 259 + + Exudates, varieties of, 33 + + Exudation cysts, 212 + + Eye, syphilitic lesions of, 160, 176, 177 + + + Facial artery, compression of, 269 + erysipelas, 107 + + Fainting, 249 + + Farcy, 125 + + Fascia, grafting of, 16 + + Fat embolism, 254 + grafting of, 16 + + Fatty hernia, 187 + tumours, 184 + + Feet, trench, 96 + + Femoral aneurysm, 318 + artery compression of, 269 + embolus of, 93 + lymph glands, 323 + + Fever, 35 + + Fibro-adenoma, 202 + + Fibroblasts, 3 + + Fibroid, recurrent, of Paget, 199, 392, 420 + uterine, 195 + + Fibroma, 194 + of bone, 491 + diffuse, 194 + recurrent, of Paget, 199, 392, 420 + of skin, 391 + varieties of, 194 + + Fibromatosis, diffuse, 194 + + Fibro-myoma, 195 + + Fibro-sarcoma, 199 + + Fibrositis, varieties of, 372, 412 + + Filaria Bancrofti, 326 + + Filarial disease, 326 + + Finger, chancre of, 154 + drop-, 411 + mallet-, 411 + + Fingers, gouty affections of, 523 + whitlow of, 55 + + Finsen light treatment, 138 + + Firearms, wounds by, 225, 227, 230 + + First intention, healing by, 2 + + Fistula, 60 + congenital, 60 + lymphatic, 325 + varieties of, 60 + + Fluctuation, 49 + + Fomentations, 37, 41 + + Foot, cellulitis of, 58 + drop-, 370 + Madura, 129 + perforating ulcer of, 73 + + Forci-pressure in haemorrhage, 271 + + Forearm, aneurysm of, 318 + cellulitis of, 58 + + Foreign bodies, embedded, 6, 231 + + Fracture, pathological, 444 + + Fraenkel's pneumococcus, 28 + + Fragilitas ossium, 479 + + Friedlander's pneumo-bacillus, 28 + + Frost-bite, gangrene from, 95 + + Furunculus orientalis, 129 + + + Galyl, 163 + + Ganglion, 214, 215, 217 + compound palmar, 217, 423 + + Ganglionic neuroma, 353 + + Gangrene, 86 + acute infective, 99 + emphysematous, 102 + from angio-sclerosis, 98 + bacterial varieties of, 99 + from burns and scalds, 95 + cancrum oris, 102 + carbolic, 95 + from chemical agents, 95 + clinical types of, 86 + varieties of, 88 + from constriction of vessels, 94 + diabetic, 96 + dry, 86 + embolic, 92 + from ergot, 98 + from frost-bite, 95 + gas, 102 + from interference with circulation, 86 + following ligation of arteries, 94 + line of demarcation in, 87 + malignant oedema, 101 + moist, 87 + noma, 102 + phagedaena, 153 + Raynaud's disease, 97 + senile, 88 + traumatic, 94 + from trench feet, 96 + white, 93 + from whitlow, 99 + + Gas gangrene, 102 + + Gasserian ganglion, removal of, 375 + + Gauze, varieties of, 247 + + Gauze, sterilisation of, 245 + + Gelatin, injection of, in aneurysm, 309 + in haemophilia, 280 + + Gelatinous degeneration of joints, 515 + + Giant cells, 3 + + Glanders, 123 + + Glands, lymph. _See_ Lymph Glands + + Glioma, 196 + + Gliomatous arthropathies, 534 + + Glio-sarcoma, 200 + + Gloves in surgery, 244 + + Gluteal aneurysm, 319 + fibrositis, 372, 413 + + Glycogen reaction, 30 + + Glycosuria in perforating ulcer, 73 + + Golfer's back, 405 + + Gonorrhoeal bursitis, 428 + joint lesions, 510 + lymphangitis, 325 + myositis, 416 + ophthalmia, joint lesions following, 510 + rheumatism, 510 + teno-synovitis, 423 + + Gout, joint affections in, 522 + + Gouty bursitis, 428 + joints, 522 + teno-synovitis, 422 + tophi, 523 + ulcers, 77 + + Grafting of bone, 436 + of epithelium, 12 + of mucous membrane, 16 + of skin, 11 + of tissues, 10 + + Granulation, healing by, 5 + tissue, formation of, 2 + syphilitic, 146 + tuberculous, 136 + + Granulations, 2 + + Granuloma, 42 + + Groin, cellulitis of, 59 + filarial disease in lymphatics of, 326 + + Growing pains, 451 + + Growth fever, 451 + + Gumma, 168 + of bone, 464 + peri-bursal, 521 + periosteal, 521 + peri-synovial, 521 + subcutaneous, 76 + syphilitic, 168 + + Gummatous infiltration, 168 + + Gunshot wounds, 225, 227, 230 + + + Haematemesis, 259 + post-operative, 275 + + Haematoma, 220 + bursal, 426 + pulsating, of bone, 498 + + Haematuria, 259 + + Haemophilia, 277 + + Haemophilic joint, 531 + + Haemoptysis, 259 + + Haemorrhage, 266 + arrest of, 266, 270, 272, 274 + arterial, 259 + capillary, 260 + cautery in, 271 + constitutional effects of, 275 + digital compression in, 269 + external, 259 + forci-pressure in, 271 + intermediate, 272 + internal, 259 + ligature in, 270 + in operations, 269 + prevention of, 269 + primary, 266 + reactionary, 272 + saline infusions in, 276 + secondary, 273 + styptics in, 271 + torsion in, 271 + tourniquets in, 270, 272 + toxic, 275 + from varicose veins, 292 + venous, 259 + + Haemorrhagic diathesis, 277 + + Haemostatics, 271 + + Hair, syphilitic lesions of, 159 + + Hand, claw-, 369 + + Hands, disinfection of, 244 + + Hard chancre, 151 + + Healing by blood-clot, 6 + by first intention, 2 + by granulation, 5 + by primary union, 2 + rate of, 9 + under scab, 6 + by second intention, 5 + sore, 69, 81 + ulcer, 77 + by union of granulating surfaces, 5 + + Heart, massage of, 265 + + Heberden's nodes, 529 + + Hectic fever, 62 + + Heliotherapy, 139 + + Hernia, fatty, 187 + of muscle, 408 + + Herpes, syphilitic, 156 + + Hilton's method of opening abscess, 50 + + Hodgkin's disease, 377 + + Horns, varieties of, 389, 391 + + Housemaid's knee, 426, 431 + + Hunter's operation for aneurysm, 307 + + Hutchinson's teeth, 177 + + Hydatid cysts, 213 + of bone, 467 + of muscle, 421 + thrill, 214 + + Hydrocele of neck, 328 + + Hydrophobia, 115, 118 + + Hydrops, 501, 518 + + Hygroma of axilla, 328 + bursal, 427 + of neck, 328 + + Hyperaemia, 32 + active, 39 + artificial, 36 + passive, 38 + in tuberculosis, 138 + + Hyperostosis, 435 + syphilitic, 464 + + Hypertrophic pulmonary osteo-arthropathy, 480 + + Hysterical joint affections, 537 + + + Ice-bags, 41 + + Ichthyma, syphilitic, 158 + + Igni-puncture in naevus, 297 + + Iliac aneurysm, 318 + + Immunity, 22 + + Imperial drink, 40 + + Implantation cysts, 212 + + Infantile scurvy, 473 + + Infection, accidental, 241 + by catgut, 51 + mixed, 20 + prevention of, 243 + of wounds, 241 + + Inflammation, 31 + changes in, 32 + chronic, 42 + clinical aspects of, 33 + constitutional disturbance in, 35 + general principles of treatment in, 36, 39 + + Inflammation, leucocytosis in, 36 + stages of, 32 + + Infusion of saline solution, 276 + + Ingrowing toe-nail, 403 + + Inguinal aneurysm, 318 + lymph glands, 323 + + Injuries, 218. _See also_ Individual Tissues and Regions + constitutional effects of, 249 + + Innominate aneurysm, 314 + + Inoculation tubercle, 382 + + Insects, poisoning by, 130 + + Instruments, sterilisation of, 245 + + Intercostal fibrositis, 413 + + Intermittent claudication of vessels, 98 + + Internal popliteal nerve. _See_ Tibial Nerve + + Interstitial keratitis, 177 + + Intestine, repair of, 9 + + Intoxication, bacterial, 21 + + Intracranial aneurysm, 316 + + Intra-cystic growths, 202 + + Intubation of larynx, 111 + + Involucrum, 443 + + Iodine, catgut, 246 + for disinfection of skin, 245 + reaction, 30 + + Iodoform gauze, 247 + injection of, 142 + in joint diseases, 519 + + Iritis, syphilitic, 160 + + Irrigation, continuous, 54 + + Irritable ulcers, 79 + + Ischaemic contracture of muscles, 415 + + Ischial bursa, 430 + + Ischias scoliotica, 372 + + Ivory exostosis, 481 + + + Jaws, actinomycosis of, 127 + changes in, in rickets, 470 + cystic tumours of, 193 + + Jigger, 130 + + Joints. _See also_ Individual Joints + ankylosis of, 503 + bacterial diseases of, 506 + bleeder's, 531 + Charcot's disease of, 533 + chondromata, multiple, of, 544 + contracture of, 502 + cysts of, 538 + developmental errors of, 505 + diseases of, general, 501, 506 + disorganisation of, 502 + empyema of, 501 + gelatinous degeneration of, 515 + gliomatous arthropathies, 534 + gonococcal affections of, 510 + gouty affections of, 522 + haemophilic, 531 + hydrops of, 501 + hysterical affections of, 537 + impaired mobility of, 502 + iodoform in diseases of, 519 + loose bodies in, 529, 539 + mimetic affections of, 537 + nerve lesions affecting, 532 + neuro-arthropathies, 532 + osteo-arthritis, 524 + pneumococcal infection of, 509 + pyaemic affections of, 508 + pyogenic diseases of, 506 + rheumatic affections of, 523, 524 + rigidity of, 502 + scarlet fever, infection of, in 508 + spinal diseases affecting, 532 + starting pains in, 502, 517 + synostosis, 503 + syphilitic diseases of, 521 + tuberculous diseases of, 512 + tumours of, 538 + typhoid infection of, 508 + white swelling of, 515, 518 + + Jumper's sprain, 406 + + + Keloid, 194, 401 + + Keratitis, interstitial, in syphilis, 177 + + Keratoma of nail bed, 391 + + Kharsivan, 163 + + Klapp's suction bells, 39 + + Klebs-Loffler bacillus, 109 + + Klumpke's paralysis, 361 + + Knee, cellulitis of, 58 + ganglion of, 215 + housemaid's, 426, 431 + + Kopf or cephalic tetanus, 116 + + Kyphosis, 471 + + + Labourer's back, 405 + + Larynx, syphilis of, 177 + + Leeches, 41 + + Leg ulcer, 72 + varicose veins of, 287 + + Leiter's lead tubes, 41 + + Leontiasis ossea, 485 + + Leucocytes, emigration of, 32 + varieties of, 29 + wandering, 3 + + Leucocythaemia, 340 + + Leucocytosis, 22, 29 + absence of, 30 + digestion, 30 + after haemorrhage, 30 + local, 32 + physiological, 29, 30 + post-operative, 30 + + Leucopenia, 30 + + Leucoplakia, 167 + + Lightning stroke, 240 + + Line of demarcation in gangrene, 87 + + Lingual dermoids, 211 + + Lipoma, 184 + arborescent, 423 + of bone, 187, 491 + diffuse, 187 + intra-muscular, 188 + multiple, 186 + nasi, 393 + periosteal, 187 + subcutaneous, 184, 186 + subserous, 187 + subsynovial, 187 + + Lipomatosis, diffuse, 187 + + Lipping of bone, 527 + + Liquor epispasticus, 42 + puris, 45 + + Listerian methods of wound treatment, 242 + + Locking of joints, 505 + + Lock-jaw, 113 + + Locomotor ataxia, joint lesions in, 532 + + Long thoracic nerve, injuries of, 363 + + Loose bodies in bursae, 427 + in joints, 529, 539 + in tendon sheaths, 423 + varieties of, 539 + + Lotion, evaporating, 41 + + Luargol, 163 + + Luetin, 149 + + Lumbago, 412 + + Lumbo-sacral fibrositis, 412 + + Lupus, 134, 382 + epithelioma, 384 + syphilitic, 169 + tuberculous, 382 + varieties of, 383, 393 + + Lymph, 321 + cysts, 214 + glands, cancer of, 340 + diseases of, 329 + functions of, 221 + sarcoma of, 341 + surgical anatomy of, 321 + syphilitic diseases of, 337 + tuberculosis of, 331 + tumours of, 340 + oedema, 325 + scrotum, 389 + vessels, diseases of, 325 + injuries of, 323 + + Lymphadenitis, 53, 329 + + Lymphadenoma, 337 + + Lymphangiectasis, 214, 326 + + Lymphangioma, varieties of, 327 + + Lymphangioplasty, 325, 386 + + Lymphangio-sarcoma, 199 + + Lymphangitis, 325 + septic, 53 + varieties of, 325 + + Lymphatic cyst, 328 + fistula, 324 + oedema, 325 + + Lymphatics, 321 + + Lymphocytosis, 29 + + Lymphorrhagia, 323 + + Lympho-sarcoma, 199, 340 + + + Macewen's method of compressing abdominal aorta, 269 + + Macrophages, 22 + + Madura foot, 129 + _Main en griffe_, 369 + + Malacia of bones, 473 + + Malignant adenoma, 209 + cachexia, 207 + oedema, 101 + pustule, 120 + tumours, 183 + ulcers, 77 + + Mallein test, 125 + + Mallet-finger, 411 + + Malum senile, 524 + + Marriage and syphilis, 167 + + Matas' operation for aneurysm, 307 + + Median nerve, lesions of, 367 + + Medullary cancer, 210 + + Melaena, 259 + + Melanotic cancer, 210, 397 + sarcoma, 200 + + Melon-seed bodies, 539 + + Meningitis, basal, 115 + cerebro-spinal, 115 + + Mercury in syphilis, administration of, 165 + + Metchnikoff's cream, 157 + + Michel's clips, 222 + + Micrococci, 18 + + Micrococcus tetragenus, 29 + + Micro-organisms, 18 + + Microphages, 22 + + Mimetic joint affections, 537 + + Miner's elbow, 426 + + Mitchell's operation for varicose veins, 294 + + Mixed infection, 20 + naevus, 295 + venereal infection, 156 + + Moist gangrene, 87 + + Moles, 390 + naevoid, 295 + + Molluscum fibrosum, 194, 359, 391 + + Moore-Corradi method of treating aneurysm, 308 + + Mosetig-Moorhof on filling of bone cavities, 447 + + Mother's mark, 294 + + Muco-pus, 52 + + Mucous membrane, grafting of, 16 + suppuration in, 51 + patches, 160, 174 + + Multilocular cystic tumours of jaw, 193 + + Mummification, 86 + + Muscle, affections of, 405 + atrophy of, 412 + calcification of, 416 + congenital absence of, 411 + contracture of, 415 + contusion of, 405 + diseases of, 411 + gonorrhoea of, 416 + grafting of, 16 + hernia of, 408 + hydatid cysts of, 421 + inflammation of, 415 + injuries of, 405 + ossification in, 416 + repair of, 8 + rheumatism of, 412 + rupture of, 405, 406 + sprain of, 405 + syphilis of, 416 + tuberculosis of, 416 + tumours of, 420 + wounds of, 409 + + Muscular rheumatism, 412 + + Musculo-cutaneous nerve, 364 + + Musculo-spiral nerve. _See_ Radial Nerve + + Mustard leaves, 42 + + Mycetoma, 129 + + Myelitis, syphilitic, 161 + + Myeloma, 195, 491 + of bone, 491 + of tendon sheaths, 424 + + Myoma, 195 + + Myo-sarcoma, 200 + + Myositis ossificans, 416, 418 + varieties of, 415 + + Myxo-adenoma, 202 + + Myxoma, 194 + of bone, 491 + + Myxo-sarcoma, 200 + + + Naevoid mole, 295 + + Naevus, 294 + electrolysis of, 297 + operations for, 298 + radium treatment of, 297 + varieties of, 294 + + Nail fold, whitlow of, 56 + horns, 391 + + Nails, affections of, 402 + ingrowing, 403 + regeneration of, 7 + syphilitic lesions of, 159, 402 + + Nasal bones, syphilitic disease of, 188, 462 + + Naso-pharyngeal polypus, 491 + + Natal sore, 129 + + Neck, cystic hygroma of, 328 + glands of, diseases, 332 + hydrocele of, 328 + lipomatosis of, 187 + painful stiff-, 413 + + Necrosis, acute, 439 + of bone, 438 + quiet, of Paget, 452 + syphilitic, 462 + + Neo-diarsenol, 163 + -kharsivan, 163 + -salvarsan, 163 + + Neoplasms, 181 + + Nerve of Bell. _See_ Long Thoracic Nerve + + Nerves, 342. _See also_ Individual Nerves + alcohol injections of, 374 + anatomy of, 342 + avulsion of, 375 + blocking of, 251, 252 + bullet wounds of, 346 + contusion of, 345 + crushing of, 345 + diseases of, 352 + dislocation of, 351, 369 + effects of division of, 344 + gun-shot wounds of, 346 + grafting of, 16 + implicated in scar tissue, 345 + individual, surgery of, 360 + injuries of, 344 + joint affections in lesions of, 532 + reaction of degeneration, 347 + regeneration of, 9, 346 + in scar tissue, 345 + sensibility, forms of, 343 + subcutaneous injuries of, 350 + suture of, primary, 348 + secondary, 349 + Tinel's sign, 349 + torn, 345 + tumours of, 353 + ulcers in lesions of, 73, 82 + + Neuralgia, varieties of, 371 + + Neurectomy, 375 + + Neuritis, multiple peripheral, varieties of, 352 + traumatic, 352 + + Neuro-arthropathies, 352. _See also_ Individual Joints + + Neuro-fibromatosis, 355, 359 + + Neurolysis, 345 + + Neuroma, stump, 344 + varieties of, 353 + "914," 613 + + Nodes, periosteal, 464 + Heberden's 529 + + Noma, 102 + + Nose, sebaceous adenoma of, 393 + + Novo-arseno-billon, 163 + + Nucleinate of soda, 29 + + + Odontoma, 192 + varieties of, 193 + + O'Dwyer's intubation apparatus, 111 + + Oedema, 32, 34 + angio-neurotic, 348 + lymphatic, 325 + malignant, 101 + persistent, 109 + + Olecranon bursa, 428 + + Omental cyst, 329 + + Onychia, varieties of, 402 + + Operations during shock, 252 + + Opisthotonos, 114 + + Opsonins, 22 + + Orbital aneurysm, 317 + + Orthotonos, 114 + + Ossification in muscles, tendons, and fasciae, 416 + + Ossifying junction, 434 + + Osteo-arthritis, 524 + syphilitic, 522 + + Osteo-arthropathy, pulmonary, 480 + + Osteochondritis dessicans, 544 + + Osteogenesis imperfecta, 479 + + Osteoid sarcoma, 200 + + Osteoma, 191, 481 + cancellous, 191 + compact, 192 + diffuse, 485 + ivory, 192 + multiple, 544 + in muscles and tendons, 416 + spongy, 191 + subungual, 191, 404, 481 + + Osteomalacia, varieties of, 473 + + Osteomyelitis, 65, 437 + acute, 65, 438, 451, 453 + after amputation, 453 + bipolar, 439 + fibrosa, 476 + gummatous, 462 + from infection from soft parts, 453 + pyogenic, 438 + relapsing, 448 + sequelae of, 443 + streptococcal, 451 + tuberculous, 456, 458 + in typhoid fever, 452 + + Osteophytes, 435 + + Osteoporosis, 437 + + Osteopsathyrosis, 479 + + Osteosarcoma, 200 + + Osteosclerosis, 435 + + Ostitis deformans, 474 + rarefying, 474 + + Ovarian dermoids, 211 + + Ovary, grafting of, 16 + + Ozoena, 176 + + + Pachydermatocele, 360 + + Paget's disease of bone, 474 + of nipple, 397 + recurrent fibroma, 199, 392, 420 + + Pain, starting, in joint disease, 502, 517 + varieties of, 35 + + Painful subcutaneous nodules, 354, 392 + + Palate, syphilitic lesions of, 178, 462 + + Palmar ganglion, compound, 217, 423 + + Papilloma, varieties of, 201, 392 + + Paraffin cancer, 395 + + Paralysis, brachial birth, 362 + Erb-Duchenne, 361 + Klumpke's, 361 + post-anaesthetic, 360 + pseudo, of syphilis, 174, 466 + + Parasitic bacteria, 20 + cysts, 213 + + Paronychia. _See_ Onychia + + Parotid abscess in pyaemia, 66 + lymph glands, 321 + tumours, 195 + + Parotitis, 66 + + Parrot's nodes, 175, 465 + + Passive hyperaemia, Bier's, 38 + + Pasteur's treatment for hydrophobia, 119 + + Pelvis, rickety changes in, 471 + + Perforating ulcer, 73, 82 + + Perichondritis, syphilitic, 465 + + Peri-lymphangitis, 325 + + Periosteum, function of, 434 + gumma of, 464 + in rickets, 469 + + Periostitis, 437. _See also_ Osteomyelitis + syphilitic, 461 + tuberculous, 455 + + Peripheral neuritis, 352 + + Peroneal nerve, 370 + + Peronei tendons, dislocation of, 409 + + Petrifying sarcoma, 200 + + Phagedaena, 153 + + Phagedaenic ulcers, 80, 85 + + Phagocytes, 3, 22 + + Phagocytosis, 22 + + Phimosis, with hard chancre, 152 + with soft sores, 155 + + Phlebitis, 285, 292 + + Phlegmasia alba dolens, 286 + + Picric acid, 13, 237 + + Pigeon-breast, 471 + + Plantaris, rupture of, 408 + + Pleurodynia, 413 + + Pleurosthotonos, 114 + + Pneumo-bacillus, Friedlander's bacteria, 28 + + Pneumococcal arthritis, 509 + + Pneumococcus, 28 + + Polypi, 195 + + Popliteal aneurysm, 320 + artery, embolus of, 93 + bursae, 432 + + lymph glands, 323 + nerves. _See_ Common Peroneal Nerve and Tibial Nerve + + Port-wine stain, 294 + + Post-anaesthetic paralysis, 360 + -anal dimple, 211 + + Posterior auricular lymph glands, 322 + + Post-rectal dermoids, 211 + + Potato-nose, 393 + + Poultice, 37 + charcoal, 84 + + Pre-auricular lymph glands, 322 + + Prepatellar bursa, 431 + + Pressure sores, 70, 82 + + Primary union of wounds, 2 + + Protopathic sensibility of nerves, 343 + + Proud flesh, 79 + + Psammoma, 200 + + Pseudo-leucaemia, 337 + + Pseudo-paralysis of syphilis, 174, 466 + + Psoas bursa, 430 + + Pulmonary osteo-arthropathy, 480 + + Pulsating aorta, 305, 314 + exophthalmos, 317 + haematoma of bone, 498 + + Punctured wounds, 222 + + Purpura, 280 + + Purulent blister, 55 + + Pus, 45 + varieties of, 46 + + Pyaemia, 64 + abscess in joints in, 508 + + Pyogenic bacteria, 24, 29 + + + Quadriceps extensor femoris, rupture of, 408 + + + Rabies, 118 + + Rachitis, 468 + adolescentium, 472 + + Radial nerve, lesions of, 364 + + Radium, in lupus, 385 + in cancer, 208 + in naevus, 297 + ulceration from, 239 + + Ranula, 329 + + Rarefying ostitis, 437 + + Ray fungus, 126 + + Raynaud's disease, 97 + + Reaction of degeneration, 347 + + Reactionary haemorrhage, 272 + + Recklinghausen's disease, 355 + + Recurrent fibroid of Paget, 199, 392, 420 + + Repair. _See_ Individual Tissues + conditions interfering with, 17 + after loss of tissue, 4 + modifications of, 4 + of separated parts, 5 + + Rest, 17 + + Rests, foetal, 181 + + Retention cysts, 212 + + Retro-pharyngeal lymph glands, 322 + + Reverdin's method of skin-grafting, 13 + + Rhabdomyoma, 196 + + Rheumatic arthritis, 524 + fever, 509 + gout, 524 + torticollis, 413 + + Rheumatism, acute, 509 + chronic, 523 + gonorrhoeal, 510 + muscular, 412 + scarlatinal, 508 + + Rheumatoid arthritis, 524 + + Rhinophyma, 393 + + Rickets, 468 + bone lesions in, 469 + changes in skeleton in, 470 + late, 472 + scurvy, 473 + + Rickety, dwarf, 469 + pelvis, 471 + rosary, 469 + scoliosis, 471 + + Rider's bone, 418 + sprain, 407 + + Rigidity of joints, 502 + + Rigor, 36 + + Risus sardonicus, 114 + + Rodent cancer, 210, 395 + ulcer, 210, 395 + + Rontgen rays. _See_ X-rays + + Rose or erysipelas, 107 + + Roseola, syphilitic, 158 + + Rupia, syphilitic, 158 + + + Sabre-blade deformity of tibia, 466 + + Sacculated aneurysm, 302 + + Saddle-nose deformity, 174 + + Saline infusions in haemorrhage, 276 + + Salvarsan in syphilis, 162 + + Sapraemia, 60 + chronic, 62 + + Saprophytic bacteria, 20 + + Sarcoma, 197 + of bone, 492 + inoperable, 201 + of joints, 538 + of lymph glands, 341 + melanotic, 200 + periosteal, 493 + of skin, 398 + of synovial membrane, 538 + of tendon sheaths, 424 + varieties, 199 + + Scab, healing under, 6 + + Scalds, 233 + + Scapula, winged, 363 + + Scarlet fever, joint lesions in, 508 + + Scars. _See_ Cicatrices + + Sciatic nerve, lesions of, 370 + + Sciatica, 371 + + Scirrhous cancer, 210 + + Sclavo's serum, 123 + + Scoliosis, rickety, 471 + in sciatica, 372 + + Scorbutic ulcers, 77 + + Scrotum, elephantiasis of, 389 + + Sculler's sprain, 406 + + Scurvy, 473 + rickets, 473 + + Sebaceous adenoma, 393 + cysts, 389 + horns, 389 + + Secondary haemorrhage, 273 + syphilis, 151, 147 + + Selenium in malignant tumours, 201, 208 + + Semilunar ganglion, 375 + + Semi-membranosus bursa, 432 + + Sepsis, 18 + + Septicaemia, 53, 63 + + Sequestrectomy, 446 + + Sequestrum of bone, 438 + + Serratus anterior muscle, paralysis of, 363 + + Serum, anti-diphtheritic, 109 + anti-bacterial, 23 + anti-tetanic, 117 + disease, 23 + in haemophilia, 280 + polyvalent, 23 + Sclavo's, for anthrax, 123 + treatment, 23 + + Seton, 217 + + Shell wounds, 231 + + Shock, 250 + delayed, 252 + + Shoulder, fibrositis of, 413 + + Sinus, 59 + epithelioma, 500 + tuberculous, 143 + + "606," 162 + + Skewers for prevention of haemorrhage, 270 + + Skin, 376 + abscesses of, 382 + actinomycosis of, 126 + cancer of, 394, 398 + dermoids, 210 + grafting of, 11, 14 + preparation of, for operation, 244 + repair of, 6 + sporotrichosis of, 385 + structure of, 376 + syphilitic lesions of, 157, 166 + tuberculosis of, 382, 385 + tumours of, 391 + + Skull, bossing of, 465 + craniotabes of, 175, 176, 465 + diffuse osteoma of, 485 + natiform, 176 + Parrot's nodes, 465 + syphilitic disease of, 462 + unilateral hypertrophy of, 487 + + Slough, 86 + + Snake-bites, 131 + + Snuffles, 173 + + Soft chancre, 154 + corns, 377 + sore, 154 + + Spas, 531 + + Spasmodic tic, 373 + + Sphagnum moss, 247 + + Spinal arthropathies, 532 + cord, joint affections in lesions of, 532 + repair of, 9 + syphilis of, 161 + + Spine, changes in rickets, 471 + + Spirilla, 19 + + Spirochaete pallida, 147 + + Spironema pallidum, 147 + + Splenic fever, 119 + + Spores, 18 + + Sporotrichosis, 385 + + Sprain of muscle, 405, 407 + + Sprinter's sprain, 406 + + Staphylococci, 19, 24, 438 + + Staphylococcus albus, 26 + aureus, 25 + + Starting pains in joints, 502, 517 + + Stasis, 32 + + Sterilisation, surgical, 243 + + Sterno-mastoid lymph glands, 322 + + Stitch abscess, 51 + + Stitches. _See_ Sutures + + Streptococci, 19, 24 + + Streptococcus pyogenes, 26 + + Streptothrix actinomyces, 126 + + Strychnin poisoning, 115 + + Stump neuroma, 344 + + Styptics, 271 + + Sub-acromial bursa, 429 + + Sub-calcanean bursa, 433 + + Subclavian aneurysm, 317 + + Sub-crural bursa, 430 + + Sub-deltoid bursa, 429 + + Submaxillary lymph glands, 322 + + Submental lymph glands, 322 + + Sub-patellar bursa, 431 + + Subscapularis bursa, 430 + + Subungual exostosis, 191, 404, 481 + + Suction bells, 39 + + Suppuration, 45 + chronic, 59 + diffuse, 52 + in mucous membranes, 52 + in wounds, 50 + + Supra-clavicular lymph glands, 322 + + Supra-hyoid lymph glands, 322 + + Supra-scapular nerve, lesions of, 364 + + Surgery, definition of, 1 + Listerian, 242 + + Surgical anatomy of blood vessels, 258 + of bone, 434 + of epiphyses, 434 + of lymphatics, 321 + of nerves, 342 + of skin, 376 + + Surgical bacteriology, 17, 18 + shock, 250 + + Sutures, 221 + sterilisation of, 245 + + Sweat-glands, tumours of, 393 + + Syncope, 249 + local, 97 + + Synostosis, 503 + + Synovial membrane, tumours of, 538 + + Synovitis, 501, 506 + gonococcal, 510 + septic, 506 + serous, 506, 507 + suppurative, 507 + syphilitic, 521 + + Syphilis, 147. _See also_ Individual Tissues and Organs + + Syphilis, acquired, 146, 149 + in infants, 179 + arsenical preparations in, 162 + arteritis in, 282 + bones, lesions in, 461, 465 + brain, lesions in, 161 + of bursae, 428 + cirrhosis in, 168 + Colles' law, 178 + contracture of muscle in, 416 + dactylitis in, 176, 460, 466 + epiphysitis of infants, 465 + extra-genital, 153 + in female, 152, 164 + gumma, 168, 462 + hydrops in, 521 + incubation of, 151 + in infants, 179 + inherited, 146, 172 + contagiousness of, 178 + diagnosis of, 178 + facies of, 174, 175 + lesions of bone in, 465 + eyes in, 176, 177 + joints in, 522 + skin in, 173, 174 + teeth in, 177 + treatment of, 179 + insontium, 153 + intermediate stage of, 167 + interstitial keratitis in, 177 + iodides in, 171 + iritis in, 166 + joint lesions in, 521 + of larynx, 177 + lupus, 169 + lymphadenitis, 153, 337 + lymphangitis, 326 + in male, 152 + malignant, 161 + and marriage, 167 + mercury in, 164 + mixed infection, 156 + of mouth, 166 + of mucous membranes, 160, 173, 174 + mucous patches, 160, 174 + of muscle, 416 + of nails, 159 + of nose, 188 + onychia in, 403 + osteo-arthritis, 522 + of palate, 178, 462 + phagedaena, 153 + phimosis in, 152 + in pregnant women, 164 + primary, 151 + diagnosis of, 155 + lesion of, 146, 151 + treatment of, 163 + prophylaxis of, 149 + pseudo-paralysis of, 174, 466 + reminders, 167 + second attacks of, 172 + secondary, 151, 157 + diagnosis of, 161 + lesions of eye in, 160 + hair in, 159 + nails in, 159, 402 + skin in, 162 + treatment of, 162 + serum diagnosis, 149 + skin affections in, 157, 166 + skull, lesions of, 462 + spirochaete pallida in, 147 + stages of, 150 + stomatitis, 174 + synovitis, 521 + teeth in, 177 + of tendon sheaths, 424 + tertiary, 151, 167 + diagnosis of, 167 + general manifestations of, 167 + lesions of mucous membrane in, 171 + skin in, 168, 169 + treatment of, 171 + ulcer, 169 + ulcers in, 76, 83, 169 + virus of, 147 + Wassermann reaction in, 156 + + Syphiloma, 168 + + Syringomyelia, joint lesions in, 534 + + + Tabes dorsales, joint lesions in, 532 + + Taenia echinococcus, 213 + + Tailor's ankle, 432 + + Tailor's bottom, 426, 430 + + Tarsal ganglion, 215 + + Tarsus, tuberculosis of, 459 + + Teeth in inherited syphilis, 177 + + Telangiectasis, congenital, 294 + + Temperature in surgical diseases, 35, 40 + + Temporal artery, compression of, 269 + + Tenderness, 34 + + Tendinitis, 416 + + Tendon sheaths, affections of, 421 + syphilitic affections of, 424 + tuberculosis of, 423, 424 + tumours of, 424 + whitlow of, 57 + + Tendons. _See also_ Individual Tendons + avulsion of, 411 + calcification in, 416 + diseases of, 411 + dislocation of, 408 + ganglion of, 217 + grafting of, 16 + inflammation of, 416 + ossification of, 416 + repair of, 8 + rupture of, 406, 408 + tumours of, 420 + wounds of, 409 + + Tennis-player's elbow, 406 + + Teno-synovitis, varieties of, 421 + + Teratoma, 212 + + Tertiary syphilis, 151, 167 + + Tetanus, varieties of, 112 + + Tetany, 116 + + Thiersch's method of skin-grafting, 12 + + Thirst, treatment of, 40 + + Thoracic aneurysm, 312 + duct, subcutaneous rupture of, 325 + surgical anatomy of, 324 + wounds of, 325 + + Thorax, rickety changes in, 469 + + Thrombo-phlebitis, 285 + + Thrombosis, 32, 281, 285, 292 + + Thyreoid gland, grafting of, 16 + secondary tumours derived from, 500 + + Tibia, sabre-blade deformity of, 466 + + Tibial nerve, lesions of, 371 + + Tic, spasmodic, 373 + + Tinel's sign, 349 + + Toe-nail, ingrowing, 403 + + Toes, gouty affections of, 522 + syphilitic dactylitis of, 176, 460, 466 + tuberculous dactylitis, 460 + + Tomato tumour, 393 + + Tophi, gouty, 523 + + Torsion of blood vessels, 271 + + Torticollis, rheumatic, 413 + + Tourniquet, varieties of, 270, 272 + + Toxaemia, 21 + + Toxins, 21, 33 + + Tracheal tug in aneurysm, 312 + + Tracheotomy, 111 + + Trade arthritis, 525 + bursitis, 426 + epithelionia, 395 + + Transfusion of blood, 276 + + Transplantation of tissues, 10 + + Trench feet, 96 + + Trendelenburg's operation for varicose veins, 293 + + Treponema pallidum, 147 + + Trifacial neuralgia, 373 + + Trigeminal neuralgia, 373 + + Trismus, 117 + + Trochanteric bursa, 430 + + Trophic changes after nerve injuries, 348 + ulcer, 73 + + Tropical elephantiasis, 386 + + Trunk neuroma, 354 + + Tubercle, anatomical, 134 + bacillus, 133 + + Tuberculin, 138 + + Tuberculosis, 133. _See also_ Individual Tissues and Organs + bacillus of, 133 + of bone, 454, 456, 458 + bovine, 136 + of bursae, 428 + calcification in, 136 + caseation in, 136 + general, 135 + human, 136 + of joints, 512 + of lymph glands, 331 + of lymph vessels, 326 + modes of infection, 136 + of muscle, 416 + of nails, 403 + open-air treatment of, 137 + passive hyperaemia in, 138 + principles of treatment of, 137 + of skin, 382, 385 + of tendon sheaths, 423, 424 + trauma in causation of, 135 + vaccine treatment in, 138 + + Tuberculous abscess, 139 + arthritic fever, 516 + dactylitis, 460 + granulation tissue, 136 + lupus, 382 + lymphadenitis, 331 + lymphangitis, 326 + onychia, 403 + sinus, 143 + + Tuberculous ulcers, 73, 83 + + Tubulo-dermoids, 211 + + Tumor albus, 518 + + Tumours, 181. _See also_ Individual Tumours and Tissues + + Typhoid, joint lesions in, 508 + osteomyelitis in, 452 + + + Ulceration, of cartilage, 502, 514 + definition of, 68 + + Ulcers, 68 + ambulatory treatment of, 85 + Bazin's disease, 74, 169 + bone changes in, 79 + callous, 79, 84 + cancerous, 205 + classification of, 70 + clinical examination of, 68 + conditions of, 77 + crateriform, 395 + duodenal, in burns, 236 + epithelioma in, 500 + healing, 77 + gouty, 77 + due to imperfect circulation, 71, 82 + due to imperfect nerve-supply, 73, 82 + inflamed, 79, 85 + irritable, 79, 85 + leg, 72, 169 + malignant, 77 + perforating, 73, 82 + phagedaenic, 80, 85 + pressure, 70 + from radium, 70 + rodent, 395 + from Rontgen rays, 70 + scorbutic, 77 + skin-grafting, 14 + spreading, 79 + syphilitic, 76, 83, 158, 160, 169 + traumatic, 70, 81 + treatment of, 80 + trophic, 73 + tuberculous, 73, 83 + varicose, 72 + weak, 77, 83 + + Ulnar nerve, lesions of, 368 + + Uterine fibroids, 195 + + + Vaccine treatment, 23, 40 + + Varicose aneurysm, 311 + eczema, 292 + ulcer, 72 + veins, 287 + + Varix, 287 + + Veins, anatomy of, 258 + entrance of air into, 265 + injuries of, 264 + repair of, 269 + rupture of, 264 + thrombosis of, 281 + varicose, 287 + wounds of, 264 + + Veldt sores, 382 + + Venereal disease. _See_ Syphilis + soft sore, 154 + + Venesection, 42 + + Venous cysts, 289 + + Verruca, 392 + + Vibrion septique, 101 + + Villous papilloma, 201 + + Volkmann's ischaemic contracture, 415 + + Vulva, diphtheria of, 111 + + + Wardrop's operation for aneurysm, 308 + + Wart, 201, 392 + venereal, 393 + X-ray, 239 + + Wassermann's reaction, 156, 162 + + Weaver's bottom, 426, 430 + + Weir-Mitchell treatment in hysterical joint affections, 538 + + Wens, 389 + + Wet-cupping, 42 + + White swelling of joints, 515, 518 + + Whitlow, 55 + gangrene from, 99 + at nail fold, 56 + purulent blister, 55 + subcutaneous, 56 + subperiosteal, 58 + of tendon sheaths, 57 + thecal, 57 + + Whitlow, of toes, 55 + varieties of, 55 + + Winged scapula, 363 + + Wool-sorter's disease, 121 + + Wounds, 220. _See also_ Individual Tissues and Regions + acute suppuration in, 50 + bullet, 229 + contused, 218, 223 + drainage of, 222 + by electricity, 239 + by explosives, 231 + by firearms, 225, 227, 230 + incised, 221 + infection of, 107 + lacerated, 223 + open method of treating, 247, 248 + pistol-shot, 226 + punctured, 222 + shell, 231 + treatment, 241 + in warfare, 225, 230 + + Wrist, drop-, 365 + + Wry-neck, rheumatic, 413 + + + Xanthoma, 188 + + X-rays, burns by, 239 + cancer from, 395 + dermatitis from, 239 + ulcers from, 239 + warts from, 239 + in diagnosis of aneurysm, 304 + arthritis deformans, 530 + bone diseases, 445 + tumours, 485, 491, 496 + tuberculosis, 455 + foreign bodies, 233 + joint tuberculosis, 516 + in treatment of cancer, 208 + lupus, 385 + sarcoma, 201 + tuberculosis, 138 + + + + + +End of the Project Gutenberg EBook of Manual of Surgery, by +Alexis Thomson and Alexander Miles + +*** END OF THIS PROJECT GUTENBERG EBOOK MANUAL OF SURGERY *** + +***** This file should be named 17921-8.txt or 17921-8.zip ***** +This and all associated files of various formats will be found in: + http://www.gutenberg.org/1/7/9/2/17921/ + +Produced by Jonathan Ingram, Laura Wisewell and the Online +Distributed Proofreading Team at http://www.pgdp.net + + +Updated editions will replace the previous one--the old editions +will be renamed. + +Creating the works from public domain print editions means that no +one owns a United States copyright in these works, so the Foundation +(and you!) can copy and distribute it in the United States without +permission and without paying copyright royalties. Special rules, +set forth in the General Terms of Use part of this license, apply to +copying and distributing Project Gutenberg-tm electronic works to +protect the PROJECT GUTENBERG-tm concept and trademark. Project +Gutenberg is a registered trademark, and may not be used if you +charge for the eBooks, unless you receive specific permission. If you +do not charge anything for copies of this eBook, complying with the +rules is very easy. You may use this eBook for nearly any purpose +such as creation of derivative works, reports, performances and +research. They may be modified and printed and given away--you may do +practically ANYTHING with public domain eBooks. Redistribution is +subject to the trademark license, especially commercial +redistribution. + + + +*** START: FULL LICENSE *** + +THE FULL PROJECT GUTENBERG LICENSE +PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK + +To protect the Project Gutenberg-tm mission of promoting the free +distribution of electronic works, by using or distributing this work +(or any other work associated in any way with the phrase "Project +Gutenberg"), you agree to comply with all the terms of the Full Project +Gutenberg-tm License (available with this file or online at +http://gutenberg.org/license). + + +Section 1. General Terms of Use and Redistributing Project Gutenberg-tm +electronic works + +1.A. By reading or using any part of this Project Gutenberg-tm +electronic work, you indicate that you have read, understand, agree to +and accept all the terms of this license and intellectual property +(trademark/copyright) agreement. If you do not agree to abide by all +the terms of this agreement, you must cease using and return or destroy +all copies of Project Gutenberg-tm electronic works in your possession. +If you paid a fee for obtaining a copy of or access to a Project +Gutenberg-tm electronic work and you do not agree to be bound by the +terms of this agreement, you may obtain a refund from the person or +entity to whom you paid the fee as set forth in paragraph 1.E.8. + +1.B. "Project Gutenberg" is a registered trademark. It may only be +used on or associated in any way with an electronic work by people who +agree to be bound by the terms of this agreement. There are a few +things that you can do with most Project Gutenberg-tm electronic works +even without complying with the full terms of this agreement. See +paragraph 1.C below. There are a lot of things you can do with Project +Gutenberg-tm electronic works if you follow the terms of this agreement +and help preserve free future access to Project Gutenberg-tm electronic +works. See paragraph 1.E below. + +1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation" +or PGLAF), owns a compilation copyright in the collection of Project +Gutenberg-tm electronic works. Nearly all the individual works in the +collection are in the public domain in the United States. If an +individual work is in the public domain in the United States and you are +located in the United States, we do not claim a right to prevent you from +copying, distributing, performing, displaying or creating derivative +works based on the work as long as all references to Project Gutenberg +are removed. Of course, we hope that you will support the Project +Gutenberg-tm mission of promoting free access to electronic works by +freely sharing Project Gutenberg-tm works in compliance with the terms of +this agreement for keeping the Project Gutenberg-tm name associated with +the work. You can easily comply with the terms of this agreement by +keeping this work in the same format with its attached full Project +Gutenberg-tm License when you share it without charge with others. + +1.D. The copyright laws of the place where you are located also govern +what you can do with this work. Copyright laws in most countries are in +a constant state of change. If you are outside the United States, check +the laws of your country in addition to the terms of this agreement +before downloading, copying, displaying, performing, distributing or +creating derivative works based on this work or any other Project +Gutenberg-tm work. The Foundation makes no representations concerning +the copyright status of any work in any country outside the United +States. + +1.E. Unless you have removed all references to Project Gutenberg: + +1.E.1. The following sentence, with active links to, or other immediate +access to, the full Project Gutenberg-tm License must appear prominently +whenever any copy of a Project Gutenberg-tm work (any work on which the +phrase "Project Gutenberg" appears, or with which the phrase "Project +Gutenberg" is associated) is accessed, displayed, performed, viewed, +copied or distributed: + +This eBook is for the use of anyone anywhere at no cost and with +almost no restrictions whatsoever. You may copy it, give it away or +re-use it under the terms of the Project Gutenberg License included +with this eBook or online at www.gutenberg.org + +1.E.2. If an individual Project Gutenberg-tm electronic work is derived +from the public domain (does not contain a notice indicating that it is +posted with permission of the copyright holder), the work can be copied +and distributed to anyone in the United States without paying any fees +or charges. If you are redistributing or providing access to a work +with the phrase "Project Gutenberg" associated with or appearing on the +work, you must comply either with the requirements of paragraphs 1.E.1 +through 1.E.7 or obtain permission for the use of the work and the +Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or +1.E.9. + +1.E.3. If an individual Project Gutenberg-tm electronic work is posted +with the permission of the copyright holder, your use and distribution +must comply with both paragraphs 1.E.1 through 1.E.7 and any additional +terms imposed by the copyright holder. Additional terms will be linked +to the Project Gutenberg-tm License for all works posted with the +permission of the copyright holder found at the beginning of this work. + +1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm +License terms from this work, or any files containing a part of this +work or any other work associated with Project Gutenberg-tm. + +1.E.5. Do not copy, display, perform, distribute or redistribute this +electronic work, or any part of this electronic work, without +prominently displaying the sentence set forth in paragraph 1.E.1 with +active links or immediate access to the full terms of the Project +Gutenberg-tm License. + +1.E.6. You may convert to and distribute this work in any binary, +compressed, marked up, nonproprietary or proprietary form, including any +word processing or hypertext form. However, if you provide access to or +distribute copies of a Project Gutenberg-tm work in a format other than +"Plain Vanilla ASCII" or other format used in the official version +posted on the official Project Gutenberg-tm web site (www.gutenberg.org), +you must, at no additional cost, fee or expense to the user, provide a +copy, a means of exporting a copy, or a means of obtaining a copy upon +request, of the work in its original "Plain Vanilla ASCII" or other +form. Any alternate format must include the full Project Gutenberg-tm +License as specified in paragraph 1.E.1. + +1.E.7. Do not charge a fee for access to, viewing, displaying, +performing, copying or distributing any Project Gutenberg-tm works +unless you comply with paragraph 1.E.8 or 1.E.9. + +1.E.8. You may charge a reasonable fee for copies of or providing +access to or distributing Project Gutenberg-tm electronic works provided +that + +- You pay a royalty fee of 20% of the gross profits you derive from + the use of Project Gutenberg-tm works calculated using the method + you already use to calculate your applicable taxes. The fee is + owed to the owner of the Project Gutenberg-tm trademark, but he + has agreed to donate royalties under this paragraph to the + Project Gutenberg Literary Archive Foundation. Royalty payments + must be paid within 60 days following each date on which you + prepare (or are legally required to prepare) your periodic tax + returns. Royalty payments should be clearly marked as such and + sent to the Project Gutenberg Literary Archive Foundation at the + address specified in Section 4, "Information about donations to + the Project Gutenberg Literary Archive Foundation." + +- You provide a full refund of any money paid by a user who notifies + you in writing (or by e-mail) within 30 days of receipt that s/he + does not agree to the terms of the full Project Gutenberg-tm + License. You must require such a user to return or + destroy all copies of the works possessed in a physical medium + and discontinue all use of and all access to other copies of + Project Gutenberg-tm works. + +- You provide, in accordance with paragraph 1.F.3, a full refund of any + money paid for a work or a replacement copy, if a defect in the + electronic work is discovered and reported to you within 90 days + of receipt of the work. + +- You comply with all other terms of this agreement for free + distribution of Project Gutenberg-tm works. + +1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm +electronic work or group of works on different terms than are set +forth in this agreement, you must obtain permission in writing from +both the Project Gutenberg Literary Archive Foundation and Michael +Hart, the owner of the Project Gutenberg-tm trademark. Contact the +Foundation as set forth in Section 3 below. + +1.F. + +1.F.1. Project Gutenberg volunteers and employees expend considerable +effort to identify, do copyright research on, transcribe and proofread +public domain works in creating the Project Gutenberg-tm +collection. Despite these efforts, Project Gutenberg-tm electronic +works, and the medium on which they may be stored, may contain +"Defects," such as, but not limited to, incomplete, inaccurate or +corrupt data, transcription errors, a copyright or other intellectual +property infringement, a defective or damaged disk or other medium, a +computer virus, or computer codes that damage or cannot be read by +your equipment. + +1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right +of Replacement or Refund" described in paragraph 1.F.3, the Project +Gutenberg Literary Archive Foundation, the owner of the Project +Gutenberg-tm trademark, and any other party distributing a Project +Gutenberg-tm electronic work under this agreement, disclaim all +liability to you for damages, costs and expenses, including legal +fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT +LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE +PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE +TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE +LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR +INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH +DAMAGE. + +1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a +defect in this electronic work within 90 days of receiving it, you can +receive a refund of the money (if any) you paid for it by sending a +written explanation to the person you received the work from. If you +received the work on a physical medium, you must return the medium with +your written explanation. The person or entity that provided you with +the defective work may elect to provide a replacement copy in lieu of a +refund. If you received the work electronically, the person or entity +providing it to you may choose to give you a second opportunity to +receive the work electronically in lieu of a refund. If the second copy +is also defective, you may demand a refund in writing without further +opportunities to fix the problem. + +1.F.4. Except for the limited right of replacement or refund set forth +in paragraph 1.F.3, this work is provided to you 'AS-IS', WITH NO OTHER +WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE. + +1.F.5. Some states do not allow disclaimers of certain implied +warranties or the exclusion or limitation of certain types of damages. +If any disclaimer or limitation set forth in this agreement violates the +law of the state applicable to this agreement, the agreement shall be +interpreted to make the maximum disclaimer or limitation permitted by +the applicable state law. The invalidity or unenforceability of any +provision of this agreement shall not void the remaining provisions. + +1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the +trademark owner, any agent or employee of the Foundation, anyone +providing copies of Project Gutenberg-tm electronic works in accordance +with this agreement, and any volunteers associated with the production, +promotion and distribution of Project Gutenberg-tm electronic works, +harmless from all liability, costs and expenses, including legal fees, +that arise directly or indirectly from any of the following which you do +or cause to occur: (a) distribution of this or any Project Gutenberg-tm +work, (b) alteration, modification, or additions or deletions to any +Project Gutenberg-tm work, and (c) any Defect you cause. + + +Section 2. Information about the Mission of Project Gutenberg-tm + +Project Gutenberg-tm is synonymous with the free distribution of +electronic works in formats readable by the widest variety of computers +including obsolete, old, middle-aged and new computers. It exists +because of the efforts of hundreds of volunteers and donations from +people in all walks of life. + +Volunteers and financial support to provide volunteers with the +assistance they need, is critical to reaching Project Gutenberg-tm's +goals and ensuring that the Project Gutenberg-tm collection will +remain freely available for generations to come. In 2001, the Project +Gutenberg Literary Archive Foundation was created to provide a secure +and permanent future for Project Gutenberg-tm and future generations. +To learn more about the Project Gutenberg Literary Archive Foundation +and how your efforts and donations can help, see Sections 3 and 4 +and the Foundation web page at http://www.pglaf.org. + + +Section 3. Information about the Project Gutenberg Literary Archive +Foundation + +The Project Gutenberg Literary Archive Foundation is a non profit +501(c)(3) educational corporation organized under the laws of the +state of Mississippi and granted tax exempt status by the Internal +Revenue Service. The Foundation's EIN or federal tax identification +number is 64-6221541. Its 501(c)(3) letter is posted at +http://pglaf.org/fundraising. Contributions to the Project Gutenberg +Literary Archive Foundation are tax deductible to the full extent +permitted by U.S. federal laws and your state's laws. + +The Foundation's principal office is located at 4557 Melan Dr. S. +Fairbanks, AK, 99712., but its volunteers and employees are scattered +throughout numerous locations. Its business office is located at +809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email +business@pglaf.org. Email contact links and up to date contact +information can be found at the Foundation's web site and official +page at http://pglaf.org + +For additional contact information: + Dr. Gregory B. Newby + Chief Executive and Director + gbnewby@pglaf.org + +Section 4. Information about Donations to the Project Gutenberg +Literary Archive Foundation + +Project Gutenberg-tm depends upon and cannot survive without wide +spread public support and donations to carry out its mission of +increasing the number of public domain and licensed works that can be +freely distributed in machine readable form accessible by the widest +array of equipment including outdated equipment. Many small donations +($1 to $5,000) are particularly important to maintaining tax exempt +status with the IRS. + +The Foundation is committed to complying with the laws regulating +charities and charitable donations in all 50 states of the United +States. Compliance requirements are not uniform and it takes a +considerable effort, much paperwork and many fees to meet and keep up +with these requirements. We do not solicit donations in locations +where we have not received written confirmation of compliance. To +SEND DONATIONS or determine the status of compliance for any +particular state visit http://pglaf.org + +While we cannot and do not solicit contributions from states where we +have not met the solicitation requirements, we know of no prohibition +against accepting unsolicited donations from donors in such states who +approach us with offers to donate. + +International donations are gratefully accepted, but we cannot make +any statements concerning tax treatment of donations received from +outside the United States. U.S. laws alone swamp our small staff. + +Please check the Project Gutenberg Web pages for current donation +methods and addresses. Donations are accepted in a number of other +ways including checks, online payments and credit card donations. +To donate, please visit: http://pglaf.org/donate + + +Section 5. General Information About Project Gutenberg-tm electronic +works. + +Professor Michael S. Hart is the originator of the Project Gutenberg-tm +concept of a library of electronic works that could be freely shared +with anyone. For thirty years, he produced and distributed Project +Gutenberg-tm eBooks with only a loose network of volunteer support. + +Project Gutenberg-tm eBooks are often created from several printed +editions, all of which are confirmed as Public Domain in the U.S. +unless a copyright notice is included. Thus, we do not necessarily +keep eBooks in compliance with any particular paper edition. + +Most people start at our Web site which has the main PG search facility: + + http://www.gutenberg.org + +This Web site includes information about Project Gutenberg-tm, +including how to make donations to the Project Gutenberg Literary +Archive Foundation, how to help produce our new eBooks, and how to +subscribe to our email newsletter to hear about new eBooks. + +*** END: FULL LICENSE *** + +The Project Gutenberg EBook of War and Peace, by Leo Tolstoy +(#9 in our series by Leo Tolstoy) + +Copyright laws are changing all over the world. Be sure to check the +copyright laws for your country before downloading or redistributing +this or any other Project Gutenberg eBook. + +This header should be the first thing seen when viewing this Project +Gutenberg file. Please do not remove it. Do not change or edit the +header without written permission. + +Please read the "legal small print," and other information about the +eBook and Project Gutenberg at the bottom of this file. Included is +important information about your specific rights and restrictions in +how the file may be used. You can also find out about how to make a +donation to Project Gutenberg, and how to get involved. + + +**Welcome To The World of Free Plain Vanilla Electronic Texts** + +**eBooks Readable By Both Humans and By Computers, Since 1971** + +*****These eBooks Were Prepared By Thousands of Volunteers!***** + + +Title: War and Peace + +Author: Leo Tolstoy + +Translator: Louise and Aylmer Maude + +Release Date: April, 2001 [EBook #2600] +[This file was first posted on October 7, 2003] +[Most recently updated: May 21, 2006] + +Edition: 11 + +Language: English + +Character set encoding: US-ASCII + +*** START OF THE PROJECT GUTENBERG EBOOK, WAR AND PEACE *** + + + + + + + + + + +War and Peace + +by Leo Tolstoy/Tolstoi + + + + +BOOK ONE: 1805 + + + + +CHAPTER I + + +"Well, Prince, so Genoa and Lucca are now just family estates of the +Buonapartes. But I warn you, if you don't tell me that this means war, +if you still try to defend the infamies and horrors perpetrated by +that Antichrist--I really believe he is Antichrist--I will have +nothing more to do with you and you are no longer my friend, no longer +my 'faithful slave,' as you call yourself! But how do you do? I see +I have frightened you--sit down and tell me all the news." + +It was in July, 1805, and the speaker was the well-known Anna +Pavlovna Scherer, maid of honor and favorite of the Empress Marya +Fedorovna. With these words she greeted Prince Vasili Kuragin, a man +of high rank and importance, who was the first to arrive at her +reception. Anna Pavlovna had had a cough for some days. She was, as +she said, suffering from la grippe; grippe being then a new word in +St. Petersburg, used only by the elite. + +All her invitations without exception, written in French, and +delivered by a scarlet-liveried footman that morning, ran as follows: + +"If you have nothing better to do, Count [or Prince], and if the +prospect of spending an evening with a poor invalid is not too +terrible, I shall be very charmed to see you tonight between 7 and 10- +Annette Scherer." + +"Heavens! what a virulent attack!" replied the prince, not in the +least disconcerted by this reception. He had just entered, wearing +an embroidered court uniform, knee breeches, and shoes, and had +stars on his breast and a serene expression on his flat face. He spoke +in that refined French in which our grandfathers not only spoke but +thought, and with the gentle, patronizing intonation natural to a +man of importance who had grown old in society and at court. He went +up to Anna Pavlovna, kissed her hand, presenting to her his bald, +scented, and shining head, and complacently seated himself on the +sofa. + +"First of all, dear friend, tell me how you are. Set your friend's +mind at rest," said he without altering his tone, beneath the +politeness and affected sympathy of which indifference and even +irony could be discerned. + +"Can one be well while suffering morally? Can one be calm in times +like these if one has any feeling?" said Anna Pavlovna. "You are +staying the whole evening, I hope?" + +"And the fete at the English ambassador's? Today is Wednesday. I +must put in an appearance there," said the prince. "My daughter is +coming for me to take me there." + +"I thought today's fete had been canceled. I confess all these +festivities and fireworks are becoming wearisome." + +"If they had known that you wished it, the entertainment would +have been put off," said the prince, who, like a wound-up clock, by +force of habit said things he did not even wish to be believed. + +"Don't tease! Well, and what has been decided about Novosiltsev's +dispatch? You know everything." + +"What can one say about it?" replied the prince in a cold, +listless tone. "What has been decided? They have decided that +Buonaparte has burnt his boats, and I believe that we are ready to +burn ours." + +Prince Vasili always spoke languidly, like an actor repeating a +stale part. Anna Pavlovna Scherer on the contrary, despite her forty +years, overflowed with animation and impulsiveness. To be an +enthusiast had become her social vocation and, sometimes even when she +did not feel like it, she became enthusiastic in order not to +disappoint the expectations of those who knew her. The subdued smile +which, though it did not suit her faded features, always played +round her lips expressed, as in a spoiled child, a continual +consciousness of her charming defect, which she neither wished, nor +could, nor considered it necessary, to correct. + +In the midst of a conversation on political matters Anna Pavlovna +burst out: + +"Oh, don't speak to me of Austria. Perhaps I don't understand +things, but Austria never has wished, and does not wish, for war. +She is betraying us! Russia alone must save Europe. Our gracious +sovereign recognizes his high vocation and will be true to it. That is +the one thing I have faith in! Our good and wonderful sovereign has to +perform the noblest role on earth, and he is so virtuous and noble +that God will not forsake him. He will fulfill his vocation and +crush the hydra of revolution, which has become more terrible than +ever in the person of this murderer and villain! We alone must +avenge the blood of the just one.... Whom, I ask you, can we rely +on?... England with her commercial spirit will not and cannot +understand the Emperor Alexander's loftiness of soul. She has +refused to evacuate Malta. She wanted to find, and still seeks, some +secret motive in our actions. What answer did Novosiltsev get? None. +The English have not understood and cannot understand the +self-abnegation of our Emperor who wants nothing for himself, but only +desires the good of mankind. And what have they promised? Nothing! And +what little they have promised they will not perform! Prussia has +always declared that Buonaparte is invincible, and that all Europe +is powerless before him.... And I don't believe a word that Hardenburg +says, or Haugwitz either. This famous Prussian neutrality is just a +trap. I have faith only in God and the lofty destiny of our adored +monarch. He will save Europe!" + +She suddenly paused, smiling at her own impetuosity. + +"I think," said the prince with a smile, "that if you had been +sent instead of our dear Wintzingerode you would have captured the +King of Prussia's consent by assault. You are so eloquent. Will you +give me a cup of tea?" + +"In a moment. A propos," she added, becoming calm again, "I am +expecting two very interesting men tonight, le Vicomte de Mortemart, +who is connected with the Montmorencys through the Rohans, one of +the best French families. He is one of the genuine emigres, the good +ones. And also the Abbe Morio. Do you know that profound thinker? He +has been received by the Emperor. Had you heard?" + +"I shall be delighted to meet them," said the prince. "But tell me," +he added with studied carelessness as if it had only just occurred +to him, though the question he was about to ask was the chief motive +of his visit, "is it true that the Dowager Empress wants Baron Funke +to be appointed first secretary at Vienna? The baron by all accounts +is a poor creature." + +Prince Vasili wished to obtain this post for his son, but others +were trying through the Dowager Empress Marya Fedorovna to secure it +for the baron. + +Anna Pavlovna almost closed her eyes to indicate that neither she +nor anyone else had a right to criticize what the Empress desired or +was pleased with. + +"Baron Funke has been recommended to the Dowager Empress by her +sister," was all she said, in a dry and mournful tone. + +As she named the Empress, Anna Pavlovna's face suddenly assumed an +expression of profound and sincere devotion and respect mingled with +sadness, and this occurred every time she mentioned her illustrious +patroness. She added that Her Majesty had deigned to show Baron +Funke beaucoup d'estime, and again her face clouded over with sadness. + +The prince was silent and looked indifferent. But, with the +womanly and courtierlike quickness and tact habitual to her, Anna +Pavlovna wished both to rebuke him (for daring to speak he had done of +a man recommended to the Empress) and at the same time to console him, +so she said: + +"Now about your family. Do you know that since your daughter came +out everyone has been enraptured by her? They say she is amazingly +beautiful." + +The prince bowed to signify his respect and gratitude. + +"I often think," she continued after a short pause, drawing nearer +to the prince and smiling amiably at him as if to show that +political and social topics were ended and the time had come for +intimate conversation--"I often think how unfairly sometimes the +joys of life are distributed. Why has fate given you two such splendid +children? I don't speak of Anatole, your youngest. I don't like +him," she added in a tone admitting of no rejoinder and raising her +eyebrows. "Two such charming children. And really you appreciate +them less than anyone, and so you don't deserve to have them." + +And she smiled her ecstatic smile. + +"I can't help it," said the prince. "Lavater would have said I +lack the bump of paternity." + +"Don't joke; I mean to have a serious talk with you. Do you know I +am dissatisfied with your younger son? Between ourselves" (and her +face assumed its melancholy expression), "he was mentioned at Her +Majesty's and you were pitied...." + +The prince answered nothing, but she looked at him significantly, +awaiting a reply. He frowned. + +"What would you have me do?" he said at last. "You know I did all +a father could for their education, and they have both turned out +fools. Hippolyte is at least a quiet fool, but Anatole is an active +one. That is the only difference between them." He said this smiling +in a way more natural and animated than usual, so that the wrinkles +round his mouth very clearly revealed something unexpectedly coarse +and unpleasant. + +"And why are children born to such men as you? If you were not a +father there would be nothing I could reproach you with," said Anna +Pavlovna, looking up pensively. + +"I am your faithful slave and to you alone I can confess that my +children are the bane of my life. It is the cross I have to bear. That +is how I explain it to myself. It can't be helped!" + +He said no more, but expressed his resignation to cruel fate by a +gesture. Anna Pavlovna meditated. + +"Have you never thought of marrying your prodigal son Anatole?" +she asked. "They say old maids have a mania for matchmaking, and +though I don't feel that weakness in myself as yet, I know a little +person who is very unhappy with her father. She is a relation of +yours, Princess Mary Bolkonskaya." + +Prince Vasili did not reply, though, with the quickness of memory +and perception befitting a man of the world, he indicated by a +movement of the head that he was considering this information. + +"Do you know," he said at last, evidently unable to check the sad +current of his thoughts, "that Anatole is costing me forty thousand +rubles a year? And," he went on after a pause, "what will it be in +five years, if he goes on like this?" Presently he added: "That's what +we fathers have to put up with.... Is this princess of yours rich?" + +"Her father is very rich and stingy. He lives in the country. He +is the well-known Prince Bolkonski who had to retire from the army +under the late Emperor, and was nicknamed 'the King of Prussia.' He is +very clever but eccentric, and a bore. The poor girl is very +unhappy. She has a brother; I think you know him, he married Lise +Meinen lately. He is an aide-de-camp of Kutuzov's and will be here +tonight." + +"Listen, dear Annette," said the prince, suddenly taking Anna +Pavlovna's hand and for some reason drawing it downwards. "Arrange +that affair for me and I shall always be your most devoted slave- +slafe with an f, as a village elder of mine writes in his reports. +She is rich and of good family and that's all I want." + +And with the familiarity and easy grace peculiar to him, he raised +the maid of honor's hand to his lips, kissed it, and swung it to and +fro as he lay back in his armchair, looking in another direction. + +"Attendez," said Anna Pavlovna, reflecting, "I'll speak to Lise, +young Bolkonski's wife, this very evening, and perhaps the thing can +be arranged. It shall be on your family's behalf that I'll start my +apprenticeship as old maid." + + + + + +CHAPTER II + + +Anna Pavlovna's drawing room was gradually filling. The highest +Petersburg society was assembled there: people differing widely in age +and character but alike in the social circle to which they belonged. +Prince Vasili's daughter, the beautiful Helene, came to take her +father to the ambassador's entertainment; she wore a ball dress and +her badge as maid of honor. The youthful little Princess +Bolkonskaya, known as la femme la plus seduisante de Petersbourg,* was +also there. She had been married during the previous winter, and being +pregnant did not go to any large gatherings, but only to small +receptions. Prince Vasili's son, Hippolyte, had come with Mortemart, +whom he introduced. The Abbe Morio and many others had also come. + + +*The most fascinating woman in Petersburg. + + +To each new arrival Anna Pavlovna said, "You have not yet seen my +aunt," or "You do not know my aunt?" and very gravely conducted him or +her to a little old lady, wearing large bows of ribbon in her cap, who +had come sailing in from another room as soon as the guests began to +arrive; and slowly turning her eyes from the visitor to her aunt, Anna +Pavlovna mentioned each one's name and then left them. + +Each visitor performed the ceremony of greeting this old aunt whom +not one of them knew, not one of them wanted to know, and not one of +them cared about; Anna Pavlovna observed these greetings with mournful +and solemn interest and silent approval. The aunt spoke to each of +them in the same words, about their health and her own, and the health +of Her Majesty, "who, thank God, was better today." And each +visitor, though politeness prevented his showing impatience, left +the old woman with a sense of relief at having performed a vexatious +duty and did not return to her the whole evening. + +The young Princess Bolkonskaya had brought some work in a +gold-embroidered velvet bag. Her pretty little upper lip, on which a +delicate dark down was just perceptible, was too short for her +teeth, but it lifted all the more sweetly, and was especially charming +when she occasionally drew it down to meet the lower lip. As is always +the case with a thoroughly attractive woman, her defect--the shortness +of her upper lip and her half-open mouth--seemed to be her own special +and peculiar form of beauty. Everyone brightened at the sight of +this pretty young woman, so soon to become a mother, so full of life +and health, and carrying her burden so lightly. Old men and dull +dispirited young ones who looked at her, after being in her company +and talking to her a little while, felt as if they too were +becoming, like her, full of life and health. All who talked to her, +and at each word saw her bright smile and the constant gleam of her +white teeth, thought that they were in a specially amiable mood that +day. + +The little princess went round the table with quick, short, +swaying steps, her workbag on her arm, and gaily spreading out her +dress sat down on a sofa near the silver samovar, as if all she was +doing was a pleasure to herself and to all around her. "I have brought +my work," said she in French, displaying her bag and addressing all +present. "Mind, Annette, I hope you have not played a wicked trick +on me," she added, turning to her hostess. "You wrote that it was to +be quite a small reception, and just see how badly I am dressed." +And she spread out her arms to show her short-waisted, lace-trimmed, +dainty gray dress, girdled with a broad ribbon just below the breast. + +"Soyez tranquille, Lise, you will always be prettier than anyone +else," replied Anna Pavlovna. + +"You know," said the princess in the same tone of voice and still in +French, turning to a general, "my husband is deserting me? He is going +to get himself killed. Tell me what this wretched war is for?" she +added, addressing Prince Vasili, and without waiting for an answer she +turned to speak to his daughter, the beautiful Helene. + +"What a delightful woman this little princess is!" said Prince +Vasili to Anna Pavlovna. + +One of the next arrivals was a stout, heavily built young man with +close-cropped hair, spectacles, the light-colored breeches fashionable +at that time, a very high ruffle, and a brown dress coat. This stout +young man was an illegitimate son of Count Bezukhov, a well-known +grandee of Catherine's time who now lay dying in Moscow. The young man +had not yet entered either the military or civil service, as he had +only just returned from abroad where he had been educated, and this +was his first appearance in society. Anna Pavlovna greeted him with +the nod she accorded to the lowest hierarchy in her drawing room. +But in spite of this lowest-grade greeting, a look of anxiety and +fear, as at the sight of something too large and unsuited to the +place, came over her face when she saw Pierre enter. Though he was +certainly rather bigger than the other men in the room, her anxiety +could only have reference to the clever though shy, but observant +and natural, expression which distinguished him from everyone else +in that drawing room. + +"It is very good of you, Monsieur Pierre, to come and visit a poor +invalid," said Anna Pavlovna, exchanging an alarmed glance with her +aunt as she conducted him to her. + +Pierre murmured something unintelligible, and continued to look +round as if in search of something. On his way to the aunt he bowed to +the little princess with a pleased smile, as to an intimate +acquaintance. + +Anna Pavlovna's alarm was justified, for Pierre turned away from the +aunt without waiting to hear her speech about Her Majesty's health. +Anna Pavlovna in dismay detained him with the words: "Do you know +the Abbe Morio? He is a most interesting man." + +"Yes, I have heard of his scheme for perpetual peace, and it is very +interesting but hardly feasible." + +"You think so?" rejoined Anna Pavlovna in order to say something and +get away to attend to her duties as hostess. But Pierre now +committed a reverse act of impoliteness. First he had left a lady +before she had finished speaking to him, and now he continued to speak +to another who wished to get away. With his head bent, and his big +feet spread apart, he began explaining his reasons for thinking the +abbe's plan chimerical. + +"We will talk of it later," said Anna Pavlovna with a smile. + +And having got rid of this young man who did not know how to behave, +she resumed her duties as hostess and continued to listen and watch, +ready to help at any point where the conversation might happen to +flag. As the foreman of a spinning mill, when he has set the hands +to work, goes round and notices here a spindle that has stopped or +there one that creaks or makes more noise than it should, and +hastens to check the machine or set it in proper motion, so Anna +Pavlovna moved about her drawing room, approaching now a silent, now a +too-noisy group, and by a word or slight rearrangement kept the +conversational machine in steady, proper, and regular motion. But amid +these cares her anxiety about Pierre was evident. She kept an +anxious watch on him when he approached the group round Mortemart to +listen to what was being said there, and again when he passed to +another group whose center was the abbe. + +Pierre had been educated abroad, and this reception at Anna +Pavlovna's was the first he had attended in Russia. He knew that all +the intellectual lights of Petersburg were gathered there and, like +a child in a toyshop, did not know which way to look, afraid of +missing any clever conversation that was to be heard. Seeing the +self-confident and refined expression on the faces of those present he +was always expecting to hear something very profound. At last he +came up to Morio. Here the conversation seemed interesting and he +stood waiting for an opportunity to express his own views, as young +people are fond of doing. + + + + +CHAPTER III + + +Anna Pavlovna's reception was in full swing. The spindles hummed +steadily and ceaselessly on all sides. With the exception of the aunt, +beside whom sat only one elderly lady, who with her thin careworn face +was rather out of place in this brilliant society, the whole company +had settled into three groups. One, chiefly masculine, had formed +round the abbe. Another, of young people, was grouped round the +beautiful Princess Helene, Prince Vasili's daughter, and the little +Princess Bolkonskaya, very pretty and rosy, though rather too plump +for her age. The third group was gathered round Mortemart and Anna +Pavlovna. + +The vicomte was a nice-looking young man with soft features and +polished manners, who evidently considered himself a celebrity but out +of politeness modestly placed himself at the disposal of the circle in +which he found himself. Anna Pavlovna was obviously serving him up +as a treat to her guests. As a clever maitre d'hotel serves up as a +specially choice delicacy a piece of meat that no one who had seen +it in the kitchen would have cared to eat, so Anna Pavlovna served +up to her guests, first the vicomte and then the abbe, as peculiarly +choice morsels. The group about Mortemart immediately began discussing +the murder of the Duc d'Enghien. The vicomte said that the Duc +d'Enghien had perished by his own magnanimity, and that there were +particular reasons for Buonaparte's hatred of him. + +"Ah, yes! Do tell us all about it, Vicomte," said Anna Pavlovna, +with a pleasant feeling that there was something a la Louis XV in +the sound of that sentence: "Contez nous cela, Vicomte." + +The vicomte bowed and smiled courteously in token of his willingness +to comply. Anna Pavlovna arranged a group round him, inviting everyone +to listen to his tale. + +"The vicomte knew the duc personally," whispered Anna Pavlovna to of +the guests. "The vicomte is a wonderful raconteur," said she to +another. "How evidently he belongs to the best society," said she to a +third; and the vicomte was served up to the company in the choicest +and most advantageous style, like a well-garnished joint of roast beef +on a hot dish. + +The vicomte wished to begin his story and gave a subtle smile. + +"Come over here, Helene, dear," said Anna Pavlovna to the +beautiful young princess who was sitting some way off, the center of +another group. + +The princess smiled. She rose with the same unchanging smile with +which she had first entered the room--the smile of a perfectly +beautiful woman. With a slight rustle of her white dress trimmed +with moss and ivy, with a gleam of white shoulders, glossy hair, and +sparkling diamonds, she passed between the men who made way for her, +not looking at any of them but smiling on all, as if graciously +allowing each the privilege of admiring her beautiful figure and +shapely shoulders, back, and bosom--which in the fashion of those days +were very much exposed--and she seemed to bring the glamour of a +ballroom with her as she moved toward Anna Pavlovna. Helene was so +lovely that not only did she not show any trace of coquetry, but on +the contrary she even appeared shy of her unquestionable and all too +victorious beauty. She seemed to wish, but to be unable, to diminish +its effect. + +"How lovely!" said everyone who saw her; and the vicomte lifted +his shoulders and dropped his eyes as if startled by something +extraordinary when she took her seat opposite and beamed upon him also +with her unchanging smile. + +"Madame, I doubt my ability before such an audience," said he, +smilingly inclining his head. + +The princess rested her bare round arm on a little table and +considered a reply unnecessary. She smilingly waited. All the time the +story was being told she sat upright, glancing now at her beautiful +round arm, altered in shape by its pressure on the table, now at her +still more beautiful bosom, on which she readjusted a diamond +necklace. From time to time she smoothed the folds of her dress, and +whenever the story produced an effect she glanced at Anna Pavlovna, at +once adopted just the expression she saw on the maid of honor's +face, and again relapsed into her radiant smile. + +The little princess had also left the tea table and followed Helene. + +"Wait a moment, I'll get my work.... Now then, what are you thinking +of?" she went on, turning to Prince Hippolyte. "Fetch me my workbag." + +There was a general movement as the princess, smiling and talking +merrily to everyone at once, sat down and gaily arranged herself in +her seat. + +"Now I am all right," she said, and asking the vicomte to begin, she +took up her work. + +Prince Hippolyte, having brought the workbag, joined the circle +and moving a chair close to hers seated himself beside her. + +Le charmant Hippolyte was surprising by his extraordinary +resemblance to his beautiful sister, but yet more by the fact that +in spite of this resemblance he was exceedingly ugly. His features +were like his sister's, but while in her case everything was lit up by +a joyous, self-satisfied, youthful, and constant smile of animation, +and by the wonderful classic beauty of her figure, his face on the +contrary was dulled by imbecility and a constant expression of +sullen self-confidence, while his body was thin and weak. His eyes, +nose, and mouth all seemed puckered into a vacant, wearied grimace, +and his arms and legs always fell into unnatural positions. + +"It's not going to be a ghost story?" said he, sitting down beside +the princess and hastily adjusting his lorgnette, as if without this +instrument he could not begin to speak. + +"Why no, my dear fellow," said the astonished narrator, shrugging +his shoulders. + +"Because I hate ghost stories," said Prince Hippolyte in a tone +which showed that he only understood the meaning of his words after he +had uttered them. + +He spoke with such self-confidence that his hearers could not be +sure whether what he said was very witty or very stupid. He was +dressed in a dark-green dress coat, knee breeches of the color of +cuisse de nymphe effrayee, as he called it, shoes, and silk stockings. + +The vicomte told his tale very neatly. It was an anecdote, then +current, to the effect that the Duc d'Enghien had gone secretly to +Paris to visit Mademoiselle George; that at her house he came upon +Bonaparte, who also enjoyed the famous actress' favors, and that in +his presence Napoleon happened to fall into one of the fainting fits +to which he was subject, and was thus at the duc's mercy. The latter +spared him, and this magnanimity Bonaparte subsequently repaid by +death. + +The story was very pretty and interesting, especially at the point +where the rivals suddenly recognized one another; and the ladies +looked agitated. + +"Charming!" said Anna Pavlovna with an inquiring glance at the +little princess. + +"Charming!" whispered the little princess, sticking the needle +into her work as if to testify that the interest and fascination of +the story prevented her from going on with it. + +The vicomte appreciated this silent praise and smiling gratefully +prepared to continue, but just then Anna Pavlovna, who had kept a +watchful eye on the young man who so alarmed her, noticed that he +was talking too loudly and vehemently with the abbe, so she hurried to +the rescue. Pierre had managed to start a conversation with the abbe +about the balance of power, and the latter, evidently interested by +the young man's simple-minded eagerness, was explaining his pet +theory. Both were talking and listening too eagerly and too naturally, +which was why Anna Pavlovna disapproved. + +"The means are... the balance of power in Europe and the rights of +the people," the abbe was saying. "It is only necessary for one +powerful nation like Russia--barbaric as she is said to be--to place +herself disinterestedly at the head of an alliance having for its +object the maintenance of the balance of power of Europe, and it would +save the world!" + +"But how are you to get that balance?" Pierre was beginning. + +At that moment Anna Pavlovna came up and, looking severely at +Pierre, asked the Italian how he stood Russian climate. The +Italian's face instantly changed and assumed an offensively +affected, sugary expression, evidently habitual to him when conversing +with women. + +"I am so enchanted by the brilliancy of the wit and culture of the +society, more especially of the feminine society, in which I have +had the honor of being received, that I have not yet had time to think +of the climate," said he. + +Not letting the abbe and Pierre escape, Anna Pavlovna, the more +conveniently to keep them under observation, brought them into the +larger circle. + + + + + +CHAPTER IV + + +Just then another visitor entered the drawing room: Prince Andrew +Bolkonski, the little princess' husband. He was a very handsome +young man, of medium height, with firm, clearcut features. +Everything about him, from his weary, bored expression to his quiet, +measured step, offered a most striking contrast to his quiet, little +wife. It was evident that he not only knew everyone in the drawing +room, but had found them to be so tiresome that it wearied him to look +at or listen to them. And among all these faces that he found so +tedious, none seemed to bore him so much as that of his pretty wife. +He turned away from her with a grimace that distorted his handsome +face, kissed Anna Pavlovna's hand, and screwing up his eyes scanned +the whole company. + +"You are off to the war, Prince?" said Anna Pavlovna. + +"General Kutuzov," said Bolkonski, speaking French and stressing the +last syllable of the general's name like a Frenchman, "has been +pleased to take me as an aide-de-camp...." + +"And Lise, your wife?" + +"She will go to the country." + +"Are you not ashamed to deprive us of your charming wife?" + +"Andre," said his wife, addressing her husband in the same +coquettish manner in which she spoke to other men, "the vicomte has +been telling us such a tale about Mademoiselle George and Buonaparte!" + +Prince Andrew screwed up his eyes and turned away. Pierre, who +from the moment Prince Andrew entered the room had watched him with +glad, affectionate eyes, now came up and took his arm. Before he +looked round Prince Andrew frowned again, expressing his annoyance +with whoever was touching his arm, but when he saw Pierre's beaming +face he gave him an unexpectedly kind and pleasant smile. + +"There now!... So you, too, are in the great world?" said he to +Pierre. + +"I knew you would be here," replied Pierre. "I will come to supper +with you. May I?" he added in a low voice so as not to disturb the +vicomte who was continuing his story. + +"No, impossible!" said Prince Andrew, laughing and pressing Pierre's +hand to show that there was no need to ask the question. He wished +to say something more, but at that moment Prince Vasili and his +daughter got up to go and the two young men rose to let them pass. + +"You must excuse me, dear Vicomte," said Prince Vasili to the +Frenchman, holding him down by the sleeve in a friendly way to prevent +his rising. "This unfortunate fete at the ambassador's deprives me +of a pleasure, and obliges me to interrupt you. I am very sorry to +leave your enchanting party," said he, turning to Anna Pavlovna. + +His daughter, Princess Helene, passed between the chairs, lightly +holding up the folds of her dress, and the smile shone still more +radiantly on her beautiful face. Pierre gazed at her with rapturous, +almost frightened, eyes as she passed him. + +"Very lovely," said Prince Andrew. + +"Very," said Pierre. + +In passing Prince Vasili seized Pierre's hand and said to Anna +Pavlovna: "Educate this bear for me! He has been staying with me a +whole month and this is the first time I have seen him in society. +Nothing is so necessary for a young man as the society of clever +women." + + +Anna Pavlovna smiled and promised to take Pierre in hand. She knew +his father to be a connection of Prince Vasili's. The elderly lady who +had been sitting with the old aunt rose hurriedly and overtook +Prince Vasili in the anteroom. All the affectation of interest she had +assumed had left her kindly and tearworn face and it now expressed +only anxiety and fear. + +"How about my son Boris, Prince?" said she, hurrying after him +into the anteroom. "I can't remain any longer in Petersburg. Tell me +what news I may take back to my poor boy." + + +Although Prince Vasili listened reluctantly and not very politely to +the elderly lady, even betraying some impatience, she gave him an +ingratiating and appealing smile, and took his hand that he might +not go away. + +"What would it cost you to say a word to the Emperor, and then he +would be transferred to the Guards at once?" said she. + +"Believe me, Princess, I am ready to do all I can," answered +Prince Vasili, "but it is difficult for me to ask the Emperor. I +should advise you to appeal to Rumyantsev through Prince Golitsyn. +That would be the best way." + +The elderly lady was a Princess Drubetskaya, belonging to one of the +best families in Russia, but she was poor, and having long been out of +society had lost her former influential connections. She had now +come to Petersburg to procure an appointment in the Guards for her +only son. It was, in fact, solely to meet Prince Vasili that she had +obtained an invitation to Anna Pavlovna's reception and had sat +listening to the vicomte's story. Prince Vasili's words frightened +her, an embittered look clouded her once handsome face, but only for a +moment; then she smiled again and clutched Prince Vasili's arm more +tightly. + +"Listen to me, Prince," said she. "I have never yet asked you for +anything and I never will again, nor have I ever reminded you of my +father's friendship for you; but now I entreat you for God's sake to +do this for my son--and I shall always regard you as a benefactor," +she added hurriedly. "No, don't be angry, but promise! I have asked +Golitsyn and he has refused. Be the kindhearted man you always +were," she said, trying to smile though tears were in her eyes. + +"Papa, we shall be late," said Princess Helene, turning her +beautiful head and looking over her classically molded shoulder as she +stood waiting by the door. + +Influence in society, however, is a capital which has to be +economized if it is to last. Prince Vasili knew this, and having +once realized that if he asked on behalf of all who begged of him, +he would soon be unable to ask for himself, he became chary of using +his influence. But in Princess Drubetskaya's case he felt, after her +second appeal, something like qualms of conscience. She had reminded +him of what was quite true; he had been indebted to her father for the +first steps in his career. Moreover, he could see by her manners +that she was one of those women--mostly mothers--who, having once made +up their minds, will not rest until they have gained their end, and +are prepared if necessary to go on insisting day after day and hour +after hour, and even to make scenes. This last consideration moved +him. + +"My dear Anna Mikhaylovna," said he with his usual familiarity and +weariness of tone, "it is almost impossible for me to do what you ask; +but to prove my devotion to you and how I respect your father's +memory, I will do the impossible--your son shall be transferred to the +Guards. Here is my hand on it. Are you satisfied?" + +"My dear benefactor! This is what I expected from you--I knew your +kindness!" He turned to go. + +"Wait--just a word! When he has been transferred to the Guards..." +she faltered. "You are on good terms with Michael Ilarionovich +Kutuzov... recommend Boris to him as adjutant! Then I shall be at +rest, and then..." + +Prince Vasili smiled. + +"No, I won't promise that. You don't know how Kutuzov is pestered +since his appointment as Commander in Chief. He told me himself that +all the Moscow ladies have conspired to give him all their sons as +adjutants." + +"No, but do promise! I won't let you go! My dear benefactor..." + +"Papa," said his beautiful daughter in the same tone as before, +"we shall be late." + +"Well, au revoir! Good-by! You hear her?" + +"Then tomorrow you will speak to the Emperor?" + +"Certainly; but about Kutuzov, I don't promise." + +"Do promise, do promise, Vasili!" cried Anna Mikhaylovna as he went, +with the smile of a coquettish girl, which at one time probably came +naturally to her, but was now very ill-suited to her careworn face. + +Apparently she had forgotten her age and by force of habit +employed all the old feminine arts. But as soon as the prince had gone +her face resumed its former cold, artificial expression. She +returned to the group where the vicomte was still talking, and again +pretended to listen, while waiting till it would be time to leave. Her +task was accomplished. + + + + + +CHAPTER V + + +"And what do you think of this latest comedy, the coronation at +Milan?" asked Anna Pavlovna, "and of the comedy of the people of Genoa +and Lucca laying their petitions before Monsieur Buonaparte, and +Monsieur Buonaparte sitting on a throne and granting the petitions +of the nations? Adorable! It is enough to make one's head whirl! It is +as if the whole world had gone crazy." + +Prince Andrew looked Anna Pavlovna straight in the face with a +sarcastic smile. + +"'Dieu me la donne, gare a qui la touche!'* They say he was very +fine when he said that," he remarked, repeating the words in +Italian: "'Dio mi l'ha dato. Guai a chi la tocchi!'" + + +*God has given it to me, let him who touches it beware! + + +"I hope this will prove the last drop that will make the glass run +over," Anna Pavlovna continued. "The sovereigns will not be able to +endure this man who is a menace to everything." + +"The sovereigns? I do not speak of Russia," said the vicomte, polite +but hopeless: "The sovereigns, madame... What have they done for Louis +XVII, for the Queen, or for Madame Elizabeth? Nothing!" and he +became more animated. "And believe me, they are reaping the reward +of their betrayal of the Bourbon cause. The sovereigns! Why, they +are sending ambassadors to compliment the usurper." + +And sighing disdainfully, he again changed his position. + +Prince Hippolyte, who had been gazing at the vicomte for some time +through his lorgnette, suddenly turned completely round toward the +little princess, and having asked for a needle began tracing the Conde +coat of arms on the table. He explained this to her with as much +gravity as if she had asked him to do it. + +"Baton de gueules, engrele de gueules d' azur--maison Conde," said +he. + +The princess listened, smiling. + +"If Buonaparte remains on the throne of France a year longer," the +vicomte continued, with the air of a man who, in a matter with which +he is better acquainted than anyone else, does not listen to others +but follows the current of his own thoughts, "things will have gone +too far. By intrigues, violence, exile, and executions, French +society--I mean good French society--will have been forever destroyed, +and then..." + +He shrugged his shoulders and spread out his hands. Pierre wished to +make a remark, for the conversation interested him, but Anna Pavlovna, +who had him under observation, interrupted: + +"The Emperor Alexander," said she, with the melancholy which +always accompanied any reference of hers to the Imperial family, + +"has declared that he will leave it to the French people themselves to +choose their own form of government; and I believe that once free from +the usurper, the whole nation will certainly throw itself into the +arms of its rightful king," she concluded, trying to be amiable to the +royalist emigrant. + +"That is doubtful," said Prince Andrew. "Monsieur le Vicomte quite +rightly supposes that matters have already gone too far. I think it +will be difficult to return to the old regime." + +"From what I have heard," said Pierre, blushing and breaking into +the conversation, "almost all the aristocracy has already gone over to +Bonaparte's side." + +"It is the Buonapartists who say that," replied the vicomte +without looking at Pierre. "At the present time it is difficult to +know the real state of French public opinion." + +"Bonaparte has said so," remarked Prince Andrew with a sarcastic +smile. + +It was evident that he did not like the vicomte and was aiming his +remarks at him, though without looking at him. + +"'I showed them the path to glory, but they did not follow it,'" +Prince Andrew continued after a short silence, again quoting +Napoleon's words. "'I opened my antechambers and they crowded in.' I +do not know how far he was justified in saying so." + +"Not in the least," replied the vicomte. "After the murder of the +duc even the most partial ceased to regard him as a hero. If to some +people," he went on, turning to Anna Pavlovna, "he ever was a hero, +after the murder of the duc there was one martyr more in heaven and +one hero less on earth." + +Before Anna Pavlovna and the others had time to smile their +appreciation of the vicomte's epigram, Pierre again broke into the +conversation, and though Anna Pavlovna felt sure he would say +something inappropriate, she was unable to stop him. + +"The execution of the Duc d'Enghien," declared Monsieur Pierre, "was +a political necessity, and it seems to me that Napoleon showed +greatness of soul by not fearing to take on himself the whole +responsibility of that deed." + +"Dieu! Mon Dieu!" muttered Anna Pavlovna in a terrified whisper. + +"What, Monsieur Pierre... Do you consider that assassination shows +greatness of soul?" said the little princess, smiling and drawing +her work nearer to her. + +"Oh! Oh!" exclaimed several voices. + +"Capital!" said Prince Hippolyte in English, and began slapping +his knee with the palm of his hand. + +The vicomte merely shrugged his shoulders. Pierre looked solemnly at +his audience over his spectacles and continued. + +"I say so," he continued desperately, "because the Bourbons fled +from the Revolution leaving the people to anarchy, and Napoleon +alone understood the Revolution and quelled it, and so for the general +good, he could not stop short for the sake of one man's life." + +"Won't you come over to the other table?" suggested Anna Pavlovna. + +But Pierre continued his speech without heeding her. + +"No," cried he, becoming more and more eager, "Napoleon is great +because he rose superior to the Revolution, suppressed its abuses, +preserved all that was good in it--equality of citizenship and freedom +of speech and of the press--and only for that reason did he obtain +power." + +"Yes, if having obtained power, without availing himself of it to +commit murder he had restored it to the rightful king, I should have +called him a great man," remarked the vicomte. + +"He could not do that. The people only gave him power that he +might rid them of the Bourbons and because they saw that he was a +great man. The Revolution was a grand thing!" continued Monsieur +Pierre, betraying by this desperate and provocative proposition his +extreme youth and his wish to express all that was in his mind. + +"What? Revolution and regicide a grand thing?... Well, after that... +But won't you come to this other table?" repeated Anna Pavlovna. + +"Rousseau's Contrat social," said the vicomte with a tolerant smile. + +"I am not speaking of regicide, I am speaking about ideas." + +"Yes: ideas of robbery, murder, and regicide," again interjected +an ironical voice. + +"Those were extremes, no doubt, but they are not what is most +important. What is important are the rights of man, emancipation +from prejudices, and equality of citizenship, and all these ideas +Napoleon has retained in full force." + +"Liberty and equality," said the vicomte contemptuously, as if at +last deciding seriously to prove to this youth how foolish his words +were, "high-sounding words which have long been discredited. Who +does not love liberty and equality? Even our Saviour preached +liberty and equality. Have people since the Revolution become happier? +On the contrary. We wanted liberty, but Buonaparte has destroyed it." + +Prince Andrew kept looking with an amused smile from Pierre to the +vicomte and from the vicomte to their hostess. In the first moment +of Pierre's outburst Anna Pavlovna, despite her social experience, was +horror-struck. But when she saw that Pierre's sacrilegious words had +not exasperated the vicomte, and had convinced herself that it was +impossible to stop him, she rallied her forces and joined the +vicomte in a vigorous attack on the orator. + +"But, my dear Monsieur Pierre," said she, "how do you explain the +fact of a great man executing a duc--or even an ordinary man who--is +innocent and untried?" + +"I should like," said the vicomte, "to ask how monsieur explains the +18th Brumaire; was not that an imposture? It was a swindle, and not at +all like the conduct of a great man!" + +"And the prisoners he killed in Africa? That was horrible!" said the +little princess, shrugging her shoulders. + +"He's a low fellow, say what you will," remarked Prince Hippolyte. + +Pierre, not knowing whom to answer, looked at them all and smiled. +His smile was unlike the half-smile of other people. When he smiled, +his grave, even rather gloomy, look was instantaneously replaced by +another--a childlike, kindly, even rather silly look, which seemed +to ask forgiveness. + +The vicomte who was meeting him for the first time saw clearly +that this young Jacobin was not so terrible as his words suggested. +All were silent. + +"How do you expect him to answer you all at once?" said Prince +Andrew. "Besides, in the actions of a statesman one has to distinguish +between his acts as a private person, as a general, and as an emperor. +So it seems to me." + +"Yes, yes, of course!" Pierre chimed in, pleased at the arrival of +this reinforcement. + +"One must admit," continued Prince Andrew, "that Napoleon as a man +was great on the bridge of Arcola, and in the hospital at Jaffa +where he gave his hand to the plague-stricken; but... but there are +other acts which it is difficult to justify." + +Prince Andrew, who had evidently wished to tone down the awkwardness +of Pierre's remarks, rose and made a sign to his wife that it was time +to go. + + +Suddenly Prince Hippolyte started up making signs to everyone to +attend, and asking them all to be seated began: + +"I was told a charming Moscow story today and must treat you to +it. Excuse me, Vicomte--I must tell it in Russian or the point will be +lost...." And Prince Hippolyte began to tell his story in such Russian +as a Frenchman would speak after spending about a year in Russia. +Everyone waited, so emphatically and eagerly did he demand their +attention to his story. + +"There is in Moscow a lady, une dame, and she is very stingy. She +must have two footmen behind her carriage, and very big ones. That was +her taste. And she had a lady's maid, also big. She said..." + +Here Prince Hippolyte paused, evidently collecting his ideas with +difficulty. + +"She said... Oh yes! She said, 'Girl,' to the maid, 'put on a +livery, get up behind the carriage, and come with me while I make some +calls.'" + +Here Prince Hippolyte spluttered and burst out laughing long +before his audience, which produced an effect unfavorable to the +narrator. Several persons, among them the elderly lady and Anna +Pavlovna, did however smile. + +"She went. Suddenly there was a great wind. The girl lost her hat +and her long hair came down...." Here he could contain himself no +longer and went on, between gasps of laughter: "And the whole world +knew...." + +And so the anecdote ended. Though it was unintelligible why he had +told it, or why it had to be told in Russian, still Anna Pavlovna +and the others appreciated Prince Hippolyte's social tact in so +agreeably ending Pierre's unpleasant and unamiable outburst. After the +anecdote the conversation broke up into insignificant small talk about +the last and next balls, about theatricals, and who would meet whom, +and when and where. + + + + + +CHAPTER VI + + +Having thanked Anna Pavlovna for her charming soiree, the guests +began to take their leave. + +Pierre was ungainly. Stout, about the average height, broad, with +huge red hands; he did not know, as the saying is, how to enter a +drawing room and still less how to leave one; that is, how to say +something particularly agreeable before going away. Besides this he +was absent-minded. When he rose to go, he took up instead of his +own, the general's three-cornered hat, and held it, pulling at the +plume, till the general asked him to restore it. All his +absent-mindedness and inability to enter a room and converse in it +was, however, redeemed by his kindly, simple, and modest expression. +Anna Pavlovna turned toward him and, with a Christian mildness that +expressed forgiveness of his indiscretion, nodded and said: "I hope to +see you again, but I also hope you will change your opinions, my +dear Monsieur Pierre." + +When she said this, he did not reply and only bowed, but again +everybody saw his smile, which said nothing, unless perhaps, "Opinions +are opinions, but you see what a capital, good-natured fellow I am." +And everyone, including Anna Pavlovna, felt this. + +Prince Andrew had gone out into the hall, and, turning his shoulders +to the footman who was helping him on with his cloak, listened +indifferently to his wife's chatter with Prince Hippolyte who had also +come into the hall. Prince Hippolyte stood close to the pretty, +pregnant princess, and stared fixedly at her through his eyeglass. + +"Go in, Annette, or you will catch cold," said the little +princess, taking leave of Anna Pavlovna. "It is settled," she added in +a low voice. + +Anna Pavlovna had already managed to speak to Lise about the match +she contemplated between Anatole and the little princess' +sister-in-law. + +"I rely on you, my dear," said Anna Pavlovna, also in a low tone. +"Write to her and let me know how her father looks at the matter. Au +revoir!"--and she left the hall. + +Prince Hippolyte approached the little princess and, bending his +face close to her, began to whisper something. + +Two footmen, the princess' and his own, stood holding a shawl and +a cloak, waiting for the conversation to finish. They listened to +the French sentences which to them were meaningless, with an air of +understanding but not wishing to appear to do so. The princess as +usual spoke smilingly and listened with a laugh. + +"I am very glad I did not go to the ambassador's," said Prince +Hippolyte "-so dull-. It has been a delightful evening, has it not? +Delightful!" + +"They say the ball will be very good," replied the princess, drawing +up her downy little lip. "All the pretty women in society will be +there." + +"Not all, for you will not be there; not all," said Prince Hippolyte +smiling joyfully; and snatching the shawl from the footman, whom he +even pushed aside, he began wrapping it round the princess. Either +from awkwardness or intentionally (no one could have said which) after +the shawl had been adjusted he kept his arm around her for a long +time, as though embracing her. + +Still smiling, she gracefully moved away, turning and glancing at +her husband. Prince Andrew's eyes were closed, so weary and sleepy did +he seem. + +"Are you ready?" he asked his wife, looking past her. + +Prince Hippolyte hurriedly put on his cloak, which in the latest +fashion reached to his very heels, and, stumbling in it, ran out +into the porch following the princess, whom a footman was helping into +the carriage. + +"Princesse, au revoir," cried he, stumbling with his tongue as +well as with his feet. + +The princess, picking up her dress, was taking her seat in the +dark carriage, her husband was adjusting his saber; Prince +Hippolyte, under pretense of helping, was in everyone's way. + +"Allow me, sir," said Prince Andrew in Russian in a cold, +disagreeable tone to Prince Hippolyte who was blocking his path. + +"I am expecting you, Pierre," said the same voice, but gently and +affectionately. + +The postilion started, the carriage wheels rattled. Prince Hippolyte +laughed spasmodically as he stood in the porch waiting for the vicomte +whom he had promised to take home. + +"Well, mon cher," said the vicomte, having seated himself beside +Hippolyte in the carriage, "your little princess is very nice, very +nice indeed, quite French," and he kissed the tips of his fingers. +Hippolyte burst out laughing. + +"Do you know, you are a terrible chap for all your innocent airs," +continued the vicomte. "I pity the poor husband, that little officer +who gives himself the airs of a monarch." + +Hippolyte spluttered again, and amid his laughter said, "And you +were saying that the Russian ladies are not equal to the French? One +has to know how to deal with them." + + +Pierre reaching the house first went into Prince Andrew's study like +one quite at home, and from habit immediately lay down on the sofa, +took from the shelf the first book that came to his hand (it was +Caesar's Commentaries), and resting on his elbow, began reading it +in the middle. + +"What have you done to Mlle Scherer? She will be quite ill now," +said Prince Andrew, as he entered the study, rubbing his small white +hands. + +Pierre turned his whole body, making the sofa creak. He lifted his +eager face to Prince Andrew, smiled, and waved his hand. + +"That abbe is very interesting but he does not see the thing in +the right light.... In my opinion perpetual peace is possible but--I +do not know how to express it... not by a balance of political +power...." + +It was evident that Prince Andrew was not interested in such +abstract conversation. + +"One can't everywhere say all one thinks, mon cher. Well, have you +at last decided on anything? Are you going to be a guardsman or a +diplomatist?" asked Prince Andrew after a momentary silence. + +Pierre sat up on the sofa, with his legs tucked under him. + +"Really, I don't yet know. I don't like either the one or the +other." + +"But you must decide on something! Your father expects it." + +Pierre at the age of ten had been sent abroad with an abbe as tutor, +and had remained away till he was twenty. When he returned to Moscow +his father dismissed the abbe and said to the young man, "Now go to +Petersburg, look round, and choose your profession. I will agree to +anything. Here is a letter to Prince Vasili, and here is money. +Write to me all about it, and I will help you in everything." Pierre +had already been choosing a career for three months, and had not +decided on anything. It was about this choice that Prince Andrew was +speaking. Pierre rubbed his forehead. + +"But he must be a Freemason," said he, referring to the abbe whom he +had met that evening. + +"That is all nonsense." Prince Andrew again interrupted him, "let us +talk business. Have you been to the Horse Guards?" + +"No, I have not; but this is what I have been thinking and wanted to +tell you. There is a war now against Napoleon. If it were a war for +freedom I could understand it and should be the first to enter the +army; but to help England and Austria against the greatest man in +the world is not right." + +Prince Andrew only shrugged his shoulders at Pierre's childish +words. He put on the air of one who finds it impossible to reply to +such nonsense, but it would in fact have been difficult to give any +other answer than the one Prince Andrew gave to this naive question. + +"If no one fought except on his own conviction, there would be no +wars," he said. + +"And that would be splendid," said Pierre. + +Prince Andrew smiled ironically. + +"Very likely it would be splendid, but it will never come about..." + +"Well, why are you going to the war?" asked Pierre. + +"What for? I don't know. I must. Besides that I am going..." He +paused. "I am going because the life I am leading here does not suit +me!" + + + + + +CHAPTER VII + + +The rustle of a woman's dress was heard in the next room. Prince +Andrew shook himself as if waking up, and his face assumed the look it +had had in Anna Pavlovna's drawing room. Pierre removed his feet +from the sofa. The princess came in. She had changed her gown for a +house dress as fresh and elegant as the other. Prince Andrew rose +and politely placed a chair for her. + +"How is it," she began, as usual in French, settling down briskly +and fussily in the easy chair, "how is it Annette never got married? +How stupid you men all are not to have married her! Excuse me for +saying so, but you have no sense about women. What an argumentative +fellow you are, Monsieur Pierre!" + +"And I am still arguing with your husband. I can't understand why he +wants to go to the war," replied Pierre, addressing the princess +with none of the embarrassment so commonly shown by young men in their +intercourse with young women. + +The princess started. Evidently Pierre's words touched her to the +quick. + +"Ah, that is just what I tell him!" said she. "I don't understand +it; I don't in the least understand why men can't live without wars. +How is it that we women don't want anything of the kind, don't need +it? Now you shall judge between us. I always tell him: Here he is +Uncle's aide-de-camp, a most brilliant position. He is so well +known, so much appreciated by everyone. The other day at the +Apraksins' I heard a lady asking, 'Is that the famous Prince +Andrew?' I did indeed." She laughed. "He is so well received +everywhere. He might easily become aide-de-camp to the Emperor. You +know the Emperor spoke to him most graciously. Annette and I were +speaking of how to arrange it. What do you think?" + +Pierre looked at his friend and, noticing that he did not like the +conversation, gave no reply. + +"When are you starting?" he asked. + +"Oh, don't speak of his going, don't! I won't hear it spoken of," +said the princess in the same petulantly playful tone in which she had +spoken to Hippolyte in the drawing room and which was so plainly +ill-suited to the family circle of which Pierre was almost a member. +"Today when I remembered that all these delightful associations must +be broken off... and then you know, Andre..." (she looked +significantly at her husband) "I'm afraid, I'm afraid!" she whispered, +and a shudder ran down her back. + +Her husband looked at her as if surprised to notice that someone +besides Pierre and himself was in the room, and addressed her in a +tone of frigid politeness. + +"What is it you are afraid of, Lise? I don't understand," said he. + +"There, what egotists men all are: all, all egotists! Just for a +whim of his own, goodness only knows why, he leaves me and locks me up +alone in the country." + +"With my father and sister, remember," said Prince Andrew gently. + +"Alone all the same, without my friends.... And he expects me not to +be afraid." + +Her tone was now querulous and her lip drawn up, giving her not a +joyful, but an animal, squirrel-like expression. She paused as if +she felt it indecorous to speak of her pregnancy before Pierre, though +the gist of the matter lay in that. + +"I still can't understand what you are afraid of," said Prince +Andrew slowly, not taking his eyes off his wife. + +The princess blushed, and raised her arms with a gesture of despair. + +"No, Andrew, I must say you have changed. Oh, how you have..." + +"Your doctor tells you to go to bed earlier," said Prince Andrew. +"You had better go." + +The princess said nothing, but suddenly her short downy lip +quivered. Prince Andrew rose, shrugged his shoulders, and walked about +the room. + +Pierre looked over his spectacles with naive surprise, now at him +and now at her, moved as if about to rise too, but changed his mind. + +"Why should I mind Monsieur Pierre being here?" exclaimed the little +princess suddenly, her pretty face all at once distorted by a +tearful grimace. "I have long wanted to ask you, Andrew, why you +have changed so to me? What have I done to you? You are going to the +war and have no pity for me. Why is it?" + +"Lise!" was all Prince Andrew said. But that one word expressed an +entreaty, a threat, and above all conviction that she would herself +regret her words. But she went on hurriedly: + +"You treat me like an invalid or a child. I see it all! Did you +behave like that six months ago?" + +"Lise, I beg you to desist," said Prince Andrew still more +emphatically. + +Pierre, who had been growing more and more agitated as he listened +to all this, rose and approached the princess. He seemed unable to +bear the sight of tears and was ready to cry himself. + +"Calm yourself, Princess! It seems so to you because... I assure you +I myself have experienced... and so... because... No, excuse me! An +outsider is out of place here... No, don't distress yourself... +Good-by!" + +Prince Andrew caught him by the hand. + +"No, wait, Pierre! The princess is too kind to wish to deprive me of +the pleasure of spending the evening with you." + +"No, he thinks only of himself," muttered the princess without +restraining her angry tears. + +"Lise!" said Prince Andrew dryly, raising his voice to the pitch +which indicates that patience is exhausted. + +Suddenly the angry, squirrel-like expression of the princess' pretty +face changed into a winning and piteous look of fear. Her beautiful +eyes glanced askance at her husband's face, and her own assumed the +timid, deprecating expression of a dog when it rapidly but feebly wags +its drooping tail. + +"Mon Dieu, mon Dieu!" she muttered, and lifting her dress with one +hand she went up to her husband and kissed him on the forehead. + +"Good night, Lise," said he, rising and courteously kissing her hand +as he would have done to a stranger. + + + + + +CHAPTER VIII + + +The friends were silent. Neither cared to begin talking. Pierre +continually glanced at Prince Andrew; Prince Andrew rubbed his +forehead with his small hand. + +"Let us go and have supper," he said with a sigh, going to the door. + +They entered the elegant, newly decorated, and luxurious dining +room. Everything from the table napkins to the silver, china, and +glass bore that imprint of newness found in the households of the +newly married. Halfway through supper Prince Andrew leaned his +elbows on the table and, with a look of nervous agitation such as +Pierre had never before seen on his face, began to talk--as one who +has long had something on his mind and suddenly determines to speak +out. + +"Never, never marry, my dear fellow! That's my advice: never marry +till you can say to yourself that you have done all you are capable +of, and until you have ceased to love the woman of your choice and +have seen her plainly as she is, or else you will make a cruel and +irrevocable mistake. Marry when you are old and good for nothing--or +all that is good and noble in you will be lost. It will all be +wasted on trifles. Yes! Yes! Yes! Don't look at me with such surprise. +If you marry expecting anything from yourself in the future, you +will feel at every step that for you all is ended, all is closed +except the drawing room, where you will be ranged side by side with +a court lackey and an idiot!... But what's the good?..." and he +waved his arm. + +Pierre took off his spectacles, which made his face seem different +and the good-natured expression still more apparent, and gazed at +his friend in amazement. + +"My wife," continued Prince Andrew, "is an excellent woman, one of +those rare women with whom a man's honor is safe; but, O God, what +would I not give now to be unmarried! You are the first and only one +to whom I mention this, because I like you." + +As he said this Prince Andrew was less than ever like that Bolkonski +who had lolled in Anna Pavlovna's easy chairs and with half-closed +eyes had uttered French phrases between his teeth. Every muscle of his +thin face was now quivering with nervous excitement; his eyes, in +which the fire of life had seemed extinguished, now flashed with +brilliant light. It was evident that the more lifeless he seemed at +ordinary times, the more impassioned he became in these moments of +almost morbid irritation. + +"You don't understand why I say this," he continued, "but it is +the whole story of life. You talk of Bonaparte and his career," said +he (though Pierre had not mentioned Bonaparte), "but Bonaparte when he +worked went step by step toward his goal. He was free, he had +nothing but his aim to consider, and he reached it. But tie yourself +up with a woman and, like a chained convict, you lose all freedom! And +all you have of hope and strength merely weighs you down and +torments you with regret. Drawing rooms, gossip, balls, vanity, and +triviality--these are the enchanted circle I cannot escape from. I +am now going to the war, the greatest war there ever was, and I know +nothing and am fit for nothing. I am very amiable and have a caustic +wit," continued Prince Andrew, "and at Anna Pavlovna's they listen +to me. And that stupid set without whom my wife cannot exist, and +those women... If you only knew what those society women are, and +women in general! My father is right. Selfish, vain, stupid, trivial +in everything--that's what women are when you see them in their true +colors! When you meet them in society it seems as if there were +something in them, but there's nothing, nothing, nothing! No, don't +marry, my dear fellow; don't marry!" concluded Prince Andrew. + +"It seems funny to me," said Pierre, "that you, you should +consider yourself incapable and your life a spoiled life. You have +everything before you, everything. And you..." + +He did not finish his sentence, but his tone showed how highly he +thought of his friend and how much he expected of him in the future. + +"How can he talk like that?" thought Pierre. He considered his +friend a model of perfection because Prince Andrew possessed in the +highest degree just the very qualities Pierre lacked, and which +might be best described as strength of will. Pierre was always +astonished at Prince Andrew's calm manner of treating everybody, his +extraordinary memory, his extensive reading (he had read everything, +knew everything, and had an opinion about everything), but above all +at his capacity for work and study. And if Pierre was often struck +by Andrew's lack of capacity for philosophical meditation (to which he +himself was particularly addicted), he regarded even this not as a +defect but as a sign of strength. + +Even in the best, most friendly and simplest relations of life, +praise and commendation are essential, just as grease is necessary +to wheels that they may run smoothly. + +"My part is played out," said Prince Andrew. "What's the use of +talking about me? Let us talk about you," he added after a silence, +smiling at his reassuring thoughts. + +That smile was immediately reflected on Pierre's face. + +"But what is there to say about me?" said Pierre, his face +relaxing into a careless, merry smile. "What am I? An illegitimate +son!" He suddenly blushed crimson, and it was plain that he had made a +great effort to say this. "Without a name and without means... And +it really..." But he did not say what "it really" was. "For the +present I am free and am all right. Only I haven't the least idea what +I am to do; I wanted to consult you seriously." + +Prince Andrew looked kindly at him, yet his glance--friendly and +affectionate as it was--expressed a sense of his own superiority. + +"I am fond of you, especially as you are the one live man among +our whole set. Yes, you're all right! Choose what you will; it's all +the same. You'll be all right anywhere. But look here: give up +visiting those Kuragins and leading that sort of life. It suits you so +badly--all this debauchery, dissipation, and the rest of it!" + +"What would you have, my dear fellow?" answered Pierre, shrugging +his shoulders. "Women, my dear fellow; women!" + +"I don't understand it," replied Prince Andrew. "Women who are comme +il faut, that's a different matter; but the Kuragins' set of women, +'women and wine' I don't understand!" + +Pierre was staying at Prince Vasili Kuragin's and sharing the +dissipated life of his son Anatole, the son whom they were planning to +reform by marrying him to Prince Andrew's sister. + +"Do you know?" said Pierre, as if suddenly struck by a happy +thought, "seriously, I have long been thinking of it.... Leading +such a life I can't decide or think properly about anything. One's +head aches, and one spends all one's money. He asked me for tonight, +but I won't go." + +"You give me your word of honor not to go?" + +"On my honor!" + + + + + +CHAPTER IX + + +It was past one o'clock when Pierre left his friend. It was a +cloudless, northern, summer night. Pierre took an open cab intending +to drive straight home. But the nearer he drew to the house the more +he felt the impossibility of going to sleep on such a night. It was +light enough to see a long way in the deserted street and it seemed +more like morning or evening than night. On the way Pierre +remembered that Anatole Kuragin was expecting the usual set for +cards that evening, after which there was generally a drinking bout, +finishing with visits of a kind Pierre was very fond of. + +"I should like to go to Kuragin's," thought he. + +But he immediately recalled his promise to Prince Andrew not to go +there. Then, as happens to people of weak character, he desired so +passionately once more to enjoy that dissipation he was so +accustomed to that he decided to go. The thought immediately +occurred to him that his promise to Prince Andrew was of no account, +because before he gave it he had already promised Prince Anatole to +come to his gathering; "besides," thought he, "all such 'words of +honor' are conventional things with no definite meaning, especially if +one considers that by tomorrow one may be dead, or something so +extraordinary may happen to one that honor and dishonor will be all +the same!" Pierre often indulged in reflections of this sort, +nullifying all his decisions and intentions. He went to Kuragin's. + +Reaching the large house near the Horse Guards' barracks, in which +Anatole lived, Pierre entered the lighted porch, ascended the +stairs, and went in at the open door. There was no one in the +anteroom; empty bottles, cloaks, and overshoes were lying about; there +was a smell of alcohol, and sounds of voices and shouting in the +distance. + +Cards and supper were over, but the visitors had not yet +dispersed. Pierre threw off his cloak and entered the first room, in +which were the remains of supper. A footman, thinking no one saw +him, was drinking on the sly what was left in the glasses. From the +third room came sounds of laughter, the shouting of familiar voices, +the growling of a bear, and general commotion. Some eight or nine +young men were crowding anxiously round an open window. Three others +were romping with a young bear, one pulling him by the chain and +trying to set him at the others. + +"I bet a hundred on Stevens!" shouted one. + +"Mind, no holding on!" cried another. + +"I bet on Dolokhov!" cried a third. "Kuragin, you part our hands." + +"There, leave Bruin alone; here's a bet on." + +"At one draught, or he loses!" shouted a fourth. + +"Jacob, bring a bottle!" shouted the host, a tall, handsome fellow +who stood in the midst of the group, without a coat, and with his fine +linen shirt unfastened in front. "Wait a bit, you fellows.... Here +is Petya! Good man!" cried he, addressing Pierre. + +Another voice, from a man of medium height with clear blue eyes, +particularly striking among all these drunken voices by its sober +ring, cried from the window: "Come here; part the bets!" This was +Dolokhov, an officer of the Semenov regiment, a notorious gambler +and duelist, who was living with Anatole. Pierre smiled, looking about +him merrily. + +"I don't understand. What's it all about?" + +"Wait a bit, he is not drunk yet! A bottle here," said Anatole, +taking a glass from the table he went up to Pierre. + +"First of all you must drink!" + +Pierre drank one glass after another, looking from under his brows +at the tipsy guests who were again crowding round the window, and +listening to their chatter. Anatole kept on refilling Pierre's glass +while explaining that Dolokhov was betting with Stevens, an English +naval officer, that he would drink a bottle of rum sitting on the +outer ledge of the third floor window with his legs hanging out. + +"Go on, you must drink it all," said Anatole, giving Pierre the last +glass, "or I won't let you go!" + +"No, I won't," said Pierre, pushing Anatole aside, and he went up to +the window. + +Dolokhov was holding the Englishman's hand and clearly and +distinctly repeating the terms of the bet, addressing himself +particularly to Anatole and Pierre. + +Dolokhov was of medium height, with curly hair and light-blue +eyes. He was about twenty-five. Like all infantry officers he wore +no mustache, so that his mouth, the most striking feature of his face, +was clearly seen. The lines of that mouth were remarkably finely +curved. The middle of the upper lip formed a sharp wedge and closed +firmly on the firm lower one, and something like two distinct smiles +played continually round the two corners of the mouth; this, +together with the resolute, insolent intelligence of his eyes, +produced an effect which made it impossible not to notice his face. +Dolokhov was a man of small means and no connections. Yet, though +Anatole spent tens of thousands of rubles, Dolokhov lived with him and +had placed himself on such a footing that all who knew them, including +Anatole himself, respected him more than they did Anatole. Dolokhov +could play all games and nearly always won. However much he drank, +he never lost his clearheadedness. Both Kuragin and Dolokhov were at +that time notorious among the rakes and scapegraces of Petersburg. + +The bottle of rum was brought. The window frame which prevented +anyone from sitting on the outer sill was being forced out by two +footmen, who were evidently flurried and intimidated by the directions +and shouts of the gentlemen around. + +Anatole with his swaggering air strode up to the window. He wanted +to smash something. Pushing away the footmen he tugged at the frame, +but could not move it. He smashed a pane. + +"You have a try, Hercules," said he, turning to Pierre. + +Pierre seized the crossbeam, tugged, and wrenched the oak frame +out with a crash. + +"Take it right out, or they'll think I'm holding on," said Dolokhov. + +"Is the Englishman bragging?... Eh? Is it all right?" said Anatole. + +"First-rate," said Pierre, looking at Dolokhov, who with a bottle of +rum in his hand was approaching the window, from which the light of +the sky, the dawn merging with the afterglow of sunset, was visible. + +Dolokhov, the bottle of rum still in his hand, jumped onto the +window sill. "Listen!" cried he, standing there and addressing those +in the room. All were silent. + +"I bet fifty imperials"--he spoke French that the Englishman might +understand him, but he did, not speak it very well--"I bet fifty +imperials... or do you wish to make it a hundred?" added he, +addressing the Englishman. + +"No, fifty," replied the latter. + +"All right. Fifty imperials... that I will drink a whole bottle of +rum without taking it from my mouth, sitting outside the window on +this spot" (he stooped and pointed to the sloping ledge outside the +window) "and without holding on to anything. Is that right?" + +"Quite right," said the Englishman. + +Anatole turned to the Englishman and taking him by one of the +buttons of his coat and looking down at him--the Englishman was short- +began repeating the terms of the wager to him in English. + +"Wait!" cried Dolokhov, hammering with the bottle on the window sill +to attract attention. "Wait a bit, Kuragin. Listen! If anyone else +does the same, I will pay him a hundred imperials. Do you understand?" + +The Englishman nodded, but gave no indication whether he intended to +accept this challenge or not. Anatole did not release him, and +though he kept nodding to show that he understood, Anatole went on +translating Dolokhov's words into English. A thin young lad, an hussar +of the Life Guards, who had been losing that evening, climbed on the +window sill, leaned over, and looked down. + +"Oh! Oh! Oh!" he muttered, looking down from the window at the +stones of the pavement. + +"Shut up!" cried Dolokhov, pushing him away from the window. The lad +jumped awkwardly back into the room, tripping over his spurs. + +Placing the bottle on the window sill where he could reach it +easily, Dolokhov climbed carefully and slowly through the window and +lowered his legs. Pressing against both sides of the window, he +adjusted himself on his seat, lowered his hands, moved a little to the +right and then to the left, and took up the bottle. Anatole brought +two candles and placed them on the window sill, though it was +already quite light. Dolokhov's back in his white shirt, and his curly +head, were lit up from both sides. Everyone crowded to the window, the +Englishman in front. Pierre stood smiling but silent. One man, older +than the others present, suddenly pushed forward with a scared and +angry look and wanted to seize hold of Dolokhov's shirt. + +"I say, this is folly! He'll be killed," said this more sensible +man. + +Anatole stopped him. + +"Don't touch him! You'll startle him and then he'll be killed. +Eh?... What then?... Eh?" + +Dolokhov turned round and, again holding on with both hands, +arranged himself on his seat. + +"If anyone comes meddling again," said he, emitting the words +separately through his thin compressed lips, "I will throw him down +there. Now then!" + +Saying this he again turned round, dropped his hands, took the +bottle and lifted it to his lips, threw back his head, and raised +his free hand to balance himself. One of the footmen who had stooped +to pick up some broken glass remained in that position without +taking his eyes from the window and from Dolokhov's back. Anatole +stood erect with staring eyes. The Englishman looked on sideways, +pursing up his lips. The man who had wished to stop the affair ran +to a corner of the room and threw himself on a sofa with his face to +the wall. Pierre hid his face, from which a faint smile forgot to fade +though his features now expressed horror and fear. All were still. +Pierre took his hands from his eyes. Dolokhov still sat in the same +position, only his head was thrown further back till his curly hair +touched his shirt collar, and the hand holding the bottle was lifted +higher and higher and trembled with the effort. The bottle was +emptying perceptibly and rising still higher and his head tilting +yet further back. "Why is it so long?" thought Pierre. It seemed to +him that more than half an hour had elapsed. Suddenly Dolokhov made +a backward movement with his spine, and his arm trembled nervously; +this was sufficient to cause his whole body to slip as he sat on the +sloping ledge. As he began slipping down, his head and arm wavered +still more with the strain. One hand moved as if to clutch the +window sill, but refrained from touching it. Pierre again covered +his eyes and thought he would never never them again. Suddenly he +was aware of a stir all around. He looked up: Dolokhov was standing on +the window sill, with a pale but radiant face. + +"It's empty." + +He threw the bottle to the Englishman, who caught it neatly. +Dolokhov jumped down. He smelt strongly of rum. + +"Well done!... Fine fellow!... There's a bet for you!... Devil +take you!" came from different sides. + +The Englishman took out his purse and began counting out the +money. Dolokhov stood frowning and did not speak. Pierre jumped upon +the window sill. + +"Gentlemen, who wishes to bet with me? I'll do the same thing!" he +suddenly cried. "Even without a bet, there! Tell them to bring me a +bottle. I'll do it.... Bring a bottle!" + +"Let him do it, let him do it," said Dolokhov, smiling. + +"What next? Have you gone mad?... No one would let you!... Why, +you go giddy even on a staircase," exclaimed several voices. + +"I'll drink it! Let's have a bottle of rum!" shouted Pierre, banging +the table with a determined and drunken gesture and preparing to climb +out of the window. + +They seized him by his arms; but he was so strong that everyone +who touched him was sent flying. + +"No, you'll never manage him that way," said Anatole. "Wait a bit +and I'll get round him.... Listen! I'll take your bet tomorrow, but +now we are all going to ----'s." + +"Come on then," cried Pierre. "Come on!... And we'll take Bruin with +us." + +And he caught the bear, took it in his arms, lifted it from the +ground, and began dancing round the room with it. + + + + + +CHAPTER X + + +Prince Vasili kept the promise he had given to Princess +Drubetskaya who had spoken to him on behalf of her only son Boris on +the evening of Anna Pavlovna's soiree. The matter was mentioned to the +Emperor, an exception made, and Boris transferred into the regiment of +Semenov Guards with the rank of cornet. He received, however, no +appointment to Kutuzov's staff despite all Anna Mikhaylovna's +endeavors and entreaties. Soon after Anna Pavlovna's reception Anna +Mikhaylovna returned to Moscow and went straight to her rich +relations, the Rostovs, with whom she stayed when in the town and +where her darling Bory, who had only just entered a regiment +of the line and was being at once transferred to the Guards as a +cornet, had been educated from childhood and lived for years at a +time. The Guards had already left Petersburg on the tenth of August, +and her son, who had remained in Moscow for his equipment, was to join +them on the march to Radzivilov. + +It was St. Natalia's day and the name day of two of the Rostovs--the +mother and the youngest daughter--both named Nataly. Ever since the +morning, carriages with six horses had been coming and going +continually, bringing visitors to the Countess Rostova's big house +on the Povarskaya, so well known to all Moscow. The countess herself +and her handsome eldest daughter were in the drawing-room with the +visitors who came to congratulate, and who constantly succeeded one +another in relays. + +The countess was a woman of about forty-five, with a thin Oriental +type of face, evidently worn out with childbearing--she had had +twelve. A languor of motion and speech, resulting from weakness, +gave her a distinguished air which inspired respect. Princess Anna + +Mikhaylovna Drubetskaya, who as a member of the household was also +seated in the drawing room, helped to receive and entertain the +visitors. The young people were in one of the inner rooms, not +considering it necessary to take part in receiving the visitors. The +count met the guests and saw them off, inviting them all to dinner. + +"I am very, very grateful to you, mon cher," or "ma chere"--he +called everyone without exception and without the slightest +variation in his tone, "my dear," whether they were above or below him +in rank--"I thank you for myself and for our two dear ones whose +name day we are keeping. But mind you come to dinner or I shall be +offended, ma chere! On behalf of the whole family I beg you to come, +mon cher!" These words he repeated to everyone without exception or +variation, and with the same expression on his full, cheerful, +clean-shaven face, the same firm pressure of the hand and the same +quick, repeated bows. As soon as he had seen a visitor off he returned +to one of those who were still in the drawing room, drew a chair +toward him or her, and jauntily spreading out his legs and putting his +hands on his knees with the air of a man who enjoys life and knows how +to live, he swayed to and fro with dignity, offered surmises about the +weather, or touched on questions of health, sometimes in Russian and +sometimes in very bad but self-confident French; then again, like a +man weary but unflinching in the fulfillment of duty, he rose to see +some visitors off and, stroking his scanty gray hairs over his bald +patch, also asked them to dinner. Sometimes on his way back from the +anteroom he would pass through the conservatory and pantry into the +large marble dining hall, where tables were being set out for eighty +people; and looking at the footmen, who were bringing in silver and +china, moving tables, and unfolding damask table linen, he would +call Dmitri Vasilevich, a man of good family and the manager of all +his affairs, and while looking with pleasure at the enormous table +would say: "Well, Dmitri, you'll see that things are all as they +should be? That's right! The great thing is the serving, that's it." +And with a complacent sigh he would return to the drawing room. + +"Marya Lvovna Karagina and her daughter!" announced the countess' +gigantic footman in his bass voice, entering the drawing room. The +countess reflected a moment and took a pinch from a gold snuffbox with +her husband's portrait on it. + +"I'm quite worn out by these callers. However, I'll see her and no +more. She is so affected. Ask her in," she said to the footman in a +sad voice, as if saying: "Very well, finish me off." + +A tall, stout, and proud-looking woman, with a round-faced smiling +daughter, entered the drawing room, their dresses rustling. + +"Dear Countess, what an age... She has been laid up, poor child... +at the Razumovski's ball... and Countess Apraksina... I was so +delighted..." came the sounds of animated feminine voices, +interrupting one another and mingling with the rustling of dresses and +the scraping of chairs. Then one of those conversations began which +last out until, at the first pause, the guests rise with a rustle of +dresses and say, "I am so delighted... Mamma's health... and +Countess Apraksina..." and then, again rustling, pass into the +anteroom, put on cloaks or mantles, and drive away. The conversation +was on the chief topic of the day: the illness of the wealthy and +celebrated beau of Catherine's day, Count Bezukhov, and about his +illegitimate son Pierre, the one who had behaved so improperly at Anna +Pavlovna's reception. + +"I am so sorry for the poor count," said the visitor. "He is in such +bad health, and now this vexation about his son is enough to kill +him!" + +"What is that?" asked the countess as if she did not know what the +visitor alluded to, though she had already heard about the cause of +Count Bezukhov's distress some fifteen times. + +"That's what comes of a modern education," exclaimed the visitor. +"It seems that while he was abroad this young man was allowed to do as +he liked, now in Petersburg I hear he has been doing such terrible +things that he has been expelled by the police." + +"You don't say so!" replied the countess. + +"He chose his friends badly," interposed Anna Mikhaylovna. "Prince +Vasili's son, he, and a certain Dolokhov have, it is said, been up +to heaven only knows what! And they have had to suffer for it. +Dolokhov has been degraded to the ranks and Bezukhov's son sent back +to Moscow. Anatole Kuragin's father managed somehow to get his son's +affair hushed up, but even he was ordered out of Petersburg." + +"But what have they been up to?" asked the countess. + +"They are regular brigands, especially Dolokhov," replied the +visitor. "He is a son of Marya Ivanovna Dolokhova, such a worthy +woman, but there, just fancy! Those three got hold of a bear +somewhere, put it in a carriage, and set off with it to visit some +actresses! The police tried to interfere, and what did the young men +do? They tied a policeman and the bear back to back and put the bear +into the Moyka Canal. And there was the bear swimming about with the +policeman on his back!" + +"What a nice figure the policeman must have cut, my dear!" shouted +the count, dying with laughter. + +"Oh, how dreadful! How can you laugh at it, Count?" + +Yet the ladies themselves could not help laughing. + +"It was all they could do to rescue the poor man," continued the +visitor. "And to think it is Cyril Vladimirovich Bezukhov's son who +amuses himself in this sensible manner! And he was said to be so +well educated and clever. This is all that his foreign education has +done for him! I hope that here in Moscow no one will receive him, in +spite of his money. They wanted to introduce him to me, but I quite +declined: I have my daughters to consider." + +"Why do you say this young man is so rich?" asked the countess, +turning away from the girls, who at once assumed an air of +inattention. "His children are all illegitimate. I think Pierre also +is illegitimate." + +The visitor made a gesture with her hand. + +"I should think he has a score of them." + +Princess Anna Mikhaylovna intervened in the conversation, +evidently wishing to show her connections and knowledge of what went +on in society. + +"The fact of the matter is," said she significantly, and also in a +half whisper, "everyone knows Count Cyril's reputation.... He has lost +count of his children, but this Pierre was his favorite." + +"How handsome the old man still was only a year ago!" remarked the +countess. "I have never seen a handsomer man." + +"He is very much altered now," said Anna Mikhaylovna. "Well, as I +was saying, Prince Vasili is the next heir through his wife, but the +count is very fond of Pierre, looked after his education, and wrote to +the Emperor about him; so that in the case of his death--and he is +so ill that he may die at any moment, and Dr. Lorrain has come from +Petersburg--no one knows who will inherit his immense fortune, +Pierre or Prince Vasili. Forty thousand serfs and millions of +rubles! I know it all very well for Prince Vasili told me himself. +Besides, Cyril Vladimirovich is my mother's second cousin. He's also +my Bory's godfather," she added, as if she attached no importance at +all to the fact. + +"Prince Vasili arrived in Moscow yesterday. I hear he has come on +some inspection business," remarked the visitor. + +"Yes, but between ourselves," said the princess, "that is a +pretext. The fact is he has come to see Count Cyril Vladimirovich, +hearing how ill he is." + +"But do you know, my dear, that was a capital joke," said the count; +and seeing that the elder visitor was not listening, he turned to +the young ladies. "I can just imagine what a funny figure that +policeman cut!" + +And as he waved his arms to impersonate the policeman, his portly +form again shook with a deep ringing laugh, the laugh of one who +always eats well and, in particular, drinks well. "So do come and dine +with us!" he said. + + + + + +CHAPTER XI + + +Silence ensued. The countess looked at her callers, smiling affably, +but not concealing the fact that she would not be distressed if they +now rose and took their leave. The visitor's daughter was already +smoothing down her dress with an inquiring look at her mother, when +suddenly from the next room were heard the footsteps of boys and girls +running to the door and the noise of a chair falling over, and a +girl of thirteen, hiding something in the folds of her short muslin +frock, darted in and stopped short in the middle of the room. It was +evident that she had not intended her flight to bring her so far. +Behind her in the doorway appeared a student with a crimson coat +collar, an officer of the Guards, a girl of fifteen, and a plump +rosy-faced boy in a short jacket. + +The count jumped up and, swaying from side to side, spread his +arms wide and threw them round the little girl who had run in. + +"Ah, here she is!" he exclaimed laughing. "My pet, whose name day it +is. My dear pet!" + +"Ma chere, there is a time for everything," said the countess with +feigned severity. "You spoil her, Ilya," she added, turning to her +husband. + +"How do you do, my dear? I wish you many happy returns of your +name day," said the visitor. "What a charming child," she added, +addressing the mother. + +This black-eyed, wide-mouthed girl, not pretty but full of life- +with childish bare shoulders which after her run heaved and shook +her bodice, with black curls tossed backward, thin bare arms, little +legs in lace-frilled drawers, and feet in low slippers--was just at +that charming age when a girl is no longer a child, though the child +is not yet a young woman. Escaping from her father she ran to hide her +flushed face in the lace of her mother's mantilla--not paying the +least attention to her severe remark--and began to laugh. She laughed, +and in fragmentary sentences tried to explain about a doll which she +produced from the folds of her frock. + +"Do you see?... My doll... Mimi... You see..." was all Natasha +managed to utter (to her everything seemed funny). She leaned +against her mother and burst into such a loud, ringing fit of laughter +that even the prim visitor could not help joining in. + +"Now then, go away and take your monstrosity with you," said the +mother, pushing away her daughter with pretended sternness, and +turning to the visitor she added: "She is my youngest girl." + +Natasha, raising her face for a moment from her mother's mantilla, +glanced up at her through tears of laughter, and again hid her face. + +The visitor, compelled to look on at this family scene, thought it +necessary to take some part in it. + +"Tell me, my dear," said she to Natasha, "is Mimi a relation of +yours? A daughter, I suppose?" + +Natasha did not like the visitor's tone of condescension to childish +things. She did not reply, but looked at her seriously. + +Meanwhile the younger generation: Boris, the officer, Anna +Mikhaylovna's son; Nicholas, the undergraduate, the count's eldest +son; Sonya, the count's fifteen-year-old niece, and little Petya, +his youngest boy, had all settled down in the drawing room and were +obviously trying to restrain within the bounds of decorum the +excitement and mirth that shone in all their faces. Evidently in the +back rooms, from which they had dashed out so impetuously, the +conversation had been more amusing than the drawing-room talk of +society scandals, the weather, and Countess Apraksina. Now and then +they glanced at one another, hardly able to suppress their laughter. + +The two young men, the student and the officer, friends from +childhood, were of the same age and both handsome fellows, though +not alike. Boris was tall and fair, and his calm and handsome face had +regular, delicate features. Nicholas was short with curly hair and +an open expression. Dark hairs were already showing on his upper +lip, and his whole face expressed impetuosity and enthusiasm. Nicholas +blushed when he entered the drawing room. He evidently tried to find +something to say, but failed. Boris on the contrary at once found +his footing, and related quietly and humorously how he had know that +doll Mimi when she was still quite a young lady, before her nose was +broken; how she had aged during the five years he had known her, and +how her head had cracked right across the skull. Having said this he +glanced at Natasha. She turned away from him and glanced at her +younger brother, who was screwing up his eyes and shaking with +suppressed laughter, and unable to control herself any longer, she +jumped up and rushed from the room as fast as her nimble little feet +would carry her. Boris did not laugh. + +"You were meaning to go out, weren't you, Mamma? Do you want the +carriage?" he asked his mother with a smile. + +"Yes, yes, go and tell them to get it ready," she answered, +returning his smile. + +Boris quietly left the room and went in search of Natasha. The plump +boy ran after them angrily, as if vexed that their program had been +disturbed. + + + + + +CHAPTER XII + + +The only young people remaining in the drawing room, not counting +the young lady visitor and the countess' eldest daughter (who was four +years older than her sister and behaved already like a grown-up +person), were Nicholas and Sonya, the niece. Sonya was a slender +little brunette with a tender look in her eyes which were veiled by +long lashes, thick black plaits coiling twice round her head, and a +tawny tint in her complexion and especially in the color of her +slender but graceful and muscular arms and neck. By the grace of her +movements, by the softness and flexibility of her small limbs, and +by a certain coyness and reserve of manner, she reminded one of a +pretty, half-grown kitten which promises to become a beautiful +little cat. She evidently considered it proper to show an interest +in the general conversation by smiling, but in spite of herself her +eyes under their thick long lashes watched her cousin who was going to +join the army, with such passionate girlish adoration that her smile +could not for a single instant impose upon anyone, and it was clear +that the kitten had settled down only to spring up with more energy +and again play with her cousin as soon as they too could, like Natasha +and Boris, escape from the drawing room. + +"Ah yes, my dear," said the count, addressing the visitor and +pointing to Nicholas, "his friend Boris has become an officer, and +so for friendship's sake he is leaving the university and me, his +old father, and entering the military service, my dear. And there +was a place and everything waiting for him in the Archives Department! +Isn't that friendship?" remarked the count in an inquiring tone. + +"But they say that war has been declared," replied the visitor. + +"They've been saying so a long while," said the count, "and +they'll say so again and again, and that will be the end of it. My +dear, there's friendship for you," he repeated. "He's joining the +hussars." + +The visitor, not knowing what to say, shook her head. + +"It's not at all from friendship," declared Nicholas, flaring up and +turning away as if from a shameful aspersion. "It is not from +friendship at all; I simply feel that the army is my vocation." + +He glanced at his cousin and the young lady visitor; and they were +both regarding him with a smile of approbation. + +"Schubert, the colonel of the Pavlograd Hussars, is dining with us +today. He has been here on leave and is taking Nicholas back with him. +It can't be helped!" said the count, shrugging his shoulders and +speaking playfully of a matter that evidently distressed him. + +"I have already told you, Papa," said his son, "that if you don't +wish to let me go, I'll stay. But I know I am no use anywhere except +in the army; I am not a diplomat or a government clerk.--I don't +know how to hide what I feel." As he spoke he kept glancing with the +flirtatiousness of a handsome youth at Sonya and the young lady +visitor. + +The little kitten, feasting her eyes on him, seemed ready at any +moment to start her gambols again and display her kittenish nature. + +"All right, all right!" said the old count. "He always flares up! +This Buonaparte has turned all their heads; they all think of how he +rose from an ensign and became Emperor. Well, well, God grant it," +he added, not noticing his visitor's sarcastic smile. + +The elders began talking about Bonaparte. Julie Karagina turned to +young Rostov. + +"What a pity you weren't at the Arkharovs' on Thursday. It was so +dull without you," said she, giving him a tender smile. + +The young man, flattered, sat down nearer to her with a coquettish +smile, and engaged the smiling Julie in a confidential conversation +without at all noticing that his involuntary smile had stabbed the +heart of Sonya, who blushed and smiled unnaturally. In the midst of +his talk he glanced round at her. She gave him a passionately angry +glance, and hardly able to restrain her tears and maintain the +artificial smile on her lips, she got up and left the room. All +Nicholas' animation vanished. He waited for the first pause in the +conversation, and then with a distressed face left the room to find +Sonya. + +"How plainly all these young people wear their hearts on their +sleeves!" said Anna Mikhaylovna, pointing to Nicholas as he went +out. "Cousinage--dangereux voisinage;"* she added. + + +*Cousinhood is a dangerous neighborhood. + + +"Yes," said the countess when the brightness these young people +had brought into the room had vanished; and as if answering a question +no one had put but which was always in her mind, "and how much +suffering, how much anxiety one has had to go through that we might +rejoice in them now! And yet really the anxiety is greater now than +the joy. One is always, always anxious! Especially just at this age, +so dangerous both for girls and boys." + +"It all depends on the bringing up," remarked the visitor. + +"Yes, you're quite right," continued the countess. "Till now I +have always, thank God, been my children's friend and had their full +confidence," said she, repeating the mistake of so many parents who +imagine that their children have no secrets from them. "I know I shall +always be my daughters' first confidante, and that if Nicholas, with +his impulsive nature, does get into mischief (a boy can't help it), he +will all the same never be like those Petersburg young men." + +"Yes, they are splendid, splendid youngsters," chimed in the +count, who always solved questions that seemed to him perplexing by +deciding that everything was splendid. "Just fancy: wants to be an +hussar. What's one to do, my dear?" + +"What a charming creature your younger girl is," said the visitor; +"a little volcano!" + +"Yes, a regular volcano," said the count. "Takes after me! And +what a voice she has; though she's my daughter, I tell the truth +when I say she'll be a singer, a second Salomoni! We have engaged an +Italian to give her lessons." + +"Isn't she too young? I have heard that it harms the voice to +train it at that age." + +"Oh no, not at all too young!" replied the count. "Why, our +mothers used to be married at twelve or thirteen." + +"And she's in love with Boris already. Just fancy!" said the +countess with a gentle smile, looking at Boris' and went on, evidently +concerned with a thought that always occupied her: "Now you see if I +were to be severe with her and to forbid it... goodness knows what +they might be up to on the sly" (she meant that they would be +kissing), "but as it is, I know every word she utters. She will come +running to me of her own accord in the evening and tell me everything. +Perhaps I spoil her, but really that seems the best plan. With her +elder sister I was stricter." + +"Yes, I was brought up quite differently," remarked the handsome +elder daughter, Countess Vera, with a smile. + +But the smile did not enhance Vera's beauty as smiles generally +do; on the contrary it gave her an unnatural, and therefore +unpleasant, expression. Vera was good-looking, not at all stupid, +quick at learning, was well brought up, and had a pleasant voice; what +she said was true and appropriate, yet, strange to say, everyone- +the visitors and countess alike--turned to look at her as if wondering +why she had said it, and they all felt awkward. + +"People are always too clever with their eldest children and try +to make something exceptional of them," said the visitor. + +"What's the good of denying it, my dear? Our dear countess was too +clever with Vera," said the count. "Well, what of that? She's turned +out splendidly all the same," he added, winking at Vera. + +The guests got up and took their leave, promising to return to +dinner. + +"What manners! I thought they would never go," said the countess, +when she had seen her guests out. + + + + + +CHAPTER XIII + + +When Natasha ran out of the drawing room she only went as far as the +conservatory. There she paused and stood listening to the conversation +in the drawing room, waiting for Boris to come out. She was already +growing impatient, and stamped her foot, ready to cry at his not +coming at once, when she heard the young man's discreet steps +approaching neither quickly nor slowly. At this Natasha dashed swiftly +among the flower tubs and hid there. + +Boris paused in the middle of the room, looked round, brushed a +little dust from the sleeve of his uniform, and going up to a mirror +examined his handsome face. Natasha, very still, peered out from her +ambush, waiting to see what he would do. He stood a little while +before the glass, smiled, and walked toward the other door. Natasha +was about to call him but changed her mind. "Let him look for me," +thought she. Hardly had Boris gone than Sonya, flushed, in tears, +and muttering angrily, came in at the other door. Natasha checked +her first impulse to run out to her, and remained in her hiding place, +watching--as under an invisible cap--to see what went on in the world. +She was experiencing a new and peculiar pleasure. Sonya, muttering +to herself, kept looking round toward the drawing-room door. It opened +and Nicholas came in. + +"Sonya, what is the matter with you? How can you?" said he, +running up to her. + +"It's nothing, nothing; leave me alone!" sobbed Sonya. + +"Ah, I know what it is." + +"Well, if you do, so much the better, and you can go back to her!" + +"So-o-onya! Look here! How can you torture me and yourself like +that, for a mere fancy?" said Nicholas taking her hand. + +Sonya did not pull it away, and left off crying. Natasha, not +stirring and scarcely breathing, watched from her ambush with +sparkling eyes. "What will happen now?" thought she. + +"Sonya! What is anyone in the world to me? You alone are +everything!" said Nicholas. "And I will prove it to you." + +"I don't like you to talk like that." + +"Well, then, I won't; only forgive me, Sonya!" He drew her to him +and kissed her. + +"Oh, how nice," thought Natasha; and when Sonya and Nicholas had +gone out of the conservatory she followed and called Boris to her. + +"Boris, come here," said she with a sly and significant look. "I +have something to tell you. Here, here!" and she led him into the +conservatory to the place among the tubs where she had been hiding. + +Boris followed her, smiling. + +"What is the something?" asked he. + +She grew confused, glanced round, and, seeing the doll she had +thrown down on one of the tubs, picked it up. + +"Kiss the doll," said she. + +Boris looked attentively and kindly at her eager face, but did not +reply. + +"Don't you want to? Well, then, come here," said she, and went +further in among the plants and threw down the doll. "Closer, closer!" +she whispered. + +She caught the young officer by his cuffs, and a look of solemnity +and fear appeared on her flushed face. + +"And me? Would you like to kiss me?" she whispered almost inaudibly, +glancing up at him from under her brows, smiling, and almost crying +from excitement. + +Boris blushed. + +"How funny you are!" he said, bending down to her and blushing still +more, but he waited and did nothing. + +Suddenly she jumped up onto a tub to be higher than he, embraced him +so that both her slender bare arms clasped him above his neck, and, +tossing back her hair, kissed him full on the lips. + +Then she slipped down among the flowerpots on the other side of +the tubs and stood, hanging her head. + +"Natasha," he said, "you know that I love you, but..." + +"You are in love with me?" Natasha broke in. + +"Yes, I am, but please don't let us do like that.... In another four +years... then I will ask for your hand." + +Natasha considered. + +"Thirteen, fourteen, fifteen, sixteen," she counted on her slender +little fingers. "All right! Then it's settled?" + +A smile of joy and satisfaction lit up her eager face. + +"Settled!" replied Boris. + +"Forever?" said the little girl. "Till death itself?" + +She took his arm and with a happy face went with him into the +adjoining sitting room. + + + + + +CHAPTER XIV + + +After receiving her visitors, the countess was so tired that she +gave orders to admit no more, but the porter was told to be sure to +invite to dinner all who came "to congratulate." The countess wished +to have a tete-a-tete talk with the friend of her childhood, +Princess Anna Mikhaylovna, whom she had not seen properly since she +returned from Petersburg. Anna Mikhaylovna, with her tear-worn but +pleasant face, drew her chair nearer to that of the countess. + +"With you I will be quite frank," said Anna Mikhaylovna. "There +are not many left of us old friends! That's why I so value your +friendship." + +Anna Mikhaylovna looked at Vera and paused. The countess pressed her +friend's hand. + +"Vera," she said to her eldest daughter who was evidently not a +favorite, "how is it you have so little tact? Don't you see you are +not wanted here? Go to the other girls, or..." + +The handsome Vera smiled contemptuously but did not seem at all +hurt. + +"If you had told me sooner, Mamma, I would have gone," she replied +as she rose to go to her own room. + +But as she passed the sitting room she noticed two couples +sitting, one pair at each window. She stopped and smiled scornfully. +Sonya was sitting close to Nicholas who was copying out some verses +for her, the first he had ever written. Boris and Natasha were at +the other window and ceased talking when Vera entered. Sonya and +Natasha looked at Vera with guilty, happy faces. + +It was pleasant and touching to see these little girls in love; +but apparently the sight of them roused no pleasant feeling in Vera. + +"How often have I asked you not to take my things?" she said. "You +have a room of your own," and she took the inkstand from Nicholas. + +"In a minute, in a minute," he said, dipping his pen. + +"You always manage to do things at the wrong time," continued +Vera. "You came rushing into the drawing room so that everyone felt +ashamed of you." + +Though what she said was quite just, perhaps for that very reason no +one replied, and the four simply looked at one another. She lingered +in the room with the inkstand in her hand. + +"And at your age what secrets can there be between Natasha and +Boris, or between you two? It's all nonsense!" + +"Now, Vera, what does it matter to you?" said Natasha in defense, +speaking very gently. + +She seemed that day to be more than ever kind and affectionate to +everyone. + +"Very silly," said Vera. "I am ashamed of you. Secrets indeed!" + +"All have secrets of their own," answered Natasha, getting warmer. +"We don't interfere with you and Berg." + +"I should think not," said Vera, "because there can never be +anything wrong in my behavior. But I'll just tell Mamma how you are +behaving with Boris." + +"Natalya Ilynichna behaves very well to me," remarked Boris. "I have +nothing to complain of." + +"Don't, Boris! You are such a diplomat that it is really +tiresome," said Natasha in a mortified voice that trembled slightly. +(She used the word "diplomat," which was just then much in vogue among +the children, in the special sense they attached to it.) "Why does she +bother me?" And she added, turning to Vera, "You'll never understand +it, because you've never loved anyone. You have no heart! You are a +Madame de Genlis and nothing more" (this nickname, bestowed on Vera by +Nicholas, was considered very stinging), "and your greatest pleasure +is to be unpleasant to people! Go and flirt with Berg as much as you +please," she finished quickly. + +"I shall at any rate not run after a young man before visitors..." + +"Well, now you've done what you wanted," put in Nicholas--"said +unpleasant things to everyone and upset them. Let's go to the +nursery." + +All four, like a flock of scared birds, got up and left the room. + +"The unpleasant things were said to me," remarked Vera, "I said none +to anyone." + +"Madame de Genlis! Madame de Genlis!" shouted laughing voices +through the door. + +The handsome Vera, who produced such an irritating and unpleasant +effect on everyone, smiled and, evidently unmoved by what had been +said to her, went to the looking glass and arranged her hair and +scarf. Looking at her own handsome face she seemed to become still +colder and calmer. + + +In the drawing room the conversation was still going on. + +"Ah, my dear," said the countess, "my life is not all roses +either. Don't I know that at the rate we are living our means won't +last long? It's all the Club and his easygoing nature. Even in the +country do we get any rest? Theatricals, hunting, and heaven knows +what besides! But don't let's talk about me; tell me how you managed +everything. I often wonder at you, Annette--how at your age you can +rush off alone in a carriage to Moscow, to Petersburg, to those +ministers and great people, and know how to deal with them all! It's +quite astonishing. How did you get things settled? I couldn't possibly +do it." + +"Ah, my love," answered Anna Mikhaylovna, "God grant you never +know what it is to be left a widow without means and with a son you +love to distraction! One learns many things then," she added with a +certain pride. "That lawsuit taught me much. When I want to see one of +those big people I write a note: 'Princess So-and-So desires an +interview with So and-So,' and then I take a cab and go myself two, +three, or four times--till I get what I want. I don't mind what they +think of me." + +"Well, and to whom did you apply about Bory?" asked the countess. +"You see yours is already an officer in the Guards, while my +Nicholas is going as a cadet. There's no one to interest himself for +him. To whom did you apply?" + +"To Prince Vasili. He was so kind. He at once agreed to +everything, and put the matter before the Emperor," said Princess Anna +Mikhaylovna enthusiastically, quite forgetting all the humiliation she +had endured to gain her end. + +"Has Prince Vasili aged much?" asked the countess. "I have not +seen him since we acted together at the Rumyantsovs' theatricals. I +expect he has forgotten me. He paid me attentions in those days," said +the countess, with a smile. + +"He is just the same as ever," replied Anna Mikhaylovna, +"overflowing with amiability. His position has not turned his head +at all. He said to me, 'I am sorry I can do so little for you, dear +Princess. I am at your command.' Yes, he is a fine fellow and a very +kind relation. But, Nataly, you know my love for my son: I would do +anything for his happiness! And my affairs are in such a bad way +that my position is now a terrible one," continued Anna Mikhaylovna, +sadly, dropping her voice. "My wretched lawsuit takes all I have and +makes no progress. Would you believe it, I have literally not a +penny and don't know how to equip Boris." She took out her +handkerchief and began to cry. "I need five hundred rubles, and have +only one twenty-five-ruble note. I am in such a state.... My only hope +now is in Count Cyril Vladimirovich Bezukhov. If he will not assist +his godson--you know he is Bory's godfather--and allow him something +for his maintenance, all my trouble will have been thrown away.... I +shall not be able to equip him." + +The countess' eyes filled with tears and she pondered in silence. + +"I often think, though, perhaps it's a sin," said the princess, +"that here lives Count Cyril Vladimirovich Bezukhov so rich, all +alone... that tremendous fortune... and what is his life worth? It's a +burden to him, and Bory's life is only just beginning...." + +"Surely he will leave something to Boris," said the countess. + +"Heaven only knows, my dear! These rich grandees are so selfish. +Still, I will take Boris and go to see him at once, and I shall +speak to him straight out. Let people think what they will of me, it's +really all the same to me when my son's fate is at stake." The +princess rose. "It's now two o'clock and you dine at four. There +will just be time." + +And like a practical Petersburg lady who knows how to make the +most of time, Anna Mikhaylovna sent someone to call her son, and +went into the anteroom with him. + +"Good-by, my dear," said she to the countess who saw her to the +door, and added in a whisper so that her son should not hear, "Wish me +good luck." + +"Are you going to Count Cyril Vladimirovich, my dear?" said the +count coming out from the dining hall into the anteroom, and he added: +"If he is better, ask Pierre to dine with us. He has been to the +house, you know, and danced with the children. Be sure to invite +him, my dear. We will see how Taras distinguishes himself today. He +says Count Orlov never gave such a dinner as ours will be!" + + + + + +CHAPTER XV + +"My dear Boris," said Princess Anna Mikhaylovna to her son as +Countess Rostova's carriage in which they were seated drove over the +straw covered street and turned into the wide courtyard of Count Cyril +Vladimirovich Bezukhov's house. "My dear Boris," said the mother, +drawing her hand from beneath her old mantle and laying it timidly and +tenderly on her son's arm, "be affectionate and attentive to him. +Count Cyril Vladimirovich is your godfather after all, your future +depends on him. Remember that, my dear, and be nice to him, as you +so well know how to be." + +"If only I knew that anything besides humiliation would come of +it..." answered her son coldly. "But I have promised and will do it +for your sake." + +Although the hall porter saw someone's carriage standing at the +entrance, after scrutinizing the mother and son (who without asking to +be announced had passed straight through the glass porch between the +rows of statues in niches) and looking significantly at the lady's old +cloak, he asked whether they wanted the count or the princesses, +and, hearing that they wished to see the count, said his excellency +was worse today, and that his excellency was not receiving anyone. + +"We may as well go back," said the son in French. + +"My dear!" exclaimed his mother imploringly, again laying her hand +on his arm as if that touch might soothe or rouse him. + +Boris said no more, but looked inquiringly at his mother without +taking off his cloak. + +"My friend," said Anna Mikhaylovna in gentle tones, addressing the +hall porter, "I know Count Cyril Vladimirovich is very ill... that's +why I have come... I am a relation. I shall not disturb him, my +friend... I only need see Prince Vasili Sergeevich: he is staying +here, is he not? Please announce me." + +The hall porter sullenly pulled a bell that rang upstairs, and +turned away. + +"Princess Drubetskaya to see Prince Vasili Sergeevich," he called to +a footman dressed in knee breeches, shoes, and a swallow-tail coat, +who ran downstairs and looked over from the halfway landing. + +The mother smoothed the folds of her dyed silk dress before a +large Venetian mirror in the wall, and in her trodden-down shoes +briskly ascended the carpeted stairs. + +"My dear," she said to her son, once more stimulating him by a +touch, "you promised me!" + +The son, lowering his eyes, followed her quietly. + +They entered the large hall, from which one of the doors led to +the apartments assigned to Prince Vasili. + +Just as the mother and son, having reached the middle of the hall, +were about to ask their way of an elderly footman who had sprung up as +they entered, the bronze handle of one of the doors turned and +Prince Vasili came out--wearing a velvet coat with a single star on +his breast, as was his custom when at home--taking leave of a +good-looking, dark-haired man. This was the celebrated Petersburg +doctor, Lorrain. + +"Then it is certain?" said the prince. + +"Prince, humanum est errare,* but..." replied the doctor, swallowing +his r's, and pronouncing the Latin words with a French accent. + + +*To err is human. + + +"Very well, very well..." + +Seeing Anna Mikhaylovna and her son, Prince Vasili dismissed the +doctor with a bow and approached them silently and with a look of +inquiry. The son noticed that an expression of profound sorrow +suddenly clouded his mother's face, and he smiled slightly. + +"Ah, Prince! In what sad circumstances we meet again! And how is our +dear invalid?" said she, as though unaware of the cold offensive +look fixed on her. + +Prince Vasili stared at her and at Boris questioningly and +perplexed. Boris bowed politely. Prince Vasili without acknowledging +the bow turned to Anna Mikhaylovna, answering her query by a +movement of the head and lips indicating very little hope for the +patient. + +"Is it possible?" exclaimed Anna Mikhaylovna. "Oh, how awful! It +is terrible to think.... This is my son," she added, indicating Boris. +"He wanted to thank you himself." + +Boris bowed again politely. + +"Believe me, Prince, a mother's heart will never forget what you +have done for us." + +"I am glad I was able to do you a service, my dear Anna +Mikhaylovna," said Prince Vasili, arranging his lace frill, and in +tone and manner, here in Moscow to Anna Mikhaylovna whom he had placed +under an obligation, assuming an air of much greater importance than +he had done in Petersburg at Anna Scherer's reception. + +"Try to serve well and show yourself worthy," added he, addressing +Boris with severity. "I am glad.... Are you here on leave?" he went on +in his usual tone of indifference. + +"I am awaiting orders to join my new regiment, your excellency," +replied Boris, betraying neither annoyance at the prince's brusque +manner nor a desire to enter into conversation, but speaking so +quietly and respectfully that the prince gave him a searching glance. + +"Are you living with your mother?" + +"I am living at Countess Rostova's," replied Boris, again adding, +"your excellency." + +"That is, with Ilya Rostov who married Nataly Shinshina," said +Anna Mikhaylovna. + +"I know, I know," answered Prince Vasili in his monotonous voice. "I +never could understand how Nataly made up her mind to marry that +unlicked bear! A perfectly absurd and stupid fellow, and a gambler +too, I am told." + +"But a very kind man, Prince," said Anna Mikhaylovna with a pathetic +smile, as though she too knew that Count Rostov deserved this censure, +but asked him not to be too hard on the poor old man. "What do the +doctors say?" asked the princess after a pause, her worn face again +expressing deep sorrow. + +"They give little hope," replied the prince. + +"And I should so like to thank Uncle once for all his kindness to me +and Boris. He is his godson," she added, her tone suggesting that this +fact ought to give Prince Vasili much satisfaction. + +Prince Vasili became thoughtful and frowned. Anna Mikhaylovna saw +that he was afraid of finding in her a rival for Count Bezukhov's +fortune, and hastened to reassure him. + +"If it were not for my sincere affection and devotion to Uncle," +said she, uttering the word with peculiar assurance and unconcern, +"I know his character: noble, upright... but you see he has no one +with him except the young princesses.... They are still young...." She +bent her head and continued in a whisper: "Has he performed his +final duty, Prince? How priceless are those last moments! It can +make things no worse, and it is absolutely necessary to prepare him if +he is so ill. We women, Prince," and she smiled tenderly, "always know +how to say these things. I absolutely must see him, however painful it +may be for me. I am used to suffering." + +Evidently the prince understood her, and also understood, as he +had done at Anna Pavlovna's, that it would be difficult to get rid +of Anna Mikhaylovna. + +"Would not such a meeting be too trying for him, dear Anna +Mikhaylovna?" said he. "Let us wait until evening. The doctors are +expecting a crisis." + +"But one cannot delay, Prince, at such a moment! Consider that the +welfare of his soul is at stake. Ah, it is awful: the duties of a +Christian..." + +A door of one of the inner rooms opened and one of the princesses, +the count's niece, entered with a cold, stern face. The length of +her body was strikingly out of proportion to her short legs. Prince +Vasili turned to her. + +"Well, how is he?" + +"Still the same; but what can you expect, this noise..." said the +princess, looking at Anna Mikhaylovna as at a stranger. + +"Ah, my dear, I hardly knew you," said Anna Mikhaylovna with a happy +smile, ambling lightly up to the count's niece. "I have come, and am +at your service to help you nurse my uncle. I imagine what you have +gone through," and she sympathetically turned up her eyes. + +The princess gave no reply and did not even smile, but left the room +as Anna Mikhaylovna took off her gloves and, occupying the position +she had conquered, settled down in an armchair, inviting Prince Vasili +to take a seat beside her. + +"Boris," she said to her son with a smile, "I shall go in to see the +count, my uncle; but you, my dear, had better go to Pierre meanwhile +and don't forget to give him the Rostovs' invitation. They ask him +to dinner. I suppose he won't go?" she continued, turning to the +prince. + +"On the contrary," replied the prince, who had plainly become +depressed, "I shall be only too glad if you relieve me of that young +man.... Here he is, and the count has not once asked for him." + +He shrugged his shoulders. A footman conducted Boris down one flight +of stairs and up another, to Pierre's rooms. + + + + + +CHAPTER XVI + + +Pierre, after all, had not managed to choose a career for himself in +Petersburg, and had been expelled from there for riotous conduct and +sent to Moscow. The story told about him at Count Rostov's was true. +Pierre had taken part in tying a policeman to a bear. He had now +been for some days in Moscow and was staying as usual at his +father's house. Though he expected that the story of his escapade +would be already known in Moscow and that the ladies about his father- +who were never favorably disposed toward him--would have used it to +turn the count against him, he nevertheless on the day of his +arrival went to his father's part of the house. Entering the drawing +room, where the princesses spent most of their time, he greeted the +ladies, two of whom were sitting at embroidery frames while a third +read aloud. It was the eldest who was reading--the one who had met +Anna Mikhaylovna. The two younger ones were embroidering: both were +rosy and pretty and they differed only in that one had a little mole +on her lip which made her much prettier. Pierre was received as if +he were a corpse or a leper. The eldest princess paused in her reading +and silently stared at him with frightened eyes; the second assumed +precisely the same expression; while the youngest, the one with the +mole, who was of a cheerful and lively disposition, bent over her +frame to hide a smile probably evoked by the amusing scene she +foresaw. She drew her wool down through the canvas and, scarcely +able to refrain from laughing, stooped as if trying to make out the +pattern. + +"How do you do, cousin?" said Pierre. "You don't recognize me?" + +"I recognize you only too well, too well." + +"How is the count? Can I see him?" asked Pierre, awkwardly as usual, +but unabashed. + +"The count is suffering physically and mentally, and apparently +you have done your best to increase his mental sufferings." + +"Can I see the count?" Pierre again asked. + +"Hm.... If you wish to kill him, to kill him outright, you can see +him... Olga, go and see whether Uncle's beef tea is ready--it is +almost time," she added, giving Pierre to understand that they were +busy, and busy making his father comfortable, while evidently he, +Pierre, was only busy causing him annoyance. + +Olga went out. Pierre stood looking at the sisters; then he bowed +and said: "Then I will go to my rooms. You will let me know when I can +see him." + +And he left the room, followed by the low but ringing laughter of +the sister with the mole. + +Next day Prince Vasili had arrived and settled in the count's house. +He sent for Pierre and said to him: "My dear fellow, if you are +going to behave here as you did in Petersburg, you will end very +badly; that is all I have to say to you. The count is very, very +ill, and you must not see him at all." + +Since then Pierre had not been disturbed and had spent the whole +time in his rooms upstairs. + +When Boris appeared at his door Pierre was pacing up and down his +room, stopping occasionally at a corner to make menacing gestures at +the wall, as if running a sword through an invisible foe, and +glaring savagely over his spectacles, and then again resuming his +walk, muttering indistinct words, shrugging his shoulders and +gesticulating. + +"England is done for," said he, scowling and pointing his finger +at someone unseen. "Mr. Pitt, as a traitor to the nation and to the +rights of man, is sentenced to..." But before Pierre--who at that +moment imagined himself to be Napoleon in person and to have just +effected the dangerous crossing of the Straits of Dover and captured +London--could pronounce Pitt's sentence, he saw a well-built and +handsome young officer entering his room. Pierre paused. He had left +Moscow when Boris was a boy of fourteen, and had quite forgotten +him, but in his usual impulsive and hearty way he took Boris by the +hand with a friendly smile. + +"Do you remember me?" asked Boris quietly with a pleasant smile. +"I have come with my mother to see the count, but it seems he is not +well." + +"Yes, it seems he is ill. People are always disturbing him," +answered Pierre, trying to remember who this young man was. + +Boris felt that Pierre did not recognize him but did not consider it +necessary to introduce himself, and without experiencing the least +embarrassment looked Pierre straight in the face. + +"Count Rostov asks you to come to dinner today," said he, after a +considerable pause which made Pierre feel uncomfortable. + +"Ah, Count Rostov!" exclaimed Pierre joyfully. "Then you are his +son, Ilya? Only fancy, I didn't know you at first. Do you remember how +we went to the Sparrow Hills with Madame Jacquot?... It's such an +age..." + +"You are mistaken," said Boris deliberately, with a bold and +slightly sarcastic smile. "I am Boris, son of Princess Anna +Mikhaylovna Drubetskaya. Rostov, the father, is Ilya, and his son is +Nicholas. I never knew any Madame Jacquot." + +Pierre shook his head and arms as if attacked by mosquitoes or bees. + +"Oh dear, what am I thinking about? I've mixed everything up. One +has so many relatives in Moscow! So you are Boris? Of course. Well, +now we know where we are. And what do you think of the Boulogne +expedition? The English will come off badly, you know, if Napoleon +gets across the Channel. I think the expedition is quite feasible. +If only Villeneuve doesn't make a mess of things!" + +Boris knew nothing about the Boulogne expedition; he did not read +the papers and it was the first time he had heard Villeneuve's name. + +"We here in Moscow are more occupied with dinner parties and scandal +than with politics," said he in his quiet ironical tone. "I know +nothing about it and have not thought about it. Moscow is chiefly busy +with gossip," he continued. "Just now they are talking about you and +your father." + +Pierre smiled in his good-natured way as if afraid for his +companion's sake that the latter might say something he would +afterwards regret. But Boris spoke distinctly, clearly, and dryly, +looking straight into Pierre's eyes. + +"Moscow has nothing else to do but gossip," Boris went on. +"Everybody is wondering to whom the count will leave his fortune, +though he may perhaps outlive us all, as I sincerely hope he will..." + +"Yes, it is all very horrid," interrupted Pierre, "very horrid." + +Pierre was still afraid that this officer might inadvertently say +something disconcerting to himself. + +"And it must seem to you," said Boris flushing slightly, but not +changing his tone or attitude, "it must seem to you that everyone is +trying to get something out of the rich man?" + +"So it does," thought Pierre. + +"But I just wish to say, to avoid misunderstandings, that you are +quite mistaken if you reckon me or my mother among such people. We are +very poor, but for my own part at any rate, for the very reason that +your father is rich, I don't regard myself as a relation of his, and +neither I nor my mother would ever ask or take anything from him." + +For a long time Pierre could not understand, but when he did, he +jumped up from the sofa, seized Boris under the elbow in his quick, +clumsy way, and, blushing far more than Boris, began to speak with a +feeling of mingled shame and vexation. + +"Well, this is strange! Do you suppose I... who could think?... I +know very well..." + +But Boris again interrupted him. + +"I am glad I have spoken out fully. Perhaps you did not like it? You +must excuse me," said he, putting Pierre at ease instead of being +put at ease by him, "but I hope I have not offended you. I always make +it a rule to speak out... Well, what answer am I to take? Will you +come to dinner at the Rostovs'?" + +And Boris, having apparently relieved himself of an onerous duty and +extricated himself from an awkward situation and placed another in it, +became quite pleasant again. + +"No, but I say," said Pierre, calming down, "you are a wonderful +fellow! What you have just said is good, very good. Of course you +don't know me. We have not met for such a long time... not since we +were children. You might think that I... I understand, quite +understand. I could not have done it myself, I should not have had the +courage, but it's splendid. I am very glad to have made your +acquaintance. It's queer," he added after a pause, "that you should +have suspected me!" He began to laugh. "Well, what of it! I hope we'll +get better acquainted," and he pressed Boris' hand. "Do you know, I +have not once been in to see the count. He has not sent for me.... I +am sorry for him as a man, but what can one do?" + +"And so you think Napoleon will manage to get an army across?" asked +Boris with a smile. + +Pierre saw that Boris wished to change the subject, and being of the +same mind he began explaining the advantages and disadvantages of +the Boulogne expedition. + +A footman came in to summon Boris--the princess was going. Pierre, +in order to make Boris' better acquaintance, promised to come to +dinner, and warmly pressing his hand looked affectionately over his +spectacles into Boris' eyes. After he had gone Pierre continued pacing +up and down the room for a long time, no longer piercing an +imaginary foe with his imaginary sword, but smiling at the remembrance +of that pleasant, intelligent, and resolute young man. + +As often happens in early youth, especially to one who leads a +lonely life, he felt an unaccountable tenderness for this young man +and made up his mind that they would be friends. + +Prince Vasili saw the princess off. She held a handkerchief to her +eyes and her face was tearful. + +"It is dreadful, dreadful!" she was saying, "but cost me what it may +I shall do my duty. I will come and spend the night. He must not be +left like this. Every moment is precious. I can't think why his nieces +put it off. Perhaps God will help me to find a way to prepare +him!... Adieu, Prince! May God support you..." + +"Adieu, ma bonne," answered Prince Vasili turning away from her. + +"Oh, he is in a dreadful state," said the mother to her son when +they were in the carriage. "He hardly recognizes anybody." + +"I don't understand, Mamma--what is his attitude to Pierre?" asked +the son. + +"The will will show that, my dear; our fate also depends on it." + +"But why do you expect that he will leave us anything?" + +"Ah, my dear! He is so rich, and we are so poor!" + +"Well, that is hardly a sufficient reason, Mamma..." + +"Oh, Heaven! How ill he is!" exclaimed the mother. + + + + + +CHAPTER XVII + +After Anna Mikhaylovna had driven off with her son to visit Count +Cyril Vladimirovich Bezukhov, Countess Rostova sat for a long time all +alone applying her handkerchief to her eyes. At last she rang. + +"What is the matter with you, my dear?" she said crossly to the maid +who kept her waiting some minutes. "Don't you wish to serve me? Then +I'll find you another place." + +The countess was upset by her friend's sorrow and humiliating +poverty, and was therefore out of sorts, a state of mind which with +her always found expression in calling her maid "my dear" and speaking +to her with exaggerated politeness. + +"I am very sorry, ma'am," answered the maid. + +"Ask the count to come to me." + +The count came waddling in to see his wife with a rather guilty look +as usual. + +"Well, little countess? What a saute of game au madere we are to +have, my dear! I tasted it. The thousand rubles I paid for Taras +were not ill-spent. He is worth it!" + +He sat down by his wife, his elbows on his knees and his hands +ruffling his gray hair. + +"What are your commands, little countess?" + +"You see, my dear... What's that mess?" she said, pointing to his +waistcoat. "It's the saute, most likely," she added with a smile. +"Well, you see, Count, I want some money." + +Her face became sad. + +"Oh, little countess!"... and the count began bustling to get out +his pocketbook. + +"I want a great deal, Count! I want five hundred rubles," and taking +out her cambric handkerchief she began wiping her husband's waistcoat. + +"Yes, immediately, immediately! Hey, who's there?" he called out +in a tone only used by persons who are certain that those they call +will rush to obey the summons. "Send Dmitri to me!" + +Dmitri, a man of good family who had been brought up in the +count's house and now managed all his affairs, stepped softly into the +room. + +"This is what I want, my dear fellow," said the count to the +deferential young man who had entered. "Bring me..." he reflected a +moment, "yes, bring me seven hundred rubles, yes! But mind, don't +bring me such tattered and dirty notes as last time, but nice clean +ones for the countess." + +"Yes, Dmitri, clean ones, please," said the countess, sighing +deeply. + +"When would you like them, your excellency?" asked Dmitri. "Allow me +to inform you... But, don't be uneasy," he added, noticing that the +count was beginning to breathe heavily and quickly which was always +a sign of approaching anger. "I was forgetting... Do you wish it +brought at once?" + +"Yes, yes; just so! Bring it. Give it to the countess." + +"What a treasure that Dmitri is," added the count with a smile +when the young man had departed. "There is never any 'impossible' +with him. That's a thing I hate! Everything is possible." + +"Ah, money, Count, money! How much sorrow it causes in the world," +said the countess. "But I am in great need of this sum." + +"You, my little countess, are a notorious spendthrift," said the +count, and having kissed his wife's hand he went back to his study. + +When Anna Mikhaylovna returned from Count Bezukhov's the money, +all in clean notes, was lying ready under a handkerchief on the +countess' little table, and Anna Mikhaylovna noticed that something +was agitating her. + +"Well, my dear?" asked the countess. + +"Oh, what a terrible state he is in! One would not know him, he is +so ill! I was only there a few moments and hardly said a word..." + +"Annette, for heaven's sake don't refuse me," the countess began, +with a blush that looked very strange on her thin, dignified, +elderly face, and she took the money from under the handkerchief. + +Anna Mikhaylovna instantly guessed her intention and stooped to be +ready to embrace the countess at the appropriate moment. + +"This is for Boris from me, for his outfit." + +Anna Mikhaylovna was already embracing her and weeping. The countess +wept too. They wept because they were friends, and because they were +kindhearted, and because they--friends from childhood--had to think +about such a base thing as money, and because their youth was over.... +But those tears were pleasant to them both. + + + + + +CHAPTER XVIII + + +Countess Rostova, with her daughters and a large number of guests, +was already seated in the drawing room. The count took the gentlemen +into his study and showed them his choice collection of Turkish pipes. +From time to time he went out to ask: "Hasn't she come yet?" They were +expecting Marya Dmitrievna Akhrosimova, known in society as le +terrible dragon, a lady distinguished not for wealth or rank, but +for common sense and frank plainness of speech. Marya Dmitrievna was +known to the Imperial family as well as to all Moscow and +Petersburg, and both cities wondered at her, laughed privately at +her rudenesses, and told good stories about her, while none the less +all without exception respected and feared her. + +In the count's room, which was full of tobacco smoke, they talked of +war that had been announced in a manifesto, and about the +recruiting. None of them had yet seen the manifesto, but they all knew +it had appeared. The count sat on the sofa between two guests who were +smoking and talking. He neither smoked nor talked, but bending his +head first to one side and then to the other watched the smokers +with evident pleasure and listened to the conversation of his two +neighbors, whom he egged on against each other. + +One of them was a sallow, clean-shaven civilian with a thin and +wrinkled face, already growing old, though he was dressed like a +most fashionable young man. He sat with his legs up on the sofa as +if quite at home and, having stuck an amber mouthpiece far into his +mouth, was inhaling the smoke spasmodically and screwing up his +eyes. This was an old bachelor, Shinshin, a cousin of the countess', a +man with "a sharp tongue" as they said in Moscow society. He seemed to +be condescending to his companion. The latter, a fresh, rosy officer +of the Guards, irreproachably washed, brushed, and buttoned, held +his pipe in the middle of his mouth and with red lips gently inhaled +the smoke, letting it escape from his handsome mouth in rings. This +was Lieutenant Berg, an officer in the Semenov regiment with whom +Boris was to travel to join the army, and about whom Natasha had, +teased her elder sister Vera, speaking of Berg as her "intended." +The count sat between them and listened attentively. His favorite +occupation when not playing boston, a card game he was very fond of, +was that of listener, especially when he succeeded in setting two +loquacious talkers at one another. + +"Well, then, old chap, mon tres honorable Alphonse Karlovich," +said Shinshin, laughing ironically and mixing the most ordinary +Russian expressions with the choicest French phrases--which was a +peculiarity of his speech. "Vous comptez vous faire des rentes sur +l'etat;* you want to make something out of your company?" + + +*You expect to make an income out of the government. + + +"No, Peter Nikolaevich; I only want to show that in the cavalry +the advantages are far less than in the infantry. Just consider my own +position now, Peter Nikolaevich..." + +Berg always spoke quietly, politely, and with great precision. His +conversation always related entirely to himself; he would remain +calm and silent when the talk related to any topic that had no +direct bearing on himself. He could remain silent for hours without +being at all put out of countenance himself or making others +uncomfortable, but as soon as the conversation concerned himself he +would begin to talk circumstantially and with evident satisfaction. + +"Consider my position, Peter Nikolaevich. Were I in the cavalry I +should get not more than two hundred rubles every four months, even +with the rank of lieutenant; but as it is I receive two hundred and +thirty," said he, looking at Shinshin and the count with a joyful, +pleasant smile, as if it were obvious to him that his success must +always be the chief desire of everyone else. + +"Besides that, Peter Nikolaevich, by exchanging into the Guards I +shall be in a more prominent position," continued Berg, "and vacancies +occur much more frequently in the Foot Guards. Then just think what +can be done with two hundred and thirty rubles! I even manage to put a +little aside and to send something to my father," he went on, emitting +a smoke ring. + +"La balance y est...* A German knows how to skin a flint, as the +proverb says," remarked Shinshin, moving his pipe to the other side of +his mouth and winking at the count. + + +*So that squares matters. + + +The count burst out laughing. The other guests seeing that +Shinshin was talking came up to listen. Berg, oblivious of irony or +indifference, continued to explain how by exchanging into the Guards +he had already gained a step on his old comrades of the Cadet Corps; +how in wartime the company commander might get killed and he, as +senior in the company, might easily succeed to the post; how popular +he was with everyone in the regiment, and how satisfied his father was +with him. Berg evidently enjoyed narrating all this, and did not +seem to suspect that others, too, might have their own interests. +But all he said was so prettily sedate, and the naivete of his +youthful egotism was so obvious, that he disarmed his hearers. + +"Well, my boy, you'll get along wherever you go--foot or horse--that +I'll warrant," said Shinshin, patting him on the shoulder and taking +his feet off the sofa. + +Berg smiled joyously. The count, by his guests, went into the +drawing room. + +It was just the moment before a big dinner when the assembled +guests, expecting the summons to zakuska,* avoid engaging in any +long conversation but think it necessary to move about and talk, in +order to show that they are not at all impatient for their food. The +host and hostess look toward the door, and now and then glance at +one another, and the visitors try to guess from these glances who, +or what, they are waiting for--some important relation who has not yet +arrived, or a dish that is not yet ready. + + +*Hors d'oeuvres. + + +Pierre had come just at dinnertime and was sitting awkwardly in +the middle of the drawing room on the first chair he had come +across, blocking the way for everyone. The countess tried to make +him talk, but he went on naively looking around through his spectacles +as if in search of somebody and answered all her questions in +monosyllables. He was in the way and was the only one who did not +notice the fact. Most of the guests, knowing of the affair with the +bear, looked with curiosity at this big, stout, quiet man, wondering +how such a clumsy, modest fellow could have played such a prank on a +policeman. + +"You have only lately arrived?" the countess asked him. + +"Oui, madame," replied he, looking around him. + +"You have not yet seen my husband?" + +"Non, madame." He smiled quite inappropriately. + +"You have been in Paris recently, I believe? I suppose it's very +interesting." + +"Very interesting." + +The countess exchanged glances with Anna Mikhaylovna. The latter +understood that she was being asked to entertain this young man, and +sitting down beside him she began to speak about his father; but he +answered her, as he had the countess, only in monosyllables. The other +guests were all conversing with one another. "The Razumovskis... It +was charming... You are very kind... Countess Apraksina..." was +heard on all sides. The countess rose and went into the ballroom. + +"Marya Dmitrievna?" came her voice from there. + +"Herself," came the answer in a rough voice, and Marya Dmitrievna +entered the room. + +All the unmarried ladies and even the married ones except the very +oldest rose. Marya Dmitrievna paused at the door. Tall and stout, +holding high her fifty-year-old head with its gray curls, she stood +surveying the guests, and leisurely arranged her wide sleeves as if +rolling them up. Marya Dmitrievna always spoke in Russian. + +"Health and happiness to her whose name day we are keeping and to +her children," she said, in her loud, full-toned voice which drowned +all others. "Well, you old sinner," she went on, turning to the +count who was kissing her hand, "you're feeling dull in Moscow, I +daresay? Nowhere to hunt with your dogs? But what is to be done, old +man? Just see how these nestlings are growing up," and she pointed +to the girls. "You must look for husbands for them whether you like it +or not...." + +"Well," said she, "how's my Cossack?" (Marya Dmitrievna always called +Natasha a Cossack) and she stroked the child's arm as she came up +fearless and gay to kiss her hand. "I know she's a scamp of a girl, +but I like her." + +She took a pair of pear-shaped ruby earrings from her huge +reticule and, having given them to the rosy Natasha, who beamed with +the pleasure of her saint's-day fete, turned away at once and +addressed herself to Pierre. + +"Eh, eh, friend! Come here a bit," said she, assuming a soft high +tone of voice. "Come here, my friend..." and she ominously tucked up +her sleeves still higher. Pierre approached, looking at her in a +childlike way through his spectacles. + +"Come nearer, come nearer, friend! I used to be the only one to tell +your father the truth when he was in favor, and in your case it's my +evident duty." She paused. All were silent, expectant of what was to +follow, for this was dearly only a prelude. + +"A fine lad! My word! A fine lad!... His father lies on his deathbed +and he amuses himself setting a policeman astride a bear! For shame, +sir, for shame! It would be better if you went to the war." + +She turned away and gave her hand to the count, who could hardly +keep from laughing. + +"Well, I suppose it is time we were at table?" said Marya +Dmitrievna. + +The count went in first with Marya Dmitrievna, the countess followed +on the arm of a colonel of hussars, a man of importance to them +because Nicholas was to go with him to the regiment; then came Anna +Mikhaylovna with Shinshin. Berg gave his arm to Vera. The smiling +Julie Karagina went in with Nicholas. After them other couples +followed, filling the whole dining hall, and last of all the children, +tutors, and governesses followed singly. The footmen began moving +about, chairs scraped, the band struck up in the gallery, and the +guests settled down in their places. Then the strains of the count's +household band were replaced by the clatter of knives and forks, the +voices of visitors, and the soft steps of the footmen. At one end of +the table sat the countess with Marya Dmitrievna on her right and Anna +Mikhaylovna on her left, the other lady visitors were farther down. At +the other end sat the count, with the hussar colonel on his left and +Shinshin and the other male visitors on his right. Midway down the +long table on one side sat the grownup young people: Vera beside Berg, +and Pierre beside Boris; and on the other side, the children, +tutors, and governesses. From behind the crystal decanters and fruit +vases the count kept glancing at his wife and her tall cap with its +light-blue ribbons, and busily filled his neighbors' glasses, not +neglecting his own. The countess in turn, without omitting her +duties as hostess, threw significant glances from behind the +pineapples at her husband whose face and bald head seemed by their +redness to contrast more than usual with his gray hair. At the ladies' +end an even chatter of voices was heard all the time, at the men's end +the voices sounded louder and louder, especially that of the colonel +of hussars who, growing more and more flushed, ate and drank so much +that the count held him up as a pattern to the other guests. Berg with +tender smiles was saying to Vera that love is not an earthly but a +heavenly feeling. Boris was telling his new friend Pierre who the +guests were and exchanging glances with Natasha, who was sitting +opposite. Pierre spoke little but examined the new faces, and ate a +great deal. Of the two soups he chose turtle with savory patties and +went on to the game without omitting a single dish or one of the +wines. These latter the butler thrust mysteriously forward, wrapped in +a napkin, from behind the next man's shoulders and whispered: "Dry +Madeira"... "Hungarian"... or "Rhine wine" as the case might be. Of +the four crystal glasses engraved with the count's monogram that stood +before his plate, Pierre held out one at random and drank with +enjoyment, gazing with ever-increasing amiability at the other guests. +Natasha, who sat opposite, was looking at Boris as girls of thirteen +look at the boy they are in love with and have just kissed for the +first time. Sometimes that same look fell on Pierre, and that funny +lively little girl's look made him inclined to laugh without knowing +why. + +Nicholas sat at some distance from Sonya, beside Julie Karagina, +to whom he was again talking with the same involuntary smile. Sonya +wore a company smile but was evidently tormented by jealousy; now +she turned pale, now blushed and strained every nerve to overhear what +Nicholas and Julie were saying to one another. The governess kept +looking round uneasily as if preparing to resent any slight that might +be put upon the children. The German tutor was trying to remember +all the dishes, wines, and kinds of dessert, in order to send a full +description of the dinner to his people in Germany; and he felt +greatly offended when the butler with a bottle wrapped in a napkin +passed him by. He frowned, trying to appear as if he did not want +any of that wine, but was mortified because no one would understand +that it was not to quench his thirst or from greediness that he wanted +it, but simply from a conscientious desire for knowledge. + + + + + +CHAPTER XIX + + +At the men's end of the table the talk grew more and more +animated. The colonel told them that the declaration of war had +already appeared in Petersburg and that a copy, which he had himself +seen, had that day been forwarded by courier to the commander in +chief. + +"And why the deuce are we going to fight Bonaparte?" remarked +Shinshin. "He has stopped Austria's cackle and I fear it will be our +turn next." + +The colonel was a stout, tall, plethoric German, evidently devoted +to the service and patriotically Russian. He resented Shinshin's +remark. + +"It is for the reasson, my goot sir," said he, speaking with a +German accent, "for the reasson zat ze Emperor knows zat. He +declares in ze manifessto zat he cannot fiew wiz indifference ze +danger vreatening Russia and zat ze safety and dignity of ze Empire as +vell as ze sanctity of its alliances..." he spoke this last word +with particular emphasis as if in it lay the gist of the matter. + +Then with the unerring official memory that characterized him he +repeated from the opening words of the manifesto: + +... and the wish, which constitutes the Emperor's sole and +absolute aim--to establish peace in Europe on firm foundations--has +now decided him to despatch part of the army abroad and to create a +new condition for the attainment of that purpose. + +"Zat, my dear sir, is vy..." he concluded, drinking a tumbler of +wine with dignity and looking to the count for approval. + +"Connaissez-vous le Proverbe:* 'Jerome, Jerome, do not roam, but +turn spindles at home!'?" said Shinshin, puckering his brows and +smiling. "Cela nous convient a merveille.*[2] Suvorov now--he knew +what he was about; yet they beat him a plate couture,*[3] and where +are we to find Suvorovs now? Je vous demande un peu,"*[4] said he, +continually changing from French to Russian. + + +*Do you know the proverb? + +*[2] That suits us down to the ground. + +*[3] Hollow. + +*[4] I just ask you that. + + +"Ve must vight to the last tr-r-op of our plood!" said the +colonel, thumping the table; "and ve must tie for our Emperor, and zen +all vill pe vell. And ve must discuss it as little as po-o-ossible"... +he dwelt particularly on the word possible... "as po-o-ossible," he +ended, again turning to the count. "Zat is how ve old hussars look +at it, and zere's an end of it! And how do you, a young man and a +young hussar, how do you judge of it?" he added, addressing +Nicholas, who when he heard that the war was being discussed had +turned from his partner with eyes and ears intent on the colonel. + +"I am quite of your opinion," replied Nicholas, flaming up, +turning his plate round and moving his wineglasses about with as +much decision and desperation as though he were at that moment +facing some great danger. "I am convinced that we Russians must die or +conquer," he concluded, conscious--as were others--after the words +were uttered that his remarks were too enthusiastic and emphatic for +the occasion and were therefore awkward. + +"What you said just now was splendid!" said his partner Julie. + +Sonya trembled all over and blushed to her ears and behind them +and down to her neck and shoulders while Nicholas was speaking. + +Pierre listened to the colonel's speech and nodded approvingly. + +"That's fine," said he. + +"The young man's a real hussar!" shouted the colonel, again thumping +the table. + +"What are you making such a noise about over there?" Marya +Dmitrievna's deep voice suddenly inquired from the other end of the +table. "What are you thumping the table for?" she demanded of the +hussar, "and why are you exciting yourself? Do you think the French +are here?" + +"I am speaking ze truce," replied the hussar with a smile. + +"It's all about the war," the count shouted down the table. "You +know my son's going, Marya Dmitrievna? My son is going." + +"I have four sons in the army but still I don't fret. It is all in +God's hands. You may die in your bed or God may spare you in a +battle," replied Marya Dmitrievna's deep voice, which easily carried +the whole length of the table. + +"That's true!" + +Once more the conversations concentrated, the ladies' at the one end +and the men's at the other. + +"You won't ask," Natasha's little brother was saying; "I know you +won't ask!" + +"I will," replied Natasha. + +Her face suddenly flushed with reckless and joyous resolution. She +half rose, by a glance inviting Pierre, who sat opposite, to listen to +what was coming, and turning to her mother: + +"Mamma!" rang out the clear contralto notes of her childish voice, +audible the whole length of the table. + +"What is it?" asked the countess, startled; but seeing by her +daughter's face that it was only mischief, she shook a finger at her +sternly with a threatening and forbidding movement of her head. + +The conversation was hushed. + +"Mamma! What sweets are we going to have?" and Natasha's voice +sounded still more firm and resolute. + +The countess tried to frown, but could not. Marya Dmitrievna shook +her fat finger. + +"Cossack!" she said threateningly. + +Most of the guests, uncertain how to regard this sally, looked at +the elders. + +"You had better take care!" said the countess. + +"Mamma! What sweets are we going to have?" Natasha again cried +boldly, with saucy gaiety, confident that her prank would be taken +in good part. + +Sonya and fat little Petya doubled up with laughter. + +"You see! I have asked," whispered Natasha to her little brother and +to Pierre, glancing at him again. + +"Ice pudding, but you won't get any," said Marya Dmitrievna. + +Natasha saw there was nothing to be afraid of and so she braved even +Marya Dmitrievna. + +"Marya Dmitrievna! What kind of ice pudding? I don't like ice +cream." + +"Carrot ices." + +"No! What kind, Marya Dmitrievna? What kind?" she almost screamed; +"I want to know!" + +Marya Dmitrievna and the countess burst out laughing, and all the +guests joined in. Everyone laughed, not at Marya Dmitrievna's answer +but at the incredible boldness and smartness of this little girl who +had dared to treat Marya Dmitrievna in this fashion. + +Natasha only desisted when she had been told that there would be +pineapple ice. Before the ices, champagne was served round. The band +again struck up, the count and countess kissed, and the guests, +leaving their seats, went up to "congratulate" the countess, and +reached across the table to clink glasses with the count, with the +children, and with one another. Again the footmen rushed about, chairs +scraped, and in the same order in which they had entered but with +redder faces, the guests returned to the drawing room and to the +count's study. + + + + + +CHAPTER XX + + +The card tables were drawn out, sets made up for boston, and the +count's visitors settled themselves, some in the two drawing rooms, +some in the sitting room, some in the library. + +The count, holding his cards fanwise, kept himself with difficulty +from dropping into his usual after-dinner nap, and laughed at +everything. The young people, at the countess' instigation, gathered +round the clavichord and harp. Julie by general request played +first. After she had played a little air with variations on the +harp, she joined the other young ladies in begging Natasha and +Nicholas, who were noted for their musical talent, to sing +something. Natasha, who was treated as though she were grown up, was +evidently very proud of this but at the same time felt shy. + +"What shall we sing?" she said. + +"'The Brook,'" suggested Nicholas. + +"Well, then, let's be quick. Boris, come here," said Natasha. "But +where is Sonya?" + +She looked round and seeing that her friend was not in the room +ran to look for her. + +Running into Sonya's room and not finding her there, Natasha ran +to the nursery, but Sonya was not there either. Natasha concluded that +she must be on the chest in the passage. The chest in the passage +was the place of mourning for the younger female generation in the +Rostov household. And there in fact was Sonya lying face downward on +Nurse's dirty feather bed on the top of the chest, crumpling her gauzy +pink dress under her, hiding her face with her slender fingers, and +sobbing so convulsively that her bare little shoulders shook. +Natasha's face, which had been so radiantly happy all that saint's +day, suddenly changed: her eyes became fixed, and then a shiver passed +down her broad neck and the corners of her mouth drooped. + +"Sonya! What is it? What is the matter?... Oo... Oo... Oo...!" And +Natasha's large mouth widened, making her look quite ugly, and she +began to wail like a baby without knowing why, except that Sonya was +crying. Sonya tried to lift her head to answer but could not, and +hid her face still deeper in the bed. Natasha wept, sitting on the +blue-striped feather bed and hugging her friend. With an effort +Sonya sat up and began wiping her eyes and explaining. + +"Nicholas is going away in a week's time, his... papers... have +come... he told me himself... but still I should not cry," and she +showed a paper she held in her hand--with the verses Nicholas had +written, "still, I should not cry, but you can't... no one can +understand... what a soul he has!" + +And she began to cry again because he had such a noble soul. + +"It's all very well for you... I am not envious... I love you and +Boris also," she went on, gaining a little strength; "he is nice... +there are no difficulties in your way.... But Nicholas is my cousin... +one would have to... the Metropolitan himself... and even then it +can't be done. And besides, if she tells Mamma" (Sonya looked upon the +countess as her mother and called her so) "that I am spoiling +Nicholas' career and am heartless and ungrateful, while truly... God +is my witness," and she made the sign of the cross, "I love her so +much, and all of you, only Vera... And what for? What have I done to +her? I am so grateful to you that I would willingly sacrifice +everything, only I have nothing...." + +Sonya could not continue, and again hid her face in her hands and in +the feather bed. Natasha began consoling her, but her face showed that + +she understood all the gravity of her friend's trouble. + +"Sonya," she suddenly exclaimed, as if she had guessed the true +reason of her friend's sorrow, "I'm sure Vera has said something to +you since dinner? Hasn't she?" + +"Yes, these verses Nicholas wrote himself and I copied some +others, and she found them on my table and said she'd show them to +Mamma, and that I was ungrateful, and that Mamma would never allow him +to marry me, but that he'll marry Julie. You see how he's been with +her all day... Natasha, what have I done to deserve it?..." + +And again she began to sob, more bitterly than before. Natasha +lifted her up, hugged her, and, smiling through her tears, began +comforting her. + +"Sonya, don't believe her, darling! Don't believe her! Do you +remember how we and Nicholas, all three of us, talked in the sitting +room after supper? Why, we settled how everything was to be. I don't +quite remember how, but don't you remember that it could all be +arranged and how nice it all was? There's Uncle Shinshin's brother has +married his first cousin. And we are only second cousins, you know. +And Boris says it is quite possible. You know I have told him all +about it. And he is so clever and so good!" said Natasha. "Don't you +cry, Sonya, dear love, darling Sonya!" and she kissed her and laughed. +"Vera's spiteful; never mind her! And all will come right and she +won't say anything to Mamma. Nicholas will tell her himself, and he +doesn't care at all for Julie." + +Natasha kissed her on the hair. + +Sonya sat up. The little kitten brightened, its eyes shone, and it +seemed ready to lift its tail, jump down on its soft paws, and begin +playing with the ball of worsted as a kitten should. + +"Do you think so?... Really? Truly?" she said, quickly smoothing her +frock and hair. + +"Really, truly!" answered Natasha, pushing in a crisp lock that +had strayed from under her friend's plaits. + +Both laughed. + +"Well, let's go and sing 'The Brook.'" + +"Come along!" + +"Do you know, that fat Pierre who sat opposite me is so funny!" said +Natasha, stopping suddenly. "I feel so happy!" + +And she set off at a run along the passage. + +Sonya, shaking off some down which clung to her and tucking away the +verses in the bosom of her dress close to her bony little chest, ran +after Natasha down the passage into the sitting room with flushed face +and light, joyous steps. At the visitors' request the young people +sang the quartette, "The Brook," with which everyone was delighted. +Then Nicholas sang a song he had just learned: + + + At nighttime in the moon's fair glow + How sweet, as fancies wander free, + To feel that in this world there's one + Who still is thinking but of thee! + + That while her fingers touch the harp + Wafting sweet music music the lea, + It is for thee thus swells her heart, + Sighing its message out to thee... + + A day or two, then bliss unspoilt, + But oh! till then I cannot live!... + + +He had not finished the last verse before the young people began +to get ready to dance in the large hall, and the sound of the feet and +the coughing of the musicians were heard from the gallery. + + +Pierre was sitting in the drawing-room where Shinshin had engaged +him, as a man recently returned from abroad, in a political +conversation in which several others joined but which bored Pierre. +When the music began Natasha came in and walking straight up to Pierre +said, laughing and blushing: + +"Mamma told me to ask you to join the dancers." + +"I am afraid of mixing the figures," Pierre replied; "but if you +will be my teacher..." And lowering his big arm he offered it to the +slender little girl. + +While the couples were arranging themselves and the musicians tuning +up, Pierre sat down with his little partner. Natasha was perfectly +happy; she was dancing with a grown-up man, who had been abroad. She +was sitting in a conspicuous place and talking to him like a +grown-up lady. She had a fan in her hand that one of the ladies had +given her to hold. Assuming quite the pose of a society woman +(heaven knows when and where she had learned it) she talked with her +partner, fanning herself and smiling over the fan. + +"Dear, dear! Just look at her!" exclaimed the countess as she +crossed the ballroom, pointing to Natasha. + +Natasha blushed and laughed. + +"Well, really, Mamma! Why should you? What is there to be +surprised at?" + + +In the midst of the third ecossaise there was a clatter of chairs +being pushed back in the sitting room where the count and Marya +Dmitrievna had been playing cards with the majority of the more +distinguished and older visitors. They now, stretching themselves +after sitting so long, and replacing their purses and pocketbooks, +entered the ballroom. First came Marya Dmitrievna and the count, +both with merry countenances. The count, with playful ceremony +somewhat in ballet style, offered his bent arm to Marya Dmitrievna. He +drew himself up, a smile of debonair gallantry lit up his face and +as soon as the last figure of the ecossaise was ended, he clapped +his hands to the musicians and shouted up to their gallery, addressing +the first violin: + +"Semen! Do you know the Daniel Cooper?" + +This was the count's favorite dance, which he had danced in his +youth. (Strictly speaking, Daniel Cooper was one figure of the +anglaise.) + +"Look at Papa!" shouted Natasha to the whole company, and quite +forgetting that she was dancing with a grown-up partner she bent her +curly head to her knees and made the whole room ring with her +laughter. + +And indeed everybody in the room looked with a smile of pleasure +at the jovial old gentleman, who standing beside his tall and stout +partner, Marya Dmitrievna, curved his arms, beat time, straightened +his shoulders, turned out his toes, tapped gently with his foot, +and, by a smile that broadened his round face more and more, +prepared the onlookers for what was to follow. As soon as the +provocatively gay strains of Daniel Cooper (somewhat resembling +those of a merry peasant dance) began to sound, all the doorways of +the ballroom were suddenly filled by the domestic serfs--the men on +one side and the women on the other--who with beaming faces had come +to see their master making merry. + +"Just look at the master! A regular eagle he is!" loudly remarked +the nurse, as she stood in one of the doorways. + +The count danced well and knew it. But his partner could not and did +not want to dance well. Her enormous figure stood erect, her +powerful arms hanging down (she had handed her reticule to the +countess), and only her stern but handsome face really joined in the +dance. What was expressed by the whole of the count's plump figure, in +Marya Dmitrievna found expression only in her more and more beaming +face and quivering nose. But if the count, getting more and more +into the swing of it, charmed the spectators by the unexpectedness +of his adroit maneuvers and the agility with which he capered about on +his light feet, Marya Dmitrievna produced no less impression by slight +exertions--the least effort to move her shoulders or bend her arms +when turning, or stamp her foot--which everyone appreciated in view of +her size and habitual severity. The dance grew livelier and +livelier. The other couples could not attract a moment's attention +to their own evolutions and did not even try to do so. All were +watching the count and Marya Dmitrievna. Natasha kept pulling everyone +by sleeve or dress, urging them to "look at Papa!" though as it was +they never took their eyes off the couple. In the intervals of the +dance the count, breathing deeply, waved and shouted to the +musicians to play faster. Faster, faster, and faster; lightly, more +lightly, and yet more lightly whirled the count, flying round Marya +Dmitrievna, now on his toes, now on his heels; until, turning his +partner round to her seat, he executed the final pas, raising his soft +foot backwards, bowing his perspiring head, smiling and making a +wide sweep with his arm, amid a thunder of applause and laughter led +by Natasha. Both partners stood still, breathing heavily and wiping +their faces with their cambric handkerchiefs. + +"That's how we used to dance in our time, ma chere," said the count. + +"That was a Daniel Cooper!" exclaimed Marya Dmitrievna, tucking up +her sleeves and puffing heavily. + + + + + +CHAPTER XXI + + +While in the Rostovs' ballroom the sixth anglaise was being +danced, to a tune in which the weary musicians blundered, and while +tired footmen and cooks were getting the supper, Count Bezukhov had +a sixth stroke. The doctors pronounced recovery impossible. After a +mute confession, communion was administered to the dying man, +preparations made for the sacrament of unction, and in his house there +was the bustle and thrill of suspense usual at such moments. Outside +the house, beyond the gates, a group of undertakers, who hid +whenever a carriage drove up, waited in expectation of an important +order for an expensive funeral. The Military Governor of Moscow, who +had been assiduous in sending aides-de-camp to inquire after the +count's health, came himself that evening to bid a last farewell to +the celebrated grandee of Catherine's court, Count Bezukhov. + +The magnificent reception room was crowded. Everyone stood up +respectfully when the Military Governor, having stayed about half an +hour alone with the dying man, passed out, slightly acknowledging +their bows and trying to escape as quickly as from the glances fixed +on him by the doctors, clergy, and relatives of the family. Prince +Vasili, who had grown thinner and paler during the last few days, +escorted him to the door, repeating something to him several times +in low tones. + +When the Military Governor had gone, Prince Vasili sat down all +alone on a chair in the ballroom, crossing one leg high over the +other, leaning his elbow on his knee and covering his face with his +hand. After sitting so for a while he rose, and, looking about him +with frightened eyes, went with unusually hurried steps down the +long corridor leading to the back of the house, to the room of the +eldest princess. + +Those who were in the dimly lit reception room spoke in nervous +whispers, and, whenever anyone went into or came from the dying +man's room, grew silent and gazed with eyes full of curiosity or +expectancy at his door, which creaked slightly when opened. + +"The limits of human life... are fixed and may not be o'erpassed," +said an old priest to a lady who had taken a seat beside him and was +listening naively to his words. + +"I wonder, is it not too late to administer unction?" asked the +lady, adding the priest's clerical title, as if she had no opinion +of her own on the subject. + +"Ah, madam, it is a great sacrament," replied the priest, passing +his hand over the thin grizzled strands of hair combed back across his +bald head. + +"Who was that? The Military Governor himself?" was being asked at +the other side of the room. "How young-looking he is!" + +"Yes, and he is over sixty. I hear the count no longer recognizes +anyone. They wished to administer the sacrament of unction." + +"I knew someone who received that sacrament seven times." + +The second princess had just come from the sickroom with her eyes +red from weeping and sat down beside Dr. Lorrain, who was sitting in a +graceful pose under a portrait of Catherine, leaning his elbow on a +table. + +"Beautiful," said the doctor in answer to a remark about the +weather. "The weather is beautiful, Princess; and besides, in Moscow +one feels as if one were in the country." + +"Yes, indeed," replied the princess with a sigh. "So he may have +something to drink?" + +Lorrain considered. + +"Has he taken his medicine?" + +"Yes." + +The doctor glanced at his watch. + +"Take a glass of boiled water and put a pinch of cream of tartar," +and he indicated with his delicate fingers what he meant by a pinch. + +"Dere has neffer been a gase," a German doctor was saying to an +aide-de-camp, "dat one liffs after de sird stroke." + +"And what a well-preserved man he was!" remarked the aide-de-camp. +"And who will inherit his wealth?" he added in a whisper. + +"It von't go begging," replied the German with a smile. + +Everyone again looked toward the door, which creaked as the second +princess went in with the drink she had prepared according to +Lorrain's instructions. The German doctor went up to Lorrain. + +"Do you think he can last till morning?" asked the German, +addressing Lorrain in French which he pronounced badly. + +Lorrain, pursing up his lips, waved a severely negative finger +before his nose. + +"Tonight, not later," said he in a low voice, and he moved away with +a decorous smile of self-satisfaction at being able clearly to +understand and state the patient's condition. + + +Meanwhile Prince Vasili had opened the door into the princess' room. + +In this room it was almost dark; only two tiny lamps were burning +before the icons and there was a pleasant scent of flowers and burnt +pastilles. The room was crowded with small pieces of furniture, +whatnots, cupboards, and little tables. The quilt of a high, white +feather bed was just visible behind a screen. A small dog began to +bark. + +"Ah, is it you, cousin?" + +She rose and smoothed her hair, which was as usual so extremely +smooth that it seemed to be made of one piece with her head and +covered with varnish. + +"Has anything happened?" she asked. "I am so terrified." + +"No, there is no change. I only came to have a talk about +business, Catiche,"* muttered the prince, seating himself wearily on +the chair she had just vacated. "You have made the place warm, I +must say," he remarked. "Well, sit down: let's have a talk." + + +*Catherine. + + +"I thought perhaps something had happened," she said with her +unchanging stonily severe expression; and, sitting down opposite the +prince, she prepared to listen. + +"I wished to get a nap, mon cousin, but I can't." + +"Well, my dear?" said Prince Vasili, taking her hand and bending +it downwards as was his habit. + +It was plain that this "well?" referred to much that they both +understood without naming. + +The princess, who had a straight, rigid body, abnormally long for +her legs, looked directly at Prince Vasili with no sign of emotion +in her prominent gray eyes. Then she shook her head and glanced up +at the icons with a sigh. This might have been taken as an +expression of sorrow and devotion, or of weariness and hope of resting +before long. Prince Vasili understood it as an expression of +weariness. + +"And I?" he said; "do you think it is easier for me? I am as worn +out as a post horse, but still I must have a talk with you, Catiche, a +very serious talk." + +Prince Vasili said no more and his cheeks began to twitch nervously, +now on one side, now on the other, giving his face an unpleasant +expression which was never to be seen on it in a drawing room. His +eyes too seemed strange; at one moment they looked impudently sly +and at the next glanced round in alarm. + +The princess, holding her little dog on her lap with her thin bony +hands, looked attentively into Prince Vasili's eyes evidently resolved +not to be the first to break silence, if she had to wait till morning. + +"Well, you see, my dear princess and cousin, Catherine Semenovna," +continued Prince Vasili, returning to his theme, apparently not +without an inner struggle; "at such a moment as this one must think of +everything. One must think of the future, of all of you... I love +you all, like children of my own, as you know." + +The princess continued to look at him without moving, and with the +same dull expression. + +"And then of course my family has also to be considered," Prince +Vasili went on, testily pushing away a little table without looking at +her. "You know, Catiche, that we--you three sisters, Mamontov, and +my wife--are the count's only direct heirs. I know, I know how hard it +is for you to talk or think of such matters. It is no easier for me; +but, my dear, I am getting on for sixty and must be prepared for +anything. Do you know I have sent for Pierre? The count," pointing +to his portrait, "definitely demanded that he should be called." + +Prince Vasili looked questioningly at the princess, but could not +make out whether she was considering what he had just said or +whether she was simply looking at him. + +"There is one thing I constantly pray God to grant, mon cousin," she +replied, "and it is that He would be merciful to him and would allow +his noble soul peacefully to leave this..." + +"Yes, yes, of course," interrupted Prince Vasili impatiently, +rubbing his bald head and angrily pulling back toward him the little +table that he had pushed away. "But... in short, the fact is... you +know yourself that last winter the count made a will by which he +left all his property, not to us his direct heirs, but to Pierre." + +"He has made wills enough!" quietly remarked the princess. "But he +cannot leave the estate to Pierre. Pierre is illegitimate." + +"But, my dear," said Prince Vasili suddenly, clutching the little +table and becoming more animated and talking more rapidly: "what if +a letter has been written to the Emperor in which the count asks for +Pierre's legitimation? Do you understand that in consideration of +the count's services, his request would be granted?..." + +The princess smiled as people do who think they know more about +the subject under discussion than those they are talking with. + +"I can tell you more," continued Prince Vasili, seizing her hand, +"that letter was written, though it was not sent, and the Emperor knew +of it. The only question is, has it been destroyed or not? If not, +then as soon as all is over," and Prince Vasili sighed to intimate +what he meant by the words all is over, "and the count's papers are +opened, the will and letter will be delivered to the Emperor, and +the petition will certainly be granted. Pierre will get everything +as the legitimate son." + +"And our share?" asked the princess smiling ironically, as if +anything might happen, only not that. + +"But, my poor Catiche, it is as clear as daylight! He will then be +the legal heir to everything and you won't get anything. You must +know, my dear, whether the will and letter were written, and whether +they have been destroyed or not. And if they have somehow been +overlooked, you ought to know where they are, and must find them, +because..." + +"What next?" the princess interrupted, smiling sardonically and +not changing the expression of her eyes. "I am a woman, and you +think we are all stupid; but I know this: an illegitimate son cannot +inherit... un batard!"* she added, as if supposing that this +translation of the word would effectively prove to Prince Vasili the +invalidity of his contention. + + +*A bastard. + + +"Well, really, Catiche! Can't you understand! You are so +intelligent, how is it you don't see that if the count has written a +letter to the Emperor begging him to recognize Pierre as legitimate, +it follows that Pierre will not be Pierre but will become Count +Bezukhov, and will then inherit everything under the will? And if +the will and letter are not destroyed, then you will have nothing +but the consolation of having been dutiful et tout ce qui s'ensuit!* +That's certain." + + +*And all that follows therefrom. + + +"I know the will was made, but I also know that it is invalid; and +you, mon cousin, seem to consider me a perfect fool," said the +princess with the expression women assume when they suppose they are +saying something witty and stinging. + +"My dear Princess Catherine Semenovna," began Prince Vasili +impatiently, "I came here not to wrangle with you, but to talk about +your interests as with a kinswoman, a good, kind, true relation. And I +tell you for the tenth time that if the letter to the Emperor and +the will in Pierre's favor are among the count's papers, then, my dear +girl, you and your sisters are not heiresses! If you don't believe me, +then believe an expert. I have just been talking to Dmitri Onufrich" +(the family solicitor) "and he says the same." + +At this a sudden change evidently took place in the princess' ideas; +her thin lips grew white, though her eyes did not change, and her +voice when she began to speak passed through such transitions as she +herself evidently did not expect. + +"That would be a fine thing!" said she. "I never wanted anything and +I don't now." + +She pushed the little dog off her lap and smoothed her dress. + +"And this is gratitude--this is recognition for those who have +sacrificed everything for his sake!" she cried. "It's splendid! +Fine! I don't want anything, Prince." + +"Yes, but you are not the only one. There are your sisters..." +replied Prince Vasili. + +But the princess did not listen to him. + +"Yes, I knew it long ago but had forgotten. I knew that I could +expect nothing but meanness, deceit, envy, intrigue, and +ingratitude--the blackest ingratitude--in this house..." + +"Do you or do you not know where that will is?" insisted Prince +Vasili, his cheeks twitching more than ever. + +"Yes, I was a fool! I still believed in people, loved them, and +sacrificed myself. But only the base, the vile succeed! I know who has +been intriguing!" + +The princess wished to rise, but the prince held her by the hand. +She had the air of one who has suddenly lost faith in the whole +human race. She gave her companion an angry glance. + +"There is still time, my dear. You must remember, Catiche, that it +was all done casually in a moment of anger, of illness, and was +afterwards forgotten. Our duty, my dear, is to rectify his mistake, to +ease his last moments by not letting him commit this injustice, and +not to let him die feeling that he is rendering unhappy those who..." + +"Who sacrificed everything for him," chimed in the princess, who +would again have risen had not the prince still held her fast, "though +he never could appreciate it. No, mon cousin," she added with a +sigh, "I shall always remember that in this world one must expect no +reward, that in this world there is neither honor nor justice. In this +world one has to be cunning and cruel." + +"Now come, come! Be reasonable. I know your excellent heart." + +"No, I have a wicked heart." + +"I know your heart," repeated the prince. "I value your friendship +and wish you to have as good an opinion of me. Don't upset yourself, +and let us talk sensibly while there is still time, be it a day or +be it but an hour.... Tell me all you know about the will, and above +all where it is. You must know. We will take it at once and show it to +the count. He has, no doubt, forgotten it and will wish to destroy it. +You understand that my sole desire is conscientiously to carry out his +wishes; that is my only reason for being here. I came simply to help +him and you." + +"Now I see it all! I know who has been intriguing--I know!" cried +the princess. + +"That's not the point, my dear." + +"It's that protege of yours, that sweet Princess Drubetskaya, that +Anna Mikhaylovna whom I would not take for a housemaid... the +infamous, vile woman!" + +"Do not let us lose any time..." + +"Ah, don't talk to me! Last winter she wheedled herself in here +and told the count such vile, disgraceful things about us, +especially about Sophie--I can't repeat them--that it made the count +quite ill and he would not see us for a whole fortnight. I know it was +then he wrote this vile, infamous paper, but I thought the thing was +invalid." + +"We've got to it at last--why did you not tell me about it sooner?" + +"It's in the inlaid portfolio that he keeps under his pillow," +said the princess, ignoring his question. "Now I know! Yes; if I +have a sin, a great sin, it is hatred of that vile woman!" almost +shrieked the princess, now quite changed. "And what does she come +worming herself in here for? But I will give her a piece of my mind. +The time will come!" + + + + + +CHAPTER XXII + + +While these conversations were going on in the reception room and +the princess' room, a carriage containing Pierre (who had been sent +for) and Anna Mikhaylovna (who found it necessary to accompany him) +was driving into the court of Count Bezukhov's house. As the wheels +rolled softly over the straw beneath the windows, Anna Mikhaylovna, +having turned with words of comfort to her companion, realized that he +was asleep in his corner and woke him up. Rousing himself, Pierre +followed Anna Mikhaylovna out of the carriage, and only then began +to think of the interview with his dying father which awaited him. +He noticed that they had not come to the front entrance but to the +back door. While he was getting down from the carriage steps two +men, who looked like tradespeople, ran hurriedly from the entrance and +hid in the shadow of the wall. Pausing for a moment, Pierre noticed +several other men of the same kind hiding in the shadow of the house +on both sides. But neither Anna Mikhaylovna nor the footman nor the +coachman, who could not help seeing these people, took any notice of +them. "It seems to be all right," Pierre concluded, and followed +Anna Mikhaylovna. She hurriedly ascended the narrow dimly lit stone +staircase, calling to Pierre, who was lagging behind, to follow. +Though he did not see why it was necessary for him to go to the +count at all, still less why he had to go by the back stairs, yet +judging by Anna Mikhaylovna's air of assurance and haste, Pierre +concluded that it was all absolutely necessary. Halfway up the +stairs they were almost knocked over by some men who, carrying +pails, came running downstairs, their boots clattering. These men +pressed close to the wall to let Pierre and Anna Mikhaylovna pass +and did not evince the least surprise at seeing them there. + +"Is this the way to the princesses' apartments?" asked Anna +Mikhaylovna of one of them. + +"Yes," replied a footman in a bold loud voice, as if anything were +now permissible; "the door to the left, ma'am." + +"Perhaps the count did not ask for me," said Pierre when he +reached the landing. "I'd better go to my own room." + +Anna Mikhaylovna paused and waited for him to come up. + +"Ah, my friend!" she said, touching his arm as she had done her +son's when speaking to him that afternoon, "believe me I suffer no +less than you do, but be a man!" + +"But really, hadn't I better go away?" he asked, looking kindly at +her over his spectacles. + +"Ah, my dear friend! Forget the wrongs that may have been done +you. Think that he is your father... perhaps in the agony of death." +She sighed. "I have loved you like a son from the first. Trust +yourself to me, Pierre. I shall not forget your interests." + +Pierre did not understand a word, but the conviction that all this +had to be grew stronger, and he meekly followed Anna Mikhaylovna who +was already opening a door. + +This door led into a back anteroom. An old man, a servant of the +princesses, sat in a corner knitting a stocking. Pierre had never been +in this part of the house and did not even know of the existence of +these rooms. Anna Mikhaylovna, addressing a maid who was hurrying past +with a decanter on a tray as "my dear" and "my sweet," asked about the +princess' health and then led Pierre along a stone passage. The +first door on the left led into the princesses' apartments. The maid +with the decanter in her haste had not closed the door (everything +in the house was done in haste at that time), and Pierre and Anna +Mikhaylovna in passing instinctively glanced into the room, where +Prince Vasili and the eldest princess were sitting close together +talking. Seeing them pass, Prince Vasili drew back with obvious +impatience, while the princess jumped up and with a gesture of +desperation slammed the door with all her might. + +This action was so unlike her usual composure and the fear +depicted on Prince Vasili's face so out of keeping with his dignity +that Pierre stopped and glanced inquiringly over his spectacles at his +guide. Anna Mikhaylovna evinced no surprise, she only smiled faintly +and sighed, as if to say that this was no more than she had expected. + +"Be a man, my friend. I will look after your interests," said she in +reply to his look, and went still faster along the passage. + +Pierre could not make out what it was all about, and still less what +"watching over his interests" meant, but he decided that all these +things had to be. From the passage they went into a large, dimly lit +room adjoining the count's reception room. It was one of those +sumptuous but cold apartments known to Pierre only from the front +approach, but even in this room there now stood an empty bath, and +water had been spilled on the carpet. They were met by a deacon with a +censer and by a servant who passed out on tiptoe without heeding them. +They went into the reception room familiar to Pierre, with two Italian +windows opening into the conservatory, with its large bust and full +length portrait of Catherine the Great. The same people were still +sitting here in almost the same positions as before, whispering to one +another. All became silent and turned to look at the pale tear-worn +Anna Mikhaylovna as she entered, and at the big stout figure of Pierre +who, hanging his head, meekly followed her. + +Anna Mikhaylovna's face expressed a consciousness that the +decisive moment had arrived. With the air of a practical Petersburg +lady she now, keeping Pierre close beside her, entered the room even +more boldly than that afternoon. She felt that as she brought with her +the person the dying man wished to see, her own admission was assured. +Casting a rapid glance at all those in the room and noticing the +count's confessor there, she glided up to him with a sort of amble, +not exactly bowing yet seeming to grow suddenly smaller, and +respectfully received the blessing first of one and then of another +priest. + +"God be thanked that you are in time," said she to one of the +priests; "all we relatives have been in such anxiety. This young man +is the count's son," she added more softly. "What a terrible moment!" + +Having said this she went up to the doctor. + +"Dear doctor," said she, "this young man is the count's son. Is +there any hope?" + +The doctor cast a rapid glance upwards and silently shrugged his +shoulders. Anna Mikhaylovna with just the same movement raised her +shoulders and eyes, almost closing the latter, sighed, and moved +away from the doctor to Pierre. To him, in a particularly respectful +and tenderly sad voice, she said: + +"Trust in His mercy!" and pointing out a small sofa for him to sit +and wait for her, she went silently toward the door that everyone +was watching and it creaked very slightly as she disappeared behind +it. + +Pierre, having made up his mind to obey his monitress implicitly, +moved toward the sofa she had indicated. As soon as Anna Mikhaylovna +had disappeared he noticed that the eyes of all in the room turned +to him with something more than curiosity and sympathy. He noticed +that they whispered to one another, casting significant looks at him +with a kind of awe and even servility. A deference such as he had +never before received was shown him. A strange lady, the one who had +been talking to the priests, rose and offered him her seat; an +aide-de-camp picked up and returned a glove Pierre had dropped; the +doctors became respectfully silent as he passed by, and moved to +make way for him. At first Pierre wished to take another seat so as +not to trouble the lady, and also to pick up the glove himself and +to pass round the doctors who were not even in his way; but all at +once he felt that this would not do, and that tonight he was a +person obliged to perform some sort of awful rite which everyone +expected of him, and that he was therefore bound to accept their +services. He took the glove in silence from the aide-de-camp, and +sat down in the lady's chair, placing his huge hands symmetrically +on his knees in the naive attitude of an Egyptian statue, and +decided in his own mind that all was as it should be, and that in +order not to lose his head and do foolish things he must not act on +his own ideas tonight, but must yield himself up entirely to the +will of those who were guiding him. + +Not two minutes had passed before Prince Vasili with head erect +majestically entered the room. He was wearing his long coat with three +stars on his breast. He seemed to have grown thinner since the +morning; his eyes seemed larger than usual when he glanced round and +noticed Pierre. He went up to him, took his hand (a thing he never +used to do), and drew it downwards as if wishing to ascertain +whether it was firmly fixed on. + +"Courage, courage, my friend! He has asked to see you. That is +well!" and he turned to go. + +But Pierre thought it necessary to ask: "How is..." and hesitated, +not knowing whether it would be proper to call the dying man "the +count," yet ashamed to call him "father." + +"He had another stroke about half an hour ago. Courage, my +friend..." + +Pierre's mind was in such a confused state that the word "stroke" +suggested to him a blow from something. He looked at Prince Vasili +in perplexity, and only later grasped that a stroke was an attack of +illness. Prince Vasili said something to Lorrain in passing and went +through the door on tiptoe. He could not walk well on tiptoe and his +whole body jerked at each step. The eldest princess followed him, +and the priests and deacons and some servants also went in at the +door. Through that door was heard a noise of things being moved about, +and at last Anna Mikhaylovna, still with the same expression, pale but +resolute in the discharge of duty, ran out and touching Pierre lightly +on the arm said: + +"The divine mercy is inexhaustible! Unction is about to be +administered. Come." + +Pierre went in at the door, stepping on the soft carpet, and noticed +that the strange lady, the aide-de-camp, and some of the servants, all +followed him in, as if there were now no further need for permission +to enter that room. + + + + + +CHAPTER XXIII + + +Pierre well knew this large room divided by columns and an arch, its +walls hung round with Persian carpets. The part of the room behind the +columns, with a high silk-curtained mahogany bedstead on one side +and on the other an immense case containing icons, was brightly +illuminated with red light like a Russian church during evening +service. Under the gleaming icons stood a long invalid chair, and in +that chair on snowy-white smooth pillows, evidently freshly changed, +Pierre saw--covered to the waist by a bright green quilt--the +familiar, majestic figure of his father, Count Bezukhov, with that +gray mane of hair above his broad forehead which reminded one of a +lion, and the deep characteristically noble wrinkles of his +handsome, ruddy face. He lay just under the icons; his large thick +hands outside the quilt. Into the right hand, which was lying palm +downwards, a wax taper had been thrust between forefinger and thumb, +and an old servant, bending over from behind the chair, held it in +position. By the chair stood the priests, their long hair falling over +their magnificent glittering vestments, with lighted tapers in their +hands, slowly and solemnly conducting the service. A little behind +them stood the two younger princesses holding handkerchiefs to their +eyes, and just in front of them their eldest sister, Catiche, with a +vicious and determined look steadily fixed on the icons, as though +declaring to all that she could not answer for herself should she +glance round. Anna Mikhaylovna, with a meek, sorrowful, and +all-forgiving expression on her face, stood by the door near the +strange lady. Prince Vasili in front of the door, near the invalid +chair, a wax taper in his left hand, was leaning his left arm on the +carved back of a velvet chair he had turned round for the purpose, and +was crossing himself with his right hand, turning his eyes upward each +time he touched his forehead. His face wore a calm look of piety and +resignation to the will of God. "If you do not understand these +sentiments," he seemed to be saying, "so much the worse for you!" + +Behind him stood the aide-de-camp, the doctors, and the menservants; +the men and women had separated as in church. All were silently +crossing themselves, and the reading of the church service, the +subdued chanting of deep bass voices, and in the intervals sighs and +the shuffling of feet were the only sounds that could be heard. Anna +Mikhaylovna, with an air of importance that showed that she felt she +quite knew what she was about, went across the room to where Pierre +was standing and gave him a taper. He lit it and, distracted by +observing those around him, began crossing himself with the hand +that held the taper. + +Sophie, the rosy, laughter-loving, youngest princess with the +mole, watched him. She smiled, hid her face in her handkerchief, and +remained with it hidden for awhile; then looking up and seeing +Pierre she again began to laugh. She evidently felt unable to look +at him without laughing, but could not resist looking at him: so to be +out of temptation she slipped quietly behind one of the columns. In +the midst of the service the voices of the priests suddenly ceased, +they whispered to one another, and the old servant who was holding the +count's hand got up and said something to the ladies. Anna Mikhaylovna +stepped forward and, stooping over the dying man, beckoned to +Lorrain from behind her back. The French doctor held no taper; he +was leaning against one of the columns in a respectful attitude +implying that he, a foreigner, in spite of all differences of faith, +understood the full importance of the rite now being performed and +even approved of it. He now approached the sick man with the noiseless +step of one in full vigor of life, with his delicate white fingers +raised from the green quilt the hand that was free, and turning +sideways felt the pulse and reflected a moment. The sick man was given +something to drink, there was a stir around him, then the people +resumed their places and the service continued. During this interval +Pierre noticed that Prince Vasili left the chair on which he had +been leaning, and--with air which intimated that he knew what he was +about and if others did not understand him it was so much the worse +for them--did not go up to the dying man, but passed by him, joined +the eldest princess, and moved with her to the side of the room +where stood the high bedstead with its silken hangings. On leaving the +bed both Prince Vasili and the princess passed out by a back door, but +returned to their places one after the other before the service was +concluded. Pierre paid no more attention to this occurrence than to +the rest of what went on, having made up his mind once for all that +what he saw happening around him that evening was in some way +essential. + +The chanting of the service ceased, and the voice of the priest +was heard respectfully congratulating the dying man on having received +the sacrament. The dying man lay as lifeless and immovable as +before. Around him everyone began to stir: steps were audible and +whispers, among which Anna Mikhaylovna's was the most distinct. + +Pierre heard her say: + +"Certainly he must be moved onto the bed; here it will be +impossible..." + +The sick man was so surrounded by doctors, princesses, and +servants that Pierre could no longer see the reddish-yellow face +with its gray mane--which, though he saw other faces as well, he had +not lost sight of for a single moment during the whole service. He +judged by the cautious movements of those who crowded round the +invalid chair that they had lifted the dying man and were moving him. + +"Catch hold of my arm or you'll drop him!" he heard one of the +servants say in a frightened whisper. "Catch hold from underneath. +Here!" exclaimed different voices; and the heavy breathing of the +bearers and the shuffling of their feet grew more hurried, as if the +weight they were carrying were too much for them. + +As the bearers, among whom was Anna Mikhaylovna, passed the young +man he caught a momentary glimpse between their heads and backs of the +dying man's high, stout, uncovered chest and powerful shoulders, +raised by those who were holding him under the armpits, and of his +gray, curly, leonine head. This head, with its remarkably broad brow +and cheekbones, its handsome, sensual mouth, and its cold, majestic +expression, was not disfigured by the approach of death. It was the +same as Pierre remembered it three months before, when the count had +sent him to Petersburg. But now this head was swaying helplessly +with the uneven movements of the bearers, and the cold listless gaze +fixed itself upon nothing. + +After a few minutes' bustle beside the high bedstead, those who +had carried the sick man dispersed. Anna Mikhaylovna touched +Pierre's hand and said, "Come." Pierre went with her to the bed on +which the sick man had been laid in a stately pose in keeping with the +ceremony just completed. He lay with his head propped high on the +pillows. His hands were symmetrically placed on the green silk +quilt, the palms downward. When Pierre came up the count was gazing +straight at him, but with a look the significance of which could not +be understood by mortal man. Either this look meant nothing but that +as long as one has eyes they must look somewhere, or it meant too +much. Pierre hesitated, not knowing what to do, and glanced +inquiringly at his guide. Anna Mikhaylovna made a hurried sign with +her eyes, glancing at the sick man's hand and moving her lips as if to +send it a kiss. Pierre, carefully stretching his neck so as not to +touch the quilt, followed her suggestion and pressed his lips to the +large boned, fleshy hand. Neither the hand nor a single muscle of +the count's face stirred. Once more Pierre looked questioningly at +Anna Mikhaylovna to see what he was to do next. Anna Mikhaylovna +with her eyes indicated a chair that stood beside the bed. Pierre +obediently sat down, his eyes asking if he were doing right. Anna +Mikhaylovna nodded approvingly. Again Pierre fell into the naively +symmetrical pose of an Egyptian statue, evidently distressed that +his stout and clumsy body took up so much room and doing his utmost to +look as small as possible. He looked at the count, who still gazed +at the spot where Pierre's face had been before he sat down. Anna +Mikhaylovna indicated by her attitude her consciousness of the +pathetic importance of these last moments of meeting between the +father and son. This lasted about two minutes, which to Pierre +seemed an hour. Suddenly the broad muscles and lines of the count's +face began to twitch. The twitching increased, the handsome mouth +was drawn to one side (only now did Pierre realize how near death +his father was), and from that distorted mouth issued an indistinct, +hoarse sound. Anna Mikhaylovna looked attentively at the sick man's +eyes, trying to guess what he wanted; she pointed first to Pierre, +then to some drink, then named Prince Vasili in an inquiring +whisper, then pointed to the quilt. The eyes and face of the sick +man showed impatience. He made an effort to look at the servant who +stood constantly at the head of the bed. + +"Wants to turn on the other side," whispered the servant, and got up +to turn the count's heavy body toward the wall. + +Pierre rose to help him. + +While the count was being turned over, one of his arms fell back +helplessly and he made a fruitless effort to pull it forward. +Whether he noticed the look of terror with which Pierre regarded +that lifeless arm, or whether some other thought flitted across his +dying brain, at any rate he glanced at the refractory arm, at Pierre's +terror-stricken face, and again at the arm, and on his face a +feeble, piteous smile appeared, quite out of keeping with his +features, that seemed to deride his own helplessness. At sight of this +smile Pierre felt an unexpected quivering in his breast and a tickling +in his nose, and tears dimmed his eyes. The sick man was turned on +to his side with his face to the wall. He sighed. + +"He is dozing," said Anna Mikhaylovna, observing that one of the +princesses was coming to take her turn at watching. "Let us go." + +Pierre went out. + + + + + +CHAPTER XXIV + + +There was now no one in the reception room except Prince Vasili +and the eldest princess, who were sitting under the portrait of +Catherine the Great and talking eagerly. As soon as they saw Pierre +and his companion they became silent, and Pierre thought he saw the +princess hide something as she whispered: + +"I can't bear the sight of that woman." + +"Catiche has had tea served in the small drawing room," said +Prince Vasili to Anna Mikhaylovna. "Go and take something, my poor +Anna Mikhaylovna, or you will not hold out." + +To Pierre he said nothing, merely giving his arm a sympathetic +squeeze below the shoulder. Pierre went with Anna Mikhaylovna into the +small drawing room. + +"There is nothing so refreshing after a sleepless night as a cup +of this delicious Russian tea," Lorrain was saying with an air of +restrained animation as he stood sipping tea from a delicate Chinese +handleless cup before a table on which tea and a cold supper were laid +in the small circular room. Around the table all who were at Count +Bezukhov's house that night had gathered to fortify themselves. Pierre +well remembered this small circular drawing room with its mirrors +and little tables. During balls given at the house Pierre, who did not +know how to dance, had liked sitting in this room to watch the +ladies who, as they passed through in their ball dresses with diamonds +and pearls on their bare shoulders, looked at themselves in the +brilliantly lighted mirrors which repeated their reflections several +times. Now this same room was dimly lighted by two candles. On one +small table tea things and supper dishes stood in disorder, and in the +middle of the night a motley throng of people sat there, not +merrymaking, but somberly whispering, and betraying by every word +and movement that they none of them forgot what was happening and what +was about to happen in the bedroom. Pierre did not eat anything though +he would very much have liked to. He looked inquiringly at his +monitress and saw that she was again going on tiptoe to the +reception room where they had left Prince Vasili and the eldest +princess. Pierre concluded that this also was essential, and after a +short interval followed her. Anna Mikhaylovna was standing beside +the princess, and they were both speaking in excited whispers. + +"Permit me, Princess, to know what is necessary and what is not +necessary," said the younger of the two speakers, evidently in the +same state of excitement as when she had slammed the door of her room. + +"But, my dear princess," answered Anna Mikhaylovna blandly but +impressively, blocking the way to the bedroom and preventing the other +from passing, "won't this be too much for poor Uncle at a moment +when he needs repose? Worldly conversation at a moment when his soul +is already prepared..." + +Prince Vasili was seated in an easy chair in his familiar +attitude, with one leg crossed high above the other. His cheeks, which +were so flabby that they looked heavier below, were twitching +violently; but he wore the air of a man little concerned in what the +two ladies were saying. + +"Come, my dear Anna Mikhaylovna, let Catiche do as she pleases. +You know how fond the count is of her." + +"I don't even know what is in this paper," said the younger of the +two ladies, addressing Prince Vasili and pointing to an inlaid +portfolio she held in her hand. "All I know is that his real will is +in his writing table, and this is a paper he has forgotten...." + +She tried to pass Anna Mikhaylovna, but the latter sprang so as to +bar her path. + +"I know, my dear, kind princess," said Anna Mikhaylovna, seizing the +portfolio so firmly that it was plain she would not let go easily. +"Dear princess, I beg and implore you, have some pity on him! Je +vous en conjure..." + +The princess did not reply. Their efforts in the struggle for the +portfolio were the only sounds audible, but it was evident that if the +princess did speak, her words would not be flattering to Anna +Mikhaylovna. Though the latter held on tenaciously, her voice lost +none of its honeyed firmness and softness. + +"Pierre, my dear, come here. I think he will not be out of place +in a family consultation; is it not so, Prince?" + +"Why don't you speak, cousin?" suddenly shrieked the princess so +loud that those in the drawing room heard her and were startled. +"Why do you remain silent when heaven knows who permits herself to +interfere, making a scene on the very threshold of a dying man's room? +Intriguer!" she hissed viciously, and tugged with all her might at the +portfolio. + +But Anna Mikhaylovna went forward a step or two to keep her hold +on the portfolio, and changed her grip. + +Prince Vasili rose. "Oh!" said he with reproach and surprise, +"this is absurd! Come, let go I tell you." + +The princess let go. + +"And you too!" + +But Anna Mikhaylovna did not obey him. + +"Let go, I tell you! I will take the responsibility. I myself will +go and ask him, I!... does that satisfy you?" + +"But, Prince," said Anna Mikhaylovna, "after such a solemn +sacrament, allow him a moment's peace! Here, Pierre, tell them your +opinion," said she, turning to the young man who, having come quite +close, was gazing with astonishment at the angry face of the +princess which had lost all dignity, and at the twitching cheeks of +Prince Vasili. + +"Remember that you will answer for the consequences," said Prince +Vasili severely. "You don't know what you are doing." + +"Vile woman!" shouted the princess, darting unexpectedly at Anna +Mikhaylovna and snatching the portfolio from her. + +Prince Vasili bent his head and spread out his hands. + +At this moment that terrible door, which Pierre had watched so +long and which had always opened so quietly, burst noisily open and +banged against the wall, and the second of the three sisters rushed +out wringing her hands. + +"What are you doing!" she cried vehemently. "He is dying and you +leave me alone with him!" + +Her sister dropped the portfolio. Anna Mikhaylovna, stooping, +quickly caught up the object of contention and ran into the bedroom. +The eldest princess and Prince Vasili, recovering themselves, followed +her. A few minutes later the eldest sister came out with a pale hard +face, again biting her underlip. At sight of Pierre her expression +showed an irrepressible hatred. + +"Yes, now you may be glad!" said she; "this is what you have been +waiting for." And bursting into tears she hid her face in her +handkerchief and rushed from the room. + +Prince Vasili came next. He staggered to the sofa on which Pierre +was sitting and dropped onto it, covering his face with his hand. +Pierre noticed that he was pale and that his jaw quivered and shook as +if in an ague. + +"Ah, my friend!" said he, taking Pierre by the elbow; and there +was in his voice a sincerity and weakness Pierre had never observed in +it before. "How often we sin, how much we deceive, and all for what? I +am near sixty, dear friend... I too... All will end in death, all! +Death is awful..." and he burst into tears. + +Anna Mikhaylovna came out last. She approached Pierre with slow, +quiet steps. + +"Pierre!" she said. + +Pierre gave her an inquiring look. She kissed the young man on his +forehead, wetting him with her tears. Then after a pause she said: + +"He is no more...." + +Pierre looked at her over his spectacles. + +"Come, I will go with you. Try to weep, nothing gives such relief as +tears." + +She led him into the dark drawing room and Pierre was glad no one +could see his face. Anna Mikhaylovna left him, and when she returned +he was fast asleep with his head on his arm. + +In the morning Anna Mikhaylovna said to Pierre: + +"Yes, my dear, this is a great loss for us all, not to speak of you. +But God will support you: you are young, and are now, I hope, in +command of an immense fortune. The will has not yet been opened. I +know you well enough to be sure that this will not turn your head, but +it imposes duties on you, and you must be a man." + +Pierre was silent. + +"Perhaps later on I may tell you, my dear boy, that if I had not +been there, God only knows what would have happened! You know, Uncle +promised me only the day before yesterday not to forget Boris. But +he had no time. I hope, my dear friend, you will carry out your +father's wish?" + +Pierre understood nothing of all this and coloring shyly looked in +silence at Princess Anna Mikhaylovna. After her talk with Pierre, Anna +Mikhaylovna returned to the Rostovs' and went to bed. On waking in the +morning she told the Rostovs and all her acquaintances the details +of Count Bezukhov's death. She said the count had died as she would +herself wish to die, that his end was not only touching but +edifying. As to the last meeting between father and son, it was so +touching that she could not think of it without tears, and did not +know which had behaved better during those awful moments--the father +who so remembered everything and everybody at last and had +spoken such pathetic words to the son, or Pierre, whom it had been +pitiful to see, so stricken was he with grief, though he tried hard to +hide it in order not to sadden his dying father. "It is painful, but +it does one good. It uplifts the soul to see such men as the old count +and his worthy son," said she. Of the behavior of the eldest +princess and Prince Vasili she spoke disapprovingly, but in whispers +and as a great secret. + + + + + +CHAPTER XXV + + +At Bald Hills, Prince Nicholas Andreevich Bolkonski's estate, the +arrival of young Prince Andrew and his wife was daily expected, but +this expectation did not upset the regular routine of life in the +old prince's household. General in Chief Prince Nicholas Andreevich +(nicknamed in society, "the King of Prussia") ever since the Emperor +Paul had exiled him to his country estate had lived there continuously +with his daughter, Princess Mary, and her companion, Mademoiselle +Bourienne. Though in the new reign he was free to return to the +capitals, he still continued to live in the country, remarking that +anyone who wanted to see him could come the hundred miles from +Moscow to Bald Hills, while he himself needed no one and nothing. He +used to say that there are only two sources of human vice--idleness +and superstition, and only two virtues--activity and intelligence. +He himself undertook his daughter's education, and to develop these +two cardinal virtues in her gave her lessons in algebra and geometry +till she was twenty, and arranged her life so that her whole time +was occupied. He was himself always occupied: writing his memoirs, +solving problems in higher mathematics, turning snuffboxes on a lathe, +working in the garden, or superintending the building that was +always going on at his estate. As regularity is a prime condition +facilitating activity, regularity in his household was carried to +the highest point of exactitude. He always came to table under +precisely the same conditions, and not only at the same hour but at +the same minute. With those about him, from his daughter to his serfs, +the prince was sharp and invariably exacting, so that without being +a hardhearted man he inspired such fear and respect as few hardhearted +men would have aroused. Although he was in retirement and had now no +influence in political affairs, every high official appointed to the +province in which the prince's estate lay considered it his duty to +visit him and waited in the lofty antechamber ante chamber just as the +architect, gardener, or Princess Mary did, till the prince appeared +punctually to the appointed hour. Everyone sitting in this antechamber +experienced the same feeling of respect and even fear when the +enormously high study door opened and showed the figure of a rather +small old man, with powdered wig, small withered hands, and bushy gray +eyebrows which, when he frowned, sometimes hid the gleam of his +shrewd, youthfully glittering eyes. + +On the morning of the day that the young couple were to arrive, +Princess Mary entered the antechamber as usual at the time appointed +for the morning greeting, crossing herself with trepidation and +repeating a silent prayer. Every morning she came in like that, and +every morning prayed that the daily interview might pass off well. + +An old powdered manservant who was sitting in the antechamber rose +quietly and said in a whisper: "Please walk in." + +Through the door came the regular hum of a lathe. The princess +timidly opened the door which moved noiselessly and easily. She paused +at the entrance. The prince was working at the lathe and after +glancing round continued his work. + +The enormous study was full of things evidently in constant use. The +large table covered with books and plans, the tall glass-fronted +bookcases with keys in the locks, the high desk for writing while +standing up, on which lay an open exercise book, and the lathe with +tools laid ready to hand and shavings scattered around--all +indicated continuous, varied, and orderly activity. The motion of +the small foot shod in a Tartar boot embroidered with silver, and +the firm pressure of the lean sinewy hand, showed that the prince +still possessed the tenacious endurance and vigor of hardy old age. +After a few more turns of the lathe he removed his foot from the +pedal, wiped his chisel, dropped it into a leather pouch attached to +the lathe, and, approaching the table, summoned his daughter. He never +gave his children a blessing, so he simply held out his bristly +cheek (as yet unshaven) and, regarding her tenderly and attentively, +said severely: + +"Quite well? All right then, sit down." He took the exercise book +containing lessons in geometry written by himself and drew up a +chair with his foot. + +"For tomorrow!" said he, quickly finding the page and making a +scratch from one paragraph to another with his hard nail. + +The princess bent over the exercise book on the table. + +"Wait a bit, here's a letter for you," said the old man suddenly, +taking a letter addressed in a woman's hand from a bag hanging above +the table, onto which he threw it. + +At the sight of the letter red patches showed themselves on the +princess' face. She took it quickly and bent her head over it. + +"From Heloise?" asked the prince with a cold smile that showed his +still sound, yellowish teeth. + +"Yes, it's from Julie," replied the princess with a timid glance and +a timid smile. + +"I'll let two more letters pass, but the third I'll read," said +the prince sternly; "I'm afraid you write much nonsense. I'll read the +third!" + +"Read this if you like, Father," said the princess, blushing still +more and holding out the letter. + +"The third, I said the third!" cried the prince abruptly, pushing +the letter away, and leaning his elbows on the table he drew toward +him the exercise book containing geometrical figures. + +"Well, madam," he began, stooping over the book close to his +daughter and placing an arm on the back of the chair on which she sat, +so that she felt herself surrounded on all sides by the acrid scent of +old age and tobacco, which she had known so long. "Now, madam, these +triangles are equal; please note that the angle ABC..." + +The princess looked in a scared way at her father's eyes +glittering close to her; the red patches on her face came and went, +and it was plain that she understood nothing and was so frightened +that her fear would prevent her understanding any of her father's +further explanations, however clear they might be. Whether it was +the teacher's fault or the pupil's, this same thing happened every +day: the princess' eyes grew dim, she could not see and could not hear +anything, but was only conscious of her stern father's withered face +close to her, of his breath and the smell of him, and could think only +of how to get away quickly to her own room to make out the problem +in peace. The old man was beside himself: moved the chair on which +he was sitting noisily backward and forward, made efforts to control +himself and not become vehement, but almost always did become +vehement, scolded, and sometimes flung the exercise book away. + +The princess gave a wrong answer. + +"Well now, isn't she a fool!" shouted the prince, pushing the book +aside and turning sharply away; but rising immediately, he paced up +and down, lightly touched his daughter's hair and sat down again. + +He drew up his chair, and continued to explain. + +"This won't do, Princess; it won't do," said he, when Princess Mary, +having taken and closed the exercise book with the next day's +lesson, was about to leave: "Mathematics are most important, madam! +I don't want to have you like our silly ladies. Get used to it and +you'll like it," and he patted her cheek. "It will drive all the +nonsense out of your head." + +She turned to go, but he stopped her with a gesture and took an +uncut book from the high desk. + +"Here is some sort of Key to the Mysteries that your Heloise has +sent you. Religious! I don't interfere with anyone's belief... I +have looked at it. Take it. Well, now go. Go." + +He patted her on the shoulder and himself closed the door after her. + +Princess Mary went back to her room with the sad, scared +expression that rarely left her and which made her plain, sickly +face yet plainer. She sat down at her writing table, on which stood +miniature portraits and which was littered with books and papers. +The princess was as untidy as her father was tidy. She put down the +geometry book and eagerly broke the seal of her letter. It was from +her most intimate friend from childhood; that same Julie Karagina +who had been at the Rostovs' name-day party. + +Julie wrote in French: + + +Dear and precious Friend, How terrible and frightful a thing is +separation! Though I tell myself that half my life and half my +happiness are wrapped up in you, and that in spite of the distance +separating us our hearts are united by indissoluble bonds, my heart +rebels against fate and in spite of the pleasures and distractions +around me I cannot overcome a certain secret sorrow that has been in +my heart ever since we parted. Why are we not together as we were last +summer, in your big study, on the blue sofa, the confidential sofa? +Why cannot I now, as three months ago, draw fresh moral strength +from your look, so gentle, calm, and penetrating, a look I loved so +well and seem to see before me as I write? + + +Having read thus far, Princess Mary sighed and glanced into the +mirror which stood on her right. It reflected a weak, ungraceful +figure and thin face. Her eyes, always sad, now looked with particular +hopelessness at her reflection in the glass. "She flatters me," +thought the princess, turning away and continuing to read. But Julie +did not flatter her friend, the princess' eyes--large, deep and +luminous (it seemed as if at times there radiated from them shafts +of warm light)--were so beautiful that very often in spite of the +plainness of her face they gave her an attraction more powerful than +that of beauty. But the princess never saw the beautiful expression of +her own eyes--the look they had when she was not thinking of +herself. As with everyone, her face assumed a forced unnatural +expression as soon as she looked in a glass. She went on reading: + + +All Moscow talks of nothing but war. One of my two brothers is +already abroad, the other is with the Guards, who are starting on +their march to the frontier. Our dear Emperor has left Petersburg +and it is thought intends to expose his precious person to the chances +of war. God grant that the Corsican monster who is destroying the +peace of Europe may be overthrown by the angel whom it has pleased the +Almighty, in His goodness, to give us as sovereign! To say nothing +of my brothers, this war has deprived me of one of the associations +nearest my heart. I mean young Nicholas Rostov, who with his +enthusiasm could not bear to remain inactive and has left the +university to join the army. I will confess to you, dear Mary, that in +spite of his extreme youth his departure for the army was a great +grief to me. This young man, of whom I spoke to you last summer, is so +noble-minded and full of that real youthfulness which one seldom finds +nowadays among our old men of twenty and, particularly, he is so frank +and has so much heart. He is so pure and poetic that my relations with +him, transient as they were, have been one of the sweetest comforts to +my poor heart, which has already suffered so much. Someday I will tell +you about our parting and all that was said then. That is still too +fresh. Ah, dear friend, you are happy not to know these poignant +joys and sorrows. You are fortunate, for the latter are generally +the stronger! I know very well that Count Nicholas is too young ever +to be more to me than a friend, but this sweet friendship, this poetic +and pure intimacy, were what my heart needed. But enough of this! +The chief news, about which all Moscow gossips, is the death of old +Count Bezukhov, and his inheritance. Fancy! The three princesses +have received very little, Prince Vasili nothing, and it is Monsieur +Pierre who has inherited all the property and has besides been +recognized as legitimate; so that he is now Count Bezukhov and +possessor of the finest fortune in Russia. It is rumored that Prince +Vasili played a very despicable part in this affair and that he +returned to Petersburg quite crestfallen. + +I confess I understand very little about all these matters of +wills and inheritance; but I do know that since this young man, whom +we all used to know as plain Monsieur Pierre, has become Count +Bezukhov and the owner of one of the largest fortunes in Russia, I +am much amused to watch the change in the tone and manners of the +mammas burdened by marriageable daughters, and of the young ladies +themselves, toward him, though, between you and me, he always seemed +to me a poor sort of fellow. As for the past two years people have +amused themselves by finding husbands for me (most of whom I don't +even know), the matchmaking chronicles of Moscow now speak of me as +the future Countess Bezukhova. But you will understand that I have +no desire for the post. A propos of marriages: do you know that a +while ago that universal auntie Anna Mikhaylovna told me, under the +seal of strict secrecy, of a plan of marriage for you. It is neither +more nor less than with Prince Vasili's son Anatole, whom they wish to +reform by marrying him to someone rich and distinguee, and it is on +you that his relations' choice has fallen. I don't know what you +will think of it, but I consider it my duty to let you know of it. +He is said to be very handsome and a terrible scapegrace. That is +all I have been able to find out about him. + +But enough of gossip. I am at the end of my second sheet of paper, +and Mamma has sent for me to go and dine at the Apraksins'. Read the +mystical book I am sending you; it has an enormous success here. +Though there are things in it difficult for the feeble human mind to +grasp, it is an admirable book which calms and elevates the soul. +Adieu! Give my respects to monsieur your father and my compliments +to Mademoiselle Bourienne. I embrace you as I love you. + +JULIE + +P.S. Let me have news of your brother and his charming little wife. + + +The princess pondered awhile with a thoughtful smile and her +luminous eyes lit up so that her face was entirely transformed. Then +she suddenly rose and with her heavy tread went up to the table. She +took a sheet of paper and her hand moved rapidly over it. This is +the reply she wrote, also in French: + + +Dear and precious Friend, Your letter of the 13th has given me great +delight. So you still love me, my romantic Julie? Separation, of which +you say so much that is bad, does not seem to have had its usual +effect on you. You complain of our separation. What then should I say, +if I dared complain, I who am deprived of all who are dear to me? +Ah, if we had not religion to console us life would be very sad. Why +do you suppose that I should look severely on your affection for +that young man? On such matters I am only severe with myself. I +understand such feelings in others, and if never having felt them I +cannot approve of them, neither do I condemn them. Only it seems to me +that Christian love, love of one's neighbor, love of one's enemy, is +worthier, sweeter, and better than the feelings which the beautiful +eyes of a young man can inspire in a romantic and loving young girl +like yourself. + +The news of Count Bezukhov's death reached us before your letter and +my father was much affected by it. He says the count was the last +representative but one of the great century, and that it is his own +turn now, but that he will do all he can to let his turn come as +late as possible. God preserve us from that terrible misfortune! + +I cannot agree with you about Pierre, whom I knew as a child. He +always seemed to me to have an excellent heart, and that is the +quality I value most in people. As to his inheritance and the part +played by Prince Vasili, it is very sad for both. Ah, my dear +friend, our divine Saviour's words, that it is easier for a camel to +go through the eye of a needle than for a rich man to enter the +Kingdom of God, are terribly true. I pity Prince Vasili but am still +more sorry for Pierre. So young, and burdened with such riches--to +what temptations he will be exposed! If I were asked what I desire +most on earth, it would be to be poorer than the poorest beggar. A +thousand thanks, dear friend, for the volume you have sent me and +which has such success in Moscow. Yet since you tell me that among +some good things it contains others which our weak human understanding +cannot grasp, it seems to me rather useless to spend time in reading +what is unintelligible and can therefore bear no fruit. I never +could understand the fondness some people have for confusing their +minds by dwelling on mystical books that merely awaken their doubts +and excite their imagination, giving them a bent for exaggeration +quite contrary to Christian simplicity. Let us rather read the +Epistles and Gospels. Let us not seek to penetrate what mysteries they +contain; for how can we, miserable sinners that we are, know the +terrible and holy secrets of Providence while we remain in this +flesh which forms an impenetrable veil between us and the Eternal? Let +us rather confine ourselves to studying those sublime rules which +our divine Saviour has left for our guidance here below. Let us try to +conform to them and follow them, and let us be persuaded that the less +we let our feeble human minds roam, the better we shall please God, +who rejects all knowledge that does not come from Him; and the less we +seek to fathom what He has been pleased to conceal from us, the sooner +will He vouchsafe its revelation to us through His divine Spirit. + +My father has not spoken to me of a suitor, but has only told me +that he has received a letter and is expecting a visit from Prince +Vasili. In regard to this project of marriage for me, I will tell you, +dear sweet friend, that I look on marriage as a divine institution +to which we must conform. However painful it may be to me, should +the Almighty lay the duties of wife and mother upon me I +shall try to perform them as faithfully as I can, without +disquieting myself by examining my feelings toward him whom He may +give me for husband. + +I have had a letter from my brother, who announces his speedy +arrival at Bald Hills with his wife. This pleasure will be but a brief +one, however, for he will leave, us again to take part in this unhappy +war into which we have been drawn, God knows how or why. Not only +where you are--at the heart of affairs and of the world--is the talk +all of war, even here amid fieldwork and the calm of nature--which +townsfolk consider characteristic of the country--rumors of war are +heard and painfully felt. My father talks of nothing but marches and +countermarches, things of which I understand nothing; and the day +before yesterday during my daily walk through the village I +witnessed a heartrending scene.... It was a convoy of conscripts +enrolled from our people and starting to join the army. You should +have seen the state of the mothers, wives, and children of the men who +were going and should have heard the sobs. It seems as though +mankind has forgotten the laws of its divine Saviour, Who preached +love and forgiveness of injuries--and that men attribute the +greatest merit to skill in killing one another. + +Adieu, dear and kind friend; may our divine Saviour and His most +Holy Mother keep you in their holy and all-powerful care! + +MARY + + +"Ah, you are sending off a letter, Princess? I have already +dispatched mine. I have written to my poor mother," said the smiling +Mademoiselle Bourienne rapidly, in her pleasant mellow tones and +with guttural r's. She brought into Princess Mary's strenuous, +mournful, and gloomy world a quite different atmosphere, careless, +lighthearted, and self-satisfied. + +"Princess, I must warn you," she added, lowering her voice and +evidently listening to herself with pleasure, and speaking with +exaggerated grasseyement, "the prince has been scolding Michael +Ivanovich. He is in a very bad humor, very morose. Be prepared." + +"Ah, dear friend," replied Princess Mary, "I have asked you never to +warn me of the humor my father is in. I do not allow myself to judge +him and would not have others do so." + +The princess glanced at her watch and, seeing that she was five +minutes late in starting her practice on the clavichord, went into the +sitting room with a look of alarm. Between twelve and two o'clock, +as the day was mapped out, the prince rested and the princess played +the clavichord. + + + + + +CHAPTER XXVI + + +The gray-haired valet was sitting drowsily listening to the +snoring of the prince, who was in his large study. From the far side +of the house through the closed doors came the sound of difficult +passages--twenty times repeated--of a sonata by Dussek. + +Just then a closed carriage and another with a hood drove up to +the porch. Prince Andrew got out of the carriage, helped his little +wife to alight, and let her pass into the house before him. Old +Tikhon, wearing a wig, put his head out of the door of the +antechamber, reported in a whisper that the prince was sleeping, and +hastily closed the door. Tikhon knew that neither the son's arrival +nor any other unusual event must be allowed to disturb the appointed +order of the day. Prince Andrew apparently knew this as well as +Tikhon; he looked at his watch as if to ascertain whether his father's +habits had changed since he was at home last, and, having assured +himself that they had not, he turned to his wife. + +"He will get up in twenty minutes. Let us go across to Mary's room," +he said. + +The little princess had grown stouter during this time, but her eyes +and her short, downy, smiling lip lifted when she began to speak +just as merrily and prettily as ever. + +"Why, this is a palace!" she said to her husband, looking around +with the expression with which people compliment their host at a ball. +"Let's come, quick, quick!" And with a glance round, she smiled at +Tikhon, at her husband, and at the footman who accompanied them. + +"Is that Mary practicing? Let's go quietly and take her by +surprise." + +Prince Andrew followed her with a courteous but sad expression. + +"You've grown older, Tikhon," he said in passing to the old man, who +kissed his hand. + +Before they reached the room from which the sounds of the clavichord +came, the pretty, fair haired Frenchwoman, Mademoiselle Bourienne, +rushed out apparently beside herself with delight. + +"Ah! what joy for the princess!" exclaimed she: "At last! I must let +her know." + +"No, no, please not... You are Mademoiselle Bourienne," said the +little princess, kissing her. "I know you already through my +sister-in-law's friendship for you. She was not expecting us?" + +They went up to the door of the sitting room from which came the +sound of the oft-repeated passage of the sonata. Prince Andrew stopped +and made a grimace, as if expecting something unpleasant. + +The little princess entered the room. The passage broke off in the +middle, a cry was heard, then Princess Mary's heavy tread and the +sound of kissing. When Prince Andrew went in the two princesses, who +had only met once before for a short time at his wedding, were in each +other's arms warmly pressing their lips to whatever place they +happened to touch. Mademoiselle Bourienne stood near them pressing her +hand to her heart, with a beatific smile and obviously equally ready +to cry or to laugh. Prince Andrew shrugged his shoulders and +frowned, as lovers of music do when they hear a false note. The two +women let go of one another, and then, as if afraid of being too late, +seized each other's hands, kissing them and pulling them away, and +again began kissing each other on the face, and then to Prince +Andrew's surprise both began to cry and kissed again. Mademoiselle +Bourienne also began to cry. Prince Andrew evidently felt ill at ease, +but to the two women it seemed quite natural that they should cry, and +apparently it never entered their heads that it could have been +otherwise at this meeting. + +"Ah! my dear!... Ah! Mary!" they suddenly exclaimed, and then +laughed. "I dreamed last night..."--"You were not expecting us?..."- +"Ah! Mary, you have got thinner?..." "And you have grown stouter!..." + +"I knew the princess at once," put in Mademoiselle Bourienne. + +"And I had no idea!..." exclaimed Princess Mary. "Ah, Andrew, I +did not see you." + +Prince Andrew and his sister, hand in hand, kissed one another, +and he told her she was still the same crybaby as ever. Princess +Mary had turned toward her brother, and through her tears the +loving, warm, gentle look of her large luminous eyes, very beautiful +at that moment, rested on Prince Andrew's face. + +The little princess talked incessantly, her short, downy upper lip +continually and rapidly touching her rosy nether lip when necessary +and drawing up again next moment when her face broke into a smile of +glittering teeth and sparkling eyes. She told of an accident they +had had on the Spasski Hill which might have been serious for her in +her condition, and immediately after that informed them that she had +left all her clothes in Petersburg and that heaven knew what she would +have to dress in here; and that Andrew had quite changed, and that +Kitty Odyntsova had married an old man, and that there was a suitor +for Mary, a real one, but that they would talk of that later. Princess +Mary was still looking silently at her brother and her beautiful +eyes were full of love and sadness. It was plain that she was +following a train of thought independent of her sister-in-law's words. +In the midst of a description of the last Petersburg fete she +addressed her brother: + +"So you are really going to the war, Andrew?" she said sighing. + +Lise sighed too. + +"Yes, and even tomorrow," replied her brother. + +"He is leaving me here, God knows why, when he might have had +promotion..." + +Princess Mary did not listen to the end, but continuing her train of +thought turned to her sister-in-law with a tender glance at her +figure. + +"Is it certain?" she said. + +The face of the little princess changed. She sighed and said: +"Yes, quite certain. Ah! it is very dreadful..." + +Her lip descended. She brought her face close to her sister-in-law's +and unexpectedly again began to cry. + +"She needs rest," said Prince Andrew with a frown. "Don't you, Lise? +Take her to your room and I'll go to Father. How is he? Just the +same?" + +"Yes, just the same. Though I don't know what your opinion will be," +answered the princess joyfully. + +"And are the hours the same? And the walks in the avenues? And the +lathe?" asked Prince Andrew with a scarcely perceptible smile which +showed that, in spite of all his love and respect for his father, he +was aware of his weaknesses. + +"The hours are the same, and the lathe, and also the mathematics and +my geometry lessons," said Princess Mary gleefully, as if her +lessons in geometry were among the greatest delights of her life. + +When the twenty minutes had elapsed and the time had come for the +old prince to get up, Tikhon came to call the young prince to his +father. The old man made a departure from his usual routine in honor +of his son's arrival: he gave orders to admit him to his apartments +while he dressed for dinner. The old prince always dressed in +old-fashioned style, wearing an antique coat and powdered hair; and +when Prince Andrew entered his father's dressing room (not with the +contemptuous look and manner he wore in drawing rooms, but with the +animated face with which he talked to Pierre), the old man was sitting +on a large leather-covered chair, wrapped in a powdering mantle, +entrusting his head to Tikhon. + +"Ah! here's the warrior! Wants to vanquish Buonaparte?" said the old +man, shaking his powdered head as much as the tail, which Tikhon was +holding fast to plait, would allow. + +"You at least must tackle him properly, or else if he goes on like +this he'll soon have us, too, for his subjects! How are you?" And he +held out his cheek. + +The old man was in a good temper after his nap before dinner. (He +used to say that a nap "after dinner was silver--before dinner, +golden.") He cast happy, sidelong glances at his son from under his +thick, bushy eyebrows. Prince Andrew went up and kissed his father +on the spot indicated to him. He made no reply on his father's +favorite topic--making fun of the military men of the day, and more +particularly of Bonaparte. + +"Yes, Father, I have come come to you and brought my wife who is +pregnant," said Prince Andrew, following every movement of his +father's face with an eager and respectful look. "How is your health?" + +"Only fools and rakes fall ill, my boy. You know me: I am busy +from morning till night and abstemious, so of course I am well." + +"Thank God," said his son smiling. + +"God has nothing to do with it! Well, go on," he continued, +returning to his hobby; "tell me how the Germans have taught you to +fight Bonaparte by this new science you call 'strategy.'" + +Prince Andrew smiled. + +"Give me time to collect my wits, Father," said he, with a smile +that showed that his father's foibles did not prevent his son from +loving and honoring him. "Why, I have not yet had time to settle +down!" + +"Nonsense, nonsense!" cried the old man, shaking his pigtail to +see whether it was firmly plaited, and grasping his by the hand. +"The house for your wife is ready. Princess Mary will take her there +and show her over, and they'll talk nineteen to the dozen. That's +their woman's way! I am glad to have her. Sit down and talk. About +Mikhelson's army I understand--Tolstoy's too... a simultaneous +expedition.... But what's the southern army to do? Prussia is +neutral... I know that. What about Austria?" said he, rising from +his chair and pacing up and down the room followed by Tikhon, who +ran after him, handing him different articles of clothing. "What of +Sweden? How will they cross Pomerania?" + +Prince Andrew, seeing that his father insisted, began--at first +reluctantly, but gradually with more and more animation, and from +habit changing unconsciously from Russian to French as he went on- +to explain the plan of operation for the coming campaign. He explained +how an army, ninety thousand strong, was to threaten Prussia so as +to bring her out of her neutrality and draw her into the war; how part +of that army was to join some Swedish forces at Stralsund; how two +hundred and twenty thousand Austrians, with a hundred thousand +Russians, were to operate in Italy and on the Rhine; how fifty +thousand Russians and as many English were to land at Naples, and +how a total force of five hundred thousand men was to attack the +French from different sides. The old prince did not evince the least +interest during this explanation, but as if he were not listening to +it continued to dress while walking about, and three times +unexpectedly interrupted. Once he stopped it by shouting: "The white +one, the white one!" + +This meant that Tikhon was not handing him the waistcoat he +wanted. Another time he interrupted, saying: + +"And will she soon be confined?" and shaking his head +reproachfully said: "That's bad! Go on, go on." + +The third interruption came when Prince Andrew was finishing his +description. The old man began to sing, in the cracked voice of old +age: "Malbrook s'en va-t-en guerre. Dieu sait quand reviendra."* + + +*"Marlborough is going to the wars; God knows when he'll return." + + +His son only smiled. + +"I don't say it's a plan I approve of," said the son; "I am only +telling you what it is. Napoleon has also formed his plan by now, +not worse than this one." + +"Well, you've told me nothing new," and the old man repeated, +meditatively and rapidly: + +"Dieu sait quand reviendra. Go to the dining room." + + + + + +CHAPTER XXVII + + +At the appointed hour the prince, powdered and shaven, entered the +dining room where his daughter-in-law, Princess Mary, and Mademoiselle +Bourienne were already awaiting him together with his architect, who +by a strange caprice of his employer's was admitted to table though +the position of that insignificant individual was such as could +certainly not have caused him to expect that honor. The prince, who +generally kept very strictly to social distinctions and rarely +admitted even important government officials to his table, had +unexpectedly selected Michael Ivanovich (who always went into a corner +to blow his nose on his checked handkerchief) to illustrate the theory +that all men are equals, and had more than once impressed on his +daughter that Michael Ivanovich was "not a whit worse than you or +I." At dinner the prince usually spoke to the taciturn Michael +Ivanovich more often than to anyone else. + +In the dining room, which like all the rooms in the house was +exceedingly lofty, the members of the household and the footmen--one +behind each chair--stood waiting for the prince to enter. The head +butler, napkin on arm, was scanning the setting of the table, making +signs to the footmen, and anxiously glancing from the clock to the +door by which the prince was to enter. Prince Andrew was looking at +a large gilt frame, new to him, containing the genealogical tree of +the Princes Bolkonski, opposite which hung another such frame with a +badly painted portrait (evidently by the hand of the artist +belonging to the estate) of a ruling prince, in a crown--an alleged +descendant of Rurik and ancestor of the Bolkonskis. Prince Andrew, +looking again at that genealogical tree, shook his head, laughing as a +man laughs who looks at a portrait so characteristic of the original +as to be amusing. + +"How thoroughly like him that is!" he said to Princess Mary, who had +come up to him. + +Princess Mary looked at her brother in surprise. She did not +understand what he was laughing at. Everything her father did inspired +her with reverence and was beyond question. + +"Everyone has his Achilles' heel," continued Prince Andrew. +"Fancy, with his powerful mind, indulging in such nonsense!" + +Princess Mary could not understand the boldness of her brother's +criticism and was about to reply, when the expected footsteps were +heard coming from the study. The prince walked in quickly and jauntily +as was his wont, as if intentionally contrasting the briskness of +his manners with the strict formality of his house. At that moment the +great clock struck two and another with a shrill tone joined in from +the drawing room. The prince stood still; his lively glittering eyes +from under their thick, bushy eyebrows sternly scanned all present and +rested on the little princess. She felt, as courtiers do when the Tsar +enters, the sensation of fear and respect which the old man inspired +in all around him. He stroked her hair and then patted her awkwardly +on the back of her neck. + +"I'm glad, glad, to see you," he said, looking attentively into +her eyes, and then quickly went to his place and sat down. "Sit +down, sit down! Sit down, Michael Ianovich!" + +He indicated a place beside him to his daughter-in-law. A footman +moved the chair for her. + +"Ho, ho!" said the old man, casting his eyes on her rounded +figure. "You've been in a hurry. That's bad!" + +He laughed in his usual dry, cold, unpleasant way, with his lips +only and not with his eyes. + +"You must walk, walk as much as possible, as much as possible," he +said. + +The little princess did not, or did not wish to, hear his words. She +was silent and seemed confused. The prince asked her about her father, +and she began to smile and talk. He asked about mutual +acquaintances, and she became still more animated and chattered away +giving him greetings from various people and retailing the town +gossip. + +"Countess Apraksina, poor thing, has lost her husband and she has +cried her eyes out," she said, growing more and more lively. + +As she became animated the prince looked at her more and more +sternly, and suddenly, as if he had studied her sufficiently and had +formed a definite idea of her, he turned away and addressed Michael +Ivanovich. + +"Well, Michael Ivanovich, our Bonaparte will be having a bad time of +it. Prince Andrew" (he always spoke thus of his son) "has been telling +me what forces are being collected against him! While you and I +never thought much of him." + +Michael Ivanovich did not at all know when "you and I" had said such +things about Bonaparte, but understanding that he was wanted as a +peg on which to hang the prince's favorite topic, he looked +inquiringly at the young prince, wondering what would follow. + +"He is a great tactician!" said the prince to his son, pointing to +the architect. + +And the conversation again turned on the war, on Bonaparte, and +the generals and statesmen of the day. The old prince seemed convinced +not only that all the men of the day were mere babies who did not know +the A B C of war or of politics, and that Bonaparte was an +insignificant little Frenchy, successful only because there were no +longer any Potemkins or Suvorovs left to oppose him; but he was also +convinced that there were no political difficulties in Europe and no +real war, but only a sort of puppet show at which the men of the day +were playing, pretending to do something real. Prince Andrew gaily +bore with his father's ridicule of the new men, and drew him on and +listened to him with evident pleasure. + +"The past always seems good," said he, "but did not Suvorov +himself fall into a trap Moreau set him, and from which he did not +know how to escape?" + +"Who told you that? Who?" cried the prince. "Suvorov!" And he jerked +away his plate, which Tikhon briskly caught. "Suvorov!... Consider, +Prince Andrew. Two... Frederick and Suvorov; Moreau!... Moreau would +have been a prisoner if Suvorov had had a free hand; but he had the +Hofs-kriegs-wurst-schnapps-Rath on his hands. It would have puzzled +the devil himself! When you get there you'll find out what those +Hofs-kriegs-wurst-Raths are! Suvorov couldn't manage them so what +chance has Michael Kutuzov? No, my dear boy," he continued, "you and +your generals won't get on against Buonaparte; you'll have to call +in the French, so that birds of a feather may fight together. The +German, Pahlen, has been sent to New York in America, to fetch the +Frenchman, Moreau," he said, alluding to the invitation made that year +to Moreau to enter the Russian service.... "Wonderful!... Were the +Potemkins, Suvorovs, and Orlovs Germans? No, lad, either you fellows +have all lost your wits, or I have outlived mine. May God help you, +but we'll see what will happen. Buonaparte has become a great +commander among them! Hm!..." + +"I don't at all say that all the plans are good," said Prince +Andrew, "I am only surprised at your opinion of Bonaparte. You may +laugh as much as you like, but all the same Bonaparte is a great +general!" + +"Michael Ivanovich!" cried the old prince to the architect who, busy +with his roast meat, hoped he had been forgotten: "Didn't I tell you +Buonaparte was a great tactician? Here, he says the same thing." + +"To be sure, your excellency." replied the architect. + +The prince again laughed his frigid laugh. + +"Buonaparte was born with a silver spoon in his mouth. He has got +splendid soldiers. Besides he began by attacking Germans. And only +idlers have failed to beat the Germans. Since the world began +everybody has beaten the Germans. They beat no one--except one +another. He made his reputation fighting them." + +And the prince began explaining all the blunders which, according to +him, Bonaparte had made in his campaigns and even in politics. His son +made no rejoinder, but it was evident that whatever arguments were +presented he was as little able as his father to change his opinion. +He listened, refraining from a reply, and involuntarily wondered how +this old man, living alone in the country for so many years, could +know and discuss so minutely and acutely all the recent European +military and political events. + +"You think I'm an old man and don't understand the present state +of affairs?" concluded his father. "But it troubles me. I don't +sleep at night. Come now, where has this great commander of yours +shown his skill?" he concluded. + +"That would take too long to tell," answered the son. + +"Well, then go to your Buonaparte! Mademoiselle Bourienne, here's +another admirer of that powder-monkey emperor of yours," he +exclaimed in excellent French. + +"You know, Prince, I am not a Bonapartist!" + +"Dieu sait quand reviendra..." hummed the prince out of tune and, +with a laugh still more so, he quitted the table. + +The little princess during the whole discussion and the rest of +the dinner sat silent, glancing with a frightened look now at her +father-in-law and now at Princess Mary. When they left the table she +took her sister-in-law's arm and drew her into another room. + +"What a clever man your father is," said she; "perhaps that is why I +am afraid of him." + +"Oh, he is so kind!" answered Princess Mary. + + + + + +CHAPTER XXVIII + + +Prince Andrew was to leave next evening. The old prince, not +altering his routine, retired as usual after dinner. The little +princess was in her sister-in-law's room. Prince Andrew in a traveling +coat without epaulettes had been packing with his valet in the rooms +assigned to him. After inspecting the carriage himself and seeing +the trunks put in, he ordered the horses to be harnessed. Only those +things he always kept with him remained in his room; a small box, a +large canteen fitted with silver plate, two Turkish pistols and a +saber--a present from his father who had brought it from the siege +of Ochakov. All these traveling effects of Prince Andrew's were in +very good order: new, clean, and in cloth covers carefully tied with +tapes. + +When starting on a journey or changing their mode of life, men +capable of reflection are generally in a serious frame of mind. At +such moments one reviews the past and plans for the future. Prince +Andrew's face looked very thoughtful and tender. With his hands behind +him he paced briskly from corner to corner of the room, looking +straight before him and thoughtfully shaking his head. Did he fear +going to the war, or was he sad at leaving his wife?--perhaps both, +but evidently he did not wish to be seen in that mood, for hearing +footsteps in the passage he hurriedly unclasped his hands, stopped +at a table as if tying the cover of the small box, and assumed his +usual tranquil and impenetrable expression. It was the heavy tread +of Princess Mary that he heard. + +"I hear you have given orders to harness," she cried, panting (she +had apparently been running), "and I did so wish to have another +talk with you alone! God knows how long we may again be parted. You +are not angry with me for coming? You have changed so, Andrusha," +she added, as if to explain such a question. + +She smiled as she uttered his pet name, "Andrusha." It was obviously +strange to her to think that this stern handsome man should be +Andrusha--the slender mischievous boy who had been her playfellow in +childhood. + +"And where is Lise?" he asked, answering her question only by a +smile. + +"She was so tired that she has fallen asleep on the sofa in my room. +Oh, Andrew! What a treasure of a wife you have," said she, sitting +down on the sofa, facing her brother. "She is quite a child: such a +dear, merry child. I have grown so fond of her." + +Prince Andrew was silent, but the princess noticed the ironical +and contemptuous look that showed itself on his face. + +"One must be indulgent to little weaknesses; who is free from +them, Andrew? Don't forget that she has grown up and been educated +in society, and so her position now is not a rosy one. We should enter +into everyone's situation. Tout comprendre, c'est tout pardonner.* +Think it must be for her, poor thing, after what she has been used to, +to be parted from her husband and be left alone in the country, in her +condition! It's very hard." + + +*To understand all is to forgive all. + + +Prince Andrew smiled as he looked at his sister, as we smile at +those we think we thoroughly understand. + +"You live in the country and don't think the life terrible," he +replied. + +"I... that's different. Why speak of me? I don't want any other +life, and can't, for I know no other. But think, Andrew: for a young +society woman to be buried in the country during the best years of her +life, all alone--for Papa is always busy, and I... well, you know what +poor resources I have for entertaining a woman used to the best +society. There is only Mademoiselle Bourienne...." + +"I don't like your Mademoiselle Bourienne at all," said Prince +Andrew. + +"No? She is very nice and kind and, above all, she's much to be +pitied. She has no one, no one. To tell the truth, I don't need her, +and she's even in my way. You know I always was a savage, and now am +even more so. I like being alone.... Father likes her very much. She +and Michael Ivanovich are the two people to whom he is always gentle +and kind, because he has been a benefactor to them both. As Sterne +says: 'We don't love people so much for the good they have done us, as +for the good we have done them.' Father took her when she was homeless +after losing her own father. She is very good-natured, and my father +likes her way of reading. She reads to him in the evenings and reads +splendidly." + +"To be quite frank, Mary, I expect Father's character sometimes +makes things trying for you, doesn't it?" Prince Andrew asked +suddenly. + +Princess Mary was first surprised and then aghast at this question. + +"For me? For me?... Trying for me!..." said she. + +"He always was rather harsh; and now I should think he's getting +very trying," said Prince Andrew, apparently speaking lightly of their +father in order to puzzle or test his sister. + +"You are good in every way, Andrew, but you have a kind of +intellectual pride," said the princess, following the train of her own +thoughts rather than the trend of the conversation--"and that's a +great sin. How can one judge Father? But even if one might, what +feeling except veneration could such a man as my father evoke? And I +am so contented and happy with him. I only wish you were all as +happy as I am." + +Her brother shook his head incredulously. + +"The only thing that is hard for me... I will tell you the truth, +Andrew... is Father's way of treating religious subjects. I don't +understand how a man of his immense intellect can fail to see what +is as clear as day, and can go so far astray. That is the only thing +that makes me unhappy. But even in this I can see lately a shade of +improvement. His satire has been less bitter of late, and there was +a monk he received and had a long talk with." + +"Ah! my dear, I am afraid you and your monk are wasting your +powder," said Prince Andrew banteringly yet tenderly. + +"Ah! mon ami, I only pray, and hope that God will hear me. +Andrew..." she said timidly after a moment's silence, "I have a +great favor to ask of you." + +"What is it, dear?" + +"No--promise that you will not refuse! It will give you no trouble +and is nothing unworthy of you, but it will comfort me. Promise, +Andrusha!..." said she, putting her hand in her reticule but not yet +taking out what she was holding inside it, as if what she held were +the subject of her request and must not be shown before the request +was granted. + +She looked timidly at her brother. + +"Even if it were a great deal of trouble..." answered Prince Andrew, +as if guessing what it was about. + +"Think what you please! I know you are just like Father. Think as +you please, but do this for my sake! Please do! Father's father, our +grandfather, wore it in all his wars." (She still did not take out +what she was holding in her reticule.) "So you promise?" + +"Of course. What is it?" + +"Andrew, I bless you with this icon and you must promise me you will +never take it off. Do you promise?" + +"If it does not weigh a hundredweight and won't break my neck... +To please you..." said Prince Andrew. But immediately, noticing the +pained expression his joke had brought to his sister's face, he +repented and added: "I am glad; really, dear, I am very glad." + +"Against your will He will save and have mercy on you and bring +you to Himself, for in Him alone is truth and peace," said she in a +voice trembling with emotion, solemnly holding up in both hands before +her brother a small, oval, antique, dark-faced icon of the Saviour +in a gold setting, on a finely wrought silver chain. + +She crossed herself, kissed the icon, and handed it to Andrew. + +"Please, Andrew, for my sake!..." + +Rays of gentle light shone from her large, timid eyes. Those eyes +lit up the whole of her thin, sickly face and made it beautiful. Her +brother would have taken the icon, but she stopped him. Andrew +understood, crossed himself and kissed the icon. There was a look of +tenderness, for he was touched, but also a gleam of irony on his face. + +"Thank you, my dear." She kissed him on the forehead and sat down +again on the sofa. They were silent for a while. + +"As I was saying to you, Andrew, be kind and generous as you +always used to be. Don't judge Lise harshly," she began. "She is so +sweet, so good-natured, and her position now is a very hard one." + +"I do not think I have complained of my wife to you, Masha, or +blamed her. Why do you say all this to me?" + +Red patches appeared on Princess Mary's face and she was silent as +if she felt guilty. + +"I have said nothing to you, but you have already been talked to. +And I am sorry for that," he went on. + +The patches grew deeper on her forehead, neck, and cheeks. She tried +to say something but could not. Her brother had guessed right: the +little princess had been crying after dinner and had spoken of her +forebodings about her confinement, and how she dreaded it, and had +complained of her fate, her father-in-law, and her husband. After +crying she had fallen asleep. Prince Andrew felt sorry for his sister. + +"Know this, Masha: I can't reproach, have not reproached, and +never shall reproach my wife with anything, and I cannot reproach +myself with anything in regard to her; and that always will be so in +whatever circumstances I may be placed. But if you want to know the +truth... if you want to know whether I am happy? No! Is she happy? No! +But why this is so I don't know..." + +As he said this he rose, went to his sister, and, stooping, kissed +her forehead. His fine eyes lit up with a thoughtful, kindly, and +unaccustomed brightness, but he was looking not at his sister but over +her head toward the darkness of the open doorway. + +"Let us go to her, I must say good-by. Or--go and wake and I'll come +in a moment. Petrushka!" he called to his valet: "Come here, take +these away. Put this on the seat and this to the right." + +Princess Mary rose and moved to the door, then stopped and said: +"Andrew, if you had faith you would have turned to God and asked Him +to give you the love you do not feel, and your prayer would have +been answered." + +"Well, may be!" said Prince Andrew. "Go, Masha; I'll come +immediately." + +On the way to his sister's room, in the passage which connected +one wing with the other, Prince Andrew met Mademoiselle Bourienne +smiling sweetly. It was the third time that day that, with an ecstatic +and artless smile, she had met him in secluded passages. + +"Oh! I thought you were in your room," she said, for some reason +blushing and dropping her eyes. + +Prince Andrew looked sternly at her and an expression of anger +suddenly came over his face. He said nothing to her but looked at +her forehead and hair, without looking at her eyes, with such contempt +that the Frenchwoman blushed and went away without a word. When he +reached his sister's room his wife was already awake and her merry +voice, hurrying one word after another, came through the open door. +She was speaking as usual in French, and as if after long +self-restraint she wished to make up for lost time. + +"No, but imagine the old Countess Zubova, with false curls and her +mouth full of false teeth, as if she were trying to cheat old +age.... Ha, ha, ha! Mary!" + +This very sentence about Countess Zubova and this same laugh +Prince Andrew had already heard from his wife in the presence of +others some five times. He entered the room softly. The little +princess, plump and rosy, was sitting in an easy chair with her work +in her hands, talking incessantly, repeating Petersburg +reminiscences and even phrases. Prince Andrew came up, stroked her +hair, and asked if she felt rested after their journey. She answered +him and continued her chatter. + +The coach with six horses was waiting at the porch. It was an autumn +night, so dark that the coachman could not see the carriage pole. +Servants with lanterns were bustling about in the porch. The immense +house was brilliant with lights shining through its lofty windows. The +domestic serfs were crowding in the hall, waiting to bid good-by to +the young prince. The members of the household were all gathered in +the reception hall: Michael Ivanovich, Mademoiselle Bourienne, +Princess Mary, and the little princess. Prince Andrew had been +called to his father's study as the latter wished to say good-by to +him alone. All were waiting for them to come out. + +When Prince Andrew entered the study the old man in his old-age +spectacles and white dressing gown, in which he received no one but +his son, sat at the table writing. He glanced round. + +"Going?" And he went on writing. + +"I've come to say good-by." + +"Kiss me here," and he touched his cheek: "Thanks, thanks!" + +"What do you thank me for?" + +"For not dilly-dallying and not hanging to a woman's apron +strings. The Service before everything. Thanks, thanks!" And he went +on writing, so that his quill spluttered and squeaked. "If you have +anything to say, say it. These two things can be done together," he +added. + +"About my wife... I am ashamed as it is to leave her on your +hands..." + +"Why talk nonsense? Say what you want." + +"When her confinement is due, send to Moscow for an accoucheur.... +Let him be here...." + +The old prince stopped writing and, as if not understanding, fixed +his stern eyes on his son. + +"I know that no one can help if nature does not do her work," said +Prince Andrew, evidently confused. "I know that out of a million cases +only one goes wrong, but it is her fancy and mine. They have been +telling her things. She has had a dream and is frightened." + +"Hm... Hm..." muttered the old prince to himself, finishing what +he was writing. "I'll do it." + +He signed with a flourish and suddenly turning to his son began to +laugh. + +"It's a bad business, eh?" + +"What is bad, Father?" + +"The wife!" said the old prince, briefly and significantly. + +"I don't understand!" said Prince Andrew. + +"No, it can't be helped, lad," said the prince. "They're all like +that; one can't unmarry. Don't be afraid; I won't tell anyone, but you +know it yourself." + +He seized his son by the hand with small bony fingers, shook it, +looked straight into his son's face with keen eyes which seemed to see +through him, and again laughed his frigid laugh. + +The son sighed, thus admitting that his father had understood him. +The old man continued to fold and seal his letter, snatching up and +throwing down the wax, the seal, and the paper, with his accustomed +rapidity. + +"What's to be done? She's pretty! I will do everything. Make your +mind easy," said he in abrupt sentences while sealing his letter. + +Andrew did not speak; he was both pleased and displeased that his +father understood him. The old man got up and gave the letter to his +son. + +"Listen!" said he; "don't worry about your wife: what can be done +shall be. Now listen! Give this letter to Michael Ilarionovich.* I +have written that he should make use of you in proper places and not +keep you long as an adjutant: a bad position! Tell him I remember +and like him. Write and tell me how he receives you. If he is all +right--serve him. Nicholas Bolkonski's son need not serve under anyone +if he is in disfavor. Now come here." + + +*Kutuzov. + + +He spoke so rapidly that he did not finish half his words, but his +son was accustomed to understand him. He led him to the desk, raised +the lid, drew out a drawer, and took out an exercise book filled +with his bold, tall, close handwriting. + +"I shall probably die before you. So remember, these are my memoirs; +hand them to the Emperor after my death. Now here is a Lombard bond +and a letter; it is a premium for the man who writes a history of +Suvorov's wars. Send it to the Academy. Here are some jottings for you +to read when I am gone. You will find them useful." + +Andrew did not tell his father that he would no doubt live a long +time yet. He felt that he must not say it. + +"I will do it all, Father," he said. + +"Well, now, good-by!" He gave his son his hand to kiss, and embraced +him. "Remember this, Prince Andrew, if they kill you it will hurt +me, your old father..." he paused unexpectedly, and then in a +querulous voice suddenly shrieked: "but if I hear that you have not +behaved like a son of Nicholas Bolkonski, I shall be ashamed!" + +"You need not have said that to me, Father," said the son with a +smile. + +The old man was silent. + +"I also wanted to ask you," continued Prince Andrew, "if I'm +killed and if I have a son, do not let him be taken away from you- +as I said yesterday... let him grow up with you.... Please." + +"Not let the wife have him?" said the old man, and laughed. + +They stood silent, facing one another. The old man's sharp eyes were +fixed straight on his son's. Something twitched in the lower part of +the old prince's face. + +"We've said good-by. Go!" he suddenly shouted in a loud, angry +voice, opening his door. + +"What is it? What?" asked both princesses when they saw for a moment +at the door Prince Andrew and the figure of the old man in a white +dressing gown, spectacled and wigless, shouting in an angry voice. + +Prince Andrew sighed and made no reply. + +"Well!" he said, turning to his wife. + +And this "Well!" sounded coldly ironic, as if he were saying,: +"Now go through your performance." + +"Andrew, already!" said the little princess, turning pale and +looking with dismay at her husband. + +He embraced her. She screamed and fell unconscious on his shoulder. + +He cautiously released the shoulder she leaned on, looked into her +face, and carefully placed her in an easy chair. + +"Adieu, Mary," said he gently to his sister, taking her by the +hand and kissing her, and then he left the room with rapid steps. + +The little princess lay in the armchair, Mademoiselle Bourienne +chafing her temples. Princess Mary, supporting her sister-in-law, +still looked with her beautiful eyes full of tears at the door through +which Prince Andrew had gone and made the sign of the cross in his +direction. From the study, like pistol shots, came the frequent +sound of the old man angrily blowing his nose. Hardly had Prince +Andrew gone when the study door opened quickly and the stern figure of +the old man in the white dressing gown looked out. + +"Gone? That's all right!" said he; and looking angrily at the +unconscious little princess, he shook his head reprovingly and slammed +the door. + + + + + +BOOK TWO: 1805 + + + + + +CHAPTER I + + +In October, 1805, a Russian army was occupying the villages and +towns of the Archduchy of Austria, and yet other regiments freshly +arriving from Russia were settling near the fortress of Braunau and +burdening the inhabitants on whom they were quartered. Braunau was the +headquarters of the commander-in-chief, Kutuzov. + +On October 11, 1805, one of the infantry regiments that had just +reached Braunau had halted half a mile from the town, waiting to be +inspected by the commander in chief. Despite the un-Russian appearance +of the locality and surroundings--fruit gardens, stone fences, tiled +roofs, and hills in the distance--and despite the fact that the +inhabitants (who gazed with curiosity at the soldiers) were not +Russians, the regiment had just the appearance of any Russian regiment +preparing for an inspection anywhere in the heart of Russia. + +On the evening of the last day's march an order had been received +that the commander in chief would inspect the regiment on the march. +Though the words of the order were not clear to the regimental +commander, and the question arose whether the troops were to be in +marching order or not, it was decided at a consultation between the +battalion commanders to present the regiment in parade order, on the +principle that it is always better to "bow too low than not bow low +enough." So the soldiers, after a twenty-mile march, were kept mending +and cleaning all night long without closing their eyes, while the +adjutants and company commanders calculated and reckoned, and by +morning the regiment--instead of the straggling, disorderly crowd it +had been on its last march the day before--presented a well-ordered +array of two thousand men each of whom knew his place and his duty, +had every button and every strap in place, and shone with cleanliness. +And not only externally was all in order, but had it pleased the +commander in chief to look under the uniforms he would have found on +every man a clean shirt, and in every knapsack the appointed number of +articles, "awl, soap, and all," as the soldiers say. There was only +one circumstance concerning which no one could be at ease. It was +the state of the soldiers' boots. More than half the men's boots +were in holes. But this defect was not due to any fault of the +regimental commander, for in spite of repeated demands boots had not +been issued by the Austrian commissariat, and the regiment had marched +some seven hundred miles. + +The commander of the regiment was an elderly, choleric, stout, and +thick-set general with grizzled eyebrows and whiskers, and wider +from chest to back than across the shoulders. He had on a brand-new +uniform showing the creases where it had been folded and thick gold +epaulettes which seemed to stand rather than lie down on his massive +shoulders. He had the air of a man happily performing one of the +most solemn duties of his life. He walked about in front of the line +and at every step pulled himself up, slightly arching his back. It was +plain that the commander admired his regiment, rejoiced in it, and +that his whole mind was engrossed by it, yet his strut seemed to +indicate that, besides military matters, social interests and the fair +sex occupied no small part of his thoughts. + +"Well, Michael Mitrich, sir?" he said, addressing one of the +battalion commanders who smilingly pressed forward (it was plain +that they both felt happy). "We had our hands full last night. +However, I think the regiment is not a bad one, eh?" + +The battalion commander perceived the jovial irony and laughed. + +"It would not be turned off the field even on the Tsaritsin Meadow." + +"What?" asked the commander. + +At that moment, on the road from the town on which signalers had +been posted, two men appeared on horse back. They were an +aide-de-camp followed by a Cossack. + +The aide-de-camp was sent to confirm the order which had not been +clearly worded the day before, namely, that the commander in chief +wished to see the regiment just in the state in which it had been on +the march: in their greatcoats, and packs, and without any preparation +whatever. + +A member of the Hofkriegsrath from Vienna had come to Kutuzov the +day before with proposals and demands for him to join up with the army +of the Archduke Ferdinand and Mack, and Kutuzov, not considering +this junction advisable, meant, among other arguments in support of +his view, to show the Austrian general the wretched state in which the +troops arrived from Russia. With this object he intended to meet the +regiment; so the worse the condition it was in, the better pleased the +commander in chief would be. Though the aide-de-camp did not know +these circumstances, he nevertheless delivered the definite order that +the men should be in their greatcoats and in marching order, and +that the commander in chief would otherwise be dissatisfied. On +hearing this the regimental commander hung his head, silently shrugged +his shoulders, and spread out his arms with a choleric gesture. + +"A fine mess we've made of it!" he remarked. + +"There now! Didn't I tell you, Michael Mitrich, that if it was +said 'on the march' it meant in greatcoats?" said he reproachfully +to the battalion commander. "Oh, my God!" he added, stepping +resolutely forward. "Company commanders!" he shouted in a voice +accustomed to command. "Sergeants major!... How soon will he be here?" +he asked the aide-de-camp with a respectful politeness evidently +relating to the personage he was referring to. + +"In an hour's time, I should say." + +"Shall we have time to change clothes?" + +"I don't know, General...." + +The regimental commander, going up to the line himself, ordered +the soldiers to change into their greatcoats. The company commanders +ran off to their companies, the sergeants major began bustling (the +greatcoats were not in very good condition), and instantly the squares +that had up to then been in regular order and silent began to sway and +stretch and hum with voices. On all sides soldiers were running to and +fro, throwing up their knapsacks with a jerk of their shoulders and +pulling the straps over their heads, unstrapping their overcoats and +drawing the sleeves on with upraised arms. + +In half an hour all was again in order, only the squares had +become gray instead of black. The regimental commander walked with his +jerky steps to the front of the regiment and examined it from a +distance. + +"Whatever is this? This!" he shouted and stood still. "Commander +of the third company!" + +"Commander of the third company wanted by the general!... +commander to the general... third company to the commander." The words +passed along the lines and an adjutant ran to look for the missing +officer. + +When the eager but misrepeated words had reached their destination +in a cry of: "The general to the third company," the missing officer +appeared from behind his company and, though he was a middle-aged +man and not in the habit of running, trotted awkwardly stumbling on +his toes toward the general. The captain's face showed the +uneasiness of a schoolboy who is told to repeat a lesson he has not +learned. Spots appeared on his nose, the redness of which was +evidently due to intemperance, and his mouth twitched nervously. The +general looked the captain up and down as he came up panting, +slackening his pace as he approached. + +"You will soon be dressing your men in petticoats! What is this?" +shouted the regimental commander, thrusting forward his jaw and +pointing at a soldier in the ranks of the third company in a greatcoat +of bluish cloth, which contrasted with the others. "What have you been +after? The commander in chief is expected and you leave your place? +Eh? I'll teach you to dress the men in fancy coats for a parade.... +Eh...?" + +The commander of the company, with his eyes fixed on his superior, +pressed two fingers more and more rigidly to his cap, as if in this +pressure lay his only hope of salvation. + +"Well, why don't you speak? Whom have you got there dressed up as +a Hungarian?" said the commander with an austere gibe. + +"Your excellency..." + +"Well, your excellency, what? Your excellency! But what about your +excellency?... nobody knows." + +"Your excellency, it's the officer Dolokhov, who has been reduced to +the ranks," said the captain softly. + +"Well? Has he been degraded into a field marshal, or into a soldier? +If a soldier, he should be dressed in regulation uniform like the +others." + +"Your excellency, you gave him leave yourself, on the march." + +"Gave him leave? Leave? That's just like you young men," said the +regimental commander cooling down a little. "Leave indeed.... One says +a word to you and you... What?" he added with renewed irritation, "I +beg you to dress your men decently." + +And the commander, turning to look at the adjutant, directed his +jerky steps down the line. He was evidently pleased at his own display +of anger and walking up to the regiment wished to find a further +excuse for wrath. Having snapped at an officer for an unpolished +badge, at another because his line was not straight, he reached the +third company. + +"H-o-o-w are you standing? Where's your leg? Your leg?" shouted +the commander with a tone of suffering in his voice, while there +were still five men between him and Dolokhov with his bluish-gray +uniform. + +Dolokhov slowly straightened his bent knee, looking straight with +his clear, insolent eyes in the general's face. + +"Why a blue coat? Off with it... Sergeant major! Change his +coat... the ras..." he did not finish. + +"General, I must obey orders, but I am not bound to endure..." +Dolokhov hurriedly interrupted. + +"No talking in the ranks!... No talking, no talking!" + +"Not bound to endure insults," Dolokhov concluded in loud, ringing +tones. + +The eyes of the general and the soldier met. The general became +silent, angrily pulling down his tight scarf. + +"I request you to have the goodness to change your coat," he said as +he turned away. + + + + + +CHAPTER II + + +"He's coming!" shouted the signaler at that moment. + +The regimental commander, flushing, ran to his horse, seized the +stirrup with trembling hands, threw his body across the saddle, +righted himself, drew his saber, and with a happy and resolute +countenance, opening his mouth awry, prepared to shout. The regiment +fluttered like a bird preening its plumage and became motionless. + +"Att-ention!" shouted the regimental commander in a soul-shaking +voice which expressed joy for himself, severity for the regiment, +and welcome for the approaching chief. + +Along the broad country road, edged on both sides by trees, came a +high, light blue Viennese caleche, slightly creaking on its springs +and drawn by six horses at a smart trot. Behind the caleche galloped +the suite and a convoy of Croats. Beside Kutuzov sat an Austrian +general, in a white uniform that looked strange among the Russian +black ones. The caleche stopped in front of the regiment. Kutuzov +and the Austrian general were talking in low voices and Kutuzov smiled +slightly as treading heavily he stepped down from the carriage just as +if those two thousand men breathlessly gazing at him and the +regimental commander did not exist. + +The word of command rang out, and again the regiment quivered, as +with a jingling sound it presented arms. Then amidst a dead silence +the feeble voice of the commander in chief was heard. The regiment +roared, "Health to your ex... len... len... lency!" and again all +became silent. At first Kutuzov stood still while the regiment +moved; then he and the general in white, accompanied by the suite, +walked between the ranks. + +From the way the regimental commander saluted the commander in chief +and devoured him with his eyes, drawing himself up obsequiously, and +from the way he walked through the ranks behind the generals, +bending forward and hardly able to restrain his jerky movements, and +from the way he darted forward at every word or gesture of the +commander in chief, it was evident that he performed his duty as a +subordinate with even greater zeal than his duty as a commander. +Thanks to the strictness and assiduity of its commander the +regiment, in comparison with others that had reached Braunau at the +same time, was in splendid condition. There were only 217 sick and +stragglers. Everything was in good order except the boots. + +Kutuzov walked through the ranks, sometimes stopping to say a few +friendly words to officers he had known in the Turkish war, +sometimes also to the soldiers. Looking at their boots he several +times shook his head sadly, pointing them out to the Austrian +general with an expression which seemed to say that he was not blaming +anyone, but could not help noticing what a bad state of things it was. +The regimental commander ran forward on each such occasion, fearing to +miss a single word of the commander in chief's regarding the regiment. +Behind Kutuzov, at a distance that allowed every softly spoken word to +be heard, followed some twenty men of his suite. These gentlemen +talked among themselves and sometimes laughed. Nearest of all to the +commander in chief walked a handsome adjutant. This was Prince +Bolkonski. Beside him was his comrade Nesvitski, a tall staff officer, +extremely stout, with a kindly, smiling, handsome face and moist eyes. +Nesvitski could hardly keep from laughter provoked by a swarthy hussar +officer who walked beside him. This hussar, with a grave face and +without a smile or a change in the expression of his fixed eyes, +watched the regimental commander's back and mimicked his every +movement. Each time the commander started and bent forward, the hussar +started and bent forward in exactly the same manner. Nesvitski laughed +and nudged the others to make them look at the wag. + +Kutuzov walked slowly and languidly past thousands of eyes which +were starting from their sockets to watch their chief. On reaching the +third company he suddenly stopped. His suite, not having expected +this, involuntarily came closer to him. + +"Ah, Timokhin!" said he, recognizing the red-nosed captain who had +been reprimanded on account of the blue greatcoat. + +One would have thought it impossible for a man to stretch himself +more than Timokhin had done when he was reprimanded by the +regimental commander, but now that the commander in chief addressed +him he drew himself up to such an extent that it seemed he could not +have sustained it had the commander in chief continued to look at him, +and so Kutuzov, who evidently understood his case and wished him +nothing but good, quickly turned away, a scarcely perceptible smile +flitting over his scarred and puffy face. + +"Another Ismail comrade," said he. "A brave officer! Are you +satisfied with him?" he asked the regimental commander. + +And the latter--unconscious that he was being reflected in the +hussar officer as in a looking glass--started, moved forward, and +answered: "Highly satisfied, your excellency!" + +"We all have our weaknesses," said Kutuzov smiling and walking +away from him. "He used to have a predilection for Bacchus." + +The regimental commander was afraid he might be blamed for this +and did not answer. The hussar at that moment noticed the face of +the red-nosed captain and his drawn-in stomach, and mimicked his +expression and pose with such exactitude that Nesvitski could not help +laughing. Kutuzov turned round. The officer evidently had complete +control of his face, and while Kutuzov was turning managed to make a +grimace and then assume a most serious, deferential, and innocent +expression. + +The third company was the last, and Kutuzov pondered, apparently +trying to recollect something. Prince Andrew stepped forward from +among the suite and said in French: + +"You told me to remind you of the officer Dolokhov, reduced to the +ranks in this regiment." + +"Where is Dolokhov?" asked Kutuzov. + +Dolokhov, who had already changed into a soldier's gray greatcoat, +did not wait to be called. The shapely figure of the fair-haired +soldier, with his clear blue eyes, stepped forward from the ranks, +went up to the commander in chief, and presented arms. + +"Have you a complaint to make?" Kutuzov asked with a slight frown. + +"This is Dolokhov," said Prince Andrew. + +"Ah!" said Kutuzov. "I hope this will be a lesson to you. Do your +duty. The Emperor is gracious, and I shan't forget you if you +deserve well." + +The clear blue eyes looked at the commander in chief just as +boldly as they had looked at the regimental commander, seeming by +their expression to tear open the veil of convention that separates +a commander in chief so widely from a private. + +"One thing I ask of your excellency," Dolokhov said in his firm, +ringing, deliberate voice. "I ask an opportunity to atone for my fault +and prove my devotion to His Majesty the Emperor and to Russia!" + +Kutuzov turned away. The same smile of the eyes with which he had +turned from Captain Timokhin again flitted over his face. He turned +away with a grimace as if to say that everything Dolokhov had said +to him and everything he could say had long been known to him, that he +was weary of it and it was not at all what he wanted. He turned away +and went to the carriage. + +The regiment broke up into companies, which went to their +appointed quarters near Braunau, where they hoped to receive boots and +clothes and to rest after their hard marches. + +"You won't bear me a grudge, Prokhor Ignatych?" said the +regimental commander, overtaking the third company on its way to its +quarters and riding up to Captain Timokhin who was walking in front. +(The regimental commander's face now that the inspection was happily +over beamed with irrepressible delight.) "It's in the Emperor's +service... it can't be helped... one is sometimes a bit hasty on +parade... I am the first to apologize, you know me!... He was very +pleased!" And he held out his hand to the captain. + +"Don't mention it, General, as if I'd be so bold!" replied the +captain, his nose growing redder as he gave a smile which showed where +two front teeth were missing that had been knocked out by the butt end +of a gun at Ismail. + +"And tell Mr. Dolokhov that I won't forget him--he may be quite +easy. And tell me, please--I've been meaning to ask--how is to ask- +how is he behaving himself, and in general..." + +"As far as the service goes he is quite punctilious, your +excellency; but his character..." said Timokhin. + +"And what about his character?" asked the regimental commander. + +"It's different on different days," answered the captain. "One day +he is sensible, well educated, and good-natured, and the next he's a +wild beast.... In Poland, if you please, he nearly killed a Jew." + +"Oh, well, well!" remarked the regimental commander. "Still, one +must have pity on a young man in misfortune. You know he has important +connections... Well, then, you just..." + +"I will, your excellency," said Timokhin, showing by his smile +that he understood his commander's wish. + +"Well, of course, of course!" + +The regimental commander sought out Dolokhov in the ranks and, +reining in his horse, said to him: + +"After the next affair... epaulettes." + +Dolokhov looked round but did not say anything, nor did the +mocking smile on his lips change. + +"Well, that's all right," continued the regimental commander. "A cup +of vodka for the men from me," he added so that the soldiers could +hear. "I thank you all! God be praised!" and he rode past that company +and overtook the next one. + +"Well, he's really a good fellow, one can serve under him," said +Timokhin to the subaltern beside him. + +"In a word, a hearty one..." said the subaltern, laughing (the +regimental commander was nicknamed King of Hearts). + +The cheerful mood of their officers after the inspection infected +the soldiers. The company marched on gaily. The soldiers' voices could +be heard on every side. + +"And they said Kutuzov was blind of one eye?" + +"And so he is! Quite blind!" + +"No, friend, he is sharper-eyed than you are. Boots and leg bands... +he noticed everything..." + +"When he looked at my feet, friend... well, thinks I..." + +"And that other one with him, the Austrian, looked as if he were +smeared with chalk--as white as flour! I suppose they polish him up as +they do the guns." + +"I say, Fedeshon!... Did he say when the battles are to begin? You +were near him. Everybody said that Buonaparte himself was at Braunau." + +"Buonaparte himself!... Just listen to the fool, what he doesn't +know! The Prussians are up in arms now. The Austrians, you see, are +putting them down. When they've been put down, the war with Buonaparte +will begin. And he says Buonaparte is in Braunau! Shows you're a fool. +You'd better listen more carefully!" + +"What devils these quartermasters are! See, the fifth company is +turning into the village already... they will have their buckwheat +cooked before we reach our quarters." + +"Give me a biscuit, you devil!" + +"And did you give me tobacco yesterday? That's just it, friend! +Ah, well, never mind, here you are." + +"They might call a halt here or we'll have to do another four +miles without eating." + +"Wasn't it fine when those Germans gave us lifts! You just sit still +and are drawn along." + +"And here, friend, the people are quite beggarly. There they all +seemed to be Poles--all under the Russian crown--but here they're +all regular Germans." + +"Singers to the front " came the captain's order. + +And from the different ranks some twenty men ran to the front. A +drummer, their leader, turned round facing the singers, and +flourishing his arm, began a long-drawn-out soldiers' song, commencing +with the words: "Morning dawned, the sun was rising," and +concluding: "On then, brothers, on to glory, led by Father + +Kamenski." This song had been composed in the Turkish campaign and now +being sung in Austria, the only change being that the words "Father +Kamenski" were replaced by "Father Kutuzov." + +Having jerked out these last words as soldiers do and waved his arms +as if flinging something to the ground, the drummer--a lean, +handsome soldier of forty--looked sternly at the singers and screwed +up his eyes. Then having satisfied himself that all eyes were fixed on +him, he raised both arms as if carefully lifting some invisible but +precious object above his head and, holding it there for some seconds, +suddenly flung it down and began: + +"Oh, my bower, oh, my bower...!" + +"Oh, my bower new...!" chimed in twenty voices, and the castanet +player, in spite of the burden of his equipment, rushed out to the +front and, walking backwards before the company, jerked his +shoulders and flourished his castanets as if threatening someone. +The soldiers, swinging their arms and keeping time spontaneously, +marched with long steps. Behind the company the sound of wheels, the +creaking of springs, and the tramp of horses' hoofs were heard. +Kutuzov and his suite were returning to the town. The commander in +chief made a sign that the men should continue to march at ease, and +he and all his suite showed pleasure at the sound of the singing and +the sight of the dancing soldier and the gay and smartly marching men. +In the second file from the right flank, beside which the carriage +passed the company, a blue-eyed soldier involuntarily attracted +notice. It was Dolokhov marching with particular grace and boldness in +time to the song and looking at those driving past as if he pitied all +who were not at that moment marching with the company. The hussar +cornet of Kutuzov's suite who had mimicked the regimental commander, +fell back from the carriage and rode up to Dolokhov. + +Hussar cornet Zherkov had at one time, in Petersburg, belonged to +the wild set led by Dolokhov. Zherkov had met Dolokhov abroad as a +private and had not seen fit to recognize him. But now that Kutuzov +had spoken to the gentleman ranker, he addressed him with the +cordiality of an old friend. + +"My dear fellow, how are you?" said he through the singing, making +his horse keep pace with the company. + +"How am I?" Dolokhov answered coldly. "I am as you see." + +The lively song gave a special flavor to the tone of free and easy +gaiety with which Zherkov spoke, and to the intentional coldness of +Dolokhov's reply. + +"And how do you get on with the officers?" inquired Zherkov. + +"All right. They are good fellows. And how have you wriggled onto +the staff?" + +"I was attached; I'm on duty." + +Both were silent. + +"She let the hawk fly upward from her wide right sleeve," went the +song, arousing an involuntary sensation of courage and cheerfulness. +Their conversation would probably have been different but for the +effect of that song. + +"Is it true that Austrians have been beaten?" asked Dolokhov. + +"The devil only knows! They say so." + +"I'm glad," answered Dolokhov briefly and clearly, as the song +demanded. + +"I say, come round some evening and we'll have a game of faro!" said +Zherkov. + +"Why, have you too much money?" + +"Do come." + +"I can't. I've sworn not to. I won't drink and won't play till I get +reinstated." + +"Well, that's only till the first engagement." + +"We shall see." + +They were again silent. + +"Come if you need anything. One can at least be of use on the +staff..." + +Dolokhov smiled. "Don't trouble. If I want anything, I won't beg- +I'll take it!" + +"Well, never mind; I only..." + +"And I only..." + +"Good-by." + +"Good health..." + + "It's a long, long way. + To my native land..." + + +Zherkov touched his horse with the spurs; it pranced excitedly +from foot to foot uncertain with which to start, then settled down, +galloped past the company, and overtook the carriage, still keeping +time to the song. + + + + + +CHAPTER III + + +On returning from the review, Kutuzov took the Austrian general into +his private room and, calling his adjutant, asked for some papers +relating to the condition of the troops on their arrival, and the +letters that had come from the Archduke Ferdinand, who was in +command of the advanced army. Prince Andrew Bolkonski came into the +room with the required papers. Kutuzov and the Austrian member of +the Hofkriegsrath were sitting at the table on which a plan was spread +out. + +"Ah!..." said Kutuzov glancing at Bolkonski as if by this +exclamation he was asking the adjutant to wait, and he went on with +the conversation in French. + +"All I can say, General," said he with a pleasant elegance of +expression and intonation that obliged one to listen to each +deliberately spoken word. It was evident that Kutuzov himself listened +with pleasure to his own voice. "All I can say, General, is that if +the matter depended on my personal wishes, the will of His Majesty the +Emperor Francis would have been fulfilled long ago. I should long +ago have joined the archduke. And believe me on my honour that to me +personally it would be a pleasure to hand over the supreme command +of the army into the hands of a better informed and more skillful +general--of whom Austria has so many--and to lay down all this heavy +responsibility. But circumstances are sometimes too strong for us, +General." + +And Kutuzov smiled in a way that seemed to say, "You are quite at +liberty not to believe me and I don't even care whether you do or not, +but you have no grounds for telling me so. And that is the whole +point." + +The Austrian general looked dissatisfied, but had no option but to +reply in the same tone. + +"On the contrary," he said, in a querulous and angry tone that +contrasted with his flattering words, "on the contrary, your +excellency's participation in the common action is highly valued by +His Majesty; but we think the present delay is depriving the +splendid Russian troops and their commander of the laurels they have +been accustomed to win in their battles," he concluded his evidently +prearranged sentence. + +Kutuzov bowed with the same smile. + +"But that is my conviction, and judging by the last letter with +which His Highness the Archduke Ferdinand has honored me, I imagine +that the Austrian troops, under the direction of so skillful a +leader as General Mack, have by now already gained a decisive +victory and no longer need our aid," said Kutuzov. + +The general frowned. Though there was no definite news of an +Austrian defeat, there were many circumstances confirming the +unfavorable rumors that were afloat, and so Kutuzov's suggestion of an +Austrian victory sounded much like irony. But Kutuzov went on +blandly smiling with the same expression, which seemed to say that +he had a right to suppose so. And, in fact, the last letter he had +received from Mack's army informed him of a victory and stated +strategically the position of the army was very favorable. + +"Give me that letter," said Kutuzov turning to Prince Andrew. +"Please have a look at it"--and Kutuzov with an ironical smile about +the corners of his mouth read to the Austrian general the following +passage, in German, from the Archduke Ferdinand's letter: + + +We have fully concentrated forces of nearly seventy thousand men +with which to attack and defeat the enemy should he cross the Lech. +Also, as we are masters of Ulm, we cannot be deprived of the advantage +of commanding both sides of the Danube, so that should the enemy not +cross the Lech, we can cross the Danube, throw ourselves on his line +of communications, recross the river lower down, and frustrate his +intention should he try to direct his whole force against our faithful +ally. We shall therefore confidently await the moment when the +Imperial Russian army will be fully equipped, and shall then, in +conjunction with it, easily find a way to prepare for the enemy the +fate he deserves. + + +Kutuzov sighed deeply on finishing this paragraph and looked at +the member of the Hofkriegsrath mildly and attentively. + +"But you know the wise maxim your excellency, advising one to expect +the worst," said the Austrian general, evidently wishing to have +done with jests and to come to business. He involuntarily looked round +at the aide-de-camp. + +"Excuse me, General," interrupted Kutuzov, also turning to Prince +Andrew. "Look here, my dear fellow, get from Kozlovski all the reports +from our scouts. Here are two letters from Count Nostitz and here is +one from His Highness the Archduke Ferdinand and here are these," he +said, handing him several papers, "make a neat memorandum in French +out of all this, showing all the news we have had of the movements +of the Austrian army, and then give it to his excellency." + +Prince Andrew bowed his head in token of having understood from +the first not only what had been said but also what Kutuzov would have +liked to tell him. He gathered up the papers and with a bow to both, +stepped softly over the carpet and went out into the waiting room. + +Though not much time had passed since Prince Andrew had left Russia, +he had changed greatly during that period. In the expression of his +face, in his movements, in his walk, scarcely a trace was left of +his former affected languor and indolence. He now looked like a man +who has time to think of the impression he makes on others, but is +occupied with agreeable and interesting work. His face expressed +more satisfaction with himself and those around him, his smile and +glance were brighter and more attractive. + +Kutuzov, whom he had overtaken in Poland, had received him very +kindly, promised not to forget him, distinguished him above the +other adjutants, and had taken him to Vienna and given him the more +serious commissions. From Vienna Kutuzov wrote to his old comrade, +Prince Andrew's father. + + +Your son bids fair to become an officer distinguished by his +industry, firmness, and expedition. I consider myself fortunate to +have such a subordinate by me. + + +On Kutuzov's staff, among his fellow officers and in the army +generally, Prince Andrew had, as he had had in Petersburg society, two +quite opposite reputations. Some, a minority, acknowledged him to be +different from themselves and from everyone else, expected great +things of him, listened to him, admired, and imitated him, and with +them Prince Andrew was natural and pleasant. Others, the majority, +disliked him and considered him conceited, cold, and disagreeable. But +among these people Prince Andrew knew how to take his stand so that +they respected and even feared him. + +Coming out of Kutuzov's room into the waiting room with the papers +in his hand Prince Andrew came up to his comrade, the aide-de-camp +on duty, Kozlovski, who was sitting at the window with a book. + +"Well, Prince?" asked Kozlovski. + +"I am ordered to write a memorandum explaining why we are not +advancing." + +"And why is it?" + +Prince Andrew shrugged his shoulders. + +"Any news from Mack?" + +"No." + +"If it were true that he has been beaten, news would have come." + +"Probably," said Prince Andrew moving toward the outer door. + +But at that instant a tall Austrian general in a greatcoat, with the +order of Maria Theresa on his neck and a black bandage round his head, +who had evidently just arrived, entered quickly, slamming the door. +Prince Andrew stopped short. + +"Commander in Chief Kutuzov?" said the newly arrived general +speaking quickly with a harsh German accent, looking to both sides and +advancing straight toward the inner door. + +"The commander in chief is engaged," said Kozlovski, going hurriedly +up to the unknown general and blocking his way to the door. "Whom +shall I announce?" + +The unknown general looked disdainfully down at Kozlovski, who was +rather short, as if surprised that anyone should not know him. + +"The commander in chief is engaged," repeated Kozlovski calmly. + +The general's face clouded, his lips quivered and trembled. He +took out a notebook, hurriedly scribbled something in pencil, tore out +the leaf, gave it to Kozlovski, stepped quickly to the window, and +threw himself into a chair, gazing at those in the room as if +asking, "Why do they look at me?" Then he lifted his head, stretched +his neck as if he intended to say something, but immediately, with +affected indifference, began to hum to himself, producing a queer +sound which immediately broke off. The door of the private room opened +and Kutuzov appeared in the doorway. The general with the bandaged +head bent forward as though running away from some danger, and, making +long, quick strides with his thin legs, went up to Kutuzov. + +"Vous voyez le malheureux Mack," he uttered in a broken voice. + +Kutuzov's face as he stood in the open doorway remained perfectly +immobile for a few moments. Then wrinkles ran over his face like a +wave and his forehead became smooth again, he bowed his head +respectfully, closed his eyes, silently let Mack enter his room before +him, and closed the door himself behind him. + +The report which had been circulated that the Austrians had been +beaten and that the whole army had surrendered at Ulm proved to be +correct. Within half an hour adjutants had been sent in various +directions with orders which showed that the Russian troops, who had +hitherto been inactive, would also soon have to meet the enemy. + +Prince Andrew was one of those rare staff officers whose chief +interest lay in the general progress of the war. When he saw Mack +and heard the details of his disaster he understood that half the +campaign was lost, understood all the difficulties of the Russian +army's position, and vividly imagined what awaited it and the part +he would have to play. Involuntarily he felt a joyful agitation at the +thought of the humiliation of arrogant Austria and that in a week's +time he might, perhaps, see and take part in the first Russian +encounter with the French since Suvorov met them. He feared that +Bonaparte's genius might outweigh all the courage of the Russian +troops, and at the same time could not admit the idea of his hero +being disgraced. + +Excited and irritated by these thoughts Prince Andrew went toward +his room to write to his father, to whom he wrote every day. In the +corridor he met Nesvitski, with whom he shared a room, and the wag +Zherkov; they were as usual laughing. + +"Why are you so glum?" asked Nesvitski noticing Prince Andrew's pale +face and glittering eyes. + +"There's nothing to be gay about," answered Bolkonski. + +Just as Prince Andrew met Nesvitski and Zherkov, there came toward +them from the other end of the corridor, Strauch, an Austrian +general who on Kutuzov's staff in charge of the provisioning of the +Russian army, and the member of the Hofkriegsrath who had arrived +the previous evening. There was room enough in the wide corridor for +the generals to pass the three officers quite easily, but Zherkov, +pushing Nesvitski aside with his arm, said in a breathless voice, + +"They're coming!... they're coming!... Stand aside, make way, please +make way!" + +The generals were passing by, looking as if they wished to avoid +embarrassing attentions. On the face of the wag Zherkov there suddenly +appeared a stupid smile of glee which he seemed unable to suppress. + +"Your excellency," said he in German, stepping forward and +addressing the Austrian general, "I have the honor to congratulate +you." + +He bowed his head and scraped first with one foot and then with +the other, awkwardly, like a child at a dancing lesson. + +The member of the Hofkriegsrath looked at him severely but, seeing +the seriousness of his stupid smile, could not but give him a moment's +attention. He screwed up his eyes showing that he was listening. + +"I have the honor to congratulate you. General Mack has arrived, +quite well, only a little bruised just here," he added, pointing +with a beaming smile to his head. + +The general frowned, turned away, and went on. + +"Gott, wie naiv!"* said he angrily, after he had gone a few steps. + +*"Good God, what simplicity!" + + +Nesvitski with a laugh threw his arms round Prince Andrew, but +Bolkonski, turning still paler, pushed him away with an angry look and +turned to Zherkov. The nervous irritation aroused by the appearance of +Mack, the news of his defeat, and the thought of what lay before the +Russian army found vent in anger at Zherkov's untimely jest. + +"If you, sir, choose to make a buffoon of yourself," he said +sharply, with a slight trembling of the lower jaw, "I can't prevent +your doing so; but I warn you that if you dare to play the fool in +my presence, I will teach you to behave yourself." + +Nesvitski and Zherkov were so surprised by this outburst that they +gazed at Bolkonski silently with wide-open eyes. + +"What's the matter? I only congratulated them," said Zherkov. + +"I am not jesting with you; please be silent!" cried Bolkonski, +and taking Nesvitski's arm he left Zherkov, who did not know what to +say. + +"Come, what's the matter, old fellow?" said Nesvitski trying to +soothe him. + +"What's the matter?" exclaimed Prince Andrew standing still in his +excitement. "Don't you understand that either we are officers +serving our Tsar and our country, rejoicing in the successes and +grieving at the misfortunes of our common cause, or we are merely +lackeys who care nothing for their master's business. Quarante mille +hommes massacres et l'armee de nos allies detruite, et vous trouvez la +le mot pour rire,"* he said, as if strengthening his views by this +French sentence. "C'est bien pour un garcon de rein comme cet +individu dont vous avez fait un ami, mais pas pour vous, pas pour +vous.*[2] Only a hobbledehoy could amuse himself in this way," he +added in Russian--but pronouncing the word with a French accent- +having noticed that Zherkov could still hear him. + + +*"Forty thousand men massacred and the army of our allies destroyed, +and you find that a cause for jesting!" + +*[2] "It is all very well for that good-for-nothing fellow of whom +you have made a friend, but not for you, not for you." + + +He waited a moment to see whether the cornet would answer, but he +turned and went out of the corridor. + + + + + +CHAPTER IV + + +The Pavlograd Hussars were stationed two miles from Braunau. The +squadron in which Nicholas Rostov served as a cadet was quartered in +the German village of Salzeneck. The best quarters in the village were +assigned to cavalry-captain Denisov, the squadron commander, known +throughout the whole cavalry division as Vaska Denisov. Cadet +Rostov, ever since he had overtaken the regiment in Poland, had +lived with the squadron commander. + +On October 11, the day when all was astir at headquarters over the +news of Mack's defeat, the camp life of the officers of this +squadron was proceeding as usual. Denisov, who had been losing at +cards all night, had not yet come home when Rostov rode back early +in the morning from a foraging expedition. Rostov in his cadet +uniform, with a jerk to his horse, rode up to the porch, swung his leg +over the saddle with a supple youthful movement, stood for a moment in +the stirrup as if loathe to part from his horse, and at last sprang +down and called to his orderly. + +"Ah, Bondarenko, dear friend!" said he to the hussar who rushed up +headlong to the horse. "Walk him up and down, my dear fellow," he +continued, with that gay brotherly cordiality which goodhearted +young people show to everyone when they are happy. + +"Yes, your excellency," answered the Ukrainian gaily, tossing his +head. + +"Mind, walk him up and down well!" + +Another hussar also rushed toward the horse, but Bondarenko had +already thrown the reins of the snaffle bridle over the horse's +head. It was evident that the cadet was liberal with his tips and that +it paid to serve him. Rostov patted the horse's neck and then his +flank, and lingered for a moment. + +"Splendid! What a horse he will be!" he thought with a smile, and +holding up his saber, his spurs jingling, he ran up the steps of the +porch. His landlord, who in a waistcoat and a pointed cap, pitchfork +in hand, was clearing manure from the cowhouse, looked out, and his +face immediately brightened on seeing Rostov. "Schon gut Morgen! Schon +gut Morgen!"* he said winking with a merry smile, evidently pleased to +greet the young man. + + +*"A very good morning! A very good morning!" + + +"Schon fleissig?"* said Rostov with the same gay brotherly smile +which did not leave his eager face. "Hoch Oestreicher! Hoch Russen! +Kaiser Alexander hoch!"*[2] said he, quoting words often repeated by +the German landlord. + + +*"Busy already?" + +*[2] "Hurrah for the Austrians! Hurrah for the Russians! Hurrah +for Emperor Alexander!" + + +The German laughed, came out of the cowshed, pulled off his cap, and +waving it above his head cried: + +"Und die ganze Welt hoch!"* + + +*"And hurrah for the whole world!" + + +Rostov waved his cap above his head like the German and cried +laughing, "Und vivat die ganze Welt!" Though neither the German +cleaning his cowshed nor Rostov back with his platoon from foraging +for hay had any reason for rejoicing, they looked at each other with +joyful delight and brotherly love, wagged their heads in token of +their mutual affection, and parted smiling, the German returning to +his cowshed and Rostov going to the cottage he occupied with Denisov. + +"What about your master?" he asked Lavrushka, Denisov's orderly, +whom all the regiment knew for a rogue. + +"Hasn't been in since the evening. Must have been losing," +answered Lavrushka. "I know by now, if he wins he comes back early +to brag about it, but if he stays out till morning it means he's +lost and will come back in a rage. Will you have coffee?" + +"Yes, bring some." + +Ten minutes later Lavrushka brought the coffee. "He's coming!" +said he. "Now for trouble!" Rostov looked out of the window and saw +Denisov coming home. Denisov was a small man with a red face, +sparkling black eyes, and black tousled mustache and hair. He wore +an unfastened cloak, wide breeches hanging down in creases, and a +crumpled shako on the back of his head. He came up to the porch +gloomily, hanging his head. + +"Lavwuska!" he shouted loudly and angrily, "take it off, blockhead!" + +"Well, I am taking it off," replied Lavrushka's voice. + +"Ah, you're up already," said Denisov, entering the room. + +"Long ago," answered Rostov, "I have already been for the hay, and +have seen Fraulein Mathilde." + +"Weally! And I've been losing, bwother. I lost yesterday like a +damned fool!" cried Denisov, not pronouncing his r's. "Such ill +luck! Such ill luck. As soon as you left, it began and went on. +Hullo there! Tea!" + +Puckering up his face though smiling, and showing his short strong +teeth, he began with stubby fingers of both hands to ruffle up his +thick tangled black hair. + +"And what devil made me go to that wat?" (an officer nicknamed +"the rat") he said, rubbing his forehead and whole face with both +hands. "Just fancy, he didn't let me win a single cahd, not one cahd." + +He took the lighted pipe that was offered to him, gripped it in +his fist, and tapped it on the floor, making the sparks fly, while +he continued to shout. + +"He lets one win the singles and collahs it as soon as one doubles +it; gives the singles and snatches the doubles!" + +He scattered the burning tobacco, smashed the pipe, and threw it +away. Then he remained silent for a while, and all at once looked +cheerfully with his glittering, black eyes at Rostov. + +"If at least we had some women here; but there's nothing foh one +to do but dwink. If we could only get to fighting soon. Hullo, who's +there?" he said, turning to the door as he heard a tread of heavy +boots and the clinking of spurs that came to a stop, and a +respectful cough. + +"The squadron quartermaster!" said Lavrushka. + +Denisov's face puckered still more. + +"Wetched!" he muttered, throwing down a purse with some gold in +it. "Wostov, deah fellow, just see how much there is left and shove +the purse undah the pillow," he said, and went out to the +quartermaster. + +Rostov took the money and, mechanically arranging the old and new +coins in separate piles, began counting them. + +"Ah! Telyanin! How d'ye do? They plucked me last night," came +Denisov's voice from the next room. + +"Where? At Bykov's, at the rat's... I knew it," replied a piping +voice, and Lieutenant Telyanin, a small officer of the same +squadron, entered the room. + +Rostov thrust the purse under the pillow and shook the damp little +hand which was offered him. Telyanin for some reason had been +transferred from the Guards just before this campaign. He behaved very +well in the regiment but was not liked; Rostov especially detested him +and was unable to overcome or conceal his groundless antipathy to +the man. + +"Well, young cavalryman, how is my Rook behaving?" he asked. (Rook +was a young horse Telyanin had sold to Rostov.) + +The lieutenant never looked the man he was speaking to straight in +the face; his eyes continually wandered from one object to another. + +"I saw you riding this morning..." he added. + +"Oh, he's all right, a good horse," answered Rostov, though the +horse for which he had paid seven hundred rubbles was not worth half +that sum. "He's begun to go a little lame on the left foreleg," he +added. + +"The hoof's cracked! That's nothing. I'll teach you what to do and +show you what kind of rivet to use." + +"Yes, please do," said Rostov. + +"I'll show you, I'll show you! It's not a secret. And it's a horse +you'll thank me for." + +"Then I'll have it brought round," said Rostov wishing to avoid +Telyanin, and he went out to give the order. + +In the passage Denisov, with a pipe, was squatting on the +threshold facing the quartermaster who was reporting to him. On seeing +Rostov, Denisov screwed up his face and pointing over his shoulder +with his thumb to the room where Telyanin was sitting, he frowned +and gave a shudder of disgust. + +"Ugh! I don't like that fellow," he said, regardless of the +quartermaster's presence. + +Rostov shrugged his shoulders as much as to say: "Nor do I, but +what's one to do?" and, having given his order, he returned to +Telyanin. + +Telyanin was sitting in the same indolent pose in which Rostov had +left him, rubbing his small white hands. + +"Well there certainly are disgusting people," thought Rostov as he +entered. + +"Have you told them to bring the horse?" asked Telyanin, getting +up and looking carelessly about him. + +"I have." + +"Let us go ourselves. I only came round to ask Denisov about +yesterday's order. Have you got it, Denisov?" + +"Not yet. But where are you off to?" + +"I want to teach this young man how to shoe a horse," said Telyanin. + +They went through the porch and into the stable. The lieutenant +explained how to rivet the hoof and went away to his own quarters. + +When Rostov went back there was a bottle of vodka and a sausage on +the table. Denisov was sitting there scratching with his pen on a +sheet of paper. He looked gloomily in Rostov's face and said: "I am +witing to her." + +He leaned his elbows on the table with his pen in his hand and, +evidently glad of a chance to say quicker in words what he wanted to +write, told Rostov the contents of his letter. + +"You see, my fwiend," he said, "we sleep when we don't love. We +are childwen of the dust... but one falls in love and one is a God, +one is pua' as on the first day of cweation... Who's that now? Send +him to the devil, I'm busy!" he shouted to Lavrushka, who went up to +him not in the least abashed. + +"Who should it be? You yourself told him to come. It's the +quartermaster for the money." + +Denisov frowned and was about to shout some reply but stopped. + +"Wetched business," he muttered to himself. "How much is left in the +puhse?" he asked, turning to Rostov. + +"Seven new and three old imperials." + +"Oh, it's wetched! Well, what are you standing there for, you +sca'cwow? Call the quahtehmasteh," he shouted to Lavrushka. + +"Please, Denisov, let me lend you some: I have some, you know," said +Rostov, blushing. + +"Don't like bowwowing from my own fellows, I don't," growled +Denisov. + +"But if you won't accept money from me like a comrade, you will +offend me. Really I have some," Rostov repeated. + +"No, I tell you." + +And Denisov went to the bed to get the purse from under the pillow. + +"Where have you put it, Wostov?" + +"Under the lower pillow." + +"It's not there." + +Denisov threw both pillows on the floor. The purse was not there. + +"That's a miwacle." + +"Wait, haven't you dropped it?" said Rostov, picking up the +pillows one at a time and shaking them. + +He pulled off the quilt and shook it. The purse was not there. + +"Dear me, can I have forgotten? No, I remember thinking that you +kept it under your head like a treasure," said Rostov. "I put it +just here. Where is it?" he asked, turning to Lavrushka. + +"I haven't been in the room. It must be where you put it." + +"But it isn't?..." + +"You're always like that; you thwow a thing down anywhere and forget +it. Feel in your pockets." + +"No, if I hadn't thought of it being a treasure," said Rostov, +"but I remember putting it there." + +Lavrushka turned all the bedding over, looked under the bed and +under the table, searched everywhere, and stood still in the middle of +the room. Denisov silently watched Lavrushka's movements, and when the +latter threw up his arms in surprise saying it was nowhere to be found +Denisov glanced at Rostov. + +"Wostov, you've not been playing schoolboy twicks..." + +Rostov felt Denisov's gaze fixed on him, raised his eyes, and +instantly dropped them again. All the blood which had seemed congested +somewhere below his throat rushed to his face and eyes. He could not +draw breath. + +"And there hasn't been anyone in the room except the lieutenant +and yourselves. It must be here somewhere," said Lavrushka. + +"Now then, you devil's puppet, look alive and hunt for it!" +shouted Denisov, suddenly, turning purple and rushing at the man +with a threatening gesture. "If the purse isn't found I'll flog you, +I'll flog you all." + +Rostov, his eyes avoiding Denisov, began buttoning his coat, buckled +on his saber, and put on his cap. + +"I must have that purse, I tell you," shouted Denisov, shaking his +orderly by the shoulders and knocking him against the wall. + +"Denisov, let him alone, I know who has taken it," said Rostov, +going toward the door without raising his eyes. Denisov paused, +thought a moment, and, evidently understanding what Rostov hinted +at, seized his arm. + +"Nonsense!" he cried, and the veins on his forehead and neck stood +out like cords. "You are mad, I tell you. I won't allow it. The +purse is here! I'll flay this scoundwel alive, and it will be found." + +"I know who has taken it," repeated Rostov in an unsteady voice, and +went to the door. + +"And I tell you, don't you dahe to do it!" shouted Denisov, +rushing at the cadet to restrain him. + +But Rostov pulled away his arm and, with as much anger as though +Denisov were his worst enemy, firmly fixed his eyes directly on his +face. + +"Do you understand what you're saying?" he said in a trembling +voice. "There was no one else in the room except myself. So that if it +is not so, then..." + +He could not finish, and ran out of the room. + +"Ah, may the devil take you and evewybody," were the last words +Rostov heard. + +Rostov went to Telyanin's quarters. + +"The master is not in, he's gone to headquarters," said Telyanin's +orderly. "Has something happened?" he added, surprised at the +cadet's troubled face. + +"No, nothing." + +"You've only just missed him," said the orderly. + +The headquarters were situated two miles away from Salzeneck, and +Rostov, without returning home, took a horse and rode there. There was +an inn in the village which the officers frequented. Rostov rode up to +it and saw Telyanin's horse at the porch. + +In the second room of the inn the lieutenant was sitting over a dish +of sausages and a bottle of wine. + +"Ah, you've come here too, young man!" he said, smiling and +raising his eyebrows. + +"Yes," said Rostov as if it cost him a great deal to utter the word; +and he sat down at the nearest table. + +Both were silent. There were two Germans and a Russian officer in +the room. No one spoke and the only sounds heard were the clatter of +knives and the munching of the lieutenant. + +When Telyanin had finished his lunch he took out of his pocket a +double purse and, drawing its rings aside with his small, white, +turned-up fingers, drew out a gold imperial, and lifting his +eyebrows gave it to the waiter. + +"Please be quick," he said. + +The coin was a new one. Rostov rose and went up to Telyanin. + +"Allow me to look at your purse," he said in a low, almost +inaudible, voice. + +With shifting eyes but eyebrows still raised, Telyanin handed him +the purse. + +"Yes, it's a nice purse. Yes, yes," he said, growing suddenly +pale, and added, "Look at it, young man." + +Rostov took the purse in his hand, examined it and the money in +it, and looked at Telyanin. The lieutenant was looking about in his +usual way and suddenly seemed to grow very merry. + +"If we get to Vienna I'll get rid of it there but in these +wretched little towns there's nowhere to spend it," said he. "Well, +let me have it, young man, I'm going." + +Rostov did not speak. + +"And you? Are you going to have lunch too? They feed you quite +decently here," continued Telyanin. "Now then, let me have it." + +He stretched out his hand to take hold of the purse. Rostov let go +of it. Telyanin took the purse and began carelessly slipping it into +the pocket of his riding breeches, with his eyebrows lifted and his +mouth slightly open, as if to say, "Yes, yes, I am putting my purse in +my pocket and that's quite simple and is no else's business." + +"Well, young man?" he said with a sigh, and from under his lifted +brows he glanced into Rostov's eyes. + +Some flash as of an electric spark shot from Telyanin's eyes to +Rostov's and back, and back again and again in an instant. + +"Come here," said Rostov, catching hold of Telyanin's arm and almost +dragging him to the window. "That money is Denisov's; you took +it..." he whispered just above Telyanin's ear. + +"What? What? How dare you? What?" said Telyanin. + +But these words came like a piteous, despairing cry and an +entreaty for pardon. As soon as Rostov heard them, an enormous load of +doubt fell from him. He was glad, and at the same instant began to +pity the miserable man who stood before him, but the task he had begun +had to be completed. + +"Heaven only knows what the people here may imagine," muttered +Telyanin, taking up his cap and moving toward a small empty room. +"We must have an explanation..." + +"I know it and shall prove it," said Rostov. + +"I..." + +Every muscle of Telyanin's pale, terrified face began to quiver, his +eyes still shifted from side to side but with a downward look not +rising to Rostov's face, and his sobs were audible. + +"Count!... Don't ruin a young fellow... here is this wretched money, +take it..." He threw it on the table. "I have an old father and +mother!..." + +Rostov took the money, avoiding Telyanin's eyes, and went out of the +room without a word. But at the door he stopped and then retraced +his steps. "O God," he said with tears in his eyes, "how could you +do it?" + +"Count..." said Telyanin drawing nearer to him. + +"Don't touch me," said Rostov, drawing back. "If you need it, take +the money," and he threw the purse to him and ran out of the inn. + + + + + +CHAPTER V + + +That same evening there was an animated discussion among the +squadron's officers in Denisov's quarters. + +"And I tell you, Rostov, that you must apologize to the colonel!" +said a tall, grizzly-haired staff captain, with enormous mustaches and +many wrinkles on his large features, to Rostov who was crimson with +excitement. + +The staff captain, Kirsten, had twice been reduced to the ranks +for affairs of honor and had twice regained his commission. + +"I will allow no one to call me a liar!" cried Rostov. "He told me I +lied, and I told him he lied. And there it rests. He may keep me on +duty every day, or may place me under arrest, but no one can make me +apologize, because if he, as commander of this regiment, thinks it +beneath his dignity to give me satisfaction, then..." + +"You just wait a moment, my dear fellow, and listen," interrupted +the staff captain in his deep bass, calmly stroking his long mustache. +"You tell the colonel in the presence of other officers that an +officer has stolen..." + +"I'm not to blame that the conversation began in the presence of +other officers. Perhaps I ought not to have spoken before them, but +I am not a diplomatist. That's why I joined the hussars, thinking that +here one would not need finesse; and he tells me that I am lying--so +let him give me satisfaction..." + +"That's all right. No one thinks you a coward, but that's not the +point. Ask Denisov whether it is not out of the question for a cadet +to demand satisfaction of his regimental commander?" + +Denisov sat gloomily biting his mustache and listening to the +conversation, evidently with no wish to take part in it. He answered +the staff captain's question by a disapproving shake of his head. + +"You speak to the colonel about this nasty business before other +officers," continued the staff captain, "and Bogdanich" (the colonel +was called Bogdanich) "shuts you up." + +"He did not shut me up, he said I was telling an untruth." + +"Well, have it so, and you talked a lot of nonsense to him and +must apologize." + +"Not on any account!" exclaimed Rostov. + +"I did not expect this of you," said the staff captain seriously and +severely. "You don't wish to apologize, but, man, it's not only to him +but to the whole regiment--all of us--you're to blame all round. The +case is this: you ought to have thought the matter over and taken +advice; but no, you go and blurt it all straight out before the +officers. Now what was the colonel to do? Have the officer tried and +disgrace the whole regiment? Disgrace the whole regiment because of +one scoundrel? Is that how you look at it? We don't see it like +that. And Bogdanich was a brick: he told you you were saying what +was not true. It's not pleasant, but what's to be done, my dear +fellow? You landed yourself in it. And now, when one wants to smooth +the thing over, some conceit prevents your apologizing, and you wish +to make the whole affair public. You are offended at being put on duty +a bit, but why not apologize to an old and honorable officer? Whatever +Bogdanich may be, anyway he is an honorable and brave old colonel! +You're quick at taking offense, but you don't mind disgracing the +whole regiment!" The staff captain's voice began to tremble. "You have +been in the regiment next to no time, my lad, you're here today and +tomorrow you'll be appointed adjutant somewhere and can snap your +fingers when it is said 'There are thieves among the Pavlograd +officers!' But it's not all the same to us! Am I not right, Denisov? +It's not the same!" + +Denisov remained silent and did not move, but occasionally looked +with his glittering black eyes at Rostov. + +"You value your own pride and don't wish to apologize," continued +the staff captain, "but we old fellows, who have grown up in and, +God willing, are going to die in the regiment, we prize the honor of +the regiment, and Bogdanich knows it. Oh, we do prize it, old +fellow! And all this is not right, it's not right! You may take +offense or not but I always stick to mother truth. It's not right!" + +And the staff captain rose and turned away from Rostov. + +"That's twue, devil take it!" shouted Denisov, jumping up. "Now then, +Wostov, now then!" + + Rostov, growing red and pale alternately, looked first at one +officer and then at the other. + +"No, gentlemen, no... you mustn't think... I quite understand. +You're wrong to think that of me... I... for me... for the honor of +the regiment I'd... Ah well, I'll show that in action, and for me +the honor of the flag... Well, never mind, it's true I'm to blame, +to blame all round. Well, what else do you want?..." + +"Come, that's right, Count!" cried the staff captain, turning +round and clapping Rostov on the shoulder with his big hand. + +"I tell you," shouted Denisov, "he's a fine fellow." + +"That's better, Count," said the staff captain, beginning to address +Rostov by his title, as if in recognition of his confession. "Go and +apologize, your excellency. Yes, go!" + +"Gentlemen, I'll do anything. No one shall hear a word from me," +said Rostov in an imploring voice, "but I can't apologize, by God I +can't, do what you will! How can I go and apologize like a little +boy asking forgiveness?" + +Denisov began to laugh. + +"It'll be worse for you. Bogdanich is vindictive and you'll pay +for your obstinacy," said Kirsten. + +"No, on my word it's not obstinacy! I can't describe the feeling. +I can't..." + +"Well, it's as you like," said the staff captain. "And what has +become of that scoundrel?" he asked Denisov. + +"He has weported himself sick, he's to be stwuck off the list +tomowwow," muttered Denisov. + +"It is an illness, there's no other way of explaining it," said +the staff captain. + +"Illness or not, he'd better not cwoss my path. I'd kill him!" +shouted Denisov in a bloodthirsty tone. + +Just then Zherkov entered the room. + +"What brings you here?" cried the officers turning to the newcomer. + +"We're to go into action, gentlemen! Mack has surrendered with his +whole army." + +"It's not true!" + +"I've seen him myself!" + +"What? Saw the real Mack? With hands and feet?" + +"Into action! Into action! Bring him a bottle for such news! But how +did you come here?" + +"I've been sent back to the regiment all on account of that devil, +Mack. An Austrian general complained of me. I congratulated him on +Mack's arrival... What's the matter, Rostov? You look as if you'd just +come out of a hot bath." + +"Oh, my dear fellow, we're in such a stew here these last two days." + +The regimental adjutant came in and confirmed the news brought by +Zherkov. They were under orders to advance next day. + +"We're going into action, gentlemen!" + +"Well, thank God! We've been sitting here too long!" + + + + + +CHAPTER VI + + +Kutuzov fell back toward Vienna, destroying behind him the bridges +over the rivers Inn (at Braunau) and Traun (near Linz). On October +23 the Russian troops were crossing the river Enns. At midday the +Russian baggage train, the artillery, and columns of troops were +defiling through the town of Enns on both sides of the bridge. + +It was a warm, rainy, autumnal day. The wide expanse that opened out +before the heights on which the Russian batteries stood guarding the +bridge was at times veiled by a diaphanous curtain of slanting rain, +and then, suddenly spread out in the sunlight, far-distant objects +could be clearly seen glittering as though freshly varnished. Down +below, the little town could be seen with its white, red-roofed +houses, its cathedral, and its bridge, on both sides of which streamed +jostling masses of Russian troops. At the bend of the Danube, vessels, +an island, and a castle with a park surrounded by the waters of the +confluence of the Enns and the Danube became visible, and the rocky +left bank of the Danube covered with pine forests, with a mystic +background of green treetops and bluish gorges. The turrets of a +convent stood out beyond a wild virgin pine forest, and far away on +the other side of the Enns the enemy's horse patrols could be +discerned. + +Among the field guns on the brow of the hill the general in +command of the rearguard stood with a staff officer, scanning the +country through his fieldglass. A little behind them Nesvitski, who +had been sent to the rearguard by the commander in chief, was +sitting on the trail of a gun carriage. A Cossack who accompanied +him had handed him a knapsack and a flask, and Nesvitski was +treating some officers to pies and real doppelkummel. The officers +gladly gathered round him, some on their knees, some squatting Turkish +fashion on the wet grass. + +"Yes, the Austrian prince who built that castle was no fool. It's +a fine place! Why are you not eating anything, gentlemen?" Nesvitski +was saying. + +"Thank you very much, Prince," answered one of the officers, pleased +to be talking to a staff officer of such importance. "It's a lovely +place! We passed close to the park and saw two deer... and what a +splendid house!" + +"Look, Prince," said another, who would have dearly liked to take +another pie but felt shy, and therefore pretended to be examining +the countryside--"See, our infantrymen have already got there. Look +there in the meadow behind the village, three of them are dragging +something. They'll ransack that castle," he remarked with evident +approval. + +"So they will," said Nesvitski. "No, but what I should like," +added he, munching a pie in his moist-lipped handsome mouth, "would be +to slip in over there." + +He pointed with a smile to a turreted nunnery, and his eyes narrowed +and gleamed. + +"That would be fine, gentlemen!" + +The officers laughed. + +"Just to flutter the nuns a bit. They say there are Italian girls +among them. On my word I'd give five years of my life for it!" + +"They must be feeling dull, too," said one of the bolder officers, +laughing. + +Meanwhile the staff officer standing in front pointed out +something to the general, who looked through his field glass. + +"Yes, so it is, so it is," said the general angrily, lowering the +field glass and shrugging his shoulders, "so it is! They'll be fired +on at the crossing. And why are they dawdling there?" + +On the opposite side the enemy could be seen by the naked eye, and +from their battery a milk-white cloud arose. Then came the distant +report of a shot, and our troops could be seen hurrying to the +crossing. + +Nesvitski rose, puffing, and went up to the general, smiling. + +"Would not your excellency like a little refreshment?" he said. + +"It's a bad business," said the general without answering him, +"our men have been wasting time." + +"Hadn't I better ride over, your excellency?" asked Nesvitski. + +"Yes, please do," answered the general, and he repeated the order +that had already once been given in detail: "and tell the hussars that +they are to cross last and to fire the bridge as I ordered; and the +inflammable material on the bridge must be reinspected." + +"Very good," answered Nesvitski. + +He called the Cossack with his horse, told him to put away the +knapsack and flask, and swung his heavy person easily into the saddle. + +"I'll really call in on the nuns," he said to the officers who +watched him smilingly, and he rode off by the winding path down the +hill. + +"Now then, let's see how far it will carry, Captain. Just try!" said +the general, turning to an artillery officer. "Have a little fun to +pass the time." + +"Crew, to your guns!" commanded the officer. + +In a moment the men came running gaily from their campfires and +began loading. + +"One!" came the command. + +Number one jumped briskly aside. The gun rang out with a deafening +metallic roar, and a whistling grenade flew above the heads of our +troops below the hill and fell far short of the enemy, a little +smoke showing the spot where it burst. + +The faces of officers and men brightened up at the sound. Everyone +got up and began watching the movements of our troops below, as +plainly visible as if but a stone's throw away, and the movements of +the approaching enemy farther off. At the same instant the sun came +fully out from behind the clouds, and the clear sound of the +solitary shot and the brilliance of the bright sunshine merged in a +single joyous and spirited impression. + + + + + +CHAPTER VII + + +Two of the enemy's shots had already flown across the bridge, +where there was a crush. Halfway across stood Prince Nesvitski, who +had alighted from his horse and whose big body was jammed +against the railings. He looked back laughing to the Cossack who stood +a few steps behind him holding two horses by their bridles. Each +time Prince Nesvitski tried to move on, soldiers and carts pushed +him back again and pressed him against the railings, and all he +could do was to smile. + +"What a fine fellow you are, friend!" said the Cossack to a convoy +soldier with a wagon, who was pressing onto the infantrymen who were +crowded together close to his wheels and his horses. "What a fellow! +You can't wait a moment! Don't you see the general wants to pass?" + +But the convoyman took no notice of the word "general" and shouted +at the soldiers who were blocking his way. "Hi there, boys! Keep to +the left! Wait a bit." But the soldiers, crowded together shoulder +to shoulder, their bayonets interlocking, moved over the bridge in a +dense mass. Looking down over the rails Prince Nesvitski saw the +rapid, noisy little waves of the Enns, which rippling and eddying +round the piles of the bridge chased each other along. Looking on +the bridge he saw equally uniform living waves of soldiers, shoulder +straps, covered shakos, knapsacks, bayonets, long muskets, and, +under the shakos, faces with broad cheekbones, sunken cheeks, and +listless tired expressions, and feet that moved through the sticky mud +that covered the planks of the bridge. Sometimes through the +monotonous waves of men, like a fleck of white foam on the waves of +the Enns, an officer, in a cloak and with a type of face different +from that of the men, squeezed his way along; sometimes like a chip of +wood whirling in the river, an hussar on foot, an orderly, or a +townsman was carried through the waves of infantry; and sometimes like +a log floating down the river, an officers' or company's baggage +wagon, piled high, leather covered, and hemmed in on all sides, +moved across the bridge. + +"It's as if a dam had burst," said the Cossack hopelessly. "Are +there many more of you to come?" + +"A million all but one!" replied a waggish soldier in a torn coat, +with a wink, and passed on followed by another, an old man. + +"If he" (he meant the enemy) "begins popping at the bridge now," +said the old soldier dismally to a comrade, "you'll forget to +scratch yourself." + +That soldier passed on, and after him came another sitting on a +cart. + +"Where the devil have the leg bands been shoved to?" said an +orderly, running behind the cart and fumbling in the back of it. + +And he also passed on with the wagon. Then came some merry +soldiers who had evidently been drinking. + +"And then, old fellow, he gives him one in the teeth with the butt +end of his gun..." a soldier whose greatcoat was well tucked up said +gaily, with a wide swing of his arm. + +"Yes, the ham was just delicious..." answered another with a loud +laugh. And they, too, passed on, so that Nesvitski did not learn who +had been struck on the teeth, or what the ham had to do with it. + +"Bah! How they scurry. He just sends a ball and they think they'll +all be killed," a sergeant was saying angrily and reproachfully. + +"As it flies past me, Daddy, the ball I mean," said a young +soldier with an enormous mouth, hardly refraining from laughing, "I +felt like dying of fright. I did, 'pon my word, I got that +frightened!" said he, as if bragging of having been frightened. + +That one also passed. Then followed a cart unlike any that had +gone before. It was a German cart with a pair of horses led by a +German, and seemed loaded with a whole houseful of effects. A fine +brindled cow with a large udder was attached to the cart behind. A +woman with an unweaned baby, an old woman, and a healthy German girl +with bright red cheeks were sitting on some feather beds. Evidently +these fugitives were allowed to pass by special permission. The eyes +of all the soldiers turned toward the women, and while the vehicle was +passing at foot pace all the soldiers' remarks related to the two +young ones. Every face bore almost the same smile, expressing unseemly +thoughts about the women. + +"Just see, the German sausage is making tracks, too!" + +"Sell me the missis," said another soldier, addressing the German, +who, angry and frightened, strode energetically along with downcast +eyes. + +"See how smart she's made herself! Oh, the devils!" + +"There, Fedotov, you should be quartered on them!" + +"I have seen as much before now, mate!" + +"Where are you going?" asked an infantry officer who was eating an +apple, also half smiling as he looked at the handsome girl. + +The German closed his eyes, signifying that he did not understand. + +"Take it if you like," said the officer, giving the girl an apple. + +The girl smiled and took it. Nesvitski like the rest of the men on +the bridge did not take his eyes off the women till they had passed. +When they had gone by, the same stream of soldiers followed, with +the same kind of talk, and at last all stopped. As often happens, +the horses of a convoy wagon became restive at the end of the +bridge, and the whole crowd had to wait. + +"And why are they stopping? There's no proper order!" said the +soldiers. "Where are you shoving to? Devil take you! Can't you wait? +It'll be worse if he fires the bridge. See, here's an officer jammed +in too"--different voices were saying in the crowd, as the men +looked at one another, and all pressed toward the exit from the +bridge. + +Looking down at the waters of the Enns under the bridge, Nesvitski +suddenly heard a sound new to him, of something swiftly approaching... +something big, that splashed into the water. + +"Just see where it carries to!" a soldier near by said sternly, +looking round at the sound. + +"Encouraging us to get along quicker," said another uneasily. + +The crowd moved on again. Nesvitski realized that it was a cannon +ball. + +"Hey, Cossack, my horse!" he said. "Now, then, you there! get out of +the way! Make way!" + +With great difficulty he managed to get to his horse, and shouting +continually he moved on. The soldiers squeezed themselves to make +way for him, but again pressed on him so that they jammed his leg, and +those nearest him were not to blame for they were themselves pressed +still harder from behind. + +"Nesvitski, Nesvitski! you numskull!" came a hoarse voice from +behind him. + +Nesvitski looked round and saw, some fifteen paces away but +separated by the living mass of moving infantry, Vaska Denisov, red +and shaggy, with his cap on the back of his black head and a cloak +hanging jauntily over his shoulder. + +"Tell these devils, these fiends, to let me pass!" shouted Denisov +evidently in a fit of rage, his coal-black eyes with their bloodshot +whites glittering and rolling as he waved his sheathed saber in a +small bare hand as red as his face. + +"Ah, Vaska!" joyfully replied Nesvitski. "What's up with you?" + +"The squadwon can't pass," shouted Vaska Denisov, showing his +white teeth fiercely and spurring his black thoroughbred Arab, which +twitched its ears as the bayonets touched it, and snorted, spurting +white foam from his bit, tramping the planks of the bridge with his +hoofs, and apparently ready to jump over the railings had his rider +let him. "What is this? They're like sheep! Just like sheep! Out of +the way!... Let us pass!... Stop there, you devil with the cart! +I'll hack you with my saber!" he shouted, actually drawing his saber +from its scabbard and flourishing it. + +The soldiers crowded against one another with terrified faces, and +Denisov joined Nesvitski. + +"How's it you're not drunk today?" said Nesvitski when the other had +ridden up to him. + +"They don't even give one time to dwink!" answered Vaska Denisov. +"They keep dwagging the wegiment to and fwo all day. If they mean to +fight, let's fight. But the devil knows what this is." + +"What a dandy you are today!" said Nesvitski, looking at Denisov's +new cloak and saddlecloth. + +Denisov smiled, took out of his sabretache a handkerchief that +diffused a smell of perfume, and put it to Nesvitski's nose. + +"Of course. I'm going into action! I've shaved, bwushed my teeth, +and scented myself." + +The imposing figure of Nesvitski followed by his Cossack, and the +determination of Denisov who flourished his sword and shouted +frantically, had such an effect that they managed to squeeze through +to the farther side of the bridge and stopped the infantry. Beside the +bridge Nesvitski found the colonel to whom he had to deliver the +order, and having done this he rode back. + +Having cleared the way Denisov stopped at the end of the bridge. +Carelessly holding in his stallion that was neighing and pawing the +ground, eager to rejoin its fellows, he watched his squadron draw +nearer. Then the clang of hoofs, as of several horses galloping, +resounded on the planks of the bridge, and the squadron, officers in +front and men four abreast, spread across the bridge and began to +emerge on his side of it. + +The infantry who had been stopped crowded near the bridge in the +trampled mud and gazed with that particular feeling of ill-will, +estrangement, and ridicule with which troops of different arms usually +encounter one another at the clean, smart hussars who moved past +them in regular order. + +"Smart lads! Only fit for a fair!" said one. + +"What good are they? They're led about just for show!" remarked +another. + +"Don't kick up the dust, you infantry!" jested an hussar whose +prancing horse had splashed mud over some foot soldiers. + +"I'd like to put you on a two days' march with a knapsack! Your fine +cords would soon get a bit rubbed," said an infantryman, wiping the +mud off his face with his sleeve. "Perched up there, you're more +like a bird than a man." + +"There now, Zikin, they ought to put you on a horse. You'd look +fine," said a corporal, chaffing a thin little soldier who bent +under the weight of his knapsack. + +"Take a stick between your legs, that'll suit you for a horse!" +the hussar shouted back. + + + + + +CHAPTER VIII + + +The last of the infantry hurriedly crossed the bridge, squeezing +together as they approached it as if passing through a funnel. At last +the baggage wagons had all crossed, the crush was less, and the last +battalion came onto the bridge. Only Denisov's squadron of hussars +remained on the farther side of the bridge facing the enemy, who could +be seen from the hill on the opposite bank but was not yet visible +from the bridge, for the horizon as seen from the valley through which +the river flowed was formed by the rising ground only half a mile +away. At the foot of the hill lay wasteland over which a few groups of +our Cossack scouts were moving. Suddenly on the road at the top of the +high ground, artillery and troops in blue uniform were seen. These +were the French. A group of Cossack scouts retired down the hill at +a trot. All the officers and men of Denisov's squadron, though they +tried to talk of other things and to look in other directions, thought +only of what was there on the hilltop, and kept constantly looking +at the patches appearing on the skyline, which they knew to be the +enemy's troops. The weather had cleared again since noon and the sun +was descending brightly upon the Danube and the dark hills around +it. It was calm, and at intervals the bugle calls and the shouts of +the enemy could be heard from the hill. There was no one now between +the squadron and the enemy except a few scattered skirmishers. An +empty space of some seven hundred yards was all that separated them. +The enemy ceased firing, and that stern, threatening, inaccessible, +and intangible line which separates two hostile armies was all the +more clearly felt. + +"One step beyond that boundary line which resembles the line +dividing the living from the dead lies uncertainty, suffering, and +death. And what is there? Who is there?--there beyond that field, that +tree, that roof lit up by the sun? No one knows, but one wants to +know. You fear and yet long to cross that line, and know that sooner +or later it must be crossed and you will have to find out what is +there, just as you will inevitably have to learn what lies the other +side of death. But you are strong, healthy, cheerful, and excited, and +are surrounded by other such excitedly animated and healthy men." So +thinks, or at any rate feels, anyone who comes in sight of the +enemy, and that feeling gives a particular glamour and glad keenness +of impression to everything that takes place at such moments. + +On the high ground where the enemy was, the smoke of a cannon +rose, and a ball flew whistling over the heads of the hussar squadron. +The officers who had been standing together rode off to their +places. The hussars began carefully aligning their horses. Silence +fell on the whole squadron. All were looking at the enemy in front and +at the squadron commander, awaiting the word of command. A second +and a third cannon ball flew past. Evidently they were firing at the +hussars, but the balls with rapid rhythmic whistle flew over the heads +of the horsemen and fell somewhere beyond them. The hussars did not +look round, but at the sound of each shot, as at the word of +command, the whole squadron with its rows of faces so alike yet so +different, holding its breath while the ball flew past, rose in the +stirrups and sank back again. The soldiers without turning their heads +glanced at one another, curious to see their comrades' impression. +Every face, from Denisov's to that of the bugler, showed one common +expression of conflict, irritation, and excitement, around chin and +mouth. The quartermaster frowned, looking at the soldiers as if +threatening to punish them. Cadet Mironov ducked every time a ball +flew past. Rostov on the left flank, mounted on his Rook--a handsome +horse despite its game leg--had the happy air of a schoolboy called up +before a large audience for an examination in which he feels sure he +will distinguish himself. He was glancing at everyone with a clear, +bright expression, as if asking them to notice how calmly he sat under +fire. But despite himself, on his face too that same indication of +something new and stern showed round the mouth. + +"Who's that curtseying there? Cadet Miwonov! That's not wight! +Look at me," cried Denisov who, unable to keep still on one spot, kept +turning his horse in front of the squadron. + +The black, hairy, snub-nosed face of Vaska Denisov, and his whole +short sturdy figure with the sinewy hairy hand and stumpy fingers in +which he held the hilt of his naked saber, looked just as it usually +did, especially toward evening when he had emptied his second +bottle; he was only redder than usual. With his shaggy head thrown +back like birds when they drink, pressing his spurs mercilessly into +the sides of his good horse, Bedouin, and sitting as though falling +backwards in the saddle, he galloped to the other flank of the +squadron and shouted in a hoarse voice to the men to look to their +pistols. He rode up to Kirsten. The staff captain on his broad-backed, +steady mare came at a walk to meet him. His face with its long +mustache was serious as always, only his eyes were brighter than +usual. + +"Well, what about it?" said he to Denisov. "It won't come to a +fight. You'll see--we shall retire." + +"The devil only knows what they're about!" muttered Denisov. "Ah, +Wostov," he cried noticing the cadet's bright face, "you've got it +at last." + +And he smiled approvingly, evidently pleased with the cadet. +Rostov felt perfectly happy. Just then the commander appeared on the +bridge. Denisov galloped up to him. + +"Your excellency! Let us attack them! I'll dwive them off." + +"Attack indeed!" said the colonel in a bored voice, puckering up his +face as if driving off a troublesome fly. "And why are you stopping +here? Don't you see the skirmishers are retreating? Lead the +squadron back." + +The squadron crossed the bridge and drew out of range of fire +without having lost a single man. The second squadron that had been in +the front line followed them across and the last Cossacks quitted +the farther side of the river. + +The two Pavlograd squadrons, having crossed the bridge, retired up +the hill one after the other. Their colonel, Karl Bogdanich +Schubert, came up to Denisov's squadron and rode at a footpace not far +from Rostov, without taking any notice of him although they were now +meeting for the first time since their encounter concerning +Telyanin. Rostov, feeling that he was at the front and in the power of +a man toward whom he now admitted that he had been to blame, did not +lift his eyes from the colonel's athletic back, his nape covered +with light hair, and his red neck. It seemed to Rostov that +Bogdanich was only pretending not to notice him, and that his whole +aim now was to test the cadet's courage, so he drew himself up and +looked around him merrily; then it seemed to him that Bogdanich rode +so near in order to show him his courage. Next he thought that his +enemy would send the squadron on a desperate attack just to punish +him--Rostov. Then he imagined how, after the attack, Bogdanich would +come up to him as he lay wounded and would magnanimously extend the +hand of reconciliation. + +The high-shouldered figure of Zherkov, familiar to the Pavlograds as +he had but recently left their regiment, rode up to the colonel. After +his dismissal from headquarters Zherkov had not remained in the +regiment, saying he was not such a fool as to slave at the front +when he could get more rewards by doing nothing on the staff, and +had succeeded in attaching himself as an orderly officer to Prince +Bagration. He now came to his former chief with an order from the +commander of the rear guard. + +"Colonel," he said, addressing Rostov's enemy with an air of +gloomy gravity and glancing round at his comrades, "there is an +order to stop and fire the bridge." + +"An order to who?" asked the colonel morosely. + +"I don't myself know 'to who,'" replied the cornet in a serious +tone, "but the prince told me to 'go and tell the colonel that the +hussars must return quickly and fire the bridge.'" + +Zherkov was followed by an officer of the suite who rode up to the +colonel of hussars with the same order. After him the stout +Nesvitski came galloping up on a Cossack horse that could scarcely +carry his weight. + +"How's this, Colonel?" he shouted as he approached. "I told you to +fire the bridge, and now someone has gone and blundered; they are +all beside themselves over there and one can't make anything out." + +The colonel deliberately stopped the regiment and turned to +Nesvitski. + +"You spoke to me of inflammable material," said he, "but you said +nothing about firing it." + +"But, my dear sir," said Nesvitski as he drew up, taking off his cap +and smoothing his hair wet with perspiration with his plump hand, +"wasn't I telling you to fire the bridge, when inflammable material +had been put in position?" + +"I am not your 'dear sir,' Mr. Staff Officer, and you did not tell +me to burn the bridge! I know the service, and it is my habit orders +strictly to obey. You said the bridge would be burned, but who would +it burn, I could not know by the holy spirit!" + +"Ah, that's always the way!" said Nesvitski with a wave of the hand. +"How did you get here?" said he, turning to Zherkov. + +"On the same business. But you are damp! Let me wring you out!" + +"You were saying, Mr. Staff Officer..." continued the colonel in +an offended tone. + +"Colonel," interrupted the officer of the suite, "You must be +quick or the enemy will bring up his guns to use grapeshot." + +The colonel looked silently at the officer of the suite, at the +stout staff officer, and at Zherkov, and he frowned. + +"I will the bridge fire," he said in a solemn tone as if to announce +that in spite of all the unpleasantness he had to endure he would +still do the right thing. + +Striking his horse with his long muscular legs as if it were to +blame for everything, the colonel moved forward and ordered the second +squadron, that in which Rostov was serving under Denisov, to return to +the bridge. + +"There, it's just as I thought," said Rostov to himself. "He +wishes to test me!" His heart contracted and the blood rushed to his +face. "Let him see whether I am a coward!" he thought. + +Again on all the bright faces of the squadron the serious expression +appeared that they had worn when under fire. Rostov watched his enemy, +the colonel, closely--to find in his face confirmation of his own +conjecture, but the colonel did not once glance at Rostov, and +looked as he always did when at the front, solemn and stern. Then came +the word of command. + +"Look sharp! Look sharp!" several voices repeated around him. + +Their sabers catching in the bridles and their spurs jingling, the +hussars hastily dismounted, not knowing what they were to do. The +men were crossing themselves. Rostov no longer looked at the +colonel, he had no time. He was afraid of falling behind the +hussars, so much afraid that his heart stood still. His hand +trembled as he gave his horse into an orderly's charge, and he felt +the blood rush to his heart with a thud. Denisov rode past him, +leaning back and shouting something. Rostov saw nothing but the +hussars running all around him, their spurs catching and their +sabers clattering. + +"Stretchers!" shouted someone behind him. + +Rostov did not think what this call for stretchers meant; he ran on, +trying only to be ahead of the others; but just at the bridge, not +looking at the ground, he came on some sticky, trodden mud, +stumbled, and fell on his hands. The others outstripped him. + +"At boss zides, Captain," he heard the voice of the colonel, who, +having ridden ahead, had pulled up his horse near the bridge, with a +triumphant, cheerful face. + +Rostov wiping his muddy hands on his breeches looked at his enemy +and was about to run on, thinking that the farther he went to the +front the better. But Bogdanich, without looking at or recognizing +Rostov, shouted to him: + +"Who's that running on the middle of the bridge? To the right! +Come back, Cadet!" he cried angrily; and turning to Denisov, who, +showing off his courage, had ridden on to the planks of the bridge: + +"Why run risks, Captain? You should dismount," he said. + +"Oh, every bullet has its billet," answered Vaska Denisov, turning +in his saddle. + + +Meanwhile Nesvitski, Zherkov, and the officer of the suite were +standing together out of range of the shots, watching, now the small +group of men with yellow shakos, dark-green jackets braided with cord, +and blue riding breeches, who were swarming near the bridge, and +then at what was approaching in the distance from the opposite side- +the blue uniforms and groups with horses, easily recognizable as +artillery. + +"Will they burn the bridge or not? Who'll get there first? Will they +get there and fire the bridge or will the French get within +grapeshot range and wipe them out?" These were the questions each +man of the troops on the high ground above the bridge involuntarily +asked himself with a sinking heart--watching the bridge and the +hussars in the bright evening light and the blue tunics advancing from +the other side with their bayonets and guns. + +"Ugh. The hussars will get it hot!" said Nesvitski; "they are within +grapeshot range now." + +"He shouldn't have taken so many men," said the officer of the +suite. + +"True enough," answered Nesvitski; "two smart fellows could have +done the job just as well." + +"Ah, your excellency," put in Zherkov, his eyes fixed on the +hussars, but still with that naive air that made it impossible to know +whether he was speaking in jest or in earnest. "Ah, your excellency! +How you look at things! Send two men? And who then would give us the +Vladimir medal and ribbon? But now, even if they do get peppered, +the squadron may be recommended for honors and he may get a ribbon. +Our Bogdanich knows how things are done." + +"There now!" said the officer of the suite, "that's grapeshot." + +He pointed to the French guns, the limbers of which were being +detached and hurriedly removed. + +On the French side, amid the groups with cannon, a cloud of smoke +appeared, then a second and a third almost simultaneously, and at +the moment when the first report was heard a fourth was seen. Then two +reports one after another, and a third. + +"Oh! Oh!" groaned Nesvitski as if in fierce pain, seizing the +officer of the suite by the arm. "Look! A man has fallen! Fallen, +fallen!" + +"Two, I think." + +"If I were Tsar I would never go to war," said Nesvitski, turning +away. + +The French guns were hastily reloaded. The infantry in their blue +uniforms advanced toward the bridge at a run. Smoke appeared again but +at irregular intervals, and grapeshot cracked and rattled onto the +bridge. But this time Nesvitski could not see what was happening +there, as a dense cloud of smoke arose from it. The hussars had +succeeded in setting it on fire and the French batteries were now +firing at them, no longer to hinder them but because the guns were +trained and there was someone to fire at. + +The French had time to fire three rounds of grapeshot before the +hussars got back to their horses. Two were misdirected and the shot +went too high, but the last round fell in the midst of a group of +hussars and knocked three of them over. + +Rostov, absorbed by his relations with Bogdanich, had paused on +the bridge not knowing what to do. There was no one to hew down (as he +had always imagined battles to himself), nor could he help to fire the +bridge because he had not brought any burning straw with him like +the other soldiers. He stood looking about him, when suddenly he heard +a rattle on the bridge as if nuts were being spilt, and the hussar +nearest to him fell against the rails with a groan. Rostov ran up to +him with the others. Again someone shouted, "Stretchers!" Four men +seized the hussar and began lifting him. + +"Oooh! For Christ's sake let me alone!" cried the wounded man, but +still he was lifted and laid on the stretcher. + +Nicholas Rostov turned away and, as if searching for something, +gazed into the distance, at the waters of the Danube, at the sky, +and at the sun. How beautiful the sky looked; how blue, how calm, +and how deep! How bright and glorious was the setting sun! With what +soft glitter the waters of the distant Danube shone. And fairer +still were the faraway blue mountains beyond the river, the nunnery, +the mysterious gorges, and the pine forests veiled in the mist of +their summits... There was peace and happiness... "I should wishing +for nothing else, nothing, if only I were there," thought Rostov. +"In myself alone and in that sunshine there is so much happiness; +but here... groans, suffering, fear, and this uncertainty and hurry... +There--they are shouting again, and again are all running back +somewhere, and I shall run with them, and it, death, is here above +me and around... Another instant and I shall never again see the +sun, this water, that gorge!..." + +At that instant the sun began to hide behind the clouds, and other +stretchers came into view before Rostov. And the fear of death and +of the stretchers, and love of the sun and of life, all merged into +one feeling of sickening agitation. + +"O Lord God! Thou who art in that heaven, save, forgive, and protect +me!" Rostov whispered. + +The hussars ran back to the men who held their horses; their +voices sounded louder and calmer, the stretchers disappeared from +sight. + +"Well, fwiend? So you've smelt powdah!" shouted Vaska Denisov just +above his ear. + +"It's all over; but I am a coward--yes, a coward!" thought Rostov, +and sighing deeply he took Rook, his horse, which stood resting one +foot, from the orderly and began to mount. + +"Was that grapeshot?" he asked Denisov. + +"Yes and no mistake!" cried Denisov. "You worked like wegular bwicks +and it's nasty work! An attack's pleasant work! Hacking away at the +dogs! But this sort of thing is the very devil, with them shooting +at you like a target." + +And Denisov rode up to a group that had stopped near Rostov, +composed of the colonel, Nesvitski, Zherkov, and the officer from +the suite. + +"Well, it seems that no one has noticed," thought Rostov. And this +was true. No one had taken any notice, for everyone knew the sensation +which the cadet under fire for the first time had experienced. + +"Here's something for you to report," said Zherkov. "See if I +don't get promoted to a sublieutenancy." + +"Inform the prince that I the bridge fired!" said the colonel +triumphantly and gaily. + +"And if he asks about the losses?" + +"A trifle," said the colonel in his bass voice: "two hussars +wounded, and one knocked out," he added, unable to restrain a happy +smile, and pronouncing the phrase "knocked out" with ringing +distinctness. + + + + + +CHAPTER IX + + +Pursued by the French army of a hundred thousand men under the +command of Bonaparte, encountering a population that was unfriendly to +it, losing confidence in its allies, suffering from shortness of +supplies, and compelled to act under conditions of war unlike anything +that had been foreseen, the Russian army of thirty-five thousand men +commanded by Kutuzov was hurriedly retreating along the Danube, +stopping where overtaken by the enemy and fighting rearguard actions +only as far as necessary to enable it to retreat without losing its +heavy equipment. There had been actions at Lambach, Amstetten, and +Melk; but despite the courage and endurance--acknowledged even by +the enemy--with which the Russians fought, the only consequence of +these actions was a yet more rapid retreat. Austrian troops that had +escaped capture at Ulm and had joined Kutuzov at Braunau now separated +from the Russian army, and Kutuzov was left with only his own weak and +exhausted forces. The defense of Vienna was no longer to be thought +of. Instead of an offensive, the plan of which, carefully prepared +in accord with the modern science of strategics, had been handed to +Kutuzov when he was in Vienna by the Austrian Hofkriegsrath, the +sole and almost unattainable aim remaining for him was to effect a +junction with the forces that were advancing from Russia, without +losing his army as Mack had done at Ulm. + +On the twenty-eighth of October Kutuzov with his army crossed to the +left bank of the Danube and took up a position for the first time with +the river between himself and the main body of the French. On the +thirtieth he attacked Mortier's division, which was on the left +bank, and broke it up. In this action for the first time trophies were +taken: banners, cannon, and two enemy generals. For the first time, +after a fortnight's retreat, the Russian troops had halted and after a +fight had not only held the field but had repulsed the French. +Though the troops were ill-clad, exhausted, and had lost a third of +their number in killed, wounded, sick, and stragglers; though a number +of sick and wounded had been abandoned on the other side of the Danube +with a letter in which Kutuzov entrusted them to the humanity of the +enemy; and though the big hospitals and the houses in Krems +converted into military hospitals could no longer accommodate all +the sick and wounded, yet the stand made at Krems and the victory over +Mortier raised the spirits of the army considerably. Throughout the +whole army and at headquarters most joyful though erroneous rumors +were rife of the imaginary approach of columns from Russia, of some +victory gained by the Austrians, and of the retreat of the +frightened Bonaparte. + +Prince Andrew during the battle had been in attendance on the +Austrian General Schmidt, who was killed in the action. His horse +had been wounded under him and his own arm slightly grazed by a +bullet. As a mark of the commander in chief's special favor he was +sent with the news of this victory to the Austrian court, now no +longer at Vienna (which was threatened by the French) but at Brunn. +Despite his apparently delicate build Prince Andrew could endure +physical fatigue far better than many very muscular men, and on the +night of the battle, having arrived at Krems excited but not weary, +with dispatches from Dokhturov to Kutuzov, he was sent immediately +with a special dispatch to Brunn. To be so sent meant not only a +reward but an important step toward promotion. + +The night was dark but starry, the road showed black in the snow +that had fallen the previous day--the day of the battle. Reviewing his +impressions of the recent battle, picturing pleasantly to himself +the impression his news of a victory would create, or recalling the +send-off given him by the commander in chief and his fellow +officers, Prince Andrew was galloping along in a post chaise +enjoying the feelings of a man who has at length begun to attain a +long-desired happiness. As soon as he closed his eyes his ears +seemed filled with the rattle of the wheels and the sensation of +victory. Then he began to imagine that the Russians were running +away and that he himself was killed, but he quickly roused himself +with a feeling of joy, as if learning afresh that this was not so +but that on the contrary the French had run away. He again recalled +all the details of the victory and his own calm courage during the +battle, and feeling reassured he dozed off.... The dark starry night +was followed by a bright cheerful morning. The snow was thawing in the +sunshine, the horses galloped quickly, and on both sides of the road +were forests of different kinds, fields, and villages. + +At one of the post stations he overtook a convoy of Russian wounded. +The Russian officer in charge of the transport lolled back in the +front cart, shouting and scolding a soldier with coarse abuse. In each +of the long German carts six or more pale, dirty, bandaged men were +being jolted over the stony road. Some of them were talking (he +heard Russian words), others were eating bread; the more severely +wounded looked silently, with the languid interest of sick children, +at the envoy hurrying past them. + +Prince Andrew told his driver to stop, and asked a soldier in what +action they had been wounded. "Day before yesterday, on the Danube," +answered the soldier. Prince Andrew took out his purse and gave the +soldier three gold pieces. + +"That's for them all," he said to the officer who came up. + +"Get well soon, lads!" he continued, turning to the soldiers. +"There's plenty to do still." + +"What news, sir?" asked the officer, evidently anxious to start a +conversation. + +"Good news!... Go on!" he shouted to the driver, and they galloped +on. + +It was already quite dark when Prince Andrew rattled over the +paved streets of Brunn and found himself surrounded by high buildings, +the lights of shops, houses, and street lamps, fine carriages, and all +that atmosphere of a large and active town which is always so +attractive to a soldier after camp life. Despite his rapid journey and +sleepless night, Prince Andrew when he drove up to the palace felt +even more vigorous and alert than he had done the day before. Only his +eyes gleamed feverishly and his thoughts followed one another with +extraordinary clearness and rapidity. He again vividly recalled the +details of the battle, no longer dim, but definite and in the +concise form in which he imagined himself stating them to +the Emperor Francis. He vividly imagined the casual questions that +might be put to him and the answers he would give. He expected to be +at once presented to the Emperor. At the chief entrance to the palace, +however, an official came running out to meet him, and learning that +he was a special messenger led him to another entrance. + +"To the right from the corridor, Euer Hochgeboren! There you will +find the adjutant on duty," said the official. "He will conduct you to +the Minister of War." + +The adjutant on duty, meeting Prince Andrew, asked him to wait, +and went in to the Minister of War. Five minutes later he returned and +bowing with particular courtesy ushered Prince Andrew before him along +a corridor to the cabinet where the Minister of War was at work. The +adjutant by his elaborate courtesy appeared to wish to ward off any +attempt at familiarity on the part of the Russian messenger. + +Prince Andrew's joyous feeling was considerably weakened as he +approached the door of the minister's room. He felt offended, and +without his noticing it the feeling of offense immediately turned into +one of disdain which was quite uncalled for. His fertile mind +instantly suggested to him a point of view which gave him a right to +despise the adjutant and the minister. "Away from the smell of powder, +they probably think it easy to gain victories!" he thought. His eyes +narrowed disdainfully, he entered the room of the Minister of War with +peculiarly deliberate steps. This feeling of disdain was heightened +when he saw the minister seated at a large table reading some papers +and making pencil notes on them, and for the first two or three +minutes taking no notice of his arrival. A wax candle stood at each +side of the minister's bent bald head with its gray temples. He went +on reading to the end, without raising his eyes at the opening of +the door and the sound of footsteps. + +"Take this and deliver it," said he to his adjutant, handing him the +papers and still taking no notice of the special messenger. + +Prince Andrew felt that either the actions of Kutuzov's army +interested the Minister of War less than any of the other matters he +was concerned with, or he wanted to give the Russian special messenger +that impression. "But that is a matter of perfect indifference to me," +he thought. The minister drew the remaining papers together, +arranged them evenly, and then raised his head. He had an intellectual +and distinctive head, but the instant he turned to Prince Andrew the +firm, intelligent expression on his face changed in a way evidently +deliberate and habitual to him. His face took on the stupid artificial +smile (which does not even attempt to hide its artificiality) of a man +who is continually receiving many petitioners one after another. + +"From General Field Marshal Kutuzov?" he asked. "I hope it is good +news? There has been an encounter with Mortier? A victory? It was high +time!" + +He took the dispatch which was addressed to him and began to read it +with a mournful expression. + +"Oh, my God! My God! Schmidt!" he exclaimed in German. "What a +calamity! What a calamity!" + +Having glanced through the dispatch he laid it on the table and +looked at Prince Andrew, evidently considering something. + +"Ah what a calamity! You say the affair was decisive? But Mortier is +not captured." Again he pondered. "I am very glad you have brought +good news, though Schmidt's death is a heavy price to pay for the +victory. His Majesty will no doubt wish to see you, but not today. I +thank you! You must have a rest. Be at the levee tomorrow after the +parade. However, I will let you know." + +The stupid smile, which had left his face while he was speaking, +reappeared. + +"Au revoir! Thank you very much. His Majesty will probably desire to +see you," he added, bowing his head. + +When Prince Andrew left the palace he felt that all the interest and +happiness the victory had afforded him had been now left in the +indifferent hands of the Minister of War and the polite adjutant. +The whole tenor of his thoughts instantaneously changed; the battle +seemed the memory of a remote event long past. + + + + + +CHAPTER X + + +Prince Andrew stayed at Brunn with Bilibin, a Russian acquaintance +of his in the diplomatic service. + +"Ah, my dear prince! I could not have a more welcome visitor," +said Bilibin as he came out to meet Prince Andrew. "Franz, put the +prince's things in my bedroom," said he to the servant who was +ushering Bolkonski in. "So you're a messenger of victory, eh? +Splendid! And I am sitting here ill, as you see." + +After washing and dressing, Prince Andrew came into the diplomat's +luxurious study and sat down to the dinner prepared for him. Bilibin +settled down comfortably beside the fire. + +After his journey and the campaign during which he had been deprived +of all the comforts of cleanliness and all the refinements of life, +Prince Andrew felt a pleasant sense of repose among luxurious +surroundings such as he had been accustomed to from childhood. Besides +it was pleasant, after his reception by the Austrians, to speak if not +in Russian (for they were speaking French) at least with a Russian who +would, he supposed, share the general Russian antipathy to the +Austrians which was then particularly strong. + +Bilibin was a man of thirty-five, a bachelor, and of the same circle +as Prince Andrew. They had known each other previously in +Petersburg, but had become more intimate when Prince Andrew was in +Vienna with Kutuzov. Just as Prince Andrew was a young man who gave +promise of rising high in the military profession, so to an even +greater extent Bilibin gave promise of rising in his diplomatic +career. He still a young man but no longer a young diplomat, as he had +entered the service at the age of sixteen, had been in Paris and +Copenhagen, and now held a rather important post in Vienna. Both the +foreign minister and our ambassador in Vienna knew him and valued him. +He was not one of those many diplomats who are esteemed because they +have certain negative qualities, avoid doing certain things, and speak +French. He was one of those, who, liking work, knew how to do it, +and despite his indolence would sometimes spend a whole night at his +writing table. He worked well whatever the import of his work. It +was not the question "What for?" but the question "How?" that +interested him. What the diplomatic matter might be he did not care, +but it gave him great pleasure to prepare a circular, memorandum, or +report, skillfully, pointedly, and elegantly. Bilibin's services +were valued not only for what he wrote, but also for his skill in +dealing and conversing with those in the highest spheres. + +Bilibin liked conversation as he liked work, only when it could be +made elegantly witty. In society he always awaited an opportunity to +say something striking and took part in a conversation only when +that was possible. His conversation was always sprinkled with +wittily original, finished phrases of general interest. These +sayings were prepared in the inner laboratory of his mind in a +portable form as if intentionally, so that insignificant society +people might carry them from drawing room to drawing room. And, in +fact, Bilibin's witticisms were hawked about in the Viennese drawing +rooms and often had an influence on matters considered important. + +His thin, worn, sallow face was covered with deep wrinkles, which +always looked as clean and well washed as the tips of one's fingers +after a Russian bath. The movement of these wrinkles formed the +principal play of expression on his face. Now his forehead would +pucker into deep folds and his eyebrows were lifted, then his eyebrows +would descend and deep wrinkles would crease his cheeks. His small, +deep-set eyes always twinkled and looked out straight. + +"Well, now tell me about your exploits," said he. + +Bolkonski, very modestly without once mentioning himself, +described the engagement and his reception by the Minister of War. + +"They received me and my news as one receives a dog in a game of +skittles," said he in conclusion. + +Bilibin smiled and the wrinkles on his face disappeared. + +"Cependant, mon cher," he remarked, examining his nails from a +distance and puckering the skin above his left eye, "malgre la haute +estime que je professe pour the Orthodox Russian army, j'avoue que +votre victoire n'est pas des plus victorieuses."* + + +*"But my dear fellow, with all my respect for the Orthodox Russian +army, I must say that your victory was not particularly victorious." + + +He went on talking in this way in French, uttering only those +words in Russian on which he wished to put a contemptuous emphasis. + +"Come now! You with all your forces fall on the unfortunate +Mortier and his one division, and even then Mortier slips through your +fingers! Where's the victory?" + +"But seriously," said Prince Andrew, "we can at any rate say without +boasting that it was a little better than at Ulm..." + +"Why didn't you capture one, just one, marshal for us?" + +"Because not everything happens as one expects or with the +smoothness of a parade. We had expected, as I told you, to get at +their rear by seven in the morning but had not reached it by five in +the afternoon." + +"And why didn't you do it at seven in the morning? You ought to have +been there at seven in the morning," returned Bilibin with a smile. +"You ought to have been there at seven in the morning." + +"Why did you not succeed in impressing on Bonaparte by diplomatic +methods that he had better leave Genoa alone?" retorted Prince +Andrew in the same tone. + +"I know," interrupted Bilibin, "you're thinking it's very easy to +take marshals, sitting on a sofa by the fire! That is true, but +still why didn't you capture him? So don't be surprised if not only +the Minister of War but also his Most August Majesty the Emperor and +King Francis is not much delighted by your victory. Even I, a poor +secretary of the Russian Embassy, do not feel any need in token of +my joy to give my Franz a thaler, or let him go with his Liebchen to +the Prater... True, we have no Prater here..." + +He looked straight at Prince Andrew and suddenly unwrinkled his +forehead. + +"It is now my turn to ask you 'why?' mon cher," said Bolkonski. "I +confess I do not understand: perhaps there are diplomatic subtleties +here beyond my feeble intelligence, but I can't make it out. Mack +loses a whole army, the Archduke Ferdinand and the Archduke Karl +give no signs of life and make blunder after blunder. Kutuzov alone at +last gains a real victory, destroying the spell of the invincibility +of the French, and the Minister of War does not even care to hear +the details." + +"That's just it, my dear fellow. You see it's hurrah for the Tsar, +for Russia, for the Orthodox Greek faith! All that is beautiful, but +what do we, I mean the Austrian court, care for your victories? +Bring us nice news of a victory by the Archduke Karl or Ferdinand (one +archduke's as good as another, as you know) and even if it is only +over a fire brigade of Bonaparte's, that will be another story and +we'll fire off some cannon! But this sort of thing seems done on +purpose to vex us. The Archduke Karl does nothing, the Archduke +Ferdinand disgraces himself. You abandon Vienna, give up its +defense--as much as to say: 'Heaven is with us, but heaven help you +and your capital!' The one general whom we all loved, Schmidt, you +expose to a bullet, and then you congratulate us on the victory! Admit +that more irritating news than yours could not have been conceived. +It's as if it had been done on purpose, on purpose. Besides, suppose +you did gain a brilliant victory, if even the Archduke Karl gained a +victory, what effect would that have on the general course of +events? It's too late now when Vienna is occupied by the French army!" + +"What? Occupied? Vienna occupied?" + +"Not only occupied, but Bonaparte is at Schonbrunn, and the count, +our dear Count Vrbna, goes to him for orders." + +After the fatigues and impressions of the journey, his reception, +and especially after having dined, Bolkonski felt that he could not +take in the full significance of the words he heard. + +"Count Lichtenfels was here this morning," Bilibin continued, "and +showed me a letter in which the parade of the French in Vienna was +fully described: Prince Murat et tout le tremblement... You see that +your victory is not a matter for great rejoicing and that you can't be +received as a savior." + +"Really I don't care about that, I don't care at all," said Prince +Andrew, beginning to understand that his news of the battle before +Krems was really of small importance in view of such events as the +fall of Austria's capital. "How is it Vienna was taken? What of the +bridge and its celebrated bridgehead and Prince Auersperg? We heard +reports that Prince Auersperg was defending Vienna?" he said. + +"Prince Auersperg is on this, on our side of the river, and is +defending us--doing it very badly, I think, but still he is +defending us. But Vienna is on the other side. No, the bridge has +not yet been taken and I hope it will not be, for it is mined and +orders have been given to blow it up. Otherwise we should long ago +have been in the mountains of Bohemia, and you and your army would +have spent a bad quarter of an hour between two fires." + +"But still this does not mean that the campaign is over," said +Prince Andrew. + +"Well, I think it is. The bigwigs here think so too, but they +daren't say so. It will be as I said at the beginning of the campaign, +it won't be your skirmishing at Durrenstein, or gunpowder at all, that +will decide the matter, but those who devised it," said Bilibin +quoting one of his own mots, releasing the wrinkles on his forehead, +and pausing. "The only question is what will come of the meeting +between the Emperor Alexander and the King of Prussia in Berlin? If +Prussia joins the Allies, Austria's hand will be forced and there will +be war. If not it is merely a question of settling where the +preliminaries of the new Campo Formio are to be drawn up." + +"What an extraordinary genius!" Prince Andrew suddenly exclaimed, +clenching his small hand and striking the table with it, "and what +luck the man has!" + +"Buonaparte?" said Bilibin inquiringly, puckering up his forehead to +indicate that he was about to say something witty. "Buonaparte?" he +repeated, accentuating the u: "I think, however, now that he lays down +laws for Austria at Schonbrunn, il faut lui faire grace de l'u!* I +shall certainly adopt an innovation and call him simply Bonaparte!" + + +*"We must let him off the u!" + + +"But joking apart," said Prince Andrew, "do you really think the +campaign is over?" + +"This is what I think. Austria has been made a fool of, and she is +not used to it. She will retaliate. And she has been fooled in the +first place because her provinces have been pillaged--they say the +Holy Russian army loots terribly--her army is destroyed, her capital +taken, and all this for the beaux yeux* of His Sardinian Majesty. +And therefore--this is between ourselves--I instinctively feel that we +are being deceived, my instinct tells me of negotiations with France +and projects for peace, a secret peace concluded separately." + + +*Fine eyes. + + +"Impossible!" cried Prince Andrew. "That would be too base." + +"If we live we shall see," replied Bilibin, his face again +becoming smooth as a sign that the conversation was at an end. + +When Prince Andrew reached the room prepared for him and lay down in +a clean shirt on the feather bed with its warmed and fragrant pillows, +he felt that the battle of which he had brought tidings was far, far +away from him. The alliance with Prussia, Austria's treachery, +Bonaparte's new triumph, tomorrow's levee and parade, and the audience +with the Emperor Francis occupied his thoughts. + +He closed his eyes, and immediately a sound of cannonading, of +musketry and the rattling of carriage wheels seemed to fill his +ears, and now again drawn out in a thin line the musketeers were +descending the hill, the French were firing, and he felt his heart +palpitating as he rode forward beside Schmidt with the bullets merrily +whistling all around, and he experienced tenfold the joy of living, as +he had not done since childhood. + +He woke up... + +"Yes, that all happened!" he said, and, smiling happily to himself +like a child, he fell into a deep, youthful slumber. + + + + + +CHAPTER XI + + +Next day he woke late. Recalling his recent impressions, the first +thought that came into his mind was that today he had to be +presented to the Emperor Francis; he remembered the Minister of War, +the polite Austrian adjutant, Bilibin, and last night's +conversation. Having dressed for his attendance at court in full +parade uniform, which he had not worn for a long time, he went into +Bilibin's study fresh, animated, and handsome, with his hand bandaged. +In the study were four gentlemen of the diplomatic corps. With +Prince Hippolyte Kuragin, who was a secretary to the embassy, +Bolkonski was already acquainted. Bilibin introduced him to the +others. + +The gentlemen assembled at Bilibin's were young, wealthy, gay +society men, who here, as in Vienna, formed a special set which +Bilibin, their leader, called les notres.* This set, consisting almost +exclusively of diplomats, evidently had its own interests which had +nothing to do with war or politics but related to high society, to +certain women, and to the official side of the service. These +gentlemen received Prince Andrew as one of themselves, an honor they +did not extend to many. From politeness and to start conversation, +they asked him a few questions about the army and the battle, and then +the talk went off into merry jests and gossip. + + +*Ours. + + +"But the best of it was," said one, telling of the misfortune of a +fellow diplomat, "that the Chancellor told him flatly that his +appointment to London was a promotion and that he was so to regard it. +Can you fancy the figure he cut?..." + +"But the worst of it, gentlemen--I am giving Kuragin away to you--is +that that man suffers, and this Don Juan, wicked fellow, is taking +advantage of it!" + +Prince Hippolyte was lolling in a lounge chair with his legs over +its arm. He began to laugh. + +"Tell me about that!" he said. + +"Oh, you Don Juan! You serpent!" cried several voices. + +"You, Bolkonski, don't know," said Bilibin turning to Prince Andrew, +"that all the atrocities of the French army (I nearly said of the +Russian army) are nothing compared to what this man has been doing +among the women!" + +"La femme est la compagne de l'homme,"* announced Prince +Hippolyte, and began looking through a lorgnette at his elevated legs. + + +*"Woman is man's companion." + + +Bilibin and the rest of "ours" burst out laughing in Hippolyte's +face, and Prince Andrew saw that Hippolyte, of whom--he had to +admit--he had almost been jealous on his wife's account, was the +butt of this set. + +"Oh, I must give you a treat," Bilibin whispered to Bolkonski. +"Kuragin is exquisite when he discusses politics--you should see his +gravity!" + +He sat down beside Hippolyte and wrinkling his forehead began +talking to him about politics. Prince Andrew and the others gathered +round these two. + +"The Berlin cabinet cannot express a feeling of alliance," began +Hippolyte gazing round with importance at the others, "without +expressing... as in its last note... you understand... Besides, unless +His Majesty the Emperor derogates from the principle of our +alliance... + +"Wait, I have not finished..." he said to Prince Andrew, seizing him +by the arm, "I believe that intervention will be stronger than +nonintervention. And..." he paused. "Finally one cannot impute the +nonreceipt of our dispatch of November 18. That is how it will end." +And he released Bolkonski's arm to indicate that he had now quite +finished. + +"Demosthenes, I know thee by the pebble thou secretest in thy golden +mouth!" said Bilibin, and the mop of hair on his head moved with +satisfaction. + +Everybody laughed, and Hippolyte louder than anyone. He was +evidently distressed, and breathed painfully, but could not restrain +the wild laughter that convulsed his usually impassive features. + +"Well now, gentlemen," said Bilibin, "Bolkonski is my guest in +this house and in Brunn itself. I want to entertain him as far as I +can, with all the pleasures of life here. If we were in Vienna it +would be easy, but here, in this wretched Moravian hole, it is more +difficult, and I beg you all to help me. Brunn's attractions must be +shown him. You can undertake the theater, I society, and you, +Hippolyte, of course the women." + +"We must let him see Amelie, she's exquisite!" said one of "ours," +kissing his finger tips. + +"In general we must turn this bloodthirsty soldier to more humane +interests," said Bilibin. + +"I shall scarcely be able to avail myself of your hospitality, +gentlemen, it is already time for me to go," replied Prince Andrew +looking at his watch. + +"Where to?" + +"To the Emperor." + +"Oh! Oh! Oh! Well, au revoir, Bolkonski! Au revoir, Prince! Come +back early to dinner," cried several voices. "We'll take you in hand." + +"When speaking to the Emperor, try as far as you can to praise the +way that provisions are supplied and the routes indicated," said +Bilibin, accompanying him to the hall. + +"I should like to speak well of them, but as far as I the facts, I +can't," replied Bolkonski, smiling. + +"Well, talk as much as you can, anyway. He has a passion for +giving audiences, but he does not like talking himself and can't do +it, as you will see." + + + + + +CHAPTER XII + + +At the levee Prince Andrew stood among the Austrian officers as he +had been told to, and the Emperor Francis merely looked fixedly into +his face and just nodded to him with to him with his long head. But +after it was over, the adjutant he had seen the previous day +ceremoniously informed Bolkonski that the Emperor desired to give +him an audience. The Emperor Francis received him standing in the +middle of the room. Before the conversation began Prince Andrew was +struck by the fact that the Emperor seemed confused and blushed as +if not knowing what to say. + +"Tell me, when did the battle begin?" he asked hurriedly. + +Prince Andrew replied. Then followed other questions just as simple: +"Was Kutuzov well? When had he left Krems?" and so on. The Emperor +spoke as if his sole aim were to put a given number of questions- +the answers to these questions, as was only too evident, did not +interest him. + +"At what o'clock did the battle begin?" asked the Emperor. + +"I cannot inform Your Majesty at what o'clock the battle began at +the front, but at Durrenstein, where I was, our attack began after +five in the afternoon," replied Bolkonski growing more animated and +expecting that he would have a chance to give a reliable account, +which he had ready in his mind, of all he knew and had seen. But the +Emperor smiled and interrupted him. + +"How many miles?" + +"From where to where, Your Majesty?" + +"From Durrenstein to Krems." + +"Three and a half miles, Your Majesty." + +"The French have abandoned the left bank?" + +"According to the scouts the last of them crossed on rafts during +the night." + +"Is there sufficient forage in Krems?" + +"Forage has not been supplied to the extent..." + +The Emperor interrupted him. + +"At what o'clock was General Schmidt killed?" + +"At seven o'clock, I believe." + +"At seven o'clock? It's very sad, very sad!" + +The Emperor thanked Prince Andrew and bowed. Prince Andrew +withdrew and was immediately surrounded by courtiers on all sides. +Everywhere he saw friendly looks and heard friendly words. Yesterday's +adjutant reproached him for not having stayed at the palace, and +offered him his own house. The Minister of War came up and +congratulated him on the Maria Theresa Order of the third grade, which +the Emperor was conferring on him. The Empress' chamberlain invited +him to see Her Majesty. The archduchess also wished to see him. He did +not know whom to answer, and for a few seconds collected his thoughts. +Then the Russian ambassador took him by the shoulder, led him to the +window, and began to talk to him. + +Contrary to Bilibin's forecast the news he had brought was +joyfully received. A thanksgiving service was arranged, Kutuzov was +awarded the Grand Cross of Maria Theresa, and the whole army +received rewards. Bolkonski was invited everywhere, and had to spend +the whole morning calling on the principal Austrian dignitaries. +Between four and five in the afternoon, having made all his calls, +he was returning to Bilibin's house thinking out a letter to his +father about the battle and his visit to Brunn. At the door he found a +vehicle half full of luggage. Franz, Bilibin's man, was dragging a +portmanteau with some difficulty out of the front door. + +Before returning to Bilibin's Prince Andrew had gone to bookshop +to provide himself with some books for the campaign, and had spent +some time in the shop. + +"What is it?" he asked. + +"Oh, your excellency!" said Franz, with difficulty rolling the +portmanteau into the vehicle, "we are to move on still farther. The +scoundrel is again at our heels!" + +"Eh? What?" asked Prince Andrew. + +Bilibin came out to meet him. His usually calm face showed +excitement. + +"There now! Confess that this is delightful," said he. "This +affair of the Thabor Bridge, at Vienna.... They have crossed without +striking a blow!" + +Prince Andrew could not understand. + +"But where do you come from not to know what every coachman in the +town knows?" + +"I come from the archduchess'. I heard nothing there." + +"And you didn't see that everybody is packing up?" + +"I did not... What is it all about?" inquired Prince Andrew +impatiently. + +"What's it all about? Why, the French have crossed the bridge that +Auersperg was defending, and the bridge was not blown up: so Murat +is now rushing along the road to Brunn and will be here in a day or +two." + +"What? Here? But why did they not blow up the bridge, if it was +mined?" + +"That is what I ask you. No one, not even Bonaparte, knows why." + +Bolkonski shrugged his shoulders. + +"But if the bridge is crossed it means that the army too is lost? It +will be cut off," said he. + +"That's just it," answered Bilibin. "Listen! The French entered +Vienna as I told you. Very well. Next day, which was yesterday, +those gentlemen, messieurs les marechaux,* Murat, Lannes,and Belliard, +mount and ride to bridge. (Observe that all three are Gascons.) +'Gentlemen,' says one of them, 'you know the Thabor Bridge is mined +and doubly mined and that there are menacing fortifications at its +head and an army of fifteen thousand men has been ordered to blow up +the bridge and not let us cross? But it will please our sovereign +the Emperor Napoleon if we take this bridge, so let us three go and +take it!' 'Yes, let's!' say the others. And off they go and take the +bridge, cross it, and now with their whole army are on this side of +the Danube, marching on us, you, and your lines of communication." + + +*The marshalls. + + +"Stop jesting," said Prince Andrew sadly and seriously. This news +grieved him and yet he was pleased. + +As soon as he learned that the Russian army was in such a hopeless +situation it occurred to him that it was he who was destined to lead +it out of this position; that here was the Toulon that would lift +him from the ranks of obscure officers and offer him the first step to +fame! Listening to Bilibin he was already imagining how on reaching +the army he would give an opinion at the war council which would be +the only one that could save the army, and how he alone would be +entrusted with the executing of the plan. + +"Stop this jesting," he said + +"I am not jesting," Bilibin went on. "Nothing is truer or sadder. +These gentlemen ride onto the bridge alone and wave white +handkerchiefs; they assure the officer on duty that they, the +marshals, are on their way to negotiate with Prince Auersperg. He lets +them enter the tete-de-pont.* They spin him a thousand gasconades, +saying that the war is over, that the Emperor Francis is arranging a +meeting with Bonaparte, that they desire to see Prince Auersperg, +and so on. The officer sends for Auersperg; these gentlemen embrace +the officers, crack jokes, sit on the cannon, and meanwhile a French +battalion gets to the bridge unobserved, flings the bags of incendiary +material into the water, and approaches the tete-de-pont. At length +appears the lieutenant general, our dear Prince Auersperg von +Mautern himself. 'Dearest foe! Flower of the Austrian army, hero of +the Turkish wars Hostilities are ended, we can shake one another's +hand.... The Emperor Napoleon burns with impatience to make Prince +Auersperg's acquaintance.' In a word, those gentlemen, Gascons indeed, +so bewildered him with fine words, and he is so flattered by his +rapidly established intimacy with the French marshals, and so +dazzled by the sight of Murat's mantle and ostrich plumes, qu'il n'y +voit que du feu, et oublie celui qu'il devait faire faire sur +l'ennemi!"*[2] In spite of the animation of his speech, Bilibin did +not forget to pause after this mot to give time for its due +appreciation. "The French battalion rushes to the bridgehead, spikes +the guns, and the bridge is taken! But what is best of all," he went +on, his excitement subsiding under the delightful interest of his +own story, "is that the sergeant in charge of the cannon which was +to give the signal to fire the mines and blow up the bridge, this +sergeant, seeing that the French troops were running onto the +bridge, was about to fire, but Lannes stayed his hand. The sergeant, +who was evidently wiser than his general, goes up to Auersperg and +says: 'Prince, you are being deceived, here are the French!' Murat, +seeing that all is lost if the sergeant is allowed to speak, turns +to Auersperg with feigned astonishment (he is a true Gascon) and says: +'I don't recognize the world-famous Austrian discipline, if you +allow a subordinate to address you like that!' It was a stroke of +genius. Prince Auersperg feels his dignity at stake and orders the +sergeant to be arrested. Come, you must own that this affair of the +Thabor Bridge is delightful! It is not exactly stupidity, nor +rascality...." + + +*Bridgehead. + +*[2] That their fire gets into his eyes and he forgets that he ought +to be firing at the enemy. + + +"It may be treachery," said Prince Andrew, vividly imagining the +gray overcoats, wounds, the smoke of gunpowder, the sounds of +firing, and the glory that awaited him. + +"Not that either. That puts the court in too bad a light," replied +Bilibin. "It's not treachery nor rascality nor stupidity: it is just as +at Ulm... it is..."--he seemed to be trying to find the right +expression. "C'est... c'est du Mack. Nous sommes mackes [It is... it +is a bit of Mack. We are Macked]," he concluded, feeling that he had +produced a good epigram, a fresh one that would be repeated. His +hitherto puckered brow became smooth as a sign of pleasure, and with a +slight smile he began to examine his nails. + +"Where are you off to?" he said suddenly to Prince Andrew who had +risen and was going toward his room. + +"I am going away." + +"Where to?" + +"To the army." + +"But you meant to stay another two days?" + +"But now I am off at once." + +And Prince Andrew after giving directions about his departure went +to his room. + +"Do you know, mon cher," said Bilibin following him, "I have been +thinking about you. Why are you going?" + +And in proof of the conclusiveness of his opinion all the wrinkles +vanished from his face. + +Prince Andrew looked inquiringly at him and gave no reply. + +"Why are you going? I know you think it your duty to gallop back +to the army now that it is in danger. I understand that. Mon cher, +it is heroism!" + +"Not at all," said Prince Andrew. + +"But as you are a philosopher, be a consistent one, look at the +other side of the question and you will see that your duty, on the +contrary, is to take care of yourself. Leave it to those who are no +longer fit for anything else.... You have not been ordered to return +and have not been dismissed from here; therefore, you can stay and +go with us wherever our ill luck takes us. They say we are going to +Olmutz, and Olmutz is a very decent town. You and I will travel +comfortably in my caleche." + +"Do stop joking, Bilibin," cried Bolkonski. + +"I am speaking sincerely as a friend! Consider! Where and why are +you going, when you might remain here? You are faced by one of two +things," and the skin over his left temple puckered, "either you +will not reach your regiment before peace is concluded, or you will +share defeat and disgrace with Kutuzov's whole army." + +And Bilibin unwrinkled his temple, feeling that the dilemma was +insoluble. + +"I cannot argue about it," replied Prince Andrew coldly, but he +thought: "I am going to save the army." + +"My dear fellow, you are a hero!" said Bilibin. + + + + + +CHAPTER XIII + + +That same night, having taken leave of the Minister of War, +Bolkonski set off to rejoin the army, not knowing where he would +find it and fearing to be captured by the French on the way to Krems. + +In Brunn everybody attached to the court was packing up, and the +heavy baggage was already being dispatched to Olmutz. Near Hetzelsdorf +Prince Andrew struck the high road along which the Russian army was +moving with great haste and in the greatest disorder. The road was +so obstructed with carts that it was impossible to get by in a +carriage. Prince Andrew took a horse and a Cossack from a Cossack +commander, and hungry and weary, making his way past the baggage +wagons, rode in search of the commander in chief and of his own +luggage. Very sinister reports of the position of the army reached him +as he went along, and the appearance of the troops in their disorderly +flight confirmed these rumors. + +"Cette armee russe que l'or de l'Angleterre a transportee des +extremites de l'univers, nous allons lui faire eprouver le meme +sort--(le sort de l'armee d'Ulm)."* He remembered these words in +Bonaparte's address to his army at the beginning of the campaign, +and they awoke in him astonishment at the genius of his hero, a +feeling of wounded pride, and a hope of glory. "And should there be +nothing left but to die?" he thought. "Well, if need be, I shall do it +no worse than others." + + +*"That Russian army which has been brought from the ends of the +earth by English gold, we shall cause to share the same fate--(the +fate of the army at Ulm)." + + +He looked with disdain at the endless confused mass of +detachments, carts, guns, artillery, and again baggage wagons and +vehicles of all kinds overtaking one another and blocking the muddy +road, three and sometimes four abreast. From all sides, behind and +before, as far as ear could reach, there were the rattle of wheels, +the creaking of carts and gun carriages, the tramp of horses, the +crack of whips, shouts, the urging of horses, and the swearing of +soldiers, orderlies, and officers. All along the sides of the road +fallen horses were to be seen, some flayed, some not, and +broken-down carts beside which solitary soldiers sat waiting for +something, and again soldiers straggling from their companies, +crowds of whom set off to the neighboring villages, or returned from +them dragging sheep, fowls, hay, and bulging sacks. At each ascent +or descent of the road the crowds were yet denser and the din of +shouting more incessant. Soldiers floundering knee-deep in mud +pushed the guns and wagons themselves. Whips cracked, hoofs slipped, +traces broke, and lungs were strained with shouting. The officers +directing the march rode backward and forward between the carts. Their +voices were but feebly heard amid the uproar and one saw by their +faces that they despaired of the possibility of checking this +disorder. + +"Here is our dear Orthodox Russian army," thought Bolkonski, +recalling Bilibin's words. + +Wishing to find out where the commander in chief was, he rode up +to a convoy. Directly opposite to him came a strange one-horse +vehicle, evidently rigged up by soldiers out of any available +materials and looking like something between a cart, a cabriolet, +and a caleche. A soldier was driving, and a woman enveloped in +shawls sat behind the apron under the leather hood of the vehicle. +Prince Andrew rode up and was just putting his question to a soldier +when his attention was diverted by the desperate shrieks of the +woman in the vehicle. An officer in charge of transport was beating +the soldier who was driving the woman's vehicle for trying to get +ahead of others, and the strokes of his whip fell on the apron of +the equipage. The woman screamed piercingly. Seeing Prince Andrew +she leaned out from behind the apron and, waving her thin arms from +under the woolen shawl, cried: + +"Mr. Aide-de-camp! Mr. Aide-de-camp!... For heaven's sake... Protect +me! What will become of us? I am the wife of the doctor of the Seventh +Chasseurs.... They won't let us pass, we are left behind and have lost +our people..." + +"I'll flatten you into a pancake!" shouted the angry officer to +the soldier. "Turn back with your slut!" + +"Mr. Aide-de-camp! Help me!... What does it all mean?" screamed +the doctor's wife. + +"Kindly let this cart pass. Don't you see it's a woman?" said Prince +Andrew riding up to the officer. + +The officer glanced at him, and without replying turned again to the +soldier. "I'll teach you to push on!... Back!" + +"Let them pass, I tell you!" repeated Prince Andrew, compressing his +lips. + +"And who are you?" cried the officer, turning on him with tipsy +rage, "who are you? Are you in command here? Eh? I am commander +here, not you! Go back or I'll flatten you into a pancake," repeated +he. This expression evidently pleased him. + +"That was a nice snub for the little aide-de-camp," came a voice +from behind. + +Prince Andrew saw that the officer was in that state of senseless, +tipsy rage when a man does not know what he is saying. He saw that his +championship of the doctor's wife in her queer trap might expose him +to what he dreaded more than anything in the world--to ridicule; but +his instinct urged him on. Before the officer finished his sentence +Prince Andrew, his face distorted with fury, rode up to him and raised +his riding whip. + +"Kind...ly let--them--pass!" + +The officer flourished his arm and hastily rode away. + +"It's all the fault of these fellows on the staff that there's +this disorder," he muttered. "Do as you like." + +Prince Andrew without lifting his eyes rode hastily away from the +doctor's wife, who was calling him her deliverer, and recalling with a +sense of disgust the minutest details of this humiliating scene he +galloped on to the village where he was told that the commander in +chief was. + +On reaching the village he dismounted and went to the nearest house, +intending to rest if but for a moment, eat something, and try to +sort out the stinging and tormenting thoughts that confused his +mind. "This is a mob of scoundrels and not an army," he was thinking +as he went up to the window of the first house, when a familiar +voice called him by name. + +He turned round. Nesvitski's handsome face looked out of the +little window. Nesvitski, moving his moist lips as he chewed +something, and flourishing his arm, called him to enter. + +"Bolkonski! Bolkonski!... Don't you hear? Eh? Come quick..." he +shouted. + +Entering the house, Prince Andrew saw Nesvitski and another adjutant +having something to eat. They hastily turned round to him asking if he +had any news. On their familiar faces he read agitation and alarm. +This was particularly noticeable on Nesvitski's usually laughing +countenance. + +"Where is the commander in chief?" asked Bolkonski. + +"Here, in that house," answered the adjutant. + +"Well, is it true that it's peace and capitulation?" asked +Nesvitski. + +"I was going to ask you. I know nothing except that it was all I +could do to get here." + +"And we, my dear boy! It's terrible! I was wrong to laugh at Mack, +we're getting it still worse," said Nesvitski. "But sit down and +have something to eat." + +"You won't be able to find either your baggage or anything else now, +Prince. And God only knows where your man Peter is," said the other +adjutant. + +"Where are headquarters?" + +"We are to spend the night in Znaim." + +"Well, I have got all I need into packs for two horses," said +Nesvitski. "They've made up splendid packs for me--fit to cross the +Bohemian mountains with. It's a bad lookout, old fellow! But what's +the matter with you? You must be ill to shiver like that," he added, +noticing that Prince Andrew winced as at an electric shock. + +"It's nothing," replied Prince Andrew. + +He had just remembered his recent encounter with the doctor's wife +and the convoy officer. + +"What is the commander in chief doing here?" he asked. + +"I can't make out at all," said Nesvitski. + +"Well, all I can make out is that everything is abominable, +abominable, quite abominable!" said Prince Andrew, and he went off +to the house where the commander in chief was. + +Passing by Kutuzov's carriage and the exhausted saddle horses of his +suite, with their Cossacks who were talking loudly together, Prince +Andrew entered the passage. Kutuzov himself, he was told, was in the +house with Prince Bagration and Weyrother. Weyrother was the +Austrian general who had succeeded Schmidt. In the passage little +Kozlovski was squatting on his heels in front of a clerk. The clerk, +with cuffs turned up, was hastily writing at a tub turned bottom +upwards. Kozlovski's face looked worn--he too had evidently not +slept all night. He glanced at Prince Andrew and did not even nod to +him. + +"Second line... have you written it?" he continued dictating to +the clerk. "The Kiev Grenadiers, Podolian..." + +"One can't write so fast, your honor," said the clerk, glancing +angrily and disrespectfully at Kozlovski. + +Through the door came the sounds of Kutuzov's voice, excited and +dissatisfied, interrupted by another, an unfamiliar voice. From the +sound of these voices, the inattentive way Kozlovski looked at him, +the disrespectful manner of the exhausted clerk, the fact that the +clerk and Kozlovski were squatting on the floor by a tub so near to +the commander in chief, and from the noisy laughter of the Cossacks +holding the horses near the window, Prince Andrew felt that +something important and disastrous was about to happen. + +He turned to Kozlovski with urgent questions. + +"Immediately, Prince," said Kozlovski. "Dispositions for Bagration." + +"What about capitulation?" + +"Nothing of the sort. Orders are issued for a battle." + +Prince Andrew moved toward the door from whence voices were heard. +Just as he was going to open it the sounds ceased, the door opened, +and Kutuzov with his eagle nose and puffy face appeared in the +doorway. Prince Andrew stood right in front of Kutuzov but the +expression of the commander in chief's one sound eye showed him to +be so preoccupied with thoughts and anxieties as to be oblivious of +his presence. He looked straight at his adjutant's face without +recognizing him. + +"Well, have you finished?" said he to Kozlovski. + +"One moment, your excellency." + +Bagration, a gaunt middle-aged man of medium height with a firm, +impassive face of Oriental type, came out after the commander in +chief. + +"I have the honor to present myself," repeated Prince Andrew +rather loudly, handing Kutuzov an envelope. + +"Ah, from Vienna? Very good. Later, later!" + +Kutuzov went out into the porch with Bagration. + +"Well, good-by, Prince," said he to Bagration. "My blessing, and may +Christ be with you in your great endeavor!" + +His face suddenly softened and tears came into his eyes. With his +left hand he drew Bagration toward him, and with his right, on which +he wore a ring, he made the sign of the cross over him with a +gesture evidently habitual, offering his puffy cheek, but Bagration +kissed him on the neck instead. + +"Christ be with you!" Kutuzov repeated and went toward his carriage. +"Get in with me," said he to Bolkonski. + +"Your excellency, I should like to be of use here. Allow me to +remain with Prince Bagration's detachment." + +"Get in," said Kutuzov, and noticing that Bolkonski still delayed, +he added: "I need good officers myself, need them myself!" + +They got into the carriage and drove for a few minutes in silence. + +"There is still much, much before us," he said, as if with an old +man's penetration he understood all that was passing in Bolkonski's +mind. "If a tenth part of his detachment returns I shall thank God," +he added as if speaking to himself. + +Prince Andrew glanced at Kutuzov's face only a foot distant from him +and involuntarily noticed the carefully washed seams of the scar +near his temple, where an Ismail bullet had pierced his skull, and the +empty eye socket. "Yes, he has a right to speak so calmly of those +men's death," thought Bolkonski. + +"That is why I beg to be sent to that detachment," he said. + +Kutuzov did not reply. He seemed to have forgotten what he had +been saying, and sat plunged in thought. Five minutes later, gently +swaying on the soft springs of the carriage, he turned to Prince +Andrew. There was not a trace of agitation on his face. With +delicate irony he questioned Prince Andrew about the details of his +interview with the Emperor, about the remarks he had heard at court +concerning the Krems affair, and about some ladies they both knew. + + + + + +CHAPTER XIV + + +On November 1 Kutuzov had received, through a spy, news that the +army he commanded was in an almost hopeless position. The spy reported +that the French, after crossing the bridge at Vienna, were advancing +in immense force upon Kutuzov's line of communication with the +troops that were arriving from Russia. If Kutuzov decided to remain at +Krems, Napoleon's army of one hundred and fifty thousand men would cut +him off completely and surround his exhausted army of forty +thousand, and he would find himself in the position of Mack at Ulm. If +Kutuzov decided to abandon the road connecting him with the troops +arriving from Russia, he would have to march with no road into unknown +parts of the Bohemian mountains, defending himself against superior +forces of the enemy and abandoning all hope of a junction with +Buxhowden. If Kutuzov decided to retreat along the road from Krems +to Olmutz, to unite with the troops arriving from Russia, he risked +being forestalled on that road by the French who had crossed the +Vienna bridge, and encumbered by his baggage and transport, having +to accept battle on the march against an enemy three times as +strong, who would hem him in from two sides. + +Kutuzov chose this latter course. + +The French, the spy reported, having crossed the Vienna bridge, were +advancing by forced marches toward Znaim, which lay sixty-six miles +off on the line of Kutuzov's retreat. If he reached Znaim before the +French, there would be great hope of saving the army; to let the +French forestall him at Znaim meant the exposure of his whole army +to a disgrace such as that of Ulm, or to utter destruction. But to +forestall the French with his whole army was impossible. The road +for the French from Vienna to Znaim was shorter and better than the +road for the Russians from Krems to Znaim. + +The night he received the news, Kutuzov sent Bagration's vanguard, +four thousand strong, to the right across the hills from the +Krems-Znaim to the Vienna-Znaim road. Bagration was to make this march +without resting, and to halt facing Vienna with Znaim to his rear, and +if he succeeded in forestalling the French he was to delay them as +long as possible. Kutuzov himself with all his transport took the road +to Znaim. + +Marching thirty miles that stormy night across roadless hills, +with his hungry, ill-shod soldiers, and losing a third of his men as +stragglers by the way, Bagration came out on the Vienna-Znaim road +at Hollabrunn a few hours ahead of the French who were approaching +Hollabrunn from Vienna. Kutuzov with his transport had still to +march for some days before he could reach Znaim. Hence Bagration +with his four thousand hungry, exhausted men would have to detain +for days the whole enemy army that came upon him at Hollabrunn, +which was clearly impossible. But a freak of fate made the +impossible possible. The success of the trick that had placed the + +Vienna bridge in the hands of the French without a fight led Murat +to try to deceive Kutuzov in a similar way. Meeting Bagration's weak +detachment on the Znaim road he supposed it to be Kutuzov's whole +army. To be able to crush it absolutely he awaited the arrival of +the rest of the troops who were on their way from Vienna, and with +this object offered a three days' truce on condition that both +armies should remain in position without moving. Murat declared that +negotiations for peace were already proceeding, and that he +therefore offered this truce to avoid unnecessary bloodshed. Count +Nostitz, the Austrian general occupying the advanced posts, believed +Murat's emissary and retired, leaving Bagration's division exposed. +Another emissary rode to the Russian line to announce the peace +negotiations and to offer the Russian army the three days' truce. +Bagration replied that he was not authorized either to accept or +refuse a truce and sent his adjutant to Kutuzov to report the offer he +had received. + +A truce was Kutuzov's sole chance of gaining time, giving +Bagration's exhausted troops some rest, and letting the transport +and heavy convoys (whose movements were concealed from the French) +advance if but one stage nearer Znaim. The offer of a truce gave the +only, and a quite unexpected, chance of saving the army. On +receiving the news he immediately dispatched Adjutant General +Wintzingerode, who was in attendance on him, to the enemy camp. +Wintzingerode was not merely to agree to the truce but also to offer +terms of capitulation, and meanwhile Kutuzov sent his adjutants back +to hasten to the utmost the movements of the baggage trains of the +entire army along the Krems-Znaim road. Bagration's exhausted and +hungry detachment, which alone covered this movement of the +transport and of the whole army, had to remain stationary in face of +an enemy eight times as strong as itself. + +Kutuzov's expectations that the proposals of capitulation (which +were in no way binding) might give time for part of the transport to +pass, and also that Murat's mistake would very soon be discovered, +proved correct. As soon as Bonaparte (who was at Schonbrunn, sixteen +miles from Hollabrunn) received Murat's dispatch with the proposal +of a truce and a capitulation, he detected a ruse and wrote the +following letter to Murat: + + +Schonbrunn, 25th Brumaire, 1805, + +at eight o'clock in the morning + +To PRINCE MURAT, + +I cannot find words to express to you my displeasure. You command +only my advance guard, and have no right to arrange an armistice +without my order. You are causing me to lose the fruits of a campaign. +Break the armistice immediately and march on the enemy. Inform him +that the general who signed that capitulation had no right to do so, +and that no one but the Emperor of Russia has that right. + +If, however, the Emperor of Russia ratifies that convention, I +will ratify it; but it is only a trick. March on, destroy the +Russian army.... You are in a position to seize its baggage and +artillery. + +The Russian Emperor's aide-de-camp is an impostor. Officers are +nothing when they have no powers; this one had none.... The +Austrians let themselves be tricked at the crossing of the Vienna +bridge, you are letting yourself be tricked by an aide-de-camp of +the Emperor. + +NAPOLEON + + +Bonaparte's adjutant rode full gallop with this menacing letter to +Murat. Bonaparte himself, not trusting to his generals, moved with all +the Guards to the field of battle, afraid of letting a ready victim +escape, and Bagration's four thousand men merrily lighted campfires, +dried and warmed themselves, cooked their porridge for the first +time for three days, and not one of them knew or imagined what was +in store for him. + + + + + +CHAPTER XV + + +Between three and four o'clock in the afternoon Prince Andrew, who +had persisted in his request to Kutuzov, arrived at Grunth and +reported himself to Bagration. Bonaparte's adjutant had not yet +reached Murat's detachment and the battle had not yet begun. In +Bagration's detachment no one knew anything of the general position of +affairs. They talked of peace but did not believe in its +possibility; others talked of a battle but also disbelieved in the +nearness of an engagement. Bagration, knowing Bolkonski to be a +favorite and trusted adjutant, received him with distinction and +special marks of favor, explaining to him that there would probably be +an engagement that day or the next, and giving him full liberty to +remain with him during the battle or to join the rearguard and have an +eye on the order of retreat, "which is also very important." + +"However, there will hardly be an engagement today," said +Bagration as if to reassure Prince Andrew. + +"If he is one of the ordinary little staff dandies sent to earn a +medal he can get his reward just as well in the rearguard, but if he +wishes to stay with me, let him... he'll be of use here if he's a +brave officer," thought Bagration. Prince Andrew, without replying, +asked the prince's permission to ride round the position to see the +disposition of the forces, so as to know his bearings should he be +sent to execute an order. The officer on duty, a handsome, elegantly +dressed man with a diamond ring on his forefinger, who was fond of +speaking French though he spoke it badly, offered to conduct Prince +Andrew. + +On all sides they saw rain-soaked officers with dejected faces who +seemed to be seeking something, and soldiers dragging doors, +benches, and fencing from the village. + +"There now, Prince! We can't stop those fellows," said the staff +officer pointing to the soldiers. "The officers don't keep them in +hand. And there," he pointed to a sutler's tent, "they crowd in and +sit. This morning I turned them all out and now look, it's full again. +I must go there, Prince, and scare them a bit. It won't take a +moment." + +"Yes, let's go in and I will get myself a roll and some cheese," +said Prince Andrew who had not yet had time to eat anything. + +"Why didn't you mention it, Prince? I would have offered you +something." + +They dismounted and entered the tent. Several officers, with flushed +and weary faces, were sitting at the table eating and drinking. + +"Now what does this mean, gentlemen?" said the staff officer, in the +reproachful tone of a man who has repeated the same thing more than +once. "You know it won't do to leave your posts like this. The +prince gave orders that no one should leave his post. Now you, +Captain," and he turned to a thin, dirty little artillery officer +who without his boots (he had given them to the canteen keeper to +dry), in only his stockings, rose when they entered, smiling not +altogether comfortably. + +"Well, aren't you ashamed of yourself, Captain Tushin?" he +continued. "One would think that as an artillery officer you would set +a good example, yet here you are without your boots! The alarm will be +sounded and you'll be in a pretty position without your boots!" (The +staff officer smiled.) "Kindly return to your posts, gentlemen, all of +you, all!" he added in a tone of command. + +Prince Andrew smiled involuntarily as he looked at the artillery +officer Tushin, who silent and smiling, shifting from one stockinged +foot to the other, glanced inquiringly with his large, intelligent, +kindly eyes from Prince Andrew to the staff officer. + +"The soldiers say it feels easier without boots," said Captain +Tushin smiling shyly in his uncomfortable position, evidently +wishing to adopt a jocular tone. But before he had finished he felt +that his jest was unacceptable and had not come off. He grew confused. + +"Kindly return to your posts," said the staff officer trying to +preserve his gravity. + +Prince Andrew glanced again at the artillery officer's small figure. +There was something peculiar about it, quite unsoldierly, rather +comic, but extremely attractive. + +The staff officer and Prince Andrew mounted their horses and rode +on. + +Having ridden beyond the village, continually meeting and overtaking +soldiers and officers of various regiments, they saw on their left +some entrenchments being thrown up, the freshly dug clay of which +showed up red. Several battalions of soldiers, in their shirt +sleeves despite the cold wind, swarmed in these earthworks like a host +of white ants; spadefuls of red clay were continually being thrown +up from behind the bank by unseen hands. Prince Andrew and the officer +rode up, looked at the entrenchment, and went on again. Just behind it +they came upon some dozens of soldiers, continually replaced by +others, who ran from the entrenchment. They had to hold their noses +and put their horses to a trot to escape from the poisoned +atmosphere of these latrines. + +"Voila l'agrement des camps, monsieur le Prince,"* said the staff +officer. + + +*"This is a pleasure one gets in camp, Prince." + + +They rode up the opposite hill. From there the French could +already be seen. Prince Andrew stopped and began examining the +position. + +"That's our battery," said the staff officer indicating the +highest point. "It's in charge of the queer fellow we saw without +his boots. You can see everything from there; let's go there, Prince." + +"Thank you very much, I will go on alone," said Prince Andrew, +wishing to rid himself of this staff officer's company, "please +don't trouble yourself further." + +The staff officer remained behind and Prince Andrew rode on alone. + +The farther forward and nearer the enemy he went, the more orderly +and cheerful were the troops. The greatest disorder and depression had +been in the baggage train he had passed that morning on the Znaim road +seven miles away from the French. At Grunth also some apprehension and +alarm could be felt, but the nearer Prince Andrew came to the French +lines the more confident was the appearance of our troops. The +soldiers in their greatcoats were ranged in lines, the sergeants major +and company officers were counting the men, poking the last man in +each section in the ribs and telling him to hold his hand up. Soldiers +scattered over the whole place were dragging logs and brushwood and +were building shelters with merry chatter and laughter; around the +fires sat others, dressed and undressed, drying their shirts and leg +bands or mending boots or overcoats and crowding round the boilers and +porridge cookers. In one company dinner was ready, and the soldiers +were gazing eagerly at the steaming boiler, waiting till the sample, +which a quartermaster sergeant was carrying in a wooden bowl to an +officer who sat on a log before his shelter, had been tasted. + +Another company, a lucky one for not all the companies had vodka, +crowded round a pock-marked, broad-shouldered sergeant major who, +tilting a keg, filled one after another the canteen lids held out to +him. The soldiers lifted the canteen lids to their lips with +reverential faces, emptied them, rolling the vodka in their mouths, +and walked away from the sergeant major with brightened expressions, +licking their lips and wiping them on the sleeves of their greatcoats. +All their faces were as serene as if all this were happening at home +awaiting peaceful encampment, and not within sight of the enemy before +an action in which at least half of them would be left on the field. +After passing a chasseur regiment and in the lines of the Kiev +grenadiers--fine fellows busy with similar peaceful affairs--near +the shelter of the regimental commander, higher than and different +from the others, Prince Andrew came out in front of a platoon of +grenadiers before whom lay a naked man. Two soldiers held him while +two others were flourishing their switches and striking him +regularly on his bare back. The man shrieked unnaturally. A stout +major was pacing up and down the line, and regardless of the screams +kept repeating: + +"It's a shame for a soldier to steal; a soldier must be honest, +honorable, and brave, but if he robs his fellows there is no honor +in him, he's a scoundrel. Go on! Go on!" + +So the swishing sound of the strokes, and the desperate but +unnatural screams, continued. + +"Go on, go on!" said the major. + +A young officer with a bewildered and pained expression on his +face stepped away from the man and looked round inquiringly at the +adjutant as he rode by. + +Prince Andrew, having reached the front line, rode along it. Our +front line and that of the enemy were far apart on the right and +left flanks, but in the center where the men with a flag of truce +had passed that morning, the lines were so near together that the +men could see one another's faces and speak to one another. Besides +the soldiers who formed the picket line on either side, there were +many curious onlookers who, jesting and laughing, stared at their +strange foreign enemies. + +Since early morning--despite an injunction not to approach the +picket line--the officers had been unable to keep sight-seers away. +The soldiers forming the picket line, like showmen exhibiting a +curiosity, no longer looked at the French but paid attention to the +sight-seers and grew weary waiting to be relieved. Prince Andrew +halted to have a look at the French. + +"Look! Look there!" one soldier was saying to another, pointing to a +Russian musketeer who had gone up to the picket line with an officer +and was rapidly and excitedly talking to a French grenadier. "Hark +to him jabbering! Fine, isn't it? It's all the Frenchy can do to +keep up with him. There now, Sidorov!" + +"Wait a bit and listen. It's fine!" answered Sidorov, who was +considered an adept at French. + +The soldier to whom the laughers referred was Dolokhov. Prince +Andrew recognized him and stopped to listen to what he was saying. +Dolokhov had come from the left flank where their regiment was +stationed, with his captain. + +"Now then, go on, go on!" incited the officer, bending forward and +trying not to lose a word of the speech which was incomprehensible +to him. "More, please: more! What's he saying?" + +Dolokhov did not answer the captain; he had been drawn into a hot +dispute with the French grenadier. They were naturally talking about +the campaign. The Frenchman, confusing the Austrians with the +Russians, was trying to prove that the Russians had surrendered and +had fled all the way from Ulm, while Dolokhov maintained that the +Russians had not surrendered but had beaten the French. + +"We have orders to drive you off here, and we shall drive you +off," said Dolokhov. + +"Only take care you and your Cossacks are not all captured!" said +the French grenadier. + +The French onlookers and listeners laughed. + +"We'll make you dance as we did under Suvorov...,"* said Dolokhov. + + +*"On vous fera danser." + + +"Qu' est-ce qu'il chante?"* asked a Frenchman. + + +*"What's he singing about?" + + +"It's ancient history," said another, guessing that it referred to a +former war. "The Emperor will teach your Suvara as he has taught the +others..." + +"Bonaparte..." began Dolokhov, but the Frenchman interrupted him. + +"Not Bonaparte. He is the Emperor! Sacre nom...!" cried he angrily. + +"The devil skin your Emperor." + +And Dolokhov swore at him in coarse soldier's Russian and +shouldering his musket walked away. + +"Let us go, Ivan Lukich," he said to the captain. + +"Ah, that's the way to talk French," said the picket soldiers. "Now, +Sidorov, you have a try!" + +Sidorov, turning to the French, winked, and began to jabber +meaningless sounds very fast: "Kari, mala, tafa, safi, muter, +Kaska," he said, trying to give an expressive intonation to his voice. + +"Ho! ho! ho! Ha! ha! ha! ha! Ouh! ouh!" came peals of such healthy +and good-humored laughter from the soldiers that it infected the +French involuntarily, so much so that the only thing left to do seemed +to be to unload the muskets, muskets, explode the ammunition, and +all return home as quickly as possible. + +But the guns remained loaded, the loopholes in blockhouses and +entrenchments looked out just as menacingly, and the unlimbered cannon +confronted one another as before. + + + + + +CHAPTER XVI + + +Having ridden round the whole line from right flank to left, +Prince Andrew made his way up to the battery from which the staff +officer had told him the whole field could be seen. Here he +dismounted, and stopped beside the farthest of the four unlimbered +cannon. Before the guns an artillery sentry was pacing up and down; he +stood at attention when the officer arrived, but at a sign resumed his +measured, monotonous pacing. Behind the guns were their limbers and +still farther back picket ropes and artillerymen's bonfires. To the +left, not far from the farthest cannon, was a small, newly constructed +wattle shed from which came the sound of officers' voices in eager +conversation. + +It was true that a view over nearly the whole Russian position and +the greater part of the enemy's opened out from this battery. Just +facing it, on the crest of the opposite hill, the village of Schon +Grabern could be seen, and in three places to left and right the +French troops amid the smoke of their campfires, the greater part of +whom were evidently in the village itself and behind the hill. To +the left from that village, amid the smoke, was something resembling a +battery, but it was impossible to see it clearly with the naked eye. +Our right flank was posted on a rather steep incline which dominated +the French position. Our infantry were stationed there, and at the +farthest point the dragoons. In the center, where Tushin's battery +stood and from which Prince Andrew was surveying the position, was the +easiest and most direct descent and ascent to the brook separating +us from Schon Grabern. On the left our troops were close to a copse, +in which smoked the bonfires of our infantry who were felling wood. +The French line was wider than ours, and it was plain that they +could easily outflank us on both sides. Behind our position was a +steep and deep dip, making it difficult for artillery and cavalry to +retire. Prince Andrew took out his notebook and, leaning on the +cannon, sketched a plan of the position. He made some notes on two +points, intending to mention them to Bagration. His idea was, first, +to concentrate all the artillery in the center, and secondly, to +withdraw the cavalry to the other side of the dip. Prince Andrew, +being always near the commander in chief, closely following the mass +movements and general orders, and constantly studying historical +accounts of battles, involuntarily pictured to himself the course of +events in the forthcoming action in broad outline. He imagined only +important possibilities: "If the enemy attacks the right flank," he +said to himself, "the Kiev grenadiers and the Podolsk chasseurs must +hold their position till reserves from the center come up. In that +case the dragoons could successfully make a flank counterattack. If +they attack our center we, having the center battery on this high +ground, shall withdraw the left flank under its cover, and retreat +to the dip by echelons." So he reasoned.... All the time he had been +beside the gun, he had heard the voices of the officers distinctly, +but as often happens had not understood a word of what they were +saying. Suddenly, however, he was struck by a voice coming from the +shed, and its tone was so sincere that he could not but listen. + +"No, friend," said a pleasant and, as it seemed to Prince Andrew, +a familiar voice, "what I say is that if it were possible to know what +is beyond death, none of us would be afraid of it. That's so, friend." + +Another, a younger voice, interrupted him: "Afraid or not, you can't +escape it anyhow." + +"All the same, one is afraid! Oh, you clever people," said a third +manly voice interrupting them both. "Of course you artillery men are +very wise, because you can take everything along with you--vodka and +snacks." + +And the owner of the manly voice, evidently an infantry officer, +laughed. + +"Yes, one is afraid," continued the first speaker, he of the +familiar voice. "One is afraid of the unknown, that's what it is. +Whatever we may say about the soul going to the sky... we know there +is no sky but only an atmosphere." + +The manly voice again interrupted the artillery officer. + +"Well, stand us some of your herb vodka, Tushin," it said. + +"Why," thought Prince Andrew, "that's the captain who stood up in +the sutler's hut without his boots." He recognized the agreeable, +philosophizing voice with pleasure. + +"Some herb vodka? Certainly!" said Tushin. "But still, to conceive a +future life..." + +He did not finish. Just then there was a whistle in the air; +nearer and nearer, faster and louder, louder and faster, a cannon +ball, as if it had not finished saying what was necessary, thudded +into the ground near the shed with super human force, throwing up a +mass of earth. The ground seemed to groan at the terrible impact. + +And immediately Tushin, with a short pipe in the corner of his mouth +and his kind, intelligent face rather pale, rushed out of the shed +followed by the owner of the manly voice, a dashing infantry officer +who hurried off to his company, buttoning up his coat as he ran. + + + + + +CHAPTER XVII + + +Mounting his horse again Prince Andrew lingered with the battery, +looking at the puff from the gun that had sent the ball. His eyes +ran rapidly over the wide space, but he only saw that the hitherto +motionless masses of the French now swayed and that there really was a +battery to their left. The smoke above it had not yet dispersed. Two +mounted Frenchmen, probably adjutants, were galloping up the hill. A +small but distinctly visible enemy column was moving down the hill, +probably to strengthen the front line. The smoke of the first shot had +not yet dispersed before another puff appeared, followed by a +report. The battle had begun! Prince Andrew turned his horse and +galloped back to Grunth to find Prince Bagration. He heard the +cannonade behind him growing louder and more frequent. Evidently our +guns had begun to reply. From the bottom of the slope, where the +parleys had taken place, came the report of musketry. + +Lemarrois had just arrived at a gallop with Bonaparte's stern +letter, and Murat, humiliated and anxious to expiate his fault, had at +once moved his forces to attack the center and outflank both the +Russian wings, hoping before evening and before the arrival of the +Emperor to crush the contemptible detachment that stood before him. + +"It has begun. Here it is!" thought Prince Andrew, feeling the blood +rush to his heart. "But where and how will my Toulon present itself?" + +Passing between the companies that had been eating porridge and +drinking vodka a quarter of an hour before, he saw everywhere the same +rapid movement of soldiers forming ranks and getting their muskets +ready, and on all their faces he recognized the same eagerness that +filled his heart. "It has begun! Here it is, dreadful but +enjoyable!" was what the face of each soldier and each officer +seemed to say. + +Before he had reached the embankments that were being thrown up, +he saw, in the light of the dull autumn evening, mounted men coming +toward him. The foremost, wearing a Cossack cloak and lambskin cap and +riding a white horse, was Prince Bagration. Prince Andrew stopped, +waiting for him to come up; Prince Bagration reined in his horse and +recognizing Prince Andrew nodded to him. He still looked ahead while +Prince Andrew told him what he had seen. + +The feeling, "It has begun! Here it is!" was seen even on Prince +Bagration's hard brown face with its half-closed, dull, sleepy eyes. +Prince Andrew gazed with anxious curiosity at that impassive face +and wished he could tell what, if anything, this man was thinking +and feeling at that moment. "Is there anything at all behind that +impassive face?" Prince Andrew asked himself as he looked. Prince +Bagration bent his head in sign of agreement with what Prince Andrew +told him, and said, "Very good!" in a tone that seemed to imply that +everything that took place and was reported to him was exactly what he +had foreseen. Prince Andrew, out of breath with his rapid ride, +spoke quickly. Prince Bagration, uttering his words with an Oriental +accent, spoke particularly slowly, as if to impress the fact that +there was no need to hurry. However, he put his horse to a trot in the +direction of Tushin's battery. Prince Andrew followed with the +suite. Behind Prince Bagration rode an officer of the suite, the +prince's personal adjutant, Zherkov, an orderly officer, the staff +officer on duty, riding a fine bobtailed horse, and a civilian--an +accountant who had asked permission to be present at the battle out of +curiosity. The accountant, a stout, full-faced man, looked around +him with a naive smile of satisfaction and presented a strange +appearance among the hussars, Cossacks, and adjutants, in his camlet +coat, as he jolted on his horse with a convoy officer's saddle. + +"He wants to see a battle," said Zherkov to Bolkonski, pointing to +the accountant, "but he feels a pain in the pit of his stomach +already." + +"Oh, leave off!" said the accountant with a beaming but rather +cunning smile, as if flattered at being made the subject of +Zherkov's joke, and purposely trying to appear stupider than he really +was. + +"It is very strange, mon Monsieur Prince," said the staff officer. +(He remembered that in French there is some peculiar way of addressing +a prince, but could not get it quite right.) + +By this time they were all approaching Tushin's battery, and a +ball struck the ground in front of them. + +"What's that that has fallen?" asked the accountant with a naive +smile. + +"A French pancake," answered Zherkov. + +"So that's what they hit with?" asked the accountant. "How awful!" + +He seemed to swell with satisfaction. He had hardly finished +speaking when they again heard an unexpectedly violent whistling which +suddenly ended with a thud into something soft... f-f-flop! and a +Cossack, riding a little to their right and behind the accountant, +crashed to earth with his horse. Zherkov and the staff officer bent +over their saddles and turned their horses away. The accountant +stopped, facing the Cossack, and examined him with attentive +curiosity. The Cossack was dead, but the horse still struggled. + +Prince Bagration screwed up his eyes, looked round, and, seeing +the cause of the confusion, turned away with indifference, as if to +say, "Is it worth while noticing trifles?" He reined in his horse with +the case of a skillful rider and, slightly bending over, disengaged +his saber which had caught in his cloak. It was an old-fashioned saber +of a kind no longer in general use. Prince Andrew remembered the story +of Suvorov giving his saber to Bagration in Italy, and the +recollection was particularly pleasant at that moment. They had +reached the battery at which Prince Andrew had been when he examined +the battlefield. + +"Whose company?" asked Prince Bagration of an artilleryman +standing by the ammunition wagon. + +He asked, "Whose company?" but he really meant, "Are you +frightened here?" and the artilleryman understood him. + +"Captain Tushin's, your excellency!" shouted the red-haired, +freckled gunner in a merry voice, standing to attention. + +"Yes, yes," muttered Bagration as if considering something, and he +rode past the limbers to the farthest cannon. + +As he approached, a ringing shot issued from it deafening him and +his suite, and in the smoke that suddenly surrounded the gun they +could see the gunners who had seized it straining to roll it quickly +back to its former position. A huge, broad-shouldered gunner, Number +One, holding a mop, his legs far apart, sprang to the wheel; while +Number Two with a trembling hand placed a charge in the cannon's +mouth. The short, round-shouldered Captain Tushin, stumbling over +the tail of the gun carriage, moved forward and, not noticing the +general, looked out shading his eyes with his small hand. + +"Lift it two lines more and it will be just right," cried he in a +feeble voice to which he tried to impart a dashing note, ill suited to +his weak figure. "Number Two!" he squeaked. "Fire, Medvedev!" + +Bagration called to him, and Tushin, raising three fingers to his +cap with a bashful and awkward gesture not at all like a military +salute but like a priest's benediction, approached the general. Though +Tushin's guns had been intended to cannonade the valley, he was firing +incendiary balls at the village of Schon Grabern visible just +opposite, in front of which large masses of French were advancing. + +No one had given Tushin orders where and at what to fire, but +after consulting his sergeant major, Zakharchenko, for whom he had +great respect, he had decided that it would be a good thing to set +fire to the village. "Very good!" said Bagration in reply to the +officer's report, and began deliberately to examine the whole +battlefield extended before him. The French had advanced nearest on +our right. Below the height on which the Kiev regiment was +stationed, in the hollow where the rivulet flowed, the soul-stirring +rolling and crackling of musketry was heard, and much farther to the +right beyond the dragoons, the officer of the suite pointed out to +Bagration a French column that was outflanking us. To the left the +horizon bounded by the adjacent wood. Prince Bagration ordered two +battalions from the center to be sent to reinforce the right flank. +The officer of the suite ventured to remark to the prince that if +these battalions went away, the guns would remain without support. +Prince Bagration turned to the officer and with his dull eyes looked +at him in silence. It seemed to Prince Andrew that the officer's +remark was just and that really no answer could be made to it. But +at that moment an adjutant galloped up with a message from the +commander of the regiment in the hollow and news that immense masses +of the French were coming down upon them and that his regiment was +in disorder and was retreating upon the Kiev grenadiers. Prince +Bagration bowed his head in sign of assent and approval. He rode off +at a walk to the right and sent an adjutant to the dragoons with +orders to attack the French. But this adjutant returned half an hour +later with the news that the commander of the dragoons had already +retreated beyond the dip in the ground, as a heavy fire had been +opened on him and he was losing men uselessly, and so had hastened +to throw some sharpshooters into the wood. + +"Very good!" said Bagration. + +As he was leaving the battery, firing was heard on the left also, +and as it was too far to the left flank for him to have time to go +there himself, Prince Bagration sent Zherkov to tell the general in +command (the one who had paraded his regiment before Kutuzov at +Braunau) that he must retreat as quickly as possible behind the hollow +in the rear, as the right flank would probably not be able to +withstand the enemy's attack very long. About Tushin and the battalion +that had been in support of his battery all was forgotten. Prince +Andrew listened attentively to Bagration's colloquies with the +commanding officers and the orders he gave them and, to his +surprise, found that no orders were really given, but that Prince +Bagration tried to make it appear that everything done by necessity, +by accident, or by the will of subordinate commanders was done, if not +by his direct command, at least in accord with his intentions. +Prince Andrew noticed, however, that though what happened was due to +chance and was independent of the commander's will, owing to the +tact Bagration showed, his presence was very valuable. Officers who +approached him with disturbed countenances became calm; soldiers and +officers greeted him gaily, grew more cheerful in his presence, and +were evidently anxious to display their courage before him. + + + + + +CHAPTER XVIII + + +Prince Bagration, having reached the highest point of our right +flank, began riding downhill to where the roll of musketry was heard +but where on account of the smoke nothing could be seen. The nearer +they got to the hollow the less they could see but the more they +felt the nearness of the actual battlefield. They began to meet +wounded men. One with a bleeding head and no cap was being dragged +along by two soldiers who supported him under the arms. There was a +gurgle in his throat and he was spitting blood. A bullet had evidently +hit him in the throat or mouth. Another was walking sturdily by +himself but without his musket, groaning aloud and swinging his arm +which had just been hurt, while blood from it was streaming over his +greatcoat as from a bottle. He had that moment been wounded and his +face showed fear rather than suffering. Crossing a road they descended +a steep incline and saw several men lying on the ground; they also met +a crowd of soldiers some of whom were unwounded. The soldiers were +ascending the hill breathing heavily, and despite the general's +presence were talking loudly and gesticulating. In front of them +rows of gray cloaks were already visible through the smoke, and an +officer catching sight of Bagration rushed shouting after the crowd of +retreating soldiers, ordering them back. Bagration rode up to the +ranks along which shots crackled now here and now there, drowning +the sound of voices and the shouts of command. The whole air reeked +with smoke. The excited faces of the soldiers were blackened with +it. Some were using their ramrods, others putting powder on the +touchpans or taking charges from their pouches, while others were +firing, though who they were firing at could not be seen for the smoke +which there was no wind to carry away. A pleasant humming and +whistling of bullets were often heard. "What is this?" thought +Prince Andrew approaching the crowd of soldiers. "It can't be an +attack, for they are not moving; it can't be a square--for they are +not drawn up for that." + +The commander of the regiment, a thin, feeble-looking old man with a +pleasant smile--his eyelids drooping more than half over his old eyes, +giving him a mild expression, rode up to Bagration and welcomed him as +a host welcomes an honored guest. He reported that his regiment had +been attacked by French cavalry and that, though the attack had been +repulsed, he had lost more than half his men. He said the attack had +been repulsed, employing this military term to describe what had +occurred to his regiment, but in reality he did not himself know +what had happened during that half-hour to the troops entrusted to +him, and could not say with certainty whether the attack had been +repulsed or his regiment had been broken up. All he knew was that at +the commencement of the action balls and shells began flying all +over his regiment and hitting men and that afterwards someone had +shouted "Cavalry!" and our men had begun firing. They were still +firing, not at the cavalry which had disappeared, but at French +infantry who had come into the hollow and were firing at our men. +Prince Bagration bowed his head as a sign that this was exactly what +he had desired and expected. Turning to his adjutant he ordered him to +bring down the two battalions of the Sixth Chasseurs whom they had +just passed. Prince Andrew was struck by the changed expression on +Prince Bagration's face at this moment. It expressed the +concentrated and happy resolution you see on the face of a man who +on a hot day takes a final run before plunging into the water. The +dull, sleepy expression was no longer there, nor the affectation of +profound thought. The round, steady, hawk's eyes looked before him +eagerly and rather disdainfully, not resting on anything although +his movements were still slow and measured. + +The commander of the regiment turned to Prince Bagration, entreating +him to go back as it was too dangerous to remain where they were. +"Please, your excellency, for God's sake!" he kept saying, glancing +for support at an officer of the suite who turned away from him. +"There, you see!" and he drew attention to the bullets whistling, +singing, and hissing continually around them. He spoke in the tone +of entreaty and reproach that a carpenter uses to a gentleman who +has picked up an ax: "We are used to it, but you, sir, will blister +your hands." He spoke as if those bullets could not kill him, and +his half-closed eyes gave still more persuasiveness to his words. +The staff officer joined in the colonel's appeals, but Bagration did +not reply; he only gave an order to cease firing and re-form, so as to +give room for the two approaching battalions. While he was speaking, +the curtain of smoke that had concealed the hollow, driven by a rising +wind, began to move from right to left as if drawn by an invisible +hand, and the hill opposite, with the French moving about on it, +opened out before them. All eyes fastened involuntarily on this French +column advancing against them and winding down over the uneven ground. +One could already see the soldiers' shaggy caps, distinguish the +officers from the men, and see the standard flapping against its +staff. + +"They march splendidly," remarked someone in Bagration's suite. + +The head of the column had already descended into the hollow. The +clash would take place on this side of it... + +The remains of our regiment which had been in action rapidly +formed up and moved to the right; from behind it, dispersing the +laggards, came two battalions of the Sixth Chasseurs in fine order. +Before they had reached Bagration, the weighty tread of the mass of +men marching in step could be heard. On their left flank, nearest to +Bagration, marched a company commander, a fine round-faced man, with a +stupid and happy expression--the same man who had rushed out of the +wattle shed. At that moment he was clearly thinking of nothing but how +dashing a fellow he would appear as he passed the commander. + +With the self-satisfaction of a man on parade, he stepped lightly +with his muscular legs as if sailing along, stretching himself to +his full height without the smallest effort, his ease contrasting with +the heavy tread of the soldiers who were keeping step with him. He +carried close to his leg a narrow unsheathed sword (small, curved, and +not like a real weapon) and looked now at the superior officers and +now back at the men without losing step, his whole powerful body +turning flexibly. It was as if all the powers of his soul were +concentrated on passing the commander in the best possible manner, and +feeling that he was doing it well he was happy. "Left... left... +left..." he seemed to repeat to himself at each alternate step; and in +time to this, with stern but varied faces, the wall of soldiers +burdened with knapsacks and muskets marched in step, and each one of +these hundreds of soldiers seemed to be repeating to himself at each +alternate step, "Left... left... left..." A fat major skirted a +bush, puffing and falling out of step; a soldier who had fallen +behind, his face showing alarm at his defection, ran at a trot, +panting to catch up with his company. A cannon ball, cleaving the air, +flew over the heads of Bagration and his suite, and fell into the +column to the measure of "Left... left!" "Close up!" came the +company commander's voice in jaunty tones. The soldiers passed in a +semicircle round something where the ball had fallen, and an old +trooper on the flank, a noncommissioned officer who had stopped beside +the dead men, ran to catch up his line and, falling into step with a +hop, looked back angrily, and through the ominous silence and the +regular tramp of feet beating the ground in unison, one seemed to hear +left... left... left. + +"Well done, lads!" said Prince Bagration. + +"Glad to do our best, your ex'len-lency!" came a confused shout from +the ranks. A morose soldier marching on the left turned his eyes on +Bagration as he shouted, with an expression that seemed to say: "We +know that ourselves!" Another, without looking round, as though +fearing to relax, shouted with his mouth wide open and passed on. + +The order was given to halt and down knapsacks. + +Bagration rode round the ranks that had marched past him and +dismounted. He gave the reins to a Cossack, took off and handed over +his felt coat, stretched his legs, and set his cap straight. The +head of the French column, with its officers leading, appeared from +below the hill. + +"Forward, with God!" said Bagration, in a resolute, sonorous +voice, turning for a moment to the front line, and slightly swinging +his arms, he went forward uneasily over the rough field with the +awkward gait of a cavalryman. Prince Andrew felt that an invisible +power was leading him forward, and experienced great happiness. + +The French were already near. Prince Andrew, walking beside +Bagration, could clearly distinguish their bandoliers, red epaulets, +and even their faces. (He distinctly saw an old French officer who, +with gaitered legs and turned-out toes, climbed the hill with +difficulty.) Prince Bagration gave no further orders and silently +continued to walk on in front of the ranks. Suddenly one shot after +another rang out from the French, smoke appeared all along their +uneven ranks, and musket shots sounded. Several of our men fell, among +them the round-faced officer who had marched so gaily and +complacently. But at the moment the first report was heard, +Bagration looked round and shouted, "Hurrah!" + +"Hurrah--ah!--ah!" rang a long-drawn shout from our ranks, and +passing Bagration and racing one another they rushed in an irregular +but joyous and eager crowd down the hill at their disordered foe. + + + + + +CHAPTER XIX + + +The attack of the Sixth Chasseurs secured the retreat of our right +flank. In the center Tushin's forgotten battery, which had managed +to set fire to the Schon Grabern village, delayed the French +advance. The French were putting out the fire which the wind was +spreading, and thus gave us time to retreat. The retirement of the +center to the other side of the dip in the ground at the rear was +hurried and noisy, but the different companies did not get mixed. +But our left--which consisted of the Azov and Podolsk infantry and the +Pavlograd hussars--was simultaneously attacked and outflanked by +superior French forces under Lannes and was thrown into confusion. +Bagration had sent Zherkov to the general commanding that left flank +with orders to retreat immediately. + +Zherkov, not removing his hand from his cap, turned his horse +about and galloped off. But no sooner had he left Bagration than his +courage failed him. He was seized by panic and could not go where it +was dangerous. + +Having reached the left flank, instead of going to the front where +the firing was, he began to look for the general and his staff where +they could not possibly be, and so did not deliver the order. + +The command of the left flank belonged by seniority to the commander +of the regiment Kutuzov had reviewed at Braunau and in which +Dolokhov was serving as a private. But the command of the extreme left +flank had been assigned to the commander of the Pavlograd regiment +in which Rostov was serving, and a misunderstanding arose. The two +commanders were much exasperated with one another and, long after +the action had begun on the right flank and the French were already +advancing, were engaged in discussion with the sole object of +offending one another. But the regiments, both cavalry and infantry, +were by no means ready for the impending action. From privates to +general they were not expecting a battle and were engaged in +peaceful occupations, the cavalry feeding the horses and the +infantry collecting wood. + +"He higher iss dan I in rank," said the German colonel of the +hussars, flushing and addressing an adjutant who had ridden up, "so +let him do what he vill, but I cannot sacrifice my hussars... +Bugler, sount ze retreat!" + +But haste was becoming imperative. Cannon and musketry, mingling +together, thundered on the right and in the center, while the +capotes of Lannes' sharpshooters were already seen crossing the +milldam and forming up within twice the range of a musket shot. The +general in command of the infantry went toward his horse with jerky +steps, and having mounted drew himself up very straight and tall and +rode to the Pavlograd commander. The commanders met with polite bows +but with secret malevolence in their hearts. + +"Once again, Colonel," said the general, "I can't leave half my +men in the wood. I beg of you, I beg of you," he repeated, "to +occupy the position and prepare for an attack." + +"I peg of you yourself not to mix in vot is not your business!" +suddenly replied the irate colonel. "If you vere in the cavalry..." + +"I am not in the cavalry, Colonel, but I am a Russian general and if +you are not aware of the fact..." + +"Quite avare, your excellency," suddenly shouted the colonel, +touching his horse and turning purple in the face. "Vill you be so +goot to come to ze front and see dat zis position iss no goot? I don't +vish to destroy my men for your pleasure!" + +"You forget yourself, Colonel. I am not considering my own +pleasure and I won't allow it to be said!" + +Taking the colonel's outburst as a challenge to his courage, the +general expanded his chest and rode, frowning, beside him to the front +line, as if their differences would be settled there amongst the +bullets. They reached the front, several bullets sped over them, and +they halted in silence. There was nothing fresh to be seen from the +line, for from where they had been before it had been evident that +it was impossible for cavalry to act among the bushes and broken +ground, as well as that the French were outflanking our left. The +general and colonel looked sternly and significantly at one another +like two fighting cocks preparing for battle, each vainly trying to +detect signs of cowardice in the other. Both passed the examination +successfully. As there was nothing to said, and neither wished to give +occasion for it to be alleged that he had been the first to leave +the range of fire, they would have remained there for a long time +testing each other's courage had it not been that just then they heard +the rattle of musketry and a muffled shout almost behind them in the +wood. The French had attacked the men collecting wood in the copse. It +was no longer possible for the hussars to retreat with the infantry. +They were cut off from the line of retreat on the left by the +French. However inconvenient the position, it was now necessary to +attack in order to cut away through for themselves. + +The squadron in which Rostov was serving had scarcely time to +mount before it was halted facing the enemy. Again, as at the Enns +bridge, there was nothing between the squadron and the enemy, and +again that terrible dividing line of uncertainty and fear- +resembling the line separating the living from the dead--lay between +them. All were conscious of this unseen line, and the question whether +they would cross it or not, and how they would cross it, +agitated them all. + +The colonel rode to the front, angrily gave some reply to +questions put to him by the officers, and, like a man desperately +insisting on having his own way, gave an order. No one said anything +definite, but the rumor of an attack spread through the squadron. +The command to form up rang out and the sabers whizzed as they were +drawn from their scabbards. Still no one moved. The troops of the left +flank, infantry and hussars alike, felt that the commander did not +himself know what to do, and this irresolution communicated itself +to the men. + +"If only they would be quick!" thought Rostov, feeling that at +last the time had come to experience the joy of an attack of which +he had so often heard from his fellow hussars. + +"Fo'ward, with God, lads!" rang out Denisov's voice. "At a twot +fo'ward!" + +The horses' croups began to sway in the front line. Rook pulled at +the reins and started of his own accord. + +Before him, on the right, Rostov saw the front lines of his +hussars and still farther ahead a dark line which he could not see +distinctly but took to be the enemy. Shots could be heard, but some +way off. + +"Faster!" came the word of command, and Rostov felt Rook's flanks +drooping as he broke into a gallop. + +Rostov anticipated his horse's movements and became more and more +elated. He had noticed a solitary tree ahead of him. This tree had +been in the middle of the line that had seemed so terrible--and now he +had crossed that line and not only was there nothing terrible, but +everything was becoming more and more happy and animated. "Oh, how I +will slash at him!" thought Rostov, gripping the hilt of his saber. + +"Hur-a-a-a-ah!" came a roar of voices. "Let anyone come my way now," +thought Rostov driving his spurs into Rook and letting him go at a +full gallop so that he outstripped the others. Ahead, the enemy was +already visible. Suddenly something like a birch broom seemed to sweep +over the squadron. Rostov raised his saber, ready to strike, but at +that instant the trooper Nikitenko, who was galloping ahead, shot away +from him, and Rostov felt as in a dream that he continued to be +carried forward with unnatural speed but yet stayed on the same +spot. From behind him Bondarchuk, an hussar he knew, jolted against +him and looked angrily at him. Bondarchuk's horse swerved and galloped +past. + +"How is it I am not moving? I have fallen, I am killed!" Rostov +asked and answered at the same instant. He was alone in the middle +of a field. Instead of the moving horses and hussars' backs, he saw +nothing before him but the motionless earth and the stubble around +him. There was warm blood under his arm. "No, I am wounded and the +horse is killed." Rook tried to rise on his forelegs but fell back, +pinning his rider's leg. Blood was flowing from his head; he struggled +but could not rise. Rostov also tried to rise but fell back, his +sabretache having become entangled in the saddle. Where our men +were, and where the French, he did not know. There was no one near. + +Having disentangled his leg, he rose. "Where, on which side, was now +the line that had so sharply divided the two armies?" he asked himself +and could not answer. "Can something bad have happened to me?" he +wondered as he got up: and at that moment he felt that something +superfluous was hanging on his benumbed left arm. The wrist felt as if +it were not his. He examined his hand carefully, vainly trying to find +blood on it. "Ah, here are people coming," he thought joyfully, seeing +some men running toward him. "They will help me!" In front came a +man wearing a strange shako and a blue cloak, swarthy, sunburned, +and with a hooked nose. Then came two more, and many more running +behind. One of them said something strange, not in Russian. In among +the hindmost of these men wearing similar shakos was a Russian hussar. +He was being held by the arms and his horse was being led behind him. + +"It must be one of ours, a prisoner. Yes. Can it be that they will +take me too? Who are these men?" thought Rostov, scarcely believing +his eyes. "Can they be French?" He looked at the approaching +Frenchmen, and though but a moment before he had been galloping to get +at them and hack them to pieces, their proximity now seemed so awful +that he could not believe his eyes. "Who are they? Why are they +running? Can they be coming at me? And why? To kill me? Me whom +everyone is so fond of?" He remembered his mother's love for him, +and his family's, and his friends', and the enemy's intention to +kill him seemed impossible. "But perhaps they may do it!" For more +than ten seconds he stood not moving from the spot or realizing the +situation. The foremost Frenchman, the one with the hooked nose, was +already so close that the expression of his face could be seen. And +the excited, alien face of that man, his bayonet hanging down, holding +his breath, and running so lightly, frightened Rostov. He seized his +pistol and, instead of firing it, flung it at the Frenchman and ran +with all his might toward the bushes. He did not now run with the +feeling of doubt and conflict with which he had trodden the Enns +bridge, but with the feeling of a hare fleeing from the hounds. One +single sentiment, that of fear for his young and happy life, possessed +his whole being. Rapidly leaping the furrows, he fled across the field +with the impetuosity he used to show at catchplay, now and then +turning his good-natured, pale, young face to look back. A shudder +of terror went through him: "No, better not look," he thought, but +having reached the bushes he glanced round once more. The French had +fallen behind, and just as he looked round the first man changed his +run to a walk and, turning, shouted something loudly to a comrade +farther back. Rostov paused. "No, there's some mistake," thought he. +"They can't have wanted to kill me." But at the same time, his left +arm felt as heavy as if a seventy-pound weight were tied to it. He +could run no more. The Frenchman also stopped and took aim. Rostov +closed his eyes and stooped down. One bullet and then another whistled +past him. He mustered his last remaining strength, took hold of his +left hand with his right, and reached the bushes. Behind these were +some Russian sharpshooters. + + + + + +CHAPTER XX + + +The infantry regiments that had been caught unawares in the +outskirts of the wood ran out of it, the different companies getting +mixed, and retreated as a disorderly crowd. One soldier, in his +fear, uttered the senseless cry, "Cut off!" that is so terrible in +battle, and that word infected the whole crowd with a feeling of +panic. + +"Surrounded! Cut off? We're lost!" shouted the fugitives. + +The moment he heard the firing and the cry from behind, the +general realized that something dreadful had happened to his regiment, +and the thought that he, an exemplary officer of many years' service +who had never been to blame, might be held responsible at headquarters +for negligence or inefficiency so staggered him that, forgetting the +recalcitrant cavalry colonel, his own dignity as a general, and +above all quite forgetting the danger and all regard for +self-preservation, he clutched the crupper of his saddle and, spurring +his horse, galloped to the regiment under a hail of bullets which fell +around, but fortunately missed him. His one desire was to know what +was happening and at any cost correct, or remedy, the mistake if he +had made one, so that he, an exemplary officer of twenty-two years' +service, who had never been censured, should not be held to blame. + +Having galloped safely through the French, he reached a field behind +the copse across which our men, regardless of orders, were running and +descending the valley. That moment of moral hesitation which decides +the fate of battles had arrived. Would this disorderly crowd of +soldiers attend to the voice of their commander, or would they, +disregarding him, continue their flight? Despite his desperate +shouts that used to seem so terrible to the soldiers, despite his +furious purple countenance distorted out of all likeness to his former +self, and the flourishing of his saber, the soldiers all continued +to run, talking, firing into the air, and disobeying orders. The moral +hesitation which decided the fate of battles was evidently culminating +in a panic. + +The general had a fit of coughing as a result of shouting and of the +powder smoke and stopped in despair. Everything seemed lost. But at +that moment the French who were attacking, suddenly and without any +apparent reason, ran back and disappeared from the outskirts, and +Russian sharpshooters showed themselves in the copse. It was +Timokhin's company, which alone had maintained its order in the wood +and, having lain in ambush in a ditch, now attacked the French +unexpectedly. Timokhin, armed only with a sword, had rushed at the +enemy with such a desperate cry and such mad, drunken determination +that, taken by surprise, the French had thrown down their muskets +and run. Dolokhov, running beside Timokhin, killed a Frenchman at +close quarters and was the first to seize the surrendering French +officer by his collar. Our fugitives returned, the battalions +re-formed, and the French who had nearly cut our left flank in half +were for the moment repulsed. Our reserve units were able to join +up, and the fight was at an end. The regimental commander and Major +Ekonomov had stopped beside a bridge, letting the retreating companies +pass by them, when a soldier came up and took hold of the +commander's stirrup, almost leaning against him. The man was wearing a +bluish coat of broadcloth, he had no knapsack or cap, his head was +bandaged, and over his shoulder a French munition pouch was slung. +He had an officer's sword in his hand. The soldier was pale, his +blue eyes looked impudently into the commander's face, and his lips +were smiling. Though the commander was occupied in giving instructions +to Major Ekonomov, he could not help taking notice of the soldier. + +"Your excellency, here are two trophies," said Dolokhov, pointing to +the French sword and pouch. "I have taken an officer prisoner. I +stopped the company." Dolokhov breathed heavily from weariness and +spoke in abrupt sentences. "The whole company can bear witness. I +beg you will remember this, your excellency!" + +"All right, all right," replied the commander, and turned to Major +Ekonomov. + +But Dolokhov did not go away; he untied the handkerchief around +his head, pulled it off, and showed the blood congealed on his hair. + +"A bayonet wound. I remained at the front. Remember, your +excellency!" + + +Tushin's battery had been forgotten and only at the very end of +the action did Prince Bagration, still hearing the cannonade in the +center, send his orderly staff officer, and later Prince Andrew +also, to order the battery to retire as quickly as possible. When +the supports attached to Tushin's battery had been moved away in the +middle of the action by someone's order, the battery had continued +firing and was only not captured by the French because the enemy could +not surmise that anyone could have the effrontery to continue firing +from four quite undefended guns. On the contrary, the energetic action +of that battery led the French to suppose that here--in the center- +the main Russian forces were concentrated. Twice they had attempted to +attack this point, but on each occasion had been driven back by +grapeshot from the four isolated guns on the hillock. + +Soon after Prince Bagration had left him, Tushin had succeeded in +setting fire to Schon Grabern. + +"Look at them scurrying! It's burning! Just see the smoke! Fine! +Grand! Look at the smoke, the smoke!" exclaimed the artillerymen, +brightening up. + +All the guns, without waiting for orders, were being fired in the +direction of the conflagration. As if urging each other on, the +soldiers cried at each shot: "Fine! That's good! Look at it... Grand!" +The fire, fanned by the breeze, was rapidly spreading. The French +columns that had advanced beyond the village went back; but as +though in revenge for this failure, the enemy placed ten guns to the +right of the village and began firing them at Tushin's battery. + +In their childlike glee, aroused by the fire and their luck in +successfully cannonading the French, our artillerymen only noticed +this battery when two balls, and then four more, fell among our +guns, one knocking over two horses and another tearing off a +munition-wagon driver's leg. Their spirits once roused were, +however, not diminished, but only changed character. The horses were +replaced by others from a reserve gun carriage, the wounded were +carried away, and the four guns were turned against the ten-gun +battery. Tushin's companion officer had been killed at the beginning +of the engagement and within an hour seventeen of the forty men of the +guns' crews had been disabled, but the artillerymen were still as +merry and lively as ever. Twice they noticed the French appearing +below them, and then they fired grapeshot at them. + +Little Tushin, moving feebly and awkwardly, kept telling his orderly +to "refill my pipe for that one!" and then, scattering sparks from it, +ran forward shading his eyes with his small hand to look at the +French. + +"Smack at 'em, lads!" he kept saying, seizing the guns by the wheels +and working the screws himself. + +Amid the smoke, deafened by the incessant reports which always +made him jump, Tushin not taking his pipe from his mouth ran from +gun to gun, now aiming, now counting the charges, now giving orders +about replacing dead or wounded horses and harnessing fresh ones, +and shouting in his feeble voice, so high pitched and irresolute. +His face grew more and more animated. Only when a man was killed or +wounded did he frown and turn away from the sight, shouting angrily at +the men who, as is always the case, hesitated about lifting the +injured or dead. The soldiers, for the most part handsome fellows and, +as is always the case in an artillery company, a head and shoulders +taller and twice as broad as their officer--all looked at their +commander like children in an embarrassing situation, and the +expression on his face was invariably reflected on theirs. + +Owing to the terrible uproar and the necessity for concentration and +activity, Tushin did not experience the slightest unpleasant sense +of fear, and the thought that he might be killed or badly wounded +never occurred to him. On the contrary, he became more and more +elated. It seemed to him that it was a very long time ago, almost a +day, since he had first seen the enemy and fired the first shot, and +that the corner of the field he stood on was well-known and familiar +ground. Though he thought of everything, considered everything, and +did everything the best of officers could do in his position, he was +in a state akin to feverish delirium or drunkenness. + +From the deafening sounds of his own guns around him, the whistle +and thud of the enemy's cannon balls, from the flushed and +perspiring faces of the crew bustling round the guns, from the sight +of the blood of men and horses, from the little puffs of smoke on +the enemy's side (always followed by a ball flying past and striking +the earth, a man, a gun, a horse), from the sight of all these +things a fantastic world of his own had taken possession of his +brain and at that moment afforded him pleasure. The enemy's guns +were in his fancy not guns but pipes from which occasional puffs +were blown by an invisible smoker. + +"There... he's puffing again," muttered Tushin to himself, as a +small cloud rose from the hill and was borne in a streak to the left +by the wind. + +"Now look out for the ball... we'll throw it back." + +"What do you want, your honor?" asked an artilleryman, standing +close by, who heard him muttering. + +"Nothing... only a shell..." he answered. + +"Come along, our Matvevna!" he said to himself. "Matvevna"* was +the name his fancy gave to the farthest gun of the battery, which +was large and of an old pattern. The French swarming round their +guns seemed to him like ants. In that world, the handsome drunkard +Number One of the second gun's crew was "uncle"; Tushin looked at +him more often than at anyone else and took delight in his every +movement. The sound of musketry at the foot of the hill, now +diminishing, now increasing, seemed like someone's breathing. He +listened intently to the ebb and flow of these sounds. + + +*Daughter of Matthew. + + +"Ah! Breathing again, breathing!" he muttered to himself. + +He imagined himself as an enormously tall, powerful man who was +throwing cannon balls at the French with both hands. + +"Now then, Matvevna, dear old lady, don't let me down!" he was +saying as he moved from the gun, when a strange, unfamiliar voice +called above his head: "Captain Tushin! Captain!" + +Tushin turned round in dismay. It was the staff officer who had +turned him out of the booth at Grunth. He was shouting in a gasping +voice: + +"Are you mad? You have twice been ordered to retreat, and you..." + +"Why are they down on me?" thought Tushin, looking in alarm at his +superior. + +"I... don't..." he muttered, holding up two fingers to his cap. +"I..." + +But the staff officer did not finish what he wanted to say. A cannon +ball, flying close to him, caused him to duck and bend over his horse. +He paused, and just as he was about to say something more, another +ball stopped him. He turned his horse and galloped off. + +"Retire! All to retire!" he shouted from a distance. + +The soldiers laughed. A moment later, an adjutant arrived with the +same order. + +It was Prince Andrew. The first thing he saw on riding up to the +space where Tushin's guns were stationed was an unharnessed horse with +a broken leg, that lay screaming piteously beside the harnessed +horses. Blood was gushing from its leg as from a spring. Among the +limbers lay several dead men. One ball after another passed over as he +approached and he felt a nervous shudder run down his spine. But the +mere thought of being afraid roused him again. "I cannot be afraid," +thought he, and dismounted slowly among the guns. He delivered the +order and did not leave the battery. He decided to have the guns +removed from their positions and withdrawn in his presence. Together +with Tushin, stepping across the bodies and under a terrible fire from +the French, he attended to the removal of the guns. + +"A staff officer was here a minute ago, but skipped off," said an +artilleryman to Prince Andrew. "Not like your honor!" + +Prince Andrew said nothing to Tushin. They were both so busy as to +seem not to notice one another. When having limbered up the only two +cannon that remained uninjured out of the four, they began moving down +the hill (one shattered gun and one unicorn were left behind), +Prince Andrew rode up to Tushin. + +"Well, till we meet again..." he said, holding out his hand to +Tushin. + +"Good-by, my dear fellow," said Tushin. "Dear soul! Good-by, my dear +fellow!" and for some unknown reason tears suddenly filled his eyes. + + + + + +CHAPTER XXI + + +The wind had fallen and black clouds, merging with the powder smoke, +hung low over the field of battle on the horizon. It was growing +dark and the glow of two conflagrations was the more conspicuous. +The cannonade was dying down, but the rattle of musketry behind and on +the right sounded oftener and nearer. As soon as Tushin with his guns, +continually driving round or coming upon wounded men, was out of range +of fire and had descended into the dip, he was met by some of the +staff, among them the staff officer and Zherkov, who had been twice +sent to Tushin's battery but had never reached it. Interrupting one +another, they all gave, and transmitted, orders as to how to +proceed, reprimanding and reproaching him. Tushin gave no orders, and, +silently--fearing to speak because at every word he felt ready to weep +without knowing why--rode behind on his artillery nag. Though the +orders were to abandon the wounded, many of them dragged themselves +after troops and begged for seats on the gun carriages. The jaunty +infantry officer who just before the battle had rushed out of Tushin's +wattle shed was laid, with a bullet in his stomach, on "Matvevna's" +carriage. At the foot of the hill, a pale hussar cadet, supporting one +hand with the other, came up to Tushin and asked for a seat. + +"Captain, for God's sake! I've hurt my arm," he said timidly. "For +God's sake... I can't walk. For God's sake!" + +It was plain that this cadet had already repeatedly asked for a lift +and been refused. He asked in a hesitating, piteous voice. + +"Tell them to give me a seat, for God's sake!" + +"Give him a seat," said Tushin. "Lay a cloak for him to sit on, +lad," he said, addressing his favorite soldier. "And where is the +wounded officer?" + +"He has been set down. He died," replied someone. + +"Help him up. Sit down, dear fellow, sit down! Spread out the cloak, +Antonov." + +The cadet was Rostov. With one hand he supported the other; he was +pale and his jaw trembled, shivering feverishly. He was placed on +"Matvevna," the gun from which they had removed the dead officer. +The cloak they spread under him was wet with blood which stained his +breeches and arm. + +"What, are you wounded, my lad?" said Tushin, approaching the gun on +which Rostov sat. + +"No, it's a sprain." + +"Then what is this blood on the gun carriage?" inquired Tushin. + +"It was the officer, your honor, stained it," answered the +artilleryman, wiping away the blood with his coat sleeve, as if +apologizing for the state of his gun. + +It was all that they could do to get the guns up the rise aided by +the infantry, and having reached the village of Gruntersdorf they +halted. It had grown so dark that one could not distinguish the +uniforms ten paces off, and the firing had begun to subside. Suddenly, +near by on the right, shouting and firing were again heard. Flashes of +shot gleamed in the darkness. This was the last French attack and +was met by soldiers who had sheltered in the village houses. They +all rushed out of the village again, but Tushin's guns could not move, +and the artillerymen, Tushin, and the cadet exchanged silent glances +as they awaited their fate. The firing died down and soldiers, talking +eagerly, streamed out of a side street. + +"Not hurt, Petrov?" asked one. + +"We've given it 'em hot, mate! They won't make another push now," +said another. + +"You couldn't see a thing. How they shot at their own fellows! +Nothing could be seen. Pitch-dark, brother! Isn't there something to +drink?" + +The French had been repulsed for the last time. And again and +again in the complete darkness Tushin's guns moved forward, surrounded +by the humming infantry as by a frame. + +In the darkness, it seemed as though a gloomy unseen river was +flowing always in one direction, humming with whispers and talk and +the sound of hoofs and wheels. Amid the general rumble, the groans and +voices of the wounded were more distinctly heard than any other +sound in the darkness of the night. The gloom that enveloped the +army was filled with their groans, which seemed to melt into one +with the darkness of the night. After a while the moving mass became +agitated, someone rode past on a white horse followed by his suite, +and said something in passing: "What did he say? Where to, now? +Halt, is it? Did he thank us?" came eager questions from all sides. +The whole moving mass began pressing closer together and a report +spread that they were ordered to halt: evidently those in front had +halted. All remained where they were in the middle of the muddy road. + +Fires were lighted and the talk became more audible. Captain Tushin, +having given orders to his company, sent a soldier to find a +dressing station or a doctor for the cadet, and sat down by a +bonfire the soldiers had kindled on the road. Rostov, too, dragged +himself to the fire. From pain, cold, and damp, a feverish shivering +shook his whole body. Drowsiness was irresistibly mastering him, but +he kept awake by an excruciating pain in his arm, for which +he could find no satisfactory position. He kept closing his eyes and +then again looking at the fire, which seemed to him dazzlingly red, +and at the feeble, round-shouldered figure of Tushin who was sitting +cross-legged like a Turk beside him. Tushin's large, kind, intelligent +eyes were fixed with sympathy and commiseration on Rostov, who saw +that Tushin with his whole heart wished to help him but could not. + +From all sides were heard the footsteps and talk of the infantry, +who were walking, driving past, and settling down all around. The +sound of voices, the tramping feet, the horses' hoofs moving in mud, +the crackling of wood fires near and afar, merged into one tremulous +rumble. + +It was no longer, as before, a dark, unseen river flowing through +the gloom, but a dark sea swelling and gradually subsiding after a +storm. Rostov looked at and listened listlessly to what passed +before and around him. An infantryman came to the fire, squatted on +his heels, held his hands to the blaze, and turned away his face. + +"You don't mind your honor?" he asked Tushin. "I've lost my company, +your honor. I don't know where... such bad luck!" + +With the soldier, an infantry officer with a bandaged cheek came +up to the bonfire, and addressing Tushin asked him to have the guns +moved a trifle to let a wagon go past. After he had gone, two soldiers +rushed to the campfire. They were quarreling and fighting desperately, +each trying to snatch from the other a boot they were both holding +on to. + +"You picked it up?... I dare say! You're very smart!" one of them +shouted hoarsely. + +Then a thin, pale soldier, his neck bandaged with a bloodstained leg +band, came up and in angry tones asked the artillerymen for water. + +"Must one die like a dog?" said he. + +Tushin told them to give the man some water. Then a cheerful soldier +ran up, begging a little fire for the infantry. + +"A nice little hot torch for the infantry! Good luck to you, +fellow countrymen. Thanks for the fire--we'll return it with +interest," said he, carrying away into the darkness a glowing stick. + +Next came four soldiers, carrying something heavy on a cloak, and +passed by the fire. One of them stumbled. + +"Who the devil has put the logs on the road?" snarled he. + +"He's dead--why carry him?" said another. + +"Shut up!" + +And they disappeared into the darkness with with their load. + +"Still aching?" Tushin asked Rostov in a whisper. + +"Yes." + +"Your honor, you're wanted by the general. He is in the hut here," +said a gunner, coming up to Tushin. + +"Coming, friend." + +Tushin rose and, buttoning his greatcoat and pulling it straight, +walked away from the fire. + +Not far from the artillery campfire, in a hut that had been prepared +for him, Prince Bagration sat at dinner, talking with some +commanding officers who had gathered at his quarters. The little old +man with the half-closed eyes was there greedily gnawing a mutton +bone, and the general who had served blamelessly for twenty-two years, +flushed by a glass of vodka and the dinner; and the staff officer with +the signet ring, and Zherkov, uneasily glancing at them all, and +Prince Andrew, pale, with compressed lips and feverishly glittering +eyes. + +In a corner of the hut stood a standard captured from the French, +and the accountant with the naive face was feeling its texture, +shaking his head in perplexity--perhaps because the banner really +interested him, perhaps because it was hard for him, hungry as he was, +to look on at a dinner where there was no place for him. In the next +hut there was a French colonel who had been taken prisoner by our +dragoons. Our officers were flocking in to look at him. Prince +Bagration was thanking the individual commanders and inquiring into +details of the action and our losses. The general whose regiment had +been inspected at Braunau was informing the prince that as soon as the +action began he had withdrawn from the wood, mustered the men who were +woodcutting, and, allowing the French to pass him, had made a +bayonet charge with two battalions and had broken up the French +troops. + +"When I saw, your excellency, that their first battalion was +disorganized, I stopped in the road and thought: 'I'll let them come +on and will meet them with the fire of the whole battalion'--and +that's what I did." + +The general had so wished to do this and was so sorry he had not +managed to do it that it seemed to him as if it had really happened. +Perhaps it might really have been so? Could one possibly make out amid +all that confusion what did or did not happen? + +"By the way, your excellency, I should inform you," he continued- +remembering Dolokhov's conversation with Kutuzov and his last +interview with the gentleman-ranker--"that Private Dolokhov, who was +reduced to the ranks, took a French officer prisoner in my presence +and particularly distinguished himself." + +"I saw the Pavlograd hussars attack there, your excellency," +chimed in Zherkov, looking uneasily around. He had not seen the +hussars all that day, but had heard about them from an infantry +officer. "They broke up two squares, your excellency." + +Several of those present smiled at Zherkov's words, expecting one of +his usual jokes, but noticing that what he was saying redounded to the +glory of our arms and of the day's work, they assumed a serious +expression, though many of them knew that what he was saying was a lie +devoid of any foundation. Prince Bagration turned to the old colonel: + +"Gentlemen, I thank you all; all arms have behaved heroically: +infantry, cavalry, and artillery. How was it that two guns were +abandoned in the center?" he inquired, searching with his eyes for +someone. (Prince Bagration did not ask about the guns on the left +flank; he knew that all the guns there had been abandoned at the +very beginning of the action.) "I think I sent you?" he added, turning +to the staff officer on duty. + +"One was damaged," answered the staff officer, "and the other I +can't understand. I was there all the time giving orders and had +only just left.... It is true that it was hot there," he added, +modestly. + +Someone mentioned that Captain Tushin was bivouacking close to the +village and had already been sent for. + +"Oh, but you were there?" said Prince Bagration, addressing Prince +Andrew. + +"Of course, we only just missed one another," said the staff +officer, with a smile to Bolkonski. + +"I had not the pleasure of seeing you," said Prince Andrew, coldly +and abruptly. + +All were silent. Tushin appeared at the threshold and made his way +timidly from behind the backs of the generals. As he stepped past +the generals in the crowded hut, feeling embarrassed as he always +was by the sight of his superiors, he did not notice the staff of +the banner and stumbled over it. Several of those present laughed. + +"How was it a gun was abandoned?" asked Bagration, frowning, not +so much at the captain as at those who were laughing, among whom +Zherkov laughed loudest. + +Only now, when he was confronted by the stern authorities, did his +guilt and the disgrace of having lost two guns and yet remaining alive +present themselves to Tushin in all their horror. He had been so +excited that he had not thought about it until that moment. The +officers' laughter confused him still more. He stood before +Bagration with his lower jaw trembling and was hardly able to +mutter: "I don't know... your excellency... I had no men... your +excellency." + +"You might have taken some from the covering troops." + +Tushin did not say that there were no covering troops, though that +was perfectly true. He was afraid of getting some other officer into +trouble, and silently fixed his eyes on Bagration as a schoolboy who +has blundered looks at an examiner. + +The silence lasted some time. Prince Bagration, apparently not +wishing to be severe, found nothing to say; the others did not venture +to intervene. Prince Andrew looked at Tushin from under his brows +and his fingers twitched nervously. + +"Your excellency!" Prince Andrew broke the silence with his abrupt +voice," you were pleased to send me to Captain Tushin's battery. I +went there and found two thirds of the men and horses knocked out, two +guns smashed, and no supports at all." + +Prince Bagration and Tushin looked with equal intentness at +Bolkonski, who spoke with suppressed agitation. + +"And, if your excellency will allow me to express my opinion," he +continued, "we owe today's success chiefly to the action of that +battery and the heroic endurance of Captain Tushin and his company," +and without awaiting a reply, Prince Andrew rose and left the table. + +Prince Bagration looked at Tushin, evidently reluctant to show +distrust in Bolkonski's emphatic opinion yet not feeling able fully to +credit it, bent his head, and told Tushin that he could go. Prince +Andrew went out with him. + +"Thank you; you saved me, my dear fellow!" said Tushin. + +Prince Andrew gave him a look, but said nothing and went away. He +felt sad and depressed. It was all so strange, so unlike what he had +hoped. + + +"Who are they? Why are they here? What do they want? And when will +all this end?" thought Rostov, looking at the changing shadows +before him. The pain in his arm became more and more intense. +Irresistible drowsiness overpowered him, red rings danced before his +eyes, and the impression of those voices and faces and a sense of +loneliness merged with the physical pain. It was they, these soldiers- +wounded and unwounded--it was they who were crushing, weighing down, +and twisting the sinews and scorching the flesh of his sprained arm +and shoulder. To rid himself of them he closed his eyes. + +For a moment he dozed, but in that short interval innumerable things +appeared to him in a dream: his mother and her large white hand, +Sonya's thin little shoulders, Natasha's eyes and laughter, Denisov +with his voice and mustache, and Telyanin and all that affair with +Telyanin and Bogdanich. That affair was the same thing as this soldier +with the harsh voice, and it was that affair and this soldier that +were so agonizingly, incessantly pulling and pressing his arm and +always dragging it in one direction. He tried to get away from them, +but they would not for an instant let his shoulder move a hair's +breadth. It would not ache--it would be well--if only they did not +pull it, but it was impossible to get rid of them. + +He opened his eyes and looked up. The black canopy of night hung +less than a yard above the glow of the charcoal. Flakes of falling +snow were fluttering in that light. Tushin had not returned, the +doctor had not come. He was alone now, except for a soldier who was +sitting naked at the other side of the fire, warming his thin yellow +body. + +"Nobody wants me!" thought Rostov. "There is no one to help me or +pity me. Yet I was once at home, strong, happy, and loved." He +sighed and, doing so, groaned involuntarily. + +"Eh, is anything hurting you?" asked the soldier, shaking his +shirt out over the fire, and not waiting for an answer he gave a grunt +and added: "What a lot of men have been crippled today--frightful!" + +Rostov did not listen to the soldier. He looked at the snowflakes +fluttering above the fire and remembered a Russian winter at his warm, +bright home, his fluffy fur coat, his quickly gliding sleigh, his +healthy body, and all the affection and care of his family. "And why +did I come here?" he wondered. + +Next day the French army did not renew their attack, and the remnant +of Bagration's detachment was reunited to Kutuzov's army. + + + + +BOOK THREE: 1805 + + + + + +CHAPTER I + + +Prince Vasili was not a man who deliberately thought out his +plans. Still less did he think of injuring anyone for his own +advantage. He was merely a man of the world who had got on and to whom +getting on had become a habit. Schemes and devices for which he +never rightly accounted to himself, but which formed the whole +interest of his life, were constantly shaping themselves in his +mind, arising from the circumstances and persons he met. Of these +plans he had not merely one or two in his head but dozens, some only +beginning to form themselves, some approaching achievement, and some +in course of disintegration. He did not, for instance, say to himself: +"This man now has influence, I must gain his confidence and friendship +and through him obtain a special grant." Nor did he say to himself: +"Pierre is a rich man, I must entice him to marry my daughter and lend +me the forty thousand rubles I need." But when he came across +a man of position his instinct immediately told him that this +man could be useful, and without any premeditation Prince Vasili +took the first opportunity to gain his confidence, flatter him, become +intimate with him, and finally make his request. + +He had Pierre at hand in Moscow and procured for him an +appointment as Gentleman of the Bedchamber, which at that time +conferred the status of Councilor of State, and insisted on the +young man accompanying him to Petersburg and staying at his house. +With apparent absent-mindedness, yet with unhesitating assurance +that he was doing the right thing, Prince Vasili did everything to get +Pierre to marry his daughter. Had he thought out his plans +beforehand he could not have been so natural and shown such unaffected +familiarity in intercourse with everybody both above and below him +in social standing. Something always drew him toward those richer +and more powerful than himself and he had rare skill in seizing the +most opportune moment for making use of people. + +Pierre, on unexpectedly becoming Count Bezukhov and a rich man, felt +himself after his recent loneliness and freedom from cares so beset +and preoccupied that only in bed was he able to be by himself. He +had to sign papers, to present himself at government offices, the +purpose of which was not clear to him, to question his chief +steward, to visit his estate near Moscow, and to receive many people +who formerly did not even wish to know of his existence but would +now have been offended and grieved had he chosen not to see them. +These different people--businessmen, relations, and acquaintances +alike--were all disposed to treat the young heir in the most +friendly and flattering manner: they were all evidently firmly +convinced of Pierre's noble qualities. He was always hearing such +words as: "With your remarkable kindness," or, "With your excellent +heart," "You are yourself so honorable Count," or, "Were he as +clever as you," and so on, till he began sincerely to believe in his +own exceptional kindness and extraordinary intelligence, the more so +as in the depth of his heart it had always seemed to him that he +really was very kind and intelligent. Even people who had formerly +been spiteful toward him and evidently unfriendly now became gentle +and affectionate. The angry eldest princess, with the long waist and +hair plastered down like a doll's, had come into Pierre's room after +the funeral. With drooping eyes and frequent blushes she told him +she was very sorry about their past misunderstandings and did not +now feel she had a right to ask him for anything, except only for +permission, after the blow she had received, to remain for a few weeks +longer in the house she so loved and where she had sacrificed so much. +She could not refrain from weeping at these words. Touched that this +statuesque princess could so change, Pierre took her hand and begged +her forgiveness, without knowing what for. From that day the eldest +princess quite changed toward Pierre and began knitting a striped +scarf for him. + +"Do this for my sake, mon cher; after all, she had to put up with +a great deal from the deceased," said Prince Vasili to him, handing +him a deed to sign for the princess' benefit. + +Prince Vasili had come to the conclusion that it was necessary to +throw this bone--a bill for thirty thousand rubles--to the poor +princess that it might not occur to her to speak of his share in the +affair of the inlaid portfolio. Pierre signed the deed and after +that the princess grew still kinder. The younger sisters also became +affectionate to him, especially the youngest, the pretty one with +the mole, who often made him feel confused by her smiles and her own +confusion when meeting him. + +It seemed so natural to Pierre that everyone should like him, and it +would have seemed so unnatural had anyone disliked him, that he +could not but believe in the sincerity of those around him. Besides, +he had no time to ask himself whether these people were sincere or +not. He was always busy and always felt in a state of mild and +cheerful intoxication. He felt as though he were the center of some +important and general movement; that something was constantly expected +of him, that if he did not do it he would grieve and disappoint many +people, but if he did this and that, all would be well; and he did +what was demanded of him, but still that happy result always +remained in the future. + +More than anyone else, Prince Vasili took possession of Pierre's +affairs and of Pierre himself in those early days. From the death of +Count Bezukhov he did not let go his hold of the lad. He had the air +of a man oppressed by business, weary and suffering, who yet would +not, for pity's sake, leave this helpless youth who, after all, was +the son of his old friend and the possessor of such enormous wealth, +to the caprice of fate and the designs of rogues. During the few +days he spent in Moscow after the death of Count Bezukhov, he would +call Pierre, or go to him himself, and tell him what ought to be +done in a tone of weariness and assurance, as if he were adding +every time: "You know I am overwhelmed with business and it is +purely out of charity that I trouble myself about you, and you also +know quite well that what I propose is the only thing possible." + +"Well, my dear fellow, tomorrow we are off at last," said Prince +Vasili one day, closing his eyes and fingering Pierre's elbow, +speaking as if he were saying something which had long since been +agreed upon and could not now be altered. "We start tomorrow and I'm +giving you a place in my carriage. I am very glad. All our important +business here is now settled, and I ought to have been off long ago. +Here is something I have received from the chancellor. I asked him for +you, and you have been entered in the diplomatic corps and made a +Gentleman of the Bedchamber. The diplomatic career now lies open +before you." + +Notwithstanding the tone of wearied assurance with which these words +were pronounced, Pierre, who had so long been considering his +career, wished to make some suggestion. But Prince Vasili +interrupted him in the special deep cooing tone, precluding the +possibility of interrupting his speech, which he used in extreme cases +when special persuasion was needed. + +"Mais, mon cher, I did this for my own sake, to satisfy my +conscience, and there is nothing to thank me for. No one has ever +complained yet of being too much loved; and besides, you are free, you +could throw it up tomorrow. But you will see everything for yourself +when you get to Petersburg. It is high time for you to get away from +these terrible recollections." Prince Vasili sighed. "Yes, yes, my +boy. And my valet can go in your carriage. Ah! I was nearly +forgetting," he added. "You know, mon cher, your father and I had some +accounts to settle, so I have received what was due from the Ryazan +estate and will keep it; you won't require it. We'll go into the +accounts later." + +By "what was due from the Ryazan estate" Prince Vasili meant several +thousand rubles quitrent received from Pierre's peasants, which the +prince had retained for himself. + +In Petersburg, as in Moscow, Pierre found the same atmosphere of +gentleness and affection. He could not refuse the post, or rather +the rank (for he did nothing), that Prince Vasili had procured for +him, and acquaintances, invitations, and social occupations were so +numerous that, even more than in Moscow, he felt a sense of +bewilderment, bustle, and continual expectation of some good, always +in front of him but never attained. + +Of his former bachelor acquaintances many were no longer in +Petersburg. The Guards had gone to the front; Dolokhov had been +reduced to the ranks; Anatole was in the army somewhere in the +provinces; Prince Andrew was abroad; so Pierre had not the opportunity +to spend his nights as he used to like to spend them, or to open his +mind by intimate talks with a friend older than himself and whom he +respected. His whole time was taken up with dinners and balls and +was spent chiefly at Prince Vasili's house in the company of the stout +princess, his wife, and his beautiful daughter Helene. + +Like the others, Anna Pavlovna Scherer showed Pierre the change of +attitude toward him that had taken place in society. + +Formerly in Anna Pavlovna's presence, Pierre had always felt that +what he was saying was out of place, tactless and unsuitable, that +remarks which seemed to him clever while they formed in his mind +became foolish as soon as he uttered them, while on the contrary +Hippolyte's stupidest remarks came out clever and apt. Now +everything Pierre said was charmant. Even if Anna Pavlovna did not say +so, he could see that she wished to and only refrained out of regard +for his modesty. + +In the beginning of the winter of 1805-6 Pierre received one of Anna +Pavlovna's usual pink notes with an invitation to which was added: +"You will find the beautiful Helene here, whom it is always delightful +to see." + +When he read that sentence, Pierre felt for the first time that some +link which other people recognized had grown up between himself and +Helene, and that thought both alarmed him, as if some obligation +were being imposed on him which he could not fulfill, and pleased +him as an entertaining supposition. + +Anna Pavlovna's "At Home" was like the former one, only the +novelty she offered her guests this time was not Mortemart, but a +diplomatist fresh from Berlin with the very latest details of the +Emperor Alexander's visit to Potsdam, and of how the two august +friends had pledged themselves in an indissoluble alliance to uphold +the cause of justice against the enemy of the human race. Anna +Pavlovna received Pierre with a shade of melancholy, evidently +relating to the young man's recent loss by the death of Count Bezukhov +(everyone constantly considered it a duty to assure Pierre that he was +greatly afflicted by the death of the father he had hardly known), and +her melancholy was just like the august melancholy she showed at the +mention of her most august Majesty the Empress Marya Fedorovna. Pierre +felt flattered by this. Anna Pavlovna arranged the different groups in +her drawing room with her habitual skill. The large group, in which +were Prince Vasili and the generals, had the benefit of the +diplomat. Another group was at the tea table. Pierre wished to join +the former, but Anna Pavlovna--who was in the excited condition of a +commander on a battlefield to whom thousands of new and brilliant +ideas occur which there is hardly time to put in action--seeing +Pierre, touched his sleeve with her finger, saying: + +"Wait a bit, I have something in view for you this evening." (She +glanced at Helene and smiled at her.) "My dear Helene, be charitable +to my poor aunt who adores you. Go and keep her company for ten +minutes. And that it will not be too dull, here is the dear count +who will not refuse to accompany you." + +The beauty went to the aunt, but Anna Pavlovna detained Pierre, +looking as if she had to give some final necessary instructions. + +"Isn't she exquisite?" she said to Pierre, pointing to the stately +beauty as she glided away. "And how she carries herself! For so +young a girl, such tact, such masterly perfection of manner! It +comes from her heart. Happy the man who wins her! With her the least +worldly of men would occupy a most brilliant position in society. +Don't you think so? I only wanted to know your opinion," and Anna +Pavlovna let Pierre go. + +Pierre, in reply, sincerely agreed with her as to Helene's +perfection of manner. If he ever thought of Helene, it was just of her +beauty and her remarkable skill in appearing silently dignified in +society. + +The old aunt received the two young people in her corner, but seemed +desirous of hiding her adoration for Helene and inclined rather to +show her fear of Anna Pavlovna. She looked at her niece, as if +inquiring what she was to do with these people. On leaving them, +Anna Pavlovna again touched Pierre's sleeve, saying: "I hope you won't +say that it is dull in my house again," and she glanced at Helene. + +Helene smiled, with a look implying that she did not admit the +possibility of anyone seeing her without being enchanted. The aunt +coughed, swallowed, and said in French that she was very pleased to +see Helene, then she turned to Pierre with the same words of welcome +and the same look. In the middle of a dull and halting conversation, +Helene turned to Pierre with the beautiful bright smile that she +gave to everyone. Pierre was so used to that smile, and it had so +little meaning for him, that he paid no attention to it. The aunt +was just speaking of a collection of snuffboxes that had belonged to +Pierre's father, Count Bezukhov, and showed them her own box. Princess +Helene asked to see the portrait of the aunt's husband on the box lid. + +"That is probably the work of Vinesse," said Pierre, mentioning a +celebrated miniaturist, and he leaned over the table to take the +snuffbox while trying to hear what was being said at the other table. + +He half rose, meaning to go round, but the aunt handed him the +snuffbox, passing it across Helene's back. Helene stooped forward to +make room, and looked round with a smile. She was, as always at +evening parties, wearing a dress such as was then fashionable, cut +very low at front and back. Her bust, which had always seemed like +marble to Pierre, was so close to him that his shortsighted eyes could +not but perceive the living charm of her neck and shoulders, so near +to his lips that he need only have bent his head a little to have +touched them. He was conscious of the warmth of her body, the scent of +perfume, and the creaking of her corset as she moved. He did not see +her marble beauty forming a complete whole with her dress, but all the +charm of her body only covered by her garments. And having once seen +this he could not help being aware it, just as we cannot renew an +illusion we have once seen through. + +"So you have never noticed before how beautiful I am?" Helene seemed +to say. "You had not noticed that I am a woman? Yes, I am a woman +who may belong to anyone--to you too," said her glance. And at that +moment Pierre felt that Helene not only could, but must, be his +wife, and that it could not be otherwise. + +He knew this at that moment as surely as if he had been standing +at the altar with her. How and when this would be he did not know, +he did not even know if it would be a good thing (he even felt, he +knew not why, that it would be a bad thing), but he knew it would +happen. + +Pierre dropped his eyes, lifted them again, and wished once more +to see her as a distant beauty far removed from him, as he had seen +her every day until then, but he could no longer do it. He could +not, any more than a man who has been looking at a tuft of steppe +grass through the mist and taking it for a tree can again take it +for a tree after he has once recognized it to be a tuft of grass. +She was terribly close to him. She already had power over him, and +between them there was no longer any barrier except the barrier of his +own will. + +"Well, I will leave you in your little corner," came Anna Pavlovna's +voice, "I see you are all right there." + +And Pierre, anxiously trying to remember whether he had done +anything reprehensible, looked round with a blush. It seemed to him +that everyone knew what had happened to him as he knew it himself. + +A little later when he went up to the large circle, Anna Pavlovna +said to him: "I hear you are refitting your Petersburg house?" + +This was true. The architect had told him that it was necessary, and +Pierre, without knowing why, was having his enormous Petersburg +house done up. + +"That's a good thing, but don't move from Prince Vasili's. It is +good to have a friend like the prince," she said, smiling at Prince +Vasili. "I know something about that. Don't I? And you are still so +young. You need advice. Don't be angry with me for exercising an old +woman's privilege." + +She paused, as women always do, expecting something after they +have mentioned their age. "If you marry it will be a different thing," +she continued, uniting them both in one glance. Pierre did not look at +Helene nor she at him. But she was just as terribly close to him. He +muttered something and colored. + +When he got home he could not sleep for a long time for thinking +of what had happened. What had happened? Nothing. He had merely +understood that the woman he had known as a child, of whom when her +beauty was mentioned he had said absent-mindedly: "Yes, she's good +looking," he had understood that this woman might belong to him. + +"But she's stupid. I have myself said she is stupid," he thought. +"There is something nasty, something wrong, in the feeling she excites +in me. I have been told that her brother Anatole was in love with +her and she with him, that there was quite a scandal and that that's +why he was sent away. Hippolyte is her brother... Prince Vasili is her +father... It's bad...." he reflected, but while he was thinking this +(the reflection was still incomplete), he caught himself smiling and +was conscious that another line of thought had sprung up, and while +thinking of her worthlessness he was also dreaming of how she would be +his wife, how she would love him become quite different, and how all +he had thought and heard of her might be false. And he again saw her +not as the daughter of Prince Vasili, but visualized her whole body +only veiled by its gray dress. "But no! Why did this thought never +occur to me before?" and again he told himself that it was impossible, +that there would be something unnatural, and as it seemed to him +dishonorable, in this marriage. He recalled her former words and looks +and the words and looks of those who had seen them together. He +recalled Anna Pavlovna's words and looks when she spoke to him about +his house, recalled thousands of such hints from Prince Vasili and +others, and was seized by terror lest he had already, in some way, +bound himself to do something that was evidently wrong and that he +ought not to do. But at the very time he was expressing this +conviction to himself, in another part of his mind her image rose in +all its womanly beauty. + + + + + +CHAPTER II + +In November, 1805, Prince Vasili had to go on a tour of inspection +in four different provinces. He had arranged this for himself so as to +visit his neglected estates at the same time and pick up his son +Anatole where his regiment was stationed, and take him to visit Prince +Nicholas Bolkonski in order to arrange a match for him with the +daughter of that rich old man. But before leaving home and undertaking +these new affairs, Prince Vasili had to settle matters with Pierre, +who, it is true, had latterly spent whole days at home, that is, in +Prince Vasili's house where he was staying, and had been absurd, +excited, and foolish in Helene's presence (as a lover should be), +but had not yet proposed to her. + +"This is all very fine, but things must be settled," said Prince +Vasili to himself, with a sorrowful sigh, one morning, feeling that +Pierre who was under such obligations to him ("But never mind that") +was not behaving very well in this matter. "Youth, frivolity... +well, God be with him," thought he, relishing his own goodness of +heart, "but it must be brought to a head. The day after tomorrow +will be Lelya's name day. I will invite two or three people, and if he +does not understand what he ought to do then it will be my affair- +yes, my affair. I am her father." + +Six weeks after Anna Pavlovna's "At Home" and after the sleepless +night when he had decided that to marry Helene would be a calamity and +that he ought to avoid her and go away, Pierre, despite that decision, +had not left Prince Vasili's and felt with terror that in people's +eyes he was every day more and more connected with her, that it was +impossible for him to return to his former conception of her, that +he could not break away from her, and that though it would be a +terrible thing he would have to unite his fate with hers. He might +perhaps have been able to free himself but that Prince Vasili (who had +rarely before given receptions) now hardly let a day go by without +having an evening party at which Pierre had to be present unless he +wished to spoil the general pleasure and disappoint everyone's +expectation. Prince Vasili, in the rare moments when he was at home, +would take Pierre's hand in passing and draw it downwards, or +absent-mindedly hold out his wrinkled, clean-shaven cheek for Pierre +to kiss and would say: "Till tomorrow," or, "Be in to dinner or I +shall not see you," or, "I am staying in for your sake," and so on. +And though Prince Vasili, when he stayed in (as he said) for +Pierre's sake, hardly exchanged a couple of words with him, Pierre +felt unable to disappoint him. Every day he said to himself one and +the same thing: "It is time I understood her and made up my mind +what she really is. Was I mistaken before, or am I mistaken now? No, +she is not stupid, she is an excellent girl," he sometimes said to +himself "she never makes a mistake, never says anything stupid. She +says little, but what she does say is always clear and simple, so +she is not stupid. She never was abashed and is not abashed now, so +she cannot be a bad woman!" He had often begun to make reflections +or think aloud in her company, and she had always answered him +either by a brief but appropriate remark--showing that it did not +interest her--or by a silent look and smile which more palpably than +anything else showed Pierre her superiority. She was right in +regarding all arguments as nonsense in comparison with that smile. + +She always addressed him with a radiantly confiding smile meant +for him alone, in which there was something more significant than in +the general smile that usually brightened her face. Pierre knew that +everyone was waiting for him to say a word and cross a certain line, +and he knew that sooner or later he would step across it, but an +incomprehensible terror seized him at the thought of that dreadful +step. A thousand times during that month and a half while he felt +himself drawn nearer and nearer to that dreadful abyss, Pierre said to +himself: "What am I doing? I need resolution. Can it be that I have +none?" + +He wished to take a decision, but felt with dismay that in this +matter he lacked that strength of will which he had known in himself +and really possessed. Pierre was one of those who are only strong when +they feel themselves quite innocent, and since that day when he was +overpowered by a feeling of desire while stooping over the snuffbox at +Anna Pavlovna's, an unacknowledged sense of the guilt of that desire +paralyzed his will. + +On Helene's name day, a small party of just their own people--as his +wife said--met for supper at Prince Vasili's. All these friends and +relations had been given to understand that the fate of the young girl +would be decided that evening. The visitors were seated at supper. +Princess Kuragina, a portly imposing woman who had once been handsome, +was sitting at the head of the table. On either side of her sat the +more important guests--an old general and his wife, and Anna +Pavlovna Scherer. At the other end sat the younger and less +important guests, and there too sat the members of the family, and +Pierre and Helene, side by side. Prince Vasili was not having any +supper: he went round the table in a merry mood, sitting down now by +one, now by another, of the guests. To each of them he made some +careless and agreeable remark except to Pierre and Helene, whose +presence he seemed not to notice. He enlivened the whole party. The +wax candles burned brightly, the silver and crystal gleamed, so did +the ladies' toilets and the gold and silver of the men's epaulets; +servants in scarlet liveries moved round the table, the clatter of +plates, knives, and glasses mingled with the animated hum of several +conversations. At one end of the table, the old chamberlain was +heard assuring an old baroness that he loved her passionately, at +which she laughed; at the other could be heard the story of the +misfortunes of some Mary Viktorovna or other. At the center of the +table, Prince Vasili attracted everybody's attention. With a facetious +smile on his face, he was telling the ladies about last Wednesday's +meeting of the Imperial Council, at which Sergey Kuzmich +Vyazmitinov, the new military governor general of Petersburg, had +received and read the then famous rescript of the Emperor Alexander +from the army to Sergey Kuzmich, in which the Emperor said that he was +receiving from all sides declarations of the people's loyalty, that +the declaration from Petersburg gave him particular pleasure, and that +he was proud to be at the head of such a nation and would endeavor +to be worthy of it. This rescript began with the words: "Sergey +Kuzmich, From all sides reports reach me," etc. + +"Well, and so he never got farther than: 'Sergey Kuzmich'?" asked +one of the ladies. + +"Exactly, not a hair's breadth farther," answered Prince Vasili, +laughing, "'Sergey Kuzmich... From all sides... From all sides... +Sergey Kuzmich...' Poor Vyazmitinov could not get any farther! He +began the rescript again and again, but as soon as he uttered 'Sergey' +he sobbed, 'Kuz-mi-ch,' tears, and 'From all sides' was smothered in +sobs and he could get no farther. And again his handkerchief, and +again: 'Sergey Kuzmich, From all sides,'... and tears, till at last +somebody else was asked to read it." + +"Kuzmich... From all sides... and then tears," someone repeated +laughing. + +"Don't be unkind," cried Anna Pavlovna from her end of the table +holding up a threatening finger. "He is such a worthy and excellent +man, our dear Vyazmitinov...." + +Everybody laughed a great deal. At the head of the table, where +the honored guests sat, everyone seemed to be in high spirits and +under the influence of a variety of exciting sensations. Only Pierre +and Helene sat silently side by side almost at the bottom of the +table, a suppressed smile brightening both their faces, a smile that +had nothing to do with Sergey Kuzmich--a smile of bashfulness at their +own feelings. But much as all the rest laughed, talked, and joked, +much as they enjoyed their Rhine wine, saute, and ices, and however +they avoided looking at the young couple, and heedless and unobservant +as they seemed of them, one could feel by the occasional glances +they gave that the story about Sergey Kuzmich, the laughter, and the +food were all a pretense, and that the whole attention of that company +was directed to--Pierre and Helene. Prince Vasili mimicked the sobbing +of Sergey Kuzmich and at the same time his eyes glanced toward his +daughter, and while he laughed the expression on his face clearly +said: "Yes... it's getting on, it will all be settled today." Anna +Pavlovna threatened him on behalf of "our dear Vyazmitinov," and in +her eyes, which, for an instant, glanced at Pierre, Prince Vasili read +a congratulation on his future son-in-law and on his daughter's +happiness. The old princess sighed sadly as she offered some wine to +the old lady next to her and glanced angrily at her daughter, and +her sigh seemed to say: "Yes, there's nothing left for you and me +but to sip sweet wine, my dear, now that the time has come for these +young ones to be thus boldly, provocatively happy." "And what nonsense +all this is that I am saying!" thought a diplomatist, glancing at +the happy faces of the lovers. "That's happiness!" + +Into the insignificant, trifling, and artificial interests uniting +that society had entered the simple feeling of the attraction of a +healthy and handsome young man and woman for one another. And this +human feeling dominated everything else and soared above all their +affected chatter. Jests fell flat, news was not interesting, and the +animation was evidently forced. Not only the guests but even the +footmen waiting at table seemed to feel this, and they forgot their +duties as they looked at the beautiful Helene with her radiant face +and at the red, broad, and happy though uneasy face of Pierre. It +seemed as if the very light of the candles was focused on those two +happy faces alone. + +Pierre felt that he was the center of it all, and this both pleased +and embarrassed him. He was like a man entirely absorbed in some +occupation. He did not see, hear, or understand anything clearly. Only +now and then detached ideas and impressions from the world of +reality shot unexpectedly through his mind. + +"So it is all finished!" he thought. "And how has it all happened? +How quickly! Now I know that not because of her alone, nor of myself +alone, but because of everyone, it must inevitably come about. They +are all expecting it, they are so sure that it will happen that I +cannot, I cannot, disappoint them. But how will it be? I do not +know, but it will certainly happen!" thought Pierre, glancing at those +dazzling shoulders close to his eyes. + +Or he would suddenly feel ashamed of he knew not what. He felt it +awkward to attract everyone's attention and to be considered a lucky +man and, with his plain face, to be looked on as a sort of Paris +possessed of a Helen. "But no doubt it always is and must be so!" he +consoled himself. "And besides, what have I done to bring it about? +How did it begin? I traveled from Moscow with Prince Vasili. Then +there was nothing. So why should I not stay at his house? Then I +played cards with her and picked up her reticule and drove out with +her. How did it begin, when did it all come about?" And here he was +sitting by her side as her betrothed, seeing, hearing, feeling her +nearness, her breathing, her movements, her beauty. Then it would +suddenly seem to him that it was not she but he was so unusually +beautiful, and that that was why they all looked so at him, and +flattered by this general admiration he would expand his chest, +raise his head, and rejoice at his good fortune. Suddenly he heard a +familiar voice repeating something to him a second time. But Pierre +was so absorbed that he did not understand what was said. + +"I am asking you when you last heard from Bolkonski," repeated +Prince Vasili a third time. "How absent-minded you are, my dear +fellow." + +Prince Vasili smiled, and Pierre noticed that everyone was smiling +at him and Helene. "Well, what of it, if you all know it?" thought +Pierre. "What of it? It's the truth!" and he himself smiled his gentle +childlike smile, and Helene smiled too. + +"When did you get the letter? Was it from Olmutz?" repeated Prince +Vasili, who pretended to want to know this in order to settle a +dispute. + +"How can one talk or think of such trifles?" thought Pierre. + +"Yes, from Olmutz," he answered, with a sigh. + +After supper Pierre with his partner followed the others into the +drawing room. The guests began to disperse, some without taking +leave of Helene. Some, as if unwilling to distract her from an +important occupation, came up to her for a moment and made haste to go +away, refusing to let her see them off. The diplomatist preserved a +mournful silence as he left the drawing room. He pictured the vanity +of his diplomatic career in comparison with Pierre's happiness. The +old general grumbled at his wife when she asked how his leg was. +"Oh, the old fool," he thought. "That Princess Helene will be +beautiful still when she's fifty." + +"I think I may congratulate you," whispered Anna Pavlovna to the old +princess, kissing her soundly. "If I hadn't this headache I'd have +stayed longer." + +The old princess did not reply, she was tormented by jealousy of her +daughter's happiness. + +While the guests were taking their leave Pierre remained for a +long time alone with Helene in the little drawing room where they were +sitting. He had often before, during the last six weeks, remained +alone with her, but had never spoken to her of love. Now he felt +that it was inevitable, but he could not make up his mind to take +the final step. He felt ashamed; he felt that he was occupying someone +else's place here beside Helene. "This happiness is not for you," some +inner voice whispered to him. "This happiness is for those who have +not in them what there is in you." + +But, as he had to say something, he began by asking her whether +she was satisfied with the party. She replied in her usual simple +manner that this name day of hers had been one of the pleasantest +she had ever had. + +Some of the nearest relatives had not yet left. They were sitting in +the large drawing room. Prince Vasili came up to Pierre with languid +footsteps. Pierre rose and said it was getting late. Prince Vasili +gave him a look of stern inquiry, as though what Pierre had just +said was so strange that one could not take it in. But then the +expression of severity changed, and he drew Pierre's hand downwards, +made him sit down, and smiled affectionately. + +"Well, Lelya?" he asked, turning instantly to his daughter and +addressing her with the careless tone of habitual tenderness natural +to parents who have petted their children from babyhood, but which +Prince Vasili had only acquired by imitating other parents. + +And he again turned to Pierre. + +"Sergey Kuzmich--From all sides-" he said, unbuttoning the top +button of his waistcoat. + +Pierre smiled, but his smile showed that he knew it was not the +story about Sergey Kuzmich that interested Prince Vasili just then, +and Prince Vasili saw that Pierre knew this. He suddenly muttered +something and went away. It seemed to Pierre that even the prince +was disconcerted. The sight of the discomposure of that old man of the +world touched Pierre: he looked at Helene and she too seemed +disconcerted, and her look seemed to say: "Well, it is your own +fault." + +"The step must be taken but I cannot, I cannot!" thought Pierre, and +he again began speaking about indifferent matters, about Sergey +Kuzmich, asking what the point of the story was as he had not heard it +properly. Helene answered with a smile that she too had missed it. + +When Prince Vasili returned to the drawing room, the princess, his +wife, was talking in low tones to the elderly lady about Pierre. + +"Of course, it is a very brilliant match, but happiness, my dear..." + +"Marriages are made in heaven," replied the elderly lady. + +Prince Vasili passed by, seeming not to hear the ladies, and sat +down on a sofa in a far corner of the room. He closed his eyes and +seemed to be dozing. His head sank forward and then he roused himself. + +"Aline," he said to his wife, "go and see what they are about." + +The princess went up to the door, passed by it with a dignified +and indifferent air, and glanced into the little drawing room. +Pierre and Helene still sat talking just as before. + +"Still the same," she said to her husband. + +Prince Vasili frowned, twisting his mouth, his cheeks quivered and +his face assumed the coarse, unpleasant expression peculiar to him. +Shaking himself, he rose, threw back his head, and with resolute steps +went past the ladies into the little drawing room. With quick steps he +went joyfully up to Pierre. His face was so unusually triumphant +that Pierre rose in alarm on seeing it. + +"Thank God!" said Prince Vasili. "My wife has told me everything!" +(He put one arm around Pierre and the other around his daughter.)--"My +dear boy... Lelya... I am very pleased." (His voice trembled.) "I +loved your father... and she will make you a good wife... God bless +you!..." + +He embraced his daughter, and then again Pierre, and kissed him with +his malodorous mouth. Tears actually moistened his cheeks. + +"Princess, come here!" he shouted. + +The old princess came in and also wept. The elderly lady was using +her handkerchief too. Pierre was kissed, and he kissed the beautiful +Helene's hand several times. After a while they were left alone again. + +"All this had to be and could not be otherwise," thought Pierre, "so +it is useless to ask whether it is good or bad. It is good because +it's definite and one is rid of the old tormenting doubt." Pierre held +the hand of his betrothed in silence, looking at her beautiful bosom +as it rose and fell. + +"Helene!" he said aloud and paused. + +"Something special is always said in such cases," he thought, but +could not remember what it was that people say. He looked at her face. +She drew nearer to him. Her face flushed. + +"Oh, take those off... those..." she said, pointing to his +spectacles. + +Pierre took them off, and his eyes, besides the strange look eyes +have from which spectacles have just been removed, had also a +frightened and inquiring look. He was about to stoop over her hand and +kiss it, but with a rapid, almost brutal movement of her head, she +intercepted his lips and met them with her own. Her face struck +Pierre, by its altered, unpleasantly excited expression. + +"It is too late now, it's done; besides I love her," thought Pierre. + +"Je vous aime!"* he said, remembering what has to be said at such +moments: but his words sounded so weak that he felt ashamed of +himself. + + +*"I love you." + + +Six weeks later he was married, and settled in Count Bezukhov's +large, newly furnished Petersburg house, the happy possessor, as +people said, of a wife who was a celebrated beauty and of millions +of money. + + + + + +CHAPTER III + + +Old Prince Nicholas Bolkonski received a letter from Prince Vasili +in November, 1805, announcing that he and his son would be paying +him a visit. "I am starting on a journey of inspection, and of +course I shall think nothing of an extra seventy miles to come and see +you at the same time, my honored benefactor," wrote Prince Vasili. "My +son Anatole is accompanying me on his way to the army, so I hope you +will allow him personally to express the deep respect that, +emulating his father, he feels for you." + +"It seems that there will be no need to bring Mary out, suitors +are coming to us of their own accord," incautiously remarked the +little princess on hearing the news. + +Prince Nicholas frowned, but said nothing. + +A fortnight after the letter Prince Vasili's servants came one +evening in advance of him, and he and his son arrived next day. + +Old Bolkonski had always had a poor opinion of Prince Vasili's +character, but more so recently, since in the new reigns of Paul and +Alexander Prince Vasili had risen to high position and honors. And +now, from the hints contained in his letter and given by the little +princess, he saw which way the wind was blowing, and his low opinion +changed into a feeling of contemptuous ill will. He snorted whenever +he mentioned him. On the day of Prince Vasili's arrival, Prince +Bolkonski was particularly discontented and out of temper. Whether +he was in a bad temper because Prince Vasili was coming, or whether +his being in a bad temper made him specially annoyed at Prince +Vasili's visit, he was in a bad temper, and in the morning Tikhon +had already advised the architect not to go to the prince with his +report. + +"Do you hear how he's walking?" said Tikhon, drawing the architect's +attention to the sound of the prince's footsteps. "Stepping flat on +his heels--we know what that means...." + +However, at nine o'clock the prince, in his velvet coat with a sable +collar and cap, went out for his usual walk. It had snowed the day +before and the path to the hothouse, along which the prince was in the +habit of walking, had been swept: the marks of the broom were still +visible in the snow and a shovel had been left sticking in one of +the soft snowbanks that bordered both sides of the path. The prince +went through the conservatories, the serfs' quarters, and the +outbuildings, frowning and silent. + +"Can a sleigh pass?" he asked his overseer, a venerable man, +resembling his master in manners and looks, who was accompanying him +back to the house. + +"The snow is deep. I am having the avenue swept, your honor." + +The prince bowed his head and went up to the porch. "God be +thanked," thought the overseer, "the storm has blown over!" + +"It would have been hard to drive up, your honor," he added. "I +heard, your honor, that a minister is coming to visit your honor." + +The prince turned round to the overseer and fixed his eyes on him, +frowning. + +"What? A minister? What minister? Who gave orders?" he said in his +shrill, harsh voice. "The road is not swept for the princess my +daughter, but for a minister! For me, there are no ministers!" + +"Your honor, I thought..." + +"You thought!" shouted the prince, his words coming more and more +rapidly and indistinctly. "You thought!... Rascals! Blackgaurds!... +I'll teach you to think!" and lifting his stick he swung it and +would have hit Alpatych, the overseer, had not the latter +instinctively avoided the blow. "Thought... Blackguards..." shouted +the prince rapidly. + +But although Alpatych, frightened at his own temerity in avoiding +the stroke, came up to the prince, bowing his bald head resignedly +before him, or perhaps for that very reason, the prince, though he +continued to shout: "Blackgaurds!... Throw the snow back on the road!" +did not lift his stick again but hurried into the house. + +Before dinner, Princess Mary and Mademoiselle Bourienne, who knew +that the prince was in a bad humor, stood awaiting him; Mademoiselle +Bourienne with a radiant face that said: "I know nothing, I am the +same as usual," and Princess Mary pale, frightened, and with +downcast eyes. What she found hardest to bear was to know that on such +occasions she ought to behave like Mademoiselle Bourienne, but could +not. She thought: "If I seem not to notice he will think that I do not +sympathize with him; if I seem sad and out of spirits myself, he +will say (as he has done before) that I'm in the dumps." + +The prince looked at his daughter's frightened face and snorted. + +"Fool... or dummy!" he muttered. + +"And the other one is not here. They've been telling tales," he +thought--referring to the little princess who was not in the dining +room. + +"Where is the princess?" he asked. "Hiding?" + +"She is not very well," answered Mademoiselle Bourienne with a +bright smile, "so she won't come down. It is natural in her state." + +"Hm! Hm!" muttered the prince, sitting down. + +His plate seemed to him not quite clean, and pointing to a spot he +flung it away. Tikhon caught it and handed it to a footman. The little +princess was not unwell, but had such an overpowering fear of the +prince that, hearing he was in a bad humor, she had decided not to +appear. + +"I am afraid for the baby," she said to Mademoiselle Bourienne: +"Heaven knows what a fright might do." + +In general at Bald Hills the little princess lived in constant fear, +and with a sense of antipathy to the old prince which she did not +realize because the fear was so much the stronger feeling. The +prince reciprocated this antipathy, but it was overpowered by his +contempt for her. When the little princess had grown accustomed to +life at Bald Hills, she took a special fancy to Mademoiselle +Bourienne, spent whole days with her, asked her to sleep in her +room, and often talked with her about the old prince and criticized +him. + +"So we are to have visitors, mon prince?" remarked Mademoiselle +Bourienne, unfolding her white napkin with her rosy fingers. "His +Excellency Prince Vasili Kuragin and his son, I understand?" she +said inquiringly. + +"Hm!--his excellency is a puppy.... I got him his appointment in the +service," said the prince disdainfully. "Why his son is coming I don't +understand. Perhaps Princess Elizabeth and Princess Mary know. I don't +want him." (He looked at his blushing daughter.) "Are you unwell +today? Eh? Afraid of the 'minister' as that idiot Alpatych called +him this morning?" + +"No, mon pere." + +Though Mademoiselle Bourienne had been so unsuccessful in her choice +of a subject, she did not stop talking, but chattered about the +conservatories and the beauty of a flower that had just opened, and +after the soup the prince became more genial. + +After dinner, he went to see his daughter-in-law. The little +princess was sitting at a small table, chattering with Masha, her +maid. She grew pale on seeing her father-in-law. + +She was much altered. She was now plain rather than pretty. Her +cheeks had sunk, her lip was drawn up, and her eyes drawn down. + +"Yes, I feel a kind of oppression," she said in reply to the +prince's question as to how she felt. + +"Do you want anything?" + +"No, merci, mon pere." + +"Well, all right, all right." + +He left the room and went to the waiting room where Alpatych stood +with bowed head. + +"Has the snow been shoveled back?" + +"Yes, your excellency. Forgive me for heaven's sake... It was only +my stupidity." + +"All right, all right," interrupted the prince, and laughing his +unnatural way, he stretched out his hand for Alpatych to kiss, and +then proceeded to his study. + +Prince Vasili arrived that evening. He was met in the avenue by +coachmen and footmen, who, with loud shouts, dragged his sleighs up to +one of the lodges over the road purposely laden with snow. + +Prince Vasili and Anatole had separate rooms assigned to them. + +Anatole, having taken off his overcoat, sat with arms akimbo +before a table on a corner of which he smilingly and absent-mindedly +fixed his large and handsome eyes. He regarded his whole life as a +continual round of amusement which someone for some reason had to +provide for him. And he looked on this visit to a churlish old man and +a rich and ugly heiress in the same way. All this might, he thought, +turn out very well and amusingly. "And why not marry her if she really +has so much money? That never does any harm," thought Anatole. + +He shaved and scented himself with the care and elegance which had +become habitual to him and, his handsome head held high, entered his +father's room with the good-humored and victorious air natural to him. +Prince Vasili's two valets were busy dressing him, and he looked round +with much animation and cheerfully nodded to his son as the latter +entered, as if to say: "Yes, that's how I want you to look." + +"I say, Father, joking apart, is she very hideous?" Anatole asked, +as if continuing a conversation the subject of which had often been +mentioned during the journey. + +"Enough! What nonsense! Above all, try to be respectful and cautious +with the old prince." + +"If he starts a row I'll go away," said Prince Anatole. "I can't +bear those old men! Eh?" + +"Remember, for you everything depends on this." + +In the meantime, not only was it known in the maidservants' rooms +that the minister and his son had arrived, but the appearance of +both had been minutely described. Princess Mary was sitting alone in +her room, vainly trying to master her agitation. + +"Why did they write, why did Lise tell me about it? It can never +happen!" she said, looking at herself in the glass. "How shall I enter +the drawing room? Even if I like him I can't now be myself with +him." The mere thought of her father's look filled her with terror. +The little princess and Mademoiselle Bourienne had already received +from Masha, the lady's maid, the necessary report of how handsome +the minister's son was, with his rosy cheeks and dark eyebrows, and +with what difficulty the father had dragged his legs upstairs while +the son had followed him like an eagle, three steps at a time. +Having received this information, the little princess and Mademoiselle +Bourienne, whose chattering voices had reached her from the +corridor, went into Princess Mary's room. + +"You know they've come, Marie?" said the little princess, waddling +in, and sinking heavily into an armchair. + +She was no longer in the loose gown she generally wore in the +morning, but had on one of her best dresses. Her hair was carefully +done and her face was animated, which, however, did not conceal its +sunken and faded outlines. Dressed as she used to be in Petersburg +society, it was still more noticeable how much plainer she had become. +Some unobtrusive touch had been added to Mademoiselle Bourienne's +toilet which rendered her fresh and pretty face yet more attractive. + +"What! Are you going to remain as you are, dear princess?" she +began. "They'll be announcing that the gentlemen are in the drawing +room and we shall have to go down, and you have not smartened yourself +up at all!" + +The little princess got up, rang for the maid, and hurriedly and +merrily began to devise and carry out a plan of how Princess Mary +should be dressed. Princess Mary's self-esteem was wounded by the fact +that the arrival of a suitor agitated her, and still more so by both +her companions' not having the least conception that it could be +otherwise. To tell them that she felt ashamed for herself and for them +would be to betray her agitation, while to decline their offers to +dress her would prolong their banter and insistence. She flushed, +her beautiful eyes grew dim, red blotches came on her face, and it +took on the unattractive martyrlike expression it so often wore, as +she submitted herself to Mademoiselle Bourienne and Lise. Both these +women quite sincerely tried to make her look pretty. She was so +plain that neither of them could think of her as a rival, so they +began dressing her with perfect sincerity, and with the naive and firm +conviction women have that dress can make a face pretty. + +"No really, my dear, this dress is not pretty," said Lise, looking +sideways at Princess Mary from a little distance. "You have a maroon +dress, have it fetched. Really! You know the fate of your whole life +may be at stake. But this one is too light, it's not becoming!" + +It was not the dress, but the face and whole figure of Princess Mary +that was not pretty, but neither Mademoiselle Bourienne nor the little +princess felt this; they still thought that if a blue ribbon were +placed in the hair, the hair combed up, and the blue scarf arranged +lower on the best maroon dress, and so on, all would be well. They +forgot that the frightened face and the figure could not be altered, +and that however they might change the setting and adornment of that +face, it would still remain piteous and plain. After two or three +changes to which Princess Mary meekly submitted, just as her hair +had been arranged on the top of her head (a style that quite altered +and spoiled her looks) and she had put on a maroon dress with a +pale-blue scarf, the little princess walked twice round her, now +adjusting a fold of the dress with her little hand, now arranging +the scarf and looking at her with her head bent first on one side +and then on the other. + +"No, it will not do," she said decidedly, clasping her hands. "No, +Mary, really this dress does not suit you. I prefer you in your little +gray everyday dress. Now please, do it for my sake. Katie," she said +to the maid, "bring the princess her gray dress, and you'll see, +Mademoiselle Bourienne, how I shall arrange it," she added, smiling +with a foretaste of artistic pleasure. + +But when Katie brought the required dress, Princess Mary remained +sitting motionless before the glass, looking at her face, and saw in +the mirror her eyes full of tears and her mouth quivering, ready to +burst into sobs. + +"Come, dear princess," said Mademoiselle Bourienne, "just one more +little effort." + +The little princess, taking the dress from the maid, came up to +Princess Mary. + +"Well, now we'll arrange something quite simple and becoming," she +said. + +The three voices, hers, Mademoiselle Bourienne's, and Katie's, who +was laughing at something, mingled in a merry sound, like the chirping +of birds. + +"No, leave me alone," said Princess Mary. + +Her voice sounded so serious and so sad that the chirping of the +birds was silenced at once. They looked at the beautiful, large, +thoughtful eyes full of tears and of thoughts, gazing shiningly and +imploringly at them, and understood that it was useless and even cruel +to insist. + +"At least, change your coiffure," said the little princess. +"Didn't I tell you," she went on, turning reproachfully to +Mademoiselle Bourienne, "Mary's is a face which such a coiffure does +not suit in the least. Not in the least! Please change it." + +"Leave me alone, please leave me alone! It is all quite the same +to me," answered a voice struggling with tears. + +Mademoiselle Bourienne and the little princess had to own to +themselves that Princess Mary in this guise looked very plain, worse +than usual, but it was too late. She was looking at them with an +expression they both knew, an expression thoughtful and sad. This +expression in Princess Mary did not frighten them (she never +inspired fear in anyone), but they knew that when it appeared on her +face, she became mute and was not to be shaken in her determination. + +"You will change it, won't you?" said Lise. And as Princess Mary +gave no answer, she left the room. + +Princess Mary was left alone. She did not comply with Lise's +request, she not only left her hair as it was, but did not even look +in her glass. Letting her arms fall helplessly, she sat with +downcast eyes and pondered. A husband, a man, a strong dominant and +strangely attractive being rose in her imagination, and carried her +into a totally different happy world of his own. She fancied a +child, her own--such as she had seen the day before in the arms of her +nurse's daughter--at her own breast, the husband standing by and +gazing tenderly at her and the child. "But no, it is impossible, I +am too ugly," she thought. + +"Please come to tea. The prince will be out in a moment," came the +maid's voice at the door. + +She roused herself, and felt appalled at what she had been thinking, +and before going down she went into the room where the icons hung and, +her eyes fixed on the dark face of a large icon of the Saviour lit +by a lamp, she stood before it with folded hands for a few moments. +A painful doubt filled her soul. Could the joy of love, of earthly +love for a man, be for her? In her thoughts of marriage Princess +Mary dreamed of happiness and of children, but her strongest, most +deeply hidden longing was for earthly love. The more she tried to hide +this feeling from others and even from herself, the stronger it +grew. "O God," she said, "how am I to stifle in my heart these +temptations of the devil? How am I to renounce forever these vile +fancies, so as peacefully to fulfill Thy will?" And scarcely had she +put that question than God gave her the answer in her own heart. +"Desire nothing for thyself, seek nothing, be not anxious or +envious. Man's future and thy own fate must remain hidden from thee, +but live so that thou mayest be ready for anything. If it be God's +will to prove thee in the duties of marriage, be ready to fulfill +His will." With this consoling thought (but yet with a hope for the +fulfillment of her forbidden earthly longing) Princess Mary sighed, +and having crossed herself went down, thinking neither of her gown and +coiffure nor of how she would go in nor of what she would say. What +could all that matter in comparison with the will of God, without +Whose care not a hair of man's head can fall? + + + + + +CHAPTER IV + + +When Princess Mary came down, Prince Vasili and his son were already +in the drawing room, talking to the little princess and Mademoiselle +Bourienne. When she entered with her heavy step, treading on her +heels, the gentlemen and Mademoiselle Bourienne rose and the little +princess, indicating her to the gentlemen, said: "Voila Marie!" +Princess Mary saw them all and saw them in detail. She saw Prince +Vasili's face, serious for an instant at the sight of her, but +immediately smiling again, and the little princess curiously noting +the impression "Marie" produced on the visitors. And she saw +Mademoiselle Bourienne, with her ribbon and pretty face, and her +unusually animated look which was fixed on him, but him she could +not see, she only saw something large, brilliant, and handsome +moving toward her as she entered the room. Prince Vasili approached +first, and she kissed the bold forehead that bent over her hand and +answered his question by saying that, on the contrary, she +remembered him quite well. Then Anatole came up to her. She still +could not see him. She only felt a soft hand taking hers firmly, and +she touched with her lips a white forehead, over which was beautiful +light-brown hair smelling of pomade. When she looked up at him she was +struck by his beauty. Anatole stood with his right thumb under a +button of his uniform, his chest expanded and his back drawn in, +slightly swinging one foot, and, with his head a little bent, looked +with beaming face at the princess without speaking and evidently not +thinking about her at all. Anatole was not quick-witted, nor ready +or eloquent in conversation, but he had the faculty, so invaluable +in society, of composure and imperturbable self-possession. If a man +lacking in self-confidence remains dumb on a first introduction and +betrays a consciousness of the impropriety of such silence and an +anxiety to find something to say, the effect is bad. But Anatole was +dumb, swung his foot, and smilingly examined the princess' hair. It +was evident that he could be silent in this way for a very long +time. "If anyone finds this silence inconvenient, let him talk, but +I don't want to," he seemed to say. Besides this, in his behavior to +women Anatole had a manner which particularly inspires in them +curiosity, awe, and even love--a supercilious consciousness of his own +superiority. It was was as if he said to them: "I know you, I know +you, but why should I bother about you? You'd be only too glad, of +course." Perhaps he did not really think this when he met women- +even probably he did not, for in general he thought very little--but +his looks and manner gave that impression. The princess felt this, and +as if wishing to show him that she did not even dare expect to +interest him, she turned to his father. The conversation was general +and animated, thanks to Princess Lise's voice and little downy lip +that lifted over her white teeth. She met Prince Vasili with that +playful manner often employed by lively chatty people, and +consisting in the assumption that between the person they so address +and themselves there are some semi-private, long-established jokes and +amusing reminiscences, though no such reminiscences really exist--just +as none existed in this case. Prince Vasili readily adopted her tone +and the little princess also drew Anatole, whom she hardly knew, +into these amusing recollections of things that had never occurred. +Mademoiselle Bourienne also shared them and even Princess Mary felt +herself pleasantly made to share in these merry reminiscences. + +"Here at least we shall have the benefit of your company all to +ourselves, dear prince," said the little princess (of course, in +French) to Prince Vasili. "It's not as at Annette's* receptions +where you always ran away; you remember cette chere Annette!" + + +*Anna Pavlovna. + +"Ah, but you won't talk politics to me like Annette!" + +"And our little tea table?" + +"Oh, yes!" + +"Why is it you were never at Annette's?" the little princess asked +Anatole. "Ah, I know, I know," she said with a sly glance, "your +brother Hippolyte told me about your goings on. Oh!" and she shook her +finger at him, "I have even heard of your doings in Paris!" + +"And didn't Hippolyte tell you?" asked Prince Vasili, turning to his +son and seizing the little princess' arm as if she would have run away +and he had just managed to catch her, "didn't he tell you how he +himself was pining for the dear princess, and how she showed him the +door? Oh, she is a pearl among women, Princess," he added, turning +to Princess Mary. + +When Paris was mentioned, Mademoiselle Bourienne for her part seized +the opportunity of joining in the general current of recollections. + +She took the liberty of inquiring whether it was long since +Anatole had left Paris and how he had liked that city. Anatole +answered the Frenchwoman very readily and, looking at her with a +smile, talked to her about her native land. When he saw the pretty +little Bourienne, Anatole came to the conclusion that he would not +find Bald Hills dull either. "Not at all bad!" he thought, examining +her, "not at all bad, that little companion! I hope she will bring her +along with her when we're married, la petite est gentille."* + + +*The little one is charming. + + +The old prince dressed leisurely in his study, frowning and +considering what he was to do. The coming of these visitors annoyed +him. "What are Prince Vasili and that son of his to me? Prince +Vasili is a shallow braggart and his son, no doubt, is a fine +specimen," he grumbled to himself. What angered him was that the +coming of these visitors revived in his mind an unsettled question +he always tried to stifle, one about which he always deceived himself. +The question was whether he could ever bring himself to part from +his daughter and give her to a husband. The prince never directly +asked himself that question, knowing beforehand that he would have +to answer it justly, and justice clashed not only with his feelings +but with the very possibility of life. Life without Princess Mary, +little as he seemed to value her, was unthinkable to him. "And why +should she marry?" he thought. "To be unhappy for certain. There's +Lise, married to Andrew--a better husband one would think could hardly +be found nowadays--but is she contented with her lot? And who would +marry Marie for love? Plain and awkward! They'll take her for her +connections and wealth. Are there no women living unmarried, and +even the happier for it?" So thought Prince Bolkonski while +dressing, and yet the question he was always putting off demanded an +immediate answer. Prince Vasili had brought his son with the evident +intention of proposing, and today or tomorrow he would probably ask +for an answer. His birth and position in society were not bad. +"Well, I've nothing against it," the prince said to himself, "but he +must be worthy of her. And that is what we shall see." + +"That is what we shall see! That is what we shall see!" he added +aloud. + +He entered the drawing room with his usual alert step, glancing +rapidly round the company. He noticed the change in the little +princess' dress, Mademoiselle Bourienne's ribbon, Princess Mary's +unbecoming coiffure, Mademoiselle Bourienne's and Anatole's smiles, +and the loneliness of his daughter amid the general conversation. "Got +herself up like a fool!" he thought, looking irritably at her. "She is +shameless, and he ignores her!" + +He went straight up to Prince Vasili. + +"Well! How d'ye do? How d'ye do? Glad to see you!" + +"Friendship laughs at distance," began Prince Vasili in his usual +rapid, self-confident, familiar tone. "Here is my second son; please +love and befriend him." + +Prince Bolkonski surveyed Anatole. + +"Fine young fellow! Fine young fellow!" he said. "Well, come and +kiss me," and he offered his cheek. + +Anatole kissed the old man, and looked at him with curiosity and +perfect composure, waiting for a display of the eccentricities his +father had told him to expect. + +Prince Bolkonski sat down in his usual place in the corner of the +sofa and, drawing up an armchair for Prince Vasili, pointed to it +and began questioning him about political affairs and news. He +seemed to listen attentively to what Prince Vasili said, but kept +glancing at Princess Mary. + +"And so they are writing from Potsdam already?" he said, repeating +Prince Vasili's last words. Then rising, he suddenly went up to his +daughter. + +"Is it for visitors you've got yourself up like that, eh?" said +he. "Fine, very fine! You have done up your hair in this new way for +the visitors, and before the visitors I tell you that in future you +are never to dare to change your way of dress without my consent." + +"It was my fault, mon pere," interceded the little princess, with +a blush. + +"You must do as you please," said Prince Bolkonski, bowing to his +daughter-in-law, "but she need not make a fool of herself, she's plain +enough as it is." + +And he sat down again, paying no more attention to his daughter, who +was reduced to tears. + +"On the contrary, that coiffure suits the princess very well," +said Prince Vasili. + +"Now you, young prince, what's your name?" said Prince Bolkonski, +turning to Anatole, "come here, let us talk and get acquainted." + +"Now the fun begins," thought Anatole, sitting down with a smile +beside the old prince. + +"Well, my dear boy, I hear you've been educated abroad, not taught +to read and write by the deacon, like your father and me. Now tell me, +my dear boy, are you serving in the Horse Guards?" asked the old +man, scrutinizing Anatole closely and intently. + +"No, I have been transferred to the line," said Anatole, hardly able +to restrain his laughter. + +"Ah! That's a good thing. So, my dear boy, you wish to serve the +Tsar and the country? It is wartime. Such a fine fellow must serve. +Well, are you off to the front?" + +"No, Prince, our regiment has gone to the front, but I am +attached... what is it I am attached to, Papa?" said Anatole, +turning to his father with a laugh. + +"A splendid soldier, splendid! 'What am I attached to!' Ha, ha, ha!" +laughed Prince Bolkonski, and Anatole laughed still louder. Suddenly +Prince Bolkonski frowned. + +"You may go," he said to Anatole. + +Anatole returned smiling to the ladies. + +"And so you've had him educated abroad, Prince Vasili, haven't you?" +said the old prince to Prince Vasili. + +"I have done my best for him, and I can assure you the education +there is much better than ours." + +"Yes, everything is different nowadays, everything is changed. The +lad's a fine fellow, a fine fellow! Well, come with me now." He took +Prince Vasili's arm and led him to his study. As soon as they were +alone together, Prince Vasili announced his hopes and wishes to the +old prince. + +"Well, do you think I shall prevent her, that I can't part from +her?" said the old prince angrily. "What an idea! I'm ready for it +tomorrow! Only let me tell you, I want to know my son-in-law better. +You know my principles--everything aboveboard? I will ask her tomorrow +in your presence; if she is willing, then he can stay on. He can +stay and I'll see." The old prince snorted. "Let her marry, it's all +the same to me!" he screamed in the same piercing tone as when parting +from his son. + +"I will tell you frankly," said Prince Vasili in the tone of a +crafty man convinced of the futility of being cunning with so +keen-sighted companion. "You know, you see right through people. +Anatole is no genius, but he is an honest, goodhearted lad; an +excellent son or kinsman." + +"All right, all right, we'll see!" + +As always happens when women lead lonely lives for any length of +time without male society, on Anatole's appearance all the three women +of Prince Bolkonski's household felt that their life had not been real +till then. Their powers of reasoning, feeling, and observing +immediately increased tenfold, and their life, which seemed to have +been passed in darkness, was suddenly lit up by a new brightness, full +of significance. + +Princess Mary grew quite unconscious of her face and coiffure. The +handsome open face of the man who might perhaps be her husband +absorbed all her attention. He seemed to her kind, brave, +determined, manly, and magnanimous. She felt convinced of that. +Thousands of dreams of a future family life continually rose in her +imagination. She drove them away and tried to conceal them. + +"But am I not too cold with him?" thought the princess. "I try to be +reserved because in the depth of my soul I feel too near to him +already, but then he cannot know what I think of him and may imagine +that I do not like him." + +And Princess Mary tried, but could not manage, to be cordial to +her new guest. "Poor girl, she's devilish ugly!" thought Anatole. + +Mademoiselle Bourienne, also roused to great excitement by Anatole's +arrival, thought in another way. Of course, she, a handsome young +woman without any definite position, without relations or even a +country, did not intend to devote her life to serving Prince +Bolkonski, to reading aloud to him and being friends with Princess +Mary. Mademoiselle Bourienne had long been waiting for a Russian +prince who, able to appreciate at a glance her superiority to the +plain, badly dressed, ungainly Russian princesses, would fall in +love with her and carry her off; and here at last was a Russian +prince. Mademoiselle Bourienne knew a story, heard from her aunt but +finished in her own way, which she liked to repeat to herself. It +was the story of a girl who had been seduced, and to whom her poor +mother (sa pauvre mere) appeared, and reproached her for yielding to a +man without being married. Mademoiselle Bourienne was often touched to +tears as in imagination she told this story to him, her seducer. And +now he, a real Russian prince, had appeared. He would carry her away +and then sa pauvre mere would appear and he would marry her. So her +future shaped itself in Mademoiselle Bourienne's head at the very time +she was talking to Anatole about Paris. It was not calculation that +guided her (she did not even for a moment consider what she should +do), but all this had long been familiar to her, and now that +Anatole had appeared it just grouped itself around him and she +wished and tried to please him as much as possible. + +The little princess, like an old war horse that hears the trumpet, +unconsciously and quite forgetting her condition, prepared for the +familiar gallop of coquetry, without any ulterior motive or any +struggle, but with naive and lighthearted gaiety. + +Although in female society Anatole usually assumed the role of a man +tired of being run after by women, his vanity was flattered by the +spectacle of his power over these three women. Besides that, he was +beginning to feel for the pretty and provocative Mademoiselle +Bourienne that passionate animal feeling which was apt to master him +with great suddenness and prompt him to the coarsest and most reckless +actions. + +After tea, the company went into the sitting room and Princess +Mary was asked to play on the clavichord. Anatole, laughing and in +high spirits, came and leaned on his elbows, facing her and beside +Mademoiselle Bourienne. Princess Mary felt his look with a painfully +joyous emotion. Her favorite sonata bore her into a most intimately +poetic world and the look she felt upon her made that world still more +poetic. But Anatole's expression, though his eyes were fixed on her, +referred not to her but to the movements of Mademoiselle Bourienne's +little foot, which he was then touching with his own under the +clavichord. Mademoiselle Bourienne was also looking at Princess +Mary, and in her lovely eyes there was a look of fearful joy and +hope that was also new to the princess. + +"How she loves me!" thought Princess Mary. "How happy I am now, +and how happy I may be with such a friend and such a husband! Husband? +Can it be possible?" she thought, not daring to look at his face, +but still feeling his eyes gazing at her. + +In the evening, after supper, when all were about to retire, Anatole +kissed Princess Mary's hand. She did not know how she found the +courage, but she looked straight into his handsome face as it came +near to her shortsighted eyes. Turning from Princess Mary he went up +and kissed Mademoiselle Bourienne's hand. (This was not etiquette, but +then he did everything so simply and with such assurance!) +Mademoiselle Bourienne flushed, and gave the princess a frightened +look. + +"What delicacy!" thought the princess. "Is it possible that Amelie" +(Mademoiselle Bourienne) "thinks I could be jealous of her, and not +value her pure affection and devotion to me?" She went up to her and +kissed her warmly. Anatole went up to kiss the little princess' hand. + +"No! No! No! When your father writes to tell me that you are +behaving well I will give you my hand to kiss. Not till then!" she +said. And smilingly raising a finger at him, she left the room. + + + + +CHAPTER V + + +They all separated, but, except Anatole who fell asleep as soon as +he got into bed, all kept awake a long time that night. + +"Is he really to be my husband, this stranger who is so kind--yes, +kind, that is the chief thing," thought Princess Mary; and fear, which +she had seldom experienced, came upon her. She feared to look round, +it seemed to her that someone was there standing behind the screen +in the dark corner. And this someone was he--the devil--and he was +also this man with the white forehead, black eyebrows, and red lips. + +She rang for her maid and asked her to sleep in her room. + +Mademoiselle Bourienne walked up and down the conservatory for a +long time that evening, vainly expecting someone, now smiling at +someone, now working herself up to tears with the imaginary words of +her pauvre mere rebuking her for her fall. + +The little princess grumbled to her maid that her bed was badly +made. She could not lie either on her face or on her side. Every +position was awkward and uncomfortable, and her burden oppressed her +now more than ever because Anatole's presence had vividly recalled +to her the time when she was not like that and when everything was +light and gay. She sat in an armchair in her dressing jacket and +nightcap and Katie, sleepy and disheveled, beat and turned the heavy +feather bed for the third time, muttering to herself. + +"I told you it was all lumps and holes!" the little princess +repeated. "I should be glad enough to fall asleep, so it's not my +fault!" and her voice quivered like that of a child about to cry. + +The old prince did not sleep either. Tikhon, half asleep, heard +him pacing angrily about and snorting. The old prince felt as though +he had been insulted through his daughter. The insult was the more +pointed because it concerned not himself but another, his daughter, +whom he loved more than himself. He kept telling himself that he would +consider the whole matter and decide what was right and how he +should act, but instead of that he only excited himself more and more. + +"The first man that turns up--she forgets her father and +everything else, runs upstairs and does up her hair and wags her +tail and is unlike herself! Glad to throw her father over! And she +knew I should notice it. Fr... fr... fr! And don't I see that that +idiot had eyes only for Bourienne--I shall have to get rid of her. And +how is it she has not pride enough to see it? If she has no pride +for herself she might at least have some for my sake! She must be +shown that the blockhead thinks nothing of her and looks only at +Bourienne. No, she has no pride... but I'll let her see...." + +The old prince knew that if he told his daughter she was making a +mistake and that Anatole meant to flirt with Mademoiselle Bourienne, +Princess Mary's self-esteem would be wounded and his point (not to +be parted from her) would be gained, so pacifying himself with this +thought, he called Tikhon and began to undress. + +"What devil brought them here?" thought he, while Tikhon was putting +the nightshirt over his dried-up old body and gray-haired chest. "I +never invited them. They came to disturb my life--and there is not +much of it left." + +"Devil take 'em!" he muttered, while his head was still covered by +the shirt. + +Tikhon knew his master's habit of sometimes thinking aloud, and +therefore met with unaltered looks the angrily inquisitive +expression of the face that emerged from the shirt. + +"Gone to bed?" asked the prince. + +Tikhon, like all good valets, instinctively knew the direction of +his master's thoughts. He guessed that the question referred to Prince +Vasili and his son. + +"They have gone to bed and put out their lights, your excellency." + +"No good... no good..." said the prince rapidly, and thrusting his +feet into his slippers and his arms into the sleeves of his dressing +gown, he went to the couch on which he slept. + +Though no words had passed between Anatole and Mademoiselle +Bourienne, they quite understood one another as to the first part of +their romance, up to the appearance of the pauvre mere; they +understood that they had much to say to one another in private and +so they had been seeking an opportunity since morning to meet one +another alone. When Princess Mary went to her father's room at the +usual hour, Mademoiselle Bourienne and Anatole met in the +conservatory. + +Princess Mary went to the door of the study with special +trepidation. It seemed to her that not only did everybody know that +her fate would be decided that day, but that they also knew what she +thought about it. She read this in Tikhon's face and in that of Prince +Vasili's valet, who made her a low bow when she met him in the +corridor carrying hot water. + +The old prince was very affectionate and careful in his treatment of +his daughter that morning. Princess Mary well knew this painstaking +expression of her father's. His face wore that expression when his dry +hands clenched with vexation at her not understanding a sum in +arithmetic, when rising from his chair he would walk away from her, +repeating in a low voice the same words several times over. + +He came to the point at once, treating her ceremoniously. + +"I have had a proposition made me concerning you," he said with an +unnatural smile. "I expect you have guessed that Prince Vasili has not +come and brought his pupil with him" (for some reason Prince Bolkonski +referred to Anatole as a "pupil") "for the sake of my beautiful +eyes. Last night a proposition was made me on your account and, as you +know my principles, I refer it to you." + +"How am I to understand you, mon pere?" said the princess, growing +pale and then blushing. + +"How understand me!" cried her father angrily. "Prince Vasili +finds you to his taste as a daughter-in-law and makes a proposal to +you on his pupil's behalf. That's how it's to be understood! 'How +understand it'!... And I ask you!" + +"I do not know what you think, Father," whispered the princess. + +"I? I? What of me? Leave me out of the question. I'm not going to +get married. What about you? That's what I want to know." + +The princess saw that her father regarded the matter with +disapproval, but at that moment the thought occurred to her that her +fate would be decided now or never. She lowered her eyes so as not +to see the gaze under which she felt that she could not think, but +would only be able to submit from habit, and she said: "I wish only to +do your will, but if I had to express my own desire..." She had no +time to finish. The old prince interrupted her. + +"That's admirable!" he shouted. "He will take you with your dowry +and take Mademoiselle Bourienne into the bargain. She'll be the +wife, while you..." + +The prince stopped. He saw the effect these words had produced on +his daughter. She lowered her head and was ready to burst into tears. + +"Now then, now then, I'm only joking!" he said. "Remember this, +Princess, I hold to the principle that a maiden has a full right to +choose. I give you freedom. Only remember that your life's happiness +depends on your decision. Never mind me!" + +"But I do not know, Father!" + +"There's no need to talk! He receives his orders and will marry +you or anybody; but you are free to choose.... Go to your room, +think it over, and come back in an hour and tell me in his presence: +yes or no. I know you will pray over it. Well, pray if you like, but +you had better think it over. Go! Yes or no, yes or no, yes or no!" he +still shouted when the princess, as if lost in a fog, had already +staggered out of the study. + +Her fate was decided and happily decided. But what her father had +said about Mademoiselle Bourienne was dreadful. It was untrue to be +sure, but still it was terrible, and she could not help thinking of +it. She was going straight on through the conservatory, neither seeing +nor hearing anything, when suddenly the well-known whispering of +Mademoiselle Bourienne aroused her. She raised her eyes, and two steps +away saw Anatole embracing the Frenchwoman and whispering something to +her. With a horrified expression on his handsome face, Anatole +looked at Princess Mary, but did not at once take his arm from the +waist of Mademoiselle Bourienne who had not yet seen her. + +"Who's that? Why? Wait a moment!" Anatole's face seemed to say. +Princess Mary looked at them in silence. She could not understand +it. At last Mademoiselle Bourienne gave a scream and ran away. Anatole +bowed to Princess Mary with a gay smile, as if inviting her to join in +a laugh at this strange incident, and then shrugging his shoulders +went to the door that led to his own apartments. + +An hour later, Tikhon came to call Princess Mary to the old +prince; he added that Prince Vasili was also there. When Tikhon came +to her Princess Mary was sitting on the sofa in her room, holding +the weeping Mademoiselle Bourienne in her arms and gently stroking her +hair. The princess' beautiful eyes with all their former calm radiance +were looking with tender affection and pity at Mademoiselle +Bourienne's pretty face. + +"No, Princess, I have lost your affection forever!" said +Mademoiselle Bourienne. + +"Why? I love you more than ever," said Princess Mary, "and I will +try to do all I can for your happiness." + +"But you despise me. You who are so pure can never understand +being so carried away by passion. Oh, only my poor mother..." + +"I quite understand," answered Princess Mary, with a sad smile. +"Calm yourself, my dear. I will go to my father," she said, and went +out. + +Prince Vasili, with one leg thrown high over the other and a +snuffbox in his hand, was sitting there with a smile of deep emotion +on his face, as if stirred to his heart's core and himself +regretting and laughing at his own sensibility, when Princess Mary +entered. He hurriedly took a pinch of snuff. + +"Ah, my dear, my dear!" he began, rising and taking her by both +hands. Then, sighing, he added: "My son's fate is in your hands. +Decide, my dear, good, gentle Marie, whom I have always loved as a +daughter!" + +He drew back and a real tear appeared in his eye. + +"Fr... fr..." snorted Prince Bolkonski. "The prince is making a +proposition to you in his pupil's--I mean, his son's--name. Do you +wish or not to be Prince Anatole Kuragin's wife? Reply: yes or no," he +shouted, "and then I shall reserve the right to state my opinion also. +Yes, my opinion, and only my opinion," added Prince Bolkonski, turning +to Prince Vasili and answering his imploring look. "Yes, or no?" + +"My desire is never to leave you, Father, never to separate my +life from yours. I don't wish to marry," she answered positively, +glancing at Prince Vasili and at her father with her beautiful eyes. + +"Humbug! Nonsense! Humbug, humbug, humbug!" cried Prince +Bolkonski, frowning and taking his daughter's hand; he did not kiss +her, but only bending his forehead to hers just touched it, and +pressed her hand so that she winced and uttered a cry. + +Prince Vasili rose. + +"My dear, I must tell you that this is a moment I shall never, never +forget. But, my dear, will you not give us a little hope of touching +this heart, so kind and generous? Say 'perhaps'... The future is so +long. Say 'perhaps.'" + +"Prince, what I have said is all there is in my heart. I thank you +for the honor, but I shall never be your son's wife." + +"Well, so that's finished, my dear fellow! I am very glad to have +seen you. Very glad! Go back to your rooms, Princess. Go!" said the +old prince. "Very, very glad to have seen you," repeated he, +embracing Prince Vasili. + +"My vocation is a different one," thought Princess Mary. "My +vocation is to be happy with another kind of happiness, the +happiness of love and self-sacrifice. And cost what it may, I will +arrange poor Amelie's happiness, she loves him so passionately, and so +passionately repents. I will do all I can to arrange the match between +them. If he is not rich I will give her the means; I will ask my +father and Andrew. I shall be so happy when she is his wife. She is so +unfortunate, a stranger, alone, helpless! And, oh God, how +passionately she must love him if she could so far forget herself! +Perhaps I might have done the same!..." thought Princess Mary. + + + + + +CHAPTER VI + + +It was long since the Rostovs had news of Nicholas. Not till +midwinter was the count at last handed a letter addressed in his son's +handwriting. On receiving it, he ran on tiptoe to his study in alarm +and haste, trying to escape notice, closed the door, and began to read +the letter. + +Anna Mikhaylovna, who always knew everything that passed in the +house, on hearing of the arrival of the letter went softly into the +room and found the count with it in his hand, sobbing and laughing +at the same time. + +Anna Mikhaylovna, though her circumstances had improved, was still +living with the Rostovs. + +"My dear friend?" said she, in a tone of pathetic inquiry, +prepared to sympathize in any way. + +The count sobbed yet more. + +"Nikolenka... a letter... wa... a... s... wounded... my darling +boy... the countess... promoted to be an officer... thank God... How +tell the little countess!" + +Anna Mikhaylovna sat down beside him, with her own handkerchief +wiped the tears from his eyes and from the letter, then having dried +her own eyes she comforted the count, and decided that at dinner and +till teatime she would prepare the countess, and after tea, with God's +help, would inform her. + +At dinner Anna Mikhaylovna talked the whole time about the war +news and about Nikolenka, twice asked when the last letter had been +received from him, though she knew that already, and remarked that +they might very likely be getting a letter from him that day. Each +time that these hints began to make the countess anxious and she +glanced uneasily at the count and at Anna Mikhaylovna, the latter very +adroitly turned the conversation to insignificant matters. Natasha, +who, of the whole family, was the most gifted with a capacity to +feel any shades of intonation, look, and expression, pricked up her +ears from the beginning of the meal and was certain that there was +some secret between her father and Anna Mikhaylovna, that it had +something to do with her brother, and that Anna Mikhaylovna was +preparing them for it. Bold as she was, Natasha, who knew how +sensitive her mother was to anything relating to Nikolenka, did not +venture to ask any questions at dinner, but she was too excited to eat +anything and kept wriggling about on her chair regardless of her +governess' remarks. After dinner, she rushed head long after Anna +Mikhaylovna and, dashing at her, flung herself on her neck as soon +as she overtook her in the sitting room. + +"Auntie, darling, do tell me what it is!" + +"Nothing, my dear." + +"No, dearest, sweet one, honey, I won't give up--I know you know +something." + +Anna Mikhaylovna shook her head. + +"You are a little slyboots," she said. + +"A letter from Nikolenka! I'm sure of it!" exclaimed Natasha, +reading confirmation in Anna Mikhaylovna's face. + +"But for God's sake, be careful, you know how it may affect your +mamma." + +"I will, I will, only tell me! You won't? Then I will go and tell at +once." + +Anna Mikhaylovna, in a few words, told her the contents of the +letter, on condition that she should tell no one. + +"No, on my true word of honor," said Natasha, crossing herself, +"I won't tell anyone!" and she ran off at once to Sonya. + +"Nikolenka... wounded... a letter," she announced in gleeful +triumph. + +"Nicholas!" was all Sonya said, instantly turning white. + +Natasha, seeing the impression the of her brother's wound produced +on Sonya, felt for the first time the sorrowful side of the news. + +She rushed to Sonya, hugged her, and began to cry. + +"A little wound, but he has been made an officer; he is well now, he +wrote himself," said she through her tears. + +"There now! It's true that all you women are crybabies," remarked +Petya, pacing the room with large, resolute strides. "Now I'm very +glad, very glad indeed, that my brother has distinguished himself +so. You are all blubberers and understand nothing." + +Natasha smiled through her tears. + +"You haven't read the letter?" asked Sonya. + +"No, but she said that it was all over and that he's now an +officer." + +"Thank God!" said Sonya, crossing herself. "But perhaps she deceived +you. Let us go to Mamma." + +Petya paced the room in silence for a time. + +"If I'd been in Nikolenka's place I would have killed even more of +those Frenchmen," he said. "What nasty brutes they are! I'd have +killed so many that there'd have been a heap of them." + +"Hold your tongue, Petya, what a goose you are!" + +"I'm not a goose, but they are who cry about trifles," said Petya. + +"Do you remember him?" Natasha suddenly asked, after a moment's +silence. + +Sonya smiled. + +"Do I remember Nicholas?" + +"No, Sonya, but do you remember so that you remember him +perfectly, remember everything?" said Natasha, with an expressive +gesture, evidently wishing to give her words a very definite +meaning. "I remember Nikolenka too, I remember him well," she said. +"But I don't remember Boris. I don't remember him a bit." + +"What! You don't remember Boris?" asked Sonya in surprise. + +"It's not that I don't remember--I know what he is like, but not +as I remember Nikolenka. Him--I just shut my eyes and remember, but +Boris... No!" (She shut her eyes.)"No! there's nothing at all." + +"Oh, Natasha!" said Sonya, looking ecstatically and earnestly at her +friend as if she did not consider her worthy to hear what she meant to +say and as if she were saying it to someone else, with whom joking was +out of the question, "I am in love with your brother once for all and, +whatever may happen to him or to me, shall never cease to love him +as long as I live." + +Natasha looked at Sonya with wondering and inquisitive eyes, and +said nothing. She felt that Sonya was speaking the truth, that there +was such love as Sonya was speaking of. But Natasha had not yet felt +anything like it. She believed it could be, but did not understand it. + +"Shall you write to him?" she asked. + +Sonya became thoughtful. The question of how to write to Nicholas, +and whether she ought to write, tormented her. Now that he was already +an officer and a wounded hero, would it be right to remind him of +herself and, as it might seem, of the obligations to her he had +taken on himself? + +"I don't know. I think if he writes, I will write too," she said, +blushing. + +"And you won't feel ashamed to write to him?" + +Sonya smiled. + +"No." + +"And I should be ashamed to write to Boris. I'm not going to." + +"Why should you be ashamed?" + +"Well, I don't know. It's awkward and would make me ashamed." + +"And I know why she'd be ashamed," said Petya, offended by Natasha's +previous remark. "It's because she was in love with that fat one in +spectacles" (that was how Petya described his namesake, the new +Count Bezukhov) "and now she's in love with that singer" (he meant +Natasha's Italian singing master), "that's why she's ashamed!" + +"Petya, you're a stupid!" said Natasha. + +"Not more stupid than you, madam," said the nine-year-old Petya, +with the air of an old brigadier. + +The countess had been prepared by Anna Mikhaylovna's hints at +dinner. On retiring to her own room, she sat in an armchair, her +eyes fixed on a miniature portrait of her son on the lid of a +snuffbox, while the tears kept coming into her eyes. Anna Mikhaylovna, +with the letter, came on tiptoe to the countess' door and paused. + +"Don't come in," she said to the old count who was following her. +"Come later." And she went in, closing the door behind her. + +The count put his ear to the keyhole and listened. + +At first he heard the sound of indifferent voices, then Anna +Mikhaylovna's voice alone in a long speech, then a cry, then +silence, then both voices together with glad intonations, and then +footsteps. Anna Mikhaylovna opened the door. Her face wore the proud +expression of a surgeon who has just performed a difficult operation +and admits the public to appreciate his skill. + +"It is done!" she said to the count, pointing triumphantly to the +countess, who sat holding in one hand the snuffbox with its portrait +and in the other the letter, and pressing them alternately to her +lips. + +When she saw the count, she stretched out her arms to him, +embraced his bald head, over which she again looked at the letter +and the portrait, and in order to press them again to her lips, she +slightly pushed away the bald head. Vera, Natasha, Sonya, and Petya +now entered the room, and the reading of the letter began. After a +brief description of the campaign and the two battles in which he +had taken part, and his promotion, Nicholas said that he kissed his +father's and mother's hands asking for their blessing, and that he +kissed Vera, Natasha, and Petya. Besides that, he sent greetings to +Monsieur Schelling, Madame Schoss, and his old nurse, and asked them +to kiss for him "dear Sonya, whom he loved and thought of just the +same as ever." When she heard this Sonya blushed so that tears came +into her eyes and, unable to bear the looks turned upon her, ran +away into the dancing hall, whirled round it at full speed with her +dress puffed out like a balloon, and, flushed and smiling, plumped +down on the floor. The countess was crying. + +"Why are you crying, Mamma?" asked Vera. "From all he says one +should be glad and not cry." + +This was quite true, but the count, the countess, and Natasha looked +at her reproachfully. "And who is it she takes after?" thought the +countess. + +Nicholas' letter was read over hundreds of times, and those who were +considered worthy to hear it had to come to the countess, for she +did not let it out of her hands. The tutors came, and the nurses, +and Dmitri, and several acquaintances, and the countess reread the +letter each time with fresh pleasure and each time discovered in it +fresh proofs of Nikolenka's virtues. How strange, how extraordinary, +how joyful it seemed, that her son, the scarcely perceptible motion of +whose tiny limbs she had felt twenty years ago within her, that son +about whom she used to have quarrels with the too indulgent count, +that son who had first learned to say "pear" and then "granny," that +this son should now be away in a foreign land amid strange +surroundings, a manly warrior doing some kind of man's work of his +own, without help or guidance. The universal experience of ages, +showing that children do grow imperceptibly from the cradle to +manhood, did not exist for the countess. Her son's growth toward +manhood, at each of its stages, had seemed as extraordinary to her +as if there had never existed the millions of human beings who grew up +in the same way. As twenty years before, it seemed impossible that the +little creature who lived somewhere under her heart would ever cry, +suck her breast, and begin to speak, so now she could not believe that +that little creature could be this strong, brave man, this model son +and officer that, judging by this letter, he now was. + +"What a style! How charmingly he describes!" said she, reading the +descriptive part of the letter. "And what a soul! Not a word about +himself.... Not a word! About some Denisov or other, though he +himself, I dare say, is braver than any of them. He says nothing about +his sufferings. What a heart! How like him it is! And how he has +remembered everybody! Not forgetting anyone. I always said when he was +only so high--I always said...." + +For more than a week preparations were being made, rough drafts of +letters to Nicholas from all the household were written and copied +out, while under the supervision of the countess and the solicitude of +the count, money and all things necessary for the uniform and +equipment of the newly commissioned officer were collected. Anna +Mikhaylovna, practical woman that she was, had even managed by favor +with army authorities to secure advantageous means of communication +for herself and her son. She had opportunities of sending her +letters to the Grand Duke Constantine Pavlovich, who commanded the +Guards. The Rostovs supposed that The Russian Guards, Abroad, was +quite a definite address, and that if a letter reached the Grand +Duke in command of the Guards there was no reason why it should not +reach the Pavlograd regiment, which was presumably somewhere in the +same neighborhood. And so it was decided to send the letters and money +by the Grand Duke's courier to Boris and Boris was to forward them +to Nicholas. The letters were from the old count, the countess, Petya, +Vera, Natasha, and Sonya, and finally there were six thousand rubles +for his outfit and various other things the old count sent to his son. + + + + + +CHAPTER VII + + +On the twelfth of November, Kutuzov's active army, in camp before +Olmutz, was preparing to be reviewed next day by the two Emperors--the +Russian and the Austrian. The Guards, just arrived from Russia, +spent the night ten miles from Olmutz and next morning were to come +straight to the review, reaching the field at Olmutz by ten o'clock. + +That day Nicholas Rostov received a letter from Boris, telling him +that the Ismaylov regiment was quartered for the night ten miles +from Olmutz and that he wanted to see him as he had a letter and money +for him. Rostov was particularly in need of money now that the troops, +after their active service, were stationed near Olmutz and the camp +swarmed with well-provisioned sutlers and Austrian Jews offering all +sorts of tempting wares. The Pavlograds held feast after feast, +celebrating awards they had received for the campaign, and made +expeditions to Olmutz to visit a certain Caroline the Hungarian, who +had recently opened a restaurant there with girls as waitresses. +Rostov, who had just celebrated his promotion to a cornetcy and bought +Denisov's horse, Bedouin, was in debt all round, to his comrades and +the sutlers. On receiving Boris' letter he rode with a fellow +officer to Olmutz, dined there, drank a bottle of wine, and then set +off alone to the Guards' camp to find his old playmate. Rostov had not +yet had time to get his uniform. He had on a shabby cadet jacket, +decorated with a soldier's cross, equally shabby cadet's riding +breeches lined with worn leather, and an officer's saber with a +sword knot. The Don horse he was riding was one he had bought from a +Cossack during the campaign, and he wore a crumpled hussar cap stuck +jauntily back on one side of his head. As he rode up to the camp he +thought how he would impress Boris and all his comrades of the +Guards by his appearance--that of a fighting hussar who had been under +fire. + +The Guards had made their whole march as if on a pleasure trip, +parading their cleanliness and discipline. They had come by easy +stages, their knapsacks conveyed on carts, and the Austrian +authorities had provided excellent dinners for the officers at every +halting place. The regiments had entered and left the town with +their bands playing, and by the Grand Duke's orders the men had +marched all the way in step (a practice on which the Guards prided +themselves), the officers on foot and at their proper posts. Boris had +been quartered, and had marched all the way, with Berg who was already +in command of a company. Berg, who had obtained his captaincy during +the campaign, had gained the confidence of his superiors by his +promptitude and accuracy and had arranged his money matters very +satisfactorily. Boris, during the campaign, had made the +acquaintance of many persons who might prove useful to him, and by a +letter of recommendation he had brought from Pierre had become +acquainted with Prince Andrew Bolkonski, through whom he hoped to +obtain a post on the commander in chief's staff. Berg and Boris, +having rested after yesterday's march, were sitting, clean and +neatly dressed, at a round table in the clean quarters allotted to +them, playing chess. Berg held a smoking pipe between his knees. +Boris, in the accurate way characteristic of him, was building a +little pyramid of chessmen with his delicate white fingers while +awaiting Berg's move, and watched his opponent's face, evidently +thinking about the game as he always thought only of whatever he was +engaged on. + +"Well, how are you going to get out of that?" he remarked. + +"We'll try to," replied Berg, touching a pawn and then removing +his hand. + +At that moment the door opened. + +"Here he is at last!" shouted Rostov. "And Berg too! Oh, you +petisenfans, allay cushay dormir!" he exclaimed, imitating his Russian +nurse's French, at which he and Boris used to laugh long ago. + +"Dear me, how you have changed!" + +Boris rose to meet Rostov, but in doing so did not omit to steady +and replace some chessmen that were falling. He was about to embrace +his friend, but Nicholas avoided him. With that peculiar feeling of +youth, that dread of beaten tracks, and wish to express itself in a +manner different from that of its elders which is often insincere, +Nicholas wished to do something special on meeting his friend. He +wanted to pinch him, push him, do anything but kiss him--a thing +everybody did. But notwithstanding this, Boris embraced him in a +quiet, friendly way and kissed him three times. + +They had not met for nearly half a year and, being at the age when +young men take their first steps on life's road, each saw immense +changes in the other, quite a new reflection of the society in which +they had taken those first steps. Both had changed greatly since +they last met and both were in a hurry to show the changes that had +taken place in them. + +"Oh, you damned dandies! Clean and fresh as if you'd been to a fete, +not like us sinners of the line," cried Rostov, with martial swagger +and with baritone notes in his voice, new to Boris, pointing to his +own mud-bespattered breeches. The German landlady, hearing Rostov's +loud voice, popped her head in at the door. + +"Eh, is she pretty?" he asked with a wink. + +"Why do you shout so? You'll frighten them!" said Boris. "I did +not expect you today," he added. "I only sent you the note yesterday +by Bolkonski--an adjutant of Kutuzov's, who's a friend of mine. I +did not think he would get it to you so quickly.... Well, how are you? +Been under fire already?" asked Boris. + +Without answering, Rostov shook the soldier's Cross of St. George +fastened to the cording of his uniform and, indicating a bandaged arm, +glanced at Berg with a smile. + +"As you see," he said. + +"Indeed? Yes, yes!" said Boris, with a smile. "And we too have had a +splendid march. You know, of course, that His Imperial Highness rode +with our regiment all the time, so that we had every comfort and every +advantage. What receptions we had in Poland! What dinners and balls! I +can't tell you. And the Tsarevich was very gracious to all our +officers." + +And the two friends told each other of their doings, the one of +his hussar revels and life in the fighting line, the other of the +pleasures and advantages of service under members of the Imperial +family. + +"Oh, you Guards!" said Rostov. "I say, send for some wine." + +Boris made a grimace. + +"If you really want it," said he. + +He went to his bed, drew a purse from under the clean pillow, and +sent for wine. + +"Yes, and I have some money and a letter to give you," he added. + +Rostov took the letter and, throwing the money on the sofa, put both +arms on the table and began to read. After reading a few lines, he +glanced angrily at Berg, then, meeting his eyes, hid his face behind +the letter. + +"Well, they've sent you a tidy sum," said Berg, eying the heavy +purse that sank into the sofa. "As for us, Count, we get along on +our pay. I can tell you for myself..." + +"I say, Berg, my dear fellow," said Rostov, "when you get a letter +from home and meet one of your own people whom you want to talk +everything over with, and I happen to be there, I'll go at once, to be +out of your way! Do go somewhere, anywhere... to the devil!" he +exclaimed, and immediately seizing him by the shoulder and looking +amiably into his face, evidently wishing to soften the rudeness of his +words, he added, "Don't be hurt, my dear fellow; you know I speak from +my heart as to an old acquaintance." + +"Oh, don't mention it, Count! I quite understand," said Berg, +getting up and speaking in a muffled and guttural voice. + +"Go across to our hosts: they invited you," added Boris. + +Berg put on the cleanest of coats, without a spot or speck of +dust, stood before a looking glass and brushed the hair on his temples +upwards, in the way affected by the Emperor Alexander, and, having +assured himself from the way Rostov looked at it that his coat had +been noticed, left the room with a pleasant smile. + +"Oh dear, what a beast I am!" muttered Rostov, as he read the +letter. + +"Why?" + +"Oh, what a pig I am, not to have written and to have given them +such a fright! Oh, what a pig I am!" he repeated, flushing suddenly. +"Well, have you sent Gabriel for some wine? All right let's have +some!" + +In the letter from his parents was enclosed a letter of +recommendation to Bagration which the old countess at Anna +Mikhaylovna's advice had obtained through an acquaintance and sent +to her son, asking him to take it to its destination and make use of +it. + +"What nonsense! Much I need it!" said Rostov, throwing the letter +under the table. + +"Why have you thrown that away?" asked Boris. + +"It is some letter of recommendation... what the devil do I want +it for!" + +"Why 'What the devil'?" said Boris, picking it up and reading the +address. "This letter would be of great use to you." + +"I want nothing, and I won't be anyone's adjutant." + +"Why not?" inquired Boris. + +"It's a lackey's job!" + +"You are still the same dreamer, I see," remarked Boris, shaking his +head. + +"And you're still the same diplomatist! But that's not the +point... Come, how are you?" asked Rostov. + +"Well, as you see. So far everything's all right, but I confess I +should much like to be an adjutant and not remain at the front." + +"Why?" + +"Because when once a man starts on military service, he should try +to make as successful a career of it as possible." + +"Oh, that's it!" said Rostov, evidently thinking of something else. + +He looked intently and inquiringly into his friend's eyes, evidently +trying in vain to find the answer to some question. + +Old Gabriel brought in the wine. + +"Shouldn't we now send for Berg?" asked Boris. "He would drink +with you. I can't." + +"Well, send for him... and how do you get on with that German?" +asked Rostov, with a contemptuous smile. + +"He is a very, very nice, honest, and pleasant fellow," answered +Boris. + +Again Rostov looked intently into Boris' eyes and sighed. Berg +returned, and over the bottle of wine conversation between the three +officers became animated. The Guardsmen told Rostov of their march and +how they had been made much of in Russia, Poland, and abroad. They +spoke of the sayings and doings of their commander, the Grand Duke, +and told stories of his kindness and irascibility. Berg, as usual, +kept silent when the subject did not relate to himself, but in +connection with the stories of the Grand Duke's quick temper he +related with gusto how in Galicia he had managed to deal with the +Grand Duke when the latter made a tour of the regiments and was +annoyed at the irregularity of a movement. With a pleasant smile +Berg related how the Grand Duke had ridden up to him in a violent +passion, shouting: "Arnauts!" ("Arnauts" was the Tsarevich's +favorite expression when he was in a rage) and called for the +company commander. + +"Would you believe it, Count, I was not at all alarmed, because I +knew I was right. Without boasting, you know, I may say that I know +the Army Orders by heart and know the Regulations as well as I do +the Lord's Prayer. So, Count, there never is any negligence in my +company, and so my conscience was at ease. I came forward...." (Berg +stood up and showed how he presented himself, with his hand to his +cap, and really it would have been difficult for a face to express +greater respect and self-complacency than his did.) "Well, he +stormed at me, as the saying is, stormed and stormed and stormed! It +was not a matter of life but rather of death, as the saying is. +'Albanians!' and 'devils!' and 'To Siberia!'" said Berg with a +sagacious smile. "I knew I was in the right so I kept silent; was +not that best, Count?... 'Hey, are you dumb?' he shouted. Still I +remained silent. And what do you think, Count? The next day it was not +even mentioned in the Orders of the Day. That's what keeping one's +head means. That's the way, Count," said Berg, lighting his pipe and +emitting rings of smoke. + +"Yes, that was fine," said Rostov, smiling. + +But Boris noticed that he was preparing to make fun of Berg, and +skillfully changed the subject. He asked him to tell them how and +where he got his wound. This pleased Rostov and he began talking about +it, and as he went on became more and more animated. He told them of +his Schon Grabern affair, just as those who have taken part in a +battle generally do describe it, that is, as they would like it to +have been, as they have heard it described by others, and as sounds +well, but not at all as it really was. Rostov was a truthful young man +and would on no account have told a deliberate lie. He began his story +meaning to tell everything just as it happened, but imperceptibly, +involuntarily, and inevitably he lapsed into falsehood. If he had told +the truth to his hearers--who like himself had often heard stories +of attacks and had formed a definite idea of what an attack was and +were expecting to hear just such a story--they would either not have +believed him or, still worse, would have thought that Rostov was +himself to blame since what generally happens to the narrators of +cavalry attacks had not happened to him. He could not tell them simply +that everyone went at a trot and that he fell off his horse and +sprained his arm and then ran as hard as he could from a Frenchman +into the wood. Besides, to tell everything as it really happened, it +would have been necessary to make an effort of will to tell only +what happened. It is very difficult to tell the truth, and young +people are rarely capable of it. His hearers expected a story of how +beside himself and all aflame with excitement, he had flown like a +storm at the square, cut his way in, slashed right and left, how his +saber had tasted flesh and he had fallen exhausted, and so on. And +so he told them all that. + +In the middle of his story, just as he was saying: "You cannot +imagine what a strange frenzy one experiences during an attack," +Prince Andrew, whom Boris was expecting, entered the room. Prince +Andrew, who liked to help young men, was flattered by being asked +for his assistance and being well disposed toward Boris, who had +managed to please him the day before, he wished to do what the young +man wanted. Having been sent with papers from Kutuzov to the +Tsarevich, he looked in on Boris, hoping to find him alone. When he +came in and saw an hussar of the line recounting his military exploits +(Prince Andrew could not endure that sort of man), he gave Boris a +pleasant smile, frowned as with half-closed eyes he looked at +Rostov, bowed slightly and wearily, and sat down languidly on the +sofa: he felt it unpleasant to have dropped in on bad company. +Rostov flushed up on noticing this, but he did not care, this was a +mere stranger. Glancing, however, at Boris, he saw that he too +seemed ashamed of the hussar of the line. + +In spite of Prince Andrew's disagreeable, ironical tone, in spite of +the contempt with which Rostov, from his fighting army point of +view, regarded all these little adjutants on the staff of whom the +newcomer was evidently one, Rostov felt confused, blushed, and +became silent. Boris inquired what news there might be on the staff, +and what, without indiscretion, one might ask about our plans. + +"We shall probably advance," replied Bolkonski, evidently +reluctant to say more in the presence of a stranger. + +Berg took the opportunity to ask, with great politeness, whether, as +was rumored, the allowance of forage money to captains of companies +would be doubled. To this Prince Andrew answered with a smile that +he could give no opinion on such an important government order, and +Berg laughed gaily. + +"As to your business," Prince Andrew continued, addressing Boris, +"we will talk of it later" (and he looked round at Rostov). "Come to +me after the review and we will do what is possible." + +And, having glanced round the room, Prince Andrew turned to +Rostov, whose state of unconquerable childish embarrassment now +changing to anger he did not condescend to notice, and said: "I +think you were talking of the Schon Grabern affair? Were you there?" + +"I was there," said Rostov angrily, as if intending to insult the +aide-de-camp. + +Bolkonski noticed the hussar's state of mind, and it amused him. +With a slightly contemptuous smile, he said: "Yes, there are many +stories now told about that affair!" + +"Yes, stories!" repeated Rostov loudly, looking with eyes suddenly +grown furious, now at Boris, now at Bolkonski. "Yes, many stories! But +our stories are the stories of men who have been under the enemy's +fire! Our stories have some weight, not like the stories of those +fellows on the staff who get rewards without doing anything!" + +"Of whom you imagine me to be one?" said Prince Andrew, with a quiet +and particularly amiable smile. + +A strange feeling of exasperation and yet of respect for this +man's self-possession mingled at that moment in Rostov's soul. + +"I am not talking about you," he said, "I don't know you and, +frankly, I don't want to. I am speaking of the staff in general." + +"And I will tell you this," Prince Andrew interrupted in a tone of +quiet authority, "you wish to insult me, and I am ready to agree +with you that it would be very easy to do so if you haven't sufficient +self-respect, but admit that the time and place are very badly chosen. +In a day or two we shall all have to take part in a greater and more +serious duel, and besides, Drubetskoy, who says he is an old friend of +yours, is not at all to blame that my face has the misfortune to +displease you. However," he added rising, "you know my name and +where to find me, but don't forget that I do not regard either +myself or you as having been at all insulted, and as a man older +than you, my advice is to let the matter drop. Well then, on Friday +after the review I shall expect you, Drubetskoy. Au revoir!" exclaimed +Prince Andrew, and with a bow to them both he went out. + +Only when Prince Andrew was gone did Rostov think of what he ought +to have said. And he was still more angry at having omitted to say it. +He ordered his horse at once and, coldly taking leave of Boris, rode +home. Should he go to headquarters next day and challenge that +affected adjutant, or really let the matter drop, was the question +that worried him all the way. He thought angrily of the pleasure he +would have at seeing the fright of that small and frail but proud +man when covered by his pistol, and then he felt with surprise that of +all the men he knew there was none he would so much like to have for a +friend as that very adjutant whom he so hated. + + + + + +CHAPTER VIII + + +The day after Rostov had been to see Boris, a review was held of the +Austrian and Russian troops, both those freshly arrived from Russia +and those who had been campaigning under Kutuzov. The two Emperors, +the Russian with his heir the Tsarevich, and the Austrian with the +Archduke, inspected the allied army of eighty thousand men. + +From early morning the smart clean troops were on the move, +forming up on the field before the fortress. Now thousands of feet and +bayonets moved and halted at the officers' command, turned with +banners flying, formed up at intervals, and wheeled round other +similar masses of infantry in different uniforms; now was heard the +rhythmic beat of hoofs and the jingling of showy cavalry in blue, red, +and green braided uniforms, with smartly dressed bandsmen in front +mounted on black, roan, or gray horses; then again, spreading out with +the brazen clatter of the polished shining cannon that quivered on the +gun carriages and with the smell of linstocks, came the artillery +which crawled between the infantry and cavalry and took up its +appointed position. Not only the generals in full parade uniforms, +with their thin or thick waists drawn in to the utmost, their red +necks squeezed into their stiff collars, and wearing scarves and all +their decorations, not only the elegant, pomaded officers, but every +soldier with his freshly washed and shaven face and his weapons +clean and polished to the utmost, and every horse groomed till its +coat shone like satin and every hair of its wetted mane lay smooth- +felt that no small matter was happening, but an important and solemn +affair. Every general and every soldier was conscious of his own +insignificance, aware of being but a drop in that ocean of men, and +yet at the same time was conscious of his strength as a part of that +enormous whole. + +From early morning strenuous activities and efforts had begun and by +ten o'clock all had been brought into due order. The ranks were +drown up on the vast field. The whole army was extended in three +lines: the cavalry in front, behind it the artillery, and behind +that again the infantry. + +A space like a street was left between each two lines of troops. The +three parts of that army were sharply distinguished: Kutuzov's +fighting army (with the Pavlograds on the right flank of the front); +those recently arrived from Russia, both Guards and regiments of the +line; and the Austrian troops. But they all stood in the same lines, +under one command, and in a like order. + +Like wind over leaves ran an excited whisper: "They're coming! +They're coming!" Alarmed voices were heard, and a stir of final +preparation swept over all the troops. + +From the direction of Olmutz in front of them, a group was seen +approaching. And at that moment, though the day was still, a light +gust of wind blowing over the army slightly stirred the streamers on +the lances and the unfolded standards fluttered against their +staffs. It looked as if by that slight motion the army itself was +expressing its joy at the approach of the Emperors. One voice was +heard shouting: "Eyes front!" Then, like the crowing of cocks at +sunrise, this was repeated by others from various sides and all became +silent. + +In the deathlike stillness only the tramp of horses was heard. +This was the Emperors' suites. The Emperors rode up to the flank, +and the trumpets of the first cavalry regiment played the general +march. It seemed as though not the trumpeters were playing, but as +if the army itself, rejoicing at the Emperors' approach, had naturally +burst into music. Amid these sounds, only the youthful kindly voice of +the Emperor Alexander was clearly heard. He gave the words of +greeting, and the first regiment roared "Hurrah!" so deafeningly, +continuously, and joyfully that the men themselves were awed by +their multitude and the immensity of the power they constituted. + +Rostov, standing in the front lines of Kutuzov's army which the Tsar +approached first, experienced the same feeling as every other man in +that army: a feeling of self-forgetfulness, a proud consciousness of +might, and a passionate attraction to him who was the cause of this +triumph. + +He felt that at a single word from that man all this vast mass +(and he himself an insignificant atom in it) would go through fire and +water, commit crime, die, or perform deeds of highest heroism, and +so he could not but tremble and his heart stand still at the imminence +of that word. + +"Hurrah! Hurrah! Hurrah!" thundered from all sides, one regiment +after another greeting the Tsar with the strains of the march, and +then "Hurrah!"... Then the general march, and again "Hurrah! +Hurrah!" growing ever stronger and fuller and merging into a deafening +roar. + +Till the Tsar reached it, each regiment in its silence and +immobility seemed like a lifeless body, but as soon as he came up it +became alive, its thunder joining the roar of the whole line along +which he had already passed. Through the terrible and deafening roar +of those voices, amid the square masses of troops standing +motionless as if turned to stone, hundreds of riders composing the +suites moved carelessly but symmetrically and above all freely, and in +front of them two men--the Emperors. Upon them the undivided, +tensely passionate attention of that whole mass of men was +concentrated. + +The handsome young Emperor Alexander, in the uniform of the Horse +Guards, wearing a cocked hat with its peaks front and back, with his +pleasant face and resonant though not loud voice, attracted everyone's +attention. + +Rostov was not far from the trumpeters, and with his keen sight +had recognized the Tsar and watched his approach. When he was within +twenty paces, and Nicholas could clearly distinguish every detail of +his handsome, happy young face, he experienced a feeling tenderness +and ecstasy such as he had never before known. Every trait and every +movement of the Tsar's seemed to him enchanting. + +Stopping in front of the Pavlograds, the Tsar said something in +French to the Austrian Emperor and smiled. + +Seeing that smile, Rostov involuntarily smiled himself and felt a +still stronger flow of love for his sovereign. He longed to show +that love in some way and knowing that this was impossible was ready +to cry. The Tsar called the colonel of the regiment and said a few +words to him. + +"Oh God, what would happen to me if the Emperor spoke to me?" +thought Rostov. "I should die of happiness!" + +The Tsar addressed the officers also: "I thank you all, gentlemen, I +thank you with my whole heart." To Rostov every word sounded like a +voice from heaven. How gladly would he have died at once for his Tsar! + +"You have earned the St. George's standards and will be worthy of +them." + +"Oh, to die, to die for him," thought Rostov. + +The Tsar said something more which Rostov did not hear, and the +soldiers, straining their lungs, shouted "Hurrah!" + +Rostov too, bending over his saddle, shouted "Hurrah!" with all +his might, feeling that he would like to injure himself by that shout, +if only to express his rapture fully. + +The Tsar stopped a few minutes in front of the hussars as if +undecided. + +"How can the Emperor be undecided?" thought Rostov, but then even +this indecision appeared to him majestic and enchanting, like +everything else the Tsar did. + +That hesitation lasted only an instant. The Tsar's foot, in the +narrow pointed boot then fashionable, touched the groin of the +bobtailed bay mare he rode, his hand in a white glove gathered up +the reins, and he moved off accompanied by an irregularly swaying +sea of aides-de-camp. Farther and farther he rode away, stopping at +other regiments, till at last only his white plumes were visible to +Rostov from amid the suites that surrounded the Emperors. + +Among the gentlemen of the suite, Rostov noticed Bolkonski, +sitting his horse indolently and carelessly. Rostov recalled their +quarrel of yesterday and the question presented itself whether he +ought or ought not to challenge Bolkonski. "Of course not!" he now +thought. "Is it worth thinking or speaking of it at such a moment? +At a time of such love, such rapture, and such self-sacrifice, what do +any of our quarrels and affronts matter? I love and forgive +everybody now." + +When the Emperor had passed nearly all the regiments, the troops +began a ceremonial march past him, and Rostov on Bedouin, recently +purchased from Denisov, rode past too, at the rear of his squadron- +that is, alone and in full view of the Emperor. + +Before he reached him, Rostov, who was a splendid horseman, +spurred Bedouin twice and successfully put him to the showy trot in +which the animal went when excited. Bending his foaming muzzle to +his chest, his tail extended, Bedouin, as if also conscious of the +Emperor's eye upon him, passed splendidly, lifting his feet with a +high and graceful action, as if flying through the air without +touching the ground. + +Rostov himself, his legs well back and his stomach drawn in and +feeling himself one with his horse, rode past the Emperor with a +frowning but blissful face "like a vewy devil," as Denisov expressed +it. + +"Fine fellows, the Pavlograds!" remarked the Emperor. + +"My God, how happy I should be if he ordered me to leap into the +fire this instant!" thought Rostov. + +When the review was over, the newly arrived officers, and also +Kutuzov's, collected in groups and began to talk about the awards, +about the Austrians and their uniforms, about their lines, about +Bonaparte, and how badly the latter would fare now, especially if +the Essen corps arrived and Prussia took our side. + +But the talk in every group was chiefly about the Emperor Alexander. +His every word and movement was described with ecstasy. + +They all had but one wish: to advance as soon as possible against +the enemy under the Emperor's command. Commanded by the Emperor +himself they could not fail to vanquish anyone, be it whom it might: +so thought Rostov and most of the officers after the review. + +All were then more confident of victory than the winning of two +battles would have made them. + + + + + +CHAPTER IX + + +The day after the review, Boris, in his best uniform and with his +comrade Berg's best wishes for success, rode to Olmutz to see +Bolkonski, wishing to profit by his friendliness and obtain for +himself the best post he could--preferably that of adjutant to some +important personage, a position in the army which seemed to him most +attractive. "It is all very well for Rostov, whose father sends him +ten thousand rubles at a time, to talk about not wishing to cringe +to anybody and not be anyone's lackey, but I who have nothing but my +brains have to make a career and must not miss opportunities, but must +avail myself of them!" he reflected. + +He did not find Prince Andrew in Olmutz that day, but the appearance +of the town where the headquarters and the diplomatic corps were +stationed and the two Emperors were living with their suites, +households, and courts only strengthened his desire to belong to +that higher world. + +He knew no one, and despite his smart Guardsman's uniform, all these +exalted personages passing in the streets in their elegant carriages +with their plumes, ribbons, and medals, both courtiers and military +men, seemed so immeasurably above him, an insignificant officer of the +Guards, that they not only did not wish to, but simply could not, be +aware of his existence. At the quarters of the commander in chief, +Kutuzov, where he inquired for Bolkonski, all the adjutants and even +the orderlies looked at him as if they wished to impress on him that a +great many officers like him were always coming there and that +everybody was heartily sick of them. In spite of this, or rather +because of it, next day, November 15, after dinner he again went to +Olmutz and, entering the house occupied by Kutuzov, asked for +Bolkonski. Prince Andrew was in and Boris was shown into a large +hall probably formerly used for dancing, but in which five beds now +stood, and furniture of various kinds: a table, chairs, and a +clavichord. One adjutant, nearest the door, was sitting at the table +in a Persian dressing gown, writing. Another, the red, stout +Nesvitski, lay on a bed with his arms under his head, laughing with an +officer who had sat down beside him. A third was playing a Viennese +waltz on the clavichord, while a fourth, lying on the clavichord, sang +the tune. Bolkonski was not there. None of these gentlemen changed his +position on seeing Boris. The one who was writing and whom Boris +addressed turned round crossly and told him Bolkonski was on duty +and that he should go through the door on the left into the +reception room if he wished to see him. Boris thanked him and went +to the reception room, where he found some ten officers and generals. + +When he entered, Prince Andrew, his eyes drooping contemptuously +(with that peculiar expression of polite weariness which plainly says, +"If it were not my duty I would not talk to you for a moment"), was +listening to an old Russian general with decorations, who stood very +erect, almost on tiptoe, with a soldier's obsequious expression on his +purple face, reporting something. + +"Very well, then, be so good as to wait," said Prince Andrew to +the general, in Russian, speaking with the French intonation he +affected when he wished to speak contemptuously, and noticing Boris, +Prince Andrew, paying no more heed to the general who ran after him +imploring him to hear something more, nodded and turned to him with +a cheerful smile. + +At that moment Boris clearly realized what he had before surmised, +that in the army, besides the subordination and discipline +prescribed in the military code, which he and the others knew in the +regiment, there was another, more important, subordination, which made +this tight-laced, purple-faced general wait respectfully while Captain +Prince Andrew, for his own pleasure, chose to chat with Lieutenant +Drubetskoy. More than ever was Boris resolved to serve in future not +according to the written code, but under this unwritten law. He felt +now that merely by having been recommended to Prince Andrew he had +already risen above the general who at the front had the power to +annihilate him, a lieutenant of the Guards. Prince Andrew came up to +him and took his hand. + + +"I am very sorry you did not find me in yesterday. I was fussing +about with Germans all day. We went with Weyrother to survey the +dispositions. When Germans start being accurate, there's no end to +it!" + +Boris smiled, as if he understood what Prince Andrew was alluding to +as something generally known. But it the first time he had heard +Weyrother's name, or even the term "dispositions." + +"Well, my dear fellow, so you still want to be an adjutant? I have +been thinking about you." + +"Yes, I was thinking"--for some reason Boris could not help +blushing--"of asking the commander in chief. He has had a letter +from Prince Kuragin about me. I only wanted to ask because I fear +the Guards won't be in action," he added as if in apology. + +"All right, all right. We'll talk it over," replied Prince Andrew. +"Only let me report this gentleman's business, and I shall be at +your disposal." + +While Prince Andrew went to report about the purple-faced general, +that gentleman--evidently not sharing Boris' conception of the +advantages of the unwritten code of subordination--looked so fixedly +at the presumptuous lieutenant who had prevented his finishing what he +had to say to the adjutant that Boris felt uncomfortable. He turned +away and waited impatiently for Prince Andrew's return from the +commander in chief's room. + +"You see, my dear fellow, I have been thinking about you," said +Prince Andrew when they had gone into the large room where the +clavichord was. "It's no use your going to the commander in chief. +He would say a lot of pleasant things, ask you to dinner" ("That would +not be bad as regards the unwritten code," thought Boris), "but +nothing more would come of it. There will soon be a battalion of us +aides-de-camp and adjutants! But this is what we'll do: I have a +good friend, an adjutant general and an excellent fellow, Prince +Dolgorukov; and though you may not know it, the fact is that now +Kutuzov with his staff and all of us count for nothing. Everything +is now centered round the Emperor. So we will go to Dolgorukov; I have +to go there anyhow and I have already spoken to him about you. We +shall see whether he cannot attach you to himself or find a place +for you somewhere nearer the sun." + +Prince Andrew always became specially keen when he had to guide a +young man and help him to worldly success. Under cover of obtaining +help of this kind for another, which from pride he would never +accept for himself, he kept in touch with the circle which confers +success and which attracted him. He very readily took up Boris' +cause and went with him to Dolgorukov. + +It was late in the evening when they entered the palace at Olmutz +occupied by the Emperors and their retinues. + +That same day a council of war had been held in which all the +members of the Hofkriegsrath and both Emperors took part. At that +council, contrary to the views of the old generals Kutuzov and +Prince Schwartzenberg, it had been decided to advance immediately +and give battle to Bonaparte. The council of war was just over when +Prince Andrew accompanied by Boris arrived at the palace to find +Dolgorukov. Everyone at headquarters was still under the spell of +the day's council, at which the party of the young had triumphed. +The voices of those who counseled delay and advised waiting for +something else before advancing had been so completely silenced and +their arguments confuted by such conclusive evidence of the advantages +of attacking that what had been discussed at the council--the coming +battle and the victory that would certainly result from it--no +longer seemed to be in the future but in the past. All the +advantages were on our side. Our enormous forces, undoubtedly superior +to Napoleon's, were concentrated in one place, the troops inspired +by the Emperors' presence were eager for action. The strategic +position where the operations would take place was familiar in all its +details to the Austrian General Weyrother: a lucky accident had +ordained that the Austrian army should maneuver the previous year on +the very fields where the French had now to be fought; the adjacent +locality was known and shown in every detail on the maps, and +Bonaparte, evidently weakened, was undertaking nothing. + +Dolgorukov, one of the warmest advocates of an attack, had just +returned from the council, tired and exhausted but eager and proud +of the victory that had been gained. Prince Andrew introduced his +protege, but Prince Dolgorukov politely and firmly pressing his hand +said nothing to Boris and, evidently unable to suppress the thoughts +which were uppermost in his mind at that moment, addressed Prince +Andrew in French. + +"Ah, my dear fellow, what a battle we have gained! God grant that +the one that will result from it will be as victorious! However, +dear fellow," he said abruptly and eagerly, "I must confess to +having been unjust to the Austrians and especially to Weyrother. +What exactitude, what minuteness, what knowledge of the locality, what +foresight for every eventuality, every possibility even to the +smallest detail! No, my dear fellow, no conditions better than our +present ones could have been devised. This combination of Austrian +precision with Russian valor--what more could be wished for?" + +"So the attack is definitely resolved on?" asked Bolkonski. + +"And do you know, my dear fellow, it seems to me that Bonaparte +has decidedly lost bearings, you know that a letter was received +from him today for the Emperor." Dolgorukov smiled significantly. + +"Is that so? And what did he say?" inquired Bolkonski. + +"What can he say? Tra-di-ri-di-ra and so on... merely to gain +time. I tell you he is in our hands, that's certain! But what was most +amusing," he continued, with a sudden, good-natured laugh, "was that +we could not think how to address the reply! If not as 'Consul' and of +course not as 'Emperor,' it seemed to me it should be to 'General +Bonaparte.'" + +"But between not recognizing him as Emperor and calling him +General Bonaparte, there is a difference," remarked Bolkonski. + +"That's just it," interrupted Dolgorukov quickly, laughing. "You +know Bilibin--he's a very clever fellow. He suggested addressing him +as 'Usurper and Enemy of Mankind.'" + +Dolgorukov laughed merrily. + +"Only that?" said Bolkonski. + +"All the same, it was Bilibin who found a suitable form for the +address. He is a wise and clever fellow." + +"What was it?" + +"To the Head of the French Government... Au chef du gouvernement +francais," said Dolgorukov, with grave satisfaction. "Good, wasn't +it?" + +"Yes, but he will dislike it extremely," said Bolkonski. + +"Oh yes, very much! My brother knows him, he's dined with him--the +present Emperor--more than once in Paris, and tells me he never met +a more cunning or subtle diplomatist--you know, a combination of +French adroitness and Italian play-acting! Do you know the tale +about him and Count Markov? Count Markov was the only man who knew how +to handle him. You know the story of the handkerchief? It is +delightful!" + +And the talkative Dolgorukov, turning now to Boris, now to Prince +Andrew, told how Bonaparte wishing to test Markov, our ambassador, +purposely dropped a handkerchief in front of him and stood looking +at Markov, probably expecting Markov to pick it up for him, and how +Markov immediately dropped his own beside it and picked it up +without touching Bonaparte's. + +"Delightful!" said Bolkonski. "But I have come to you, Prince, as +a petitioner on behalf of this young man. You see..." but before +Prince Andrew could finish, an aide-de-camp came in to summon +Dolgorukov to the Emperor. + +"Oh, what a nuisance," said Dolgorukov, getting up hurriedly and +pressing the hands of Prince Andrew and Boris. "You know I should be +very glad to do all in my power both for you and for this dear young +man." Again he pressed the hand of the latter with an expression of +good-natured, sincere, and animated levity. "But you see... another +time!" + +Boris was excited by the thought of being so close to the higher +powers as he felt himself to be at that moment. He was conscious +that here he was in contact with the springs that set in motion the +enormous movements of the mass of which in his regiment he felt +himself a tiny, obedient, and insignificant atom. They followed Prince +Dolgorukov out into the corridor and met--coming out of the door of +the Emperor's room by which Dolgorukov had entered--a short man in +civilian clothes with a clever face and sharply projecting jaw +which, without spoiling his face, gave him a peculiar vivacity and +shiftiness of expression. This short man nodded to Dolgorukov as to an +intimate friend and stared at Prince Andrew with cool intensity, +walking straight toward him and evidently expecting him to bow or to +step out of his way. Prince Andrew did neither: a look of animosity +appeared on his face and the other turned away and went down the +side of the corridor. + +"Who was that?" asked Boris. + +"He is one of the most remarkable, but to me most unpleasant of men- +the Minister of Foreign Affairs, Prince Adam Czartoryski.... It is +such men as he who decide the fate of nations," added Bolkonski with a +sigh he could not suppress, as they passed out of the palace. + +Next day, the army began its campaign, and up to the very battle +of Austerlitz, Boris was unable to see either Prince Andrew or +Dolgorukov again and remained for a while with the Ismaylov regiment. + + + + + +CHAPTER X + + +At dawn on the sixteenth of November, Denisov's squadron, in which +Nicholas Rostov served and which was in Prince Bagration's detachment, +moved from the place where it had spent the night, advancing into +action as arranged, and after going behind other columns for about two +thirds of a mile was stopped on the highroad. Rostov saw the +Cossacks and then the first and second squadrons of hussars and +infantry battalions and artillery pass by and go forward and then +Generals Bagration and Dolgorukov ride past with their adjutants. +All the fear before action which he had experienced as previously, all +the inner struggle to conquer that fear, all his dreams of +distinguishing himself as a true hussar in this battle, had been +wasted. Their squadron remained in reserve and Nicholas Rostov spent +that day in a dull and wretched mood. At nine in the morning, he heard +firing in front and shouts of hurrah, and saw wounded being brought +back (there were not many of them), and at last he saw how a whole +detachment of French cavalry was brought in, convoyed by a sontnya +of Cossacks. Evidently the affair was over and, though not big, had +been a successful engagement. The men and officers returning spoke +of a brilliant victory, of the occupation of the town of Wischau and +the capture of a whole French squadron. The day was bright and sunny +after a sharp night frost, and the cheerful glitter of that autumn day +was in keeping with the news of victory which was conveyed, not only +by the tales of those who had taken part in it, but also by the joyful +expression on the faces of soldiers, officers, generals, and +adjutants, as they passed Rostov going or coming. And Nicholas, who +had vainly suffered all the dread that precedes a battle and had spent +that happy day in inactivity, was all the more depressed. + +"Come here, Wostov. Let's dwink to dwown our gwief!" shouted +Denisov, who had settled down by the roadside with a flask and some +food. + +The officers gathered round Denisov's canteen, eating and talking. + +"There! They are bringing another!" cried one of the officers, +indicating a captive French dragoon who was being brought in on foot +by two Cossacks. + +One of them was leading by the bridle a fine large French horse he +had taken from the prisoner. + +"Sell us that horse!" Denisov called out to the Cossacks. + +"If you like, your honor!" + +The officers got up and stood round the Cossacks and their prisoner. +The French dragoon was a young Alsatian who spoke French with a German +accent. He was breathless with agitation, his face was red, and when +he heard some French spoken he at once began speaking to the officers, +addressing first one, then another. He said he would not have been +taken, it was not his fault but the corporal's who had sent him to +seize some horsecloths, though he had told him the Russians were +there. And at every word he added: "But don't hurt my little horse!" +and stroked the animal. It was plain that he did not quite grasp where +he was. Now he excused himself for having been taken prisoner and now, +imagining himself before his own officers, insisted on his soldierly +discipline and zeal in the service. He brought with him into our +rearguard all the freshness of atmosphere of the French army, which +was so alien to us. + +The Cossacks sold the horse for two gold pieces, and Rostov, being +the richest of the officers now that he had received his money, bought +it. + +"But don't hurt my little horse!" said the Alsatian good-naturedly +to Rostov when the animal was handed over to the hussar. + +Rostov smilingly reassured the dragoon and gave him money. + +"Alley! Alley!" said the Cossack, touching the prisoner's arm to +make him go on. + +"The Emperor! The Emperor!" was suddenly heard among the hussars. + +All began to run and bustle, and Rostov saw coming up the road +behind him several riders with white plumes in their hats. In a moment +everyone was in his place, waiting. + +Rostov did not know or remember how he ran to his place and mounted. +Instantly his regret at not having been in action and his dejected +mood amid people of whom he was weary had gone, instantly every +thought of himself had vanished. He was filled with happiness at his +nearness to the Emperor. He felt that this nearness by itself made +up to him for the day he had lost. He was happy as a lover when the +longed-for moment of meeting arrives. Not daring to look round and +without looking round, he was ecstatically conscious of his +approach. He felt it not only from the sound of the hoofs of the +approaching cavalcade, but because as he drew near everything grew +brighter, more joyful, more significant, and more festive around +him. Nearer and nearer to Rostov came that sun shedding beams of +mild and majestic light around, and already he felt himself +enveloped in those beams, he heard his voice, that kindly, calm, and +majestic voice that was yet so simple! And as if in accord with +Rostov's feeling, there was a deathly stillness amid which was heard +the Emperor's voice. + +"The Pavlograd hussars?" he inquired. + +"The reserves, sire!" replied a voice, a very human one compared +to that which had said: "The Pavlograd hussars?" + +The Emperor drew level with Rostov and halted. Alexander's face +was even more beautiful than it had been three days before at the +review. It shone with such gaiety and youth, such innocent youth, that +it suggested the liveliness of a fourteen-year-old boy, and yet it was +the face of the majestic Emperor. Casually, while surveying the +squadron, the Emperor's eyes met Rostov's and rested on them for not +more than two seconds. Whether or no the Emperor understood what was +going on in Rostov's soul (it seemed to Rostov that he understood +everything), at any rate his light-blue eyes gazed for about two +seconds into Rostov's face. A gentle, mild light poured from them. +Then all at once he raised his eyebrows, abruptly touched his horse +with his left foot, and galloped on. + +The younger Emperor could not restrain his wish to be present at the +battle and, in spite of the remonstrances of his courtiers, at +twelve o'clock left the third column with which he had been and +galloped toward the vanguard. Before he came up with the hussars, +several adjutants met him with news of the successful result of the +action. + +This battle, which consisted in the capture of a French squadron, +was represented as a brilliant victory over the French, and so the +Emperor and the whole army, especially while the smoke hung over the +battlefield, believed that the French had been defeated and were +retreating against their will. A few minutes after the Emperor had +passed, the Pavlograd division was ordered to advance. In Wischau +itself, a petty German town, Rostov saw the Emperor again. In the +market place, where there had been some rather heavy firing before the +Emperor's arrival, lay several killed and wounded soldiers whom +there had not been time to move. The Emperor, surrounded by his +suite of officers and courtiers, was riding a bobtailed chestnut mare, +a different one from that which he had ridden at the review, and +bending to one side he gracefully held a gold lorgnette to his eyes +and looked at a soldier who lay prone, with blood on his uncovered +head. The wounded soldier was so dirty, coarse, and revolting that his +proximity to the Emperor shocked Rostov. Rostov saw how the +Emperor's rather round shoulders shuddered as if a cold shiver had run +down them, how his left foot began convulsively tapping the horse's +side with the spur, and how the well-trained horse looked round +unconcerned and did not stir. An adjutant, dismounting, lifted the +soldier under the arms to place him on a stretcher that had been +brought. The soldier groaned. + +"Gently, gently! Can't you do it more gently?" said the Emperor +apparently suffering more than the dying soldier, and he rode away. + +Rostov saw tears filling the Emperor's eyes and heard him, as he was +riding away, say to Czartoryski: "What a terrible thing war is: what a +terrible thing! Quelle terrible chose que la guerre!" + +The troops of the vanguard were stationed before Wischau, within +sight of the enemy's lines, which all day long had yielded ground to +us at the least firing. The Emperor's gratitude was announced to the +vanguard, rewards were promised, and the men received a double +ration of vodka. The campfires crackled and the soldiers' songs +resounded even more merrily than on the previous night. Denisov +celebrated his promotion to the rank of major, and Rostov, who had +already drunk enough, at the end of the feast proposed the Emperor's +health. "Not 'our Sovereign, the Emperor,' as they say at official +dinners," said he, "but the health of our Sovereign, that good, +enchanting, and great man! Let us drink to his health and to the +certain defeat of the French!" + +"If we fought before," he said, "not letting the French pass, as +at Schon Grabern, what shall we not do now when he is at the front? We +will all die for him gladly! Is it not so, gentlemen? Perhaps I am not +saying it right, I have drunk a good deal--but that is how I feel, and +so do you too! To the health of Alexander the First! Hurrah!" + +"Hurrah!" rang the enthusiastic voices of the officers. + +And the old cavalry captain, Kirsten, shouted enthusiastically and +no less sincerely than the twenty-year-old Rostov. + +When the officers had emptied and smashed their glasses, Kirsten +filled others and, in shirt sleeves and breeches, went glass in hand +to the soldiers' bonfires and with his long gray mustache, his white +chest showing under his open shirt, he stood in a majestic pose in the +light of the campfire, waving his uplifted arm. + +"Lads! here's to our Sovereign, the Emperor, and victory over our +enemies! Hurrah!" he exclaimed in his dashing, old, hussar's baritone. + +The hussars crowded round and responded heartily with loud shouts. + +Late that night, when all had separated, Denisov with his short hand +patted his favorite, Rostov, on the shoulder. + +"As there's no one to fall in love with on campaign, he's fallen +in love with the Tsar," he said. + +"Denisov, don't make fun of it!" cried Rostov. "It is such a +lofty, beautiful feeling, such a..." + +"I believe it, I believe it, fwiend, and I share and appwove..." + +"No, you don't understand!" + +And Rostov got up and went wandering among the campfires, dreaming +of what happiness it would be to die--not in saving the Emperor's life +(he did not even dare to dream of that), but simply to die before +his eyes. He really was in love with the Tsar and the glory of the +Russian arms and the hope of future triumph. And he was not the only +man to experience that feeling during those memorable days preceding +the battle of Austerlitz: nine tenths of the men in the Russian army +were then in love, though less ecstatically, with their Tsar and the +glory of the Russian arms. + + + + + +CHAPTER XI + + +The next day the Emperor stopped at Wischau, and Villier, his +physician, was repeatedly summoned to see him. At headquarters and +among the troops near by the news spread that the Emperor was +unwell. He ate nothing and had slept badly that night, those around +him reported. The cause of this indisposition was the strong +impression made on his sensitive mind by the sight of the killed and +wounded. + +At daybreak on the seventeenth, a French officer who had come with a +flag of truce, demanding an audience with the Russian Emperor, was +brought into Wischau from our outposts. This officer was Savary. The +Emperor had only just fallen asleep and so Savary had to wait. At +midday he was admitted to the Emperor, and an hour later he rode off +with Prince Dolgorukov to the advanced post of the French army. + +It was rumored that Savary had been sent to propose to Alexander a +meeting with Napoleon. To the joy and pride of the whole army, a +personal interview was refused, and instead of the Sovereign, Prince +Dolgorukov, the victor at Wischau, was sent with Savary to negotiate +with Napoleon if, contrary to expectations, these negotiations were +actuated by a real desire for peace. + +Toward evening Dolgorukov came back, went straight to the Tsar, +and remained alone with him for a long time. + +On the eighteenth and nineteenth of November, the army advanced +two days' march and the enemy's outposts after a brief interchange +of shots retreated. In the highest army circles from midday on the +nineteenth, a great, excitedly bustling activity began which lasted +till the morning of the twentieth, when the memorable battle of +Austerlitz was fought. + +Till midday on the nineteenth, the activity--the eager talk, running +to and fro, and dispatching of adjutants--was confined to the +Emperor's headquarters. But on the afternoon of that day, this +activity reached Kutuzov's headquarters and the staffs of the +commanders of columns. By evening, the adjutants had spread it to +all ends and parts of the army, and in the night from the nineteenth +to the twentieth, the whole eighty thousand allied troops rose from +their bivouacs to the hum of voices, and the army swayed and started +in one enormous mass six miles long. + +The concentrated activity which had begun at the Emperor's +headquarters in the morning and had started the whole movement that +followed was like the first movement of the main wheel of a large +tower clock. One wheel slowly moved, another was set in motion, and +a third, and wheels began to revolve faster and faster, levers and +cogwheels to work, chimes to play, figures to pop out, and the hands +to advance with regular motion as a result of all that activity. + +Just as in the mechanism of a clock, so in the mechanism of the +military machine, an impulse once given leads to the final result; and +just as indifferently quiescent till the moment when motion is +transmitted to them are the parts of the mechanism which the impulse +has not yet reached. Wheels creak on their axles as the cogs engage +one another and the revolving pulleys whirr with the rapidity of their +movement, but a neighboring wheel is as quiet and motionless as though +it were prepared to remain so for a hundred years; but the moment +comes when the lever catches it and obeying the impulse that wheel +begins to creak and joins in the common motion the result and aim of +which are beyond its ken. + +Just as in a clock, the result of the complicated motion of +innumerable wheels and pulleys is merely a slow and regular movement +of the hands which show the time, so the result of all the complicated +human activities of 160,000 Russians and French--all their passions, +desires, remorse, humiliations, sufferings, outbursts of pride, +fear, and enthusiasm--was only the loss of the battle of Austerlitz, +the so-called battle of the three Emperors--that is to say, a slow +movement of the hand on the dial of human history. + +Prince Andrew was on duty that day and in constant attendance on the +commander in chief. + +At six in the evening, Kutuzov went to the Emperor's headquarters +and after staying but a short time with the Tsar went to see the grand +marshal of the court, Count Tolstoy. + +Bolkonski took the opportunity to go in to get some details of the +coming action from Dolgorukov. He felt that Kutuzov was upset and +dissatisfied about something and that at headquarters they were +dissatisfied with him, and also that at the Emperor's headquarters +everyone adopted toward him the tone of men who know something +others do not know: he therefore wished to speak to Dolgorukov. + +"Well, how d'you do, my dear fellow?" said Dolgorukov, who was +sitting at tea with Bilibin. "The fete is for tomorrow. How is your +old fellow? Out of sorts?" + +"I won't say he is out of sorts, but I fancy he would like to be +heard." + +"But they heard him at the council of war and will hear him when +he talks sense, but to temporize and wait for something now when +Bonaparte fears nothing so much as a general battle is impossible." + +"Yes, you have seen him?" said Prince Andrew. "Well, what is +Bonaparte like? How did he impress you?" + +"Yes, I saw him, and am convinced that he fears nothing so much as a +general engagement," repeated Dolgorukov, evidently prizing this +general conclusion which he had arrived at from his interview with +Napoleon. "If he weren't afraid of a battle why did he ask for that +interview? Why negotiate, and above all why retreat, when to retreat +is so contrary to his method of conducting war? Believe me, he is +afraid, afraid of a general battle. His hour has come! Mark my words!" + +"But tell me, what is he like, eh?" said Prince Andrew again. + +"He is a man in a gray overcoat, very anxious that I should call him +'Your Majesty,' but who, to his chagrin, got no title from me! +That's the sort of man he is, and nothing more," replied Dolgorukov, +looking round at Bilibin with a smile. + +"Despite my great respect for old Kutuzov," he continued, "we should +be a nice set of fellows if we were to wait about and so give him a +chance to escape, or to trick us, now that we certainly have him in +our hands! No, we mustn't forget Suvorov and his rule--not to put +yourself in a position to be attacked, but yourself to attack. Believe +me in war the energy of young men often shows the way better than +all the experience of old Cunctators." + +"But in what position are we going to attack him? I have been at the +outposts today and it is impossible to say where his chief forces +are situated," said Prince Andrew. + +He wished to explain to Dolgorukov a plan of attack he had himself +formed. + +"Oh, that is all the same," Dolgorukov said quickly, and getting +up he spread a map on the table. "All eventualities have been +foreseen. If he is standing before Brunn..." + +And Prince Dolgorukov rapidly but indistinctly explained Weyrother's +plan of a flanking movement. + +Prince Andrew began to reply and to state his own plan, which +might have been as good as Weyrother's, but for the disadvantage +that Weyrother's had already been approved. As soon as Prince Andrew +began to demonstrate the defects of the latter and the merits of his +own plan, Prince Dolgorukov ceased to listen to him and gazed +absent-mindedly not at the map, but at Prince Andrew's face. + +"There will be a council of war at Kutuzov's tonight, though; you +can say all this there," remarked Dolgorukov. + +"I will do so," said Prince Andrew, moving away from the map. + +"Whatever are you bothering about, gentlemen?" said Bilibin, who, +till then, had listened with an amused smile to their conversation and +now was evidently ready with a joke. "Whether tomorrow brings +victory or defeat, the glory of our Russian arms is secure. Except +your Kutuzov, there is not a single Russian in command of a column! +The commanders are: Herr General Wimpfen, le Comte de Langeron, le +Prince de Lichtenstein, le Prince, de Hohenlohe, and finally +Prishprish, and so on like all those Polish names." + +"Be quiet, backbiter!" said Dolgorukov. "It is not true; there are +now two Russians, Miloradovich, and Dokhturov, and there would be a +third, Count Arakcheev, if his nerves were not too weak." + +"However, I think General Kutuzov has come out," said Prince Andrew. +"I wish you good luck and success, gentlemen!" he added and went out +after shaking hands with Dolgorukov and Bilibin. + +On the way home, Prince Andrew could not refrain from asking +Kutuzov, who was sitting silently beside him, what he thought of +tomorrow's battle. + +Kutuzov looked sternly at his adjutant and, after a pause, +replied: "I think the battle will be lost, and so I told Count Tolstoy +and asked him to tell the Emperor. What do you think he replied? 'But, +my dear general, I am engaged with rice and cutlets, look after +military matters yourself!' Yes... That was the answer I got!" + + + + + +CHAPTER XII + + +Shortly after nine o'clock that evening, Weyrother drove with his +plans to Kutuzov's quarters where the council of war was to be held. +All the commanders of columns were summoned to the commander in +chief's and with the exception of Prince Bagration, who declined to +come, were all there at the appointed time. + +Weyrother, who was in full control of the proposed battle, by his +eagerness and briskness presented a marked contrast to the +dissatisfied and drowsy Kutuzov, who reluctantly played the part of +chairman and president of the council of war. Weyrother evidently felt +himself to be at the head of a movement that had already become +unrestrainable. He was like a horse running downhill harnessed to a +heavy cart. Whether he was pulling it or being pushed by it he did not +know, but rushed along at headlong speed with no time to consider what +this movement might lead to. Weyrother had been twice that evening +to the enemy's picket line to reconnoiter personally, and twice to the +Emperors, Russian and Austrian, to report and explain, and to his +headquarters where he had dictated the dispositions in German, and +now, much exhausted, he arrived at Kutuzov's. + +He was evidently so busy that he even forgot to be polite to the +commander in chief. He interrupted him, talked rapidly and +indistinctly, without looking at the man he was addressing, and did +not reply to questions put to him. He was bespattered with mud and had +a pitiful, weary, and distracted air, though at the same time he was +haughty and self-confident. + +Kutuzov was occupying a nobleman's castle of modest dimensions +near Ostralitz. In the large drawing room which had become the +commander in chief's office were gathered Kutuzov himself, +Weyrother, and the members of the council of war. They were drinking +tea, and only awaited Prince Bagration to begin the council. At last +Bagration's orderly came with the news that the prince could not +attend. Prince Andrew came in to inform the commander in chief of this +and, availing himself of permission previously given him by Kutuzov to +be present at the council, he remained in the room. + +"Since Prince Bagration is not coming, we may begin," said +Weyrother, hurriedly rising from his seat and going up to the table on +which an enormous map of the environs of Brunn was spread out. + +Kutuzov, with his uniform unbuttoned so that his fat neck bulged +over his collar as if escaping, was sitting almost asleep in a low +chair, with his podgy old hands resting symmetrically on its arms. +At the sound of Weyrother's voice, he opened his one eye with an +effort. + + +"Yes, yes, if you please! It is already late," said he, and +nodding his head he let it droop and again closed his eye. + +If at first the members of the council thought that Kutuzov was +pretending to sleep, the sounds his nose emitted during the reading +that followed proved that the commander in chief at that moment was +absorbed by a far more serious matter than a desire to show his +contempt for the dispositions or anything else--he was engaged in +satisfying the irresistible human need for sleep. He really was +asleep. Weyrother, with the gesture of a man too busy to lose a +moment, glanced at Kutuzov and, having convinced himself that he was +asleep, took up a paper and in a loud, monotonous voice began to +read out the dispositions for the impending battle, under a heading +which he also read out: + +"Dispositions for an attack on the enemy position behind Kobelnitz +and Sokolnitz, November 30, 1805." + +The dispositions were very complicated and difficult. They began +as follows: + +"As the enemy's left wing rests on wooded hills and his right +extends along Kobelnitz and Sokolnitz behind the ponds that are there, +while we, on the other hand, with our left wing by far outflank his +right, it is advantageous to attack the enemy's latter wing especially +if we occupy the villages of Sokolnitz and Kobelnitz, whereby we can +both fall on his flank and pursue him over the plain between +Schlappanitz and the Thuerassa forest, avoiding the defiles of +Schlappanitz and Bellowitz which cover the enemy's front. For this +object it is necessary that... The first column marches... The +second column marches... The third column marches..." and so on, +read Weyrother. + +The generals seemed to listen reluctantly to the difficult +dispositions. The tall, fair-haired General Buxhowden stood, leaning +his back against the wall, his eyes fixed on a burning candle, and +seemed not to listen or even to wish to be thought to listen. +Exactly opposite Weyrother, with his glistening wide-open eyes fixed +upon him and his mustache twisted upwards, sat the ruddy +Miloradovich in a military pose, his elbows turned outwards, his hands +on his knees, and his shoulders raised. He remained stubbornly silent, +gazing at Weyrother's face, and only turned away his eyes when the +Austrian chief of staff finished reading. Then Miloradovich looked +round significantly at the other generals. But one could not tell from +that significant look whether he agreed or disagreed and was satisfied +or not with the arrangements. Next to Weyrother sat Count Langeron +who, with a subtle smile that never left his typically southern French +face during the whole time of the reading, gazed at his delicate +fingers which rapidly twirled by its corners a gold snuffbox on +which was a portrait. In the middle of one of the longest sentences, +he stopped the rotary motion of the snuffbox, raised his head, and +with inimical politeness lurking in the corners of his thin lips +interrupted Weyrother, wishing to say something. But the Austrian +general, continuing to read, frowned angrily and jerked his elbows, as +if to say: "You can tell me your views later, but now be so good as to +look at the map and listen." Langeron lifted his eyes with an +expression of perplexity, turned round to Miloradovich as if seeking +an explanation, but meeting the latter's impressive but meaningless +gaze drooped his eyes sadly and again took to twirling his snuffbox. + +"A geography lesson!" he muttered as if to himself, but loud +enough to be heard. + +Przebyszewski, with respectful but dignified politeness, held his +hand to his ear toward Weyrother, with the air of a man absorbed in +attention. Dohkturov, a little man, sat opposite Weyrother, with an +assiduous and modest mien, and stooping over the outspread map +conscientiously studied the dispositions and the unfamiliar +locality. He asked Weyrother several times to repeat words he had +not clearly heard and the difficult names of villages. Weyrother +complied and Dohkturov noted them down. + +When the reading which lasted more than an hour was over, Langeron +again brought his snuffbox to rest and, without looking at Weyrother +or at anyone in particular, began to say how difficult it was to carry +out such a plan in which the enemy's position was assumed to be known, +whereas it was perhaps not known, since the enemy was in movement. +Langeron's objections were valid but it was obvious that their chief +aim was to show General Weyrother--who had read his dispositions +with as much self-confidence as if he were addressing school children- +that he had to do, not with fools, but with men who could teach him +something in military matters. + +When the monotonous sound of Weyrother's voice ceased, Kutuzov +opened his eye as a miller wakes up when the soporific drone of the +mill wheel is interrupted. He listened to what Langeron said, as if +remarking, "So you are still at that silly business!" quickly closed +his eye again, and let his head sink still lower. + +Langeron, trying as virulently as possible to sting Weyrother's +vanity as author of the military plan, argued that Bonaparte might +easily attack instead of being attacked, and so render the whole of +this plan perfectly worthless. Weyrother met all objections with a +firm and contemptuous smile, evidently prepared beforehand to meet all +objections be they what they might. + +"If he could attack us, he would have done so today," said he. + +"So you think he is powerless?" said Langeron. + +"He has forty thousand men at most," replied Weyrother, with the +smile of a doctor to whom an old wife wishes to explain the +treatment of a case. + +"In that case he is inviting his doom by awaiting our attack," +said Langeron, with a subtly ironical smile, again glancing round +for support to Miloradovich who was near him. + +But Miloradovich was at that moment evidently thinking of anything +rather than of what the generals were disputing about. + +"Ma foi!" said he, "tomorrow we shall see all that on the +battlefield." + +Weyrother again gave that smile which seemed to say that to him it +was strange and ridiculous to meet objections from Russian generals +and to have to prove to them what he had not merely convinced +himself of, but had also convinced the sovereign Emperors of. + +"The enemy has quenched his fires and a continual noise is heard +from his camp," said he. "What does that mean? Either he is +retreating, which is the only thing we need fear, or he is changing +his position." (He smiled ironically.) "But even if he also took up +a position in the Thuerassa, he merely saves us a great deal of +trouble and all our arrangements to the minutest detail remain the +same." + +"How is that?..." began Prince Andrew, who had for long been waiting +an opportunity to express his doubts. + +Kutuzov here woke up, coughed heavily, and looked round at the +generals. + +"Gentlemen, the dispositions for tomorrow--or rather for today, +for it is past midnight--cannot now be altered," said he. "You have +heard them, and we shall all do our duty. But before a battle, there +is nothing more important..." he paused, "than to have a good sleep." + +He moved as if to rise. The generals bowed and retired. It was +past midnight. Prince Andrew went out. + + +The council of war, at which Prince Andrew had not been able to +express his opinion as he had hoped to, left on him a vague and uneasy +impression. Whether Dolgorukov and Weyrother, or Kutuzov, Langeron, +and the others who did not approve of the plan of attack, were +right--he did not know. "But was it really not possible for Kutuzov to +state his views plainly to the Emperor? Is it possible that on account +of court and personal considerations tens of thousands of lives, and +my life, my life," he thought, "must be risked?" + +"Yes, it is very likely that I shall be killed tomorrow," he +thought. And suddenly, at this thought of death, a whole series of +most distant, most intimate, memories rose in his imagination: he +remembered his last parting from his father and his wife; he +remembered the days when he first loved her. He thought of her +pregnancy and felt sorry for her and for himself, and in a nervously +emotional and softened mood he went out of the hut in which he was +billeted with Nesvitski and began to walk up and down before it. + +The night was foggy and through the fog the moonlight gleamed +mysteriously. "Yes, tomorrow, tomorrow!" he thought. "Tomorrow +everything may be over for me! All these memories will be no more, +none of them will have any meaning for me. Tomorrow perhaps, even +certainly, I have a presentiment that for the first time I shall +have to show all I can do." And his fancy pictured the battle, its +loss, the concentration of fighting at one point, and the hesitation +of all the commanders. And then that happy moment, that Toulon for +which he had so long waited, presents itself to him at last. He firmly +and clearly expresses his opinion to Kutuzov, to Weyrother, and to the +Emperors. All are struck by the justness of his views, but no one +undertakes to carry them out, so he takes a regiment, a division- +stipulates that no one is to interfere with his arrangements--leads +his division to the decisive point, and gains the victory alone. +"But death and suffering?" suggested another voice. Prince Andrew, +however, did not answer that voice and went on dreaming of his +triumphs. The dispositions for the next battle are planned by him +alone. Nominally he is only an adjutant on Kutuzov's staff, but he +does everything alone. The next battle is won by him alone. Kutuzov is +removed and he is appointed... "Well and then?" asked the other voice. +"If before that you are not ten times wounded, killed, or betrayed, +well... what then?..." "Well then," Prince Andrew answered himself, "I +don't know what will happen and don't want to know, and can't, but +if I want this--want glory, want to be known to men, want to be +loved by them, it is not my fault that I want it and want nothing +but that and live only for that. Yes, for that alone! I shall never +tell anyone, but, oh God! what am I to do if I love nothing but fame +and men's esteem? Death, wounds, the loss of family--I fear nothing. +And precious and dear as many persons are to me--father, sister, wife- +those dearest to me--yet dreadful and unnatural as it seems, I would +give them all at once for a moment of glory, of triumph over men, of +love from men I don't know and never shall know, for the love of these +men here," he thought, as he listened to voices in Kutuzov's +courtyard. The voices were those of the orderlies who were packing up; +one voice, probably a coachman's, was teasing Kutuzov's old cook +whom Prince Andrew knew, and who was called Tit. He was saying, +"Tit, I say, Tit!" + +"Well?" returned the old man. + +"Go, Tit, thresh a bit!" said the wag. + +"Oh, go to the devil!" called out a voice, drowned by the laughter +of the orderlies and servants. + +"All the same, I love and value nothing but triumph over them all, I +value this mystic power and glory that is floating here above me in +this mist!" + + + + + +CHAPTER XIII + + +That same night, Rostov was with a platoon on skirmishing duty in +front of Bagration's detachment. His hussars were placed along the +line in couples and he himself rode along the line trying to master +the sleepiness that kept coming over him. An enormous space, with +our army's campfires dimly glowing in the fog, could be seen behind +him; in front of him was misty darkness. Rostov could see nothing, +peer as he would into that foggy distance: now something gleamed gray, +now there was something black, now little lights seemed to glimmer +where the enemy ought to be, now he fancied it was only something in +his own eyes. His eyes kept closing, and in his fancy appeared--now +the Emperor, now Denisov, and now Moscow memories--and he again +hurriedly opened his eyes and saw close before him the head and ears +of the horse he was riding, and sometimes, when he came within six +paces of them, the black figures of hussars, but in the distance was +still the same misty darkness. "Why not?... It might easily happen," +thought Rostov, "that the Emperor will meet me and give me an order as +he would to any other officer; he'll say: 'Go and find out what's +there.' There are many stories of his getting to know an officer in +just such a chance way and attaching him to himself! What if he gave +me a place near him? Oh, how I would guard him, how I would tell him +the truth, how I would unmask his deceivers!" And in order to +realize vividly his love devotion to the sovereign, Rostov pictured to +himself an enemy or a deceitful German, whom he would not only kill +with pleasure but whom he would slap in the face before the Emperor. +Suddenly a distant shout aroused him. He started and opened his eyes. + +"Where am I? Oh yes, in the skirmishing line... pass and +watchword--shaft, Olmutz. What a nuisance that our squadron will be in +reserve tomorrow," he thought. "I'll ask leave to go to the front, +this may be my only chance of seeing the Emperor. It won't be long now +before I am off duty. I'll take another turn and when I get back +I'll go to the general and ask him." He readjusted himself in the +saddle and touched up his horse to ride once more round his hussars. +It seemed to him that it was getting lighter. To the left he saw a +sloping descent lit up, and facing it a black knoll that seemed as +steep as a wall. On this knoll there was a white patch that Rostov +could not at all make out: was it a glade in the wood lit up by the +moon, or some unmelted snow, or some white houses? He even thought +something moved on that white spot. "I expect it's snow... that +spot... a spot--une tache," he thought. "There now... it's not a +tache... Natasha... sister, black eyes... Na... tasha... (Won't she be +surprised when I tell her how I've seen the Emperor?) Natasha... +take my sabretache..."--"Keep to the right, your honor, there are +bushes here," came the voice of an hussar, past whom Rostov was riding +in the act of falling asleep. Rostov lifted his head that had sunk +almost to his horse's mane and pulled up beside the hussar. He was +succumbing to irresistible, youthful, childish drowsiness. "But what +was I thinking? I mustn't forget. How shall I speak to the Emperor? +No, that's not it--that's tomorrow. Oh yes! Natasha... sabretache... +saber them...Whom? The hussars... Ah, the hussars with mustaches. +Along the Tverskaya Street rode the hussar with mustaches... I thought +about him too, just opposite Guryev's house... Old Guryev.... Oh, +but Denisov's a fine fellow. But that's all nonsense. The chief +thing is that the Emperor is here. How he looked at me and wished to +say something, but dared not.... No, it was I who dared not. But +that's nonsense, the chief thing is not to forget the important +thing I was thinking of. Yes, Na-tasha, sabretache, oh, yes, yes! +That's right!" And his head once more sank to his horse's neck. All at +once it seemed to him that he was being fired at. "What? What? +What?... Cut them down! What?..." said Rostov, waking up. At the +moment he opened his eyes he heard in front of him, where the +enemy was, the long-drawn shouts of thousands of voices. His horse and +the horse of the hussar near him pricked their ears at these shouts. +Over there, where the shouting came from, a fire flared up and went +out again, then another, and all along the French line on the hill +fires flared up and the shouting grew louder and louder. Rostov +could hear the sound of French words but could not distinguish them. +The din of many voices was too great; all he could hear was: "ahahah!" +and "rrrr!" + +"What's that? What do you make of it?" said Rostov to the hussar +beside him. "That must be the enemy's camp!" + +The hussar did not reply. + +"Why, don't you hear it?" Rostov asked again, after waiting for a +reply. + +"Who can tell, your honor?" replied the hussar reluctantly. + +"From the direction, it must be the enemy," repeated Rostov. + +"It may be he or it may be nothing," muttered the hussar. "It's +dark... Steady!" he cried to his fidgeting horse. + +Rostov's horse was also getting restive: it pawed the frozen ground, +pricking its ears at the noise and looking at the lights. The shouting +grew still louder and merged into a general roar that only an army +of several thousand men could produce. The lights spread farther and +farther, probably along the line of the French camp. Rostov no +longer wanted to sleep. The gay triumphant shouting of the enemy +army had a stimulating effect on him. "Vive l'Empereur! L'Empereur!" +he now heard distinctly. + +"They can't be far off, probably just beyond the stream," he said to +the hussar beside him. + +The hussar only sighed without replying and coughed angrily. The +sound of horse's hoofs approaching at a trot along the line of hussars +was heard, and out of the foggy darkness the figure of a sergeant of +hussars suddenly appeared, looming huge as an elephant. + +"Your honor, the generals!" said the sergeant, riding up to Rostov. + +Rostov, still looking round toward the fires and the shouts, rode +with the sergeant to meet some mounted men who were riding along the +line. One was on a white horse. Prince Bagration and Prince Dolgorukov +with their adjutants had come to witness the curious phenomenon of the +lights and shouts in the enemy's camp. Rostov rode up to Bagration, +reported to him, and then joined the adjutants listening to what the +generals were saying. + +"Believe me," said Prince Dolgorukov, addressing Bagration, "it is +nothing but a trick! He has retreated and ordered the rearguard to +kindle fires and make a noise to deceive us." + +"Hardly," said Bagration. "I saw them this evening on that knoll; if +they had retreated they would have withdrawn from that too.... +Officer!" said Bagration to Rostov, "are the enemy's skirmishers still +there?" + +"They were there this evening, but now I don't know, your +excellency. Shall I go with some of my hussars to see?" replied +Rostov. + +Bagration stopped and, before replying, tried to see Rostov's face +in the mist. + +"Well, go and see," he said, after a pause. + +"Yes, sir." + +Rostov spurred his horse, called to Sergeant Fedchenko and two other +hussars, told them to follow him, and trotted downhill in the +direction from which the shouting came. He felt both frightened and +pleased to be riding alone with three hussars into that mysterious and +dangerous misty distance where no one had been before him. Bagration +called to him from the hill not to go beyond the stream, but Rostov +pretended not to hear him and did not stop but rode on and on, +continually mistaking bushes for trees and gullies for men and +continually discovering his mistakes. Having descended the hill at a +trot, he no longer saw either our own or the enemy's fires, but +heard the shouting of the French more loudly and distinctly. In the +valley he saw before him something like a river, but when he reached +it he found it was a road. Having come out onto the road he reined +in his horse, hesitating whether to ride along it or cross it and ride +over the black field up the hillside. To keep to the road which +gleamed white in the mist would have been safer because it would be +easier to see people coming along it. "Follow me!" said he, crossed +the road, and began riding up the hill at a gallop toward the point +where the French pickets had been standing that evening. + +"Your honor, there he is!" cried one of the hussars behind him. +And before Rostov had time to make out what the black thing was that +had suddenly appeared in the fog, there was a flash, followed by a +report, and a bullet whizzing high up in the mist with a plaintive +sound passed out of hearing. Another musket missed fire but flashed in +the pan. Rostov turned his horse and galloped back. Four more +reports followed at intervals, and the bullets passed somewhere in the +fog singing in different tones. Rostov reined in his horse, whose +spirits had risen, like his own, at the firing, and went back at a +footpace. "Well, some more! Some more!" a merry voice was saying in +his soul. But no more shots came. + +Only when approaching Bagration did Rostov let his horse gallop +again, and with his hand at the salute rode up to the general. + +Dolgorukov was still insisting that the French had retreated and had +only lit fires to deceive us. + +"What does that prove?" he was saying as Rostov rode up. "They might +retreat and leave the pickets." + +"It's plain that they have not all gone yet, Prince," said +Bagration. "Wait till tomorrow morning, we'll find out everything +tomorrow." + +"The picket is still on the hill, your excellency, just where it was +in the evening," reported Rostov, stooping forward with his hand at +the salute and unable to repress the smile of delight induced by his +ride and especially by the sound of the bullets. + +"Very good, very good," said Bagration. "Thank you, officer." + +"Your excellency," said Rostov, "may I ask a favor?" + +"What is it?" + +"Tomorrow our squadron is to be in reserve. May I ask to be attached +to the first squadron?" + +"What's your name?" + +"Count Rostov." + +"Oh, very well, you may stay in attendance on me." + +"Count Ilya Rostov's son?" asked Dolgorukov. + +But Rostov did not reply. + +"Then I may reckon on it, your excellency?" + +"I will give the order." + +"Tomorrow very likely I may be sent with some message to the +Emperor," thought Rostov. + +"Thank God!" + + +The fires and shouting in the enemy's army were occasioned by the +fact that while Napoleon's proclamation was being read to the troops +the Emperor himself rode round his bivouacs. The soldiers, on seeing +him, lit wisps of straw and ran after him, shouting, "Vive +l'Empereur!" Napoleon's proclamation was as follows: + + +Soldiers! The Russian army is advancing against you to avenge the +Austrian army of Ulm. They are the same battalions you broke at +Hollabrunn and have pursued ever since to this place. The position +we occupy is a strong one, and while they are marching to go round +me on the right they will expose a flank to me. Soldiers! I will +myself direct your battalions. I will keep out of fire if you with +your habitual valor carry disorder and confusion into the enemy's +ranks, but should victory be in doubt, even for a moment, you will see +your Emperor exposing himself to the first blows of the enemy, for +there must be no doubt of victory, especially on this day when what is +at stake is the honor of the French infantry, so necessary to the +honor of our nation. + +Do not break your ranks on the plea of removing the wounded! Let +every man be fully imbued with the thought that we must defeat these +hirelings of England, inspired by such hatred of our nation! This +victory will conclude our campaign and we can return to winter +quarters, where fresh French troops who are being raised in France +will join us, and the peace I shall conclude will be worthy of my +people, of you, and of myself. + +NAPOLEON + + + + + +CHAPTER XIV + + +At five in the morning it was still quite dark. The troops of the +center, the reserves, and Bagration's right flank had not yet moved, +but on the left flank the columns of infantry, cavalry, and artillery, +which were to be the first to descend the heights to attack the French +right flank and drive it into the Bohemian mountains according to +plan, were already up and astir. The smoke of the campfires, into +which they were throwing everything superfluous, made the eyes +smart. It was cold and dark. The officers were hurriedly drinking +tea and breakfasting, the soldiers, munching biscuit and beating a +tattoo with their feet to warm themselves, gathering round the fires +throwing into the flames the remains of sheds, chairs, tables, wheels, +tubs, and everything that they did not want or could not carry away +with them. Austrian column guides were moving in and out among the +Russian troops and served as heralds of the advance. As soon as an +Austrian officer showed himself near a commanding officer's +quarters, the regiment began to move: the soldiers ran from the fires, +thrust their pipes into their boots, their bags into the carts, got +their muskets ready, and formed rank. The officers buttoned up their +coats, buckled on their swords and pouches, and moved along the +ranks shouting. The train drivers and orderlies harnessed and packed +the wagons and tied on the loads. The adjutants and battalion and +regimental commanders mounted, crossed themselves, gave final +instructions, orders, and commissions to the baggage men who +remained behind, and the monotonous tramp of thousands of feet +resounded. The column moved forward without knowing where and +unable, from the masses around them, the smoke and the increasing fog, +to see either the place they were leaving or that to which they were +going. + +A soldier on the march is hemmed in and borne along by his +regiment as much as a sailor is by his ship. However far he has +walked, whatever strange, unknown, and dangerous places he reaches, +just as a sailor is always surrounded by the same decks, masts, and +rigging of his ship, so the soldier always has around him the same +comrades, the same ranks, the same sergeant major Ivan Mitrich, the +same company dog Jack, and the same commanders. The sailor rarely +cares to know the latitude in which his ship is sailing, but on the +day of battle--heaven knows how and whence--a stern note of which +all are conscious sounds in the moral atmosphere of an army, +announcing the approach of something decisive and solemn, and +awakening in the men an unusual curiosity. On the day of battle the +soldiers excitedly try to get beyond the interests of their +regiment, they listen intently, look about, and eagerly ask concerning +what is going on around them. + +The fog had grown so dense that though it was growing light they +could not see ten paces ahead. Bushes looked like gigantic trees and +level ground like cliffs and slopes. Anywhere, on any side, one +might encounter an enemy invisible ten paces off. But the columns +advanced for a long time, always in the same fog, descending and +ascending hills, avoiding gardens and enclosures, going over new and +unknown ground, and nowhere encountering the enemy. On the contrary, +the soldiers became aware that in front, behind, and on all sides, +other Russian columns were moving in the same direction. Every soldier +felt glad to know that to the unknown place where he was going, many +more of our men were going too. + +"There now, the Kurskies have also gone past," was being said in the +ranks. + +"It's wonderful what a lot of our troops have gathered, lads! Last +night I looked at the campfires and there was no end of them. A +regular Moscow!" + +Though none of the column commanders rode up to the ranks or +talked to the men (the commanders, as we saw at the council of war, +were out of humor and dissatisfied with the affair, and so did not +exert themselves to cheer the men but merely carried out the +orders), yet the troops marched gaily, as they always do when going +into action, especially to an attack. But when they had marched for +about an hour in the dense fog, the greater part of the men had to +halt and an unpleasant consciousness of some dislocation and blunder +spread through the ranks. How such a consciousness is communicated +is very difficult to define, but it certainly is communicated very +surely, and flows rapidly, imperceptibly, and irrepressibly, as +water does in a creek. Had the Russian army been alone without any +allies, it might perhaps have been a long time before this +consciousness of mismanagement became a general conviction, but as +it was, the disorder was readily and naturally attributed to the +stupid Germans, and everyone was convinced that a dangerous muddle had +been occasioned by the sausage eaters. + +"Why have we stopped? Is the way blocked? Or have we already come up +against the French?" + +"No, one can't hear them. They'd be firing if we had." + +"They were in a hurry enough to start us, and now here we stand in +the middle of a field without rhyme or reason. It's all those damned +Germans' muddling! What stupid devils!" + +"Yes, I'd send them on in front, but no fear, they're crowding up +behind. And now here we stand hungry." + +"I say, shall we soon be clear? They say the cavalry are blocking +the way," said an officer. + +"Ah, those damned Germans! They don't know their own country!" +said another. + +"What division are you?" shouted an adjutant, riding up. + +"The Eighteenth." + +"Then why are you here? You should have gone on long ago, now you +won't get there till evening." + +"What stupid orders! They don't themselves know what they are +doing!" said the officer and rode off. + +Then a general rode past shouting something angrily, not in Russian. + +"Tafa-lafa! But what he's jabbering no one can make out," said a +soldier, mimicking the general who had ridden away. "I'd shoot them, +the scoundrels!" + +"We were ordered to be at the place before nine, but we haven't +got halfway. Fine orders!" was being repeated on different sides. + +And the feeling of energy with which the troops had started began to +turn into vexation and anger at the stupid arrangements and at the +Germans. + +The cause of the confusion was that while the Austrian cavalry was +moving toward our left flank, the higher command found that our center +was too far separated from our right flank and the cavalry were all +ordered to turn back to the right. Several thousand cavalry crossed in +front of the infantry, who had to wait. + +At the front an altercation occurred between an Austrian guide and a +Russian general. The general shouted a demand that the cavalry +should be halted, the Austrian argued that not he, but the higher +command, was to blame. The troops meanwhile stood growing listless and +dispirited. After an hour's delay they at last moved on, descending +the hill. The fog that was dispersing on the hill lay still more +densely below, where they were descending. In front in the fog a +shot was heard and then another, at first irregularly at varying +intervals--trata... tat--and then more and more regularly and rapidly, +and the action at the Goldbach Stream began. + +Not expecting to come on the enemy down by the stream, and having +stumbled on him in the fog, hearing no encouraging word from their +commanders, and with a consciousness of being too late spreading +through the ranks, and above all being unable to see anything in front +or around them in the thick fog, the Russians exchanged shots with the +enemy lazily and advanced and again halted, receiving no timely orders +from the officers or adjutants who wandered about in the fog in +those unknown surroundings unable to find their own regiments. In this +way the action began for the first, second, and third columns, which +had gone down into the valley. The fourth column, with which Kutuzov +was, stood on the Pratzen Heights. + +Below, where the fight was beginning, there was still thick fog; +on the higher ground it was clearing, but nothing could be seen of +what was going on in front. Whether all the enemy forces were, as we +supposed, six miles away, or whether they were near by in that sea +of mist, no one knew till after eight o'clock. + +It was nine o'clock in the morning. The fog lay unbroken like a +sea down below, but higher up at the village of Schlappanitz where +Napoleon stood with his marshals around him, it was quite light. Above +him was a clear blue sky, and the sun's vast orb quivered like a +huge hollow, crimson float on the surface of that milky sea of mist. +The whole French army, and even Napoleon himself with his staff, +were not on the far side of the streams and hollows of Sokolnitz and +Schlappanitz beyond which we intended to take up our position and +begin the action, but were on this side, so close to our own forces +that Napoleon with the naked eye could distinguish a mounted man +from one on foot. Napoleon, in the blue cloak which he had worn on his +Italian campaign, sat on his small gray Arab horse a little in front +of his marshals. He gazed silently at the hills which seemed to rise +out of the sea of mist and on which the Russian troops were moving +in the distance, and he listened to the sounds of firing in the +valley. Not a single muscle of his face--which in those days was still +thin--moved. His gleaming eyes were fixed intently on one spot. His +predictions were being justified. Part of the Russian force had +already descended into the valley toward the ponds and lakes and +part were leaving these Pratzen Heights which he intended to attack +and regarded as the key to the position. He saw over the mist that +in a hollow between two hills near the village of Pratzen, the Russian +columns, their bayonets glittering, were moving continuously in one +direction toward the valley and disappearing one after another into +the mist. From information he had received the evening before, from +the sound of wheels and footsteps heard by the outposts during the +night, by the disorderly movement of the Russian columns, and from all +indications, he saw clearly that the allies believed him to be far +away in front of them, and that the columns moving near Pratzen +constituted the center of the Russian army, and that that center was +already sufficiently weakened to be successfully attacked. But still +he did not begin the engagement. + +Today was a great day for him--the anniversary of his coronation. +Before dawn he had slept for a few hours, and refreshed, vigorous, and +in good spirits, he mounted his horse and rode out into the field in +that happy mood in which everything seems possible and everything +succeeds. He sat motionless, looking at the heights visible above +the mist, and his cold face wore that special look of confident, +self-complacent happiness that one sees on the face of a boy happily +in love. The marshals stood behind him not venturing to distract his +attention. He looked now at the Pratzen Heights, now at the sun +floating up out of the mist. + +When the sun had entirely emerged from the fog, and fields and +mist were aglow with dazzling light--as if he had only awaited this to +begin the action--he drew the glove from his shapely white hand, +made a sign with it to the marshals, and ordered the action to +begin. The marshals, accompanied by adjutants, galloped off in +different directions, and a few minutes later the chief forces of +the French army moved rapidly toward those Pratzen Heights which +were being more and more denuded by Russian troops moving down the +valley to their left. + + + + + +CHAPTER XV + + +At eight o'clock Kutuzov rode to Pratzen at the head of the fourth +column, Miloradovich's, the one that was to take the place of +Przebyszewski's and Langeron's columns which had already gone down +into the valley. He greeted the men of the foremost regiment and +gave them the order to march, thereby indicating that he intended to +lead that column himself. When he had reached the village of Pratzen +he halted. Prince Andrew was behind, among the immense number +forming the commander in chief's suite. He was in a state of +suppressed excitement and irritation, though controlledly calm as a +man is at the approach of a long-awaited moment. He was firmly +convinced that this was the day of his Toulon, or his bridge of +Arcola. How it would come about he did not know, but he felt sure it +would do so. The locality and the position of our troops were known to +him as far as they could be known to anyone in our army. His own +strategic plan, which obviously could not now be carried out, was +forgotten. Now, entering into Weyrother's plan, Prince Andrew +considered possible contingencies and formed new projects such as +might call for his rapidity of perception and decision. + +To the left down below in the mist, the musketry fire of unseen +forces could be heard. It was there Prince Andrew thought the fight +would concentrate. "There we shall encounter difficulties, and there," +thought he, "I shall be sent with a brigade or division, and there, +standard in hand, I shall go forward and break whatever is in front of +me." + +He could not look calmly at the standards of the passing battalions. +Seeing them he kept thinking, "That may be the very standard with +which I shall lead the army." + +In the morning all that was left of the night mist on the heights +was a hoar frost now turning to dew, but in the valleys it still lay +like a milk-white sea. Nothing was visible in the valley to the left +into which our troops had descended and from whence came the sounds of +firing. Above the heights was the dark clear sky, and to the right the +vast orb of the sun. In front, far off on the farther shore of that +sea of mist, some wooded hills were discernible, and it was there +the enemy probably was, for something could be descried. On the +right the Guards were entering the misty region with a sound of +hoofs and wheels and now and then a gleam of bayonets; to the left +beyond the village similar masses of cavalry came up and disappeared +in the sea of mist. In front and behind moved infantry. The +commander in chief was standing at the end of the village letting +the troops pass by him. That morning Kutuzov seemed worn and +irritable. The infantry passing before him came to a halt without +any command being given, apparently obstructed by something in front. + +"Do order them to form into battalion columns and go round the +village!" he said angrily to a general who had ridden up. "Don't you +understand, your excellency, my dear sir, that you must not defile +through narrow village streets when we are marching against the +enemy?" + +"I intended to re-form them beyond the village, your excellency," +answered the general. + +Kutuzov laughed bitterly. + +"You'll make a fine thing of it, deploying in sight of the enemy! +Very fine!" + +"The enemy is still far away, your excellency. According to the +dispositions..." + +"The dispositions!" exclaimed Kutuzov bitterly. "Who told you +that?... Kindly do as you are ordered." + +"Yes, sir." + +"My dear fellow," Nesvitski whispered to Prince Andrew, "the old man +is as surly as a dog." + +An Austrian officer in a white uniform with green plumes in his +hat galloped up to Kutuzov and asked in the Emperor's name had the +fourth column advanced into action. + +Kutuzov turned round without answering and his eye happened to +fall upon Prince Andrew, who was beside him. Seeing him, Kutuzov's +malevolent and caustic expression softened, as if admitting that +what was being done was not his adjutant's fault, and still not +answering the Austrian adjutant, he addressed Bolkonski. + +"Go, my dear fellow, and see whether the third division has passed +the village. Tell it to stop and await my orders." + +Hardly had Prince Andrew started than he stopped him. + +"And ask whether sharpshooters have been posted," he added. "What +are they doing? What are they doing?" he murmured to himself, still +not replying to the Austrian. + +Prince Andrew galloped off to execute the order. + +Overtaking the battalions that continued to advance, he stopped +the third division and convinced himself that there really were no +sharpshooters in front of our columns. The colonel at the head of +the regiment was much surprised at the commander in chief's order to +throw out skirmishers. He had felt perfectly sure that there were +other troops in front of him and that the enemy must be at least six +miles away. There was really nothing to be seen in front except a +barren descent hidden by dense mist. Having given orders in the +commander in chief's name to rectify this omission, Prince Andrew +galloped back. Kutuzov still in the same place, his stout body resting +heavily in the saddle with the lassitude of age, sat yawning wearily +with closed eyes. The troops were no longer moving, but stood with the +butts of their muskets on the ground. + +"All right, all right!" he said to Prince Andrew, and turned to a +general who, watch in hand, was saying it was time they started as all +the left-flank columns had already descended. + +"Plenty of time, your excellency," muttered Kutuzov in the midst +of a yawn. "Plenty of time," he repeated. + +Just then at a distance behind Kutuzov was heard the sound of +regiments saluting, and this sound rapidly came nearer along the whole +extended line of the advancing Russian columns. Evidently the person +they were greeting was riding quickly. When the soldiers of the +regiment in front of which Kutuzov was standing began to shout, he +rode a little to one side and looked round with a frown. Along the +road from Pratzen galloped what looked like a squadron of horsemen +in various uniforms. Two of them rode side by side in front, at full +gallop. One in a black uniform with white plumes in his hat rode a +bobtailed chestnut horse, the other who was in a white uniform rode +a black one. These were the two Emperors followed by their suites. +Kutuzov, affecting the manners of an old soldier at the front, gave +the command "Attention!" and rode up to the Emperors with a salute. +His whole appearance and manner were suddenly transformed. He put on +the air of a subordinate who obeys without reasoning. With an +affectation of respect which evidently struck Alexander +unpleasantly, he rode up and saluted. + +This unpleasant impression merely flitted over the young and happy +face of the Emperor like a cloud of haze across a clear sky and +vanished. After his illness he looked rather thinner that day than +on the field of Olmutz where Bolkonski had seen him for the first time +abroad, but there was still the same bewitching combination of majesty +and mildness in his fine gray eyes, and on his delicate lips the +same capacity for varying expression and the same prevalent appearance +of goodhearted innocent youth. + +At the Olmutz review he had seemed more majestic; here he seemed +brighter and more energetic. He was slightly flushed after galloping +two miles, and reining in his horse he sighed restfully and looked +round at the faces of his suite, young and animated as his own. +Czartoryski, Novosiltsev, Prince Volkonsky, Strogonov, and the others, +all richly dressed gay young men on splendid, well-groomed, fresh, +only slightly heated horses, exchanging remarks and smiling, had +stopped behind the Emperor. The Emperor Francis, a rosy, long faced +young man, sat very erect on his handsome black horse, looking about +him in a leisurely and preoccupied manner. He beckoned to one of his +white adjutants and asked some question--"Most likely he is asking +at what o'clock they started," thought Prince Andrew, watching his old +acquaintance with a smile he could not repress as he recalled his +reception at Brunn. In the Emperors' suite were the picked young +orderly officers of the Guard and line regiments, Russian and +Austrian. Among them were grooms leading the Tsar's beautiful relay +horses covered with embroidered cloths. + +As when a window is opened a whiff of fresh air from the fields +enters a stuffy room, so a whiff of youthfulness, energy, and +confidence of success reached Kutuzov's cheerless staff with the +galloping advent of all these brilliant young men. + +"Why aren't you beginning, Michael Ilarionovich?" said the Emperor +Alexander hurriedly to Kutuzov, glancing courteously at the same +time at the Emperor Francis. + +"I am waiting, Your Majesty," answered Kutuzov, bending forward +respectfully. + +The Emperor, frowning slightly, bent his ear forward as if he had +not quite heard. + +"Waiting, Your Majesty," repeated Kutuzov. (Prince Andrew noted that +Kutuzov's upper lip twitched unnaturally as he said the word +"waiting.") "Not all the columns have formed up yet, Your Majesty." + +The Tsar heard but obviously did not like the reply; he shrugged his +rather round shoulders and glanced at Novosiltsev who was near him, as +if complaining of Kutuzov. + +"You know, Michael Ilarionovich, we are not on the +Empress' Field where a parade does not begin till all the troops are +assembled," said the Tsar with another glance at the Emperor +Francis, as if inviting him if not to join in at least to listen to +what he was saying. But the Emperor Francis continued to look about +him and did not listen. + +"That is just why I do not begin, sire," said Kutuzov in a +resounding voice, apparently to preclude the possibility of not +being heard, and again something in his face twitched--"That is just +why I do not begin, sire, because we are not on parade and not on +the Empress' Field." said clearly and distinctly. + +In the Emperor's suite all exchanged rapid looks that expressed +dissatisfaction and reproach. "Old though he may be, he should not, he +certainly should not, speak like that," their glances seemed to say. + +The Tsar looked intently and observantly into Kutuzov's eye +waiting to hear whether he would say anything more. But Kutuzov, +with respectfully bowed head, seemed also to be waiting. The silence +lasted for about a minute. + +"However, if you command it, Your Majesty," said Kutuzov, lifting +his head and again assuming his former tone of a dull, unreasoning, +but submissive general. + +He touched his horse and having called Miloradovich, the commander +of the column, gave him the order to advance. + +The troops again began to move, and two battalions of the Novgorod +and one of the Apsheron regiment went forward past the Emperor. + +As this Apsheron battalion marched by, the red-faced Miloradovich, +without his greatcoat, with his Orders on his breast and an enormous +tuft of plumes in his cocked hat worn on one side with its corners +front and back, galloped strenuously forward, and with a dashing +salute reined in his horse before the Emperor. + +"God be with you, general!" said the Emperor. + +"Ma foi, sire, nous ferons ce qui sera dans notre possibilite, +sire,"* he answered gaily, raising nevertheless ironic smiles among +the gentlemen of the Tsar's suite by his poor French. + + +*"Indeed, Sire, we shall do everything it is possible to do, Sire." + + +Miloradovich wheeled his horse sharply and stationed himself a +little behind the Emperor. The Apsheron men, excited by the Tsar's +presence, passed in step before the Emperors and their suites at a +bold, brisk pace. + +"Lads!" shouted Miloradovich in a loud, self-confident, and cheery +voice, obviously so elated by the sound of firing, by the prospect +of battle, and by the sight of the gallant Apsherons, his comrades +in Suvorov's time, now passing so gallantly before the Emperors, +that he forgot the sovereigns' presence. "Lads, it's not the first +village you've had to take," cried he. + +"Glad to do our best!" shouted the soldiers. + +The Emperor's horse started at the sudden cry. This horse that had +carried the sovereign at reviews in Russia bore him also here on the +field of Austerlitz, enduring the heedless blows of his left foot +and pricking its ears at the sound of shots just as it had done on the +Empress' Field, not understanding the significance of the firing, +nor of the nearness of the Emperor Francis' black cob, nor of all that +was being said, thought, and felt that day by its rider. + +The Emperor turned with a smile to one of his followers and made a +remark to him, pointing to the gallant Apsherons. + + + + + +CHAPTER XVI + + +Kutuzov accompanied by his adjutants rode at a walking pace behind +the carabineers. + +When he had gone less than half a mile in the rear of the column +he stopped at a solitary, deserted house that had probably once been +an inn, where two roads parted. Both of them led downhill and troops +were marching along both. + +The fog had begun to clear and enemy troops were already dimly +visible about a mile and a half off on the opposite heights. Down +below, on the left, the firing became more distinct. Kutuzov had +stopped and was speaking to an Austrian general. Prince Andrew, who +was a little behind looking at them, turned to an adjutant to ask +him for a field glass. + +"Look, look!" said this adjutant, looking not at the troops in the +distance, but down the hill before him. "It's the French!" + +The two generals and the adjutant took hold of the field glass, +trying to snatch it from one another. The expression on all their +faces suddenly changed to one of horror. The French were supposed to +be a mile and a half away, but had suddenly and unexpectedly +appeared just in front of us. + +"It's the enemy?... No!... Yes, see it is!... for certain.... But +how is that?" said different voices. + +With the naked eye Prince Andrew saw below them to the right, not +more than five hundred paces from where Kutuzov was standing, a +dense French column coming up to meet the Apsherons. + +"Here it is! The decisive moment has arrived. My turn has come," +thought Prince Andrew, and striking his horse he rode up to Kutuzov. + +"The Apsherons must be stopped, your excellency," cried he. But at +that very instant a cloud of smoke spread all round, firing was +heard quite close at hand, and a voice of naive terror barely two +steps from Prince Andrew shouted, "Brothers! All's lost!" And at +this as if at a command, everyone began to run. + +Confused and ever-increasing crowds were running back to where +five minutes before the troops had passed the Emperors. Not only would +it have been difficult to stop that crowd, it was even impossible +not to be carried back with it oneself. Bolkonski only tried not to +lose touch with it, and looked around bewildered and unable to grasp +what was happening in front of him. Nesvitski with an angry face, +red and unlike himself, was shouting to Kutuzov that if he did not +ride away at once he would certainly be taken prisoner. Kutuzov +remained in the same place and without answering drew out a +handkerchief. Blood was flowing from his cheek. Prince Andrew forced +his way to him. + +"You are wounded?" he asked, hardly able to master the trembling +of his lower jaw. + +"The wound is not here, it is there!" said Kutuzov, pressing the +handkerchief to his wounded cheek and pointing to the fleeing +soldiers. "Stop them!" he shouted, and at the same moment, probably +realizing that it was impossible to stop them, spurred his horse and +rode to the right. + +A fresh wave of the flying mob caught him and bore him back with it. + +The troops were running in such a dense mass that once surrounded by +them it was difficult to get out again. One was shouting, "Get on! Why +are you hindering us?" Another in the same place turned round and +fired in the air; a third was striking the horse Kutuzov himself rode. +Having by a great effort got away to the left from that flood of +men, Kutuzov, with his suite diminished by more than half, rode toward +a sound of artillery fire near by. Having forced his way out of the +crowd of fugitives, Prince Andrew, trying to keep near Kutuzov, saw on +the slope of the hill amid the smoke a Russian battery that was +still firing and Frenchmen running toward it. Higher up stood some +Russian infantry, neither moving forward to protect the battery nor +backward with the fleeing crowd. A mounted general separated himself +from the infantry and approached Kutuzov. Of Kutuzov's suite only four +remained. They were all pale and exchanged looks in silence. + +"Stop those wretches!" gasped Kutuzov to the regimental commander, +pointing to the flying soldiers; but at that instant, as if to +punish him for those words, bullets flew hissing across the regiment +and across Kutuzov's suite like a flock of little birds. + +The French had attacked the battery and, seeing Kutuzov, were firing +at him. After this volley the regimental commander clutched at his +leg; several soldiers fell, and a second lieutenant who was holding +the flag let it fall from his hands. It swayed and fell, but caught on +the muskets of the nearest soldiers. The soldiers started firing +without orders. + +"Oh! Oh! Oh!" groaned Kutuzov despairingly and looked around.... +"Bolkonski!" he whispered, his voice trembling from a consciousness of +the feebleness of age, "Bolkonski!" he whispered, pointing to the +disordered battalion and at the enemy, "what's that?" + +But before he had finished speaking, Prince Andrew, feeling tears of +shame and anger choking him, had already leapt from his horse and +run to the standard. + +"Forward, lads!" he shouted in a voice piercing as a child's. + +"Here it is!" thought he, seizing the staff of the standard and +hearing with pleasure the whistle of bullets evidently aimed at him. +Several soldiers fell. + +"Hurrah!" shouted Prince Andrew, and, scarcely able to hold up the +heavy standard, he ran forward with full confidence that the whole +battalion would follow him. + +And really he only ran a few steps alone. One soldier moved and then +another and soon the whole battalion ran forward shouting "Hurrah!" +and overtook him. A sergeant of the battalion ran up and took the flag +that was swaying from its weight in Prince Andrew's hands, but he +was immediately killed. Prince Andrew again seized the standard and, +dragging it by the staff, ran on with the battalion. In front he saw +our artillerymen, some of whom were fighting, while others, having +abandoned their guns, were running toward him. He also saw French +infantry soldiers who were seizing the artillery horses and turning +the guns round. Prince Andrew and the battalion were already within +twenty paces of the cannon. He heard the whistle of bullets above +him unceasingly and to right and left of him soldiers continually +groaned and dropped. But he did not look at them: he looked only at +what was going on in front of him--at the battery. He now saw +clearly the figure of a red-haired gunner with his shako knocked awry, +pulling one end of a mop while a French soldier tugged at the other. +He could distinctly see the distraught yet angry expression on the +faces of these two men, who evidently did not realize what they were +doing. + +"What are they about?" thought Prince Andrew as he gazed at them. +"Why doesn't the red-haired gunner run away as he is unarmed? Why +doesn't the Frenchman stab him? He will not get away before the +Frenchman remembers his bayonet and stabs him...." + +And really another French soldier, trailing his musket, ran up to +the struggling men, and the fate of the red-haired gunner, who had +triumphantly secured the mop and still did not realize what awaited +him, was about to be decided. But Prince Andrew did not see how it +ended. It seemed to him as though one of the soldiers near him hit him +on the head with the full swing of a bludgeon. It hurt a little, but +the worst of it was that the pain distracted him and prevented his +seeing what he had been looking at. + +"What's this? Am I falling? My legs are giving way," thought he, and +fell on his back. He opened his eyes, hoping to see how the struggle +of the Frenchmen with the gunners ended, whether the red-haired gunner +had been killed or not and whether the cannon had been captured or +saved. But he saw nothing. Above him there was now nothing but the +sky--the lofty sky, not clear yet still immeasurably lofty, with +gray clouds gliding slowly across it. "How quiet, peaceful, and +solemn; not at all as I ran," thought Prince Andrew--"not as we ran, +shouting and fighting, not at all as the gunner and the Frenchman with +frightened and angry faces struggled for the mop: how differently do +those clouds glide across that lofty infinite sky! How was it I did +not see that lofty sky before? And how happy I am to have found it +at last! Yes! All is vanity, all falsehood, except that infinite +sky. There is nothing, nothing, but that. But even it does not +exist, there is nothing but quiet and peace. Thank God!..." + + + + + +CHAPTER XVII + + +On our right flank commanded by Bagration, at nine o'clock the +battle had not yet begun. Not wishing to agree to Dolgorukov's +demand to commence the action, and wishing to avert responsibility +from himself, Prince Bagration proposed to Dolgorukov to send to +inquire of the commander in chief. Bagration knew that as the distance +between the two flanks was more than six miles, even if the +messenger were not killed (which he very likely would be), and found +the commander in chief (which would be very difficult), he would not +be able to get back before evening. + +Bagration cast his large, expressionless, sleepy eyes round his +suite, and the boyish face Rostov, breathless with excitement and +hope, was the first to catch his eye. He sent him. + +"And if I should meet His Majesty before I meet the commander in +chief, your excellency?" said Rostov, with his hand to his cap. + +"You can give the message to His Majesty," said Dolgorukov, +hurriedly interrupting Bagration. + +On being relieved from picket duty Rostov had managed to get a few +hours' sleep before morning and felt cheerful, bold, and resolute, +with elasticity of movement, faith in his good fortune, and +generally in that state of mind which makes everything seem +possible, pleasant, and easy. + +All his wishes were being fulfilled that morning: there was to be +a general engagement in which he was taking part, more than that, he +was orderly to the bravest general, and still more, he was going +with a message to Kutuzov, perhaps even to the sovereign himself. +The morning was bright, he had a good horse under him, and his heart +was full of joy and happiness. On receiving the order he gave his +horse the rein and galloped along the line. At first he rode along the +line of Bagration's troops, which had not yet advanced into action but +were standing motionless; then he came to the region occupied by +Uvarov's cavalry and here he noticed a stir and signs of preparation +for battle; having passed Uvarov's cavalry he clearly heard the +sound of cannon and musketry ahead of him. The firing grew louder +and louder. + +In the fresh morning air were now heard, not two or three musket +shots at irregular intervals as before, followed by one or two +cannon shots, but a roll of volleys of musketry from the slopes of the +hill before Pratzen, interrupted by such frequent reports of cannon +that sometimes several of them were not separated from one another but +merged into a general roar. + +He could see puffs of musketry smoke that seemed to chase one +another down the hillsides, and clouds of cannon smoke rolling, +spreading, and mingling with one another. He could also, by the +gleam of bayonets visible through the smoke, make out moving masses of +infantry and narrow lines of artillery with green caissons. + +Rostov stopped his horse for a moment on a hillock to see what was +going on, but strain his attention as he would he could not understand +or make out anything of what was happening: there in the smoke men +of some sort were moving about, in front and behind moved lines of +troops; but why, whither, and who they were, it was impossible to make +out. These sights and sounds had no depressing or intimidating +effect on him; on the contrary, they stimulated his energy and +determination. + +"Go on! Go on! Give it them!" he mentally exclaimed at these sounds, +and again proceeded to gallop along the line, penetrating farther +and farther into the region where the army was already in action. + +"How it will be there I don't know, but all will be well!" thought +Rostov. + +After passing some Austrian troops he noticed that the next part +of the line (the Guards) was already in action. + +"So much the better! I shall see it close," he thought. + +He was riding almost along the front line. A handful of men came +galloping toward him. They were our Uhlans who with disordered ranks +were returning from the attack. Rostov got out of their way, +involuntarily noticed that one of them was bleeding, and galloped on. + +"That is no business of mine," he thought. He had not ridden many +hundred yards after that before he saw to his left, across the whole +width of the field, an enormous mass of cavalry in brilliant white +uniforms, mounted on black horses, trotting straight toward him and +across his path. Rostov put his horse to full gallop to get out of the +way of these men, and he would have got clear had they continued at +the same speed, but they kept increasing their pace, so that some of +the horses were already galloping. Rostov heard the thud of their +hoofs and the jingle of their weapons and saw their horses, their +figures, and even their faces, more and more distinctly. They were our +Horse Guards, advancing to attack the French cavalry that was coming +to meet them. + +The Horse Guards were galloping, but still holding in their +horses. Rostov could already see their faces and heard the command: +"Charge!" shouted by an officer who was urging his thoroughbred to +full speed. Rostov, fearing to be crushed or swept into the attack +on the French, galloped along the front as hard as his horse could go, +but still was not in time to avoid them. + +The last of the Horse Guards, a huge pockmarked fellow, frowned +angrily on seeing Rostov before him, with whom he would inevitably +collide. This Guardsman would certainly have bowled Rostov and his +Bedouin over (Rostov felt himself quite tiny and weak compared to +these gigantic men and horses) had it not occurred to Rostov to +flourish his whip before the eyes of the Guardsman's horse. The +heavy black horse, sixteen hands high, shied, throwing back its +ears; but the pockmarked Guardsman drove his huge spurs in +violently, and the horse, flourishing its tail and extending its neck, +galloped on yet faster. Hardly had the Horse Guards passed Rostov +before he heard them shout, "Hurrah!" and looking back saw that +their foremost ranks were mixed up with some foreign cavalry with +red epaulets, probably French. He could see nothing more, for +immediately afterwards cannon began firing from somewhere and smoke +enveloped everything. + +At that moment, as the Horse Guards, having passed him, +disappeared in the smoke, Rostov hesitated whether to gallop after +them or to go where he was sent. This was the brilliant charge of +the Horse Guards that amazed the French themselves. Rostov was +horrified to hear later that of all that mass of huge and handsome +men, of all those brilliant, rich youths, officers and cadets, who had +galloped past him on their thousand-ruble horses, only eighteen were +left after the charge. + +"Why should I envy them? My chance is not lost, and maybe I shall +see the Emperor immediately!" thought Rostov and galloped on. + +When he came level with the Foot Guards he noticed that about them +and around them cannon balls were flying, of which he was aware not so +much because he heard their sound as because he saw uneasiness on +the soldiers' faces and unnatural warlike solemnity on those of the +officers. + +Passing behind one of the lines of a regiment of Foot Guards he +heard a voice calling him by name. + +"Rostov!" + +"What?" he answered, not recognizing Boris. + +"I say, we've been in the front line! Our regiment attacked!" said +Boris with the happy smile seen on the faces of young men who have +been under fire for the first time. + +Rostov stopped. + +"Have you?" he said. "Well, how did it go?" + +"We drove them back!" said Boris with animation, growing +talkative. "Can you imagine it?" and he began describing how the +Guards, having taken up their position and seeing troops before +them, thought they were Austrians, and all at once discovered from the +cannon balls discharged by those troops that they were themselves in +the front line and had unexpectedly to go into action. Rostov +without hearing Boris to the end spurred his horse. + +"Where are you off to?" asked Boris. + +"With a message to His Majesty." + +"There he is!" said Boris, thinking Rostov had said "His +Highness," and pointing to the Grand Duke who with his high +shoulders and frowning brows stood a hundred paces away from them in +his helmet and Horse Guards' jacket, shouting something to a pale, +white uniformed Austrian officer. + +"But that's the Grand Duke, and I want the commander in chief or the +Emperor," said Rostov, and was about to spur his horse. + +"Count! Count!" shouted Berg who ran up from the other side as eager +as Boris. "Count! I am wounded in my right hand" (and he showed his +bleeding hand with a handkerchief tied round it) "and I remained at +the front. I held my sword in my left hand, Count. All our family--the +von Bergs--have been knights!" + +He said something more, but Rostov did not wait to hear it and +rode away. + +Having passed the Guards and traversed an empty space, Rostov, to +avoid again getting in front of the first line as he had done when the +Horse Guards charged, followed the line of reserves, going far round +the place where the hottest musket fire and cannonade were heard. +Suddenly he heard musket fire quite close in front of him and behind +our troops, where he could never have expected the enemy to be. + +"What can it be?" he thought. "The enemy in the rear of our army? +Impossible!" And suddenly he was seized by a panic of fear for himself +and for the issue of the whole battle. "But be that what it may," he +reflected, "there is no riding round it now. I must look for the +commander in chief here, and if all is lost it is for me to perish +with the rest." + +The foreboding of evil that had suddenly come over Rostov was more +and more confirmed the farther he rode into the region behind the +village of Pratzen, which was full of troops of all kinds. + +"What does it mean? What is it? Whom are they firing at? Who is +firing?" Rostov kept asking as he came up to Russian and Austrian +soldiers running in confused crowds across his path. + +"The devil knows! They've killed everybody! It's all up now!" he was +told in Russian, German, and Czech by the crowd of fugitives who +understood what was happening as little as he did. + +"Kill the Germans!" shouted one. + +"May the devil take them--the traitors!" + +"Zum Henker diese Russen!"* muttered a German. + + +*"Hang these Russians!" + + +Several wounded men passed along the road, and words of abuse, +screams, and groans mingled in a general hubbub, then the firing +died down. Rostov learned later that Russian and Austrian soldiers had +been firing at one another. + +"My God! What does it all mean?" thought he. "And here, where at any +moment the Emperor may see them.... But no, these must be only a +handful of scoundrels. It will soon be over, it can't be that, it +can't be! Only to get past them quicker, quicker!" + +The idea of defeat and flight could not enter Rostov's head. +Though he saw French cannon and French troops on the Pratzen Heights +just where he had been ordered to look for the commander in chief, +he could not, did not wish to, believe that. + + + + + +CHAPTER XVIII + + +Rostov had been ordered to look for Kutuzov and the Emperor near the +village of Pratzen. But neither they nor a single commanding officer +were there, only disorganized crowds of troops of various kinds. He +urged on his already weary horse to get quickly past these crowds, but +the farther he went the more disorganized they were. The highroad on +which he had come out was thronged with caleches, carriages of all +sorts, and Russian and Austrian soldiers of all arms, some wounded and +some not. This whole mass droned and jostled in confusion under the +dismal influence of cannon balls flying from the French batteries +stationed on the Pratzen Heights. + +"Where is the Emperor? Where is Kutuzov?" Rostov kept asking +everyone he could stop, but got no answer from anyone. + +At last seizing a soldier by his collar he forced him to answer. + +"Eh, brother! They've all bolted long ago!" said the soldier, +laughing for some reason and shaking himself free. + +Having left that soldier who was evidently drunk, Rostov stopped the +horse of a batman or groom of some important personage and began to +question him. The man announced that the Tsar had been driven in a +carriage at full speed about an hour before along that very road and +that he was dangerously wounded. + +"It can't be!" said Rostov. "It must have been someone else." + +"I saw him myself." replied the man with a self-confident smile of +derision. "I ought to know the Emperor by now, after the times I've +seen him in Petersburg. I saw him just as I see you.... There he sat +in the carriage as pale as anything. How they made the four black +horses fly! Gracious me, they did rattle past! It's time I knew the +Imperial horses and Ilya Ivanych. I don't think Ilya drives anyone +except the Tsar!" + +Rostov let go of the horse and was about to ride on, when a +wounded officer passing by addressed him: + +"Who is it you want?" he asked. "The commander in chief? He was +killed by a cannon ball--struck in the breast before our regiment." + +"Not killed--wounded!" another officer corrected him. + +"Who? Kutuzov?" asked Rostov. + +"Not Kutuzov, but what's his name--well, never mind... there are not +many left alive. Go that way, to that village, all the commanders +are there," said the officer, pointing to the village of Hosjeradek, +and he walked on. + +Rostov rode on at a footpace not knowing why or to whom he was now +going. The Emperor was wounded, the battle lost. It was impossible +to doubt it now. Rostov rode in the direction pointed out to him, in +which he saw turrets and a church. What need to hurry? What was he now +to say to the Tsar or to Kutuzov, even if they were alive and +unwounded? + +"Take this road, your honor, that way you will be killed at once!" a +soldier shouted to him. "They'd kill you there!" + +"Oh, what are you talking about?" said another. "Where is he to +go? That way is nearer." + +Rostov considered, and then went in the direction where they said he +would be killed. + +"It's all the same now. If the Emperor is wounded, am I to try to +save myself?" he thought. He rode on to the region where the +greatest number of men had perished in fleeing from Pratzen. The +French had not yet occupied that region, and the Russians--the +uninjured and slightly wounded--had left it long ago. All about the +field, like heaps of manure on well-kept plowland, lay from ten to +fifteen dead and wounded to each couple of acres. The wounded crept +together in twos and threes and one could hear their distressing +screams and groans, sometimes feigned--or so it seemed to Rostov. He +put his horse to a trot to avoid seeing all these suffering men, and +he felt afraid--afraid not for his life, but for the courage he needed +and which he knew would not stand the sight of these unfortunates. + +The French, who had ceased firing at this field strewn with dead and +wounded where there was no one left to fire at, on seeing an +adjutant riding over it trained a gun on him and fired several +shots. The sensation of those terrible whistling sounds and of the +corpses around him merged in Rostov's mind into a single feeling of +terror and pity for himself. He remembered his mother's last letter. +"What would she feel," thought he, "if she saw me here now on this +field with the cannon aimed at me?" + +In the village of Hosjeradek there were Russian troops retiring from +the field of battle, who though still in some confusion were less +disordered. The French cannon did not reach there and the musketry +fire sounded far away. Here everyone clearly saw and said that the +battle was lost. No one whom Rostov asked could tell him where the +Emperor or Kutuzov was. Some said the report that the Emperor was +wounded was correct, others that it was not, and explained the false +rumor that had spread by the fact that the Emperor's carriage had +really galloped from the field of battle with the pale and terrified +Ober-Hofmarschal Count Tolstoy, who had ridden out to the +battlefield with others in the Emperor's suite. One officer told +Rostov that he had seen someone from headquarters behind the village +to the left, and thither Rostov rode, not hoping to find anyone but +merely to ease his conscience. When he had ridden about two miles +and had passed the last of the Russian troops, he saw, near a +kitchen garden with a ditch round it, two men on horseback facing +the ditch. One with a white plume in his hat seemed familiar to +Rostov; the other on a beautiful chestnut horse (which Rostov +fancied he had seen before) rode up to the ditch, struck his horse +with his spurs, and giving it the rein leaped lightly over. Only a +little earth crumbled from the bank under the horse's hind hoofs. +Turning the horse sharply, he again jumped the ditch, and +deferentially addressed the horseman with the white plumes, +evidently suggesting that he should do the same. The rider, whose +figure seemed familiar to Rostov and involuntarily riveted his +attention, made a gesture of refusal with his head and hand and by +that gesture Rostov instantly recognized his lamented and adored +monarch. + +"But it can't be he, alone in the midst of this empty field!" +thought Rostov. At that moment Alexander turned his head and Rostov +saw the beloved features that were so deeply engraved on his memory. +The Emperor was pale, his cheeks sunken and his eyes hollow, but the +charm, the mildness of his features, was all the greater. Rostov was +happy in the assurance that the rumors about the Emperor being wounded +were false. He was happy to be seeing him. He knew that he might and +even ought to go straight to him and give the message Dolgorukov had +ordered him to deliver. + +But as a youth in love trembles, is unnerved, and dares not utter +the thoughts he has dreamed of for nights, but looks around for help +or a chance of delay and flight when the longed-for moment comes and +he is alone with her, so Rostov, now that he had attained what he +had longed for more than anything else in the world, did not know +how to approach the Emperor, and a thousand reasons occurred to him +why it would be inconvenient, unseemly, and impossible to do so. + +"What! It is as if I were glad of a chance to take advantage of +his being alone and despondent! A strange face may seem unpleasant +or painful to him at this moment of sorrow; besides, what can I say to +him now, when my heart fails me and my mouth feels dry at the mere +sight of him?" Not one of the innumerable speeches addressed to the +Emperor that he had composed in his imagination could he now recall. +Those speeches were intended for quite other conditions, they were for +the most part to be spoken at a moment of victory and triumph, +generally when he was dying of wounds and the sovereign had thanked +him for heroic deeds, and while dying he expressed the love his +actions had proved. + +"Besides how can I ask the Emperor for his instructions for the +right flank now that it is nearly four o'clock and the battle is lost? +No, certainly I must not approach him, I must not intrude on his +reflections. Better die a thousand times than risk receiving an unkind +look or bad opinion from him," Rostov decided; and sorrowfully and +with a heart full despair he rode away, continually looking back at +the Tsar, who still remained in the same attitude of indecision. + +While Rostov was thus arguing with himself and riding sadly away, +Captain von Toll chanced to ride to the same spot, and seeing the +Emperor at once rode up to him, offered his services, and assisted him +to cross the ditch on foot. The Emperor, wishing to rest and feeling +unwell, sat down under an apple tree and von Toll remained beside him. +Rostov from a distance saw with envy and remorse how von Toll spoke +long and warmly to the Emperor and how the Emperor, evidently weeping, +covered his eyes with his hand and pressed von Toll's hand. + +"And I might have been in his place!" thought Rostov, and hardly +restraining his tears of pity for the Emperor, he rode on in utter +despair, not knowing where to or why he was now riding. + +His despair was all the greater from feeling that his own weakness +was the cause his grief. + +He might... not only might but should, have gone up to the +sovereign. It was a unique chance to show his devotion to the +Emperor and he had not made use of it.... "What have I done?" +thought he. And he turned round and galloped back to the place where +he had seen the Emperor, but there was no one beyond the ditch now. +Only some carts and carriages were passing by. From one of the drivers +he learned that Kutuzov's staff were not far off, in the village the +vehicles were going to. Rostov followed them. In front of him walked +Kutuzov's groom leading horses in horsecloths. Then came a cart, and +behind that walked an old, bandy-legged domestic serf in a peaked +cap and sheepskin coat. + +"Tit! I say, Tit!" said the groom. + +"What?" answered the old man absent-mindedly. + +"Go, Tit! Thresh a bit!" + +"Oh, you fool!" said the old man, spitting angrily. Some time passed +in silence, and then the same joke was repeated. + + +Before five in the evening the battle had been lost at all points. +More than a hundred cannon were already in the hands of the French. + +Przebyszewski and his corps had laid down their arms. Other +columns after losing half their men were retreating in disorderly +confused masses. + +The remains of Langeron's and Dokhturov's mingled forces were +crowding around the dams and banks of the ponds near the village of +Augesd. + +After five o'clock it was only at the Augesd Dam that a hot +cannonade (delivered by the French alone) was still to be heard from +numerous batteries ranged on the slopes of the Pratzen Heights, +directed at our retreating forces. + +In the rearguard, Dokhturov and others rallying some battalions kept +up a musketry fire at the French cavalry that was pursuing our troops. +It was growing dusk. On the narrow Augesd Dam where for so many +years the old miller had been accustomed to sit in his tasseled cap +peacefully angling, while his grandson, with shirt sleeves rolled +up, handled the floundering silvery fish in the watering can, on +that dam over which for so many years Moravians in shaggy caps and +blue jackets had peacefully driven their two-horse carts loaded with +wheat and had returned dusty with flour whitening their carts--on that +narrow dam amid the wagons and the cannon, under the horses' hoofs and +between the wagon wheels, men disfigured by fear of death now +crowded together, crushing one another, dying, stepping over the dying +and killing one another, only to move on a few steps and be killed +themselves in the same way. + +Every ten seconds a cannon ball flew compressing the air around, +or a shell burst in the midst of that dense throng, killing some and +splashing with blood those near them. + +Dolokhov--now an officer--wounded in the arm, and on foot, with +the regimental commander on horseback and some ten men of his company, +represented all that was left of that whole regiment. Impelled by +the crowd, they had got wedged in at the approach to the dam and, +jammed in on all sides, had stopped because a horse in front had +fallen under a cannon and the crowd were dragging it out. A cannon +ball killed someone behind them, another fell in front and splashed +Dolokhov with blood. The crowd, pushing forward desperately, +squeezed together, moved a few steps, and again stopped. + +"Move on a hundred yards and we are certainly saved, remain here +another two minutes and it is certain death," thought each one. + +Dolokhov who was in the midst of the crowd forced his way to the +edge of the dam, throwing two soldiers off their feet, and ran onto +the slippery ice that covered the millpool. + +"Turn this way!" he shouted, jumping over the ice which creaked +under him; "turn this way!" he shouted to those with the gun. "It +bears!..." + +The ice bore him but it swayed and creaked, and it was plain that it +would give way not only under a cannon or a crowd, but very soon +even under his weight alone. The men looked at him and pressed to +the bank, hesitating to step onto the ice. The general on horseback at +the entrance to the dam raised his hand and opened his mouth to +address Dolokhov. Suddenly a cannon ball hissed so low above the crowd +that everyone ducked. It flopped into something moist, and the general +fell from his horse in a pool of blood. Nobody gave him a look or +thought of raising him. + +"Get onto the ice, over the ice! Go on! Turn! Don't you hear? Go +on!" innumerable voices suddenly shouted after the ball had struck the +general, the men themselves not knowing what, or why, they were +shouting. + +One of the hindmost guns that was going onto the dam turned off onto +the ice. Crowds of soldiers from the dam began running onto the frozen +pond. The ice gave way under one of the foremost soldiers, and one leg +slipped into the water. He tried to right himself but fell in up to +his waist. The nearest soldiers shrank back, the gun driver stopped +his horse, but from behind still came the shouts: "Onto the ice, why +do you stop? Go on! Go on!" And cries of horror were heard in the +crowd. The soldiers near the gun waved their arms and beat the +horses to make them turn and move on. The horses moved off the bank. +The ice, that had held under those on foot, collapsed in a great mass, +and some forty men who were on it dashed, some forward and some +back, drowning one another. + +Still the cannon balls continued regularly to whistle and flop +onto the ice and into the water and oftenest of all among the crowd +that covered the dam, the pond, and the bank. + + + + + +CHAPTER XIX + + +On the Pratzen Heights, where he had fallen with the flagstaff in +his hand, lay Prince Andrew Bolkonski bleeding profusely and +unconsciously uttering a gentle, piteous, and childlike moan. + +Toward evening he ceased moaning and became quite still. He did +not know how long his unconsciousness lasted. Suddenly he again felt +that he was alive and suffering from a burning, lacerating pain in his +head. + +"Where is it, that lofty sky that I did not know till now, but saw +today?" was his first thought. "And I did not know this suffering +either," he thought. "Yes, I did not know anything, anything at all +till now. But where am I?" + +He listened and heard the sound of approaching horses, and voices +speaking French. He opened his eyes. Above him again was the same +lofty sky with clouds that had risen and were floating still higher, +and between them gleamed blue infinity. He did not turn his head and +did not see those who, judging by the sound of hoofs and voices, had +ridden up and stopped near him. + +It was Napoleon accompanied by two aides-de-camp. Bonaparte riding +over the battlefield had given final orders to strengthen the +batteries firing at the Augesd Dam and was looking at the killed and +wounded left on the field. + +"Fine men!" remarked Napoleon, looking at a dead Russian +grenadier, who, with his face buried in the ground and a blackened +nape, lay on his stomach with an already stiffened arm flung wide. + +"The ammunition for the guns in position is exhausted, Your +Majesty," said an adjutant who had come from the batteries that were +firing at Augesd. + +"Have some brought from the reserve," said Napoleon, and having gone +on a few steps he stopped before Prince Andrew, who lay on his back +with the flagstaff that had been dropped beside him. (The flag had +already been taken by the French as a trophy.) + +"That's a fine death!" said Napoleon as he gazed at Bolkonski. + +Prince Andrew understood that this was said of him and that it was +Napoleon who said it. He heard the speaker addressed as Sire. But he +heard the words as he might have heard the buzzing of a fly. Not +only did they not interest him, but he took no notice of them and at +once forgot them. His head was burning, he felt himself bleeding to +death, and he saw above him the remote, lofty, and everlasting sky. He +knew it was Napoleon--his hero--but at that moment Napoleon seemed +to him such a small, insignificant creature compared with what was +passing now between himself and that lofty infinite sky with the +clouds flying over it. At that moment it meant nothing to him who +might be standing over him, or what was said of him; he was only +glad that people were standing near him and only wished that they +would help him and bring him back to life, which seemed to him so +beautiful now that he had today learned to understand it so +differently. He collected all his strength, to stir and utter a sound. +He feebly moved his leg and uttered a weak, sickly groan which aroused +his own pity. + +"Ah! He is alive," said Napoleon. "Lift this young man up and +carry him to the dressing station." + +Having said this, Napoleon rode on to meet Marshal Lannes, who, +hat in hand, rode up smiling to the Emperor to congratulate him on the +victory. + +Prince Andrew remembered nothing more: he lost consciousness from +the terrible pain of being lifted onto the stretcher, the jolting +while being moved, and the probing of his wound at the dressing +station. He did not regain consciousness till late in the day, when +with other wounded and captured Russian officers he was carried to the +hospital. During this transfer he felt a little stronger and was +able to look about him and even speak. + +The first words he heard on coming to his senses were those of a +French convoy officer, who said rapidly: "We must halt here: the +Emperor will pass here immediately; it will please him to see these +gentlemen prisoners." + +"There are so many prisoners today, nearly the whole Russian army, +that he is probably tired of them," said another officer. + +"All the same! They say this one is the commander of all the Emperor +Alexander's Guards," said the first one, indicating a Russian +officer in the white uniform of the Horse Guards. + +Bolkonski recognized Prince Repnin whom he had met in Petersburg +society. Beside him stood a lad of nineteen, also a wounded officer of +the Horse Guards. + +Bonaparte, having come up at a gallop, stopped his horse. + +"Which is the senior?" he asked, on seeing the prisoners. + +They named the colonel, Prince Repnin. + +"You are the commander of the Emperor Alexander's regiment of +Horse Guards?" asked Napoleon. + +"I commanded a squadron," replied Repnin. + +"Your regiment fulfilled its duty honorably," said Napoleon. + +"The praise of a great commander is a soldier's highest reward," +said Repnin. + +"I bestow it with pleasure," said Napoleon. "And who is that young +man beside you?" + +Prince Repnin named Lieutenant Sukhtelen. + +After looking at him Napoleon smiled. + +"He's very young to come to meddle with us." + +"Youth is no hindrance to courage," muttered Sukhtelen in a +failing voice. + +"A splendid reply!" said Napoleon. "Young man, you will go far!" + +Prince Andrew, who had also been brought forward before the +Emperor's eyes to complete the show of prisoners, could not fail to +attract his attention. Napoleon apparently remembered seeing him on +the battlefield and, addressing him, again used the epithet "young +man" that was connected in his memory with Prince Andrew. + +"Well, and you, young man," said he. "How do you feel, mon brave?" + +Though five minutes before, Prince Andrew had been able to say a few +words to the soldiers who were carrying him, now with his eyes fixed +straight on Napoleon, he was silent.... So insignificant at that +moment seemed to him all the interests that engrossed Napoleon, so +mean did his hero himself with his paltry vanity and joy in victory +appear, compared to the lofty, equitable, and kindly sky which he +had seen and understood, that he could not answer him. + +Everything seemed so futile and insignificant in comparison with the +stern and solemn train of thought that weakness from loss of blood, +suffering, and the nearness of death aroused in him. Looking into +Napoleon's eyes Prince Andrew thought of the insignificance of +greatness, the unimportance of life which no one could understand, and +the still greater unimportance of death, the meaning of which no one +alive could understand or explain. + +The Emperor without waiting for an answer turned away and said to +one of the officers as he went: "Have these gentlemen attended to +and taken to my bivouac; let my doctor, Larrey, examine their +wounds. Au revoir, Prince Repnin!" and he spurred his horse and +galloped away. + +His face shone with self-satisfaction and pleasure. + +The soldiers who had carried Prince Andrew had noticed and taken the +little gold icon Princess Mary had hung round her brother's neck, +but seeing the favor the Emperor showed the prisoners, they now +hastened to return the holy image. + +Prince Andrew did not see how and by whom it was replaced, but the +little icon with its thin gold chain suddenly appeared upon his +chest outside his uniform. + +"It would be good," thought Prince Andrew, glancing at the icon +his sister had hung round his neck with such emotion and reverence, +"it would be good if everything were as clear and simple as it seems +to Mary. How good it would be to know where to seek for help in this +life, and what to expect after it beyond the grave! How happy and calm +I should be if I could now say: 'Lord, have mercy on me!'... But to +whom should I say that? Either to a Power indefinable, +incomprehensible, which I not only cannot address but which I cannot +even express in words--the Great All or Nothing-" said he to +himself, "or to that God who has been sewn into this amulet by Mary! +There is nothing certain, nothing at all except the unimportance of +everything I understand, and the greatness of something +incomprehensible but all-important." + +The stretchers moved on. At every jolt he again felt unendurable +pain; his feverishness increased and he grew delirious. Visions of his +father, wife, sister, and future son, and the tenderness he had felt +the night before the battle, the figure of the insignificant little +Napoleon, and above all this the lofty sky, formed the chief +subjects of his delirious fancies. + +The quiet home life and peaceful happiness of Bald Hills presented +itself to him. He was already enjoying that happiness when that little +Napoleon had suddenly appeared with his unsympathizing look of +shortsighted delight at the misery of others, and doubts and +torments had followed, and only the heavens promised peace. Toward +morning all these dreams melted and merged into the chaos and darkness +of unconciousness and oblivion which in the opinion of Napoleon's +doctor, Larrey, was much more likely to end in death than in +convalescence. + +"He is a nervous, bilious subject," said Larrey, "and will not +recover." + +And Prince Andrew, with others fatally wounded, was left to the care +of the inhabitants of the district. + + + + + +BOOK FOUR: 1806 + + + +CHAPTER I + + +Early in the year 1806 Nicholas Rostov returned home on leave. +Denisov was going home to Voronezh and Rostov persuaded him to +travel with him as far as Moscow and to stay with him there. Meeting a +comrade at the last post station but one before Moscow, Denisov had +drunk three bottles of wine with him and, despite the jolting ruts +across the snow-covered road, did not once wake up on the way to +Moscow, but lay at the bottom of the sleigh beside Rostov, who grew +more and more impatient the nearer they got to Moscow. + +"How much longer? How much longer? Oh, these insufferable streets, +shops, bakers' signboards, street lamps, and sleighs!" thought Rostov, +when their leave permits had been passed at the town gate and they had +entered Moscow. + +"Denisov! We're here! He's asleep," he added, leaning forward with +his whole body as if in that position he hoped to hasten the speed +of the sleigh. + +Denisov gave no answer. + +"There's the corner at the crossroads, where the cabman, Zakhar, has +his stand, and there's Zakhar himself and still the same horse! And +here's the little shop where we used to buy gingerbread! Can't you +hurry up? Now then!" + +"Which house is it?" asked the driver. + +"Why, that one, right at the end, the big one. Don't you see? That's +our house," said Rostov. "Of course, it's our house! Denisov, Denisov! +We're almost there!" + +Denisov raised his head, coughed, and made no answer. + +"Dmitri," said Rostov to his valet on the box, "those lights are +in our house, aren't they?" + +"Yes, sir, and there's a light in your father's study." + +"Then they've not gone to bed yet? What do you think? Mind now, +don't forget to put out my new coat," added Rostov, fingering his +new mustache. "Now then, get on," he shouted to the driver. "Do wake +up, Vaska!" he went on, turning to Denisov, whose head was again +nodding. "Come, get on! You shall have three rubles for vodka--get +on!" Rostov shouted, when the sleigh was only three houses from his +door. It seemed to him the horses were not moving at all. At last +the sleigh bore to the right, drew up at an entrance, and Rostov saw +overhead the old familiar cornice with a bit of plaster broken off, +the porch, and the post by the side of the pavement. He sprang out +before the sleigh stopped, and ran into the hall. The house stood cold +and silent, as if quite regardless of who had come to it. There was no +one in the hall. "Oh God! Is everyone all right?" he thought, stopping +for a moment with a sinking heart, and then immediately starting to +run along the hall and up the warped steps of the familiar +staircase. The well-known old door handle, which always angered the +countess when it was not properly cleaned, turned as loosely as +ever. A solitary tallow candle burned in the anteroom. + +Old Michael was asleep on the chest. Prokofy, the footman, who was +so strong that he could lift the back of the carriage from behind, sat +plaiting slippers out of cloth selvedges. He looked up at the +opening door and his expression of sleepy indifference suddenly +changed to one of delighted amazement. + +"Gracious heavens! The young count!" he cried, recognizing his young +master. "Can it be? My treasure!" and Prokofy, trembling with +excitement, rushed toward the drawing-room door, probably in order +to announce him, but, changing his mind, came back and stooped to kiss +the young man's shoulder. + +"All well?" asked Rostov, drawing away his arm. + +"Yes, God be thanked! Yes! They've just finished supper. Let me have +a look at you, your excellency." + +"Is everything quite all right?" + +"The Lord be thanked, yes!" + +Rostov, who had completely forgotten Denisov, not wishing anyone +to forestall him, threw off his fur coat and ran on tiptoe through the +large dark ballroom. All was the same: there were the same old card +tables and the same chandelier with a cover over it; but someone had +already seen the young master, and, before he had reached the +drawing room, something flew out from a side door like a tornado and +began hugging and kissing him. Another and yet another creature of the +same kind sprang from a second door and a third; more hugging, more +kissing, more outcries, and tears of joy. He could not distinguish +which was Papa, which Natasha, and which Petya. Everyone shouted, +talked, and kissed him at the same time. Only his mother was not +there, he noticed that. + +"And I did not know... Nicholas... My darling!..." + +"Here he is... our own... Kolya,* dear fellow... How he has +changed!... Where are the candles?... Tea!..." + + +*Nicholas. + + +"And me, kiss me!" + +"Dearest... and me!" + +Sonya, Natasha, Petya, Anna Mikhaylovna, Vera, and the old count +were all hugging him, and the serfs, men and maids, flocked into the +room, exclaiming and oh-ing and ah-ing. + +Petya, clinging to his legs, kept shouting, "And me too!" + +Natasha, after she had pulled him down toward her and covered his +face with kisses, holding him tight by the skirt of his coat, sprang +away and pranced up and down in one place like a goat and shrieked +piercingly. + +All around were loving eyes glistening with tears of joy, and all +around were lips seeking a kiss. + +Sonya too, all rosy red, clung to his arm and, radiant with bliss, +looked eagerly toward his eyes, waiting for the look for which she +longed. Sonya now was sixteen and she was very pretty, especially at +this moment of happy, rapturous excitement. She gazed at him, not +taking her eyes off him, and smiling and holding her breath. He gave +her a grateful look, but was still expectant and looking for +someone. The old countess had not yet come. But now steps were heard +at the door, steps so rapid that they could hardly be his mother's. + +Yet it was she, dressed in a new gown which he did not know, made +since he had left. All the others let him go, and he ran to her. +When they met, she fell on his breast, sobbing. She could not lift her +face, but only pressed it to the cold braiding of his hussar's jacket. +Denisov, who had come into the room unnoticed by anyone, stood there +and wiped his eyes at the sight. + +"Vasili Denisov, your son's friend," he said, introducing himself to +the count, who was looking inquiringly at him. + +"You are most welcome! I know, I know," said the count, kissing +and embracing Denisov. "Nicholas wrote us... Natasha, Vera, look! Here +is Denisov!" + +The same happy, rapturous faces turned to the shaggy figure of +Denisov. + +"Darling Denisov!" screamed Natasha, beside herself with rapture, +springing to him, putting her arms round him, and kissing him. This +escapade made everybody feel confused. Denisov blushed too, but smiled +and, taking Natasha's hand, kissed it. + +Denisov was shown to the room prepared for him, and the Rostovs +all gathered round Nicholas in the sitting room. + +The old countess, not letting go of his hand and kissing it every +moment, sat beside him: the rest, crowding round him, watched every +movement, word, or look of his, never taking their blissfully +adoring eyes off him. His brother and sisters struggled for the places +nearest to him and disputed with one another who should bring him +his tea, handkerchief, and pipe. + +Rostov was very happy in the love they showed him; but the first +moment of meeting had been so beatific that his present joy seemed +insufficient, and he kept expecting something more, more and yet more. + +Next morning, after the fatigues of their journey, the travelers +slept till ten o'clock. + +In the room next their bedroom there was a confusion of sabers, +satchels, sabretaches, open portmanteaus, and dirty boots. Two freshly +cleaned pairs with spurs had just been placed by the wall. The +servants were bringing in jugs and basins, hot water for shaving, +and their well-brushed clothes. There was a masculine odor and a smell +of tobacco. + +"Hallo, Gwiska--my pipe!" came Vasili Denisov's husky voice. +"Wostov, get up!" + +Rostov, rubbing his eyes that seemed glued together, raised his +disheveled head from the hot pillow. + +"Why, is it late?" + +"Late! It's nearly ten o'clock," answered Natasha's voice. A +rustle of starched petticoats and the whispering and laughter of +girls' voices came from the adjoining room. The door was opened a +crack and there was a glimpse of something blue, of ribbons, black +hair, and merry faces. It was Natasha, Sonya, and Petya, who had +come to see whether they were getting up. + +"Nicholas! Get up!" Natasha's voice was again heard at the door. + +"Directly!" + +Meanwhile, Petya, having found and seized the sabers in the outer +room, with the delight boys feel at the sight of a military elder +brother, and forgetting that it was unbecoming for the girls to see +men undressed, opened the bedroom door. + +"Is this your saber?" he shouted. + +The girls sprang aside. Denisov hid his hairy legs under the +blanket, looking with a scared face at his comrade for help. The door, +having let Petya in, closed again. A sound of laughter came from +behind it. + +"Nicholas! Come out in your dressing gown!" said Natasha's voice. + +"Is this your saber?" asked Petya. "Or is it yours?" he said, +addressing the black-mustached Denisov with servile deference. + +Rostov hurriedly put something on his feet, drew on his dressing +gown, and went out. Natasha had put on one spurred boot and was just +getting her foot into the other. Sonya, when he came in, was +twirling round and was about to expand her dresses into a balloon +and sit down. They were dressed alike, in new pale-blue frocks, and +were both fresh, rosy, and bright. Sonya ran away, but Natasha, taking +her brother's arm, led him into the sitting room, where they began +talking. They hardly gave one another time to ask questions and give +replies concerning a thousand little matters which could not +interest anyone but themselves. Natasha laughed at every word he +said or that she said herself, not because what they were saying was +amusing, but because she felt happy and was unable to control her +joy which expressed itself by laughter. + +"Oh, how nice, how splendid!" she said to everything. + +Rostov felt that, under the influence of the warm rays of love, that +childlike smile which had not once appeared on his face since he +left home now for the first time after eighteen months again +brightened his soul and his face. + +"No, but listen," she said, "now you are quite a man, aren't you? +I'm awfully glad you're my brother." She touched his mustache. "I want +to know what you men are like. Are you the same as we? No?" + +"Why did Sonya run away?" asked Rostov. + +"Ah, yes! That's a whole long story! How are you going to speak to +her--thou or you?" + +"As may happen," said Rostov. + +"No, call her you, please! I'll tell you all about it some other +time. No, I'll tell you now. You know Sonya's my dearest friend. +Such a friend that I burned my arm for her sake. Look here!" + +She pulled up her muslin sleeve and showed him a red scar on her +long, slender, delicate arm, high above the elbow on that part that is +covered even by a ball dress. + +"I burned this to prove my love for her. I just heated a ruler in +the fire and pressed it there!" + +Sitting on the sofa with the little cushions on its arms, in what +used to be his old schoolroom, and looking into Natasha's wildly +bright eyes, Rostov re-entered that world of home and childhood +which had no meaning for anyone else, but gave him some of the best +joys of his life; and the burning of an arm with a ruler as a proof of +love did not seem to him senseless, he understood and was not +surprised at it. + +"Well, and is that all?" he asked. + +"We are such friends, such friends! All that ruler business was just +nonsense, but we are friends forever. She, if she loves anyone, does +it for life, but I don't understand that, I forget quickly." + +"Well, what then?" + +"Well, she loves me and you like that." + +Natasha suddenly flushed. + +"Why, you remember before you went away?... Well, she says you are +to forget all that.... She says: 'I shall love him always, but let him +be free.' Isn't that lovely and noble! Yes, very noble? Isn't it?" +asked Natasha, so seriously and excitedly that it was evident that +what she was now saying she had talked of before, with tears. + +Rostov became thoughtful. + +"I never go back on my word," he said. "Besides, Sonya is so +charming that only a fool would renounce such happiness." + +"No, no!" cried Natasha, "she and I have already talked it over. +We knew you'd say so. But it won't do, because you see, if you say +that--if you consider yourself bound by your promise--it will seem +as if she had not meant it seriously. It makes it as if you were +marrying her because you must, and that wouldn't do at all." + +Rostov saw that it had been well considered by them. Sonya had +already struck him by her beauty on the preceding day. Today, when +he had caught a glimpse of her, she seemed still more lovely. She +was a charming girl of sixteen, evidently passionately in love with +him (he did not doubt that for an instant). Why should he not love her +now, and even marry her, Rostov thought, but just now there were so +many other pleasures and interests before him! "Yes, they have taken a +wise decision," he thought, "I must remain free." + +"Well then, that's excellent," said he. "We'll talk it over later +on. Oh, how glad I am to have you!" + +"Well, and are you still true to Boris?" he continued. + +"Oh, what nonsense!" cried Natasha, laughing. "I don't think about +him or anyone else, and I don't want anything of the kind." + +"Dear me! Then what are you up now?" + +"Now?" repeated Natasha, and a happy smile lit up her face. "Have +you seen Duport?" + +"No." + +"Not seen Duport--the famous dancer? Well then, you won't +understand. That's what I'm up to." + +Curving her arms, Natasha held out her skirts as dancers do, ran +back a few steps, turned, cut a caper, brought her little feet sharply +together, and made some steps on the very tips of her toes. + +"See, I'm standing! See!" she said, but could not maintain herself +on her toes any longer. "So that's what I'm up to! I'll never marry +anyone, but will be a dancer. Only don't tell anyone." + +Rostov laughed so loud and merrily that Denisov, in his bedroom, +felt envious and Natasha could not help joining in. + +"No, but don't you think it's nice?" she kept repeating. + +"Nice! And so you no longer wish to marry Boris?" + +Natasha flared up. "I don't want to marry anyone. And I'll tell +him so when I see him!" + +"Dear me!" said Rostov. + +"But that's all rubbish," Natasha chattered on. "And is Denisov +nice?" she asked. + +"Yes, indeed!" + +"Oh, well then, good-by: go and dress. Is he very terrible, +Denisov?" + +"Why terrible?" asked Nicholas. "No, Vaska is a splendid fellow." + +"You call him Vaska? That's funny! And is he very nice?" + +"Very." + +"Well then, be quick. We'll all have breakfast together." + +And Natasha rose and went out of the room on tiptoe, like a ballet +dancer, but smiling as only happy girls of fifteen can smile. When +Rostov met Sonya in the drawing room, he reddened. He did not know how +to behave with her. The evening before, in the first happy moment of +meeting, they had kissed each other, but today they felt it could +not be done; he felt that everybody, including his mother and sisters, +was looking inquiringly at him and watching to see how he would behave +with her. He kissed her hand and addressed her not as thou but as you- +Sonya. But their eyes met and said thou, and exchanged tender +kisses. Her looks asked him to forgive her for having dared, by +Natasha's intermediacy, to remind him of his promise, and then thanked +him for his love. His looks thanked her for offering him his freedom +and told her that one way or another he would never cease to love her, +for that would be impossible. + +"How strange it is," said Vera, selecting a moment when all were +silent, "that Sonya and Nicholas now say you to one another and meet +like strangers." + +Vera's remark was correct, as her remarks always were, but, like +most of her observations, it made everyone feel uncomfortable, not +only Sonya, Nicholas, and Natasha, but even the old countess, who- +dreading this love affair which might hinder Nicholas from making a +brilliant match--blushed like a girl. + +Denisov, to Rostov's surprise, appeared in the drawing room with +pomaded hair, perfumed, and in a new uniform, looking just as smart as +he made himself when going into battle, and he was more amiable to the +ladies and gentlemen than Rostov had ever expected to see him. + + + + + +CHAPTER II + + +On his return to Moscow from the army, Nicholas Rostov was +welcomed by his home circle as the best of sons, a hero, and their +darling Nikolenka; by his relations as a charming, attractive, and +polite young man; by his acquaintances as a handsome lieutenant of +hussars, a good dancer, and one of the best matches in the city. + +The Rostovs knew everybody in Moscow. The old count had money enough +that year, as all his estates had been remortgaged, and so Nicholas, +acquiring a trotter of his own, very stylish riding breeches of the +latest cut, such as no one else yet had in Moscow, and boots of the +latest fashion, with extremely pointed toes and small silver spurs, +passed his time very gaily. After a short period of adapting himself +to the old conditions of life, Nicholas found it very pleasant to be +at home again. He felt that he had grown up and matured very much. His +despair at failing in a Scripture examination, his borrowing money +from Gavril to pay a sleigh driver, his kissing Sonya on the sly--he +now recalled all this as childishness he had left immeasurably behind. +Now he was a lieutenant of hussars, in a jacket laced with silver, and +wearing the Cross of St. George, awarded to soldiers for bravery in +action, and in the company of well-known, elderly, and respected +racing men was training a trotter of his own for a race. He knew a +lady on one of the boulevards whom he visited of an evening. He led +the mazurka at the Arkharovs' ball, talked about the war with Field +Marshal Kamenski, visited the English Club, and was on intimate +terms with a colonel of forty to whom Denisov had introduced him. + +His passion for the Emperor had cooled somewhat in Moscow. But +still, as he did not see him and had no opportunity of seeing him, +he often spoke about him and about his love for him, letting it be +understood that he had not told all and that there was something in +his feelings for the Emperor not everyone could understand, and with +his whole soul he shared the adoration then common in Moscow for the +Emperor, who was spoken of as the "angel incarnate." + +During Rostov's short stay in Moscow, before rejoining the army, +he did not draw closer to Sonya, but rather drifted away from her. She +was very pretty and sweet, and evidently deeply in love with him, +but he was at the period of youth when there seems so much to do +that there is no time for that sort of thing and a young man fears +to bind himself and prizes his freedom which he needs for so many +other things. When he thought of Sonya, during this stay in Moscow, he +said to himself, "Ah, there will be, and there are, many more such +girls somewhere whom I do not yet know. There will be time enough to +think about love when I want to, but now I have no time." Besides, +it seemed to him that the society of women was rather derogatory to +his manhood. He went to balls and into ladies' society with an +affectation of doing so against his will. The races, the English Club, +sprees with Denisov, and visits to a certain house--that was another +matter and quite the thing for a dashing young hussar! + +At the beginning of March, old Count Ilya Rostov was very busy +arranging a dinner in honor of Prince Bagration at the English Club. + +The count walked up and down the hall in his dressing gown, giving +orders to the club steward and to the famous Feoktist, the Club's head +cook, about asparagus, fresh cucumbers, strawberries, veal, and fish +for this dinner. The count had been a member and on the committee of +the Club from the day it was founded. To him the Club entrusted the +arrangement of the festival in honor of Bagration, for few men knew so +well how to arrange a feast on an open-handed, hospitable scale, and +still fewer men would be so well able and willing to make up out of +their own resources what might be needed for the success of the +fete. The club cook and the steward listened to the count's orders +with pleased faces, for they knew that under no other management could +they so easily extract a good profit for themselves from a dinner +costing several thousand rubles. + +"Well then, mind and have cocks' comb in the turtle soup, you know!" + +"Shall we have three cold dishes then?" asked the cook. + +The count considered. + +"We can't have less--yes, three... the mayonnaise, that's one," said +he, bending down a finger. + +"Then am I to order those large sterlets?" asked the steward. + +"Yes, it can't be helped if they won't take less. Ah, dear me! I was +forgetting. We must have another entree. Ah, goodness gracious!" he +clutched at his head. "Who is going to get me the flowers? Dmitri! Eh, +Dmitri! Gallop off to our Moscow estate," he said to the factotum +who appeared at his call. "Hurry off and tell Maksim, the gardener, to +set the serfs to work. Say that everything out of the hothouses must +be brought here well wrapped up in felt. I must have two hundred +pots here on Friday." + +Having given several more orders, he was about to go to his +"little countess" to have a rest, but remembering something else of +importance, he returned again, called back the cook and the club +steward, and again began giving orders. A light footstep and the +clinking of spurs were heard at the door, and the young count, +handsome, rosy, with a dark little mustache, evidently rested and made +sleeker by his easy life in Moscow, entered the room. + +"Ah, my boy, my head's in a whirl!" said the old man with a smile, +as if he felt a little confused before his son. "Now, if you would +only help a bit! I must have singers too. I shall have my own +orchestra, but shouldn't we get the gypsy singers as well? You +military men like that sort of thing." + +"Really, Papa, I believe Prince Bagration worried himself less +before the battle of Schon Grabern than you do now," said his son with +a smile. + +The old count pretended to be angry. + +"Yes, you talk, but try it yourself!" + +And the count turned to the cook, who, with a shrewd and +respectful expression, looked observantly and sympathetically at the +father and son. + +"What have the young people come to nowadays, eh, Feoktist?" said +he. "Laughing at us old fellows!" + +"That's so, your excellency, all they have to do is to eat a good +dinner, but providing it and serving it all up, that's not their +business!" + +"That's it, that's it!" exclaimed the count, and gaily seizing his +son by both hands, he cried, "Now I've got you, so take the sleigh and +pair at once, and go to Bezukhob's, and tell him 'Count Ilya has +sent you to ask for strawberries and fresh pineapples.' We can't get +them from anyone else. He's not there himself, so you'll have to go in +and ask the princesses; and from there go on to the Rasgulyay--the +coachman Ipatka knows--and look up the gypsy Ilyushka, the one who +danced at Count Orlov's, you remember, in a white Cossack coat, and +bring him along to me." + +"And am I to bring the gypsy girls along with him?" asked +Nicholas, laughing. "Dear, dear!..." + +At that moment, with noiseless footsteps and with the +businesslike, preoccupied, yet meekly Christian look which never +left her face, Anna Mikhaylovna entered the hall. Though she came upon +the count in his dressing gown every day, he invariably became +confused and begged her to excuse his costume. + +"No matter at all, my dear count," she said, meekly closing her +eyes. "But I'll go to Bezukhov's myself. Pierre has arrived, and now +we shall get anything we want from his hothouses. I have to see him in +any case. He has forwarded me a letter from Boris. Thank God, Boris is +now on the staff." + +The count was delighted at Anna Mikhaylovna's taking upon herself +one of his commissions and ordered the small closed carriage for her. + +"Tell Bezukhov to come. I'll put his name down. Is his wife with +him?" he asked. + +Anna Mikhaylovna turned up her eyes, and profound sadness was +depicted on her face. + +"Ah, my dear friend, he is very unfortunate," she said. "If what +we hear is true, it is dreadful. How little we dreamed of such a thing +when we were rejoicing at his happiness! And such a lofty angelic soul +as young Bezukhov! Yes, I pity him from my heart, and shall try to +give him what consolation I can." + +"Wh-what is the matter?" asked both the young and old Rostov. + +Anna Mikhaylovna sighed deeply. + +"Dolokhov, Mary Ivanovna's son," she said in a mysterious whisper, +"has compromised her completely, they say. Pierre took him up, invited +him to his house in Petersburg, and now... she has come here and +that daredevil after her!" said Anna Mikhaylovna, wishing to show +her sympathy for Pierre, but by involuntary intonations and a half +smile betraying her sympathy for the "daredevil," as she called +Dolokhov. "They say Pierre is quite broken by his misfortune." + +"Dear, dear! But still tell him to come to the Club--it will all +blow over. It will be a tremendous banquet." + +Next day, the third of March, soon after one o'clock, two hundred +and fifty members of the English Club and fifty guests were awaiting +the guest of honor and hero of the Austrian campaign, Prince +Bagration, to dinner. + +On the first arrival of the news of the battle of Austerlitz, Moscow +had been bewildered. At that time, the Russians were so used to +victories that on receiving news of the defeat some would simply not +believe it, while others sought some extraordinary explanation of so +strange an event. In the English Club, where all who were +distinguished, important, and well informed forgathered when the +news began to arrive in December, nothing was said about the war and +the last battle, as though all were in a conspiracy of silence. The +men who set the tone in conversation--Count Rostopchin, Prince Yuri +Dolgorukov, Valuev, Count Markov, and Prince Vyazemski--did not show +themselves at the Club, but met in private houses in intimate circles, +and the Moscovites who took their opinions from others--Ilya Rostov +among them--remained for a while without any definite opinion on the +subject of the war and without leaders. The Moscovites felt that +something was wrong and that to discuss the bad news was difficult, +and so it was best to be silent. But after a while, just as a jury +comes out of its room, the bigwigs who guided the Club's opinion +reappeared, and everybody began speaking clearly and definitely. +Reasons were found for the incredible, unheard-of, and impossible +event of a Russian defeat, everything became clear, and in all corners +of Moscow the same things began to be said. These reasons were the +treachery of the Austrians, a defective commissariat, the treachery of +the Pole Przebyszewski and of the Frenchman Langeron, Kutuzov's +incapacity, and (it was whispered) the youth and inexperience of the +sovereign, who had trusted worthless and insignificant people. But the +army, the Russian army, everyone declared, was extraordinary and had +achieved miracles of valor. The soldiers, officers, and generals were +heroes. But the hero of heroes was Prince Bagration, distinguished +by his Schon Grabern affair and by the retreat from Austerlitz, +where he alone had withdrawn his column unbroken and had all day +beaten back an enemy force twice as numerous as his own. What also +conduced to Bagration's being selected as Moscow's hero was the fact +that he had no connections in the city and was a stranger there. In +his person, honor was shown to a simple fighting Russian soldier +without connections and intrigues, and to one who was associated by +memories of the Italian campaign with the name of Suvorov. Moreover, +paying such honor to Bagration was the best way of expressing +disapproval and dislike of Kutuzov. + +"Had there been no Bagration, it would have been necessary to invent +him," said the wit Shinshin, parodying the words of Voltaire. +Kutuzov no one spoke of, except some who abused him in whispers, +calling him a court weathercock and an old satyr. + +All Moscow repeated Prince Dolgorukov's saying: "If you go on +modeling and modeling you must get smeared with clay," suggesting +consolation for our defeat by the memory of former victories; and +the words of Rostopchin, that French soldiers have to be incited to +battle by highfalutin words, and Germans by logical arguments to +show them that it is more dangerous to run away than to advance, but +that Russian soldiers only need to be restrained and held back! On all +sides, new and fresh anecdotes were heard of individual examples of +heroism shown by our officers and men at Austerlitz. One had saved a +standard, another had killed five Frenchmen, a third had loaded five +cannon singlehanded. Berg was mentioned, by those who did not know +him, as having, when wounded in the right hand, taken his sword in the +left, and gone forward. Of Bolkonski, nothing was said, and only those +who knew him intimately regretted that he had died so young, leaving a +pregnant wife with his eccentric father. + + + + + +CHAPTER III + + +On that third of March, all the rooms in the English Club were +filled with a hum of conversation, like the hum of bees swarming in +springtime. The members and guests of the Club wandered hither and +thither, sat, stood, met, and separated, some in uniform and some in +evening dress, and a few here and there with powdered hair and in +Russian kaftans. Powdered footmen, in livery with buckled shoes and +smart stockings, stood at every door anxiously noting visitors' +every movement in order to offer their services. Most of those present +were elderly, respected men with broad, self-confident faces, fat +fingers, and resolute gestures and voices. This class of guests and +members sat in certain habitual places and met in certain habitual +groups. A minority of those present were casual guests--chiefly +young men, among whom were Denisov, Rostov, and Dolokhov--who was +now again an officer in the Semenov regiment. The faces of these young +people, especially those who were militarymen, bore that expression of +condescending respect for their elders which seems to say to the older +generation, "We are prepared to respect and honor you, but all the +same remember that the future belongs to us." + +Nesvitski was there as an old member of the Club. Pierre, who at his +wife's command had let his hair grow and abandoned his spectacles, +went about the rooms fashionably dressed but looking sad and dull. +Here, as elsewhere, he was surrounded by an atmosphere of subservience +to his wealth, and being in the habit of lording it over these people, +he treated them with absent-minded contempt. + +By his age he should have belonged to the younger men, but by his +wealth and connections he belonged to the groups old and honored +guests, and so he went from one group to another. Some of the most +important old men were the center of groups which even strangers +approached respectfully to hear the voices of well-known men. The +largest circles formed round Count Rostopchin, Valuev, and +Naryshkin. Rostopchin was describing how the Russians had been +overwhelmed by flying Austrians and had had to force their way through +them with bayonets. + +Valuev was confidentially telling that Uvarov had been sent from +Petersburg to ascertain what Moscow was thinking about Austerlitz. + +In the third circle, Naryshkin was speaking of the meeting of the +Austrian Council of War at which Suvorov crowed like a cock in reply +to the nonsense talked by the Austrian generals. Shinshin, standing +close by, tried to make a joke, saying that Kutuzov had evidently +failed to learn from Suvorov even so simple a thing as the art of +crowing like a cock, but the elder members glanced severely at the +wit, making him feel that in that place and on that day, it was +improper to speak so of Kutuzov. + +Count Ilya Rostov, hurried and preoccupied, went about in his soft +boots between the dining and drawing rooms, hastily greeting the +important and unimportant, all of whom he knew, as if they were all +equals, while his eyes occasionally sought out his fine well-set-up +young son, resting on him and winking joyfully at him. Young Rostov +stood at a window with Dolokhov, whose acquaintance he had lately made +and highly valued. The old count came up to them and pressed +Dolokhov's hand. + +"Please come and visit us... you know my brave boy... been +together out there... both playing the hero... Ah, Vasili +Ignatovich... How d'ye do, old fellow?" he said, turning to an old man +who was passing, but before he had finished his greeting there was a +general stir, and a footman who had run in announced, with a +frightened face: "He's arrived!" + +Bells rang, the stewards rushed forward, and--like rye shaken +together in a shovel--the guests who had been scattered about in +different rooms came together and crowded in the large drawing room by +the door of the ballroom. + +Bagration appeared in the doorway of the anteroom without hat or +sword, which, in accord with the Club custom, he had given up to the +hall porter. He had no lambskin cap on his head, nor had he a loaded +whip over his shoulder, as when Rostov had seen him on the eve of +the battle of Austerlitz, but wore a tight new uniform with Russian +and foreign Orders, and the Star of St. George on his left breast. +Evidently just before coming to the dinner he had had his hair and +whiskers trimmed, which changed his appearance for the worse. There +was something naively festive in his air, which, in conjunction with +his firm and virile features, gave him a rather comical expression. +Bekleshev and Theodore Uvarov, who had arrived with him, paused at the +doorway to allow him, as the guest of honor, to enter first. Bagration +was embarrassed, not wishing to avail himself of their courtesy, and +this caused some delay at the doors, but after all he did at last +enter first. He walked shyly and awkwardly over the parquet floor of +the reception room, not knowing what to do with his hands; he was more +accustomed to walk over a plowed field under fire, as he had done at +the head of the Kursk regiment at Schon Grabern--and he would have +found that easier. The committeemen met him at the first door and, +expressing their delight at seeing such a highly honored guest, took +possession of him as it were, without waiting for his reply, +surrounded him, and led him to the drawing room. It was at first +impossible to enter the drawing-room door for the crowd of members and +guests jostling one another and trying to get a good look at Bagration +over each other's shoulders, as if he were some rare animal. Count +Ilya Rostov, laughing and repeating the words, "Make way, dear boy! +Make way, make way!" pushed through the crowd more energetically +than anyone, led the guests into the drawing room, and seated them +on the center sofa. The bigwigs, the most respected members of the +Club, beset the new arrivals. Count Ilya, again thrusting his way +through the crowd, went out of the drawing room and reappeared a +minute later with another committeeman, carrying a large silver salver +which he presented to Prince Bagration. On the salver lay some +verses composed and printed in the hero's honor. Bagration, on +seeing the salver, glanced around in dismay, as though seeking help. +But all eyes demanded that he should submit. Feeling himself in +their power, he resolutely took the salver with both hands and +looked sternly and reproachfully at the count who had presented it +to him. Someone obligingly took the dish from Bagration (or he +would, it seemed, have held it till evening and have gone in to dinner +with it) and drew his attention to the verses. + +"Well, I will read them, then!" Bagration seemed to say, and, fixing +his weary eyes on the paper, began to read them with a fixed and +serious expression. But the author himself took the verses and began +reading them aloud. Bagration bowed his bead and listened: + + Bring glory then to Alexander's reign + And on the throne our Titus shield. + A dreaded foe be thou, kindhearted as a man, + A Rhipheus at home, a Caesar in the field! + E'en fortunate Napoleon + Knows by experience, now, Bagration, + And dare not Herculean Russians trouble... + +But before he had finished reading, a stentorian major-domo +announced that dinner was ready! The door opened, and from the +dining room came the resounding strains of the polonaise: + + Conquest's joyful thunder waken, + Triumph, valiant Russians, now!... + +and Count Rostov, glancing angrily at the author who went on reading +his verses, bowed to Bagration. Everyone rose, feeling that dinner was +more important than verses, and Bagration, again preceding all the +rest, went in to dinner. He was seated in the place of honor between +two Alexanders--Bekleshev and Naryshkin--which was a significant +allusion to the name of the sovereign. Three hundred persons took +their seats in the dining room, according to their rank and +importance: the more important nearer to the honored guest, as +naturally as water flows deepest where the land lies lowest. + +Just before dinner, Count Ilya Rostov presented his son to +Bagration, who recognized him and said a few words to him, +disjointed and awkward, as were all the words he spoke that day, and +Count Ilya looked joyfully and proudly around while Bagration spoke to +his son. + +Nicholas Rostov, with Denisov and his new acquaintance, Dolokhov, +sat almost at the middle of the table. Facing them sat Pierre, +beside Prince Nesvitski. Count Ilya Rostov with the other members of +the committee sat facing Bagration and, as the very personification of +Moscow hospitality, did the honors to the prince. + +His efforts had not been in vain. The dinner, both the Lenten and +the other fare, was splendid, yet he could not feel quite at ease till +the end of the meal. He winked at the butler, whispered directions +to the footmen, and awaited each expected dish with some anxiety. +Everything was excellent. With the second course, a gigantic sterlet +(at sight of which Ilya Rostov blushed with self-conscious +pleasure), the footmen began popping corks and filling the champagne +glasses. After the fish, which made a certain sensation, the count +exchanged glances with the other committeemen. "There will be many +toasts, it's time to begin," he whispered, and taking up his glass, he +rose. All were silent, waiting for what he would say. + +"To the health of our Sovereign, the Emperor!" he cried, and at +the same moment his kindly eyes grew moist with tears of joy and +enthusiasm. The band immediately struck up "Conquest's joyful +thunder waken..." All rose and cried "Hurrah!" Bagration also rose and +shouted "Hurrah!" in exactly the same voice in which he had shouted it +on the field at Schon Grabern. Young Rostov's ecstatic voice could +be heard above the three hundred others. He nearly wept. "To the +health of our Sovereign, the Emperor!" he roared, "Hurrah!" and +emptying his glass at one gulp he dashed it to the floor. Many +followed his example, and the loud shouting continued for a long time. +When the voices subsided, the footmen cleared away the broken glass +and everybody sat down again, smiling at the noise they had made and +exchanging remarks. The old count rose once more, glanced at a note +lying beside his plate, and proposed a toast, "To the health of the +hero of our last campaign, Prince Peter Ivanovich Bagration!" and +again his blue eyes grew moist. "Hurrah!" cried the three hundred +voices again, but instead of the band a choir began singing a +cantata composed by Paul Ivanovich Kutuzov: + + Russians! O'er all barriers on! + Courage conquest guarantees; + Have we not Bagration? + He brings foe men to their knees,... etc. + + +As soon as the singing was over, another and another toast was +proposed and Count Ilya Rostov became more and more moved, more +glass was smashed, and the shouting grew louder. They drank to +Bekleshev, Naryshkin, Uvarov, Dolgorukov, Apraksin, Valuev, to the +committee, to all the Club members and to all the Club guests, and +finally to Count Ilya Rostov separately, as the organizer of the +banquet. At that toast, the count took out his handkerchief and, +covering his face, wept outright. + + + + + +CHAPTER IV + + +Pierre sat opposite Dolokhov and Nicholas Rostov. As usual, he ate +and drank much, and eagerly. But those who knew him intimately noticed +that some great change had come over him that day. He was silent all +through dinner and looked about, blinking and scowling, or, with fixed +eyes and a look of complete absent-mindedness, kept rubbing the bridge +of his nose. His face was depressed and gloomy. He seemed to see and +hear nothing of what was going on around him and to be absorbed by +some depressing and unsolved problem. + +The unsolved problem that tormented him was caused by hints given by +the princess, his cousin, at Moscow, concerning Dolokhov's intimacy +with his wife, and by an anonymous letter he had received that +morning, which in the mean jocular way common to anonymous letters +said that he saw badly through his spectacles, but that his wife's +connection with Dolokhov was a secret to no one but himself. Pierre +absolutely disbelieved both the princess' hints and the letter, but he +feared now to look at Dolokhov, who was sitting opposite him. Every +time he chanced to meet Dolokhov's handsome insolent eyes, Pierre felt +something terrible and monstrous rising in his soul and turned quickly +away. Involuntarily recalling his wife's past and her relations with +Dolokhov, Pierre saw clearly that what was said in the letter might be +true, or might at least seem to be true had it not referred to his +wife. He involuntarily remembered how Dolokhov, who had fully +recovered his former position after the campaign, had returned to +Petersburg and come to him. Availing himself of his friendly relations +with Pierre as a boon companion, Dolokhov had come straight to his +house, and Pierre had put him up and lent him money. Pierre recalled +how Helene had smilingly expressed disapproval of Dolokhov's living at +their house, and how cynically Dolokhov had praised his wife's +beauty to him and from that time till they came to Moscow had not left +them for a day. + +"Yes, he is very handsome," thought Pierre, "and I know him. It +would be particularly pleasant to him to dishonor my name and ridicule +me, just because I have exerted myself on his behalf, befriended +him, and helped him. I know and understand what a spice that would add +to the pleasure of deceiving me, if it really were true. Yes, if it +were true, but I do not believe it. I have no right to, and can't, +believe it." He remembered the expression Dolokhov's face assumed in +his moments of cruelty, as when tying the policeman to the bear and +dropping them into the water, or when he challenged a man to a duel +without any reason, or shot a post-boy's horse with a pistol. That +expression was often on Dolokhov's face when looking at him. "Yes, +he is a bully," thought Pierre, "to kill a man means nothing to him. +It must seem to him that everyone is afraid of him, and that must +please him. He must think that I, too, am afraid of him--and in fact I +am afraid of him," he thought, and again he felt something terrible +and monstrous rising in his soul. Dolokhov, Denisov, and Rostov were +now sitting opposite Pierre and seemed very gay. Rostov was talking +merrily to his two friends, one of whom was a dashing hussar and the +other a notorious duelist and rake, and every now and then he +glanced ironically at Pierre, whose preoccupied, absent-minded, and +massive figure was a very noticeable one at the dinner. Rostov +looked inimically at Pierre, first because Pierre appeared to his +hussar eyes as a rich civilian, the husband of a beauty, and in a +word--an old woman; and secondly because Pierre in his preoccupation +and absent-mindedness had not recognized Rostov and had not +responded to his greeting. When the Emperor's health was drunk, +Pierre, lost in thought, did not rise or lift his glass. + +"What are you about?" shouted Rostov, looking at him in an ecstasy +of exasperation. "Don't you hear it's His Majesty the Emperor's +health?" + +Pierre sighed, rose submissively, emptied his glass, and, waiting +till all were seated again, turned with his kindly smile to Rostov. + +"Why, I didn't recognize you!" he said. But Rostov was otherwise +engaged; he was shouting "Hurrah!" + +"Why don't you renew the acquaintance?" said Dolokhov to Rostov. + +"Confound him, he's a fool!" said Rostov. + +"One should make up to the husbands of pretty women," said Denisov. + +Pierre did not catch what they were saying, but knew they were +talking about him. He reddened and turned away. + +"Well, now to the health of handsome women!" said Dolokhov, and with +a serious expression, but with a smile lurking at the corners of his +mouth, he turned with his glass to Pierre. + +"Here's to the health of lovely women, Peterkin--and their +lovers!" he added. + +Pierre, with downcast eyes, drank out of his glass without looking +at Dolokhov or answering him. The footman, who was distributing +leaflets with Kutuzov's cantata, laid one before Pierre as one of +the principal guests. He was just going to take it when Dolokhov, +leaning across, snatched it from his hand and began reading it. Pierre +looked at Dolokhov and his eyes dropped, the something terrible and +monstrous that had tormented him all dinnertime rose and took +possession of him. He leaned his whole massive body across the table. + +"How dare you take it?" he shouted. + +Hearing that cry and seeing to whom it was addressed, Nesvitski +and the neighbor on his right quickly turned in alarm to Bezukhov. + +"Don't! Don't! What are you about?" whispered their frightened +voices. + +Dolokhov looked at Pierre with clear, mirthful, cruel eyes, and that +smile of his which seemed to say, "Ah! This is what I like!" + +"You shan't have it!" he said distinctly. + +Pale, with quivering lips, Pierre snatched the copy. + +"You...! you... scoundrel! I challenge you!" he ejaculated, and, +pushing back his chair, he rose from the table. + +At the very instant he did this and uttered those words, Pierre felt +that the question of his wife's guilt which had been tormenting him +the whole day was finally and indubitably answered in the affirmative. +He hated her and was forever sundered from her. Despite Denisov's +request that he would take no part in the matter, Rostov agreed to +be Dolokhov's second, and after dinner he discussed the arrangements +for the duel with Nesvitski, Bezukhov's second. Pierre went home, +but Rostov with Dolokhov and Denisov stayed on at the Club till +late, listening to the gypsies and other singers. + +"Well then, till tomorrow at Sokolniki," said Dolokhov, as he took +leave of Rostov in the Club porch. + +"And do you feel quite calm?" Rostov asked. + +Dolokhov paused. + +"Well, you see, I'll tell you the whole secret of dueling in two +words. If you are going to fight a duel, and you make a will and write +affectionate letters to your parents, and if you think you may be +killed, you are a fool and are lost for certain. But go with the +firm intention of killing your man as quickly and surely as +possible, and then all will be right, as our bear huntsman at Kostroma +used to tell me. 'Everyone fears a bear,' he says, 'but when you see +one your fear's all gone, and your only thought is not to let him +get away!' And that's how it is with me. A demain, mon cher."* + + +*Till tomorrow, my dear fellow. + + +Next day, at eight in the morning, Pierre and Nesvitski drove to the +Sokolniki forest and found Dolokhov, Denisov, and Rostov already +there. Pierre had the air of a man preoccupied with considerations +which had no connection with the matter in hand. His haggard face +was yellow. He had evidently not slept that night. He looked about +distractedly and screwed up his eyes as if dazzled by the sun. He +was entirely absorbed by two considerations: his wife's guilt, of +which after his sleepless night he had not the slightest doubt, and +the guiltlessness of Dolokhov, who had no reason to preserve the honor +of a man who was nothing to him.... "I should perhaps have done the +same thing in his place," thought Pierre. "It's even certain that I +should have done the same, then why this duel, this murder? Either I +shall kill him, or he will hit me in the head, or elbow, or knee. +Can't I go away from here, run away, bury myself somewhere?" passed +through his mind. But just at moments when such thoughts occurred to +him, he would ask in a particularly calm and absent-minded way, +which inspired the respect of the onlookers, "Will it be long? Are +things ready?" + +When all was ready, the sabers stuck in the snow to mark the +barriers, and the pistols loaded, Nesvitski went up to Pierre. + +"I should not be doing my duty, Count," he said in timid tones, "and +should not justify your confidence and the honor you have done me in +choosing me for your second, if at this grave, this very grave, moment +I did not tell you the whole truth. I think there is no sufficient +ground for this affair, or for blood to be shed over it.... You were +not right, not quite in the right, you were impetuous..." + +"Oh yes, it is horribly stupid," said Pierre. + +"Then allow me to express your regrets, and I am sure your +opponent will accept them," said Nesvitski (who like the others +concerned in the affair, and like everyone in similar cases, did not +yet believe that the affair had come to an actual duel). "You know, +Count, it is much more honorable to admit one's mistake than to let +matters become irreparable. There was no insult on either side. +Allow me to convey...." + +"No! What is there to talk about?" said Pierre. "It's all the +same.... Is everything ready?" he added. "Only tell me where to go and +where to shoot," he said with an unnaturally gentle smile. + +He took the pistol in his hand and began asking about the working of +the trigger, as he had not before held a pistol in his hand--a fact +that he did not to confess. + +"Oh yes, like that, I know, I only forgot," said he. + +"No apologies, none whatever," said Dolokhov to Denisov (who on +his side had been attempting a reconciliation), and he also went up to +the appointed place. + +The spot chosen for the duel was some eighty paces from the road, +where the sleighs had been left, in a small clearing in the pine +forest covered with melting snow, the frost having begun to break up +during the last few days. The antagonists stood forty paces apart at +the farther edge of the clearing. The seconds, measuring the paces, +left tracks in the deep wet snow between the place where they had been +standing and Nesvitski's and Dolokhov's sabers, which were stuck +intothe ground ten paces apart to mark the barrier. It was thawing and +misty; at forty paces' distance nothing could be seen. For three +minutes all had been ready, but they still delayed and all were +silent. + + + + + +CHAPTER V + + +"Well begin!" said Dolokhov. + +"All right," said Pierre, still smiling in the same way. A feeling +of dread was in the air. It was evident that the affair so lightly +begun could no longer be averted but was taking its course +independently of men's will. + +Denisov first went to the barrier and announced: "As the adve'sawies +have wefused a weconciliation, please pwoceed. Take your pistols, +and at the word thwee begin to advance. + +"O-ne! T-wo! Thwee!" he shouted angrily and stepped aside. + +The combatants advanced along the trodden tracks, nearer and +nearer to one another, beginning to see one another through the +mist. They had the right to fire when they liked as they approached +the barrier. Dolokhov walked slowly without raising his pistol, +looking intently with his bright, sparkling blue eyes into his +antagonist's face. His mouth wore its usual semblance of a smile. + +"So I can fire when I like!" said Pierre, and at the word "three," +he went quickly forward, missing the trodden path and stepping into +the deep snow. He held the pistol in his right hand at arm's length, +apparently afraid of shooting himself with it. His left hand he held +carefully back, because he wished to support his right hand with it +and knew he must not do so. Having advanced six paces and strayed +off the track into the snow, Pierre looked down at his feet, then +quickly glanced at Dolokhov and, bending his finger as he had been +shown, fired. Not at all expecting so loud a report, Pierre +shuddered at the sound and then, smiling at his own sensations, +stood still. The smoke, rendered denser by the mist, prevented him +from seeing anything for an instant, but there was no second report as +he had expected. He only heard Dolokhov's hurried steps, and his +figure came in view through the smoke. He was pressing one hand to his +left side, while the other clutched his drooping pistol. His face +was pale. Rostov ran toward him and said something. + +"No-o-o!" muttered Dolokhov through his teeth, "no, it's not +over." And after stumbling a few staggering steps right up to the +saber, he sank on the snow beside it. His left hand was bloody; he +wiped it on his coat and supported himself with it. His frowning +face was pallid and quivered. + +"Plea..." began Dolokhov, but could not at first pronounce the word. + +"Please," he uttered with an effort. + +Pierre, hardly restraining his sobs, began running toward Dolokhov +and was about to cross the space between the barriers, when Dolokhov +cried: + +"To your barrier!" and Pierre, grasping what was meant, stopped by +his saber. Only ten paces divided them. Dolokhov lowered his head to +the snow, greedily bit at it, again raised his head, adjusted himself, +drew in his legs and sat up, seeking a firm center of gravity. He +sucked and swallowed the cold snow, his lips quivered but +his eyes, still smiling, glittered with effort and exasperation as +he mustered his remaining strength. He raised his pistol and aimed. + +"Sideways! Cover yourself with your pistol!" ejaculated Nesvitski. + +"Cover yourself!" even Denisov cried to his adversary. + +Pierre, with a gentle smile of pity and remorse, his arms and legs +helplessly spread out, stood with his broad chest directly facing +Dolokhov looked sorrowfully at him. Denisov, Rostov, and Nesvitski +closed their eyes. At the same instant they heard a report and +Dolokhov's angry cry. + +"Missed!" shouted Dolokhov, and he lay helplessly, face downwards on +the snow. + +Pierre clutched his temples, and turning round went into the forest, +trampling through the deep snow, and muttering incoherent words: + +"Folly... folly! Death... lies..." he repeated, puckering his face. + +Nesvitski stopped him and took him home. + +Rostov and Denisov drove away with the wounded Dolokhov. + +The latter lay silent in the sleigh with closed eyes and did not +answer a word to the questions addressed to him. But on entering +Moscow he suddenly came to and, lifting his head with an effort, +took Rostov, who was sitting beside him, by the hand. Rostov was +struck by the totally altered and unexpectedly rapturous and tender +expression on Dolokhov's face. + +"Well? How do you feel?" he asked. + +"Bad! But it's not that, my friend-" said Dolokhov with a gasping +voice. "Where are we? In Moscow, I know. I don't matter, but I have +killed her, killed... She won't get over it! She won't survive...." + +"Who?" asked Rostov. + +"My mother! My mother, my angel, my adored angel mother," and +Dolokhov pressed Rostov's hand and burst into tears. + +When he had become a little quieter, he explained to Rostov that +he was living with his mother, who, if she saw him dying, would not +survive it. He implored Rostov to go on and prepare her. + +Rostov went on ahead to do what was asked, and to his great surprise +learned that Dolokhov the brawler, Dolokhov the bully, lived in Moscow +with an old mother and a hunchback sister, and was the most +affectionate of sons and brothers. + + + + + +CHAPTER VI + + +Pierre had of late rarely seen his wife alone. Both in Petersburg +and in Moscow their house was always full of visitors. The night after +the duel he did not go to his bedroom but, as he often did, remained +in his father's room, that huge room in which Count Bezukhov had died. + +He lay down on the sofa meaning to fall asleep and forget all that +had happened to him, but could not do so. Such a storm of feelings, +thoughts, and memories suddenly arose within him that he could not +fall asleep, nor even remain in one place, but had to jump up and pace +the room with rapid steps. Now he seemed to see her in the early +days of their marriage, with bare shoulders and a languid, +passionate look on her face, and then immediately he saw beside her +Dolokhov's handsome, insolent, hard, and mocking face as he had seen +it at the banquet, and then that same face pale, quivering, and +suffering, as it had been when he reeled and sank on the snow. + +"What has happened?" he asked himself. "I have killed her lover, +yes, killed my wife's lover. Yes, that was it! And why? How did I come +to do it?"--"Because you married her," answered an inner voice. + +"But in what was I to blame?" he asked. "In marrying her without +loving her; in deceiving yourself and her." And he vividly recalled +that moment after supper at Prince Vasili's, when he spoke those words +he had found so difficult to utter: "I love you." "It all comes from +that! Even then I felt it," he thought. "I felt then that it was not +so, that I had no right to do it. And so it turns out." + +He remembered his honeymoon and blushed at the recollection. +Particularly vivid, humiliating, and shameful was the recollection +of how one day soon after his marriage he came out of the bedroom into +his study a little before noon in his silk dressing gown and found his +head steward there, who, bowing respectfully, looked into his face and +at his dressing gown and smiled slightly, as if expressing +respectful understanding of his employer's happiness. + +"But how often I have felt proud of her, proud of her majestic +beauty and social tact," thought he; "been proud of my house, in +which she received all Petersburg, proud of her unapproachability and +beauty. So this is what I was proud of! I then thought that I did +not understand her. How often when considering her character I have +told myself that I was to blame for not understanding her, for not +understanding that constant composure and complacency and lack of +all interests or desires, and the whole secret lies in the terrible +truth that she is a depraved woman. Now I have spoken that terrible +word to myself all has become clear. + +"Anatole used to come to borrow money from her and used to kiss +her naked shoulders. She did not give him the money, but let herself +be kissed. Her father in jest tried to rouse her jealousy, and she +replied with a calm smile that she was not so stupid as to be jealous: +'Let him do what he pleases,' she used to say of me. One day I asked +her if she felt any symptoms of pregnancy. She laughed +contemptuously and said she was not a fool to want to have children, +and that she was not going to have any children by me." + +Then he recalled the coarseness and bluntness of her thoughts and +the vulgarity of the expressions that were natural to her, though +she had been brought up in the most aristocratic circles. + +"I'm not such a fool.... Just you try it on.... Allez-vous +promener,"* she used to say. Often seeing the success she had with +young and old men and women Pierre could not understand why he did not +love her. + + +*"You clear out of this." + + +"Yes, I never loved her," said he to himself; "I knew she was a +depraved woman," he repeated, "but dared not admit it to myself. And +now there's Dolokhov sitting in the snow with a forced smile and +perhaps dying, while meeting my remorse with some forced bravado!" + +Pierre was one of those people who, in spite of an appearance of +what is called weak character, do not seek a confidant in their +troubles. He digested his sufferings alone. + +"It is all, all her fault," he said to himself; "but what of that? +Why did I bind myself to her? Why did I say 'Je vous aime'* to her, +which was a lie, and worse than a lie? I am guilty and must +endure... what? A slur on my name? A misfortune for life? Oh, that's +nonsense," he thought. "The slur on my name and honor--that's all +apart from myself. + + +*I love you. + + +"Louis XVI was executed because they said he was dishonorable and +a criminal," came into Pierre's head, "and from their point of view +they were right, as were those too who canonized him and died a +martyr's death for his sake. Then Robespierre was beheaded for being a +despot. Who is right and who is wrong? No one! But if you are alive- +live: tomorrow you'll die as I might have died an hour ago. And is +it worth tormenting oneself, when one has only a moment of life in +comparison with eternity?" + +But at the moment when he imagined himself calmed by such +reflections, she suddenly came into his mind as she was at the moments +when he had most strongly expressed his insincere love for her, and he +felt the blood rush to his heart and had again to get up and move +about and break and tear whatever came to his hand. "Why did I tell +her that 'Je vous aime'?" he kept repeating to himself. And when he +had said it for the tenth time, Molibre's words: "Mais que diable +alloit-il faire dans cette galere?" occurred to him, and he began to +laugh at himself. + +In the night he called his valet and told him to pack up to go to +Petersburg. He could not imagine how he could speak to her now. He +resolved to go away next day and leave a letter informing her of his +intention to part from her forever. + +Next morning when the valet came into the room with his coffee, +Pierre was lying asleep on the ottoman with an open book in his hand. + +He woke up and looked round for a while with a startled +expression, unable to realize where he was. + +"The countess told me to inquire whether your excellency was at +home," said the valet. + +But before Pierre could decide what answer he would send, the +countess herself in a white satin dressing gown embroidered with +silver and with simply dressed hair (two immense plaits twice round +her lovely head like a coronet) entered the room, calm and majestic, +except that there was a wrathful wrinkle on her rather prominent +marble brow. With her imperturbable calm she did not begin to speak in +front of the valet. She knew of the duel and had come to speak about +it. She waited till the valet had set down the coffee things and +left the room. Pierre looked at her timidly over his spectacles, and +like a hare surrounded by hounds who lays back her ears and +continues to crouch motionless before her enemies, he tried to +continue reading. But feeling this to be senseless and impossible, +he again glanced timidly at her. She did not sit down but looked at +him with a contemptuous smile, waiting for the valet to go. + +"Well, what's this now? What have you been up to now, I should +like to know?" she asked sternly. + +"I? What have I...?" stammered Pierre. + +"So it seems you're a hero, eh? Come now, what was this duel +about? What is it meant to prove? What? I ask you." + +Pierre turned over heavily on the ottoman and opened his mouth, +but could not reply. + +"If you won't answer, I'll tell you..." Helene went on. "You believe +everything you're told. You were told..." Helene laughed, "that +Dolokhov was my lover," she said in French with her coarse plainness +of speech, uttering the word amant as casually as any other word, "and +you believed it! Well, what have you proved? What does this duel +prove? That you're a fool, que vous etes un sot, but everybody knew +that. What will be the result? That I shall be the laughingstock of +all Moscow, that everyone will say that you, drunk and not knowing +what you were about, challenged a man you are jealous of without +cause." Helene raised her voice and became more and more excited, "A +man who's a better man than you in every way..." + +"Hm... Hm...!" growled Pierre, frowning without looking at her, +and not moving a muscle. + +"And how could you believe he was my lover? Why? Because I like +his company? If you were cleverer and more agreeable, I should +prefer yours." + +"Don't speak to me... I beg you," muttered Pierre hoarsely. + +"Why shouldn't I speak? I can speak as I like, and I tell you +plainly that there are not many wives with husbands such as you who +would not have taken lovers (des amants), but I have not done so," +said she. + +Pierre wished to say something, looked at her with eyes whose +strange expression she did not understand, and lay down again. He +was suffering physically at that moment, there was a weight on his +chest and he could not breathe. He knew that he must do something to +put an end to this suffering, but what he wanted to do was too +terrible. + +"We had better separate," he muttered in a broken voice. + +"Separate? Very well, but only if you give me a fortune," said +Helene. "Separate! That's a thing to frighten me with!" + +Pierre leaped up from the sofa and rushed staggering toward her. + +"I'll kill you!" he shouted, and seizing the marble top of a table +with a strength he had never before felt, he made a step toward her +brandishing the slab. + +Helene's face became terrible, she shrieked and sprang aside. His +father's nature showed itself in Pierre. He felt the fascination and +delight of frenzy. He flung down the slab, broke it, and swooping down +on her with outstretched hands shouted, "Get out!" in such a +terrible voice that the whole house heard it with horror. God knows +what he would have done at that moment had Helene not fled from the +room. + + +A week later Pierre gave his wife full power to control all his +estates in Great Russia, which formed the larger part of his property, +and left for Petersburg alone. + + + + + +CHAPTER VII + + +Two months had elapsed since the news of the battle of Austerlitz +and the loss of Prince Andrew had reached Bald Hills, and in spite +of the letters sent through the embassy and all the searches made, his +body had not been found nor was he on the list of prisoners. What +was worst of all for his relations was the fact that there was still a +possibility of his having been picked up on the battlefield by the +people of the place and that he might now be lying, recovering or +dying, alone among strangers and unable to send news of himself. The +gazettes from which the old prince first heard of the defeat at +Austerlitz stated, as usual very briefly and vaguely, that after +brilliant engagements the Russians had had to retreat and had made +their withdrawal in perfect order. The old prince understood from this +official report that our army had been defeated. A week after the +gazette report of the battle of Austerlitz came a letter from +Kutuzov informing the prince of the fate that had befallen his son. + +"Your son," wrote Kutuzov, "fell before my eyes, a standard in his +hand and at the head of a regiment--he fell as a hero, worthy of his +father and his fatherland. To the great regret of myself and of the +whole army it is still uncertain whether he is alive or not. I comfort +myself and you with the hope that your son is alive, for otherwise +he would have been mentioned among the officers found on the field +of battle, a list of whom has been sent me under flag of truce." + +After receiving this news late in the evening, when he was alone +in his study, the old prince went for his walk as usual next +morning, but he was silent with his steward, the gardener, and the +architect, and though he looked very grim he said nothing to anyone. + +When Princess Mary went to him at the usual hour he was working at +his lathe and, as usual, did not look round at her. + +"Ah, Princess Mary!" he said suddenly in an unnatural voice, +throwing down his chisel. (The wheel continued to revolve by its own +impetus, and Princess Mary long remembered the dying creak of that +wheel, which merged in her memory with what followed.) + +She approached him, saw his face, and something gave way within her. +Her eyes grew dim. By the expression of her father's face, not sad, +not crushed, but angry and working unnaturally, she saw that hanging +over her and about to crush her was some terrible misfortune, the +worst in life, one she had not yet experienced, irreparable and +incomprehensible--the death of one she loved. + +"Father! Andrew!"--said the ungraceful, awkward princess with such +an indescribable charm of sorrow and self-forgetfulness that her +father could not bear her look but turned away with a sob. + +"Bad news! He's not among the prisoners nor among the killed! +Kutuzov writes..." and he screamed as piercingly as if he wished to +drive the princess away by that scream... "Killed!" + +The princess did not fall down or faint. She was already pale, but +on hearing these words her face changed and something brightened in +her beautiful, radiant eyes. It was as if joy--a supreme joy apart +from the joys and sorrows of this world--overflowed the great grief +within her. She forgot all fear of her father, went up to him, took +his hand, and drawing him down put her arm round his thin, scraggy +neck. + +"Father," she said, "do not turn away from me, let us weep together." + +"Scoundrels! Blackguards!" shrieked the old man, turning his face +away from her. "Destroying the army, destroying the men! And why? +Go, go and tell Lise." + +The princess sank helplessly into an armchair beside her father +and wept. She saw her brother now as he had been at the moment when he +took leave of her and of Lise, his look tender yet proud. She saw +him tender and amused as he was when he put on the little icon. "Did +he believe? Had he repented of his unbelief? Was he now there? There +in the realms of eternal peace and blessedness?" she thought. + +"Father, tell me how it happened," she asked through her tears. + +"Go! Go! Killed in battle, where the best of Russian men and +Russia's glory were led to destruction. Go, Princess Mary. Go and tell +Lise. I will follow." + +When Princess Mary returned from her father, the little princess sat +working and looked up with that curious expression of inner, happy +calm peculiar to pregnant women. It was evident that her eyes did +not see Princess Mary but were looking within... into herself... at +something joyful and mysterious taking place within her. + +"Mary," she said, moving away from the embroidery frame and lying +back, "give me your hand." She took her sister-in-law's hand and +held it below her waist. + +Her eyes were smiling expectantly, her downy lip rose and remained +lifted in childlike happiness. + +Princess Mary knelt down before her and hid her face in the folds of +her sister-in-law's dress. + +"There, there! Do you feel it? I feel so strange. And do you know, +Mary, I am going to love him very much," said Lise, looking with +bright and happy eyes at her sister-in-law. + +Princess Mary could not lift her head, she was weeping. + +"What is the matter, Mary?" + +"Nothing... only I feel sad... sad about Andrew," she said, wiping +away her tears on her sister-in-law's knee. + +Several times in the course of the morning Princess Mary began +trying to prepare her sister-in-law, and every time began to cry. +Unobservant as was the little princess, these tears, the cause of +which she did not understand, agitated her. She said nothing but +looked about uneasily as if in search of something. Before dinner +the old prince, of whom she was always afraid, came into her room with +a peculiarly restless and malign expression and went out again without +saying a word. She looked at Princess Mary, then sat thinking for a +while with that expression of attention to something within her that +is only seen in pregnant women, and suddenly began to cry. + +"Has anything come from Andrew?" she asked. + +"No, you know it's too soon for news. But my father is anxious and I +feel afraid." + +"So there's nothing?" + +"Nothing," answered Princess Mary, looking firmly with her radiant +eyes at her sister-in-law. + +She had determined not to tell her and persuaded her father to +hide the terrible news from her till after her confinement, which +was expected within a few days. Princess Mary and the old prince +each bore and hid their grief in their own way. The old prince would +not cherish any hope: he made up his mind that Prince Andrew had +been killed, and though he sent an official to Austria to seek for +traces of his son, he ordered a monument from Moscow which he intended +to erect in his own garden to his memory, and he told everybody that +his son had been killed. He tried not to change his former way of +life, but his strength failed him. He walked less, ate less, slept +less, and became weaker every day. Princess Mary hoped. She prayed for +her brother as living and was always awaiting news of his return. + + + + + +CHAPTER VIII + + +"Dearest," said the little princess after breakfast on the morning +of the nineteenth March, and her downy little lip rose from old habit, +but as sorrow was manifest in every smile, the sound of every word, +and even every footstep in that house since the terrible news had +come, so now the smile of the little princess--influenced by the +general mood though without knowing its cause--was such as to remind +one still more of the general sorrow. + +"Dearest, I'm afraid this morning's fruschtique*--as Foka the cook +calls it--has disagreed with me." + + +*Fruhstuck: breakfast. + + +"What is the matter with you, my darling? You look pale. Oh, you are +very pale!" said Princess Mary in alarm, running with her soft, +ponderous steps up to her sister-in-law. + +"Your excellency, should not Mary Bogdanovna be sent for?" said +one of the maids who was present. (Mary Bogdanovna was a midwife +from the neighboring town, who had been at Bald Hills for the last +fortnight.) + +"Oh yes," assented Princess Mary, "perhaps that's it. I'll go. +Courage, my angel." She kissed Lise and was about to leave the room. + +"Oh, no, no!" And besides the pallor and the physical suffering on +the little princess' face, an expression of childish fear of +inevitable pain showed itself. + +"No, it's only indigestion?... Say it's only indigestion, say so, +Mary! Say..." And the little princess began to cry capriciously like a +suffering child and to wring her little hands even with some +affectation. Princess Mary ran out of the room to fetch Mary +Bogdanovna. + +"Mon Dieu! Mon Dieu! Oh!" she heard as she left the room. + +The midwife was already on her way to meet her, rubbing her small, +plump white hands with an air of calm importance. + +"Mary Bogdanovna, I think it's beginning!" said Princess Mary +looking at the midwife with wide-open eyes of alarm. + +"Well, the Lord be thanked, Princess," said Mary Bogdanovna, not +hastening her steps. "You young ladies should not know anything +about it." + +"But how is it the doctor from Moscow is not here yet?" said the +princess. (In accordance with Lise's and Prince Andrew's wishes they +had sent in good time to Moscow for a doctor and were expecting him at +any moment.) + +"No matter, Princess, don't be alarmed," said Mary Bogdanovna. +"We'll manage very well without a doctor." + +Five minutes later Princess Mary from her room heard something heavy +being carried by. She looked out. The men servants were carrying the +large leather sofa from Prince Andrew's study into the bedroom. On +their faces was a quiet and solemn look. + +Princess Mary sat alone in her room listening to the sounds in the +house, now and then opening her door when someone passed and +watching what was going on in the passage. Some women passing with +quiet steps in and out of the bedroom glanced at the princess and +turned away. She did not venture to ask any questions, and shut the +door again, now sitting down in her easy chair, now taking her +prayer book, now kneeling before the icon stand. To her surprise and +distress she found that her prayers did not calm her excitement. +Suddenly her door opened softly and her old nurse, Praskovya Savishna, +who hardly ever came to that room as the old prince had forbidden +it, appeared on the threshold with a shawl round her head. + +"I've come to sit with you a bit, Masha," said the nurse, "and +here I've brought the prince's wedding candles to light before his +saint, my angel," she said with a sigh. + +"Oh, nurse, I'm so glad!" + +"God is merciful, birdie." + +The nurse lit the gilt candles before the icons and sat down by +the door with her knitting. Princess Mary took a book and began +reading. Only when footsteps or voices were heard did they look at one +another, the princess anxious and inquiring, the nurse encouraging. +Everyone in the house was dominated by the same feeling that +Princess Mary experienced as she sat in her room. But owing to the +superstition that the fewer the people who know of it the less a woman +in travail suffers, everyone tried to pretend not to know; no one +spoke of it, but apart from the ordinary staid and respectful good +manners habitual in the prince's household, a common anxiety, a +softening of the heart, and a consciousness that something great and +mysterious was being accomplished at that moment made itself felt. + +There was no laughter in the maids' large hall. In the men servants' +hall all sat waiting, silently and alert. In the outlying serfs' +quarters torches and candles were burning and no one slept. The old +prince, stepping on his heels, paced up and down his study and sent +Tikhon to ask Mary Bogdanovna what news.--"Say only that 'the prince +told me to ask,' and come and tell me her answer." + +"Inform the prince that labor has begun," said Mary Bogdanovna, +giving the messenger a significant look. + +Tikhon went and told the prince. + +"Very good!" said the prince closing the door behind him, and Tikhon +did not hear the slightest sound from the study after that. + +After a while he re-entered it as if to snuff the candles, and, +seeing the prince was lying on the sofa, looked at him, noticed his +perturbed face, shook his head, and going up to him silently kissed +him on the shoulder and left the room without snuffing the candles +or saying why he had entered. The most solemn mystery in the world +continued its course. Evening passed, night came, and the feeling of +suspense and softening of heart in the presence of the unfathomable +did not lessen but increased. No one slept. + +It was one of those March nights when winter seems to wish to resume +its sway and scatters its last snows and storms with desperate fury. A +relay of horses had been sent up the highroad to meet the German +doctor from Moscow who was expected every moment, and men on horseback +with lanterns were sent to the crossroads to guide him over the +country road with its hollows and snow-covered pools of water. + +Princess Mary had long since put aside her book: she sat silent, her +luminous eyes fixed on her nurse's wrinkled face (every line of +which she knew so well), on the lock of gray hair that escaped from +under the kerchief, and the loose skin that hung under her chin. + +Nurse Savishna, knitting in hand, was telling in low tones, scarcely +hearing or understanding her own words, what she had told hundreds +of times before: how the late princess had given birth to Princess +Mary in Kishenev with only a Moldavian peasant woman to help instead +of a midwife. + +"God is merciful, doctors are never needed," she said. + +Suddenly a gust of wind beat violently against the casement of the +window, from which the double frame had been removed (by order of +the prince, one window frame was removed in each room as soon as the +larks returned), and, forcing open a loosely closed latch, set the +damask curtain flapping and blew out the candle with its chill, +snowy draft. Princess Mary shuddered; her nurse, putting down the +stocking she was knitting, went to the window and leaning out tried to +catch the open casement. The cold wind flapped the ends of her +kerchief and her loose locks of gray hair. + +"Princess, my dear, there's someone driving up the avenue!" she +said, holding the casement and not closing it. "With lanterns. Most +likely the doctor." + +"Oh, my God! thank God!" said Princess Mary. "I must go and meet +him, he does not know Russian." + +Princess Mary threw a shawl over her head and ran to meet the +newcomer. As she was crossing the anteroom she saw through the +window a carriage with lanterns, standing at the entrance. She went +out on the stairs. On a banister post stood a tallow candle which +guttered in the draft. On the landing below, Philip, the footman, +stood looking scared and holding another candle. Still lower, beyond +the turn of the staircase, one could hear the footstep of someone in +thick felt boots, and a voice that seemed familiar to Princess Mary +was saying something. + +"Thank God!" said the voice. "And Father?" + +"Gone to bed," replied the voice of Demyan the house steward, who +was downstairs. + +Then the voice said something more, Demyan replied, and the steps in +the felt boots approached the unseen bend of the staircase more +rapidly. + +"It's Andrew!" thought Princess Mary. "No it can't be, that would be +too extraordinary," and at the very moment she thought this, the +face and figure of Prince Andrew, in a fur cloak the deep collar of +which covered with snow, appeared on the landing where the footman +stood with the candle. Yes, it was he, pale, thin, with a changed +and strangely softened but agitated expression on his face. He came up +the stairs and embraced his sister. + +"You did not get my letter?" he asked, and not waiting for a +reply--which he would not have received, for the princess was unable +to speak--he turned back, rapidly mounted the stairs again with the +doctor who had entered the hall after him (they had met at the last +post station), and again embraced his sister. + +"What a strange fate, Masha darling!" And having taken off his cloak +and felt boots, he went to the little princess' apartment. + + + + + +CHAPTER IX + + +The little princess lay supported by pillows, with a white cap on +her head (the pains had just left her). Strands of her black hair +lay round her inflamed and perspiring cheeks, her charming rosy +mouth with its downy lip was open and she was smiling joyfully. Prince +Andrew entered and paused facing her at the foot of the sofa on +which she was lying. Her glittering eyes, filled with childlike fear +and excitement, rested on him without changing their expression. "I +love you all and have done no harm to anyone; why must I suffer so? +Help me!" her look seemed to say. She saw her husband, but did not +realize the significance of his appearance before her now. Prince +Andrew went round the sofa and kissed her forehead. + +"My darling!" he said--a word he had never used to her before. +"God is merciful...." + +She looked at him inquiringly and with childlike reproach. + +"I expected help from you and I get none, none from you either!" +said her eyes. She was not surprised at his having come; she did not +realize that he had come. His coming had nothing to do with her +sufferings or with their relief. The pangs began again and Mary +Bogdanovna advised Prince Andrew to leave the room. + +The doctor entered. Prince Andrew went out and, meeting Princess +Mary, again joined her. They began talking in whispers, but their talk +broke off at every moment. They waited and listened. + +"Go, dear," said Princess Mary. + +Prince Andrew went again to his wife and sat waiting in the room +next to hers. A woman came from the bedroom with a frightened face and +became confused when she saw Prince Andrew. He covered his face with +his hands and remained so for some minutes. Piteous, helpless, +animal moans came through the door. Prince Andrew got up, went to +the door, and tried to open it. Someone was holding it shut. + +"You can't come in! You can't!" said a terrified voice from within. + +He began pacing the room. The screaming ceased, and a few more +seconds went by. Then suddenly a terrible shriek--it could not be +hers, she could not scream like that--came from the bedroom. Prince +Andrew ran to the door; the scream ceased and he heard the wail of +an infant. + +"What have they taken a baby in there for?" thought Prince Andrew in +the first second. "A baby? What baby...? Why is there a baby there? Or +is the baby born?" + +Then suddenly he realized the joyful significance of that wail; +tears choked him, and leaning his elbows on the window sill be began +to cry, sobbing like a child. The door opened. The doctor with his +shirt sleeves tucked up, without a coat, pale and with a trembling +jaw, came out of the room. Prince Andrew turned to him, but the doctor +gave him a bewildered look and passed by without a word. A woman +rushed out and seeing Prince Andrew stopped, hesitating on the +threshold. He went into his wife's room. She was lying dead, in the +same position he had seen her in five minutes before and, despite +the fixed eyes and the pallor of the cheeks, the same expression was +on her charming childlike face with its upper lip covered with tiny +black hair. + +"I love you all, and have done no harm to anyone; and what have +you done to me?"--said her charming, pathetic, dead face. + +In a corner of the room something red and tiny gave a grunt and +squealed in Mary Bogdanovna's trembling white hands. + + +Two hours later Prince Andrew, stepping softly, went into his +father's room. The old man already knew everything. He was standing +close to the door and as soon as it opened his rough old arms closed +like a vise round his son's neck, and without a word he began to sob +like a child. + + +Three days later the little princess was buried, and Prince Andrew +went up the steps to where the coffin stood, to give her the +farewell kiss. And there in the coffin was the same face, though +with closed eyes. "Ah, what have you done to me?" it still seemed to +say, and Prince Andrew felt that something gave way in his soul and +that he was guilty of a sin he could neither remedy nor forget. He +could not weep. The old man too came up and kissed the waxen little +hands that lay quietly crossed one on the other on her breast, and +to him, too, her face seemed to say: "Ah, what have you done to me, +and why?" And at the sight the old man turned angrily away. + + +Another five days passed, and then the young Prince Nicholas +Andreevich was baptized. The wet nurse supported the coverlet with her +while the priest with a goose feather anointed the boy's little red +and wrinkled soles and palms. + +His grandfather, who was his godfather, trembling and afraid of +dropping him, carried the infant round the battered tin font and +handed him over to the godmother, Princess Mary. Prince Andrew sat +in another room, faint with fear lest the baby should be drowned in +the font, and awaited the termination of the ceremony. He looked up +joyfully at the baby when the nurse brought it to him and nodded +approval when she told him that the wax with the baby's hair had not +sunk in the font but had floated. + + + + + +CHAPTER X + + +Rostov's share in Dolokhov's duel with Bezukhov was hushed up by the +efforts of the old count, and instead of being degraded to the ranks +as he expected he was appointed an adjutant to the governor general of +Moscow. As a result he could not go to the country with the rest of +the family, but was kept all summer in Moscow by his new duties. +Dolokhov recovered, and Rostov became very friendly with him during +his convalescence. Dolokhov lay ill at his mother's who loved him +passionately and tenderly, and old Mary Ivanovna, who had grown fond +of Rostov for his friendship to her Fedya, often talked to him about +her son. + +"Yes, Count," she would say, "he is too noble and pure-souled for +our present, depraved world. No one now loves virtue; it seems like +a reproach to everyone. Now tell me, Count, was it right, was it +honorable, of Bezukhov? And Fedya, with his noble spirit, loved him +and even now never says a word against him. Those pranks in Petersburg +when they played some tricks on a policeman, didn't they do it +together? And there! Bezukhov got off scotfree, while Fedya had to +bear the whole burden on his shoulders. Fancy what he had to go +through! It's true he has been reinstated, but how could they fail +to do that? I think there were not many such gallant sons of the +fatherland out there as he. And now--this duel! Have these people no +feeling, or honor? Knowing him to be an only son, to challenge him and +shoot so straight! It's well God had mercy on us. And what was it for? +Who doesn't have intrigues nowadays? Why, if he was so jealous, as I +see things he should have shown it sooner, but he lets it go on for +months. And then to call him out, reckoning on Fedya not fighting +because he owed him money! What baseness! What meanness! I know you +understand Fedya, my dear count; that, believe me, is why I am so fond +of you. Few people do understand him. He is such a lofty, heavenly +soul!" + +Dolokhov himself during his convalescence spoke to Rostov in a way +no one would have expected of him. + +"I know people consider me a bad man!" he said. "Let them! I don't +care a straw about anyone but those I love; but those I love, I love +so that I would give my life for them, and the others I'd throttle +if they stood in my way. I have an adored, a priceless mother, and two +or three friends--you among them--and as for the rest I only care +about them in so far as they are harmful or useful. And most of them +are harmful, especially the women. Yes, dear boy," he continued, "I +have met loving, noble, high-minded men, but I have not yet met any +women--countesses or cooks--who were not venal. I have not yet met +that divine purity and devotion I look for in women. If I found such a +one I'd give my life for her! But those!..." and he made a gesture of +contempt. "And believe me, if I still value my life it is only because +I still hope to meet such a divine creature, who will regenerate, +purify, and elevate me. But you don't understand it." + +"Oh, yes, I quite understand," answered Rostov, who was under his +new friend's influence. + +In the autumn the Rostovs returned to Moscow. Early in the winter +Denisov also came back and stayed with them. The first half of the +winter of 1806, which Nicholas Rostov spent in Moscow, was one of +the happiest, merriest times for him and the whole family. Nicholas +brought many young men to his parents' house. Vera was a handsome girl +of twenty; Sonya a girl of sixteen with all the charm of an opening +flower; Natasha, half grown up and half child, was now childishly +amusing, now girlishly enchanting. + +At that time in the Rostovs' house there prevailed an amorous +atmosphere characteristic of homes where there are very young and very +charming girls. Every young man who came to the house--seeing those +impressionable, smiling young faces (smiling probably at their own +happiness), feeling the eager bustle around him, and hearing the +fitful bursts of song and music and the inconsequent but friendly +prattle of young girls ready for anything and full of hope- +experienced the same feeling; sharing with the young folk of the +Rostovs' household a readiness to fall in love and an expectation of +happiness. + +Among the young men introduced by Rostov one of the first was +Dolokhov, whom everyone in the house liked except Natasha. She +almost quarreled with her brother about him. She insisted that he +was a bad man, and that in the duel with Bezukhov, Pierre was right +and Dolokhov wrong, and further that he was disagreeable and +unnatural. + +"There's nothing for me to understand," cried out with resolute +self-will, "he is wicked and heartless. There now, I like your Denisov +though he is a rake and all that, still I like him; so you see I do +understand. I don't know how to put it... with this one everything +is calculated, and I don't like that. But Denisov..." + +"Oh, Denisov is quite different," replied Nicholas, implying that +even Denisov was nothing compared to Dolokhov--"you must understand +what a soul there is in Dolokhov, you should see him with his +mother. What a heart!" + +"Well, I don't know about that, but I am uncomfortable with him. And +do you know he has fallen in love with Sonya?" + +"What nonsense..." + +"I'm certain of it; you'll see." + +Natasha's prediction proved true. Dolokhov, who did not usually care +for the society of ladies, began to come often to the house, and the +question for whose sake he came (though no one spoke of it) was soon +settled. He came because of Sonya. And Sonya, though she would never +have dared to say so, knew it and blushed scarlet every time +Dolokhov appeared. + +Dolokhov often dined at the Rostovs', never missed a performance +at which they were present, and went to Iogel's balls for young people +which the Rostovs always attended. He was pointedly attentive to Sonya +and looked at her in such a way that not only could she not bear his +glances without coloring, but even the old countess and Natasha +blushed when they saw his looks. + +It was evident that this strange, strong man was under the +irresistible influence of the dark, graceful girl who loved another. + +Rostov noticed something new in Dolokhov's relations with Sonya, but +he did not explain to himself what these new relations were. +"They're always in love with someone," he thought of Sonya and +Natasha. But he was not as much at ease with Sonya and Dolokhov as +before and was less frequently at home. + +In the autumn of 1806 everybody had again begun talking of the war +with Napoleon with even greater warmth than the year before. Orders +were given to raise recruits, ten men in every thousand for the +regular army, and besides this, nine men in every thousand for the +militia. Everywhere Bonaparte was anathematized and in Moscow +nothing but the coming war was talked of. For the Rostov family the +whole interest of these preparations for war lay in the fact that +Nicholas would not hear of remaining in Moscow, and only awaited the +termination of Denisov's furlough after Christmas to return with him +to their regiment. His approaching departure did not prevent his +amusing himself, but rather gave zest to his pleasures. He spent the +greater part of his time away from home, at dinners, parties, and +balls. + + + + + +CHAPTER XI + + +On the third day after Christmas Nicholas dined at home, a thing +he had rarely done of late. It was a grand farewell dinner, as he +and Denisov were leaving to join their regiment after Epiphany. +About twenty people were present, including Dolokhov and Denisov. + +Never had love been so much in the air, and never had the amorous +atmosphere made itself so strongly felt in the Rostovs' house as at +this holiday time. "Seize the moments of happiness, love and be loved! +That is the only reality in the world, all else is folly. It is the +one thing we are interested in here," said the spirit of the place. + +Nicholas, having as usual exhausted two pairs of horses, without +visiting all the places he meant to go to and where he had been +invited, returned home just before dinner. As soon as he entered he +noticed and felt the tension of the amorous air in the house, and also +noticed a curious embarrassment among some of those present. Sonya, +Dolokhov, and the old countess were especially disturbed, and to a +lesser degree Natasha. Nicholas understood that something must have +happened between Sonya and Dolokhov before dinner, and with the kindly +sensitiveness natural to him was very gentle and wary with them both +at dinner. On that same evening there was to be one of the balls +that Iogel (the dancing master) gave for his pupils durings the +holidays. + +"Nicholas, will you come to Iogel's? Please do!" said Natasha. "He +asked you, and Vasili Dmitrich* is also going." + + +*Denisov. + + +"Where would I not go at the countess' command!" said Denisov, who +at the Rostovs' had jocularly assumed the role of Natasha's knight. +"I'm even weady to dance the pas de chale." + +"If I have time," answered Nicholas. "But I promised the +Arkharovs; they have a party." + +"And you?" he asked Dolokhov, but as soon as he had asked the +question he noticed that it should not have been put. + +"Perhaps," coldly and angrily replied Dolokhov, glancing at Sonya, +and, scowling, he gave Nicholas just such a look as he had given +Pierre at the Club dinner. + +"There is something up," thought Nicholas, and he was further +confirmed in this conclusion by the fact that Dolokhov left +immediately after dinner. He called Natasha and asked her what was the +matter. + +"And I was looking for you," said Natasha running out to him. "I +told you, but you would not believe it," she said triumphantly. "He +has proposed to Sonya!" + +Little as Nicholas had occupied himself with Sonya of late, +something seemed to give way within him at this news. Dolokhov was a +suitable and in some respects a brilliant match for the dowerless, +orphan girl. From the point of view of the old countess and of society +it was out of the question for her to refuse him. And therefore +Nicholas' first feeling on hearing the news was one of anger with +Sonya.... He tried to say, "That's capital; of course she'll forget +her childish promises and accept the offer," but before he had time to +say it Natasha began again. + +"And fancy! she refused him quite definitely!" adding, after a +pause, "she told him she loved another." + +"Yes, my Sonya could not have done otherwise!" thought Nicholas. + +"Much as Mamma pressed her, she refused, and I know she won't change +once she has said..." + +"And Mamma pressed her!" said Nicholas reproachfully. + +"Yes," said Natasha. "Do you know, Nicholas--don't be angry--but I +know you will not marry her. I know, heaven knows how, but I know +for certain that you won't marry her." + +"Now don't know that at all!" said Nicholas. "But I must talk to +her. What a darling Sonya is!" he added with a smile. + +"Ah, she is indeed a darling! I'll send her to you." + +And Natasha kissed her brother and ran away. + +A minute later Sonya came in with a frightened, guilty, and scared +look. Nicholas went up to her and kissed her hand. This was the +first time since his return that they had talked alone and about their +love. + +"Sophie," he began, timidly at first and then more and more +boldly, "if you wish to refuse one who is not only a brilliant and +advantageous match but a splendid, noble fellow... he is my friend..." + +Sonya interrupted him. + +"I have already refused," she said hurriedly. + +"If you are refusing for my sake, I am afraid that I..." + +Sonya again interrupted. She gave him an imploring, frightened look. + +"Nicholas, don't tell me that!" she said. + +"No, but I must. It may be arrogant of me, but still it is best to +say it. If you refuse him on my account, I must tell you the whole +truth. I love you, and I think I love you more than anyone else...." + +"That is enough for me," said Sonya, blushing. + +"No, but I have been in love a thousand times and shall fall in love +again, though for no one have I such a feeling of friendship, +confidence, and love as I have for you. Then I am young. Mamma does +not wish it. In a word, I make no promise. And I beg you to consider +Dolokhov's offer," he said, articulating his friend's name with +difficulty. + +"Don't say that to me! I want nothing. I love you as a brother and +always shall, and I want nothing more." + +"You are an angel: I am not worthy of you, but I am afraid of +misleading you." + +And Nicholas again kissed her hand. + + + + + +CHAPTER XII + + +Iogel's were the most enjoyable balls in Moscow. So said the mothers +as they watched their young people executing their newly learned +steps, and so said the youths and maidens themselves as they danced +till they were ready to drop, and so said the grown-up young men and +women who came to these balls with an air of condescension and found +them most enjoyable. That year two marriages had come of these +balls. The two pretty young Princesses Gorchakov met suitors there and +were married and so further increased the fame of these dances. What +distinguished them from others was the absence of host or hostess +and the presence of the good-natured Iogel, flying about like a +feather and bowing according to the rules of his art, as he +collected the tickets from all his visitors. There was the fact that +only those came who wished to dance and amuse themselves as girls of +thirteen and fourteen do who are wearing long dresses for the first +time. With scarcely any exceptions they all were, or seemed to be, +pretty--so rapturous were their smiles and so sparkling their eyes. +Sometimes the best of the pupils, of whom Natasha, who was +exceptionally graceful, was first, even danced the pas de chale, but +at this last ball only the ecossaise, the anglaise, and the mazurka, +which was just coming into fashion, were danced. Iogel had taken a +ballroom in Bezukhov's house, and the ball, as everyone said, was a +great success. There were many pretty girls and the Rostov girls +were among the prettiest. They were both particularly happy and gay. +That evening, proud of Dolokhov's proposal, her refusal, and her +explanation with Nicholas, Sonya twirled about before she left home so +that the maid could hardly get her hair plaited, and she was +transparently radiant with impulsive joy. + +Natasha no less proud of her first long dress and of being at a real +ball was even happier. They were both dressed in white muslin with +pink ribbons. + +Natasha fell in love the very moment she entered the ballroom. She +was not in love with anyone in particular, but with everyone. Whatever +person she happened to look at she was in love with for that moment. + +"Oh, how delightful it is!" she kept saying, running up to Sonya. + +Nicholas and Denisov were walking up and down, looking with kindly +patronage at the dancers. + +"How sweet she is--she will be a weal beauty!" said Denisov. + +"Who?" + +"Countess Natasha," answered Denisov. + +"And how she dances! What gwace!" he said again after a pause. + +"Who are you talking about?" + +"About your sister," ejaculated Denisov testily. + +Rostov smiled. + +"My dear count, you were one of my best pupils--you must dance," +said little Iogel coming up to Nicholas. "Look how many charming young +ladies-" He turned with the same request to Denisov who was also a +former pupil of his. + +"No, my dear fellow, I'll be a wallflower," said Denisov. "Don't you +wecollect what bad use I made of your lessons?" + +"Oh no!" said Iogel, hastening to reassure him. "You were only +inattentive, but you had talent--oh yes, you had talent!" + + The band struck up the newly introduced mazurka. Nicholas could not +refuse Iogel and asked Sonya to dance. Denisov sat down by the old +ladies and, leaning on his saber and beating time with his foot, +told them something funny and kept them amused, while he watched the +young people dancing, Iogel with Natasha, his pride and his best +pupil, were the first couple. Noiselessly, skillfully stepping with +his little feet in low shoes, Iogel flew first across the hall with +Natasha, who, though shy, went on carefully executing her steps. +Denisov did not take his eyes off her and beat time with his saber +in a way that clearly indicated that if he was not dancing it was +because he would not and not because he could not. In the middle of +a figure he beckoned to Rostov who was passing: + +"This is not at all the thing," he said. "What sort of Polish +mazuwka is this? But she does dance splendidly." + +Knowing that Denisov had a reputation even in Poland for the +masterly way in which he danced the mazurka, Nicholas ran up to +Natasha: + +"Go and choose Denisov. He is a real dancer, a wonder!" he said. + +When it came to Natasha's turn to choose a partner, she rose and, +tripping rapidly across in her little shoes trimmed with bows, ran +timidly to the corner where Denisov sat. She saw that everybody was +looking at her and waiting. Nicholas saw that Denisov was refusing +though he smiled delightedly. He ran up to them. + +"Please, Vasili Dmitrich," Natasha was saying, "do come!" + +"Oh no, let me off, Countess," Denisov replied. + +"Now then, Vaska," said Nicholas. + +"They coax me as if I were Vaska the cat!" said Denisov jokingly. + +"I'll sing for you a whole evening," said Natasha. + +"Oh, the faiwy! She can do anything with me!" said Denisov, and he +unhooked his saber. He came out from behind the chairs, clasped his +partner's hand firmly, threw back his head, and advanced his foot, +waiting for the beat. Only on horse back and in the mazurka was +Denisov's short stature not noticeable and he looked the fine fellow +he felt himself to be. At the right beat of the music he looked +sideways at his partner with a merry and triumphant air, suddenly +stamped with one foot, bounded from the floor like a ball, and flew +round the room taking his partner with him. He glided silently on +one foot half across the room, and seeming not to notice the chairs +was dashing straight at them, when suddenly, clinking his spurs and +spreading out his legs, he stopped short on his heels, stood so a +second, stamped on the spot clanking his spurs, whirled rapidly round, +and, striking his left heel against his right, flew round again in a +circle. Natasha guessed what he meant to do, and abandoning herself to +him followed his lead hardly knowing how. First he spun her round, +holding her now with his left, now with his right hand, then falling +on one knee he twirled her round him, and again jumping up, dashed +so impetuously forward that it seemed as if he would rush through +the whole suite of rooms without drawing breath, and then he +suddenly stopped and performed some new and unexpected steps. When +at last, smartly whirling his partner round in front of her chair, +he drew up with a click of his spurs and bowed to her, Natasha did not +even make him a curtsy. She fixed her eyes on him in amazement, +smiling as if she did not recognize him. + +"What does this mean?" she brought out. + +Although Iogel did not acknowledge this to be the real mazurka, +everyone was delighted with Denisov's skill, he was asked again and +again as a partner, and the old men began smilingly to talk about +Poland and the good old days. Denisov, flushed after the mazurka and +mopping himself with his handkerchief, sat down by Natasha and did not +leave her for the rest of the evening. + + + + + +CHAPTER XIII + + +For two days after that Rostov did not see Dolokhov at his own or at +Dolokhov's home: on the third day he received a note from him: + + +As I do not intend to be at your house again for reasons you know +of, and am going to rejoin my regiment, I am giving a farewell +supper tonight to my friends--come to the English Hotel. + + +About ten o'clock Rostov went to the English Hotel straight from the +theater, where he had been with his family and Denisov. He was at once +shown to the best room, which Dolokhov had taken for that evening. +Some twenty men were gathered round a table at which Dolokhov sat +between two candles. On the table was a pile of gold and paper +money, and he was keeping the bank. Rostov had not seen him since +his proposal and Sonya's refusal and felt uncomfortable at the thought +of how they would meet. + +Dolokhov's clear, cold glance met Rostov as soon as he entered the +door, as though he had long expected him. + +"It's a long time since we met," he said. "Thanks for coming. I'll +just finish dealing, and then Ilyushka will come with his chorus." + +"I called once or twice at your house," said Rostov, reddening. + +Dolokhov made no reply. + +"You may punt," he said. + +Rostov recalled at that moment a strange conversation he had once +had with Dolokhov. "None but fools trust to luck in play," Dolokhov +had then said. + +"Or are you afraid to play with me?" Dolokhov now asked as if +guessing Rostov's thought. + +Beneath his smile Rostov saw in him the mood he had shown at the +Club dinner and at other times, when as if tired of everyday life he +had felt a need to escape from it by some strange, and usually +cruel, action. + +Rostov felt ill at ease. He tried, but failed, to find some joke +with which to reply to Dolokhov's words. But before he had thought +of anything, Dolokhov, looking straight in his face, said slowly and +deliberately so that everyone could hear: + +"Do you remember we had a talk about cards... 'He's a fool who +trusts to luck, one should make certain,' and I want to try." + +"To try his luck or the certainty?" Rostov asked himself. + +"Well, you'd better not play," Dolokhov added, and springing a new +pack of cards said: "Bank, gentlemen!" + +Moving the money forward he prepared to deal. Rostov sat down by his +side and at first did not play. Dolokhov kept glancing at him. + +"Why don't you play?" he asked. + +And strange to say Nicholas felt that he could not help taking up +a card, putting a small stake on it, and beginning to play. + +"I have no money with me," he said. + +"I'll trust you." + +Rostov staked five rubles on a card and lost, staked again, and +again lost. Dolokhov "killed," that is, beat, ten cards of Rostov's +running. + +"Gentlemen," said Dolokhov after he had dealt for some time. "Please +place your money on the cards or I may get muddled in the reckoning." + +One of the players said he hoped he might be trusted. + +"Yes, you might, but I am afraid of getting the accounts mixed. So I +ask you to put the money on your cards," replied Dolokhov. "Don't +stint yourself, we'll settle afterwards," he added, turning to Rostov. + +The game continued; a waiter kept handing round champagne. + +All Rostov's cards were beaten and he had eight hundred rubles +scored up against him. He wrote "800 rubles" on a card, but while +the waiter filled his glass he changed his mind and altered it to +his usual stake of twenty rubles. + +"Leave it," said Dolokhov, though he did not seem to be even looking +at Rostov, "you'll win it back all the sooner. I lose to the others +but win from you. Or are you afraid of me?" he asked again. + +Rostov submitted. He let the eight hundred remain and laid down a +seven of hearts with a torn corner, which he had picked up from the +floor. He well remembered that seven afterwards. He laid down the +seven of hearts, on which with a broken bit of chalk he had written +"800 rubles" in clear upright figures; he emptied the glass of warm +champagne that was handed him, smiled at Dolokhov's words, and with +a sinking heart, waiting for a seven to turn up, gazed at Dolokhov's +hands which held the pack. Much depended on Rostov's winning or losing +on that seven of hearts. On the previous Sunday the old count had +given his son two thousand rubles, and though he always disliked +speaking of money difficulties had told Nicholas that this was all +he could let him have till May, and asked him to be more economical +this time. Nicholas had replied that it would be more than enough +for him and that he gave his word of honor not to take anything more +till the spring. Now only twelve hundred rubles was left of that +money, so that this seven of hearts meant for him not only the loss of +sixteen hundred rubles, but the necessity of going back on his word. +With a sinking heart he watched Dolokhov's hands and thought, "Now +then, make haste and let me have this card and I'll take my cap and +drive home to supper with Denisov, Natasha, and Sonya, and will +certainly never touch a card again." At that moment his home life, +jokes with Petya, talks with Sonya, duets with Natasha, piquet with +his father, and even his comfortable bed in the house on the +Povarskaya rose before him with such vividness, clearness, and charm +that it seemed as if it were all a lost and unappreciated bliss, +long past. He could not conceive that a stupid chance, letting the +seven be dealt to the right rather than to the left, might deprive him +of all this happiness, newly appreciated and newly illumined, and +plunge him into the depths of unknown and undefined misery. That could +not be, yet he awaited with a sinking heart the movement of Dolokhov's +hands. Those broad, reddish hands, with hairy wrists visible from +under the shirt cuffs, laid down the pack and took up a glass and a +pipe that were handed him. + +"So you are not afraid to play with me?" repeated Dolokhov, and as +if about to tell a good story he put down the cards, leaned back in +his chair, and began deliberately with a smile: + +"Yes, gentlemen, I've been told there's a rumor going about Moscow +that I'm a sharper, so I advise you to be careful." + +"Come now, deal!" exclaimed Rostov. + +"Oh, those Moscow gossips!" said Dolokhov, and he took up the +cards with a smile. + +"Aah!" Rostov almost screamed lifting both hands to his head. The +seven he needed was lying uppermost, the first card in the pack. He +had lost more than he could pay. + +"Still, don't ruin yourself!" said Dolokhov with a side glance at +Rostov as he continued to deal. + + + + + +CHAPTER XIV + + +An hour and a half later most of the players were but little +interested in their own play. + +The whole interest was concentrated on Rostov. Instead of sixteen +hundred rubles he had a long column of figures scored against him, +which he had reckoned up to ten thousand, but that now, as he +vaguely supposed, must have risen to fifteen thousand. In reality it +already exceeded twenty thousand rubles. Dolokhov was no longer +listening to stories or telling them, but followed every movement of +Rostov's hands and occasionally ran his eyes over the score against +him. He had decided to play until that score reached forty-three +thousand. He had fixed on that number because forty-three was the +sum of his and Sonya's joint ages. Rostov, leaning his head on both +hands, sat at the table which was scrawled over with figures, wet with +spilled wine, and littered with cards. One tormenting impression did +not leave him: that those broad-boned reddish hands with hairy +wrists visible from under the shirt sleeves, those hands which he +loved and hated, held him in their power. + +"Six hundred rubles, ace, a corner, a nine... winning it back's +impossible... Oh, how pleasant it was at home!... The knave, double or +quits... it can't be!... And why is he doing this to me?" Rostov +pondered. Sometimes he staked a large sum, but Dolokhov refused to +accept it and fixed the stake himself. Nicholas submitted to him, +and at one moment prayed to God as he had done on the battlefield at +the bridge over the Enns, and then guessed that the card that came +first to hand from the crumpled heap under the table would save him, +now counted the cords on his coat and took a card with that number and +tried staking the total of his losses on it, then he looked round +for aid from the other players, or peered at the now cold face of +Dolokhov and tried to read what was passing in his mind. + +"He knows of course what this loss means to me. He can't want my +ruin. Wasn't he my friend? Wasn't I fond of him? But it's not his +fault. What's he to do if he has such luck?... And it's not my fault +either," he thought to himself, "I have done nothing wrong. Have I +killed anyone, or insulted or wished harm to anyone? Why such a +terrible misfortune? And when did it begin? Such a little while ago +I came to this table with the thought of winning a hundred rubles to +buy that casket for Mamma's name day and then going home. I was so +happy, so free, so lighthearted! And I did not realize how happy I +was! When did that end and when did this new, terrible state of things +begin? What marked the change? I sat all the time in this same place +at this table, chose and placed cards, and watched those broad-boned +agile hands in the same way. When did it happen and what has happened? +I am well and strong and still the same and in the same place. No, +it can't be! Surely it will all end in nothing!" + +He was flushed and bathed in perspiration, though the room was not +hot. His face was terrible and piteous to see, especially from its +helpless efforts to seem calm. + +The score against him reached the fateful sum of forty-three +thousand. Rostov had just prepared a card, by bending the corner of +which he meant to double the three thousand just put down to his +score, when Dolokhov, slamming down the pack of cards, put it aside +and began rapidly adding up the total of Rostov's debt, breaking the +chalk as he marked the figures in his clear, bold hand. + +"Supper, it's time for supper! And here are the gypsies!" + +Some swarthy men and women were really entering from the cold +outside and saying something in their gypsy accents. Nicholas +understood that it was all over; but he said in an indifferent tone: + +"Well, won't you go on? I had a splendid card all ready," as if it +were the fun of the game which interested him most. + +"It's all up! I'm lost!" thought he. "Now a bullet through my brain- +that's all that's left me!" And at the same time he said in a +cheerful voice: + +"Come now, just this one more little card!" + +"All right!" said Dolokhov, having finished the addition. "All +right! Twenty-one rubles," he said, pointing to the figure +twenty-one by which the total exceeded the round sum of forty-three +thousand; and taking up a pack he prepared to deal. Rostov +submissively unbent the corner of his card and, instead of the six +thousand he had intended, carefully wrote twenty-one. + +"It's all the same to me," he said. "I only want to see whether +you will let me win this ten, or beat it." + +Dolokhov began to deal seriously. Oh, how Rostov detested at that +moment those hands with their short reddish fingers and hairy +wrists, which held him in their power.... The ten fell to him. + +"You owe forty-three thousand, Count," said Dolokhov, and stretching +himself he rose from the table. "One does get tired sitting so +long," he added. + +"Yes, I'm tired too," said Rostov. + +Dolokhov cut him short, as if to remind him that it was not for +him to jest. + +"When am I to receive the money, Count?" + +Rostov, flushing, drew Dolokhov into the next room. + +"I cannot pay it all immediately. Will you take an I.O.U.?" he said. + +"I say, Rostov," said Dolokhov clearly, smiling and looking Nicholas +straight in the eyes, "you know the saying, 'Lucky in love, unlucky at +cards.' Your cousin is in love with you, I know." + +"Oh, it's terrible to feel oneself so in this man's power," +thought Rostov. He knew what a shock he would inflict on his father +and mother by the news of this loss, he knew what a relief it would be +to escape it all, and felt that Dolokhov knew that he could save him +from all this shame and sorrow, but wanted now to play with him as a +cat does with a mouse. + +"Your cousin..." Dolokhov started to say, but Nicholas interrupted +him. + +"My cousin has nothing to do with this and it's not necessary to +mention her!" he exclaimed fiercely. + +"Then when am I to have it?" + +"Tomorrow," replied Rostov and left the room. + + + + + +CHAPTER XV + + +To say "tomorrow" and keep up a dignified tone was not difficult, +but to go home alone, see his sisters, brother, mother, and father, +confess and ask for money he had no right to after giving his word +of honor, was terrible. + +At home, they had not yet gone to bed. The young people, after +returning from the theater, had had supper and were grouped round +the clavichord. As soon as Nicholas entered, he was enfolded in that +poetic atmosphere of love which pervaded the Rostov household that +winter and, now after Dolokhov's proposal and Iogel's ball, seemed +to have grown thicker round Sonya and Natasha as the air does before a +thunderstorm. Sonya and Natasha, in the light-blue dresses they had +worn at the theater, looking pretty and conscious of it, were standing +by the clavichord, happy and smiling. Vera was playing chess with +Shinshin in the drawing room. The old countess, waiting for the return +of her husband and son, sat playing patience with the old +gentlewoman who lived in their house. Denisov, with sparkling eyes and +ruffled hair, sat at the clavichord striking chords with his short +fingers, his legs thrown back and his eyes rolling as he sang, with +his small, husky, but true voice, some verses called "Enchantress," +which he had composed, and to which he was trying to fit music: + + Enchantress, say, to my forsaken lyre + What magic power is this recalls me still? + What spark has set my inmost soul on fire, + What is this bliss that makes my fingers thrill? + +He was singing in passionate tones, gazing with his +sparkling black-agate eyes at the frightened and happy Natasha. + +"Splendid! Excellent!" exclaimed Natasha. "Another verse," she +said, without noticing Nicholas. + +"Everything's still the same with them," thought Nicholas, +glancing into the drawing room, where he saw Vera and his mother +with the old lady. + +"Ah, and here's Nicholas!" cried Natasha, running up to him. + +"Is Papa at home?" he asked. + +"I am so glad you've come!" said Natasha, without answering him. "We +are enjoying ourselves! Vasili Dmitrich is staying a day longer for my +sake! Did you know?" + +"No, Papa is not back yet," said Sonya. + +"Nicholas, have you come? Come here, dear!" called the old +countess from the drawing room. + +Nicholas went to her, kissed her hand, and sitting down silently +at her table began to watch her hands arranging the cards. From the +dancing room, they still heard the laughter and merry voices trying to +persuade Natasha to sing. + +"All wight! All wight!" shouted Denisov. "It's no good making +excuses now! It's your turn to sing the ba'cawolla--I entweat you!" + +The countess glanced at her silent son. + +"What is the matter?" she asked. + +"Oh, nothing," said he, as if weary of being continually asked the +same question. "Will Papa be back soon?" + +"I expect so." + +"Everything's the same with them. They know nothing about it! +Where am I to go?" thought Nicholas, and went again into the dancing +room where the clavichord stood. + +Sonya was sitting at the clavichord, playing the prelude to +Denisov's favorite barcarolle. Natasha was preparing to sing. +Denisov was looking at her with enraptured eyes. + +Nicholas began pacing up and down the room. + +"Why do they want to make her sing? How can she sing? There's +nothing to be happy about!" thought he. + +Sonya struck the first chord of the prelude. + +"My God, I'm a ruined and dishonored man! A bullet through my +brain is the only thing left me--not singing!" his thoughts ran on. +"Go away? But where to? It's one--let them sing!" + +He continued to pace the room, looking gloomily at Denisov and the +girls and avoiding their eyes. + +"Nikolenka, what is the matter?" Sonya's eyes fixed on him seemed to +ask. She noticed at once that something had happened to him. + +Nicholas turned away from her. Natasha too, with her quick instinct, +had instantly noticed her brother's condition. But, though she noticed +it, she was herself in such high spirits at that moment, so far from +sorrow, sadness, or self-reproach, that she purposely deceived herself +as young people often do. "No, I am too happy now to spoil my +enjoyment by sympathy with anyone's sorrow," she felt, and she said to +herself: "No, I must be mistaken, he must be feeling happy, just as +I am." + +"Now, Sonya!" she said, going to the very middle of the room, +where she considered the resonance was best. + +Having lifted her head and let her arms droop lifelessly, as +ballet dancers do, Natasha, rising energetically from her heels to her +toes, stepped to the middle of the room and stood still. + +"Yes, that's me!" she seemed to say, answering the rapt gaze with +which Denisov followed her. + +"And what is she so pleased about?" thought Nicholas, looking at his +sister. "Why isn't she dull and ashamed?" + +Natasha took the first note, her throat swelled, her chest rose, her +eyes became serious. At that moment she was oblivious of her +surroundings, and from her smiling lips flowed sounds which anyone may +produce at the same intervals hold for the same time, but which +leave you cold a thousand times and the thousand and first time thrill +you and make you weep. + +Natasha, that winter, had for the first time begun to sing +seriously, mainly because Denisov so delighted in her singing. She +no longer sang as a child, there was no longer in her singing that +comical, childish, painstaking effect that had been in it before; +but she did not yet sing well, as all the connoisseurs who heard her +said: "It is not trained, but it is a beautiful voice that must be +trained." Only they generally said this some time after she had +finished singing. While that untrained voice, with its incorrect +breathing and labored transitions, was sounding, even the connoisseurs +said nothing, but only delighted in it and wished to hear it again. In +her voice there was a virginal freshness, an unconsciousness of her +own powers, and an as yet untrained velvety softness, which so mingled +with her lack of art in singing that it seemed as if nothing in that +voice could be altered without spoiling it. + +"What is this?" thought Nicholas, listening to her with widely +opened eyes. "What has happened to her? How she is singing today!" And +suddenly the whole world centered for him on anticipation of the +next note, the next phrase, and everything in the world was divided +into three beats: "Oh mio crudele affetto."... One, two, three... one, +two, three... One... "Oh mio crudele affetto."... One, two, three... +One. "Oh, this senseless life of ours!" thought Nicholas. "All this +misery, and money, and Dolokhov, and anger, and honor--it's all +nonsense... but this is real.... Now then, Natasha, now then, dearest! +Now then, darling! How will she take that si? She's taken it! Thank +God!" And without noticing that he was singing, to strengthen the si +he sung a second, a third below the high note. "Ah, God! How fine! Did +I really take it? How fortunate!" he thought. + +Oh, how that chord vibrated, and how moved was something that was +finest in Rostov's soul! And this something was apart from +everything else in the world and above everything in the world. +"What were losses, and Dolokhov, and words of honor?... All +nonsense! One might kill and rob and yet be happy..." + + + + + +CHAPTER XVI + + +It was long since Rostov had felt such enjoyment from music as he +did that day. But no sooner had Natasha finished her barcarolle than +reality again presented itself. He got up without saying a word and +went downstairs to his own room. A quarter of an hour later the old +count came in from his Club, cheerful and contented. Nicholas, hearing +him drive up, went to meet him. + +"Well--had a good time?" said the old count, smiling gaily and +proudly at his son. + +Nicholas tried to say "Yes," but could not: and he nearly burst into +sobs. The count was lighting his pipe and did not notice his son's +condition. + +"Ah, it can't be avoided!" thought Nicholas, for the first and +last time. And suddenly, in the most casual tone, which made him +feel ashamed of himself, he said, as if merely asking his +father to let him have the carriage to drive to town: + +"Papa, I have come on a matter of business. I was nearly forgetting. +I need some money." + +"Dear me!" said his father, who was in a specially good humor. "I +told you it would not be enough. How much?" + +"Very much," said Nicholas flushing, and with a stupid careless +smile, for which he was long unable to forgive himself, "I have lost a +little, I mean a good deal, a great deal--forty three thousand." + +"What! To whom?... Nonsense!" cried the count, suddenly reddening +with an apoplectic flush over neck and nape as old people do. + +"I promised to pay tomorrow," said Nicholas. + +"Well!..." said the old count, spreading out his arms and sinking +helplessly on the sofa. + +"It can't be helped It happens to everyone!" said the son, with a +bold, free, and easy tone, while in his soul he regarded himself as +a worthless scoundrel whose whole life could not atone for his +crime. He longed to kiss his father's hands and kneel to beg his +forgiveness, but said, in a careless and even rude voice, that it +happens to everyone! + +The old count cast down his eyes on hearing his son's words and +began bustlingly searching for something. + +"Yes, yes," he muttered, "it will be difficult, I fear, difficult to +raise... happens to everybody! Yes, who has not done it?" + +And with a furtive glance at his son's face, the count went out of +the room.... Nicholas had been prepared for resistance, but had not at +all expected this. + +"Papa! Pa-pa!" he called after him, sobbing, "forgive me!" And +seizing his father's hand, he pressed it to his lips and burst into +tears. + +While father and son were having their explanation, the mother and +daughter were having one not less important. Natasha came running to +her mother, quite excited. + +"Mamma!... Mamma!... He has made me..." + +"Made what?" + +"Made, made me an offer, Mamma! Mamma!" she exclaimed. + +The countess did not believe her ears. Denisov had proposed. To +whom? To this chit of a girl, Natasha, who not so long ago was playing +with dolls and who was still having lessons. + +"Don't, Natasha! What nonsense!" she said, hoping it was a joke. + +"Nonsense, indeed! I am telling you the fact," said Natasha +indignantly. "I come to ask you what to do, and you call it +'nonsense!'" + +The countess shrugged her shoulders. + +"If it true that Monsieur Denisov has made you a proposal, tell +him he is a fool, that's all!" + +"No, he's not a fool!" replied Natasha indignantly and seriously. + +"Well then, what do you want? You're all in love nowadays. Well, +if you are in love, marry him!" said the countess, with a laugh of +annoyance. "Good luck to you!" + +"No, Mamma, I'm not in love with him, I suppose I'm not in love with +him." + +"Well then, tell him so." + +"Mamma, are you cross? Don't be cross, dear! Is it my fault?" + +"No, but what is it, my dear? Do you want me to go and tell him?" +said the countess smiling. + +"No, I will do it myself, only tell me what to say. It's all very +well for you," said Natasha, with a responsive smile. "You should have +seen how he said it! I know he did not mean to say it, but it came out +accidently." + +"Well, all the same, you must refuse him." + +"No, I mustn't. I am so sorry for him! He's so nice." + +"Well then, accept his offer. It's high time for you to be married," +answered the countess sharply and sarcastically. + +"No, Mamma, but I'm so sorry for him. I don't know how I'm to say +it." + +"And there's nothing for you to say. I shall speak to him myself," +said the countess, indignant that they should have dared to treat this +little Natasha as grown up. + +"No, not on any account! I will tell him myself, and you'll listen +at the door," and Natasha ran across the drawing room to the dancing +hall, where Denisov was sitting on the same chair by the clavichord +with his face in his hands. + +He jumped up at the sound of her light step. + +"Nataly," he said, moving with rapid steps toward her, "decide my +fate. It is in your hands." + +"Vasili Dmitrich, I'm so sorry for you!... No, but you are so +nice... but it won't do...not that... but as a friend, I shall +always love you." + +Denisov bent over her hand and she heard strange sounds she did +not understand. She kissed his rough curly black head. At this +instant, they heard the quick rustle of the countess' dress. She +came up to them. + +"Vasili Dmitrich, I thank you for the honor," she said, with an +embarrassed voice, though it sounded severe to Denisov--"but my +daughter is so young, and I thought that, as my son's friend, you +would have addressed yourself first to me. In that case you would +not have obliged me to give this refusal." + +"Countess..." said Denisov, with downcast eyes and a guilty face. He +tried to say more, but faltered. + +Natasha could not remain calm, seeing him in such a plight. She +began to sob aloud. + +"Countess, I have done w'ong," Denisov went on in an unsteady voice, +"but believe me, I so adore your daughter and all your family that I +would give my life twice over..." He looked at the countess, and +seeing her severe face said: "Well, good-by, Countess," and kissing +her hand, he left the room with quick resolute strides, without +looking at Natasha. + + +Next day Rostov saw Denisov off. He not wish to stay another day +in Moscow. All Denisov's Moscow friends gave him a farewell +entertainment at the gypsies', with the result that he had no +recollection of how he was put in the sleigh or of the first three +stages of his journey. + +After Denisov's departure, Rostov spent another fortnight in Moscow, +without going out of the house, waiting for the money his father could +not at once raise, and he spent most of his time in the girls' room. + +Sonya was more tender and devoted to him than ever. It was as if she +wanted to show him that his losses were an achievement that made her +love him all the more, but Nicholas now considered himself unworthy of +her. + +He filled the girls' albums with verses and music, and having at +last sent Dolokhov the whole forty-three thousand rubles and +received his receipt, he left at the end of November, without taking +leave of any of his acquaintances, to overtake his regiment which +was already in Poland. + + + + + +BOOK FIVE: 1806 --07 + + + + + +CHAPTER I + + +After his interview with his wife Pierre left for Petersburg. At the +Torzhok post station, either there were no horses or the postmaster +would not supply them. Pierre was obliged to wait. Without undressing, +he lay down on the leather sofa in front of a round table, put his big +feet in their overboots on the table, and began to reflect. + +"Will you have the portmanteaus brought in? And a bed got ready, and +tea?" asked his valet. + +Pierre gave no answer, for he neither heard nor saw anything. He had +begun to think of the last station and was still pondering on the same +question--one so important that he took no notice of what went on +around him. Not only was he indifferent as to whether he got to +Petersburg earlier or later, or whether he secured accommodation at +this station, but compared to the thoughts that now occupied him it +was a matter of indifference whether he remained there for a few hours +or for the rest of his life. + +The postmaster, his wife, the valet, and a peasant woman selling +Torzhok embroidery came into the room offering their services. Without +changing his careless attitude, Pierre looked at them over his +spectacles unable to understand what they wanted or how they could +go on living without having solved the problems that so absorbed +him. He had been engrossed by the same thoughts ever since the day +he returned from Sokolniki after the duel and had spent that first +agonizing, sleepless night. But now, in the solitude of the journey, +they seized him with special force. No matter what he thought about, +he always returned to these same questions which he could not solve +and yet could not cease to ask himself. It was as if the thread of the +chief screw which held his life together were stripped, so that the +screw could not get in or out, but went on turning uselessly in the +same place. + +The postmaster came in and began obsequiously to beg his +excellency to wait only two hours, when, come what might, he would let +his excellency have the courier horses. It was plain that he was lying +and only wanted to get more money from the traveler. + +"Is this good or bad?" Pierre asked himself. "It is good for me, bad +for another traveler, and for himself it's unavoidable, because he +needs money for food; the man said an officer had once given him a +thrashing for letting a private traveler have the courier horses. +But the officer thrashed him because he had to get on as quickly as +possible. And I," continued Pierre, "shot Dolokhov because I +considered myself injured, and Louis XVI was executed because they +considered him a criminal, and a year later they executed those who +executed him--also for some reason. What is bad? What is good? What +should one love and what hate? What does one live for? And what am +I? What is life, and what is death? What power governs all?" + +There was no answer to any of these questions, except one, and +that not a logical answer and not at all a reply to them. The answer +was: "You'll die and all will end. You'll die and know all, or cease +asking." But dying was also dreadful. + +The Torzhok peddler woman, in a whining voice, went on offering +her wares, especially a pair of goatskin slippers. "I have hundreds of +rubles I don't know what to do with, and she stands in her tattered +cloak looking timidly at me," he thought. "And what does she want +the money for? As if that money could add a hair's breadth to +happiness or peace of mind. Can anything in the world make her or me +less a prey to evil and death?--death which ends all and must come +today or tomorrow--at any rate, in an instant as compared with +eternity." And again he twisted the screw with the stripped thread, +and again it turned uselessly in the same place. + +His servant handed him a half-cut novel, in the form of letters, +by Madame de Souza. He began reading about the sufferings and virtuous +struggles of a certain Emilie de Mansfeld. "And why did she resist her +seducer when she loved him?" he thought. "God could not have put +into her heart an impulse that was against His will. My wife--as she +once was--did not struggle, and perhaps she was right. Nothing has +been found out, nothing discovered," Pierre again said to himself. +"All we can know is that we know nothing. And that's the height of +human wisdom." + +Everything within and around him seemed confused, senseless, and +repellent. Yet in this very repugnance to all his circumstances Pierre +found a kind of tantalizing satisfaction. + +"I make bold to ask your excellency to move a little for this +gentleman," said the postmaster, entering the room followed by another +traveler, also detained for lack of horses. + +The newcomer was a short, large-boned, yellow-faced, wrinkled old +man, with gray bushy eyebrows overhanging bright eyes of an indefinite +grayish color. + +Pierre took his feet off the table, stood up, and lay down on a +bed that had been got ready for him, glancing now and then at the +newcomer, who, with a gloomy and tired face, was wearily taking off +his wraps with the aid of his servant, and not looking at Pierre. With +a pair of felt boots on his thin bony legs, and keeping on a worn, +nankeen-covered, sheepskin coat, the traveler sat down on the sofa, +leaned back his big head with its broad temples and close-cropped +hair, and looked at Bezukhov. The stern, shrewd, and penetrating +expression of that look struck Pierre. He felt a wish to speak to +the stranger, but by the time he had made up his mind to ask him a +question about the roads, the traveler had closed his eyes. His +shriveled old hands were folded and on the finger of one of them +Pierre noticed a large cast iron ring with a seal representing a +death's head. The stranger sat without stirring, either resting or, as +it seemed to Pierre, sunk in profound and calm meditation. His servant +was also a yellow, wrinkled old man, without beard or mustache, +evidently not because he was shaven but because they had never +grown. This active old servant was unpacking the traveler's canteen +and preparing tea. He brought in a boiling samovar. When everything +was ready, the stranger opened his eyes, moved to the table, filled +a tumbler with tea for himself and one for the beardless old man to +whom he passed it. Pierre began to feel a sense of uneasiness, and the +need, even the inevitability, of entering into conversation with +this stranger. + +The servant brought back his tumbler turned upside down,* with an +unfinished bit of nibbled sugar, and asked if anything more would be +wanted. + + +*To indicate he did not want more tea. + + +"No. Give me the book," said the stranger. + +The servant handed him a book which Pierre took to be a devotional +work, and the traveler became absorbed in it. Pierre looked at him. +All at once the stranger closed the book, putting in a marker, and +again, leaning with his arms on the back of the sofa, sat in his +former position with his eyes shut. Pierre looked at him and had not +time to turn away when the old man, opening his eyes, fixed his steady +and severe gaze straight on Pierre's face. + +Pierre felt confused and wished to avoid that look, but the bright +old eyes attracted him irresistibly. + + + + + +CHAPTER II + + +"I have the pleasure of addressing Count Bezukhov, if I am not +mistaken," said the stranger in a deliberate and loud voice. + +Pierre looked silently and inquiringly at him over his spectacles. + +"I have heard of you, my dear sir," continued the stranger, "and +of your misfortune." He seemed to emphasize the last word, as if to +say--"Yes, misfortune! Call it what you please, I know that what +happened to you in Moscow was a misfortune."--"I regret it very +much, my dear sir." + +Pierre flushed and, hurriedly putting his legs down from the bed, +bent forward toward the old man with a forced and timid smile. + +"I have not referred to this out of curiosity, my dear sir, but +for greater reasons." + +He paused, his gaze still on Pierre, and moved aside on the sofa +by way of inviting the other to take a seat beside him. Pierre felt +reluctant to enter into conversation with this old man, but, +submitting to him involuntarily, came up and sat down beside him. + +"You are unhappy, my dear sir," the stranger continued. "You are +young and I am old. I should like to help you as far as lies in my +power." + +"Oh, yes!" said Pierre, with a forced smile. "I am very grateful +to you. Where are you traveling from?" + +The stranger's face was not genial, it was even cold and severe, but +in spite of this, both the face and words of his new acquaintance were +irresistibly attractive to Pierre. + +"But if for reason you don't feel inclined to talk to me," said +the old man, "say so, my dear sir." And he suddenly smiled, in an +unexpected and tenderly paternal way. + +"Oh no, not at all! On the contrary, I am very glad to make your +acquaintance," said Pierre. And again, glancing at the stranger's +hands, he looked more closely at the ring, with its skull--a Masonic +sign. + +"Allow me to ask," he said, "are you a Mason?" + +"Yes, I belong to the Brotherhood of the Freemasons," said the +stranger, looking deeper and deeper into Pierre's eyes. "And in +their name and my own I hold out a brotherly hand to you." + +"I am afraid," said Pierre, smiling, and wavering between the +confidence the personality of the Freemason inspired in him and his +own habit of ridiculing the Masonic beliefs--"I am afraid I am very +far from understanding--how am I to put it?--I am afraid my way of +looking at the world is so opposed to yours that we shall not +understand one another." + +"I know your outlook," said the Mason, "and the view of life you +mention, and which you think is the result of your own mental efforts, +is the one held by the majority of people, and is the invariable fruit +of pride, indolence, and ignorance. Forgive me, my dear sir, but if +I had not known it I should not have addressed you. Your view of +life is a regrettable delusion." + +"Just as I may suppose you to be deluded," said Pierre, with a faint +smile. + +"I should never dare to say that I know the truth," said the +Mason, whose words struck Pierre more and more by their precision +and firmness. "No one can attain to truth by himself. Only by laying +stone on stone with the cooperation of all, by the millions of +generations from our forefather Adam to our own times, is that +temple reared which is to be a worthy dwelling place of the Great +God," he added, and closed his eyes. + +"I ought to tell you that I do not believe... do not believe in God," +said Pierre, regretfully and with an effort, feeling it essential to +speak the whole truth. + +The Mason looked intently at Pierre and smiled as a rich man with +millions in hand might smile at a poor fellow who told him that he, +poor man, had not the five rubles that would make him happy. + +"Yes, you do not know Him, my dear sir," said the Mason. "You cannot +know Him. You do not know Him and that is why you are unhappy." + +"Yes, yes, I am unhappy," assented Pierre. "But what am I to do?" + +"You know Him not, my dear sir, and so you are very unhappy. You +do not know Him, but He is here, He is in me, He is in my words, He +is in thee, and even in those blasphemous words thou hast just +uttered!" pronounced the Mason in a stern and tremulous voice. + +He paused and sighed, evidently trying to calm himself. + +"If He were not," he said quietly, "you and I would not be +speaking of Him, my dear sir. Of what, of whom, are we speaking? +Whom hast thou denied?" he suddenly asked with exulting austerity +and authority in his voice. "Who invented Him, if He did not exist? +Whence came thy conception of the existence of such an +incomprehensible Being? didst thou, and why did the whole world, +conceive the idea of the existence of such an incomprehensible +Being, a Being all-powerful, eternal, and infinite in all His +attributes?..." + +He stopped and remained silent for a long time. + +Pierre could not and did not wish to break this silence. + +"He exists, but to understand Him is hard," the Mason began again, +looking not at Pierre but straight before him, and turning the +leaves of his book with his old hands which from excitement he could +not keep still. "If it were a man whose existence thou didst doubt I +could bring him to thee, could take him by the hand and show him to +thee. But how can I, an insignificant mortal, show His omnipotence, +His infinity, and all His mercy to one who is blind, or who shuts +his eyes that he may not see or understand Him and may not see or +understand his own vileness and sinfulness?" He paused again. "Who art +thou? Thou dreamest that thou art wise because thou couldst utter +those blasphemous words," he went on, with a somber and scornful +smile. "And thou art more foolish and unreasonable than a little +child, who, playing with the parts of a skillfully made watch, dares +to say that, as he does not understand its use, he does not believe in +the master who made it. To know Him is hard.... For ages, from our +forefather Adam to our own day, we labor to attain that knowledge +and are still infinitely far from our aim; but in our lack of +understanding we see only our weakness and His greatness...." + +Pierre listened with swelling heart, gazing into the Mason's face +with shining eyes, not interrupting or questioning him, but +believing with his whole soul what the stranger said. Whether he +accepted the wise reasoning contained in the Mason's words, or +believed as a child believes, in the speaker's tone of conviction +and earnestness, or the tremor of the speaker's voice--which sometimes +almost broke--or those brilliant aged eyes grown old in this +conviction, or the calm firmness and certainty of his vocation, +which radiated from his whole being (and which struck Pierre +especially by contrast with his own dejection and hopelessness)--at +any rate, Pierre longed with his whole soul to believe and he did +believe, and felt a joyful sense of comfort, regeneration, and +return to life. + +"He is not to be apprehended by reason, but by life," said the +Mason. + +"I do not understand," said Pierre, feeling with dismay doubts +reawakening. He was afraid of any want of clearness, any weakness, +in the Mason's arguments; he dreaded not to be able to believe in him. +"I don't understand," he said, "how it is that the mind of man +cannot attain the knowledge of which you speak." + +The Mason smiled with his gentle fatherly smile. + +"The highest wisdom and truth are like the purest liquid we may wish +to imbibe," he said. "Can I receive that pure liquid into an impure +vessel and judge of its purity? Only by the inner purification of +myself can I retain in some degree of purity the liquid I receive." + +"Yes, yes, that is so," said Pierre joyfully. + +"The highest wisdom is not founded on reason alone, not on those +worldly sciences of physics, history, chemistry, and the like, into +which intellectual knowledge is divided. The highest wisdom is one. +The highest wisdom has but one science--the science of the whole- +the science explaining the whole creation and man's place in it. To +receive that science it is necessary to purify and renew one's inner +self, and so before one can know, it is necessary to believe and to +perfect one's self. And to attain this end, we have the light called +conscience that God has implanted in our souls." + +"Yes, yes," assented Pierre. + +"Look then at thy inner self with the eyes of the spirit, and ask +thyself whether thou art content with thyself. What hast thou attained +relying on reason only? What art thou? You are young, you are rich, +you are clever, you are well educated. And what have you done with all +these good gifts? Are you content with yourself and with your life?" + +"No, I hate my life," Pierre muttered, wincing. + +"Thou hatest it. Then change it, purify thyself; and as thou art +purified, thou wilt gain wisdom. Look at your life, my dear sir. How +have you spent it? In riotous orgies and debauchery, receiving +everything from society and giving nothing in return. You have +become the possessor of wealth. How have you used it? What have you +done for your neighbor? Have you ever thought of your tens of +thousands of slaves? Have you helped them physically and morally? +No! You have profited by their toil to lead a profligate life. That is +what you have done. Have you chosen a post in which you might be of +service to your neighbor? No! You have spent your life in idleness. +Then you married, my dear sir--took on yourself responsibility for the +guidance of a young woman; and what have you done? You have not helped +her to find the way of truth, my dear sir, but have thrust her into an +abyss of deceit and misery. A man offended you and you shot him, and +you say you do not know God and hate your life. There is nothing +strange in that, my dear sir!" + +After these words, the Mason, as if tired by his long discourse, +again leaned his arms on the back of the sofa and closed his eyes. +Pierre looked at that aged, stern, motionless, almost lifeless face +and moved his lips without uttering a sound. He wished to say, "Yes, a +vile, idle, vicious life!" but dared not break the silence. + +The Mason cleared his throat huskily, as old men do, and called +his servant. + +"How about the horses?" he asked, without looking at Pierre. + +"The exchange horses have just come," answered the servant. "Will +you not rest here?" + +"No, tell them to harness." + +"Can he really be going away leaving me alone without having told me +all, and without promising to help me?" thought Pierre, rising with +downcast head; and he began to pace the room, glancing occasionally at +the Mason. "Yes, I never thought of it, but I have led a +contemptible and profligate life, though I did not like it and did not +want to," thought Pierre. "But this man knows the truth and, if he +wished to, could disclose it to me." + +Pierre wished to say this to the Mason, but did not dare to. The +traveler, having packed his things with his practiced hands, began +fastening his coat. When he had finished, he turned to Bezukhov, and +said in a tone of indifferent politeness: + +"Where are you going to now, my dear sir?" + +"I?... I'm going to Petersburg," answered Pierre, in a childlike, +hesitating voice. "I thank you. I agree with all you have said. But do +not suppose me to be so bad. With my whole soul I wish to be what +you would have me be, but I have never had help from anyone.... But it +is I, above all, who am to blame for everything. Help me, teach me, +and perhaps I may..." + +Pierre could not go on. He gulped and turned away. + +The Mason remained silent for a long time, evidently considering. + +"Help comes from God alone," he said, "but such measure of help as +our Order can bestow it will render you, my dear sir. You are going to +Petersburg. Hand this to Count Willarski" (he took out his notebook +and wrote a few words on a large sheet of paper folded in four). +"Allow me to give you a piece of advice. When you reach the capital, +first of all devote some time to solitude and self-examination and +do not resume your former way of life. And now I wish you a good +journey, my dear sir," he added, seeing that his servant had +entered... "and success." + +The traveler was Joseph Alexeevich Bazdeev, as Pierre saw from the +postmaster's book. Bazdeev had been one of the best-known Freemasons +and Martinists, even in Novikov's time. For a long while after he +had gone, Pierre did not go to bed or order horses but paced up and +down the room, pondering over his vicious past, and with a rapturous +sense of beginning anew pictured to himself the blissful, +irreproachable, virtuous future that seemed to him so easy. It +seemed to him that he had been vicious only because he had somehow +forgotten how good it is to be virtuous. Not a trace of his former +doubts remained in his soul. He firmly believed in the possibility +of the brotherhood of men united in the aim of supporting one +another in the path of virtue, and that is how Freemasonry presented +itself to him. + + + + + +CHAPTER III + + +On reaching Petersburg Pierre did not let anyone know of his +arrival, he went nowhere and spent whole days in reading Thomas a +Kempis, whose book had been sent him by someone unknown. One thing +he continually realized as he read that book: the joy, hitherto +unknown to him, of believing in the possibility of attaining +perfection, and in the possibility of active brotherly love among men, +which Joseph Alexeevich had revealed to him. A week after his arrival, +the young Polish count, Willarski, whom Pierre had known slightly in +Petersburg society, came into his room one evening in the official and +ceremonious manner in which Dolokhov's second had called on him, +and, having closed the door behind him and satisfied himself that +there was nobody else in the room, addressed Pierre. + +"I have come to you with a message and an offer, Count," he said +without sitting down. "A person of very high standing in our +Brotherhood has made application for you to be received into our Order +before the usual term and has proposed to me to be your sponsor. I +consider it a sacred duty to fulfill that person's wishes. Do you wish +to enter the Brotherhood of Freemasons under my sponsorship?" + + The cold, austere tone of this man, whom he had almost always +before met at balls, amiably smiling in the society of the most +brilliant women, surprised Pierre. + +"Yes, I do wish it," said he. + +Willarski bowed his head. + +"One more question, Count," he said, "which beg you to answer in all +sincerity--not as a future Mason but as an honest man: have you +renounced your former convictions--do you believe in God?" + +Pierre considered. + +"Yes... yes, I believe in God," he said. + +"In that case..." began Willarski, but Pierre interrupted him. + +"Yes, I do believe in God," he repeated. + +"In that case we can go," said Willarski. "My carriage is at your +service." + +Willarski was silent throughout the drive. To Pierre's inquiries +as to what he must do and how he should answer, Willarski only replied +that brothers more worthy than he would test him and that Pierre had +only to tell the truth. + +Having entered the courtyard of a large house where the Lodge had +its headquarters, and having ascended a dark staircase, they entered a +small well-lit anteroom where they took off their cloaks without the +aid of a servant. From there they passed into another room. A man in +strange attire appeared at the door. Willarski, stepping toward him, +said something to him in French in an undertone and then went up to +a small wardrobe in which Pierre noticed garments such as he had never +seen before. Having taken a kerchief from the cupboard, Willarski +bound Pierre's eyes with it and tied it in a knot behind, catching +some hairs painfully in the knot. Then he drew his face down, kissed +him, and taking him by the hand led him forward. The hairs tied in the +knot hurt Pierre and there were lines of pain on his face and a +shamefaced smile. His huge figure, with arms hanging down and with a +puckered, though smiling face, moved after Willarski with uncertain, +timid steps. + +Having led him about ten paces, Willarski stopped. + +"Whatever happens to you," he said, "you must bear it all manfully +if you have firmly resolved to join our Brotherhood." (Pierre nodded +affirmatively.) "When you hear a knock at the door, you will uncover +your eyes," added Willarski. "I wish you courage and success," and, +pressing Pierre's hand, he went out. + +Left alone, Pierre went on smiling in the same way. Once or twice he +shrugged his and raised his hand to the kerchief, as if wishing to +take it off, but let it drop again. The five minutes spent with his +eyes bandaged seemed to him an hour. His arms felt numb, his legs +almost gave way, it seemed to him that he was tired out. He +experienced a variety of most complex sensations. He felt afraid of +what would happen to him and still more afraid of showing his fear. He +felt curious to know what was going to happen and what would be +revealed to him; but most of all, he felt joyful that the moment had +come when he would at last start on that path of regeneration and on +the actively virtuous life of which he had been dreaming since he +met Joseph Alexeevich. Loud knocks were heard at the door. Pierre took +the bandage off his eyes and glanced around him. The room was in black +darkness, only a small lamp was burning inside something white. Pierre +went nearer and saw that the lamp stood on a black table on which +lay an open book. The book was the Gospel, and the white thing with +the lamp inside was a human skull with its cavities and teeth. After +reading the first words of the Gospel: "In the beginning was the +Word and the Word was with God," Pierre went round the table and saw a +large open box filled with something. It was a coffin with bones +inside. He was not at all surprised by what he saw. Hoping to enter on +an entirely new life quite unlike the old one, he expected +everything to be unusual, even more unusual than what he was seeing. A +skull, a coffin, the Gospel--it seemed to him that he had expected all +this and even more. Trying to stimulate his emotions he looked around. +"God, death, love, the brotherhood of man," he kept saying to himself, +associating these words with vague yet joyful ideas. The door opened +and someone came in. + +By the dim light, to which Pierre had already become accustomed, +he saw rather short man. Having evidently come from the light into the +darkness, the man paused, then moved with cautious steps toward the +table and placed on it his small leather-gloved hands. + +This short man had on a white leather apron which covered his +chest and part of his legs; he had on a kind of necklace above which +rose a high white ruffle, outlining his rather long face which was lit +up from below. + +"For what have you come hither?" asked the newcomer, turning in +Pierre's direction at a slight rustle made by the latter. "Why have +you, who do not believe in the truth of the light and who have not +seen the light, come here? What do you seek from us? Wisdom, virtue, +enlightenment?" + +At the moment the door opened and the stranger came in, Pierre +felt a sense of awe and veneration such as he had experienced in his +boyhood at confession; he felt himself in the presence of one socially +a complete stranger, yet nearer to him through the brotherhood of man. +With bated breath and beating heart he moved toward the Rhetor (by +which name the brother who prepared a seeker for entrance into the +Brotherhood was known). Drawing nearer, he recognized in the Rhetor +a man he knew, Smolyaninov, and it mortified him to think that the +newcomer was an acquaintance--he wished him simply a brother and a +virtuous instructor. For a long time he could not utter a word, so +that the Rhetor had to repeat his question. + +"Yes... I... I... desire regeneration," Pierre uttered with +difficulty. + +"Very well," said Smolyaninov, and went on at once: "Have you any +idea of the means by which our holy Order will help you to reach +your aim?" said he quietly and quickly. + +"I... hope... for guidance... help... in regeneration," said Pierre, +with a trembling voice and some difficulty in utterance due to his +excitement and to being unaccustomed to speak of abstract matters in +Russian. + +"What is your conception of Freemasonry?" + +"I imagine that Freemasonry is the fraternity and equality of men +who have virtuous aims," said Pierre, feeling ashamed of the +inadequacy of his words for the solemnity of the moment, as he +spoke. "I imagine..." + +"Good!" said the Rhetor quickly, apparently satisfied with this +answer. "Have you sought for means of attaining your aim in religion?" + +"No, I considered it erroneous and did not follow it," said +Pierre, so softly that the Rhetor did not hear him and asked him +what he was saying. "I have been an atheist," answered Pierre. + +"You are seeking for truth in order to follow its laws in your life, +therefore you seek wisdom and virtue. Is that not so?" said the +Rhetor, after a moment's pause. + +"Yes, yes," assented Pierre. + +The Rhetor cleared his throat, crossed his gloved hands on his +breast, and began to speak. + +"Now I must disclose to you the chief aim of our Order," he said, +"and if this aim coincides with yours, you may enter our Brotherhood +with profit. The first and chief object of our Order, the foundation +on which it rests and which no human power can destroy, is the +preservation and handing on to posterity of a certain important +mystery... which has come down to us from the remotest ages, even from +the first man--a mystery on which perhaps the fate of mankind depends. +But since this mystery is of such a nature that nobody can know or use +it unless he be prepared by long and diligent self-purification, not +everyone can hope to attain it quickly. Hence we have a secondary aim, +that of preparing our members as much as possible to reform their +hearts, to purify and enlighten their minds, by means handed on to +us by tradition from those who have striven to attain this mystery, +and thereby to render them capable of receiving it. + +"By purifying and regenerating our members we try, thirdly, to +improve the whole human race, offering it in our members an example of +piety and virtue, and thereby try with all our might to combat the +evil which sways the world. Think this over and I will come to you +again." + +"To combat the evil which sways the world..." Pierre repeated, and a +mental image of his future activity in this direction rose in his +mind. He imagined men such as he had himself been a fortnight ago, and +he addressed an edifying exhortation to them. He imagined to himself +vicious and unfortunate people whom he would assist by word and +deed, imagined oppressors whose victims he would rescue. Of the +three objects mentioned by the Rhetor, this last, that of improving +mankind, especially appealed to Pierre. The important mystery +mentioned by the Rhetor, though it aroused his curiosity, did not seem +to him essential, and the second aim, that of purifying and +regenerating himself, did not much interest him because at that moment +he felt with delight that he was already perfectly cured of his former +faults and was ready for all that was good. + +Half an hour later, the Rhetor returned to inform the seeker of +the seven virtues, corresponding to the seven steps of Solomon's +temple, which every Freemason should cultivate in himself. These +virtues were: 1. Discretion, the keeping of the secrets of the Order. + 2. Obedience to those of higher ranks in the Order. 3. Morality. 4. +Love of mankind. 5. Courage. 6. Generosity. 7. The love of death. + +"In the seventh place, try, by the frequent thought of death," the +Rhetor said, "to bring yourself to regard it not as a dreaded foe, but +as a friend that frees the soul grown weary in the labors of virtue +from this distressful life, and leads it to its place of recompense +and peace." + +"Yes, that must be so," thought Pierre, when after these words the +Rhetor went away, leaving him to solitary meditation. "It must be +so, but I am still so weak that I love my life, the meaning of which +is only now gradually opening before me." But five of the other +virtues which Pierre recalled, counting them on his fingers, he felt +already in his soul: courage, generosity, morality, love of mankind, +and especially obedience--which did not even seem to him a virtue, but +a joy. (He now felt so glad to be free from his own lawlessness and to +submit his will to those who knew the indubitable truth.) He forgot +what the seventh virtue was and could not recall it. + +The third time the Rhetor came back more quickly and asked Pierre +whether he was still firm in his intention and determined to submit to +all that would be required of him. + +"I am ready for everything," said Pierre. + +"I must also inform you," said the Rhetor, "that our Order +delivers its teaching not in words only but also by other means, which +may perhaps have a stronger effect on the sincere seeker after +wisdom and virtue than mere words. This chamber with what you see +therein should already have suggested to your heart, if it is sincere, +more than words could do. You will perhaps also see in your further +initiation a like method of enlightenment. Our Order imitates the +ancient societies that explained their teaching by hieroglyphics. A +hieroglyph," said the Rhetor, "is an emblem of something not +cognizable by the senses but which possesses qualities resembling +those of the symbol." + +Pierre knew very well what a hieroglyph was, but dared not speak. He +listened to the Rhetor in silence, feeling from all he said that his +ordeal was about to begin. + +"If you are resolved, I must begin your initiation," said the Rhetor +coming closer to Pierre. "In token of generosity I ask you to give +me all your valuables." + +"But I have nothing here," replied Pierre, supposing that he was +asked to give up all he possessed. + +"What you have with you: watch, money, rings...." + +Pierre quickly took out his purse and watch, but could not manage +for some time to get the wedding ring off his fat finger. When that +had been done, the Rhetor said: + +"In token of obedience, I ask you to undress." + +Pierre took off his coat, waistcoat, and left boot according to +the Rhetor's instructions. The Mason drew the shirt back from Pierre's +left breast, and stooping down pulled up the left leg of his +trousers to above the knee. Pierre hurriedly began taking off his +right boot also and was going to tuck up the other trouser leg to save +this stranger the trouble, but the Mason told him that was not +necessary and gave him a slipper for his left foot. With a childlike +smile of embarrassment, doubt, and self-derision, which appeared on +his face against his will, Pierre stood with his arms hanging down and +legs apart, before his brother Rhetor, and awaited his further +commands. + +"And now, in token of candor, I ask you to reveal to me your chief +passion," said the latter. + +"My passion! I have had so many," replied Pierre. + +"That passion which more than all others caused you to waver on +the path of virtue," said the Mason. + +Pierre paused, seeking a reply. + +"Wine? Gluttony? Idleness? Laziness? Irritability? Anger? Women?" He +went over his vices in his mind, not knowing to which of them to +give the pre-eminence. + +"Women," he said in a low, scarcely audible voice. + +The Mason did not move and for a long time said nothing after this +answer. At last he moved up to Pierre and, taking the kerchief that +lay on the table, again bound his eyes. + +"For the last time I say to you--turn all your attention upon +yourself, put a bridle on your senses, and seek blessedness, not in +passion but in your own heart. The source of blessedness is not +without us but within...." + +Pierre had already long been feeling in himself that refreshing +source of blessedness which now flooded his heart with glad emotion. + + + + + +CHAPTER IV + + +Soon after this there came into the dark chamber to fetch Pierre, +not the Rhetor but Pierre's sponsor, Willarski, whom he recognized +by his voice. To fresh questions as to the firmness of his +resolution Pierre replied: "Yes, yes, I agree," and with a beaming, +childlike smile, his fat chest uncovered, stepping unevenly and +timidly in one slippered and one booted foot, he advanced, while +Willarski held a sword to his bare chest. He was conducted from that +room along passages that turned backwards and forwards and was at last +brought to the doors of the Lodge. Willarski coughed, he was +answered by the Masonic knock with mallets, the doors opened before +them. A bass voice (Pierre was still blindfold) questioned him as to +who he was, when and where he was born, and so on. Then he was again +led somewhere still blindfold, and as they went along he was told +allegories of the toils of his pilgrimage, of holy friendship, of +the Eternal Architect of the universe, and of the courage with which +he should endure toils and dangers. During these wanderings, Pierre +noticed that he was spoken of now as the "Seeker," now as the +"Sufferer," and now as the "Postulant," to the accompaniment of +various knockings with mallets and swords. As he was being led up to +some object he noticed a hesitation and uncertainty among his +conductors. He heard those around him disputing in whispers and one of +them insisting that he should be led along a certain carpet. After +that they took his right hand, placed it on something, and told him to +hold a pair of compasses to his left breast with the other hand and to +repeat after someone who read aloud an oath of fidelity to the laws of +the Order. The candles were then extinguished and some spirit lighted, +as Pierre knew by the smell, and he was told that he would now see the +lesser light. The bandage was taken off his eyes and, by the faint +light of the burning spirit, Pierre, as in a dream, saw several men +standing before him, wearing aprons like the Rhetor's and holding +swords in their hands pointed at his breast. Among them stood a man +whose white shirt was stained with blood. On seeing this, Pierre moved +forward with his breast toward the swords, meaning them to pierce +it. But the swords were drawn back from him and he was at once +blindfolded again. + +"Now thou hast seen the lesser light," uttered a voice. Then the +candles were relit and he was told that he would see the full light; +the bandage was again removed and more than ten voices said +together: "Sic transit gloria mundi." + +Pierre gradually began to recover himself and looked about at the +room and at the people in it. Round a long table covered with black +sat some twelve men in garments like those he had already seen. Some +of them Pierre had met in Petersburg society. In the President's chair +sat a young man he did not know, with a peculiar cross hanging from +his neck. On his right sat the Italian abbe whom Pierre had met at +Anna Pavlovna's two years before. There were also present a very +distinguished dignitary and a Swiss who had formerly been tutor at the +Kuragins'. All maintained a solemn silence, listening to the words +of the President, who held a mallet in his hand. Let into the wall was +a star-shaped light. At one side of the table was a small carpet +with various figures worked upon it, at the other was something +resembling an altar on which lay a Testament and a skull. Round it +stood seven large candlesticks like those used in churches. Two of the +brothers led Pierre up to the altar, placed his feet at right +angles, and bade him lie down, saying that he must prostrate himself +at the Gates of the Temple. + +"He must first receive the trowel," whispered one of the brothers. + +"Oh, hush, please!" said another. + +Pierre, perplexed, looked round with his shortsighted eyes without +obeying, and suddenly doubts arose in his mind. "Where am I? What am I +doing? Aren't they laughing at me? Shan't I be ashamed to remember +this?" But these doubts only lasted a moment. Pierre glanced at the +serious faces of those around, remembered all he had already gone +through, and realized that he could not stop halfway. He was aghast at +his hesitation and, trying to arouse his former devotional feeling, +prostrated himself before the Gates of the Temple. And really, the +feeling of devotion returned to him even more strongly than before. +When he had lain there some time, he was told to get up, and a white +leather apron, such as the others wore, was put on him: he was given a +trowel and three pairs of gloves, and then the Grand Master +addressed him. He told him that he should try to do nothing to stain +the whiteness of that apron, which symbolized strength and purity; +then of the unexplained trowel, he told him to toil with it to cleanse +his own heart from vice, and indulgently to smooth with it the heart +of his neighbor. As to the first pair of gloves, a man's, he said that +Pierre could not know their meaning but must keep them. The second +pair of man's gloves he was to wear at the meetings, and finally of +the third, a pair of women's gloves, he said: "Dear brother, these +woman's gloves are intended for you too. Give them to the woman whom +you shall honor most of all. This gift will be a pledge of your purity +of heart to her whom you select to be your worthy helpmeet in +Masonry." And after a pause, he added: "But beware, dear brother, that +these gloves do not deck hands that are unclean." While the Grand +Master said these last words it seemed to Pierre that he grew +embarrassed. Pierre himself grew still more confused, blushed like a +child till tears came to his eyes, began looking about him uneasily, +and an awkward pause followed. + +This silence was broken by one of the brethren, who led Pierre up to +the rug and began reading to him from a manuscript book an explanation +of all the figures on it: the sun, the moon, a hammer, a plumb line, a +trowel, a rough stone and a squared stone, a pillar, three windows, +and so on. Then a place was assigned to Pierre, he was shown the signs +of the Lodge, told the password, and at last was permitted to sit +down. The Grand Master began reading the statutes. They were very +long, and Pierre, from joy, agitation, and embarrassment, was not in a +state to understand what was being read. He managed to follow only the +last words of the statutes and these remained in his mind. + +"In our temples we recognize no other distinctions," read the +Grand Master, "but those between virtue and vice. Beware of making any +distinctions which may infringe equality. Fly to a brother's aid +whoever he may be, exhort him who goeth astray, raise him that +falleth, never bear malice or enmity toward thy brother. Be kindly and +courteous. Kindle in all hearts the flame of virtue. Share thy +happiness with thy neighbor, and may envy never dim the purity of that +bliss. Forgive thy enemy, do not avenge thyself except by doing him +good. Thus fulfilling the highest law thou shalt regain traces of +the ancient dignity which thou hast lost." + +He finished and, getting up, embraced and kissed Pierre, who, with +tears of joy in his eyes, looked round him, not knowing how to +answer the congratulations and greetings from acquaintances that met +him on all sides. He acknowledged no acquaintances but saw in all +these men only brothers, and burned with impatience to set to work +with them. + +The Grand Master rapped with his mallet. All the Masons sat down +in their places, and one of them read an exhortation on the +necessity of humility. + +The Grand Master proposed that the last duty should be performed, +and the distinguished dignitary who bore the title of "Collector of +Alms" went round to all the brothers. Pierre would have liked to +subscribe all he had, but fearing that it might look like pride +subscribed the same amount as the others. + +The meeting was at an end, and on reaching home Pierre felt as if he +had returned from a long journey on which he had spent dozens of +years, had become completely changed, and had quite left behind his +former habits and way of life. + + + + + +CHAPTER V + + +The day after he had been received into the Lodge, Pierre was +sitting at home reading a book and trying to fathom the significance +of the Square, one side of which symbolized God, another moral things, +a third physical things, and the fourth a combination of these. Now +and then his attention wandered from the book and the Square and he +formed in imagination a new plan of life. On the previous evening at +the Lodge, he had heard that a rumor of his duel had reached the +Emperor and that it would be wiser for him to leave Petersburg. Pierre +proposed going to his estates in the south and there attending to +the welfare of his serfs. He was joyfully planning this new life, when +Prince Vasili suddenly entered the room. + +"My dear fellow, what have you been up to in Moscow? Why have you +quarreled with Helene, mon cher? You are under a delusion," said +Prince Vasili, as he entered. "I know all about it, and I can tell you +positively that Helene is as innocent before you as Christ was +before the Jews." + +Pierre was about to reply, but Prince Vasili interrupted him. + +"And why didn't you simply come straight to me as to a friend? I +know all about it and understand it all," he said. "You behaved as +becomes a man values his honor, perhaps too hastily, but we won't go +into that. But consider the position in which you are placing her +and me in the eyes of society, and even of the court," he added, +lowering his voice. "She is living in Moscow and you are here. +Remember, dear boy," and he drew Pierre's arm downwards, "it is simply +a misunderstanding. I expect you feel it so yourself. Let us write her +a letter at once, and she'll come here and all will be explained, or +else, my dear boy, let me tell you it's quite likely you'll have to +suffer for it." + +Prince Vasili gave Pierre a significant look. + +"I know from reliable sources that the Dowager Empress is taking a +keen interest in the whole affair. You know she is very gracious to +Helene." + +Pierre tried several times to speak, but, on one hand, Prince Vasili +did not let him and, on the other, Pierre himself feared to begin to +speak in the tone of decided refusal and disagreement in which he +had firmly resolved to answer his father-in-law. Moreover, the words +of the Masonic statutes, "be kindly and courteous," recurred to him. +He blinked, went red, got up and sat down again, struggling with +himself to do what was for him the most difficult thing in life--to +say an unpleasant thing to a man's face, to say what the other, +whoever he might be, did not expect. He was so used to submitting to +Prince Vasili's tone of careless self-assurance that he felt he +would be unable to withstand it now, but he also felt that on what +he said now his future depended--whether he would follow the same +old road, or that new path so attractively shown him by the Masons, on +which he firmly believed he would be reborn to a new life. + +"Now, dear boy," said Prince Vasili playfully, "say 'yes,' and +I'll write to her myself, and we will kill the fatted calf." + +But before Prince Vasili had finished his playful speech, Pierre, +without looking at him, and with a kind of fury that made him like his +father, muttered in a whisper: + +"Prince, I did not ask you here. Go, please go!" And he jumped up +and opened the door for him. + +"Go!" he repeated, amazed at himself and glad to see the look of +confusion and fear that showed itself on Prince Vasili's face. + +"What's the matter with you? Are you ill?" + +"Go!" the quivering voice repeated. And Prince Vasili had to go +without receiving any explanation. + +A week later, Pierre, having taken leave of his new friends, the +Masons, and leaving large sums of money with them for alms, went +away to his estates. His new brethren gave him letters to the Kiev and +Odessa Masons and promised to write to him and guide him in his new +activity. + + + + + +CHAPTER VI + + +The duel between Pierre and Dolokhov was hushed up and, in spite +of the Emperor's severity regarding duels at that time, neither the +principals nor their seconds suffered for it. But the story of the +duel, confirmed by Pierre's rupture with his wife, was the talk of +society. Pierre who had been regarded with patronizing condescension +when he was an illegitimate son, and petted and extolled when he was +the best match in Russia, had sunk greatly in the esteem of society +after his marriage--when the marriageable daughters and their +mothers had nothing to hope from him--especially as he did not know +how, and did not wish, to court society's favor. Now he alone was +blamed for what had happened, he was said to be insanely jealous and +subject like his father to fits of bloodthirsty rage. And when after +Pierre's departure Helene returned to Petersburg, she was received +by all her acquaintances not only cordially, but even with a shade +of deference due to her misfortune. When conversation turned on her +husband Helene assumed a dignified expression, which with +characteristic tact she had acquired though she did not understand its +significance. This expression suggested that she had resolved to +endure her troubles uncomplainingly and that her husband was a cross +laid upon her by God. Prince Vasili expressed his opinion more openly. +He shrugged his shoulders when Pierre was mentioned and, pointing to +his forehead, remarked: + +"A bit touched--I always said so." + +"I said from the first," declared Anna Pavlovna referring to Pierre, +"I said at the time and before anyone else" (she insisted on her +priority) "that that senseless young man was spoiled by the depraved +ideas of these days. I said so even at the time when everybody was +in raptures about him, when he had just returned from abroad, and +when, if you remember, he posed as a sort of Marat at one of my +soirees. And how has it ended? I was against this marriage even then +and foretold all that has happened." + +Anna Pavlovna continued to give on free evenings the same kind of +soirees as before--such as she alone had the gift of arranging--at +which was to be found "the cream of really good society, the bloom +of the intellectual essence of Petersburg," as she herself put it. +Besides this refined selection of society Anna Pavlovna's receptions +were also distinguished by the fact that she always presented some new +and interesting person to the visitors and that nowhere else was the +state of the political thermometer of legitimate Petersburg court +society so dearly and distinctly indicated. + +Toward the end of 1806, when all the sad details of Napoleon's +destruction of the Prussian army at Jena and Auerstadt and the +surrender of most of the Prussian fortresses had been received, when +our troops had already entered Prussia and our second war with +Napoleon was beginning, Anna Pavlovna gave one of her soirees. The +"cream of really good society" consisted of the fascinating Helene, +forsaken by her husband, Mortemart, the delightful Prince Hippolyte +who had just returned from Vienna, two diplomatists, the old aunt, a +young man referred to in that drawing room as "a man of great merit" +(un homme de beaucoup de merite), a newly appointed maid of honor +and her mother, and several other less noteworthy persons. + +The novelty Anna Pavlovna was setting before her guests that evening +was Boris Drubetskoy, who had just arrived as a special messenger from +the Prussian army and was aide-de-camp to a very important personage. + +The temperature shown by the political thermometer to the company +that evening was this: + +"Whatever the European sovereigns and commanders may do to +countenance Bonaparte, and to cause me, and us in general, annoyance +and mortification, our opinion of Bonaparte cannot alter. We shall not +cease to express our sincere views on that subject, and can only say +to the King Prussia and others: 'So much the worse for you. Tu l'as +voulu, George Dandin,' that's all we have to say about it!" + +When Boris, who was to be served up to the guests, entered the +drawing room, almost all the company had assembled, and the +conversation, guided by Anna Pavlovna, was about our diplomatic +relations with Austria and the hope of an alliance with her. + +Boris, grown more manly and looking fresh, rosy and +self-possessed, entered the drawing room elegantly dressed in the +uniform of an aide-de-camp and was duly conducted to pay his +respects to the aunt and then brought back to the general circle. + +Anna Pavlovna gave him her shriveled hand to kiss and introduced him +to several persons whom he did not know, giving him a whispered +description of each. + +"Prince Hippolyte Kuragin, M. Krug, the charge d'affaires from +Copenhagen--a profound intellect," and simply, "Mr. Shitov--a +man of great merit"--this of the man usually so described. + +Thanks to Anna Mikhaylovna's efforts, his own tastes, and the +peculiarities of his reserved nature, Boris had managed during his +service to place himself very advantageously. He was aide-de-camp to a +very important personage, had been sent on a very important mission to +Prussia, and had just returned from there as a special messenger. He +had become thoroughly conversant with that unwritten code with which +he had been so pleased at Olmutz and according to which an ensign +might rank incomparably higher than a general, and according to +which what was needed for success in the service was not effort or +work, or courage, or perseverance, but only the knowledge of how to +get on with those who can grant rewards, and he was himself often +surprised at the rapidity of his success and at the inability of +others to understand these things. In consequence of this discovery +his whole manner of life, all his relations with old friends, all +his plans for his future, were completely altered. He was not rich, +but would spend his last groat to be better dressed than others, and +would rather deprive himself of many pleasures than allow himself to +be seen in a shabby equipage or appear in the streets of Petersburg in +an old uniform. He made friends with and sought the acquaintance of +only those above him in position and who could therefore be of use +to him. He liked Petersburg and despised Moscow. The remembrance of +the Rostovs' house and of his childish love for Natasha was unpleasant +to him and he had not once been to see the Rostovs since the day of +his departure for the army. To be in Anna Pavlovna's drawing room he +considered an important step up in the service, and he at once +understood his role, letting his hostess make use of whatever interest +he had to offer. He himself carefully scanned each face, appraising +the possibilities of establishing intimacy with each of those present, +and the advantages that might accrue. He took the seat indicated to +him beside the fair Helene and listened to the general conversation. + +"Vienna considers the bases of the proposed treaty so unattainable +that not even a continuity of most brilliant successes would secure +them, and she doubts the means we have of gaining them. That is the +actual phrase used by the Vienna cabinet," said the Danish charge +d'affaires. + +"The doubt is flattering," said "the man of profound intellect," +with a subtle smile. + +"We must distinguish between the Vienna cabinet and the Emperor of +Austria," said Mortemart. "The Emperor of Austria can never have +thought of such a thing, it is only the cabinet that says it." + +"Ah, my dear vicomte," put in Anna Pavlovna, "L'Urope" (for some +reason she called it Urope as if that were a specially refined +French pronunciation which she could allow herself when conversing +with a Frenchman), "L'Urope ne sera jamais notre alliee sincere."* + + +*"Europe will never be our sincere ally." + + +After that Anna Pavlovna led up to the courage and firmness of the +King of Prussia, in order to draw Boris into the conversation. + +Boris listened attentively to each of the speakers, awaiting his +turn, but managed meanwhile to look round repeatedly at his +neighbor, the beautiful Helene, whose eyes several times met those +of the handsome young aide-de-camp with a smile. + +Speaking of the position of Prussia, Anna Pavlovna very naturally +asked Boris to tell them about his journey to Glogau and in what state +he found the Prussian army. Boris, speaking with deliberation, told +them in pure, correct French many interesting details about the armies +and the court, carefully abstaining from expressing an opinion of +his own about the facts he was recounting. For some time he +engrossed the general attention, and Anna Pavlovna felt that the +novelty she had served up was received with pleasure by all her +visitors. The greatest attention of all to Boris' narrative was +shown by Helene. She asked him several questions about his journey and +seemed greatly interested in the state of the Prussian army. As soon +as he had finished she turned to him with her usual smile. + +"You absolutely must come and see me," she said in a tone that +implied that, for certain considerations he could not know of, this +was absolutely necessary. + +"On Tuesday between eight and nine. It will give me great pleasure." + +Boris promised to fulfill her wish and was about to begin a +conversation with her, when Anna Pavlovna called him away on the +pretext that her aunt wished to hear him. + +"You know her husband, of course?" said Anna Pavlovna, closing her +eyes and indicating Helene with a sorrowful gesture. "Ah, she is +such an unfortunate and charming woman! Don't mention him before +her--please don't! It is too painful for her!" + + + + + +CHAPTER VII + + +When Boris and Anna Pavlovna returned to the others Prince Hippolyte +had the ear of the company. + +Bending forward in his armchair he said: "Le Roi de Prusse!" and +having said this laughed. Everyone turned toward him. + +"Le Roi de Prusse?" Hippolyte said interrogatively, again +laughing, and then calmly and seriously sat back in his chair. Anna +Pavlovna waited for him to go on, but as he seemed quite decided to +say no more she began to tell of how at Potsdam the impious +Bonaparte had stolen the sword of Frederick the Great. + +"It is the sword of Frederick the Great which I..." she began, but +Hippolyte interrupted her with the words: "Le Roi de Prusse..." and +again, as soon as all turned toward him, excused himself and +said no more. + +Anna Pavlovna frowned. Mortemart, Hippolyte's friend, addressed +him firmly. + +"Come now, what about your Roi de Prusse?" + +Hippolyte laughed as if ashamed of laughing. + +"Oh, it's nothing. I only wished to say..." (he wanted to repeat a +joke he had heard in Vienna and which he had been trying all that +evening to get in) "I only wished to say that we are wrong to fight +pour le Roi de Prusse!" + +Boris smiled circumspectly, so that it might be taken as ironical or +appreciative according to the way the joke was received. Everybody +laughed. + +"Your joke is too bad, it's witty but unjust," said Anna Pavlovna, +shaking her little shriveled finger at him. + +"We are not fighting pour le Roi de Prusse, but for right +principles. Oh, that wicked Prince Hippolyte!" she said. + +The conversation did not flag all evening and turned chiefly on +the political news. It became particularly animated toward the end +of the evening when the rewards bestowed by the Emperor were +mentioned. + +"You know N--N--received a snuffbox with the portrait last year?" +said "the man of profound intellect." "Why shouldn't S--S--get the +same distinction?" + +"Pardon me! A snuffbox with the Emperor's portrait is a reward but +not a distinction," said the diplomatist--"a gift, rather." + +"There are precedents, I may mention Schwarzenberg." + +"It's impossible," replied another. + +"Will you bet? The ribbon of the order is a different matter...." + +When everybody rose to go, Helene who had spoken very little all the +evening again turned to Boris, asking him in a tone of caressing +significant command to come to her on Tuesday. + +"It is of great importance to me," she said, turning with a smile +toward Anna Pavlovna, and Anna Pavlovna, with the same sad smile +with which she spoke of her exalted patroness, supported Helene's +wish. + +It seemed as if from some words Boris had spoken that evening +about the Prussian army, Helene had suddenly found it necessary to see +him. She seemed to promise to explain that necessity to him when he +came on Tuesday. + +But on Tuesday evening, having come to Helene's splendid salon, +Boris received no clear explanation of why it had been necessary for +him to come. There were other guests and the countess talked little to +him, and only as he kissed her hand on taking leave said +unexpectedly and in a whisper, with a strangely unsmiling face: +"Come to dinner tomorrow... in the evening. You must come.... Come!" + +During that stay in Petersburg, Boris became an intimate in the +countess' house. + + + + + +CHAPTER VIII + + +The war was flaming up and nearing the Russian frontier. +Everywhere one heard curses on Bonaparte, "the enemy of mankind." +Militiamen and recruits were being enrolled in the villages, and +from the seat of war came contradictory news, false as usual and +therefore variously interpreted. The life of old Prince Bolkonski, +Prince Andrew, and Princess Mary had greatly changed since 1805. + +In 1806 the old prince was made one of the eight commanders in chief +then appointed to supervise the enrollment decreed throughout +Russia. Despite the weakness of age, which had become particularly +noticeable since the time when he thought his son had been killed, +he did not think it right to refuse a duty to which he had been +appointed by the Emperor himself, and this fresh opportunity for +action gave him new energy and strength. He was continually +traveling through the three provinces entrusted to him, was pedantic +in the fulfillment of his duties, severe to cruelty with his +subordinates, and went into everything down to the minutest details +himself. Princess Mary had ceased taking lessons in mathematics from +her father, and when the old prince was at home went to his study with +the wet nurse and little Prince Nicholas (as his grandfather called +him). The baby Prince Nicholas lived with his wet nurse and nurse +Savishna in the late princess' rooms and Princess Mary spent most of +the day in the nursery, taking a mother's place to her little nephew +as best she could. Mademoiselle Bourienne, too, seemed passionately +fond of the boy, and Princess Mary often deprived herself to give +her friend the pleasure of dandling the little angel--as she called +her nephew--and playing with him. + +Near the altar of the church at Bald Hills there was a chapel over +the tomb of the little princess, and in this chapel was a marble +monument brought from Italy, representing an angel with outspread +wings ready to fly upwards. The angel's upper lip was slightly +raised as though about to smile, and once on coming out of the +chapel Prince Andrew and Princess Mary admitted to one another that +the angel's face reminded them strangely of the little princess. But +what was still stranger, though of this Prince Andrew said nothing +to his sister, was that in the expression the sculptor had happened to +give the angel's face, Prince Andrew read the same mild reproach he +had read on the face of his dead wife: "Ah, why have you done this +to me?" + +Soon after Prince Andrew's return the old prince made over to him +a large estate, Bogucharovo, about twenty-five miles from Bald +Hills. Partly because of the depressing memories associated with +Bald Hills, partly because Prince Andrew did not always feel equal +to bearing with his father's peculiarities, and partly because he +needed solitude, Prince Andrew made use of Bogucharovo, began building +and spent most of his time there. + +After the Austerlitz campaign Prince Andrew had firmly resolved +not to continue his military service, and when the war recommenced and +everybody had to serve, he took a post under his father in the +recruitment so as to avoid active service. The old prince and his +son seemed to have changed roles since the campaign of 1805. The old +man, roused by activity, expected the best results from the new +campaign, while Prince Andrew on the contrary, taking no part in the +war and secretly regretting this, saw only the dark side. + +On February 26, 1807, the old prince set off on one of his circuits. +Prince Andrew remained at Bald Hills as usual during his father's +absence. Little Nicholas had been unwell for four days. The coachman +who had driven the old prince to town returned bringing papers and +letters for Prince Andrew. + +Not finding the young prince in his study the valet went with the +letters to Princess Mary's apartments, but did not find him there. +He was told that the prince had gone to the nursery. + +"If you please, your excellency, Petrusha has brought some +papers," said one of the nursemaids to Prince Andrew who was sitting +on a child's little chair while, frowning and with trembling hands, he +poured drops from a medicine bottle into a wineglass half full of +water. + +"What is it?" he said crossly, and, his hand shaking +unintentionally, he poured too many drops into the glass. He threw the +mixture onto the floor and asked for some more water. The maid brought +it. + +There were in the room a child's cot, two boxes, two armchairs, a +table, a child's table, and the little chair on which Prince Andrew +was sitting. The curtains were drawn, and a single candle was +burning on the table, screened by a bound music book so that the light +did not fall on the cot. + +"My dear," said Princess Mary, addressing her brother from beside +the cot where she was standing, "better wait a bit... later..." + +"Oh, leave off, you always talk nonsense and keep putting things +off--and this is what comes of it!" said Prince Andrew in an +exasperated whisper, evidently meaning to wound his sister. + +"My dear, really... it's better not to wake him... he's asleep," +said the princess in a tone of entreaty. + +Prince Andrew got up and went on tiptoe up to the little bed, +wineglass in hand. + +"Perhaps we'd really better not wake him," he said hesitating. + +"As you please... really... I think so... but as you please," said +Princess Mary, evidently intimidated and confused that her opinion had +prevailed. She drew her brother's attention to the maid who was +calling him in a whisper. + +It was the second night that neither of them had slept, watching the +boy who was in a high fever. These last days, mistrusting their +household doctor and expecting another for whom they had sent to town, +they had been trying first one remedy and then another. Worn out by +sleeplessness and anxiety they threw their burden of sorrow on one +another and reproached and disputed with each other. + +"Petrusha has come with papers from your father," whispered the +maid. + +Prince Andrew went out. + +"Devil take them!" he muttered, and after listening to the verbal +instructions his father had sent and taking the correspondence and his +father's letter, he returned to the nursery. + +"Well?" he asked. + +"Still the same. Wait, for heaven's sake. Karl Ivanich always says +that sleep is more important than anything," whispered Princess Mary +with a sigh. + +Prince Andrew went up to the child and felt him. He was burning hot. + +"Confound you and your Karl Ivanich!" He took the glass with the +drops and again went up to the cot. + +"Andrew, don't!" said Princess Mary. + +But he scowled at her angrily though also with suffering in his +eyes, and stooped glass in hand over the infant. + +"But I wish it," he said. "I beg you--give it him!" + +Princess Mary shrugged her shoulders but took the glass submissively +and calling the nurse began giving the medicine. The child screamed +hoarsely. Prince Andrew winced and, clutching his head, went out and +sat down on a sofa in the next room. + +He still had all the letters in his hand. Opening them +mechanically he began reading. The old prince, now and then using +abbreviations, wrote in his large elongated hand on blue paper as +follows: + + +Have just this moment received by special messenger very joyful +news--if it's not false. Bennigsen seems to have obtained a complete +victory over Buonaparte at Eylau. In Petersburg everyone is rejoicing, +and the rewards sent to the army are innumerable. Though he is a +German--I congratulate him! I can't make out what the commander at +Korchevo--a certain Khandrikov--is up to; till now the additional +men and provisions have not arrived. Gallop off to him at once and say +I'll have his head off if everything is not here in a week. Have +received another letter about the Preussisch-Eylau battle from +Petenka--he took part in it--and it's all true. When mischief-makers +don't meddle even a German beats Buonaparte. He is said to be +fleeing in great disorder. Mind you gallop off to Korchevo without +delay and carry out instructions! + + +Prince Andrew sighed and broke the seal of another envelope. It +was a closely written letter of two sheets from Bilibin. He folded +it up without reading it and reread his father's letter, ending with +the words: "Gallop off to Korchevo and carry out instructions!" + +"No, pardon me, I won't go now till the child is better," thought +he, going to the door and looking into the nursery. + +Princess Mary was still standing by the cot, gently rocking the +baby. + +"Ah yes, and what else did he say that's unpleasant?" thought Prince +Andrew, recalling his father's letter. "Yes, we have gained a +victory over Bonaparte, just when I'm not serving. Yes, yes, he's +always poking fun at me.... Ah, well! Let him!" And he began reading +Bilibin's letter which was written in French. He read without +understanding half of it, read only to forget, if but for a moment, +what he had too long been thinking of so painfully to the exclusion of +all else. + + + + + +CHAPTER IX + + +Bilibin was now at army headquarters in a diplomatic capacity, and +though he wrote in French and used French jests and French idioms, +he described the whole campaign with a fearless self-censure and +self-derision genuinely Russian. Bilibin wrote that the obligation +of diplomatic discretion tormented him, and he was happy to have in +Prince Andrew a reliable correspondent to whom he could pour out the +bile he had accumulated at the sight of all that was being done in the +army. The letter was old, having been written before the battle at +Preussisch-Eylau. + +"Since the day of our brilliant success at Austerlitz," wrote +Bilibin, "as you know, my dear prince, I never leave headquarters. I +have certainly acquired a taste for war, and it is just as well for +me; what I have seen during these last three months is incredible. + +"I begin ab ovo. 'The enemy of the human race,' as you know, attacks +the Prussians. The Prussians are our faithful allies who have only +betrayed us three times in three years. We take up their cause, but it +turns out that 'the enemy of the human race' pays no heed to our +fine speeches and in his rude and savage way throws himself on the +Prussians without giving them time to finish the parade they had +begun, and in two twists of the hand he breaks them to smithereens and +installs himself in the palace at Potsdam. + +"'I most ardently desire,' writes the King of Prussia to +Bonaparte, 'that Your Majesty should be received and treated in my +palace in a manner agreeable to yourself, and in so far as +circumstances allowed, I have hastened to take all steps to that +end. May I have succeeded!' The Prussian generals pride themselves +on being polite to the French and lay down their arms at the first +demand. + +"The head of the garrison at Glogau, with ten thousand men, asks the +King of Prussia what he is to do if he is summoned to surrender.... +All this is absolutely true. + +"In short, hoping to settle matters by taking up a warlike attitude, +it turns out that we have landed ourselves in war, and what is more, +in war on our own frontiers, with and for the King of Prussia. We have +everything in perfect order, only one little thing is lacking, namely, +a commander in chief. As it was considered that the Austerlitz success +might have been more decisive had the commander in chief not been so +young, all our octogenarians were reviewed, and of Prozorovski and +Kamenski the latter was preferred. The general comes to us, +Suvorov-like, in a kibitka, and is received with acclamations of joy +and triumph. + +"On the 4th, the first courier arrives from Petersburg. The mails +are taken to the field marshal's room, for he likes to do everything +himself. I am called in to help sort the letters and take those +meant for us. The field marshal looks on and waits for letters +addressed to him. We search, but none are to be found. The field +marshal grows impatient and sets to work himself and finds letters +from the Emperor to Count T., Prince V., and others. Then he bursts +into one of his wild furies and rages at everyone and everything, +seizes the letters, opens them, and reads those from the Emperor +addressed to others. 'Ah! So that's the way they treat me! No +confidence in me! Ah, ordered to keep an eye on me! Very well then! +Get along with you!' So he writes the famous order of the day to +General Bennigsen: + +'I am wounded and cannot ride and consequently cannot command the +army. You have brought your army corps to Pultusk, routed: here it +is exposed, and without fuel or forage, so something must be done, +and, as you yourself reported to Count Buxhowden yesterday, you must +think of retreating to our frontier--which do today.' + +"'From all my riding,' he writes to the Emperor, 'I have got a +saddle sore which, coming after all my previous journeys, quite +prevents my riding and commanding so vast an army, so I have passed on +the command to the general next in seniority, Count Buxhowden, +having sent him my whole staff and all that belongs to it, advising +him if there is a lack of bread, to move farther into the interior +of Prussia, for only one day's ration of bread remains, and in some +regiments none at all, as reported by the division commanders, +Ostermann and Sedmoretzki, and all that the peasants had has been +eaten up. I myself will remain in hospital at Ostrolenka till I +recover. In regard to which I humbly submit my report, with the +information that if the army remains in its present bivouac another +fortnight there will not be a healthy man left in it by spring. + +"'Grant leave to retire to his country seat to an old man who is +already in any case dishonored by being unable to fulfill the great +and glorious task for which he was chosen. I shall await your most +gracious permission here in hospital, that I may not have to play +the part of a secretary rather than commander in the army. My +removal from the army does not produce the slightest stir--a blind man +has left it. There are thousands such as I in Russia.' + +"The field marshal is angry with the Emperor and he punishes us all, +isn't it logical? + +"This is the first act. Those that follow are naturally increasingly +interesting and entertaining. After the field marshal's departure it +appears that we are within sight of the enemy and must give battle. +Buxhowden is commander in chief by seniority, but General Bennigsen +does not quite see it; more particularly as it is he and his corps who +are within sight of the enemy and he wishes to profit by the +opportunity to fight a battle 'on his own hand' as the Germans say. He +does so. This is the battle of Pultusk, which is considered a great +victory but in my opinion was nothing of the kind. We civilians, as +you know, have a very bad way of deciding whether a battle was won +or lost. Those who retreat after a battle have lost it is what we say; +and according to that it is we who lost the battle of Pultusk. In +short, we retreat after the battle but send a courier to Petersburg +with news of a victory, and General Bennigsen, hoping to receive +from Petersburg the post of commander in chief as a reward for his +victory, does not give up the command of the army to General +Buxhowden. During this interregnum we begin a very original and +interesting series of maneuvers. Our aim is no longer, as it should +be, to avoid or attack the enemy, but solely to avoid General +Buxhowden who by right of seniority should be our chief. So +energetically do we pursue this aim that after crossing an +unfordable river we burn the bridges to separate ourselves from our +enemy, who at the moment is not Bonaparte but Buxhowden. General +Buxhowden was all but attacked and captured by a superior enemy +force as a result of one of these maneuvers that enabled us to +escape him. Buxhowden pursues us--we scuttle. He hardly crosses the +river to our side before we recross to the other. At last our enemy. +Buxhowden, catches us and attacks. Both generals are angry, and the +result is a challenge on Buxhowden's part and an epileptic fit on +Bennigsen's. But at the critical moment the courier who carried the +news of our victory at Pultusk to Petersburg returns bringing our +appointment as commander in chief, and our first foe, Buxhowden, is +vanquished; we can now turn our thoughts to the second, Bonaparte. But +as it turns out, just at that moment a third enemy rises before us- +namely the Orthodox Russian soldiers, loudly demanding bread, meat, +biscuits, fodder, and whatnot! The stores are empty, the roads +impassable. The Orthodox begin looting, and in a way of which our last +campaign can give you no idea. Half the regiments form bands and scour +the countryside and put everything to fire and sword. The +inhabitants are totally ruined, the hospitals overflow with sick, +and famine is everywhere. Twice the marauders even attack our +headquarters, and the commander in chief has to ask for a battalion to +disperse them. During one of these attacks they carried off my empty +portmanteau and my dressing gown. The Emperor proposes to give all +commanders of divisions the right to shoot marauders, but I much +fear this will oblige one half the army to shoot the other." + +At first Prince Andrew read with his eyes only, but after a while, +in spite of himself (although he knew how far it was safe to trust +Bilibin), what he had read began to interest him more and more. When +he had read thus far, he crumpled the letter up and threw it away. +It was not what he had read that vexed him, but the fact that the life +out there in which he had now no part could perturb him. He shut his +eyes, rubbed his forehead as if to rid himself of all interest in what +he had read, and listened to what was passing in the nursery. Suddenly +he thought he heard a strange noise through the door. He was seized +with alarm lest something should have happened to the child while he +was reading the letter. He went on tiptoe to the nursery door and +opened it. + +Just as he went in he saw that the nurse was hiding something from +him with a scared look and that Princess Mary was no longer by the +cot. + +"My dear," he heard what seemed to him her despairing whisper behind +him. + +As often happens after long sleeplessness and long anxiety, he was +seized by an unreasoning panic--it occurred to him that the child +was dead. All that he saw and heard seemed to confirm this terror. + +"All is over," he thought, and a cold sweat broke out on his +forehead. He went to the cot in confusion, sure that he would find +it empty and that the nurse had been hiding the dead baby. He drew the +curtain aside and for some time his frightened, restless eyes could +not find the baby. At last he saw him: the rosy boy had tossed about +till he lay across the bed with his head lower than the pillow, and +was smacking his lips in his sleep and breathing evenly. + +Prince Andrew was as glad to find the boy like that, as if he had +already lost him. He bent over him and, as his sister had taught +him, tried with his lips whether the child was still feverish. The +soft forehead was moist. Prince Andrew touched the head with his hand; +even the hair was wet, so profusely had the child perspired. He was +not dead, but evidently the crisis was over and he was convalescent. +Prince Andrew longed to snatch up, to squeeze, to hold to his heart, +this helpless little creature, but dared not do so. He stood over him, +gazing at his head and at the little arms and legs which showed +under the blanket. He heard a rustle behind him and a shadow +appeared under the curtain of the cot. He did not look round, but +still gazing at the infant's face listened to his regular breathing. +The dark shadow was Princess Mary, who had come up to the cot with +noiseless steps, lifted the curtain, and dropped it again behind +her. Prince Andrew recognized her without looking and held out his +hand to her. She pressed it. + +"He has perspired," said Prince Andrew. + +"I was coming to tell you so." + +The child moved slightly in his sleep, smiled, and rubbed his +forehead against the pillow. + +Prince Andrew looked at his sister. In the dim shadow of the curtain +her luminous eyes shone more brightly than usual from the tears of joy +that were in them. She leaned over to her brother and kissed him, +slightly catching the curtain of the cot. Each made the other a +warning gesture and stood still in the dim light beneath the curtain +as if not wishing to leave that seclusion where they three were shut +off from all the world. Prince Andrew was the first to move away, +ruffling his hair against the muslin of the curtain. + +"Yes, this is the one thing left me now," he said with a sigh. + + + + +CHAPTER X + + +Soon after his admission to the Masonic Brotherhood, Pierre went +to the Kiev province, where he had the greatest number of serfs, +taking with him full directions which he had written down for his +own guidance as to what he should do on his estates. + +When he reached Kiev he sent for all his stewards to the head office +and explained to them his intentions and wishes. He told them that +steps would be taken immediately to free his serfs--and that till then +they were not to be overburdened with labor, women while nursing their +babies were not to be sent to work, assistance was to be given to +the serfs, punishments were to be admonitory and not corporal, and +hospitals, asylums, and schools were to be established on all the +estates. Some of the stewards (there were semiliterate foremen among +them) listened with alarm, supposing these words to mean that the +young count was displeased with their management and embezzlement of +money, some after their first fright were amused by Pierre's lisp +and the new words they had not heard before, others simply enjoyed +hearing how the master talked, while the cleverest among them, +including the chief steward, understood from this speech how they +could best handle the master for their own ends. + +The chief steward expressed great sympathy with Pierre's intentions, +but remarked that besides these changes it would be necessary to go +into the general state of affairs which was far from satisfactory. + +Despite Count Bezukhov's enormous wealth, since he had come into +an income which was said to amount to five hundred thousand rubles a +year, Pierre felt himself far poorer than when his father had made him +an allowance of ten thousand rubles. He had a dim perception of the +following budget: + +About 80,000 went in payments on all the estates to the Land Bank, +about 30,000 went for the upkeep of the estate near Moscow, the town +house, and the allowance to the three princesses; about 15,000 was +given in pensions and the same amount for asylums; 150,000 alimony was +sent to the countess; about 70,00 went for interest on debts. The +building of a new church, previously begun, had cost about 10,000 in +each of the last two years, and he did not know how the rest, about +100,000 rubles, was spent, and almost every year he was obliged to +borrow. Besides this the chief steward wrote every year telling him of +fires and bad harvests, or of the necessity of rebuilding factories +and workshops. So the first task Pierre had to face was one for +which he had very little aptitude or inclination--practical business. + +He discussed estate affairs every day with his chief steward. But he +felt that this did not forward matters at all. He felt that these +consultations were detached from real affairs and did not link up with +them or make them move. On the one hand, the chief steward put the +state of things to him in the very worst light, pointing out the +necessity of paying off the debts and undertaking new activities +with serf labor, to which Pierre did not agree. On the other hand, +Pierre demanded that steps should be taken to liberate the serfs, +which the steward met by showing the necessity of first paying off the +loans from the Land Bank, and the consequent impossibility of a speedy +emancipation. + +The steward did not say it was quite impossible, but suggested +selling the forests in the province of Kostroma, the land lower down +the river, and the Crimean estate, in order to make it possible: all +of which operations according to him were connected with such +complicated measures--the removal of injunctions, petitions, +permits, and so on--that Pierre became quite bewildered and only +replied: + +"Yes, yes, do so." + +Pierre had none of the practical persistence that would have enabled +him to attend to the business himself and so he disliked it and only +tried to pretend to the steward that he was attending to it. The +steward for his part tried to pretend to the count that he +considered these consultations very valuable for the proprietor and +troublesome to himself. + +In Kiev Pierre found some people he knew, and strangers hastened +to make his acquaintance and joyfully welcomed the rich newcomer, +the largest landowner of the province. Temptations to Pierre's +greatest weakness--the one to which he had confessed when admitted +to the Lodge--were so strong that he could not resist them. Again +whole days, weeks, and months of his life passed in as great a rush +and were as much occupied with evening parties, dinners, lunches, +and balls, giving him no time for reflection, as in Petersburg. +Instead of the new life he had hoped to lead he still lived the old +life, only in new surroundings. + +Of the three precepts of Freemasonry Pierre realized that he did not +fulfill the one which enjoined every Mason to set an example of +moral life, and that of the seven virtues he lacked two--morality +and the love of death. He consoled himself with the thought that he +fulfilled another of the precepts--that of reforming the human race- +and had other virtues--love of his neighbor, and especially +generosity. + +In the spring of 1807 he decided to return to Petersburg. On the way +he intended to visit all his estates and see for himself how far his +orders had been carried out and in what state were the serfs whom +God had entrusted to his care and whom he intended to benefit. + +The chief steward, who considered the young count's attempts +almost insane--unprofitable to himself, to the count, and to the +serfs--made some concessions. Continuing to represent the liberation +of the serfs as impracticable, he arranged for the erection of large +buildings--schools, hospitals, and asylums--on all the estates +before the master arrived. Everywhere preparations were made not for +ceremonious welcomes (which he knew Pierre would not like), but for +just such gratefully religious ones, with offerings of icons and the +bread and salt of hospitality, as, according to his understanding of +his master, would touch and delude him. + +The southern spring, the comfortable rapid traveling in a Vienna +carriage, and the solitude of the road, all had a gladdening effect on +Pierre. The estates he had not before visited were each more +picturesque than the other; the serfs everywhere seemed thriving and +touchingly grateful for the benefits conferred on them. Everywhere +were receptions, which though they embarrassed Pierre awakened a +joyful feeling in the depth of his heart. In one place the peasants +presented him with bread and salt and an icon of Saint Peter and Saint +Paul, asking permission, as a mark of their gratitude for the benefits +he had conferred on them, to build a new chantry to the church at +their own expense in honor of Peter and Paul, his patron saints. In +another place the women with infants in arms met him to thank him +for releasing them from hard work. On a third estate the priest, +bearing a cross, came to meet him surrounded by children whom, by +the count's generosity, he was instructing in reading, writing, and +religion. On all his estates Pierre saw with his own eyes brick +buildings erected or in course of erection, all on one plan, for +hospitals, schools, and almshouses, which were soon to be opened. +Everywhere he saw the stewards' accounts, according to which the +serfs' manorial labor had been diminished, and heard the touching +thanks of deputations of serfs in their full-skirted blue coats. + +What Pierre did not know was that the place where they presented him +with bread and salt and wished to build a chantry in honor of Peter +and Paul was a market village where a fair was held on St. Peter's +day, and that the richest peasants (who formed the deputation) had +begun the chantry long before, but that nine tenths of the peasants in +that villages were in a state of the greatest poverty. He did not know +that since the nursing mothers were no longer sent to work on his +land, they did still harder work on their own land. He did not know +that the priest who met him with the cross oppressed the peasants by +his exactions, and that the pupils' parents wept at having to let +him take their children and secured their release by heavy payments. +He did not know that the brick buildings, built to plan, were being +built by serfs whose manorial labor was thus increased, though +lessened on paper. He did not know that where the steward had shown +him in the accounts that the serfs' payments had been diminished by +a third, their obligatory manorial work had been increased by a +half. And so Pierre was delighted with his visit to his estates and +quite recovered the philanthropic mood in which he had left +Petersburg, and wrote enthusiastic letters to his "brother-instructor" +as he called the Grand Master. + +"How easy it is, how little effort it needs, to do so much good," +thought Pierre, "and how little attention we pay to it!" + +He was pleased at the gratitude he received, but felt abashed at +receiving it. This gratitude reminded him of how much more he might do +for these simple, kindly people. + +The chief steward, a very stupid but cunning man who saw perfectly +through the naive and intelligent count and played with him as with +a toy, seeing the effect these prearranged receptions had on Pierre, +pressed him still harder with proofs of the impossibility and above +all the uselessness of freeing the serfs, who were quite happy as it +was. + +Pierre in his secret soul agreed with the steward that it would be +difficult to imagine happier people, and that God only knew what would +happen to them when they were free, but he insisted, though +reluctantly, on what he thought right. The steward promised to do +all in his power to carry out the count's wishes, seeing clearly +that not only would the count never be able to find out whether all +measures had been taken for the sale of the land and forests and to +release them from the Land Bank, but would probably never even inquire +and would never know that the newly erected buildings were standing +empty and that the serfs continued to give in money and work all +that other people's serfs gave--that is to say, all that could be +got out of them. + + + + + +CHAPTER XI + + +Returning from his journey through South Russia in the happiest +state of mind, Pierre carried out an intention he had long had of +visiting his friend Bolkonski, whom he had not seen for two years. + +Bogucharovo lay in a flat uninteresting part of the country among +fields and forests of fir and birch, which were partly cut down. The +house lay behind a newly dug pond filled with water to the brink and +with banks still bare of grass. It was at the end of a village that +stretched along the highroad in the midst of a young copse in which +were a few fir trees. + +The homestead consisted of a threshing floor, outhouses, stables, +a bathhouse, a lodge, and a large brick house with semicircular facade +still in course of construction. Round the house was a garden newly +laid out. The fences and gates were new and solid; two fire pumps +and a water cart, painted green, stood in a shed; the paths were +straight, the bridges were strong and had handrails. Everything bore +an impress of tidiness and good management. Some domestic serfs Pierre +met, in reply to inquiries as to where the prince lived, pointed out a +small newly built lodge close to the pond. Anton, a man who had looked +after Prince Andrew in his boyhood, helped Pierre out of his carriage, +said that the prince was at home, and showed him into a clean little +anteroom. + +Pierre was struck by the modesty of the small though clean house +after the brilliant surroundings in which he had last met his friend +in Petersburg. + +He quickly entered the small reception room with its +still-unplastered wooden walls redolent of pine, and would have gone +farther, but Anton ran ahead on tiptoe and knocked at a door. + +"Well, what is it?" came a sharp, unpleasant voice. + +"A visitor," answered Anton. + +"Ask him to wait," and the sound was heard of a chair being pushed +back. + +Pierre went with rapid steps to the door and suddenly came face to +face with Prince Andrew, who came out frowning and looking old. Pierre +embraced him and lifting his spectacles kissed his friend on the cheek +and looked at him closely. + +"Well, I did not expect you, I am very glad," said Prince Andrew. + +Pierre said nothing; he looked fixedly at his friend with +surprise. He was struck by the change in him. His words were kindly +and there was a smile on his lips and face, but his eyes were dull and +lifeless and in spite of his evident wish to do so he could not give +them a joyous and glad sparkle. Prince Andrew had grown thinner, +paler, and more manly-looking, but what amazed and estranged Pierre +till he got used to it were his inertia and a wrinkle on his brow +indicating prolonged concentration on some one thought. + +As is usually the case with people meeting after a prolonged +separation, it was long before their conversation could settle on +anything. They put questions and gave brief replies about things +they knew ought to be talked over at length. At last the +conversation gradually settled on some of the topics at first +lightly touched on: their past life, plans for the future, Pierre's +journeys and occupations, the war, and so on. The preoccupation and +despondency which Pierre had noticed in his friend's look was now +still more clearly expressed in the smile with which he listened to +Pierre, especially when he spoke with joyful animation of the past +or the future. It was as if Prince Andrew would have liked to +sympathize with what Pierre was saying, but could not. The latter +began to feel that it was in bad taste to speak of his enthusiasms, +dreams, and hopes of happiness or goodness, in Prince Andrew's +presence. He was ashamed to express his new Masonic views, which had +been particularly revived and strengthened by his late tour. He +checked himself, fearing to seem naive, yet he felt an irresistible +desire to show his friend as soon as possible that he was now a +quite different, and better, Pierre than he had been in Petersburg. + +"I can't tell you how much I have lived through since then. I hardly +know myself again." + +"Yes, we have altered much, very much, since then," said Prince +Andrew. + +"Well, and you? What are your plans?" + +"Plans!" repeated Prince Andrew ironically. "My plans?" he said, +as if astonished at the word. "Well, you see, I'm building. I mean +to settle here altogether next year...." + +Pierre looked silently and searchingly into Prince Andrew's face, +which had grown much older. + +"No, I meant to ask..." Pierre began, but Prince Andrew +interrupted him. + +"But why talk of me?... Talk to me, yes, tell me about your +travels and all you have been doing on your estates." + +Pierre began describing what he had done on his estates, trying as +far as possible to conceal his own part in the improvements that had +been made. Prince Andrew several times prompted Pierre's story of what +he had been doing, as though it were all an old-time story, and he +listened not only without interest but even as if ashamed of what +Pierre was telling him. + +Pierre felt uncomfortable and even depressed in his friend's company +and at last became silent. + +"I'll tell you what, my dear fellow," said Prince Andrew, who +evidently also felt depressed and constrained with his visitor, "I +am only bivouacking here and have just come to look round. I am +going back to my sister today. I will introduce you to her. But of +course you know her already," he said, evidently trying to entertain a +visitor with whom he now found nothing in common. "We will go after +dinner. And would you now like to look round my place?" + +They went out and walked about till dinnertime, talking of the +political news and common acquaintances like people who do not know +each other intimately. Prince Andrew spoke with some animation and +interest only of the new homestead he was constructing and its +buildings, but even here, while on the scaffolding, in the midst of +a talk explaining the future arrangements of the house, he interrupted +himself: + +"However, this is not at all interesting. Let us have dinner, and +then we'll set off." + +At dinner, conversation turned on Pierre's marriage. + +"I was very much surprised when I heard of it," said Prince Andrew. + +Pierre blushed, as he always did when it was mentioned, and said +hurriedly: "I will tell you some time how it all happened. But you +know it is all over, and forever." + +"Forever?" said Prince Andrew. "Nothing's forever." + +"But you know how it all ended, don't you? You heard of the duel?" + +"And so you had to go through that too!" + +"One thing I thank God for is that I did not kill that man," said +Pierre. + +"Why so?" asked Prince Andrew. "To kill a vicious dog is a very good +thing really." + +"No, to kill a man is bad--wrong." + +"Why is it wrong?" urged Prince Andrew. "It is not given to man to +know what is right and what is wrong. Men always did and always will +err, and in nothing more than in what they consider right and wrong." + +"What does harm to another is wrong," said Pierre, feeling with +pleasure that for the first time since his arrival Prince Andrew was +roused, had begun to talk, and wanted to express what had brought +him to his present state. + +"And who has told you what is bad for another man?" he asked. + +"Bad! Bad!" exclaimed Pierre. "We all know what is bad for +ourselves." + +"Yes, we know that, but the harm I am conscious of in myself is +something I cannot inflict on others," said Prince Andrew, growing +more and more animated and evidently wishing to express his new +outlook to Pierre. He spoke in French. "I only know two very real +evils in life: remorse and illness. The only good is the absence of +those evils. To live for myself avoiding those two evils is my whole +philosophy now." + +"And love of one's neighbor, and self-sacrifice?" began Pierre. "No, +I can't agree with you! To live only so as not to do evil and not to +have to repent is not enough. I lived like that, I lived for myself +and ruined my life. And only now when I am living, or at least trying" +(Pierre's modesty made him correct himself) "to live for others, +only now have I understood all the happiness of life. No, I shall +not agree with you, and you do not really believe what you are +saying." Prince Andrew looked silently at Pierre with an ironic smile. + +"When you see my sister, Princess Mary, you'll get on with her," +he said. "Perhaps you are right for yourself," he added after a +short pause, "but everyone lives in his own way. You lived for +yourself and say you nearly ruined your life and only found +happiness when you began living for others. I experienced just the +reverse. I lived for glory.--And after all what is glory? The same +love of others, a desire to do something for them, a desire for +their approval.--So I lived for others, and not almost, but quite, +ruined my life. And I have become calmer since I began to live only +for myself." + +"But what do you mean by living only for yourself?" asked Pierre, +growing excited. "What about your son, your sister, and your father?" + +"But that's just the same as myself--they are not others," explained +Prince Andrew. "The others, one's neighbors, le prochain, as you and +Princess Mary call it, are the chief source of all error and evil. +Le prochain--your Kiev peasants to whom you want to do good." + +And he looked at Pierre with a mocking, challenging expression. He +evidently wished to draw him on. + +"You are joking," replied Pierre, growing more and more excited. +"What error or evil can there be in my wishing to do good, and even +doing a little--though I did very little and did it very badly? What +evil can there be in it if unfortunate people, our serfs, people +like ourselves, were growing up and dying with no idea of God and +truth beyond ceremonies and meaningless prayers and are now instructed +in a comforting belief in future life, retribution, recompense, and +consolation? What evil and error are there in it, if people were dying +of disease without help while material assistance could so easily be +rendered, and I supplied them with a doctor, a hospital, and an asylum +for the aged? And is it not a palpable, unquestionable good if a +peasant, or a woman with a baby, has no rest day or night and I give +them rest and leisure?" said Pierre, hurrying and lisping. "And I have +done that though badly and to a small extent; but I have done +something toward it and you cannot persuade me that it was not a +good action, and more than that, you can't make me believe that you do +not think so yourself. And the main thing is," he continued, "that I +know, and know for certain, that the enjoyment of doing this good is +the only sure happiness in life." + +"Yes, if you put it like that it's quite a different matter," said +Prince Andrew. "I build a house and lay out a garden, and you build +hospitals. The one and the other may serve as a pastime. But what's +right and what's good must be judged by one who knows all, but not +by us. Well, you want an argument," he added, "come on then." + +They rose from the table and sat down in the entrance porch which +served as a veranda. + +"Come, let's argue then," said Prince Andrew, "You talk of schools," +he went on, crooking a finger, "education and so forth; that is, you +want to raise him" (pointing to a peasant who passed by them taking +off his cap) "from his animal condition and awaken in him spiritual +needs, while it seems to me that animal happiness is the only +happiness possible, and that is just what you want to deprive him +of. I envy him, but you want to make him what I am, without giving him +my means. Then you say, 'lighten his toil.' But as I see it, +physical labor is as essential to him, as much a condition of his +existence, as mental activity is to you or me. You can't help +thinking. I go to bed after two in the morning, thoughts come and I +can't sleep but toss about till dawn, because I think and can't help +thinking, just as he can't help plowing and mowing; if he didn't, he +would go to the drink shop or fall ill. Just as I could not stand +his terrible physical labor but should die of it in a week, so he +could not stand my physical idleness, but would grow fat and die. +The third thing--what else was it you talked about?" and Prince Andrew +crooked a third finger. "Ah, yes, hospitals, medicine. He has a fit, +he is dying, and you come and bleed him and patch him up. He will drag +about as a cripple, a burden to everybody, for another ten years. It +would be far easier and simpler for him to die. Others are being +born and there are plenty of them as it is. It would be different if +you grudged losing a laborer--that's how I regard him--but you want to +cure him from love of him. And he does not want that. And besides, +what a notion that medicine ever cured anyone! Killed them, yes!" said +he, frowning angrily and turning away from Pierre. + +Prince Andrew expressed his ideas so clearly and distinctly that +it was evident he had reflected on this subject more than once, and he +spoke readily and rapidly like a man who has not talked for a long +time. His glance became more animated as his conclusions became more +hopeless. + +"Oh, that is dreadful, dreadful!" said Pierre. "I don't understand +how one can live with such ideas. I had such moments myself not long +ago, in Moscow and when traveling, but at such times I collapsed so +that I don't live at all--everything seems hateful to me... myself +most of all. Then I don't eat, don't wash... and how is it with +you?..." + +"Why not wash? That is not cleanly," said Prince Andrew; "on the +contrary one must try to make one's life as pleasant as possible. +I'm alive, that is not my fault, so I must live out my life as best +I can without hurting others." + +"But with such ideas what motive have you for living? One would +sit without moving, undertaking nothing...." + +"Life as it is leaves one no peace. I should be thankful to do +nothing, but here on the one hand the local nobility have done me +the honor to choose me to be their marshal; it was all I could do to +get out of it. They could not understand that I have not the necessary +qualifications for it--the kind of good-natured, fussy shallowness +necessary for the position. Then there's this house, which must be +built in order to have a nook of one's own in which to be quiet. And +now there's this recruiting." + +"Why aren't you serving in the army?" + +"After Austerlitz!" said Prince Andrew gloomily. "No, thank you very +much! I have promised myself not to serve again in the active +Russian army. And I won't--not even if Bonaparte were here at Smolensk +threatening Bald Hills--even then I wouldn't serve in the Russian +army! Well, as I was saying," he continued, recovering his +composure, "now there's this recruiting. My father is chief in command +of the Third District, and my only way of avoiding active service is +to serve under him." + +"Then you are serving?" + +"I am." + +He paused a little while. + +"And why do you serve?" + +"Why, for this reason! My father is one of the most remarkable men +of his time. But he is growing old, and though not exactly cruel he +has too energetic a character. He is so accustomed to unlimited +power that he is terrible, and now he has this authority of a +commander in chief of the recruiting, granted by the Emperor. If I had +been two hours late a fortnight ago he would have had a paymaster's +clerk at Yukhnovna hanged," said Prince Andrew with a smile. "So I +am serving because I alone have any influence with my father, and +now and then can save him from actions which would torment him +afterwards." + +"Well, there you see!" + +"Yes, but it is not as you imagine," Prince Andrew continued. "I did +not, and do not, in the least care about that scoundrel of a clerk who +had stolen some boots from the recruits; I should even have been +very glad to see him hanged, but I was sorry for my father--that again +is for myself." + +Prince Andrew grew more and more animated. His eyes glittered +feverishly while he tried to prove to Pierre that in his actions there +was no desire to do good to his neighbor. + +"There now, you wish to liberate your serfs," he continued; "that is +a very good thing, but not for you--I don't suppose you ever had +anyone flogged or sent to Siberia--and still less for your serfs. If +they are beaten, flogged, or sent to Siberia, I don't suppose they are +any the worse off. In Siberia they lead the same animal life, and +the stripes on their bodies heal, and they are happy as before. But it +is a good thing for proprietors who perish morally, bring remorse upon +themselves, stifle this remorse and grow callous, as a result of being +able to inflict punishments justly and unjustly. It is those people +I pity, and for their sake I should like to liberate the serfs. You +may not have seen, but I have seen, how good men brought up in those +traditions of unlimited power, in time when they grow more +irritable, become cruel and harsh, are conscious of it, but cannot +restrain themselves and grow more and more miserable." + +Prince Andrew spoke so earnestly that Pierre could not help thinking +that these thoughts had been suggested to Prince Andrew by his +father's case. + +He did not reply. + +"So that's what I'm sorry for--human dignity, peace of mind, purity, +and not the serfs' backs and foreheads, which, beat and shave as you +may, always remain the same backs and foreheads." + +"No, no! A thousand times no! I shall never agree with you," said +Pierre. + + + + + +CHAPTER XII + + +In the evening Andrew and Pierre got into the open carriage and +drove to Bald Hills. Prince Andrew, glancing at Pierre, broke the +silence now and then with remarks which showed that he was in a good +temper. + +Pointing to the fields, he spoke of the improvements he was making +in his husbandry. + +Pierre remained gloomily silent, answering in monosyllables and +apparently immersed in his own thoughts. + +He was thinking that Prince Andrew was unhappy, had gone astray, did +not see the true light, and that he, Pierre, ought to aid, +enlighten, and raise him. But as soon as he thought of what he +should say, he felt that Prince Andrew with one word, one argument, +would upset all his teaching, and he shrank from beginning, afraid +of exposing to possible ridicule what to him was precious and sacred. + +"No, but why do you think so?" Pierre suddenly began, lowering his +head and looking like a bull about to charge, "why do you think so? +You should not think so." + +"Think? What about?" asked Prince Andrew with surprise. + +"About life, about man's destiny. It can't be so. I myself thought +like that, and do you know what saved me? Freemasonry! No, don't +smile. Freemasonry is not a religious ceremonial sect, as I thought it +was: Freemasonry is the best expression of the best, the eternal, +aspects of humanity." + +And he began to explain Freemasonry as he understood it to Prince +Andrew. He said that Freemasonry is the teaching of Christianity freed +from the bonds of State and Church, a teaching of equality, +brotherhood, and love. + +"Only our holy brotherhood has the real meaning of life, all the +rest is a dream," said Pierre. "Understand, my dear fellow, that +outside this union all is filled with deceit and falsehood and I agree +with you that nothing is left for an intelligent and good man but to +live out his life, like you, merely trying not to harm others. But +make our fundamental convictions your own, join our brotherhood, +give yourself up to us, let yourself be guided, and you will at once +feel yourself, as I have felt myself, a part of that vast invisible +chain the beginning of which is hidden in heaven," said Pierre. + +Prince Andrew, looking straight in front of him, listened in silence +to Pierre's words. More than once, when the noise of the wheels +prevented his catching what Pierre said, he asked him to repeat it, +and by the peculiar glow that came into Prince Andrew's eyes and by +his silence, Pierre saw that his words were not in vain and that +Prince Andrew would not interrupt him or laugh at what he said. + +They reached a river that had overflowed its banks and which they +had to cross by ferry. While the carriage and horses were being placed +on it, they also stepped on the raft. + +Prince Andrew, leaning his arms on the raft railing, gazed +silently at the flooding waters glittering in the setting sun. + +"Well, what do you think about it?" Pierre asked. "Why are you +silent?" + +"What do I think about it? I am listening to you. It's all very +well.... You say: join our brotherhood and we will show you the aim of +life, the destiny of man, and the laws which govern the world. But who +are we? Men. How is it you know everything? Why do I alone not see +what you see? You see a reign of goodness and truth on earth, but I +don't see it." + +Pierre interrupted him. + +"Do you believe in a future life?" he asked. + +"A future life?" Prince Andrew repeated, but Pierre, giving him no +time to reply, took the repetition for a denial, the more readily as +he knew Prince Andrew's former atheistic convictions. + +"You say you can't see a reign of goodness and truth on earth. Nor +could I, and it cannot be seen if one looks on our life here as the +end of everything. On earth, here on this earth" (Pierre pointed to +the fields), "there is no truth, all is false and evil; but in the +universe, in the whole universe there is a kingdom of truth, and we +who are now the children of earth are--eternally--children of the +whole universe. Don't I feel in my soul that I am part of this vast +harmonious whole? Don't I feel that I form one link, one step, between +the lower and higher beings, in this vast harmonious multitude of +beings in whom the Deity--the Supreme Power if you prefer the term--is +manifest? If I see, clearly see, that ladder leading from plant to +man, why should I suppose it breaks off at me and does not go +farther and farther? I feel that I cannot vanish, since nothing +vanishes in this world, but that I shall always exist and always +have existed. I feel that beyond me and above me there are spirits, +and that in this world there is truth." + +"Yes, that is Herder's theory," said Prince Andrew, "but it is not +that which can convince me, dear friend--life and death are what +convince. What convinces is when one sees a being dear to one, bound +up with one's own life, before whom one was to blame and had hoped +to make it right" (Prince Andrew's voice trembled and he turned away), +"and suddenly that being is seized with pain, suffers, and ceases to +exist.... Why? It cannot be that there is no answer. And I believe +there is.... That's what convinces, that is what has convinced me," +said Prince Andrew. + +"Yes, yes, of course," said Pierre, "isn't that what I'm saying?" + +"No. All I say is that it is not argument that convinces me of the +necessity of a future life, but this: when you go hand in hand with +someone and all at once that person vanishes there, into nowhere, +and you yourself are left facing that abyss, and look in. And I have +looked in...." + +"Well, that's it then! You know that there is a there and there is a +Someone? There is the future life. The Someone is--God." + +Prince Andrew did not reply. The carriage and horses had long +since been taken off, onto the farther bank, and reharnessed. The +sun had sunk half below the horizon and an evening frost was +starring the puddles near the ferry, but Pierre and Andrew, to the +astonishment of the footmen, coachmen, and ferrymen, still stood on +the raft and talked. + +"If there is a God and future life, there is truth and good, and +man's highest happiness consists in striving to attain them. We must +live, we must love, and we must believe that we live not only today on +this scrap of earth, but have lived and shall live forever, there, +in the Whole," said Pierre, and he pointed to the sky. + +Prince Andrew stood leaning on the railing of the raft listening +to Pierre, and he gazed with his eyes fixed on the red reflection of +the sun gleaming on the blue waters. There was perfect stillness. +Pierre became silent. The raft had long since stopped and only the +waves of the current beat softly against it below. Prince Andrew +felt as if the sound of the waves kept up a refrain to Pierre's words, +whispering: + +"It is true, believe it." + +He sighed, and glanced with a radiant, childlike, tender look at +Pierre's face, flushed and rapturous, but yet shy before his +superior friend. + +"Yes, if it only were so!" said Prince Andrew. "However, it is +time to get on," he added, and, stepping off the raft, he looked up at +the sky to which Pierre had pointed, and for the first time since +Austerlitz saw that high, everlasting sky he had seen while lying on +that battlefield; and something that had long been slumbering, +something that was best within him, suddenly awoke, joyful and +youthful, in his soul. It vanished as soon as he returned to the +customary conditions of his life, but he knew that this feeling +which he did not know how to develop existed within him. His meeting +with Pierre formed an epoch in Prince Andrew's life. Though +outwardly he continued to live in the same old way, inwardly he +began a new life. + + + + + +CHAPTER XIII + + +It was getting dusk when Prince Andrew and Pierre drove up to the +front entrance of the house at Bald Hills. As they approached the +house, Prince Andrew with a smile drew Pierre's attention to a +commotion going on at the back porch. A woman, bent with age, with a +wallet on her back, and a short, long-haired, young man in a black +garment had rushed back to the gate on seeing the carriage driving up. +Two women ran out after them, and all four, looking round at the +carriage, ran in dismay up the steps of the back porch. + +"Those are Mary's 'God's folk,'" said Prince Andrew. "They have +mistaken us for my father. This is the one matter in which she +disobeys him. He orders these pilgrims to be driven away, but she +receives them." + +"But what are 'God's folk'?" asked Pierre. + +Prince Andrew had no time to answer. The servants came out to meet +them, and he asked where the old prince was and whether he was +expected back soon. + +The old prince had gone to the town and was expected back any +minute. + +Prince Andrew led Pierre to his own apartments, which were always +kept in perfect order and readiness for him in his father's house; +he himself went to the nursery. + +"Let us go and see my sister," he said to Pierre when he returned. +"I have not found her yet, she is hiding now, sitting with her +'God's folk.' It will serve her right, she will be confused, but you +will see her 'God's folk.' It's really very curious." + +"What are 'God's folk'?" asked Pierre. + +"Come, and you'll see for yourself." + +Princess Mary really was disconcerted and red patches came on her +face when they went in. In her snug room, with lamps burning before +the icon stand, a young lad with a long nose and long hair, wearing +a monk's cassock, sat on the sofa beside her, behind a samovar. Near +them, in an armchair, sat a thin, shriveled, old woman, with a meek +expression on her childlike face. + +"Andrew, why didn't you warn me?" said the princess, with mild +reproach, as she stood before her pilgrims like a hen before her +chickens. + +"Charmee de vous voir. Je suis tres contente de vous voir,"* she +said to Pierre as he kissed her hand. She had known him as a child, +and now his friendship with Andrew, his misfortune with his wife, +and above all his kindly, simple face disposed her favorably toward +him. She looked at him with her beautiful radiant eyes and seemed to +say, "I like you very much, but please don't laugh at my people." +After exchanging the first greetings, they sat down. + + +*"Delighted to see you. I am very glad to see you." + + +"Ah, and Ivanushka is here too!" said Prince Andrew, glancing with a +smile at the young pilgrim. + +"Andrew!" said Princess Mary, imploringly. "Il faut que vous sachiez +que c'est une femme,"* said Prince Andrew to Pierre. + +"Andrew, au nom de Dieu!"*[2] Princess Mary repeated. + + +*"You must know that this is a woman." + +*[2] "For heaven's sake." + + +It was evident that Prince Andrew's ironical tone toward the +pilgrims and Princess Mary's helpless attempts to protect them were +their customary long-established relations on the matter. + +"Mais, ma bonne amie," said Prince Andrew, "vous devriez au +contraire m'etre reconnaissante de ce que j'explique a Pierre votre +intimite avec ce jeune homme."* + + +*"But, my dear, you ought on the contrary to be grateful to me for +explaining to Pierre your intimacy with this young man." + + +"Really?" said Pierre, gazing over his spectacles with curiosity and +seriousness (for which Princess Mary was specially grateful to him) +into Ivanushka's face, who, seeing that she was being spoken about, +looked round at them all with crafty eyes. + +Princess Mary's embarrassment on her people's account was quite +unnecessary. They were not in the least abashed. The old woman, +lowering her eyes but casting side glances at the newcomers, had +turned her cup upside down and placed a nibbled bit of sugar beside +it, and sat quietly in her armchair, though hoping to be offered +another cup of tea. Ivanushka, sipping out of her saucer, looked +with sly womanish eyes from under her brows at the young men. + +"Where have you been? To Kiev?" Prince Andrew asked the old woman. + +"I have, good sir," she answered garrulously. "Just at Christmastime +I was deemed worthy to partake of the holy and heavenly sacrament at +the shrine of the saint. And now I'm from Kolyazin, master, where a +great and wonderful blessing has been revealed." + +"And was Ivanushka with you?" + +"I go by myself, benefactor," said Ivanushka, trying to speak in a +bass voice. "I only came across Pelageya in Yukhnovo..." + +Pelageya interrupted her companion; she evidently wished to tell +what she had seen. + +"In Kolyazin, master, a wonderful blessing has been revealed." + +"What is it? Some new relics?" asked Prince Andrew. + +"Andrew, do leave off," said Princess Mary. "Don't tell him, +Pelageya." + +"No... why not, my dear, why shouldn't I? I like him. He is kind, he +is one of God's chosen, he's a benefactor, he once gave me ten rubles, +I remember. When I was in Kiev, Crazy Cyril says to me (he's one of +God's own and goes barefoot summer and winter), he says, 'Why are +you not going to the right place? Go to Kolyazin where a +wonder-working icon of the Holy Mother of God has been revealed.' On +hearing those words I said good-by to the holy folk and went." + +All were silent, only the pilgrim woman went on in measured tones, +drawing in her breath. + +"So I come, master, and the people say to me: 'A great blessing +has been revealed, holy oil trickles from the cheeks of our blessed +Mother, the Holy Virgin Mother of God'...." + +"All right, all right, you can tell us afterwards," said Princess +Mary, flushing. + +"Let me ask her," said Pierre. "Did you see it yourselves?" he +inquired. + +"Oh, yes, master, I was found worthy. Such a brightness on the +face like the light of heaven, and from the blessed Mother's cheek +it drops and drops...." + +"But, dear me, that must be a fraud!" said Pierre, naively, who +had listened attentively to the pilgrim. + +"Oh, master, what are you saying?" exclaimed the horrified Pelageya, +turning to Princess Mary for support. + +"They impose on the people," he repeated. + +"Lord Jesus Christ!" exclaimed the pilgrim woman, crossing +herself. "Oh, don't speak so, master! There was a general who did +not believe, and said, 'The monks cheat,' and as soon as he'd said +it he went blind. And he dreamed that the Holy Virgin Mother of the +Kiev catacombs came to him and said, 'Believe in me and I will make +you whole.' So he begged: 'Take me to her, take me to her.' It's the +real truth I'm telling you, I saw it myself. So he was brought, +quite blind, straight to her, and he goes up to her and falls down and +says, 'Make me whole,' says he, 'and I'll give thee what the Tsar +bestowed on me.' I saw it myself, master, the star is fixed into the +icon. Well, and what do you think? He received his sight! It's a sin +to speak so. God will punish you," she said admonishingly, turning +to Pierre. + +"How did the star get into the icon?" Pierre asked. + +"And was the Holy Mother promoted to the rank of general?" said +Prince Andrew, with a smile. + +Pelageya suddenly grew quite pale and clasped her hands. + +"Oh, master, master, what a sin! And you who have a son!" she began, +her pallor suddenly turning to a vivid red. "Master, what have you +said? God forgive you!" And she crossed herself. "Lord forgive him! My +dear, what does it mean?..." she asked, turning to Princess Mary. +She got up and, almost crying, began to arrange her wallet. She +evidently felt frightened and ashamed to have accepted charity in a +house where such things could be said, and was at the same time +sorry to have now to forgo the charity of this house. + +"Now, why need you do it?" said Princess Mary. "Why did you come +to me?..." + +"Come, Pelageya, I was joking," said Pierre. "Princesse, ma +parole, je n'ai pas voulu l'offenser.* I did not mean anything, I +was only joking," he said, smiling shyly and trying to efface his +offense. "It was all my fault, and Andrew was only joking." + + +*"Princess, on my word, I did not wish to offend her." + + +Pelageya stopped doubtfully, but in Pierre's face there was such a +look of sincere penitence, and Prince Andrew glanced so meekly now +at her and now at Pierre, that she was gradually reassured. + + + + + +CHAPTER XIV + + +The pilgrim woman was appeased and, being encouraged to talk, gave a +long account of Father Amphilochus, who led so holy a life that his +hands smelled of incense, and how on her last visit to Kiev some monks +she knew let her have the keys of the catacombs, and how she, taking +some dried bread with her, had spent two days in the catacombs with +the saints. "I'd pray awhile to one, ponder awhile, then go on to +another. I'd sleep a bit and then again go and kiss the relics, and +there was such peace all around, such blessedness, that one don't want +to come out, even into the light of heaven again." + +Pierre listened to her attentively and seriously. Prince Andrew went +out of the room, and then, leaving "God's folk" to finish their tea, +Princess Mary took Pierre into the drawing room. + +"You are very kind," she said to him. + +"Oh, I really did not mean to hurt her feelings. I understand them +so well and have the greatest respect for them." + +Princess Mary looked at him silently and smiled affectionately. + +"I have known you a long time, you see, and am as fond of you as +of a brother," she said. "How do you find Andrew?" she added +hurriedly, not giving him time to reply to her affectionate words. +"I am very anxious about him. His health was better in the winter, but +last spring his wound reopened and the doctor said he ought to go away +for a cure. And I am also very much afraid for him spiritually. He has +not a character like us women who, when we suffer, can weep away our +sorrows. He keeps it all within him. Today he is cheerful and in +good spirits, but that is the effect of your visit--he is not often +like that. If you could persuade him to go abroad. He needs +activity, and this quiet regular life is very bad for him. Others +don't notice it, but I see it." + +Toward ten o'clock the men servants rushed to the front door, +hearing the bells of the old prince's carriage approaching. Prince +Andrew and Pierre also went out into the porch. + +"Who's that?" asked the old prince, noticing Pierre as he got out +of, the carriage. + +"Ah! Very glad! Kiss me," he said, having learned who the young +stranger was. + +The old prince was in a good temper and very gracious to Pierre. + +Before supper, Prince Andrew, coming back to his father's study, +found him disputing hotly with his visitor. Pierre was maintaining +that a time would come when there would be no more wars. The old +prince disputed it chaffingly, but without getting angry. + +"Drain the blood from men's veins and put in water instead, then +there will be no more war! Old women's nonsense--old women's +nonsense!" he repeated, but still he patted Pierre affectionately on +the shoulder, and then went up to the table where Prince Andrew, +evidently not wishing to join in the conversation, was looking over +the papers his father had brought from town. The old prince went up to +him and began to talk business. + +"The marshal, a Count Rostov, hasn't sent half his contingent. He +came to town and wanted to invite me to dinner--I gave him a pretty +dinner!... And there, look at this.... Well, my boy," the old prince +went on, addressing his son and patting Pierre on the shoulder. "A +fine fellow--your friend--I like him! He stirs me up. Another says +clever things and one doesn't care to listen, but this one talks +rubbish yet stirs an old fellow up. Well, go! Get along! Perhaps +I'll come and sit with you at supper. We'll have another dispute. Make +friends with my little fool, Princess Mary," he shouted after +Pierre, through the door. + +Only now, on his visit to Bald Hills, did Pierre fully realize the +strength and charm of his friendship with Prince Andrew. That charm +was not expressed so much in his relations with him as with all his +family and with the household. With the stern old prince and the +gentle, timid Princess Mary, though he had scarcely known them, Pierre +at once felt like an old friend. They were all fond of him already. +Not only Princess Mary, who had been won by his gentleness with the +pilgrims, gave him her most radiant looks, but even the one-year-old +"Prince Nicholas" (as his grandfather called him) smiled at Pierre and +let himself be taken in his arms, and Michael Ivanovich and +Mademoiselle Bourienne looked at him with pleasant smiles when he +talked to the old prince. + +The old prince came in to supper; this was evidently on Pierre's +account. And during the two days of the young man's visit he was +extremely kind to him and told him to visit them again. + +When Pierre had gone and the members of the household met +together, they began to express their opinions of him as people always +do after a new acquaintance has left, but as seldom happens, no one +said anything but what was good of him. + + + + + +CHAPTER XV + + +When returning from his leave, Rostov felt, for the first time, +how close was the bond that united him to Denisov and and the whole +regiment. + +On approaching it, Rostov felt as he had done when approaching his +home in Moscow. When he saw the first hussar with the unbuttoned +uniform of his regiment, when he recognized red-haired Dementyev and +saw the picket ropes of the roan horses, when Lavrushka gleefully +shouted to his master, "The count has come!" and Denisov, who had been +asleep on his bed, ran all disheveled out of the mud hut to embrace +him, and the officers collected round to greet the new arrival, Rostov +experienced the same feeling his mother, his father, and his sister +had embraced him, and tears of joy choked him so that he could not +speak. The regiment was also a home, and as unalterably dear and +precious as his parents' house. + +When he had reported himself to the commander of the regiment and +had been reassigned to his former squadron, had been on duty and had +gone out foraging, when he had again entered into all the little +interests of the regiment and felt himself deprived of liberty and +bound in one narrow, unchanging frame, he experienced the same sense +of peace, of moral support, and the same sense being at home here in +his own place, as he had felt under the parental roof. But here was +none of all that turmoil of the world at large, where he did not +know his right place and took mistaken decisions; here was no Sonya +with whom he ought, or ought not, to have an explanation; here was +no possibility of going there or not going there; here there were +not twenty-four hours in the day which could be spent in such a +variety of ways; there was not that innumerable crowd of people of +whom not one was nearer to him or farther from him than another; there +were none of those uncertain and undefined money relations with his +father, and nothing to recall that terrible loss to Dolokhov. Here, in +the regiment, all was clear and simple. The whole world was divided +into two unequal parts: one, our Pavlograd regiment; the other, all +the rest. And the rest was no concern of his. In the regiment, +everything was definite: who was lieutenant, who captain, who was a +good fellow, who a bad one, and most of all, who was a comrade. The +canteenkeeper gave one credit, one's pay came every four months, there +was nothing to think out or decide, you had only to do nothing that +was considered bad in the Pavlograd regiment and, when given an order, +to do what was clearly, distinctly, and definitely ordered--and all +would be well. + +Having once more entered into the definite conditions of this +regimental life, Rostov felt the joy and relief a tired man feels on +lying down to rest. Life in the regiment, during this campaign, was +all the pleasanter for him, because, after his loss to Dolokhov (for +which, in spite of all his family's efforts to console him, he could +not forgive himself), he had made up his mind to atone for his fault +by serving, not as he had done before, but really well, and by being a +perfectly first-rate comrade and officer--in a word, a splendid man +altogether, a thing which seemed so difficult out in the world, but so +possible in the regiment. + +After his losses, he had determined to pay back his debt to his +parents in five years. He received ten thousand rubles a year, but now +resolved to take only two thousand and leave the rest to repay the +debt to his parents. + +Our army, after repeated retreats and advances and battles at +Pultusk and Preussisch-Eylau, was concentrated near Bartenstein. It +was awaiting the Emperor's arrival and the beginning of a new +campaign. + +The Pavlograd regiment, belonging to that part of the army which had +served in the 1805 campaign, had been recruiting up to strength in +Russia, and arrived too late to take part in the first actions of +the campaign. It had been neither at Pultusk nor at Preussisch-Eylau +and, when it joined the army in the field in the second half of the +campaign, was attached to Platov's division. + +Platov's division was acting independently of the main army. Several +times parts of the Pavlograd regiment had exchanged shots with the +enemy, had taken prisoners, and once had even captured Marshal +Oudinot's carriages. In April the Pavlograds were stationed +immovably for some weeks near a totally ruined and deserted German +village. + +A thaw had set in, it was muddy and cold, the ice on the river +broke, and the roads became impassable. For days neither provisions +for the men nor fodder for the horses had been issued. As no +transports could arrive, the men dispersed about the abandoned and +deserted villages, searching for potatoes, but found few even of +these. + +Everything had been eaten up and the inhabitants had all fled--if +any remained, they were worse than beggars and nothing more could be +taken from them; even the soldiers, usually pitiless enough, instead +of taking anything from them, often gave them the last of their +rations. + +The Pavlograd regiment had had only two men wounded in action, but +had lost nearly half its men from hunger and sickness. In the +hospitals, death was so certain that soldiers suffering from fever, or +the swelling that came from bad food, preferred to remain on duty, and +hardly able to drag their legs went to the front rather than to the +hospitals. When spring came on, the soldiers found a plant just +showing out of the ground that looked like asparagus, which, for +some reason, they called "Mashka's sweet root." It was very bitter, +but they wandered about the fields seeking it and dug it out with +their sabers and ate it, though they were ordered not to do so, as +it was a noxious plant. That spring a new disease broke +out among the soldiers, a swelling of the arms, legs, and face, +which the doctors attributed to eating this root. But in spite of +all this, the soldiers of Denisov's squadron fed chiefly on +"Mashka's sweet root," because it was the second week that the last of +the biscuits were being doled out at the rate of half a pound a man +and the last potatoes received had sprouted and frozen. + +The horses also had been fed for a fortnight on straw from the +thatched roofs and had become terribly thin, though still covered with +tufts of felty winter hair. + +Despite this destitution, the soldiers and officers went on living +just as usual. Despite their pale swollen faces and tattered uniforms, +the hussars formed line for roll call, kept things in order, groomed +their horses, polished their arms, brought in straw from the +thatched roofs in place of fodder, and sat down to dine round the +caldrons from which they rose up hungry, joking about their nasty food +and their hunger. As usual, in their spare time, they lit bonfires, +steamed themselves before them naked; smoked, picked out and baked +sprouting rotten potatoes, told and listened to stories of +Potemkin's and Suvorov's campaigns, or to legends of Alesha the Sly, +or the priest's laborer Mikolka. + +The officers, as usual, lived in twos and threes in the roofless, +half-ruined houses. The seniors tried to collect straw and potatoes +and, in general, food for the men. The younger ones occupied +themselves as before, some playing cards (there was plenty of money, +though there was no food), some with more innocent games, such as +quoits and skittles. The general trend of the campaign was rarely +spoken of, partly because nothing certain was known about it, partly +because there was a vague feeling that in the main it was going badly. + +Rostov lived, as before, with Denisov, and since their furlough they +had become more friendly than ever. Denisov never spoke of Rostov's +family, but by the tender friendship his commander showed him, +Rostov felt that the elder hussar's luckless love for Natasha played a +part in strengthening their friendship. Denisov evidently tried to +expose Rostov to danger as seldom as possible, and after an action +greeted his safe return with evident joy. On one of his foraging +expeditions, in a deserted and ruined village to which he had come +in search of provisions, Rostov found a family consisting of an old +Pole and his daughter with an infant in arms. They were half clad, +hungry, too weak to get away on foot and had no means of obtaining a +conveyance. Rostov brought them to his quarters, placed them in his +own lodging, and kept them for some weeks while the old man was +recovering. One of his comrades, talking of women, began chaffing +Rostov, saying that he was more wily than any of them and that it +would not be a bad thing if he introduced to them the pretty Polish +girl he had saved. Rostov took the joke as an insult, flared up, and +said such unpleasant things to the officer that it was all Denisov +could do to prevent a duel. When the officer had gone away, Denisov, +who did not himself know what Rostov's relations with the Polish +girl might be, began to upbraid him for his quickness of temper, and +Rostov replied: + +"Say what you like.... She is like a sister to me, and I can't +tell you how it offended me... because... well, for that reason...." + +Denisov patted him on the shoulder and began rapidly pacing the room +without looking at Rostov, as was his way at moments of deep feeling. + +"Ah, what a mad bweed you Wostovs are!" he muttered, and Rostov +noticed tears in his eyes. + + + + + +CHAPTER XVI + + +In April the troops were enlivened by news of the Emperor's arrival, +but Rostov had no chance of being present at the review he held at +Bartenstein, as the Pavlograds were at the outposts far beyond that +place. + +They were bivouacking. Denisov and Rostov were living in an earth +hut, dug out for them by the soldiers and roofed with branches and +turf. The hut was made in the following manner, which had then come +into vogue. A trench was dug three and a half feet wide, four feet +eight inches deep, and eight feet long. At one end of the trench, +steps were cut out and these formed the entrance and vestibule. The +trench itself was the room, in which the lucky ones, such as the +squadron commander, had a board, lying on piles at the end opposite +the entrance, to serve as a table. On each side of the trench, the +earth was cut out to a breadth of about two and a half feet, and +this did duty for bedsteads and couches. The roof was so constructed +that one could stand up in the middle of the trench and could even sit +up on the beds if one drew close to the table. Denisov, who was living +luxuriously because the soldiers of his squadron liked him, had also a +board in the roof at the farther end, with a piece of (broken but +mended) glass in it for a window. When it was very cold, embers from +the soldiers' campfire were placed on a bent sheet of iron on the +steps in the "reception room"--as Denisov called that part of the hut- +and it was then so warm that the officers, of whom there were always +some with Denisov and Rostov, sat in their shirt sleeves. + +In April, Rostov was on orderly duty. One morning, between seven and +eight, returning after a sleepless night, he sent for embers, +changed his rain-soaked underclothes, said his prayers, drank tea, got +warm, then tidied up the things on the table and in his own corner, +and, his face glowing from exposure to the wind and with nothing on +but his shirt, lay down on his back, putting his arms under his +head. He was pleasantly considering the probability of being +promoted in a few days for his last reconnoitering expedition, and +was awaiting Denisov, who had gone out somewhere and with whom he +wanted a talk. + +Suddenly he heard Denisov shouting in a vibrating voice behind the +hut, evidently much excited. Rostov moved to the window to see whom he +was speaking to, and saw the quartermaster, Topcheenko. + +"I ordered you not to let them eat that Mashka woot stuff!" Denisov +was shouting. "And I saw with my own eyes how Lazarchuk bwought some +fwom the fields." + +"I have given the order again and again, your honor, but they +don't obey," answered the quartermaster. + +Rostov lay down again on his bed and thought complacently: "Let +him fuss and bustle now, my job's done and I'm lying down--capitally!" +He could hear that Lavrushka--that sly, bold orderly of Denisov's--was +talking, as well as the quartermaster. Lavrushka was saying +something about loaded wagons, biscuits, and oxen he had seen when +he had gone out for provisions. + +Then Denisov's voice was heard shouting farther and farther away. +"Saddle! Second platoon!" + +"Where are they off to now?" thought Rostov. + +Five minutes later, Denisov came into the hut, climbed with muddy +boots on the bed, lit his pipe, furiously scattered his things +about, took his leaded whip, buckled on his saber, and went out again. +In answer to Rostov's inquiry where he was going, he answered +vaguely and crossly that he had some business. + +"Let God and our gweat monarch judge me afterwards!" said Denisov +going out, and Rostov heard the hoofs of several horses splashing +through the mud. He did not even trouble to find out where Denisov had +gone. Having got warm in his corner, he fell asleep and did not +leave the hut till toward evening. Denisov had not yet returned. The +weather had cleared up, and near the next hut two officers and a cadet +were playing svayka, laughing as they threw their missiles which +buried themselves in the soft mud. Rostov joined them. In the middle +of the game, the officers saw some wagons approaching with fifteen +hussars on their skinny horses behind them. The wagons escorted by the +hussars drew up to the picket ropes and a crowd of hussars +surrounded them. + +"There now, Denisov has been worrying," said Rostov, "and here are +the provisions." + +"So they are!" said the officers. "Won't the soldiers be glad!" + +A little behind the hussars came Denisov, accompanied by two +infantry officers with whom he was talking. + +Rostov went to meet them. + +"I warn you, Captain," one of the officers, a short thin man, + +evidently very angry, was saying. + +"Haven't I told you I won't give them up?" replied Denisov. + +"You will answer for it, Captain. It is mutiny--seizing the +transport of one's own army. Our men have had nothing to eat for two +days." + +"And mine have had nothing for two weeks," said Denisov. + +"It is robbery! You'll answer for it, sir!" said the infantry +officer, raising his voice. + +"Now, what are you pestewing me for?" cried Denisov, suddenly losing +his temper. "I shall answer for it and not you, and you'd better not +buzz about here till you get hurt. Be off! Go!" he shouted at the +officers. + +"Very well, then!" shouted the little officer, undaunted and not +riding away. "If you are determined to rob, I'll..." + +"Go to the devil! quick ma'ch, while you're safe and sound!" and +Denisov turned his horse on the officer. + +"Very well, very well!" muttered the officer, threateningly, and +turning his horse he trotted away, jolting in his saddle. + +"A dog astwide a fence! A weal dog astwide a fence!" shouted Denisov +after him (the most insulting expression a cavalryman can address to a +mounted infantryman) and riding up to Rostov, he burst out laughing. + +"I've taken twansports from the infantwy by force!" he said. +"After all, can't let our men starve." + +The wagons that had reached the hussars had been consigned to an +infantry regiment, but learning from Lavrushka that the transport +was unescorted, Denisov with his hussars had seized it by force. The +soldiers had biscuits dealt out to them freely, and they even shared +them with the other squadrons. + +The next day the regimental commander sent for Denisov, and +holding his fingers spread out before his eyes said: + +"This is how I look at this affair: I know nothing about it and +won't begin proceedings, but I advise you to ride over to the staff +and settle the business there in the commissariat department and if +possible sign a receipt for such and such stores received. If not, +as the demand was booked against an infantry regiment, there will be a +row and the affair may end badly." + +From the regimental commander's, Denisov rode straight to the +staff with a sincere desire to act on this advice. In the evening he +came back to his dugout in a state such as Rostov had never yet seen +him in. Denisov could not speak and gasped for breath. When Rostov +asked what was the matter, he only uttered some incoherent oaths and +threats in a hoarse, feeble voice. + +Alarmed at Denisov's condition, Rostov suggested that he should +undress, drink some water, and send for the doctor. + +"Twy me for wobbewy... oh! Some more water... Let them twy me, but +I'll always thwash scoundwels... and I'll tell the Empewo'... +Ice..." he muttered. + +The regimental doctor, when he came, said it was absolutely +necessary to bleed Denisov. A deep saucer of black blood was taken +from his hairy arm and only then was he able to relate what had +happened to him. + +"I get there," began Denisov. "'Now then, where's your chief's +quarters?' They were pointed out. 'Please to wait.' 'I've widden +twenty miles and have duties to attend to and no time to wait. +Announce me.' Vewy well, so out comes their head chief--also took it +into his head to lecture me: 'It's wobbewy!'--'Wobbewy,' I say, 'is +not done by man who seizes pwovisions to feed his soldiers, but by him +who takes them to fill his own pockets!' 'Will you please be +silent?' 'Vewy good!' Then he says: 'Go and give a weceipt to the +commissioner, but your affair will be passed on to headquarters.' I go +to the commissioner. I enter, and at the table... who do you think? +No, but wait a bit!... Who is it that's starving us?" shouted Denisov, +hitting the table with the fist of his newly bled arm so violently +that the table nearly broke down and the tumblers on it jumped +about. "Telyanin! 'What? So it's you who's starving us to death! Is +it? Take this and this!' and I hit him so pat, stwaight on his +snout... 'Ah, what a... what...!' and I sta'ted fwashing him... +Well, I've had a bit of fun I can tell you!" cried Denisov, gleeful +and yet angry, his showing under his black mustache. "I'd have +killed him if they hadn't taken him away!" + +"But what are you shouting for? Calm yourself," said Rostov. "You've +set your arm bleeding afresh. Wait, we must tie it up again." + +Denisov was bandaged up again and put to bed. Next day he woke +calm and cheerful. + +But at noon the adjutant of the regiment came into Rostov's and +Denisov's dugout with a grave and serious face and regretfully +showed them a paper addressed to Major Denisov from the regimental +commander in which inquiries were made about yesterday's occurrence. +The adjutant told them that the affair was likely to take a very bad +turn: that a court-martial had been appointed, and that in view of the +severity with which marauding and insubordination were now regarded, +degradation to the ranks would be the best that could be hoped for. + +The case, as represented by the offended parties, was that, after +seizing the transports, Major Denisov, being drunk, went to the +chief quartermaster and without any provocation called him a thief, +threatened to strike him, and on being led out had rushed into the +office and given two officials a thrashing, and dislocated the arm +of one of them. + +In answer to Rostov's renewed questions, Denisov said, laughing, +that he thought he remembered that some other fellow had got mixed +up in it, but that it was all nonsense and rubbish, and he did not +in the least fear any kind of trial, and that if those scoundrels +dared attack him he would give them an answer that they would not +easily forget. + +Denisov spoke contemptuously of the whole matter, but Rostov knew +him too well not to detect that (while hiding it from others) at heart +he feared a court-martial and was worried over the affair, which was +evidently taking a bad turn. Every day, letters of inquiry and notices +from the court arrived, and on the first of May, Denisov was ordered +to hand the squadron over to the next in seniority and appear before +the staff of his division to explain his violence at the +commissariat office. On the previous day Platov reconnoitered with two +Cossack regiments and two squadrons of hussars. Denisov, as was his +wont, rode out in front of the outposts, parading his courage. A +bullet fired by a French sharpshooter hit him in the fleshy part of +his leg. Perhaps at another time Denisov would not have left the +regiment for so slight a wound, but now he took advantage of it to +excuse himself from appearing at the staff and went into hospital. + + + + + +CHAPTER XVII + + +In June the battle of Friedland was fought, in which the +Pavlograds did not take part, and after that an armistice was +proclaimed. Rostov, who felt his friend's absence very much, having no +news of him since he left and feeling very anxious about his wound and +the progress of his affairs, took advantage of the armistice to get +leave to visit Denisov in hospital. + +The hospital was in a small Prussian town that had been twice +devastated by Russian and French troops. Because it was summer, when +it is so beautiful out in the fields, the little town presented a +particularly dismal appearance with its broken roofs and fences, its +foul streets, tattered inhabitants, and the sick and drunken +soldiers wandering about. + +The hospital was in a brick building with some of the window +frames and panes broken and a courtyard surrounded by the remains of a +wooden fence that had been pulled to pieces. Several bandaged +soldiers, with pale swollen faces, were sitting or walking about in +the sunshine in the yard. + +Directly Rostov entered the door he was enveloped by a smell of +putrefaction and hospital air. On the stairs he met a Russian army +doctor smoking a cigar. The doctor was followed by a Russian +assistant. + +"I can't tear myself to pieces," the doctor was saying. "Come to +Makar Alexeevich in the evening. I shall be there." + +The assistant asked some further questions. + +"Oh, do the best you can! Isn't it all the same?" The doctor noticed +Rostov coming upstairs. + +"What do you want, sir?" said the doctor. "What do you want? The +bullets having spared you, do you want to try typhus? This is a +pesthouse, sir." + +"How so?" asked Rostov. + +"Typhus, sir. It's death to go in. Only we two, Makeev and I" (he +pointed to the assistant), "keep on here. Some five of us doctors have +died in this place.... When a new one comes he is done for in a week," +said the doctor with evident satisfaction. "Prussian doctors have been +invited here, but our allies don't like it at all." + +Rostov explained that he wanted to see Major Denisov of the hussars, +who was wounded. + +"I don't know. I can't tell you, sir. Only think! I am alone in +charge of three hospitals with more than four hundred patients! It's +well that the charitable Prussian ladies send us two pounds of +coffee and some lint each month or we should be lost!" he laughed. +"Four hundred, sir, and they're always sending me fresh ones. There +are four hundred? Eh?" he asked, turning to the assistant. + +The assistant looked fagged out. He was evidently vexed and +impatient for the talkative doctor to go. + +"Major Denisov," Rostov said again. "He was wounded at Molliten." + +"Dead, I fancy. Eh, Makeev?" queried the doctor, in a tone of +indifference. + +The assistant, however, did not confirm the doctor's words. + +"Is he tall and with reddish hair?" asked the doctor. + +Rostov described Denisov's appearance. + +"There was one like that," said the doctor, as if pleased. "That one +is dead, I fancy. However, I'll look up our list. We had a list. +Have you got it, Makeev?" + +"Makar Alexeevich has the list," answered the assistant. "But if +you'll step into the officers' wards you'll see for yourself," he +added, turning to Rostov. + +"Ah, you'd better not go, sir," said the doctor, "or you may have to +stay here yourself." + +But Rostov bowed himself away from the doctor and asked the +assistant to show him the way. + +"Only don't blame me!" the doctor shouted up after him. + +Rostov and the assistant went into the dark corridor. The smell +was so strong there that Rostov held his nose and had to pause and +collect his strength before he could go on. A door opened to the +right, and an emaciated sallow man on crutches, barefoot and in +underclothing, limped out and, leaning against the doorpost, looked +with glittering envious eyes at those who were passing. Glancing in at +the door, Rostov saw that the sick and wounded were lying on the floor +on straw and overcoats. + +"May I go in and look?" + +"What is there to see?" said the assistant. + +But, just because the assistant evidently did not want him to go in, +Rostov entered the soldiers' ward. The foul air, to which he had +already begun to get used in the corridor, was still stronger here. It +was a little different, more pungent, and one felt that this was where +it originated. + +In the long room, brightly lit up by the sun through the large +windows, the sick and wounded lay in two rows with their heads to +the walls, and leaving a passage in the middle. Most of them were +unconscious and paid no attention to the newcomers. Those who were +conscious raised themselves or lifted their thin yellow faces, and all +looked intently at Rostov with the same expression of hope, of relief, +reproach, and envy of another's health. Rostov went to the middle of +the room and looking through the open doors into the two adjoining +rooms saw the same thing there. He stood still, looking silently +around. He had not at all expected such a sight. Just before him, +almost across the middle of the passage on the bare floor, lay a +sick man, probably a Cossack to judge by the cut of his hair. The +man lay on his back, his huge arms and legs outstretched. His face was +purple, his eyes were rolled back so that only the whites were seen, +and on his bare legs and arms which were still red, the veins stood +out like cords. He was knocking the back of his head against the +floor, hoarsely uttering some word which he kept repeating. Rostov +listened and made out the word. It was "drink, drink, a drink!" Rostov +glanced round, looking for someone who would put this man back in +his place and bring him water. + +"Who looks after the sick here?" he asked the assistant. + +Just then a commissariat soldier, a hospital orderly, came in from +the next room, marching stiffly, and drew up in front of Rostov. + +"Good day, your honor!" he shouted, rolling his eyes at Rostov and +evidently mistaking him for one of the hospital authorities. + +"Get him to his place and give him some water," said Rostov, +pointing to the Cossack. + +"Yes, your honor," the soldier replied complacently, and rolling his +eyes more than ever he drew himself up still straighter, but did not +move. + +"No, it's impossible to do anything here," thought Rostov, +lowering his eyes, and he was going out, but became aware of an +intense look fixed on him on his right, and he turned. Close to the +corner, on an overcoat, sat an old, unshaven, gray-bearded soldier +as thin as a skeleton, with a stern sallow face and eyes intently +fixed on Rostov. The man's neighbor on one side whispered something to +him, pointing at Rostov, who noticed that the old man wanted to +speak to him. He drew nearer and saw that the old man had only one leg +bent under him, the other had been amputated above the knee. His +neighbor on the other side, who lay motionless some distance from +him with his head thrown back, was a young soldier with a snub nose. +His pale waxen face was still freckled and his eyes were rolled +back. Rostov looked at the young soldier and a cold chill ran down his +back. + +"Why, this one seems..." he began, turning to the assistant. + +"And how we've been begging, your honor," said the old soldier, +his jaw quivering. "He's been dead since morning. After all we're men, +not dogs." + +"I'll send someone at once. He shall be taken away--taken away at +once," said the assistant hurriedly. "Let us go, your honor." + +"Yes, yes, let us go," said Rostov hastily, and lowering his eyes +and shrinking, he tried to pass unnoticed between the rows of +reproachful envious eyes that were fixed upon him, and went out of the +room. + + + + + +CHAPTER XVIII + + +Going along the corridor, the assistant led Rostov to the +officers' wards, consisting of three rooms, the doors of which stood +open. There were beds in these rooms and the sick and wounded officers +were lying or sitting on them. Some were walking about the rooms in +hospital dressing gowns. The first person Rostov met in the +officers' ward was a thin little man with one arm, who was walking +about the first room in a nightcap and hospital dressing gown, with +a pipe between his teeth. Rostov looked at him, trying to remember +where he had seen him before. + +"See where we've met again!" said the little man. "Tushin, Tushin, +don't you remember, who gave you a lift at Schon Grabern? And I've had +a bit cut off, you see..." he went on with a smile, pointing to the +empty sleeve of his dressing gown. "Looking for Vasili Dmitrich +Denisov? My neighbor," he added, when he heard who Rostov wanted. +"Here, here," and Tushin led him into the next room, from whence +came sounds of several laughing voices. + +"How can they laugh, or even live at all here?" thought Rostov, +still aware of that smell of decomposing flesh that had been so strong +in the soldiers' ward, and still seeming to see fixed on him those +envious looks which had followed him out from both sides, and the face +of that young soldier with eyes rolled back. + +Denisov lay asleep on his bed with his head under the blanket, +though it was nearly noon. + +"Ah, Wostov? How are you, how are you?" he called out, still in +the same voice as in the regiment, but Rostov noticed sadly that under +this habitual ease and animation some new, sinister, hidden feeling +showed itself in the expression of Denisov's face and the +intonations of his voice. + +His wound, though a slight one, had not yet healed even now, six +weeks after he had been hit. His face had the same swollen pallor as +the faces of the other hospital patients, but it was not this that +struck Rostov. What struck him was that Denisov did not seem glad to +see him, and smiled at him unnaturally. He did not ask about the +regiment, nor about the general state of affairs, and when Rostov +spoke of these matters did not listen. + +Rostov even noticed that Denisov did not like to be reminded of +the regiment, or in general of that other free life which was going on +outside the hospital. He seemed to try to forget that old life and was +only interested in the affair with the commissariat officers. On +Rostov's inquiry as to how the matter stood, he at once produced +from under his pillow a paper he had received from the commission +and the rough draft of his answer to it. He became animated when he +began reading his paper and specially drew Rostov's attention to the +stinging rejoinders he made to his enemies. His hospital companions, +who had gathered round Rostov--a fresh arrival from the world outside- +gradually began to disperse as soon as Denisov began reading his +answer. Rostov noticed by their faces that all those gentlemen had +already heard that story more than once and were tired of it. Only the +man who had the next bed, a stout Uhlan, continued to sit on his +bed, gloomily frowning and smoking a pipe, and little one-armed Tushin +still listened, shaking his head disapprovingly. In the middle of +the reading, the Uhlan interrupted Denisov. + +"But what I say is," he said, turning to Rostov, "it would be best +simply to petition the Emperor for pardon. They say great rewards will +now be distributed, and surely a pardon would be granted...." + +"Me petition the Empewo'!" exclaimed Denisov, in a voice to which he +tried hard to give the old energy and fire, but which sounded like +an expression of irritable impotence. "What for? If I were a wobber +I would ask mercy, but I'm being court-martialed for bwinging +wobbers to book. Let them twy me, I'm not afwaid of anyone. I've +served the Tsar and my countwy honowably and have not stolen! And am I +to be degwaded?... Listen, I'm w'iting to them stwaight. This is +what I say: 'If I had wobbed the Tweasuwy...'" + +"It's certainly well written," said Tushin, "but that's not the +point, Vasili Dmitrich," and he also turned to Rostov. "One has to +submit, and Vasili Dmitrich doesn't want to. You know the auditor told +you it was a bad business." + +"Well, let it be bad," said Denisov. + +"The auditor wrote out a petition for you," continued Tushin, "and +you ought to sign it and ask this gentleman to take it. No doubt he" +(indicating Rostov) "has connections on the staff. You won't find a +better opportunity." + +"Haven't I said I'm not going to gwovel?" Denisov interrupted him, +went on reading his paper. + +Rostov had not the courage to persuade Denisov, though he +instinctively felt that the way advised by Tushin and the other +officers was the safest, and though he would have been glad to be of +service to Denisov. He knew his stubborn will and straightforward +hasty temper. + +When the reading of Denisov's virulent reply, which took more than +an hour, was over, Rostov said nothing, and he spent the rest of the +day in a most dejected state of mind amid Denisov's hospital comrades, +who had round him, telling them what he knew and listening to their +stories. Denisov was moodily silent all the evening. + +Late in the evening, when Rostov was about to leave, he asked +Denisov whether he had no commission for him. + +"Yes, wait a bit," said Denisov, glancing round at the officers, and +taking his papers from under his pillow he went to the window, where +he had an inkpot, and sat down to write. + +"It seems it's no use knocking one's head against a wall!" he +said, coming from the window and giving Rostov a large envelope. In it +was the petition to the Emperor drawn up by the auditor, in which +Denisov, without alluding to the offenses of the commissariat +officials, simply asked for pardon. + +"Hand it in. It seems..." + +He did not finish, but gave a painfully unnatural smile. + + + + + +CHAPTER XIX + + +Having returned to the regiment and told the commander the state +of Denisov's affairs, Rostov rode to Tilsit with the letter to the +Emperor. + +On the thirteenth of June the French and Russian Emperors arrived in +Tilsit. Boris Drubetskoy had asked the important personage on whom +he was in attendance, to include him in the suite appointed for the +stay at Tilsit. + +"I should like to see the great man," he said, alluding to Napoleon, +whom hitherto he, like everyone else, had always called Buonaparte. + +"You are speaking of Buonaparte?" asked the general, smiling. + + +Boris looked at his general inquiringly and immediately saw that +he was being tested. + +"I am speaking, Prince, of the Emperor Napoleon," he replied. The +general patted him on the shoulder, with a smile. + +"You will go far," he said, and took him to Tilsit with him. + +Boris was among the few present at the Niemen on the day the two +Emperors met. He saw the raft, decorated with monograms, saw +Napoleon pass before the French Guards on the farther bank of the +river, saw the pensive face of the Emperor Alexander as he sat in +silence in a tavern on the bank of the Niemen awaiting Napoleon's +arrival, saw both Emperors get into boats, and saw how Napoleon- +reaching the raft first--stepped quickly forward to meet Alexander and +held out his hand to him, and how they both retired into the pavilion. +Since he had begun to move in the highest circles Boris had made it +his habit to watch attentively all that went on around him and to note +it down. At the time of the meeting at Tilsit he asked the names of +those who had come with Napoleon and about the uniforms they wore, and +listened attentively to words spoken by important personages. At the +moment the Emperors went into the pavilion he looked at his watch, and +did not forget to look at it again when Alexander came out. The +interview had lasted an hour and fifty-three minutes. He noted this +down that same evening, among other facts he felt to be of historic +importance. As the Emperor's suite was a very small one, it was a +matter of great importance, for a man who valued his success in the +service, to be at Tilsit on the occasion of this interview between the +two Emperors, and having succeeded in this, Boris felt that henceforth +his position was fully assured. He had not only become known, but +people had grown accustomed to him and accepted him. Twice he had +executed commissions to the Emperor himself, so that the latter knew +his face, and all those at court, far from cold-shouldering him as +at first when they considered him a newcomer, would now have been +surprised had he been absent. + +Boris lodged with another adjutant, the Polish Count Zhilinski. +Zhilinski, a Pole brought up in Paris, was rich, and passionately fond +of the French, and almost every day of the stay at Tilsit, French +officers of the Guard and from French headquarters were dining and +lunching with him and Boris. + +On the evening of the twenty-fourth of June, Count Zhilinski +arranged a supper for his French friends. The guest of honor was an +aide-de-camp of Napoleon's, there were also several French officers of +the Guard, and a page of Napoleon's, a young lad of an old +aristocratic French family. That same day, Rostov, profiting by the +darkness to avoid being recognized in civilian dress, came to Tilsit +and went to the lodging occupied by Boris and Zhilinski. + +Rostov, in common with the whole army from which he came, was far +from having experienced the change of feeling toward Napoleon and +the French--who from being foes had suddenly become friends--that +had taken place at headquarters and in Boris. In the army, Bonaparte +and the French were still regarded with mingled feelings of anger, +contempt, and fear. Only recently, talking with one of Platov's +Cossack officers, Rostov had argued that if Napoleon were taken +prisoner he would be treated not as a sovereign, but as a criminal. +Quite lately, happening to meet a wounded French colonel on the +road, Rostov had maintained with heat that peace was impossible +between a legitimate sovereign and the criminal Bonaparte. Rostov +was therefore unpleasantly struck by the presence of French officers +in Boris' lodging, dressed in uniforms he had been accustomed to see +from quite a different point of view from the outposts of the flank. +As soon as he noticed a French officer, who thrust his head out of the +door, that warlike feeling of hostility which he always experienced at +the sight of the enemy suddenly seized him. He stopped at the +threshold and asked in Russian whether Drubetskoy lived there. +Boris, hearing a strange voice in the anteroom, came out to meet +him. An expression of annoyance showed itself for a moment on his face +on first recognizing Rostov. + +"Ah, it's you? Very glad, very glad to see you," he said, however, +coming toward him with a smile. But Rostov had noticed his first +impulse. + +"I've come at a bad time I think. I should not have come, but I have +business," he said coldly. + +"No, I only wonder how you managed to get away from your regiment. +Dans un moment je suis a vous,"* he said, answering someone who called +him. + + +*"In a minute I shall be at your disposal." + + +"I see I'm intruding," Rostov repeated. + +The look of annoyance had already disappeared from Boris' face: +having evidently reflected and decided how to act, he very quietly +took both Rostov's hands and led him into the next room. His eyes, +looking serenely and steadily at Rostov, seemed to be veiled by +something, as if screened by blue spectacles of conventionality. So it +seemed to Rostov. + +"Oh, come now! As if you could come at a wrong time!" said Boris, +and he led him into the room where the supper table was laid and +introduced him to his guests, explaining that he was not a civilian, +but an hussar officer, and an old friend of his. + +"Count Zhilinski--le Comte N. N.--le Capitaine S. S.," said he, +naming his guests. Rostov looked frowningly at the Frenchmen, bowed +reluctantly, and remained silent. + +Zhilinski evidently did not receive this new Russian person very +willingly into his circle and did not speak to Rostov. Boris did not +appear to notice the constraint the newcomer produced and, with the +same pleasant composure and the same veiled look in his eyes with +which he had met Rostov, tried to enliven the conversation. One of the +Frenchmen, with the politeness characteristic of his countrymen, +addressed the obstinately taciturn Rostov, saying that the latter +had probably come to Tilsit to see the Emperor. + +"No, I came on business," replied Rostov, briefly. + +Rostov had been out of humor from the moment he noticed the look +of dissatisfaction on Boris' face, and as always happens to those in a +bad humor, it seemed to him that everyone regarded him with aversion +and that he was in everybody's way. He really was in their way, for he +alone took no part in the conversation which again became general. The +looks the visitors cast on him seemed to say: "And what is he +sitting here for?" He rose and went up to Boris. + +"Anyhow, I'm in your way," he said in a low tone. "Come and talk +over my business and I'll go away." + +"Oh, no, not at all," said Boris. "But if you are tired, come and +lie down in my room and have a rest." + +"Yes, really..." + +They went into the little room where Boris slept. Rostov, without +sitting down, began at once, irritably (as if Boris were to blame in +some way) telling him about Denisov's affair, asking him whether, +through his general, he could and would intercede with the Emperor +on Denisov's behalf and get Denisov's petition handed in. When he +and Boris were alone, Rostov felt for the first time that he could not +look Boris in the face without a sense of awkwardness. Boris, with one +leg crossed over the other and stroking his left hand with the slender +fingers of his right, listened to Rostov as a general listens to the +report of a subordinate, now looking aside and now gazing straight +into Rostov's eyes with the same veiled look. Each time this +happened Rostov felt uncomfortable and cast down his eyes. + +"I have heard of such cases and know that His Majesty is very severe +in such affairs. I think it would be best not to bring it before the +Emperor, but to apply to the commander of the corps.... But in +general, I think..." + +"So you don't want to do anything? Well then, say so!" Rostov almost +shouted, not looking Boris in the face. + +Boris smiled. + +"On the contrary, I will do what I can. Only I thought..." + +At that moment Zhilinski's voice was heard calling Boris. + +"Well then, go, go, go..." said Rostov, and refusing supper and +remaining alone in the little room, he walked up and down for a long +time, hearing the lighthearted French conversation from the next room. + + + + + +CHAPTER XX + + +Rostov had come to Tilsit the day least suitable for a petition on +Denisov's behalf. He could not himself go to the general in attendance +as he was in mufti and had come to Tilsit without permission to do so, +and Boris, even had he wished to, could not have done so on the +following day. On that day, June 27, the preliminaries of peace were +signed. The Emperors exchanged decorations: Alexander received the +Cross of the Legion of Honor and Napoleon the Order of St. Andrew of +the First Degree, and a dinner had been arranged for the evening, +given by a battalion of the French Guards to the Preobrazhensk +battalion. The Emperors were to be present at that banquet. + +Rostov felt so ill at ease and uncomfortable with Boris that, when +the latter looked in after supper, he pretended to be asleep, and +early next morning went away, avoiding Boris. In his civilian +clothes and a round hat, he wandered about the town, staring at the +French and their uniforms and at the streets and houses where the +Russian and French Emperors were staying. In a square he saw tables +being set up and preparations made for the dinner; he saw the +Russian and French colors draped from side to side of the streets, +with hugh monograms A and N. In the windows of the houses also flags +and bunting were displayed. + +"Boris doesn't want to help me and I don't want to ask him. That's +settled," thought Nicholas. "All is over between us, but I won't leave +here without having done all I can for Denisov and certainly not +without getting his letter to the Emperor. The Emperor!... He is +here!" thought Rostov, who had unconsciously returned to the house +where Alexander lodged. + +Saddled horses were standing before the house and the suite were +assembling, evidently preparing for the Emperor to come out. + +"I may see him at any moment," thought Rostov. "If only I were to +hand the letter direct to him and tell him all... could they really +arrest me for my civilian clothes? Surely not! He would understand +on whose side justice lies. He understands everything, knows +everything. Who can be more just, more magnanimous than he? And even +if they did arrest me for being here, what would it matter?" thought +he, looking at an officer who was entering the house the Emperor +occupied. "After all, people do go in.... It's all nonsense! I'll go +in and hand the letter to the Emperor myself so much the worse for +Drubetskoy who drives me to it!" And suddenly with a determination +he himself did not expect, Rostov felt for the letter in his pocket +and went straight to the house. + +"No, I won't miss my opportunity now, as I did after Austerlitz," he +thought, expecting every moment to meet the monarch, and conscious +of the blood that rushed to his heart at the thought. "I will fall +at his feet and beseech him. He will lift me up, will listen, and will +even thank me. 'I am happy when I can do good, but to remedy injustice +is the greatest happiness,'" Rostov fancied the sovereign saying. +And passing people who looked after him with curiosity, he entered the +porch of the Emperor's house. + +A broad staircase led straight up from the entry, and to the right +he saw a closed door. Below, under the staircase, was a door leading +to the lower floor. + +"Whom do you want?" someone inquired. + +"To hand in a letter, a petition, to His Majesty," said Nicholas, +with a tremor in his voice. + +"A petition? This way, to the officer on duty" (he was +shown the door leading downstairs), "only it won't be accepted." + +On hearing this indifferent voice, Rostov grew frightened at what he +was doing; the thought of meeting the Emperor at any moment was so +fascinating and consequently so alarming that he was ready to run +away, but the official who had questioned him opened the door, and +Rostov entered. + +A short stout man of about thirty, in white breeches and high +boots and a batiste shirt that he had evidently only just put on, +standing in that room, and his valet was buttoning on to the back of +his breeches a new pair of handsome silk-embroidered braces that, +for some reason, attracted Rostov's attention. This man was was +speaking to someone in the adjoining room. + +"A good figure and in her first bloom," he was saying, but on seeing +Rostov, he stopped short and frowned. + +"What is it? A petition?" + +"What is it?" asked the person in the other room. + +"Another petitioner," answered the man with the braces. + +"Tell him to come later. He'll be coming out directly, we must go." + +"Later... later! Tomorrow. It's too late..." + +Rostov turned and was about to go, but the man in the braces stopped +him. + +"Whom have you come from? Who are you?" + +"I come from Major Denisov," answered Rostov. + +"Are you an officer?" + +"Lieutenant Count Rostov." + +"What audacity! Hand it in through your commander. And go along with +you... go," and he continued to put on the uniform the valet handed +him. + +Rostov went back into the hall and noticed that in the porch there +were many officers and generals in full parade uniform, whom he had to +pass. + +Cursing his temerity, his heart sinking at the thought of finding +himself at any moment face to face with the Emperor and being put to +shame and arrested in his presence, fully alive now to the impropriety +of his conduct and repenting of it, Rostov, with downcast eyes, was +making his way out of the house through the brilliant suite when a +familiar voice called him and a hand detained him. + +"What are you doing here, sir, in civilian dress?" asked a deep +voice. + +It was a cavalry general who had obtained the Emperor's special +favor during this campaign, and who had formerly commanded the +division in which Rostov was serving. + +Rostov, in dismay, began justifying himself, but seeing the +kindly, jocular face of the general, he took him aside and in an +excited voice told him the whole affair, asking him to intercede for +Denisov, whom the general knew. Having heard Rostov to the end, the +general shook his head gravely. + +"I'm sorry, sorry for that fine fellow. Give me the letter." + +Hardly had Rostov handed him the letter and finished explaining +Denisov's case, when hasty steps and the jingling of spurs were +heard on the stairs, and the general, leaving him, went to the +porch. The gentlemen of the Emperor's suite ran down the stairs and +went to their horses. Hayne, the same groom who had been at +Austerlitz, led up the Emperor's horse, and the faint creak of a +footstep Rostov knew at once was heard on the stairs. Forgetting the +danger of being recognized, Rostov went close to the porch, together +with some inquisitive civilians, and again, after two years, saw those +features he adored: that same face and same look and step, and the +same union of majesty and mildness.... And the feeling of enthusiasm +and love for his sovereign rose again in Rostov's soul in all its +old force. In the uniform of the Preobrazhensk regiment--white +chamois-leather breeches and high boots--and wearing a star Rostov did +not know (it was that of the Legion d'honneur), the monarch came out +into the porch, putting on his gloves and carrying his hat under his +arm. He stopped and looked about him, brightening everything around by +his glance. He spoke a few words to some of the generals, and, +recognizing the former commander of Rostov's division, smiled and +beckoned to him. + +All the suite drew back and Rostov saw the general talking for +some time to the Emperor. + +The Emperor said a few words to him and took a step toward his +horse. Again the crowd of members of the suite and street gazers +(among whom was Rostov) moved nearer to the Emperor. Stopping beside +his horse, with his hand on the saddle, the Emperor turned to the +cavalry general and said in a loud voice, evidently wishing to be +heard by all: + +"I cannot do it, General. I cannot, because the law is stronger than +I," and he raised his foot to the stirrup. + +The general bowed his head respectfully, and the monarch mounted and +rode down the street at a gallop. Beside himself with enthusiasm, +Rostov ran after him with the crowd. + + + + + +CHAPTER XXI + + +The Emperor rode to the square where, facing one another, a +battalion of the Preobrazhensk regiment stood on the right and a +battalion of the French Guards in their bearskin caps on the left. + +As the Tsar rode up to one flank of the battalions, which +presented arms, another group of horsemen galloped up to the +opposite flank, and at the head of them Rostov recognized Napoleon. It +could be no one else. He came at a gallop, wearing a small hat, a blue +uniform open over a white vest, and the St. Andrew ribbon over his +shoulder. He was riding a very fine thoroughbred gray Arab horse +with a crimson gold-embroidered saddlecloth. On approaching +Alexander he raised his hat, and as he did so, Rostov, with his +cavalryman's eye, could not help noticing that Napoleon did not sit +well or firmly in the saddle. The battalions shouted "Hurrah!" and +"Vive l'Empereur!" Napoleon said something to Alexander, and both +Emperors dismounted and took each other's hands. Napoleon's face +wore an unpleasant and artificial smile. Alexander was saying +something affable to him. + +In spite of the trampling of the French gendarmes' horses, which +were pushing back the crowd, Rostov kept his eyes on every movement of +Alexander and Bonaparte. It struck him as a surprise that Alexander +treated Bonaparte as an equal and that the latter was quite at ease +with the Tsar, as if such relations with an Emperor were an everyday +matter to him. + +Alexander and Napoleon, with the long train of their suites, +approached the right flank of the Preobrazhensk battalion and came +straight up to the crowd standing there. The crowd unexpectedly +found itself so close to the Emperors that Rostov, standing in the +front row, was afraid he might be recognized. + +"Sire, I ask your permission to present the Legion of Honor to the +bravest of your soldiers," said a sharp, precise voice, articulating +every letter. + +This was said by the undersized Napoleon, looking up straight into +Alexander's eyes. Alexander listened attentively to what was said to +him and, bending his head, smiled pleasantly. + +"To him who has borne himself most bravely in this last war," +added Napoleon, accentuating each syllable, as with a composure and +assurance exasperating to Rostov, he ran his eyes over the Russian +ranks drawn up before him, who all presented arms with their eyes +fixed on their Emperor. + +"Will Your Majesty allow me to consult the colonel?" said +Alexander and took a few hasty steps toward Prince Kozlovski, the +commander of the battalion. + +Bonaparte meanwhile began taking the glove off his small white hand, +tore it in doing so, and threw it away. An aide-de-camp behind him +rushed forward and picked it up. + +"To whom shall it be given?" the Emperor Alexander asked +Koslovski, in Russian in a low voice. + +"To whomever Your Majesty commands." + +The Emperor knit his brows with dissatisfaction and, glancing +back, remarked: + +"But we must give him an answer." + +Kozlovski scanned the ranks resolutely and included Rostov in his +scrutiny. + +"Can it be me?" thought Rostov. + +"Lazarev!" the colonel called, with a frown, and Lazarev, the +first soldier in the rank, stepped briskly forward. + +"Where are you off to? Stop here!" voices whispered to Lazarev who +did not know where to go. Lazarev stopped, casting a sidelong look +at his colonel in alarm. His face twitched, as often happens to +soldiers called before the ranks. + +Napoleon slightly turned his head, and put his plump little hand out +behind him as if to take something. The members of his suite, guessing +at once what he wanted, moved about and whispered as they passed +something from one to another, and a page--the same one Rostov had +seen the previous evening at Boris'--ran forward and, bowing +respectfully over the outstretched hand and not keeping it waiting a +moment, laid in it an Order on a red ribbon. Napoleon, without +looking, pressed two fingers together and the badge was between +them. Then he approached Lazarev (who rolled his eyes and persistently +gazed at his own monarch), looked round at the Emperor Alexander to +imply that what he was now doing was done for the sake of his ally, +and the small white hand holding the Order touched one of Lazarev's +buttons. It was as if Napoleon knew that it was only necessary for his +hand to deign to touch that soldier's breast for the soldier to be +forever happy, rewarded, and distinguished from everyone else in the +world. Napoleon merely laid the cross on Lazarev's breast and, +dropping his hand, turned toward Alexander as though sure that the +cross would adhere there. And it really did. + +Officious hands, Russian and French, immediately seized the cross +and fastened it to the uniform. Lazarev glanced morosely at the little +man with white hands who was doing something to him and, still +standing motionless presenting arms, looked again straight into +Alexander's eyes, as if asking whether he should stand there, or go +away, or do something else. But receiving no orders, he remained for +some time in that rigid position. + +The Emperors remounted and rode away. The Preobrazhensk battalion, +breaking rank, mingled with the French Guards and sat down at the +tables prepared for them. + +Lazarev sat in the place of honor. Russian and French officers +embraced him, congratulated him, and pressed his hands. Crowds of +officers and civilians drew near merely to see him. A rumble of +Russian and French voices and laughter filled the air round the tables +in the square. Two officers with flushed faces, looking cheerful and +happy, passed by Rostov. + +"What d'you think of the treat? All on silver plate," one of them +was saying. "Have you seen Lazarev?" + +"I have." + +"Tomorrow, I hear, the Preobrazhenskis will give them a dinner." + +"Yes, but what luck for Lazarev! Twelve hundred francs' pension +for life." + +"Here's a cap, lads!" shouted a Preobrazhensk soldier, donning a +shaggy French cap. + +"It's a fine thing! First-rate!" + +"Have you heard the password?" asked one Guards' officer of another. +"The day before yesterday it was 'Napoleon, France, bravoure'; +yesterday, 'Alexandre, Russie, grandeur.' One day our Emperor gives it +and next day Napoleon. Tomorrow our Emperor will send a St. George's +Cross to the bravest of the French Guards. It has to be done. He +must respond in kind." + +Boris, too, with his friend Zhilinski, came to see the Preobrazhensk +banquet. On his way back, he noticed Rostov standing by the corner +of a house. + +"Rostov! How d'you do? We missed one another," he said, and could +not refrain from asking what was the matter, so strangely dismal and +troubled was Rostov's face. + +"Nothing, nothing," replied Rostov. + +"You'll call round?" + +"Yes, I will." + +Rostov stood at that corner for a long time, watching the feast from +a distance. In his mind, a painful process was going on +which he could not bring to a conclusion. Terrible doubts rose in +his soul. Now he remembered Denisov with his changed expression, his +submission, and the whole hospital, with arms and legs torn off and +its dirt and disease. So vividly did he recall that hospital stench of +dead flesh that he looked round to see where the smell came from. Next +he thought of that self-satisfied Bonaparte, with his small white +hand, who was now an Emperor, liked and respected by Alexander. Then +why those severed arms and legs and those dead men?... Then again he +thought of Lazarev rewarded and Denisov punished and unpardoned. He +caught himself harboring such strange thoughts that he was frightened. + +The smell of the food the Preobrazhenskis were eating and a sense of +hunger recalled him from these reflections; he had to get something to +eat before going away. He went to a hotel he had noticed that morning. +There he found so many people, among them officers who, like +himself, had come in civilian clothes, that he had difficulty in +getting a dinner. Two officers of his own division joined him. The +conversation naturally turned on the peace. The officers, his +comrades, like most of the army, were dissatisfied with the peace +concluded after the battle of Friedland. They said that had we held +out a little longer Napoleon would have been done for, as his troops +had neither provisions nor ammunition. Nicholas ate and drank (chiefly +the latter) in silence. He finished a couple of bottles of wine by +himself. The process in his mind went on tormenting him without +reaching a conclusion. He feared to give way to his thoughts, yet +could not get rid of them. Suddenly, on one of the officers' saying +that it was humiliating to look at the French, Rostov began shouting +with uncalled-for wrath, and therefore much to the surprise of the +officers: + +"How can you judge what's best?" he cried, the blood suddenly +rushing to his face. "How can you judge the Emperor's actions? What +right have we to argue? We cannot comprehend either the Emperor's or +his actions!" + +"But I never said a word about the Emperor!" said the officer, +justifying himself, and unable to understand Rostov's outburst, except +on the supposition that he was drunk. + +But Rostov did not listen to him. + +"We are not diplomatic officials, we are soldiers and nothing more," +he went on. "If we are ordered to die, we must die. If we're punished, +it means that we have deserved it, it's not for us to judge. If the +Emperor pleases to recognize Bonaparte as Emperor and to conclude an +alliance with him, it means that that is the right thing to do. If +once we begin judging and arguing about everything, nothing sacred +will be left! That way we shall be saying there is no God--nothing!" +shouted Nicholas, banging the table--very little to the point as it +seemed to his listeners, but quite relevantly to the course of his own +thoughts. + +"Our business is to do our duty, to fight and not to think! That's +all...." said he. + +"And to drink," said one of the officers, not wishing to quarrel. + +"Yes, and to drink," assented Nicholas. "Hullo there! Another +bottle!" he shouted. + +In 1808 the Emperor Alexander went to Erfurt for a fresh interview +with the Emperor Napoleon, and in the upper circles of Petersburg +there was much talk of the grandeur of this important meeting. + + + + + +CHAPTER XXII + + +In 1809 the intimacy between "the world's two arbiters," as Napoleon +and Alexander were called, was such that when Napoleon declared war on +Austria a Russian corps crossed the frontier to co-operate with our +old enemy Bonaparte against our old ally the Emperor of Austria, and +in court circles the possibility of marriage between Napoleon and +one of Alexander's sisters was spoken of. But besides considerations +of foreign policy, the attention of Russian society was at that time +keenly directed on the internal changes that were being undertaken +in all the departments of government. + +Life meanwhile--real life, with its essential interests of health +and sickness, toil and rest, and its intellectual interests in +thought, science, poetry, music, love, friendship, hatred, and +passions--went on as usual, independently of and apart from +political friendship or enmity with Napoleon Bonaparte and from all +the schemes of reconstruction. + + + + +BOOK SIX: 1808 --10 + + + + + +CHAPTER I + + +Prince Andrew had spent two years continuously in the country. + +All the plans Pierre had attempted on his estates--and constantly +changing from one thing to another had never accomplished--were +carried out by Prince Andrew without display and without perceptible +difficulty. + +He had in the highest degree a practical tenacity which Pierre +lacked, and without fuss or strain on his part this set things going. + +On one of his estates the three hundred serfs were liberated and +became free agricultural laborers--this being one of the first +examples of the kind in Russia. On other estates the serfs' compulsory +labor was commuted for a quitrent. A trained midwife was engaged for +Bogucharovo at his expense, and a priest was paid to teach reading and +writing to the children of the peasants and household serfs. + +Prince Andrew spent half his time at Bald Hills with his father +and his son, who was still in the care of nurses. The other half he +spent in "Bogucharovo Cloister," as his father called Prince +Andrew's estate. Despite the indifference to the affairs of the +world he had expressed to Pierre, he diligently followed all that went +on, received many books, and to his surprise noticed that when he or +his father had visitors from Petersburg, the very vortex of life, +these people lagged behind himself--who never left the country--in +knowledge of what was happening in home and foreign affairs. + +Besides being occupied with his estates and reading a great +variety of books, Prince Andrew was at this time busy with a +critical of survey our last two unfortunate campaigns, and with +drawing up a proposal for a reform of the army rules and regulations. + +In the spring of 1809 he went to visit the Ryazan estates which +had been inherited by his son, whose guardian he was. + +Warmed by the spring sunshine he sat in the caleche looking at the +new grass, the first leaves on the birches, and the first puffs of +white spring clouds floating across the clear blue sky. He was not +thinking of anything, but looked absent-mindedly and cheerfully from +side to side. + +They crossed the ferry where he had talked with Pierre the year +before. They went through the muddy village, past threshing floors and +green fields of winter rye, downhill where snow still lodged near +the bridge, uphill where the clay had been liquefied by the rain, past +strips of stubble land and bushes touched with green here and there, +and into a birch forest growing on both sides of the road. In the +forest it was almost hot, no wind could be felt. The birches with +their sticky green leaves were motionless, and lilac-colored flowers +and the first blades of green grass were pushing up and lifting last +year's leaves. The coarse evergreen color of the small fir trees +scattered here and there among the birches was an unpleasant +reminder of winter. On entering the forest the horses began to snort +and sweated visibly. + +Peter the footman made some remark to the coachman; the latter +assented. But apparently the coachman's sympathy was not enough for +Peter, and he turned on the box toward his master. + +"How pleasant it is, your excellency!" he said with a respectful +smile. + +"What?" + +"It's pleasant, your excellency!" + +"What is he talking about?" thought Prince Andrew. "Oh, the +spring, I suppose," he thought as he turned round. "Yes, really +everything is green already.... How early! The birches and cherry +and alders too are coming out.... But the oaks show no sign yet. Ah, +here is one oak!" + + At the edge of the road stood an oak. Probably ten times the age of +the birches that formed the forest, it was ten times as thick and +twice as tall as they. It was an enormous tree, its girth twice as +great as a man could embrace, and evidently long ago some of its +branches had been broken off and its bark scarred. With its huge +ungainly limbs sprawling unsymmetrically, and its gnarled hands and +fingers, it stood an aged, stern, and scornful monster among the +smiling birch trees. Only the dead-looking evergreen firs dotted about +in the forest, and this oak, refused to yield to the charm of spring +or notice either the spring or the sunshine. + +"Spring, love, happiness!" this oak seemed to say. "Are you not +weary of that stupid, meaningless, constantly repeated fraud? Always +the same and always a fraud? There is no spring, no sun, no happiness! +Look at those cramped dead firs, ever the same, and at me too, +sticking out my broken and barked fingers just where they have +grown, whether from my back or my sides: as they have grown so I +stand, and I do not believe in your hopes and your lies." + +As he passed through the forest Prince Andrew turned several times +to look at that oak, as if expecting something from it. Under the oak, +too, were flowers and grass, but it stood among them scowling, +rigid, misshapen, and grim as ever. + +"Yes, the oak is right, a thousand times right," thought Prince +Andrew. "Let others--the young--yield afresh to that fraud, but we +know life, our life is finished!" + +A whole sequence of new thoughts, hopeless but mournfully +pleasant, rose in his soul in connection with that tree. During this +journey he, as it were, considered his life afresh and arrived at +his old conclusion, restful in its hopelessness: that it was not for +him to begin anything anew--but that he must live out his life, +content to do no harm, and not disturbing himself or desiring +anything. + + + + + +CHAPTER II + + +Prince Andrew had to see the Marshal of the Nobility for the +district in connection with the affairs of the Ryazan estate of +which he was trustee. This Marshal was Count Ilya Rostov, and in the +middle of May Prince Andrew went to visit him. + +It was now hot spring weather. The whole forest was already +clothed in green. It was dusty and so hot that on passing near water +one longed to bathe. + +Prince Andrew, depressed and preoccupied with the business about +which he had to speak to the Marshal, was driving up the avenue in the +grounds of the Rostovs' house at Otradnoe. He heard merry girlish +cries behind some trees on the right and saw a group of girls running to +cross the path of his caleche. Ahead of the rest and nearer to him ran +a dark-haired, remarkably slim, pretty girl in a yellow chintz +dress, with a white handkerchief on her head from under which loose +locks of hair escaped. The girl was shouting something but, seeing +that he was a stranger, ran back laughing without looking at him. + +Suddenly, he did not know why, he felt a pang. The day was so +beautiful, the sun so bright, everything around so gay, but that +slim pretty girl did not know, or wish to know, of his existence and +was contented and cheerful in her own separate--probably foolish- +but bright and happy life. "What is she so glad about? What is she +thinking of? Not of the military regulations or of the arrangement +of the Ryazan serfs' quitrents. Of what is she thinking? Why is she so +happy?" Prince Andrew asked himself with instinctive curiosity. + +In 1809 Count Ilya Rostov was living at Otradnoe just as he had done +in former years, that is, entertaining almost the whole province +with hunts, theatricals, dinners, and music. He was glad to see Prince +Andrew, as he was to see any new visitor, and insisted on his +staying the night. + +During the dull day, in the course of which he was entertained by +his elderly hosts and by the more important of the visitors (the old +count's house was crowded on account of an approaching name day), +Prince Andrew repeatedly glanced at Natasha, gay and laughing among +the younger members of the company, and asked himself each time, "What +is she thinking about? Why is she so glad?" + +That night, alone in new surroundings, he was long unable to +sleep. He read awhile and then put out his candle, but relit it. It +was hot in the room, the inside shutters of which were closed. He +was cross with the stupid old man (as he called Rostov), who had +made him stay by assuring him that some necessary documents had not +yet arrived from town, and he was vexed with himself for having +stayed. + +He got up and went to the window to open it. As soon as he opened +the shutters the moonlight, as if it had long been watching for +this, burst into the room. He opened the casement. The night was +fresh, bright, and very still. Just before the window was a row of +pollard trees, looking black on one side and with a silvery light on +the other. Beneath the trees grewsome kind of lush, wet, bushy +vegetation with silver-lit leaves and stems here and there. Farther +back beyond the dark trees a roof glittered with dew, to the right was +a leafy tree with brilliantly white trunk and branches, and above it +shone the moon, nearly at its full, in a pale, almost starless, spring +sky. Prince Andrew leaned his elbows on the window ledge and his +eyes rested on that sky. + +His room was on the first floor. Those in the rooms above were +also awake. He heard female voices overhead. + +"Just once more," said a girlish voice above him which Prince Andrew +recognized at once. + +"But when are you coming to bed?" replied another voice. + +"I won't, I can't sleep, what's the use? Come now for the last +time." + + Two girlish voices sang a musical passage--the end of some song. + +"Oh, how lovely! Now go to sleep, and there's an end of it." + +"You go to sleep, but I can't," said the first voice, coming +nearer to the window. She was evidently leaning right out, for the +rustle of her dress and even her breathing could be heard. +Everything was stone-still, like the moon and its light and the +shadows. Prince Andrew, too, dared not stir, for fear of betraying his +unintentional presence. + +"Sonya! Sonya!" he again heard the first speaker. "Oh, how can you +sleep? Only look how glorious it is! Ah, how glorious! Do wake up, +Sonya!" she said almost with tears in her voice. "There never, never +was such a lovely night before!" + +Sonya made some reluctant reply. + +"Do just come and see what a moon!... Oh, how lovely! Come +here.... Darling, sweetheart, come here! There, you see? I feel like +sitting down on my heels, putting my arms round my knees like this, +straining tight, as tight as possible, and flying away! Like this...." + +"Take care, you'll fall out." + +He heard the sound of a scuffle and Sonya's disapproving voice: +"It's past one o'clock." + +"Oh, you only spoil things for me. All right, go, go!" + +Again all was silent, but Prince Andrew knew she was still sitting +there. From time to time he heard a soft rustle and at times a sigh. + +"O God, O God! What does it mean?" she suddenly exclaimed. "To bed +then, if it must be!" and she slammed the casement. + +"For her I might as well not exist!" thought Prince Andrew while +he listened to her voice, for some reason expecting yet fearing that +she might say something about him. "There she is again! As if it +were on purpose," thought he. + +In his soul there suddenly arose such an unexpected turmoil of +youthful thoughts and hopes, contrary to the whole tenor of his +life, that unable to explain his condition to himself he lay down +and fell asleep at once. + + + + + +CHAPTER III + + +Next morning, having taken leave of no one but the count, and not +waiting for the ladies to appear, Prince Andrew set off for home. + +It was already the beginning of June when on his return journey he +drove into the birch forest where the gnarled old oak had made so +strange and memorable an impression on him. In the forest the +harness bells sounded yet more muffled than they had done six weeks +before, for now all was thick, shady, and dense, and the young firs +dotted about in the forest did not jar on the general beauty but, +lending themselves to the mood around, were delicately green with +fluffy young shoots. + +The whole day had been hot. Somewhere a storm was gathering, but +only a small cloud had scattered some raindrops lightly, sprinkling +the road and the sappy leaves. The left side of the forest was dark in +the shade, the right side glittered in the sunlight, wet and shiny and +scarcely swayed by the breeze. Everything was in blossom, the +nightingales trilled, and their voices reverberated now near, now +far away. + +"Yes, here in this forest was that oak with which I agreed," thought +Prince Andrew. "But where is it?" he again wondered, gazing at the +left side of the road, and without recognizing it he looked with +admiration at the very oak he sought. The old oak, quite transfigured, +spreading out a canopy of sappy dark-green foliage, stood rapt and +slightly trembling in the rays of the evening sun. Neither gnarled +fingers nor old scars nor old doubts and sorrows were any of them in +evidence now. Through the hard century-old bark, even where there were +no twigs, leaves had sprouted such as one could hardly believe the old +veteran could have produced. + +"Yes, it is the same oak," thought Prince Andrew, and all at once he +was seized by an unreasoning springtime feeling of joy and renewal. +All the best moments of his life suddenly rose to his memory. +Austerlitz with the lofty heavens, his wife's dead reproachful face, +Pierre at the ferry, that girl thrilled by the beauty of the night, +and that night itself and the moon, and.... all this rushed suddenly +to his mind. + +"No, life is not over at thirty-one!" Prince Andrew suddenly decided +finally and decisively. "It is not enough for me to know what I have +in me--everyone must know it: Pierre, and that young girl who wanted +to fly away into the sky, everyone must know me, so that my life may +not be lived for myself alone while others live so apart from it, +but so that it may be reflected in them all, and they and I may live +in harmony!" + + +On reaching home Prince Andrew decided to go to Petersburg that +autumn and found all sorts of reasons for this decision. A whole +serics of sensible and logical considerations showing it to be +essential for him to go to Petersburg, and even to re-enter the +service, kept springing up in his mind. He could not now understand +how he could ever even have doubted the necessity of taking an +active share in life, just as a month before he had not understood how +the idea of leaving the quiet country could ever enter his head. It +now seemed clear to him that all his experience of life must be +senselessly wasted unless he applied it to some kind of work and again +played an active part in life. He did not even remember how +formerly, on the strength of similar wretched logical arguments, it +had seemed obvious that he would be degrading himself if he now, after +the lessons he had had in life, allowed himself to believe in the +possibility of being useful and in the possibility of happiness or +love. Now reason suggested quite the opposite. After that journey to +Ryazan he found the country dull; his former pursuits no longer +interested him, and often when sitting alone in his study he got up, +went to the mirror, and gazed a long time at his own face. Then he +would turn away to the portrait of his dead Lise, who with hair curled +a la grecque looked tenderly and gaily at him out of the gilt frame. +She did not now say those former terrible words to him, but looked +simply, merrily, and inquisitively at him. And Prince Andrew, crossing +his arms behind him, long paced the room, now frowning, now smiling, +as he reflected on those irrational, inexpressible thoughts, secret as +a crime, which altered his whole life and were connected with +Pierre, with fame, with the girl at the window, the oak, and woman's +beauty and love. And if anyone came into his room at such moments he +was particularly cold, stern, and above all unpleasantly logical. + +"My dear," Princess Mary entering at such a moment would say, +"little Nicholas can't go out today, it's very cold." + +"If it were hot," Prince Andrew would reply at such times very dryly +to his sister, "he could go out in his smock, but as it is cold he +must wear warm clothes, which were designed for that purpose. That +is what follows from the fact that it is cold; and not that a child +who needs fresh air should remain at home," he would add with +extreme logic, as if punishing someone for those secret illogical +emotions that stirred within him. + +At such moments Princess Mary would think how intellectual work +dries men up. + + + + + +CHAPTER IV + + +Prince Andrew arrived in Petersburg in August, 1809. It was the time +when the youthful Speranski was at the zenith of his fame and his +reforms were being pushed forward with the greatest energy. That +same August the Emperor was thrown from his caleche, injured his +leg, and remained three weeks at Peterhof, receiving Speranski every +day and no one else. At that time the two famous decrees were being +prepared that so agitated society--abolishing court ranks and +introducing examinations to qualify for the grades of Collegiate +Assessor and State Councilor--and not merely these but a whole state +constitution, intended to change the existing order of government in +Russia: legal, administrative, and financial, from the Council of +State down to the district tribunals. Now those vague liberal dreams +with which the Emperor Alexander had ascended the throne, and which he +had tried to put into effect with the aid of his associates, +Czartoryski, Novosiltsev, Kochubey, and Strogonov--whom he himself +in jest had called his Comite de salut public--were taking shape and +being realized. + +Now all these men were replaced by Speranski on the civil side, +and Arakcheev on the military. Soon after his arrival Prince Andrew, +as a gentleman of the chamber, presented himself at court and at a +levee. The Emperor, though he met him twice, did not favor him with +a single word. It had always seemed to Prince Andrew before that he +was antipathetic to the Emperor and that the latter disliked his +face and personality generally, and in the cold, repellent glance +the Emperor gave him, he now found further confirmation of this +surmise. The courtiers explained the Emperor's neglect of him by His +Majesty's displeasure at Bolkonski's not having served since 1805. + +"I know myself that one cannot help one's sympathies and +antipathies," thought Prince Andrew, "so it will not do to present +my proposal for the reform of the army regulations to the Emperor +personally, but the project will speak for itself." + +He mentioned what he had written to an old field marshal, a friend +of his father's. The field marshal made an appointment to see him, +received him graciously, and promised to inform the Emperor. A few +days later Prince Andrew received notice that he was to go to see +the Minister of War, Count Arakcheev. + + +On the appointed day Prince Andrew entered Count Arakcheev's waiting +room at nine in the morning. + +He did not know Arakcheev personally, had never seen him, and all he +had heard of him inspired him with but little respect for the man. + +"He is Minister of War, a man trusted by the Emperor, and I need not +concern myself about his personal qualities: he has been +commissioned to consider my project, so he alone can get it +adopted," thought Prince Andrew as he waited among a number of +important and unimportant people in Count Arakcheev's waiting room. + +During his service, chiefly as an adjutant, Prince Andrew had seen +the anterooms of many important men, and the different types of such +rooms were well known to him. Count Arakcheev's anteroom had quite a +special character. The faces of the unimportant people awaiting +their turn for an audience showed embarrassment and servility; the +faces of those of higher rank expressed a common feeling of +awkwardness, covered by a mask of unconcern and ridicule of +themselves, their situation, and the person for whom they were +waiting. Some walked thoughtfully up and down, others whispered and +laughed. Prince Andrew heard the nickname "Sila Andreevich" and the +words, "Uncle will give it to us hot," in reference to Count +Arakcheev. One general (an important personage), evidently feeling +offended at having to wait so long, sat crossing and uncrossing his +legs and smiling contemptuously to himself. + +But the moment the door opened one feeling alone appeared on all +faces--that of fear. Prince Andrew for the second time asked the +adjutant on duty to take in his name, but received an ironical look +and was told that his turn would come in due course. After some others +had been shown in and out of the minister's room by the adjutant on +duty, an officer who struck Prince Andrew by his humiliated and +frightened air was admitted at that terrible door. This officer's +audience lasted a long time. Then suddenly the grating sound of a +harsh voice was heard from the other side of the door, and the +officer--with pale face and trembling lips--came out and passed +through the waiting room, clutching his head. + +After this Prince Andrew was conducted to the door and the officer +on duty said in a whisper, "To the right, at the window." + +Prince Andrew entered a plain tidy room and saw at the table a man +of forty with a long waist, a long closely cropped head, deep +wrinkles, scowling brows above dull greenish-hazel eyes and an +overhanging red nose. Arakcheev turned his head toward him without +looking at him. + +"What is your petition?" asked Arakcheev. + +"I am not petitioning, your excellency," returned Prince Andrew +quietly. + +Arakcheev's eyes turned toward him. + +"Sit down," said he. "Prince Bolkonski?" + +"I am not petitioning about anything. His Majesty the Emperor has +deigned to send your excellency a project submitted by me..." + +"You see, my dear sir, I have read your project," interrupted +Arakcheev, uttering only the first words amiably and then--again +without looking at Prince Andrew--relapsing gradually into a tone of +grumbling contempt. "You are proposing new military laws? There are +many laws but no one to carry out the old ones. Nowadays everybody +designs laws, it is easier writing than doing." + +"I came at His Majesty the Emperor's wish to learn from your +excellency how you propose to deal with the memorandum I have +presented," said Prince Andrew politely. + +"I have endorsed a resolution on your memorandum and sent it to +the committee. I do not approve of it," said Arakcheev, rising and +taking a paper from his writing table. "Here!" and he handed it to +Prince Andrew. + +Across the paper was scrawled in pencil, without capital letters, +misspelled, and without punctuation: "Unsoundly constructed because +resembles an imitation of the French military code and from the +Articles of War needlessly deviating." + +"To what committee has the memorandum been referred?" inquired +Prince Andrew. + +"To the Committee on Army Regulations, and I have recommended that +your honor should be appointed a member, but without a salary." + +Prince Andrew smiled. + +"I don't want one." + +"A member without salary," repeated Arakcheev. "I have the +honor... Eh! Call the next one! Who else is there?" he shouted, bowing +to Prince Andrew. + + + + + +CHAPTER V + + +While waiting for the announcement of his appointment to the +committee Prince Andrew looked up his former acquaintances, +particularly those he knew to be in power and whose aid he might need. +In Petersburg he now experienced the same feeling he had had on the +eve of a battle, when troubled by anxious curiosity and irresistibly +attracted to the ruling circles where the future, on which the fate of +millions depended, was being shaped. From the irritation of the +older men, the curiosity of the uninitiated, the reserve of the +initiated, the hurry and preoccupation of everyone, and the +innumerable committees and commissions of whose existence he learned +every day, he felt that now, in 1809, here in Petersburg a vast +civil conflict was in preparation, the commander in chief of which was +a mysterious person he did not know, but who was supposed to be a +man of genius--Speranski. And this movement of reconstruction of which +Prince Andrew had a vague idea, and Speranski its chief promoter, +began to interest him so keenly that the question of the army +regulations quickly receded to a secondary place in his consciousness. + +Prince Andrew was most favorably placed to secure good reception +in the highest and most diverse Petersburg circles of the day. The +reforming party cordially welcomed and courted him, the first place +because he was reputed to be clever and very well read, and secondly +because by liberating his serfs he had obtained the reputation of +being a liberal. The party of the old and dissatisfied, who censured +the innovations, turned to him expecting his sympathy in their +disapproval of the reforms, simply because he was the son of his +father. The feminine society world welcomed him gladly, because he was +rich, distinguished, a good match, and almost a newcomer, with a +halo of romance on account of his supposed death and the tragic loss +of his wife. Besides this the general opinion of all who had known him +previously was that he had greatly improved during these last five +years, having softened and grown more manly, lost his former +affectation, pride, and contemptuous irony, and acquired the +serenity that comes with years. People talked about him, were +interested in him, and wanted to meet him. + +The day after his interview with Count Arakcheev, Prince Andrew +spent the evening at Count Kochubey's. He told the count of his +interview with Sila Andreevich (Kochubey spoke of Arakcheev by that +nickname with the same vague irony Prince Andrew had noticed in the +Minister of War's anteroom). + +"Mon cher, even in this case you can't do without Michael +Mikhaylovich Speranski. He manages everything. I'll speak to him. He +has promised to come this evening." + +"What has Speranski to do with the army regulations?" asked Prince +Andrew. + +Kochubey shook his head smilingly, as if surprised at Bolkonski's +simplicity. + +"We were talking to him about you a few days ago," Kochubey +continued, "and about your freed plowmen." + +"Oh, is it you, Prince, who have freed your serfs?" said an old +man of Catherine's day, turning contemptuously toward Bolkonski. + +"It was a small estate that brought in no profit," replied Prince +Andrew, trying to extenuate his action so as not to irritate the old +man uselessly. + +"Afraid of being late..." said the old man, looking at Kochubey. + +"There's one thing I don't understand," he continued. "Who will plow +the land if they are set free? It is easy to write laws, but difficult +to rule.... Just the same as now--I ask you, Count--who will be +heads of the departments when everybody has to pass examinations?" + +"Those who pass the examinations, I suppose," replied Kochubey, +crossing his legs and glancing round. + +"Well, I have Pryanichnikov serving under me, a splendid man, a +priceless man, but he's sixty. Is he to go up for examination?" + +"Yes, that's a difficulty, as education is not at all general, +but..." + +Count Kochubey did not finish. He rose, took Prince Andrew by the +arm, and went to meet a tall, bald, fair man of about forty with a +large open forehead and a long face of unusual and peculiar whiteness, +who was just entering. The newcomer wore a blue swallow-tail coat with +a cross suspended from his neck and a star on his left breast. It +was Speranski. Prince Andrew recognized him at once, and felt a +throb within him, as happens at critical moments of life. Whether it +was from respect, envy, or anticipation, he did not know. +Speranski's whole figure was of a peculiar type that made him easily +recognizable. In the society in which Prince Andrew lived he had never +seen anyone who together with awkward and clumsy gestures possessed +such calmness and self-assurance; he had never seen so resolute yet +gentle an expression as that in those half-closed, rather humid +eyes, or so firm a smile that expressed nothing; nor had he heard such +a refined, smooth, soft voice; above all he had never seen such +delicate whiteness of face or hands--hands which were broad, but +very plump, soft, and white. Such whiteness and softness Prince Andrew +had only seen on the faces of soldiers who had been long in +hospital. This was Speranski, Secretary of State, reporter to the +Emperor and his companion at Erfurt, where he had more than once met +and talked with Napoleon. + +Speranski did not shift his eyes from one face to another as +people involuntarily do on entering a large company and was in no +hurry to speak. He spoke slowly, with assurance that he would be +listened to, and he looked only at the person with whom he was +conversing. + +Prince Andrew followed Speranski's every word and movement with +particular attention. As happens to some people, especially to men who +judge those near to them severely, he always on meeting anyone new- +especially anyone whom, like Speranski, he knew by reputation- +expected to discover in him the perfection of human qualities. + +Speranski told Kochubey he was sorry he had been unable to come +sooner as he had been detained at the palace. He did not say that +the Emperor had kept him, and Prince Andrew noticed this affectation +of modesty. When Kochubey introduced Prince Andrew, Speranski slowly +turned his eyes to Bolkonski with his customary smile and looked at +him in silence. + +"I am very glad to make your acquaintance. I had heard of you, as +everyone has," he said after a pause. + +Kochubey said a few words about the reception Arakcheev had given +Bolkonski. Speranski smiled more markedly. + +"The chairman of the Committee on Army Regulations is my good friend +Monsieur Magnitski," he said, fully articulating every word and +syllable, "and if you like I can put you in touch with him." He paused +at the full stop. "I hope you will find him sympathetic and ready to +co-operate in promoting all that is reasonable." + +A circle soon formed round Speranski, and the old man who had talked +about his subordinate Pryanichnikov addressed a question to him. + +Prince Andrew without joining in the conversation watched every +movement of Speranski's: this man, not long since an insignificant +divinity student, who now, Bolkonski thought, held in his hands--those +plump white hands--the fate of Russia. Prince Andrew was struck by the +extraordinarily disdainful composure with which Speranski answered the +old man. He appeared to address condescending words to him from an +immeasurable height. When the old man began to speak too loud, +Speranski smiled and said he could not judge of the advantage or +disadvantage of what pleased the sovereign. + +Having talked for a little while in the general circle, Speranski +rose and coming up to Prince Andrew took him along to the other end of +the room. It was clear that he thought it necessary to interest +himself in Bolkonski. + +"I had no chance to talk with you, Prince, during the animated +conversation in which that venerable gentleman involved me," he said +with a mildly contemptuous smile, as if intimating by that smile +that he and Prince Andrew understood the insignificance of the +people with whom he had just been talking. This flattered Prince +Andrew. "I have known of you for a long time: first from your action +with regard to your serfs, a first example, of which it is very +desirable that there should be more imitators; and secondly because +you are one of those gentlemen of the chamber who have not +considered themselves offended by the new decree concerning the +ranks allotted to courtiers, which is causing so much gossip and +tittle-tattle." + +"No," said Prince Andrew, "my father did not wish me to take +advantage of the privilege. I began the service from the lower grade." + +"Your father, a man of the last century, evidently stands above +our contemporaries who so condemn this measure which merely +reestablishes natural justice." + +"I think, however, that these condemnations have some ground," +returned Prince Andrew, trying to resist Speranski's influence, of +which he began to be conscious. He did not like to agree with him in +everything and felt a wish to contradict. Though he usually spoke +easily and well, he felt a difficulty in expressing himself now +while talking with Speranski. He was too much absorbed in observing +the famous man's personality. + +"Grounds of personal ambition maybe," Speranski put in quietly. + +"And of state interest to some extent," said Prince Andrew. + +"What do you mean?" asked Speranski quietly, lowering his eyes. + +"I am an admirer of Montesquieu," replied Prince Andrew, "and his +idea that le principe des monarchies est l'honneur me parait +incontestable. Certains droits et privileges de la noblesse me +paraissent etre des moyens de soutenir ce sentiment."* + + +*"The principle of monarchies is honor seems to me incontestable. +Certain rights and privileges for the aristocracy appear to me a means +of maintaining that sentiment." + + +The smile vanished from Speranski's white face, which was much +improved by the change. Probably Prince Andrew's thought interested +him. + +"Si vous envisagez la question sous ce point de vue,"* he began, +pronouncing French with evident difficulty, and speaking even slower +than in Russian but quite calmly. + + +*"If you regard the question from that point of view." + + +Speranski went on to say that honor, l'honeur, cannot be upheld by +privileges harmful to the service; that honor, l'honneur, is either +a negative concept of not doing what is blameworthy or it is a +source of emulation in pursuit of commendation and rewards, which +recognize it. His arguments were concise, simple, and clear. + +"An institution upholding honor, the source of emulation, is one +similar to the Legion d'honneur of the great Emperor Napoleon, not +harmful but helpful to the success of the service, but not a class +or court privilege." + +"I do not dispute that, but it cannot be denied that court +privileges have attained the same end," returned Prince Andrew. "Every +courtier considers himself bound to maintain his position worthily." + +"Yet you do not care to avail yourself of the privilege, Prince," +said Speranski, indicating by a smile that he wished to finish amiably +an argument which was embarrassing for his companion. "If you will +do me the honor of calling on me on Wednesday," he added, "I will, +after talking with Magnitski, let you know what may interest you, +and shall also have the pleasure of a more detailed chat with you." + +Closing his eyes, he bowed a la francaise, without taking leave, and +trying to attract as little attention as possible, he left the room. + + + + + +CHAPTER VI + + +During the first weeks of his stay in Petersburg Prince Andrew +felt the whole trend of thought he had formed during his life of +seclusion quite overshadowed by the trifling cares that engrossed +him in that city. + +On returning home in the evening he would jot down in his notebook +four or five necessary calls or appointments for certain hours. The +mechanism of life, the arrangement of the day so as to be in time +everywhere, absorbed the greater part of his vital energy. He did +nothing, did not even think or find time to think, but only talked, +and talked successfully, of what he had thought while in the country. + +He sometimes noticed with dissatisfaction that he repeated the +same remark on the same day in different circles. But he was so busy +for whole days together that he had no time to notice that he was +thinking of nothing. + +As he had done on their first meeting at Kochubey's, Speranski +produced a strong impression on Prince Andrew on the Wednesday, when +he received him tete-a-tate at his own house and talked to him long +and confidentially. + +To Bolkonski so many people appeared contemptible and +insignificant creatures, and he so longed to find in someone the +living ideal of that perfection toward which he strove, that he +readily believed that in Speranski he had found this ideal of a +perfectly rational and virtuous man. Had Speranski sprung from the +same class as himself and possessed the same breeding and +traditions, Bolkonski would soon have discovered his weak, human, +unheroic sides; but as it was, Speranski's strange and logical turn of +mind inspired him with respect all the more because he did not quite +understand him. Moreover, Speranski, either because he appreciated the +other's capacity or because he considered it necessary to win him to +his side, showed off his dispassionate calm reasonableness before +Prince Andrew and flattered him with that subtle flattery which goes +hand in hand with self-assurance and consists in a tacit assumption +that one's companion is the only man besides oneself capable of +understanding the folly of the rest of mankind and the +reasonableness and profundity of one's own ideas. + +During their long conversation on Wednesday evening, Speranski +more than once remarked: "We regard everything that is above the +common level of rooted custom..." or, with a smile: "But we want the +wolves to be fed and the sheep to be safe..." or: "They cannot +understand this..." and all in a way that seemed to say: "We, you +and I, understand what they are and who we are." + +This first long conversation with Speranski only strengthened in +Prince Andrew the feeling he had experienced toward him at their first +meeting. He saw in him a remarkable, clear-thinking man of vast +intellect who by his energy and persistence had attained power, +which he was using solely for the welfare of Russia. In Prince +Andrew's eyes Speranski was the man he would himself have wished to +be--one who explained all the facts of life reasonably, considered +important only what was rational, and was capable of applying the +standard of reason to everything. Everything seemed so simple and +clear in Speranski's exposition that Prince Andrew involuntarily +agreed with him about everything. If he replied and argued, it was +only because he wished to maintain his independence and not submit +to Speranski's opinions entirely. Everything was right and +everything was as it should be: only one thing disconcerted Prince +Andrew. This was Speranski's cold, mirrorlike look, which did not +allow one to penetrate to his soul, and his delicate white hands, +which Prince Andrew involuntarily watched as one does watch the +hands of those who possess power. This mirrorlike gaze and those +delicate hands irritated Prince Andrew, he knew not why. He was +unpleasantly struck, too, by the excessive contempt for others that he +observed in Speranski, and by the diversity of lines of argument he +used to support his opinions. He made use of every kind of mental +device, except analogy, and passed too boldly, it seemed to Prince +Andrew, from one to another. Now he would take up the position of a +practical man and condemn dreamers; now that of a satirist, and +laugh ironically at his opponents; now grow severely logical, or +suddenly rise to the realm of metaphysics. (This last resource was one +he very frequently employed.) He would transfer a question to +metaphysical heights, pass on to definitions of space, time, and +thought, and, having deduced the refutation he needed, would again +descend to the level of the original discussion. + +In general the trait of Speranski's mentality which struck Prince +Andrew most was his absolute and unshakable belief in the power and +authority of reason. It was evident that the thought could never occur +to him which to Prince Andrew seemed so natural, namely, that it is +after all impossible to express all one thinks; and that he had +never felt the doubt, "Is not all I think and believe nonsense?" And +it was just this peculiarity of Speranski's mind that particularly +attracted Prince Andrew. + +During the first period of their acquaintance Bolkonski felt a +passionate admiration for him similar to that which he had once felt +for Bonaparte. The fact that Speranski was the son of a village +priest, and that stupid people might meanly despise him on account +of his humble origin (as in fact many did), caused Prince Andrew to +cherish his sentiment for him the more, and unconsciously to +strengthen it. + +On that first evening Bolkonski spent with him, having mentioned the +Commission for the Revision of the Code of Laws, Speranski told him +sarcastically that the Commission had existed for a hundred and +fifty years, had cost millions, and had done nothing except that +Rosenkampf had stuck labels on the corresponding paragraphs of the +different codes. + +"And that is all the state has for the millions it has spent," +said he. "We want to give the Senate new juridical powers, but we have +no laws. That is why it is a sin for men like you, Prince, not to +serve in these times!" + +Prince Andrew said that for that work an education in +jurisprudence was needed which he did not possess. + +"But nobody possesses it, so what would you have? It is a vicious +circle from which we must break a way out." + +A week later Prince Andrew was a member of the Committee on Army +Regulations and--what he had not at all expected--was chairman of a +section of the committee for the revision of the laws. At +Speranski's request he took the first part of the Civil Code that +was being drawn up and, with the aid of the Code Napoleon and the +Institutes of Justinian, he worked at formulating the section on +Personal Rights. + + + + + +CHAPTER VII + + +Nearly two years before this, in 1808, Pierre on returning to +Petersburg after visiting his estates had involuntarily found +himself in a leading position among the Petersburg Freemasons. He +arranged dining and funeral lodge meetings, enrolled new members, +and busied himself uniting various lodges and acquiring authentic +charters. He gave money for the erection of temples and supplemented +as far as he could the collection of alms, in regard to which the +majority of members were stingy and irregular. He supported almost +singlehanded a poorhouse the order had founded in Petersburg. + +His life meanwhile continued as before, with the same infatuations +and dissipations. He liked to dine and drink well, and though he +considered it immoral and humiliating could not resist the temptations +of the bachelor circles in which he moved. + +Amid the turmoil of his activities and distractions, however, Pierre +at the end of a year began to feel that the more firmly he tried to +rest upon it, the more Masonic ground on which he stood gave way under +him. At the same time he felt that the deeper the ground sank under +him the closer bound he involuntarily became to the order. When he had +joined the Freemasons he had experienced the feeling of one who +confidently steps onto the smooth surface of a bog. When he put his +foot down it sank in. To make quite sure of the firmness the ground, +he put his other foot down and sank deeper still, became stuck in +it, and involuntarily waded knee-deep in the bog. + +Joseph Alexeevich was not in Petersburg--he had of late stood +aside from the affairs of the Petersburg lodges, and lived almost +entirely in Moscow. All the members of the lodges were men Pierre knew +in ordinary life, and it was difficult for him to regard them merely +as Brothers in Freemasonry and not as Prince B. or Ivan Vasilevich D., +whom he knew in society mostly as weak and insignificant men. Under +the Masonic aprons and insignia he saw the uniforms and decorations at +which they aimed in ordinary life. Often after collecting alms, and +reckoning up twenty to thirty rubles received for the most part in +promises from a dozen members, of whom half were as well able to pay +as himself, Pierre remembered the Masonic vow in which each Brother +promised to devote all his belongings to his neighbor, and doubts on +which he tried not to dwell arose in his soul. + +He divided the Brothers he knew into four categories. In the first +he put those who did not take an active part in the affairs of the +lodges or in human affairs, but were exclusively occupied with the +mystical science of the order: with questions of the threefold +designation of God, the three primordial elements--sulphur, mercury, +and salt--or the meaning of the square and all the various figures +of the temple of Solomon. Pierre respected this class of Brothers to +which the elder ones chiefly belonged, including, Pierre thought, +Joseph Alexeevich himself, but he did not share their interests. His +heart was not in the mystical aspect of Freemasonry. + +In the second category Pierre reckoned himself and others like +him, seeking and vacillating, who had not yet found in Freemasonry a +straight and comprehensible path, but hoped to do so. + +In the third category he included those Brothers (the majority) +who saw nothing in Freemasonry but the external forms and +ceremonies, and prized the strict performance of these forms without +troubling about their purport or significance. Such were Willarski and +even the Grand Master of the principal lodge. + +Finally, to the fourth category also a great many Brothers belonged, +particularly those who had lately joined. These according to +Pierre's observations were men who had no belief in anything, nor +desire for anything, but joined the Freemasons merely to associate +with the wealthy young Brothers who were influential through their +connections or rank, and of whom there were very many in the lodge. + +Pierre began to feel dissatisfied with what he was doing. +Freemasonry, at any rate as he saw it here, sometimes seemed to him +based merely on externals. He did not think of doubting Freemasonry +itself, but suspected that Russian Masonry had taken a wrong path +and deviated from its original principles. And so toward the end of +the year he went abroad to be initiated into the higher secrets of the +order. + +In the summer of 1809 Pierre returned to Petersburg. Our +Freemasons knew from correspondence with those abroad that Bezukhov +had obtained the confidence of many highly placed persons, had been +initiated into many mysteries, had been raised to a higher grade, +and was bringing back with him much that might conduce to the +advantage of the Masonic cause in Russia. The Petersburg Freemasons +all came to see him, tried to ingratiate themselves with him, and it +seemed to them all that he was preparing something for them and +concealing it. + +A solemn meeting of the lodge of the second degree was convened, +at which Pierre promised to communicate to the Petersburg Brothers +what he had to deliver to them from the highest leaders of their +order. The meeting was a full one. After the usual ceremonies Pierre +rose and began his address. + +"Dear Brothers," he began, blushing and stammering, with a written +speech in his hand, "it is not sufficient to observe our mysteries +in the seclusion of our lodge--we must act--act! We are drowsing, +but we must act." Pierre raised his notebook and began to read. + +"For the dissemination of pure truth and to secure the triumph of +virtue," he read, "we must cleanse men from prejudice, diffuse +principles in harmony with the spirit of the times, undertake the +education of the young, unite ourselves in indissoluble bonds with the +wisest men, boldly yet prudently overcome superstitions, infidelity, +and folly, and form of those devoted to us a body linked together by +unity of purpose and possessed of authority and power. + +"To attain this end we must secure a preponderance of virtue over +vice and must endeavor to secure that the honest man may, even in this +world, receive a lasting reward for his virtue. But in these great +endeavors we are gravely hampered by the political institutions of +today. What is to be done in these circumstances? To favor +revolutions, overthrow everything, repel force by force?... No! We are +very far from that. Every violent reform deserves censure, for it +quite fails to remedy evil while men remain what they are, and also +because wisdom needs no violence. + +"The whole plan of our order should be based on the idea of +preparing men of firmness and virtue bound together by unity of +conviction--aiming at the punishment of vice and folly, and +patronizing talent and virtue: raising worthy men from the dust and +attaching them to our Brotherhood. Only then will our order have the +power unobtrusively to bind the hands of the protectors of disorder +and to control them without their being aware of it. In a word, we +must found a form of government holding universal sway, which should +be diffused over the whole world without destroying the bonds of +citizenship, and beside which all other governments can continue in +their customary course and do everything except what impedes the great +aim of our order, which is to obtain for virtue the victory over vice. +This aim was that of Christianity itself. It taught men to be wise and +good and for their own benefit to follow the example and instruction +of the best and wisest men. + +"At that time, when everything was plunged in darkness, preaching +alone was of course sufficient. The novelty of Truth endowed her +with special strength, but now we need much more powerful methods. +It is now necessary that man, governed by his senses, should find in +virtue a charm palpable to those senses. It is impossible to eradicate +the passions; but we must strive to direct them to a noble aim, and it +is therefore necessary that everyone should be able to satisfy his +passions within the limits of virtue. Our order should provide means +to that end. + +"As soon as we have a certain number of worthy men in every state, +each of them again training two others and all being closely united, +everything will be possible for our order, which has already in secret +accomplished much for the welfare of mankind." + +This speech not only made a strong impression, but created +excitement in the lodge. The majority of the Brothers, seeing in it +dangerous designs of Illuminism,* met it with a coldness that +surprised Pierre. The Grand Master began answering him, and Pierre +began developing his views with more and more warmth. It was long +since there had been so stormy a meeting. Parties were formed, some +accusing Pierre of Illuminism, others supporting him. At that +meeting he was struck for the first time by the endless variety of +men's minds, which prevents a truth from ever presenting itself +identically to two persons. Even those members who seemed to be on his +side understood him in their own way with limitations and +alterations he could not agree to, as what he always wanted most was +to convey his thought to others just as he himself understood it. + + +*The Illuminati sought to substitute republican for monarchical +institutions. + + +At the end of the meeting the Grand Master with irony and ill-will +reproved Bezukhov for his vehemence and said it was not love of virtue +alone, but also a love of strife that had moved him in the dispute. +Pierre did not answer him and asked briefly whether his proposal would +be accepted. He was told that it would not, and without waiting for +the usual formalities he left the lodge and went home. + + + + + +CHAPTER VIII + + +Again Pierre was overtaken by the depression he so dreaded. For +three days after the delivery of his speech at the lodge he lay on a +sofa at home receiving no one and going nowhere. + +It was just then that he received a letter from his wife, who +implored him to see her, telling him how grieved she was about him and +how she wished to devote her whole life to him. + +At the end of the letter she informed him that in a few days she +would return to Petersburg from abroad. + +Following this letter one of the Masonic Brothers whom Pierre +respected less than the others forced his way in to see him and, +turning the conversation upon Pierre's matrimonial affairs, by way +of fraternal advice expressed the opinion that his severity to his +wife was wrong and that he was neglecting one of the first rules of +Freemasonry by not forgiving the penitent. + +At the same time his mother-in-law, Prince Vasili's wife, sent to +him imploring him to come if only for a few minutes to discuss a +most important matter. Pierre saw that there was a conspiracy +against him and that they wanted to reunite him with his wife, and +in the mood he then was, this was not even unpleasant to him. +Nothing mattered to him. Nothing in life seemed to him of much +importance, and under the influence of the depression that possessed +him he valued neither his liberty nor his resolution to punish his +wife. + +"No one is right and no one is to blame; so she too is not to +blame," he thought. + +If he did not at once give his consent to a reunion with his wife, +it was only because in his state of depression he did not feel able to +take any step. Had his wife come to him, he would not have turned +her away. Compared to what preoccupied him, was it not a matter of +indifference whether he lived with his wife or not? + +Without replying either to his wife or his mother-in-law, Pierre +late one night prepared for a journey and started for Moscow to see +Joseph Alexeevich. This is what he noted in his diary: + + +Moscow, 17th November + +I have just returned from my benefactor, and hasten to write down +what I have experienced. Joseph Alexeevich is living poorly and has +for three years been suffering from a painful disease of the +bladder. No one has ever heard him utter a groan or a word of +complaint. From morning till late at night, except when he eats his +very plain food, he is working at science. He received me graciously +and made me sit down on the bed on which he lay. I made the sign of +the Knights of the East and of Jerusalem, and he responded in the same +manner, asking me with a mild smile what I had learned and gained in +the Prussian and Scottish lodges. I told him everything as best I +could, and told him what I had proposed to our Petersburg lodge, of +the bad reception I had encountered, and of my rupture with the +Brothers. Joseph Alexeevich, having remained silent and thoughtful for +a good while, told me his view of the matter, which at once lit up for +me my whole past and the future path I should follow. He surprised +me by asking whether I remembered the threefold aim of the order: +(1) The preservation and study of the mystery. (2) The purification +and reformation of oneself for its reception, and (3) The +improvement of the human race by striving for such purification. Which +is the principal aim of these three? Certainly self-reformation and +self-purification. Only to this aim can we always strive independently +of circumstances. But at the same time just this aim demands the +greatest efforts of us; and so, led astray by pride, losing sight of +this aim, we occupy ourselves either with the mystery which in our +impurity we are unworthy to receive, or seek the reformation of the +human race while ourselves setting an example of baseness and +profligacy. Illuminism is not a pure doctrine, just because it is +attracted by social activity and puffed up by pride. On this ground +Joseph Alexeevich condemned my speech and my whole activity, and in +the depth of my soul I agreed with him. Talking of my family affairs +he said to me, "the chief duty of a true Mason, as I have told you, +lies in perfecting himself. We often think that by removing all the +difficulties of our life we shall more quickly reach our aim, but on +the contrary, my dear sir, it is only in the midst of worldly cares +that we can attain our three chief aims: (1) Self-knowledge--for man +can only know himself by comparison, (2) Self-perfecting, which can +only be attained by conflict, and (3) The attainment of the chief +virtue--love of death. Only the vicissitudes of life can show us its +vanity and develop our innate love of death or of rebirth to a new +life." These words are all the more remarkable because, in spite of +his great physical sufferings, Joseph Alexeevich is never weary of +life though he loves death, for which--in spite of the purity and +loftiness of his inner man--he does not yet feel himself +sufficiently prepared. My benefactor then explained to me fully the +meaning of the Great Square of creation and pointed out to me that the +numbers three and seven are the basis of everything. He advised me not +to avoid intercourse with the Petersburg Brothers, but to take up only +second-grade posts in the lodge, to try, while diverting the +Brothers from pride, to turn them toward the true path +self-knowledge and self-perfecting. Besides this he advised me for +myself personally above all to keep a watch over myself, and to that +end he gave me a notebook, the one I am now writing in and in which +I will in future note down all my actions. + + +Petersburg, 23rd November + +I am again living with my wife. My mother-in-law came to me in tears +and said that Helene was here and that she implored me to hear her; +that she was innocent and unhappy at my desertion, and much more. I +knew that if I once let myself see her I should not have strength to +go on refusing what she wanted. In my perplexity I did not know +whose aid and advice to seek. Had my benefactor been here he would +have told me what to do. I went to my room and reread Joseph +Alexeevich's letters and recalled my conversations with him, and +deduced from it all that I ought not to refuse a suppliant, and +ought to reach a helping hand to everyone--especially to one so +closely bound to me--and that I must bear my cross. But if I forgive +her for the sake of doing right, then let union with her have only a +spiritual aim. That is what I decided, and what I wrote to Joseph +Alexeevich. I told my wife that I begged her to forget the past, to +forgive me whatever wrong I may have done her, and that I had +nothing to forgive. It gave me joy to tell her this. She need not know +how hard it was for me to see her again. I have settled on the upper +floor of this big house and am experiencing a happy feeling of +regeneration. + + + + + +CHAPTER IX + + +At that time, as always happens, the highest society that met at +court and at the grand balls was divided into several circles, each +with its own particular tone. The largest of these was the French +circle of the Napoleonic alliance, the circle of Count Rumyantsev +and Caulaincourt. In this group Helene, as soon as she had settled +in Petersburg with her husband, took a very prominent place. She was +visited by the members of the French embassy and by many belonging +to that circle and noted for their intellect and polished manners. + +Helene had been at Erfurt during the famous meeting of the +Emperors and had brought from there these connections with the +Napoleonic notabilities. At Erfurt her success had been brilliant. +Napoleon himself had noticed her in the theater and said of her: +"C'est un superbe animal."* Her success as a beautiful and elegant +woman did not surprise Pierre, for she had become even handsomer +than before. What did surprise him was that during these last two +years his wife had succeeded in gaining the reputation "d' une femme +charmante, aussi spirituelle que belle."*[2] The distinguished +Prince de Ligne wrote her eight-page letters. Bilibin saved up his +epigrams to produce them in Countess Bezukhova's presence. To be +received in the Countess Bezukhova's salon was regarded as a diploma +of intellect. Young men read books before attending Helene's evenings, +to have something to say in her salon, and secretaries of the embassy, +and even ambassadors, confided diplomatic secrets to her, so that in a +way Helene was a power. Pierre, who knew she was very stupid, +sometimes attended, with a strange feeling of perplexity and fear, her +evenings and dinner parties, where politics, poetry, and philosophy +were discussed. At these parties his feelings were like those of a +conjuror who always expects his trick to be found out at any moment. +But whether because stupidity was just what was needed to run such a +salon, or because those who were deceived found pleasure in the +deception, at any rate it remained unexposed and Helene Bezukhova's +reputation as a lovely and clever woman became so firmly established +that she could say the emptiest and stupidest things and everybody +would go into raptures over every word of hers and look for a profound +meaning in it of which she herself had no conception. + + +*"That's a superb animal." + +*[2] "Of a charming woman, as witty as she is lovely." + + +Pierre was just the husband needed for a brilliant society woman. He +was that absent-minded crank, a grand seigneur husband who was in no +one's way, and far from spoiling the high tone and general +impression of the drawing room, he served, by the contrast he +presented to her, as an advantageous background to his elegant and +tactful wife. Pierre during the last two years, as a result of his +continual absorption in abstract interests and his sincere contempt +for all else, had acquired in his wife's circle, which did not +interest him, that air of unconcern, indifference, and benevolence +toward all, which cannot be acquired artificially and therefore +inspires involuntary respect. He entered his wife's drawing room as +one enters a theater, was acquainted with everybody, equally pleased +to see everyone, and equally indifferent to them all. Sometimes he +joined in a conversation which interested him and, regardless of +whether any "gentlemen of the embassy" were present or not, +lispingly expressed his views, which were sometimes not at all in +accord with the accepted tone of the moment. But the general opinion +concerning the queer husband of "the most distinguished woman in +Petersburg" was so well established that no one took his freaks +seriously. + +Among the many young men who frequented her house every day, Boris +Drubetskoy, who had already achieved great success in the service, was +the most intimate friend of the Bezukhov household since Helene's +return from Erfurt. Helene spoke of him as "mon page" and treated +him like a child. Her smile for him was the same as for everybody, but +sometimes that smile made Pierre uncomfortable. Toward him Boris +behaved with a particularly dignified and sad deference. This shade of +deference also disturbed Pierre. He had suffered so painfully three +years before from the mortification to which his wife had subjected +him that he now protected himself from the danger of its repetition, +first by not being a husband to his wife, and secondly by not allowing +himself to suspect. + +"No, now that she has become a bluestocking she has finally +renounced her former infatuations," he told himself. "There has +never been an instance of a bluestocking being carried away by affairs +of the heart"--a statement which, though gathered from an unknown +source, he believed implicitly. Yet strange to say Boris' presence +in his wife's drawing room (and he was almost always there) had a +physical effect upon Pierre; it constricted his limbs and destroyed +the unconsciousness and freedom of his movements. + +"What a strange antipathy," thought Pierre, "yet I used to like +him very much." + +In the eyes of the world Pierre was a great gentleman, the rather +blind and absurd husband of a distinguished wife, a clever crank who +did nothing but harmed nobody and was a first-rate, good-natured +fellow. But a complex and difficult process of internal development +was taking place all this time in Pierre's soul, revealing much to him +and causing him many spiritual doubts and joys. + + + + + +CHAPTER X + + +Pierre went on with his diary, and this is what he wrote in it +during that time: + + +24th November + +Got up at eight, read the Scriptures, then went to my duties. [By +Joseph Alexeevich's advice Pierre had entered the service of the state +and served on one of the committees.] Returned home for dinner and +dined alone--the countess had many visitors I do not like. I ate and +drank moderately and after dinner copied out some passages for the +Brothers. In the evening I went down to the countess and told a +funny story about B., and only remembered that I ought not to have +done so when everybody laughed loudly at it. + +I am going to bed with a happy and tranquil mind. Great God, help me +to walk in Thy paths, (1) to conquer anger by calmness and +deliberation, (2) to vanquish lust by self-restraint and repulsion, +(3) to withdraw from worldliness, but not avoid (a) the service of the +state, (b) family duties, (c) relations with my friends, and the +management of my affairs. + + +27th November + +I got up late. On waking I lay long in bed yielding to sloth. O God, +help and strengthen me that I may walk in Thy ways! Read the +Scriptures, but without proper feeling. Brother Urusov came and we +talked about worldly vanities. He told me of the Emperor's new +projects. I began to criticize them, but remembered my rules and my +benefactor's words--that a true Freemason should be a zealous worker +for the state when his aid is required and a quiet onlooker when not +called on to assist. My tongue is my enemy. Brothers G. V. and O. +visited me and we had a preliminary talk about the reception of a +new Brother. They laid on me the duty of Rhetor. I feel myself weak +and unworthy. Then our talk turned to the interpretation of the +seven pillars and steps of the Temple, the seven sciences, the seven +virtues, the seven vices, and the seven gifts of the Holy Spirit. +Brother O. was very eloquent. In the evening the admission took place. +The new decoration of the Premises contributed much to the +magnificence of the spectacle. It was Boris Drubetskoy who was +admitted. I nominated him and was the Rhetor. A strange feeling +agitated me all the time I was alone with him in the dark chamber. I +caught myself harboring a feeling of hatred toward him which I +vainly tried to overcome. That is why I should really like to save him +from evil and lead him into the path of truth, but evil thoughts of +him did not leave me. It seemed to me that his object in entering +the Brotherhood was merely to be intimate and in favor with members of +our lodge. Apart from the fact that he had asked me several times +whether N. and S. were members of our lodge (a question to which I +could not reply) and that according to my observation he is +incapable of feeling respect for our holy order and is too preoccupied +and satisfied with the outer man to desire spiritual improvement, I +had no cause to doubt him, but he seemed to me insincere, and all +the time I stood alone with him in the dark temple it seemed to me +that he was smiling contemptuously at my words, and I wished really to +stab his bare breast with the sword I held to it. I could not be +eloquent, nor could I frankly mention my doubts to the Brothers and to +the Grand Master. Great Architect of Nature, help me to find the +true path out of the labyrinth of lies! + + + After this, three pages were left blank in the diary, and then +the following was written: + + +I have had a long and instructive talk alone with Brother V., who +advised me to hold fast by brother A. Though I am unworthy, much was +revealed to me. Adonai is the name of the creator of the world. Elohim +is the name of the ruler of all. The third name is the name +unutterable which means the All. Talks with Brother V. strengthen, +refresh, and support me in the path of virtue. In his presence doubt +has no place. The distinction between the poor teachings of mundane +science and our sacred all-embracing teaching is clear to me. Human +sciences dissect everything to comprehend it, and kill everything to +examine it. In the holy science of our order all is one, all is +known in its entirety and life. The Trinity--the three elements of +matter--are sulphur, mercury, and salt. Sulphur is of an oily and +fiery nature; in combination with salt by its fiery nature it +arouses a desire in the latter by means of which it attracts +mercury, seizes it, holds it, and in combination produces other +bodies. Mercury is a fluid, volatile, spiritual essence. Christ, the +Holy Spirit, Him!... + + +3rd December + +Awoke late, read the Scriptures but was apathetic. Afterwards went +and paced up and down the large hall. I wished to meditate, but +instead my imagination pictured an occurrence of four years ago, +when Dolokhov, meeting me in Moscow after our duel, said he hoped I +was enjoying perfect peace of mind in spite of my wife's absence. At +the time I gave him no answer. Now I recalled every detail of that +meeting and in my mind gave him the most malevolent and bitter +replies. I recollected myself and drove away that thought only when +I found myself glowing with anger, but I did not sufficiently +repent. Afterwards Boris Drubetskoy came and began relating various +adventures. His coming vexed me from the first, and I said something +disagreeable to him. He replied. I flared up and said much that was +unpleasant and even rude to him. He became silent, and I recollected +myself only when it was too late. My God, I cannot get on with him +at all. The cause of this is my egotism. I set myself above him and so +become much worse than he, for he is lenient to my rudeness while I on +the contrary nourish contempt for him. O God, grant that in his +presence I may rather see my own vileness, and behave so that he too +may benefit. After dinner I fell asleep and as I was drowsing off I +clearly heard a voice saying in my left ear, "Thy day!" + +I dreamed that I was walking in the dark and was suddenly surrounded +by dogs, but I went on undismayed. Suddenly a smallish dog seized my +left thigh with its teeth and would not let go. I began to throttle it +with my hands. Scarcely had I torn it off before another, a bigger +one, began biting me. I lifted it up, but the higher I lifted it the +bigger and heavier it grew. And suddenly Brother A. came and, taking +my arm, led me to a building to enter which we had to pass along a +narrow plank. I stepped on it, but it bent and gave way and I began to +clamber up a fence which I could scarcely reach with my hands. After +much effort I dragged myself up, so that my leg hung down on one +side and my body on the other. I looked round and saw Brother A. +standing on the fence and pointing me to a broad avenue and garden, +and in the garden was a large and beautiful building. I woke up. O +Lord, great Architect of Nature, help me to tear from myself these +dogs--my passions especially the last, which unites in itself the +strength of all the former ones, and aid me to enter that temple of +virtue to a vision of which I attained in my dream. + + +7th December + +I dreamed that Joseph Alexeevich was sitting in my house, and that I +was very glad and wished to entertain him. It seemed as if I chattered +incessantly with other people and suddenly remembered that this +could not please him, and I wished to come close to him and embrace +him. But as soon as I drew near I saw that his face had changed and +grown young, and he was quietly telling me something about the +teaching of our order, but so softly that I could not hear it. Then it +seemed that we all left the room and something strange happened. We +were sitting or lying on the floor. He was telling me something, and I +wished to show him my sensibility, and not listening to what he was +saying I began picturing to myself the condition of my inner man and +the grace of God sanctifying me. And tears came into my eyes, and I +was glad he noticed this. But he looked at me with vexation and jumped +up, breaking off his remarks. I felt abashed and asked whether what he +had been saying did not concern me; but he did not reply, gave me a +kind look, and then we suddenly found ourselves in my bedroom where +there is a double bed. He lay down on the edge of it and I burned with +longing to caress him and lie down too. And he said, "Tell me +frankly what is your chief temptation? Do you know it? I think you +know it already." Abashed by this question, I replied that sloth was +my chief temptation. He shook his head incredulously; and even more +abashed, I said that though I was living with my wife as he advised, I +was not living with her as her husband. To this he replied that one +should not deprive a wife of one's embraces and gave me to +understand that that was my duty. But I replied that I should be +ashamed to do it, and suddenly everything vanished. And I awoke and +found in my mind the text from the Gospel: "The life was the light +of men. And the light shineth in darkness; and the darkness +comprehended it not." Joseph Alexeevich's face had looked young and +bright. That day I received a letter from my benefactor in which he +wrote about "conjugal duties." + + +9th December + +I had a dream from which I awoke with a throbbing heart. I saw +that I was in Moscow in my house, in the big sitting room, and +Joseph Alexeevich came in from the drawing room. I seemed to know at +once that the process of regeneration had already taken place in +him, and I rushed to meet him. I embraced him and kissed his hands, +and he said, "Hast thou noticed that my face is different?" I looked +at him, still holding him in my arms, and saw that his face was young, +but that he had no hair on his head and his features were quite +changed. And I said, "I should have known you had I met you by +chance," and I thought to myself, "Am I telling the truth?" And +suddenly I saw him lying like a dead body; then he gradually recovered +and went with me into my study carrying a large book of sheets of +drawing paper; I said, "I drew that," and he answered by bowing his +head. I opened the book, and on all the pages there were excellent +drawings. And in my dream I knew that these drawings represented the +love adventures of the soul with its beloved. And on its pages I saw a +beautiful representation of a maiden in transparent garments and +with a transparent body, flying up to the clouds. And I seemed to know +that this maiden was nothing else than a representation of the Song of +Songs. And looking at those drawings I dreamed I felt that I was doing +wrong, but could not tear myself away from them. Lord, help me! My +God, if Thy forsaking me is Thy doing, Thy will be done; but if I am +myself the cause, teach me what I should do! I shall perish of my +debauchery if Thou utterly desertest me! + + + + + +CHAPTER XI + + +The Rostovs' monetary affairs had not improved during the two +years they had spent in the country. + +Though Nicholas Rostov had kept firmly to his resolution and was +still serving modestly in an obscure regiment, spending +comparatively little, the way of life at Otradnoe--Mitenka's +management of affairs, in particular--was such that the debts +inevitably increased every year. The only resource obviously +presenting itself to the old count was to apply for an official +post, so he had come to Petersburg to look for one and also, as he +said, to let the lassies enjoy themselves for the last time. + +Soon after their arrival in Petersburg Berg proposed to Vera and was +accepted. + +Though in Moscow the Rostovs belonged to the best society without +themselves giving it a thought, yet in Petersburg their circle of +acquaintances was a mixed and indefinite one. In Petersburg they +were provincials, and the very people they had entertained in Moscow +without inquiring to what set they belonged, here looked down on them. + +The Rostovs lived in the same hospitable way in Petersburg as in +Moscow, and the most diverse people met at their suppers. Country +neighbors from Otradnoe, impoverished old squires and their daughters, +Peronskaya a maid of honor, Pierre Bezukhov, and the son of their +district postmaster who had obtained a post in Petersburg. Among the +men who very soon became frequent visitors at the Rostovs' house in +Petersburg were Boris, Pierre whom the count had met in the street and +dragged home with him, and Berg who spent whole days at the Rostovs' +and paid the eldest daughter, Countess Vera, the attentions a young +man pays when he intends to propose. + +Not in vain had Berg shown everybody his right hand wounded at +Austerlitz and held a perfectly unnecessary sword in his left. He +narrated that episode so persistently and with so important an air +that everyone believed in the merit and usefulness of his deed, and he +had obtained two decorations for Austerlitz. + +In the Finnish war he also managed to distinguish himself. He had +picked up the scrap of a grenade that had killed an aide-de-camp +standing near the commander in chief and had taken it to his +commander. Just as he had done after Austerlitz, he related this +occurrence at such length and so insistently that everyone again +believed it had been necessary to do this, and he received two +decorations for the Finnish war also. In 1809 he was a captain in +the Guards, wore medals, and held some special lucrative posts in +Petersburg. + +Though some skeptics smiled when told of Berg's merits, it could not +be denied that he was a painstaking and brave officer, on excellent +terms with his superiors, and a moral young man with a brilliant +career before him and an assured position in society. + +Four years before, meeting a German comrade in the stalls of a +Moscow theater, Berg had pointed out Vera Rostova to him and had +said in German, "das soll mein Weib werden,"* and from that moment had +made up his mind to marry her. Now in Petersburg, having considered +the Rostovs' position and his own, he decided that the time had come +to propose. + + +*"That girl shall be my wife." + + +Berg's proposal was at first received with a perplexity that was not +flattering to him. At first it seemed strange that the son of an +obscure Livonian gentleman should propose marriage to a Countess +Rostova; but Berg's chief characteristic was such a naive and good +natured egotism that the Rostovs involuntarily came to think it +would be a good thing, since he himself was so firmly convinced that +it was good, indeed excellent. Moreover, the Rostovs' affairs were +seriously embarrassed, as the suitor could not but know; and above +all, Vera was twenty-four, had been taken out everywhere, and though +she was certainly good-looking and sensible, no one up to now had +proposed to her. So they gave their consent. + +"You see," said Berg to his comrade, whom he called "friend" only +because he knew that everyone has friends, "you see, I have considered +it all, and should not marry if I had not thought it all out or if +it were in any way unsuitable. But on the contrary, my papa and +mamma are now provided for--I have arranged that rent for them in +the Baltic Provinces--and I can live in Petersburg on my pay, and with +her fortune and my good management we can get along nicely. I am not +marrying for money--I consider that dishonorable--but a wife should +bring her share and a husband his. I have my position in the +service, she has connections and some means. In our times that is +worth something, isn't it? But above all, she is a handsome, estimable +girl, and she loves me..." + +Berg blushed and smiled. + +"And I love her, because her character is sensible and very good. +Now the other sister, though they are the same family, is quite +different--an unpleasant character and has not the same +intelligence. She is so... you know?... Unpleasant... But my +fiancee!... Well, you will be coming," he was going to say, "to dine," +but changed his mind and said "to take tea with us," and quickly +doubling up his tongue he blew a small round ring of tobacco smoke, +perfectly embodying his dream of happiness. + +After the first feeling of perplexity aroused in the parents by +Berg's proposal, the holiday tone of joyousness usual at such times +took possession of the family, but the rejoicing was external and +insincere. In the family's feeling toward this wedding a certain +awkwardness and constraint was evident, as if they were ashamed of not +having loved Vera sufficiently and of being so ready to get her off +their hands. The old count felt this most. He would probably have been +unable to state the cause of his embarrassment, but it resulted from +the state of his affairs. He did not know at all how much he had, what +his debts amounted to, or what dowry he could give Vera. When his +daughters were born he had assigned to each of them, for her dowry, an +estate with three hundred serfs; but one of these estates had +already been sold, and the other was mortgaged and the interest so +much in arrears that it would have to be sold, so that it was +impossible to give it to Vera. Nor had he any money. + +Berg had already been engaged a month, and only a week remained +before the wedding, but the count had not yet decided in his own +mind the question of the dowry, nor spoken to his wife about it. At +one time the count thought of giving her the Ryazan estate or of +selling a forest, at another time of borrowing money on a note of +hand. A few days before the wedding Berg entered the count's study +early one morning and, with a pleasant smile, respectfully asked his +future father-in-law to let him know what Vera's dowry would be. The +count was so disconcerted by this long-foreseen inquiry that without +consideration he gave the first reply that came into his head. "I like +your being businesslike about it.... I like it. You shall be +satisfied...." + +And patting Berg on the shoulder he got up, wishing to end the +conversation. But Berg, smiling pleasantly, explained that if he did +not know for certain how much Vera would have and did not receive at +least part of the dowry in advance, he would have to break matters +off. + +"Because, consider, Count--if I allowed myself to marry now +without having definite means to maintain my wife, I should be +acting badly...." + +The conversation ended by the count, who wished to be generous and +to avoid further importunity, saying that he would give a note of hand +for eighty thousand rubles. Berg smiled meekly, kissed the count on +the shoulder, and said that he was very grateful, but that it was +impossible for him to arrange his new life without receiving thirty +thousand in ready money. "Or at least twenty thousand, Count," he +added, "and then a note of hand for only sixty thousand." + +"Yes, yes, all right!" said the count hurriedly. "Only excuse me, my + +dear fellow, I'll give you twenty thousand and a note of hand for +eighty thousand as well. Yes, yes! Kiss me." + + + + + +CHAPTER XII + + +Natasha was sixteen and it was the year 1809, the very year to which +she had counted on her fingers with Boris after they had kissed four +years ago. Since then she had not seen him. Before Sonya and her +mother, if Boris happened to be mentioned, she spoke quite freely of +that episode as of some childish, long-forgotten matter that was not +worth mentioning. But in the secret depths of her soul the question +whether her engagement to Boris was a jest or an important, binding +promise tormented her. + +Since Boris left Moscow in 1805 to join the army he had had not seen +the Rostovs. He had been in Moscow several times, and had passed +near Otradnoe, but had never been to see them. + +Sometimes it occurred to Natasha that he not wish to see her, and +this conjecture was confirmed by the sad tone in which her elders +spoke of him. + +"Nowadays old friends are not remembered," the countess would say +when Boris was mentioned. + +Anna Mikhaylovna also had of late visited them less frequently, +seemed to hold herself with particular dignity, and always spoke +rapturously and gratefully of the merits of her son and the +brilliant career on which he had entered. When the Rostovs came to +Petersburg Boris called on them. + +He drove to their house in some agitation. The memory of Natasha was +his most poetic recollection. But he went with the firm intention of +letting her and her parents feel that the childish relations between +himself and Natasha could not be binding either on her or on him. He +had a brilliant position in society thanks to his intimacy with +Countess Bezukhova, a brilliant position in the service thanks to +the patronage of an important personage whose complete confidence he +enjoyed, and he was beginning to make plans for marrying one of the +richest heiresses in Petersburg, plans which might very easily be +realized. When he entered the Rostovs' drawing room Natasha was in her +own room. When she heard of his arrival she almost ran into the +drawing room, flushed and beaming with a more than cordial smile. + +Boris remembered Natasha in a short dress, with dark eyes shining +from under her curls and boisterous, childish laughter, as he had +known her four years before; and so he was taken aback when quite a +different Natasha entered, and his face expressed rapturous +astonishment. This expression on his face pleased Natasha. + +"Well, do you recognize your little madcap playmate?" asked the +countess. + +Boris kissed Natasha's hand and said that he was astonished at the +change in her. + +"How handsome you have grown!" + +"I should think so!" replied Natasha's laughing eyes. + +"And is Papa older?" she asked. + +Natasha sat down and, without joining in Boris' conversation with +the countess, silently and minutely studied her childhood's suitor. He +felt the weight of that resolute and affectionate scrutiny and glanced +at her occasionally. + +Boris' uniform, spurs, tie, and the way his hair was brushed were +all comme il faut and in the latest fashion. This Natasha noticed at +once. He sat rather sideways in the armchair next to the countess, +arranging with his right hand the cleanest of gloves that fitted his +left hand like a skin, and he spoke with a particularly refined +compression of his lips about the amusements of the highest Petersburg +society, recalling with mild irony old times in Moscow and Moscow +acquaintances. It was not accidentally, Natasha felt, that he alluded, +when speaking of the highest aristocracy, to an ambassador's ball he +had attended, and to invitations he had received from N.N. and S.S. + +All this time Natasha sat silent, glancing up at him from under +her brows. This gaze disturbed and confused Boris more and more. He +looked round more frequently toward her, and broke off in what he +was saying. He did not stay more than ten minutes, then rose and +took his leave. The same inquisitive, challenging, and rather +mocking eyes still looked at him. After his first visit Boris said +to himself that Natasha attracted him just as much as ever, but that +he must not yield to that feeling, because to marry her, a girl almost +without fortune, would mean ruin to his career, while to renew their +former relations without intending to marry her would be dishonorable. +Boris made up his mind to avoid meeting Natasha, but despite that +resolution he called again a few days later and began calling often +and spending whole days at the Rostovs'. It seemed to him that he +ought to have an explanation with Natasha and tell her that the old +times must be forgotten, that in spite of everything... she could +not be his wife, that he had no means, and they would never let her +marry him. But he failed to do so and felt awkward about entering on +such an explanation. From day to day he became more and more +entangled. It seemed to her mother and Sonya that Natasha was in +love with Boris as of old. She sang him his favorite songs, showed him +her album, making him write in it, did not allow him to allude to +the past, letting it be understood how was the present; and every +day he went away in a fog, without having said what he meant to, and +not knowing what he was doing or why he came, or how it would all end. +He left off visiting Helene and received reproachful notes from her +every day, and yet he continued to spend whole days with the Rostovs. + + + + + +CHAPTER XIII + + +One night when the old countess, in nightcap and dressing jacket, +without her false curls, and with her poor little knob of hair showing +under her white cotton cap, knelt sighing and groaning on a rug and +bowing to the ground in prayer, her door creaked and Natasha, also +in a dressing jacket with slippers on her bare feet and her hair in +curlpapers, ran in. The countess--her prayerful mood dispelled--looked +round and frowned. She was finishing her last prayer: "Can it be +that this couch will be my grave?" Natasha, flushed and eager, +seeing her mother in prayer, suddenly checked her rush, half sat down, +and unconsciously put out her tongue as if chiding herself. Seeing +that her mother was still praying she ran on tiptoe to the bed and, +rapidly slipping one little foot against the other, pushed off her +slippers and jumped onto the bed the countess had feared might +become her grave. This couch was high, with a feather bed and five +pillows each smaller than the one below. Natasha jumped on it, sank +into the feather bed, rolled over to the wall, and began snuggling +up the bedclothes as she settled down, raising her knees to her +chin, kicking out and laughing almost inaudibly, now covering +herself up head and all, and now peeping at her mother. The countess +finished her prayers and came to the bed with a stern face, but +seeing, that Natasha's head was covered, she smiled in her kind, +weak way. + +"Now then, now then!" said she. + +"Mamma, can we have a talk? Yes?" said Natasha. "Now, just one on +your throat and another... that'll do!" And seizing her mother round +the neck, she kissed her on the throat. In her behavior to her +mother Natasha seemed rough, but she was so sensitive and tactful that +however she clasped her mother she always managed to do it without +hurting her or making her feel uncomfortable or displeased. + +"Well, what is it tonight?" said the mother, having arranged her +pillows and waited until Natasha, after turning over a couple of +times, had settled down beside her under the quilt, spread out her +arms, and assumed a serious expression. + +These visits of Natasha's at night before the count returned from +his club were one of the greatest pleasures of both mother, and +daughter. + +"What is it tonight?--But I have to tell you..." + +Natasha put her hand on her mother's mouth. + +"About Boris... I know," she said seriously; "that's what I have +come about. Don't say it--I know. No, do tell me!" and she removed her +hand. "Tell me, Mamma! He's nice?" + +"Natasha, you are sixteen. At your age I was married. You say +Boris is nice. He is very nice, and I love him like a son. But what +then?... What are you thinking about? You have quite turned his +head, I can see that...." + +As she said this the countess looked round at her daughter. +Natasha was lying looking steadily straight before her at one of the +mahogany sphinxes carved on the corners of the bedstead, so that the +countess only saw her daughter's face in profile. That face struck her +by its peculiarly serious and concentrated expression. + +Natasha was listening and considering. + +"Well, what then?" said she. + +"You have quite turned his head, and why? What do you want of him? +You know you can't marry him." + +"Why not?" said Natasha, without changing her position. + +"Because he is young, because he is poor, because he is a +relation... and because you yourself don't love him." + +"How do you know?" + +"I know. It is not right, darling!" + + "But if I want to..." said Natasha. + +"Leave off talking nonsense," said the countess. + +"But if I want to..." + +"Natasha, I am in earnest..." + +Natasha did not let her finish. She drew the countess' large hand to +her, kissed it on the back and then on the palm, then again turned +it over and began kissing first one knuckle, then the space between +the knuckles, then the next knuckle, whispering, "January, February, +March, April, May. Speak, Mamma, why don't you say anything? Speak!" +said she, turning to her mother, who was tenderly gazing at her +daughter and in that contemplation seemed to have forgotten all she +had wished to say. + +"It won't do, my love! Not everyone will understand this +friendship dating from your childish days, and to see him so +intimate with you may injure you in the eyes of other young men who +visit us, and above all it torments him for nothing. He may already +have found a suitable and wealthy match, and now he's half crazy." + +"Crazy?" repeated Natasha. + +"I'll tell you some things about myself. I had a cousin..." + +"I know! Cyril Matveich... but he is old." + +"He was not always old. But this is what I'll do, Natasha, I'll have +a talk with Boris. He need not come so often...." + +"Why not, if he likes to?" + +"Because I know it will end in nothing...." + +"How can you know? No, Mamma, don't speak to him! What nonsense!" +said Natasha in the tone of one being deprived of her property. "Well, +I won't marry, but let him come if he enjoys it and I enjoy it." +Natasha smiled and looked at her mother. "Not to marry, but just +so," she added. + +"How so, my pet?" + +"Just so. There's no need for me to marry him. But... just so." + +"Just so, just so," repeated the countess, and shaking all over, she +went off into a good humored, unexpected, elderly laugh. + +"Don't laugh, stop!" cried Natasha. "You're shaking the whole bed! +You're awfully like me, just such another giggler.... Wait..." and she +seized the countess' hands and kissed a knuckle of the little +finger, saying, "June," and continued, kissing, "July, August," on the +other hand. "But, Mamma, is he very much in love? What do you think? +Was anybody ever so much in love with you? And he's very nice, very, +very nice. Only not quite my taste--he is so narrow, like the +dining-room clock.... Don't you understand? Narrow, you know--gray, +light gray..." + +"What rubbish you're talking!" said the countess. + +Natasha continued: "Don't you really understand? Nicholas would +understand.... Bezukhov, now, is blue, dark-blue and red, and he is +square." + +"You flirt with him too," said the countess, laughing. + +"No, he is a Freemason, I have found out. He is fine, dark-blue +and red.... How can I explain it to you?" + +"Little countess!" the count's voice called from behind the door. +"You're not asleep?" Natasha jumped up, snatched up her slippers, +and ran barefoot to her own room. + +It was a long time before she could sleep. She kept thinking that no +one could understand all that she understood and all there was in her. + +"Sonya?" she thought, glancing at that curled-up, sleeping little +kitten with her enormous plait of hair. "No, how could she? She's +virtuous. She fell in love with Nicholas and does not wish to know +anything more. Even Mamma does not understand. It is wonderful how +clever I am and how... charming she is," she went on, speaking of +herself in the third person, and imagining it was some very wise +man--the wisest and best of men--who was saying it of her. "There is +everything, everything in her," continued this man. "She is +unusually intelligent, charming... and then she is pretty, +uncommonly pretty, and agile--she swims and rides splendidly... and +her voice! One can really say it's a wonderful voice!" + +She hummed a scrap from her favorite opera by Cherubini, threw +herself on her bed, laughed at the pleasant thought that she would +immediately fall asleep, called Dunyasha the maid to put out the +candle, and before Dunyasha had left the room had already passed +into yet another happier world of dreams, where everything was as +light and beautiful as in reality, and even more so because it was +different. + + +Next day the countess called Boris aside and had a talk with him, +after which he ceased coming to the Rostovs'. + + + + + +CHAPTER XIV + + +On the thirty-first of December, New Year's Eve, 1809 --10 an old +grandee of Catherine's day was giving a ball and midnight supper. +The diplomatic corps and the Emperor himself were to be present. + +The grandee's well-known mansion on the English Quay glittered +with innumerable lights. Police were stationed at the brightly lit +entrance which was carpeted with red baize, and not only gendarmes but +dozens of police officers and even the police master himself stood +at the porch. Carriages kept driving away and fresh ones arriving, +with red-liveried footmen and footmen in plumed hats. From the +carriages emerged men wearing uniforms, stars, and ribbons, while +ladies in satin and ermine cautiously descended the carriage steps +which were let down for them with a clatter, and then walked hurriedly +and noiselessly over the baize at the entrance. + +Almost every time a new carriage drove up a whisper ran through +the crowd and caps were doffed. + +"The Emperor?... No, a minister.... prince... ambassador. Don't +you see the plumes?..." was whispered among the crowd. + +One person, better dressed than the rest, seemed to know everyone +and mentioned by name the greatest dignitaries of the day. + +A third of the visitors had already arrived, but the Rostovs, who +were to be present, were still hurrying to get dressed. + +There had been many discussions and preparations for this ball in +the Rostov family, many fears that the invitation would not arrive, +that the dresses would not be ready, or that something would not be +arranged as it should be. + +Marya Ignatevna Peronskaya, a thin and shallow maid of honor at +the court of the Dowager Empress, who was a friend and relation of the +countess and piloted the provincial Rostovs in Petersburg high +society, was to accompany them to the ball. + +They were to call for her at her house in the Taurida Gardens at ten +o'clock, but it was already five minutes to ten, and the girls were +not yet dressed. + +Natasha was going to her first grand ball. She had got up at eight +that morning and had been in a fever of excitement and activity all +day. All her powers since morning had been concentrated on ensuring +that they all--she herself, Mamma, and Sonya--should be as well +dressed as possible. Sonya and her mother put themselves entirely in +her hands. The countess was to wear a claret-colored velvet dress, and +the two girls white gauze over pink silk slips, with roses on their +bodices and their hair dressed a la grecque. + +Everything essential had already been done; feet, hands, necks, +and ears washed, perfumed, and powdered, as befits a ball; the +openwork silk stockings and white satin shoes with ribbons were +already on; the hairdressing was almost done. Sonya was finishing +dressing and so was the countess, but Natasha, who had bustled about +helping them all, was behindhand. She was still sitting before a +looking-glass with a dressing jacket thrown over her slender +shoulders. Sonya stood ready dressed in the middle of the room and, +pressing the head of a pin till it hurt her dainty finger, was +fixing on a last ribbon that squeaked as the pin went through it. + +"That's not the way, that's not the way, Sonya!" cried Natasha +turning her head and clutching with both hands at her hair which the +maid who was dressing it had not time to release. "That bow is not +right. Come here!" + +Sonya sat down and Natasha pinned the ribbon on differently. + +"Allow me, Miss! I can't do it like that," said the maid who was +holding Natasha's hair. + +"Oh, dear! Well then, wait. That's right, Sonya." + +"Aren't you ready? It is nearly ten," came the countess' voice. + +"Directly! Directly! And you, Mamma?" + +"I have only my cap to pin on." + +"Don't do it without me!" called Natasha. "You won't do it right." + +"But it's already ten." + +They had decided to be at the ball by half past ten, and Natasha had +still to get dressed and they had to call at the Taurida Gardens. + +When her hair was done, Natasha, in her short petticoat from under +which her dancing shoes showed, and in her mother's dressing jacket, +ran up to Sonya, scrutinized her, and then ran to her mother. +Turning her mother's head this way and that, she fastened on the cap +and, hurriedly kissing her gray hair, ran back to the maids who were +turning up the hem of her skirt. + +The cause of the delay was Natasha's skirt, which was too long. +Two maids were turning up the hem and hurriedly biting off the ends of +thread. A third with pins in her mouth was running about between the +countess and Sonya, and a fourth held the whole of the gossamer +garment up high on one uplifted hand. + +"Mavra, quicker, darling!" + +"Give me my thimble, Miss, from there..." + +"Whenever will you be ready?" asked the count coming to the door. +"Here is here is some scent. Peronskaya must be tired of waiting." + +"It's ready, Miss," said the maid, holding up the shortened gauze +dress with two fingers, and blowing and shaking something off it, as +if by this to express a consciousness of the airiness and purity of +what she held. + +Natasha began putting on the dress. + +"In a minute! In a minute! Don't come in, Papa!" she cried to her +father as he opened the door--speaking from under the filmy skirt +which still covered her whole face. + +Sonya slammed the door to. A minute later they let the count in. +He was wearing a blue swallow-tail coat, shoes and stockings, and +was perfumed and his hair pomaded. + +"Oh, Papa! how nice you look! Charming!" cried Natasha, as she stood +in the middle of the room smoothing out the folds of the gauze. + +"If you please, Miss! allow me," said the maid, who on her knees was +pulling the skirt straight and shifting the pins from one side of +her mouth to the other with her tongue. + +"Say what you like," exclaimed Sonya, in a despairing voice as she +looked at Natasha, "say what you like, it's still too long." + +Natasha stepped back to look at herself in the pier glass. The dress +was too long. + +"Really, madam, it is not at all too long," said Mavra, crawling +on her knees after her young lady. + +"Well, if it's too long we'll take it up... we'll tack it up in +one minute," said the resolute Dunyasha taking a needle that was stuck +on the front of her little shawl and, still kneeling on the floor, set +to work once more. + +At that moment, with soft steps, the countess came in shyly, in +her cap and velvet gown. + +"Oo-oo, my beauty!" exclaimed the count, "she looks better than +any of you!" + +He would have embraced her but, blushing, she stepped aside +fearing to be rumpled. + +"Mamma, your cap, more to this side," said Natasha. "I'll arrange +it," and she rushed forward so that the maids who were tacking up +her skirt could not move fast enough and a piece of gauze was torn +off. + +"Oh goodness! What has happened? Really it was not my fault!" + +"Never mind, I'll run it up, it won't show," said Dunyasha. + +"What a beauty--a very queen!" said the nurse as she came to the +door. "And Sonya! They are lovely!" + +At a quarter past ten they at last got into their carriages and +started. But they had still to call at the Taurida Gardens. + +Peronskaya was quite ready. In spite of her age and plainness she +had gone through the same process as the Rostovs, but with less +flurry--for to her it was a matter of routine. Her ugly old body was +washed, perfumed, and powdered in just the same way. She had washed +behind her ears just as carefully, and when she entered her drawing +room in her yellow dress, wearing her badge as maid of honor, her +old lady's maid was as full of rapturous admiration as the Rostovs' +servants had been. + +She praised the Rostovs' toilets. They praised her taste and toilet, +and at eleven o'clock, careful of their coiffures and dresses, they +settled themselves in their carriages and drove off. + + + + + +CHAPTER XV + + +Natasha had not had a moment free since early morning and had not +once had time to think of what lay before her. + +In the damp chill air and crowded closeness of the swaying carriage, +she for the first time vividly imagined what was in store for her +there at the ball, in those brightly lighted rooms--with music, +flowers, dances, the Emperor, and all the brilliant young people of +Petersburg. The prospect was so splendid that she hardly believed it +would come true, so out of keeping was it with the chill darkness +and closeness of the carriage. She understood all that awaited her +only when, after stepping over the red baize at the entrance, she +entered the hall, took off her fur cloak, and, beside Sonya and in +front of her mother, mounted the brightly illuminated stairs between +the flowers. Only then did she remember how she must behave at a ball, +and tried to assume the majestic air she considered indispensable +for a girl on such an occasion. But, fortunately for her, she felt her +eyes growing misty, she saw nothing clearly, her pulse beat a +hundred to the minute, and the blood throbbed at her heart. She +could not assume that pose, which would have made her ridiculous, +and she moved on almost fainting from excitement and trying with all +her might to conceal it. And this was the very attitude that became +her best. Before and behind them other visitors were entering, also +talking in low tones and wearing ball dresses. The mirrors on the +landing reflected ladies in white, pale-blue, and pink dresses, with +diamonds and pearls on their bare necks and arms. + +Natasha looked in the mirrors and could not distinguish her +reflection from the others. All was blended into one brilliant +procession. On entering the ballroom the regular hum of voices, +footsteps, and greetings deafened Natasha, and the light and glitter +dazzled her still more. The host and hostess, who had already been +standing at the door for half an hour repeating the same words to +the various arrivals, "Charme de vous voir,"* greeted the Rostovs +and Peronskaya in the same manner. + + +*"Delighted to see you." + + +The two girls in their white dresses, each with a rose in her +black hair, both curtsied in the same way, but the hostess' eye +involuntarily rested longer on the slim Natasha. She looked at her and +gave her alone a special smile in addition to her usual smile as +hostess. Looking at her she may have recalled the golden, +irrecoverable days of her own girlhood and her own first ball. The +host also followed Natasha with his eyes and asked the count which was +his daughter. + +"Charming!" said he, kissing the tips of his fingers. + +In the ballroom guests stood crowding at the entrance doors awaiting +the Emperor. The countess took up a position in one of the front +rows of that crowd. Natasha heard and felt that several people were +asking about her and looking at her. She realized that those +noticing her liked her, and this observation helped to calm her. + +"There are some like ourselves and some worse," she thought. + +Peronskaya was pointing out to the countess the most important +people at the ball. + +"That is the Dutch ambassador, do you see? That gray-haired man," +she said, indicating an old man with a profusion of silver-gray +curly hair, who was surrounded by ladies laughing at something he +said. + +"Ah, here she is, the Queen of Petersburg, Countess Bezukhova," said +Peronskaya, indicating Helene who had just entered. "How lovely! She +is quite equal to Marya Antonovna. See how the men, young and old, pay +court to her. Beautiful and clever... they say Prince--is quite mad +about her. But see, those two, though not good-looking, are even +more run after." + +She pointed to a lady who was crossing the room followed by a very +plain daughter. + +"She is a splendid match, a millionairess," said Peronskaya. "And +look, here come her suitors." + +"That is Bezukhova's brother, Anatole Kuragin," she said, indicating +a handsome officer of the Horse Guards who passed by them with head +erect, looking at something over the heads of the ladies. "He's +handsome, isn't he? I hear they will marry him to that rich girl. +But your cousin, Drubetskoy, is also very attentive to her. They say +she has millions. Oh yes, that's the French ambassador himself!" she +replied to the countess' inquiry about Caulaincourt. "Looks as if he +were a king! All the same, the French are charming, very charming. +No one more charming in society. Ah, here she is! Yes, she is still +the most beautiful of them all, our Marya Antonovna! And how simply +she is dressed! Lovely! And that stout one in spectacles is the +universal Freemason," she went on, indicating Pierre. "Put him +beside his wife and he looks a regular buffoon!" + +Pierre, swaying his stout body, advanced, making way through the +crowd and nodding to right and left as casually and good-naturedly +as if he were passing through a crowd at a fair. He pushed through, +evidently looking for someone. + +Natasha looked joyfully at the familiar face of Pierre, "the +buffoon," as Peronskaya had called him, and knew he was looking for +them, and for her in particular. He had promised to be at the ball and +introduce partners to her. + +But before he reached them Pierre stopped beside a very handsome, +dark man of middle height, and in a white uniform, who stood by a +window talking to a tall man wearing stars and a ribbon. Natasha at +once recognized the shorter and younger man in the white uniform: it +was Bolkonski, who seemed to her to have grown much younger, +happier, and better-looking. + +"There's someone else we know--Bolkonski, do you see, Mamma?" said +Natasha, pointing out Prince Andrew. "You remember, he stayed a +night with us at Otradnoe." + +"Oh, you know him?" said Peronskaya. "I can't bear him. Il fait a +present la pluie et le beau temps.* He's too proud for anything. +Takes after his father. And he's hand in glove with Speranski, writing +some project or other. Just look how he treats the ladies! There's one +talking to him and he has turned away," she said, pointing at him. +"I'd give it to him if he treated me as he does those ladies." + + +*"He is all the rage just now. + + + + + +CHAPTER XVI + + +Suddenly everybody stirred, began talking, and pressed forward and +then back, and between the two rows, which separated, the Emperor +entered to the sounds of music that had immediately struck up. +Behind him walked his host and hostess. He walked in rapidly, bowing +to right and left as if anxious to get the first moments of the +reception over. The band played the polonaise in vogue at that time on +account of the words that had been set to it, beginning: "Alexander, +Elisaveta, all our hearts you ravish quite..." The Emperor passed on +to the drawing room, the crowd made a rush for the doors, and +several persons with excited faces hurried there and back again. +Then the crowd hastily retired from the drawing-room door, at which +the Emperor reappeared talking to the hostess. A young man, looking +distraught, pounced down on the ladies, asking them to move aside. +Some ladies, with faces betraying complete forgetfulness of all the +rules of decorum, pushed forward to the detriment of their toilets. +The men began to choose partners and take their places for the +polonaise. + +Everyone moved back, and the Emperor came smiling out of the drawing +room leading his hostess by the hand but not keeping time to the +music. The host followed with Marya Antonovna Naryshkina; then came +ambassadors, ministers, and various generals, whom Peronskaya +diligently named. More than half the ladies already had partners and +were taking up, or preparing to take up, their positions for the +polonaise. Natasha felt that she would be left with her mother and +Sonya among a minority of women who crowded near the wall, not +having been invited to dance. She stood with her slender arms +hanging down, her scarcely defined bosom rising and falling regularly, +and with bated breath and glittering, frightened eyes gazed straight +before her, evidently prepared for the height of joy or misery. She +was not concerned about the Emperor or any of those great people +whom Peronskaya was pointing out--she had but one thought: "Is it +possible no one will ask me, that I shall not be among the first to +dance? Is it possible that not one of all these men will notice me? +They do not even seem to see me, or if they do they look as if they +were saying, 'Ah, she's not the one I'm after, so it's not worth +looking at her!' No, it's impossible," she thought. "They must know +how I long to dance, how splendidly I dance, and how they would +enjoy dancing with me." + +The strains of the polonaise, which had continued for a considerable +time, had begun to sound like a sad reminiscence to Natasha's ears. +She wanted to cry. Peronskaya had left them. The count was at the +other end of the room. She and the countess and Sonya were standing by +themselves as in the depths of a forest amid that crowd of +strangers, with no one interested in them and not wanted by anyone. +Prince Andrew with a lady passed by, evidently not recognizing them. +The handsome Anatole was smilingly talking to a partner on his arm and +looked at Natasha as one looks at a wall. Boris passed them twice +and each time turned away. Berg and his wife, who were not dancing, +came up to them. + +This family gathering seemed humiliating to Natasha--as if there +were nowhere else for the family to talk but here at the ball. She did +not listen to or look at Vera, who was telling her something about her +own green dress. + +At last the Emperor stopped beside his last partner (he had danced +with three) and the music ceased. A worried aide-de-camp ran up to the +Rostovs requesting them to stand farther back, though as it was they +were already close to the wall, and from the gallery resounded the +distinct, precise, enticingly rhythmical strains of a waltz. The +Emperor looked smilingly down the room. A minute passed but no one had +yet begun dancing. An aide-de-camp, the Master of Ceremonies, went +up to Countess Bezukhova and asked her to dance. She smilingly +raised her hand and laid it on his shoulder without looking at him. +The aide-de-camp, an adept in his art, grasping his partner firmly +round her waist, with confident deliberation started smoothly, gliding +first round the edge of the circle, then at the corner of the room +he caught Helene's left hand and turned her, the only sound audible, +apart from the ever-quickening music, being the rhythmic click of +the spurs on his rapid, agile feet, while at every third beat his +partner's velvet dress spread out and seemed to flash as she whirled +round. Natasha gazed at them and was ready to cry because it was not +she who was dancing that first turn of the waltz. + +Prince Andrew, in the white uniform of a cavalry colonel, wearing +stockings and dancing shoes, stood looking animated and bright in +the front row of the circle not far from the Rostovs. Baron Firhoff +was talking to him about the first sitting of the Council of State +to be held next day. Prince Andrew, as one closely connected with +Speranski and participating in the work of the legislative commission, +could give reliable information about that sitting, concerning which +various rumors were current. But not listening to what Firhoff was +saying, he was gazing now at the sovereign and now at the men +intending to dance who had not yet gathered courage to enter the +circle. + +Prince Andrew was watching these men abashed by the Emperor's +presence, and the women who were breathlessly longing to be asked to +dance. + +Pierre came up to him and caught him by the arm. + +"You always dance. I have a protegee, the young Rostova, here. Ask +her," he said. + +"Where is she?" asked Bolkonski. "Excuse me!" he added, turning to +the baron, "we will finish this conversation elsewhere--at a ball +one must dance." He stepped forward in the direction Pierre indicated. +The despairing, dejected expression of Natasha's face caught his +eye. He recognized her, guessed her feelings, saw that it was her +debut, remembered her conversation at the window, and with an +expression of pleasure on his face approached Countess Rostova. + +"Allow me to introduce you to my daughter," said the countess, +with heightened color. + +"I have the pleasure of being already acquainted, if the countess +remembers me," said Prince Andrew with a low and courteous bow quite +belying Peronskaya's remarks about his rudeness, and approaching +Natasha he held out his arm to grasp her waist before he had completed +his invitation. He asked her to waltz. That tremulous expression on +Natasha's face, prepared either for despair or rapture, suddenly +brightened into a happy, grateful, childlike smile. + +"I have long been waiting for you," that frightened happy little +girl seemed to say by the smile that replaced the threatened tears, as +she raised her hand to Prince Andrew's shoulder. They were the +second couple to enter the circle. Prince Andrew was one of the best +dancers of his day and Natasha danced exquisitely. Her little feet +in their white satin dancing shoes did their work swiftly, lightly, +and independently of herself, while her face beamed with ecstatic +happiness. Her slender bare arms and neck were not beautiful--compared +to Helene's her shoulders looked thin and her bosom undeveloped. But +Helene seemed, as it were, hardened by a varnish left by the thousands +of looks that had scanned her person, while Natasha was like a girl +exposed for the first time, who would have felt very much ashamed +had she not been assured that this was absolutely necessary. + +Prince Andrew liked dancing, and wishing to escape as quickly as +possible from the political and clever talk which everyone addressed +to him, wishing also to break up the circle of restraint he +disliked, caused by the Emperor's presence, he danced, and had +chosen Natasha because Pierre pointed her out to him and because she +was the first pretty girl who caught his eye; but scarcely had he +embraced that slender supple figure and felt her stirring so close +to him and smiling so near him than the wine of her charm rose to +his head, and he felt himself revived and rejuvenated when after +leaving her he stood breathing deeply and watching the other dancers. + + + + + +CHAPTER XVII + + +After Prince Andrew, Boris came up to ask Natasha for dance, and +then the aide-de-camp who had opened the ball, and several other young +men, so that, flushed and happy, and passing on her superfluous +partners to Sonya, she did not cease dancing all the evening. She +noticed and saw nothing of what occupied everyone else. Not only did +she fail to notice that the Emperor talked a long time with the French +ambassador, and how particularly gracious he was to a certain lady, or +that Prince So-and-so and So-and-so did and said this and that, and +that Helene had great success and was honored was by the special +attention of So-and-so, but she did not even see the Emperor, and only +noticed that he had gone because the ball became livelier after his +departure. For one of the merry cotillions before supper Prince Andrew +was again her partner. He reminded her of their first encounter in the +Otradnoe avenue, and how she had been unable to sleep that moonlight +night, and told her how he had involuntarily overheard her. Natasha +blushed at that recollection and tried to excuse herself, as if +there had been something to be ashamed of in what Prince Andrew had +overheard. + +Like all men who have grown up in society, Prince Andrew liked +meeting someone there not of the conventional society stamp. And +such was Natasha, with her surprise, her delight, her shyness, and +even her mistakes in speaking French. With her he behaved with special +care and tenderness, sitting beside her and talking of the simplest +and most unimportant matters; he admired her shy grace. In the +middle of the cotillion, having completed one of the figures, Natasha, +still out of breath, was returning to her seat when another dancer +chose her. She was tired and panting and evidently thought of +declining, but immediately put her hand gaily on the man's shoulder, +smiling at Prince Andrew. + +"I'd be glad to sit beside you and rest: I'm tired; but you see +how they keep asking me, and I'm glad of it, I'm happy and I love +everybody, and you and I understand it all," and much, much more was +said in her smile. When her partner left her Natasha ran across the +room to choose two ladies for the figure. + +"If she goes to her cousin first and then to another lady, she +will be my wife," said Prince Andrew to himself quite to his own +surprise, as he watched her. She did go first to her cousin. + +"What rubbish sometimes enters one's head!" thought Prince Andrew, +"but what is certain is that that girl is so charming, so original, +that she won't be dancing here a month before she will be +married.... Such as she are rare here," he thought, as Natasha, +readjusting a rose that was slipping on her bodice, settled herself +beside him. + +When the cotillion was over the old count in his blue coat came up +to the dancers. He invited Prince Andrew to come and see them, and +asked his daughter whether she was enjoying herself. Natasha did not +answer at once but only looked up with a smile that said +reproachfully: "How can you ask such a question?" + +"I have never enjoyed myself so much before!" she said, and Prince +Andrew noticed how her thin arms rose quickly as if to embrace her +father and instantly dropped again. Natasha was happier than she had +ever been in her life. She was at that height of bliss when one +becomes completely kind and good and does not believe in the +possibility of evil, unhappiness, or sorrow. + +At that ball Pierre for the first time felt humiliated by the +position his wife occupied in court circles. He was gloomy and +absent-minded. A deep furrow ran across his forehead, and standing +by a window he stared over his spectacles seeing no one. + +On her way to supper Natasha passed him. + +Pierre's gloomy, unhappy look struck her. She stopped in front of +him. She wished to help him, to bestow on him the superabundance of +her own happiness. + +"How delightful it is, Count!" said she. "Isn't it?" + +Pierre smiled absent-mindedly, evidently not grasping what she said. + +"Yes, I am very glad," he said. + +"How can people be dissatisfied with anything?" thought Natasha. +"Especially such a capital fellow as Bezukhov!" In Natasha's eyes +all the people at the ball alike were good, kind, and splendid people, +loving one another; none of them capable of injuring another--and so +they ought all to be happy. + + + + + +CHAPTER XVIII + + +Next day Prince Andrew thought of the ball, but his mind did not +dwell on it long. "Yes, it was a very brilliant ball," and then... +"Yes, that little Rostova is very charming. There's something fresh, +original, un-Petersburg-like about her that distinguishes her." That +was all he thought about yesterday's ball, and after his morning tea +he set to work. + +But either from fatigue or want of sleep he was ill-disposed for +work and could get nothing done. He kept criticizing his own work, +as he often did, and was glad when he heard someone coming. + +The visitor was Bitski, who served on various committees, frequented +all the societies in Petersburg, and a passionate devotee of the new +ideas and of Speranski, and a diligent Petersburg newsmonger--one of +those men who choose their opinions like their clothes according to +the fashion, but who for that very reason appear to be the warmest +partisans. Hardly had he got rid of his hat before he ran into +Prince Andrew's room with a preoccupied air and at once began talking. +He had just heard particulars of that morning's sitting of the Council +of State opened by the Emperor, and he spoke of it enthusiastically. +The Emperor's speech had been extraordinary. It had been a speech such +as only constitutional monarchs deliver. "The Sovereign plainly said +that the Council and Senate are estates of the realm, he said that the +government must rest not on authority but on secure bases. The Emperor +said that the fiscal system must be reorganized and the accounts +published," recounted Bitski, emphasizing certain words and opening +his eyes significantly. + +"Ah, yes! Today's events mark an epoch, the greatest epoch in our +history," he concluded. + +Prince Andrew listened to the account of the opening of the +Council of State, which he had so impatiently awaited and to which +he had attached such importance, and was surprised that this event, +now that it had taken place, did not affect him, and even seemed quite +insignificant. He listened with quiet irony to Bitski's enthusiastic +account of it. A very simple thought occurred to him: "What does it +matter to me or to Bitski what the Emperor was pleased to say at the +Council? Can all that make me any happier or better?" + +And this simple reflection suddenly destroyed all the interest +Prince Andrew had felt in the impending reforms. He was going to +dine that evening at Speranski's, "with only a few friends," as the +host had said when inviting him. The prospect of that dinner in the +intimate home circle of the man he so admired had greatly interested +Prince Andrew, especially as he had not yet seen Speranski in his +domestic surroundings, but now he felt disinclined to go to it. + +At the appointed hour, however, he entered the modest house +Speranski owned in the Taurida Gardens. In the parqueted dining room +this small house, remarkable for its extreme cleanliness (suggesting +that of a monastery), Prince Andrew, who was rather late, found the +friendly gathering of Speranski's intimate acquaintances already +assembled at five o'clock. There were no ladies present except +Speranski's little daughter (long-faced like her father) and her +governess. The other guests were Gervais, Magnitski, and Stolypin. +While still in the anteroom Prince Andrew heard loud voices and a +ringing staccato laugh--a laugh such as one hears on the stage. +Someone--it sounded like Speranski--was distinctly ejaculating +ha-ha-ha. Prince Andrew had never before heard Speranski's famous +laugh, and this ringing, high pitched laughter from a statesman made a +strange impression on him. + +He entered the dining room. The whole company were standing +between two windows at a small table laid with hors-d'oeuvres. +Speranski, wearing a gray swallow-tail coat with a star on the breast, +and evidently still the same waistcoat and high white stock he had +worn at the meeting of the Council of State, stood at the table with a +beaming countenance. His guests surrounded him. Magnitski, +addressing himself to Speranski, was relating an anecdote, and +Speranski was laughing in advance at what Magnitski was going to +say. When Prince Andrew entered the room Magnitski's words were +again crowned by laughter. Stolypin gave a deep bass guffaw as he +munched a piece of bread and cheese. Gervais laughed softly with a +hissing chuckle, and Speranski in a high-pitched staccato manner. + +Still laughing, Speranski held out his soft white hand to Prince +Andrew. + +"Very pleased to see you, Prince," he said. "One moment..." he +went on, turning to Magnitski and interrupting his story. "We have +agreed that this is a dinner for recreation, with not a word about +business!" and turning again to the narrator he began to laugh afresh. + +Prince Andrew looked at the laughing Speranski with astonishment, +regret, and disillusionment. It seemed to him that this was not +Speranski but someone else. Everything that had formerly appeared +mysterious and fascinating in Speranski suddenly became plain and +unattractive. + +At dinner the conversation did not cease for a moment and seemed +to consist of the contents of a book of funny anecdotes. Before +Magnitski had finished his story someone else was anxious to relate +something still funnier. Most of the anecdotes, if not relating to the +state service, related to people in the service. It seemed that in +this company the insignificance of those people was so definitely +accepted that the only possible attitude toward them was one of good +humored ridicule. Speranski related how at the Council that morning +a deaf dignitary, when asked his opinion, replied that he thought so +too. Gervais gave a long account of an official revision, remarkable +for the stupidity of everybody concerned. Stolypin, stuttering, +broke into the conversation and began excitedly talking of the +abuses that existed under the former order of things--threatening to +give a serious turn to the conversation. Magnitski starting quizzing +Stolypin about his vehemence. Gervais intervened with a joke, and +the talk reverted to its former lively tone. + +Evidently Speranski liked to rest after his labors and find +amusement in a circle of friends, and his guests, understanding his +wish, tried to enliven him and amuse themselves. But their gaiety +seemed to Prince Andrew mirthless and tiresome. Speranski's +high-pitched voice struck him unpleasantly, and the incessant laughter +grated on him like a false note. Prince Andrew did not laugh and +feared that he would be a damper on the spirits of the company, but no +one took any notice of his being out of harmony with the general mood. +They all seemed very gay. + +He tried several times to join in the conversation, but his +remarks were tossed aside each time like a cork thrown out of the +water, and he could not jest with them. + +There was nothing wrong or unseemly in what they said, it was +witty and might have been funny, but it lacked just that something +which is the salt of mirth, and they were not even aware that such a +thing existed. + +After dinner Speranski's daughter and her governess rose. He +patted the little girl with his white hand and kissed her. And that +gesture, too, seemed unnatural to Prince Andrew. + +The men remained at table over their port--English fashion. In the +midst of a conversation that was started about Napoleon's Spanish +affairs, which they all agreed in approving, Prince Andrew began to +express a contrary opinion. Speranski smiled and, with an evident wish +to prevent the conversation from taking an unpleasant course, told a +story that had no connection with the previous conversation. For a few +moments all were silent. + +Having sat some time at table, Speranski corked a bottle of wine +and, remarking, "Nowadays good wine rides in a carriage and pair," +passed it to the servant and got up. All rose and continuing to talk +loudly went into the drawing room. Two letters brought by a courier +were handed to Speranski and he took them to his study. As soon as +he had left the room the general merriment stopped and the guests +began to converse sensibly and quietly with one another. + +"Now for the recitation!" said Speranski on returning from his +study. "A wonderful talent!" he said to Prince Andrew, and Magnitski +immediately assumed a pose and began reciting some humorous verses +in French which he had composed about various well-known Petersburg +people. He was interrupted several times by applause. When the +verses were finished Prince Andrew went up to Speranski and took his +leave. + +"Where are you off to so early?" asked Speranski. + +"I promised to go to a reception." + +They said no more. Prince Andrew looked closely into those +mirrorlike, impenetrable eyes, and felt that it had been ridiculous of +him to have expected anything from Speranski and from any of his own +activities connected with him, or ever to have attributed importance +to what Speranski was doing. That precise, mirthless laughter rang +in Prince Andrew's ears long after he had left the house. + +When he reached home Prince Andrew began thinking of his life in +Petersburg during those last four months as if it were something +new. He recalled his exertions and solicitations, and the history of +his project of army reform, which had been accepted for +consideration and which they were trying to pass over in silence +simply because another, a very poor one, had already been prepared and +submitted to the Emperor. He thought of the meetings of a committee of +which Berg was a member. He remembered how carefully and at what +length everything relating to form and procedure was discussed at +those meetings, and how sedulously and promptly all that related to +the gist of the business was evaded. He recalled his labors on the +Legal Code, and how painstakingly he had translated the articles of +the Roman and French codes into Russian, and he felt ashamed of +himself. Then he vividly pictured to himself Bogucharovo, his +occupations in the country, his journey to Ryazan; he remembered the +peasants and Dron the village elder, and mentally applying to them the +Personal Rights he had divided into paragraphs, he felt astonished +that he could have spent so much time on such useless work. + + + + + +CHAPTER XIX + + +Next day Prince Andrew called at a few houses he had not visited +before, and among them at the Rostovs' with whom he had renewed +acquaintance at the ball. Apart from considerations of politeness +which demanded the call, he wanted to see that original, eager girl +who had left such a pleasant impression on his mind, in her own home. + +Natasha was one of the first to meet him. She was wearing a +dark-blue house dress in which Prince Andrew thought her even prettier +than in her ball dress. She and all the Rostov family welcomed him +as an old friend, simply and cordially. The whole family, whom he +had formerly judged severely, now seemed to him to consist of +excellent, simple, and kindly people. The old count's hospitality +and good nature, which struck one especially in Petersburg as a +pleasant surprise, were such that Prince Andrew could not refuse to +stay to dinner. "Yes," he thought, "they are capital people, who of +course have not the slightest idea what a treasure they possess in +Natasha; but they are kindly folk and form the best possible setting +for this strikingly poetic, charming girl, overflowing with life!" + +In Natasha Prince Andrew was conscious of a strange world completely +alien to him and brimful of joys unknown to him, a different world, +that in the Otradnoe avenue and at the window that moonlight night had +already begun to disconcert him. Now this world disconcerted him no +longer and was no longer alien to him, but he himself having entered +it found in it a new enjoyment. + +After dinner Natasha, at Prince Andrew's request, went to the +clavichord and began singing. Prince Andrew stood by a window +talking to the ladies and listened to her. In the midst of a phrase he +ceased speaking and suddenly felt tears choking him, a thing he had +thought impossible for him. He looked at Natasha as she sang, and +something new and joyful stirred in his soul. He felt happy and at the +same time sad. He had absolutely nothing to weep about yet he was +ready to weep. What about? His former love? The little princess? His +disillusionments?... His hopes for the future?... Yes and no. The +chief reason was a sudden, vivid sense of the terrible contrast +between something infinitely great and illimitable within him and that +limited and material something that he, and even she, was. This +contrast weighed on and yet cheered him while she sang. + +As soon as Natasha had finished she went up to him and asked how +he liked her voice. She asked this and then became confused, feeling +that she ought not to have asked it. He smiled, looking at her, and +said he liked her singing as he liked everything she did. + +Prince Andrew left the Rostovs' late in the evening. He went to +bed from habit, but soon realized that he could not sleep. Having +lit his candle he sat up in bed, then got up, then lay down again +not at all troubled by his sleeplessness: his soul was as fresh and +joyful as if he had stepped out of a stuffy room into God's own +fresh air. It did not enter his head that he was in love with Natasha; +he was not thinking about her, but only picturing her to himself, +and in consequence all life appeared in a new light. "Why do I strive, +why do I toil in this narrow, confined frame, when life, all life with +all its joys, is open to me?" said he to himself. And for the first +time for a very long while he began making happy plans for the future. +He decided that he must attend to his son's education by finding a +tutor and putting the boy in his charge, then he ought to retire +from the service and go abroad, and see England, Switzerland and +Italy. "I must use my freedom while I feel so much strength and +youth in me," he said to himself. "Pierre was right when he said one +must believe in the possibility of happiness in order to be happy, and +now I do believe in it. Let the dead bury their dead, but while one +has life one must live and be happy!" thought he. + + + + + +CHAPTER XX + + +One morning Colonel Berg, whom Pierre knew as he knew everybody in +Moscow and Petersburg, came to see him. Berg arrived in an +immaculate brand-new uniform, with his hair pomaded and brushed +forward over his temples as the Emperor Alexander wore his hair. + +"I have just been to see the countess, your wife. Unfortunately +she could not grant my request, but I hope, Count, I shall be more +fortunate with you," he said with a smile. + +"What is it you wish, Colonel? I am at your service." + +"I have now quite settled in my new rooms, Count" (Berg said this +with perfect conviction that this information could not but be +agreeable), "and so I wish to arrange just a small party for my own +and my wife's friends." (He smiled still more pleasantly.) "I wished +to ask the countess and you to do me the honor of coming to tea and to +supper." + +Only Countess Helene, considering the society of such people as +the Bergs beneath her, could be cruel enough to refuse such an +invitation. Berg explained so clearly why he wanted to collect at +his house a small but select company, and why this would give him +pleasure, and why though he grudged spending money on cards or +anything harmful, he was prepared to run into some expense for the +sake of good society--that Pierre could not refuse, and promised to +come. + +"But don't be late, Count, if I may venture to ask; about ten +minutes to eight, please. We shall make up a rubber. Our general is +coming. He is very good to me. We shall have supper, Count. So you +will do me the favor." + +Contrary to his habit of being late, Pierre on that day arrived at +the Bergs' house, not at ten but at fifteen minutes to eight. + +Having prepared everything necessary for the party, the Bergs were +ready for their guests' arrival. + +In their new, clean, and light study with its small busts and +pictures and new furniture sat Berg and his wife. Berg, closely +buttoned up in his new uniform, sat beside his wife explaining to +her that one always could and should be acquainted with people above +one, because only then does one get satisfaction from acquaintances. + +"You can get to know something, you can ask for something. See how I +managed from my first promotion." (Berg measured his life not by years +but by promotions.) "My comrades are still nobodies, while I am only +waiting for a vacancy to command a regiment, and have the happiness to +be your husband." (He rose and kissed Vera's hand, and on the way to +her straightened out a turned-up corner of the carpet.) "And how +have I obtained all this? Chiefly by knowing how to choose my +aquaintances. It goes without saying that one must be conscientious +and methodical." + +Berg smiled with a sense of his superiority over a weak woman, and +paused, reflecting that this dear wife of his was after all but a weak +woman who could not understand all that constitutes a man's dignity, +what it was ein Mann zu sein.* Vera at the same time smiling with a +sense of superiority over her good, conscientious husband, who all the +same understood life wrongly, as according to Vera all men did. +Berg, judging by his wife, thought all women weak and foolish. Vera, +judging only by her husband and generalizing from that observation, +supposed that all men, though they understand nothing and are +conceited and selfish, ascribe common sense to themselves alone. + + +*To be a man. + + +Berg rose and embraced his wife carefully, so as not to crush her +lace fichu for which he had paid a good price, kissing her straight on +the lips. + +"The only thing is, we mustn't have children too soon," he +continued, following an unconscious sequence of ideas. + +"Yes," answered Vera, "I don't at all want that. We must live for +society." + +"Princess Yusupova wore one exactly like this," said Berg, +pointing to the fichu with a happy and kindly smile. + +Just then Count Bezukhov was announced. Husband and wife glanced +at one another, both smiling with self-satisfaction, and each mentally +claiming the honor of this visit. + +"This is what what comes of knowing how to make acquaintances," +thought Berg. "This is what comes of knowing how to conduct oneself." + +"But please don't interrupt me when I am entertaining the guests," +said Vera, "because I know what interests each of them and what to say +to different people." + +Berg smiled again. + +"It can't be helped: men must sometimes have masculine +conversation," said he. + +They received Pierre in their small, new drawing-room, where it +was impossible to sit down anywhere without disturbing its symmetry, +neatness, and order; so it was quite comprehensible and not strange +that Berg, having generously offered to disturb the symmetry of an +armchair or of the sofa for his dear guest, but being apparently +painfully undecided on the matter himself, eventually left the visitor +to settle the question of selection. Pierre disturbed the symmetry +by moving a chair for himself, and Berg and Vera immediately began +their evening party, interrupting each other in their efforts to +entertain their guest. + +Vera, having decided in her own mind that Pierre ought to be +entertained with conversation about the French embassy, at once +began accordingly. Berg, having decided that masculine conversation +was required, interrupted his wife's remarks and touched on the +question of the war with Austria, and unconsciously jumped from the +general subject to personal considerations as to the proposals made +him to take part in the Austrian campaign and the reasons why he had +declined them. Though the conversation was very incoherent and Vera +was angry at the intrusion of the masculine element, both husband +and wife felt with satisfaction that, even if only one guest was +present, their evening had begun very well and was as like as two peas +to every other evening party with its talk, tea, and lighted candles. + +Before long Boris, Berg's old comrade, arrived. There was a shade of +condescension and patronage in his treatment of Berg and Vera. After +Boris came a lady with the colonel, then the general himself, then the +Rostovs, and the party became unquestionably exactly like all other +evening parties. Berg and Vera could not repress their smiles of +satisfaction at the sight of all this movement in their drawing +room, at the sound of the disconnected talk, the rustling of +dresses, and the bowing and scraping. Everything was just as everybody +always has it, especially so the general, who admired the apartment, +patted Berg on the shoulder, and with parental authority superintended +the setting out of the table for boston. The general sat down by Count +Ilya Rostov, who was next to himself the most important guest. The old +people sat with the old, the young with the young, and the hostess +at the tea table, on which stood exactly the same kind of cakes in a +silver cake basket as the Panins had at their party. Everything was +just as it was everywhere else. + + + + + +CHAPTER XXI + + +Pierre, as one of the principal guests, had to sit down to boston +with Count Rostov, the general, and the colonel. At the card table +he happened to be directly facing Natasha, and was struck by a curious +change that had come over her since the ball. She was silent, and +not only less pretty than at the ball, but only redeemed from +plainness by her look of gentle indifference to everything around. + +"What's the matter with her?" thought Pierre, glancing at her. She +was sitting by her sister at the tea table, and reluctantly, without +looking at him, made some reply to Boris who sat down beside her. +After playing out a whole suit and to his partner's delight taking +five tricks, Pierre, hearing greetings and the steps of someone who +had entered the room while he was picking up his tricks, glanced again +at Natasha. + +"What has happened to her?" he asked himself with still greater +surprise. + +Prince Andrew was standing before her, saying something to her +with a look of tender solicitude. She, having raised her head, was +looking up at him, flushed and evidently trying to master her rapid +breathing. And the bright glow of some inner fire that had been +suppressed was again alight in her. She was completely transformed and +from a plain girl had again become what she had been at the ball. + +Prince Andrew went up to Pierre, and the latter noticed a new and +youthful expression in his friend's face. + +Pierre changed places several times during the game, sitting now +with his back to Natasha and now facing her, but during the whole of +the six rubbers he watched her and his friend. + +"Something very important is happening between them," thought +Pierre, and a feeling that was both joyful and painful agitated him +and made him neglect the game. + +After six rubbers the general got up, saying that it was no use +playing like that, and Pierre was released. Natasha on one side was +talking with Sonya and Boris, and Vera with a subtle smile was +saying something to Prince Andrew. Pierre went up to his friend and, +asking whether they were talking secrets, sat down beside them. +Vera, having noticed Prince Andrew's attentions to Natasha, decided +that at a party, a real evening party, subtle allusions to the +tender passion were absolutely necessary and, seizing a moment when +Prince Andrew was alone, began a conversation with him about +feelings in general and about her sister. With so intellectual a guest +as she considered Prince Andrew to be, she felt that she had to employ +her diplomatic tact. + +When Pierre went up to them he noticed that Vera was being carried +away by her self-satisfied talk, but that Prince Andrew seemed +embarrassed, a thing that rarely happened with him. + +"What do you think?" Vera was saying with an arch smile. "You are so +discerning, Prince, and understand people's characters so well at a +glance. What do you think of Natalie? Could she be constant in her +attachments? Could she, like other women" (Vera meant herself), +"love a man once for all and remain true to him forever? That is +what I consider true love. What do you think, Prince?" + +"I know your sister too little," replied Prince Andrew, with a +sarcastic smile under which he wished to hide his embarrassment, "to +be able to solve so delicate a question, and then I have noticed +that the less attractive a woman is the more constant she is likely to +be," he added, and looked up Pierre who was just approaching them. + +"Yes, that is true, Prince. In our days," continued Vera--mentioning +"our days" as people of limited intelligence are fond of doing, +imagining that they have discovered and appraised the peculiarities of +"our days" and that human characteristics change with the times--"in +our days a girl has so much freedom that the pleasure of being courted +often stifles real feeling in her. And it must be confessed that +Natalie is very susceptible." This return to the subject of Natalie +caused Prince Andrew to knit his brows with discomfort: he was about +to rise, but Vera continued with a still more subtle smile: + +"I think no one has been more courted than she," she went on, "but +till quite lately she never cared seriously for anyone. Now you +know, Count," she said to Pierre, "even our dear cousin Boris, who, +between ourselves, was very far gone in the land of tenderness..." +(alluding to a map of love much in vogue at that time). + +Prince Andrew frowned and remained silent. + +"You are friendly with Boris, aren't you?" asked Vera. + +"Yes, I know him..." + +"I expect he has told you of his childish love for Natasha?" + +"Oh, there was childish love?" suddenly asked Prince Andrew, +blushing unexpectedly. + +"Yes, you know between cousins intimacy often leads to love. Le +cousinage est un dangereux voisinage.* Don't you think so?" + + +*"Cousinhood is a dangerous neighborhood." + + +"Oh, undoubtedly!" said Prince Andrew, and with sudden and unnatural +liveliness he began chaffing Pierre about the need to be very +careful with his fifty-year-old Moscow cousins, and in the midst of +these jesting remarks he rose, taking Pierre by the arm, and drew +him aside. + +"Well?" asked Pierre, seeing his friend's strange animation with +surprise, and noticing the glance he turned on Natasha as he rose. + +"I must... I must have a talk with you," said Prince Andrew. "You +know that pair of women's gloves?" (He referred to the Masonic +gloves given to a newly initiated Brother to present to the woman he +loved.) "I... but no, I will talk to you later on," and with a strange +light in his eyes and restlessness in his movements, Prince Andrew +approached Natasha and sat down beside her. Pierre saw how Prince +Andrew asked her something and how she flushed as she replied. + +But at that moment Berg came to Pierre and began insisting that he +should take part in an argument between the general and the colonel on +the affairs in Spain. + +Berg was satisfied and happy. The smile of pleasure never left his +face. The party was very successful and quite like other parties he +had seen. Everything was similar: the ladies' subtle talk, the +cards, the general raising his voice at the card table, and the +samovar and the tea cakes; only one thing was lacking that he had +always seen at the evening parties he wished to imitate. They had +not yet had a loud conversation among the men and a dispute about +something important and clever. Now the general had begun such a +discussion and so Berg drew Pierre to it. + + + + + +CHAPTER XXII + + +Next day, having been invited by the count, Prince Andrew dined with +the Rostovs and spent the rest of the day there. + +Everyone in the house realized for whose sake Prince Andrew came, +and without concealing it he tried to be with Natasha all day. Not +only in the soul of the frightened yet happy and enraptured Natasha, +but in the whole house, there was a feeling of awe at something +important that was bound to happen. The countess looked with sad and +sternly serious eyes at Prince Andrew when he talked to Natasha and +timidly started some artificial conversation about trifles as soon +as he looked her way. Sonya was afraid to leave Natasha and afraid +of being in the way when she was with them. Natasha grew pale, in a +panic of expectation, when she remained alone with him for a moment. +Prince Andrew surprised her by his timidity. She felt that he wanted +to say something to her but could not bring himself to do so. + +In the evening, when Prince Andrew had left, the countess went up to +Natasha and whispered: "Well, what?" + +"Mamma! For heaven's sake don't ask me anything now! One can't +talk about that," said Natasha. + +But all the same that night Natasha, now agitated and now +frightened, lay a long time in her mother's bed gazing straight +before her. She told her how he had complimented her, how he told +her he was going abroad, asked her where they were going to spend +the summer, and then how he had asked her about Boris. + +"But such a... such a... never happened to me before!" she said. +"Only I feel afraid in his presence. I am always afraid when I'm +with him. What does that mean? Does it mean that it's the real +thing? Yes? Mamma, are you asleep?" + +"No, my love; I am frightened myself," answered her mother. "Now +go!" + +"All the same I shan't sleep. What silliness, to sleep! Mummy! +Mummy! such a thing never happened to me before," she said, +surprised and alarmed at the feeling she was aware of in herself. "And +could we ever have thought!..." + +It seemed to Natasha that even at the time she first saw Prince +Andrew at Otradnoe she had fallen in love with him. It was as if she +feared this strange, unexpected happiness of meeting again the very +man she had then chosen (she was firmly convinced she had done so) and +of finding him, as it seemed, not indifferent to her. + +"And it had to happen that he should come specially to Petersburg +while we are here. And it had to happen that we should meet at that +ball. It is fate. Clearly it is fate that everything led up to this! +Already then, directly I saw him I felt something peculiar." + +"What else did he say to you? What are those verses? Read them..." +said her mother, thoughtfully, referring to some verses Prince +Andrew had written in Natasha's album. + +"Mamma, one need not be ashamed of his being a widower?" + +"Don't, Natasha! Pray to God. 'Marriages are made in heaven,'" +said her mother. + +"Darling Mummy, how I love you! How happy I am!" cried Natasha, +shedding tears of joy and excitement and embracing her mother. + +At that very time Prince Andrew was sitting with Pierre and +telling him of his love for Natasha and his firm resolve to make her +his wife. + +That day Countess Helene had a reception at her house. The French +ambassador was there, and a foreign prince of the blood who had of +late become a frequent visitor of hers, and many brilliant ladies +and gentlemen. Pierre, who had come downstairs, walked through the +rooms and struck everyone by his preoccupied, absent-minded, and +morose air. + +Since the ball he had felt the approach of a fit of nervous +depression and had made desperate efforts to combat it. Since the +intimacy of his wife with the royal prince, Pierre had unexpectedly +been made a gentleman of the bedchamber, and from that time he had +begun to feel oppressed and ashamed in court society, and dark +thoughts of the vanity of all things human came to him oftener than +before. At the same time the feeling he had noticed between his +protegee Natasha and Prince Andrew accentuated his gloom by the +contrast between his own position and his friend's. He tried equally +to avoid thinking about his wife, and about Natasha and Prince Andrew; +and again everything seemed to him insignificant in comparison with +eternity; again the question: for what? presented itself; and he +forced himself to work day and night at Masonic labors, hoping to +drive away the evil spirit that threatened him. Toward midnight, after +he had left the countess' apartments, he was sitting upstairs in a +shabby dressing gown, copying out the original transaction of the +Scottish lodge of Freemasons at a table in his low room cloudy with +tobacco smoke, when someone came in. It was Prince Andrew. + +"Ah, it's you!" said Pierre with a preoccupied, dissatisfied air. +"And I, you see, am hard at it." He pointed to his manuscript book +with that air of escaping from the ills of life with which unhappy +people look at their work. + +Prince Andrew, with a beaming, ecstatic expression of renewed life +on his face, paused in front of Pierre and, not noticing his sad look, +smiled at him with the egotism of joy. + +"Well, dear heart," said he, "I wanted to tell you about it +yesterday and I have come to do so today. I never experienced anything +like it before. I am in love, my friend!" + +Suddenly Pierre heaved a deep sigh and dumped his heavy person +down on the sofa beside Prince Andrew. + +"With Natasha Rostova, yes?" said he. + +"Yes, yes! Who else should it be? I should never have believed it, +but the feeling is stronger than I. Yesterday I tormented myself and +suffered, but I would not exchange even that torment for anything in +the world, I have not lived till now. At last I live, but I can't live +without her! But can she love me?... I am too old for her.... Why +don't you speak?" + +"I? I? What did I tell you?" said Pierre suddenly, rising and +beginning to pace up and down the room. "I always thought it.... +That girl is such a treasure... she is a rare girl.... My dear friend, +I entreat you, don't philosophize, don't doubt, marry, marry, +marry.... And I am sure there will not be a happier man than you." + +"But what of her?" + +"She loves you." + +"Don't talk rubbish..." said Prince Andrew, smiling and looking into +Pierre's eyes. + +"She does, I know," Pierre cried fiercely. + +"But do listen," returned Prince Andrew, holding him by the arm. "Do +you know the condition I am in? I must talk about it to someone." + +"Well, go on, go on. I am very glad," said Pierre, and his face +really changed, his brow became smooth, and he listened gladly to +Prince Andrew. Prince Andrew seemed, and really was, quite a +different, quite a new man. Where was his spleen, his contempt for +life, his disillusionment? Pierre was the only person to whom he +made up his mind to speak openly; and to him he told all that was in +his soul. Now he boldly and lightly made plans for an extended future, +said he could not sacrifice his own happiness to his father's caprice, +and spoke of how he would either make his father consent to this +marriage and love her, or would do without his consent; then he +marveled at the feeling that had mastered him as at something strange, +apart from and independent of himself. + +"I should not have believed anyone who told me that I was capable of +such love," said Prince Andrew. "It is not at all the same feeling +that I knew in the past. The whole world is now for me divided into +two halves: one half is she, and there all is joy, hope, light: the +other half is everything where she is not, and there is all gloom +and darkness...." + +"Darkness and gloom," reiterated Pierre: "yes, yes, I understand +that." + +"I cannot help loving the light, it is not my fault. And I am very +happy! You understand me? I know you are glad for my sake." + +"Yes, yes," Pierre assented, looking at his friend with a touched +and sad expression in his eyes. The brighter Prince Andrew's lot +appeared to him, the gloomier seemed his own. + + + + + +CHAPTER XXIII + + +Prince Andrew needed his father's consent to his marriage, and to +obtain this he started for the country next day. + +His father received his son's communication with external composure, +but inward wrath. He could not comprehend how anyone could wish to +alter his life or introduce anything new into it, when his own life +was already ending. "If only they would let me end my days as I want +to," thought the old man, "then they might do as they please." With +his son, however, he employed the diplomacy he reserved for +important occasions and, adopting a quiet tone, discussed the whole +matter. + +In the first place the marriage was not a brilliant one as regards +birth, wealth, or rank. Secondly, Prince Andrew was no longer as young +as he had been and his health was poor (the old man laid special +stress on this), while she was very young. Thirdly, he had a son +whom it would be a pity to entrust to a chit of a girl. "Fourthly +and finally," the father said, looking ironically at his son, "I beg +you to put it off for a year: go abroad, take a cure, look out as +you wanted to for a German tutor for Prince Nicholas. Then if your +love or passion or obstinacy--as you please--is still as great, marry! +And that's my last word on it. Mind, the last..." concluded the +prince, in a tone which showed that nothing would make him alter his +decision. + +Prince Andrew saw clearly that the old man hoped that his +feelings, or his fiancee's, would not stand a year's test, or that +he (the old prince himself) would die before then, and he decided to +conform to his father's wish--to propose, and postpone the wedding for +a year. + +Three weeks after the last evening he had spent with the Rostovs, +Prince Andrew returned to Petersburg. + + +Next day after her talk with her mother Natasha expected Bolkonski +all day, but he did not come. On the second and third day it was the +same. Pierre did not come either and Natasha, not knowing that +Prince Andrew had gone to see his father, could not explain his +absence to herself. + +Three weeks passed in this way. Natasha had no desire to go out +anywhere and wandered from room to room like a shadow, idle and +listless; she wept secretly at night and did not go to her mother in +the evenings. She blushed continually and was irritable. It seemed +to her that everybody knew about her disappointment and was laughing +at her and pitying her. Strong as was her inward grief, this wound +to her vanity intensified her misery. + +Once she came to her mother, tried to say something, and suddenly +began to cry. Her tears were those of an offended child who does not +know why it is being punished. + +The countess began to soothe Natasha, who after first listening to +her mother's words, suddenly interrupted her: + +"Leave off, Mamma! I don't think, and don't want to think about +it! He just came and then left off, left off..." + +Her voice trembled, and she again nearly cried, but recovered and +went on quietly: + +"And I don't at all want to get married. And I am afraid of him; I +have now become quite calm, quite calm." + +The day after this conversation Natasha put on the old dress which +she knew had the peculiar property of conducing to cheerfulness in the +mornings, and that day she returned to the old way of life which she +had abandoned since the ball. Having finished her morning tea she went +to the ballroom, which she particularly liked for its loud +resonance, and began singing her solfeggio. When she had finished +her first exercise she stood still in the middle of the room and +sang a musical phrase that particularly pleased her. She listened +joyfully (as though she had not expected it) to the charm of the notes +reverberating, filling the whole empty ballroom, and slowly dying +away; and all at once she felt cheerful. "What's the good of making so +much of it? Things are nice as it is," she said to herself, and she +began walking up and down the room, not stepping simply on the +resounding parquet but treading with each step from the heel to the +toe (she had on a new and favorite pair of shoes) and listening to the +regular tap of the heel and creak of the toe as gladly as she had to +the sounds of her own voice. Passing a mirror she glanced into it. +"There, that's me!" the expression of her face seemed to say as she +caught sight of herself. "Well, and very nice too! I need nobody." + +A footman wanted to come in to clear away something in the room +but she would not let him, and having closed the door behind him +continued her walk. That morning she had returned to her favorite +mood--love of, and delight in, herself. "How charming that Natasha +is!" she said again, speaking as some third, collective, male +person. "Pretty, a good voice, young, and in nobody's way if only they +leave her in peace." But however much they left her in peace she could +not now be at peace, and immediately felt this. + +In the hall the porch door opened, and someone asked, "At home?" and +then footsteps were heard. Natasha was looking at the mirror, but +did not see herself. She listened to the sounds in the hall. When +she saw herself, her face was pale. It was he. She knew this for +certain, though she hardly heard his voice through the closed doors. + +Pale and agitated, Natasha ran into the drawing room. + +"Mamma! Bolkonski has come!" she said. "Mamma, it is awful, it is +unbearable! I don't want... to be tormented? What am I to do?..." + +Before the countess could answer, Prince Andrew entered the room +with an agitated and serious face. As soon as he saw Natasha his +face brightened. He kissed the countess' hand and Natasha's, and sat +down beside the sofa. + +"It is long since we had the pleasure..." began the countess, but +Prince Andrew interrupted her by answering her intended question, +obviously in haste to say what he had to. + +"I have not been to see all this time because I have been at my +father's. I had to talk over a very important matter with him. I +only got back last night," he said glancing at Natasha; "I want to +have a talk with you, Countess," he added after a moment's pause. + +The countess lowered her eyes, sighing deeply. + +"I am at your disposal," she murmured. + +Natasha knew that she ought to go away, but was unable to do so: +something gripped her throat, and regardless of manners she stared +straight at Prince Andrew with wide-open eyes. + +"At once? This instant!... No, it can't be!" she thought. + +Again he glanced at her, and that glance convinced her that she +was not mistaken. Yes, at once, that very instant, her fate would be +decided. + +"Go, Natasha! I will call you," said the countess in a whisper. + +Natasha glanced with frightened imploring eyes at Prince Andrew +and at her mother and went out. + +"I have come, Countess, to ask for your daughter's hand," said +Prince Andrew. + +The countess' face flushed hotly, but she said nothing. + +"Your offer..." she began at last sedately. He remained silent, +looking into her eyes. "Your offer..." (she grew confused) "is +agreeable to us, and I accept your offer. I am glad. And my husband... +I hope... but it will depend on her...." + +"I will speak to her when I have your consent.... Do you give it +to me?" said Prince Andrew. + +"Yes," replied the countess. She held out her hand to him, and +with a mixed feeling of estrangement and tenderness pressed her lips +to his forehead as he stooped to kiss her hand. She wished to love him +as a son, but felt that to her he was a stranger and a terrifying man. +"I am sure my husband will consent," said the countess, "but your +father..." + +"My father, to whom I have told my plans, has made it an express +condition of his consent that the wedding is not to take place for a +year. And I wished to tell you of that," said Prince Andrew. + +"It is true that Natasha is still young, but--so long as that?..." + +"It is unavoidable," said Prince Andrew with a sigh. + +"I will send her to you," said the countess, and left the room. + +"Lord have mercy upon us!" she repeated while seeking her daughter. + +Sonya said that Natasha was in her bedroom. Natasha was sitting on +the bed, pale and dry eyed, and was gazing at the icons and whispering +something as she rapidly crossed herself. Seeing her mother she jumped +up and flew to her. + +"Well, Mamma?... Well?..." + +"Go, go to him. He is asking for your hand," said the countess, +coldly it seemed to Natasha. "Go... go," said the mother, sadly and +reproachfully, with a deep sigh, as her daughter ran away. + +Natasha never remembered how she entered the drawing room. When +she came in and saw him she paused. "Is it possible that this stranger +has now become everything to me?" she asked herself, and immediately +answered, "Yes, everything! He alone is now dearer to me than +everything in the world." Prince Andrew came up to her with downcast +eyes. + +"I have loved you from the very first moment I saw you. May I hope?" + +He looked at her and was struck by the serious impassioned +expression of her face. Her face said: "Why ask? Why doubt what you +cannot but know? Why speak, when words cannot express what one feels?" + +She drew near to him and stopped. He took her hand and kissed it. + +"Do you love me?" + +"Yes, yes!" Natasha murmured as if in vexation. Then she sighed +loudly and, catching her breath more and more quickly, began to sob. + +"What is it? What's the matter?" + +"Oh, I am so happy!" she replied, smiled through her tears, bent +over closer to him, paused for an instant as if asking herself whether +she might, and then kissed him. + +Prince Andrew held her hands, looked into her eyes, and did not find +in his heart his former love for her. Something in him had suddenly +changed; there was no longer the former poetic and mystic charm of +desire, but there was pity for her feminine and childish weakness, +fear at her devotion and trustfulness, and an oppressive yet joyful +sense of the duty that now bound him to her forever. The present +feeling, though not so bright and poetic as the former, was stronger +and more serious. + +"Did your mother tell you that it cannot be for a year?" asked +Prince Andrew, still looking into her eyes. + +"Is it possible that I--the 'chit of a girl,' as everybody called +me," thought Natasha--"is it possible that I am now to be the wife and +the equal of this strange, dear, clever man whom even my father +looks up to? Can it be true? Can it be true that there can be no +more playing with life, that now I am grown up, that on me now lies +a responsibility for my every word and deed? Yes, but what did he +ask me?" + +"No," she replied, but she had not understood his question. + +"Forgive me!" he said. "But you are so young, and I have already +been through so much in life. I am afraid for you, you do not yet know +yourself." + +Natasha listened with concentrated attention, trying but failing +to take in the meaning of his words. + +"Hard as this year which delays my happiness will be," continued +Prince Andrew, "it will give you time to be sure of yourself. I ask +you to make me happy in a year, but you are free: our engagement shall +remain a secret, and should you find that you do not love me, or +should you come to love..." said Prince Andrew with an unnatural +smile. + +"Why do you say that?" Natasha interrupted him. "You know that +from the very day you first came to Otradnoe I have loved you," she +cried, quite convinced that she spoke the truth. + +"In a year you will learn to know yourself...." + +"A whole year!" Natasha repeated suddenly, only now realizing that +the marriage was to be postponed for a year. "But why a year? Why a +year?..." + +Prince Andrew began to explain to her the reasons for this delay. +Natasha did not hear him. + +"And can't it be helped?" she asked. Prince Andrew did not reply, +but his face expressed the impossibility of altering that decision. + +"It's awful! Oh, it's awful! awful!" Natasha suddenly cried, and +again burst into sobs. "I shall die, waiting a year: it's +impossible, it's awful!" She looked into her lover's face and saw in +it a look of commiseration and perplexity. + +"No, no! I'll do anything!" she said, suddenly checking her tears. +"I am so happy." + +The father and mother came into the room and gave the betrothed +couple their blessing. + +From that day Prince Andrew began to frequent the Rostovs' as +Natasha's affianced lover. + + + + + +CHAPTER XXIV + +No betrothal ceremony took place and Natasha's engagement to +Bolkonski was not announced; Prince Andrew insisted on that. He said +that as he was responsible for the delay he ought to bear the whole +burden of it; that he had given his word and bound himself forever, +but that he did not wish to bind Natasha and gave her perfect freedom. +If after six months she felt that she did not love him she would +have full right to reject him. Naturally neither Natasha nor her +parents wished to hear of this, but Prince Andrew was firm. He came +every day to the Rostovs', but did not behave to Natasha as an +affianced lover: he did not use the familiar thou, but said you to +her, and kissed only her hand. After their engagement, quite +different, intimate, and natural relations sprang up between them. +It was as if they had not known each other till now. Both liked to +recall how they had regarded each other when as yet they were +nothing to one another; they felt themselves now quite different +beings: then they were artificial, now natural and sincere. At first +the family felt some constraint in intercourse with Prince Andrew; +he seemed a man from another world, and for a long time Natasha +trained the family to get used to him, proudly assuring them all +that he only appeared to be different, but was really just like all of +them, and that she was not afraid of him and no one else ought to +be. After a few days they grew accustomed to him, and without +restraint in his presence pursued their usual way of life, in which he +took his part. He could talk about rural economy with the count, +fashions with the countess and Natasha, and about albums and fancywork +with Sonya. Sometimes the household both among themselves and in his +presence expressed their wonder at how it had all happened, and at the +evident omens there had been of it: Prince Andrew's coming to Otradnoe +and their coming to Petersburg, and the likeness between Natasha and +Prince Andrew which her nurse had noticed on his first visit, and +Andrew's encounter with Nicholas in 1805, and many other incidents +betokening that it had to be. + +In the house that poetic dullness and quiet reigned which always +accompanies the presence of a betrothed couple. Often when all sitting +together everyone kept silent. Sometimes the others would get up and +go away and the couple, left alone, still remained silent. They rarely +spoke of their future life. Prince Andrew was afraid and ashamed to +speak of it. Natasha shared this as she did all his feelings, which +she constantly divined. Once she began questioning him about his +son. Prince Andrew blushed, as he often did now--Natasha +particularly liked it in him--and said that his son would not live +with them. + +"Why not?" asked Natasha in a frightened tone. + +"I cannot take him away from his grandfather, and besides..." + +"How I should have loved him!" said Natasha, immediately guessing +his thought; "but I know you wish to avoid any pretext for finding +fault with us." + +Sometimes the old count would come up, kiss Prince Andrew, and ask +his advice about Petya's education or Nicholas' service. The old +countess sighed as she looked at them; Sonya was always getting +frightened lest she should be in the way and tried to find excuses for +leaving them alone, even when they did not wish it. When Prince Andrew +spoke (he could tell a story very well), Natasha listened to him +with pride; when she spoke she noticed with fear and joy that he gazed +attentively and scrutinizingly at her. She asked herself in +perplexity: "What does he look for in me? He is trying to discover +something by looking at me! What if what he seeks in me is not there?" +Sometimes she fell into one of the mad, merry moods characteristic +of her, and then she particularly loved to hear and see how Prince +Andrew laughed. He seldom laughed, but when he did he abandoned +himself entirely to his laughter, and after such a laugh she always +felt nearer to him. Natasha would have been completely happy if the +thought of the separation awaiting her and drawing near had not +terrified her, just as the mere thought of it made him turn pale and +cold. + +On the eve of his departure from Petersburg Prince Andrew brought +with him Pierre, who had not been to the Rostovs' once since the ball. +Pierre seemed disconcerted and embarrassed. He was talking to the +countess, and Natasha sat down beside a little chess table with Sonya, +thereby inviting Prince Andrew to come too. He did so. + +"You have known Bezukhov a long time?" he asked. "Do you like him?" + +"Yes, he's a dear, but very absurd." + +And as usual when speaking of Pierre, she began to tell anecdotes of +his absent-mindedness, some of which had even been invented about him. + +"Do you know I have entrusted him with our secret? I have known +him from childhood. He has a heart of gold. I beg you, Natalie," +Prince Andrew said with sudden seriousness--"I am going away and +heaven knows what may happen. You may cease to... all right, I know +I am not to say that. Only this, then: whatever may happen to you when +I am not here..." + +"What can happen?" + +"Whatever trouble may come," Prince Andrew continued, "I beg you, +Mademoiselle Sophie, whatever may happen, to turn to him alone for +advice and help! He is a most absent-minded and absurd fellow, but +he has a heart of gold." + +Neither her father, nor her mother, nor Sonya, nor Prince Andrew +himself could have foreseen how the separation from her lover would +act on Natasha. Flushed and agitated she went about the house all that +day, dry-eyed, occupied with most trivial matters as if not +understanding what awaited her. She did not even cry when, on taking +leave, he kissed her hand for the last time. "Don't go!" she said in a +tone that made him wonder whether he really ought not to stay and +which he remembered long afterwards. Nor did she cry when he was gone; +but for several days she sat in her room dry-eyed, taking no +interest in anything and only saying now and then, "Oh, why did he +go away?" + +But a fortnight after his departure, to the surprise of those around +her, she recovered from her mental sickness just as suddenly and +became her old self again, but with a change in her moral physiognomy, +as a child gets up after a long illness with a changed expression of +face. + + + + + +CHAPTER XXV + + +During that year after his son's departure, Prince Nicholas +Bolkonski's health and temper became much worse. He grew still more +irritable, and it was Princess Mary who generally bore the brunt of +his frequent fits of unprovoked anger. He seemed carefully to seek out +her tender spots so as to torture her mentally as harshly as possible. +Princess Mary had two passions and consequently two joys--her +nephew, little Nicholas, and religion--and these were the favorite +subjects of the prince's attacks and ridicule. Whatever was spoken +of he would bring round to the superstitiousness of old maids, or +the petting and spoiling of children. "You want to make him"--little +Nicholas--"into an old maid like yourself! A pity! Prince Andrew wants +a son and not an old maid," he would say. Or, turning to +Mademoiselle Bourienne, he would ask her in Princess Mary's presence +how she liked our village priests and icons and would joke about them. + +He continually hurt Princess Mary's feelings and tormented her, +but it cost her no effort to forgive him. Could he be to blame +toward her, or could her father, whom she knew loved her in spite of +it all, be unjust? And what is justice? The princess never thought +of that proud word "justice." All the complex laws of man centered for +her in one clear and simple law--the law of love and self-sacrifice +taught us by Him who lovingly suffered for mankind though He Himself +was God. What had she to do with the justice or injustice of other +people? She had to endure and love, and that she did. + +During the winter Prince Andrew had come to Bald Hills and had +been gay, gentle, and more affectionate than Princess Mary had known +him for a long time past. She felt that something had happened to him, +but he said nothing to her about his love. Before he left he had a +long talk with his father about something, and Princess Mary noticed +that before his departure they were dissatisfied with one another. + +Soon after Prince Andrew had gone, Princess Mary wrote to her friend +Julie Karagina in Petersburg, whom she had dreamed (as all girls +dream) of marrying to her brother, and who was at that time in +mourning for her own brother, killed in Turkey. + + +Sorrow, it seems, is our common lot, my dear, tender friend Julie. + +Your loss is so terrible that I can only explain it to myself as a +special providence of God who, loving you, wishes to try you and +your excellent mother. Oh, my friend! Religion, and religion alone, +can--I will not say comfort us--but save us from despair. Religion +alone can explain to us what without its help man cannot comprehend: +why, for what cause, kind and noble beings able to find happiness in +life--not merely harming no one but necessary to the happiness of +others--are called away to God, while cruel, useless, harmful persons, +or such as are a burden to themselves and to others, are left +living. The first death I saw, and one I shall never forget--that of +my dear sister-in-law--left that impression on me. Just as you ask +destiny why your splendid brother had to die, so I asked why that +angel Lise, who not only never wronged anyone, but in whose soul there +were never any unkind thoughts, had to die. And what do you think, +dear friend? Five years have passed since then, and already I, with my +petty understanding, begin to see clearly why she had to die, and in +what way that death was but an expression of the infinite goodness +of the Creator, whose every action, though generally +incomprehensible to us, is but a manifestation of His infinite love +for His creatures. Perhaps, I often think, she was too angelically +innocent to have the strength to perform all a mother's duties. As a +young wife she was irreproachable; perhaps she could not have been +so as a mother. As it is, not only has she left us, and particularly +Prince Andrew, with the purest regrets and memories, but probably +she will there receive a place I dare not hope for myself. But not +to speak of her alone, that early and terrible death has had the +most beneficent influence on me and on my brother in spite of all +our grief. Then, at the moment of our loss, these thoughts could not +occur to me; I should then have dismissed them with horror, but now +they are very clear and certain. I write all this to you, dear friend, +only to convince you of the Gospel truth which has become for me a +principle of life: not a single hair of our heads will fall without +His will. And His will is governed only by infinite love for us, and +so whatever befalls us is for our good. + +You ask whether we shall spend next winter in Moscow. In spite of my +wish to see you, I do not think so and do not want to do so. You +will be surprised to hear that the reason for this is Buonaparte! +The case is this: my father's health is growing noticeably worse, he +cannot stand any contradiction and is becoming irritable. This +irritability is, as you know, chiefly directed to political questions. +He cannot endure the notion that Buonaparte is negotiating on equal +terms with all the sovereigns of Europe and particularly with our own, +the grandson of the Great Catherine! As you know, I am quite +indifferent to politics, but from my father's remarks and his talks +with Michael Ivanovich I know all that goes on in the world and +especially about the honors conferred on Buonaparte, who only at +Bald Hills in the whole world, it seems, is not accepted as a great +man, still less as Emperor of France. And my father cannot stand this. +It seems to me that it is chiefly because of his political views +that my father is reluctant to speak of going to Moscow; for he +foresees the encounters that would result from his way of expressing +his views regardless of anybody. All the benefit he might derive +from a course of treatment he would lose as a result of the disputes +about Buonaparte which would be inevitable. In any case it will be +decided very shortly. + +Our family life goes on in the old way except for my brother +Andrew's absence. He, as I wrote you before, has changed very much +of late. After his sorrow he only this year quite recovered his +spirits. He has again become as I used to know him when a child: kind, +affectionate, with that heart of gold to which I know no equal. He has +realized, it seems to me, that life is not over for him. But +together with this mental change he has grown physically much +weaker. He has become thinner and more nervous. I am anxious about him +and glad he is taking this trip abroad which the doctors recommended +long ago. I hope it will cure him. You write that in Petersburg he +is spoken of as one of the most active, cultivated, and capable of the +young men. Forgive my vanity as a relation, but I never doubted it. +The good he has done to everybody here, from his peasants up to the +gentry, is incalculable. On his arrival in Petersburg he received only +his due. I always wonder at the way rumors fly from Petersburg to +Moscow, especially such false ones as that you write about--I mean the +report of my brother's betrothal to the little Rostova. I do not think +my brother will ever marry again, and certainly not her; and this is +why: first, I know that though he rarely speaks about the wife he +has lost, the grief of that loss has gone too deep in his heart for +him ever to decide to give her a successor and our little angel a +stepmother. Secondly because, as far as I know, that girl is not the +kind of girl who could please Prince Andrew. I do not think he would +choose her for a wife, and frankly I do not wish it. But I am +running on too long and am at the end of my second sheet. Good-by, +my dear friend. May God keep you in His holy and mighty care. My +dear friend, Mademoiselle Bourienne, sends you kisses. + +MARY + + + + + +CHAPTER XXVI + + +In the middle of the summer Princess Mary received an unexpected +letter from Prince Andrew in Switzerland in which he gave her +strange and surprising news. He informed her of his engagement to +Natasha Rostova. The whole letter breathed loving rapture for his +betrothed and tender and confiding affection for his sister. He +wrote that he had never loved as he did now and that only now did he +understand and know what life was. He asked his sister to forgive +him for not having told her of his resolve when he had last visited +Bald Hills, though he had spoken of it to his father. He had not +done so for fear Princess Mary should ask her father to give his +consent, irritating him and having to bear the brunt of his +displeasure without attaining her object. "Besides," he wrote, "the +matter was not then so definitely settled as it is now. My father then +insisted on a delay of a year and now already six months, half of that +period, have passed, and my resolution is firmer than ever. If the +doctors did not keep me here at the spas I should be back in Russia, +but as it is I have to postpone my return for three months. You know +me and my relations with Father. I want nothing from him. I have +been and always shall be independent; but to go against his will and +arouse his anger, now that he may perhaps remain with us such a +short time, would destroy half my happiness. I am now writing to him +about the same question, and beg you to choose a good moment to hand +him the letter and to let me know how he looks at the whole matter and +whether there is hope that he may consent to reduce the term by four +months." + +After long hesitations, doubts, and prayers, Princess Mary gave +the letter to her father. The next day the old prince said to her +quietly: + +"Write and tell your brother to wait till I am dead.... It won't +be long--I shall soon set him free." + +The princess was about to reply, but her father would not let her +speak and, raising his voice more and more, cried: + +"Marry, marry, my boy!... A good family!... Clever people, eh? Rich, +eh? Yes, a nice stepmother little Nicholas will have! Write and tell +him that he may marry tomorrow if he likes. She will be little +Nicholas' stepmother and I'll marry Bourienne!... Ha, ha, ha! He +mustn't be without a stepmother either! Only one thing, no more +women are wanted in my house--let him marry and live by himself. +Perhaps you will go and live with him too?" he added, turning to +Princess Mary. "Go in heavens name! Go out into the frost... the +frost... the frost! + +After this outburst the prince did not speak any more about the +matter. But repressed vexation at his son's poor-spirited behavior +found expression in his treatment of his daughter. To his former +pretexts for irony a fresh one was now added--allusions to stepmothers +and amiabilities to Mademoiselle Bourienne. + +"Why shouldn't I marry her?" he asked his daughter. "She'll make a +splendid princess!" + +And latterly, to her surprise and bewilderment, Princess Mary +noticed that her father was really associating more and more with +the Frenchwoman. She wrote to Prince Andrew about the reception of his +letter, but comforted him with hopes of reconciling their father to +the idea. + +Little Nicholas and his education, her brother Andrew, and +religion were Princess Mary's joys and consolations; but besides that, +since everyone must have personal hopes, Princess Mary in the +profoundest depths of her heart had a hidden dream and hope that +supplied the chief consolation of her life. This comforting dream +and hope were given her by God's folk--the half-witted and other +pilgrims who visited her without the prince's knowledge. The longer +she lived, the more experience and observation she had of life, the +greater was her wonder at the short-sightedness of men who seek +enjoyment and happiness here on earth: toiling, suffering, struggling, +and harming one another, to obtain that impossible, visionary, +sinful happiness. Prince Andrew had loved his wife, she died, but that +was not enough: he wanted to bind his happiness to another woman. +Her father objected to this because he wanted a more distinguished and +wealthier match for Andrew. And they all struggled and suffered and +tormented one another and injured their souls, their eternal souls, +for the attainment of benefits which endure but for an instant. Not +only do we know this ourselves, but Christ, the Son of God, came +down to earth and told us that this life is but for a moment and is +a probation; yet we cling to it and think to find happiness in it. +"How is it that no one realizes this?" thought Princess Mary. "No +one except these despised God's folk who, wallet on back, come to me +by the back door, afraid of being seen by the prince, not for fear +of ill-usage by him but for fear of causing him to sin. To leave +family, home, and all the cares of worldly welfare, in order without +clinging to anything to wander in hempen rags from place to place +under an assumed name, doing no one any harm but praying for all- +for those who drive one away as well as for those who protect one: +higher than that life and truth there is no life or truth!" + +There was one pilgrim, a quiet pockmarked little woman of fifty +called Theodosia, who for over thirty years had gone about barefoot +and worn heavy chains. Princess Mary was particularly fond of her. +Once, when in a room with a lamp dimly lit before the icon Theodosia +was talking of her life, the thought that Theodosia alone had found +the true path of life suddenly came to Princess Mary with such force +that she resolved to become a pilgrim herself. When Theodosia had gone +to sleep Princess Mary thought about this for a long time, and at last +made up her mind that, strange as it might seem, she must go on a +pilgrimage. She disclosed this thought to no one but to her confessor, +Father Akinfi, the monk, and he approved of her intention. Under guise +of a present for the pilgrims, Princess Mary prepared a pilgrim's +complete costume for herself: a coarse smock, bast shoes, a rough +coat, and a black kerchief. Often, approaching the chest of drawers +containing this secret treasure, Princess Mary paused, uncertain +whether the time had not already come to put her project into +execution. + +Often, listening to the pilgrims' tales, she was so stimulated by +their simple speech, mechanical to them but to her so full of deep +meaning, that several times she was on the point of abandoning +everything and running away from home. In imagination she already +pictured herself by Theodosia's side, dressed in coarse rags, +walking with a staff, a wallet on her back, along the dusty road, +directing her wanderings from one saint's shrine to another, free from +envy, earthly love, or desire, and reaching at last the place where +there is no more sorrow or sighing, but eternal joy and bliss. + +"I shall come to a place and pray there, and before having time to +get used to it or getting to love it, I shall go farther. I will go on +till my legs fail, and I'll lie down and die somewhere, and shall at +last reach that eternal, quiet haven, where there is neither sorrow +nor sighing..." thought Princess Mary. + +But afterwards, when she saw her father and especially little Koko +(Nicholas), her resolve weakened. She wept quietly, and felt that +she was a sinner who loved her father and little nephew more than God. + + + + + +BOOK SEVEN: 1810 --11 + + + + + +CHAPTER I + + +The Bible legend tells us that the absence of labor--idleness--was a +condition of the first man's blessedness before the Fall. Fallen man +has retained a love of idleness, but the curse weighs on the race +not only because we have to seek our bread in the sweat of our +brows, but because our moral nature is such that we cannot be both +idle and at ease. An inner voice tells us we are in the wrong if we +are idle. If man could find a state in which he felt that though +idle he was fulfilling his duty, he would have found one of the +conditions of man's primitive blessedness. And such a state of +obligatory and irreproachable idleness is the lot of a whole class- +the military. The chief attraction of military service has consisted +and will consist in this compulsory and irreproachable idleness. + +Nicholas Rostov experienced this blissful condition to the full +when, after 1807, he continued to serve in the Pavlograd regiment, +in which he already commanded the squadron he had taken over from +Denisov. + +Rostov had become a bluff, good-natured fellow, whom his Moscow +acquaintances would have considered rather bad form, but who was liked +and respected by his comrades, subordinates, and superiors, and was +well contented with his life. Of late, in 1809, he found in letters +from home more frequent complaints from his mother that their +affairs were falling into greater and greater disorder, and that it +was time for him to come back to gladden and comfort his old parents. + +Reading these letters, Nicholas felt a dread of their wanting to +take him away from surroundings in which, protected from all the +entanglements of life, he was living so calmly and quietly. He felt +that sooner or later he would have to re-enter that whirlpool of life, +with its embarrassments and affairs to be straightened out, its +accounts with stewards, quarrels, and intrigues, its ties, society, +and with Sonya's love and his promise to her. It was all dreadfully +difficult and complicated; and he replied to his mother in cold, +formal letters in French, beginning: "My dear Mamma," and ending: +"Your obedient son," which said nothing of when he would return. In +1810 he received letters from his parents, in which they told him of +Natasha's engagement to Bolkonski, and that the wedding would be in +a year's time because the old prince made difficulties. This letter +grieved and mortified Nicholas. In the first place he was sorry that +Natasha, for whom he cared more than for anyone else in the family, +should be lost to the home; and secondly, from his hussar point of +view, he regretted not to have been there to show that fellow +Bolkonski that connection with him was no such great honor after +all, and that if he loved Natasha he might dispense with permission +from his dotard father. For a moment he hesitated whether he should +not apply for leave in order to see Natasha before she was married, +but then came the maneuvers, and considerations about Sonya and +about the confusion of their affairs, and Nicholas again put it off. +But in the spring of that year, he received a letter from his +mother, written without his father's knowledge, and that letter +persuaded him to return. She wrote that if he did not come and take +matters in hand, their whole property would be sold by auction and +they would all have to go begging. The count was so weak, and +trusted Mitenka so much, and was so good-natured, that everybody +took advantage of him and things were going from bad to worse. "For +God's sake, I implore you, come at once if you do not wish to make +me and the whole family wretched," wrote the countess. + +This letter touched Nicholas. He had that common sense of a +matter-of-fact man which showed him what he ought to do. + +The right thing now was, if not to retire from the service, at any +rate to go home on leave. Why he had to go he did not know; but +after his after-dinner nap he gave orders to saddle Mars, an extremely +vicious gray stallion that had not been ridden for a long time, and +when he returned with the horse all in a lather, he informed Lavrushka +(Denisov's servant who had remained with him) and his comrades who +turned up in the evening that he was applying for leave and was +going home. Difficult and strange as it was for him to reflect that he +would go away without having heard from the staff--and this interested +him extremely--whether he was promoted to a captaincy or would receive +the Order of St. Anne for the last maneuvers; strange as it was to +think that he would go away without having sold his three roans to the +Polish Count Golukhovski, who was bargaining for the horses Rostov had +betted he would sell for two thousand rubles; incomprehensible as it +seemed that the ball the hussars were giving in honor of the Polish +Mademoiselle Przazdziecka (out of rivalry to the Uhlans who had +given one in honor of their Polish Mademoiselle Borzozowska) would +take place without him--he knew he must go away from this good, bright +world to somewhere where everything was stupid and confused. A week +later he obtained his leave. His hussar comrades--not only those of +his own regiment, but the whole brigade--gave Rostov a dinner to which +the subscription was fifteen rubles a head, and at which there were +two bands and two choirs of singers. Rostov danced the Trepak with +Major Basov; the tipsy officers tossed, embraced, and dropped +Rostov; the soldiers of the third squadron tossed him too, and shouted +"hurrah!" and then they put him in his sleigh and escorted him as +far as the first post station. + +During the first half of the journey--from Kremenchug to Kiev--all +Rostov's thoughts, as is usual in such cases, were behind him, with +the squadron; but when he had gone more than halfway he began to +forget his three roans and Dozhoyveyko, his quartermaster, and to +wonder anxiously how things would be at Otradnoe and what he would +find there. Thoughts of home grew stronger the nearer he approached +it--far stronger, as though this feeling of his was subject to the law +by which the force of attraction is in inverse proportion to the +square of the distance. At the last post station before Otradnoe he +gave the driver a three-ruble tip, and on arriving he ran +breathlessly, like a boy, up the steps of his home. + +After the rapture of meeting, and after that odd feeling of +unsatisfied expectation--the feeling that "everything is just the +same, so why did I hurry?"--Nicholas began to settle down in his old +home world. His father and mother were much the same, only a little +older. What was new in them was a certain uneasiness and occasional +discord, which there used not to be, and which, as Nicholas soon found +out, was due to the bad state of their affairs. Sonya was nearly +twenty; she had stopped growing prettier and promised nothing more +than she was already, but that was enough. She exhaled happiness and +love from the time Nicholas returned, and the faithful, unalterable +love of this girl had a gladdening effect on him. Petya and Natasha +surprised Nicholas most. Petya was a big handsome boy of thirteen, +merry, witty, and mischievous, with a voice that was already breaking. +As for Natasha, for a long while Nicholas wondered and laughed +whenever he looked at her. + +"You're not the same at all," he said. + +"How? Am I uglier?" + +"On the contrary, but what dignity? A princess!" he whispered to +her. + +"Yes, yes, yes!" cried Natasha, joyfully. + +She told him about her romance with Prince Andrew and of his visit +to Otradnoe and showed him his last letter. + +"Well, are you glad?" Natasha asked. "I am so tranquil and happy +now." + +"Very glad," answered Nicholas. "He is an excellent fellow.... And +are you very much in love?" + +"How shall I put it?" replied Natasha. "I was in love with Boris, +with my teacher, and with Denisov, but this is quite different. I feel +at peace and settled. I know that no better man than he exists, and +I am calm and contented now. Not at all as before." + +Nicholas expressed his disapproval of the postponement of the +marriage for a year; but Natasha attacked her brother with +exasperation, proving to him that it could not be otherwise, and +that it would be a bad thing to enter a family against the father's +will, and that she herself wished it so. + +"You don't at all understand," she said. + +Nicholas was silent and agreed with her. + +Her brother often wondered as he looked at her. She did not seem +at all like a girl in love and parted from her affianced husband. +She was even-tempered and calm and quite as cheerful as of old. This +amazed Nicholas and even made him regard Bolkonski's courtship +skeptically. He could not believe that her fate was sealed, especially +as he had not seen her with Prince Andrew. It always seemed to him +that there was something not quite right about this intended marriage. + +"Why this delay? Why no betrothal?" he thought. Once, when he had +touched on this topic with his mother, he discovered, to his +surprise and somewhat to his satisfaction, that in the depth of her +soul she too had doubts about this marriage. + +"You see he writes," said she, showing her son a letter of Prince +Andrew's, with that latent grudge a mother always has in regard to a +daughter's future married happiness, "he writes that he won't come +before December. What can be keeping him? Illness, probably! His +health is very delicate. Don't tell Natasha. And don't attach +importance to her being so bright: that's because she's living through +the last days of her girlhood, but I know what she is like every +time we receive a letter from him! However, God grant that +everything turns out well!" (She always ended with these words.) "He +is an excellent man!" + + + + + +CHAPTER II + + +After reaching home Nicholas was at first serious and even dull. +He was worried by the impending necessity of interfering in the stupid +business matters for which his mother had called him home. To throw +off this burden as quickly as possible, on the third day after his +arrival he went, angry and scowling and without answering questions as +to where he was going, to Mitenka's lodge and demanded an account of +everything. But what an account of everything might be Nicholas knew +even less than the frightened and bewildered Mitenka. The conversation +and the examination of the accounts with Mitenka did not last long. +The village elder, a peasant delegate, and the village clerk, who were +waiting in the passage, heard with fear and delight first the young +count's voice roaring and snapping and rising louder and louder, and +then words of abuse, dreadful words, ejaculated one after the other. + +"Robber!... Ungrateful wretch!... I'll hack the dog to pieces! I'm +not my father!... Robbing us!..." and so on. + +Then with no less fear and delight they saw how the young count, red +in the face and with bloodshot eyes, dragged Mitenka out by the scruff +of the neck and applied his foot and knee to his behind with great +agility at convenient moments between the words, shouting, "Be off! +Never let me see your face here again, you villain!" + +Mitenka flew headlong down the six steps and ran away into the +shrubbery. (This shrubbery was a well-known haven of refuge for +culprits at Otradnoe. Mitenka himself, returning tipsy from the +town, used to hide there, and many of the residents at Otradnoe, +hiding from Mitenka, knew of its protective qualities.) + +Mitenka's wife and sisters-in-law thrust their heads and +frightened faces out of the door of a room where a bright samovar +was boiling and where the steward's high bedstead stood with its +patchwork quilt. + +The young count paid no heed to them, but, breathing hard, passed by +with resolute strides and went into the house. + +The countess, who heard at once from the maids what had happened +at the lodge, was calmed by the thought that now their affairs would +certainly improve, but on the other hand felt anxious as to the effect +this excitement might have on her son. She went several times to his +door on tiptoe and listened, as he lighted one pipe after another. + +Next day the old count called his son aside and, with an embarrassed +smile, said to him: + +"But you know, my dear boy, it's a pity you got excited! Mitenka has +told me all about it." + +"I knew," thought Nicholas, "that I should never understand anything +in this crazy world." + +"You were angry that he had not entered those 700 rubles. But they +were carried forward--and you did not look at the other page." + +"Papa, he is a blackguard and a thief! I know he is! And what I have +done, I have done; but, if you like, I won't speak to him again." + +"No, my dear boy" (the count, too, felt embarrassed. He knew he +had mismanaged his wife's property and was to blame toward his +children, but he did not know how to remedy it). "No, I beg you to +attend to the business. I am old. I..." + +"No, Papa. Forgive me if I have caused you unpleasantness. I +understand it all less than you do." + +"Devil take all these peasants, and money matters, and carryings +forward from page to page," he thought. "I used to understand what a +'corner' and the stakes at cards meant, but carrying forward to +another page I don't understand at all," said he to himself, and after +that he did not meddle in business affairs. But once the countess +called her son and informed him that she had a promissory note from +Anna Mikhaylovna for two thousand rubles, and asked him what he +thought of doing with it. + +"This," answered Nicholas. "You say it rests with me. Well, I +don't like Anna Mikhaylovna and I don't like Boris, but they were +our friends and poor. Well then, this!" and he tore up the note, and +by so doing caused the old countess to weep tears of joy. After +that, young Rostov took no further part in any business affairs, but +devoted himself with passionate enthusiasm to what was to him a new +pursuit--the chase--for which his father kept a large establishment. + + + + + +CHAPTER III + + +The weather was already growing wintry and morning frosts +congealed an earth saturated by autumn rains. The verdure had +thickened and its bright green stood out sharply against the +brownish strips of winter rye trodden down by the cattle, and +against the pale-yellow stubble of the spring buckwheat. The wooded +ravines and the copses, which at the end of August had still been +green islands amid black fields and stubble, had become golden and +bright-red islands amid the green winter rye. The hares had already +half changed their summer coats, the fox cubs were beginning to +scatter, and the young wolves were bigger than dogs. It was the best +time of the year for the chase. The hounds of that ardent young +sportsman Rostov had not merely reached hard winter condition, but +were so jaded that at a meeting of the huntsmen it was decided to give +them a three days' rest and then, on the sixteenth of September, to go +on a distant expedition, starting from the oak grove where there was +an undisturbed litter of wolf cubs. + +All that day the hounds remained at home. It was frosty and the +air was sharp, but toward evening the sky became overcast and it began +to thaw. On the fifteenth, when young Rostov, in his dressing gown, +looked out of the window, he saw it was an unsurpassable morning for +hunting: it was as if the sky were melting and sinking to the earth +without any wind. The only motion in the air was that of the dripping, +microscopic particles of drizzling mist. The bare twigs in the +garden were hung with transparent drops which fell on the freshly +fallen leaves. The earth in the kitchen garden looked wet and black +and glistened like poppy seed and at a short distance merged into +the dull, moist veil of mist. Nicholas went out into the wet and muddy +porch. There was a smell of decaying leaves and of dog. Milka, a +black-spotted, broad-haunched bitch with prominent black eyes, got +up on seeing her master, stretched her hind legs, lay down like a +hare, and then suddenly jumped up and licked him right on his nose and +mustache. Another borzoi, a dog, catching sight of his master from the +garden path, arched his back and, rushing headlong toward the porch +with lifted tail, began rubbing himself against his legs. + +"O-hoy!" came at that moment, that inimitable huntsman's call +which unites the deepest bass with the shrillest tenor, and round +the corner came Daniel the head huntsman and head kennelman, a gray, +wrinkled old man with hair cut straight over his forehead, Ukrainian +fashion, a long bent whip in his hand, and that look of independence +and scorn of everything that is only seen in huntsmen. He doffed his +Circassian cap to his master and looked at him scornfully. This +scorn was not offensive to his master. Nicholas knew that this Daniel, +disdainful of everybody and who considered himself above them, was all +the same his serf and huntsman. + +"Daniel!" Nicholas said timidly, conscious at the sight of the +weather, the hounds, and the huntsman that he was being carried away +by that irresistible passion for sport which makes a man forget all +his previous resolutions, as a lover forgets in the presence of his +mistress. + +"What orders, your excellency?" said the huntsman in his deep +bass, deep as a proto-deacon's and hoarse with hallooing--and two +flashing black eyes gazed from under his brows at his master, who +was silent. "Can you resist it?" those eyes seemed to be asking. + +"It's a good day, eh? For a hunt and a gallop, eh?" asked +Nicholas, scratching Milka behind the ears. + +Daniel did not answer, but winked instead. + +"I sent Uvarka at dawn to listen," his bass boomed out after a +minute's pause. "He says she's moved them into the Otradnoe enclosure. +They were howling there." (This meant that the she-wolf, about whom +they both knew, had moved with her cubs to the Otradnoe copse, a small +place a mile and a half from the house.) + +"We ought to go, don't you think so?" said Nicholas. "Come to me +with Uvarka." + +"As you please." + +"Then put off feeding them." + +"Yes, sir." + +Five minutes later Daniel and Uvarka were standing in Nicholas' +big study. Though Daniel was not a big man, to see him in a room was +like seeing a horse or a bear on the floor among the furniture and +surroundings of human life. Daniel himself felt this, and as usual +stood just inside the door, trying to speak softly and not move, for +fear of breaking something in the master's apartment, and he +hastened to say all that was necessary so as to get from under that +ceiling, out into the open under the sky once more. + +Having finished his inquiries and extorted from Daniel an opinion +that the hounds were fit (Daniel himself wished to go hunting), +Nicholas ordered the horses to be saddled. But just as Daniel was +about to go Natasha came in with rapid steps, not having done up her +hair or finished dressing and with her old nurse's big shawl wrapped +round her. Petya ran in at the same time. + +"You are going?" asked Natasha. "I knew you would! Sonya said you +wouldn't go, but I knew that today is the sort of day when you +couldn't help going." + +"Yes, we are going," replied Nicholas reluctantly, for today, as +he intended to hunt seriously, he did not want to take Natasha and +Petya. "We are going, but only wolf hunting: it would be dull for +you." + +"You know it is my greatest pleasure," said Natasha. "It's not fair; +you are going by yourself, are having the horses saddled and said +nothing to us about it." + +"'No barrier bars a Russian's path'--we'll go!" shouted Petya. + +"But you can't. Mamma said you mustn't," said Nicholas to Natasha. + +"Yes, I'll go. I shall certainly go," said Natasha decisively. +"Daniel, tell them to saddle for us, and Michael must come with my +dogs," she added to the huntsman. + +It seemed to Daniel irksome and improper to be in a room at all, but +to have anything to do with a young lady seemed to him impossible. +He cast down his eyes and hurried out as if it were none of his +business, careful as he went not to inflict any accidental injury on +the young lady. + + + + + +CHAPTER IV + + +The old count, who had always kept up an enormous hunting +establishment but had now handed it all completely over to his son's +care, being in very good spirits on this fifteenth of September, +prepared to go out with the others. + +In an hour's time the whole hunting party was at the porch. +Nicholas, with a stern and serious air which showed that now was no +time for attending to trifles, went past Natasha and Petya who were +trying to tell him something. He had a look at all the details of +the hunt, sent a pack of hounds and huntsmen on ahead to find the +quarry, mounted his chestnut Donets, and whistling to his own leash of +borzois, set off across the threshing ground to a field leading to the +Otradnoe wood. The old count's horse, a sorrel gelding called +Viflyanka, was led by the groom in attendance on him, while the +count himself was to drive in a small trap straight to a spot reserved +for him. + +They were taking fifty-four hounds, with six hunt attendants and +whippers-in. Besides the family, there were eight borzoi kennelmen and +more than forty borzois, so that, with the borzois on the leash +belonging to members of the family, there were about a hundred and +thirty dogs and twenty horsemen. + +Each dog knew its master and its call. Each man in the hunt knew his +business, his place, what he had to do. As soon as they had passed the +fence they all spread out evenly and quietly, without noise or talk, +along the road and field leading to the Otradnoe covert. + +The horses stepped over the field as over a thick carpet, now and +then splashing into puddles as they crossed a road. The misty sky +still seemed to descend evenly and imperceptibly toward the earth, the +air was still, warm, and silent. Occasionally the whistle of a +huntsman, the snort of a horse, the crack of a whip, or the whine of a +straggling hound could be heard. + +When they had gone a little less than a mile, five more riders +with dogs appeared out of the mist, approaching the Rostovs. In +front rode a fresh-looking, handsome old man with a large gray +mustache. + +"Good morning, Uncle!" said Nicholas, when the old man drew near. + +"That's it. Come on!... I was sure of it," began "Uncle." (He was +a distant relative of the Rostovs', a man of small means, and their +neighbor.) "I knew you wouldn't be able to resist it and it's a good +thing you're going. That's it! Come on! (This was "Uncle's" favorite +expression.) "Take the covert at once, for my Girchik says the Ilagins +are at Korniki with their hounds. That's it. Come on!... They'll +take the cubs from under your very nose." + +"That's where I'm going. Shall we join up our packs?" asked +Nicholas. + +The hounds were joined into one pack, and "Uncle" and Nicholas +rode on side by side. Natasha, muffled up in shawls which did not hide +her eager face and shining eyes, galloped up to them. She was followed +by Petya who always kept close to her, by Michael, a huntsman, and +by a groom appointed to look after her. Petya, who was laughing, +whipped and pulled at his horse. Natasha sat easily and confidently on +her black Arabchik and reined him in without effort with a firm hand. + +"Uncle" looked round disapprovingly at Petya and Natasha. He did not +like to combine frivolity with the serious business of hunting. + +"Good morning, Uncle! We are going too!" shouted Petya. + +"Good morning, good morning! But don't go overriding the hounds," +said "Uncle" sternly. + +"Nicholas, what a fine dog Trunila is! He knew me," said Natasha, +referring to her favorite hound. + +"In the first place, Trunila is not a 'dog,' but a harrier," thought +Nicholas, and looked sternly at his sister, trying to make her feel +the distance that ought to separate them at that moment. Natasha +understood it. + +"You mustn't think we'll be in anyone's way, Uncle," she said. +"We'll go to our places and won't budge." + +"A good thing too, little countess," said "Uncle," "only mind you +don't fall off your horse," he added, "because--that's it, come on!- +you've nothing to hold on to." + +The oasis of the Otradnoe covert came in sight a few hundred yards +off, the huntsmen were already nearing it. Rostov, having finally +settled with "Uncle" where they should set on the hounds, and having +shown Natasha where she was to stand--a spot where nothing could +possibly run out--went round above the ravine. + +"Well, nephew, you're going for a big wolf," said "Uncle." "Mind and +don't let her slip!" + +"That's as may happen," answered Rostov. "Karay, here!" he +shouted, answering "Uncle's" remark by this call to his borzoi. +Karay was a shaggy old dog with a hanging jowl, famous for having +tackled a big wolf unaided. They all took up their places. + +The old count, knowing his son's ardor in the hunt, hurried so as +not to be late, and the huntsmen had not yet reached their places when +Count Ilya Rostov, cheerful, flushed, and with quivering cheeks, drove +up with his black horses over the winter rye to the place reserved for +him, where a wolf might come out. Having straightened his coat and +fastened on his hunting knives and horn, he mounted his good, sleek, +well-fed, and comfortable horse, Viflyanka, which was turning gray, +like himself. His horses and trap were sent home. Count Ilya Rostov, +though not at heart a keen sportsman, knew the rules of the hunt well, +and rode to the bushy edge of the road where he was to stand, arranged +his reins, settled himself in the saddle, and, feeling that he was +ready, looked about with a smile. + +Beside him was Simon Chekmar, his personal attendant, an old +horseman now somewhat stiff in the saddle. Chekmar held in leash three +formidable wolfhounds, who had, however, grown fat like their master +and his horse. Two wise old dogs lay down unleashed. Some hundred +paces farther along the edge of the wood stood Mitka, the count's +other groom, a daring horseman and keen rider to hounds. Before the +hunt, by old custom, the count had drunk a silver cupful of mulled +brandy, taken a snack, and washed it down with half a bottle of his +favorite Bordeaux. + +He was somewhat flushed with the wine and the drive. His eyes were +rather moist and glittered more than usual, and as he sat in his +saddle, wrapped up in his fur coat, he looked like a child taken out +for an outing. + +The thin, hollow-cheeked Chekmar, having got everything ready, +kept glancing at his master with whom he had lived on the best of +terms for thirty years, and understanding the mood he was in +expected a pleasant chat. A third person rode up circumspectly through +the wood (it was plain that he had had a lesson) and stopped behind +the count. This person was a gray-bearded old man in a woman's +cloak, with a tall peaked cap on his head. He was the buffoon, who +went by a woman's name, Nastasya Ivanovna. + +"Well, Nastasya Ivanovna!" whispered the count, winking at him. +"If you scare away the beast, Daniel'll give it you!" + +"I know a thing or two myself!" said Nastasya Ivanovna. + +"Hush!" whispered the count and turned to Simon. "Have you seen +the young countess?" he asked. "Where is she?" + +"With young Count Peter, by the Zharov rank grass," answered +Simon, smiling. "Though she's a lady, she's very fond of hunting." + +"And you're surprised at the way she rides, Simon, eh?" said the +count. "She's as good as many a man!" + +"Of course! It's marvelous. So bold, so easy!" + +"And Nicholas? Where is he? By the Lyadov upland, isn't he?" + +"Yes, sir. He knows where to stand. He understands the matter so +well that Daniel and I are often quite astounded," said Simon, well +knowing what would please his master. + +"Rides well, eh? And how well he looks on his horse, eh?" + +"A perfect picture! How he chased a fox out of the rank grass by the +Zavarzinsk thicket the other day! Leaped a fearful place; what a sight +when they rushed from the covert... the horse worth a thousand +rubles and the rider beyond all price! Yes, one would have to search +far to find another as smart." + +"To search far..." repeated the count, evidently sorry Simon had not +said more. "To search far," he said, turning back the skirt of his +coat to get at his snuffbox. + +"The other day when he came out from Mass in full uniform, Michael +Sidorych..." Simon did not finish, for on the still air he had +distinctly caught the music of the hunt with only two or three +hounds giving tongue. He bent down his head and listened, shaking a +warning finger at his master. "They are on the scent of the cubs..." +he whispered, "straight to the Lyadov uplands." + +The count, forgetting to smooth out the smile on his face, looked +into the distance straight before him, down the narrow open space, +holding the snuffbox in his hand but not taking any. After the cry +of the hounds came the deep tones of the wolf call from Daniel's +hunting horn; the pack joined the first three hounds and they could be +heard in full cry, with that peculiar lift in the note that +indicates that they are after a wolf. The whippers-in no longer set on +the hounds, but changed to the cry of ulyulyu, and above the others +rose Daniel's voice, now a deep bass, now piercingly shrill. His voice +seemed to fill the whole wood and carried far beyond out into the open +field. + +After listening a few moments in silence, the count and his +attendant convinced themselves that the hounds had separated into +two packs: the sound of the larger pack, eagerly giving tongue, +began to die away in the distance, the other pack rushed by the wood +past the count, and it was with this that Daniel's voice was heard +calling ulyulyu. The sounds of both packs mingled and broke apart +again, but both were becoming more distant. + +Simon sighed and stooped to straighten the leash a young borzoi +had entangled; the count too sighed and, noticing the snuffbox in +his hand, opened it and took a pinch. "Back!" cried Simon to a +borzoi that was pushing forward out of the wood. The count started and +dropped the snuffbox. Nastasya Ivanovna dismounted to pick it up. +The count and Simon were looking at him. + +Then, unexpectedly, as often happens, the sound of the hunt suddenly +approached, as if the hounds in full cry and Daniel ulyulyuing were +just in front of them. + +The count turned and saw on his right Mitka staring at him with eyes +starting out of his head, raising his cap and pointing before him to +the other side. + +"Look out!" he shouted, in a voice plainly showing that he had +long fretted to utter that word, and letting the borzois slip he +galloped toward the count. + +The count and Simon galloped out of the wood and saw on their left a +wolf which, softly swaying from side to side, was coming at a quiet +lope farther to the left to the very place where they were standing. +The angry borzois whined and getting free of the leash rushed past the +horses' feet at the wolf. + +The wolf paused, turned its heavy forehead toward the dogs +awkwardly, like a man suffering from the quinsy, and, still slightly +swaying from side to side, gave a couple of leaps and with a swish +of its tail disappeared into the skirt of the wood. At the same +instant, with a cry like a wail, first one hound, then another, and +then another, sprang helter-skelter from the wood opposite and the +whole pack rushed across the field toward the very spot where the wolf +had disappeared. The hazel bushes parted behind the hounds and +Daniel's chestnut horse appeared, dark with sweat. On its long back +sat Daniel, hunched forward, capless, his disheveled gray hair hanging +over his flushed, perspiring face. + +"Ulyulyulyu! ulyulyu!..." he cried. When he caught sight of the +count his eyes flashed lightning. + +"Blast you!" he shouted, holding up his whip threateningly at the +count. + +"You've let the wolf go!... What sportsmen!" and as if scorning to +say more to the frightened and shamefaced count, he lashed the heaving +flanks of his sweating chestnut gelding with all the anger the count +had aroused and flew off after the hounds. The count, like a +punished schoolboy, looked round, trying by a smile to win Simon's +sympathy for his plight. But Simon was no longer there. He was +galloping round by the bushes while the field was coming up on both +sides, all trying to head the wolf, but it vanished into the wood +before they could do so. + + + + + +CHAPTER V + + +Nicholas Rostov meanwhile remained at his post, waiting for the +wolf. By the way the hunt approached and receded, by the cries of +the dogs whose notes were familiar to him, by the way the voices of +the huntsmen approached, receded, and rose, he realized what was +happening at the copse. He knew that young and old wolves were +there, that the hounds had separated into two packs, that somewhere +a wolf was being chased, and that something had gone wrong. He +expected the wolf to come his way any moment. He made thousands of +different conjectures as to where and from what side the beast would +come and how he would set upon it. Hope alternated with despair. +Several times he addressed a prayer to God that the wolf should come +his way. He prayed with that passionate and shame-faced feeling with +which men pray at moments of great excitement arising from trivial +causes. "What would it be to Thee to do this for me?" he said to +God. "I know Thou art great, and that it is a sin to ask this of Thee, +but for God's sake do let the old wolf come my way and let Karay +spring at it--in sight of 'Uncle' who is watching from over there--and +seize it by the throat in a death grip!" A thousand times during +that half-hour Rostov cast eager and restless glances over the edge of +the wood, with the two scraggy oaks rising above the aspen undergrowth +and the gully with its water-worn side and "Uncle's" cap just +visible above the bush on his right. + +"No, I shan't have such luck," thought Rostov, "yet what wouldn't it +be worth! It is not to be! Everywhere, at cards and in war, I am +always unlucky." Memories of Austerlitz and of Dolokhov flashed +rapidly and clearly through his mind. "Only once in my life to get +an old wolf, I want only that!" thought he, straining eyes and ears +and looking to the left and then to the right and listening to the +slightest variation of note in the cries of the dogs. + +Again he looked to the right and saw something running toward him +across the deserted field. "No, it can't be!" thought Rostov, taking a +deep breath, as a man does at the coming of something long hoped +for. The height of happiness was reached--and so simply, without +warning, or noise, or display, that Rostov could not believe his +eyes and remained in doubt for over a second. The wolf ran forward and +jumped heavily over a gully that lay in her path. She was an old +animal with a gray back and big reddish belly. She ran without +hurry, evidently feeling sure that no one saw her. Rostov, holding his +breath, looked round at the borzois. They stood or lay not seeing +the wolf or understanding the situation. Old Karay had turned his head +and was angrily searching for fleas, baring his yellow teeth and +snapping at his hind legs. + +"Ulyulyulyu!" whispered Rostov, pouting his lips. The borzois jumped +up, jerking the rings of the leashes and pricking their ears. Karay +finished scratching his hindquarters and, cocking his ears, got up +with quivering tail from which tufts of matted hair hung down. + +"Shall I loose them or not?" Nicholas asked himself as the wolf +approached him coming from the copse. Suddenly the wolf's whole +physiognomy changed: she shuddered, seeing what she had probably never +seen before--human eyes fixed upon her--and turning her head a +little toward Rostov, she paused. + +"Back or forward? Eh, no matter, forward..." the wolf seemed to +say to herself, and she moved forward without again looking round +and with a quiet, long, easy yet resolute lope. + +"Ulyulyu!" cried Nicholas, in a voice not his own, and of its own +accord his good horse darted headlong downhill, leaping over gullies +to head off the wolf, and the borzois passed it, running faster still. +Nicholas did not hear his own cry nor feel that he was galloping, +nor see the borzois, nor the ground over which he went: he saw only +the wolf, who, increasing her speed, bounded on in the same +direction along the hollow. The first to come into view was Milka, +with her black markings and powerful quarters, gaining upon the +wolf. Nearer and nearer... now she was ahead of it; but the wolf +turned its head to face her, and instead of putting on speed as she +usually did Milka suddenly raised her tail and stiffened her forelegs. + +"Ulyulyulyulyu!" shouted Nicholas. + +The reddish Lyubim rushed forward from behind Milka, sprang +impetuously at the wolf, and seized it by its hindquarters, but +immediately jumped aside in terror. The wolf crouched, gnashed her +teeth, and again rose and bounded forward, followed at the distance of +a couple of feet by all the borzois, who did not get any closer to +her. + +"She'll get away! No, it's impossible!" thought Nicholas, still +shouting with a hoarse voice. + +"Karay, ulyulyu!..." he shouted, looking round for the old borzoi +who was now his only hope. Karay, with all the strength age had left +him, stretched himself to the utmost and, watching the wolf, +galloped heavily aside to intercept it. But the quickness of the +wolf's lope and the borzoi's slower pace made it plain that Karay +had miscalculated. Nicholas could already see not far in front of +him the wood where the wolf would certainly escape should she reach +it. But, coming toward him, he saw hounds and a huntsman galloping +almost straight at the wolf. There was still hope. A long, yellowish + +young borzoi, one Nicholas did not know, from another leash, rushed +impetuously at the wolf from in front and almost knocked her over. But +the wolf jumped up more quickly than anyone could have expected and, +gnashing her teeth, flew at the yellowish borzoi, which, with a +piercing yelp, fell with its head on the ground, bleeding from a +gash in its side. + +"Karay? Old fellow!..." wailed Nicholas. + +Thanks to the delay caused by this crossing of the wolf's path, +the old dog with its felted hair hanging from its thigh was within +five paces of it. As if aware of her danger, the wolf turned her +eyes on Karay, tucked her tail yet further between her legs, and +increased her speed. But here Nicholas only saw that something +happened to Karay--the borzoi was suddenly on the wolf, and they +rolled together down into a gully just in front of them. + +That instant, when Nicholas saw the wolf struggling in the gully +with the dogs, while from under them could be seen her gray hair and +outstretched hind leg and her frightened choking head, with her ears +laid back (Karay was pinning her by the throat), was the happiest +moment of his life. With his hand on his saddlebow, he was ready to +dismount and stab the wolf, when she suddenly thrust her head up +from among that mass of dogs, and then her forepaws were on the edge +of the gully. She clicked her teeth (Karay no longer had her by the +throat), leaped with a movement of her hind legs out of the gully, and +having disengaged herself from the dogs, with tail tucked in again, +went forward. Karay, his hair bristling, and probably bruised or +wounded, climbed with difficulty out of the gully. + +"Oh my God! Why?" Nicholas cried in despair. + +"Uncle's" huntsman was galloping from the other side across the +wolf's path and his borzois once more stopped the animal's advance. +She was again hemmed in. + +Nicholas and his attendant, with "Uncle" and his huntsman, were +all riding round the wolf, crying "ulyulyu!" shouting and preparing to +dismount each moment that the wolf crouched back, and starting forward +again every time she shook herself and moved toward the wood where she +would be safe. + +Already, at the beginning of this chase, Daniel, hearing the +ulyulyuing, had rushed out from the wood. He saw Karay seize the wolf, +and checked his horse, supposing the affair to be over. But when he +saw that the horsemen did not dismount and that the wolf shook herself +and ran for safety, Daniel set his chestnut galloping, not at the wolf +but straight toward the wood, just as Karay had run to cut the +animal off. As a result of this, he galloped up to the wolf just +when she had been stopped a second time by "Uncle's" borzois. + +Daniel galloped up silently, holding a naked dagger in his left hand +and thrashing the laboring sides of his chestnut horse with his whip +as if it were a flail. + +Nicholas neither saw nor heard Daniel until the chestnut, +breathing heavily, panted past him, and he heard the fall of a body +and saw Daniel lying on the wolf's back among the dogs, trying to +seize her by the ears. It was evident to the dogs, the hunters, and to +the wolf herself that all was now over. The terrified wolf pressed +back her ears and tried to rise, but the borzois stuck to her. +Daniel rose a little, took a step, and with his whole weight, as if +lying down to rest, fell on the wolf, seizing her by the ears. +Nicholas was about to stab her, but Daniel whispered, "Don't! We'll +gag her!" and, changing his position, set his foot on the wolf's neck. +A stick was thrust between her jaws and she was fastened with a leash, +as if bridled, her legs were bound together, and Daniel rolled her +over once or twice from side to side. + +With happy, exhausted faces, they laid the old wolf, alive, on a +shying and snorting horse and, accompanied by the dogs yelping at her, +took her to the place where they were all to meet. The hounds had +killed two of the cubs and the borzois three. The huntsmen assembled +with their booty and their stories, and all came to look at the +wolf, which, with her broad-browed head hanging down and the bitten +stick between her jaws, gazed with great glassy eyes at this crowd +of dogs and men surrounding her. When she was touched, she jerked +her bound legs and looked wildly yet simply at everybody. Old Count +Rostov also rode up and touched the wolf. + +"Oh, what a formidable one!" said he. "A formidable one, eh?" he +asked Daniel, who was standing near. + +"Yes, your excellency," answered Daniel, quickly doffing his cap. + +The count remembered the wolf he had let slip and his encounter with +Daniel. + +"Ah, but you are a crusty fellow, friend!" said the count. + +For sole reply Daniel gave him a shy, childlike, meek, and amiable +smile. + + + + + +CHAPTER VI + + +The old count went home, and Natasha and Petya promised to return +very soon, but as it was still early the hunt went farther. At +midday they put the hounds into a ravine thickly overgrown with +young trees. Nicholas standing in a fallow field could see all his +whips. + +Facing him lay a field of winter rye, there his own huntsman stood +alone in a hollow behind a hazel bush. The hounds had scarcely been +loosed before Nicholas heard one he knew, Voltorn, giving tongue at +intervals; other hounds joined in, now pausing and now again giving +tongue. A moment later he heard a cry from the wooded ravine that a +fox had been found, and the whole pack, joining together, rushed along +the ravine toward the ryefield and away from Nicholas. + +He saw the whips in their red caps galloping along the edge of the +ravine, he even saw the hounds, and was expecting a fox to show itself +at any moment on the ryefield opposite. + +The huntsman standing in the hollow moved and loosed his borzois, +and Nicholas saw a queer, short-legged red fox with a fine brush going +hard across the field. The borzois bore down on it.... Now they drew +close to the fox which began to dodge between the field in sharper and +sharper curves, trailing its brush, when suddenly a strange white +borzoi dashed in followed by a black one, and everything was in +confusion; the borzois formed a star-shaped figure, scarcely swaying +their bodies and with tails turned away from the center of the +group. Two huntsmen galloped up to the dogs; one in a red cap, the +other, a stranger, in a green coat. + +"What's this?" thought Nicholas. "Where's that huntsman from? He +is not 'Uncle's' man." + +The huntsmen got the fox, but stayed there a long time without +strapping it to the saddle. Their horses, bridled and with high +saddles, stood near them and there too the dogs were lying. The +huntsmen waved their arms and did something to the fox. Then from that +spot came the sound of a horn, with the signal agreed on in case of +a fight. + +"That's Ilagin's huntsman having a row with our Ivan," said +Nicholas' groom. + +Nicholas sent the man to call Natasha and Petya to him, and rode +at a footpace to the place where the whips were getting the hounds +together. Several of the field galloped to the spot where the fight +was going on. + +Nicholas dismounted, and with Natasha and Petya, who had ridden +up, stopped near the hounds, waiting to see how the matter would +end. Out of the bushes came the huntsman who had been fighting and +rode toward his young master, with the fox tied to his crupper. +While still at a distance he took off his cap and tried to speak +respectfully, but he was pale and breathless and his face was angry. +One of his eyes was black, but he probably was not even aware of it. + +"What has happened?" asked Nicholas. + +"A likely thing, killing a fox our dogs had hunted! And it was my +gray bitch that caught it! Go to law, indeed!... He snatches at the +fox! I gave him one with the fox. Here it is on my saddle! Do you want +a taste of this?..." said the huntsman, pointing to his dagger and +probably imagining himself still speaking to his foe. + +Nicholas, not stopping to talk to the man, asked his sister and +Petya to wait for him and rode to the spot where the enemy's, +Ilagin's, hunting party was. + +The victorious huntsman rode off to join the field, and there, +surrounded by inquiring sympathizers, recounted his exploits. + +The facts were that Ilagin, with whom the Rostovs had a quarrel +and were at law, hunted over places that belonged by custom to the +Rostovs, and had now, as if purposely, sent his men to the very +woods the Rostovs were hunting and let his man snatch a fox their dogs +had chased. + +Nicholas, though he had never seen Ilagin, with his usual absence of +moderation in judgment, hated him cordially from reports of his +arbitrariness and violence, and regarded him as his bitterest foe. +He rode in angry agitation toward him, firmly grasping his whip and +fully prepared to take the most resolute and desperate steps to punish +his enemy. + +Hardly had he passed an angle of the wood before a stout gentleman +in a beaver cap came riding toward him on a handsome raven-black +horse, accompanied by two hunt servants. + +Instead of an enemy, Nicholas found in Ilagin a stately and +courteous gentleman who was particularly anxious to make the young +count's acquaintance. Having ridden up to Nicholas, Ilagin raised +his beaver cap and said he much regretted what had occurred and +would have the man punished who had allowed himself to seize a fox +hunted by someone else's borzois. He hoped to become better acquainted +with the count and invited him to draw his covert. + +Natasha, afraid that her brother would do something dreadful, had +followed him in some excitement. Seeing the enemies exchanging +friendly greetings, she rode up to them. Ilagin lifted his beaver +cap still higher to Natasha and said, with a pleasant smile, that +the young countess resembled Diana in her passion for the chase as +well as in her beauty, of which he had heard much. + +To expiate his huntsman's offense, Ilagin pressed the Rostovs to +come to an upland of his about a mile away which he usually kept for +himself and which, he said, swarmed with hares. Nicholas agreed, and +the hunt, now doubled, moved on. + +The way to Iligin's upland was across the fields. The hunt +servants fell into line. The masters rode together. "Uncle," Rostov, +and Ilagin kept stealthily glancing at one another's dogs, trying +not to be observed by their companions and searching uneasily for +rivals to their own borzois. + +Rostov was particularly struck by the beauty of a small, +pure-bred, red-spotted bitch on Ilagin's leash, slender but with +muscles like steel, a delicate muzzle, and prominent black eyes. He +had heard of the swiftness of Ilagin's borzois, and in that +beautiful bitch saw a rival to his own Milka. + +In the middle of a sober conversation begun by Ilagin about the +year's harvest, Nicholas pointed to the red-spotted bitch. + +"A fine little bitch, that!" said he in a careless tone. "Is she +swift?" + +"That one? Yes, she's a good dog, gets what she's after," answered +Ilagin indifferently, of the red-spotted bitch Erza, for which, a year +before, he had given a neighbor three families of house serfs. "So +in your parts, too, the harvest is nothing to boast of, Count?" he +went on, continuing the conversation they had begun. And considering +it polite to return the young count's compliment, Ilagin looked at his +borzois and picked out Milka who attracted his attention by her +breadth. "That black-spotted one of yours is fine--well shaped!" +said he. + +"Yes, she's fast enough," replied Nicholas, and thought: "If only +a full-grown hare would cross the field now I'd show you what sort +of borzoi she is," and turning to his groom, he said he would give a +ruble to anyone who found a hare. + +"I don't understand," continued Ilagin, "how some sportsmen can be +so jealous about game and dogs. For myself, I can tell you, Count, I +enjoy riding in company such as this... what could be better?" (he +again raised his cap to Natasha) "but as for counting skins and what +one takes, I don't care about that." + +"Of course not!" + +"Or being upset because someone else's borzoi and not mine catches +something. All I care about is to enjoy seeing the chase, is it not +so, Count? For I consider that..." + +"A-tu!" came the long-drawn cry of one of the borzoi whippers-in, +who had halted. He stood on a knoll in the stubble, holding his whip +aloft, and again repeated his long-drawn cry, "A-tu!" (This call and +the uplifted whip meant that he saw a sitting hare.) + +"Ah, he has found one, I think," said Ilagin carelessly. "Yes, we +must ride up.... Shall we both course it?" answered Nicholas, seeing +in Erza and "Uncle's" red Rugay two rivals he had never yet had a +chance of pitting against his own borzois. "And suppose they outdo +my Milka at once!" he thought as he rode with "Uncle" and Ilagin +toward the hare. + +"A full-grown one?" asked Ilagin as he approached the whip who had +sighted the hare--and not without agitation he looked round and +whistled to Erza. + +"And you, Michael Nikanorovich?" he said, addressing "Uncle." + +The latter was riding with a sullen expression on his face. + +"How can I join in? Why, you've given a village for each of your +borzois! That's it, come on! Yours are worth thousands. Try yours +against one another, you two, and I'll look on!" + +"Rugay, hey, hey!" he shouted. "Rugayushka!" he added, involuntarily +by this diminutive expressing his affection and the hopes he placed on +this red borzoi. Natasha saw and felt the agitation the two elderly +men and her brother were trying to conceal, and was herself excited by +it. + +The huntsman stood halfway up the knoll holding up his whip and +the gentlefolk rode up to him at a footpace; the hounds that were +far off on the horizon turned away from the hare, and the whips, but +not the gentlefolk, also moved away. All were moving slowly and +sedately. + +"How is it pointing?" asked Nicholas, riding a hundred paces +toward the whip who had sighted the hare. + +But before the whip could reply, the hare, scenting the frost coming +next morning, was unable to rest and leaped up. The pack on leash +rushed downhill in full cry after the hare, and from all sides the +borzois that were not on leash darted after the hounds and the hare. +All the hunt, who had been moving slowly, shouted, "Stop!" calling +in the hounds, while the borzoi whips, with a cry of "A-tu!" galloped +across the field setting the borzois on the hare. The tranquil Ilagin, +Nicholas, Natasha, and "Uncle" flew, reckless of where and how they +went, seeing only the borzois and the hare and fearing only to lose +sight even for an instant of the chase. The hare they had started +was a strong and swift one. When he jumped up he did not run at +once, but pricked his ears listening to the shouting and trampling +that resounded from all sides at once. He took a dozen bounds, not +very quickly, letting the borzois gain on him, and, finally having +chosen his direction and realized his danger, laid back his ears and +rushed off headlong. He had been lying in the stubble, but in front of +him was the autumn sowing where the ground was soft. The two borzois +of the huntsman who had sighted him, having been the nearest, were the +first to see and pursue him, but they had not gone far before Ilagin's +red-spotted Erza passed them, got within a length, flew at the hare +with terrible swiftness aiming at his scut, and, thinking she had +seized him, rolled over like a ball. The hare arched his back and +bounded off yet more swiftly. From behind Erza rushed the +broad-haunched, black-spotted Milka and began rapidly gaining on the +hare. + +"Milashka, dear!" rose Nicholas' triumphant cry. It looked as if +Milka would immediately pounce on the hare, but she overtook him and +flew past. The hare had squatted. Again the beautiful Erza reached +him, but when close to the hare's scut paused as if measuring the +distance, so as not to make a mistake this time but seize his hind +leg. + +"Erza, darling!" Ilagin wailed in a voice unlike his own. Erza did +not hearken to his appeal. At the very moment when she would have +seized her prey, the hare moved and darted along the balk between +the winter rye and the stubble. Again Erza and Milka were abreast, +running like a pair of carriage horses, and began to overtake the +hare, but it was easier for the hare to run on the balk and the +borzois did not overtake him so quickly. + +"Rugay, Rugayushka! That's it, come on!" came a third voice just +then, and "Uncle's" red borzoi, straining and curving its back, caught +up with the two foremost borzois, pushed ahead of them regardless of +the terrible strain, put on speed close to the hare, knocked it off +the balk onto the ryefield, again put on speed still more viciously, +sinking to his knees in the muddy field, and all one could see was +how, muddying his back, he rolled over with the hare. A ring of +borzois surrounded him. A moment later everyone had drawn up round the +crowd of dogs. Only the delighted "Uncle" dismounted, and cut off a +pad, shaking the hare for the blood to drip off, and anxiously +glancing round with restless eyes while his arms and legs twitched. He +spoke without himself knowing whom to or what about. "That's it, +come on! That's a dog!... There, it has beaten them all, the +thousand-ruble as well as the one-ruble borzois. That's it, come +on!" said he, panting and looking wrathfully around as if he were +abusing someone, as if they were all his enemies and had insulted him, +and only now had he at last succeeded in justifying himself. "There +are your thousand-ruble ones.... That's it, come on!..." + +"Rugay, here's a pad for you!" he said, throwing down the hare's +muddy pad. "You've deserved it, that's it, come on!" + +"She'd tired herself out, she'd run it down three times by herself," +said Nicholas, also not listening to anyone and regardless of +whether he were heard or not. + +"But what is there in running across it like that?" said Ilagin's +groom. + +"Once she had missed it and turned it away, any mongrel could take +it," Ilagin was saying at the same time, breathless from his gallop +and his excitement. At the same moment Natasha, without drawing +breath, screamed joyously, ecstatically, and so piercingly that it set +everyone's ear tingling. By that shriek she expressed what the +others expressed by all talking at once, and it was so strange that +she must herself have been ashamed of so wild a cry and everyone +else would have been amazed at it at any other time. "Uncle" himself +twisted up the hare, threw it neatly and smartly across his horse's +back as if by that gesture he meant to rebuke everybody, and, with +an air of not wishing to speak to anyone, mounted his bay and rode +off. The others all followed, dispirited and shamefaced, and only much +later were they able to regain their former affectation of +indifference. For a long time they continued to look at red Rugay who, +his arched back spattered with mud and clanking the ring of his leash, +walked along just behind "Uncle's" horse with the serene air of a +conqueror. + +"Well, I am like any other dog as long as it's not a question of +coursing. But when it is, then look out!" his appearance seemed to +Nicholas to be saying. + +When, much later, "Uncle" rode up to Nicholas and began talking to +him, he felt flattered that, after what had happened, "Uncle" +deigned to speak to him. + + + + + +CHAPTER VII + + +Toward evening Ilagin took leave of Nicholas, who found that they +were so far from home that he accepted "Uncle's" offer that the +hunting party should spend the night in his little village of +Mikhaylovna. + +"And if you put up at my house that will be better still. That's it, +come on!" said "Uncle." "You see it's damp weather, and you could +rest, and the little countess could be driven home in a trap." + +"Uncle's" offer was accepted. A huntsman was sent to Otradnoe for +a trap, while Nicholas rode with Natasha and Petya to "Uncle's" house. + +Some five male domestic serfs, big and little, rushed out to the +front porch to meet their master. A score of women serfs, old and +young, as well as children, popped out from the back entrance to +have a look at the hunters who were arriving. The presence of Natasha- +a woman, a lady, and on horseback--raised the curiosity of the serfs +to such a degree that many of them came up to her, stared her in the +face, and unabashed by her presence made remarks about her as though +she were some prodigy on show and not a human being able to hear or +understand what was said about her. + +"Arinka! Look, she sits sideways! There she sits and her skirt +dangles.... See, she's got a little hunting horn!" + +"Goodness gracious! See her knife?..." + +"Isn't she a Tartar!" + +"How is it you didn't go head over heels?" asked the boldest of all, +addressing Natasha directly. + +"Uncle" dismounted at the porch of his little wooden house which +stood in the midst of an overgrown garden and, after a glance at his +retainers, shouted authoritatively that the superfluous ones should +take themselves off and that all necessary preparations should be made +to receive the guests and the visitors. + +The serfs all dispersed. "Uncle" lifted Natasha off her horse and +taking her hand led her up the rickety wooden steps of the porch. +The house, with its bare, unplastered log walls, was not overclean--it +did not seem that those living in it aimed at keeping it spotless--but +neither was it noticeably neglected. In the entry there was a smell of +fresh apples, and wolf and fox skins hung about. + +"Uncle" led the visitors through the anteroom into a small hall with +a folding table and red chairs, then into the drawing room with a +round birchwood table and a sofa, and finally into his private room +where there was a tattered sofa, a worn carpet, and portraits of +Suvorov, of the host's father and mother, and of himself in military +uniform. The study smelt strongly of tobacco and dogs. "Uncle" asked +his visitors to sit down and make themselves at home, and then went +out of the room. Rugay, his back still muddy, came into the room and +lay down on the sofa, cleaning himself with his tongue and teeth. +Leading from the study was a passage in which a partition with +ragged curtains could be seen. From behind this came women's +laughter and whispers. Natasha, Nicholas, and Petya took off their +wraps and sat down on the sofa. Petya, leaning on his elbow, fell +asleep at once. Natasha and Nicholas were silent. Their faces +glowed, they were hungry and very cheerful. They looked at one another +(now that the hunt was over and they were in the house, Nicholas no +longer considered it necessary to show his manly superiority over +his sister), Natasha gave him a wink, and neither refrained long +from bursting into a peal of ringing laughter even before they had a +pretext ready to account for it. + +After a while "Uncle" came in, in a Cossack coat, blue trousers, and +small top boots. And Natasha felt that this costume, the very one +she had regarded with surprise and amusement at Otradnoe, was just the +right thing and not at all worse than a swallow-tail or frock coat. +"Uncle" too was in high spirits and far from being offended by the +brother's and sister's laughter (it could never enter his head that +they might be laughing at his way of life) he himself joined in the +merriment. + +"That's right, young countess, that's it, come on! I never saw +anyone like her!" said he, offering Nicholas a pipe with a long stem +and, with a practiced motion of three fingers, taking down another +that had been cut short. "She's ridden all day like a man, and is as +fresh as ever!" + +Soon after "Uncle's" reappearance the door was opened, evidently +from the sound by a barefooted girl, and a stout, rosy, good-looking +woman of about forty, with a double chin and full red lips, entered +carrying a large loaded tray. With hospitable dignity and cordiality +in her glance and in every motion, she looked at the visitors and, +with a pleasant smile, bowed respectfully. In spite of her exceptional +stoutness, which caused her to protrude her chest and stomach and +throw back her head, this woman (who was "Uncle's" housekeeper) trod +very lightly. She went to the table, set down the tray, and with her +plump white hands deftly took from it the bottles and various hors +d'oeuvres and dishes and arranged them on the table. When she had +finished, she stepped aside and stopped at the door with a smile on +her face. "Here I am. I am she! Now do you understand 'Uncle'?" her +expression said to Rostov. How could one help understanding? Not +only Nicholas, but even Natasha understood the meaning of his puckered +brow and the happy complacent smile that slightly puckered his lips +when Anisya Fedorovna entered. On the tray was a bottle of herb +wine, different kinds of vodka, pickled mushrooms, rye cakes made with +buttermilk, honey in the comb, still mead and sparkling mead, +apples, nuts (raw and roasted), and nut-and-honey sweets. Afterwards +she brought a freshly roasted chicken, ham, preserves made with honey, +and preserves made with sugar. + +All this was the fruit of Anisya Fedorovna's housekeeping, +gathered and prepared by her. The smell and taste of it all had a +smack of Anisya Fedorovna herself: a savor of juiciness, +cleanliness, whiteness, and pleasant smiles. + +"Take this, little Lady-Countess!" she kept saying, as she offered +Natasha first one thing and then another. + +Natasha ate of everything and thought she had never seen or eaten +such buttermilk cakes, such aromatic jam, such honey-and-nut sweets, +or such a chicken anywhere. Anisya Fedorovna left the room. + +After supper, over their cherry brandy, Rostov and "Uncle" talked of +past and future hunts, of Rugay and Ilagin's dogs, while Natasha sat +upright on the sofa and listened with sparkling eyes. She tried +several times to wake Petya that he might eat something, but he only +muttered incoherent words without waking up. Natasha felt so +lighthearted and happy in these novel surroundings that she only +feared the trap would come for her too soon. After a casual pause, +such as often occurs when receiving friends for the first time in +one's own house, "Uncle," answering a thought that was in his +visitors' mind, said: + +"This, you see, is how I am finishing my days... Death will come. +That's it, come on! Nothing will remain. Then why harm anyone?" + +"Uncle's" face was very significant and even handsome as he said +this. Involuntarily Rostov recalled all the good he had heard about +him from his father and the neighbors. Throughout the whole province +"Uncle" had the reputation of being the most honorable and +disinterested of cranks. They called him in to decide family disputes, +chose him as executor, confided secrets to him, elected him to be a +justice and to other posts; but he always persistently refused +public appointments, passing the autumn and spring in the fields on +his bay gelding, sitting at home in winter, and lying in his overgrown +garden in summer. + +"Why don't you enter the service, Uncle?" + +"I did once, but gave it up. I am not fit for it. That's it, come +on! I can't make head or tail of it. That's for you--I haven't +brains enough. Now, hunting is another matter--that's it, come on! +Open the door, there!" he shouted. "Why have you shut it?" + +The door at the end of the passage led to the huntsmen's room, as +they called the room for the hunt servants. + +There was a rapid patter of bare feet, and an unseen hand opened the +door into the huntsmen's room, from which came the clear sounds of a +balalayka on which someone, who was evidently a master of the art, was +playing. Natasha had been listening to those strains for some time and +now went out into the passage to hear better. + +"That's Mitka, my coachman.... I have got him a good balalayka. +I'm fond of it," said "Uncle." + +It was the custom for Mitka to play the balalayka in the +huntsmen's room when "Uncle" returned from the chase. "Uncle" was fond +of such music. + +"How good! Really very good!" said Nicholas with some +unintentional superciliousness, as if ashamed to confess that the +sounds pleased him very much. + +"Very good?" said Natasha reproachfully, noticing her brother's +tone. "Not 'very good' it's simply delicious!" + +Just as "Uncle's" pickled mushrooms, honey, and cherry brandy had +seemed to her the best in the world, so also that song, at that +moment, seemed to her the acme of musical delight. + +"More, please, more!" cried Natasha at the door as soon as the +balalayka ceased. Mitka tuned up afresh, and recommenced thrumming the +balalayka to the air of My Lady, with trills and variations. "Uncle" +sat listening, slightly smiling, with his head on one side. The air +was repeated a hundred times. The balalayka was retuned several +times and the same notes were thrummed again, but the listeners did +not grow weary of it and wished to hear it again and again. Anisya +Fedorovna came in and leaned her portly person against the doorpost. + +"You like listening?" she said to Natasha, with a smile extremely +like "Uncle's." "That's a good player of ours," she added. + +"He doesn't play that part right!" said "Uncle" suddenly, with an +energetic gesture. "Here he ought to burst out--that's it, come on!- +ought to burst out." + +"Do you play then?" asked Natasha. + +"Uncle" did not answer, but smiled. + +"Anisya, go and see if the strings of my guitar are all right. I +haven't touched it for a long time. That's it--come on! I've given +it up." + +Anisya Fedorovna, with her light step, willingly went to fulfill her +errand and brought back the guitar. + +Without looking at anyone, "Uncle" blew the dust off it and, tapping +the case with his bony fingers, tuned the guitar and settled himself +in his armchair. He took the guitar a little above the fingerboard, +arching his left elbow with a somewhat theatrical gesture, and, with a +wink at Anisya Fedorovna, struck a single chord, pure and sonorous, +and then quietly, smoothly, and confidently began playing in very slow +time, not My Lady, but the well-known song: Came a maiden down the +street. The tune, played with precision and in exact time, began to +thrill in the hearts of Nicholas and Natasha, arousing in them the +same kind of sober mirth as radiated from Anisya Fedorovna's whole +being. Anisya Fedorovna flushed, and drawing her kerchief over her +face went laughing out of the room. "Uncle" continued to play +correctly, carefully, with energetic firmness, looking with a +changed and inspired expression at the spot where Anisya Fedorovna had +just stood. Something seemed to be laughing a little on one side of +his face under his gray mustaches, especially as the song grew brisker +and the time quicker and when, here and there, as he ran his fingers +over the strings, something seemed to snap. + +"Lovely, lovely! Go on, Uncle, go on!" shouted Natasha as soon as he +had finished. She jumped up and hugged and kissed him. "Nicholas, +Nicholas!" she said, turning to her brother, as if asking him: "What +is it moves me so?" + +Nicholas too was greatly pleased by "Uncle's" playing, and "Uncle" +played the piece over again. Anisya Fedorovna's smiling face +reappeared in the doorway and behind hers other faces... + + Fetching water clear and sweet, + Stop, dear maiden, I entreat- + +played "Uncle" once more, running his fingers skillfully over the +strings, and then he stopped short and jerked his shoulders. + +"Go on, Uncle dear," Natasha wailed in an imploring tone as if her +life depended on it. + +"Uncle" rose, and it was as if there were two men in him: one of +them smiled seriously at the merry fellow, while the merry fellow +struck a naive and precise attitude preparatory to a folk dance. + +"Now then, niece!" he exclaimed, waving to Natasha the hand that had +just struck a chord. + +Natasha threw off the shawl from her shoulders, ran forward to +face "Uncle," and setting her arms akimbo also made a motion with +her shoulders and struck an attitude. + +Where, how, and when had this young countess, educated by an emigree +French governess, imbibed from the Russian air she breathed that +spirit and obtained that manner which the pas de chale* would, one +would have supposed, long ago have effaced? But the spirit and the +movements were those inimitable and unteachable Russian ones that +"Uncle" had expected of her. As soon as she had struck her pose, and +smiled triumphantly, proudly, and with sly merriment, the fear that +had at first seized Nicholas and the others that she might not do +the right thing was at an end, and they were already admiring her. + + +*The French shawl dance. + + +She did the right thing with such precision, such complete +precision, that Anisya Fedorovna, who had at once handed her the +handkerchief she needed for the dance, had tears in her eyes, though +she laughed as she watched this slim, graceful countess, reared in +silks and velvets and so different from herself, who yet was able to +understand all that was in Anisya and in Anisya's father and mother +and aunt, and in every Russian man and woman. + +"Well, little countess; that's it--come on!" cried "Uncle," with a +joyous laugh, having finished the dance. "Well done, niece! Now a fine +young fellow must be found as husband for you. That's it--come on!" + +"He's chosen already," said Nicholas smiling. + +"Oh?" said "Uncle" in surprise, looking inquiringly at Natasha, +who nodded her head with a happy smile. + +"And such a one!" she said. But as soon as she had said it a new +train of thoughts and feelings arose in her. "What did Nicholas' smile +mean when he said 'chosen already'? Is he glad of it or not? It is +as if he thought my Bolkonski would not approve of or understand our +gaiety. But he would understand it all. Where is he now?" she thought, +and her face suddenly became serious. But this lasted only a second. +"Don't dare to think about it," she said to herself, and sat down +again smilingly beside "Uncle," begging him to play something more. + +"Uncle" played another song and a valse; then after a pause he +cleared his throat and sang his favorite hunting song: + + As 'twas growing dark last night + Fell the snow so soft and light... + + +"Uncle" sang as peasants sing, with full and naive conviction that +the whole meaning of a song lies in the words and that the tune +comes of itself, and that apart from the words there is no tune, which +exists only to give measure to the words. As a result of this the +unconsidered tune, like the song of a bird, was extraordinarily +good. Natasha was in ecstasies over "Uncle's" singing. She resolved to +give up learning the harp and to play only the guitar. She asked +"Uncle" for his guitar and at once found the chords of the song. + +After nine o'clock two traps and three mounted men, who had been +sent to look for them, arrived to fetch Natasha and Petya. The count +and countess did not know where they were and were very anxious, +said one of the men. + +Petya was carried out like a log and laid in the larger of the two +traps. Natasha and Nicholas got into the other. "Uncle" wrapped +Natasha up warmly and took leave of her with quite a new tenderness. +He accompanied them on foot as far as the bridge that could not be +crossed, so that they had to go round by the ford, and he sent +huntsmen to ride in front with lanterns. + +"Good-by, dear niece," his voice called out of the darkness--not the +voice Natasha had known previously, but the one that had sung As 'twas +growing dark last night. + +In the village through which they passed there were red lights and a +cheerful smell of smoke. + +"What a darling Uncle is!" said Natasha, when they had come out onto +the highroad. + +"Yes," returned Nicholas. "You're not cold?" + +"No. I'm quite, quite all right. I feel so comfortable!" answered +Natasha, almost perplexed by her feelings. They remained silent a long +while. The night was dark and damp. They could not see the horses, but +only heard them splashing through the unseen mud. + +What was passing in that receptive childlike soul that so eagerly +caught and assimilated all the diverse impressions of life? How did +they all find place in her? But she was very happy. As they were +nearing home she suddenly struck up the air of As 'twas growing dark +last night--the tune of which she had all the way been trying to get +and had at last caught. + +"Got it?" said Nicholas. + +"What were you thinking about just now, Nicholas?" inquired Natasha. + +They were fond of asking one another that question. + +"I?" said Nicholas, trying to remember. "Well, you see, first I +thought that Rugay, the red hound, was like Uncle, and that if he were +a man he would always keep Uncle near him, if not for his riding, then +for his manner. What a good fellow Uncle is! Don't you think so?... +Well, and you?" + +"I? Wait a bit, wait.... Yes, first I thought that we are driving +along and imagining that we are going home, but that heaven knows +where we are really going in the darkness, and that we shall arrive +and suddenly find that we are not in Otradnoe, but in Fairyland. And +then I thought... No, nothing else." + +"I know, I expect you thought of him," said Nicholas, smiling as +Natasha knew by the sound of his voice. + +"No," said Natasha, though she had in reality been thinking about +Prince Andrew at the same time as of the rest, and of how he would +have liked "Uncle." "And then I was saying to myself all the way, 'How +well Anisya carried herself, how well!'" And Nicholas heard her +spontaneous, happy, ringing laughter. "And do you know," she +suddenly said, "I know that I shall never again be as happy and +tranquil as I am now." + +"Rubbish, nonsense, humbug!" exclaimed Nicholas, and he thought: +"How charming this Natasha of mine is! I have no other friend like her +and never shall have. Why should she marry? We might always drive +about together!" + +"What a darling this Nicholas of mine is!" thought Natasha. + +"Ah, there are still lights in the drawingroom!" she said, +pointing to the windows of the house that gleamed invitingly in the +moist velvety darkness of the night. + + + + + +CHAPTER VIII + + +Count Ilya Rostov had resigned the position of Marshal of the +Nobility because it involved him in too much expense, but still his +affairs did not improve. Natasha and Nicholas often noticed their +parents conferring together anxiously and privately and heard +suggestions of selling the fine ancestral Rostov house and estate near +Moscow. It was not necessary to entertain so freely as when the +count had been Marshal, and life at Otradnoe was quieter than in +former years, but still the enormous house and its lodges were full of +people and more than twenty sat down to table every day. These were +all their own people who had settled down in the house almost as +members of the family, or persons who were, it seemed, obliged to live +in the count's house. Such were Dimmler the musician and his wife, +Vogel the dancing master and his family, Belova, an old maiden lady, +an inmate of the house, and many others such as Petya's tutors, the +girls' former governess, and other people who simply found it +preferable and more advantageous to live in the count's house than +at home. They had not as many visitors as before, but the old habits +of life without which the count and countess could not conceive of +existence remained unchanged. There was still the hunting +establishment which Nicholas had even enlarged, the same fifty +horses and fifteen grooms in the stables, the same expensive +presents and dinner parties to the whole district on name days; +there were still the count's games of whist and boston, at which- +spreading out his cards so that everybody could see them--he let +himself be plundered of hundreds of rubles every day by his neighbors, +who looked upon an opportunity to play a rubber with Count Rostov as a +most profitable source of income. + +The count moved in his affairs as in a huge net, trying not to +believe that he was entangled but becoming more and more so at every +step, and feeling too feeble to break the meshes or to set to work +carefully and patiently to disentangle them. The countess, with her +loving heart, felt that her children were being ruined, that it was +not the count's fault for he could not help being what he was--that +(though he tried to hide it) he himself suffered from the +consciousness of his own and his children's ruin, and she tried to +find means of remedying the position. From her feminine point of +view she could see only one solution, namely, for Nicholas to marry +a rich heiress. She felt this to be their last hope and that if +Nicholas refused the match she had found for him, she would have to +abandon the hope of ever getting matters right. This match was with +Julie Karagina, the daughter of excellent and virtuous parents, a girl +the Rostovs had known from childhood, and who had now become a wealthy +heiress through the death of the last of her brothers. + +The countess had written direct to Julie's mother in Moscow +suggesting a marriage between their children and had received a +favorable answer from her. Karagina had replied that for her part +she was agreeable, and everything depend on her daughter's +inclination. She invited Nicholas to come to Moscow. + +Several times the countess, with tears in her eyes, told her son +that now both her daughters were settled, her only wish was to see him +married. She said she could lie down in her grave peacefully if that +were accomplished. Then she told him that she knew of a splendid +girl and tried to discover what he thought about marriage. + +At other times she praised Julie to him and advised him to go to +Moscow during the holidays to amuse himself. Nicholas guessed what his +mother's remarks were leading to and during one of these conversations +induced her to speak quite frankly. She told him that her only hope of +getting their affairs disentangled now lay in his marrying Julie +Karagina. + +"But, Mamma, suppose I loved a girl who has no fortune, would you +expect me to sacrifice my feelings and my honor for the sake of +money?" he asked his mother, not realizing the cruelty of his question +and only wishing to show his noble-mindedness. + +"No, you have not understood me," said his mother, not knowing how +to justify herself. "You have not understood me, Nikolenka. It is your +happiness I wish for," she added, feeling that she was telling an +untruth and was becoming entangled. She began to cry. + +"Mamma, don't cry! Only tell me that you wish it, and you know I +will give my life, anything, to put you at ease," said Nicholas. "I +would sacrifice anything for you--even my feelings." + +But the countess did not want the question put like that: she did +not want a sacrifice from her son, she herself wished to make a +sacrifice for him. + +"No, you have not understood me, don't let us talk about it," she +replied, wiping away her tears. + +"Maybe I do love a poor girl," said Nicholas to himself. "Am I to +sacrifice my feelings and my honor for money? I wonder how Mamma could +speak so to me. Because Sonya is poor I must not love her," he +thought, "must not respond to her faithful, devoted love? Yet I should +certainly be happier with her than with some doll-like Julie. I can +always sacrifice my feelings for my family's welfare," he said to +himself, "but I can't coerce my feelings. If I love Sonya, that +feeling is for me stronger and higher than all else." + +Nicholas did not go to Moscow, and the countess did not renew the +conversation with him about marriage. She saw with sorrow, and +sometimes with exasperation, symptoms of a growing attachment +between her son and the portionless Sonya. Though she blamed herself +for it, she could not refrain from grumbling at and worrying Sonya, +often pulling her up without reason, addressing her stiffly as "my +dear," and using the formal "you" instead of the intimate "thou" in +speaking to her. The kindhearted countess was the more vexed with +Sonya because that poor, dark-eyed niece of hers was so meek, so kind, +so devotedly grateful to her benefactors, and so faithfully, +unchangingly, and unselfishly in love with Nicholas, that there were +no grounds for finding fault with her. + +Nicholas was spending the last of his leave at home. A fourth letter +had come from Prince Andrew, from Rome, in which he wrote that he +would have been on his way back to Russia long ago had not his wound +unexpectedly reopened in the warm climate, which obliged him to +defer his return till the beginning of the new year. Natasha was still +as much in love with her betrothed, found the same comfort in that +love, and was still as ready to throw herself into all the pleasures +of life as before; but at the end of the fourth month of their +separation she began to have fits of depression which she could not +master. She felt sorry for herself: sorry that she was being wasted +all this time and of no use to anyone--while she felt herself so +capable of loving and being loved. + +Things were not cheerful in the Rostovs' home. + + + + + +CHAPTER IX + + +Christmas came and except for the ceremonial Mass, the solemn and +wearisome Christmas congratulations from neighbors and servants, and +the new dresses everyone put on, there were no special festivities, +though the calm frost of twenty degrees Reaumur, the dazzling sunshine +by day, and the starlight of the winter nights seemed to call for some +special celebration of the season. + +On the third day of Christmas week, after the midday dinner, all the +inmates of the house dispersed to various rooms. It was the dullest +time of the day. Nicholas, who had been visiting some neighbors that +morning, was asleep on the sitting-room sofa. The old count was +resting in his study. Sonya sat in the drawing room at the round +table, copying a design for embroidery. The countess was playing +patience. Nastasya Ivanovna the buffoon sat with a sad face at the +window with two old ladies. Natasha came into the room, went up to +Sonya, glanced at what she was doing, and then went up to her mother +and stood without speaking. + +"Why are you wandering about like an outcast?" asked her mother. +"What do you want?" + +"Him... I want him... now, this minute! I want him!" said Natasha, +with glittering eyes and no sign of a smile. + +The countess lifted her head and looked attentively at her daughter. + +"Don't look at me, Mamma! Don't look; I shall cry directly." + +"Sit down with me a little," said the countess. + +"Mamma, I want him. Why should I be wasted like this, Mamma?" + +Her voice broke, tears gushed from her eyes, and she turned +quickly to hide them and left the room. + +She passed into the sitting room, stood there thinking awhile, and +then went into the maids' room. There an old maidservant was grumbling +at a young girl who stood panting, having just run in through the cold +from the serfs' quarters. + +"Stop playing--there's a time for everything," said the old woman. + +"Let her alone, Kondratevna," said Natasha. "Go, Mavrushka, go." + +Having released Mavrushka, Natasha crossed the dancing hall and went +to the vestibule. There an old footman and two young ones were playing +cards. They broke off and rose as she entered. + +"What can I do with them?" thought Natasha. + +"Oh, Nikita, please go... where can I send him?... Yes, go to the +yard and fetch a fowl, please, a cock, and you, Misha, bring me some +oats." + +"Just a few oats?" said Misha, cheerfully and readily. + +"Go, go quickly," the old man urged him. + +"And you, Theodore, get me a piece of chalk." + +On her way past the butler's pantry she told them to set a +samovar, though it was not at all the time for tea. + +Foka, the butler, was the most ill-tempered person in the house. +Natasha liked to test her power over him. He distrusted the order +and asked whether the samovar was really wanted. + +"Oh dear, what a young lady!" said Foka, pretending to frown at +Natasha. + +No one in the house sent people about or gave them as much trouble +as Natasha did. She could not see people unconcernedly, but had to +send them on some errand. She seemed to be trying whether any of +them would get angry or sulky with her; but the serfs fulfilled no +one's orders so readily as they did hers. "What can I do, where can +I go?" thought she, as she went slowly along the passage. + +"Nastasya Ivanovna, what sort of children shall I have?" she asked +the buffoon, who was coming toward her in a woman's jacket. + +"Why, fleas, crickets, grasshoppers," answered the buffoon. + +"O Lord, O Lord, it's always the same! Oh, where am I to go? What am +I to do with myself?" And tapping with her heels, she ran quickly +upstairs to see Vogel and his wife who lived on the upper story. + +Two governesses were sitting with the Vogels at a table, on which +were plates of raisins, walnuts, and almonds. The governesses were +discussing whether it was cheaper to live in Moscow or Odessa. Natasha +sat down, listened to their talk with a serious and thoughtful air, +and then got up again. + +"The island of Madagascar," she said, "Ma-da-gas-car," she repeated, +articulating each syllable distinctly, and, not replying to Madame +Schoss who asked her what she was saying, she went out of the room. + +Her brother Petya was upstairs too; with the man in attendance on +him he was preparing fireworks to let off that night. + +"Petya! Petya!" she called to him. "Carry me downstairs." + +Petya ran up and offered her his back. She jumped on it, putting her +arms round his neck, and he pranced along with her. + +"No, don't... the island of Madagascar!" she said, and jumping off +his back she went downstairs. + +Having as it were reviewed her kingdom, tested her power, and made +sure that everyone was submissive, but that all the same it was +dull, Natasha betook herself to the ballroom, picked up her guitar, +sat down in a dark corner behind a bookcase, and began to run her +fingers over the strings in the bass, picking out a passage she +recalled from an opera she had heard in Petersburg with Prince Andrew. +What she drew from the guitar would have had no meaning for other +listeners, but in her imagination a whole series of reminiscences +arose from those sounds. She sat behind the bookcase with her eyes +fixed on a streak of light escaping from the pantry door and +listened to herself and pondered. She was in a mood for brooding on +the past. + +Sonya passed to the pantry with a glass in her hand. Natasha glanced +at her and at the crack in the pantry door, and it seemed to her +that she remembered the light failing through that crack once before +and Sonya passing with a glass in her hand. "Yes it was exactly the +same," thought Natasha. + +"Sonya, what is this?" she cried, twanging a thick string. + +"Oh, you are there!" said Sonya with a start, and came near and +listened. "I don't know. A storm?" she ventured timidly, afraid of +being wrong. + +"There! That's just how she started and just how she came up smiling +timidly when all this happened before," thought Natasha, "and in +just the same way I thought there was something lacking in her." + +"No, it's the chorus from The Water-Carrier, listen!" and Natasha +sang the air of the chorus so that Sonya should catch it. "Where +were you going?" she asked. + +"To change the water in this glass. I am just finishing the design." + +"You always find something to do, but I can't," said Natasha. "And +where's Nicholas?" + +"Asleep, I think." + +"Sonya, go and wake him," said Natasha. "Tell him I want him to come +and sing." + +She sat awhile, wondering what the meaning of it all having happened +before could be, and without solving this problem, or at all +regretting not having done so, she again passed in fancy to the time +when she was with him and he was looking at her with a lover's eyes. + +"Oh, if only he would come quicker! I am so afraid it will never be! +And, worst of all, I am growing old--that's the thing! There won't +then be in me what there is now. But perhaps he'll come today, will +come immediately. Perhaps he has come and is sitting in the drawing +room. Perhaps he came yesterday and I have forgotten it." She rose, +put down the guitar, and went to the drawing room. + +All the domestic circle, tutors, governesses, and guests, were +already at the tea table. The servants stood round the table--but +Prince Andrew was not there and life was going on as before. + +"Ah, here she is!" said the old count, when he saw Natasha enter. +"Well, sit down by me." But Natasha stayed by her mother and glanced +round as if looking for something. + +"Mamma!" she muttered, "give him to me, give him, Mamma, quickly, +quickly!" and she again had difficulty in repressing her sobs. + +She sat down at the table and listened to the conversation between +the elders and Nicholas, who had also come to the table. "My God, my +God! The same faces, the same talk, Papa holding his cup and blowing +in the same way!" thought Natasha, feeling with horror a sense of +repulsion rising up in her for the whole household, because they +were always the same. + +After tea, Nicholas, Sonya, and Natasha went to the sitting room, to +their favorite corner where their most intimate talks always began. + + + + + +CHAPTER X + + +"Does it ever happen to you," said Natasha to her brother, when +they settled down in the sitting room, "does it ever happen to you +to feel as if there were nothing more to come--nothing; that +everything good is past? And to feel not exactly dull, but sad?" + +"I should think so!" he replied. "I have felt like that when +everything was all right and everyone was cheerful. The thought has +come into my mind that I was already tired of it all, and that we must +all die. Once in the regiment I had not gone to some merrymaking where +there was music... and suddenly I felt so depressed..." + +"Oh yes, I know, I know, I know!" Natasha interrupted him. "When I +was quite little that used to be so with me. Do you remember when I +was punished once about some plums? You were all dancing, and I sat +sobbing in the schoolroom? I shall never forget it: I felt sad and +sorry for everyone, for myself, and for everyone. And I was +innocent--that was the chief thing," said Natasha. "Do you remember?" + +"I remember," answered Nicholas. "I remember that I came to you +afterwards and wanted to comfort you, but do you know, I felt +ashamed to. We were terribly absurd. I had a funny doll then and +wanted to give it to you. Do you remember?" + +"And do you remember," Natasha asked with a pensive smile, "how +once, long, long ago, when we were quite little, Uncle called us +into the study--that was in the old house--and it was dark--we went in +and suddenly there stood..." + +"A Negro," chimed in Nicholas with a smile of delight. "Of course +I remember. Even now I don't know whether there really was a Negro, or +if we only dreamed it or were told about him." + +"He was gray, you remember, and had white teeth, and stood and +looked at us..." + +"Sonya, do you remember?" asked Nicholas. + +"Yes, yes, I do remember something too," Sonya answered timidly. + +"You know I have asked Papa and Mamma about that Negro," said +Natasha, "and they say there was no Negro at all. But you see, you +remember!" + +"Of course I do, I remember his teeth as if I had just seen them." + +"How strange it is! It's as if it were a dream! I like that." + +"And do you remember how we rolled hard-boiled eggs in the ballroom, +and suddenly two old women began spinning round on the carpet? Was +that real or not? Do you remember what fun it was?" + +"Yes, and you remember how Papa in his blue overcoat fired a gun +in the porch?" + +So they went through their memories, smiling with pleasure: not +the sad memories of old age, but poetic, youthful ones--those +impressions of one's most distant past in which dreams and realities +blend--and they laughed with quiet enjoyment. + +Sonya, as always, did not quite keep pace with them, though they +shared the same reminiscences. + +Much that they remembered had slipped from her mind, and what she +recalled did not arouse the same poetic feeling as they experienced. +She simply enjoyed their pleasure and tried to fit in with it. + +She only really took part when they recalled Sonya's first +arrival. She told them how afraid she had been of Nicholas because +he had on a corded jacket and her nurse had told her that she, too, +would be sewn up with cords. + +"And I remember their telling me that you had been born under a +cabbage," said Natasha, "and I remember that I dared not disbelieve +it then, but knew that it was not true, and I felt so uncomfortable." + +While they were talking a maid thrust her head in at the other +door of the sitting room. + +"They have brought the cock, Miss," she said in a whisper. + +"It isn't wanted, Petya. Tell them to take it away," replied +Natasha. + +In the middle of their talk in the sitting room, Dimmler came in and +went up to the harp that stood there in a corner. He took off its +cloth covering, and the harp gave out a jarring sound. + +"Mr. Dimmler, please play my favorite nocturne by Field," came the +old countess' voice from the drawing room. + +Dimmler struck a chord and, turning to Natasha, Nicholas, and Sonya, +remarked: "How quiet you young people are!" + +"Yes, we're philosophizing," said Natasha, glancing round for a +moment and then continuing the conversation. They were now +discussing dreams. + +Dimmler began to play; Natasha went on tiptoe noiselessly to the +table, took up a candle, carried it out, and returned, seating herself +quietly in her former place. It was dark in the room especially +where they were sitting on the sofa, but through the big windows the +silvery light of the full moon fell on the floor. Dimmler had finished +the piece but still sat softly running his fingers over the strings, +evidently uncertain whether to stop or to play something else. + +"Do you know," said Natasha in a whisper, moving closer to +Nicholas and Sonya, "that when one goes on and on recalling +memories, one at last begins to remember what happened before one +was in the world..." + +"That is metempsychosis," said Sonya, who had always learned well, +and remembered everything. "The Egyptians believed that our souls have +lived in animals, and will go back into animals again." + +"No, I don't believe we ever were in animals," said Natasha, still +in a whisper though the music had ceased. "But I am certain that we +were angels somewhere there, and have been here, and that is why we +remember...." + +"May I join you?" said Dimmler who had come up quietly, and he sat +down by them. + +"If we have been angels, why have we fallen lower?" said Nicholas. +"No, that can't be!" + +"Not lower, who said we were lower?... How do I know what I was +before?" Natasha rejoined with conviction. "The soul is immortal--well +then, if I shall always live I must have lived before, lived for a +whole eternity." + +"Yes, but it is hard for us to imagine eternity," remarked +Dimmler, who had joined the young folk with a mildly condescending +smile but now spoke as quietly and seriously as they. + +"Why is it hard to imagine eternity?" said Natasha. "It is now +today, and it will be tomorrow, and always; and there was yesterday, +and the day before..." + +"Natasha! Now it's your turn. Sing me something," they heard the +countess say. "Why are you sitting there like conspirators?" + +"Mamma, I don't at all want to," replied Natasha, but all the same +she rose. + +None of them, not even the middle-aged Dimmler, wanted to break +off their conversation and quit that corner in the sitting room, but +Natasha got up and Nicholas sat down at the clavichord. Standing as +usual in the middle of the hall and choosing the place where the +resonance was best, Natasha began to sing her mother's favorite song. + +She had said she did not want to sing, but it was long since she had +sung, and long before she again sang, as she did that evening. The +count, from his study where he was talking to Mitenka, heard her +and, like a schoolboy in a hurry to run out to play, blundered in +his talk while giving orders to the steward, and at last stopped, +while Mitenka stood in front of him also listening and smiling. +Nicholas did not take his eyes off his sister and drew breath in +time with her. Sonya, as she listened, thought of the immense +difference there was between herself and her friend, and how +impossible it was for her to be anything like as bewitching as her +cousin. The old countess sat with a blissful yet sad smile and with +tears in her eyes, occasionally shaking her head. She thought of +Natasha and of her own youth, and of how there was something unnatural +and dreadful in this impending marriage of Natasha and Prince Andrew. + +Dimmler, who had seated himself beside the countess, listened with +closed eyes. + +"Ah, Countess," he said at last, "that's a European talent, she +has nothing to learn--what softness, tenderness, and strength...." + +"Ah, how afraid I am for her, how afraid I am!" said the countess, +not realizing to whom she was speaking. Her maternal instinct told her +that Natasha had too much of something, and that because of this she +would not be happy. Before Natasha had finished singing, +fourteen-year-old Petya rushed in delightedly, to say that some +mummers had arrived. + +Natasha stopped abruptly. + +"Idiot!" she screamed at her brother and, running to a chair, +threw herself on it, sobbing so violently that she could not stop +for a long time. + +"It's nothing, Mamma, really it's nothing; only Petya startled +me," she said, trying to smile, but her tears still flowed and sobs +still choked her. + +The mummers (some of the house serfs) dressed up as bears, Turks, +innkeepers, and ladies--frightening and funny--bringing in with them +the cold from outside and a feeling of gaiety, crowded, at first +timidly, into the anteroom, then hiding behind one another they pushed +into the ballroom where, shyly at first and then more and more merrily +and heartily, they started singing, dancing, and playing Christmas +games. The countess, when she had identified them and laughed at their +costumes, went into the drawing room. The count sat in the ballroom, +smiling radiantly and applauding the players. The young people had +disappeared. + +Half an hour later there appeared among the other mummers in the +ballroom an old lady in a hooped skirt--this was Nicholas. A Turkish +girl was Petya. A clown was Dimmler. An hussar was Natasha, and a +Circassian was Sonya with burnt-cork mustache and eyebrows. + +After the condescending surprise, nonrecognition, and praise, from +those who were not themselves dressed up, the young people decided +that their costumes were so good that they ought to be shown +elsewhere. + +Nicholas, who, as the roads were in splendid condition, wanted to +take them all for a drive in his troyka, proposed to take with them +about a dozen of the serf mummers and drive to "Uncle's." + +"No, why disturb the old fellow?" said the countess. "Besides, you +wouldn't have room to turn round there. If you must go, go to the +Melyukovs'." + +Melyukova was a widow, who, with her family and their tutors and +governesses, lived three miles from the Rostovs. + +"That's right, my dear," chimed in the old count, thoroughly +aroused. "I'll dress up at once and go with them. I'll make Pashette +open her eyes." + +But the countess would not agree to his going; he had had a bad +leg all these last days. It was decided that the count must not go, +but that if Louisa Ivanovna (Madame Schoss) would go with them, the +young ladies might go to the Melyukovs', Sonya, generally so timid and +shy, more urgently than anyone begging Louisa Ivanovna not to refuse. + +Sonya's costume was the best of all. Her mustache and eyebrows +were extraordinarily becoming. Everyone told her she looked very +handsome, and she was in a spirited and energetic mood unusual with +her. Some inner voice told her that now or never her fate would be +decided, and in her male attire she seemed quite a different person. +Louisa Ivanovna consented to go, and in half an hour four troyka +sleighs with large and small bells, their runners squeaking and +whistling over the frozen snow, drove up to the porch. + +Natasha was foremost in setting a merry holiday tone, which, passing +from one to another, grew stronger and reached its climax +when they all came out into the frost and got into the sleighs, +talking, calling to one another, laughing, and shouting. + +Two of the troykas were the usual household sleighs, the third was +the old count's with a trotter from the Orlov stud as shaft horse, the +fourth was Nicholas' own with a short shaggy black shaft horse. +Nicholas, in his old lady's dress over which he had belted his +hussar overcoat, stood in the middle of the sleigh, reins in hand. + +It was so light that he could see the moonlight reflected from the +metal harness disks and from the eyes of the horses, who looked +round in alarm at the noisy party under the shadow of the porch roof. + +Natasha, Sonya, Madame Schoss, and two maids got into Nicholas' +sleigh; Dimmler, his wife, and Petya, into the old count's, and the +rest of the mummers seated themselves in the other two sleighs. + +"You go ahead, Zakhar!" shouted Nicholas to his father's coachman, +wishing for a chance to race past him. + +The old count's troyka, with Dimmler and his party, started forward, +squeaking on its runners as though freezing to the snow, its +deep-toned bell clanging. The side horses, pressing against the shafts +of the middle horse, sank in the snow, which was dry and glittered +like sugar, and threw it up. + +Nicholas set off, following the first sleigh; behind him the +others moved noisily, their runners squeaking. At first they drove +at a steady trot along the narrow road. While they drove past the +garden the shadows of the bare trees often fell across the road and +hid the brilliant moonlight, but as soon as they were past the +fence, the snowy plain bathed in moonlight and motionless spread out +before them glittering like diamonds and dappled with bluish +shadows. Bang, bang! went the first sleigh over a cradle hole in the +snow of the road, and each of the other sleighs jolted in the same +way, and rudely breaking the frost-bound stillness, the troykas +began to speed along the road, one after the other. + +"A hare's track, a lot of tracks!" rang out Natasha's voice +through the frost-bound air. + +"How light it is, Nicholas!" came Sonya's voice. + +Nicholas glanced round at Sonya, and bent down to see her face +closer. Quite a new, sweet face with black eyebrows and mustaches +peeped up at him from her sable furs--so close and yet so distant- +in the moonlight. + +"That used to be Sonya," thought he, and looked at her closer and +smiled. + +"What is it, Nicholas?" + +"Nothing," said he and turned again to the horses. + +When they came out onto the beaten highroad--polished by sleigh +runners and cut up by rough-shod hoofs, the marks of which were +visible in the moonlight--the horses began to tug at the reins of +their own accord and increased their pace. The near side horse, +arching his head and breaking into a short canter, tugged at his +traces. The shaft horse swayed from side to side, moving his ears as +if asking: "Isn't it time to begin now?" In front, already far ahead +the deep bell of the sleigh ringing farther and farther off, the black +horses driven by Zakhar could be clearly seen against the white +snow. From that sleigh one could hear the shouts, laughter, and voices +of the mummers. + +"Gee up, my darlings!" shouted Nicholas, pulling the reins to one +side and flourishing the whip. + +It was only by the keener wind that met them and the jerks given +by the side horses who pulled harder--ever increasing their gallop- +that one noticed how fast the troyka was flying. Nicholas looked back. +With screams squeals, and waving of whips that caused even the shaft +horses to gallop--the other sleighs followed. The shaft horse swung +steadily beneath the bow over its head, with no thought of +slackening pace and ready to put on speed when required. + +Nicholas overtook the first sleigh. They were driving downhill and +coming out upon a broad trodden track across a meadow, near a river. + +"Where are we?" thought he. "It's the Kosoy meadow, I suppose. But +no--this is something new I've never seen before. This isn't the Kosoy +meadow nor the Demkin hill, and heaven only knows what it is! It is +something new and enchanted. Well, whatever it may be..." And shouting +to his horses, he began to pass the first sleigh. + +Zakhar held back his horses and turned his face, which was already +covered with hoarfrost to his eyebrows. + +Nicholas gave the horses the rein, and Zakhar, stretching out his +arms, clucked his tongue and let his horses go. + +"Now, look out, master!" he cried. + +Faster still the two troykas flew side by side, and faster moved the +feet of the galloping side horses. Nicholas began to draw ahead. +Zakhar, while still keeping his arms extended, raised one hand with +the reins. + +"No you won't, master!" he shouted. + +Nicholas put all his horses to a gallop and passed Zakhar. The +horses showered the fine dry snow on the faces of those in the sleigh- +beside them sounded quick ringing bells and they caught confused +glimpses of swiftly moving legs and the shadows of the troyka they +were passing. The whistling sound of the runners on the snow and the +voices of girls shrieking were heard from different sides. + +Again checking his horses, Nicholas looked around him. They were +still surrounded by the magic plain bathed in moonlight and spangled +with stars. + +"Zakhar is shouting that I should turn to the left, but why to the +left?" thought Nicholas. "Are we getting to the Melyukovs'? Is this +Melyukovka? Heaven only knows where we are going, and heaven knows +what is happening to us--but it is very strange and pleasant +whatever it is." And he looked round in the sleigh. + +"Look, his mustache and eyelashes are all white!" said one of the +strange, pretty, unfamiliar people--the one with fine eyebrows and +mustache. + +"I think this used to be Natasha," thought Nicholas, "and that was +Madame Schoss, but perhaps it's not, and this Circassian with the +mustache I don't know, but I love her." + +"Aren't you cold?" he asked. + +They did not answer but began to laugh. Dimmler from the sleigh +behind shouted something--probably something funny--but they could not +make out what he said. + +"Yes, yes!" some voices answered, laughing. + +"But here was a fairy forest with black moving shadows, and a +glitter of diamonds and a flight of marble steps and the silver +roofs of fairy buildings and the shrill yells of some animals. And +if this is really Melyukovka, it is still stranger that we drove +heaven knows where and have come to Melyukovka," thought Nicholas. + +It really was Melyukovka, and maids and footmen with merry faces +came running, out to the porch carrying candles. + +"Who is it?" asked someone in the porch. + +"The mummers from the count's. I know by the horses," replied some +voices. + + + + + +CHAPTER XI + + +Pelageya Danilovna Melyukova, a broadly built, energetic woman +wearing spectacles, sat in the drawing room in a loose dress, +surrounded by her daughters whom she was trying to keep from feeling +dull. They were quietly dropping melted wax into snow and looking at +the shadows the wax figures would throw on the wall, when they heard +the steps and voices of new arrivals in the vestibule. + +Hussars, ladies, witches, clowns, and bears, after clearing their +throats and wiping the hoarfrost from their faces in the vestibule, +came into the ballroom where candles were hurriedly lighted. The +clown--Dimmler--and the lady--Nicholas--started a dance. Surrounded by +the screaming children the mummers, covering their faces and +disguising their voices, bowed to their hostess and arranged +themselves about the room. + +"Dear me! there's no recognizing them! And Natasha! See whom she +looks like! She really reminds me of somebody. But Herr Dimmler--isn't +he good! I didn't know him! And how he dances. Dear me, there's a +Circassian. Really, how becoming it is to dear Sonya. And who is that? +Well, you have cheered us up! Nikita and Vanya--clear away the tables! +And we were sitting so quietly. Ha, ha, ha!... The hussar, the hussar! +Just like a boy! And the legs!... I can't look at him..." different +voices were saying. + +Natasha, the young Melyukovs' favorite, disappeared with them into +the back rooms where a cork and various dressing gowns and male +garments were called for and received from the footman by bare girlish +arms from behind the door. Ten minutes later, all the young +Melyukovs joined the mummers. + +Pelageya Danilovna, having given orders to clear the rooms for the +visitors and arranged about refreshments for the gentry and the serfs, +went about among the mummers without removing her spectacles, +peering into their faces with a suppressed smile and failing to +recognize any of them. It was not merely Dimmler and the Rostovs she +failed to recognize, she did not even recognize her own daughters, +or her late husband's, dressing gowns and uniforms, which they had put +on. + +"And who is is this?" she asked her governess, peering into the face +of her own daughter dressed up as a Kazan-Tartar. "I suppose it is one +of the Rostovs! Well, Mr. Hussar, and what regiment do you serve +in?" she asked Natasha. "Here, hand some fruit jelly to the Turk!" she +ordered the butler who was handing things round. "That's not forbidden +by his law." + +Sometimes, as she looked at the strange but amusing capers cut by +the dancers, who--having decided once for all that being disguised, no +one would recognize them--were not at all shy, Pelageya Danilovna +hid her face in her handkerchief, and her whole stout body shook +with irrepressible, kindly, elderly laughter. + +"My little Sasha! Look at Sasha!" she said. + +After Russian country dances and chorus dances, Pelageya Danilovna +made the serfs and gentry join in one large circle: a ring, a +string, and a silver ruble were fetched and they all played games +together. + +In an hour, all the costumes were crumpled and disordered. The +corked eyebrows and mustaches were smeared over the perspiring, +flushed, and merry faces. Pelageya Danilovna began to recognize the +mummers, admired their cleverly contrived costumes, and particularly +how they suited the young ladies, and she thanked them all for +having entertained her so well. The visitors were invited to supper in +the drawing room, and the serfs had something served to them in the +ballroom. + +"Now to tell one's fortune in the empty bathhouse is frightening!" +said an old maid who lived with the Melyukovs, during supper. + +"Why?" said the eldest Melyukov girl. + +"You wouldn't go, it takes courage..." + +"I'll go," said Sonya. + +"Tell what happened to the young lady!" said the second Melyukov +girl. + +"Well," began the old maid, "a young lady once went out, took a +cock, laid the table for two, all properly, and sat down. After +sitting a while, she suddenly hears someone coming... a sleigh +drives up with harness bells; she hears him coming! He comes in, +just in the shape of a man, like an officer--comes in and sits down to +table with her." + +"Ah! ah!" screamed Natasha, rolling her eyes with horror. + +"Yes? And how... did he speak?" + +"Yes, like a man. Everything quite all right, and he began +persuading her; and she should have kept him talking till cockcrow, +but she got frightened, just got frightened and hid her face in her +hands. Then he caught her up. It was lucky the maids ran in just +then..." + +"Now, why frighten them?" said Pelageya Danilovna. + +"Mamma, you used to try your fate yourself..." said her daughter. + +"And how does one do it in a barn?" inquired Sonya. + +"Well, say you went to the barn now, and listened. It depends on +what you hear; hammering and knocking--that's bad; but a sound of +shifting grain is good and one sometimes hears that, too." + +"Mamma, tell us what happened to you in the barn." + +Pelageya Danilovna smiled. + +"Oh, I've forgotten..." she replied. "But none of you would go?" + +"Yes, I will; Pelageya Danilovna, let me! I'll go," said Sonya. + +"Well, why not, if you're not afraid?" + +"Louisa Ivanovna, may I?" asked Sonya. + +Whether they were playing the ring and string game or the ruble game +or talking as now, Nicholas did not leave Sonya's side, and gazed at +her with quite new eyes. It seemed to him that it was only today, +thanks to that burnt-cork mustache, that he had fully learned to +know her. And really, that evening, Sonya was brighter, more animated, +and prettier than Nicholas had ever seen her before. + +"So that's what she is like; what a fool I have been!" he thought +gazing at her sparkling eyes, and under the mustache a happy rapturous +smile dimpled her cheeks, a smile he had never seen before. + +"I'm not afraid of anything," said Sonya. "May I go at once?" She +got up. + +They told her where the barn was and how she should stand and +listen, and they handed her a fur cloak. She threw this over her +head and shoulders and glanced at Nicholas. + +"What a darling that girl is!" thought he. "And what have I been +thinking of till now?" + +Sonya went out into the passage to go to the barn. Nicholas went +hastily to the front porch, saying he felt too hot. The crowd of +people really had made the house stuffy. + +Outside, there was the same cold stillness and the same moon, but +even brighter than before. The light was so strong and the snow +sparkled with so many stars that one did not wish to look up at the +sky and the real stars were unnoticed. The sky was black and dreary, +while the earth was gay. + +"I am a fool, a fool! what have I been waiting for?" thought +Nicholas, and running out from the porch he went round the corner of +the house and along the path that led to the back porch. He knew Sonya +would pass that way. Halfway lay some snow-covered piles of firewood +and across and along them a network of shadows from the bare old +lime trees fell on the snow and on the path. This path led to the +barn. The log walls of the barn and its snow-covered roof, that looked +as if hewn out of some precious stone, sparkled in the moonlight. A +tree in the garden snapped with the frost, and then all was again +perfectly silent. His bosom seemed to inhale not air but the +strength of eternal youth and gladness. + +From the back porch came the sound of feet descending the steps, the +bottom step upon which snow had fallen gave a ringing creak and he +heard the voice of an old maidservant saying, "Straight, straight, +along the path, Miss. Only, don't look back." + +"I am not afraid," answered Sonya's voice, and along the path toward +Nicholas came the crunching, whistling sound of Sonya's feet in her +thin shoes. + +Sonya came along, wrapped in her cloak. She was only a couple of +paces away when she saw him, and to her too he was not the Nicholas +she had known and always slightly feared. He was in a woman's dress, +with tousled hair and a happy smile new to Sonya. She ran rapidly +toward him. + +"Quite different and yet the same," thought Nicholas, looking at her +face all lit up by the moonlight. He slipped his arms under the +cloak that covered her head, embraced her, pressed her to him, and +kissed her on the lips that wore a mustache and had a smell of burnt +cork. Sonya kissed him full on the lips, and disengaging her little +hands pressed them to his cheeks. + +"Sonya!... Nicholas!"... was all they said. They ran to the barn and +then back again, re-entering, he by the front and she by the back +porch. + + + + + +CHAPTER XII + + +When they all drove back from Pelageya Danilovna's, Natasha, who +always saw and noticed everything, arranged that she and Madame Schoss +should go back in the sleigh with Dimmler, and Sonya with Nicholas and +the maids. + +On the way back Nicholas drove at a steady pace instead of racing +and kept peering by that fantastic all-transforming light into Sonya's +face and searching beneath the eyebrows and mustache for his former +and his present Sonya from whom he had resolved never to be parted +again. He looked and recognizing in her both the old and the new +Sonya, and being reminded by the smell of burnt cork of the +sensation of her kiss, inhaled the frosty air with a full breast +and, looking at the ground flying beneath him and at the sparkling +sky, felt himself again in fairyland. + +"Sonya, is it well with thee?" he asked from time to time. + +"Yes!" she replied. "And with thee?" + +When halfway home Nicholas handed the reins to the coachman and +ran for a moment to Natasha's sleigh and stood on its wing. + +"Natasha!" he whispered in French, "do you know I have made up my +mind about Sonya?" + +"Have you told her?" asked Natasha, suddenly beaming all over with +joy. + +"Oh, how strange you are with that mustache and those eyebrows!... +Natasha--are you glad?" + +"I am so glad, so glad! I was beginning to be vexed with you. I +did not tell you, but you have been treating her badly. What a heart +she has, Nicholas! I am horrid sometimes, but I was ashamed to be +happy while Sonya was not," continued Natasha. "Now I am so glad! +Well, run back to her." + +"No, wait a bit.... Oh, how funny you look!" cried Nicholas, peering +into her face and finding in his sister too something new, unusual, +and bewitchingly tender that he had not seen in her before. +"Natasha, it's magical, isn't it?" + +"Yes," she replied. "You have done splendidly." + +"Had I seen her before as she is now," thought Nicholas, "I should +long ago have asked her what to do and have done whatever she told me, +and all would have been well." + +"So you are glad and I have done right?" + +"Oh, quite right! I had a quarrel with Mamma some time ago about it. +Mamma said she was angling for you. How could she say such a thing! +I nearly stormed at Mamma. I will never let anyone say anything bad of +Sonya, for there is nothing but good in her." + +"Then it's all right?" said Nicholas, again scrutinizing the +expression of his sister's face to see if she was in earnest. Then +he jumped down and, his boots scrunching the snow, ran back to his +sleigh. The same happy, smiling Circassian, with mustache and +beaming eyes looking up from under a sable hood, was still sitting +there, and that Circassian was Sonya, and that Sonya was certainly his +future happy and loving wife. + +When they reached home and had told their mother how they had +spent the evening at the Melyukovs', the girls went to their +bedroom. When they had undressed, but without washing off the cork +mustaches, they sat a long time talking of their happiness. They +talked of how they would live when they were married, how their +husbands would be friends, and how happy they would be. On Natasha's +table stood two looking glasses which Dunyasha had prepared +beforehand. + +"Only when will all that be? I am afraid never.... It would be too +good!" said Natasha, rising and going to the looking glasses. + +"Sit down, Natasha; perhaps you'll see him," said Sonya. + +Natasha lit the candles, one on each side of one of the looking +glasses, and sat down. + +"I see someone with a mustache," said Natasha, seeing her own face. + +"You mustn't laugh, Miss," said Dunyasha. + +With Sonya's help and the maid's, Natasha got the glass she held +into the right position opposite the other; her face assumed a serious +expression and she sat silent. She sat a long time looking at the +receding line of candles reflected in the glasses and expecting +(from tales she had heard) to see a coffin, or him, Prince Andrew, +in that last dim, indistinctly outlined square. But ready as she was +to take the smallest speck for the image of a man or of a coffin, +she saw nothing. She began blinking rapidly and moved away from the +looking glasses. + +"Why is it others see things and I don't?" she said. "You sit down +now, Sonya. You absolutely must, tonight! Do it for me.... Today I +feel so frightened!" + +Sonya sat down before the glasses, got the right position, and began +looking. + +"Now, Miss Sonya is sure to see something," whispered Dunyasha; +"while you do nothing but laugh." + +Sonya heard this and Natasha's whisper: + +"I know she will. She saw something last year." + +For about three minutes all were silent. + +"Of course she will!" whispered Natasha, but did not finish... +suddenly Sonya pushed away the glass she was holding and covered her +eyes with her hand. + +"Oh, Natasha!" she cried. + +"Did you see? Did you? What was it?" exclaimed Natasha, holding up +the looking glass. + +Sonya had not seen anything, she was just wanting to blink and to +get up when she heard Natasha say, "Of course she will!" She did not +wish to disappoint either Dunyasha or Natasha, but it was hard to +sit still. She did not herself know how or why the exclamation escaped +her when she covered her eyes. + +"You saw him?" urged Natasha, seizing her hand. + +"Yes. Wait a bit... I... saw him," Sonya could not help saying, +not yet knowing whom Natasha meant by him, Nicholas or Prince Andrew. + +"But why shouldn't I say I saw something? Others do see! Besides who +can tell whether I saw anything or not?" flashed through Sonya's mind. + +"Yes, I saw him," she said. + +"How? Standing or lying?" + +"No, I saw... At first there was nothing, then I saw him lying +down." + +"Andrew lying? Is he ill?" asked Natasha, her frightened eyes +fixed on her friend. + +"No, on the contrary, on the contrary! His face was cheerful, and he +turned to me." And when saying this she herself fancied she had really +seen what she described. + +"Well, and then, Sonya?..." + +"After that, I could not make out what there was; something blue and +red..." + +"Sonya! When will he come back? When shall I see him! O, God, how +afraid I am for him and for myself and about everything!..." Natasha +began, and without replying to Sonya's words of comfort she got into +bed, and long after her candle was out lay open-eyed and motionless, +gazing at the moonlight through the frosty windowpanes. + + + + + +CHAPTER XIII + + +Soon after the Christmas holidays Nicholas told his mother of his +love for Sonya and of his firm resolve to marry her. The countess, who +had long noticed what was going on between them and was expecting this +declaration, listened to him in silence and then told her son that +he might marry whom he pleased, but that neither she nor his father +would give their blessing to such a marriage. Nicholas, for the +first time, felt that his mother was displeased with him and that, +despite her love for him, she would not give way. Coldly, without +looking at her son, she sent for her husband and, when he came, +tried briefly and coldly to inform him of the facts, in her son's +presence, but unable to restrain herself she burst into tears of +vexation and left the room. The old count began irresolutely to +admonish Nicholas and beg him to abandon his purpose. Nicholas replied +that he could not go back on his word, and his father, sighing and +evidently disconcerted, very soon became silent and went in to the +countess. In all his encounters with his son, the count was always +conscious of his own guilt toward him for having wasted the family +fortune, and so he could not be angry with him for refusing to marry +an heiress and choosing the dowerless Sonya. On this occasion, he +was only more vividly conscious of the fact that if his affairs had +not been in disorder, no better wife for Nicholas than Sonya could +have been wished for, and that no one but himself with his Mitenka and +his uncomfortable habits was to blame for the condition of the +family finances. + +The father and mother did not speak of the matter to their son +again, but a few days later the countess sent for Sonya and, with a +cruelty neither of them expected, reproached her niece for trying to +catch Nicholas and for ingratitude. Sonya listened silently with +downcast eyes to the countess' cruel words, without understanding what +was required of her. She was ready to sacrifice everything for her +benefactors. Self-sacrifice was her most cherished idea but in this +case she could not see what she ought to sacrifice, or for whom. She +could not help loving the countess and the whole Rostov family, but +neither could she help loving Nicholas and knowing that his +happiness depended on that love. She was silent and sad and did not +reply. Nicholas felt the situation to be intolerable and went to +have an explanation with his mother. He first implored her to +forgive him and Sonya and consent to their marriage, then he +threatened that if she molested Sonya he would at once marry her +secretly. + +The countess, with a coldness her son had never seen in her +before, replied that he was of age, that Prince Andrew was marrying +without his father's consent, and he could do the same, but that she +would never receive that intriguer as her daughter. + +Exploding at the word intriguer, Nicholas, raising his voice, told +his mother he had never expected her to try to force him to sell his +feelings, but if that were so, he would say for the last time.... +But he had no time to utter the decisive word which the expression +of his face caused his mother to await with terror, and which would +perhaps have forever remained a cruel memory to them both. He had +not time to say it, for Natasha, with a pale and set face, entered the +room from the door at which she had been listening. + +"Nicholas, you are talking nonsense! Be quiet, be quiet, be quiet, I +tell you!..." she almost screamed, so as to drown his voice. + +"Mamma darling, it's not at all so... my poor, sweet darling," she +said to her mother, who conscious that they had been on the brink of a +rupture gazed at her son with terror, but in the obstinacy and +excitement of the conflict could not and would not give way. + +"Nicholas, I'll explain to you. Go away! Listen, Mamma darling," +said Natasha. + +Her words were incoherent, but they attained the purpose at which +she was aiming. + +The countess, sobbing heavily, hid her face on her daughter's +breast, while Nicholas rose, clutching his head, and left the room. + +Natasha set to work to effect a reconciliation, and so far succeeded +that Nicholas received a promise from his mother that Sonya should not +be troubled, while he on his side promised not to undertake anything +without his parents' knowledge. + +Firmly resolved, after putting his affairs in order in the regiment, +to retire from the army and return and marry Sonya, Nicholas, serious, +sorrowful, and at variance with his parents, but, as it seemed to him, +passionately in love, left at the beginning of January to rejoin his +regiment. + +After Nicholas had gone things in the Rostov household were more +depressing than ever, and the countess fell ill from mental agitation. + +Sonya was unhappy at the separation from Nicholas and still more +so on account of the hostile tone the countess could not help adopting +toward her. The count was more perturbed than ever by the condition of +his affairs, which called for some decisive action. Their town house +and estate near Moscow had inevitably to be sold, and for this they +had to go to Moscow. But the countess' health obliged them to delay +their departure from day to day. + +Natasha, who had borne the first period of separation from her +betrothed lightly and even cheerfully, now grew more agitated and +impatient every day. The thought that her best days, which she would +have employed in loving him, were being vainly wasted, with no +advantage to anyone, tormented her incessantly. His letters for the +most part irritated her. It hurt her to think that while she lived +only in the thought of him, he was living a real life, seeing new +places and new people that interested him. The more interesting his +letters were the more vexed she felt. Her letters to him, far from +giving her any comfort, seemed to her a wearisome and artificial +obligation. She could not write, because she could not conceive the +possibility of expressing sincerely in a letter even a thousandth part +of what she expressed by voice, smile, and glance. She wrote to him +formal, monotonous, and dry letters, to which she attached no +importance herself, and in the rough copies of which the countess +corrected her mistakes in spelling. + +There was still no improvement in the countess' health, but it was +impossible to defer the journey to Moscow any longer. Natasha's +trousseau had to be ordered and the house sold. Moreover, Prince +Andrew was expected in Moscow, where old Prince Bolkonski was spending +the winter, and Natasha felt sure he had already arrived. + +So the countess remained in the country, and the count, taking Sonya +and Natasha with him, went to Moscow at the end of January. + + + + +BOOK EIGHT: 1811 --12 + + + + + +CHAPTER I + + +After Prince Andrews engagement to Natasha, Pierre without any +apparent cause suddenly felt it impossible to go on living as +before. Firmly convinced as he was of the truths revealed to him by +his benefactor, and happy as he had been in perfecting his inner +man, to which he had devoted himself with such ardor--all the zest +of such a life vanished after the engagement of Andrew and Natasha and +the death of Joseph Alexeevich, the news of which reached him almost +at the same time. Only the skeleton of life remained: his house, a +brilliant wife who now enjoyed the favors of a very important +personage, acquaintance with all Petersburg, and his court service +with its dull formalities. And this life suddenly seemed to Pierre +unexpectedly loathsome. He ceased keeping a diary, avoided the company +of the Brothers, began going to the Club again, drank a great deal, +and came once more in touch with the bachelor sets, leading such a +life that the Countess Helene thought it necessary to speak severely +to him about it. Pierre felt that she right, and to avoid compromising +her went away to Moscow. + +In Moscow as soon as he entered his huge house in which the faded +and fading princesses still lived, with its enormous retinue; as +soon as, driving through the town, he saw the Iberian shrine with +innumerable tapers burning before the golden covers of the icons, +the Kremlin Square with its snow undisturbed by vehicles, the sleigh +drivers and hovels of the Sivtsev Vrazhok, those old Moscovites who +desired nothing, hurried nowhere, and were ending their days +leisurely; when he saw those old Moscow ladies, the Moscow balls, +and the English Club, he felt himself at home in a quiet haven. In +Moscow he felt at peace, at home, warm and dirty as in an old dressing +gown. + +Moscow society, from the old women down to the children, received +Pierre like a long-expected guest whose place was always ready +awaiting him. For Moscow society Pierre was the nicest, kindest, +most intellectual, merriest, and most magnanimous of cranks, a +heedless, genial nobleman of the old Russian type. His purse was +always empty because it was open to everyone. + +Benefit performances, poor pictures, statues, benevolent +societies, gypsy choirs, schools, subscription dinners, sprees, +Freemasons, churches, and books--no one and nothing met with a refusal +from him, and had it not been for two friends who had borrowed large +sums from him and taken him under their protection, he would have +given everything away. There was never a dinner or soiree at the +Club without him. As soon as he sank into his place on the sofa +after two bottles of Margaux he was surrounded, and talking, +disputing, and joking began. When there were quarrels, his kindly +smile and well-timed jests reconciled the antagonists. The Masonic +dinners were dull and dreary when he was not there. + +When after a bachelor supper he rose with his amiable and kindly +smile, yielding to the entreaties of the festive company to drive +off somewhere with them, shouts of delight and triumph arose among the +young men. At balls he danced if a partner was needed. Young ladies, +married and unmarried, liked him because without making love to any of +them, he was equally amiable to all, especially after supper. "Il +est charmant; il n'a pas de sexe,"* they said of him. + + +*"He is charming; he has no sex." + + +Pierre was one of those retired gentlemen-in-waiting of whom there +were hundreds good-humoredly ending their days in Moscow. + +How horrified he would have been seven years before, when he first +arrived from abroad, had he been told that there was no need for him +to seek or plan anything, that his rut had long been shaped, eternally +predetermined, and that wriggle as he might, he would be what all in +his position were. He could not have believed it! Had he not at one +time longed with all his heart to establish a republic in Russia; then +himself to be a Napoleon; then to be a philosopher; and then a +strategist and the conqueror of Napoleon? Had he not seen the +possibility of, and passionately desired, the regeneration of the +sinful human race, and his own progress to the highest degree of +perfection? Had he not established schools and hospitals and liberated +his serfs? + +But instead of all that--here he was, the wealthy husband of an +unfaithful wife, a retired gentleman-in-waiting, fond of eating and +drinking and, as he unbuttoned his waistcoat, of abusing the +government a bit, a member of the Moscow English Club, and a universal +favorite in Moscow society. For a long time he could not reconcile +himself to the idea that he was one of those same retired Moscow +gentlemen-in-waiting he had so despised seven years before. + +Sometimes he consoled himself with the thought that he was only +living this life temporarily; but then he was shocked by the thought +of how many, like himself, had entered that life and that Club +temporarily, with all their teeth and hair, and had only left it +when not a single tooth or hair remained. + +In moments of pride, when he thought of his position it seemed to +him that he was quite different and distinct from those other +retired gentlemen-in-waiting he had formerly despised: they were +empty, stupid, contented fellows, satisfied with their position, +"while I am still discontented and want to do something for mankind. +But perhaps all these comrades of mine struggled just like me and +sought something new, a path in life of their own, and like me were +brought by force of circumstances, society, and race--by that +elemental force against which man is powerless--to the condition I +am in," said he to himself in moments of humility; and after living +some time in Moscow he no longer despised, but began to grow fond +of, to respect, and to pity his comrades in destiny, as he pitied +himself. + +Pierre longer suffered moments of despair, hypochondria, and disgust +with life, but the malady that had formerly found expression in such +acute attacks was driven inwards and never left him for a moment. +"What for? Why? What is going on in the world?" he would ask himself +in perplexity several times a day, involuntarily beginning to +reflect anew on the meaning of the phenomena of life; but knowing by +experience that there were no answers to these questions he made haste +to turn away from them, and took up a book, or hurried of to the +Club or to Apollon Nikolaevich's, to exchange the gossip of the town. + +"Helene, who has never cared for anything but her own body and is +one of the stupidest women in the world," thought Pierre, "is regarded +by people as the acme of intelligence and refinement, and they pay +homage to her. Napoleon Bonaparte was despised by all as long as he +was great, but now that he has become a wretched comedian the +Emperor Francis wants to offer him his daughter in an illegal +marriage. The Spaniards, through the Catholic clergy, offer praise +to God for their victory over the French on the fourteenth of June, +and the French, also through the Catholic clergy, offer praise because +on that same fourteenth of June they defeated the Spaniards. My +brother Masons swear by the blood that they are ready to sacrifice +everything for their neighbor, but they do not give a ruble each to +the collections for the poor, and they intrigue, the Astraea Lodge +against the Manna Seekers, and fuss about an authentic Scotch carpet +and a charter that nobody needs, and the meaning of which the very man +who wrote it does not understand. We all profess the Christian law +of forgiveness of injuries and love of our neighbors, the law in honor +of which we have built in Moscow forty times forty churches--but +yesterday a deserter was knouted to death and a minister of that +same law of love and forgiveness, a priest, gave the soldier a cross +to kiss before his execution." So thought Pierre, and the whole of +this general deception which everyone accepts, accustomed as he was to +it, astonished him each time as if it were something new. "I +understand the deception and confusion," he thought, "but how am I +to tell them all that I see? I have tried, and have always found +that they too in the depths of their souls understand it as I do, +and only try not to see it. So it appears that it must be so! But I- +what is to become of me?" thought he. He had the unfortunate +capacity many men, especially Russians, have of seeing and believing +in the possibility of goodness and truth, but of seeing the evil and +falsehood of life too clearly to be able to take a serious part in it. +Every sphere of work was connected, in his eyes, with evil and +deception. Whatever he tried to be, whatever he engaged in, the evil +and falsehood of it repulsed him and blocked every path of activity. +Yet he had to live and to find occupation. It was too dreadful to be +under the burden of these insoluble problems, so he abandoned +himself to any distraction in order to forget them. He frequented +every kind of society, drank much, bought pictures, engaged in +building, and above all--read. + +He read, and read everything that came to hand. On coming home, +while his valets were still taking off his things, he picked up a book +and began to read. From reading he passed to sleeping, from sleeping +to gossip in drawing rooms of the Club, from gossip to carousals and +women; from carousals back to gossip, reading, and wine. Drinking +became more and more a physical and also a moral necessity. Though the +doctors warned him that with his corpulence wine was dangerous for +him, he drank a great deal. He was only quite at ease when having +poured several glasses of wine mechanically into his large mouth he +felt a pleasant warmth in his body, an amiability toward all his +fellows, and a readiness to respond superficially to every idea +without probing it deeply. Only after emptying a bottle or two did +he feel dimly that the terribly tangled skein of life which previously +had terrified him was not as dreadful as he had thought. He was always +conscious of some aspect of that skein, as with a buzzing in his +head after dinner or supper he chatted or listened to conversation +or read. But under the influence of wine he said to himself: "It +doesn't matter. I'll get it unraveled. I have a solution ready, but +have no time now--I'll think it all out later on!" But the later on +never came. + +In the morning, on an empty stomach, all the old questions +appeared as insoluble and terrible as ever, and Pierre hastily +picked up a book, and if anyone came to see him he was glad. + +Sometimes he remembered how he had heard that soldiers in war when +entrenched under the enemy's fire, if they have nothing to do, try +hard to find some occupation the more easily to bear the danger. To +Pierre all men seemed like those soldiers, seeking refuge from life: +some in ambition, some in cards, some in framing laws, some in +women, some in toys, some in horses, some in politics, some in +sport, some in wine, and some in governmental affairs. "Nothing is +trivial, and nothing is important, it's all the same--only to save +oneself from it as best one can," thought Pierre. "Only not to see it, +that dreadful it!" + + + + + +CHAPTER II + + +At the beginning of winter Prince Nicholas Bolkonski and his +daughter moved to Moscow. At that time enthusiasm for the Emperor +Alexander's regime had weakened and a patriotic and anti-French +tendency prevailed there, and this, together with his past and his +intellect and his originality, at once made Prince Nicholas +Bolkonski an object of particular respect to the Moscovites and the +center of the Moscow opposition to the government. + +The prince had aged very much that year. He showed marked signs of +senility by a tendency to fall asleep, forgetfulness of quite recent +events, remembrance of remote ones, and the childish vanity with which +he accepted the role of head of the Moscow opposition. In spite of +this the old man inspired in all his visitors alike a feeling of +respectful veneration--especially of an evening when he came in to tea +in his old-fashioned coat and powdered wig and, aroused by anyone, +told his abrupt stories of the past, or uttered yet more abrupt and +scathing criticisms of the present. For them all, that old-fashioned +house with its gigantic mirrors, pre-Revolution furniture, powdered +footmen, and the stern shrewd old man (himself a relic of the past +century) with his gentle daughter and the pretty Frenchwoman who +were reverently devoted to him presented a majestic and agreeable +spectacle. But the visitors did not reflect that besides the couple of +hours during which they saw their host, there were also twenty-two +hours in the day during which the private and intimate life of the +house continued. + +Latterly that private life had become very trying for Princess Mary. +There in Moscow she was deprived of her greatest pleasures--talks with +the pilgrims and the solitude which refreshed her at Bald Hills--and +she had none of the advantages and pleasures of city life. She did not +go out into society; everyone knew that her father would not let her +go anywhere without him, and his failing health prevented his going +out himself, so that she was not invited to dinners and evening +parties. She had quite abandoned the hope of getting married. She +saw the coldness and malevolence with which the old prince received +and dismissed the young men, possible suitors, who sometimes +appeared at their house. She had no friends: during this visit to +Moscow she had been disappointed in the two who had been nearest to +her. Mademoiselle Bourienne, with whom she had never been able to be +quite frank, had now become unpleasant to her, and for various reasons +Princess Mary avoided her. Julie, with whom she had corresponded for +the last five years, was in Moscow, but proved to be quite alien to +her when they met. Just then Julie, who by the death of her brothers +had become one of the richest heiresses in Moscow, was in the full +whirl of society pleasures. She was surrounded by young men who, she +fancied, had suddenly learned to appreciate her worth. Julie was at +that stage in the life of a society woman when she feels that her last +chance of marrying has come and that her fate must be decided now or +never. On Thursdays Princess Mary remembered with a mournful smile +that she now had no one to write to, since Julie--whose presence +gave her no pleasure was here and they met every week. Like the old +emigre who declined to marry the lady with whom he had spent his +evenings for years, she regretted Julie's presence and having no one +to write to. In Moscow Princess Mary had no one to talk to, no one +to whom to confide her sorrow, and much sorrow fell to her lot just +then. The time for Prince Andrew's return and marriage was +approaching, but his request to her to prepare his father for it had +not been carried out; in fact, it seemed as if matters were quite +hopeless, for at every mention of the young Countess Rostova the old +prince (who apart from that was usually in a bad temper) lost +control of himself. Another lately added sorrow arose from the lessons +she gave her six year-old nephew. To her consternation she detected in +herself in relation to little Nicholas some symptoms of her father's +irritability. However often she told herself that she must not get +irritable when teaching her nephew, almost every time that, pointer in +hand, she sat down to show him the French alphabet, she so longed to +pour her own knowledge quickly and easily into the child--who was +already afraid that Auntie might at any moment get angry--that at +his slightest inattention she trembled, became flustered and heated, +raised her voice, and sometimes pulled him by the arm and put him in +the corner. Having put him in the corner she would herself begin to +cry over her cruel, evil nature, and little Nicholas, following her +example, would sob, and without permission would leave his corner, +come to her, pull her wet hands from her face, and comfort her. But +what distressed the princess most of all was her father's +irritability, which was always directed against her and had of late +amounted to cruelty. Had he forced her to prostrate herself to the +ground all night, had he beaten her or made her fetch wood or water, +it would never have entered her mind to think her position hard; but +this loving despot--the more cruel because he loved her and for that +reason tormented himself and her--knew how not merely to hurt and +humiliate her deliberately, but to show her that she was always to +blame for everything. Of late he had exhibited a new trait that +tormented Princess Mary more than anything else; this was his +ever-increasing intimacy with Mademoiselle Bourienne. The idea that at +the first moment of receiving the news of his son's intentions had +occurred to him in jest--that if Andrew got married he himself would +marry Bourienne--had evidently pleased him, and latterly he had +persistently, and as it seemed to Princess Mary merely to offend +her, shown special endearments to the companion and expressed his +dissatisfaction with his daughter by demonstrations of love of +Bourienne. + +One day in Moscow in Princess Mary's presence (she thought her +father did it purposely when she was there) the old prince kissed +Mademoiselle Bourienne's hand and, drawing her to him, embraced her +affectionately. Princess Mary flushed and ran out of the room. A few +minutes later Mademoiselle Bourienne came into Princess Mary's room +smiling and making cheerful remarks in her agreeable voice. Princess +Mary hastily wiped away her tears, went resolutely up to +Mademoiselle Bourienne, and evidently unconscious of what she was +doing began shouting in angry haste at the Frenchwoman, her voice +breaking: "It's horrible, vile, inhuman, to take advantage of the +weakness..." She did not finish. "Leave my room," she exclaimed, and +burst into sobs. + +Next day the prince did not say a word to his daughter, but she +noticed that at dinner he gave orders that Mademoiselle Bourienne +should be served first. After dinner, when the footman handed coffee +and from habit began with the princess, the prince suddenly grew +furious, threw his stick at Philip, and instantly gave instructions to +have him conscripted for the army. + +"He doesn't obey... I said it twice... and he doesn't obey! She is +the first person in this house; she's my best friend," cried the +prince. "And if you allow yourself," he screamed in a fury, addressing +Princess Mary for the first time, "to forget yourself again before her +as you dared to do yesterday, I will show you who is master in this +house. Go! Don't let me set eyes on you; beg her pardon!" + +Princess Mary asked Mademoiselle Bourienne's pardon, and also her +father's pardon for herself and for Philip the footman, who had begged +for her intervention. + +At such moments something like a pride of sacrifice gathered in +her soul. And suddenly that father whom she had judged would look +for his spectacles in her presence, fumbling near them and not +seeing them, or would forget something that had just occurred, or take +a false step with his failing legs and turn to see if anyone had +noticed his feebleness, or, worst of all, at dinner when there were no +visitors to excite him would suddenly fall asleep, letting his +napkin drop and his shaking head sink over his plate. "He is old and +feeble, and I dare to condemn him!" she thought at such moments, +with a feeling of revulsion against herself. + + + + + +CHAPTER III + + +In 1811 there was living in Moscow a French doctor--Metivier--who +had rapidly become the fashion. He was enormously tall, handsome, +amiable as Frenchmen are, and was, as all Moscow said, an +extraordinarily clever doctor. He was received in the best houses +not merely as a doctor, but as an equal. + +Prince Nicholas had always ridiculed medicine, but latterly on +Mademoiselle Bourienne's advice had allowed this doctor to visit him +and had grown accustomed to him. Metivier came to see the prince about +twice a week. + +On December 6--St. Nicholas' Day and the prince's name day--all +Moscow came to the prince's front door but he gave orders to admit +no one and to invite to dinner only a small number, a list of whom +he gave to Princess Mary. + +Metivier, who came in the morning with his felicitations, considered +it proper in his quality of doctor de forcer la consigne,* as he +told Princess Mary, and went in to see the prince. It happened that on +that morning of his name day the prince was in one of his worst moods. +He had been going about the house all the morning finding fault with +everyone and pretending not to understand what was said to him and not +to be understood himself. Princess Mary well knew this mood of quiet +absorbed querulousness, which generally culminated in a burst of rage, +and she went about all that morning as though facing a cocked and +loaded gun and awaited the inevitable explosion. Until the doctor's +arrival the morning had passed off safely. After admitting the doctor, +Princess Mary sat down with a book in the drawing room near the door +through which she could hear all that passed in the study. + + +*To force the guard. + + +At first she heard only Metivier's voice, then her father's, then +both voices began speaking at the same time, the door was flung +open, and on the threshold appeared the handsome figure of the +terrified Metivier with his shock of black hair, and the prince in his +dressing gown and fez, his face distorted with fury and the pupils +of his eyes rolled downwards. + +"You don't understand?" shouted the prince, "but I do! French spy, +slave of Buonaparte, spy, get out of my house! Be off, I tell you..." + +Metivier, shrugging his shoulders, went up to Mademoiselle Bourienne +who at the sound of shouting had run in from an adjoining room. + +"The prince is not very well: bile and rush of blood to the head. +Keep calm, I will call again tomorrow," said Metivier; and putting his +fingers to his lips he hastened away. + +Through the study door came the sound of slippered feet and the cry: +"Spies, traitors, traitors everywhere! Not a moment's peace in my +own house!" + +After Metivier's departure the old prince called his daughter in, +and the whole weight of his wrath fell on her. She was to blame that a +spy had been admitted. Had he not told her, yes, told her to make a +list, and not to admit anyone who was not on that list? Then why was +that scoundrel admitted? She was the cause of it all. With her, he +said, he could not have a moment's peace and could not die quietly. + +"No, ma'am! We must part, we must part! Understand that, +understand it! I cannot endure any more," he said, and left the +room. Then, as if afraid she might find some means of consolation, +he returned and trying to appear calm added: "And don't imagine I have +said this in a moment of anger. I am calm. I have thought it over, and +it will be carried out--we must part; so find some place for +yourself...." But he could not restrain himself and with the virulence +of which only one who loves is capable, evidently suffering himself, +he shook his fists at her and screamed: + +"If only some fool would marry her!" Then he slammed the door, +sent for Mademoiselle Bourienne, and subsided into his study. + +At two o'clock the six chosen guests assembled for dinner. + +These guests--the famous Count Rostopchin, Prince Lopukhin with +his nephew, General Chatrov an old war comrade of the prince's, and of +the younger generation Pierre and Boris Drubetskoy--awaited the prince +in the drawing room. + +Boris, who had come to Moscow on leave a few days before, had been +anxious to be presented to Prince Nicholas Bolkonski, and had +contrived to ingratiate himself so well that the old prince in his +case made an exception to the rule of not receiving bachelors in his +house. + +The prince's house did not belong to what is known as fashionable +society, but his little circle--though not much talked about in +town--was one it was more flattering to be received in than any other. +Boris had realized this the week before when the commander in chief in +his presence invited Rostopchin to dinner on St. Nicholas' Day, and +Rostopchin had replied that he could not come: + +"On that day I always go to pay my devotions to the relics of Prince +Nicholas Bolkonski." + +"Oh, yes, yes!" replied the commander in chief. "How is he?..." + +The small group that assembled before dinner in the lofty +old-fashioned drawing room with its old furniture resembled the solemn +gathering of a court of justice. All were silent or talked in low +tones. Prince Nicholas came in serious and taciturn. Princess Mary +seemed even quieter and more diffident than usual. The guests were +reluctant to address her, feeling that she was in no mood for their +conversation. Count Rostopchin alone kept the conversation going, +now relating the latest town news, and now the latest political +gossip. + +Lopukhin and the old general occasionally took part in the +conversation. Prince Bolkonski listened as a presiding judge +receives a report, only now and then, silently or by a brief word, +showing that he took heed of what was being reported to him. The +tone of the conversation was such as indicated that no one approved of +what was being done in the political world. Incidents were related +evidently confirming the opinion that everything was going from bad to +worse, but whether telling a story or giving an opinion the speaker +always stopped, or was stopped, at the point beyond which his +criticism might touch the sovereign himself. + +At dinner the talk turned on the latest political news: Napoleon's +seizure of the Duke of Oldenburg's territory, and the Russian Note, +hostile to Napoleon, which had been sent to all the European courts. + +"Bonaparte treats Europe as a pirate does a captured vessel," said +Count Rostopchin, repeating a phrase he had uttered several times +before. "One only wonders at the long-suffering or blindness of the +crowned heads. Now the Pope's turn has come and Bonaparte doesn't +scruple to depose the head of the Catholic Church--yet all keep +silent! Our sovereign alone has protested against the seizure of the +Duke of Oldenburg's territory, and even..." Count Rostopchin paused, +feeling that he had reached the limit beyond which censure was +impossible. + +"Other territories have been offered in exchange for the Duchy of +Oldenburg," said Prince Bolkonski. "He shifts the Dukes about as I +might move my serfs from Bald Hills to Bogucharovo or my Ryazan +estates." + +"The Duke of Oldenburg bears his misfortunes with admirable strength +of character and resignation," remarked Boris, joining in +respectfully. + +He said this because on his journey from Petersburg he had had the +honor of being presented to the Duke. Prince Bolkonski glanced at +the young man as if about to say something in reply, but changed his +mind, evidently considering him too young. + +"I have read our protests about the Oldenburg affair and was +surprised how badly the Note was worded," remarked Count Rostopchin in +the casual tone of a man dealing with a subject quite familiar to him. + +Pierre looked at Rostopchin with naive astonishment, not +understanding why he should be disturbed by the bad composition of the +Note. + +"Does it matter, Count, how the Note is worded," he asked, "so +long as its substance is forcible?" + +"My dear fellow, with our five hundred thousand troops it should +be easy to have a good style," returned Count Rostopchin. + +Pierre now understood the count's dissatisfaction with the wording +of the Note. + +"One would have thought quill drivers enough had sprung up," +remarked the old prince. "There in Petersburg they are always writing- +not notes only but even new laws. My Andrew there has written a +whole volume of laws for Russia. Nowadays they are always writing!" +and he laughed unnaturally. + +There was a momentary pause in the conversation; the old general +cleared his throat to draw attention. + +"Did you hear of the last event at the review in Petersburg? The +figure cut by the new French ambassador." + +"Eh? Yes, I heard something: he said something awkward in His +Majesty's presence." + +"His Majesty drew attention to the Grenadier division and to the +march past," continued the general, "and it seems the ambassador +took no notice and allowed himself to reply that: 'We in France pay no +attention to such trifles!' The Emperor did not condescend to reply. +At the next review, they say, the Emperor did not once deign to +address him." + +All were silent. On this fact relating to the Emperor personally, it +was impossible to pass any judgment. + +"Impudent fellows!" said the prince. "You know Metivier? I turned +him out of my house this morning. He was here; they admitted him spite +of my request that they should let no one in," he went on, glancing +angrily at his daughter. + +And he narrated his whole conversation with the French doctor and +the reasons that convinced him that Metivier was a spy. Though these +reasons were very insufficient and obscure, no one made any rejoinder. + +After the roast, champagne was served. The guests rose to +congratulate the old prince. Princess Mary, too, went round to him. + +He gave her a cold, angry look and offered her his wrinkled, +clean-shaven cheek to kiss. The whole expression of his face told +her that he had not forgotten the morning's talk, that his decision +remained in force, and only the presence of visitors hindered his +speaking of it to her now. + +When they went into the drawing room where coffee was served, the +old men sat together. + +Prince Nicholas grew more animated and expressed his views on the +impending war. + +He said that our wars with Bonaparte would be disastrous so long +as we sought alliances with the Germans and thrust ourselves into +European affairs, into which we had been drawn by the Peace of Tilsit. +"We ought not to fight either for or against Austria. Our political +interests are all in the East, and in regard to Bonaparte the only +thing is to have an armed frontier and a firm policy, and he will +never dare to cross the Russian frontier, as was the case in 1807!" + +"How can we fight the French, Prince?" said Count Rostopchin. "Can +we arm ourselves against our teachers and divinities? Look at our +youths, look at our ladies! The French are our Gods: Paris is our +Kingdom of Heaven." + +He began speaking louder, evidently to be heard by everyone. + +"French dresses, French ideas, French feelings! There now, you +turned Metivier out by the scruff of his neck because he is a +Frenchman and a scoundrel, but our ladies crawl after him on their +knees. I went to a party last night, and there out of five ladies +three were Roman Catholics and had the Pope's indulgence for doing +woolwork on Sundays. And they themselves sit there nearly naked, +like the signboards at our Public Baths if I may say so. Ah, when +one looks at our young people, Prince, one would like to take Peter +the Great's old cudgel out of the museum and belabor them in the +Russian way till all the nonsense jumps out of them." + +All were silent. The old prince looked at Rostopchin with a smile +and wagged his head approvingly. + +"Well, good-by, your excellency, keep well!" said Rostopchin, +getting up with characteristic briskness and holding out his hand to +the prince. + +"Good-by, my dear fellow.... His words are music, I never tire of +hearing him!" said the old prince, keeping hold of the hand and +offering his cheek to be kissed. + +Following Rostopchin's example the others also rose. + + + + + +CHAPTER IV + + +Princess Mary as she sat listening to the old men's talk and +faultfinding, understood nothing of what she heard; she only +wondered whether the guests had all observed her father's hostile +attitude toward her. She did not even notice the special attentions +and amiabilities shown her during dinner by Boris Drubetskoy, who +was visiting them for the third time already. + +Princess Mary turned with absent-minded questioning look to +Pierre, who hat in hand and with a smile on his face was the last of +the guests to approach her after the old prince had gone out and +they were left alone in the drawing room. + +"May I stay a little longer?" he said, letting his stout body sink +into an armchair beside her. + +"Oh yes," she answered. "You noticed nothing?" her look asked. + +Pierre was in an agreeable after-dinner mood. He looked straight +before him and smiled quietly. + +"Have you known that young man long, Princess?" he asked. + +"Who?" + +"Drubetskoy." + +"No, not long..." + +"Do you like him?" + +"Yes, he is an agreeable young man.... Why do you ask me that?" said +Princess Mary, still thinking of that morning's conversation with +her father. + +"Because I have noticed that when a young man comes on leave from +Petersburg to Moscow it is usually with the object of marrying an +heiress." + +"You have observed that?" said Princess Mary. + +"Yes," returned Pierre with a smile, "and this young man now manages +matters so that where there is a wealthy heiress there he is too. I +can read him like a book. At present he is hesitating whom to lay +siege to--you or Mademoiselle Julie Karagina. He is very attentive +to her." + +"He visits them?" + +"Yes, very often. And do you know the new way of courting?" said +Pierre with an amused smile, evidently in that cheerful mood of good +humored raillery for which he so often reproached himself in his +diary. + +"No," replied Princess Mary. + +"To please Moscow girls nowadays one has to be melancholy. He is +very melancholy with Mademoiselle Karagina," said Pierre. + +"Really?" asked Princess Mary, looking into Pierre's kindly face and +still thinking of her own sorrow. "It would be a relief," thought she, +"if I ventured to confide what I am feeling to someone. I should +like to tell everything to Pierre. He is kind and generous. It would +be a relief. He would give me advice." + +"Would you marry him?" + +"Oh, my God, Count, there are moments when I would marry anybody!" +she cried suddenly to her own surprise and with tears in her voice. +"Ah, how bitter it is to love someone near to you and to feel that..." +she went on in a trembling voice, "that you can do nothing for him but +grieve him, and to know that you cannot alter this. Then there is only +one thing left--to go away, but where could I go?" + +"What is wrong? What is it, Princess?" + +But without finishing what she was saying, Princess Mary burst +into tears. + +"I don't know what is the matter with me today. Don't take any +notice--forget what I have said!" + +Pierre's gaiety vanished completely. He anxiously questioned the +princess, asked her to speak out fully and confide her grief to him; +but she only repeated that she begged him to forget what she had said, +that she did not remember what she had said, and that she had no +trouble except the one he knew of--that Prince Andrew's marriage +threatened to cause a rupture between father and son. + +"Have you any news of the Rostovs?" she asked, to change the +subject. "I was told they are coming soon. I am also expecting +Andrew any day. I should like them to meet here." + +"And how does he now regard the matter?" asked Pierre, referring +to the old prince. + +Princess Mary shook her head. + +"What is to be done? In a few months the year will be up. The +thing is impossible. I only wish I could spare my brother the first +moments. I wish they would come sooner. I hope to be friends with her. +You have known them a long time," said Princess Mary. "Tell me +honestly the whole truth: what sort of girl is she, and what do you +think of her?--The real truth, because you know Andrew is risking so +much doing this against his father's will that I should like to +know..." + +An undefined instinct told Pierre that these explanations, and +repeated requests to be told the whole truth, expressed ill-will on +the princess' part toward her future sister-in-law and a wish that +he should disapprove of Andrew's choice; but in reply he said what +he felt rather than what he thought. + +"I don't know how to answer your question," he said, blushing +without knowing why. "I really don't know what sort of girl she is; +I can't analyze her at all. She is enchanting, but what makes her so I +don't know. That is all one can say about her." + +Princess Mary sighed, and the expression on her face said: "Yes, +that's what I expected and feared." + +"Is she clever?" she asked. + +Pierre considered. + +"I think not," he said, "and yet--yes. She does not deign to be +clever.... Oh no, she is simply enchanting, and that is all." + +Princess Mary again shook her head disapprovingly. + +"Ah, I so long to like her! Tell her so if you see her before I do." + +"I hear they are expected very soon," said Pierre. + +Princess Mary told Pierre of her plan to become intimate with her +future sister-in-law as soon as the Rostovs arrived and to try to +accustom the old prince to her. + + + + + +CHAPTER V + + +Boris had not succeeded in making a wealthy match in Petersburg, +so with the same object in view he came to Moscow. There he wavered +between the two richest heiresses, Julie and Princess Mary. Though +Princess Mary despite her plainness seemed to him more attractive than +Julie, he, without knowing why, felt awkward about paying court to +her. When they had last met on the old prince's name day, she had +answered at random all his attempts to talk sentimentally, evidently +not listening to what he was saying. + +Julie on the contrary accepted his attentions readily, though in a +manner peculiar to herself. + +She was twenty-seven. After the death of her brothers she had become +very wealthy. She was by now decidedly plain, but thought herself +not merely as good-looking as before but even far more attractive. She +was confirmed in this delusion by the fact that she had become a +very wealthy heiress and also by the fact that the older she grew +the less dangerous she became to men, and the more freely they could +associate with her and avail themselves of her suppers, soirees, and +the animated company that assembled at her house, without incurring +any obligation. A man who would have been afraid ten years before of +going every day to the house when there was a girl of seventeen there, +for fear of compromising her and committing himself, would now go +boldly every day and treat her not as a marriageable girl but as a +sexless acquaintance. + +That winter the Karagins' house was the most agreeable and +hospitable in Moscow. In addition to the formal evening and dinner +parties, a large company, chiefly of men, gathered there every day, +supping at midnight and staying till three in the morning. Julie never +missed a ball, a promenade, or a play. Her dresses were always of +the latest fashion. But in spite of that she seemed to be +disillusioned about everything and told everyone that she did not +believe either in friendship or in love, or any of the joys of life, +and expected peace only "yonder." She adopted the tone of one who +has suffered a great disappointment, like a girl who has either lost +the man she loved or been cruelly deceived by him. Though nothing of +the kind had happened to her she was regarded in that light, and had +even herself come to believe that she had suffered much in life. +This melancholy, which did not prevent her amusing herself, did not +hinder the young people who came to her house from passing the time +pleasantly. Every visitor who came to the house paid his tribute to +the melancholy mood of the hostess, and then amused himself with +society gossip, dancing, intellectual games, and bouts rimes, which +were in vogue at the Karagins'. Only a few of these young men, among +them Boris, entered more deeply into Julie's melancholy, and with +these she had prolonged conversations in private on the vanity of +all worldly things, and to them she showed her albums filled with +mournful sketches, maxims, and verses. + +To Boris, Julie was particularly gracious: she regretted his early +disillusionment with life, offered him such consolation of +friendship as she who had herself suffered so much could render, and +showed him her album. Boris sketched two trees in the album and wrote: +"Rustic trees, your dark branches shed gloom and melancholy upon me." + +On another page he drew a tomb, and wrote: + + La mort est secourable et la mort est tranquille. + Ah! contre les douleurs il n'y a pas d'autre asile.* + + +*Death gives relief and death is peaceful. + + Ah! from suffering there is no other refuge. + +Julia said this was charming + +"There is something so enchanting in the smile of melancholy," she +said to Boris, repeating word for word a passage she had copied from a +book. "It is a ray of light in the darkness, a shade between sadness +and despair, showing the possibility of consolation." + +In reply Boris wrote these lines: + + Aliment de poison d'une ame trop sensible, + Toi, sans qui le bonheur me serait impossible, + Tendre melancholie, ah, viens me consoler, + Viens calmer les tourments de ma sombre retraite, + Et mele une douceur secrete + A ces pleurs que je sens couler.* + + +*Poisonous nourishment of a too sensitive soul, + + Thou, without whom happiness would for me be impossible, + + Tender melancholy, ah, come to console me, + + Come to calm the torments of my gloomy retreat, + + And mingle a secret sweetness + + With these tears that I feel to be flowing. + + +For Boris, Julie played most doleful nocturnes on her harp. Boris +read Poor Liza aloud to her, and more than once interrupted the +reading because of the emotions that choked him. Meeting at large +gatherings Julie and Boris looked on one another as the only souls who +understood one another in a world of indifferent people. + +Anna Mikhaylovna, who often visited the Karagins, while playing +cards with the mother made careful inquiries as to Julie's dowry +(she was to have two estates in Penza and the Nizhegorod forests). +Anna Mikhaylovna regarded the refined sadness that united her son to +the wealthy Julie with emotion, and resignation to the Divine will. + +"You are always charming and melancholy, my dear Julie," she said to +the daughter. "Boris says his soul finds repose at your house. He +has suffered so many disappointments and is so sensitive," said she to +the mother. "Ah, my dear, I can't tell you how fond I have grown of +Julie latterly," she said to her son. "But who could help loving +her? She is an angelic being! Ah, Boris, Boris!"--she paused. "And how +I pity her mother," she went on; "today she showed me her accounts and +letters from Penza (they have enormous estates there), and she, poor +thing, has no one to help her, and they do cheat her so!" + +Boris smiled almost imperceptibly while listening to his mother. +He laughed blandly at her naive diplomacy but listened to what she had +to say, and sometimes questioned her carefully about the Penza and +Nizhegorod estates. + +Julie had long been expecting a proposal from her melancholy +adorer and was ready to accept it; but some secret feeling of +repulsion for her, for her passionate desire to get married, for her +artificiality, and a feeling of horror at renouncing the possibility +of real love still restrained Boris. His leave was expiring. He +spent every day and whole days at the Karagins', and every day on +thinking the matter over told himself that he would propose +tomorrow. But in Julie's presence, looking at her red face and chin +(nearly always powdered), her moist eyes, and her expression of +continual readiness to pass at once from melancholy to an unnatural +rapture of married bliss, Boris could not utter the decisive words, +though in imagination he had long regarded himself as the possessor of +those Penza and Nizhegorod estates and had apportioned the use of +the income from them. Julie saw Boris' indecision, and sometimes the +thought occurred to her that she was repulsive to him, but her +feminine self-deception immediately supplied her with consolation, and +she told herself that he was only shy from love. Her melancholy, +however, began to turn to irritability, and not long before Boris' +departure she formed a definite plan of action. Just as Boris' leave +of absence was expiring, Anatole Kuragin made his appearance in +Moscow, and of course in the Karagins' drawing room, and Julie, +suddenly abandoning her melancholy, became cheerful and very attentive +to Kuragin. + +"My dear," said Anna Mikhaylovna to her son, "I know from a reliable +source that Prince Vasili has sent his son to Moscow to get him +married to Julie. I am so fond of Julie that I should be sorry for +her. What do you think of it, my dear?" + +The idea of being made a fool of and of having thrown away that +whole month of arduous melancholy service to Julie, and of seeing +all the revenue from the Penza estates which he had already mentally +apportioned and put to proper use fall into the hands of another, +and especially into the hands of that idiot Anatole, pained Boris. +He drove to the Karagins' with the firm intention of proposing. +Julie met him in a gay, careless manner, spoke casually of how she had +enjoyed yesterday's ball, and asked when he was leaving. Though +Boris had come intentionally to speak of his love and therefore +meant to be tender, he began speaking irritably of feminine +inconstancy, of how easily women can turn from sadness to joy, and how +their moods depend solely on who happens to be paying court to them. +Julie was offended and replied that it was true that a woman needs +variety, and the same thing over and over again would weary anyone. + +"Then I should advise you..." Boris began, wishing to sting her; but +at that instant the galling thought occurred to him that he might have +to leave Moscow without having accomplished his aim, and have vainly +wasted his efforts--which was a thing he never allowed to happen. + +He checked himself in the middle of the sentence, lowered his eyes +to avoid seeing her unpleasantly irritated and irresolute face, and +said: + +"I did not come here at all to quarrel with you. On the contrary..." + +He glanced at her to make sure that he might go on. Her irritability +had suddenly quite vanished, and her anxious, imploring eyes were +fixed on him with greedy expectation. "I can always arrange so as +not to see her often," thought Boris. "The affair has been begun and +must be finished!" He blushed hotly, raised his eyes to hers, and +said: + +"You know my feelings for you!" + +There was no need to say more: Julie's face shone with triumph and +self-satisfaction; but she forced Boris to say all that is said on +such occasions--that he loved her and had never loved any other +woman more than her. She knew that for the Penza estates and +Nizhegorod forests she could demand this, and she received what she +demanded. + +The affianced couple, no longer alluding to trees that shed gloom +and melancholy upon them, planned the arrangements of a splendid house +in Petersburg, paid calls, and prepared everything for a brilliant +wedding. + + + + + +CHAPTER VI + + +At the end of January old Count Rostov went to Moscow with Natasha +and Sonya. The countess was still unwell and unable to travel but it +was impossible to wait for her recovery. Prince Andrew was expected in +Moscow any day, the trousseau had to be ordered and the estate near +Moscow had to be sold, besides which the opportunity of presenting his +future daughter-in-law to old Prince Bolkonski while he was in +Moscow could not be missed. The Rostovs' Moscow house had not been +heated that winter and, as they had come only for a short time and the +countess was not with them, the count decided to stay with Marya +Dmitrievna Akhrosimova, who had long been pressing her hospitality +on them. + +Late one evening the Rostovs' four sleighs drove into Marya +Dmitrievna's courtyard in the old Konyusheny street. Marya +Dmitrievna lived alone. She had already married off her daughter, +and her sons were all in the service. + +She held herself as erect, told everyone her opinion as candidly, +loudly, and bluntly as ever, and her whole bearing seemed a reproach +to others for any weakness, passion, or temptation--the possibility of +which she did not admit. From early in the morning, wearing a dressing +jacket, she attended to her household affairs, and then she drove out: +on holy days to church and after the service to jails and prisons on +affairs of which she never spoke to anyone. On ordinary days, after +dressing, she received petitioners of various classes, of whom there +were always some. Then she had dinner, a substantial and appetizing +meal at which there were always three or four guests; after dinner she +played a game of boston, and at night she had the newspapers or a +new book read to her while she knitted. She rarely made an exception +and went out to pay visits, and then only to the most important +persons in the town. + +She had not yet gone to bed when the Rostovs arrived and the +pulley of the hall door squeaked from the cold as it let in the +Rostovs and their servants. Marya Dmitrievna, with her spectacles +hanging down on her nose and her head flung back, stood in the hall +doorway looking with a stern, grim face at the new arrivals. One might +have thought she was angry with the travelers and would immediately +turn them out, had she not at the same time been giving careful +instructions to the servants for the accommodation of the visitors and +their belongings. + +"The count's things? Bring them here," she said, pointing to the +portmanteaus and not greeting anyone. "The young ladies'? There to the +left. Now what are you dawdling for?" she cried to the maids. "Get the +samovar ready!... You've grown plumper and prettier," she remarked, +drawing Natasha (whose cheeks were glowing from the cold) to her by +the hood. "Foo! You are cold! Now take off your things, quick!" she +shouted to the count who was going to kiss her hand. "You're half +frozen, I'm sure! Bring some rum for tea!... Bonjour, Sonya dear!" she +added, turning to Sonya and indicating by this French greeting her +slightly contemptuous though affectionate attitude toward her. + +When they came in to tea, having taken off their outdoor things +and tidied themselves up after their journey, Marya Dmitrievna +kissed them all in due order. + +"I'm heartily glad you have come and are staying with me. It was +high time," she said, giving Natasha a significant look. "The old +man is here and his son's expected any day. You'll have to make his +acquaintance. But we'll speak of that later on," she added, glancing at +Sonya with a look that showed she did not want to speak of it in her +presence. "Now listen," she said to the count. "What do you want +tomorrow? Whom will you send for? Shinshin?" she crooked one of her +fingers. "The sniveling Anna Mikhaylovna? That's two. She's here +with her son. The son is getting married! Then Bezukhov, eh? He is +here too, with his wife. He ran away from her and she came galloping +after him. He dined with me on Wednesday. As for them"--and she +pointed to the girls--"tomorrow I'll take them first to the Iberian +shrine of the Mother of God, and then we'll drive to the +Super-Rogue's. I suppose you'll have everything new. Don't judge by +me: sleeves nowadays are this size! The other day young Princess Irina +Vasilevna came to see me; she was an awful sight--looked as if she had +put two barrels on her arms. You know not a day passes now without +some new fashion.... And what have you to do yourself?" she asked +the count sternly. + +"One thing has come on top of another: her rags to buy, and now a +purchaser has turned up for the Moscow estate and for the house. If +you will be so kind, I'll fix a time and go down to the estate just +for a day, and leave my lassies with you." + +"All right. All right. They'll be safe with me, as safe as in +Chancery! I'll take them where they must go, scold them a bit, and pet +them a bit," said Marya Dmitrievna, touching her goddaughter and +favorite, Natasha, on the cheek with her large hand. + +Next morning Marya Dmitrievna took the young ladies to the Iberian +shrine of the Mother of God and to Madame Suppert-Roguet, who was so +afraid of Marya Dmitrievna that she always let her have costumes at +a loss merely to get rid of her. Marya Dmitrievna ordered almost the +whole trousseau. When they got home she turned everybody out of the +room except Nataisha, and then called her pet to her armchair. + +"Well, now we'll talk. I congratulate you on your betrothed. +You've hooked a fine fellow! I am glad for your sake and I've known +him since he was so high." She held her hand a couple of feet from the +ground. Natasha blushed happily. "I like him and all his family. Now +listen! You know that old Prince Nicholas much dislikes his son's +marrying. The old fellow's crotchety! Of course Prince Andrew is not a +child and can shift without him, but it's not nice to enter a family +against a father's will. One wants to do it peacefully and lovingly. +You're a clever girl and you'll know how to manage. Be kind, and use +your wits. Then all will be well." + +Natasha remained silent, from shyness Marya Dmitrievna supposed, but +really because she disliked anyone interfering in what touched her +love of Prince Andrew, which seemed to her so apart from all human +affairs that no one could understand it. She loved and knew Prince +Andrew, he loved her only, and was to come one of these days and +take her. She wanted nothing more. + +"You see I have known him a long time and am also fond of Mary, your +future sister-in-law. 'Husbands' sisters bring up blisters,' but +this one wouldn't hurt a fly. She has asked me to bring you two +together. Tomorrow you'll go with your father to see her. Be very nice +and affectionate to her: you're younger than she. When he comes, he'll +find you already know his sister and father and are liked by them. +Am I right or not? Won't that be best?" + +"Yes, it will," Natasha answered reluctantly. + + + + + +CHAPTER VII + + +Next day, by Marya Dmitrievna's advice, Count Rostov took Natasha to +call on Prince Nicholas Bolkonski. The count did not set out +cheerfully on this visit, at heart he felt afraid. He well +remembered the last interview he had had with the old prince at the +time of the enrollment, when in reply to an invitation to dinner he +had had to listen to an angry reprimand for not having provided his +full quota of men. Natasha, on the other hand, having put on her +best gown, was in the highest spirits. "They can't help liking me," +she thought. "Everybody always has liked me, and I am so willing to do +anything they wish, so ready to be fond of him--for being his +father--and of her--for being his sister--that there is no reason +for them not to like me..." + +They drove up to the gloomy old house on the Vozdvizhenka and +entered the vestibule. + +"Well, the Lord have mercy on us!" said the count, half in jest, +half in earnest; but Natasha noticed that her father was flurried on +entering the anteroom and inquired timidly and softly whether the +prince and princess were at home. + +When they had been announced a perturbation was noticeable among the +servants. The footman who had gone to announce them was stopped by +another in the large hall and they whispered to one another. Then a +maidservant ran into the hall and hurriedly said something, mentioning +the princess. At last an old, cross looking footman came and announced +to the Rostovs that the prince was not receiving, but that the +princess begged them to walk up. The first person who came to meet the +visitors was Mademoiselle Bourienne. She greeted the father and +daughter with special politeness and showed them to the princess' +room. The princess, looking excited and nervous, her face flushed in +patches, ran in to meet the visitors, treading heavily, and vainly +trying to appear cordial and at ease. From the first glance Princess +Mary did not like Natasha. She thought her too fashionably dressed, +frivolously gay and vain. She did not at all realize that before +having seen her future sister-in-law she was prejudiced against her by +involuntary envy of her beauty, youth, and happiness, as well as by +jealousy of her brother's love for her. Apart from this insuperable +antipathy to her, Princess Mary was agitated just then because on +the Rostovs' being announced, the old prince had shouted that he did +not wish to see them, that Princess Mary might do so if she chose, but +they were not to be admitted to him. She had decided to receive +them, but feared lest the prince might at any moment indulge in some +freak, as he seemed much upset by the Rostovs' visit. + +"There, my dear princess, I've brought you my songstress," said +the count, bowing and looking round uneasily as if afraid the old +prince might appear. "I am so glad you should get to know one +another... very sorry the prince is still ailing," and after a few +more commonplace remarks he rose. "If you'll allow me to leave my +Natasha in your hands for a quarter of an hour, Princess, I'll drive +round to see Anna Semenovna, it's quite near in the Dogs' Square, +and then I'll come back for her." + +The count had devised this diplomatic ruse (as he afterwards told +his daughter) to give the future sisters-in-law an opportunity to talk +to one another freely, but another motive was to avoid the danger of +encountering the old prince, of whom he was afraid. He did not mention +this to his daughter, but Natasha noticed her father's nervousness and +anxiety and felt mortified by it. She blushed for him, grew still +angrier at having blushed, and looked at the princess with a bold +and defiant expression which said that she was not afraid of +anybody. The princess told the count that she would be delighted, +and only begged him to stay longer at Anna Semenovna's, and he +departed. + +Despite the uneasy glances thrown at her by Princess Mary--who +wished to have a tete-a-tete with Natasha--Mademoiselle Bourienne +remained in the room and persistently talked about Moscow amusements +and theaters. Natasha felt offended by the hesitation she had +noticed in the anteroom, by her father's nervousness, and by the +unnatural manner of the princess who--she thought--was making a +favor of receiving her, and so everything displeased her. She did +not like Princess Mary, whom she thought very plain, affected, and +dry. Natasha suddenly shrank into herself and involuntarily assumed an +offhand air which alienated Princess Mary still more. After five +minutes of irksome, constrained conversation, they heard the sound +of slippered feet rapidly approaching. Princess Mary looked +frightened. + +The door opened and the old prince, in a dress, ing gown and a white +nightcap, came in. + +"Ah, madam!" he began. "Madam, Countess... Countess Rostova, if I am +not mistaken... I beg you to excuse me, to excuse me... I did not +know, madam. God is my witness, I did not know you had honored us with +a visit, and I came in such a costume only to see my daughter. I beg +you to excuse me... God is my witness, I didn't know-" he repeated, +stressing the word "God" so unnaturally and so unpleasantly that +Princess Mary stood with downcast eyes not daring to look either at +her father or at Natasha. + +Nor did the latter, having risen and curtsied, know what to do. +Mademoiselle Bourienne alone smiled agreeably. + +"I beg you to excuse me, excuse me! God is my witness, I did not +know," muttered the old man, and after looking Natasha over from +head to foot he went out. + +Mademoiselle Bourienne was the first to recover herself after this +apparition and began speaking about the prince's indisposition. +Natasha and Princess Mary looked at one another in silence, and the +longer they did so without saying what they wanted to say, the greater +grew their antipathy to one another. + +When the count returned, Natasha was impolitely pleased and hastened +to get away: at that moment she hated the stiff, elderly princess, who +could place her in such an embarrassing position and had spent half an +hour with her without once mentioning Prince Andrew. "I couldn't begin +talking about him in the presence of that Frenchwoman," thought +Natasha. The same thought was meanwhile tormenting Princess Mary. +She knew what she ought to have said to Natasha, but she had been +unable to say it because Mademoiselle Bourienne was in the way, and +because, without knowing why, she felt it very difficult to speak of +the marriage. When the count was already leaving the room, Princess +Mary went up hurriedly to Natasha, took her by the hand, and said with +a deep sigh: + +"Wait, I must..." + +Natasha glanced at her ironically without knowing why. + +"Dear Natalie," said Princess Mary, "I want you to know that I am +glad my brother has found happiness...." + +She paused, feeling that she was not telling the truth. Natasha +noticed this and guessed its reason. + +"I think, Princess, it is not convenient to speak of that now," +she said with external dignity and coldness, though she felt the tears +choking her. + +"What have I said and what have I done?" thought she, as soon as she +was out of the room. + +They waited a long time for Natasha to come to dinner that day. +She sat in her room crying like a child, blowing her nose and sobbing. +Sonya stood beside her, kissing her hair. + +"Natasha, what is it about?" she asked. "What do they matter to you? +It will all pass, Natasha." + +"But if you only knew how offensive it was... as if I..." + +"Don't talk about it, Natasha. It wasn't your fault so why should +you mind? Kiss me," said Sonya. + +Natasha raised her head and, kissing her friend on the lips, pressed +her wet face against her. + +"I can't tell you, I don't know. No one's to blame," said Natasha- +"It's my fault. But it all hurts terribly. Oh, why doesn't he +come?..." + +She came in to dinner with red eyes. Marya Dmitrievna, who knew +how the prince had received the Rostovs, pretended not to notice how +upset Natasha was and jested resolutely and loudly at table with the +count and the other guests. + + + + + +CHAPTER VIII + + +That evening the Rostovs went to the Opera, for which Marya +Dmitrievna had taken a box. + +Natasha did not want to go, but could not refuse Marya +Dmitrievna's kind offer which was intended expressly for her. When she +came ready dressed into the ballroom to await her father, and +looking in the large mirror there saw that she was pretty, very +pretty, she felt even more sad, but it was a sweet, tender sadness. + +"O God, if he were here now I would not behave as I did then, but +differently. I would not be silly and afraid of things, I would simply +embrace him, cling to him, and make him look at me with those +searching inquiring eyes with which he has so often looked at me, +and then I would make him laugh as he used to laugh. And his eyes--how +I see those eyes!" thought Natasha. "And what do his father and sister +matter to me? I love him alone, him, him, with that face and those +eyes, with his smile, manly and yet childlike.... No, I had better not +think of him; not think of him but forget him, quite forget him for +the present. I can't bear this waiting and I shall cry in a minute!" +and she turned away from the glass, making an effort not to cry. +"And how can Sonya love Nicholas so calmly and quietly and wait so +long and so patiently?" thought she, looking at Sonya, who also came +in quite ready, with a fan in her hand. "No, she's altogether +different. I can't!" + +Natasha at that moment felt so softened and tender that it was not +enough for her to love and know she was beloved, she wanted now, at +once, to embrace the man she loved, to speak and hear from him words +of love such as filled her heart. While she sat in the carriage beside +her father, pensively watching the lights of the street lamps +flickering on the frozen window, she felt still sadder and more in +love, and forgot where she was going and with whom. Having fallen into +the line of carriages, the Rostovs' carriage drove up to the +theater, its wheels squeaking over the snow. Natasha and Sonya, +holding up their dresses, jumped out quickly. The count got out helped +by the footmen, and, passing among men and women who were entering and +the program sellers, they all three went along the corridor to the +first row of boxes. Through the closed doors the music was already +audible. + +"Natasha, your hair!..." whispered Sonya. + +An attendant deferentially and quickly slipped before the ladies and +opened the door of their box. The music sounded louder and through the +door rows of brightly lit boxes in which ladies sat with bare arms and +shoulders, and noisy stalls brilliant with uniforms, glittered +before their eyes. A lady entering the next box shot a glance of +feminine envy at Natasha. The curtain had not yet risen and the +overture was being played. Natasha, smoothing her gown, went in with +Sonya and sat down, scanning the brilliant tiers of boxes opposite. +A sensation she had not experienced for a long time--that of +hundreds of eyes looking at her bare arms and neck--suddenly +affected her both agreeably and disagreeably and called up a whole +crowd of memories, desires and emotions associated with that feeling. + +The two remarkably pretty girls, Natasha and Sonya, with Count +Rostov who had not been seen in Moscow for a long time, attracted +general attention. Moreover, everybody knew vaguely of Natasha's +engagement to Prince Andrew, and knew that the Rostovs had lived in +the country ever since, and all looked with curiosity at a fiancee who +was making one of the best matches in Russia. + +Natasha's looks, as everyone told her, had improved in the +country, and that evening thanks to her agitation she was particularly +pretty. She struck those who saw her by her fullness of life and +beauty, combined with her indifference to everything about her. Her +black eyes looked at the crowd without seeking anyone, and her +delicate arm, bare to above the elbow, lay on the velvet edge of the +box, while, evidently unconsciously, she opened and closed her hand in +time to the music, crumpling her program. "Look, there's Alenina," +said Sonya, "with her mother, isn't it?" + +"Dear me, Michael Kirilovich has grown still stouter!" remarked +the count. + +"Look at our Anna Mikhaylovna--what a headdress she has on!" + +"The Karagins, Julie--and Boris with them. One can see at once +that they're engaged...." + +"Drubetskoy has proposed?" + +"Oh yes, I heard it today," said Shinshin, coming into the +Rostovs' box. + +Natasha looked in the direction in which her father's eyes were +turned and saw Julie sitting beside her mother with a happy look on +her face and a string of pearls round her thick red neck--which +Natasha knew was covered with powder. Behind them, wearing a smile and +leaning over with an ear to Julie's mouth, was Boris' handsome +smoothly brushed head. He looked the Rostovs from under his brows +and said something, smiling, to his betrothed. + +"They are talking about us, about me and him!" thought Natasha. "And +he no doubt is calming her jealousy of me. They needn't trouble +themselves! If only they knew how little I am concerned about any of +them." + +Behind them sat Anna Mikhaylovna wearing a green headdress and +with a happy look of resignation to the will of God on her face. Their +box was pervaded by that atmosphere of an affianced couple which +Natasha knew so well and liked so much. She turned away and suddenly +remembered all that had been so humiliating in her morning's visit. + +"What right has he not to wish to receive me into his family? Oh, +better not think of it--not till he comes back!" she told herself, and +began looking at the faces, some strange and some familiar, in the +stalls. In the front, in the very center, leaning back against the +orchestra rail, stood Dolokhov in a Persian dress, his curly hair +brushed up into a huge shock. He stood in full view of the audience, +well aware that he was attracting everyone's attention, yet as much at +ease as though he were in his own room. Around him thronged Moscow's +most brilliant young men, whom he evidently dominated. + +The count, laughing, nudged the blushing Sonya and pointed to her +former adorer. + +"Do you recognize him?" said he. "And where has he sprung from?" +he asked, turning to Shinshin. "Didn't he vanish somewhere?" + +"He did," replied Shinshin. "He was in the Caucasus and ran away +from there. They say he has been acting as minister to some ruling +prince in Persia, where he killed the Shah's brother. Now all the +Moscow ladies are mad about him! It's 'Dolokhov the Persian' that does +it! We never hear a word but Dolokhov is mentioned. They swear by him, +they offer him to you as they would a dish of choice sterlet. Dolokhov +and Anatole Kuragin have turned all our ladies' heads." + +A tall, beautiful woman with a mass of plaited hair and much exposed +plump white shoulders and neck, round which she wore a double string +of large pearls, entered the adjoining box rustling her heavy silk +dress and took a long time settling into her place. + +Natasha involuntarily gazed at that neck, those shoulders, and +pearls and coiffure, and admired the beauty of the shoulders and the +pearls. While Natasha was fixing her gaze on her for the second time +the lady looked round and, meeting the count's eyes, nodded to him and +smiled. She was the Countess Bezukhova, Pierre's wife, and the +count, who knew everyone in society, leaned over and spoke to her. + +"Have you been here long, Countess?" he inquired. "I'll call, I'll +call to kiss your hand. I'm here on business and have brought my girls +with me. They say Semenova acts marvelously. Count Pierre never used +to forget us. Is he here?" + +"Yes, he meant to look in," answered Helene, and glanced attentively +at Natasha. + +Count Rostov resumed his seat. + +"Handsome, isn't she?" he whispered to Natasha. + +"Wonderful!" answered Natasha. "She's a woman one could easily +fall in love with." + +Just then the last chords of the overture were heard and the +conductor tapped with his stick. Some latecomers took their seats in +the stalls, and the curtain rose. + +As soon as it rose everyone in the boxes and stalls became silent, +and all the men, old and young, in uniform and evening dress, and +all the women with gems on their bare flesh, turned their whole +attention with eager curiosity to the stage. Natasha too began to look +at it. + + + + + +CHAPTER IX + + +The floor of the stage consisted of smooth boards, at the sides +was some painted cardboard representing trees, and at the back was a +cloth stretched over boards. In the center of the stage sat some girls +in red bodices and white skirts. One very fat girl in a white silk +dress sat apart on a low bench, to the back of which a piece of +green cardboard was glued. They all sang something. When they had +finished their song the girl in white went up to the prompter's box +and a man with tight silk trousers over his stout legs, and holding +a plume and a dagger, went up to her and began singing, waving his +arms about. + +First the man in the tight trousers sang alone, then she sang, +then they both paused while the orchestra played and the man +fingered the hand of the girl in white, obviously awaiting the beat to +start singing with her. They sang together and everyone in the theater +began clapping and shouting, while the man and woman on the stage--who +represented lovers--began smiling, spreading out their arms, and +bowing. + +After her life in the country, and in her present serious mood, +all this seemed grotesque and amazing to Natasha. She could not follow +the opera nor even listen to the music; she saw only the painted +cardboard and the queerly dressed men and women who moved, spoke, +and sang so strangely in that brilliant light. She knew what it was +all meant to represent, but it was so pretentiously false and +unnatural that she first felt ashamed for the actors and then amused +at them. She looked at the faces of the audience, seeking in them +the same sense of ridicule and perplexity she herself experienced, but +they all seemed attentive to what was happening on the stage, and +expressed delight which to Natasha seemed feigned. "I suppose it has +to be like this!" she thought. She kept looking round in turn at the +rows of pomaded heads in the stalls and then at the seminude women +in the boxes, especially at Helene in the next box, who--apparently +quite unclothed--sat with a quiet tranquil smile, not taking her +eyes off the stage. And feeling the bright light that flooded the +whole place and the warm air heated by the crowd, Natasha little by +little began to pass into a state of intoxication she had not +experienced for a long while. She did not realize who and where she +was, nor what was going on before her. As she looked and thought, +the strangest fancies unexpectedly and disconnectedly passed through +her mind: the idea occurred to her of jumping onto the edge of the box +and singing the air the actress was singing, then she wished to +touch with her fan an old gentleman sitting not far from her, then +to lean over to Helene and tickle her. + +At a moment when all was quiet before the commencement of a song, +a door leading to the stalls on the side nearest the Rostovs' box +creaked, and the steps of a belated arrival were heard. "There's +Kuragin!" whispered Shinshin. Countess Bezukhova turned smiling to the +newcomer, and Natasha, following the direction of that look, saw an +exceptionally handsome adjutant approaching their box with a +self-assured yet courteous bearing. This was Anatole Kuragin whom +she had seen and noticed long ago at the ball in Petersburg. He was +now in an adjutant's uniform with one epaulet and a shoulder knot. +He moved with a restrained swagger which would have been ridiculous +had he not been so good-looking and had his handsome face not worn +such an expression of good-humored complacency and gaiety. Though +the performance was proceeding, he walked deliberately down the +carpeted gangway, his sword and spurs slightly jingling and his +handsome perfumed head held high. Having looked at Natasha he +approached his sister, laid his well gloved hand on the edge of her +box, nodded to her, and leaning forward asked a question, with a +motion toward Natasha. + +"Mais charmante!" said he, evidently referring to Natasha, who did +not exactly hear his words but understood them from the movement of +his lips. Then he took his place in the first row of the stalls and +sat down beside Dolokhov, nudging with his elbow in a friendly and +offhand way that Dolokhov whom others treated so fawningly. He +winked at him gaily, smiled, and rested his foot against the orchestra +screen. + +"How like the brother is to the sister," remarked the count. "And +how handsome they both are!" + +Shinshin, lowering his voice, began to tell the count of some +intrigue of Kuragin's in Moscow, and Natasha tried to overhear it just +because he had said she was "charmante." + +The first act was over. In the stalls everyone began moving about, +going out and coming in. + +Boris came to the Rostovs' box, received their congratulations +very simply, and raising his eyebrows with an absent-minded smile +conveyed to Natasha and Sonya his fiancee's invitation to her wedding, +and went away. Natasha with a gay, coquettish smile talked to him, and +congratulated on his approaching wedding that same Boris with whom she +had formerly been in love. In the state of intoxication she was in, +everything seemed simple and natural. + +The scantily clad Helene smiled at everyone in the same way, and +Natasha gave Boris a similar smile. + +Helene's box was filled and surrounded from the stalls by the most +distinguished and intellectual men, who seemed to vie with one another +in their wish to let everyone see that they knew her. + +During the whole of that entr'acte Kuragin stood with Dolokhov in +front of the orchestra partition, looking at the Rostovs' box. Natasha +knew he was talking about her and this afforded her pleasure. She even +turned so that he should see her profile in what she thought was its +most becoming aspect. Before the beginning of the second act Pierre +appeared in the stalls. The Rostovs had not seen him since their +arrival. His face looked sad, and he had grown still stouter since +Natasha last saw him. He passed up to the front rows, not noticing +anyone. Anatole went up to him and began speaking to him, looking at +and indicating the Rostovs' box. On seeing Natasha Pierre grew +animated and, hastily passing between the rows, came toward their box. +When he got there he leaned on his elbows and, smiling, talked to +her for a long time. While conversing with Pierre, Natasha heard a +man's voice in Countess Bezukhova's box and something told her it +was Kuragin. She turned and their eyes met. Almost smiling, he gazed +straight into her eyes with such an enraptured caressing look that +it seemed strange to be so near him, to look at him like that, to be +so sure he admired her, and not to be acquainted with him. + +In the second act there was scenery representing tombstones, there +was a round hole in the canvas to represent the moon, shades were +raised over the footlights, and from horns and contrabass came deep +notes while many people appeared from right and left wearing black +cloaks and holding things like daggers in their hands. They began +waving their arms. Then some other people ran in and began dragging +away the maiden who had been in white and was now in light blue. +They did not drag her away at once, but sang with her for a long +time and then at last dragged her off, and behind the scenes something +metallic was struck three times and everyone knelt down and sang a +prayer. All these things were repeatedly interrupted by the +enthusiastic shouts of the audience. + +During this act every time Natasha looked toward the stalls she +saw Anatole Kuragin with an arm thrown across the back of his chair, +staring at her. She was pleased to see that he was captivated by her +and it did not occur to her that there was anything wrong in it. + +When the second act was over Countess Bezukhova rose, turned to +the Rostovs' box--her whole bosom completely exposed--beckoned the old +count with a gloved finger, and paying no attention to those who had +entered her box began talking to him with an amiable smile. + +"Do make me acquainted with your charming daughters," said she. "The +whole town is singing their praises and I don't even know then!" + +Natasha rose and curtsied to the splendid countess. She was so +pleased by praise from this brilliant beauty that she blushed with +pleasure. + +"I want to become a Moscovite too, now," said Helene. "How is it +you're not ashamed to bury such pearls in the country?" + +Countess Bezukhova quite deserved her reputation of being a +fascinating woman. She could say what she did not think--especially +what was flattering--quite simply and naturally. + +"Dear count, you must let me look after your daughters! Though I +am not staying here long this time--nor are you--I will try to amuse +them. I have already heard much of you in Petersburg and wanted to get +to know you," said she to Natasha with her stereotyped and lovely +smile. "I had heard about you from my page, Drubetskoy. Have you heard +he is getting married? And also from my husband's friend Bolkonski, +Prince Andrew Bolkonski," she went on with special emphasis, +implying that she knew of his relation to Natasha. To get better +acquainted she asked that one of the young ladies should come into her +box for the rest of the performance, and Natasha moved over to it. + +The scene of the third act represented a palace in which many +candles were burning and pictures of knights with short beards hung on +the walls. In the middle stood what were probably a king and a +queen. The king waved his right arm and, evidently nervous, sang +something badly and sat down on a crimson throne. The maiden who had +been first in white and then in light blue, now wore only a smock, and +stood beside the throne with her hair down. She sang something +mournfully, addressing the queen, but the king waved his arm severely, +and men and women with bare legs came in from both sides and began +dancing all together. Then the violins played very shrilly and merrily +and one of the women with thick bare legs and thin arms, separating +from the others, went behind the wings, adjusted her bodice, +returned to the middle of the stage, and began jumping and striking +one foot rapidly against the other. In the stalls everyone clapped and +shouted "bravo!" Then one of the men went into a corner of the +stage. The cymbals and horns in the orchestra struck up more loudly, +and this man with bare legs jumped very high and waved his feet +about very rapidly. (He was Duport, who received sixty thousand rubles +a year for this art.) Everybody in the stalls, boxes, and galleries +began clapping and shouting with all their might, and the man +stopped and began smiling and bowing to all sides. Then other men +and women danced with bare legs. Then the king again shouted to the +sound of music, and they all began singing. But suddenly a storm +came on, chromatic scales and diminished sevenths were heard in the +orchestra, everyone ran off, again dragging one of their number +away, and the curtain dropped. Once more there was a terrible noise +and clatter among the audience, and with rapturous faces everyone +began shouting: "Duport! Duport! Duport!" Natasha no longer thought +this strange. She look about with pleasure, smiling joyfully. + +"Isn't Duport delightful?" Helene asked her. + +"Oh, yes," replied Natasha. + + + + + +CHAPTER X + + +During the entr'acte a whiff of cold air came into Helene's box, the +door opened, and Anatole entered, stooping and trying not to brush +against anyone. + +"Let me introduce my brother to you," said Helene, her eyes shifting +uneasily from Natasha to Anatole. + +Natasha turned her pretty little head toward the elegant young +officer and smiled at him over her bare shoulder. Anatole, who was +as handsome at close quarters as at a distance, sat down beside her +and told her he had long wished to have this happiness--ever since the +Naryshkins' ball in fact, at which he had had the well-remembered +pleasure of seeing her. Kuragin was much more sensible and simple with +women than among men. He talked boldly and naturally, and Natasha +was strangely and agreeably struck by the fact that there was +nothing formidable in this man about whom there was so much talk, +but that on the contrary his smile was most naive, cheerful, and +good-natured. + +Kuragin asked her opinion of the performance and told her how at a +previous performance Semenova had fallen down on the stage. + +"And do you know, Countess," he said, suddenly addressing her as +an old, familiar acquaintance, "we are getting up a costume +tournament; you ought to take part in it! It will be great fun. We +shall all meet at the Karagins'! Please come! No! Really, eh?" said +he. + +While saying this he never removed his smiling eyes from her face, +her neck, and her bare arms. Natasha knew for certain that he was +enraptured by her. This pleased her, yet his presence made her feel +constrained and oppressed. When she was not looking at him she felt +that he was looking at her shoulders, and she involuntarily caught his +eye so that he should look into hers rather than this. But looking +into his eyes she was frightened, realizing that there was not that +barrier of modesty she had always felt between herself and other +men. She did not know how it was that within five minutes she had come +to feel herself terribly near to this man. When she turned away she +feared he might seize her from behind by her bare arm and kiss her +on the neck. They spoke of most ordinary things, yet she felt that +they were closer to one another than she had ever been to any man. +Natasha kept turning to Helene and to her father, as if asking what it +all meant, but Helene was engaged in conversation with a general and +did not answer her look, and her father's eyes said nothing but what +they always said: "Having a good time? Well, I'm glad of it!" + +During one of these moments of awkward silence when Anatole's +prominent eyes were gazing calmly and fixedly at her, Natasha, to +break the silence, asked him how he liked Moscow. She asked the +question and blushed. She felt all the time that by talking to him she +was doing something improper. Anatole smiled as though to encourage +her. + +"At first I did not like it much, because what makes a town pleasant +ce sont les jolies femmes,* isn't that so? But now I like it very much +indeed," he said, looking at her significantly. "You'll come to the +costume tournament, Countess? Do come!" and putting out his hand to +her bouquet and dropping his voice, he added, "You will be the +prettiest there. Do come, dear countess, and give me this flower as +a pledge!" + + +*Are the pretty women. + + +Natasha did not understand what he was saying any more than he did +himself, but she felt that his incomprehensible words had an +improper intention. She did not know what to say and turned away as if +she had not heard his remark. But as soon as she had turned away she +felt that he was there, behind, so close behind her. + +"How is he now? Confused? Angry? Ought I to put it right?" she asked +herself, and she could not refrain from turning round. She looked +straight into his eyes, and his nearness, self-assurance, and the +good-natured tenderness of his smile vanquished her. She smiled just +as he was doing, gazing straight into his eyes. And again she felt +with horror that no barrier lay between him and her. + +The curtain rose again. Anatole left the box, serene and gay. +Natasha went back to her father in the other box, now quite submissive +to the world she found herself in. All that was going on before her +now seemed quite natural, but on the other hand all her previous +thoughts of her betrothed, of Princess Mary, or of life in the country +did not once recur to her mind and were as if belonging to a remote +past. + +In the fourth act there was some sort of devil who sang waving his +arm about, till the boards were withdrawn from under him and he +disappeared down below. That was the only part of the fourth act +that Natasha saw. She felt agitated and tormented, and the cause of +this was Kuragin whom she could not help watching. As they were +leaving the theater Anatole came up to them, called their carriage, +and helped them in. As he was putting Natasha in he pressed her arm +above the elbow. Agitated and flushed she turned round. He was looking +at her with glittering eyes, smiling tenderly. + + +Only after she had reached home was Natasha able clearly to think +over what had happened to her, and suddenly remembering Prince +Andrew she was horrified, and at tea to which all had sat down after +the opera, she gave a loud exclamation, flushed, and ran out of the +room. + +"O God! I am lost!" she said to herself. "How could I let him?" +She sat for a long time hiding her flushed face in her hands trying to +realize what had happened to her, but was unable either to +understand what had happened or what she felt. Everything seemed dark, +obscure, and terrible. There in that enormous, illuminated theater +where the bare-legged Duport, in a tinsel-decorated jacket, jumped +about to the music on wet boards, and young girls and old men, and the +nearly naked Helene with her proud, calm smile, rapturously cried +"bravo!"--there in the presence of that Helene it had all seemed clear +and simple; but now, alone by herself, it was incomprehensible. +"What is it? What was that terror I felt of him? What is this +gnawing of conscience I am feeling now?" she thought. + +Only to the old countess at night in bed could Natasha have told all +she was feeling. She knew that Sonya with her severe and simple +views would either not understand it at all or would be horrified at +such a confession. So Natasha tried to solve what was torturing her by +herself. + +"Am I spoiled for Andrew's love or not?" she asked herself, and with +soothing irony replied: "What a fool I am to ask that! What did happen +to me? Nothing! I have done nothing, I didn't lead him on at all. +Nobody will know and I shall never see him again," she told herself. +"So it is plain that nothing has happened and there is nothing to +repent of, and Andrew can love me still. But why 'still?' O God, why +isn't he here?" Natasha quieted herself for a moment, but again some +instinct told her that though all this was true, and though nothing +had happened, yet the former purity of her love for Prince Andrew +had perished. And again in imagination she went over her whole +conversation with Kuragin, and again saw the face, gestures, and +tender smile of that bold handsome man when he pressed her arm. + + + + + +CHAPTER XI + +Anatole Kuragin was staying in Moscow because his father had sent +him away from Petersburg, where he had been spending twenty thousand +rubles a year in cash, besides running up debts for as much more, +which his creditors demanded from his father. + +His father announced to him that he would now pay half his debts for +the last time, but only on condition that he went to Moscow as +adjutant to the commander in chief--a post his father had procured for +him--and would at last try to make a good match there. He indicated to +him Princess Mary and Julie Karagina. + +Anatole consented and went to Moscow, where he put up at Pierre's +house. Pierre received him unwillingly at first, but got used to him +after a while, sometimes even accompanied him on his carousals, and +gave him money under the guise of loans. + +As Shinshin had remarked, from the time of his arrival Anatole had +turned the heads of the Moscow ladies, especially by the fact that +he slighted them and plainly preferred the gypsy girls and French +actresses--with the chief of whom, Mademoiselle George, he was said to +be on intimate relations. He had never missed a carousal at +Danilov's or other Moscow revelers', drank whole nights through, +outvying everyone else, and was at all the balls and parties of the +best society. There was talk of his intrigues with some of the ladies, +and he flirted with a few of them at the balls. But he did not run +after the unmarried girls, especially the rich heiresses who were most +of them plain. There was a special reason for this, as he had got +married two years before--a fact known only to his most intimate +friends. At that time while with his regiment in Poland, a Polish +landowner of small means had forced him to marry his daughter. Anatole +had very soon abandoned his wife and, for a payment which he agreed to +send to his father-in-law, had arranged to be free to pass himself off +as a bachelor. + +Anatole was always content with his position, with himself, and with +others. He was instinctively and thoroughly convinced that was +impossible for him to live otherwise than as he did and that he had +never in his life done anything base. He was incapable of +considering how his actions might affect others or what the +consequences of this or that action of his might be. He was +convinced that, as a duck is so made that it must live in water, so +God had made him such that he must spend thirty thousand rubles a year +and always occupy a prominent position in society. He believed this so +firmly that others, looking at him, were persuaded of it too and did +not refuse him either a leading place in society or money, which he +borrowed from anyone and everyone and evidently would not repay. + +He was not a gambler, at any rate he did not care about winning. +He was not vain. He did not mind what people thought of him. Still +less could he be accused of ambition. More than once he had vexed +his father by spoiling his own career, and he laughed at +distinctions of all kinds. He was not mean, and did not refuse +anyone who asked of him. All he cared about was gaiety and women, +and as according to his ideas there was nothing dishonorable in +these tastes, and he was incapable of considering what the +gratification of his tastes entailed for others, he honestly +considered himself irreproachable, sincerely despised rogues and bad +people, and with a tranquil conscience carried his head high. + +Rakes, those male Magdalenes, have a secret feeling of innocence +similar to that which female Magdalenes have, based on the same hope +of forgiveness. "All will be forgiven her, for she loved much; and all +will be forgiven him, for he enjoyed much." + +Dolokhov, who had reappeared that year in Moscow after his exile and +his Persian adventures, and was leading a life of luxury, gambling, +and dissipation, associated with his old Petersburg comrade Kuragin +and made use of him for his own ends. + +Anatole was sincerely fond of Dolokhov for his cleverness and +audacity. Dolokhov, who needed Anatole Kuragin's name, position, and +connections as a bait to draw rich young men into his gambling set, +made use of him and amused himself at his expense without letting +the other feel it. Apart from the advantage he derived from Anatole, +the very process of dominating another's will was in itself a +pleasure, a habit, and a necessity to Dolokhov. + +Natasha had made a strong impression on Kuragin. At supper after the +opera he described to Dolokhov with the air of a connoisseur the +attractions of her arms, shoulders, feet, and hair and expressed his +intention of making love to her. Anatole had no notion and was +incapable of considering what might come of such love-making, as he +never had any notion of the outcome of any of his actions. + +"She's first-rate, my dear fellow, but not for us," replied +Dolokhov. + +"I will tell my sister to ask her to dinner," said Anatole. "Eh?" + +"You'd better wait till she's married...." + +"You know, I adore little girls, they lose their heads at once," +pursued Anatole. + +"You have been caught once already by a 'little girl,'" said +Dolokhov who knew of Kuragin's marriage. "Take care!" + +"Well, that can't happen twice! Eh?" said Anatole, with a +good-humored laugh. + + + + + +CHAPTER XII + + +The day after the opera the Rostovs went nowhere and nobody came +to see them. Marya Dmitrievna talked to the count about something +which they concealed from Natasha. Natasha guessed they were talking +about the old prince and planning something, and this disquieted and +offended her. She was expecting Prince Andrew any moment and twice +that day sent a manservant to the Vozdvizhenka to ascertain whether he +had come. He had not arrived. She suffered more now than during her +first days in Moscow. To her impatience and pining for him were now +added the unpleasant recollection of her interview with Princess +Mary and the old prince, and a fear and anxiety of which she did not +understand the cause. She continually fancied that either he would +never come or that something would happen to her before he came. She +could no longer think of him by herself calmly and continuously as she +had done before. As soon as she began to think of him, the +recollection of the old prince, of Princess Mary, of the theater, +and of Kuragin mingled with her thoughts. The question again presented +itself whether she was not guilty, whether she had not already +broken faith with Prince Andrew, and again she found herself recalling +to the minutest detail every word, every gesture, and every shade in +the play of expression on the face of the man who had been able to +arouse in her such an incomprehensible and terrifying feeling. To +the family Natasha seemed livelier than usual, but she was far less +tranquil and happy than before. + +On Sunday morning Marya Dmitrievna invited her visitors to Mass at +her parish church--the Church of the Assumption built over the +graves of victims of the plague. + +"I don't like those fashionable churches," she said, evidently +priding herself on her independence of thought. "God is the same every +where. We have an excellent priest, he conducts the service decently +and with dignity, and the deacon is the same. What holiness is there +in giving concerts in the choir? I don't like it, it's just +self-indulgence!" + +Marya Dmitrievna liked Sundays and knew how to keep them. Her +whole house was scrubbed and cleaned on Saturdays; neither she nor the +servants worked, and they all wore holiday dress and went to church. +At her table there were extra dishes at dinner, and the servants had +vodka and roast goose or suckling pig. But in nothing in the house was +the holiday so noticeable as in Marya Dmitrievna's broad, stern +face, which on that day wore an invariable look of solemn festivity. + +After Mass, when they had finished their coffee in the dining room +where the loose covers had been removed from the furniture, a +servant announced that the carriage was ready, and Marya Dmitrievna +rose with a stern air. She wore her holiday shawl, in which she paid +calls, and announced that she was going to see Prince Nicholas +Bolkonski to have an explanation with him about Natasha. + +After she had gone, a dressmaker from Madame Suppert-Roguet waited +on the Rostovs, and Natasha, very glad of this diversion, having +shut herself into a room adjoining the drawing room, occupied +herself trying on the new dresses. Just as she had put on a bodice +without sleeves and only tacked together, and was turning her head +to see in the glass how the back fitted, she heard in the drawing room +the animated sounds of her father's voice and another's--a woman's- +that made her flush. It was Helene. Natasha had not time to take off +the bodice before the door opened and Countess Bezukhova, dressed in a +purple velvet gown with a high collar, came into the room beaming with +good-humored amiable smiles. + +"Oh, my enchantress!" she cried to the blushing Natasha. +"Charming! No, this is really beyond anything, my dear count," said +she to Count Rostov who had followed her in. "How can you live in +Moscow and go nowhere? No, I won't let you off! Mademoiselle George +will recite at my house tonight and there'll be some people, and if +you don't bring your lovely girls--who are prettier than +Mademoiselle George--I won't know you! My husband is away in Tver or I +would send him to fetch you. You must come. You positively must! +Between eight and nine." + +She nodded to the dressmaker, whom she knew and who had curtsied +respectfully to her, and seated herself in an armchair beside the +looking glass, draping the folds of her velvet dress picturesquely. +She did not cease chattering good-naturedly and gaily, continually +praising Natasha's beauty. She looked at Natasha's dresses and praised +them, as well as a new dress of her own made of "metallic gauze," +which she had received from Paris, and advised Natasha to have one +like it. + +"But anything suits you, my charmer!" she remarked. + +A smile of pleasure never left Natasha's face. She felt happy and as +if she were blossoming under the praise of this dear Countess +Bezukhova who had formerly seemed to her so unapproachable and +important and was now so kind to her. Natasha brightened up and felt +almost in love with this woman, who was so beautiful and so kind. +Helene for her part was sincerely delighted with Natasha and wished to +give her a good time. Anatole had asked her to bring him and Natasha +together, and she was calling on the Rostovs for that purpose. The +idea of throwing her brother and Natasha together amused her. + +Though at one time, in Petersburg, she had been annoyed with Natasha +for drawing Boris away, she did not think of that now, and in her +own way heartily wished Natasha well. As she was leaving the Rostovs +she called her protegee aside. + +"My brother dined with me yesterday--we nearly died of laughter- +he ate nothing and kept sighing for you, my charmer! He is madly, +quite madly, in love with you, my dear." + +Natasha blushed scarlet when she heard this. + +"How she blushes, how she blushes, my pretty!" said Helene. "You +must certainly come. If you love somebody, my charmer, that is not a +reason to shut yourself up. Even if you are engaged, I am sure your +fiance would wish you to go into society rather than be bored to +death." + +"So she knows I am engaged, and she and her husband Pierre--that +good Pierre--have talked and laughed about this. So it's all right." +And again, under Helene's influence, what had seemed terrible now +seemed simple and natural. "And she is such a grande dame, so kind, +and evidently likes me so much. And why not enjoy myself?" thought +Natasha, gazing at Helene with wide-open, wondering eyes. + +Marya Dmitrievna came back to dinner taciturn and serious, having +evidently suffered a defeat at the old prince's. She was still too +agitated by the encounter to be able to talk of the affair calmly. +In answer to the count's inquiries she replied that things were all +right and that she would tell about it next day. On hearing of +Countess Bezukhova's visit and the invitation for that evening, +Marya Dmitrievna remarked: + +"I don't care to have anything to do with Bezukhova and don't advise +you to; however, if you've promised--go. It will divert your +thoughts," she added, addressing Natasha. + + + + + +CHAPTER XIII + + +Count Rostov took the girls to Countess Bezukhova's. There were a +good many people there, but nearly all strangers to Natasha. Count +Rostov was displeased to see that the company consisted almost +entirely of men and women known for the freedom of their conduct. +Mademoiselle George was standing in a corner of the drawing room +surrounded by young men. There were several Frenchmen present, among +them Metivier who from the time Helene reached Moscow had been an +intimate in her house. The count decided not to sit down to cards or +let his girls out of his sight and to get away as soon as Mademoiselle +George's performance was over. + +Anatole was at the door, evidently on the lookout for the Rostovs. +Immediately after greeting the count he went up to Natasha and +followed her. As soon as she saw him she was seized by the same +feeling she had had at the opera--gratified vanity at his admiration +of her and fear at the absence of a moral barrier between them. + +Helene welcomed Natasha delightedly and was loud in admiration of +her beauty and her dress. Soon after their arrival Mademoiselle George +went out of the room to change her costume. In the drawing room people +began arranging the chairs and taking their seats. Anatole moved a +chair for Natasha and was about to sit down beside her, but the count, +who never lost sight of her, took the seat himself. Anatole sat down +behind her. + +Mademoiselle George, with her bare, fat, dimpled arms, and a red +shawl draped over one shoulder, came into the space left vacant for +her, and assumed an unnatural pose. Enthusiastic whispering was +audible. + +Mademoiselle George looked sternly and gloomily at the audience +and began reciting some French verses describing her guilty love for +her son. In some places she raised her voice, in others she whispered, +lifting her head triumphantly; sometimes she paused and uttered hoarse +sounds, rolling her eyes. + +"Adorable! divine! delicious!" was heard from every side. + +Natasha looked at the fat actress, but neither saw nor heard nor +understood anything of what went on before her. She only felt +herself again completely borne away into this strange senseless world- +so remote from her old world--a world in which it was impossible to +know what was good or bad, reasonable or senseless. Behind her sat +Anatole, and conscious of his proximity she experienced a frightened +sense of expectancy. + +After the first monologue the whole company rose and surrounded +Mademoiselle George, expressing their enthusiasm. + +"How beautiful she is!" Natasha remarked to her father who had +also risen and was moving through the crowd toward the actress. + +"I don't think so when I look at you!" said Anatole, following +Natasha. He said this at a moment when she alone could hear him. +"You are enchanting... from the moment I saw you I have never +ceased..." + +"Come, come, Natasha!" said the count, as he turned back for his +daughter. "How beautiful she is!" Natasha without saying anything +stepped up to her father and looked at him with surprised inquiring +eyes. + +After giving several recitations, Mademoiselle George left, and +Countess Bezukhova asked her visitors into the ballroom. + +The count wished to go home, but Helene entreated him not to spoil +her improvised ball, and the Rostovs stayed on. Anatole asked +Natasha for a valse and as they danced he pressed her waist and hand +and told her she was bewitching and that he loved her. During the +ecossaise, which she also danced with him, Anatole said nothing when +they happened to be by themselves, but merely gazed at her. Natasha +lifted her frightened eyes to him, but there was such confident +tenderness in his affectionate look and smile that she could not, +whilst looking at him, say what she had to say. She lowered her eyes. + +"Don't say such things to me. I am betrothed and love another," +she said rapidly.... She glanced at him. + +Anatole was not upset or pained by what she had said. + +"Don't speak to me of that! What can I do?" said he. "I tell you I +am madly, madly, in love with you! Is it my fault that you are +enchanting?... It's our turn to begin." + +Natasha, animated and excited, looked about her with wide-open +frightened eyes and seemed merrier than usual. She understood hardly +anything that went on that evening. They danced the ecossaise and +the Grossvater. Her father asked her to come home, but she begged to +remain. Wherever she went and whomever she was speaking to, she felt +his eyes upon her. Later on she recalled how she had asked her +father to let her go to the dressing room to rearrange her dress, that +Helene had followed her and spoken laughingly of her brother's love, +and that she again met Anatole in the little sitting room. Helene +had disappeared leaving them alone, and Anatole had taken her hand and +said in a tender voice: + +"I cannot come to visit you but is it possible that I shall never +see you? I love you madly. Can I never...?" and, blocking her path, he +brought his face close to hers. + +His large, glittering, masculine eyes were so close to hers that she +saw nothing but them. + +"Natalie?" he whispered inquiringly while she felt her hands being +painfully pressed. "Natalie?" + +"I don't understand. I have nothing to say," her eyes replied. + +Burning lips were pressed to hers, and at the same instant she +felt herself released, and Helene's footsteps and the rustle of her +dress were heard in the room. Natasha looked round at her, and then, +red and trembling, threw a frightened look of inquiry at Anatole and +moved toward the door. + +"One word, just one, for God's sake!" cried Anatole. + +She paused. She so wanted a word from him that would explain to +her what had happened and to which she could find no answer. + +"Natalie, just a word, only one!" he kept repeating, evidently not +knowing what to say and he repeated it till Helene came up to them. + +Helene returned with Natasha to the drawing room. The Rostovs went +away without staying for supper. + +After reaching home Natasha did not sleep all night. She was +tormented by the insoluble question whether she loved Anatole or +Prince Andrew. She loved Prince Andrew--she remembered distinctly +how deeply she loved him. But she also loved Anatole, of that there +was no doubt. "Else how could all this have happened?" thought she. +"If, after that, I could return his smile when saying good-by, if I +was able to let it come to that, it means that I loved him from the +first. It means that he is kind, noble, and splendid, and I could +not help loving him. What am I to do if I love him and the other one +too?" she asked herself, unable to find an answer to these terrible +questions. + + + + + +CHAPTER XIV + + +Morning came with its cares and bustle. Everyone got up and began to +move about and talk, dressmakers came again. Marya Dmitrievna +appeared, and they were called to breakfast. Natasha kept looking +uneasily at everybody with wide-open eyes, as if wishing to +intercept every glance directed toward her, and tried to appear the +same as usual. + +After breakfast, which was her best time, Marya Dmitrievna sat +down in her armchair and called Natasha and the count to her. + +"Well, friends, I have now thought the whole matter over and this is +my advice," she began. "Yesterday, as you know, I went to see Prince +Bolkonski. Well, I had a talk with him.... He took it into his head to +begin shouting, but I am not one to be shouted down. I said what I had +to say!" + +"Well, and he?" asked the count. + +"He? He's crazy... he did not want to listen. But what's the use +of talking? As it is we have worn the poor girl out," said Marya +Dmitrievna. "My advice to you is finish your business and go back home +to Otradnoe... and wait there." + +"Oh, no!" exclaimed Natasha. + +"Yes, go back," said Marya Dmitrievna, "and wait there. If your +betrothed comes here now--there will be no avoiding a quarrel; but +alone with the old man he will talk things over and then come on to +you." + +Count Rostov approved of this suggestion, appreciating its +reasonableness. If the old man came round it would be all the better +to visit him in Moscow or at Bald Hills later on; and if not, the +wedding, against his wishes, could only be arranged at Otradnoe. + +"That is perfectly true. And I am sorry I went to see him and took +her," said the old count. + +"No, why be sorry? Being here, you had to pay your respects. But +if he won't--that's his affair," said Marya Dmitrievna, looking for +something in her reticule. "Besides, the trousseau is ready, so +there is nothing to wait for; and what is not ready I'll send after +you. Though I don't like letting you go, it is the best way. So go, +with God's blessing!" + +Having found what she was looking for in the reticule she handed +it to Natasha. It was a letter from Princess Mary. + +"She has written to you. How she torments herself, poor thing! She's +afraid you might think that she does not like you." + +"But she doesn't like me," said Natasha. + +"Don't talk nonsense!" cried Marya Dmitrievna. + +"I shan't believe anyone, I know she doesn't like me," replied +Natasha boldly as she took the letter, and her face expressed a cold +and angry resolution that caused Marya Dmitrievna to look at her +more intently and to frown. + +"Don't answer like that, my good girl!" she said. "What I say is +true! Write an answer!" Natasha did not reply and went to her own room +to read Princess Mary's letter. + +Princess Mary wrote that she was in despair at the +misunderstanding that had occurred between them. Whatever her father's +feelings might be, she begged Natasha to believe that she could not +help loving her as the one chosen by her brother, for whose +happiness she was ready to sacrifice everything. + +"Do not think, however," she wrote, "that my father is +ill-disposed toward you. He is an invalid and an old man who must be +forgiven; but he is good and magnanimous and will love her who makes +his son happy." Princess Mary went on to ask Natasha to fix a time +when she could see her again. + +After reading the letter Natasha sat down at the writing table to +answer it. "Dear Princess," she wrote in French quickly and +mechanically, and then paused. What more could she write after all +that had happened the evening before? "Yes, yes! All that has +happened, and now all is changed," she thought as she sat with the +letter she had begun before her. "Must I break off with him? Must I +really? That's awful..." and to escape from these dreadful thoughts +she went to Sonya and began sorting patterns with her. + +After dinner Natasha went to her room and again took up Princess +Mary's letter. "Can it be that it is all over?" she thought. "Can it +be that all this has happened so quickly and has destroyed all that +went before?" She recalled her love for Prince Andrew in all its +former strength, and at the same time felt that she loved Kuragin. She +vividly pictured herself as Prince Andrew's wife, and the scenes of +happiness with him she had so often repeated in her imagination, and +at the same time, aglow with excitement, recalled every detail of +yesterday's interview with Anatole. + +"Why could that not be as well?" she sometimes asked herself in +complete bewilderment. "Only so could I be completely happy; but now I +have to choose, and I can't be happy without either of them. Only," +she thought, "to tell Prince Andrew what has happened or to hide it +from him are both equally impossible. But with that one nothing is +spoiled. But am I really to abandon forever the joy of Prince Andrew's +love, in which I have lived so long?" + +"Please, Miss!" whispered a maid entering the room with a mysterious +air. "A man told me to give you this-" and she handed Natasha a +letter. + +"Only, for Christ's sake..." the girl went on, as Natasha, without +thinking, mechanically broke the seal and read a love letter from +Anatole, of which, without taking in a word, she understood only +that it was a letter from him--from the man she loved. Yes, she +loved him, or else how could that have happened which had happened? +And how could she have a love letter from him in her hand? + +With trembling hands Natasha held that passionate love letter +which Dolokhov had composed for Anatole, and as she read it she +found in it an echo of all that she herself imagined she was feeling. + +"Since yesterday evening my fate has been sealed; to be loved by you +or to die. There is no other way for me," the letter began. Then he +went on to say that he knew her parents would not give her to him--for +this there were secret reasons he could reveal only to her--but that +if she loved him she need only say the word yes, and no human power +could hinder their bliss. Love would conquer all. He would steal her +away and carry her off to the ends of the earth. + +"Yes, yes! I love him!" thought Natasha, reading the letter for +the twentieth time and finding some peculiarly deep meaning in each +word of it. + +That evening Marya Dmitrievna was going to the Akharovs' and +proposed to take the girls with her. Natasha, pleading a headache, +remained at home. + + + + + +CHAPTER XV + + +On returning late in the evening Sonya went to Natasha's room, and +to her surprise found her still dressed and asleep on the sofa. Open +on the table, beside her lay Anatole's letter. Sonya picked it up +and read it. + +As she read she glanced at the sleeping Natasha, trying to find in +her face an explanation of what she was reading, but did not find +it. Her face was calm, gentle, and happy. Clutching her breast to keep +herself from choking, Sonya, pale and trembling with fear and +agitation, sat down in an armchair and burst into tears. + +"How was it I noticed nothing? How could it go so far? Can she +have left off loving Prince Andrew? And how could she let Kuragin go +to such lengths? He is a deceiver and a villain, that's plain! What +will Nicholas, dear noble Nicholas, do when he hears of it? So this is +the meaning of her excited, resolute, unnatural look the day before +yesterday, yesterday, and today," thought Sonya. "But it can't be that +she loves him! She probably opened the letter without knowing who it +was from. Probably she is offended by it. She could not do such a +thing!" + +Sonya wiped away her tears and went up to Natasha, again scanning +her face. + +"Natasha!" she said, just audibly. + +Natasha awoke and saw Sonya. + +"Ah, you're back?" + +And with the decision and tenderness that often come at the moment +of awakening, she embraced her friend, but noticing Sonya's look of +embarrassment, her own face expressed confusion and suspicion. + +"Sonya, you've read that letter?" she demanded. + +"Yes," answered Sonya softly. + +Natasha smiled rapturously. + +"No, Sonya, I can't any longer!" she said. "I can't hide it from you +any longer. You know, we love one another! Sonya, darling, he +writes... Sonya..." + +Sonya stared open-eyed at Natasha, unable to believe her ears. + +"And Bolkonski?" she asked. + +"Ah, Sonya, if you only knew how happy I am!" cried Natasha. "You +don't know what love is...." + +"But, Natasha, can that be all over?" + +Natasha looked at Sonya with wide-open eyes as if she could not +grasp the question. + +"Well, then, are you refusing Prince Andrew?" said Sonya. + +"Oh, you don't understand anything! Don't talk nonsense, just +listen!" said Natasha, with momentary vexation. + +"But I can't believe it," insisted Sonya. "I don't understand. How +is it you have loved a man for a whole year and suddenly... Why, you +have only seen him three times! Natasha, I don't believe you, you're +joking! In three days to forget everything and so..." + +"Three days?" said Natasha. "It seems to me I've loved him a hundred +years. It seems to me that I have never loved anyone before. You can't +understand it.... Sonya, wait a bit, sit here," and Natasha embraced +and kissed her. + +"I had heard that it happens like this, and you must have heard it +too, but it's only now that I feel such love. It's not the same as +before. As soon as I saw him I felt he was my master and I his +slave, and that I could not help loving him. Yes, his slave! +Whatever he orders I shall do. You don't understand that. What can I +do? What can I do, Sonya?" cried Natasha with a happy yet frightened +expression. + +"But think what you are doing," cried Sonya. "I can't leave it +like this. This secret correspondence... How could you let him go so +far?" she went on, with a horror and disgust she could hardly conceal. + +"I told you that I have no will," Natasha replied. "Why can't you +understand? I love him!" + +"Then I won't let it come to that... I shall tell!" cried Sonya, +bursting into tears. + +"What do you mean? For God's sake... If you tell, you are my enemy!" +declared Natasha. "You want me to be miserable, you want us to be +separated...." + +When she saw Natasha's fright, Sonya shed tears of shame and pity +for her friend. + +"But what has happened between you?" she asked. "What has he said to +you? Why doesn't he come to the house?" + +Natasha did not answer her questions. + +"For God's sake, Sonya, don't tell anyone, don't torture me," +Natasha entreated. "Remember no one ought to interfere in such +matters! I have confided in you...." + +"But why this secrecy? Why doesn't he come to the house?" asked +Sonya. "Why doesn't he openly ask for your hand? You know Prince +Andrew gave you complete freedom--if it is really so; but I don't +believe it! Natasha, have you considered what these secret reasons can +be?" + +Natasha looked at Sonya with astonishment. Evidently this question +presented itself to her mind for the first time and she did not know +how to answer it. + +"I don't know what the reasons are. But there must be reasons!" + +Sonya sighed and shook her head incredulously. + +"If there were reasons..." she began. + +But Natasha, guessing her doubts, interrupted her in alarm. + +"Sonya, one can't doubt him! One can't, one can't! Don't you +understand?" she cried. + +"Does he love you?" + +"Does he love me?" Natasha repeated with a smile of pity at her +friend's lack of comprehension. "Why, you have read his letter and you +have seen him." + +"But if he is dishonorable?" + +"He! dishonorable? If you only knew!" exclaimed Natasha. + +"If he is an honorable man he should either declare his intentions +or cease seeing you; and if you won't do this, I will. I will write to +him, and I will tell Papa!" said Sonya resolutely. + +"But I can't live without him!" cried Natasha. + +"Natasha, I don't understand you. And what are you saying! Think +of your father and of Nicholas." + +"I don't want anyone, I don't love anyone but him. How dare you +say he is dishonorable? Don't you know that I love him?" screamed +Natasha. "Go away, Sonya! I don't want to quarrel with you, but go, +for God's sake go! You see how I am suffering!" Natasha cried angrily, +in a voice of despair and repressed irritation. Sonya burst into +sobs and ran from the room. + +Natasha went to the table and without a moment's reflection wrote +that answer to Princess Mary which she had been unable to write all +the morning. In this letter she said briefly that all their +misunderstandings were at an end; that availing herself of the +magnanimity of Prince Andrew who when he went abroad had given her her +freedom, she begged Princess Mary to forget everything and forgive her +if she had been to blame toward her, but that she could not be his wife. +At that moment this all seemed quite easy, simple, and clear to Natasha. + + +On Friday the Rostovs were to return to the country, but on +Wednesday the count went with the prospective purchaser to his +estate near Moscow. + +On the day the count left, Sonya and Natasha were invited to a big +dinner party at the Karagins', and Marya Dmitrievna took them there. +At that party Natasha again met Anatole, and Sonya noticed that she +spoke to him, trying not to be overheard, and that all through +dinner she was more agitated than ever. When they got home Natasha was +the first to begin the explanation Sonya expected. + +"There, Sonya, you were talking all sorts of nonsense about him," +Natasha began in a mild voice such as children use when they wish to +be praised. "We have had an explanation today." + +"Well, what happened? What did he say? Natasha, how glad I am you're +not angry with me! Tell me everything--the whole truth. What did he +say?" + +Natasha became thoughtful. + +"Oh, Sonya, if you knew him as I do! He said... He asked me what I +had promised Bolkonski. He was glad I was free to refuse him." + +Sonya sighed sorrowfully. + +"But you haven't refused Bolkonski?" said she. + +"Perhaps I have. Perhaps all is over between me and Bolkonski. Why +do you think so badly of me?" + +"I don't think anything, only I don't understand this..." + +"Wait a bit, Sonya, you'll understand everything. You'll see what +a man he is! Now don't think badly of me or of him. I don't think +badly of anyone: I love and pity everybody. But what am I to do?" + +Sonya did not succumb to the tender tone Natasha used toward her. +The more emotional and ingratiating the expression of Natasha's face +became, the more serious and stern grew Sonya's. + +"Natasha," said she, "you asked me not to speak to you, and I +haven't spoken, but now you yourself have begun. I don't trust him, +Natasha. Why this secrecy?" + +"Again, again!" interrupted Natasha. + +"Natasha, I am afraid for you!" + +"Afraid of what?" + +"I am afraid you're going to your ruin," said Sonya resolutely, +and was herself horrified at what she had said. + +Anger again showed in Natasha's face. + +"And I'll go to my ruin, I will, as soon as possible! It's not +your business! It won't be you, but I, who'll suffer. Leave me +alone, leave me alone! I hate you!" + +"Natasha!" moaned Sonya, aghast. + +"I hate you, I hate you! You're my enemy forever!" And Natasha ran +out of the room. + +Natasha did not speak to Sonya again and avoided her. With the +same expression of agitated surprise and guilt she went about the +house, taking up now one occupation, now another, and at once +abandoning them. + +Hard as it was for Sonya, she watched her friend and did not let her +out of her sight. + +The day before the count was to return, Sonya noticed that Natasha +sat by the drawingroom window all the morning as if expecting +something and that she made a sign to an officer who drove past, +whom Sonya took to be Anatole. + +Sonya began watching her friend still more attentively and noticed +that at dinner and all that evening Natasha was in a strange and +unnatural state. She answered questions at random, began sentences she +did not finish, and laughed at everything. + +After tea Sonya noticed a housemaid at Natasha's door timidly +waiting to let her pass. She let the girl go in, and then listening at +the door learned that another letter had been delivered. + +Then suddenly it became clear to Sonya that Natasha had some +dreadful plan for that evening. Sonya knocked at her door. Natasha did +not let her in. + +"She will run away with him!" thought Sonya. "She is capable of +anything. There was something particularly pathetic and resolute in +her face today. She cried as she said good-by to Uncle," Sonya +remembered. "Yes, that's it, she means to elope with him, but what +am I to do?" thought she, recalling all the signs that clearly +indicated that Natasha had some terrible intention. "The count is +away. What am I to do? Write to Kuragin demanding an explanation? +But what is there to oblige him to reply? Write to Pierre, as Prince +Andrew asked me to in case of some misfortune?... But perhaps she +really has already refused Bolkonski--she sent a letter to Princess +Mary yesterday. And Uncle is away...." To tell Marya Dmitrievna who +had such faith in Natasha seemed to Sonya terrible. "Well, anyway," +thought Sonya as she stood in the dark passage, "now or never I must +prove that I remember the family's goodness to me and that I love +Nicholas. Yes! If I don't sleep for three nights I'll not leave this +passage and will hold her back by force and will and not let the +family be disgraced," thought she. + + + + + +CHAPTER XVI + + +Anatole had lately moved to Dolokhov's. The plan for Natalie +Rostova's abduction had been arranged and the preparations made by +Dolokhov a few days before, and on the day that Sonya, after listening +at Natasha's door, resolved to safeguard her, it was to have been +put into execution. Natasha had promised to come out to Kuragin at the +back porch at ten that evening. Kuragin was to put her into a troyka +he would have ready and to drive her forty miles to the village of +Kamenka, where an unfrocked priest was in readiness to perform a +marriage ceremony over them. At Kamenka a relay of horses was to +wait which would take them to the Warsaw highroad, and from there they +would hasten abroad with post horses. + +Anatole had a passport, an order for post horses, ten thousand +rubles he had taken from his sister and another ten thousand +borrowed with Dolokhov's help. + +Two witnesses for the mock marriage--Khvostikov, a retired petty +official whom Dolokhov made use of in his gambling transactions, and +Makarin, a retired hussar, a kindly, weak fellow who had an +unbounded affection for Kuragin--were sitting at tea in Dolokhov's +front room. + +In his large study, the walls of which were hung to the ceiling with +Persian rugs, bearskins, and weapons, sat Dolokhov in a traveling +cloak and high boots, at an open desk on which lay abacus and some +bundles of paper money. Anatole, with uniform unbuttoned, walked to +and fro from the room where the witnesses were sitting, through the +study to the room behind, where his French valet and others were +packing the last of his things. Dolokhov was counting the money and +noting something down. + +"Well," he said, "Khvostikov must have two thousand." + +"Give it to him, then," said Anatole. + +"Makarka" (their name for Makarin) "will go through fire and water +for you for nothing. So here are our accounts all settled," said +Dolokhov, showing him the memorandum. "Is that right?" + +"Yes, of course," returned Anatole, evidently not listening to +Dolokhov and looking straight before him with a smile that did not +leave his face. + +Dolokhov banged down the or of his and turned to Anatole with an +ironic smile: + +"Do you know? You'd really better drop it all. There's still time!" + +"Fool," retorted Anatole. "Don't talk nonsense! If you only +knew... it's the devil knows what!" + +"No, really, give it up!" said Dolokhov. "I am speaking seriously. +It's no joke, this plot you've hatched." + +"What, teasing again? Go to the devil! Eh?" said Anatole, making a +grimace. "Really it's no time for your stupid jokes," and he left +the room. + +Dolokhov smiled contemptuously and condescendingly when Anatole +had gone out. + +"You wait a bit," he called after him. "I'm not joking, I'm +talking sense. Come here, come here!" + +Anatole returned and looked at Dolokhov, trying to give him his +attention and evidently submitting to him involuntarily. + +"Now listen to me. I'm telling you this for the last time. Why +should I joke about it? Did I hinder you? Who arranged everything +for you? Who found the priest and got the passport? Who raised the +money? I did it all." + +"Well, thank you for it. Do you think I am not grateful?" And +Anatole sighed and embraced Dolokhov. + +"I helped you, but all the same I must tell you the truth; it is a +dangerous business, and if you think about it--a stupid business. +Well, you'll carry her off--all right! Will they let it stop at +that? It will come out that you're already married. Why, they'll +have you in the criminal court...." + +"Oh, nonsense, nonsense!" Anatole ejaculated and again made a +grimace. "Didn't I explain to you? What?" And Anatole, with the +partiality dull-witted people have for any conclusion they have +reached by their own reasoning, repeated the argument he had already +put to Dolokhov a hundred times. "Didn't I explain to you that I +have come to this conclusion: if this marriage is invalid," he went +on, crooking one finger, "then I have nothing to answer for; but if it +is valid, no matter! Abroad no one will know anything about it. +Isn't that so? And don't talk to me, don't, don't." + +"Seriously, you'd better drop it! You'll only get yourself into a +mess!" + +"Go to the devil!" cried Anatole and, clutching his hair, left the +room, but returned at once and dropped into an armchair in front of +Dolokhov with his feet turned under him. "It's the very devil! What? +Feel how it beats!" He took Dolokhov's hand and put it on his heart. +"What a foot, my dear fellow! What a glance! A goddess!" he added in +French. "What?" + +Dolokhov with a cold smile and a gleam in his handsome insolent eyes +looked at him--evidently wishing to get some more amusement out of +him. + +"Well and when the money's gone, what then?" + +"What then? Eh?" repeated Anatole, sincerely perplexed by a +thought of the future. "What then?... Then, I don't know.... But why +talk nonsense!" He glanced at his watch. "It's time!" + +Anatole went into the back room. + +"Now then! Nearly ready? You're dawdling!" he shouted to the +servants. + +Dolokhov put away the money, called a footman whom he ordered to +bring something for them to eat and drink before the journey, and went +into the room where Khvostikov and Makarin were sitting. + +Anatole lay on the sofa in the study leaning on his elbow and +smiling pensively, while his handsome lips muttered tenderly to +himself. + +"Come and eat something. Have a drink!" Dolokhov shouted to him from +the other room. + +"I don't want to," answered Anatole continuing to smile. + +"Come! Balaga is here." + +Anatole rose and went into the dining room. Balaga was a famous +troyka driver who had known Dolokhov and Anatole some six years and +had given them good service with his troykas. More than once when +Anatole's regiment was stationed at Tver he had taken him from Tver in +the evening, brought him to Moscow by daybreak, and driven him back +again the next night. More than once he had enabled Dolokhov to escape +when pursued. More than once he had driven them through the town +with gypsies and "ladykins" as he called the cocottes. More than +once in their service he had run over pedestrians and upset vehicles +in the streets of Moscow and had always been protected from the +consequences by "my gentlemen" as he called them. He had ruined more +than one horse in their service. More than once they had beaten him, +and more than once they had made him drunk on champagne and Madeira, +which he loved; and he knew more than one thing about each of them +which would long ago have sent an ordinary man to Siberia. They +often called Balaga into their orgies and made him drink and dance +at the gypsies', and more than one thousand rubles of their money +had passed through his hands. In their service he risked his skin +and his life twenty times a year, and in their service had lost more +horses than the money he had from them would buy. But he liked them; +liked that mad driving at twelve miles an hour, liked upsetting a +driver or running down a pedestrian, and flying at full gallop through +the Moscow streets. He liked to hear those wild, tipsy shouts behind +him: "Get on! Get on!" when it was impossible to go any faster. He +liked giving a painful lash on the neck to some peasant who, more dead +than alive, was already hurrying out of his way. "Real gentlemen!" +he considered them. + +Anatole and Dolokhov liked Balaga too for his masterly driving and +because he liked the things they liked. With others Balaga +bargained, charging twenty-five rubles for a two hours' drive, and +rarely drove himself, generally letting his young men do so. But +with "his gentlemen" he always drove himself and never demanded +anything for his work. Only a couple of times a year--when he knew +from their valets that they had money in hand--he would turn up of a +morning quite sober and with a deep bow would ask them to help him. +The gentlemen always made him sit down. + +"Do help me out, Theodore Ivanych, sir," or "your excellency," he +would say. "I am quite out of horses. Let me have what you can to go +to the fair." + +And Anatole and Dolokhov, when they had money, would give him a +thousand or a couple of thousand rubles. + +Balaga was a fair-haired, short, and snub-nosed peasant of about +twenty-seven; red-faced, with a particularly red thick neck, +glittering little eyes, and a small beard. He wore a fine, +dark-blue, silk-lined cloth coat over a sheepskin. + +On entering the room now he crossed himself, turning toward the +front corner of the room, and went up to Dolokhov, holding out a +small, black hand. + +"Theodore Ivanych!" he said, bowing. + +"How d'you do, friend? Well, here he is!" + +"Good day, your excellency!" he said, again holding out his hand +to Anatole who had just come in. + +"I say, Balaga," said Anatole, putting his hands on the man's +shoulders, "do you care for me or not? Eh? Now, do me a service.... +What horses have you come with? Eh?" + +"As your messenger ordered, your special beasts," replied Balaga. + +"Well, listen, Balaga! Drive all three to death but get me there +in three hours. Eh?" + +"When they are dead, what shall I drive?" said Balaga with a wink. + +"Mind, I'll smash your face in! Don't make jokes!" cried Anatole, +suddenly rolling his eyes. + +"Why joke?" said the driver, laughing. "As if I'd grudge my +gentlemen anything! As fast as ever the horses can gallop, so fast +we'll go!" + +"Ah!" said Anatole. "Well, sit down." + +"Yes, sit down!" said Dolokhov. + +"I'll stand, Theodore Ivanych." + +"Sit down; nonsense! Have a drink!" said Anatole, and filled a large +glass of Madeira for him. + +The driver's eyes sparkled at the sight of the wine. After +refusing it for manners' sake, he drank it and wiped his mouth with +a red silk handkerchief he took out of his cap. + +"And when are we to start, your excellency?" + +"Well..." Anatole looked at his watch. "We'll start at once. Mind, +Balaga! You'll get there in time? Eh?" + +"That depends on our luck in starting, else why shouldn't we be +there in time?" replied Balaga. "Didn't we get you to Tver in seven +hours? I think you remember that, your excellency?" + +"Do you know, one Christmas I drove from Tver," said Anatole, +smilingly at the recollection and turning to Makarin who gazed +rapturously at him with wide-open eyes. "Will you believe it, Makarka, +it took one's breath away, the rate we flew. We came across a train of +loaded sleighs and drove right over two of them. Eh?" + +"Those were horses!" Balaga continued the tale. "That time I'd +harnessed two young side horses with the bay in the shafts," he went +on, turning to Dolokhov. "Will you believe it, Theodore Ivanych, those +animals flew forty miles? I couldn't hold them in, my hands grew +numb in the sharp frost so that I threw down the reins--'Catch hold +yourself, your excellency!' says I, and I just tumbled on the bottom +of the sleigh and sprawled there. It wasn't a case of urging them +on, there was no holding them in till we reached the place. The devils +took us there in three hours! Only the near one died of it." + + + + + +CHAPTER XVII + + +Anatole went out of the room and returned a few minutes later +wearing a fur coat girt with a silver belt, and a sable cap jauntily +set on one side and very becoming to his handsome face. Having +looked in a mirror, and standing before Dolokhov in the same pose he +had assumed before it, he lifted a glass of wine. + +"Well, good-by, Theodore. Thank you for everything and farewell!" +said Anatole. "Well, comrades and friends..." he considered for a +moment "...of my youth, farewell!" he said, turning to Makarin and the +others. + +Though they were all going with him, Anatole evidently wished to +make something touching and solemn out of this address to his +comrades. He spoke slowly in a loud voice and throwing out his chest +slightly swayed one leg. + +"All take glasses; you too, Balaga. Well, comrades and friends of my +youth, we've had our fling and lived and reveled. Eh? And now, when +shall we meet again? I am going abroad. We have had a good time--now +farewell, lads! To our health! Hurrah!..." he cried, and emptying +his glass flung it on the floor. + +"To your health!" said Balaga who also emptied his glass, and +wiped his mouth with his handkerchief. + +Makarin embraced Anatole with tears in his eyes. + +"Ah, Prince, how sorry I am to part from you! + +"Let's go. Let's go!" cried Anatole. + +Balaga was about to leave the room. + +"No, stop!" said Anatole. "Shut the door; we have first to sit down. +That's the way." + +They shut the door and all sat down. + +"Now, quick march, lads!" said Anatole, rising. + +Joseph, his valet, handed him his sabretache and saber, and they all +went out into the vestibule. + +"And where's the fur cloak?" asked Dolokhov. "Hey, Ignatka! Go to +Matrena Matrevna and ask her for the sable cloak. I have heard what +elopements are like," continued Dolokhov with a wink. "Why, she'll +rush out more dead than alive just in the things she is wearing; if +you delay at all there'll be tears and 'Papa' and 'Mamma,' and she's +frozen in a minute and must go back--but you wrap the fur cloak +round her first thing and carry her to the sleigh." + +The valet brought a woman's fox-lined cloak. + +"Fool, I told you the sable one! Hey, Matrena, the sable!" he +shouted so that his voice rang far through the rooms. + +A handsome, slim, and pale-faced gypsy girl with glittering black +eyes and curly blue-black hair, wearing a red shawl, ran out with a +sable mantle on her arm. + +"Here, I don't grudge it--take it!" she said, evidently afraid of +her master and yet regretful of her cloak. + +Dolokhov, without answering, took the cloak, threw it over +Matrena, and wrapped her up in it. + +"That's the way," said Dolokhov, "and then so!" and he turned the +collar up round her head, leaving only a little of the face uncovered. +"And then so, do you see?" and he pushed Anatole's head forward to +meet the gap left by the collar, through which Matrena's brilliant +smile was seen. + +"Well, good-by, Matrena," said Anatole, kissing her. "Ah, my +revels here are over. Remember me to Steshka. There, good-by! Good-by, +Matrena, wish me luck!" + +"Well, Prince, may God give you great luck!" said Matrena in her +gypsy accent. + +Two troykas were standing before the porch and two young drivers +were holding the horses. Balaga took his seat in the front one and +holding his elbows high arranged the reins deliberately. Anatole and +Dolokhov got in with him. Makarin, Khvostikov, and a valet seated +themselves in the other sleigh. + +"Well, are you ready?" asked Balaga. + +"Go!" he cried, twisting the reins round his hands, and the troyka +tore down the Nikitski Boulevard. + +"Tproo! Get out of the way! Hi!... Tproo!..." The shouting of Balaga +and of the sturdy young fellow seated on the box was all that could be +heard. On the Arbat Square the troyka caught against a carriage; +something cracked, shouts were heard, and the troyka flew along the +Arbat Street. + +After taking a turn along the Podnovinski Boulevard, Balaga began to +rein in, and turning back drew up at the crossing of the old +Konyusheny Street. + +The young fellow on the box jumped down to hold the horses and +Anatole and Dolokhov went along the pavement. When they reached the +gate Dolokhov whistled. The whistle was answered, and a maidservant +ran out. + +"Come into the courtyard or you'll be seen; she'll come out +directly," said she. + +Dolokhov stayed by the gate. Anatole followed the maid into the +courtyard, turned the corner, and ran up into the porch. + +He was met by Gabriel, Marya Dmitrievna's gigantic footman. + +"Come to the mistress, please," said the footman in his deep bass, +intercepting any retreat. + +"To what Mistress? Who are you?" asked Anatole in a breathless +whisper. + +"Kindly step in, my orders are to bring you in." + +"Kuragin! Come back!" shouted Dolokhov. "Betrayed! Back!" + +Dolokhov, after Anatole entered, had remained at the wicket gate and +was struggling with the yard porter who was trying to lock it. With +a last desperate effort Dolokhov pushed the porter aside, and when +Anatole ran back seized him by the arm, pulled him through the wicket, +and ran back with him to the troyka. + + + + + +CHAPTER XVIII + + +Marya Dmitrievna, having found Sonya weeping in the corridor, made +her confess everything, and intercepting the note to Natasha she +read it and went into Natasha's room with it in her hand. + +"You shameless good-for-nothing!" said she. "I won't hear a word." + +Pushing back Natasha who looked at her with astonished but +tearless eyes, she locked her in; and having given orders to the +yard porter to admit the persons who would be coming that evening, but +not to let them out again, and having told the footman to bring them +up to her, she seated herself in the drawing room to await the +abductors. + +When Gabriel came to inform her that the men who had come had run +away again, she rose frowning, and clasping her hands behind her paced +through the rooms a long time considering what she should do. Toward +midnight she went to Natasha's room fingering the key in her pocket. +Sonya was sitting sobbing in the corridor. "Marya Dmitrievna, for +God's sake let me in to her!" she pleaded, but Marya Dmitrievna +unlocked the door and went in without giving her an answer.... +"Disgusting, abominable... In my house... horrid girl, hussy! I'm only +sorry for her father!" thought she, trying to restrain her wrath. +"Hard as it may be, I'll tell them all to hold their tongues and +will hide it from the count." She entered the room with resolute +steps. Natasha lying on the sofa, her head hidden in her hands, and +she did not stir. She was in just the same position in which Marya +Dmitrievna had left her. + +"A nice girl! Very nice!" said Marya Dmitrievna. "Arranging meetings +with lovers in my house! It's no use pretending: you listen when I +speak to you!" And Marya Dmitrievna touched her arm. "Listen when when +I speak! You've disgraced yourself like the lowest of hussies. I'd +treat you differently, but I'm sorry for your father, so I will +conceal it." + +Natasha did not change her position, but her whole body heaved +with noiseless, convulsive sobs which choked her. Marya Dmitrievna +glanced round at Sonya and seated herself on the sofa beside Natasha. + +"It's lucky for him that he escaped me; but I'll find him!" she said +in her rough voice. "Do you hear what I am saying or not?" she added. + +She put her large hand under Natasha's face and turned it toward +her. Both Marya Dmitrievna and Sonya were amazed when they saw how +Natasha looked. Her eyes were dry and glistening, her lips compressed, +her cheeks sunken. + +"Let me be!... What is it to me?... I shall die!" she muttered, +wrenching herself from Marya Dmitrievna's hands with a vicious +effort and sinking down again into her former position. + +"Natalie!" said Marya Dmitrievna. "I wish for your good. Lie +still, stay like that then, I won't touch you. But listen. I won't +tell you how guilty you are. You know that yourself. But when your +father comes back tomorrow what am I to tell him? Eh?" + +Again Natasha's body shook with sobs. + +"Suppose he finds out, and your brother, and your betrothed?" + +"I have no betrothed: I have refused him!" cried Natasha. + +"That's all the same," continued Dmitrievna. "If they hear of +this, will they let it pass? He, your father, I know him... if he +challenges him to a duel will that be all right? Eh?" + +"Oh, let me be! Why have you interfered at all? Why? Why? Who +asked you to?" shouted Natasha, raising herself on the sofa and +looking malignantly at Marya Dmitrievna. + +"But what did you want?" cried Marya Dmitrievna, growing angry +again. "Were you kept under lock and key? Who hindered his coming to +the house? Why carry you off as if you were some gypsy singing +girl?... Well, if he had carried you off... do you think they wouldn't +have found him? Your father, or brother, or your betrothed? And he's a +scoundrel, a wretch--that's a fact!" + +"He is better than any of you!" exclaimed Natasha getting up. "If +you hadn't interfered... Oh, my God! What is it all? What is it? +Sonya, why?... Go away!" + +And she burst into sobs with the despairing vehemence with which +people bewail disasters they feel they have themselves occasioned. +Marya Dmitrievna was to speak again but Natasha cried out: + +"Go away! Go away! You all hate and despise me!" and she threw +herself back on the sofa. + +Marya Dmitrievna went on admonishing her for some time, enjoining on +her that it must all be kept from her father and assuring her that +nobody would know anything about it if only Natasha herself would +undertake to forget it all and not let anyone see that something had +happened. Natasha did not reply, nor did she sob any longer, but she +grew cold and had a shivering fit. Marya Dmitrievna put a pillow under +her head, covered her with two quilts, and herself brought her some +lime-flower water, but Natasha did not respond to her. + +"Well, let her sleep," said Marya Dmitrievna as she went of the room +supposing Natasha to be asleep. + +But Natasha was not asleep; with pale face and fixed wide-open +eyes she looked straight before her. All that night she did not +sleep or weep and did not speak to Sonya who got up and went to her +several times. + +Next day Count Rostov returned from his estate near Moscow in time +for lunch as he had promised. He was in very good spirits; the +affair with the purchaser was going on satisfactorily, and there was +nothing to keep him any longer in Moscow, away from the countess +whom he missed. Marya Dmitrievna met him and told him that Natasha had +been very unwell the day before and that they had sent for the doctor, +but that she was better now. Natasha had not left her room that +morning. With compressed and parched lips and dry fixed eyes, she +sat at the window, uneasily watching the people who drove past and +hurriedly glancing round at anyone who entered the room. She was +evidently expecting news of him and that he would come or would +write to her. + +When the count came to see her she turned anxiously round at the +sound of a man's footstep, and then her face resumed its cold and +malevolent expression. She did not even get up to greet him. "What +is the matter with you, my angel? Are you ill?" asked the count. + +After a moment's silence Natasha answered: "Yes, ill." + +In reply to the count's anxious inquiries as to why she was so +dejected and whether anything had happened to her betrothed, she +assured him that nothing had happened and asked him not to worry. +Marya Dmitrievna confirmed Natasha's assurances that nothing had +happened. From the pretense of illness, from his daughter's +distress, and by the embarrassed faces of Sonya and Marya +Dmitrievna, the count saw clearly that something had gone wrong during +his absence, but it was so terrible for him to think that anything +disgraceful had happened to his beloved daughter, and he so prized his +own cheerful tranquillity, that he avoided inquiries and tried to +assure himself that nothing particularly had happened; and he was only +dissatisfied that her indisposition delayed their return to the +country. + + + + + +CHAPTER XIX + + +From the day his wife arrived in Moscow Pierre had been intending to +go away somewhere, so as not to be near her. Soon after the Rostovs +came to Moscow the effect Natasha had on him made him hasten to +carry out his intention. He went to Tver to see Joseph Alexeevich's +widow, who had long since promised to hand over to him some papers +of her deceased husband's. + +When he returned to Moscow Pierre was handed a letter from Marya +Dmitrievna asking him to come and see her on a matter of great +importance relating to Andrew Bolkonski and his betrothed. Pierre +had been avoiding Natasha because it seemed to him that his feeling +for her was stronger than a married man's should be for his friend's +fiancee. Yet some fate constantly threw them together. + +"What can have happened? And what can they want with me?" thought he +as he dressed to go to Marya Dmitrievna's. "If only Prince Andrew +would hurry up and come and marry her!" thought he on his way to the +house. + +On the Tverskoy Boulevard a familiar voice called to him. + +"Pierre! Been back long?" someone shouted. Pierre raised his head. +In a sleigh drawn by two gray trotting-horses that were bespattering +the dashboard with snow, Anatole and his constant companion Makarin +dashed past. Anatole was sitting upright in the classic pose of +military dandies, the lower part of his face hidden by his beaver +collar and his head slightly bent. His face was fresh and rosy, his +white-plumed hat, tilted to one side, disclosed his curled and pomaded +hair besprinkled with powdery snow. + +"Yes, indeed, that's a true sage," thought Pierre. "He sees +nothing beyond the pleasure of the moment, nothing troubles him and so +he is always cheerful, satisfied, and serene. What wouldn't I give +to be like him!" he thought enviously. + +In Marya Dmitrievna's anteroom the footman who helped him off with +his fur coat said that the mistress asked him to come to her bedroom. + +When he opened the ballroom door Pierre saw Natasha sitting at the +window, with a thin, pale, and spiteful face. She glanced round at +him, frowned, and left the room with an expression of cold dignity. + +"What has happened?" asked Pierre, entering Marya Dmitrievna's room. + +"Fine doings!" answered Dmitrievna. "For fifty-eight years have I +lived in this world and never known anything so disgraceful!" + +And having put him on his honor not to repeat anything she told him, +Marya Dmitrievna informed him that Natasha had refused Prince Andrew +without her parents' knowledge and that the cause of this was +Anatole Kuragin into whose society Pierre's wife had thrown her and +with whom Natasha had tried to elope during her father's absence, in +order to be married secretly. + +Pierre raised his shoulders and listened open-mouthed to what was +told him, scarcely able to believe his own ears. That Prince +Andrew's deeply loved affianced wife--the same Natasha Rostova who +used to be so charming--should give up Bolkonski for that fool Anatole +who was already secretly married (as Pierre knew), and should be so in +love with him as to agree to run away with him, was something Pierre +could not conceive and could not imagine. + +He could not reconcile the charming impression he had of Natasha, +whom he had known from a child, with this new conception of her +baseness, folly, and cruelty. He thought of his wife. "They are all +alike!" he said to himself, reflecting that he was not the only man +unfortunate enough to be tied to a bad woman. But still he pitied +Prince Andrew to the point of tears and sympathized with his wounded +pride, and the more he pitied his friend the more did he think with +contempt and even with disgust of that Natasha who had just passed him +in the ballroom with such a look of cold dignity. He did not know that +Natasha's soul was overflowing with despair, shame, and humiliation, +and that it was not her fault that her face happened to assume an +expression of calm dignity and severity. + +"But how get married?" said Pierre, in answer to Marya Dmitrievna. +"He could not marry--he is married!" + +"Things get worse from hour to hour!" ejaculated Marya Dmitrievna. +"A nice youth! What a scoundrel! And she's expecting him--expecting +him since yesterday. She must be told! Then at least she won't go on +expecting him." + +After hearing the details of Anatole's marriage from Pierre, and +giving vent to her anger against Anatole in words of abuse, Marya +Dmitrievna told Pierre why she had sent for him. She was afraid that +the count or Bolkonski, who might arrive at any moment, if they knew +of this affair (which she hoped to hide from them) might challenge +Anatole to a duel, and she therefore asked Pierre to tell his +brother-in-law in her name to leave Moscow and not dare to let her set +eyes on him again. Pierre--only now realizing the danger to the old +count, Nicholas, and Prince Andrew--promised to do as she wished. +Having briefly and exactly explained her wishes to him, she let him go +to the drawing room. + +"Mind, the count knows nothing. Behave as if you know nothing +either," she said. "And I will go and tell her it is no use +expecting him! And stay to dinner if you care to!" she called after +Pierre. + +Pierre met the old count, who seemed nervous and upset. That morning +Natasha had told him that she had rejected Bolkonski. + +"Troubles, troubles, my dear fellow!" he said to Pierre. "What +troubles one has with these girls without their mother! I do so regret +having come here.... I will be frank with you. Have you heard she +has broken off her engagement without consulting anybody? It's true +this engagement never was much to my liking. Of course he is an +excellent man, but still, with his father's disapproval they +wouldn't have been happy, and Natasha won't lack suitors. Still, it +has been going on so long, and to take such a step without father's or +mother's consent! And now she's ill, and God knows what! It's hard, +Count, hard to manage daughters in their mother's absence...." + +Pierre saw that the count was much upset and tried to change the +subject, but the count returned to his troubles. + +Sonya entered the room with an agitated face. + +"Natasha is not quite well; she's in her room and would like to +see you. Marya Dmitrievna is with her and she too asks you to come." + +"Yes, you are a great friend of Bolkonski's, no doubt she wants to +send him a message," said the count. "Oh dear! Oh dear! How happy it +all was!" + +And clutching the spare gray locks on his temples the count left the +room. + +When Marya Dmitrievna told Natasha that Anatole was married, Natasha +did not wish to believe it and insisted on having it confirmed by +Pierre himself. Sonya told Pierre this as she led him along the +corridor to Natasha's room. + +Natasha, pale and stern, was sitting beside Marya Dmitrievna, and +her eyes, glittering feverishly, met Pierre with a questioning look +the moment he entered. She did not smile or nod, but only gazed +fixedly at him, and her look asked only one thing: was he a friend, or +like the others an enemy in regard to Anatole? As for Pierre, he +evidently did not exist for her. + +"He knows all about it," said Marya Dmitrievna pointing to Pierre +and addressing Natasha. "Let him tell you whether I have told the +truth." + +Natasha looked from one to the other as a hunted and wounded +animal looks at the approaching dogs and sportsmen. + +"Natalya Ilynichna," Pierre began, dropping his eyes with a +feeling of pity for her and loathing for the thing he had to do, +"whether it is true or not should make no difference to you, +because..." + +"Then it is not true that he's married!" + +"Yes, it is true." + +"Has he been married long?" she asked. "On your honor?..." + +Pierre gave his word of honor. + +"Is he still here?" she asked, quickly. + +"Yes, I have just seen him." + +She was evidently unable to speak and made a sign with her hands +that they should leave her alone. + + + + + +CHAPTER XX + + +Pierre did not stay for dinner, but left the room and went away at +once. He drove through the town seeking Anatole Kuragin, at the +thought of whom now the blood rushed to his heart and he felt a +difficulty in breathing. He was not at the ice hills, nor at the +gypsies', nor at Komoneno's. Pierre drove to the Club. In the Club all +was going on as usual. The members who were assembling for dinner were +sitting about in groups; they greeted Pierre and spoke of the town +news. The footman having greeted him, knowing his habits and his +acquaintances, told him there was a place left for him in the small +dining room and that Prince Michael Zakharych was in the library, +but Paul Timofeevich had not yet arrived. One of Pierre's +acquaintances, while they were talking about the weather, asked if +he had heard of Kuragin's abduction of Rostova which was talked of +in the town, and was it true? Pierre laughed and said it was +nonsense for he had just come from the Rostovs'. He asked everyone +about Anatole. One man told him he had not come yet, and another +that he was coming to dinner. Pierre felt it strange to see this calm, +indifferent crowd of people unaware of what was going on in his +soul. He paced through the ballroom, waited till everyone had come, +and as Anatole had not turned up did not stay for dinner but drove +home. + +Anatole, for whom Pierre was looking, dined that day with +Dolokhov, consulting him as to how to remedy this unfortunate +affair. It seemed to him essential to see Natasha. In the evening he +drove to his sister's to discuss with her how to arrange a meeting. +When Pierre returned home after vainly hunting all over Moscow, his +valet informed him that Prince Anatole was with the countess. The +countess' drawing room was full of guests. + +Pierre without greeting his wife whom he had not seen since his +return--at that moment she was more repulsive to him than ever- +entered the drawing room and seeing Anatole went up to him. + +"Ah, Pierre," said the countess going up to her husband. "You +don't know what a plight our Anatole..." + +She stopped, seeing in the forward thrust of her husband's head, +in his glowing eyes and his resolute gait, the terrible indications of +that rage and strength which she knew and had herself experienced +after his duel with Dolokhov. + +"Where you are, there is vice and evil!" said Pierre to his wife. +"Anatole, come with me! I must speak to you," he added in French. + +Anatole glanced round at his sister and rose submissively, ready +to follow Pierre. Pierre, taking him by the arm, pulled him toward +himself and was leading him from the room. + +"If you allow yourself in my drawing room..." whispered Helene, +but Pierre did not reply and went out of the room. + +Anatole followed him with his usual jaunty step but his face +betrayed anxiety. + +Having entered his study Pierre closed the door and addressed +Anatole without looking at him. + +"You promised Countess Rostova to marry her and were about to +elope with her, is that so?" + +"Mon cher," answered Anatole (their whole conversation was in +French), "I don't consider myself bound to answer questions put to +me in that tone." + +Pierre's face, already pale, became distorted by fury. He seized +Anatole by the collar of his uniform with his big hand and shook him +from side to side till Anatole's face showed a sufficient degree of +terror. + +"When I tell you that I must talk to you!..." repeated Pierre. + +"Come now, this is stupid. What?" said Anatole, fingering a button +of his collar that had been wrenched loose with a bit of the cloth. + +"You're a scoundrel and a blackguard, and I don't know what deprives +me from the pleasure of smashing your head with this!" said Pierre, +expressing himself so artificially because he was talking French. + +He took a heavy paperweight and lifted it threateningly, but at once +put it back in its place. + +"Did you promise to marry her?" + +"I... I didn't think of it. I never promised, because..." + +Pierre interrupted him. + +"Have you any letters of hers? Any letters?" he said, moving +toward Anatole. + +Anatole glanced at him and immediately thrust his hand into his +pocket and drew out his pocketbook. + +Pierre took the letter Anatole handed him and, pushing aside a table +that stood in his way, threw himself on the sofa. + +"I shan't be violent, don't be afraid!" said Pierre in answer to a +frightened gesture of Anatole's. "First, the letters," said he, as +if repeating a lesson to himself. "Secondly," he continued after a +short pause, again rising and again pacing the room, "tomorrow you +must get out of Moscow." + +"But how can I?..." + +"Thirdly," Pierre continued without listening to him, "you must +never breathe a word of what has passed between you and Countess +Rostova. I know I can't prevent your doing so, but if you have a spark +of conscience..." Pierre paced the room several times in silence. + +Anatole sat at a table frowning and biting his lips. + +"After all, you must understand that besides your pleasure there +is such a thing as other people's happiness and peace, and that you +are ruining a whole life for the sake of amusing yourself! Amuse +yourself with women like my wife--with them you are within your +rights, for they know what you want of them. They are armed against +you by the same experience of debauchery; but to promise a maid to +marry her... to deceive, to kidnap.... Don't you understand that it is +as mean as beating an old man or a child?..." + +Pierre paused and looked at Anatole no longer with an angry but with +a questioning look. + +"I don't know about that, eh?" said Anatole, growing more +confident as Pierre mastered his wrath. "I don't know that and don't +want to," he said, not looking at Pierre and with a slight tremor of +his lower jaw, "but you have used such words to me--'mean' and so +on--which as a man of honor I can't allow anyone to use." + +Pierre glanced at him with amazement, unable to understand what he +wanted. + +"Though it was tete-a-tete," Anatole continued, "still I can't..." + +"Is it satisfaction you want?" said Pierre ironically. + +"You could at least take back your words. What? If you want me to do +as you wish, eh?" + +"I take them back, I take them back!" said Pierre, "and I ask you to +forgive me." Pierre involuntarily glanced at the loose button. "And if +you require money for your journey..." + +Anatole smiled. The expression of that base and cringing smile, +which Pierre knew so well in his wife, revolted him. + +"Oh, vile and heartless brood!" he exclaimed, and left the room. + +Next day Anatole left for Petersburg. + + + + + +CHAPTER XXI + + +Pierre drove to Marya Dmitrievna's to tell her of the fulfillment of +her wish that Kuragin should be banished from Moscow. The whole +house was in a state of alarm and commotion. Natasha was very ill, +having, as Marya Dmitrievna told him in secret, poisoned herself the +night after she had been told that Anatole was married, with some +arsenic she had stealthily procured. After swallowing a little she had +been so frightened that she woke Sonya and told her what she had done. +The necessary antidotes had been administered in time and she was +now out of danger, though still so weak that it was out of the +question to move her to the country, and so the countess had been sent +for. Pierre saw the distracted count, and Sonya, who had a +tear-stained face, but he could not see Natasha. + +Pierre dined at the club that day and heard on all sides gossip +about the attempted abduction of Rostova. He resolutely denied these +rumors, assuring everyone that nothing had happened except that his +brother-in-law had proposed to her and been refused. It seemed to +Pierre that it was his duty to conceal the whole affair and +re-establish Natasha's reputation. + +He was awaiting Prince Andrew's return with dread and went every day +to the old prince's for news of him. + +Old Prince Bolkonski heard all the rumors current in the town from +Mademoiselle Bourienne and had read the note to Princess Mary in which +Natasha had broken off her engagement. He seemed in better spirits +than usual and awaited his son with great impatience. + +Some days after Anatole's departure Pierre received a note from +Prince Andrew, informing him of his arrival and asking him to come +to see him. + +As soon as he reached Moscow, Prince Andrew had received from his +father Natasha's note to Princess Mary breaking off her engagement +(Mademoiselle Bourienne had purloined it from Princess Mary and +given it to the old prince), and he heard from him the story of +Natasha's elopement, with additions. + +Prince Andrew had arrived in the evening and Pierre came to see +him next morning. Pierre expected to find Prince Andrew in almost +the same state as Natasha and was therefore surprised on entering +the drawing room to hear him in the study talking in a loud animated +voice about some intrigue going on in Petersburg. The old prince's +voice and another now and then interrupted him. Princess Mary came out +to meet Pierre. She sighed, looking toward the door of the room +where Prince Andrew was, evidently intending to express her sympathy +with his sorrow, but Pierre saw by her face that she was glad both +at what had happened and at the way her brother had taken the news +of Natasha's faithlessness. + +"He says he expected it," she remarked. "I know his pride will not +let him express his feelings, but still he has taken it better, far +better, than I expected. Evidently it had to be...." + +"But is it possible that all is really ended?" asked Pierre. + +Princess Mary looked at him with astonishment. She did not +understand how he could ask such a question. Pierre went into the +study. Prince Andrew, greatly changed and plainly in better health, +but with a fresh horizontal wrinkle between his brows, stood in +civilian dress facing his father and Prince Meshcherski, warmly +disputing and vigorously gesticulating. The conversation was about +Speranski--the news of whose sudden exile and alleged treachery had +just reached Moscow. + +"Now he is censured and accused by all who were enthusiastic about +him a month ago," Prince Andrew was saying, "and by those who were +unable to understand his aims. To judge a man who is in disfavor and +to throw on him all the blame of other men's mistakes is very easy, +but I maintain that if anything good has been accomplished in this +reign it was done by him, by him alone." + +He paused at the sight of Pierre. His face quivered and +immediately assumed a vindictive expression. + +"Posterity will do him justice," he concluded, and at once turned to +Pierre. + +"Well, how are you? Still getting stouter?" he said with +animation, but the new wrinkle on his forehead deepened. "Yes, I am +well," he said in answer to Pierre's question, and smiled. + +To Pierre that smile said plainly: "I am well, but my health is +now of no use to anyone." + +After a few words to Pierre about the awful roads from the Polish +frontier, about people he had met in Switzerland who knew Pierre, +and about M. Dessalles, whom he had brought from abroad to be his +son's tutor, Prince Andrew again joined warmly in the conversation +about Speranski which was still going on between the two old men. + +"If there were treason, or proofs of secret relations with Napoleon, +they would have been made public," he said with warmth and haste. "I +do not, and never did, like Speranski personally, but I like justice!" + +Pierre now recognized in his friend a need with which he was only +too familiar, to get excited and to have arguments about extraneous +matters in order to stifle thoughts that were too oppressive and too +intimate. When Prince Meshcherski had left, Prince Andrew took +Pierre's arm and asked him into the room that had been assigned him. A +bed had been made up there, and some open portmanteaus and trunks +stood about. Prince Andrew went to one and took out a small casket, +from which he drew a packet wrapped in paper. He did it all silently +and very quickly. He stood up and coughed. His face was gloomy and his +lips compressed. + +"Forgive me for troubling you..." + +Pierre saw that Prince Andrew was going to speak of Natasha, and his +broad face expressed pity and sympathy. This expression irritated +Prince Andrew, and in a determined, ringing, and unpleasant tone he +continued: + +"I have received a refusal from Countess Rostova and have heard +reports of your brother-in-law having sought her hand, or something of +that kind. Is that true?" + +"Both true and untrue," Pierre began; but Prince Andrew +interrupted him. + +"Here are her letters and her portrait," said he. + +He took the packet from the table and handed it to Pierre. + +"Give this to the countess... if you see her." + +"She is very ill," said Pierre. + +"Then she is here still?" said Prince Andrew. "And Prince +Kuragin?" he added quickly. + +"He left long ago. She has been at death's door." + +"I much regret her illness," said Prince Andrew; and he smiled +like his father, coldly, maliciously, and unpleasantly. + +"So Monsieur Kuragin has not honored Countess Rostova with his +hand?" said Prince Andrew, and he snorted several times. + +"He could not marry, for he was married already," said Pierre. + +Prince Andrew laughed disagreeably, again reminding one of his +father. + +"And where is your brother-in-law now, if I may ask?" he said. + +"He has gone to Peters... But I don't know," said Pierre. + +"Well, it doesn't matter," said Prince Andrew. "Tell Countess +Rostova that she was and is perfectly free and that I wish her all +that is good." + +Pierre took the packet. Prince Andrew, as if trying to remember +whether he had something more to say, or waiting to see if Pierre +would say anything, looked fixedly at him. + +"I say, do you remember our discussion in Petersburg?" asked Pierre, +"about..." + +"Yes," returned Prince Andrew hastily. "I said that a fallen woman +should be forgiven, but I didn't say I could forgive her. I can't." + +"But can this be compared...?" said Pierre. + +Prince Andrew interrupted him and cried sharply: "Yes, ask her +hand again, be magnanimous, and so on?... Yes, that would be very +noble, but I am unable to follow in that gentleman's footsteps. If you +wish to be my friend never speak to me of that... of all that! Well, +good-by. So you'll give her the packet?" + +Pierre left the room and went to the old prince and Princess Mary. + +The old man seemed livelier than usual. Princess Mary was the same +as always, but beneath her sympathy for her brother, Pierre noticed +her satisfaction that the engagement had been broken off. Looking at +them Pierre realized what contempt and animosity they all felt for the +Rostovs, and that it was impossible in their presence even to +mention the name of her who could give up Prince Andrew for anyone +else. + +At dinner the talk turned on the war, the approach of which was +becoming evident. Prince Andrew talked incessantly, arguing now with +his father, now with the Swiss tutor Dessalles, and showing an +unnatural animation, the cause of which Pierre so well understood. + + + + + +CHAPTER XXII + + +That same evening Pierre went to the Rostovs' to fulfill the +commission entrusted to him. Natasha was in bed, the count at the +Club, and Pierre, after giving the letters to Sonya, went to Marya +Dmitrievna who was interested to know how Prince Andrew had taken +the news. Ten minutes later Sonya came to Marya Dmitrievna. + +"Natasha insists on seeing Count Peter Kirilovich," said she. + +"But how? Are we to take him up to her? The room there has not +been tidied up." + +"No, she has dressed and gone into the drawing room," said Sonya. + +Marya Dmitrievna only shrugged her shoulders. + +"When will her mother come? She has worried me to death! Now mind, +don't tell her everything!" said she to Pierre. "One hasn't the +heart to scold her, she is so much to be pitied, so much to be +pitied." + +Natasha was standing in the middle of the drawing room, emaciated, +with a pale set face, but not at all shamefaced as Pierre expected +to find her. When he appeared at the door she grew flurried, evidently +undecided whether to go to meet him or to wait till he came up. + +Pierre hastened to her. He thought she would give him her hand as +usual; but she, stepping up to him, stopped, breathing heavily, her +arms hanging lifelessly just in the pose she used to stand in when she +went to the middle of the ballroom to sing, but with quite a different +expression of face. + +"Peter Kirilovich," she began rapidly, "Prince Bolkonski was your +friend--is your friend," she corrected herself. (It seemed to her that +everything that had once been must now be different.) "He told me once +to apply to you..." + +Pierre sniffed as he looked at her, but did not speak. Till then +he had reproached her in his heart and tried to despise her, but he +now felt so sorry for her that there was no room in his soul for +reproach. + +"He is here now: tell him... to for... forgive me!" She stopped +and breathed still more quickly, but did not shed tears. + +"Yes... I will tell him," answered Pierre; "but..." + +He did not know what to say. + +Natasha was evidently dismayed at the thought of what he might think +she had meant. + +"No, I know all is over," she said hurriedly. "No, that can never +be. I'm only tormented by the wrong I have done him. Tell him only +that I beg him to forgive, forgive, forgive me for everything...." + +She trembled all over and sat down on a chair. + +A sense of pity he had never before known overflowed Pierre's heart. + +"I will tell him, I will tell him everything once more," said +Pierre. "But... I should like to know one thing...." + +"Know what?" Natasha's eyes asked. + +"I should like to know, did you love..." Pierre did not know how +to refer to Anatole and flushed at the thought of him--"did you love +that bad man?" + +"Don't call him bad!" said Natasha. "But I don't know, don't know at +all...." + +She began to cry and a still greater sense of pity, tenderness, +and love welled up in Pierre. He felt the tears trickle under his +spectacles and hoped they would not be noticed. + +"We won't speak of it any more, my dear," said Pierre, and his +gentle, cordial tone suddenly seemed very strange to Natasha. + +"We won't speak of it, my dear--I'll tell him everything; but one +thing I beg of you, consider me your friend and if you want help, +advice, or simply to open your heart to someone--not now, but when +your mind is clearer think of me!" He took her hand and kissed it. +"I shall be happy if it's in my power..." + +Pierre grew confused. + +"Don't speak to me like that. I am not worth it!" exclaimed +Natasha and turned to leave the room, but Pierre held her hand. + +He knew he had something more to say to her. But when he said it +he was amazed at his own words. + +"Stop, stop! You have your whole life before you," said he to her. + +"Before me? No! All is over for me," she replied with shame and +self-abasement. + + "All over?" he repeated. "If I were not myself, but the handsomest, +cleverest, and best man in the world, and were free, I would this +moment ask on my knees for your hand and your love!" + +For the first time for many days Natasha wept tears of gratitude and +tenderness, and glancing at Pierre she went out of the room. + +Pierre too when she had gone almost ran into the anteroom, +restraining tears of tenderness and joy that choked him, and without +finding the sleeves of his fur cloak threw it on and got into his +sleigh. + +"Where to now, your excellency?" asked the coachman. + +"Where to?" Pierre asked himself. "Where can I go now? Surely not to +the Club or to pay calls?" All men seemed so pitiful, so poor, in +comparison with this feeling of tenderness and love he experienced: in +comparison with that softened, grateful, last look she had given him +through her tears. + +"Home!" said Pierre, and despite twenty-two degrees of frost +Fahrenheit he threw open the bearskin cloak from his broad chest and +inhaled the air with joy. + +It was clear and frosty. Above the dirty, ill-lit streets, above the +black roofs, stretched the dark starry sky. Only looking up at the sky +did Pierre cease to feel how sordid and humiliating were all mundane +things compared with the heights to which his soul had just been +raised. At the entrance to the Arbat Square an immense expanse of dark +starry sky presented itself to his eyes. Almost in the center of it, +above the Prechistenka Boulevard, surrounded and sprinkled on all +sides by stars but distinguished from them all by its nearness to +the earth, its white light, and its long uplifted tail, shone the +enormous and brilliant comet of 1812--the comet which was said to +portend all kinds of woes and the end of the world. In Pierre, +however, that comet with its long luminous tail aroused no feeling +of fear. On the contrary he gazed joyfully, his eyes moist with tears, +at this bright comet which, having traveled in its orbit with +inconceivable velocity through immeasurable space, seemed suddenly- +like an arrow piercing the earth--to remain fixed in a chosen spot, +vigorously holding its tail erect, shining and displaying its white +light amid countless other scintillating stars. It seemed to Pierre +that this comet fully responded to what was passing in his own +softened and uplifted soul, now blossoming into a new life. + + + + + +BOOK NINE: 1812 + + + + + +CHAPTER I + + +From the close of the year 1811 intensified arming and concentrating +of the forces of Western Europe began, and in 1812 these forces- +millions of men, reckoning those transporting and feeding the army- +moved from the west eastwards to the Russian frontier, toward which +since 1811 Russian forces had been similarly drawn. On the twelfth +of June, 1812, the forces of Western Europe crossed the Russian +frontier and war began, that is, an event took place opposed to +human reason and to human nature. Millions of men perpetrated +against one another such innumerable crimes, frauds, treacheries, +thefts, forgeries, issues of false money, burglaries, incendiarisms, +and murders as in whole centuries are not recorded in the annals of +all the law courts of the world, but which those who committed them +did not at the time regard as being crimes. + +What produced this extraordinary occurrence? What were its causes? +The historians tell us with naive assurance that its causes were the +wrongs inflicted on the Duke of Oldenburg, the nonobservance of the +Continental System, the ambition of Napoleon, the firmness of +Alexander, the mistakes of the diplomatists, and so on. + +Consequently, it would only have been necessary for Metternich, +Rumyantsev, or Talleyrand, between a levee and an evening party, to +have taken proper pains and written a more adroit note, or for +Napoleon to have written to Alexander: "My respected Brother, I +consent to restore the duchy to the Duke of Oldenburg"--and there +would have been no war. + +We can understand that the matter seemed like that to +contemporaries. It naturally seemed to Napoleon that the war was +caused by England's intrigues (as in fact he said on the island of St. +Helena). It naturally seemed to members of the English Parliament that +the cause of the war was Napoleon's ambition; to the Duke of +Oldenburg, that the cause of the war was the violence done to him; +to businessmen that the cause of the way was the Continental System +which was ruining Europe; to the generals and old soldiers that the +chief reason for the war was the necessity of giving them +employment; to the legitimists of that day that it was the need of +re-establishing les bons principes, and to the diplomatists of that +time that it all resulted from the fact that the alliance between +Russia and Austria in 1809 had not been sufficiently well concealed +from Napoleon, and from the awkward wording of Memorandum No. 178. +It is natural that these and a countless and infinite quantity of +other reasons, the number depending on the endless diversity of points +of view, presented themselves to the men of that day; but to us, to +posterity who view the thing that happened in all its magnitude and +perceive its plain and terrible meaning, these causes seem +insufficient. To us it is incomprehensible that millions of +Christian men killed and tortured each other either because Napoleon +was ambitious or Alexander was firm, or because England's policy was +astute or the Duke of Oldenburg wronged. We cannot grasp what +connection such circumstances have with the actual fact of slaughter +and violence: why because the Duke was wronged, thousands of men +from the other side of Europe killed and ruined the people of Smolensk +and Moscow and were killed by them. + +To us, their descendants, who are not historians and are not carried +away by the process of research and can therefore regard the event +with unclouded common sense, an incalculable number of causes +present themselves. The deeper we delve in search of these causes +the more of them we find; and each separate cause or whole series of +causes appears to us equally valid in itself and equally false by +its insignificance compared to the magnitude of the events, and by its +impotence--apart from the cooperation of all the other coincident +causes--to occasion the event. To us, the wish or objection of this or +that French corporal to serve a second term appears as much a cause as +Napoleon's refusal to withdraw his troops beyond the Vistula and to +restore the duchy of Oldenburg; for had he not wished to serve, and +had a second, a third, and a thousandth corporal and private also +refused, there would have been so many less men in Napoleon's army and +the war could not have occurred. + +Had Napoleon not taken offense at the demand that he should withdraw +beyond the Vistula, and not ordered his troops to advance, there would +have been no war; but had all his sergeants objected to serving a +second term then also there could have been no war. Nor could there +have been a war had there been no English intrigues and no Duke of +Oldenburg, and had Alexander not felt insulted, and had there not been +an autocratic government in Russia, or a Revolution in France and a +subsequent dictatorship and Empire, or all the things that produced +the French Revolution, and so on. Without each of these causes nothing +could have happened. So all these causes--myriads of causes--coincided +to bring it about. And so there was no one cause for that +occurrence, but it had to occur because it had to. Millions of men, +renouncing their human feelings and reason, had to go from west to +east to slay their fellows, just as some centuries previously hordes +of men had come from the east to the west, slaying their fellows. + +The actions of Napoleon and Alexander, on whose words the event +seemed to hang, were as little voluntary as the actions of any soldier +who was drawn into the campaign by lot or by conscription. This +could not be otherwise, for in order that the will of Napoleon and +Alexander (on whom the event seemed to depend) should be carried +out, the concurrence of innumerable circumstances was needed without +any one of which the event could not have taken place. It was +necessary that millions of men in whose hands lay the real power- +the soldiers who fired, or transported provisions and guns--should +consent to carry out the will of these weak individuals, and should +have been induced to do so by an infinite number of diverse and +complex causes. + +We are forced to fall back on fatalism as an explanation of +irrational events (that is to say, events the reasonableness of +which we do not understand). The more we try to explain such events in +history reasonably, the more unreasonable and incomprehensible do they +become to us. + +Each man lives for himself, using his freedom to attain his personal +aims, and feels with his whole being that he can now do or abstain +from doing this or that action; but as soon as he has done it, that +action performed at a certain moment in time becomes irrevocable and +belongs to history, in which it has not a free but a predestined +significance. + +There are two sides to the life of every man, his individual life, +which is the more free the more abstract its interests, and his +elemental hive life in which he inevitably obeys laws laid down for +him. + +Man lives consciously for himself, but is an unconscious +instrument in the attainment of the historic, universal, aims of +humanity. A deed done is irrevocable, and its result coinciding in +time with the actions of millions of other men assumes an historic +significance. The higher a man stands on the social ladder, the more +people he is connected with and the more power he has over others, the +more evident is the predestination and inevitability of his every +action. + +"The king's heart is in the hands of the Lord." + +A king is history's slave. + +History, that is, the unconscious, general, hive life of mankind, +uses every moment of the life of kings as a tool for its own purposes. + +Though Napoleon at that time, in 1812, was more convinced than +ever that it depended on him, verser (ou ne pas verser) le sang de ses +peuples*--as Alexander expressed it in the last letter he wrote him- +he had never been so much in the grip of inevitable laws, which +compelled him, while thinking that he was acting on his own +volition, to perform for the hive life--that is to say, for history- +whatever had to be performed. + + +*"To shed (or not to shed) the blood of his peoples." + + +The people of the west moved eastwards to slay their fellow men, and +by the law of coincidence thousands of minute causes fitted in and +co-ordinated to produce that movement and war: reproaches for the +nonobservance of the Continental System, the Duke of Oldenburg's +wrongs, the movement of troops into Prussia--undertaken (as it +seemed to Napoleon) only for the purpose of securing an armed peace, +the French Emperor's love and habit of war coinciding with his +people's inclinations, allurement by the grandeur of the preparations, +and the expenditure on those preparations and the need of obtaining +advantages to compensate for that expenditure, the intoxicating honors +he received in Dresden, the diplomatic negotiations which, in the +opinion of contemporaries, were carried on with a sincere desire to +attain peace, but which only wounded the self-love of both sides, +and millions of other causes that adapted themselves to +the event that was happening or coincided with it. + +When an apple has ripened and falls, why does it fall? Because of +its attraction to the earth, because its stalk withers, because it +is dried by the sun, because it grows heavier, because the wind shakes +it, or because the boy standing below wants to eat it? + +Nothing is the cause. All this is only the coincidence of conditions +in which all vital organic and elemental events occur. And the +botanist who finds that the apple falls because the cellular tissue +decays and so forth is equally right with the child who stands under +the tree and says the apple fell because he wanted to eat it and +prayed for it. Equally right or wrong is he who says that Napoleon +went to Moscow because he wanted to, and perished because Alexander +desired his destruction, and he who says that an undermined hill +weighing a million tons fell because the last navvy struck it for +the last time with his mattock. In historic events the so-called great +men are labels giving names to events, and like labels they have but +the smallest connection with the event itself. + +Every act of theirs, which appears to them an act of their own will, +is in an historical sense involuntary and is related to the whole +course of history and predestined from eternity. + + + + + +CHAPTER II + + +On the twenty-ninth of May Napoleon left Dresden, where he had spent +three weeks surrounded by a court that included princes, dukes, kings, +and even an emperor. Before leaving, Napoleon showed favor to the +emperor, kings, and princes who had deserved it, reprimanded the kings +and princes with whom he was dissatisfied, presented pearls and +diamonds of his own--that is, which he had taken from other kings- +to the Empress of Austria, and having, as his historian tells us, +tenderly embraced the Empress Marie Louise--who regarded him as her +husband, though he had left another wife in Paris--left her grieved by +the parting which she seemed hardly able to bear. Though the +diplomatists still firmly believed in the possibility of peace and +worked zealously to that end, and though the Emperor Napoleon +himself wrote a letter to Alexander, calling him Monsieur mon frere, +and sincerely assured him that he did not want war and would always +love and honor him--yet he set off to join his army, and at every +station gave fresh orders to accelerate the movement of his troops +from west to east. He went in a traveling coach with six horses, +surrounded by pages, aides-de-camp, and an escort, along the road to +Posen, Thorn, Danzig, and Konigsberg. At each of these towns thousands +of people met him with excitement and enthusiasm. + +The army was moving from west to east, and relays of six horses +carried him in the same direction. On the tenth of June,* coming up +with the army, he spent the night in apartments prepared for him on +the estate of a Polish count in the Vilkavisski forest. + + +*Old style. + + +Next day, overtaking the army, he went in a carriage to the +Niemen, and, changing into a Polish uniform, he drove to the riverbank +in order to select a place for the crossing. + +Seeing, on the other side, some Cossacks (les Cosaques) and the +wide-spreading steppes in the midst of which lay the holy city of +Moscow (Moscou, la ville sainte), the capital of a realm such as the +Scythia into which Alexander the Great had marched--Napoleon +unexpectedly, and contrary alike to strategic and diplomatic +considerations, ordered an advance, and the next day his army began to +cross the Niemen. + +Early in the morning of the twelfth of June he came out of his tent, +which was pitched that day on the steep left bank of the Niemen, and +looked through a spyglass at the streams of his troops pouring out +of the Vilkavisski forest and flowing over the three bridges thrown +across the river. The troops, knowing of the Emperor's presence, +were on the lookout for him, and when they caught sight of a figure in +an overcoat and a cocked hat standing apart from his suite in front of +his tent on the hill, they threw up their caps and shouted: "Vive +l'Empereur!" and one after another poured in a ceaseless stream out of +the vast forest that had concealed them and, separating, flowed on and +on by the three bridges to the other side. + +"Now we'll go into action. Oh, when he takes it in hand himself, +things get hot... by heaven!... There he is!... Vive l'Empereur! So +these are the steppes of Asia! It's a nasty country all the same. Au +revoir, Beauche; I'll keep the best palace in Moscow for you! Au +revoir. Good luck!... Did you see the Emperor? Vive l'Empereur!... +preur!--If they make me Governor of India, Gerard, I'll make you +Minister of Kashmir--that's settled. Vive l'Empereur! Hurrah! +hurrah! hurrah! The Cossacks--those rascals--see how they run! Vive +l'Empereur! There he is, do you see him? I've seen him twice, as I see +you now. The little corporal... I saw him give the cross to one of the +veterans.... Vive l'Empereur!" came the voices of men, old and +young, of most diverse characters and social positions. On the faces +of all was one common expression of joy at the commencement of the +long-expected campaign and of rapture and devotion to the man in the +gray coat who was standing on the hill. + +On the thirteenth of June a rather small, thoroughbred Arab horse +was brought to Napoleon. He mounted it and rode at a gallop to one +of the bridges over the Niemen, deafened continually by incessant +and rapturous acclamations which he evidently endured only because +it was impossible to forbid the soldiers to express their love of +him by such shouting, but the shouting which accompanied him +everywhere disturbed him and distracted him from the military cares +that had occupied him from the time he joined the army. He rode across +one of the swaying pontoon bridges to the farther side, turned sharply +to the left, and galloped in the direction of Kovno, preceded by +enraptured, mounted chasseurs of the Guard who, breathless with +delight, galloped ahead to clear a path for him through the troops. On +reaching the broad river Viliya, he stopped near a regiment of +Polish Uhlans stationed by the river. + +"Vivat!" shouted the Poles, ecstatically, breaking their ranks and +pressing against one another to see him. + +Napoleon looked up and down the river, dismounted, and sat down on a +log that lay on the bank. At a mute sign from him, a telescope was +handed him which he rested on the back of a happy page who had run +up to him, and he gazed at the opposite bank. Then he became +absorbed in a map laid out on the logs. Without lifting his head he +said something, and two of his aides-de-camp galloped off to the +Polish Uhlans. + +"What? What did he say?" was heard in the ranks of the Polish Uhlans +when one of the aides-de-camp rode up to them. + +The order was to find a ford and to cross the river. The colonel +of the Polish Uhlans, a handsome old man, flushed and, fumbling in his +speech from excitement, asked the aide-de-camp whether he would be +permitted to swim the river with his Uhlans instead of seeking a ford. +In evident fear of refusal, like a boy asking for permission to get on +a horse, he begged to be allowed to swim across the river before the +Emperor's eyes. The aide-de-camp replied that probably the Emperor +would not be displeased at this excess of zeal. + +As soon as the aide-de-camp had said this, the old mustached +officer, with happy face and sparkling eyes, raised his saber, shouted +"Vivat!" and, commanding the Uhlans to follow him, spurred his horse +and galloped into the river. He gave an angry thrust to his horse, +which had grown restive under him, and plunged into the water, heading +for the deepest part where the current was swift. Hundreds of Uhlans +galloped in after him. It was cold and uncanny in the rapid current in +the middle of the stream, and the Uhlans caught hold of one another as +they fell off their horses. Some of the horses were drowned and some +of the men; the others tried to swim on, some in the saddle and some +clinging to their horses' manes. They tried to make their way +forward to the opposite bank and, though there was a ford one third of +a mile away, were proud that they were swimming and drowning in this +river under the eyes of the man who sat on the log and was not even +looking at what they were doing. When the aide-de-camp, having +returned and choosing an opportune moment, ventured to draw the +Emperor's attention to the devotion of the Poles to his person, the +little man in the gray overcoat got up and, having summoned +Berthier, began pacing up and down the bank with him, giving him +instructions and occasionally glancing disapprovingly at the +drowning Uhlans who distracted his attention. + +For him it was no new conviction that his presence in any part of +the world, from Africa to the steppes of Muscovy alike, was enough +to dumfound people and impel them to insane self-oblivion. He called +for his horse and rode to his quarters. + +Some forty Uhlans were drowned in the river, though boats were +sent to their assistance. The majority struggled back to the bank from +which they had started. The colonel and some of his men got across and +with difficulty clambered out on the further bank. And as soon as they +had got out, in their soaked and streaming clothes, they shouted +"Vivat!" and looked ecstatically at the spot where Napoleon had been +but where he no longer was and at that moment considered themselves +happy. + +That evening, between issuing one order that the forged Russian +paper money prepared for use in Russia should be delivered as +quickly as possible and another that a Saxon should be shot, on whom a +letter containing information about the orders to the French army +had been found, Napoleon also gave instructions that the Polish +colonel who had needlessly plunged into the river should be enrolled +in the Legion d'honneur of which Napoleon was himself the head. + +Quos vult perdere dementat.* + + +*Those whom (God) wishes to destroy he drives mad. + + + + + +CHAPTER III + + +The Emperor of Russia had, meanwhile, been in Vilna for more than +a month, reviewing troops and holding maneuvers. Nothing was ready for +the war that everyone expected and to prepare for which the Emperor +had come from Petersburg. There was no general plan of action. The +vacillation between the various plans that were proposed had even +increased after the Emperor had been at headquarters for a month. Each +of the three armies had its own commander in chief, but there was no +supreme commander of all the forces, and the Emperor did not assume +that responsibility himself. + +The longer the Emperor remained in Vilna the less did everybody- +tired of waiting--prepare for the war. All the efforts of those who +surrounded the sovereign seemed directed merely to making him spend +his time pleasantly and forget that war was impending. + +In June, after many balls and fetes given by the Polish magnates, by +the courtiers, and by the Emperor himself, it occurred to one of the +Polish aides-de-camp in attendance that a dinner and ball should be +given for the Emperor by his aides-de-camp. This idea was eagerly +received. The Emperor gave his consent. The aides-de-camp collected +money by subscription. The lady who was thought to be most pleasing to +the Emperor was invited to act as hostess. Count Bennigsen, being a +landowner in the Vilna province, offered his country house for the +fete, and the thirteenth of June was fixed for a ball, dinner, +regatta, and fireworks at Zakret, Count Bennigsen's country seat. + + +The very day that Napoleon issued the order to cross the Niemen, and +his vanguard, driving off the Cossacks, crossed the Russian +frontier, Alexander spent the evening at the entertainment given by +his aides-de-camp at Bennigsen's country house. + +It was a gay and brilliant fete. Connoisseurs of such matters +declared that rarely had so many beautiful women been assembled in one +place. Countess Bezukhova was present among other Russian ladies who +had followed the sovereign from Petersburg to Vilna and eclipsed the +refined Polish ladies by her massive, so called Russian type of +beauty. The Emperor noticed her and honored her with a dance. + +Boris Drubetskoy, having left his wife in Moscow and being for the +present en garcon (as he phrased it), was also there and, though not +an aide-de-camp, had subscribed a large sum toward the expenses. Boris +was now a rich man who had risen to high honors and no longer sought +patronage but stood on an equal footing with the highest of those of +his own age. He was meeting Helene in Vilna after not having seen +her for a long time and did not recall the past, but as Helene was +enjoying the favors of a very important personage and Boris had only +recently married, they met as good friends of long standing. + +At midnight dancing was still going on. Helene, not having a +suitable partner, herself offered to dance the mazurka with Boris. +They were the third couple. Boris, coolly looking at Helene's dazzling +bare shoulders which emerged from a dark, gold-embroidered, gauze +gown, talked to her of old acquaintances and at the same time, unaware +of it himself and unnoticed by others, never for an instant ceased +to observe the Emperor who was in the same room. The Emperor was not +dancing, he stood in the doorway, stopping now one pair and now +another with gracious words which he alone knew how to utter. + +As the mazurka began, Boris saw that Adjutant General Balashev, +one of those in closest attendance on the Emperor, went up to him +and contrary to court etiquette stood near him while he was talking to +a Polish lady. Having finished speaking to her, the Emperor looked +inquiringly at Balashev and, evidently understanding that he only +acted thus because there were important reasons for so doing, nodded +slightly to the lady and turned to him. Hardly had Balashev begun to +speak before a look of amazement appeared on the Emperor's face. He +took Balashev by the arm and crossed the room with him, +unconsciously clearing a path seven yards wide as the people on both +sides made way for him. Boris noticed Arakcheev's excited face when +the sovereign went out with Balashev. Arakcheev looked at the +Emperor from under his brow and, sniffing with his red nose, stepped +forward from the crowd as if expecting the Emperor to address him. +(Boris understood that Arakcheev envied Balashev and was displeased +that evidently important news had reached the Emperor otherwise than +through himself.) + +But the Emperor and Balashev passed out into the illuminated +garden without noticing Arakcheev who, holding his sword and +glancing wrathfully around, followed some twenty paces behind them. + +All the time Boris was going through the figures of the mazurka, +he was worried by the question of what news Balashev had brought and +how he could find it out before others. In the figure in which he +had to choose two ladies, he whispered to Helene that he meant to +choose Countess Potocka who, he thought, had gone out onto the +veranda, and glided over the parquet to the door opening into the +garden, where, seeing Balashev and the Emperor returning to the +veranda, he stood still. They were moving toward the door. Boris, +fluttering as if he had not had time to withdraw, respectfully pressed +close to the doorpost with bowed head. + +The Emperor, with the agitation of one who has been personally +affronted, was finishing with these words: + +"To enter Russia without declaring war! I will not make peace as +long as a single armed enemy remains in my country!" It seemed to +Boris that it gave the Emperor pleasure to utter these words. He was +satisfied with the form in which he had expressed his thoughts, but +displeased that Boris had overheard it. + +"Let no one know of it!" the Emperor added with a frown. + +Boris understood that this was meant for him and, closing his +eyes, slightly bowed his head. The Emperor re-entered the ballroom and +remained there about another half-hour. + +Boris was thus the first to learn the news that the French army +had crossed the Niemen and, thanks to this, was able to show certain +important personages that much that was concealed from others was +usually known to him, and by this means he rose higher in their +estimation. + + +The unexpected news of the French having crossed the Niemen was +particularly startling after a month of unfulfilled expectations, +and at a ball. On first receiving the news, under the influence of +indignation and resentment the Emperor had found a phrase that pleased +him, fully expressed his feelings, and has since become famous. On +returning home at two o'clock that night he sent for his secretary, +Shishkov, and told him to write an order to the troops and a +rescript to Field Marshal Prince Saltykov, in which he insisted on the +words being inserted that he would not make peace so long as a +single armed Frenchman remained on Russian soil. + +Next day the following letter was sent to Napoleon: + + +Monsieur mon frere, + +Yesterday I learned that, despite the loyalty which I have kept my +engagements with Your Majesty, your troops have crossed the Russian +frontier, and I have this moment received from Petersburg a note, in +which Count Lauriston informs me, as a reason for this aggression, +that Your Majesty has considered yourself to be in a state of war with +me from the time Prince Kuragin asked for his passports. The reasons +on which the Duc de Bassano based his refusal to deliver them to him +would never have led me to suppose that that could serve as a +pretext for aggression. In fact, the ambassador, as he himself has +declared, was never authorized to make that demand, and as soon as I +was informed of it I let him know how much I disapproved of it and +ordered him to remain at his post. If Your Majesty does not intend +to shed the blood of our peoples for such a misunderstanding, and +consents to withdraw your troops from Russian territory, I will regard +what has passed as not having occurred and an understanding between us +will be possible. In the contrary case, Your Majesty, I shall see +myself forced to repel an attack that nothing on my part has provoked. +It still depends on Your Majesty to preserve humanity from the +calamity of another war. I am, etc., + (signed) Alexander + + + + + +CHAPTER IV + + +At two in the morning of the fourteenth of June, the Emperor, having +sent for Balashev and read him his letter to Napoleon, ordered him +to take it and hand it personally to the French Emperor. When +dispatching Balashev, the Emperor repeated to him the words that he +would not make peace so long as a single armed enemy remained on +Russian soil and told him to transmit those words to Napoleon. +Alexander did not insert them in his letter to Napoleon, because +with his characteristic tact he felt it would be injudicious to use +them at a moment when a last attempt at reconciliation was being made, +but he definitely instructed Balashev to repeat them personally to +Napoleon. + +Having set off in the small hours of the fourteenth, accompanied +by a bugler and two Cossacks, Balashev reached the French outposts +at the village of Rykonty, on the Russian side of the Niemen, by dawn. +There he was stopped by French cavalry sentinels. + +A French noncommissioned officer of hussars, in crimson uniform +and a shaggy cap, shouted to the approaching Balashev to halt. +Balashev did not do so at once, but continued to advance along the +road at a walking pace. + +The noncommissioned officer frowned and, muttering words of abuse, +advanced his horse's chest against Balashev, put his hand to his +saber, and shouted rudely at the Russian general, asking: was he +deaf that he did not do as he was told? Balashev mentioned who he was. +The noncommissioned officer began talking with his comrades about +regimental matters without looking at the Russian general. + +After living at the seat of the highest authority and power, after +conversing with the Emperor less than three hours before, and in +general being accustomed to the respect due to his rank in the +service, Balashev found it very strange here on Russian soil to +encounter this hostile, and still more this disrespectful, application +of brute force to himself. + +The sun was only just appearing from behind the clouds, the air +was fresh and dewy. A herd of cattle was being driven along the road +from the village, and over the fields the larks rose trilling, one +after another, like bubbles rising in water. + +Balashev looked around him, awaiting the arrival of an officer +from the village. The Russian Cossacks and bugler and the French +hussars looked silently at one another from time to time. + +A French colonel of hussars, who had evidently just left his bed, +came riding from the village on a handsome sleek gray horse, +accompanied by two hussars. The officer, the soldiers, and their +horses all looked smart and well kept. + +It was that first period of a campaign when troops are still in full +trim, almost like that of peacetime maneuvers, but with a shade of +martial swagger in their clothes, and a touch of the gaiety and spirit +of enterprise which always accompany the opening of a campaign. + +The French colonel with difficulty repressed a yawn, but was +polite and evidently understood Balashev's importance. He led him past +his soldiers and behind the outposts and told him that his wish to +be presented to the Emperor would most likely be satisfied +immediately, as the Emperor's quarters were, he believed, not far off. + +They rode through the village of Rykonty, past tethered French +hussar horses, past sentinels and men who saluted their colonel and +stared with curiosity at a Russian uniform, and came out at the +other end of the village. The colonel said that the commander of the +division was a mile and a quarter away and would receive Balashev +and conduct him to his destination. + +The sun had by now risen and shone gaily on the bright verdure. + +They had hardly ridden up a hill, past a tavern, before they saw a +group of horsemen coming toward them. In front of the group, on a +black horse with trappings that glittered in the sun, rode a tall +man with plumes in his hat and black hair curling down to his +shoulders. He wore a red mantle, and stretched his long legs forward +in French fashion. This man rode toward Balashev at a gallop, his +plumes flowing and his gems and gold lace glittering in the bright +June sunshine. + +Balashev was only two horses' length from the equestrian with the +bracelets, plunies, necklaces, and gold embroidery, who was +galloping toward him with a theatrically solemn countenance, when +Julner, the French colonel, whispered respectfully: "The King of +Naples!" It was, in fact, Murat, now called "King of Naples." Though +it was quite incomprehensible why he should be King of Naples, he +was called so, and was himself convinced that he was so, and therefore +assumed a more solemn and important air than formerly. He was so +sure that he really was the King of Naples that when, on the eve of +his departure from that city, while walking through the streets with +his wife, some Italians called out to him: "Viva il re!"* he turned to +his wife with a pensive smile and said: "Poor fellows, they don't know +that I am leaving them tomorrow!" + + +*"Long live the king." + + +But though he firmly believed himself to be King of Naples and +pitied the grief felt by the subjects he was abandoning, latterly, +after he had been ordered to return to military service--and +especially since his last interview with Napoleon in Danzig, when +his august brother-in-law had told him: "I made you King that you +should reign in my way, but not in yours!"--he had cheerfully taken up +his familiar business, and--like a well-fed but not overfat horse that +feels himself in harness and grows skittish between the shafts--he +dressed up in clothes as variegated and expensive as possible, and +gaily and contentedly galloped along the roads of Poland, without +himself knowing why or whither. + +On seeing the Russian general he threw back his head, with its +long hair curling to his shoulders, in a majestically royal manner, +and looked inquiringly at the French colonel. The colonel respectfully +informed His Majesty of Balashev's mission, whose name he could not +pronounce. + +"De Bal-macheve!" said the King (overcoming by his assurance the +difficulty that had presented itself to the colonel). "Charmed to make +your acquaintance, General!" he added, with a gesture of kingly +condescension. + +As soon as the King began to speak loud and fast his royal dignity +instantly forsook him, and without noticing it he passed into his +natural tone of good-natured familiarity. He laid his hand on the +withers of Balashev's horse and said: + +"Well, General, it all looks like war," as if regretting a +circumstance of which he was unable to judge. + +"Your Majesty," replied Balashev, "my master, the Emperor, does +not desire war and as Your Majesty sees..." said Balashev, using the +words Your Majesty at every opportunity, with the affectation +unavoidable in frequently addressing one to whom the title was still a +novelty. + +Murat's face beamed with stupid satisfaction as he listened to +"Monsieur de Bal-macheve." But royaute oblige!* and he felt it +incumbent on him, as a king and an ally, to confer on state affairs +with Alexander's envoy. He dismounted, took Balashev's arm, and moving +a few steps away from his suite, which waited respectfully, began to +pace up and down with him, trying to speak significantly. He +referred to the fact that the Emperor Napoleon had resented the demand +that he should withdraw his troops from Prussia, especially when +that demand became generally known and the dignity of France was +thereby offended. + + +*"Royalty has its obligations." + + +Balashev replied that there was "nothing offensive in the demand, +because..." but Murat interrupted him. + +"Then you don't consider the Emperor Alexander the aggressor?" he +asked unexpectedly, with a kindly and foolish smile. + +Balashev told him why he considered Napoleon to be the originator of +the war. + +"Oh, my dear general!" Murat again interrupted him, "with all my +heart I wish the Emperors may arrange the affair between them, and +that the war begun by no wish of mine may finish as quickly as +possible!" said he, in the tone of a servant who wants to remain +good friends with another despite a quarrel between their masters. + +And he went on to inquiries about the Grand Duke and the state of +his health, and to reminiscences of the gay and amusing times he had +spent with him in Naples. Then suddenly, as if remembering his royal +dignity, Murat solemnly drew himself up, assumed the pose in which +he had stood at his coronation, and, waving his right arm, said: + +"I won't detain you longer, General. I wish success to your +mission," and with his embroidered red mantle, his flowing feathers, +and his glittering ornaments, he rejoined his suite who were +respectfully awaiting him. + +Balashev rode on, supposing from Murat's words that he would very +soon be brought before Napoleon himself. But instead of that, at the +next village the sentinels of Davout's infantry corps detained him +as the pickets of the vanguard had done, and an adjutant of the +corps commander, who was fetched, conducted him into the village to +Marshal Davout. + + + + + +CHAPTER V + + +Davout was to Napoleon what Arakcheev was to Alexander--though not a +coward like Arakcheev, he was as precise, as cruel, and as unable to +express his devotion to his monarch except by cruelty. + +In the organism of states such men are necessary, as wolves are +necessary in the organism of nature, and they always exist, always +appear and hold their own, however incongruous their presence and +their proximity to the head of the government may be. This +inevitability alone can explain how the cruel Arakcheev, who tore +out a grenadier's mustache with his own hands, whose weak nerves +rendered him unable to face danger, and who was neither an educated +man nor a courtier, was able to maintain his powerful position with +Alexander, whose own character was chivalrous, noble, and gentle. + +Balashev found Davout seated on a barrel in the shed of a +peasant's hut, writing--he was auditing accounts. Better quarters +could have been found him, but Marshal Davout was one of those men who +purposely put themselves in most depressing conditions to have a +justification for being gloomy. For the same reason they are always +hard at work and in a hurry. "How can I think of the bright side of +life when, as you see, I am sitting on a barrel and working in a dirty +shed?" the expression of his face seemed to say. The chief pleasure +and necessity of such men, when they encounter anyone who shows +animation, is to flaunt their own dreary, persistent activity. +Davout allowed himself that pleasure when Balashev was brought in. +He became still more absorbed in his task when the Russian general +entered, and after glancing over his spectacles at Balashev's face, +which was animated by the beauty of the morning and by his talk with +Murat, he did not rise or even stir, but scowled still more and +sneered malevolently. + +When he noticed in Balashev's face the disagreeable impression +this reception produced, Davout raised his head and coldly asked +what he wanted. + +Thinking he could have been received in such a manner only because +Davout did not know that he was adjutant general to the Emperor +Alexander and even his envoy to Napoleon, Balashev hastened to +inform him of his rank and mission. Contrary to his expectation, +Davout, after hearing him, became still surlier and ruder. + +"Where is your dispatch?" he inquired. "Give it to me. I will send +it to the Emperor." + +Balashev replied that he had been ordered to hand it personally to +the Emperor. + +"Your Emperor's orders are obeyed in your army, but here," said +Davout, "you must do as you're told." + +And, as if to make the Russian general still more conscious of his +dependence on brute force, Davout sent an adjutant to call the officer +on duty. + +Balashev took out the packet containing the Emperor's letter and +laid it on the table (made of a door with its hinges still hanging +on it, laid across two barrels). Davout took the packet and read the +inscription. + +"You are perfectly at liberty to treat me with respect or not," +protested Balashev, "but permit me to observe that I have the honor to +be adjutant general to His Majesty...." + +Davout glanced at him silently and plainly derived pleasure from the +signs of agitation and confusion which appeared on Balashev's face. + +"You will be treated as is fitting," said he and, putting the packet +in his pocket, left the shed. + +A minute later the marshal's adjutant, de Castres, came in and +conducted Balashev to the quarters assigned him. + +That day he dined with the marshal, at the same board on the +barrels. + +Next day Davout rode out early and, after asking Balashev to come to +him, peremptorily requested him to remain there, to move on with the +baggage train should orders come for it to move, and to talk to no one +except Monsieur de Castres. + +After four days of solitude, ennui, and consciousness of his +impotence and insignificance--particularly acute by contrast with +the sphere of power in which he had so lately moved--and after several +marches with the marshal's baggage and the French army, which occupied +the whole district, Balashev was brought to Vilna--now occupied by the +French--through the very gate by which he had left it four days +previously. + +Next day the imperial gentleman-in-waiting, the Comte de Turenne, +came to Balashev and informed him of the Emperor Napoleon's wish to +honor him with an audience. + +Four days before, sentinels of the Preobrazhensk regiment had +stood in front of the house to which Balashev was conducted, and now +two French grenadiers stood there in blue uniforms unfastened in front +and with shaggy caps on their heads, and an escort of hussars and +Uhlans and a brilliant suite of aides-de-camp, pages, and generals, +who were waiting for Napoleon to come out, were standing at the porch, +round his saddle horse and his Mameluke, Rustan. Napoleon received +Balashev in the very house in Vilna from which Alexander had +dispatched him on his mission. + + + + + +CHAPTER VI + + +Though Balashev was used to imperial pomp, he was amazed at the +luxury and magnificence of Napoleon's court. + +The Comte de Turenne showed him into a big reception room where many +generals, gentlemen-in-waiting, and Polish magnates--several of whom +Balashev had seen at the court of the Emperor of Russia--were waiting. +Duroc said that Napoleon would receive the Russian general before +going for his ride. + +After some minutes, the gentleman-in-waiting who was on duty came +into the great reception room and, bowing politely, asked Balashev +to follow him. + +Balashev went into a small reception room, one door of which led +into a study, the very one from which the Russian Emperor had +dispatched him on his mission. He stood a minute or two, waiting. He +heard hurried footsteps beyond the door, both halves of it were opened +rapidly; all was silent and then from the study the sound was heard of +other steps, firm and resolute--they were those of Napoleon. He had +just finished dressing for his ride, and wore a blue uniform, +opening in front over a white waistcoat so long that it covered his +rotund stomach, white leather breeches tightly fitting the fat +thighs of his short legs, and Hessian boots. His short hair had +evidently just been brushed, but one lock hung down in the middle of +his broad forehead. His plump white neck stood out sharply above the +black collar of his uniform, and he smelled of Eau de Cologne. His +full face, rather young-looking, with its prominent chin, wore a +gracious and majestic expression of imperial welcome. + +He entered briskly, with a jerk at every step and his head +slightly thrown back. His whole short corpulent figure with broad +thick shoulders, and chest and stomach involuntarily protruding, had +that imposing and stately appearance one sees in men of forty who live +in comfort. It was evident, too, that he was in the best of spirits +that day. + +He nodded in answer to Balashav's low and respectful bow, and coming +up to him at once began speaking like a man who values every moment of +his time and does not condescend to prepare what he has to say but +is sure he will always say the right thing and say it well. + +"Good day, General!" said he. "I have received the letter you +brought from the Emperor Alexander and am very glad to see you." He +glanced with his large eyes into Balashav's face and immediately +looked past him. + +It was plain that Balashev's personality did not interest him at +all. Evidently only what took place within his own mind interested +him. Nothing outside himself had any significance for him, because +everything in the world, it seemed to him, depended entirely on his +will. + +"I do not, and did not, desire war," he continued, "but it has +been forced on me. Even now" (he emphasized the word) "I am ready to +receive any explanations you can give me." + +And he began clearly and concisely to explain his reasons for +dissatisfaction with the Russian government. Judging by the calmly +moderate and amicable tone in which the French Emperor spoke, Balashev +was firmly persuaded that he wished for peace and intended to enter +into negotiations. + +When Napoleon, having finished speaking, looked inquiringly at the +Russian envoy, Balashev began a speech he had prepared long before: +"Sire! The Emperor, my master..." but the sight of the Emperor's +eyes bent on him confused him. "You are flurried--compose yourself!" +Napoleon seemed to say, as with a scarcely perceptible smile he looked +at Balashev's uniform and sword. + +Balashev recovered himself and began to speak. He said that the +Emperor Alexander did not consider Kurakin's demand for his +passports a sufficient cause for war; that Kurakin had acted on his +own initiative and without his sovereign's assent, that the Emperor +Alexander did not desire war, and had no relations with England. + +"Not yet!" interposed Napoleon, and, as if fearing to give vent to +his feelings, he frowned and nodded slightly as a sign that Balashev +might proceed. + +After saying all he had been instructed to say, Balashev added +that the Emperor Alexander wished for peace, but would not enter +into negotiations except on condition that... Here Balashev hesitated: +he remembered the words the Emperor Alexander had not written in his +letter, but had specially inserted in the rescript to Saltykov and had +told Balashev to repeat to Napoleon. Balashev remembered these +words, "So long as a single armed foe remains on Russian soil," but +some complex feeling restrained him. He could not utter them, though +he wished to do so. He grew confused and said: "On condition that +the French army retires beyond the Niemen." + +Napoleon noticed Balashev's embarrassment when uttering these last +words; his face twitched and the calf of his left leg began to +quiver rhythmically. Without moving from where he stood he began +speaking in a louder tone and more hurriedly than before. During the +speech that followed, Balashev, who more than once lowered his eyes, +involuntarily noticed the quivering of Napoleon's left leg which +increased the more Napoleon raised his voice. + +"I desire peace, no less than the Emperor Alexander," he began. +"Have I not for eighteen months been doing everything to obtain it? +I have waited eighteen months for explanations. But in order to +begin negotiations, what is demanded of me?" he said, frowning and +making an energetic gesture of inquiry with his small white plump +hand. + +"The withdrawal of your army beyond the Niemen, sire," replied +Balashev. + +"The Niemen?" repeated Napoleon. "So now you want me to retire +beyond the Niemen--only the Niemen?" repeated Napoleon, looking +straight at Balashev. + +The latter bowed his head respectfully. + +Instead of the demand of four months earlier to withdraw from +Pomerania, only a withdrawal beyond the Niemen was now demanded. +Napoleon turned quickly and began to pace the room. + +"You say the demand now is that I am to withdraw beyond the Niemen +before commencing negotiations, but in just the same way two months +ago the demand was that I should withdraw beyond the Vistula and the +Oder, and yet you are willing to negotiate." + +He went in silence from one corner of the room to the other and +again stopped in front of Balashev. Balashev noticed that his left leg +was quivering faster than before and his face seemed petrified in +its stern expression. This quivering of his left leg was a thing +Napoleon was conscious of. "The vibration of my left calf is a great +sign with me," he remarked at a later date. + +"Such demands as to retreat beyond the Vistula and Oder may be +made to a Prince of Baden, but not to me!" Napoleon almost screamed, +quite to his own surprise. "If you gave me Petersburg and Moscow I +could not accept such conditions. You say I have begun this war! But +who first joined his army? The Emperor Alexander, not I! And you offer +me negotiations when I have expended millions, when you are in +alliance with England, and when your position is a bad one. You +offer me negotiations! But what is the aim of your alliance with +England? What has she given you?" he continued hurriedly, evidently no +longer trying to show the advantages of peace and discuss its +possibility, but only to prove his own rectitude and power and +Alexander's errors and duplicity. + +The commencement of his speech had obviously been made with the +intention of demonstrating the advantages of his position and +showing that he was nevertheless willing to negotiate. But he had +begun talking, and the more he talked the less could he control his +words. + +The whole purport of his remarks now was evidently to exalt +himself and insult Alexander--just what he had least desired at the +commencement of the interview. + +"I hear you have made peace with Turkey?" + +Balashev bowed his head affirmatively. + +"Peace has been concluded..." he began. + +But Napoleon did not let him speak. He evidently wanted to do all +the talking himself, and continued to talk with the sort of +eloquence and unrestrained irritability to which spoiled people are so +prone. + +"Yes, I know you have made peace with the Turks without obtaining +Moldavia and Wallachia; I would have given your sovereign those +provinces as I gave him Finland. Yes," he went on, "I promised and +would have given the Emperor Alexander Moldavia and Wallachia, and now +he won't have those splendid provinces. Yet he might have united +them to his empire and in a single reign would have extended Russia +from the Gulf of Bothnia to the mouths of the Danube. Catherine the +Great could not have done more," said Napoleon, growing more and +more excited as he paced up and down the room, repeating to Balashev +almost the very words he had used to Alexander himself at Tilsit. "All +that, he would have owed to my friendship. Oh, what a splendid reign!" +he repeated several times, then paused, drew from his pocket a gold +snuffbox, lifted it to his nose, and greedily sniffed at it. + +"What a splendid reign the Emperor Alexander's might have been!" + +He looked compassionately at Balashev, and as soon as the latter +tried to make some rejoinder hastily interrupted him. + +"What could he wish or look for that he would not have obtained +through my friendship?" demanded Napoleon, shrugging his shoulders +in perplexity. "But no, he has preferred to surround himself with my +enemies, and with whom? With Steins, Armfeldts, Bennigsens, and +Wintzingerodes! Stein, a traitor expelled from his own country; +Armfeldt, a rake and an intriguer; Wintzingerode, a fugitive French +subject; Bennigsen, rather more of a soldier than the others, but +all the same an incompetent who was unable to do anything in 1807 +and who should awaken terrible memories in the Emperor Alexander's +mind.... Granted that were they competent they might be made use +of," continued Napoleon--hardly able to keep pace in words with the +rush of thoughts that incessantly sprang up, proving how right and +strong he was (in his perception the two were one and the same)- +"but they are not even that! They are neither fit for war nor peace! +Barclay is said to be the most capable of them all, but I cannot say +so, judging by his first movements. And what are they doing, all these +courtiers? Pfuel proposes, Armfeldt disputes, Bennigsen considers, and +Barclay, called on to act, does not know what to decide on, and time +passes bringing no result. Bagration alone is a military man. He's +stupid, but he has experience, a quick eye, and resolution.... And +what role is your young monarch playing in that monstrous crowd? +They compromise him and throw on him the responsibility for all that +happens. A sovereign should not be with the army unless he is a +general!" said Napoleon, evidently uttering these words as a direct +challenge to the Emperor. He knew how Alexander desired to be a +military commander. + +"The campaign began only a week ago, and you haven't even been +able to defend Vilna. You are cut in two and have been driven out of +the Polish provinces. Your army is grumbling." + +"On the contrary, Your Majesty," said Balashev, hardly able to +remember what had been said to him and following these verbal +fireworks with difficulty, "the troops are burning with eagerness..." + +"I know everything!" Napoleon interrupted him. "I know everything. I +know the number of your battalions as exactly as I know my own. You +have not two hundred thousand men, and I have three times that number. +I give you my word of honor," said Napoleon, forgetting that his +word of honor could carry no weight--"I give you my word of honor that +I have five hundred and thirty thousand men this side of the +Vistula. The Turks will be of no use to you; they are worth nothing +and have shown it by making peace with you. As for the Swedes--it is +their fate to be governed by mad kings. Their king was insane and they +changed him for another--Bernadotte, who promptly went mad--for no +Swede would ally himself with Russia unless he were mad." + +Napoleon grinned maliciously and again raised his snuffbox to his +nose. + +Balashev knew how to reply to each of Napoleon's remarks, and +would have done so; he continually made the gesture of a man wishing +to say something, but Napoleon always interrupted him. To the +alleged insanity of the Swedes, Balashev wished to reply that when +Russia is on her side Sweden is practically an island: but Napoleon +gave an angry exclamation to drown his voice. Napoleon was in that +state of irritability in which a man has to talk, talk, and talk, +merely to convince himself that he is in the right. Balashev began +to feel uncomfortable: as envoy he feared to demean his dignity and +felt the necessity of replying; but, as a man, he shrank before the +transport of groundless wrath that had evidently seized Napoleon. He +knew that none of the words now uttered by Napoleon had any +significance, and that Napoleon himself would be ashamed of them +when he came to his senses. Balashev stood with downcast eyes, looking +at the movements of Napoleon's stout legs and trying to avoid +meeting his eyes. + +"But what do I care about your allies?" said Napoleon. "I have +allies--the Poles. There are eighty thousand of them and they fight +like lions. And there will be two hundred thousand of them." + +And probably still more perturbed by the fact that he had uttered +this obvious falsehood, and that Balashev still stood silently +before him in the same attitude of submission to fate, Napoleon +abruptly turned round, drew close to Balashev's face, and, +gesticulating rapidly and energetically with his white hands, almost +shouted: + +"Know that if you stir up Prussia against me, I'll wipe it off the +map of Europe!" he declared, his face pale and distorted by anger, and +he struck one of his small hands energetically with the other. "Yes, I +will throw you back beyond the Dvina and beyond the Dnieper, and +will re-erect against you that barrier which it was criminal and blind +of Europe to allow to be destroyed. Yes, that is what will happen to +you. That is what you have gained by alienating me!" And he walked +silently several times up and down the room, his fat shoulders +twitching. + +He put his snuffbox into his waistcoat pocket, took it out again, +lifted it several times to his nose, and stopped in front of Balashev. +He paused, looked ironically straight into Balashev's eyes, and said +in a quiet voice: + +"And yet what a splendid reign your master might have had!" + +Balashev, feeling it incumbent on him to reply, said that from the +Russian side things did not appear in so gloomy a light. Napoleon +was silent, still looking derisively at him and evidently not +listening to him. Balashev said that in Russia the best results were +expected from the war. Napoleon nodded condescendingly, as if to +say, "I know it's your duty to say that, but you don't believe it +yourself. I have convinced you." + +When Balashev had ended, Napoleon again took out his snuffbox, +sniffed at it, and stamped his foot twice on the floor as a signal. +The door opened, a gentleman-in-waiting, bending respectfully, +handed the Emperor his hat and gloves; another brought him a pocket +handkerchief. Napoleon, without giving them a glance, turned to +Balashev: + +"Assure the Emperor Alexander from me," said he, taking his hat, +"that I am as devoted to him as before: I know him thoroughly and very +highly esteem his lofty qualities. I will detain you no longer, +General; you shall receive my letter to the Emperor." + +And Napoleon went quickly to the door. Everyone in the reception +room rushed forward and descended the staircase. + + + + + +CHAPTER VII + + +After all that Napoleon had said to him--those bursts of anger and +the last dryly spoken words: "I will detain you no longer, General; +you shall receive my letter," Balashev felt convinced that Napoleon +would not wish to see him, and would even avoid another meeting with +him--an insulted envoy--especially as he had witnessed his unseemly +anger. But, to his surprise, Balashev received, through Duroc, an +invitation to dine with the Emperor that day. + +Bessieres, Caulaincourt, and Berthier were present at that dinner. + +Napoleon met Balashev cheerfully and amiably. He not only showed +no sign of constraint or self-reproach on account of his outburst that +morning, but, on the contrary, tried to reassure Balashev. It was +evident that he had long been convinced that it was impossible for him +to make a mistake, and that in his perception whatever he did was +right, not because it harmonized with any idea of right and wrong, but +because he did it. + +The Emperor was in very good spirits after his ride through Vilna, +where crowds of people had rapturously greeted and followed him. +From all the windows of the streets through which he rode, rugs, +flags, and his monogram were displayed, and the Polish ladies, +welcoming him, waved their handkerchiefs to him. + +At dinner, having placed Balashev beside him, Napoleon not only +treated him amiably but behaved as if Balashev were one of his own +courtiers, one of those who sympathized with his plans and ought to +rejoice at his success. In the course of conversation he mentioned +Moscow and questioned Balashev about the Russian capital, not merely +as an interested traveler asks about a new city he intends to visit, +but as if convinced that Balashev, as a Russian, must be flattered +by his curiosity. + +"How many inhabitants are there in Moscow? How many houses? Is it +true that Moscow is called 'Holy Moscow'? How many churches are +there in Moscow?" he asked. + +And receiving the reply that there were more than two hundred +churches, he remarked: + +"Why such a quantity of churches?" + +"The Russians are very devout," replied Balashev. + +"But a large number of monasteries and churches is always a sign +of the backwardness of a people," said Napoleon, turning to +Caulaincourt for appreciation of this remark. + +Balashev respectfully ventured to disagree with the French Emperor. + +"Every country has its own character," said he. + +"But nowhere in Europe is there anything like that," said Napoleon. + +"I beg your Majesty's pardon," returned Balashev, "besides Russia +there is Spain, where there are also many churches and monasteries." + +This reply of Balashev's, which hinted at the recent defeats of +the French in Spain, was much appreciated when he related it at +Alexander's court, but it was not much appreciated at Napoleon's +dinner, where it passed unnoticed. + +The uninterested and perplexed faces of the marshals showed that +they were puzzled as to what Balashev's tone suggested. "If there is a +point we don't see it, or it is not at all witty," their expressions +seemed to say. So little was his rejoinder appreciated that Napoleon +did not notice it at all and naively asked Balashev through what towns +the direct road from there to Moscow passed. Balashev, who was on +the alert all through the dinner, replied that just as "all roads lead +to Rome," so all roads lead to Moscow: there were many roads, and +"among them the road through Poltava, which Charles XII chose." +Balashev involuntarily flushed with pleasure at the aptitude of this +reply, but hardly had he uttered the word Poltava before +Caulaincourt began speaking of the badness of the road from Petersburg +to Moscow and of his Petersburg reminiscences. + +After dinner they went to drink coffee in Napoleon's study, which +four days previously had been that of the Emperor Alexander. +Napoleon sat down, toying with his Sevres coffee cup, and motioned +Balashev to a chair beside him. + +Napoleon was in that well-known after-dinner mood which, more than +any reasoned cause, makes a man contented with himself and disposed to +consider everyone his friend. It seemed to him that he was +surrounded by men who adored him: and he felt convinced that, after +his dinner, Balashev too was his friend and worshiper. Napoleon turned +to him with a pleasant, though slightly ironic, smile. + +"They tell me this is the room the Emperor Alexander occupied? +Strange, isn't it, General?" he said, evidently not doubting that this +remark would be agreeable to his hearer since it went to prove his, +Napoleon's, superiority to Alexander. + +Balashev made no reply and bowed his head in silence. + +"Yes. Four days ago in this room, Wintzingerode and Stein were +deliberating," continued Napoleon with the same derisive and +self-confident smile. "What I can't understand," he went on, "is +that the Emperor Alexander has surrounded himself with my personal +enemies. That I do not... understand. Has he not thought that I may +the same?" and he turned inquiringly to Balashev, and evidently this +thought turned him back on to the track of his morning's anger, +which was still fresh in him. + +"And let him know that I will do so!" said Napoleon, rising and +pushing his cup away with his hand. "I'll drive all his Wurttemberg, +Baden, and Weimar relations out of Germany.... Yes. I'll drive them +out. Let him prepare an asylum for them in Russia!" + +Balashev bowed his head with an air indicating that he would like to +make his bow and leave, and only listened because he could not help +hearing what was said to him. Napoleon did not notice this expression; +he treated Balashev not as an envoy from his enemy, but as a man now +fully devoted to him and who must rejoice at his former master's +humiliation. + +"And why has the Emperor Alexander taken command of the armies? What +is the good of that? War is my profession, but his business is to +reign and not to command armies! Why has he taken on himself such a +responsibility?" + +Again Napoleon brought out his snuffbox, paced several times up +and down the room in silence, and then, suddenly and unexpectedly, +went up to Balashev and with a slight smile, as confidently, +quickly, and simply as if he were doing something not merely +important but pleasing to Balashev, he raised his hand to the +forty-year-old Russian general's face and, taking him by the ear, +pulled it gently, smiling with his lips only. + +To have one's ear pulled by the Emperor was considered the +greatest honor and mark of favor at the French court. + +"Well, adorer and courtier of the Emperor Alexander, why don't you +say anything?" said he, as if it was ridiculous, in his presence, to +be the adorer and courtier of anyone but himself, Napoleon. "Are the +horses ready for the general?" he added, with a slight inclination +of his head in reply to Balashev's bow. "Let him have mine, he has a +long way to go!" + +The letter taken by Balashev was the last Napoleon sent to +Alexander. Every detail of the interview was communicated to the +Russian monarch, and the war began... + + + + + +CHAPTER VIII + + +After his interview with Pierre in Moscow, Prince Andrew went to +Petersburg, on business as he told his family, but really to meet +Anatole Kuragin whom he felt it necessary to encounter. On reaching +Petersburg he inquired for Kuragin but the latter had already left the +city. Pierre had warned his brother-in-law that Prince Andrew was on +his track. Anatole Kuragin promptly obtained an appointment from the +Minister of War and went to join the army in Moldavia. While in +Petersburg Prince Andrew met Kutuzov, his former commander who was +always well disposed toward him, and Kutuzov suggested that he +should accompany him to the army in Moldavia, to which the old general +had been appointed commander in chief. So Prince Andrew, having +received an appointment on the headquarters staff, left for Turkey. + +Prince Andrew did not think it proper to write and challenge +Kuragin. He thought that if he challenged him without some fresh cause +it might compromise the young Countess Rostova and so he wanted to +meet Kuragin personally in order to find a fresh pretext for a duel. +But he again failed to meet Kuragin in Turkey, for soon after Prince +Andrew arrived, the latter returned to Russia. In a new country, +amid new conditions, Prince Andrew found life easier to bear. After +his betrothed had broken faith with him--which he felt the more +acutely the more he tried to conceal its effects--the surroundings +in which he had been happy became trying to him, and the freedom and +independence he had once prized so highly were still more so. Not only +could he no longer think the thoughts that had first come to him as he +lay gazing at the sky on the field of Austerlitz and had later +enlarged upon with Pierre, and which had filled his solitude at +Bogucharovo and then in Switzerland and Rome, but he even dreaded to +recall them and the bright and boundless horizons they had +revealed. He was now concerned only with the nearest practical matters +unrelated to his past interests, and he seized on these the more +eagerly the more those past interests were closed to him. It was as if +that lofty, infinite canopy of heaven that had once towered above +him had suddenly turned into a low, solid vault that weighed him down, +in which all was clear, but nothing eternal or mysterious. + +Of the activities that presented themselves to him, army service was +the simplest and most familiar. As a general on duty on Kutuzov's +staff, he applied himself to business with zeal and perseverance and +surprised Kutuzov by his willingness and accuracy in work. Not +having found Kuragin in Turkey, Prince Andrew did not think it +necessary to rush back to Russia after him, but all the same he knew +that however long it might be before he met Kuragin, despite his +contempt for him and despite all the proofs he deduced to convince +himself that it was not worth stooping to a conflict with him--he knew +that when he did meet him he would not be able to resist calling him +out, any more than a ravenous man can help snatching at food. And +the consciousness that the insult was not yet avenged, that his rancor +was still unspent, weighed on his heart and poisoned the artificial +tranquillity which he managed to obtain in Turkey by means of +restless, plodding, and rather vainglorious and ambitious activity. + +In the year 1812, when news of the war with Napoleon reached +Bucharest--where Kutuzov had been living for two months, passing his +days and nights with a Wallachian woman--Prince Andrew asked Kutuzov +to transfer him to the Western Army. Kutuzov, who was already weary of +Bolkonski's activity which seemed to reproach his own idleness, very +readily let him go and gave him a mission to Barclay de Tolly. + +Before joining the Western Army which was then, in May, encamped +at Drissa, Prince Andrew visited Bald Hills which was directly on +his way, being only two miles off the Smolensk highroad. During the +last three years there had been so many changes in his life, he had +thought, felt, and seen so much (having traveled both in the east +and the west), that on reaching Bald Hills it struck him as strange +and unexpected to find the way of life there unchanged and still the +same in every detail. He entered through the gates with their stone +pillars and drove up the avenue leading to the house as if he were +entering an enchanted, sleeping castle. The same old stateliness, +the same cleanliness, the same stillness reigned there, and inside +there was the same furniture, the same walls, sounds, and smell, and +the same timid faces, only somewhat older. Princess Mary was still the +same timid, plain maiden getting on in years, uselessly and +joylessly passing the best years of her life in fear and constant +suffering. Mademoiselle Bourienne was the same coquettish, +self-satisfied girl, enjoying every moment of her existence and full +of joyous hopes for the future. She had merely become more +self-confident, Prince Andrew thought. Dessalles, the tutor he had +brought from Switzerland, was wearing a coat of Russian cut and +talking broken Russian to the servants, but was still the same +narrowly intelligent, conscientious, and pedantic preceptor. The old +prince had changed in appearance only by the loss of a tooth, which +left a noticeable gap on one side of his mouth; in character he was +the same as ever, only showing still more irritability and +skepticism as to what was happening in the world. Little Nicholas +alone had changed. He had grown, become rosier, had curly dark hair, +and, when merry and laughing, quite unconsciously lifted the upper lip +of his pretty little mouth just as the little princess used to do. +He alone did not obey the law of immutability in the enchanted, +sleeping castle. But though externally all remained as of old, the +inner relations of all these people had changed since Prince Andrew +had seen them last. The household was divided into two alien and +hostile camps, who changed their habits for his sake and only met +because he was there. To the one camp belonged the old prince, +Madmoiselle Bourienne, and the architect; to the other Princess +Mary, Dessalles, little Nicholas, and all the old nurses and maids. + +During his stay at Bald Hills all the family dined together, but +they were ill at ease and Prince Andrew felt that he was a visitor for +whose sake an exception was being made and that his presence made them +all feel awkward. Involuntarily feeling this at dinner on the first +day, he was taciturn, and the old prince noticing this also became +morosely dumb and retired to his apartments directly after dinner. +In the evening, when Prince Andrew went to him and, trying to rouse +him, began to tell him of the young Count Kamensky's campaign, the old +prince began unexpectedly to talk about Princess Mary, blaming her for +her superstitions and her dislike of Mademoiselle Bourienne, who, he +said, was the only person really attached to him. + +The old prince said that if he was ill it was only because of +Princess Mary: that she purposely worried and irritated him, and +that by indulgence and silly talk she was spoiling little Prince +Nicholas. The old prince knew very well that he tormented his daughter +and that her life was very hard, but he also knew that he could not +help tormenting her and that she deserved it. "Why does Prince Andrew, +who sees this, say nothing to me about his sister? Does he think me +a scoundrel, or an old fool who, without any reason, keeps his own +daughter at a distance and attaches this Frenchwoman to himself? He +doesn't understand, so I must explain it, and he must hear me out," +thought the old prince. And he began explaining why he could not put +up with his daughter's unreasonable character. + +"If you ask me," said Prince Andrew, without looking up (he was +censuring his father for the first time in his life), "I did not +wish to speak about it, but as you ask me I will give you my frank +opinion. If there is any misunderstanding and discord between you +and Mary, I can't blame her for it at all. I know how she loves and +respects you. Since you ask me," continued Prince Andrew, becoming +irritable--as he was always liable to do of late--"I can only say that +if there are any misunderstandings they are caused by that worthless +woman, who is not fit to be my sister's companion." + +The old man at first stared fixedly at his son, and an unnatural +smile disclosed the fresh gap between his teeth to which Prince Andrew +could not get accustomed. + +"What companion, my dear boy? Eh? You've already been talking it +over! Eh?" + +"Father, I did not want to judge," said Prince Andrew, in a hard and +bitter tone, "but you challenged me, and I have said, and always shall +say, that Mary is not to blame, but those to blame--the one to +blame--is that Frenchwoman." + +"Ah, he has passed judgment... passed judgement!" said the old man +in a low voice and, as it seemed to Prince Andrew, with some +embarrassment, but then he suddenly jumped up and cried: "Be off, be +off! Let not a trace of you remain here!..." + + +Prince Andrew wished to leave at once, but Princess Mary persuaded +him to stay another day. That day he did not see his father, who did +not leave his room and admitted no one but Mademoiselle Bourienne +and Tikhon, but asked several times whether his son had gone. Next +day, before leaving, Prince Andrew went to his son's rooms. The boy, +curly-headed like his mother and glowing with health, sat on his knee, +and Prince Andrew began telling him the story of Bluebeard, but fell +into a reverie without finishing the story. He thought not of this +pretty child, his son whom he held on his knee, but of himself. He +sought in himself either remorse for having angered his father or +regret at leaving home for the first time in his life on bad terms +with him, and was horrified to find neither. What meant still more +to him was that he sought and did not find in himself the former +tenderness for his son which he had hoped to reawaken by caressing the +boy and taking him on his knee. + +"Well, go on!" said his son. + +Prince Andrew, without replying, put him down from his knee and went +out of the room. + +As soon as Prince Andrew had given up his daily occupations, and +especially on returning to the old conditions of life amid which he +had been happy, weariness of life overcame him with its former +intensity, and he hastened to escape from these memories and to find +some work as soon as possible. + +"So you've decided to go, Andrew?" asked his sister. + +"Thank God that I can," replied Prince Andrew. "I am very sorry +you can't." + +"Why do you say that?" replied Princess Mary. "Why do you say +that, when you are going to this terrible war, and he is so old? +Mademoiselle Bourienne says he has been asking about you...." + +As soon as she began to speak of that, her lips trembled and her +tears began to fall. Prince Andrew turned away and began pacing the +room. + +"Ah, my God! my God! When one thinks who and what--what trash--can +cause people misery!" he said with a malignity that alarmed Princess +Mary. + +She understood that when speaking of "trash" he referred not only to +Mademoiselle Bourienne, the cause of her misery, but also to the man +who had ruined his own happiness. + +"Andrew! One thing I beg, I entreat of you!" she said, touching +his elbow and looking at him with eyes that shone through her tears. +"I understand you" (she looked down). "Don't imagine that sorrow is +the work of men. Men are His tools." She looked a little above +Prince Andrew's head with the confident, accustomed look with which +one looks at the place where a familiar portrait hangs. "Sorrow is +sent by Him, not by men. Men are His instruments, they are not to +blame. If you think someone has wronged you, forget it and forgive! We +have no right to punish. And then you will know the happiness of +forgiving." + +"If I were a woman I would do so, Mary. That is a woman's virtue. +But a man should not and cannot forgive and forget," he replied, and +though till that moment he had not been thinking of Kuragin, all his +unexpended anger suddenly swelled up in his heart. + +"If Mary is already persuading me forgive, it means that I ought +long ago to have punished him," he thought. And giving her no +further reply, he began thinking of the glad vindictive moment when he +would meet Kuragin who he knew was now in the army. + +Princess Mary begged him to stay one day more, saying that she +knew how unhappy her father would be if Andrew left without being +reconciled to him, but Prince Andrew replied that he would probably +soon be back again from the army and would certainly write to his +father, but that the longer he stayed now the more embittered their +differences would become. + +"Good-by, Andrew! Remember that misfortunes come from God, and men +are never to blame," were the last words he heard from his sister when +he took leave of her. + +"Then it must be so!" thought Prince Andrew as he drove out of the +avenue from the house at Bald Hills. "She, poor innocent creature, +is left to be victimized by an old man who has outlived his wits. +The old man feels he is guilty, but cannot change himself. My boy is +growing up and rejoices in life, in which like everybody else he +will deceive or be deceived. And I am off to the army. Why? I myself +don't know. I want to meet that man whom I despise, so as to give +him a chance to kill and laugh at me!" + +These conditions of life had been the same before, but then they +were all connected, while now they had all tumbled to pieces. Only +senseless things, lacking coherence, presented themselves one after +another to Prince Andrew's mind. + + + + + +CHAPTER IX + + +Prince Andrew reached the general headquarters of the army at the +end of June. The first army, with which was the Emperor, occupied +the fortified camp at Drissa; the second army was retreating, trying +to effect a junction with the first one from which it was said to be +cut off by large French forces. Everyone was dissatisfied with the +general course of affairs in the Russian army, but no one +anticipated any danger of invasion of the Russian provinces, and no +one thought the war would extend farther than the western, the Polish, +provinces. + +Prince Andrew found Barclay de Tolly, to whom he had been +assigned, on the bank of the Drissa. As there was not a single town or +large village in the vicinity of the camp, the immense number of +generals and courtiers accompanying the army were living in the best +houses of the villages on both sides of the river, over a radius of +six miles. Barclay de Tolly was quartered nearly three miles from +the Emperor. He received Bolkonski stiffly and coldly and told him +in his foreign accent that he would mention him to the Emperor for a +decision as to his employment, but asked him meanwhile to remain on +his staff. Anatole Kuragin, whom Prince Andrew had hoped to find +with the army, was not there. He had gone to Petersburg, but Prince +Andrew was glad to hear this. His mind was occupied by the interests +of the center that was conducting a gigantic war, and he was glad to +be free for a while from the distraction caused by the thought of +Kuragin. During the first four days, while no duties were required +of him, Prince Andrew rode round the whole fortified camp and, by +the aid of his own knowledge and by talks with experts, tried to +form a definite opinion about it. But the question whether the camp +was advantageous or disadvantageous remained for him undecided. +Already from his military experience and what he had seen in the +Austrian campaign, he had come to the conclusion that in war the +most deeply considered plans have no significance and that all depends +on the way unexpected movements of the enemy--that cannot be foreseen- +are met, and on how and by whom the whole matter is handled. To +clear up this last point for himself, Prince Andrew, utilizing his +position and acquaintances, tried to fathom the character of the +control of the army and of the men and parties engaged in it, and he +deduced for himself the following of the state of affairs. + +While the Emperor had still been at Vilna, the forces had been +divided into three armies. First, the army under Barclay de Tolly, +secondly, the army under Bagration, and thirdly, the one commanded +by Tormasov. The Emperor was with the first army, but not as commander +in chief. In the orders issued it was stated, not that the Emperor +would take command, but only that he would be with the army. The +Emperor, moreover, had with him not a commander in chief's staff but +the imperial headquarters staff. In attendance on him was the head +of the imperial staff, Quartermaster General Prince Volkonski, as well +as generals, imperial aides-de-camp, diplomatic officials, and a large +number of foreigners, but not the army staff. Besides these, there +were in attendance on the Emperor without any definite appointments: +Arakcheev, the ex-Minister of War; Count Bennigsen, the senior general +in rank; the Grand Duke Tsarevich Constantine Pavlovich; Count +Rumyantsev, the Chancellor; Stein, a former Prussian minister; +Armfeldt, a Swedish general; Pfuel, the chief author of the plan of +campaign; Paulucci, an adjutant general and Sardinian emigre; +Wolzogen--and many others. Though these men had no military +appointment in the army, their position gave them influence, and often +a corps commander, or even the commander in chief, did not know in +what capacity he was questioned by Bennigsen, the Grand Duke, +Arakcheev, or Prince Volkonski, or was given this or that advice and +did not know whether a certain order received in the form of advice +emanated from the man who gave it or from the Emperor and whether it +had to be executed or not. But this was only the external condition; +the essential significance of the presence of the Emperor and of all +these people, from a courtier's point of view (and in an Emperor's +vicinity all became courtiers), was clear to everyone. It was this: +the Emperor did not assume the title of commander in chief, but +disposed of all the armies; the men around him were his assistants. +Arakcheev was a faithful custodian to enforce order and acted as the +sovereign's bodyguard. Bennigsen was a landlord in the Vilna +province who appeared to be doing the honors of the district, but +was in reality a good general, useful as an adviser and ready at +hand to replace Barclay. The Grand Duke was there because it suited +him to be. The ex-Minister Stein was there because his advice was +useful and the Emperor Alexander held him in high esteem personally. +Armfeldt virulently hated Napoleon and was a general full of +self-confidence, a quality that always influenced Alexander. +Paulucci was there because he was bold and decided in speech. The +adjutants general were there because they always accompanied the +Emperor, and lastly and chiefly Pfuel was there because he had drawn +up the plan of campaign against Napoleon and, having induced Alexander +to believe in the efficacy of that plan, was directing the whole +business of the war. With Pfuel was Wolzogen, who expressed Pfuel's +thoughts in a more comprehensible way than Pfuel himself (who was a +harsh, bookish theorist, self-confident to the point of despising +everyone else) was able to do. + +Besides these Russians and foreigners who propounded new and +unexpected ideas every day--especially the foreigners, who did so with +a boldness characteristic of people employed in a country not their +own--there were many secondary personages accompanying the army +because their principals were there. + +Among the opinions and voices in this immense, restless, +brilliant, and proud sphere, Prince Andrew noticed the following +sharply defined subdivisions of and parties: + +The first party consisted of Pfuel and his adherents--military +theorists who believed in a science of war with immutable laws--laws +of oblique movements, outflankings, and so forth. Pfuel and his +adherents demanded a retirement into the depths of the country in +accordance with precise laws defined by a pseudo-theory of war, and +they saw only barbarism, ignorance, or evil intention in every +deviation from that theory. To this party belonged the foreign nobles, +Wolzogen, Wintzingerode, and others, chiefly Germans. + +The second party was directly opposed to the first; one extreme, +as always happens, was met by representatives of the other. The +members of this party were those who had demanded an advance from +Vilna into Poland and freedom from all prearranged plans. Besides +being advocates of bold action, this section also represented +nationalism, which made them still more one-sided in the dispute. They +were Russians: Bagration, Ermolov (who was beginning to come to the +front), and others. At that time a famous joke of Ermolov's was +being circulated, that as a great favor he had petitioned the +Emperor to make him a German. The men of that party, remembering +Suvorov, said that what one had to do was not to reason, or stick pins +into maps, but to fight, beat the enemy, keep him out of Russia, and +not let the army get discouraged. + +To the third party--in which the Emperor had most confidence- +belonged the courtiers who tried to arrange compromises between the +other two. The members of this party, chiefly civilians and to whom +Arakcheev belonged, thought and said what men who have no +convictions but wish to seem to have some generally say. They said +that undoubtedly war, particularly against such a genius as +Bonaparte (they called him Bonaparte now), needs most deeply devised +plans and profound scientific knowledge and in that respect Pfuel +was a genius, but at the same time it had to be acknowledged that +the theorists are often one sided, and therefore one should not +trust them absolutely, but should also listen to what Pfuel's +opponents and practical men of experience in warfare had to say, and +then choose a middle course. They insisted on the retention of the +camp at Drissa, according to Pfuel's plan, but on changing the +movements of the other armies. Though, by this course, neither one aim +nor the other could be attained, yet it seemed best to the adherents +of this third party. + +Of a fourth opinion the most conspicuous representative was the +Tsarevich, who could not forget his disillusionment at Austerlitz, +where he had ridden out at the head of the Guards, in his casque and +cavalry uniform as to a review, expecting to crush the French +gallantly; but unexpectedly finding himself in the front line had +narrowly escaped amid the general confusion. The men of this party had +both the quality and the defect of frankness in their opinions. They +feared Napoleon, recognized his strength and their own weakness, and +frankly said so. They said: "Nothing but sorrow, shame, and ruin +will come of all this! We have abandoned Vilna and Vitebsk and shall +abandon Drissa. The only reasonable thing left to do is to conclude +peace as soon as possible, before we are turned out of Petersburg." + +This view was very general in the upper army circles and found +support also in Petersburg and from the chancellor, Rumyantsev, who, +for other reasons of state, was in favor of peace. + +The fifth party consisted of those who were adherents of Barclay +de Tolly, not so much as a man but as minister of war and commander in +chief. "Be he what he may" (they always began like that), "he is an +honest, practical man and we have nobody better. Give him real +power, for war cannot be conducted successfully without unity of +command, and he will show what he can do, as he did in Finland. If our +army is well organized and strong and has withdrawn to Drissa +without suffering any defeats, we owe this entirely to Barclay. If +Barclay is now to be superseded by Bennigsen all will be lost, for +Bennigsen showed his incapacity already in 1807." + +The sixth party, the Bennigsenites, said, on the contrary, that at +any rate there was no one more active and experienced than +Bennigsen: "and twist about as you may, you will have to come to +Bennigsen eventually. Let the others make mistakes now!" said they, +arguing that our retirement to Drissa was a most shameful reverse +and an unbroken series of blunders. "The more mistakes that are made +the better. It will at any rate be understood all the sooner that +things cannot go on like this. What is wanted is not some Barclay or +other, but a man like Bennigsen, who made his mark in 1807, and to +whom Napoleon himself did justice--a man whose authority would be +willingly recognized, and Bennigsen is the only such man." + +The seventh party consisted of the sort of people who are always +to be found, especially around young sovereigns, and of whom there +were particularly many round Alexander--generals and imperial +aides-de-camp passionately devoted to the Emperor, not merely as a +monarch but as a man, adoring him sincerely and disinterestedly, as +Rostov had done in 1805, and who saw in him not only all the virtues +but all human capabilities as well. These men, though enchanted with +the sovereign for refusing the command of the army, yet blamed him for +such excessive modesty, and only desired and insisted that their +adored sovereign should abandon his diffidence and openly announce +that he would place himself at the head of the army, gather round +him a commander in chief's staff, and, consulting experienced +theoreticians and practical men where necessary, would himself lead +the troops, whose spirits would thereby be raised to the highest +pitch. + +The eighth and largest group, which in its enormous numbers was to +the others as ninety-nine to one, consisted of men who desired neither +peace nor war, neither an advance nor a defensive camp at the Drissa +or anywhere else, neither Barclay nor the Emperor, neither Pfuel nor +Bennigsen, but only the one most essential thing--as much advantage +and pleasure for themselves as possible. In the troubled waters of +conflicting and intersecting intrigues that eddied about the Emperor's +headquarters, it was possible to succeed in many ways unthinkable at +other times. A man who simply wished to retain his lucrative post +would today agree with Pfuel, tomorrow with his opponent, and the +day after, merely to avoid responsibility or to please the Emperor, +would declare that he had no opinion at all on the matter. Another who +wished to gain some advantage would attract the Emperor's attention by +loudly advocating the very thing the Emperor had hinted at the day +before, and would dispute and shout at the council, beating his breast +and challenging those who did not agree with him to duels, thereby +proving that he was prepared to sacrifice himself for the common good. +A third, in the absence of opponents, between two councils would +simply solicit a special gratuity for his faithful services, well +knowing that at that moment people would be too busy to refuse him. +A fourth while seemingly overwhelmed with work would often come +accidentally under the Emperor's eye. A fifth, to achieve his +long-cherished aim of dining with the Emperor, would stubbornly insist +on the correctness or falsity of some newly emerging opinion and for +this object would produce arguments more or less forcible and correct. + +All the men of this party were fishing for rubles, decorations, +and promotions, and in this pursuit watched only the weathercock of +imperial favor, and directly they noticed it turning in any direction, +this whole drone population of the army began blowing hard that way, +so that it was all the harder for the Emperor to turn it elsewhere. +Amid the uncertainties of the position, with the menace of serious +danger giving a peculiarly threatening character to everything, amid +this vortex of intrigue, egotism, conflict of views and feelings, +and the diversity of race among these people--this eighth and +largest party of those preoccupied with personal interests imparted +great confusion and obscurity to the common task. Whatever question +arose, a swarm of these drones, without having finished their +buzzing on a previous theme, flew over to the new one and by their hum +drowned and obscured the voices of those who were disputing honestly. + +From among all these parties, just at the time Prince Andrew reached +the army, another, a ninth party, was being formed and was beginning +to raise its voice. This was the party of the elders, reasonable men +experienced and capable in state affairs, who, without sharing any +of those conflicting opinions, were able to take a detached view of +what was going on at the staff at headquarters and to consider means +of escape from this muddle, indecision, intricacy, and weakness. + +The men of this party said and thought that what was wrong +resulted chiefly from the Emperor's presence in the army with his +military court and from the consequent presence there of an +indefinite, conditional, and unsteady fluctuation of relations, +which is in place at court but harmful in an army; that a sovereign +should reign but not command the army, and that the only way out of +the position would be for the Emperor and his court to leave the army; +that the mere presence of the Emperor paralyzed the action of fifty +thousand men required to secure his personal safety, and that the +worst commander in chief if independent would be better than the +very best one trammeled by the presence and authority of the monarch. + +Just at the time Prince Andrew was living unoccupied at Drissa, +Shishkov, the Secretary of State and one of the chief +representatives of this party, wrote a letter to the Emperor which +Arakcheev and Balashev agreed to sign. In this letter, availing +himself of permission given him by the Emperor to discuss the +general course of affairs, he respectfully suggested--on the plea that +it was necessary for the sovereign to arouse a warlike spirit in the +people of the capital--that the Emperor should leave the army. + +That arousing of the people by their sovereign and his call to +them to defend their country--the very incitement which was the +chief cause of Russia's triumph in so far as it was produced by the +Tsar's personal presence in Moscow--was suggested to the Emperor, +and accepted by him, as a pretext for quitting the army. + + + + + +CHAPTER X + + +This letter had not yet been presented to the Emperor when +Barclay, one day at dinner, informed Bolkonski that the sovereign +wished to see him personally, to question him about Turkey, and that +Prince Andrew was to present himself at Bennigsen's quarters at six +that evening. + +News was received at the Emperor's quarters that very day of a fresh +movement by Napoleon which might endanger the army--news +subsequently found to be false. And that morning Colonel Michaud had +ridden round the Drissa fortifications with the Emperor and had +pointed out to him that this fortified camp constructed by Pfuel, +and till then considered a chef-d'oeuvre of tactical science which +would ensure Napoleon's destruction, was an absurdity, threatening the +destruction of the Russian army. + +Prince Andrew arrived at Bennigsen's quarters--a country gentleman's +house of moderate size, situated on the very banks of the river. +Neither Bennigsen nor the Emperor was there, but Chernyshev, the +Emperor's aide-de-camp, received Bolkonski and informed him that the +Emperor, accompanied by General Bennigsen and Marquis Paulucci, had +gone a second time that day to inspect the fortifications of the +Drissa camp, of the suitability of which serious doubts were beginning +to be felt. + +Chernyshev was sitting at a window in the first room with a French +novel in his hand. This room had probably been a music room; there was +still an organ in it on which some rugs were piled, and in one +corner stood the folding bedstead of Bennigsen's adjutant. This +adjutant was also there and sat dozing on the rolled-up bedding, +evidently exhausted by work or by feasting. Two doors led from the +room, one straight on into what had been the drawing room, and +another, on the right, to the study. Through the first door came the +sound of voices conversing in German and occasionally in French. In +that drawing room were gathered, by the Emperor's wish, not a military +council (the Emperor preferred indefiniteness), but certain persons +whose opinions he wished to know in view of the impending +difficulties. It was not a council of war, but, as it were, a +council to elucidate certain questions for the Emperor personally. +To this semicouncil had been invited the Swedish General Armfeldt, +Adjutant General Wolzogen, Wintzingerode (whom Napoleon had referred +to as a renegade French subject), Michaud, Toll, Count Stein who was +not a military man at all, and Pfuel himself, who, as Prince Andrew +had heard, was the mainspring of the whole affair. Prince Andrew had +an opportunity of getting a good look at him, for Pfuel arrived soon +after himself and, in passing through to the drawing room, stopped a +minute to speak to Chernyshev. + +At first sight, Pfuel, in his ill-made uniform of a Russian general, +which fitted him badly like a fancy costume, seemed familiar to Prince +Andrew, though he saw him now for the first time. There was about +him something of Weyrother, Mack, and Schmidt, and many other German +theorist-generals whom Prince Andrew had seen in 1805, but he was more +typical than any of them. Prince Andrew had never yet seen a German +theorist in whom all the characteristics of those others were united +to such an extent. + +Pfuel was short and very thin but broad-boned, of coarse, robust +build, broad in the hips, and with prominent shoulder blades. His face +was much wrinkled and his eyes deep set. His hair had evidently been +hastily brushed smooth in front of the temples, but stuck up behind in +quaint little tufts. He entered the room, looking restlessly and +angrily around, as if afraid of everything in that large apartment. +Awkwardly holding up his sword, he addressed Chernyshev and asked in +German where the Emperor was. One could see that he wished to pass +through the rooms as quickly as possible, finish with the bows and +greetings, and sit down to business in front of a map, where he +would feel at home. He nodded hurriedly in reply to Chernyshev, and +smiled ironically on hearing that the sovereign was inspecting the +fortifications that he, Pfuel, had planned in accord with his +theory. He muttered something to himself abruptly and in a bass voice, +as self-assured Germans do--it might have been "stupid fellow"... or +"the whole affair will be ruined," or "something absurd will come of +it."... Prince Andrew did not catch what he said and would have passed +on, but Chernyshev introduced him to Pfuel, remarking that Prince +Andrew was just back from Turkey where the war had terminated so +fortunately. Pfuel barely glanced--not so much at Prince Andrew as +past him--and said, with a laugh: "That must have been a fine tactical +war"; and, laughing contemptuously, went on into the room from which +the sound of voices was heard. + +Pfuel, always inclined to be irritably sarcastic, was particularly +disturbed that day, evidently by the fact that they had dared to +inspect and criticize his camp in his absence. From this short +interview with Pfuel, Prince Andrew, thanks to his Austerlitz +experiences, was able to form a clear conception of the man. Pfuel was +one of those hopelessly and immutably self-confident men, +self-confident to the point of martyrdom as only Germans are, +because only Germans are self-confident on the basis of an abstract +notion--science, that is, the supposed knowledge of absolute truth. +A Frenchman is self-assured because he regards himself personally, +both in mind and body, as irresistibly attractive to men and women. An +Englishman is self-assured, as being a citizen of the best-organized +state in the world, and therefore as an Englishman always knows what +he should do and knows that all he does as an Englishman is +undoubtedly correct. An Italian is self-assured because he is +excitable and easily forgets himself and other people. A Russian is +self-assured just because he knows nothing does not want to know +anything, since he does not believe that anything can be known. The +German's self-assurance is worst of all, stronger and more repulsive +than any other, because he imagines that he knows the truth- +science--which he himself has invented but which is for him the +absolute truth. + +Pfuel was evidently of that sort. He had a science--the theory of +oblique movements deduced by him from the history of Frederick the +Great's wars, and all he came across in the history of more recent +warfare seemed to him absurd and barbarous--monstrous collisions in +which so many blunders were committed by both sides that these wars +could not be called wars, they did not accord with the theory, and +therefore could not serve as material for science. + +In 1806 Pfuel had been one of those responsible, for the plan of +campaign that ended in Jena and Auerstadt, but he did not see the +least proof of the fallibility of his theory in the disasters of +that war. On the contrary, the deviations made from his theory were, +in his opinion, the sole cause of the whole disaster, and with +characteristically gleeful sarcasm he would remark, "There, I said the +whole affair would go to the devil!" Pfuel was one of those +theoreticians who so love their theory that they lose sight of the +theory's object--its practical application. His love of theory made +him hate everything practical, and he would not listen to it. He was +even pleased by failures, for failures resulting from deviations in +practice from the theory only proved to him the accuracy of his +theory. + +He said a few words to Prince Andrew and Chernyshev about the +present war, with the air of a man who knows beforehand that all +will go wrong, and who is not displeased that it should be so. The +unbrushed tufts of hair sticking up behind and the hastily brushed +hair on his temples expressed this most eloquently. + +He passed into the next room, and the deep, querulous sounds of +his voice were at once heard from there. + + + + + +CHAPTER XI + + +Prince Andrew's eyes were still following Pfuel out of the room when +Count Bennigsen entered hurriedly, and nodding to Bolkonski, but not +pausing, went into the study, giving instructions to his adjutant as +he went. The Emperor was following him, and Bennigsen had hastened +on to make some preparations and to be ready to receive the sovereign. +Chernyshev and Prince Andrew went out into the porch, where the +Emperor, who looked fatigued, was dismounting. Marquis Paulucci was +talking to him with particular warmth and the Emperor, with his head +bent to the left, was listening with a dissatisfied air. The Emperor +moved forward evidently wishing to end the conversation, but the +flushed and excited Italian, oblivious of decorum, followed him and +continued to speak. + +"And as for the man who advised forming this camp--the Drissa camp," +said Paulucci, as the Emperor mounted the steps and noticing Prince +Andrew scanned his unfamiliar face, "as to that person, sire..." +continued Paulucci, desperately, apparently unable to restrain +himself, "the man who advised the Drissa camp--I see no alternative +but the lunatic asylum or the gallows!" + +Without heeding the end of the Italian's remarks, and as though +not hearing them, the Emperor, recognizing Bolkonski, addressed him +graciously. + +"I am very glad to see you! Go in there where they are meeting, +and wait for me." + +The Emperor went into the study. He was followed by Prince Peter +Mikhaylovich Volkonski and Baron Stein, and the door closed behind +them. Prince Andrew, taking advantage of the Emperor's permission, +accompanied Paulucci, whom he had known in Turkey, into the drawing +room where the council was assembled. + +Prince Peter Mikhaylovich Volkonski occupied the position, as it +were, of chief of the Emperor's staff. He came out of the study into +the drawing room with some maps which he spread on a table, and put +questions on which he wished to hear the opinion of the gentlemen +present. What had happened was that news (which afterwards proved to +be false) had been received during the night of a movement by the +French to outflank the Drissa camp. + +The first to speak was General Armfeldt who, to meet the +difficulty that presented itself, unexpectedly proposed a perfectly +new position away from the Petersburg and Moscow roads. The reason for +this was inexplicable (unless he wished to show that he, too, could +have an opinion), but he urged that at this point the army should +unite and there await the enemy. It was plain that Armfeldt had +thought out that plan long ago and now expounded it not so much to +answer the questions put--which, in fact, his plan did not answer- +as to avail himself of the opportunity to air it. It was one of the +millions of proposals, one as good as another, that could be made as +long as it was quite unknown what character the war would take. Some +disputed his arguments, others defended them. Young Count Toll +objected to the Swedish general's views more warmly than anyone +else, and in the course of the dispute drew from his side pocket a +well-filled notebook, which he asked permission to read to them. In +these voluminous notes Toll suggested another scheme, totally +different from Armfeldt's or Pfuel's plan of campaign. In answer to +Toll, Paulucci suggested an advance and an attack, which, he urged, +could alone extricate us from the present uncertainty and from the +trap (as he called the Drissa camp) in which we were situated. + +During all these discussions Pfuel and his interpreter, Wolzogen +(his "bridge" in court relations), were silent. Pfuel only snorted +contemptuously and turned away, to show that he would never demean +himself by replying to such nonsense as he was now hearing. So when +Prince Volkonski, who was in the chair, called on him to give his +opinion, he merely said: + +"Why ask me? General Armfeldt has proposed a splendid position +with an exposed rear, or why not this Italian gentleman's attack--very +fine, or a retreat, also good! Why ask me?" said he. "Why, you +yourselves know everything better than I do." + +But when Volkonski said, with a frown, that it was in the +Emperor's name that he asked his opinion, Pfuel rose and, suddenly +growing animated, began to speak: + +"Everything has been spoiled, everything muddled, everybody +thought they knew better than I did, and now you come to me! How +mend matters? There is nothing to mend! The principles laid down by me +must be strictly adhered to," said he, drumming on the table with +his bony fingers. "What is the difficulty? Nonsense, childishness!" + +He went up to the map and speaking rapidly began proving that no +eventuality could alter the efficiency of the Drissa camp, that +everything had been foreseen, and that if the enemy were really +going to outflank it, the enemy would inevitably be destroyed. + +Paulucci, who did not know German, began questioning him in +French. Wolzogen came to the assistance of his chief, who spoke French +badly, and began translating for him, hardly able to keep pace with +Pfuel, who was rapidly demonstrating that not only all that had +happened, but all that could happen, had been foreseen in his +scheme, and that if there were now any difficulties the whole fault +lay in the fact that his plan had not been precisely executed. He kept +laughing sarcastically, he demonstrated, and at last contemptuously +ceased to demonstrate, like a mathematician who ceases to prove in +various ways the accuracy of a problem that has already been proved. +Wolzogen took his place and continued to explain his views in +French, every now and then turning to Pfuel and saying, "Is it not so, +your excellency?" But Pfuel, like a man heated in a fight who + +strikes those on his own side, shouted angrily at his own supporter, +Wolzogen: + +"Well, of course, what more is there to explain?" + +Paulucci and Michaud both attacked Wolzogen simultaneously in +French. Armfeldt addressed Pfuel in German. Toll explained to +Volkonski in Russian. Prince Andrew listened and observed in silence. + +Of all these men Prince Andrew sympathized most with Pfuel, angry, +determined, and absurdly self-confident as he was. Of all those +present, evidently he alone was not seeking anything for himself, +nursed no hatred against anyone, and only desired that the plan, +formed on a theory arrived at by years of toil, should be carried out. +He was ridiculous, and unpleasantly sarcastic, but yet he inspired +involuntary respect by his boundless devotion to an idea. Besides +this, the remarks of all except Pfuel had one common trait that had +not been noticeable at the council of war in 1805: there was now a +panic fear of Napoleon's genius, which, though concealed, was +noticeable in every rejoinder. Everything was assumed to be possible +for Napoleon, they expected him from every side, and invoked his +terrible name to shatter each other's proposals. Pfuel alone seemed to +consider Napoleon a barbarian like everyone else who opposed his +theory. But besides this feeling of respect, Pfuel evoked pity in +Prince Andrew. From the tone in which the courtiers addressed him +and the way Paulucci had allowed himself to speak of him to the +Emperor, but above all from a certain desperation in Pfuel's own +expressions, it was clear that the others knew, and Pfuel himself +felt, that his fall was at hand. And despite his self-confidence and +grumpy German sarcasm he was pitiable, with his hair smoothly +brushed on the temples and sticking up in tufts behind. Though he +concealed the fact under a show of irritation and contempt, he was +evidently in despair that the sole remaining chance of verifying his +theory by a huge experiment and proving its soundness to the whole +world was slipping away from him. + +The discussions continued a long time, and the longer they lasted +the more heated became the disputes, culminating in shouts and +personalities, and the less was it possible to arrive at any general +conclusion from all that had been said. Prince Andrew, listening to +this polyglot talk and to these surmises, plans, refutations, and +shouts, felt nothing but amazement at what they were saying. A thought +that had long since and often occurred to him during his military +activities--the idea that there is not and cannot be any science of +war, and that therefore there can be no such thing as a military +genius--now appeared to him an obvious truth. "What theory and science +is possible about a matter the conditions and circumstances of which +are unknown and cannot be defined, especially when the strength of the +acting forces cannot be ascertained? No one was or is able to +foresee in what condition our or the enemy's armies will be in a day's +time, and no one can gauge the force of this or that detachment. +Sometimes--when there is not a coward at the front to shout, 'We are +cut off!' and start running, but a brave and jolly lad who shouts, +'Hurrah!'--a detachment of five thousand is worth thirty thousand, +as at Schon Grabern, while at times fifty thousand run from eight +thousand, as at Austerlitz. What science can there be in a matter in +which, as in all practical matters, nothing can be defined and +everything depends on innumerable conditions, the significance of +which is determined at a particular moment which arrives no one +knows when? Armfeldt says our army is cut in half, and Paulucci says +we have got the French army between two fires; Michaud says that the +worthlessness of the Drissa camp lies in having the river behind it, +and Pfuel says that is what constitutes its strength; Toll proposes +one plan, Armfeldt another, and they are all good and all bad, and the +advantages of any suggestions can be seen only at the moment of trial. +And why do they all speak of a 'military genius'? Is a man a genius +who can order bread to be brought up at the right time and say who +is to go to the right and who to the left? It is only because military +men are invested with pomp and power and crowds of sychophants flatter +power, attributing to it qualities of genius it does not possess. +The best generals I have known were, on the contrary, stupid or +absent-minded men. Bagration was the best, Napoleon himself admitted +that. And of Bonaparte himself! I remember his limited, self-satisfied +face on the field of Austerlitz. Not only does a good army commander +not need any special qualities, on the contrary he needs the absence +of the highest and best human attributes--love, poetry, tenderness, +and philosophic inquiring doubt. He should be limited, firmly +convinced that what he is doing is very important (otherwise he will +not have sufficient patience), and only then will he be a brave +leader. God forbid that he should be humane, should love, or pity, +or think of what is just and unjust. It is understandable that a +theory of their 'genius' was invented for them long ago because they +have power! The success of a military action depends not on them, +but on the man in the ranks who shouts, 'We are lost!' or who +shouts, 'Hurrah!' And only in the ranks can one serve with assurance +of being useful." + +So thought Prince Andrew as he listened to the talking, and he +roused himself only when Paulucci called him and everyone was leaving. + +At the review next day the Emperor asked Prince Andrew where he +would like to serve, and Prince Andrew lost his standing in court +circles forever by not asking to remain attached to the sovereign's +person, but for permission to serve in the army. + + + + + +CHAPTER XII + + +Before the beginning of the campaign, Rostov had received a letter +from his parents in which they told him briefly of Natasha's illness +and the breaking off of her engagement to Prince Andrew (which they +explained by Natasha's having rejected him) and again asked Nicholas +to retire from the army and return home. On receiving this letter, +Nicholas did not even make any attempt to get leave of absence or to +retire from the army, but wrote to his parents that he was sorry +Natasha was ill and her engagement broken off, and that he would do +all he could to meet their wishes. To Sonya he wrote separately. + +"Adored friend of my soul!" he wrote. "Nothing but honor could +keep me from returning to the country. But now, at the commencement of +the campaign, I should feel dishonored, not only in my comrades' +eyes but in my own, if I preferred my own happiness to my love and +duty to the Fatherland. But this shall be our last separation. Believe +me, directly the war is over, if I am still alive and still loved by +you, I will throw up everything and fly to you, to press you forever +to my ardent breast." + +It was, in fact, only the commencement of the campaign that +prevented Rostov from returning home as he had promised and marrying +Sonya. The autumn in Otradnoe with the hunting, and the winter with +the Christmas holidays and Sonya's love, had opened out to him a vista +of tranquil rural joys and peace such as he had never known before, +and which now allured him. "A splendid wife, children, a good pack +of hounds, a dozen leashes of smart borzois, agriculture, neighbors, +service by election..." thought he. But now the campaign was +beginning, and he had to remain with his regiment. And since it had to +be so, Nicholas Rostov, as was natural to him, felt contented with the +life he led in the regiment and was able to find pleasure in that +life. + +On his return from his furlough Nicholas, having been joyfully +welcomed by his comrades, was sent to obtain remounts and brought back +from the Ukraine excellent horses which pleased him and earned him +commendation from his commanders. During his absence he had been +promoted captain, and when the regiment was put on war footing with an +increase in numbers, he was again allotted his old squadron. + +The campaign began, the regiment was moved into Poland on double +pay, new officers arrived, new men and horses, and above all everybody +was infected with the merrily excited mood that goes with the +commencement of a war, and Rostov, conscious of his advantageous +position in the regiment, devoted himself entirely to the pleasures +and interests of military service, though he knew that sooner or later +he would have to relinquish them. + +The troops retired from Vilna for various complicated reasons of +state, political and strategic. Each step of the retreat was +accompanied by a complicated interplay of interests, arguments, and +passions at headquarters. For the Pavlograd hussars, however, the +whole of this retreat during the finest period of summer and with +sufficient supplies was a very simple and agreeable business. + +It was only at headquarters that there was depression, uneasiness, +and intriguing; in the body of the army they did not ask themselves +where they were going or why. If they regretted having to retreat, +it was only because they had to leave billets they had grown +accustomed to, or some pretty young Polish lady. If the thought that +things looked bad chanced to enter anyone's head, he tried to be as +cheerful as befits a good soldier and not to think of the general +trend of affairs, but only of the task nearest to hand. First they +camped gaily before Vilna, making acquaintance with the Polish +landowners, preparing for reviews and being reviewed by the Emperor +and other high commanders. Then came an order to retreat to Sventsyani +and destroy any provisions they could not carry away with them. +Sventsyani was remembered by the hussars only as the drunken camp, a +name the whole army gave to their encampment there, and because many +complaints were made against the troops, who, taking advantage of +the order to collect provisions, took also horses, carriages, and +carpets from the Polish proprietors. Rostov remembered Sventsyani, +because on the first day of their arrival at that small town he +changed his sergeant major and was unable to manage all the drunken +men of his squadron who, unknown to him, had appropriated five barrels +of old beer. From Sventsyani they retired farther and farther to +Drissa, and thence again beyond Drissa, drawing near to the frontier +of Russia proper. + +On the thirteenth of July the Pavlograds took part in a serious +action for the first time. + +On the twelfth of July, on the eve of that action, there was a heavy +storm of rain and hail. In general, the summer of 1812 was +remarkable for its storms. + +The two Pavlograd squadrons were bivouacking on a field of rye, +which was already in ear but had been completely trodden down by +cattle and horses. The rain was descending in torrents, and Rostov, +with a young officer named Ilyin, his protege, was sitting in a +hastily constructed shelter. An officer of their regiment, with long +mustaches extending onto his cheeks, who after riding to the staff had +been overtaken by the rain, entered Rostov's shelter. + +"I have come from the staff, Count. Have you heard of Raevski's +exploit?" + +And the officer gave them details of the Saltanov battle, which he +had heard at the staff. + +Rostov, smoking his pipe and turning his head about as the water +trickled down his neck, listened inattentively, with an occasional +glance at Ilyin, who was pressing close to him. This officer, a lad of +sixteen who had recently joined the regiment, was now in the same +relation to Nicholas that Nicholas had been to Denisov seven years +before. Ilyin tried to imitate Rostov in everything and adored him +as a girl might have done. + +Zdrzhinski, the officer with the long mustache, spoke +grandiloquently of the Saltanov dam being "a Russian Thermopylae," and +of how a deed worthy of antiquity had been performed by General +Raevski. He recounted how Raevski had led his two sons onto the dam +under terrific fire and had charged with them beside him. Rostov heard +the story and not only said nothing to encourage Zdrzhinski's +enthusiasm but, on the contrary, looked like a man ashamed of what +he was hearing, though with no intention of contradicting it. Since +the campaigns of Austerlitz and of 1807 Rostov knew by experience that +men always lie when describing military exploits, as he himself had +done when recounting them; besides that, he had experience enough to +know that nothing happens in war at all as we can imagine or relate +it. And so he did not like Zdrzhinski's tale, nor did he like +Zdrzhinski himself who, with his mustaches extending over his +cheeks, bent low over the face of his hearer, as was his habit, and +crowded Rostov in the narrow shanty. Rostov looked at him in +silence. "In the first place, there must have been such a confusion +and crowding on the dam that was being attacked that if Raevski did +lead his sons there, it could have had no effect except perhaps on +some dozen men nearest to him," thought he, "the rest could not have +seen how or with whom Raevski came onto the dam. And even those who +did see it would not have been much stimulated by it, for what had +they to do with Raevski's tender paternal feelings when their own +skins were in danger? And besides, the fate of the Fatherland did +not depend on whether they took the Saltanov dam or not, as we are +told was the case at Thermopylae. So why should he have made such a +sacrifice? And why expose his own children in the battle? I would +not have taken my brother Petya there, or even Ilyin, who's a stranger +to me but a nice lad, but would have tried to put them somewhere under +cover," Nicholas continued to think, as he listened to Zdrzhinski. But +he did not express his thoughts, for in such matters, too, he had +gained experience. He knew that this tale redounded to the glory of +our arms and so one had to pretend not to doubt it. And he acted +accordingly. + +"I can't stand this any more," said Ilyin, noticing that Rostov +did not relish Zdrzhinski's conversation. "My stockings and shirt... +and the water is running on my seat! I'll go and look for shelter. The +rain seems less heavy." + +Ilyin went out and Zdrzhinski rode away. + +Five minutes later Ilyin, splashing through the mud, came running +back to the shanty. + +"Hurrah! Rostov, come quick! I've found it! About two hundred +yards away there's a tavern where ours have already gathered. We can +at least get dry there, and Mary Hendrikhovna's there." + +Mary Hendrikhovna was the wife of the regimental doctor, a pretty +young German woman he had married in Poland. The doctor, whether +from lack of means or because he did not like to part from his young +wife in the early days of their marriage, took her about with him +wherever the hussar regiment went and his jealousy had become a +standing joke among the hussar officers. + +Rostov threw his cloak over his shoulders, shouted to Lavrushka to +follow with the things, and--now slipping in the mud, now splashing +right through it--set off with Ilyin in the lessening rain and the +darkness that was occasionally rent by distant lightning. + +"Rostov, where are you?" + +"Here. What lightning!" they called to one another. + + + + + +CHAPTER XIII + + +In the tavern, before which stood the doctor's covered cart, there +were already some five officers. Mary Hendrikhovna, a plump little +blonde German, in a dressing jacket and nightcap, was sitting on a +broad bench in the front corner. Her husband, the doctor, lay asleep +behind her. Rostov and Ilyin, on entering the room, were welcomed with +merry shouts and laughter. + +"Dear me, how jolly we are!" said Rostov laughing. + +"And why do you stand there gaping?" + +"What swells they are! Why, the water streams from them! Don't +make our drawing room so wet." + +"Don't mess Mary Hendrikhovna's dress!" cried other voices. + +Rostov and Ilyin hastened to find a corner where they could change +into dry clothes without offending Mary Hendrikhovna's modesty. They +were going into a tiny recess behind a partition to change, but +found it completely filled by three officers who sat playing cards +by the light of a solitary candle on an empty box, and these +officers would on no account yield their position. Mary Hendrikhovna +obliged them with the loan of a petticoat to be used as a curtain, and +behind that screen Rostov and Ilyin, helped by Lavrushka who had +brought their kits, changed their wet things for dry ones. + +A fire was made up in the dilapidated brick stove. A board was +found, fixed on two saddles and covered with a horsecloth, a small +samovar was produced and a cellaret and half a bottle of rum, and +having asked Mary Hendrikhovna to preside, they all crowded round her. +One offered her a clean handkerchief to wipe her charming hands, +another spread a jacket under her little feet to keep them from the +damp, another hung his coat over the window to keep out the draft, and +yet another waved the flies off her husband's face, lest he should +wake up. + +"Leave him alone," said Mary Hendrikhovna, smiling timidly and +happily. "He is sleeping well as it is, after a sleepless night." + +"Oh, no, Mary Hendrikhovna," replied the officer, "one must look +after the doctor. Perhaps he'll take pity on me someday, when it comes +to cutting off a leg or an arm for me." + +There were only three tumblers, the water was so muddy that one +could not make out whether the tea was strong or weak, and the samovar +held only six tumblers of water, but this made it all the pleasanter +to take turns in order of seniority to receive one's tumbler from Mary +Hendrikhovna's plump little hands with their short and not overclean +nails. All the officers appeared to be, and really were, in love +with her that evening. Even those playing cards behind the partition +soon left their game and came over to the samovar, yielding to the +general mood of courting Mary Hendrikhovna. She, seeing herself +surrounded by such brilliant and polite young men, beamed with +satisfaction, try as she might to hide it, and perturbed as she +evidently was each time her husband moved in his sleep behind her. + +There was only one spoon, sugar was more plentiful than anything +else, but it took too long to dissolve, so it was decided that Mary +Hendrikhovna should stir the sugar for everyone in turn. Rostov +received his tumbler, and adding some rum to it asked Mary +Hendrikhovna to stir it. + +"But you take it without sugar?" she said, smiling all the time, +as if everything she said and everything the others said was very +amusing and had a double meaning. + +"It is not the sugar I want, but only that your little hand should +stir my tea." + +Mary Hendrikhovna assented and began looking for the spoon which +someone meanwhile had pounced on. + +"Use your finger, Mary Hendrikhovna, it will be still nicer," said +Rostov. + +"Too hot!" she replied, blushing with pleasure. + +Ilyin put a few drops of rum into the bucket of water and brought it +to Mary Hendrikhovna, asking her to stir it with her finger. + +"This is my cup," said he. "Only dip your finger in it and I'll +drink it all up." + +When they had emptied the samovar, Rostov took a pack of cards and +proposed that they should play "Kings" with Mary Hendrikhovna. They +drew lots to settle who should make up her set. At Rostov's suggestion +it was agreed that whoever became "King" should have the right to kiss +Mary Hendrikhovna's hand, and that the "Booby" should go to refill and +reheat the samovar for the doctor when the latter awoke. + +"Well, but supposing Mary Hendrikhovna is 'King'?" asked Ilyin. + +"As it is, she is Queen, and her word is law!" + +They had hardly begun to play before the doctor's disheveled head +suddenly appeared from behind Mary Hendrikhovna. He had been awake for +some time, listening to what was being said, and evidently found +nothing entertaining or amusing in what was going on. His face was sad +and depressed. Without greeting the officers, he scratched himself and +asked to be allowed to pass as they were blocking the way. As soon +as he had left the room all the officers burst into loud laughter +and Mary Hendrikhovna blushed till her eyes filled with tears and +thereby became still more attractive to them. Returning from the yard, +the doctor told his wife (who had ceased to smile so happily, and +looked at him in alarm, awaiting her sentence) that the rain had +ceased and they must go to sleep in their covered cart, or +everything in it would be stolen. + +"But I'll send an orderly.... Two of them!" said Rostov. "What an +idea, doctor!" + +"I'll stand guard on it myself!" said Ilyin. + +"No, gentlemen, you have had your sleep, but I have not slept for +two nights," replied the doctor, and he sat down morosely beside his +wife, waiting for the game to end. + +Seeing his gloomy face as he frowned at his wife, the officers +grew still merrier, and some of them could not refrain from +laughter, for which they hurriedly sought plausible pretexts. When +he had gone, taking his wife with him, and had settled down with her +in their covered cart, the officers lay down in the tavern, covering +themselves with their wet cloaks, but they did not sleep for a long +time; now they exchanged remarks, recalling the doctor's uneasiness +and his wife's delight, now they ran out into the porch and reported +what was taking place in the covered trap. Several times Rostov, +covering his head, tried to go to sleep, but some remark would +arouse him and conversation would be resumed, to the accompaniment +of unreasoning, merry, childlike laughter. + + + + + +CHAPTER XIV + + +It was nearly three o'clock but no one was yet asleep, when the +quartermaster appeared with an order to move on to the little town +of Ostrovna. Still laughing and talking, the officers began +hurriedly getting ready and again boiled some muddy water +in the samovar. But Rostov went off to his squadron without waiting +for tea. Day was breaking, the rain had ceased, and the clouds were +dispersing. It felt damp and cold, especially in clothes that were +still moist. As they left the tavern in the twilight of the dawn, +Rostov and Ilyin both glanced under the wet and glistening leather +hood of the doctor's cart, from under the apron of which his feet were +sticking out, and in the middle of which his wife's nightcap was +visible and her sleepy breathing audible. + +"She really is a dear little thing," said Rostov to Ilyin, who was +following him. + +"A charming woman!" said Ilyin, with all the gravity of a boy of +sixteen. + +Half an hour later the squadron was lined up on the road. The +command was heard to "mount" and the soldiers crossed themselves and +mounted. Rostov riding in front gave the order "Forward!" and the +hussars, with clanking sabers and subdued talk, their horses' hoofs +splashing in the mud, defiled in fours and moved along the broad +road planted with birch trees on each side, following the infantry and +a battery that had gone on in front. + +Tattered, blue-purple clouds, reddening in the east, were scudding +before the wind. It was growing lighter and lighter. That curly +grass which always grows by country roadsides became clearly +visible, still wet with the night's rain; the drooping branches of the +birches, also wet, swayed in the wind and flung down bright drops of +water to one side. The soldiers' faces were more and more clearly +visible. Rostov, always closely followed by Ilyin, rode along the side +of the road between two rows of birch trees. + +When campaigning, Rostov allowed himself the indulgence of riding +not a regimental but a Cossack horse. A judge of horses and a +sportsman, he had lately procured himself a large, fine, mettlesome, +Donets horse, dun-colored, with light mane and tail, and when he +rode it no one could outgallop him. To ride this horse was a +pleasure to him, and he thought of the horse, of the morning, of the +doctor's wife, but not once of the impending danger. + +Formerly, when going into action, Rostov had felt afraid; now he had +not the least feeling of fear. He was fearless, not because he had +grown used to being under fire (one cannot grow used to danger), but +because he had learned how to manage his thoughts when in danger. He +had grown accustomed when going into action to think about anything +but what would seem most likely to interest him--the impending danger. +During the first period of his service, hard as he tried and much as +he reproached himself with cowardice, he had not been able to do this, +but with time it had come of itself. Now he rode beside Ilyin under +the birch trees, occasionally plucking leaves from a branch that met +his hand, sometimes touching his horse's side with his foot, or, +without turning round, handing a pipe he had finished to an hussar +riding behind him, with as calm and careless an air as though he +were merely out for a ride. He glanced with pity at the excited face +of Ilyin, who talked much and in great agitation. He knew from +experience the tormenting expectation of terror and death the cornet +was suffering and knew that only time could help him. + +As soon as the sun appeared in a clear strip of sky beneath the +clouds, the wind fell, as if it dared not spoil the beauty of the +summer morning after the storm; drops still continued to fall, but +vertically now, and all was still. The whole sun appeared on the +horizon and disappeared behind a long narrow cloud that hung above it. +A few minutes later it reappeared brighter still from behind the top +of the cloud, tearing its edge. Everything grew bright and +glittered. And with that light, and as if in reply to it, came the +sound of guns ahead of them. + +Before Rostov had had time to consider and determine the distance of +that firing, Count Ostermann-Tolstoy's adjutant came galloping from +Vitebsk with orders to advance at a trot along the road. + +The squadron overtook and passed the infantry and the battery--which +had also quickened their pace--rode down a hill, and passing through +an empty and deserted village again ascended. The horses began to +lather and the men to flush. + +"Halt! Dress your ranks!" the order of the regimental commander +was heard ahead. "Forward by the left. Walk, march!" came the order +from in front. + +And the hussars, passing along the line of troops on the left +flank of our position, halted behind our Uhlans who were in the +front line. To the right stood our infantry in a dense column: they +were the reserve. Higher up the hill, on the very horizon, our guns +were visible through the wonderfully clear air, brightly illuminated +by slanting morning sunbeams. In front, beyond a hollow dale, could be +seen the enemy's columns and guns. Our advanced line, already in +action, could be heard briskly exchanging shots with the enemy in +the dale. + +At these sounds, long unheard, Rostov's spirits rose, as at the +strains of the merriest music. Trap-ta-ta-tap! cracked the shots, +now together, now several quickly one after another. Again all was +silent and then again it sounded as if someone were walking on +detonators and exploding them. + +The hussars remained in the same place for about an hour. A +cannonade began. Count Ostermann with his suite rode up behind the +squadron, halted, spoke to the commander of the regiment, and rode +up the hill to the guns. + +After Ostermann had gone, a command rang out to the Uhlans. + +"Form column! Prepare to charge!" + +The infantry in front of them parted into platoons to allow the +cavalry to pass. The Uhlans started, the streamers on their spears +fluttering, and trotted downhill toward the French cavalry which was +seen below to the left. + +As soon as the Uhlans descended the hill, the hussars were ordered +up the hill to support the battery. As they took the places vacated by +the Uhlans, bullets came from the front, whining and whistling, but +fell spent without taking effect. + +The sounds, which he had not heard for so long, had an even more +pleasurable and exhilarating effect on Rostov than the previous sounds +of firing. Drawing himself up, he viewed the field of battle opening +out before him from the hill, and with his whole soul followed the +movement of the Uhlans. They swooped down close to the French +dragoons, something confused happened there amid the smoke, and five +minutes later our Uhlans were galloping back, not to the place they +had occupied but more to the left, and among the orange-colored Uhlans +on chestnut horses and behind them, in a large group, blue French +dragoons on gray horses could be seen. + + + + + +CHAPTER XV + + +Rostov, with his keen sportsman's eye, was one of the first to catch +sight of these blue French dragoons pursuing our Uhlans. Nearer and +nearer in disorderly crowds came the Uhlans and the French dragoons +pursuing them. He could already see how these men, who looked so small +at the foot of the hill, jostled and overtook one another, waving +their arms and their sabers in the air. + +Rostov gazed at what was happening before him as at a hunt. He +felt instinctively that if the hussars struck at the French dragoons +now, the latter could not withstand them, but if a charge was to be +made it must be done now, at that very moment, or it would be too +late. He looked around. A captain, standing beside him, was gazing +like himself with eyes fixed on the cavalry below them. + +"Andrew Sevastyanych!" said Rostov. "You know, we could crush +them...." + +"A fine thing too!" replied the captain, "and really..." + +Rostov, without waiting to hear him out, touched his horse, galloped +to the front of his squadron, and before he had time to finish +giving the word of command, the whole squadron, sharing his feeling, +was following him. Rostov himself did not know how or why he did it. +He acted as he did when hunting, without reflecting or considering. He +saw the dragoons near and that they were galloping in disorder; he +knew they could not withstand an attack--knew there was only that +moment and that if he let it slip it would not return. The bullets +were whining and whistling so stimulatingly around him and his horse +was so eager to go that he could not restrain himself. He touched +his horse, gave the word of command, and immediately, hearing behind +him the tramp of the horses of his deployed squadron, rode at full +trot downhill toward the dragoons. Hardly had they reached the +bottom of the hill before their pace instinctively changed to a +gallop, which grew faster and faster as they drew nearer to our Uhlans +and the French dragoons who galloped after them. The dragoons were now +close at hand. On seeing the hussars, the foremost began to turn, +while those behind began to halt. With the same feeling with which +he had galloped across the path of a wolf, Rostov gave rein to his +Donets horse and galloped to intersect the path of the dragoons' +disordered lines. One Uhlan stopped, another who was on foot flung +himself to the ground to avoid being knocked over, and a riderless +horse fell in among the hussars. Nearly all the French dragoons were +galloping back. Rostov, picking out one on a gray horse, dashed +after him. On the way he came upon a bush, his gallant horse cleared +it, and almost before he had righted himself in his saddle he saw that +he would immediately overtake the enemy he had selected. That +Frenchman, by his uniform an officer, was going at a gallop, crouching +on his gray horse and urging it on with his saber. In another moment +Rostov's horse dashed its breast against the hindquarters of the +officer's horse, almost knocking it over, and at the same instant +Rostov, without knowing why, raised his saber and struck the Frenchman +with it. + +The instant he had done this, all Rostov's animation vanished. The +officer fell, not so much from the blow--which had but slightly cut +his arm above the elbow--as from the shock to his horse and from +fright. Rostov reined in his horse, and his eyes sought his foe to see +whom he had vanquished. The French dragoon officer was hopping with +one foot on the ground, the other being caught in the stirrup. His +eyes, screwed up with fear as if he every moment expected another +blow, gazed up at Rostov with shrinking terror. His pale and +mud-stained face--fair and young, with a dimple in the chin and +light-blue eyes--was not an enemy's face at all suited to a +battlefield, but a most ordinary, homelike face. Before Rostov had +decided what to do with him, the officer cried, "I surrender!" He +hurriedly but vainly tried to get his foot out of the stirrup and +did not remove his frightened blue eyes from Rostov's face. Some +hussars who galloped up disengaged his foot and helped him into the +saddle. On all sides, the hussars were busy with the dragoons; one was +wounded, but though his face was bleeding, he would not give up his +horse; another was perched up behind an hussar with his arms round +him; a third was being helped by an hussar to mount his horse. In +front, the French infantry were firing as they ran. The hussars +galloped hastily back with their prisoners. Rostov galloped back +with the rest, aware of an unpleasant feeling of depression in his +heart. Something vague and confused, which he could not at all account +for, had come over him with the capture of that officer and the blow +he had dealt him. + +Count Ostermann-Tolstoy met the returning hussars, sent for +Rostov, thanked him, and said he would report his gallant deed to +the Emperor and would recommend him for a St. George's Cross. When +sent for by Count Ostermann, Rostov, remembering that he had charged +without orders, felt sure his commander was sending for him to +punish him for breach of discipline. Ostermann's flattering words +and promise of a reward should therefore have struck him all the +more pleasantly, but he still felt that same vaguely disagreeable +feeling of moral nausea. "But what on earth is worrying me?" he +asked himself as he rode back from the general. "Ilyin? No, he's safe. +Have I disgraced myself in any way? No, that's not it." Something +else, resembling remorse, tormented him. "Yes, oh yes, that French +officer with the dimple. And I remember how my arm paused when I +raised it." + +Rostov saw the prisoners being led away and galloped after them to +have a look at his Frenchman with the dimple on his chin. He was +sitting in his foreign uniform on an hussar packhorse and looked +anxiously about him; The sword cut on his arm could scarcely be called +a wound. He glanced at Rostov with a feigned smile and waved his +hand in greeting. Rostov still had the same indefinite feeling, as +of shame. + +All that day and the next his friends and comrades noticed that +Rostov, without being dull or angry, was silent, thoughtful, and +preoccupied. He drank reluctantly, tried to remain alone, and kept +turning something over in his mind. + +Rostov was always thinking about that brilliant exploit of his, +which to his amazement had gained him the St. George's Cross and +even given him a reputation for bravery, and there was something he +could not at all understand. "So others are even more afraid than I +am!" he thought. "So that's all there is in what is called heroism! +And heroism! And did I do it for my country's sake? And how was he +to blame, with his dimple and blue eyes? And how frightened he was! He +thought that I should kill him. Why should I kill him? My hand +trembled. And they have given me a St. George's Cross.... I can't make +it out at all." + +But while Nicholas was considering these questions and still could +reach no clear solution of what puzzled him so, the wheel of fortune +in the service, as often happens, turned in his favor. After the +affair at Ostrovna he was brought into notice, received command of +an hussar battalion, and when a brave officer was needed he was +chosen. + + + + + +CHAPTER XVI + + +On receiving news of Natasha's illness, the countess, though not +quite well yet and still weak, went to Moscow with Petya and the +rest of the household, and the whole family moved from Marya +Dmitrievna's house to their own and settled down in town. + +Natasha's illness was so serious that, fortunately for her and for +her parents, the consideration of all that had caused the illness, her +conduct and the breaking off of her engagement, receded into the +background. She was so ill that it was impossible for them to consider +in how far she was to blame for what had happened. She could not eat +or sleep, grew visibly thinner, coughed, and, as the doctors made them +feel, was in danger. They could not think of anything but how to +help her. Doctors came to see her singly and in consultation, talked +much in French, German, and Latin, blamed one another, and +prescribed a great variety of medicines for all the diseases known +to them, but the simple idea never occurred to any of them that they +could not know the disease Natasha was suffering from, as no disease +suffered by a live man can be known, for every living person has his +own peculiarities and always has his own peculiar, personal, novel, +complicated disease, unknown to medicine--not a disease of the +lungs, liver, skin, heart, nerves, and so on mentioned in medical +books, but a disease consisting of one of the innumerable combinations +of the maladies of those organs. This simple thought could not occur +to the doctors (as it cannot occur to a wizard that he is unable to +work his charms) because the business of their lives was to cure, +and they received money for it and had spent the best years of their +lives on that business. But, above all, that thought was kept out of +their minds by the fact that they saw they were really useful, as in +fact they were to the whole Rostov family. Their usefulness did not +depend on making the patient swallow substances for the most part +harmful (the harm was scarcely perceptible, as they were given in +small doses), but they were useful, necessary, and indispensable +because they satisfied a mental need of the invalid and of those who +loved her--and that is why there are, and always will be, +pseudo-healers, wise women, homeopaths, and allopaths. They +satisfied that eternal human need for hope of relief, for sympathy, +and that something should be done, which is felt by those who are +suffering. They satisfied the need seen in its most elementary form in +a child, when it wants to have a place rubbed that has been hurt. A +child knocks itself and runs at once to the arms of its mother or +nurse to have the aching spot rubbed or kissed, and it feels better +when this is done. The child cannot believe that the strongest and +wisest of its people have no remedy for its pain, and the hope of +relief and the expression of its mother's sympathy while she rubs +the bump comforts it. The doctors were of use to Natasha because +they kissed and rubbed her bump, assuring her that it would soon +pass if only the coachman went to the chemist's in the Arbat and got a +powder and some pills in a pretty box of a ruble and seventy kopeks, +and if she took those powders in boiled water at intervals of +precisely two hours, neither more nor less. + +What would Sonya and the count and countess have done, how would +they have looked, if nothing had been done, if there had not been +those pills to give by the clock, the warm drinks, the chicken +cutlets, and all the other details of life ordered by the doctors, the +carrying out of which supplied an occupation and consolation to the +family circle? How would the count have borne his dearly loved +daughter's illness had he not known that it was costing him a thousand +rubles, and that he would not grudge thousands more to benefit her, or +had he not known that if her illness continued he would not grudge yet +other thousands and would take her abroad for consultations there, and +had he not been able to explain the details of how Metivier and Feller +had not understood the symptoms, but Frise had, and Mudrov had +diagnosed them even better? What would the countess have done had +she not been able sometimes to scold the invalid for not strictly +obeying the doctor's orders? + +"You'll never get well like that," she would say, forgetting her +grief in her vexation, "if you won't obey the doctor and take your +medicine at the right time! You mustn't trifle with it, you know, or +it may turn to pneumonia," she would go on, deriving much comfort from +the utterance of that foreign word, incomprehensible to others as well +as to herself. + +What would Sonya have done without the glad consciousness that she +had not undressed during the first three nights, in order to be +ready to carry out all the doctor's injunctions with precision, and +that she still kept awake at night so as not to miss the proper time +when the slightly harmful pills in the little gilt box had to be +administered? Even to Natasha herself it was pleasant to see that so +many sacrifices were being made for her sake, and to know that she had +to take medicine at certain hours, though she declared that no +medicine would cure her and that it was all nonsense. And it was +even pleasant to be able to show, by disregarding the orders, that she +did not believe in medical treatment and did not value her life. + +The doctor came every day, felt her pulse, looked at her tongue, and +regardless of her grief-stricken face joked with her. But when he +had gone into another room, to which the countess hurriedly followed +him, he assumed a grave air and thoughtfully shaking his head said +that though there was danger, he had hopes of the effect of this +last medicine and one must wait and see, that the malady was chiefly +mental, but... And the countess, trying to conceal the action from +herself and from him, slipped a gold coin into his hand and always +returned to the patient with a more tranquil mind. + +The symptoms of Natasha's illness were that she ate little, slept +little, coughed, and was always low-spirited. The doctors said that +she could not get on without medical treatment, so they kept her in +the stifling atmosphere of the town, and the Rostovs did not move to +the country that summer of 1812. + +In spite of the many pills she swallowed and the drops and powders +out of the little bottles and boxes of which Madame Schoss who was +fond of such things made a large collection, and in spite of being +deprived of the country life to which she was accustomed, youth +prevailed. Natasha's grief began to be overlaid by the impressions +of daily life, it ceased to press so painfully on her heart, it +gradually faded into the past, and she began to recover physically. + + + + + +CHAPTER XVII + + +Natasha was calmer but no happier. She not merely avoided all +external forms of pleasure--balls, promenades, concerts, and theaters- +but she never laughed without a sound of tears in her laughter. She +could not sing. As soon as she began to laugh, or tried to sing by +herself, tears choked her: tears of remorse, tears at the recollection +of those pure times which could never return, tears of vexation that +she should so uselessly have ruined her young life which might have +been so happy. Laughter and singing in particular seemed to her like a +blasphemy, in face of her sorrow. Without any need of +self-restraint, no wish to coquet ever entered her head. She said +and felt at that time that no man was more to her than Nastasya +Ivanovna, the buffoon. Something stood sentinel within her and forbade +her every joy. Besides, she had lost all the old interests of her +carefree girlish life that had been so full of hope. The previous +autumn, the hunting, "Uncle," and the Christmas holidays spent with +Nicholas at Otradnoe were what she recalled oftenest and most +painfully. What would she not have given to bring back even a single +day of that time! But it was gone forever. Her presentiment at the +time had not deceived her--that that state of freedom and readiness +for any enjoyment would not return again. Yet it was necessary to live +on. + +It comforted her to reflect that she was not better as she had +formerly imagined, but worse, much worse, than anybody else in the +world. But this was not enough. She knew that, and asked herself, +"What next?" But there was nothing to come. There was no joy in +life, yet life was passing. Natasha apparently tried not to be a +burden or a hindrance to anyone, but wanted nothing for herself. She +kept away from everyone in the house and felt at ease only with her +brother Petya. She liked to be with him better than with the others, +and when alone with him she sometimes laughed. She hardly ever left +the house and of those who came to see them was glad to see only one +person, Pierre. It would have been impossible to treat her with more +delicacy, greater care, and at the same time more seriously than did +Count Bezukhov. Natasha unconsciously felt this delicacy and so +found great pleasure in his society. But she was not even grateful +to him for it; nothing good on Pierre's part seemed to her to be an +effort, it seemed so natural for him to be kind to everyone that there +was no merit in his kindness. Sometimes Natasha noticed +embarrassment and awkwardness on his part in her presence, +especially when he wanted to do something to please her, or feared +that something they spoke of would awaken memories distressing to her. +She noticed this and attributed it to his general kindness and +shyness, which she imagined must be the same toward everyone as it was +to her. After those involuntary words--that if he were free he would +have asked on his knees for her hand and her love--uttered at a moment +when she was so strongly agitated, Pierre never spoke to Natasha of +his feelings; and it seemed plain to her that those words, which had +then so comforted her, were spoken as all sorts of meaningless words +are spoken to comfort a crying child. It was not because Pierre was +a married man, but because Natasha felt very strongly with him that +moral barrier the absence of which she had experienced with Kuragin +that it never entered her head that the relations between him and +herself could lead to love on her part, still less on his, or even +to the kind of tender, self-conscious, romantic friendship between a +man and a woman of which she had known several instances. + +Before the end of the fast of St. Peter, Agrafena Ivanovna Belova, a +country neighbor of the Rostovs, came to Moscow to pay her devotions +at the shrines of the Moscow saints. She suggested that Natasha should +fast and prepare for Holy Communion, and Natasha gladly welcomed the +idea. Despite the doctor's orders that she should not go out early +in the morning, Natasha insisted on fasting and preparing for the +sacrament, not as they generally prepared for it in the Rostov +family by attending three services in their own house, but as Agrafena +Ivanovna did, by going to church every day for a week and not once +missing Vespers, Matins, or Mass. + +The countess was pleased with Natasha's zeal; after the poor results +of the medical treatment, in the depths of her heart she hoped that +prayer might help her daughter more than medicines and, though not +without fear and concealing it from the doctor, she agreed to +Natasha's wish and entrusted her to Belova. Agrafena Ivanovna used +to come to wake Natasha at three in the morning, but generally found +her already awake. She was afraid of being late for Matins. Hastily +washing, and meekly putting on her shabbiest dress and an old +mantilla, Natasha, shivering in the fresh air, went out into the +deserted streets lit by the clear light of dawn. By Agrafena +Ivanovna's advice Natasha prepared herself not in their own parish, +but at a church where, according to the devout Agrafena Ivanovna, +the priest was a man of very severe and lofty life. There were never +many people in the church; Natasha always stood beside Belova in the +customary place before an icon of the Blessed Virgin, let into the +screen before the choir on the left side, and a feeling, new to her, +of humility before something great and incomprehensible, seized her +when at that unusual morning hour, gazing at the dark face of the +Virgin illuminated by the candles burning before it and by the morning +light falling from the window, she listened to the words of the +service which she tried to follow with understanding. When she +understood them her personal feeling became interwoven in the +prayers with shades of its own. When she did not understand, it was +sweeter still to think that the wish to understand everything is +pride, that it is impossible to understand all, that it is only +necessary to believe and to commit oneself to God, whom she felt +guiding her soul at those moments. She crossed herself, bowed low, and +when she did not understand, in horror at her own vileness, simply +asked God to forgive her everything, everything, to have mercy upon +her. The prayers to which she surrendered herself most of all were +those of repentance. On her way home at an early hour when she met +no one but bricklayers going to work or men sweeping the street, and +everybody within the houses was still asleep, Natasha experienced a +feeling new to her, a sense of the possibility of correcting her +faults, the possibility of a new, clean life, and of happiness. + +During the whole week she spent in this way, that feeling grew every +day. And the happiness of taking communion, or "communing" as Agrafena +Ivanovna, joyously playing with the word, called it, seemed to Natasha +so great that she felt she should never live till that blessed Sunday. + +But the happy day came, and on that memorable Sunday, when, +dressed in white muslin, she returned home after communion, for the +first time for many months she felt calm and not oppressed by the +thought of the life that lay before her. + +The doctor who came to see her that day ordered her to continue +the powders he had prescribed a fortnight previously. + +"She must certainly go on taking them morning and evening," said he, +evidently sincerely satisfied with his success. "Only, please be +particular about it. + +"Be quite easy," he continued playfully, as he adroitly took the +gold coin in his palm. "She will soon be singing and frolicking about. +The last medicine has done her a very great deal of good. She has +freshened up very much." + +The countess, with a cheerful expression on her face, looked down at +her nails and spat a little for luck as she returned to the drawing +room. + + + + + +CHAPTER XVIII + + +At the beginning of July more and more disquieting reports about the +war began to spread in Moscow; people spoke of an appeal by the +Emperor to the people, and of his coming himself from the army to +Moscow. And as up to the eleventh of July no manifesto or appeal had +been received, exaggerated reports became current about them and about +the position of Russia. It was said that the Emperor was leaving the +army because it was in danger, it was said that Smolensk had +surrendered, that Napoleon had an army of a million and only a miracle +could save Russia. + +On the eleventh of July, which was Saturday, the manifesto was +received but was not yet in print, and Pierre, who was at the +Rostovs', promised to come to dinner next day, Sunday, and bring a +copy of the manifesto and appeal, which he would obtain from Count +Rostopchin. + +That Sunday, the Rostovs went to Mass at the Razumovskis' private +chapel as usual. It was a hot July day. Even at ten o'clock, when +the Rostovs got out of their carriage at the chapel, the sultry air, +the shouts of hawkers, the light and gay summer clothes of the +crowd, the dusty leaves of the trees on the boulevard, the sounds of +the band and the white trousers of a battalion marching to parade, the +rattling of wheels on the cobblestones, and the brilliant, hot +sunshine were all full of that summer languor, that content and +discontent with the present, which is most strongly felt on a +bright, hot day in town. All the Moscow notabilities, all the Rostovs' +acquaintances, were at the Razumovskis' chapel, for, as if expecting +something to happen, many wealthy families who usually left town for +their country estates had not gone away that summer. As Natasha, at +her mother's side, passed through the crowd behind a liveried +footman who cleared the way for them, she heard a young man speaking +about her in too loud a whisper. + +"That's Rostova, the one who..." + +"She's much thinner, but all the same she's pretty!" + +She heard, or thought she heard, the names of Kuragin and Bolkonski. +But she was always imagining that. It always seemed to her that +everyone who looked at her was thinking only of what had happened to +her. With a sinking heart, wretched as she always was now when she +found herself in a crowd, Natasha in her lilac silk dress trimmed with +black lace walked--as women can walk--with the more repose and +stateliness the greater the pain and shame in her soul. She knew for +certain that she was pretty, but this no longer gave her +satisfaction as it used to. On the contrary it tormented her more than +anything else of late, and particularly so on this bright, hot +summer day in town. "It's Sunday again--another week past," she +thought, recalling that she had been here the Sunday before, "and +always the same life that is no life, and the same surroundings in +which it used to be so easy to live. I'm pretty, I'm young, and I know +that now I am good. I used to be bad, but now I know I am good," she +thought, "but yet my best years are slipping by and are no good to +anyone." She stood by her mother's side and exchanged nods with +acquaintances near her. From habit she scrutinized the ladies' +dresses, condemned the bearing of a lady standing close by who was not +crossing herself properly but in a cramped manner, and again she +thought with vexation that she was herself being judged and was +judging others, and suddenly, at the sound of the service, she felt +horrified at her own vileness, horrified that the former purity of her +soul was again lost to her. + +A comely, fresh-looking old man was conducting the service with that +mild solemnity which has so elevating and soothing an effect on the +souls of the worshipers. The gates of the sanctuary screen were +closed, the curtain was slowly drawn, and from behind it a soft +mysterious voice pronounced some words. Tears, the cause of which +she herself did not understand, made Natasha's breast heave, and a +joyous but oppressive feeling agitated her. + +"Teach me what I should do, how to live my life, how I may grow good +forever, forever!" she pleaded. + +The deacon came out onto the raised space before the altar screen +and, holding his thumb extended, drew his long hair from under his +dalmatic and, making the sign of the cross on his breast, began in a +loud and solemn voice to recite the words of the prayer... + +"In peace let us pray unto the Lord." + +"As one community, without distinction of class, without enmity, +united by brotherly love--let us pray!" thought Natasha. + +"For the peace that is from above, and for the salvation of our +souls." + +"For the world of angels and all the spirits who dwell above us," +prayed Natasha. + +When they prayed for the warriors, she thought of her brother and +Denisov. When they prayed for all traveling by land and sea, she +remembered Prince Andrew, prayed for him, and asked God to forgive her +all the wrongs she had done him. When they prayed for those who love +us, she prayed for the members of her own family, her father and +mother and Sonya, realizing for the first time how wrongly she had +acted toward them, and feeling all the strength of her love for +them. When they prayed for those who hate us, she tried to think of +her enemies and people who hated her, in order to pray for them. She +included among her enemies the creditors and all who had business +dealings with her father, and always at the thought of enemies and +those who hated her she remembered Anatole who had done her so much +harm--and though he did not hate her she gladly prayed for him as +for an enemy. Only at prayer did she feel able to think clearly and +calmly of Prince Andrew and Anatole, as men for whom her feelings were +as nothing compared with her awe and devotion to God. When they prayed +for the Imperial family and the Synod, she bowed very low and made the +sign of the cross, saying to herself that even if she did not +understand, still she could not doubt, and at any rate loved the +governing Synod and prayed for it. + +When he had finished the Litany the deacon crossed the stole over +his breast and said, "Let us commit ourselves and our whole lives to +Christ the Lord!" + +"Commit ourselves to God," Natasha inwardly repeated. "Lord God, I +submit myself to Thy will!" she thought. "I want nothing, wish for +nothing; teach me what to do and how to use my will! Take me, take +me!" prayed Natasha, with impatient emotion in her heart, not crossing +herself but letting her slender arms hang down as if expecting some +invisible power at any moment to take her and deliver her from +herself, from her regrets, desires, remorse, hopes, and sins. + +The countess looked round several times at her daughter's softened +face and shining eyes and prayed God to help her. + +Unexpectedly, in the middle of the service, and not in the usual +order Natasha knew so well, the deacon brought out a small stool, +the one he knelt on when praying on Trinity Sunday, and placed it +before the doors of the sanctuary screen. The priest came out with his +purple velvet biretta on his head, adjusted his hair, and knelt down +with an effort. Everybody followed his example and they looked at +one another in surprise. Then came the prayer just received from the +Synod--a prayer for the deliverance of Russia from hostile invasion. + +"Lord God of might, God of our salvation!" began the priest in +that voice, clear, not grandiloquent but mild, in which only the +Slav clergy read and which acts so irresistibly on a Russian heart. + +"Lord God of might, God of our salvation! Look this day in mercy and +blessing on Thy humble people, and graciously hear us, spare us, and +have mercy upon us! This foe confounding Thy land, desiring to lay +waste the whole world, rises against us; these lawless men are +gathered together to overthrow Thy kingdom, to destroy Thy dear +Jerusalem, Thy beloved Russia; to defile Thy temples, to overthrow +Thine altars, and to desecrate our holy shrines. How long, O Lord, how +long shall the wicked triumph? How long shall they wield unlawful +power? + +"Lord God! Hear us when we pray to Thee; strengthen with Thy might +our most gracious sovereign lord, the Emperor Alexander Pavlovich; +be mindful of his uprightness and meekness, reward him according to +his righteousness, and let it preserve us, Thy chosen Israel! Bless +his counsels, his undertakings, and his work; strengthen his kingdom +by Thine almighty hand, and give him victory over his enemy, even as +Thou gavest Moses the victory over Amalek, Gideon over Midian, and +David over Goliath. Preserve his army, put a bow of brass in the hands +of those who have armed themselves in Thy Name, and gird their loins +with strength for the fight. Take up the spear and shield and arise to +help us; confound and put to shame those who have devised evil against +us, may they be before the faces of Thy faithful warriors as dust +before the wind, and may Thy mighty Angel confound them and put them +to flight; may they be ensnared when they know it not, and may the +plots they have laid in secret be turned against them; let them fall +before Thy servants' feet and be laid low by our hosts! Lord, Thou art +able to save both great and small; Thou art God, and man cannot +prevail against Thee! + +"God of our fathers! Remember Thy bounteous mercy and +loving-kindness which are from of old; turn not Thy face from us, +but be gracious to our unworthiness, and in Thy great goodness and Thy +many mercies regard not our transgressions and iniquities! Create in +us a clean heart and renew a right spirit within us, strengthen us all +in Thy faith, fortify our hope, inspire us with true love one for +another, arm us with unity of spirit in the righteous defense of the +heritage Thou gavest to us and to our fathers, and let not the scepter +of the wicked be exalted against the destiny of those Thou hast +sanctified. + +"O Lord our God, in whom we believe and in whom we put our trust, +let us not be confounded in our hope of Thy mercy, and give us a token +of Thy blessing, that those who hate us and our Orthodox faith may see +it and be put to shame and perish, and may all the nations know that +Thou art the Lord and we are Thy people. Show Thy mercy upon us this +day, O Lord, and grant us Thy salvation; make the hearts of Thy +servants to rejoice in Thy mercy; smite down our enemies and destroy +them swiftly beneath the feet of Thy faithful servants! For Thou art +the defense, the succor, and the victory of them that put their +trust in Thee, and to Thee be all glory, to Father, Son, and Holy +Ghost, now and forever, world without end. Amen." + +In Natasha's receptive condition of soul this prayer affected her +strongly. She listened to every word about the victory of Moses over +Amalek, of Gideon over Midian, and of David over Goliath, and about +the destruction of "Thy Jerusalem," and she prayed to God with the +tenderness and emotion with which her heart was overflowing, but +without fully understanding what she was asking of God in that prayer. +She shared with all her heart in the prayer for the spirit of +righteousness, for the strengthening of the heart by faith and hope, +and its animation by love. But she could not pray that her enemies +might be trampled under foot when but a few minutes before she had +been wishing she had more of them that she might pray for them. But +neither could she doubt the righteousness of the prayer that was being +read on bended knees. She felt in her heart a devout and tremulous awe +at the thought of the punishment that overtakes men for their sins, +and especially of her own sins, and she prayed to God to forgive +them all, and her too, and to give them all, and her too, peace and +happiness. And it seemed to her that God heard her prayer. + + + + + +CHAPTER XIX + + +From the day when Pierre, after leaving the Rostovs' with +Natasha's grateful look fresh in his mind, had gazed at the comet that +seemed to be fixed in the sky and felt that something new was +appearing on his own horizon--from that day the problem of the +vanity and uselessness of all earthly things, that had incessantly +tormented him, no longer presented itself. That terrible question +"Why?" "Wherefore?" which had come to him amid every occupation, was +now replaced, not by another question or by a reply to the former +question, but by her image. When he listened to, or himself took +part in, trivial conversations, when he read or heard of human +baseness or folly, he was not horrified as formerly, and did not ask +himself why men struggled so about these things when all is so +transient and incomprehensible--but he remembered her as he had last +seen her, and all his doubts vanished--not because she had answered +the questions that had haunted him, but because his conception of +her transferred him instantly to another, a brighter, realm of +spiritual activity in which no one could be justified or guilty--a +realm of beauty and love which it was worth living for. Whatever +worldly baseness presented itself to him, he said to himself: + +"Well, supposing N. N. swindled the country and the Tsar, and the +country and the Tsar confer honors upon him, what does that matter? +She smiled at me yesterday and asked me to come again, and I love her, +and no one will ever know it." And his soul felt calm and peaceful. + +Pierre still went into society, drank as much and led the same +idle and dissipated life, because besides the hours he spent at the +Rostovs' there were other hours he had to spend somehow, and the +habits and acquaintances he had made in Moscow formed a current that +bore him along irresistibly. But latterly, when more and more +disquieting reports came from the seat of war and Natasha's health +began to improve and she no longer aroused in him the former feeling +of careful pity, an ever-increasing restlessness, which he could not +explain, took possession of him. He felt that the condition he was +in could not continue long, that a catastrophe was coming which +would change his whole life, and he impatiently sought everywhere +for signs of that approaching catastrophe. One of his brother Masons +had revealed to Pierre the following prophecy concerning Napoleon, +drawn from the Revelation of St. John. + +In chapter 13, verse 18, of the Apocalypse, it is said: + + +Here is wisdom. Let him that hath understanding count the number +of the beast: for it is the number of a man; and his number is Six +hundred threescore and six. + +And in the fifth verse of the same chapter: + + +And there was given unto him a mouth speaking great things and +blasphemies; and power was given unto him to continue forty and two +months. + + +The French alphabet, written out with the same numerical values as +the Hebrew, in which the first nine letters denote units and the +others tens, will have the following significance: + + a b c d e f g h i k + 1 2 3 4 5 6 7 8 9 10 + l m n o p q r s + 20 30 40 50 60 70 80 90 + t u v w x y + 100 110 120 130 140 150 + z + 160 + + +Writing the words L'Empereur Napoleon in numbers, it appears that +the sum of them is 666, and that Napoleon therefore the beast foretold +in the Apocalypse. Moreover, by applying the same system to the +words quarante-deux,* which was the term allowed to the beast that +"spoke great things and blasphemies," the same number 666 was +obtained; from which it followed that the limit fixed for Napoleon's +power had come in the year 1812 when the French emperor was forty-two. +This prophecy pleased Pierre very much and he often asked himself what +would put an end to the power of the beast, that is, of Napoleon, +and tried by the same system of using letters as numbers and adding +them up, to find an answer to the question that engrossed him. He +wrote the words L'Empereur Alexandre, La nation russe and added up +their numbers, but the sums were either more or less than 666. Once +when making such calculations he wrote down his own name in French, +Comte Pierre Besouhoff, but the sum of the numbers did not come right. +Then he changed the spelling, substituting a z for the s and adding de +and the article le, still without obtaining the desired result. Then +it occurred to him: if the answer to the question were contained in +his name, his nationality would also be given in the answer. So he +wrote Le russe Besuhof and adding up the numbers got 671. This was +only five too much, and five was represented by e, the very letter +elided from the article le before the word Empereur. By omitting the +e, though incorrectly, Pierre got the answer he sought. L'russe +Besuhof made 666. This discovery excited him. How, or by what means, +he was connected with the great event foretold in the Apocalypse he +did not know, but he did not doubt that connection for a moment. His +love for Natasha, Antichrist, Napoleon, the invasion, the comet, +666, L'Empereur Napoleon, and L'russe Besuhof--all this had to +mature and culminate, to lift him out of that spellbound, petty sphere +of Moscow habits in which he felt himself held captive and lead him to +a great achievement and great happiness. + + +*Forty-two. + + + +On the eve of the Sunday when the special prayer was read, Pierre +had promised the Rostovs to bring them, from Count Rostopchin whom +he knew well, both the appeal to the people and the news from the +army. In the morning, when he went to call at Rostopchin's he met +there a courier fresh from the army, an acquaintance of his own, who +often danced at Moscow balls. + +"Do, please, for heaven's sake, relieve me of something!" said the +courier. "I have a sackful of letters to parents." + +Among these letters was one from Nicholas Rostov to his father. +Pierre took that letter, and Rostopchin also gave him the Emperor's +appeal to Moscow, which had just been printed, the last army orders, +and his own most recent bulletin. Glancing through the army orders, +Pierre found in one of them, in the lists of killed, wounded, and +rewarded, the name of Nicholas Rostov, awarded a St. George's Cross of +the Fourth Class for courage shown in the Ostrovna affair, and in +the same order the name of Prince Andrew Bolkonski, appointed to the +command of a regiment of Chasseurs. Though he did not want to remind +the Rostovs of Bolkonski, Pierre could not refrain from making them +happy by the news of their son's having received a decoration, so he +sent that printed army order and Nicholas' letter to the Rostovs, +keeping the appeal, the bulletin, and the other orders to take with +him when he went to dinner. + +His conversation with Count Rostopchin and the latter's tone of +anxious hurry, the meeting with the courier who talked casually of how +badly things were going in the army, the rumors of the discovery of +spies in Moscow and of a leaflet in circulation stating that +Napoleon promised to be in both the Russian capitals by the autumn, +and the talk of the Emperor's being expected to arrive next day--all +aroused with fresh force that feeling of agitation and expectation +in Pierre which he had been conscious of ever since the appearance +of the comet, and especially since the beginning of the war. + +He had long been thinking of entering the army and would have done +so had he not been hindered, first, by his membership of the Society +of Freemasons to which he was bound by oath and which preached +perpetual peace and the abolition of war, and secondly, by the fact +that when he saw the great mass of Muscovites who had donned uniform +and were talking patriotism, he somehow felt ashamed to take the step. +But the chief reason for not carrying out his intention to enter the +army lay in the vague idea that he was L'russe Besuhof who had the +number of the beast, 666; that his part in the great affair of setting +a limit to the power of the beast that spoke great and blasphemous +things had been predestined from eternity, and that therefore he ought +not to undertake anything, but wait for what was bound to come to +pass. + + + + + +CHAPTER XX + + +A few intimate friends were dining with the Rostovs that day, as +usual on Sundays. + +Pierre came early so as to find them alone. + +He had grown so stout this year that he would have been abnormal had +he not been so tall, so broad of limb, and so strong that he carried +his bulk with evident ease. + +He went up the stairs, puffing and muttering something. His coachman +did not even ask whether he was to wait. He knew that when his +master was at the Rostovs' he stayed till midnight. The Rostovs' +footman rushed eagerly forward to help him off with his cloak and take +his hat and stick. Pierre, from club habit, always left both hat and +stick in the anteroom. + +The first person he saw in the house was Natasha. Even before he saw +her, while taking off his cloak, he heard her. She was practicing +solfa exercises in the music room. He knew that she had not sung since +her illness, and so the sound of her voice surprised and delighted +him. He opened the door softly and saw her, in the lilac dress she had +worn at church, walking about the room singing. She had her back to +him when he opened the door, but when, turning quickly, she saw his +broad, surprised face, she blushed and came rapidly up to him. + +"I want to try to sing again," she said, adding as if by way of +excuse, "it is, at least, something to do." + +"That's capital!" + +"How glad I am you've come! I am so happy today," she said, with the +old animation Pierre had not seen in her for along time. "You know +Nicholas has received a St. George's Cross? I am so proud of him." + +"Oh yes, I sent that announcement. But I don't want to interrupt +you," he added, and was about to go to the drawing room. + +Natasha stopped him. + +"Count, is it wrong of me to sing?" she said blushing, and fixing +her eyes inquiringly on him. + +"No... Why should it be? On the contrary... But why do you ask me?" + +"I don't know myself," Natasha answered quickly, "but I should not +like to do anything you disapproved of. I believe in you completely. +You don't know how important you are to me, how much you've done for +me...." She spoke rapidly and did not notice how Pierre flushed at her +words. "I saw in that same army order that he, Bolkonski" (she +whispered the name hastily), "is in Russia, and in the army again. +What do you think?"--she was speaking hurriedly, evidently afraid +her strength might fail her--"Will he ever forgive me? Will he not +always have a bitter feeling toward me? What do you think? What do you +think?" + +"I think..." Pierre replied, "that he has nothing to forgive.... +If I were in his place..." + +By association of ideas, Pierre was at once carried back to the +day when, trying to comfort her, he had said that if he were not +himself but the best man in the world and free, he would ask on his +knees for her hand; and the same feeling of pity, tenderness, and love +took possession of him and the same words rose to his lips. But she +did not give him time to say them. + +"Yes, you... you..." she said, uttering the word you rapturously- +"that's a different thing. I know no one kinder, more generous, or +better than you; nobody could be! Had you not been there then, and now +too, I don't know what would have become of me, because..." + +Tears suddenly rose in her eyes, she turned away, lifted her music +before her eyes, began singing again, and again began walking up and +down the room. + +Just then Petya came running in from the drawing room. + +Petya was now a handsome rosy lad of fifteen with full red lips +and resembled Natasha. He was preparing to enter the university, but +he and his friend Obolenski had lately, in secret, agreed to join +the hussars. + +Petya had come rushing out to talk to his namesake about this +affair. He had asked Pierre to find out whether he would be accepted +in the hussars. + +Pierre walked up and down the drawing room, not listening to what +Petya was saying. + +Petya pulled him by the arm to attract his attention. + +"Well, what about my plan? Peter Kirilych, for heaven's sake! You +are my only hope," said Petya. + +"Oh yes, your plan. To join the hussars? I'll mention it, I'll bring +it all up today." + +"Well, mon cher, have you got the manifesto?" asked the old count. +"The countess has been to Mass at the Razumovskis' and heard the new +prayer. She says it's very fine." + +"Yes, I've got it," said Pierre. "The Emperor is to be here +tomorrow... there's to be an Extraordinary Meeting of the nobility, +and they are talking of a levy of ten men per thousand. Oh yes, let me +congratulate you!" + +"Yes, yes, thank God! Well, and what news from the army?" + +"We are again retreating. They say we're already near Smolensk," +replied Pierre. + +"O Lord, O Lord!" exclaimed the count. "Where is the manifesto?" + +"The Emperor's appeal? Oh yes!" + +Pierre began feeling in his pockets for the papers, but could not +find them. Still slapping his pockets, he kissed the hand of the +countess who entered the room and glanced uneasily around, evidently +expecting Natasha, who had left off singing but had not yet come +into the drawing room. + +"On my word, I don't know what I've done with it," he said. + +"There he is, always losing everything!" remarked the countess. + +Natasha entered with a softened and agitated expression of face +and sat down looking silently at Pierre. As soon as she entered, +Pierre's features, which had been gloomy, suddenly lighted up, and +while still searching for the papers he glanced at her several times. + +"No, really! I'll drive home, I must have left them there. I'll +certainly..." + +"But you'll be late for dinner." + +"Oh! And my coachman has gone." + +But Sonya, who had gone to look for the papers in the anteroom, +had found them in Pierre's hat, where he had carefully tucked them +under the lining. Pierre was about to begin reading. + +"No, after dinner," said the old count, evidently expecting much +enjoyment from that reading. + +At dinner, at which champagne was drunk to the health of the new +chevalier of St. George, Shinshin told them the town news, of the +illness of the old Georgian princess, of Metivier's disappearance from +Moscow, and of how some German fellow had been brought to Rostopchin +and accused of being a French "spyer" (so Count Rostopchin had told +the story), and how Rostopchin let him go and assured the people +that he was "not a spire at all, but only an old German ruin." + +"People are being arrested..." said the count. "I've told the +countess she should not speak French so much. It's not the time for it +now." + +"And have you heard?" Shinshin asked. "Prince Golitsyn has engaged a +master to teach him Russian. It is becoming dangerous to speak +French in the streets." + +"And how about you, Count Peter Kirilych? If they call up the +militia, you too will have to mount a horse," remarked the old +count, addressing Pierre. + +Pierre had been silent and preoccupied all through dinner, seeming +not to grasp what was said. He looked at the count. + +"Oh yes, the war," he said. "No! What sort of warrior should I make? +And yet everything is so strange, so strange! I can't make it out. I +don't know, I am very far from having military tastes, but in these +times no one can answer for himself." + +After dinner the count settled himself comfortably in an easy +chair and with a serious face asked Sonya, who was considered an +excellent reader, to read the appeal. + + +"To Moscow, our ancient Capital! + +"The enemy has entered the borders of Russia with immense forces. He +comes to despoil our beloved country," + + +Sonya read painstakingly in her high-pitched voice. The count +listened with closed eyes, heaving abrupt sighs at certain passages. + +Natasha sat erect, gazing with a searching look now at her father +and now at Pierre. + +Pierre felt her eyes on him and tried not to look round. The +countess shook her head disapprovingly and angrily at every solemn +expression in the manifesto. In all these words she saw only that +the danger threatening her son would not soon be over. Shinshin, +with a sarcastic smile on his lips, was evidently preparing to make +fun of anything that gave him the opportunity: Sonya's reading, any +remark of the count's, or even the manifesto itself should no better +pretext present itself. + +After reading about the dangers that threatened Russia, the hopes +the Emperor placed on Moscow and especially on its illustrious +nobility, Sonya, with a quiver in her voice due chiefly to the +attention that was being paid to her, read the last words: + + +"We ourselves will not delay to appear among our people in that +Capital and in others parts of our realm for consultation, and for the +direction of all our levies, both those now barring the enemy's path +and those freshly formed to defeat him wherever he may appear. May the +ruin he hopes to bring upon us recoil on his own head, and may +Europe delivered from bondage glorify the name of Russia!" + + +"Yes, that's it!" cried the count, opening his moist eyes and +sniffing repeatedly, as if a strong vinaigrette had been held to his +nose; and he added, "Let the Emperor but say the word and we'll +sacrifice everything and begrudge nothing." + +Before Shinshin had time to utter the joke he was ready to make on +the count's patriotism, Natasha jumped up from her place and ran to +her father. + +"What a darling our Papa is!" she cried, kissing him, and she +again looked at Pierre with the unconscious coquetry that had returned +to her with her better spirits. + +"There! Here's a patriot for you!" said Shinshin. + +"Not a patriot at all, but simply..." Natasha replied in an +injured tone. "Everything seems funny to you, but this isn't at all +a joke...." + +"A joke indeed!" put in the count. "Let him but say the word and +we'll all go.... We're not Germans!" + +"But did you notice, it says, 'for consultation'?" said Pierre. + +"Never mind what it's for...." + +At this moment, Petya, to whom nobody was paying any attention, came +up to his father with a very flushed face and said in his breaking +voice that was now deep and now shrill: + +"Well, Papa, I tell you definitely, and Mamma too, it's as you +please, but I say definitely that you must let me enter the army, +because I can't... that's all...." + +The countess, in dismay, looked up to heaven, clasped her hands, and +turned angrily to her husband. + +"That comes of your talking!" said she. + +But the count had already recovered from his excitement. + +"Come, come!" said he. "Here's a fine warrior! No! Nonsense! You +must study." + +"It's not nonsense, Papa. Fedya Obolenski is younger than I, and +he's going too. Besides, all the same I can't study now when..." Petya +stopped short, flushed till he perspired, but still got out the words, +"when our Fatherland is in danger." + +"That'll do, that'll do--nonsense...." + +"But you said yourself that we would sacrifice everything." + +"Petya! Be quiet, I tell you!" cried the count, with a glance at his +wife, who had turned pale and was staring fixedly at her son. + +"And I tell you--Peter Kirilych here will also tell you..." + +"Nonsense, I tell you. Your mother's milk has hardly dried on your +lips and you want to go into the army! There, there, I tell you," +and the count moved to go out of the room, taking the papers, probably +to reread them in his study before having a nap. + +"Well, Peter Kirilych, let's go and have a smoke," he said. + +Pierre was agitated and undecided. Natasha's unwontedly brilliant +eyes, continually glancing at him with a more than cordial look, had +reduced him to this condition. + +"No, I think I'll go home." + +"Home? Why, you meant to spend the evening with us.... You don't +often come nowadays as it is, and this girl of mine," said the count +good-naturedly, pointing to Natasha, "only brightens up when you're +here." + +"Yes, I had forgotten... I really must go home... business..." +said Pierre hurriedly. + +"Well, then, au revoir!" said the count, and went out of the room. + +"Why are you going? Why are you upset?" asked Natasha, and she +looked challengingly into Pierre's eyes. + +"Because I love you!" was what he wanted to say, but he did not +say it, and only blushed till the tears came, and lowered his eyes. + +"Because it is better for me to come less often... because... No, +simply I have business...." + +"Why? No, tell me!" Natasha began resolutely and suddenly stopped. + +They looked at each other with dismayed and embarrassed faces. He +tried to smile but could not: his smile expressed suffering, and he +silently kissed her hand and went out. + +Pierre made up his mind not to go to the Rostovs' any more. + + + + + +CHAPTER XXI + + +After the definite refusal he had received, Petya went to his room +and there locked himself in and wept bitterly. When he came in to tea, +silent, morose, and with tear-stained face, everybody pretended not to +notice anything. + +Next day the Emperor arrived in Moscow, and several of the +Rostovs' domestic serfs begged permission to go to have a look at him. +That morning Petya was a long time dressing and arranging his hair and +collar to look like a grown-up man. He frowned before his looking +glass, gesticulated, shrugged his shoulders, and finally, without +saying a word to anyone, took his cap and left the house by the back +door, trying to avoid notice. Petya decided to go straight to where +the Emperor was and to explain frankly to some gentleman-in-waiting +(he imagined the Emperor to be always surrounded by +gentlemen-in-waiting) that he, Count Rostov, in spite of his youth +wished to serve his country; that youth could be no hindrance to +loyalty, and that he was ready to... While dressing, Petya had +prepared many fine things he meant to say to the gentleman-in-waiting. + +It was on the very fact of being so young that Petya counted for +success in reaching the Emperor--he even thought how surprised +everyone would be at his youthfulness--and yet in the arrangement of +his collar and hair and by his sedate deliberate walk he wished to +appear a grown-up man. But the farther he went and the more his +attention was diverted by the ever-increasing crowds moving toward the +Kremlin, the less he remembered to walk with the sedateness and +deliberation of a man. As he approached the Kremlin he even began to +avoid being crushed and resolutely stuck out his elbows in a +menacing way. But within the Trinity Gateway he was so pressed to +the wall by people who probably were unaware of the patriotic +intentions with which he had come that in spite of all his +determination he had to give in, and stop while carriages passed in, +rumbling beneath the archway. Beside Petya stood a peasant woman, a +footman, two tradesmen, and a discharged soldier. After standing +some time in the gateway, Petya tried to move forward in front of +the others without waiting for all the carriages to pass, and he began +resolutely working his way with his elbows, but the woman just in +front of him, who was the first against whom he directed his +efforts, angrily shouted at him: + +"What are you shoving for, young lordling? Don't you see we're all +standing still? Then why push?" + +"Anybody can shove," said the footman, and also began working his +elbows to such effect that he pushed Petya into a very filthy corner +of the gateway. + +Petya wiped his perspiring face with his hands and pulled up the +damp collar which he had arranged so well at home to seem like a +man's. + +He felt that he no longer looked presentable, and feared that if +he were now to approach the gentlemen-in-waiting in that plight he +would not be admitted to the Emperor. But it was impossible to smarten +oneself up or move to another place, because of the crowd. One of +the generals who drove past was an acquaintance of the Rostovs', and +Petya thought of asking his help, but came to the conclusion that that +would not be a manly thing to do. When the carriages had all passed +in, the crowd, carrying Petya with it, streamed forward into the +Kremlin Square which was already full of people. There were people not +only in the square, but everywhere--on the slopes and on the roofs. As +soon as Petya found himself in the square he clearly heard the sound +of bells and the joyous voices of the crowd that filled the whole +Kremlin. + +For a while the crowd was less dense, but suddenly all heads were +bared, and everyone rushed forward in one direction. Petya was being +pressed so that he could scarcely breathe, and everybody shouted, +"Hurrah! hurrah! hurrah!" Petya stood on tiptoe and pushed and +pinched, but could see nothing except the people about him. + +All the faces bore the same expression of excitement and enthusiasm. +A tradesman's wife standing beside Petya sobbed, and the tears ran +down her cheeks. + +"Father! Angel! Dear one!" she kept repeating, wiping away her tears +with her fingers. + +"Hurrah!" was heard on all sides. + +For a moment the crowd stood still, but then it made another rush +forward. + +Quite beside himself, Petya, clinching his teeth and rolling his +eyes ferociously, pushed forward, elbowing his way and shouting +"hurrah!" as if he were prepared that instant to kill himself and +everyone else, but on both sides of him other people with similarly +ferocious faces pushed forward and everybody shouted "hurrah!" + +"So this is what the Emperor is!" thought Petya. "No, I can't +petition him myself--that would be too bold." But in spite of this +he continued to struggle desperately forward, and from between the +backs of those in front he caught glimpses of an open space with a +strip of red cloth spread out on it; but just then the crowd swayed +back--the police in front were pushing back those who had pressed +too close to the procession: the Emperor was passing from the palace +to the Cathedral of the Assumption--and Petya unexpectedly received +such a blow on his side and ribs and was squeezed so hard that +suddenly everything grew dim before his eyes and he lost +consciousness. When he came to himself, a man of clerical appearance +with a tuft of gray hair at the back of his head and wearing a +shabby blue cassock--probably a church clerk and chanter--was +holding him under the arm with one hand while warding off the pressure +of the crowd with the other. + +"You've crushed the young gentleman!" said the clerk. "What are +you up to? Gently!... They've crushed him, crushed him!" + +The Emperor entered the Cathedral of the Assumption. The crowd +spread out again more evenly, and the clerk led Petya--pale and +breathless--to the Tsar-cannon. Several people were sorry for Petya, +and suddenly a crowd turned toward him and pressed round him. Those +who stood nearest him attended to him, unbuttoned his coat, seated him +on the raised platform of the cannon, and reproached those others +(whoever they might be) who had crushed him. + +"One might easily get killed that way! What do they mean by it? +Killing people! Poor dear, he's as white as a sheet!"--various +voices were heard saying. + +Petya soon came to himself, the color returned to his face, the pain +had passed, and at the cost of that temporary unpleasantness he had +obtained a place by the cannon from where he hoped to see the +Emperor who would be returning that way. Petya no longer thought of +presenting his petition. If he could only see the Emperor he would +be happy! + +While the service was proceeding in the Cathedral of the Assumption- +it was a combined service of prayer on the occasion of the Emperor's +arrival and of thanksgiving for the conclusion of peace with the +Turks--the crowd outside spread out and hawkers appeared, selling +kvas, gingerbread, and poppyseed sweets (of which Petya was +particularly fond), and ordinary conversation could again be heard. +A tradesman's wife was showing a rent in her shawl and telling how +much the shawl had cost; another was saying that all silk goods had +now got dear. The clerk who had rescued Petya was talking to a +functionary about the priests who were officiating that day with the +bishop. The clerk several times used the word "plenary" (of the +service), a word Petya did not understand. Two young citizens were +joking with some serf girls who were cracking nuts. All these +conversations, especially the joking with the girls, were such as +might have had a particular charm for Petya at his age, but they did +not interest him now. He sat on his elevation--the pedestal of the +cannon--still agitated as before by the thought of the Emperor and +by his love for him. The feeling of pain and fear he had experienced +when he was being crushed, together with that of rapture, still +further intensified his sense of the importance of the occasion. + +Suddenly the sound of a firing of cannon was heard from the +embankment, to celebrate the signing of peace with the Turks, and +the crowd rushed impetuously toward the embankment to watch the +firing. Petya too would have run there, but the clerk who had taken +the young gentleman under his protection stopped him. The firing was +still proceeding when officers, generals, and gentlemen-in-waiting +came running out of the cathedral, and after them others in a more +leisurely manner: caps were again raised, and those who had run to +look at the cannon ran back again. At last four men in uniforms and +sashes emerged from the cathedral doors. "Hurrah! hurrah!" shouted the +crowd again. + +"Which is he? Which?" asked Petya in a tearful voice, of those +around him, but no one answered him, everybody was too excited; and +Petya, fixing on one of those four men, whom he could not clearly +see for the tears of joy that filled his eyes, concentrated all his +enthusiasm on him--though it happened not to be the Emperor- +frantically shouted "Hurrah!" and resolved that tomorrow, come what +might, he would join the army. + +The crowd ran after the Emperor, followed him to the palace, and +began to disperse. It was already late, and Petya had not eaten +anything and was drenched with perspiration, yet he did not go home +but stood with that diminishing, but still considerable, crowd +before the palace while the Emperor dined--looking in at the palace +windows, expecting he knew not what, and envying alike the notables he +saw arriving at the entrance to dine with the Emperor and the court +footmen who served at table, glimpses of whom could be seen through +the windows. + +While the Emperor was dining, Valuev, looking out of the window, +said: + +"The people are still hoping to see Your Majesty again." + +The dinner was nearly over, and the Emperor, munching a biscuit, +rose and went out onto the balcony. The people, with Petya among them, +rushed toward the balcony. + +"Angel! Dear one! Hurrah! Father!..." cried the crowd, and Petya +with it, and again the women and men of weaker mold, Petya among them, +wept with joy. + +A largish piece of the biscuit the Emperor was holding in his hand +broke off, fell on the balcony parapet, and then to the ground. A +coachman in a jerkin, who stood nearest, sprang forward and snatched +it up. Several people in the crowd rushed at the coachman. Seeing this +the Emperor had a plateful of biscuits brought him and began +throwing them down from the balcony. Petya's eyes grew bloodshot, +and still more excited by the danger of being crushed, he rushed at +the biscuits. He did not know why, but he had to have a biscuit from +the Tsar's hand and he felt that he must not give way. He sprang +forward and upset an old woman who was catching at a biscuit; the +old woman did not consider herself defeated though she was lying on +the ground--she grabbed at some biscuits but her hand did not reach +them. Petya pushed her hand away with his knee, seized a biscuit, +and as if fearing to be too late, again shouted "Hurrah!" with a voice +already hoarse. + +The Emperor went in, and after that the greater part of the crowd +began to disperse. + +"There! I said if only we waited--and so it was!" was being joyfully +said by various people. + +Happy as Petya was, he felt sad at having to go home knowing that +all the enjoyment of that day was over. He did not go straight home +from the Kremlin, but called on his friend Obolenski, who was +fifteen and was also entering the regiment. On returning home Petya +announced resolutely and firmly that if he was not allowed to enter +the service he would run away. And next day, Count Ilya Rostov--though +he had not yet quite yielded--went to inquire how he could arrange for +Petya to serve where there would be least danger. + + + + + +CHAPTER XXII + + +Two days later, on the fifteenth of July, an immense number of +carriages were standing outside the Sloboda Palace. + +The great halls were full. In the first were the nobility and gentry +in their uniforms, in the second bearded merchants in full-skirted +coats of blue cloth and wearing medals. In the noblemen's hall there +was an incessant movement and buzz of voices. The chief magnates sat +on high-backed chairs at a large table under the portrait of the +Emperor, but most of the gentry were strolling about the room. + +All these nobles, whom Pierre met every day at the Club or in +their own houses, were in uniform--some in that of Catherine's day, +others in that of Emperor Paul, others again in the new uniforms of +Alexander's time or the ordinary uniform of the nobility, and the +general characteristic of being in uniform imparted something +strange and fantastic to these diverse and familiar personalities, +both old and young. The old men, dim-eyed, toothless, bald, sallow, +and bloated, or gaunt and wrinkled, were especially striking. For +the most part they sat quietly in their places and were silent, or, if +they walked about and talked, attached themselves to someone +younger. On all these faces, as on the faces of the crowd Petya had +seen in the Square, there was a striking contradiction: the general +expectation of a solemn event, and at the same time the everyday +interests in a boston card party, Peter the cook, Zinaida Dmitrievna's +health, and so on. + +Pierre was there too, buttoned up since early morning in a +nobleman's uniform that had become too tight for him. He was agitated; +this extraordinary gathering not only of nobles but also of the +merchant-class--les etats generaux (States-General)--evoked in him a +whole series of ideas he had long laid aside but which were deeply +graven in his soul: thoughts of the Contrat social and the French +Revolution. The words that had struck him in the Emperor's appeal- +that the sovereign was coming to the capital for consultation with his +people--strengthened this idea. And imagining that in this direction +something important which he had long awaited was drawing near, he +strolled about watching and listening to conversations, but nowhere +finding any confirmation of the ideas that occupied him. + +The Emperor's manifesto was read, evoking enthusiasm, and then all +moved about discussing it. Besides the ordinary topics of +conversation, Pierre heard questions of where the marshals of the +nobility were to stand when the Emperor entered, when a ball should be +given in the Emperor's honor, whether they should group themselves +by districts or by whole provinces... and so on; but as soon as the +war was touched on, or what the nobility had been convened for, the +talk became undecided and indefinite. Then all preferred listening +to speaking. + +A middle-aged man, handsome and virile, in the uniform of a +retired naval officer, was speaking in one of the rooms, and a small +crowd was pressing round him. Pierre went up to the circle that had +formed round the speaker and listened. Count Ilya Rostov, in a +military uniform of Catherine's time, was sauntering with a pleasant +smile among the crowd, with all of whom he was acquainted. He too +approached that group and listened with a kindly smile and nods of +approval, as he always did, to what the speaker was saying. The +retired naval man was speaking very boldly, as was evident from the +expression on the faces of the listeners and from the fact that some +people Pierre knew as the meekest and quietest of men walked away +disapprovingly or expressed disagreement with him. Pierre pushed his +way into the middle of the group, listened, and convinced himself that +the man was indeed a liberal, but of views quite different from his +own. The naval officer spoke in a particularly sonorous, musical, +and aristocratic baritone voice, pleasantly swallowing his r's and +generally slurring his consonants: the voice of a man calling out to +his servant, "Heah! Bwing me my pipe!" It was indicative of +dissipation and the exercise of authority. + +"What if the Smolensk people have offahd to waise militia for the +Empewah? Ah we to take Smolensk as our patte'n? If the noble +awistocwacy of the pwovince of Moscow thinks fit, it can show its +loyalty to our sov'weign the Empewah in other ways. Have we +fo'gotten the waising of the militia in the yeah 'seven? All that +did was to enwich the pwiests' sons and thieves and wobbahs...." + +Count Ilya Rostov smiled blandly and nodded approval. + +"And was our militia of any use to the Empia? Not at all! It only +wuined our farming! Bettah have another conscwiption... o' ou' men +will wetu'n neithah soldiers no' peasants, and we'll get only +depwavity fwom them. The nobility don't gwudge theah lives--evewy +one of us will go and bwing in more wecwuits, and the sov'weign" (that +was the way he referred to the Emperor) "need only say the word and +we'll all die fo' him!" added the orator with animation. + +Count Rostov's mouth watered with pleasure and he nudged Pierre, but +Pierre wanted to speak himself. He pushed forward, feeling stirred, +but not yet sure what stirred him or what he would say. Scarcely had +he opened his mouth when one of the senators, a man without a tooth in +his head, with a shrewd though angry expression, standing near the +first speaker, interrupted him. Evidently accustomed to managing +debates and to maintaining an argument, he began in low but distinct +tones: + +"I imagine, sir," said he, mumbling with his toothless mouth, +"that we have been summoned here not to discuss whether it's best +for the empire at the present moment to adopt conscription or to +call out the militia. We have been summoned to reply to the appeal +with which our sovereign the Emperor has honored us. But to judge what +is best--conscription or the militia--we can leave to the supreme +authority...." + +Pierre suddenly saw an outlet for his excitement. He hardened his +heart against the senator who was introducing this set and narrow +attitude into the deliberations of the nobility. Pierre stepped +forward and interrupted him. He himself did not yet know what he would +say, but he began to speak eagerly, occasionally lapsing into French +or expressing himself in bookish Russian. + +"Excuse me, your excellency," he began. (He was well acquainted with +the senator, but thought it necessary on this occasion to address +him formally.) "Though I don't agree with the gentleman..." (he +hesitated: he wished to say, "Mon tres honorable preopinant"--"My very +honorable opponent") "with the gentleman... whom I have not the +honor of knowing, I suppose that the nobility have been summoned not +merely to express their sympathy and enthusiasm but also to consider +the means by which we can assist our Fatherland! I imagine," he went +on, warming to his subject, "that the Emperor himself would not be +satisfied to find in us merely owners of serfs whom we are willing +to devote to his service, and chair a canon* we are ready to make of +ourselves--and not to obtain from us any co-co-counsel." + + +*"Food for cannon." + + +Many persons withdrew from the circle, noticing the senator's +sarcastic smile and the freedom of Pierre's remarks. Only Count Rostov +was pleased with them as he had been pleased with those of the naval +officer, the senator, and in general with whatever speech he had +last heard. + +"I think that before discussing these questions," Pierre +continued, "we should ask the Emperor--most respectfully ask His +Majesty--to let us know the number of our troops and the position in +which our army and our forces now are, and then..." + +But scarcely had Pierre uttered these words before he was attacked +from three sides. The most vigorous attack came from an old +acquaintance, a boston player who had always been well disposed toward +him, Stepan Stepanovich Adraksin. Adraksin was in uniform, and whether +as a result of the uniform or from some other cause Pierre saw +before him quite a different man. With a sudden expression of +malevolence on his aged face, Adraksin shouted at Pierre: + +"In the first place, I tell you we have no right to question the +Emperor about that, and secondly, if the Russian nobility had that +right, the Emperor could not answer such a question. The troops are +moved according to the enemy's movements and the number of men +increases and decreases..." + +Another voice, that of a nobleman of medium height and about forty +years of age, whom Pierre had formerly met at the gypsies' and knew as +a bad cardplayer, and who, also transformed by his uniform, came up to +Pierre, interrupted Adraksin. + +"Yes, and this is not a time for discussing," he continued, "but for +acting: there is war in Russia! The enemy is advancing to destroy +Russia, to desecrate the tombs of our fathers, to carry off our +wives and children." The nobleman smote his breast. "We will all +arise, every one of us will go, for our father the Tsar!" he +shouted, rolling his bloodshot eyes. Several approving voices were +heard in the crowd. "We are Russians and will not grudge our blood +in defense of our faith, the throne, and the Fatherland! We must cease +raving if we are sons of our Fatherland! We will show Europe how +Russia rises to the defense of Russia!" + +Pierre wished to reply, but could not get in a word. He felt that +his words, apart from what meaning they conveyed, were less audible +than the sound of his opponent's voice. + +Count Rostov at the back of the crowd was expressing approval; +several persons, briskly turning a shoulder to the orator at the end +of a phrase, said: + +"That's right, quite right! Just so!" + +Pierre wished to say that he was ready to sacrifice his money, his +serfs, or himself, only one ought to know the state of affairs in +order to be able to improve it, but he was unable to speak. Many +voices shouted and talked at the same time, so that Count Rostov had +not time to signify his approval of them all, and the group increased, +dispersed, re-formed, and then moved with a hum of talk into the +largest hall and to the big table. Not only was Pierre's attempt to +speak unsuccessful, but he was rudely interrupted, pushed aside, and +people turned away from him as from a common enemy. This happened +not because they were displeased by the substance of his speech, which +had even been forgotten after the many subsequent speeches, but to +animate it the crowd needed a tangible object to love and a tangible +object to hate. Pierre became the latter. Many other orators spoke +after the excited nobleman, and all in the same tone. Many spoke +eloquently and with originality. + +Glinka, the editor of the Russian Messenger, who was recognized +(cries of "author! author!" were heard in the crowd), said that +"hell must be repulsed by hell," and that he had seen a child +smiling at lightning flashes and thunderclaps, but "we will not be +that child." + +"Yes, yes, at thunderclaps!" was repeated approvingly in the back +rows of the crowd. + +The crowd drew up to the large table, at which sat gray-haired or +bald seventy-year-old magnates, uniformed and besashed almost all of +whom Pierre had seen in their own homes with their buffoons, or +playing boston at the clubs. With an incessant hum of voices the crowd +advanced to the table. Pressed by the throng against the high backs of +the chairs, the orators spoke one after another and sometimes two +together. Those standing behind noticed what a speaker omitted to +say and hastened to supply it. Others in that heat and crush racked +their brains to find some thought and hastened to utter it. The old +magnates, whom Pierre knew, sat and turned to look first at one and +then at another, and their faces for the most part only expressed +the fact that they found it very hot. Pierre, however, felt excited, +and the general desire to show that they were ready to go to all +lengths--which found expression in the tones and looks more than in +the substance of the speeches--infected him too. He did not renounce +his opinions, but felt himself in some way to blame and wished to +justify himself. + +"I only said that it would be more to the purpose to make sacrifices +when we know what is needed!" said he, trying to be heard above the +other voices. + +One of the old men nearest to him looked round, but his attention +was immediately diverted by an exclamation at the other side of the +table. + +"Yes, Moscow will be surrendered! She will be our expiation!" +shouted one man. + +"He is the enemy of mankind!" cried another. "Allow me to speak...." +"Gentlemen, you are crushing me!..." + + + + + +CHAPTER XXIII + + +At that moment Count Rostopchin with his protruding chin and alert +eyes, wearing the uniform of a general with sash over his shoulder, +entered the room, stepping briskly to the front of the crowd of +gentry. + +"Our sovereign the Emperor will be here in a moment," said +Rostopchin. "I am straight from the palace. Seeing the position we are +in, I think there is little need for discussion. The Emperor has +deigned to summon us and the merchants. Millions will pour forth +from there"--he pointed to the merchants' hall--"but our business is +to supply men and not spare ourselves... That is the least we can do!" + +A conference took place confined to the magnates sitting at the +table. The whole consultation passed more than quietly. After all +the preceding noise the sound of their old voices saying one after +another, "I agree," or for variety, "I too am of that opinion," and so +on had even a mournful effect. + +The secretary was told to write down the resolution of the Moscow +nobility and gentry, that they would furnish ten men, fully +equipped, out of every thousand serfs, as the Smolensk gentry had +done. Their chairs made a scraping noise as the gentlemen who had +conferred rose with apparent relief, and began walking up and down, +arm in arm, to stretch their legs and converse in couples. + +"The Emperor! The Emperor!" a sudden cry resounded through the halls +and the whole throng hurried to the entrance. + +The Emperor entered the hall through a broad path between two +lines of nobles. Every face expressed respectful, awe-struck +curiosity. Pierre stood rather far off and could not hear all that the +Emperor said. From what he did hear he understood that the Emperor +spoke of the danger threatening the empire and of the hopes he +placed on the Moscow nobility. He was answered by a voice which +informed him of the resolution just arrived at. + +"Gentlemen!" said the Emperor with a quivering voice. + +There was a rustling among the crowd and it again subsided, so +that Pierre distinctly heard the pleasantly human voice of the Emperor +saying with emotion: + +"I never doubted the devotion of the Russian nobles, but today it +has surpassed my expectations. I thank you in the name of the +Fatherland! Gentlemen, let us act! Time is most precious..." + +The Emperor ceased speaking, the crowd began pressing round him, and +rapturous exclamations were heard from all sides. + +"Yes, most precious... a royal word," said Count Rostov, with a sob. +He stood at the back, and, though he had heard hardly anything, +understood everything in his own way. + +From the hall of the nobility the Emperor went to that of the +merchants. There he remained about ten minutes. Pierre was among those +who saw him come out from the merchants' hall with tears of emotion in +his eyes. As became known later, he had scarcely begun to address +the merchants before tears gushed from his eyes and he concluded in +a trembling voice. When Pierre saw the Emperor he was coming out +accompanied by two merchants, one of whom Pierre knew, a fat +otkupshchik. The other was the mayor, a man with a thin sallow face +and narrow beard. Both were weeping. Tears filled the thin man's eyes, +and the fat otkupshchik sobbed outright like a child and kept +repeating: + +"Our lives and property--take them, Your Majesty!" + +Pierre's one feeling at the moment was a desire to show that he +was ready to go all lengths and was prepared to sacrifice +everything. He now felt ashamed of his speech with its +constitutional tendency and sought an opportunity of effacing it. +Having heard that Count Mamonov was furnishing a regiment, Bezukhov at +once informed Rostopchin that he would give a thousand men and their +maintenance. + +Old Rostov could not tell his wife of what had passed without tears, +and at once consented to Petya's request and went himself to enter his +name. + +Next day the Emperor left Moscow. The assembled nobles all took +off their uniforms and settled down again in their homes and clubs, +and not without some groans gave orders to their stewards about the +enrollment, feeling amazed themselves at what they had done. + + + + + +BOOK TEN: 1812 + + + + + +CHAPTER I + + +Napoleon began the war with Russia because he could not resist going +to Dresden, could not help having his head turned by the homage he +received, could not help donning a Polish uniform and yielding to +the stimulating influence of a June morning, and could not refrain +from bursts of anger in the presence of Kurakin and then of Balashev. + +Alexander refused negotiations because he felt himself to be +personally insulted. Barclay de Tolly tried to command the army in the +best way, because he wished to fulfill his duty and earn fame as a +great commander. Rostov charged the French because he could not +restrain his wish for a gallop across a level field; and in the same +way the innumerable people who took part in the war acted in accord +with their personal characteristics, habits, circumstances, and +aims. They were moved by fear or vanity, rejoiced or were indignant, +reasoned, imagining that they knew what they were doing and did it +of their own free will, but they all were involuntary tools of +history, carrying on a work concealed from them but comprehensible +to us. Such is the inevitable fate of men of action, and the higher +they stand in the social hierarchy the less are they free. + +The actors of 1812 have long since left the stage, their personal +interests have vanished leaving no trace, and nothing remains of +that time but its historic results. + +Providence compelled all these men, striving to attain personal +aims, to further the accomplishment of a stupendous result no one of +them at all expected--neither Napoleon, nor Alexander, nor still +less any of those who did the actual fighting. + +The cause of the destruction of the French army in 1812 is clear +to us now. No one will deny that that cause was, on the one hand, +its advance into the heart of Russia late in the season without any +preparation for a winter campaign and, on the other, the character +given to the war by the burning of Russian towns and the hatred of the +foe this aroused among the Russian people. But no one at the time +foresaw (what now seems so evident) that this was the only way an army +of eight hundred thousand men--the best in the world and led by the +best general--could be destroyed in conflict with a raw army of half +its numerical strength, and led by inexperienced commanders as the +Russian army was. Not only did no one see this, but on the Russian +side every effort was made to hinder the only thing that could save +Russia, while on the French side, despite Napoleon's experience and +so-called military genius, every effort was directed to pushing on +to Moscow at the end of the summer, that is, to doing the very thing +that was bound to lead to destruction. + +In historical works on the year 1812 French writers are very fond of +saying that Napoleon felt the danger of extending his line, that he +sought a battle and that his marshals advised him to stop at Smolensk, +and of making similar statements to show that the danger of the +campaign was even then understood. Russian authors are still fonder of +telling us that from the commencement of the campaign a Scythian war +plan was adopted to lure Napoleon into the depths of Russia, and +this plan some of them attribute to Pfuel, others to a certain +Frenchman, others to Toll, and others again to Alexander himself- +pointing to notes, projects, and letters which contain hints of such a + +line of action. But all these hints at what happened, both from the +French side and the Russian, are advanced only because they fit in +with the event. Had that event not occurred these hints would have +been forgotten, as we have forgotten the thousands and millions of +hints and expectations to the contrary which were current then but +have now been forgotten because the event falsified them. There are +always so many conjectures as to the issue of any event that however +it may end there will always be people to say: "I said then that it +would be so," quite forgetting that amid their innumerable conjectures +many were to quite the contrary effect. + +Conjectures as to Napoleon's awareness of the danger of extending +his line, and (on the Russian side) as to luring the enemy into the +depths of Russia, are evidently of that kind, and only by much +straining can historians attribute such conceptions to Napoleon and +his marshals, or such plans to the Russian commanders. All the facts +are in flat contradiction to such conjectures. During the whole period +of the war not only was there no wish on the Russian side to draw +the French into the heart of the country, but from their first entry +into Russia everything was done to stop them. And not only was +Napoleon not afraid to extend his line, but he welcomed every step +forward as a triumph and did not seek battle as eagerly as in former +campaigns, but very lazily. + +At the very beginning of the war our armies were divided, and our +sole aim was to unite them, though uniting the armies was no advantage +if we meant to retire and lure the enemy into the depths of the +country. Our Emperor joined the army to encourage it to defend every +inch of Russian soil and not to retreat. The enormous Drissa camp +was formed on Pfuel's plan, and there was no intention of retiring +farther. The Emperor reproached the commanders in chief for every step +they retired. He could not bear the idea of letting the enemy even +reach Smolensk, still less could he contemplate the burning of Moscow, +and when our armies did unite he was displeased that Smolensk was +abandoned and burned without a general engagement having been fought +under its walls. + +So thought the Emperor, and the Russian commanders and people were +still more provoked at the thought that our forces were retreating +into the depths of the country. + +Napoleon having cut our armies apart advanced far into the country +and missed several chances of forcing an engagement. In August he +was at Smolensk and thought only of how to advance farther, though +as we now see that advance was evidently ruinous to him. + +The facts clearly show that Napoleon did not foresee the danger of +the advance on Moscow, nor did Alexander and the Russian commanders +then think of luring Napoleon on, but quite the contrary. The luring +of Napoleon into the depths of the country was not the result of any +plan, for no one believed it to be possible; it resulted from a most +complex interplay of intrigues, aims, and wishes among those who +took part in the war and had no perception whatever of the inevitable, +or of the one way of saving Russia. Everything came about +fortuitously. The armies were divided at the commencement of the +campaign. We tried to unite them, with the evident intention of giving +battle and checking the enemy's advance, and by this effort to unite +them while avoiding battle with a much stronger enemy, and necessarily +withdrawing the armies at an acute angle--we led the French on to +Smolensk. But we withdrew at an acute angle not only because the +French advanced between our two armies; the angle became still more +acute and we withdrew still farther, because Barclay de Tolly was an +unpopular foreigner disliked by Bagration (who would come his +command), and Bagration--being in command of the second army--tried to +postpone joining up and coming under Barclay's command as long as he +could. Bagration was slow in effecting the junction--though that was +the chief aim of all at headquarters--because, as he alleged, he +exposed his army to danger on this march, and it was best for him to +retire more to the left and more to the south, worrying the enemy from +flank and rear and securing from the Ukraine recruits for his army; +and it looks as if he planned this in order not to come under the +command of the detested foreigner Barclay, whose rank was inferior +to his own. + +The Emperor was with the army to encourage it, but his presence +and ignorance of what steps to take, and the enormous number of +advisers and plans, destroyed the first army's energy and it retired. + +The intention was to make a stand at the Drissa camp, but +Paulucci, aiming at becoming commander in chief, unexpectedly employed +his energy to influence Alexander, and Pfuel's whole plan was +abandoned and the command entrusted to Barclay. But as Barclay did not +inspire confidence his power was limited. The armies were divided, +there was no unity of command, and Barclay was unpopular; but from +this confusion, division, and the unpopularity of the foreign +commander in chief, there resulted on the one hand indecision and +the avoidance of a battle (which we could not have refrained from +had the armies been united and had someone else, instead of Barclay, +been in command) and on the other an ever-increasing indignation +against the foreigners and an increase in patriotic zeal. + +At last the Emperor left the army, and as the most convenient and +indeed the only pretext for his departure it was decided that it was +necessary for him to inspire the people in the capitals and arouse the +nation in general to a patriotic war. And by this visit of the Emperor +to Moscow the strength of the Russian army was trebled. + +He left in order not to obstruct the commander in chief's +undivided control of the army, and hoping that more decisive action +would then be taken, but the command of the armies became still more +confused and enfeebled. Bennigsen, the Tsarevich, and a swarm of +adjutants general remained with the army to keep the commander in +chief under observation and arouse his energy, and Barclay, feeling +less free than ever under the observation of all these "eyes of the +Emperor," became still more cautious of undertaking any decisive +action and avoided giving battle. + +Barclay stood for caution. The Tsarevich hinted at treachery and +demanded a general engagement. Lubomirski, Bronnitski, Wlocki, and the +others of that group stirred up so much trouble that Barclay, under +pretext of sending papers to the Emperor, dispatched these Polish +adjutants general to Petersburg and plunged into an open struggle with +Bennigsen and the Tsarevich. + +At Smolensk the armies at last reunited, much as Bagration +disliked it. + +Bagration drove up in a carriage to to the house occupied by +Barclay. Barclay donned his sash and came out to meet and report to +his senior officer Bagration. + +Despite his seniority in rank Bagration, in this contest of +magnanimity, took his orders from Barclay, but, having submitted, +agreed with him less than ever. By the Emperor's orders Bagration +reported direct to him. He wrote to Arakcheev, the Emperor's +confidant: "It must be as my sovereign pleases, but I cannot work with +the Minister (meaning Barclay). For God's sake send me somewhere +else if only in command of a regiment. I cannot stand it here. +Headquarters are so full of Germans that a Russian cannot exist and +there is no sense in anything. I thought I was really serving my +sovereign and the Fatherland, but it turns out that I am serving +Barclay. I confess I do not want to." + +The swarm of Bronnitskis and Wintzingerodes and their like still +further embittered the relations between the commanders in chief, +and even less unity resulted. Preparations were made to fight the +French before Smolensk. A general was sent to survey the position. +This general, hating Barclay, rode to visit a friend of his own, a +corps commander, and, having spent the day with him, returned to +Barclay and condemned, as unsuitable from every point of view, the +battleground he had not seen. + +While disputes and intrigues were going on about the future field of +battle, and while we were looking for the French--having lost touch +with them--the French stumbled upon Neverovski's division and +reached the walls of Smolensk. + +It was necessary to fight an unexpected battle at Smolensk to save +our lines of communication. The battle was fought and thousands were +killed on both sides. + +Smolensk was abandoned contrary to the wishes of the Emperor and +of the whole people. But Smolensk was burned by its own +inhabitants-who had been misled by their governor. And these ruined +inhabitants, setting an example to other Russians, went to Moscow +thinking only of their own losses but kindling hatred of the foe. +Napoleon advanced farther and we retired, thus arriving at the very +result which caused his destruction. + + + + + +CHAPTER II + + +The day after his son had left, Prince Nicholas sent for Princess +Mary to come to his study. + +"Well? Are you satisfied now?" said he. "You've made me quarrel with +my son! Satisfied, are you? That's all you wanted! Satisfied?... It +hurts me, it hurts. I'm old and weak and this is what you wanted. Well +then, gloat over it! Gloat over it!" + +After that Princess Mary did not see her father for a whole week. He +was ill and did not leave his study. + +Princess Mary noticed to her surprise that during this illness the +old prince not only excluded her from his room, but did not admit +Mademoiselle Bourienne either. Tikhon alone attended him. + +At the end of the week the prince reappeared and resumed his +former way of life, devoting himself with special activity to building +operations and the arrangement of the gardens and completely +breaking off his relations with Mademoiselle Bourienne. His looks +and cold tone to his daughter seemed to say: "There, you see? You +plotted against me, you lied to Prince Andrew about my relations +with that Frenchwoman and made me quarrel with him, but you see I need +neither her nor you!" + +Princess Mary spent half of every day with little Nicholas, watching +his lessons, teaching him Russian and music herself, and talking to +Dessalles; the rest of the day she spent over her books, with her +old nurse, or with "God's folk" who sometimes came by the back door to +see her. + +Of the war Princess Mary thought as women do think about wars. She +feared for her brother who was in it, was horrified by and amazed at +the strange cruelty that impels men to kill one another, but she did +not understand the significance of this war, which seemed to her +like all previous wars. She did not realize the significance of this +war, though Dessalles with whom she constantly conversed was +passionately interested in its progress and tried to explain his own +conception of it to her, and though the "God's folk" who came to see +her reported, in their own way, the rumors current among the people of +an invasion by Antichrist, and though Julie (now Princess +Drubetskaya), who had resumed correspondence with her, wrote patriotic +letters from Moscow. + +"I write you in Russian, my good friend," wrote Julie in her +Frenchified Russian, "because I have a detestation for all the French, +and the same for their language which I cannot support to hear +spoken.... We in Moscow are elated by enthusiasm for our adored +Emperor. + +"My poor husband is enduring pains and hunger in Jewish taverns, but +the news which I have inspires me yet more. + +"You heard probably of the heroic exploit of Raevski, embracing +his two sons and saying: 'I will perish with them but we will not be +shaken!' And truly though the enemy was twice stronger than we, we +were unshakable. We pass the time as we can, but in war as in war! The +princesses Aline and Sophie sit whole days with me, and we, unhappy +widows of live men, make beautiful conversations over our charpie, +only you, my friend, are missing..." and so on. + +The chief reason Princess Mary did not realize the full significance +of this war was that the old prince never spoke of it, did not +recognize it, and laughed at Dessalles when he mentioned it at dinner. +The prince's tone was so calm and confident that Princess Mary +unhesitatingly believed him. + +All that July the old prince was exceedingly active and even +animated. He planned another garden and began a new building for the +domestic serfs. The only thing that made Princess Mary anxious about +him was that he slept very little and, instead of sleeping in his +study as usual, changed his sleeping place every day. One day he would +order his camp bed to be set up in the glass gallery, another day he +remained on the couch or on the lounge chair in the drawing room and +dozed there without undressing, while--instead of Mademoiselle +Bourienne--a serf boy read to him. Then again he would spend a night +in the dining room. + +On August 1, a second letter was received from Prince Andrew. In his +first letter which came soon after he had left home, Prince Andrew had +dutifully asked his father's forgiveness for what he had allowed +himself to say and begged to be restored to his favor. To this +letter the old prince had replied affectionately, and from that time +had kept the Frenchwoman at a distance. Prince Andrew's second letter, +written near Vitebsk after the French had occupied that town, gave a +brief account of the whole campaign, enclosed for them a plan he had +drawn and forecasts as to the further progress of the war. In this +letter Prince Andrew pointed out to his father the danger of staying +at Bald Hills, so near the theater of war and on the army's direct +line of march, and advised him to move to Moscow. + +At dinner that day, on Dessalles' mentioning that the French were +said to have already entered Vitebsk, the old prince remembered his +son's letter. + +"There was a letter from Prince Andrew today," he said to Princess +Mary--"Haven't you read it?" + +"No, Father," she replied in a frightened voice. + +She could not have read the letter as she did not even know it had +arrived. + +"He writes about this war," said the prince, with the ironic smile +that had become habitual to him in speaking of the present war. + +"That must be very interesting," said Dessalles. "Prince Andrew is +in a position to know..." + +"Oh, very interesting!" said Mademoiselle Bourienne. + +"Go and get it for me," said the old prince to Mademoiselle +Bourienne. "You know--under the paperweight on the little table." + +Mademoiselle Bourienne jumped up eagerly. + +"No, don't!" he exclaimed with a frown. "You go, Michael Ivanovich." + +Michael Ivanovich rose and went to the study. But as soon as he +had left the room the old prince, looking uneasily round, threw down +his napkin and went himself. + +"They can't do anything... always make some muddle," he muttered. + +While he was away Princess Mary, Dessalles, Mademoiselle +Bourienne, and even little Nicholas exchanged looks in silence. The +old prince returned with quick steps, accompanied by Michael +Ivanovich, bringing the letter and a plan. These he put down beside +him--not letting anyone read them at dinner. + +On moving to the drawing room he handed the letter to Princess +Mary and, spreading out before him the plan of the new building and +fixing his eyes upon it, told her to read the letter aloud. When she +had done so Princess Mary looked inquiringly at her father. He was +examining the plan, evidently engrossed in his own ideas. + +"What do you think of it, Prince?" Dessalles ventured to ask. + +"I? I?..." said the prince as if unpleasantly awakened, and not +taking his eyes from the plan of the building. + +"Very possibly the theater of war will move so near to us that..." + +"Ha ha ha! The theater of war!" said the prince. "I have said and +still say that the theater of war is Poland and the enemy will never +get beyond the Niemen." + +Dessalles looked in amazement at the prince, who was talking of +the Niemen when the enemy was already at the Dnieper, but Princess +Mary, forgetting the geographical position of the Niemen, thought that +what her father was saying was correct. + +"When the snow melts they'll sink in the Polish swamps. Only they +could fail to see it," the prince continued, evidently thinking of the +campaign of 1807 which seemed to him so recent. "Bennigsen should have +advanced into Prussia sooner, then things would have taken a different +turn..." + +"But, Prince," Dessalles began timidly, "the letter mentions +Vitebsk...." + +"Ah, the letter? Yes..." replied the prince peevishly. "Yes... +yes..." His face suddenly took on a morose expression. He paused. +"Yes, he writes that the French were beaten at... at... what river +is it?" + +Dessalles dropped his eyes. + +"The prince says nothing about that," he remarked gently. + +"Doesn't he? But I didn't invent it myself." + +No one spoke for a long time. + +"Yes... yes... Well, Michael Ivanovich," he suddenly went on, +raising his head and pointing to the plan of the building, "tell me +how you mean to alter it...." + +Michael Ivanovich went up to the plan, and the prince after speaking +to him about the building looked angrily at Princess Mary and +Dessalles and went to his own room. + +Princess Mary saw Dessalles' embarrassed and astonished look fixed +on her father, noticed his silence, and was struck by the fact that +her father had forgotten his son's letter on the drawing-room table; +but she was not only afraid to speak of it and ask Dessalles the +reason of his confusion and silence, but was afraid even to think +about it. + +In the evening Michael Ivanovich, sent by the prince, came to +Princess Mary for Prince Andrew's letter which had been forgotten in +the drawing room. She gave it to him and, unpleasant as it was to +her to do so, ventured to ask him what her father was doing. + +"Always busy," replied Michael Ivanovich with a respectfully +ironic smile which caused Princess Mary to turn pale. "He's worrying +very much about the new building. He has been reading a little, but +now"--Michael Ivanovich went on, lowering his voice--"now he's at +his desk, busy with his will, I expect." (One of the prince's favorite +occupations of late had been the preparation of some papers he meant +to leave at his death and which he called his "will.") + +"And Alpatych is being sent to Smolensk?" asked Princess Mary. + +"Oh, yes, he has been waiting to start for some time." + + + + + +CHAPTER III + + +When Michael Ivanovich returned to the study with the letter, the +old prince, with spectacles on and a shade over his eyes, was +sitting at his open bureau with screened candles, holding a paper in +his outstretched hand, and in a somewhat dramatic attitude was reading +his manuscript--his "Remarks" as he termed it--which was to be +transmitted to the Emperor after his death. + +When Michael Ivanovich went in there were tears in the prince's eyes +evoked by the memory of the time when the paper he was now reading had +been written. He took the letter from Michael Ivanovich's hand, put it +in his pocket, folded up his papers, and called in Alpatych who had +long been waiting. + +The prince had a list of things to be bought in Smolensk and, +walking up and down the room past Alpatych who stood by the door, he +gave his instructions. + +"First, notepaper--do you hear? Eight quires, like this sample, +gilt-edged... it must be exactly like the sample. Varnish, sealing +wax, as in Michael Ivanovich's list." + +He paced up and down for a while and glanced at his notes. + +"Then hand to the governor in person a letter about the deed." + +Next, bolts for the doors of the new building were wanted and had to +be of a special shape the prince had himself designed, and a leather +case had to be ordered to keep the "will" in. + +The instructions to Alpatych took over two hours and still the +prince did not let him go. He sat down, sank into thought, closed +his eyes, and dozed off. Alpatych made a slight movement. + +"Well, go, go! If anything more is wanted I'll send after you." + +Alpatych went out. The prince again went to his bureau, glanced into +it, fingered his papers, closed the bureau again, and sat down at +the table to write to the governor. + +It was already late when he rose after sealing the letter. He wished +to sleep, but he knew he would not be able to and that most depressing +thoughts came to him in bed. So he called Tikhon and went through +the rooms with him to show him where to set up the bed for that night. + +He went about looking at every corner. Every place seemed +unsatisfactory, but worst of all was his customary couch in the study. +That couch was dreadful to him, probably because of the oppressive +thoughts he had had when lying there. It was unsatisfactory +everywhere, but the corner behind the piano in the sitting room was +better than other places: he had never slept there yet. + +With the help of a footman Tikhon brought in the bedstead and +began putting it up. + +"That's not right! That's not right!" cried the prince, and +himself pushed it a few inches from the corner and then closer in +again. + +"Well, at last I've finished, now I'll rest," thought the prince, +and let Tikhon undress him. + +Frowning with vexation at the effort necessary to divest himself +of his coat and trousers, the prince undressed, sat down heavily on +the bed, and appeared to be meditating as he looked contemptuously +at his withered yellow legs. He was not meditating, but only deferring +the moment of making the effort to lift those legs up and turn over on +the bed. "Ugh, how hard it is! Oh, that this toil might end and you +would release me!" thought he. Pressing his lips together he made that +effort for the twenty-thousandth time and lay down. But hardly had +he done so before he felt the bed rocking backwards and forwards +beneath him as if it were breathing heavily and jolting. This happened +to him almost every night. He opened his eyes as they were closing. + +"No peace, damn them!" he muttered, angry he knew not with whom. "Ah +yes, there was something else important, very important, that I was +keeping till I should be in bed. The bolts? No, I told him about them. +No, it was something, something in the drawing room. Princess Mary +talked some nonsense. Dessalles, that fool, said something. +Something in my pocket--can't remember..." + +"Tikhon, what did we talk about at dinner?" + +"About Prince Michael..." + +"Be quiet, quiet!" The prince slapped his hand on the table. "Yes, I +know, Prince Andrew's letter! Princess Mary read it. Dessalles said +something about Vitebsk. Now I'll read it." + +He had the letter taken from his pocket and the table--on which +stood a glass of lemonade and a spiral wax candle--moved close to +the bed, and putting on his spectacles he began reading. Only now in +the stillness of the night, reading it by the faint light under the +green shade, did he grasp its meaning for a moment. + +"The French at Vitebsk, in four days' march they may be at Smolensk; +perhaps are already there! Tikhon!" Tikhon jumped up. "No, no, I don't +want anything!" he shouted. + +He put the letter under the candlestick and closed his eyes. And +there rose before him the Danube at bright noonday: reeds, the Russian +camp, and himself a young general without a wrinkle on his ruddy face, +vigorous and alert, entering Potemkin's gaily colored tent, and a +burning sense of jealousy of "the favorite" agitated him now as +strongly as it had done then. He recalled all the words spoken at that +first meeting with Potemkin. And he saw before him a plump, rather +sallow-faced, short, stout woman, the Empress Mother, with her smile +and her words at her first gracious reception of him, and then that +same face on the catafalque, and the encounter he had with Zubov +over her coffin about his right to kiss her hand. + +"Oh, quicker, quicker! To get back to that time and have done with +all the present! Quicker, quicker--and that they should leave me in +peace!" + + + + + +CHAPTER IV + + +Bald Hills, Prince Nicholas Bolkonski's estate, lay forty miles east +from Smolensk and two miles from the main road to Moscow. + +The same evening that the prince gave his instructions to +Alpatych, Dessalles, having asked to see Princess Mary, told her that, +as the prince was not very well and was taking no steps to secure +his safety, though from Prince Andrew's letter it was evident that +to remain at Bald Hills might be dangerous, he respectfully advised +her to send a letter by Alpatych to the Provincial Governor at +Smolensk, asking him to let her know the state of affairs and the +extent of the danger to which Bald Hills was exposed. Dessalles +wrote this letter to the Governor for Princess Mary, she signed it, +and it was given to Alpatych with instructions to hand it to the +Governor and to come back as quickly as possible if there was danger. + +Having received all his orders Alpatych, wearing a white beaver hat- +a present from the prince--and carrying a stick as the prince did, +went out accompanied by his family. Three well-fed roans stood ready +harnessed to a small conveyance with a leather hood. + +The larger bell was muffled and the little bells on the harness +stuffed with paper. The prince allowed no one at Bald Hills to drive +with ringing bells; but on a long journey Alpatych liked to have them. +His satellites--the senior clerk, a countinghouse clerk, a scullery +maid, a cook, two old women, a little pageboy, the coachman, and +various domestic serfs--were seeing him off. + +His daughter placed chintz-covered down cushions for him to sit on +and behind his back. His old sister-in-law popped in a small bundle, +and one of the coachmen helped him into the vehicle. + +"There! There! Women's fuss! Women, women!" said Alpatych, puffing +and speaking rapidly just as the prince did, and he climbed into the +trap. + +After giving the clerk orders about the work to be done, Alpatych, +not trying to imitate the prince now, lifted the hat from his bald +head and crossed himself three times. + +"If there is anything... come back, Yakov Alpatych! For Christ's +sake think of us!" cried his wife, referring to the rumors of war +and the enemy. + +"Women, women! Women's fuss!" muttered Alpatych to himself and +started on his journey, looking round at the fields of yellow rye +and the still-green, thickly growing oats, and at other quite black +fields just being plowed a second time. + +As he went along he looked with pleasure at the year's splendid crop +of corn, scrutinized the strips of ryefield which here and there +were already being reaped, made his calculations as to the sowing +and the harvest, and asked himself whether he had not forgotten any of +the prince's orders. + +Having baited the horses twice on the way, he arrived at the town +toward evening on the fourth of August. + +Alpatych kept meeting and overtaking baggage trains and troops on +the road. As he approached Smolensk he heard the sounds of distant +firing, but these did not impress him. What struck him most was the +sight of a splendid field of oats in which a camp had been pitched and +which was being mown down by the soldiers, evidently for fodder. +This fact impressed Alpatych, but in thinking about his own business +he soon forgot it. + +All the interests of his life for more than thirty years had been +bounded by the will of the prince, and he never went beyond that +limit. Everything not connected with the execution of the prince's +orders did not interest and did not even exist for Alpatych. + +On reaching Smolensk on the evening of the fourth of August he put +up in the Gachina suburb across the Dnieper, at the inn kept by +Ferapontov, where he had been in the habit of putting up for the +last thirty years. Some thirty years ago Ferapontov, by Alpatych's +advice, had bought a wood from the prince, had begun to trade, and now +had a house, an inn, and a corn dealer's shop in that province. He was +a stout, dark, red-faced peasant in the forties, with thick lips, a +broad knob of a nose, similar knobs over his black frowning brows, and +a round belly. + +Wearing a waistcoat over his cotton shirt, Ferapontov was standing +before his shop which opened onto the street. On seeing Alpatych he +went up to him. + +"You're welcome, Yakov Alpatych. Folks are leaving the town, but you +have come to it," said he. + +"Why are they leaving the town?" asked Alpatych. + +"That's what I say. Folks are foolish! Always afraid of the French." + +"Women's fuss, women's fuss!" said Alpatych. + +"Just what I think, Yakov Alpatych. What I say is: orders have +been given not to let them in, so that must be right. And the peasants +are asking three rubles for carting--it isn't Christian!" + +Yakov Alpatych heard without heeding. He asked for a samovar and for +hay for his horses, and when he had had his tea he went to bed. + +All night long troops were moving past the inn. Next morning +Alpatych donned a jacket he wore only in town and went out on +business. It was a sunny morning and by eight o'clock it was already +hot. "A good day for harvesting," thought Alpatych. + +From beyond the town firing had been heard since early morning. At +eight o'clock the booming of cannon was added to the sound of +musketry. Many people were hurrying through the streets and there were +many soldiers, but cabs were still driving about, tradesmen stood at +their shops, and service was being held in the churches as usual. +Alpatych went to the shops, to government offices, to the post office, +and to the Governor's. In the offices and shops and at the post office +everyone was talking about the army and about the enemy who was +already attacking the town, everybody was asking what should be +done, and all were trying to calm one another. + +In front of the Governor's house Alpatych found a large number of +people, Cossacks, and a traveling carriage of the Governor's. At the +porch he met two of the landed gentry, one of whom he knew. This +man, an ex-captain of police, was saying angrily: + +"It's no joke, you know! It's all very well if you're single. 'One +man though undone is but one,' as the proverb says, but with +thirteen in your family and all the property... They've brought us +to utter ruin! What sort of governors are they to do that? They +ought to be hanged--the brigands!..." + +"Oh come, that's enough!" said the other. + +"What do I care? Let him hear! We're not dogs," said the +ex-captain of police, and looking round he noticed Alpatych. + +"Oh, Yakov Alpatych! What have you come for?" + +"To see the Governor by his excellency's order," answered +Alpatych, lifting his head and proudly thrusting his hand into the +bosom of his coat as he always did when he mentioned the prince.... +"He has ordered me to inquire into the position of affairs," he added. + +"Yes, go and find out!" shouted the angry gentleman. "They've +brought things to such a pass that there are no carts or +anything!... There it is again, do you hear?" said he, pointing +in the direction whence came the sounds of firing. + +"They've brought us all to ruin... the brigands!" he repeated, and +descended the porch steps. + +Alpatych swayed his head and went upstairs. In the waiting room were +tradesmen, women, and officials, looking silently at one another. +The door of the Governor's room opened and they all rose and moved +forward. An official ran out, said some words to a merchant, called +a stout official with a cross hanging on his neck to follow him, and +vanished again, evidently wishing to avoid the inquiring looks and +questions addressed to him. Alpatych moved forward and next time the +official came out addressed him, one hand placed in the breast of +his buttoned coat, and handed him two letters. + +"To his Honor Baron Asch, from General-in-Chief Prince Bolkonski," +he announced with such solemnity and significance that the official +turned to him and took the letters. + +A few minutes later the Governor received Alpatych and hurriedly +said to him: + +"Inform the prince and princess that I knew nothing: I acted on +the highest instructions--here..." and he handed a paper to +Alpatych. "Still, as the prince is unwell my advice is that they +should go to Moscow. I am just starting myself. Inform them..." + +But the Governor did not finish: a dusty perspiring officer ran into +the room and began to say something in French. The Governor's face +expressed terror. + +"Go," he said, nodding his head to Alpatych, and began questioning +the officer. + +Eager, frightened, helpless glances were turned on Alpatych when +he came out of the Governor's room. Involuntarily listening now to the +firing, which had drawn nearer and was increasing in strength, +Alpatych hurried to his inn. The paper handed to him by the Governor +said this: + + +"I assure you that the town of Smolensk is not in the slightest +danger as yet and it is unlikely that it will be threatened with +any. I from the one side and Prince Bagration from the other are +marching to unite our forces before Smolensk, which junction will be +effected on the 22nd instant, and both armies with their united forces +will defend our compatriots of the province entrusted to your care +till our efforts shall have beaten back the enemies of our Fatherland, +or till the last warrior in our valiant ranks has perished. From +this you will see that you have a perfect right to reassure the +inhabitants of Smolensk, for those defended by two such brave armies +may feel assured of victory." (Instructions from Barclay de Tolly to +Baron Asch, the civil governor of Smolensk, 1812.) + + +People were anxiously roaming about the streets. + +Carts piled high with household utensils, chairs, and cupboards kept +emerging from the gates of the yards and moving along the streets. +Loaded carts stood at the house next to Ferapontov's and women were +wailing and lamenting as they said good-by. A small watchdog ran round +barking in front of the harnessed horses. + +Alpatych entered the innyard at a quicker pace than usual and went +straight to the shed where his horses and trap were. The coachman +was asleep. He woke him up, told him to harness, and went into the +passage. From the host's room came the sounds of a child crying, the +despairing sobs of a woman, and the hoarse angry shouting of +Ferapontov. The cook began running hither and thither in the passage +like a frightened hen, just as Alpatych entered. + +"He's done her to death. Killed the mistress!... Beat her... dragged +her about so!..." + +"What for?" asked Alpatych. + +"She kept begging to go away. She's a woman! 'Take me away,' says +she, 'don't let me perish with my little children! Folks,' she says, +'are all gone, so why,' she says, 'don't we go?' And he began +beating and pulling her about so!" + +At these words Alpatych nodded as if in approval, and not wishing to +hear more went to the door of the room opposite the innkeeper's, where +he had left his purchases. + +"You brute, you murderer!" screamed a thin, pale woman who, with a +baby in her arms and her kerchief torn from her head, burst through +the door at that moment and down the steps into the yard. + +Ferapontov came out after her, but on seeing Alpatych adjusted his +waistcoat, smoothed his hair, yawned, and followed Alpatych into the +opposite room. + +"Going already?" said he. + +Alpatych, without answering or looking at his host, sorted his +packages and asked how much he owed. + +"We'll reckon up! Well, have you been to the Governor's?" asked +Ferapontov. "What has been decided?" + +Alpatych replied that the Governor had not told him anything +definite. + +"With our business, how can we get away?" said Ferapontov. "We'd +have to pay seven rubles a cartload to Dorogobuzh and I tell them +they're not Christians to ask it! Selivanov, now, did a good stroke +last Thursday--sold flour to the army at nine rubles a sack. Will +you have some tea?" he added. + +While the horses were being harnessed Alpatych and Ferapontov over +their tea talked of the price of corn, the crops, and the good weather +for harvesting. + +"Well, it seems to be getting quieter," remarked Ferapontov, +finishing his third cup of tea and getting up. "Ours must have got the +best of it. The orders were not to let them in. So we're in force, +it seems.... They say the other day Matthew Ivanych Platov drove +them into the river Marina and drowned some eighteen thousand in one +day." + +Alpatych collected his parcels, handed them to the coachman who +had come in, and settled up with the innkeeper. The noise of wheels, +hoofs, and bells was heard from the gateway as a little trap passed +out. + +It was by now late in the afternoon. Half the street was in +shadow, the other half brightly lit by the sun. Alpatych looked out of +the window and went to the door. Suddenly the strange sound of a +far-off whistling and thud was heard, followed by a boom of cannon +blending into a dull roar that set the windows rattling. + +He went out into the street: two men were running past toward the +bridge. From different sides came whistling sounds and the thud of +cannon balls and bursting shells falling on the town. But these sounds +were hardly heard in comparison with the noise of the firing outside +the town and attracted little attention from the inhabitants. The town +was being bombarded by a hundred and thirty guns which Napoleon had +ordered up after four o'clock. The people did not at once realize +the meaning of this bombardment. + +At first the noise of the falling bombs and shells only aroused +curiosity. Ferapontov's wife, who till then had not ceased wailing +under the shed, became quiet and with the baby in her arms went to the +gate, listening to the sounds and looking in silence at the people. + +The cook and a shop assistant came to the gate. With lively +curiosity everyone tried to get a glimpse of the projectiles as they +flew over their heads. Several people came round the corner talking +eagerly. + +"What force!" remarked one. "Knocked the roof and ceiling all to +splinters!" + +"Routed up the earth like a pig," said another. + +"That's grand, it bucks one up!" laughed the first. "Lucky you +jumped aside, or it would have wiped you out!" + +Others joined those men and stopped and told how cannon balls had +fallen on a house close to them. Meanwhile still more projectiles, now +with the swift sinister whistle of a cannon ball, now with the +agreeable intermittent whistle of a shell, flew over people's heads +incessantly, but not one fell close by, they all flew over. Alpatych +was getting into his trap. The innkeeper stood at the gate. + +"What are you staring at?" he shouted to the cook, who in her red +skirt, with sleeves rolled up, swinging her bare elbows, had stepped +to the corner to listen to what was being said. + +"What marvels!" she exclaimed, but hearing her master's voice she +turned back, pulling down her tucked-up skirt. + +Once more something whistled, but this time quite close, swooping +downwards like a little bird; a flame flashed in the middle of the +street, something exploded, and the street was shrouded in smoke. + +"Scoundrel, what are you doing?" shouted the innkeeper, rushing to +the cook. + +At that moment the pitiful wailing of women was heard from different +sides, the frightened baby began to cry, and people crowded silently +with pale faces round the cook. The loudest sound in that crowd was +her wailing. + +"Oh-h-h! Dear souls, dear kind souls! Don't let me die! My good +souls!..." + +Five minutes later no one remained in the street. The cook, with her +thigh broken by a shell splinter, had been carried into the kitchen. +Alpatych, his coachman, Ferapontov's wife and children and the house +porter were all sitting in the cellar, listening. The roar of guns, +the whistling of projectiles, and the piteous moaning of the cook, +which rose above the other sounds, did not cease for a moment. The +mistress rocked and hushed her baby and when anyone came into the +cellar asked in a pathetic whisper what had become of her husband +who had remained in the street. A shopman who entered told her that +her husband had gone with others to the cathedral, whence they were +fetching the wonder-working icon of Smolensk. + +Toward dusk the cannonade began to subside. Alpatych left the cellar +and stopped in the doorway. The evening sky that had been so clear was +clouded with smoke, through which, high up, the sickle of the new moon +shone strangely. Now that the terrible din of the guns had ceased a +hush seemed to reign over the town, broken only by the rustle of +footsteps, the moaning, the distant cries, and the crackle of fires +which seemed widespread everywhere. The cook's moans had now subsided. +On two sides black curling clouds of smoke rose and spread from the +fires. Through the streets soldiers in various uniforms walked or +ran confusedly in different directions like ants from a ruined +ant-hill. Several of them ran into Ferapontov's yard before Alpatych's +eyes. Alpatych went out to the gate. A retreating regiment, +thronging and hurrying, blocked the street. + +Noticing him, an officer said: "The town is being abandoned. Get +away, get away!" and then, turning to the soldiers, shouted: + +"I'll teach you to run into the yards!" + +Alpatych went back to the house, called the coachman, and told him +to set off. Ferapontov's whole household came out too, following +Alpatych and the coachman. The women, who had been silent till then, +suddenly began to wail as they looked at the fires--the smoke and even +the flames of which could be seen in the failing twilight--and as if +in reply the same kind of lamentation was heard from other parts of +the street. Inside the shed Alpatych and the coachman arranged the +tangled reins and traces of their horses with trembling hands. + +As Alpatych was driving out of the gate he saw some ten soldiers +in Ferapontov's open shop, talking loudly and filling their bags and +knapsacks with flour and sunflower seeds. Just then Ferapontov +returned and entered his shop. On seeing the soldiers he was about +to shout at them, but suddenly stopped and, clutching at his hair, +burst into sobs and laughter: + +"Loot everything, lads! Don't let those devils get it!" he cried, +taking some bags of flour himself and throwing them into the street. + +Some of the soldiers were frightened and ran away, others went on +filling their bags. On seeing Alpatych, Ferapontov turned to him: + +"Russia is done for!" he cried. "Alpatych, I'll set the place on +fire myself. We're done for!..." and Ferapontov ran into the yard. + +Soldiers were passing in a constant stream along the street blocking +it completely, so that Alpatych could not pass out and had to wait. +Ferapontov's wife and children were also sitting in a cart waiting +till it was possible to drive out. + +Night had come. There were stars in the sky and the new moon shone +out amid the smoke that screened it. On the sloping descent to the +Dnieper Alpatych's cart and that of the innkeeper's wife, which were +slowly moving amid the rows of soldiers and of other vehicles, had +to stop. In a side street near the crossroads where the vehicles had +stopped, a house and some shops were on fire. This fire was already +burning itself out. The flames now died down and were lost in the +black smoke, now suddenly flared up again brightly, lighting up with +strange distinctness the faces of the people crowding at the +crossroads. Black figures flitted about before the fire, and through +the incessant crackling of the flames talking and shouting could be +heard. Seeing that his trap would not be able to move on for some +time, Alpatych got down and turned into the side street to look at the +fire. Soldiers were continually rushing backwards and forwards near +it, and he saw two of them and a man in a frieze coat dragging burning +beams into another yard across the street, while others carried +bundles of hay. + +Alpatych went up to a large crowd standing before a high barn +which was blazing briskly. The walls were all on fire and the back +wall had fallen in, the wooden roof was collapsing, and the rafters +were alight. The crowd was evidently watching for the roof to fall in, +and Alpatych watched for it too. + +"Alpatych!" a familiar voice suddenly hailed the old man. + +"Mercy on us! Your excellency!" answered Alpatych, immediately +recognizing the voice of his young prince. + +Prince Andrew in his riding cloak, mounted on a black horse, was +looking at Alpatych from the back of the crowd. + +"Why are you here?" he asked. + +"Your... your excellency," stammered Alpatych and broke into sobs. +"Are we really lost? Master!..." + +"Why are you here?" Prince Andrew repeated. + +At that moment the flames flared up and showed his young master's +pale worn face. Alpatych told how he had been sent there and how +difficult it was to get away. + +"Are we really quite lost, your excellency?" he asked again. + +Prince Andrew without replying took out a notebook and raising his +knee began writing in pencil on a page he tore out. He wrote to his +sister: + + +"Smolensk is being abandoned. Bald Hills will be occupied by the +enemy within a week. Set off immediately for Moscow. Let me know at +once when you will start. Send by special messenger to Usvyazh." + + +Having written this and given the paper to Alpatych, he told him how +to arrange for departure of the prince, the princess, his son, and the +boy's tutor, and how and where to let him know immediately. Before +he had had time to finish giving these instructions, a chief of +staff followed by a suite galloped up to him. + +"You are a colonel?" shouted the chief of staff with a German +accent, in a voice familiar to Prince Andrew. "Houses are set on +fire in your presence and you stand by! What does this mean? You +will answer for it!" shouted Berg, who was now assistant to the +chief of staff of the commander of the left flank of the infantry of +the first army, a place, as Berg said, "very agreeable and well en +evidence." + +Prince Andrew looked at him and without replying went on speaking to +Alpatych. + +"So tell them that I shall await a reply till the tenth, and if by +the tenth I don't receive news that they have all got away I shall +have to throw up everything and come myself to Bald Hills." + +"Prince," said Berg, recognizing Prince Andrew, "I only spoke +because I have to obey orders, because I always do obey exactly.... +You must please excuse me," he went on apologetically. + +Something cracked in the flames. The fire died down for a moment and +wreaths of black smoke rolled from under the roof. There was another +terrible crash and something huge collapsed. + +"Ou-rou-rou!" yelled the crowd, echoing the crash of the +collapsing roof of the barn, the burning grain in which diffused a +cakelike aroma all around. The flames flared up again, lighting the +animated, delighted, exhausted faces of the spectators. + +The man in the frieze coat raised his arms and shouted: + +"It's fine, lads! Now it's raging... It's fine!" + +"That's the owner himself," cried several voices. + +"Well then," continued Prince Andrew to Alpatych, "report to them as +I have told you"; and not replying a word to Berg who was now mute +beside him, he touched his horse and rode down the side street. + + + + + +CHAPTER V + + +From Smolensk the troops continued to retreat, followed by the +enemy. On the tenth of August the regiment Prince Andrew commanded was +marching along the highroad past the avenue leading to Bald Hills. +Heat and drought had continued for more than three weeks. Each day +fleecy clouds floated across the sky and occasionally veiled the +sun, but toward evening the sky cleared again and the sun set in +reddish-brown mist. Heavy night dews alone refreshed the earth. The +unreaped corn was scorched and shed its grain. The marshes dried up. +The cattle lowed from hunger, finding no food on the sun-parched +meadows. Only at night and in the forests while the dew lasted was +there any freshness. But on the road, the highroad along which the +troops marched, there was no such freshness even at night or when +the road passed through the forest; the dew was imperceptible on the +sandy dust churned up more than six inches deep. As soon as day dawned +the march began. The artillery and baggage wagons moved noiselessly +through the deep dust that rose to the very hubs of the wheels, and +the infantry sank ankle-deep in that soft, choking, hot dust that +never cooled even at night. Some of this dust was kneaded by the +feet and wheels, while the rest rose and hung like a cloud over the +troops, settling in eyes, ears, hair, and nostrils, and worst of all +in the lungs of the men and beasts as they moved along that road. +The higher the sun rose the higher rose that cloud of dust, and +through the screen of its hot fine particles one could look with naked +eye at the sun, which showed like a huge crimson ball in the unclouded +sky. There was no wind, and the men choked in that motionless +atmosphere. They marched with handkerchiefs tied over their noses +and mouths. When they passed through a village they all rushed to +the wells and fought for the water and drank it down to the mud. + +Prince Andrew was in command of a regiment, and the management of +that regiment, the welfare of the men and the necessity of receiving +and giving orders, engrossed him. The burning of Smolensk and its +abandonment made an epoch in his life. A novel feeling of anger +against the foe made him forget his own sorrow. He was entirely +devoted to the affairs of his regiment and was considerate and kind to +his men and officers. In the regiment they called him "our prince," +were proud of him and loved him. But he was kind and gentle only to +those of his regiment, to Timokhin and the like--people quite new to +him, belonging to a different world and who could not know and +understand his past. As soon as he came across a former acquaintance +or anyone from the staff, he bristled up immediately and grew +spiteful, ironical, and contemptuous. Everything that reminded him +of his past was repugnant to him, and so in his relations with that +former circle he confined himself to trying to do his duty and not +to be unfair. + +In truth everything presented itself in a dark and gloomy light to +Prince Andrew, especially after the abandonment of Smolensk on the +sixth of August (he considered that it could and should have been +defended) and after his sick father had had to flee to Moscow, +abandoning to pillage his dearly beloved Bald Hills which he had built +and peopled. But despite this, thanks to his regiment, Prince Andrew +had something to think about entirely apart from general questions. +Two days previously he had received news that his father, son, and +sister had left for Moscow; and though there was nothing for him to do +at Bald Hills, Prince Andrew with a characteristic desire to foment +his own grief decided that he must ride there. + +He ordered his horse to be saddled and, leaving his regiment on +the march, rode to his father's estate where he had been born and +spent his childhood. Riding past the pond where there used always to +be dozens of women chattering as they rinsed their linen or beat it +with wooden beetles, Prince Andrew noticed that there was not a soul +about and that the little washing wharf, torn from its place and +half submerged, was floating on its side in the middle of the pond. He +rode to the keeper's lodge. No one at the stone entrance gates of +the drive and the door stood open. Grass had already begun to grow +on the garden paths, and horses and calves were straying in the +English park. Prince Andrew rode up to the hothouse; some of the glass +panes were broken, and of the trees in tubs some were overturned and +others dried up. He called for Taras the gardener, but no one replied. +Having gone round the corner of the hothouse to the ornamental garden, +he saw that the carved garden fence was broken and branches of the +plum trees had been torn off with the fruit. An old peasant whom +Prince Andrew in his childhood had often seen at the gate was +sitting on a green garden seat, plaiting a bast shoe. + +He was deaf and did not hear Prince Andrew ride up. He was sitting +on the seat the old prince used to like to sit on, and beside him +strips of bast were hanging on the broken and withered branch of a +magnolia. + +Prince Andrew rode up to the house. Several limes in the old +garden had been cut down and a piebald mare and her foal were +wandering in front of the house among the rosebushes. The shutters +were all closed, except at one window which was open. A little serf +boy, seeing Prince Andrew, ran into the house. Alpatych, having sent +his family away, was alone at Bald Hills and was sitting indoors +reading the Lives of the Saints. On hearing that Prince Andrew had +come, he went out with his spectacles on his nose, buttoning his coat, +and, hastily stepping up, without a word began weeping and kissing +Prince Andrew's knee. + +Then, vexed at his own weakness, he turned away and began to +report on the position of affairs. Everything precious and valuable +had been removed to Bogucharovo. Seventy quarters of grain had also +been carted away. The hay and the spring corn, of which Alpatych +said there had been a remarkable crop that year, had been commandeered +by the troops and mown down while still green. The peasants were +ruined; some of them too had gone to Bogucharovo, only a few remained. + +Without waiting to hear him out, Prince Andrew asked: + +"When did my father and sister leave?" meaning when did they leave +for Moscow. + +Alpatych, understanding the question to refer to their departure for +Bogucharovo, replied that they had left on the seventh and again +went into details concerning the estate management, asking for +instructions. + +"Am I to let the troops have the oats, and to take a receipt for +them? We have still six hundred quarters left," he inquired. + +"What am I to say to him?" thought Prince Andrew, looking down on +the old man's bald head shining in the sun and seeing by the +expression on his face that the old man himself understood how +untimely such questions were and only asked them to allay his grief. + +"Yes, let them have it," replied Prince Andrew. + +"If you noticed some disorder in the garden," said Alpatych, "it was +impossible to prevent it. Three regiments have been here and spent the +night, dragoons mostly. I took down the name and rank of their +commanding officer, to hand in a complaint about it." + +"Well, and what are you going to do? Will you stay here if the enemy +occupies the place?" asked Prince Andrew. + +Alpatych turned his face to Prince Andrew, looked at him, and +suddenly with a solemn gesture raised his arm. + +"He is my refuge! His will be done!" he exclaimed. + +A group of bareheaded peasants was approaching across the meadow +toward the prince. + +"Well, good-by!" said Prince Andrew, bending over to Alpatych. +"You must go away too, take away what you can and tell the serfs to go +to the Ryazan estate or to the one near Moscow." + +Alpatych clung to Prince Andrew's leg and burst into sobs. Gently +disengaging himself, the prince spurred his horse and rode down the +avenue at a gallop. + +The old man was still sitting in the ornamental garden, like a fly +impassive on the face of a loved one who is dead, tapping the last +on which he was making the bast shoe, and two little girls, running +out from the hot house carrying in their skirts plums they had plucked +from the trees there, came upon Prince Andrew. On seeing the young +master, the elder one frightened look clutched her younger companion +by the hand and hid with her behind a birch tree, not stopping to pick +up some green plums they had dropped. + +Prince Andrew turned away with startled haste, unwilling to let them +see that they had been observed. He was sorry for the pretty +frightened little girl, was afraid of looking at her, and yet felt +an irresistible desire to do so. A new sensation of comfort and relief +came over him when, seeing these girls, he realized the existence of +other human interests entirely aloof from his own and just as +legitimate as those that occupied him. Evidently these girls +passionately desired one thing--to carry away and eat those green +plums without being caught--and Prince Andrew shared their wish for +the success of their enterprise. He could not resist looking at them +once more. Believing their danger past, they sprang from their +ambush and, chirruping something in their shrill little voices and +holding up their skirts, their bare little sunburned feet scampered +merrily and quickly across the meadow grass. + +Prince Andrew was somewhat refreshed by having ridden off the +dusty highroad along which the troops were moving. But not far from +Bald Hills he again came out on the road and overtook his regiment +at its halting place by the dam of a small pond. It was past one +o'clock. The sun, a red ball through the dust, burned and scorched his +back intolerably through his black coat. The dust always hung +motionless above the buzz of talk that came from the resting troops. +There was no wind. As he crossed the dam Prince Andrew smelled the +ooze and freshness of the pond. He longed to get into that water, +however dirty it might be, and he glanced round at the pool from +whence came sounds of shrieks and laughter. The small, muddy, green +pond had risen visibly more than a foot, flooding the dam, because +it was full of the naked white bodies of soldiers with brick-red +hands, necks, and faces, who were splashing about in it. All this +naked white human flesh, laughing and shrieking, floundered about in +that dirty pool like carp stuffed into a watering can, and the +suggestion of merriment in that floundering mass rendered it specially +pathetic. + +One fair-haired young soldier of the third company, whom Prince +Andrew knew and who had a strap round the calf of one leg, crossed +himself, stepped back to get a good run, and plunged into the water; +another, a dark noncommissioned officer who was always shaggy, stood +up to his waist in the water joyfully wriggling his muscular figure +and snorted with satisfaction as he poured the water over his head +with hands blackened to the wrists. There were sounds of men +slapping one another, yelling, and puffing. + +Everywhere on the bank, on the dam, and in the pond, there was +healthy, white, muscular flesh. The officer, Timokhin, with his red +little nose, standing on the dam wiping himself with a towel, felt +confused at seeing the prince, but made up his mind to address him +nevertheless. + +"It's very nice, your excellency! Wouldn't you like to?" said he. + +"It's dirty," replied Prince Andrew, making a grimace. + +"We'll clear it out for you in a minute," said Timokhin, and, +still undressed, ran off to clear the men out of the pond. + +"The prince wants to bathe." + +"What prince? Ours?" said many voices, and the men were in such +haste to clear out that the prince could hardly stop them. He +decided that he would rather wash himself with water in the barn. + +"Flesh, bodies, cannon fodder!" he thought, and he looked at his own +naked body and shuddered, not from cold but from a sense of disgust +and horror he did not himself understand, aroused by the sight of that +immense number of bodies splashing about in the dirty pond. + + +On the seventh of August Prince Bagration wrote as follows from +his quarters at Mikhaylovna on the Smolensk road: + + +Dear Count Alexis Andreevich--(He was writing to Arakcheev but +knew that his letter would be read by the Emperor, and therefore +weighed every word in it to the best of his ability.) + +I expect the Minister [Barclay de Tolly] has already reported the +abandonment of Smolensk to the enemy. It is pitiable and sad, and +the whole army is in despair that this most important place has been +wantonly abandoned. I, for my part, begged him personally most +urgently and finally wrote him, but nothing would induce him to +consent. I swear to you on my honor that Napoleon was in such a fix as +never before and might have lost half his army but could not have +taken Smolensk. Our troops fought, and are fighting, as never +before. With fifteen thousand men I held the enemy at bay for +thirty-five hours and beat him; but he would not hold out even for +fourteen hours. It is disgraceful, a stain on our army, and as for +him, he ought, it seems to me, not to live. If he reports that our +losses were great, it is not true; perhaps about four thousand, not +more, and not even that; but even were they ten thousand, that's +war! But the enemy has lost masses... + +What would it have cost him to hold out for another two days? They +would have had to retire of their own accord, for they had no water +for men or horses. He gave me his word he would not retreat, but +suddenly sent instructions that he was retiring that night. We +cannot fight in this way, or we may soon bring the enemy to Moscow... + +There is a rumor that you are thinking of peace. God forbid that you +should make peace after all our sacrifices and such insane retreats! +You would set all Russia against you and every one of us would feel +ashamed to wear the uniform. If it has come to this--we must fight +as long as Russia can and as long as there are men able to stand... + +One man ought to be in command, and not two. Your Minister may +perhaps be good as a Minister, but as a general he is not merely bad +but execrable, yet to him is entrusted the fate of our whole +country.... I am really frantic with vexation; forgive my writing +boldly. It is clear that the man who advocates the conclusion of a +peace, and that the Minister should command the army, does not love +our sovereign and desires the ruin of us all. So I write you +frankly: call out the militia. For the Minister is leading these +visitors after him to Moscow in a most masterly way. The whole army +feels great suspicion of the Imperial aide-de-camp Wolzogen. He is +said to be more Napoleon's man than ours, and he is always advising +the Minister. I am not merely civil to him but obey him like a +corporal, though I am his senior. This is painful, but, loving my +benefactor and sovereign, I submit. Only I am sorry for the Emperor +that he entrusts our fine army to such as he. Consider that on our +retreat we have lost by fatigue and left in the hospital more than +fifteen thousand men, and had we attacked this would not have +happened. Tell me, for God's sake, what will Russia, our mother +Russia, say to our being so frightened, and why are we abandoning +our good and gallant Fatherland to such rabble and implanting feelings +of hatred and shame in all our subjects? What are we scared at and +of whom are we afraid? I am not to blame that the Minister is +vacillating, a coward, dense, dilatory, and has all bad qualities. The +whole army bewails it and calls down curses upon him... + + + + + +CHAPTER VI + + +Among the innumerable categories applicable to the phenomena of +human life one may discriminate between those in which substance +prevails and those in which form prevails. To the latter--as +distinguished from village, country, provincial, or even Moscow +life--we may allot Petersburg life, and especially the life of its +salons. That life of the salons is unchanging. Since the year 1805 +we had made peace and had again quarreled with Bonaparte and had +made constitutions and unmade them again, but the salons of Anna +Pavlovna Helene remained just as they had been--the one seven and +the other five years before. At Anna Pavlovna's they talked with +perplexity of Bonaparte's successes just as before and saw in them and +in the subservience shown to him by the European sovereigns a +malicious conspiracy, the sole object of which was to cause +unpleasantness and anxiety to the court circle of which Anna +Pavlovna was the representative. And in Helene's salon, which +Rumyantsev himself honored with his visits, regarding Helene as a +remarkably intelligent woman, they talked with the same ecstasy in +1812 as in 1808 of the "great nation" and the "great man," and +regretted our rupture with France, a rupture which, according to them, +ought to be promptly terminated by peace. + +Of late, since the Emperor's return from the army, there had been +some excitement in these conflicting salon circles and some +demonstrations of hostility to one another, but each camp retained its +own tendency. In Anna Pavlovna's circle only those Frenchmen were +admitted who were deep-rooted legitimists, and patriotic views were +expressed to the effect that one ought not to go to the French theater +and that to maintain the French troupe was costing the government as +much as a whole army corps. The progress of the war was eagerly +followed, and only the reports most flattering to our army were +circulated. In the French circle of Helene and Rumyantsev the +reports of the cruelty of the enemy and of the war were contradicted +and all Napoleon's attempts at conciliation were discussed. In that +circle they discountenanced those who advised hurried preparations for +a removal to Kazan of the court and the girls' educational +establishments under the patronage of the Dowager Empress. In Helene's +circle the war in general was regarded as a series of formal +demonstrations which would very soon end in peace, and the view +prevailed expressed by Bilibin--who now in Petersburg was quite at +home in Helene's house, which every clever man was obliged to visit- +that not by gunpowder but by those who invented it would matters be +settled. In that circle the Moscow enthusiasm--news of which had +reached Petersburg simultaneously with the Emperor's return--was +ridiculed sarcastically and very cleverly, though with much caution. + +Anna Pavlovna's circle on the contrary was enraptured by this +enthusiasm and spoke of it as Plutarch speaks of the deeds of the +ancients. Prince Vasili, who still occupied his former important +posts, formed a connecting link between these two circles. He +visited his "good friend Anna Pavlovna" as well as his daughter's +"diplomatic salon," and often in his constant comings and goings +between the two camps became confused and said at Helene's what he +should have said at Anna Pavlovna's and vice versa. + +Soon after the Emperor's return Prince Vasili in a conversation +about the war at Anna Pavlovna's severely condemned Barclay de +Tolly, but was undecided as to who ought to be appointed commander +in chief. One of the visitors, usually spoken of as "a man of great +merit," having described how he had that day seen Kutuzov, the newly +chosen chief of the Petersburg militia, presiding over the +enrollment of recruits at the Treasury, cautiously ventured to suggest +that Kutuzov would be the man to satisfy all requirements. + +Anna Pavlovna remarked with a melancholy smile that Kutuzov had done +nothing but cause the Emperor annoyance. + +"I have talked and talked at the Assembly of the Nobility," Prince +Vasili interrupted, "but they did not listen to me. I told them his +election as chief of the militia would not please the Emperor. They +did not listen to me. + +"It's all this mania for opposition," he went on. "And who for? It +is all because we want to ape the foolish enthusiasm of those +Muscovites," Prince Vasili continued, forgetting for a moment that +though at Helene's one had to ridicule the Moscow enthusiasm, at +Anna Pavlovna's one had to be ecstatic about it. But he retrieved +his mistake at once. "Now, is it suitable that Count Kutuzov, the +oldest general in Russia, should preside at that tribunal? He will get +nothing for his pains! How could they make a man commander in chief +who cannot mount a horse, who drops asleep at a council, and has the +very worst morals! A good reputation he made for himself at Bucharest! +I don't speak of his capacity as a general, but at a time like this +how they appoint a decrepit, blind old man, positively +blind? A fine idea to have a blind general! He can't see anything. +To play blindman's bluff? He can't see at all!" + +No one replied to his remarks. + +This was quite correct on the twenty-fourth of July. But on the +twenty-ninth of July Kutuzov received the title of Prince. This +might indicate a wish to get rid of him, and therefore Prince Vasili's +opinion continued to be correct though he was not now in any hurry +to express it. But on the eighth of August a committee, consisting +of Field Marshal Saltykov, Arakcheev, Vyazmitinov, Lopukhin, and +Kochubey met to consider the progress of the war. This committee +came to the conclusion that our failures were due to a want of unity +in the command and though the members of the committee were aware of +the Emperor's dislike of Kutuzov, after a short deliberation they +agreed to advise his appointment as commander in chief. That same +day Kutuzov was appointed commander in chief with full powers over the +armies and over the whole region occupied by them. + +On the ninth of August Prince Vasili at Anna Pavlovna's again met +the "man of great merit." The latter was very attentive to Anna +Pavlovna because he wanted to be appointed director of one of the +educational establishments for young ladies. Prince Vasili entered the +room with the air of a happy conqueror who has attained the object +of his desires. + +"Well, have you heard the great news? Prince Kutuzov is field +marshal! All dissensions are at an end! I am so glad, so delighted! At +last we have a man!" said he, glancing sternly and significantly round +at everyone in the drawing room. + +The "man of great merit," despite his desire to obtain the post of +director, could not refrain from reminding Prince Vasili of his former +opinion. Though this was impolite to Prince Vasili in Anna +Pavlovna's drawing room, and also to Anna Pavlovna herself who had +received the news with delight, he could not resist the temptation. + +"But, Prince, they say he is blind!" said he, reminding Prince +Vasili of his own words. + +"Eh? Nonsense! He sees well enough," said Prince Vasili rapidly, +in a deep voice and with a slight cough--the voice and cough with +which he was wont to dispose of all difficulties. + +"He sees well enough," he added. "And what I am so pleased about," +he went on, "is that our sovereign has given him full powers over +all the armies and the whole region--powers no commander in chief ever +had before. He is a second autocrat," he concluded with a victorious +smile. + +"God grant it! God grant it!" said Anna Pavlovna. + +The "man of great merit," who was still a novice in court circles, +wishing to flatter Anna Pavlovna by defending her former position on +this question, observed: + +"It is said that the Emperor was reluctant to give Kutuzov those +powers. They say he blushed like a girl to whom Joconde is read, +when he said to Kutuzov: 'Your Emperor and the Fatherland award you +this honor.'" + +"Perhaps the heart took no part in that speech," said Anna Pavlovna. + +"Oh, no, no!" warmly rejoined Prince Vasili, who would not now yield +Kutuzov to anyone; in his opinion Kutuzov was not only admirable +himself, but was adored by everybody. "No, that's impossible," said +he, "for our sovereign appreciated him so highly before." + +"God grant only that Prince Kutuzov assumes real power and does +not allow anyone to put a spoke in his wheel," observed Anna Pavlovna. + +Understanding at once to whom she alluded, Prince Vasili said in a +whisper: + +"I know for a fact that Kutuzov made it an absolute condition that +the Tsarevich should not be with the army. Do you know what he said to +the Emperor?" + +And Prince Vasili repeated the words supposed to have been spoken by +Kutuzov to the Emperor. "I can neither punish him if he does wrong nor +reward him if he does right." + +"Oh, a very wise man is Prince Kutuzov! I have known him a long +time!" + +"They even say," remarked the "man of great merit" who did not yet +possess courtly tact, "that his excellency made it an express +condition that the sovereign himself should not be with the army." + +As soon as he said this both Prince Vasili and Anna Pavlovna +turned away from him and glanced sadly at one another with a sigh at +his naivete. + + + + + +CHAPTER VII + + +While this was taking place in Petersburg the French had already +passed Smolensk and were drawing nearer and nearer to Moscow. +Napoleon's historian Thiers, like other of his historians, trying to +justify his hero says that he was drawn to the walls of Moscow against +his will. He is as right as other historians who look for the +explanation of historic events in the will of one man; he is as +right as the Russian historians who maintain that Napoleon was drawn +to Moscow by the skill of the Russian commanders. Here besides the law +of retrospection, which regards all the past as a preparation for +events that subsequently occur, the law of reciprocity comes in, +confusing the whole matter. A good chessplayer having lost a game is +sincerely convinced that his loss resulted from a mistake he made +and looks for that mistake in the opening, but forgets that at each +stage of the game there were similar mistakes and that none of his +moves were perfect. He only notices the mistake to which he pays +attention, because his opponent took advantage of it. How much more +complex than this is the game of war, which occurs under certain +limits of time, and where it is not one will that manipulates lifeless +objects, but everything results from innumerable conflicts of +various wills! + +After Smolensk Napoleon sought a battle beyond Dorogobuzh at Vyazma, +and then at Tsarevo-Zaymishche, but it happened that owing to a +conjunction of innumerable circumstances the Russians could not give +battle till they reached Borodino, seventy miles from Moscow. From +Vyazma Napoleon ordered a direct advance on Moscow. + +Moscou, la capitale asiatique de ce grand empire, la ville sacree +des peuples d'Alexandre, Moscou avec ses innombrables eglises en forme +de pagodes chinoises,* this Moscow gave Napoleon's imagination no +rest. On the march from Vyazma to Tsarevo-Zaymishche he rode his light +bay bobtailed ambler accompanied by his Guards, his bodyguard, his +pages, and aides-de-camp. Berthier, his chief of staff, dropped behind +to question a Russian prisoner captured by the cavalry. Followed by +Lelorgne d'Ideville, an interpreter, he overtook Napoleon at a +gallop and reined in his horse with an amused expression. + + +*"Moscow, the Asiatic capital of this great empire, the sacred +city of Alexander's people, Moscow with its innumerable churches +shaped like Chinese pagodas." + + +"Well?" asked Napoleon. + +"One of Platov's Cossacks says that Platov's corps is joining up +with the main army and that Kutuzov has been appointed commander in +chief. He is a very shrewd and garrulous fellow." + +Napoleon smiled and told them to give the Cossack a horse and +bring the man to him. He wished to talk to him himself. Several +adjutants galloped off, and an hour later, Lavrushka, the serf Denisov +had handed over to Rostov, rode up to Napoleon in an orderly's +jacket and on a French cavalry saddle, with a merry, and tipsy face. +Napoleon told him to ride by his side and began questioning him. + +"You are a Cossack?" + +"Yes, a Cossack, your Honor." + +"The Cossack, not knowing in what company he was, for Napoleon's +plain appearance had nothing about it that would reveal to an Oriental +mind the presence of a monarch, talked with extreme familiarity of the +incidents of the war," says Thiers, narrating this episode. In reality +Lavrushka, having got drunk the day before and left his master +dinnerless, had been whipped and sent to the village in quest of +chickens, where he engaged in looting till the French took him +prisoner. Lavrushka was one of those coarse, bare-faced lackeys who +have seen all sorts of things, consider it necessary to do +everything in a mean and cunning way, are ready to render any sort +of service to their master, and are keen at guessing their master's +baser impulses, especially those prompted by vanity and pettiness. + +Finding himself in the company of Napoleon, whose identity he had +easily and surely recognized, Lavrushka was not in the least abashed +but merely did his utmost to gain his new master's favor. + +He knew very well that this was Napoleon, but Napoleon's presence +could no more intimidate him than Rostov's, or a sergeant major's with +the rods, would have done, for he had nothing that either the sergeant +major or Napoleon could deprive him of. + +So he rattled on, telling all the gossip he had heard among the +orderlies. Much of it true. But when Napoleon asked him whether the +Russians thought they would beat Bonaparte or not, Lavrushka screwed +up his eyes and considered. + +In this question he saw subtle cunning, as men of his type see +cunning in everything, so he frowned and did not answer immediately. + +"It's like this," he said thoughtfully, "if there's a battle soon, +yours will win. That's right. But if three days pass, then after that, +well, then that same battle will not soon be over." + +Lelorgne d'Ideville smilingly interpreted this speech to Napoleon +thus: "If a battle takes place within the next three days the French +will win, but if later, God knows what will happen." Napoleon did +not smile, though he was evidently in high good humor, and he +ordered these words to be repeated. + +Lavrushka noticed this and to entertain him further, pretending +not to know who Napoleon was, added: + +"We know that you have Bonaparte and that he has beaten everybody in +the world, but we are a different matter..."--without knowing why or +how this bit of boastful patriotism slipped out at the end. + +The interpreter translated these words without the last phrase, +and Bonaparte smiled. "The young Cossack made his mighty +interlocutor smile," says Thiers. After riding a few paces in silence, +Napoleon turned to Berthier and said he wished to see how the news +that he was talking to the Emperor himself, to that very Emperor who +had written his immortally victorious name on the Pyramids, would +affect this enfant du Don.* + + +*"Child of the Don." + + +The fact was accordingly conveyed to Lavrushka. + +Lavrushka, understanding that this was done to perplex him and +that Napoleon expected him to be frightened, to gratify his new +masters promptly pretended to be astonished and awe-struck, opened his +eyes wide, and assumed the expression he usually put on when taken +to be whipped. "As soon as Napoleon's interpreter had spoken," says +Thiers, "the Cossack, seized by amazement, did not utter another word, +but rode on, his eyes fixed on the conqueror whose fame had reached +him across the steppes of the East. All his loquacity was suddenly +arrested and replaced by a naive and silent feeling of admiration. +Napoleon, after making the Cossack a present, had him set free like +a bird restored to its native fields." + +Napoleon rode on, dreaming of the Moscow that so appealed to his +imagination, and "the bird restored to its native fields" galloped +to our outposts, inventing on the way all that had not taken place but +that he meant to relate to his comrades. What had really taken place +he did not wish to relate because it seemed to him not worth +telling. He found the Cossacks, inquired for the regiment operating +with Platov's detachment and by evening found his master, Nicholas +Rostov, quartered at Yankovo. Rostov was just mounting to go for a +ride round the neighboring villages with Ilyin; he let Lavrushka +have another horse and took him along with him. + + + + + +CHAPTER VIII + + +Princess Mary was not in Moscow and out of danger as Prince Andrew +supposed. + +After the return of Alpatych from Smolensk the old prince suddenly +seemed to awake as from a dream. He ordered the militiamen to be +called up from the villages and armed, and wrote a letter to the +commander in chief informing him that he had resolved to remain at +Bald Hills to the last extremity and to defend it, leaving to the +commander in chief's discretion to take measures or not for the +defense of Bald Hills, where one of Russia's oldest generals would +be captured or killed, and he announced to his household that he would +remain at Bald Hills. + +But while himself remaining, he gave instructions for the +departure of the princess and Dessalles with the little prince to +Bogucharovo and thence to Moscow. Princess Mary, alarmed by her +father's feverish and sleepless activity after his previous apathy, +could not bring herself to leave him alone and for the first time in +her life ventured to disobey him. She refused to go away and her +father's fury broke over her in a terrible storm. He repeated every +injustice he had ever inflicted on her. Trying to convict her, he told +her she had worn him out, had caused his quarrel with his son, had +harbored nasty suspicions of him, making it the object of her life +to poison his existence, and he drove her from his study telling her +that if she did not go away it was all the same to him. He declared +that he did not wish to remember her existence and warned her not to +dare to let him see her. The fact that he did not, as she had +feared, order her to be carried away by force but only told her not to +let him see her cheered Princess Mary. She knew it was a proof that in +the depth of his soul he was glad she was remaining at home and had +not gone away. + +The morning after little Nicholas had left, the old prince donned +his full uniform and prepared to visit the commander in chief. His +caleche was already at the door. Princess Mary saw him walk out of the +house in his uniform wearing all his orders and go down the garden +to review his armed peasants and domestic serfs. She sat by the window +listening to his voice which reached her from the garden. Suddenly +several men came running up the avenue with frightened faces. + +Princess Mary ran out to the porch, down the flower-bordered path, +and into the avenue. A large crowd of militiamen and domestics were +moving toward her, and in their midst several men were supporting by +the armpits and dragging along a little old man in a uniform and +decorations. She ran up to him and, in the play of the sunlight that +fell in small round spots through the shade of the lime-tree avenue, +could not be sure what change there was in his face. All she could see +was that his former stern and determined expression had altered to one +of timidity and submission. On seeing his daughter he moved his +helpless lips and made a hoarse sound. It was impossible to make out +what he wanted. He was lifted up, carried to his study, and laid on +the very couch he had so feared of late. + +The doctor, who was fetched that same night, bled him and said +that the prince had had a seizure paralyzing his right side. + +It was becoming more and more dangerous to remain at Bald Hills, and +next day they moved the prince to Bogucharovo, the doctor accompanying +him. + +By the time they reached Bogucharovo, Dessalles and the little +prince had already left for Moscow. + +For three weeks the old prince lay stricken by paralysis in the +new house Prince Andrew had built at Bogucharovo, ever in the same +state, getting neither better nor worse. He was unconscious and lay +like a distorted corpse. He muttered unceasingly, his eyebrows and +lips twitching, and it was impossible to tell whether he understood +what was going on around him or not. One thing was certain--that he +was suffering and wished to say something. But what it was, no one +could tell: it might be some caprice of a sick and half-crazy man, +or it might relate to public affairs, or possibly to family concerns. + +The doctor said this restlessness did not mean anything and was +due to physical causes; but Princess Mary thought he wished to tell +her something, and the fact that her presence always increased his +restlessness confirmed her opinion. + +He was evidently suffering both physically and mentally. There was +no hope of recovery. It was impossible for him to travel, it would not +do to let him die on the road. "Would it not be better if the end +did come, the very end?" Princess Mary sometimes thought. Night and +day, hardly sleeping at all, she watched him and, terrible to say, +often watched him not with hope of finding signs of improvement but +wishing to find symptoms of the approach of the end. + +Strange as it was to her to acknowledge this feeling in herself, yet +there it was. And what seemed still more terrible to her was that +since her father's illness began (perhaps even sooner, when she stayed +with him expecting something to happen), all the personal desires +and hopes that had been forgotten or sleeping within her had awakened. +Thoughts that had not entered her mind for years--thoughts of a life +free from the fear of her father, and even the possibility of love and +of family happiness--floated continually in her imagination like +temptations of the devil. Thrust them aside as she would, questions +continually recurred to her as to how she would order her life now, +after that. These were temptations of the devil and Princess Mary knew +it. She knew that the sole weapon against him was prayer, and she +tried to pray. She assumed an attitude of prayer, looked at the icons, +repeated the words of a prayer, but she could not pray. She felt +that a different world had now taken possession of her--the life of +a world of strenuous and free activity, quite opposed to the spiritual +world in which till now she had been confined and in which her +greatest comfort had been prayer. She could not pray, could not +weep, and worldly cares took possession of her. + +It was becoming dangerous to remain in Bogucharovo. News of the +approach of the French came from all sides, and in one village, ten +miles from Bogucharovo, a homestead had been looted by French +marauders. + +The doctor insisted on the necessity of moving the prince; the +provincial Marshal of the Nobility sent an official to Princess Mary +to persuade her to get away as quickly as possible, and the head of +the rural police having come to Bogucharovo urged the same thing, +saying that the French were only some twenty-five miles away, that +French proclamations were circulating in the villages, and that if the +princess did not take her father away before the fifteenth, he could +not answer for the consequences. + +The princess decided to leave on the fifteenth. The cares of +preparation and giving orders, for which everyone came to her, +occupied her all day. She spent the night of the fourteenth as +usual, without undressing, in the room next to the one where the +prince lay. Several times, waking up, she heard his groans and +muttering, the creak of his bed, and the steps of Tikhon and the +doctor when they turned him over. Several times she listened at the +door, and it seemed to her that his mutterings were louder than +usual and that they turned him over oftener. She could not sleep and +several times went to the door and listened, wishing to enter but +not deciding to do so. Though he did not speak, Princess Mary saw +and knew how unpleasant every sign of anxiety on his account was to +him. She had noticed with what dissatisfaction he turned from the look +she sometimes involuntarily fixed on him. She knew that her going in +during the night at an unusual hour would irritate him. + +But never had she felt so grieved for him or so much afraid of +losing him. She recalled all her life with him and in every word and +act of his found an expression of his love of her. Occasionally amid +these memories temptations of the devil would surge into her +imagination: thoughts of how things would be after his death, and +how her new, liberated life would be ordered. But she drove these +thoughts away with disgust. Toward morning he became quiet and she +fell asleep. + +She woke late. That sincerity which often comes with waking showed +her clearly what chiefly concerned her about her father's illness. +On waking she listened to what was going on behind the door and, +hearing him groan, said to herself with a sigh that things were +still the same. + +"But what could have happened? What did I want? I want his death!" +she cried with a feeling of loathing for herself. + +She washed, dressed, said her prayers, and went out to the porch. In +front of it stood carriages without horses and things were being +packed into the vehicles. + +It was a warm, gray morning. Princess Mary stopped at the porch, +still horrified by her spiritual baseness and trying to arrange her +thoughts before going to her father. The doctor came downstairs and +went out to her. + +"He is a little better today," said he. "I was looking for you. +One can make out something of what he is saying. His head is +clearer. Come in, he is asking for you..." + +Princess Mary's heart beat so violently at this news that she grew +pale and leaned against the wall to keep from falling. To see him, +talk to him, feel his eyes on her now that her whole soul was +overflowing with those dreadful, wicked temptations, was a torment +of joy and terror. + +"Come," said the doctor. + +Princess Mary entered her father's room and went up to his bed. He +was lying on his back propped up high, and his small bony hands with +their knotted purple veins were lying on the quilt; his left eye gazed +straight before him, his right eye was awry, and his brows and lips +motionless. He seemed altogether so thin, small, and pathetic. His +face seemed to have shriveled or melted; his features had grown +smaller. Princess Mary went up and kissed his hand. His left hand +pressed hers so that she understood that he had long been waiting +for her to come. He twitched her hand, and his brows and lips quivered +angrily. + +She looked at him in dismay trying to guess what he wanted of her. +When she changed her position so that his left eye could see her +face he calmed down, not taking his eyes off her for some seconds. +Then his lips and tongue moved, sounds came, and he began to speak, +gazing timidly and imploringly at her, evidently afraid that she might +not understand. + +Straining all her faculties Princess Mary looked at him. The comic +efforts with which he moved his tongue made her drop her eyes and with +difficulty repress the sobs that rose to her throat. He said +something, repeating the same words several times. She could not +understand them, but tried to guess what he was saying and inquiringly +repeated the words he uttered. + +"Mmm...ar...ate...ate..." he repeated several times. + +It was quite impossible to understand these sounds. The doctor +thought he had guessed them, and inquiringly repeated: "Mary, are +you afraid?" The prince shook his head, again repeated the same +sounds. + +"My mind, my mind aches?" questioned Princess Mary. + +He made a mumbling sound in confirmation of this, took her hand, and +began pressing it to different parts of his breast as if trying to +find the right place for it. + +"Always thoughts... about you... thoughts..." he then uttered much +more clearly than he had done before, now that he was sure of being +understood. + +Princess Mary pressed her head against his hand, trying to hide +her sobs and tears. + +He moved his hand over her hair. + +"I have been calling you all night..." he brought out. + +"If only I had known..." she said through her tears. "I was afraid +to come in." + +He pressed her hand. + +"Weren't you asleep?" + +"No, I did not sleep," said Princess Mary, shaking her head. + +Unconsciously imitating her father, she now tried to express herself +as he did, as much as possible by signs, and her tongue too seemed +to move with difficulty. + +"Dear one... Dearest..." Princess Mary could not quite make out what +he had said, but from his look it was clear that he had uttered a +tender caressing word such as he had never used to her before. "Why +didn't you come in?" + +"And I was wishing for his death!" thought Princess Mary. + +He was silent awhile. + +"Thank you... daughter dear!... for all, for all... forgive!... +thank you!... forgive!... thank you!..." and tears began to flow +from his eyes. "Call Andrew!" he said suddenly, and a childish, +timid expression of doubt showed itself on his face as he spoke. + +He himself seemed aware that his demand was meaningless. So at least +it seemed to Princess Mary. + +"I have a letter from him," she replied. + +He glanced at her with timid surprise. + +"Where is he?" + +"He's with the army, Father, at Smolensk." + +He closed his eyes and remained silent a long time. Then as if in +answer to his doubts and to confirm the fact that now he understood +and remembered everything, he nodded his head and reopened his eyes. + +"Yes," he said, softly and distinctly. "Russia has perished. They've +destroyed her." + +And he began to sob, and again tears flowed from his eyes. +Princess Mary could no longer restrain herself and wept while she +gazed at his face. + +Again he closed his eyes. His sobs ceased, he pointed to his eyes, +and Tikhon, understanding him, wiped away the tears. + +Then he again opened his eyes and said something none of them +could understand for a long time, till at last Tikhon understood and +repeated it. Princess Mary had sought the meaning of his words in +the mood in which he had just been speaking. She thought he was +speaking of Russia, or Prince Andrew, of herself, of his grandson, +or of his own death, and so she could not guess his words. + +"Put on your white dress. I like it," was what he said. + +Having understood this Princess Mary sobbed still louder, and the +doctor taking her arm led her out to the veranda, soothing her and +trying to persuade her to prepare for her journey. When she had left +the room the prince again began speaking about his son, about the war, +and about the Emperor, angrily twitching his brows and raising his +hoarse voice, and then he had a second and final stroke. + +Princess Mary stayed on the veranda. The day had cleared, it was hot +and sunny. She could understand nothing, think of nothing and feel +nothing, except passionate love for her father, love such as she +thought she had never felt till that moment. She ran out sobbing +into the garden and as far as the pond, along the avenues of young +lime trees Prince Andrew had planted. + +"Yes... I... I... I wished for his death! Yes, I wanted it to end +quicker.... I wished to be at peace.... And what will become of me? +What use will peace be when he is no longer here?" Princess Mary +murmured, pacing the garden with hurried steps and pressing her +hands to her bosom which heaved with convulsive sobs. + +When she had completed the tour of the garden, which brought her +again to the house, she saw Mademoiselle Bourienne--who had remained +at Bogucharovo and did not wish to leave it--coming toward her with +a stranger. This was the Marshal of the Nobility of the district, +who had come personally to point out to the princess the necessity for +her prompt departure. Princess Mary listened without understanding +him; she led him to the house, offered him lunch, and sat down with +him. Then, excusing herself, she went to the door of the old +prince's room. The doctor came out with an agitated face and said +she could not enter. + +"Go away, Princess! Go away... go away!" + +She returned to the garden and sat down on the grass at the foot +of the slope by the pond, where no one could see her. She did not know +how long she had been there when she was aroused by the sound of a +woman's footsteps running along the path. She rose and saw Dunyasha +her maid, who was evidently looking for her, and who stopped +suddenly as if in alarm on seeing her mistress. + +"Please come, Princess... The Prince," said Dunyasha in a breaking +voice. + +"Immediately, I'm coming, I'm coming!" replied the princess +hurriedly, not giving Dunyasha time to finish what she was saying, and +trying to avoid seeing the girl she ran toward the house. + +"Princess, it's God's will! You must be prepared for everything," +said the Marshal, meeting her at the house door. + +"Let me alone; it's not true!" she cried angrily to him. + +The doctor tried to stop her. She pushed him aside and ran to her +father's door. "Why are these people with frightened faces stopping +me? I don't want any of them! And what are they doing here?" she +thought. She opened the door and the bright daylight in that +previously darkened room startled her. In the room were her nurse +and other women. They all drew back from the bed, making way for +her. He was still lying on the bed as before, but the stern expression +of his quiet face made Princess Mary stop short on the threshold. + +"No, he's not dead--it's impossible!" she told herself and +approached him, and repressing the terror that seized her, she pressed +her lips to his cheek. But she stepped back immediately. All the force +of the tenderness she had been feeling for him vanished instantly +and was replaced by a feeling of horror at what lay there before +her. "No, he is no more! He is not, but here where he was is something +unfamiliar and hostile, some dreadful, terrifying, and repellent +mystery!" And hiding her face in her hands, Princess Mary sank into +the arms of the doctor, who held her up. + + +In the presence of Tikhon and the doctor the women washed what had +been the prince, tied his head up with a handkerchief that the mouth +should not stiffen while open, and with another handkerchief tied +together the legs that were already spreading apart. Then they dressed +him in uniform with his decorations and placed his shriveled little +body on a table. Heaven only knows who arranged all this and when, but +it all got done as if of its own accord. Toward night candles were +burning round his coffin, a pall was spread over it, the floor was +strewn with sprays of juniper, a printed band was tucked in under +his shriveled head, and in a corner of the room sat a chanter +reading the psalms. + +Just as horses shy and snort and gather about a dead horse, so the +inmates of the house and strangers crowded into the drawing room round +the coffin--the Marshal, the village Elder, peasant women--and all +with fixed and frightened eyes, crossing themselves, bowed and +kissed the old prince's cold and stiffened hand. + + + + + +CHAPTER IX + + +Until Prince Andrew settled in Bogucharovo its owners had always +been absentees, and its peasants were of quite a different character +from those of Bald Hills. They differed from them in speech, dress, +and disposition. They were called steppe peasants. The old prince used +to approve of them for their endurance at work when they came to +Bald Hills to help with the harvest or to dig ponds, and ditches, +but he disliked them for their boorishness. + +Prince Andrew's last stay at Bogucharovo, when he introduced +hospitals and schools and reduced the quitrent the peasants had to +pay, had not softened their disposition but had on the contrary +strengthened in them the traits of character the old prince called +boorishness. Various obscure rumors were always current among them: at +one time a rumor that they would all be enrolled as Cossacks; at +another of a new religion to which they were all to be converted; then +of some proclamation of the Tsar's and of an oath to the Tsar Paul +in 1797 (in connection with which it was rumored that freedom had been +granted them but the landowners had stopped it), then of Peter +Fedorovich's return to the throne in seven years' time, when +everything would be made free and so "simple" that there would be no +restrictions. Rumors of the war with Bonaparte and his invasion were +connected in their minds with the same sort of vague notions of +Antichrist, the end of the world, and "pure freedom." + +In the vicinity of Bogucharovo were large villages belonging to +the crown or to owners whose serfs paid quitrent and could work +where they pleased. There were very few resident landlords in the +neighborhood and also very few domestic or literate serfs, and in +the lives of the peasantry of those parts the mysterious undercurrents +in the life of the Russian people, the causes and meaning of which are +so baffling to contemporaries, were more clearly and strongly +noticeable than among others. One instance, which had occurred some +twenty years before, was a movement among the peasants to emigrate +to some unknown "warm rivers." Hundreds of peasants, among them the +Bogucharovo folk, suddenly began selling their cattle and moving in +whole families toward the southeast. As birds migrate to somewhere +beyond the sea, so these men with their wives and children streamed to +the southeast, to parts where none of them had ever been. They set off +in caravans, bought their freedom one by one or ran away, and drove or +walked toward the "warm rivers." Many of them were punished, some sent +to Siberia, many died of cold and hunger on the road, many returned of +their own accord, and the movement died down of itself just as it +had sprung up, without apparent reason. But such undercurrents still +existed among the people and gathered new forces ready to manifest +themselves just as strangely, unexpectedly, and at the same time +simply, naturally, and forcibly. Now in 1812, to anyone living in +close touch with these people it was apparent that these undercurrents +were acting strongly and nearing an eruption. + +Alpatych, who had reached Bogucharovo shortly before the old +prince's death, noticed an agitation among the peasants, and that +contrary to what was happening in the Bald Hills district, where +over a radius of forty miles all the peasants were moving away and +leaving their villages to be devastated by the Cossacks, the +peasants in the steppe region round Bogucharovo were, it was +rumored, in touch with the French, received leaflets from them that +passed from hand to hand, and did not migrate. He learned from +domestic serfs loyal to him that the peasant Karp, who possessed great +influence in the village commune and had recently been away driving +a government transport, had returned with news that the Cossacks +were destroying deserted villages, but that the French did not harm +them. Alpatych also knew that on the previous day another peasant +had even brought from the village of Visloukhovo, which was occupied +by the French, a proclamation by a French general that no harm would +be done to the inhabitants, and if they remained they would be paid +for anything taken from them. As proof of this the peasant had brought +from Visloukhovo a hundred rubles in notes (he did not know that +they were false) paid to him in advance for hay. + +More important still, Alpatych learned that on the morning of the +very day he gave the village Elder orders to collect carts to move the +princess' luggage from Bogucharovo, there had been a village meeting +at which it had been decided not to move but to wait. Yet there was no +time to waste. On the fifteenth, the day of the old prince's death, +the Marshal had insisted on Princess Mary's leaving at once, as it was +becoming dangerous. He had told her that after the sixteenth he +could not be responsible for what might happen. On the evening of +the day the old prince died the Marshal went away, promising to return +next day for the funeral. But this he was unable to do, for he +received tidings that the French had unexpectedly advanced, and had +barely time to remove his own family and valuables from his estate. + +For some thirty years Bogucharovo had been managed by the village +Elder, Dron, whom the old prince called by the diminutive "Dronushka." + +Dron was one of those physically and mentally vigorous peasants +who grow big beards as soon as they are of age and go on unchanged +till they are sixty or seventy, without a gray hair or the loss of a +tooth, as straight and strong at sixty as at thirty. + +Soon after the migration to the "warm rivers," in which he had taken +part like the rest, Dron was made village Elder and overseer of +Bogucharovo, and had since filled that post irreproachably for +twenty-three years. The peasants feared him more than they did their +master. The masters, both the old prince and the young, and the +steward respected him and jestingly called him "the Minister." +During the whole time of his service Dron had never been drunk or ill, +never after sleepless nights or the hardest tasks had he shown the +least fatigue, and though he could not read he had never forgotten a +single money account or the number of quarters of flour in any of +the endless cartloads he sold for the prince, nor a single shock of +the whole corn crop on any single acre of the Bogucharovo fields. + +Alpatych, arriving from the devastated Bald Hills estate, sent for +his Dron on the day of the prince's funeral and told him to have +twelve horses got ready for the princess' carriages and eighteen carts +for the things to be removed from Bogucharovo. Though the peasants +paid quitrent, Alpatych thought no difficulty would be made about +complying with this order, for there were two hundred and thirty +households at work in Bogucharovo and the peasants were well to do. +But on hearing the order Dron lowered his eyes and remained silent. +Alpatych named certain peasants he knew, from whom he told him to take +the carts. + +Dron replied that the horses of these peasants were away carting. +Alpatych named others, but they too, according to Dron, had no +horses available: some horses were carting for the government, +others were too weak, and others had died for want of fodder. It +seemed that no horses could be had even for the carriages, much less +for the carting. + +Alpatych looked intently at Dron and frowned. Just as Dron was a +model village Elder, so Alpatych had not managed the prince's +estates for twenty years in vain. He a model steward, possessing in +the highest degree the faculty of divining the needs and instincts +of those he dealt with. Having glanced at Dron he at once understood +that his answers did not express his personal views but the general +mood of the Bogucharovo commune, by which the Elder had already been +carried away. But he also knew that Dron, who had acquired property +and was hated by the commune, must be hesitating between the two +camps: the masters' and the serfs'. He noticed this hesitation in +Dron's look and therefore frowned and moved closer up to him. + +"Now just listen, Dronushka," said he. "Don't talk nonsense to me. +His excellency Prince Andrew himself gave me orders to move all the +people away and not leave them with the enemy, and there is an order +from the Tsar about it too. Anyone who stays is a traitor to the Tsar. +Do you hear?" + +"I hear," Dron answered without lifting his eyes. + +Alpatych was not satisfied with this reply. + +"Eh, Dron, it will turn out badly!" he said, shaking his head. + +"The power is in your hands," Dron rejoined sadly. + +"Eh, Dron, drop it!" Alpatych repeated, withdrawing his hand from +his bosom and solemnly pointing to the floor at Dron's feet. "I can +see through you and three yards into the ground under you," he +continued, gazing at the floor in front of Dron. + +Dron was disconcerted, glanced furtively at Alpatych and again +lowered his eyes. + +"You drop this nonsense and tell the people to get ready to leave +their homes and go to Moscow and to get carts ready for tomorrow +morning for the princess' things. And don't go to any meeting +yourself, do you hear?" + +Dron suddenly fell on his knees. + +"Yakov Alpatych, discharge me! Take the keys from me and discharge +me, for Christ's sake!" + +"Stop that!" cried Alpatych sternly. "I see through you and three +yards under you," he repeated, knowing that his skill in beekeeping, +his knowledge of the right time to sow the oats, and the fact that +he had been able to retain the old prince's favor for twenty years had +long since gained him the reputation of being a wizard, and that the +power of seeing three yards under a man is considered an attribute +of wizards. + +Dron got up and was about to say something, but Alpatych interrupted +him. + +"What is it you have got into your heads, eh?... What are you +thinking of, eh?" + +"What am I to do with the people?" said Dron. "They're quite +beside themselves; I have already told them..." + +"'Told them,' I dare say!" said Alpatych. "Are they drinking?" he +asked abruptly. + +"Quite beside themselves, Yakov Alpatych; they've fetched another +barrel." + +"Well, then, listen! I'll go to the police officer, and you tell +them so, and that they must stop this and the carts must be got +ready." + +"I understand." + +Alpatych did not insist further. He had managed people for a long +time and knew that the chief way to make them obey is to show no +suspicion that they can possibly disobey. Having wrung a submissive "I +understand" from Dron, Alpatych contented himself with that, though he +not only doubted but felt almost certain that without the help of +troops the carts would not be forthcoming. + +And so it was, for when evening came no carts had been provided. +In the village, outside the drink shop, another meeting was being +held, which decided that the horses should be driven out into the +woods and the carts should not be provided. Without saying anything of +this to the princess, Alpatych had his own belongings taken out of the +carts which had arrived from Bald Hills and had those horses got ready +for the princess' carriages. Meanwhile he went himself to the police +authorities. + + + + + +CHAPTER X + + +After her father's funeral Princess Mary shut herself up in her room +and did not admit anyone. A maid came to the door to say that Alpatych +was asking for orders about their departure. (This was before his talk +with Dron.) Princess Mary raised herself on the sofa on which she +had been lying and replied through the closed door that she did not +mean to go away and begged to be left in peace. + +The windows of the room in which she was lying looked westward. +She lay on the sofa with her face to the wall, fingering the buttons +of the leather cushion and seeing nothing but that cushion, and her +confused thoughts were centered on one subject--the irrevocability +of death and her own spiritual baseness, which she had not +suspected, but which had shown itself during her father's illness. She +wished to pray but did not dare to, dared not in her present state +of mind address herself to God. She lay for a long time in that +position. + +The sun had reached the other side of the house, and its slanting +rays shone into the open window, lighting up the room and part of +the morocco cushion at which Princess Mary was looking. The flow of +her thoughts suddenly stopped. Unconsciously she sat up, smoothed +her hair, got up, and went to the window, involuntarily inhaling the +freshness of the clear but windy evening. + +"Yes, you can well enjoy the evening now! He is gone and no one will +hinder you," she said to herself, and sinking into a chair she let her +head fall on the window sill. + +Someone spoke her name in a soft and tender voice from the garden +and kissed her head. She looked up. It was Mademoiselle Bourienne in a +black dress and weepers. She softly approached Princess Mary, +sighed, kissed her, and immediately began to cry. The princess +looked up at her. All their former disharmony and her own jealousy +recurred to her mind. But she remembered too how he had changed of +late toward Mademoiselle Bourienne and could not bear to see her, +thereby showing how unjust were the reproaches Princess Mary had +mentally addressed to her. "Besides, is it for me, for me who +desired his death, to condemn anyone?" she thought. + +Princess Mary vividly pictured to herself the position of +Mademoiselle Bourienne, whom she had of late kept at a distance, but +who yet was dependent on her and living in her house. She felt sorry +for her and held out her hand with a glance of gentle inquiry. +Mademoiselle Bourienne at once began crying again and kissed that +hand, speaking of the princess' sorrow and making herself a partner in +it. She said her only consolation was the fact that the princess +allowed her to share her sorrow, that all the old misunderstandings +should sink into nothing but this great grief; that she felt herself +blameless in regard to everyone, and that he, from above, saw her +affection and gratitude. The princess heard her, not heeding her words +but occasionally looking up at her and listening to the sound of her +voice. + +"Your position is doubly terrible, dear princess," said Mademoiselle +Bourienne after a pause. "I understand that you could not, and cannot, +think of yourself, but with my love for you I must do so.... Has +Alpatych been to you? Has he spoken to you of going away?" she asked. + +Princess Mary did not answer. She did not understand who was to go +or where to. "Is it possible to plan or think of anything now? Is it +not all the same?" she thought, and did not reply. + +"You know, chere Marie," said Mademoiselle Bourienne, "that we are +in danger--are surrounded by the French. It would be dangerous to move +now. If we go we are almost sure to be taken prisoners, and God +knows..." + +Princess Mary looked at her companion without understanding what she +was talking about. + +"Oh, if anyone knew how little anything matters to me now," she +said. "Of course I would on no account wish to go away from him.... +Alpatych did say something about going.... Speak to him; I can do +nothing, nothing, and don't want to...." + +"I've spoken to him. He hopes we should be in time to get away +tomorrow, but I think it would now be better to stay here," said +Mademoiselle Bourienne. "Because, you will agree, chere Marie, to fall +into the hands of the soldiers or of riotous peasants would be +terrible." + +Mademoiselle Bourienne took from her reticule a proclamation (not +printed on ordinary Russian paper) of General Rameau's, telling people +not to leave their homes and that the French authorities would +afford them proper protection. She handed this to the princess. + +"I think it would be best to appeal to that general," she continued, +"and and am sure that all due respect would be shown you." + +Princess Mary read the paper, and her face began to quiver with +stifled sobs. + +"From whom did you get this?" she asked. + +"They probably recognized that I am French, by my name," replied +Mademoiselle Bourienne blushing. + +Princess Mary, with the paper in her hand, rose from the window +and with a pale face went out of the room and into what had been +Prince Andrew's study. + +"Dunyasha, send Alpatych, or Dronushka, or somebody to me!" she +said, "and tell Mademoiselle Bourienne not to come to me," she +added, hearing Mademoiselle Bourienne's voice. "We must go at once, at +once!" she said, appalled at the thought of being left in the hands of +the French. + +"If Prince Andrew heard that I was in the power of the French! +That I, the daughter of Prince Nicholas Bolkonski, asked General +Rameau for protection and accepted his favor!" This idea horrified +her, made her shudder, blush, and feel such a rush of anger and +pride as she had never experienced before. All that was distressing, +and especially all that was humiliating, in her position rose +vividly to her mind. "They, the French, would settle in this house: M. +le General Rameau would occupy Prince Andrew's study and amuse himself +by looking through and reading his letters and papers. Mademoiselle +Bourienne would do the honors of Bogucharovo for him. I should be +given a small room as a favor, the soldiers would violate my +father's newly dug grave to steal his crosses and stars, they would +tell me of their victories over the Russians, and would pretend to +sympathize with my sorrow..." thought Princess Mary, not thinking +her own thoughts but feeling bound to think like her father and her +brother. For herself she did not care where she remained or what +happened to her, but she felt herself the representative of her dead +father and of Prince Andrew. Involuntarily she thought their +thoughts and felt their feelings. What they would have said and what +they would have done she felt bound to say and do. She went into +Prince Andrew's study, trying to enter completely into his ideas, +and considered her position. + +The demands of life, which had seemed to her annihilated by her +father's death, all at once rose before her with a new, previously +unknown force and took possession of her. + +Agitated and flushed she paced the room, sending now for Michael +Ivanovich and now for Tikhon or Dron. Dunyasha, the nurse, and the +other maids could not say in how far Mademoiselle Bourienne's +statement was correct. Alpatych was not at home, he had gone to the +police. Neither could the architect Michael Ivanovich, who on being +sent for came in with sleepy eyes, tell Princess Mary anything. With +just the same smile of agreement with which for fifteen years he had +been accustomed to answer the old prince without expressing views of +his own, he now replied to Princess Mary, so that nothing definite +could be got from his answers. The old valet Tikhon, with sunken, +emaciated face that bore the stamp of inconsolable grief, replied: +"Yes, Princess" to all Princess Mary's questions and hardly +refrained from sobbing as he looked at her. + +At length Dron, the village Elder, entered the room and with a +deep bow to Princess Mary came to a halt by the doorpost. + +Princess Mary walked up and down the room and stopped in front of +him. + +"Dronushka," she said, regarding as a sure friend this Dronushka who +always used to bring a special kind of gingerbread from his visit to +the fair at Vyazma every year and smilingly offer it to her, +"Dronushka, now since our misfortune..." she began, but could not go +on. + +"We are all in God's hands," said he, with a sigh. + +They were silent for a while. + +"Dronushka, Alpatych has gone off somewhere and I have no one to +turn to. Is true, as they tell me, that I can't even go away?" + +"Why shouldn't you go away, your excellency? You can go," said Dron. + +"I was told it would be dangerous because of the enemy. Dear friend, +I can do nothing. I understand nothing. I have nobody! I want to go +away tonight or early tomorrow morning." + +Dron paused. He looked askance at Princess Mary and said: "There are +no horses; I told Yakov Alpatych so." + +"Why are there none?" asked the princess. + +"It's all God's scourge," said Dron. "What horses we had have been +taken for the army or have died--this is such a year! It's not a +case of feeding horses--we may die of hunger ourselves! As it is, some +go three days without eating. We've nothing, we've been ruined." + +Princess Mary listened attentively to what he told her. + +"The peasants are ruined? They have no bread?" she asked. + +"They're dying of hunger," said Dron. "It's not a case of carting." + +"But why didn't you tell me, Dronushka? Isn't it possible to help +them? I'll do all I can...." + +To Princess Mary it was strange that now, at a moment when such +sorrow was filling her soul, there could be rich people and poor, +and the rich could refrain from helping the poor. She had heard +vaguely that there was such a thing as "landlord's corn" which was +sometimes given to the peasants. She also knew that neither her father +nor her brother would refuse to help the peasants in need, she only +feared to make some mistake in speaking about the distribution of +the grain she wished to give. She was glad such cares presented +themselves, enabling her without scruple to forget her own grief. +She began asking Dron about the peasants' needs and what there was +in Bogucharovo that belonged to the landlord. + +"But we have grain belonging to my brother?" she said. + +"The landlord's grain is all safe," replied Dron proudly. "Our +prince did not order it to be sold." + +"Give it to the peasants, let them have all they need; I give you +leave in my brother's name," said she. + +Dron made no answer but sighed deeply. + +"Give them that corn if there is enough of it. Distribute it all. +I give this order in my brother's name; and tell them that what is +ours is theirs. We do not grudge them anything. Tell them so." + +Dron looked intently at the princess while she was speaking. + +"Discharge me, little mother, for God's sake! Order the keys to be +taken from me," said he. "I have served twenty-three years and have +done no wrong. Discharge me, for God's sake!" + +Princess Mary did not understand what he wanted of her or why he was +asking to be discharged. She replied that she had never doubted his +devotion and that she was ready to do anything for him and for the +peasants. + + + + + +CHAPTER XI + + +An hour later Dunyasha came to tell the princess that Dron had come, +and all the peasants had assembled at the barn by the princess' +order and wished to have word with their mistress. + +"But I never told them to come," said Princess Mary. "I only told +Dron to let them have the grain." + +"Only, for God's sake, Princess dear, have them sent away and +don't go out to them. It's all a trick," said Dunyasha, "and when +Yakov Alpatych returns let us get away... and please don't..." + +"What is a trick?" asked Princess Mary in surprise. + +"I know it is, only listen to me for God's sake! Ask nurse too. They +say they don't agree to leave Bogucharovo as you ordered." + +"You're making some mistake. I never ordered them to go away," +said Princess Mary. "Call Dronushka." + +Dron came and confirmed Dunyasha's words; the peasants had come by +the princess' order. + +"But I never sent for them," declared the princess. "You must have +given my message wrong. I only said that you were to give them the +grain." + +Dron only sighed in reply. + +"If you order it they will go away," said he. + +"No, no. I'll go out to them," said Princess Mary, and in spite of +the nurse's and Dunyasha's protests she went out into the porch; Dron, +Dunyasha, the nurse, and Michael Ivanovich following her. + +"They probably think I am offering them the grain to bribe them to +remain here, while I myself go away leaving them to the mercy of the +French," thought Princess Mary. "I will offer them monthly rations and +housing at our Moscow estate. I am sure Andrew would do even more in +my place," she thought as she went out in the twilight toward the +crowd standing on the pasture by the barn. + +The men crowded closer together, stirred, and rapidly took off their +hats. Princess Mary lowered her eyes and, tripping over her skirt, +came close up to them. So many different eyes, old and young, were +fixed on her, and there were so many different faces, that she could +not distinguish any of them and, feeling that she must speak to them +all at once, did not know how to do it. But again the sense that she +represented her father and her brother gave her courage, and she +boldly began her speech. + +"I am very glad you have come," she said without raising her eyes, +and feeling her heart beating quickly and violently. "Dronushka +tells me that the war has ruined you. That is our common misfortune, +and I shall grudge nothing to help you. I am myself going away because +it is dangerous here... the enemy is near... because... I am giving +you everything, my friends, and I beg you to take everything, all +our grain, so that you may not suffer want! And if you have been +told that I am giving you the grain to keep you here--that is not +true. On the contrary, I ask you to go with all your belongings to our +estate near Moscow, and I promise you I will see to it that there +you shall want for nothing. You shall be given food and lodging." + +The princess stopped. Sighs were the only sound heard in the crowd. + +"I am not doing this on my own account," she continued, "I do it +in the name of my dead father, who was a good master to you, and of my +brother and his son." + +Again she paused. No one broke the silence. + +"Ours is a common misfortune and we will share it together. All that +is mine is yours," she concluded, scanning the faces before her. + +All eyes were gazing at her with one and the same expression. She +could not fathom whether it was curiosity, devotion, gratitude, or +apprehension and distrust--but the expression on all the faces was +identical. + +"We are all very thankful for your bounty, but it won't do for us to +take the landlord's grain," said a voice at the back of the crowd. + +"But why not?" asked the princess. + +No one replied and Princess Mary, looking round at the crowd, +found that every eye she met now was immediately dropped. + +"But why don't you want to take it?" she asked again. + +No one answered. + +The silence began to oppress the princess and she tried to catch +someone's eye. + +"Why don't you speak?" she inquired of a very old man who stood just +in front of her leaning on his stick. "If you think something more +is wanted, tell me! I will do anything," said she, catching his eye. + +But as if this angered him, he bent his head quite low and muttered: + +"Why should we agree? We don't want the grain." + +"Why should we give up everything? We don't agree. Don't agree.... +We are sorry for you, but we're not willing. Go away yourself, +alone..." came from various sides of the crowd. + +And again all the faces in that crowd bore an identical +expression, though now it was certainly not an expression of curiosity +or gratitude, but of angry resolve. + +"But you can't have understood me," said Princess Mary with a sad +smile. "Why don't you want to go? I promise to house and feed you, +while here the enemy would ruin you..." + +But her voice was drowned by the voices of the crowd. + +"We're not willing. Let them ruin us! We won't take your grain. We +don't agree." + +Again Princess Mary tried to catch someone's eye, but not a single +eye in the crowd was turned to her; evidently they were all trying +to avoid her look. She felt strange and awkward. + +"Oh yes, an artful tale! Follow her into slavery! Pull down your +houses and go into bondage! I dare say! 'I'll give you grain, indeed!' +she says," voices in the crowd were heard saying. + +With drooping head Princess Mary left the crowd and went back to the +house. Having repeated her order to Dron to have horses ready for +her departure next morning, she went to her room and remained alone +with her own thoughts. + + + + + +CHAPTER XII + + +For a long time that night Princess Mary sat by the open window of +her room hearing the sound of the peasants' voices that reached her +from the village, but it was not of them she was thinking. She felt +that she could not understand them however much she might think +about them. She thought only of one thing, her sorrow, which, after +the break caused by cares for the present, seemed already to belong to +the past. Now she could remember it and weep or pray. + +After sunset the wind had dropped. The night was calm and fresh. +Toward midnight the voices began to subside, a cock crowed, the full +moon began to show from behind the lime trees, a fresh white dewy mist +began to rise, and stillness reigned over the village and the house. + +Pictures of the near past--her father's illness and last moments- +rose one after another to her memory. With mournful pleasure she now +lingered over these images, repelling with horror only the last one, +the picture of his death, which she felt she could not contemplate +even in imagination at this still and mystic hour of night. And +these pictures presented themselves to her so clearly and in such +detail that they seemed now present, now past, and now future. + +She vividly recalled the moment when he had his first stroke and was +being dragged along by his armpits through the garden at Bald Hills, +muttering something with his helpless tongue, twitching his gray +eyebrows and looking uneasily and timidly at her. + +"Even then he wanted to tell me what he told me the day he died," +she thought. "He had always thought what he said then." And she +recalled in all its detail the night at Bald Hills before he had the +last stroke, when with a foreboding of disaster she had remained at +home against his will. She had not slept and had stolen downstairs +on tiptoe, and going to the door of the conservatory where he slept +that night had listened at the door. In a suffering and weary voice he +was saying something to Tikhon, speaking of the Crimea and its warm +nights and of the Empress. Evidently he had wanted to talk. "And why +didn't he call me? Why didn't he let me be there instead of Tikhon?" +Princess Mary had thought and thought again now. "Now he will never +tell anyone what he had in his soul. Never will that moment return for +him or for me when he might have said all he longed to say, and not +Tikhon but I might have heard and understood him. Why didn't I enter +the room?" she thought. "Perhaps he would then have said to me what he +said the day he died. While talking to Tikhon he asked about me twice. +He wanted to see me, and I was standing close by, outside the door. It +was sad and painful for him to talk to Tikhon who did not understand +him. I remember how he began speaking to him about Lise as if she were +alive--he had forgotten she was dead--and Tikhon reminded him that she +was no more, and he shouted, 'Fool!' He was greatly depressed. From +behind the door I heard how he lay down on his bed groaning and loudly +exclaimed, 'My God!' Why didn't I go in then? What could he have +done to me? What could I have lost? And perhaps he would then have +been comforted and would have said that word to me." And Princess Mary +uttered aloud the caressing word he had said to her on the day of +his death. "Dear-est!" she repeated, and began sobbing, with tears +that relieved her soul. She now saw his face before her. And not the +face she had known ever since she could remember and had always seen +at a distance, but the timid, feeble face she had seen for the first +time quite closely, with all its wrinkles and details, when she +stooped near to his mouth to catch what he said. + +"Dear-est!" she repeated again. + +"What was he thinking when he uttered that word? What is he thinking +now?" This question suddenly presented itself to her, and in answer +she saw him before her with the expression that was on his face as +he lay in his coffin with his chin bound up with a white handkerchief. +And the horror that had seized her when she touched him and +convinced herself that that was not he, but something mysterious and +horrible, seized her again. She tried to think of something else and +to pray, but could do neither. With wide-open eyes she gazed at the +moonlight and the shadows, expecting every moment to see his dead +face, and she felt that the silence brooding over the house and within +it held her fast. + +"Dunyasha," she whispered. "Dunyasha!" she screamed wildly, and +tearing herself out of this silence she ran to the servants' +quarters to meet her old nurse and the maidservants who came running +toward her. + + + + + +CHAPTER XIII + + +On the seventeenth of August Rostov and Ilyin, accompanied by +Lavrushka who had just returned from captivity and by an hussar +orderly, left their quarters at Yankovo, ten miles from Bogucharovo, +and went for a ride--to try a new horse Ilyin had bought and to find +out whether there was any hay to be had in the villages. + +For the last three days Bogucharovo had lain between the two hostile +armies, so that it was as easy for the Russian rearguard to get to +it as for the French vanguard; Rostov, as a careful squadron +commander, wished to take such provisions as remained at Bogucharovo +before the French could get them. + +Rostov and Ilyin were in the merriest of moods. On the way to +Bogucharovo, a princely estate with a dwelling house and farm where +they hoped to find many domestic serfs and pretty girls, they +questioned Lavrushka about Napoleon and laughed at his stories, and +raced one another to try Ilyin's horse. + +Rostov had no idea that the village he was entering was the property +of that very Bolkonski who had been engaged to his sister. + +Rostov and Ilyin gave rein to their horses for a last race along the +incline before reaching Bogucharovo, and Rostov, outstripping Ilyin, +was the first to gallop into the village street. + +"You're first!" cried Ilyin, flushed. + +"Yes, always first both on the grassland and here," answered Rostov, +stroking his heated Donets horse. + +"And I'd have won on my Frenchy, your excellency," said Lavrushka +from behind, alluding to his shabby cart horse, "only I didn't wish to +mortify you." + +They rode at a footpace to the barn, where a large crowd of peasants +was standing. + +Some of the men bared their heads, others stared at the new arrivals +without doffing their caps. Two tall old peasants with wrinkled +faces and scanty beards emerged from the tavern, smiling, +staggering, and singing some incoherent song, and approached the +officers. + +"Fine fellows!" said Rostov laughing. "Is there any hay here?" + +"And how like one another," said Ilyin. + +"A mo-o-st me-r-r-y co-o-m-pa...!" sang one of the peasants with a +blissful smile. + +One of the men came out of the crowd and went up to Rostov. + +"Who do you belong to?" he asked. + +"The French," replied Ilyin jestingly, "and here is Napoleon +himself"--and he pointed to Lavrushka. + +"Then you are Russians?" the peasant asked again. + +"And is there a large force of you here?" said another, a short man, +coming up. + +"Very large," answered Rostov. "But why have you collected here?" he +added. "Is it a holiday?" + +"The old men have met to talk over the business of the commune," +replied the peasant, moving away. + +At that moment, on the road leading from the big house, two women +and a man in a white hat were seen coming toward the officers. + +"The one in pink is mine, so keep off!" said Ilyin on seeing +Dunyasha running resolutely toward him. + +"She'll be ours!" said Lavrushka to Ilyin, winking. + +"What do you want, my pretty?" said Ilyin with a smile. + +"The princess ordered me to ask your regiment and your name." + +"This is Count Rostov, squadron commander, and I am your humble +servant." + +"Co-o-om-pa-ny!" roared the tipsy peasant with a beatific smile as +he looked at Ilyin talking to the girl. Following Dunyasha, Alpatych +advanced to Rostov, having bared his head while still at a distance. + +"May I make bold to trouble your honor?" said he respectfully, but +with a shade of contempt for the youthfulness of this officer and with +a hand thrust into his bosom. "My mistress, daughter of General in +Chief Prince Nicholas Bolkonski who died on the fifteenth of this +month, finding herself in difficulties owing to the boorishness of +these people"--he pointed to the peasants--"asks you to come up to the +house.... Won't you, please, ride on a little farther," said +Alpatych with a melancholy smile, "as it is not convenient in the +presence of...?" He pointed to the two peasants who kept as close to +him as horseflies to a horse. + +"Ah!... Alpatych... Ah, Yakov Alpatych... Grand! Forgive us for +Christ's sake, eh?" said the peasants, smiling joyfully at him. + +Rostov looked at the tipsy peasants and smiled. + +"Or perhaps they amuse your honor?" remarked Alpatych with a staid +air, as he pointed at the old men with his free hand. + +"No, there's not much to be amused at here," said Rostov, and rode +on a little way. "What's the matter?" he asked. + +"I make bold to inform your honor that the rude peasants here +don't wish to let the mistress leave the estate, and threaten to +unharness her horses, so that though everything has been packed up +since morning, her excellency cannot get away." + +"Impossible!" exclaimed Rostov. + +"I have the honor to report to you the actual truth," said Alpatych. + +Rostov dismounted, gave his horse to the orderly, and followed +Alpatych to the house, questioning him as to the state of affairs. +It appeared that the princess' offer of corn to the peasants the +previous day, and her talk with Dron and at the meeting, had +actually had so bad an effect that Dron had finally given up the +keys and joined the peasants and had not appeared when Alpatych sent +for him; and that in the morning when the princess gave orders to +harness for her journey, the peasants had come in a large crowd to the +barn and sent word that they would not let her leave the village: that +there was an order not to move, and that they would unharness the +horses. Alpatych had gone out to admonish them, but was told (it was +chiefly Karp who did the talking, Dron not showing himself in the +crowd) that they could not let the princess go, that there was an +order to the contrary, but that if she stayed they would serve her +as before and obey her in everything. + +At the moment when Rostov and Ilyin were galloping along the road, +Princess Mary, despite the dissuasions of Alpatych, her nurse, and the +maids, had given orders to harness and intended to start, but when the +cavalrymen were espied they were taken for Frenchmen, the coachman ran +away, and the women in the house began to wail. + +"Father! Benefactor! God has sent you!" exclaimed deeply moved +voices as Rostov passed through the anteroom. + +Princess Mary was sitting helpless and bewildered in the large +sitting room, when Rostov was shown in. She could not grasp who he was +and why he had come, or what was happening to her. When she saw his +Russian face, and by his walk and the first words he uttered +recognized him as a man of her own class, she glanced at him with +her deep radiant look and began speaking in a voice that faltered +and trembled with emotion. This meeting immediately struck Rostov as a +romantic event. "A helpless girl overwhelmed with grief, left to the +mercy of coarse, rioting peasants! And what a strange fate sent me +here! What gentleness and nobility there are in her features and +expression!" thought he as he looked at her and listened to her +timid story. + +When she began to tell him that all this had happened the day +after her father's funeral, her voiced trembled. She turned away, +and then, as if fearing he might take her words as meant to move him +to pity, looked at him with an apprehensive glance of inquiry. There +were tears in Rostov's eyes. Princess Mary noticed this and glanced +gratefully at him with that radiant look which caused the plainness of +her face to be forgotten. + +"I cannot express, Princess, how glad I am that I happened to ride +here and am able to show my readiness to serve you," said Rostov, +rising. "Go when you please, and I give you my word of honor that no +one shall dare to cause you annoyance if only you will allow me to act +as your escort." And bowing respectfully, as if to a lady of royal +blood, he moved toward the door. + +Rostov's deferential tone seemed to indicate that though he would +consider himself happy to be acquainted with her, he did not wish to +take advantage of her misfortunes to intrude upon her. + +Princess Mary understood this and appreciated his delicacy. + +"I am very, very grateful to you," she said in French, "but I hope +it was all a misunderstanding and that no one is to blame for it." She +suddenly began to cry. + +"Excuse me!" she said. + +Rostov, knitting his brows, left the room with another low bow. + + + + + +CHAPTER XIV + + +"Well, is she pretty? Ah, friend--my pink one is delicious; her +name is Dunyasha...." + +But on glancing at Rostov's face Ilyin stopped short. He saw that +his hero and commander was following quite a different train of +thought. + +Rostov glanced angrily at Ilyin and without replying strode off with +rapid steps to the village. + +"I'll show them; I'll give it to them, the brigands!" said he to +himself. + +Alpatych at a gliding trot, only just managing not to run, kept up +with him with difficulty. + +"What decision have you been pleased to come to?" said he. + +Rostov stopped and, clenching his fists, suddenly and sternly turned +on Alpatych. + +"Decision? What decision? Old dotard!..." cried he. "What have you +been about? Eh? The peasants are rioting, and you can't manage them? +You're a traitor yourself! I know you. I'll flay you all alive!..." +And as if afraid of wasting his store of anger, he left Alpatych and +went rapidly forward. Alpatych, mastering his offended feelings, +kept pace with Rostov at a gliding gait and continued to impart his +views. He said the peasants were obdurate and that at the present +moment it would be imprudent to "overresist" them without an armed +force, and would it not be better first to send for the military? + +"I'll give them armed force... I'll 'overresist' them!" uttered +Rostov meaninglessly, breathless with irrational animal fury and the +need to vent it. + +Without considering what he would do he moved unconciously with +quick, resolute steps toward the crowd. And the nearer he drew to it +the more Alpatych felt that this unreasonable action might produce +good results. The peasants in the crowd were similarly impressed +when they saw Rostov's rapid, firm steps and resolute, frowning face. + +After the hussars had come to the village and Rostov had gone to see +the princess, a certain confusion and dissension had arisen among +the crowd. Some of the peasants said that these new arrivals were +Russians and might take it amiss that the mistress was being detained. +Dron was of this opinion, but as soon as he expressed it Karp and +others attacked their ex-Elder. + +"How many years have you been fattening on the commune?" Karp +shouted at him. "It's all one to you! You'll dig up your pot of +money and take it away with you.... What does it matter to you whether +our homes are ruined or not?" + +"We've been told to keep order, and that no one is to leave their +homes or take away a single grain, and that's all about it!" cried +another. + +"It was your son's turn to be conscripted, but no fear! You +begrudged your lump of a son," a little old man suddenly began +attacking Dron--"and so they took my Vanka to be shaved for a soldier! +But we all have to die." + +"To be sure, we all have to die. I'm not against the commune," +said Dron. + +"That's it--not against it! You've filled your belly...." + +The two tall peasants had their say. As soon as Rostov, followed +by Ilyin, Lavrushka, and Alpatych, came up to the crowd, Karp, +thrusting his fingers into his belt and smiling a little, walked to +the front. Dron on the contrary retired to the rear and the crowd drew +closer together. + +"Who is your Elder here? Hey?" shouted Rostov, coming up to the +crowd with quick steps. + +"The Elder? What do you want with him?..." asked Karp. + +But before the words were well out of his mouth, his cap flew off +and a fierce blow jerked his head to one side. + +"Caps off, traitors!" shouted Rostov in a wrathful voice. "Where's +the Elder?" he cried furiously. + +"The Elder.... He wants the Elder!... Dron Zakharych, you!" meek and +flustered voices here and there were heard calling and caps began to +come off their heads. + +"We don't riot, we're following the orders," declared Karp, and at +that moment several voices began speaking together. + +"It's as the old men have decided--there's too many of you giving +orders." + +"Arguing? Mutiny!... Brigands! Traitors!" cried Rostov unmeaningly +in a voice not his own, gripping Karp by the collar. "Bind him, bind +him!" he shouted, though there was no one to bind him but Lavrushka +and Alpatych. + +Lavrushka, however, ran up to Karp and seized him by the arms from +behind. + +"Shall I call up our men from beyond the hill?" he called out. + +Alpatych turned to the peasants and ordered two of them by name to +come and bind Karp. The men obediently came out of the crowd and began +taking off their belts. + +"Where's the Elder?" demanded Rostov in a loud voice. + +With a pale and frowning face Dron stepped out of the crowd. + +"Are you the Elder? Bind him, Lavrushka!" shouted Rostov, as if that +order, too, could not possibly meet with any opposition. + +And in fact two more peasants began binding Dron, who took off his +own belt and handed it to them, as if to aid them. + +"And you all listen to me!" said Rostov to the peasants. "Be off +to your houses at once, and don't let one of your voices be heard!" + +"Why, we've not done any harm! We did it just out of foolishness. +It's all nonsense... I said then that it was not in order," voices +were heard bickering with one another. + +"There! What did I say?" said Alpatych, coming into his own again. +"It's wrong, lads!" + + "All our stupidity, Yakov Alpatych," came the answers, and the +crowd began at once to disperse through the village. + +The two bound men were led off to the master's house. The two +drunken peasants followed them. + +"Aye, when I look at you!..." said one of them to Karp. + +"How can one talk to the masters like that? What were you thinking +of, you fool?" added the other--"A real fool!" + +Two hours later the carts were standing in the courtyard of the +Bogucharovo house. The peasants were briskly carrying out the +proprietor's goods and packing them on the carts, and Dron, +liberated at Princess Mary's wish from the cupboard where he had +been confined, was standing in the yard directing the men. + +"Don't put it in so carelessly," said one of the peasants, a man +with a round smiling face, taking a casket from a housemaid. "You know +it has cost money! How can you chuck it in like that or shove it under +the cord where it'll get rubbed? I don't like that way of doing +things. Let it all be done properly, according to rule. Look here, put +it under the bast matting and cover it with hay--that's the way!" + +"Eh, books, books!" said another peasant, bringing out Prince +Andrew's library cupboards. "Don't catch up against it! It's heavy, +lads--solid books." + +"Yes, they worked all day and didn't play!" remarked the tall, +round-faced peasant gravely, pointing with a significant wink at the +dictionaries that were on the top. + + +Unwilling to obtrude himself on the princess, Rostov did not go back +to the house but remained in the village awaiting her departure. +When her carriage drove out of the house, he mounted and accompanied +her eight miles from Bogucharovo to where the road was occupied by our +troops. At the inn at Yankovo he respectfully took leave of her, for +the first time permitting himself to kiss her hand. + +"How can you speak so!" he blushingly replied to Princess Mary's +expressions of gratitude for her deliverance, as she termed what had +occurred. "Any police officer would have done as much! If we had had +only peasants to fight, we should not have let the enemy come so far," +said he with a sense of shame and wishing to change the subject. "I am +only happy to have had the opportunity of making your acquaintance. +Good-by, Princess. I wish you happiness and consolation and hope to +meet you again in happier circumstances. If you don't want to make +me blush, please don't thank me!" + +But the princess, if she did not again thank him in words, thanked +him with the whole expression of her face, radiant with gratitude +and tenderness. She could not believe that there was nothing to +thank him for. On the contrary, it seemed to her certain that had he +not been there she would have perished at the hands of the mutineers +and of the French, and that he had exposed himself to terrible and +obvious danger to save her, and even more certain was it that he was a +man of lofty and noble soul, able to understand her position and her +sorrow. His kind, honest eyes, with the tears rising in them when +she herself had begun to cry as she spoke of her loss, did leave her +memory. + +When she had taken leave of him and remained alone she suddenly felt +her eyes filling with tears, and then not for the first time the +strange question presented itself to her: did she love him? + +On the rest of the way to Moscow, though the princess' position +was not a cheerful one, Dunyasha, who went with her in the carriage, +more than once noticed that her mistress leaned out of the window +and smiled at something with an expression of mingled joy and sorrow. + +"Well, supposing I do love him?" thought Princess Mary. + +Ashamed as she was of acknowledging to herself that she had fallen +in love with a man who would perhaps never love her, she comforted +herself with the thought that no one would ever know it and that she +would not be to blame if, without ever speaking of it to anyone, she +continued to the end of her life to love the man with whom she had +fallen in love for the first and last time in her life. + +Sometimes when she recalled his looks, his sympathy, and his +words, happiness did not appear impossible to her. It was at those +moments that Dunyasha noticed her smiling as she looked out of the +carriage window. + +"Was it not fate that brought him to Bogucharovo, and at that very +moment?" thought Princess Mary. "And that caused his sister to +refuse my brother?" And in all this Princess Mary saw the hand of +Providence. + +The impression the princess made on Rostov was a very agreeable one. +To remember her gave him pleasure, and when his comrades, hearing of +his adventure at Bogucharovo, rallied him on having gone to look for +hay and having picked up one of the wealthiest heiresses in Russia, he +grew angry. It made him angry just because the idea of marrying the +gentle Princess Mary, who was attractive to him and had an enormous +fortune, had against his will more than once entered his head. For +himself personally Nicholas could not wish for a better wife: by +marrying her he would make the countess his mother happy, would be +able to put his father's affairs in order, and would even--he felt it- +ensure Princess Mary's happiness. + +But Sonya? And his plighted word? That was why Rostov grew angry +when he was rallied about Princess Bolkonskaya. + + + + + +CHAPTER XV + + +On receiving command of the armies Kutuzov remembered Prince +Andrew and sent an order for him to report at headquarters. + +Prince Andrew arrived at Tsarevo-Zaymishche on the very day and at +the very hour that Kutuzov was reviewing the troops for the first +time. He stopped in the village at the priest's house in front of +which stood the commander in chief's carriage, and he sat down on +the bench at the gate awaiting his Serene Highness, as everyone now +called Kutuzov. From the field beyond the village came now sounds of +regimental music and now the roar of many voices shouting "Hurrah!" to +the new commander in chief. Two orderlies, a courier and a major-domo, +stood near by, some ten paces from Prince Andrew, availing +themselves of Kutuzov's absence and of the fine weather. A short, +swarthy lieutenant colonel of hussars with thick mustaches and +whiskers rode up to the gate and, glancing at Prince Andrew, +inquired whether his Serene Highness was putting up there and +whether he would soon be back. + +Prince Andrew replied that he was not on his Serene Highness' +staff but was himself a new arrival. The lieutenant colonel turned +to a smart orderly, who, with the peculiar contempt with which a +commander in chief's orderly speaks to officers, replied: + +"What? His Serene Highness? I expect he'll be here soon. What do you +want?" + +The lieutenant colonel of hussars smiled beneath his mustache at the +orderly's tone, dismounted, gave his horse to a dispatch runner, and +approached Bolkonski with a slight bow. Bolkonski made room for him on +the bench and the lieutenant colonel sat down beside him. + +"You're also waiting for the commander in chief?" said he. "They say +he weceives evewyone, thank God!... It's awful with those sausage +eaters! Ermolov had weason to ask to be pwomoted to be a German! Now +p'waps Wussians will get a look in. As it was, devil only knows what +was happening. We kept wetweating and wetweating. Did you take part in +the campaign?" he asked. + +"I had the pleasure," replied Prince Andrew, "not only of taking +part in the retreat but of losing in that retreat all I held dear--not +to mention the estate and home of my birth--my father, who died of +grief. I belong to the province of Smolensk." + +"Ah? You're Pwince Bolkonski? Vewy glad to make your acquaintance! +I'm Lieutenant Colonel Denisov, better known as 'Vaska,'" said +Denisov, pressing Prince Andrew's hand and looking into his face +with a particularly kindly attention. "Yes, I heard," said he +sympathetically, and after a short pause added: "Yes, it's Scythian +warfare. It's all vewy well--only not for those who get it in the +neck. So you are Pwince Andwew Bolkonski?" He swayed his head. "Vewy +pleased, Pwince, to make your acquaintance!" he repeated again, +smiling sadly, and he again pressed Prince Andrew's hand. + +Prince Andrew knew Denisov from what Natasha had told him of her +first suitor. This memory carried him sadly and sweetly back to +those painful feelings of which he had not thought lately, but which +still found place in his soul. Of late he had received so many new and +very serious impressions--such as the retreat from Smolensk, his visit +to Bald Hills, and the recent news of his father's death--and had +experienced so many emotions, that for a long time past those memories +had not entered his mind, and now that they did, they did not act on +him with nearly their former strength. For Denisov, too, the +memories awakened by the name of Bolkonski belonged to a distant, +romantic past, when after supper and after Natasha's singing he had +proposed to a little girl of fifteen without realizing what he was +doing. He smiled at the recollection of that time and of his love +for Natasha, and passed at once to what now interested him +passionately and exclusively. This was a plan of campaign he had +devised while serving at the outposts during the retreat. He had +proposed that plan to Barclay de Tolly and now wished to propose it to +Kutuzov. The plan was based on the fact that the French line of +operation was too extended, and it proposed that instead of, or +concurrently with, action on the front to bar the advance of the +French, we should attack their line of communication. He began +explaining his plan to Prince Andrew. + +"They can't hold all that line. It's impossible. I will undertake to +bweak thwough. Give me five hundwed men and I will bweak the line, +that's certain! There's only one way--guewilla warfare!" + +Denisov rose and began gesticulating as he explained his plan to +Bolkonski. In the midst of his explanation shouts were heard from +the army, growing more incoherent and more diffused, mingling with +music and songs and coming from the field where the review was held. +Sounds of hoofs and shouts were nearing the village. + +"He's coming! He's coming!" shouted a Cossack standing at the gate. + +Bolkonski and Denisov moved to the gate, at which a knot of soldiers +(a guard of honor) was standing, and they saw Kutuzov coming down +the street mounted on a rather small sorrel horse. A huge suite of +generals rode behind him. Barclay was riding almost beside him, and +a crowd of officers ran after and around them shouting, "Hurrah!" + +His adjutants galloped into the yard before him. Kutuzov was +impatiently urging on his horse, which ambled smoothly under his +weight, and he raised his hand to his white Horse Guard's cap with a +red band and no peak, nodding his head continually. When he came up to +the guard of honor, a fine set of Grenadiers mostly wearing +decorations, who were giving him the salute, he looked at them +silently and attentively for nearly a minute with the steady gaze of a +commander and then turned to the crowd of generals and officers +surrounding him. Suddenly his face assumed a subtle expression, he +shrugged his shoulders with an air of perplexity. + +"And with such fine fellows to retreat and retreat! Well, good-by, +General," he added, and rode into the yard past Prince Andrew and +Denisov. + +"Hurrah! hurrah! hurrah!" shouted those behind him. + +Since Prince Andrew had last seen him Kutuzov had grown still more +corpulent, flaccid, and fat. But the bleached eyeball, the scar, and +the familiar weariness of his expression were still the same. He was +wearing the white Horse Guard's cap and a military overcoat with a +whip hanging over his shoulder by a thin strap. He sat heavily and +swayed limply on his brisk little horse. + +"Whew... whew... whew!" he whistled just audibly as he rode into the +yard. His face expressed the relief of relaxed strain felt by a man +who means to rest after a ceremony. He drew his left foot out of the +stirrup and, lurching with his whole body and puckering his face +with the effort, raised it with difficulty onto the saddle, leaned +on his knee, groaned, and slipped down into the arms of the Cossacks +and adjutants who stood ready to assist him. + +He pulled himself together, looked round, screwing up his eyes, +glanced at Prince Andrew, and, evidently not recognizing him, moved +with his waddling gait to the porch. "Whew... whew... whew!" he +whistled, and again glanced at Prince Andrew. As often occurs with old +men, it was only after some seconds that the impression produced by +Prince Andrew's face linked itself up with Kutuzov's remembrance of +his personality. + +"Ah, how do you do, my dear prince? How do you do, my dear boy? Come +along..." said he, glancing wearily round, and he stepped onto the +porch which creaked under his weight. + +He unbuttoned his coat and sat down on a bench in the porch. + +"And how's your father?" + +"I received news of his death, yesterday," replied Prince Andrew +abruptly. + +Kutuzov looked at him with eyes wide open with dismay and then +took off his cap and crossed himself: + +"May the kingdom of Heaven be his! God's will be done to us all!" He +sighed deeply, his whole chest heaving, and was silent for a while. "I +loved him and respected him, and sympathize with you with all my +heart." + +He embraced Prince Andrew, pressing him to his fat breast, and for +some time did not let him go. When he released him Prince Andrew saw +that Kutuzov's flabby lips were trembling and that tears were in his +eyes. He sighed and pressed on the bench with both hands to raise +himself. + +"Come! Come with me, we'll have a talk," said he. + +But at that moment Denisov, no more intimidated by his superiors +than by the enemy, came with jingling spurs up the steps of the porch, +despite the angry whispers of the adjutants who tried to stop him. +Kutuzov, his hands still pressed on the seat, glanced at him glumly. +Denisov, having given his name, announced that he had to communicate +to his Serene Highness a matter of great importance for their +country's welfare. Kutuzov looked wearily at him and, lifting his +hands with a gesture of annoyance, folded them across his stomach, +repeating the words: "For our country's welfare? Well, what is it? +Speak!" Denisov blushed like a girl (it was strange to see the color +rise in that shaggy, bibulous, time-worn face) and boldly began to +expound his plan of cutting the enemy's lines of communication between +Smolensk and Vyazma. Denisov came from those parts and knew the +country well. His plan seemed decidedly a good one, especially from +the strength of conviction with which he spoke. Kutuzov looked down at +his own legs, occasionally glancing at the door of the adjoining hut +as if expecting something unpleasant to emerge from it. And from +that hut, while Denisov was speaking, a general with a portfolio under +his arm really did appear. + +"What?" said Kutuzov, in the midst of Denisov's explanations, "are +you ready so soon?" + +"Ready, your Serene Highness," replied the general. + +Kutuzov swayed his head, as much as to say: "How is one man to +deal with it all?" and again listened to Denisov. + +"I give my word of honor as a Wussian officer," said Denisov, +"that I can bweak Napoleon's line of communication!" + +"What relation are you to Intendant General Kiril Andreevich +Denisov?" asked Kutuzov, interrupting him. + +"He is my uncle, your Sewene Highness." + +"Ah, we were friends," said Kutuzov cheerfully. "All right, all +right, friend, stay here at the staff and tomorrow we'll have a talk." + +With a nod to Denisov he turned away and put out his hand for the +papers Konovnitsyn had brought him. + +"Would not your Serene Highness like to come inside?" said the +general on duty in a discontented voice, "the plans must be examined +and several papers have to be signed." + +An adjutant came out and announced that everything was in +readiness within. But Kutuzov evidently did not wish to enter that +room till he was disengaged. He made a grimace... + +"No, tell them to bring a small table out here, my dear boy. I'll +look at them here," said he. "Don't go away," he added, turning to +Prince Andrew, who remained in the porch and listened to the general's +report. + +While this was being given, Prince Andrew heard the whisper of a +woman's voice and the rustle of a silk dress behind the door. +Several times on glancing that way he noticed behind that door a +plump, rosy, handsome woman in a pink dress with a lilac silk kerchief +on her head, holding a dish and evidently awaiting the entrance of the +commander in chief. Kutuzov's adjutant whispered to Prince Andrew +that this was the wife of the priest whose home it was, and that she +intended to offer his Serene Highness bread and salt. "Her husband has +welcomed his Serene Highness with the cross at the church, and she +intends to welcome him in the house.... She's very pretty," added +the adjutant with a smile. At those words Kutuzov looked round. He was +listening to the general's report--which consisted chiefly of a +criticism of the position at Tsarevo-Zaymishche--as he had listened to +Denisov, and seven years previously had listened to the discussion +at the Austerlitz council of war. He evidently listened only because +he had ears which, though there was a piece of tow in one of them, +could not help hearing; but it was evident that nothing the general +could say would surprise or even interest him, that he knew all that +would be said beforehand, and heard it all only because he had to, +as one has to listen to the chanting of a service of prayer. All +that Denisov had said was clever and to the point. What the general +was saying was even more clever and to the point, but it was evident +that Kutuzov despised knowledge and cleverness, and knew of +something else that would decide the matter--something independent +of cleverness and knowledge. Prince Andrew watched the commander +in chief's face attentively, and the only expression he could see +there was one of boredom, curiosity as to the meaning of the +feminine whispering behind the door, and a desire to observe +propriety. It was evident that Kutuzov despised cleverness and +learning and even the patriotic feeling shown by Denisov, but despised +them not because of his own intellect, feelings, or knowledge--he +did not try to display any of these--but because of something else. He +despised them because of his old age and experience of life. The +only instruction Kutuzov gave of his own accord during that report +referred to looting by the Russian troops. At the end of the report +the general put before him for signature a paper relating to the +recovery of payment from army commanders for green oats mown down by +the soldiers, when landowners lodged petitions for compensation. + +After hearing the matter, Kutuzov smacked his lips together and +shook his head. + +"Into the stove... into the fire with it! I tell you once for all, +my dear fellow," said he, "into the fire with all such things! Let +them cut the crops and burn wood to their hearts' content. I don't +order it or allow it, but I don't exact compensation either. One can't +get on without it. 'When wood is chopped the chips will fly.'" He +looked at the paper again. "Oh, this German precision!" he muttered, +shaking his head. + + + + + +CHAPTER XVI + + +"Well, that's all!" said Kutuzov as he signed the last of the +documents, and rising heavily and smoothing out the folds in his fat +white neck he moved toward the door with a more cheerful expression. + +The priest's wife, flushing rosy red, caught up the dish she had +after all not managed to present at the right moment, though she had +so long been preparing for it, and with a low bow offered it to +Kutuzov. + +He screwed up his eyes, smiled, lifted her chin with his hand, and +said: + +"Ah, what a beauty! Thank you, sweetheart!" + +He took some gold pieces from his trouser pocket and put them on the +dish for her. "Well, my dear, and how are we getting on?" he asked, +moving to the door of the room assigned to him. The priest's wife +smiled, and with dimples in her rosy cheeks followed him into the +room. The adjutant came out to the porch and asked Prince Andrew to +lunch with him. Half an hour later Prince Andrew was again called to +Kutuzov. He found him reclining in an armchair, still in the same +unbuttoned overcoat. He had in his hand a French book which he +closed as Prince Andrew entered, marking the place with a knife. +Prince Andrew saw by the cover that it was Les Chevaliers du Cygne +by Madame de Genlis. + +"Well, sit down, sit down here. Let's have a talk," said Kutuzov. +"It's sad, very sad. But remember, my dear fellow, that I am a +father to you, a second father...." + +Prince Andrew told Kutuzov all he knew of his father's death, and +what he had seen at Bald Hills when he passed through it. + +"What... what they have brought us to!" Kutuzov suddenly cried in an +agitated voice, evidently picturing vividly to himself from Prince +Andrew's story the condition Russia was in. "But give me time, give me +time!" he said with a grim look, evidently not wishing to continue +this agitating conversation, and added: "I sent for you to keep you +with me." + +"I thank your Serene Highness, but I fear I am no longer fit for the +staff," replied Prince Andrew with a smile which Kutuzov noticed. + +Kutuzov glanced inquiringly at him. + +"But above all," added Prince Andrew, "I have grown used to my +regiment, am fond of the officers, and I fancy the men also like me. I +should be sorry to leave the regiment. If I decline the honor of being +with you, believe me..." + +A shrewd, kindly, yet subtly derisive expression lit up Kutuzov's +podgy face. He cut Bolkonski short. + +"I am sorry, for I need you. But you're right, you're right! It's +not here that men are needed. Advisers are always plentiful, but men +are not. The regiments would not be what they are if the would-be +advisers served there as you do. I remember you at Austerlitz.... I +remember, yes, I remember you with the standard!" said Kutuzov, and +a flush of pleasure suffused Prince Andrew's face at this +recollection. + +Taking his hand and drawing him downwards, Kutuzov offered his cheek +to be kissed, and again Prince Andrew noticed tears in the old man's +eyes. Though Prince Andrew knew that Kutuzov's tears came easily, +and that he was particularly tender to and considerate of him from a +wish to show sympathy with his loss, yet this reminder of Austerlitz +was both pleasant and flattering to him. + +"Go your way and God be with you. I know your path is the path of +honor!" He paused. "I missed you at Bucharest, but I needed someone to +send." And changing the subject, Kutuzov began to speak of the Turkish +war and the peace that had been concluded. "Yes, I have been much +blamed," he said, "both for that war and the peace... but everything +came at the right time. Tout vient a point a celui qui sait attendre.* +And there were as many advisers there as here..." he went on, +returning to the subject of "advisers" which evidently occupied him. +"Ah, those advisers!" said he. "If we had listened to them all we +should not have made peace with Turkey and should not have been +through with that war. Everything in haste, but more haste, less +speed. Kamenski would have been lost if he had not died. He stormed +fortresses with thirty thousand men. It is not difficult to capture +a fortress but it is difficult to win a campaign. For that, storming +and attacking but patience and time are wanted. Kamenski sent soldiers +to Rustchuk, but I only employed these two things and took more +fortresses than Kamenski and made them but eat horseflesh!" He swayed +his head. "And the French shall too, believe me," he went on, +growing warmer and beating his chest, "I'll make them eat horseflesh!" +And tears again dimmed his eyes. + + +*"Everything comes in time to him who knows how to wait." + + +"But shan't we have to accept battle?" remarked Prince Andrew. + +"We shall if everybody wants it; it can't be helped.... But +believe me, my dear boy, there is nothing stronger than those two: +patience and time, they will do it all. But the advisers n'entendent +pas de cette oreille, voila le mal.* Some want a thing--others +don't. What's one to do?" he asked, evidently expecting an answer. +"Well, what do you want us to do?" he repeated and his eye shone +with a deep, shrewd look. "I'll tell you what to do," he continued, as +Prince Andrew still did not reply: "I will tell you what to do, and +what I do. Dans le doute, mon cher," he paused, "abstiens-toi"*[2]--he +articulated the French proverb deliberately. + + +*"Don't see it that way, that's the trouble." + +*[2] "When in doubt, my dear fellow, do nothing." + + +"Well, good-by, my dear fellow; remember that with all my heart I +share your sorrow, and that for you I am not a Serene Highness, nor +a prince, nor a commander in chief, but a father! If you want anything +come straight to me. Good-by, my dear boy." + +Again he embraced and kissed Prince Andrew, but before the latter +had left the room Kutuzov gave a sigh of relief and went on with his +unfinished novel, Les Chevaliers du Cygne by Madame de Genlis. + +Prince Andrew could not have explained how or why it was, but +after that interview with Kutuzov he went back to his regiment +reassured as to the general course of affairs and as to the man to +whom it had been entrusted. The more he realized the absence of all +personal motive in that old man--in whom there seemed to remain only +the habit of passions, and in place of an intellect (grouping events +and drawing conclusions) only the capacity calmly to contemplate the +course of events--the more reassured he was that everything would be +as it should. "He will not bring in any plan of his own. He will not +devise or undertake anything," thought Prince Andrew, "but he will +hear everything, remember everything, and put everything in its place. +He will not hinder anything useful nor allow anything harmful. He +understands that there is something stronger and more important than +his own will--the inevitable course of events, and he can see them and +grasp their significance, and seeing that significance can refrain +from meddling and renounce his personal wish directed to something +else. And above all," thought Prince Andrew, "one believes in him +because he's Russian, despite the novel by Genlis and the French +proverbs, and because his voice shook when he said: 'What they have +brought us to!' and had a sob in it when he said he would 'make them +eat horseflesh!'" + +On such feelings, more or less dimly shared by all, the unanimity +and general approval were founded with which, despite court +influences, the popular choice of Kutuzov as commander in chief was +received. + + + + + +CHAPTER XVII + + +After the Emperor had left Moscow, life flowed on there in its usual +course, and its course was so very usual that it was difficult to +remember the recent days of patriotic elation and ardor, hard to +believe that Russia was really in danger and that the members of the +English Club were also sons of the Fatherland ready to sacrifice +everything for it. The one thing that recalled the patriotic fervor +everyone had displayed during the Emperor's stay was the call for +contributions of men and money, a necessity that as soon as the +promises had been made assumed a legal, official form and became +unavoidable. + +With the enemy's approach to Moscow, the Moscovites' view of their +situation did not grow more serious but on the contrary became even +more frivolous, as always happens with people who see a great danger +approaching. At the approach of danger there are always two voices +that speak with equal power in the human soul: one very reasonably +tells a man to consider the nature of the danger and the means of +escaping it; the other, still more reasonably, says that it is too +depressing and painful to think of the danger, since it is not in +man's power to foresee everything and avert the general course of +events, and it is therefore better to disregard what is painful till +it comes, and to think about what is pleasant. In solitude a man +generally listens to the first voice, but in society to the second. So +it was now with the inhabitants of Moscow. It was long since people +had been as gay in Moscow as that year. + +Rostopchin's broadsheets, headed by woodcuts of a drink shop, a +potman, and a Moscow burgher called Karpushka Chigirin, "who--having +been a militiaman and having had rather too much at the pub--heard +that Napoleon wished to come to Moscow, grew angry, abused the +French in very bad language, came out of the drink shop, and, under +the sign of the eagle, began to address the assembled people," were +read and discussed, together with the latest of Vasili Lvovich +Pushkin's bouts rimes. + +In the corner room at the Club, members gathered to read these +broadsheets, and some liked the way Karpushka jeered at the French, +saying: "They will swell up with Russian cabbage, burst with our +buckwheat porridge, and choke themselves with cabbage soup. They are +all dwarfs and one peasant woman will toss three of them with a +hayfork." Others did not like that tone and said it was stupid and +vulgar. It was said that Rostopchin had expelled all Frenchmen and +even all foreigners from Moscow, and that there had been some spies +and agents of Napoleon among them; but this was told chiefly to +introduce Rostopchin's witty remark on that occasion. The foreigners +were deported to Nizhni by boat, and Rostopchin had said to them in +French: "Rentrez en vousmemes; entrez dans la barque, et n'en faites +pas une barque de Charon."* There was talk of all the government +offices having been already removed from Moscow, and to this +Shinshin's witticism was added--that for that alone Moscow ought to be +grateful to Napoleon. It was said that Mamonov's regiment would cost +him eight hundred thousand rubles, and that Bezukhov had spent even +more on his, but that the best thing about Bezukhov's action was +that he himself was going to don a uniform and ride at the head of his +regiment without charging anything for the show. + + +*"Think it over; get into the barque, and take care not to make it a +barque of Charon." + + +"You don't spare anyone," said Julie Drubetskaya as she collected +and pressed together a bunch of raveled lint with her thin, beringed +fingers. + +Julie was preparing to leave Moscow next day and was giving a +farewell soiree. + +"Bezukhov est ridicule, but he is so kind and good-natured. What +pleasure is there to be so caustique?" + +"A forfeit!" cried a young man in militia uniform whom Julie +called "mon chevalier," and who was going with her to Nizhni. + +In Julie's set, as in many other circles in Moscow, it had been +agreed that they would speak nothing but Russian and that those who +made a slip and spoke French should pay fines to the Committee of +Voluntary Contributions. + +"Another forfeit for a Gallicism," said a Russian writer who was +present. "'What pleasure is there to be' is not Russian!" + +"You spare no one," continued Julie to the young man without heeding +the author's remark. + +"For caustique--I am guilty and will pay, and I am prepared to pay +again for the pleasure of telling you the truth. For Gallicisms I +won't be responsible," she remarked, turning to the author: "I have +neither the money nor the time, like Prince Galitsyn, to engage a +master to teach me Russian!" + +"Ah, here he is!" she added. "Quand on... No, no," she said to the +militia officer, "you won't catch me. Speak of the sun and you see its +rays!" and she smiled amiably at Pierre. "We were just talking of +you," she said with the facility in lying natural to a society +woman. "We were saying that your regiment would be sure to be better +than Mamonov's." + +"Oh, don't talk to me of my regiment," replied Pierre, kissing his +hostess' hand and taking a seat beside her. "I am so sick of it." + +"You will, of course, command it yourself?" said Julie, directing +a sly, sarcastic glance toward the militia officer. + +The latter in Pierre's presence had ceased to be caustic, and his +face expressed perplexity as to what Julie's smile might mean. In +spite of his absent-mindedness and good nature, Pierre's personality +immediately checked any attempt to ridicule him to his face. + +"No," said Pierre, with a laughing glance at his big, stout body. "I +should make too good a target for the French, besides I am afraid I +should hardly be able to climb onto a horse." + +Among those whom Julie's guests happened to choose to gossip about +were the Rostovs. + +"I hear that their affairs are in a very bad way," said Julie. +"And he is so unreasonable, the count himself I mean. The +Razumovskis wanted to buy his house and his estate near Moscow, but it +drags on and on. He asks too much." + +"No, I think the sale will come off in a few days," said someone. +"Though it is madness to buy anything in Moscow now." + +"Why?" asked Julie. "You don't think Moscow is in danger?" + +"Then why are you leaving?" + +"I? What a question! I am going because... well, because everyone is +going: and besides--I am not Joan of Arc or an Amazon." + +"Well, of course, of course! Let me have some more strips of linen." + +"If he manages the business properly he will be able to pay off +all his debts," said the militia officer, speaking of Rostov. + +"A kindly old man but not up to much. And why do they stay on so +long in Moscow? They meant to leave for the country long ago. +Natalie is quite well again now, isn't she?" Julie asked Pierre with a +knowing smile. + +"They are waiting for their younger son," Pierre replied. "He joined +Obolenski's Cossacks and went to Belaya Tserkov where the regiment +is being formed. But now they have had him transferred to my +regiment and are expecting him every day. The count wanted to leave +long ago, but the countess won't on any account leave Moscow till +her son returns." + +"I met them the day before yesterday at the Arkharovs'. Natalie +has recovered her looks and is brighter. She sang a song. How easily +some people get over everything!" + +"Get over what?" inquired Pierre, looking displeased. + +Julie smiled. + +"You know, Count, such knights as you are only found in Madame de +Souza's novels." + +"What knights? What do you mean?" demanded Pierre, blushing. + +"Oh, come, my dear count! C'est la fable de tout Moscou. Je vous +admire, ma parole d'honneur!"* + + +*"It is the talk of all Moscow. My word, I admire you!" + + +"Forfeit, forfeit!" cried the militia officer. + +"All right, one can't talk--how tiresome!" + +"What is 'the talk of all Moscow'?" Pierre asked angrily, rising +to his feet. + +"Come now, Count, you know!" + +"I don't know anything about it," said Pierre. + +"I know you were friendly with Natalie, and so... but I was always +more friendly with Vera--that dear Vera." + +"No, madame!" Pierre continued in a tone of displeasure, "I have not +taken on myself the role of Natalie Rostova's knight at all, and +have not been their house for nearly a month. But I cannot +understand the cruelty..." + +"Qui s'excuse s'accuse,"* said Julie, smiling and waving the lint +triumphantly, and to have the last word she promptly changed the +subject. "Do you know what I heard today? Poor Mary Bolkonskaya +arrived in Moscow yesterday. Do you know that she has lost her +father?" + + +*"Who excuses himself, accuses himself." + + +"Really? Where is she? I should like very much to see her," said +Pierre. + +"I spent the evening with her yesterday. She is going to their +estate near Moscow either today or tomorrow morning, with her nephew." + +"Well, and how is she?" asked Pierre. + +"She is well, but sad. But do you know who rescued her? It is +quite a romance. Nicholas Rostov! She was surrounded, and they +wanted to kill her and had wounded some of her people. He rushed in +and saved her...." + +"Another romance," said the militia officer. "Really, this general +flight has been arranged to get all the old maids married off. Catiche +is one and Princess Bolkonskaya another." + +"Do you know, I really believe she is un petit peu amoureuse du +jeune homme."* + + +*"A little bit in love with the young man." + + +"Forfeit, forfeit, forfeit!" + +"But how could one say that in Russian?" + + + + + +CHAPTER XVIII + + +When Pierre returned home he was handed two of Rostopchin's +broadsheets that had been brought that day. + +The first declared that the report that Count Rostopchin had +forbidden people to leave Moscow was false; on the contrary he was +glad that ladies and tradesmen's wives were leaving the city. "There +will be less panic and less gossip," ran the broadsheet "but I will +stake my life on it that that will not enter Moscow." These words +showed Pierre clearly for the first time that the French would enter +Moscow. The second broadsheet stated that our headquarters were at +Vyazma, that Count Wittgenstein had defeated the French, but that as +many of the inhabitants of Moscow wished to be armed, weapons were +ready for them at the arsenal: sabers, pistols, and muskets which +could be had at a low price. The tone of the proclamation was not as +jocose as in the former Chigirin talks. Pierre pondered over these +broadsheets. Evidently the terrible stormcloud he had desired with the +whole strength of his soul but which yet aroused involuntary horror in +him was drawing near. + +"Shall I join the army and enter the service, or wait?" he asked +himself for the hundredth time. He took a pack of cards that lay on +the table and began to lay them out for a game of patience. + +"If this patience comes out," he said to himself after shuffling the +cards, holding them in his hand, and lifting his head, "if it comes +out, it means... what does it mean?" + +He had not decided what it should mean when he heard the voice of +the eldest princess at the door asking whether she might come in. + +"Then it will mean that I must go to the army," said Pierre to +himself. "Come in, come in!" he added to the princess. + +Only the eldest princess, the one with the stony face and long +waist, was still living in Pierre's house. The two younger ones had +both married. + +"Excuse my coming to you, cousin," she said in a reproachful and +agitated voice. "You know some decision must be come to. What is going +to happen? Everyone has left Moscow and the people are rioting. How is +it that we are staying on?" + +"On the contrary, things seem satisfactory, ma cousine," said Pierre +in the bantering tone he habitually adopted toward her, always feeling +uncomfortable in the role of her benefactor. + +"Satisfactory, indeed! Very satisfactory! Barbara Ivanovna told me +today how our troops are distinguishing themselves. It certainly +does them credit! And the people too are quite mutinous--they no +longer obey, even my maid has taken to being rude. At this rate they +will soon begin beating us. One can't walk in the streets. But, +above all, the French will be here any day now, so what are we waiting +for? I ask just one thing of you, cousin," she went on, "arrange for +me to be taken to Petersburg. Whatever I may be, I can't live under +Bonaparte's rule." + +"Oh, come, ma cousine! Where do you get your information from? On +the contrary..." + +"I won't submit to your Napoleon! Others may if they please.... If +you don't want to do this..." + +"But I will, I'll give the order at once." + +The princess was apparently vexed at not having anyone to be angry +with. Muttering to herself, she sat down on a chair. + +"But you have been misinformed," said Pierre. "Everything is quiet +in the city and there is not the slightest danger. See! I've just been +reading..." He showed her the broadsheet. "Count Rostopchin writes +that he will stake his life on it that the enemy will not enter +Moscow." + +"Oh, that count of yours!" said the princess malevolently. "He is +a hypocrite, a rascal who has himself roused the people to riot. +Didn't he write in those idiotic broadsheets that anyone, 'whoever +it might be, should be dragged to the lockup by his hair'? (How +silly!) 'And honor and glory to whoever captures him,' he says. This +is what his cajolery has brought us to! Barbara Ivanovna told me the +mob near killed her because she said something in French." + +"Oh, but it's so... You take everything so to heart," said Pierre, +and began laying out his cards for patience. + +Although that patience did come out, Pierre did not join the army, +but remained in deserted Moscow ever in the same state of agitation, +irresolution, and alarm, yet at the same time joyfully expecting +something terrible. + +Next day toward evening the princess set off, and Pierre's head +steward came to inform him that the money needed for the equipment +of his regiment could not be found without selling one of the estates. +In general the head steward made out to Pierre that his project of +raising a regiment would ruin him. Pierre listened to him, scarcely +able to repress a smile. + +"Well then, sell it," said he. "What's to be done? I can't draw back +now!" + +The worse everything became, especially his own affairs, the +better was Pierre pleased and the more evident was it that the +catastrophe he expected was approaching. Hardly anyone he knew was +left in town. Julie had gone, and so had Princess Mary. Of his +intimate friends only the Rostovs remained, but he did not go to see +them. + +To distract his thoughts he drove that day to the village of +Vorontsovo to see the great balloon Leppich was constructing to +destroy the foe, and a trial balloon that was to go up next day. The +balloon was not yet ready, but Pierre learned that it was being +constructed by the Emperor's desire. The Emperor had written to +Count Rostopchin as follows: + + +As soon as Leppich is ready, get together a crew of reliable and +intelligent men for his car and send a courier to General Kutuzov to +let him know. I have informed him of the matter. + +Please impress upon Leppich to be very careful where he descends for +the first time, that he may not make a mistake and fall into the +enemy's hands. It is essential for him to combine his movements with +those of the commander in chief. + + +On his way home from Vorontsovo, as he was passing the Bolotnoe +Place Pierre, seeing a large crowd round the Lobnoe Place, stopped and +got out of his trap. A French cook accused of being a spy was being +flogged. The flogging was only just over, and the executioner was +releasing from the flogging bench a stout man with red whiskers, in +blue stockings and a green jacket, who was moaning piteously. +Another criminal, thin and pale, stood near. Judging by their faces +they were both Frenchmen. With a frightened and suffering look +resembling that on the thin Frenchman's face, Pierre pushed his way in +through the crowd. + +"What is it? Who is it? What is it for?" he kept asking. + +But the attention of the crowd--officials, burghers, shopkeepers, +peasants, and women in cloaks and in pelisses--was so eagerly centered +on what was passing in Lobnoe Place that no one answered him. The +stout man rose, frowned, shrugged his shoulders, and evidently +trying to appear firm began to pull on his jacket without looking +about him, but suddenly his lips trembled and he began to cry, in +the way full-blooded grown-up men cry, though angry with himself for +doing so. In the crowd people began talking loudly, to stifle their +feelings of pity as it seemed to Pierre. + +"He's cook to some prince." + +"Eh, mounseer, Russian sauce seems to be sour to a Frenchman... sets +his teeth on edge!" said a wrinkled clerk who was standing behind +Pierre, when the Frenchman began to cry. + +The clerk glanced round, evidently hoping that his joke would be +appreciated. Some people began to laugh, others continued to watch +in dismay the executioner who was undressing the other man. + +Pierre choked, his face puckered, and he turned hastily away, went +back to his trap muttering something to himself as he went, and took +his seat. As they drove along he shuddered and exclaimed several times +so audibly that the coachman asked him: + +"What is your pleasure?" + +"Where are you going?" shouted Pierre to the man, who was driving to +Lubyanka Street. + +"To the Governor's, as you ordered," answered the coachman. + +"Fool! Idiot!" shouted Pierre, abusing his coachman--a thing he +rarely did. "Home, I told you! And drive faster, blockhead!" "I must +get away this very day," he murmured to himself. + +At the sight of the tortured Frenchman and the crowd surrounding the +Lobnoe Place, Pierre had so definitely made up his mind that he +could no longer remain in Moscow and would leave for the army that +very day that it seemed to him that either he had told the coachman +this or that the man ought to have known it for himself. + +On reaching home Pierre gave orders to Evstafey--his head coachman +who knew everything, could do anything, and was known to all Moscow- +that he would leave that night for the army at Mozhaysk, and that +his saddle horses should be sent there. This could not all be arranged +that day, so on Evstafey's representation Pierre had to put off his +departure till next day to allow time for the relay horses to be +sent on in advance. + +On the twenty-fourth the weather cleared up after a spell of rain, +and after dinner Pierre left Moscow. When changing horses that night +in Perkhushkovo, he learned that there had been a great battle that +evening. (This was the battle of Shevardino.) He was told that there +in Perkhushkovo the earth trembled from the firing, but nobody could +answer his questions as to who had won. At dawn next day Pierre was +approaching Mozhaysk. + +Every house in Mozhaysk had soldiers quartered in it, and at the +hostel where Pierre was met by his groom and coachman there was no +room to be had. It was full of officers. + +Everywhere in Mozhaysk and beyond it, troops were stationed or on +the march. Cossacks, foot and horse soldiers, wagons, caissons, and +cannon were everywhere. Pierre pushed forward as fast as he could, and +the farther he left Moscow behind and the deeper he plunged into +that sea of troops the more was he overcome by restless agitation +and a new and joyful feeling he had not experienced before. It was a +feeling akin to what he had felt at the Sloboda Palace during the +Emperor's visit--a sense of the necessity of undertaking something and +sacrificing something. He now experienced a glad consciousness that +everything that constitutes men's happiness--the comforts of life, +wealth, even life itself--is rubbish it is pleasant to throw away, +compared with something... With what? Pierre could not say, and he did +not try to determine for whom and for what he felt such particular +delight in sacrificing everything. He was not occupied with the +question of what to sacrifice for; the fact of sacrificing in itself +afforded him a new and joyous sensation. + + + + + +CHAPTER XIX + + +On the twenty-fourth of August the battle of the Shevardino +Redoubt was fought, on the twenty-fifth not a shot was fired by either +side, and on the twenty-sixth the battle of Borodino itself took +place. + +Why and how were the battles of Shevardino and Borodino given and +accepted? Why was the battle of Borodino fought? There was not the +least sense in it for either the French or the Russians. Its immediate +result for the Russians was, and was bound to be, that we were brought +nearer to the destruction of Moscow--which we feared more than +anything in the world; and for the French its immediate result was +that they were brought nearer to the destruction of their whole +army--which they feared more than anything in the world. What the +result must be was quite obvious, and yet Napoleon offered and Kutuzov +accepted that battle. + +If the commanders had been guided by reason, it would seem that it +must have been obvious to Napoleon that by advancing thirteen +hundred miles and giving battle with a probability of losing a quarter +of his army, he was advancing to certain destruction, and it must have +been equally clear to Kutuzov that by accepting battle and risking the +loss of a quarter of his army he would certainly lose Moscow. For +Kutuzov this was mathematically clear, as it is that if when playing +draughts I have one man less and go on exchanging, I shall certainly +lose, and therefore should not exchange. When my opponent has +sixteen men and I have fourteen, I am only one eighth weaker than +he, but when I have exchanged thirteen more men he will be three times +as strong as I am. + +Before the battle of Borodino our strength in proportion to the +French was about as five to six, but after that battle it was little +more than one to two: previously we had a hundred thousand against a +hundred and twenty thousand; afterwards little more than fifty +thousand against a hundred thousand. Yet the shrewd and experienced +Kutuzov accepted the battle, while Napoleon, who was said to be a +commander of genius, gave it, losing a quarter of his army and +lengthening his lines of communication still more. If it is said +that he expected to end the campaign by occupying Moscow as he had +ended a previous campaign by occupying Vienna, there is much +evidence to the contrary. Napoleon's historians themselves tell us +that from Smolensk onwards he wished to stop, knew the danger of his +extended position, and knew that the occupation of Moscow would not be +the end of the campaign, for he had seen at Smolensk the state in +which Russian towns were left to him, and had not received a single +reply to his repeated announcements of his wish to negotiate. + +In giving and accepting battle at Borodino, Kutuzov acted +involuntarily and irrationally. But later on, to fit what had +occurred, the historians provided cunningly devised evidence of the +foresight and genius the generals who, of all the blind tools of +history were the most enslaved and involuntary. + +The ancients have left us model heroic poems in which the heroes +furnish the whole interest of the story, and we are still unable to +accustom ourselves to the fact that for our epoch histories of that +kind are meaningless. + +On the other question, how the battle of Borodino and the +preceding battle of Shevardino were fought, there also exists a +definite and well-known, but quite false, conception. All the +historians describe the affair as follows: + +The Russian army, they say, in its retreat from Smolensk sought +out for itself the best position for a general engagement and found +such a position at Borodino. + +The Russians, they say, fortified this position in advance on the +left of the highroad (from Moscow to Smolensk) and almost at a right +angle to it, from Borodino to Utitsa, at the very place where the +battle was fought. + +In front of this position, they say, a fortified outpost was set +up on the Shevardino mound to observe the enemy. On the twenty-fourth, +we are told, Napoleon attacked this advanced post and took it, and, on +the twenty-sixth, attacked the whole Russian army, which was in +position on the field of Borodino. + +So the histories say, and it is all quite wrong, as anyone who cares +to look into the matter can easily convince himself. + +The Russians did not seek out the best position but, on the +contrary, during the retreat passed many positions better than +Borodino. They did not stop at any one of these positions because +Kutuzov did not wish to occupy a position he had not himself chosen, +because the popular demand for a battle had not yet expressed itself +strongly enough, and because Miloradovich had not yet arrived with the +militia, and for many other reasons. The fact is that other +positions they had passed were stronger, and that the position at +Borodino (the one where the battle was fought), far from being strong, +was no more a position than any other spot one might find in the +Russian Empire by sticking a pin into the map at hazard. + +Not only did the Russians not fortify the position on the field of +Borodino to the left of, and at a right angle to, the highroad (that +is, the position on which the battle took place), but never till the +twenty-fifth of August, 1812, did they think that a battle might be +fought there. This was shown first by the fact that there were no +entrenchments there by the twenty fifth and that those begun on the +twenty-fifth and twenty-sixth were not completed, and secondly, by the +position of the Shevardino Redoubt. That redoubt was quite senseless +in front of the position where the battle was accepted. Why was it +more strongly fortified than any other post? And why were all +efforts exhausted and six thousand men sacrificed to defend it till +late at night on the twenty-fourth? A Cossack patrol would have +sufficed to observe the enemy. Thirdly, as proof that the position +on which the battle was fought had not been foreseen and that the +Shevardino Redoubt was not an advanced post of that position, we +have the fact that up to the twenty-fifth, Barclay de Tolly and +Bagration were convinced that the Shevardino Redoubt was the left +flank of the position, and that Kutuzov himself in his report, written +in hot haste after the battle, speaks of the Shevardino Redoubt as the +left flank of the position. It was much later, when reports on the +battle of Borodino were written at leisure, that the incorrect and +extraordinary statement was invented (probably to justify the mistakes +of a commander in chief who had to be represented as infallible) +that the Shevardino Redoubt was an advanced post--whereas in reality +it was simply a fortified point on the left flank--and that the battle +of Borodino was fought by us on an entrenched position previously +selected, where as it was fought on a quite unexpected spot which +was almost unentrenched. + +The case was evidently this: a position was selected along the river +Kolocha--which crosses the highroad not at a right angle but at an +acute angle--so that the left flank was at Shevardino, the right flank +near the village of Novoe, and the center at Borodino at the +confluence of the rivers Kolocha and Voyna. + +To anyone who looks at the field of Borodino without thinking of how +the battle was actually fought, this position, protected by the +river Kolocha, presents itself as obvious for an army whose object was +to prevent an enemy from advancing along the Smolensk road to Moscow. + +Napoleon, riding to Valuevo on the twenty-fourth, did not see (as +the history books say he did) the position of the Russians from Utitsa +to Borodino (he could not have seen that position because it did not +exist), nor did he see an advanced post of the Russian army, but while +pursuing the Russian rearguard he came upon the left flank of the +Russian position--at the Shevardino Redoubt--and unexpectedly for +the Russians moved his army across the Kolocha. And the Russians, +not having time to begin a general engagement, withdrew their left +wing from the position they had intended to occupy and took up a new +position which had not been foreseen and was not fortified. By +crossing to the other side of the Kolocha to the left of the highroad, +Napoleon shifted the whole forthcoming battle from right to left +(looking from the Russian side) and transferred it to the plain +between Utitsa, Semenovsk, and Borodino--a plain no more +advantageous as a position than any other plain in Russia--and there +the whole battle of the twenty-sixth of August took place. + +Had Napoleon not ridden out on the evening of the twenty-fourth to +the Kolocha, and had he not then ordered an immediate attack on the +redoubt but had begun the attack next morning, no one would have +doubted that the Shevardino Redoubt was the left flank of our and +the battle would have taken place where we expected it. In that case +we should probably have defended the Shevardino Redoubt--our left +flank--still more obstinately. We should have attacked Napoleon in the +center or on the right, and the engagement would have taken place on +the twenty-fifth, in the position we intended and had fortified. But +as the attack on our left flank took place in the evening after the +retreat of our rear guard (that is, immediately after the fight at +Gridneva), and as the Russian commanders did not wish, or were not +in time, to begin a general engagement then on the evening of the +twenty-fourth, the first and chief action of the battle of Borodino +was already lost on the twenty-fourth, and obviously led to the loss +of the one fought on the twenty-sixth. + +After the loss of the Shevardino Redoubt, we found ourselves on +the morning of the twenty-fifth without a position for our left flank, +and were forced to bend it back and hastily entrench it where it +chanced to be. + +Not only was the Russian army on the twenty-sixth defended by +weak, unfinished entrenchments, but the disadvantage of that +position was increased by the fact that the Russian commanders--not +having fully realized what had happened, namely the loss of our +position on the left flank and the shifting of the whole field of +the forthcoming battle from right to left--maintained their extended +position from the village of Novoe to Utitsa, and consequently had +to move their forces from right to left during the battle. So it +happened that throughout the whole battle the Russians opposed the +entire French army launched against our left flank with but half as +many men. (Poniatowski's action against Utitsa, and Uvarov's on the +right flank against the French, were actions distinct from the main +course of the battle.) So the battle of Borodino did not take place at +all as (in an effort to conceal our commanders' mistakes even at the +cost of diminishing the glory due to the Russian army and people) it +has been described. The battle of Borodino was not fought on a +chosen and entrenched position with forces only slightly weaker than +those of the enemy, but, as a result of the loss of the Shevardino +Redoubt, the Russians fought the battle of Borodino on an open and +almost unentrenched position, with forces only half as numerous as the +French; that is to say, under conditions in which it was not merely +unthinkable to fight for ten hours and secure an indecisive result, +but unthinkable to keep an army even from complete disintegration +and flight. + + + + + +CHAPTER XX + + +On the morning of the twenty-fifth Pierre was leaving Mozhaysk. At +the descent of the high steep hill, down which a winding road led +out of the town past the cathedral on the right, where a service was +being held and the bells were ringing, Pierre got out of his vehicle +and proceeded on foot. Behind him a cavalry regiment was coming down +the hill preceded by its singers. Coming up toward him was a train +of carts carrying men who had been wounded in the engagement the day +before. The peasant drivers, shouting and lashing their horses, kept +crossing from side to side. The carts, in each of which three or +four wounded soldiers were lying or sitting, jolted over the stones +that had been thrown on the steep incline to make it something like +a road. The wounded, bandaged with rags, with pale cheeks, +compressed lips, and knitted brows, held on to the sides of the +carts as they were jolted against one another. Almost all of them +stared with naive, childlike curiosity at Pierre's white hat and green +swallow-tail coat. + +Pierre's coachman shouted angrily at the convoy of wounded to keep +to one side of the road. The cavalry regiment, as it descended the +hill with its singers, surrounded Pierre's carriage and blocked the +road. Pierre stopped, being pressed against the side of the cutting in +which the road ran. The sunshine from behind the hill did not +penetrate into the cutting and there it was cold and damp, but above +Pierre's head was the bright August sunshine and the bells sounded +merrily. One of the carts with wounded stopped by the side of the road +close to Pierre. The driver in his bast shoes ran panting up to it, +placed a stone under one of its tireless hind wheels, and began +arranging the breech-band on his little horse. + +One of the wounded, an old soldier with a bandaged arm who was +following the cart on foot, caught hold of it with his sound hand +and turned to look at Pierre. + +"I say, fellow countryman! Will they set us down here or take us +on to Moscow?" he asked. + +Pierre was so deep in thought that he did not hear the question. +He was looking now at the cavalry regiment that had met the convoy +of wounded, now at the cart by which he was standing, in which two +wounded men were sitting and one was lying. One of those sitting up in +the cart had probably been wounded in the cheek. His whole head was +wrapped in rags and one cheek was swollen to the size of a baby's +head. His nose and mouth were twisted to one side. This soldier was +looking at the cathedral and crossing himself. Another, a young lad, a +fair-haired recruit as white as though there was no blood in his +thin face, looked at Pierre kindly, with a fixed smile. The third +lay prone so that his face was not visible. The cavalry singers were +passing close by: + + Ah lost, quite lost... is my head so keen, + Living in a foreign land. + +they sang their soldiers' dance song. + +As if responding to them but with a different sort of merriment, the +metallic sound of the bells reverberated high above and the hot rays +of the sun bathed the top of the opposite slope with yet another +sort of merriment. But beneath the slope, by the cart with the wounded +near the panting little nag where Pierre stood, it was damp, somber, +and sad. + +The soldier with the swollen cheek looked angrily at the cavalry +singers. + +"Oh, the coxcombs!" he muttered reproachfully. + +"It's not the soldiers only, but I've seen peasants today, too.... +The peasants--even they have to go," said the soldier behind the cart, +addressing Pierre with a sad smile. "No distinctions made nowadays.... +They want the whole nation to fall on them--in a word, it's Moscow! +They want to make an end of it." + +In spite of the obscurity of the soldier's words Pierre understood +what he wanted to say and nodded approval. + +The road was clear again; Pierre descended the hill and drove on. + +He kept looking to either side of the road for familiar faces, but +only saw everywhere the unfamiliar faces of various military men of +different branches of the service, who all looked with astonishment at +his white hat and green tail coat. + +Having gone nearly three miles he at last met an acquaintance and +eagerly addressed him. This was one of the head army doctors. He was +driving toward Pierre in a covered gig, sitting beside a young +surgeon, and on recognizing Pierre he told the Cossack who occupied +the driver's seat to pull up. + +"Count! Your excellency, how come you to be here?" asked the doctor. + +"Well, you know, I wanted to see..." + +"Yes, yes, there will be something to see...." + +Pierre got out and talked to the doctor, explaining his intention of +taking part in a battle. + +The doctor advised him to apply direct to Kutuzov. + +"Why should you be God knows where out of sight, during the battle?" +he said, exchanging glances with his young companion. "Anyhow his +Serene Highness knows you and will receive you graciously. That's what +you must do." + +The doctor seemed tired and in a hurry. + +"You think so?... Ah, I also wanted to ask you where our position is +exactly?" said Pierre. + +"The position?" repeated the doctor. "Well, that's not my line. +Drive past Tatarinova, a lot of digging is going on there. Go up the +hillock and you'll see." + +"Can one see from there?... If you would..." + +But the doctor interrupted him and moved toward his gig. + +"I would go with you but on my honor I'm up to here"--and he pointed +to his throat. "I'm galloping to the commander of the corps. How do +matters stand?... You know, Count, there'll be a battle tomorrow. +Out of an army of a hundred thousand we must expect at least twenty +thousand wounded, and we haven't stretchers, or bunks, or dressers, or +doctors enough for six thousand. We have ten thousand carts, but we +need other things as well--we must manage as best we can!" + +The strange thought that of the thousands of men, young and old, who +had stared with merry surprise at his hat (perhaps the very men he had +noticed), twenty thousand were inevitably doomed to wounds and death +amazed Pierre. + +"They may die tomorrow; why are they thinking of anything but +death?" And by some latent sequence of thought the descent of the +Mozhaysk hill, the carts with the wounded, the ringing bells, the +slanting rays of the sun, and the songs of the cavalrymen vividly +recurred to his mind. + +"The cavalry ride to battle and meet the wounded and do not for a +moment think of what awaits them, but pass by, winking at the wounded. +Yet from among these men twenty thousand are doomed to die, and they +wonder at my hat! Strange!" thought Pierre, continuing his way to +Tatarinova. + +In front of a landowner's house to the left of the road stood +carriages, wagons, and crowds of orderlies and sentinels. The +commander in chief was putting up there, but just when Pierre +arrived he was not in and hardly any of the staff were there--they had +gone to the church service. Pierre drove on toward Gorki. + +When he had ascended the hill and reached the little village street, +he saw for the first time peasant militiamen in their white shirts and +with crosses on their caps, who, talking and laughing loudly, animated +and perspiring, were at work on a huge knoll overgrown with grass to +the right of the road. + +Some of them were digging, others were wheeling barrowloads of earth +along planks, while others stood about doing nothing. + +Two officers were standing on the knoll, directing the men. On +seeing these peasants, who were evidently still amused by the +novelty of their position as soldiers, Pierre once more thought of the +wounded men at Mozhaysk and understood what the soldier had meant when +he said: "They want the whole nation to fall on them." The sight of +these bearded peasants at work on the battlefield, with their queer, +clumsy boots and perspiring necks, and their shirts opening from the +left toward the middle, unfastened, exposing their sunburned +collarbones, impressed Pierre more strongly with the solemnity and +importance of the moment than anything he had yet seen or heard. + + + + + +CHAPTER XXI + + +Pierre stepped out of his carriage and, passing the toiling +militiamen, ascended the knoll from which, according to the doctor, +the battlefield could be seen. + +It was about eleven o'clock. The sun shone somewhat to the left +and behind him and brightly lit up the enormous panorama which, rising +like an amphitheater, extended before him in the clear rarefied +atmosphere. + +From above on the left, bisecting that amphitheater, wound the +Smolensk highroad, passing through a village with a white church +some five hundred paces in front of the knoll and below it. This was +Borodino. Below the village the road crossed the river by a bridge +and, winding down and up, rose higher and higher to the village of +Valuevo visible about four miles away, where Napoleon was then +stationed. Beyond Valuevo the road disappeared into a yellowing forest +on the horizon. Far in the distance in that birch and fir forest to +the right of the road, the cross and belfry of the Kolocha Monastery +gleamed in the sun. Here and there over the whole of that blue +expanse, to right and left of the forest and the road, smoking +campfires could be seen and indefinite masses of troops--ours and +the enemy's. The ground to the right--along the course of the +Kolocha and Moskva rivers--was broken and hilly. Between the hollows +the villages of Bezubova and Zakharino showed in the distance. On +the left the ground was more level; there were fields of grain, and +the smoking ruins of Semenovsk, which had been burned down, could be +seen. + +All that Pierre saw was so indefinite that neither the left nor +the right side of the field fully satisfied his expectations. +Nowhere could he see the battlefield he had expected to find, but only +fields, meadows, troops, woods, the smoke of campfires, villages, +mounds, and streams; and try as he would he could descry no military +"position" in this place which teemed with life, nor could he even +distinguish our troops from the enemy's. + +"I must ask someone who knows," he thought, and addressed an officer +who was looking with curiosity at his huge unmilitary figure. + +"May I ask you," said Pierre, "what village that is in front?" + +"Burdino, isn't it?" said the officer, turning to his companion. + +"Borodino," the other corrected him. + +The officer, evidently glad of an opportunity for a talk, moved up +to Pierre. + +"Are those our men there?" Pierre inquired. + +"Yes, and there, further on, are the French," said the officer. +"There they are, there... you can see them." + +"Where? Where?" asked Pierre. + +"One can see them with the naked eye... Why, there!" + +The officer pointed with his hand to the smoke visible on the left +beyond the river, and the same stern and serious expression that +Pierre had noticed on many of the faces he had met came into his face. + +"Ah, those are the French! And over there?..." Pierre pointed to a +knoll on the left, near which some troops could be seen. + +"Those are ours." + +"Ah, ours! And there?..." Pierre pointed to another knoll in the +distance with a big tree on it, near a village that lay in a hollow +where also some campfires were smoking and something black was +visible. + +"That's his again," said the officer. (It was the Shevardino +Redoubt.) "It was ours yesterday, but now it is his." + +"Then how about our position?" + +"Our position?" replied the officer with a smile of satisfaction. "I +can tell you quite clearly, because I constructed nearly all our +entrenchments. There, you see? There's our center, at Borodino, just +there," and he pointed to the village in front of them with the +white church. "That's where one crosses the Kolocha. You see down +there where the rows of hay are lying in the hollow, there's the +bridge. That's our center. Our right flank is over there"--he +pointed sharply to the right, far away in the broken ground--"That's +where the Moskva River is, and we have thrown up three redoubts there, +very strong ones. The left flank..." here the officer paused. "Well, +you see, that's difficult to explain.... Yesterday our left flank +was there at Shevardino, you see, where the oak is, but now we have +withdrawn our left wing--now it is over there, do you see that village +and the smoke? That's Semenovsk, yes, there," he pointed to +Raevski's knoll. "But the battle will hardly be there. His having +moved his troops there is only a ruse; he will probably pass round +to the right of the Moskva. But wherever it may be, many a man will be +missing tomorrow!" he remarked. + +An elderly sergeant who had approached the officer while he was +giving these explanations had waited in silence for him to finish +speaking, but at this point, evidently not liking the officer's +remark, interrupted him. + +"Gabions must be sent for," said he sternly. + +The officer appeared abashed, as though he understood that one might +think of how many men would be missing tomorrow but ought not to speak +to speak of it. + +"Well, send number three company again," the officer replied +hurriedly. + +"And you, are you one of the doctors?" + +"No, I've come on my own," answered Pierre, and he went down the +hill again, passing the militiamen. + +"Oh, those damned fellows!" muttered the officer who followed him, +holding his nose as he ran past the men at work. + +"There they are... bringing her, coming... There they are... They'll +be here in a minute..." voices were suddenly heard saying; and +officers, soldiers, and militiamen began running forward along the +road. + +A church procession was coming up the hill from Borodino. First +along the dusty road came the infantry in ranks, bareheaded and with +arms reversed. From behind them came the sound of church singing. + +Soldiers and militiamen ran bareheaded past Pierre toward the +procession. + +"They are bringing her, our Protectress!... The Iberian Mother of +God!" someone cried. + +"The Smolensk Mother of God," another corrected him. + +The militiamen, both those who had been in the village and those who +had been at work on the battery, threw down their spades and ran to +meet the church procession. Following the battalion that marched along +the dusty road came priests in their vestments--one little old man +in a hood with attendants and singers. Behind them soldiers and +officers bore a large, dark-faced icon with an embossed metal cover. +This was the icon that had been brought from and had since accompanied +the army. Behind, before, and on both sides, crowds of militiamen with +bared heads walked, ran, and bowed to the ground. + +At the summit of the hill they stopped with the icon; the men who +had been holding it up by the linen bands attached to it were relieved +by others, the chanters relit their censers, and service began. The +hot rays of the sun beat down vertically and a fresh soft wind +played with the hair of the bared heads and with the ribbons +decorating the icon. The singing did not sound loud under the open +sky. An immense crowd of bareheaded officers, soldiers, and militiamen +surrounded the icon. Behind the priest and a chanter stood the +notabilities on a spot reserved for them. A bald general with +general with a St. George's Cross on his neck stood just behind the +priest's back, and without crossing himself (he was evidently a +German) patiently awaited the end of the service, which he +considered it necessary to hear to the end, probably to arouse the +patriotism of the Russian people. Another general stood in a martial +pose, crossing himself by shaking his hand in front of his chest while +looking about him. Standing among the crowd of peasants, Pierre +recognized several acquaintances among these notables, but did not +look at them--his whole attention was absorbed in watching the serious +expression on the faces of the crowd of soldiers and militiamen who +were all gazing eagerly at the icon. As soon as the tired chanters, +who were singing the service for the twentieth time that day, began +lazily and mechanically to sing: "Save from calamity Thy servants, O +Mother of God," and the priest and deacon chimed in: "For to Thee +under God we all flee as to an inviolable bulwark and protection," +there again kindled in all those faces the same expression of +consciousness of the solemnity of the impending moment that Pierre had +seen on the faces at the foot of the hill at Mozhaysk and +momentarily on many and many faces he had met that morning; and +heads were bowed more frequently and hair tossed back, and sighs and +the sound men made as they crossed themselves were heard. + +The crowd round the icon suddenly parted and pressed against Pierre. +Someone, a very important personage judging by the haste with which +way was made for him, was approaching the icon. + +It was Kutuzov, who had been riding round the position and on his +way back to Tatarinova had stopped where the service was being held. +Pierre recognized him at once by his peculiar figure, which +distinguished him from everybody else. + +With a long overcoat on his his exceedingly stout, +round-shouldered body, with uncovered white head and puffy face +showing the white ball of the eye he had lost, Kutuzov walked with +plunging, swaying gait into the crowd and stopped behind the priest. +He crossed himself with an accustomed movement, bent till he touched +the ground with his hand, and bowed his white head with a deep sigh. +Behind Kutuzov was Bennigsen and the suite. Despite the presence of +the commander in chief, who attracted the attention of all the +superior officers, the militiamen and soldiers continued their prayers +without looking at him. + +When the service was over, Kutuzov stepped up to the icon, sank +heavily to his knees, bowed to the ground, and for a long time tried +vainly to rise, but could not do so on account of his weakness and +weight. His white head twitched with the effort. At last he rose, +kissed the icon as a child does with naively pouting lips, and again +bowed till he touched the ground with his hand. The other generals +followed his example, then the officers, and after them with excited +faces, pressing on one another, crowding, panting, and pushing, +scrambled the soldiers and militiamen. + + + + + +CHAPTER XXII + + +Staggering amid the crush, Pierre looked about him. + +"Count Peter Kirilovich! How did you get here?" said a voice. + +Pierre looked round. Boris Drubetskoy, brushing his knees with his +hand (he had probably soiled them when he, too, had knelt before the +icon), came up to him smiling. Boris was elegantly dressed, with a +slightly martial touch appropriate to a campaign. He wore a long +coat and like Kutuzov had a whip slung across his shoulder. + +Meanwhile Kutuzov had reached the village and seated himself in +the shade of the nearest house, on a bench which one Cossack had run +to fetch and another had hastily covered with a rug. An immense and +brilliant suite surrounded him. + +The icon was carried further, accompanied by the throng. Pierre +stopped some thirty paces from Kutuzov, talking to Boris. + +He explained his wish to be present at the battle and to see the +position. + +"This is what you must do," said Boris. "I will do the honors of the +camp to you. You will see everything best from where Count Bennigsen +will be. I am in attendance on him, you know; I'll mention it to +him. But if you want to ride round the position, come along with us. +We are just going to the left flank. Then when we get back, do spend +the night with me and we'll arrange a game of cards. Of course you +know Dmitri Sergeevich? Those are his quarters," and he pointed to the +third house in the village of Gorki. + +"But I should like to see the right flank. They say it's very +strong," said Pierre. "I should like to start from the Moskva River +and ride round the whole position." + +"Well, you can do that later, but the chief thing is the left +flank." + +"Yes, yes. But where is Prince Bolkonski's regiment? Can you point +it out to me?" + +"Prince Andrew's? We shall pass it and I'll take you to him." + +"What about the left flank?" asked Pierre + +"To tell you the truth, between ourselves, God only knows what state +our left flank is in," said Boris confidentially lowering his voice. +"It is not at all what Count Bennigsen intended. He meant to fortify +that knoll quite differently, but..." Boris shrugged his shoulders, +"his Serene Highness would not have it, or someone persuaded him. +You see..." but Boris did not finish, for at that moment Kaysarov, +Kutuzov's adjutant, came up to Pierre. "Ah, Kaysarov!" said Boris, +addressing him with an unembarrassed smile, "I was just trying to +explain our position to the count. It is amazing how his Serene +Highness could so the intentions of the French!" + +"You mean the left flank?" asked Kaysarov. + + +"Yes, exactly; the left flank is now extremely strong." + +Though Kutuzov had dismissed all unnecessary men from the staff, +Boris had contrived to remain at headquarters after the changes. He +had established himself with Count Bennigsen, who, like all on whom +Boris had been in attendance, considered young Prince Drubetskoy an +invaluable man. + +In the higher command there were two sharply defined parties: +Kutuzov's party and that of Bennigsen, the chief of staff. Boris +belonged to the latter and no one else, while showing servile +respect to Kutuzov, could so create an impression that the old +fellow was not much good and that Bennigsen managed everything. Now +the decisive moment of battle had come when Kutuzov would be destroyed +and the power pass to Bennigsen, or even if Kutuzov won the battle +it would be felt that everything was done by Bennigsen. In any case +many great rewards would have to be given for tomorrow's action, and +new men would come to the front. So Boris was full of nervous vivacity +all day. + +After Kaysarov, others whom Pierre knew came up to him, and he had +not time to reply to all the questions about Moscow that were showered +upon him, or to listen to all that was told him. The faces all +expressed animation and apprehension, but it seemed to Pierre that the +cause of the excitement shown in some of these faces lay chiefly in +questions of personal success; his mind, however, was occupied by +the different expression he saw on other faces--an expression that +spoke not of personal matters but of the universal questions of life +and death. Kutuzov noticed Pierre's figure and the group gathered +round him. + +"Call him to me," said Kutuzov. + +An adjutant told Pierre of his Serene Highness' wish, and Pierre +went toward Kutuzov's bench. But a militiaman got there before him. It +was Dolokhov. + +"How did that fellow get here?" asked Pierre. + +"He's a creature that wriggles in anywhere!" was the answer. "He has +been degraded, you know. Now he wants to bob up again. He's been +proposing some scheme or other and has crawled into the enemy's picket +line at night.... He's a brave fellow." + +Pierre took off his hat and bowed respectfully to Kutuzov. + +"I concluded that if I reported to your Serene Highness you might +send me away or say that you knew what I was reporting, but then I +shouldn't lose anything..." Dolokhov was saying. + +"Yes, yes." + +"But if I were right, I should be rendering a service to my +Fatherland for which I am ready to die." + +"Yes, yes." + +"And should your Serene Highness require a man who will not spare +his skin, please think of me.... Perhaps I may prove useful to your +Serene Highness." + +"Yes... Yes..." Kutuzov repeated, his laughing eye narrowing more +and more as he looked at Pierre. + +Just then Boris, with his courtierlike adroitness, stepped up to +Pierre's side near Kutuzov and in a most natural manner, without +raising his voice, said to Pierre, as though continuing an interrupted +conversation: + +"The militia have put on clean white shirts to be ready to die. What +heroism, Count!" + +Boris evidently said this to Pierre in order to be overheard by +his Serene Highness. He knew Kutuzov's attention would be caught by +those words, and so it was. + +"What are you saying about the militia?" he asked Boris. + +"Preparing for tomorrow, your Serene Highness--for death--they +have put on clean shirts." + +"Ah... a wonderful, a matchless people!" said Kutuzov; and he closed +his eyes and swayed his head. "A matchless people!" he repeated with a +sigh. + +"So you want to smell gunpowder?" he said to Pierre. "Yes, it's a +pleasant smell. I have the honor to be one of your wife's adorers. +Is she well? My quarters are at your service." + +And as often happens with old people, Kutuzov began looking about +absent-mindedly as if forgetting all he wanted to say or do. + +Then, evidently remembering what he wanted, he beckoned to Andrew +Kaysarov, his adjutant's brother. + +"Those verses... those verses of Marin's... how do they go, eh? +Those he wrote about Gerakov: 'Lectures for the corps inditing'... +Recite them, recite them!" said he, evidently preparing to laugh. + +Kaysarov recited.... Kutuzov smilingly nodded his head to the rhythm +of the verses. + +When Pierre had left Kutuzov, Dolokhov came up to him and took his +hand. + +"I am very glad to meet you here, Count," he said aloud, +regardless of the presence of strangers and in a particularly resolute +and solemn tone. "On the eve of a day when God alone knows who of us +is fated to survive, I am glad of this opportunity to tell you that +I regret the misunderstandings that occurred between us and should +wish you not to have any ill feeling for me. I beg you to forgive me." + +Pierre looked at Dolokhov with a smile, not knowing what to say to +him. With tears in his eyes Dolokhov embraced Pierre and kissed him. + +Boris said a few words to his general, and Count Bennigsen turned to +Pierre and proposed that he should ride with him along the line. + +"It will interest you," said he. + +"Yes, very much," replied Pierre. + +Half an hour later Kutuzov left for Tatarinova, and Bennigsen and +his suite, with Pierre among them, set out on their ride along the +line. + + + + + +CHAPTER XXIII + + +From Gorki, Bennigsen descended the highroad to the bridge which, +when they had looked it from the hill, the officer had pointed out +as being the center of our position and where rows of fragrant +new-mown hay lay by the riverside. They rode across that bridge into +the village of Borodino and thence turned to the left, passing an +enormous number of troops and guns, and came to a high knoll where +militiamen were digging. This was the redoubt, as yet unnamed, which +afterwards became known as the Raevski Redoubt, or the Knoll +Battery, but Pierre paid no special attention to it. He did not know +that it would become more memorable to him than any other spot on +the plain of Borodino. + +They then crossed the hollow to Semenovsk, where the soldiers were +dragging away the last logs from the huts and barns. Then they rode +downhill and uphill, across a ryefield trodden and beaten down as if +by hail, following a track freshly made by the artillery over the +furrows of the plowed land, and reached some fleches* which were still +being dug. + + +*A kind of entrenchment. + + +At the fleches Bennigsen stopped and began looking at the Shevardino +Redoubt opposite, which had been ours the day before and where several +horsemen could be descried. The officers said that either Napoleon +or Murat was there, and they all gazed eagerly at this little group of +horsemen. Pierre also looked at them, trying to guess which of the +scarcely discernible figures was Napoleon. At last those mounted men +rode away from the mound and disappeared. + +Bennigsen spoke to a general who approached him, and began +explaining the whole position of our troops. Pierre listened to him, +straining each faculty to understand the essential points of the +impending battle, but was mortified to feel that his mental capacity +was inadequate for the task. He could make nothing of it. Bennigsen +stopped speaking and, noticing that Pierre was listening, suddenly +said to him: + +"I don't think this interests you?" + +"On the contrary it's very interesting!" replied Pierre not quite +truthfully. + +From the fleches they rode still farther to the left, along a road +winding through a thick, low-growing birch wood. In the middle of +the wood a brown hare with white feet sprang out and, scared by the +tramp of the many horses, grew so confused that it leaped along the +road in front of them for some time, arousing general attention and +laughter, and only when several voices shouted at it did it dart to +one side and disappear in the thicket. After going through the wood +for about a mile and a half they came out on a glade where troops of +Tuchkov's corps were stationed to defend the left flank. + +Here, at the extreme left flank, Bennigsen talked a great deal and +with much heat, and, as it seemed to Pierre, gave orders of great +military importance. In front of Tuchkov's troops was some high ground +not occupied by troops. Bennigsen loudly criticized this mistake, +saying that it was madness to leave a height which commanded the +country around unoccupied and to place troops below it. Some of the +generals expressed the same opinion. One in particular declared with +martial heat that they were put there to be slaughtered. Bennigsen +on his own authority ordered the troops to occupy the high ground. +This disposition on the left flank increased Pierre's doubt of his own +capacity to understand military matters. Listening to Bennigsen and +the generals criticizing the position of the troops behind the hill, +he quite understood them and shared their opinion, but for that very +reason he could not understand how the man who put them there behind +the hill could have made so gross and palpable a blunder. + +Pierre did not know that these troops were not, as Bennigsen +supposed, put there to defend the position, but were in a concealed +position as an ambush, that they should not be seen and might be +able to strike an approaching enemy unexpectedly. Bennigsen did not +know this and moved the troops forward according to his own ideas +without mentioning the matter to the commander in chief. + + + + + +CHAPTER XXIV + + +On that bright evening of August 25, Prince Andrew lay leaning on +his elbow in a broken-down shed in the village of Knyazkovo at the +further end of his regiment's encampment. Through a gap in the +broken wall he could see, beside the wooden fence, a row of thirty +year-old birches with their lower branches lopped off, a field on +which shocks of oats were standing, and some bushes near which rose +the smoke of campfires--the soldiers' kitchens. + +Narrow and burdensome and useless to anyone as his life now seemed +to him, Prince Andrew on the eve of battle felt agitated and irritable +as he had done seven years before at Austerlitz. + +He had received and given the orders for next day's battle and had +nothing more to do. But his thoughts--the simplest, clearest, and +therefore most terrible thoughts--would give him no peace. He knew +that tomorrow's battle would be the most terrible of all he had +taken part in, and for the first time in his life the possibility of +death presented itself to him--not in relation to any worldly matter +or with reference to its effect on others, but simply in relation to +himself, to his own soul--vividly, plainly, terribly, and almost as +a certainty. And from the height of this perception all that had +previously tormented and preoccupied him suddenly became illumined +by a cold white light without shadows, without perspective, without +distinction of outline. All life appeared to him like magic-lantern +pictures at which he had long been gazing by artificial light +through a glass. Now he suddenly saw those badly daubed pictures in +clear daylight and without a glass. "Yes, yes! There they are, those +false images that agitated, enraptured, and tormented me," said he +to himself, passing in review the principal pictures of the magic +lantern of life and regarding them now in the cold white daylight of +his clear perception of death. "There they are, those rudely painted +figures that once seemed splendid and mysterious. Glory, the good of +society, love of a woman, the Fatherland itself--how important these +pictures appeared to me, with what profound meaning they seemed to +be filled! And it is all so simple, pale, and crude in the cold +white light of this morning which I feel is dawning for me." The three +great sorrows of his life held his attention in particular: his love +for a woman, his father's death, and the French invasion which had +overrun half Russia. "Love... that little girl who seemed to me +brimming over with mystic forces! Yes, indeed, I loved her. I made +romantic plans of love and happiness with her! Oh, what a boy I +was!" he said aloud bitterly. "Ah me! I believed in some ideal love +which was to keep her faithful to me for the whole year of my absence! +Like the gentle dove in the fable she was to pine apart from me.... +But it was much simpler really.... It was all very simple and +horrible." + +"When my father built Bald Hills he thought the place was his: his +land, his air, his peasants. But Napoleon came and swept him aside, +unconscious of his existence, as he might brush a chip from his +path, and his Bald Hills and his whole life fell to pieces. Princess +Mary says it is a trial sent from above. What is the trial for, when +he is not here and will never return? He is not here! For whom then is +the trial intended? The Fatherland, the destruction of Moscow! And +tomorrow I shall be killed, perhaps not even by a Frenchman but by one +of our own men, by a soldier discharging a musket close to my ear as +one of them did yesterday, and the French will come and take me by +head and heels and fling me into a hole that I may not stink under +their noses, and new conditions of life will arise, which will seem +quite ordinary to others and about which I shall know nothing. I shall +not exist..." + +He looked at the row of birches shining in the sunshine, with +their motionless green and yellow foliage and white bark. "To die... +to be killed tomorrow... That I should not exist... That all this +should still be, but no me...." + +And the birches with their light and shade, the curly clouds, the +smoke of the campfires, and all that was around him changed and seemed +terrible and menacing. A cold shiver ran down his spine. He rose +quickly, went out of the shed, and began to walk about. + +After he had returned, voices were heard outside the shed. "Who's +that?" he cried. + +The red-nosed Captain Timokhin, formerly Dolokhov's squadron +commander, but now from lack of officers a battalion commander, + +shyly entered the shed followed by an adjutant and the regimental +paymaster. + +Prince Andrew rose hastily, listened to the business they had come +about, gave them some further instructions, and was about to dismiss +them when he heard a familiar, lisping, voice behind the shed. + +"Devil take it!" said the voice of a man stumbling over something. + +Prince Andrew looked out of the shed and saw Pierre, who had tripped +over a pole on the ground and had nearly fallen, coming his way. It +was unpleasant to Prince Andrew to meet people of his own set in +general, and Pierre especially, for he reminded him of all the painful +moments of his last visit to Moscow. + +"You? What a surprise!" said he. "What brings you here? This is +unexpected!" + +As he said this his eyes and face expressed more than coldness--they +expressed hostility, which Pierre noticed at once. He had approached +the shed full of animation, but on seeing Prince Andrew's face he felt +constrained and ill at ease. + +"I have come... simply... you know... come... it interests me," said +Pierre, who had so often that day senselessly repeated that word +"interesting." "I wish to see the battle." + +"Oh yes, and what do the Masonic brothers say about war? How would +they stop it?" said Prince Andrew sarcastically. "Well, and how's +Moscow? And my people? Have they reached Moscow at last?" he asked +seriously. + +"Yes, they have. Julie Drubetskaya told me so. I went to see them, +but missed them. They have gone to your estate near Moscow." + + + + + +CHAPTER XXV + + +The officers were about to take leave, but Prince Andrew, apparently +reluctant to be left alone with his friend, asked them to stay and +have tea. Seats were brought in and so was the tea. The officers gazed +with surprise at Pierre's huge stout figure and listened to his talk +of Moscow and the position of our army, round which he had ridden. +Prince Andrew remained silent, and his expression was so forbidding +that Pierre addressed his remarks chiefly to the good-natured +battalion commander. + +"So you understand the whole position of our troops?" Prince +Andrew interrupted him. + +"Yes--that is, how do you mean?" said Pierre. "Not being a +military man I can't say I have understood it fully, but I +understand the general position." + +"Well, then, you know more than anyone else, be it who it may," said +Prince Andrew. + +"Oh!" said Pierre, looking over his spectacles in perplexity at +Prince Andrew. "Well, and what do think of Kutuzov's appointment?" +he asked. + +"I was very glad of his appointment, that's all I know," replied +Prince Andrew. + +"And tell me your opinion of Barclay de Tolly. In Moscow they are +saying heaven knows what about him.... What do you think of him?" + +"Ask them," replied Prince Andrew, indicating the officers. + +Pierre looked at Timokhin with the condescendingly interrogative +smile with which everybody involuntarily addressed that officer. + +"We see light again, since his Serenity has been appointed, your +excellency," said Timokhin timidly, and continually turning to +glance at his colonel. + +"Why so?" asked Pierre. + +"Well, to mention only firewood and fodder, let me inform you. +Why, when we were retreating from Sventsyani we dare not touch a stick +or a wisp of hay or anything. You see, we were going away, so he would +get it all; wasn't it so, your excellency?" and again Timokhin +turned to the prince. "But we daren't. In our regiment two officers +were court-martialed for that kind of thing. But when his Serenity +took command everything became straight forward. Now we see light..." + +"Then why was it forbidden?" + +Timokhin looked about in confusion, not knowing what or how to +answer such a question. Pierre put the same question to Prince Andrew. + +"Why, so as not to lay waste the country we were abandoning to the +enemy," said Prince Andrew with venomous irony. "It is very sound: one +can't permit the land to be pillaged and accustom the troops to +marauding. At Smolensk too he judged correctly that the French might +outflank us, as they had larger forces. But he could not understand +this," cried Prince Andrew in a shrill voice that seemed to escape him +involuntarily: "he could not understand that there, for the first +time, we were fighting for Russian soil, and that there was a spirit +in the men such as I had never seen before, that we had held the +French for two days, and that that success had increased our +strength tenfold. He ordered us to retreat, and all our efforts and +losses went for nothing. He had no thought of betraying us, he tried +to do the best he could, he thought out everything, and that is why he +is unsuitable. He is unsuitable now, just because he plans out +everything very thoroughly and accurately as every German has to. +How can I explain?... Well, say your father has a German valet, and he +is a splendid valet and satisfies your father's requirements better +than you could, then it's all right to let him serve. But if your +father is mortally sick you'll send the valet away and attend to +your father with your own unpracticed, awkward hands, and will +soothe him better than a skilled man who is a stranger could. So it +has been with Barclay. While Russia was well, a foreigner could +serve her and be a splendid minister; but as soon as she is in +danger she needs one of her own kin. But in your Club they have been +making him out a traitor! They slander him as a traitor, and the +only result will be that afterwards, ashamed of their false +accusations, they will make him out a hero or a genius instead of a +traitor, and that will be still more unjust. He is an honest and +very punctilious German." + +"And they say he's a skillful commander," rejoined Pierre. + +"I don't understand what is meant by 'a skillful commander,'" +replied Prince Andrew ironically. + +"A skillful commander?" replied Pierre. "Why, one who foresees all +contingencies... and foresees the adversary's intentions." + +"But that's impossible," said Prince Andrew as if it were a matter +settled long ago. + +Pierre looked at him in surprise. + +"And yet they say that war is like a game of chess?" he remarked. + +"Yes," replied Prince Andrew, "but with this little difference, that +in chess you may think over each move as long as you please and are +not limited for time, and with this difference too, that a knight is +always stronger than a pawn, and two pawns are always stronger than +one, while in war a battalion is sometimes stronger than a division +and sometimes weaker than a company. The relative strength of bodies +of troops can never be known to anyone. Believe me," he went on, "if +things depended on arrangements made by the staff, I should be there +making arrangements, but instead of that I have the honor to serve +here in the regiment with these gentlemen, and I consider that on us +tomorrow's battle will depend and not on those others.... Success +never depends, and never will depend, on position, or equipment, or +even on numbers, and least of all on position." + +"But on what then?" + +"On the feeling that is in me and in him," he pointed to Timokhin, +"and in each soldier." + +Prince Andrew glanced at Timokhin, who looked at his commander in +alarm and bewilderment. In contrast to his former reticent taciturnity +Prince Andrew now seemed excited. He could apparently not refrain from +expressing the thoughts that had suddenly occurred to him. + +"A battle is won by those who firmly resolve to win it! Why did we +lose the battle at Austerlitz? The French losses were almost equal +to ours, but very early we said to ourselves that we were losing the +battle, and we did lose it. And we said so because we had nothing to +fight for there, we wanted to get away from the battlefield as soon as +we could. 'We've lost, so let us run,' and we ran. If we had not +said that till the evening, heaven knows what might not have happened. +But tomorrow we shan't say it! You talk about our position, the left +flank weak and the right flank too extended," he went on. "That's +all nonsense, there's nothing of the kind. But what awaits us +tomorrow? A hundred million most diverse chances which will be decided +on the instant by the fact that our men or theirs run or do not run, +and that this man or that man is killed, but all that is being done at +present is only play. The fact is that those men with whom you have +ridden round the position not only do not help matters, but hinder. +They are only concerned with their own petty interests." + +"At such a moment?" said Pierre reproachfully. + +"At such a moment!" Prince Andrew repeated. "To them it is only a +moment affording opportunities to undermine a rival and obtain an +extra cross or ribbon. For me tomorrow means this: a Russian army of a +hundred thousand and a French army of a hundred thousand have met to +fight, and the thing is that these two hundred thousand men will fight +and the side that fights more fiercely and spares itself least will +win. And if you like I will tell you that whatever happens and +whatever muddles those at the top may make, we shall win tomorrow's +battle. Tomorrow, happen what may, we shall win!" + +"There now, your excellency! That's the truth, the real truth," said +Timokhin. "Who would spare himself now? The soldiers in my +battalion, believe me, wouldn't drink their vodka! 'It's not the day +for that!' they say." + +All were silent. The officers rose. Prince Andrew went out of the +shed with them, giving final orders to the adjutant. After they had +gone Pierre approached Prince Andrew and was about to start a +conversation when they heard the clatter of three horses' hoofs on the +road not far from the shed, and looking in that direction Prince +Andrew recognized Wolzogen and Clausewitz accompanied by a Cossack. +They rode close by continuing to converse, and Prince Andrew +involuntarily heard these words: + +"Der Krieg muss in Raum verlegt werden. Der Ansicht kann ich nicht +genug Preis geben,"* said one of them. + + +*"The war must be extended widely. I cannot sufficiently commend +that view." + + +"Oh, ja," said the other, "der Zweck ist nur den Feind zu schwachen, +so kann man gewiss nicht den Verlust der Privat-Personen in Achtung +nehmen."* + + +*"Oh, yes, the only aim is to weaken the enemy, so of course one +cannot take into account the loss of private individuals." + + +"Oh, no," agreed the other. + +"Extend widely!" said Prince Andrew with an angry snort, when they +had ridden past. "In that 'extend' were my father, son, and sister, at +Bald Hills. That's all the same to him! That's what I was saying to +you--those German gentlemen won't win the battle tomorrow but will +only make all the mess they can, because they have nothing in their +German heads but theories not worth an empty eggshell and haven't in +their hearts the one thing needed tomorrow--that which Timokhin has. +They have yielded up all Europe to him, and have now come to teach us. +Fine teachers!" and again his voice grew shrill. + +"So you think we shall win tomorrow's battle?" asked Pierre. + +"Yes, yes," answered Prince Andrew absently. "One thing I would do + +if I had the power," he began again, "I would not take prisoners. +Why take prisoners? It's chivalry! The French have destroyed my home +and are on their way to destroy Moscow, they have outraged and are +outraging me every moment. They are my enemies. In my opinion they are +all criminals. And so thinks Timokhin and the whole army. They +should be executed! Since they are my foes they cannot be my +friends, whatever may have been said at Tilsit." + +"Yes, yes," muttered Pierre, looking with shining eyes at Prince +Andrew. "I quite agree with you!" + +The question that had perturbed Pierre on the Mozhaysk hill and +all that day now seemed to him quite clear and completely solved. He +now understood the whole meaning and importance of this war and of the +impending battle. All he had seen that day, all the significant and +stern expressions on the faces he had seen in passing, were lit up for +him by a new light. He understood that latent heat (as they say in +physics) of patriotism which was present in all these men he had seen, +and this explained to him why they all prepared for death calmly, +and as it were lightheartedly. + +"Not take prisoners," Prince Andrew continued: "That by itself would +quite change the whole war and make it less cruel. As it is we have +played at war--that's what's vile! We play at magnanimity and all that +stuff. Such magnanimity and sensibility are like the magnanimity and +sensibility of a lady who faints when she sees a calf being killed: +she is so kind-hearted that she can't look at blood, but enjoys eating +the calf served up with sauce. They talk to us of the rules of war, of +chivalry, of flags of truce, of mercy to the unfortunate and so on. +It's all rubbish! I saw chivalry and flags of truce in 1805; they +humbugged us and we humbugged them. They plunder other people's +houses, issue false paper money, and worst of all they kill my +children and my father, and then talk of rules of war and +magnanimity to foes! Take no prisoners, but kill and be killed! He who +has come to this as I have through the same sufferings..." + +Prince Andrew, who had thought it was all the same to him whether or +not Moscow was taken as Smolensk had been, was suddenly checked in his +speech by an unexpected cramp in his throat. He paced up and down a +few times in silence, but his eyes glittered feverishly and his lips +quivered as he began speaking. + +"If there was none of this magnanimity in war, we should go to war +only when it was worth while going to certain death, as now. Then +there would not be war because Paul Ivanovich had offended Michael +Ivanovich. And when there was a war, like this one, it would be war! +And then the determination of the troops would be quite different. +Then all these Westphalians and Hessians whom Napoleon is leading +would not follow him into Russia, and we should not go to fight in +Austria and Prussia without knowing why. War is not courtesy but the +most horrible thing in life; and we ought to understand that and not +play at war. We ought to accept this terrible necessity sternly and +seriously. It all lies in that: get rid of falsehood and let war be +war and not a game. As it is now, war is the favorite pastime of the +idle and frivolous. The military calling is the most highly honored. + +"But what is war? What is needed for success in warfare? What are +the habits of the military? The aim of war is murder; the methods of +war are spying, treachery, and their encouragement, the ruin of a +country's inhabitants, robbing them or stealing to provision the army, +and fraud and falsehood termed military craft. The habits of the +military class are the absence of freedom, that is, discipline, +idleness, ignorance, cruelty, debauchery, and drunkenness. And in +spite of all this it is the highest class, respected by everyone. +All the kings, except the Chinese, wear military uniforms, and he +who kills most people receives the highest rewards. + +"They meet, as we shall meet tomorrow, to murder one another; they +kill and maim tens of thousands, and then have thanksgiving services +for having killed so many people (they even exaggerate the number), +and they announce a victory, supposing that the more people they +have killed the greater their achievement. How does God above look +at them and hear them?" exclaimed Prince Andrew in a shrill, +piercing voice. "Ah, my friend, it has of late become hard for me to +live. I see that I have begun to understand too much. And it doesn't +do for man to taste of the tree of knowledge of good and evil.... +Ah, well, it's not for long!" he added. + +"However, you're sleepy, and it's time for me to sleep. Go back to +Gorki!" said Prince Andrew suddenly. + +"Oh no!" Pierre replied, looking at Prince Andrew with frightened, +compassionate eyes. + +"Go, go! Before a battle one must have one's sleep out," repeated +Prince Andrew. + +He came quickly up to Pierre and embraced and kissed him. +"Good-by, be off!" he shouted. "Whether we meet again or not..." +and turning away hurriedly he entered the shed. + +It was already dark, and Pierre could not make out whether the +expression of Prince Andrew's face was angry or tender. + +For some time he stood in silence considering whether he should +follow him or go away. "No, he does not want it!" Pierre concluded. +"And I know that this is our last meeting!" He sighed deeply and +rode back to Gorki. + +On re-entering the shed Prince Andrew lay down on a rug, but he +could not sleep. + +He closed his eyes. One picture succeeded another in his +imagination. On one of them he dwelt long and joyfully. He vividly +recalled an evening in Petersburg. Natasha with animated and excited +face was telling him how she had gone to look for mushrooms the +previous summer and had lost her way in the big forest. She +incoherently described the depths of the forest, her feelings, and a +talk with a beekeeper she met, and constantly interrupted her story to +say: "No, I can't! I'm not telling it right; no, you don't +understand," though he encouraged her by saying that he did +understand, and he really had understood all she wanted to say. But +Natasha was not satisfied with her own words: she felt that they did +not convey the passionately poetic feeling she had experienced that +day and wished to convey. "He was such a delightful old man, and it +was so dark in the forest... and he had such kind... No, I can't +describe it," she had said, flushed and excited. Prince Andrew +smiled now the same happy smile as then when he had looked into her +eyes. "I understood her," he thought. "I not only understood her, +but it was just that inner, spiritual force, that sincerity, that +frankness of soul--that very soul of hers which seemed to be +fettered by her body--it was that soul I loved in her... loved so +strongly and happily..." and suddenly he remembered how his love had +ended. "He did not need anything of that kind. He neither saw nor +understood anything of the sort. He only saw in her a pretty and fresh +young girl, with whom he did not deign to unite his fate. And I?... +and he is still alive and gay!" + +Prince Andrew jumped up as if someone had burned him, and again +began pacing up and down in front of the shed. + + + + + +CHAPTER XXVI + + +On August 25, the eve of the battle of Borodino, M. de Beausset, +prefect of the French Emperor's palace, arrived at Napoleon's quarters +at Valuevo with Colonel Fabvier, the former from Paris and the +latter from Madrid. + +Donning his court uniform, M. de Beausset ordered a box he had +brought for the Emperor to be carried before him and entered the first +compartment of Napoleon's tent, where he began opening the box while +conversing with Napoleon's aides-de-camp who surrounded him. + +Fabvier, not entering the tent, remained at the entrance talking +to some generals of his acquaintance. + +The Emperor Napoleon had not yet left his bedroom and was +finishing his toilet. Slightly snorting and grunting, he presented now +his back and now his plump hairy chest to the brush with which his +valet was rubbing him down. Another valet, with his finger over the +mouth of a bottle, was sprinkling Eau de Cologne on the Emperor's +pampered body with an expression which seemed to say that he alone +knew where and how much Eau de Cologne should be sprinkled. Napoleon's +short hair was wet and matted on the forehead, but his face, though +puffy and yellow, expressed physical satisfaction. "Go on, harder, +go on!" he muttered to the valet who was rubbing him, slightly +twitching and grunting. An aide-de-camp, who had entered the bedroom +to report to the Emperor the number of prisoners taken in +yesterday's action, was standing by the door after delivering his +message, awaiting permission to withdraw. Napoleon, frowning, looked +at him from under his brows. + +"No prisoners!" said he, repeating the aide-de-camp's words. "They +are forcing us to exterminate them. So much the worse for the +Russian army.... Go on... harder, harder!" he muttered, hunching his +back and presenting his fat shoulders. + +"All right. Let Monsieur de Beausset enter, and Fabvier too," he +said, nodding to the aide-de-camp. + +"Yes, sire," and the aide-de-camp disappeared through the door of +the tent. + +Two valets rapidly dressed His Majesty, and wearing the blue uniform +of the Guards he went with firm quick steps to the reception room. + +De Beausset's hands meanwhile were busily engaged arranging the +present he had brought from the Empress, on two chairs directly in +front of the entrance. But Napoleon had dressed and come out with such +unexpected rapidity that he had not time to finish arranging the +surprise. + +Napoleon noticed at once what they were about and guessed that +they were not ready. He did not wish to deprive them of the pleasure +of giving him a surprise, so he pretended not to see de Beausset and +called Fabvier to him, listening silently and with a stern frown to +what Fabvier told him of the heroism and devotion of his troops +fighting at Salamanca, at the other end of Europe, with but one +thought--to be worthy of their Emperor--and but one fear--to fail to +please him. The result of that battle had been deplorable. Napoleon +made ironic remarks during Fabvier's account, as if he had not +expected that matters could go otherwise in his absence. + +"I must make up for that in Moscow," said Napoleon. "I'll see you +later," he added, and summoned de Beausset, who by that time had +prepared the surprise, having placed something on the chairs and +covered it with a cloth. + +De Beausset bowed low, with that courtly French bow which only the +old retainers of the Bourbons knew how to make, and approached him, +presenting an envelope. + +Napoleon turned to him gaily and pulled his ear. + +"You have hurried here. I am very glad. Well, what is Paris saying?" +he asked, suddenly changing his former stern expression for a most +cordial tone. + +"Sire, all Paris regrets your absence," replied de Beausset as was +proper. + +But though Napoleon knew that de Beausset had to say something of +this kind, and though in his lucid moments he knew it was untrue, he +was pleased to hear it from him. Again he honored him by touching +his ear. + +"I am very sorry to have made you travel so far," said he. + +"Sire, I expected nothing less than to find you at the gates of +Moscow," replied de Beausset. + +Napoleon smiled and, lifting his head absentmindedly, glanced to the +right. An aide-de-camp approached with gliding steps and offered him a +gold snuffbox, which he took. + +"Yes, it has happened luckily for you," he said, raising the open +snuffbox to his nose. "You are fond of travel, and in three days you +will see Moscow. You surely did not expect to see that Asiatic +capital. You will have a pleasant journey." + +De Beausset bowed gratefully at this regard for his taste for travel +(of which he had not till then been aware). + +"Ha, what's this?" asked Napoleon, noticing that all the courtiers +were looking at something concealed under a cloth. + +With courtly adroitness de Beausset half turned and without +turning his back to the Emperor retired two steps, twitching off the +cloth at the same time, and said: + +"A present to Your Majesty from the Empress." + +It was a portrait, painted in bright colors by Gerard, of the son +borne to Napoleon by the daughter of the Emperor of Austria, the boy +whom for some reason everyone called "The King of Rome." + +A very pretty curly-headed boy with a look of the Christ in the +Sistine Madonna was depicted playing at stick and ball. The ball +represented the terrestrial globe and the stick in his other hand a +scepter. + +Though it was not clear what the artist meant to express by +depicting the so-called King of Rome spiking the earth with a stick, +the allegory apparently seemed to Napoleon, as it had done to all +who had seen it in Paris, quite clear and very pleasing. + +"The King of Rome!" he said, pointing to the portrait with a +graceful gesture. "Admirable!" + +With the natural capacity of an Italian for changing the +expression of his face at will, he drew nearer to the portrait and +assumed a look of pensive tenderness. He felt that what he now said +and did would be historical, and it seemed to him that it would now be +best for him--whose grandeur enabled his son to play stick and ball +with the terrestrial globe--to show, in contrast to that grandeur, the +simplest paternal tenderness. His eyes grew dim, he moved forward, +glanced round at a chair (which seemed to place itself under him), and +sat down on it before the portrait. At a single gesture from him +everyone went out on tiptoe, leaving the great man to himself and +his emotion. + +Having sat still for a while he touched--himself not knowing why- +the thick spot of paint representing the highest light in the +portrait, rose, and recalled de Beausset and the officer on duty. He +ordered the portrait to be carried outside his tent, that the Old +Guard, stationed round it, might not be deprived of the pleasure of +seeing the King of Rome, the son and heir of their adored monarch. + +And while he was doing M. de Beausset the honor of breakfasting with +him, they heard, as Napoleon had anticipated, the rapturous cries of +the officers and men of the Old Guard who had run up to see the +portrait. + +"Vive l'Empereur! Vive le roi de Rome! Vive l'Empereur!" came +those ecstatic cries. + +After breakfast Napoleon in de Beausset's presence dictated his +order of the day to the army. + +"Short and energetic!" he remarked when he had read over the +proclamation which he had dictated straight off without corrections. +It ran: + + +Soldiers! This is the battle you have so longed for. Victory depends +on you. It is essential for us; it will give us all we need: +comfortable quarters and a speedy return to our country. Behave as you +did at Austerlitz, Friedland, Vitebsk, and Smolensk. Let our +remotest posterity recall your achievements this day with pride. Let +it be said of each of you: "He was in the great battle before Moscow!" + + +"Before Moscow!" repeated Napoleon, and inviting M. de Beausset, who +was so fond of travel, to accompany him on his ride, he went out of +the tent to where the horses stood saddled. + +"Your Majesty is too kind!" replied de Beausset to the invitation to +accompany the Emperor; he wanted to sleep, did not know how to ride +and was afraid of doing so. + +But Napoleon nodded to the traveler, and de Beausset had to mount. +When Napoleon came out of the tent the shouting of the Guards before +his son's portrait grew still louder. Napoleon frowned. + +"Take him away!" he said, pointing with a gracefully majestic +gesture to the portrait. "It is too soon for him to see a field of +battle." + +De Beausset closed his eyes, bowed his head, and sighed deeply, to +indicate how profoundly he valued and comprehended the Emperor's +words. + + + + + +CHAPTER XXVII + + +On the twenty-fifth of August, so his historians tell us, Napoleon +spent the whole day on horseback inspecting the locality, +considering plans submitted to him by his marshals, and personally +giving commands to his generals. + +The original line of the Russian forces along the river Kolocha +had been dislocated by the capture of the Shevardino Redoubt on the +twenty-fourth, and part of the line--the left flank--had been drawn +back. That part of the line was not entrenched and in front of it +the ground was more open and level than elsewhere. It was evident to +anyone, military or not, that it was here the French should attack. It +would seem that not much consideration was needed to reach this +conclusion, nor any particular care or trouble on the part of the +Emperor and his marshals, nor was there any need of that special and +supreme quality called genius that people are so apt to ascribe to +Napoleon; yet the historians who described the event later and the men +who then surrounded Napoleon, and he himself, thought otherwise. + +Napoleon rode over the plain and surveyed the locality with a +profound air and in silence, nodded with approval or shook his head +dubiously, and without communicating to the generals around him the +profound course of ideas which guided his decisions merely gave them +his final conclusions in the form of commands. Having listened to a +suggestion from Davout, who was now called Prince d'Eckmuhl, to turn +the Russian left wing, Napoleon said it should not be done, without +explaining why not. To a proposal made by General Campan (who was to +attack the fleches) to lead his division through the woods, Napoleon +agreed, though the so-called Duke of Elchingen (Ney) ventured to +remark that a movement through the woods was dangerous and might +disorder the division. + +Having inspected the country opposite the Shevardino Redoubt, +Napoleon pondered a little in silence and then indicated the spots +where two batteries should be set up by the morrow to act against +the Russian entrenchments, and the places where, in line with them, +the field artillery should be placed. + +After giving these and other commands he returned to his tent, and +the dispositions for the battle were written down from his dictation. + +These dispositions, of which the French historians write with +enthusiasm and other historians with profound respect, were as +follows: + + +At dawn the two new batteries established during the night on the +plain occupied by the Prince d'Eckmuhl will open fire on the +opposing batteries of the enemy. + +At the same time the commander of the artillery of the 1st Corps, +General Pernetti, with thirty cannon of Campan's division and all +the howitzers of Dessaix's and Friant's divisions, will move +forward, open fire, and overwhelm with shellfire the enemy's +battery, against which will operate: + + 24 guns of the artillery of the Guards + 30 guns of Campan's division + +and 8 guns of Friant's and Dessaix's divisions + -- + +in all 62 guns. + + +The commander of the artillery of the 3rd Corps, General Fouche, +will place the howitzers of the 3rd and 8th Corps, sixteen in all, +on the flanks of the battery that is to bombard the entrenchment on +the left, which will have forty guns in all directed against it. + +General Sorbier must be ready at the first order to advance with all +the howitzers of the Guard's artillery against either one or other +of the entrenchments. + +During the cannonade Prince Poniatowski is to advance through the +wood on the village and turn the enemy's position. + +General Campan will move through the wood to seize the first +fortification. + +After the advance has begun in this manner, orders will be given +in accordance with the enemy's movements. + +The cannonade on the left flank will begin as soon as the guns of +the right wing are heard. The sharpshooters of Morand's division and +of the vice-King's division will open a heavy fire on seeing the +attack commence on the right wing. + +The vice-King will occupy the village and cross by its three +bridges, advancing to the same heights as Morand's and Gibrard's +divisions, which under his leadership will be directed against the +redoubt and come into line with the rest of the forces. + +All this must be done in good order (le tout se fera avec ordre et +methode) as far as possible retaining troops in reserve. + The Imperial Camp near Mozhaysk, + September, 6, 1812. + + +These dispositions, which are very obscure and confused if one +allows oneself to regard the arrangements without religious awe of his +genius, related to Napoleon's orders to deal with four points--four +different orders. Not one of these was, or could be, carried out. + +In the disposition it is said first that the batteries placed on the +spot chosen by Napoleon, with the guns of Pernetti and Fouche; which +were to come in line with them, 102 guns in all, were to open fire and +shower shells on the Russian fleches and redoubts. This could not be +done, as from the spots selected by Napoleon the projectiles did not +carry to the Russian works, and those 102 guns shot into the air until +the nearest commander, contrary to Napoleon's instructions, moved them +forward. + +The second order was that Poniatowski, moving to the village through +the wood, should turn the Russian left flank. This could not be done +and was not done, because Poniatowski, advancing on the village +through the wood, met Tuchkov there barring his way, and could not and +did not turn the Russian position. + +The third order was: General Campan will move through the wood to +seize the first fortification. General Campan's division did not seize +the first fortification but was driven back, for on emerging from +the wood it had to reform under grapeshot, of which Napoleon was +unaware. + +The fourth order was: The vice-King will occupy the village +(Borodino) and cross by its three bridges, advancing to the same +heights as Morand's and Gdrard's divisions (for whose movements no +directions are given), which under his leadership will be directed +against the redoubt and come into line with the rest of the forces. + +As far as one can make out, not so much from this unintelligible +sentence as from the attempts the vice-King made to execute the orders +given him, he was to advance from the left through Borodino to the +redoubt while the divisions of Morand and Gerard were to advance +simultaneously from the front. + +All this, like the other parts of the disposition, was not and could +not be executed. After passing through Borodino the vice-King was +driven back to the Kolocha and could get no farther; while the +divisions of Morand and Gerard did not take the redoubt but were +driven back, and the redoubt was only taken at the end of the battle +by the cavalry (a thing probably unforeseen and not heard of by +Napoleon). So not one of the orders in the disposition was, or could +be, executed. But in the disposition it is said that, after the +fight has commenced in this manner, orders will be given in accordance +with the enemy's movements, and so it might be supposed that all +necessary arrangements would be made by Napoleon during the battle. +But this was not and could not be done, for during the whole battle +Napoleon was so far away that, as appeared later, he could not know +the course of the battle and not one of his orders during the fight +could be executed. + + + + + +CHAPTER XXVIII + + +Many historians say that the French did not win the battle of +Borodino because Napoleon had a cold, and that if he had not had a +cold the orders he gave before and during the battle would have been +still more full of genius and Russia would have been lost and the face +of the world have been changed. To historians who believe that +Russia was shaped by the will of one man--Peter the Great--and that +France from a republic became an empire and French armies went to +Russia at the will of one man--Napoleon--to say that Russia remained a +power because Napoleon had a bad cold on the twenty-fourth of August +may seem logical and convincing. + +If it had depended on Napoleon's will to fight or not to fight the +battle of Borodino, and if this or that other arrangement depended +on his will, then evidently a cold affecting the manifestation of +his will might have saved Russia, and consequently the valet who +omitted to bring Napoleon his waterproof boots on the twenty-fourth +would have been the savior of Russia. Along that line of thought +such a deduction is indubitable, as indubitable as the deduction +Voltaire made in jest (without knowing what he was jesting at) when he +saw that the Massacre of St. Bartholomew was due to Charles IX's +stomach being deranged. But to men who do not admit that Russia was +formed by the will of one man, Peter I, or that the French Empire +was formed and the war with Russia begun by the will of one man, +Napoleon, that argument seems not merely untrue and irrational, but +contrary to all human reality. To the question of what causes historic +events another answer presents itself, namely, that the course of +human events is predetermined from on high--depends on the coincidence +of the wills of all who take part in the events, and that a Napoleon's +influence on the course of these events is purely external and +fictitious. + +Strange as at first glance it may seem to suppose that the +Massacre of St. Bartholomew was not due to Charles IX's will, though +he gave the order for it and thought it was done as a result of that +order; and strange as it may seem to suppose that the slaughter of +eighty thousand men at Borodino was not due to Napoleon's will, though +he ordered the commencement and conduct of the battle and thought it +was done because he ordered it; strange as these suppositions +appear, yet human dignity--which tells me that each of us is, if not +more at least not less a man than the great Napoleon--demands the +acceptance of that solution of the question, and historic +investigation abundantly confirms it. + +At the battle of Borodino Napoleon shot at no one and killed no one. +That was all done by the soldiers. Therefore it was not he who +killed people. + +The French soldiers went to kill and be killed at the battle of +Borodino not because of Napoleon's orders but by their own volition. +The whole army--French, Italian, German, Polish, and Dutch--hungry, +ragged, and weary of the campaign, felt at the sight of an army +blocking their road to Moscow that the wine was drawn and must be +drunk. Had Napoleon then forbidden them to fight the Russians, they +would have killed him and have proceeded to fight the Russians because +it was inevitable. + +When they heard Napoleon's proclamation offering them, as +compensation for mutilation and death, the words of posterity about +their having been in the battle before Moscow, they cried "Vive +l'Empereur!" just as they had cried "Vive l'Empereur!" at the sight of +the portrait of the boy piercing the terrestrial globe with a toy +stick, and just as they would have cried "Vive l'Empereur!" at any +nonsense that might be told them. There was nothing left for them to +do but cry "Vive l'Empereur!" and go to fight, in order to get food +and rest as conquerors in Moscow. So it was not because of +Napoleon's commands that they killed their fellow men. + +And it was not Napoleon who directed the course of the battle, for +none of his orders were executed and during the battle he did not know +what was going on before him. So the way in which these people +killed one another was not decided by Napoleon's will but occurred +independently of him, in accord with the will of hundreds of thousands +of people who took part in the common action. It only seemed to +Napoleon that it all took place by his will. And so the question +whether he had or had not a cold has no more historic interest than +the cold of the least of the transport soldiers. + +Moreover, the assertion made by various writers that his cold was +the cause of his dispositions not being as well planned as on former +occasions, and of his orders during the battle not being as good as +previously, is quite baseless, which again shows that Napoleon's +cold on the twenty-sixth of August was unimportant. + +The dispositions cited above are not at all worse, but are even +better, than previous dispositions by which he had won victories. +His pseudo-orders during the battle were also no worse than +formerly, but much the same as usual. These dispositions and orders +only seem worse than previous ones because the battle of Borodino +was the first Napoleon did not win. The profoundest and most excellent +dispositions and orders seem very bad, and every learned militarist +criticizes them with looks of importance, when they relate to a +battle that has been lost, and the very worst dispositions and +orders seem very good, and serious people fill whole volumes to +demonstrate their merits, when they relate to a battle that has been +won. + +The dispositions drawn up by Weyrother for the battle of +Austerlitz were a model of perfection for that kind of composition, +but still they were criticized--criticized for their very +perfection, for their excessive minuteness. + +Napoleon at the battle of Borodino fulfilled his office as +representative of authority as well as, and even better than, at other +battles. He did nothing harmful to the progress of the battle; he +inclined to the most reasonable opinions, he made no confusion, did +not contradict himself, did not get frightened or run away from the +field of battle, but with his great tact and military experience +carried out his role of appearing to command, calmly and with dignity. + + + + + +CHAPTER XXIX + + +On returning from a second inspection of the lines, Napoleon +remarked: + +"The chessmen are set up, the game will begin tomorrow!" + +Having ordered punch and summoned de Beausset, he began to talk to +him about Paris and about some changes he meant to make the Empress' +household, surprising the prefect by his memory of minute details +relating to the court. + +He showed an interest in trifles, joked about de Beausset's love +of travel, and chatted carelessly, as a famous, self-confident surgeon +who knows his job does when turning up his sleeves and putting on +his apron while a patient is being strapped to the operating table. +"The matter is in my hands and is clear and definite in my head. +When the times comes to set to work I shall do it as no one else +could, but now I can jest, and the more I jest and the calmer I am the +more tranquil and confident you ought to be, and the more amazed at my +genius." + +Having finished his second glass of punch, Napoleon went to rest +before the serious business which, he considered, awaited him next +day. He was so much interested in that task that he was unable to +sleep, and in spite of his cold which had grown worse from the +dampness of the evening, he went into the large division of the tent +at three o'clock in the morning, loudly blowing his nose. He asked +whether the Russians had not withdrawn, and was told that the +enemy's fires were still in the same places. He nodded approval. + +The adjutant in attendance came into the tent. + +"Well, Rapp, do you think we shall do good business today?" Napoleon +asked him. + +"Without doubt, sire," replied Rapp. + +Napoleon looked at him. + +"Do you remember, sire, what you did me the honor to say at +Smolensk?" continued Rapp. "The wine is drawn and must be drunk." + +Napoleon frowned and sat silent for a long time leaning his head +on his hand. + +"This poor army!" he suddenly remarked. "It has diminished greatly +since Smolensk. Fortune is frankly a courtesan, Rapp. I have always +said so and I am beginning to experience it. But the Guards, Rapp, the +Guards are intact?" he remarked interrogatively. + +"Yes, sire," replied Rapp. + +Napoleon took a lozenge, put it in his mouth, and glanced at his +watch. He was not sleepy and it was still not nearly morning. It was +impossible to give further orders for the sake of killing time, for +the orders had all been given and were now being executed. + +"Have the biscuits and rice been served out to the regiments of +the Guards?" asked Napoleon sternly. + +"Yes, sire." + +"The rice too?" + +Rapp replied that he had given the Emperor's order about the rice, +but Napoleon shook his head in dissatisfaction as if not believing +that his order had been executed. An attendant came in with punch. +Napoleon ordered another glass to be brought for Rapp, and silently +sipped his own. + +"I have neither taste nor smell," he remarked, sniffing at his +glass. "This cold is tiresome. They talk about medicine--what is the +good of medicine when it can't cure a cold! Corvisart gave me these +lozenges but they don't help at all. What can doctors cure? One +can't cure anything. Our body is a machine for living. It is organized +for that, it is its nature. Let life go on in it unhindered and let it +defend itself, it will do more than if you paralyze it by +encumbering it with remedies. Our body is like a perfect watch that +should go for a certain time; watchmaker cannot open it, he can only +adjust it by fumbling, and that blindfold.... Yes, our body is just +a machine for living, that is all." + +And having entered on the path of definition, of which he was +fond, Napoleon suddenly and unexpectedly gave a new one. + +"Do you know, Rapp, what military art is?" asked he. "It is the +art of being stronger than the enemy at a given moment. That's all." + +Rapp made no reply. + +"Tomorrow we shall have to deal with Kutuzov!" said Napoleon. "We +shall see! Do you remember at Braunau he commanded an army for three +weeks and did not once mount a horse to inspect his +entrenchments.... We shall see!" + +He looked at his watch. It was still only four o'clock. He did not +feel sleepy. The punch was finished and there was still nothing to do. +He rose, walked to and fro, put on a warm overcoat and a hat, and went +out of the tent. The night was dark and damp, a scarcely perceptible +moisture was descending from above. Near by, the campfires were +dimly burning among the French Guards, and in the distance those of +the Russian line shone through the smoke. The weather was calm, and +the rustle and tramp of the French troops already beginning to move to +take up their positions were clearly audible. + +Napoleon walked about in front of his tent, looked at the fires +and listened to these sounds, and as he was passing a tall guardsman +in a shaggy cap, who was standing sentinel before his tent and had +drawn himself up like a black pillar at sight of the Emperor, Napoleon +stopped in front of him. + +"What year did you enter the service?" he asked with that +affectation of military bluntness and geniality with which he always +addressed the soldiers. + +The man answered the question. + +"Ah! One of the old ones! Has your regiment had its rice?" + +"It has, Your Majesty." + +Napoleon nodded and walked away. + + +At half-past five Napoleon rode to the village of Shevardino. + +It was growing light, the sky was clearing, only a single cloud +lay in the east. The abandoned campfires were burning themselves out +in the faint morning light. + +On the right a single deep report of a cannon resounded and died +away in the prevailing silence. Some minutes passed. A second and a +third report shook the air, then a fourth and a fifth boomed +solemnly near by on the right. + +The first shots had not yet ceased to reverberate before others rang +out and yet more were heard mingling with and overtaking one another. + +Napoleon with his suite rode up to the Shevardino Redoubt where he +dismounted. The game had begun. + + + + + +CHAPTER XXX + + +On returning to Gorki after having seen Prince Andrew, Pierre +ordered his groom to get the horses ready and to call him early in the +morning, and then immediately fell asleep behind a partition in a +corner Boris had given up to him. + +Before he was thoroughly awake next morning everybody had already +left the hut. The panes were rattling in the little windows and his +groom was shaking him. + +"Your excellency! Your excellency! Your excellency!" he kept +repeating pertinaciously while he shook Pierre by the shoulder without +looking at him, having apparently lost hope of getting him to wake up. + +"What? Has it begun? Is it time?" Pierre asked, waking up. + +"Hear the firing," said the groom, a discharged soldier. "All the +gentlemen have gone out, and his Serene Highness himself rode past +long ago." + +Pierre dressed hastily and ran out to the porch. Outside all was +bright, fresh, dewy, and cheerful. The sun, just bursting forth from +behind a cloud that had concealed it, was shining, with rays still +half broken by the clouds, over the roofs of the street opposite, on +the dew-besprinkled dust of the road, on the walls of the houses, on +the windows, the fence, and on Pierre's horses standing before the +hut. The roar of guns sounded more distinct outside. An adjutant +accompanied by a Cossack passed by at a sharp trot. + +"It's time, Count; it's time!" cried the adjutant. + +Telling the groom to follow him with the horses, Pierre went down +the street to the knoll from which he had looked at the field of +battle the day before. A crowd of military men was assembled there, +members of the staff could be heard conversing in French, and +Kutuzov's gray head in a white cap with a red band was visible, his +gray nape sunk between his shoulders. He was looking through a field +glass down the highroad before him. + +Mounting the steps to the knoll Pierre looked at the scene before +him, spellbound by beauty. It was the same panorama he had admired +from that spot the day before, but now the whole place was full of +troops and covered by smoke clouds from the guns, and the slanting +rays of the bright sun, rising slightly to the left behind Pierre, +cast upon it through the clear morning air penetrating streaks of +rosy, golden tinted light and long dark shadows. The forest at the +farthest extremity of the panorama seemed carved in some precious +stone of a yellowish-green color; its undulating outline was +silhouetted against the horizon and was pierced beyond Valuevo by +the Smolensk highroad crowded with troops. Nearer at hand glittered +golden cornfields interspersed with copses. There were troops to be +seen everywhere, in front and to the right and left. All this was +vivid, majestic, and unexpected; but what impressed Pierre most of all +was the view of the battlefield itself, of Borodino and the hollows on +both sides of the Kolocha. + +Above the Kolocha, in Borodino and on both sides of it, especially +to the left where the Voyna flowing between its marshy banks falls +into the Kolocha, a mist had spread which seemed to melt, to dissolve, +and to become translucent when the brilliant sun appeared and +magically colored and outlined everything. The smoke of the guns +mingled with this mist, and over the whole expanse and through that +mist the rays of the morning sun were reflected, flashing back like +lightning from the water, from the dew, and from the bayonets of the +troops crowded together by the riverbanks and in Borodino. A white +church could be seen through the mist, and here and there the roofs of +huts in Borodino as well as dense masses of soldiers, or green +ammunition chests and ordnance. And all this moved, or seemed to move, +as the smoke and mist spread out over the whole space. Just as in +the mist-enveloped hollow near Borodino, so along the entire line +outside and above it and especially in the woods and fields to the +left, in the valleys and on the summits of the high ground, clouds +of powder smoke seemed continually to spring up out of nothing, now +singly, now several at a time, some translucent, others dense, +which, swelling, growing, rolling, and blending, extended over the +whole expanse. + +These puffs of smoke and (strange to say) the sound of +the firing produced the chief beauty of the spectacle. + +"Puff!"--suddenly a round compact cloud of smoke was seen merging +from violet into gray and milky white, and "boom!" came the report a +second later. + +"Puff! puff!"--and two clouds arose pushing one another and blending +together; and "boom, boom!" came the sounds confirming what the eye +had seen. + +Pierre glanced round at the first cloud, which he had seen as a +round compact ball, and in its place already were balloons of smoke +floating to one side, and--"puff" (with a pause)--"puff, puff!" +three and then four more appeared and then from each, with the same +interval--"boom--boom, boom!" came the fine, firm, precise sounds in +reply. It seemed as if those smoke clouds sometimes ran and +sometimes stood still while woods, fields, and glittering bayonets ran +past them. From the left, over fields and bushes, those large balls of +smoke were continually appearing followed by their solemn reports, +while nearer still, in the hollows and woods, there burst from the +muskets small cloudlets that had no time to become balls, but had +their little echoes in just the same way. "Trakh-ta-ta-takh!" came the +frequent crackle of musketry, but it was irregular and feeble in +comparison with the reports of the cannon. + +Pierre wished to be there with that smoke, those shining bayonets, +that movement, and those sounds. He turned to look at Kutuzov and +his suite, to compare his impressions with those of others. They +were all looking at the field of battle as he was, and, as it seemed +to him, with the same feelings. All their faces were now shining +with that latent warmth of feeling Pierre had noticed the day before +and had fully understood after his talk with Prince Andrew. + +"Go, my dear fellow, go... and Christ be with you!" Kutuzov was +saying to a general who stood beside him, not taking his eye from +the battlefield. + +Having received this order the general passed by Pierre on his way +down the knoll. + +"To the crossing!" said the general coldly and sternly in reply to +one of the staff who asked where he was going. + +"I'll go there too, I too!" thought Pierre, and followed the +general. + +The general mounted a horse a Cossack had brought him. Pierre went +to his groom who was holding his horses and, asking which was the +quietest, clambered onto it, seized it by the mane, and turning out +his toes pressed his heels against its sides and, feeling that his +spectacles were slipping off but unable to let go of the mane and +reins, he galloped after the general, causing the staff officers to +smile as they watched him from the knoll. + + + + + +CHAPTER XXXI + + +Having descended the hill the general after whom Pierre was +galloping turned sharply to the left, and Pierre, losing sight of him, +galloped in among some ranks of infantry marching ahead of him. He +tried to pass either in front of them or to the right or left, but +there were soldiers everywhere, all with expression and busy with some +unseen but evidently important task. They all gazed with the same +dissatisfied and inquiring expression at this stout man in a white +hat, who for some unknown reason threatened to trample them under +his horse's hoofs. + +"Why ride into the middle of the battalion?" one of them shouted +at him. + +Another prodded his horse with the butt end of a musket, and Pierre, +bending over his saddlebow and hardly able to control his shying +horse, galloped ahead of the soldiers where there was a free space. + +There was a bridge ahead of him, where other soldiers stood +firing. Pierre rode up to them. Without being aware of it he had +come to the bridge across the Kolocha between Gorki and Borodino, +which the French (having occupied Borodino) were attacking in the +first phase of the battle. Pierre saw that there was a bridge in front +of him and that soldiers were doing something on both sides of it +and in the meadow, among the rows of new-mown hay which he had taken +no notice of amid the smoke of the campfires the day before; but +despite the incessant firing going on there he had no idea that this +was the field of battle. He did not notice the sound of the bullets +whistling from every side, or the projectiles that flew over him, +did not see the enemy on the other side of the river, and for a long +time did not notice the killed and wounded, though many fell near him. +He looked about him with a smile which did not leave his face. + +"Why's that fellow in front of the line?" shouted somebody at him +again. + +"To the left!... Keep to the right!" the men shouted to him. + +Pierre went to the right, and unexpectedly encountered one of +Raevski's adjutants whom he knew. The adjutant looked angrily at +him, evidently also intending to shout at him, but on recognizing +him he nodded. + +"How have you got here?" he said, and galloped on. + +Pierre, feeling out of place there, having nothing to do, and afraid +of getting in someone's way again, galloped after the adjutant. + +"What's happening here? May I come with you?" he asked. + +"One moment, one moment!" replied the adjutant, and riding up to a +stout colonel who was standing in the meadow, he gave him some message +and then addressed Pierre. + +"Why have you come here, Count?" he asked with a smile. "Still +inquisitive?" + +"Yes, yes," assented Pierre. + +But the adjutant turned his horse about and rode on. + +"Here it's tolerable," said he, "but with Bagration on the left +flank they're getting it frightfully hot." + +"Really?" said Pierre. "Where is that?" + +"Come along with me to our knoll. We can get a view from there and +in our battery it is still bearable," said the adjutant. "Will you +come?" + +"Yes, I'll come with you," replied Pierre, looking round for his +groom. + +It was only now that he noticed wounded men staggering along or +being carried on stretchers. On that very meadow he had ridden over +the day before, a soldier was lying athwart the rows of scented hay, +with his head thrown awkwardly back and his shako off. + +"Why haven't they carried him away?" Pierre was about to ask, but +seeing the stern expression of the adjutant who was also looking +that way, he checked himself. + +Pierre did not find his groom and rode along the hollow with the +adjutant to Raevski's Redoubt. His horse lagged behind the +adjutant's and jolted him at every step. + +"You don't seem to be used to riding, Count?" remarked the adjutant. + +"No it's not that, but her action seems so jerky," said Pierre in +a puzzled tone. + +"Why... she's wounded!" said the adjutant. "In the off foreleg above +the knee. A bullet, no doubt. I congratulate you, Count, on your +baptism of fire!" + +Having ridden in the smoke past the Sixth Corps, behind the +artillery which had been moved forward and was in action, deafening +them with the noise of firing, they came to a small wood. There it was +cool and quiet, with a scent of autumn. Pierre and the adjutant +dismounted and walked up the hill on foot. + +"Is the general here?" asked the adjutant on reaching the knoll. + +"He was here a minute ago but has just gone that way," someone +told him, pointing to the right. + +The adjutant looked at Pierre as if puzzled what to do with him now. + +"Don't trouble about me," said Pierre. "I'll go up onto the knoll if +I may?" + +"Yes, do. You'll see everything from there and it's less +dangerous, and I'll come for you." + +Pierre went to the battery and the adjutant rode on. They did not +meet again, and only much later did Pierre learn that he lost an arm +that day. + +The knoll to which Pierre ascended was that famous one afterwards +known to the Russians as the Knoll Battery or Raevski's Redoubt, and +to the French as la grande redoute, la fatale redoute, la redoute du +centre, around which tens of thousands fell, and which the French +regarded as the key to the whole position. + +This redoubt consisted of a knoll, on three sides of which +trenches had been dug. Within the entrenchment stood ten guns that +were being fired through openings in the earthwork. + +In line with the knoll on both sides stood other guns which also +fired incessantly. A little behind the guns stood infantry. When +ascending that knoll Pierre had no notion that this spot, on which +small trenches had been dug and from which a few guns were firing, was +the most important point of the battle. + +On the contrary, just because he happened to be there he thought +it one of the least significant parts of the field. + +Having reached the knoll, Pierre sat down at one end of a trench +surrounding the battery and gazed at what was going on around him with +an unconsciously happy smile. Occasionally he rose and walked about +the battery still with that same smile, trying not to obstruct the +soldiers who were loading, hauling the guns, and continually running +past him with bags and charges. The guns of that battery were being +fired continually one after another with a deafening roar, +enveloping the whole neighborhood in powder smoke. + +In contrast with the dread felt by the infantrymen placed in +support, here in the battery where a small number of men busy at their +work were separated from the rest by a trench, everyone experienced +a common and as it were family feeling of animation. + +The intrusion of Pierre's nonmilitary figure in a white hat made +an unpleasant impression at first. The soldiers looked askance at +him with surprise and even alarm as they went past him. The senior +artillery officer, a tall, long-legged, pockmarked man, moved over +to Pierre as if to see the action of the farthest gun and looked at +him with curiosity. + +A young round-faced officer, quite a boy still and evidently only +just out of the Cadet College, who was zealously commanding the two +guns entrusted to him, addressed Pierre sternly. + +"Sir," he said, "permit me to ask you to stand aside. You must not +be here." + +The soldiers shook their heads disapprovingly as they looked at +Pierre. But when they had convinced themselves that this man in the +white hat was doing no harm, but either sat quietly on the slope of +the trench with a shy smile or, politely making way for the +soldiers, paced up and down the battery under fire as calmly as if +he were on a boulevard, their feeling of hostile distrust gradually +began to change into a kindly and bantering sympathy, such as soldiers +feel for their dogs, cocks, goats, and in general for the animals that +live with the regiment. The men soon accepted Pierre into their +family, adopted him, gave him a nickname ("our gentleman"), and made +kindly fun of him among themselves. + +A shell tore up the earth two paces from Pierre and he looked around +with a smile as he brushed from his clothes some earth it had thrown +up. + +"And how's it you're not afraid, sir, really now?" a red-faced, +broad-shouldered soldier asked Pierre, with a grin that disclosed a +set of sound, white teeth. + +"Are you afraid, then?" said Pierre. + +"What else do you expect?" answered the soldier. "She has no +mercy, you know! When she comes spluttering down, out go your innards. +One can't help being afraid," he said laughing. + +Several of the men, with bright kindly faces, stopped beside Pierre. +They seemed not to have expected him to talk like anybody else, and +the discovery that he did so delighted them. + +"It's the business of us soldiers. But in a gentleman it's +wonderful! There's a gentleman for you!" + +"To your places!" cried the young officer to the men gathered +round Pierre. + +The young officer was evidently exercising his duties for the +first or second time and therefore treated both his superiors and +the men with great precision and formality. + +The booming cannonade and the fusillade of musketry were growing +more intense over the whole field, especially to the left where +Bagration's fleches were, but where Pierre was the smoke of the firing +made it almost impossible to distinguish anything. Moreover, his whole +attention was engrossed by watching the family circle--separated +from all else--formed by the men in the battery. His first unconscious +feeling of joyful animation produced by the sights and sounds of the +battlefield was now replaced by another, especially since he had +seen that soldier lying alone in the hayfield. Now, seated on the +slope of the trench, he observed the faces of those around him. + +By ten o'clock some twenty men had already been carried away from +the battery; two guns were smashed and cannon balls fell more and more +frequently on the battery and spent bullets buzzed and whistled +around. But the men in the battery seemed not to notice this, and +merry voices and jokes were heard on all sides. + +"A live one!" shouted a man as a whistling shell approached. + +"Not this way! To the infantry!" added another with loud laughter, +seeing the shell fly past and fall into the ranks of the supports. + +"Are you bowing to a friend, eh?" remarked another, chaffing a +peasant who ducked low as a cannon ball flew over. + +Several soldiers gathered by the wall of the trench, looking out +to see what was happening in front. + +"They've withdrawn the front line, it has retired," said they, +pointing over the earthwork. + +"Mind your own business," an old sergeant shouted at them. "If +they've retired it's because there's work for them to do farther +back." + +And the sergeant, taking one of the men by the shoulders, gave him a +shove with his knee. This was followed by a burst of laughter. + +"To the fifth gun, wheel it up!" came shouts from one side. + +"Now then, all together, like bargees!" rose the merry voices of +those who were moving the gun. + +"Oh, she nearly knocked our gentleman's hat off!" cried the +red-faced humorist, showing his teeth chaffing Pierre. "Awkward +baggage!" he added reproachfully to a cannon ball that struck a cannon +wheel and a man's leg. + +"Now then, you foxes!" said another, laughing at some militiamen +who, stooping low, entered the battery to carry away the wounded man. + +"So this gruel isn't to your taste? Oh, you crows! You're scared!" +they shouted at the militiamen who stood hesitating before the man +whose leg had been torn off. + +"There, lads... oh, oh!" they mimicked the peasants, "they don't +like it at all!" + +Pierre noticed that after every ball that hit the redoubt, and after +every loss, the liveliness increased more and more. + +As the flames of the fire hidden within come more and more vividly +and rapidly from an approaching thundercloud, so, as if in +opposition to what was taking place, the lightning of hidden fire +growing more and more intense glowed in the faces of these men. + +Pierre did not look out at the battlefield and was not concerned +to know what was happening there; he was entirely absorbed in watching +this fire which burned ever more brightly and which he felt was +flaming up in the same way in his own soul. + +At ten o'clock the infantry that had been among the bushes in +front of the battery and along the Kamenka streamlet retreated. From +the battery they could be seen running back past it carrying their +wounded on their muskets. A general with his suite came to the +battery, and after speaking to the colonel gave Pierre an angry look +and went away again having ordered the infantry supports behind the +battery to lie down, so as to be less exposed to fire. After this from +amid the ranks of infantry to the right of the battery came the +sound of a drum and shouts of command, and from the battery one saw +how those ranks of infantry moved forward. + +Pierre looked over the wall of the trench and was particularly +struck by a pale young officer who, letting his sword hang down, was +walking backwards and kept glancing uneasily around. + +The ranks of the infantry disappeared amid the smoke but their +long-drawn shout and rapid musketry firing could still be heard. A few +minutes later crowds of wounded men and stretcher-bearers came back +from that direction. Projectiles began to fall still more frequently +in the battery. Several men were lying about who had not been removed. +Around the cannon the men moved still more briskly and busily. No +one any longer took notice of Pierre. Once or twice he was shouted +at for being in the way. The senior officer moved with big, rapid +strides from one gun to another with a frowning face. The young +officer, with his face still more flushed, commanded the men more +scrupulously than ever. The soldiers handed up the charges, turned, +loaded, and did their business with strained smartness. They gave +little jumps as they walked, as though they were on springs. + +The stormcloud had come upon them, and in every face the fire +which Pierre had watched kindle burned up brightly. Pierre standing +beside the commanding officer. The young officer, his hand to his +shako, ran up to his superior. + +"I have the honor to report, sir, that only eight rounds are left. +Are we to continue firing?" he asked. + +"Grapeshot!" the senior shouted, without answering the question, +looking over the wall of the trench. + +Suddenly something happened: the young officer gave a gasp and +bending double sat down on the ground like a bird shot on the wing. +Everything became strange, confused, and misty in Pierre's eyes. + +One cannon ball after another whistled by and struck the +earthwork, a soldier, or a gun. Pierre, who had not noticed these +sounds before, now heard nothing else. On the right of the battery +soldiers shouting "Hurrah!" were running not forwards but backwards, +it seemed to Pierre. + +A cannon ball struck the very end of the earth work by which he +was standing, crumbling down the earth; a black ball flashed before +his eyes and at the same instant plumped into something. Some +militiamen who were entering the battery ran back. + +"All with grapeshot!" shouted the officer. + +The sergeant ran up to the officer and in a frightened whisper +informed him (as a butler at dinner informs his master that there is +no more of some wine asked for) that there were no more charges. + +"The scoundrels! What are they doing?" shouted the officer, +turning to Pierre. + +The officer's face was red and perspiring and his eyes glittered +under his frowning brow. + +"Run to the reserves and bring up the ammunition boxes!" he +yelled, angrily avoiding Pierre with his eyes and speaking to his men. + +"I'll go," said Pierre. + +The officer, without answering him, strode across to the opposite +side. + +"Don't fire.... Wait!" he shouted. + +The man who had been ordered to go for ammunition stumbled against +Pierre. + +"Eh, sir, this is no place for you," said he, and ran down the +slope. + +Pierre ran after him, avoiding the spot where the young officer +was sitting. + +One cannon ball, another, and a third flew over him, falling in +front, beside, and behind him. Pierre ran down the slope. "Where am +I going?" he suddenly asked himself when he was already near the green +ammunition wagons. He halted irresolutely, not knowing whether to +return or go on. Suddenly a terrible concussion threw him backwards to +the ground. At the same instant he was dazzled by a great flash of +flame, and immediately a deafening roar, crackling, and whistling made +his ears tingle. + +When he came to himself he was sitting on the ground leaning on +his hands; the ammunition wagons he had been approaching no longer +existed, only charred green boards and rags littered the scorched +grass, and a horse, dangling fragments of its shaft behind it, +galloped past, while another horse lay, like Pierre, on the ground, +uttering prolonged and piercing cries. + + + + + +CHAPTER XXXII + + +Beside himself with terror Pierre jumped up and ran back to the +battery, as to the only refuge from the horrors that surrounded him. + +On entering the earthwork he noticed that there were men doing +something there but that no shots were being fired from the battery. +He had no time to realize who these men were. He saw the senior +officer lying on the earth wall with his back turned as if he were +examining something down below and that one of the soldiers he had +noticed before was struggling forward shouting "Brothers!" and +trying to free himself from some men who were holding him by the +arm. He also saw something else that was strange. + +But he had not time to realize that the colonel had been killed, +that the soldier shouting "Brothers!" was a prisoner, and that another +man had been bayoneted in the back before his eyes, for hardly had +he run into the redoubt before a thin, sallow-faced, perspiring man in +a blue uniform rushed on him sword in hand, shouting something. +Instinctively guarding against the shock--for they had been running +together at full speed before they saw one another--Pierre put out his +hands and seized the man (a French officer) by the shoulder with one +hand and by the throat with the other. The officer, dropping his +sword, seized Pierre by his collar. + +For some seconds they gazed with frightened eyes at one another's +unfamiliar faces and both were perplexed at what they had done and +what they were to do next. "Am I taken prisoner or have I taken him +prisoner?" each was thinking. But the French officer was evidently +more inclined to think he had been taken prisoner because Pierre's +strong hand, impelled by instinctive fear, squeezed his throat ever +tighter and tighter. The Frenchman was about to say something, when +just above their heads, terrible and low, a cannon ball whistled, +and it seemed to Pierre that the French officer's head had been torn +off, so swiftly had he ducked it. + +Pierre too bent his head and let his hands fall. Without further +thought as to who had taken whom prisoner, the Frenchman ran back to +the battery and Pierre ran down the slope stumbling over the dead +and wounded who, it seemed to him, caught at his feet. But before he +reached the foot of the knoll he was met by a dense crowd of Russian +soldiers who, stumbling, tripping up, and shouting, ran merrily and +wildly toward the battery. (This was the attack for which Ermolov +claimed the credit, declaring that only his courage and good luck made +such a feat possible: it was the attack in which he was said to have +thrown some St. George's Crosses he had in his pocket into the battery +for the first soldiers to take who got there.) + +The French who had occupied the battery fled, and our troops +shouting "Hurrah!" pursued them so far beyond the battery that it +was difficult to call them back. + +The prisoners were brought down from the battery and among them +was a wounded French general, whom the officers surrounded. Crowds +of wounded--some known to Pierre and some unknown--Russians and +French, with faces distorted by suffering, walked, crawled, and were +carried on stretchers from the battery. Pierre again went up onto +the knoll where he had spent over an hour, and of that family circle +which had received him as a member he did not find a single one. There +were many dead whom he did not know, but some he recognized. The young +officer still sat in the same way, bent double, in a pool of blood +at the edge of the earth wall. The red-faced man was still +twitching, but they did not carry him away. + +Pierre ran down the slope once more. + +"Now they will stop it, now they will be horrified at what they have +done!" he thought, aimlessly going toward a crowd of stretcher bearers +moving from the battlefield. + +But behind the veil of smoke the sun was still high, and in front +and especially to the left, near Semenovsk, something seemed to be +seething in the smoke, and the roar of cannon and musketry did not +diminish, but even increased to desperation like a man who, +straining himself, shrieks with all his remaining strength. + + + + + +CHAPTER XXXIII + + +The chief action of the battle of Borodino was fought within the +seven thousand feet between Borodino and Bagration's fleches. Beyond +that space there was, on the one side, a demonstration made by the +Russians with Uvarov's cavalry at midday, and on the other side, +beyond Utitsa, Poniatowski's collision with Tuchkov; but these two +were detached and feeble actions in comparison with what took place in +the center of the battlefield. On the field between Borodino and the +fleches, beside the wood, the chief action of the day took place on an +open space visible from both sides and was fought in the simplest +and most artless way. + +The battle began on both sides with a cannonade from several hundred +guns. + +Then when the whole field was covered with smoke, two divisions, +Campan's and Dessaix's, advanced from the French right, while +Murat's troops advanced on Borodino from their left. + +From the Shevardino Redoubt where Napoleon was standing the +fleches were two thirds of a mile away, and it was more than a mile as +the crow flies to Borodino, so that Napoleon could not see what was +happening there, especially as the smoke mingling with the mist hid +the whole locality. The soldiers of Dessaix's division advancing +against the fleches could only be seen till they had entered the +hollow that lay between them and the fleches. As soon as they had +descended into that hollow, the smoke of the guns and musketry on +the fleches grew so dense that it covered the whole approach on that +side of it. Through the smoke glimpses could be caught of something +black--probably men--and at times the glint of bayonets. But whether +they were moving or stationary, whether they were French or Russian, +could not be discovered from the Shevardino Redoubt. + +The sun had risen brightly and its slanting rays struck straight +into Napoleon's face as, shading his eyes with his hand, he looked +at the fleches. The smoke spread out before them, and at times it +looked as if the smoke were moving, at times as if the troops moved. +Sometimes shouts were heard through the firing, but it was +impossible to tell what was being done there. + +Napoleon, standing on the knoll, looked through a field glass, and +in its small circlet saw smoke and men, sometimes his own and +sometimes Russians, but when he looked again with the naked eye, he +could not tell where what he had seen was. + +He descended the knoll and began walking up and down before it. + +Occasionally he stopped, listened to the firing, and gazed +intently at the battlefield. + +But not only was it impossible to make out what was happening from +where he was standing down below, or from the knoll above on which +some of his generals had taken their stand, but even from the +fleches themselves--in which by this time there were now Russian and +now French soldiers, alternately or together, dead, wounded, alive, +frightened, or maddened--even at those fleches themselves it was +impossible to make out what was taking place. There for several +hours amid incessant cannon and musketry fire, now Russians were +seen alone, now Frenchmen alone, now infantry, and now cavalry: they +appeared, fired, fell, collided, not knowing what to do with one +another, screamed, and ran back again. + +From the battlefield adjutants he had sent out, and orderlies from +his marshals, kept galloping up to Napoleon with reports of the +progress of the action, but all these reports were false, both because +it was impossible in the heat of battle to say what was happening at +any given moment and because many of the adjutants did not go to the +actual place of conflict but reported what they had heard from others; +and also because while an adjutant was riding more than a mile to +Napoleon circumstances changed and the news he brought was already +becoming false. Thus an adjutant galloped up from Murat with tidings +that Borodino had been occupied and the bridge over the Kolocha was in +the hands of the French. The adjutant asked whether Napoleon wished +the troops to cross it? Napoleon gave orders that the troops should +form up on the farther side and wait. But before that order was given- +almost as soon in fact as the adjutant had left Borodino--the bridge +had been retaken by the Russians and burned, in the very skirmish at +which Pierre had been present at the beginning of the battle. + +An adjutant galloped up from the fleches with a pale and +frightened face and reported to Napoleon that their attack had been +repulsed, Campan wounded, and Davout killed; yet at the very time +the adjutant had been told that the French had been repulsed, the +fleches had in fact been recaptured by other French troops, and Davout +was alive and only slightly bruised. On the basis of these necessarily +untrustworthy reports Napoleon gave his orders, which had either +been executed before he gave them or could not be and were not +executed. + +The marshals and generals, who were nearer to the field of battle +but, like Napoleon, did not take part in the actual fighting and +only occasionally went within musket range, made their own +arrangements without asking Napoleon and issued orders where and in +what direction to fire and where cavalry should gallop and infantry +should run. But even their orders, like Napoleon's, were seldom +carried out, and then but partially. For the most part things happened +contrary to their orders. Soldiers ordered to advance ran back on +meeting grapeshot; soldiers ordered to remain where they were, +suddenly, seeing Russians unexpectedly before them, sometimes rushed +back and sometimes forward, and the cavalry dashed without orders in +pursuit of the flying Russians. In this way two cavalry regiments +galloped through the Semenovsk hollow and as soon as they reached +the top of the incline turned round and galloped full speed back +again. The infantry moved in the same way, sometimes running to +quite other places than those they were ordered to go to. All orders +as to where and when to move the guns, when to send infantry to +shoot or horsemen to ride down the Russian infantry--all such orders +were given by the officers on the spot nearest to the units concerned, +without asking either Ney, Davout, or Murat, much less Napoleon. +They did not fear getting into trouble for not fulfilling orders or +for acting on their own initiative, for in battle what is at stake +is what is dearest to man--his own life--and it sometimes seems that +safety lies in running back, sometimes in running forward; and these +men who were right in the heat of the battle acted according to the +mood of the moment. In reality, however, all these movements forward +and backward did not improve or alter the position of the troops. +All their rushing and galloping at one another did little harm, the +harm of disablement and death was caused by the balls and bullets that +flew over the fields on which these men were floundering about. As +soon as they left the place where the balls and bullets were flying +about, their superiors, located in the background, re-formed them +and brought them under discipline and under the influence of that +discipline led them back to the zone of fire, where under the +influence of fear of death they lost their discipline and rushed about +according to the chance promptings of the throng. + + + + + +CHAPTER XXXIV + + +Napoleon's generals--Davout, Ney, and Murat, who were near that +region of fire and sometimes even entered it--repeatedly led into it +huge masses of well-ordered troops. But contrary to what had always +happened in their former battles, instead of the news they expected of +the enemy's flight, these orderly masses returned thence as +disorganized and terrified mobs. The generals re-formed them, but +their numbers constantly decreased. In the middle of the day Murat +sent his adjutant to Napoleon to demand reinforcements. + +Napoleon sat at the foot of the knoll, drinking punch, when +Murat's adjutant galloped up with an assurance that the Russians would +be routed if His Majesty would let him have another division. + +"Reinforcements?" said Napoleon in a tone of stern surprise, looking +at the adjutant--a handsome lad with long black curls arranged like +Murat's own--as though he did not understand his words. + +"Reinforcements!" thought Napoleon to himself. "How can they need +reinforcements when they already have half the army directed against a +weak, unentrenched Russian wing?" + +"Tell the King of Naples," said he sternly, "that it is not noon +yet, and I don't yet see my chessboard clearly. Go!..." + +The handsome boy adjutant with the long hair sighed deeply without +removing his hand from his hat and galloped back to where men were +being slaughtered. + +Napoleon rose and having summoned Caulaincourt and Berthier began +talking to them about matters unconnected with the battle. + +In the midst of this conversation, which was beginning to interest +Napoleon, Berthier's eyes turned to look at a general with a suite, +who was galloping toward the knoll on a lathering horse. It was +Belliard. Having dismounted he went up to the Emperor with rapid +strides and in a loud voice began boldly demonstrating the necessity +of sending reinforcements. He swore on his honor that the Russians +were lost if the Emperor would give another division. + +Napoleon shrugged his shoulders and continued to pace up and down +without replying. Belliard began talking loudly and eagerly to the +generals of the suite around him. + +"You are very fiery, Belliard," said Napoleon, when he again came up +to the general. "In the heat of a battle it is easy to make a mistake. +Go and have another look and then come back to me." + +Before Belliard was out of sight, a messenger from another part of +the battlefield galloped up. + +"Now then, what do you want?" asked Napoleon in the tone of a man +irritated at being continually disturbed. + +"Sire, the prince..." began the adjutant. + +"Asks for reinforcements?" said Napoleon with an angry gesture. + +The adjutant bent his head affirmatively and began to report, but +the Emperor turned from him, took a couple of steps, stopped, came +back, and called Berthier. + +"We must give reserves," he said, moving his arms slightly apart. +"Who do you think should be sent there?" he asked of Berthier (whom he +subsequently termed "that gosling I have made an eagle"). + +"Send Claparede's division, sire," replied Berthier, who knew all +the divisions regiments, and battalions by heart. + +Napoleon nodded assent. + +The adjutant galloped to Claparede's division and a few minutes +later the Young Guards stationed behind the knoll moved forward. +Napoleon gazed silently in that direction. + +"No!" he suddenly said to Berthier. "I can't send Claparede. Send +Friant's division." + +Though there was no advantage in sending Friant's division instead +of Claparede's, and even in obvious inconvenience and delay in +stopping Claparede and sending Friant now, the order was carried out +exactly. Napoleon did not notice that in regard to his army he was +playing the part of a doctor who hinders by his medicines--a role he +so justly understood and condemned. + +Friant's division disappeared as the others had done into the +smoke of the battlefield. From all sides adjutants continued to arrive +at a gallop and as if by agreement all said the same thing. They all +asked for reinforcements and all said that the Russians were holding +their positions and maintaining a hellish fire under which the +French army was melting away. + +Napoleon sat on a campstool, wrapped in thought. + +M. de Beausset, the man so fond of travel, having fasted since +morning, came up to the Emperor and ventured respectfully to suggest +lunch to His Majesty. + +"I hope I may now congratulate Your Majesty on a victory?" said he. + +Napoleon silently shook his head in negation. Assuming the +negation to refer only to the victory and not to the lunch, M. de +Beausset ventured with respectful jocularity to remark that there is +no reason for not having lunch when one can get it. + +"Go away..." exclaimed Napoleon suddenly and morosely, and turned +aside. + +A beatific smile of regret, repentance, and ecstasy beamed on M. +de Beausset's face and he glided away to the other generals. + +Napoleon was experiencing a feeling of depression like that of an +ever-lucky gambler who, after recklessly flinging money about and +always winning, suddenly just when he has calculated all the chances +of the game, finds that the more he considers his play the more surely +he loses. + +His troops were the same, his generals the same, the same +preparations had been made, the same dispositions, and the same +proclamation courte et energique, he himself was still the same: he +knew that and knew that he was now even more experienced and +skillful than before. Even the enemy was the same as at Austerlitz and +Friedland--yet the terrible stroke of his arm had supernaturally +become impotent. + +All the old methods that had been unfailingly crowned with +success: the concentration of batteries on one point, an attack by +reserves to break the enemy's line, and a cavalry attack by "the men +of iron," all these methods had already been employed, yet not only +was there no victory, but from all sides came the same news of +generals killed and wounded, of reinforcements needed, of the +impossibility of driving back the Russians, and of disorganization +among his own troops. + +Formerly, after he had given two or three orders and uttered a few +phrases, marshals and adjutants had come galloping up with +congratulations and happy faces, announcing the trophies taken, the +corps of prisoners, bundles of enemy eagles and standards, cannon +and stores, and Murat had only begged leave to loose the cavalry to +gather in the baggage wagons. So it had been at Lodi, Marengo, Arcola, +Jena, Austerlitz, Wagram, and so on. But now something strange was +happening to his troops. + +Despite news of the capture of the fleches, Napoleon saw that this +was not the same, not at all the same, as what had happened in his +former battles. He saw that what he was feeling was felt by all the +men about him experienced in the art of war. All their faces looked +dejected, and they all shunned one another's eyes--only a de +Beausset could fail to grasp the meaning of what was happening. + +But Napoleon with his long experience of war well knew the meaning +of a battle not gained by the attacking side in eight hours, after all +efforts had been expended. He knew that it was a lost battle and +that the least accident might now--with the fight balanced on such a +strained center--destroy him and his army. + +When he ran his mind over the whole of this strange Russian campaign +in which not one battle had been won, and in which not a flag, or +cannon, or army corps had been captured in two months, when he +looked at the concealed depression on the faces around him and heard +reports of the Russians still holding their ground--a terrible feeling +like a nightmare took possession of him, and all the unlucky accidents +that might destroy him occurred to his mind. The Russians might fall +on his left wing, might break through his center, he himself might +be killed by a stray cannon ball. All this was possible. In former +battles he had only considered the possibilities of success, but now +innumerable unlucky chances presented themselves, and he expected them +all. Yes, it was like a dream in which a man fancies that a ruffian is +coming to attack him, and raises his arm to strike that ruffian a +terrible blow which he knows should annihilate him, but then feels +that his arm drops powerless and limp like a rag, and the horror of +unavoidable destruction seizes him in his helplessness. + +The news that the Russians were attacking the left flank of the +French army aroused that horror in Napoleon. He sat silently on a +campstool below the knoll, with head bowed and elbows on his knees. +Berthier approached and suggested that they should ride along the line +to ascertain the position of affairs. + +"What? What do you say?" asked Napoleon. "Yes, tell them to bring me +my horse." + +He mounted and rode toward Semenovsk. + +Amid the powder smoke, slowly dispersing over the whole space +through which Napoleon rode, horses and men were lying in pools of +blood, singly or in heaps. Neither Napoleon nor any of his generals +had ever before seen such horrors or so many slain in such a small +area. The roar of guns, that had not ceased for ten hours, wearied the +ear and gave a peculiar significance to the spectacle, as music does +to tableaux vivants. Napoleon rode up the high ground at Semenovsk, +and through the smoke saw ranks of men in uniforms of a color +unfamiliar to him. They were Russians. + +The Russians stood in serried ranks behind Semenovsk village and its +knoll, and their guns boomed incessantly along their line and sent +forth clouds of smoke. It was no longer a battle: it was a +continuous slaughter which could be of no avail either to the French +or the Russians. Napoleon stopped his horse and again fell into the +reverie from which Berthier had aroused him. He could not stop what +was going on before him and around him and was supposed to be directed +by him and to depend on him, and from its lack of success this affair, +for the first time, seemed to him unnecessary and horrible. + +One of the generals rode up to Napoleon and ventured to offer to +lead the Old Guard into action. Ney and Berthier, standing near +Napoleon, exchanged looks and smiled contemptuously at this +general's senseless offer. + +Napoleon bowed his head and remained silent a long time. + +"At eight hundred leagues from France, I will not have my Guard +destroyed!" he said, and turning his horse rode back to Shevardino. + + + + + +CHAPTER XXXV + + +On the rug-covered bench where Pierre had seen him in the morning +sat Kutuzov, his gray head hanging, his heavy body relaxed. He gave no +orders, but only assented to or dissented from what others suggested. + +"Yes, yes, do that," he replied to various proposals. "Yes, yes: go, +dear boy, and have a look," he would say to one or another of those +about him; or, "No, don't, we'd better wait!" He listened to the +reports that were brought him and gave directions when his +subordinates demanded that of him; but when listening to the reports +it seemed as if he were not interested in the import of the words +spoken, but rather in something else--in the expression of face and +tone of voice of those who were reporting. By long years of military +experience he knew, and with the wisdom of age understood, that it +is impossible for one man to direct hundreds of thousands of others +struggling with death, and he knew that the result of a battle is +decided not by the orders of a commander in chief, nor the place where +the troops are stationed, nor by the number of cannon or of +slaughtered men, but by that intangible force called the spirit of the +army, and he watched this force and guided it in as far as that was in +his power. + +Kutuzov's general expression was one of concentrated quiet +attention, and his face wore a strained look as if he found it +difficult to master the fatigue of his old and feeble body. + +At eleven o'clock they brought him news that the fleches captured by +the French had been retaken, but that Prince Bagration was wounded. +Kutuzov groaned and swayed his head. + +"Ride over to Prince Peter Ivanovich and find out about it exactly," +he said to one of his adjutants, and then turned to the Duke of +Wurttemberg who was standing behind him. + +"Will Your Highness please take command of the first army?" + +Soon after the duke's departure--before he could possibly have +reached Semenovsk--his adjutant came back from him and told Kutuzov +that the duke asked for more troops. + +Kutuzov made a grimace and sent an order to Dokhturov to take over +the command of the first army, and a request to the duke--whom he said +he could not spare at such an important moment--to return to him. When +they brought him news that Murat had been taken prisoner, and the +staff officers congratulated him, Kutuzov smiled. + +"Wait a little, gentlemen," said he. "The battle is won, and there +is nothing extraordinary in the capture of Murat. Still, it is +better to wait before we rejoice." + +But he sent an adjutant to take the news round the army. + +When Scherbinin came galloping from the left flank with news that +the French had captured the fleches and the village of Semenovsk, +Kutuzov, guessing by the sounds of the battle and by Scherbinin's +looks that the news was bad, rose as if to stretch his legs and, +taking Scherbinin's arm, led him aside. + +"Go, my dear fellow," he said to Ermolov, "and see whether something +can't be done." + +Kutuzov was in Gorki, near the center of the Russian position. The +attack directed by Napoleon against our left flank had been several +times repulsed. In the center the French had not got beyond +Borodino, and on their left flank Uvarov's cavalry had put the +French to flight. + +Toward three o'clock the French attacks ceased. On the faces of +all who came from the field of battle, and of those who stood around +him, Kutuzov noticed an expression of extreme tension. He was +satisfied with the day's success--a success exceeding his +expectations, but the old man's strength was failing him. Several +times his head dropped low as if it were falling and he dozed off. +Dinner was brought him. + +Adjutant General Wolzogen, the man who when riding past Prince +Andrew had said, "the war should be extended widely," and whom +Bagration so detested, rode up while Kutuzov was at dinner. Wolzogen +had come from Barclay de Tolly to report on the progress of affairs on +the left flank. The sagacious Barclay de Tolly, seeing crowds of +wounded men running back and the disordered rear of the army, +weighed all the circumstances, concluded that the battle was lost, and +sent his favorite officer to the commander in chief with that news. + +Kutuzov was chewing a piece of roast chicken with difficulty and +glanced at Wolzogen with eyes that brightened under their puckering +lids. + +Wolzogen, nonchalantly stretching his legs, approached Kutuzov +with a half-contemptuous smile on his lips, scarcely touching the peak +of his cap. + +He treated his Serene Highness with a somewhat affected +nonchalance intended to show that, as a highly trained military man, +he left it to Russians to make an idol of this useless old man, but +that he knew whom he was dealing with. "Der alte Herr" (as in their +own set the Germans called Kutuzov) "is making himself very +comfortable," thought Wolzogen, and looking severely at the dishes +in front of Kutuzov he began to report to "the old gentleman" the +position of affairs on the left flank as Barclay had ordered him to +and as he himself had seen and understood it. + +"All the points of our position are in the enemy's hands and we +cannot dislodge them for lack of troops, the men are running away +and it is impossible to stop them," he reported. + +Kutuzov ceased chewing and fixed an astonished gaze on Wolzogen, +as if not understand what was said to him. Wolzogen, noticing "the old +gentleman's" agitation, said with a smile: + +"I have not considered it right to conceal from your Serene Highness +what I have seen. The troops are in complete disorder..." + +"You have seen? You have seen?..." Kutuzov shouted frowning, and +rising quickly he went up to Wolzogen. + +"How... how dare you!..." he shouted, choking and making a +threatening gesture with his trembling arms: "How dare you, sir, say +that to me? You know nothing about it. Tell General Barclay from me +that his information is incorrect and that the real course of the +battle is better known to me, the commander in chief, than to him." + +Wolzogen was about to make a rejoinder, but Kutuzov interrupted him. + +"The enemy has been repulsed on the left and defeated on the right +flank. If you have seen amiss, sir, do not allow yourself to say +what you don't know! Be so good as to ride to General Barclay and +inform him of my firm intention to attack the enemy tomorrow," said +Kutuzov sternly. + +All were silent, and the only sound audible was the heavy +breathing of the panting old general. + +"They are repulsed everywhere, for which I thank God and our brave +army! The enemy is beaten, and tomorrow we shall drive him from the +sacred soil of Russia," said Kutuzov crossing himself, and he suddenly +sobbed as his eyes filled with tears. + +Wolzogen, shrugging his shoulders and curling his lips, stepped +silently aside, marveling at "the old gentleman's" conceited +stupidity. + +"Ah, here he is, my hero!" said Kutuzov to a portly, handsome, +dark-haired general who was just ascending the knoll. + +This was Raevski, who had spent the whole day at the most +important part of the field of Borodino. + +Raevski reported that the troops were firmly holding their ground +and that the French no longer ventured to attack. + +After hearing him, Kutuzov said in French: + +"Then you do not think, like some others, that we must retreat?" + +"On the contrary, your Highness, in indecisive actions it is +always the most stubborn who remain victors," replied Raevski, "and in +my opinion..." + +"Kaysarov!" Kutuzov called to his adjutant. "Sit down and write +out the order of the day for tomorrow. And you," he continued, +addressing another, "ride along the line and that tomorrow we attack." + +While Kutuzov was talking to Raevski and dictating the order of +the day, Wolzogen returned from Barclay and said that General +Barclay wished to have written confirmation of the order the field +marshal had given. + +Kutuzov, without looking at Wolzogen, gave directions for the +order to be written out which the former commander in chief, to +avoid personal responsibility, very judiciously wished to receive. + +And by means of that mysterious indefinable bond which maintains +throughout an army one and the same temper, known as "the spirit of +the army," and which constitutes the sinew of war, Kutuzov's words, +his order for a battle next day, immediately became known from one end +of the army to the other. + +It was far from being the same words or the same order that +reached the farthest links of that chain. The tales passing from mouth +to mouth at different ends of the army did not even resemble what +Kutuzov had said, but the sense of his words spread everywhere because +what he said was not the outcome of cunning calculations, but of a +feeling that lay in the commander in chief's soul as in that of +every Russian. + +And on learning that tomorrow they were to attack the enemy, and +hearing from the highest quarters a confirmation of what they wanted +to believe, the exhausted, wavering men felt comforted and inspirited. + + + + + +CHAPTER XXXVI + + +Prince Andrew's regiment was among the reserves which till after one +o'clock were stationed inactive behind Semenovsk, under heavy +artillery fire. Toward two o'clock the regiment, having already lost +more than two hundred men, was moved forward into a trampled +oatfield in the gap between Semenovsk and the Knoll Battery, where +thousands of men perished that day and on which an intense, +concentrated fire from several hundred enemy guns was directed between +one and two o'clock. + +Without moving from that spot or firing a single shot the regiment +here lost another third of its men. From in front and especially +from the right, in the unlifting smoke the guns boomed, and out of the +mysterious domain of smoke that overlay the whole space in front, +quick hissing cannon balls and slow whistling shells flew unceasingly. +At times, as if to allow them a respite, a quarter of an hour passed +during which the cannon balls and shells all flew overhead, but +sometimes several men were torn from the regiment in a minute and +the slain were continually being dragged away and the wounded +carried off. + +With each fresh blow less and less chance of life remained for those +not yet killed. The regiment stood in columns of battalion, three +hundred paces apart, but nevertheless the men were always in one and +the same mood. All alike were taciturn and morose. Talk was rarely +heard in the ranks, and it ceased altogether every time the thud of +a successful shot and the cry of "stretchers!" was heard. Most of +the time, by their officers' order, the men sat on the ground. One, +having taken off his shako, carefully loosened the gathers of its +lining and drew them tight again; another, rubbing some dry clay +between his palms, polished his bayonet; another fingered the strap +and pulled the buckle of his bandolier, while another smoothed and +refolded his leg bands and put his boots on again. Some built little +houses of the tufts in the plowed ground, or plaited baskets from +the straw in the cornfield. All seemed fully absorbed in these +pursuits. When men were killed or wounded, when rows of stretchers +went past, when some troops retreated, and when great masses of the +enemy came into view through the smoke, no one paid any attention to +these things. But when our artillery or cavalry advanced or some of +our infantry were seen to move forward, words of approval were heard +on all sides. But the liveliest attention was attracted by occurrences +quite apart from, and unconnected with, the battle. It was as if the +minds of these morally exhausted men found relief in everyday, +commonplace occurrences. A battery of artillery was passing in front +of the regiment. The horse of an ammunition cart put its leg over a +trace. "Hey, look at the trace horse!... Get her leg out! She'll +fall.... Ah, they don't see it!" came identical shouts from the +ranks all along the regiment. Another time, general attention was +attracted by a small brown dog, coming heaven knows whence, which +trotted in a preoccupied manner in front of the ranks with tail +stiffly erect till suddenly a shell fell close by, when it yelped, +tucked its tail between its legs, and darted aside. Yells and +shrieks of laughter rose from the whole regiment. But such +distractions lasted only a moment, and for eight hours the men had +been inactive, without food, in constant fear of death, and their pale +and gloomy faces grew ever paler and gloomier. + +Prince Andrew, pale and gloomy like everyone in the regiment, +paced up and down from the border of one patch to another, at the edge +of the meadow beside an oatfield, with head bowed and arms behind +his back. There was nothing for him to do and no orders to be given. +Everything went on of itself. The killed were dragged from the +front, the wounded carried away, and the ranks closed up. If any +soldiers ran to the rear they returned immediately and hastily. At +first Prince Andrew, considering it his duty to rouse the courage of +the men and to set them an example, walked about among the ranks, +but he soon became convinced that this was unnecessary and that +there was nothing he could teach them. All the powers of his soul, +as of every soldier there, were unconsciously bent on avoiding the +contemplation of the horrors of their situation. He walked along the +meadow, dragging his feet, rustling the grass, and gazing at the +dust that covered his boots; now he took big strides trying to keep to +the footprints left on the meadow by the mowers, then he counted his +steps, calculating how often he must walk from one strip to another to +walk a mile, then he stripped the flowers from the wormwood that +grew along a boundary rut, rubbed them in his palms, and smelled their +pungent, sweetly bitter scent. Nothing remained of the previous +day's thoughts. He thought of nothing. He listened with weary ears +to the ever-recurring sounds, distinguishing the whistle of flying +projectiles from the booming of the reports, glanced at the tiresomely +familiar faces of the men of the first battalion, and waited. "Here it +comes... this one is coming our way again!" he thought, listening to +an approaching whistle in the hidden region of smoke. "One, another! +Again! It has hit...." He stopped and looked at the ranks. "No, it has +gone over. But this one has hit!" And again he started trying to reach +the boundary strip in sixteen paces. A whizz and a thud! Five paces +from him, a cannon ball tore up the dry earth and disappeared. A chill +ran down his back. Again he glanced at the ranks. Probably many had +been hit--a large crowd had gathered near the second battalion. + +"Adjutant!" he shouted. "Order them not to crowd together." + +The adjutant, having obeyed this instruction, approached Prince +Andrew. From the other side a battalion commander rode up. + +"Look out!" came a frightened cry from a soldier and, like a bird +whirring in rapid flight and alighting on the ground, a shell +dropped with little noise within two steps of Prince Andrew and +close to the battalion commander's horse. The horse first, +regardless of whether it was right or wrong to show fear, snorted, +reared almost throwing the major, and galloped aside. The horse's +terror infected the men. + +"Lie down!" cried the adjutant, throwing himself flat on the ground. + +Prince Andrew hesitated. The smoking shell spun like a top between +him and the prostrate adjutant, near a wormwood plant between the +field and the meadow. + +"Can this be death?" thought Prince Andrew, looking with a quite +new, envious glance at the grass, the wormwood, and the streamlet of +smoke that curled up from the rotating black ball. "I cannot, I do not +wish to die. I love life--I love this grass, this earth, this air...." +He thought this, and at the same time remembered that people were +looking at him. + +"It's shameful, sir!" he said to the adjutant. "What..." + +He did not finish speaking. At one and the same moment came the +sound of an explosion, a whistle of splinters as from a breaking +window frame, a suffocating smell of powder, and Prince Andrew started +to one side, raising his arm, and fell on his chest. Several +officers ran up to him. From the right side of his abdomen, blood +was welling out making a large stain on the grass. + +The militiamen with stretchers who were called up stood behind the +officers. Prince Andrew lay on his chest with his face in the grass, +breathing heavily and noisily. + +"What are you waiting for? Come along!" + +The peasants went up and took him by his shoulders and legs, but +he moaned piteously and, exchanging looks, they set him down again. + +"Pick him up, lift him, it's all the same!" cried someone. + +They again took him by the shoulders and laid him on the stretcher. + +"Ah, God! My God! What is it? The stomach? That means death! My +God!"--voices among the officers were heard saying. + +"It flew a hair's breadth past my ear," said the adjutant. + +The peasants, adjusting the stretcher to their shoulders, started +hurriedly along the path they had trodden down, to the dressing +station. + +"Keep in step! Ah... those peasants!" shouted an officer, seizing by +their shoulders and checking the peasants, who were walking unevenly +and jolting the stretcher. + +"Get into step, Fedor... I say, Fedor!" said the foremost peasant. + +"Now that's right!" said the one behind joyfully, when he had got +into step. + +"Your excellency! Eh, Prince!" said the trembling voice of Timokhin, +who had run up and was looking down on the stretcher. + +Prince Andrew opened his eyes and looked up at the speaker from +the stretcher into which his head had sunk deep and again his +eyelids drooped. + + +The militiamen carried Prince Andrew to dressing station by the +wood, where wagons were stationed. The dressing station consisted of +three tents with flaps turned back, pitched at the edge of a birch +wood. In the wood, wagons and horses were standing. The horses were +eating oats from their movable troughs and sparrows flew down and +pecked the grains that fell. Some crows, scenting blood, flew among +the birch trees cawing impatiently. Around the tents, over more than +five acres, bloodstained men in various garbs stood, sat, or lay. +Around the wounded stood crowds of soldier stretcher-bearers with +dismal and attentive faces, whom the officers keeping order tried in +vain to drive from the spot. Disregarding the officers' orders, the +soldiers stood leaning against their stretchers and gazing intently, +as if trying to comprehend the difficult problem of what was taking +place before them. From the tents came now loud angry cries and now +plaintive groans. Occasionally dressers ran out to fetch water, or +to point out those who were to be brought in next. The wounded men +awaiting their turn outside the tents groaned, sighed, wept, screamed, +swore, or asked for vodka. Some were delirious. Prince Andrew's +bearers, stepping over the wounded who had not yet been bandaged, took +him, as a regimental commander, close up to one of the tents and there +stopped, awaiting instructions. Prince Andrew opened his eyes and +for a long time could not make out what was going on around him. He +remembered the meadow, the wormwood, the field, the whirling black +ball, and his sudden rush of passionate love of life. Two steps from +him, leaning against a branch and talking loudly and attracting +general attention, stood a tall, handsome, black-haired +noncommissioned officer with a bandaged head. He had been wounded in +the head and leg by bullets. Around him, eagerly listening to his +talk, a crowd of wounded and stretcher-bearers was gathered. + +"We kicked him out from there so that he chucked everything, we +grabbed the King himself!" cried he, looking around him with eyes that +glittered with fever. "If only reserves had come up just then, lads, +there wouldn't have been nothing left of him! I tell you surely..." + +Like all the others near the speaker, Prince Andrew looked at him +with shining eyes and experienced a sense of comfort. "But isn't it +all the same now?" thought he. "And what will be there, and what has +there been here? Why was I so reluctant to part with life? There was +something in this life I did not and do not understand." + + + + + +CHAPTER XXXVII + + +One of the doctors came out of the tent in a bloodstained apron, +holding a cigar between the thumb and little finger of one of his +small bloodstained hands, so as not to smear it. He raised his head +and looked about him, but above the level of the wounded men. He +evidently wanted a little respite. After turning his head from right +to left for some time, he sighed and looked down. + +"All right, immediately," he replied to a dresser who pointed Prince +Andrew out to him, and he told them to carry him into the tent. + +Murmurs arose among the wounded who were waiting. + +"It seems that even in the next world only the gentry are to have +a chance!" remarked one. + +Prince Andrew was carried in and laid on a table that had only +just been cleared and which a dresser was washing down. Prince +Andrew could not make out distinctly what was in that tent. The +pitiful groans from all sides and the torturing pain in his thigh, +stomach, and back distracted him. All he saw about him merged into a +general impression of naked, bleeding human bodies that seemed to fill +the whole of the low tent, as a few weeks previously, on that hot +August day, such bodies had filled the dirty pond beside the +Smolensk road. Yes, it was the same flesh, the same chair a canon, the +sight of which had even then filled him with horror, as by a +presentiment. + +There were three operating tables in the tent. Two were occupied, +and on the third they placed Prince Andrew. For a little while he +was left alone and involuntarily witnessed what was taking place on +the other two tables. On the nearest one sat a Tartar, probably a +Cossack, judging by the uniform thrown down beside him. Four +soldiers were holding him, and a spectacled doctor was cutting into +his muscular brown back. + +"Ooh, ooh, ooh!" grunted the Tartar, and suddenly lifting up his +swarthy snub-nosed face with its high cheekbones, and baring his white +teeth, he began to wriggle and twitch his body and utter piercing, +ringing, and prolonged yells. On the other table, round which many +people were crowding, a tall well-fed man lay on his back with his +head thrown back. His curly hair, its color, and the shape of his head +seemed strangely familiar to Prince Andrew. Several dressers were +pressing on his chest to hold him down. One large, white, plump leg +twitched rapidly all the time with a feverish tremor. The man was +sobbing and choking convulsively. Two doctors--one of whom was pale +and trembling--were silently doing something to this man's other, gory +leg. When he had finished with the Tartar, whom they covered with an +overcoat, the spectacled doctor came up to Prince Andrew, wiping his +hands. + +He glanced at Prince Andrew's face and quickly turned away. + +"Undress him! What are you waiting for?" he cried angrily to the +dressers. + +His very first, remotest recollections of childhood came back to +Prince Andrew's mind when the dresser with sleeves rolled up began +hastily to undo the buttons of his clothes and undressed him. The +doctor bent down over the wound, felt it, and sighed deeply. Then he +made a sign to someone, and the torturing pain in his abdomen caused +Prince Andrew to lose consciousness. When he came to himself the +splintered portions of his thighbone had been extracted, the torn +flesh cut away, and the wound bandaged. Water was being sprinkled on +his face. As soon as Prince Andrew opened his eyes, the doctor bent +over, kissed him silently on the lips, and hurried away. + +After the sufferings he had been enduring, Prince Andrew enjoyed a +blissful feeling such as he had not experienced for a long time. All +the best and happiest moments of his life--especially his earliest +childhood, when he used to be undressed and put to bed, and when +leaning over him his nurse sang him to sleep and he, burying his +head in the pillow, felt happy in the mere consciousness of life- +returned to his memory, not merely as something past but as +something present. + +The doctors were busily engaged with the wounded man the shape of +whose head seemed familiar to Prince Andrew: they were lifting him +up and trying to quiet him. + +"Show it to me.... Oh, ooh... Oh! Oh, ooh!" his frightened moans +could be heard, subdued by suffering and broken by sobs. + +Hearing those moans Prince Andrew wanted to weep. +Whether because he was dying without glory, or because he was sorry to +part with life, or because of those memories of a childhood that could +not return, or because he was suffering and others were suffering +and that man near him was groaning so piteously--he felt like +weeping childlike, kindly, and almost happy tears. + +The wounded man was shown his amputated leg stained with clotted +blood and with the boot still on. + +"Oh! Oh, ooh!" he sobbed, like a woman. + +The doctor who had been standing beside him, preventing Prince +Andrew from seeing his face, moved away. + +"My God! What is this? Why is he here?" said Prince Andrew to +himself. + +In the miserable, sobbing, enfeebled man whose leg had just been +amputated, he recognized Anatole Kuragin. Men were supporting him in +their arms and offering him a glass of water, but his trembling, +swollen lips could not grasp its rim. Anatole was sobbing painfully. +"Yes, it is he! Yes, that man is somehow closely and painfully +connected with me," thought Prince Andrew, not yet clearly grasping +what he saw before him. "What is the connection of that man with my +childhood and life?" he asked himself without finding an answer. And +suddenly a new unexpected memory from that realm of pure and loving +childhood presented itself to him. He remembered Natasha as he had +seen her for the first time at the ball in 1810, with her slender neck +and arms and with a frightened happy face ready for rapture, and +love and tenderness for her, stronger and more vivid than ever, +awoke in his soul. He now remembered the connection that existed +between himself and this man who was dimly gazing at him through tears +that filled his swollen eyes. He remembered everything, and ecstatic +pity and love for that man overflowed his happy heart. + +Prince Andrew could no longer restrain himself and wept tender +loving tears for his fellow men, for himself, and for his own and +their errors. + +"Compassion, love of our brothers, for those who love us and for +those who hate us, love of our enemies; yes, that love which God +preached on earth and which Princess Mary taught me and I did not +understand--that is what made me sorry to part with life, that is what +remained for me had I lived. But now it is too late. I know it!" + + + + + +CHAPTER XXXVIII + + +The terrible spectacle of the battlefield covered with dead and +wounded, together with the heaviness of his head and the news that +some twenty generals he knew personally had been killed or wounded, +and the consciousness of the impotence of his once mighty arm, +produced an unexpected impression on Napoleon who usually liked to +look at the killed and wounded, thereby, he considered, testing his +strength of mind. This day the horrible appearance of the +battlefield overcame that strength of mind which he thought +constituted his merit and his greatness. He rode hurriedly from the +battlefield and returned to the Shevardino knoll, where he sat on +his campstool, his sallow face swollen and heavy, his eyes dim, his +nose red, and his voice hoarse, involuntarily listening, with downcast +eyes, to the sounds of firing. With painful dejection he awaited the +end of this action, in which he regarded himself as a participant +and which he was unable to arrest. A personal, human feeling for a +brief moment got the better of the artificial phantasm of life he +had served so long. He felt in his own person the sufferings and death +he had witnessed on the battlefield. The heaviness of his head and +chest reminded him of the possibility of suffering and death for +himself. At that moment he did not desire Moscow, or victory, or glory +(what need had he for any more glory?). The one thing he wished for +was rest, tranquillity, and freedom. But when he had been on the +Semenovsk heights the artillery commander had proposed to him to bring +several batteries of artillery up to those heights to strengthen the +fire on the Russian troops crowded in front of Knyazkovo. Napoleon had +assented and had given orders that news should be brought to him of +the effect those batteries produced. + +An adjutant came now to inform him that the fire of two hundred guns +had been concentrated on the Russians, as he had ordered, but that +they still held their ground. + +"Our fire is mowing them down by rows, but still they hold on," said +the adjutant. + +"They want more!..." said Napoleon in a hoarse voice. + +"Sire?" asked the adjutant who had not heard the remark. + +"They want more!" croaked Napoleon frowning. "Let them have it!" + +Even before he gave that order the thing he did not desire, and +for which he gave the order only because he thought it was expected of +him, was being done. And he fell back into that artificial realm of +imaginary greatness, and again--as a horse walking a treadmill +thinks it is doing something for itself--he submissively fulfilled the +cruel, sad, gloomy, and inhuman role predestined for him. + +And not for that day and hour alone were the mind and conscience +darkened of this man on whom the responsibility for what was happening +lay more than on all the others who took part in it. Never to the +end of his life could he understand goodness, beauty, or truth, or the +significance of his actions which were too contrary to goodness and +truth, too remote from everything human, for him ever to be able to +grasp their meaning. He could not disavow his actions, belauded as +they were by half the world, and so he had to repudiate truth, +goodness, and all humanity. + +Not only on that day, as he rode over the battlefield strewn with +men killed and maimed (by his will as he believed), did he reckon as +he looked at them how many Russians there were for each Frenchman and, +deceiving himself, find reason for rejoicing in the calculation that +there were five Russians for every Frenchman. Not on that day alone +did he write in a letter to Paris that "the battle field was +superb," because fifty thousand corpses lay there, but even on the +island of St. Helena in the peaceful solitude where he said he +intended to devote his leisure to an account of the great deeds he had +done, he wrote: + + +The Russian war should have been the most popular war of modern +times: it was a war of good sense, for real interests, for the +tranquillity and security of all; it was purely pacific and +conservative. + +It was a war for a great cause, the end of uncertainties and the +beginning of security. A new horizon and new labors were opening +out, full of well-being and prosperity for all. The European system +was already founded; all that remained was to organize it. + +Satisfied on these great points and with tranquility everywhere, I +too should have had my Congress and my Holy Alliance. Those ideas were +stolen from me. In that reunion of great sovereigns we should have +discussed our interests like one family, and have rendered account +to the peoples as clerk to master. + +Europe would in this way soon have been, in fact, but one people, +and anyone who traveled anywhere would have found himself always in +the common fatherland. I should have demanded the freedom of all +navigable rivers for everybody, that the seas should be common to all, +and that the great standing armies should be reduced henceforth to +mere guards for the sovereigns. + +On returning to France, to the bosom of the great, strong, +magnificent, peaceful, and glorious fatherland, I should have +proclaimed her frontiers immutable; all future wars purely +defensive, all aggrandizement antinational. I should have associated +my son in the Empire; my dictatorship would have been finished, and +his constitutional reign would have begun. + +Paris would have been the capital of the world, and the French the +envy of the nations! + +My leisure then, and my old age, would have been devoted, in company +with the Empress and during the royal apprenticeship of my son, to +leisurely visiting, with our own horses and like a true country +couple, every corner of the Empire, receiving complaints, redressing +wrongs, and scattering public buildings and benefactions on all +sides and everywhere. + + +Napoleon, predestined by Providence for the gloomy role of +executioner of the peoples, assured himself that the aim of his +actions had been the peoples' welfare and that he could control the +fate of millions and by the employment of power confer benefactions. + + +"Of four hundred thousand who crossed the Vistula," he wrote further +of the Russian war, "half were Austrians, Prussians, Saxons, Poles, +Bavarians, Wurttembergers, Mecklenburgers, Spaniards, Italians, and +Neapolitans. The Imperial army, strictly speaking, was one third +composed of Dutch, Belgians, men from the borders of the Rhine, +Piedmontese, Swiss, Genevese, Tuscans, Romans, inhabitants of the +Thirty-second Military Division, of Bremen, of Hamburg, and so on: +it included scarcely a hundred and forty thousand who spoke French. +The Russian expedition actually cost France less than fifty thousand +men; the Russian army in its retreat from Vilna to Moscow lost in +the various battles four times more men than the French army; the +burning of Moscow cost the lives of a hundred thousand Russians who +died of cold and want in the woods; finally, in its march from +Moscow to the Oder the Russian army also suffered from the severity of +the season; so that by the the time it reached Vilna it numbered +only fifty thousand, and at Kalisch less than eighteen thousand." + + +He imagined that the war with Russia came about by his will, and the +horrors that occurred did not stagger his soul. He boldly took the +whole responsibility for what happened, and his darkened mind found +justification in the belief that among the hundreds of thousands who +perished there were fewer Frenchmen than Hessians and Bavarians. + + + + + +CHAPTER XXXIX + + +Several tens of thousands of the slain lay in diverse postures and +various uniforms on the fields and meadows belonging to the Davydov +family and to the crown serfs--those fields and meadows where for +hundreds of years the peasants of Borodino, Gorki, Shevardino, and +Semenovsk had reaped their harvests and pastured their cattle. At +the dressing stations the grass and earth were soaked with blood for a +space of some three acres around. Crowds of men of various arms, +wounded and unwounded, with frightened faces, dragged themselves +back to Mozhaysk from the one army and back to Valuevo from the other. +Other crowds, exhausted and hungry, went forward led by their +officers. Others held their ground and continued to fire. + +Over the whole field, previously so gaily beautiful with the glitter +of bayonets and cloudlets of smoke in the morning sun, there now +spread a mist of damp and smoke and a strange acid smell of +saltpeter and blood. Clouds gathered and drops of rain began to fall +on the dead and wounded, on the frightened, exhausted, and +hesitating men, as if to say: "Enough, men! Enough! Cease... bethink +yourselves! What are you doing?" + +To the men of both sides alike, worn out by want of food and rest, +it began equally to appear doubtful whether they should continue to +slaughter one another; all the faces expressed hesitation, and the +question arose in every soul: "For what, for whom, must I kill and +be killed?... You may go and kill whom you please, but I don't want to +do so anymore!" By evening this thought had ripened in every soul. +At any moment these men might have been seized with horror at what +they were doing and might have thrown up everything and run away +anywhere. + +But though toward the end of the battle the men felt all the +horror of what they were doing, though they would have been glad to +leave off, some incomprehensible, mysterious power continued to +control them, and they still brought up the charges, loaded, aimed, +and applied the match, though only one artilleryman survived out of +every three, and though they stumbled and panted with fatigue, +perspiring and stained with blood and powder. The cannon balls flew +just as swiftly and cruelly from both sides, crushing human bodies, +and that terrible work which was not done by the will of a man but +at the will of Him who governs men and worlds continued. + +Anyone looking at the disorganized rear of the Russian army would +have said that, if only the French made one more slight effort, it +would disappear; and anyone looking at the rear of the French army +would have said that the Russians need only make one more slight +effort and the French would be destroyed. But neither the French nor +the Russians made that effort, and the flame of battle burned slowly +out. + +The Russians did not make that effort because they were not +attacking the French. At the beginning of the battle they stood +blocking the way to Moscow and they still did so at the end of the +battle as at the beginning. But even had the aim of the Russians +been to drive the French from their positions, they could not have +made this last effort, for all the Russian troops had been broken +up, there was no part of the Russian army that had not suffered in the +battle, and though still holding their positions they had lost ONE +HALF of their army. + +The French, with the memory of all their former victories during +fifteen years, with the assurance of Napoleon's invincibility, with +the consciousness that they had captured part of the battlefield and +had lost only a quarter of their men and still had their Guards +intact, twenty thousand strong, might easily have made that effort. +The French had attacked the Russian army in order to drive it from its +position ought to have made that effort, for as long as the Russians +continued to block the road to Moscow as before, the aim of the French +had not been attained and all their efforts and losses were in vain. +But the French did not make that effort. Some historians say that +Napoleon need only have used his Old Guards, who were intact, and +the battle would have been won. To speak of what would have happened +had Napoleon sent his Guards is like talking of what would happen if +autumn became spring. It could not be. Napoleon did not give his +Guards, not because he did not want to, but because it could not be +done. All the generals, officers, and soldiers of the French army knew +it could not be done, because the flagging spirit of the troops +would not permit it. + +It was not Napoleon alone who had experienced that nightmare feeling +of the mighty arm being stricken powerless, but all the generals and +soldiers of his army whether they had taken part in the battle or not, +after all their experience of previous battles--when after one tenth +of such efforts the enemy had fled--experienced a similar feeling of +terror before an enemy who, after losing HALF his men, stood as +threateningly at the end as at the beginning of the battle. The +moral force of the attacking French army was exhausted. Not that +sort of victory which is defined by the capture of pieces of +material fastened to sticks, called standards, and of the ground on +which the troops had stood and were standing, but a moral victory that +convinces the enemy of the moral superiority of his opponent and of +his own impotence was gained by the Russians at Borodino. The French +invaders, like an infuriated animal that has in its onslaught received +a mortal wound, felt that they were perishing, but could not stop, any +more than the Russian army, weaker by one half, could help swerving. +By impetus gained, the French army was still able to roll forward to +Moscow, but there, without further effort on the part of the Russians, +it had to perish, bleeding from the mortal wound it had received at +Borodino. The direct consequence of the battle of Borodino was +Napoleon's senseless flight from Moscow, his retreat along the old +Smolensk road, the destruction of the invading army of five hundred +thousand men, and the downfall of Napoleonic France, on which at +Borodino for the first time the hand of an opponent of stronger spirit +had been laid. + + + + + +BOOK ELEVEN: 1812 + + + + + +CHAPTER I + + +Absolute continuity of motion is not comprehensible to the human +mind. Laws of motion of any kind become comprehensible to man only +when he examines arbitrarily selected elements of that motion; but +at the same time, a large proportion of human error comes from the +arbitrary division of continuous motion into discontinuous elements. +There is a well known, so-called sophism of the ancients consisting in +this, that Achilles could never catch up with a tortoise he was +following, in spite of the fact that he traveled ten times as fast +as the tortoise. By the time Achilles has covered the distance that +separated him from the tortoise, the tortoise has covered one tenth of +that distance ahead of him: when Achilles has covered that tenth, +the tortoise has covered another one hundredth, and so on forever. +This problem seemed to the ancients insoluble. The absurd answer (that +Achilles could never overtake the tortoise) resulted from this: that +motion was arbitrarily divided into discontinuous elements, whereas +the motion both of Achilles and of the tortoise was continuous. + +By adopting smaller and smaller elements of motion we only +approach a solution of the problem, but never reach it. Only when we +have admitted the conception of the infinitely small, and the +resulting geometrical progression with a common ratio of one tenth, +and have found the sum of this progression to infinity, do we reach +a solution of the problem. + +A modern branch of mathematics having achieved the art of dealing +with the infinitely small can now yield solutions in other more +complex problems of motion which used to appear insoluble. + +This modern branch of mathematics, unknown to the ancients, when +dealing with problems of motion admits the conception of the +infinitely small, and so conforms to the chief condition of motion +(absolute continuity) and thereby corrects the inevitable error +which the human mind cannot avoid when it deals with separate elements +of motion instead of examining continuous motion. + +In seeking the laws of historical movement just the same thing +happens. The movement of humanity, arising as it does from innumerable +arbitrary human wills, is continuous. + +To understand the laws of this continuous movement is the aim of +history. But to arrive at these laws, resulting from the sum of all +those human wills, man's mind postulates arbitrary and disconnected +units. The first method of history is to take an arbitrarily +selected series of continuous events and examine it apart from others, +though there is and can be no beginning to any event, for one event +always flows uninterruptedly from another. + +The second method is to consider the actions of some one man--a king +or a commander--as equivalent to the sum of many individual wills; +whereas the sum of individual wills is never expressed by the activity +of a single historic personage. + +Historical science in its endeavor to draw nearer to truth +continually takes smaller and smaller units for examination. But +however small the units it takes, we feel that to take any unit +disconnected from others, or to assume a beginning of any +phenomenon, or to say that the will of many men is expressed by the +actions of any one historic personage, is in itself false. + +It needs no critical exertion to reduce utterly to dust any +deductions drawn from history. It is merely necessary to select some +larger or smaller unit as the subject of observation--as criticism has +every right to do, seeing that whatever unit history observes must +always be arbitrarily selected. + +Only by taking infinitesimally small units for observation (the +differential of history, that is, the individual tendencies of men) +and attaining to the art of integrating them (that is, finding the sum +of these infinitesimals) can we hope to arrive at the laws of history. + +The first fifteen years of the nineteenth century in Europe +present an extraordinary movement of millions of people. Men leave +their customary pursuits, hasten from one side of Europe to the other, +plunder and slaughter one another, triumph and are plunged in despair, +and for some years the whole course of life is altered and presents an +intensive movement which first increases and then slackens. What was +the cause of this movement, by what laws was it governed? asks the +mind of man. + +The historians, replying to this question, lay before us the sayings +and doings of a few dozen men in a building in the city of Paris, +calling these sayings and doings "the Revolution"; then they give a +detailed biography of Napoleon and of certain people favorable or +hostile to him; tell of the influence some of these people had on +others, and say: that is why this movement took place and those are +its laws. + +But the mind of man not only refuses to believe this explanation, +but plainly says that this method of explanation is fallacious, +because in it a weaker phenomenon is taken as the cause of a stronger. +The sum of human wills produced the Revolution and Napoleon, and +only the sum of those wills first tolerated and then destroyed them. + +"But every time there have been conquests there have been +conquerors; every time there has been a revolution in any state +there have been great men," says history. And, indeed, human reason +replies: every time conquerors appear there have been wars, but this +does not prove that the conquerors caused the wars and that it is +possible to find the laws of a war in the personal activity of a +single man. Whenever I look at my watch and its hands point to ten, +I hear the bells of the neighboring church; but because the bells +begin to ring when the hands of the clock reach ten, I have no right +to assume that the movement of the bells is caused by the position +of the hands of the watch. + +Whenever I see the movement of a locomotive I hear the whistle and +see the valves opening and wheels turning; but I have no right to +conclude that the whistling and the turning of wheels are the cause of +the movement of the engine. + +The peasants say that a cold wind blows in late spring because the +oaks are budding, and really every spring cold winds do blow when +the oak is budding. But though I do not know what causes the cold +winds to blow when the oak buds unfold, I cannot agree with the +peasants that the unfolding of the oak buds is the cause of the cold +wind, for the force of the wind is beyond the influence of the buds. I +see only a coincidence of occurrences such as happens with all the +phenomena of life, and I see that however much and however carefully I +observe the hands of the watch, and the valves and wheels of the +engine, and the oak, I shall not discover the cause of the bells +ringing, the engine moving, or of the winds of spring. To that I +must entirely change my point of view and study the laws of the +movement of steam, of the bells, and of the wind. History must do +the same. And attempts in this direction have already been made. + +To study the laws of history we must completely change the subject +of our observation, must leave aside kings, ministers, and generals, +and the common, infinitesimally small elements by which the masses are +moved. No one can say in how far it is possible for man to advance +in this way toward an understanding of the laws of history; but it +is evident that only along that path does the possibility of +discovering the laws of history lie, and that as yet not a millionth +part as much mental effort has been applied in this direction by +historians as has been devoted to describing the actions of various +kings, commanders, and ministers and propounding the historians' own +reflections concerning these actions. + + + + + +CHAPTER II + + +The forces of a dozen European nations burst into Russia. The +Russian army and people avoided a collision till Smolensk was reached, +and again from Smolensk to Borodino. The French army pushed on to +Moscow, its goal, its impetus ever increasing as it neared its aim, +just as the velocity of a falling body increases as it approaches +the earth. Behind it were seven hundred miles of hunger-stricken, +hostile country; ahead were a few dozen miles separating it from its +goal. Every soldier in Napoleon's army felt this and the invasion +moved on by its own momentum. + +The more the Russian army retreated the more fiercely a spirit of +hatred of the enemy flared up, and while it retreated the army +increased and consolidated. At Borodino a collision took place. +Neither army was broken up, but the Russian army retreated immediately +after the collision as inevitably as a ball recoils after colliding +with another having a greater momentum, and with equal inevitability +the ball of invasion that had advanced with such momentum rolled on +for some distance, though the collision had deprived it of all its +force. + +The Russians retreated eighty miles--to beyond Moscow--and the +French reached Moscow and there came to a standstill. For five weeks +after that there was not a single battle. The French did not move. +As a bleeding, mortally wounded animal licks its wounds, they remained +inert in Moscow for five weeks, and then suddenly, with no fresh +reason, fled back: they made a dash for the Kaluga road, and (after +a victory--for at Malo-Yaroslavets the field of conflict again +remained theirs) without undertaking a single serious battle, they +fled still more rapidly back to Smolensk, beyond Smolensk, beyond +the Berezina, beyond Vilna, and farther still. + +On the evening of the twenty-sixth of August, Kutuzov and the +whole Russian army were convinced that the battle of Borodino was a +victory. Kutuzov reported so to the Emperor. He gave orders to prepare +for a fresh conflict to finish the enemy and did this not to deceive +anyone, but because he knew that the enemy was beaten, as everyone who +had taken part in the battle knew it. + +But all that evening and next day reports came in one after +another of unheard-of losses, of the loss of half the army, and a +fresh battle proved physically impossible. + +It was impossible to give battle before information had been +collected, the wounded gathered in, the supplies of ammunition +replenished, the slain reckoned up, new officers appointed to +replace those who had been killed, and before the men had had food and +sleep. And meanwhile, the very next morning after the battle, the +French army advanced of itself upon the Russians, carried forward by +the force of its own momentum now seemingly increased in inverse +proportion to the square of the distance from its aim. Kutuzov's +wish was to attack next day, and the whole army desired to do so. +But to make an attack the wish to do so is not sufficient, there +must also be a possibility of doing it, and that possibility did not +exist. It was impossible not to retreat a day's march, and then in the +same way it was impossible not to retreat another and a third day's +march, and at last, on the first of September when the army drew +near Moscow--despite the strength of the feeling that had arisen in +all ranks--the force of circumstances compelled it to retire beyond +Moscow. And the troops retired one more, last, day's march, and +abandoned Moscow to the enemy. + +For people accustomed to think that plans of campaign and battles +are made by generals--as any one of us sitting over a map in his study +may imagine how he would have arranged things in this or that +battle--the questions present themselves: Why did Kutuzov during the +retreat not do this or that? Why did he not take up a position +before reaching Fili? Why did he not retire at once by the Kaluga +road, abandoning Moscow? and so on. People accustomed to think in that +way forget, or do not know, the inevitable conditions which always +limit the activities of any commander in chief. The activity of a +commander in chief does not all resemble the activity we imagine to +ourselves when we sit at case in our studies examining some campaign +on the map, with a certain number of troops on this and that side in a +certain known locality, and begin our plans from some given moment. +A commander in chief is never dealing with the beginning of any event- +the position from which we always contemplate it. The commander in +chief is always in the midst of a series of shifting events and so +he never can at any moment consider the whole import of an event +that is occurring. Moment by moment the event is imperceptibly shaping +itself, and at every moment of this continuous, uninterrupted +shaping of events the commander in chief is in the midst of a most +complex play of intrigues, worries, contingencies, authorities, +projects, counsels, threats, and deceptions and is continually obliged +to reply to innumerable questions addressed to him, which constantly +conflict with one another. + +Learned military authorities quite seriously tell us that Kutuzov +should have moved his army to the Kaluga road long before reaching +Fili, and that somebody actually submitted such a proposal to him. But +a commander in chief, especially at a difficult moment, has always +before him not one proposal but dozens simultaneously. And all these +proposals, based on strategics and tactics, contradict each other. + +A commander in chief's business, it would seem, is simply to +choose one of these projects. But even that he cannot do. Events and +time do not wait. For instance, on the twenty-eighth it is suggested +to him to cross to the Kaluga road, but just then an adjutant +gallops up from Miloradovich asking whether he is to engage the French +or retire. An order must be given him at once, that instant. And the +order to retreat carries us past the turn to the Kaluga road. And +after the adjutant comes the commissary general asking where the +stores are to be taken, and the chief of the hospitals asks where +the wounded are to go, and a courier from Petersburg brings a letter +from the sovereign which does not admit of the possibility of +abandoning Moscow, and the commander in chief's rival, the man who +is undermining him (and there are always not merely one but several +such), presents a new project diametrically opposed to that of turning +to the Kaluga road, and the commander in chief himself needs sleep and +refreshment to maintain his energy and a respectable general who has +been overlooked in the distribution of rewards comes to complain, +and the inhabitants of the district pray to be defended, and an +officer sent to inspect the locality comes in and gives a report quite +contrary to what was said by the officer previously sent; and a spy, a +prisoner, and a general who has been on reconnaissance, all describe +the position of the enemy's army differently. People accustomed to +misunderstand or to forget these inevitable conditions of a +commander in chief's actions describe to us, for instance, the +position of the army at Fili and assume that the commander in chief +could, on the first of September, quite freely decide whether to +abandon Moscow or defend it; whereas, with the Russian army less +than four miles from Moscow, no such question existed. When had that +question been settled? At Drissa and at Smolensk and most palpably +of all on the twenty-fourth of August at Shevardino and on the +twenty-sixth at Borodino, and each day and hour and minute of the +retreat from Borodino to Fili. + + + + + +CHAPTER III + + +When Ermolov, having been sent by Kutuzov to inspect the position, +told the field marshal that it was impossible to fight there before +Moscow and that they must retreat, Kutuzov looked at him in silence. + +"Give me your hand," said he and, turning it over so as to feel +the pulse, added: "You are not well, my dear fellow. Think what you +are saying!" + +Kutuzov could not yet admit the possibility of retreating beyond +Moscow without a battle. + +On the Poklonny Hill, four miles from the Dorogomilov gate of +Moscow, Kutuzov got out of his carriage and sat down on a bench by the +roadside. A great crowd of generals gathered round him, and Count +Rostopchin, who had come out from Moscow, joined them. This +brilliant company separated into several groups who all discussed +the advantages and disadvantages of the position, the state of the +army, the plans suggested, the situation of Moscow, and military +questions generally. Though they had not been summoned for the +purpose, and though it was not so called, they all felt that this +was really a council of war. The conversations all dealt with public +questions. If anyone gave or asked for personal news, it was done in a +whisper and they immediately reverted to general matters. No jokes, or +laughter, or smiles even, were seen among all these men. They +evidently all made an effort to hold themselves at the height the +situation demanded. And all these groups, while talking among +themselves, tried to keep near the commander in chief (whose bench +formed the center of the gathering) and to speak so that he might +overhear them. The commander in chief listened to what was being +said and sometimes asked them to repeat their remarks, but did not +himself take part in the conversations or express any opinion. After +hearing what was being said by one or other of these groups he +generally turned away with an air of disappointment, as though they +were not speaking of anything he wished to hear. Some discussed the +position that had been chosen, criticizing not the position itself +so much as the mental capacity of those who had chosen it. Others +argued that a mistake had been made earlier and that a battle should +have been fought two days before. Others again spoke of the battle +of Salamanca, which was described by Crosart, a newly arrived +Frenchman in a Spanish uniform. (This Frenchman and one of the +German princes serving with the Russian army were discussing the siege +of Saragossa and considering the possibility of defending Moscow in +a similar manner.) Count Rostopchin was telling a fourth group that he +was prepared to die with the city train bands under the walls of the +capital, but that he still could not help regretting having been +left in ignorance of what was happening, and that had he known it +sooner things would have been different.... A fifth group, +displaying the profundity of their strategic perceptions, discussed +the direction the troops would now have to take. A sixth group was +talking absolute nonsense. Kutuzov's expression grew more and more +preoccupied and gloomy. From all this talk he saw only one thing: that +to defend Moscow was a physical impossibility in the full meaning of +those words, that is to say, so utterly impossible that if any +senseless commander were to give orders to fight, confusion would +result but the battle would still not take place. It would not take +place because the commanders not merely all recognized the position to +be impossible, but in their conversations were only discussing what +would happen after its inevitable abandonment. How could the +commanders lead their troops to a field of battle they considered +impossible to hold? The lower-grade officers and even the soldiers +(who too reason) also considered the position impossible and therefore +could not go to fight, fully convinced as they were of defeat. If +Bennigsen insisted on the position being defended and others still +discussed it, the question was no longer important in itself but +only as a pretext for disputes and intrigue. This Kutuzov knew well. + +Bennigsen, who had chosen the position, warmly displayed his Russian +patriotism (Kutuzov could not listen to this without wincing) by +insisting that Moscow must be defended. His aim was as clear as +daylight to Kutuzov: if the defense failed, to throw the blame on +Kutuzov who had brought the army as far as the Sparrow Hills without +giving battle; if it succeeded, to claim the success as his own; or if +battle were not given, to clear himself of the crime of abandoning +Moscow. But this intrigue did not now occupy the old man's mind. One +terrible question absorbed him and to that question he heard no +reply from anyone. The question for him now was: "Have I really +allowed Napoleon to reach Moscow, and when did I do so? When was it +decided? Can it have been yesterday when I ordered Platov to +retreat, or was it the evening before, when I had a nap and told +Bennigsen to issue orders? Or was it earlier still?... When, when +was this terrible affair decided? Moscow must be abandoned. The army +must retreat and the order to do so must be given." To give that +terrible order seemed to him equivalent to resigning the command of +the army. And not only did he love power to which he was accustomed +(the honours awarded to Prince Prozorovski, under whom he had served +in Turkey, galled him), but he was convinced that he was destined to +save Russia and that that was why, against the Emperor's wish and by +the will of the people, he had been chosen commander in chief. He +was convinced that he alone could maintain command of the army in +these difficult circumstances, and that in all the world he alone +could encounter the invincible Napoleon without fear, and he was +horrified at the thought of the order he had to issue. But something +had to be decided, and these conversations around him which were +assuming too free a character must be stopped. + +He called the most important generals to him. + +"My head, be it good or bad, must depend on itself," said he, rising +from the bench, and he rode to Fili where his carriages were waiting. + + + + + +CHAPTER IV + + +The Council of War began to assemble at two in the afternoon in +the better and roomier part of Andrew Savostyanov's hut. The men, +women, and children of the large peasant family crowded into the +back room across the passage. Only Malasha, Andrew's six-year-old +granddaughter whom his Serene Highness had petted and to whom he had +given a lump of sugar while drinking his tea, remained on the top of +the brick oven in the larger room. Malasha looked down from the oven +with shy delight at the faces, uniforms, and decorations of the +generals, who one after another came into the room and sat down on the +broad benches in the corner under the icons. "Granddad" himself, as +Malasha in her own mind called Kutuzov, sat apart in a dark corner +behind the oven. He sat, sunk deep in a folding armchair, and +continually cleared his throat and pulled at the collar of his coat +which, though it was unbuttoned, still seemed to pinch his neck. Those +who entered went up one by one to the field marshal; he pressed the +hands of some and nodded to others. His adjutant Kaysarov was about to +draw back the curtain of the window facing Kutuzov, but the latter +moved his hand angrily and Kaysarov understood that his Serene +Highness did not wish his face to be seen. + +Round the peasant's deal table, on which lay maps, plans, pencils, +and papers, so many people gathered that the orderlies brought in +another bench and put it beside the table. Ermolov, Kaysarov, and +Toll, who had just arrived, sat down on this bench. In the foremost +place, immediately under the icons, sat Barclay de Tolly, his high +forehead merging into his bald crown. He had a St. George's Cross +round his neck and looked pale and ill. He had been feverish for two +days and was now shivering and in pain. Beside him sat Uvarov, who +with rapid gesticulations was giving him some information, speaking in +low tones as they all did. Chubby little Dokhturov was listening +attentively with eyebrows raised and arms folded on his stomach. On +the other side sat Count Ostermann-Tolstoy, seemingly absorbed in +his own thoughts. His broad head with its bold features and glittering +eyes was resting on his hand. Raevski, twitching forward the black +hair on his temples as was his habit, glanced now at Kutuzov and now +at the door with a look of impatience. Konovnitsyn's firm, handsome, +and kindly face was lit up by a tender, sly smile. His glance met +Malasha's, and the expression of his eyes caused the little girl to +smile. + +They were all waiting for Bennigsen, who on the pretext of +inspecting the position was finishing his savory dinner. They waited +for him from four till six o'clock and did not begin their +deliberations all that time talked in low tones of other matters. + +Only when Bennigsen had entered the hut did Kutuzov leave his corner +and draw toward the table, but not near enough for the candles that +had been placed there to light up his face. + +Bennigsen opened the council with the question: "Are we to abandon +Russia's ancient and sacred capital without a struggle, or are we to +defend it?" A prolonged and general silence followed. There was a +frown on every face and only Kutuzov's angry grunts and occasional +cough broke the silence. All eyes were gazing at him. Malasha too +looked at "Granddad." She was nearest to him and saw how his face +puckered; he seemed about to cry, but this did not last long. + +"Russia's ancient and sacred capital!" he suddenly said, repeating +Bennigsen's words in an angry voice and thereby drawing attention to +the false note in them. "Allow me to tell you, your excellency, that +that question has no meaning for a Russian." (He lurched his heavy +body forward.) "Such a question cannot be put; it is senseless! The +question I have asked these gentlemen to meet to discuss is a military +one. The question is that of saving Russia. Is it better to give up +Moscow without a battle, or by accepting battle to risk losing the +army as well as Moscow? That is the question on which I want your +opinion," and he sank back in his chair. + +The discussion began. Bennigsen did not yet consider his game +lost. Admitting the view of Barclay and others that a defensive battle +at Fili was impossible, but imbued with Russian patriotism and the +love of Moscow, he proposed to move troops from the right to the +left flank during the night and attack the French right flank the +following day. Opinions were divided, and arguments were advanced +for and against that project. Ermolov, Dokhturov, and Raevski agreed +with Bennigsen. Whether feeling it necessary to make a sacrifice +before abandoning the capital or guided by other, personal +considerations, these generals seemed not to understand that this +council could not alter the inevitable course of events and that +Moscow was in effect already abandoned. The other generals, however, +understood it and, leaving aside the question of Moscow, of the +direction the army should take in its retreat. Malasha, who kept her +eyes fixed on what was going on before her, understood the meaning +of the council differently. It seemed to her that it was only a +personal struggle between "Granddad" and "Long-coat" as she termed +Bennigsen. She saw that they grew spiteful when they spoke to one +another, and in her heart she sided with "Granddad." In the midst of +the conversation she noticed "Granddad" give Bennigsen a quick, subtle +glance, and then to her joys he saw that "Granddad" said something +to "Long-coat" which settled him. Bennigsen suddenly reddened and +paced angrily up and down the room. What so affected him was Kutuzov's +calm and quiet comment on the advantage or disadvantage of Bennigsen's +proposal to move troops by night from the right to the left flank to +attack the French right wing. + +"Gentlemen," said Kutuzov, "I cannot approve of the count's plan. +Moving troops in close proximity to an enemy is always dangerous, +and military history supports that view. For instance..." Kutuzov +seemed to reflect, searching for an example, then with a clear, +naive look at Bennigsen he added: "Oh yes; take the battle of +Friedland, which I think the count well remembers, and which was... +not fully successful, only because our troops were rearranged too near +the enemy..." + +There followed a momentary pause, which seemed very long to them +all. + +The discussion recommenced, but pauses frequently occurred and +they all felt that there was no more to be said. + +During one of these pauses Kutuzov heaved a deep sigh as if +preparing to speak. They all looked at him. + +"Well, gentlemen, I see that it is I who will have to pay for the +broken crockery," said he, and rising slowly he moved to the table. +"Gentlemen, I have heard your views. Some of you will not agree with +me. But I," he paused, "by the authority entrusted to me by my +Sovereign and country, order a retreat." + +After that the generals began to disperse with the solemnity and +circumspect silence of people who are leaving, after a funeral. + +Some of the generals, in low tones and in a strain very different +from the way they had spoken during the council, communicated +something to their commander in chief. + +Malasha, who had long been expected for supper, climbed carefully +backwards down from the oven, her bare little feet catching at its +projections, and slipping between the legs of the generals she +darted out of the room. + +When he had dismissed the generals Kutuzov sat a long time with +his elbows on the table, thinking always of the same terrible +question: "When, when did the abandonment of Moscow become inevitable? +When was that done which settled the matter? And who was to blame +for it?" + +"I did not expect this," said he to his adjutant Schneider when +the latter came in late that night. "I did not expect this! I did +not think this would happen." + +"You should take some rest, your Serene Highness," replied +Schneider. + +"But no! They shall eat horseflesh yet, like the Turks!" exclaimed +Kutuzov without replying, striking the table with his podgy fist. +"They shall too, if only..." + + + + + +CHAPTER V + + +At that very time, in circumstances even more important than +retreating without a battle, namely the evacuation and burning of +Moscow, Rostopchin, who is usually represented as being the instigator +of that event, acted in an altogether different manner from Kutuzov. + +After the battle of Borodino the abandonment and burning of Moscow +was as inevitable as the retreat of the army beyond Moscow without +fighting. + +Every Russian might have predicted it, not by reasoning but by the +feeling implanted in each of us and in our fathers. + +The same thing that took place in Moscow had happened in all the +towns and villages on Russian soil beginning with Smolensk, without +the participation of Count Rostopchin and his broadsheets. The +people awaited the enemy unconcernedly, did not riot or become excited +or tear anyone to pieces, but faced its fate, feeling within it the +strength to find what it should do at that most difficult moment. +And as soon as the enemy drew near the wealthy classes went away +abandoning their property, while the poorer remained and burned and +destroyed what was left. + +The consciousness that this would be so and would always be so was +and is present in the heart of every Russian. And a consciousness of +this, and a foreboding that Moscow would be taken, was present in +Russian Moscow society in 1812. Those who had quitted Moscow already +in July and at the beginning of August showed that they expected this. +Those who went away, taking what they could and abandoning their +houses and half their belongings, did so from the latent patriotism +which expresses itself not by phrases or by giving one's children to +save the fatherland and similar unnatural exploits, but unobtrusively, +simply, organically, and therefore in the way that always produces the +most powerful results. + +"It is disgraceful to run away from danger; only cowards are running +away from Moscow," they were told. In his broadsheets Rostopchin +impressed on them that to leave Moscow was shameful. They were ashamed +to be called cowards, ashamed to leave, but still they left, knowing +it had to be done. Why did they go? It is impossible to suppose that +Rostopchin had scared them by his accounts of horrors Napoleon had +committed in conquered countries. The first people to go away were the +rich educated people who knew quite well that Vienna and Berlin had +remained intact and that during Napoleon's occupation the +inhabitants had spent their time pleasantly in the company of the +charming Frenchmen whom the Russians, and especially the Russian +ladies, then liked so much. + +They went away because for Russians there could be no question as to +whether things would go well or ill under French rule in Moscow. It +was out of the question to be under French rule, it would be the worst +thing that could happen. They went away even before the battle of +Borodino and still more rapidly after it, despite Rostopchin's calls +to defend Moscow or the announcement of his intention to take the +wonder-working icon of the Iberian Mother of God and go to fight, or +of the balloons that were to destroy the French, and despite all the +nonsense Rostopchin wrote in his broadsheets. They knew that it was +for the army to fight, and that if it could not succeed it would not +do to take young ladies and house serfs to the Three Hills quarter +of Moscow to fight Napoleon, and that they must go away, sorry as they +were to abandon their property to destruction. They went away +without thinking of the tremendous significance of that immense and +wealthy city being given over to destruction, for a great city with +wooden buildings was certain when abandoned by its inhabitants to be +burned. They went away each on his own account, and yet it was only in +consequence of their going away that the momentous event was +accomplished that will always remain the greatest glory of the Russian +people. The lady who, afraid of being stopped by Count Rostopchin's +orders, had already in June moved with her Negroes and her women +jesters from Moscow to her Saratov estate, with a vague +consciousness that she was not Bonaparte's servant, was really, +simply, and truly carrying out the great work which saved Russia. +But Count Rostopchin, who now taunted those who left Moscow and now +had the government offices removed; now distributed quite useless +weapons to the drunken rabble; now had processions displaying the +icons, and now forbade Father Augustin to remove icons or the relics +of saints; now seized all the private carts in Moscow and on one +hundred and thirty-six of them removed the balloon that was being +constructed by Leppich; now hinted that he would burn Moscow and +related how he had set fire to his own house; now wrote a proclamation +to the French solemnly upbraiding them for having destroyed his +Orphanage; now claimed the glory of having hinted that he would burn +Moscow and now repudiated the deed; now ordered the people to catch +all spies and bring them to him, and now reproached them for doing so; +now expelled all the French residents from Moscow, and now allowed +Madame Aubert-Chalme (the center of the whole French colony in Moscow) +to remain, but ordered the venerable old postmaster Klyucharev to be +arrested and exiled for no particular offense; now assembled the +people at the Three Hills to fight the French and now, to get rid of +them, handed over to them a man to be killed and himself drove away by +a back gate; now declared that he would not survive the fall of +Moscow, and now wrote French verses in albums concerning his share +in the affair--this man did not understand the meaning of what was +happening but merely wanted to do something himself that would +astonish people, to perform some patriotically heroic feat; and like a +child he made sport of the momentous, and unavoidable event--the +abandonment and burning of Moscow--and tried with his puny hand now to +speed and now to stay the enormous, popular tide that bore him along +with it. + + + + + +CHAPTER VI + + +Helene, having returned with the court from Vilna to Petersburg, +found herself in a difficult position. + +In Petersburg she had enjoyed the special protection of a grandee +who occupied one of the highest posts in the Empire. In Vilna she +had formed an intimacy with a young foreign prince. When she +returned to Petersburg both the magnate and the prince were there, and +both claimed their rights. Helene was faced by a new problem--how to +preserve her intimacy with both without offending either. + +What would have seemed difficult or even impossible to another woman +did not cause the least embarrassment to Countess Bezukhova, who +evidently deserved her reputation of being a very clever woman. Had +she attempted concealment, or tried to extricate herself from her +awkward position by cunning, she would have spoiled her case by +acknowledging herself guilty. But Helene, like a really great man +who can do whatever he pleases, at once assumed her own position to be +correct, as she sincerely believed it to be, and that everyone else +was to blame. + +The first time the young foreigner allowed himself to reproach +her, she lifted her beautiful head and, half turning to him, said +firmly: "That's just like a man--selfish and cruel! I expected nothing +else. A woman sacrifices herself for you, she suffers, and this is her +reward! What right have you, monseigneur, to demand an account of my +attachments and friendships? He is a man who has been more than a +father to me!" The prince was about to say something, but Helene +interrupted him. + +"Well, yes," said she, "it may be that he has other sentiments for +me than those of a father, but that is not a reason for me to shut +my door on him. I am not a man, that I should repay kindness with +ingratitude! Know, monseigneur, that in all that relates to my +intimate feelings I render account only to God and to my +conscience," she concluded, laying her hand on her beautiful, fully +expanded bosom and looking up to heaven. + +"But for heaven's sake listen to me!" + +"Marry me, and I will be your slave!" + +"But that's impossible." + +"You won't deign to demean yourself by marrying me, you..." said +Helene, beginning to cry. + +The prince tried to comfort her, but Helene, as if quite distraught, +said through her tears that there was nothing to prevent her marrying, +that there were precedents (there were up to that time very few, but +she mentioned Napoleon and some other exalted personages), that she +had never been her husband's wife, and that she had been sacrificed. + +"But the law, religion..." said the prince, already yielding. + +"The law, religion... What have they been invented for if they can't +arrange that?" said Helene. + +The prince was surprised that so simple an idea had not occurred +to him, and he applied for advice to the holy brethren of the +Society of Jesus, with whom he was on intimate terms. + +A few days later at one of those enchanting fetes which Helene +gave at her country house on the Stone Island, the charming Monsieur +de Jobert, a man no longer young, with snow white hair and brilliant +black eyes, a Jesuit a robe courte* was presented to her, and in the +garden by the light of the illuminations and to the sound of music +talked to her for a long time of the love of God, of Christ, of the +Sacred Heart, and of the consolations the one true Catholic religion +affords in this world and the next. Helene was touched, and more +than once tears rose to her eyes and to those of Monsieur de Jobert +and their voices trembled. A dance, for which her partner came to seek +her, put an end to her discourse with her future directeur de +conscience, but the next evening Monsieur de Jobert came to see Helene +when she was alone, and after that often came again. + + +*Lay member of the Society of Jesus. + + +One day he took the countess to a Roman Catholic church, where she +knelt down before the altar to which she was led. The enchanting, +middle-aged Frenchman laid his hands on her head and, as she herself +afterward described it, she felt something like a fresh breeze +wafted into her soul. It was explained to her that this was la grace. + +After that a long-frocked abbe was brought to her. She confessed +to him, and he absolved her from her sins. Next day she received a box +containing the Sacred Host, which was left at her house for her to +partake of. A few days later Helene learned with pleasure that she had +now been admitted to the true Catholic Church and that in a few days +the Pope himself would hear of her and would send her a certain +document. + +All that was done around her and to her at this time, all the +attention devoted to her by so many clever men and expressed in such +pleasant, refined ways, and the state of dove-like purity she was +now in (she wore only white dresses and white ribbons all that time) +gave her pleasure, but her pleasure did not cause her for a moment +to forget her aim. And as it always happens in contests of cunning +that a stupid person gets the better of cleverer ones, Helene- +having realized that the main object of all these words and all this +trouble was, after converting her to Catholicism, to obtain money from +her for Jesuit institutions (as to which she received indications)- +before parting with her money insisted that the various operations +necessary to free her from her husband should be performed. In her +view the aim of every religion was merely to preserve certain +proprieties while affording satisfaction to human desires. And with +this aim, in one of her talks with her Father Confessor, she +insisted on an answer to the question, in how far was she bound by her +marriage? + +They were sitting in the twilight by a window in the drawing room. +The scent of flowers came in at the window. Helene was wearing a white +dress, transparent over her shoulders and bosom. The abbe, a +well-fed man with a plump, clean-shaven chin, a pleasant firm mouth, +and white hands meekly folded on his knees, sat close to Helene and, +with a subtle smile on his lips and a peaceful look of delight at +her beauty, occasionally glanced at her face as he explained his +opinion on the subject. Helene with an uneasy smile looked at his +curly hair and his plump, clean-shaven, blackish cheeks and every +moment expected the conversation to take a fresh turn. But the abbe, +though he evidently enjoyed the beauty of his companion, was +absorbed in his mastery of the matter. + +The course of the Father Confessor's arguments ran as follows: +"Ignorant of the import of what you were undertaking, you made a vow +of conjugal fidelity to a man who on his part, by entering the married +state without faith in the religious significance of marriage, +committed an act of sacrilege. That marriage lacked the dual +significance it should have had. Yet in spite of this your vow was +binding. You swerved from it. What did you commit by so acting? A +venial, or a mortal, sin? A venial sin, for you acted without evil +intention. If now you married again with the object of bearing +children, your sin might be forgiven. But the question is again a +twofold one: firstly..." + +But suddenly Helene, who was getting bored, said with one of her +bewitching smiles: "But I think that having espoused the true religion +I cannot be bound by what a false religion laid upon me." + +The director of her conscience was astounded at having the case +presented to him thus with the simplicity of Columbus' egg. He was +delighted at the unexpected rapidity of his pupil's progress, but +could not abandon the edifice of argument he had laboriously +constructed. + +"Let us understand one another, Countess," said he with a smile, and +began refuting his spiritual daughter's arguments. + + + + + +CHAPTER VII + + +Helene understood that the question was very simple and easy from +the ecclesiastical point of view, and that her directors were making +difficulties only because they were apprehensive as to how the +matter would be regarded by the secular authorities. + +So she decided that it was necessary to prepare the opinion of +society. She provoked the jealousy of the elderly magnate and told him +what she had told her other suitor; that is, she put the matter so +that the only way for him to obtain a right over her was to marry her. +The elderly magnate was at first as much taken aback by this +suggestion of marriage with a woman whose husband was alive, as the +younger man had been, but Helene's imperturbable conviction that it +was as simple and natural as marrying a maiden had its effect on him +too. Had Helene herself shown the least sign of hesitation, shame, +or secrecy, her cause would certainly have been lost; but not only did +she show no signs of secrecy or shame, on the contrary, with +good-natured naivete she told her intimate friends (and these were all +Petersburg) that both the prince and the magnate had proposed to her +and that she loved both and was afraid of grieving either. + +A rumor immediately spread in Petersburg, not that Helene wanted +to be divorced from her husband (had such a report spread many would +have opposed so illegal an intention) but simply that the +unfortunate and interesting Helene was in doubt which of the two men +she should marry. The question was no longer whether this was +possible, but only which was the better match and how the matter would +be regarded at court. There were, it is true, some rigid individuals +unable to rise to the height of such a question, who saw in the +project a desecration of the sacrament of marriage, but there were not +many such and they remained silent, while the majority were interested +in Helene's good fortune and in the question which match would be +the more advantageous. Whether it was right or wrong to remarry +while one had a husband living they did not discuss, for that question +had evidently been settled by people "wiser than you or me," as they +said, and to doubt the correctness of that decision would be to risk +exposing one's stupidity and incapacity to live in society. + +Only Marya Dmitrievna Akhrosimova, had come to Petersburg that +summer to see one of her sons, allowed herself plainly to express an +opinion contrary to the general one. Meeting Helene at a ball she +stopped her in the middle of the room and, amid general silence, +said in her gruff voice: "So wives of living men have started marrying +again! Perhaps you think you have invented a novelty? You have been +forestalled, my dear! It was thought of long ago. It is done in all +the brothels," and with these words Marya Dmitrievna, turning up her +wide sleeves with her usual threatening gesture and glancing sternly +round, moved across the room. + +Though people were afraid of Marya Dmitrievna she was regarded in +Petersburg as a buffoon, and so of what she had said they only +noticed, and repeated in a whisper, the one coarse word she had +used, supposing the whole sting of her remark to lie in that word. + +Prince Vasili, who of late very often forgot what he had said and +repeated one and the same thing a hundred times, remarked to his +daughter whenever he chanced to see her: + +"Helene, I have a word to say to you," and he would lead her +aside, drawing her hand downward. "I have heard of certain projects +concerning... you know. Well my dear child, you know how your father's +heart rejoices to know that you... You have suffered so much.... +But, my dear child, consult only your own heart. That is all I have to +say," and concealing his unvarying emotion he would press his cheek +against his daughter's and move away. + +Bilibin, who had not lost his reputation of an exceedingly clever +man, and who was one of the disinterested friends so +brilliant a woman as Helene always has--men friends who can never +change into lovers--once gave her his view of the matter at a small +and intimate gathering. + +"Listen, Bilibin," said Helene (she always called friends of that +sort by their surnames), and she touched his coat sleeve with her +white, beringed fingers. "Tell me, as you would a sister, what I ought +to do. Which of the two?" + +Bilibin wrinkled up the skin over his eyebrows and pondered, with +a smile on his lips. + +"You are not taking me unawares, you know," said he. "As a true +friend, I have thought and thought again about your affair. You see, +if you marry the prince"--he meant the younger man--and he crooked one +finger, "you forever lose the chance of marrying the other, and you +will displease the court besides. (You know there is some kind of +connection.) But if you marry the old count you will make his last +days happy, and as widow of the Grand... the prince would no longer be +making a mesalliance by marrying you," and Bilibin smoothed out his +forehead. + +"That's a true friend!" said Helene beaming, and again touching +Bilibin's sleeve. "But I love them, you know, and don't want to +distress either of them. I would give my life for the happiness of +them both." + +Bilibin shrugged his shoulders, as much as to say that not even he +could help in that difficulty. + +"Une maitresse-femme!* That's what is called putting things +squarely. She would like to be married to all three at the same time," +thought he. + + +*A masterly woman. + + +"But tell me, how will your husband look at the matter?" Bilibin +asked, his reputation being so well established that he did not fear +to ask so naive a question. "Will he agree?" + +"Oh, he loves me so!" said Helene, who for some reason imagined that +Pierre too loved her. "He will do anything for me." + +Bilibin puckered his skin in preparation for something witty. + +"Even divorce you?" said he. + +Helene laughed. + +Among those who ventured to doubt the justifiability of the proposed +marriage was Helene's mother, Princess Kuragina. She was continually +tormented by jealousy of her daughter, and now that jealousy concerned +a subject near to her own heart, she could not reconcile herself to +the idea. She consulted a Russian priest as to the possibility of +divorce and remarriage during a husband's lifetime, and the priest +told her that it was impossible, and to her delight showed her a +text in the Gospel which (as it seemed to him) plainly remarriage +while the husband is alive. + +Armed with these arguments, which appeared to her unanswerable, +she drove to her daughter's early one morning so as to find her alone. + +Having listened to her mother's objections, Helene smiled blandly +and ironically. + +"But it says plainly: 'Whosoever shall marry her that is +divorced...'" said the old princess. + +"Ah, Maman, ne dites pas de betises. Vous ne comprenez rein. Dans ma +position j'ai des devoirs,"* said Helene changing from Russian, in +which language she always felt that her case did not sound quite +clear, into French which suited it better. + + +*"Oh, Mamma, don't talk nonsense! You don't understand anything. +In my position I have obligations. + + +"But, my dear...." + +"Oh, Mamma, how is it you don't understand that the Holy Father, who +has the right to grant dispensations..." + +Just then the lady companion who lived with Helene came in to +announce that His Highness was in the ballroom and wished to see her. + +"Non, dites-lui que je ne veux pas le voir, que je suis furieuse +contre lui, parce qu'il m' a manque parole."* + + +*"No, tell him I don't wish to see him, I am furious with him for +not keeping his word to me." + + +"Comtesse, a tout peche misericorde,"* said a fair-haired young +man with a long face and nose, as he entered the room. + + +*"Countess, there is mercy for every sin." + + +The old princess rose respectfully and curtsied. The young man who +had entered took no notice of her. The princess nodded to her daughter +and sidled out of the room. + +"Yes, she is right," thought the old princess, all her convictions +dissipated by the appearance of His Highness. "She is right, but how +is it that we in our irrecoverable youth did not know it? Yet it is so +simple," she thought as she got into her carriage. + + +By the beginning of August Helene's affairs were clearly defined and +she wrote a letter to her husband--who, as she imagined, loved her +very much--informing him of her intention to marry N.N. and of her +having embraced the one true faith, and asking him to carry out all +the formalities necessary for a divorce, which would be explained to +him by the bearer of the letter. + + +And so I pray God to have you, my friend, in His holy and powerful +keeping--Your friend Helene. + + +This letter was brought to Pierre's house when he was on the field +of Borodino. + + + + + +CHAPTER VIII + + +Toward the end of the battle of Borodino, Pierre, having run down +from Raevski's battery a second time, made his way through a gully +to Knyazkovo with a crowd of soldiers, reached the dressing station, +and seeing blood and hearing cries and groans hurried on, still +entangled in the crowds of soldiers. + +The one thing he now desired with his whole soul was to get away +quickly from the terrible sensations amid which he had lived that +day and return to ordinary conditions of life and sleep quietly in a +room in his own bed. He felt that only in the ordinary conditions of +life would he be able to understand himself and all he had seen and +felt. But such ordinary conditions of life were nowhere to be found. + +Though shells and bullets did not whistle over the road along +which he was going, still on all sides there was what there had been +on the field of battle. There were still the same suffering, +exhausted, and sometimes strangely indifferent faces, the same +blood, the same soldiers' overcoats, the same sounds of firing +which, though distant now, still aroused terror, and besides this +there were the foul air and the dust. + +Having gone a couple of miles along the Mozhaysk road, Pierre sat +down by the roadside. + +Dusk had fallen, and the roar of guns died away. Pierre lay +leaning on his elbow for a long time, gazing at the shadows that moved +past him in the darkness. He was continually imagining that a cannon +ball was flying toward him with a terrific whizz, and then he +shuddered and sat up. He had no idea how long he had been there. In +the middle of the night three soldiers, having brought some +firewood, settled down near him and began lighting a fire. + +The soldiers, who threw sidelong glances at Pierre, got the fire +to burn and placed an iron pot on it into which they broke some +dried bread and put a little dripping. The pleasant odor of greasy +viands mingled with the smell of smoke. Pierre sat up and sighed. +The three soldiers were eating and talking among themselves, taking no +notice of him. + +"And who may you be?" one of them suddenly asked Pierre, evidently +meaning what Pierre himself had in mind, namely: "If you want to eat +we'll give you some food, only let us know whether you are an honest +man." + +"I, I..." said Pierre, feeling it necessary to minimize his social +position as much as possible so as to be nearer to the soldiers and +better understood by them. "By rights I am a militia officer, but my +men are not here. I came to the battle and have lost them." + +"There now!" said one of the soldiers. + +Another shook his head. + +"Would you like a little mash?" the first soldier asked, and +handed Pierre a wooden spoon after licking it clean. + +Pierre sat down by the fire and began eating the mash, as they +called the food in the cauldron, and he thought it more delicious than +any food he had ever tasted. As he sat bending greedily over it, +helping himself to large spoonfuls and chewing one after another, +his was lit up by the fire and the soldiers looked at him in silence. + +"Where have you to go to? Tell us!" said one of them. + +"To Mozhaysk." + +"You're a gentleman, aren't you?" + +"Yes." + +"And what's your name?" + +"Peter Kirilych." + +"Well then, Peter Kirilych, come along with us, we'll take you +there." + +In the total darkness the soldiers walked with Pierre to Mozhaysk. + +By the time they got near Mozhaysk and began ascending the steep +hill into the town, the cocks were already crowing. Pierre went on +with the soldiers, quite forgetting that his inn was at the bottom +of the hill and that he had already passed it. He would not soon +have remembered this, such was his state of forgetfulness, had he +not halfway up the hill stumbled upon his groom, who had been to +look for him in the town and was returning to the inn. The groom +recognized Pierre in the darkness by his white hat. + +"Your excellency!" he said. "Why, we were beginning to despair! +How is it you are on foot? And where are you going, please?" + +"Oh, yes!" said Pierre. + +The soldiers stopped. + +"So you've found your folk?" said one of them. "Well, good-by, Peter +Kirilych--isn't it?" + +"Good-by, Peter Kirilych!" Pierre heard the other voices repeat. + +"Good-by!" he said and turned with his groom toward the inn. + +"I ought to give them something!" he thought, and felt in his +pocket. "No, better not!" said another, inner voice. + +There was not a room to be had at the inn, they were all occupied. +Pierre went out into the yard and, covering himself up head and all, +lay down in his carriage. + + + + + +CHAPTER IX + + +Scarcely had Pierre laid his head on the pillow before he felt +himself falling asleep, but suddenly, almost with the distinctness +of reality, he heard the boom, boom, boom of firing, the thud of +projectiles, groans and cries, and smelled blood and powder, and a +feeling of horror and dread of death seized him. Filled with fright he +opened his eyes and lifted his head from under his cloak. All was +tranquil in the yard. Only someone's orderly passed through the +gateway, splashing through the mud, and talked to the innkeeper. Above +Pierre's head some pigeons, disturbed by the movement he had made in +sitting up, fluttered under the dark roof of the penthouse. The +whole courtyard was permeated by a strong peaceful smell of stable +yards, delightful to Pierre at that moment. He could see the clear +starry sky between the dark roofs of two penthouses. + +"Thank God, there is no more of that!" he thought, covering up his +head again. "Oh, what a terrible thing is fear, and how shamefully I +yielded to it! But they... they were steady and calm all the time, +to the end..." thought he. + +They, in Pierre's mind, were the soldiers, those who had been at the +battery, those who had given him food, and those who had prayed before +the icon. They, those strange men he had not previously known, stood +out clearly and sharply from everyone else. + +"To be a soldier, just a soldier!" thought Pierre as he fell asleep, +"to enter communal life completely, to be imbued by what makes them +what they are. But how cast off all the superfluous, devilish burden +of my outer man? There was a time when I could have done it. I could +have run away from my father, as I wanted to. Or I might have been +sent to serve as a soldier after the duel with Dolokhov." And the +memory of the dinner at the English Club when he had challenged +Dolokhov flashed through Pierre's mind, and then he remembered his +benefactor at Torzhok. And now a picture of a solemn meeting of the +lodge presented itself to his mind. It was taking place at the English +Club and someone near and dear to him sat at the end of the table. +"Yes, that is he! It is my benefactor. But he died!" thought Pierre. +"Yes, he died, and I did not know he was alive. How sorry I am that he +died, and how glad I am that he is alive again!" On one side of the +table sat Anatole, Dolokhov, Nesvitski, Denisov, and others like +them (in his dream the category to which these men belonged was as +clearly defined in his mind as the category of those he termed +they), and he heard those people, Anatole and Dolokhov, shouting and +singing loudly; yet through their shouting the voice of his benefactor +was heard speaking all the time and the sound of his words was as +weighty and uninterrupted as the booming on the battlefield, but +pleasant and comforting. Pierre did not understand what his benefactor +was saying, but he knew (the categories of thoughts were also quite +distinct in his dream) that he was talking of goodness and the +possibility of being what they were. And they with their simple, kind, +firm faces surrounded his benefactor on all sides. But though they +were kindly they did not look at Pierre and did not know him. +Wishing to speak and to attract their attention, he got up, but at +that moment his legs grew cold and bare. + +He felt ashamed, and with one arm covered his legs from which his +cloak had in fact slipped. For a moment as he was rearranging his +cloak Pierre opened his eyes and saw the same penthouse roofs, +posts, and yard, but now they were all bluish, lit up, and +glittering with frost or dew. + +"It is dawn," thought Pierre. "But that's not what I want. I want to +hear and understand my benefactor's words." Again he covered himself +up with his cloak, but now neither the lodge nor his benefactor was +there. There were only thoughts clearly expressed in words, thoughts +that someone was uttering or that he himself was formulating. + +Afterwards when he recalled those thoughts Pierre was convinced that +someone outside himself had spoken them, though the impressions of +that day had evoked them. He had never, it seemed to him, been able to +think and express his thoughts like that when awake. + +"To endure war is the most difficult subordination of man's +freedom to the law of God," the voice had said. "Simplicity is +submission to the will of God; you cannot escape from Him. And they +are simple. They do not talk, but act. The spoken word is silver but +the unspoken is golden. Man can be master of nothing while he fears +death, but he who does not fear it possesses all. If there were no +suffering, man would not know his limitations, would not know himself. +The hardest thing [Pierre went on thinking, or hearing, in his +dream] is to be able in your soul to unite the meaning of all. To +unite all?" he asked himself. "No, not to unite. Thoughts cannot be +united, but to harness all these thoughts together is what we need! +Yes, one must harness them, must harness them!" he repeated to himself +with inward rapture, feeling that these words and they alone expressed +what he wanted to say and solved the question that tormented him. + +"Yes, one must harness, it is time to harness." + +"Time to harness, time to harness, your excellency! Your +excellency!" some voice was repeating. "We must harness, it is time to +harness...." + +It was the voice of the groom, trying to wake him. The sun shone +straight into Pierre's face. He glanced at the dirty innyard in the +middle of which soldiers were watering their lean horses at the pump +while carts were passing out of the gate. Pierre turned away with +repugnance, and closing his eyes quickly fell back on the carriage +seat. "No, I don't want that, I don't want to see and understand that. +I want to understand what was revealing itself to me in my dream. +One second more and I should have understood it all! But what am I +to do? Harness, but how can I harness everything?" and Pierre felt +with horror that the meaning of all he had seen and thought in the +dream had been destroyed. + +The groom, the coachman, and the innkeeper told Pierre that an +officer had come with news that the French were already near +Mozhaysk and that our men were leaving it. + +Pierre got up and, having told them to harness and overtake him, +went on foot through the town. + +The troops were moving on, leaving about ten thousand wounded behind +them. There were wounded in the yards, at the windows of the houses, +and the streets were crowded with them. In the streets, around carts +that were to take some of the wounded away, shouts, curses, and +blows could be heard. Pierre offered the use of his carriage, which +had overtaken him, to a wounded general he knew, and drove with him +to Moscow. On the way Pierre was told of the death of his +brother-in-law Anatole and of that of Prince Andrew. + + + + + +CHAPTER X + + +On the thirteenth of August Pierre reached Moscow. Close to the +gates of the city he was met by Count Rostopchin's adjutant. + +"We have been looking for you everywhere," said the adjutant. "The +count wants to see you particularly. He asks you to come to him at +once on a very important matter." + +Without going home, Pierre took a cab and drove to see the Moscow +commander in chief. + +Count Rostopchin had only that morning returned to town from his +summer villa at Sokolniki. The anteroom and reception room of his +house were full of officials who had been summoned or had come for +orders. Vasilchikov and Platov had already seen the count and +explained to him that it was impossible to defend Moscow and that it +would have to be surrendered. Though this news was being concealed +from the inhabitants, the officials--the heads of the various +government departments--knew that Moscow would soon be in the +enemy's hands, just as Count Rostopchin himself knew it, and to escape +personal responsibility they had all come to the governor to ask how +they were to deal with their various departments. + +As Pierre was entering the reception room a courier from the army +came out of Rostopchin's private room. + +In answer to questions with which he was greeted, the courier made a +despairing gesture with his hand and passed through the room. + +While waiting in the reception room Pierre with weary eyes watched +the various officials, old and young, military and civilian, who +were there. They all seemed dissatisfied and uneasy. Pierre went up to +a group of men, one of whom he knew. After greeting Pierre they +continued their conversation. + +"If they're sent out and brought back again later on it will do no +harm, but as things are now one can't answer for anything." + +"But you see what he writes..." said another, pointing to a +printed sheet he held in his hand. + +"That's another matter. That's necessary for the people," said the +first. + +"What is it?" asked Pierre. + +"Oh, it's a fresh broadsheet." + +Pierre took it and began reading. + + +His Serene Highness has passed through Mozhaysk in order to join +up with the troops moving toward him and has taken up a strong +position where the enemy will not soon attack him. Forty eight guns +with ammunition have been sent him from here, and his Serene +Highness says he will defend Moscow to the last drop of blood and is +even ready to fight in the streets. Do not be upset, brothers, that +the law courts are closed; things have to be put in order, and we will +deal with villains in our own way! When the time comes I shall want +both town and peasant lads and will raise the cry a day or two +beforehand, but they are not wanted yet so I hold my peace. An ax will +be useful, a hunting spear not bad, but a three-pronged fork will be +best of all: a Frenchman is no heavier than a sheaf of rye. Tomorrow +after dinner I shall take the Iberian icon of the Mother of God to the +wounded in the Catherine Hospital where we will have some water +blessed. That will help them to get well quicker. I, too, am well now: +one of my eyes was sore but now I am on the lookout with both. + + +"But military men have told me that it is impossible to fight in the +town," said Pierre, "and that the position..." + +"Well, of course! That's what we were saying," replied the first +speaker. + +"And what does he mean by 'One of my eyes was sore but now I am on +the lookout with both'?" asked Pierre. + +"The count had a sty," replied the adjutant smiling, "and was very +much upset when I told him people had come to ask what was the +matter with him. By the by, Count," he added suddenly, addressing +Pierre with a smile, "we heard that you have family troubles and +that the countess, your wife..." + +"I have heard nothing," Pierre replied unconcernedly. "But what have +you heard?" + +"Oh, well, you know people often invent things. I only say what I +heard." + +"But what did you hear?" + +"Well, they say," continued the adjutant with the same smile, +"that the countess, your wife, is preparing to go abroad. I expect +it's nonsense...." + +"Possibly," remarked Pierre, looking about him absent-mindedly. "And +who is that?" he asked, indicating a short old man in a clean blue +peasant overcoat, with a big snow-white beard and eyebrows and a ruddy +face. + +"He? That's a tradesman, that is to say, he's the restaurant keeper, +Vereshchagin. Perhaps you have heard of that affair with the +proclamation." + +"Oh, so that is Vereshchagin!" said Pierre, looking at the firm, +calm face of the old man and seeking any indication of his being a +traitor. + +"That's not he himself, that's the father of the fellow who wrote +the proclamation," said the adjutant. "The young man is in prison +and I expect it will go hard with him." + +An old gentleman wearing a star and another official, a German +wearing a cross round his neck, approached the speaker. + +"It's a complicated story, you know," said the adjutant. "That +proclamation appeared about two months ago. The count was informed +of it. He gave orders to investigate the matter. Gabriel Ivanovich +here made the inquiries. The proclamation had passed through exactly +sixty-three hands. He asked one, 'From whom did you get it?' 'From +so-and-so.' He went to the next one. 'From whom did you get it?' and +so on till he reached Vereshchagin, a half educated tradesman, you +know, 'a pet of a trader,'" said the adjutant smiling. "They asked +him, 'Who gave it you?' And the point is that we knew whom he had it +from. He could only have had it from the Postmaster. But evidently +they had come to some understanding. He replied: 'From no one; I +made it up myself.' They threatened and questioned him, but he stuck +to that: 'I made it up myself.' And so it was reported to the count, +who sent for the man. 'From whom did you get the proclamation?' 'I +wrote it myself.' Well, you know the count," said the adjutant +cheerfully, with a smile of pride, "he flared up dreadfully--and +just think of the fellow's audacity, lying, and obstinacy!" + + "And the count wanted him to say it was from Klyucharev? I +understand!" said Pierre. + +"Not at all," rejoined the adjutant in dismay. "Klyucharev had his +own sins to answer for without that and that is why he has been +banished. But the point is that the count was much annoyed. 'How could +you have written it yourself?' said he, and he took up the Hamburg +Gazette that was lying on the table. 'Here it is! You did not write it +yourself but translated it, and translated it abominably, because +you don't even know French, you fool.' And what do you think? 'No,' +said he, 'I have not read any papers, I made it up myself.' 'If that's +so, you're a traitor and I'll have you tried, and you'll be hanged! +Say from whom you had it.' 'I have seen no papers, I made it up +myself.' And that was the end of it. The count had the father fetched, +but the fellow stuck to it. He was sent for trial and condemned to +hard labor, I believe. Now the father has come to intercede for him. +But he's a good-for-nothing lad! You know that sort of tradesman's +son, a dandy and lady-killer. He attended some lectures somewhere +and imagines that the devil is no match for him. That's the sort of +fellow he is. His father keeps a cookshop here by the Stone Bridge, +and you know there was a large icon of God Almighty painted with a +scepter in one hand and an orb in the other. Well, he took that icon +home with him for a few days and what did he do? He found some +scoundrel of a painter..." + + + + + +CHAPTER XI + + +In the middle of this fresh tale Pierre was summoned to the +commander in chief. + +When he entered the private room Count Rostopchin, puckering his +face, was rubbing his forehead and eyes with his hand. A short man was +saying something, but when Pierre entered he stopped speaking and went +out. + +"Ah, how do you do, great warrior?" said Rostopchin as soon as the +short man had left the room. "We have heard of your prowess. But +that's not the point. Between ourselves, mon cher, do you belong to +the Masons?" he went on severely, as though there were something wrong +about it which he nevertheless intended to pardon. Pierre remained +silent. "I am well informed, my friend, but I am aware that there +are Masons and I hope that you are not one of those who +on pretense of saving mankind wish to ruin Russia." + +"Yes, I am a Mason," Pierre replied. + +"There, you see, mon cher! I expect you know that Messrs. +Speranski and Magnitski have been deported to their proper place. +Mr. Klyucharev has been treated in the same way, and so have others +who on the plea of building up the temple of Solomon have tried to +destroy the temple of their fatherland. You can understand that +there are reasons for this and that I could not have exiled the +Postmaster had he not been a harmful person. It has now come to my +knowledge that you lent him your carriage for his removal from town, +and that you have even accepted papers from him for safe custody. I +like you and don't wish you any harm and--as you are only half my age- +I advise you, as a father would, to cease all communication with men +of that stamp and to leave here as soon as possible." + +"But what did Klyucharev do wrong, Count?" asked Pierre. + +"That is for me to know, but not for you to ask," shouted +Rostopchin. + +"If he is accused of circulating Napoleon's proclamation it is not +proved that he did so," said Pierre without looking at Rostopchin, +"and Vereshchagin..." + +"There we are!" Rostopchin shouted at Pierre louder than before, +frowning suddenly. "Vereshchagin is a renegade and a traitor who +will be punished as he deserves," said he with the vindictive heat +with which people speak when recalling an insult. "But I did not +summon you to discuss my actions, but to give you advice--or an +order if you prefer it. I beg you to leave the town and break off +all communication with such men as Klyucharev. And I will knock the +nonsense out of anybody"--but probably realizing that he was +shouting at Bezukhov who so far was not guilty of anything, he +added, taking Pierre's hand in a friendly manner, "We are on the eve +of a public disaster and I haven't time to be polite to everybody +who has business with me. My head is sometimes in a whirl. Well, mon +cher, what are you doing personally?" + +"Why, nothing," answered Pierre without raising his eyes or changing +the thoughtful expression of his face. + +The count frowned. + +"A word of friendly advice, mon cher. Be off as soon as you can, +that's all I have to tell you. Happy he who has ears to hear. Good-by, +my dear fellow. Oh, by the by!" he shouted through the doorway after +Pierre, "is it true that the countess has fallen into the clutches +of the holy fathers of the Society of Jesus?" + +Pierre did not answer and left Rostopchin's room more sullen and +angry than he had ever before shown himself. + +When he reached home it was already getting dark. Some eight +people had come to see him that evening: the secretary of a committee, +the colonel of his battalion, his steward, his major-domo, and various +petitioners. They all had business with Pierre and wanted decisions +from him. Pierre did not understand and was not interested in any of +these questions and only answered them in order to get rid of these +people. When left alone at last he opened and read his wife's letter. + +"They, the soldiers at the battery, Prince Andrew killed... that old +man... Simplicity is submission to God. Suffering is necessary... +the meaning of all... one must harness... my wife is getting +married... One must forget and understand..." And going to his bed +he threw himself on it without undressing and immediately fell asleep. + +When he awoke next morning the major-domo came to inform him that +a special messenger, a police officer, had come from Count +Rostopchin to know whether Count Bezukhov had left or was leaving +the town. + +A dozen persons who had business with Pierre were awaiting him in +the drawing room. Pierre dressed hurriedly and, instead of going to +see them, went to the back porch and out through the gate. + +From that time till the end of the destruction of Moscow no one of +Bezukhov's household, despite all the search they made, saw Pierre +again or knew where he was. + + + + + +CHAPTER XII + + +The Rostovs remained in Moscow till the first of September, that is, +till the eve of the enemy's entry into the city. + +After Petya had joined Obolenski's regiment of Cossacks and left for +Belaya Tserkov where that regiment was forming, the countess was +seized with terror. The thought that both her sons were at the war, +had both gone from under her wing, that today or tomorrow either or +both of them might be killed like the three sons of one of her +acquaintances, struck her that summer for the first time with cruel +clearness. She tried to get Nicholas back and wished to go herself +to join Petya, or to get him an appointment somewhere in Petersburg, +but neither of these proved possible. Petya could not return unless +his regiment did so or unless he was transferred to another regiment +on active service. Nicholas was somewhere with the army and had not +sent a word since his last letter, in which he had given a detailed +account of his meeting with Princess Mary. The countess did not +sleep at night, or when she did fall asleep dreamed that she saw her +sons lying dead. After many consultations and conversations, the count +at last devised means to tranquillize her. He got Petya transferred +from Obolenski's regiment to Bezukhov's, which was in training near +Moscow. Though Petya would remain in the service, this transfer +would give the countess the consolation of seeing at least one of +her sons under her wing, and she hoped to arrange matters for her +Petya so as not to let him go again, but always get him appointed to +places where he could not possibly take part in a battle. As long as +Nicholas alone was in danger the countess imagined that she loved +her first-born more than all her other children and even reproached +herself for it; but when her youngest: the scapegrace who had been bad +at lessons, was always breaking things in the house and making himself +a nuisance to everybody, that snub-nosed Petya with his merry black +eyes and fresh rosy cheeks where soft down was just beginning to show- +when he was thrown amid those big, dreadful, cruel men who were +fighting somewhere about something and apparently finding pleasure +in it--then his mother thought she loved him more, much more, than all +her other children. The nearer the time came for Petya to return, +the more uneasy grew the countess. She began to think she would +never live to see such happiness. The presence of Sonya, of her +beloved Natasha, or even of her husband irritated her. "What do I want +with them? I want no one but Petya," she thought. + +At the end of August the Rostovs received another letter from +Nicholas. He wrote from the province of Voronezh where he had been +sent to procure remounts, but that letter did not set the countess +at ease. Knowing that one son was out of danger she became the more +anxious about Petya. + +Though by the twentieth of August nearly all the Rostovs' +acquaintances had left Moscow, and though everybody tried to +persuade the countess to get away as quickly as possible, she would +not bear of leaving before her treasure, her adored Petya, returned. +On the twenty-eighth of August he arrived. The passionate tenderness +with which his mother received him did not please the sixteen-year-old +officer. Though she concealed from him her intention of keeping him +under her wing, Petya guessed her designs, and instinctively fearing +that he might give way to emotion when with her--might "become +womanish" as he termed it to himself--he treated her coldly, avoided +her, and during his stay in Moscow attached himself exclusively to +Natasha for whom he had always had a particularly brotherly +tenderness, almost lover-like. + +Owing to the count's customary carelessness nothing was ready for +their departure by the twenty-eighth of August and the carts that were +to come from their Ryazan and Moscow estates to remove their household +belongings did not arrive till the thirtieth. + +From the twenty-eighth till the thirty-first all Moscow was in a +bustle and commotion. Every day thousands of men wounded at Borodino +were brought in by the Dorogomilov gate and taken to various parts +of Moscow, and thousands of carts conveyed the inhabitants and their +possessions out by the other gates. In spite of Rostopchin's +broadsheets, or because of them or independently of them, the +strangest and most contradictory rumors were current in the town. Some +said that no one was to be allowed to leave the city, others on the +contrary said that all the icons had been taken out of the churches +and everybody was to be ordered to leave. Some said there had been +another battle after Borodino at which the French had been routed, +while others on the contrary reported that the Russian army bad been +destroyed. Some talked about the Moscow militia which, preceded by the +clergy, would go to the Three Hills; others whispered that Augustin +had been forbidden to leave, that traitors had been seized, that the +peasants were rioting and robbing people on their way from Moscow, and +so on. But all this was only talk; in reality (though the Council of +Fili, at which it was decided to abandon Moscow, had not yet been +held) both those who went away and those who remained behind felt, +though they did not show it, that Moscow would certainly be abandoned, +and that they ought to get away as quickly as possible and save +their belongings. It was felt that everything would suddenly break +up and change, but up to the first of September nothing had done so. +As a criminal who is being led to execution knows that he must die +immediately, but yet looks about him and straightens the cap that is +awry on his head, so Moscow involuntarily continued its wonted life, +though it knew that the time of its destruction was near when the +conditions of life to which its people were accustomed to submit would +be completely upset. + +During the three days preceding the occupation of Moscow the whole +Rostov family was absorbed in various activities. The head of the +family, Count Ilya Rostov, continually drove about the city collecting +the current rumors from all sides and gave superficial and hasty +orders at home about the preparations for their departure. + +The countess watched the things being packed, was dissatisfied +with everything, was constantly in pursuit of Petya who was always +running away from her, and was jealous of Natasha with whom he spent +all his time. Sonya alone directed the practical side of matters by +getting things packed. But of late Sonya had been particularly sad and +silent. Nicholas' letter in which he mentioned Princess Mary had +elicited, in her presence, joyous comments from the countess, who +saw an intervention of Providence in this meeting of the princess +and Nicholas. + +"I was never pleased at Bolkonski's engagement to Natasha," said the +countess, "but I always wanted Nicholas to marry the princess, and had +a presentiment that it would happen. What a good thing it would be!" + +Sonya felt that this was true: that the only possibility of +retrieving the Rostovs' affairs was by Nicholas marrying a rich woman, +and that the princess was a good match. It was very bitter for her. +But despite her grief, or perhaps just because of it, she took on +herself all the difficult work of directing the storing and packing of +their things and was busy for whole days. The count and countess +turned to her when they had any orders to give. Petya and Natasha on +the contrary, far from helping their parents, were generally a +nuisance and a hindrance to everyone. Almost all day long the house +resounded with their running feet, their cries, and their +spontaneous laughter. They laughed and were gay not because there +was any reason to laugh, but because gaiety and mirth were in their +hearts and so everything that happened was a cause for gaiety and +laughter to them. Petya was in high spirits because having left home a +boy he had returned (as everybody told him) a fine young man, +because he was at home, because he had left Belaya Tserkov where there +was no hope of soon taking part in a battle and had come to Moscow +where there was to be fighting in a few days, and chiefly because +Natasha, whose lead he always followed, was in high spirits. Natasha +was gay because she had been sad too long and now nothing reminded her +of the cause of her sadness, and because she was feeling well. She was +also happy because she had someone to adore her: the adoration of +others was a lubricant the wheels of her machine needed to make them +run freely--and Petya adored her. Above all, they were gay because +there was a war near Moscow, there would be fighting at the town +gates, arms were being given out, everybody was escaping--going away +somewhere, and in general something extraordinary was happening, and +that is always exciting, especially to the young. + + + + + +CHAPTER XIII + + +On Saturday, the thirty-first of August, everything in the +Rostovs' house seemed topsy-turvy. All the doors were open, all the +furniture was being carried out or moved about, and the mirrors and +pictures had been taken down. There were trunks in the rooms, and hay, +wrapping paper, and ropes were scattered about. The peasants and house +serfs carrying out the things were treading heavily on the parquet +floors. The yard was crowded with peasant carts, some loaded high +and already corded up, others still empty. + +The voices and footsteps of the many servants and of the peasants +who had come with the carts resounded as they shouted to one another +in the yard and in the house. The count bad been out since morning. +The countess had a headache brought on by all the noise and turmoil +and was lying down in the new sitting room with a vinegar compress +on her head. Petya was not at home, he had gone to visit a friend with +whom he meant to obtain a transfer from the militia to the active +army. Sonya was in the ballroom looking after the packing of the glass +and china. Natasha was sitting on the floor of her dismantled room +with dresses, ribbons, and scarves strewn all about her, gazing +fixedly at the floor and holding in her hands the old ball dress +(already out of fashion) which she had worn at her first Petersburg +ball. + +Natasha was ashamed of doing nothing when everyone else was so busy, +and several times that morning had tried to set to work, but her heart +was not in it, and she could not and did not know how to do anything +except with all her heart and all her might. For a while she had stood +beside Sonya while the china was being packed and tried to help, but +soon gave it up and went to her room to pack her own things. At +first she found it amusing to give away dresses and ribbons to the +maids, but when that was done and what was left had still to be +packed, she found it dull. + +"Dunyasha, you pack! You will, won't you, dear?" And when Dunyasha +willingly promised to do it all for her, Natasha sat down on the +floor, took her old ball dress, and fell into a reverie quite +unrelated to what ought to have occupied her thoughts now. She was +roused from her reverie by the talk of the maids in the next room +(which was theirs) and by the sound of their hurried footsteps going +to the back porch. Natasha got up and looked out of the window. An +enormously long row of carts full of wounded men had stopped in the +street. + +The housekeeper, the old nurse, the cooks, coachmen, maids, footmen, +postilions, and scullions stood at the gate, staring at the wounded. + +Natasha, throwing a clean pocket handkerchief over her hair and +holding an end of it in each hand, went out into the street. + +The former housekeeper, old Mavra Kuzminichna, had stepped out of +the crowd by the gate, gone up to a cart with a hood constructed of +bast mats, and was speaking to a pale young officer who lay inside. +Natasha moved a few steps forward and stopped shyly, still holding her +handkerchief, and listened to what the housekeeper was saying. + +"Then you have nobody in Moscow?" she was saying. "You would be more +comfortable somewhere in a house... in ours, for instance... the +family are leaving." + +"I don't know if it would be allowed," replied the officer in a weak +voice. "Here is our commanding officer... ask him," and he pointed +to a stout major who was walking back along the street past the row of +carts. + +Natasha glanced with frightened eyes at the face of the wounded +officer and at once went to meet the major. + +"May the wounded men stay in our house?" she asked. + +The major raised his hand to his cap with a smile. + +"Which one do you want, Ma'am'selle?" said he, screwing up his +eyes and smiling. + +Natasha quietly repeated her question, and her face and whole manner +were so serious, though she was still holding the ends of her +handkerchief, that the major ceased smiling and after some reflection- +as if considering in how far the thing was possible--replied in the +affirmative. + +"Oh yes, why not? They may," he said. + +With a slight inclination of her head, Natasha stepped back +quickly to Mavra Kuzminichna, who stood talking compassionately to the +officer. + +"They may. He says they may!" whispered Natasha. + +The cart in which the officer lay was turned into the Rostovs' yard, +and dozens of carts with wounded men began at the invitation of the +townsfolk to turn into the yards and to draw up at the entrances of +the houses in Povarskaya Street. Natasha was evidently pleased to be +dealing with new people outside the ordinary routine of her life. +She and Mavra Kuzminichna tried to get as many of the wounded as +possible into their yard. + +"Your Papa must be told, though," said Mavra Kuzminichna. + +"Never mind, never mind, what does it matter? For one day we can +move into the drawing room. They can have all our half of the house." + +"There now, young lady, you do take things into your head! Even if +we put them into the wing, the men's room, or the nurse's room, we +must ask permission." + +"Well, I'll ask." + +Natasha ran into the house and went on tiptoe through the +half-open door into the sitting room, where there was a smell of +vinegar and Hoffman's drops. + +"Are you asleep, Mamma?" + +"Oh, what sleep-?" said the countess, waking up just as she was +dropping into a doze. + +"Mamma darling!" said Natasha, kneeling by her mother and bringing +her face close to her mother's, "I am sorry, forgive me, I'll never do +it again; I woke you up! Mavra Kuzminichna has sent me: they have +brought some wounded here--officers. Will you let them come? They have +nowhere to go. I knew you'd let them come!" she said quickly all in +one breath. + +"What officers? Whom have they brought? I don't understand +anything about it," said the countess. + +Natasha laughed, and the countess too smiled slightly. + +"I knew you'd give permission... so I'll tell them," and, having +kissed her mother, Natasha got up and went to the door. + +In the hall she met her father, who had returned with bad news. + +"We've stayed too long!" said the count with involuntary vexation. +"The Club is closed and the police are leaving." + +"Papa, is it all right--I've invited some of the wounded into the +house?" said Natasha. + +"Of course it is," he answered absently. "That's not the point. I +beg you not to indulge in trifles now, but to help to pack, and +tomorrow we must go, go, go!...." + +And the count gave a similar order to the major-domo and the +servants. + +At dinner Petya having returned home told them the news he had +heard. He said the people had been getting arms in the Kremlin, and +that though Rostopchin's broadsheet had said that he would sound a +call two or three days in advance, the order had certainly already +been given for everyone to go armed to the Three Hills tomorrow, and +that there would be a big battle there. + +The countess looked with timid horror at her son's eager, excited +face as he said this. She realized that if she said a word about his +not going to the battle (she knew he enjoyed the thought of the +impending engagement) he would say something about men, honor, and the +fatherland--something senseless, masculine, and obstinate which +there would be no contradicting, and her plans would be spoiled; and +so, hoping to arrange to leave before then and take Petya with her +as their protector and defender, she did not answer him, but after +dinner called the count aside and implored him with tears to take +her away quickly, that very night if possible. With a woman's +involuntary loving cunning she, who till then had not shown any alarm, +said that she would die of fright if they did not leave that very +night. Without any pretense she was now afraid of everything. + + + + + +CHAPTER XIV + + +Madame Schoss, who had been out to visit her daughter, increased the +countess' fears still more by telling what she had seen at a spirit +dealer's in Myasnitski Street. When returning by that street she had +been unable to pass because of a drunken crowd rioting in front of the +shop. She had taken a cab and driven home by a side street and the +cabman had told her that the people were breaking open the barrels +at the drink store, having received orders to do so. + +After dinner the whole Rostov household set to work with +enthusiastic haste packing their belongings and preparing for their +departure. The old count, suddenly setting to work, kept passing +from the yard to the house and back again, shouting confused +instructions to the hurrying people, and flurrying them still more. +Petya directed things in the yard. Sonya, owing to the count's +contradictory orders, lost her head and did not know what to do. The +servants ran noisily about the house and yard, shouting and disputing. +Natasha, with the ardor characteristic of all she did suddenly set +to work too. At first her intervention in the business of packing +was received skeptically. Everybody expected some prank from her and +did not wish to obey her; but she resolutely and passionately demanded +obedience, grew angry and nearly cried because they did not heed +her, and at last succeeded in making them believe her. Her first +exploit, which cost her immense effort and established her +authority, was the packing of the carpets. The count had valuable +Gobelin tapestries and Persian carpets in the house. When Natasha +set to work two cases were standing open in the ballroom, one almost +full up with crockery, the other with carpets. There was also much +china standing on the tables, and still more was being brought in from +the storeroom. A third case was needed and servants had gone to +fetch it. + +"Sonya, wait a bit--we'll pack everything into these," said Natasha. + +"You can't, Miss, we have tried to," said the butler's assistant. + +"No, wait a minute, please." + +And Natasha began rapidly taking out of the case dishes and plates +wrapped in paper. + +"The dishes must go in here among the carpets," said she. + +"Why, it's a mercy if we can get the carpets alone into three +cases," said the butler's assistant. + +"Oh, wait, please!" And Natasha began rapidly and deftly sorting out +the things. "These aren't needed," said she, putting aside some plates +of Kiev ware. "These--yes, these must go among the carpets," she said, +referring to the Saxony china dishes. + +"Don't, Natasha! Leave it alone! We'll get it all packed," urged +Sonya reproachfully. + +"What a young lady she is!" remarked the major-domo. + +But Natasha would not give in. She turned everything out and began +quickly repacking, deciding that the inferior Russian carpets and +unnecessary crockery should not be taken at all. When everything had +been taken out of the cases, they recommenced packing, and it turned +out that when the cheaper things not worth taking had nearly all +been rejected, the valuable ones really did all go into the two cases. +Only the lid of the case containing the carpets would not shut down. A +few more things might have been taken out, but Natasha insisted on +having her own way. She packed, repacked, pressed, made the butler's +assistant and Petya--whom she had drawn into the business of +packing--press on the lid, and made desperate efforts herself. + +"That's enough, Natasha," said Sonya. "I see you were right, but +just take out the top one." + +"I won't!" cried Natasha, with one hand bolding back the hair that +hung over her perspiring face, while with the other she pressed down +the carpets. "Now press, Petya! Press, Vasilich, press hard!" she +cried. + +The carpets yielded and the lid closed; Natasha, clapping her hands, +screamed with delight and tears fell from her eyes. But this only +lasted a moment. She at once set to work afresh and they now trusted +her completely. The count was not angry even when they told him that +Natasha had countermanded an order of his, and the servants now came +to her to ask whether a cart was sufficiently loaded, and whether it +might be corded up. Thanks to Natasha's directions the work now went +on expeditiously, unnecessary things were left, and the most +valuable packed as compactly as possible. + +But hard as they all worked till quite late that night, they could +not get everything packed. The countess had fallen asleep and the +count, having put off their departure till next morning, went to bed. + +Sonya and Natasha slept in the sitting room without undressing. + +That night another wounded man was driven down the Povarskaya, and +Mavra Kuzminichna, who was standing at the gate, had him brought +into the Rostovs' yard. Mavra Kuzminichna concluded that he was a very +important man. He was being conveyed in a caleche with a raised +hood, and was quite covered by an apron. On the box beside the +driver sat a venerable old attendant. A doctor and two soldiers +followed the carriage in a cart. + +"Please come in here. The masters are going away and the whole house +will be empty," said the old woman to the old attendant. + +"Well, perhaps," said he with a sigh. "We don't expect to get him +home alive! We have a house of our own in Moscow, but it's a long +way from here, and there's nobody living in it." + +"Do us the honor to come in, there's plenty of everything in the +master's house. Come in," said Mavra Kuzminichna. "Is he very ill?" +she asked. + +The attendant made a hopeless gesture. + +"We don't expect to get him home! We must ask the doctor." + +And the old servant got down from the box and went up to the cart. + +"All right!" said the doctor. + +The old servant returned to the caleche, looked into it, shook his +head disconsolately, told the driver to turn into the yard, and +stopped beside Mavra Kuzminichna. + +"O, Lord Jesus Christ!" she murmured. + +She invited them to take the wounded man into the house. + +"The masters won't object..." she said. + +But they had to avoid carrying the man upstairs, and so they took +him into the wing and put him in the room that had been Madame +Schoss'. + +This wounded man was Prince Andrew Bolkonski. + + + + + +CHAPTER XV + + +Moscow's last day had come. It was a clear bright autumn day, a +Sunday. The church bells everywhere were ringing for service, just +as usual on Sundays. Nobody seemed yet to realize what awaited the +city. + +Only two things indicated the social condition of Moscow--the +rabble, that is the poor people, and the price of commodities. An +enormous crowd of factory hands, house serfs, and peasants, with +whom some officials, seminarists, and gentry were mingled, had gone +early that morning to the Three Hills. Having waited there for +Rostopchin who did not turn up, they became convinced that Moscow +would be surrendered, and then dispersed all about the town to the +public houses and cookshops. Prices too that day indicated the state +of affairs. The price of weapons, of gold, of carts and horses, kept +rising, but the value of paper money and city articles kept falling, +so that by midday there were instances of carters removing valuable +goods, such as cloth, and receiving in payment a half of what they +carted, while peasant horses were fetching five hundred rubles each, +and furniture, mirrors, and bronzes were being given away for nothing. + +In the Rostovs' staid old-fashioned house the dissolution of +former conditions of life was but little noticeable. As to the serfs +the only indication was that three out of their huge retinue +disappeared during the night, but nothing was stolen; and as to the +value of their possessions, the thirty peasant carts that had come +in from their estates and which many people envied proved to be +extremely valuable and they were offered enormous sums of money for +them. Not only were huge sums offered for the horses and carts, but on +the previous evening and early in the morning of the first of +September, orderlies and servants sent by wounded officers came to the +Rostovs' and wounded men dragged themselves there from the Rostovs' +and from neighboring houses where they were accommodated, entreating +the servants to try to get them a lift out of Moscow. The major-domo +to whom these entreaties were addressed, though he was sorry for the +wounded, resolutely refused, saying that he dare not even mention +the matter to the count. Pity these wounded men as one might, it was +evident that if they were given one cart there would be no reason to +refuse another, or all the carts and one's own carriages as well. +Thirty carts could not save all the wounded and in the general +catastrophe one could not disregard oneself and one's own family. So +thought the major-domo on his master's behalf. + +On waking up that morning Count Ilya Rostov left his bedroom softly, +so as not to wake the countess who had fallen asleep only toward +morning, and came out to the porch in his lilac silk dressing gown. In +the yard stood the carts ready corded. The carriages were at the front +porch. The major-domo stood at the porch talking to an elderly orderly +and to a pale young officer with a bandaged arm. On seeing the count +the major-domo made a significant and stern gesture to them both to go +away. + +"Well, Vasilich, is everything ready?" asked the count, and stroking +his bald head he looked good-naturedly at the officer and the +orderly and nodded to them. (He liked to see new faces.) + +"We can harness at once, your excellency." + +"Well, that's right. As soon as the countess wakes we'll be off, God +willing! What is it, gentlemen?" he added, turning to the officer. +"Are you staying in my house?" + +The officer came nearer and suddenly his face flushed crimson. + +"Count, be so good as to allow me... for God's sake, to get into +some corner of one of your carts! I have nothing here with me.... I +shall be all right on a loaded cart..." + +Before the officer had finished speaking the orderly made the same +request on behalf of his master. + +"Oh, yes, yes, yes!" said the count hastily. "I shall be very +pleased, very pleased. Vasilich, you'll see to it. Just unload one +or two carts. Well, what of it... do what's necessary..." said the +count, muttering some indefinite order. + +But at the same moment an expression of warm gratitude on the +officer's face had already sealed the order. The count looked around +him. In the yard, at the gates, at the window of the wings, wounded +officers and their orderlies were to be seen. They were all looking at +the count and moving toward the porch. + +"Please step into the gallery, your excellency," said the +major-domo. "What are your orders about the pictures?" + +The count went into the house with him, repeating his order not to +refuse the wounded who asked for a lift. + +"Well, never mind, some of the things can be unloaded," he added +in a soft, confidential voice, as though afraid of being overheard. + +At nine o'clock the countess woke up, and Matrena Timofeevna, who +had been her lady's maid before her marriage and now performed a +sort of chief gendarme's duty for her, came to say that Madame +Schoss was much offended and the young ladies' summer dresses could +not be left behind. On inquiry, the countess learned that Madame +Schoss was offended because her trunk had been taken down from its +cart, and all the loads were being uncorded and the luggage taken +out of the carts to make room for wounded men whom the count in the +simplicity of his heart had ordered that they should take with them. +The countess sent for her husband. + +"What is this, my dear? I hear that the luggage is being unloaded." + +"You know, love, I wanted to tell you... Countess dear... an officer +came to me to ask for a few carts for the wounded. After all, ours are +things that can be bought but think what being left behind means to +them!... Really now, in our own yard--we asked them in ourselves and +there are officers among them.... You know, I think, my dear... let +them be taken... where's the hurry?" + +The count spoke timidly, as he always did when talking of money +matters. The countess was accustomed to this tone as a precursor of +news of something detrimental to the children's interests, such as the +building of a new gallery or conservatory, the inauguration of a +private theater or an orchestra. She was accustomed always to oppose +anything announced in that timid tone and considered it her duty to do +so. + +She assumed her dolefully submissive manner and said to her husband: +"Listen to me, Count, you have managed matters so that we are +getting nothing for the house, and now you wish to throw away all our- +all the children's property! You said yourself that we have a +hundred thousand rubles' worth of things in the house. I don't +consent, my dear, I don't! Do as you please! It's the government's +business to look after the wounded; they know that. Look at the +Lopukhins opposite, they cleared out everything two days ago. That's +what other people do. It's only we who are such fools. If you have +no pity on me, have some for the children." + +Flourishing his arms in despair the count left the room without +replying. + +"Papa, what are you doing that for?" asked Natasha, who had followed +him into her mother's room. + +"Nothing! What business is it of yours?" muttered the count angrily. + +"But I heard," said Natasha. "Why does Mamma object?" + +"What business is it of yours?" cried the count. + +Natasha stepped up to the window and pondered. + +"Papa! Here's Berg coming to see us," said she, looking out of the +window. + + + + + +CHAPTER XVI + + +Berg, the Rostovs' son-in-law, was already a colonel wearing the +orders of Vladimir and Anna, and he still filled the quiet and +agreeable post of assistant to the head of the staff of the +assistant commander of the first division of the Second Army. + +On the first of September he had come to Moscow from the army. + +He had nothing to do in Moscow, but he had noticed that everyone +in the army was asking for leave to visit Moscow and had something +to do there. So he considered it necessary to ask for leave of absence +for family and domestic reasons. + +Berg drove up to his father-in-law's house in his spruce little trap +with a pair of sleek roans, exactly like those of a certain prince. He +looked attentively at the carts in the yard and while going up to +the porch took out a clean pocket handkerchief and tied a knot in it. + +From the anteroom Berg ran with smooth though impatient steps into +the drawing room, where he embraced the count, kissed the hands of +Natasha and Sonya, and hastened to inquire after "Mamma's" health. + +"Health, at a time like this?" said the count. "Come, tell us the +news! Is the army retreating or will there be another battle?" + +"God Almighty alone can decide the fate of our fatherland, Papa," +said Berg. "The army is burning with a spirit of heroism and the +leaders, so to say, have now assembled in council. No one knows what +is coming. But in general I can tell you, Papa, that such a heroic +spirit, the truly antique valor of the Russian army, which they--which +it" (he corrected himself) "has shown or displayed in the battle of +the twenty-sixth--there are no words worthy to do it justice! I tell +you, Papa" (he smote himself on the breast as a general he had heard +speaking had done, but Berg did it a trifle late for he should have +struck his breast at the words "Russian army"), "I tell you frankly +that we, the commanders, far from having to urge the men on or +anything of that kind, could hardly restrain those... those... yes, +those exploits of antique valor," he went on rapidly. "General Barclay +de Tolly risked his life everywhere at the head of the troops, I can +assure you. Our corps was stationed on a hillside. You can imagine!" + +And Berg related all that he remembered of the various tales he +had heard those days. Natasha watched him with an intent gaze that +confused him, as if she were trying to find in his face the answer +to some question. + +"Altogether such heroism as was displayed by the Russian warriors +cannot be imagined or adequately praised!" said Berg, glancing round +at Natasha, and as if anxious to conciliate her, replying to her +intent look with a smile. "'Russia is not in Moscow, she lives in +the hearts of her sons!' Isn't it so, Papa?" said he. + +Just then the countess came in from the sitting room with a weary +and dissatisfied expression. Berg hurriedly jumped up, kissed her +hand, asked about her health, and, swaying his head from side to +side to express sympathy, remained standing beside her. + +"Yes, Mamma, I tell you sincerely that these are hard and sad +times for every Russian. But why are you so anxious? You have still +time to get away...." + +"I can't think what the servants are about," said the countess, +turning to her husband. "I have just been told that nothing is ready +yet. Somebody after all must see to things. One misses Mitenka at such +times. There won't be any end to it." + +The count was about to say something, but evidently restrained +himself. He got up from his chair and went to the door. + +At that moment Berg drew out his handkerchief as if to blow his nose +and, seeing the knot in it, pondered, shaking his head sadly and +significantly. + +"And I have a great favor to ask of you, Papa," said he. + +"Hm..." said the count, and stopped. + +"I was driving past Yusupov's house just now," said Berg with a +laugh, "when the steward, a man I know, ran out and asked me whether I +wouldn't buy something. I went in out of curiosity, you know, and +there is a small chiffonier and a dressing table. You know how dear +Vera wanted a chiffonier like that and how we had a dispute about it." +(At the mention of the chiffonier and dressing table Berg +involuntarily changed his tone to one of pleasure at his admirable +domestic arrangements.) "And it's such a beauty! It pulls out and +has a secret English drawer, you know! And dear Vera has long wanted +one. I wish to give her a surprise, you see. I saw so many of those +peasant carts in your yard. Please let me have one, I will pay the man +well, and..." + +The count frowned and coughed. + +"Ask the countess, I don't give orders." + +"If it's inconvenient, please don't," said Berg. "Only I so wanted +it, for dear Vera's sake." + +"Oh, go to the devil, all of you! To the devil, the devil, the +devil..." cried the old count. "My head's in a whirl!" + +And he left the room. The countess began to cry. + +"Yes, Mamma! Yes, these are very hard times!" said Berg. + +Natasha left the room with her father and, as if finding it +difficult to reach some decision, first followed him and then ran +downstairs. + +Petya was in the porch, engaged in giving out weapons to the +servants who were to leave Moscow. The loaded carts were still +standing in the yard. Two of them had been uncorded and a wounded +officer was climbing into one of them helped by an orderly. + +"Do you know what it's about?" Petya asked Natasha. + +She understood that he meant what were their parents quarreling +about. She did not answer. + +"It's because Papa wanted to give up all the carts to the +wounded," said Petya. "Vasilich told me. I consider..." + +"I consider," Natasha suddenly almost shouted, turning her angry +face to Petya, "I consider it so horrid, so abominable, so... I +don't know what. Are we despicable Germans?" + +Her throat quivered with convulsive sobs and, afraid of weakening +and letting the force of her anger run to waste, she turned and rushed +headlong up the stairs. + +Berg was sitting beside the countess consoling her with the +respectful attention of a relative. The count, pipe in hand, was +pacing up and down the room, when Natasha, her face distorted by +anger, burst in like a tempest and approached her mother with rapid +steps. + +"It's horrid! It's abominable!" she screamed. "You can't possibly +have ordered it!" + +Berg and the countess looked at her, perplexed and frightened. The +count stood still at the window and listened. + +"Mamma, it's impossible: see what is going on in the yard!" she +cried. "They will be left!..." + +"What's the matter with you? Who are 'they'? What do you want?" + +"Why, the wounded! It's impossible, Mamma. It's monstrous!... No, +Mamma darling, it's not the thing. Please forgive me, darling.... +Mamma, what does it matter what we take away? Only look what is +going on in the yard... Mamma!... It's impossible!" + +The count stood by the window and listened without turning round. +Suddenly he sniffed and put his face closer to the window. + +The countess glanced at her daughter, saw her face full of shame for +her mother, saw her agitation, and understood why her husband did +not turn to look at her now, and she glanced round quite disconcerted. + +"Oh, do as you like! Am I hindering anyone?" she said, not +surrendering at once. + +"Mamma, darling, forgive me!" + +But the countess pushed her daughter away and went up to her +husband. + +"My dear, you order what is right.... You know I don't understand +about it," said she, dropping her eyes shamefacedly. + +"The eggs... the eggs are teaching the hen," muttered the count +through tears of joy, and he embraced his wife who was glad to hide +her look of shame on his breast. + +"Papa! Mamma! May I see to it? May I?..." asked Natasha. "We will +still take all the most necessary things." + +The count nodded affirmatively, and Natasha, at the rapid pace at +which she used to run when playing at tag, ran through the ballroom to +the anteroom and downstairs into the yard. + +The servants gathered round Natasha, but could not believe the +strange order she brought them until the count himself, in his +wife's name, confirmed the order to give up all the carts to the +wounded and take the trunks to the storerooms. When they understood +that order the servants set to work at this new task with pleasure and +zeal. It no longer seemed strange to them but on the contrary it +seemed the only thing that could be done, just as a quarter of an hour +before it had not seemed strange to anyone that the wounded should +be left behind and the goods carted away but that had seemed the +only thing to do. + +The whole household, as if to atone for not having done it sooner, +set eagerly to work at the new task of placing the wounded in the +carts. The wounded dragged themselves out of their rooms and stood +with pale but happy faces round the carts. The news that carts were to +be had spread to the neighboring houses, from which wounded men +began to come into the Rostovs' yard. Many of the wounded asked them +not to unload the carts but only to let them sit on the top of the +things. But the work of unloading, once started, could not be +arrested. It seemed not to matter whether all or only half the +things were left behind. Cases full of china, bronzes, pictures, and +mirrors that had been so carefully packed the night before now lay +about the yard, and still they went on searching for and finding +possibilities of unloading this or that and letting the wounded have +another and yet another cart. + +"We can take four more men," said the steward. "They can have my +trap, or else what is to become of them?" + +"Let them have my wardrobe cart," said the countess. "Dunyasha can +go with me in the carriage." + +They unloaded the wardrobe cart and sent it to take wounded men from +a house two doors off. The whole household, servants included, was +bright and animated. Natasha was in a state of rapturous excitement +such as she had not known for a long time. + +"What could we fasten this onto?" asked the servants, trying to +fix a trunk on the narrow footboard behind a carriage. "We must keep +at least one cart." + +"What's in it?" asked Natasha. + +"The count's books." + +"Leave it, Vasilich will put it away. It's not wanted." + +The phaeton was full of people and there was a doubt as to where +Count Peter could sit. + +"On the box. You'll sit on the box, won't you, Petya?" cried +Natasha. + +Sonya too was busy all this time, but the aim of her efforts was +quite different from Natasha's. She was putting away the things that +had to be left behind and making a list of them as the countess +wished, and she tried to get as much taken away with them as possible. + + + + + +CHAPTER XVII + + +Before two o'clock in the afternoon the Rostovs' four carriages, +packed full and with the horses harnessed, stood at the front door. +One by one the carts with the wounded had moved out of the yard. + +The caleche in which Prince Andrew was being taken attracted Sonya's +attention as it passed the front porch. With the help of a maid she +was arranging a seat for the countess in the huge high coach that +stood at the entrance. + +"Whose caleche is that?" she inquired, leaning out of the carriage +window. + +"Why, didn't you know, Miss?" replied the maid. "The wounded prince: +he spent the night in our house and is going with us." + +"But who is it? What's his name?" + +"It's our intended that was--Prince Bolkonski himself! They say he +is dying," replied the maid with a sigh. + +Sonya jumped out of the coach and ran to the countess. The countess, +tired out and already dressed in shawl and bonnet for her journey, was +pacing up and down the drawing room, waiting for the household to +assemble for the usual silent prayer with closed doors before +starting. Natasha was not in the room. + +"Mamma," said Sonya, "Prince Andrew is here, mortally wounded. He is +going with us." + +The countess opened her eyes in dismay and, seizing Sonya's arm, +glanced around. + +"Natasha?" she murmured. + +At that moment this news had only one significance for both of them. +They knew their Natasha, and alarm as to what would happen if she +heard this news stifled all sympathy for the man they both liked. + +"Natasha does not know yet, but he is going with us," said Sonya. + +"You say he is dying?" + +Sonya nodded. + +The countess put her arms around Sonya and began to cry. + +"The ways of God are past finding out!" she thought, feeling that +the Almighty Hand, hitherto unseen, was becoming manifest in all +that was now taking place. + +"Well, Mamma? Everything is ready. What's the matter?" asked +Natasha, as with animated face she ran into the room. + +"Nothing," answered the countess. "If everything is ready let us +start." + +And the countess bent over her reticule to hide her agitated face. +Sonya embraced Natasha and kissed her. + +Natasha looked at her inquiringly. + +"What is it? What has happened?" + +"Nothing... No..." + +"Is it something very bad for me? What is it?" persisted Natasha +with her quick intuition. + +Sonya sighed and made no reply. The count, Petya, Madame Schoss, +Mavra Kuzminichna, and Vasilich came into the drawing room and, having +closed the doors, they all sat down and remained for some moments +silently seated without looking at one another. + +The count was the first to rise, and with a loud sigh crossed +himself before the icon. All the others did the same. Then the count +embraced Mavra Kuzminichna and Vasilich, who were to remain in Moscow, +and while they caught at his hand and kissed his shoulder he patted +their backs lightly with some vaguely affectionate and comforting +words. The countess went into the oratory and there Sonya found her on +her knees before the icons that had been left here and there hanging +on the wall. (The most precious ones, with which some family tradition +was connected, were being taken with them.) + +In the porch and in the yard the men whom Petya had armed with +swords and daggers, with trousers tucked inside their high boots and +with belts and girdles tightened, were taking leave of those remaining +behind. + +As is always the case at a departure, much had been forgotten or put +in the wrong place, and for a long time two menservants stood one on +each side of the open door and the carriage steps waiting to help +the countess in, while maids rushed with cushions and bundles from the +house to the carriages, the caleche, the phaeton, and back again. + +"They always will forget everything!" said the countess. "Don't +you know I can't sit like that?" + +And Dunyasha, with clenched teeth, without replying but with an +aggrieved look on her face, hastily got into the coach to rearrange +the seat. + +"Oh, those servants!" said the count, swaying his head. + +Efim, the old coachman, who was the only one the countess trusted to +drive her, sat perched up high on the box and did not so much as +glance round at what was going on behind him. From thirty years' +experience he knew it would be some time yet before the order, "Be +off, in God's name!" would be given him: and he knew that even when it +was said he would be stopped once or twice more while they sent back +to fetch something that had been forgotten, and even after that he +would again be stopped and the countess herself would lean out of +the window and beg him for the love of heaven to drive carefully +down the hill. He knew all this and therefore waited calmly for what +would happen, with more patience than the horses, especially the +near one, the chestnut Falcon, who was pawing the ground and +champing his bit. At last all were seated, the carriage steps were +folded and pulled up, the door was shut, somebody was sent for a +traveling case, and the countess leaned out and said what she had to +say. Then Efim deliberately doffed his hat and began crossing himself. +The postilion and all the other servants did the same. "Off, in +God's name!" said Efim, putting on his hat. "Start!" The postilion +started the horses, the off pole horse tugged at his collar, the +high springs creaked, and the body of the coach swayed. The footman +sprang onto the box of the moving coach which jolted as it passed +out of the yard onto the uneven roadway; the other vehicles jolted +in their turn, and the procession of carriages moved up the street. In +the carriages, the caleche, and the phaeton, all crossed themselves as +they passed the church opposite the house. Those who were to remain in +Moscow walked on either side of the vehicles seeing the travelers off. + +Rarely had Natasha experienced so joyful a feeling as now, sitting +in the carriage beside the countess and gazing at the slowly +receding walls of forsaken, agitated Moscow. Occasionally she leaned +out of the carriage window and looked back and then forward at the +long train of wounded in front of them. Almost at the head of the line +she could see the raised hood of Prince Andrew's caleche. She did +not know who was in it, but each time she looked at the procession her +eyes sought that caleche. She knew it was right in front. + +In Kudrino, from the Nikitski, Presnya, and Podnovinsk Streets +came several other trains of vehicles similar to the Rostovs', and +as they passed along the Sadovaya Street the carriages and carts +formed two rows abreast. + +As they were going round the Sukharev water tower Natasha, who was +inquisitively and alertly scrutinizing the people driving or walking +past, suddenly cried out in joyful surprise: + +"Dear me! Mamma, Sonya, look, it's he!" + +"Who? Who?" + +"Look! Yes, on my word, it's Bezukhov!" said Natasha, putting her +head out of the carriage and staring at a tall, stout man in a +coachman's long coat, who from his manner of walking and moving was +evidently a gentleman in disguise, and who was passing under the +arch of the Sukharev tower accompanied by a small, sallow-faced, +beardless old man in a frieze coat. + +"Yes, it really is Bezukhov in a coachman's coat, with a +queer-looking old boy. Really," said Natasha, "look, look!" + +"No, it's not he. How can you talk such nonsense?" + +"Mamma," screamed Natasha, "I'll stake my head it's he! I assure +you! Stop, stop!" she cried to the coachman. + +But the coachman could not stop, for from the Meshchanski Street +came more carts and carriages, and the Rostovs were being shouted at +to move on and not block the way. + +In fact, however, though now much farther off than before, the +Rostovs all saw Pierre--or someone extraordinarily like him--in a +coachman's coat, going down the street with head bent and a serious +face beside a small, beardless old man who looked like a footman. That +old man noticed a face thrust out of the carriage window gazing at +them, and respectfully touching Pierre's elbow said something to him +and pointed to the carriage. Pierre, evidently engrossed in thought, +could not at first understand him. At length when he had understood +and looked in the direction the old man indicated, he recognized +Natasha, and following his first impulse stepped instantly and rapidly +toward the coach. But having taken a dozen steps he seemed to remember +something and stopped. + +Natasha's face, leaning out of the window, beamed with quizzical +kindliness. + +"Peter Kirilovich, come here! We have recognized you! This is +wonderful!" she cried, holding out her hand to him. "What are you +doing? Why are you like this?" + +Pierre took her outstretched hand and kissed it awkwardly as he +walked along beside her while the coach still moved on. + +"What is the matter, Count?" asked the countess in a surprised and +commiserating tone. + +"What? What? Why? Don't ask me," said Pierre, and looked round at +Natasha whose radiant, happy expression--of which he was conscious +without looking at her--filled him with enchantment. + +"Are you remaining in Moscow, then?" + +Pierre hesitated. + +"In Moscow?" he said in a questioning tone. "Yes, in Moscow. +Goodby!" + +"Ah, if only I were a man? I'd certainly stay with you. How +splendid!" said Natasha. "Mamma, if you'll let me, I'll stay!" + +Pierre glanced absently at Natasha and was about to say something, +but the countess interrupted him. + +"You were at the battle, we heard." + +"Yes, I was," Pierre answered. "There will be another battle +tomorrow..." he began, but Natasha interrupted him. + +"But what is the matter with you, Count? You are not like +yourself...." + +"Oh, don't ask me, don't ask me! I don't know myself. Tomorrow... +But no! Good-by, good-by!" he muttered. "It's an awful time!" and +dropping behind the carriage he stepped onto the pavement. + +Natasha continued to lean out of the window for a long time, beaming +at him with her kindly, slightly quizzical, happy smile. + + + + + +CHAPTER XVIII + + +For the last two days, ever since leaving home, Pierre had been +living in the empty house of his deceased benefactor, Bazdeev. This is +how it happened. + +When he woke up on the morning after his return to Moscow and his +interview with Count Rostopchin, he could not for some time make out +where he was and what was expected of him. When he was informed that +among others awaiting him in his reception room there was a +Frenchman who had brought a letter from his wife, the Countess Helene, +he felt suddenly overcome by that sense of confusion and +hopelessness to which he was apt to succumb. He felt that everything +was now at an end, all was in confusion and crumbling to pieces, +that nobody was right or wrong, the future held nothing, and there was +no escape from this position. Smiling unnaturally and muttering to +himself, he first sat down on the sofa in an attitude of despair, then +rose, went to the door of the reception room and peeped through the +crack, returned flourishing his arms, and took up a book. His +major-domo came in a second time to say that the Frenchman who had +brought the letter from the countess was very anxious to see him if +only for a minute, and that someone from Bazdeev's widow had called to +ask Pierre to take charge of her husband's books, as she herself was +leaving for the country. + +"Oh, yes, in a minute; wait... or no! No, of course... go and say +I will come directly," Pierre replied to the major-domo. + +But as soon as the man had left the room Pierre took up his hat +which was lying on the table and went out of his study by the other +door. There was no one in the passage. He went along the whole +length of this passage to the stairs and, frowning and rubbing his +forehead with both hands, went down as far as the first landing. The +hall porter was standing at the front door. From the landing where +Pierre stood there was a second staircase leading to the back +entrance. He went down that staircase and out into the yard. No one +had seen him. But there were some carriages waiting, and as soon as +Pierre stepped out of the gate the coachmen and the yard porter +noticed him and raised their caps to him. When he felt he was being +looked at he behaved like an ostrich which hides its head in a bush in +order not to be seen: he hung his head and quickening his pace went +down the street. + +Of all the affairs awaiting Pierre that day the sorting of Joseph +Bazdeev's books and papers appeared to him the most necessary. + + +He hired the first cab he met and told the driver to go to the +Patriarch's Ponds, where the widow Bazdeev's house was. + +Continually turning round to look at the rows of loaded carts that +were making their way from all sides out of Moscow, and balancing +his bulky body so as not to slip out of the ramshackle old vehicle, +Pierre, experiencing the joyful feeling of a boy escaping from school, +began to talk to his driver. + +The man told him that arms were being distributed today at the +Kremlin and that tomorrow everyone would be sent out beyond the +Three Hills gates and a great battle would be fought there. + +Having reached the Patriarch's Ponds Pierre found the Bazdeevs' +house, where he had not been for a long time past. He went up to the +gate. Gerasim, that sallow beardless old man Pierre had seen at +Torzhok five years before with Joseph Bazdeev, came out in answer to +his knock. + +"At home?" asked Pierre. + +"Owing to the present state of things Sophia Danilovna has gone to +the Torzhok estate with the children, your excellency." + +"I will come in all the same, I have to look through the books," +said Pierre. + +"Be so good as to step in. Makar Alexeevich, the brother of my +late master--may the kingdom of heaven be his--has remained here, +but he is in a weak state as you know," said the old servant. + +Pierre knew that Makar Alexeevich was Joseph Bazdeev's half-insane +brother and a hard drinker. + +"Yes, yes, I know. Let us go in..." said Pierre and entered the +house. + +A tall, bald-headed old man with a red nose, wearing a dressing gown +and with galoshes on his bare feet, stood in the anteroom. On seeing +Pierre he muttered something angrily and went away along the passage. + +"He was a very clever man but has now grown quite feeble, as your +honor sees," said Gerasim. "Will you step into the study?" Pierre +nodded. "As it was sealed up so it has remained, but Sophia +Danilovna gave orders that if anyone should come from you they were to +have the books." + +Pierre went into that gloomy study which he had entered with such +trepidation in his benefactor's lifetime. The room, dusty and +untouched since the death of Joseph Bazdeev was now even gloomier. + +Gerasim opened one of the shutters and left the room on tiptoe. +Pierre went round the study, approached the cupboard in which the +manuscripts were kept, and took out what had once been one of the most +important, the holy of holies of the order. This was the authentic +Scotch Acts with Bazdeev's notes and explanations. He sat down at +the dusty writing table, and, having laid the manuscripts before +him, opened them out, closed them, finally pushed them away, and +resting his head on his hand sank into meditation. + +Gerasim looked cautiously into the study several times and saw +Pierre always sitting in the same attitude. + +More than two hours passed and Gerasim took the liberty of making +a slight noise at the door to attract his attention, but Pierre did +not hear him. + +"Is the cabman to be discharged, your honor?" + +"Oh yes!" said Pierre, rousing himself and rising hurriedly. "Look +here," he added, taking Gerasim by a button of his coat and looking +down at the old man with moist, shining, and ecstatic eyes, "I say, do +you know that there is going to be a battle tomorrow?" + +"We heard so," replied the man. + +"I beg you not to tell anyone who I am, and to do what I ask you." + +"Yes, your excellency," replied Gerasim. "Will you have something to +eat?" + +"No, but I want something else. I want peasant clothes and a +pistol," said Pierre, unexpectedly blushing. + +"Yes, your excellency," said Gerasim after thinking for a moment. + +All the rest of that day Pierre spent alone in his benefactor's +study, and Gerasim heard him pacing restlessly from one corner to +another and talking to himself. And he spent the night on a bed made +up for him there. + +Gerasim, being a servant who in his time had seen many strange +things, accepted Pierre's taking up his residence in the house without +surprise, and seemed pleased to have someone to wait on. That same +evening--without even asking himself what they were wanted for--he +procured a coachman's coat and cap for Pierre, and promised to get him +the pistol next day. Makar Alexeevich came twice that evening +shuffling along in his galoshes as far as the door and stopped and +looked ingratiatingly at Pierre. But as soon as Pierre turned toward +him he wrapped his dressing gown around him with a shamefaced and +angry look and hurried away. It was when Pierre (wearing the +coachman's coat which Gerasim had procured for him and had disinfected +by steam) was on his way with the old man to buy the pistol at the +Sukharev market that he met the Rostovs. + + + + + +CHAPTER XIX + + +Kutuzov's order to retreat through Moscow to the Ryazan road was +issued at night on the first of September. + +The first troops started at once, and during the night they +marched slowly and steadily without hurry. At daybreak, however, those +nearing the town at the Dorogomilov bridge saw ahead of them masses of +soldiers crowding and hurrying across the bridge, ascending on the +opposite side and blocking the streets and alleys, while endless +masses of troops were bearing down on them from behind, and an +unreasoning hurry and alarm overcame them. They all rushed forward +to the bridge, onto it, and to the fords and the boats. Kutuzov +himself had driven round by side streets to the other side of Moscow. + +By ten o'clock in the morning of the second of September, only the +rear guard remained in the Dorogomilov suburb, where they had ample +room. The main army was on the other side of Moscow or beyond it. + +At that very time, at ten in the morning of the second of September, +Napoleon was standing among his troops on the Poklonny Hill looking at +the panorama spread out before him. From the twenty-sixth of August to +the second of September, that is from the battle of Borodino to the +entry of the French into Moscow, during the whole of that agitating, +memorable week, there had been the extraordinary autumn weather that +always comes as a surprise, when the sun hangs low and gives more heat +than in spring, when everything shines so brightly in the rare clear +atmosphere that the eyes smart, when the lungs are strengthened and +refreshed by inhaling the aromatic autumn air, when even the nights +are warm, and when in those dark warm nights, golden stars startle and +delight us continually by falling from the sky. + +At ten in the morning of the second of September this weather +still held. + +The brightness of the morning was magical. Moscow seen from the +Poklonny Hill lay spaciously spread out with her river, her gardens, +and her churches, and she seemed to be living her usual life, her +cupolas glittering like stars in the sunlight. + +The view of the strange city with its peculiar architecture, such as +he had never seen before, filled Napoleon with the rather envious +and uneasy curiosity men feel when they see an alien form of life that +has no knowledge of them. This city was evidently living with the full +force of its own life. By the indefinite signs which, even at a +distance, distinguish a living body from a dead one, Napoleon from the +Poklonny Hill perceived the throb of life in the town and felt, as +it were, the breathing of that great and beautiful body. + +Every Russian looking at Moscow feels her to be a mother; every +foreigner who sees her, even if ignorant of her significance as the +mother city, must feel her feminine character, and Napoleon felt it. + +"Cette ville asiatique aux innombrables eglises, Moscou la sainte. +La voila done enfin, cette fameuse ville! Il etait temps,"* said he, +and dismounting he ordered a plan of Moscow to be spread out before +him, and summoned Lelorgne d'Ideville, the interpreter. + + +*"That Asiatic city of the innumerable churches, holy Moscow! Here +it is then at last, that famous city. It was high time." + + +"A town captured by the enemy is like a maid who has lost her +honor," thought he (he had said so to Tuchkov at Smolensk). From +that point of view he gazed at the Oriental beauty he had not seen +before. It seemed strange to him that his long-felt wish, which had +seemed unattainable, had at last been realized. In the clear morning +light he gazed now at the city and now at the plan, considering its +details, and the assurance of possessing it agitated and awed him. + +"But could it be otherwise?" he thought. "Here is this capital at my +feet. Where is Alexander now, and of what is he thinking? A strange, +beautiful, and majestic city; and a strange and majestic moment! In +what light must I appear to them!" thought he, thinking of his troops. +"Here she is, the reward for all those fainthearted men," he +reflected, glancing at those near him and at the troops who were +approaching and forming up. "One word from me, one movement of my +hand, and that ancient capital of the Tsars would perish. But my +clemency is always ready to descend upon the vanquished. I must be +magnanimous and truly great. But no, it can't be true that I am in +Moscow," he suddenly thought. "Yet here she is lying at my feet, +with her golden domes and crosses scintillating and twinkling in the +sunshine. But I shall spare her. On the ancient monuments of barbarism +and despotism I will inscribe great words of justice and mercy.... +It is just this which Alexander will feel most painfully, I know him." +(It seemed to Napoleon that the chief import of what was taking +place lay in the personal struggle between himself and Alexander.) +"From the height of the Kremlin--yes, there is the Kremlin, yes--I +will give them just laws; I will teach them the meaning of true +civilization, I will make generations of boyars remember their +conqueror with love. I will tell the deputation that I did not, and do +not, desire war, that I have waged war only against the false policy +of their court; that I love and respect Alexander and that in Moscow I +will accept terms of peace worthy of myself and of my people. I do not +wish to utilize the fortunes of war to humiliate an honored monarch. +'Boyars,' I will say to them, 'I do not desire war, I desire the peace +and welfare of all my subjects.' However, I know their presence will +inspire me, and I shall speak to them as I always do: clearly, +impressively, and majestically. But can it be true that I am in +Moscow? Yes, there she lies." + +"Qu'on m'amene les boyars,"* said he to his suite. + + +*"Bring the boyars to me." + + +A general with a brilliant suite galloped off at once to fetch the +boyars. + +Two hours passed. Napoleon had lunched and was again standing in the +same place on the Poklonny Hill awaiting the deputation. His speech to +the boyars had already taken definite shape in his imagination. That +speech was full of dignity and greatness as Napoleon understood it. + +He was himself carried away by the tone of magnanimity he intended +to adopt toward Moscow. In his imagination he appointed days for +assemblies at the palace of the Tsars, at which Russian notables and +his own would mingle. He mentally appointed a governor, one who +would win the hearts of the people. Having learned that there were +many charitable institutions in Moscow he mentally decided that he +would shower favors on them all. He thought that, as in Africa he +had to put on a burnoose and sit in a mosque, so in Moscow he must +be beneficent like the Tsars. And in order finally to touch the hearts +of the Russians--and being like all Frenchmen unable to imagine +anything sentimental without a reference to ma chere, ma tendre, ma +pauvre mere* --he decided that he would place an inscription on all +these establishments in large letters: "This establishment is +dedicated to my dear mother." Or no, it should be simply: Maison de ma +Mere,*[2] he concluded. "But am I really in Moscow? Yes, here it +lies before me, but why is the deputation from the city so long in +appearing?" he wondered. + + +*"My dear, my tender, my poor mother." + +*[2] "House of my Mother." + + +Meanwhile an agitated consultation was being carried on in +whispers among his generals and marshals at the rear of his suite. +Those sent to fetch the deputation had returned with the news that +Moscow was empty, that everyone had left it. The faces of those who +were not conferring together were pale and perturbed. They were not +alarmed by the fact that Moscow had been abandoned by its +inhabitants (grave as that fact seemed), but by the question how to +tell the Emperor--without putting him in the terrible position of +appearing ridiculous--that he had been awaiting the boyars so long +in vain: that there were drunken mobs left in Moscow but no one +else. Some said that a deputation of some sort must be scraped +together, others disputed that opinion and maintained that the Emperor +should first be carefully and skillfully prepared, and then told the +truth. + +"He will have to be told, all the same," said some gentlemen of +the suite. "But, gentlemen..." + +The position was the more awkward because the Emperor, meditating +upon his magnanimous plans, was pacing patiently up and down before +the outspread map, occasionally glancing along the road to Moscow from +under his lifted hand with a bright and proud smile. + +"But it's impossible..." declared the gentlemen of the suite, +shrugging their shoulders but not venturing to utter the implied word- +le ridicule... + +At last the Emperor, tired of futile expectation, his actor's +instinct suggesting to him that the sublime moment having been too +long drawn out was beginning to lose its sublimity, gave a sign with +his hand. A single report of a signaling gun followed, and the troops, +who were already spread out on different sides of Moscow, moved into +the city through Tver, Kaluga, and Dorogomilov gates. Faster and +faster, vying with one another, they moved at the double or at a trot, +vanishing amid the clouds of dust they raised and making the air +ring with a deafening roar of mingling shouts. + +Drawn on by the movement of his troops Napoleon rode with them as +far as the Dorogomilov gate, but there again stopped and, +dismounting from his horse, paced for a long time by the +Kammer-Kollezski rampart, awaiting the deputation. + + + + + +CHAPTER XX + +Meanwhile Moscow was empty. There were still people in it, perhaps a +fiftieth part of its former inhabitants had remained, but it was +empty. It was empty in the sense that a dying queenless hive is empty. + +In a queenless hive no life is left though to a superficial glance +it seems as much alive as other hives. + +The bees circle round a queenless hive in the hot beams of the +midday sun as gaily as around the living hives; from a distance it +smells of honey like the others, and bees fly in and out in the same +way. But one has only to observe that hive to realize that there is no +longer any life in it. The bees do not fly in the same way, the +smell and the sound that meet the beekeeper are not the same. To the +beekeeper's tap on the wall of the sick hive, instead of the former +instant unanimous humming of tens of thousands of bees with their +abdomens threateningly compressed, and producing by the rapid +vibration of their wings an aerial living sound, the only reply is a +disconnected buzzing from different parts of the deserted hive. From +the alighting board, instead of the former spirituous fragrant smell +of honey and venom, and the warm whiffs of crowded life, comes an odor +of emptiness and decay mingling with the smell of honey. There are +no longer sentinels sounding the alarm with their abdomens raised, and +ready to die in defense of the hive. There is no longer the measured +quiet sound of throbbing activity, like the sound of boiling water, +but diverse discordant sounds of disorder. In and out of the hive long +black robber bees smeared with honey fly timidly and shiftily. They do +not sting, but crawl away from danger. Formerly only bees laden with +honey flew into the hive, and they flew out empty; now they fly out +laden. The beekeeper opens the lower part of the hive and peers in. +Instead of black, glossy bees--tamed by toil, clinging to one +another's legs and drawing out the wax, with a ceaseless hum of labor- +that used to hang in long clusters down to the floor of the hive, +drowsy shriveled bees crawl about separately in various directions +on the floor and walls of the hive. Instead of a neatly glued floor, +swept by the bees with the fanning of their wings, there is a floor +littered with bits of wax, excrement, dying bees scarcely moving their +legs, and dead ones that have not been cleared away. + +The beekeeper opens the upper part of the hive and examines the +super. Instead of serried rows of bees sealing up every gap in the +combs and keeping the brood warm, he sees the skillful complex +structures of the combs, but no longer in their former state of +purity. All is neglected and foul. Black robber bees are swiftly and +stealthily prowling about the combs, and the short home bees, +shriveled and listless as if they were old, creep slowly about without +trying to hinder the robbers, having lost all motive and all sense +of life. Drones, bumblebees, wasps, and butterflies knock awkwardly +against the walls of the hive in their flight. Here and there among +the cells containing dead brood and honey an angry buzzing can +sometimes be heard. Here and there a couple of bees, by force of habit +and custom cleaning out the brood cells, with efforts beyond their +strength laboriously drag away a dead bee or bumblebee without knowing +why they do it. In another corner two old bees are languidly fighting, +or cleaning themselves, or feeding one another, without themselves +knowing whether they do it with friendly or hostile intent. In a third +place a crowd of bees, crushing one another, attack some victim and +fight and smother it, and the victim, enfeebled or killed, drops +from above slowly and lightly as a feather, among the heap of corpses. +The keeper opens the two center partitions to examine the brood cells. +In place of the former close dark circles formed by thousands of +bees sitting back to back and guarding the high mystery of generation, +he sees hundreds of dull, listless, and sleepy shells of bees. They +have almost all died unawares, sitting in the sanctuary they had +guarded and which is now no more. They reek of decay and death. Only a +few of them still move, rise, and feebly fly to settle on the +enemy's hand, lacking the spirit to die stinging him; the rest are +dead and fall as lightly as fish scales. The beekeeper closes the +hive, chalks a mark on it, and when he has time tears out its contents +and burns it clean. + +So in the same way Moscow was empty when Napoleon, weary, uneasy, +and morose, paced up and down in front of the Kammer-Kollezski +rampart, awaiting what to his mind was a necessary, if but formal, +observance of the proprieties--a deputation. + +In various corners of Moscow there still remained a few people +aimlessly moving about, following their old habits and hardly aware of +what they were doing. + +When with due circumspection Napoleon was informed that Moscow was +empty, he looked angrily at his informant, turned away, and silently +continued to walk to and fro. + +"My carriage!" he said. + +He took his seat beside the aide-de-camp on duty and drove into +the suburb. "Moscow deserted!" he said to himself. "What an incredible +event!" + +He did not drive into the town, but put up at an inn in the +Dorogomilov suburb. + +The coup de theatre had not come off. + + + + + +CHAPTER XXI + + +The Russian troops were passing through Moscow from two o'clock at +night till two in the afternoon and bore away with them the wounded +and the last of the inhabitants who were leaving. + +The greatest crush during the movement of the troops took place at +the Stone, Moskva, and Yauza bridges. + +While the troops, dividing into two parts when passing around the +Kremlin, were thronging the Moskva and the Stone bridges, a great many +soldiers, taking advantage of the stoppage and congestion, turned back +from the bridges and slipped stealthily and silently past the church +of Vasili the Beatified and under the Borovitski gate, back up the +hill to the Red Square where some instinct told them they could easily +take things not belonging to them. Crowds of the kind seen at cheap +sales filled all the passages and alleys of the Bazaar. But there were +no dealers with voices of ingratiating affability inviting customers +to enter; there were no hawkers, nor the usual motley crowd of +female purchasers--but only soldiers, in uniforms and overcoats though +without muskets, entering the Bazaar empty-handed and silently +making their way out through its passages with bundles. Tradesmen +and their assistants (of whom there were but few) moved about among +the soldiers quite bewildered. They unlocked their shops and locked +them up again, and themselves carried goods away with the help their +assistants. On the square in front of the Bazaar were drummers beating +the muster call. But the roll of the drums did not make the looting +soldiers run in the direction of the drum as formerly, but made +them, on the contrary, run farther away. Among the soldiers in the +shops and passages some men were to be seen in gray coats, with +closely shaven heads. Two officers, one with a scarf over his +uniform and mounted on a lean, dark-gray horse, the other in an +overcoat and on foot, stood at the corner of Ilyinka Street, +talking. A third officer galloped up to them. + +"The general orders them all to be driven out at once, without fail. +This is outrageous! Half the men have dispersed." + +"Where are you off to?... Where?..." he shouted to three infantrymen +without muskets who, holding up the skirts of their overcoats, were +slipping past him into the Bazaar passage. "Stop, you rascals!" + +"But how are you going to stop them?" replied another officer. +"There is no getting them together. The army should push on before the +rest bolt, that's all!" + +"How can one push on? They are stuck there, wedged on the bridge, +and don't move. Shouldn't we put a cordon round to prevent the rest +from running away?" + +"Come, go in there and drive them out!" shouted the senior officer. + +The officer in the scarf dismounted, called up a drummer, and went +with him into the arcade. Some soldiers started running away in a +group. A shopkeeper with red pimples on his cheeks near the nose, +and a calm, persistent, calculating expression on his plump face, +hurriedly and ostentatiously approached the officer, swinging his +arms. + +"Your honor!" said he. "Be so good as to protect us! We won't grudge +trifles, you are welcome to anything--we shall be delighted! +Pray!... I'll fetch a piece of cloth at once for such an honorable +gentleman, or even two pieces with pleasure. For we feel how it is; +but what's all this--sheer robbery! If you please, could not guards be +placed if only to let us close the shop...." + +Several shopkeepers crowded round the officer. + +"Eh, what twaddle!" said one of them, a thin, stern-looking man. +"When one's head is gone one doesn't weep for one's hair! Take what +any of you like!" And flourishing his arm energetically he turned +sideways to the officer. + +"It's all very well for you, Ivan Sidorych, to talk," said the first +tradesman angrily. "Please step inside, your honor!" + +"Talk indeed!" cried the thin one. "In my three shops here I have +a hundred thousand rubles' worth of goods. Can they be saved when +the army has gone? Eh, what people! 'Against God's might our hands +can't fight.'" + +"Come inside, your honor!" repeated the tradesman, bowing. + +The officer stood perplexed and his face showed indecision. + +"It's not my business!" he exclaimed, and strode on quickly down one +of the passages. + +From one open shop came the sound of blows and vituperation, and +just as the officer came up to it a man in a gray coat with a shaven +head was flung out violently. + +This man, bent double, rushed past the tradesman and the officer. +The officer pounced on the soldiers who were in the shops, but at that +moment fearful screams reached them from the huge crowd on the +Moskva bridge and the officer ran out into the square. + +"What is it? What is it?" he asked, but his comrade was already +galloping off past Vasili the Beatified in the direction from which +the screams came. + +The officer mounted his horse and rode after him. When he reached +the bridge he saw two unlimbered guns, the infantry crossing the +bridge, several overturned carts, and frightened and laughing faces +among the troops. Beside the cannon a cart was standing to which two +horses were harnessed. Four borzois with collars were pressing close +to the wheels. The cart was loaded high, and at the very top, beside a +child's chair with its legs in the air, sat a peasant woman uttering +piercing and desperate shrieks. He was told by his fellow officers +that the screams of the crowd and the shrieks of the woman were due to +the fact that General Ermolov, coming up to the crowd and learning +that soldiers were dispersing among the shops while crowds of +civilians blocked the bridge, had ordered two guns to be unlimbered +and made a show of firing at the bridge. The crowd, crushing one +another, upsetting carts, and shouting and squeezing desperately, +had cleared off the bridge and the troops were now moving forward. + + + + + +CHAPTER XXII + + +Meanwhile, the city itself was deserted. There was hardly anyone +in the streets. The gates and shops were all closed, only here and +there round the taverns solitary shouts or drunken songs could be +heard. Nobody drove through the streets and footsteps were rarely +heard. The Povarskaya was quite still and deserted. The huge courtyard +of the Rostovs' house was littered with wisps of hay and with dung +from the horses, and not a soul was to be seen there. In the great +drawing room of the house, which had been left with all it +contained, were two people. They were the yard porter Ignat, and the +page boy Mishka, Vasilich's grandson who had stayed in Moscow with his +grandfather. Mishka had opened the clavichord and was strumming on +it with one finger. The yard porter, his arms akimbo, stood smiling +with satisfaction before the large mirror. + +"Isn't it fine, eh, Uncle Ignat?" said the boy, suddenly beginning +to strike the keyboard with both hands. + +"Only fancy!" answered Ignat, surprised at the broadening grin on +his face in the mirror. + +"Impudence! Impudence!" they heard behind them the voice of Mavra +Kuzminichna who had entered silently. "How he's grinning, the fat mug! +Is that what you're here for? Nothing's cleared away down there and +Vasilich is worn out. Just you wait a bit!" + +Ignat left off smiling, adjusted his belt, and went out of the +room with meekly downcast eyes. + +"Aunt, I did it gently," said the boy. + +"I'll give you something gently, you monkey you!" cried Mavra +Kuzminichna, raising her arm threateningly. "Go and get the samovar to +boil for your grandfather." + +Mavra Kuzminichna flicked the dust off the clavichord and closed it, +and with a deep sigh left the drawing room and locked its main door. + +Going out into the yard she paused to consider where she should go +next--to drink tea in the servants' wing with Vasilich, or into the +storeroom to put away what still lay about. + +She heard the sound of quick footsteps in the quiet street. +Someone stopped at the gate, and the latch rattled as someone tried to +open it. Mavra Kuzminichna went to the gate. + +"Who do you want?" + +"The count--Count Ilya Andreevich Rostov." + +"And who are you?" + +"An officer, I have to see him," came the reply in a pleasant, +well-bred Russian voice. + +Mavra Kuzminichna opened the gate and an officer of eighteen, with +the round face of a Rostov, entered the yard. + +"They have gone away, sir. Went away yesterday at vespertime," +said Mavra Kuzminichna cordially. + +The young officer standing in the gateway, as if hesitating +whether to enter or not, clicked his tongue. + +"Ah, how annoying!" he muttered. "I should have come yesterday.... +Ah, what a pity." + +Meanwhile, Mavra Kuzminichna was attentively and sympathetically +examining the familiar Rostov features of the young man's face, his +tattered coat and trodden-down boots. + +"What did you want to see the count for?" she asked. + +"Oh well... it can't be helped!" said he in a tone of vexation and +placed his hand on the gate as if to leave. + +He again paused in indecision. + +"You see," he suddenly said, "I am a kinsman of the count's and he +has been very kind to me. As you see" (he glanced with an amused air +and good-natured smile at his coat and boots) "my things are worn +out and I have no money, so I was going to ask the count..." + +Mavra Kuzminichna did not let him finish. + +"Just wait a minute, sir. One little moment," said she. + +And as soon as the officer let go of the gate handle she turned and, +hurrying away on her old legs, went through the back yard to the +servants' quarters. + +While Mavra Kuzminichna was running to her room the officer walked +about the yard gazing at his worn-out boots with lowered head and a +faint smile on his lips. "What a pity I've missed Uncle! What a nice +old woman! Where has she run off to? And how am I to find the +nearest way to overtake my regiment, which must by now be getting near +the Rogozhski gate?" thought he. Just then Mavra Kuzminichna +appeared from behind the corner of the house with a frightened yet +resolute look, carrying a rolled-up check kerchief in her hand. +While still a few steps from the officer she unfolded the kerchief and +took out of it a white twenty-five-ruble assignat and hastily handed +it to him. + +"If his excellency had been at home, as a kinsman he would of +course... but as it is..." + +Mavra Kuzminichna grew abashed and confused. The officer did not +decline, but took the note quietly and thanked her. + +"If the count had been at home..." Mavra Kuzminichna went on +apologetically. "Christ be with you, sir! May God preserve you!" +said she, bowing as she saw him out. + +Swaying his head and smiling as if amused at himself, the officer +ran almost at a trot through the deserted streets toward the Yauza +bridge to overtake his regiment. + +But Mavra Kuzminichna stood at the closed gate for some time with +moist eyes, pensively swaying her head and feeling an unexpected +flow of motherly tenderness and pity for the unknown young officer. + + + + + +CHAPTER XXIII + + +From an unfinished house on the Varvarka, the ground floor of +which was a dramshop, came drunken shouts and songs. On benches +round the tables in a dirty little room sat some ten factory hands. +Tipsy and perspiring, with dim eyes and wide-open mouths, they were +all laboriously singing some song or other. They were singing +discordantly, arduously, and with great effort, evidently not +because they wished to sing, but because they wanted to show they were +drunk and on a spree. One, a tall, fair-haired lad in a clean blue +coat, was standing over the others. His face with its fine straight +nose would have been handsome had it not been for his thin, +compressed, twitching lips and dull, gloomy, fixed eyes. Evidently +possessed by some idea, he stood over those who were singing, and +solemnly and jerkily flourished above their heads his white arm with +the sleeve turned up to the elbow, trying unnaturally to spread out +his dirty fingers. The sleeve of his coat kept slipping down and he +always carefully rolled it up again with his left hand, as if it +were most important that the sinewy white arm he was flourishing +should be bare. In the midst of the song cries were heard, and +fighting and blows in the passage and porch. The tall lad waved his +arm. + +"Stop it!" he exclaimed peremptorily. "There's a fight, lads!" +And, still rolling up his sleeve, he went out to the porch. + +The factory hands followed him. These men, who under the +leadership of the tall lad were drinking in the dramshop that morning, +had brought the publican some skins from the factory and for this +had had drink served them. The blacksmiths from a neighboring +smithy, hearing the sounds of revelry in the tavern and supposing it +to have been broken into, wished to force their way in too and a fight +in the porch had resulted. + +The publican was fighting one of the smiths at the door, and when +the workmen came out the smith, wrenching himself free from the tavern +keeper, fell face downward on the pavement. + +Another smith tried to enter the doorway, pressing against the +publican with his chest. + +The lad with the turned-up sleeve gave the smith a blow in the +face and cried wildly: "They're fighting us, lads!" + +At that moment the first smith got up and, scratching his bruised +face to make it bleed, shouted in a tearful voice: "Police! Murder!... +They've killed a man, lads!" + +"Oh, gracious me, a man beaten to death--killed!..." screamed a +woman coming out of a gate close by. + +A crowd gathered round the bloodstained smith. + +"Haven't you robbed people enough--taking their last shirts?" said a +voice addressing the publican. "What have you killed a man for, you +thief?" + +The tall lad, standing in the porch, turned his bleared eyes from +the publican to the smith and back again as if considering whom he +ought to fight now. + +"Murderer!" he shouted suddenly to the publican. "Bind him, lads!" + +"I daresay you would like to bind me!" shouted the publican, pushing +away the men advancing on him, and snatching his cap from his head +he flung it on the ground. + +As if this action had some mysterious and menacing significance, the +workmen surrounding the publican paused in indecision. + +"I know the law very well, mates! I'll take the matter to the +captain of police. You think I won't get to him? Robbery is not +permitted to anybody now a days!" shouted the publican, picking up his +cap. + +"Come along then! Come along then!" the publican and the tall +young fellow repeated one after the other, and they moved up the +street together. + +The bloodstained smith went beside them. The factory hands and +others followed behind, talking and shouting. + +At the corner of the Moroseyka, opposite a large house with closed +shutters and bearing a bootmaker's signboard, stood a score of thin, +worn-out, gloomy-faced bootmakers, wearing overalls and long +tattered coats. + +"He should pay folks off properly," a thin workingman, with frowning +brows and a straggly beard, was saying. + +"But he's sucked our blood and now he thinks he's quit of us. He's +been misleading us all the week and now that he's brought us to this +pass he's made off." + +On seeing the crowd and the bloodstained man the workman ceased +speaking, and with eager curiosity all the bootmakers joined the +moving crowd. + +"Where are all the folks going?" + +"Why, to the police, of course!" + +"I say, is it true that we have been beaten?" "And what did you +think? Look what folks are saying." + +Questions and answers were heard. The publican, taking advantage +of the increased crowd, dropped behind and returned to his tavern. + +The tall youth, not noticing the disappearance of his foe, waved his +bare arm and went on talking incessantly, attracting general attention +to himself. It was around him that the people chiefly crowded, +expecting answers from him to the questions that occupied all their +minds. + +"He must keep order, keep the law, that's what the government is +there for. Am I not right, good Christians?" said the tall youth, with +a scarcely perceptible smile. "He thinks there's no government! How +can one do without government? Or else there would be plenty who'd rob +us." + +"Why talk nonsense?" rejoined voices in the crowd. "Will they give +up Moscow like this? They told you that for fun, and you believed +it! Aren't there plenty of troops on the march? Let him in, indeed! +That's what the government is for. You'd better listen to what +people are saying," said some of the mob pointing to the tall youth. + +By the wall of China-Town a smaller group of people were gathered +round a man in a frieze coat who held a paper in his hand. + +"An ukase, they are reading an ukase! Reading an ukase!" cried +voices in the crowd, and the people rushed toward the reader. + +The man in the frieze coat was reading the broadsheet of August 31 +When the crowd collected round him he seemed confused, but at the +demand of the tall lad who had pushed his way up to him, he began in a +rather tremulous voice to read the sheet from the beginning. + +"Early tomorrow I shall go to his Serene Highness," he read +("Sirin Highness," said the tall fellow with a triumphant smile on his +lips and a frown on his brow), "to consult with him to act, and to aid +the army to exterminate these scoundrels. We too will take part..." +the reader went on, and then paused ("Do you see," shouted the youth +victoriously, "he's going to clear up the whole affair for +you...."), "in destroying them, and will send these visitors to the +devil. I will come back to dinner, and we'll set to work. We will +do, completely do, and undo these scoundrels." + +The last words were read out in the midst of complete silence. The +tall lad hung his head gloomily. It was evident that no one had +understood the last part. In particular, the words "I will come back +to dinner," evidently displeased both reader and audience. The +people's minds were tuned to a high pitch and this was too simple +and needlessly comprehensible--it was what any one of them might +have said and therefore was what an ukase emanating from the highest +authority should not say. + +They all stood despondent and silent. The tall youth moved his +lips and swayed from side to side. + +"We should ask him... that's he himself?"... "Yes, ask him +indeed!... Why not? He'll explain"... voices in the rear of the +crowd were suddenly heard saying, and the general attention turned +to the police superintendent's trap which drove into the square +attended by two mounted dragoons. + +The superintendent of police, who had that morning by Count +Rostopchin's orders to burn the barges and had in connection with that +matter acquired a large sum of money which was at that moment in his +pocket, on seeing a crowd bearing down upon him told his coachman to +stop. + +"What people are these?" he shouted to the men, who were moving +singly and timidly in the direction of his trap. + +"What people are these?" he shouted again, receiving no answer. + +"Your honor..." replied the shopman in the frieze coat, "your honor, +in accord with the proclamation of his highest excellency the count, +they desire to serve, not sparing their lives, and it is not any +kind of riot, but as his highest excellence said..." + +"The count has not left, he is here, and an order will be issued +concerning you," said the superintendent of police. "Go on!" he +ordered his coachman. + +The crowd halted, pressing around those who had heard what the +superintendent had said, and looking at the departing trap. + +The superintendent of police turned round at that moment with a +scared look, said something to his coachman, and his horses +increased their speed. + +"It's a fraud, lads! Lead the way to him, himself!" shouted the tall +youth. "Don't let him go, lads! Let him answer us! Keep him!" +shouted different people and the people dashed in pursuit of the trap. + +Following the superintendent of police and talking loudly the +crowd went in the direction of the Lubyanka Street. + +"There now, the gentry and merchants have gone away and left us to +perish. Do they think we're dogs?" voices in the crowd were heard +saying more and more frequently. + + + + + +CHAPTER XXIV + + +On the evening of the first of September, after his interview with +Kutuzov, Count Rostopchin had returned to Moscow mortified and +offended because he had not been invited to attend the council of war, +and because Kutuzov had paid no attention to his offer to take part in +the defense of the city; amazed also at the novel outlook revealed +to him at the camp, which treated the tranquillity of the capital +and its patriotic fervor as not merely secondary but quite +irrelevant and unimportant matters. Distressed, offended, and +surprised by all this, Rostopchin had returned to Moscow. After supper +he lay down on a sofa without undressing, and was awakened soon +after midnight by a courier bringing him a letter from Kutuzov. This +letter requested the count to send police officers to guide the troops +through the town, as the army was retreating to the Ryazan road beyond +Moscow. This was not news to Rostopchin. He had known that Moscow +would be abandoned not merely since his interview the previous day +with Kutuzov on the Poklonny Hill but ever since the battle of +Borodino, for all the generals who came to Moscow after that battle +had said unanimously that it was impossible to fight another battle, +and since then the government property had been removed every night, +and half the inhabitants had left the city with Rostopchin's own +permission. Yet all the same this information astonished and irritated +the count, coming as it did in the form of a simple note with an order +from Kutuzov, and received at night, breaking in on his beauty sleep. + +When later on in his memoirs Count Rostopchin explained his +actions at this time, he repeatedly says that he was then actuated +by two important considerations: to maintain tranquillity in Moscow +and expedite the departure of the inhabitants. If one accepts this +twofold aim all Rostopchin's actions appear irreproachable. "Why +were the holy relics, the arms, ammunition, gunpowder, and stores of +corn not removed? Why were thousands of inhabitants deceived into +believing that Moscow would not be given up--and thereby ruined?" +"To presence the tranquillity of the city," explains Count Rostopchin. +"Why were bundles of useless papers from the government offices, and +Leppich's balloon and other articles removed?" "To leave the town +empty," explains Count Rostopchin. One need only admit that public +tranquillity is in danger and any action finds a justification. + +All the horrors of the reign of terror were based only on solicitude +for public tranquillity. + +On what, then, was Count Rostopchin's fear for the tranquillity of +Moscow based in 1812? What reason was there for assuming any +probability of an uprising in the city? The inhabitants were leaving +it and the retreating troops were filling it. Why should that cause +the masses to riot? + +Neither in Moscow nor anywhere in Russia did anything resembling +an insurrection ever occur when the enemy entered a town. More than +ten thousand people were still in Moscow on the first and second of +September, and except for a mob in the governor's courtyard, assembled +there at his bidding, nothing happened. It is obvious that there would +have been even less reason to expect a disturbance among the people if +after the battle of Borodino, when the surrender of Moscow became +certain or at least probable, Rostopchin instead of exciting the +people by distributing arms and broadsheets had taken steps to +remove all the holy relics, the gunpowder, munitions, and money, and +had told the population plainly that the town would be abandoned. + +Rostopchin, though he had patriotic sentiments, was a sanguine and +impulsive man who had always moved in the highest administrative +circles and had no understanding at all of the people he supposed +himself to be guiding. Ever since the enemy's entry into Smolensk he +had in imagination been playing the role of director of the popular +feeling of "the heart of Russia." Not only did it seem to him (as to +all administrators) that he controlled the external actions of +Moscow's inhabitants, but he also thought he controlled their mental +attitude by means of his broadsheets and posters, written in a +coarse tone which the people despise in their own class and do not +understand from those in authority. Rostopchin was so pleased with the +fine role of leader of popular feeling, and had grown so used to it, +that the necessity of relinquishing that role and abandoning Moscow +without any heroic display took him unawares and he suddenly felt +the ground slip away from under his feet, so that he positively did +not know what to do. Though he knew it was coming, he did not till the +last moment wholeheartedly believe that Moscow would be abandoned, and +did not prepare for it. The inhabitants left against his wishes. If +the government offices were removed, this was only done on the +demand of officials to whom the count yielded reluctantly. He was +absorbed in the role he had created for himself. As is often the +case with those gifted with an ardent imagination, though he had +long known that Moscow would be abandoned he knew it only with his +intellect, he did not believe it in his heart and did not adapt +himself mentally to this new position of affairs. + +All his painstaking and energetic activity (in how far it was useful +and had any effect on the people is another question) had been +simply directed toward arousing in the masses his own feeling of +patriotic hatred of the French. + +But when events assumed their true historical character, when +expressing hatred for the French in words proved insufficient, when it +was not even possible to express that hatred by fighting a battle, +when self-confidence was of no avail in relation to the one question +before Moscow, when the whole population streamed out of Moscow as one +man, abandoning their belongings and proving by that negative action +all the depth of their national feeling, then the role chosen by +Rostopchin suddenly appeared senseless. He unexpectedly felt himself +ridiculous, weak, and alone, with no ground to stand on. + +When, awakened from his sleep, he received that cold, peremptory +note from Kutuzov, he felt the more irritated the more he felt himself +to blame. All that he had been specially put in charge of, the state +property which he should have removed, was still in Moscow and it +was no longer possible to take the whole of it away. + +"Who is to blame for it? Who has let things come to such a pass?" he +ruminated. "Not I, of course. I had everything ready. I had Moscow +firmly in hand. And this is what they have let it come to! Villains! +Traitors!" he thought, without clearly defining who the villains and +traitors were, but feeling it necessary to hate those traitors whoever +they might be who were to blame for the false and ridiculous +position in which he found himself. + +All that night Count Rostopchin issued orders, for which people came +to him from all parts of Moscow. Those about him had never seen the +count so morose and irritable. + +"Your excellency, the Director of the Registrar's Department has +sent for instructions... From the Consistory, from the Senate, from +the University, from the Foundling Hospital, the Suffragan has sent... +asking for information.... What are your orders about the Fire +Brigade? From the governor of the prison... from the superintendent of +the lunatic asylum..." All night long such announcements were +continually being received by the count. + +To all these inquiries he gave brief and angry replies indicating +that orders from him were not now needed, that the whole affair, +carefully prepared by him, had now been ruined by somebody, and that +that somebody would have to bear the whole responsibility for all that +might happen. + +"Oh, tell that blockhead," he said in reply to the question from the +Registrar's Department, "that he should remain to guard his documents. +Now why are you asking silly questions about the Fire Brigade? They +have horses, let them be off to Vladimir, and not leave them to the +French." + +"Your excellency, the superintendent of the lunatic asylum has come: +what are your commands?" + +"My commands? Let them go away, that's all.... And let the +lunatics out into the town. When lunatics command our armies God +evidently means these other madmen to be free." + +In reply to an inquiry about the convicts in the prison, Count +Rostopchin shouted angrily at the governor: + +"Do you expect me to give you two battalions--which we have not got- +for a convoy? Release them, that's all about it!" + +"Your excellency, there are some political prisoners, Meshkov, +Vereshchagin..." + +"Vereshchagin! Hasn't he been hanged yet?" shouted Rostopchin. +"Bring him to me!" + + + + + +CHAPTER XXV + + +Toward nine o'clock in the morning, when the troops were already +moving through Moscow, nobody came to the count any more for +instructions. Those who were able to get away were going of their +own accord, those who remained behind decided for themselves what they +must do. + +The count ordered his carriage that he might drive to Sokolniki, and +sat in his study with folded hands, morose, sallow, and taciturn. + +In quiet and untroubled times it seems to every administrator that +it is only by his efforts that the whole population under his rule +is kept going, and in this consciousness of being indispensable +every administrator finds the chief reward of his labor and efforts. +While the sea of history remains calm the ruler-administrator in his +frail bark, holding on with a boat hook to the ship of the people +and himself moving, naturally imagines that his efforts move the +ship he is holding on to. But as soon as a storm arises and the sea +begins to heave and the ship to move, such a delusion is no longer +possible. The ship moves independently with its own enormous motion, +the boat hook no longer reaches the moving vessel, and suddenly the +administrator, instead of appearing a ruler and a source of power, +becomes an insignificant, useless, feeble man. + +Rostopchin felt this, and it was this which exasperated him. + +The superintendent of police, whom the crowd had stopped, went in to +see him at the same time as an adjutant who informed the count that +the horses were harnessed. They were both pale, and the superintendent +of police, after reporting that he had executed the instructions he +had received, informed the count that an immense crowd had collected +in the courtyard and wished to see him. + +Without saying a word Rostopchin rose and walked hastily to his +light, luxurious drawing room, went to the balcony door, took hold +of the handle, let it go again, and went to the window from which he +had a better view of the whole crowd. The tall lad was standing in +front, flourishing his arm and saying something with a stern look. The +blood stained smith stood beside him with a gloomy face. A drone of +voices was audible through the closed window. + +"Is my carriage ready?" asked Rostopchin, stepping back from the +window. + +"It is, your excellency," replied the adjutant. + +Rostopchin went again to the balcony door. + +"But what do they want?" he asked the superintendent of police. + +"Your excellency, they say they have got ready, according to your +orders, to go against the French, and they shouted something about +treachery. But it is a turbulent crowd, your excellency--I hardly +managed to get away from it. Your excellency, I venture to suggest..." + +"You may go. I don't need you to tell me what to do!" exclaimed +Rostopchin angrily. + +He stood by the balcony door looking at the crowd. + +"This is what they have done with Russia! This is what they have +done with me!" thought he, full of an irrepressible fury that welled +up within him against the someone to whom what was happening might +be attributed. As often happens with passionate people, he was +mastered by anger but was still seeking an object on which to vent it. +"Here is that mob, the dregs of the people," he thought as he gazed at +the crowd: "this rabble they have roused by their folly! They want a +victim," he thought as he looked at the tall lad flourishing his +arm. And this thought occurred to him just because he himself +desired a victim, something on which to vent his rage. + +"Is the carriage ready?" he asked again. + +"Yes, your excellency. What are your orders about Vereshchagin? He +is waiting at the porch," said the adjutant. + +"Ah!" exclaimed Rostopchin, as if struck by an unexpected +recollection. + +And rapidly opening the door he went resolutely out onto the +balcony. The talking instantly ceased, hats and caps were doffed, +and all eyes were raised to the count. + +"Good morning, lads!" said the count briskly and loudly. "Thank +you for coming. I'll come out to you in a moment, but we must first +settle with the villain. We must punish the villain who has caused the +ruin of Moscow. Wait for me!" + +And the count stepped as briskly back into the room and slammed +the door behind him. + +A murmur of approbation and satisfaction ran through the crowd. +"He'll settle with all the villains, you'll see! And you said the +French... He'll show you what law is!" the mob were saying as if +reproving one another for their lack of confidence. + +A few minutes later an officer came hurriedly out of the front door, +gave an order, and the dragoons formed up in line. The crowd moved +eagerly from the balcony toward the porch. Rostopchin, coming out +there with quick angry steps, looked hastily around as if seeking +someone. + +"Where is he?" he inquired. And as he spoke he saw a young man +coming round the corner of the house between two dragoons. He had a +long thin neck, and his head, that had been half shaved, was again +covered by short hair. This young man was dressed in a threadbare blue +cloth coat lined with fox fur, that had once been smart, and dirty +hempen convict trousers, over which were pulled his thin, dirty, +trodden-down boots. On his thin, weak legs were heavy chains which +hampered his irresolute movements. + +"Ah!" said Rostopchin, hurriedly turning away his eyes from the +young man in the fur-lined coat and pointing to the bottom step of the +porch. "Put him there." + +The young man in his clattering chains stepped clumsily to the +spot indicated, holding away with one finger the coat collar which +chafed his neck, turned his long neck twice this way and that, sighed, +and submissively folded before him his thin hands, unused to work. + +For several seconds while the young man was taking his place on +the step the silence continued. Only among the back rows of the +people, who were all pressing toward the one spot, could sighs, +groans, and the shuffling of feet be heard. + +While waiting for the young man to take his place on the step +Rostopchin stood frowning and rubbing his face with his hand. + +"Lads!" said he, with a metallic ring in his voice. "This man, +Vereshchagin, is the scoundrel by whose doing Moscow is perishing." + +The young man in the fur-lined coat, stooping a little, stood in a +submissive attitude, his fingers clasped before him. His emaciated +young face, disfigured by the half-shaven head, hung down +hopelessly. At the count's first words he raised it slowly and +looked up at him as if wishing to say something or at least to meet +his eye. But Rostopchin did not look at him. A vein in the young man's +long thin neck swelled like a cord and went blue behind the ear, and +suddenly his face flushed. + +All eyes were fixed on him. He looked at the crowd, and rendered +more hopeful by the expression he read on the faces there, he smiled +sadly and timidly, and lowering his head shifted his feet on the step. + +"He has betrayed his Tsar and his country, he had gone over to +Bonaparte. He alone of all the Russians has disgraced the Russian +name, he has caused Moscow to perish," said Rostopchin in a sharp, +even voice, but suddenly he glanced down at Vereshchagin who continued +to stand in the same submissive attitude. As if inflamed by the sight, +he raised his arm and addressed the people, almost shouting: + +"Deal with him as you think fit! I hand him over to you." + +The crowd remained silent and only pressed closer and closer to +one another. To keep one another back, to breathe in that stifling +atmosphere, to be unable to stir, and to await something unknown, +uncomprehended, and terrible, was becoming unbearable. Those +standing in front, who had seen and heard what had taken place +before them, all stood with wide open eyes and mouths, straining +with all their strength, and held back the crowd that was pushing +behind them. + +"Beat him!... Let the traitor perish and not disgrace the Russian +name!" shouted Rostopchin. "Cut him down. I command it." + +Hearing not so much the words as the angry tone of Rostopchin's +voice, the crowd moaned and heaved forward, but again paused. + +"Count!" exclaimed the timid yet theatrical voice of Vereshchagin in +the midst of the momentary silence that ensued, "Count! One God is +above us both...." He lifted his head and again the thick vein in +his thin neck filled with blood and the color rapidly came and went in +his face. + +He did not finish what he wished to say. + +"Cut him down! I command it..." shouted Rostopchin, suddenly growing +pale like Vereshchagin. + +"Draw sabers!" cried the dragoon officer, drawing his own. + +Another still stronger wave flowed through the crowd and reaching +the front ranks carried it swaying to the very steps of the porch. The +tall youth, with a stony look on his face, and rigid and uplifted arm, +stood beside Vereshchagin. + +"Saber him!" the dragoon officer almost whispered. + +And one of the soldiers, his face all at once distorted with fury, +struck Vereshchagin on the head with the blunt side of his saber. + +"Ah!" cried Vereshchagin in meek surprise, looking round with a +frightened glance as if not understanding why this was done to him. +A similar moan of surprise and horror ran through the crowd. "O Lord!" +exclaimed a sorrowful voice. + +But after the exclamation of surprise that had escaped from +Vereshchagin he uttered a plaintive cry of pain, and that cry was +fatal. The barrier of human feeling, strained to the utmost, that +had held the crowd in check suddenly broke. The crime had begun and +must now be completed. The plaintive moan of reproach was drowned by +the threatening and angry roar of the crowd. Like the seventh and last +wave that shatters a ship, that last irresistible wave burst from +the rear and reached the front ranks, carrying them off their feet and +engulfing them all. The dragoon was about to repeat his blow. +Vereshchagin with a cry of horror, covering his head with his hands, +rushed toward the crowd. The tall youth, against whom he stumbled, +seized his thin neck with his hands and, yelling wildly, fell with him +under the feet of the pressing, struggling crowd. + +Some beat and tore at Vereshchagin, others at the tall youth. And +the screams of those that were being trampled on and of those who +tried to rescue the tall lad only increased the fury of the crowd. +It was a long time before the dragoons could extricate the bleeding +youth, beaten almost to death. And for a long time, despite the +feverish haste with which the mob tried to end the work that had +been begun, those who were hitting, throttling, and tearing at +Vereshchagin were unable to kill him, for the crowd pressed from all +sides, swaying as one mass with them in the center and rendering it +impossible for them either to kill him or let him go. + +"Hit him with an ax, eh!... Crushed?... Traitor, he sold +Christ.... Still alive... tenacious... serves him right! Torture +serves a thief right. Use the hatchet!... What--still alive?" + +Only when the victim ceased to struggle and his cries changed to a +long-drawn, measured death rattle did the crowd around his +prostrate, bleeding corpse begin rapidly to change places. Each one +came up, glanced at what had been done, and with horror, reproach, and +astonishment pushed back again. + +"O Lord! The people are like wild beasts! How could he be alive?" +voices in the crowd could be heard saying. "Quite a young fellow +too... must have been a merchant's son. What men!... and they say he's +not the right one.... How not the right one?... O Lord! And there's +another has been beaten too--they say he's nearly done for.... Oh, the +people... Aren't they afraid of sinning?..." said the same mob now, +looking with pained distress at the dead body with its long, thin, +half-severed neck and its livid face stained with blood and dust. + +A painstaking police officer, considering the presence of a corpse +in his excellency's courtyard unseemly, told the dragoons to take it +away. Two dragoons took it by its distorted legs and dragged it +along the ground. The gory, dust-stained, half-shaven head with its +long neck trailed twisting along the ground. The crowd shrank back +from it. + +At the moment when Vereshchagin fell and the crowd closed in with +savage yells and swayed about him, Rostopchin suddenly turned pale +and, instead of going to the back entrance where his carriage +awaited him, went with hurried steps and bent head, not knowing +where and why, along the passage leading to the rooms on the ground +floor. The count's face was white and he could not control the +feverish twitching of his lower jaw. + + +"This way, your excellency... Where are you going?... This way, +please..." said a trembling, frightened voice behind him. + +Count Rostopchin was unable to reply and, turning obediently, went +in the direction indicated. At the back entrance stood his caleche. +The distant roar of the yelling crowd was audible even there. He +hastily took his seat and told the coachman to drive him to his +country house in Sokolniki. + +When they reached the Myasnitski Street and could no longer hear the +shouts of the mob, the count began to repent. He remembered with +dissatisfaction the agitation and fear he had betrayed before his +subordinates. "The mob is terrible--disgusting," he said to himself in +French. "They are like wolves whom nothing but flesh can appease." +"Count! One God is above us both!"--Vereshchagin's words suddenly +recurred to him, and a disagreeable shiver ran down his back. But this +was only a momentary feeling and Count Rostopchin smiled +disdainfully at himself. "I had other duties," thought he. "The people +had to be appeased. Many other victims have perished and are perishing +for the public good"--and he began thinking of his social duties to +his family and to the city entrusted to him, and of himself--not +himself as Theodore Vasilyevich Rostopchin (he fancied that Theodore +Vasilyevich Rostopchin was sacrificing himself for the public good) +but himself as governor, the representative of authority and of the +Tsar. "Had I been simply Theodore Vasilyevich my course of action +would have been quite different, but it was my duty to safeguard my +life and dignity as commander in chief." + +Lightly swaying on the flexible springs of his carriage and no +longer hearing the terrible sounds of the crowd, Rostopchin grew +physically calm and, as always happens, as soon as he became +physically tranquil his mind devised reasons why he should be mentally +tranquil too. The thought which tranquillized Rostopchin was not a new +one. Since the world began and men have killed one another no one +has ever committed such a crime against his fellow man without +comforting himself with this same idea. This idea is le bien public, +the hypothetical welfare of other people. + +To a man not swayed by passion that welfare is never certain, but he +who commits such a crime always knows just where that welfare lies. +And Rostopchin now knew it. + +Not only did his reason not reproach him for what he had done, but +he even found cause for self-satisfaction in having so successfully +contrived to avail himself of a convenient opportunity to punish a +criminal and at the same time pacify the mob. + +"Vereshchagin was tried and condemned to death," thought +Rostopchin (though the Senate had only condemned Vereshchagin to +hard labor), "he was a traitor and a spy. I could not let him go +unpunished and so I have killed two birds with one stone: to appease +the mob I gave them a victim and at the same time punished a +miscreant." + +Having reached his country house and begun to give orders about +domestic arrangements, the count grew quite tranquil. + +Half an hour later he was driving with his fast horses across the +Sokolniki field, no longer thinking of what had occurred but +considering what was to come. He was driving to the Yauza bridge where +he had heard that Kutuzov was. Count Rostopchin was mentally preparing +the angry and stinging reproaches he meant to address to Kutuzov for +his deception. He would make that foxy old courtier feel that the +responsibility for all the calamities that would follow the +abandonment of the city and the ruin of Russia (as Rostopchin regarded +it) would fall upon his doting old head. Planning beforehand what he +would say to Kutuzov, Rostopchin turned angrily in his caleche and +gazed sternly from side to side. + +The Sokolniki field was deserted. Only at the end of it, in front of +the almshouse and the lunatic asylum, could be seen some people in +white and others like them walking singly across the field shouting +and gesticulating. + +One of these was running to cross the path of Count Rostopchin's +carriage, and the count himself, his coachman, and his dragoons looked +with vague horror and curiosity at these released lunatics and +especially at the one running toward them. + +Swaying from side to side on his long, thin legs in his fluttering +dressing gown, this lunatic was running impetuously, his gaze fixed on +Rostopchin, shouting something in a hoarse voice and making signs to +him to stop. The lunatic's solemn, gloomy face was thin and yellow, +with its beard growing in uneven tufts. His black, agate pupils with +saffron-yellow whites moved restlessly near the lower eyelids. + +"Stop! Pull up, I tell you!" he cried in a piercing voice, and again +shouted something breathlessly with emphatic intonations and gestures. + +Coming abreast of the caleche he ran beside it. + +"Thrice have they slain me, thrice have I risen from the dead. +They stoned me, crucified me... I shall rise... shall rise... shall +rise. They have torn my body. The kingdom of God will be overthrown... +Thrice will I overthrow it and thrice re-establish it!" he cried, +raising his voice higher and higher. + +Count Rostopchin suddenly grew pale as he had done when the crowd +closed in on Vereshchagin. He turned away. "Go fas... faster!" he +cried in a trembling voice to his coachman. The caleche flew over +the ground as fast as the horses could draw it, but for a long time +Count Rostopchin still heard the insane despairing screams growing +fainter in the distance, while his eyes saw nothing but the +astonished, frightened, bloodstained face of "the traitor" in the +fur-lined coat. + +Recent as that mental picture was, Rostopchin already felt that it +had cut deep into his heart and drawn blood. Even now he felt +clearly that the gory trace of that recollection would not pass with +time, but that the terrible memory would, on the contrary, dwell in +his heart ever more cruelly and painfully to the end of his life. He +seemed still to hear the sound of his own words: "Cut him down! I +command it...." + +"Why did I utter those words? It was by some accident I said +them.... I need not have said them," he thought. "And then nothing +would have happened." He saw the frightened and then infuriated face +of the dragoon who dealt the blow, the look of silent, timid +reproach that boy in the fur-lined coat had turned upon him. "But I +did not do it for my own sake. I was bound to act that way.... The +mob, the traitor... the public welfare," thought he. + +Troops were still crowding at the Yauza bridge. It was hot. Kutuzov, +dejected and frowning, sat on a bench by the bridge toying with his +whip in the sand when a caleche dashed up noisily. A man in a +general's uniform with plumes in his hat went up to Kutuzov and said +something in French. It was Count Rostopchin. He told Kutuzov that +he had come because Moscow, the capital, was no more and only the army +remained. + +"Things would have been different if your Serene Highness had not +told me that you would not abandon Moscow without another battle; +all this would not have happened," he said. + +Kutuzov looked at Rostopchin as if, not grasping what was said to +him, he was trying to read something peculiar written at that moment +on the face of the man addressing him. Rostopchin grew confused and +became silent. Kutuzov slightly shook his head and not taking his +penetrating gaze from Rostopchin's face muttered softly: + +"No! I shall not give up Moscow without a battle!" + +Whether Kutuzov was thinking of something entirely different when he +spoke those words, or uttered them purposely, knowing them to be +meaningless, at any rate Rostopchin made no reply and hastily left +him. And strange to say, the Governor of Moscow, the proud Count +Rostopchin, took up a Cossack whip and went to the bridge where he +began with shouts to drive on the carts that blocked the way. + + + + + +CHAPTER XXVI + + +Toward four o'clock in the afternoon Murat's troops were entering +Moscow. In front rode a detachment of Wurttemberg hussars and behind +them rode the King of Naples himself accompanied by a numerous suite. + +About the middle of the Arbat Street, near the Church of the +Miraculous Icon of St. Nicholas, Murat halted to await news from the +advanced detachment as to the condition in which they had found the +citadel, le Kremlin. + +Around Murat gathered a group of those who had remained in Moscow. +They all stared in timid bewilderment at the strange, long-haired +commander dressed up in feathers and gold. + +"Is that their Tsar himself? He's not bad!" low voices could be +heard saying. + +An interpreter rode up to the group. + +"Take off your cap... your caps!" These words went from one to +another in the crowd. The interpreter addressed an old porter and +asked if it was far to the Kremlin. The porter, listening in +perplexity to the unfamiliar Polish accent and not realizing that +the interpreter was speaking Russian, did not understand what was +being said to him and slipped behind the others. + +Murat approached the interpreter and told him to ask where the +Russian army was. One of the Russians understood what was asked and +several voices at once began answering the interpreter. A French +officer, returning from the advanced detachment, rode up to Murat +and reported that the gates of the citadel had been barricaded and +that there was probably an ambuscade there. + +"Good!" said Murat and, turning to one of the gentlemen in his +suite, ordered four light guns to be moved forward to fire at the +gates. + +The guns emerged at a trot from the column following Murat and +advanced up the Arbat. When they reached the end of the Vozdvizhenka +Street they halted and drew in the Square. Several French officers +superintended the placing of the guns and looked at the Kremlin +through field glasses. + +The bells in the Kremlin were ringing for vespers, and this sound +troubled the French. They imagined it to be a call to arms. A few +infantrymen ran to the Kutafyev Gate. Beams and wooden screens had +been put there, and two musket shots rang out from under the gate as +soon as an officer and men began to run toward it. A general who was +standing by the guns shouted some words of command to the officer, and +the latter ran back again with his men. + +The sound of three more shots came from the gate. + +One shot struck a French soldier's foot, and from behind the screens +came the strange sound of a few voices shouting. Instantly as at a +word of command the expression of cheerful serenity on the faces of +the French general, officers, and men changed to one of determined +concentrated readiness for strife and suffering. To all of them from +the marshal to the least soldier, that place was not the Vozdvizhenka, +Mokhavaya, or Kutafyev Street, nor the Troitsa Gate (places familiar +in Moscow), but a new battlefield which would probably prove +sanguinary. And all made ready for that battle. The cries from the +gates ceased. The guns were advanced, the artillerymen blew the ash +off their linstocks, and an officer gave the word "Fire!" This was +followed by two whistling sounds of canister shot, one after +another. The shot rattled against the stone of the gate and upon the +wooden beams and screens, and two wavering clouds of smoke rose over +the Square. + +A few instants after the echo of the reports resounding over the +stone-built Kremlin had died away the French heard a strange sound +above their head. Thousands of crows rose above the walls and +circled in the air, cawing and noisily flapping their wings. +Together with that sound came a solitary human cry from the gateway +and amid the smoke appeared the figure of a bareheaded man in a +peasant's coat. He grasped a musket and took aim at the French. +"Fire!" repeated the officer once more, and the reports of a musket +and of two cannon shots were heard simultaneously. The gate again +hidden by smoke. + +Nothing more stirred behind the screens and the French infantry +soldiers and officers advanced to the gate. In the gateway lay three +wounded and four dead. Two men in peasant coats ran away at the foot +of the wall, toward the Znamenka. + +"Clear that away!" said the officer, pointing to the beams and the +corpses, and the French soldiers, after dispatching the wounded, threw +the corpses over the parapet. + +Who these men were nobody knew. "Clear that away!" was all that +was said of them, and they were thrown over the parapet and removed +later on that they might not stink. Thiers alone dedicates a few +eloquent lines to their memory: "These wretches had occupied the +sacred citadel, having supplied themselves with guns from the arsenal, +and fired" (the wretches) "at the French. Some of them were sabered +and the Kremlin was purged of their presence." + +Murat was informed that the way had been cleared. The French entered +the gates and began pitching their camp in the Senate Square. Out of +the windows of the Senate House the soldiers threw chairs into the +Square for fuel and kindled fires there. + +Other detachments passed through the Kremlin and encamped along +the Moroseyka, the Lubyanka, and Pokrovka Streets. Others quartered +themselves along the Vozdvizhenka, the Nikolski, and the Tverskoy +Streets. No masters of the houses being found anywhere, the French +were not billeted on the inhabitants as is usual in towns but lived in +it as in a camp. + +Though tattered, hungry, worn out, and reduced to a third of their +original number, the French entered Moscow in good marching order. +It was a weary and famished, but still a fighting and menacing army. +But it remained an army only until its soldiers had dispersed into +their different lodgings. As soon as the men of the various +regiments began to disperse among the wealthy and deserted houses, the +army was lost forever and there came into being something nondescript, +neither citizens nor soldiers but what are known as marauders. When +five weeks later these same men left Moscow, they no longer formed +an army. They were a mob of marauders, each carrying a quantity of +articles which seemed to him valuable or useful. The aim of each man +when he left Moscow was no longer, as it had been, to conquer, but +merely to keep what he had acquired. Like a monkey which puts its +paw into the narrow neck of a jug, and having seized a handful of nuts +will not open its fist for fear of losing what it holds, and therefore +perishes, the French when they left Moscow had inevitably to perish +because they carried their loot with them, yet to abandon what they +had stolen was as impossible for them as it is for the monkey to +open its paw and let go of its nuts. Ten minutes after each regiment +had entered a Moscow district, not a soldier or officer was left. +Men in military uniforms and Hessian boots could be seen through the +windows, laughing and walking through the rooms. In cellars and +storerooms similar men were busy among the provisions, and in the +yards unlocking or breaking open coach house and stable doors, +lighting fires in kitchens and kneading and baking bread with +rolled-up sleeves, and cooking; or frightening, amusing, or +caressing women and children. There were many such men both in the +shops and houses--but there was no army. + +Order after order was issued by the French commanders that day +forbidding the men to disperse about the town, sternly forbidding +any violence to the inhabitants or any looting, and announcing a +roll call for that very evening. But despite all these measures the +men, who had till then constituted an army, flowed all over the +wealthy, deserted city with its comforts and plentiful supplies. As +a hungry herd of cattle keeps well together when crossing a barren +field, but gets out of hand and at once disperses uncontrollably as +soon as it reaches rich pastures, so did the army disperse all over +the wealthy city. + +No residents were left in Moscow, and the soldiers--like water +percolating through sand--spread irresistibly through the city in +all directions from the Kremlin into which they had first marched. The +cavalry, on entering a merchant's house that had been abandoned and +finding there stabling more than sufficient for their horses, went on, +all the same, to the next house which seemed to them better. Many of +them appropriated several houses, chalked their names on them, and +quarreled and even fought with other companies for them. Before they +had had time to secure quarters the soldiers ran out into the +streets to see the city and, hearing that everything had been +abandoned, rushed to places where valuables were to be had for the +taking. The officers followed to check the soldiers and were +involuntarily drawn into doing the same. In Carriage Row carriages had +been left in the shops, and generals flocked there to select +caleches and coaches for themselves. The few inhabitants who had +remained invited commanding officers to their houses, hoping thereby +to secure themselves from being plundered. There were masses of wealth +and there seemed no end to it. All around the quarters occupied by the +French were other regions still unexplored and unoccupied where, +they thought, yet greater riches might be found. And Moscow engulfed +the army ever deeper and deeper. When water is spilled on dry ground +both the dry ground and the water disappear and mud results; and in +the same way the entry of the famished army into the rich and deserted +city resulted in fires and looting and the destruction of both the +army and the wealthy city. + + +The French attributed the Fire of Moscow au patriotisme feroce de +Rostopchine,* the Russians to the barbarity of the French. In reality, +however, it was not, and could not be, possible to explain the burning +of Moscow by making any individual, or any group of people, +responsible for it. Moscow was burned because it found itself in a +position in which any town built of wood was bound to burn, quite +apart from whether it had, or had not, a hundred and thirty inferior +fire engines. Deserted Moscow had to burn as inevitably as a heap of +shavings has to burn on which sparks continually fall for several +days. A town built of wood, where scarcely a day passes without +conflagrations when the house owners are in residence and a police +force is present, cannot help burning when its inhabitants have left +it and it is occupied by soldiers who smoke pipes, make campfires of +the Senate chairs in the Senate Square, and cook themselves meals +twice a day. In peacetime it is only necessary to billet troops in the +villages of any district and the number of fires in that district +immediately increases. How much then must the probability of fire be +increased in an abandoned, wooden town where foreign troops are +quartered. "Le patriotisme feroce de Rostopchine" and the barbarity of +the French were not to blame in the matter. Moscow was set on fire +by the soldiers' pipes, kitchens, and campfires, and by the +carelessness of enemy soldiers occupying houses they did not own. Even +if there was any arson (which is very doubtful, for no one had any +reason to burn the houses--in any case a troublesome and dangerous +thing to do), arson cannot be regarded as the cause, for the same +thing would have happened without any incendiarism. + + +*To Rostopchin's ferocious patriotism. + + +However tempting it might be for the French to blame Rostopchin's +ferocity and for Russians to blame the scoundrel Bonaparte, or later +on to place an heroic torch in the hands of their own people, it is +impossible not to see that there could be no such direct cause of +the fire, for Moscow had to burn as every village, factory, or house +must burn which is left by its owners and in which strangers are +allowed to live and cook their porridge. Moscow was burned by its +inhabitants, it is true, but by those who had abandoned it and not +by those who remained in it. Moscow when occupied by the enemy did not +remain intact like Berlin, Vienna, and other towns, simply because its +inhabitants abandoned it and did not welcome the French with bread and +salt, nor bring them the keys of the city. + + + + + +CHAPTER XXVII + + +The absorption of the French by Moscow, radiating starwise as it +did, only reached the quarter where Pierre was staying by the +evening of the second of September. + +After the last two days spent in solitude and unusual circumstances, +Pierre was in a state bordering on insanity. He was completely +obsessed by one persistent thought. He did not know how or when this +thought had taken such possession of him, but he remembered nothing of +the past, understood nothing of the present, and all he saw and +heard appeared to him like a dream. + +He had left home only to escape the intricate tangle of life's +demands that enmeshed him, and which in his present condition he was +unable to unravel. He had gone to Joseph Alexeevich's house, on the +plea of sorting the deceased's books and papers, only in search of +rest from life's turmoil, for in his mind the memory of Joseph +Alexeevich was connected with a world of eternal, solemn, and calm +thoughts, quite contrary to the restless confusion into which he +felt himself being drawn. He sought a quiet refuge, and in Joseph +Alexeevich's study he really found it. When he sat with his elbows +on the dusty writing table in the deathlike stillness of the study, +calm and significant memories of the last few days rose one after +another in his imagination, particularly of the battle of Borodino and +of that vague sense of his own insignificance and insincerity compared +with the truth, simplicity, and strength of the class of men he +mentally classed as they. When Gerasim roused him from his reverie the +idea occurred to him of taking part in the popular defense of Moscow +which he knew was projected. And with that object he had asked Gerasim +to get him a peasant's coat and a pistol, confiding to him his +intentions of remaining in Joseph Alexeevich's house and keeping his +name secret. Then during the first day spent in inaction and +solitude (he tried several times to fix his attention on the Masonic +manuscripts, but was unable to do so) the idea that had previously +occurred to him of the cabalistic significance of his name in +connection with Bonaparte's more than once vaguely presented itself. +But the idea that he, L'russe Besuhof, was destined to set a limit +to the power of the Beast was as yet only one of the fancies that +often passed through his mind and left no trace behind. + +When, having bought the coat merely with the object of taking part +among the people in the defense of Moscow, Pierre had met the +Rostovs and Natasha had said to him: "Are you remaining in +Moscow?... How splendid!" the thought flashed into his mind that it +really would be a good thing, even if Moscow were taken, for him to +remain there and do what he was predestined to do. + +Next day, with the sole idea of not sparing himself and not +lagging in any way behind them, Pierre went to the Three Hills gate. +But when he returned to the house convinced that Moscow would not be +defended, he suddenly felt that what before had seemed to him merely a +possibility had now become absolutely necessary and inevitable. He +must remain in Moscow, concealing his name, and must meet Napoleon and +kill him, and either perish or put an end to the misery of all Europe- +which it seemed to him was solely due to Napoleon. + +Pierre knew all the details of the attempt on Bonaparte's life in +1809 by a German student in Vienna, and knew that the student had been +shot. And the risk to which he would expose his life by carrying out +his design excited him still more. + +Two equally strong feelings drew Pierre irresistibly to this +purpose. The first was a feeling of the necessity of sacrifice and +suffering in view of the common calamity, the same feeling that had +caused him to go to Mozhaysk on the twenty-fifth and to make his way +to the very thick of the battle and had now caused him to run away +from his home and, in place of the luxury and comfort to which he +was accustomed, to sleep on a hard sofa without undressing and eat the +same food as Gerasim. The other was that vague and quite Russian +feeling of contempt for everything conventional, artificial, and +human--for everything the majority of men regard as the greatest +good in the world. Pierre had first experienced this strange and +fascinating feeling at the Sloboda Palace, when he had suddenly felt +that wealth, power, and life--all that men so painstakingly acquire +and guard--if it has any worth has so only by reason the joy with +which it can all be renounced. + +It was the feeling that induces a volunteer recruit to spend his +last penny on drink, and a drunken man to smash mirrors or glasses for +no apparent reason and knowing that it will cost him all the money +he possesses: the feeling which causes a man to perform actions +which from an ordinary point of view are insane, to test, as it +were, his personal power and strength, affirming the existence of a +higher, nonhuman criterion of life. + +From the very day Pierre had experienced this feeling for the +first time at the Sloboda Palace he had been continuously under its +influence, but only now found full satisfaction for it. Moreover, at +this moment Pierre was supported in his design and prevented from +renouncing it by what he had already done in that direction. If he +were now to leave Moscow like everyone else, his flight from home, the +peasant coat, the pistol, and his announcement to the Rostovs that +he would remain in Moscow would all become not merely meaningless +but contemptible and ridiculous, and to this Pierre was very +sensitive. + +Pierre's physical condition, as is always the case, corresponded +to his mental state. The unaccustomed coarse food, the vodka he +drank during those days, the absence of wine and cigars, his dirty +unchanged linen, two almost sleepless nights passed on a short sofa +without bedding--all this kept him in a state of excitement +bordering on insanity. + +It was two o'clock in the afternoon. The French had already +entered Moscow. Pierre knew this, but instead of acting he only +thought about his undertaking, going over its minutest details in +his mind. In his fancy he did not clearly picture to himself either +the striking of the blow or the death of Napoleon, but with +extraordinary vividness and melancholy enjoyment imagined his own +destruction and heroic endurance. + +"Yes, alone, for the sake of all, I must do it or perish!" he +thought. "Yes, I will approach... and then suddenly... with pistol +or dagger? But that is all the same! 'It is not I but the hand of +Providence that punishes thee,' I shall say," thought he, imagining +what he would say when killing Napoleon. "Well then, take me and +execute me!" he went on, speaking to himself and bowing his head +with a sad but firm expression. + +While Pierre, standing in the middle of the room, was talking to +himself in this way, the study door opened and on the threshold +appeared the figure of Makar Alexeevich, always so timid before but +now quite transformed. + +His dressing gown was unfastened, his face red and distorted. He was +obviously drunk. On seeing Pierre he grew confused at first, but +noticing embarrassment on Pierre's face immediately grew bold and, +staggering on his thin legs, advanced into the middle of the room. + +"They're frightened," he said confidentially in a hoarse voice. "I +say I won't surrender, I say... Am I not right, sir?" + +He paused and then suddenly seeing the pistol on the table seized it +with unexpected rapidity and ran out into the corridor. + +Gerasim and the porter, who had followed Makar Alexeevich, stopped +him in the vestibule and tried to take the pistol from him. Pierre, +coming out into the corridor, looked with pity and repulsion at the +half-crazy old man. Makar Alexeevich, frowning with exertion, held +on to the pistol and screamed hoarsely, evidently with some heroic +fancy in his head. + +"To arms! Board them! No, you shan't get it," he yelled. + +"That will do, please, that will do. Have the goodness--please, sir, +to let go! Please, sir..." pleaded Gerasim, trying carefully to +steer Makar Alexeevich by the elbows back to the door. + +"Who are you? Bonaparte!..." shouted Makar Alexeevich. + +"That's not right, sir. Come to your room, please, and rest. Allow +me to have the pistol." + +"Be off, thou base slave! Touch me not! See this?" shouted Makar +Alexeevich, brandishing the pistol. "Board them!" + +"Catch hold!" whispered Gerasim to the porter. + +They seized Makar Alexeevich by the arms and dragged him to the +door. + +The vestibule was filled with the discordant sounds of a struggle +and of a tipsy, hoarse voice. + +Suddenly a fresh sound, a piercing feminine scream, reverberated +from the porch and the cook came running into the vestibule. + +"It's them! Gracious heavens! O Lord, four of them, horsemen!" she +cried. + +Gerasim and the porter let Makar Alexeevich go, and in the now +silent corridor the sound of several hands knocking at the front +door could be heard. + + + + + +CHAPTER XXVIII + + +Pierre, having decided that until he had carried out his design he +would disclose neither his identity nor his knowledge of French, stood +at the half-open door of the corridor, intending to conceal himself as +soon as the French entered. But the French entered and still Pierre +did not retire--an irresistible curiosity kept him there. + +There were two of them. One was an officer--a tall, soldierly, +handsome man--the other evidently a private or an orderly, +sunburned, short, and thin, with sunken cheeks and a dull +expression. The officer walked in front, leaning on a stick and +slightly limping. When he had advanced a few steps he stopped, +having apparently decided that these were good quarters, turned +round to the soldiers standing at the entrance, and in a loud voice of +command ordered them to put up the horses. Having done that, the +officer, lifting his elbow with a smart gesture, stroked his +mustache and lightly touched his hat. + +"Bonjour, la compagnie!"* said he gaily, smiling and looking about +him. + + +*"Good day, everybody!" + + +No one gave any reply. + +"Vous etes le bourgeois?"* the officer asked Gerasim. + + +*"Are you the master here?" + + +Gerasim gazed at the officer with an alarmed and inquiring look. + +"Quartier, quartier, logement!" said the officer, looking down at +the little man with a condescending and good-natured smile. "Les +francais sont de bons enfants. Que diable! Voyons! Ne nous fachons +pas, mon vieux!"* added he, clapping the scared and silent Gerasim +on the shoulder. "Well, does no one speak French in this +establishment?" he asked again in French, looking around and meeting +Pierre's eyes. Pierre moved away from the door. + + +*"Quarters, quarters, lodgings! The French are good fellows. What +the devil! There, don't let us be cross, old fellow!" + + +Again the officer turned to Gerasim and asked him to show him the +rooms in the house. + +"Master, not here--don't understand... me, you..." said Gerasim, +trying to render his words more comprehensible by contorting them. + +Still smiling, the French officer spread out his hands before +Gerasim's nose, intimating that he did not understand him either, +and moved, limping, to the door at which Pierre was standing. Pierre +wished to go away and conceal himself, but at that moment he saw Makar +Alexeevich appearing at the open kitchen door with the pistol in his +hand. With a madman's cunning, Makar Alexeevich eyed the Frenchman, +raised his pistol, and took aim. + +"Board them!" yelled the tipsy man, trying to press the trigger. +Hearing the yell the officer turned round, and at the same moment +Pierre threw himself on the drunkard. Just when Pierre snatched at and +struck up the pistol Makar Alexeevich at last got his fingers on the +trigger, there was a deafening report, and all were enveloped in a +cloud of smoke. The Frenchman turned pale and rushed to the door. + +Forgetting his intention of concealing his knowledge of French, +Pierre, snatching away the pistol and throwing it down, ran up to +the officer and addressed him in French. + +"You are not wounded?" he asked. + +"I think not," answered the Frenchman, feeling himself over. "But +I have had a lucky escape this time," he added, pointing to the +damaged plaster of the wall. "Who is that man?" said he, looking +sternly at Pierre. + +"Oh, I am really in despair at what has occurred," said Pierre +rapidly, quite forgetting the part he had intended to play. "He is +an unfortunate madman who did not know what he was doing." + +The officer went up to Makar Alexeevich and took him by the collar. + +Makar Alexeevich was standing with parted lips, swaying, as if about +to fall asleep, as he leaned against the wall. + +"Brigand! You shall pay for this," said the Frenchman, letting go of +him. "We French are merciful after victory, but we do not pardon +traitors," he added, with a look of gloomy dignity and a fine +energetic gesture. + +Pierre continued, in French, to persuade the officer not to hold +that drunken imbecile to account. The Frenchman listened in silence +with the same gloomy expression, but suddenly turned to Pierre with +a smile. For a few seconds he looked at him in silence. His handsome +face assumed a melodramatically gentle expression and he held out +his hand. + +"You have saved my life. You are French," said he. + +For a Frenchman that deduction was indubitable. Only a Frenchman +could perform a great deed, and to save his life--the life of M. +Ramballe, captain of the 13th Light Regiment--was undoubtedly a very +great deed. + +But however indubitable that conclusion and the officer's conviction +based upon it, Pierre felt it necessary to disillusion him. + +"I am Russian," he said quickly. + +"Tut, tut, tut! Tell that to others," said the officer, waving his +finger before his nose and smiling. "You shall tell me all about +that presently. I am delighted to meet a compatriot. Well, and what +are we to do with this man?" he added, addressing himself to Pierre as +to a brother. + +Even if Pierre were not a Frenchman, having once received that +loftiest of human appellations he could not renounce it, said the +officer's look and tone. In reply to his last question Pierre again +explained who Makar Alexeevich was and how just before their arrival +that drunken imbecile had seized the loaded pistol which they had +not had time to recover from him, and begged the officer to let the +deed go unpunished. + +The Frenchman expanded his chest and made a majestic gesture with +his arm. + +"You have saved my life! You are French. You ask his pardon? I grant +it you. Lead that man away!" said he quickly and energetically, and +taking the arm of Pierre whom he had promoted to be a Frenchman for +saving his life, he went with him into the room. + +The soldiers in the yard, hearing the shot, came into the passage +asking what had happened, and expressed their readiness to punish +the culprits, but the officer sternly checked them. + +"You will be called in when you are wanted," he said. + +The soldiers went out again, and the orderly, who had meanwhile +had time to visit the kitchen, came up to his officer. + +"Captain, there is soup and a leg of mutton in the kitchen," said +he. "Shall I serve them up?" + +"Yes, and some wine," answered the captain. + + + + + +CHAPTER XXIX + + +When the French officer went into the room with Pierre the latter +again thought it his duty to assure him that he was not French and +wished to go away, but the officer would not hear of it. He was so +very polite, amiable, good-natured, and genuinely grateful to Pierre +for saving his life that Pierre had not the heart to refuse, and sat +down with him in the parlor--the first room they entered. To +Pierre's assurances that he was not a Frenchman, the captain, +evidently not understanding how anyone could decline so flattering +an appellation, shrugged his shoulders and said that if Pierre +absolutely insisted on passing for a Russian let it be so, but for all +that he would be forever bound to Pierre by gratitude for saving his +life. + +Had this man been endowed with the slightest capacity for perceiving +the feelings of others, and had he at all understood what Pierre's +feelings were, the latter would probably have left him, but the +man's animated obtuseness to everything other than himself disarmed +Pierre. + +"A Frenchman or a Russian prince incognito," said the officer, +looking at Pierre's fine though dirty linen and at the ring on his +finger. "I owe my life to you and offer you my friendship. A Frenchman +never forgets either an insult or a service. I offer you my +friendship. That is all I can say." + +There was so much good nature and nobility (in the French sense of +the word) in the officer's voice, in the expression of his face and in +his gestures, that Pierre, unconsciously smiling in response to the +Frenchman's smile, pressed the hand held out to him. + +"Captain Ramballe, of the 13th Light Regiment, Chevalier of the +Legion of Honor for the affair on the seventh of September," he +introduced himself, a self-satisfied irrepressible smile puckering his +lips under his mustache. "Will you now be so good as to tell me with +whom I have the honor of conversing so pleasantly, instead of being in +the ambulance with that maniac's bullet in my body?" + +Pierre replied that he could not tell him his name and, blushing, +began to try to invent a name and to say something about his reason +for concealing it, but the Frenchman hastily interrupted him. + +"Oh, please!" said he. "I understand your reasons. You are an +officer... a superior officer perhaps. You have borne arms against us. +That's not my business. I owe you my life. That is enough for me. I am +quite at your service. You belong to the gentry?" he concluded with +a shade of inquiry in his tone. Pierre bent his head. "Your +baptismal name, if you please. That is all I ask. Monsieur Pierre, you +say.... That's all I want to know." + +When the mutton and an omelet had been served and a samovar and +vodka brought, with some wine which the French had taken from a +Russian cellar and brought with them, Ramballe invited Pierre to share +his dinner, and himself began to eat greedily and quickly like a +healthy and hungry man, munching his food rapidly with his strong +teeth, continually smacking his lips, and repeating--"Excellent! +Delicious!" His face grew red and was covered with perspiration. +Pierre was hungry and shared the dinner with pleasure. Morel, the +orderly, brought some hot water in a saucepan and placed a bottle of +claret in it. He also brought a bottle of kvass, taken from the +kitchen for them to try. That beverage was already known to the French +and had been given a special name. They called it limonade de cochon +(pig's lemonade), and Morel spoke well of the limonade de cochon he +had found in the kitchen. But as the captain had the wine they had +taken while passing through Moscow, he left the kvass to Morel and +applied himself to the bottle of Bordeaux. He wrapped the bottle up to +its neck in a table napkin and poured out wine for himself and for +Pierre. The satisfaction of his hunger and the wine rendered the +captain still more lively and he chatted incessantly all through +dinner. + +"Yes, my dear Monsieur Pierre, I owe you a fine votive candle for +saving me from that maniac.... You see, I have bullets enough in my +body already. Here is one I got at Wagram" (he touched his side) +"and a second at Smolensk"--he showed a scar on his cheek--"and this +leg which as you see does not want to march, I got that on the seventh +at the great battle of la Moskowa. Sacre Dieu! It was splendid! That +deluge of fire was worth seeing. It was a tough job you set us +there, my word! You may be proud of it! And on my honor, in spite of +the cough I caught there, I should be ready to begin again. I pity +those who did not see it." + +"I was there," said Pierre. + +"Bah, really? So much the better! You are certainly brave foes. +The great redoubt held out well, by my pipe!" continued the Frenchman. +"And you made us pay dear for it. I was at it three times--sure as I +sit here. Three times we reached the guns and three times we were +thrown back like cardboard figures. Oh, it was beautiful, Monsieur +Pierre! Your grenadiers were splendid, by heaven! I saw them close +up their ranks six times in succession and march as if on parade. Fine +fellows! Our King of Naples, who knows what's what, cried 'Bravo!' Ha, +ha! So you are one of us soldiers!" he added, smiling, after a +momentary pause. "So much the better, so much the better, Monsieur +Pierre! Terrible in battle... gallant... with the fair" (he winked and +smiled), "that's what the French are, Monsieur Pierre, aren't they?" + +The captain was so naively and good-humoredly gay, so real, and so +pleased with himself that Pierre almost winked back as he looked +merrily at him. Probably the word "gallant" turned the captain's +thoughts to the state of Moscow. + +"Apropos, tell me please, is it true that the women have all left +Moscow? What a queer idea! What had they to be afraid of?" + +"Would not the French ladies leave Paris if the Russians entered +it?" asked Pierre. + +"Ha, ha, ha!" The Frenchman emitted a merry, sanguine chuckle, +patting Pierre on the shoulder. "What a thing to say!" he exclaimed. +"Paris?... But Paris, Paris..." + +"Paris--the capital of the world," Pierre finished his remark for +him. + +The captain looked at Pierre. He had a habit of stopping short in +the middle of his talk and gazing intently with his laughing, kindly +eyes. + +"Well, if you hadn't told me you were Russian, I should have wagered +that you were Parisian! You have that... I don't know what, that..." +and having uttered this compliment, he again gazed at him in silence. + +"I have been in Paris. I spent years there," said Pierre. + +"Oh yes, one sees that plainly. Paris!... A man who doesn't know +Paris is a savage. You can tell a Parisian two leagues off. Paris is +Talma, la Duchenois, Potier, the Sorbonne, the boulevards," and +noticing that his conclusion was weaker than what had gone before, +he added quickly: "There is only one Paris in the world. You have been +to Paris and have remained Russian. Well, I don't esteem you the +less for it." + +Under the influence of the wine he had drunk, and after the days +he had spent alone with his depressing thoughts, Pierre +involuntarily enjoyed talking with this cheerful and good-natured man. + +"To return to your ladies--I hear they are lovely. What a wretched +idea to go and bury themselves in the steppes when the French army +is in Moscow. What a chance those girls have missed! Your peasants, +now--that's another thing; but you civilized people, you ought to know +us better than that. We took Vienna, Berlin, Madrid, Naples, Rome, +Warsaw, all the world's capitals.... We are feared, but we are +loved. We are nice to know. And then the Emperor..." he began, but +Pierre interrupted him. + +"The Emperor," Pierre repeated, and his face suddenly became sad and +embarrassed, "is the Emperor...?" + +"The Emperor? He is generosity, mercy, justice, order, genius- +that's what the Emperor is! It is I, Ramballe, who tell you so.... I +assure you I was his enemy eight years ago. My father was an +emigrant count.... But that man has vanquished me. He has taken hold +of me. I could not resist the sight of the grandeur and glory with +which he has covered France. When I understood what he wanted--when +I saw that he was preparing a bed of laurels for us, you know, I +said to myself: 'That is a monarch,' and I devoted myself to him! So +there! Oh yes, mon cher, he is the greatest man of the ages past or +future." + +"Is he in Moscow?" Pierre stammered with a guilty look. + +The Frenchman looked at his guilty face and smiled. + +"No, he will make his entry tomorrow," he replied, and continued his +talk. + +Their conversation was interrupted by the cries of several voices at +the gate and by Morel, who came to say that some Wurttemberg hussars +had come and wanted to put up their horses in the yard where the +captain's horses were. This difficulty had arisen chiefly because +the hussars did not understand what was said to them in French. + +The captain had their senior sergeant called in, and in a stern +voice asked him to what regiment he belonged, who was his commanding +officer, and by what right he allowed himself to claim quarters that +were already occupied. The German who knew little French, answered the +two first questions by giving the names of his regiment and of his +commanding officer, but in reply to the third question which he did +not understand said, introducing broken French into his own German, +that he was the quartermaster of the regiment and his commander had +ordered him to occupy all the houses one after another. Pierre, who +knew German, translated what the German said to the captain and gave +the captain's reply to the Wurttemberg hussar in German. When he had +understood what was said to him, the German submitted and took his men +elsewhere. The captain went out into the porch and gave some orders in +a loud voice. + +When he returned to the room Pierre was sitting in the same place as +before, with his head in his hands. His face expressed suffering. He +really was suffering at that moment. When the captain went out and +he was left alone, suddenly he came to himself and realized the +position he was in. It was not that Moscow had been taken or that +the happy conquerors were masters in it and were patronizing him. +Painful as that was it was not that which tormented Pierre at the +moment. He was tormented by the consciousness of his own weakness. The +few glasses of wine he had drunk and the conversation with this +good-natured man had destroyed the mood of concentrated gloom in which +he had spent the last few days and which was essential for the +execution of his design. The pistol, dagger, and peasant coat were +ready. Napoleon was to enter the town next day. Pierre still +considered that it would be a useful and worthy action to slay the +evildoer, but now he felt that he would not do it. He did not know +why, but he felt a foreboding that he would not carry out his +intention. He struggled against the confession of his weakness but +dimly felt that he could not overcome it and that his former gloomy +frame of mind, concerning vengeance, killing, and self-sacrifice, +had been dispersed like dust by contact with the first man he met. + +The captain returned to the room, limping slightly and whistling a +tune. + +The Frenchman's chatter which had previously amused Pierre now +repelled him. The tune he was whistling, his gait, and the gesture +with which he twirled his mustache, all now seemed offensive. "I +will go away immediately. I won't say another word to him," thought +Pierre. He thought this, but still sat in the same place. A strange +feeling of weakness tied him to the spot; he wished to get up and go +away, but could not do so. + +The captain, on the other hand, seemed very cheerful. He paced up +and down the room twice. His eyes shone and his mustache twitched as +if he were smiling to himself at some amusing thought. + +"The colonel of those Wurttembergers is delightful," he suddenly +said. "He's a German, but a nice fellow all the same.... But he's a +German." He sat down facing Pierre. "By the way, you know German, +then?" + +Pierre looked at him in silence. + +"What is the German for 'shelter'?" + +"Shelter?" Pierre repeated. "The German for shelter is Unterkunft." + +"How do you say it?" the captain asked quickly and doubtfully. + +"Unterkunft," Pierre repeated. + +"Onterkoff," said the captain and looked at Pierre for some +seconds with laughing eyes. "These Germans are first-rate fools, don't +you think so, Monsieur Pierre?" he concluded. + +"Well, let's have another bottle of this Moscow Bordeaux, shall +we? Morel will warm us up another little bottle. Morel!" he called out +gaily. + +Morel brought candles and a bottle of wine. The captain looked at +Pierre by the candlelight and was evidently struck by the troubled +expression on his companion's face. Ramballe, with genuine distress +and sympathy in his face, went up to Pierre and bent over him. + +"There now, we're sad," said he, touching Pierre's hand. "Have I +upset you? No, really, have you anything against me?" he asked Pierre. +"Perhaps it's the state of affairs?" + +Pierre did not answer, but looked cordially into the Frenchman's +eyes whose expression of sympathy was pleasing to him. + +"Honestly, without speaking of what I owe you, I feel friendship for +you. Can I do anything for you? Dispose of me. It is for life and +death. I say it with my hand on my heart!" said he, striking his +chest. + +"Thank you," said Pierre. + +The captain gazed intently at him as he had done when he learned +that "shelter" was Unterkunft in German, and his face suddenly +brightened. + +"Well, in that case, I drink to our friendship!" he cried gaily, +filling two glasses with wine. + +Pierre took one of the glasses and emptied it. Ramballe emptied +his too, again pressed Pierre's hand, and leaned his elbows on the +table in a pensive attitude. + +"Yes, my dear friend," he began, "such is fortune's caprice. Who +would have said that I should be a soldier and a captain of dragoons +in the service of Bonaparte, as we used to call him? Yet here I am +in Moscow with him. I must tell you, mon cher," he continued in the +sad and measured tones of a man who intends to tell a long story, +"that our name is one of the most ancient in France." + +And with a Frenchman's easy and naive frankness the captain told +Pierre the story of his ancestors, his childhood, youth, and +manhood, and all about his relations and his financial and family +affairs, "ma pauvre mere" playing of course an important part in the +story. + +"But all that is only life's setting, the real thing is love- +love! Am I not right, Monsieur Pierre?" said he, growing animated. +"Another glass?" + +Pierre again emptied his glass and poured himself out a third. + +"Oh, women, women!" and the captain, looking with glistening eyes at +Pierre, began talking of love and of his love affairs. + +There were very many of these, as one could easily believe, +looking at the officer's handsome, self-satisfied face, and noting the +eager enthusiasm with which he spoke of women. Though all Ramballe's +love stories had the sensual character which Frenchmen regard as the +special charm and poetry of love, yet he told his story with such +sincere conviction that he alone had experienced and known all the +charm of love and he described women so alluringly that Pierre +listened to him with curiosity. + +It was plain that l'amour which the Frenchman was so fond of was not +that low and simple kind that Pierre had once felt for his wife, nor +was it the romantic love stimulated by himself that he experienced for +Natasha. (Ramballe despised both these kinds of love equally: the +one he considered the "love of clodhoppers" and the other the "love of +simpletons.") L'amour which the Frenchman worshiped consisted +principally in the unnaturalness of his relation to the woman and in a +combination of incongruities giving the chief charm to the feeling. + +Thus the captain touchingly recounted the story of his love for a +fascinating marquise of thirty-five and at the same time for a +charming, innocent child of seventeen, daughter of the bewitching +marquise. The conflict of magnanimity between the mother and the +daughter, ending in the mother's sacrificing herself and offering +her daughter in marriage to her lover, even now agitated the +captain, though it was the memory of a distant past. Then he recounted +an episode in which the husband played the part of the lover, and +he--the lover--assumed the role of the husband, as well as several +droll incidents from his recollections of Germany, where "shelter" +is called Unterkunft and where the husbands eat sauerkraut and the +young girls are "too blonde." + +Finally, the latest episode in Poland still fresh in the captain's +memory, and which he narrated with rapid gestures and glowing face, +was of how he had saved the life of a Pole (in general, the saving +of life continually occurred in the captain's stories) and the Pole +had entrusted to him his enchanting wife (parisienne de coeur) while +himself entering the French service. The captain was happy, the +enchanting Polish lady wished to elope with him, but, prompted by +magnanimity, the captain restored the wife to the husband, saying as +he did so: "I have saved your life, and I save your honor!" Having +repeated these words the captain wiped his eyes and gave himself a +shake, as if driving away the weakness which assailed him at this +touching recollection. + +Listening to the captain's tales, Pierre--as often happens late in +the evening and under the influence of wine--followed all that was +told him, understood it all, and at the same time followed a train +of personal memories which, he knew not why, suddenly arose in his +mind. While listening to these love stories his own love for Natasha +unexpectedly rose to his mind, and going over the pictures of that +love in his imagination he mentally compared them with Ramballe's +tales. Listening to the story of the struggle between love and duty, +Pierre saw before his eyes every minutest detail of his last meeting +with the object of his love at the Sukharev water tower. At the time +of that meeting it had not produced an effect upon him--he had not +even once recalled it. But now it seemed to him that that meeting +had had in it something very important and poetic. + +"Peter Kirilovich, come here! We have recognized you," he now seemed +to hear the words she had uttered and to see before him her eyes, +her smile, her traveling hood, and a stray lock of her hair... and +there seemed to him something pathetic and touching in all this. + +Having finished his tale about the enchanting Polish lady, the +captain asked Pierre if he had ever experienced a similar impulse to +sacrifice himself for love and a feeling of envy of the legitimate +husband. + +Challenged by this question Pierre raised his head and felt a need +to express the thoughts that filled his mind. He began to explain that +he understood love for a women somewhat differently. He said that in +all his life he had loved and still loved only one woman, and that she +could never be his. + +"Tiens!" said the captain. + +Pierre then explained that he had loved this woman from his earliest +years, but that he had not dared to think of her because she was too +young, and because he had been an illegitimate son without a name. +Afterwards when he had received a name and wealth he dared not think +of her because he loved her too well, placing her far above everything +in the world, and especially therefore above himself. + +When he had reached this point, Pierre asked the captain whether +he understood that. + +The captain made a gesture signifying that even if he did not +understand it he begged Pierre to continue. + +"Platonic love, clouds..." he muttered. + +Whether it was the wine he had drunk, or an impulse of frankness, or +the thought that this man did not, and never would, know any of +those who played a part in his story, or whether it was all these +things together, something loosened Pierre's tongue. Speaking +thickly and with a faraway look in his shining eyes, he told the whole +story of his life: his marriage, Natasha's love for his best friend, +her betrayal of him, and all his own simple relations with her. +Urged on by Ramballe's questions he also told what he had at first +concealed--his own position and even his name. + +More than anything else in Pierre's story the captain was +impressed by the fact that Pierre was very rich, had two mansions in +Moscow, and that he had abandoned everything and not left the city, +but remained there concealing his name and station. + +When it was late at night they went out together into the street. +The night was warm and light. To the left of the house on the Pokrovka +a fire glowed--the first of those that were beginning in Moscow. To +the right and high up in the sky was the sickle of the waning moon and +opposite to it hung that bright comet which was connected in +Pierre's heart with his love. At the gate stood Gerasim, the cook, and +two Frenchmen. Their laughter and their mutually incomprehensible +remarks in two languages could be heard. They were looking at the glow +seen in the town. + +There was nothing terrible in the one small, distant fire in the +immense city. + +Gazing at the high starry sky, at the moon, at the comet, and at the +glow from the fire, Pierre experienced a joyful emotion. "There now, +how good it is, what more does one need?" thought he. And suddenly +remembering his intention he grew dizzy and felt so faint that he +leaned against the fence to save himself from falling. + +Without taking leave of his new friend, Pierre left the gate with +unsteady steps and returning to his room lay down on the sofa and +immediately fell asleep. + + + + + +CHAPTER XXX + + +The glow of the first fire that began on the second of September was +watched from the various roads by the fugitive Muscovites and by the +retreating troops, with many different feelings. + +The Rostov party spent the night at Mytishchi, fourteen miles from +Moscow. They had started so late on the first of September, the road +had been so blocked by vehicles and troops, so many things had been +forgotten for which servants were sent back, that they had decided +to spend that night at a place three miles out of Moscow. The next +morning they woke late and were again delayed so often that they +only got as far as Great Mytishchi. At ten o'clock that evening the +Rostov family and the wounded traveling with them were all distributed +in the yards and huts of that large village. The Rostovs' servants and +coachmen and the orderlies of the wounded officers, after attending to +their masters, had supper, fed the horses, and came out into the +porches. + +In a neighboring hut lay Raevski's adjutant with a fractured +wrist. The awful pain he suffered made him moan incessantly and +piteously, and his moaning sounded terrible in the darkness of the +autumn night. He had spent the first night in the same yard as the +Rostovs. The countess said she had been unable to close her eyes on +account of his moaning, and at Mytishchi she moved into a worse hut +simply to be farther away from the wounded man. + +In the darkness of the night one of the servants noticed, above +the high body of a coach standing before the porch, the small glow +of another fire. One glow had long been visible and everybody knew +that it was Little Mytishchi burning--set on fire by Mamonov's +Cossacks. + +"But look here, brothers, there's another fire!" remarked an +orderly. + +All turned their attention to the glow. + +"But they told us Little Mytishchi had been set on fire by Mamonov's +Cossacks." + +"But that's not Mytishchi, it's farther away." + +"Look, it must be in Moscow!" + +Two of the gazers went round to the other side of the coach and +sat down on its steps. + +"It's more to the left, why, Little Mytishchi is over there, and +this is right on the other side." + +Several men joined the first two. + +"See how it's flaring," said one. "That's a fire in Moscow: either +in the Sushchevski or the Rogozhski quarter." + +No one replied to this remark and for some time they all gazed +silently at the spreading flames of the second fire in the distance. + +Old Daniel Terentich, the count's valet (as he was called), came +up to the group and shouted at Mishka. + +"What are you staring at, you good-for-nothing?... The count will be +calling and there's nobody there; go and gather the clothes together." + +"I only ran out to get some water," said Mishka. + +"But what do you think, Daniel Terentich? Doesn't it look as if that +glow were in Moscow?" remarked one of the footmen. + +Daniel Terentich made no reply, and again for a long time they +were all silent. The glow spread, rising and failing, farther and +farther still. + +"God have mercy.... It's windy and dry..." said another voice. + +"Just look! See what it's doing now. O Lord! You can even see the +crows flying. Lord have mercy on us sinners!" + +"They'll put it out, no fear!" + +"Who's to put it out?" Daniel Terentich, who had hitherto been +silent, was heard to say. His voice was calm and deliberate. "Moscow +it is, brothers," said he. "Mother Moscow, the white..." his voice +faltered, and he gave way to an old man's sob. + +And it was as if they had all only waited for this to realize the +significance for them of the glow they were watching. Sighs were +heard, words of prayer, and the sobbing of the count's old valet. + + + + + +CHAPTER XXXI + + +The valet, returning to the cottage, informed the count that +Moscow was burning. The count donned his dressing gown and went out to +look. Sonya and Madame Schoss, who had not yet undressed, went out +with him. Only Natasha and the countess remained in the room. Petya +was no longer with the family, he had gone on with his regiment +which was making for Troitsa. + +The countess, on hearing that Moscow was on fire, began to cry. +Natasha, pale, with a fixed look, was sitting on the bench under the +icons just where she had sat down on arriving and paid no attention to +her father's words. She was listening to the ceaseless moaning of +the adjutant, three houses off. + +"Oh, how terrible," said Sonya returning from the yard chilled and +frightened. "I believe the whole of Moscow will burn, there's an awful +glow! Natasha, do look! You can see it from the window," she said to +her cousin, evidently wishing to distract her mind. + +But Natasha looked at her as if not understanding what was said to +her and again fixed her eyes on the corner of the stove. She had +been in this condition of stupor since the morning, when Sonya, to the +surprise and annoyance of the countess, had for some unaccountable +reason found it necessary to tell Natasha of Prince Andrew's wound and +of his being with their party. The countess had seldom been so angry +with anyone as she was with Sonya. Sonya had cried and begged to be +forgiven and now, as if trying to atone for her fault, paid +unceasing attention to her cousin. + +"Look, Natasha, how dreadfully it is burning!" said she. + +"What's burning?" asked Natasha. "Oh, yes, Moscow." + +And as if in order not to offend Sonya and to get rid of her, she +turned her face to the window, looked out in such a way that it was +evident that she could not see anything, and again settled down in her +former attitude. + +"But you didn't see it!" + +"Yes, really I did," Natasha replied in a voice that pleaded to be +left in peace. + +Both the countess and Sonya understood that, naturally, neither +Moscow nor the burning of Moscow nor anything else could seem of +importance to Natasha. + +The count returned and lay down behind the partition. The countess +went up to her daughter and touched her head with the back of her hand +as she was wont to do when Natasha was ill, then touched her +forehead with her lips as if to feel whether she was feverish, and +finally kissed her. + +"You are cold. You are trembling all over. You'd better lie down," +said the countess. + +"Lie down? All right, I will. I'll lie down at once," said Natasha. + +When Natasha had been told that morning that Prince Andrew was +seriously wounded and was traveling with their party, she had at first +asked many questions: Where was he going? How was he wounded? Was it +serious? And could she see him? But after she had been told that she +could not see him, that he was seriously wounded but that his life was +not in danger, she ceased to ask questions or to speak at all, +evidently disbelieving what they told her, and convinced that say what +she might she would still be told the same. All the way she had sat +motionless in a corner of the coach with wide open eyes, and the +expression in them which the countess knew so well and feared so much, +and now she sat in the same way on the bench where she had seated +herself on arriving. She was planning something and either deciding or +had already decided something in her mind. The countess knew this, but +what it might be she did not know, and this alarmed and tormented her. + +"Natasha, undress, darling; lie down on my bed." + +A bed had been made on a bedstead for the countess only. Madame +Schoss and the two girls were to sleep on some hay on the floor. + +"No, Mamma, I will lie down here on the floor," Natasha replied +irritably and she went to the window and opened it. Through the open +window the moans of the adjutant could be heard more distinctly. She +put her head out into the damp night air, and the countess saw her +slim neck shaking with sobs and throbbing against the window frame. +Natasha knew it was not Prince Andrew who was moaning. She knew Prince +Andrew was in the same yard as themselves and in a part of the hut +across the passage; but this dreadful incessant moaning made her +sob. The countess exchanged a look with Sonya. + +"Lie down, darling; lie down, my pet," said the countess, softly +touching Natasha's shoulders. "Come, lie down." + +"Oh, yes... I'll lie down at once," said Natasha, and began +hurriedly undressing, tugging at the tapes of her petticoat. + +When she had thrown off her dress and put on a dressing jacket, +she sat down with her foot under her on the bed that had been made +up on the floor, jerked her thin and rather short plait of hair to the +front, and began replaiting it. Her long, thin, practiced fingers +rapidly unplaited, replaited, and tied up her plait. Her head moved +from side to side from habit, but her eyes, feverishly wide, looked +fixedly before her. When her toilet for the night was finished she +sank gently onto the sheet spread over the hay on the side nearest the +door. + +"Natasha, you'd better lie in the middle," said Sonya. + +"I'll stay here," muttered Natasha. "Do lie down," she added +crossly, and buried her face in the pillow. + +The countess, Madame Schoss, and Sonya undressed hastily and lay +down. The small lamp in front of the icons was the only light left +in the room. But in the yard there was a light from the fire at Little +Mytishchi a mile and a half away, and through the night came the noise +of people shouting at a tavern Mamonov's Cossacks had set up across +the street, and the adjutant's unceasing moans could still be heard. + +For a long time Natasha listened attentively to the sounds that +reached her from inside and outside the room and did not move. First +she heard her mother praying and sighing and the creaking of her bed +under her, then Madame Schoss' familiar whistling snore and Sonya's +gentle breathing. Then the countess called to Natasha. Natasha did not +answer. + +"I think she's asleep, Mamma," said Sonya softly. + +After short silence the countess spoke again but this time no one +replied. + +Soon after that Natasha heard her mother's even breathing. Natasha +did not move, though her little bare foot, thrust out from under the +quilt, was growing cold on the bare floor. + +As if to celebrate a victory over everybody, a cricket chirped in +a crack in the wall. A cock crowed far off and another replied near +by. The shouting in the tavern had died down; only the moaning of +the adjutant was heard. Natasha sat up. + +"Sonya, are you asleep? Mamma?" she whispered. + +No one replied. Natasha rose slowly and carefully, crossed +herself, and stepped cautiously on the cold and dirty floor with her +slim, supple, bare feet. The boards of the floor creaked. Stepping +cautiously from one foot to the other she ran like a kitten the few +steps to the door and grasped the cold door handle. + +It seemed to her that something heavy was beating rhythmically +against all the walls of the room: it was her own heart, sinking +with alarm and terror and overflowing with love. + +She opened the door and stepped across the threshold and onto the +cold, damp earthen floor of the passage. The cold she felt refreshed +her. With her bare feet she touched a sleeping man, stepped over +him, and opened the door into the part of the hut where Prince +Andrew lay. It was dark in there. In the farthest corner, on a bench +beside a bed on which something was lying, stood a tallow candle +with a long, thick, and smoldering wick. + +From the moment she had been told that of Prince Andrew's wound +and his presence there, Natasha had resolved to see him. She did not +know why she had to, she knew the meeting would be painful, but felt +the more convinced that it was necessary. + +All day she had lived only in hope of seeing him that night. But now +that the moment had come she was filled with dread of what she might +see. How was he maimed? What was left of him? Was he like that +incessant moaning of the adjutant's? Yes, he was altogether like that. +In her imagination he was that terrible moaning personified. When +she saw an indistinct shape in the corner, and mistook his knees +raised under the quilt for his shoulders, she imagined a horrible body +there, and stood still in terror. But an irresistible impulse drew her +forward. She cautiously took one step and then another, and found +herself in the middle of a small room containing baggage. Another man- +Timokhin--was lying in a corner on the benches beneath the icons, +and two others--the doctor and a valet--lay on the floor. + +The valet sat up and whispered something. Timokhin, kept awake by +the pain in his wounded leg, gazed with wide-open eyes at this strange +apparition of a girl in a white chemise, dressing jacket, and +nightcap. The valet's sleepy, frightened exclamation, "What do you +want? What's the matter?" made Natasha approach more swiftly to what +was lying in the corner. Horribly unlike a man as that body looked, +she must see him. She passed the valet, the snuff fell from the candle +wick, and she saw Prince Andrew clearly with his arms outside the +quilt, and such as she had always seen him. + +He was the same as ever, but the feverish color of his face, his +glittering eyes rapturously turned toward her, and especially his +neck, delicate as a child's, revealed by the turn-down collar of his +shirt, gave him a peculiarly innocent, childlike look, such as she had +never seen on him before. She went up to him and with a swift, +flexible, youthful movement dropped on her knees. + +He smiled and held out his hand to her. + + + + + +CHAPTER XXXII + + +Seven days had passed since Prince Andrew found himself in the +ambulance station on the field of Borodino. His feverish state and the +inflammation of his bowels, which were injured, were in the doctor's + +opinion sure to carry him off. But on the seventh day he ate with +pleasure a piece of bread with some tea, and the doctor noticed that +his temperature was lower. He had regained consciousness that morning. +The first night after they left Moscow had been fairly warm and he had +remained in the caleche, but at Mytishchi the wounded man himself +asked to be taken out and given some tea. The pain caused by his +removal into the hut had made him groan aloud and again lose +consciousness. When he had been placed on his camp bed he lay for a +long time motionless with closed eyes. Then he opened them and +whispered softly: "And the tea?" His remembering such a small detail +of everyday life astonished the doctor. He felt Prince Andrew's pulse, +and to his surprise and dissatisfaction found it had improved. He +was dissatisfied because he knew by experience that if his patient did +not die now, he would do so a little later with greater suffering. +Timokhin, the red-nosed major of Prince Andrew's regiment, had +joined him in Moscow and was being taken along with him, having been +wounded in the leg at the battle of Borodino. They were accompanied by +a doctor, Prince Andrew's valet, his coachman, and two orderlies. + +They gave Prince Andrew some tea. He drank it eagerly, looking +with feverish eyes at the door in front of him as if trying to +understand and remember something. + +"I don't want any more. Is Timokhin here?" he asked. + +Timokhin crept along the bench to him. + +"I am here, your excellency." + +"How's your wound?" + +"Mine, sir? All right. But how about you?" + +Prince Andrew again pondered as if trying to remember something. + +"Couldn't one get a book?" he asked. + +"What book?" + +"The Gospels. I haven't one." + +The doctor promised to procure it for him and began to ask how he +was feeling. Prince Andrew answered all his questions reluctantly +but reasonably, and then said he wanted a bolster placed under him +as he was uncomfortable and in great pain. The doctor and valet lifted +the cloak with which he was covered and, making wry faces at the +noisome smell of mortifying flesh that came from the wound, began +examining that dreadful place. The doctor was very much displeased +about something and made a change in the dressings, turning the +wounded man over so that he groaned again and grew unconscious and +delirious from the agony. He kept asking them to get him the book +and put it under him. + +"What trouble would it be to you?" he said. "I have not got one. +Please get it for me and put it under for a moment," he pleaded in a +piteous voice. + +The doctor went into the passage to wash his hands. + +"You fellows have no conscience," said he to the valet who was +pouring water over his hands. "For just one moment I didn't look after +you... It's such pain, you know, that I wonder how he can bear it." + +"By the Lord Jesus Christ, I thought we had put something under +him!" said the valet. + +The first time Prince Andrew understood where he was and what was +the matter with him and remembered being wounded and how was when he +asked to be carried into the hut after his caleche had stopped at +Mytishchi. After growing confused from pain while being carried into +the hut he again regained consciousness, and while drinking tea once +more recalled all that had happened to him, and above all vividly +remembered the moment at the ambulance station when, at the sight of +the sufferings of a man he disliked, those new thoughts had come to +him which promised him happiness. And those thoughts, though now vague +and indefinite, again possessed his soul. He remembered that he had +now a new source of happiness and that this happiness had something to +do with the Gospels. That was why he asked for a copy of them. The +uncomfortable position in which they had put him and turned him over +again confused his thoughts, and when he came to himself a third +time it was in the complete stillness of the night. Everybody near him +was sleeping. A cricket chirped from across the passage; someone was +shouting and singing in the street; cockroaches rustled on the +table, on the icons, and on the walls, and a big fly flopped at the +head of the bed and around the candle beside him, the wick of which +was charred and had shaped itself like a mushroom. + +His mind was not in a normal state. A healthy man usually thinks of, +feels, and remembers innumerable things simultaneously, but has the +power and will to select one sequence of thoughts or events on which +to fix his whole attention. A healthy man can tear himself away from +the deepest reflections to say a civil word to someone who comes in +and can then return again to his own thoughts. But Prince Andrew's +mind was not in a normal state in that respect. All the powers of +his mind were more active and clearer than ever, but they acted +apart from his will. Most diverse thoughts and images occupied him +simultaneously. At times his brain suddenly began to work with a +vigor, clearness, and depth it had never reached when he was in +health, but suddenly in the midst of its work it would turn to some +unexpected idea and he had not the strength to turn it back again. + +"Yes, a new happiness was revealed to me of which man cannot be +deprived," he thought as he lay in the semi-darkness of the quiet hut, +gazing fixedly before him with feverish wide open eyes. "A happiness +lying beyond material forces, outside the material influences that act +on man--a happiness of the soul alone, the happiness of loving. +Every man can understand it, but to conceive it and enjoin it was +possible only for God. But how did God enjoin that law? And why was +the Son...?" + +And suddenly the sequence of these thoughts broke off, and Prince +Andrew heard (without knowing whether it was a delusion or reality) +a soft whispering voice incessantly and rhythmically repeating +"piti-piti-piti," and then "titi," and then again "piti-piti-piti," +and "ti-ti" once more. At the same time he felt that above his face, +above the very middle of it, some strange airy structure was being +erected out of slender needles or splinters, to the sound of this +whispered music. He felt that he had to balance carefully (though it +was difficult) so that this airy structure should not collapse; but +nevertheless it kept collapsing and again slowly rising to the sound +of whispered rhythmic music--"it stretches, stretches, spreading out +and stretching," said Prince Andrew to himself. While listening to +this whispering and feeling the sensation of this drawing out and +the construction of this edifice of needles, he also saw by glimpses a +red halo round the candle, and heard the rustle of the cockroaches and +the buzzing of the fly that flopped against his pillow and his face. +Each time the fly touched his face it gave him a burning sensation and +yet to his surprise it did not destroy the structure, though it +knocked against the very region of his face where it was rising. But +besides this there was something else of importance. It was +something white by the door--the statue of a sphinx, which also +oppressed him. + +"But perhaps that's my shirt on the table," he thought, "and +that's my legs, and that is the door, but why is it always +stretching and drawing itself out, and 'piti-piti-piti' and 'ti-ti' +and 'piti-piti-piti'...? That's enough, please leave off!" Prince +Andrew painfully entreated someone. And suddenly thoughts and feelings +again swam to the surface of his mind with peculiar clearness and +force. + +"Yes--love," he thought again quite clearly. "But not love which +loves for something, for some quality, for some purpose, or for some +reason, but the love which I--while dying--first experienced when I +saw my enemy and yet loved him. I experienced that feeling of love +which is the very essence of the soul and does not require an +object. Now again I feel that bliss. To love one's neighbors, to +love one's enemies, to love everything, to love God in all His +manifestations. It is possible to love someone dear to you with +human love, but an enemy can only be loved by divine love. That is why +I experienced such joy when I felt that I loved that man. What has +become of him? Is he alive?... + +"When loving with human love one may pass from love to hatred, but +divine love cannot change. No, neither death nor anything else can +destroy it. It is the very essence of the soul. Yet how many people +have I hated in my life? And of them all, I loved and hated none as +I did her." And he vividly pictured to himself Natasha, not as he +had done in the past with nothing but her charms which gave him +delight, but for the first time picturing to himself her soul. And +he understood her feelings, her sufferings, shame, and remorse. He now +understood for the first time all the cruelty of his rejection of her, +the cruelty of his rupture with her. "If only it were possible for +me to see her once more! Just once, looking into those eyes to say..." + + +"Piti-piti-piti and ti-ti and piti-piti-piti boom!" flopped the +fly... And his attention was suddenly carried into another world, a +world of reality and delirium in which something particular was +happening. In that world some structure was still being erected and +did not fall, something was still stretching out, and the candle +with its red halo was still burning, and the same shirtlike sphinx lay +near the door; but besides all this something creaked, there was a +whiff of fresh air, and a new white sphinx appeared, standing at the +door. And that sphinx had the pale face and shining eyes of the very +Natasha of whom he had just been thinking. + +"Oh, how oppressive this continual delirium is," thought Prince +Andrew, trying to drive that face from his imagination. But the face +remained before him with the force of reality and drew nearer. +Prince Andrew wished to return that former world of pure thought, +but he could not, and delirium drew him back into its domain. The soft +whispering voice continued its rhythmic murmur, something oppressed +him and stretched out, and the strange face was before him. Prince +Andrew collected all his strength in an effort to recover his +senses, he moved a little, and suddenly there was a ringing in his +ears, a dimness in his eyes, and like a man plunged into water he lost +consciousness. When he came to himself, Natasha, that same living +Natasha whom of all people he most longed to love with this new pure +divine love that had been revealed to him, was kneeling before him. He +realized that it was the real living Natasha, and he was not surprised +but quietly happy. Natasha, motionless on her knees (she was unable to +stir), with frightened eyes riveted on him, was restraining her +sobs. Her face was pale and rigid. Only in the lower part of it +something quivered. + +Prince Andrew sighed with relief, smiled, and held out his hand. + +"You?" he said. "How fortunate!" + +With a rapid but careful movement Natasha drew nearer to him on +her knees and, taking his hand carefully, bent her face over it and +began kissing it, just touching it lightly with her lips. + +"Forgive me!" she whispered, raising her head and glancing at him. +"Forgive me!" + +"I love you," said Prince Andrew. + +"Forgive...!" + +"Forgive what?" he asked. + +"Forgive me for what I ha-ve do-ne!" faltered Natasha in a +scarcely audible, broken whisper, and began kissing his hand more +rapidly, just touching it with her lips. + +"I love you more, better than before," said Prince Andrew, lifting +her face with his hand so as to look into her eyes. + +Those eyes, filled with happy tears, gazed at him timidly, +compassionately, and with joyous love. Natasha's thin pale face, +with its swollen lips, was more than plain--it was dreadful. But +Prince Andrew did not see that, he saw her shining eyes which were +beautiful. They heard the sound of voices behind them. + +Peter the valet, who was now wide awake, had roused the doctor. +Timokhin, who had not slept at all because of the pain in his leg, had +long been watching all that was going on, carefully covering his +bare body with the sheet as he huddled up on his bench. + +"What's this?" said the doctor, rising from his bed. "Please go +away, madam!" + +At that moment a maid sent by the countess, who had noticed her +daughter's absence, knocked at the door. + +Like a somnambulist aroused from her sleep Natasha went out of the +room and, returning to her hut, fell sobbing on her bed. + + +From that time, during all the rest of the Rostovs' journey, at +every halting place and wherever they spent a night, Natasha never +left the wounded Bolkonski, and the doctor had to admit that he had +not expected from a young girl either such firmness or such skill in +nursing a wounded man. + +Dreadful as the countess imagined it would be should Prince Andrew +die in her daughter's arms during the journey--as, judging by what the +doctor said, it seemed might easily happen--she could not oppose +Natasha. Though with the intimacy now established between the +wounded man and Natasha the thought occurred that should he recover +their former engagement would be renewed, no one--least of all Natasha +and Prince Andrew--spoke of this: the unsettled question of life and +death, which hung not only over Bolkonski but over all Russia, shut +out all other considerations. + + + + + +CHAPTER XXXIII + + +On the third of September Pierre awoke late. His head was aching, +the clothes in which he had slept without undressing felt +uncomfortable on his body, and his mind had a dim consciousness of +something shameful he had done the day before. That something shameful +was his yesterday's conversation with Captain Ramballe. + +It was eleven by the clock, but it seemed peculiarly dark out of +doors. Pierre rose, rubbed his eyes, and seeing the pistol with an +engraved stock which Gerasim had replaced on the writing table, he +remembered where he was and what lay before him that very day. + +"Am I not too late?" he thought. "No, probably he won't make his +entry into Moscow before noon." + +Pierre did not allow himself to reflect on what lay before him, +but hastened to act. + +After arranging his clothes, he took the pistol and was about to +go out. But it then occurred to him for the first time that he +certainly could not carry the weapon in his hand through the +streets. It was difficult to hide such a big pistol even under his +wide coat. He could not carry it unnoticed in his belt or under his +arm. Besides, it had been discharged, and he had not had time to +reload it. "No matter, dagger will do," he said to himself, though +when planning his design he had more than once come to the +conclusion that the chief mistake made by the student in 1809 had been +to try to kill Napoleon with a dagger. But as his chief aim +consisted not in carrying out his design, but in proving to himself +that he would not abandon his intention and was doing all he could +to achieve it, Pierre hastily took the blunt jagged dagger in a +green sheath which he had bought at the Sukharev market with the +pistol, and hid it under his waistcoat. + +Having tied a girdle over his coat and pulled his cap low on his +head, Pierre went down the corridor, trying to avoid making a noise or +meeting the captain, and passed out into the street. + +The conflagration, at which he had looked with so much +indifference the evening before, had greatly increased during the +night. Moscow was on fire in several places. The buildings in Carriage +Row, across the river, in the Bazaar and the Povarskoy, as well as the +barges on the Moskva River and the timber yards by the Dorogomilov +Bridge, were all ablaze. + +Pierre's way led through side streets to the Povarskoy and from +there to the church of St. Nicholas on the Arbat, where he had long +before decided that the deed should should be done. The gates of +most of the houses were locked and the shutters up. The streets and +lanes were deserted. The air was full of smoke and the smell of +burning. Now and then he met Russians with anxious and timid faces, +and Frenchmen with an air not of the city but of the camp, walking +in the middle of the streets. Both the Russians and the French +looked at Pierre with surprise. Besides his height and stoutness, +and the strange morose look of suffering in his face and whole figure, +the Russians stared at Pierre because they could not make out to +what class he could belong. The French followed him with +astonishment in their eyes chiefly because Pierre, unlike all the +other Russians who gazed at the French with fear and curiosity, paid +no attention to them. At the gate of one house three Frenchmen, who +were explaining something to some Russians who did not understand +them, stopped Pierre asking if he did not know French. + +Pierre shook his head and went on. In another side street a sentinel +standing beside a green caisson shouted at him, but only when the +shout was threateningly repeated and he heard the click of the man's +musket as he raised it did Pierre understand that he had to pass on +the other side of the street. He heard nothing and saw nothing of what +went on around him. He carried his resolution within himself in terror +and haste, like something dreadful and alien to him, for, after the +previous night's experience, he was afraid of losing it. But he was +not destined to bring his mood safely to his destination. And even had +he not been hindered by anything on the way, his intention could not +now have been carried out, for Napoleon had passed the Arbat more than +four hours previously on his way from the Dorogomilov suburb to the +Kremlin, and was now sitting in a very gloomy frame of mind in a royal +study in the Kremlin, giving detailed and exact orders as to +measures to be taken immediately to extinguish the fire, to prevent +looting, and to reassure the inhabitants. But Pierre did not know +this; he was entirely absorbed in what lay before him, and was +tortured--as those are who obstinately undertake a task that is +impossible for them not because of its difficulty but because of its +incompatibility with their natures--by the fear of weakening at the +decisive moment and so losing his self-esteem. + +Though he heard and saw nothing around him he found his way by +instinct and did not go wrong in the side streets that led to the +Povarskoy. + +As Pierre approached that street the smoke became denser and denser- +he even felt the heat of the fire. Occasionally curly tongues of flame +rose from under the roofs of the houses. He met more people in the +streets and they were more excited. But Pierre, though he felt that +something unusual was happening around him, did not realize that he +was approaching the fire. As he was going along a foot path across a +wide-open space adjoining the Povarskoy on one side and the gardens of +Prince Gruzinski's house on the other, Pierre suddenly heard the +desperate weeping of a woman close to him. He stopped as if +awakening from a dream and lifted his head. + +By the side of the path, on the dusty dry grass, all sorts of +household goods lay in a heap: featherbeds, a samovar, icons, and +trunks. On the ground, beside the trunks, sat a thin woman no longer +young, with long, prominent upper teeth, and wearing a black cloak and +cap. This woman, swaying to and fro and muttering something, was +choking with sobs. Two girls of about ten and twelve, dressed in dirty +short frocks and cloaks, were staring at their mother with a look of +stupefaction on their pale frightened faces. The youngest child, a boy +of about seven, who wore an overcoat and an immense cap evidently +not his own, was crying in his old nurse's arms. A dirty, barefooted +maid was sitting on a trunk, and, having undone her pale-colored +plait, was pulling it straight and sniffing at her singed hair. The +woman's husband, a short, round-shouldered man in the undress +uniform of a civilian official, with sausage-shaped whiskers and +showing under his square-set cap the hair smoothly brushed forward +over his temples, with expressionless face was moving the trunks, +which were placed one on another, and was dragging some garments +from under them. + +As soon as she saw Pierre, the woman almost threw herself at his +feet. + +"Dear people, good Christians, save me, help me, dear friends... +help us, somebody," she muttered between her sobs. "My girl... My +daughter! My youngest daughter is left behind. She's burned! Ooh! +Was it for this I nursed you.... Ooh!" + +"Don't, Mary Nikolievna!" said her husband to her in a low voice, +evidently only to justify himself before the stranger. "Sister must +have taken her, or else where can she be?" he added. + +"Monster! Villain!" shouted the woman angrily, suddenly ceasing to +weep. "You have no heart, you don't feel for your own child! Another +man would have rescued her from the fire. But this is a monster and +neither a man nor a father! You, honored sir, are a noble man," she +went on, addressing Pierre rapidly between her sobs. "The fire broke +out alongside, and blew our way, the maid called out 'Fire!' and we +rushed to collect our things. We ran out just as we were.... This is +what we have brought away.... The icons, and my dowry bed, all the +rest is lost. We seized the children. But not Katie! Ooh! O +Lord!..." and again she began to sob. "My child, my dear one! +Burned, burned!" + +"But where was she left?" asked Pierre. + +From the expression of his animated face the woman saw that this man +might help her. + +"Oh, dear sir!" she cried, seizing him by the legs. "My +benefactor, set my heart at ease.... Aniska, go, you horrid girl, show +him the way!" she cried to the maid, angrily opening her mouth and +still farther exposing her long teeth. + +"Show me the way, show me, I... I'll do it," gasped Pierre rapidly. + +The dirty maidservant stepped from behind the trunk, put up her +plait, sighed, and went on her short, bare feet along the path. Pierre +felt as if he had come back to life after a heavy swoon. He held his +head higher, his eyes shone with the light of life, and with swift +steps he followed the maid, overtook her, and came out on the +Povarskoy. The whole street was full of clouds of black smoke. Tongues +of flame here and there broke through that cloud. A great number of +people crowded in front of the conflagration. In the middle of the +street stood a French general saying something to those around him. +Pierre, accompanied by the maid, was advancing to the spot where the +general stood, but the French soldiers stopped him. + +"On ne passe pas!"* cried a voice. + + +*"You can't pass! + + +"This way, uncle," cried the girl. "We'll pass through the side +street, by the Nikulins'!" + +Pierre turned back, giving a spring now and then to keep up with +her. She ran across the street, turned down a side street to the left, +and, passing three houses, turned into a yard on the right. + +"It's here, close by," said she and, running across the yard, opened +a gate in a wooden fence and, stopping, pointed out to him a small +wooden wing of the house, which was burning brightly and fiercely. One +of its sides had fallen in, another was on fire, and bright flames +issued from the openings of the windows and from under the roof. + +As Pierre passed through the fence gate, he was enveloped by hot air +and involuntarily stopped. + +"Which is it? Which is your house?" he asked. + +"Ooh!" wailed the girl, pointing to the wing. "That's it, that was +our lodging. You've burned to death, our treasure, Katie, my +precious little missy! Ooh!" lamented Aniska, who at the sight of +the fire felt that she too must give expression to her feelings. + +Pierre rushed to the wing, but the heat was so great that he +involuntarily passed round in a curve and came upon the large house +that was as yet burning only at one end, just below the roof, and +around which swarmed a crowd of Frenchmen. At first Pierre did not +realize what these men, who were dragging something out, were about; +but seeing before him a Frenchman hitting a peasant with a blunt saber +and trying to take from him a fox-fur coat, he vaguely understood that +looting was going on there, but he had no time to dwell on that idea. + +The sounds of crackling and the din of falling walls and ceilings, +the whistle and hiss of the flames, the excited shouts of the +people, and the sight of the swaying smoke, now gathering into thick +black clouds and now soaring up with glittering sparks, with here +and there dense sheaves of flame (now red and now like golden fish +scales creeping along the walls), and the heat and smoke and +rapidity of motion, produced on Pierre the usual animating effects +of a conflagration. It had a peculiarly strong effect on him because +at the sight of the fire he felt himself suddenly freed from the ideas +that had weighed him down. He felt young, bright, adroit, and +resolute. He ran round to the other side of the lodge and was about to +dash into that part of it which was still standing, when just above +his head he heard several voices shouting and then a cracking sound +and the ring of something heavy falling close beside him. + +Pierre looked up and saw at a window of the large house some +Frenchmen who had just thrown out the drawer of a chest, filled with +metal articles. Other French soldiers standing below went up to the +drawer. + +"What does this fellow want?" shouted one of them referring to +Pierre. + +"There's a child in that house. Haven't you seen a child?" cried +Pierre. + +"What's he talking about? Get along!" said several voices, and one +of the soldiers, evidently afraid that Pierre might want to take +from them some of the plate and bronzes that were in the drawer, moved +threateningly toward him. + +"A child?" shouted a Frenchman from above. "I did hear something +squealing in the garden. Perhaps it's his brat that the fellow is +looking for. After all, one must be human, you know...." + +"Where is it? Where?" said Pierre. + +"There! There!" shouted the Frenchman at the window, pointing to the +garden at the back of the house. "Wait a bit--I'm coming down." + +And a minute or two later the Frenchman, a black-eyed fellow with +a spot on his cheek, in shirt sleeves, really did jump out of a window +on the ground floor, and clapping Pierre on the shoulder ran with +him into the garden. + +"Hurry up, you others!" he called out to his comrades. "It's getting +hot." + +When they reached a gravel path behind the house the Frenchman +pulled Pierre by the arm and pointed to a round, graveled space +where a three-year-old girl in a pink dress was lying under a seat. + +"There is your child! Oh, a girl, so much the better!" said the +Frenchman. "Good-by, Fatty. We must be human, we are all mortal you +know!" and the Frenchman with the spot on his cheek ran back to his +comrades. + +Breathless with joy, Pierre ran to the little girl and was going +to take her in his arms. But seeing a stranger the sickly, +scrofulous-looking child, unattractively like her mother, began to +yell and run away. Pierre, however, seized her and lifted her in his +arms. She screamed desperately and angrily and tried with her little +hands to pull Pierre's hands away and to bite them with her slobbering +mouth. Pierre was seized by a sense of horror and repulsion such as he +had experienced when touching some nasty little animal. But he made an +effort not to throw the child down and ran with her to the large +house. It was now, however, impossible to get back the way he had +come; the maid, Aniska, was no longer there, and Pierre with a feeling +of pity and disgust pressed the wet, painfully sobbing child to +himself as tenderly as he could and ran with her through the garden +seeking another way out. + + + + + +CHAPTER XXXIV + + +Having run through different yards and side streets, Pierre got back +with his little burden to the Gruzinski garden at the corner of the +Povarskoy. He did not at first recognize the place from which he had +set out to look for the child, so crowded was it now with people and +goods that had been dragged out of the houses. Besides Russian +families who had taken refuge here from the fire with their +belongings, there were several French soldiers in a variety of +clothing. Pierre took no notice of them. He hurried to find the family +of that civil servant in order to restore the daughter to her mother +and go to save someone else. Pierre felt that he had still much to +do and to do quickly. Glowing with the heat and from running, he +felt at that moment more strongly than ever the sense of youth, +animation, and determination that had come on him when he ran to +save the child. She had now become quiet and, clinging with her little +hands to Pierre's coat, sat on his arm gazing about her like some +little wild animal. He glanced at her occasionally with a slight +smile. He fancied he saw something pathetically innocent in that +frightened, sickly little face. + +He did not find the civil servant or his wife where he had left +them. He walked among the crowd with rapid steps, scanning the various +faces he met. Involuntarily he noticed a Georgian or Armenian family +consisting of a very handsome old man of Oriental type, wearing a new, +cloth-covered, sheepskin coat and new boots, an old woman of similar +type, and a young woman. That very young woman seemed to Pierre the +perfection of Oriental beauty, with her sharply outlined, arched, +black eyebrows and the extraordinarily soft, bright color of her long, +beautiful, expressionless face. Amid the scattered property and the +crowd on the open space, she, in her rich satin cloak with a bright +lilac shawl on her head, suggested a delicate exotic plant thrown +out onto the snow. She was sitting on some bundles a little behind the +old woman, and looked from under her long lashes with motionless, +large, almond-shaped eyes at the ground before her. Evidently she +was aware of her beauty and fearful because of it. Her face struck +Pierre and, hurrying along by the fence, he turned several times to +look at her. When he had reached the fence, still without finding +those he sought, he stopped and looked about him. + +With the child in his arms his figure was now more conspicuous +than before, and a group of Russians, both men and women, gathered +about him. + +"Have you lost anyone, my dear fellow? You're of the gentry +yourself, aren't you? Whose child is it?" they asked him. + +Pierre replied that the child belonged to a woman in a black coat +who had been sitting there with her other children, and he asked +whether anyone knew where she had gone. + +"Why, that must be the Anferovs," said an old deacon, addressing a +pockmarked peasant woman. "Lord have mercy, Lord have mercy!" he added +in his customary bass. + +"The Anferovs? No," said the woman. "They left in the morning. +That must be either Mary Nikolievna's or the Ivanovs'!" + +"He says 'a woman,' and Mary Nikolievna is a lady," remarked a house +serf. + +"Do you know her? She's thin, with long teeth," said Pierre. + +"That's Mary Nikolievna! They went inside the garden when these +wolves swooped down," said the woman, pointing to the French soldiers. + +"O Lord, have mercy!" added the deacon. + +"Go over that way, they're there. It's she! She kept on lamenting +and crying," continued the woman. "It's she. Here, this way!" + +But Pierre was not listening to the woman. He had for some seconds +been intently watching what was going on a few steps away. He was +looking at the Armenian family and at two French soldiers who had gone +up to them. One of these, a nimble little man, was wearing a blue coat +tied round the waist with a rope. He had a nightcap on his head and +his feet were bare. The other, whose appearance particularly struck +Pierre, was a long, lank, round-shouldered, fair-haired man, slow in +his movements and with an idiotic expression of face. He wore a +woman's loose gown of frieze, blue trousers, and large torn Hessian +boots. The little barefooted Frenchman in the blue coat went up to the +Armenians and, saying something, immediately seized the old man by his +legs and the old man at once began pulling off his boots. The other in +the frieze gown stopped in front of the beautiful Armenian girl and +with his hands in his pockets stood staring at her, motionless and +silent. + +"Here, take the child!" said Pierre peremptorily and hurriedly to +the woman, handing the little girl to her. "Give her back to them, +give her back!" he almost shouted, putting the child, who began +screaming, on the ground, and again looking at the Frenchman and the +Armenian family. + +The old man was already sitting barefoot. The little Frenchman had +secured his second boot and was slapping one boot against the other. +The old man was saying something in a voice broken by sobs, but Pierre +caught but a glimpse of this, his whole attention was directed to +the Frenchman in the frieze gown who meanwhile, swaying slowly from +side to side, had drawn nearer to the young woman and taking his hands +from his pockets had seized her by the neck. + +The beautiful Armenian still sat motionless and in the same +attitude, with her long lashes drooping as if she did not see or +feel what the soldier was doing to her. + +While Pierre was running the few steps that separated him from the +Frenchman, the tall marauder in the frieze gown was already tearing +from her neck the necklace the young Armenian was wearing, and the +young woman, clutching at her neck, screamed piercingly. + +"Let that woman alone!" exclaimed Pierre hoarsely in a furious +voice, seizing the soldier by his round shoulders and throwing him +aside. + +The soldier fell, got up, and ran away. But his comrade, throwing +down the boots and drawing his sword, moved threateningly toward +Pierre. + +"Voyons, Pas de betises!"* he cried. + + +*"Look here, no nonsense!" + + +Pierre was in such a transport of rage that he remembered nothing +and his strength increased tenfold. He rushed at the barefooted +Frenchman and, before the latter had time to draw his sword, knocked +him off his feet and hammered him with his fists. Shouts of approval +were heard from the crowd around, and at the same moment a mounted +patrol of French Uhlans appeared from round the corner. The Uhlans +came up at a trot to Pierre and the Frenchman and surrounded them. +Pierre remembered nothing of what happened after that. He only +remembered beating someone and being beaten and finally feeling that +his hands were bound and that a crowd of French soldiers stood +around him and were searching him. + +"Lieutenant, he has a dagger," were the first words Pierre +understood. + +"Ah, a weapon?" said the officer and turned to the barefooted +soldier who had been arrested with Pierre. "All right, you can tell +all about it at the court-martial." Then he turned to Pierre. "Do +you speak French?" + +Pierre looked around him with bloodshot eyes and did not reply. +His face probably looked very terrible, for the officer said something +in a whisper and four more Uhlans left the ranks and placed themselves +on both sides of Pierre. + +"Do you speak French?" the officer asked again, keeping at a +distance from Pierre. "Call the interpreter." + +A little man in Russian civilian clothes rode out from the ranks, +and by his clothes and manner of speaking Pierre at once knew him to +be a French salesman from one of the Moscow shops. + +"He does not look like a common man," said the interpreter, after +a searching look at Pierre. + +"Ah, he looks very much like an incendiary," remarked the officer. +"And ask him who he is," he added. + +"Who are you?" asked the interpreter in poor Russian. "You must +answer the chief." + +"I will not tell you who I am. I am your prisoner--take me!" +Pierre suddenly replied in French. + +"Ah, ah!" muttered the officer with a frown. "Well then, march!" + +A crowd had collected round the Uhlans. Nearest to Pierre stood +the pockmarked peasant woman with the little girl, and when the patrol +started she moved forward. + +"Where are they taking you to, you poor dear?" said she. "And the +little girl, the little girl, what am I to do with her if she's not +theirs?" said the woman. + +"What does that woman want?" asked the officer. + +Pierre was as if intoxicated. His elation increased at the sight +of the little girl he had saved. + +"What does she want?" he murmured. "She is bringing me my daughter +whom I have just saved from the flames," said he. "Good-by!" And +without knowing how this aimless lie had escaped him, he went along +with resolute and triumphant steps between the French soldiers. + +The French patrol was one of those sent out through the various +streets of Moscow by Durosnel's order to put a stop to the pillage, +and especially to catch the incendiaries who, according to the general +opinion which had that day originated among the higher French +officers, were the cause of the conflagrations. After marching through +a number of streets the patrol arrested five more Russian suspects: +a small shopkeeper, two seminary students, a peasant, and a house +serf, besides several looters. But of all these various suspected +characters, Pierre was considered to be the most suspicious of all. +When they had all been brought for the night to a large house on the +Zubov Rampart that was being used as a guardhouse, Pierre was placed +apart under strict guard. + + + + + +BOOK TWELVE: 1812 + + + + + +CHAPTER I + + +In Petersburg at that time a complicated struggle was being +carried on with greater heat than ever in the highest circles, between +the parties of Rumyantsev, the French, Marya Fedorovna, the Tsarevich, +and others, drowned as usual by the buzzing of the court drones. But +the calm, luxurious life of Petersburg, concerned only about +phantoms and reflections of real life, went on in its old way and made +it hard, except by a great effort, to realize the danger and the +difficult position of the Russian people. There were the same +receptions and balls, the same French theater, the same court +interests and service interests and intrigues as usual. Only in the +very highest circles were attempts made to keep in mind the +difficulties of the actual position. Stories were whispered of how +differently the two Empresses behaved in these difficult +circumstances. The Empress Marya, concerned for the welfare of the +charitable and educational institutions under her patronage, had given +directions that they should all be removed to Kazan, and the things +belonging to these institutions had already been packed up. The +Empress Elisabeth, however, when asked what instructions she would +be pleased to give--with her characteristic Russian patriotism had +replied that she could give no directions about state institutions for +that was the affair of the sovereign, but as far as she personally was +concerned she would be the last to quit Petersburg. + +At Anna Pavlovna's on the twenty-sixth of August, the very day of +the battle of Borodino, there was a soiree, the chief feature of which +was to be the reading of a letter from His Lordship the Bishop when +sending the Emperor an icon of the Venerable Sergius. It was +regarded as a model of ecclesiastical, patriotic eloquence. Prince +Vasili himself, famed for his elocution, was to read it. (He used to +read at the Empress'.) The art of his reading was supposed to lie in +rolling out the words, quite independently of their meaning, in a loud +and singsong voice alternating between a despairing wail and a +tender murmur, so that the wail fell quite at random on one word and +the murmur on another. This reading, as was always the case at Anna +Pavlovna's soirees, had a political significance. That evening she +expected several important personages who had to be made ashamed of +their visits to the French theater and aroused to a patriotic +temper. A good many people had already arrived, but Anna Pavlovna, not +yet seeing all those whom she wanted in her drawing room, did not +let the reading begin but wound up the springs of a general +conversation. + +The news of the day in Petersburg was the illness of Countess +Bezukhova. She had fallen ill unexpectedly a few days previously, +had missed several gatherings of which she was usually ornament, and +was said to be receiving no one, and instead of the celebrated +Petersburg doctors who usually attended her had entrusted herself to +some Italian doctor who was treating her in some new and unusual way. + +They all knew very well that the enchanting countess' illness +arose from an inconvenience resulting from marrying two husbands at +the same time, and that the Italian's cure consisted in removing +such inconvenience; but in Anna Pavlovna's presence no one dared to +think of this or even appear to know it. + +"They say the poor countess is very ill. The doctor says it is +angina pectoris." + +"Angina? Oh, that's a terrible illness!" + +"They say that the rivals are reconciled, thanks to the angina..." +and the word angina was repeated with great satisfaction. + +"The count is pathetic, they say. He cried like a child when the +doctor told him the case was dangerous." + +"Oh, it would be a terrible loss, she is an enchanting woman." + +"You are speaking of the poor countess?" said Anna Pavlovna, +coming up just then. "I sent to ask for news, and hear that she is a +little better. Oh, she is certainly the most charming woman in the +world," she went on, with a smile at her own enthusiasm. "We belong to +different camps, but that does not prevent my esteeming her as she +deserves. She is very unfortunate!" added Anna Pavlovna. + +Supposing that by these words Anna Pavlovna was somewhat lifting the +veil from the secret of the countess' malady, an unwary young man +ventured to express surprise that well known doctors had not been +called in and that the countess was being attended by a charlatan +who might employ dangerous remedies. + +"Your information maybe better than mine," Anna Pavlovna suddenly +and venomously retorted on the inexperienced young man, "but I know on +good authority that this doctor is a very learned and able man. He +is private physician to the Queen of Spain." + +And having thus demolished the young man, Anna Pavlovna turned to +another group where Bilibin was talking about the Austrians: having +wrinkled up his face he was evidently preparing to smooth it out again +and utter one of his mots. + +"I think it is delightful," he said, referring to a diplomatic +note that had been sent to Vienna with some Austrian banners +captured from the French by Wittgenstein, "the hero of Petropol" as he +was then called in Petersburg. + +"What? What's that?" asked Anna Pavlovna, securing silence for the +mot, which she had heard before. + +And Bilibin repeated the actual words of the diplomatic dispatch, +which he had himself composed. + +"The Emperor returns these Austrian banners," said Bilibin, +"friendly banners gone astray and found on a wrong path," and his brow +became smooth again. + +"Charming, charming!" observed Prince Vasili. + +"The path to Warsaw, perhaps," Prince Hippolyte remarked loudly +and unexpectedly. Everybody looked at him, understanding what he +meant. Prince Hippolyte himself glanced around with amused surprise. +He knew no more than the others what his words meant. During his +diplomatic career he had more than once noticed that such utterances +were received as very witty, and at every opportunity he uttered in +that way the first words that entered his head. "It may turn out +very well," he thought, "but if not, they'll know how to arrange +matters." And really, during the awkward silence that ensued, that +insufficiently patriotic person entered whom Anna Pavlovna had been +waiting for and wished to convert, and she, smiling and shaking a +finger at Hippolyte, invited Prince Vasili to the table and bringing +him two candles and the manuscript begged him to begin. Everyone +became silent. + + +"Most Gracious Sovereign and Emperor!" Prince Vasili sternly +declaimed, looking round at his audience as if to inquire whether +anyone had anything to say to the contrary. But no one said +anything. "Moscow, our ancient capital, the New Jerusalem, receives +her Christ"--he placed a sudden emphasis on the word her--"as a mother +receives her zealous sons into her arms, and through the gathering +mists, foreseeing the brilliant glory of thy rule, sings in +exultation, 'Hosanna, blessed is he that cometh!'" + + +Prince Vasili pronounced these last words in a tearful voice. + +Bilibin attentively examined his nails, and many of those present +appeared intimidated, as if asking in what they were to blame. Anna +Pavlovna whispered the next words in advance, like an old woman +muttering the prayer at Communion: "Let the bold and insolent +Goliath..." she whispered. + +Prince Vasili continued. + + +"Let the bold and insolent Goliath from the borders of France +encompass the realms of Russia with death-bearing terrors; humble +Faith, the sling of the Russian David, shall suddenly smite his head +in his blood-thirsty pride. This icon of the Venerable Sergius, the +servant of God and zealous champion of old of our country's weal, is +offered to Your Imperial Majesty. I grieve that my waning strength +prevents rejoicing in the sight of your most gracious presence. I +raise fervent prayers to Heaven that the Almighty may exalt the race +of the just, and mercifully fulfill the desires of Your Majesty." + + +"What force! What a style!" was uttered in approval both of reader +and of author. + +Animated by that address Anna Pavlovna's guests talked for a long +time of the state of the fatherland and offered various conjectures as +to the result of the battle to be fought in a few days. + +"You will see," said Anna Pavlovna, "that tomorrow, on the Emperor's +birthday, we shall receive news. I have a favorable presentiment!" + + + + + +CHAPTER II + + +Anna Pavlovna's presentiment was in fact fulfilled. Next day +during the service at the palace church in honor of the Emperor's +birthday, Prince Volkonski was called out of the church and received a +dispatch from Prince Kutuzov. It was Kutuzov's report, written from +Tatarinova on the day of the battle. Kutuzov wrote that the Russians +had not retreated a step, that the French losses were much heavier +than ours, and that he was writing in haste from the field of battle +before collecting full information. It followed that there must have +been a victory. And at once, without leaving the church, thanks were +rendered to the Creator for His help and for the victory. + +Anna Pavlovna's presentiment was justified, and all that morning a +joyously festive mood reigned in the city. Everyone believed the +victory to have been complete, and some even spoke of Napoleon's +having been captured, of his deposition, and of the choice of a new +ruler for France. + +It is very difficult for events to be reflected in their real +strength and completeness amid the conditions of court life and far +from the scene of action. General events involuntarily group +themselves around some particular incident. So now the courtiers' +pleasure was based as much on the fact that the news had arrived on +the Emperor's birthday as on the fact of the victory itself. It was +like a successfully arranged surprise. Mention was made in Kutuzov's +report of the Russian losses, among which figured the names of +Tuchkov, Bagration, and Kutaysov. In the Petersburg world this sad +side of the affair again involuntarily centered round a single +incident: Kutaysov's death. Everybody knew him, the Emperor liked him, +and he was young and interesting. That day everyone met with the +words: + +"What a wonderful coincidence! Just during the service. But what a +loss Kutaysov is! How sorry I am!" + +"What did I tell about Kutuzov?" Prince Vasili now said with a +prophet's pride. "I always said he was the only man capable of +defeating Napoleon." + +But next day no news arrived from the army and the public mood +grew anxious. The courtiers suffered because of the suffering the +suspense occasioned the Emperor. + +"Fancy the Emperor's position!" said they, and instead of +extolling Kutuzov as they had done the day before, they condemned +him as the cause of the Emperor's anxiety. That day Prince Vasili no +longer boasted of his protege Kutuzov, but remained silent when the +commander in chief was mentioned. Moreover, toward evening, as if +everything conspired to make Petersburg society anxious and uneasy, +a terrible piece of news was added. Countess Helene Bezukhova had +suddenly died of that terrible malady it had been so agreeable to +mention. Officially, at large gatherings, everyone said that +Countess Bezukhova had died of a terrible attack of angina pectoris, +but in intimate circles details were mentioned of how the private +physician of the Queen of Spain had prescribed small doses of a +certain drug to produce a certain effect; but Helene, tortured by +the fact that the old count suspected her and that her husband to whom +she had written (that wretched, profligate Pierre) had not replied, +had suddenly taken a very large dose of the drug, and had died in +agony before assistance could be rendered her. It was said that Prince +Vasili and the old count had turned upon the Italian, but the latter +had produced such letters from the unfortunate deceased that they +had immediately let the matter drop. + +Talk in general centered round three melancholy facts: the Emperor's +lack of news, the loss of Kutuzov, and the death of Helene. + +On the third day after Kutuzov's report a country gentleman +arrived from Moscow, and news of the surrender of Moscow to the French +spread through the whole town. This was terrible! What a position +for the Emperor to be in! Kutuzov was a traitor, and Prince Vasili +during the visits of condolence paid to him on the occasion of his +daughter's death said of Kutuzov, whom he had formerly praised (it was +excusable for him in his grief to forget what he had said), that it +was impossible to expect anything else from a blind and depraved old +man. + +"I only wonder that the fate of Russia could have been entrusted +to such a man." + +As long as this news remained unofficial it was possible to doubt +it, but the next day the following communication was received from +Count Rostopchin: + + +Prince Kutuzov's adjutant has brought me a letter in which he +demands police officers to guide the army to the Ryazan road. He +writes that he is regretfully abandoning Moscow. Sire! Kutuzov's +action decides the fate of the capital and of your empire! Russia will +shudder to learn of the abandonment of the city in which her greatness +is centered and in which lie the ashes of your ancestors! I shall +follow the army. I have had everything removed, and it only remains +for me to weep over the fate of my fatherland. + + +On receiving this dispatch the Emperor sent Prince Volkonski to +Kutuzov with the following rescript: + + +Prince Michael Ilarionovich! Since the twenty-ninth of August I have +received no communication from you, yet on the first of September I +received from the commander in chief of Moscow, via Yaroslavl, the sad +news that you, with the army, have decided to abandon Moscow. You +can yourself imagine the effect this news has had on me, and your +silence increases my astonishment. I am sending this by +Adjutant-General Prince Volkonski, to hear from you the situation of +the army and the reasons that have induced you to take this melancholy +decision. + + + + + +CHAPTER III + + +Nine days after the abandonment of Moscow, a messenger from +Kutuzov reached Petersburg with the official announcement of that +event. This messenger was Michaud, a Frenchman who did not know +Russian, but who was quoique etranger, russe de coeur et d'ame,* as he +said of himself. + + +*Though a foreigner, Russian in heart and soul. + + +The Emperor at once received this messenger in his study at the +palace on Stone Island. Michaud, who had never seen Moscow before +the campaign and who did not know Russian, yet felt deeply moved (as +he wrote) when he appeared before notre tres gracieux souverain* +with the news of the burning of Moscow, dont les flammes eclairaient +sa route.*[2] + + +*Our most gracious sovereign. + +*[2] Whose flames illumined his route. + + +Though the source of M. Michaud's chagrin must have been different +from that which caused Russians to grieve, he had such a sad face when +shown into the Emperor's study that the latter at once asked: + +"Have you brought me sad news, Colonel?" + +"Very sad, sire," replied Michaud, lowering his eyes with a sigh. +"The abandonment of Moscow." + +"Have they surrendered my ancient capital without a battle?" asked +the Emperor quickly, his face suddenly flushing. + +Michaud respectfully delivered the message Kutuzov had entrusted +to him, which was that it had been impossible to fight before +Moscow, and that as the only remaining choice was between losing the +army as well as Moscow, or losing Moscow alone, the field marshal +had to choose the latter. + +The Emperor listened in silence, not looking at Michaud. + +"Has the enemy entered the city?" he asked. + +"Yes, sire, and Moscow is now in ashes. I left it all in flames," +replied Michaud in a decided tone, but glancing at the Emperor he +was frightened by what he had done. + +The Emperor began to breathe heavily and rapidly, his lower lip +trembled, and tears instantly appeared in his fine blue eyes. + +But this lasted only a moment. He suddenly frowned, as if blaming +himself for his weakness, and raising his head addressed Michaud in +a firm voice: + +"I see, Colonel, from all that is happening, that Providence +requires great sacrifices of us... I am ready to submit myself in +all things to His will; but tell me, Michaud, how did you leave the +army when it saw my ancient capital abandoned without a battle? Did +you not notice discouragement?..." + +Seeing that his most gracious ruler was calm once more, Michaud also +grew calm, but was not immediately ready to reply to the Emperor's +direct and relevant question which required a direct answer. + +"Sire, will you allow me to speak frankly as befits a loyal +soldier?" he asked to gain time. + +"Colonel, I always require it," replied the Emperor. "Conceal +nothing from me, I wish to know absolutely how things are." + +"Sire!" said Michaud with a subtle, scarcely perceptible smile on +his lips, having now prepared a well-phrased reply, "sire, I left +the whole army, from its chiefs to the lowest soldier, without +exception in desperate and agonized terror..." + +"How is that?" the Emperor interrupted him, frowning sternly. "Would +misfortune make my Russians lose heart?... Never!" + +Michaud had only waited for this to bring out the phrase he had +prepared. + +"Sire," he said, with respectful playfulness, "they are only +afraid lest Your Majesty, in the goodness of your heart, should +allow yourself to be persuaded to make peace. They are burning for the +combat," declared this representative of the Russian nation, "and to +prove to Your Majesty by the sacrifice of their lives how devoted they +are...." + +"Ah!" said the Emperor reassured, and with a kindly gleam in his +eyes, he patted Michaud on the shoulder. "You set me at ease, +Colonel." + +He bent his head and was silent for some time. + +"Well, then, go back to the army," he said, drawing himself up to +his full height and addressing Michaud with a gracious and majestic +gesture, "and tell our brave men and all my good subjects wherever you +go that when I have not a soldier left I shall put myself at the +head of my beloved nobility and my good peasants and so use the last +resources of my empire. It still offers me more than my enemies +suppose," said the Emperor growing more and more animated; "but should +it ever be ordained by Divine Providence," he continued, raising to +heaven his fine eyes shining with emotion, "that my dynasty should +cease to reign on the throne of my ancestors, then after exhausting +all the means at my command, I shall let my beard grow to here" (he +pointed halfway down his chest) "and go and eat potatoes with the +meanest of my peasants, rather than sign the disgrace of my country +and of my beloved people whose sacrifices I know how to appreciate." + +Having uttered these words in an agitated voice the Emperor suddenly +turned away as if to hide from Michaud the tears that rose to his +eyes, and went to the further end of his study. Having stood there a +few moments, he strode back to Michaud and pressed his arm below the +elbow with a vigorous movement. The Emperor's mild and handsome face +was flushed and his eyes gleamed with resolution and anger. + +"Colonel Michaud, do not forget what I say to you here, perhaps we +may recall it with pleasure someday... Napoleon or I," said the +Emperor, touching his breast. "We can no longer both reign together. I +have learned to know him, and he will not deceive me any more...." + +And the Emperor paused, with a frown. + +When he heard these words and saw the expression of firm +resolution in the Emperor's eyes, Michaud--quoique etranger, russe +de coeur et d'ame--at that solemn moment felt himself enraptured by +all that he had heard (as he used afterwards to say), and gave +expression to his own feelings and those of the Russian people whose +representative he considered himself to be, in the following words: + +"Sire!" said he, "Your Majesty is at this moment signing the glory +of the nation and the salvation of Europe!" + +With an inclination of the head the Emperor dismissed him. + + + + + +CHAPTER IV + + +It is natural for us who were not living in those days to imagine +that when half Russia had been conquered and the inhabitants were +fleeing to distant provinces, and one levy after another was being +raised for the defense of the fatherland, all Russians from the +greatest to the least were solely engaged in sacrificing themselves, +saving their fatherland, or weeping over its downfall. The tales and +descriptions of that time without exception speak only of the +self-sacrifice, patriotic devotion, despair, grief, and the heroism of +the Russians. But it was not really so. It appears so to us because we +see only the general historic interest of that time and do not see all +the personal human interests that people had. Yet in reality those +personal interests of the moment so much transcend the general +interests that they always prevent the public interest from being felt +or even noticed. Most of the people at that time paid no attention +to the general progress of events but were guided only by their +private interests, and they were the very people whose activities at +that period were most useful. + +Those who tried to understand the general course of events and to +take part in it by self-sacrifice and heroism were the most useless +members of society, they saw everything upside down, and all they +did for the common good turned out to be useless and foolish--like +Pierre's and Mamonov's regiments which looted Russian villages, and +the lint the young ladies prepared and that never reached the wounded, +and so on. Even those, fond of intellectual talk and of expressing +their feelings, who discussed Russia's position at the time +involuntarily introduced into their conversation either a shade of +pretense and falsehood or useless condemnation and anger directed +against people accused of actions no one could possibly be guilty +of. In historic events the rule forbidding us to eat of the fruit of +the Tree of Knowledge is specially applicable. Only unconscious action +bears fruit, and he who plays a part in an historic event never +understands its significance. If he tries to realize it his efforts +are fruitless. + +The more closely a man was engaged in the events then taking place +in Russia the less did he realize their significance. In Petersburg +and in the provinces at a distance from Moscow, ladies, and +gentlemen in militia uniforms, wept for Russia and its ancient capital +and talked of self-sacrifice and so on; but in the army which +retired beyond Moscow there was little talk or thought of Moscow, +and when they caught sight of its burned ruins no one swore to be +avenged on the French, but they thought about their next pay, their +next quarters, of Matreshka the vivandiere, and like matters. + +As the war had caught him in the service, Nicholas Rostov took a +close and prolonged part in the defense of his country, but did so +casually, without any aim at self-sacrifice, and he therefore looked +at what was going on in Russia without despair and without dismally +racking his brains over it. Had he been asked what he thought of the +state of Russia, he would have said that it was not his business to +think about it, that Kutuzov and others were there for that purpose, +but that he had heard that the regiments were to be made up to their +full strength, that fighting would probably go on for a long time yet, +and that things being so it was quite likely he might be in command of +a regiment in a couple of years' time. + +As he looked at the matter in this way, he learned that he was being +sent to Voronezh to buy remounts for his division, not only without +regret at being prevented from taking part in the coming battle, but +with the greatest pleasure--which he did not conceal and which his +comrades fully understood. + +A few days before the battle of Borodino, Nicholas received the +necessary money and warrants, and having sent some hussars on in +advance, he set out with post horses for Voronezh. + +Only a man who has experienced it--that is, has passed some months +continuously in an atmosphere of campaigning and war--can understand +the delight Nicholas felt when he escaped from the region covered by +the army's foraging operations, provision trains, and hospitals. When- +free from soldiers, wagons, and the filthy traces of a camp--he saw +villages with peasants and peasant women, gentlemen's country +houses, fields where cattle were grazing, posthouses with +stationmasters asleep in them, he rejoiced as though seeing all this +for the first time. What for a long while specially surprised and +delighted him were the women, young and healthy, without a dozen +officers making up to each of them; women, too, who were pleased and +flattered that a passing officer should joke with them. + +In the highest spirits Nicholas arrived at night at a hotel in +Voronezh, ordered things he had long been deprived of in camp, and +next day, very clean-shaven and in a full-dress uniform he had not +worn for a long time, went to present himself to the authorities. + +The commander of the militia was a civilian general, an old man +who was evidently pleased with his military designation and rank. He +received Nicholas brusquely (imagining this to be characteristically +military) and questioned him with an important air, as if +considering the general progress of affairs and approving and +disapproving with full right to do so. Nicholas was in such good +spirits that this merely amused him. + +From the commander of the militia he drove to the governor. The +governor was a brisk little man, very simple and affable. He indicated +the stud farms at which Nicholas might procure horses, recommended +to him a horse dealer in the town and a landowner fourteen miles out +of town who had the best horses, and promised to assist him in every +way. + +"You are Count Ilya Rostov's son? My wife was a great friend of your +mother's. We are at home on Thursdays--today is Thursday, so please +come and see us quite informally," said the governor, taking leave +of him. + +Immediately on leaving the governor's, Nicholas hired post horses +and, taking his squadron quartermaster with him, drove at a gallop +to the landowner, fourteen miles away, who had the stud. Everything +seemed to him pleasant and easy during that first part of his stay +in Voronezh and, as usually happens when a man is in a pleasant +state of mind, everything went well and easily. + +The landowner to whom Nicholas went was a bachelor, an old +cavalryman, a horse fancier, a sportsman, the possessor of some +century-old brandy and some old Hungarian wine, who had a snuggery +where he smoked, and who owned some splendid horses. + +In very few words Nicholas bought seventeen picked stallions for six +thousand rubles--to serve, as he said, as samples of his remounts. +After dining and taking rather too much of the Hungarian wine, +Nicholas--having exchanged kisses with the landowner, with whom he was +already on the friendliest terms--galloped back over abominable roads, +in the brightest frame of mind, continually urging on the driver so as +to be in time for the governor's party. + +When he had changed, poured water over his head, and scented +himself, Nicholas arrived at the governor's rather late, but with +the phrase "better late than never" on his lips. + +It was not a ball, nor had dancing been announced, but everyone knew +that Catherine Petrovna would play valses and the ecossaise on the +clavichord and that there would be dancing, and so everyone had come +as to a ball. + +Provincial life in 1812 went on very much as usual, but with this +difference, that it was livelier in the towns in consequence of the +arrival of many wealthy families from Moscow, and as in everything +that went on in Russia at that time a special recklessness was +noticeable, an "in for a penny, in for a pound--who cares?" spirit, +and the inevitable small talk, instead of turning on the weather and +mutual acquaintances, now turned on Moscow, the army, and Napoleon. + +The society gathered together at the governor's was the best in +Voronezh. + +There were a great many ladies and some of Nicholas' Moscow +acquaintances, but there were no men who could at all vie with the +cavalier of St. George, the hussar remount officer, the good-natured +and well-bred Count Rostov. Among the men was an Italian prisoner, +an officer of the French army; and Nicholas felt that the presence +of that prisoner enhanced his own importance as a Russian hero. The +Italian was, as it were, a war trophy. Nicholas felt this, it seemed +to him that everyone regarded the Italian in the same light, and he +treated him cordially though with dignity and restraint. + +As soon as Nicholas entered in his hussar uniform, diffusing +around him a fragrance of perfume and wine, and had uttered the +words "better late than never" and heard them repeated several times +by others, people clustered around him; all eyes turned on him, and he +felt at once that he had entered into his proper position in the +province--that of a universal favorite: a very pleasant position, +and intoxicatingly so after his long privations. At posting +stations, at inns, and in the landowner's snuggery, maidservants had +been flattered by his notice, and here too at the governor's party +there were (as it seemed to Nicholas) an inexhaustible number of +pretty young women, married and unmarried, impatiently awaiting his +notice. The women and girls flirted with him and, from the first +day, the people concerned themselves to get this fine young +daredevil of an hussar married and settled down. Among these was the +governor's wife herself, who welcomed Rostov as a near relative and +called him "Nicholas." + +Catherine Petrovna did actually play valses and the ecossaise, and +dancing began in which Nicholas still further captivated the +provincial society by his agility. His particularly free manner of +dancing even surprised them all. Nicholas was himself rather surprised +at the way he danced that evening. He had never danced like that in +Moscow and would even have considered such a very free and easy manner +improper and in bad form, but here he felt it incumbent on him to +astonish them all by something unusual, something they would have to +accept as the regular thing in the capital though new to them in the +provinces. + +All the evening Nicholas paid attention to a blue-eyed, plump and +pleasing little blonde, the wife of one of the provincial officials. +With the naive conviction of young men in a merry mood that other +men's wives were created for them, Rostov did not leave the lady's +side and treated her husband in a friendly and conspiratorial style, +as if, without speaking of it, they knew how capitally Nicholas and +the lady would get on together. The husband, however, did not seem +to share that conviction and tried to behave morosely with Rostov. But +the latter's good-natured naivete was so boundless that sometimes even +he involuntarily yielded to Nicholas' good humor. Toward the end of +the evening, however, as the wife's face grew more flushed and +animated, the husband's became more and more melancholy and solemn, as +though there were but a given amount of animation between them and +as the wife's share increased the husband's diminished. + + + + + +CHAPTER V + + +Nicholas sat leaning slightly forward in an armchair, bending +closely over the blonde lady and paying her mythological compliments +with a smile that never left his face. Jauntily shifting the +position of his legs in their tight riding breeches, diffusing an odor +of perfume, and admiring his partner, himself, and the fine outlines +of his legs in their well-fitting Hessian boots, Nicholas told the +blonde lady that he wished to run away with a certain lady here in +Voronezh. + +"Which lady?" + +"A charming lady, a divine one. Her eyes" (Nicholas looked at his +partner) "are blue, her mouth coral and ivory; her figure" (he glanced +at her shoulders) "like Diana's...." + +The husband came up and sullenly asked his wife what she was talking +about. + +"Ah, Nikita Ivanych!" cried Nicholas, rising politely, and as if +wishing Nikita Ivanych to share his joke, he began to tell him of +his intention to elope with a blonde lady. + +The husband smiled gloomily, the wife gaily. The governor's +good-natured wife came up with a look of disapproval. + +"Anna Ignatyevna wants to see you, Nicholas," said she, +pronouncing the name so that Nicholas at once understood that Anna +Ignatyevna was a very important person. "Come, Nicholas! You know +you let me call you so?" + +"Oh, yes, Aunt. Who is she?" + +"Anna Ignatyevna Malvintseva. She has heard from her niece how you +rescued her... Can you guess?" + +"I rescued such a lot of them!" said Nicholas. + +"Her niece, Princess Bolkonskaya. She is here in Voronezh with her +aunt. Oho! How you blush. Why, are...?" + +"Not a bit! Please don't, Aunt!" + +"Very well, very well!... Oh, what a fellow you are!" + +The governor's wife led him up to a tall and very stout old lady +with a blue headdress, who had just finished her game of cards with +the most important personages of the town. This was Malvintseva, +Princess Mary's aunt on her mother's side, a rich, childless widow who +always lived in Voronezh. When Rostov approached her she was +standing settling up for the game. She looked at him and, screwing +up her eyes sternly, continued to upbraid the general who had won from +her. + +"Very pleased, mon cher," she then said, holding out her hand to +Nicholas. "Pray come and see me." + +After a few words about Princess Mary and her late father, whom +Malvintseva had evidently not liked, and having asked what Nicholas +knew of Prince Andrew, who also was evidently no favorite of hers, the +important old lady dismissed Nicholas after repeating her invitation +to come to see her. + +Nicholas promised to come and blushed again as he bowed. At the +mention of Princess Mary he experienced a feeling of shyness and +even of fear, which he himself did not understand. + +When he had parted from Malvintseva Nicholas wished to return to the +dancing, but the governor's little wife placed her plump hand on his +sleeve and, saying that she wanted to have a talk with him, led him to +her sitting room, from which those who were there immediately withdrew +so as not to be in her way. + +"Do you know, dear boy," began the governor's wife with a serious +expression on her kind little face, "that really would be the match +for you: would you like me to arrange it?" + +"Whom do you mean, Aunt?" asked Nicholas. + +"I will make a match for you with the princess. Catherine Petrovna +speaks of Lily, but I say, no--the princess! Do you want me to do +it? I am sure your mother will be grateful to me. What a charming girl +she is, really! And she is not at all so plain, either." + +"Not at all," replied Nicholas as if offended at the idea. "As +befits a soldier, Aunt, I don't force myself on anyone or refuse +anything," he said before he had time to consider what he was saying. + +"Well then, remember, this is not a joke!" + +"Of course not!" + +"Yes, yes," the governor's wife said as if talking to herself. "But, +my dear boy, among other things you are too attentive to the other, +the blonde. One is sorry for the husband, really...." + +"Oh no, we are good friends with him," said Nicholas in the +simplicity of his heart; it did not enter his head that a pastime so +pleasant to himself might not be pleasant to someone else. + +"But what nonsense I have been saying to the governor's wife!" +thought Nicholas suddenly at supper. "She will really begin to arrange +a match... and Soyna...?" And on taking leave of the governor's +wife, when she again smilingly said to him, "Well then, remember!" +he drew her aside. + +"But see here, to tell the truth, Aunt..." + +"What is it, my dear? Come, let's sit down here," said she. + +Nicholas suddenly felt a desire and need to tell his most intimate +thoughts (which he would not have told to his mother, his sister, or +his friend) to this woman who was almost a stranger. When he +afterwards recalled that impulse to unsolicited and inexplicable +frankness which had very important results for him, it seemed to +him--as it seems to everyone in such cases--that it was merely some +silly whim that seized him: yet that burst of frankness, together with +other trifling events, had immense consequences for him and for all +his family. + +"You see, Aunt, Mamma has long wanted me to marry an heiress, but +the very idea of marrying for money is repugnant to me." + +"Oh yes, I understand," said the governor's wife. + +"But Princess Bolkonskaya--that's another matter. I will tell you +the truth. In the first place I like her very much, I feel drawn to +her; and then, after I met her under such circumstances--so strangely, +the idea often occurred to me: 'This is fate.' Especially if you +remember that Mamma had long been thinking of it; but I had never +happened to meet her before, somehow it had always happened that we +did not meet. And as long as my sister Natasha was engaged to her +brother it was of course out of the question for me to think of +marrying her. And it must needs happen that I should meet her just +when Natasha's engagement had been broken off... and then +everything... So you see... I never told this to anyone and never +will, only to you." + +The governor's wife pressed his elbow gratefully. + +"You know Sonya, my cousin? I love her, and promised to marry her, +and will do so.... So you see there can be no question about-" said +Nicholas incoherently and blushing. + +"My dear boy, what a way to look at it! You know Sonya has nothing +and you yourself say your Papa's affairs are in a very bad way. And +what about your mother? It would kill her, that's one thing. And +what sort of life would it be for Sonya--if she's a girl with a heart? +Your mother in despair, and you all ruined.... No, my dear, you and +Sonya ought to understand that." + +Nicholas remained silent. It comforted him to hear these arguments. + +"All the same, Aunt, it is impossible," he rejoined with a sigh, +after a short pause. "Besides, would the princess have me? And +besides, she is now in mourning. How can one think of it!" + +"But you don't suppose I'm going to get you married at once? There +is always a right way of doing things," replied the governor's wife. + +"What a matchmaker you are, Aunt..." said Nicholas, kissing her +plump little hand. + + + + + +CHAPTER VI + + +On reaching Moscow after her meeting with Rostov, Princess Mary +had found her nephew there with his tutor, and a letter from Prince +Andrew giving her instructions how to get to her Aunt Malvintseva at +Voronezh. That feeling akin to temptation which had tormented her +during her father's illness, since his death, and especially since her +meeting with Rostov was smothered by arrangements for the journey, +anxiety about her brother, settling in a new house, meeting new +people, and attending to her nephew's education. She was sad. Now, +after a month passed in quiet surroundings, she felt more and more +deeply the loss of her father which was associated in her mind with +the ruin of Russia. She was agitated and incessantly tortured by the +thought of the dangers to which her brother, the only intimate +person now remaining to her, was exposed. She was worried too about +her nephew's education for which she had always felt herself +incompetent, but in the depths of her soul she felt at peace--a +peace arising from consciousness of having stifled those personal +dreams and hopes that had been on the point of awakening within her +and were related to her meeting with Rostov. + +The day after her party the governor's wife came to see +Malvintseva and, after discussing her plan with the aunt, remarked +that though under present circumstances a formal betrothal was, of +course, not to be thought of, all the same the young people might be +brought together and could get to know one another. Malvintseva +expressed approval, and the governor's wife began to speak of Rostov +in Mary's presence, praising him and telling how he had blushed when +Princess Mary's name was mentioned. But Princess Mary experienced a +painful rather than a joyful feeling--her mental tranquillity was +destroyed, and desires, doubts, self-reproach, and hopes reawoke. + +During the two days that elapsed before Rostov called, Princess Mary +continually thought of how she ought to behave to him. First she +decided not to come to the drawing room when he called to see her +aunt--that it would not be proper for her, in her deep mourning, to +receive visitors; then she thought this would be rude after what he +had done for her; then it occurred to her that her aunt and the +governor's wife had intentions concerning herself and Rostov--their +looks and words at times seemed to confirm this supposition--then +she told herself that only she, with her sinful nature, could think +this of them: they could not forget that situated as she was, while +still wearing deep mourning, such matchmaking would be an insult to +her and to her father's memory. Assuming that she did go down to see +him, Princess Mary imagined the words he would say to her and what she +would say to him, and these words sometimes seemed undeservedly cold +and then to mean too much. More than anything she feared lest the +confusion she felt might overwhelm her and betray her as soon as she +saw him. + +But when on Sunday after church the footman announced in the drawing +room that Count Rostov had called, the princess showed no confusion, +only a slight blush suffused her cheeks and her eyes lit up with a new +and radiant light. + +"You have met him, Aunt?" said she in a calm voice, unable herself +to understand that she could be outwardly so calm and natural. + +When Rostov entered the room, the princess dropped her eyes for an +instant, as if to give the visitor time to greet her aunt, and then +just as Nicholas turned to her she raised her head and met his look +with shining eyes. With a movement full of dignity and grace she +half rose with a smile of pleasure, held out her slender, delicate +hand to him, and began to speak in a voice in which for the first time +new deep womanly notes vibrated. Mademoiselle Bourienne, who was in +the drawing room, looked at Princess Mary in bewildered surprise. +Herself a consummate coquette, she could not have maneuvered better on +meeting a man she wished to attract. + +"Either black is particularly becoming to her or she really has +greatly improved without my having noticed it. And above all, what +tact and grace!" thought Mademoiselle Bourienne. + +Had Princess Mary been capable of reflection at that moment, she +would have been more surprised than Mademoiselle Bourienne at the +change that had taken place in herself. From the moment she recognized +that dear, loved face, a new life force took possession of her and +compelled her to speak and act apart from her own will. From the +time Rostov entered, her face became suddenly transformed. It was as +if a light had been kindled in a carved and painted lantern and the +intricate, skillful, artistic work on its sides, that previously +seemed dark, coarse, and meaningless, was suddenly shown up in +unexpected and striking beauty. For the first time all that pure, +spiritual, inward travail through which she had lived appeared on +the surface. All her inward labor, her dissatisfaction with herself, +her sufferings, her strivings after goodness, her meekness, love, +and self-sacrifice--all this now shone in those radiant eyes, in her +delicate smile, and in every trait of her gentle face. + +Rostov saw all this as clearly as if he had known her whole life. He +felt that the being before him was quite different from, and better +than, anyone he had met before, and above all better than himself. + +Their conversation was very simple and unimportant. They spoke of +the war, and like everyone else unconsciously exaggerated their sorrow +about it; they spoke of their last meeting--Nicholas trying to +change the subject--they talked of the governor's kind wife, of +Nicholas' relations, and of Princess Mary's. + +She did not talk about her brother, diverting the conversation as +soon as her aunt mentioned Andrew. Evidently she could speak of +Russia's misfortunes with a certain artificiality, but her brother was +too near her heart and she neither could nor would speak lightly of +him. Nicholas noticed this, as he noticed every shade of Princess +Mary's character with an observation unusual to him, and everything +confirmed his conviction that she was a quite unusual and +extraordinary being. Nicholas blushed and was confused when people +spoke to him about the princess (as she did when he was mentioned) and +even when he thought of her, but in her presence he felt quite at +ease, and said not at all what he had prepared, but what, quite +appropriately, occurred to him at the moment. + +When a pause occurred during his short visit, Nicholas, as is +usual when there are children, turned to Prince Andrew's little son, +caressing him and asking whether he would like to be an hussar. He +took the boy on his knee, played with him, and looked round at +Princess Mary. With a softened, happy, timid look she watched the +boy she loved in the arms of the man she loved. Nicholas also +noticed that look and, as if understanding it, flushed with pleasure +and began to kiss the boy with good natured playfulness. + +As she was in mourning Princess Mary did not go out into society, +and Nicholas did not think it the proper thing to visit her again; but +all the same the governor's wife went on with her matchmaking, passing +on to Nicholas the flattering things Princess Mary said of him and +vice versa, and insisting on his declaring himself to Princess Mary. +For this purpose she arranged a meeting between the young people at +the bishop's house before Mass. + +Though Rostov told the governeor's wife that he would not make any +declaration to Princess Mary, he promised to go. + +As at Tilsit Rostov had not allowed himself to doubt that what +everybody considered right was right, so now, after a short but +sincere struggle between his effort to arrange his life by his own +sense of justice, and in obedient submission to circumstances, he +chose the latter and yielded to the power he felt irresistibly +carrying him he knew not where. He knew that after his promise to +Sonya it would be what he deemed base to declare his feelings to +Princess Mary. And he knew that he would never act basely. But he also +knew (or rather felt at the bottom of his heart) that by resigning +himself now to the force of circumstances and to those who were +guiding him, he was not only doing nothing wrong, but was doing +something very important--more important than anything he had ever +done in his life. + +After meeting Princess Mary, though the course of his life went on +externally as before, all his former amusements lost their charm for +him and he often thought about her. But he never thought about her +as he had thought of all the young ladies without exception whom he +had met in society, nor as he had for a long time, and at one time +rapturously, thought about Sonya. He had pictured each of those +young ladies as almost all honest-hearted young men do, that is, as +a possible wife, adapting her in his imagination to all the conditions +of married life: a white dressing gown, his wife at the tea table, his +wife's carriage, little ones, Mamma and Papa, their relations to +her, and so on--and these pictures of the future had given him +pleasure. But with Princess Mary, to whom they were trying to get +him engaged, he could never picture anything of future married life. +If he tried, his pictures seemed incongruous and false. It made him +afraid. + + + + + +CHAPTER VII + + +The dreadful news of the battle of Borodino, of our losses in killed +and wounded, and the still more terrible news of the loss of Moscow +reached Voronezh in the middle of September. Princess Mary, having +learned of her brother's wound only from the Gazette and having no +definite news of him, prepared (so Nicholas heard, he had not seen her +again himself) to set off in search of Prince Andrew. + +When he received the news of the battle of Borodino and the +abandonment of Moscow, Rostov was not seized with despair, anger, +the desire for vengeance, or any feeling of that kind, but +everything in Voronezh suddenly seemed to him dull and tiresome, and +he experienced an indefinite feeling of shame and awkwardness. The +conversations he heard seemed to him insincere; he did not know how to +judge all these affairs and felt that only in the regiment would +everything again become clear to him. He made haste to finish buying +the horses, and often became unreasonably angry with his servant and +squadron quartermaster. + +A few days before his departure a special thanksgiving, at which +Nicholas was present, was held in the cathedral for the Russian +victory. He stood a little behind the governor and held himself with +military decorum through the service, meditating on a great variety of +subjects. When the service was over the governor's wife beckoned him +to her. + +"Have you seen the princess?" she asked, indicating with a +movement of her head a lady standing on the opposite side, beyond +the choir. + +Nicholas immediately recognized Princess Mary not so much by the +profile he saw under her bonnet as by the feeling of solicitude, +timidity, and pity that immediately overcame him. Princess Mary, +evidently engrossed by her thoughts, was crossing herself for the last +time before leaving the church. + +Nicholas looked at her face with surprise. It was the same face he +had seen before, there was the same general expression of refined, +inner, spiritual labor, but now it was quite differently lit up. There +was a pathetic expression of sorrow, prayer, and hope in it. As had +occurred before when she was present, Nicholas went up to her +without waiting to be prompted by the governor's wife and not asking +himself whether or not it was right and proper to address her here +in church, and told her he had heard of her trouble and sympathized +with his whole soul. As soon as she heard his voice a vivid glow +kindled in her face, lighting up both her sorrow and her joy. + +"There is one thing I wanted to tell you, Princess," said Rostov. +"It is that if your brother, Prince Andrew Nikolievich, were not +living, it would have been at once announced in the Gazette, as he +is a colonel." + +The princess looked at him, not grasping what he was saying, but +cheered by the expression of regretful sympathy on his face. + +"And I have known so many cases of a splinter wound" (the Gazette +said it was a shell) "either proving fatal at once or being very +slight," continued Nicholas. "We must hope for the best, and I am +sure..." + +Princess Mary interrupted him. + +"Oh, that would be so dread..." she began and, prevented by +agitation from finishing, she bent her head with a movement as +graceful as everything she did in his presence and, looking up at +him gratefully, went out, following her aunt. + +That evening Nicholas did not go out, but stayed at home to settle +some accounts with the horse dealers. When he had finished that +business it was already too late to go anywhere but still too early to +go to bed, and for a long time he paced up and down the room, +reflecting on his life, a thing he rarely did. + +Princess Mary had made an agreeable impression on him when he had +met her in Smolensk province. His having encountered her in such +exceptional circumstances, and his mother having at one time mentioned +her to him as a good match, had drawn his particular attention to her. +When he met her again in Voronezh the impression she made on him was +not merely pleasing but powerful. Nicholas had been struck by the +peculiar moral beauty he observed in her at this time. He was, +however, preparing to go away and it had not entered his head to +regret that he was thus depriving himself of chances of meeting her. +But that day's encounter in church had, he felt, sunk deeper than +was desirable for his peace of mind. That pale, sad, refined face, +that radiant look, those gentle graceful gestures, and especially +the deep and tender sorrow expressed in all her features agitated +him and evoked his sympathy. In men Rostov could not bear to see the +expression of a higher spiritual life (that was why he did not like +Prince Andrew) and he referred to it contemptuously as philosophy +and dreaminess, but in Princess Mary that very sorrow which revealed +the depth of a whole spiritual world foreign to him was an +irresistible attraction. + +"She must be a wonderful woman. A real angel!" he said to himself. +"Why am I not free? Why was I in such a hurry with Sonya?" And he +involuntarily compared the two: the lack of spirituality in the one +and the abundance of it in the other--a spirituality he himself lacked +and therefore valued most highly. He tried to picture what would +happen were he free. How he would propose to her and how she would +become his wife. But no, he could not imagine that. He felt awed, +and no clear picture presented itself to his mind. He had long ago +pictured to himself a future with Sonya, and that was all clear and +simple just because it had all been thought out and he knew all +there was in Sonya, but it was impossible to picture a future with +Princess Mary, because he did not understand her but simply loved her. + +Reveries about Sonya had had something merry and playful in them, +but to dream of Princess Mary was always difficult and a little +frightening. + +"How she prayed!" he thought. "It was plain that her whole soul +was in her prayer. Yes, that was the prayer that moves mountains, +and I am sure her prayer will be answered. Why don't I pray for what I +want?" he suddenly thought. "What do I want? To be free, released from +Sonya... She was right," he thought, remembering what the governor's +wife had said: "Nothing but misfortune can come of marrying Sonya. +Muddles, grief for Mamma... business difficulties... muddles, terrible +muddles! Besides, I don't love her--not as I should. O, God! release +me from this dreadful, inextricable position!" he suddenly began to +pray. "Yes, prayer can move mountains, but one must have faith and not +pray as Natasha and I used to as children, that the snow might turn +into sugar--and then run out into the yard to see whether it had +done so. No, but I am not praying for trifles now," he thought as he +put his pipe down in a corner, and folding his hands placed himself +before the icon. Softened by memories of Princess Mary he began to +pray as he had not done for a long time. Tears were in his eyes and in +his throat when the door opened and Lavrushka came in with some +papers. + +"Blockhead! Why do you come in without being called?" cried +Nicholas, quickly changing his attitude. + +"From the governor," said Lavrushka in a sleepy voice. "A courier +has arrived and there's a letter for you." + +"Well, all right, thanks. You can go!" + +Nicholas took the two letters, one of which was from his mother +and the other from Sonya. He recognized them by the handwriting and +opened Sonya's first. He had read only a few lines when he turned pale +and his eyes opened wide with fear and joy. + +"No, it's not possible!" he cried aloud. + +Unable to sit still he paced up and down the room holding the letter +and reading it. He glanced through it, then read it again, and then +again, and standing still in the middle of the room he raised his +shoulders, stretching out his hands, with his mouth wide open and +his eyes fixed. What he had just been praying for with confidence that +God would hear him had come to pass; but Nicholas was as much +astonished as if it were something extraordinary and unexpected, and +as if the very fact that it had happened so quickly proved that it had +not come from God to whom he had prayed, but by some ordinary +coincidence. + +This unexpected and, as it seemed to Nicholas, quite voluntary +letter from Sonya freed him from the knot that fettered him and from +which there had seemed no escape. She wrote that the last +unfortunate events--the loss of almost the whole of the Rostovs' +Moscow property--and the countess' repeatedly expressed wish that +Nicholas should marry Princess Bolkonskaya, together with his +silence and coldness of late, had all combined to make her decide to +release him from his promise and set him completely free. + + +It would be too painful to me to think that I might be a cause of +sorrow or discord in the family that has been so good to me (she +wrote), and my love has no aim but the happiness of those I love; +so, Nicholas, I beg you to consider yourself free, and to be assured +that, in spite of everything, no one can love you more than does + +Your Sonya + + +Both letters were written from Troitsa. The other, from the +countess, described their last days in Moscow, their departure, the +fire, and the destruction of all their property. In this letter the +countess also mentioned that Prince Andrew was among the wounded +traveling with them; his state was very critical, but the doctor +said there was now more hope. Sonya and Natasha were nursing him. + +Next day Nicholas took his mother's letter and went to see +Princess Mary. Neither he nor she said a word about what "Natasha +nursing him" might mean, but thanks to this letter Nicholas suddenly +became almost as intimate with the princess as if they were relations. + +The following day he saw Princess Mary off on her journey to +Yaroslavl, and a few days later left to rejoin his regiment. + + + + + +CHAPTER VIII + + +Sonya's letter written from Troitsa, which had come as an answer +to Nicholas' prayer, was prompted by this: the thought of getting +Nicholas married to an heiress occupied the old countess' mind more +and more. She knew that Sonya was the chief obstacle to this +happening, and Sonya's life in the countess' house had grown harder +and harder, especially after they had received a letter from +Nicholas telling of his meeting with Princess Mary in Bogucharovo. The +countess let no occasion slip of making humiliating or cruel allusions +to Sonya. + +But a few days before they left Moscow, moved and excited by all +that was going on, she called Sonya to her and, instead of reproaching +and making demands on her, tearfully implored her to sacrifice herself +and repay all that the family had done for her by breaking off her +engagement with Nicholas. + +"I shall not be at peace till you promise me this." + +Sonya burst into hysterical tears and replied through her sobs +that she would do anything and was prepared for anything, but gave +no actual promise and could not bring herself to decide to do what was +demanded of her. She must sacrifice herself for the family that had +reared and brought her up. To sacrifice herself for others was Sonya's +habit. Her position in the house was such that only by sacrifice could +she show her worth, and she was accustomed to this and loved doing it. +But in all her former acts of self-sacrifice she had been happily +conscious that they raised her in her own esteem and in that of +others, and so made her more worthy of Nicholas whom she loved more +than anything in the world. But now they wanted her to sacrifice the +very thing that constituted the whole reward for her self-sacrifice +and the whole meaning of her life. And for the first time she felt +bitterness against those who had been her benefactors only to +torture her the more painfully; she felt jealous of Natasha who had +never experienced anything of this sort, had never needed to sacrifice +herself, but made others sacrifice themselves for her and yet was +beloved by everybody. And for the first time Sonya felt that out of +her pure, quiet love for Nicholas a passionate feeling was beginning +to grow up which was stronger than principle, virtue, or religion. +Under the influence of this feeling Sonya, whose life of dependence +had taught her involuntarily to be secretive, having answered the +countess in vague general terms, avoided talking with her and resolved +to wait till she should see Nicholas, not in order to set him free but +on the contrary at that meeting to bind him to her forever. + +The bustle and terror of the Rostovs' last days in Moscow stifled +the gloomy thoughts that oppressed Sonya. She was glad to find +escape from them in practical activity. But when she heard of Prince +Andrew's presence in their house, despite her sincere pity for him and +for Natasha, she was seized by a joyful and superstitious feeling that +God did not intend her to be separated from Nicholas. She knew that +Natasha loved no one but Prince Andrew and had never ceased to love +him. She knew that being thrown together again under such terrible +circumstances they would again fall in love with one another, and that +Nicholas would then not be able to marry Princess Mary as they would +be within the prohibited degrees of affinity. Despite all the terror +of what had happened during those last days and during the first +days of their journey, this feeling that Providence was intervening in +her personal affairs cheered Sonya. + +At the Troitsa monastery the Rostovs first broke their journey for a +whole day. + +Three large rooms were assigned to them in the monastery hostelry, +one of which was occupied by Prince Andrew. The wounded man was much +better that day and Natasha was sitting with him. In the next room sat +the count and countess respectfully conversing with the prior, who was +calling on them as old acquaintances and benefactors of the monastery. +Sonya was there too, tormented by curiosity as to what Prince Andrew +and Natasha were talking about. She heard the sound of their voices +through the door. That door opened and Natasha came out, looking +excited. Not noticing the monk, who had risen to greet her and was +drawing back the wide sleeve on his right arm, she went up to Sonya +and took her hand. + +"Natasha, what are you about? Come here!" said the countess. + +Natasha went up to the monk for his blessing, and advised her to +pray for aid to God and His saint. + +As soon as the prior withdrew, Natasha took her friend by the hand +and went with her into the unoccupied room. + +"Sonya, will he live?" she asked. "Sonya, how happy I am, and how +unhappy!... Sonya, dovey, everything is as it used to be. If only he +lives! He cannot... because... because... of" and Natasha burst into +tears. + +"Yes! I knew it! Thank God!" murmured Sonya. "He will live." + +Sonya was not less agitated than her friend by the latter's fear and +grief and by her own personal feelings which she shared with no one. +Sobbing, she kissed and comforted Natasha. "If only he lives!" she +thought. Having wept, talked, and wiped away their tears, the two +friends went together to Prince Andrew's door. Natasha opened it +cautiously and glanced into the room, Sonya standing beside her at the +half-open door. + +Prince Andrew was lying raised high on three pillows. His pale +face was calm, his eyes closed, and they could see his regular +breathing. + +"O, Natasha!" Sonya suddenly almost screamed, catching her +companion's arm and stepping back from the door. + +"What? What is it?" asked Natasha. + +"It's that, that..." said Sonya, with a white face and trembling +lips. + +Natasha softly closed the door and went with Sonya to the window, +not yet understanding what the latter was telling her. + +"You remember," said Sonya with a solemn and frightened +expression. "You remember when I looked in the mirror for you... at +Otradnoe at Christmas? Do you remember what I saw?" + +"Yes, yes!" cried Natasha opening her eyes wide, and vaguely +recalling that Sonya had told her something about Prince Andrew whom +she had seen lying down. + +"You remember?" Sonya went on. "I saw it then and told everybody, +you and Dunyasha. I saw him lying on a bed," said she, making a +gesture with her hand and a lifted finger at each detail, "and that he +had his eyes closed and was covered just with a pink quilt, and that +his hands were folded," she concluded, convincing herself that the +details she had just seen were exactly what she had seen in the +mirror. + +She had in fact seen nothing then but had mentioned the first +thing that came into her head, but what she had invented then seemed +to her now as real as any other recollection. She not only +remembered what she had then said--that he turned to look at her and +smiled and was covered with something red--but was firmly convinced +that she had then seen and said that he was covered with a pink +quilt and that his eyes were closed. + +"Yes, yes, it really was pink!" cried Natasha, who now thought she +too remembered the word pink being used, and saw in this the most +extraordinary and mysterious part of the prediction. + +"But what does it mean?" she added meditatively. + +"Oh, I don't know, it is all so strange," replied Sonya, clutching +at her head. + +A few minutes later Prince Andrew rang and Natasha went to him, +but Sonya, feeling unusually excited and touched, remained at the +window thinking about the strangeness of what had occurred. + + +They had an opportunity that day to send letters to the army, and +the countess was writing to her son. + +"Sonya!" said the countess, raising her eyes from her letter as +her niece passed, "Sonya, won't you write to Nicholas?" She spoke in a +soft, tremulous voice, and in the weary eyes that looked over her +spectacles Sonya read all that the countess meant to convey with these +words. Those eyes expressed entreaty, shame at having to ask, fear +of a refusal, and readiness for relentless hatred in case of such +refusal. + +Sonya went up to the countess and, kneeling down, kissed her hand. + +"Yes, Mamma, I will write," said she. + +Sonya was softened, excited, and touched by all that had occurred +that day, especially by the mysterious fulfillment she had just seen +of her vision. Now that she knew that the renewal of Natasha's +relations with Prince Andrew would prevent Nicholas from marrying +Princess Mary, she was joyfully conscious of a return of that +self-sacrificing spirit in which she was accustomed to live and +loved to live. So with a joyful consciousness of performing a +magnanimous deed--interrupted several times by the tears that dimmed +her velvety black eyes--she wrote that touching letter the arrival +of which had so amazed Nicholas. + + + + + +CHAPTER IX + + +The officer and soldiers who had arrested Pierre treated him with +hostility but yet with respect, in the guardhouse to which he was +taken. In their attitude toward him could still be felt both +uncertainty as to who he might be--perhaps a very important person- +and hostility as a result of their recent personal conflict with him. + +But when the guard was relieved next morning, Pierre felt that for +the new guard--both officers and men--he was not as interesting as +he had been to his captors; and in fact the guard of the second day +did not recognize in this big, stout man in a peasant coat the +vigorous person who had fought so desperately with the marauder and +the convoy and had uttered those solemn words about saving a child; +they saw in him only No. 17 of the captured Russians, arrested and +detained for some reason by order of the Higher Command. If they +noticed anything remarkable about Pierre, it was only his unabashed, +meditative concentration and thoughtfulness, and the way he spoke +French, which struck them as surprisingly good. In spite of this he +was placed that day with the other arrested suspects, as the +separate room he had occupied was required by an officer. + +All the Russians confined with Pierre were men of the lowest class +and, recognizing him as a gentleman, they all avoided him, more +especially as he spoke French. Pierre felt sad at hearing them +making fun of him. + +That evening he learned that all these prisoners (he, probably, +among them) were to be tried for incendiarism. On the third day he was +taken with the others to a house where a French general with a white +mustache sat with two colonels and other Frenchmen with scarves on +their arms. With the precision and definiteness customary in +addressing prisoners, and which is supposed to preclude human frailty, +Pierre like the others was questioned as to who he was, where he had +been, with what object, and so on. + +These questions, like questions put at trials generally, left the +essence of the matter aside, shut out the possibility of that +essence's being revealed, and were designed only to form a channel +through which the judges wished the answers of the accused to flow +so as to lead to the desired result, namely a conviction. As soon as +Pierre began to say anything that did not fit in with that aim, the +channel was removed and the water could flow to waste. Pierre felt, +moreover, what the accused always feel at their trial, perplexity as +to why these questions were put to him. He had a feeling that it was +only out of condescension or a kind of civility that this device of +placing a channel was employed. He knew he was in these men's power, +that only by force had they brought him there, that force alone gave +them the right to demand answers to their questions, and that the sole +object of that assembly was to inculpate him. And so, as they had +the power and wish to inculpate him, this expedient of an inquiry +and trial seemed unnecessary. It was evident that any answer would +lead to conviction. When asked what he was doing when he was arrested, +Pierre replied in a rather tragic manner that he was restoring to +its parents a child he had saved from the flames. Why had he fought +the marauder? Pierre answered that he "was protecting a woman," and +that "to protect a woman who was being insulted was the duty of +every man; that..." They interrupted him, for this was not to the +point. Why was he in the yard of a burning house where witnesses had +seen him? He replied that he had gone out to see what was happening in +Moscow. Again they interrupted him: they had not asked where he was +going, but why he was found near the fire? Who was he? they asked, +repeating their first question, which he had declined to answer. Again +he replied that he could not answer it. + +"Put that down, that's bad... very bad," sternly remarked the +general with the white mustache and red flushed face. + + +On the fourth day fires broke out on the Zubovski rampart. + +Pierre and thirteen others were moved to the coach house of a +merchant's house near the Crimean bridge. On his way through the +streets Pierre felt stifled by the smoke which seemed to hang over the +whole city. Fires were visible on all sides. He did not then realize +the significance of the burning of Moscow, and looked at the fires +with horror. + +He passed four days in the coach house near the Crimean bridge and +during that time learned, from the talk of the French soldiers, that +all those confined there were awaiting a decision which might come any +day from the marshal. What marshal this was, Pierre could not learn +from the soldiers. Evidently for them "the marshal" represented a very +high and rather mysterious power. + +These first days, before the eighth of September when the +prisoners were had up for a second examination, were the hardest of +all for Pierre. + + + + + +CHAPTER X + + +On the eighth of September an officer--a very important one +judging by the respect the guards showed him--entered the coach +house where the prisoners were. This officer, probably someone on +the staff, was holding a paper in his hand, and called over all the +Russians there, naming Pierre as "the man who does not give his name." +Glancing indolently and indifferently at all the prisoners, he ordered +the officer in charge to have them decently dressed and tidied up +before taking them to the marshal. An hour later a squad of soldiers +arrived and Pierre with thirteen others was led to the Virgin's Field. +It was a fine day, sunny after rain, and the air was unusually pure. +The smoke did not hang low as on the day when Pierre had been taken +from the guardhouse on the Zubovski rampart, but rose through the pure +air in columns. No flames were seen, but columns of smoke rose on +all sides, and all Moscow as far as Pierre could see was one vast +charred ruin. On all sides there were waste spaces with only stoves +and chimney stacks still standing, and here and there the blackened +walls of some brick houses. Pierre gazed at the ruins and did not +recognize districts he had known well. Here and there he could see +churches that had not been burned. The Kremlin, which was not +destroyed, gleamed white in the distance with its towers and the +belfry of Ivan the Great. The domes of the New Convent of the Virgin +glittered brightly and its bells were ringing particularly clearly. +These bells reminded Pierre that it was Sunday and the feast of the +Nativity of the Virgin. But there seemed to be no one to celebrate +this holiday: everywhere were blackened ruins, and the few Russians to +be seen were tattered and frightened people who tried to hide when +they saw the French. + +It was plain that the Russian nest was ruined and destroyed, but +in place of the Russian order of life that had been destroyed, +Pierre unconsciously felt that a quite different, firm, French order +had been established over this ruined nest. He felt this in the +looks of the soldiers who, marching in regular ranks briskly and +gaily, were escorting him and the other criminals; he felt it in the +looks of an important French official in a carriage and pair driven by +a soldier, whom they met on the way. He felt it in the merry sounds of +regimental music he heard from the left side of the field, and felt +and realized it especially from the list of prisoners the French +officer had read out when he came that morning. Pierre had been +taken by one set of soldiers and led first to one and then to +another place with dozens of other men, and it seemed that they +might have forgotten him, or confused him with the others. But no: the +answers he had given when questioned had come back to him in his +designation as "the man who does not give his name," and under that +appellation, which to Pierre seemed terrible, they were now leading +him somewhere with unhesitating assurance on their faces that he and +all the other prisoners were exactly the ones they wanted and that +they were being taken to the proper place. Pierre felt himself to be +an insignificant chip fallen among the wheels of a machine whose +action he did not understand but which was working well. + +He and the other prisoners were taken to the right side of the +Virgin's Field, to a large white house with an immense garden not +far from the convent. This was Prince Shcherbitov's house, where +Pierre had often been in other days, and which, as he learned from the +talk of the soldiers, was now occupied by the marshal, the Duke of +Eckmuhl (Davout). + +They were taken to the entrance and led into the house one by one. +Pierre was the sixth to enter. He was conducted through a glass +gallery, an anteroom, and a hall, which were familiar to him, into a +long low study at the door of which stood an adjutant. + +Davout, spectacles on nose, sat bent over a table at the further end +of the room. Pierre went close up to him, but Davout, evidently +consulting a paper that lay before him, did not look up. Without +raising his eyes, he said in a low voice: + +"Who are you?" + +Pierre was silent because he was incapable of uttering a word. To +him Davout was not merely a French general, but a man notorious for +his cruelty. Looking at his cold face, as he sat like a stern +schoolmaster who was prepared to wait awhile for an answer, Pierre +felt that every instant of delay might cost him his life; but he did +not know what to say. He did not venture to repeat what he had said at +his first examination, yet to disclose his rank and position was +dangerous and embarrassing. So he was silent. But before he had +decided what to do, Davout raised his head, pushed his spectacles back +on his forehead, screwed up his eyes, and looked intently at him. + +"I know that man," he said in a cold, measured tone, evidently +calculated to frighten Pierre. + +The chill that had been running down Pierre's back now seized his +head as in a vise. + +"You cannot know me, General, I have never seen you..." + +"He is a Russian spy," Davout interrupted, addressing another +general who was present, but whom Pierre had not noticed. + +Davout turned away. With an unexpected reverberation in his voice +Pierre rapidly began: + +"No, monseigneur," he said, suddenly remembering that Davout was a +duke. "No, monseigneur, you cannot have known me. I am a militia +officer and have not quitted Moscow." + +"Your name?" asked Davout. + +"Bezukhov." + +"What proof have I that you are not lying?" + +"Monseigneur!" exclaimed Pierre, not in an offended but in a +pleading voice. + +Davout looked up and gazed intently at him. For some seconds they +looked at one another, and that look saved Pierre. Apart from +conditions of war and law, that look established human relations +between the two men. At that moment an immense number of things passed +dimly through both their minds, and they realized that they were +both children of humanity and were brothers. + +At the first glance, when Davout had only raised his head from the +papers where human affairs and lives were indicated by numbers, Pierre +was merely a circumstance, and Davout could have shot him without +burdening his conscience with an evil deed, but now he saw in him a +human being. He reflected for a moment. + +"How can you show me that you are telling the truth?" said Davout +coldly. + +Pierre remembered Ramballe, and named him and his regiment and the +street where the house was. + +"You are not what you say," returned Davout. + +In a trembling, faltering voice Pierre began adducing proofs of +the truth of his statements. + +But at that moment an adjutant entered and reported something to +Davout. + +Davout brightened up at the news the adjutant brought, and began +buttoning up his uniform. It seemed that he had quite forgotten +Pierre. + +When the adjutant reminded him of the prisoner, he jerked his head +in Pierre's direction with a frown and ordered him to be led away. But +where they were to take him Pierre did not know: back to the coach +house or to the place of execution his companions had pointed out to +him as they crossed the Virgin's Field. + +He turned his head and saw that the adjutant was putting another +question to Davout. + +"Yes, of course!" replied Davout, but what this "yes" meant, +Pierre did not know. + +Pierre could not afterwards remember how he went, whether it was +far, or in which direction. His faculties were quite numbed, he was +stupefied, and noticing nothing around him went on moving his legs +as the others did till they all stopped and he stopped too. The only +thought in his mind at that time was: who was it that had really +sentenced him to death? Not the men on the commission that had first +examined him--not one of them wished to or, evidently, could have done +it. It was not Davout, who had looked at him in so human a way. In +another moment Davout would have realized that he was doing wrong, but +just then the adjutant had come in and interrupted him. The +adjutant, also, had evidently had no evil intent though he might +have refrained from coming in. Then who was executing him, killing +him, depriving him of life--him, Pierre, with all his memories, +aspirations, hopes, and thoughts? Who was doing this? And Pierre +felt that it was no one. + +It was a system--a concurrence of circumstances. + +A system of some sort was killing him--Pierre--depriving him of +life, of everything, annihilating him. + + + + + +CHAPTER XI + + +From Prince Shcherbatov's house the prisoners were led straight down +the Virgin's Field, to the left of the nunnery, as far as a kitchen +garden in which a post had been set up. Beyond that post a fresh pit +had been dug in the ground, and near the post and the pit a large +crowd stood in a semicircle. The crowd consisted of a few Russians and +many of Napoleon's soldiers who were not on duty--Germans, Italians, +and Frenchmen, in a variety of uniforms. To the right and left of +the post stood rows of French troops in blue uniforms with red +epaulets and high boots and shakos. + +The prisoners were placed in a certain order, according to the +list (Pierre was sixth), and were led to the post. Several drums +suddenly began to beat on both sides of them, and at that sound Pierre +felt as if part of his soul had been torn away. He lost the power of +thinking or understanding. He could only hear and see. And he had only +one wish--that the frightful thing that had to happen should happen +quickly. Pierre looked round at his fellow prisoners and scrutinized +them. + +The two first were convicts with shaven heads. One was tall and +thin, the other dark, shaggy, and sinewy, with a flat nose. The +third was a domestic serf, about forty-five years old, with grizzled +hair and a plump, well-nourished body. The fourth was a peasant, a +very handsome man with a broad, light-brown beard and black eyes. +The fifth was a factory hand, a thin, sallow-faced lad of eighteen +in a loose coat. + +Pierre heard the French consulting whether to shoot them +separately or two at a time. "In couples," replied the officer in +command in a calm voice. There was a stir in the ranks of the soldiers +and it was evident that they were all hurrying--not as men hurry to do +something they understand, but as people hurry to finish a necessary +but unpleasant and incomprehensible task. + +A French official wearing a scarf came up to the right of the row of +prisoners and read out the sentence in Russian and in French. + +Then two pairs of Frenchmen approached the criminals and at the +officer's command took the two convicts who stood first in the row. +The convicts stopped when they reached the post and, while sacks +were being brought, looked dumbly around as a wounded beast looks at +an approaching huntsman. One crossed himself continually, the other +scratched his back and made a movement of the lips resembling a smile. +With hurried hands the soldiers blindfolded them, drawing the sacks +over their heads, and bound them to the post. + +Twelve sharpshooters with muskets stepped out of the ranks with a +firm regular tread and halted eight paces from the post. Pierre turned +away to avoid seeing what was going to happen. Suddenly a crackling, +rolling noise was heard which seemed to him louder than the most +terrific thunder, and he looked round. There was some smoke, and the +Frenchmen were doing something near the pit, with pale faces and +trembling hands. Two more prisoners were led up. In the same way and +with similar looks, these two glanced vainly at the onlookers with +only a silent appeal for protection in their eyes, evidently unable to +understand or believe what was going to happen to them. They could not +believe it because they alone knew what their life meant to them, +and so they neither understood nor believed that it could be taken +from them. + +Again Pierre did not wish to look and again turned away; but again +the sound as of a frightful explosion struck his ear, and at the +same moment he saw smoke, blood, and the pale, scared faces of the +Frenchmen who were again doing something by the post, their +trembling hands impeding one another. Pierre, breathing heavily, +looked around as if asking what it meant. The same question was +expressed in all the looks that met his. + +On the faces of all the Russians and of the French soldiers and +officers without exception, he read the same dismay, horror, and +conflict that were in his own heart. "But who, after all, is doing +this? They are all suffering as I am. Who then is it? Who?" flashed +for an instant through his mind. + +"Sharpshooters of the 86th, forward!" shouted someone. The fifth +prisoner, the one next to Pierre, was led away--alone. Pierre did +not understand that he was saved, that he and the rest had been +brought there only to witness the execution. With ever-growing horror, +and no sense of joy or relief, he gazed at what was taking place. +The fifth man was the factory lad in the loose cloak. The moment +they laid hands on him he sprang aside in terror and clutched at +Pierre. (Pierre shuddered and shook himself free.) The lad was +unable to walk. They dragged him along, holding him up under the arms, +and he screamed. When they got him to the post he grew quiet, as if he +suddenly understood something. Whether he understood that screaming +was useless or whether he thought it incredible that men should kill +him, at any rate he took his stand at the post, waiting to be +blindfolded like the others, and like a wounded animal looked around +him with glittering eyes. + +Pierre was no longer able to turn away and close his eyes. His +curiosity and agitation, like that of the whole crowd, reached the +highest pitch at this fifth murder. Like the others this fifth man +seemed calm; he wrapped his loose cloak closer and rubbed one bare +foot with the other. + +When they began to blindfold him he himself adjusted the knot +which hurt the back of his head; then when they propped him against +the bloodstained post, he leaned back and, not being comfortable in +that position, straightened himself, adjusted his feet, and leaned +back again more comfortably. Pierre did not take his eyes from him and +did not miss his slightest movement. + +Probably a word of command was given and was followed by the reports +of eight muskets; but try as he would Pierre could not afterwards +remember having heard the slightest sound of the shots. He only saw +how the workman suddenly sank down on the cords that held him, how +blood showed itself in two places, how the ropes slackened under the +weight of the hanging body, and how the workman sat down, his head +hanging unnaturally and one leg bent under him. Pierre ran up to the +post. No one hindered him. Pale, frightened people were doing +something around the workman. The lower jaw of an old Frenchman with a +thick mustache trembled as he untied the ropes. The body collapsed. +The soldiers dragged it awkwardly from the post and began pushing it +into the pit. + +They all plainly and certainly knew that they were criminals who +must hide the traces of their guilt as quickly as possible. + +Pierre glanced into the pit and saw that the factory lad was lying +with his knees close up to his head and one shoulder higher than the +other. That shoulder rose and fell rhythmically and convulsively, +but spadefuls of earth were already being thrown over the whole +body. One of the soldiers, evidently suffering, shouted gruffly and +angrily at Pierre to go back. But Pierre did not understand him and +remained near the post, and no one drove him away. + +When the pit had been filled up a command was given. Pierre was +taken back to his place, and the rows of troops on both sides of the +post made a half turn and went past it at a measured pace. The +twenty-four sharpshooters with discharged muskets, standing in the +center of the circle, ran back to their places as the companies passed +by. + +Pierre gazed now with dazed eyes at these sharpshooters who ran in +couples out of the circle. All but one rejoined their companies. +This one, a young soldier, his face deadly pale, his shako pushed +back, and his musket resting on the ground, still stood near the pit +at the spot from which he had fired. He swayed like a drunken man, +taking some steps forward and back to save himself from falling. An +old, noncommissioned officer ran out of the ranks and taking him by +the elbow dragged him to his company. The crowd of Russians and +Frenchmen began to disperse. They all went away silently and with +drooping heads. + +"That will teach them to start fires," said one of the Frenchmen. + +Pierre glanced round at the speaker and saw that it was a soldier +who was trying to find some relief after what had been done, but was +not able to do so. Without finishing what he had begun to say he +made a hopeless movement with his arm and went away. + + + + + +CHAPTER XII + + +After the execution Pierre was separated from the rest of the +prisoners and placed alone in a small, ruined, and befouled church. + +Toward evening a noncommissioned officer entered with two soldiers +and told him that he had been pardoned and would now go to the +barracks for the prisoners of war. Without understanding what was said +to him, Pierre got up and went with the soldiers. They took him to the +upper end of the field, where there were some sheds built of charred +planks, beams, and battens, and led him into one of them. In the +darkness some twenty different men surrounded Pierre. He looked at +them without understanding who they were, why they were there, or what +they wanted of him. He heard what they said, but did not understand +the meaning of the words and made no kind of deduction from or +application of them. He replied to questions they put to him, but +did not consider who was listening to his replies, nor how they +would understand them. He looked at their faces and figures, but +they all seemed to him equally meaningless. + +From the moment Pierre had witnessed those terrible murders +committed by men who did not wish to commit them, it was as if the +mainspring of his life, on which everything depended and which made +everything appear alive, had suddenly been wrenched out and everything +had collapsed into a heap of meaningless rubbish. Though he did not +acknowledge it to himself, his faith in the right ordering of the +universe, in humanity, in his own soul, and in God, had been +destroyed. He had experienced this before, but never so strongly as +now. When similar doubts had assailed him before, they had been the +result of his own wrongdoing, and at the bottom of his heart he had +felt that relief from his despair and from those doubts was to be +found within himself. But now he felt that the universe had crumbled +before his eyes and only meaningless ruins remained, and this not by +any fault of his own. He felt that it was not in his power to regain +faith in the meaning of life. + +Around him in the darkness men were standing and evidently something +about him interested them greatly. They were telling him something and +asking him something. Then they led him away somewhere, and at last he +found himself in a corner of the shed among men who were laughing +and talking on all sides. + +"Well, then, mates... that very prince who..." some voice at the +other end of the shed was saying, with a strong emphasis on the word +who. + +Sitting silent and motionless on a heap of straw against the wall, +Pierre sometimes opened and sometimes closed his eyes. But as soon +as he closed them he saw before him the dreadful face of the factory +lad--especially dreadful because of its simplicity--and the faces of +the murderers, even more dreadful because of their disquiet. And he +opened his eyes again and stared vacantly into the darkness around +him. + +Beside him in a stooping position sat a small man of whose +presence he was first made aware by a strong smell of perspiration +which came from him every time he moved. This man was doing +something to his legs in the darkness, and though Pierre could not see +his face he felt that the man continually glanced at him. On growing +used to the darkness Pierre saw that the man was taking off his leg +bands, and the way he did it aroused Pierre's interest. + +Having unwound the string that tied the band on one leg, he +carefully coiled it up and immediately set to work on the other leg, +glancing up at Pierre. While one hand hung up the first string the +other was already unwinding the band on the second leg. In this way, +having carefully removed the leg bands by deft circular motions of his +arm following one another uninterruptedly, the man hung the leg +bands up on some pegs fixed above his head. Then he took out a +knife, cut something, closed the knife, placed it under the head of +his bed, and, seating himself comfortably, clasped his arms round +his lifted knees and fixed his eyes on Pierre. The latter was +conscious of something pleasant, comforting, and well rounded in these +deft movements, in the man's well-ordered arrangements in his +corner, and even in his very smell, and he looked at the man without +taking his eyes from him. + +"You've seen a lot of trouble, sir, eh?" the little man suddenly +said. + +And there was so much kindliness and simplicity in his singsong +voice that Pierre tried to reply, but his jaw trembled and he felt +tears rising to his eyes. The little fellow, giving Pierre no time +to betray his confusion, instantly continued in the same pleasant +tones: + +"Eh, lad, don't fret!" said he, in the tender singsong caressing +voice old Russian peasant women employ. "Don't fret, friend--'suffer +an hour, live for an age!' that's how it is, my dear fellow. And +here we live, thank heaven, without offense. Among these folk, too, +there are good men as well as bad," said he, and still speaking, he +turned on his knees with a supple movement, got up, coughed, and +went off to another part of the shed. + +"Eh, you rascal!" Pierre heard the same kind voice saying at the +other end of the shed. "So you've come, you rascal? She remembers... +Now, now, that'll do!" + +And the soldier, pushing away a little dog that was jumping up at +him, returned to his place and sat down. In his hands he had something +wrapped in a rag. + +"Here, eat a bit, sir," said he, resuming his former respectful tone +as he unwrapped and offered Pierre some baked potatoes. "We had soup +for dinner and the potatoes are grand!" + +Pierre had not eaten all day and the smell of the potatoes seemed +extremely pleasant to him. He thanked the soldier and began to eat. + +"Well, are they all right?" said the soldier with a smile. "You +should do like this." + +He took a potato, drew out his clasp knife, cut the potato into +two equal halves on the palm of his hand, sprinkled some salt on it +from the rag, and handed it to Pierre. + +"The potatoes are grand!" he said once more. "Eat some like that!" + +Pierre thought he had never eaten anything that tasted better. + +"Oh, I'm all right," said he, "but why did they shoot those poor +fellows? The last one was hardly twenty." + +"Tss, tt...!" said the little man. "Ah, what a sin... what a sin!" +he added quickly, and as if his words were always waiting ready in his +mouth and flew out involuntarily he went on: "How was it, sir, that +you stayed in Moscow?" + +"I didn't think they would come so soon. I stayed accidentally," +replied Pierre. + +"And how did they arrest you, dear lad? At your house?" + +"No, I went to look at the fire, and they arrested me there, and +tried me as an incendiary." + +"Where there's law there's injustice," put in the little man. + +"And have you been here long?" Pierre asked as he munched the last +of the potato. + +"I? It was last Sunday they took me, out of a hospital in Moscow." + +"Why, are you a soldier then?" + +"Yes, we are soldiers of the Apsheron regiment. I was dying of +fever. We weren't told anything. There were some twenty of us lying +there. We had no idea, never guessed at all." + +"And do you feel sad here?" Pierre inquired. + +"How can one help it, lad? My name is Platon, and the surname is +Karataev," he added, evidently wishing to make it easier for Pierre to +address him. "They call me 'little falcon' in the regiment. How is one +to help feeling sad? Moscow--she's the mother of cities. How can one +see all this and not feel sad? But 'the maggot gnaws the cabbage, +yet dies first'; that's what the old folks used to tell us," he +added rapidly. + +"What? What did you say?" asked Pierre. + +"Who? I?" said Karataev. "I say things happen not as we plan but +as God judges," he replied, thinking that he was repeating what he had +said before, and immediately continued: + +"Well, and you, have you a family estate, sir? And a house? So you +have abundance, then? And a housewife? And your old parents, are +they still living?" he asked. + +And though it was too dark for Pierre to see, he felt that a +suppressed smile of kindliness puckered the soldier's lips as he put +these questions. He seemed grieved that Pierre had no parents, +especially that he had no mother. + +"A wife for counsel, a mother-in-law for welcome, but there's none +as dear as one's own mother!" said he. "Well, and have you little +ones?" he went on asking. + +Again Pierre's negative answer seemed to distress him, and he +hastened to add: + +"Never mind! You're young folks yet, and please God may still have +some. The great thing is to live in harmony...." + +"But it's all the same now," Pierre could not help saying. + +"Ah, my dear fellow!" rejoined Karataev, "never decline a prison +or a beggar's sack!" + +He seated himself more comfortably and coughed, evidently +preparing to tell a long story. + +"Well, my dear fellow, I was still living at home," he began. "We +had a well-to-do homestead, plenty of land, we peasants lived well and +our house was one to thank God for. When Father and we went out mowing +there were seven of us. We lived well. We were real peasants. It so +happened..." + +And Platon Karataev told a long story of how he had gone into +someone's copse to take wood, how he had been caught by the keeper, +had been tried, flogged, and sent to serve as a soldier. + +"Well, lad," and a smile changed the tone of his voice "we thought +it was a misfortune but it turned out a blessing! If it had not been +for my sin, my brother would have had to go as a soldier. But he, my +younger brother, had five little ones, while I, you see, only left a +wife behind. We had a little girl, but God took her before I went as a +soldier. I come home on leave and I'll tell you how it was, I look and +see that they are living better than before. The yard full of +cattle, the women at home, two brothers away earning wages, and only +Michael the youngest, at home. Father, he says, 'All my children are +the same to me: it hurts the same whichever finger gets bitten. But if +Platon hadn't been shaved for a soldier, Michael would have had to +go.' called us all to him and, will you believe it, placed us in front +of the icons. 'Michael,' he says, 'come here and bow down to his feet; +and you, young woman, you bow down too; and you, grandchildren, also +bow down before him! Do you understand?' he says. That's how it is, +dear fellow. Fate looks for a head. But we are always judging, 'that's +not well--that's not right!' Our luck is like water in a dragnet: +you pull at it and it bulges, but when you've drawn it out it's empty! +That's how it is." + +And Platon shifted his seat on the straw. + +After a short silence he rose. + +"Well, I think you must be sleepy," said he, and began rapidly +crossing himself and repeating: + +"Lord Jesus Christ, holy Saint Nicholas, Frola and Lavra! Lord Jesus +Christ, holy Saint Nicholas, Frola and Lavra! Lord Jesus Christ, +have mercy on us and save us!" he concluded, then bowed to the ground, +got up, sighed, and sat down again on his heap of straw. "That's the +way. Lay me down like a stone, O God, and raise me up like a loaf," he +muttered as he lay down, pulling his coat over him. + +"What prayer was that you were saying?" asked Pierre. + +"Eh?" murmured Platon, who had almost fallen asleep. "What was I +saying? I was praying. Don't you pray?" + +"Yes, I do," said Pierre. "But what was that you said: Frola and +Lavra?" + +"Well, of course," replied Platon quickly, "the horses' saints. +One must pity the animals too. Eh, the rascal! Now you've curled up +and got warm, you daughter of a bitch!" said Karataev, touching the +dog that lay at his feet, and again turning over he fell asleep +immediately. + +Sounds of crying and screaming came from somewhere in the distance +outside, and flames were visible through the cracks of the shed, but +inside it was quiet and dark. For a long time Pierre did not sleep, +but lay with eyes open in the darkness, listening to the regular +snoring of Platon who lay beside him, and he felt that the world +that had been shattered was once more stirring in his soul with a +new beauty and on new and unshakable foundations. + + + + + +CHAPTER XIII + + +Twenty-three soldiers, three officers, and two officials were +confined in the shed in which Pierre had been placed and where he +remained for four weeks. + +When Pierre remembered them afterwards they all seemed misty figures +to him except Platon Karataev, who always remained in his mind a +most vivid and precious memory and the personification of everything +Russian, kindly, and round. When Pierre saw his neighbor next +morning at dawn the first impression of him, as of something round, +was fully confirmed: Platon's whole figure--in a French overcoat +girdled with a cord, a soldier's cap, and bast shoes--was round. His +head was quite round, his back, chest, shoulders, and even his arms, +which he held as if ever ready to embrace something, were rounded, his +pleasant smile and his large, gentle brown eyes were also round. + +Platon Karataev must have been fifty, judging by his stories of +campaigns he had been in, told as by an old soldier. He did not +himself know his age and was quite unable to determine it. But his +brilliantly white, strong teeth which showed in two unbroken +semicircles when he laughed--as he often did--were all sound and good, +there was not a gray hair in his beard or on his head, and his whole +body gave an impression of suppleness and especially of firmness and +endurance. + +His face, despite its fine, rounded wrinkles, had an expression of +innocence and youth, his voice was pleasant and musical. But the chief +peculiarity of his speech was its directness and appositeness. It +was evident that he never considered what he had said or was going +to say, and consequently the rapidity and justice of his intonation +had an irresistible persuasiveness. + +His physical strength and agility during the first days of his +imprisonment were such that he seemed not to know what fatigue and +sickness meant. Every night before lying down, he said: "Lord, lay +me down as a stone and raise me up as a loaf!" and every morning on +getting up, he said: "I lay down and curled up, I get up and shake +myself." And indeed he only had to lie down, to fall asleep like a +stone, and he only had to shake himself, to be ready without a +moment's delay for some work, just as children are ready to play +directly they awake. He could do everything, not very well but not +badly. He baked, cooked, sewed, planed, and mended boots. He was +always busy, and only at night allowed himself conversation--of +which he was fond--and songs. He did not sing like a trained singer +who knows he is listened to, but like the birds, evidently giving vent +to the sounds in the same way that one stretches oneself or walks +about to get rid of stiffness, and the sounds were always +high-pitched, mournful, delicate, and almost feminine, and his face at +such times was very serious. + +Having been taken prisoner and allowed his beard to grow, he +seemed to have thrown off all that had been forced upon him- +everything military and alien to himself--and had returned to his +former peasant habits. + +"A soldier on leave--a shirt outside breeches," he would say. + +He did not like talking about his life as a soldier, though he did +not complain, and often mentioned that he had not been flogged once +during the whole of his army service. When he related anything it +was generally some old and evidently precious memory of his +"Christian" life, as he called his peasant existence. The proverbs, of +which his talk was full, were for the most part not the coarse and +indecent saws soldiers employ, but those folk sayings which taken +without a context seem so insignificant, but when used appositely +suddenly acquire a significance of profound wisdom. + +He would often say the exact opposite of what he had said on a +previous occasion, yet both would be right. He liked to talk and he +talked well, adorning his speech with terms of endearment and with +folk sayings which Pierre thought he invented himself, but the chief +charm of his talk lay in the fact that the commonest events--sometimes +just such as Pierre had witnessed without taking notice of them- +assumed in Karataev's a character of solemn fitness. He liked to +hear the folk tales one of the soldiers used to tell of an evening +(they were always the same), but most of all he liked to hear +stories of real life. He would smile joyfully when listening to such +stories, now and then putting in a word or asking a question to make +the moral beauty of what he was told clear to himself. Karataev had no +attachments, friendships, or love, as Pierre understood them, but +loved and lived affectionately with everything life brought him in +contact with, particularly with man--not any particular man, but those +with whom he happened to be. He loved his dog, his comrades, the +French, and Pierre who was his neighbor, but Pierre felt that in spite +of Karataev's affectionate tenderness for him (by which he +unconsciously gave Pierre's spiritual life its due) he would not +have grieved for a moment at parting from him. And Pierre began to +feel in the same way toward Karataev. + +To all the other prisoners Platon Karataev seemed a most ordinary +soldier. They called him "little falcon" or "Platosha," chaffed him +good-naturedly, and sent him on errands. But to Pierre he always +remained what he had seemed that first night: an unfathomable, +rounded, eternal personification of the spirit of simplicity and +truth. + +Platon Karataev knew nothing by heart except his prayers. When he +began to speak he seemed not to know how he would conclude. + +Sometimes Pierre, struck by the meaning of his words, would ask +him to repeat them, but Platon could never recall what he had said a +moment before, just as he never could repeat to Pierre the words of +his favorite song: native and birch tree and my heart is sick occurred +in it, but when spoken and not sung, no meaning could be got out of +it. He did not, and could not, understand the meaning of words apart +from their context. Every word and action of his was the manifestation +of an activity unknown to him, which was his life. But his life, as he +regarded it, had no meaning as a separate thing. It had meaning only +as part of a whole of which he was always conscious. His words and +actions flowed from him as evenly, inevitably, and spontaneously as +fragrance exhales from a flower. He could not understand the value +or significance of any word or deed taken separately. + + + + + +CHAPTER XIV + + +When Princess Mary heard from Nicholas that her brother was with the +Rostovs at Yaroslavl she at once prepared to go there, in spite of her +aunt's efforts to dissuade her--and not merely to go herself but to +take her nephew with her. Whether it were difficult or easy, +possible or impossible, she did not ask and did not want to know: it +was her duty not only herself to be near her brother who was perhaps +dying, but to do everything possible to take his son to him, and so +she prepared to set off. That she had not heard from Prince Andrew +himself, Princess Mary attributed to his being too weak to write or to +his considering the long journey too hard and too dangerous for her +and his son. + +In a few days Princess Mary was ready to start. Her equipages were +the huge family coach in which she had traveled to Voronezh, a +semiopen trap, and a baggage cart. With her traveled Mademoiselle +Bourienne, little Nicholas and his tutor, her old nurse, three +maids, Tikhon, and a young footman and courier her aunt had sent to +accompany her. + +The usual route through Moscow could not be thought of, and the +roundabout way Princess Mary was obliged to take through Lipetsk, +Ryazan, Vladimir, and Shuya was very long and, as post horses were not +everywhere obtainable, very difficult, and near Ryazan where the +French were said to have shown themselves was even dangerous. + +During this difficult journey Mademoiselle Bourienne, Dessalles, and +Princess Mary's servants were astonished at her energy and firmness of +spirit. She went to bed later and rose earlier than any of them, and +no difficulties daunted her. Thanks to her activity and energy, +which infected her fellow travelers, they approached Yaroslavl by +the end of the second week. + +The last days of her stay in Voronezh had been the happiest of her +life. Her love for Rostov no longer tormented or agitated her. It +filled her whole soul, had become an integral part of herself, and she +no longer struggled against it. Latterly she had become convinced that +she loved and was beloved, though she never said this definitely to +herself in words. She had become convinced of it at her last interview +with Nicholas, when he had come to tell her that her brother was +with the Rostovs. Not by a single word had Nicholas alluded to the +fact that Prince Andrew's relations with Natasha might, if he +recovered, be renewed, but Princess Mary saw by his face that he +knew and thought of this. + +Yet in spite of that, his relation to her--considerate, delicate, +and loving--not only remained unchanged, but it sometimes seemed to +Princess Mary that he was even glad that the family connection between +them allowed him to express his friendship more freely. She knew +that she loved for the first and only time in her life and felt that +she was beloved, and was happy in regard to it. + +But this happiness on one side of her spiritual nature did not +prevent her feeling grief for her brother with full force; on the +contrary, that spiritual tranquility on the one side made it the +more possible for her to give full play to her feeling for her +brother. That feeling was so strong at the moment of leaving +Voronezh that those who saw her off, as they looked at her careworn, +despairing face, felt sure she would fall ill on the journey. But +the very difficulties and preoccupations of the journey, which she +took so actively in hand, saved her for a while from her grief and +gave her strength. + +As always happens when traveling, Princess Mary thought only of +the journey itself, forgetting its object. But as she approached +Yaroslavl the thought of what might await her there--not after many +days, but that very evening--again presented itself to her and her +agitation increased to its utmost limit. + +The courier who had been sent on in advance to find out where the +Rostovs were staying in Yaroslavl, and in what condition Prince Andrew +was, when he met the big coach just entering the town gates was +appalled by the terrible pallor of the princess' face that looked +out at him from the window. + +"I have found out everything, your excellency: the Rostovs are +staying at the merchant Bronnikov's house, in the Square not far +from here, right above the Volga," said the courier. + +Princess Mary looked at him with frightened inquiry, not +understanding why he did not reply to what she chiefly wanted to know: +how was her brother? Mademoiselle Bourienne put that question for her. + +"How is the prince?" she asked. + +"His excellency is staying in the same house with them." + +"Then he is alive," thought Princess Mary, and asked in a low voice: +"How is he?" + +"The servants say he is still the same." + +What "still the same" might mean Princess Mary did not ask, but with +an unnoticed glance at little seven-year-old Nicholas, who was sitting +in front of her looking with pleasure at the town, she bowed her +head and did not raise it again till the heavy coach, rumbling, +shaking and swaying, came to a stop. The carriage steps clattered as +they were let down. + +The carriage door was opened. On the left there was water--a great +river--and on the right a porch. There were people at the entrance: +servants, and a rosy girl with a large plait of black hair, smiling as +it seemed to Princess Mary in an unpleasantly affected way. (This +was Sonya.) Princess Mary ran up the steps. "This way, this way!" said +the girl, with the same artificial smile, and the princess found +herself in the hall facing an elderly woman of Oriental type, who came +rapidly to meet her with a look of emotion. This was the countess. She +embraced Princess Mary and kissed her. + +"Mon enfant!" she muttered, "je vous aime et vous connais depuis +longtemps."* + + +*"My child! I love you and have known you a long time." + + Despite her excitement, Princess Mary realized that this was the +countess and that it was necessary to say something to her. Hardly +knowing how she did it, she contrived to utter a few polite phrases in +French in the same tone as those that had been addressed to her, and +asked: "How is he?" + +"The doctor says that he is not in danger," said the countess, but +as she spoke she raised her eyes with a sigh, and her gesture conveyed +a contradiction of her words. + +"Where is he? Can I see him--can I?" asked the princess. + +"One moment, Princess, one moment, my dear! Is this his son?" said +the countess, turning to little Nicholas who was coming in with +Dessalles. "There will be room for everybody, this is a big house. Oh, +what a lovely boy!" + +The countess took Princess Mary into the drawing room, where Sonya +was talking to Mademoiselle Bourienne. The countess caressed the +boy, and the old count came in and welcomed the princess. He had +changed very much since Princess Mary had last seen him. Then he had +been a brisk, cheerful, self-assured old man; now he seemed a pitiful, +bewildered person. While talking to Princess Mary he continually +looked round as if asking everyone whether he was doing the right +thing. After the destruction of Moscow and of his property, thrown out +of his accustomed groove he seemed to have lost the sense of his own +significance and to feel that there was no longer a place for him in +life. + +In spite of her one desire to see her brother as soon as possible, +and her vexation that at the moment when all she wanted was to see him +they should be trying to entertain her and pretending to admire her +nephew, the princess noticed all that was going on around her and felt +the necessity of submitting, for a time, to this new order of things +which she had entered. She knew it to be necessary, and though it +was hard for her she was not vexed with these people. + +"This is my niece," said the count, introducing Sonya--"You don't +know her, Princess?" + +Princess Mary turned to Sonya and, trying to stifle the hostile +feeling that arose in her toward the girl, she kissed her. But she +felt oppressed by the fact that the mood of everyone around her was so +far from what was in her own heart. + +"Where is he?" she asked again, addressing them all. + +"He is downstairs. Natasha is with him," answered Sonya, flushing. +"We have sent to ask. I think you must be tired, Princess." + +Tears of vexation showed themselves in Princess Mary's eyes. She +turned away and was about to ask the countess again how to go to +him, when light, impetuous, and seemingly buoyant steps were heard +at the door. The princess looked round and saw Natasha coming in, +almost running--that Natasha whom she had liked so little at their +meeting in Moscow long since. + +But hardly had the princess looked at Natasha's face before she +realized that here was a real comrade in her grief, and consequently a +friend. She ran to meet her, embraced her, and began to cry on her +shoulder. + +As soon as Natasha, sitting at the head of Prince Andrew's bed, +heard of Princess Mary's arrival, she softly left his room and +hastened to her with those swift steps that had sounded buoyant to +Princess Mary. + +There was only one expression on her agitated face when she ran into +the drawing room--that of love--boundless love for him, for her, and +for all that was near to the man she loved; and of pity, suffering for +others, and passionate desire to give herself entirely to helping +them. It was plain that at that moment there was in Natasha's heart no +thought of herself or of her own relations with Prince Andrew. + +Princess Mary, with her acute sensibility, understood all this at +the first glance at Natasha's face, and wept on her shoulder with +sorrowful pleasure. + +"Come, come to him, Mary," said Natasha, leading her into the +other room. + +Princess Mary raised her head, dried her eyes, and turned to +Natasha. She felt that from her she would be able to understand and +learn everything. + +"How..." she began her question but stopped short. + +She felt that it was impossible to ask, or to answer, in words. +Natasha's face eyes would have to tell her all more clearly +and profoundly. + +Natasha was gazing at her, but seemed afraid and in doubt whether to +say all she knew or not; she seemed to feel that before those luminous +eyes which penetrated into the very depths of her heart, it was +impossible not to tell the whole truth which she saw. And suddenly, +Natasha's lips twitched, ugly wrinkles gathered round her mouth, and +covering her face with her hands she burst into sobs. + +Princess Mary understood. + +But she still hoped, and asked, in words she herself did not trust: + +"But how is his wound? What is his general condition?" + +"You, you... will see," was all Natasha could say. + +They sat a little while downstairs near his room till they had +left off crying and were able to go to him with calm faces. + +"How has his whole illness gone? Is it long since he grew worse? +When did this happen?" Princess Mary inquired. + +Natasha told her that at first there had been danger from his +feverish condition and the pain he suffered, but at Troitsa that had +passed and the doctor had only been afraid of gangrene. That danger +had also passed. When they reached Yaroslavl the wound had begun to +fester (Natasha knew all about such things as festering) and the +doctor had said that the festering might take a normal course. Then +fever set in, but the doctor had said the fever was not very serious. + +"But two days ago this suddenly happened," said Natasha, +struggling with her sobs. "I don't know why, but you will see what +he is like." + +"Is he weaker? Thinner?" asked the princess. + +"No, it's not that, but worse. You will see. O, Mary, he is too +good, he cannot, cannot live, because..." + + + + + +CHAPTER XV + + +When Natasha opened Prince Andrew's door with a familiar movement +and let Princess Mary pass into the room before her, the princess felt +the sobs in her throat. Hard as she had tried to prepare herself, +and now tried to remain tranquil, she knew that she would be unable to +look at him without tears. + +The princess understood what Natasha had meant by the words: "two +days ago this suddenly happened." She understood those words to mean +that he had suddenly softened and that this softening and gentleness +were signs of approaching death. As she stepped to the door she +already saw in imagination Andrew's face as she remembered it in +childhood, a gentle, mild, sympathetic face which he had rarely shown, +and which therefore affected her very strongly. She was sure he +would speak soft, tender words to her such as her father had uttered +before his death, and that she would not be able to bear it and +would burst into sobs in his presence. Yet sooner or later it had to +be, and she went in. The sobs rose higher and higher in her throat +as she more and more clearly distinguished his form and her +shortsighted eyes tried to make out his features, and then she saw his +face and met his gaze. + +He was lying in a squirrel-fur dressing gown on a divan, +surrounded by pillows. He was thin and pale. In one thin, +translucently white hand he held a handkerchief, while with the +other he stroked the delicate mustache he had grown, moving his +fingers slowly. His eyes gazed at them as they entered. + +On seeing his face and meeting his eyes Princess Mary's pace +suddenly slackened, she felt her tears dry up and her sobs ceased. She +suddenly felt guilty and grew timid on catching the expression of +his face and eyes. + +"But in what am I to blame?" she asked herself. And his cold, +stern look replied: "Because you are alive and thinking of the living, +while I..." + +In the deep gaze that seemed to look not outwards but +inwards there was an almost hostile expression as he slowly regarded +his sister and Natasha. + +He kissed his sister, holding her hand in his as was their wont. + +"How are you, Mary? How did you manage to get here?" said he in a +voice as calm and aloof as his look. + +Had he screamed in agony, that scream would not have struck such +horror into Princess Mary's heart as the tone of his voice. + +"And have you brought little Nicholas?" he asked in the same slow, +quiet manner and with an obvious effort to remember. + +"How are you now?" said Princess Mary, herself surprised at what she +was saying. + +"That, my dear, you must ask the doctor," he replied, and again +making an evident effort to be affectionate, he said with his lips +only (his words clearly did not correspond to his thoughts): + +"Merci, chere amie, d'etre venue."* + + +*"Thank you for coming, my dear." + + +Princess Mary pressed his hand. The pressure made him wince just +perceptibly. He was silent, and she did not know what to say. She +now understood what had happened to him two days before. In his words, +his tone, and especially in that calm, almost antagonistic look +could be felt an estrangement from everything belonging to this world, +terrible in one who is alive. Evidently only with an effort did he +understand anything living; but it was obvious that he failed to +understand, not because he lacked the power to do so but because he +understood something else--something the living did not and could +not understand--and which wholly occupied his mind. + +"There, you see how strangely fate has brought us together," said +he, breaking the silence and pointing to Natasha. "She looks after +me all the time." + +Princess Mary heard him and did not understand how he could say such +a thing. He, the sensitive, tender Prince Andrew, how could he say +that, before her whom he loved and who loved him? Had he expected to +live he could not have said those words in that offensively cold tone. +If he had not known that he was dying, how could he have failed to +pity her and how could he speak like that in her presence? The only +explanation was that he was indifferent, because something else, +much more important, had been revealed to him. + +The conversation was cold and disconnected and continually broke +off. + +"Mary came by way of Ryazan," said Natasha. + +Prince Andrew did not notice that she called his sister Mary, and +only after calling her so in his presence did Natasha notice it +herself. + +"Really?" he asked. + +"They told her that all Moscow has been burned down, and that..." + +Natasha stopped. It was impossible to talk. It was plain that he was +making an effort to listen, but could not do so. + +"Yes, they say it's burned," he said. "It's a great pity," and he +gazed straight before him, absently stroking his mustache with his +fingers. + +"And so you have met Count Nicholas, Mary?" Prince Andrew suddenly +said, evidently wishing to speak pleasantly to them. "He wrote here +that he took a great liking to you," he went on simply and calmly, +evidently unable to understand all the complex significance his +words had for living people. "If you liked him too, it would be a good +thing for you to get married," he added rather more quickly, as if +pleased at having found words he had long been seeking. + +Princess Mary heard his words but they had no meaning for her, +except as a proof of how far away he now was from everything living. + +"Why talk of me?" she said quietly and glanced at Natasha. + +Natasha, who felt her glance, did not look at her. All three were +again silent. + +"Andrew, would you like..." Princess Mary suddenly said in a +trembling voice, "would you like to see little Nicholas? He is +always talking about you!" + +Prince Andrew smiled just perceptibly and for the first time, but +Princess Mary, who knew his face so well, saw with horror that he +did not smile with pleasure or affection for his son, but with +quiet, gentle irony because he thought she was trying what she +believed to be the last means of arousing him. + +"Yes, I shall be very glad to see him. Is he quite well?" + +When little Nicholas was brought into Prince Andrew's room he looked +at his father with frightened eyes, but did not cry, because no one +else was crying. Prince Andrew kissed him and evidently did not know +what to say to him. + +When Nicholas had been led away, Princess Mary again went up to +her brother, kissed him, and unable to restrain her tears any longer +began to cry. + +He looked at her attentively. + +"Is it about Nicholas?" he asked. + +Princess Mary nodded her head, weeping. + +"Mary, you know the Gosp..." but he broke off. + +"What did you say?" + +"Nothing. You mustn't cry here," he said, looking at her with the +same cold expression. + + +When Princess Mary began to cry, he understood that she was crying +at the thought that little Nicholas would be left without a father. +With a great effort he tried to return to life and to see things +from their point of view. + +"Yes, to them it must seem sad!" he thought. "But how simple it is. + +"The fowls of the air sow not, neither do they reap, yet your Father +feedeth them," he said to himself and wished to say to Princess +Mary; "but no, they will take it their own way, they won't understand! +They can't understand that all those feelings they prize so--all our +feelings, all those ideas that seem so important to us, are +unnecessary. We cannot understand one another," and he remained +silent. + + +Prince Andrew's little son was seven. He could scarcely read, and +knew nothing. After that day he lived through many things, gaining +knowledge, observation, and experience, but had he possessed all the +faculties he afterwards acquired, he could not have had a better or +more profound understanding of the meaning of the scene he had +witnessed between his father, Mary, and Natasha, than he had then. +He understood it completely, and, leaving the room without crying, +went silently up to Natasha who had come out with him and looked shyly +at her with his beautiful, thoughtful eyes, then his uplifted, rosy +upper lip trembled and leaning his head against her he began to cry. + +After that he avoided Dessalles and the countess who caressed him +and either sat alone or came timidly to Princess Mary, or to Natasha +of whom he seemed even fonder than of his aunt, and clung to them +quietly and shyly. + +When Princess Mary had left Prince Andrew she fully understood +what Natasha's face had told her. She did not speak any more to +Natasha of hopes of saving his life. She took turns with her beside +his sofa, and did not cry any more, but prayed continually, turning in +soul to that Eternal and Unfathomable, whose presence above the +dying man was now so evident. + + + + + +CHAPTER XVI + + +Not only did Prince Andrew know he would die, but he felt that he +was dying and was already half dead. He was conscious of an +aloofness from everything earthly and a strange and joyous lightness +of existence. Without haste or agitation he awaited what was coming. +That inexorable, eternal, distant, and unknown the presence of which +he had felt continually all his life--was now near to him and, by +the strange lightness he experienced, almost comprehensible and +palpable... + + +Formerly he had feared the end. He had twice experienced that +terribly tormenting fear of death--the end--but now he no longer +understood that fear. + + He had felt it for the first time when the shell spun like a top +before him, and he looked at the fallow field, the bushes, and the +sky, and knew that he was face to face with death. When he came to +himself after being wounded and the flower of eternal, unfettered love +had instantly unfolded itself in his soul as if freed from the bondage +of life that had restrained it, he no longer feared death and ceased +to think about it. + +During the hours of solitude, suffering, and partial delirium he +spent after he was wounded, the more deeply he penetrated into the new +principle of eternal love revealed to him, the more he unconsciously +detached himself from earthly life. To love everything and everybody +and always to sacrifice oneself for love meant not to love anyone, not +to live this earthly life. And the more imbued he became with that +principle of love, the more he renounced life and the more +completely he destroyed that dreadful barrier which--in the absence of +such love--stands between life and death. When during those first days +he remembered that he would have to die, he said to himself: "Well, +what of it? So much the better!" + +But after the night in Mytishchi when, half delirious, he had seen +her for whom he longed appear before him and, having pressed her +hand to his lips, had shed gentle, happy tears, love for a +particular woman again crept unobserved into his heart and once more +bound him to life. And joyful and agitating thoughts began to occupy +his mind. Recalling the moment at the ambulance station when he had +seen Kuragin, he could not now regain the feeling he then had, but was +tormented by the question whether Kuragin was alive. And he dared +not inquire. + +His illness pursued its normal physical course, but what Natasha +referred to when she said: "This suddenly happened," had occurred +two days before Princess Mary arrived. It was the last spiritual +struggle between life and death, in which death gained the victory. It +was the unexpected realization of the fact that he still valued life +as presented to him in the form of his love for Natasha, and a last, +though ultimately vanquished, attack of terror before the unknown. + +It was evening. As usual after dinner he was slightly feverish, +and his thoughts were preternaturally clear. Sonya was sitting by +the table. He began to doze. Suddenly a feeling of happiness seized +him. + +"Ah, she has come!" thought he. + +And so it was: in Sonya's place sat Natasha who had just come in +noiselessly. + +Since she had begun looking after him, he had always experienced +this physical consciousness of her nearness. She was sitting in an +armchair placed sideways, screening the light of the candle from +him, and was knitting a stocking. She had learned to knit stockings +since Prince Andrew had casually mentioned that no one nursed the sick +so well as old nurses who knit stockings, and that there is +something soothing in the knitting of stockings. The needles clicked +lightly in her slender, rapidly moving hands, and he could clearly see +the thoughtful profile of her drooping face. She moved, and the ball +rolled off her knees. She started, glanced round at him, and screening +the candle with her hand stooped carefully with a supple and exact +movement, picked up the ball, and regained her former position. + +He looked at her without moving and saw that she wanted to draw a +deep breath after stooping, but refrained from doing so and breathed +cautiously. + +At the Troitsa monastery they had spoken of the past, and he had +told her that if he lived he would always thank God for his wound +which had brought them together again, but after that they never spoke +of the future. + +"Can it or can it not be?" he now thought as he looked at her and +listened to the light click of the steel needles. "Can fate have +brought me to her so strangely only for me to die?... Is it possible +that the truth of life has been revealed to me only to show me that +I have spent my life in falsity? I love her more than anything in +the world! But what am I to do if I love her?" he thought, and he +involuntarily groaned, from a habit acquired during his sufferings. + +On hearing that sound Natasha put down the stocking, leaned nearer +to him, and suddenly, noticing his shining eyes, stepped lightly up to +him and bent over him. + +"You are not asleep?" + +"No, I have been looking at you a long time. I felt you come in. +No one else gives me that sense of soft tranquillity that you do... +that light. I want to weep for joy." + +Natasha drew closer to him. Her face shone with rapturous joy. + +"Natasha, I love you too much! More than anything in the world." + +"And I!"--She turned away for an instant. "Why too much?" she asked. + +"Why too much?... Well, what do you, what do you feel in your +soul, your whole soul--shall I live? What do you think?" + +"I am sure of it, sure!" Natasha almost shouted, taking hold of both +his hands with a passionate movement. + +He remained silent awhile. + +"How good it would be!" and taking her hand he kissed it. + +Natasha felt happy and agitated, but at once remembered that this +would not do and that he had to be quiet. + +"But you have not slept," she said, repressing her joy. "Try to +sleep... please!" + +He pressed her hand and released it, and she went back to the candle +and sat down again in her former position. Twice she turned and looked +at him, and her eyes met his beaming at her. She set herself a task on +her stocking and resolved not to turn round till it was finished. + +Soon he really shut his eyes and fell asleep. He did not sleep +long and suddenly awoke with a start and in a cold perspiration. + +As he fell asleep he had still been thinking of the subject that now +always occupied his mind--about life and death, and chiefly about +death. He felt himself nearer to it. + +"Love? What is love?" he thought. + +"Love hinders death. Love is life. All, everything that I +understand, I understand only because I love. Everything is, +everything exists, only because I love. Everything is united by it +alone. Love is God, and to die means that I, a particle of love, shall +return to the general and eternal source." These thoughts seemed to +him comforting. But they were only thoughts. Something was lacking +in them, they were not clear, they were too one-sidedly personal and +brain-spun. And there was the former agitation and obscurity. He +fell asleep. + +He dreamed that he was lying in the room he really was in, but +that he was quite well and unwounded. Many various, indifferent, and +insignificant people appeared before him. He talked to them and +discussed something trivial. They were preparing to go away somewhere. +Prince Andrew dimly realized that all this was trivial and that he had +more important cares, but he continued to speak, surprising them by +empty witticisms. Gradually, unnoticed, all these persons began to +disappear and a single question, that of the closed door, superseded +all else. He rose and went to the door to bolt and lock it. Everything +depended on whether he was, or was not, in time to lock it. He went, +and tried to hurry, but his legs refused to move and he knew he +would not be in time to lock the door though he painfully strained all +his powers. He was seized by an agonizing fear. And that fear was +the fear of death. It stood behind the door. But just when he was +clumsily creeping toward the door, that dreadful something on the +other side was already pressing against it and forcing its way in. +Something not human--death--was breaking in through that door, and had +to be kept out. He seized the door, making a final effort to hold it +back--to lock it was no longer possible--but his efforts were weak and +clumsy and the door, pushed from behind by that terror, opened and +closed again. + +Once again it pushed from outside. His last superhuman efforts +were vain and both halves of the door noiselessly opened. It +entered, and it was death, and Prince Andrew died. + +But at the instant he died, Prince Andrew remembered that he was +asleep, and at the very instant he died, having made an effort, he +awoke. + +"Yes, it was death! I died--and woke up. Yes, death is an +awakening!" And all at once it grew light in his soul and the veil +that had till then concealed the unknown was lifted from his spiritual +vision. He felt as if powers till then confined within him had been +liberated, and that strange lightness did not again leave him. + +When, waking in a cold perspiration, he moved on the divan, +Natasha went up and asked him what was the matter. He did not answer +and looked at her strangely, not understanding. + +That was what had happened to him two days before Princess Mary's +arrival. From that day, as the doctor expressed it, the wasting +fever assumed a malignant character, but what the doctor said did +not interest Natasha, she saw the terrible moral symptoms which to her +were more convincing. + +From that day an awakening from life came to Prince Andrew +together with his awakening from sleep. And compared to the duration +of life it did not seem to him slower than an awakening from sleep +compared to the duration of a dream. + +There was nothing terrible or violent in this comparatively slow +awakening. + +His last days and hours passed in an ordinary and simple way. Both +Princess Mary and Natasha, who did not leave him, felt this. They +did not weep or shudder and during these last days they themselves +felt that they were not attending on him (he was no longer there, he +had left them) but on what reminded them most closely of him--his +body. Both felt this so strongly that the outward and terrible side of +death did not affect them and they did not feel it necessary to foment +their grief. Neither in his presence nor out of it did they weep, +nor did they ever talk to one another about him. They felt that they +could not express in words what they understood. + +They both saw that he was sinking slowly and quietly, deeper and +deeper, away from them, and they both knew that this had to be so +and that it was right. + +He confessed, and received communion: everyone came to take leave of +him. When they brought his son to him, he pressed his lips to the +boy's and turned away, not because he felt it hard and sad (Princess +Mary and Natasha understood that) but simply because he thought it was +all that was required of him, but when they told him to bless the boy, +he did what was demanded and looked round as if asking whether there +was anything else he should do. + +When the last convulsions of the body, which the spirit was leaving, +occurred, Princess Mary and Natasha were present. + +"Is it over?" said Princess Mary when his body had for a few minutes +lain motionless, growing cold before them. Natasha went up, looked +at the dead eyes, and hastened to close them. She closed them but +did not kiss them, but clung to that which reminded her most nearly of +him--his body. + +"Where has he gone? Where is he now?..." + +When the body, washed and dressed, lay in the coffin on a table, +everyone came to take leave of him and they all wept. + +Little Nicholas cried because his heart was rent by painful +perplexity. The countess and Sonya cried from pity for Natasha and +because he was no more. The old count cried because he felt that +before long, he, too, must take the same terrible step. + +Natasha and Princess Mary also wept now, but not because of their +own personal grief; they wept with a reverent and softening emotion +which had taken possession of their souls at the consciousness of +the simple and solemn mystery of death that had been accomplished in +their presence. + + + + + +BOOK THIRTEEN: 1812 + + + + + +CHAPTER I + + +Man's mind cannot grasp the causes of events in their +completeness, but the desire to find those causes is implanted in +man's soul. And without considering the multiplicity and complexity of +the conditions any one of which taken separately may seem to be the +cause, he snatches at the first approximation to a cause that seems to +him intelligible and says: "This is the cause!" In historical events +(where the actions of men are the subject of observation) the first +and most primitive approximation to present itself was the will of the +gods and, after that, the will of those who stood in the most +prominent position--the heroes of history. But we need only +penetrate to the essence of any historic event--which lies in the +activity of the general mass of men who take part in it--to be +convinced that the will of the historic hero does not control the +actions of the mass but is itself continually controlled. It may +seem to be a matter of indifference whether we understand the +meaning of historical events this way or that; yet there is the same +difference between a man who says that the people of the West moved on +the East because Napoleon wished it and a man who says that this +happened because it had to happen, as there is between those who +declared that the earth was stationary and that the planets moved +round it and those who admitted that they did not know what upheld the +earth, but knew there were laws directing its movement and that of the +other planets. There is, and can be, no cause of an historical event +except the one cause of all causes. But there are laws directing +events, and some of these laws are known to us while we are +conscious of others we cannot comprehend. The discovery of these +laws is only possible when we have quite abandoned the +attempt to find the cause in the will of some one man, just as the +discovery of the laws of the motion of the planets was possible only +when men abandoned the conception of the fixity of the earth. + +The historians consider that, next to the battle of Borodino and the +occupation of Moscow by the enemy and its destruction by fire, the +most important episode of the war of 1812 was the movement of the +Russian army from the Ryazana to the Kaluga road and to the Tarutino +camp--the so-called flank march across the Krasnaya Pakhra River. They +ascribe the glory of that achievement of genius to different men and +dispute as to whom the honor is due. Even foreign historians, +including the French, acknowledge the genius of the Russian commanders +when they speak of that flank march. But it is hard to understand +why military writers, and following them others, consider this flank +march to be the profound conception of some one man who saved Russia +and destroyed Napoleon. In the first place it is hard to understand +where the profundity and genius of this movement lay, for not much +mental effort was needed to see that the best position for an army +when it is not being attacked is where there are most provisions; +and even a dull boy of thirteen could have guessed that the best +position for an army after its retreat from Moscow in 1812 was on +the Kaluga road. So it is impossible to understand by what reasoning +the historians reach the conclusion that this maneuver was a +profound one. And it is even more difficult to understand just why +they think that this maneuver was calculated to save Russia and +destroy the French; for this flank march, had it been preceded, +accompanied, or followed by other circumstances, might have proved +ruinous to the Russians and salutary for the French. If the position +of the Russian army really began to improve from the time of that +march, it does not at all follow that the march was the cause of it. + +That flank march might not only have failed to give any advantage to +the Russian army, but might in other circumstances have led to its +destruction. What would have happened had Moscow not burned down? If +Murat had not lost sight of the Russians? If Napoleon had not remained +inactive? If the Russian army at Krasnaya Pakhra had given battle as +Bennigsen and Barclay advised? What would have happened had the French +attacked the Russians while they were marching beyond the Pakhra? What +would have happened if on approaching Tarutino, Napoleon had +attacked the Russians with but a tenth of the energy he had shown when +he attacked them at Smolensk? What would have happened had the +French moved on Petersburg?... In any of these eventualities the flank +march that brought salvation might have proved disastrous. + +The third and most incomprehensible thing is that people studying +history deliberately avoid seeing that this flank march cannot be +attributed to any one man, that no one ever foresaw it, and that in +reality, like the retreat from Fili, it did not suggest itself to +anyone in its entirety, but resulted--moment by moment, step by +step, event by event--from an endless number of most diverse +circumstances and was only seen in its entirety when it had been +accomplished and belonged to the past. + +At the council at Fili the prevailing thought in the minds of the +Russian commanders was the one naturally suggesting itself, namely, +a direct retreat by the Nizhni road. In proof of this there is the +fact that the majority of the council voted for such a retreat, and +above all there is the well-known conversation after the council, +between the commander in chief and Lanskoy, who was in charge of the +commissariat department. Lanskoy informed the commander in chief +that the army supplies were for the most part stored along the Oka +in the Tula and Ryazan provinces, and that if they retreated on Nizhni +the army would be separated from its supplies by the broad river +Oka, which cannot be crossed early in winter. This was the first +indication of the necessity of deviating from what had previously +seemed the most natural course--a direct retreat on Nizhni-Novgorod. +The army turned more to the south, along the Ryazan road and nearer to +its supplies. Subsequently the inactivity of the French (who even +lost sight of the Russian army), concern for the safety of the arsenal +at Tula, and especially the advantages of drawing nearer to its +supplies caused the army to turn still further south to the Tula road. +Having crossed over, by a forced march, to the Tula road beyond the +Pakhra, the Russian commanders intended to remain at Podolsk and had +no thought of the Tarutino position; but innumerable circumstances and +the reappearance of French troops who had for a time lost touch with +the Russians, and projects of giving battle, and above all the +abundance of provisions in Kaluga province, obliged our army to turn +still more to the south and to cross from the Tula to the Kaluga +road and go to Tarutino, which was between the roads along which those +supplies lay. Just as it is impossible to say when it was decided to +abandon Moscow, so it is impossible to say precisely when, or by whom, +it was decided to move to Tarutino. Only when the army had got +there, as the result of innumerable and varying forces, did people +begin to assure themselves that they had desired this movement and +long ago foreseen its result. + + + + + +CHAPTER II + + +The famous flank movement merely consisted in this: after the +advance of the French had ceased, the Russian army, which had been +continually retreating straight back from the invaders, deviated +from that direct course and, not finding itself pursued, was naturally +drawn toward the district where supplies were abundant. + +If instead of imagining to ourselves commanders of genius leading +the Russian army, we picture that army without any leaders, it could +not have done anything but make a return movement toward Moscow, +describing an arc in the direction where most provisions were to be +found and where the country was richest. + +That movement from the Nizhni to the Ryazan, Tula, and Kaluga +roads was so natural that even the Russian marauders moved in that +direction, and demands were sent from Petersburg for Kutuzov to take +his army that way. At Tarutino Kutuzov received what was almost a +reprimand from the Emperor for having moved his army along the +Ryazan road, and the Emperor's letter indicated to him the very +position he had already occupied near Kaluga. + +Having rolled like a ball in the direction of the impetus given by +the whole campaign and by the battle of Borodino, the Russian army- +when the strength of that impetus was exhausted and no fresh push +was received--assumed the position natural to it. + +Kutuzov's merit lay, not in any strategic maneuver of genius, as +it is called, but in the fact that he alone understood the +significance of what had happened. He alone then understood the +meaning of the French army's inactivity, he alone continued to +assert that the battle of Borodino had been a victory, he alone--who +as commander in chief might have been expected to be eager to +attack--employed his whole strength to restrain the Russian army +from useless engagements. + +The beast wounded at Borodino was lying where the fleeing hunter had +left him; but whether he was still alive, whether he was strong and +merely lying low, the hunter did not know. Suddenly the beast was +heard to moan. + +The moan of that wounded beast (the French army) which betrayed +its calamitous condition was the sending of Lauriston to Kutuzov's +camp with overtures for peace. + +Napoleon, with his usual assurance that whatever entered his head +was right, wrote to Kutuzov the first words that occurred to him, +though they were meaningless. + + +MONSIEUR LE PRINCE KOUTOUZOV: I am sending one of my +adjutants-general to discuss several interesting questions with you. I +beg your Highness to credit what he says to you, especially when he +expresses the sentiment of esteem and special regard I have long +entertained for your person. This letter having no other object, I +pray God, monsieur le Prince Koutouzov, to keep you in His holy and +gracious protection! + +NAPOLEON + +MOSCOW, OCTOBER 30, 1812 + + +Kutuzov replied: "I should be cursed by posterity were I looked on +as the initiator of a settlement of any sort. Such is the present +spirit of my nation." But he continued to exert all his powers to +restrain his troops from attacking. + +During the month that the French troops were pillaging in Moscow and +the Russian troops were quietly encamped at Tarutino, a change had +taken place in the relative strength of the two armies--both in spirit +and in number--as a result of which the superiority had passed to +the Russian side. Though the condition and numbers of the French +army were unknown to the Russians, as soon as that change occurred the +need of attacking at once showed itself by countless signs. These +signs were: Lauriston's mission; the abundance of provisions at +Tarutino; the reports coming in from all sides of the inactivity and +disorder of the French; the flow of recruits to our regiments; the +fine weather; the long rest the Russian soldiers had enjoyed, and +the impatience to do what they had been assembled for, which usually +shows itself in an army that has been resting; curiosity as to what +the French army, so long lost sight of, was doing; the boldness with +which our outposts now scouted close up to the French stationed at +Tarutino; the news of easy successes gained by peasants and +guerrilla troops over the French, the envy aroused by this; the desire +for revenge that lay in the heart of every Russian as long as the +French were in Moscow, and (above all) a dim consciousness in every +soldier's mind that the relative strength of the armies had changed +and that the advantage was now on our side. There was a substantial +change in the relative strength, and an advance had become inevitable. +And at once, as a clock begins to strike and chime as soon as the +minute hand has completed a full circle, this change was shown by an +increased activity, whirring, and chiming in the higher spheres. + + + + + +CHAPTER III + + +The Russian army was commanded by Kutuzov and his staff, and also by +the Emperor from Petersburg. Before the news of the abandonment of +Moscow had been received in Petersburg, a detailed plan of the whole +campaign had been drawn up and sent to Kutuzov for his guidance. +Though this plan had been drawn up on the supposition that Moscow +was still in our hands, it was approved by the staff and accepted as a +basis for action. Kutuzov only replied that movements arranged from +a distance were always difficult to execute. So fresh instructions +were sent for the solution of difficulties that might be +encountered, as well as fresh people who were to watch Kutuzov's +actions and report upon them. + +Besides this, the whole staff of the Russian army was now +reorganized. The posts left vacant by Bagration, who had been +killed, and by Barclay, who had gone away in dudgeon, had to be +filled. Very serious consideration was given to the question whether +it would be better to put A in B's place and B in D's, or on the +contrary to put D in A's place, and so on--as if anything more than +A's or B's satisfaction depended on this. + +As a result of the hostility between Kutuzov and Bennigsen, his +Chief of Staff, the presence of confidential representatives of the +Emperor, and these transfers, a more than usually complicated play +of parties was going on among the staff of the army. A was undermining +B, D was undermining C, and so on in all possible combinations and +permutations. In all these plottings the subject of intrigue was +generally the conduct of the war, which all these men believed they +were directing; but this affair of the war went on independently of +them, as it had to go: that is, never in the way people devised, but +flowing always from the essential attitude of the masses. Only in +the highest spheres did all these schemes, crossings, and +interminglings appear to be a true reflection of what had to happen. + + +Prince Michael Ilarionovich! (wrote the Emperor on the second of +October in a letter that reached Kutuzov after the battle at Tarutino) +Since September 2 Moscow has been in the hands of the enemy. Your last +reports were written on the twentieth, and during all this time not +only has no action been taken against the enemy or for the relief of +the ancient capital, but according to your last report you have even +retreated farther. Serpukhov is already occupied by an enemy +detachment and Tula with its famous arsenal so indispensable to the +army, is in danger. From General Wintzingerode's reports, I see that +an enemy corps of ten thousand men is moving on the Petersburg road. +Another corps of several thousand men is moving on Dmitrov. A third +has advanced along the Vladimir road, and a fourth, rather +considerable detachment is stationed between Ruza and Mozhaysk. +Napoleon himself was in Moscow as late as the twenty-fifth. In view of +all this information, when the enemy has scattered his forces in large +detachments, and with Napoleon and his Guards in Moscow, is it +possible that the enemy's forces confronting you are so considerable +as not to allow of your taking the offensive? On the contrary, he is +probably pursuing you with detachments, or at most with an army +corps much weaker than the army entrusted to you. It would seem +that, availing yourself of these circumstances, you might +advantageously attack a weaker one and annihilate him, or at least +oblige him to retreat, retaining in our hands an important part of the +provinces now occupied by the enemy, and thereby averting danger +from Tula and other towns in the interior. You will be responsible +if the enemy is able to direct a force of any size against +Petersburg to threaten this capital in which it has not been +possible to retain many troops; for with the army entrusted to you, +and acting with resolution and energy, you have ample means to avert +this fresh calamity. Remember that you have still to answer to our +offended country for the loss of Moscow. You have experienced my +readiness to reward you. That readiness will not weaken in me, but I +and Russia have a right to expect from you all the zeal, firmness, and +success which your intellect, military talent, and the courage of +the troops you command justify us in expecting. + + +But by the time this letter, which proved that the real relation +of the forces had already made itself felt in Petersburg, was +dispatched, Kutuzov had found himself unable any longer to restrain +the army he commanded from attacking and a battle had taken place. + +On the second of October a Cossack, Shapovalov, who was out +scouting, killed one hare and wounded another. Following the wounded +hare he made his way far into the forest and came upon the left +flank of Murat's army, encamped there without any precautions. The +Cossack laughingly told his comrades how he had almost fallen into the +hands of the French. A cornet, hearing the story, informed his +commander. + +The Cossack was sent for and questioned. The Cossack officers wished +to take advantage of this chance to capture some horses, but one of +the superior officers, who was acquainted with the higher authorities, +reported the incident to a general on the staff. The state of +things on the staff had of late been exceedingly strained. Ermolov had +been to see Bennigsen a few days previously and had entreated him to +use his influence with the commander in chief to induce him to take +the offensive. + +"If I did not know you I should think you did not want what you +are asking for. I need only advise anything and his Highness is sure +to do the opposite," replied Bennigsen. + +The Cossack's report, confirmed by horse patrols who were sent +out, was the final proof that events had matured. The tightly coiled +spring was released, the clock began to whirr and the chimes to +play. Despite all his supposed power, his intellect, his experience, +and his knowledge of men, Kutuzov--having taken into consideration the +Cossack's report, a note from Bennigsen who sent personal reports to +the Emperor, the wishes he supposed the Emperor to hold, and the +fact that all the generals expressed the same wish--could no longer +check the inevitable movement, and gave the order to do what he +regarded as useless and harmful--gave his approval, that is, to the +accomplished fact. + + + + + +CHAPTER IV + + +Bennigsen's note and the Cossack's information that the left flank +of the French was unguarded were merely final indications that it +was necessary to order an attack, and it was fixed for the fifth of +October. + +On the morning of the fourth of October Kutuzov signed the +dispositions. Toll read them to Ermolov, asking him to attend to the +further arrangements. + +"All right--all right. I haven't time just now," replied Ermolov, +and left the hut. + +The dispositions drawn up by Toll were very good. As in the +Austerlitz dispositions, it was written--though not in German this +time: + +"The First Column will march here and here," "the Second Column will +march there and there," and so on; and on paper, all these columns +arrived at their places at the appointed time and destroyed the enemy. +Everything had been admirably thought out as is usual in dispositions, +and as is always the case, not a single column reached its place at +the appointed time. + +When the necessary number of copies of the dispositions had been +prepared, an officer was summoned and sent to deliver them to +Ermolov to deal with. A young officer of the Horse Guards, Kutuzov's +orderly, pleased at the importance of the mission entrusted to him, +went to Ermolov's quarters. + +"Gone away," said Ermolov's orderly. + +The officer of the Horse Guards went to a general with whom +Ermolov was often to be found. + +"No, and the general's out too." + +The officer, mounting his horse, rode off to someone else. + +"No, he's gone out." + +"If only they don't make me responsible for this delay! What a +nuisance it is!" thought the officer, and he rode round the whole +camp. One man said he had seen Ermolov ride past with some other +generals, others said he must have returned home. The officer searched +till six o'clock in the evening without even stopping to eat. +Ermolov was nowhere to be found and no one knew where he was. The +officer snatched a little food at a comrade's, and rode again to the +vanguard to find Miloradovich. Miloradovich too was away, but here +he was told that he had gone to a ball at General Kikin's and that +Ermolov was probably there too. + +"But where is it?" + +"Why, there, over at Echkino," said a Cossack officer, pointing to a +country house in the far distance. + +"What, outside our line?" + +"They've put two regiments as outposts, and they're having such a +spree there, it's awful! Two bands and three sets of singers!" + +The officer rode out beyond our lines to Echkino. While still at a +distance he heard as he rode the merry sounds of a soldier's dance +song proceeding from the house. + +"In the meadows... in the meadows!" he heard, accompanied by +whistling and the sound of a torban, drowned every now and then by +shouts. These sounds made his spirits rise, but at the same time he +was afraid that he would be blamed for not having executed sooner +the important order entrusted to him. It was already past eight +o'clock. He dismounted and went up into the porch of a large country +house which had remained intact between the Russian and French forces. +In the refreshment room and the hall, footmen were bustling about with +wine and viands. Groups of singers stood outside the windows. The +officer was admitted and immediately saw all the chief generals of the +army together, and among them Ermolov's big imposing figure. They +all had their coats unbuttoned and were standing in a semicircle +with flushed and animated faces, laughing loudly. In the middle of the +room a short handsome general with a red face was dancing the trepak +with much spirit and agility. + +"Ha, ha, ha! Bravo, Nicholas Ivanych! Ha, ha, ha!" + +The officer felt that by arriving with important orders at such a +moment he was doubly to blame, and he would have preferred to wait; +but one of the generals espied him and, hearing what he had come +about, informed Ermolov. + +Ermolov came forward with a frown on his face and, hearing what +the officer had to say, took the papers from him without a word. + + +"You think he went off just by chance?" said a comrade, who was on +the staff that evening, to the officer of the Horse Guards, +referring to Ermolov. "It was a trick. It was done on purpose to get +Konovnitsyn into trouble. You'll see what a mess there'll be +tomorrow." + + + + + +CHAPTER V + + +Next day the decrepit Kutuzov, having given orders to be called +early, said his prayers, dressed, and, with an unpleasant +consciousness of having to direct a battle he did not approve of, +got into his caleche and drove from Letashovka (a village three and +a half miles from Tarutino) to the place where the attacking columns +were to meet. He sat in the caleche, dozing and waking up by turns, +and listening for any sound of firing on the right as an indication +that the action had begun. But all was still quiet. A damp dull autumn +morning was just dawning. On approaching Tarutino Kutuzov noticed +cavalrymen leading their horses to water across the road along which +he was driving. Kutuzov looked at them searchingly, stopped his +carriage, and inquired what regiment they belonged to. They belonged +to a column that should have been far in front and in ambush long +before then. "It may be a mistake," thought the old commander in +chief. But a little further on he saw infantry regiments with their +arms piled and the soldiers, only partly dressed, eating their rye +porridge and carrying fuel. He sent for an officer. The officer +reported that no order to advance had been received. + +"How! Not rec..." Kutuzov began, but checked himself immediately and +sent for a senior officer. Getting out of his caleche, he waited +with drooping head and breathing heavily, pacing silently up and down. +When Eykhen, the officer of the general staff whom he had summoned, +appeared, Kutuzov went purple in the face, not because that officer +was to blame for the mistake, but because he was an object of +sufficient importance for him to vent his wrath on. Trembling and +panting the old man fell into that state of fury in which he sometimes +used to roll on the ground, and he fell upon Eykhen, threatening him +with his hands, shouting and loading him with gross abuse. Another +man, Captain Brozin, who happened to turn up and who was not at all to +blame, suffered the same fate. + +"What sort of another blackguard are you? I'll have you shot! +Scoundrels!" yelled Kutuzov in a hoarse voice, waving his arms and +reeling. + +He was suffering physically. He, the commander in chief, a Serene +Highness who everybody said possessed powers such as no man had ever +had in Russia, to be placed in this position--made the laughingstock +of the whole army! "I needn't have been in such a hurry to pray +about today, or have kept awake thinking everything over all night," +thought he to himself. "When I was a chit of an officer no one would +have dared to mock me so... and now!" He was in a state of physical +suffering as if from corporal punishment, and could not avoid +expressing it by cries of anger and distress. But his strength soon +began to fail him, and looking about him, conscious of having said +much that was amiss, he again got into his caleche and drove back in +silence. + +His wrath, once expended, did not return, and blinking feebly he +listened to excuses and self-justifications (Ermolov did not come to +see him till the next day) and to the insistence of Bennigsen, +Konovnitsyn, and Toll that the movement that had miscarried should +be executed next day. And once more Kutuzov had to consent. + + + + + +CHAPTER VI + + +Next day the troops assembled in their appointed places in the +evening and advanced during the night. It was an autumn night with +dark purple clouds, but no rain. The ground was damp but not muddy, +and the troops advanced noiselessly, only occasionally a jingling of +the artillery could be faintly heard. The men were forbidden to talk +out loud, to smoke their pipes, or to strike a light, and they tried +to prevent their horses neighing. The secrecy of the undertaking +heightened its charm and they marched gaily. Some columns, +supposing they had reached their destination, halted, piled arms, and +settled down on the cold ground, but the majority marched all night +and arrived at places where they evidently should not have been. + +Only Count Orlov-Denisov with his Cossacks (the least important +detachment of all) got to his appointed place at the right time. +This detachment halted at the outskirts of a forest, on the path +leading from the village of Stromilova to Dmitrovsk. + +Toward dawn, Count Orlov-Denisov, who had dozed off, was awakened by +a deserter from the French army being brought to him. This was a +Polish sergeant of Poniatowski's corps, who explained in Polish that +he had come over because he had been slighted in the service: that +he ought long ago to have been made an officer, that he was braver +than any of them, and so he had left them and wished to pay them +out. He said that Murat was spending the night less than a mile from +where they were, and that if they would let him have a convoy of a +hundred men he would capture him alive. Count Orlov-Denisov +consulted his fellow officers. + +The offer was too tempting to be refused. Everyone volunteered to go +and everybody advised making the attempt. After much disputing and +arguing, Major-General Grekov with two Cossack regiments decided to go +with the Polish sergeant. + +"Now, remember," said Count Orlov-Denisov to the sergeant at +parting, "if you have been lying I'll have you hanged like a dog; +but if it's true you shall have a hundred gold pieces!" + +Without replying, the sergeant, with a resolute air, mounted and +rode away with Grekov whose men had quickly assembled. They +disappeared into the forest, and Count Orlov-Denisov, having seen +Grekov off, returned, shivering from the freshness of the early dawn +and excited by what he had undertaken on his own responsibility, and +began looking at the enemy camp, now just visible in the deceptive +light of dawn and the dying campfires. Our columns ought to have begun +to appear on an open declivity to his right. He looked in that +direction, but though the columns would have been visible quite far +off, they were not to be seen. It seemed to the count that things were +beginning to stir in the French camp, and his keen-sighted adjutant +confirmed this. + +"Oh, it is really too late," said Count Orlov, looking at the camp. + +As often happens when someone we have trusted is no longer before +our eyes, it suddenly seemed quite clear and obvious to him that the +sergeant was an impostor, that he had lied, and that the whole Russian +attack would be ruined by the absence of those two regiments, which he +would lead away heaven only knew where. How could one capture a +commander in chief from among such a mass of troops! + +"I am sure that rascal was lying," said the count. + +"They can still be called back," said one of his suite, who like +Count Orlov felt distrustful of the adventure when he looked at the +enemy's camp. + +"Eh? Really... what do you think? Should we let them go on or not?" + +"Will you have them fetched back?" + +"Fetch them back, fetch them back!" said Count Orlov with sudden +determination, looking at his watch. "It will be too late. It is quite +light." + +And the adjutant galloped through the forest after Grekov. When +Grekov returned, Count Orlov-Denisov, excited both by the abandoned +attempt and by vainly awaiting the infantry columns that still did not +appear, as well as by the proximity of the enemy, resolved to advance. +All his men felt the same excitement. + +"Mount!" he commanded in a whisper. The men took their places and +crossed themselves.... "Forward, with God's aid!" + +"Hurrah-ah-ah!" reverberated in the forest, and the Cossack +companies, trailing their lances and advancing one after another as if +poured out of a sack, dashed gaily across the brook toward the camp. + +One desperate, frightened yell from the first French soldier who saw +the Cossacks, and all who were in the camp, undressed and only just +waking up, ran off in all directions, abandoning cannons, muskets, and +horses. + +Had the Cossacks pursued the French, without heeding what was behind +and around them, they would have captured Murat and everything +there. That was what the officers desired. But it was impossible to +make the Cossacks budge when once they had got booty and prisoners. +None of them listened to orders. Fifteen hundred prisoners and +thirty-eight guns were taken on the spot, besides standards and +(what seemed most important to the Cossacks) horses, saddles, +horsecloths, and the like. All this had to be dealt with, the +prisoners and guns secured, the booty divided--not without some +shouting and even a little themselves--and it was on this that the +Cossacks all busied themselves. + +The French, not being farther pursued, began to recover +themselves: they formed into detachments and began firing. +Orlov-Denisov, still waiting for the other columns to arrive, advanced +no further. + +Meantime, according to the dispositions which said that "the First +Column will march" and so on, the infantry of the belated columns, +commanded by Bennigsen and directed by Toll, had started in due +order and, as always happens, had got somewhere, but not to their +appointed places. As always happens the men, starting cheerfully, +began to halt; murmurs were heard, there was a sense of confusion, and +finally a backward movement. Adjutants and generals galloped about, +shouted, grew angry, quarreled, said they had come quite wrong and +were late, gave vent to a little abuse, and at last gave it all up and +went forward, simply to get somewhere. "We shall get somewhere or +other!" And they did indeed get somewhere, though not to their right +places; a few eventually even got to their right place, but too late +to be of any use and only in time to be fired at. Toll, who in this +battle played the part of Weyrother at Austerlitz, galloped +assiduously from place to place, finding everything upside down +everywhere. Thus he stumbled on Bagovut's corps in a wood when it +was already broad daylight, though the corps should long before have +joined Orlov-Denisov. Excited and vexed by the failure and supposing +that someone must be responsible for it, Toll galloped up to the +commander of the corps and began upbraiding him severely, saying +that he ought to be shot. General Bagovut, a fighting old soldier of +placid temperament, being also upset by all the delay, confusion, +and cross-purposes, fell into a rage to everybody's surprise and quite +contrary to his usual character and said disagreeable things to Toll. + +"I prefer not to take lessons from anyone, but I can die with my men +as well as anybody," he said, and advanced with a single division. + +Coming out onto a field under the enemy's fire, this brave general +went straight ahead, leading his men under fire, without considering +in his agitation whether going into action now, with a single +division, would be of any use or no. Danger, cannon balls, and bullets +were just what he needed in his angry mood. One of the first bullets +killed him, and other bullets killed many of his men. And his division +remained under fire for some time quite uselessly. + + + + + +CHAPTER VII + + +Meanwhile another column was to have attacked the French from the +front, but Kutuzov accompanied that column. He well knew that +nothing but confusion would come of this battle undertaken against his +will, and as far as was in his power held the troops back. He did +not advance. + +He rode silently on his small gray horse, indolently answering +suggestions that they should attack. + +"The word attack is always on your tongue, but you don't see that we +are unable to execute complicated maneuvers," said he to +Miloradovich who asked permission to advance. + +"We couldn't take Murat prisoner this morning or get to the place in +time, and nothing can be done now!" he replied to someone else. + +When Kutuzov was informed that at the French rear--where according +to the reports of the Cossacks there had previously been nobody--there +were now two battalions of Poles, he gave a sidelong glance at Ermolov +who was behind him and to whom he had not spoken since the previous +day. + +"You see! They are asking to attack and making plans of all kinds, +but as soon as one gets to business nothing is ready, and the enemy, +forewarned, takes measures accordingly." + +Ermolov screwed up his eyes and smiled faintly on hearing these +words. He understood that for him the storm had blown over, and that +Kutuzov would content himself with that hint. + +"He's having a little fun at my expense," said Ermolov softly, +nudging with his knee Raevski who was at his side. + +Soon after this, Ermolov moved up to Kutuzov and respectfully +remarked: + +"It is not too late yet, your Highness--the enemy has not gone away- +if you were to order an attack! If not, the Guards will not so much as +see a little smoke." + +Kutuzov did not reply, but when they reported to him that Murat's +troops were in retreat he ordered an advance, though at every +hundred paces he halted for three quarters of an hour. + +The whole battle consisted in what Orlov-Denisov's Cossacks had +done: the rest of the army merely lost some hundreds of men uselessly. + +In consequence of this battle Kutuzov received a diamond decoration, +and Bennigsen some diamonds and a hundred thousand rubles, others also +received pleasant recognitions corresponding to their various +grades, and following the battle fresh changes were made in the staff. + +"That's how everything is done with us, all topsy-turvy!" said the +Russian officers and generals after the Tarutino battle, letting it be +understood that some fool there is doing things all wrong but that +we ourselves should not have done so, just as people speak today. +But people who talk like that either do not know what they are talking +about or deliberately deceive themselves. No battle--Tarutino, +Borodino, or Austerlitz--takes place as those who planned it +anticipated. That is an essential condition. + +A countless number of free forces (for nowhere is man freer than +during a battle, where it is a question of life and death) influence +the course taken by the fight, and that course never can be known in +advance and never coincides with the direction of any one force. + +If many simultaneously and variously directed forces act on a +given body, the direction of its motion cannot coincide with any one +of those forces, but will always be a mean--what in mechanics is +represented by the diagonal of a parallelogram of forces. + +If in the descriptions given by historians, especially French +ones, we find their wars and battles carried out in accordance with +previously formed plans, the only conclusion to be drawn is that those +descriptions are false. + +The battle of Tarutino obviously did not attain the aim Toll had +in view--to lead the troops into action in the order prescribed by the +dispositions; nor that which Count Orlov-Denisov may have had in view- +to take Murat prisoner; nor the result of immediately destroying the +whole corps, which Bennigsen and others may have had in view; nor +the aim of the officer who wished to go into action to distinguish +himself; nor that of the Cossack who wanted more booty than he got, +and so on. But if the aim of the battle was what actually resulted and +what all the Russians of that day desired--to drive the French out +of Russia and destroy their army--it is quite clear that the battle of +Tarutino, just because of its incongruities, was exactly what was +wanted at that stage of the campaign. It would be difficult and even +impossible to imagine any result more opportune than the actual +outcome of this battle. With a minimum of effort and insignificant +losses, despite the greatest confusion, the most important results +of the whole campaign were attained: the transition from retreat to +advance, an exposure of the weakness of the French, and the +administration of that shock which Napoleon's army had only awaited to +begin its flight. + + + + + +CHAPTER VIII + + +Napoleon enters Moscow after the brilliant victory de la Moskowa; +there can be no doubt about the victory for the battlefield remains in +the hands of the French. The Russians retreat and abandon their +ancient capital. Moscow, abounding in provisions, arms, munitions, and +incalculable wealth, is in Napoleon's hands. The Russian army, only +half the strength of the French, does not make a single attempt to +attack for a whole month. Napoleon's position is most brilliant. He +can either fall on the Russian army with double its strength and +destroy it; negotiate an advantageous peace, or in case of a refusal +make a menacing move on Petersburg, or even, in the case of a reverse, +return to Smolensk or Vilna; or remain in Moscow; in short, no special +genius would seem to be required to retain the brilliant position +the French held at that time. For that, only very simple and easy +steps were necessary: not to allow the troops to loot, to prepare +winter clothing--of which there was sufficient in Moscow for the whole +army--and methodically to collect the provisions, of which +(according to the French historians) there were enough in Moscow to +supply the whole army for six months. Yet Napoleon, that greatest of +all geniuses, who the historians declare had control of the army, took +none of these steps. + +He not merely did nothing of the kind, but on the contrary he used +his power to select the most foolish and ruinous of all the courses +open to him. Of all that Napoleon might have done: wintering in +Moscow, advancing on Petersburg or on Nizhni-Novgorod, or retiring +by a more northerly or more southerly route (say by the road Kutuzov +afterwards took), nothing more stupid or disastrous can be imagined +than what he actually did. He remained in Moscow till October, letting +the troops plunder the city; then, hesitating whether to leave a +garrison behind him, he quitted Moscow, approached Kutuzov without +joining battle, turned to the right and reached Malo-Yaroslavets, +again without attempting to break through and take the road Kutuzov +took, but retiring instead to Mozhaysk along the devastated Smolensk +road. Nothing more stupid than that could have been devised, or more +disastrous for the army, as the sequel showed. Had Napoleon's aim been +to destroy his army, the most skillful strategist could hardly have +devised any series of actions that would so completely have +accomplished that purpose, independently of anything the Russian +army might do. + + +Napoleon, the man of genius, did this! But to say that he +destroyed his army because he wished to, or because he was very +stupid, would be as unjust as to say that he had brought his troops to +Moscow because he wished to and because he was very clever and a +genius. + +In both cases his personal activity, having no more force than the +personal activity of any soldier, merely coincided with the laws +that guided the event. + +The historians quite falsely represent Napoleon's faculties as +having weakened in Moscow, and do so only because the results did +not justify his actions. He employed all his ability and strength to +do the best he could for himself and his army, as he had done +previously and as he did subsequently in 1813. His activity at that +time was no less astounding than it was in Egypt, in Italy, in +Austria, and in Prussia. We do not know for certain in how far his +genius was genuine in Egypt--where forty centuries looked down upon +his grandeur--for his great exploits there are all told us by +Frenchmen. We cannot accurately estimate his genius in Austria or +Prussia, for we have to draw our information from French or German +sources, and the incomprehensible surrender of whole corps without +fighting and of fortresses without a siege must incline Germans to +recognize his genius as the only explanation of the war carried on +in Germany. But we, thank God, have no need to recognize his genius in +order to hide our shame. We have paid for the right to look at the +matter plainly and simply, and we will not abandon that right. + +His activity in Moscow was as amazing and as full of genius as +elsewhere. Order after order order and plan after plan were issued +by him from the time he entered Moscow till the time he left it. The +absence of citizens and of a deputation, and even the burning of +Moscow, did not disconcert him. He did not lose sight either of the +welfare of his army or of the doings of the enemy, or of the welfare +of the people of Russia, or of the direction of affairs in Paris, or +of diplomatic considerations concerning the terms of the anticipated +peace. + + + + + +CHAPTER IX + + +With regard to military matters, Napoleon immediately on his entry +into Moscow gave General Sabastiani strict orders to observe the +movements of the Russian army, sent army corps out along the different +roads, and charged Murat to find Kutuzov. Then he gave careful +directions about the fortification of the Kremlin, and drew up a +brilliant plan for a future campaign over the whole map of Russia. + +With regard to diplomatic questions, Napoleon summoned Captain +Yakovlev, who had been robbed and was in rags and did not know how +to get out of Moscow, minutely explained to him his whole policy and +his magnanimity, and having written a letter to the Emperor +Alexander in which he considered it his duty to inform his Friend +and Brother that Rostopchin had managed affairs badly in Moscow, he +dispatched Yakovlev to Petersburg. + +Having similarly explained his views and his magnanimity to +Tutolmin, he dispatched that old man also to Petersburg to negotiate. + +With regard to legal matters, immediately after the fires he gave +orders to find and execute the incendiaries. And the scoundrel +Rostopchin was punished by an order to burn down his houses. + +With regard to administrative matters, Moscow was granted a +constitution. A municipality was established and the following +announcement issued: + + +INHABITANTS OF MOSCOW! + +Your misfortunes are cruel, but His Majesty the Emperor and King +desires to arrest their course. Terrible examples have taught you +how he punishes disobedience and crime. Strict measures have been +taken to put an end to disorder and to re-establish public security. A +paternal administration, chosen from among yourselves, will form +your municipality or city government. It will take care of you, of +your needs, and of your welfare. Its members will be distinguished +by a red ribbon worn across the shoulder, and the mayor of the city +will wear a white belt as well. But when not on duty they will only +wear a red ribbon round the left arm. + +The city police is established on its former footing, and better +order already prevails in consequence of its activity. The +government has appointed two commissaries general, or chiefs of +police, and twenty commissaries or captains of wards have been +appointed to the different wards of the city. You will recognize +them by the white ribbon they will wear on the left arm. Several +churches of different denominations are open, and divine service is +performed in them unhindered. Your fellow citizens are returning every +day to their homes. and orders have been given that they should find +in them the help and protection due to their misfortunes. These are +the measures the government has adopted to re-establish order and +relieve your condition. But to achieve this aim it is necessary that +you should add your efforts and should, if possible, forget the +misfortunes you have suffered, should entertain the hope of a less +cruel fate, should be certain that inevitable and ignominious death +awaits those who make any attempt on your persons or on what remains +of your property, and finally that you should not doubt that these +will be safeguarded, since such is the will of the greatest and most +just of monarchs. Soldiers and citizens, of whatever nation you may +be, re-establish public confidence, the source of the welfare of a +state, live like brothers, render mutual aid and protection one to +another, unite to defeat the intentions of the evil-minded, obey the +military and civil authorities, and your tears will soon cease to +flow! + + +With regard to supplies for the army, Napoleon decreed that all +the troops in turn should enter Moscow a la maraude* to obtain +provisions for themselves, so that the army might have its future +provided for. + + +*As looters. + + +With regard to religion, Napoleon ordered the priests to be +brought back and services to be again performed in the churches. + +With regard to commerce and to provisioning the army, the +following was placarded everywhere: + + +PROCLAMATION! + +You, peaceful inhabitants of Moscow, artisans and workmen whom +misfortune has driven from the city, and you scattered tillers of +the soil, still kept out in the fields by groundless fear, listen! +Tranquillity is returning to this capital and order is being +restored in it. Your fellow countrymen are emerging boldly from +their hiding places on finding that they are respected. Any violence +to them or to their property is promptly punished. His Majesty the +Emperor and King protects them, and considers no one among you his +enemy except those who disobey his orders. He desires to end your +misfortunes and restore you to your homes and families. Respond, +therefore, to his benevolent intentions and come to us without fear. +Inhabitants, return with confidence to your abodes! You will soon find +means of satisfying your needs. Craftsmen and industrious artisans, +return to your work, your houses, your shops, where the protection +of guards awaits you! You shall receive proper pay for your work. +And lastly you too, peasants, come from the forests where you are +hiding in terror, return to your huts without fear, in full +assurance that you will find protection! Markets are established in +the city where peasants can bring their surplus supplies and the +products of the soil. The government has taken the following steps +to ensure freedom of sale for them: (1) From today, peasants, +husbandmen, and those living in the neighborhood of Moscow may without +any danger bring their supplies of all kinds to two appointed markets, +of which one is on the Mokhovaya Street and the other at the Provision +Market. (2) Such supplies will be bought from them at such prices as +seller and buyer may agree on, and if a seller is unable to obtain a +fair price he will be free to take his goods back to his village and +no one may hinder him under any pretense. (3) Sunday and Wednesday +of each week are appointed as the chief market days and to that end +a sufficient number of troops will be stationed along the highroads on +Tuesdays and Saturdays at such distances from the town as to protect +the carts. (4) Similar measures will be taken that peasants with their +carts and horses may meet with no hindrance on their return journey. +(5) Steps will immediately be taken to re-establish ordinary trading. + +Inhabitants of the city and villages, and you, workingmen and +artisans, to whatever nation you belong, you are called on to carry +out the paternal intentions of His Majesty the Emperor and King and to +co-operate with him for the public welfare! Lay your respect and +confidence at his feet and do not delay to unite with us! + + +With the object of raising the spirits of the troops and of the +people, reviews were constantly held and rewards distributed. The +Emperor rode through the streets to comfort the inhabitants, and, +despite his preoccupation with state affairs, himself visited the +theaters that were established by his order. + +In regard to philanthropy, the greatest virtue of crowned heads, +Napoleon also did all in his power. He caused the words Maison de ma +Mere to be inscribed on the charitable institutions, thereby combining +tender filial affection with the majestic benevolence of a monarch. He +visited the Foundling Hospital and, allowing the orphans saved by +him to kiss his white hands, graciously conversed with Tutolmin. Then, +as Thiers eloquently recounts, he ordered his soldiers to be paid in +forged Russian money which he had prepared: "Raising the use of +these means by an act worthy of himself and of the French army, he let +relief be distributed to those who had been burned out. But as food +was too precious to be given to foreigners, who were for the most part +enemies, Napoleon preferred to supply them with money with which to +purchase food from outside, and had paper rubles distributed to them." + +With reference to army discipline, orders were continually being +issued to inflict severe punishment for the nonperformance of military +duties and to suppress robbery. + + + + + +CHAPTER X + + +But strange to say, all these measures, efforts, and plans--which +were not at all worse than others issued in similar circumstances--did +not affect the essence of the matter but, like the hands of a clock +detached from the mechanism, swung about in an arbitrary and aimless +way without engaging the cogwheels. + +With reference to the military side--the plan of campaign--that work +of genius of which Thiers remarks that, "His genius never devised +anything more profound, more skillful, or more admirable," and +enters into a polemic with M. Fain to prove that this work of genius +must be referred not to the fourth but to the fifteenth of October- +that plan never was or could be executed, for it was quite out of +touch with the facts of the case. The fortifying of the Kremlin, for +which la Mosquee (as Napoleon termed the church of Basil the +Beatified) was to have been razed to the ground, proved quite useless. +The mining of the Kremlin only helped toward fulfilling Napoleon's +wish that it should be blown up when he left Moscow--as a child +wants the floor on which he has hurt himself to be beaten. The pursuit +of the Russian army, about which Napoleon was so concerned, produced +an unheard-of result. The French generals lost touch with the +Russian army of sixty thousand men, and according to Thiers it was +only eventually found, like a lost pin, by the skill--and apparently +the genius--of Murat. + +With reference to diplomacy, all Napoleon's arguments as to his +magnanimity and justice, both to Tutolmin and to Yakovlev (whose chief +concern was to obtain a greatcoat and a conveyance), proved useless; +Alexander did not receive these envoys and did not reply to their +embassage. + +With regard to legal matters, after the execution of the supposed +incendiaries the rest of Moscow burned down. + +With regard to administrative matters, the establishment of a +municipality did not stop the robberies and was only of use to certain +people who formed part of that municipality and under pretext of +preserving order looted Moscow or saved their own property from +being looted. + +With regard to religion, as to which in Egypt matters had so +easily been settled by Napoleon's visit to a mosque, no results were +achieved. Two or three priests who were found in Moscow did try to +carry out Napoleon's wish, but one of them was slapped in the face +by a French soldier while conducting service, and a French official +reported of another that: "The priest whom I found and invited to +say Mass cleaned and locked up the church. That night the doors were +again broken open, the padlocks smashed, the books mutilated, and +other disorders perpetrated." + +With reference to commerce, the proclamation to industrious +workmen and to peasants evoked no response. There were no +industrious workmen, and the peasants caught the commissaries who +ventured too far out of town with the proclamation and killed them. + +As to the theaters for the entertainment of the people and the +troops, these did not meet with success either. The theaters set up in +the Kremlin and in Posnyakov's house were closed again at once because +the actors and actresses were robbed. + +Even philanthropy did not have the desired effect. The genuine as +well as the false paper money which flooded Moscow lost its value. The +French, collecting booty, cared only for gold. Not only was the +paper money valueless which Napoleon so graciously distributed to +the unfortunate, but even silver lost its value in relation to gold. + +But the most amazing example of the ineffectiveness of the orders +given by the authorities at that time was Napoleon's attempt to stop +the looting and re-establish discipline. + +This is what the army authorities were reporting: + +"Looting continues in the city despite the decrees against it. Order +is not yet restored and not a single merchant is carrying on trade +in a lawful manner. The sutlers alone venture to trade, and they +sell stolen goods." + +"The neighborhood of my ward continues to be pillaged by soldiers of +the 3rd Corps who, not satisfied with taking from the unfortunate +inhabitants hiding in the cellars the little they have left, even have +the ferocity to wound them with their sabers, as I have repeatedly +witnessed." + +"Nothing new, except that the soldiers are robbing and pillaging- +October 9." + +"Robbery and pillaging continue. There is a band of thieves in our +district who ought to be arrested by a strong force--October 11." + +"The Emperor is extremely displeased that despite the strict +orders to stop pillage, parties of marauding Guards are continually +seen returning to the Kremlin. Among the Old Guard disorder and +pillage were renewed more violently than ever yesterday evening, +last night, and today. The Emperor sees with regret that the picked +soldiers appointed to guard his person, who should set an example of +discipline, carry disobedience to such a point that they break into +the cellars and stores containing army supplies. Others have disgraced +themselves to the extent of disobeying sentinels and officers, and +have abused and beaten them." + +"The Grand Marshal of the palace," wrote the governor, "complains +bitterly that in spite of repeated orders, the soldiers continue to +commit nuisances in all the courtyards and even under the very windows +of the Emperor." + +That army, like a herd of cattle run wild and trampling underfoot +the provender which might have saved it from starvation, disintegrated +and perished with each additional day it remained in Moscow. But it +did not go away. + +It began to run away only when suddenly seized by a panic caused +by the capture of transport trains on the Smolensk road, and by the +battle of Tarutino. The news of that battle of Tarutino, +unexpectedly received by Napoleon at a review, evoked in him a +desire to punish the Russians (Thiers says), and he issued the order +for departure which the whole army was demanding. + +Fleeing from Moscow the soldiers took with them everything they +had stolen. Napoleon, too, carried away his own personal tresor, but +on seeing the baggage trains that impeded the army, he was (Thiers +says) horror-struck. And yet with his experience of war he did not +order all the superfluous vehicles to be burned, as he had done with +those of a certain marshal when approaching Moscow. He gazed at the +caleches and carriages in which soldiers were riding and remarked that +it was a very good thing, as those vehicles could be used to carry +provisions, the sick, and the wounded. + +The plight of the whole army resembled that of a wounded animal +which feels it is perishing and does not know what it is doing. To +study the skillful tactics and aims of Napoleon and his army from +the time it entered Moscow till it was destroyed is like studying +the dying leaps and shudders of a mortally wounded animal. Very +often a wounded animal, hearing a rustle, rushes straight at the +hunter's gun, runs forward and back again, and hastens its own end. +Napoleon, under pressure from his whole army, did the same thing. +The rustle of the battle of Tarutino frightened the beast, and it +rushed forward onto the hunter's gun, reached him, turned back, and +finally--like any wild beast--ran back along the most +disadvantageous and dangerous path, where the old scent was familiar. + +During the whole of that period Napoleon, who seems to us to have +been the leader of all these movements--as the figurehead of a ship +may seem to a savage to guide the vessel--acted like a child who, +holding a couple of strings inside a carriage, thinks he is driving +it. + + + + + +CHAPTER XI + + +Early in the morning of the sixth of October Pierre went out of +the shed, and on returning stopped by the door to play with a little +blue-gray dog, with a long body and short bandy legs, that jumped +about him. This little dog lived in their shed, sleeping beside +Karataev at night; it sometimes made excursions into the town but +always returned again. Probably it had never had an owner, and it +still belonged to nobody and had no name. The French called it Azor; +the soldier who told stories called it Femgalka; Karataev and others +called it Gray, or sometimes Flabby. Its lack of a master, a name, +or even of a breed or any definite color did not seem to trouble the +blue-gray dog in the least. Its furry tail stood up firm and round +as a plume, its bandy legs served it so well that it would often +gracefully lift a hind leg and run very easily and quickly on three +legs, as if disdaining to use all four. Everything pleased it. Now +it would roll on its back, yelping with delight, now bask in the sun +with a thoughtful air of importance, and now frolic about playing with +a chip of wood or a straw. + +Pierre's attire by now consisted of a dirty torn shirt (the only +remnant of his former clothing), a pair of soldier's trousers which by +Karataev's advice he tied with string round the ankles for warmth, and +a peasant coat and cap. Physically he had changed much during this +time. He no longer seemed stout, though he still had the appearance of +solidity and strength hereditary in his family. A beard and mustache +covered the lower part of his face, and a tangle of hair, infested +with lice, curled round his head like a cap. The look of his eyes +was resolute, calm, and animatedly alert, as never before. The +former slackness which had shown itself even in his eyes was now +replaced by an energetic readiness for action and resistance. His feet +were bare. + +Pierre first looked down the field across which vehicles and +horsemen were passing that morning, then into the distance across +the river, then at the dog who was pretending to be in earnest about +biting him, and then at his bare feet which he placed with pleasure in +various positions, moving his dirty thick big toes. Every time he +looked at his bare feet a smile of animated self-satisfaction +flitted across his face. The sight of them reminded him of all he +had experienced and learned during these weeks and this recollection +was pleasant to him. + +For some days the weather had been calm and clear with slight frosts +in the mornings--what is called an "old wives' summer." + +In the sunshine the air was warm, and that warmth was particularly +pleasant with the invigorating freshness of the morning frost still in +the air. + +On everything--far and near--lay the magic crystal glitter seen only +at that time autumn. The Sparrow Hills were visible in the distance, +with the village, the church, and the large white house. The bare +trees, the sand, the bricks and roofs of the houses, the green +church spire, and the corners of the white house in the distance, +all stood out in the transparent air in most delicate outline and with +unnatural clearness. Near by could be seen the familiar ruins of a +half-burned mansion occupied by the French, with lilac bushes still +showing dark green beside the fence. And even that ruined and befouled +house--which in dull weather was repulsively ugly--seemed quietly +beautiful now, in the clear, motionless brilliance. + +A French corporal, with coat unbuttoned in a homely way, a +skullcap on his head, and a short pipe in his mouth, came from +behind a corner of the shed and approached Pierre with a friendly +wink. + +"What sunshine, Monsieur Kiril!" (Their name for Pierre.) "Eh? +Just like spring!" + +And the corporal leaned against the door and offered Pierre his +pipe, though whenever he offered it Pierre always declined it. + +"To be on the march in such weather..." he began. + +Pierre inquired what was being said about leaving, and the +corporal told him that nearly all the troops were starting and there +ought to be an order about the prisoners that day. Sokolov, one of the +soldiers in the shed with Pierre, was dying, and Pierre told the +corporal that something should be done about him. The corporal replied +that Pierre need not worry about that as they had an ambulance and a +permanent hospital and arrangements would be made for the sick, and +that in general everything that could happen had been foreseen by +the authorities. + +"Besides, Monsieur Kiril, you have only to say a word to the +captain, you know. He is a man who never forgets anything. Speak to +the captain when he makes his round, he will do anything for you." + +(The captain of whom the corporal spoke often had long chats with +Pierre and showed him all sorts of favors.) + +"'You see, St. Thomas,' he said to me the other day. 'Monsieur Kiril +is a man of education, who speaks French. He is a Russian seigneur who +has had misfortunes, but he is a man. He knows what's what.... If he +wants anything and asks me, he won't get a refusal. When one has +studied, you see, one likes education and well-bred people.' It is for +your sake I mention it, Monsieur Kiril. The other day if it had not +been for you that affair would have ended ill." + +And after chatting a while longer, the corporal went away. (The +affair he had alluded to had happened a few days before--a fight +between the prisoners and the French soldiers, in which Pierre had +succeeded in pacifying his comrades.) Some of the prisoners who had +heard Pierre talking to the corporal immediately asked what the +Frenchman had said. While Pierre was repeating what he had been told +about the army leaving Moscow, a thin, sallow, tattered French soldier +came up to the door of the shed. Rapidly and timidly raising his +fingers to his forehead by way of greeting, he asked Pierre whether +the soldier Platoche to whom he had given a shirt to sew was in that +shed. + +A week before the French had had boot leather and linen issued to +them, which they had given out to the prisoners to make up into +boots and shirts for them. + +"Ready, ready, dear fellow!" said Karataev, coming out with a neatly +folded shirt. + +Karataev, on account of the warm weather and for convenience at +work, was wearing only trousers and a tattered shirt as black as soot. +His hair was bound round, workman fashion, with a wisp of lime-tree +bast, and his round face seemed rounder and pleasanter than ever. + +"A promise is own brother to performance! I said Friday and here +it is, ready," said Platon, smiling and unfolding the shirt he had +sewn. + +The Frenchman glanced around uneasily and then, as if overcoming his +hesitation, rapidly threw off his uniform and put on the shirt. He had +a long, greasy, flowered silk waistcoat next to his sallow, thin +bare body, but no shirt. He was evidently afraid the prisoners looking +on would laugh at him, and thrust his head into the shirt hurriedly. +None of the prisoners said a word. + +"See, it fits well!" Platon kept repeating, pulling the shirt +straight. + +The Frenchman, having pushed his head and hands through, without +raising his eyes, looked down at the shirt and examined the seams. + +"You see, dear man, this is not a sewing shop, and I had no proper +tools; and, as they say, one needs a tool even to kill a louse," +said Platon with one of his round smiles, obviously pleased with his +work. + +"It's good, quite good, thank you," said the Frenchman, in French, +"but there must be some linen left over. + +"It will fit better still when it sets to your body," said Karataev, +still admiring his handiwork. "You'll be nice and comfortable...." + +"Thanks, thanks, old fellow.... But the bits left over?" said the +Frenchman again and smiled. He took out an assignation ruble note +and gave it to Karataev. "But give me the pieces that are over." + +Pierre saw that Platon did not want to understand what the Frenchman +was saying, and he looked on without interfering. Karataev thanked the +Frenchman for the money and went on admiring his own work. The +Frenchman insisted on having the pieces returned that were left over +and asked Pierre to translate what he said. + +"What does he want the bits for?" said Karataev. "They'd make fine +leg bands for us. Well, never mind." + +And Karataev, with a suddenly changed and saddened expression, +took a small bundle of scraps from inside his shirt and gave it to the +Frenchman without looking at him. "Oh dear!" muttered Karataev and +went away. The Frenchman looked at the linen, considered for a moment, +then looked inquiringly at Pierre and, as if Pierre's look had told +him something, suddenly blushed and shouted in a squeaky voice: + +"Platoche! Eh, Platoche! Keep them yourself!" And handing back the +odd bits he turned and went out. + +"There, look at that," said Karataev, swaying his head. "People said +they were not Christians, but they too have souls. It's what the old +folk used to say: 'A sweating hand's an open hand, a dry hand's +close.' He's naked, but yet he's given it back." + +Karataev smiled thoughtfully and was silent awhile looking at the +pieces. + +"But they'll make grand leg bands, dear friend," he said, and went +back into the shed. + + + + + +CHAPTER XII + + +Four weeks had passed since Pierre had been taken prisoner and +though the French had offered to move him from the men's to the +officers' shed, he had stayed in the shed where he was first put. + +In burned and devastated Moscow Pierre experienced almost the +extreme limits of privation a man can endure; but thanks to his +physical strength and health, of which he had till then been +unconscious, and thanks especially to the fact that the privations +came so gradually that it was impossible to say when they began, he +endured his position not only lightly but joyfully. And just at this +time he obtained the tranquillity and ease of mind he had formerly +striven in vain to reach. He had long sought in different ways that +tranquillity of mind, that inner harmony which had so impressed him in +the soldiers at the battle of Borodino. He had sought it in +philanthropy, in Freemasonry, in the dissipations of town life, in +wine, in heroic feats of self-sacrifice, and in romantic love for +Natasha; he had sought it by reasoning--and all these quests and +experiments had failed him. And now without thinking about it he had +found that peace and inner harmony only through the horror of death, +through privation, and through what he recognized in Karataev. + +Those dreadful moments he had lived through at the executions had as +it were forever washed away from his imagination and memory the +agitating thoughts and feelings that had formerly seemed so important. +It did not now occur to him to think of Russia, or the war, or +politics, or Napoleon. It was plain to him that all these things +were no business of his, and that he was not called on to judge +concerning them and therefore could not do so. "Russia and summer +weather are not bound together," he thought, repeating words of +Karataev's which he found strangely consoling. His intention of +killing Napoleon and his calculations of the cabalistic number of +the beast of the Apocalypse now seemed to him meaningless and even +ridiculous. His anger with his wife and anxiety that his name should +not be smirched now seemed not merely trivial but even amusing. What +concern was it of his that somewhere or other that woman was leading +the life she preferred? What did it matter to anybody, and +especially to him, whether or not they found out that their prisoner's +name was Count Bezukhov? + +He now often remembered his conversation with Prince Andrew and +quite agreed with him, though he understood Prince Andrew's thoughts +somewhat differently. Prince Andrew had thought and said that +happiness could only be negative, but had said it with a shade of +bitterness and irony as though he was really saying that all desire +for positive happiness is implanted in us merely to torment us and +never be satisfied. But Pierre believed it without any mental +reservation. The absence of suffering, the satisfaction of one's needs +and consequent freedom in the choice of one's occupation, that is, +of one's way of life, now seemed to Pierre to be indubitably man's +highest happiness. Here and now for the first time he fully +appreciated the enjoyment of eating when he wanted to eat, drinking +when he wanted to drink, sleeping when he wanted to sleep, of warmth +when he was cold, of talking to a fellow man when he wished to talk +and to hear a human voice. The satisfaction of one's needs--good food, +cleanliness, and freedom--now that he was deprived of all this, seemed +to Pierre to constitute perfect happiness; and the choice of +occupation, that is, of his way of life--now that that was so +restricted--seemed to him such an easy matter that he forgot that a +superfluity of the comforts of life destroys all joy in satisfying +one's needs, while great freedom in the choice of occupation--such +freedom as his wealth, his education, and his social position had +given him in his own life--is just what makes the choice of occupation +insolubly difficult and destroys the desire and possibility of +having an occupation. + +All Pierre's daydreams now turned on the time when he would be free. +Yet subsequently, and for the rest of his life, he thought and spoke +with enthusiasm of that month of captivity, of those irrecoverable, +strong, joyful sensations, and chiefly of the complete peace of mind +and inner freedom which he experienced only during those weeks. + +When on the first day he got up early, went out of the shed at dawn, +and saw the cupolas and crosses of the New Convent of the Virgin still +dark at first, the hoarfrost on the dusty grass, the Sparrow Hills, +and the wooded banks above the winding river vanishing in the purple +distance, when he felt the contact of the fresh air and heard the +noise of the crows flying from Moscow across the field, and when +afterwards light gleamed from the east and the sun's rim appeared +solemnly from behind a cloud, and the cupolas and crosses, the +hoarfrost, the distance and the river, all began to sparkle in the +glad light--Pierre felt a new joy and strength in life such as he +had never before known. And this not only stayed with him during the +whole of his imprisonment, but even grew in strength as the +hardships of his position increased. + +That feeling of alertness and of readiness for anything was still +further strengthened in him by the high opinion his fellow prisoners +formed of him soon after his arrival at the shed. With his knowledge +of languages, the respect shown him by the French, his simplicity, his +readiness to give anything asked of him (he received the allowance +of three rubles a week made to officers); with his strength, which +he showed to the soldiers by pressing nails into the walls of the hut; +his gentleness to his companions, and his capacity for sitting still +and thinking without doing anything (which seemed to them +incomprehensible), he appeared to them a rather mysterious and +superior being. The very qualities that had been a hindrance, if not +actually harmful, to him in the world he had lived in--his strength, +his disdain for the comforts of life, his absent-mindedness and +simplicity--here among these people gave him almost the status of a +hero. And Pierre felt that their opinion placed responsibilities +upon him. + + + + +CHAPTER XIII + + +The French evacuation began on the night between the sixth and +seventh of October: kitchens and sheds were dismantled, carts +loaded, and troops and baggage trains started. + +At seven in the morning a French convoy in marching trim, wearing +shakos and carrying muskets, knapsacks, and enormous sacks, stood in +front of the sheds, and animated French talk mingled with curses +sounded all along the lines. + +In the shed everyone was ready, dressed, belted, shod, and only +awaited the order to start. The sick soldier, Sokolov, pale and thin +with dark shadows round his eyes, alone sat in his place barefoot +and not dressed. His eyes, prominent from the emaciation of his +face, gazed inquiringly at his comrades who were paying no attention +to him, and he moaned regularly and quietly. It was evidently not so +much his sufferings that caused him to moan (he had dysentery) as +his fear and grief at being left alone. + +Pierre, girt with a rope round his waist and wearing shoes +Karataev had made for him from some leather a French soldier had +torn off a tea chest and brought to have his boots mended with, went +up to the sick man and squatted down beside him. + +"You know, Sokolov, they are not all going away! They have a +hospital here. You may be better off than we others," said Pierre. + +"O Lord! Oh, it will be the death of me! O Lord!" moaned the man +in a louder voice. + +"I'll go and ask them again directly," said Pierre, rising and going +to the door of the shed. + +Just as Pierre reached the door, the corporal who had offered him +a pipe the day before came up to it with two soldiers. The corporal +and soldiers were in marching kit with knapsacks and shakos that had +metal straps, and these changed their familiar faces. + +The corporal came, according to orders, to shut the door. The +prisoners had to be counted before being let out. + +"Corporal, what will they do with the sick man?..." Pierre began. + +But even as he spoke he began to doubt whether this was the corporal +he knew or a stranger, so unlike himself did the corporal seem at that +moment. Moreover, just as Pierre was speaking a sharp rattle of +drums was suddenly heard from both sides. The corporal frowned at +Pierre's words and, uttering some meaningless oaths, slammed the door. +The shed became semidark, and the sharp rattle of the drums on two +sides drowned the sick man's groans. + +"There it is!... It again!..." said Pierre to himself, and an +involuntary shudder ran down his spine. In the corporal's changed +face, in the sound of his voice, in the stirring and deafening noise +of the drums, he recognized that mysterious, callous force which +compelled people against their will to kill their fellow men--that +force the effect of which he had witnessed during the executions. To +fear or to try to escape that force, to address entreaties or +exhortations to those who served as its tools, was useless. Pierre +knew this now. One had to wait and endure. He did not again go to +the sick man, nor turn to look at him, but stood frowning by the +door of the hut. + +When that door was opened and the prisoners, crowding against one +another like a flock of sheep, squeezed into the exit, Pierre pushed +his way forward and approached that very captain who as the corporal +had assured him was ready to do anything for him. The captain was also +in marching kit, and on his cold face appeared that same it which +Pierre had recognized in the corporal's words and in the roll of the +drums. + +"Pass on, pass on!" the captain reiterated, frowning sternly, and +looking at the prisoners who thronged past him. + +Pierre went up to him, though he knew his attempt would be vain. + +"What now?" the officer asked with a cold look as if not recognizing +Pierre. + +Pierre told him about the sick man. + +"He'll manage to walk, devil take him!" said the captain. "Pass +on, pass on!" he continued without looking at Pierre. + +"But he is dying," Pierre again began. + +"Be so good..." shouted the captain, frowning angrily. + +"Dram-da-da-dam, dam-dam..." rattled the drums, and Pierre +understood that this mysterious force completely controlled these +men and that it was now useless to say any more. + +The officer prisoners were separated from the soldiers and told to +march in front. There were about thirty officers, with Pierre among +them, and about three hundred men. + +The officers, who had come from the other sheds, were all +strangers to Pierre and much better dressed than he. They looked at +him and at his shoes mistrustfully, as at an alien. Not far from him +walked a fat major with a sallow, bloated, angry face, who was wearing +a Kazan dressing grown tied round with a towel, and who evidently +enjoyed the respect of his fellow prisoners. He kept one hand, in +which he clasped his tobacco pouch, inside the bosom of his dressing +gown and held the stem of his pipe firmly with the other. Panting +and puffing, the major grumbled and growled at everybody because he +thought he was being pushed and that they were all hurrying when +they had nowhere to hurry to and were all surprised at something +when there was nothing to be surprised at. Another, a thin little +officer, was speaking to everyone, conjecturing where they were now +being taken and how far they would get that day. An official in felt +boots and wearing a commissariat uniform ran round from side to side +and gazed at the ruins of Moscow, loudly announcing his observations +as to what had been burned down and what this or that part of the city +was that they could see. A third officer, who by his accent was a +Pole, disputed with the commissariat officer, arguing that he was +mistaken in his identification of the different wards of Moscow. + +"What are you disputing about?" said the major angrily. "What does +it matter whether it is St. Nicholas or St. Blasius? You see it's +burned down, and there's an end of it.... What are you pushing for? +Isn't the road wide enough?" said he, turning to a man behind him +who was not pushing him at all. + +"Oh, oh, oh! What have they done?" the prisoners on one side and +another were heard saying as they gazed on the charred ruins. "All +beyond the river, and Zubova, and in the Kremlin.... Just look! +There's not half of it left. Yes, I told you--the whole quarter beyond +the river, and so it is." + +"Well, you know it's burned, so what's the use of talking?" said the +major. + +As they passed near a church in the Khamovniki (one of the few +unburned quarters of Moscow) the whole mass of prisoners suddenly +started to one side and exclamations of horror and disgust were heard. + +"Ah, the villains! What heathens! Yes; dead, dead, so he is... And +smeared with something!" + +Pierre too drew near the church where the thing was that evoked +these exclamations, and dimly made out something leaning against the +palings surrounding the church. From the words of his comrades who saw +better than he did, he found that this was the body of a man, set +upright against the palings with its face smeared with soot. + +"Go on! What the devil... Go on! Thirty thousand devils!..." the +convoy guards began cursing and the French soldiers, with fresh +virulence, drove away with their swords the crowd of prisoners who +were gazing at the dead man. + + + + + +CHAPTER XIV + + +Through the cross streets of the Khamovniki quarter the prisoners +marched, followed only by their escort and the vehicles and wagons +belonging to that escort, but when they reached the supply stores they +came among a huge and closely packed train of artillery mingled with +private vehicles. + +At the bridge they all halted, waiting for those in front to get +across. From the bridge they had a view of endless lines of moving +baggage trains before and behind them. To the right, where the +Kaluga road turns near Neskuchny, endless rows of troops and carts +stretched away into the distance. These were troops of Beauharnais' +corps which had started before any of the others. Behind, along the +riverside and across the Stone Bridge, were Ney's troops and +transport. + +Davout's troops, in whose charge were the prisoners, were crossing +the Crimean bridge and some were already debouching into the Kaluga +road. But the baggage trains stretched out so that the last of +Beauharnais' train had not yet got out of Moscow and reached the +Kaluga road when the vanguard of Ney's army was already emerging +from the Great Ordynka Street. + +When they had crossed the Crimean bridge the prisoners moved a few +steps forward, halted, and again moved on, and from all sides vehicles +and men crowded closer and closer together. They advanced the few +hundred paces that separated the bridge from the Kaluga road, taking +more than an hour to do so, and came out upon the square where the +streets of the Transmoskva ward and the Kaluga road converge, and +the prisoners jammed close together had to stand for some hours at +that crossway. From all sides, like the roar of the sea, were heard +the rattle of wheels, the tramp of feet, and incessant shouts of anger +and abuse. Pierre stood pressed against the wall of a charred house, +listening to that noise which mingled in his imagination with the roll +of the drums. + +To get a better view, several officer prisoners climbed onto the +wall of the half-burned house against which Pierre was leaning. + +"What crowds! Just look at the crowds!... They've loaded goods +even on the cannon! Look there, those are furs!" they exclaimed. "Just +see what the blackguards have looted.... There! See what that one +has behind in the cart.... Why, those are settings taken from some +icons, by heaven!... Oh, the rascals!... See how that fellow has +loaded himself up, he can hardly walk! Good lord, they've even grabbed +those chaises!... See that fellow there sitting on the trunks.... +Heavens! They're fighting." + +"That's right, hit him on the snout--on his snout! Like this, we +shan't get away before evening. Look, look there.... Why, that must be +Napoleon's own. See what horses! And the monograms with a crown! +It's like a portable house.... That fellow's dropped his sack and +doesn't see it. Fighting again... A woman with a baby, and not +bad-looking either! Yes, I dare say, that's the way they'll let you +pass... Just look, there's no end to it. Russian wenches, by heaven, +so they are! In carriages--see how comfortably they've settled +themselves!" + +Again, as at the church in Khamovniki, a wave of general curiosity +bore all the prisoners forward onto the road, and Pierre, thanks to +his stature, saw over the heads of the others what so attracted +their curiosity. In three carriages involved among the munition carts, +closely squeezed together, sat women with rouged faces, dressed in +glaring colors, who were shouting something in shrill voices. + +From the moment Pierre had recognized the appearance of the +mysterious force nothing had seemed to him strange or dreadful: +neither the corpse smeared with soot for fun nor these women +hurrying away nor the burned ruins of Moscow. All that he now +witnessed scarcely made an impression on him--as if his soul, making +ready for a hard struggle, refused to receive impressions that might +weaken it. + +The women's vehicles drove by. Behind them came more carts, +soldiers, wagons, soldiers, gun carriages, carriages, soldiers, +ammunition carts, more soldiers, and now and then women. + +Pierre did not see the people as individuals but saw their movement. + +All these people and horses seemed driven forward by some +invisible power. During the hour Pierre watched them they all came +flowing from the different streets with one and the same desire to get +on quickly; they all jostled one another, began to grow angry and to +fight, white teeth gleamed, brows frowned, ever the same words of +abuse flew from side to side, and all the faces bore the same +swaggeringly resolute and coldly cruel expression that had struck +Pierre that morning on the corporal's face when the drums were +beating. + +It was not till nearly evening that the officer commanding the +escort collected his men and with shouts and quarrels forced his way +in among the baggage trains, and the prisoners, hemmed in on all +sides, emerged onto the Kaluga road. + +They marched very quickly, without resting, and halted only when the +sun began to set. The baggage carts drew up close together and the men +began to prepare for their night's rest. They all appeared angry and +dissatisfied. For a long time, oaths, angry shouts, and fighting could +be heard from all sides. A carriage that followed the escort ran +into one of the carts and knocked a hole in it with its pole. +Several soldiers ran toward the cart from different sides: some beat +the carriage horses on their heads, turning them aside, others +fought among themselves, and Pierre saw that one German was badly +wounded on the head by a sword. + +It seemed that all these men, now that they had stopped amid +fields in the chill dusk of the autumn evening, experienced one and +the same feeling of unpleasant awakening from the hurry and +eagerness to push on that had seized them at the start. Once at a +standstill they all seemed to understand that they did not yet know +where they were going, and that much that was painful and difficult +awaited them on this journey. + +During this halt the escort treated the prisoners even worse than +they had done at the start. It was here that the prisoners for the +first time received horseflesh for their meat ration. + +From the officer down to the lowest soldier they showed what +seemed like personal spite against each of the prisoners, in +unexpected contrast to their former friendly relations. + +This spite increased still more when, on calling over the roll of +prisoners, it was found that in the bustle of leaving Moscow one +Russian soldier, who had pretended to suffer from colic, had +escaped. Pierre saw a Frenchman beat a Russian soldier cruelly for +straying too far from the road, and heard his friend the captain +reprimand and threaten to court-martial a noncommissioned officer on +account of the escape of the Russian. To the noncommissioned officer's +excuse that the prisoner was ill and could not walk, the officer +replied that the order was to shoot those who lagged behind. Pierre +felt that that fatal force which had crushed him during the +executions, but which he had not felt during his imprisonment, now +again controlled his existence. It was terrible, but he felt that in +proportion to the efforts of that fatal force to crush him, there grew +and strengthened in his soul a power of life independent of it. + +He ate his supper of buckwheat soup with horseflesh and chatted with +his comrades. + +Neither Pierre nor any of the others spoke of what they had seen +in Moscow, or of the roughness of their treatment by the French, or of +the order to shoot them which had been announced to them. As if in +reaction against the worsening of their position they were all +particularly animated and gay. They spoke of personal reminiscences, +of amusing scenes they had witnessed during the campaign, and +avoided all talk of their present situation. + +The sun had set long since. Bright stars shone out here and there in +the sky. A red glow as of a conflagration spread above the horizon +from the rising full moon, and that vast red ball swayed strangely +in the gray haze. It grew light. The evening was ending, but the night +had not yet come. Pierre got up and left his new companions, +crossing between the campfires to the other side of the road where +he had been told the common soldier prisoners were stationed. He +wanted to talk to them. On the road he was stopped by a French +sentinel who ordered him back. + +Pierre turned back, not to his companions by the campfire, but to an +unharnessed cart where there was nobody. Tucking his legs under him +and dropping his head he sat down on the cold ground by the wheel of +the cart and remained motionless a long while sunk in thought. +Suddenly he burst out into a fit of his broad, good-natured +laughter, so loud that men from various sides turned with surprise +to see what this strange and evidently solitary laughter could mean. + +"Ha-ha-ha!" laughed Pierre. And he said aloud to himself: "The +soldier did not let me pass. They took me and shut me up. They hold me +captive. What, me? Me? My immortal soul? Ha-ha-ha! Ha-ha-ha!..." and +he laughed till tears started to his eyes. + +A man got up and came to see what this queer big fellow was laughing +at all by himself. Pierre stopped laughing, got up, went farther +away from the inquisitive man, and looked around him. + +The huge, endless bivouac that had previously resounded with the +crackling of campfires and the voices of many men had grown quiet, the +red campfires were growing paler and dying down. High up in the +light sky hung the full moon. Forests and fields beyond the camp, +unseen before, were now visible in the distance. And farther still, +beyond those forests and fields, the bright, oscillating, limitless +distance lured one to itself. Pierre glanced up at the sky and the +twinkling stars in its faraway depths. "And all that is me, all that +is within me, and it is all I!" thought Pierre. "And they caught all +that and put it into a shed boarded up with planks!" He smiled, and +went and lay down to sleep beside his companions. + + + + + +CHAPTER XV + + +In the early days of October another envoy came to Kutuzov with a +letter from Napoleon proposing peace and falsely dated from Moscow, +though Napoleon was already not far from Kutuzov on the old Kaluga +road. Kutuzov replied to this letter as he had done to the one +formerly brought by Lauriston, saying that there could be no +question of peace. + +Soon after that a report was received from Dorokhov's guerrilla +detachment operating to the left of Tarutino that troops of +Broussier's division had been seen at Forminsk and that being +separated from the rest of the French army they might easily be +destroyed. The soldiers and officers again demanded action. Generals +on the staff, excited by the memory of the easy victory at Tarutino, +urged Kutuzov to carry out Dorokhov's suggestion. Kutuzov did not +consider any offensive necessary. The result was a compromise which +was inevitable: a small detachment was sent to Forminsk to attack +Broussier. + +By a strange coincidence, this task, which turned out to be a most +difficult and important one, was entrusted to Dokhturov--that same +modest little Dokhturov whom no one had described to us as drawing +up plans of battles, dashing about in front of regiments, showering +crosses on batteries, and so on, and who was thought to be and was +spoken of as undecided and undiscerning--but whom we find commanding +wherever the position was most difficult all through the +Russo-French wars from Austerlitz to the year 1813. At Austerlitz he +remained last at the Augezd dam, rallying the regiments, saving what +was possible when all were flying and perishing and not a single +general was left in the rear guard. Ill with fever he went to Smolensk +with twenty thousand men to defend the town against Napoleon's whole +army. In Smolensk, at the Malakhov Gate, he had hardly dozed off in +a paroxysm of fever before he was awakened by the bombardment of the +town--and Smolensk held out all day long. At the battle of Borodino, +when Bagration was killed and nine tenths of the men of our left flank +had fallen and the full force of the French artillery fire was +directed against it, the man sent there was this same irresolute and +undiscerning Dokhturov--Kutuzov hastening to rectify a mistake he +had made by sending someone else there first. And the quiet little +Dokhturov rode thither, and Borodino became the greatest glory of +the Russian army. Many heroes have been described to us in verse and +prose, but of Dokhturov scarcely a word has been said. + +It was Dokhturov again whom they sent to Forminsk and from there +to Malo-Yaroslavets, the place where the last battle with the French +was fought and where the obvious disintegration of the French army +began; and we are told of many geniuses and heroes of that period of +the campaign, but of Dokhturov nothing or very little is said and that +dubiously. And this silence about Dokhturov is the clearest +testimony to his merit. + +It is natural for a man who does not understand the workings of a +machine to imagine that a shaving that has fallen into it by chance +and is interfering with its action and tossing about in it is its most +important part. The man who does not understand the construction of +the machine cannot conceive that the small connecting cogwheel which +revolves quietly is one of the most essential parts of the machine, +and not the shaving which merely harms and hinders the working. + +On the tenth of October when Dokhturov had gone halfway to +Forminsk and stopped at the village of Aristovo, preparing +faithfully to execute the orders he had received, the whole French +army having, in its convulsive movement, reached Murat's position +apparently in order to give battle--suddenly without any reason turned +off to the left onto the new Kaluga road and began to enter +Forminsk, where only Broussier had been till then. At that time +Dokhturov had under his command, besides Dorokhov's detachment, the +two small guerrilla detachments of Figner and Seslavin. + +On the evening of October 11 Seslavin came to the Aristovo +headquarters with a French guardsman he had captured. The prisoner +said that the troops that had entered Forminsk that day were the +vanguard of the whole army, that Napoleon was there and the whole army +had left Moscow four days previously. That same evening a house serf +who had come from Borovsk said he had seen an immense army entering +the town. Some Cossacks of Dokhturov's detachment reported having +sighted the French Guards marching along the road to Borovsk. From all +these reports it was evident that where they had expected to meet a +single division there was now the whole French army marching from +Moscow in an unexpected direction--along the Kaluga road. Dokhturov +was unwilling to undertake any action, as it was not clear to him +now what he ought to do. He had been ordered to attack Forminsk. But +only Broussier had been there at that time and now the whole French +army was there. Ermolov wished to act on his own judgment, but +Dokhturov insisted that he must have Kutuzov's instructions. So it was +decided to send a dispatch to the staff. + +For this purpose a capable officer, Bolkhovitinov, was chosen, who +was to explain the whole affair by word of mouth, besides delivering a +written report. Toward midnight Bolkhovitinov, having received the +dispatch and verbal instructions, galloped off to the General Staff +accompanied by a Cossack with spare horses. + + + + + +CHAPTER XVI + + +It was a warm, dark, autumn night. It had been raining for four +days. Having changed horses twice and galloped twenty miles in an hour +and a half over a sticky, muddy road, Bolkhovitinov reached Litashevka +after one o'clock at night. Dismounting at a cottage on whose wattle +fence hung a signboard, GENERAL STAFF, and throwing down his reins, he +entered a dark passage. + +"The general on duty, quick! It's very important!" said he to +someone who had risen and was sniffing in the dark passage. + +"He has been very unwell since the evening and this is the third +night he has not slept," said the orderly pleadingly in a whisper. +"You should wake the captain first." + +"But this is very important, from General Dokhturov," said +Bolkhovitinov, entering the open door which he had found by feeling in +the dark. + +The orderly had gone in before him and began waking somebody. + +"Your honor, your honor! A courier." + +"What? What's that? From whom?" came a sleepy voice. + +"From Dokhturov and from Alexey Petrovich. Napoleon is at Forminsk," +said Bolkhovitinov, unable to see in the dark who was speaking but +guessing by the voice that it was not Konovnitsyn. + +The man who had wakened yawned and stretched himself. + +"I don't like waking him," he said, fumbling for something. "He is +very ill. Perhaps this is only a rumor." + +"Here is the dispatch," said Bolkhovitinov. "My orders are to give +it at once to the general on duty." + +"Wait a moment, I'll light a candle. You damned rascal, where do you +always hide it?" said the voice of the man who was stretching himself, +to the orderly. (This was Shcherbinin, Konovnitsyn's adjutant.) +"I've found it, I've found it!" he added. + +The orderly was striking a light and Shcherbinin was fumbling for +something on the candlestick. + +"Oh, the nasty beasts!" said he with disgust. + +By the light of the sparks Bolkhovitinov saw Shcherbinin's +youthful face as he held the candle, and the face of another man who +was still asleep. This was Konovnitsyn. + +When the flame of the sulphur splinters kindled by the tinder burned +up, first blue and then red, Shcherbinin lit the tallow candle, from +the candlestick of which the cockroaches that had been gnawing it were +running away, and looked at the messenger. Bolkhovitinov was +bespattered all over with mud and had smeared his face by wiping it +with his sleeve. + +"Who gave the report?" inquired Shcherbinin, taking the envelope. + +"The news is reliable," said Bolkhovitinov. "Prisoners, Cossacks, +and the scouts all say the same thing." + +"There's nothing to be done, we'll have to wake him," said +Shcherbinin, rising and going up to the man in the nightcap who lay +covered by a greatcoat. "Peter Petrovich!" said he. (Konovnitsyn did +not stir.) "To the General Staff!" he said with a smile, knowing +that those words would be sure to arouse him. + +And in fact the head in the nightcap was lifted at once. On +Konovnitsyn's handsome, resolute face with cheeks flushed by fever, +there still remained for an instant a faraway dreamy expression remote +from present affairs, but then he suddenly started and his face +assumed its habitual calm and firm appearance. + +"Well, what is it? From whom?" he asked immediately but without +hurry, blinking at the light. + +While listening to the officer's report Konovnitsyn broke the seal +and read the dispatch. Hardly had he done so before he lowered his +legs in their woolen stockings to the earthen floor and began +putting on his boots. Then he took off his nightcap, combed his hair +over his temples, and donned his cap. + +"Did you get here quickly? Let us go to his Highness." + +Konovnitsyn had understood at once that the news brought was of +great importance and that no time must be lost. He did not consider or +ask himself whether the news was good or bad. That did not interest +him. He regarded the whole business of the war not with his +intelligence or his reason but by something else. There was within him +a deep unexpressed conviction that all would be well, but that one +must not trust to this and still less speak about it, but must only +attend to one's own work. And he did his work, giving his whole +strength to the task. + +Peter Petrovich Konovnitsyn, like Dokhturov, seems to have been +included merely for propriety's sake in the list of the so-called +heroes of 1812--the Barclays, Raevskis, Ermolovs, Platovs, and +Miloradoviches. Like Dokhturov he had the reputation of being a man of +very limited capacity and information, and like Dokhturov he never +made plans of battle but was always found where the situation was most +difficult. Since his appointment as general on duty he had always +slept with his door open, giving orders that every messenger should be +allowed to wake him up. In battle he was always under fire, so that +Kutuzov reproved him for it and feared to send him to the front, and +like Dokhturov he was one of those unnoticed cogwheels that, without +clatter or noise, constitute the most essential part of the machine. + +Coming out of the hut into the damp, dark night Konovnitsyn frowned- +partly from an increased pain in his head and partly at the unpleasant +thought that occurred to him, of how all that nest of influential +men on the staff would be stirred up by this news, especially +Bennigsen, who ever since Tarutino had been at daggers drawn with +Kutuzov; and how they would make suggestions, quarrel, issue orders, +and rescind them. And this premonition was disagreeable to him +though he knew it could not be helped. + +And in fact Toll, to whom he went to communicate the news, +immediately began to expound his plans to a general sharing his +quarters, until Konovnitsyn, who listened in weary silence, reminded +him that they must go to see his Highness. + + + + + +CHAPTER XVII + + +Kutuzov like all old people did not sleep much at night. He often +fell asleep unexpectedly in the daytime, but at night, lying on his +bed without undressing, he generally remained awake thinking. + +So he lay now on his bed, supporting his large, heavy, scarred +head on his plump hand, with his one eye open, meditating and +peering into the darkness. + +Since Bennigsen, who corresponded with the Emperor and had more +influence than anyone else on the staff, had begun to avoid him, +Kutuzov was more at ease as to the possibility of himself and his +troops being obliged to take part in useless aggressive movements. The +lesson of the Tarutino battle and of the day before it, which +Kutuzov remembered with pain, must, he thought, have some effect on +others too. + +"They must understand that we can only lose by taking the offensive. +Patience and time are my warriors, my champions," thought Kutuzov. +He knew that an apple should not be plucked while it is green. It will +fall of itself when ripe, but if picked unripe the apple is spoiled, +the tree is harmed, and your teeth are set on edge. Like an +experienced sportsman he knew that the beast was wounded, and +wounded as only the whole strength of Russia could have wounded it, +but whether it was mortally wounded or not was still an undecided +question. Now by the fact of Lauriston and Barthelemi having been +sent, and by the reports of the guerrillas, Kutuzov was almost sure +that the wound was mortal. But he needed further proofs and it was +necessary to wait. + +"They want to run to see how they have wounded it. Wait and we shall +see! Continual maneuvers, continual advances!" thought he. "What +for? Only to distinguish themselves! As if fighting were fun. They are +like children from whom one can't get any sensible account of what has +happened because they all want to show how well they can fight. But +that's not what is needed now. + +"And what ingenious maneuvers they all propose to me! It seems to +them that when they have thought of two or three contingencies" (he +remembered the general plan sent him from Petersburg) "they have +foreseen everything. But the contingencies are endless." + +The undecided question as to whether the wound inflicted at Borodino +was mortal or not had hung over Kutuzov's head for a whole month. On +the one hand the French had occupied Moscow. On the other Kutuzov felt +assured with all his being that the terrible blow into which he and +all the Russians had put their whole strength must have been mortal. +But in any case proofs were needed; he had waited a whole month for +them and grew more impatient the longer he waited. Lying on his bed +during those sleepless nights he did just what he reproached those +younger generals for doing. He imagined all sorts of possible +contingencies, just like the younger men, but with this difference, +that he saw thousands of contingencies instead of two or three and +based nothing on them. The longer he thought the more contingencies +presented themselves. He imagined all sorts of movements of the +Napoleonic army as a whole or in sections--against Petersburg, or +against him, or to outflank him. He thought too of the possibility +(which he feared most of all) that Napoleon might fight him with his +own weapon and remain in Moscow awaiting him. Kutuzov even imagined +that Napoleon's army might turn back through Medyn and Yukhnov, but +the one thing he could not foresee was what happened--the insane, +convulsive stampede of Napoleon's army during its first eleven days +after leaving Moscow: a stampede which made possible what Kutuzov +had not yet even dared to think of--the complete extermination of +the French. Dorokhov's report about Broussier's division, the +guerrillas' reports of distress in Napoleon's army, rumors of +preparations for leaving Moscow, all confirmed the supposition that +the French army was beaten and preparing for flight. But these were +only suppositions, which seemed important to the younger men but not +to Kutuzov. With his sixty years' experience he knew what value to +attach to rumors, knew how apt people who desire anything are to group +all news so that it appears to confirm what they desire, and he knew +how readily in such cases they omit all that makes for the contrary. +And the more he desired it the less he allowed himself to believe +it. This question absorbed all his mental powers. All else was to +him only life's customary routine. To such customary routine +belonged his conversations with the staff, the letters he wrote from +Tarutino to Madame de Stael, the reading of novels, the distribution +of awards, his correspondence with Petersburg, and so on. But the +destruction of the French, which he alone foresaw, was his heart's one +desire. + +On the night of the eleventh of October he lay leaning on his arm +and thinking of that. + +There was a stir in the next room and he heard the steps of Toll, +Konovnitsyn, and Bolkhovitinov. + +"Eh, who's there? Come in, come in! What news?" the field marshal +called out to them. + +While a footman was lighting a candle, Toll communicated the +substance of the news. + +"Who brought it?" asked Kutuzov with a look which, when the candle +was lit, struck Toll by its cold severity. + +"There can be no doubt about it, your Highness." + +"Call him in, call him here." + +Kutuzov sat up with one leg hanging down from the bed and his big +paunch resting against the other which was doubled under him. He +screwed up his seeing eye to scrutinize the messenger more +carefully, as if wishing to read in his face what preoccupied his +own mind. + +"Tell me, tell me, friend," said he to Bolkhovitinov in his low, +aged voice, as he pulled together the shirt which gaped open on his +chest, "come nearer--nearer. What news have you brought me? Eh? That +Napoleon has left Moscow? Are you sure? Eh?" + +Bolkhovitinov gave a detailed account from the beginning of all he +had been told to report. + +"Speak quicker, quicker! Don't torture me!" Kutuzov interrupted him. + +Bolkhovitinov told him everything and was then silent, awaiting +instructions. Toll was beginning to say something but Kutuzov +checked him. He tried to say something, but his face suddenly puckered +and wrinkled; he waved his arm at Toll and turned to the opposite side +of the room, to the corner darkened by the icons that hung there. + +"O Lord, my Creator, Thou has heard our prayer..." said he in a +tremulous voice with folded hands. "Russia is saved. I thank Thee, O +Lord!" and he wept. + + + + + +CHAPTER XVIII + + +From the time he received this news to the end of the campaign all +Kutuzov's activity was directed toward restraining his troops, by +authority, by guile, and by entreaty, from useless attacks, maneuvers, +or encounters with the perishing enemy. Dokhturov went to +Malo-Yaroslavets, but Kutuzov lingered with the main army and gave +orders for the evacuation of Kaluga--a retreat beyond which town +seemed to him quite possible. + +Everywhere Kutuzov retreated, but the enemy without waiting for +his retreat fled in the opposite direction. + +Napoleon's historians describe to us his skilled maneuvers at +Tarutino and Malo-Yaroslavets, and make conjectures as to what would +have happened had Napoleon been in time to penetrate into the rich +southern provinces. + +But not to speak of the fact that nothing prevented him from +advancing into those southern provinces (for the Russian army did +not bar his way), the historians forget that nothing could have +saved his army, for then already it bore within itself the germs of +inevitable ruin. How could that army--which had found abundant +supplies in Moscow and had trampled them underfoot instead of +keeping them, and on arriving at Smolensk had looted provisions +instead of storing them--how could that army recuperate in Kaluga +province, which was inhabited by Russians such as those who lived in +Moscow, and where fire had the same property of consuming what was set +ablaze? + +That army could not recover anywhere. Since the battle of Borodino +and the pillage of Moscow it had borne within itself, as it were, +the chemical elements of dissolution. + +The members of what had once been an army--Napoleon himself and +all his soldiers fled--without knowing whither, each concerned only to +make his escape as quickly as possible from this position, of the +hopelessness of which they were all more or less vaguely conscious. + +So it came about that at the council at Malo-Yaroslavets, when the +generals pretending to confer together expressed various opinions, all +mouths were closed by the opinion uttered by the simple-minded soldier +Mouton who, speaking last, said what they all felt: that the one thing +needful was to get away as quickly as possible; and no one, not even +Napoleon, could say anything against that truth which they all +recognized. + +But though they all realized that it was necessary to get away, +there still remained a feeling of shame at admitting that they must +flee. An external shock was needed to overcome that shame, and this +shock came in due time. It was what the French called "le hourra de +l'Empereur." + +The day after the council at Malo-Yaroslavets Napoleon rode out +early in the morning amid the lines of his army with his suite of +marshals and an escort, on the pretext of inspecting the army and +the scene of the previous and of the impending battle. Some Cossacks +on the prowl for booty fell in with the Emperor and very nearly +captured him. If the Cossacks did not capture Napoleon then, what +saved him was the very thing that was destroying the French army, +the booty on which the Cossacks fell. Here as at Tarutino they went +after plunder, leaving the men. Disregarding Napoleon they rushed +after the plunder and Napoleon managed to escape. + +When les enfants du Don might so easily have taken the Emperor +himself in the midst of his army, it was clear that there was +nothing for it but to fly as fast as possible along the nearest, +familiar road. Napoleon with his forty-year-old stomach understood +that hint, not feeling his former agility and boldness, and under +the influence of the fright the Cossacks had given him he at once +agreed with Mouton and issued orders--as the historians tell us--to +retreat by the Smolensk road. + +That Napoleon agreed with Mouton, and that the army retreated, +does not prove that Napoleon caused it to retreat, but that the forces +which influenced the whole army and directed it along the Mozhaysk +(that is, the Smolensk) road acted simultaneously on him also. + + + + + +CHAPTER XIX + + +A man in motion always devises an aim for that motion. To be able to +go a thousand miles he must imagine that something good awaits him +at the end of those thousand miles. One must have the prospect of a +promised land to have the strength to move. + +The promised land for the French during their advance had been +Moscow, during their retreat it was their native land. But that native +land was too far off, and for a man going a thousand miles it is +absolutely necessary to set aside his final goal and to say to +himself: "Today I shall get to a place twenty-five miles off where I +shall rest and spend the night," and during the first day's journey +that resting place eclipses his ultimate goal and attracts all his +hopes and desires. And the impulses felt by a single person are always +magnified in a crowd. + +For the French retreating along the old Smolensk road, the final +goal--their native land--was too remote, and their immediate goal +was Smolensk, toward which all their desires and hopes, enormously +intensified in the mass, urged them on. It was not that they knew that +much food and fresh troops awaited them in Smolensk, nor that they +were told so (on the contrary their superior officers, and Napoleon +himself, knew that provisions were scarce there), but because this +alone could give them strength to move on and endure their present +privations. So both those who knew and those who did not know deceived +themselves, and pushed on to Smolensk as to a promised land. + +Coming out onto the highroad the French fled with surprising +energy and unheard-of rapidity toward the goal they had fixed on. +Besides the common impulse which bound the whole crowd of French +into one mass and supplied them with a certain energy, there was +another cause binding them together--their great numbers. As with +the physical law of gravity, their enormous mass drew the individual +human atoms to itself. In their hundreds of thousands they moved +like a whole nation. + +Each of them desired nothing more than to give himself up as a +prisoner to escape from all this horror and misery; but on the one +hand the force of this common attraction to Smolensk, their goal, drew +each of them in the same direction; on the other hand an army corps +could not surrender to a company, and though the French availed +themselves of every convenient opportunity to detach themselves and to +surrender on the slightest decent pretext, such pretexts did not +always occur. Their very numbers and their crowded and swift +movement deprived them of that possibility and rendered it not only +difficult but impossible for the Russians to stop this movement, to +which the French were directing all their energies. Beyond a certain +limit no mechanical disruption of the body could hasten the process of +decomposition. + +A lump of snow cannot be melted instantaneously. There is a +certain limit of time in less than which no amount of heat can melt +the snow. On the contrary the greater the heat the more solidified the +remaining snow becomes. + +Of the Russian commanders Kutuzov alone understood this. When the +flight of the French army along the Smolensk road became well defined, +what Konovnitsyn had foreseen on the night of the eleventh of +October began to occur. The superior officers all wanted to +distinguish themselves, to cut off, to seize, to capture, and to +overthrow the French, and all clamored for action. + +Kutuzov alone used all his power (and such power is very limited +in the case of any commander in chief) to prevent an attack. + +He could not tell them what we say now: "Why fight, why block the +road, losing our own men and inhumanly slaughtering unfortunate +wretches? What is the use of that, when a third of their army has +melted away on the road from Moscow to Vyazma without any battle?" But +drawing from his aged wisdom what they could understand, he told +them of the golden bridge, and they laughed at and slandered him, +flinging themselves on, rending and exulting over the dying beast. + +Ermolov, Miloradovich, Platov, and others in proximity to the French +near Vyazma could not resist their desire to cut off and break up +two French corps, and by way of reporting their intention to Kutuzov +they sent him a blank sheet of paper in an envelope. + +And try as Kutuzov might to restrain the troops, our men attacked, +trying to bar the road. Infantry regiments, we are told, advanced to +the attack with music and with drums beating, and killed and lost +thousands of men. + +But they did not cut off or overthrow anybody and the French army, +closing up more firmly at the danger, continued, while steadily +melting away, to pursue its fatal path to Smolensk. + + + + + + +BOOK FOURTEEN: 1812 + + + + + +CHAPTER I + + +The Battle of Borodino, with the occupation of Moscow that +followed it and the flight of the French without further conflicts, is +one of the most instructive phenomena in history. + +All historians agree that the external activity of states and +nations in their conflicts with one another is expressed in wars, +and that as a direct result of greater or less success in war the +political strength of states and nations increases or decreases. + +Strange as may be the historical account of how some king or +emperor, having quarreled with another, collects an army, fights his +enemy's army, gains a victory by killing three, five, or ten +thousand men, and subjugates a kingdom and an entire nation of several +millions, all the facts of history (as far as we know it) confirm +the truth of the statement that the greater or lesser success of one +army against another is the cause, or at least an essential +indication, of an increase or decrease in the strength of the +nation--even though it is unintelligible why the defeat of an army- +a hundredth part of a nation--should oblige that whole nation to +submit. An army gains a victory, and at once the rights of the +conquering nation have increased to the detriment of the defeated. +An army has suffered defeat, and at once a people loses its rights +in proportion to the severity of the reverse, and if its army +suffers a complete defeat the nation is quite subjugated. + +So according to history it has been found from the most ancient +times, and so it is to our own day. All Napoleon's wars serve to +confirm this rule. In proportion to the defeat of the Austrian army +Austria loses its rights, and the rights and the strength of France +increase. The victories of the French at Jena and Auerstadt destroy +the independent existence of Prussia. + +But then, in 1812, the French gain a victory near Moscow. Moscow +is taken and after that, with no further battles, it is not Russia +that ceases to exist, but the French army of six hundred thousand, and +then Napoleonic France itself. To strain the facts to fit the rules of +history: to say that the field of battle at Borodino remained in the +hands of the Russians, or that after Moscow there were other battles +that destroyed Napoleon's army, is impossible. + +After the French victory at Borodino there was no general engagement +nor any that were at all serious, yet the French army ceased to exist. +What does this mean? If it were an example taken from the history of +China, we might say that it was not an historic phenomenon (which is +the historians' usual expedient when anything does not fit their +standards); if the matter concerned some brief conflict in which +only a small number of troops took part, we might treat it as an +exception; but this event occurred before our fathers' eyes, and for +them it was a question of the life or death of their fatherland, and +it happened in the greatest of all known wars. + +The period of the campaign of 1812 from the battle of Borodino to +the expulsion of the French proved that the winning of a battle does +not produce a conquest and is not even an invariable indication of +conquest; it proved that the force which decides the fate of peoples +lies not in the conquerors, nor even in armies and battles, but in +something else. + +The French historians, describing the condition of the French army +before it left Moscow, affirm that all was in order in the Grand Army, +except the cavalry, the artillery, and the transport--there was no +forage for the horses or the cattle. That was a misfortune no one +could remedy, for the peasants of the district burned their hay rather +than let the French have it. + +The victory gained did not bring the usual results because the +peasants Karp and Vlas (who after the French had evacuated Moscow +drove in their carts to pillage the town, and in general personally +failed to manifest any heroic feelings), and the whole innumerable +multitude of such peasants, did not bring their hay to Moscow for +the high price offered them, but burned it instead. + +Let us imagine two men who have come out to fight a duel with +rapiers according to all the rules of the art of fencing. The +fencing has gone on for some time; suddenly one of the combatants, +feeling himself wounded and understanding that the matter is no joke +but concerns his life, throws down his rapier, and seizing the first +cudgel that comes to hand begins to brandish it. Then let us imagine +that the combatant who so sensibly employed the best and simplest +means to attain his end was at the same time influenced by +traditions of chivalry and, desiring to conceal the facts of the case, +insisted that he had gained his victory with the rapier according to +all the rules of art. One can imagine what confusion and obscurity +would result from such an account of the duel. + +The fencer who demanded a contest according to the rules of +fencing was the French army; his opponent who threw away the rapier +and snatched up the cudgel was the Russian people; those who try to +explain the matter according to the rules of fencing are the +historians who have described the event. + +After the burning of Smolensk a war began which did not follow any +previous traditions of war. The burning of towns and villages, the +retreats after battles, the blow dealt at Borodino and the renewed +retreat, the burning of Moscow, the capture of marauders, the +seizure of transports, and the guerrilla war were all departures +from the rules. + +Napoleon felt this, and from the time he took up the correct fencing +attitude in Moscow and instead of his opponent's rapier saw a cudgel +raised above his head, he did not cease to complain to Kutuzov and +to the Emperor Alexander that the war was being carried on contrary to +all the rules--as if there were any rules for killing people. In spite +of the complaints of the French as to the nonobservance of the +rules, in spite of the fact that to some highly placed Russians it +seemed rather disgraceful to fight with a cudgel and they wanted to +assume a pose en quarte or en tierce according to all the rules, and +to make an adroit thrust en prime, and so on--the cudgel of the +people's war was lifted with all its menacing and majestic strength, +and without consulting anyone's tastes or rules and regardless of +anything else, it rose and fell with stupid simplicity, but +consistently, and belabored the French till the whole invasion had +perished. + +And it is well for a people who do not--as the French did in 1813- +salute according to all the rules of art, and, presenting the hilt +of their rapier gracefully and politely, hand it to their +magnanimous conqueror, but at the moment of trial, without asking what +rules others have adopted in similar cases, simply and easily pick +up the first cudgel that comes to hand and strike with it till the +feeling of resentment and revenge in their soul yields to a feeling of +contempt and compassion. + + + + + +CHAPTER II + + +One of the most obvious and advantageous departures from the +so-called laws of war is the action of scattered groups against men +pressed together in a mass. Such action always occurs in wars that +take on a national character. In such actions, instead of two crowds +opposing each other, the men disperse, attack singly, run away when +attacked by stronger forces, but again attack when opportunity offers. +This was done by the guerrillas in Spain, by the mountain tribes in +the Caucasus, and by the Russians in 1812. + +People have called this kind of war "guerrilla warfare" and assume +that by so calling it they have explained its meaning. But such a +war does not fit in under any rule and is directly opposed to a +well-known rule of tactics which is accepted as infallible. That +rule says that an attacker should concentrate his forces in order to +be stronger than his opponent at the moment of conflict. + +Guerrilla war (always successful, as history shows) directly +infringes that rule. + +This contradiction arises from the fact that military science +assumes the strength of an army to be identical with its numbers. +Military science says that the more troops the greater the strength. +Les gros bataillons ont toujours raison.* + + +*Large battalions are always victorious. + + +For military science to say this is like defining momentum in +mechanics by reference to the mass only: stating that momenta are +equal or unequal to each other simply because the masses involved +are equal or unequal. + +Momentum (quantity of motion) is the product of mass and velocity. + +In military affairs the strength of an army is the product of its +mass and some unknown x. + +Military science, seeing in history innumerable instances of the +fact that the size of any army does not coincide with its strength and +that small detachments defeat larger ones, obscurely admits the +existence of this unknown factor and tries to discover it--now in a +geometric formation, now in the equipment employed, now, and most +usually, in the genius of the commanders. But the assignment of +these various meanings to the factor does not yield results which +accord with the historic facts. + +Yet it is only necessary to abandon the false view (adopted to +gratify the "heroes") of the efficacy of the directions issued in +wartime by commanders, in order to find this unknown quantity. + +That unknown quantity is the spirit of the army, that is to say, the +greater or lesser readiness to fight and face danger felt by all the +men composing an army, quite independently of whether they are, or are +not, fighting under the command of a genius, in two--or three-line +formation, with cudgels or with rifles that repeat thirty times a +minute. Men who want to fight will always put themselves in the most +advantageous conditions for fighting. + +The spirit of an army is the factor which multiplied by the mass +gives the resulting force. To define and express the significance of +this unknown factor--the spirit of an army--is a problem for science. + +This problem is only solvable if we cease arbitrarily to +substitute for the unknown x itself the conditions under which that +force becomes apparent--such as the commands of the general, the +equipment employed, and so on--mistaking these for the real +significance of the factor, and if we recognize this unknown +quantity in its entirety as being the greater or lesser desire to +fight and to face danger. Only then, expressing known historic facts +by equations and comparing the relative significance of this factor, +can we hope to define the unknown. + +Ten men, battalions, or divisions, fighting fifteen men, battalions, +or divisions, conquer--that is, kill or take captive--all the +others, while themselves losing four, so that on the one side four and +on the other fifteen were lost. Consequently the four were equal to +the fifteen, and therefore 4x = 15y. Consequently x/y = 15/4. This +equation does not give us the value of the unknown factor but gives us +a ratio between two unknowns. And by bringing variously selected +historic units (battles, campaigns, periods of war) into such +equations, a series of numbers could be obtained in which certain laws +should exist and might be discovered. + +The tactical rule that an army should act in masses when +attacking, and in smaller groups in retreat, unconsciously confirms +the truth that the strength of an army depends on its spirit. To +lead men forward under fire more discipline (obtainable only by +movement in masses) is needed than is needed to resist attacks. But +this rule which leaves out of account the spirit of the army +continually proves incorrect and is in particularly striking +contrast to the facts when some strong rise or fall in the spirit of +the troops occurs, as in all national wars. + +The French, retreating in 1812--though according to tactics they +should have separated into detachments to defend themselves- +congregated into a mass because the spirit of the army had so fallen +that only the mass held the army together. The Russians, on the +contrary, ought according to tactics to have attacked in mass, but +in fact they split up into small units, because their spirit had so +risen that separate individuals, without orders, dealt blows at the +French without needing any compulsion to induce them to expose +themselves to hardships and dangers. + + + + + +CHAPTER III + + +The so-called partisan war began with the entry of the French into +Smolensk. + +Before partisan warfare had been officially recognized by the +government, thousands of enemy stragglers, marauders, and foragers had +been destroyed by the Cossacks and the peasants, who killed them off +as instinctively as dogs worry a stray mad dog to death. Denis +Davydov, with his Russian instinct, was the first to recognize the +value of this terrible cudgel which regardless of the rules of +military science destroyed the French, and to him belongs the credit +for taking the first step toward regularizing this method of warfare. + +On August 24 Davydov's first partisan detachment was formed and then +others were recognized. The further the campaign progressed the more +numerous these detachments became. + +The irregulars destroyed the great army piecemeal. They gathered the +fallen leaves that dropped of themselves from that withered tree- +the French army--and sometimes shook that tree itself. By October, +when the French were fleeing toward Smolensk, there were hundreds of +such companies, of various sizes and characters. There were some +that adopted all the army methods and had infantry, artillery, staffs, +and the comforts of life. Others consisted solely of Cossack +cavalry. There were also small scratch groups of foot and horse, and +groups of peasants and landowners that remained unknown. A sacristan +commanded one party which captured several hundred prisoners in the +course of a month; and there was Vasilisa, the wife of a village +elder, who slew hundreds of the French. + +The partisan warfare flamed up most fiercely in the latter days of +October. Its first period had passed: when the partisans themselves, +amazed at their own boldness, feared every minute to be surrounded and +captured by the French, and hid in the forests without unsaddling, +hardly daring to dismount and always expecting to be pursued. By the +end of October this kind of warfare had taken definite shape: it had +become clear to all what could be ventured against the French and what +could not. Now only the commanders of detachments with staffs, and +moving according to rules at a distance from the French, still +regarded many things as impossible. The small bands that had started +their activities long before and had already observed the French +closely considered things possible which the commanders of the big +detachments did not dare to contemplate. The Cossacks and peasants who +crept in among the French now considered everything possible. + +On October 22, Denisov (who was one of the irregulars) was with +his group at the height of the guerrilla enthusiasm. Since early +morning he and his party had been on the move. All day long he had +been watching from the forest that skirted the highroad a large French +convoy of cavalry baggage and Russian prisoners separated from the +rest of the army, which--as was learned from spies and prisoners- +was moving under a strong escort to Smolensk. Besides Denisov and +Dolokhov (who also led a small party and moved in Denisov's vicinity), +the commanders of some large divisions with staffs also knew of this +convoy and, as Denisov expressed it, were sharpening their teeth for +it. Two of the commanders of large parties--one a Pole and the other a +German--sent invitations to Denisov almost simultaneously, +requesting him to join up with their divisions to attack the convoy. + +"No, bwother, I have gwown mustaches myself," said Denisov on +reading these documents, and he wrote to the German that, despite +his heartfelt desire to serve under so valiant and renowned a general, +he had to forgo that pleasure because he was already under the command +of the Polish general. To the Polish general he replied to the same +effect, informing him that he was already under the command of the +German. + +Having arranged matters thus, Denisov and Dolokhov intended, without +reporting matters to the higher command, to attack and seize that +convoy with their own small forces. On October 22 it was moving from +the village of Mikulino to that of Shamshevo. To the left of the +road between Mikulino and Shamshevo there were large forests, +extending in some places up to the road itself though in others a mile +or more back from it. Through these forests Denisov and his party rode +all day, sometimes keeping well back in them and sometimes coming to +the very edge, but never losing sight of the moving French. That +morning, Cossacks of Denisov's party had seized and carried off into +the forest two wagons loaded with cavalry saddles, which had stuck +in the mud not far from Mikulino where the forest ran close to the +road. Since then, and until evening, the party had the movements of +the French without attacking. It was necessary to let the French reach +Shamshevo quietly without alarming them and then, after joining +Dolokhov who was to come that evening to a consultation at a +watchman's hut in the forest less than a mile from Shamshevo, to +surprise the French at dawn, falling like an avalanche on their +heads from two sides, and rout and capture them all at one blow. + +In their rear, more than a mile from Mikulino where the forest +came right up to the road, six Cossacks were posted to report if any +fresh columns of French should show themselves. + +Beyond Shamshevo, Dolokhov was to observe the road in the same +way, to find out at what distance there were other French troops. They +reckoned that the convoy had fifteen hundred men. Denisov had two +hundred, and Dolokhov might have as many more, but the disparity of +numbers did not deter Denisov. All that he now wanted to know was what +troops these were and to learn that he had to capture a "tongue"--that +is, a man from the enemy column. That morning's attack on the wagons +had been made so hastily that the Frenchmen with the wagons had all +been killed; only a little drummer boy had been taken alive, and as he +was a straggler he could tell them nothing definite about the troops +in that column. + +Denisov considered it dangerous to make a second attack for fear +of putting the whole column on the alert, so he sent Tikhon +Shcherbaty, a peasant of his party, to Shamshevo to try and seize at +least one of the French quartermasters who had been sent on in +advance. + + + + +CHAPTER IV + + +It was a warm rainy autumn day. The sky and the horizon were both +the color of muddy water. At times a sort of mist descended, and +then suddenly heavy slanting rain came down. + +Denisov in a felt cloak and a sheepskin cap from which the rain +ran down was riding a thin thoroughbred horse with sunken sides. +Like his horse, which turned its head and laid its ears back, he +shrank from the driving rain and gazed anxiously before him. His +thin face with its short, thick black beard looked angry. + +Beside Denisov rode an esaul,* Denisov's fellow worker, also in felt +cloak and sheepskin cap, and riding a large sleek Don horse. + + +*A captain of Cossacks. + + +Esaul Lovayski the Third was a tall man as straight as an arrow, +pale-faced, fair-haired, with narrow light eyes and with calm +self-satisfaction in his face and bearing. Though it was impossible to +say in what the peculiarity of the horse and rider lay, yet at first +glance at the esaul and Denisov one saw that the latter was wet and +uncomfortable and was a man mounted on a horse, while looking at the +esaul one saw that he was as comfortable and as much at ease as always +and that he was not a man who had mounted a horse, but a man who was +one with his horse, a being consequently possessed of twofold +strength. + +A little ahead of them walked a peasant guide, wet to the skin and +wearing a gray peasant coat and a white knitted cap. + +A little behind, on a poor, small, lean Kirghiz mount with an +enormous tail and mane and a bleeding mouth, rode a young officer in a +blue French overcoat. + +Beside him rode an hussar, with a boy in a tattered French uniform +and blue cap behind him on the crupper of his horse. The boy held on +to the hussar with cold, red hands, and raising his eyebrows gazed +about him with surprise. This was the French drummer boy captured that +morning. + +Behind them along the narrow, sodden, cutup forest road came hussars +in threes and fours, and then Cossacks: some in felt cloaks, some in +French greatcoats, and some with horsecloths over their heads. The +horses, being drenched by the rain, all looked black whether +chestnut or bay. Their necks, with their wet, close-clinging manes, +looked strangely thin. Steam rose from them. Clothes, saddles, +reins, were all wet, slippery, and sodden, like the ground and the +fallen leaves that strewed the road. The men sat huddled up trying not +to stir, so as to warm the water that had trickled to their bodies and +not admit the fresh cold water that was leaking in under their +seats, their knees, and at the back of their necks. In the midst of +the outspread line of Cossacks two wagons, drawn by French horses +and by saddled Cossack horses that had been hitched on in front, +rumbled over the tree stumps and branches and splashed through the +water that lay in the ruts. + +Denisov's horse swerved aside to avoid a pool in the track and +bumped his rider's knee against a tree. + +"Oh, the devil!" exclaimed Denisov angrily, and showing his teeth he +struck his horse three times with his whip, splashing himself and +his comrades with mud. + +Denisov was out of sorts both because of the rain and also from +hunger (none of them had eaten anything since morning), and yet more +because he still had no news from Dolokhov and the man sent to capture +a "tongue" had not returned. + +"There'll hardly be another such chance to fall on a transport as +today. It's too risky to attack them by oneself, and if we put it +off till another day one of the big guerrilla detachments will +snatch the prey from under our noses," thought Denisov, continually +peering forward, hoping to see a messenger from Dolokhov. + +On coming to a path in the forest along which he could see far to +the right, Denisov stopped. + +"There's someone coming," said he. + +The esaul looked in the direction Denisov indicated. + +"There are two, an officer and a Cossack. But it is not +presupposable that it is the lieutenant colonel himself," said the +esaul, who was fond of using words the Cossacks did not know. + +The approaching riders having descended a decline were no longer +visible, but they reappeared a few minutes later. In front, at a weary +gallop and using his leather whip, rode an officer, disheveled and +drenched, whose trousers had worked up to above his knees. Behind him, +standing in the stirrups, trotted a Cossack. The officer, a very young +lad with a broad rosy face and keen merry eyes, galloped up to Denisov +and handed him a sodden envelope. + +"From the general," said the officer. "Please excuse its not being +quite dry." + +Denisov, frowning, took the envelope and opened it. + +"There, they kept telling us: 'It's dangerous, it's dangerous,'" +said the officer, addressing the esaul while Denisov was reading the +dispatch. "But Komarov and I"--he pointed to the Cossack--"were +prepared. We have each of us two pistols.... But what's this?" he +asked, noticing the French drummer boy. "A prisoner? You've already +been in action? May I speak to him?" + +"Wostov! Petya!" exclaimed Denisov, having run through the dispatch. +"Why didn't you say who you were?" and turning with a smile he held +out his hand to the lad. + +The officer was Petya Rostov. + +All the way Petya had been preparing himself to behave with +Denisov as befitted a grownup man and an officer--without hinting at +their previous acquaintance. But as soon as Denisov smiled at him +Petya brightened up, blushed with pleasure, forgot the official manner +he had been rehearsing, and began telling him how he had already +been in a battle near Vyazma and how a certain hussar had +distinguished himself there. + +"Well, I am glad to see you," Denisov interrupted him, and his +face again assumed its anxious expression. + +"Michael Feoklitych," said he to the esaul, "this is again fwom that +German, you know. He"--he indicated Petya--"is serving under him." + +And Denisov told the esaul that the dispatch just delivered was a +repetition of the German general's demand that he should join forces +with him for an attack on the transport. + +"If we don't take it tomowwow, he'll snatch it fwom under our +noses," he added. + +While Denisov was talking to the esaul, Petya--abashed by +Denisov's cold tone and supposing that it was due to the condition +of his trousers--furtively tried to pull them down under his greatcoat +so that no one should notice it, while maintaining as martial an air +as possible. + +"Will there be any orders, your honor?" he asked Denisov, holding +his hand at the salute and resuming the game of adjutant and general +for which he had prepared himself, "or shall I remain with your +honor?" + +"Orders?" Denisov repeated thoughtfully. "But can you stay till +tomowwow?" + +"Oh, please... May I stay with you?" cried Petya. + +"But, just what did the genewal tell you? To weturn at once?" +asked Denisov. + +Petya blushed. + +"He gave me no instructions. I think I could?" he returned, +inquiringly. + +"Well, all wight," said Denisov. + +And turning to his men he directed a party to go on to the halting +place arranged near the watchman's hut in the forest, and told the +officer on the Kirghiz horse (who performed the duties of an adjutant) +to go and find out where Dolokhov was and whether he would come that +evening. Denisov himself intended going with the esaul and Petya to +the edge of the forest where it reached out to Shamshevo, to have a +look at the part of the French bivouac they were to attack next day. + +"Well, old fellow," said he to the peasant guide, "lead us to +Shamshevo." + +Denisov, Petya, and the esaul, accompanied by some Cossacks and +the hussar who had the prisoner, rode to the left across a ravine to +the edge of the forest. + + + + + +CHAPTER V + + +The rain had stopped, and only the mist was falling and drops from +the trees. Denisov, the esaul, and Petya rode silently, following +the peasant in the knitted cap who, stepping lightly with outturned +toes and moving noiselessly in his bast shoes over the roots and wet +leaves, silently led them to the edge of the forest. + +He ascended an incline, stopped, looked about him, and advanced to +where the screen of trees was less dense. On reaching a large oak tree +that had not yet shed its leaves, he stopped and beckoned mysteriously +to them with his hand. + +Denisov and Petya rode up to him. From the spot where the peasant +was standing they could see the French. Immediately beyond the forest, +on a downward slope, lay a field of spring rye. To the right, beyond a +steep ravine, was a small village and a landowner's house with a +broken roof. In the village, in the house, in the garden, by the well, +by the pond, over all the rising ground, and all along the road uphill +from the bridge leading to the village, not more than five hundred +yards away, crowds of men could be seen through the shimmering mist. +Their un-Russian shouting at their horses which were straining +uphill with the carts, and their calls to one another, could be +clearly heard. + +"Bwing the prisoner here," said Denisov in a low voice, not taking +his eyes off the French. + +A Cossack dismounted, lifted the boy down, and took him to +Denisov. Pointing to the French troops, Denisov asked him what these +and those of them were. The boy, thrusting his cold hands into his +pockets and lifting his eyebrows, looked at Denisov in affright, but +in spite of an evident desire to say all he knew gave confused +answers, merely assenting to everything Denisov asked him. Denisov +turned away from him frowning and addressed the esaul, conveying his +own conjectures to him. + +Petya, rapidly turning his head, looked now at the drummer boy, +now at Denisov, now at the esaul, and now at the French in the village +and along the road, trying not to miss anything of importance. + +"Whether Dolokhov comes or not, we must seize it, eh?" said +Denisov with a merry sparkle in his eyes. + +"It is a very suitable spot," said the esaul. + +"We'll send the infantwy down by the swamps," Denisov continued. +"They'll cweep up to the garden; you'll wide up fwom there with the +Cossacks"--he pointed to a spot in the forest beyond the village--"and +I with my hussars fwom here. And at the signal shot..." + +"The hollow is impassable--there's a swamp there," said the esaul. +"The horses would sink. We must ride round more to the left...." + +While they were talking in undertones the crack of a shot sounded +from the low ground by the pond, a puff of white smoke appeared, +then another, and the sound of hundreds of seemingly merry French +voices shouting together came up from the slope. For a moment +Denisov and the esaul drew back. They were so near that they thought +they were the cause of the firing and shouting. But the firing and +shouting did not relate to them. Down below, a man wearing something +red was running through the marsh. The French were evidently firing +and shouting at him. + +"Why, that's our Tikhon," said the esaul. + +"So it is! It is!" + +"The wascal!" said Denisov. + +"He'll get away!" said the esaul, screwing up his eyes. + +The man whom they called Tikhon, having run to the stream, plunged +in so that the water splashed in the air, and, having disappeared +for an instant, scrambled out on all fours, all black with the wet, +and ran on. The French who had been pursuing him stopped. + +"Smart, that!" said the esaul. + +"What a beast!" said Denisov with his former look of vexation. "What +has he been doing all this time?" + +"Who is he?" asked Petya. + +"He's our plastun. I sent him to capture a 'tongue.'" + +"Oh, yes," said Petya, nodding at the first words Denisov uttered as +if he understood it all, though he really did not understand +anything of it. + +Tikhon Shcherbaty was one of the most indispensable men in their +band. He was a peasant from Pokrovsk, near the river Gzhat. When +Denisov had come to Pokrovsk at the beginning of his operations and +had as usual summoned the village elder and asked him what he knew +about the French, the elder, as though shielding himself, had replied, +as all village elders did, that he had neither seen nor heard anything +of them. But when Denisov explained that his purpose was to kill the +French, and asked if no French had strayed that way, the elder replied +that some "more-orderers" had really been at their village, but that +Tikhon Shcherbaty was the only man who dealt with such matters. +Denisov had Tikhon called and, having praised him for his activity, +said a few words in the elder's presence about loyalty to the Tsar and +the country and the hatred of the French that all sons of the +fatherland should cherish. + +"We don't do the French any harm," said Tikhon, evidently frightened +by Denisov's words. "We only fooled about with the lads for fun, you +know! We killed a score or so of 'more-orderers,' but we did no harm +else..." + +Next day when Denisov had left Pokrovsk, having quite forgotten +about this peasant, it was reported to him that Tikhon had attached +himself to their party and asked to be allowed to remain with it. +Denisov gave orders to let him do so. + +Tikhon, who at first did rough work, laying campfires, fetching +water, flaying dead horses, and so on, soon showed a great liking +and aptitude for partisan warfare. At night he would go out for +booty and always brought back French clothing and weapons, and when +told to would bring in French captives also. Denisov then relieved him +from drudgery and began taking him with him when he went out on +expeditions and had him enrolled among the Cossacks. + +Tikhon did not like riding, and always went on foot, never lagging +behind the cavalry. He was armed with a musketoon (which he carried +rather as a joke), a pike and an ax, which latter he used as a wolf +uses its teeth, with equal case picking fleas out of its fur or +crunching thick bones. Tikhon with equal accuracy would split logs +with blows at arm's length, or holding the head of the ax would cut +thin little pegs or carve spoons. In Denisov's party he held a +peculiar and exceptional position. When anything particularly +difficult or nasty had to be done--to push a cart out of the mud +with one's shoulders, pull a horse out of a swamp by its tail, skin +it, slink in among the French, or walk more than thirty miles in a +day--everybody pointed laughingly at Tikhon. + +"It won't hurt that devil--he's as strong as a horse!" they said +of him. + +Once a Frenchman Tikhon was trying to capture fired a pistol at +him and shot him in the fleshy part of the back. That wound (which +Tikhon treated only with internal and external applications of +vodka) was the subject of the liveliest jokes by the whole detachment- +jokes in which Tikhon readily joined. + +"Hallo, mate! Never again? Gave you a twist?" the Cossacks would +banter him. And Tikhon, purposely writhing and making faces, pretended +to be angry and swore at the French with the funniest curses. The only +effect of this incident on Tikhon was that after being wounded he +seldom brought in prisoners. + +He was the bravest and most useful man in the party. No one found +more opportunities for attacking, no one captured or killed more +Frenchmen, and consequently he was made the buffoon of all the +Cossacks and hussars and willingly accepted that role. Now he had been +sent by Denisov overnight to Shamshevo to capture a "tongue." But +whether because he had not been content to take only one Frenchman +or because he had slept through the night, he had crept by day into +some bushes right among the French and, as Denisov had witnessed +from above, had been detected by them. + + + + + +CHAPTER VI + + +After talking for some time with the esaul about next day's +attack, which now, seeing how near they were to the French, he +seemed to have definitely decided on, Denisov turned his horse and +rode back. + +"Now, my lad, we'll go and get dwy," he said to Petya. + +As they approached the watchhouse Denisov stopped, peering into +the forest. Among the trees a man with long legs and long, swinging +arms, wearing a short jacket, bast shoes, and a Kazan hat, was +approaching with long, light steps. He had a musketoon over his +shoulder and an ax stuck in his girdle. When he espied Denisov he +hastily threw something into the bushes, removed his sodden hat by its +floppy brim, and approached his commander. It was Tikhon. His wrinkled +and pockmarked face and narrow little eyes beamed with +self-satisfied merriment. He lifted his head high and gazed at Denisov +as if repressing a laugh. + +"Well, where did you disappear to?" inquired Denisov. + +"Where did I disappear to? I went to get Frenchmen," answered Tikhon +boldly and hurriedly, in a husky but melodious bass voice. + +"Why did you push yourself in there by daylight? You ass! Well, +why haven't you taken one?" + +"Oh, I took one all right," said Tikhon. + +"Where is he?" + +"You see, I took him first thing at dawn," Tikhon continued, +spreading out his flat feet with outturned toes in their bast shoes. +"I took him into the forest. Then I see he's no good and think I'll go +and fetch a likelier one." + +"You see?... What a wogue--it's just as I thought," said Denisov +to the esaul. "Why didn't you bwing that one?" + +"What was the good of bringing him?" Tikhon interrupted hastily +and angrily--"that one wouldn't have done for you. As if I don't +know what sort you want!" + +"What a bwute you are!... Well?" + +"I went for another one," Tikhon continued, "and I crept like this +through the wood and lay down." (He suddenly lay down on his stomach +with a supple movement to show how he had done it.) "One turned up and +I grabbed him, like this." (He jumped up quickly and lightly.) +"'Come along to the colonel,' I said. He starts yelling, and +suddenly there were four of them. They rushed at me with their +little swords. So I went for them with my ax, this way: 'What are +you up to?' says I. 'Christ be with you!'" shouted Tikhon, waving +his arms with an angry scowl and throwing out his chest. + +"Yes, we saw from the hill how you took to your heels through the +puddles!" said the esaul, screwing up his glittering eyes. + +Petya badly wanted to laugh, but noticed that they all refrained +from laughing. He turned his eyes rapidly from Tikhon's face to the +esaul's and Denisov's, unable to make out what it all meant. + +"Don't play the fool!" said Denisov, coughing angrily. "Why didn't +you bwing the first one?" + +Tikhon scratched his back with one hand and his head with the other, +then suddenly his whole face expanded into a beaming, foolish grin, +disclosing a gap where he had lost a tooth (that was why he was called +Shcherbaty--the gap-toothed). Denisov smiled, and Petya burst into a +peal of merry laughter in which Tikhon himself joined. + +"Oh, but he was a regular good-for-nothing," said Tikhon. "The +clothes on him--poor stuff! How could I bring him? And so rude, your +honor! Why, he says: 'I'm a general's son myself, I won't go!' he +says." + +"You are a bwute!" said Denisov. "I wanted to question..." + +"But I questioned him," said Tikhon. "He said he didn't know much. +'There are a lot of us,' he says, 'but all poor stuff--only soldiers +in name,' he says. 'Shout loud at them,' he says, 'and you'll take +them all,'" Tikhon concluded, looking cheerfully and resolutely into +Denisov's eyes. + +"I'll give you a hundwed sharp lashes--that'll teach you to play the +fool!" said Denisov severely. + +"But why are you angry?" remonstrated Tikhon, "just as if I'd +never seen your Frenchmen! Only wait till it gets dark and I'll +fetch you any of them you want--three if you like." + +"Well, let's go," said Denisov, and rode all the way to the +watchhouse in silence and frowning angrily. + +Tikhon followed behind and Petya heard the Cossacks laughing with +him and at him, about some pair of boots he had thrown into the +bushes. + +When the fit of laughter that had seized him at Tikhon's words and +smile had passed and Petya realized for a moment that this Tikhon +had killed a man, he felt uneasy. He looked round at the captive +drummer boy and felt a pang in his heart. But this uneasiness lasted +only a moment. He felt it necessary to hold his head higher, to +brace himself, and to question the esaul with an air of importance +about tomorrow's undertaking, that he might not be unworthy of the +company in which he found himself. + +The officer who had been sent to inquire met Denisov on the way with +the news that Dolokhov was soon coming and that all was well with him. + +Denisov at once cheered up and, calling Petya to him, said: "Well, +tell me about yourself." + + + + + +CHAPTER VII + + +Petya, having left his people after their departure from Moscow, +joined his regiment and was soon taken as orderly by a general +commanding a large guerrilla detachment. From the time he received his +commission, and especially since he had joined the active army and +taken part in the battle of Vyazma, Petya had been in a constant state +of blissful excitement at being grown-up and in a perpetual ecstatic +hurry not to miss any chance to do something really heroic. He was +highly delighted with what he saw and experienced in the army, but +at the same time it always seemed to him that the really heroic +exploits were being performed just where he did not happen to be. +And he was always in a hurry to get where he was not. + +When on the twenty-first of October his general expressed a wish +to send somebody to Denisov's detachment, Petya begged so piteously to +be sent that the general could not refuse. But when dispatching him he +recalled Petya's mad action at the battle of Vyazma, where instead +of riding by the road to the place to which he had been sent, he had +galloped to the advanced line under the fire of the French and had +there twice fired his pistol. So now the general explicitly forbade +his taking part in any action whatever of Denisov's. That was why +Petya had blushed and grown confused when Denisov asked him whether he +could stay. Before they had ridden to the outskirts of the forest +Petya had considered he must carry out his instructions strictly and +return at once. But when he saw the French and saw Tikhon and +learned that there would certainly be an attack that night, he +decided, with the rapidity with which young people change their views, +that the general, whom he had greatly respected till then, was a +rubbishy German, that Denisov was a hero, the esaul a hero, and Tikhon +a hero too, and that it would be shameful for him to leave them at a +moment of difficulty. + +It was already growing dusk when Denisov, Petya, and the esaul +rode up to the watchhouse. In the twilight saddled horses could be +seen, and Cossacks and hussars who had rigged up rough shelters in the +glade and were kindling glowing fires in a hollow of the forest +where the French could not see the smoke. In the passage of the +small watchhouse a Cossack with sleeves rolled up was chopping some +mutton. In the room three officers of Denisov's band were converting a +door into a tabletop. Petya took off his wet clothes, gave them to +be dried, and at once began helping the officers to fix up the +dinner table. + +In ten minutes the table was ready and a napkin spread on it. On the +table were vodka, a flask of rum, white bread, roast mutton, and salt. + +Sitting at table with the officers and tearing the fat savory mutton +with his hands, down which the grease trickled, Petya was in an +ecstatic childish state of love for all men, and consequently of +confidence that others loved him in the same way. + +"So then what do you think, Vasili Dmitrich?" said he to Denisov. +"It's all right my staying a day with you?" And not waiting for a +reply he answered his own question: "You see I was told to find out- +well, I am finding out.... Only do let me into the very... into the +chief... I don't want a reward... But I want..." + +Petya clenched his teeth and looked around, throwing back his head +and flourishing his arms. + +"Into the vewy chief..." Denisov repeated with a smile. + +"Only, please let me command something, so that I may really +command..." Petya went on. "What would it be to you?... Oh, you want a +knife?" he said, turning to an officer who wished to cut himself a +piece of mutton. + +And he handed him his clasp knife. The officer admired it. + +"Please keep it. I have several like it," said Petya, blushing. +"Heavens! I was quite forgetting!" he suddenly cried. "I have some +raisins, fine ones; you know, seedless ones. We have a new sutler +and he has such capital things. I bought ten pounds. I am used to +something sweet. Would you like some?..." and Petya ran out into the +passage to his Cossack and brought back some bags which contained +about five pounds of raisins. "Have some, gentlemen, have some!" + +"You want a coffeepot, don't you?" he asked the esaul. "I bought a +capital one from our sutler! He has splendid things. And he's very +honest, that's the chief thing. I'll be sure to send it to you. Or +perhaps your flints are giving out, or are worn out--that happens +sometimes, you know. I have brought some with me, here they are"- +and he showed a bag--"a hundred flints. I bought them very cheap. +Please take as many as you want, or all if you like...." + +Then suddenly, dismayed lest he had said too much, Petya stopped and +blushed. + +He tried to remember whether he had not done anything else that +was foolish. And running over the events of the day he remembered +the French drummer boy. "It's capital for us here, but what of him? +Where have they put him? Have they fed him? Haven't they hurt his +feelings?" he thought. But having caught himself saying too much about +the flints, he was now afraid to speak out. + +"I might ask," he thought, "but they'll say: 'He's a boy himself and +so he pities the boy.' I'll show them tomorrow whether I'm a boy. Will +it seem odd if I ask?" Petya thought. "Well, never mind!" and +immediately, blushing and looking anxiously at the officers to see +if they appeared ironical, he said: + +"May I call in that boy who was taken prisoner and give him +something to eat?... Perhaps..." + +"Yes, he's a poor little fellow," said Denisov, who evidently saw +nothing shameful in this reminder. "Call him in. His name is Vincent +Bosse. Have him fetched." + +"I'll call him," said Petya. + +"Yes, yes, call him. A poor little fellow," Denisov repeated. + +Petya was standing at the door when Denisov said this. He slipped in +between the officers, came close to Denisov, and said: + +"Let me kiss you, dear old fellow! Oh, how fine, how splendid!" + +And having kissed Denisov he ran out of the hut. + +"Bosse! Vincent!" Petya cried, stopping outside the door. + +"Who do you want, sir?" asked a voice in the darkness. + +Petya replied that he wanted the French lad who had been captured +that day. + +"Ah, Vesenny?" said a Cossack. + +Vincent, the boy's name, had already been changed by the Cossacks +into Vesenny (vernal) and into Vesenya by the peasants and soldiers. +In both these adaptations the reference to spring (vesna) matched +the impression made by the young lad. + +"He is warming himself there by the bonfire. Ho, Vesenya! +Vesenya!--Vesenny!" laughing voices were heard calling to one +another in the darkness. + +"He's a smart lad," said an hussar standing near Petya. "We gave him +something to eat a while ago. He was awfully hungry!" + +The sound of bare feet splashing through the mud was heard in the +darkness, and the drummer boy came to the door. + +"Ah, c'est vous!" said Petya. "Voulez-vous manger? N'ayez pas +peur, on ne vous fera pas de mal,"* he added shyly and affectionately, +touching the boy's hand. "Entrez, entrez."*[2] + + +*"Ah, it's you! Do you want something to eat? Don't be afraid, +they won't hurt you." + +*[2] "Come in, come in." + + +"Merci, monsieur,"* said the drummer boy in a trembling almost +childish voice, and he began scraping his dirty feet on the threshold. + + +*"Thank you, sir." + + +There were many things Petya wanted to say to the drummer boy, but +did not dare to. He stood irresolutely beside him in the passage. Then +in the darkness he took the boy's hand and pressed it. + +"Come in, come in!" he repeated in a gentle whisper. "Oh, what can I +do for him?" he thought, and opening the door he let the boy pass in +first. + +When the boy had entered the hut, Petya sat down at a distance +from him, considering it beneath his dignity to pay attention to +him. But he fingered the money in his pocket and wondered whether it +would seem ridiculous to give some to the drummer boy. + + + + + +CHAPTER VIII + + +The arrival of Dolokhov diverted Petya's attention from the +drummer boy, to whom Denisov had had some mutton and vodka given, +and whom he had had dressed in a Russian coat so that he might be kept +with their band and not sent away with the other prisoners. Petya +had heard in the army many stories of Dolokhov's extraordinary bravery +and of his cruelty to the French, so from the moment he entered the +hut Petya did not take his eyes from him, but braced himself up more +and more and held his head high, that he might not be unworthy even of +such company. + +Dolokhov's appearance amazed Petya by its simplicity. + +Denisov wore a Cossack coat, had a beard, had an icon of Nicholas +the Wonder-Worker on his breast, and his way of speaking and +everything he did indicated his unusual position. But Dolokhov, who in +Moscow had worn a Persian costume, had now the appearance of a most +correct officer of the Guards. He was clean-shaven and wore a +Guardsman's padded coat with an Order of St. George at his +buttonhole and a plain forage cap set straight on his head. He took +off his wet felt cloak in a corner of the room, and without greeting +anyone went up to Denisov and began questioning him about the matter +in hand. Denisov told him of the designs the large detachments had +on the transport, of the message Petya had brought, and his own +replies to both generals. Then he told him all he knew of the French +detachment. + +"That's so. But we must know what troops they are and their +numbers," said Dolokhov. "It will be necessary to go there. We can't +start the affair without knowing for certain how many there are. I +like to work accurately. Here now--wouldn't one of these gentlemen +like to ride over to the French camp with me? I have brought a spare +uniform." + +"I, I... I'll go with you!" cried Petya. + +"There's no need for you to go at all," said Denisov, addressing +Dolokhov, "and as for him, I won't let him go on any account." + +"I like that!" exclaimed Petya. "Why shouldn't I go?" + +"Because it's useless." + +"Well, you must excuse me, because... because... I shall go, and +that's all. You'll take me, won't you?" he said, turning to Dolokhov. + +"Why not?" Dolokhov answered absently, scrutinizing the face of +the French drummer boy. "Have you had that youngster with you long?" +he asked Denisov. + +"He was taken today but he knows nothing. I'm keeping him with me." + +"Yes, and where do you put the others?" inquired Dolokhov. + +"Where? I send them away and take a weceipt for them," shouted +Denisov, suddenly flushing. "And I say boldly that I have not a single +man's life on my conscience. Would it be difficult for you to send +thirty or thwee hundwed men to town under escort, instead of staining- +I speak bluntly--staining the honor of a soldier?" + +"That kind of amiable talk would be suitable from this young count +of sixteen," said Dolokhov with cold irony, "but it's time for you +to drop it." + +"Why, I've not said anything! I only say that I'll certainly go with +you," said Petya shyly. + +"But for you and me, old fellow, it's time to drop these amenities," +continued Dolokhov, as if he found particular pleasure in speaking +of this subject which irritated Denisov. "Now, why have you kept +this lad?" he went on, swaying his head. "Because you are sorry for +him! Don't we know those 'receipts' of yours? You send a hundred men +away, and thirty get there. The rest either starve or get killed. So +isn't it all the same not to send them?" + +The esaul, screwing up his light-colored eyes, nodded approvingly. + +"That's not the point. I'm not going to discuss the matter. I do not +wish to take it on my conscience. You say they'll die. All wight. Only +not by my fault!" + +Dolokhov began laughing. + +"Who has told them not to capture me these twenty times over? But if +they did catch me they'd string me up to an aspen tree, and with all +your chivalry just the same." He paused. "However, we must get to +work. Tell the Cossack to fetch my kit. I have two French uniforms +in it. Well, are you coming with me?" he asked Petya. + +"I? Yes, yes, certainly!" cried Petya, blushing almost to tears +and glancing at Denisov. + +While Dolokhov had been disputing with Denisov what should be done +with prisoners, Petya had once more felt awkward and restless; but +again he had no time to grasp fully what they were talking about. +"If grown-up, distinguished men think so, it must be necessary and +right," thought he. "But above all Denisov must not dare to imagine +that I'll obey him and that he can order me about. I will certainly go +to the French camp with Dolokhov. If he can, so can I!" + +And to all Denisov's persuasions, Petya replied that he too was +accustomed to do everything accurately and not just anyhow, and that +he never considered personal danger. + +"For you'll admit that if we don't know for sure how many of them +there are... hundreds of lives may depend on it, while there are +only two of us. Besides, I want to go very much and certainly will go, +so don't hinder me," said he. "It will only make things worse..." + + + + + +CHAPTER IX + + +Having put on French greatcoats and shakos, Petya and Dolokhov +rode to the clearing from which Denisov had reconnoitered the French +camp, and emerging from the forest in pitch darkness they descended +into the hollow. On reaching the bottom, Dolokhov told the Cossacks +accompanying him to await him there and rode on at a quick trot +along the road to the bridge. Petya, his heart in his mouth with +excitement, rode by his side. + +"If we're caught, I won't be taken alive! I have a pistol," +whispered he. + +"Don't talk Russian," said Dolokhov in a hurried whisper, and at +that very moment they heard through the darkness the challenge: "Qui +vive?"* and the click of a musket. + + +*"Who goes there?" + + +The blood rushed to Petya's face and he grasped his pistol. + +"Lanciers du 6-me,"* replied Dolokhov, neither hastening nor +slackening his horse's pace. + + +*"Lancers of the 6th Regiment." + + +The black figure of a sentinel stood on the bridge. + +"Mot d'ordre."* + + +*"Password." + + +Dolokhov reined in his horse and advanced at a walk. + +"Dites donc, le colonel Gerard est ici?"* he asked. + + +*"Tell me, is Colonel Gerard here?" + + +"Mot d'ordre," repeated the sentinel, barring the way and not +replying. + +"Quand un officier fait sa ronde, les sentinelles ne demandent pas +le mot d'ordre..." cried Dolokhov suddenly flaring up and riding +straight at the sentinel. "Je vous demande si le colonel est ici."* + + +*"When an officer is making his round, sentinels don't ask him for +the password.... I am asking you if the colonel is here." + + +And without waiting for an answer from the sentinel, who had stepped +aside, Dolokhov rode up the incline at a walk. + +Noticing the black outline of a man crossing the road, Dolokhov +stopped him and inquired where the commander and officers were. The +man, a soldier with a sack over his shoulder, stopped, came close up +to Dolokhov's horse, touched it with his hand, and explained simply +and in a friendly way that the commander and the officers were +higher up the hill to the right in the courtyard of the farm, as he +called the landowner's house. + +Having ridden up the road, on both sides of which French talk +could be heard around the campfires, Dolokhov turned into the +courtyard of the landowner's house. Having ridden in, he dismounted +and approached a big blazing campfire, around which sat several men +talking noisily. Something was boiling in a small cauldron at the edge +of the fire and a soldier in a peaked cap and blue overcoat, lit up by +the fire, was kneeling beside it stirring its contents with a ramrod. + +"Oh, he's a hard nut to crack," said one of the officers who was +sitting in the shadow at the other side of the fire. + +"He'll make them get a move on, those fellows!" said another, +laughing. + +Both fell silent, peering out through the darkness at the sound of +Dolokhov's and Petya's steps as they advanced to the fire leading +their horses. + +"Bonjour, messieurs!"* said Dolokhov loudly and clearly. + + +*"Good day, gentlemen." + + +There was a stir among the officers in the shadow beyond the fire, +and one tall, long-necked officer, walking round the fire, came up +to Dolokhov. + +"Is that you, Clement?" he asked. "Where the devil...?" But, noticing +his mistake, he broke off short and, with a frown, greeted Dolokhov as +a stranger, asking what he could do for him. + +Dolokhov said that he and his companion were trying to overtake +their regiment, and addressing the company in general asked whether +they knew anything of the 6th Regiment. None of them knew anything, +and Petya thought the officers were beginning to look at him and +Dolokhov with hostility and suspicion. For some seconds all were +silent. + +"If you were counting on the evening soup, you have come too +late," said a voice from behind the fire with a repressed laugh. + +Dolokhov replied that they were not hungry and must push on +farther that night. + +He handed the horses over to the soldier who was stirring the pot +and squatted down on his heels by the fire beside the officer with the +long neck. That officer did not take his eyes from Dolokhov and +again asked to what regiment he belonged. Dolokhov, as if he had not +heard the question, did not reply, but lighting a short French pipe +which he took from his pocket began asking the officer in how far +the road before them was safe from Cossacks. + +"Those brigands are everywhere," replied an officer from behind +the fire. + +Dolokhov remarked that the Cossacks were a danger only to stragglers +such as his companion and himself, "but probably they would not dare +to attack large detachments?" he added inquiringly. No one replied. + +"Well, now he'll come away," Petya thought every moment as he +stood by the campfire listening to the talk. + +But Dolokhov restarted the conversation which had dropped and +began putting direct questions as to how many men there were in the +battalion, how many battalions, and how many prisoners. Asking about +the Russian prisoners with that detachment, Dolokhov said: + +"A horrid business dragging these corpses about with one! It would +be better to shoot such rabble," and burst into loud laughter, so +strange that Petya thought the French would immediately detect their +disguise, and involuntarily took a step back from the campfire. + +No one replied a word to Dolokhov's laughter, and a French officer +whom they could not see (he lay wrapped in a greatcoat) rose and +whispered something to a companion. Dolokhov got up and called to +the soldier who was holding their horses. + +"Will they bring our horses or not?" thought Petya, instinctively +drawing nearer to Dolokhov. + +The horses were brought. + +"Good evening, gentlemen," said Dolokhov. + +Petya wished to say "Good night" but could not utter a word. The +officers were whispering together. Dolokhov was a long time mounting +his horse which would not stand still, then he rode out of the yard at +a footpace. Petya rode beside him, longing to look round to see +whether or no the French were running after them, but not daring to. + +Coming out onto the road Dolokhov did not ride back across the +open country, but through the village. At one spot he stopped and +listened. "Do you hear?" he asked. Petya recognized the sound of +Russian voices and saw the dark figures of Russian prisoners round +their campfires. When they had descended to the bridge Petya and +Dolokhov rode past the sentinel, who without saying a word paced +morosely up and down it, then they descended into the hollow where the +Cossacks awaited them. + +"Well now, good-by. Tell Denisov, 'at the first shot at +daybreak,'" said Dolokhov and was about to ride away, but Petya seized +hold of him. + +"Really!" he cried, "you are such a hero! Oh, how fine, how +splendid! How I love you!" + +"All right, all right!" said Dolokhov. But Petya did not let go of +him and Dolokhov saw through the gloom that Petya was bending toward +him and wanted to kiss him. Dolokhov kissed him, laughed, turned his +horse, and vanished into the darkness. + + + + + +CHAPTER X + + +Having returned to the watchman's hut, Petya found Denisov in the +passage. He was awaiting Petya's return in a state of agitation, +anxiety, and self-reproach for having let him go. + +"Thank God!" he exclaimed. "Yes, thank God!" he repeated, +listening to Petya's rapturous account. "But, devil take you, I +haven't slept because of you! Well, thank God. Now lie down. We can +still get a nap before morning." + +"But... no," said Petya, "I don't want to sleep yet. Besides I +know myself, if I fall asleep it's finished. And then I am used to not +sleeping before a battle." + +He sat awhile in the hut joyfully recalling the details of his +expedition and vividly picturing to himself what would happen next +day. + +Then, noticing that Denisov was asleep, he rose and went out of +doors. + +It was still quite dark outside. The rain was over, but drops were +still falling from the trees. Near the watchman's hut the black shapes +of the Cossacks' shanties and of horses tethered together could be +seen. Behind the hut the dark shapes of the two wagons with their +horses beside them were discernible, and in the hollow the dying +campfire gleamed red. Not all the Cossacks and hussars were asleep; +here and there, amid the sounds of falling drops and the munching of +the horses near by, could be heard low voices which seemed to be +whispering. + +Petya came out, peered into the darkness, and went up to the wagons. +Someone was snoring under them, and around them stood saddled horses +munching their oats. In the dark Petya recognized his own horse, which +he called "Karabakh" though it was of Ukranian breed, and went up to +it. + +"Well, Karabakh! We'll do some service tomorrow," said he, +sniffing its nostrils and kissing it. + +"Why aren't you asleep, sir?" said a Cossack who was sitting under a +wagon. + +"No, ah... Likhachev--isn't that your name? Do you know I have +only just come back! We've been into the French camp." + +And Petya gave the Cossack a detailed account not only of his ride +but also of his object, and why he considered it better to risk his +life than to act "just anyhow." + +"Well, you should get some sleep now," said the Cossack. + +"No, I am used to this," said Petya. "I say, aren't the flints in +your pistols worn out? I brought some with me. Don't you want any? You +can have some." + + +The Cossack bent forward from under the wagon to get a closer look +at Petya. + +"Because I am accustomed to doing everything accurately," said +Petya. "Some fellows do things just anyhow, without preparation, and +then they're sorry for it afterwards. I don't like that." + +"Just so," said the Cossack. + +"Oh yes, another thing! Please, my dear fellow, will you sharpen +my saber for me? It's got bl..." (Petya feared to tell a lie, and +the saber never had been sharpened.) "Can you do it?" + +"Of course I can." + +Likhachev got up, rummaged in his pack, and soon Petya heard the +warlike sound of steel on whetstone. He climbed onto the wagon and sat +on its edge. The Cossack was sharpening the saber under the wagon. + +"I say! Are the lads asleep?" asked Petya. + +"Some are, and some aren't--like us." + +"Well, and that boy?" + +"Vesenny? Oh, he's thrown himself down there in the passage. Fast +asleep after his fright. He was that glad!" + +After that Petya remained silent for a long time, listening to the +sounds. He heard footsteps in the darkness and a black figure +appeared. + +"What are you sharpening?" asked a man coming up to the wagon. + +"Why, this gentleman's saber." + +"That's right," said the man, whom Petya took to be an hussar. +"Was the cup left here?" + +"There, by the wheel!" + +The hussar took the cup. + +"It must be daylight soon," said he, yawning, and went away. + +Petya ought to have known that he was in a forest with Denisov's +guerrilla band, less than a mile from the road, sitting on a wagon +captured from the French beside which horses were tethered, that under +it Likhachev was sitting sharpening a saber for him, that the big dark +blotch to the right was the watchman's hut, and the red blotch below +to the left was the dying embers of a campfire, that the man who had +come for the cup was an hussar who wanted a drink; but he neither knew +nor waited to know anything of all this. He was in a fairy kingdom +where nothing resembled reality. The big dark blotch might really be +the watchman's hut or it might be a cavern leading to the very +depths of the earth. Perhaps the red spot was a fire, or it might be +the eye of an enormous monster. Perhaps he was really sitting on a +wagon, but it might very well be that he was not sitting on a wagon +but on a terribly high tower from which, if he fell, he would have +to fall for a whole day or a whole month, or go on falling and never +reach the bottom. Perhaps it was just the Cossack, Likhachev, who +was sitting under the wagon, but it might be the kindest, bravest, +most wonderful, most splendid man in the world, whom no one knew of. +It might really have been that the hussar came for water and went back +into the hollow, but perhaps he had simply vanished--disappeared +altogether and dissolved into nothingness. + +Nothing Petya could have seen now would have surprised him. He was +in a fairy kingdom where everything was possible. + +He looked up at the sky. And the sky was a fairy realm like the +earth. It was clearing, and over the tops of the trees clouds were +swiftly sailing as if unveiling the stars. Sometimes it looked as if +the clouds were passing, and a clear black sky appeared. Sometimes +it seemed as if the black spaces were clouds. Sometimes the sky seemed +to be rising high, high overhead, and then it seemed to sink so low +that one could touch it with one's hand. + +Petya's eyes began to close and he swayed a little. + +The trees were dripping. Quiet talking was heard. The horses neighed +and jostled one another. Someone snored. + +"Ozheg-zheg, Ozheg-zheg..." hissed the saber against the +whetstone, and suddenly Petya heard an harmonious orchestra playing +some unknown, sweetly solemn hymn. Petya was as musical as Natasha and +more so than Nicholas, but had never learned music or thought about +it, and so the melody that unexpectedly came to his mind seemed to him +particularly fresh and attractive. The music became more and more +audible. The melody grew and passed from one instrument to another. +And what was played was a fugue--though Petya had not the least +conception of what a fugue is. Each instrument--now resembling a +violin and now a horn, but better and clearer than violin or horn- +played its own part, and before it had finished the melody merged with +another instrument that began almost the same air, and then with a +third and a fourth; and they all blended into one and again became +separate and again blended, now into solemn church music, now into +something dazzlingly brilliant and triumphant. + +"Oh--why, that was in a dream!" Petya said to himself, as he lurched +forward. "It's in my ears. But perhaps it's music of my own. Well, +go on, my music! Now!..." + +He closed his eyes, and, from all sides as if from a distance, +sounds fluttered, grew into harmonies, separated, blended, and again +all mingled into the same sweet and solemn hymn. "Oh, this is +delightful! As much as I like and as I like!" said Petya to himself. +He tried to conduct that enormous orchestra. + +"Now softly, softly die away!" and the sounds obeyed him. "Now +fuller, more joyful. Still more and more joyful!" And from an +unknown depth rose increasingly triumphant sounds. "Now voices join +in!" ordered Petya. And at first from afar he heard men's voices and +then women's. The voices grew in harmonious triumphant strength, and +Petya listened to their surpassing beauty in awe and joy. + +With a solemn triumphal march there mingled a song, the drip from +the trees, and the hissing of the saber, "Ozheg-zheg-zheg..." and +again the horses jostled one another and neighed, not disturbing the +choir but joining in it. + +Petya did not know how long this lasted: he enjoyed himself all +the time, wondered at his enjoyment and regretted that there was no +one to share it. He was awakened by Likhachev's kindly voice. + +"It's ready, your honor; you can split a Frenchman in half with it!" + +Petya woke up. + +"It's getting light, it's really getting light!" he exclaimed. + +The horses that had previously been invisible could now be seen to +their very tails, and a watery light showed itself through the bare +branches. Petya shook himself, jumped up, took a ruble from his pocket +and gave it to Likhachev; then he flourished the saber, tested it, and +sheathed it. The Cossacks were untying their horses and tightening +their saddle girths. + +"And here's the commander," said Likhachev. + +Denisov came out of the watchman's hut and, having called Petya, +gave orders to get ready. + + + + +CHAPTER XI + + +The men rapidly picked out their horses in the semidarkness, +tightened their saddle girths, and formed companies. Denisov stood +by the watchman's hut giving final orders. The infantry of the +detachment passed along the road and quickly disappeared amid the +trees in the mist of early dawn, hundreds of feet splashing through +the mud. The esaul gave some orders to his men. Petya held his horse +by the bridle, impatiently awaiting the order to mount. His face, +having been bathed in cold water, was all aglow, and his eyes were +particularly brilliant. Cold shivers ran down his spine and his +whole body pulsed rhythmically. + +"Well, is ev'wything weady?" asked Denisov. "Bwing the horses." + +The horses were brought. Denisov was angry with the Cossack +because the saddle girths were too slack, reproved him, and mounted. +Petya put his foot in the stirrup. His horse by habit made as if to +nip his leg, but Petya leaped quickly into the saddle unconscious of +his own weight and, turning to look at the hussars starting in the +darkness behind him, rode up to Denisov. + +"Vasili Dmitrich, entrust me with some commission! Please... for +God's sake...!" said he. + +Denisov seemed to have forgotten Petya's very existence. He turned +to glance at him. + +"I ask one thing of you," he said sternly, "to obey me and not shove +yourself forward anywhere." + +He did not say another word to Petya but rode in silence all the +way. When they had come to the edge of the forest it was noticeably +growing light over the field. Denisov talked in whispers with the +esaul and the Cossacks rode past Petya and Denisov. When they had +all ridden by, Denisov touched his horse and rode down the hill. +Slipping onto their haunches and sliding, the horses descended with +their riders into the ravine. Petya rode beside Denisov, the pulsation +of his body constantly increasing. It was getting lighter and lighter, +but the mist still hid distant objects. Having reached the valley, +Denisov looked back and nodded to a Cossack beside him. + +"The signal!" said he. + +The Cossack raised his arm and a shot rang out. In an instant the +tramp of horses galloping forward was heard, shouts came from +various sides, and then more shots. + +At the first sound of trampling hoofs and shouting, Petya lashed his +horse and loosening his rein galloped forward, not heeding Denisov who +shouted at him. It seemed to Petya that at the moment the shot was +fired it suddenly became as bright as noon. He galloped to the bridge. +Cossacks were galloping along the road in front of him. On the +bridge he collided with a Cossack who had fallen behind, but he +galloped on. In front of him soldiers, probably Frenchmen, were +running from right to left across the road. One of them fell in the +mud under his horse's feet. + +Cossacks were crowding about a hut, busy with something. From the +midst of that crowd terrible screams arose. Petya galloped up, and the +first thing he saw was the pale face and trembling jaw of a Frenchman, +clutching the handle of a lance that had been aimed at him. + +"Hurrah!... Lads!... ours!" shouted Petya, and giving rein to his +excited horse he galloped forward along the village street. + +He could hear shooting ahead of him. Cossacks, hussars, and ragged +Russian prisoners, who had come running from both sides of the road, +were shouting something loudly and incoherently. A gallant-looking +Frenchman, in a blue overcoat, capless, and with a frowning red +face, had been defending himself against the hussars. When Petya +galloped up the Frenchman had already fallen. "Too late again!" +flashed through Petya's mind and he galloped on to the place from +which the rapid firing could be heard. The shots came from the yard of +the landowner's house he had visited the night before with Dolokhov. +The French were making a stand there behind a wattle fence in a garden +thickly overgrown with bushes and were firing at the Cossacks who +crowded at the gateway. Through the smoke, as he approached the +gate, Petya saw Dolokhov, whose face was of a pale-greenish tint, +shouting to his men. "Go round! Wait for the infantry!" he exclaimed +as Petya rode up to him. + +"Wait?... Hurrah-ah-ah!" shouted Petya, and without pausing a moment +galloped to the place whence came the sounds of firing and where the +smoke was thickest. + +A volley was heard, and some bullets whistled past, while others +plashed against something. The Cossacks and Dolokhov galloped after +Petya into the gateway of the courtyard. In the dense wavering smoke +some of the French threw down their arms and ran out of the bushes +to meet the Cossacks, while others ran down the hill toward the +pond. Petya was galloping along the courtyard, but instead of +holding the reins he waved both his arms about rapidly and +strangely, slipping farther and farther to one side in his saddle. His +horse, having galloped up to a campfire that was smoldering in the +morning light, stopped suddenly, and Petya fell heavily on to the +wet ground. The Cossacks saw that his arms and legs jerked rapidly +though his head was quite motionless. A bullet had pierced his skull. + +After speaking to the senior French officer, who came out of the +house with a white handkerchief tied to his sword and announced that +they surrendered, Dolokhov dismounted and went up to Petya, who lay +motionless with outstretched arms. + +"Done for!" he said with a frown, and went to the gate to meet +Denisov who was riding toward him. + +"Killed?" cried Denisov, recognizing from a distance the +unmistakably lifeless attitude--very familiar to him--in which Petya's +body was lying. + +"Done for!" repeated Dolokhov as if the utterance of these words +afforded him pleasure, and he went quickly up to the prisoners, who +were surrounded by Cossacks who had hurried up. "We won't take +them!" he called out to Denisov. + +Denisov did not reply; he rode up to Petya, dismounted, and with +trembling hands turned toward himself the bloodstained, +mud-bespattered face which had already gone white. + +"I am used to something sweet. Raisins, fine ones... take them all!" +he recalled Petya's words. And the Cossacks looked round in surprise +at the sound, like the yelp of a dog, with which Denisov turned +away, walked to the wattle fence, and seized hold of it. + +Among the Russian prisoners rescued by Denisov and Dolokhov was +Pierre Bezukhov. + + + + + +CHAPTER XII + +During the whole of their march from Moscow no fresh orders had been +issued by the French authorities concerning the party of prisoners +among whom was Pierre. On the twenty-second of October that party +was no longer with the same troops and baggage trains with which it +had left Moscow. Half the wagons laden with hardtack that had traveled +the first stages with them had been captured by Cossacks, the other +half had gone on ahead. Not one of those dismounted cavalrymen who had +marched in front of the prisoners was left; they had all +disappeared. The artillery the prisoners had seen in front of them +during the first days was now replaced by Marshal Junot's enormous +baggage train, convoyed by Westphalians. Behind the prisoners came a +cavalry baggage train. + +From Vyazma onwards the French army, which had till then moved in +three columns, went on as a single group. The symptoms of disorder +that Pierre had noticed at their first halting place after leaving +Moscow had now reached the utmost limit. + +The road along which they moved was bordered on both sides by dead +horses; ragged men who had fallen behind from various regiments +continually changed about, now joining the moving column, now again +lagging behind it. + +Several times during the march false alarms had been given and the +soldiers of the escort had raised their muskets, fired, and run +headlong, crushing one another, but had afterwards reassembled and +abused each other for their causeless panic. + +These three groups traveling together--the cavalry stores, the +convoy of prisoners, and Junot's baggage train--still constituted a +separate and united whole, though each of the groups was rapidly +melting away. + +Of the artillery baggage train which had consisted of a hundred +and twenty wagons, not more than sixty now remained; the rest had been +captured or left behind. Some of Junot's wagons also had been captured +or abandoned. Three wagons had been raided and robbed by stragglers +from Davout's corps. From the talk of the Germans Pierre learned +that a larger guard had been allotted to that baggage train than to +the prisoners, and that one of their comrades, a German soldier, had +been shot by the marshal's own order because a silver spoon +belonging to the marshal had been found in his possession. + +The group of prisoners had melted away most of all. Of the three +hundred and thirty men who had set out from Moscow fewer than a +hundred now remained. The prisoners were more burdensome to the escort +than even the cavalry saddles or Junot's baggage. They understood that +the saddles and Junot's spoon might be of some use, but that cold +and hungry soldiers should have to stand and guard equally cold and +hungry Russians who froze and lagged behind on the road (in which case +the order was to shoot them) was not merely incomprehensible but +revolting. And the escort, as if afraid, in the grievous condition +they themselves were in, of giving way to the pity they felt for the +prisoners and so rendering their own plight still worse, treated +them with particular moroseness and severity. + +At Dorogobuzh while the soldiers of the convoy, after locking the +prisoners in a stable, had gone off to pillage their own stores, +several of the soldier prisoners tunneled under the wall and ran away, +but were recaptured by the French and shot. + +The arrangement adopted when they started, that the officer +prisoners should be kept separate from the rest, had long since been +abandoned. All who could walk went together, and after the third stage +Pierre had rejoined Karataev and the gray-blue bandy-legged dog that +had chosen Karataev for its master. + +On the third day after leaving Moscow Karataev again fell ill with +the fever he had suffered from in the hospital in Moscow, and as he +grew gradually weaker Pierre kept away from him. Pierre did not know +why, but since Karataev had begun to grow weaker it had cost him an +effort to go near him. When he did so and heard the subdued moaning +with which Karataev generally lay down at the halting places, and when +he smelled the odor emanating from him which was now stronger than +before, Pierre moved farther away and did not think about him. + +While imprisoned in the shed Pierre had learned not with his +intellect but with his whole being, by life itself, that man is +created for happiness, that happiness is within him, in the +satisfaction of simple human needs, and that all unhappiness arises +not from privation but from superfluity. And now during these last +three weeks of the march he had learned still another new, consolatory +truth--that nothing in this world is terrible. He had learned that +as there is no condition in which man can be happy and entirely +free, so there is no condition in which he need be unhappy and lack +freedom. He learned that suffering and freedom have their limits and +that those limits are very near together; that the person in a bed +of roses with one crumpled petal suffered as keenly as he now, +sleeping on the bare damp earth with one side growing chilled while +the other was warming; and that when he had put on tight dancing shoes +he had suffered just as he did now when he walked with bare feet +that were covered with sores--his footgear having long since fallen to +pieces. He discovered that when he had married his wife--of his own +free will as it had seemed to him--he had been no more free than now +when they locked him up at night in a stable. Of all that he himself +subsequently termed his sufferings, but which at the time he +scarcely felt, the worst was the state of his bare, raw, and +scab-covered feet. (The horseflesh was appetizing and nourishing, +the saltpeter flavor of the gunpowder they used instead of salt was +even pleasant; there was no great cold, it was always warm walking +in the daytime, and at night there were the campfires; the lice that +devoured him warmed his body.) The one thing that was at first hard to +bear was his feet. + +After the second day's march Pierre, having examined his feet by the +campfire, thought it would be impossible to walk on them; but when +everybody got up he went along, limping, and, when he had warmed up, +walked without feeling the pain, though at night his feet were more +terrible to look at than before. However, he did not look at them now, +but thought of other things. + +Only now did Pierre realize the full strength of life in man and the +saving power he has of transferring his attention from one thing to +another, which is like the safety valve of a boiler that allows +superfluous steam to blow off when the pressure exceeds a certain +limit. + +He did not see and did not hear how they shot the prisoners who +lagged behind, though more than a hundred perished in that way. He did +not think of Karataev who grew weaker every day and evidently would +soon have to share that fate. Still less did Pierre think about +himself. The harder his position became and the more terrible the +future, the more independent of that position in which he found +himself were the joyful and comforting thoughts, memories, and +imaginings that came to him. + + + + + +CHAPTER XIII + + +At midday on the twenty-second of October Pierre was going uphill +along the muddy, slippery road, looking at his feet and at the +roughness of the way. Occasionally he glanced at the familiar crowd +around him and then again at his feet. The former and the latter +were alike familiar and his own. The blue-gray bandy legged dog ran +merrily along the side of the road, sometimes in proof of its +agility and self-satisfaction lifting one hind leg and hopping along +on three, and then again going on all four and rushing to bark at +the crows that sat on the carrion. The dog was merrier and sleeker +than it had been in Moscow. All around lay the flesh of different +animals--from men to horses--in various stages of decomposition; and +as the wolves were kept off by the passing men the dog could eat all +it wanted. + +It had been raining since morning and had seemed as if at any moment +it might cease and the sky clear, but after a short break it began +raining harder than before. The saturated road no longer absorbed +the water, which ran along the ruts in streams. + +Pierre walked along, looking from side to side, counting his steps +in threes, and reckoning them off on his fingers. Mentally +addressing the rain, he repeated: "Now then, now then, go on! Pelt +harder!" + +It seemed to him that he was thinking of nothing, but far down and +deep within him his soul was occupied with something important and +comforting. This something was a most subtle spiritual deduction +from a conversation with Karataev the day before. + +At their yesterday's halting place, feeling chilly by a dying +campfire, Pierre had got up and gone to the next one, which was +burning better. There Platon Karataev was sitting covered up--head and +all--with his greatcoat as if it were a vestment, telling the soldiers +in his effective and pleasant though now feeble voice a story Pierre +knew. It was already past midnight, the hour when Karataev was usually +free of his fever and particularly lively. When Pierre reached the +fire and heard Platon's voice enfeebled by illness, and saw his +pathetic face brightly lit up by the blaze, he felt a painful prick at +his heart. His feeling of pity for this man frightened him and he +wished to go away, but there was no other fire, and Pierre sat down, +trying not to look at Platon. + +"Well, how are you?" he asked. + +"How am I? If we grumble at sickness, God won't grant us death," +replied Platon, and at once resumed the story he had begun. + +"And so, brother," he continued, with a smile on his pale +emaciated face and a particularly happy light in his eyes, "you +see, brother..." + +Pierre had long been familiar with that story. Karataev had told +it to him alone some half-dozen times and always with a specially +joyful emotion. But well as he knew it, Pierre now listened to that +tale as to something new, and the quiet rapture Karataev evidently +felt as he told it communicated itself also to Pierre. The story was +of an old merchant who lived a good and God-fearing life with his +family, and who went once to the Nizhni fair with a companion--a +rich merchant. + +Having put up at an inn they both went to sleep, and next morning +his companion was found robbed and with his throat cut. A bloodstained +knife was found under the old merchant's pillow. He was tried, +knouted, and his nostrils having been torn off, "all in due form" as +Karataev put it, he was sent to hard labor in Siberia. + +"And so, brother" (it was at this point that Pierre came up), "ten +years or more passed by. The old man was living as a convict, +submitting as he should and doing no wrong. Only he prayed to God +for death. Well, one night the convicts were gathered just as we +are, with the old man among them. And they began telling what each was +suffering for, and how they had sinned against God. One told how he +had taken a life, another had taken two, a third had set a house on +fire, while another had simply been a vagrant and had done nothing. So +they asked the old man: 'What are you being punished for, Daddy?'--'I, +my dear brothers,' said he, 'am being punished for my own and other +men's sins. But I have not killed anyone or taken anything that was +not mine, but have only helped my poorer brothers. I was a merchant, +my dear brothers, and had much property. 'And he went on to tell +them all about it in due order. 'I don't grieve for myself,' he +says, 'God, it seems, has chastened me. Only I am sorry for my old +wife and the children,' and the old man began to weep. Now it happened +that in the group was the very man who had killed the other +merchant. 'Where did it happen, Daddy?' he said. 'When, and in what +month?' He asked all about it and his heart began to ache. So he comes +up to the old man like this, and falls down at his feet! 'You are +perishing because of me, Daddy,' he says. 'It's quite true, lads, that +this man,' he says, 'is being tortured innocently and for nothing! I,' +he says, 'did that deed, and I put the knife under your head while you +were asleep. Forgive me, Daddy,' he says, 'for Christ's sake!'" + +Karataev paused, smiling joyously as he gazed into the fire, and +he drew the logs together. + +"And the old man said, 'God will forgive you, we are all sinners +in His sight. I suffer for my own sins,' and he wept bitter tears. +Well, and what do you think, dear friends?" Karataev continued, his +face brightening more and more with a rapturous smile as if what he +now had to tell contained the chief charm and the whole meaning of his +story: "What do you think, dear fellows? That murderer confessed to +the authorities. 'I have taken six lives,' he says (he was a great +sinner), 'but what I am most sorry for is this old man. Don't let +him suffer because of me.' So he confessed and it was all written down +and the papers sent off in due form. The place was a long way off, and +while they were judging, what with one thing and another, filling in +the papers all in due form--the authorities I mean--time passed. The +affair reached the Tsar. After a while the Tsar's decree came: to +set the merchant free and give him a compensation that had been +awarded. The paper arrived and they began to look for the old man. +'Where is the old man who has been suffering innocently and in vain? A +paper has come from the Tsar!' so they began looking for him," here +Karataev's lower jaw trembled, "but God had already forgiven him--he +was dead! That's how it was, dear fellows!" Karataev concluded and sat +for a long time silent, gazing before him with a smile. + +And Pierre's soul was dimly but joyfully filled not by the story +itself but by its mysterious significance: by the rapturous joy that +lit up Karataev's face as he told it, and the mystic significance of +that joy. + + + + + +CHAPTER XIV + + +"A vos places!"* suddenly cried a voice. + + +*"To your places." + + +A pleasant feeling of excitement and an expectation of something +joyful and solemn was aroused among the soldiers of the convoy and the +prisoners. From all sides came shouts of command, and from the left +came smartly dressed cavalrymen on good horses, passing the +prisoners at a trot. The expression on all faces showed the tension +people feel at the approach of those in authority. The prisoners +thronged together and were pushed off the road. The convoy formed up. + +"The Emperor! The Emperor! The Marshal! The Duke!" and hardly had +the sleek cavalry passed, before a carriage drawn by six gray horses +rattled by. Pierre caught a glimpse of a man in a three-cornered hat +with a tranquil look on his handsome, plump, white face. It was one of +the marshals. His eye fell on Pierre's large and striking figure, +and in the expression with which he frowned and looked away Pierre +thought he detected sympathy and a desire to conceal that sympathy. + +The general in charge of the stores galloped after the carriage with +a red and frightened face, whipping up his skinny horse. Several +officers formed a group and some soldiers crowded round them. Their +faces all looked excited and worried. + +"What did he say? What did he say?" Pierre heard them ask. + +While the marshal was passing, the prisoners had huddled together in +a crowd, and Pierre saw Karataev whom he had not yet seen that +morning. He sat in his short overcoat leaning against a birch tree. On +his face, besides the look of joyful emotion it had worn yesterday +while telling the tale of the merchant who suffered innocently, +there was now an expression of quiet solemnity. + +Karataev looked at Pierre with his kindly round eyes now filled with +tears, evidently wishing him to come near that he might say +something to him. But Pierre was not sufficiently sure of himself. +He made as if he did not notice that look and moved hastily away. + +When the prisoners again went forward Pierre looked round. +Karataev was still sitting at the side of the road under the birch +tree and two Frenchmen were talking over his head. Pierre did not look +round again but went limping up the hill. + +From behind, where Karataev had been sitting, came the sound of a +shot. Pierre heard it plainly, but at that moment he remembered that +he had not yet finished reckoning up how many stages still remained to +Smolensk--a calculation he had begun before the marshal went by. And +he again started reckoning. Two French soldiers ran past Pierre, one +of whom carried a lowered and smoking gun. They both looked pale, +and in the expression on their faces--one of them glanced timidly at +Pierre--there was something resembling what he had seen on the face of +the young soldier at the execution. Pierre looked at the soldier and +remembered that, two days before, that man had burned his shirt +while drying it at the fire and how they had laughed at him. + +Behind him, where Karataev had been sitting, the dog began to +howl. "What a stupid beast! Why is it howling?" thought Pierre. + +His comrades, the prisoner soldiers walking beside him, avoided +looking back at the place where the shot had been fired and the dog +was howling, just as Pierre did, but there was a set look on all their +faces. + + + + + +CHAPTER XV + + +The stores, the prisoners, and the marshal's baggage train stopped +at the village of Shamshevo. The men crowded together round the +campfires. Pierre went up to the fire, ate some roast horseflesh, +lay down with his back to the fire, and immediately fell asleep. He +again slept as he had done at Mozhaysk after the battle of Borodino. + +Again real events mingled with dreams and again someone, he or +another, gave expression to his thoughts, and even to the same +thoughts that had been expressed in his dream at Mozhaysk. + +"Life is everything. Life is God. Everything changes and moves and +that movement is God. And while there is life there is joy in +consciousness of the divine. To love life is to love God. Harder and +more blessed than all else is to love this life in one's sufferings, +in innocent sufferings." + +"Karataev!" came to Pierre's mind. + +And suddenly he saw vividly before him a long-forgotten, kindly +old man who had given him geography lessons in Switzerland. "Wait a +bit," said the old man, and showed Pierre a globe. This globe was +alive--a vibrating ball without fixed dimensions. Its whole surface +consisted of drops closely pressed together, and all these drops moved +and changed places, sometimes several of them merging into one, +sometimes one dividing into many. Each drop tried to spread out and +occupy as much space as possible, but others striving to do the same +compressed it, sometimes destroyed it, and sometimes merged with it. + +"That is life," said the old teacher. + +"How simple and clear it is," thought Pierre. "How is it I did not +know it before?" + +"God is in the midst, and each drop tries to expand so as to reflect +Him to the greatest extent. And it grows, merges, disappears from +the surface, sinks to the depths, and again emerges. There now, +Karataev has spread out and disappeared. Do you understand, my child?" +said the teacher. + +"Do you understand, damn you?" shouted a voice, and Pierre woke up. + +He lifted himself and sat up. A Frenchman who had just pushed a +Russian soldier away was squatting by the fire, engaged in roasting +a piece of meat stuck on a ramrod. His sleeves were rolled up and +his sinewy, hairy, red hands with their short fingers deftly turned +the ramrod. His brown morose face with frowning brows was clearly +visible by the glow of the charcoal. + +"It's all the same to him," he muttered, turning quickly to a +soldier who stood behind him. "Brigand! Get away!" + +And twisting the ramrod he looked gloomily at Pierre, who turned +away and gazed into the darkness. A prisoner, the Russian soldier +the Frenchman had pushed away, was sitting near the fire patting +something with his hand. Looking more closely Pierre recognized the +blue-gray dog, sitting beside the soldier, wagging its tail. + +"Ah, he's come?" said Pierre. "And Plat-" he began, but did not +finish. + +Suddenly and simultaneously a crowd of memories awoke in his +fancy--of the look Platon had given him as he sat under the tree, of +the shot heard from that spot, of the dog's howl, of the guilty +faces of the two Frenchmen as they ran past him, of the lowered and +smoking gun, and of Karataev's absence at this halt--and he was on the +point of realizing that Karataev had been killed, but just at that +instant, he knew not why, the recollection came to his mind of a +summer evening he had spent with a beautiful Polish lady on the +veranda of his house in Kiev. And without linking up the events of the +day or drawing a conclusion from them, Pierre closed his eyes, +seeing a vision of the country in summertime mingled with memories +of bathing and of the liquid, vibrating globe, and he sank into +water so that it closed over his head. + +Before sunrise he was awakened by shouts and loud and rapid +firing. French soldiers were running past him. + +"The Cossacks!" one of them shouted, and a moment later a crowd of +Russians surrounded Pierre. + +For a long time he could not understand what was happening to him. +All around he heard his comrades sobbing with joy. + +"Brothers! Dear fellows! Darlings!" old soldiers exclaimed, weeping, +as they embraced Cossacks and hussars. + +The hussars and Cossacks crowded round the prisoners; one offered +them clothes, another boots, and a third bread. Pierre sobbed as he +sat among them and could not utter a word. He hugged the first soldier +who approached him, and kissed him, weeping. + +Dolokhov stood at the gate of the ruined house, letting a crowd of +disarmed Frenchmen pass by. The French, excited by all that had +happened, were talking loudly among themselves, but as they passed +Dolokhov who gently switched his boots with his whip and watched +them with cold glassy eyes that boded no good, they became silent. +On the opposite side stood Dolokhov's Cossack, counting the +prisoners and marking off each hundred with a chalk line on the gate. + +"How many?" Dolokhov asked the Cossack. + +"The second hundred," replied the Cossack. + +"Filez, filez!"* Dolokhov kept saying, having adopted this +expression from the French, and when his eyes met those of the +prisoners they flashed with a cruel light. + + +*"Get along, get along!" + + +Denisov, bareheaded and with a gloomy face, walked behind some +Cossacks who were carrying the body of Petya Rostov to a hole that had +been dug in the garden. + + + + + +CHAPTER XVI + + +After the twenty-eighth of October when the frosts began, the flight +of the French assumed a still more tragic character, with men +freezing, or roasting themselves to death at the campfires, while +carriages with people dressed in furs continued to drive past, +carrying away the property that had been stolen by the Emperor, kings, +and dukes; but the process of the flight and disintegration of the +French army went on essentially as before. + +From Moscow to Vyazma the French army of seventy-three thousand +men not reckoning the Guards (who did nothing during the whole war but +pillage) was reduced to thirty-six thousand, though not more than five +thousand had fallen in battle. From this beginning the succeeding +terms of the progression could be determined mathematically. The +French army melted away and perished at the same rate from Moscow to +Vyazma, from Vyazma to Smolensk, from Smolensk to the Berezina, and +from the Berezina to Vilna--independently of the greater or lesser +intensity of the cold, the pursuit, the barring of the way, or any +other particular conditions. Beyond Vyazma the French army instead +of moving in three columns huddled together into one mass, and so went +on to the end. Berthier wrote to his Emperor (we know how far +commanding officers allow themselves to diverge from the truth in +describing the condition of an army) and this is what he said: + + +I deem it my duty to report to Your Majesty the condition of the +various corps I have had occasion to observe during different stages +of the last two or three days' march. They are almost disbanded. +Scarcely a quarter of the soldiers remain with the standards of +their regiments, the others go off by themselves in different +directions hoping to find food and escape discipline. In general +they regard Smolensk as the place where they hope to recover. During +the last few days many of the men have been seen to throw away their +cartridges and their arms. In such a state of affairs, whatever your +ultimate plans may be, the interest of Your Majesty's service +demands that the army should be rallied at Smolensk and should first +of all be freed from ineffectives, such as dismounted cavalry, +unnecessary baggage, and artillery material that is no longer in +proportion to the present forces. The soldiers, who are worn out +with hunger and fatigue, need these supplies as well as a few days' +rest. Many have died last days on the road or at the bivouacs. This +state of things is continually becoming worse and makes one fear +that unless a prompt remedy is applied the troops will no longer be +under control in case of an engagement. + +November 9: twenty miles from Smolensk. + + +After staggering into Smolensk which seemed to them a promised land, +the French, searching for food, killed one another, sacked their own +stores, and when everything had been plundered fled farther. + +They all went without knowing whither or why they were going. +Still less did that genius, Napoleon, know it, for no one issued any +orders to him. But still he and those about him retained their old +habits: wrote commands, letters, reports, and orders of the day; +called one another sire, mon cousin, prince d'Eckmuhl, roi de +Naples, and so on. But these orders and reports were only on paper, +nothing in them was acted upon for they could not be carried out, +and though they entitled one another Majesties, Highnesses, or +Cousins, they all felt that they were miserable wretches who had +done much evil for which they had now to pay. And though they +pretended to be concerned about the army, each was thinking only of +himself and of how to get away quickly and save himself. + + + + +CHAPTER XVII + + +The movements of the Russian and French armies during the campaign +from Moscow back to the Niemen were like those in a game of Russian +blindman's bluff, in which two players are blindfolded and one of them +occasionally rings a little bell to inform the catcher of his +whereabouts. First he rings his bell fearlessly, but when he gets into +a tight place he runs away as quietly as he can, and often thinking to +escape runs straight into his opponent's arms. + +At first while they were still moving along the Kaluga road, +Napoleon's armies made their presence known, but later when they +reached the Smolensk road they ran holding the clapper of their bell +tight--and often thinking they were escaping ran right into the +Russians. + +Owing to the rapidity of the French flight and the Russian pursuit +and the consequent exhaustion of the horses, the chief means of +approximately ascertaining the enemy's position--by cavalry +scouting--was not available. Besides, as a result of the frequent +and rapid change of position by each army, even what information was +obtained could not be delivered in time. If news was received one +day that the enemy had been in a certain position the day before, by +the third day when something could have been done, that army was +already two days' march farther on and in quite another position. + +One army fled and the other pursued. Beyond Smolensk there were +several different roads available for the French, and one would have +thought that during their stay of four days they might have learned +where the enemy was, might have arranged some more advantageous plan +and undertaken something new. But after a four days' halt the mob, +with no maneuvers or plans, again began running along the beaten +track, neither to the right nor to the left but along the old--the +worst--road, through Krasnoe and Orsha. + +Expecting the enemy from behind and not in front, the French +separated in their flight and spread out over a distance of +twenty-four hours. In front of them all fled the Emperor, then the +kings, then the dukes. The Russian army, expecting Napoleon to take +the road to the right beyond the Dnieper--which was the only +reasonable thing for him to do--themselves turned to the right and +came out onto the highroad at Krasnoe. And here as in a game of +blindman's buff the French ran into our vanguard. Seeing their enemy +unexpectedly the French fell into confusion and stopped short from the +sudden fright, but then they resumed their flight, abandoning their +comrades who were farther behind. Then for three days separate +portions of the French army--first Murat's (the vice-king's), then +Davout's, and then Ney's--ran, as it were, the gauntlet of the Russian +army. They abandoned one another, abandoned all their heavy baggage, +their artillery, and half their men, and fled, getting past the +Russians by night by making semicircles to the right. + +Ney, who came last, had been busying himself blowing up the walls of +Smolensk which were in nobody's way, because despite the unfortunate +plight of the French or because of it, they wished to punish the floor +against which they had hurt themselves. Ney, who had had a corps of +ten thousand men, reached Napoleon at Orsha with only one thousand men +left, having abandoned all the rest and all his cannon, and having +crossed the Dnieper at night by stealth at a wooded spot. + +From Orsha they fled farther along the road to Vilna, still +playing at blindman's buff with the pursuing army. At the Berezina +they again became disorganized, many were drowned and many +surrendered, but those who got across the river fled farther. Their +supreme chief donned a fur coat and, having seated himself in a +sleigh, galloped on alone, abandoning his companions. The others who +could do so drove away too, leaving those who could not to surrender +or die. + + + + + +CHAPTER XVIII + + +This campaign consisted in a flight of the French during which +they did all they could to destroy themselves. From the time they +turned onto the Kaluga road to the day their leader fled from the +army, none of the movements of the crowd had any sense. So one might +have thought that regarding this period of the campaign the +historians, who attributed the actions of the mass to the will of +one man, would have found it impossible to make the story of the +retreat fit their theory. But no! Mountains of books have been written +by the historians about this campaign, and everywhere are described +Napoleon's arrangements, the maneuvers, and his profound plans which +guided the army, as well as the military genius shown by his marshals. + +The retreat from Malo-Yaroslavets when he had a free road into a +well-supplied district and the parallel road was open to him along +which Kutuzov afterwards pursued him--this unnecessary retreat along a +devastated road--is explained to us as being due to profound +considerations. Similarly profound considerations are given for his +retreat from Smolensk to Orsha. Then his heroism at Krasnoe is +described, where he is reported to have been prepared to accept battle +and take personal command, and to have walked about with a birch stick +and said: + +"J'ai assez fait l'empereur; il est temps de faire le general,"* but +nevertheless immediately ran away again, abandoning to its fate the +scattered fragments of the army he left behind. + + +*"I have acted the Emperor long enough; it is time to act the +general." + + +Then we are told of the greatness of soul of the marshals, +especially of Ney--a greatness of soul consisting in this: that he +made his way by night around through the forest and across the Dnieper +and escaped to Orsha, abandoning standards, artillery, and nine tenths +of his men. + +And lastly, the final departure of the great Emperor from his heroic +army is presented to us by the historians as something great and +characteristic of genius. Even that final running away, described in +ordinary language as the lowest depth of baseness which every child is +taught to be ashamed of--even that act finds justification in the +historians' language. + +When it is impossible to stretch the very elastic threads of +historical ratiocination any farther, when actions are clearly +contrary to all that humanity calls right or even just, the historians +produce a saving conception of "greatness." "Greatness," it seems, +excludes the standards of right and wrong. For the "great" man nothing +is wrong, there is no atrocity for which a "great" man can be blamed. + +"C'est grand!"* say the historians, and there no longer exists +either good or evil but only "grand" and "not grand." Grand is good, +not grand is bad. Grand is the characteristic, in their conception, of +some special animals called "heroes." And Napoleon, escaping home in a +warm fur coat and leaving to perish those who were not merely his +comrades but were (in his opinion) men he had brought there, feels que +c'est grand,*[2] and his soul is tranquil. + + +*"It is great." + +*[2] That it is great. + + +"Du sublime (he saw something sublime in himself) au ridicule il n'y +a qu'un pas,"* said he. And the whole world for fifty years has been +repeating: "Sublime! Grand! Napoleon le Grand!" Du sublime au ridicule +il n'y a qu'un pas. + + +*"From the sublime to the ridiculous is but a step." + + +And it occurs to no one that to admit a greatness not +commensurable with the standard of right and wrong is merely to +admit one's own nothingness and immeasurable meanness. + +For us with the standard of good and evil given us by Christ, no +human actions are incommensurable. And there is no greatness where +simplicity, goodness, and truth are absent. + + + + + +CHAPTER XIX + + +What Russian, reading the account of the last part of the campaign +of 1812, has not experienced an uncomfortable feeling of regret, +dissatisfaction, and perplexity? Who has not asked himself how it is +that the French were not all captured or destroyed when our three +armies surrounded them in superior numbers, when the disordered +French, hungry and freezing, surrendered in crowds, and when (as the +historians relate) the aim of the Russians was to stop the French, +to cut them off, and capture them all? + +How was it that the Russian army, which when numerically weaker than +the French had given battle at Borodino, did not achieve its purpose +when it had surrounded the French on three sides and when its aim +was to capture them? Can the French be so enormously superior to us +that when we had surrounded them with superior forces we could not +beat them? How could that happen? + +History (or what is called by that name) replying to these questions +says that this occurred because Kutuzov and Tormasov and Chichagov, +and this man and that man, did not execute such and such maneuvers... + +But why did they not execute those maneuvers? And why if they were +guilty of not carrying out a prearranged plan were they not tried +and punished? But even if we admitted that Kutuzov, Chichagov, and +others were the cause of the Russian failures, it is still +incomprehensible why, the position of the Russian army being what it +was at Krasnoe and at the Berezina (in both cases we had superior +forces), the French army with its marshals, kings, and Emperor was not +captured, if that was what the Russians aimed at. + +The explanation of this strange fact given by Russian military +historians (to the effect that Kutuzov hindered an attack) is +unfounded, for we know that he could not restrain the troops from +attacking at Vyazma and Tarutino. + +Why was the Russian army--which with inferior forces had withstood +the enemy in full strength at Borodino--defeated at Krasnoe and the +Berezina by the disorganized crowds of the French when it was +numerically superior? + +If the aim of the Russians consisted in cutting off and capturing +Napoleon and his marshals--and that aim was not merely frustrated +but all attempts to attain it were most shamefully baffled--then +this last period of the campaign is quite rightly considered by the +French to be a series of victories, and quite wrongly considered +victorious by Russian historians. + +The Russian military historians in so far as they submit to claims +of logic must admit that conclusion, and in spite of their lyrical +rhapsodies about valor, devotion, and so forth, must reluctantly admit +that the French retreat from Moscow was a series of victories for +Napoleon and defeats for Kutuzov. + +But putting national vanity entirely aside one feels that such a +conclusion involves a contradiction, since the series of French +victories brought the French complete destruction, while the series of +Russian defeats led to the total destruction of their enemy and the +liberation of their country. + +The source of this contradiction lies in the fact that the +historians studying the events from the letters of the sovereigns +and the generals, from memoirs, reports, projects, and so forth, +have attributed to this last period of the war of 1812 an aim that +never existed, namely that of cutting off and capturing Napoleon +with his marshals and his army. + +There never was or could have been such an aim, for it would have +been senseless and its attainment quite impossible. + +It would have been senseless, first because Napoleon's +disorganized army was flying from Russia with all possible speed, that +is to say, was doing just what every Russian desired. So what was +the use of performing various operations on the French who were +running away as fast as they possibly could? + +Secondly, it would have been senseless to block the passage of men +whose whole energy was directed to flight. + +Thirdly, it would have been senseless to sacrifice one's own +troops in order to destroy the French army, which without external +interference was destroying itself at such a rate that, though its +path was not blocked, it could not carry across the frontier more than +it actually did in December, namely a hundredth part of the original +army. + +Fourthly, it would have been senseless to wish to take captive the +Emperor, kings, and dukes--whose capture would have been in the +highest degree embarrassing for the Russians, as the most adroit +diplomatists of the time (Joseph de Maistre and others) recognized. +Still more senseless would have been the wish to capture army corps of +the French, when our own army had melted away to half before +reaching Krasnoe and a whole division would have been needed to convoy +the corps of prisoners, and when our men were not always getting +full rations and the prisoners already taken were perishing of hunger. + +All the profound plans about cutting off and capturing Napoleon +and his army were like the plan of a market gardener who, when driving +out of his garden a cow that had trampled down the beds he had +planted, should run to the gate and hit the cow on the head. The +only thing to be said in excuse of that gardener would be that he +was very angry. But not even that could be said for those who drew +up this project, for it was not they who had suffered from the +trampled beds. + +But besides the fact that cutting off Napoleon with his army would +have been senseless, it was impossible. + +It was impossible first because--as experience shows that a +three-mile movement of columns on a battlefield never coincides with +the plans--the probability of Chichagov, Kutuzov, and Wittgenstein +effecting a junction on time at an appointed place was so remote as to +be tantamount to impossibility, as in fact thought Kutuzov, who when +he received the plan remarked that diversions planned over great +distances do not yield the desired results. + +Secondly it was impossible, because to paralyze the momentum with +which Napoleon's army was retiring, incomparably greater forces than +the Russians possessed would have been required. + +Thirdly it was impossible, because the military term "to cut off" +has no meaning. One can cut off a slice of bread, but not an army. +To cut off an army--to bar its road--is quite impossible, for there is +always plenty of room to avoid capture and there is the night when +nothing can be seen, as the military scientists might convince +themselves by the example of Krasnoe and of the Berezina. It is only +possible to capture prisoners if they agree to be captured, just as it +is only possible to catch a swallow if it settles on one's hand. Men +can only be taken prisoners if they surrender according to the rules +of strategy and tactics, as the Germans did. But the French troops +quite rightly did not consider that this suited them, since death by +hunger and cold awaited them in flight or captivity alike. + +Fourthly and chiefly it was impossible, because never since the +world began has a war been fought under such conditions as those +that obtained in 1812, and the Russian army in its pursuit of the +French strained its strength to the utmost and could not have done +more without destroying itself. + +During the movement of the Russian army from Tarutino to Krasnoe +it lost fifty thousand sick or stragglers, that is a number equal to +the population of a large provincial town. Half the men fell out of +the army without a battle. + +And it is of this period of the campaign--when the army lacked boots +and sheepskin coats, was short of provisions and without vodka, and +was camping out at night for months in the snow with fifteen degrees +of frost, when there were only seven or eight hours of daylight and +the rest was night in which the influence of discipline cannot be +maintained, when men were taken into that region of death where +discipline fails, not for a few hours only as in a battle, but for +months, where they were every moment fighting death from hunger and +cold, when half the army perished in a single month--it is of this +period of the campaign that the historians tell us how Miloradovich +should have made a flank march to such and such a place, Tormasov to +another place, and Chichagov should have crossed (more than +knee-deep in snow) to somewhere else, and how so-and-so "routed" and +"cut off" the French and so on and so on. + +The Russians, half of whom died, did all that could and should +have been done to attain an end worthy of the nation, and they are not +to blame because other Russians, sitting in warm rooms, proposed +that they should do what was impossible. + +All that strange contradiction now difficult to understand between +the facts and the historical accounts only arises because the +historians dealing with the matter have written the history of the +beautiful words and sentiments of various generals, and not the +history of the events. + +To them the words of Miloradovich seem very interesting, and so do +their surmises and the rewards this or that general received; but +the question of those fifty thousand men who were left in hospitals +and in graves does not even interest them, for it does not come within +the range of their investigation. + +Yet one need only discard the study of the reports and general plans +and consider the movement of those hundreds of thousands of men who +took a direct part in the events, and all the questions that seemed +insoluble easily and simply receive an immediate and certain solution. + +The aim of cutting off Napoleon and his army never existed except in +the imaginations of a dozen people. It could not exist because it +was senseless and unattainable. + +The people had a single aim: to free their land from invasion. +That aim was attained in the first place of itself, as the French +ran away, and so it was only necessary not to stop their flight. +Secondly it was attained by the guerrilla warfare which was destroying +the French, and thirdly by the fact that a large Russian army was +following the French, ready to use its strength in case their movement +stopped. + +The Russian army had to act like a whip to a running animal. And the +experienced driver knew it was better to hold the whip raised as a +menace than to strike the running animal on the head. + + + + + +BOOK FIFTEEN: 1812 --13 + + + + + +CHAPTER I + + +When seeing a dying animal a man feels a sense of horror: +substance similar to his own is perishing before his eyes. But when it +is a beloved and intimate human being that is dying, besides this +horror at the extinction of life there is a severance, a spiritual +wound, which like a physical wound is sometimes fatal and sometimes +heals, but always aches and shrinks at any external irritating touch. + +After Prince Andrew's death Natasha and Princess Mary alike felt +this. Drooping in spirit and closing their eyes before the menacing +cloud of death that overhung them, they dared not look life in the +face. They carefully guarded their open wounds from any rough and +painful contact. Everything: a carriage passing rapidly in the street, +a summons to dinner, the maid's inquiry what dress to prepare, or +worse still any word of insincere or feeble sympathy, seemed an +insult, painfully irritated the wound, interrupting that necessary +quiet in which they both tried to listen to the stern and dreadful +choir that still resounded in their imagination, and hindered their +gazing into those mysterious limitless vistas that for an instant +had opened out before them. + +Only when alone together were they free from such outrage and +pain. They spoke little even to one another, and when they did it +was of very unimportant matters. + +Both avoided any allusion to the future. To admit the possibility of +a future seemed to them to insult his memory. Still more carefully did +they avoid anything relating to him who was dead. It seemed to them +that what they had lived through and experienced could not be +expressed in words, and that any reference to the details of his +life infringed the majesty and sacredness of the mystery that had been +accomplished before their eyes. + +Continued abstention from speech, and constant avoidance of +everything that might lead up to the subject--this halting on all +sides at the boundary of what they might not mention--brought before +their minds with still greater purity and clearness what they were +both feeling. + +But pure and complete sorrow is as impossible as pure and complete +joy. Princess Mary, in her position as absolute and independent +arbiter of her own fate and guardian and instructor of her nephew, was +the first to be called back to life from that realm of sorrow in which +she had dwelt for the first fortnight. She received letters from her +relations to which she had to reply; the room in which little Nicholas +had been put was damp and he began to cough; Alpatych came to +Yaroslavl with reports on the state of their affairs and with advice +and suggestions that they should return to Moscow to the house on +the Vozdvizhenka Street, which had remained uninjured and needed +only slight repairs. Life did not stand still and it was necessary +to live. Hard as it was for Princess Mary to emerge from the realm +of secluded contemplation in which she had lived till then, and +sorry and almost ashamed as she felt to leave Natasha alone, yet the +cares of life demanded her attention and she involuntarily yielded +to them. She went through the accounts with Alpatych, conferred with +Dessalles about her nephew, and gave orders and made preparations +for the journey to Moscow. + +Natasha remained alone and, from the time Princess Mary began making +preparations for departure, held aloof from her too. + +Princess Mary asked the countess to let Natasha go with her to +Moscow, and both parents gladly accepted this offer, for they saw +their daughter losing strength every day and thought that a change +of scene and the advice of Moscow doctors would be good for her. + +"I am not going anywhere," Natasha replied when this was proposed to +her. "Do please just leave me alone!" And she ran out of the room, +with difficulty refraining from tears of vexation and irritation +rather than of sorrow. + +After she felt herself deserted by Princes Mary and alone in her +grief, Natasha spent most of the time in her room by herself, +sitting huddled up feet and all in the corner of the sofa, tearing and +twisting something with her slender nervous fingers and gazing +intently and fixedly at whatever her eyes chanced to fall on. This +solitude exhausted and tormented her but she was in absolute need of +it. As soon as anyone entered she got up quickly, changed her position +and expression, and picked up a book or some sewing, evidently waiting +impatiently for the intruder to go. + +She felt all the time as if she might at any moment penetrate that +on which--with a terrible questioning too great for her strength- +her spiritual gaze was fixed. + +One day toward the end of December Natasha, pale and thin, dressed +in a black woolen gown, her plaited hair negligently twisted into a +knot, was crouched feet and all in the corner of her sofa, nervously +crumpling and smoothing out the end of her sash while she looked at +a corner of the door. + +She was gazing in the direction in which he had gone--to the other +side of life. And that other side of life, of which she had never +before thought and which had formerly seemed to her so far away and +improbable, was now nearer and more akin and more comprehensible +than this side of life, where everything was either emptiness and +desolation or suffering and indignity. + +She was gazing where she knew him to be; but she could not imagine +him otherwise than as he had been here. She now saw him again as he +had been at Mytishchi, at Troitsa, and at Yaroslavl. + +She saw his face, heard his voice, repeated his words and her own, +and sometimes devised other words they might have spoken. + +There he is lying back in an armchair in his velvet cloak, leaning +his head on his thin pale hand. His chest is dreadfully hollow and his +shoulders raised. His lips are firmly closed, his eyes glitter, and +a wrinkle comes and goes on his pale forehead. One of his legs +twitches just perceptibly, but rapidly. Natasha knows that he is +struggling with terrible pain. "What is that pain like? Why does he +have that pain? What does he feel? How does it hurt him?" thought +Natasha. He noticed her watching him, raised his eyes, and began to +speak seriously: + +"One thing would be terrible," said he: "to bind oneself forever +to a suffering man. It would be continual torture." And he looked +searchingly at her. Natasha as usual answered before she had time to +think what she would say. She said: "This can't go on--it won't. You +will get well--quite well." + +She now saw him from the commencement of that scene and relived what +she had then felt. She recalled his long sad and severe look at +those words and understood the meaning of the rebuke and despair in +that protracted gaze. + +"I agreed," Natasha now said to herself, "that it would be +dreadful if he always continued to suffer. I said it then only because +it would have been dreadful for him, but he understood it differently. +He thought it would be dreadful for me. He then still wished to live +and feared death. And I said it so awkwardly and stupidly! I did not +say what I meant. I thought quite differently. Had I said what I +thought, I should have said: even if he had to go on dying, to die +continually before my eyes, I should have been happy compared with +what I am now. Now there is nothing... nobody. Did he know that? No, +he did not and never will know it. And now it will never, never be +possible to put it right." And now he again seemed to be saying the +same words to her, only in her imagination Natasha this time gave +him a different answer. She stopped him and said: "Terrible for you, +but not for me! You know that for me there is nothing in life but you, +and to suffer with you is the greatest happiness for me," and he +took her hand and pressed it as he had pressed it that terrible +evening four days before his death. And in her imagination she said +other tender and loving words which she might have said then but +only spoke now: "I love thee!... thee! I love, love..." she said, +convulsively pressing her hands and setting her teeth with a desperate +effort... + +She was overcome by sweet sorrow and tears were already rising in +her eyes; then she suddenly asked herself to whom she was saying this. +Again everything was shrouded in hard, dry perplexity, and again +with a strained frown she peered toward the world where he was. And +now, now it seemed to her she was penetrating the mystery.... But at +the instant when it seemed that the incomprehensible was revealing +itself to her a loud rattle of the door handle struck painfully on her +ears. Dunyasha, her maid, entered the room quickly and abruptly with a +frightened look on her face and showing no concern for her mistress. + +"Come to your Papa at once, please!" said she with a strange, +excited look. "A misfortune... about Peter Ilynich... a letter," she +finished with a sob. + + + + + +CHAPTER II + + +Besides a feeling of aloofness from everybody Natasha was feeling +a special estrangement from the members of her own family. All of +them--her father, mother, and Sonya--were so near to her, so familiar, +so commonplace, that all their words and feelings seemed an insult +to the world in which she had been living of late, and she felt not +merely indifferent to them but regarded them with hostility. She heard +Dunyasha's words about Peter Ilynich and a misfortune, but did not +grasp them. + +"What misfortune? What misfortune can happen to them? They just live +their own old, quiet, and commonplace life," thought Natasha. + +As she entered the ballroom her father was hurriedly coming out of +her mother's room. His face was puckered up and wet with tears. He had +evidently run out of that room to give vent to the sobs that were +choking him. When he saw Natasha he waved his arms despairingly and +burst into convulsively painful sobs that distorted his soft round +face. + +"Pe... Petya... Go, go, she... is calling..." and weeping like a +child and quickly shuffling on his feeble legs to a chair, he almost +fell into it, covering his face with his hands. + +Suddenly an electric shock seemed to run through Natasha's whole +being. Terrible anguish struck her heart, she felt a dreadful ache +as if something was being torn inside her and she were dying. But +the pain was immediately followed by a feeling of release from the +oppressive constraint that had prevented her taking part in life. +The sight of her father, the terribly wild cries of her mother that +she heard through the door, made her immediately forget herself and +her own grief. + +She ran to her father, but he feebly waved his arm, pointing to +her mother's door. Princess Mary, pale and with quivering chin, came +out from that room and taking Natasha by the arm said something to +her. Natasha neither saw nor heard her. She went in with rapid +steps, pausing at the door for an instant as if struggling with +herself, and then ran to her mother. + +The countess was lying in an armchair in a strange and awkward +position, stretching out and beating her head against the wall. +Sonya and the maids were holding her arms. + +"Natasha! Natasha!..." cried the countess. "It's not true... it's +not true... He's lying... Natasha!" she shrieked, pushing those around +her away. "Go away, all of you; it's not true! Killed!... ha, ha, +ha!... It's not true!" + +Natasha put one knee on the armchair, stooped over her mother, +embraced her, and with unexpected strength raised her, turned her face +toward herself, and clung to her. + +"Mummy!... darling!... I am here, my dearest Mummy," she kept on +whispering, not pausing an instant. + +She did not let go of her mother but struggled tenderly with her, +demanded a pillow and hot water, and unfastened and tore open her +mother's dress. + +"My dearest darling... Mummy, my precious!..." she whispered +incessantly, kissing her head, her hands, her face, and feeling her +own irrepressible and streaming tears tickling her nose and cheeks. + +The countess pressed her daughter's hand, closed her eyes, and +became quiet for a moment. Suddenly she sat up with unaccustomed +swiftness, glanced vacantly around her, and seeing Natasha began to +press her daughter's head with all her strength. Then she turned +toward her daughter's face which was wincing with pain and gazed +long at it. + +"Natasha, you love me?" she said in a soft trustful whisper. +"Natasha, you would not deceive me? You'll tell me the whole truth?" + +Natasha looked at her with eyes full of tears and in her look +there was nothing but love and an entreaty for forgiveness. + +"My darling Mummy!" she repeated, straining all the power of her +love to find some way of taking on herself the excess of grief that +crushed her mother. + +And again in a futile struggle with reality her mother, refusing +to believe that she could live when her beloved boy was killed in +the bloom of life, escaped from reality into a world of delirium. + +Natasha did not remember how that day passed nor that night, nor the +next day and night. She did not sleep and did not leave her mother. +Her persevering and patient love seemed completely to surround the +countess every moment, not explaining or consoling, but recalling +her to life. + +During the third night the countess kept very quiet for a few +minutes, and Natasha rested her head on the arm of her chair and +closed her eyes, but opened them again on hearing the bedstead +creak. The countess was sitting up in bed and speaking softly. + +"How glad I am you have come. You are tired. Won't you have some +tea?" Natasha went up to her. "You have improved in looks and grown +more manly," continued the countess, taking her daughter's hand. + +"Mamma! What are you saying..." + +"Natasha, he is no more, no more!" + +And embracing her daughter, the countess began to weep for the first +time. + + + + + +CHAPTER III + + +Princess Mary postponed her departure. Sonya and the count tried +to replace Natasha but could not. They saw that she alone was able +to restrain her mother from unreasoning despair. For three weeks +Natasha remained constantly at her mother's side, sleeping on a lounge +chair in her room, making her eat and drink, and talking to her +incessantly because the mere sound of her tender, caressing tones +soothed her mother. + +The mother's wounded spirit could not heal. Petya's +death had torn from her half her life. When the news of Petya's +death had come she had been a fresh and vigorous woman of fifty, but a +month later she left her room a listless old woman taking no +interest in life. But the same blow that almost killed the countess, +this second blow, restored Natasha to life. + +A spiritual wound produced by a rending of the spiritual body is +like a physical wound and, strange as it may seem, just as a deep +wound may heal and its edges join, physical and spiritual wounds alike +can yet heal completely only as the result of a vital force from +within. + +Natasha's wound healed in that way. She thought her life was +ended, but her love for her mother unexpectedly showed her that the +essence of life--love--was still active within her. Love awoke and +so did life. + +Prince Andrew's last days had bound Princess Mary and Natasha +together; this new sorrow brought them still closer to one another. +Princess Mary put off her departure, and for three weeks looked +after Natasha as if she had been a sick child. The last weeks passed +in her mother's bedroom had strained Natasha's physical strength. + +One afternoon noticing Natasha shivering with fever, Princess Mary +took her to her own room and made her lie down on the bed. Natasha lay +down, but when Princess Mary had drawn the blinds and was going away +she called her back. + +"I don't want to sleep, Mary, sit by me a little." + +"You are tired--try to sleep." + +"No, no. Why did you bring me away? She will be asking for me." + +"She is much better. She spoke so well today," said Princess Mary. + +Natasha lay on the bed and in the semidarkness of the room scanned +Princess Mary's face. + +"Is she like him?" thought Natasha. "Yes, like and yet not like. But +she is quite original, strange, new, and unknown. And she loves me. +What is in her heart? All that is good. But how? What is her mind +like? What does she think about me? Yes, she is splendid!" + +"Mary," she said timidly, drawing Princess Mary's hand to herself, +"Mary, you mustn't think me wicked. No? Mary darling, how I love +you! Let us be quite, quite friends." + +And Natasha, embracing her, began kissing her face and hands, making +Princess Mary feel shy but happy by this demonstration of her +feelings. + +From that day a tender and passionate friendship such as exists only +between women was established between Princess Mary and Natasha. +They were continually kissing and saying tender things to one +another and spent most of their time together. When one went out the +other became restless and hastened to rejoin her. Together they felt +more in harmony with one another than either of them felt with herself +when alone. A feeling stronger than friendship sprang up between them; +an exclusive feeling of life being possible only in each other's +presence. + +Sometimes they were silent for hours; sometimes after they were +already in bed they would begin talking and go on till morning. They +spoke most of what was long past. Princess Mary spoke of her +childhood, of her mother, her father, and her daydreams; and +Natasha, who with a passive lack of understanding had formerly +turned away from that life of devotion, submission, and the poetry +of Christian self-sacrifice, now feeling herself bound to Princess +Mary by affection, learned to love her past too and to understand a +side of life previously incomprehensible to her. She did not think +of applying submission and self-abnegation to her own life, for she +was accustomed to seek other joys, but she understood and loved in +another those previously incomprehensible virtues. For Princess +Mary, listening to Natasha's tales of childhood and early youth, there +also opened out a new and hitherto uncomprehended side of life: belief +in life and its enjoyment. + +Just as before, they never mentioned him so as not to lower (as they +thought) their exalted feelings by words; but this silence about him +had the effect of making them gradually begin to forget him without +being conscious of it. + +Natasha had grown thin and pale and physically so weak that they all +talked about her health, and this pleased her. But sometimes she was +suddenly overcome by fear not only of death but of sickness, weakness, +and loss of good looks, and involuntarily she examined her bare arm +carefully, surprised at its thinness, and in the morning noticed her +drawn and, as it seemed to her, piteous face in her glass. It seemed +to her that things must be so, and yet it was dreadfully sad. + +One day she went quickly upstairs and found herself out of breath. +Unconsciously she immediately invented a reason for going down, and +then, testing her strength, ran upstairs again, observing the result. + +Another time when she called Dunyasha her voice trembled, so she +called again--though she could hear Dunyasha coming--called her in the +deep chest tones in which she had been wont to sing, sing, and +listened attentively to herself. + +She did not know and would not have believed it, but beneath the +layer of slime that covered her soul and seemed to her impenetrable, +delicate young shoots of grass were already sprouting, which taking +root would so cover with their living verdure the grief that weighed +her down that it would soon no longer be seen or noticed. The wound +had begun to heal from within. + +At the end of January Princess Mary left for Moscow, and the count +insisted on Natasha's going with her to consult the doctors. + + + + + +CHAPTER IV + + +After the encounter at Vyazma, where Kutuzov had been unable to hold +back his troops in their anxiety to overwhelm and cut off the enemy +and so on, the farther movement of the fleeing French, and of the +Russians who pursued them, continued as far as Krasnoe without a +battle. The flight was so rapid that the Russian army pursuing the +French could not keep up with them; cavalry and artillery horses broke +down, and the information received of the movements of the French +was never reliable. + +The men in the Russian army were so worn out by this continuous +marching at the rate of twenty-seven miles a day that they could not +go any faster. + +To realize the degree of exhaustion of the Russian army it is only +necessary to grasp clearly the meaning of the fact that, while not +losing more than five thousand killed and wounded after Tarutino and +less than a hundred prisoners, the Russian army which left that +place a hundred thousand strong reached Krasnoe with only fifty +thousand. + +The rapidity of the Russian pursuit was just as destructive to our +army as the flight of the French was to theirs. The only difference +was that the Russian army moved voluntarily, with no such threat of +destruction as hung over the French, and that the sick Frenchmen +were left behind in enemy hands while the sick Russians left behind +were among their own people. The chief cause of the wastage of +Napoleon's army was the rapidity of its movement, and a convincing +proof of this is the corresponding decrease of the Russian army. + +Kutuzov as far as was in his power, instead of trying to check the +movement of the French as was desired in Petersburg and by the Russian +army generals, directed his whole activity here, as he had done at +Tarutino and Vyazma, to hastening it on while easing the movement of +our army. + +But besides this, since the exhaustion and enormous diminution of +the army caused by the rapidity of the advance had become evident, +another reason for slackening the pace and delaying presented itself +to Kutuzov. The aim of the Russian army was to pursue the French. +The road the French would take was unknown, and so the closer our +troops trod on their heels the greater distance they had to cover. +Only by following at some distance could one cut across the zigzag +path of the French. All the artful maneuvers suggested by our generals +meant fresh movements of the army and a lengthening of its marches, +whereas the only reasonable aim was to shorten those marches. To +that end Kutuzov's activity was directed during the whole campaign +from Moscow to Vilna--not casually or intermittently but so +consistently that he never once deviated from it. + +Kutuzov felt and knew--not by reasoning or science but with the +whole of his Russian being--what every Russian soldier felt: that +the French were beaten, that the enemy was flying and must be driven +out; but at the same time he like the soldiers realized all the +hardship of this march, the rapidity of which was unparalleled for +such a time of the year. + +But to the generals, especially the foreign ones in the Russian +army, who wished to distinguish themselves, to astonish somebody, +and for some reason to capture a king or a duke--it seemed that now- +when any battle must be horrible and senseless--was the very time to +fight and conquer somebody. Kutuzov merely shrugged his shoulders when +one after another they presented projects of maneuvers to be made with +those soldiers--ill-shod, insufficiently clad, and half starved--who +within a month and without fighting a battle had dwindled to half +their number, and who at the best if the flight continued would have +to go a greater distance than they had already traversed, before +they reached the frontier. + +This longing to distinguish themselves, to maneuver, to overthrow, +and to cut off showed itself particularly whenever the Russians +stumbled on the French army. + +So it was at Krasnoe, where they expected to find one of the three +French columns and stumbled instead on Napoleon himself with sixteen +thousand men. Despite all Kutuzov's efforts to avoid that ruinous +encounter and to preserve his troops, the massacre of the broken mob +of French soldiers by worn-out Russians continued at Krasnoe for three +days. + +Toll wrote a disposition: "The first column will march to so and +so," etc. And as usual nothing happened in accord with the +disposition. Prince Eugene of Wurttemberg fired from a hill over the +French crowds that were running past, and demanded reinforcements +which did not arrive. The French, avoiding the Russians, dispersed and +hid themselves in the forest by night, making their way round as +best they could, and continued their flight. + +Miloradovich, who said he did not want to know anything about the +commissariat affairs of his detachment, and could never be found +when he was wanted--that chevalier sans peur et sans reproche* as he +styled himself--who was fond of parleys with the French, sent envoys +demanding their surrender, wasted time, and did not do what he was +ordered to do. + + +*Knight without fear and without reproach. + + +"I give you that column, lads," he said, riding up to the troops and +pointing out the French to the cavalry. + +And the cavalry, with spurs and sabers urging on horses that could +scarcely move, trotted with much effort to the column presented to +them--that is to say, to a crowd of Frenchmen stark with cold, +frost-bitten, and starving--and the column that had been presented +to them threw down its arms and surrendered as it had long been +anxious to do. + +At Krasnoe they took twenty-six thousand prisoners, several +hundred cannon, and a stick called a "marshal's staff," and disputed +as to who had distinguished himself and were pleased with their +achievement--though they much regretted not having taken Napoleon, +or at least a marshal or a hero of some sort, and reproached one +another and especially Kutuzov for having failed to do so. + +These men, carried away by their passions, were but blind tools of +the most melancholy law of necessity, but considered themselves heroes +and imagined that they were accomplishing a most noble and honorable +deed. They blamed Kutuzov and said that from the very beginning of the +campaign he had prevented their vanquishing Napoleon, that he +thought nothing but satisfying his passions and would not advance from +the Linen Factories because he was comfortable there, that at +Krasnoe he checked the advance because on learning that Napoleon was +there he had quite lost his head, and that it was probable that he had +an understanding with Napoleon and had been bribed by him, and so +on, and so on. + +Not only did his contemporaries, carried away by their passions, +talk in this way, but posterity and history have acclaimed Napoleon as +grand, while Kutuzov is described by foreigners as a crafty, +dissolute, weak old courtier, and by Russians as something indefinite- +a sort of puppet useful only because he had a Russian name. + + + + + +CHAPTER V + + +In 1812 and 1813 Kutuzov was openly accused of blundering. The +Emperor was dissatisfied with him. And in a history recently written +by order of the Highest Authorities it is said that Kutuzov was a +cunning court liar, frightened of the name of Napoleon, and that by +his blunders at Krasnoe and the Berezina he deprived the Russian +army of the glory of complete victory over the French.* + + +*History of the year 1812. The character of Kutuzov and +reflections on the unsatisfactory results of the battles at Krasnoe, +by Bogdanovich. + + +Such is the fate not of great men (grands hommes) whom the Russian +mind does not acknowledge, but of those rare and always solitary +individuals who, discerning the will of Providence, submit their +personal will to it. The hatred and contempt of the crowd punish +such men for discerning the higher laws. + +For Russian historians, strange and terrible to say, Napoleon- +that most insignificant tool of history who never anywhere, even in +exile, showed human dignity--Napoleon is the object of adulation and +enthusiasm; he is grand. But Kutuzov--the man who from the beginning +to the end of his activity in 1812, never once swerving by word or +deed from Borodino to Vilna, presented an example exceptional in +history of self-sacrifice and a present consciousness of the future +importance of what was happening--Kutuzov seems to them something +indefinite and pitiful, and when speaking of him and of the year +1812 they always seem a little ashamed. + +And yet it is difficult to imagine an historical character whose +activity was so unswervingly directed to a single aim; and it would be +difficult to imagine any aim more worthy or more consonant with the +will of the whole people. Still more difficult would it be to find +an instance in history of the aim of an historical personage being +so completely accomplished as that to which all Kutuzov's efforts were +directed in 1812. + +Kutuzov never talked of "forty centuries looking down from the +Pyramids," of the sacrifices he offered for the fatherland, or of what +he intended to accomplish or had accomplished; in general he said +nothing about himself, adopted no prose, always appeared to be the +simplest and most ordinary of men, and said the simplest and most +ordinary things. He wrote letters to his daughters and to Madame de +Stael, read novels, liked the society of pretty women, jested with +generals, officers, and soldiers, and never contradicted those who +tried to prove anything to him. When Count Rostopchin at the Yauza +bridge galloped up to Kutuzov with personal reproaches for having +caused the destruction of Moscow, and said: "How was it you promised +not to abandon Moscow without a battle?" Kutuzov replied: "And I shall +not abandon Moscow without a battle," though Moscow was then already +abandoned. When Arakcheev, coming to him from the Emperor, said that +Ermolov ought to be appointed chief of the artillery, Kutuzov replied: +"Yes, I was just saying so myself," though a moment before he had said +quite the contrary. What did it matter to him--who then alone amid a +senseless crowd understood the whole tremendous significance of what +was happening--what did it matter to him whether Rostopchin attributed +the calamities of Moscow to him or to himself? Still less could it +matter to him who was appointed chief of the artillery. + +Not merely in these cases but continually did that old man--who by +experience of life had reached the conviction that thoughts and the +words serving as their expression are not what move people--use +quite meaningless words that happened to enter his head. + +But that man, so heedless of his words, did not once during the +whole time of his activity utter one word inconsistent with the single +aim toward which he moved throughout the whole war. Obviously in spite +of himself, in very diverse circumstances, he repeatedly expressed his +real thoughts with the bitter conviction that he would not be +understood. Beginning with the battle of Borodino, from which time his +disagreement with those about him began, he alone said that the battle +of Borodino was a victory, and repeated this both verbally and in +his dispatches and reports up to the time of his death. He alone +said that the loss of Moscow is not the loss of Russia. In reply to +Lauriston's proposal of peace, he said: There can be no peace, for +such is the people's will. He alone during the retreat of the French +said that all our maneuvers are useless, everything is being +accomplished of itself better than we could desire; that the enemy +must be offered "a golden bridge"; that neither the Tarutino, the +Vyazma, nor the Krasnoe battles were necessary; that we must keep some +force to reach the frontier with, and that he would not sacrifice a +single Russian for ten Frenchmen. + +And this courtier, as he is described to us, who lies to Arakcheev +to please the Emperor, he alone--incurring thereby the Emperor's +displeasure--said in Vilna that to carry the war beyond the frontier +is useless and harmful. + +Nor do words alone prove that only he understood the meaning of +the events. His actions--without the smallest deviation--were all +directed to one and the same threefold end: (1) to brace all his +strength for conflict with the French, (2) to defeat them, and (3) +to drive them out of Russia, minimizing as far as possible the +sufferings of our people and of our army. + +This procrastinator Kutuzov, whose motto was "Patience and Time," +this enemy of decisive action, gave battle at Borodino, investing +the preparations for it with unparalleled solemnity. This Kutuzov +who before the battle of Austerlitz began said that it would be +lost, he alone, in contradiction to everyone else, declared till his +death that Borodino was a victory, despite the assurance of generals +that the battle was lost and despite the fact that for an army to have +to retire after winning a battle was unprecedented. He alone during +the whole retreat insisted that battles, which were useless then, +should not be fought, and that a new war should not be begun nor the +frontiers of Russia crossed. + +It is easy now to understand the significance of these events--if +only we abstain from attributing to the activity of the mass aims that +existed only in the heads of a dozen individuals--for the events and +results now lie before us. + +But how did that old man, alone, in opposition to the general +opinion, so truly discern the importance of the people's view of the +events that in all his activity he was never once untrue to it? + +The source of that extraordinary power of penetrating the meaning of +the events then occuring lay in the national feeling which he +possessed in full purity and strength. + +Only the recognition of the fact that he possessed this feeling +caused the people in so strange a manner, contrary to the Tsar's wish, +to select him--an old man in disfavor--to be their representative in +the national war. And only that feeling placed him on that highest +human pedestal from which he, the commander in chief, devoted all +his powers not to slaying and destroying men but to saving and showing +pity on them. + +That simple, modest, and therefore truly great, figure could not +be cast in the false mold of a European hero--the supposed ruler of +men--that history has invented. + +To a lackey no man can be great, for a lackey has his own conception +of greatness. + + + + + +CHAPTER VI + + +The fifth of November was the first day of what is called the battle +of Krasnoe. Toward evening--after much disputing and many mistakes +made by generals who did not go to their proper places, and after +adjutants had been sent about with counterorders--when it had become +plain that the enemy was everywhere in flight and that there could and +would be no battle, Kutuzov left Krasnoe and went to Dobroe whither +his headquarters had that day been transferred. + +The day was clear and frosty. Kutuzov rode to Dobroe on his plump +little white horse, followed by an enormous suite of discontented +generals who whispered among themselves behind his back. All along the +road groups of French prisoners captured that day (there were seven +thousand of them) were crowding to warm themselves at campfires. +Near Dobroe an immense crowd of tattered prisoners, buzzing with +talk and wrapped and bandaged in anything they had been able to get +hold of, were standing in the road beside a long row of unharnessed +French guns. At the approach of the commander in chief the buzz of +talk ceased and all eyes were fixed on Kutuzov who, wearing a white +cap with a red band and a padded overcoat that bulged on his round +shoulders, moved slowly along the road on his white horse. One of +the generals was reporting to him where the guns and prisoners had +been captured. + +Kutuzov seemed preoccupied and did not listen to what the general +was saying. He screwed up his eyes with a dissatisfied look as he +gazed attentively and fixedly at these prisoners, who presented a +specially wretched appearance. Most of them were disfigured by +frost-bitten noses and cheeks, and nearly all had red, swollen and +festering eyes. + +One group of the French stood close to the road, and two of them, +one of whom had his face covered with sores, were tearing a piece of +raw flesh with their hands. There was something horrible and bestial +in the fleeting glance they threw at the riders and in the +malevolent expression with which, after a glance at Kutuzov, the +soldier with the sores immediately turned away and went on with what +he was doing. + +Kutuzov looked long and intently at these two soldiers. He +puckered his face, screwed up his eyes, and pensively swayed his head. +At another spot he noticed a Russian soldier laughingly patting a +Frenchman on the shoulder, saying something to him in a friendly +manner, and Kutuzov with the same expression on his face again +swayed his head. + +"What were you saying?" he asked the general, who continuing his +report directed the commander in chief's attention to some standards +captured from the French and standing in front of the Preobrazhensk +regiment. + +"Ah, the standards!" said Kutuzov, evidently detaching himself +with difficulty from the thoughts that preoccupied him. + +He looked about him absently. Thousands of eyes were looking at +him from all sides awaiting a word from him. + +He stopped in front of the Preobrazhensk regiment, sighed deeply, +and closed his eyes. One of his suite beckoned to the soldiers +carrying the standards to advance and surround the commander in +chief with them. Kutuzov was silent for a few seconds and then, +submitting with evident reluctance to the duty imposed by his +position, raised his head and began to speak. A throng of officers +surrounded him. He looked attentively around at the circle of +officers, recognizing several of them. + +"I thank you all!" he said, addressing the soldiers and then again +the officers. In the stillness around him his slowly uttered words +were distinctly heard. "I thank you all for your hard and faithful +service. The victory is complete and Russia will not forget you! Honor +to you forever." + +He paused and looked around. + +"Lower its head, lower it!" he said to a soldier who had +accidentally lowered the French eagle he was holding before the +Preobrazhensk standards. "Lower, lower, that's it. Hurrah lads!" he +added, addressing the men with a rapid movement of his chin. + +"Hur-r-rah!" roared thousands of voices. + +While the soldiers were shouting Kutuzov leaned forward in his +saddle and bowed his head, and his eye lit up with a mild and +apparently ironic gleam. + +"You see, brothers..." said he when the shouts had ceased... and all +at once his voice and the expression of his face changed. It was no +longer the commander in chief speaking but an ordinary old man who +wanted to tell his comrades something very important. + +There was a stir among the throng of officers and in the ranks of +the soldiers, who moved that they might hear better what he was +going to say. + +"You see, brothers, I know it's hard for you, but it can't be +helped! Bear up; it won't be for long now! We'll see our visitors +off and then we'll rest. The Tsar won't forget your service. It is +hard for you, but still you are at home while they--you see what +they have come to," said he, pointing to the prisoners. "Worse off +than our poorest beggars. While they were strong we didn't spare +ourselves, but now we may even pity them. They are human beings too. +Isn't it so, lads?" + +He looked around, and in the direct, respectful, wondering gaze +fixed upon him he read sympathy with what he had said. His face grew +brighter and brighter with an old man's mild smile, which drew the +corners of his lips and eyes into a cluster of wrinkles. He ceased +speaking and bowed his head as if in perplexity. + +"But after all who asked them here? Serves them right, the bloody +bastards!" he cried, suddenly lifting his head. + +And flourishing his whip he rode off at a gallop for the first +time during the whole campaign, and left the broken ranks of the +soldiers laughing joyfully and shouting "Hurrah!" + +Kutuzov's words were hardly understood by the troops. No one could +have repeated the field marshal's address, begun solemnly and then +changing into an old man's simplehearted talk; but the hearty +sincerity of that speech, the feeling of majestic triumph combined +with pity for the foe and consciousness of the justice of our cause, +exactly expressed by that old man's good-natured expletives, was not +merely understood but lay in the soul of every soldier and found +expression in their joyous and long-sustained shouts. Afterwards +when one of the generals addressed Kutuzov asking whether he wished +his caleche to be sent for, Kutuzov in answering unexpectedly gave a +sob, being evidently greatly moved. + + + + + +CHAPTER VII + + +When the troops reached their night's halting place on the eighth of +November, the last day of the Krasnoe battles, it was already +growing dusk. All day it had been calm and frosty with occasional +lightly falling snow and toward evening it began to clear. Through the +falling snow a purple-black and starry sky showed itself and the frost +grew keener. + +An infantry regiment which had left Tarutino three thousand strong +but now numbered only nine hundred was one of the first to arrive that +night at its halting place--a village on the highroad. The +quartermasters who met the regiment announced that all the huts were +full of sick and dead Frenchmen, cavalrymen, and members of the staff. +There was only one hut available for the regimental commander. + +The commander rode up to his hut. The regiment passed through the +village and stacked its arms in front of the last huts. + +Like some huge many-limbed animal, the regiment began to prepare its +lair and its food. One part of it dispersed and waded knee-deep +through the snow into a birch forest to the right of the village, +and immediately the sound of axes and swords, the crashing of +branches, and merry voices could be heard from there. Another +section amid the regimental wagons and horses which were standing in a +group was busy getting out caldrons and rye biscuit, and feeding the +horses. A third section scattered through the village arranging +quarters for the staff officers, carrying out the French corpses +that were in the huts, and dragging away boards, dry wood, and +thatch from the roofs, for the campfires, or wattle fences to serve +for shelter. + +Some fifteen men with merry shouts were shaking down the high wattle +wall of a shed, the roof of which had already been removed. + +"Now then, all together--shove!" cried the voices, and the huge +surface of the wall, sprinkled with snow and creaking with frost, +was seen swaying in the gloom of the night. The lower stakes cracked +more and more and at last the wall fell, and with it the men who had +been pushing it. Loud, coarse laughter and joyous shouts ensued. + +"Now then, catch hold in twos! Hand up the lever! That's it... Where +are you shoving to?" + +"Now, all together! But wait a moment, boys... With a song!" + +All stood silent, and a soft, pleasant velvety voice began to +sing. At the end of the third verse as the last note died away, twenty +voices roared out at once: "Oo-oo-oo-oo! That's it. All together! +Heave away, boys!..." but despite their united efforts the wattle +hardly moved, and in the silence that followed the heavy breathing +of the men was audible. + +"Here, you of the Sixth Company! Devils that you are! Lend a hand... +will you? You may want us one of these days." + +Some twenty men of the Sixth Company who were on their way into +the village joined the haulers, and the wattle wall, which was about +thirty-five feet long and seven feet high, moved forward along the +village street, swaying, pressing upon and cutting the shoulders of +the gasping men. + +"Get along... Falling? What are you stopping for? There now..." + +Merry senseless words of abuse flowed freely. + +"What are you up to?" suddenly came the authoritative voice of a +sergeant major who came upon the men who were hauling their burden. +"There are gentry here; the general himself is in that hut, and you +foul-mouthed devils, you brutes, I'll give it to you!" shouted he, +hitting the first man who came in his way a swinging blow on the back. +"Can't you make less noise?" + +The men became silent. The soldier who had been struck groaned and +wiped his face, which had been scratched till it bled by his falling +against the wattle. + +"There, how that devil hits out! He's made my face all bloody," said +he in a frightened whisper when the sergeant major had passed on. + +"Don't you like it?" said a laughing voice, and moderating their +tones the men moved forward. + +When they were out of the village they began talking again as loud +as before, interlarding their talk with the same aimless expletives. + +In the hut which the men had passed, the chief officers had gathered +and were in animated talk over their tea about the events of the day +and the maneuvers suggested for tomorrow. It was proposed to make a +flank march to the left, cut off the Vice-King (Murat) and capture +him. + +By the time the soldiers had dragged the wattle fence to its place +the campfires were blazing on all sides ready for cooking, the wood +crackled, the snow was melting, and black shadows of soldiers +flitted to and fro all over the occupied space where the snow had been +trodden down. + +Axes and choppers were plied all around. Everything was done without +any orders being given. Stores of wood were brought for the night, +shelters were rigged up for the officers, caldrons were being +boiled, and muskets and accouterments put in order. + +The wattle wall the men had brought was set up in a semicircle by +the Eighth Company as a shelter from the north, propped up by musket +rests, and a campfire was built before it. They beat the tattoo, +called the roll, had supper, and settled down round the fires for +the night--some repairing their footgear, some smoking pipes, and some +stripping themselves naked to steam the lice out of their shirts. + + + + + +CHAPTER VIII + + +One would have thought that under the almost incredibly wretched +conditions the Russian soldiers were in at that time--lacking warm +boots and sheepskin coats, without a roof over their heads, in the +snow with eighteen degrees of frost, and without even full rations +(the commissariat did not always keep up with the troops)--they +would have presented a very sad and depressing spectacle. + +On the contrary, the army had never under the best material +conditions presented a more cheerful and animated aspect. This was +because all who began to grow depressed or who lost strength were +sifted out of the army day by day. All the physically or morally +weak had long since been left behind and only the flower of the +army--physically and mentally--remained. + +More men collected behind the wattle fence of the Eighth Company +than anywhere else. Two sergeants major were sitting with them and +their campfire blazed brighter than others. For leave to sit by +their wattle they demanded contributions of fuel. + +"Eh, Makeev! What has become of you, you son of a bitch? Are you +lost or have the wolves eaten you? Fetch some more wood!" shouted a +red-haired and red-faced man, screwing up his eyes and blinking +because of the smoke but not moving back from the fire. "And you, +Jackdaw, go and fetch some wood!" said he to another soldier. + +This red-haired man was neither a sergeant nor a corporal, but being +robust he ordered about those weaker than himself. The soldier they +called "Jackdaw," a thin little fellow with a sharp nose, rose +obediently and was about to go but at that instant there came into the +light of the fire the slender, handsome figure of a young soldier +carrying a load of wood. + +"Bring it here--that's fine!" + +They split up the wood, pressed it down on the fire, blew at it with +their mouths, and fanned it with the skirts of their greatcoats, +making the flames hiss and crackle. The men drew nearer and lit +their pipes. The handsome young soldier who had brought the wood, +setting his arms akimbo, began stamping his cold feet rapidly and +deftly on the spot where he stood. + +"Mother! The dew is cold but clear.... It's well that I'm a +musketeer..." he sang, pretending to hiccough after each syllable. + +"Look out, your soles will fly off!" shouted the red-haired man, +noticing that the sole of the dancer's boot was hanging loose. "What a +fellow you are for dancing!" + +The dancer stopped, pulled off the loose piece of leather, and threw +it on the fire. + +"Right enough, friend," said he, and, having sat down, took out of +his knapsack a scrap of blue French cloth, and wrapped it round his +foot. "It's the steam that spoils them," he added, stretching out +his feet toward the fire. + +"They'll soon be issuing us new ones. They say that when we've +finished hammering them, we're to receive double kits!" + +"And that son of a bitch Petrov has lagged behind after all, it +seems," said one sergeant major. + +"I've had an eye on him this long while," said the other. + +"Well, he's a poor sort of soldier..." + +"But in the Third Company they say nine men were missing yesterday." + +"Yes, it's all very well, but when a man's feet are frozen how can +he walk?" + +"Eh? Don't talk nonsense!" said a sergeant major. + +"Do you want to be doing the same?" said an old soldier, turning +reproachfully to the man who had spoken of frozen feet. + +"Well, you know," said the sharp-nosed man they called Jackdaw in +a squeaky and unsteady voice, raising himself at the other side of the +fire, "a plump man gets thin, but for a thin one it's death. Take +me, now! I've got no strength left," he added, with sudden +resolution turning to the sergeant major. "Tell them to send me to + +hospital; I'm aching all over; anyway I shan't be able to keep up." + +"That'll do, that'll do!" replied the sergeant major quietly. + +The soldier said no more and the talk went on. + +"What a lot of those Frenchies were taken today, and the fact is +that not one of them had what you might call real boots on," said a +soldier, starting a new theme. "They were no more than make-believes." + +"The Cossacks have taken their boots. They were clearing the hut for +the colonel and carried them out. It was pitiful to see them, boys," +put in the dancer. "As they turned them over one seemed still alive +and, would you believe it, he jabbered something in their lingo." + +"But they're a clean folk, lads," the first man went on; "he was +white--as white as birchbark--and some of them are such fine +fellows, you might think they were nobles." + +"Well, what do you think? They make soldiers of all classes there." + +"But they don't understand our talk at all," said the dancer with +a puzzled smile. "I asked him whose subject he was, and he jabbered in +his own way. A queer lot!" + +"But it's strange, friends," continued the man who had wondered at +their whiteness, "the peasants at Mozhaysk were saying that when +they began burying the dead--where the battle was you know--well, +those dead had been lying there for nearly a month, and says the +peasant, 'they lie as white as paper, clean, and not as much smell +as a puff of powder smoke.'" + +"Was it from the cold?" asked someone. + +"You're a clever fellow! From the cold indeed! Why, it was hot. If +it had been from the cold, ours would not have rotted either. 'But,' +he says, 'go up to ours and they are all rotten and maggoty. So,' he +says, 'we tie our faces up with kerchiefs and turn our heads away as +we drag them off: we can hardly do it. But theirs,' he says, 'are +white as paper and not so much smell as a whiff of gunpowder.'" + +All were silent. + +"It must be from their food," said the sergeant major. "They used to +gobble the same food as the gentry." + +No one contradicted him. + +"That peasant near Mozhaysk where the battle was said the men were +all called up from ten villages around and they carted for twenty days +and still didn't finish carting the dead away. And as for the +wolves, he says..." + +"That was a real battle," said an old soldier. "It's the only one +worth remembering; but since that... it's only been tormenting folk." + +"And do you know, Daddy, the day before yesterday we ran at them +and, my word, they didn't let us get near before they just threw +down their muskets and went on their knees. 'Pardon!' they say. That's +only one case. They say Platov took 'Poleon himself twice. But he +didn't know the right charm. He catches him and catches him--no +good! He turns into a bird in his hands and flies away. And there's no +way of killing him either." + +"You're a first-class liar, Kiselev, when I come to look at you!" + +"Liar, indeed! It's the real truth." + +"If he fell into my hands, when I'd caught him I'd bury him in the +ground with an aspen stake to fix him down. What a lot of men he's +ruined!" + +"Well, anyhow we're going to end it. He won't come here again," +remarked the old soldier, yawning. + +The conversation flagged, and the soldiers began settling down to +sleep. + +"Look at the stars. It's wonderful how they shine! You would think +the women had spread out their linen," said one of the men, gazing +with admiration at the Milky Way. + +"That's a sign of a good harvest next year." + +"We shall want some more wood." + +"You warm your back and your belly gets frozen. That's queer." + +"O Lord!" + +"What are you pushing for? Is the fire only for you? Look how he's +sprawling!" + +In the silence that ensued, the snoring of those who had fallen +asleep could be heard. Others turned over and warmed themselves, now +and again exchanging a few words. From a campfire a hundred paces +off came a sound of general, merry laughter. + +"Hark at them roaring there in the Fifth Company!" said one of the +soldiers, "and what a lot of them there are!" + +One of the men got up and went over to the Fifth Company. + +"They're having such fun," said he, coming back. "Two Frenchies have +turned up. One's quite frozen and the other's an awful swaggerer. He's +singing songs...." + +"Oh, I'll go across and have a look...." + +And several of the men went over to the Fifth Company. + + + + + +CHAPTER IX + + +The fifth company was bivouacking at the very edge of the forest. +A huge campfire was blazing brightly in the midst of the snow, +lighting up the branches of trees heavy with hoarfrost. + +About midnight they heard the sound of steps in the snow of the +forest, and the crackling of dry branches. + +"A bear, lads," said one of the men. + +They all raised their heads to listen, and out of the forest into +the bright firelight stepped two strangely clad human figures clinging +to one another. + +These were two Frenchmen who had been hiding in the forest. They +came up to the fire, hoarsely uttering something in a language our +soldiers did not understand. One was taller than the other; he wore an +officer's hat and seemed quite exhausted. On approaching the fire he +had been going to sit down, but fell. The other, a short sturdy +soldier with a shawl tied round his head, was stronger. He raised +his companion and said something, pointing to his mouth. The +soldiers surrounded the Frenchmen, spread a greatcoat on the ground +for the sick man, and brought some buckwheat porridge and vodka for +both of them. + +The exhausted French officer was Ramballe and the man with his +head wrapped in the shawl was Morel, his orderly. + +When Morel had drunk some vodka and finished his bowl of porridge he +suddenly became unnaturally merry and chattered incessantly to the +soldiers, who could not understand him. Ramballe refused food and +resting his head on his elbow lay silent beside the campfire, +looking at the Russian soldiers with red and vacant eyes. Occasionally +he emitted a long-drawn groan and then again became silent. Morel, +pointing to his shoulders, tried to impress on the soldiers the fact +that Ramballe was an officer and ought to be warmed. A Russian officer +who had come up to the fire sent to ask his colonel whether he would +not take a French officer into his hut to warm him, and when the +messenger returned and said that the colonel wished the officer to +be brought to him, Ramballe was told to go. He rose and tried to walk, +but staggered and would have fallen had not a soldier standing by held +him up. + +"You won't do it again, eh?" said one of the soldiers, winking and +turning mockingly to Ramballe. + +"Oh, you fool! Why talk rubbish, lout that you are--a real peasant!" +came rebukes from all sides addressed to the jesting soldier. + +They surrounded Ramballe, lifted him on the crossed arms of two +soldiers, and carried him to the hut. Ramballe put his arms around +their necks while they carried him and began wailing plaintively: + +"Oh, you fine fellows, my kind, kind friends! These are men! Oh, +my brave, kind friends," and he leaned his head against the shoulder +of one of the men like a child. + +Meanwhile Morel was sitting in the best place by the fire, +surrounded by the soldiers. + +Morel, a short sturdy Frenchman with inflamed and streaming eyes, +was wearing a woman's cloak and had a shawl tied woman fashion round +his head over his cap. He was evidently tipsy, and was singing a +French song in a hoarse broken voice, with an arm thrown round the +nearest soldier. The soldiers simply held their sides as they +watched him. + +"Now then, now then, teach us how it goes! I'll soon pick it up. How +is it?" said the man--a singer and a wag--whom Morel was embracing. + +"Vive Henri Quatre! Vive ce roi valiant!" sang Morel, winking. "Ce +diable a quatre..."* + + +*"Long live Henry the Fourth, that valiant king! That rowdy devil." + + +"Vivarika! Vif-seruvaru! Sedyablyaka!" repeated the soldier, +flourishing his arm and really catching the tune. + +"Bravo! Ha, ha, ha!" rose their rough, joyous laughter from all +sides. + +Morel, wrinkling up his face, laughed too. + +"Well, go on, go on!" + + "Qui eut le triple talent, + De boire, de battre, + Et d'etre un vert galant."* + + +*Who had a triple talent + + For drinking, for fighting, + + And for being a gallant old boy... + + +"It goes smoothly, too. Well, now, Zaletaev!" + +"Ke..." Zaletaev, brought out with effort: "ke-e-e-e," he drawled, +laboriously pursing his lips, "le-trip-ta-la-de-bu-de-ba, e +de-tra-va-ga-la" he sang. + +"Fine! Just like the Frenchie! Oh, ho ho! Do you want some more to +eat?" + +"Give him some porridge: it takes a long time to get filled up after +starving." + +They gave him some more porridge and Morel with a laugh set to +work on his third bowl. All the young soldiers smiled gaily as they +watched him. The older men, who thought it undignified to amuse +themselves with such nonsense, continued to lie at the opposite side +of the fire, but one would occasionally raise himself on an elbow +and glance at Morel with a smile. + +"They are men too," said one of them as he wrapped himself up in his +coat. "Even wormwood grows on its own root." + +"O Lord, O Lord! How starry it is! Tremendous! That means a hard +frost...." + +They all grew silent. The stars, as if knowing that no one was +looking at them, began to disport themselves in the dark sky: now +flaring up, now vanishing, now trembling, they were busy whispering +something gladsome and mysterious to one another. + + + + + +CHAPTER X + + +The French army melted away at the uniform rate of a mathematical +progression; and that crossing of the Berezina about which so much has +been written was only one intermediate stage in its destruction, and +not at all the decisive episode of the campaign. If so much has been +and still is written about the Berezina, on the French side this is +only because at the broken bridge across that river the calamities +their army had been previously enduring were suddenly concentrated +at one moment into a tragic spectacle that remained in every memory, +and on the Russian side merely because in Petersburg--far from the +seat of war--a plan (again one of Pfuel's) had been devised to catch +Napoleon in a strategic trap at the Berezina River. Everyone assured +himself that all would happen according to plan, and therefore +insisted that it was just the crossing of the Berezina that +destroyed the French army. In reality the results of the crossing were +much less disastrous to the French--in guns and men lost--than Krasnoe +had been, as the figures show. + +The sole importance of the crossing of the Berezina lies in the fact +that it plainly and indubitably proved the fallacy of all the plans +for cutting off the enemy's retreat and the soundness of the only +possible line of action--the one Kutuzov and the general mass of the +army demanded--namely, simply to follow the enemy up. The French crowd +fled at a continually increasing speed and all its energy was directed +to reaching its goal. It fled like a wounded animal and it was +impossible to block its path. This was shown not so much by the +arrangements it made for crossing as by what took place at the +bridges. When the bridges broke down, unarmed soldiers, people from +Moscow and women with children who were with the French transport, +all--carried on by vis inertiae--pressed forward into boats and into +the ice-covered water and did not, surrender. + +That impulse was reasonable. The condition of fugitives and of +pursuers was equally bad. As long as they remained with their own +people each might hope for help from his fellows and the definite +place he held among them. But those who surrendered, while remaining +in the same pitiful plight, would be on a lower level to claim a share +in the necessities of life. The French did not need to be informed +of the fact that half the prisoners--with whom the Russians did not +know what to do--perished of cold and hunger despite their captors' +desire to save them; they felt that it could not be otherwise. The +most compassionate Russian commanders, those favorable to the +French--and even the Frenchmen in the Russian service--could do +nothing for the prisoners. The French perished from the conditions +to which the Russian army was itself exposed. It was impossible to +take bread and clothes from our hungry and indispensable soldiers to +give to the French who, though not harmful, or hated, or guilty, +were simply unnecessary. Some Russians even did that, but they were +exceptions. + +Certain destruction lay behind the French but in front there was +hope. Their ships had been burned, there was no salvation save in +collective flight, and on that the whole strength of the French was +concentrated. + +The farther they fled the more wretched became the plight of the +remnant, especially after the Berezina, on which (in consequence of +the Petersburg plan) special hopes had been placed by the Russians, +and the keener grew the passions of the Russian commanders, blamed one +another and Kutuzov most of all. Anticipation that the failure of +the Petersburg Berezina plan would be attributed to Kutuzov led to +dissatisfaction, contempt, and ridicule, more and more strongly +expressed. The ridicule and contempt were of course expressed in a +respectful form, making it impossible for him to ask wherein he was to +blame. They did not talk seriously to him; when reporting to him or +asking for his sanction they appeared to be fulfilling a regrettable +formality, but they winked behind his back and tried to mislead him at +every turn. + +Because they could not understand him all these people assumed +that it was useless to talk to the old man; that he would never +grasp the profundity of their plans, that he would answer with his +phrases (which they thought were mere phrases) about a "golden +bridge," about the impossibility of crossing the frontier with a crowd +of tatterdemalions, and so forth. They had heard all that before. +And all he said--that it was necessary to await provisions, or that +the men had no boots--was so simple, while what they proposed was so +complicated and clever, that it was evident that he was old and stupid +and that they, though not in power, were commanders of genius. + +After the junction with the army of the brilliant admiral and +Petersburg hero Wittgenstein, this mood and the gossip of the staff +reached their maximum. Kutuzov saw this and merely sighed and shrugged +his shoulders. Only once, after the affair of the Berezina, did he get +angry and write to Bennigsen (who reported separately to the +Emperor) the following letter: + +"On account of your spells of ill health, will your excellency +please be so good as to set off for Kaluga on receipt of this, and +there await further commands and appointments from His Imperial +Majesty." + +But after Bennigsen's departure, the Grand Duke Tsarevich +Constantine Pavlovich joined the army. He had taken part in the +beginning of the campaign but had subsequently been removed from the +army by Kutuzov. Now having come to the army, he informed Kutuzov of +the Emperor's displeasure at the poor success of our forces and the +slowness of their advance. The Emperor intended to join the army +personally in a few days' time. + +The old man, experienced in court as well as in military affairs- +this same Kutuzov who in August had been chosen commander in chief +against the sovereign's wishes and who had removed the Grand Duke +and heir--apparent from the army--who on his own authority and +contrary to the Emperor's will had decided on the abandonment of +Moscow, now realized at once that his day was over, that his part +was played, and that the power he was supposed to hold was no longer +his. And he understood this not merely from the attitude of the court. +He saw on the one hand that the military business in which he had +played his part was ended and felt that his mission was +accomplished; and at the same time he began to be conscious of the +physical weariness of his aged body and of the necessity of physical +rest. + +On the twenty-ninth of November Kutuzov entered Vilna--his "dear +Vilna" as he called it. Twice during his career Kutuzov had been +governor of Vilna. In that wealthy town, which had not been injured, +he found old friends and associations, besides the comforts of life of +which he had so long been deprived. And he suddenly turned from the +cares of army and state and, as far as the passions that seethed +around him allowed, immersed himself in the quiet life to which he had +formerly been accustomed, as if all that was taking place and all that +had still to be done in the realm of history did not concern him at +all. + +Chichagov, one of the most zealous "cutters-off" and +"breakers-up," who had first wanted to effect a diversion in Greece +and then in Warsaw but never wished to go where he was sent: +Chichagov, noted for the boldness with which he spoke to the +Emperor, and who considered Kutuzov to be under an obligation to him +because when he was sent to make peace with Turkey in 1811 +independently of Kutuzov, and found that peace had already been +concluded, he admitted to the Emperor that the merit of securing +that peace was really Kutuzov's; this Chichagov was the first to +meet Kutuzov at the castle where the latter was to stay. In undress +naval uniform, with a dirk, and holding his cap under his arm, he +handed Kutuzov a garrison report and the keys of the town. The +contemptuously respectful attitude of the younger men to the old man +in his dotage was expressed in the highest degree by the behavior of +Chichagov, who knew of the accusations that were being directed +against Kutuzov. + +When speaking to Chichagov, Kutuzov incidentally mentioned that +the vehicles packed with china that had been captured from him at +Borisov had been recovered and would be restored to him. + +"You mean to imply that I have nothing to eat out of.... On the +contrary, I can supply you with everything even if you want to give +dinner parties," warmly replied Chichagov, who tried by every word +he spoke to prove his own rectitude and therefore imagined Kutuzov +to be animated by the same desire. + +Kutuzov, shrugging his shoulders, replied with his subtle +penetrating smile: "I meant merely to say what I said." + +Contrary to the Emperor's wish Kutuzov detained the greater part +of the army at Vilna. Those about him said that he became +extraordinarily slack and physically feeble during his stay in that +town. He attended to army affairs reluctantly, left everything to +his generals, and while awaiting the Emperor's arrival led a +dissipated life. + +Having left Petersburg on the seventh of December with his suite- +Count Tolstoy, Prince Volkonski, Arakcheev, and others--the Emperor +reached Vilna on the eleventh, and in his traveling sleigh drove +straight to the castle. In spite of the severe frost some hundred +generals and staff officers in full parade uniform stood in front of +the castle, as well as a guard of honor of the Semenov regiment. + +A courier who galloped to the castle in advance, in a troyka with +three foam-flecked horses, shouted "Coming!" and Konovnitsyn rushed +into the vestibule to inform Kutuzov, who was waiting in the hall +porter's little lodge. + +A minute later the old man's large stout figure in full-dress +uniform, his chest covered with orders and a scarf drawn round his +stomach, waddled out into the porch. He put on his hat with its +peaks to the sides and, holding his gloves in his hand and walking +with an effort sideways down the steps to the level of the street, +took in his hand the report he had prepared for the Emperor. + +There was running to and fro and whispering; another troyka +furiously up, and then all eyes were turned on an approaching sleigh +in which the figures of the Emperor and Volkonski could already be +descried. + +From the habit of fifty years all this had a physically agitating +effect on the old general. He carefully and hastily felt himself all +over, readjusted his hat, and pulling himself together drew himself up +and, at the very moment when the Emperor, having alighted from the +sleigh, lifted his eyes to him, handed him the report and began +speaking in his smooth, ingratiating voice. + +The Emperor with a rapid glance scanned Kutuzov from head to foot, +frowned for an instant, but immediately mastering himself went up to +the old man, extended his arms and embraced him. And this embrace too, +owing to a long-standing impression related to his innermost feelings, +had its usual effect on Kutuzov and he gave a sob. + +The Emperor greeted the officers and the Semenov guard, and again +pressing the old man's hand went with him into the castle. + +When alone with the field marshal the Emperor expressed his +dissatisfaction at the slowness of the pursuit and at the mistakes +made at Krasnoe and the Berezina, and informed him of his intentions +for a future campaign abroad. Kutuzov made no rejoinder or remark. The +same submissive, expressionless look with which he had listened to the +Emperor's commands on the field of Austerlitz seven years before +settled on his face now. + +When Kutuzov came out of the study and with lowered head was +crossing the ballroom with his heavy waddling gait, he was arrested by +someone's voice saying: + +"Your Serene Highness!" + +Kutuzov raised his head and looked for a long while into the eyes of +Count Tolstoy, who stood before him holding a silver salver on which +lay a small object. Kutuzov seemed not to understand what was expected +of him. + +Suddenly he seemed to remember; a scarcely perceptible smile flashed +across his puffy face, and bowing low and respectfully he took the +object that lay on the salver. It was the Order of St. George of the +First Class. + + + + + +CHAPTER XI + + +Next day the field marshal gave a dinner and ball which the +Emperor honored by his presence. Kutuzov had received the Order of St. +George of the First Class and the Emperor showed him the highest +honors, but everyone knew of the imperial dissatisfaction with him. +The proprieties were observed and the Emperor was the first to set +that example, but everybody understood that the old man was +blameworthy and good-for-nothing. When Kutuzov, conforming to a custom +of Catherine's day, ordered the standards that had been captured to be +lowered at the Emperor's feet on his entering the ballroom, the +Emperor made a wry face and muttered something in which some people +caught the words, "the old comedian." + +The Emperor's displeasure with Kutuzov was specially increased at +Vilna by the fact that Kutuzov evidently could not or would not +understand the importance of the coming campaign. + +When on the following morning the Emperor said to the officers +assembled about him: "You have not only saved Russia, you have saved +Europe!" they all understood that the war was not ended. + +Kutuzov alone would not see this and openly expressed his opinion +that no fresh war could improve the position or add to the glory of +Russia, but could only spoil and lower the glorious position that +Russia had gained. He tried to prove to the Emperor the +impossibility of levying fresh troops, spoke of the hardships +already endured by the people, of the possibility of failure and so +forth. + +This being the field marshal's frame of mind he was naturally +regarded as merely a hindrance and obstacle to the impending war. + +To avoid unpleasant encounters with the old man, the natural +method was to do what had been done with him at Austerlitz and with +Barclay at the beginning of the Russian campaign--to transfer the +authority to the Emperor himself, thus cutting the ground from under +the commander in chief's feet without upsetting the old man by +informing him of the change. + +With this object his staff was gradually reconstructed and its +real strength removed and transferred to the Emperor. Toll, +Konovnitsyn, and Ermolov received fresh appointments. Everyone spoke +loudly of the field marshal's great weakness and failing health. + +His health had to be bad for his place to be taken away and given to +another. And in fact his health was poor. + +So naturally, simply, and gradually--just as he had come from Turkey +to the Treasury in Petersburg to recruit the militia, and then to +the army when he was needed there--now when his part was played out, +Kutuzov's place was taken by a new and necessary performer. + +The war 1812, besides its national significance dear to every +Russian heart, was now to assume another, a European, significance. + +The movement of peoples from west to east was to be succeeded by a +movement of peoples from east to west, and for this fresh war +another leader was necessary, having qualities and views differing +from Kutuzov's and animated by different motives. + +Alexander I was as necessary for the movement of the peoples from +east to west and for the refixing of national frontiers as Kutuzov had +been for the salvation and glory of Russia. + +Kutuzov did not understand what Europe, the balance of power, or +Napoleon meant. He could not understand it. For the representative +of the Russian people, after the enemy had been destroyed and Russia +had been liberated and raised to the summit of her glory, there was +nothing left to do as a Russian. Nothing remained for the +representative of the national war but to die, and Kutuzov died. + + + + + +CHAPTER XII + + +As generally happens, Pierre did not feel the full effects of the +physical privation and strain he had suffered as prisoner until +after they were over. After his liberation he reached Orel, and on the +third day there, when preparing to go to Kiev, he fell ill and was +laid up for three months. He had what the doctors termed "bilious +fever." But despite the fact that the doctors treated him, bled him, +and gave him medicines to drink, he recovered. + +Scarcely any impression was left on Pierre's mind by all that +happened to him from the time of his rescue till his illness. He +remembered only the dull gray weather now rainy and now snowy, +internal physical distress, and pains in his feet and side. He +remembered a general impression of the misfortunes and sufferings of +people and of being worried by the curiosity of officers and +generals who questioned him, he also remembered his difficulty in +procuring a conveyance and horses, and above all he remembered his +incapacity to think and feel all that time. On the day of his rescue +he had seen the body of Petya Rostov. That same day he had learned +that Prince Andrew, after surviving the battle of Borodino for more +than a month had recently died in the Rostovs' house at Yaroslavl, and +Denisov who told him this news also mentioned Helene's death, +supposing that Pierre had heard of it long before. All this at the +time seemed merely strange to Pierre: he felt he could not grasp its +significance. Just then he was only anxious to get away as quickly +as possible from places where people were killing one another, to some +peaceful refuge where he could recover himself, rest, and think over +all the strange new facts he had learned; but on reaching Orel he +immediately fell ill. When he came to himself after his illness he saw +in attendance on him two of his servants, Terenty and Vaska, who had +come from Moscow; and also his cousin the eldest princess, who had +been living on his estate at Elets and hearing of his rescue and +illness had come to look after him. + +It was only gradually during his convalescence that Pierre lost +the impressions he had become accustomed to during the last few months +and got used to the idea that no one would oblige him to go anywhere +tomorrow, that no one would deprive him of his warm bed, and that he +would be sure to get his dinner, tea, and supper. But for a long +time in his dreams he still saw himself in the conditions of +captivity. In the same way little by little he came to understand +the news he had been told after his rescue, about the death of +Prince Andrew, the death of his wife, and the destruction of the +French. + +A joyous feeling of freedom--that complete inalienable freedom +natural to man which he had first experienced at the first halt +outside Moscow--filled Pierre's soul during his convalescence. He +was surprised to find that this inner freedom, which was independent +of external conditions, now had as it were an additional setting of +external liberty. He was alone in a strange town, without +acquaintances. No one demanded anything of him or sent him anywhere. +He had all he wanted: the thought of his wife which had been a +continual torment to him was no longer there, since she was no more. + +"Oh, how good! How splendid!" said he to himself when a cleanly laid +table was moved up to him with savory beef tea, or when he lay down +for the night on a soft clean bed, or when he remembered that the +French had gone and that his wife was no more. "Oh, how good, how +splendid!" + +And by old habit he asked himself the question: "Well, and what +then? What am I going to do?" And he immediately gave himself the +answer: "Well, I shall live. Ah, how splendid!" + +The very question that had formerly tormented him, the thing he +had continually sought to find--the aim of life--no longer existed for +him now. That search for the aim of life had not merely disappeared +temporarily--he felt that it no longer existed for him and could not +present itself again. And this very absence of an aim gave him the +complete, joyous sense of freedom which constituted his happiness at +this time. + +He could not see an aim, for he now had faith--not faith in any kind +of rule, or words, or ideas, but faith in an ever-living, +ever-manifest God. Formerly he had sought Him in aims he set +himself. That search for an aim had been simply a search for God, +and suddenly in his captivity he had learned not by words or reasoning +but by direct feeling what his nurse had told him long ago: that God +is here and everywhere. In his captivity he had learned that in +Karataev God was greater, more infinite and unfathomable than in the +Architect of the Universe recognized by the Freemasons. He felt like a +man who after straining his eyes to see into the far distance finds +what he sought at his very feet. All his life he had looked over the +heads of the men around him, when he should have merely looked in +front of him without straining his eyes. + +In the past he had never been able to find that great inscrutable +infinite something. He had only felt that it must exist somewhere +and had looked for it. In everything near and comprehensible he had +only what was limited, petty, commonplace, and senseless. He had +equipped himself with a mental telescope and looked into remote space, +where petty worldliness hiding itself in misty distance had seemed +to him great and infinite merely because it was not clearly seen. +And such had European life, politics, Freemasonry, philosophy, and +philanthropy seemed to him. But even then, at moments of weakness as +he had accounted them, his mind had penetrated to those distances +and he had there seen the same pettiness, worldliness, and +senselessness. Now, however, he had learned to see the great, eternal, +and infinite in everything, and therefore--to see it and enjoy its +contemplation--he naturally threw away the telescope through which +he had till now gazed over men's heads, and gladly regarded the +ever-changing, eternally great, unfathomable, and infinite life around +him. And the closer he looked the more tranquil and happy he became. +That dreadful question, "What for?" which had formerly destroyed all +his mental edifices, no longer existed for him. To that question, +"What for?" a simple answer was now always ready in his soul: "Because +there is a God, that God without whose will not one hair falls from +a man's head." + + + + + +CHAPTER XIII + + +In external ways Pierre had hardly changed at all. In appearance +he was just what he used to be. As before he was absent-minded and +seemed occupied not with what was before his eyes but with something +special of his own. The difference between his former and present self +was that formerly when he did not grasp what lay before him or was +said to him, he had puckered his forehead painfully as if vainly +seeking to distinguish something at a distance. At present he still +forgot what was said to him and still did not see what was before +his eyes, but he now looked with a scarcely perceptible and +seemingly ironic smile at what was before him and listened to what was +said, though evidently seeing and hearing something quite different. +Formerly he had appeared to be a kindhearted but unhappy man, and so +people had been inclined to avoid him. Now a smile at the joy of +life always played round his lips, and sympathy for others, shone in +his eyes with a questioning look as to whether they were as +contented as he was, and people felt pleased by his presence. + +Previously he had talked a great deal, grew excited when he +talked, and seldom listened; now he was seldom carried away in +conversation and knew how to listen so that people readily told him +their most intimate secrets. + +The princess, who had never liked Pierre and had been particularly +hostile to him since she had felt herself under obligations to him +after the old count's death, now after staying a short time in Orel- +where she had come intending to show Pierre that in spite of his +ingratitude she considered it her duty to nurse him--felt to her +surprise and vexation that she had become fond of him. Pierre did +not in any way seek her approval, he merely studied her with interest. +Formerly she had felt that he regarded her with indifference and +irony, and so had shrunk into herself as she did with others and had +shown him only the combative side of her nature; but now he seemed +to be trying to understand the most intimate places of her heart, and, +mistrustfully at first but afterwards gratefully, she let him see +the hidden, kindly sides of her character. + +The most cunning man could not have crept into her confidence more +successfully, evoking memories of the best times of her youth and +showing sympathy with them. Yet Pierre's cunning consisted simply in +finding pleasure in drawing out the human qualities of the embittered, +hard, and (in her own way) proud princess. + +"Yes, he is a very, very kind man when he is not under the influence +of bad people but of people such as myself," thought she. + +His servants too--Terenty and Vaska--in their own way noticed the +change that had taken place in Pierre. They considered that he had +become much "simpler." Terenty, when he had helped him undress and +wished him good night, often lingered with his master's boots in his +hands and clothes over his arm, to see whether he would not start a +talk. And Pierre, noticing that Terenty wanted a chat, generally +kept him there. + +"Well, tell me... now, how did you get food?" he would ask. + +And Terenty would begin talking of the destruction of Moscow, and of +the old count, and would stand for a long time holding the clothes and +talking, or sometimes listening to Pierre's stories, and then would go +out into the hall with a pleasant sense of intimacy with his master +and affection for him. + +The doctor who attended Pierre and visited him every day, though +he considered it his duty as a doctor to pose as a man whose every +moment was of value to suffering humanity, would sit for hours with +Pierre telling him his favorite anecdotes and his observations on +the characters of his patients in general, and especially of the +ladies. + +"It's a pleasure to talk to a man like that; he is not like our +provincials," he would say. + +There were several prisoners from the French army in Orel, and the +doctor brought one of them, a young Italian, to see Pierre. + +This officer began visiting Pierre, and the princess used to make +fun of the tenderness the Italian expressed for him. + +The Italian seemed happy only when he could come to see Pierre, talk +with him, tell him about his past, his life at home, and his love, and +pour out to him his indignation against the French and especially +against Napoleon. + +"If all Russians are in the least like you, it is sacrilege to fight +such a nation," he said to Pierre. "You, who have suffered so from the +French, do not even feel animosity toward them." + +Pierre had evoked the passionate affection of the Italian merely +by evoking the best side of his nature and taking a pleasure in so +doing. + +During the last days of Pierre's stay in Orel his old Masonic +acquaintance Count Willarski, who had introduced him to the lodge in +1807, came to see him. Willarski was married to a Russian heiress +who had a large estate in Orel province, and he occupied a temporary +post in the commissariat department in that town. + +Hearing that Bezukhov was in Orel, Willarski, though they had +never been intimate, came to him with the professions of friendship +and intimacy that people who meet in a desert generally express for +one another. Willarski felt dull in Orel and was pleased to meet a man +of his own circle and, as he supposed, of similar interests. + +But to his surprise Willarski soon noticed that Pierre had lagged +much behind the times, and had sunk, as he expressed it to himself, +into apathy and egotism. + +"You are letting yourself go, my dear fellow," he said. + +But for all that Willarski found it pleasanter now than it had +been formerly to be with Pierre, and came to see him every day. To +Pierre as he looked at and listened to Willarski, it seemed strange to +think that he had been like that himself but a short time before. + +Willarski was a married man with a family, busy with his family +affairs, his wife's affairs, and his official duties. He regarded +all these occupations as hindrances to life, and considered that +they were all contemptible because their aim was the welfare of +himself and his family. Military, administrative, political, and +Masonic interests continually absorbed his attention. And Pierre, +without trying to change the other's views and without condemning him, +but with the quiet, joyful, and amused smile now habitual to him, +was interested in this strange though very familiar phenomenon. + +There was a new feature in Pierre's relations with Willarski, with +the princess, with the doctor, and with all the people he now met, +which gained for him the general good will. This was his +acknowledgment of the impossibility of changing a man's convictions by +words, and his recognition of the possibility of everyone thinking, +feeling, and seeing things each from his own point of view. This +legitimate peculiarity of each individual which used to excite and +irritate Pierre now became a basis of the sympathy he felt for, and +the interest he took in, other people. The difference, and sometimes +complete contradiction, between men's opinions and their lives, and +between one man and another, pleased him and drew from him an amused +and gentle smile. + +In practical matters Pierre unexpectedly felt within himself a +center of gravity he had previously lacked. Formerly all pecuniary +questions, especially requests for money to which, as an extremely +wealthy man, he was very exposed, produced in him a state of +hopeless agitation and perplexity. "To give or not to give?" he had +asked himself. "I have it and he needs it. But someone else needs it +still more. Who needs it most? And perhaps they are both impostors?" +In the old days he had been unable to find a way out of all these +surmises and had given to all who asked as long as he had anything +to give. Formerly he had been in a similar state of perplexity with +regard to every question concerning his property, when one person +advised one thing and another something else. + +Now to his surprise he found that he no longer felt either doubt +or perplexity about these questions. There was now within him a +judge who by some rule unknown to him decided what should or should +not be done. + +He was as indifferent as heretofore to money matters, but now he +felt certain of what ought and what ought not to be done. The first +time he had recourse to his new judge was when a French prisoner, a +colonel, came to him and, after talking a great deal about his +exploits, concluded by making what amounted to a demand that Pierre +should give him four thousand francs to send to his wife and children. +Pierre refused without the least difficulty or effort, and was +afterwards surprised how simple and easy had been what used to +appear so insurmountably difficult. At the same time that he refused +the colonel's demand he made up his mind that he must have recourse to +artifice when leaving Orel, to induce the Italian officer to accept +some money of which he was evidently in need. A further proof to +Pierre of his own more settled outlook on practical matters was +furnished by his decision with regard to his wife's debts and to the +rebuilding of his houses in and near Moscow. + +His head steward came to him at Orel and Pierre reckoned up with him +his diminished income. The burning of Moscow had cost him, according +to the head steward's calculation, about two million rubles. + +To console Pierre for these losses the head steward gave him an +estimate showing that despite these losses his income would not be +diminished but would even be increased if he refused to pay his wife's +debts which he was under no obligation to meet, and did not rebuild +his Moscow house and the country house on his Moscow estate, which had +cost him eighty thousand rubles a year and brought in nothing. + +"Yes, of course that's true," said Pierre with a cheerful smile. +"I don't need all that at all. By being ruined I have become much +richer." + +But in January Savelich came from Moscow and gave him an account +of the state of things there, and spoke of the estimate an architect +had made of the cost of rebuilding the town and country houses, +speaking of this as of a settled matter. About the same time he +received letters from Prince Vasili and other Petersburg acquaintances +speaking of his wife's debts. And Pierre decided that the steward's +proposals which had so pleased him were wrong and that he must go to +Petersburg and settle his wife's affairs and must rebuild in Moscow. +Why this was necessary he did not know, but he knew for certain that +it was necessary. His income would be reduced by three fourths, but he +felt it must be done. + +Willarski was going to Moscow and they agreed to travel together. + +During the whole time of his convalescence in Orel Pierre had +experienced a feeling of joy, freedom, and life; but when during his +journey he found himself in the open world and saw hundreds of new +faces, that feeling was intensified. Throughout his journey he felt +like a schoolboy on holiday. Everyone--the stagecoach driver, the +post-house overseers, the peasants on the roads and in the villages- +had a new significance for him. The presence and remarks of +Willarski who continually deplored the ignorance and poverty of Russia +and its backwardness compared with Europe only heightened Pierre's +pleasure. Where Willarski saw deadness Pierre saw an extraordinary +strength and vitality--the strength which in that vast space amid +the snows maintained the life of this original, peculiar, and unique +people. He did not contradict Willarski and even seemed to agree +with him--an apparent agreement being the simplest way to avoid +discussions that could lead to nothing--and he smiled joyfully as he +listened to him. + + + + + +CHAPTER XIV + + +It would be difficult to explain why and whither ants whose heap has +been destroyed are hurrying: some from the heap dragging bits of +rubbish, larvae, and corpses, others back to the heap, or why they +jostle, overtake one another, and fight, and it would be equally +difficult to explain what caused the Russians after the departure of +the French to throng to the place that had formerly been Moscow. But +when we watch the ants round their ruined heap, the tenacity, +energy, and immense number of the delving insects prove that despite +the destruction of the heap, something indestructible, which though +intangible is the real strength of the colony, still exists; and +similarly, though in Moscow in the month of October there was no +government no churches, shrines, riches, or houses--it was still the +Moscow it had been in August. All was destroyed, except something +intangible yet powerful and indestructible. + +The motives of those who thronged from all sides to Moscow after +it had been cleared of the enemy were most diverse and personal, and +at first for the most part savage and brutal. One motive only they all +had in common: a desire to get to the place that had been called +Moscow, to apply their activities there. + +Within a week Moscow already had fifteen thousand inhabitants, in +a fortnight twenty-five thousand, and so on. By the autumn of 1813 the +number, ever increasing and increasing, exceeded what it had been in +1812. + +The first Russians to enter Moscow were the Cossacks of +Wintzingerode's detachment, peasants from the adjacent villages, and +residents who had fled from Moscow and had been hiding in its +vicinity. The Russians who entered Moscow, finding it plundered, +plundered it in their turn. They continued what the French had +begun. Trains of peasant carts came to Moscow to carry off to the +villages what had been abandoned in the ruined houses and the streets. +The Cossacks carried off what they could to their camps, and the +householders seized all they could find in other houses and moved it +to their own, pretending that it was their property. + +But the first plunderers were followed by a second and a third +contingent, and with increasing numbers plundering became more and +more difficult and assumed more definite forms. + +The French found Moscow abandoned but with all the organizations +of regular life, with diverse branches of commerce and +craftsmanship, with luxury, and governmental and religious +institutions. These forms were lifeless but still existed. There +were bazaars, shops, warehouses, market stalls, granaries--for the +most part still stocked with goods--and there were factories and +workshops, palaces and wealthy houses filled with luxuries, hospitals, +prisons, government offices, churches, and cathedrals. The longer +the French remained the more these forms of town life perished, +until finally all was merged into one confused, lifeless scene of +plunder. + +The more the plundering by the French continued, the more both the +wealth of Moscow and the strength of its plunderers was destroyed. But +plundering by the Russians, with which the reoccupation of the city +began, had an opposite effect: the longer it continued and the greater +the number of people taking part in it the more rapidly was the wealth +of the city and its regular life restored. + +Besides the plunderers, very various people, some drawn by +curiosity, some by official duties, some by self-interest--house +owners, clergy, officials of all kinds, tradesmen, artisans, and +peasants--streamed into Moscow as blood flows to the heart. + +Within a week the peasants who came with empty carts to carry off +plunder were stopped by the authorities and made to cart the corpses +out of the town. Other peasants, having heard of their comrades' +discomfiture, came to town bringing rye, oats, and hay, and beat +down one another's prices to below what they had been in former +days. Gangs of carpenters hoping for high pay arrived in Moscow +every day, and on all sides logs were being hewn, new houses built, +and old, charred ones repaired. Tradesmen began trading in booths. +Cookshops and taverns were opened in partially burned houses. The +clergy resumed the services in many churches that had not been burned. +Donors contributed Church property that had been stolen. Government +clerks set up their baize-covered tables and their pigeonholes of +documents in small rooms. The higher authorities and the police +organized the distribution of goods left behind by the French. The +owners of houses in which much property had been left, brought there +from other houses, complained of the injustice of taking everything to +the Faceted Palace in the Kremlin; others insisted that as the +French had gathered things from different houses into this or that +house, it would be unfair to allow its owner to keep all that was +found there. They abused the police and bribed them, made out +estimates at ten times their value for government stores that had +perished in the fire, and demanded relief. And Count Rostopchin +wrote proclamations. + + + + + +CHAPTER XV + + +At the end of January Pierre went to Moscow and stayed in an annex +of his house which had not been burned. He called on Count +Rostopchin and on some acquaintances who were back in Moscow, and he +intended to leave for Petersburg two days later. Everybody was +celebrating the victory, everything was bubbling with life in the +ruined but reviving city. Everyone was pleased to see Pierre, everyone +wished to meet him, and everyone questioned him about what he had +seen. Pierre felt particularly well disposed toward them all, but +was now instinctively on his guard for fear of binding himself in +any way. To all questions put to him--whether important or quite +trifling--such as: Where would he live? Was he going to rebuild? +When was he going to Petersburg and would he mind taking a parcel +for someone?--he replied: "Yes, perhaps," or, "I think so," and so on. + +He had heard that the Rostovs were at Kostroma but the thought of +Natasha seldom occurred to him. If it did it was only as a pleasant +memory of the distant past. He felt himself not only free from +social obligations but also from that feeling which, it seemed to him, +he had aroused in himself. + +On the third day after his arrival he heard from the Drubetskoys +that Princess Mary was in Moscow. The death, sufferings, and last days +of Prince Andrew had often occupied Pierre's thoughts and now recurred +to him with fresh vividness. Having heard at dinner that Princess Mary +was in Moscow and living in her house--which had not been burned--in +Vozdvizhenka Street, he drove that same evening to see her. + +On his way to the house Pierre kept thinking of Prince Andrew, of +their friendship, of his various meetings with him, and especially +of the last one at Borodino. + +"Is it possible that he died in the bitter frame of mind he was then +in? Is it possible that the meaning of life was not disclosed to him +before he died?" thought Pierre. He recalled Karataev and his death +and involuntarily began to compare these two men, so different, and +yet so similar in that they had both lived and both died and in the +love he felt for both of them. + +Pierre drove up to the house of the old prince in a most serious +mood. The house had escaped the fire; it showed signs of damage but +its general aspect was unchanged. The old footman, who met Pierre with +a stern face as if wishing to make the visitor feel that the absence +of the old prince had not disturbed the order of things in the +house, informed him that the princess had gone to her own +apartments, and that she received on Sundays. + +"Announce me. Perhaps she will see me," said Pierre. + +"Yes, sir," said the man. "Please step into the portrait gallery." + +A few minutes later the footman returned with Dessalles, who brought +word from the princess that she would be very glad to see Pierre if he +would excuse her want of ceremony and come upstairs to her apartment. + +In a rather low room lit by one candle sat the princess and with her +another person dressed in black. Pierre remembered that the princess +always had lady companions, but who they were and what they were +like he never knew or remembered. "This must be one of her +companions," he thought, glancing at the lady in the black dress. + +The princess rose quickly to meet him and held out her hand. + +"Yes," she said, looking at his altered face after he had kissed her +hand, "so this is how we meet again. He spoke of you even at the +very last," she went on, turning her eyes from Pierre to her companion +with a shyness that surprised him for an instant. + +"I was so glad to hear of your safety. It was the first piece of +good news we had received for a long time." + +Again the princess glanced round at her companion with even more +uneasiness in her manner and was about to add something, but Pierre +interrupted her. + +"Just imagine--I knew nothing about him!" said he. "I thought he had +been killed. All I know I heard at second hand from others. I only +know that he fell in with the Rostovs.... What a strange coincidence!" + +Pierre spoke rapidly and with animation. He glanced once at the +companion's face, saw her attentive and kindly gaze fixed on him, and, +as often happens when one is talking, felt somehow that this companion +in the black dress was a good, kind, excellent creature who would +not hinder his conversing freely with Princess Mary. + +But when he mentioned the Rostovs, Princess Mary's face expressed +still greater embarrassment. She again glanced rapidly from Pierre's +face to that of the lady in the black dress and said: + +"Do you really not recognize her?" + +Pierre looked again at the companion's pale, delicate face with +its black eyes and peculiar mouth, and something near to him, long +forgotten and more than sweet, looked at him from those attentive +eyes. + +"But no, it can't be!" he thought. "This stern, thin, pale face that +looks so much older! It cannot be she. It merely reminds me of her." +But at that moment Princess Mary said, "Natasha!" And with difficulty, +effort, and stress, like the opening of a door grown rusty on its +hinges, a smile appeared on the face with the attentive eyes, and from +that opening door came a breath of fragrance which suffused Pierre +with a happiness he had long forgotten and of which he had not even +been thinking--especially at that moment. It suffused him, seized him, +and enveloped him completely. When she smiled doubt was no longer +possible, it was Natasha and he loved her. + +At that moment Pierre involuntarily betrayed to her, to Princess +Mary, and above all to himself, a secret of which he himself had +been unaware. He flushed joyfully yet with painful distress. He +tried to hide his agitation. But the more he tried to hide it the more +clearly--clearer than any words could have done--did he betray to +himself, to her, and to Princess Mary that he loved her. + +"No, it's only the unexpectedness of it," thought Pierre. But as +soon as he tried to continue the conversation he had begun with +Princess Mary he again glanced at Natasha, and a still-deeper flush +suffused his face and a still-stronger agitation of mingled joy and +fear seized his soul. He became confused in his speech and stopped +in the middle of what he was saying. + +Pierre had failed to notice Natasha because he did not at all expect +to see her there, but he had failed to recognize her because the +change in her since he last saw her was immense. She had grown thin +and pale, but that was not what made her unrecognizable; she was +unrecognizable at the moment he entered because on that face whose +eyes had always shone with a suppressed smile of the joy of life, +now when he first entered and glanced at her there was not the least +shadow of a smile: only her eyes were kindly attentive and sadly +interrogative. + +Pierre's confusion was not reflected by any confusion on Natasha's +part, but only by the pleasure that just perceptibly lit up her +whole face. + + + + + +CHAPTER XVI + + +"She has come to stay with me," said Princess Mary. "The count and +countess will be here in a few days. The countess is in a dreadful +state; but it was necessary for Natasha herself to see a doctor. +They insisted on her coming with me." + +"Yes, is there a family free from sorrow now?" said Pierre, +addressing Natasha. "You know it happened the very day we were +rescued. I saw him. What a delightful boy he was!" + +Natasha looked at him, and by way of answer to his words her eyes +widened and lit up. + +"What can one say or think of as a consolation?" said Pierre. +"Nothing! Why had such a splendid boy, so full of life, to die?" + +"Yes, in these days it would be hard to live without faith..." +remarked Princess Mary. + +"Yes, yes, that is really true," Pierre hastily interrupted her. + +"Why is it true?" Natasha asked, looking attentively into Pierre's +eyes. + +"How can you ask why?" said Princess Mary. "The thought alone of +what awaits..." + +Natasha without waiting for Princess Mary to finish again looked +inquiringly at Pierre. + +"And because," Pierre continued, "only one who believes that there +is a God ruling us can bear a loss such as hers and... yours." + +Natasha had already opened her mouth to speak but suddenly +stopped. Pierre hurriedly turned away from her and again addressed +Princess Mary, asking about his friend's last days. + +Pierre's confusion had now almost vanished, but at the same time +he felt that his freedom had also completely gone. He felt that +there was now a judge of his every word and action whose judgment +mattered more to him than that of all the rest of the world. As he +spoke now he was considering what impression his words would make on +Natasha. He did not purposely say things to please her, but whatever +he was saying he regarded from her standpoint. + +Princess Mary--reluctantly as is usual in such cases--began +telling of the condition in which she had found Prince Andrew. But +Pierre's face quivering with emotion, his questions and his eager +restless expression, gradually compelled her to go into details +which she feared to recall for her own sake. + +"Yes, yes, and so...?" Pierre kept saying as he leaned toward her +with his whole body and eagerly listened to her story. "Yes, yes... so +he grew tranquil and softened? With all his soul he had always +sought one thing--to be perfectly good--so he could not be afraid of +death. The faults he had--if he had any--were not of his making. So he +did soften?... What a happy thing that he saw you again," he added, +suddenly turning to Natasha and looking at her with eyes full of +tears. + +Natasha's face twitched. She frowned and lowered her eyes for a +moment. She hesitated for an instant whether to speak or not. + +"Yes, that was happiness," she then said in her quiet voice with its +deep chest notes. "For me it certainly was happiness." She paused. +"And he... he... he said he was wishing for it at the very moment I +entered the room...." + +Natasha's voice broke. She blushed, pressed her clasped hands on her +knees, and then controlling herself with an evident effort lifted +her head and began to speak rapidly. + +"We knew nothing of it when we started from Moscow. I did not dare +to ask about him. Then suddenly Sonya told me he was traveling with +us. I had no idea and could not imagine what state he was in, all I +wanted was to see him and be with him," she said, trembling, and +breathing quickly. + +And not letting them interrupt her she went on to tell what she +had never yet mentioned to anyone--all she had lived through during +those three weeks of their journey and life at Yaroslavl. + +Pierre listened to her with lips parted and eyes fixed upon her full +of tears. As he listened he did not think of Prince Andrew, nor of +death, nor of what she was telling. He listened to her and felt only +pity for her, for what she was suffering now while she was speaking. + +Princess Mary, frowning in her effort to hold back her tears, sat +beside Natasha, and heard for the first time the story of those last +days of her brother's and Natasha's love. + +Evidently Natasha needed to tell that painful yet joyful tale. + +She spoke, mingling most trifling details with the intimate +secrets of her soul, and it seemed as if she could never finish. +Several times she repeated the same thing twice. + +Dessalles' voice was heard outside the door asking whether little +Nicholas might come in to say good night. + +"Well, that's all--everything," said Natasha. + +She got up quickly just as Nicholas entered, almost ran to the +door which was hidden by curtains, struck her head against it, and +rushed from the room with a moan either of pain or sorrow. + +Pierre gazed at the door through which she had disappeared and did +not understand why he suddenly felt all alone in the world. + +Princess Mary roused him from his abstraction by drawing his +attention to her nephew who had entered the room. + +At that moment of emotional tenderness young Nicholas' face, which +resembled his father's, affected Pierre so much that when he had +kissed the boy he got up quickly, took out his handkerchief, and +went to the window. He wished to take leave of Princess Mary, but +she would not let him go. + +"No, Natasha and I sometimes don't go to sleep till after two, so +please don't go. I will order supper. Go downstairs, we will come +immediately." + +Before Pierre left the room Princess Mary told him: "This is the +first time she has talked of him like that." + + + + + +CHAPTER XVII + + +Pierre was shown into the large, brightly lit dining room; a few +minutes later he heard footsteps and Princess Mary entered with +Natasha. Natasha was calm, though a severe and grave expression had +again settled on her face. They all three of them now experienced that +feeling of awkwardness which usually follows after a serious and +heartfelt talk. It is impossible to go back to the same +conversation, to talk of trifles is awkward, and yet the desire to +speak is there and silence seems like affectation. They went +silently to table. The footmen drew back the chairs and pushed them up +again. Pierre unfolded his cold table napkin and, resolving to break +the silence, looked at Natasha and at Princess Mary. They had +evidently both formed the same resolution; the eyes of both shone with +satisfaction and a confession that besides sorrow life also has joy. + +"Do you take vodka, Count?" asked Princess Mary, and those words +suddenly banished the shadows of the past. "Now tell us about +yourself," said she. "One hears such improbable wonders about you." + +"Yes," replied Pierre with the smile of mild irony now habitual to +him. "They even tell me wonders I myself never dreamed of! Mary +Abramovna invited me to her house and kept telling me what had +happened, or ought to have happened, to me. Stepan Stepanych also +instructed me how I ought to tell of my experiences. In general I have +noticed that it is very easy to be an interesting man (I am an +interesting man now); people invite me out and tell me all about +myself." + +Natasha smiled and was on the point of speaking. + +"We have been told," Princess Mary interrupted her, "that you lost +two millions in Moscow. Is that true?" + +"But I am three times as rich as before," returned Pierre. + +Though the position was now altered by his decision to pay his +wife's debts and to rebuild his houses, Pierre still maintained that +he had become three times as rich as before. + +"What I have certainly gained is freedom," he began seriously, but +did not continue, noticing that this theme was too egotistic. + +"And are you building?" + +"Yes. Savelich says I must!" + +"Tell me, you did not know of the countess' death when you decided +to remain in Moscow?" asked Princess Mary and immediately blushed, +noticing that her question, following his mention of freedom, ascribed +to his words a meaning he had perhaps not intended. + +"No," answered Pierre, evidently not considering awkward the meaning +Princess Mary had given to his words. "I heard of it in Orel and you +cannot imagine how it shocked me. We were not an exemplary couple," he +added quickly, glancing at Natasha and noticing on her face +curiosity as to how he would speak of his wife, "but her death shocked +me terribly. When two people quarrel they are always both in fault, +and one's own guilt suddenly becomes terribly serious when the other +is no longer alive. And then such a death... without friends and +without consolation! I am very, very sorry for her," he concluded, and +was pleased to notice a look of glad approval on Natasha's face. + +"Yes, and so you are once more an eligible bachelor," said +Princess Mary. + +Pierre suddenly flushed crimson and for a long time tried not to +look at Natasha. When he ventured to glance her way again her face was +cold, stern, and he fancied even contemptuous. + +"And did you really see and speak to Napoleon, as we have been +told?" said Princess Mary. + +Pierre laughed. + +"No, not once! Everybody seems to imagine that being taken +prisoner means being Napoleon's guest. Not only did I never see him +but I heard nothing about him--I was in much lower company!" + +Supper was over, and Pierre who at first declined to speak about his +captivity was gradually led on to do so. + +"But it's true that you remained in Moscow to kill Napoleon?" +Natasha asked with a slight smile. "I guessed it then when we met at +the Sukharev tower, do you remember?" + +Pierre admitted that it was true, and from that was gradually led by +Princess Mary's questions and especially by Natasha's into giving a +detailed account of his adventures. + +At first he spoke with the amused and mild irony now customary +with him toward everybody and especially toward himself, but when he +came to describe the horrors and sufferings he had witnessed he was +unconsciously carried away and began speaking with the suppressed +emotion of a man re-experiencing in recollection strong impressions he +has lived through. + +Princess Mary with a gentle smile looked now at Pierre and now at +Natasha. In the whole narrative she saw only Pierre and his +goodness. Natasha, leaning on her elbow, the expression of her face +constantly changing with the narrative, watched Pierre with an +attention that never wandered--evidently herself experiencing all that +he described. Not only her look, but her exclamations and the brief +questions she put, showed Pierre that she understood just what he +wished to convey. It was clear that she understood not only what he +said but also what he wished to, but could not, express in words. +The account Pierre gave of the incident with the child and the woman +for protecting whom he was arrested was this: "It was an awful +sight--children abandoned, some in the flames... One was snatched +out before my eyes... and there were women who had their things +snatched off and their earrings torn out..." he flushed and grew +confused. "Then a patrol arrived and all the men--all those who were + +not looting, that is--were arrested, and I among them." + +"I am sure you're not telling us everything; I am sure you did +something..." said Natasha and pausing added, "something fine?" + +Pierre continued. When he spoke of the execution he wanted to pass +over the horrible details, but Natasha insisted that he should not +omit anything. + +Pierre began to tell about Karataev, but paused. By this time he had +risen from the table and was pacing the room, Natasha following him +with her eyes. Then he added: + +"No, you can't understand what I learned from that illiterate man- +that simple fellow." + +"Yes, yes, go on!" said Natasha. "Where is he?" + +"They killed him almost before my eyes." + +And Pierre, his voice trembling continually, went on to tell of +the last days of their retreat, of Karataev's illness and his death. + +He told of his adventures as he had never yet recalled them. He now, +as it were, saw a new meaning in all he had gone through. Now that +he was telling it all to Natasha he experienced that pleasure which +a man has when women listen to him--not clever women who when +listening either try to remember what they hear to enrich their +minds and when opportunity offers to retell it, or who wish to adopt +it to some thought of their own and promptly contribute their own +clever comments prepared in their little mental workshop--but the +pleasure given by real women gifted with a capacity to select and +absorb the very best a man shows of himself. Natasha without knowing +it was all attention: she did not lose a word, no single quiver in +Pierre's voice, no look, no twitch of a muscle in his face, nor a +single gesture. She caught the unfinished word in its flight and +took it straight into her open heart, divining the secret meaning of +all Pierre's mental travail. + +Princess Mary understood his story and sympathized with him, but she +now saw something else that absorbed all her attention. She saw the +possibility of love and happiness between Natasha and Pierre, and +the first thought of this filled her heart with gladness. + +It was three o'clock in the morning. The footmen came in with sad +and stern faces to change the candles, but no one noticed them. + +Pierre finished his story. Natasha continued to look at him intently +with bright, attentive, and animated eyes, as if trying to +understand something more which he had perhaps left untold. Pierre +in shamefaced and happy confusion glanced occasionally at her, and +tried to think what to say next to introduce a fresh subject. Princess +Mary was silent. It occurred to none of them that it was three o'clock +and time to go to bed. + +"People speak of misfortunes and sufferings," remarked Pierre, +"but if at this moment I were asked: 'Would you rather be what you +were before you were taken prisoner, or go through all this again?' +then for heaven's sake let me again have captivity and horseflesh! +We imagine that when we are thrown out of our usual ruts all is +lost, but it is only then that what is new and good begins. While +there is life there is happiness. There is much, much before us. I say +this to you," he added, turning to Natasha. + +"Yes, yes," she said, answering something quite different. "I too +should wish nothing but to relive it all from the beginning." + +Pierre looked intently at her. + +"Yes, and nothing more." said Natasha. + +"It's not true, not true!" cried Pierre. "I am not to blame for +being alive and wishing to live--nor you either." + +Suddenly Natasha bent her head, covered her face with her hands, and +began to cry. + +"What is it, Natasha?" said Princess Mary. + +"Nothing, nothing." She smiled at Pierre through her tears. "Good +night! It is time for bed." + +Pierre rose and took his leave. + + +Princess Mary and Natasha met as usual in the bedroom. They talked +of what Pierre had told them. Princess Mary did not express her +opinion of Pierre nor did Natasha speak of him. + +"Well, good night, Mary!" said Natasha. "Do you know, I am often +afraid that by not speaking of him" (she meant Prince Andrew) "for +fear of not doing justice to our feelings, we forget him." + +Princess Mary sighed deeply and thereby acknowledged the justice +of Natasha's remark, but she did not express agreement in words. + +"Is it possible to forget?" said she. + +"It did me so much good to tell all about it today. It was hard +and painful, but good, very good!" said Natasha. "I am sure he +really loved him. That is why I told him... Was it all right?" she +added, suddenly blushing. + +"To tell Pierre? Oh, yes. What a splendid man he is!" said +Princess Mary. + +"Do you know, Mary..." Natasha suddenly said with a mischievous +smile such as Princess Mary had not seen on her face for a long +time, "he has somehow grown so clean, smooth, and fresh--as if he +had just come out of a Russian bath; do you understand? Out of a moral +bath. Isn't it true?" + +"Yes," replied Princess Mary. "He has greatly improved." + +"With a short coat and his hair cropped; just as if, well, just as +if he had come straight from the bath... Papa used to..." + +"I understand why he" (Prince Andrew) "liked no one so much as him," +said Princess Mary. + +"Yes, and yet he is quite different. They say men are friends when +they are quite different. That must be true. Really he is quite unlike +him--in everything." + +"Yes, but he's wonderful." + +"Well, good night," said Natasha. + +And the same mischievous smile lingered for a long time on her +face as if it had been forgotten there. + + + + +CHAPTER XVIII + + +It was a long time before Pierre could fall asleep that night. He +paced up and down his room, now turning his thoughts on a difficult +problem and frowning, now suddenly shrugging his shoulders and +wincing, and now smiling happily. + +He was thinking of Prince Andrew, of Natasha, and of their love, +at one moment jealous of her past, then reproaching himself for that +feeling. It was already six in the morning and he still paced up and +down the room. + +"Well, what's to be done if it cannot be avoided? What's to be done? +Evidently it has to be so," said he to himself, and hastily undressing +he got into bed, happy and agitated but free from hesitation or +indecision. + +"Strange and impossible as such happiness seems, I must do +everything that she and I may be man and wife," he told himself. + +A few days previously Pierre had decided to go to Petersburg on +the Friday. When he awoke on the Thursday, Savelich came to ask him +about packing for the journey. + +"What, to Petersburg? What is Petersburg? Who is there in +Petersburg?" he asked involuntarily, though only to himself. "Oh, yes, +long ago before this happened I did for some reason mean to go to +Petersburg," he reflected. "Why? But perhaps I shall go. What a good +fellow he is and how attentive, and how he remembers everything," he +thought, looking at Savelich's old face, "and what a pleasant smile he +has!" + +"Well, Savelich, do you still not wish to accept your freedom?" +Pierre asked him. + +"What's the good of freedom to me, your excellency? We lived under +the late count--the kingdom of heaven be his!--and we have lived under +you too, without ever being wronged." + +"And your children?" + +"The children will live just the same. With such masters one can +live." + +"But what about my heirs?" said Pierre. "Supposing I suddenly +marry... it might happen," he added with an involuntary smile. + +"If I may take the liberty, your excellency, it would be a good +thing." + +"How easy he thinks it," thought Pierre. "He doesn't know how +terrible it is and how dangerous. Too soon or too late... it is +terrible!" + +"So what are your orders? Are you starting tomorrow?" asked +Savelich. + +"No, I'll put it off for a bit. I'll tell you later. You must +forgive the trouble I have put you to," said Pierre, and seeing +Savelich smile, he thought: "But how strange it is that he should +not know that now there is no Petersburg for me, and that that must be +settled first of all! But probably he knows it well enough and is only +pretending. Shall I have a talk with him and see what he thinks?" +Pierre reflected. "No, another time." + +At breakfast Pierre told the princess, his cousin, that he had +been to see Princess Mary the day before and had there met--"Whom do +you think? Natasha Rostova!" + +The princess seemed to see nothing more extraordinary in that than +if he had seen Anna Semenovna. + +"Do you know her?" asked Pierre. + +"I have seen the princess," she replied. "I heard that they were +arranging a match for her with young Rostov. It would be a very good +thing for the Rostovs, they are said to be utterly ruined." + +"No; I mean do you know Natasha Rostova?" + +"I heard about that affair of hers at the time. It was a great +pity." + +"No, she either doesn't understand or is pretending," thought +Pierre. "Better not say anything to her either." + +The princess too had prepared provisions for Pierre's journey. + +"How kind they all are," thought Pierre. "What is surprising is that +they should trouble about these things now when it can no longer be of +interest to them. And all for me!" + +On the same day the Chief of Police came to Pierre, inviting him +to send a representative to the Faceted Palace to recover things +that were to be returned to their owners that day. + +"And this man too," thought Pierre, looking into the face of the +Chief of Police. "What a fine, good-looking officer and how kind. +Fancy bothering about such trifies now! And they actually say he is +not honest and takes bribes. What nonsense! Besides, why shouldn't +he take bribes? That's the way he was brought up, and everybody does +it. But what a kind, pleasant face and how he smiles as he looks at +me." + +Pierre went to Princess Mary's to dinner. + +As he drove through the streets past the houses that had been burned +down, he was surprised by the beauty of those ruins. The +picturesqueness of the chimney stacks and tumble-down walls of the +burned-out quarters of the town, stretching out and concealing one +another, reminded him of the Rhine and the Colosseum. The cabmen he +met and their passengers, the carpenters cutting the timber for new +houses with axes, the women hawkers, and the shopkeepers, all looked +at him with cheerful beaming eyes that seemed to say: "Ah, there he +is! Let's see what will come of it!" + +At the entrance to Princess Mary's house Pierre felt doubtful +whether he had really been there the night before and really seen +Natasha and talked to her. "Perhaps I imagined it; perhaps I shall +go in and find no one there." But he had hardly entered the room +before he felt her presence with his whole being by the loss of his +sense of freedom. She was in the same black dress with soft folds +and her hair was done the same way as the day before, yet she was +quite different. Had she been like this when he entered the day before +he could not for a moment have failed to recognize her. + +She was as he had known her almost as a child and later on as Prince +Andrew's fiancee. A bright questioning light shone in her eyes, and on +her face was a friendly and strangely roguish expression. + +Pierre dined with them and would have spent the whole evening there, +but Princess Mary was going to vespers and Pierre left the house +with her. + +Next day he came early, dined, and stayed the whole evening. +Though Princess Mary and Natasha were evidently glad to see their +visitor and though all Pierre's interest was now centered in that +house, by the evening they had talked over everything and the +conversation passed from one trivial topic to another and repeatedly +broke off. He stayed so long that Princess Mary and Natasha +exchanged glances, evidently wondering when he would go. Pierre +noticed this but could not go. He felt uneasy and embarrassed, but sat +on because he simply could not get up and take his leave. + +Princess Mary, foreseeing no end to this, rose first, and +complaining of a headache began to say good night. + +"So you are going to Petersburg tomorrow?" she asked. + +"No, I am not going," Pierre replied hastily, in a surprised tone +and as though offended. "Yes... no... to Petersburg? Tomorrow--but I +won't say good-by yet. I will call round in case you have any +commissions for me," said he, standing before Princess Mary and +turning red, but not taking his departure. + +Natasha gave him her hand and went out. Princess Mary on the other +hand instead of going away sank into an armchair, and looked sternly +and intently at him with her deep, radiant eyes. The weariness she had +plainly shown before had now quite passed off. With a deep and +long-drawn sigh she seemed to be prepared for a lengthy talk. + +When Natasha left the room Pierre's confusion and awkwardness +immediately vanished and were replaced by eager excitement. He quickly +moved an armchair toward Princess Mary. + +"Yes, I wanted to tell you," said he, answering her look as if she +had spoken. "Princess, help me! What am I to do? Can I hope? Princess, +my dear friend, listen! I know it all. I know I am not worthy of +her, I know it's impossible to speak of it now. But I want to be a +brother to her. No, not that, I don't, I can't..." + +He paused and rubbed his face and eyes with his hands. + +"Well," he went on with an evident effort at self-control and +coherence. "I don't know when I began to love her, but I have loved +her and her alone all my life, and I love her so that I cannot imagine +life without her. I cannot propose to her at present, but the +thought that perhaps she might someday be my wife and that I may be +missing that possibility... that possibility... is terrible. Tell +me, can I hope? Tell me what I am to do, dear princess!" he added +after a pause, and touched her hand as she did not reply. + +"I am thinking of what you have told me," answered Princess Mary. +"This is what I will say. You are right that to speak to her of love +at present..." + +Princess Mary stopped. She was going to say that to speak of love +was impossible, but she stopped because she had seen by the sudden +change in Natasha two days before that she would not only not be +hurt if Pierre spoke of his love, but that it was the very thing she +wished for. + +"To speak to her now wouldn't do," said the princess all the same. + +"But what am I to do?" + +"Leave it to me," said Princess Mary. "I know..." + +Pierre was looking into Princess Mary's eyes. + +"Well?... Well?..." he said. + +"I know that she loves... will love you," Princess Mary corrected +herself. + +Before her words were out, Pierre had sprung up and with a +frightened expression seized Princess Mary's hand. + +"What makes you think so? You think I may hope? You think...?" + +"Yes, I think so," said Princess Mary with a smile. "Write to her +parents, and leave it to me. I will tell her when I can. I wish it +to happen and my heart tells me it will." + +"No, it cannot be! How happy I am! But it can't be.... How happy I +am! No, it can't be!" Pierre kept saying as he kissed Princess +Mary's hands. + +"Go to Petersburg, that will be best. And I will write to you," +she said. + +"To Petersburg? Go there? Very well, I'll go. But I may come again +tomorrow?" + +Next day Pierre came to say good-by. Natasha was less animated +than she had been the day before; but that day as he looked at her +Pierre sometimes felt as if he was vanishing and that neither he nor +she existed any longer, that nothing existed but happiness. "Is it +possible? No, it can't be," he told himself at every look, gesture, +and word that filled his soul with joy. + +When on saying good-by he took her thin, slender hand, he could +not help holding it a little longer in his own. + +"Is it possible that this hand, that face, those eyes, all this +treasure of feminine charm so strange to me now, is it possible that +it will one day be mine forever, as familiar to me as I am to +myself?... No, that's impossible!..." + +"Good-by, Count," she said aloud. "I shall look forward very much to +your return," she added in a whisper. + +And these simple words, her look, and the expression on her face +which accompanied them, formed for two months the subject of +inexhaustible memories, interpretations, and happy meditations for +Pierre. "'I shall look forward very much to your return....' Yes, yes, +how did she say it? Yes, 'I shall look forward very much to your +return.' Oh, how happy I am! What is happening to me? How happy I am!" +said Pierre to himself. + + + + + +CHAPTER XIX + + +There was nothing in Pierre's soul now at all like what had troubled +it during his courtship of Helene. + +He did not repeat to himself with a sickening feeling of shame the +words he had spoken, or say: "Oh, why did I not say that?" and, +"Whatever made me say 'Je vous aime'?" On the contrary, he now +repeated in imagination every word that he or Natasha had spoken and +pictured every detail of her face and smile, and did not wish to +diminish or add anything, but only to repeat it again and again. There +was now not a shadow of doubt in his mind as to whether what he had +undertaken was right or wrong. Only one terrible doubt sometimes +crossed his mind: "Wasn't it all a dream? Isn't Princess Mary +mistaken? Am I not too conceited and self-confident? I believe all +this--and suddenly Princess Mary will tell her, and she will be sure +to smile and say: 'How strange! He must be deluding himself. Doesn't +he know that he is a man, just a man, while I...? I am something +altogether different and higher.'" + +That was the only doubt often troubling Pierre. He did not now +make any plans. The happiness before him appeared so inconceivable +that if only he could attain it, it would be the end of all things. +Everything ended with that. + +A joyful, unexpected frenzy, of which he had thought himself +incapable, possessed him. The whole meaning of life--not for him alone +but for the whole world--seemed to him centered in his love and the +possibility of being loved by her. At times everybody seemed to him to +be occupied with one thing only--his future happiness. Sometimes it +seemed to him that other people were all as pleased as he was +himself and merely tried to hide that pleasure by pretending to be +busy with other interests. In every word and gesture he saw +allusions to his happiness. He often surprised those he met by his +significantly happy looks and smiles which seemed to express a +secret understanding between him and them. And when he realized that +people might not be aware of his happiness, he pitied them with his +whole heart and felt a desire somehow to explain to them that all that +occupied them was a mere frivolous trifle unworthy of attention. + +When it was suggested to him that he should enter the civil service, +or when the war or any general political affairs were discussed on the +assumption that everybody's welfare depended on this or that issue +of events, he would listen with a mild and pitying smile and +surprise people by his strange comments. But at this time he saw +everybody--both those who, as he imagined, understood the real meaning +of life (that is, what he was feeling) and those unfortunates who +evidently did not understand it--in the bright light of the emotion +that shone within himself, and at once without any effort saw in +everyone he met everything that was good and worthy of being loved. + +When dealing with the affairs and papers of his dead wife, her +memory aroused in him no feeling but pity that she had not known the +bliss he now knew. Prince Vasili, who having obtained a new post and +some fresh decorations was particularly proud at this time, seemed +to him a pathetic, kindly old man much to be pitied. + +Often in afterlife Pierre recalled this period of blissful insanity. +All the views he formed of men and circumstances at this time remained +true for him always. He not only did not renounce them subsequently, +but when he was in doubt or inwardly at variance, he referred to the +views he had held at this time of his madness and they always proved +correct. + +"I may have appeared strange and queer then," he thought, "but I was +not so mad as I seemed. On the contrary I was then wiser and had +more insight than at any other time, and understood all that is +worth understanding in life, because... because I was happy." + +Pierre's insanity consisted in not waiting, as he used to do, to +discover personal attributes which he termed "good qualities" in +people before loving them; his heart was now overflowing with love, +and by loving people without cause he discovered indubitable causes +for loving them. + + + + + +CHAPTER XX + + +After Pierre's departure that first evening, when Natasha had said +to Princess Mary with a gaily mocking smile: "He looks just, yes, just +as if he had come out of a Russian bath--in a short coat and with +his hair cropped," something hidden and unknown to herself, but +irrepressible, awoke in Natasha's soul. + +Everything: her face, walk, look, and voice, was suddenly altered. +To her own surprise a power of life and hope of happiness rose to +the surface and demanded satisfaction. From that evening she seemed to +have forgotten all that had happened to her. She no longer +complained of her position, did not say a word about the past, and +no longer feared to make happy plans for the future. She spoke +little of Pierre, but when Princess Mary mentioned him a +long-extinguished light once more kindled in her eyes and her lips +curved with a strange smile. + +The change that took place in Natasha at first surprised Princess +Mary; but when she understood its meaning it grieved her. "Can she +have loved my brother so little as to be able to forget him so +soon?" she thought when she reflected on the change. But when she +was with Natasha she was not vexed with her and did not reproach +her. The reawakened power of life that had seized Natasha was so +evidently irrepressible and unexpected by her that in her presence +Princess Mary felt that she had no right to reproach her even in her +heart. + + Natasha gave herself up so fully and frankly to this new feeling +that she did not try to hide the fact that she was no longer sad, +but bright and cheerful. + +When Princess Mary returned to her room after her nocturnal talk +with Pierre, Natasha met her on the threshold. + +"He has spoken? Yes? He has spoken?" she repeated. + +And a joyful yet pathetic expression which seemed to beg forgiveness +for her joy settled on Natasha's face. + +"I wanted to listen at the door, but I knew you would tell me." + +Understandable and touching as the look with which Natasha gazed +at her seemed to Princess Mary, and sorry as she was to see her +agitation, these words pained her for a moment. She remembered her +brother and his love. + +"But what's to be done? She can't help it," thought the princess. + +And with a sad and rather stern look she told Natasha all that +Pierre had said. On hearing that he was going to Petersburg Natasha +was astounded. + +"To Petersburg!" she repeated as if unable to understand. + +But noticing the grieved expression on Princess Mary's face she +guessed the reason of that sadness and suddenly began to cry. + +"Mary," said she, "tell me what I should do! I am afraid of being +bad. Whatever you tell me, I will do. Tell me...." + +"You love him?" + +"Yes," whispered Natasha. + +"Then why are you crying? I am happy for your sake," said Princess +Mary, who because of those tears quite forgave Natasha's joy. + +"It won't be just yet--someday. Think what fun it will be when I +am his wife and you marry Nicholas!" + +"Natasha, I have asked you not to speak of that. Let us talk about +you." + +They were silent awhile. + +"But why go to Petersburg?" Natasha suddenly asked, and hastily +replied to her own question. "But no, no, he must... Yes, Mary, He +must...." + + + + + + +FIRST EPILOGUE: 1813 --20 + + + + + +CHAPTER I + + +Seven years had passed. The storm-tossed sea of European history had +subsided within its shores and seemed to have become calm. But the +mysterious forces that move humanity (mysterious because the laws of +their motion are unknown to us) continued to operate. + +Though the surface of the sea of history seemed motionless, the +movement of humanity went on as unceasingly as the flow of time. +Various groups of people formed and dissolved, the coming formation +and dissolution of kingdoms and displacement of peoples was in +course of preparation. + +The sea of history was not driven spasmodically from shore to +shore as previously. It was seething in its depths. Historic figures +were not borne by the waves from one shore to another as before. +They now seemed to rotate on one spot. The historical figures at the +head of armies, who formerly reflected the movement of the masses by +ordering wars, campaigns, and battles, now reflected the restless +movement by political and diplomatic combinations, laws, and treaties. + +The historians call this activity of the historical figures "the +reaction." + +In dealing with this period they sternly condemn the historical +personages who, in their opinion, caused what they describe as the +reaction. All the well-known people of that period, from Alexander and +Napoleon to Madame de Stael, Photius, Schelling, Fichte, +Chateaubriand, and the rest, pass before their stern judgment seat and +are acquitted or condemned according to whether they conduced to +progress or to reaction. + +According to their accounts a reaction took place at that time in +Russia also, and the chief culprit was Alexander I, the same man who +according to them was the chief cause of the liberal movement at the +commencement of his reign, being the savior of Russia. + +There is no one in Russian literature now, from schoolboy essayist +to learned historian, who does not throw his little stone at Alexander +for things he did wrong at this period of his reign. + +"He ought to have acted in this way and in that way. In this case he +did well and in that case badly. He behaved admirably at the beginning +of his reign and during 1812, but acted badly by giving a constitution +to Poland, forming the Holy Alliance, entrusting power to Arakcheev, +favoring Golitsyn and mysticism, and afterwards Shishkov and +Photius. He also acted badly by concerning himself with the active +army and disbanding the Semenov regiment." + +It would take a dozen pages to enumerate all the reproaches the +historians address to him, based on their knowledge of what is good +for humanity. + +What do these reproaches mean? + +Do not the very actions for which the historians praise Alexander +I (the liberal attempts at the beginning of his reign, his struggle +with Napoleon, the firmness he displayed in 1812 and the campaign of +1813) flow from the same sources--the circumstances of his birth, +education, and life--that made his personality what it was and from +which the actions for which they blame him (the Holy Alliance, the +restoration of Poland, and the reaction of 1820 and later) also +flowed? + +In what does the substance of those reproaches lie? + +It lies in the fact that an historic character like Alexander I, +standing on the highest possible pinnacle of human power with the +blinding light of history focused upon him; a character exposed to +those strongest of all influences: the intrigues, flattery, and +self-deception inseparable from power; a character who at every moment +of his life felt a responsibility for all that was happening in +Europe; and not a fictitious but a live character who like every man +had his personal habits, passions, and impulses toward goodness, +beauty, and truth--that this character--though not lacking in virtue +(the historians do not accuse him of that)--had not the same +conception of the welfare of humanity fifty years ago as a present-day +professor who from his youth upwards has been occupied with +learning: that is, with books and lectures and with taking notes +from them. + +But even if we assume that fifty years ago Alexander I was +mistaken in his view of what was good for the people, we must +inevitably assume that the historian who judges Alexander will also +after the lapse of some time turn out to be mistaken in his view of +what is good for humanity. This assumption is all the more natural and +inevitable because, watching the movement of history, we see that +every year and with each new writer, opinion as to what is good for +mankind changes; so that what once seemed good, ten years later +seems bad, and vice versa. And what is more, we find at one and the +same time quite contradictory views as to what is bad and what is good +in history: some people regard giving a constitution to Poland and +forming the Holy Alliance as praiseworthy in Alexander, while others +regard it as blameworthy. + +The activity of Alexander or of Napoleon cannot be called useful +or harmful, for it is impossible to say for what it was useful or +harmful. If that activity displeases somebody, this is only because it +does not agree with his limited understanding of what is good. Whether +the preservation of my father's house in Moscow, or the glory of the +Russian arms, or the prosperity of the Petersburg and other +universities, or the freedom of Poland or the greatness of Russia, +or the balance of power in Europe, or a certain kind of European +culture called "progress" appear to me to be good or bad, I must admit +that besides these things the action of every historic character has +other more general purposes inaccessible to me. + +But let us assume that what is called science can harmonize all +contradictions and possesses an unchanging standard of good and bad by +which to try historic characters and events; let us say that Alexander +could have done everything differently; let us say that with +guidance from those who blame him and who profess to know the ultimate +aim of the movement of humanity, he might have arranged matters +according to the program his present accusers would have given him--of +nationality, freedom, equality, and progress (these, I think, cover +the ground). Let us assume that this program was possible and had then +been formulated, and that Alexander had acted on it. What would then +have become of the activity of all those who opposed the tendency that +then prevailed in the government--an activity that in the opinion of +the historians was good and beneficent? Their activity would not +have existed: there would have been no life, there would have been +nothing. + +If we admit that human life can be ruled by reason, the +possibility of life is destroyed. + + + + + +CHAPTER II + + +If we assume as the historians do that great men lead humanity to +the attainment of certain ends--the greatness of Russia or of +France, the balance of power in Europe, the diffusion of the ideas +of the Revolution general progress or anything else--then it is +impossible to explain the facts of history without introducing the +conceptions of chance and genius. + +If the aim of the European wars at the beginning of the nineteenth +century had been the aggrandizement of Russia, that aim might have +been accomplished without all the preceding wars and without the +invasion. If the aim was the aggrandizement of France, that might have +been attained without the Revolution and without the Empire. If the +aim was the dissemination of ideas, the printing press could have +accomplished that much better than warfare. If the aim was the +progress of civilization, it is easy to see that there are other +ways of diffusing civilization more expedient than by the +destruction of wealth and of human lives. + +Why did it happen in this and not in some other way? + +Because it happened so! "Chance created the situation; genius +utilized it," says history. + +But what is chance? What is genius? + +The words chance and genius do not denote any really existing +thing and therefore cannot be defined. Those words only denote a +certain stage of understanding of phenomena. I do not know why a +certain event occurs; I think that I cannot know it; so I do not try +to know it and I talk about chance. I see a force producing effects +beyond the scope of ordinary human agencies; I do not understand why +this occurs and I talk of genius. + +To a herd of rams, the ram the herdsman drives each evening into a +special enclosure to feed and that becomes twice as fat as the +others must seem to be a genius. And it must appear an astonishing +conjunction of genius with a whole series of extraordinary chances +that this ram, who instead of getting into the general fold every +evening goes into a special enclosure where there are oats--that +this very ram, swelling with fat, is killed for meat. + +But the rams need only cease to suppose that all that happens to +them happens solely for the attainment of their sheepish aims; they +need only admit that what happens to them may also have purposes +beyond their ken, and they will at once perceive a unity and coherence +in what happened to the ram that was fattened. Even if they do not +know for what purpose they are fattened, they will at least know +that all that happened to the ram did not happen accidentally, and +will no longer need the conceptions of chance or genius. + +Only by renouncing our claim to discern a purpose immediately +intelligible to us, and admitting the ultimate purpose to be beyond +our ken, may we discern the sequence of experiences in the lives of +historic characters and perceive the cause of the effect they +produce (incommensurable with ordinary human capabilities), and then +the words chance and genius become superfluous. + +We need only confess that we do not know the purpose of the European +convulsions and that we know only the facts--that is, the murders, +first in France, then in Italy, in Africa, in Prussia, in Austria, +in Spain, and in Russia--and that the movements from the west to the +east and from the east to the west form the essence and purpose of +these events, and not only shall we have no need to see exceptional +ability and genius in Napoleon and Alexander, but we shall be unable +to consider them to be anything but like other men, and we shall not +be obliged to have recourse to chance for an explanation of those +small events which made these people what they were, but it will be +clear that all those small events were inevitable. + +By discarding a claim to knowledge of the ultimate purpose, we shall +clearly perceive that just as one cannot imagine a blossom or seed for +any single plant better suited to it than those it produces, so it +is impossible to imagine any two people more completely adapted down +to the smallest detail for the purpose they had to fulfill, than +Napoleon and Alexander with all their antecedents. + + + + + +CHAPTER III + + +The fundamental and essential significance of the European events of +the beginning of the nineteenth century lies in the movement of the +mass of the European peoples from west to east and afterwards from +east to west. The commencement of that movement was the movement +from west to east. For the peoples of the west to be able to make +their warlike movement to Moscow it was necessary: (1) that they +should form themselves into a military group of a size able to +endure a collision with the warlike military group of the east, (2) +that they should abandon all established traditions and customs, and +(3) that during their military movement they should have at their head +a man who could justify to himself and to them the deceptions, +robberies, and murders which would have to be committed during that +movement. + +And beginning with the French Revolution the old inadequately +large group was destroyed, as well as the old habits and traditions, +and step by step a group was formed of larger dimensions with new +customs and traditions, and a man was produced who would stand at +the head of the coming movement and bear the responsibility for all +that had to be done. + +A man without convictions, without habits, without traditions, +without a name, and not even a Frenchman, emerges--by what seem the +strangest chances--from among all the seething French parties, and +without joining any one of them is borne forward to a prominent +position. + +The ignorance of his colleagues, the weakness and insignificance +of his opponents, the frankness of his falsehoods, and the dazzling +and self-confident limitations of this man raise him to the head of +the army. The brilliant qualities of the soldiers of the army sent +to Italy, his opponents' reluctance to fight, and his own childish +audacity and self-confidence secure him military fame. Innumerable +so called chances accompany him everywhere. The disfavor into which he +falls with the rulers of France turns to his advantage. His attempts +to avoid his predestined path are unsuccessful: he is not received +into the Russian service, and the appointment he seeks in Turkey comes +to nothing. During the war in Italy he is several times on the verge +of destruction and each time is saved in an unexpected manner. Owing +to various diplomatic considerations the Russian armies--just those +which might have destroyed his prestige--do not appear upon the +scene till he is no longer there. + +On his return from Italy he finds the government in Paris in a +process of dissolution in which all those who are in it are inevitably +wiped out and destroyed. And by chance an escape from this dangerous +position presents itself in the form of an aimless and senseless +expedition to Africa. Again so-called chance accompanies him. +Impregnable Malta surrenders without a shot; his most reckless schemes +are crowned with success. The enemy's fleet, which subsequently did +not let a single boat pass, allows his entire army to elude it. In +Africa a whole series of outrages are committed against the almost +unarmed inhabitants. And the men who commit these crimes, especially +their leader, assure themselves that this is admirable, this is glory- +it resembles Caesar and Alexander the Great and is therefore good. + +This ideal of glory and grandeur--which consists not merely in +considering nothing wrong that one does but in priding oneself on +every crime one commits, ascribing to it an incomprehensible +supernatural significance--that ideal, destined to guide this man +and his associates, had scope for its development in Africa. +Whatever he does succeeds. The plague does not touch him. The +cruelty of murdering prisoners is not imputed to him as a fault. His +childishly rash, uncalled-for, and ignoble departure from Africa, +leaving his comrades in distress, is set down to his credit, and again +the enemy's fleet twice lets him slip past. When, intoxicated by the +crimes he has committed so successfully, he reaches Paris, the +dissolution of the republican government, which a year earlier might +have ruined him, has reached its extreme limit, and his presence there +now as a newcomer free from party entanglements can only serve to +exalt him--and though he himself has no plan, he is quite ready for +his new role. + +He had no plan, he was afraid of everything, but the parties +snatched at him and demanded his participation. + +He alone--with his ideal of glory and grandeur developed in Italy +and Egypt, his insane self-adulation, his boldness in crime and +frankness in lying--he alone could justify what had to be done. + +He is needed for the place that awaits him, and so almost apart from +his will and despite his indecision, his lack of a plan, and all his +mistakes, he is drawn into a conspiracy that aims at seizing power and +the conspiracy is crowned with success. + +He is pushed into a meeting of the legislature. In alarm he wishes +to flee, considering himself lost. He pretends to fall into a swoon +and says senseless things that should have ruined him. But the once +proud and shrewd rulers of France, feeling that their part is played +out, are even more bewildered than he, and do not say the words they +should have said to destroy him and retain their power. + +Chance, millions of chances, give him power, and all men as if by +agreement co-operate to confirm that power. Chance forms the +characters of the rulers of France, who submit to him; chance forms +the character of Paul I of Russia who recognizes his government; +chance contrives a plot against him which not only fails to harm him +but confirms his power. Chance puts the Duc d'Enghien in his hands and +unexpectedly causes him to kill him--thereby convincing the mob more +forcibly than in any other way that he had the right, since he had the +might. Chance contrives that though he directs all his efforts to +prepare an expedition against England (which would inevitably have +ruined him) he never carries out that intention, but unexpectedly +falls upon Mack and the Austrians, who surrender without a battle. +Chance and genius give him the victory at Austerlitz; and by chance +all men, not only the French but all Europe--except England which does +not take part in the events about to happen--despite their former +horror and detestation of his crimes, now recognize his authority, the +title he has given himself, and his ideal of grandeur and glory, which +seems excellent and reasonable to them all. + +As if measuring themselves and preparing for the coming movement, +the western forces push toward the east several times in 1805, 1806, +1807, and 1809, gaining strength and growing. In 1811 the group of +people that had formed in France unites into one group with the +peoples of Central Europe. The strength of the justification of the +man who stands at the head of the movement grows with the increased +size of the group. During the ten-year preparatory period this man had +formed relations with all the crowned heads of Europe. The discredited +rulers of the world can oppose no reasonable ideal to the insensate +Napoleonic ideal of glory and grandeur. One after another they +hasten to display their insignificance before him. The King of Prussia +sends his wife to seek the great man's mercy; the Emperor of Austria +considers it a favor that this man receives a daughter the Caesars +into his bed; the Pope, the guardian of all that the nations hold +sacred, utilizes religion for the aggrandizement of the great man. +It is not Napoleon who prepares himself for the accomplishment of +his role, so much as all those round him who prepare him to take on +himself the whole responsibility for what is happening and has to +happen. There is no step, no crime or petty fraud he commits, which in +the mouths of those around him is not at once represented as a great +deed. The most suitable fete the Germans can devise for him is a +celebration of Jena and Auerstadt. Not only is he great, but so are +his ancestors, his brothers, his stepsons, and his brothers-in-law. +Everything is done to deprive him of the remains of his reason and +to prepare him for his terrible part. And when he is ready so too +are the forces. + +The invasion pushes eastward and reaches its final goal--Moscow. +That city is taken; the Russian army suffers heavier losses than the +opposing armies had suffered in the former war from Austerlitz to +Wagram. But suddenly instead of those chances and that genius which +hitherto had so consistently led him by an uninterrupted series of +successes to the predestined goal, an innumerable sequence of +inverse chances occur--from the cold in his head at Borodino to the +sparks which set Moscow on fire, and the frosts--and instead of +genius, stupidity and immeasurable baseness become evident. + +The invaders flee, turn back, flee again, and all the chances are +now not for Napoleon but always against him. + +A countermovement is then accomplished from east to west with a +remarkable resemblance to the preceding movement from west to east. +Attempted drives from east to west--similar to the contrary +movements of 1805, 1807, and 1809--precede the great westward +movement; there is the same coalescence into a group of enormous +dimensions; the same adhesion of the people of Central Europe to the +movement; the same hesitation midway, and the same increasing rapidity +as the goal is approached. + +Paris, the ultimate goal, is reached. The Napoleonic government +and army are destroyed. Napoleon himself is no longer of any +account; all his actions are evidently pitiful and mean, but again +an inexplicable chance occurs. The allies detest Napoleon whom they +regard as the cause of their sufferings. Deprived of power and +authority, his crimes and his craft exposed, he should have appeared +to them what he appeared ten years previously and one year later--an +outlawed brigand. But by some strange chance no one perceives this. +His part is not yet ended. The man who ten years before and a year +later was considered an outlawed brigand is sent to an island two +days' sail from France, which for some reason is presented to him as +his dominion, and guards are given to him and millions of money are +paid him. + + + + + +CHAPTER IV + + +The flood of nations begins to subside into its normal channels. The +waves of the great movement abate, and on the calm surface eddies +are formed in which float the diplomatists, who imagine that they have +caused the floods to abate. + +But the smooth sea again suddenly becomes disturbed. The +diplomatists think that their disagreements are the cause of this +fresh pressure of natural forces; they anticipate war between their +sovereigns; the position seems to them insoluble. But the wave they +feel to be rising does not come from the quarter they expect. It rises +again from the same point as before--Paris. The last backwash of the +movement from the west occurs: a backwash which serves to solve the +apparently insuperable diplomatic difficulties and ends the military +movement of that period of history. + +The man who had devastated France returns to France alone, without +any conspiracy and without soldiers. Any guard might arrest him, but +by strange chance no one does so and all rapturously greet the man +they cursed the day before and will curse again a month later. + +This man is still needed to justify the final collective act. + +That act is performed. + +The last role is played. The actor is bidden to disrobe and wash off +his powder and paint: he will not be wanted any more. + +And some years pass during which he plays a pitiful comedy to +himself in solitude on his island, justifying his actions by intrigues +and lies when the justification is no longer needed, and displaying to +the whole world what it was that people had mistaken for strength as +long as an unseen hand directed his actions. + +The manager having brought the drama to a close and stripped the +actor shows him to us. + +"See what you believed in! This is he! Do you now see that it was +not he but I who moved you?" + +But dazed by the force of the movement, it was long before people +understood this. + +Still greater coherence and inevitability is seen in the life of +Alexander I, the man who stood at the head of the countermovement from +east to west. + +What was needed for him who, overshadowing others, stood at the head +of that movement from east to west? + +What was needed was a sense of justice and a sympathy with +European affairs, but a remote sympathy not dulled by petty interests; +a moral superiority over those sovereigns of the day who co-operated +with him; a mild and attractive personality; and a personal +grievance against Napoleon. And all this was found in Alexander I; all +this had been prepared by innumerable so-called chances in his life: +his education, his early liberalism, the advisers who surrounded +him, and by Austerlitz, and Tilsit, and Erfurt. + +During the national war he was inactive because he was not needed. +But as soon as the necessity for a general European war presented +itself he appeared in his place at the given moment and, uniting the +nations of Europe, led them to the goal. + +The goal is reached. After the final war of 1815 Alexander possesses +all possible power. How does he use it? + +Alexander I--the pacifier of Europe, the man who from his early +years had striven only for his people's welfare, the originator of the +liberal innovations in his fatherland--now that he seemed to possess +the utmost power and therefore to have the possibility of bringing +about the welfare of his peoples--at the time when Napoleon in exile +was drawing up childish and mendacious plans of how he would have made +mankind happy had he retained power--Alexander I, having fulfilled his +mission and feeling the hand of God upon him, suddenly recognizes +the insignificance of that supposed power, turns away from it, and +gives it into the hands of contemptible men whom he despises, saying +only: + +"Not unto us, not unto us, but unto Thy Name!... I too am a man like +the rest of you. Let me live like a man and think of my soul and of +God." + +As the sun and each atom of ether is a sphere complete in itself, +and yet at the same time only a part of a whole too immense for man to +comprehend, so each individual has within himself his own aims and yet +has them to serve a general purpose incomprehensible to man. + +A bee settling on a flower has stung a child. And the child is +afraid of bees and declares that bees exist to sting people. A poet +admires the bee sucking from the chalice of a flower and says it +exists to suck the fragrance of flowers. A beekeeper, seeing the bee +collect pollen from flowers and carry it to the hive, says that it +exists to gather honey. Another beekeeper who has studied the life +of the hive more closely says that the bee gathers pollen dust to feed +the young bees and rear a queen, and that it exists to perpetuate +its race. A botanist notices that the bee flying with the pollen of +a male flower to a pistil fertilizes the latter, and sees in this +the purpose of the bee's existence. Another, observing the migration +of plants, notices that the bee helps in this work, and may say that +in this lies the purpose of the bee. But the ultimate purpose of the +bee is not exhausted by the first, the second, or any of the processes +the human mind can discern. The higher the human intellect rises in +the discovery of these purposes, the more obvious it becomes, that the +ultimate purpose is beyond our comprehension. + +All that is accessible to man is the relation of the life of the bee +to other manifestations of life. And so it is with the purpose of +historic characters and nations. + + + + + +CHAPTER V + + +Natasha's wedding to Bezukhov, which took place in 1813, was the +last happy event in the family of the old Rostovs. Count Ilya Rostov +died that same year and, as always happens, after the father's death +the family group broke up. + +The events of the previous year: the burning of Moscow and the +flight from it, the death of Prince Andrew, Natasha's despair, Petya's +death, and the old countess' grief fell blow after blow on the old +count's head. He seemed to be unable to understand the meaning of +all these events, and bowed his old head in a spiritual sense as if +expecting and inviting further blows which would finish him. He seemed +now frightened and distraught and now unnaturally animated and +enterprising. + +The arrangements for Natasha's marriage occupied him for a while. He +ordered dinners and suppers and obviously tried to appear cheerful, +but his cheerfulness was not infectious as it used to be: on the +contrary it evoked the compassion of those who knew and liked him. + +When Pierre and his wife had left, he grew very quiet and began to +complain of depression. A few days later he fell ill and took to his +bed. He realized from the first that he would not get up again, +despite the doctor's encouragement. The countess passed a fortnight in +an armchair by his pillow without undressing. Every time she gave +him his medicine he sobbed and silently kissed her hand. On his last +day, sobbing, he asked her and his absent son to forgive him for +having dissipated their property--that being the chief fault of +which he was conscious. After receiving communion and unction he +quietly died; and next day a throng of acquaintances who came to pay +their last respects to the deceased filled the house rented by the +Rostovs. All these acquaintances, who had so often dined and danced at +his house and had so often laughed at him, now said, with a common +feeling of self-reproach and emotion, as if justifying themselves: +"Well, whatever he may have been he was a most worthy man. You don't +meet such men nowadays.... And which of us has not weaknesses of his +own?" + +It was just when the count's affairs had become so involved that +it was impossible to say what would happen if he lived another year +that he unexpectedly died. + +Nicholas was with the Russian army in Paris when the news of his +father's death reached him. He at once resigned his commission, and +without waiting for it to be accepted took leave of absence and went +to Moscow. The state of the count's affairs became quite obvious a +month after his death, surprising everyone by the immense total of +small debts the existence of which no one had suspected. The debts +amounted to double the value of the property. + +Friends and relations advised Nicholas to decline the inheritance. +But he regarded such a refusal as a slur on his father's memory, which +he held sacred, and therefore would not hear of refusing and +accepted the inheritance together with the obligation to pay the +debts. + +The creditors who had so long been silent, restrained by a vague but +powerful influence exerted on them while he lived by the count's +careless good nature, all proceeded to enforce their claims at once. +As always happens in such cases rivalry sprang up as to which should +get paid first, and those who like Mitenka held promissory notes given +them as presents now became the most exacting of the creditors. +Nicholas was allowed no respite and no peace, and those who had seemed +to pity the old man--the cause of their losses (if they were +losses)--now remorselessly pursued the young heir who had +voluntarily undertaken the debts and was obviously not guilty of +contracting them. + +Not one of the plans Nicholas tried succeeded; the estate was sold +by auction for half its value, and half the debts still remained +unpaid. Nicholas accepted thirty thousand rubles offered him by his +brother-in-law Bezukhov to pay off debts he regarded as genuinely +due for value received. And to avoid being imprisoned for the +remainder, as the creditors threatened, he re-entered the government +service. + +He could not rejoin the army where he would have been made colonel +at the next vacancy, for his mother now clung to him as her one hold +on life; and so despite his reluctance to remain in Moscow among people +who had known him before, and despite his abhorrence of the civil +service, he accepted a post in Moscow in that service, doffed the +uniform of which he was so fond, and moved with his mother and Sonya +to a small house on the Sivtsev Vrazhek. + +Natasha and Pierre were living in Petersburg at the time and had +no clear idea of Nicholas' circumstances. Having borrowed money from +his brother-in-law, Nicholas tried to hide his wretched condition from +him. His position was the more difficult because with his salary of +twelve hundred rubles he had not only to keep himself, his mother, and +Sonya, but had to shield his mother from knowledge of their poverty. +The countess could not conceive of life without the luxurious +conditions she had been used to from childhood and, unable to +realize how hard it was for her son, kept demanding now a carriage +(which they did not keep) to send for a friend, now some expensive +article of food for herself, or wine for her son, or money to buy a +present as a surprise for Natasha or Sonya, or for Nicholas himself. + +Sonya kept house, attended on her aunt, read to her, put up with her +whims and secret ill-will, and helped Nicholas to conceal their +poverty from the old countess. Nicholas felt himself irredeemably +indebted to Sonya for all she was doing for his mother and greatly +admired her patience and devotion, but tried to keep aloof from her. + +He seemed in his heart to reproach her for being too perfect, and +because there was nothing to reproach her with. She had all that +people are valued for, but little that could have made him love her. +He felt that the more he valued her the less he loved her. He had +taken her at her word when she wrote giving him his freedom and now +behaved as if all that had passed between them had been long forgotten +and could never in any case be renewed. + +Nicholas' position became worse and worse. The idea of putting +something aside out of his salary proved a dream. Not only did he +not save anything, but to comply with his mother's demands he even +incurred some small debts. He could see no way out of this +situation. The idea of marrying some rich woman, which was suggested +to him by his female relations, was repugnant to him. The other way +out--his mother's death--never entered his head. He wished for nothing +and hoped for nothing, and deep in his heart experienced a gloomy +and stern satisfaction in an uncomplaining endurance of his +position. He tried to avoid his old acquaintances with their +commiseration and offensive offers of assistance; he avoided all +distraction and recreation, and even at home did nothing but play +cards with his mother, pace silently up and down the room, and smoke +one pipe after another. He seemed carefully to cherish within +himself the gloomy mood which alone enabled him to endure his +position. + + + + + +CHAPTER VI + + +At the beginning of winter Princess Mary came to Moscow. From +reports current in town she learned how the Rostovs were situated, and +how "the son has sacrificed himself for his mother," as people were +saying. + +"I never expected anything else of him," said Princess Mary to +herself, feeling a joyous sense of her love for him. Remembering her +friendly relations with all the Rostovs which had made her almost a +member of the family, she thought it her duty to go to see them. But +remembering her relations with Nicholas in Voronezh she was shy +about doing so. Making a great effort she did however go to call on +them a few weeks after her arrival in Moscow. + +Nicholas was the first to meet her, as the countess' room could only +be reached through his. But instead of being greeted with pleasure +as she had expected, at his first glance at her his face assumed a +cold, stiff, proud expression she had not seen on it before. He +inquired about her health, led the way to his mother, and having sat +there for five minutes left the room. + +When the princess came out of the countess' room Nicholas met her +again, and with marked solemnity and stiffness accompanied her to +the anteroom. To her remarks about his mother's health he made no +reply. "What's that to you? Leave me in peace," his looks seemed to +say. + +"Why does she come prowling here? What does she want? I can't bear +these ladies and all these civilities!" said he aloud in Sonya's +presence, evidently unable to repress his vexation, after the +princess' carriage had disappeared. + +"Oh, Nicholas, how can you talk like that?" cried Sonya, hardly able +to conceal her delight. "She is so kind and Mamma is so fond of her!" + +Nicholas did not reply and tried to avoid speaking of the princess +any more. But after her visit the old countess spoke of her several +times a day. + +She sang her praises, insisted that her son must call on her, +expressed a wish to see her often, but yet always became ill-humored +when she began to talk about her. + +Nicholas tried to keep silence when his mother spoke of the +princess, but his silence irritated her. + +"She is a very admirable and excellent young woman," said she, +"and you must go and call on her. You would at least be seeing +somebody, and I think it must be dull for you only seeing us." + +"But I don't in the least want to, Mamma." + +"You used to want to, and now you don't. Really I don't understand +you, my dear. One day you are dull, and the next you refuse to see +anyone." + +"But I never said I was dull." + +"Why, you said yourself you don't want even to see her. She is a +very admirable young woman and you always liked her, but now +suddenly you have got some notion or other in your head. You hide +everything from me." + +"Not at all, Mamma." + +"If I were asking you to do something disagreeable now--but I only +ask you to return a call. One would think mere politeness required +it.... Well, I have asked you, and now I won't interfere any more +since you have secrets from your mother." + +"Well, then, I'll go if you wish it." + +"It doesn't matter to me. I only wish it for your sake." + +Nicholas sighed, bit his mustache, and laid out the cards for a +patience, trying to divert his mother's attention to another topic. + +The same conversation was repeated next day and the day after, and +the day after that. + +After her visit to the Rostovs and her unexpectedly chilly reception +by Nicholas, Princess Mary confessed to herself that she had been +right in not wishing to be the first to call. + +"I expected nothing else," she told herself, calling her pride to +her aid. "I have nothing to do with him and I only wanted to see the +old lady, who was always kind to me and to whom I am under many +obligations." + +But she could not pacify herself with these reflections; a feeling +akin to remorse troubled her when she thought of her visit. Though she +had firmly resolved not to call on the Rostovs again and to forget the +whole matter, she felt herself all the time in an awkward position. +And when she asked herself what distressed her, she had to admit +that it was her relation to Rostov. His cold, polite manner did not +express his feeling for her (she knew that) but it concealed +something, and until she could discover what that something was, she +felt that she could not be at ease. + +One day in midwinter when sitting in the schoolroom attending to her +nephew's lessons, she was informed that Rostov had called. With a firm +resolution not to betray herself and not show her agitation, she +sent for Mademoiselle Bourienne and went with her to the drawing room. + +Her first glance at Nicholas' face told her that he had only come to +fulfill the demands of politeness, and she firmly resolved to maintain +the tone in which he addressed her. + +They spoke of the countess' health, of their mutual friends, of +the latest war news, and when the ten minutes required by propriety +had elapsed after which a visitor may rise, Nicholas got up to say +good-by. + +With Mademoiselle Bourienne's help the princess had maintained the +conversation very well, but at the very last moment, just when he +rose, she was so tired of talking of what did not interest her, and +her mind was so full of the question why she alone was granted so +little happiness in life, that in a fit of absent-mindedness she sat +still, her luminous eyes gazing fixedly before her, not noticing +that he had risen. + +Nicholas glanced at her and, wishing to appear not to notice her +abstraction, made some remark to Mademoiselle Bourienne and then again +looked at the princess. She still sat motionless with a look of +suffering on her gentle face. He suddenly felt sorry for her and was +vaguely conscious that he might be the cause of the sadness her face +expressed. He wished to help her and say something pleasant, but could +think of nothing to say. + +"Good-by, Princess!" said he. + +She started, flushed, and sighed deeply. + +"Oh, I beg your pardon," she said as if waking up. "Are you going +already, Count? Well then, good-by! Oh, but the cushion for the +countess!" + +"Wait a moment, I'll fetch it," said Mademoiselle Bourienne, and she +left the room. + +They both sat silent, with an occasional glance at one another. + +"Yes, Princess," said Nicholas at last with a sad smile, "it doesn't +seem long ago since we first met at Bogucharovo, but how much water +has flowed since then! In what distress we all seemed to be then, +yet I would give much to bring back that time... but there's no +bringing it back." + +Princess Mary gazed intently into his eyes with her own luminous +ones as he said this. She seemed to be trying to fathom the hidden +meaning of his words which would explain his feeling for her. + +"Yes, yes," said she, "but you have no reason to regret the past, +Count. As I understand your present life, I think you will always +recall it with satisfaction, because the self-sacrifice that fills +it now..." + +"I cannot accept your praise," he interrupted her hurriedly. "On the +contrary I continually reproach myself.... But this is not at all an +interesting or cheerful subject." + +His face again resumed its former stiff and cold expression. But the +princess had caught a glimpse of the man she had known and loved, +and it was to him that she now spoke. + +"I thought you would allow me to tell you this," she said. "I had +come so near to you... and to all your family that I thought you would +not consider my sympathy misplaced, but I was mistaken," and +suddenly her voice trembled. "I don't know why," she continued, +recovering herself, "but you used to be different, and..." + +"There are a thousand reasons why," laying special emphasis on the +why. "Thank you, Princess," he added softly. "Sometimes it is hard." + +"So that's why! That's why!" a voice whispered in Princess Mary's +soul. "No, it was not only that gay, kind, and frank look, not only +that handsome exterior, that I loved in him. I divined his noble, +resolute, self-sacrificing spirit too," she said to herself. "Yes, +he is poor now and I am rich.... Yes, that's the only reason.... +Yes, were it not for that..." And remembering his former tenderness, +and looking now at his kind, sorrowful face, she suddenly understood +the cause of his coldness. + +"But why, Count, why?" she almost cried, unconsciously moving closer +to him. "Why? Tell me. You must tell me!" + +He was silent. + +"I don't understand your why, Count," she continued, "but it's +hard for me... I confess it. For some reason you wish to deprive me of +our former friendship. And that hurts me." There were tears in her +eyes and in her voice. "I have had so little happiness in life that +every loss is hard for me to bear.... Excuse me, good-by!" and +suddenly she began to cry and was hurrying from the room. + +"Princess, for God's sake!" he exclaimed, trying to stop her. +"Princess!" + +She turned round. For a few seconds they gazed silently into one +another's eyes--and what had seemed impossible and remote suddenly +became possible, inevitable, and very near. + + + + + +CHAPTER VII + + +In the winter of 1813 Nicholas married Princess Mary and moved to +Bald Hills with his wife, his mother, and Sonya. + +Within four years he had paid off all his remaining debts without +selling any of his wife's property, and having received a small +inheritance on the death of a cousin he paid his debt to Pierre as +well. + +In another three years, by 1820, he had so managed his affairs +that he was able to buy a small estate adjoining Bald Hills and was +negotiating to buy back Otradnoe--that being his pet dream. + +Having started farming from necessity, he soon grew so devoted to it +that it became his favorite and almost his sole occupation. Nicholas +was a plain farmer: he did not like innovations, especially the +English ones then coming into vogue. He laughed at theoretical +treatises on estate management, disliked factories, the raising of +expensive products, and the buying of expensive seed corn, and did not +make a hobby of any particular part of the work on his estate. He +always had before his mind's eye the estate as a whole and not any +particular part of it. The chief thing in his eyes was not the +nitrogen in the soil, nor the oxygen in the air, nor manures, nor +special plows, but that most important agent by which nitrogen, +oxygen, manure, and plow were made effective--the peasant laborer. +When Nicholas first began farming and began to understand its +different branches, it was the serf who especially attracted his +attention. The peasant seemed to him not merely a tool, but also a +judge of farming and an end in himself. At first he watched the serfs, +trying to understand their aims and what they considered good and bad, +and only pretended to direct them and give orders while in reality +learning from them their methods, their manner of speech, and their +judgment of what was good and bad. Only when he had understood the +peasants' tastes and aspirations, had learned to talk their +language, to grasp the hidden meaning of their words, and felt akin to +them did he begin boldly to manage his serfs, that is, to perform +toward them the duties demanded of him. And Nicholas' management +produced very brilliant results. + +Guided by some gift of insight, on taking up the management of the +estates he at once unerringly appointed as bailiff, village elder, and +delegate, the very men the serfs would themselves have chosen had they +had the right to choose, and these posts never changed hands. Before +analyzing the properties of manure, before entering into the debit and +credit (as he ironically called it), he found out how many cattle +the peasants had and increased the number by all possible means. He +kept the peasant families together in the largest groups possible, not +allowing the family groups to divide into separate households. He +was hard alike on the lazy, the depraved, and the weak, and tried to +get them expelled from the commune. + +He was as careful of the sowing and reaping of the peasants' hay and +corn as of his own, and few landowners had their crops sown and +harvested so early and so well, or got so good a return, as did +Nicholas. + +He disliked having anything to do with the domestic serfs--the +"drones" as he called them--and everyone said he spoiled them by his +laxity. When a decision had to be taken regarding a domestic serf, +especially if one had to be punished, he always felt undecided and +consulted everybody in the house; but when it was possible to have a +domestic serf conscripted instead of a land worker he did so without +the least hesitation. He never felt any hesitation in dealing with the +peasants. He knew that his every decision would be approved by them +all with very few exceptions. + +He did not allow himself either to be hard on or punish a man, or to +make things easy for or reward anyone, merely because he felt inclined +to do so. He could not have said by what standard he judged what he +should or should not do, but the standard was quite firm and +definite in his own mind. + +Often, speaking with vexation of some failure or irregularity, he +would say: "What can one do with our Russian peasants?" and imagined +that he could not bear them. + +Yet he loved "our Russian peasants" and their way of life with his +whole soul, and for that very reason had understood and assimilated +the one way and manner of farming which produced good results. + +Countess Mary was jealous of this passion of her husband's and +regretted that she could not share it; but she could not understand +the joys and vexations he derived from that world, to her so remote +and alien. She could not understand why he was so particularly +animated and happy when, after getting up at daybreak and spending the +whole morning in the fields or on the threshing floor, he returned +from the sowing or mowing or reaping to have tea with her. She did not +understand why he spoke with such admiration and delight of the +farming of the thrifty and well-to-do peasant Matthew Ermishin, who +with his family had carted corn all night; or of the fact that his +(Nicholas') sheaves were already stacked before anyone else had his +harvest in. She did not understand why he stepped out from the +window to the veranda and smiled under his mustache and winked so +joyfully, when warm steady rain began to fall on the dry and thirsty +shoots of the young oats, or why when the wind carried away a +threatening cloud during the hay harvest he would return from the +barn, flushed, sunburned, and perspiring, with a smell of wormwood and +gentian in his hair and, gleefully rubbing his hands, would say: +"Well, one more day and my grain and the peasants' will all be under +cover." + +Still less did she understand why he, kindhearted and always ready +to anticipate her wishes, should become almost desperate when she +brought him a petition from some peasant men or women who had appealed +to her to be excused some work; why he, that kind Nicholas, should +obstinately refuse her, angrily asking her not to interfere in what +was not her business. She felt he had a world apart, which he loved +passionately and which had laws she had not fathomed. + +Sometimes when, trying to understand him, she spoke of the good work +he was doing for his serfs, he would be vexed and reply: "Not in the +least; it never entered my head and I wouldn't do that for their good! +That's all poetry and old wives' talk--all that doing good to one's +neighbor! What I want is that our children should not have to go +begging. I must put our affairs in order while I am alive, that's all. +And to do that, order and strictness are essential.... That's all +about it!" said he, clenching his vigorous fist. "And fairness, of +course," he added, "for if the peasant is naked and hungry and has +only one miserable horse, he can do no good either for himself or +for me." + +And all Nicholas did was fruitful--probably just because he +refused to allow himself to think that he was doing good to others for +virtue's sake. His means increased rapidly; serfs from neighboring +estates came to beg him to buy them, and long after his death the +memory of his administration was devoutly preserved among the serfs. +"He was a master... the peasants' affairs first and then his own. Of +course he was not to be trifled with either--in a word, he was a +real master!" + + + + + +CHAPTER VIII + +One matter connected with his management sometimes worried Nicholas, +and that was his quick temper together with his old hussar habit of +making free use of his fists. At first he saw nothing reprehensible in +this, but in the second year of his marriage his view of that form +of punishment suddenly changed. + +Once in summer he had sent for the village elder from Bogucharovo, a +man who had succeeded to the post when Dron died and who was accused +of dishonesty and various irregularities. Nicholas went out into the +porch to question him, and immediately after the elder had given a few +replies the sound of cries and blows were heard. On returning to lunch +Nicholas went up to his wife, who sat with her head bent low over +her embroidery frame, and as usual began to tell her what he had +been doing that morning. Among other things he spoke of the +Bogucharovo elder. Countess Mary turned red and then pale, but +continued to sit with head bowed and lips compressed and gave her +husband no reply. + +"Such an insolent scoundrel!" he cried, growing hot again at the +mere recollection of him. "If he had told me he was drunk and did +not see... But what is the matter with you, Mary?" he suddenly asked. + +Countess Mary raised her head and tried to speak, but hastily looked +down again and her lips puckered. + +"Why, whatever is the matter, my dearest?" + +The looks of the plain Countess Mary always improved when she was in +tears. She never cried from pain or vexation, but always from sorrow +or pity, and when she wept her radiant eyes acquired an irresistible +charm. + +The moment Nicholas took her hand she could no longer restrain +herself and began to cry. + +"Nicholas, I saw it... he was to blame, but why do you... Nicholas!" +and she covered her face with her hands. + +Nicholas said nothing. He flushed crimson, left her side, and +paced up and down the room. He understood what she was weeping +about, but could not in his heart at once agree with her that what +he had regarded from childhood as quite an everyday event was wrong. +"Is it just sentimentality, old wives' tales, or is she right?" he +asked himself. Before he had solved that point he glanced again at her +face filled with love and pain, and he suddenly realized that she +was right and that he had long been sinning against himself. + +"Mary," he said softly, going up to her, "it will never happen +again; I give you my word. Never," he repeated in a trembling voice +like a boy asking for forgiveness. + +The tears flowed faster still from the countess' eyes. She took +his hand and kissed it. + +"Nicholas, when did you break your cameo?" she asked to change the +subject, looking at his finger on which he wore a ring with a cameo +of Laocoon's head. + +"Today--it was the same affair. Oh, Mary, don't remind me of it!" +and again he flushed. "I give you my word of honor it shan't occur +again, and let this always be a reminder to me," and he pointed to the +broken ring. + +After that, when in discussions with his village elders or +stewards the blood rushed to his face and his fists began to clench, +Nicholas would turn the broken ring on his finger and would drop his +eyes before the man who was making him angry. But he did forget +himself once or twice within a twelvemonth, and then he would go and +confess to his wife, and would again promise that this should really +be the very last time. + +"Mary, you must despise me!" he would say. "I deserve it." + +"You should go, go away at once, if you don't feel strong enough +to control yourself," she would reply sadly, trying to comfort her +husband. + +Among the gentry of the province Nicholas was respected but not +liked. He did not concern himself with the interests of his own class, +and consequently some thought him proud and others thought him stupid. +The whole summer, from spring sowing to harvest, he was busy with +the work on his farm. In autumn he gave himself up to hunting with the +same business like seriousness--leaving home for a month, or even two, +with his hunt. In winter he visited his other villages or spent his +time reading. The books he read were chiefly historical, and on +these he spent a certain sum every year. He was collecting, as he +said, a serious library, and he made it a rule to read through all the +books he bought. He would sit in his study with a grave air, +reading--a task he first imposed upon himself as a duty, but which +afterwards became a habit affording him a special kind of pleasure and +a consciousness of being occupied with serious matters. In winter, +except for business excursions, he spent most of his time at home +making himself one with his family and entering into all the details +of his children's relations with their mother. The harmony between him +and his wife grew closer and closer and he daily discovered fresh +spiritual treasures in her. + +From the time of his marriage Sonya had lived in his house. Before +that, Nicholas had told his wife all that had passed between himself +and Sonya, blaming himself and commending her. He had asked Princess +Mary to be gentle and kind to his cousin. She thoroughly realized +the wrong he had done Sonya, felt herself to blame toward her, and +imagined that her wealth had influenced Nicholas' choice. She could +not find fault with Sonya in any way and tried to be fond of her, +but often felt ill-will toward her which she could not overcome. + +Once she had a talk with her friend Natasha about Sonya and about +her own injustice toward her. + +"You know," said Natasha, "you have read the Gospels a great deal- +there is a passage in them that just fits Sonya." + +"What?" asked Countess Mary, surprised. + +"'To him that hath shall be given, and from him that hath not +shall be taken away.' You remember? She is one that hath not; why, I +don't know. Perhaps she lacks egotism, I don't know, but from her is +taken away, and everything has been taken away. Sometimes I am +dreadfully sorry for her. Formerly I very much wanted Nicholas to +marry her, but I always had a sort of presentiment that it would not +come off. She is a sterile flower, you know--like some strawberry +blossoms. Sometimes I am sorry for her, and sometimes I think she +doesn't feel it as you or I would." + +Though Countess Mary told Natasha that those words in the Gospel +must be understood differently, yet looking at Sonya she agreed with +Natasha's explanation. It really seemed that Sonya did not feel her +position trying, and had grown quite reconciled to her lot as a +sterile flower. She seemed to be fond not so much of individuals as of +the family as a whole. Like a cat, she had attached herself not to the +people but to the home. She waited on the old countess, petted and +spoiled the children, was always ready to render the small services +for which she had a gift, and all this was unconsciously accepted from +her with insufficient gratitude. + +The country seat at Bald Hills had been rebuilt, though not on the +same scale as under the old prince. + +The buildings, begun under straitened circumstances, were more +than simple. The immense house on the old stone foundations was of +wood, plastered only inside. It had bare deal floors and was furnished +with very simple hard sofas, armchairs, tables, and chairs made by +their own serf carpenters out of their own birchwood. The house was +spacious and had rooms for the house serfs and apartments for +visitors. Whole families of the Rostovs' and Bolkonskis' relations +sometimes came to Bald Hills with sixteen horses and dozens of +servants and stayed for months. Besides that, four times a year, on +the name days and birthdays of the hosts, as many as a hundred +visitors would gather there for a day or two. The rest of the year +life pursued its unbroken routine with its ordinary occupations, and +its breakfasts, lunches, dinners, and suppers, provided out of the +produce of the estate. + + + + + +CHAPTER IX + + +It was the eve of St. Nicholas, the fifth of December, 1820. Natasha +had been staying at her brother's with her husband and children +since early autumn. Pierre had gone to Petersburg on business of his +own for three weeks as he said, but had remained there nearly seven +weeks and was expected back every minute. + +Besides the Bezukhov family, Nicholas' old friend the retired +General Vasili Dmitrich Denisov was staying with the Rostovs this +fifth of December. + +On the sixth, which was his name day when the house would be full of +visitors, Nicholas knew he would have to exchange his Tartar tunic for +a tail coat, and put on narrow boots with pointed toes, and drive to +the new church he had built, and then receive visitors who would +come to congratulate him, offer them refreshments, and talk about +the elections of the nobility; but he considered himself entitled to +spend the eve of that day in his usual way. He examined the +bailiff's accounts of the village in Ryazan which belonged to his +wife's nephew, wrote two business letters, and walked over to the +granaries, cattle yards and stables before dinner. Having taken +precautions against the general drunkenness to be expected on the +morrow because it was a great saint's day, he returned to dinner, +and without having time for a private talk with his wife sat down at +the long table laid for twenty persons, at which the whole household +had assembled. At that table were his mother, his mother's old lady +companion Belova, his wife, their three children with their +governess and tutor, his wife's nephew with his tutor, Sonya, Denisov, +Natasha, her three children, their governess, and old Michael +Ivanovich, the late prince's architect, who was living on in +retirement at Bald Hills. + +Countess Mary sat at the other end of the table. When her husband +took his place she concluded, from the rapid manner in which after +taking up his table napkin he pushed back the tumbler and wineglass +standing before him, that he was out of humor, as was sometimes the +case when he came in to dinner straight from the farm--especially +before the soup. Countess Mary well knew that mood of his, and when +she herself was in a good frame of mind quietly waited till he had had +his soup and then began to talk to him and make him admit that there +was no cause for his ill-humor. But today she quite forgot that and +was hurt that he should be angry with her without any reason, and +she felt unhappy. She asked him where he had been. He replied. She +again inquired whether everything was going well on the farm. Her +unnatural tone made him wince unpleasantly and he replied hastily. + +"Then I'm not mistaken," thought Countess Mary. "Why is he cross +with me?" She concluded from his tone that he was vexed with her and +wished to end the conversation. She knew her remarks sounded +unnatural, but could not refrain from asking some more questions. + +Thanks to Denisov the conversation at table soon became general +and lively, and she did not talk to her husband. When they left the +table and went as usual to thank the old countess, Countess Mary +held out her hand and kissed her husband, and asked him why he was +angry with her. + +"You always have such strange fancies! I didn't even think of +being angry," he replied. + +But the word always seemed to her to imply: "Yes, I am angry but I +won't tell you why." + +Nicholas and his wife lived together so happily that even Sonya +and the old countess, who felt jealous and would have liked them to +disagree, could find nothing to reproach them with; but even they +had their moments of antagonism. Occasionally, and it was always +just after they had been happiest together, they suddenly had a +feeling of estrangement and hostility, which occurred most +frequently during Countess Mary's pregnancies, and this was such a +time. + +"Well, messieurs et mesdames," said Nicholas loudly and with +apparent cheerfulness (it seemed to Countess Mary that he did it on +purpose to vex her), "I have been on my feet since six this morning. +Tomorrow I shall have to suffer, so today I'll go and rest." + +And without a word to his wife he went to the little sitting room +and lay down on the sofa. + +"That's always the way," thought Countess Mary. "He talks to +everyone except me. I see... I see that I am repulsive to him, +especially when I am in this condition." She looked down at her +expanded figure and in the glass at her pale, sallow, emaciated face +in which her eyes now looked larger than ever. + +And everything annoyed her--Denisov's shouting and laughter, +Natasha's talk, and especially a quick glance Sonya gave her. + +Sonya was always the first excuse Countess Mary found for feeling +irritated. + +Having sat awhile with her visitors without understanding anything +of what they were saying, she softly left the room and went to the +nursery. + +The children were playing at "going to Moscow" in a carriage made of +chairs and invited her to go with them. She sat down and played with +them a little, but the thought of her husband and his unreasonable +crossness worried her. She got up and, walking on tiptoe with +difficulty, went to the small sitting room. + +"Perhaps he is not asleep; I'll have an explanation with him," she +said to herself. Little Andrew, her eldest boy, imitating his +mother, followed her on tiptoe. She not notice him. + +"Mary, dear, I think he is asleep--he was so tired," said Sonya, +meeting her in the large sitting room (it seemed to Countess Mary that +she crossed her path everywhere). "Andrew may wake him." + +Countess Mary looked round, saw little Andrew following her, felt +that Sonya was right, and for that very reason flushed and with +evident difficulty refrained from saying something harsh. She made +no reply, but to avoid obeying Sonya beckoned to Andrew to follow +her quietly and went to the door. Sonya went away by another door. +From the room in which Nicholas was sleeping came the sound of his +even breathing, every slightest tone of which was familiar to his +wife. As she listened to it she saw before her his smooth handsome +forehead, his mustache, and his whole face, as she had so often seen +it in the stillness of the night when he slept. Nicholas suddenly +moved and cleared his throat. And at that moment little Andrew shouted +from outside the door: "Papa! Mamma's standing here!" Countess Mary +turned pale with fright and made signs to the boy. He grew silent, and +quiet ensued for a moment, terrible to Countess Mary. She knew how +Nicholas disliked being waked. Then through the door she heard +Nicholas clearing his throat again and stirring, and his voice said +crossly: + +"I can't get a moment's peace.... Mary, is that you? Why did you +bring him here?" + +"I only came in to look and did not notice... forgive me..." + +Nicholas coughed and said no more. Countess Mary moved away from the +door and took the boy back to the nursery. Five minutes later little +black-eyed three-year-old Natasha, her father's pet, having learned +from her brother that Papa was asleep and Mamma was in the sitting +room, ran to her father unobserved by her mother. The dark-eyed little +girl boldly opened the creaking door, went up to the sofa with +energetic steps of her sturdy little legs, and having examined the +position of her father, who was asleep with his back to her, rose on +tiptoe and kissed the hand which lay under his head. Nicholas turned +with a tender smile on his face. + +"Natasha, Natasha!" came Countess Mary's frightened whisper from the +door. "Papa wants to sleep." + +"No, Mamma, he doesn't want to sleep," said little Natasha with +conviction. "He's laughing." + +Nicholas lowered his legs, rose, and took his daughter in his arms. + +"Come in, Mary," he said to his wife. + +She went in and sat down by her husband. + +"I did not notice him following me," she said timidly. "I just +looked in." + +Holding his little girl with one arm, Nicholas glanced at his wife +and, seeing her guilty expression, put his other arm around her and +kissed her hair. + +"May I kiss Mamma?" he asked Natasha. + +Natasha smiled bashfully. + +"Again!" she commanded, pointing with a peremptory gesture to the +spot where Nicholas had placed the kiss. + +"I don't know why you think I am cross," said Nicholas, replying +to the question he knew was in his wife's mind. + +"You have no idea how unhappy, how lonely, I feel when you are +like that. It always seems to me... " + +"Mary, don't talk nonsense. You ought to be ashamed of yourself!" he +said gaily. + +"It seems to be that you can't love me, that I am so plain... +always... and now... in this cond..." + +"Oh, how absurd you are! It is not beauty that endears, it's love +that makes us see beauty. It is only Malvinas and women of that kind +who are loved for their beauty. But do I love my wife? I don't love +her, but... I don't know how to put it. Without you, or when something +comes between us like this, I seem lost and can't do anything. Now +do I love my finger? I don't love it, but just try to cut it off!" + +"I'm not like that myself, but I understand. So you're not angry +with me?" + +"Awfully angry!" he said, smiling and getting up. And smoothing +his hair he began to pace the room. + +"Do you know, Mary, what I've been thinking?" he began, +immediately thinking aloud in his wife's presence now that they had +made it up. + +He did not ask if she was ready to listen to him. He did not care. A +thought had occurred to him and so it belonged to her also. And he +told her of his intention to persuade Pierre to stay with them till +spring. + +Countess Mary listened till he had finished, made some remark, and +in her turn began thinking aloud. Her thoughts were about the +children. + +"You can see the woman in her already," she said in French, pointing +to little Natasha. "You reproach us women with being illogical. Here +is our logic. I say: 'Papa wants to sleep!' but she says, 'No, he's +laughing.' And she was right," said Countess Mary with a happy smile. + +"Yes, yes." And Nicholas, taking his little daughter in his strong +hand, lifted her high, placed her on his shoulder, held her by the +legs, and paced the room with her. There was an expression of carefree +happiness on the faces of both father and daughter. + +"But you know you may be unfair. You are too fond of this one," +his wife whispered in French. + +"Yes, but what am I to do?... I try not to show..." + +At that moment they heard the sound of the door pulley and footsteps +in the hall and anteroom, as if someone had arrived. + +"Somebody has come." + +"I am sure it is Pierre. I will go and see," said Countess Mary +and left the room. + +In her absence Nicholas allowed himself to give his little +daughter a gallop round the room. Out of breath, he took the +laughing child quickly from his shoulder and pressed her to his heart. +His capers reminded him of dancing, and looking at the child's round +happy little face he thought of what she would be like when he was +an old man, taking her into society and dancing the mazurka with her +as his old father had danced Daniel Cooper with his daughter. + +"It is he, it is he, Nicholas!" said Countess Mary, re-entering +the room a few minutes later. "Now our Natasha has come to life. You +should have seen her ecstasy, and how he caught it for having stayed +away so long. Well, come along now, quick, quick! It's time you two +were parted," she added, looking smilingly at the little girl who +clung to her father. + +Nicholas went out holding the child by the hand. + +Countess Mary remained in the sitting room. + +"I should never, never have believed that one could be so happy," +she whispered to herself. A smile lit up her face but at the same time +she sighed, and her deep eyes expressed a quiet sadness as though +she felt, through her happiness, that there is another sort of +happiness unattainable in this life and of which she involuntarily +thought at that instant. + + + + + +CHAPTER X + + +Natasha had married in the early spring of 1813, and in 1820 already +had three daughters besides a son for whom she had longed and whom she +was now nursing. She had grown stouter and broader, so that it was +difficult to recognize in this robust, motherly woman the slim, lively +Natasha of former days. Her features were more defined and had a calm, +soft, and serene expression. In her face there was none of the +ever-glowing animation that had formerly burned there and +constituted its charm. Now her face and body were of all that one saw, +and her soul was not visible at all. All that struck the eye was a +strong, handsome, and fertile woman. The old fire very rarely +kindled in her face now. That happened only when, as was the case that +day, her husband returned home, or a sick child was convalescent, or +when she and Countess Mary spoke of Prince Andrew (she never mentioned +him to her husband, who she imagined was jealous of Prince Andrew's +memory), or on the rare occasions when something happened to induce +her to sing, a practice she had quite abandoned since her marriage. At +the rare moments when the old fire did kindle in her handsome, fully +developed body she was even more attractive than in former days. + +Since their marriage Natasha and her husband had lived in Moscow, in +Petersburg, on their estate near Moscow, or with her mother, that is +to say, in Nicholas' house. The young Countess Bezukhova was not often +seen in society, and those who met her there were not pleased with her +and found her neither attractive nor amiable. Not that Natasha liked +solitude--she did not know whether she liked it or not, she even +thought that she did not--but with her pregnancies, her +confinements, the nursing of her children, and sharing every moment of +her husband's life, she had demands on her time which could be +satisfied only by renouncing society. All who had known Natasha before +her marriage wondered at the change in her as at something +extraordinary. Only the old countess with her maternal instinct had +realized that all Natasha's outbursts had been due to her need of +children and a husband--as she herself had once exclaimed at +Otradnoe not so much in fun as in earnest--and her mother was now +surprised at the surprise expressed by those who had never +understood Natasha, and she kept saying that she had always known that +Natasha would make an exemplary wife and mother. + +"Only she lets her love of her husband and children overflow all +bounds," said the countess, "so that it even becomes absurd." + +Natasha did not follow the golden rule advocated by clever folk, +especially by the French, which says that a girl should not let +herself go when she marries, should not neglect her accomplishments, +should be even more careful of her appearance than when she was +unmarried, and should fascinate her husband as much as she did +before he became her husband. Natasha on the contrary had at once +abandoned all her witchery, of which her singing had been an unusually +powerful part. She gave it up just because it was so powerfully +seductive. She took no pains with her manners or with of speech, or +with her toilet, or to show herself to her husband in her most +becoming attitudes, or to avoid inconveniencing him by being too +exacting. She acted in contradiction to all those rules. She felt that +the allurements instinct had formerly taught her to use would now be +merely ridiculous in the eyes of her husband, to whom she had from the +first moment given herself up entirely--that is, with her whole +soul, leaving no corner of it hidden from him. She felt that her unity +with her husband was not maintained by the poetic feelings that had +attracted him to her, but by something else--indefinite but firm as +the bond between her own body and soul. + +To fluff out her curls, put on fashionable dresses, and sing +romantic songs to fascinate her husband would have seemed as strange +as to adorn herself to attract herself. To adorn herself for others +might perhaps have been agreeable--she did not know--but she had no +time at all for it. The chief reason for devoting no time either to +singing, to dress, or to choosing her words was that she really had no +time to spare for these things. + +We know that man has the faculty of becoming completely absorbed +in a subject however trivial it may be, and that there is no subject +so trivial that it will not grow to infinite proportions if one's +entire attention is devoted to it. + +The subject which wholly engrossed Natasha's attention was her +family: that is, her husband whom she had to keep so that he should +belong entirely to her and to the home, and the children whom she +had to bear, bring into the world, nurse, and bring up. + +And the deeper she penetrated, not with her mind only but with her +whole soul, her whole being, into the subject that absorbed her, the +larger did that subject grow and the weaker and more inadequate did +her powers appear, so that she concentrated them wholly on that one +thing and yet was unable to accomplish all that she considered +necessary. + +There were then as now conversations and discussions about women's +rights, the relations of husband and wife and their freedom and +rights, though these themes were not yet termed questions as they +are now; but these topics were not merely uninteresting to Natasha, +she positively did not understand them. + +These questions, then as now, existed only for those who see nothing +in marriage but the pleasure married people get from one another, that +is, only the beginnings of marriage and not its whole significance, +which lies in the family. + +Discussions and questions of that kind, which are like the +question of how to get the greatest gratification from one's dinner, +did not then and do not now exist for those for whom the purpose of +a dinner is the nourishment it affords; and the purpose of marriage is +the family. + +If the purpose of dinner is to nourish the body, a man who eats +two dinners at once may perhaps get more enjoyment but will not attain +his purpose, for his stomach will not digest the two dinners. + +If the purpose of marriage is the family, the person who wishes to +have many wives or husbands may perhaps obtain much pleasure, but in +that case will not have a family. + +If the purpose of food is nourishment and the purpose of marriage is +the family, the whole question resolves itself into not eating more +than one can digest, and not having more wives or husbands than are +needed for the family--that is, one wife or one husband. Natasha +needed a husband. A husband was given her and he gave her a family. +And she not only saw no need of any other or better husband, but as +all the powers of her soul were intent on serving that husband and +family, she could not imagine and saw no interest in imagining how +it would be if things were different. + +Natasha did not care for society in general, but prized the more the +society of her relatives--Countess Mary, and her brother, her +mother, and Sonya. She valued the company of those to whom she could +come striding disheveled from the nursery in her dressing gown, and +with joyful face show a yellow instead of a green stain on baby's +napkin, and from whom she could hear reassuring words to the effect +that baby was much better. + +To such an extent had Natasha let herself go that the way she +dressed and did her hair, her ill-chosen words, and her jealousy- +she was jealous of Sonya, of the governess, and of every woman, pretty +or plain--were habitual subjects of jest to those about her. The +general opinion was that Pierre was under his wife's thumb, which +was really true. From the very first days of their married life +Natasha had announced her demands. Pierre was greatly surprised by his +wife's view, to him a perfectly novel one, that every moment of his +life belonged to her and to the family. His wife's demands +astonished him, but they also flattered him, and he submitted to them. + +Pierre's subjection consisted in the fact that he not only dared not +flirt with, but dared not even speak smilingly to, any other woman; +did not dare dine at the Club as a pastime, did not dare spend money a +whim, and did not dare absent himself for any length of time, except +on business--in which his wife included his intellectual pursuits, +which she did not in the least understand but to which she +attributed great importance. To make up for this, at home Pierre had +the right to regulate his life and that of the whole family exactly as +he chose. At home Natasha placed herself in the position of a slave to +her husband, and the whole household went on tiptoe when he was +occupied--that is, was reading or writing in his study. Pierre had but +to show a partiality for anything to get just what he liked done +always. He had only to express a wish and Natasha would jump up and +run to fulfill it. + +The entire household was governed according to Pierre's supposed +orders, that is, by his wishes which Natasha tried to guess. Their way +of life and place of residence, their acquaintances and ties, +Natasha's occupations, the children's upbringing, were all selected +not merely with regard to Pierre's expressed wishes, but to what +Natasha from the thoughts he expressed in conversation supposed his +wishes to be. And she deduced the essentials of his wishes quite +correctly, and having once arrived at them clung to them +tenaciously. When Pierre himself wanted to change his mind she would +fight him with his own weapons. + +Thus in a time of trouble ever memorable to him after the birth of +their first child who was delicate, when they had to change the wet +nurse three times and Natasha fell ill from despair, Pierre one day +told her of Rousseau's view, with which he quite agreed, that to +have a wet nurse is unnatural and harmful. When her next baby was +born, despite the opposition of her mother, the doctors, and even of +her husband himself--who were all vigorously opposed to her nursing +her baby herself, a thing then unheard of and considered injurious- +she insisted on having her own way, and after that nursed all her +babies herself. + +It very often happened that in a moment of irritation husband and +wife would have a dispute, but long afterwards Pierre to his +surprise and delight would find in his wife's ideas and actions the +very thought against which she had argued, but divested of +everything superfluous that in the excitement of the dispute he had +added when expressing his opinion. + +After seven years of marriage Pierre had the joyous and firm +consciousness that he was not a bad man, and he felt this because he +saw himself reflected in his wife. He felt the good and bad within +himself inextricably mingled and overlapping. But only what was really +good in him was reflected in his wife, all that was not quite good was +rejected. And this was not the result of logical reasoning but was a +direct and mysterious reflection. + + + + + +CHAPTER XI + + +Two months previously when Pierre was already staying with the +Rostovs he had received a letter from Prince Theodore, asking him to +come to Petersburg to confer on some important questions that were +being discussed there by a society of which Pierre was one of the +principal founders. + +On reading that letter (she always read her husband's letters) +Natasha herself suggested that he should go to Petersburg, though +she would feel his absence very acutely. She attributed immense +importance to all her husband's intellectual and abstract interests +though she did not understand them, and she always dreaded being a +hindrance to him in such matters. To Pierre's timid look of inquiry +after reading the letter she replied by asking him to go, but to fix a +definite date for his return. He was given four weeks' leave of +absence. + +Ever since that leave of absence had expired, more than a +fortnight before, Natasha had been in a constant state of alarm, +depression, and irritability. + +Denisov, now a general on the retired list and much dissatisfied +with the present state of affairs, had arrived during that +fortnight. He looked at Natasha with sorrow and surprise as at a bad +likeness of a person once dear. A dull, dejected look, random replies, +and talk about the nursery was all he saw and heard from his former +enchantress. + +Natasha was sad and irritable all that time, especially when her +mother, her brother, Sonya, or Countess Mary in their efforts to +console her tried to excuse Pierre and suggested reasons for his delay +in returning. + +"It's all nonsense, all rubbish--those discussions which lead to +nothing and all those idiotic societies!" Natasha declared of the very +affairs in the immense importance of which she firmly believed. + +And she would go to the nursery to nurse Petya, her only boy. No one +else could tell her anything so comforting or so reasonable as this +little three-month-old creature when he lay at her breast and she +was conscious of the movement of his lips and the snuffling of his +little nose. That creature said: "You are angry, you are jealous, +you would like to pay him out, you are afraid--but here am I! And I am +he..." and that was unanswerable. It was more than true. + +During that fortnight of anxiety Natasha resorted to the baby for +comfort so often, and fussed over him so much, that she overfed him +and he fell ill. She was terrified by his illness, and yet that was +just what she needed. While attending to him she bore the anxiety +about her husband more easily. + +She was nursing her boy when the sound of Pierre's sleigh was +heard at the front door, and the old nurse--knowing how to please +her mistress--entered the room inaudibly but hurriedly and with a +beaming face. + +"Has he come?" Natasha asked quickly in a whisper, afraid to move +lest she should rouse the dozing baby. + +"He's come, ma'am," whispered the nurse. + +The blood rushed to Natasha's face and her feet involuntarily moved, +but she could not jump up and run out. The baby again opened his +eyes and looked at her. "You're here?" he seemed to be saying, and +again lazily smacked his lips. + +Cautiously withdrawing her breast, Natasha rocked him a little, +handed him to the nurse, and went with rapid steps toward the door. +But at the door she stopped as if her conscience reproached her for +having in her joy left the child too soon, and she glanced round. +The nurse with raised elbows was lifting the infant over the rail of +his cot. + +"Go, ma'am! Don't worry, go!" she whispered, smiling, with the +kind of familiarity that grows up between a nurse and her mistress. + +Natasha ran with light footsteps to the anteroom. + +Denisov, who had come out of the study into the dancing room with +his pipe, now for the first time recognized the old Natasha. A flood +of brilliant, joyful light poured from her transfigured face. + +"He's come!" she exclaimed as she ran past, and Denisov felt that he +too was delighted that Pierre, whom he did not much care for, had +returned. + +On reaching the vestibule Natasha saw a tall figure in a fur coat +unwinding his scarf. "It's he! It's really he! He has come!" she +said to herself, and rushing at him embraced him, pressed his head +to her breast, and then pushed him back and gazed at his ruddy, +happy face, covered with hoarfrost. "Yes, it is he, happy and +contented..." + +Then all at once she remembered the tortures of suspense she had +experienced for the last fortnight, and the joy that had lit up her +face vanished; she frowned and overwhelmed Pierre with a torrent of +reproaches and angry words. + +"Yes, it's all very well for you. You are pleased, you've had a good +time.... But what about me? You might at least have shown +consideration for the children. I am nursing and my milk was +spoiled.... Petya was at death's door. But you were enjoying yourself. +Yes, enjoying..." + +Pierre knew he was not to blame, for he could not have come +sooner; he knew this outburst was unseemly and would blow over in a +minute or two; above all he knew that he himself was bright and happy. +He wanted to smile but dared not even think of doing so. He made a +piteous, frightened face and bent down. + +"I could not, on my honor. But how is Petya?" + +"All right now. Come along! I wonder you're not ashamed! If only you +could see what I was like without you, how I suffered!" + +"You are well?" + +"Come, come!" she said, not letting go of his arm. And they went +to their rooms. + +When Nicholas and his wife came to look for Pierre he was in the +nursery holding his baby son, who was again awake, on his huge right +palm and dandling him. A blissful bright smile was fixed on the baby's +broad face with its toothless open mouth. The storm was long since +over and there was bright, joyous sunshine on Natasha's face as she +gazed tenderly at her husband and child. + +"And have you talked everything well over with Prince Theodore?" she +asked. + +"Yes, capitally." + +"You see, he holds it up." (She meant the baby's head.) "But how +he did frighten me... You've seen the princess? Is it true she's in +love with that..." + +"Yes, just fancy..." + +At that moment Nicholas and Countess Mary came in. Pierre with the +baby on his hand stooped, kissed them, and replied to their inquiries. +But in spite of much that was interesting and had to be discussed, the +baby with the little cap on its unsteady head evidently absorbed all +his attention. + +"How sweet!" said Countess Mary, looking at and playing with the +baby. "Now, Nicholas," she added, turning to her husband, "I can't +understand how it is you don't see the charm of these delicious +marvels." + +"I don't and can't," replied Nicholas, looking coldly at the baby. +"A lump of flesh. Come along, Pierre!" + +"And yet he's such an affectionate father," said Countess Mary, +vindicating her husband, "but only after they are a year old or so..." + +"Now, Pierre nurses them splendidly," said Natasha. "He says his +hand is just made for a baby's seat. Just look!" + +"Only not for this..." Pierre suddenly exclaimed with a laugh, and +shifting the baby he gave him to the nurse. + + + + + +CHAPTER XII + + +As in every large household, there were at Bald Hills several +perfectly distinct worlds which merged into one harmonious whole, +though each retained its own peculiarities and made concessions to the +others. Every event, joyful or sad, that took place in that house +was important to all these worlds, but each had its own special +reasons to rejoice or grieve over that occurrence independently of the +others. + +For instance, Pierre's return was a joyful and important event and +they all felt it to be so. + +The servants--the most reliable judges of their masters because they +judge not by their conversation or expressions of feeling but by their +acts and way of life--were glad of Pierre's return because they knew +that when he was there Count Nicholas would cease going every day +to attend to the estate, and would be in better spirits and temper, +and also because they would all receive handsome presents for the +holidays. + +The children and their governesses were glad of Pierre's return +because no one else drew them into the social life of the household as +he did. He alone could play on the clavichord that ecossaise (his only +piece) to which, as he said, all possible dances could be danced, +and they felt sure he had brought presents for them all. + +Young Nicholas, now a slim lad of fifteen, delicate and intelligent, +with curly light-brown hair and beautiful eyes, was delighted +because Uncle Pierre as he called him was the object of his +rapturous and passionate affection. No one had instilled into him this +love for Pierre whom he saw only occasionally. Countess Mary who had +brought him up had done her utmost to make him love her husband as she +loved him, and little Nicholas did love his uncle, but loved him +with just a shade of contempt. Pierre, however, he adored. He did +not want to be an hussar or a Knight of St. George like his uncle +Nicholas; he wanted to be learned, wise, and kind like Pierre. In +Pierre's presence his face always shone with pleasure and he flushed +and was breathless when Pierre spoke to him. He did not miss a +single word he uttered, and would afterwards, with Dessalles or by +himself, recall and reconsider the meaning of everything Pierre had +said. Pierre's past life and his unhappiness prior to 1812 (of which +young Nicholas had formed a vague poetic picture from some words he +had overheard), his adventures in Moscow, his captivity, Platon +Karataev (of whom he had heard from Pierre), his love for Natasha +(of whom the lad was also particularly fond), and especially +Pierre's friendship with the father whom Nicholas could not +remember--all this made Pierre in his eyes a hero and a saint. + +From broken remarks about Natasha and his father, from the emotion +with which Pierre spoke of that dead father, and from the careful, +reverent tenderness with which Natasha spoke of him, the boy, who +was only just beginning to guess what love is, derived the notion that +his father had loved Natasha and when dying had left her to his +friend. But the father whom the boy did not remember appeared to him a +divinity who could not be pictured, and of whom he never thought +without a swelling heart and tears of sadness and rapture. So the +boy also was happy that Pierre had arrived. + +The guests welcomed Pierre because he always helped to enliven and +unite any company he was in. + +The grown-up members of the family, not to mention his wife, were +pleased to have back a friend whose presence made life run more +smoothly and peacefully. + +The old ladies were pleased with the presents he brought them, and +especially that Natasha would now be herself again. + +Pierre felt the different outlooks of these various worlds and +made haste to satisfy all their expectations. + +Though the most absent-minded and forgetful of men, Pierre, with the +aid of a list his wife drew up, had now bought everything, not +forgetting his mother--and brother-in-law's commissions, nor the dress +material for a present to Belova, nor toys for his wife's nephews. +In the early days of his marriage it had seemed strange to him that +his wife should expect him not to forget to procure all the things +he undertook to buy, and he had been taken aback by her serious +annoyance when on his first trip he forgot everything. But in time +he grew used to this demand. Knowing that Natasha asked nothing for +herself, and gave him commissions for others only when he himself +had offered to undertake them, he now found an unexpected and +childlike pleasure in this purchase of presents for everyone in the +house, and never forgot anything. If he now incurred Natasha's censure +it was only for buying too many and too expensive things. To her other +defects (as most people thought them, but which to Pierre were +qualities) of untidiness and neglect of herself, she now added +stinginess. + +From the time that Pierre began life as a family man on a footing +entailing heavy expenditure, he had noticed to his surprise that he +spent only half as much as before, and that his affairs--which had +been in disorder of late, chiefly because of his first wife's debts- +had begun to improve. + +Life was cheaper because it was circumscribed: that most expensive +luxury, the kind of life that can be changed at any moment, was no +longer his nor did he wish for it. He felt that his way of life had +now been settled once for all till death and that to change it was not +in his power, and so that way of life proved economical. + +With a merry, smiling face Pierre was sorting his purchases. + +"What do you think of this?" said he, unrolling a piece of stuff +like a shopman. + +Natasha, who was sitting opposite to him with her eldest daughter on +her lap, turned her sparkling eyes swiftly from her husband to the +things he showed her. + +"That's for Belova? Excellent!" She felt the quality of the +material. "It was a ruble an arshin, I suppose?" + +Pierre told her the price. + +"Too dear!" Natasha remarked. "How pleased the children will be +and Mamma too! Only you need not have bought me this," she added, +unable to suppress a smile as she gazed admiringly at a gold comb +set with pearls, of a kind then just coming into fashion. + +"Adele tempted me: she kept on telling me to buy it," returned +Pierre. + +"When am I to wear it?" and Natasha stuck it in her coil of hair. +"When I take little Masha into society? Perhaps they will be +fashionable again by then. Well, let's go now." + +And collecting the presents they went first to the nursery and +then to the old countess' rooms. + +The countess was sitting with her companion Belova, playing +grand-patience as usual, when Pierre and Natasha came into the drawing +room with parcels under their arms. + +The countess was now over sixty, was quite gray, and wore a cap with +a frill that surrounded her face. Her face had shriveled, her upper +lip had sunk in, and her eyes were dim. + +After the deaths of her son and husband in such rapid succession, +she felt herself a being accidentally forgotten in this world and left +without aim or object for her existence. She ate, drank, slept, or +kept awake, but did not live. Life gave her no new impressions. She +wanted nothing from life but tranquillity, and that tranquillity +only death could give her. But until death came she had to go on +living, that is, to use her vital forces. A peculiarity one sees in +very young children and very old people was particularly evident in +her. Her life had no external aims--only a need to exercise her +various functions and inclinations was apparent. She had to eat, +sleep, think, speak, weep, work, give vent to her anger, and so on, +merely because she had a stomach, a brain, muscles, nerves, and a +liver. She did these things not under any external impulse as people +in the full vigor of life do, when behind the purpose for which they +strive that of exercising their functions remains unnoticed. She +talked only because she physically needed to exercise her tongue and +lungs. She cried as a child does, because her nose had to be +cleared, and so on. What for people in their full vigor is an aim +was for her evidently merely a pretext. + +Thus in the morning--especially if she had eaten anything rich the +day before--she felt a need of being angry and would choose as the +handiest pretext Belova's deafness. + +She would begin to say something to her in a low tone from the other +end of the room. + +"It seems a little warmer today, my dear," she would murmur. + +And when Belova replied: "Oh yes, they've come," she would mutter +angrily: "O Lord! How stupid and deaf she is!" + +Another pretext would be her snuff, which would seem too dry or +too damp or not rubbed fine enough. After these fits of irritability +her face would grow yellow, and her maids knew by infallible +symptoms when Belova would again be deaf, the snuff damp, and the +countess' face yellow. Just as she needed to work off her spleen so +she had sometimes to exercise her still-existing faculty of +thinking--and the pretext for that was a game of patience. When she +needed to cry, the deceased count would be the pretext. When she +wanted to be agitated, Nicholas and his health would be the pretext, +and when she felt a need to speak spitefully, the pretext would be +Countess Mary. When her vocal organs needed exercise, which was +usually toward seven o'clock when she had had an after-dinner rest +in a darkened room, the pretext would be the retelling of the same +stories over and over again to the same audience. + +The old lady's condition was understood by the whole household +though no one ever spoke of it, and they all made every possible +effort to satisfy her needs. Only by a rare glance exchanged with a +sad smile between Nicholas, Pierre, Natasha, and Countess Mary was the +common understanding of her condition expressed. + +But those glances expressed something more: they said that she had +played her part in life, that what they now saw was not her whole +self, that we must all become like her, and that they were glad to +yield to her, to restrain themselves for this once precious being +formerly as full of life as themselves, but now so much to be +pitied. "Memento mori," said these glances. + +Only the really heartless, the stupid ones of that household, and +the little children failed to understand this and avoided her. + + + + + +CHAPTER XIII + + +When Pierre and his wife entered the drawing room the countess was +in one of her customary states in which she needed the mental exertion +of playing patience, and so--though by force of habit she greeted +him with the words she always used when Pierre or her son returned +after an absence: "High time, my dear, high time! We were all weary of +waiting for you. Well, thank God!" and received her presents with +another customary remark: "It's not the gift that's precious, my dear, +but that you give it to me, an old woman..."--yet it was evident +that she was not pleased by Pierre's arrival at that moment when it +diverted her attention from the unfinished game. + +She finished her game of patience and only then examined the +presents. They consisted of a box for cards, of splendid +workmanship, a bright-blue Sevres tea cup with shepherdesses +depicted on it and with a lid, and a gold snuffbox with the count's +portrait on the lid which Pierre had had done by a miniaturist in +Petersburg. The countess had long wished for such a box, but as she +did not want to cry just then she glanced indifferently at the +portrait and gave her attention chiefly to the box for cards. + +"Thank you, my dear, you have cheered me up," said she as she always +did. "But best of all you have brought yourself back--for I never +saw anything like it, you ought to give your wife a scolding! What are +we to do with her? She is like a mad woman when you are away. +Doesn't see anything, doesn't remember anything," she went on, +repeating her usual phrases. "Look, Anna Timofeevna," she added to her +companion, "see what a box for cards my son has brought us!" + +Belova admired the presents and was delighted with her dress +material. + +Though Pierre, Natasha, Nicholas, Countess Mary, and Denisov had +much to talk about that they could not discuss before the old +countess--not that anything was hidden from her, but because she had +dropped so far behindhand in many things that had they begun to +converse in her presence they would have had to answer inopportune +questions and to repeat what they had already told her many times: +that so-and-so was dead and so-and-so was married, which she would +again be unable to remember--yet they sat at tea round the samovar +in the drawing room from habit, and Pierre answered the countess' +questions as to whether Prince Vasili had aged and whether Countess +Mary Alexeevna had sent greetings and still thought of them, and other +matters that interested no one and to which she herself was +indifferent. + +Conversation of this kind, interesting to no one yet unavoidable, +continued all through teatime. All the grown-up members of the +family were assembled near the round tea table at which Sonya presided +beside the samovar. The children with their tutors and governesses had +had tea and their voices were audible from the next room. At tea all +sat in their accustomed places: Nicholas beside the stove at a small +table where his tea was handed to him; Milka, the old gray borzoi +bitch (daughter of the first Milka), with a quite gray face and +large black eyes that seemed more prominent than ever, lay on the +armchair beside him; Denisov, whose curly hair, mustache, and whiskers +had turned half gray, sat beside countess Mary with his general's +tunic unbuttoned; Pierre sat between his wife and the old countess. He +spoke of what he knew might interest the old lady and that she could +understand. He told her of external social events and of the people +who had formed the circle of her contemporaries and had once been a +real, living, and distinct group, but who were now for the most part +scattered about the world and like herself were garnering the last +ears of the harvests they had sown in earlier years. But to the old +countess those contemporaries of hers seemed to be the only serious +and real society. Natasha saw by Pierre's animation that his visit had +been interesting and that he had much to tell them but dare not say it +before the old countess. Denisov, not being a member of the family, +did not understand Pierre's caution and being, as a malcontent, much +interested in what was occurring in Petersburg, kept urging Pierre +to tell them about what had happened in the Semenovsk regiment, then +about Arakcheev, and then about the Bible Society. Once or twice +Pierre was carried away and began to speak of these things, but +Nicholas and Natasha always brought him back to the health of Prince +Ivan and Countess Mary Alexeevna. + +"Well, and all this idiocy--Gossner and Tatawinova?" Denisov +asked. "Is that weally still going on?" + +"Going on?" Pierre exclaimed. "Why more than ever! The Bible Society +is the whole government now!" + + "What is that, mon cher ami?" asked the countess, who had +finished her tea and evidently needed a pretext for being angry +after her meal. "What are you saying about the government? I don't +understand." + +"Well, you know, Maman," Nicholas interposed, knowing how to +translate things into his mother's language, "Prince Alexander +Golitsyn has founded a society and in consequence has great influence, +they say." + +"Arakcheev and Golitsyn," incautiously remarked Pierre, "are now the +whole government! And what a government! They see treason everywhere +and are afraid of everything." + +"Well, and how is Prince Alexander to blame? He is a most +estimable man. I used to meet him at Mary Antonovna's," said the +countess in an offended tone; and still more offended that they all +remained silent, she went on: "Nowadays everyone finds fault. A Gospel +Society! Well, and what harm is there in that?" and she rose +(everybody else got up too) and with a severe expression sailed back +to her table in the sitting room. + +The melancholy silence that followed was broken by the sounds of the +children's voices and laughter from the next room. Evidently some +jolly excitement was going on there. + +"Finished, finished!" little Natasha's gleeful yell rose above +them all. + +Pierre exchanged glances with Countess Mary and Nicholas (Natasha he +never lost sight of) and smiled happily. + +"That's delightful music!" said he. + +"It means that Anna Makarovna has finished her stocking," said +Countess Mary. + +"Oh, I'll go and see," said Pierre, jumping up. "You know," he +added, stopping at the door, "why I'm especially fond of that music? +It is always the first thing that tells me all is well. When I was +driving here today, the nearer I got to the house the more anxious I +grew. As I entered the anteroom I heard Andrusha's peals of laughter +and that meant that all was well." + +"I know! I know that feeling," said Nicholas. "But I mustn't go +there--those stockings are to be a surprise for me." + +Pierre went to the children, and the shouting and laughter grew +still louder. + +"Come, Anna Makarovna," Pierre's voice was heard saying, "come +here into the middle of the room and at the word of command, 'One, +two,' and when I say 'three'... You stand here, and you in my arms- +well now! One, two!..." said Pierre, and a silence followed: +"three!" and a rapturously breathless cry of children's voices +filled the room. "Two, two!" they shouted. + +This meant two stockings, which by a secret process known only to +herself Anna Makarovna used to knit at the same time on the same +needles, and which, when they were ready, she always triumphantly +drew, one out of the other, in the children's presence. + + + + + +CHAPTER XIV + + +Soon after this the children came in to say good night. They +kissed everyone, the tutors and governesses made their bows, and +they went out. Only young Nicholas and his tutor remained. Dessalles +whispered to the boy to come downstairs. + +"No, Monsieur Dessalles, I will ask my aunt to let me stay," replied +Nicholas Bolkonski also in a whisper. + +"Ma tante, please let me stay," said he, going up to his aunt. + +His face expressed entreaty, agitation, and ecstasy. Countess Mary +glanced at him and turned to Pierre. + +"When you are here he can't tear himself away," she said. + +"I will bring him to you directly, Monsieur Dessalles. Good +night!" said Pierre, giving his hand to the Swiss tutor, and he turned +to young Nicholas with a smile. "You and I haven't seen anything of +one another yet... How like he is growing, Mary!" he added, addressing +Countess Mary. + +"Like my father?" asked the boy, flushing crimson and looking up +at Pierre with bright, ecstatic eyes. + +Pierre nodded, and went on with what he had been saying when the +children had interrupted. Countess Mary sat down doing woolwork; +Natasha did not take her eyes off her husband. Nicholas and Denisov +rose, asked for their pipes, smoked, went to fetch more tea from +Sonya--who sat weary but resolute at the samovar--and questioned +Pierre. The curly-headed, delicate boy sat with shining eyes unnoticed +in a corner, starting every now and then and muttering something to +himself, and evidently experiencing a new and powerful emotion as he +turned his curly head, with his thin neck exposed by his turn-down +collar, toward the place where Pierre sat. + +The conversation turned on the contemporary gossip about those in +power, in which most people see the chief interest of home politics. +Denisov, dissatisfied with the government on account of his own +disappointments in the service, heard with pleasure of the things done +in Petersburg which seemed to him stupid, and made forcible and +sharp comments on what Pierre told them. + +"One used to have to be a German--now one must dance with Tatawinova +and Madame Kwudener, and wead Ecka'tshausen and the bwethwen. Oh, they +should let that fine fellow Bonaparte lose--he'd knock all this +nonsense out of them! Fancy giving the command of the Semenov wegiment +to a fellow like that Schwa'tz!" he cried. + +Nicholas, though free from Denisov's readiness to find fault with +everything, also thought that discussion of the government was a +very serious and weighty matter, and the fact that A had been +appointed Minister of This and B Governor General of That, and that +the Emperor had said so-and-so and this minister so-and-so, seemed +to him very important. And so he thought it necessary to take an +interest in these things and to question Pierre. The questions put +by these two kept the conversation from changing its ordinary +character of gossip about the higher government circles. + +But Natasha, knowing all her husband's ways and ideas, saw that he +had long been wishing but had been unable to divert the conversation +to another channel and express his own deeply felt idea for the sake +of which he had gone to Petersburg to consult with his new friend +Prince Theodore, and she helped him by asking how his affairs with +Prince Theodore had gone. + +"What was it about?" asked Nicholas. + +"Always the same thing," said Pierre, looking round at his +listeners. "Everybody sees that things are going so badly that they +cannot be allowed to go on so and that it is the duty of all decent +men to counteract it as far as they can." + +"What can decent men do?" Nicholas inquired, frowning slightly. +"What can be done?" + +"Why, this..." + +"Come into my study," said Nicholas. + +Natasha, who had long expected to be fetched to nurse her baby, +now heard the nurse calling her and went to the nursery. Countess Mary +followed her. The men went into the study and little Nicholas +Bolkonski followed them unnoticed by his uncle and sat down at the +writing table in a shady corner by the window. + +"Well, what would you do?" asked Denisov. + +"Always some fantastic schemes," said Nicholas. + +"Why this," began Pierre, not sitting down but pacing the room, +sometimes stopping short, gesticulating, and lisping: "the position in +Petersburg is this: the Emperor does not look into anything. He has +abandoned himself altogether to this mysticism" (Pierre could not +tolerate mysticism in anyone now). "He seeks only for peace, and +only these people sans foi ni loi* can give it him--people who +recklessly hack at and strangle everything--Magnitski, Arakcheev, +and tutti quanti.... You will agree that if you did not look after +your estates yourself but only wanted a quiet life, the harsher your +steward was the more readily your object might be attained," he said +to Nicholas. + + +*Without faith or law. + + +"Well, what does that lead up to?" said Nicholas. + +"Well, everything is going to ruin! Robbery in the law courts, in +the army nothing but flogging, drilling, and Military Settlements; the +people are tortured, enlightenment is suppressed. All that is young +and honest is crushed! Everyone sees that this cannot go on. +Everything is strained to such a degree that it will certainly break," +said Pierre (as those who examine the actions of any government have +always said since governments began). "I told them just one thing in +Petersburg." + +"Told whom?" + +"Well, you know whom," said Pierre, with a meaning glance from under +his brows. "Prince Theodore and all those. To encourage culture and +philanthropy is all very well of course. The aim is excellent but in +the present circumstances something else is needed." + +At that moment Nicholas noticed the presence of his nephew. His face +darkened and he went up to the boy. + +"Why are you here?" + +"Why? Let him be," said Pierre, taking Nicholas by the arm and +continuing. "That is not enough, I told them. Something else is +needed. When you stand expecting the overstrained string to snap at +any moment, when everyone is expecting the inevitable catastrophe, +as many as possible must join hands as closely as they can to +withstand the general calamity. Everything that is young and strong is +being enticed away and depraved. One is lured by women, another by +honors, a third by ambition or money, and they go over to that camp. +No independent men, such as you or I, are left. What I say is widen +the scope of our society, let the mot d'ordre be not virtue alone +but independence and action as well!" + +Nicholas, who had left his nephew, irritably pushed up an +armchair, sat down in it, and listened to Pierre, coughing +discontentedly and frowning more and more. + +"But action with what aim?" he cried. "And what position will you +adopt toward the government?" + +"Why, the position of assistants. The society need not be secret +if the government allows it. Not merely is it not hostile to +government, but it is a society of true conservatives--a society of +gentlemen in the full meaning of that word. It is only to prevent some +Pugachev or other from killing my children and yours, and Arakcheev +from sending me off to some Military Settlement. We join hands only +for the public welfare and the general safety." + +"Yes, but it's a secret society and therefore a hostile and +harmful one which can only cause harm." + +"Why? Did the Tugendbund which saved Europe" (they did not then +venture to suggest that Russia had saved Europe) "do any harm? The +Tugendbund is an alliance of virtue: it is love, mutual help... it +is what Christ preached on the Cross." + +Natasha, who had come in during the conversation, looked joyfully at +her husband. It was not what he was saying that pleased her--that +did not even interest her, for it seemed to her that was all extremely +simple and that she had known it a long time (it seemed so to her +because she knew that it sprang from Pierre's whole soul), but it +was his animated and enthusiastic appearance that made her glad. + +The boy with the thin neck stretching out from the turn-down collar- +whom everyone had forgotten--gazed at Pierre with even greater and +more rapturous joy. Every word of Pierre's burned into his heart, +and with a nervous movement of his fingers he unconsciously broke +the sealing wax and quill pens his hands came upon on his uncle's +table. + +"It is not at all what you suppose; but that is what the German +Tugendbund was, and what I am proposing." + +"No, my fwiend! The Tugendbund is all vewy well for the sausage +eaters, but I don't understand it and can't even pwonounce it," +interposed Denisov in a loud and resolute voice. "I agwee that +evewything here is wotten and howwible, but the Tugendbund I don't +understand. If we're not satisfied, let us have a bunt of our own. +That's all wight. Je suis vot'e homme!"* + + +*"I'm your man." + + +Pierre smiled, Natasha began to laugh, but Nicholas knitted his +brows still more and began proving to Pierre that there was no +prospect of any great change and that all the danger he spoke of +existed only in his imagination. Pierre maintained the contrary, and +as his mental faculties were greater and more resourceful, Nicholas +felt himself cornered. This made him still angrier, for he was fully +convinced, not by reasoning but by something within him stronger +than reason, of the justice of his opinion. + +"I will tell you this," he said, rising and trying with nervously +twitching fingers to prop up his pipe in a corner, but finally +abandoning the attempt. "I can't prove it to you. You say that +everything here is rotten and that an overthrow is coming: I don't see +it. But you also say that our oath of allegiance is a conditional +matter, and to that I reply: 'You are my best friend, as you know, but +if you formed a secret society and began working against the +government--be it what it may--I know it is my duty to obey the +government. And if Arakcheev ordered me to lead a squadron against you +and cut you down, I should not hesitate an instant, but should do it.' +And you may argue about that as you like!" + +An awkward silence followed these words. Natasha was the first to +speak, defending her husband and attacking her brother. Her defense +was weak and inapt but she attained her object. The conversation was +resumed, and no longer in the unpleasantly hostile tone of Nicholas' +last remark. + +When they all got up to go in to supper, little Nicholas Bolkonski +went up to Pierre, pale and with shining, radiant eyes. + +"Uncle Pierre, you... no... If Papa were alive... would he agree +with you?" he asked. + +And Pierre suddenly realized what a special, independent, complex, +and powerful process of thought and feeling must have been going on in +this boy during that conversation, and remembering all he had said +he regretted that the lad should have heard him. He had, however, to +give him an answer. + +"Yes, I think so," he said reluctantly, and left the study. + +The lad looked down and seemed now for the first time to notice what +he had done to the things on the table. He flushed and went up to +Nicholas. + +"Uncle, forgive me, I did that... unintentionally," he said, +pointing to the broken sealing wax and pens. + +Nicholas started angrily. + +"All right, all right," he said, throwing the bits under the table. + +And evidently suppressing his vexation with difficulty, he turned +away from the boy. + +"You ought not to have been here at all," he said. + + + + + +CHAPTER XV + + +The conversation at supper was not about politics or societies, +but turned on the subject Nicholas liked best--recollections of +1812. Denisov started these and Pierre was particularly agreeable +and amusing about them. The family separated on the most friendly +terms. + +After supper Nicholas, having undressed in his study and given +instructions to the steward who had been waiting for him, went to +the bedroom in his dressing gown, where he found his wife still at her +table, writing. + +"What are you writing, Mary?" Nicholas asked. + +Countess Mary blushed. She was afraid that what she was writing +would not be understood or approved by her husband. + +She had wanted to conceal what she was writing from him, but at +the same time was glad he had surprised her at it and that she would +now have to tell him. + +"A diary, Nicholas," she replied, handing him a blue exercise book +filled with her firm, bold writing. + +"A diary?" Nicholas repeated with a shade of irony, and he took up +the book. + +It was in French. + + +December 4. Today when Andrusha (her eldest boy) woke up he did +not wish to dress and Mademoiselle Louise sent for me. He was +naughty and obstinate. I tried threats, but he only grew angrier. Then +I took the matter in hand: I left him alone and began with nurse's +help to get the other children up, telling him that I did not love +him. For a long time he was silent, as if astonished, then he jumped +out of bed, ran to me in his shirt, and sobbed so that I could not +calm him for a long time. It was plain that what troubled him most was +that he had grieved me. Afterwards in the evening when I gave him +his ticket, he again began crying piteously and kissing me. One can do +anything with him by tenderness. + + +"What is a 'ticket'?" Nicholas inquired. + +"I have begun giving the elder ones marks every evening, showing how +they have behaved." + +Nicholas looked into the radiant eyes that were gazing at him, and +continued to turn over the pages and read. In the diary was set down +everything in the children's lives that seemed noteworthy to their +mother as showing their characters or suggesting general reflections +on educational methods. They were for the most part quite +insignificant trifles, but did not seem so to the mother or to the +father either, now that he read this diary about his children for +the first time. + +Under the date "5" was entered: + + +Mitya was naughty at table. Papa said he was to have no pudding. +He had none, but looked so unhappily and greedily at the others +while they were eating! I think that punishment by depriving +children of sweets only develops their greediness. Must tell +Nicholas this. + + +Nicholas put down the book and looked at his wife. The radiant +eyes gazed at him questioningly: would he approve or disapprove of her +diary? There could be no doubt not only of his approval but also of +his admiration for his wife. + +Perhaps it need not be done so pedantically, thought Nicholas, or +even done at all, but this untiring, continual spiritual effort of +which the sole aim was the children's moral welfare delighted him. Had +Nicholas been able to analyze his feelings he would have found that +his steady, tender, and proud love of his wife rested on his feeling +of wonder at her spirituality and at the lofty moral world, almost +beyond his reach, in which she had her being. + +He was proud of her intelligence and goodness, recognized his own +insignificance beside her in the spiritual world, and rejoiced all the +more that she with such a soul not only belonged to him but was part +of himself. + +"I quite, quite approve, my dearest!" said he with a significant +look, and after a short pause he added: "And I behaved badly today. +You weren't in the study. We began disputing--Pierre and I--and I lost +my temper. But he is impossible: such a child! I don't know what would +become of him if Natasha didn't keep him in hand.... Have you any idea +why he went to Petersburg? They have formed..." + +"Yes, I know," said Countess Mary. "Natasha told me." + +"Well, then, you know," Nicholas went on, growing hot at the mere +recollection of their discussion, "he wanted to convince me that it is +every honest man's duty to go against the government, and that the +oath of allegiance and duty... I am sorry you weren't there. They +all fell on me--Denisov and Natasha... Natasha is absurd. How she +rules over him! And yet there need only be a discussion and she has no +words of her own but only repeats his sayings..." added Nicholas, +yielding to that irresistible inclination which tempts us to judge +those nearest and dearest to us. He forgot that what he was saying +about Natasha could have been applied word for word to himself in +relation to his wife. + +"Yes, I have noticed that," said Countess Mary. + +"When I told him that duty and the oath were above everything, he +started proving goodness knows what! A pity you were not there--what +would you have said?" + +"As I see it you were quite right, and I told Natasha so. Pierre +says everybody is suffering, tortured, and being corrupted, and that +it is our duty to help our neighbor. Of course he is right there," +said Countess Mary, "but he forgets that we have other duties nearer +to us, duties indicated to us by God Himself, and that though we might +expose ourselves to risks we must not risk our children." + +"Yes, that's it! That's just what I said to him," put in Nicholas, +who fancied he really had said it. "But they insisted on their own +view: love of one's neighbor and Christianity--and all this in the +presence of young Nicholas, who had gone into my study and broke all +my things." + +"Ah, Nicholas, do you know I am often troubled about little +Nicholas," said Countess Mary. "He is such an exceptional boy. I am +afraid I neglect him in favor of my own: we all have children and +relations while he has no one. He is constantly alone with his +thoughts." + +"Well, I don't think you need reproach yourself on his account. +All that the fondest mother could do for her son you have done and are +doing for him, and of course I am glad of it. He is a fine lad, a fine +lad! This evening he listened to Pierre in a sort of trance, and +fancy--as we were going in to supper I looked and he had broken +everything on my table to bits, and he told me of it himself at +once! I never knew him to tell an untruth. A fine lad, a fine lad!" +repeated Nicholas, who at heart was not fond of Nicholas Bolkonski but +was always anxious to recognize that he was a fine lad. + +"Still, I am not the same as his own mother," said Countess Mary. "I +feel I am not the same and it troubles me. A wonderful boy, but I am +dreadfully afraid for him. It would be good for him to have +companions." + +"Well it won't be for long. Next summer I'll take him to +Petersburg," said Nicholas. "Yes, Pierre always was a dreamer and +always will be," he continued, returning to the talk in the study +which had evidently disturbed him. "Well, what business is it of +mine what goes on there--whether Arakcheev is bad, and all that? +What business was it of mine when I married and was so deep in debt +that I was threatened with prison, and had a mother who could not +see or understand it? And then there are you and the children and +our affairs. Is it for my own pleasure that I am at the farm or in the +office from morning to night? No, but I know I must work to comfort my +mother, to repay you, and not to leave the children such beggars as +I was." + +Countess Mary wanted to tell him that man does not live by bread +alone and that he attached too much importance to these matters. But +she knew she must not say this and that it would be useless to do +so. She only took his hand and kissed it. He took this as a sign of +approval and a confirmation of his thoughts, and after a few +minutes' reflection continued to think aloud. + +"You know, Mary, today Elias Mitrofanych" (this was his overseer) +"came back from the Tambov estate and told me they are already +offering eighty thousand rubles for the forest." + +And with an eager face Nicholas began to speak of the possibility of +repurchasing Otradnoe before long, and added: "Another ten years of +life and I shall leave the children... in an excellent position." + +Countess Mary listened to her husband and understood all that he +told her. She knew that when he thought aloud in this way he would +sometimes ask her what he had been saying, and be vexed if he +noticed that she had been thinking about something else. But she had +to force herself to attend, for what he was saying did not interest +her at all. She looked at him and did not think, but felt, about +something different. She felt a submissive tender love for this man +who would never understand all that she understood, and this seemed to +make her love for him still stronger and added a touch of passionate +tenderness. Besides this feeling which absorbed her altogether and +hindered her from following the details of her husband's plans, +thoughts that had no connection with what he was saying flitted +through her mind. She thought of her nephew. Her husband's account +of the boy's agitation while Pierre was speaking struck her +forcibly, and various traits of his gentle, sensitive character +recurred to her mind; and while thinking of her nephew she thought +also of her own children. She did not compare them with him, but +compared her feeling for them with her feeling for him, and felt +with regret that there was something lacking in her feeling for +young Nicholas. + +Sometimes it seemed to her that this difference arose from the +difference in their ages, but she felt herself to blame toward him and +promised in her heart to do better and to accomplish the impossible- +in this life to love her husband, her children, little Nicholas, and +all her neighbors, as Christ loved mankind. Countess Mary's soul +always strove toward the infinite, the eternal, and the absolute, +and could therefore never be at peace. A stern expression of the +lofty, secret suffering of a soul burdened by the body appeared on her +face. Nicholas gazed at her. "O God! What will become of us if she +dies, as I always fear when her face is like that?" thought he, and +placing himself before the icon he began to say his evening prayers. + + + + + +CHAPTER XVI + + +Natasha and Pierre, left alone, also began to talk as only a husband +and wife can talk, that is, with extraordinary clearness and rapidity, +understanding and expressing each other's thoughts in ways contrary to +all rules of logic, without premises, deductions, or conclusions, +and in a quite peculiar way. Natasha was so used to this kind of +talk with her husband that for her it was the surest sign of something +being wrong between them if Pierre followed a line of logical +reasoning. When he began proving anything, or talking +argumentatively and calmly and she, led on by his example, began to do +the same, she knew that they were on the verge of a quarrel. + +From the moment they were alone and Natasha came up to him with +wide-open happy eyes, and quickly seizing his head pressed it to her +bosom, saying: "Now you are all mine, mine! You won't escape!"--from +that moment this conversation began, contrary to all the laws of logic +and contrary to them because quite different subjects were talked +about at one and the same time. This simultaneous discussion of many +topics did not prevent a clear understanding but on the contrary was +the surest sign that they fully understood one another. + +Just as in a dream when all is uncertain, unreasoning, and +contradictory, except the feeling that guides the dream, so in this +intercourse contrary to all laws of reason, the words themselves +were not consecutive and clear but only the feeling that prompted +them. + +Natasha spoke to Pierre about her brother's life and doings, of +how she had suffered and lacked life during his own absence, and of +how she was fonder than ever of Mary, and how Mary was in every way +better than herself. In saying this Natasha was sincere in +acknowledging Mary's superiority, but at the same time by saying it +she made a demand on Pierre that he should, all the same, prefer her +to Mary and to all other women, and that now, especially after +having seen many women in Petersburg, he should tell her so afresh. + +Pierre, answering Natasha's words, told her how intolerable it had +been for him to meet ladies at dinners and balls in Petersburg. + +"I have quite lost the knack of talking to ladies," he said. "It was +simply dull. Besides, I was very busy." + +Natasha looked intently at him and went on: + +"Mary is so splendid," she said. "How she understands children! It +is as if she saw straight into their souls. Yesterday, for instance, +Mitya was naughty..." + +"How like his father he is," Pierre interjected. + +Natasha knew why he mentioned Mitya's likeness to Nicholas: the +recollection of his dispute with his brother-in-law was unpleasant and +he wanted to know what Natasha thought of it. + +"Nicholas has the weakness of never agreeing with anything not +generally accepted. But I understand that you value what opens up a +fresh line," said she, repeating words Pierre had once uttered. + +"No, the chief point is that to Nicholas ideas and discussions are +an amusement--almost a pastime," said Pierre. "For instance, he is +collecting a library and has made it a rule not to buy a new book till +he has read what he had already bought--Sismondi and Rousseau and +Montesquieu," he added with a smile. "You know how much I..." he began +to soften down what he had said; but Natasha interrupted him to show +that this was unnecessary. + +"So you say ideas are an amusement to him...." + +"Yes, and for me nothing else is serious. All the time in Petersburg +I saw everyone as in a dream. When I am taken up by a thought, all +else is mere amusement." + +"Ah, I'm so sorry I wasn't there when you met the children," said +Natasha. "Which was most delighted? Lisa, I'm sure." + +"Yes," Pierre replied, and went on with what was in his mind. +"Nicholas says we ought not to think. But I can't help it. Besides, +when I was in Petersburg I felt (I can this to you) that the whole +affair would go to pieces without me--everyone was pulling his own +way. But I succeeded in uniting them all; and then my idea is so clear +and simple. You see, I don't say that we ought to oppose this and +that. We may be mistaken. What I say is: 'Join hands, you who love the +right, and let there be but one banner--that of active virtue.' Prince +Sergey is a fine fellow and clever." + +Natasha would have had no doubt as to the greatness of Pierre's +idea, but one thing disconcerted her. "Can a man so important and +necessary to society be also my husband? How did this happen?" She +wished to express this doubt to him. "Now who could decide whether +he is really cleverer than all the others?" she asked herself, and +passed in review all those whom Pierre most respected. Judging by what +he had said there was no one he had respected so highly as Platon +Karataev. + +"Do you know what I am thinking about?" she asked. "About Platon +Karataev. Would he have approved of you now, do you think?" + +Pierre was not at all surprised at this question. He understood +his wife's line of thought. + +"Platon Karataev?" he repeated, and pondered, evidently sincerely +trying to imagine Karataev's opinion on the subject. "He would not +have understood... yet perhaps he would." + +"I love you awfully!" Natasha suddenly said. "Awfully, awfully!" + +"No, he would not have approved," said Pierre, after reflection. +"What he would have approved of is our family life. He was always so +anxious to find seemliness, happiness, and peace in everything, and +I should have been proud to let him see us. There now--you talk of +my absence, but you wouldn't believe what a special feeling I have for +you after a separation...." + +"Yes, I should think..." Natasha began. + +"No, it's not that. I never leave off loving you. And one couldn't +love more, but this is something special.... Yes, of course-" he did +not finish because their eyes meeting said the rest. + +"What nonsense it is," Natasha suddenly exclaimed, "about +honeymoons, and that the greatest happiness is at first! On the +contrary, now is the best of all. If only you did not go away! Do +you remember how we quarreled? And it was always my fault. Always +mine. And what we quarreled about--I don't even remember!" + +"Always about the same thing," said Pierre with a smile. "Jealo..." + +"Don't say it! I can't bear it!" Natasha cried, and her eyes +glittered coldly and vindictively. "Did you see her?" she added, after +a pause. + +"No, and if I had I shouldn't have recognized her." + +They were silent for a while. + +"Oh, do you know? While you were talking in the study I was +looking at you," Natasha began, evidently anxious to disperse the +cloud that had come over them. "You are as like him as two peas- +like the boy." (She meant her little son.) "Oh, it's time to go to +him.... The milk's come.... But I'm sorry to leave you." + +They were silent for a few seconds. Then suddenly turning to one +another at the same time they both began to speak. Pierre began with +self-satisfaction and enthusiasm, Natasha with a quiet, happy smile. +Having interrupted one another they both stopped to let the other +continue. + +"No. What did you say? Go on, go on." + +"No, you go on, I was talking nonsense," said Natasha. + +Pierre finished what he had begun. It was the sequel to his +complacent reflections on his success in Petersburg. At that moment it +seemed to him that he was chosen to give a new direction to the +whole of Russian society and to the whole world. + +"I only wished to say that ideas that have great results are +always simple ones. My whole idea is that if vicious people are united +and constitute a power, then honest folk must do the same. Now +that's simple enough." + +"Yes." + +"And what were you going to say?" + +"I? Only nonsense." + +"But all the same?" + +"Oh nothing, only a trifle," said Natasha, smilingly still more +brightly. "I only wanted to tell you about Petya: today nurse was +coming to take him from me, and he laughed, shut his eyes, and clung +to me. I'm sure he thought he was hiding. Awfully sweet! There, now +he's crying. Well, good-by!" and she left the room. + + +Meanwhile downstairs in young Nicholas Bolkonski's bedroom a +little lamp was burning as usual. (The boy was afraid of the dark +and they could not cure him of it.) Dessalles slept propped up on four +pillows and his Roman nose emitted sounds of rhythmic snoring. +Little Nicholas, who had just waked up in a cold perspiration, sat +up in bed and gazed before him with wide-open eyes. He had awaked from +a terrible dream. He had dreamed that he and Uncle Pierre, wearing +helmets such as were depicted in his Plutarch, were leading a huge +army. The army was made up of white slanting lines that filled the air +like the cobwebs that float about in autumn and which Dessalles called +les fils de la Vierge. In front was Glory, which was similar to +those threads but rather thicker. He and Pierre were borne along +lightly and joyously, nearer and nearer to their goal. Suddenly the +threads that moved them began to slacken and become entangled and it +grew difficult to move. And Uncle Nicholas stood before them in a +stern and threatening attitude. + +"Have you done this?" he said, pointing to some broken sealing wax +and pens. "I loved you, but I have orders from Arakcheev and will kill +the first of you who moves forward." Little Nicholas turned to look at +Pierre but Pierre was no longer there. In his place was his father- +Prince Andrew--and his father had neither shape nor form, but he +existed, and when little Nicholas perceived him he grew faint with +love: he felt himself powerless, limp, and formless. His father +caressed and pitied him. But Uncle Nicholas came nearer and nearer +to them. Terror seized young Nicholas and he awoke. + +"My father!" he thought. (Though there were two good portraits of +Prince Andrew in the house, Nicholas never imagined him in human +form.) "My father has been with me and caressed me. He approved of +me and of Uncle Pierre. Whatever he may tell me, I will do it. +Mucius Scaevola burned his hand. Why should not the same sort of thing +happen to me? I know they want me to learn. And I will learn. But +someday I shall have finished learning, and then I will do +something. I only pray God that something may happen to me such as +happened to Plutarch's men, and I will act as they did. I will do +better. Everyone shall know me, love me, and be delighted with me!" +And suddenly his bosom heaved with sobs and he began to cry. + +"Are you ill?" he heard Dessalles' voice asking. + +"No," answered Nicholas, and lay back on his pillow. + +"He is good and kind and I am fond of him!" he thought of Dessalles. +"But Uncle Pierre! Oh, what a wonderful man he is! And my father? +Oh, Father, Father! Yes, I will do something with which even he +would be satisfied...." + + + + + + + +SECOND EPILOGUE + + + + + +CHAPTER I + + +History is the life of nations and of humanity. To seize and put +into words, to describe directly the life of humanity or even of a +single nation, appears impossible. + +The ancient historians all employed one and the same method to +describe and seize the apparently elusive--the life of a people. +They described the activity of individuals who ruled the people, and +regarded the activity of those men as representing the activity of the +whole nation. + +The question: how did individuals make nations act as they wished +and by what was the will of these individuals themselves guided? the +ancients met by recognizing a divinity which subjected the nations +to the will of a chosen man, and guided the will of that chosen man so +as to accomplish ends that were predestined. + +For the ancients these questions were solved by a belief in the +direct participation of the Deity in human affairs. + +Modern history, in theory, rejects both these principles. + +It would seem that having rejected the belief of the ancients in +man's subjection to the Deity and in a predetermined aim toward +which nations are led, modern history should study not the +manifestations of power but the causes that produce it. But modern +history has not done this. Having in theory rejected the view held +by the ancients, it still follows them in practice. + +Instead of men endowed with divine authority and directly guided +by the will of God, modern history has given us either heroes +endowed with extraordinary, superhuman capacities, or simply men of +very various kinds, from monarchs to journalists, who lead the masses. +Instead of the former divinely appointed aims of the Jewish, Greek, or +Roman nations, which ancient historians regarded as representing the +progress of humanity, modern history has postulated its own aims- +the welfare of the French, German, or English people, or, in its +highest abstraction, the welfare and civilization of humanity in +general, by which is usually meant that of the peoples occupying a +small northwesterly portion of a large continent. + +Modern history has rejected the beliefs of the ancients without +replacing them by a new conception, and the logic of the situation has +obliged the historians, after they had apparently rejected the +divine authority of the kings and the "fate" of the ancients, to reach +the same conclusion by another road, that is, to recognize (1) nations +guided by individual men, and (2) the existence of a known aim to +which these nations and humanity at large are tending. + +At the basis of the works of all the modern historians from Gibbon +to Buckle, despite their seeming disagreements and the apparent +novelty of their outlooks, lie those two old, unavoidable assumptions. + +In the first place the historian describes the activity of +individuals who in his opinion have directed humanity (one historian +considers only monarchs, generals, and ministers as being such men, +while another includes also orators, learned men, reformers, +philosophers, and poets). Secondly, it is assumed that the goal toward +which humanity is being led is known to the historians: to one of them +this goal is the greatness of the Roman, Spanish, or French realm; +to another it is liberty, equality, and a certain kind of civilization +of a small corner of the world called Europe. + +In 1789 a ferment arises in Paris; it grows, spreads, and is +expressed by a movement of peoples from west to east. Several times it +moves eastward and collides with a countermovement from the east +westward. In 1812 it reaches its extreme limit, Moscow, and then, with +remarkable symmetry, a countermovement occurs from east to west, +attracting to it, as the first movement had done, the nations of +middle Europe. The counter movement reaches the starting point of +the first movement in the west--Paris--and subsides. + +During that twenty-year period an immense number of fields were left +untilled, houses were burned, trade changed its direction, millions of +men migrated, were impoverished, or were enriched, and millions of +Christian men professing the law of love of their fellows slew one +another. + +What does all this mean? Why did it happen? What made those people +burn houses and slay their fellow men? What were the causes of these +events? What force made men act so? These are the instinctive, +plain, and most legitimate questions humanity asks itself when it +encounters the monuments and tradition of that period. + +For a reply to these questions the common sense of mankind turns +to the science of history, whose aim is to enable nations and humanity +to know themselves. + +If history had retained the conception of the ancients it would have +said that God, to reward or punish his people, gave Napoleon power and +directed his will to the fulfillment of the divine ends, and that +reply, would have been clear and complete. One might believe or +disbelieve in the divine significance of Napoleon, but for anyone +believing in it there would have been nothing unintelligible in the +history of that period, nor would there have been any contradictions. + +But modern history cannot give that reply. Science does not admit +the conception of the ancients as to the direct participation of the +Deity in human affairs, and therefore history ought to give other +answers. + +Modern history replying to these questions says: you want to know +what this movement means, what caused it, and what force produced +these events? Then listen: + +"Louis XIV was a very proud and self-confident man; he had such +and such mistresses and such and such ministers and he ruled France +badly. His descendants were weak men and they too ruled France +badly. And they had such and such favorites and such and such +mistresses. Moreover, certain men wrote some books at that time. At +the end of the eighteenth century there were a couple of dozen men +in Paris who began to talk about all men being free and equal. This +caused people all over France to begin to slash at and drown one +another. They killed the king and many other people. At that time +there was in France a man of genius--Napoleon. He conquered +everybody everywhere--that is, he killed many people because he was +a great genius. And for some reason he went to kill Africans, and +killed them so well and was so cunning and wise that when he +returned to France he ordered everybody to obey him, and they all +obeyed him. Having become an Emperor he again went out to kill +people in Italy, Austria, and Prussia. And there too he killed a great +many. In Russia there was an Emperor, Alexander, who decided to +restore order in Europe and therefore fought against Napoleon. In 1807 +he suddenly made friends with him, but in 1811 they again quarreled +and again began killing many people. Napoleon led six hundred thousand +men into Russia and captured Moscow; then he suddenly ran away from +Moscow, and the Emperor Alexander, helped by the advice of Stein and +others, united Europe to arm against the disturber of its peace. All +Napoleon's allies suddenly became his enemies and their forces +advanced against the fresh forces he raised. The Allies defeated +Napoleon, entered Paris, forced Napoleon to abdicate, and sent him +to the island of Elba, not depriving him of the title of Emperor and +showing him every respect, though five years before and one year later +they all regarded him as an outlaw and a brigand. Then Louis XVIII, +who till then had been the laughingstock both of the French and the +Allies, began to reign. And Napoleon, shedding tears before his Old +Guards, renounced the throne and went into exile. Then the skillful +statesmen and diplomatists (especially Talleyrand, who managed to +sit down in a particular chair before anyone else and thereby extended +the frontiers of France) talked in Vienna and by these conversations +made the nations happy or unhappy. Suddenly the diplomatists and +monarchs nearly quarreled and were on the point of again ordering +their armies to kill one another, but just then Napoleon arrived in +France with a battalion, and the French, who had been hating him, +immediately all submitted to him. But the Allied monarchs were angry +at this and went to fight the French once more. And they defeated +the genius Napoleon and, suddenly recognizing him as a brigand, sent +him to the island of St. Helena. And the exile, separated from the +beloved France so dear to his heart, died a lingering death on that +rock and bequeathed his great deeds to posterity. But in Europe a +reaction occurred and the sovereigns once again all began to oppress +their subjects." + +It would be a mistake to think that this is ironic--a caricature +of the historical accounts. On the contrary it is a very mild +expression of the contradictory replies, not meeting the questions, +which all the historians give, from the compilers of memoirs and the +histories of separate states to the writers of general histories and +the new histories of the culture of that period. + +The strangeness and absurdity of these replies arise from the fact +that modern history, like a deaf man, answers questions no one has +asked. + +If the purpose of history be to give a description of the movement +of humanity and of the peoples, the first question--in the absence +of a reply to which all the rest will be incomprehensible--is: what is +the power that moves peoples? To this, modern history laboriously +replies either that Napoleon was a great genius, or that Louis XIV was +very proud, or that certain writers wrote certain books. + +All that may be so and mankind is ready to agree with it, but it +is not what was asked. All that would be interesting if we +recognized a divine power based on itself and always consistently +directing its nations through Napoleons, Louis-es, and writers; but we +do not acknowledge such a power, and therefore before speaking about +Napoleons, Louis-es, and authors, we ought to be shown the +connection existing between these men and the movement of the nations. + +If instead of a divine power some other force has appeared, it +should be explained in what this new force consists, for the whole +interest of history lies precisely in that force. + +History seems to assume that this force is self-evident and known to +everyone. But in spite of every desire to regard it as known, anyone +reading many historical works cannot help doubting whether this new +force, so variously understood by the historians themselves, is really +quite well known to everybody. + + + + + +CHAPTER II + + +What force moves the nations? + +Biographical historians and historians of separate nations +understand this force as a power inherent in heroes and rulers. In +their narration events occur solely by the will of a Napoleon, and +Alexander, or in general of the persons they describe. The answers +given by this kind of historian to the question of what force causes +events to happen are satisfactory only as long as there is but one +historian to each event. As soon as historians of different +nationalities and tendencies begin to describe the same event, the +replies they give immediately lose all meaning, for this force is +understood by them all not only differently but often in quite +contradictory ways. One historian says that an event was produced by +Napoleon's power, another that it was produced by Alexander's, a third +that it was due to the power of some other person. Besides this, +historians of that kind contradict each other even in their +statement as to the force on which the authority of some particular +person was based. Thiers, a Bonapartist, says that Napoleon's power +was based on his virtue and genius. Lanfrey, a Republican, says it was +based on his trickery and deception of the people. So the historians +of this class, by mutually destroying one another's positions, destroy +the understanding of the force which produces events, and furnish no +reply to history's essential question. + +Writers of universal history who deal with all the nations seem to +recognize how erroneous is the specialist historians' view of the +force which produces events. They do not recognize it as a power +inherent in heroes and rulers, but as the resultant of a +multiplicity of variously directed forces. In describing a war or +the subjugation of a people, a general historian looks for the cause +of the event not in the power of one man, but in the interaction of +many persons connected with the event. + +According to this view the power of historical personages, +represented as the product of many forces, can no longer, it would +seem, be regarded as a force that itself produces events. Yet in +most cases universal historians still employ the conception of power +as a force that itself produces events, and treat it as their cause. +In their exposition, an historic character is first the product of his +time, and his power only the resultant of various forces, and then his +power is itself a force producing events. Gervinus, Schlosser, and +others, for instance, at one time prove Napoleon to be a product of +the Revolution, of the ideas of 1789 and so forth, and at another +plainly say that the campaign of 1812 and other things they do not +like were simply the product of Napoleon's misdirected will, and +that the very ideas of 1789 were arrested in their development by +Napoleon's caprice. The ideas of the Revolution and the general temper +of the age produced Napoleon's power. But Napoleon's power +suppressed the ideas of the Revolution and the general temper of the +age. + +This curious contradiction is not accidental. Not only does it occur +at every step, but the universal historians' accounts are all made +up of a chain of such contradictions. This contradiction occurs +because after entering the field of analysis the universal +historians stop halfway. + +To find component forces equal to the composite or resultant +force, the sum of the components must equal the resultant. This +condition is never observed by the universal historians, and so to +explain the resultant forces they are obliged to admit, in addition to +the insufficient components, another unexplained force affecting the +resultant action. + +Specialist historians describing the campaign of 1813 or the +restoration of the Bourbons plainly assert that these events were +produced by the will of Alexander. But the universal historian +Gervinus, refuting this opinion of the specialist historian, tries +to prove that the campaign of 1813 and the restoration of the Bourbons +were due to other things beside Alexander's will--such as the activity +of Stein, Metternich, Madame de Stael, Talleyrand, Fichte +Chateaubriand, and others. The historian evidently decomposes +Alexander's power into the components: Talleyrand, Chateaubriand, +and the rest--but the sum of the components, that is, the interactions +of Chateaubriand, Talleyrand, Madame de Stael, and the others, +evidently does not equal the resultant, namely the phenomenon of +millions of Frenchmen submitting to the Bourbons. That +Chateaubriand, Madame de Stael, and others spoke certain words to +one another only affected their mutual relations but does not +account for the submission of millions. And therefore to explain how +from these relations of theirs the submission of millions of people +resulted--that is, how component forces equal to one A gave a +resultant equal to a thousand times A--the historian is again +obliged to fall back on power--the force he had denied--and to +recognize it as the resultant of the forces, that is, he has to +admit an unexplained force acting on the resultant. And that is just +what the universal historians do, and consequently they not only +contradict the specialist historians but contradict themselves. + +Peasants having no clear idea of the cause of rain, say, according +to whether they want rain or fine weather: "The wind has blown the +clouds away," or, "The wind has brought up the clouds." And in the +same way the universal historians sometimes, when it pleases them +and fits in with their theory, say that power is the result of events, +and sometimes, when they want to prove something else, say that +power produces events. + +A third class of historians--the so-called historians of culture- +following the path laid down by the universal historians who sometimes +accept writers and ladies as forces producing events--again take +that force to be something quite different. They see it in what is +called culture--in mental activity. + +The historians of culture are quite consistent in regard to their +progenitors, the writers of universal histories, for if historical +events may be explained by the fact that certain persons treated one +another in such and such ways, why not explain them by the fact that +such and such people wrote such and such books? Of the immense +number of indications accompanying every vital phenomenon, these +historians select the indication of intellectual activity and say that +this indication is the cause. But despite their endeavors to prove +that the cause of events lies in intellectual activity, only by a +great stretch can one admit that there is any connection between +intellectual activity and the movement of peoples, and in no case +can one admit that intellectual activity controls people's actions, +for that view is not confirmed by such facts as the very cruel murders +of the French Revolution resulting from the doctrine of the equality +of man, or the very cruel wars and executions resulting from the +preaching of love. + +But even admitting as correct all the cunningly devised arguments +with which these histories are filled--admitting that nations are +governed by some undefined force called an idea--history's essential +question still remains unanswered, and to the former power of monarchs +and to the influence of advisers and other people introduced by the +universal historians, another, newer force--the idea--is added, the +connection of which with the masses needs explanation. It is +possible to understand that Napoleon had power and so events occurred; +with some effort one may even conceive that Napoleon together with +other influences was the cause of an event; but how a book, Le Contrat +social, had the effect of making Frenchmen begin to drown one +another cannot be understood without an explanation of the causal +nexus of this new force with the event. + +Undoubtedly some relation exists between all who live +contemporaneously, and so it is possible to find some connection +between the intellectual activity of men and their historical +movements, just as such a connection may be found between the +movements of humanity and commerce, handicraft, gardening, or anything +else you please. But why intellectual activity is considered by the +historians of culture to be the cause or expression of the whole +historical movement is hard to understand. Only the following +considerations can have led the historians to such a conclusion: (1) +that history is written by learned men, and so it is natural and +agreeable for them to think that the activity of their class +supplies the basis of the movement of all humanity, just as a +similar belief is natural and agreeable to traders, agriculturists, +and soldiers (if they do not express it, that is merely because +traders and soldiers do not write history), and (2) that spiritual +activity, enlightenment, civilization, culture, ideas, are all +indistinct, indefinite conceptions under whose banner it is very +easy to use words having a still less definite meaning, and which +can therefore be readily introduced into any theory. + +But not to speak of the intrinsic quality of histories of this +kind (which may possibly even be of use to someone for something) +the histories of culture, to which all general histories tend more and +more to approximate, are significant from the fact that after +seriously and minutely examining various religious, philosophic, and +political doctrines as causes of events, as soon as they have to +describe an actual historic event such as the campaign of 1812 for +instance, they involuntarily describe it as resulting from an exercise +of power--and say plainly that that was the result of Napoleon's will. +Speaking so, the historians of culture involuntarily contradict +themselves, and show that the new force they have devised does not +account for what happens in history, and that history can only be +explained by introducing a power which they apparently do not +recognize. + + + + + +CHAPTER III + + +A locomotive is moving. Someone asks: "What moves it?" A peasant +says the devil moves it. Another man says the locomotive moves because +its wheels go round. A third asserts that the cause of its movement +lies in the smoke which the wind carries away. + +The peasant is irrefutable. He has devised a complete explanation. +To refute him someone would have to prove to him that there is no +devil, or another peasant would have to explain to him that it is +not the devil but a German, who moves the locomotive. Only then, as +a result of the contradiction, will they see that they are both wrong. +But the man who says that the movement of the wheels is the cause +refutes himself, for having once begun to analyze he ought to go on +and explain further why the wheels go round; and till he has reached +the ultimate cause of the movement of the locomotive in the pressure +of steam in the boiler, he has no right to stop in his search for +the cause. The man who explains the movement of the locomotive by +the smoke that is carried back has noticed that the wheels do not +supply an explanation and has taken the first sign that occurs to +him and in his turn has offered that as an explanation. + +The only conception that can explain the movement of the +locomotive is that of a force commensurate with the movement observed. + +The only conception that can explain the movement of the peoples +is that of some force commensurate with the whole movement of the +peoples. + +Yet to supply this conception various historians take forces of +different kinds, all of which are incommensurate with the movement +observed. Some see it as a force directly inherent in heroes, as the +peasant sees the devil in the locomotive; others as a force +resulting from several other forces, like the movement of the +wheels; others again as an intellectual influence, like the smoke that +is blown away. + +So long as histories are written of separate individuals, whether +Caesars, Alexanders, Luthers, or Voltaires, and not the histories of +all, absolutely all those who take part in an event, it is quite +impossible to describe the movement of humanity without the conception +of a force compelling men to direct their activity toward a certain +end. And the only such conception known to historians is that of +power. + +This conception is the one handle by means of which the material +of history, as at present expounded, can be dealt with, and anyone who +breaks that handle off, as Buckle did, without finding some other +method of treating historical material, merely deprives himself of the +one possible way of dealing with it. The necessity of the conception +of power as an explanation of historical events is best demonstrated +by the universal historians and historians of culture themselves, +for they professedly reject that conception but inevitably have +recourse to it at every step. + +In dealing with humanity's inquiry, the science of history up to now +is like money in circulation--paper money and coin. The biographies +and special national histories are like paper money. They can be +used and can circulate and fulfill their purpose without harm to +anyone and even advantageously, as long as no one asks what is the +security behind them. You need only forget to ask how the will of +heroes produces events, and such histories as Thiers' will be +interesting and instructive and may perhaps even possess a tinge of +poetry. But just as doubts of the real value of paper money arise +either because, being easy to make, too much of it gets made or +because people try to exchange it for gold, so also doubts +concerning the real value of such histories arise either because too +many of them are written or because in his simplicity of heart someone +inquires: by what force did Napoleon do this?--that is, wants to +exchange the current paper money for the real gold of actual +comprehension. + +The writers of universal histories and of the history of culture are +like people who, recognizing the defects of paper money, decide to +substitute for it money made of metal that has not the specific +gravity of gold. It may indeed make jingling coin, but will do no more +than that. Paper money may deceive the ignorant, but nobody is +deceived by tokens of base metal that have no value but merely jingle. +As gold is gold only if it is serviceable not merely for exchange +but also for use, so universal historians will be valuable only when +they can reply to history's essential question: what is power? The +universal historians give contradictory replies to that question, +while the historians of culture evade it and answer something quite +different. And as counters of imitation gold can be used only among +a group of people who agree to accept them as gold, or among those who +do not know the nature of gold, so universal historians and historians +of culture, not answering humanity's essential question, serve as +currency for some purposes of their own, only in universities and +among the mass of readers who have a taste for what they call "serious +reading." + + + + + +CHAPTER IV + + +Having abandoned the conception of the ancients as to the divine +subjection of the will of a nation to some chosen man and the +subjection of that man's will to the Deity, history cannot without +contradictions take a single step till it has chosen one of two +things: either a return to the former belief in the direct +intervention of the Deity in human affairs or a definite explanation +of the meaning of the force producing historical events and termed +"power." + +A return to the first is impossible, the belief has been +destroyed; and so it is essential to explain what is meant by power. + +Napoleon ordered an army to be raised and go to war. We are so +accustomed to that idea and have become so used to it that the +question: why did six hundred thousand men go to fight when Napoleon +uttered certain words, seems to us senseless. He had the power and +so what he ordered was done. + +This reply is quite satisfactory if we believe that the power was +given him by God. But as soon as we do not admit that, it becomes +essential to determine what is this power of one man over others. + +It cannot be the direct physical power of a strong man over a weak +one--a domination based on the application or threat of physical +force, like the power of Hercules; nor can it be based on the effect +of moral force, as in their simplicity some historians think who say +that the leading figures in history are heroes, that is, men gifted +with a special strength of soul and mind called genius. This power +cannot be based on the predominance of moral strength, for, not to +mention heroes such as Napoleon about whose moral qualities opinions +differ widely, history shows us that neither a Louis XI nor a +Metternich, who ruled over millions of people, had any particular +moral qualities, but on the contrary were generally morally weaker +than any of the millions they ruled over. + +If the source of power lies neither in the physical nor in the moral +qualities of him who possesses it, it must evidently be looked for +elsewhere--in the relation to the people of the man who wields the +power. + +And that is how power is understood by the science of jurisprudence, +that exchange bank of history which offers to exchange history's +understanding of power for true gold. + +Power is the collective will of the people transferred, by expressed +or tacit consent, to their chosen rulers. + +In the domain of jurisprudence, which consists of discussions of how +a state and power might be arranged were it possible for all that to +be arranged, it is all very clear; but when applied to history that +definition of power needs explanation. + +The science of jurisprudence regards the state and power as the +ancients regarded fire--namely, as something existing absolutely. +But for history, the state and power are merely phenomena, just as for +modern physics fire is not an element but a phenomenon. + +From this fundamental difference between the view held by history +and that held by jurisprudence, it follows that jurisprudence can tell +minutely how in its opinion power should be constituted and what +power--existing immutably outside time--is, but to history's questions +about the meaning of the mutations of power in time it can answer +nothing. + +If power be the collective will of the people transferred to their +ruler, was Pugachev a representative of the will of the people? If +not, then why was Napoleon I? Why was Napoleon III a criminal when +he was taken prisoner at Boulogne, and why, later on, were those +criminals whom he arrested? + +Do palace revolutions--in which sometimes only two or three people +take part--transfer the will of the people to a new ruler? In +international relations, is the will of the people also transferred to +their conqueror? Was the will of the Confederation of the Rhine +transferred to Napoleon in 1806? Was the will of the Russian people +transferred to Napoleon in 1809, when our army in alliance with the +French went to fight the Austrians? + +To these questions three answers are possible: + +Either to assume (1) that the will of the people is always +unconditionally transferred to the ruler or rulers they have chosen, +and that therefore every emergence of a new power, every struggle +against the power once appointed, should be absolutely regarded as +an infringement of the real power; or (2) that the will of the +people is transferred to the rulers conditionally, under definite +and known conditions, and to show that all limitations, conflicts, and +even destructions of power result from a nonobservance by the rulers +of the conditions under which their power was entrusted to them; or +(3) that the will of the people is delegated to the rulers +conditionally, but that the conditions are unknown and indefinite, and +that the appearance of several authorities, their struggles and +their falls, result solely from the greater or lesser fulfillment by +the rulers of these unknown conditions on which the will of the people +is transferred from some people to others. + +And these are the three ways in which the historians do explain +the relation of the people to their rulers. + +Some historians--those biographical and specialist historians +already referred to--in their simplicity failing to understand the +question of the meaning of power, seem to consider that the collective +will of the people is unconditionally transferred to historical +persons, and therefore when describing some single state they assume +that particular power to be the one absolute and real power, and +that any other force opposing this is not a power but a violation of +power--mere violence. + +Their theory, suitable for primitive and peaceful periods of +history, has the inconvenience--in application to complex and stormy +periods in the life of nations during which various powers arise +simultaneously and struggle with one another--that a Legitimist +historian will prove that the National Convention, the Directory, +and Bonaparte were mere infringers of the true power, while a +Republican and a Bonapartist will prove: the one that the Convention +and the other that the Empire was the real power, and that all the +others were violations of power. Evidently the explanations +furnished by these historians being mutually contradictory can only +satisfy young children. + +Recognizing the falsity of this view of history, another set of +historians say that power rests on a conditional delegation of the +will of the people to their rulers, and that historical leaders have +power only conditionally on carrying out the program that the will +of the people has by tacit agreement prescribed to them. But what this +program consists in these historians do not say, or if they do they +continually contradict one another. + +Each historian, according to his view of what constitutes a nation's +progress, looks for these conditions in the greatness, wealth, +freedom, or enlightenment of citizens of France or some other country. +But not to mention the historians' contradictions as to the nature +of this program--or even admitting that some one general program of +these conditions exists--the facts of history almost always contradict +that theory. If the conditions under which power is entrusted +consist in the wealth, freedom, and enlightenment of the people, how +is it that Louis XIV and Ivan the Terrible end their reigns +tranquilly, while Louis XVI and Charles I are executed by their +people? To this question historians reply that Louis XIV's activity, +contrary to the program, reacted on Louis XVI. But why did it not +react on Louis XIV or on Louis XV--why should it react just on Louis +XVI? And what is the time limit for such reactions? To these questions +there are and can be no answers. Equally little does this view explain +why for several centuries the collective will is not withdrawn from +certain rulers and their heirs, and then suddenly during a period of +fifty years is transferred to the Convention, to the Directory, to +Napoleon, to Alexander, to Louis XVIII, to Napoleon again, to +Charles X, to Louis Philippe, to a Republican government, and to +Napoleon III. When explaining these rapid transfers of the people's +will from one individual to another, especially in view of +international relations, conquests, and alliances, the historians +are obliged to admit that some of these transfers are not normal +delegations of the people's will but are accidents dependent on +cunning, on mistakes, on craft, or on the weakness of a diplomatist, a +ruler, or a party leader. So that the greater part of the events of +history--civil wars, revolutions, and conquests--are presented by +these historians not as the results of free transferences of the +people's will, but as results of the ill-directed will of one or +more individuals, that is, once again, as usurpations of power. And so +these historians also see and admit historical events which are +exceptions to the theory. + +These historians resemble a botanist who, having noticed that some +plants grow from seeds producing two cotyledons, should insist that +all that grows does so by sprouting into two leaves, and that the +palm, the mushroom, and even the oak, which blossom into full growth +and no longer resemble two leaves, are deviations from the theory. + +Historians of the third class assume that the will of the people +is transferred to historic personages conditionally, but that the +conditions are unknown to us. They say that historical personages have +power only because they fulfill the will of the people which has +been delegated to them. + +But in that case, if the force that moves nations lies not in the +historic leaders but in the nations themselves, what significance have +those leaders? + +The leaders, these historians tell us, express the will of the +people: the activity of the leaders represents the activity of the +people. + +But in that case the question arises whether all the activity of the +leaders serves as an expression of the people's will or only some part +of it. If the whole activity of the leaders serves as the expression +of the people's will, as some historians suppose, then all the details +of the court scandals contained in the biographies of a Napoleon or +a Catherine serve to express the life of the nation, which is +evident nonsense; but if it is only some particular side of the +activity of an historical leader which serves to express the +people's life, as other so-called "philosophical" historians +believe, then to determine which side of the activity of a leader +expresses the nation's life, we have first of all to know in what +the nation's life consists. + +Met by this difficulty historians of that class devise some most +obscure, impalpable, and general abstraction which can cover all +conceivable occurrences, and declare this abstraction to be the aim of +humanity's movement. The most usual generalizations adopted by +almost all the historians are: freedom, equality, enlightenment, +progress, civilization, and culture. Postulating some generalization +as the goal of the movement of humanity, the historians study the +men of whom the greatest number of monuments have remained: kings, +ministers, generals, authors, reformers, popes, and journalists, to +the extent to which in their opinion these persons have promoted or +hindered that abstraction. But as it is in no way proved that the +aim of humanity does consist in freedom, equality, enlightenment, or +civilization, and as the connection of the people with the rulers +and enlighteners of humanity is only based on the arbitrary assumption +that the collective will of the people is always transferred to the +men whom we have noticed, it happens that the activity of the millions +who migrate, burn houses, abandon agriculture, and destroy one another +never is expressed in the account of the activity of some dozen people +who did not burn houses, practice agriculture, or slay their fellow +creatures. + +History proves this at every turn. Is the ferment of the peoples +of the west at the end of the eighteenth century and their drive +eastward explained by the activity of Louis XIV, XV, and XVI, their +mistresses and ministers, and by the lives of Napoleon, Rousseau, +Diderot, Beaumarchais, and others? + +Is the movement of the Russian people eastward to Kazan and +Siberia expressed by details of the morbid character of Ivan the +Terrible and by his correspondence with Kurbski? + +Is the movement of the peoples at the time of the Crusades explained +by the life and activity of the Godfreys and the Louis-es and their +ladies? For us that movement of the peoples from west to east, without +leaders, with a crowd of vagrants, and with Peter the Hermit, +remains incomprehensible. And yet more incomprehensible is the +cessation of that movement when a rational and sacred aim for the +Crusade--the deliverance of Jerusalem--had been clearly defined by +historic leaders. Popes, kings, and knights incited the peoples to +free the Holy Land; but the people did not go, for the unknown cause +which had previously impelled them to go no longer existed. The +history of the Godfreys and the Minnesingers can evidently not cover +the life of the peoples. And the history of the Godfreys and the +Minnesingers has remained the history of Godfreys and Minnesingers, +but the history of the life of the peoples and their impulses has +remained unknown. + +Still less does the history of authors and reformers explain to us +the life of the peoples. + +The history of culture explains to us the impulses and conditions of +life and thought of a writer or a reformer. We learn that Luther had a +hot temper and said such and such things; we learn that Rousseau was +suspicious and wrote such and such books; but we do not learn why +after the Reformation the peoples massacred one another, nor why +during the French Revolution they guillotined one another. + +If we unite both these kinds of history, as is done by the newest +historians, we shall have the history of monarchs and writers, but not +the history of the life of the peoples. + + + + + +CHAPTER V + + +The life of the nations is not contained in the lives of a few +men, for the connection between those men and the nations has not been +found. The theory that this connection is based on the transference of +the collective will of a people to certain historical personages is an +hypothesis unconfirmed by the experience of history. + +The theory of the transference of the collective will of the +people to historic persons may perhaps explain much in the domain of +jurisprudence and be essential for its purposes, but in its +application to history, as soon as revolutions, conquests, or civil +wars occur--that is, as soon as history begins--that theory explains +nothing. + +The theory seems irrefutable just because the act of transference of +the people's will cannot be verified, for it never occurred. + +Whatever happens and whoever may stand at the head of affairs, the +theory can always say that such and such a person took the lead +because the collective will was transferred to him. + +The replies this theory gives to historical questions are like the +replies of a man who, watching the movements of a herd of cattle and +paying no attention to the varying quality of the pasturage in +different parts of the field, or to the driving of the herdsman, +should attribute the direction the herd takes to what animal happens +to be at its head. + +"The herd goes in that direction because the animal in front leads +it and the collective will of all the other animals is vested in +that leader." This is what historians of the first class say--those +who assume the unconditional transference of the people's will. + +"If the animals leading the herd change, this happens because the +collective will of all the animals is transferred from one leader to +another, according to whether the animal is or is not leading them +in the direction selected by the whole herd." Such is the reply +historians who assume that the collective will of the people is +delegated to rulers under conditions which they regard as known. (With +this method of observation it often happens that the observer, +influenced by the direction he himself prefers, regards those as +leaders who, owing to the people's change of direction, are no +longer in front, but on one side, or even in the rear.) + +"If the animals in front are continually changing and the +direction of the whole herd is constantly altered, this is because +in order to follow a given direction the animals transfer their will +to the animals that have attracted our attention, and to study the +movements of the herd we must watch the movements of all the prominent +animals moving on all sides of the herd." So say the third class of +historians who regard all historical persons, from monarchs to +journalists, as the expression of their age. + +The theory of the transference of the will of the people to historic +persons is merely a paraphrase--a restatement of the question in other +words. + +What causes historical events? Power. What is power? Power is the +collective will of the people transferred to one person. Under what +condition is the will of the people delegated to one person? On +condition that that person expresses the will of the whole people. +That is, power is power: in other words, power is a word the meaning +of which we do not understand. + + +If the realm of human knowledge were confined to abstract reasoning, +then having subjected to criticism the explanation of "power" that +juridical science gives us, humanity would conclude that power is +merely a word and has no real existence. But to understand phenomena +man has, besides abstract reasoning, experience by which he verifies +his reflections. And experience tells us that power is not merely a +word but an actually existing phenomenon. + +Not to speak of the fact that no description of the collective +activity of men can do without the conception of power, the +existence of power is proved both by history and by observing +contemporary events. + +Whenever an event occurs a man appears or men appear, by whose +will the event seems to have taken place. Napoleon III issues a decree +and the French go to Mexico. The King of Prussia and Bismarck issue +decrees and an army enters Bohemia. Napoleon I issues a decree and +an army enters Russia. Alexander I gives a command and the French +submit to the Bourbons. Experience shows us that whatever event occurs +it is always related to the will of one or of several men who have +decreed it. + +The historians, in accord with the old habit of acknowledging divine +intervention in human affairs, want to see the cause of events in +the expression of the will of someone endowed with power, but that +supposition is not confirmed either by reason or by experience. + +On the one side reflection shows that the expression of a man's +will--his words--are only part of the general activity expressed in an +event, as for instance in a war or a revolution, and so without +assuming an incomprehensible, supernatural force--a miracle--one +cannot admit that words can be the immediate cause of the movements of +millions of men. On the other hand, even if we admitted that words +could be the cause of events, history shows that the expression of the +will of historical personages does not in most cases produce any +effect, that is to say, their commands are often not executed, and +sometimes the very opposite of what they order occurs. + +Without admitting divine intervention in the affairs of humanity +we cannot regard "power" as the cause of events. + +Power, from the standpoint of experience, is merely the relation +that exists between the expression of someone's will and the execution +of that will by others. + +To explain the conditions of that relationship we must first +establish a conception of the expression of will, referring it to +man and not to the Deity. + +If the Deity issues a command, expresses His will, as ancient +history tells us, the expression of that will is independent of time +and is not caused by anything, for the Divinity is not controlled by +an event. But speaking of commands that are the expression of the will +of men acting in time and in relation to one another, to explain the +connection of commands with events we must restore: (1) the +condition of all that takes place: the continuity of movement in +time both of the events and of the person who commands, and (2) the +inevitability of the connection between the person commanding and +those who execute his command. + + + + + +CHAPTER VI + + +Only the expression of the will of the Deity, not dependent on time, +can relate to a whole series of events occurring over a period of +years or centuries, and only the Deity, independent of everything, can +by His sole will determine the direction of humanity's movement; but +man acts in time and himself takes part in what occurs. + +Reinstating the first condition omitted, that of time, we see that +no command can be executed without some preceding order having been +given rendering the execution of the last command possible. + +No command ever appears spontaneously, or itself covers a whole +series of occurrences; but each command follows from another, and +never refers to a whole series of events but always to one moment only +of an event. + +When, for instance, we say that Napoleon ordered armies to go to +war, we combine in one simultaneous expression a whole series of +consecutive commands dependent one on another. Napoleon could not have +commanded an invasion of Russia and never did so. Today he ordered +such and such papers to be written to Vienna, to Berlin, and to +Petersburg; tomorrow such and such decrees and orders to the army, the +fleet, the commissariat, and so on and so on--millions of commands, +which formed a whole series corresponding to a series of events +which brought the French armies into Russia. + +If throughout his reign Napoleon gave commands concerning an +invasion of England and expended on no other undertaking so much +time and effort, and yet during his whole reign never once attempted +to execute that design but undertook an expedition into Russia, with +which country he considered it desirable to be in alliance (a +conviction he repeatedly expressed)--this came about because his +commands did not correspond to the course of events in the first case, +but did so correspond in the latter. + +For an order to be certainly executed, it is necessary that a man +should order what can be executed. But to know what can and what +cannot be executed is impossible, not only in the case of Napoleon's +invasion of Russia in which millions participated, but even in the +simplest event, for in either case millions of obstacles may arise +to prevent its execution. Every order executed is always one of an +immense number unexecuted. All the impossible orders inconsistent with +the course of events remain unexecuted. Only the possible ones get +linked up with a consecutive series of commands corresponding to a +series of events, and are executed. + +Our false conception that an event is caused by a command which +precedes it is due to the fact that when the event has taken place and +out of thousands of others those few commands which were consistent +with that event have been executed, we forget about the others that +were not executed because they could not be. Apart from that, the +chief source of our error in this matter is due to the fact that in +the historical accounts a whole series of innumerable, diverse, and +petty events, such for instance as all those which led the French +armies to Russia, is generalized into one event in accord with the +result produced by that series of events, and corresponding with +this generalization the whole series of commands is also generalized +into a single expression of will. + +We say that Napoleon wished to invade Russia and invaded it. In +reality in all Napoleon's activity we never find anything resembling +an expression of that wish, but find a series of orders, or +expressions of his will, very variously and indefinitely directed. +Amid a long series of unexecuted orders of Napoleon's one series, +for the campaign of 1812, was carried out--not because those orders +differed in any way from the other, unexecuted orders but because they +coincided with the course of events that led the French army into +Russia; just as in stencil work this or that figure comes out not +because the color was laid on from this side or in that way, but +because it was laid on from all sides over the figure cut in the +stencil. + +So that examining the relation in time of the commands to the +events, we find that a command can never be the cause of the event, +but that a certain definite dependence exists between the two. + +To understand in what this dependence consists it is necessary to +reinstate another omitted condition of every command proceeding not +from the Deity but from a man, which is, that the man who gives the +command himself takes part in. + +This relation of the commander to those he commands is just what +is called power. This relation consists in the following: + +For common action people always unite in certain combinations, in +which regardless of the difference of the aims set for the common +action, the relation between those taking part in it is always the +same. + +Men uniting in these combinations always assume such relations +toward one another that the larger number take a more direct share, +and the smaller number a less direct share, in the collective action +for which they have combined. + +Of all the combinations in which men unite for collective action one +of the most striking and definite examples is an army. + +Every army is composed of lower grades of the service--the rank +and file--of whom there are always the greatest number; of the next +higher military rank--corporals and noncommissioned officers of whom +there are fewer, and of still-higher officers of whom there are +still fewer, and so on to the highest military command which is +concentrated in one person. + +A military organization may be quite correctly compared to a cone, +of which the base with the largest diameter consists of the rank and +file; the next higher and smaller section of the cone consists of +the next higher grades of the army, and so on to the apex, the point +of which will represent the commander in chief. + +The soldiers, of whom there are the most, form the lower section +of the cone and its base. The soldier himself does the stabbing, +hacking, burning, and pillaging, and always receives orders for +these actions from men above him; he himself never gives an order. The +noncommissioned officers (of whom there are fewer) perform the +action itself less frequently than the soldiers, but they already give +commands. An officer still less often acts directly himself, but +commands still more frequently. A general does nothing but command the +troops, indicates the objective, and hardly ever uses a weapon +himself. The commander in chief never takes direct part in the +action itself, but only gives general orders concerning the movement +of the mass of the troops. A similar relation of people to one another +is seen in every combination of men for common activity--in +agriculture, trade, and every administration. + +And so without particularly analyzing all the contiguous sections of +a cone and of the ranks of an army, or the ranks and positions in +any administrative or public business whatever from the lowest to +the highest, we see a law by which men, to take associated action, +combine in such relations that the more directly they participate in +performing the action the less they can command and the more +numerous they are, while the less their direct participation in the +action itself, the more they command and the fewer of them there +are; rising in this way from the lowest ranks to the man at the top, +who takes the least direct share in the action and directs his +activity chiefly to commanding. + +This relation of the men who command to those they command is what +constitutes the essence of the conception called power. + +Having restored the condition of time under which all events +occur, find that a command is executed only when it is related to a +corresponding series of events. Restoring the essential condition of +relation between those who command and those who execute, we find that +by the very nature of the case those who command take the smallest +part in the action itself and that their activity is exclusively +directed to commanding. + + + + + +CHAPTER VII + + +When an event is taking place people express their opinions and +wishes about it, and as the event results from the collective activity +of many people, some one of the opinions or wishes expressed is sure +to be fulfilled if but approximately. When one of the opinions +expressed is fulfilled, that opinion gets connected with the event +as a command preceding it. + +Men are hauling a log. Each of them expresses his opinion as to +how and where to haul it. They haul the log away, and it happens +that this is done as one of them said. He ordered it. There we have +command and power in their primary form. The man who worked most +with his hands could not think so much about what he was doing, or +reflect on or command what would result from the common activity; +while the man who commanded more would evidently work less with his +hands on account of his greater verbal activity. + +When some larger concourse of men direct their activity to a +common aim there is a yet sharper division of those who, because their +activity is given to directing and commanding, take less less part +in the direct work. + +When a man works alone he always has a certain set of reflections +which as it seems to him directed his past activity, justify his +present activity, and guide him in planning his future actions. Just +the same is done by a concourse of people, allowing those who do not +take a direct part in the activity to devise considerations, +justifications, and surmises concerning their collective activity. + +For reasons known or unknown to us the French began to drown and +kill one another. And corresponding to the event its justification +appears in people's belief that this was necessary for the welfare +of France, for liberty, and for equality. People ceased to kill one +another, and this event was accompanied by its justification in the +necessity for a centralization of power, resistance to Europe, and +so on. Men went from the west to the east killing their fellow men, +and the event was accompanied by phrases about the glory of France, +the baseness of England, and so on. History shows us that these +justifications of the events have no common sense and are all +contradictory, as in the case of killing a man as the result of +recognizing his rights, and the killing of millions in Russia for +the humiliation of England. But these justifications have a very +necessary significance in their own day. + +These justifications release those who produce the events from moral +responsibility. These temporary aims are like the broom fixed in front +of a locomotive to clear the snow from the rails in front: they +clear men's moral responsibilities from their path. + +Without such justification there would be no reply to the simplest +question that presents itself when examining each historical event. +How is it that millions of men commit collective crimes--make war, +commit murder, and so on? + +With the present complex forms of political and social life in +Europe can any event that is not prescribed, decreed, or ordered by +monarchs, ministers, parliaments, or newspapers be imagined? Is +there any collective action which cannot find its justification in +political unity, in patriotism, in the balance of power, or in +civilization? So that every event that occurs inevitably coincides +with some expressed wish and, receiving a justification, presents +itself as the result of the will of one man or of several men. + +In whatever direction a ship moves, the flow of the waves it cuts +will always be noticeable ahead of it. To those on board the ship +the movement of those waves will be the only perceptible motion. + +Only by watching closely moment by moment the movement of that +flow and comparing it with the movement of the ship do we convince +ourselves that every bit of it is occasioned by the forward movement +of the ship, and that we were led into error by the fact that we +ourselves were imperceptibly moving. + +We see the same if we watch moment by moment the movement of +historical characters (that is, re-establish the inevitable +condition of all that occurs--the continuity of movement in time) +and do not lose sight of the essential connection of historical +persons with the masses. + +When the ship moves in one direction there is one and the same +wave ahead of it, when it turns frequently the wave ahead of it also +turns frequently. But wherever it may turn there always will be the +wave anticipating its movement. + +Whatever happens it always appears that just that event was foreseen +and decreed. Wherever the ship may go, the rush of water which neither +directs nor increases its movement foams ahead of it, and at a +distance seems to us not merely to move of itself but to govern the +ship's movement also. + + +Examining only those expressions of the will of historical persons +which, as commands, were related to events, historians have assumed +that the events depended on those commands. But examining the events +themselves and the connection in which the historical persons stood to +the people, we have found that they and their orders were dependent on +events. The incontestable proof of this deduction is that, however +many commands were issued, the event does not take place unless +there are other causes for it, but as soon as an event occurs--be it +what it may--then out of all the continually expressed wishes of +different people some will always be found which by their meaning +and their time of utterance are related as commands to the events. + +Arriving at this conclusion we can reply directly and positively +to these two essential questions of history: + +(1) What is power? + +(2) What force produces the movement of the nations? + +(1) Power is the relation of a given person to other individuals, in +which the more this person expresses opinions, predictions, and +justifications of the collective action that is performed, the less is +his participation in that action. + +(2) The movement of nations is caused not by power, nor by +intellectual activity, nor even by a combination of the two as +historians have supposed, but by the activity of all the people who +participate in the events, and who always combine in such a way that +those taking the largest direct share in the event take on +themselves the least responsibility and vice versa. + +Morally the wielder of power appears to cause the event; +physically it is those who submit to the power. But as the moral +activity is inconceivable without the physical, the cause of the event +is neither in the one nor in the other but in the union of the two. + +Or in other words, the conception of a cause is inapplicable to +the phenomena we are examining. + +In the last analysis we reach the circle of infinity--that final +limit to which in every domain of thought man's reason arrives if it +is not playing with the subject. Electricity produces heat, heat +produces electricity. Atoms attract each other and atoms repel one +another. + +Speaking of the interaction of heat and electricity and of atoms, we +cannot say why this occurs, and we say that it is so because it is +inconceivable otherwise, because it must be so and that it is a law. +The same applies to historical events. Why war and revolution occur we +do not know. We only know that to produce the one or the other action, +people combine in a certain formation in which they all take part, and +we say that this is so because it is unthinkable otherwise, or in +other words that it is a law. + + + + + +CHAPTER VIII + + +If history dealt only with external phenomena, the establishment +of this simple and obvious law would suffice and we should have +finished our argument. But the law of history relates to man. A +particle of matter cannot tell us that it does not feel the law of +attraction or repulsion and that that law is untrue, but man, who is +the subject of history, says plainly: I am free and am therefore not +subject to the law. + +The presence of the problem of man's free will, though +unexpressed, is felt at every step of history. + +All seriously thinking historians have involuntarily encountered +this question. All the contradictions and obscurities of history and +the false path historical science has followed are due solely to the +lack of a solution of that question. + +If the will of every man were free, that is, if each man could act +as he pleased, all history would be a series of disconnected +incidents. + +If in a thousand years even one man in a million could act freely, +that is, as he chose, it is evident that one single free act of that +man's in violation of the laws governing human action would destroy +the possibility of the existence of any laws for the whole of +humanity. + +If there be a single law governing the actions of men, free will +cannot exist, for then man's will is subject to that law. + +In this contradiction lies the problem of free will, which from most +ancient times has occupied the best human minds and from most +ancient times has been presented in its whole tremendous significance. + +The problem is that regarding man as a subject of observation from +whatever point of view--theological, historical, ethical, or +philosophic--we find a general law of necessity to which he (like +all that exists) is subject. But regarding him from within ourselves +as what we are conscious of, we feel ourselves to be free. + +This consciousness is a source of self-cognition quite apart from +and independent of reason. Through his reason man observes himself, +but only through consciousness does he know himself. + +Apart from consciousness of self no observation or application of +reason is conceivable. + +To understand, observe, and draw conclusions, man must first of +all be conscious of himself as living. A man is only conscious of +himself as a living being by the fact that he wills, that is, is +conscious of his volition. But his will--which forms the essence of +his life--man recognizes (and can but recognize) as free. + +If, observing himself, man sees that his will is always directed +by one and the same law (whether he observes the necessity of taking +food, using his brain, or anything else) he cannot recognize this +never-varying direction of his will otherwise than as a limitation +of it. Were it not free it could not be limited. A man's will seems to +him to be limited just because he is not conscious of it except as +free. + +You say: I am not and am not free. But I have lifted my hand and let +it fall. Everyone understands that this illogical reply is an +irrefutable demonstration of freedom. + +That reply is the expression of a consciousness that is not +subject to reason. + +If the consciousness of freedom were not a separate and +independent source of self-consciousness it would be subject to +reasoning and to experience, but in fact such subjection does not +exist and is inconceivable. + +A series of experiments and arguments proves to every man that he, +as an object of observation, is subject to certain laws, and man +submits to them and never resists the laws of gravity or +impermeability once he has become acquainted with them. But the same +series of experiments and arguments proves to him that the complete +freedom of which he is conscious in himself is impossible, and that +his every action depends on his organization, his character, and the +motives acting upon him; yet man never submits to the deductions of +these experiments and arguments. Having learned from experiment and +argument that a stone falls downwards, a man indubitably believes this +and always expects the law that he has learned to be fulfilled. + +But learning just as certainly that his will is subject to laws, +he does not and cannot believe this. + +However often experiment and reasoning may show a man that under the +same conditions and with the same character he will do the same +thing as before, yet when under the same conditions and with the +same character he approaches for the thousandth time the action that +always ends in the same way, he feels as certainly convinced as before +the experiment that he can act as he pleases. Every man, savage or +sage, however incontestably reason and experiment may prove to him +that it is impossible to imagine two different courses of action in +precisely the same conditions, feels that without this irrational +conception (which constitutes the essence of freedom) he cannot +imagine life. He feels that however impossible it may be, it is so, +for without this conception of freedom not only would he be unable +to understand life, but he would be unable to live for a single +moment. + +He could not live, because all man's efforts, all his impulses to +life, are only efforts to increase freedom. Wealth and poverty, fame +and obscurity, power and subordination, strength and weakness, +health and disease, culture and ignorance, work and leisure, repletion +and hunger, virtue and vice, are only greater or lesser degrees of +freedom. + +A man having no freedom cannot be conceived of except as deprived of +life. + +If the conception of freedom appears to reason to be a senseless +contradiction like the possibility of performing two actions at one +and the same instant of time, or of an effect without a cause, that +only proves that consciousness is not subject to reason. + +This unshakable, irrefutable consciousness of freedom, +uncontrolled by experiment or argument, recognized by all thinkers and +felt by everyone without exception, this consciousness without which +no conception of man is possible constitutes the other side of the +question. + +Man is the creation of an all-powerful, all-good, and all-seeing +God. What is sin, the conception of which arises from the +consciousness of man's freedom? That is a question for theology. + +The actions of men are subject to general immutable laws expressed +in statistics. What is man's responsibility to society, the conception +of which results from the conception of freedom? That is a question +for jurisprudence. + +Man's actions proceed from his innate character and the motives +acting upon him. What is conscience and the perception of right and +wrong in actions that follows from the consciousness of freedom? +That is a question for ethics. + +Man in connection with the general life of humanity appears +subject to laws which determine that life. But the same man apart from +that connection appears to free. How should the past life of nations +and of humanity be regarded--as the result of the free, or as the +result of the constrained, activity of man? That is a question for +history. + +Only in our self-confident day of the popularization of knowledge- +thanks to that most powerful engine of ignorance, the diffusion of +printed matter--has the question of the freedom of will been put on +a level on which the question itself cannot exist. In our time the +majority of so-called advanced people--that is, the crowd of +ignoramuses--have taken the work of the naturalists who deal with +one side of the question for a solution of the whole problem. + +They say and write and print that the soul and freedom do not exist, +for the life of man is expressed by muscular movements and muscular +movements are conditioned by the activity of the nerves; the soul +and free will do not exist because at an unknown period of time we +sprang from the apes. They say this, not at all suspecting that +thousands of years ago that same law of necessity which with such +ardor they are now trying to prove by physiology and comparative +zoology was not merely acknowledged by all the religions and all the +thinkers, but has never been denied. They do not see that the role +of the natural sciences in this matter is merely to serve as an +instrument for the illumination of one side of it. For the fact +that, from the point of view of observation, reason and the will are +merely secretions of the brain, and that man following the general law +may have developed from lower animals at some unknown period of +time, only explains from a fresh side the truth admitted thousands +of years ago by all the religious and philosophic theories--that +from the point of view of reason man is subject to the law of +necessity; but it does not advance by a hair's breadth the solution of +the question, which has another, opposite, side, based on the +consciousness of freedom. + +If men descended from the apes at an unknown period of time, that is +as comprehensible as that they were made from a handful of earth at +a certain period of time (in the first case the unknown quantity is +the time, in the second case it is the origin); and the question of +how man's consciousness of freedom is to be reconciled with the law of +necessity to which he is subject cannot be solved by comparative +physiology and zoology, for in a frog, a rabbit, or an ape, we can +observe only the muscular nervous activity, but in man we observe +consciousness as well as the muscular and nervous activity. + +The naturalists and their followers, thinking they can solve this +question, are like plasterers set to plaster one side of the walls +of a church who, availing themselves of the absence of the chief +superintendent of the work, should in an access of zeal plaster over +the windows, icons, woodwork, and still unbuttressed walls, and should +be delighted that from their point of view as plasterers, everything +is now so smooth and regular. + + + + + +CHAPTER IX + + +For the solution of the question of free will or inevitability, +history has this advantage over other branches of knowledge in which +the question is dealt with, that for history this question does not +refer to the essence of man's free will but its manifestation in the +past and under certain conditions. + +In regard to this question, history stands to the other sciences +as experimental science stands to abstract science. + +The subject for history is not man's will itself but our +presentation of it. + +And so for history, the insoluble mystery presented by the +incompatibility of free will and inevitability does not exist as it +does for theology, ethics, and philosophy. History surveys a +presentation of man's life in which the union of these two +contradictions has already taken place. + +In actual life each historic event, each human action, is very +clearly and definitely understood without any sense of +contradiction, although each event presents itself as partly free +and partly compulsory. + +To solve the question of how freedom and necessity are combined +and what constitutes the essence of these two conceptions, the +philosophy of history can and should follow a path contrary to that +taken by other sciences. Instead of first defining the conceptions +of freedom and inevitability in themselves, and then ranging the +phenomena of life under those definitions, history should deduce a +definition of the conception of freedom and inevitability themselves +from the immense quantity of phenomena of which it is cognizant and +that always appear dependent on these two elements. + +Whatever presentation of the activity of many men or of an +individual we may consider, we always regard it as the result partly +of man's free will and partly of the law of inevitability. + +Whether we speak of the migration of the peoples and the +incursions of the barbarians, or of the decrees of Napoleon III, or of +someone's action an hour ago in choosing one direction out of +several for his walk, we are unconscious of any contradiction. The +degree of freedom and inevitability governing the actions of these +people is clearly defined for us. + +Our conception of the degree of freedom often varies according to +differences in the point of view from which we regard the event, but +every human action appears to us as a certain combination of freedom +and inevitability. In every action we examine we see a certain measure +of freedom and a certain measure of inevitability. And always the more +freedom we see in any action the less inevitability do we perceive, +and the more inevitability the less freedom. + +The proportion of freedom to inevitability decreases and increases +according to the point of view from which the action is regarded, +but their relation is always one of inverse proportion. + +A sinking man who clutches at another and drowns him; or a hungry +mother exhausted by feeding her baby, who steals some food; or a man +trained to discipline who on duty at the word of command kills a +defenseless man--seem less guilty, that is, less free and more subject +to the law of necessity, to one who knows the circumstances in which +these people were placed, and more free to one who does not know +that the man was himself drowning, that the mother was hungry, that +the soldier was in the ranks, and so on. Similarly a man who committed +a murder twenty years ago and has since lived peaceably and harmlessly +in society seems less guilty and his action more due to the law of +inevitability, to someone who considers his action after twenty +years have elapsed than to one who examined it the day after it was +committed. And in the same way every action of an insane, intoxicated, +or highly excited man appears less free and more inevitable to one who +knows the mental condition of him who committed the action, and +seems more free and less inevitable to one who does not know it. In +all these cases the conception of freedom is increased or diminished +and the conception of compulsion is correspondingly decreased or +increased, according to the point of view from which the action is +regarded. So that the greater the conception of necessity the +smaller the conception of freedom and vice versa. + +Religion, the common sense of mankind, the science of jurisprudence, +and history itself understand alike this relation between necessity +and freedom. + +All cases without exception in which our conception of freedom and +necessity is increased and diminished depend on three considerations: + +(1) The relation to the external world of the man who commits the +deeds. + +(2) His relation to time. + +(3) His relation to the causes leading to the action. + +The first consideration is the clearness of our perception of the +man's relation to the external world and the greater or lesser +clearness of our understanding of the definite position occupied by +the man in relation to everything coexisting with him. This is what +makes it evident that a drowning man is less free and more subject +to necessity than one standing on dry ground, and that makes the +actions of a man closely connected with others in a thickly +populated district, or of one bound by family, official, or business +duties, seem certainly less free and more subject to necessity than +those of a man living in solitude and seclusion. + +If we consider a man alone, apart from his relation to everything +around him, each action of his seems to us free. But if we see his +relation to anything around him, if we see his connection with +anything whatever--with a man who speaks to him, a book he reads, +the work on which he is engaged, even with the air he breathes or +the light that falls on the things about him--we see that each of +these circumstances has an influence on him and controls at least some +side of his activity. And the more we perceive of these influences the +more our conception of his freedom diminishes and the more our +conception of the necessity that weighs on him increases. + +The second consideration is the more or less evident time relation +of the man to the world and the clearness of our perception of the +place the man's action occupies in time. That is the ground which +makes the fall of the first man, resulting in the production of the +human race, appear evidently less free than a man's entry into +marriage today. It is the reason why the life and activity of people +who lived centuries ago and are connected with me in time cannot +seem to me as free as the life of a contemporary, the consequences +of which are still unknown to me. + +The degree of our conception of freedom or inevitability depends +in this respect on the greater or lesser lapse of time between the +performance of the action and our judgment of it. + +If I examine an act I performed a moment ago in approximately the +same circumstances as those I am in now, my action appears to me +undoubtedly free. But if I examine an act performed a month ago, +then being in different circumstances, I cannot help recognizing +that if that act had not been committed much that resulted from it- +good, agreeable, and even essential--would not have taken place. If +I reflect on an action still more remote, ten years ago or more, +then the consequences of my action are still plainer to me and I +find it hard to imagine what would have happened had that action not +been performed. The farther I go back in memory, or what is the same +thing the farther I go forward in my judgment, the more doubtful +becomes my belief in the freedom of my action. + +In history we find a very similar progress of conviction +concerning the part played by free will in the general affairs of +humanity. A contemporary event seems to us to be indubitably the doing +of all the known participants, but with a more remote event we already +see its inevitable results which prevent our considering anything else +possible. And the farther we go back in examining events the less +arbitrary do they appear. + +The Austro-Prussian war appears to us undoubtedly the result of +the crafty conduct of Bismarck, and so on. The Napoleonic wars still +seem to us, though already questionably, to be the outcome of their +heroes' will. But in the Crusades we already see an event occupying +its definite place in history and without which we cannot imagine +the modern history of Europe, though to the chroniclers of the +Crusades that event appeared as merely due to the will of certain +people. In regard to the migration of the peoples it does not enter +anyone's head today to suppose that the renovation of the European +world depended on Attila's caprice. The farther back in history the +object of our observation lies, the more doubtful does the free will +of those concerned in the event become and the more manifest the law +of inevitability. + +The third consideration is the degree to which we apprehend that +endless chain of causation inevitably demanded by reason, in which +each phenomenon comprehended, and therefore man's every action, must +have its definite place as a result of what has gone before and as a +cause of what will follow. + +The better we are acquainted with the physiological, +psychological, and historical laws deduced by observation and by which +man is controlled, and the more correctly we perceive the +physiological, psychological, and historical causes of the action, and +the simpler the action we are observing and the less complex the +character and mind of the man in question, the more subject to +inevitability and the less free do our actions and those of others +appear. + +When we do not at all understand the cause of an action, whether a +crime, a good action, or even one that is simply nonmoral, we +ascribe a greater amount of freedom to it. In the case of a crime we +most urgently demand the punishment for such an act; in the case of +a virtuous act we rate its merit most highly. In an indifferent case +we recognize in it more individuality, originality, and +independence. But if even one of the innumerable causes of the act +is known to us we recognize a certain element of necessity and are +less insistent on punishment for the crime, or the acknowledgment of +the merit of the virtuous act, or the freedom of the apparently +original action. That a criminal was reared among male factors +mitigates his fault in our eyes. The self-sacrifice of a father or +mother, or self-sacrifice with the possibility of a reward, is more +comprehensible than gratuitous self-sacrifice, and therefore seems +less deserving of sympathy and less the result of free will. The +founder of a sect or party, or an inventor, impresses us less when +we know how or by what the way was prepared for his activity. If we +have a large range of examples, if our observation is constantly +directed to seeking the correlation of cause and effect in people's +actions, their actions appear to us more under compulsion and less +free the more correctly we connect the effects with the causes. If +we examined simple actions and had a vast number of such actions under +observation, our conception of their inevitability would be still +greater. The dishonest conduct of the son of a dishonest father, the +misconduct of a woman who had fallen into bad company, a drunkard's +relapse into drunkenness, and so on are actions that seem to us less +free the better we understand their cause. If the man whose actions we +are considering is on a very low stage of mental development, like a +child, a madman, or a simpleton--then, knowing the causes of the act +and the simplicity of the character and intelligence in question, we +see so large an element of necessity and so little free will that as +soon as we know the cause prompting the action we can foretell the +result. + +On these three considerations alone is based the conception of +irresponsibility for crimes and the extenuating circumstances admitted +by all legislative codes. The responsibility appears greater or less +according to our greater or lesser knowledge of the circumstances in +which the man was placed whose action is being judged, and according +to the greater or lesser interval of time between the commission of +the action and its investigation, and according to the greater or +lesser understanding of the causes that led to the action. + + + + + +CHAPTER X + + +Thus our conception of free will and inevitability gradually +diminishes or increases according to the greater or lesser +connection with the external world, the greater or lesser remoteness +of time, and the greater or lesser dependence on the causes in +relation to which we contemplate a man's life. + +So that if we examine the case of a man whose connection with the +external world is well known, where the time between the action and +its examination is great, and where the causes of the action are +most accessible, we get the conception of a maximum of inevitability +and a minimum of free will. If we examine a man little dependent on +external conditions, whose action was performed very recently, and the +causes of whose action are beyond our ken, we get the conception of +a minimum of inevitability and a maximum of freedom. + +In neither case--however we may change our point of view, however +plain we may make to ourselves the connection between the man and +the external world, however inaccessible it may be to us, however long +or short the period of time, however intelligible or +incomprehensible the causes of the action may be--can we ever conceive +either complete freedom or complete necessity. + +(1) To whatever degree we may imagine a man to be exempt from the +influence of the external world, we never get a conception of +freedom in space. Every human action is inevitably conditioned by what +surrounds him and by his own body. I lift my arm and let it fall. My +action seems to me free; but asking myself whether I could raise my +arm in every direction, I see that I raised it in the direction in +which there was least obstruction to that action either from things +around me or from the construction of my own body. I chose one out +of all the possible directions because in it there were fewest +obstacles. For my action to be free it was necessary that it should +encounter no obstacles. To conceive of a man being free we must +imagine him outside space, which is evidently impossible. + +(2) However much we approximate the time of judgment to the time +of the deed, we never get a conception of freedom in time. For if I +examine an action committed a second ago I must still recognize it +as not being free, for it is irrevocably linked to the moment at which +it was committed. Can I lift my arm? I lift it, but ask myself: +could I have abstained from lifting my arm at the moment that has +already passed? To convince myself of this I do not lift it the next +moment. But I am not now abstaining from doing so at the first +moment when I asked the question. Time has gone by which I could not +detain, the arm I then lifted is no longer the same as the arm I now +refrain from lifting, nor is the air in which I lifted it the same +that now surrounds me. The moment in which the first movement was made +is irrevocable, and at that moment I could make only one movement, and +whatever movement I made would be the only one. That I did not lift my +arm a moment later does not prove that I could have abstained from +lifting it then. And since I could make only one movement at that +single moment of time, it could not have been any other. To imagine it +as free, it is necessary to imagine it in the present, on the boundary +between the past and the future--that is, outside time, which is +impossible. + +(3) However much the difficulty of understanding the causes may be +increased, we never reach a conception of complete freedom, that is, +an absence of cause. However inaccessible to us may be the cause of +the expression of will in any action, our own or another's, the +first demand of reason is the assumption of and search for a cause, +for without a cause no phenomenon is conceivable. I raise my arm to +perform an action independently of any cause, but my wish to perform +an action without a cause is the cause of my action. + +But even if--imagining a man quite exempt from all influences, +examining only his momentary action in the present, unevoked by any +cause--we were to admit so infinitely small a remainder of +inevitability as equaled zero, we should even then not have arrived at +the conception of complete freedom in man, for a being uninfluenced by +the external world, standing outside of time and independent of cause, +is no longer a man. + +In the same way we can never imagine the action of a man quite +devoid of freedom and entirely subject to the law of inevitability. + +(1) However we may increase our knowledge of the conditions of space +in which man is situated, that knowledge can never be complete, for +the number of those conditions is as infinite as the infinity of +space. And therefore so long as not all the conditions influencing men +are defined, there is no complete inevitability but a certain +measure of freedom remains. + +(2) However we may prolong the period of time between the action +we are examining and the judgment upon it, that period will be finite, +while time is infinite, and so in this respect too there can never +be absolute inevitability. + +(3) However accessible may be the chain of causation of any +action, we shall never know the whole chain since it is endless, and +so again we never reach absolute inevitability. + +But besides this, even if, admitting the remaining minimum of +freedom to equal zero, we assumed in some given case--as for +instance in that of a dying man, an unborn babe, or an idiot--complete +absence of freedom, by so doing we should destroy the very +conception of man in the case we are examining, for as soon as there +is no freedom there is also no man. And so the conception of the +action of a man subject solely to the law of inevitability without any +element of freedom is just as impossible as the conception of a +man's completely free action. + +And so to imagine the action of a man entirely subject to the law of +inevitability without any freedom, we must assume the knowledge of +an infinite number of space relations, an infinitely long period of +time, and an infinite series of causes. + +To imagine a man perfectly free and not subject to the law of +inevitability, we must imagine him all alone, beyond space, beyond +time, and free from dependence on cause. + +In the first case, if inevitability were possible without freedom we +should have reached a definition of inevitability by the laws of +inevitability itself, that is, a mere form without content. + +In the second case, if freedom were possible without inevitability +we should have arrived at unconditioned freedom beyond space, time, +and cause, which by the fact of its being unconditioned and +unlimited would be nothing, or mere content without form. + +We should in fact have reached those two fundamentals of which man's +whole outlook on the universe is constructed--the incomprehensible +essence of life, and the laws defining that essence. + +Reason says: (1) space with all the forms of matter that give it +visibility is infinite, and cannot be imagined otherwise. (2) Time +is infinite motion without a moment of rest and is unthinkable +otherwise. (3) The connection between cause and effect has no +beginning and can have no end. + +Consciousness says: (1) I alone am, and all that exists is but me, +consequently I include space. (2) I measure flowing time by the +fixed moment of the present in which alone I am conscious of myself as +living, consequently I am outside time. (3) I am beyond cause, for I +feel myself to be the cause of every manifestation of my life. + +Reason gives expression to the laws of inevitability. +Consciousness gives expression to the essence of freedom. + +Freedom not limited by anything is the essence of life, in man's +consciousness. Inevitability without content is man's reason in its +three forms. + +Freedom is the thing examined. Inevitability is what examines. +Freedom is the content. Inevitability is the form. + +Only by separating the two sources of cognition, related to one +another as form to content, do we get the mutually exclusive and +separately incomprehensible conceptions of freedom and inevitability. + +Only by uniting them do we get a clear conception of man's life. + +Apart from these two concepts which in their union mutually define +one another as form and content, no conception of life is possible. + +All that we know of the life of man is merely a certain relation +of free will to inevitability, that is, of consciousness to the laws +of reason. + +All that we know of the external world of nature is only a certain +relation of the forces of nature to inevitability, or of the essence +of life to the laws of reason. + +The great natural forces lie outside us and we are not conscious +of them; we call those forces gravitation, inertia, electricity, +animal force, and so on, but we are conscious of the force of life +in man and we call that freedom. + +But just as the force of gravitation, incomprehensible in itself but +felt by every man, is understood by us only to the extent to which +we know the laws of inevitability to which it is subject (from the +first knowledge that all bodies have weight, up to Newton's law), so +too the force of free will, incomprehensible in itself but of which +everyone is conscious, is intelligible to us only in as far as we know +the laws of inevitability to which it is subject (from the fact that +every man dies, up to the knowledge of the most complex economic and +historic laws). + +All knowledge is merely a bringing of this essence of life under the +laws of reason. + +Man's free will differs from every other force in that man is +directly conscious of it, but in the eyes of reason it in no way +differs from any other force. The forces of gravitation, +electricity, or chemical affinity are only distinguished from one +another in that they are differently defined by reason. Just so the +force of man's free will is distinguished by reason from the other +forces of nature only by the definition reason gives it. Freedom, +apart from necessity, that is, apart from the laws of reason that +define it, differs in no way from gravitation, or heat, or the force +that makes things grow; for reason, it is only a momentary undefinable +sensation of life. + +And as the undefinable essence of the force moving the heavenly +bodies, the undefinable essence of the forces of heat and electricity, +or of chemical affinity, or of the vital force, forms the content of +astronomy, physics, chemistry, botany, zoology, and so on, just in the +same way does the force of free will form the content of history. +But just as the subject of every science is the manifestation of +this unknown essence of life while that essence itself can only be the +subject of metaphysics, even the manifestation of the force of free +will in human beings in space, in time, and in dependence on cause +forms the subject of history, while free will itself is the subject of +metaphysics. + +In the experimental sciences what we know we call the laws of +inevitability, what is unknown to us we call vital force. Vital +force is only an expression for the unknown remainder over and above +what we know of the essence of life. + +So also in history what is known to us we call laws of +inevitability, what is unknown we call free will. Free will is for +history only an expression for the unknown remainder of what we know +about the laws of human life. + + + + + +CHAPTER XI + + +History examines the manifestations of man's free will in connection +with the external world in time and in dependence on cause, that is, +it defines this freedom by the laws of reason, and so history is a +science only in so far as this free will is defined by those laws. + +The recognition of man's free will as something capable of +influencing historical events, that is, as not subject to laws, is the +same for history as the recognition of a free force moving the +heavenly bodies would be for astronomy. + +That assumption would destroy the possibility of the existence of +laws, that is, of any science whatever. If there is even a single body +moving freely, then the laws of Kepler and Newton are negatived and no +conception of the movement of the heavenly bodies any longer exists. +If any single action is due to free will, then not a single historical +law can exist, nor any conception of historical events. + +For history, lines exist of the movement of human wills, one end +of which is hidden in the unknown but at the other end of which a +consciousness of man's will in the present moves in space, time, and +dependence on cause. + +The more this field of motion spreads out before our eyes, the +more evident are the laws of that movement. To discover and define +those laws is the problem of history. + +From the standpoint from which the science of history now regards +its subject on the path it now follows, seeking the causes of events +in man's freewill, a scientific enunciation of those laws is +impossible, for however man's free will may be restricted, as soon +as we recognize it as a force not subject to law, the existence of law +becomes impossible. + +Only by reducing this element of free will to the infinitesimal, +that is, by regarding it as an infinitely small quantity, can we +convince ourselves of the absolute inaccessibility of the causes, +and then instead of seeking causes, history will take the discovery of +laws as its problem. + +The search for these laws has long been begun and the new methods of +thought which history must adopt are being worked out simultaneously +with the self-destruction toward which--ever dissecting and dissecting +the causes of phenomena--the old method of history is moving. + +All human sciences have traveled along that path. Arriving at +infinitesimals, mathematics, the most exact of sciences, abandons +the process of analysis and enters on the new process of the +integration of unknown, infinitely small, quantities. Abandoning the +conception of cause, mathematics seeks law, that is, the property +common to all unknown, infinitely small, elements. + +In another form but along the same path of reflection the other +sciences have proceeded. When Newton enunciated the law of gravity +he did not say that the sun or the earth had a property of attraction; +he said that all bodies from the largest to the smallest have the +property of attracting one another, that is, leaving aside the +question of the cause of the movement of the bodies, he expressed +the property common to all bodies from the infinitely large to the +infinitely small. The same is done by the natural sciences: leaving +aside the question of cause, they seek for laws. History stands on the +same path. And if history has for its object the study of the movement +of the nations and of humanity and not the narration of episodes in +the lives of individuals, it too, setting aside the conception of +cause, should seek the laws common to all the inseparably +interconnected infinitesimal elements of free will. + + + + + +CHAPTER XII + + +From the time the law of Copernicus was discovered and proved, the +mere recognition of the fact that it was not the sun but the earth +that moves sufficed to destroy the whole cosmography of the +ancients. By disproving that law it might have been possible to retain +the old conception of the movements of the bodies, but without +disproving it, it would seem impossible to continue studying the +Ptolemaic worlds. But even after the discovery of the law of +Copernicus the Ptolemaic worlds were still studied for a long time. + +From the time the first person said and proved that the number of +births or of crimes is subject to mathematical laws, and that this +or that mode of government is determined by certain geographical and +economic conditions, and that certain relations of population to +soil produce migrations of peoples, the foundations on which history +had been built were destroyed in their essence. + +By refuting these new laws the former view of history might have +been retained; but without refuting them it would seem impossible to +continue studying historic events as the results of man's free will. +For if a certain mode of government was established or certain +migrations of peoples took place in consequence of such and such +geographic, ethnographic, or economic conditions, then the free will +of those individuals who appear to us to have established that mode of +government or occasioned the migrations can no longer be regarded as +the cause. + +And yet the former history continues to be studied side by side with +the laws of statistics, geography, political economy, comparative +philology, and geology, which directly contradict its assumptions. + +The struggle between the old views and the new was long and +stubbornly fought out in physical philosophy. Theology stood on +guard for the old views and accused the new of violating revelation. +But when truth conquered, theology established itself just as firmly +on the new foundation. + +Just as prolonged and stubborn is the struggle now proceeding +between the old and the new conception of history, and theology in the +same way stands on guard for the old view, and accuses the new view of +subverting revelation. + +In the one case as in the other, on both sides the struggle provokes +passion and stifles truth. On the one hand there is fear and regret +for the loss of the whole edifice constructed through the ages, on the +other is the passion for destruction. + +To the men who fought against the rising truths of physical +philosophy, it seemed that if they admitted that truth it would +destroy faith in God, in the creation of the firmament, and in the +miracle of Joshua the son of Nun. To the defenders of the laws of +Copernicus and Newton, to Voltaire for example, it seemed that the +laws of astronomy destroyed religion, and he utilized the law of +gravitation as a weapon against religion. + +Just so it now seems as if we have only to admit the law of +inevitability, to destroy the conception of the soul, of good and +evil, and all the institutions of state and church that have been +built up on those conceptions. + +So too, like Voltaire in his time, uninvited defenders of the law of +inevitability today use that law as a weapon against religion, +though the law of inevitability in history, like the law of Copernicus +in astronomy, far from destroying, even strengthens the foundation +on which the institutions of state and church are erected. + +As in the question of astronomy then, so in the question of +history now, the whole difference of opinion is based on the +recognition or nonrecognition of something absolute, serving as the +measure of visible phenomena. In astronomy it was the immovability +of the earth, in history it is the independence of personality--free +will. + +As with astronomy the difficulty of recognizing the motion of the +earth lay in abandoning the immediate sensation of the earth's +fixity and of the motion of the planets, so in history the +difficulty of recognizing the subjection of personality to the laws of +space, time, and cause lies in renouncing the direct feeling of the +independence of one's own personality. But as in astronomy the new +view said: "It is true that we do not feel the movement of the +earth, but by admitting its immobility we arrive at absurdity, while +by admitting its motion (which we do not feel) we arrive at laws," +so also in history the new view says: "It is true that we are not +conscious of our dependence, but by admitting our free will we +arrive at absurdity, while by admitting our dependence on the external +world, on time, and on cause, we arrive at laws." + +In the first case it was necessary to renounce the consciousness +of an unreal immobility in space and to recognize a motion we did +not feel; in the present case it is similarly necessary to renounce +a freedom that does not exist, and to recognize a dependence of +which we are not conscious. + + + + +*** END OF THE PROJECT GUTENBERG EBOOK, WAR AND PEACE *** + +This file should be named wrnpc11.txt or wrnpc11.zip +Corrected EDITIONS of our eBooks get a new NUMBER, wrnpc12.txt +VERSIONS based on separate sources get new LETTER, wrnpc11a.txt + +Project Gutenberg eBooks are often created from several printed +editions, all of which are confirmed as Public Domain in the US +unless a copyright notice is included. Thus, we usually do not +keep eBooks in compliance with any particular paper edition. + +We are now trying to release all our eBooks one year in advance +of the official release dates, leaving time for better editing. +Please be encouraged to tell us about any error or corrections, +even years after the official publication date. + +Please note neither this listing nor its contents are final til +midnight of the last day of the month of any such announcement. +The official release date of all Project Gutenberg eBooks is at +Midnight, Central Time, of the last day of the stated month. A +preliminary version may often be posted for suggestion, comment +and editing by those who wish to do so. + +Most people start at our Web sites at: +http://gutenberg.net or +http://promo.net/pg + +These Web sites include award-winning information about Project +Gutenberg, including how to donate, how to help produce our new +eBooks, and how to subscribe to our email newsletter (free!). + + +Those of you who want to download any eBook before announcement +can get to them as follows, and just download by date. This is +also a good way to get them instantly upon announcement, as the +indexes our cataloguers produce obviously take a while after an +announcement goes out in the Project Gutenberg Newsletter. + +http://www.ibiblio.org/gutenberg/etext05 or +ftp://ftp.ibiblio.org/pub/docs/books/gutenberg/etext05 + +Or /etext04, 03, 02, 01, 00, 99, 98, 97, 96, 95, 94, 93, 92, 92, +91 or 90 + +Just search by the first five letters of the filename you want, +as it appears in our Newsletters. + + +Information about Project Gutenberg (one page) + +We produce about two million dollars for each hour we work. The +time it takes us, a rather conservative estimate, is fifty hours +to get any eBook selected, entered, proofread, edited, copyright +searched and analyzed, the copyright letters written, etc. Our +projected audience is one hundred million readers. If the value +per text is nominally estimated at one dollar then we produce $2 +million dollars per hour in 2002 as we release over 100 new text +files per month: 1240 more eBooks in 2001 for a total of 4000+ +We are already on our way to trying for 2000 more eBooks in 2002 +If they reach just 1-2% of the world's population then the total +will reach over half a trillion eBooks given away by year's end. + +The Goal of Project Gutenberg is to Give Away 1 Trillion eBooks! +This is ten thousand titles each to one hundred million readers, +which is only about 4% of the present number of computer users. + +Here is the briefest record of our progress (* means estimated): + +eBooks Year Month + + 1 1971 July + 10 1991 January + 100 1994 January + 1000 1997 August + 1500 1998 October + 2000 1999 December + 2500 2000 December + 3000 2001 November + 4000 2001 October/November + 6000 2002 December* + 9000 2003 November* +10000 2004 January* + + +The Project Gutenberg Literary Archive Foundation has been created +to secure a future for Project Gutenberg into the next millennium. + +We need your donations more than ever! + +As of February, 2002, contributions are being solicited from people +and organizations in: Alabama, Alaska, Arkansas, Connecticut, +Delaware, District of Columbia, Florida, Georgia, Hawaii, Illinois, +Indiana, Iowa, Kansas, Kentucky, Louisiana, Maine, Massachusetts, +Michigan, Mississippi, Missouri, Montana, Nebraska, Nevada, New +Hampshire, New Jersey, New Mexico, New York, North Carolina, Ohio, +Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina, South +Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West +Virginia, Wisconsin, and Wyoming. + +We have filed in all 50 states now, but these are the only ones +that have responded. + +As the requirements for other states are met, additions to this list +will be made and fund raising will begin in the additional states. +Please feel free to ask to check the status of your state. + +In answer to various questions we have received on this: + +We are constantly working on finishing the paperwork to legally +request donations in all 50 states. If your state is not listed and +you would like to know if we have added it since the list you have, +just ask. + +While we cannot solicit donations from people in states where we are +not yet registered, we know of no prohibition against accepting +donations from donors in these states who approach us with an offer to +donate. + +International donations are accepted, but we don't know ANYTHING about +how to make them tax-deductible, or even if they CAN be made +deductible, and don't have the staff to handle it even if there are +ways. + +Donations by check or money order may be sent to: + + PROJECT GUTENBERG LITERARY ARCHIVE FOUNDATION + 809 North 1500 West + Salt Lake City, UT 84116 + +Contact us if you want to arrange for a wire transfer or payment +method other than by check or money order. + +The Project Gutenberg Literary Archive Foundation has been approved by +the US Internal Revenue Service as a 501(c)(3) organization with EIN +[Employee Identification Number] 64-622154. Donations are +tax-deductible to the maximum extent permitted by law. As fund-raising +requirements for other states are met, additions to this list will be +made and fund-raising will begin in the additional states. + +We need your donations more than ever! + +You can get up to date donation information online at: + +http://www.gutenberg.net/donation.html + + +*** + +If you can't reach Project Gutenberg, +you can always email directly to: + +Michael S. Hart + +Prof. Hart will answer or forward your message. + +We would prefer to send you information by email. + + +**The Legal Small Print** + + +(Three Pages) + +***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN EBOOKS**START*** +Why is this "Small Print!" statement here? You know: lawyers. +They tell us you might sue us if there is something wrong with +your copy of this eBook, even if you got it for free from +someone other than us, and even if what's wrong is not our +fault. So, among other things, this "Small Print!" statement +disclaims most of our liability to you. It also tells you how +you may distribute copies of this eBook if you want to. + +*BEFORE!* YOU USE OR READ THIS EBOOK +By using or reading any part of this PROJECT GUTENBERG-tm +eBook, you indicate that you understand, agree to and accept +this "Small Print!" statement. If you do not, you can receive +a refund of the money (if any) you paid for this eBook by +sending a request within 30 days of receiving it to the person +you got it from. If you received this eBook on a physical +medium (such as a disk), you must return it with your request. + +ABOUT PROJECT GUTENBERG-TM EBOOKS +This PROJECT GUTENBERG-tm eBook, like most PROJECT GUTENBERG-tm eBooks, +is a "public domain" work distributed by Professor Michael S. Hart +through the Project Gutenberg Association (the "Project"). +Among other things, this means that no one owns a United States copyright +on or for this work, so the Project (and you!) can copy and +distribute it in the United States without permission and +without paying copyright royalties. Special rules, set forth +below, apply if you wish to copy and distribute this eBook +under the "PROJECT GUTENBERG" trademark. + +Please do not use the "PROJECT GUTENBERG" trademark to market +any commercial products without permission. + +To create these eBooks, the Project expends considerable +efforts to identify, transcribe and proofread public domain +works. Despite these efforts, the Project's eBooks and any +medium they may be on may contain "Defects". Among other +things, Defects may take the form of incomplete, inaccurate or +corrupt data, transcription errors, a copyright or other +intellectual property infringement, a defective or damaged +disk or other eBook medium, a computer virus, or computer +codes that damage or cannot be read by your equipment. + +LIMITED WARRANTY; DISCLAIMER OF DAMAGES +But for the "Right of Replacement or Refund" described below, +[1] Michael Hart and the Foundation (and any other party you may +receive this eBook from as a PROJECT GUTENBERG-tm eBook) disclaims +all liability to you for damages, costs and expenses, including +legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR +UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT, +INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE +OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE +POSSIBILITY OF SUCH DAMAGES. + +If you discover a Defect in this eBook within 90 days of +receiving it, you can receive a refund of the money (if any) +you paid for it by sending an explanatory note within that +time to the person you received it from. If you received it +on a physical medium, you must return it with your note, and +such person may choose to alternatively give you a replacement +copy. If you received it electronically, such person may +choose to alternatively give you a second opportunity to +receive it electronically. + +THIS EBOOK IS OTHERWISE PROVIDED TO YOU "AS-IS". NO OTHER +WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS +TO THE EBOOK OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT +LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A +PARTICULAR PURPOSE. + +Some states do not allow disclaimers of implied warranties or +the exclusion or limitation of consequential damages, so the +above disclaimers and exclusions may not apply to you, and you +may have other legal rights. + +INDEMNITY +You will indemnify and hold Michael Hart, the Foundation, +and its trustees and agents, and any volunteers associated +with the production and distribution of Project Gutenberg-tm +texts harmless, from all liability, cost and expense, including +legal fees, that arise directly or indirectly from any of the +following that you do or cause: [1] distribution of this eBook, +[2] alteration, modification, or addition to the eBook, +or [3] any Defect. + +DISTRIBUTION UNDER "PROJECT GUTENBERG-tm" +You may distribute copies of this eBook electronically, or by +disk, book or any other medium if you either delete this +"Small Print!" and all other references to Project Gutenberg, +or: + +[1] Only give exact copies of it. Among other things, this + requires that you do not remove, alter or modify the + eBook or this "small print!" statement. You may however, + if you wish, distribute this eBook in machine readable + binary, compressed, mark-up, or proprietary form, + including any form resulting from conversion by word + processing or hypertext software, but only so long as + *EITHER*: + + [*] The eBook, when displayed, is clearly readable, and + does *not* contain characters other than those + intended by the author of the work, although tilde + (~), asterisk (*) and underline (_) characters may + be used to convey punctuation intended by the + author, and additional characters may be used to + indicate hypertext links; OR + + [*] The eBook may be readily converted by the reader at + no expense into plain ASCII, EBCDIC or equivalent + form by the program that displays the eBook (as is + the case, for instance, with most word processors); + OR + + [*] You provide, or agree to also provide on request at + no additional cost, fee or expense, a copy of the + eBook in its original plain ASCII form (or in EBCDIC + or other equivalent proprietary form). + +[2] Honor the eBook refund and replacement provisions of this + "Small Print!" statement. + +[3] Pay a trademark license fee to the Foundation of 20% of the + gross profits you derive calculated using the method you + already use to calculate your applicable taxes. If you + don't derive profits, no royalty is due. Royalties are + payable to "Project Gutenberg Literary Archive Foundation" + the 60 days following each date you prepare (or were + legally required to prepare) your annual (or equivalent + periodic) tax return. Please contact us beforehand to + let us know your plans and to work out the details. + +WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO? +Project Gutenberg is dedicated to increasing the number of +public domain and licensed works that can be freely distributed +in machine readable form. + +The Project gratefully accepts contributions of money, time, +public domain materials, or royalty free copyright licenses. +Money should be paid to the: +"Project Gutenberg Literary Archive Foundation." + +If you are interested in contributing scanning equipment or +software or other items, please contact Michael Hart at: +hart@pobox.com + +[Portions of this eBook's header and trailer may be reprinted only +when distributed free of all fees. Copyright (C) 2001, 2002 by +Michael S. Hart. Project Gutenberg is a TradeMark and may not be +used in any sales of Project Gutenberg eBooks or other materials be +they hardware or software or any other related product without +express permission.] + +*END THE SMALL PRINT! FOR PUBLIC DOMAIN EBOOKS*Ver.02/11/02*END* + + the + be + of + and + a + in + to + have + it + to + for + i + that + you + he + on + with + do + at + by + not + this + but + from + they + his + that + she + or + which + as + we + an + say + will + would + can + if + their + go + what + there + all + get + her + make + who + as + out + up + see + know + time + take + them + some + could + so + him + year + into + its + then + think + my + come + than + more + about + now + last + your + me + no + other + give + just + should + these + people + also + well + any + only + new + very + when + may + way + look + like + use + her + such + how + because + when + as + good + find + man + our + want + day + between + even + there + many + those + one + after + down + yeah + so + thing + tell + through + back + still + must + child + here + over + too + put + own + on + no + work + become + more + old + government + mean + part + leave + life + great + where + case + woman + over + seem + same + us + work + need + feel + system + each + might + may + much + ask + group + number + yes + however + another + again + world + area + show + course + company + shall + under + problem + against + never + all + most + service + try + call + hand + party + high + about + something + school + in + small + place + before + why + while + away + keep + point + house + different + country + really + provide + week + hold + large + member + off + always + next + follow + without + turn + end + within + local + where + during + bring + most + word + begin + although + example + next + family + rather + fact + like + social + write + state + percent + quite + both + start + run + long + right + set + help + every + home + month + side + night + important + eye + head + information + question + business + play + power + money + change + move + interest + order + book + often + development + young + national + pay + hear + room + whether + water + form + car + other + yet + perhaps + meet + level + until + though + policy + include + believe + council + already + possible + nothing + line + allow + need + effect + big + use + lead + stand + idea + study + lot + live + job + since + name + result + body + happen + friend + right + least + right + almost + much + carry + authority + long + early + view + himself + public + together + talk + report + after + only + before + bit + face + sit + market + appear + continue + able + political + later + hour + rate + law + door + court + office + let + war + produce + reason + less + minister + subject + person + term + particular + full + involve + sort + require + suggest + far + towards + anything + period + consider + read + change + society + process + mother + offer + late + voice + both + once + police + kind + lose + add + probably + expect + ever + available + no + price + little + action + issue + far + remember + position + low + cost + little + matter + community + remain + figure + type + research + actually + education + fall + speak + few + today + enough + open + bad + buy + programme + minute + moment + girl + age + centre + stop + control + value + send + health + decide + main + win + understand + decision + develop + class + industry + receive + back + several + return + build + spend + force + condition + itself + paper + themselves + off + major + describe + agree + economic + increase + upon + learn + general + century + therefore + father + section + patient + around + activity + road + table + including + church + reach + real + lie + mind + likely + among + team + experience + death + soon + act + sense + staff + certain + student + half + around + language + walk + die + special + difficult + international + particularly + department + management + morning + draw + hope + across + plan + product + city + early + committee + ground + letter + create + evidence + foot + clear + boy + game + food + role + practice + bank + else + support + sell + event + building + range + behind + sure + report + pass + black + stage + meeting + sometimes + thus + accept + town + art + further + club + cause + arm + history + parent + land + trade + watch + white + situation + whose + ago + teacher + record + manager + relation + common + strong + whole + field + free + break + yesterday + support + window + account + explain + stay + few + wait + usually + difference + material + air + wife + cover + apply + project + raise + sale + relationship + indeed + light + claim + form + base + care + someone + everything + certainly + rule + home + cut + grow + similar + story + quality + tax + worker + nature + structure + data + necessary + pound + method + unit + central + bed + union + movement + board + true + well + simply + contain + especially + open + short + personal + detail + model + bear + single + join + reduce + establish + herself + wall + face + easy + private + computer + former + hospital + chapter + scheme + theory + choose + wish + property + achieve + financial + poor + officer + up + charge + director + drive + deal + place + approach + chance + application + seek + cos + foreign + along + top + amount + son + operation + fail + human + opportunity + simple + leader + look + share + production + recent + firm + picture + source + security + serve + according + end + contract + wide + occur + agreement + better + kill + act + site + either + labour + plan + various + since + test + eat + loss + close + represent + love + colour + clearly + shop + benefit + animal + heart + election + purpose + standard + due + secretary + rise + date + hard + music + hair + prepare + factor + other + anyone + pattern + manage + piece + discuss + prove + front + evening + royal + tree + population + fine + plant + pressure + response + catch + street + pick + performance + knowledge + despite + design + page + enjoy + individual + suppose + rest + instead + wear + basis + size + environment + per + fire + series + success + natural + wrong + near + round + thought + list + argue + final + future + introduce + analysis + enter + space + arrive + ensure + demand + statement + to + attention + love + principle + pull + set + doctor + choice + refer + feature + couple + step + following + thank + machine + income + training + present + association + film + region + effort + player + everyone + present + award + village + control + organisation + whatever + news + nice + difficulty + modern + cell + close + current + legal + energy + finally + degree + mile + means + growth + whom + treatment + sound + above + task + provision + affect + please + red + happy + behaviour + concerned + point + function + identify + resource + defence + garden + floor + technology + style + feeling + science + relate + doubt + horse + force + answer + compare + suffer + individual + forward + announce + user + fund + character + risk + normal + myself + nor + dog + obtain + quickly + army + indicate + forget + station + glass + cup + previous + husband + recently + publish + serious + anyway + visit + capital + either + note + season + argument + listen + show + responsibility + significant + deal + prime + economy + element + finish + duty + fight + train + maintain + attempt + leg + investment + save + throughout + design + suddenly + brother + improve + avoid + wonder + tend + title + hotel + aspect + increase + help + industrial + express + summer + determine + generally + daughter + exist + used + share + baby + nearly + smile + sorry + sea + skill + claim + treat + remove + concern + university + labour + left + dead + discussion + specific + customer + box + outside + state + conference + whole + total + profit + division + throw + procedure + fill + king + assume + image + oil + obviously + unless + appropriate + circumstance + military + proposal + mention + client + sector + direction + admit + though + replace + basic + hard + instance + sign + original + successful + okay + reflect + aware + measure + attitude + yourself + disease + exactly + above + commission + intend + beyond + seat + president + encourage + addition + goal + round + miss + popular + affair + technique + respect + drop + professional + less + once + item + fly + reveal + version + maybe + ability + operate + good + campaign + heavy + advice + institution + top + discover + surface + library + pupil + record + refuse + prevent + advantage + dark + teach + memory + culture + blood + cost + majority + answer + variety + press + depend + bill + competition + ready + general + access + hit + stone + useful + extent + employment + regard + apart + present + appeal + text + parliament + cause + terms + bar + attack + effective + mouth + down + result + fish + future + visit + little + easily + attempt + enable + trouble + traditional + payment + best + post + county + lady + holiday + realise + importance + chair + facility + complete + article + object + context + survey + notice + complete + turn + direct + immediately + collection + reference + card + interesting + considerable + television + extend + communication + agency + physical + except + check + sun + species + possibility + official + chairman + speaker + second + career + laugh + weight + sound + responsible + base + document + solution + return + medical + hot + recognise + talk + budget + river + fit + organization + existing + start + push + tomorrow + requirement + cold + edge + opposition + opinion + drug + quarter + option + sign + worth + call + define + stock + influence + occasion + eventually + software + highly + exchange + lack + shake + study + concept + blue + star + radio + no + arrangement + examine + bird + green + band + sex + finger + past + independent + equipment + north + mind + move + message + fear + afternoon + drink + fully + race + gain + strategy + extra + scene + slightly + kitchen + speech + arise + network + tea + peace + failure + employee + ahead + scale + hardly + attend + shoulder + otherwise + railway + directly + supply + expression + owner + associate + corner + past + match + sport + status + beautiful + offer + marriage + hang + civil + perform + sentence + crime + ball + marry + wind + truth + protect + safety + partner + completely + copy + balance + sister + reader + below + trial + rock + damage + adopt + newspaper + meaning + light + essential + obvious + nation + confirm + south + length + branch + deep + none + planning + trust + working + pain + studio + positive + spirit + college + accident + star + hope + mark + works + league + clear + imagine + through + cash + normally + play + strength + train + travel + target + very + pair + male + gas + issue + contribution + complex + supply + beat + artist + agent + presence + along + environmental + strike + contact + protection + beginning + demand + media + relevant + employ + shoot + executive + slowly + relatively + aid + huge + late + speed + review + test + order + route + consequence + telephone + release + proportion + primary + consideration + reform + driver + annual + nuclear + latter + practical + commercial + rich + emerge + apparently + ring + distance + exercise + key + close + skin + island + separate + aim + danger + credit + usual + link + candidate + track + safe + interested + assessment + path + merely + plus + district + regular + reaction + impact + collect + debate + lay + rise + belief + conclusion + shape + vote + aim + politics + reply + press + approach + file + western + earth + public + survive + estate + boat + prison + additional + settle + largely + wine + observe + limit + deny + for + straight + somebody + writer + weekend + clothes + active + sight + video + reality + hall + nevertheless + regional + vehicle + worry + powerful + possibly + cross + colleague + charge + lead + farm + respond + employer + carefully + understanding + connection + comment + grant + concentrate + ignore + phone + hole + insurance + content + confidence + sample + transport + objective + alone + flower + injury + lift + stick + front + mainly + battle + generation + currently + winter + inside + impossible + somewhere + arrange + will + sleep + progress + volume + ship + legislation + commitment + enough + conflict + bag + fresh + entry + smile + fair + promise + introduction + senior + manner + background + key + touch + vary + sexual + ordinary + cabinet + painting + entirely + engine + previously + administration + tonight + adult + prefer + author + actual + song + investigation + debt + visitor + forest + repeat + wood + contrast + extremely + wage + domestic + commit + threat + bus + warm + sir + regulation + drink + relief + internal + strange + excellent + run + fairly + technical + tradition + measure + insist + his + farmer + until + traffic + dinner + consumer + meal + warn + living + package + half + increasingly + description + soft + stuff + award + existence + improvement + coffee + appearance + standard + attack + sheet + category + distribution + equally + session + cultural + loan + bind + museum + conversation + threaten + link + launch + proper + victim + audience + famous + master + lip + religious + joint + cry + potential + broad + exhibition + experience + judge + formal + housing + past + concern + freedom + gentleman + attract + explanation + appoint + note + chief + total + lovely + official + date + demonstrate + construction + middle + yard + unable + acquire + surely + crisis + propos + west + impose + market + care + god + favour + before + name + equal + capacity + flat + selection + alone + football + victory + factory + rural + twice + sing + whereas + own + head + examination + deliver + nobody + substantial + invite + intention + egg + reasonable + onto + retain + aircraft + decade + cheap + quiet + bright + contribute + row + search + limit + definition + unemployment + spread + mark + flight + account + output + last + tour + address + immediate + reduction + interview + assess + promote + everybody + suitable + ought + growing + nod + reject + while + high + dream + vote + divide + declare + handle + detailed + challenge + notice + rain + destroy + mountain + concentration + limited + finance + pension + influence + afraid + murder + neck + weapon + hide + offence + absence + error + representative + enterprise + criticism + average + quick + sufficient + appointment + match + transfer + acid + spring + birth + ear + recognize + recommend + module + instruction + democratic + park + weather + bottle + address + bedroom + kid + pleasure + realize + assembly + expensive + select + teaching + desire + whilst + contact + implication + combine + temperature + wave + magazine + totally + mental + used + store + scientific + frequently + thanks + beside + settlement + absolutely + critical + recognition + touch + consist + below + silence + expenditure + institute + dress + dangerous + familiar + asset + belong + educational + sum + publication + partly + block + seriously + youth + tape + elsewhere + cover + fee + program + treaty + necessarily + unlikely + properly + guest + code + hill + screen + household + sequence + correct + female + phase + crowd + welcome + metal + human + widely + undertake + cut + sky + brain + expert + experiment + tiny + perfect + disappear + initiative + assumption + photograph + ministry + congress + transfer + reading + scientist + fast + fast + closely + thin + solicitor + secure + plate + pool + gold + emphasis + recall + shout + generate + location + display + heat + gun + shut + journey + imply + violence + dry + historical + step + curriculum + noise + lunch + fear + succeed + fall + bottom + initial + theme + characteristic + pretty + empty + display + combination + interpretation + rely + escape + score + justice + upper + tooth + organise + cat + tool + spot + bridge + double + direct + conclude + relative + soldier + climb + breath + afford + urban + nurse + narrow + liberal + coal + priority + wild + revenue + membership + grant + approve + tall + apparent + faith + under + fix + slow + troop + motion + leading + component + bloody + literature + conservative + variation + remind + inform + alternative + neither + outside + mass + busy + chemical + careful + investigate + roll + instrument + guide + criterion + pocket + suggestion + aye + entitle + tone + attractive + wing + surprise + male + ring + pub + fruit + passage + illustrate + pay + ride + foundation + restaurant + vital + alternative + burn + map + united + device + jump + estimate + conduct + derive + comment + east + advise + advance + motor + satisfy + hell + winner + effectively + mistake + incident + focus + exercise + representation + release + leaf + border + wash + prospect + blow + trip + observation + gather + ancient + brief + gate + elderly + persuade + overall + rare + index + hand + circle + creation + drawing + anybody + flow + matter + external + capable + recover + shot + request + impression + neighbour + theatre + beneath + hurt + mechanism + potential + lean + defendant + atmosphere + slip + chain + accompany + wonderful + earn + enemy + desk + engineering + panel + distinction + deputy + discipline + strike + married + plenty + establishment + fashion + roof + milk + entire + tear + secondary + finding + welfare + increased + attach + typical + meanwhile + leadership + walk + negotiation + clean + religion + count + grey + hence + alright + first + fuel + mine + appeal + servant + liability + constant + hate + shoe + expense + vast + soil + writing + nose + origin + lord + rest + drive + ticket + editor + switch + provided + northern + significance + channel + convention + damage + funny + bone + severe + search + iron + vision + via + somewhat + inside + trend + revolution + terrible + knee + dress + unfortunately + steal + criminal + signal + notion + comparison + academic + outcome + lawyer + strongly + surround + explore + achievement + odd + expectation + corporate + prisoner + question + rapidly + deep + southern + amongst + withdraw + afterwards + paint + judge + citizen + permanent + weak + separate + ourselves + plastic + connect + fundamental + plane + height + opening + lesson + similarly + shock + rail + tenant + owe + originally + middle + somehow + minor + negative + knock + root + pursue + inner + crucial + occupy + that + independence + column + proceeding + female + beauty + perfectly + struggle + gap + house + database + stretch + stress + passenger + boundary + easy + view + manufacturer + sharp + formation + queen + waste + virtually + expand + contemporary + politician + back + territory + championship + exception + thick + inquiry + topic + resident + transaction + parish + supporter + massive + light + unique + challenge + inflation + assistance + list + identity + suit + parliamentary + unknown + preparation + elect + badly + moreover + tie + cancer + champion + exclude + review + licence + breakfast + minority + appreciate + fan + chief + accommodation + subsequent + democracy + brown + taste + crown + permit + buyer + gift + resolution + angry + metre + wheel + clause + break + tank + benefit + engage + alive + complaint + inch + firm + abandon + blame + clean + quote + yours + quantity + rule + guilty + prior + round + eastern + coat + involvement + tension + diet + enormous + score + rarely + prize + remaining + significantly + glance + dominate + trust + naturally + interpret + land + frame + extension + mix + spokesman + friendly + acknowledge + register + regime + fault + mine + dispute + grass + quietly + decline + dismiss + delivery + complain + conservative + shift + port + beach + string + depth + unusual + travel + pilot + obligation + gene + yellow + republic + shadow + dear + analyse + anywhere + average + phrase + long + crew + lucky + restore + convince + coast + engineer + heavily + extensive + glad + charity + oppose + defend + alter + warning + arrest + framework + approval + bother + novel + accuse + surprised + currency + restrict + possess + moral + protein + distinguish + gently + reckon + incorporate + proceed + assist + sure + stress + justify + behalf + councillor + setting + command + maintenance + stair + poem + chest + like + secret + restriction + efficient + suspect + hat + tough + firmly + willing + healthy + focus + construct + occasionally + mode + saving + comfortable + camp + trade + export + wake + partnership + daily + abroad + profession + load + countryside + boot + mostly + sudden + implement + reputation + print + calculate + keen + guess + recommendation + autumn + conventional + cope + constitute + poll + voluntary + valuable + recovery + cast + premise + resolve + regularly + solve + plaintiff + critic + agriculture + ice + constitution + communist + layer + recession + slight + dramatic + golden + temporary + suit + shortly + initially + arrival + protest + resistance + silent + presentation + soul + self + judgment + feed + muscle + shareholder + opposite + pollution + wealth + video + kingdom + bread + perspective + camera + prince + illness + cake + meat + submit + ideal + relax + penalty + purchase + tired + beer + specify + short + monitor + electricity + specifically + bond + statutory + laboratory + federal + captain + deeply + pour + boss + creature + urge + locate + being + struggle + lifespan + flat + valley + like + guard + emergency + dark + bomb + dollar + efficiency + mood + convert + possession + marketing + please + habit + subsequently + round + purchase + sort + outside + gradually + expansion + competitive + co + acceptable + angle + cook + net + sensitive + ratio + kiss + amount + sleep + finance + essentially + fund + preserve + wedding + personality + bishop + dependent + landscape + pure + mirror + lock + symptom + promotion + global + aside + tendency + conservation + reply + estimate + qualification + pack + governor + expected + invest + cycle + alright + philosophy + gallery + sad + intervention + emotional + advertising + regard + dance + cigarette + predict + adequate + variable + net + retire + sugar + pale + frequency + guy + feature + furniture + administrative + wooden + input + phenomenon + surprising + jacket + actor + kick + producer + hearing + chip + equation + certificate + hello + remarkable + alliance + smoke + awareness + throat + discovery + festival + dance + promise + rose + principal + brilliant + proposed + coach + absolute + drama + recording + precisely + bath + celebrate + substance + swing + for + rapid + rough + investor + fire + rank + compete + sweet + decline + rent + dealer + bend + solid + cloud + across + level + enquiry + fight + abuse + golf + guitar + electronic + cottage + scope + pause + mixture + emotion + comprehensive + shirt + allowance + retirement + breach + infection + resist + qualify + paragraph + sick + near + researcher + consent + written + literary + ill + wet + lake + entrance + peak + successfully + sand + breathe + cold + cheek + platform + interaction + need + watch + borrow + birthday + knife + extreme + core + peasant + armed + permission + supreme + overcome + greatly + visual + lad + genuine + personnel + judgement + exciting + stream + perception + guarantee + disaster + darkness + bid + sake + organize + tourist + policeman + castle + figure + race + demonstration + anger + briefly + presumably + clock + hero + expose + custom + maximum + wish + earning + priest + resign + store + widespread + comprise + chamber + acquisition + involved + confident + circuit + radical + detect + stupid + grand + consumption + hold + zone + mean + altogether + rush + numerous + sink + everywhere + classical + respectively + distinct + mad + honour + statistics + false + square + differ + disk + truly + survival + proud + tower + deposit + pace + compensation + adviser + consultant + drag + advanced + landlord + whenever + delay + green + car + holder + secret + edition + occupation + agricultural + intelligence + empire + definitely + negotiate + host + relative + mass + helpful + fellow + sweep + poet + journalist + defeat + unlike + primarily + tight + indication + dry + cricket + whisper + routine + print + anxiety + witness + concerning + mill + gentle + curtain + mission + supplier + basically + assure + poverty + snow + prayer + pipe + deserve + shift + split + near + consistent + carpet + ownership + joke + fewer + workshop + salt + aged + symbol + slide + cross + anxious + tale + preference + inevitably + mere + behave + gain + nervous + guide + remark + pleased + province + steel + practise + flow + holy + dose + alcohol + guidance + constantly + climate + enhance + reasonably + waste + smooth + dominant + conscious + formula + tail + ha + electric + sheep + medicine + strategic + disabled + smell + operator + mount + advance + remote + measurement + favour + neither + architecture + worth + tie + barrier + practitioner + outstanding + enthusiasm + theoretical + implementation + worried + pitch + drop + phone + shape + clinical + lane + apple + catalogue + tip + publisher + opponent + live + burden + tackle + historian + bury + stomach + percentage + evaluation + outline + talent + lend + silver + pack + fun + democrat + fortune + storage + professional + reserve + interval + dimension + honest + awful + manufacture + confusion + pink + impressive + satisfaction + visible + vessel + stand + curve + pot + replacement + accurate + mortgage + salary + impress + constitutional + emphasise + developing + proof + furthermore + dish + interview + considerably + distant + lower + favourite + tear + fixed + by + luck + count + precise + determination + bite + dear + consultation + range + residential + conduct + capture + ultimately + cheque + economics + sustain + secondly + silly + merchant + lecture + musical + leisure + check + cheese + lift + participate + fabric + distribute + lover + childhood + cool + ban + supposed + mouse + strain + specialist + consult + minimum + approximately + participant + monetary + confuse + dare + smoke + movie + seed + cease + open + journal + shopping + equivalent + palace + exceed + isolated + poetry + perceive + lack + strengthen + snap + readily + spite + conviction + corridor + behind + ward + profile + fat + comfort + bathroom + shell + reward + deliberately + automatically + vegetable + imagination + junior + unemployed + mystery + pose + violent + march + found + dig + dirty + straight + psychological + grab + pleasant + surgery + inevitable + transform + bell + announcement + draft + unity + airport + upset + pretend + plant + till + known + admission + tissue + magistrate + joy + free + pretty + operating + headquarters + grateful + classroom + turnover + project + shrug + sensible + limitation + specialist + newly + tongue + refugee + delay + dream + composition + alongside + ceiling + highlight + stick + favourite + tap + universe + request + label + confine + scream + rid + acceptance + detective + sail + adjust + designer + running + summit + participation + weakness + block + so + adapt + absorb + encounter + defeat + excitement + brick + blind + wire + crop + square + transition + thereby + protest + roll + stop + assistant + deaf + constituency + continuous + concert + breast + extraordinary + squad + wonder + cream + tennis + personally + communicate + pride + bowl + file + expertise + govern + leather + observer + margin + uncertainty + reinforce + ideal + injure + holding + universal + evident + dust + overseas + desperate + swim + occasional + trouser + surprisingly + register + album + guideline + disturb + amendment + architect + objection + chart + cattle + doubt + react + consciousness + right + purely + tin + tube + fulfil + commonly + sufficiently + coin + frighten + grammar + diary + flesh + summary + infant + stir + storm + mail + rugby + virtue + specimen + psychology + paint + constraint + trace + privilege + completion + progress + hers + grade + exploit + import + potato + repair + passion + seize + low + underlying + heaven + nerve + park + collapse + win + printer + coalition + button + pray + ultimate + venture + timber + companion + horror + gesture + moon + remark + clever + van + consequently + raw + glance + broken + jury + gaze + burst + charter + feminist + discourse + reflection + carbon + sophisticated + ban + taxation + prosecution + softly + asleep + aids + publicity + departure + welcome + sharply + reception + cousin + relieve + linguistic + vat + forward + blue + multiple + pass + outer + vulnerable + patient + evolution + allocate + creative + potentially + just + out + judicial + risk + ideology + smell + agenda + transport + illegal + chicken + plain + innovation + opera + lock + grin + shelf + pole + punishment + strict + wave + inside + carriage + fit + conversion + hurry + essay + integration + resignation + treasury + traveller + chocolate + assault + schedule + undoubtedly + twin + format + murder + sigh + seller + lease + bitter + double + ally + stake + processing + informal + flexible + cap + stable + till + sympathy + tunnel + pen + instal + suspend + blow + wander + notably + disappoint + wipe + folk + attraction + disc + inspire + machinery + undergo + nowhere + inspector + wise + balance + purchaser + resort + pop + organ + ease + friendship + deficit + dear + convey + reserve + planet + frequent + loose + intense + retail + wind + lost + grain + particle + destruction + witness + pit + registration + conception + steady + rival + steam + back + chancellor + crash + belt + logic + premium + confront + precede + experimental + alarm + rational + incentive + roughly + bench + wrap + regarding + inadequate + ambition + since + fate + vendor + stranger + spiritual + increasing + anticipate + logical + fibre + attribute + sense + black + petrol + maker + generous + allocation + depression + declaration + spot + modest + bottom + dividend + devote + condemn + integrate + pile + identification + acute + barely + providing + directive + bet + modify + bare + swear + final + accordingly + valid + wherever + mortality + medium + silk + funeral + depending + cow + correspond + cite + classic + inspection + calculation + rubbish + minimum + hypothesis + youngster + slope + patch + invitation + ethnic + federation + duke + wholly + closure + dictionary + withdrawal + automatic + liable + cry + slow + borough + well + suspicion + portrait + local + jew + fragment + revolutionary + evaluate + competitor + sole + reliable + weigh + medieval + clinic + shine + knit + complexity + remedy + fence + bike + freeze + eliminate + interior + intellectual + established + voter + garage + era + pregnant + plot + greet + electrical + lie + disorder + formally + excuse + socialist + cancel + harm + excess + exact + oblige + accountant + mutual + fat + volunteer + laughter + trick + load + disposal + taxi + murmur + tonne + spell + clerk + curious + satisfactory + identical + applicant + removal + processor + cotton + reverse + hesitate + professor + admire + namely + electoral + delight + urgent + prompt + mate + exposure + server + distinctive + marginal + structural + rope + miner + entertainment + acre + pig + encouraging + guarantee + gear + anniversary + past + ceremony + rub + monopoly + left + flee + yield + discount + above + uncle + audit + advertisement + explosion + contrary + tribunal + swallow + typically + fun + rat + cloth + cable + interrupt + crash + flame + controversy + rabbit + everyday + allegation + strip + stability + tide + illustration + insect + correspondent + devise + determined + brush + adjustment + controversial + organic + escape + thoroughly + interface + historic + collapse + temple + shade + craft + nursery + piano + desirable + assurance + jurisdiction + advertise + bay + specification + disability + presidential + arrest + unexpected + switch + penny + respect + celebration + gross + aid + superb + process + innocent + leap + colony + wound + hardware + satellite + float + bible + statistical + marked + hire + cathedral + motive + correct + gastric + raid + comply + accommodate + mutter + induce + trap + invasion + humour + bulk + traditionally + commission + upstairs + translate + rhythm + emission + collective + transformation + battery + stimulus + naked + white + menu + toilet + butter + surprise + needle + effectiveness + accordance + molecule + fiction + learning + statute + reluctant + overlook + junction + necessity + nearby + experienced + lorry + exclusive + graphics + stimulate + warmth + therapy + convenient + cinema + domain + tournament + doctrine + sheer + proposition + grip + widow + discrimination + bloody + ruling + fit + nonetheless + myth + episode + drift + assert + terrace + uncertain + twist + insight + undermine + tragedy + enforce + criticise + march + leaflet + fellow + object + pond + adventure + diplomatic + mixed + rebel + equity + literally + magnificent + loyalty + tremendous + airline + shore + restoration + physically + render + institutional + emphasize + mess + commander + straightforward + singer + squeeze + full + breed + successor + triumph + heading + mathematics + laugh + clue + still + ease + specially + biological + forgive + trustee + photo + fraction + chase + whereby + mud + pensioner + functional + copy + strictly + desperately + await + coverage + wildlife + indicator + lightly + hierarchy + evolve + mechanical + expert + creditor + capitalist + essence + compose + mentally + gaze + seminar + target + label + fig + continent + chap + flexibility + verse + minute + whisky + equivalent + recruit + echo + unfair + launch + cupboard + bush + shortage + prominent + merger + command + subtle + capital + gang + fish + unhappy + lifetime + elite + refusal + finish + aggressive + superior + landing + exchange + debate + educate + separation + productivity + initiate + probability + virus + reporter + fool + pop + capitalism + painful + correctly + complex + rumour + imperial + justification + availability + spectacular + remain + ocean + cliff + sociology + sadly + missile + situate + artificial + apartment + provoke + oral + maximum + angel + spare + shame + intelligent + discretion + businessman + explicit + book + uniform + push + counter + subject + objective + hungry + clothing + ride + romantic + attendance + part + trace + backing + sensation + carrier + interest + classification + classic + beg + appendix + doorway + density + working + legislative + hint + shower + current + succession + nasty + duration + desert + receipt + native + chapel + amazing + hopefully + fleet + comparable + oxygen + installation + developer + disadvantage + recipe + crystal + modification + schedule + midnight + successive + formerly + loud + value + physics + truck + stroke + kiss + envelope + speculation + canal + unionist + directory + receiver + isolation + fade + chemistry + unnecessary + hit + defender + stance + sin + realistic + socialist + subsidy + content + toy + darling + decent + liberty + forever + skirt + coordinate + tactic + influential + import + accent + compound + bastard + ingredient + dull + cater + scholar + faint + ghost + sculpture + ridiculous + diagnosis + delegate + neat + kit + lion + dialogue + repair + tray + fantasy + leave + export + forth + lamp + allege + pavement + brand + constable + compromise + flag + filter + reign + execute + pity + merit + diagram + wool + organism + elegant + red + undertaking + lesser + reach + marvellous + improved + locally + entity + rape + secure + descend + backwards + peer + excuse + genetic + fold + portfolio + consensus + thesis + shop + nest + frown + builder + administer + tip + lung + delegation + outside + heating + like + instinct + teenager + lonely + residence + radiation + extract + concession + autonomy + norm + musician + graduate + glory + bear + persist + rescue + equip + partial + officially + capability + worry + liberation + hunt + daily + heel + contract + update + assign + spring + single + commons + weekly + stretch + pregnancy + happily + spectrum + interfere + suicide + panic + invent + intensive + damp + simultaneously + giant + casual + sphere + precious + sword + envisage + bean + time + crazy + changing + primary + concede + besides + unite + severely + separately + instruct + insert + go + exhibit + brave + tutor + tune + debut + continued + bid + incidence + downstairs + cafe + regret + killer + delicate + subsidiary + gender + entertain + cling + vertical + fetch + strip + plead + duck + breed + assistant + pint + abolish + translation + princess + line + excessive + digital + steep + jet + hey + grave + exceptional + boost + random + correlation + outline + intervene + packet + motivation + safely + harsh + spell + spread + draw + concrete + complicated + alleged + redundancy + progressive + intensity + crack + fly + fancy + alternatively + waiting + scandal + resemble + parameter + fierce + tropical + colour + ours + engagement + contest + edit + courage + hip + delighted + sponsor + carer + crack + substantially + occupational + trainer + remainder + related + inherit + resume + assignment + conceal + disclose + exclusively + working + mild + chronic + splendid + function + rider + clay + firstly + conceive + politically + terminal + accuracy + coup + ambulance + living + offender + similarity + orchestra + brush + systematic + striker + guard + casualty + steadily + painter + opt + handsome + banking + sensitivity + navy + fascinating + disappointment + auditor + hostility + spending + scarcely + compulsory + photographer + ok + neighbourhood + ideological + wide + pardon + double + criticize + supervision + guilt + deck + payable + execution + suite + elected + solely + moral + collector + questionnaire + flavour + couple + faculty + tour + basket + mention + kick + horizon + drain + happiness + fighter + estimated + copper + legend + relevance + decorate + continental + ship + operational + incur + parallel + divorce + opposed + equilibrium + trader + ton + can + juice + forum + spin + research + hostile + consistently + technological + nightmare + medal + diamond + speed + peaceful + accounting + scatter + monster + horrible + nonsense + chaos + accessible + humanity + frustration + chin + bureau + advocate + polytechnic + inhabitant + evil + slave + reservation + slam + handle + provincial + fishing + facilitate + yield + elbow + bye + warm + sleeve + exploration + creep + adjacent + theft + round + grace + predecessor + supermarket + smart + sergeant + regulate + clash + assemble + arrow + nowadays + giant + waiting + tap + shit + sandwich + vanish + commerce + pursuit + post + will + waste + collar + socialism + skill + rice + exclusion + upwards + transmission + instantly + forthcoming + appointed + geographical + fist + abstract + embrace + dynamic + drawer + dismissal + magic + endless + definite + broadly + affection + dawn + principal + bloke + organiser + trap + communist + competence + complicate + neutral + fortunately + commonwealth + breakdown + combined + candle + venue + supper + analyst + vague + publicly + marine + fair + pause + notable + freely + counterpart + lively + script + sue + legitimate + geography + reproduce + moving + lamb + gay + contemplate + terror + stable + founder + utility + signal + shelter + poster + hitherto + mature + cooking + head + wealthy + fucking + confess + age + miracle + magic + jaw + pan + coloured + tent + telephone + reduced + tumour + super + funding + dump + stitch + shared + ladder + keeper + endorse + invariably + smash + shield + heat + surgeon + centre + orange + explode + comedy + classify + artistic + ruler + biscuit + workstation + prey + manual + cure + overall + tighten + tax + pope + manufacturing + adult + rush + blanket + republican + referendum + palm + nearby + mix + devil + adoption + workforce + segment + regardless + contractor + portion + differently + deposit + cook + prediction + oven + matrix + liver + fraud + beam + signature + limb + verdict + dramatically + container + aunt + dock + submission + arm + odd + certainty + boring + electron + drum + wisdom + antibody + unlike + terrorist + post + circulation + alteration + fluid + ambitious + socially + riot + petition + fox + recruitment + well + top + service + flood + taste + memorial + helicopter + correspondence + ye + beef + overall + lighting + harbour + empirical + shallow + seal + decrease + constituent + exam + toe + reward + thrust + bureaucracy + wrist + nut + plain + magnetic + evil + widen + hazard + dispose + dealing + absent + reassure + model + inn + initial + suspension + respondent + over + naval + monthly + log + advisory + fitness + blank + indirect + tile + rally + economist + vein + strand + disturbance + stuff + seldom + coming + cab + grandfather + flash + destination + actively + regiment + closed + boom + handful + remarkably + encouragement + awkward + required + flood + defect + surplus + champagne + liquid + shed + welcome + rejection + discipline + halt + electronics + administrator + sentence + ill + contradiction + nail + senior + lacking + colonial + primitive + whoever + lap + commodity + planned + intellectual + imprisonment + coincide + sympathetic + atom + tempt + sanction + praise + favourable + dissolve + tightly + surrounding + soup + encounter + abortion + grasp + custody + composer + charm + short + metropolitan + waist + equality + tribute + bearing + auction + standing + manufacture + horn + barn + mayor + emperor + rescue + integrated + conscience + commence + grandmother + discharge + profound + takeover + nationalist + effect + dolphin + fortnight + elephant + seal + spoil + plea + forwards + breeze + prevention + mineral + runner + pin + integrity + thereafter + quid + owl + rigid + orange + draft + reportedly + hedge + formulate + associated + position + thief + tomato + exhaust + evidently + eagle + specified + resulting + blade + peculiar + killing + desktop + bowel + long + ugly + expedition + saint + variable + supplement + stamp + slide + faction + enthusiastic + enquire + brass + inequality + eager + bold + neglect + saying + ridge + earl + yacht + suck + missing + extended + valuation + delight + beat + worship + fossil + diminish + taxpayer + corruption + accurately + honour + depict + pencil + drown + stem + lump + applicable + rate + mobility + immense + goodness + price + preliminary + graph + referee + calm + onwards + omit + genuinely + excite + dreadful + cave + revelation + grief + erect + tuck + meantime + barrel + lawn + hut + swing + subject + ruin + slice + transmit + thigh + practically + dedicate + mistake + corresponding + albeit + sound + nurse + discharge + comparative + cluster + propose + obstacle + motorway + heritage + counselling + breeding + characteristic + bucket + migration + campaign + ritual + originate + hunting + crude + protocol + prejudice + inspiration + dioxide + chemical + uncomfortable + worthy + inspect + summon + parallel + outlet + okay + collaboration + booking + salad + productive + charming + polish + oak + access + tourism + independently + cruel + diversity + accused + supplement + fucking + forecast + amend + soap + ruling + interference + executive + mining + minimal + clarify + strain + novel + try + coastal + rising + quota + minus + kilometre + characterise + suspicious + pet + beneficial + fling + deprive + covenant + bias + trophy + verb + honestly + extract + straw + stem + eyebrow + noble + mask + lecturer + girlfriend + forehead + timetable + symbolic + farming + lid + librarian + injection + sexuality + irrelevant + bonus + abuse + thumb + survey + ankle + psychologist + occurrence + profitable + deliberate + bow + tribe + rightly + representative + code + validity + marble + bow + plunge + maturity + hidden + contrast + tobacco + middle + grip + clergy + trading + passive + decoration + racial + well + embarrassment + sauce + fatal + banker + compensate + make + seat + popularity + interior + eligible + continuity + bunch + hook + wicket + pronounce + ballet + heir + positively + insufficient + substitute + mysterious + dancer + trail + caution + donation + added + weaken + tyre + sufferer + managerial + elaborate + restraint + renew + gardener + dilemma + configuration + rear + embark + misery + importantly + continually + appreciation + radical + diverse + revive + trip + lounge + dwelling + parental + loyal + privatisation + outsider + forbid + yep + prospective + manuscript + inherent + deem + telecommunication + intermediate + worthwhile + calendar + basin + utterly + rebuild + pulse + suppress + predator + width + stiff + spine + betray + punish + stall + lifestyle + compile + arouse + partially + headline + divine + unpleasant + sacred + useless + cool + tremble + statue + obey + drunk + tender + molecular + circulate + exploitation + explicitly + utterance + linear + chat + revision + distress + spill + steward + knight + sum + semantic + selective + learner + dignity + senate + grid + fiscal + activate + rival + fortunate + jeans + select + fitting + commentator + weep + handicap + crush + towel + stay + skilled + repeatedly + defensive + calm + temporarily + rain + pin + villa + rod + frontier + enforcement + protective + philosophical + lordship + disagree + boyfriend + activist + viewer + slim + this + textile + mist + harmony + deed + merge + invention + commissioner + caravan + bolt + ending + publishing + gut + stamp + map + loud + stroke + shock + rug + picture + slip + praise + fine + monument + material + garment + toward + realm + melt + reproduction + reactor + furious + distinguished + characterize + alike + pump + probe + feedback + aspiration + suspect + solar + fare + carve + qualified + membrane + dependence + convict + bacteria + trading + ambassador + wound + drug + conjunction + cabin + trail + shaft + treasure + inappropriate + half + attribute + liquid + embassy + terribly + exemption + array + tablet + sack + erosion + bull + warehouse + unfortunate + promoter + compel + motivate + burning + vitamin + sail + lemon + foreigner + powder + persistent + bat + ancestor + predominantly + mathematical + compliance + arch + woodland + serum + overnight + doubtful + doing + coach + binding + surrounding + peer + ozone + mid + invisible + depart + brigade + manipulate + consume + temptation + intact + glove + aggression + emergence + stag + coffin + beautifully + clutch + wit + underline + trainee + scrutiny + neatly + follower + sterling + tariff + bee + relaxation + negligence + sunlight + penetrate + knot + temper + skull + openly + grind + whale + throne + supervise + sickness + package + intake + within + inland + beast + rear + morality + competent + sink + uniform + reminder + permanently + optimistic + bargain + seemingly + respective + horizontal + decisive + bless + bile + spatial + bullet + respectable + overseas + convincing + unacceptable + confrontation + swiftly + paid + joke + instant + illusion + cheer + congregation + worldwide + winning + wake + toss + medium + jewellery + fond + alarm + guerrilla + dive + desire + cooperation + thread + prescribe + calcium + redundant + marker + chemist + mammal + legacy + debtor + testament + tragic + silver + grin + spectacle + inheritance + heal + sovereignty + enzyme + host + neighbouring + corn + layout + dictate + rip + regain + probable + inclusion + booklet + bar + privately + laser + fame + bronze + mobile + metaphor + complication + narrow + old + chop + synthesis + diameter + bomb + silently + shed + fusion + trigger + printing + onion + dislike + embody + curl + sunshine + sponsorship + rage + loop + halt + cop + bang + toxic + thinking + orientation + likelihood + wee + up + polite + apology + exile + brow + miserable + outbreak + comparatively + pump + fuck + forecast + timing + headmaster + terrify + sigh + premier + joint + incredible + gravity + regulatory + cylinder + curiosity + resident + narrative + cognitive + lengthy + gothic + dip + adverse + accountability + hydrogen + gravel + willingness + inhibit + attain + specialise + steer + selected + like + confer + usage + portray + planner + manual + boast + unconscious + jail + fertility + documentation + wolf + patent + exit + corps + proclaim + multiply + brochure + screen + orthodox + locomotive + considering + unaware + syndrome + reform + confirmation + printed + curve + costly + underground + territorial + designate + comfort + plot + misleading + weave + scratch + echo + ideally + endure + verbal + stride + nursing + exert + compatible + causal + mosaic + manor + implicit + following + fashionable + valve + proceed + sofa + snatch + jazz + patron + provider + interim + intent + chosen + applied + shiver + pie + fury + abolition + soccer + corpse + accusation + kind + dead + nursing + contempt + prevail + murderer + liberal + gathering + adequately + subjective + disagreement + cleaner + boil + static + scent + civilian + monk + abruptly + keyboard + hammer + despair + controller + yell + entail + cheerful + reconstruction + patience + legally + habitat + queue + spectator + given + purple + outlook + genius + dual + canvas + grave + pepper + conform + cautious + dot + conspiracy + butterfly + sponsor + sincerely + rating + weird + teenage + salmon + recorder + postpone + maid + furnish + ethical + bicycle + sick + sack + renaissance + luxury + gasp + wardrobe + native + fringe + adaptation + quotation + hunger + enclose + disastrous + choir + overwhelming + glimpse + divorce + circular + locality + ferry + balcony + sailor + precision + desert + dancing + alert + surrender + archive + jump + philosopher + revival + presume + node + fantastic + herb + assertion + thorough + quit + grim + fair + broadcast + annoy + divert + accelerate + polymer + sweat + survivor + subscription + repayment + anonymous + summarise + punch + lodge + landowner + ignorance + discourage + bride + likewise + depressed + abbey + quarry + archbishop + sock + large + glare + descent + stumble + mistress + empty + prosperity + harm + formulation + atomic + agreed + wicked + threshold + lobby + repay + varying + track + crawl + tolerate + salvation + pudding + counter + propaganda + cage + broker + ashamed + scan + document + apparatus + theology + analogy + efficiently + bitterly + performer + individually + amid + squadron + sentiment + making + exotic + dominance + coherent + placement + flick + colourful + mercy + angrily + amuse + mainstream + appraisal + annually + torch + intimate + gold + arbitrary + venture + preservation + shy + disclosure + lace + inability + motif + listener + hunt + delicious + term + substitute + highway + haul + dragon + chair + accumulate + unchanged + sediment + sample + exclaim + fan + volunteer + root + parcel + psychiatric + delightful + confidential + calorie + flash + crowd + aggregate + scholarship + monitor + disciplinary + rock + hatred + pill + noisy + feather + lexical + staircase + autonomous + viewpoint + projection + offensive + controlled + flush + racism + flourish + resentment + pillow + courtesy + photography + monkey + glorious + evolutionary + gradual + bankruptcy + sacrifice + uphold + sketch + presidency + formidable + differentiate + continuing + cart + stadium + dense + catch + beyond + immigration + clarity + worm + slot + rifle + screw + harvest + foster + academic + impulse + guardian + ambiguity + triangle + terminate + retreat + pony + outdoor + deficiency + decree + apologise + yarn + staff + renewal + rebellion + incidentally + flour + developed + chorus + ballot + appetite + stain + notebook + loudly + homeless + census + bizarre + striking + greenhouse + part + burial + embarrassed + ash + actress + cassette + privacy + fridge + feed + excess + calf + associate + ruin + jointly + drill + photograph + devoted + indirectly + driving + memorandum + default + costume + variant + shatter + methodology + frame + allegedly + swell + investigator + imaginative + bored + bin + awake + recycle + group + enjoyment + contemporary + texture + donor + bacon + sunny + stool + prosecute + commentary + bass + theirs + sniff + repetition + eventual + credit + suburb + organisational + newcomer + romance + film + experiment + daylight + warrant + fur + parking + nuisance + civilian + foolish + bulb + balloon + vivid + surveyor + spontaneous + biology + injunction + appalling + amusement + aesthetic + vegetation + stab + rude + offset + thinking + mainframe + flock + amateur + academy + shilling + reluctance + velocity + spare + wartime + soak + rib + mighty + shocked + vocational + spit + gall + bowl + prescription + fever + axis + reservoir + magnitude + rape + cutting + bracket + agony + strive + strangely + pledge + recipient + moor + invade + dairy + chord + shrink + poison + pillar + washing + warrior + supervisor + outfit + innovative + dressing + dispute + jungle + brewery + adjective + straighten + restrain + monarchy + trunk + herd + deadline + tiger + supporting + moderate + kneel + ego + sexually + ministerial + bitch + wheat + stagger + snake + ribbon + mainland + fisherman + economically + unwilling + nationalism + knitting + irony + handling + desired + bomber + voltage + unusually + toast + feel + suffering + polish + technically + meaningful + aloud + waiter + tease + opposite + goat + conceptual + ant + inflict + bowler + roar + drain + wrong + galaxy + aluminium + receptor + preach + parade + opposite + critique + query + outset + integral + grammatical + testing + patrol + pad + unreasonable + sausage + criminal + constructive + worldwide + highlight + doll + frightened + biography + vocabulary + offend + accumulation + linen + fairy + disco + hint + versus + ray + pottery + immune + retreat + master + injured + holly + battle + solidarity + embarrassing + cargo + theorist + reluctantly + preferred + dash + total + reconcile + drill + credibility + copyright + beard + bang + vigorous + vaguely + punch + prevalence + uneasy + boost + scrap + ironically + fog + faithful + bounce + batch + smooth + sleeping + poorly + accord + vice + duly + blast + square + prohibit + brake + asylum + obscure + nun + heap + smoothly + rhetoric + privileged + liaison + jockey + concrete + allied + rob + indulge + except + distort + whatsoever + viable + nucleus + exaggerate + compact + nationality + direct + cast + altar + refuge + presently + mandatory + authorise + accomplish + startle + indigenous + worse + retailer + compound + admiration + absurd + coincidence + principally + passport + depot + soften + secretion + invoke + dirt + scared + mug + convenience + calm + optional + unsuccessful + consistency + umbrella + solo + hemisphere + extreme + brandy + belly + attachment + wash + uncover + treat + repeated + pine + offspring + communism + nominate + soar + geological + frog + donate + co + nicely + innocence + housewife + disguise + demolish + counsel + cord + semi + reasoning + litre + inclined + evoke + courtyard + arena + simplicity + inhibition + frozen + vacuum + immigrant + bet + revenge + jail + helmet + unclear + jerk + disruption + attainment + sip + program + lunchtime + cult + chat + accord + supposedly + offering + broadcast + secular + overwhelm + momentum + infinite + manipulation + inquest + decrease + cellar + counsellor + avenue + rubber + labourer + lab + damn + comfortably + tense + socket + par + thrust + scenario + frankly + slap + recreation + rank + spy + filter + clearance + blessing + embryo + varied + predictable + mutation + equal + can + burst + retrieve + elder + rehearsal + optical + hurry + conflict + combat + absorption + ion + wrong + heroin + bake + x + vector + stolen + sacrifice + robbery + probe + organizational + chalk + bourgeois + villager + morale + express + climb + notify + jam + bureaucratic + literacy + frustrate + freight + clearing + aviation + legislature + curiously + banana + deploy + passionate + monastery + kettle + enjoyable + diagnose + quantitative + distortion + monarch + kindly + glow + acquaintance + unexpectedly + handy + deprivation + attacker + assault + screening + retired + quick + portable + hostage + underneath + jealous + proportional + gown + chimney + bleak + seasonal + plasma + stunning + spray + referral + promptly + fluctuation + decorative + unrest + resent + plaster + chew + grouping + gospel + distributor + differentiation + blonde + aquarium + witch + renewed + jar + approved + advocate + worrying + minimise + footstep + delete + underneath + lone + level + exceptionally + drift + spider + hectare + colonel + swimming + realism + insider + hobby + computing + infrastructure + co + burn + cereal + fold + compromise + boxing + rear + lick + constrain + clerical + hire + contend + amateur + instrumental + terminal + electorate + congratulate + balanced + manufacturing + split + domination + blink + bleed + unlawful + precedent + notorious + indoor + upgrade + trench + therapist + illuminate + bargain + warranty + scar + consortium + anger + insure + extensively + appropriately + spoon + sideways + enhanced + disrupt + satisfied + precaution + kite + instant + gig + continuously + consolidate + fountain + graduate + gloom + bite + structure + noun + nomination + armchair + virtual + unprecedented + tumble + ski + architectural + violation + rocket + inject + departmental + row + luxury + fax + deer + climber + photographic + haunt + fiercely + dining + sodium + gossip + bundle + bend + recruit + hen + fragile + deteriorate + dependency + swift + scramble + overview + imprison + trolley + rotation + denial + boiler + amp + trivial + shout + overtake + make + hunter + guess + doubtless + syllable + obscure + mould + limestone + leak + beneficiary + veteran + surplus + manifestation + vicar + textbook + novelist + halfway + contractual + swap + guild + ulcer + slab + detector + detection + cough + whichever + spelling + lender + glow + raised + prolonged + voucher + t + linger + humble + honey + scream + postcard + managing + alien + trouble + reverse + odour + fundamentally + discount + blast + syntactic + scrape + residue + procession + pioneer + intercourse + deter + deadly + complement + restrictive + nitrogen + citizenship + pedestrian + detention + wagon + microphone + hastily + fixture + choke + wet + weed + programming + power + nationally + dozen + carrot + bulletin + wording + vicious + urgency + spoken + skeleton + motorist + interactive + compute + whip + urgently + telly + shrub + porter + ethics + banner + velvet + omission + hook + gallon + financially + superintendent + plug + continuation + reliance + justified + fool + detain + damaging + orbit + mains + discard + dine + compartment + revised + privatization + memorable + lately + distributed + disperse + blame + basement + slump + puzzle + monitoring + talented + nominal + mushroom + instructor + fork + board + want + disposition + cemetery + attempted + nephew + magical + ivory + hospitality + besides + astonishing + tract + proprietor + license + differential + affinity + talking + royalty + neglect + irrespective + whip + sticky + regret + incapable + franchise + dentist + contrary + profitability + enthusiast + crop + utter + pile + pier + dome + bubble + treasurer + stocking + sanctuary + ascertain + arc + quest + mole + marathon + feast + crouch + storm + hardship + entitlement + circular + walking + strap + sore + complementary + understandable + noticeable + mankind + majesty + course + pigeon + goalkeeper + ambiguous + walker + virgin + prestige + preoccupation + upset + municipal + groan + craftsman + anticipation + revise + knock + infect + denounce + confession + turkey + toll + pal + transcription + sulphur + provisional + hug + particular + intent + fascinate + conductor + feasible + vacant + trait + meadow + creed + unfamiliar + optimism + wary + twist + sweet + substantive + excavation + destiny + thick + pasture + archaeological + tick + profit + pat + papal + cultivate + awake + trained + civic + voyage + siege + enormously + distract + stroll + jewel + immediately + honourable + helpless + hay + expel + eternal + demonstrator + correction + civilization + ample + retention + rehabilitation + premature + encompass + distinctly + diplomat + articulate + restricted + prop + intensify + deviation + contest + workplace + lazy + kidney + insistence + whisper + multimedia + forestry + excited + decay + screw + rally + pest + invaluable + homework + harmful + bump + bodily + grasp + finished + facade + cushion + conversely + urge + tune + solvent + slogan + petty + perceived + install + fuss + rack + imminent + short + revert + ram + contraction + tread + supplementary + ham + defy + athlete + sociological + physician + crossing + bail + unwanted + tight + plausible + midfield + alert + feminine + drainage + cruelty + abnormal + relate + poison + symmetry + stake + rotten + prone + marsh + litigation + curl + urine + latin + hover + greeting + chase + spouse + produce + forge + salon + handicapped + sway + homosexual + handicap + colon + upstairs + stimulation + spray + original + lay + garlic + suitcase + skipper + moan + manpower + manifest + incredibly + historically + decision + wildly + reformer + quantum + considering + +the of and to in I that was his he it with is for as had you not be her on at by which have or from this him but all she they were my are me one their so an said them we who would been will no when there if more out up into do any your what has man could other than our some very time upon about may its only now like little then can should made did us such a great before must two these see know over much down after first mr good men + + + +own never most old shall day where those came come himself way work life without go make well through being long say might how am too even def again many back here think every people went same last thought away under take found hand eyes still place while just also young yet though against things get ever give god years off face nothing right once another left part saw house world head three took new love always mrs put night each king between tell mind heart few because thing whom far seemed looked called whole de set both got find + + + +done heard look name days told let lord country asked going seen better p having home knew side something moment father among course hands woman enough words mother soon full end gave room almost small thou cannot water want however light quite brought nor word whose given door best turned taken does use morning myself gutenberg felt until since power themselves used rather began present voice others white works less money next poor death stood form within together till thy large matter kind often certain herself year friend half order round true anything keep sent wife means believe passed feet + + + +near public state son hundred children thus hope alone above case dear thee says person high read city already received fact gone girl known hear times least perhaps sure indeed english open body itself along land return leave air nature answered either law help lay point child letter four wish fire cried women speak number therefore hour friends held free war during several business whether er manner second reason replied united call general why behind became john become dead earth boy lost forth thousand looking i'll family soul feel coming england spirit question care truth ground really rest mean + + + + +different making possible fell towards human kept short town following need cause met evening returned five strong able french live lady subject sn answer sea fear understand hard terms doubt around ask arms turn sense seems black bring followed beautiful close dark hold character sort sight ten show party fine ye ready story common book electronic talk account mark interest written can't bed necessary age else force idea longer art spoke across brother early ought sometimes line saying table appeared river continued eye ety sun information later everything reached suddenly past hours strange deep change miles feeling act meet paid + + + +further purpose happy added seem taking blood rose south beyond cold neither forward view i've position sound none entered clear road late stand suppose la daughter real nearly mine laws knowledge comes toward bad cut copy husband six france living peace didn't low north remember effect natural pretty fall fair service below except american hair london laid pass led copyright doing army run horse future opened pleasure history west pay red an' hath note although wanted gold makes desire play master office tried front big dr lived certainly wind receive attention government unto church strength length company placed paper + + + +letters probably glad important especially greater yourself fellow bear opinion window ran faith ago agreement charge beauty lips remained arm latter duty send distance silence foot wild object die save gentleman trees green trouble smile books wrong various sleep persons blockquote happened particular drew minutes hardly walked chief chance according beginning action deal loved visit thinking follow standing knows try presence heavy sweet plain donations immediately wrote mouth rich thoughts months u won't afraid paris single joy enemy broken unless states ship condition carry exclaimed including filled seeing influence write boys appear outside secret parts please appearance evil march george + + + +whatever slowly tears horses places caught stay instead struck blue york impossible period sister battle school mary raised occasion married man's former food youth learned merely reach system twenty dinner quiet easily moved afterwards giving walk stopped laughed language expression week hall danger property wonder usual figure born court generally grew showed getting ancient respect third worth simple tree leaving remain society fight wall result heaven william started command tone regard expected mere month beside silent perfect experience street writing goes circumstances entirely fresh duke covered bound east wood stone quickly notice bright christ boat noble meant somewhat sudden value + + + +c direction chair due support tom date waiting christian village lives reading agree lines considered field observed scarcely wished wait greatest permission success piece british ex charles formed speaking trying conversation proper hill music opportunity that's german afternoon cry cost allowed girls considerable c broke honour seven private sit news top scene discovered marriage step garden race begin per individual sitting learn political difficult bit speech henry lie cast eat authority etc floor ill ways officers offered original happiness flowers produced summer provide study religion picture walls personal america watch pleased leaves declared hot understood effort prepared escape attempt supposed + + + + +killed fast author indian brown determined pain spring takes drawn soldiers houses beneath talking turning century steps intended soft straight matters likely corner trademark justice simply produce trust appears rome laugh forget europe passage eight closed ourselves gives dress passing terrible required medium efforts sake breath wise ladies possession pleasant perfectly o' memory usually grave fixed modern spot troops rise break fifty island meeting camp nation existence reply i'd copies sky touch equal fortune v shore domain named situation looks promise orders degree middle winter plan spent allow pale conduct running religious surprise minute roman cases shot lead move names + + + +stop higher et father's threw worse built spoken glass board vain affairs instance safe loss doctor offer class complete access lower wouldn't repeated forms darkness military warm drink passion ones physical example ears questions start lying smiled keeping spite shown directly james hart serious hat dog silver sufficient main mentioned servant pride crowd train wonderful moral instant associated path greek meaning fit ordered lot he's proved obliged enter rule sword attack seat game health paragraph statement social refund sorry courage members grace official dream worthy rock jack provided special shook request mighty glance heads movement fee share expect couldn't dollars + + + +spread opposite glory twelve space engaged peter wine ordinary mountains taste iron isn't distribute trade consider greatly accepted forced advantage ideas decided using officer rate clothes sign feelings native promised judge difference working anxious marry captain finished extent watched curious foreign besides method excellent confidence marked 'em jesus exactly importance finally bill vast prove fancy quick yes sought prevent neck hearts liberty interesting sides legal gentlemen dry serve aside pure concerning forgotten lose powers possessed thrown evidence distant michael progress similar narrow altogether building page particularly knowing weeks settled holding mountain search sad sin lies proud pieces clearly price ships + + + +thirty sick honest shut talked bank fate dropped judgment conditions king's accept hills removed forest measure species seek highest otherwise stream honor carefully obtained ear bread bottom additional presented aid fingers q remembered choose agreed animal events there's fully delight rights amount obtain tax servants sons cross shoulders thick points stranger woods facts dare grow creature hung rain false tall gate nations created refused quietly surface freely holy streets blow july regarded fashion report coast daily file shoulder surprised faces succeeded birds distribution royal song wealth comfort failed freedom peculiar anyone advance gentle surely animals waited secure desired grass touched + + + + +occupied draw stage portion expressed opening june spirits fish tongue capital angry growing served carriage weather breast presently snow david papers necessity practice claim hast education sharp prince permitted group enemies robert played throughout pity expense yours million add pray taught explained tired leading kill shadow companion weight mass established suffered gray brave thin satisfied check virtue golden numerous frequently famous telling powerful alive waters national weak divine material principal gathered suggested frank valley guess finding yellow heat remains bent seized guard equally naturally box remarkable gods moon slight style pointed saved windows crossed louis pounds ain't evidently principle immediate + + + +willing consequence richard principles characters paul season remarked science tender worked grown whispered interested quarter midst liked advanced apparently bore pwh active noticed aware thomas uncle list dangerous august calm genius sacred kingdom entire popular unknown nice habit spanish familiar reader published direct handsome you'll joined actually kings sd posted approach washington hearing needed increased walking twice throw intellectual appointed wisdom ceased truly numbers demanded priest wounded sorrow drive fault listened palace affair contact distinguished station beat distributed e listen italy fool becomes watching hurt wants express occurred favour height size edge subjects task follows interests nine sympathy burst putting + + + + +dressed lifted hopes suffer noise smiling rode tells minds farther literature vessel affection suffering proceeded flesh advice grand carrying legs spain post collection empty rank storm god's imagine wore duties admitted countries pocket arrival imagination driven loud sentence lovely extraordinary november december happen absence breakfast population thank rules inhabitants series laughing address relief bird owner impression satisfaction coat prepare relations shape birth rapidly smoke january mother's machine content consideration accompanied regular moving stands wholly teeth busy treated burning shame quality bay discover inside brain soil completely message ring resolved calling phrase acts mention square pair won title understanding sunday fruit + + + +mad forces included tea rocks nearer slaves falling absolutely slow bearing mercy larger explain contain grief soldier wasn't countenance previous explanation welcome proposed prayer stars germany belief informed moments poetry constant buy final faithful ride policy supper drawing excitement dying demand fighting fields drove upper sum philip motion assistance forty april stones edward fees kindly dignity catch october seated knees amongst current sending parties objects gained bitter possibly slave separate loose text receiving worst sold don credit chosen hoped printed terror features fond control capable fifteen doesn't firm superior cruel spiritual harry splendid proof pressed sooner join process crime dust + + + +instantly lands relation doors concerned deeply practical colour sing destroy anger distributing results increase reasons nose friendly entrance rooms admit supply clean useful yesterday delicate fail continue remove addressed choice huge needs wear blind unable cover double victory dozen constantly level india release rough ended shows fly praise devil ahead smith connected degrees gain addition committed chamber notes italian gradually acquaintance bought souls mission sacrifice cities mistake exercise conscience based car buried theory commanded nobody minister closely energy dick bare fought partly mistress hate arose playing color lake safety provisions description asleep centre faint thinks parents escaped careful enjoy drop + + + +brilliant brief bringing worship goods tale skin roof grey highly crown castle excited throne stated despair ease attached total kindness mile citizens circle dull extreme clouds figures intention prison term assured hidden thoroughly cup member civil apply labor everywhere intelligence strike fairly comply fellows haven't event gently connection protection conscious edition directed pulled flight evident surrounded wishes yards voices weary couple variety whilst volume details older requirements custom apart bow awful everybody labour asking lover showing introduced suit becoming composed plans rendered pictures lest volunteers singing eager precious paused require meat whenever milk dogs successful plants vision rare granted raise + + + +egypt manners cousin you've development arthur obs cool trial learning approached bridge abroad devoted paying literary writer fn israel disappeared interrupted stock readers dreadful female protect accustomed virginia type recognized salt destroyed signs innocent temper plenty pope avoid hurried represented favor mental attitude returning admiration brothers anxiety queen teach count curiosity solemn causes vessels compelled dance hotel wicked fled kissed guns fill visible younger guide earnest actual companions prisoner miserable lad harm views irish utterly ends shop stairs pardon gay beg seldom kinds record fat sand violent branches inquired iv september worn ireland flat departure delivered gift ruin skill cattle + + + +equipment temple calls earlier license visited en consent sufficiently natives wound laughter contained perceived scattered whence rushed chiefly bold anywhere witness foolish helped kitchen sell anybody self extremely treatment throat dreams patient speed growth quantity latin immense conclusion computer affected severe excuse triumph origin joseph slept eternal thine audience pages sounds swift limited wings stepped services library remaining containing base confusion win maid charming editions attended softly reality performed glorious likewise site sail frightened acquainted unhappy feared article prisoners store adopted shalt remark cook thousands pause inclined convinced band valuable hence desert effects kiss plant ice ball stick absolute readily + + + + +behold fierce argument observe blessed bosom rage striking discovery creatures shouted guilty related setting forgot punishment gun slightly articles police mysterious extended confess shade murder emotion destruction wondered increasing hide expedition horror local expenses ignorant doctrine generous range host wet cloud mystery ed waste changes possess consciousness february trembling disease formerly spend production source mankind universal deck sees habits estate aunt reign humble compliance delay shining reported hers unfortunate midnight listening flower hero accomplished doth classes thanks banks philosophy belong finger comfortable market cap waves woman's glanced troubled difficulties picked european purposes somewhere delighted pushed press household fleet baby region + + + + +lately uttered exact image ages murmured melancholy suspicion bowed refuse elizabeth staff liability we'll enjoyed stretched gaze belonged ashamed reward meal blame nodded status opinions indicate poem savage arise voyage misery guests painted attend afford donate job proceed loves forehead regret plainly risk ad lighted angel rapid distinct doubtless properly wit fame singular error utmost methods reputation appeal she's w strongly margaret lack breaking dawn violence fatal render career design displayed gets commercial forgive lights agreeable suggestion utter sheep resolution spare patience domestic concluded 'tis farm reference chinese exist corn approaching alike mounted jane issue key providing majority measures towns + + + +flame boston dared ignorance reduced occasionally y weakness furnished china priests flying cloth gazed profit fourth bell hitherto benefit movements eagerly acted urged ascii disposed electronically atmosphere chapter begged helen hole invited borne departed catholic files reasonable sugar replacement sigh humanity thrust frame opposition disk haste lonely artist knight quarters charm substance rolled email flung celebrated division slavery verse decision probable painful governor forever turns branch ocean rear leader delightful stared boats keen disposition senses occasions readable beloved inches bones enthusiasm materials luck derived managed community apparent preserved magnificent hurry scheme oil thence reaching dim wretched hanging pipe useless nevertheless + + + +print smooth solid pursued necessarily build attempted centuries eggs equivalent hastily burned you'd recent oh travel cries noon crying generations located cabin announcement britain compared handed cease smaller circumstance tent frequent alarm nervous beast what's aloud independent gates distinction essential observation stronger recovered belonging loving masters writers cf permanent mortal stern gratitude preserve burden aspect millions merry knife dread clever applicable district shadows jim silk failure links cent sentiment amid profits agent finds russia bade russian desperate union imagined contempt raising lords hell separated grant seriously tribes hit enormous defective conviction secured mixed insisted wooden prefer prayers fever selected daughters + + + +treat warning flew speaks developed impulse slipped ours johnson mistaken damages ambition resumed christmas yield ideal schools confirmed descended rush falls deny calculated correct perform hadn't somehow accordingly stayed acquired counsel distress sins notion discussion constitution anne hundreds instrument firmly actions steady remarks empire elements idle pen entering online africa permit th' tide vol leaned college maintain sovereign tail generation crowded fears nights limitation tied horrible cat displaying port male experienced opposed treaty contents rested mode poured les occur seeking practically abandoned reports eleven sank begins founded brings trace instinct collected scotland characteristic chose cheerful tribe costs threatened arrangement western + + + + +sang beings sam pressure politics sorts shelter rude scientific revealed winds riding scenes shake industry claims pp merit profession lamp interview territory sleeping sex coffee devotion thereof creation trail romans supported requires fathers prospect obey alexander shone operation northern nurse profound hungry scott sisters assure exceedingly match wrath continually rest gifts folly chain uniform debt teaching venture execution shoes mood crew perceive accounts eating multitude declare yard o'er astonishment version vague odd grateful nearest infinite elsewhere copying apartment activity wives parted security cared sensible owing martin saturday cottage jews leaning capacity joe settle referred francis holder involved sunshine dutch council + + + +princes ate examination steel strangers beheld test noted slightest widow charity realized element shed errors communication reflection attacked organization maintained restored folks concealed accordance heavens star examined deeds wordforms somebody incident oath guest bar row poverty bottle prevented bless stir intense completed quarrel touching inner available fix resistance unusual deed derive hollow suspected contains sighed province deserted establishment vote muttered thither oxford cavalry lofty endure succeed leg bid alice hated civilization u s acting landed christians passions interior scarce lightly disturbed rev supreme hang notwithstanding shock exception offering display strain drank confined o exhausted poets sounded aim critical jerusalem directions negro + + + + +fearful standard studied bag n buildings consequences commenced deeper repeat driving beasts track rid holds residence steadily intimate drinking swear treasure fun throwing apt enterprise queer seed tower runs defend favourite desires heavily assembled existed depends poems hesitated stuff section settlement staring sole roads plate mexico overcome pains performing dwell grounds taxes marble recently tones ability awake walter wave shaking folk possibility butter fury marched moses writes issued sailed instructions hatred pursuit pull furniture additions hid rope vi adventure royalty vanished arts elder signal wanting supplied feast safely burn describe references lesson annual card passes application intelligent county beaten presents + + + +format flow sixty scale damage marks obtaining moreover commerce startled southern consequently outer belongs ben wrought average naked conducted rivers songs obvious foundation concern ceremony magic campaign hunting carolina liberal whisper largely commonly torn exists contributions hunt teacher christianity lawyer operations detail shortly caesar wondering leaders blessing princess he'd altar tenderness tiny web cardinal sharply regiment chest distinctly purple creating gather depth indignation performance election prosperity gloomy conception clerk decide drunk victim reflected pour preceding individuals gazing absurd lift gesture armies limbs manage brethren hugh plays hastened dragged motive whatsoever pointing verses pronounced exchange definite emperor tendency remote finish flag + + + +boots enabled administration denied churches rarely earnestly considering previously ugly bears signed genuine harmless mingled obedience walks training badly feed central contrast relieved romance mississippi structure payment pace passages succession persuaded sources inquiry inspired angels roll wilt inch troubles perfection lee wherever owe handle advantages trip shoot fortunate newspaper employment fitted refuge misfortune providence owns cutting beard stirred tear dan resist bob depths maiden determine commission merchant whereas crossing independence lively breeze provinces jean virtues conceived relative solitary smell wandering thereby eighteen locked provision courts eaten historical regarding florence preferred pick ruined wherein vanity condemned deliver unexpected desk gross lane + + + +happens represent billy root holland mud respectable cleared feels fruits testimony milton existing bride rang ranks responsibility beating disappointed suitable depend judges giant grasp arrive simplicity autumn absent legally veil gloom doubtful suspect weapons limits determination feeble prophet shak gathering basis examine corrupt payments returns laying prize instances greeks d they're theatre purchase comparison composition rival someone realize defeat demands foe shared consists studies balance intercourse id forming slender coach criminal knocked silly humour masses indifferent recall occupation discourse keeps regions intervals assist novel intellect leads hither tales sale revenge lucy yonder resources jealous we're wheel invitation narrative risen burnt + + + +sentiments inferior amusement marie flash recognize swiftly portrait create summoned suggest induced conflict fed curse disappointment helpless preparing construction lincoln zeal responsible indicated groups positive germans attracted vengeance fort club cure stout missed gracious include flood satisfy agony respects ventured implied maria stupid seas spaniards grain enjoyment wearing indifference conceal horizon pleasures therein precisely canada day's assume registered estimate steep route gardens visitor closer harmony non thunder wire graceful crept greece childhood knee saddle supplies weeping mostly paragraphs unconscious mutual scorn grows external agents software institutions losing universe clock attempts instruction injury roots receipt jumped dearest sore earliest finest enable + + + +discipline motives fastened introduction converted wilderness confused fancied offices slip revolution wedding girl's farmer silently fires wept behalf reckon responded uncertain neglected stroke exquisite engagement dirty rolling platform messenger privilege admirable offers mischief physician imposed organized covering student daring cave wars convey he'll sincere tradition gravely combined gallant sensation travelling charges submit tragedy specific commander inn stiff accompany score virgin farewell paradise villages hunger trembled favorite criticism proprietary customs cotton ruth hospital restrictions outward impressed blows plains flashed rent prey owed longing musical satisfactory ridiculous sheet disgrace colored shouldn't originally samuel wages papa gas inevitable extensive leisure deadly chin claimed + + + +glow husband's emotions adam jealousy leaf publication englishman allah jones hostile wandered railway translation procession betrayed pound admired elected pierre sunk ruins eastern roses citizen reminded deceived tables beach starting funeral arrested flour feature correspondence consisted counted reserve proceedings roar romantic twenty five hut strangely absorbed propose seats bark reception pleasing attained wake research prayed monarch clothing dollar illness calmly obeyed heartily pressing daylight warriors jest abruptly washed comment metal preparations nerves solution pretended sixteen assembly tobacco entity dwelling depart swung bitterly alteration colony disclaimers wing peaceful lion opportunities alarmed furnish resting accused culture writings dwelt conquered trick trusted column financial + + + +cunning preparation drama joke entertained mist hypertext shell medicine proofread nest reverence situated yielded conceive appointment lessons fetch tomb candle offence coarse heap mixture homes model men's defect destined occasional fourteen hint knights solicit dreamed objection craft acid namely asia neglect data weapon confessed arrangements repose complying copied pink user heels grandfather other's income i e regards streams vigorous accepting bishop lightning authors flames observations compressed sport powder beds orange painting shout austria bath careless chap derivative roused primitive doorway climbed volumes vulgar arguments st sunset convenient mail recalled wrapped abode planted paint surrender establish mild promptly appearing department parish stephen + + + +nay lit handkerchief basket easier deserve quit assurance mirror plot yer upward sadly secretary adding modest dish cares straw net advised heavenly largest proceeding impatient wounds warmth certainty restless meantime rays salvation lovers experiment shores today tremendous afforded moonlight intend california cultivated flushed shakespeare newspapers rocky pious wont steam improvement garments ned treasury merchants perpetual trained products affectionate dispute visitors poison proposition maybe rifle warned parting shield erected employ prevailed talent rises climate chairs searched unlike recover mate arrange fortunes puzzled committee aged ohio ashes ghost b promises bushes effective distinguish manifest comparatively esteem blew revelation wash recognition confession clay + + + +nonsense trunk management undoubtedly dried dorothy chiefs coal stolen earthly restore indirectly lasted selfish renewed canoe protest vice races deemed temporary pile frederick chapel moderate spell massachusetts upright quoted area bone solitude instruments formal students greatness struggling monday reproach altered grim leaped venice federal questioned editor desirable acknowledge motionless remedy bestowed pursue representative pole gladly linen vital sink pacific hopeless dangers gratefully president travelled ward nephew ms cheer bloody siege commands justified atlantic stomach improved admire openly sailors abide advancing forests records polly recorded modification dramatic statements upstairs varied letting wilson comrades sets descent whither envy load pretend folded brass + + + +internal furious curtain healthy obscure summit alas fifth center faced cheap saints colonel egyptian contest owned adventures exclusion seize chances springs alter landing fence leagues glimpse statue contract luxury artillery doubts saving fro string combination awakened faded arrest protected temperature strict contented professional intent brother's injured neighborhood andrew abundance smoking yourselves medical garrison likes corps heroic inform wife's retained agitation nobles prominent institution judged embrace wheels closing damaged pack affections eldest anguish surrounding obviously strictly capture drops inquire ample remainder justly recollection deer answers bedroom purely bush plunged thyself joint refer expecting madam railroad spake respecting jan columns weep identify + + + +discharge bench ralph heir oak rescue limit unpleasant anxiously innocence awoke expectation incomplete program reserved secretly we've invention faults disagreeable piano defeated charms purse persuade deprived electric endless interval chase heroes invisible well known occupy jacob gown cruelty lock lowest hesitation withdrew proposal destiny recognised commons foul loaded amidst titles ancestors types commanding madness happily assigned declined temptation lady's subsequent jewels breathed willingly youthful bells spectacle uneasy shine formidable stately machinery fragments rushing attractive product economic sickness uses dashed engine ashore dates theirs adv clasped international leather spared crushed interfere subtle waved slope floating worry effected passengers violently donation steamer witnesses + + + +specified learnt stores designed guessed roger timber talents heed jackson murdered vivid woe calculate killing laura savages wasted trifle funny pockets philosopher insult den representation incapable eloquence dine temples ann sensitive robin appetite wishing picturesque douglas courtesy flowing remembrance lawyers sphere murmur elegant honourable stopping guilt welfare avoided fishing perish sober steal delicious infant lip norman offended dost memories wheat japanese humor exhibited encounter footsteps marquis smiles amiable twilight arrows consisting park retire economy sufferings secrets na halted govern favourable colors translated stretch formation immortal gallery parallel lean tempted frontier continent knock impatience unity dealing prohibition decent fiery images tie + + + +punished submitted julia albert rejoined speedily consented major preliminary cell void placing prudence egg amazement border artificial hereafter fanny crimes breathe exempt anchor chicago sits purchased eminent neighbors glowing sunlight examples exercised wealthy seeming bonaparte shouting thanked illustrious curiously inspiration seeds naval foes everyone longed abundant doubted painter greeted erect glasses meanwhile shooting athens wagon lend lent crisis undertake particulars eh veins polite anna experiences seal header clergy mount array corners magazine loudly bitterness texas guardian searching rejected harsh includes boldly maurice kate lunch pine shells seconds despite hoping injustice expressions flies push tight problems landscape sue protested scarlet abandon + + + + +artistic mainly measured loyal boiling desirous suited alliance advise waist sinking apprehension stable gregory maximum commit hideous hamilton sweetness dismissed tore affect shaken evils unworthy significance modified miracle lieu peasant considerably observing conveyed resemblance extend riches personally morality rebellion thread dumb inclination forbidden copper differences sailor requested alfred response promoting imperial blank purity victor bending solemnly twenty four minor del crimson republic teachers ma'am danced bargain dealt fatigue telephone cents whip adams dislike witnessed infantry acres checked countrymen enemy's companies normal shirt addresses introduce sofa mothers sweep conversion sketch african deserved answering virtuous persian anyway thief driver retain constructed daniel ut + + + +philadelphia conspicuous channel nobility edith berlin editing cambridge declaration guards personality smallest excess separation disgust ha accomplish speeches herbert convent rightly suspended reform mob thirst unnecessary treasures asks viewed designs gleam threatening palm missouri filling quoth fur fortnight holes addressing frightful encourage speaker tribute procure frankly recommended relieve intentions unjust legislation project threshold merits morrow traces induce spear inward pupils corresponding fairy conclude clung neat lucky lap session torture damp ridge spoil liable swords hearty bc abraham thoughtful traveller chains favorable tin imp strongest horace dependent couch bills warrant complaint endeavour sails dined convention guarded angle widely illinois charlotte endeavoured + + + + +ardent cow mill victims prejudice foremost map probability porch lieutenant surprising fountain sustained appropriate ford clara assisted lewis rejoice extending marvellous clothed jew collar bands confident hasty nigh organ prose privileges selection inquiries codes replace saint districts deliberately awe beforehand strife released compare beer retorted relate cheerfully pistol presume velvet wretch susan pennsylvania stirring righteousness missing fain facing fashionable producing peoples positively reasoning gravity disturb sermon exchanged partner brains lowered association estates abuse flock niece languages asserted bodily notions oliver faculty cannon thirteen sailing rings smart possessions disciples petty widest divisions prudent caution justify awhile boxes manuscript cigar warrior impressions + + + +aught lifting inaccurate tidings friday liquid staying concept creek lo brush download specially cream meetings jump unwilling adapted practised combat subdued jewish innumerable blowing extra civilized invented japan pitch cliff crowned portions awkward horrid pulling appreciate communicated kentucky jury encountered attacks monster simon maintaining sites frozen invariably dies survive literally consolation m phenomena pot ellen briefly rice planned barbara respected sublime dropping guy behaviour desolate penny adopt replaced revenue formats hired regularly infringement curtains eagerness helping investigation constitutional insist occurs fools inheritance latest leap games apple visiting travellers experiments hasn't pupil enjoying totally twisted discuss firing background subscribe tenderly transcribe + + + +descend differ majesty's avail disaster bet periodic bull entertainment computers cursed raw fulfilled georgia virus log skies scotch embraced hospitality faintly solomon robbed cart influences ascended incidents childish robe aboard resembling reflect dominion dreary serving complexion engage tents herd attain collect disclaims pan relatives borrowed convert outline blown comprehend peasants opera assault deceive doctrines representatives dedicated struggled officials hiding paths backs prominently prices procured mourning compliment heights approval gasped breadth withdraw tune compassion polished latitude dishes parent contrived delicacy projected akin f betray traced resentment indemnify pseud sacrifices disguise transcription document neighbour squire punish bars glittering tossed block lots worldly + + + +muscles elbow obligation trifling decline attachment ambitious filename artists bloom holiday brute repair fist recollect eagle honorable significant barren functions guided dense fiction viz adds rows recommend suspicious resulting seventy shillings educational duly governed scripture upwards sworn nicholas horn brook fund vienna lodge infinitely clergyman marshal ruled fiercely portuguese costume pit disorder sheer exalted fare applause chaucer remind binary packed pillow jersey abbey nowhere anyhow agitated marching catching el grasped arrow tend carved fitting bonds instructed elaborate corpse bewildered essence positions emily edited continues harold elevation realm debts glancing shops complained loyalty coin clad staircase documents interpreted th extremity accord + + + +sally lace tremble exile gospel mechanical successfully scholar wonders arab temperament expressing fred trap spots awaiting potatoes likeness harbour proofs jolly contributed wits generosity ruler lawrence cake lamps crazy sincerity entertain madame sir faculties hesitate deepest seventeen lordship greeting feminine monstrous tongues barely d mansion facility praised warranties sarah happier indicating rob gigantic honey ladder ending wales swallowed sunny knelt tyranny decree stake divide dreaming proclaimed dignified tread mines viewing defense oldest incredible bidding brick arch everlasting elect sprung harder winding deductible magistrate respective liquor imitation shy perished prime studying eighty hebrew unfortunately licensed fog coloured bits consult moves r + + + + +warn taylor vile depended phil legend locations shallow doom dreaded encouragement impatiently scent varieties irregular battles compass neighbouring bliss harvest promotion stove faithfully anthony excellence transfer awaited heathen poetic consulted illustrated gilbert br fundamental bundle rebel cultivation joys rigid tragic review representing flowed brows whereupon terribly melted venerable towers cooking mustn't suspicions old fashioned oppressed australia friend's revolt swell improve williams describes goddess wreck tennessee convince sentences bowl radiant prussia westward indignant refined unseen illustration pertaining swamp austrian saxon congregation nerve undertaking disclaimer characteristics stare specimens ascertain pledge earn warfare supposing subsequently attending angrily select animated industrial hurriedly manhood quantities interpretation + + + +dressing rejoiced edinburgh catherine challenge produces forbid gang boiled shouts so called theme thankful admission enters elevated frenchman pool terrified lads persisted conference equality genus didst newly generals surroundings sorrows occasioned invasion workmen monks sends turkish discretion pattern reveal endured resolve columbia preach exceeding ringing triumphant defiance errand woke grandmother weighed wool orleans communicate strikes promising scenery righteous essentially oppose joyous specimen doctors eloquent manager organs sticks drag haunted chorus rational crop processing accurate wolf adorned sheets resort refusal bond vicinity preacher sympathetic casting opens prophets horns warmly salary continuous satan continual defended breaks workers lantern balls rod blaze examining naples + + + +peculiarly vegetables ingenious excite howard horseback re use louisiana farmers wildly mouths carpet sadness customary circles aren't wonderfully max juan successor allied ceiling confirmation glances diamonds goal representations cash vacant antiquity despise lawn they'll appealed turkey texts neighbor spreading discharged phrases ultimate tastes submission entry rachel blush monument hardy thorough ein ecclesiastical fertile exciting captive severity considerations shew faster louise grandeur winning solely globe malice echoed lodging conservative throng prosperous whistle floated transferred declaring reckoned cheese bite thoughtfully breach enthusiastic cars downstairs allowing invite adjoining dusk cathedral truths plague sandy boil caroline beautifully inhabited tomorrow exclamation finishing shocked escort forgetting hanged + + + +hats mirth uncomfortable connecticut bows pierced harbor tricks rubbed apparatus mysteries honesty negroes concerns wander assert ceremonies sacrificed utterance dismay fright rail reflections crops pushing proves jimmy pathetic imperfect haughty navy fortress hurrying x blessings attempting insects selling appreciation suppressed acquire offensive ripe dresses reigned coldly candles km sixth blazing youngest mask florida lecture parlor decidedly whereby gordon reverend successive perception buffalo sire quitted keys develop function morals damned vexed d pouring bullet excessive bind identical cliffs tools byron mexican piety superstition git substantial bulk prevail wiser preaching prolonged annoyed westminster splendour remembering richmond upset cab bunch pencil subjected vegetable + + + +exhibit emerged cooked hay kansas gale preached arnold trousers debate dated tumult corruption summons comrade eternity hears lingered propriety stillness partial welcomed cabinet proceeds vow quaint soup beef rests slay surgeon irresistible sealed repeating needn't allowance undertaken treachery posts borders attendant unite murderer owners nm sweeping unconsciously blade saviour theories graham behaved pleaded spy possesses lawful tommy seasons withdrawn reckless factory shades gossip seventh attendance robes journal systems dryden maine token intimacy abstract machines bestow chanced locks honestly legitimate accent symptoms votes ragged thursday manifested fidelity swinging descending sincerely bred whereof indies novels league failing succeeding santa approve cautiously miller + + + + +afflicted lodgings petition traffic sparkling limb architecture disposal carriages crack kindred naught ornament slew steward fantastic evolution patiently reverse survey dug amuse stretching isaac forthwith contemporary foliage receives scandal donors deliberate influenced intolerable hearth symbol governments repaired pleasantly homage victorious columbus recovery defined attendants modesty diana washing pavement unnatural decisive wisely precise negative occurrence snatched shaft linked festival exclusively jove wickedness visions maggie rosy carelessly stem corporation dec feeding allen cows schemes preference urge husbands labours shrill exercises sovereignty reduce distressed clearing removal dean scottish assertion accessible comedy flush code philosophers adequate vaguely treason hunter chambers split yielding newsletter snake + + + +pub historian ass intensity democracy battery draws netherlands creed liking luke tyrant strove attraction slaughter dismal deposited assent cups concert downward canal evenings wax detective fancies spoiled revolver murray earned analysis finer paces roaring prompt paperwork wherefore emphasis sharing delayed inherited bronze waking garment redistributing wholesome remorse plato morris stooped dew monk thrill hue exclusive funds porter uncommon dash strained confounded swim strip middle aged ultimately team missionary esteemed tracks envelope whoever expensive headquarters cherished brandy startling homer talks acute cigarette motor embarrassed janet volunteer offspring network reaches indispensable plane reaction regiments g sums partially prejudices proudly baggage terrace deaf allusion + + + +grip juice isabel resigned humility benjamin blast ministry sexual nile diameter troop onward crowds marrying tightly sullen brutal axe holmes penalty tops diamond boards corridor endowed strengthened cells proportions alternate echo restraint trials reads identity headed softened quivering stages sway poetical objected screen professed dirt ascertained era wider ambassador constituted breed interference eyebrows shapes afar consist acceptance displays flashing hunted beauties lazy shrewd extravagant momentary cordial engineer rapidity nov halt alternative devils stamp compact whites breathless encoding drift disappear roared revived counter venus imaginary diminished honoured th despatched objections ray climbing attract astonishing competition suggestions ink oft crystal shower diseases + + + +ferdinand obedient draught wondrous await armour massive bottles kin cellar falsehood pillars edgar philosophical martha worlds memorable jacques detected stealing noisy henceforth cicero laden frost device glare touches senate lasting communion transport constantinople coffin eventually johnny enclosed forgiveness awfully clinging darkened contemplation termed manufacture swallow commonplace nancy resembled she'd labors contracted inscription comfortably indulge indulgence bravely kneeling yea keenly exhibition agricultural enlightened quest compliments crest extension uneasiness constitute inflicted lakes swing meadow noblest downloading complex controversy freed resignation tempest guidance prospects humbly lined serene shrugged honours roughly checks remarkably dainty overhead commencement singularly brightness oppression repeatedly conspiracy restrain splendor preservation + + + +pub pepper basin creeping matthew publicly percy continuing grove calamity pony vigour melody profitable descendants hire speculation discoveries accepts drunken candidate principally worried obstinate hasten foreigners elderly overwhelmed instincts telegraph russell university ghastly patron varying barbarous celestial t' patriotism modify earnestness exertion fox refusing horsemen inspection stations grieved louder bursting regretted mournful pursuing traitor associations cautious foundations stamped prior undertook telegram beggar chimney complicated davis striving magistrates converse graces wiped oars apology scared imprisonment eastward substitute yahweh handful usage lodged of villain banished restoration serpent hedge k jurisdiction captains settlers gaining valiant primary storms beam victoria tour prophecy spectacles obsolete + + + +buying shepherd wells harriet exaggerated heated penetrated travels earl hereditary ali supernatural competent piled hostess agriculture boughs urgent gratified suffice ports drifted accuracy deceased circular securing possibilities rhine alert neighboring democratic quebec bud accounted aided augustus blanket hail pretence beams andy pig shaped oven rounded ivory northward isolated policeman aug conventional babylon dusty bishops complaints stripped plead hinder vo cord flows personage classical alongside wrongs extract rewarded lungs lighter kisses serves pint forgiven sternly proclamation realised pipes arising pitched tube observer smote avenue elephant burke footing statesman rebels nails wears doomed edges esther indiana affecting stormy bee bury efficient mix + + + +supporting actor disturbance sweat executive seemingly tenth blossoms ethel folds painfully polish shudder oe roofs comparative begging imposing notable invested imprisoned mute amy cage esq pg cured cargo prof negotiations assented jail skilful ideals conferred resulted illusion torment troublesome crowns feb repentance blankets proprietor uncertainty concentrated mediterranean covers scream compromise respectful chariot ammunition bonnet secondary persia persecution lesser assistant saluted fits indulged springing cane fold boundary valued she'll rugged aloft thieves parlour indebted tons processes dave moore argue dearly logic panic restrained lb vainly weariness enlarged franklin tasted rural torrent resolute refrain kissing gorgeous meets circulation passionately inasmuch unexpectedly stress + + + + +consumption groan suits sustain hosts crash resemble epoch quote lacking nominally choked aristocracy granite gradual delights hurled joyful sack slumber detached snapped shadowy accompanying annoyance crush needle repent phenomenon execute canst smoked greet monarchy behave richly controlled strive endeavor barrier canadian curve politeness flora rely flank convenience courteous logs lamb effectually robinson logical shan't dimly withered diet praises fulfil mantle ne'er discussing chicken judicial consistent ridicule as reins barrel distrust trunks verily hunters feather desperately goodly habitual voluntary luncheon eighteenth exertions expert coolly mistakes tedious contemplated clark jacket gleaming shrank swimming kent perplexed impressive universally displeasure maids rates underneath expedient + + + +emma impress bees bounded worshipped resisted provincial popularity baker shattered merciful olive tramp compensation ernest martial genial syria conjecture van waiter detained items promote delaware covenant nought interposed seizing sinner vigor devote decorated sentimental yoke properties warlike perilous threats kindled lays hostility dragging mare regulations obstacle sage destitute pays sleepy dublin jonathan posterity they'd nod mason patriotic plantation pitiful foster requisite expose oxen patch anderson stuart interruption lance payable definition birthday thumb wolves hammer overwhelming intensely revolutionary fragrant bleeding sheltered circuit dominions sales energetic insignificant repetition we'd amazing trains skirts tip trivial kick tended rejoicing dig pet skull lectures ness + + + +threat legislature plunder removing jungle ghosts numbered famine palaces sorrowful improvements coleridge fuller asp blocks darted shrine heel typical throws fortunately recognise fuel th tranquil frown destination plunge moor pin mars associate here's owen th arabic vicious framed banquet expressive instinctively lighting scanning subordinate jaws patent courtyard gulf destroying detailed regulating closet compel inland excepting pretext legislative stationed rash margin champion settling billion shorter betwixt admiring morgan nick chemical chapters worthless aristocratic nan especial hon attentive maintenance charlie explanatory differently furiously pulse scanty flee admiral clause resume compound pilot growled charmed imitate happening knot rags mock majestic messages prussian suspense + + + + +clare relationship skirt agency arisen grin unusually michigan hoarse mills intently dining demonstration depression lain expectations joining weekly trenches technical vehicle aimed borrow flattering portugal prodigious scope vegetation switzerland arkansas swelling fortified favoured salute topic blushed superb strengthen confidential crow shawl sunrise sings coats sturdy dissolved lifetime dispersed sergeant contribute strode brigade verdict they've honors panting females richest attribute brighter hook discontent orderly airs tiger messengers penetrate sabbath identification holiness crooked housekeeper productions prescribed rector spark sleeve honored tame highway alabama edmund militia nobleman energies spacious tearing affliction photograph ally hampshire ascent ditch fishes jupiter rubbing tract standards afore ribbon + + + +cecilia oregon integrity plus transparent farms pulpit ropes nineteen rescued counting perfume socrates hounds solicited bother fascinating qualified desolation essay rains renew odious assuredly suggests rider loneliness pond activities dazzling leaping squadron bowing novelty wrist keeper homeward alexandria finely li efficiency marvel tranquillity agnes charities spenser condemn elephants elders julian tries nd sweetly endurance bags reared jaw unique navigation inevitably admirably sect drum poles verge piercing sanction russians forlorn approbation organic stanley allegiance bin expressly ingenuity dispose stained theology withal duration fundraising adj collecting weigh sweetest float consul monastery raging publish knocking precaution privately aaron endeavored insight definitely stature troy + + + +miriam judah oblige urging shift mould courses countless associates hymn rapture tonight trumpet parker entrusted firmness comic breeding ken questioning factor monuments loveliness handled communities saloon stumbled witch confronted traveling seamen backed profoundly gladness pomp mess practise sanctuary superstitious casual iowa analyzed historic bored shrink judging treating expenditure encouraging diplomatic forcing studio exposure crude compilation vermont eve ascend unbroken apollo countess binding exceed frail hans champagne shuddered carter mule inserted parson rascal inspire banner divorce treacherous nineteenth invalid weaker organizations bolt ticket backwards captivity lame provoked vein lists gallop communications dagger passive shoe thrice corrected mystic infancy foam keith tavern + + + +fraud th cradle rifles vigorously censure gentleness jr sobbing monotonous explosion catastrophe respectfully wearied cats blamed needful fireplace gravel affords discovering jar selfishness tolerably clerks ark moist wid sauce prompted exceptions bullets writ bruce insolent moisture thompson furnace healing fewer deem apron humiliation punctuation rolls doe rotten richer swiss behavior nowadays pamphlet loan beads divers unreasonable realise lust ah annually detach gaily shares gifted planet feverish resurrection saul consecrated enforced vincent shelf fan fluid brightly damsel gabriel kid frantic neatly anon ascribed insane tropical th milan hardened overthrow phase achievement immortality obscurity assumption discern hopeful humorous composure turf poland dame + + + + +missionaries orator perpetually arbitrary ecstasy retirement pronounce authorized familiarity nl hastings clubs reconciled grievous mercury elegance chivalry luminous beseech benevolent confided dances perplexity escaping terrific companionship commence daisy parliament th creep pleading disdain pm sympathies guides emergency parcel suicide replies drawer contribution supposition vii weren't link homely pluck ruling patrick statesmen hannah printing joshua synonymous sinister advocate destructive environment blossom bridle yon waistcoat extends confirm listing solemnity projects reporter deprive detachment infernal traversed moss skilled announce hateful fugitive gothic coolness insurrection cum med coachman expend stepping julius resign despatch excluded reject tough plea roy fragment lacked wordsworth balcony darker mac + + + +nevada christopher fork flatter iniquity meditation disastrous stain patches hints ordained drinks whipped burial matt employee employer hypothesis steed width sweden transaction victories devout outrage vary attorney rouse doubled sidney schooner flaming offend sheriff encamped magnificence vent politely vines flags italians necessities austin nobler accusation impulses packet shabby irritated dakota industrious classic ranch ascending cruelly happiest antonio accuse insulted bridges players sixteenth solicitation embarked idol odds aims illuminated enchanted adversary pie reflecting pension luxurious pigs choir tumbled conqueror irritation verb monkey acceptable dynasty accurately divinity signature heretofore hazard dora sq stead attire fling marine occupations soothing devised singer spaces emerson + + + +disguised antique orthodox poisoned dove gratification sydney electricity alien sorely cracked supremacy summon depressed sexes offerings pledged irony recourse tortured thickly correspondent sounding sombre brushed reasonably th duel reluctantly implies cable ridden acre grieve inquiring colonists addison republican illustrate tim liverpool gilded clumsy satin displeased odor clearer prairie hudson feudal flint easter freshness nursery explanations adoption reluctance crosses blushing imported notorious equipped sinful starving eugene bedside sovereigns abrupt excused injure incessant correctly drooping adored embroidered pasture pillar import founder torch vault worm ay bravery confinement trusting butler rattle transported estimation edit gotten cuts headlong outfit insolence secrecy thereupon unlucky + + + +eighth valour grammar relaxed mentions adjacent knives attacking exceptional recollections deposit establishing muddy arches aspects senior fragrance colonial penetrating refinement te yacht intelligible stray forcibly jenny superficial tends identified wan choosing frighten grotesque reprinted tutor contributing welsh gaiety besieged robbery transmitted swam consequential slid stony donald gratify heavier confidently mabel demon treatise mechanically batteries trading cock pilgrimage extinct idleness sicily merrily excursion handling utah eminence lump boyhood montana superfluous wee dome shivering accidental thickness darwin continuance fixing harris rustic cheered vernon premises delivery nodding snowy curved productive discouraged variations shilling swollen miraculous stubborn belgium drives jerome orchard persuasion invaded alps + + + +ungrateful insensible muscle madrid flanders cultivate involuntarily speedy variation marian harp peaks daybreak magnitude precautions rub requiring coral grapes fairest locality opponent bondage beans cowardly grandson leo gertrude nail protecting hospitable proving benevolence brussels civilisation mounting desiring rushes precision watchful harness perchance forbade channels indication zealous tact seventeenth theodore stating toast dreadfully judith asterisk virgil edifice swelled accomplishment sundry reckoning mouse prostrate helm slim whistling syllable handwriting commissioners lime spur unfit gen relish reduction sown venetian cordially hush breasts slipping pat arabian dialogue forwards entreat fascination belly neutral grasping diligence disgusted retiring strokes sob vine compose valentine harvey icy inconvenience + + + +v pots dimensions abused armor detect contradiction banker infamous powerless passenger crust historians disclaim norway peculiarities sting simultaneously watches cong episode achieve populace sherman incense rebecca jordan persistent wisconsin ho ta fruitful scoundrel coasts starve denmark scots consultation habitation goat howling tailor flourish trifles dashing disappearance sour practicable shameful inviting criminals leisurely accumulated audible topics expends radiance underline parade spoils helmet consternation expenditures impose originator pa unequal wooded enduring ox valet proclaim carl impossibility lydia territories deference ravine geoffrey blanche accommodation boyish spray theological anonymous injurious formally sports ab scales wyoming discontinue calf manual disturbing potent anticipation melt tilde thames + + + +grade mischievous pang pathos alternately brisk stool justification foreigner endeavouring satire al delete masculine spies umbrella transportation yell remnant boot ignored thrilling ale mineral goose nebraska truce lastly airy sketches groves col th comprehension cling duck abyss alaska baffled planning abominable aversion drawings customers weird stewart traveled alan incessantly flattery director improbable moderation awakening males pairs temporal con nicely lapse vitality soap patriot malicious eyed pirates enforce doll briskly sez skeleton comprehensive buttons crushing personages threaten nuts undone wright frankness hides progressive rogers villa aristotle resource irs confine sewing co congratulate walt reconcile insurance terminated dusky appoint pearl thrilled gains + + + +interrupt extravagance jokes suppress quod signify layer clue kettle contemplate aforesaid tooth sensibility boldness mature cuba tolerable rabbit befallen needless yankee awaken clasp lets blinded conductor dependence guarantee affectionately player wires thicket walker outstretched procedure wheeled aye oneself recommendation projecting shriek futile cheerfulness deity fifteenth gap muscular dripping insect values brooding restaurant baptism imaginative rhyme exhaustion intrigue senseless hercules yearly baron occupying imply absurdity launched resolutely vowed attach characterized fellowship posture caps leon demanding owl beset ensuring suite tennyson thereto heaped jewel regained voluntarily longitude permanently jumping babe secondly violin rogue rainy reconciliation emotional radical accursed tendencies concrete resident lustre + + + +hull ominous overboard uproar cavern combine respectively menace pilgrims jeff peak currency silken violet khan mastery objective plucked litter memorial bids fondly clapped tariff beneficial unsolicited reluctant separately patronage revenues dragon zeus mike ranges vexation indicates overheard tray raymond thereafter exporting mound taxation frenzy horizontal thirsty disputed charter redistribution boasted item moscow termination eminently suggestive linger shady calculation expansion mast confer sophia commanders pitied twist traditional involve interfered achilles wanton repay brother in law routine son in law gaul groom solve grassy tempt unsuccessful witty politician yearning lid noticing courtiers cheering bounty consequent renown regulation fowl mayor wrinkled defy threads violation junction boss particles + + + +glories signifies constrained paternal piles hardware engaging e g peer counties mocking ch avoiding rebuke abolished cheers idiot rd morbid wrung e mail outcome gilt coldness applying strand renowned fishermen creative circus moustache proverb lowering biggest sly nursing boon weighing oklahoma brink degraded avenge hum minority spaniard ridges perils larry merchandise aloof despairing acquisition asylum chickens placid affirm trod gardener schedule calmness protector concealment trench fore accession h dey connexion cairo mend considers twenty one municipal achievements cherish deserving exert riot veteran advancement inventor meek cameron hopelessly judicious tending testify governess orchestra garb condemnation foregoing bacon maternal wasting australian strata hushed maryland sculpture + + + + +miniature corrections tangled completion regulated athenian flavor brand intimately unlimited dipped luggage inconsistent forsaken feebly woven lloyd rubbish tool spirited christendom chaos twinkling muffled accents accidentally degradation emancipation prosecution cleveland outbreak defending dwarf abundantly turner disadvantage abolition disregard deliberation filthy ak notifies dealings demonstrated paced tense drums interpreter vanish astray hen workman asunder baked baltimore bustle winged mentioning pastoral fabric trim musician twenty two patty mentally wrecked discreet godfrey apostle ledge roast accessed preface convincing quiver stocks mourn commented redistribute precipice outdated juliet dialect elementary freight cowardice wipe deserts shelves denial b traits denounced eric underground phantom whirling pecuniary dire hostilities + + + +gait it'll vividly instruct dickens puritan clutched acknowledgment conjunction oppressive intermediate formula hungary sneer ore plentiful plump combinations purest cheat doubly inadequate leslie blest forbear haunt treaties fearless constable enveloped enmity watson bridegroom curate developing frock mining audacity improper motto parisian faction architect melting delicately register heroine indefinite console defensive perceptible fruitless ransom surplus solicitude effectual shiver gal wed contemptuous plough snakes felicity reef outset constitutes lament tissue draft impelled epic fisherman hawaii obstinacy ulysses lemon voltaire hound measuring conscientious robber toy impart statute barry girdle basil rebellious stair biting consulting perseverance manila massacre cough blazed claude transition button headache + + + +tenant burns harmonious dreamy burgundy collections unkind inscribed cushions programme din laborious manufacturing markets zone humane ac fertility languid ninth curses introducing alcohol impending declining advantageous heal millennium karl ft staid planting theatrical spectator winchester greedy commonwealth suffrage tremulous commodities stuffed admitting aching ninety discomfort imperative montreal bobby bachelor geographical longest courageous carpenter sundays concluding danish steer influential surround random ounce afresh dictated ruddy rusty drown irving slide sow appalling profess sickly rides spoon imminent dominant leadership pinch wearily ducks diary duchess regain rum churchyard fondness apprehend ordinarily quicker thereon ni balloon individuality securely connecting celebrate bluff dawned amiss chalk + + + +sticking fuss dazed deputy forsake automobile discussions harrison refreshment amendment appealing eden vertical insufficient manchester hem gorge baptized damn silvery pastor inherent preventing inference advertisement mutton packing enclosure theft publisher spontaneous otto rats apparition refreshing irene sweetheart renounce lifeless adore vinegar normandy uncovered utility orphan symbols gracefully mightily peculiarity ash floods partake contemptible deities profane foreseen ti conceit commend twelfth bristol manifestation revive prone connect princely overtake improving downwards ferocious intervention subsistence susceptible tunnel disciple revival twins ivy puzzle citadel temporarily despotism internet mechanism stoop directors mathematics raft fade soothe pork substituted physically brilliancy dot loaf expanse shocking rudely isle + + + +balanced extracted fable matches index gerard cigars liver transmit dispatch onto veranda dip inexplicable liar diminish dungeon unit pagan phillips brig monopoly rim sordid complaining temperate chat gambling maps amber trot howl shipping ton magazines bricks submarine roberts cumberland cecil semblance palestine perpendicular regardless fervent sane wreath animation earthquake sloping smoothly tension intrigues fearfully macaulay laboratory cork comments whale wedded whiteness convicted deception paved scruple paintings therewith religions governing colleagues shrinking tickets prophetic undergo hare haze poisonous omit beware sagacity concession worker ted incline caste leapt dissatisfied hardest self control toilet buddha offense woodland gentry starvation grudge penance tips rooted outburst + + + +fortitude turk devour malignant accorded brandon anticipate speechless inquisition eccentric anecdote annals scrutiny burroughs rhythm discord marius diversion archie rat knit correspond detain dis esp interpret vehement soda naughty salon operate idly imperious peru candid whig blooming wharf disgraceful stunned redemption drain wage cooper embassy unfinished nasty impetuous cemetery oblivion prohibited breeches abound christine frivolous hugo essays plaster tap chairman dismiss katherine provoke reside deficient decoration heroism toe wade apparel hazel inability farthest invent knave twain carelessness affectation connections climax avowed industries brood tempting define antwerp forefathers stretches gratifying plight restricted cupboard ludicrous alms colossal stupidity monotony stimulus vigilance digest + + + +vale overcoat colorado wink nous rack incomprehensible antagonist methinks barley plateau superintendent indescribable expanded presentation archbishop devise rubber adieu exclude carts lone whisky abuses inflict nightfall counts chocolate privileged hermit exultation overtook coincidence scratch screw caravan divert eliza comparing hood explore glove chaste whirl adventurous skipper tiresome implements recompense plank insure laboured exaggeration mi shepherds lilies ballad befall cylinder teddy summary daresay photographs colleges dissolution geneva marches instituted seals vehemence chaplain knots wail kneel unlikely deceit challenged geography herald lowly peep swarm clarke joyfully engraved ll bowels purposely blindness systematic virtually conformity remedies maxim indexes marshall baking invincible impertinent bust + + + + +visage intuition mingle bathing arched investment tabernacle client ghostly furs catalogue dock tenor arouse verbal excessively brazil strenuous irishman recess unclean psalms analogy chemistry peninsula infer maritime secular hawk rein averted bake constantine oracle alley softness pierce spinning snatch manufactured launch psychology worms regulate farming fasten actress etiquette theater thanksgiving valor untouched tactics drug adverse gaunt conducting veritable overtaken distorted rosa nina quart caprice candy obliging planets soothed sic opium pavilion strait sanguine cords odour trout paste regularity metallic scrap convict instructive investigate celtic package pirate fiend moan revealing trades rounds accomplishments crawl aft prevalent role dose evans hypocrisy + + + +l salmon snap alma magical tire hetty impenetrable geese madly manifold noticeable pudding volcanic locke magnetic deals core decency observance durst scratched predecessor diplomacy wert impartial disinterested wig pump swedish norfolk reigns similarly reap dam facilities slippery transformation oxygen suburbs dares ornamental pondered fringe raiment henrietta wellington foreman feat thirteenth sultan certificate rue heresy arabia medal location ether ruby heading subdue adorn ancestor warmer cluster quotation fullest exposition custody thermometer plausible toss desperation rhetoric scornful bailey rung civility dingy scaffold concentration avarice scrape pools oar flutter martyr handy montague bait login commotion congenial drawers telescope deposits edwards craving bureau oscar + + + + +speculative huddled diverse slice renaissance angelo meg murderous serenity perspiration coventry impudent ardor necklace alight stimulated clifford steadfast genoa anglo saxon courier inflamed xi drill spelling respond seriousness fourteenth womb literal singers usefulness cloudy mortality profusion fleeting twentieth maturity surf weed phases overcame womanhood envious tapped latent whiskey relatively forbidding cleopatra willow mathematical sojourn booty camel implore amateur morally qualifications gasp gliding tested racing brightest joel extremes damascus labored peggy exit originality humming isolation sometime glee adult solace biography ff hardship lied donkey trader rumour amply confide favors perspective belgian withstand robust pro val eats snare monthly wines ignore envoy + + + +flown reverie jehovah contrive chatter judas nourishment reforms clatter adrian allude corrupted thorn junior tony calcutta re holt psychological constancy misunderstood signals drying harshly distressing novelist cyril editors intricate limestone forty five collision pebbles willie knitting ordeal foresee peas repast supplying clan abject dart berth bridal indirect unnoticed tint insults precedent twisting bully vacation 'll canon aisle click inspiring oval impracticable delirium cedar contradict ingratitude soften bewilderment servitude comely stump redeem spun elastic poultry horseman dictionary prettiest adoration icel wager involving pathway essex wistful advent gear celebration conceivable drowning faintest acquiring befell good looking wares rendezvous snug watery accompaniment chaps crawling lumber + + + +publishing customer mediaeval prints lavish md genesis rug analogous eleventh noah galley partition blunder glasgow fanciful ham rainbow sentinel hereby outlook smitten unmarried mice installed vivacity marking aesthetic consume resent pose contentment sterling veneration p m barking bower organism unintelligible emphatic occurring factors guise editorial impudence midday corporal sg aright nigger lily noun scout spit cursing friedrich manifestly marco battalion heritage brotherhood nun wad folding discerned powerfully mitchell helpful persist ellis frigate spotted atoms curves outlet erroneous violated withheld fairies inherit sledge taller supervision butt handsomely tank velocity arctic colleague pins butcher drowsy butterfly chart twin sunken exasperated narrowly collins insulting + + + +deficiency operating overthrown gallows diligent hindu blunt omen bleak vehemently wretchedness e'er ensure denotes sentenced unfair encampment possessor absorbing descendant sub drugs engineers independently bucket clerical ache glitter ordinance bamboo amsterdam vocation admirer limp pallid mildly organisation timothy dealer yorkshire auspicious deuce emblem gibson primarily reducing ritual decorations thigh groaning scant fiscal mien charging cor railing peers inferred sanctity accumulation cynical inspector wardrobe jesuit texture adjustment epistle adventurer priesthood seaman turbulent chant marsh palmer unaware vase ty initial baths weighty minimum correction morsel overlook meagre unanimous magician mystical twenty three inhabit shaggy unaccountable nightmare carbon coil lawless stairway willingness sarcasm crisp + + + +jerk tout vocabulary stroll poorly composing parliamentary controlling fitness thoughtless soames temperance illumination translations martyrdom mellow nationality jam austere shoots casually pensive flavour nets dice satisfactorily shrunk administer ante swine baptist listener unimportant genera contrivance deplorable museum benefactor tints alphabet rout scatter boer ftp steve extant bohemia misunderstanding universities dexterity rag inseparable punch brazen economical pernicious craig mythology drained bolted abel stride circumference meddle axis gum las kinder closes ferocity giddy secluded resisting satisfying reliable disgusting thirty six ethical raleigh crouching lash recital buddhist collapse unsatisfactory lore varies mainland scot repute cushion confound scrub myth flights oats layers ownership cape glimmer + + + + +scare waked bengal scrupulous equals redress brake nut stability crafty kirk bough momentous albeit enlarge hardness civilised dotted defiant timidity solar heartless thomson mat shun raid disclose suppression puff juncture beak unjustly foresaw rot aggressive predicted quaker grate lease ponderous maketh repaid charcoal chilly arrogance friction participation pier stale intoxicated commissioned ratio comb masterpiece wholesale embraces trodden ephraim shaw translate mortar recreation rite truthful cavalier caress si curling rivalry whim abreast thebes faust peg wilhelm pestilence ceremonial receiver sample distinctive consummate matron claiming plural initiative inexhaustible a m spider reed streak blocked titus smashed populous baronet commodore jelly advocates dinah + + + +salutation mutiny chronicles comforting serviceable parchment playful potato transient administrative anarchy barber revision operated farce germ profile provides noting disordered menacing heightened finance averse azure bathe campaigns lessen slate acquaint gin humiliating cleft conveyance chivalrous capricious tribune pilgrim entreaty womanly paltry sporting maker digestion bart infamy lambs gaping periodical standpoint amorous tub luxuriant basic mutually chris greed premature extinction boiler intimation scandalous separating oratory banish electrical herb multiply prosper friar nightly ole monkeys interminable enjoys similarity riddle cleaning subscription copious exclaim forged voting scourge darkly privacy arena bearded vera alacrity sensual spin neutrality flannel fasting trailer avert trustworthy jamaica unchanged + + + +traveler unfamiliar puffed mirrors phoebe father in law conform particle railways stupendous paddle innate reformation volley statistics agrees simpler padre congratulations lids muse inhabitant ishmael rustle clump calendar flute inaccessible yore jay repulsive fray po nomination conclusive peaceable beth inconceivable e'en emerald lava trillion uppermost arduous lyric downright reproduction foresight consistency ape senators pallor span salad snuff drooped greetings chestnut inquisitive vicar noel attic savings affirmative ills applications t dye gloucester nominal demonstrate dispense dissatisfaction merciless trusty coloring perusal plaintive discarded precarious infection ruinous bolts arithmetic considerate lark ethics conventions stumbling pitcher slips seine officially danube annoy glide impunity amends sol conveying + + + +abandonment mane tinge brim forenoon seventy five sparkle syllables shrug enchantment franz trait bribe composer preparatory audacious outskirts soiled fiddle football isaiah partnership continuation pioneer vest bass derby quarry rigging dizzy abnormal omission idolatry sequence squeeze cabbage canopy athletic shirley drunkenness intrusion 'cause assign tackle dreamt sceptre exacting parched eddy percentage twinkle curb sandstone invaluable fathom preferable adelaide advertising scraps lever muster cavity barbarian sleepless fried abstraction forefinger spade erection scorned pail withdrawal senator mortgage ancestral succour ma forbearance repress spouse valid witchcraft workmanship legacy proximity bombay paula incorporated muzzle reuben clusters valve compelling dissipated flickering guinea sup tarry derision vehicles + + + +accommodate glossy iris relic ant heath bug vocal downfall construct undue vapor bat whimsical contradictory unlocked foretold automatic explicit indolent mates artful downcast well being winston ordinances catharine effectively missions stalk indistinct pregnant reddish coveted fret peeping buck sumptuous indefinitely reliance panama cocked dad everyday intoxication aghast subterranean turmoil forfeit chasm inspect perverse precipitate dover ambush evermore mass blot nook verdure parapet jake cessation ankle classification fervently oddly haul saxony embarrassing hairy northwest disabled laurel preston arrogant hurts demonstrations splash curl livelihood wary scattering brace converts detestable abandoning somerset weakly clothe gem tremor surveying variable anniversary thirty two wrap curly diversity + + + + +prestige desertion freezing heedless sentry believer ram rowing negligence self sulphur discrimination cooling millionaire flowering meridian wins awed beastly nuisance abstain continental stanza target unwonted whit jason stall sham dictate empress gout jobs manure nigel sidewalk sate grievance axes bony invest birmingham ebb rabble restlessness cruise rally rumor hysterical girlish actively shortest marseilles cheque disregarded retort rocking emerge perch flask ka countryman lonesome manned unarmed wast frog twenty eight unscrupulous yarn victuals outrageous appropriation foolishness quickness adversity parma diseased iliad salutary smelt territorial hurricane irons canyon jeremiah brooklyn indulging vapour disobedience atrocious leaps tapestry provocation twenty six impotent smite acquitted os tumultuous + + + +barge palpable apprentice lances compartment godly sarcastic therefrom specifically uniformity emerging atonement whereabouts davy framework sponge mountainous annoying cot squirrel wand grind bang unreal blacksmith injunction scarcity withhold outright bavaria cement growl aggregate fraction exaltation inexorable jug purer sap illegal sister in law presses stealthily dissolve volcano hungarian equilibrium obstinately sullenly assassination commissions respectability bases maxwell resounded closest embroidery gunpowder reproof yale combining weaving earnings hamburg indoors manufacturers pitiless scarf picnic misled pompous brian respite exploit tracing geological passport confines dishonour executioner township vacancy acquiescence cornwall crumbling three quarters exploration needy stationary disconcerted wanderer beaver lookout onion depicted boisterous couples speakers woollen lightness + + + +bitten aux toleration lucia scar bohemian vested affinity carlo sous penitent simpson abiding ca immoral dishonest yawning mustache supplement whirlwind clash terence lamentable bennett farthing speck biscuit appellation gdp reserves uncouth birch armchair judy greasy leaden dough lining cleverness ascetic clutch krishna embark quotations friendliness liberally trance untrue rejection grating hanover inexperienced mon wintry stalwart meats stamping variance apiece firmament absorption apprehensive terminate wilful conveniently 'n' cleanliness collective angela filth philippines timely herein ignoble canton lamentations moslem ware adjective glen invade livid buggy prolong weaken folio dismissal quay enchanting heave purified syrian significantly experimental film repressed cooperation sequel wench calves +Retrieved from "http //en wiktionary org/wiki/Wiktionary Frequency_lists/PG/ / / " + +def g(): + global big + big = file('big.txt').read() + N = len(big) + s = set() + for i in xrange(6, N): + c = big[i] + if ord(c) > 127 and c not in s: + print i, c, ord(c), big[max(0, i-10):min(N, i+10)] + s.add(c) + print s + print [ord(c) for c in s] diff --git a/testdocs/sqlite3.c b/testdocs/sqlite3.c new file mode 100644 index 0000000..fcc3da2 --- /dev/null +++ b/testdocs/sqlite3.c @@ -0,0 +1,202918 @@ +/****************************************************************************** +** This file is an amalgamation of many separate C source files from SQLite +** version 3.19.3. By combining all the individual C code files into this +** single large file, the entire code can be compiled as a single translation +** unit. This allows many compilers to do optimizations that would not be +** possible if the files were compiled separately. Performance improvements +** of 5% or more are commonly seen when SQLite is compiled as a single +** translation unit. +** +** This file is all you need to compile SQLite. To use SQLite in other +** programs, you need this file and the "sqlite3.h" header file that defines +** the programming interface to the SQLite library. (If you do not have +** the "sqlite3.h" header file at hand, you will find a copy embedded within +** the text of this file. Search for "Begin file sqlite3.h" to find the start +** of the embedded sqlite3.h header file.) Additional code files may be needed +** if you want a wrapper to interface SQLite with your choice of programming +** language. The code for the "sqlite3" command-line shell is also in a +** separate file. This file contains only code for the core SQLite library. +*/ +#define SQLITE_CORE 1 +#define SQLITE_AMALGAMATION 1 +#ifndef SQLITE_PRIVATE +# define SQLITE_PRIVATE static +#endif +/************** Begin file sqliteInt.h ***************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** Internal interface definitions for SQLite. +** +*/ +#ifndef SQLITEINT_H +#define SQLITEINT_H + +/* Special Comments: +** +** Some comments have special meaning to the tools that measure test +** coverage: +** +** NO_TEST - The branches on this line are not +** measured by branch coverage. This is +** used on lines of code that actually +** implement parts of coverage testing. +** +** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false +** and the correct answer is still obtained, +** though perhaps more slowly. +** +** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true +** and the correct answer is still obtained, +** though perhaps more slowly. +** +** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread +** that would be harmless and undetectable +** if it did occur. +** +** In all cases, the special comment must be enclosed in the usual +** slash-asterisk...asterisk-slash comment marks, with no spaces between the +** asterisks and the comment text. +*/ + +/* +** Make sure the Tcl calling convention macro is defined. This macro is +** only used by test code and Tcl integration code. +*/ +#ifndef SQLITE_TCLAPI +# define SQLITE_TCLAPI +#endif + +/* +** Make sure that rand_s() is available on Windows systems with MSVC 2005 +** or higher. +*/ +#if defined(_MSC_VER) && _MSC_VER>=1400 +# define _CRT_RAND_S +#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 +** that are included by this file. +*/ +/************** Include msvc.h in the middle of sqliteInt.h ******************/ +/************** Begin file msvc.h ********************************************/ +/* +** 2015 January 12 +** +** 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 that is specific to MSVC. +*/ +#ifndef SQLITE_MSVC_H +#define SQLITE_MSVC_H + +#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) */ + +#endif /* SQLITE_MSVC_H */ + +/************** End of msvc.h ************************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ + +/* +** Special setup for VxWorks +*/ +/************** Include vxworks.h in the middle of sqliteInt.h ***************/ +/************** Begin file vxworks.h *****************************************/ +/* +** 2015-03-02 +** +** 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 that is specific to Wind River's VxWorks +*/ +#if defined(__RTP__) || defined(_WRS_KERNEL) +/* This is VxWorks. Set up things specially for that OS +*/ +#include +#include /* amalgamator: dontcache */ +#define OS_VXWORKS 1 +#define SQLITE_OS_OTHER 0 +#define SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1 +#define SQLITE_OMIT_LOAD_EXTENSION 1 +#define SQLITE_ENABLE_LOCKING_STYLE 0 +#define HAVE_UTIME 1 +#else +/* This is not VxWorks. */ +#define OS_VXWORKS 0 +#define HAVE_FCHOWN 1 +#define HAVE_READLINK 1 +#define HAVE_LSTAT 1 +#endif /* defined(_WRS_KERNEL) */ + +/************** End of vxworks.h *********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ + +/* +** These #defines should enable >2GB file support on POSIX if the +** underlying operating system supports it. If the OS lacks +** large file support, or if the OS is windows, these should be no-ops. +** +** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any +** system #includes. Hence, this block of code must be the very first +** code in all source files. +** +** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch +** on the compiler command line. This is necessary if you are compiling +** on a recent machine (ex: Red Hat 7.2) but you want your code to work +** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2 +** without this option, LFS is enable. But LFS does not exist in the kernel +** in Red Hat 6.0, so the code won't work. Hence, for maximum binary +** portability you should omit LFS. +** +** The previous paragraph was written in 2005. (This paragraph is written +** on 2008-11-28.) These days, all Linux kernels support large files, so +** you should probably leave LFS enabled. But some embedded platforms might +** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful. +** +** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later. +*/ +#ifndef SQLITE_DISABLE_LFS +# define _LARGE_FILE 1 +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# define _LARGEFILE_SOURCE 1 +#endif + +/* The GCC_VERSION and MSVC_VERSION macros are used to +** conditionally include optimizations for each of these compilers. A +** value of 0 means that compiler is not being used. The +** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific +** optimizations, and hence set all compiler macros to 0 +** +** There was once also a CLANG_VERSION macro. However, we learn that the +** version numbers in clang are for "marketing" only and are inconsistent +** and unreliable. Fortunately, all versions of clang also recognize the +** gcc version numbers and have reasonable settings for gcc version numbers, +** so the GCC_VERSION macro will be set to a correct non-zero value even +** when compiling with clang. +*/ +#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) +# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) +#else +# define GCC_VERSION 0 +#endif +#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) +# define MSVC_VERSION _MSC_VER +#else +# define MSVC_VERSION 0 +#endif + +/* Needed for various definitions... */ +#if defined(__GNUC__) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif + +#if defined(__OpenBSD__) && !defined(_BSD_SOURCE) +# define _BSD_SOURCE +#endif + +/* +** For MinGW, check to see if we can include the header file containing its +** version information, among other things. Normally, this internal MinGW +** header file would [only] be included automatically by other MinGW header +** files; however, the contained version information is now required by this +** header file to work around binary compatibility issues (see below) and +** this is the only known way to reliably obtain it. This entire #if block +** would be completely unnecessary if there was any other way of detecting +** MinGW via their preprocessor (e.g. if they customized their GCC to define +** some MinGW-specific macros). When compiling for MinGW, either the +** _HAVE_MINGW_H or _HAVE__MINGW_H (note the extra underscore) macro must be +** defined; otherwise, detection of conditions specific to MinGW will be +** disabled. +*/ +#if defined(_HAVE_MINGW_H) +# include "mingw.h" +#elif defined(_HAVE__MINGW_H) +# include "_mingw.h" +#endif + +/* +** For MinGW version 4.x (and higher), check to see if the _USE_32BIT_TIME_T +** define is required to maintain binary compatibility with the MSVC runtime +** library in use (e.g. for Windows XP). +*/ +#if !defined(_USE_32BIT_TIME_T) && !defined(_USE_64BIT_TIME_T) && \ + defined(_WIN32) && !defined(_WIN64) && \ + defined(__MINGW_MAJOR_VERSION) && __MINGW_MAJOR_VERSION >= 4 && \ + defined(__MSVCRT__) +# define _USE_32BIT_TIME_T +#endif + +/* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear +** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for +** MinGW. +*/ +/************** Include sqlite3.h in the middle of sqliteInt.h ***************/ +/************** Begin file sqlite3.h *****************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface that the SQLite library +** presents to client programs. If a C-function, structure, datatype, +** or constant definition does not appear in this file, then it is +** not a published API of SQLite, is subject to change without +** notice, and should not be referenced by programs that use SQLite. +** +** Some of the definitions that are in this file are marked as +** "experimental". Experimental interfaces are normally new +** features recently added to SQLite. We do not anticipate changes +** to experimental interfaces but reserve the right to make minor changes +** if experience from use "in the wild" suggest such changes are prudent. +** +** The official C-language API documentation for SQLite is derived +** from comments in this file. This file is the authoritative source +** on how SQLite interfaces are supposed to operate. +** +** The name of this file under configuration management is "sqlite.h.in". +** The makefile makes some minor changes to this file (such as inserting +** the version number) and changes its name to "sqlite3.h" as +** part of the build process. +*/ +#ifndef SQLITE3_H +#define SQLITE3_H +#include /* Needed for the definition of va_list */ + +/* +** Make sure we can call this stuff from C++. +*/ +#if 0 +extern "C" { +#endif + + +/* +** Provide the ability to override linkage features of the interface. +*/ +#ifndef SQLITE_EXTERN +# define SQLITE_EXTERN extern +#endif +#ifndef SQLITE_API +# define SQLITE_API +#endif +#ifndef SQLITE_CDECL +# define SQLITE_CDECL +#endif +#ifndef SQLITE_APICALL +# define SQLITE_APICALL +#endif +#ifndef SQLITE_STDCALL +# define SQLITE_STDCALL SQLITE_APICALL +#endif +#ifndef SQLITE_CALLBACK +# define SQLITE_CALLBACK +#endif +#ifndef SQLITE_SYSAPI +# define SQLITE_SYSAPI +#endif + +/* +** These no-op macros are used in front of interfaces to mark those +** interfaces as either deprecated or experimental. New applications +** should not use deprecated interfaces - they are supported for backwards +** compatibility only. Application writers should be aware that +** experimental interfaces are subject to change in point releases. +** +** These macros used to resolve to various kinds of compiler magic that +** would generate warning messages when they were used. But that +** compiler magic ended up generating such a flurry of bug reports +** that we have taken it all out and gone back to using simple +** noop macros. +*/ +#define SQLITE_DEPRECATED +#define SQLITE_EXPERIMENTAL + +/* +** Ensure these symbols were not defined by some previous header file. +*/ +#ifdef SQLITE_VERSION +# undef SQLITE_VERSION +#endif +#ifdef SQLITE_VERSION_NUMBER +# undef SQLITE_VERSION_NUMBER +#endif + +/* +** CAPI3REF: Compile-Time Library Version Numbers +** +** ^(The [SQLITE_VERSION] C preprocessor macro in the sqlite3.h header +** evaluates to a string literal that is the SQLite version in the +** format "X.Y.Z" where X is the major version number (always 3 for +** SQLite3) and Y is the minor version number and Z is the release number.)^ +** ^(The [SQLITE_VERSION_NUMBER] C preprocessor macro resolves to an integer +** with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same +** numbers used in [SQLITE_VERSION].)^ +** The SQLITE_VERSION_NUMBER for any given release of SQLite will also +** be larger than the release from which it is derived. Either Y will +** be held constant and Z will be incremented or else Y will be incremented +** and Z will be reset to zero. +** +** Since [version 3.6.18] ([dateof:3.6.18]), +** SQLite source code has been stored in the +** Fossil configuration management +** system. ^The SQLITE_SOURCE_ID macro evaluates to +** a string which identifies a particular check-in of SQLite +** within its configuration management system. ^The SQLITE_SOURCE_ID +** string contains the date and time of the check-in (UTC) and a SHA1 +** or SHA3-256 hash of the entire source tree. +** +** See also: [sqlite3_libversion()], +** [sqlite3_libversion_number()], [sqlite3_sourceid()], +** [sqlite_version()] and [sqlite_source_id()]. +*/ +#define SQLITE_VERSION "3.19.3" +#define SQLITE_VERSION_NUMBER 3019003 +#define SQLITE_SOURCE_ID "2017-06-08 14:26:16 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b" + +/* +** CAPI3REF: Run-Time Library Version Numbers +** KEYWORDS: sqlite3_version sqlite3_sourceid +** +** These interfaces provide the same information as the [SQLITE_VERSION], +** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros +** but are associated with the library instead of the header file. ^(Cautious +** programmers might include assert() statements in their application to +** verify that values returned by these interfaces match the macros in +** the header, and thus ensure that the application is +** compiled with matching library and header files. +** +**
+** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
+** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
+** 
)^ +** +** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] +** macro. ^The sqlite3_libversion() function returns a pointer to the +** to the sqlite3_version[] string constant. The sqlite3_libversion() +** function is provided for use in DLLs since DLL users usually do not have +** direct access to string constants within the DLL. ^The +** sqlite3_libversion_number() function returns an integer equal to +** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns +** a pointer to a string constant whose value is the same as the +** [SQLITE_SOURCE_ID] C preprocessor macro. +** +** See also: [sqlite_version()] and [sqlite_source_id()]. +*/ +SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; +SQLITE_API const char *sqlite3_libversion(void); +SQLITE_API const char *sqlite3_sourceid(void); +SQLITE_API int sqlite3_libversion_number(void); + +/* +** CAPI3REF: Run-Time Library Compilation Options Diagnostics +** +** ^The sqlite3_compileoption_used() function returns 0 or 1 +** indicating whether the specified option was defined at +** compile time. ^The SQLITE_ prefix may be omitted from the +** option name passed to sqlite3_compileoption_used(). +** +** ^The sqlite3_compileoption_get() function allows iterating +** over the list of options that were defined at compile time by +** returning the N-th compile time option string. ^If N is out of range, +** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ +** prefix is omitted from any strings returned by +** sqlite3_compileoption_get(). +** +** ^Support for the diagnostic functions sqlite3_compileoption_used() +** and sqlite3_compileoption_get() may be omitted by specifying the +** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. +** +** See also: SQL functions [sqlite_compileoption_used()] and +** [sqlite_compileoption_get()] and the [compile_options pragma]. +*/ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_API int sqlite3_compileoption_used(const char *zOptName); +SQLITE_API const char *sqlite3_compileoption_get(int N); +#endif + +/* +** CAPI3REF: Test To See If The Library Is Threadsafe +** +** ^The sqlite3_threadsafe() function returns zero if and only if +** SQLite was compiled with mutexing code omitted due to the +** [SQLITE_THREADSAFE] compile-time option being set to 0. +** +** SQLite can be compiled with or without mutexes. When +** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes +** are enabled and SQLite is threadsafe. When the +** [SQLITE_THREADSAFE] macro is 0, +** the mutexes are omitted. Without the mutexes, it is not safe +** to use SQLite concurrently from more than one thread. +** +** Enabling mutexes incurs a measurable performance penalty. +** So if speed is of utmost importance, it makes sense to disable +** the mutexes. But for maximum safety, mutexes should be enabled. +** ^The default behavior is for mutexes to be enabled. +** +** This interface can be used by an application to make sure that the +** version of SQLite that it is linking against was compiled with +** the desired setting of the [SQLITE_THREADSAFE] macro. +** +** This interface only reports on the compile-time mutex setting +** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with +** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but +** can be fully or partially disabled using a call to [sqlite3_config()] +** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], +** or [SQLITE_CONFIG_SERIALIZED]. ^(The return value of the +** sqlite3_threadsafe() function shows only the compile-time setting of +** thread safety, not any run-time changes to that setting made by +** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() +** is unchanged by calls to sqlite3_config().)^ +** +** See the [threading mode] documentation for additional information. +*/ +SQLITE_API int sqlite3_threadsafe(void); + +/* +** CAPI3REF: Database Connection Handle +** KEYWORDS: {database connection} {database connections} +** +** Each open SQLite database is represented by a pointer to an instance of +** the opaque structure named "sqlite3". It is useful to think of an sqlite3 +** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and +** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] +** and [sqlite3_close_v2()] are its destructors. There are many other +** interfaces (such as +** [sqlite3_prepare_v2()], [sqlite3_create_function()], and +** [sqlite3_busy_timeout()] to name but three) that are methods on an +** sqlite3 object. +*/ +typedef struct sqlite3 sqlite3; + +/* +** CAPI3REF: 64-Bit Integer Types +** KEYWORDS: sqlite_int64 sqlite_uint64 +** +** Because there is no cross-platform way to specify 64-bit integer types +** SQLite includes typedefs for 64-bit signed and unsigned integers. +** +** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions. +** The sqlite_int64 and sqlite_uint64 types are supported for backwards +** compatibility only. +** +** ^The sqlite3_int64 and sqlite_int64 types can store integer values +** between -9223372036854775808 and +9223372036854775807 inclusive. ^The +** sqlite3_uint64 and sqlite_uint64 types can store integer values +** between 0 and +18446744073709551615 inclusive. +*/ +#ifdef SQLITE_INT64_TYPE + typedef SQLITE_INT64_TYPE sqlite_int64; +# ifdef SQLITE_UINT64_TYPE + typedef SQLITE_UINT64_TYPE sqlite_uint64; +# else + typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; +# endif +#elif defined(_MSC_VER) || defined(__BORLANDC__) + typedef __int64 sqlite_int64; + typedef unsigned __int64 sqlite_uint64; +#else + typedef long long int sqlite_int64; + typedef unsigned long long int sqlite_uint64; +#endif +typedef sqlite_int64 sqlite3_int64; +typedef sqlite_uint64 sqlite3_uint64; + +/* +** If compiling for a processor that lacks floating point support, +** substitute integer for floating-point. +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# define double sqlite3_int64 +#endif + +/* +** CAPI3REF: Closing A Database Connection +** DESTRUCTOR: sqlite3 +** +** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors +** for the [sqlite3] object. +** ^Calls to sqlite3_close() and sqlite3_close_v2() return [SQLITE_OK] if +** the [sqlite3] object is successfully destroyed and all associated +** resources are deallocated. +** +** ^If the database connection is associated with unfinalized prepared +** statements or unfinished sqlite3_backup objects then sqlite3_close() +** will leave the database connection open and return [SQLITE_BUSY]. +** ^If sqlite3_close_v2() is called with unfinalized prepared statements +** and/or unfinished sqlite3_backups, then the database connection becomes +** an unusable "zombie" which will automatically be deallocated when the +** last prepared statement is finalized or the last sqlite3_backup is +** finished. The sqlite3_close_v2() interface is intended for use with +** host languages that are garbage collected, and where the order in which +** destructors are called is arbitrary. +** +** Applications should [sqlite3_finalize | finalize] all [prepared statements], +** [sqlite3_blob_close | close] all [BLOB handles], and +** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated +** with the [sqlite3] object prior to attempting to close the object. ^If +** sqlite3_close_v2() is called on a [database connection] that still has +** outstanding [prepared statements], [BLOB handles], and/or +** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation +** of resources is deferred until all [prepared statements], [BLOB handles], +** and [sqlite3_backup] objects are also destroyed. +** +** ^If an [sqlite3] object is destroyed while a transaction is open, +** the transaction is automatically rolled back. +** +** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)] +** must be either a NULL +** pointer or an [sqlite3] object pointer obtained +** from [sqlite3_open()], [sqlite3_open16()], or +** [sqlite3_open_v2()], and not previously closed. +** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer +** argument is a harmless no-op. +*/ +SQLITE_API int sqlite3_close(sqlite3*); +SQLITE_API int sqlite3_close_v2(sqlite3*); + +/* +** The type for a callback function. +** This is legacy and deprecated. It is included for historical +** compatibility and is not documented. +*/ +typedef int (*sqlite3_callback)(void*,int,char**, char**); + +/* +** CAPI3REF: One-Step Query Execution Interface +** METHOD: sqlite3 +** +** The sqlite3_exec() interface is a convenience wrapper around +** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], +** that allows an application to run multiple statements of SQL +** without having to use a lot of C code. +** +** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, +** semicolon-separate SQL statements passed into its 2nd argument, +** in the context of the [database connection] passed in as its 1st +** argument. ^If the callback function of the 3rd argument to +** sqlite3_exec() is not NULL, then it is invoked for each result row +** coming out of the evaluated SQL statements. ^The 4th argument to +** sqlite3_exec() is relayed through to the 1st argument of each +** callback invocation. ^If the callback pointer to sqlite3_exec() +** is NULL, then no callback is ever invoked and result rows are +** ignored. +** +** ^If an error occurs while evaluating the SQL statements passed into +** sqlite3_exec(), then execution of the current statement stops and +** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() +** is not NULL then any error message is written into memory obtained +** from [sqlite3_malloc()] and passed back through the 5th parameter. +** To avoid memory leaks, the application should invoke [sqlite3_free()] +** on error message strings returned through the 5th parameter of +** sqlite3_exec() after the error message string is no longer needed. +** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors +** occur, then sqlite3_exec() sets the pointer in its 5th parameter to +** NULL before returning. +** +** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() +** routine returns SQLITE_ABORT without invoking the callback again and +** without running any subsequent SQL statements. +** +** ^The 2nd argument to the sqlite3_exec() callback function is the +** number of columns in the result. ^The 3rd argument to the sqlite3_exec() +** callback is an array of pointers to strings obtained as if from +** [sqlite3_column_text()], one for each column. ^If an element of a +** result row is NULL then the corresponding string pointer for the +** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the +** sqlite3_exec() callback is an array of pointers to strings where each +** entry represents the name of corresponding result column as obtained +** from [sqlite3_column_name()]. +** +** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer +** to an empty string, or a pointer that contains only whitespace and/or +** SQL comments, then no SQL statements are evaluated and the database +** is not changed. +** +** Restrictions: +** +**
    +**
  • The application must ensure that the 1st parameter to sqlite3_exec() +** is a valid and open [database connection]. +**
  • The application must not close the [database connection] specified by +** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. +**
  • The application must not modify the SQL statement text passed into +** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. +**
+*/ +SQLITE_API int sqlite3_exec( + sqlite3*, /* An open database */ + const char *sql, /* SQL to be evaluated */ + int (*callback)(void*,int,char**,char**), /* Callback function */ + void *, /* 1st argument to callback */ + char **errmsg /* Error msg written here */ +); + +/* +** CAPI3REF: Result Codes +** KEYWORDS: {result code definitions} +** +** Many SQLite functions return an integer result code from the set shown +** here in order to indicate success or failure. +** +** New error codes may be added in future versions of SQLite. +** +** See also: [extended result code definitions] +*/ +#define SQLITE_OK 0 /* Successful result */ +/* beginning-of-error-codes */ +#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ +#define SQLITE_PERM 3 /* Access permission denied */ +#define SQLITE_ABORT 4 /* Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* The database file is locked */ +#define SQLITE_LOCKED 6 /* A table in the database is locked */ +#define SQLITE_NOMEM 7 /* A malloc() failed */ +#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ +#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ +#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ +#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ +#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ +#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 /* Database is empty */ +#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 */ +#define SQLITE_MISMATCH 20 /* Data type mismatch */ +#define SQLITE_MISUSE 21 /* Library used incorrectly */ +#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ +#define SQLITE_AUTH 23 /* Authorization denied */ +#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ +#define SQLITE_NOTADB 26 /* File opened that is not a database file */ +#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ +#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ +#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ +#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ +/* end-of-error-codes */ + +/* +** CAPI3REF: Extended Result Codes +** KEYWORDS: {extended result code definitions} +** +** In its default configuration, SQLite API routines return one of 30 integer +** [result codes]. However, experience has shown that many of +** these result codes are too coarse-grained. They do not provide as +** much information about problems as programmers might like. In an effort to +** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] +** and later) include +** support for additional result codes that provide more detailed information +** about errors. These [extended result codes] are enabled or disabled +** on a per database connection basis using the +** [sqlite3_extended_result_codes()] API. Or, the extended code for +** the most recent error can be obtained using +** [sqlite3_extended_errcode()]. +*/ +#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) +#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) +#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) +#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) +#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) +#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) +#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) +#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8)) +#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) +#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) +#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) +#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) +#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) +#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) +#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) +#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) +#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) +#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) +#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) +#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) +#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) +#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) +#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) +#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_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) +#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) +#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) +#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) +#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) +#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) +#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) +#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) +#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) +#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) +#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) +#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) +#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) +#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) +#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) +#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) +#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) +#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) +#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) +#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) +#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) +#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) +#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) +#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) +#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) + +/* +** CAPI3REF: Flags For File Open Operations +** +** These bit values are intended for use in the +** 3rd parameter to the [sqlite3_open_v2()] interface and +** in the 4th parameter to the [sqlite3_vfs.xOpen] method. +*/ +#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ +#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ +#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ +#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ +#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ +#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ +#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ +#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ +#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ +#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ + +/* Reserved: 0x00F00000 */ + +/* +** CAPI3REF: Device Characteristics +** +** The xDeviceCharacteristics method of the [sqlite3_io_methods] +** object returns an integer which is a vector of these +** bit values expressing I/O characteristics of the mass storage +** device that holds the file that the [sqlite3_io_methods] +** refers to. +** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that +** after reboot following a crash or power loss, the only bytes in a +** file that were written at the application level might have changed +** and that adjacent bytes, even bytes within the same sector are +** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN +** flag indicates that a file cannot be deleted when open. The +** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on +** read-only media and cannot be changed even by processes with +** elevated privileges. +*/ +#define SQLITE_IOCAP_ATOMIC 0x00000001 +#define SQLITE_IOCAP_ATOMIC512 0x00000002 +#define SQLITE_IOCAP_ATOMIC1K 0x00000004 +#define SQLITE_IOCAP_ATOMIC2K 0x00000008 +#define SQLITE_IOCAP_ATOMIC4K 0x00000010 +#define SQLITE_IOCAP_ATOMIC8K 0x00000020 +#define SQLITE_IOCAP_ATOMIC16K 0x00000040 +#define SQLITE_IOCAP_ATOMIC32K 0x00000080 +#define SQLITE_IOCAP_ATOMIC64K 0x00000100 +#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 +#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 +#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 +#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 +#define SQLITE_IOCAP_IMMUTABLE 0x00002000 + +/* +** CAPI3REF: File Locking Levels +** +** SQLite uses one of these integer values as the second +** argument to calls it makes to the xLock() and xUnlock() methods +** of an [sqlite3_io_methods] object. +*/ +#define SQLITE_LOCK_NONE 0 +#define SQLITE_LOCK_SHARED 1 +#define SQLITE_LOCK_RESERVED 2 +#define SQLITE_LOCK_PENDING 3 +#define SQLITE_LOCK_EXCLUSIVE 4 + +/* +** CAPI3REF: Synchronization Type Flags +** +** When SQLite invokes the xSync() method of an +** [sqlite3_io_methods] object it uses a combination of +** these integer values as the second argument. +** +** When the SQLITE_SYNC_DATAONLY flag is used, it means that the +** sync operation only needs to flush data to mass storage. Inode +** information need not be flushed. If the lower four bits of the flag +** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics. +** If the lower four bits equal SQLITE_SYNC_FULL, that means +** to use Mac OS X style fullsync instead of fsync(). +** +** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags +** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL +** settings. The [synchronous pragma] determines when calls to the +** xSync VFS method occur and applies uniformly across all platforms. +** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how +** energetic or rigorous or forceful the sync operations are and +** only make a difference on Mac OSX for the default SQLite code. +** (Third-party VFS implementations might also make the distinction +** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the +** operating systems natively supported by SQLite, only Mac OSX +** cares about the difference.) +*/ +#define SQLITE_SYNC_NORMAL 0x00002 +#define SQLITE_SYNC_FULL 0x00003 +#define SQLITE_SYNC_DATAONLY 0x00010 + +/* +** CAPI3REF: OS Interface Open File Handle +** +** An [sqlite3_file] object represents an open file in the +** [sqlite3_vfs | OS interface layer]. Individual OS interface +** implementations will +** want to subclass this object by appending additional fields +** for their own use. The pMethods entry is a pointer to an +** [sqlite3_io_methods] object that defines methods for performing +** I/O operations on the open file. +*/ +typedef struct sqlite3_file sqlite3_file; +struct sqlite3_file { + const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ +}; + +/* +** CAPI3REF: OS Interface File Virtual Methods Object +** +** Every file opened by the [sqlite3_vfs.xOpen] method populates an +** [sqlite3_file] object (or, more commonly, a subclass of the +** [sqlite3_file] object) with a pointer to an instance of this object. +** This object defines the methods used to perform various operations +** against the open file represented by the [sqlite3_file] object. +** +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element +** to a non-NULL pointer, then the sqlite3_io_methods.xClose method +** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The +** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] +** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element +** to NULL. +** +** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or +** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). +** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] +** flag may be ORed in to indicate that only the data of the file +** and not its inode needs to be synced. +** +** The integer values to xLock() and xUnlock() are one of +**
    +**
  • [SQLITE_LOCK_NONE], +**
  • [SQLITE_LOCK_SHARED], +**
  • [SQLITE_LOCK_RESERVED], +**
  • [SQLITE_LOCK_PENDING], or +**
  • [SQLITE_LOCK_EXCLUSIVE]. +**
+** xLock() increases the lock. xUnlock() decreases the lock. +** The xCheckReservedLock() method checks whether any database connection, +** either in this process or in some other process, is holding a RESERVED, +** PENDING, or EXCLUSIVE lock on the file. It returns true +** if such a lock exists and false otherwise. +** +** The xFileControl() method is a generic interface that allows custom +** VFS implementations to directly control an open file using the +** [sqlite3_file_control()] interface. The second "op" argument is an +** integer opcode. The third argument is a generic pointer intended to +** point to a structure that may contain arguments or space in which to +** write return values. Potential uses for xFileControl() might be +** functions to enable blocking locks with timeouts, to change the +** locking strategy (for example to use dot-file locks), to inquire +** about the status of a lock, or to break stale locks. The SQLite +** core reserves all opcodes less than 100 for its own use. +** A [file control opcodes | list of opcodes] less than 100 is available. +** Applications that define a custom xFileControl method should use opcodes +** greater than 100 to avoid conflicts. VFS implementations should +** return [SQLITE_NOTFOUND] for file control opcodes that they do not +** recognize. +** +** The xSectorSize() method returns the sector size of the +** device that underlies the file. The sector size is the +** minimum write that can be performed without disturbing +** other bytes in the file. The xDeviceCharacteristics() +** method returns a bit vector describing behaviors of the +** underlying device: +** +**
    +**
  • [SQLITE_IOCAP_ATOMIC] +**
  • [SQLITE_IOCAP_ATOMIC512] +**
  • [SQLITE_IOCAP_ATOMIC1K] +**
  • [SQLITE_IOCAP_ATOMIC2K] +**
  • [SQLITE_IOCAP_ATOMIC4K] +**
  • [SQLITE_IOCAP_ATOMIC8K] +**
  • [SQLITE_IOCAP_ATOMIC16K] +**
  • [SQLITE_IOCAP_ATOMIC32K] +**
  • [SQLITE_IOCAP_ATOMIC64K] +**
  • [SQLITE_IOCAP_SAFE_APPEND] +**
  • [SQLITE_IOCAP_SEQUENTIAL] +**
  • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] +**
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] +**
  • [SQLITE_IOCAP_IMMUTABLE] +**
+** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). +** +** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill +** in the unread portions of the buffer with zeros. A VFS that +** fails to zero-fill short reads might seem to work. However, +** failure to zero-fill short reads will eventually lead to +** database corruption. +*/ +typedef struct sqlite3_io_methods sqlite3_io_methods; +struct sqlite3_io_methods { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + /* Methods above are valid for version 1 */ + int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); + int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); + void (*xShmBarrier)(sqlite3_file*); + int (*xShmUnmap)(sqlite3_file*, int deleteFlag); + /* Methods above are valid for version 2 */ + int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); + int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); + /* Methods above are valid for version 3 */ + /* Additional methods may be added in future releases */ +}; + +/* +** CAPI3REF: Standard File Control Opcodes +** KEYWORDS: {file control opcodes} {file control opcode} +** +** These integer constants are opcodes for the xFileControl method +** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] +** interface. +** +**
    +**
  • [[SQLITE_FCNTL_LOCKSTATE]] +** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This +** opcode causes the xFileControl method to write the current state of +** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], +** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) +** into an integer that the pArg argument points to. This capability +** is used during testing and is only available when the SQLITE_TEST +** compile-time option is used. +** +**
  • [[SQLITE_FCNTL_SIZE_HINT]] +** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS +** layer a hint of how large the database file will grow to be during the +** current transaction. This hint is not guaranteed to be accurate but it +** is often close. The underlying VFS might choose to preallocate database +** file space based on this hint in order to help writes to the database +** file run faster. +** +**
  • [[SQLITE_FCNTL_CHUNK_SIZE]] +** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS +** extends and truncates the database file in chunks of a size specified +** by the user. The fourth argument to [sqlite3_file_control()] should +** point to an integer (type int) containing the new chunk-size to use +** for the nominated database. Allocating database file space in large +** chunks (say 1MB at a time), may reduce file-system fragmentation and +** improve performance on some systems. +** +**
  • [[SQLITE_FCNTL_FILE_POINTER]] +** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer +** to the [sqlite3_file] object associated with a particular database +** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER]. +** +**
  • [[SQLITE_FCNTL_JOURNAL_POINTER]] +** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer +** to the [sqlite3_file] object associated with the journal file (either +** the [rollback journal] or the [write-ahead log]) for a particular database +** connection. See also [SQLITE_FCNTL_FILE_POINTER]. +** +**
  • [[SQLITE_FCNTL_SYNC_OMITTED]] +** No longer in use. +** +**
  • [[SQLITE_FCNTL_SYNC]] +** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and +** sent to the VFS immediately before the xSync method is invoked on a +** database file descriptor. Or, if the xSync method is not invoked +** because the user has configured SQLite with +** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place +** of the xSync method. In most cases, the pointer argument passed with +** this file-control is NULL. However, if the database file is being synced +** as part of a multi-database commit, the argument points to a nul-terminated +** string containing the transactions master-journal file name. VFSes that +** do not need this signal should silently ignore this opcode. Applications +** should not call [sqlite3_file_control()] with this opcode as doing so may +** disrupt the operation of the specialized VFSes that do require it. +** +**
  • [[SQLITE_FCNTL_COMMIT_PHASETWO]] +** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite +** and sent to the VFS after a transaction has been committed immediately +** but before the database is unlocked. VFSes that do not need this signal +** should silently ignore this opcode. Applications should not call +** [sqlite3_file_control()] with this opcode as doing so may disrupt the +** operation of the specialized VFSes that do require it. +** +**
  • [[SQLITE_FCNTL_WIN32_AV_RETRY]] +** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic +** retry counts and intervals for certain disk I/O operations for the +** windows [VFS] in order to provide robustness in the presence of +** anti-virus programs. By default, the windows VFS will retry file read, +** file write, and file delete operations up to 10 times, with a delay +** of 25 milliseconds before the first retry and with the delay increasing +** by an additional 25 milliseconds with each subsequent retry. This +** opcode allows these two values (10 retries and 25 milliseconds of delay) +** to be adjusted. The values are changed for all database connections +** within the same process. The argument is a pointer to an array of two +** integers where the first integer is the new retry count and the second +** integer is the delay. If either integer is negative, then the setting +** is not changed but instead the prior value of that setting is written +** into the array entry, allowing the current retry settings to be +** interrogated. The zDbName parameter is ignored. +** +**
  • [[SQLITE_FCNTL_PERSIST_WAL]] +** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the +** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary +** write ahead log and shared memory files used for transaction control +** are automatically deleted when the latest connection to the database +** closes. Setting persistent WAL mode causes those files to persist after +** close. Persisting the files is useful when other processes that do not +** have write permission on the directory containing the database file want +** to read the database file, as the WAL and shared memory files must exist +** in order for the database to be readable. The fourth parameter to +** [sqlite3_file_control()] for this opcode should be a pointer to an integer. +** That integer is 0 to disable persistent WAL mode or 1 to enable persistent +** WAL mode. If the integer is -1, then it is overwritten with the current +** WAL persistence setting. +** +**
  • [[SQLITE_FCNTL_POWERSAFE_OVERWRITE]] +** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the +** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting +** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the +** xDeviceCharacteristics methods. The fourth parameter to +** [sqlite3_file_control()] for this opcode should be a pointer to an integer. +** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage +** mode. If the integer is -1, then it is overwritten with the current +** zero-damage mode setting. +** +**
  • [[SQLITE_FCNTL_OVERWRITE]] +** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening +** a write transaction to indicate that, unless it is rolled back for some +** reason, the entire database file will be overwritten by the current +** transaction. This is used by VACUUM operations. +** +**
  • [[SQLITE_FCNTL_VFSNAME]] +** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of +** all [VFSes] in the VFS stack. The names are of all VFS shims and the +** final bottom-level VFS are written into memory obtained from +** [sqlite3_malloc()] and the result is stored in the char* variable +** that the fourth parameter of [sqlite3_file_control()] points to. +** The caller is responsible for freeing the memory when done. As with +** all file-control actions, there is no guarantee that this will actually +** do anything. Callers should initialize the char* variable to a NULL +** pointer in case this file-control is not implemented. This file-control +** is intended for diagnostic use only. +** +**
  • [[SQLITE_FCNTL_VFS_POINTER]] +** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level +** [VFSes] currently in use. ^(The argument X in +** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be +** of type "[sqlite3_vfs] **". This opcodes will set *X +** to a pointer to the top-level VFS.)^ +** ^When there are multiple VFS shims in the stack, this opcode finds the +** upper-most shim only. +** +**
  • [[SQLITE_FCNTL_PRAGMA]] +** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] +** file control is sent to the open [sqlite3_file] object corresponding +** to the database file to which the pragma statement refers. ^The argument +** to the [SQLITE_FCNTL_PRAGMA] file control is an array of +** pointers to strings (char**) in which the second element of the array +** is the name of the pragma and the third element is the argument to the +** pragma or NULL if the pragma has no argument. ^The handler for an +** [SQLITE_FCNTL_PRAGMA] file control can optionally make the first element +** of the char** argument point to a string obtained from [sqlite3_mprintf()] +** or the equivalent and that string will become the result of the pragma or +** the error message if the pragma fails. ^If the +** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal +** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] +** file control returns [SQLITE_OK], then the parser assumes that the +** VFS has handled the PRAGMA itself and the parser generates a no-op +** prepared statement if result string is NULL, or that returns a copy +** of the result string if the string is non-NULL. +** ^If the [SQLITE_FCNTL_PRAGMA] file control returns +** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means +** that the VFS encountered an error while handling the [PRAGMA] and the +** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] +** file control occurs at the beginning of pragma statement analysis and so +** it is able to override built-in [PRAGMA] statements. +** +**
  • [[SQLITE_FCNTL_BUSYHANDLER]] +** ^The [SQLITE_FCNTL_BUSYHANDLER] +** file-control may be invoked by SQLite on the database file handle +** shortly after it is opened in order to provide a custom VFS with access +** to the connections busy-handler callback. The argument is of type (void **) +** - an array of two (void *) values. The first (void *) actually points +** to a function of type (int (*)(void *)). In order to invoke the connections +** busy-handler, this function should be invoked with the second (void *) in +** the array as the only argument. If it returns non-zero, then the operation +** should be retried. If it returns zero, the custom VFS should abandon the +** current operation. +** +**
  • [[SQLITE_FCNTL_TEMPFILENAME]] +** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control +** to have SQLite generate a +** temporary filename using the same algorithm that is followed to generate +** temporary filenames for TEMP tables and other internal uses. The +** argument should be a char** which will be filled with the filename +** written into memory obtained from [sqlite3_malloc()]. The caller should +** invoke [sqlite3_free()] on the result to avoid a memory leak. +** +**
  • [[SQLITE_FCNTL_MMAP_SIZE]] +** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the +** maximum number of bytes that will be used for memory-mapped I/O. +** The argument is a pointer to a value of type sqlite3_int64 that +** is an advisory maximum number of bytes in the file to memory map. The +** pointer is overwritten with the old value. The limit is not changed if +** the value originally pointed to is negative, and so the current limit +** can be queried by passing in a pointer to a negative number. This +** file-control is used internally to implement [PRAGMA mmap_size]. +** +**
  • [[SQLITE_FCNTL_TRACE]] +** The [SQLITE_FCNTL_TRACE] file control provides advisory information +** to the VFS about what the higher layers of the SQLite stack are doing. +** This file control is used by some VFS activity tracing [shims]. +** The argument is a zero-terminated string. Higher layers in the +** SQLite stack may generate instances of this file control if +** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled. +** +**
  • [[SQLITE_FCNTL_HAS_MOVED]] +** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a +** pointer to an integer and it writes a boolean into that integer depending +** on whether or not the file has been renamed, moved, or deleted since it +** was first opened. +** +**
  • [[SQLITE_FCNTL_WIN32_GET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the +** underlying native file handle associated with a file handle. This file +** control interprets its argument as a pointer to a native file handle and +** writes the resulting value there. +** +**
  • [[SQLITE_FCNTL_WIN32_SET_HANDLE]] +** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This +** opcode causes the xFileControl method to swap the file handle with the one +** pointed to by the pArg argument. This capability is used during testing +** and only needs to be supported when SQLITE_TEST is defined. +** +**
  • [[SQLITE_FCNTL_WAL_BLOCK]] +** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might +** be advantageous to block on the next WAL lock if the lock is not immediately +** available. The WAL subsystem issues this signal during rare +** circumstances in order to fix a problem with priority inversion. +** Applications should not use this file-control. +** +**
  • [[SQLITE_FCNTL_ZIPVFS]] +** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other +** VFS should return SQLITE_NOTFOUND for this opcode. +** +**
  • [[SQLITE_FCNTL_RBU]] +** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by +** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for +** this opcode. +**
+*/ +#define SQLITE_FCNTL_LOCKSTATE 1 +#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 +#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 +#define SQLITE_FCNTL_LAST_ERRNO 4 +#define SQLITE_FCNTL_SIZE_HINT 5 +#define SQLITE_FCNTL_CHUNK_SIZE 6 +#define SQLITE_FCNTL_FILE_POINTER 7 +#define SQLITE_FCNTL_SYNC_OMITTED 8 +#define SQLITE_FCNTL_WIN32_AV_RETRY 9 +#define SQLITE_FCNTL_PERSIST_WAL 10 +#define SQLITE_FCNTL_OVERWRITE 11 +#define SQLITE_FCNTL_VFSNAME 12 +#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 +#define SQLITE_FCNTL_PRAGMA 14 +#define SQLITE_FCNTL_BUSYHANDLER 15 +#define SQLITE_FCNTL_TEMPFILENAME 16 +#define SQLITE_FCNTL_MMAP_SIZE 18 +#define SQLITE_FCNTL_TRACE 19 +#define SQLITE_FCNTL_HAS_MOVED 20 +#define SQLITE_FCNTL_SYNC 21 +#define SQLITE_FCNTL_COMMIT_PHASETWO 22 +#define SQLITE_FCNTL_WIN32_SET_HANDLE 23 +#define SQLITE_FCNTL_WAL_BLOCK 24 +#define SQLITE_FCNTL_ZIPVFS 25 +#define SQLITE_FCNTL_RBU 26 +#define SQLITE_FCNTL_VFS_POINTER 27 +#define SQLITE_FCNTL_JOURNAL_POINTER 28 +#define SQLITE_FCNTL_WIN32_GET_HANDLE 29 +#define SQLITE_FCNTL_PDB 30 + +/* deprecated names */ +#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE +#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE +#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO + + +/* +** CAPI3REF: Mutex Handle +** +** The mutex module within SQLite defines [sqlite3_mutex] to be an +** abstract type for a mutex object. The SQLite core never looks +** at the internal representation of an [sqlite3_mutex]. It only +** deals with pointers to the [sqlite3_mutex] object. +** +** Mutexes are created using [sqlite3_mutex_alloc()]. +*/ +typedef struct sqlite3_mutex sqlite3_mutex; + +/* +** CAPI3REF: Loadable Extension Thunk +** +** A pointer to the opaque sqlite3_api_routines structure is passed as +** the third parameter to entry points of [loadable extensions]. This +** structure must be typedefed in order to work around compiler warnings +** on some platforms. +*/ +typedef struct sqlite3_api_routines sqlite3_api_routines; + +/* +** CAPI3REF: OS Interface Object +** +** An instance of the sqlite3_vfs object defines the interface between +** the SQLite core and the underlying operating system. The "vfs" +** in the name of the object stands for "virtual file system". See +** the [VFS | VFS documentation] for further information. +** +** The value of the iVersion field is initially 1 but may be larger in +** future versions of SQLite. Additional fields may be appended to this +** object when the iVersion value is increased. Note that the structure +** of the sqlite3_vfs object changes in the transaction between +** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not +** modified. +** +** The szOsFile field is the size of the subclassed [sqlite3_file] +** structure used by this VFS. mxPathname is the maximum length of +** a pathname in this VFS. +** +** Registered sqlite3_vfs objects are kept on a linked list formed by +** the pNext pointer. The [sqlite3_vfs_register()] +** and [sqlite3_vfs_unregister()] interfaces manage this list +** in a thread-safe way. The [sqlite3_vfs_find()] interface +** searches the list. Neither the application code nor the VFS +** implementation should use the pNext pointer. +** +** The pNext field is the only field in the sqlite3_vfs +** structure that SQLite will ever modify. SQLite will only access +** or modify this field while holding a particular static mutex. +** The application should never modify anything within the sqlite3_vfs +** object once the object has been registered. +** +** The zName field holds the name of the VFS module. The name must +** be unique across all VFS modules. +** +** [[sqlite3_vfs.xOpen]] +** ^SQLite guarantees that the zFilename parameter to xOpen +** is either a NULL pointer or string obtained +** from xFullPathname() with an optional suffix added. +** ^If a suffix is added to the zFilename parameter, it will +** consist of a single "-" character followed by no more than +** 11 alphanumeric and/or "-" characters. +** ^SQLite further guarantees that +** the string will be valid and unchanged until xClose() is +** called. Because of the previous sentence, +** the [sqlite3_file] can safely store a pointer to the +** filename if it needs to remember the filename for some reason. +** If the zFilename parameter to xOpen is a NULL pointer then xOpen +** must invent its own temporary name for the file. ^Whenever the +** xFilename parameter is NULL it will also be the case that the +** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. +** +** The flags argument to xOpen() includes all bits set in +** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] +** or [sqlite3_open16()] is used, then flags includes at least +** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. +** If xOpen() opens a file read-only then it sets *pOutFlags to +** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. +** +** ^(SQLite will also add one of the following flags to the xOpen() +** call, depending on the object being opened: +** +**
    +**
  • [SQLITE_OPEN_MAIN_DB] +**
  • [SQLITE_OPEN_MAIN_JOURNAL] +**
  • [SQLITE_OPEN_TEMP_DB] +**
  • [SQLITE_OPEN_TEMP_JOURNAL] +**
  • [SQLITE_OPEN_TRANSIENT_DB] +**
  • [SQLITE_OPEN_SUBJOURNAL] +**
  • [SQLITE_OPEN_MASTER_JOURNAL] +**
  • [SQLITE_OPEN_WAL] +**
)^ +** +** The file I/O implementation can use the object type flags to +** change the way it deals with files. For example, an application +** that does not care about crash recovery or rollback might make +** the open of a journal file a no-op. Writes to this journal would +** also be no-ops, and any attempt to read the journal would return +** SQLITE_IOERR. Or the implementation might recognize that a database +** file will be doing page-aligned sector reads and writes in a random +** order and set up its I/O subsystem accordingly. +** +** SQLite might also add one of the following flags to the xOpen method: +** +**
    +**
  • [SQLITE_OPEN_DELETEONCLOSE] +**
  • [SQLITE_OPEN_EXCLUSIVE] +**
+** +** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be +** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] +** will be set for TEMP databases and their journals, transient +** databases, and subjournals. +** +** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction +** with the [SQLITE_OPEN_CREATE] flag, which are both directly +** analogous to the O_EXCL and O_CREAT flags of the POSIX open() +** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the +** SQLITE_OPEN_CREATE, is used to indicate that file should always +** be created, and that it is an error if it already exists. +** It is not used to indicate the file should be opened +** for exclusive access. +** +** ^At least szOsFile bytes of memory are allocated by SQLite +** to hold the [sqlite3_file] structure passed as the third +** argument to xOpen. The xOpen method does not have to +** allocate the structure; it should just fill it in. Note that +** the xOpen method must set the sqlite3_file.pMethods to either +** a valid [sqlite3_io_methods] object or to NULL. xOpen must do +** this even if the open fails. SQLite expects that the sqlite3_file.pMethods +** element will be valid after xOpen returns regardless of the success +** or failure of the xOpen call. +** +** [[sqlite3_vfs.xAccess]] +** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] +** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to +** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] +** to test whether a file is at least readable. The file can be a +** directory. +** +** ^SQLite will always allocate at least mxPathname+1 bytes for the +** output buffer xFullPathname. The exact size of the output buffer +** is also passed as a parameter to both methods. If the output buffer +** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is +** handled as a fatal error by SQLite, vfs implementations should endeavor +** to prevent this by setting mxPathname to a sufficiently large value. +** +** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() +** interfaces are not strictly a part of the filesystem, but they are +** included in the VFS structure for completeness. +** The xRandomness() function attempts to return nBytes bytes +** of good-quality randomness into zOut. The return value is +** the actual number of bytes of randomness obtained. +** The xSleep() method causes the calling thread to sleep for at +** least the number of microseconds given. ^The xCurrentTime() +** method returns a Julian Day Number for the current date and time as +** a floating point value. +** ^The xCurrentTimeInt64() method returns, as an integer, the Julian +** Day Number multiplied by 86400000 (the number of milliseconds in +** a 24-hour day). +** ^SQLite will use the xCurrentTimeInt64() method to get the current +** date and time if that method is available (if iVersion is 2 or +** greater and the function pointer is not NULL) and will fall back +** to xCurrentTime() if xCurrentTimeInt64() is unavailable. +** +** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** are not used by the SQLite core. These optional interfaces are provided +** by some VFSes to facilitate testing of the VFS code. By overriding +** system calls with functions under its control, a test program can +** simulate faults and error conditions that would otherwise be difficult +** or impossible to induce. The set of system calls that can be overridden +** varies from one VFS to another, and from one version of the same VFS to the +** next. Applications that use these interfaces must be prepared for any +** or all of these interfaces to be NULL or for their behavior to change +** from one release to the next. Applications must not attempt to access +** any of these methods if the iVersion of the VFS is less than 3. +*/ +typedef struct sqlite3_vfs sqlite3_vfs; +typedef void (*sqlite3_syscall_ptr)(void); +struct sqlite3_vfs { + int iVersion; /* Structure version number (currently 3) */ + int szOsFile; /* Size of subclassed sqlite3_file */ + int mxPathname; /* Maximum file pathname length */ + sqlite3_vfs *pNext; /* Next registered VFS */ + const char *zName; /* Name of this virtual file system */ + void *pAppData; /* Pointer to application-specific data */ + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + int (*xGetLastError)(sqlite3_vfs*, int, char *); + /* + ** The methods above are in version 1 of the sqlite_vfs object + ** definition. Those that follow are added in version 2 or later + */ + int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); + /* + ** The methods above are in versions 1 and 2 of the sqlite_vfs object. + ** Those below are for version 3 and greater. + */ + int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); + const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); + /* + ** The methods above are in versions 1 through 3 of the sqlite_vfs object. + ** New fields may be appended in future versions. The iVersion + ** value will increment whenever this happens. + */ +}; + +/* +** CAPI3REF: Flags for the xAccess VFS method +** +** These integer constants can be used as the third parameter to +** the xAccess method of an [sqlite3_vfs] object. They determine +** what kind of permissions the xAccess method is looking for. +** With SQLITE_ACCESS_EXISTS, the xAccess method +** simply checks whether the file exists. +** With SQLITE_ACCESS_READWRITE, the xAccess method +** checks whether the named directory is both readable and writable +** (in other words, if files can be added, removed, and renamed within +** the directory). +** The SQLITE_ACCESS_READWRITE constant is currently used only by the +** [temp_store_directory pragma], though this could change in a future +** release of SQLite. +** With SQLITE_ACCESS_READ, the xAccess method +** checks whether the file is readable. The SQLITE_ACCESS_READ constant is +** currently unused, though it might be used in a future release of +** SQLite. +*/ +#define SQLITE_ACCESS_EXISTS 0 +#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */ +#define SQLITE_ACCESS_READ 2 /* Unused */ + +/* +** CAPI3REF: Flags for the xShmLock VFS method +** +** These integer constants define the various locking operations +** allowed by the xShmLock method of [sqlite3_io_methods]. The +** following are the only legal combinations of flags to the +** xShmLock method: +** +**
    +**
  • SQLITE_SHM_LOCK | SQLITE_SHM_SHARED +**
  • SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE +**
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED +**
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE +**
+** +** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as +** was given on the corresponding lock. +** +** The xShmLock method can transition between unlocked and SHARED or +** between unlocked and EXCLUSIVE. It cannot transition between SHARED +** and EXCLUSIVE. +*/ +#define SQLITE_SHM_UNLOCK 1 +#define SQLITE_SHM_LOCK 2 +#define SQLITE_SHM_SHARED 4 +#define SQLITE_SHM_EXCLUSIVE 8 + +/* +** CAPI3REF: Maximum xShmLock index +** +** The xShmLock method on [sqlite3_io_methods] may use values +** between 0 and this upper bound as its "offset" argument. +** The SQLite core will never attempt to acquire or release a +** lock outside of this range +*/ +#define SQLITE_SHM_NLOCK 8 + + +/* +** CAPI3REF: Initialize The SQLite Library +** +** ^The sqlite3_initialize() routine initializes the +** SQLite library. ^The sqlite3_shutdown() routine +** deallocates any resources that were allocated by sqlite3_initialize(). +** These routines are designed to aid in process initialization and +** shutdown on embedded systems. Workstation applications using +** SQLite normally do not need to invoke either of these routines. +** +** A call to sqlite3_initialize() is an "effective" call if it is +** the first time sqlite3_initialize() is invoked during the lifetime of +** the process, or if it is the first time sqlite3_initialize() is invoked +** following a call to sqlite3_shutdown(). ^(Only an effective call +** of sqlite3_initialize() does any initialization. All other calls +** are harmless no-ops.)^ +** +** A call to sqlite3_shutdown() is an "effective" call if it is the first +** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only +** an effective call to sqlite3_shutdown() does any deinitialization. +** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^ +** +** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() +** is not. The sqlite3_shutdown() interface must only be called from a +** single thread. All open [database connections] must be closed and all +** other SQLite resources must be deallocated prior to invoking +** sqlite3_shutdown(). +** +** Among other things, ^sqlite3_initialize() will invoke +** sqlite3_os_init(). Similarly, ^sqlite3_shutdown() +** will invoke sqlite3_os_end(). +** +** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success. +** ^If for some reason, sqlite3_initialize() is unable to initialize +** the library (perhaps it is unable to allocate a needed resource such +** as a mutex) it returns an [error code] other than [SQLITE_OK]. +** +** ^The sqlite3_initialize() routine is called internally by many other +** SQLite interfaces so that an application usually does not need to +** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] +** calls sqlite3_initialize() so the SQLite library will be automatically +** initialized when [sqlite3_open()] is called if it has not be initialized +** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] +** compile-time option, then the automatic calls to sqlite3_initialize() +** are omitted and the application must call sqlite3_initialize() directly +** prior to using any other SQLite interface. For maximum portability, +** it is recommended that applications always invoke sqlite3_initialize() +** directly prior to using any other SQLite interface. Future releases +** of SQLite may require this. In other words, the behavior exhibited +** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the +** default behavior in some future release of SQLite. +** +** The sqlite3_os_init() routine does operating-system specific +** initialization of the SQLite library. The sqlite3_os_end() +** routine undoes the effect of sqlite3_os_init(). Typical tasks +** performed by these routines include allocation or deallocation +** of static resources, initialization of global variables, +** setting up a default [sqlite3_vfs] module, or setting up +** a default configuration using [sqlite3_config()]. +** +** The application should never invoke either sqlite3_os_init() +** or sqlite3_os_end() directly. The application should only invoke +** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() +** interface is called automatically by sqlite3_initialize() and +** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate +** implementations for sqlite3_os_init() and sqlite3_os_end() +** are built into SQLite when it is compiled for Unix, Windows, or OS/2. +** When [custom builds | built for other platforms] +** (using the [SQLITE_OS_OTHER=1] compile-time +** option) the application must supply a suitable implementation for +** sqlite3_os_init() and sqlite3_os_end(). An application-supplied +** implementation of sqlite3_os_init() or sqlite3_os_end() +** must return [SQLITE_OK] on success and some other [error code] upon +** failure. +*/ +SQLITE_API int sqlite3_initialize(void); +SQLITE_API int sqlite3_shutdown(void); +SQLITE_API int sqlite3_os_init(void); +SQLITE_API int sqlite3_os_end(void); + +/* +** CAPI3REF: Configuring The SQLite Library +** +** The sqlite3_config() interface is used to make global configuration +** changes to SQLite in order to tune SQLite to the specific needs of +** the application. The default configuration is recommended for most +** applications and so this routine is usually not necessary. It is +** provided to support rare applications with unusual needs. +** +** The sqlite3_config() interface is not threadsafe. The application +** must ensure that no other SQLite interfaces are invoked by other +** threads while sqlite3_config() is running. +** +** The sqlite3_config() interface +** may only be invoked prior to library initialization using +** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. +** ^If sqlite3_config() is called after [sqlite3_initialize()] and before +** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. +** Note, however, that ^sqlite3_config() can be called as part of the +** implementation of an application-defined [sqlite3_os_init()]. +** +** The first argument to sqlite3_config() is an integer +** [configuration option] that determines +** what property of SQLite is to be configured. Subsequent arguments +** vary depending on the [configuration option] +** in the first argument. +** +** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. +** ^If the option is unknown or SQLite is unable to set the option +** then this routine returns a non-zero [error code]. +*/ +SQLITE_API int sqlite3_config(int, ...); + +/* +** CAPI3REF: Configure database connections +** METHOD: sqlite3 +** +** The sqlite3_db_config() interface is used to make configuration +** changes to a [database connection]. The interface is similar to +** [sqlite3_config()] except that the changes apply to a single +** [database connection] (specified in the first argument). +** +** The second argument to sqlite3_db_config(D,V,...) is the +** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code +** that indicates what aspect of the [database connection] is being configured. +** Subsequent arguments vary depending on the configuration verb. +** +** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if +** the call is considered successful. +*/ +SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Memory Allocation Routines +** +** An instance of this object defines the interface between SQLite +** and low-level memory allocation routines. +** +** This object is used in only one place in the SQLite interface. +** A pointer to an instance of this object is the argument to +** [sqlite3_config()] when the configuration option is +** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. +** By creating an instance of this object +** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) +** during configuration, an application can specify an alternative +** memory allocation subsystem for SQLite to use for all of its +** dynamic memory needs. +** +** Note that SQLite comes with several [built-in memory allocators] +** that are perfectly adequate for the overwhelming majority of applications +** and that this object is only useful to a tiny minority of applications +** with specialized memory allocation requirements. This object is +** also used during testing of SQLite in order to specify an alternative +** memory allocator that simulates memory out-of-memory conditions in +** order to verify that SQLite recovers gracefully from such +** conditions. +** +** The xMalloc, xRealloc, and xFree methods must work like the +** malloc(), realloc() and free() functions from the standard C library. +** ^SQLite guarantees that the second argument to +** xRealloc is always a value returned by a prior call to xRoundup. +** +** xSize should return the allocated size of a memory allocation +** previously obtained from xMalloc or xRealloc. The allocated size +** is always at least as big as the requested size but may be larger. +** +** The xRoundup method returns what would be the allocated size of +** a memory allocation given a particular requested size. Most memory +** allocators round up memory allocations at least to the next multiple +** of 8. Some allocators round up to a larger multiple or to a power of 2. +** Every memory allocation request coming in through [sqlite3_malloc()] +** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, +** that causes the corresponding memory allocation to fail. +** +** The xInit method initializes the memory allocator. For example, +** it might allocate any require mutexes or initialize internal data +** structures. The xShutdown method is invoked (indirectly) by +** [sqlite3_shutdown()] and should deallocate any resources acquired +** by xInit. The pAppData pointer is used as the only parameter to +** xInit and xShutdown. +** +** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes +** the xInit method, so the xInit method need not be threadsafe. The +** xShutdown method is only called from [sqlite3_shutdown()] so it does +** not need to be threadsafe either. For all other methods, SQLite +** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the +** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which +** it is by default) and so the methods are automatically serialized. +** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other +** methods must be threadsafe or else make their own arrangements for +** serialization. +** +** SQLite will never invoke xInit() more than once without an intervening +** call to xShutdown(). +*/ +typedef struct sqlite3_mem_methods sqlite3_mem_methods; +struct sqlite3_mem_methods { + void *(*xMalloc)(int); /* Memory allocation function */ + void (*xFree)(void*); /* Free a prior allocation */ + void *(*xRealloc)(void*,int); /* Resize an allocation */ + int (*xSize)(void*); /* Return the size of an allocation */ + int (*xRoundup)(int); /* Round up request size to allocation size */ + int (*xInit)(void*); /* Initialize the memory allocator */ + void (*xShutdown)(void*); /* Deinitialize the memory allocator */ + void *pAppData; /* Argument to xInit() and xShutdown() */ +}; + +/* +** CAPI3REF: Configuration Options +** KEYWORDS: {configuration option} +** +** These constants are the available integer configuration options that +** can be passed as the first argument to the [sqlite3_config()] interface. +** +** New configuration options may be added in future releases of SQLite. +** Existing configuration options might be discontinued. Applications +** should check the return code from [sqlite3_config()] to make sure that +** the call worked. The [sqlite3_config()] interface will return a +** non-zero [error code] if a discontinued or unsupported configuration option +** is invoked. +** +**
+** [[SQLITE_CONFIG_SINGLETHREAD]]
SQLITE_CONFIG_SINGLETHREAD
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Single-thread. In other words, it disables +** all mutexing and puts SQLite into a mode where it can only be used +** by a single thread. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to change the [threading mode] from its default +** value of Single-thread and so [sqlite3_config()] will return +** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD +** configuration option.
+** +** [[SQLITE_CONFIG_MULTITHREAD]]
SQLITE_CONFIG_MULTITHREAD
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Multi-thread. In other words, it disables +** mutexing on [database connection] and [prepared statement] objects. +** The application is responsible for serializing access to +** [database connections] and [prepared statements]. But other mutexes +** are enabled so that SQLite will be safe to use in a multi-threaded +** environment as long as no two threads attempt to use the same +** [database connection] at the same time. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to set the Multi-thread [threading mode] and +** [sqlite3_config()] will return [SQLITE_ERROR] if called with the +** SQLITE_CONFIG_MULTITHREAD configuration option.
+** +** [[SQLITE_CONFIG_SERIALIZED]]
SQLITE_CONFIG_SERIALIZED
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Serialized. In other words, this option enables +** all mutexes including the recursive +** mutexes on [database connection] and [prepared statement] objects. +** In this mode (which is the default when SQLite is compiled with +** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access +** to [database connections] and [prepared statements] so that the +** application is free to use the same [database connection] or the +** same [prepared statement] in different threads at the same time. +** ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to set the Serialized [threading mode] and +** [sqlite3_config()] will return [SQLITE_ERROR] if called with the +** SQLITE_CONFIG_SERIALIZED configuration option.
+** +** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
+**
^(The SQLITE_CONFIG_MALLOC option takes a single argument which is +** a pointer to an instance of the [sqlite3_mem_methods] structure. +** The argument specifies +** alternative low-level memory allocation routines to be used in place of +** the memory allocation routines built into SQLite.)^ ^SQLite makes +** its own private copy of the content of the [sqlite3_mem_methods] structure +** before the [sqlite3_config()] call returns.
+** +** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
+**
^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which +** is a pointer to an instance of the [sqlite3_mem_methods] structure. +** The [sqlite3_mem_methods] +** structure is filled with the currently defined memory allocation routines.)^ +** This option can be used to overload the default memory allocation +** routines with a wrapper that simulations memory allocation failure or +** tracks memory usage, for example.
+** +** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
+**
^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, +** interpreted as a boolean, which enables or disables the collection of +** memory allocation statistics. ^(When memory allocation statistics are +** disabled, the following SQLite interfaces become non-operational: +**
    +**
  • [sqlite3_memory_used()] +**
  • [sqlite3_memory_highwater()] +**
  • [sqlite3_soft_heap_limit64()] +**
  • [sqlite3_status64()] +**
)^ +** ^Memory allocation statistics are enabled by default unless SQLite is +** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory +** allocation statistics are disabled by default. +**
+** +** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
+**
^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.

+** ^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. +**

+** +** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
+**
^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool +** that SQLite can use for the database page cache with the default page +** cache implementation. +** This configuration option is a no-op if an application-define page +** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]. +** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to +** 8-byte aligned memory (pMem), the size of each page cache line (sz), +** and the number of cache lines (N). +** The sz argument should be the size of the largest database page +** (a power of two between 512 and 65536) plus some extra bytes for each +** page header. ^The number of extra bytes needed by the page header +** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ]. +** ^It is harmless, apart from the wasted memory, +** for the sz parameter to be larger than necessary. The pMem +** argument must be either a NULL pointer or a pointer to an 8-byte +** aligned block of memory of at least sz*N bytes, otherwise +** subsequent behavior is undefined. +** ^When pMem is not NULL, SQLite will strive to use the memory provided +** to satisfy page cache needs, falling back to [sqlite3_malloc()] if +** a page cache line is larger than sz bytes or if all of the pMem buffer +** is exhausted. +** ^If pMem is NULL and N is non-zero, then each database connection +** does an initial bulk allocation for page cache memory +** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or +** of -1024*N bytes if N is negative, . ^If additional +** page cache memory is needed beyond what is provided by the initial +** allocation, then SQLite goes to [sqlite3_malloc()] separately for each +** additional cache line.
+** +** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
+**
^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]. +** ^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. +** ^There are three arguments to SQLITE_CONFIG_HEAP: +** An 8-byte aligned pointer to the memory, +** the number of bytes in the memory buffer, and the minimum allocation size. +** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts +** to using its default memory allocator (the system malloc() implementation), +** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the +** memory pointer is not NULL then the alternative memory +** allocator is engaged to handle all of SQLites memory allocation needs. +** The first pointer (the memory pointer) must be aligned to an 8-byte +** boundary or subsequent behavior of SQLite will be undefined. +** The minimum allocation size is capped at 2**12. Reasonable values +** for the minimum allocation size are 2**5 through 2**8.
+** +** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
+**
^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a +** pointer to an instance of the [sqlite3_mutex_methods] structure. +** The argument specifies alternative low-level mutex routines to be used +** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of +** the content of the [sqlite3_mutex_methods] structure before the call to +** [sqlite3_config()] returns. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** the entire mutexing subsystem is omitted from the build and hence calls to +** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will +** return [SQLITE_ERROR].
+** +** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
+**
^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which +** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The +** [sqlite3_mutex_methods] +** structure is filled with the currently defined mutex routines.)^ +** This option can be used to overload the default mutex allocation +** routines with a wrapper used to track mutex usage for performance +** profiling or testing, for example. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** the entire mutexing subsystem is omitted from the build and hence calls to +** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will +** return [SQLITE_ERROR].
+** +** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
+**
^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine +** the default size of lookaside memory on each [database connection]. +** The first argument is the +** size of each lookaside buffer slot and the second is the number of +** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE +** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] +** option to [sqlite3_db_config()] can be used to change the lookaside +** configuration on individual connections.)^
+** +** [[SQLITE_CONFIG_PCACHE2]]
SQLITE_CONFIG_PCACHE2
+**
^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is +** a pointer to an [sqlite3_pcache_methods2] object. This object specifies +** the interface to a custom page cache implementation.)^ +** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
+** +** [[SQLITE_CONFIG_GETPCACHE2]]
SQLITE_CONFIG_GETPCACHE2
+**
^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which +** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of +** the current page cache implementation into that object.)^
+** +** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
+**
The SQLITE_CONFIG_LOG option is used to configure the SQLite +** global [error log]. +** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a +** function with a call signature of void(*)(void*,int,const char*), +** and a pointer to void. ^If the function pointer is not NULL, it is +** invoked by [sqlite3_log()] to process each logging event. ^If the +** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. +** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is +** passed through as the first parameter to the application-defined logger +** function whenever that function is invoked. ^The second parameter to +** the logger function is a copy of the first parameter to the corresponding +** [sqlite3_log()] call and is intended to be a [result code] or an +** [extended result code]. ^The third parameter passed to the logger is +** log message after formatting via [sqlite3_snprintf()]. +** The SQLite logging interface is not reentrant; the logger function +** supplied by the application must not invoke any SQLite interface. +** In a multi-threaded application, the application-defined logger +** function must be threadsafe.
+** +** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI +**
^(The SQLITE_CONFIG_URI option takes a single argument of type int. +** If non-zero, then URI handling is globally enabled. If the parameter is zero, +** then URI handling is globally disabled.)^ ^If URI handling is globally +** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()], +** [sqlite3_open16()] or +** specified as part of [ATTACH] commands are interpreted as URIs, regardless +** of whether or not the [SQLITE_OPEN_URI] flag is set when the database +** connection is opened. ^If it is globally disabled, filenames are +** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the +** database connection is opened. ^(By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** [SQLITE_USE_URI] symbol defined.)^ +** +** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
SQLITE_CONFIG_COVERING_INDEX_SCAN +**
^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer +** argument which is interpreted as a boolean in order to enable or disable +** the use of covering indices for full table scans in the query optimizer. +** ^The default setting is determined +** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" +** if that compile-time option is omitted. +** The ability to disable the use of covering indices for full table scans +** is because some incorrectly coded legacy applications might malfunction +** when the optimization is enabled. Providing the ability to +** disable the optimization allows the older, buggy application code to work +** without change even with newer versions of SQLite. +** +** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] +**
SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE +**
These options are obsolete and should not be used by new code. +** They are retained for backwards compatibility but are now no-ops. +**
+** +** [[SQLITE_CONFIG_SQLLOG]] +**
SQLITE_CONFIG_SQLLOG +**
This option is only available if sqlite is compiled with the +** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should +** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). +** The second should be of type (void*). The callback is invoked by the library +** in three separate circumstances, identified by the value passed as the +** fourth parameter. If the fourth parameter is 0, then the database connection +** passed as the second argument has just been opened. The third argument +** points to a buffer containing the name of the main database file. If the +** fourth parameter is 1, then the SQL statement that the third parameter +** points to has just been executed. Or, if the fourth parameter is 2, then +** the connection being passed as the second parameter is being closed. The +** third parameter is passed NULL In this case. An example of using this +** configuration option can be seen in the "test_sqllog.c" source file in +** the canonical SQLite source tree.
+** +** [[SQLITE_CONFIG_MMAP_SIZE]] +**
SQLITE_CONFIG_MMAP_SIZE +**
^SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values +** that are the default mmap size limit (the default setting for +** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. +** ^The default setting can be overridden by each database connection using +** either the [PRAGMA mmap_size] command, or by using the +** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size +** will be silently truncated if necessary so that it does not exceed the +** compile-time maximum mmap size set by the +** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ +** ^If either argument to this option is negative, then that argument is +** changed to its compile-time default. +** +** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] +**
SQLITE_CONFIG_WIN32_HEAPSIZE +**
^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is +** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro +** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value +** that specifies the maximum size of the created heap. +** +** [[SQLITE_CONFIG_PCACHE_HDRSZ]] +**
SQLITE_CONFIG_PCACHE_HDRSZ +**
^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which +** is a pointer to an integer and writes into that integer the number of extra +** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. +** The amount of extra space required can change depending on the compiler, +** target platform, and SQLite version. +** +** [[SQLITE_CONFIG_PMASZ]] +**
SQLITE_CONFIG_PMASZ +**
^The SQLITE_CONFIG_PMASZ option takes a single parameter which +** is an unsigned integer and sets the "Minimum PMA Size" for the multithreaded +** sorter to that integer. The default minimum PMA Size is set by the +** [SQLITE_SORTER_PMASZ] compile-time option. New threads are launched +** to help with sort operations when multithreaded sorting +** is enabled (using the [PRAGMA threads] command) and the amount of content +** to be sorted exceeds the page size times the minimum of the +** [PRAGMA cache_size] setting and this value. +** +** [[SQLITE_CONFIG_STMTJRNL_SPILL]] +**
SQLITE_CONFIG_STMTJRNL_SPILL +**
^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which +** becomes the [statement journal] spill-to-disk threshold. +** [Statement journals] are held in memory until their size (in bytes) +** exceeds this threshold, at which point they are written to disk. +** Or if the threshold is -1, statement journals are always held +** exclusively in memory. +** Since many statement journals never become large, setting the spill +** threshold to a value such as 64KiB can greatly reduce the amount of +** I/O required to support statement rollback. +** The default value for this setting is controlled by the +** [SQLITE_STMTJRNL_SPILL] compile-time option. +**
+*/ +#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ +#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ +#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ +#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ +#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ +#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ +#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ +#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ +/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ +#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ +#define SQLITE_CONFIG_PCACHE 14 /* no-op */ +#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ +#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ +#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ +#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ +#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ +#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ +#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ +#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ +#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ +#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ + +/* +** CAPI3REF: Database Connection Configuration Options +** +** These constants are the available integer configuration options that +** can be passed as the second argument to the [sqlite3_db_config()] interface. +** +** New configuration options may be added in future releases of SQLite. +** Existing configuration options might be discontinued. Applications +** should check the return code from [sqlite3_db_config()] to make sure that +** the call worked. ^The [sqlite3_db_config()] interface will return a +** non-zero [error code] if a discontinued or unsupported configuration option +** is invoked. +** +**
+**
SQLITE_DBCONFIG_LOOKASIDE
+**
^This option takes three additional arguments that determine the +** [lookaside memory allocator] configuration for the [database connection]. +** ^The first argument (the third parameter to [sqlite3_db_config()] is a +** pointer to a memory buffer to use for lookaside memory. +** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb +** may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the +** size of each lookaside buffer slot. ^The third argument is the number of +** slots. The size of the buffer in the first argument must be greater than +** or equal to the product of the second and third arguments. The buffer +** must be aligned to an 8-byte boundary. ^If the second argument to +** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally +** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** configuration for a database connection can only be changed when that +** connection is not currently using lookaside memory, or in other words +** when the "current value" returned by +** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. +** Any attempt to change the lookaside memory configuration when lookaside +** memory is in use leaves the configuration unchanged and returns +** [SQLITE_BUSY].)^
+** +**
SQLITE_DBCONFIG_ENABLE_FKEY
+**
^This option is used to enable or disable the enforcement of +** [foreign key constraints]. There should be two additional arguments. +** The first argument is an integer which is 0 to disable FK enforcement, +** positive to enable FK enforcement or negative to leave FK enforcement +** unchanged. The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether FK enforcement is off or on +** following this call. The second parameter may be a NULL pointer, in +** which case the FK enforcement setting is not reported back.
+** +**
SQLITE_DBCONFIG_ENABLE_TRIGGER
+**
^This option is used to enable or disable [CREATE TRIGGER | triggers]. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable triggers, +** positive to enable triggers or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether triggers are disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the trigger setting is not reported back.
+** +**
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
+**
^This option is used to enable or disable the two-argument +** version of the [fts3_tokenizer()] function which is part of the +** [FTS3] full-text search engine extension. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable fts3_tokenizer() or +** positive to enable fts3_tokenizer() or negative to leave the setting +** unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the new setting is not reported back.
+** +**
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
+**
^This option is used to enable or disable the [sqlite3_load_extension()] +** interface independently of the [load_extension()] SQL function. +** The [sqlite3_enable_load_extension()] API enables or disables both the +** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. +** There should be two additional arguments. +** When the first argument to this interface is 1, then only the C-API is +** enabled and the SQL function remains disabled. If the first argument to +** this interface is 0, then both the C-API and the SQL function are disabled. +** If the first argument is -1, then no changes are made to state of either the +** C-API or the SQL function. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface +** is disabled or enabled following this call. The second parameter may +** be a NULL pointer, in which case the new setting is not reported back. +**
+** +**
SQLITE_DBCONFIG_MAINDBNAME
+**
^This option is used to change the name of the "main" database +** schema. ^The sole argument is a pointer to a constant UTF8 string +** which will become the new schema name in place of "main". ^SQLite +** does not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into this DBCONFIG option is unchanged +** until after the database connection closes. +**
+** +**
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
+**
Usually, when a database in wal mode is closed or detached from a +** database handle, SQLite checks if this will mean that there are now no +** connections at all to the database. If so, it performs a checkpoint +** operation before closing the connection. This option may be used to +** override this behaviour. The first parameter passed to this operation +** is an integer - non-zero to disable checkpoints-on-close, or zero (the +** default) to enable them. The second parameter is a pointer to an integer +** into which is written 0 or 1 to indicate whether checkpoints-on-close +** have been disabled - 0 if they are not disabled, 1 if they are. +**
+** +**
+*/ +#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ +#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ +#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ + + +/* +** CAPI3REF: Enable Or Disable Extended Result Codes +** METHOD: sqlite3 +** +** ^The sqlite3_extended_result_codes() routine enables or disables the +** [extended result codes] feature of SQLite. ^The extended result +** codes are disabled by default for historical compatibility. +*/ +SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); + +/* +** CAPI3REF: Last Insert Rowid +** METHOD: sqlite3 +** +** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) +** has a unique 64-bit signed +** integer key called the [ROWID | "rowid"]. ^The rowid is always available +** as an undeclared column named ROWID, OID, or _ROWID_ as long as those +** names are not also used by explicitly declared columns. ^If +** the table has a column of type [INTEGER PRIMARY KEY] then that column +** is another alias for the rowid. +** +** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of +** the most recent successful [INSERT] into a rowid table or [virtual table] +** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not +** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred +** on the database connection D, then sqlite3_last_insert_rowid(D) returns +** zero. +** +** As well as being set automatically as rows are inserted into database +** tables, the value returned by this function may be set explicitly by +** [sqlite3_set_last_insert_rowid()] +** +** Some virtual table implementations may INSERT rows into rowid tables as +** part of committing a transaction (e.g. to flush data accumulated in memory +** to disk). In this case subsequent calls to this function return the rowid +** associated with these internal INSERT operations, which leads to +** unintuitive results. Virtual table implementations that do write to rowid +** tables in this way can avoid this problem by restoring the original +** rowid value using [sqlite3_set_last_insert_rowid()] before returning +** control to the user. +** +** ^(If an [INSERT] occurs within a trigger then this routine will +** return the [rowid] of the inserted row as long as the trigger is +** running. Once the trigger program ends, the value returned +** by this routine reverts to what it was before the trigger was fired.)^ +** +** ^An [INSERT] that fails due to a constraint violation is not a +** successful [INSERT] and does not change the value returned by this +** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, +** and INSERT OR ABORT make no changes to the return value of this +** routine when their insertion fails. ^(When INSERT OR REPLACE +** encounters a constraint violation, it does not fail. The +** INSERT continues to completion after deleting rows that caused +** the constraint problem so INSERT OR REPLACE will always change +** the return value of this interface.)^ +** +** ^For the purposes of this routine, an [INSERT] is considered to +** be successful even if it is subsequently rolled back. +** +** This function is accessible to SQL statements via the +** [last_insert_rowid() SQL function]. +** +** If a separate thread performs a new [INSERT] on the same +** database connection while the [sqlite3_last_insert_rowid()] +** function is running and thus changes the last insert [rowid], +** then the value returned by [sqlite3_last_insert_rowid()] is +** unpredictable and might not equal either the old or the new +** last insert [rowid]. +*/ +SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + +/* +** CAPI3REF: Set the Last Insert Rowid value. +** METHOD: sqlite3 +** +** The sqlite3_set_last_insert_rowid(D, R) method allows the application to +** set the value returned by calling sqlite3_last_insert_rowid(D) to R +** without inserting a row into the database. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); + +/* +** CAPI3REF: Count The Number Of Rows Modified +** METHOD: sqlite3 +** +** ^This function returns the number of rows modified, inserted or +** deleted by the most recently completed INSERT, UPDATE or DELETE +** statement on the database connection specified by the only parameter. +** ^Executing any other type of SQL statement does not modify the value +** returned by this function. +** +** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are +** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], +** [foreign key actions] or [REPLACE] constraint resolution are not counted. +** +** Changes to a view that are intercepted by +** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value +** returned by sqlite3_changes() immediately after an INSERT, UPDATE or +** DELETE statement run on a view is always zero. Only changes made to real +** tables are counted. +** +** Things are more complicated if the sqlite3_changes() function is +** executed while a trigger program is running. This may happen if the +** program uses the [changes() SQL function], or if some other callback +** function invokes sqlite3_changes() directly. Essentially: +** +**
    +**
  • ^(Before entering a trigger program the value returned by +** sqlite3_changes() function is saved. After the trigger program +** has finished, the original value is restored.)^ +** +**
  • ^(Within a trigger program each INSERT, UPDATE and DELETE +** statement sets the value returned by sqlite3_changes() +** upon completion as normal. Of course, this value will not include +** any changes performed by sub-triggers, as the sqlite3_changes() +** value will be saved and restored after each sub-trigger has run.)^ +**
+** +** ^This means that if the changes() SQL function (or similar) is used +** by the first INSERT, UPDATE or DELETE statement within a trigger, it +** returns the value as set when the calling statement began executing. +** ^If it is used by the second or subsequent such statement within a trigger +** program, the value returned reflects the number of rows modified by the +** previous INSERT, UPDATE or DELETE statement within the same trigger. +** +** See also the [sqlite3_total_changes()] interface, the +** [count_changes pragma], and the [changes() SQL function]. +** +** If a separate thread makes changes on the same database connection +** while [sqlite3_changes()] is running then the value returned +** is unpredictable and not meaningful. +*/ +SQLITE_API int sqlite3_changes(sqlite3*); + +/* +** CAPI3REF: Total Number Of Rows Modified +** METHOD: sqlite3 +** +** ^This function returns the total number of rows inserted, modified or +** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed +** since the database connection was opened, including those executed as +** part of trigger programs. ^Executing any other type of SQL statement +** does not affect the value returned by sqlite3_total_changes(). +** +** ^Changes made as part of [foreign key actions] are included in the +** count, but those made as part of REPLACE constraint resolution are +** not. ^Changes to a view that are intercepted by INSTEAD OF triggers +** are not counted. +** +** See also the [sqlite3_changes()] interface, the +** [count_changes pragma], and the [total_changes() SQL function]. +** +** If a separate thread makes changes on the same database connection +** while [sqlite3_total_changes()] is running then the value +** returned is unpredictable and not meaningful. +*/ +SQLITE_API int sqlite3_total_changes(sqlite3*); + +/* +** CAPI3REF: Interrupt A Long-Running Query +** METHOD: sqlite3 +** +** ^This function causes any pending database operation to abort and +** return at its earliest opportunity. This routine is typically +** called in response to a user action such as pressing "Cancel" +** or Ctrl-C where the user wants a long query operation to halt +** immediately. +** +** ^It is safe to call this routine from a thread different from the +** thread that is currently running the database operation. But it +** is not safe to call this routine with a [database connection] that +** is closed or might close before sqlite3_interrupt() returns. +** +** ^If an SQL operation is very nearly finished at the time when +** sqlite3_interrupt() is called, then it might not have an opportunity +** to be interrupted and might continue to completion. +** +** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT]. +** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE +** that is inside an explicit transaction, then the entire transaction +** will be rolled back automatically. +** +** ^The sqlite3_interrupt(D) call is in effect until all currently running +** SQL statements on [database connection] D complete. ^Any new SQL statements +** that are started after the sqlite3_interrupt() call and before the +** running statements reaches zero are interrupted as if they had been +** running prior to the sqlite3_interrupt() call. ^New SQL statements +** that are started after the running statement count reaches zero are +** not effected by the sqlite3_interrupt(). +** ^A call to sqlite3_interrupt(D) that occurs when there are no running +** SQL statements is a no-op and has no effect on SQL statements +** that are started after the sqlite3_interrupt() call returns. +*/ +SQLITE_API void sqlite3_interrupt(sqlite3*); + +/* +** CAPI3REF: Determine If An SQL Statement Is Complete +** +** These routines are useful during command-line input to determine if the +** currently entered text seems to form a complete SQL statement or +** if additional input is needed before sending the text into +** SQLite for parsing. ^These routines return 1 if the input string +** appears to be a complete SQL statement. ^A statement is judged to be +** complete if it ends with a semicolon token and is not a prefix of a +** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within +** string literals or quoted identifier names or comments are not +** independent tokens (they are part of the token in which they are +** embedded) and thus do not count as a statement terminator. ^Whitespace +** and comments that follow the final semicolon are ignored. +** +** ^These routines return 0 if the statement is incomplete. ^If a +** memory allocation fails, then SQLITE_NOMEM is returned. +** +** ^These routines do not parse the SQL statements thus +** will not detect syntactically incorrect SQL. +** +** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior +** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked +** automatically by sqlite3_complete16(). If that initialization fails, +** then the return value from sqlite3_complete16() will be non-zero +** regardless of whether or not the input SQL is complete.)^ +** +** The input to [sqlite3_complete()] must be a zero-terminated +** UTF-8 string. +** +** The input to [sqlite3_complete16()] must be a zero-terminated +** UTF-16 string in native byte order. +*/ +SQLITE_API int sqlite3_complete(const char *sql); +SQLITE_API int sqlite3_complete16(const void *sql); + +/* +** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors +** KEYWORDS: {busy-handler callback} {busy handler} +** METHOD: sqlite3 +** +** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X +** that might be invoked with argument P whenever +** an attempt is made to access a database table associated with +** [database connection] D when another thread +** or process has the table locked. +** The sqlite3_busy_handler() interface is used to implement +** [sqlite3_busy_timeout()] and [PRAGMA busy_timeout]. +** +** ^If the busy callback is NULL, then [SQLITE_BUSY] +** is returned immediately upon encountering the lock. ^If the busy callback +** is not NULL, then the callback might be invoked with two arguments. +** +** ^The first argument to the busy handler is a copy of the void* pointer which +** is the third argument to sqlite3_busy_handler(). ^The second argument to +** the busy handler callback is the number of times that the busy handler has +** been invoked previously for the same locking event. ^If the +** busy callback returns 0, then no additional attempts are made to +** access the database and [SQLITE_BUSY] is returned +** to the application. +** ^If the callback returns non-zero, then another attempt +** is made to access the database and the cycle repeats. +** +** The presence of a busy handler does not guarantee that it will be invoked +** when there is lock contention. ^If SQLite determines that invoking the busy +** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] +** to the application instead of invoking the +** busy handler. +** Consider a scenario where one process is holding a read lock that +** it is trying to promote to a reserved lock and +** a second process is holding a reserved lock that it is trying +** to promote to an exclusive lock. The first process cannot proceed +** because it is blocked by the second and the second process cannot +** proceed because it is blocked by the first. If both processes +** invoke the busy handlers, neither will make any progress. Therefore, +** SQLite returns [SQLITE_BUSY] for the first process, hoping that this +** will induce the first process to release its read lock and allow +** the second process to proceed. +** +** ^The default busy callback is NULL. +** +** ^(There can only be a single busy handler defined for each +** [database connection]. Setting a new busy handler clears any +** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] +** or evaluating [PRAGMA busy_timeout=N] will change the +** busy handler and thus clear any previously set busy handler. +** +** The busy callback should not take any actions which modify the +** database connection that invoked the busy handler. In other words, +** the busy handler is not reentrant. Any such actions +** result in undefined behavior. +** +** A busy handler must not close the database connection +** or [prepared statement] that invoked the busy handler. +*/ +SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); + +/* +** CAPI3REF: Set A Busy Timeout +** METHOD: sqlite3 +** +** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps +** for a specified amount of time when a table is locked. ^The handler +** will sleep multiple times until at least "ms" milliseconds of sleeping +** have accumulated. ^After at least "ms" milliseconds of sleeping, +** the handler returns 0 which causes [sqlite3_step()] to return +** [SQLITE_BUSY]. +** +** ^Calling this routine with an argument less than or equal to zero +** turns off all busy handlers. +** +** ^(There can only be a single busy handler for a particular +** [database connection] at any given moment. If another busy handler +** was defined (using [sqlite3_busy_handler()]) prior to calling +** this routine, that other busy handler is cleared.)^ +** +** See also: [PRAGMA busy_timeout] +*/ +SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); + +/* +** CAPI3REF: Convenience Routines For Running Queries +** METHOD: sqlite3 +** +** This is a legacy interface that is preserved for backwards compatibility. +** Use of this interface is not recommended. +** +** Definition: A result table is memory data structure created by the +** [sqlite3_get_table()] interface. A result table records the +** complete query results from one or more queries. +** +** The table conceptually has a number of rows and columns. But +** these numbers are not part of the result table itself. These +** numbers are obtained separately. Let N be the number of rows +** and M be the number of columns. +** +** A result table is an array of pointers to zero-terminated UTF-8 strings. +** There are (N+1)*M elements in the array. The first M pointers point +** to zero-terminated strings that contain the names of the columns. +** The remaining entries all point to query results. NULL values result +** in NULL pointers. All other values are in their UTF-8 zero-terminated +** string representation as returned by [sqlite3_column_text()]. +** +** A result table might consist of one or more memory allocations. +** It is not safe to pass a result table directly to [sqlite3_free()]. +** A result table should be deallocated using [sqlite3_free_table()]. +** +** ^(As an example of the result table format, suppose a query result +** is as follows: +** +**
+**        Name        | Age
+**        -----------------------
+**        Alice       | 43
+**        Bob         | 28
+**        Cindy       | 21
+** 
+** +** There are two column (M==2) and three rows (N==3). Thus the +** result table has 8 entries. Suppose the result table is stored +** in an array names azResult. Then azResult holds this content: +** +**
+**        azResult[0] = "Name";
+**        azResult[1] = "Age";
+**        azResult[2] = "Alice";
+**        azResult[3] = "43";
+**        azResult[4] = "Bob";
+**        azResult[5] = "28";
+**        azResult[6] = "Cindy";
+**        azResult[7] = "21";
+** 
)^ +** +** ^The sqlite3_get_table() function evaluates one or more +** semicolon-separated SQL statements in the zero-terminated UTF-8 +** string of its 2nd parameter and returns a result table to the +** pointer given in its 3rd parameter. +** +** After the application has finished with the result from sqlite3_get_table(), +** it must pass the result table pointer to sqlite3_free_table() in order to +** release the memory that was malloced. Because of the way the +** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling +** function must not try to call [sqlite3_free()] directly. Only +** [sqlite3_free_table()] is able to release the memory properly and safely. +** +** The sqlite3_get_table() interface is implemented as a wrapper around +** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access +** to any internal data structures of SQLite. It uses only the public +** interface defined here. As a consequence, errors that occur in the +** wrapper layer outside of the internal [sqlite3_exec()] call are not +** reflected in subsequent calls to [sqlite3_errcode()] or +** [sqlite3_errmsg()]. +*/ +SQLITE_API int sqlite3_get_table( + sqlite3 *db, /* An open database */ + const char *zSql, /* SQL to be evaluated */ + char ***pazResult, /* Results of the query */ + int *pnRow, /* Number of result rows written here */ + int *pnColumn, /* Number of result columns written here */ + char **pzErrmsg /* Error msg written here */ +); +SQLITE_API void sqlite3_free_table(char **result); + +/* +** CAPI3REF: Formatted String Printing Functions +** +** These routines are work-alikes of the "printf()" family of functions +** from the standard C library. +** These routines understand most of the common K&R formatting options, +** plus some additional non-standard formats, detailed below. +** Note that some of the more obscure formatting options from recent +** C-library standards are omitted from this implementation. +** +** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their +** results into memory obtained from [sqlite3_malloc()]. +** The strings returned by these two routines should be +** released by [sqlite3_free()]. ^Both routines return a +** NULL pointer if [sqlite3_malloc()] is unable to allocate enough +** memory to hold the resulting string. +** +** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from +** the standard C library. The result is written into the +** buffer supplied as the second parameter whose size is given by +** the first parameter. Note that the order of the +** first two parameters is reversed from snprintf().)^ This is an +** historical accident that cannot be fixed without breaking +** backwards compatibility. ^(Note also that sqlite3_snprintf() +** returns a pointer to its buffer instead of the number of +** characters actually written into the buffer.)^ We admit that +** the number of characters written would be a more useful return +** value but we cannot change the implementation of sqlite3_snprintf() +** now without breaking compatibility. +** +** ^As long as the buffer size is greater than zero, sqlite3_snprintf() +** guarantees that the buffer is always zero-terminated. ^The first +** parameter "n" is the total size of the buffer, including space for +** the zero terminator. So the longest string that can be completely +** written will be n-1 characters. +** +** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). +** +** These routines all implement some additional formatting +** options that are useful for constructing SQL statements. +** All of the usual printf() formatting options apply. In addition, there +** is are "%q", "%Q", "%w" and "%z" options. +** +** ^(The %q option works like %s in that it substitutes a nul-terminated +** string from the argument list. But %q also doubles every '\'' character. +** %q is designed for use inside a string literal.)^ By doubling each '\'' +** character it escapes that character and allows it to be inserted into +** the string. +** +** For example, assume the string variable zText contains text as follows: +** +**
+**  char *zText = "It's a happy day!";
+** 
+** +** One can use this text in an SQL statement as follows: +** +**
+**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
+**  sqlite3_exec(db, zSQL, 0, 0, 0);
+**  sqlite3_free(zSQL);
+** 
+** +** Because the %q format string is used, the '\'' character in zText +** is escaped and the SQL generated is as follows: +** +**
+**  INSERT INTO table1 VALUES('It''s a happy day!')
+** 
+** +** This is correct. Had we used %s instead of %q, the generated SQL +** would have looked like this: +** +**
+**  INSERT INTO table1 VALUES('It's a happy day!');
+** 
+** +** This second example is an SQL syntax error. As a general rule you should +** always use %q instead of %s when inserting text into a string literal. +** +** ^(The %Q option works like %q except it also adds single quotes around +** the outside of the total string. Additionally, if the parameter in the +** argument list is a NULL pointer, %Q substitutes the text "NULL" (without +** single quotes).)^ So, for example, one could say: +** +**
+**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
+**  sqlite3_exec(db, zSQL, 0, 0, 0);
+**  sqlite3_free(zSQL);
+** 
+** +** The code above will render a correct SQL statement in the zSQL +** variable even if the zText variable is a NULL pointer. +** +** ^(The "%w" formatting option is like "%q" except that it expects to +** be contained within double-quotes instead of single quotes, and it +** escapes the double-quote character instead of the single-quote +** character.)^ The "%w" formatting option is intended for safely inserting +** table and column names into a constructed SQL statement. +** +** ^(The "%z" formatting option works like "%s" but with the +** addition that after the string has been read and copied into +** the result, [sqlite3_free()] is called on the input string.)^ +*/ +SQLITE_API char *sqlite3_mprintf(const char*,...); +SQLITE_API char *sqlite3_vmprintf(const char*, va_list); +SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); +SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); + +/* +** CAPI3REF: Memory Allocation Subsystem +** +** The SQLite core uses these three routines for all of its own +** internal memory allocation needs. "Core" in the previous sentence +** does not include operating-system specific VFS implementation. The +** Windows VFS uses native malloc() and free() for some operations. +** +** ^The sqlite3_malloc() routine returns a pointer to a block +** of memory at least N bytes in length, where N is the parameter. +** ^If sqlite3_malloc() is unable to obtain sufficient free +** memory, it returns a NULL pointer. ^If the parameter N to +** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns +** a NULL pointer. +** +** ^The sqlite3_malloc64(N) routine works just like +** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead +** of a signed 32-bit integer. +** +** ^Calling sqlite3_free() with a pointer previously returned +** by sqlite3_malloc() or sqlite3_realloc() releases that memory so +** that it might be reused. ^The sqlite3_free() routine is +** a no-op if is called with a NULL pointer. Passing a NULL pointer +** to sqlite3_free() is harmless. After being freed, memory +** should neither be read nor written. Even reading previously freed +** memory might result in a segmentation fault or other severe error. +** Memory corruption, a segmentation fault, or other severe error +** might result if sqlite3_free() is called with a non-NULL pointer that +** was not obtained from sqlite3_malloc() or sqlite3_realloc(). +** +** ^The sqlite3_realloc(X,N) interface attempts to resize a +** prior memory allocation X to be at least N bytes. +** ^If the X parameter to sqlite3_realloc(X,N) +** is a NULL pointer then its behavior is identical to calling +** sqlite3_malloc(N). +** ^If the N parameter to sqlite3_realloc(X,N) is zero or +** negative then the behavior is exactly the same as calling +** sqlite3_free(X). +** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation +** of at least N bytes in size or NULL if insufficient memory is available. +** ^If M is the size of the prior allocation, then min(N,M) bytes +** of the prior allocation are copied into the beginning of buffer returned +** by sqlite3_realloc(X,N) and the prior allocation is freed. +** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the +** prior allocation is not freed. +** +** ^The sqlite3_realloc64(X,N) interfaces works the same as +** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead +** of a 32-bit signed integer. +** +** ^If X is a memory allocation previously obtained from sqlite3_malloc(), +** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then +** sqlite3_msize(X) returns the size of that memory allocation in bytes. +** ^The value returned by sqlite3_msize(X) might be larger than the number +** of bytes requested when X was allocated. ^If X is a NULL pointer then +** sqlite3_msize(X) returns zero. If X points to something that is not +** the beginning of memory allocation, or if it points to a formerly +** valid memory allocation that has now been freed, then the behavior +** of sqlite3_msize(X) is undefined and possibly harmful. +** +** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(), +** sqlite3_malloc64(), and sqlite3_realloc64() +** is always aligned to at least an 8 byte boundary, or to a +** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time +** option is used. +** +** In SQLite version 3.5.0 and 3.5.1, it was possible to define +** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in +** implementation of these routines to be omitted. That capability +** is no longer provided. Only built-in memory allocators can be used. +** +** Prior to SQLite version 3.7.10, the Windows OS interface layer called +** the system malloc() and free() directly when converting +** filenames between the UTF-8 encoding used by SQLite +** and whatever filename encoding is used by the particular Windows +** installation. Memory allocation errors were detected, but +** they were reported back as [SQLITE_CANTOPEN] or +** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. +** +** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] +** must be either NULL or else pointers obtained from a prior +** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have +** not yet been released. +** +** The application must not read or write any part of +** a block of memory after it has been released using +** [sqlite3_free()] or [sqlite3_realloc()]. +*/ +SQLITE_API void *sqlite3_malloc(int); +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64); +SQLITE_API void *sqlite3_realloc(void*, int); +SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64); +SQLITE_API void sqlite3_free(void*); +SQLITE_API sqlite3_uint64 sqlite3_msize(void*); + +/* +** CAPI3REF: Memory Allocator Statistics +** +** SQLite provides these two interfaces for reporting on the status +** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()] +** routines, which form the built-in memory allocation subsystem. +** +** ^The [sqlite3_memory_used()] routine returns the number of bytes +** of memory currently outstanding (malloced but not freed). +** ^The [sqlite3_memory_highwater()] routine returns the maximum +** value of [sqlite3_memory_used()] since the high-water mark +** was last reset. ^The values returned by [sqlite3_memory_used()] and +** [sqlite3_memory_highwater()] include any overhead +** added by SQLite in its implementation of [sqlite3_malloc()], +** but not overhead added by the any underlying system library +** routines that [sqlite3_malloc()] may call. +** +** ^The memory high-water mark is reset to the current value of +** [sqlite3_memory_used()] if and only if the parameter to +** [sqlite3_memory_highwater()] is true. ^The value returned +** by [sqlite3_memory_highwater(1)] is the high-water mark +** prior to the reset. +*/ +SQLITE_API sqlite3_int64 sqlite3_memory_used(void); +SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); + +/* +** CAPI3REF: Pseudo-Random Number Generator +** +** SQLite contains a high-quality pseudo-random number generator (PRNG) used to +** select random [ROWID | ROWIDs] when inserting new records into a table that +** already uses the largest possible [ROWID]. The PRNG is also used for +** the build-in random() and randomblob() SQL functions. This interface allows +** applications to access the same PRNG for other purposes. +** +** ^A call to this routine stores N bytes of randomness into buffer P. +** ^The P parameter can be a NULL pointer. +** +** ^If this routine has not been previously called or if the previous +** call had N less than one or a NULL pointer for P, then the PRNG is +** seeded using randomness obtained from the xRandomness method of +** the default [sqlite3_vfs] object. +** ^If the previous call to this routine had an N of 1 or more and a +** non-NULL P then the pseudo-randomness is generated +** internally and without recourse to the [sqlite3_vfs] xRandomness +** method. +*/ +SQLITE_API void sqlite3_randomness(int N, void *P); + +/* +** CAPI3REF: Compile-Time Authorization Callbacks +** METHOD: sqlite3 +** KEYWORDS: {authorizer callback} +** +** ^This routine registers an authorizer callback with a particular +** [database connection], supplied in the first argument. +** ^The authorizer callback is invoked as SQL statements are being compiled +** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], +** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** points during the compilation process, as logic is being created +** to perform various actions, the authorizer callback is invoked to +** see if those actions are allowed. ^The authorizer callback should +** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the +** specific action but allow the SQL statement to continue to be +** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be +** rejected with an error. ^If the authorizer callback returns +** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] +** then the [sqlite3_prepare_v2()] or equivalent call that triggered +** the authorizer will fail with an error message. +** +** When the callback returns [SQLITE_OK], that means the operation +** requested is ok. ^When the callback returns [SQLITE_DENY], the +** [sqlite3_prepare_v2()] or equivalent call that triggered the +** authorizer will fail with an error message explaining that +** access is denied. +** +** ^The first parameter to the authorizer callback is a copy of the third +** parameter to the sqlite3_set_authorizer() interface. ^The second parameter +** to the callback is an integer [SQLITE_COPY | action code] that specifies +** the particular action to be authorized. ^The third through sixth parameters +** to the callback are either NULL pointers or zero-terminated strings +** that contain additional details about the action to be authorized. +** Applications must always be prepared to encounter a NULL pointer in any +** of the third through the sixth parameters of the authorization callback. +** +** ^If the action code is [SQLITE_READ] +** and the callback returns [SQLITE_IGNORE] then the +** [prepared statement] statement is constructed to substitute +** a NULL value in place of the table column that would have +** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] +** return can be used to deny an untrusted user access to individual +** columns of a table. +** ^When a table is referenced by a [SELECT] but no column values are +** extracted from that table (for example in a query like +** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback +** is invoked once for that table with a column name that is an empty string. +** ^If the action code is [SQLITE_DELETE] and the callback returns +** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the +** [truncate optimization] is disabled and all rows are deleted individually. +** +** An authorizer is used when [sqlite3_prepare | preparing] +** SQL statements from an untrusted source, to ensure that the SQL statements +** do not try to access data they are not allowed to see, or that they do not +** try to execute malicious statements that damage the database. For +** example, an application may allow a user to enter arbitrary +** SQL queries for evaluation by a database. But the application does +** not want the user to be able to make arbitrary changes to the +** database. An authorizer could then be put in place while the +** user-entered SQL is being [sqlite3_prepare | prepared] that +** disallows everything except [SELECT] statements. +** +** Applications that need to process SQL from untrusted sources +** might also consider lowering resource limits using [sqlite3_limit()] +** and limiting database size using the [max_page_count] [PRAGMA] +** in addition to using an authorizer. +** +** ^(Only a single authorizer can be in place on a database connection +** at a time. Each call to sqlite3_set_authorizer overrides the +** previous call.)^ ^Disable the authorizer by installing a NULL callback. +** The authorizer is disabled by default. +** +** The authorizer callback must not do anything that will modify +** the database connection that invoked the authorizer callback. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the +** statement might be re-prepared during [sqlite3_step()] due to a +** schema change. Hence, the application should ensure that the +** correct authorizer callback remains in place during the [sqlite3_step()]. +** +** ^Note that the authorizer callback is invoked only during +** [sqlite3_prepare()] or its variants. Authorization is not +** performed during statement evaluation in [sqlite3_step()], unless +** as stated in the previous paragraph, sqlite3_step() invokes +** sqlite3_prepare_v2() to reprepare a statement after a schema change. +*/ +SQLITE_API int sqlite3_set_authorizer( + sqlite3*, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pUserData +); + +/* +** CAPI3REF: Authorizer Return Codes +** +** The [sqlite3_set_authorizer | authorizer callback function] must +** return either [SQLITE_OK] or one of these two constants in order +** to signal SQLite whether or not the action is permitted. See the +** [sqlite3_set_authorizer | authorizer documentation] for additional +** information. +** +** Note that SQLITE_IGNORE is also used as a [conflict resolution mode] +** returned from the [sqlite3_vtab_on_conflict()] interface. +*/ +#define SQLITE_DENY 1 /* Abort the SQL statement with an error */ +#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ + +/* +** CAPI3REF: Authorizer Action Codes +** +** The [sqlite3_set_authorizer()] interface registers a callback function +** that is invoked to authorize certain SQL statement actions. The +** second parameter to the callback is an integer code that specifies +** what action is being authorized. These are the integer action codes that +** the authorizer callback may be passed. +** +** These action code values signify what kind of operation is to be +** authorized. The 3rd and 4th parameters to the authorization +** callback function will be parameters or NULL depending on which of these +** codes is used as the second parameter. ^(The 5th parameter to the +** authorizer callback is the name of the database ("main", "temp", +** etc.) if applicable.)^ ^The 6th parameter to the authorizer callback +** is the name of the inner-most trigger or view that is responsible for +** the access attempt or NULL if this access attempt is directly from +** top-level SQL code. +*/ +/******************************************* 3rd ************ 4th ***********/ +#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ +#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ +#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ +#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ +#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ +#define SQLITE_CREATE_VIEW 8 /* View Name NULL */ +#define SQLITE_DELETE 9 /* Table Name NULL */ +#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ +#define SQLITE_DROP_TABLE 11 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ +#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ +#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ +#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ +#define SQLITE_DROP_VIEW 17 /* View Name NULL */ +#define SQLITE_INSERT 18 /* Table Name NULL */ +#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ +#define SQLITE_READ 20 /* Table Name Column Name */ +#define SQLITE_SELECT 21 /* NULL NULL */ +#define SQLITE_TRANSACTION 22 /* Operation NULL */ +#define SQLITE_UPDATE 23 /* Table Name Column Name */ +#define SQLITE_ATTACH 24 /* Filename NULL */ +#define SQLITE_DETACH 25 /* Database Name NULL */ +#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ +#define SQLITE_REINDEX 27 /* Index Name NULL */ +#define SQLITE_ANALYZE 28 /* Table Name NULL */ +#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ +#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ +#define SQLITE_FUNCTION 31 /* NULL Function Name */ +#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ +#define SQLITE_COPY 0 /* No longer used */ +#define SQLITE_RECURSIVE 33 /* NULL NULL */ + +/* +** CAPI3REF: Tracing And Profiling Functions +** METHOD: sqlite3 +** +** These routines are deprecated. Use the [sqlite3_trace_v2()] interface +** instead of the routines described here. +** +** These routines register callback functions that can be used for +** tracing and profiling the execution of SQL statements. +** +** ^The callback function registered by sqlite3_trace() is invoked at +** various times when an SQL statement is being run by [sqlite3_step()]. +** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the +** SQL statement text as the statement first begins executing. +** ^(Additional sqlite3_trace() callbacks might occur +** as each triggered subprogram is entered. The callbacks for triggers +** contain a UTF-8 SQL comment that identifies the trigger.)^ +** +** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit +** the length of [bound parameter] expansion in the output of sqlite3_trace(). +** +** ^The callback function registered by sqlite3_profile() is invoked +** as each SQL statement finishes. ^The profile callback contains +** the original statement text and an estimate of wall-clock time +** of how long that statement took to run. ^The profile callback +** time is in units of nanoseconds, however the current implementation +** is only capable of millisecond resolution so the six least significant +** digits in the time are meaningless. Future versions of SQLite +** might provide greater resolution on the profiler callback. The +** sqlite3_profile() function is considered experimental and is +** subject to change in future versions of SQLite. +*/ +SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, + void(*xTrace)(void*,const char*), void*); +SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, + void(*xProfile)(void*,const char*,sqlite3_uint64), void*); + +/* +** CAPI3REF: SQL Trace Event Codes +** KEYWORDS: SQLITE_TRACE +** +** These constants identify classes of events that can be monitored +** using the [sqlite3_trace_v2()] tracing logic. The third argument +** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** the following constants. ^The first argument to the trace callback +** is one of the following constants. +** +** New tracing constants may be added in future releases. +** +** ^A trace callback has four arguments: xCallback(T,C,P,X). +** ^The T argument is one of the integer type codes above. +** ^The C argument is a copy of the context pointer passed in as the +** fourth argument to [sqlite3_trace_v2()]. +** The P and X arguments are pointers whose meanings depend on T. +** +**
+** [[SQLITE_TRACE_STMT]]
SQLITE_TRACE_STMT
+**
^An SQLITE_TRACE_STMT callback is invoked when a prepared statement +** first begins running and possibly at other times during the +** execution of the prepared statement, such as at the start of each +** trigger subprogram. ^The P argument is a pointer to the +** [prepared statement]. ^The X argument is a pointer to a string which +** is the unexpanded SQL text of the prepared statement or an SQL comment +** that indicates the invocation of a trigger. ^The callback can compute +** the same text that would have been returned by the legacy [sqlite3_trace()] +** interface by using the X argument when X begins with "--" and invoking +** [sqlite3_expanded_sql(P)] otherwise. +** +** [[SQLITE_TRACE_PROFILE]]
SQLITE_TRACE_PROFILE
+**
^An SQLITE_TRACE_PROFILE callback provides approximately the same +** information as is provided by the [sqlite3_profile()] callback. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. +** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. +** +** [[SQLITE_TRACE_ROW]]
SQLITE_TRACE_ROW
+**
^An SQLITE_TRACE_ROW callback is invoked whenever a prepared +** statement generates a single row of result. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument is unused. +** +** [[SQLITE_TRACE_CLOSE]]
SQLITE_TRACE_CLOSE
+**
^An SQLITE_TRACE_CLOSE callback is invoked when a database +** connection closes. +** ^The P argument is a pointer to the [database connection] object +** and the X argument is unused. +**
+*/ +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 + +/* +** CAPI3REF: SQL Trace Hook +** METHOD: sqlite3 +** +** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback +** function X against [database connection] D, using property mask M +** and context pointer P. ^If the X callback is +** NULL or if the M mask is zero, then tracing is disabled. The +** M argument should be the bitwise OR-ed combination of +** zero or more [SQLITE_TRACE] constants. +** +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). +** +** ^The X callback is invoked whenever any of the events identified by +** mask M occur. ^The integer return value from the callback is currently +** ignored, though this may change in future releases. Callback +** implementations should return zero to ensure future compatibility. +** +** ^A trace callback is invoked with four arguments: callback(T,C,P,X). +** ^The T argument is one of the [SQLITE_TRACE] +** constants to indicate why the callback was invoked. +** ^The C argument is a copy of the context pointer. +** The P and X arguments are pointers whose meanings depend on T. +** +** The sqlite3_trace_v2() interface is intended to replace the legacy +** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which +** are deprecated. +*/ +SQLITE_API int sqlite3_trace_v2( + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx +); + +/* +** CAPI3REF: Query Progress Callbacks +** METHOD: sqlite3 +** +** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback +** function X to be invoked periodically during long running calls to +** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for +** database connection D. An example use for this +** interface is to keep a GUI updated during a large query. +** +** ^The parameter P is passed through as the only parameter to the +** callback function X. ^The parameter N is the approximate number of +** [virtual machine instructions] that are evaluated between successive +** invocations of the callback X. ^If N is less than one then the progress +** handler is disabled. +** +** ^Only a single progress handler may be defined at one time per +** [database connection]; setting a new progress handler cancels the +** old one. ^Setting parameter X to NULL disables the progress handler. +** ^The progress handler is also disabled by setting N to a value less +** than 1. +** +** ^If the progress callback returns non-zero, the operation is +** interrupted. This feature can be used to implement a +** "Cancel" button on a GUI progress dialog box. +** +** The progress handler callback must not do anything that will modify +** the database connection that invoked the progress handler. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +*/ +SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); + +/* +** CAPI3REF: Opening A New Database Connection +** CONSTRUCTOR: sqlite3 +** +** ^These routines open an SQLite database file as specified by the +** filename argument. ^The filename argument is interpreted as UTF-8 for +** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte +** order for sqlite3_open16(). ^(A [database connection] handle is usually +** returned in *ppDb, even if an error occurs. The only exception is that +** if SQLite is unable to allocate memory to hold the [sqlite3] object, +** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] +** object.)^ ^(If the database is opened (and/or created) successfully, then +** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The +** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain +** an English language description of the error following a failure of any +** of the sqlite3_open() routines. +** +** ^The default encoding will be UTF-8 for databases created using +** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases +** created using sqlite3_open16() will be UTF-16 in the native byte order. +** +** Whether or not an error occurs when it is opened, resources +** associated with the [database connection] handle should be released by +** passing it to [sqlite3_close()] when it is no longer required. +** +** The sqlite3_open_v2() interface works like sqlite3_open() +** except that it accepts two additional parameters for additional control +** over the new database connection. ^(The flags parameter to +** sqlite3_open_v2() can take one of +** the following three values, optionally combined with the +** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], +** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ +** +**
+** ^(
[SQLITE_OPEN_READONLY]
+**
The database is opened in read-only mode. If the database does not +** already exist, an error is returned.
)^ +** +** ^(
[SQLITE_OPEN_READWRITE]
+**
The database is opened for reading and writing if possible, or reading +** only if the file is write protected by the operating system. In either +** case the database must already exist, otherwise an error is returned.
)^ +** +** ^(
[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
+**
The database is opened for reading and writing, and is created if +** it does not already exist. This is the behavior that is always used for +** sqlite3_open() and sqlite3_open16().
)^ +**
+** +** If the 3rd parameter to sqlite3_open_v2() is not one of the +** combinations shown above optionally combined with other +** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] +** then the behavior is undefined. +** +** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection +** opens in the multi-thread [threading mode] as long as the single-thread +** mode has not been set at compile-time or start-time. ^If the +** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens +** in the serialized [threading mode] unless single-thread was +** previously selected at compile-time or start-time. +** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be +** eligible to use [shared cache mode], regardless of whether or not shared +** cache is enabled using [sqlite3_enable_shared_cache()]. ^The +** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not +** participate in [shared cache mode] even if it is enabled. +** +** ^The fourth parameter to sqlite3_open_v2() is the name of the +** [sqlite3_vfs] object that defines the operating system interface that +** the new database connection should use. ^If the fourth parameter is +** a NULL pointer then the default [sqlite3_vfs] object is used. +** +** ^If the filename is ":memory:", then a private, temporary in-memory database +** is created for the connection. ^This in-memory database will vanish when +** the database connection is closed. Future versions of SQLite might +** make use of additional special filenames that begin with the ":" character. +** It is recommended that when a database filename actually does begin with +** a ":" character you should prefix the filename with a pathname such as +** "./" to avoid ambiguity. +** +** ^If the filename is an empty string, then a private, temporary +** on-disk database will be created. ^This private database will be +** automatically deleted as soon as the database connection is closed. +** +** [[URI filenames in sqlite3_open()]]

URI Filenames

+** +** ^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 +** 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 +** by default, but future releases of SQLite might enable URI filename +** interpretation by default. See "[URI filenames]" for additional +** information. +** +** URI filenames are parsed according to RFC 3986. ^If the URI contains an +** authority, then it must be either an empty string or the string +** "localhost". ^If the authority is not an empty string or "localhost", an +** error is returned to the caller. ^The fragment component of a URI, if +** present, is ignored. +** +** ^SQLite uses the path component of the URI as the name of the disk file +** which contains the database. ^If the path begins with a '/' character, +** then it is interpreted as an absolute path. ^If the path does not begin +** with a '/' (meaning that the authority section is omitted from the URI) +** then the path is interpreted as a relative path. +** ^(On windows, the first component of an absolute path +** is a drive specification (e.g. "C:").)^ +** +** [[core URI query parameters]] +** The query component of a URI may contain parameters that are interpreted +** either by SQLite itself, or by a [VFS | custom VFS implementation]. +** SQLite and its built-in [VFSes] interpret the +** following query parameters: +** +**
    +**
  • vfs: ^The "vfs" parameter may be used to specify the name of +** a VFS object that provides the operating system interface that should +** be used to access the database file on disk. ^If this option is set to +** an empty string the default VFS object is used. ^Specifying an unknown +** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is +** present, then the VFS specified by the option takes precedence over +** the value passed as the fourth parameter to sqlite3_open_v2(). +** +**
  • mode: ^(The mode parameter may be set to either "ro", "rw", +** "rwc", or "memory". Attempting to set it to any other value is +** an error)^. +** ^If "ro" is specified, then the database is opened for read-only +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the +** third argument to sqlite3_open_v2(). ^If the mode option is set to +** "rw", then the database is opened for read-write (but not create) +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had +** been set. ^Value "rwc" is equivalent to setting both +** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is +** set to "memory" then a pure [in-memory database] that never reads +** or writes from disk is used. ^It is an error to specify a value for +** the mode parameter that is less restrictive than that specified by +** the flags passed in the third parameter to sqlite3_open_v2(). +** +**
  • cache: ^The cache parameter may be set to either "shared" or +** "private". ^Setting it to "shared" is equivalent to setting the +** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is +** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. +** ^If sqlite3_open_v2() is used and the "cache" parameter is present in +** a URI filename, its value overrides any behavior requested by setting +** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +** +**
  • psow: ^The psow parameter indicates whether or not the +** [powersafe overwrite] property does or does not apply to the +** storage media on which the database file resides. +** +**
  • nolock: ^The nolock parameter is a boolean query parameter +** which if set disables file locking in rollback journal modes. This +** is useful for accessing a database on a filesystem that does not +** support locking. Caution: Database corruption might result if two +** or more processes write to the same database and any one of those +** processes uses nolock=1. +** +**
  • immutable: ^The immutable parameter is a boolean query +** parameter that indicates that the database file is stored on +** read-only media. ^When immutable is set, SQLite assumes that the +** database file cannot be changed, even by a process with higher +** privilege, and so the database is opened read-only and all locking +** and change detection is disabled. Caution: Setting the immutable +** property on a database file that does in fact change can result +** in incorrect query results and/or [SQLITE_CORRUPT] errors. +** See also: [SQLITE_IOCAP_IMMUTABLE]. +** +**
+** +** ^Specifying an unknown parameter in the query component of a URI is not an +** error. Future versions of SQLite might understand additional query +** parameters. See "[query parameters with special meaning to SQLite]" for +** additional information. +** +** [[URI filename examples]]

URI filename examples

+** +** +**
URI filenames Results +**
file:data.db +** Open the file "data.db" in the current directory. +**
file:/home/fred/data.db
+** file:///home/fred/data.db
+** file://localhost/home/fred/data.db
+** Open the database file "/home/fred/data.db". +**
file://darkstar/home/fred/data.db +** An error. "darkstar" is not a recognized authority. +**
+** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db +** Windows only: Open the file "data.db" on fred's desktop on drive +** C:. Note that the %20 escaping in this example is not strictly +** necessary - space characters can be used literally +** in URI filenames. +**
file:data.db?mode=ro&cache=private +** Open file "data.db" in the current directory for read-only access. +** Regardless of whether or not shared-cache mode is enabled by +** default, use a private cache. +**
file:/home/fred/data.db?vfs=unix-dotfile +** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" +** that uses dot-files in place of posix advisory locking. +**
file:data.db?mode=readonly +** An error. "readonly" is not a valid option for the "mode" parameter. +**
+** +** ^URI hexadecimal escape sequences (%HH) are supported within the path and +** query components of a URI. A hexadecimal escape sequence consists of a +** percent sign - "%" - followed by exactly two hexadecimal digits +** specifying an octet value. ^Before the path or query components of a +** URI filename are interpreted, they are encoded using UTF-8 and all +** hexadecimal escape sequences replaced by a single byte containing the +** corresponding octet. If this process generates an invalid UTF-8 encoding, +** the results are undefined. +** +** Note to Windows users: The encoding used for the filename argument +** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever +** codepage is currently defined. Filenames containing international +** characters must be converted to UTF-8 prior to passing them into +** sqlite3_open() or sqlite3_open_v2(). +** +** Note to Windows Runtime users: The temporary directory must be set +** prior to calling sqlite3_open() or sqlite3_open_v2(). Otherwise, various +** features that require the use of temporary files may fail. +** +** See also: [sqlite3_temp_directory] +*/ +SQLITE_API int sqlite3_open( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +SQLITE_API int sqlite3_open16( + const void *filename, /* Database filename (UTF-16) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +SQLITE_API int sqlite3_open_v2( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ +); + +/* +** CAPI3REF: Obtain Values For URI Parameters +** +** These are utility routines, useful to VFS implementations, that check +** to see if a database file was a URI that contained a specific query +** parameter, and if so obtains the value of that query parameter. +** +** If F is the database filename pointer passed into the xOpen() method of +** a VFS implementation when the flags parameter to xOpen() has one or +** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and +** P is the name of the query parameter, then +** sqlite3_uri_parameter(F,P) returns the value of the P +** parameter if it exists or a NULL pointer if P does not appear as a +** query parameter on F. If P is a query parameter of F +** has no explicit value, then sqlite3_uri_parameter(F,P) returns +** a pointer to an empty string. +** +** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean +** parameter and returns true (1) or false (0) according to the value +** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the +** value of query parameter P is one of "yes", "true", or "on" in any +** case or if the value begins with a non-zero number. The +** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of +** query parameter P is one of "no", "false", or "off" in any case or +** if the value begins with a numeric zero. If P is not a query +** parameter on F or if the value of P is does not match any of the +** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). +** +** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a +** 64-bit signed integer and returns that integer, or D if P does not +** exist. If the value of P is something other than an integer, then +** zero is returned. +** +** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and +** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and +** is not a database file pathname pointer that SQLite passed into the xOpen +** VFS method, then the behavior of this routine is undefined and probably +** undesirable. +*/ +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); +SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); +SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); + + +/* +** CAPI3REF: Error Codes And Messages +** METHOD: sqlite3 +** +** ^If the most recent sqlite3_* API call associated with +** [database connection] D failed, then the sqlite3_errcode(D) interface +** returns the numeric [result code] or [extended result code] for that +** API call. +** If the most recent API call was successful, +** then the return value from sqlite3_errcode() is undefined. +** ^The sqlite3_extended_errcode() +** interface is the same except that it always returns the +** [extended result code] even when extended result codes are +** disabled. +** +** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language +** text that describes the error, as either UTF-8 or UTF-16 respectively. +** ^(Memory to hold the error message string is managed internally. +** The application does not need to worry about freeing the result. +** However, the error string might be overwritten or deallocated by +** subsequent calls to other SQLite interface functions.)^ +** +** ^The sqlite3_errstr() interface returns the English-language text +** that describes the [result code], as UTF-8. +** ^(Memory to hold the error message string is managed internally +** and must not be freed by the application)^. +** +** When the serialized [threading mode] is in use, it might be the +** case that a second error occurs on a separate thread in between +** the time of the first error and the call to these interfaces. +** When that happens, the second error will be reported since these +** interfaces always report the most recent result. To avoid +** this, each thread can obtain exclusive use of the [database connection] D +** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning +** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after +** all calls to the interfaces listed here are completed. +** +** If an interface fails with SQLITE_MISUSE, that means the interface +** was invoked incorrectly by the application. In that case, the +** error code and message may or may not be set. +*/ +SQLITE_API int sqlite3_errcode(sqlite3 *db); +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); +SQLITE_API const char *sqlite3_errmsg(sqlite3*); +SQLITE_API const void *sqlite3_errmsg16(sqlite3*); +SQLITE_API const char *sqlite3_errstr(int); + +/* +** CAPI3REF: Prepared Statement Object +** KEYWORDS: {prepared statement} {prepared statements} +** +** An instance of this object represents a single SQL statement that +** has been compiled into binary form and is ready to be evaluated. +** +** Think of each SQL statement as a separate computer program. The +** original SQL text is source code. A prepared statement object +** is the compiled object code. All SQL must be converted into a +** prepared statement before it can be run. +** +** The life-cycle of a prepared statement object usually goes like this: +** +**
    +**
  1. Create the prepared statement object using [sqlite3_prepare_v2()]. +**
  2. Bind values to [parameters] using the sqlite3_bind_*() +** interfaces. +**
  3. Run the SQL by calling [sqlite3_step()] one or more times. +**
  4. Reset the prepared statement using [sqlite3_reset()] then go back +** to step 2. Do this zero or more times. +**
  5. Destroy the object using [sqlite3_finalize()]. +**
+*/ +typedef struct sqlite3_stmt sqlite3_stmt; + +/* +** CAPI3REF: Run-time Limits +** METHOD: sqlite3 +** +** ^(This interface allows the size of various constructs to be limited +** on a connection by connection basis. The first parameter is the +** [database connection] whose limit is to be set or queried. The +** second parameter is one of the [limit categories] that define a +** class of constructs to be size limited. The third parameter is the +** new limit for that construct.)^ +** +** ^If the new limit is a negative number, the limit is unchanged. +** ^(For each limit category SQLITE_LIMIT_NAME there is a +** [limits | hard upper bound] +** set at compile-time by a C preprocessor macro called +** [limits | SQLITE_MAX_NAME]. +** (The "_LIMIT_" in the name is changed to "_MAX_".))^ +** ^Attempts to increase a limit above its hard upper bound are +** silently truncated to the hard upper bound. +** +** ^Regardless of whether or not the limit was changed, the +** [sqlite3_limit()] interface returns the prior value of the limit. +** ^Hence, to find the current value of a limit without changing it, +** simply invoke this interface with the third parameter set to -1. +** +** Run-time limits are intended for use in applications that manage +** both their own internal database and also databases that are controlled +** by untrusted external sources. An example application might be a +** web browser that has its own databases for storing history and +** separate databases controlled by JavaScript applications downloaded +** off the Internet. The internal databases can be given the +** large, default limits. Databases managed by external sources can +** be given much smaller limits designed to prevent a denial of service +** attack. Developers might also want to use the [sqlite3_set_authorizer()] +** interface to further control untrusted SQL. The size of the database +** created by an untrusted script can be contained using the +** [max_page_count] [PRAGMA]. +** +** New run-time limit categories may be added in future releases. +*/ +SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); + +/* +** CAPI3REF: Run-Time Limit Categories +** KEYWORDS: {limit category} {*limit categories} +** +** These constants define various performance limits +** that can be lowered at run-time using [sqlite3_limit()]. +** The synopsis of the meanings of the various limits is shown below. +** Additional information is available at [limits | Limits in SQLite]. +** +**
+** [[SQLITE_LIMIT_LENGTH]] ^(
SQLITE_LIMIT_LENGTH
+**
The maximum size of any string or BLOB or table row, in bytes.
)^ +** +** [[SQLITE_LIMIT_SQL_LENGTH]] ^(
SQLITE_LIMIT_SQL_LENGTH
+**
The maximum length of an SQL statement, in bytes.
)^ +** +** [[SQLITE_LIMIT_COLUMN]] ^(
SQLITE_LIMIT_COLUMN
+**
The maximum number of columns in a table definition or in the +** result set of a [SELECT] or the maximum number of columns in an index +** or in an ORDER BY or GROUP BY clause.
)^ +** +** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
+**
The maximum depth of the parse tree on any expression.
)^ +** +** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
SQLITE_LIMIT_COMPOUND_SELECT
+**
The maximum number of terms in a compound SELECT statement.
)^ +** +** [[SQLITE_LIMIT_VDBE_OP]] ^(
SQLITE_LIMIT_VDBE_OP
+**
The maximum number of instructions in a virtual machine program +** used to implement an SQL statement. If [sqlite3_prepare_v2()] or +** the equivalent tries to allocate space for more than this many opcodes +** in a single prepared statement, an SQLITE_NOMEM error is returned.
)^ +** +** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
SQLITE_LIMIT_FUNCTION_ARG
+**
The maximum number of arguments on a function.
)^ +** +** [[SQLITE_LIMIT_ATTACHED]] ^(
SQLITE_LIMIT_ATTACHED
+**
The maximum number of [ATTACH | attached databases].)^
+** +** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] +** ^(
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
+**
The maximum length of the pattern argument to the [LIKE] or +** [GLOB] operators.
)^ +** +** [[SQLITE_LIMIT_VARIABLE_NUMBER]] +** ^(
SQLITE_LIMIT_VARIABLE_NUMBER
+**
The maximum index number of any [parameter] in an SQL statement.)^ +** +** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
+**
The maximum depth of recursion for triggers.
)^ +** +** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
SQLITE_LIMIT_WORKER_THREADS
+**
The maximum number of auxiliary worker threads that a single +** [prepared statement] may start.
)^ +**
+*/ +#define SQLITE_LIMIT_LENGTH 0 +#define SQLITE_LIMIT_SQL_LENGTH 1 +#define SQLITE_LIMIT_COLUMN 2 +#define SQLITE_LIMIT_EXPR_DEPTH 3 +#define SQLITE_LIMIT_COMPOUND_SELECT 4 +#define SQLITE_LIMIT_VDBE_OP 5 +#define SQLITE_LIMIT_FUNCTION_ARG 6 +#define SQLITE_LIMIT_ATTACHED 7 +#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 +#define SQLITE_LIMIT_VARIABLE_NUMBER 9 +#define SQLITE_LIMIT_TRIGGER_DEPTH 10 +#define SQLITE_LIMIT_WORKER_THREADS 11 + + +/* +** CAPI3REF: Compiling An SQL Statement +** KEYWORDS: {SQL statement compiler} +** METHOD: sqlite3 +** CONSTRUCTOR: sqlite3_stmt +** +** To execute an SQL query, it must first be compiled into a byte-code +** program using one of these routines. +** +** The first argument, "db", is a [database connection] obtained from a +** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or +** [sqlite3_open16()]. The database connection must not have been closed. +** +** The second argument, "zSql", is the statement to be compiled, encoded +** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() +** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() +** use UTF-16. +** +** ^If the nByte argument is negative, then zSql is read up to the +** first zero terminator. ^If nByte is positive, then it is the +** number of bytes read from zSql. ^If nByte is zero, then no prepared +** statement is generated. +** If the caller knows that the supplied string is nul-terminated, then +** there is a small performance advantage to passing an nByte parameter that +** is the number of bytes in the input string including +** the nul-terminator. +** +** ^If pzTail is not NULL then *pzTail is made to point to the first byte +** past the end of the first SQL statement in zSql. These routines only +** compile the first statement in zSql, so *pzTail is left pointing to +** what remains uncompiled. +** +** ^*ppStmt is left pointing to a compiled [prepared statement] that can be +** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set +** to NULL. ^If the input text contains no SQL (if the input is an empty +** string or a comment) then *ppStmt is set to NULL. +** The calling procedure is responsible for deleting the compiled +** SQL statement using [sqlite3_finalize()] after it has finished with it. +** ppStmt may not be NULL. +** +** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; +** otherwise an [error code] is returned. +** +** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are +** recommended for all new programs. The two older interfaces are retained +** for backwards compatibility, but their use is discouraged. +** ^In the "v2" interfaces, the prepared statement +** that is returned (the [sqlite3_stmt] object) contains a copy of the +** original SQL text. This causes the [sqlite3_step()] interface to +** behave differently in three ways: +** +**
    +**
  1. +** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it +** always used to do, [sqlite3_step()] will automatically recompile the SQL +** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY] +** retries will occur before sqlite3_step() gives up and returns an error. +**
  2. +** +**
  3. +** ^When an error occurs, [sqlite3_step()] will return one of the detailed +** [error codes] or [extended error codes]. ^The legacy behavior was that +** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code +** and the application would have to make a second call to [sqlite3_reset()] +** in order to find the underlying cause of the problem. With the "v2" prepare +** interfaces, the underlying reason for the error is returned immediately. +**
  4. +** +**
  5. +** ^If the specific value bound to [parameter | host parameter] in the +** WHERE clause might influence the choice of query plan for a statement, +** then the statement will be automatically recompiled, as if there had been +** a schema change, on the first [sqlite3_step()] call following any change +** to the [sqlite3_bind_text | bindings] of that [parameter]. +** ^The specific value of WHERE-clause [parameter] might influence the +** choice of query plan if the parameter is the left-hand side of a [LIKE] +** or [GLOB] operator or if the parameter is compared to an indexed column +** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. +**
  6. +**
+*/ +SQLITE_API int sqlite3_prepare( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare_v2( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16_v2( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); + +/* +** CAPI3REF: Retrieving Statement SQL +** METHOD: sqlite3_stmt +** +** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 +** SQL text used to create [prepared statement] P if P was +** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 +** string containing the SQL text of prepared statement P with +** [bound parameters] expanded. +** +** ^(For example, if a prepared statement is created using the SQL +** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 +** and parameter :xyz is unbound, then sqlite3_sql() will return +** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() +** will return "SELECT 2345,NULL".)^ +** +** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory +** is available to hold the result, or if the result would exceed the +** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** +** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of +** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time +** option causes sqlite3_expanded_sql() to always return NULL. +** +** ^The string returned by sqlite3_sql(P) is managed by SQLite and is +** automatically freed when the prepared statement is finalized. +** ^The string returned by sqlite3_expanded_sql(P), on the other hand, +** is obtained from [sqlite3_malloc()] and must be free by the application +** by passing it to [sqlite3_free()]. +*/ +SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Determine If An SQL Statement Writes The Database +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if +** and only if the [prepared statement] X makes no direct changes to +** the content of the database file. +** +** Note that [application-defined SQL functions] or +** [virtual tables] might change the database indirectly as a side effect. +** ^(For example, if an application defines a function "eval()" that +** calls [sqlite3_exec()], then the following SQL statement would +** change the database file through side-effects: +** +**
+**    SELECT eval('DELETE FROM t1') FROM t2;
+** 
+** +** But because the [SELECT] statement does not change the database file +** directly, sqlite3_stmt_readonly() would still return true.)^ +** +** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], +** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, +** since the statements themselves do not actually modify the database but +** rather they control the timing of when other statements modify the +** database. ^The [ATTACH] and [DETACH] statements also cause +** sqlite3_stmt_readonly() to return true since, while those statements +** change the configuration of a database connection, they do not make +** changes to the content of the database files on disk. +** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since +** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and +** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so +** sqlite3_stmt_readonly() returns false for those commands. +*/ +SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Determine If A Prepared Statement Has Been Reset +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the +** [prepared statement] S has been stepped at least once using +** [sqlite3_step(S)] but has neither run to completion (returned +** [SQLITE_DONE] from [sqlite3_step(S)]) nor +** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) +** interface returns false if S is a NULL pointer. If S is not a +** NULL pointer and is not a pointer to a valid [prepared statement] +** object, then the behavior is undefined and probably undesirable. +** +** This interface can be used in combination [sqlite3_next_stmt()] +** to locate all prepared statements associated with a database +** connection that are in need of being reset. This can be used, +** for example, in diagnostic routines to search for prepared +** statements that are holding a transaction open. +*/ +SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); + +/* +** CAPI3REF: Dynamically Typed Value Object +** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value} +** +** SQLite uses the sqlite3_value object to represent all values +** that can be stored in a database table. SQLite uses dynamic typing +** for the values it stores. ^Values stored in sqlite3_value objects +** can be integers, floating point values, strings, BLOBs, or NULL. +** +** An sqlite3_value object may be either "protected" or "unprotected". +** Some interfaces require a protected sqlite3_value. Other interfaces +** will accept either a protected or an unprotected sqlite3_value. +** Every interface that accepts sqlite3_value arguments specifies +** whether or not it requires a protected sqlite3_value. The +** [sqlite3_value_dup()] interface can be used to construct a new +** protected sqlite3_value from an unprotected sqlite3_value. +** +** The terms "protected" and "unprotected" refer to whether or not +** a mutex is held. An internal mutex is held for a protected +** sqlite3_value object but no mutex is held for an unprotected +** sqlite3_value object. If SQLite is compiled to be single-threaded +** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) +** or if SQLite is run in one of reduced mutex modes +** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] +** then there is no distinction between protected and unprotected +** sqlite3_value objects and they can be used interchangeably. However, +** for maximum code portability it is recommended that applications +** still make the distinction between protected and unprotected +** sqlite3_value objects even when not strictly required. +** +** ^The sqlite3_value objects that are passed as parameters into the +** 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()]. +** The [sqlite3_value_blob | sqlite3_value_type()] family of +** interfaces require protected sqlite3_value objects. +*/ +typedef struct sqlite3_value sqlite3_value; + +/* +** CAPI3REF: SQL Function Context Object +** +** The context in which an SQL function executes is stored in an +** sqlite3_context object. ^A pointer to an sqlite3_context object +** is always first parameter to [application-defined SQL functions]. +** The application-defined SQL function implementation will pass this +** pointer through into calls to [sqlite3_result_int | sqlite3_result()], +** [sqlite3_aggregate_context()], [sqlite3_user_data()], +** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], +** and/or [sqlite3_set_auxdata()]. +*/ +typedef struct sqlite3_context sqlite3_context; + +/* +** CAPI3REF: Binding Values To Prepared Statements +** KEYWORDS: {host parameter} {host parameters} {host parameter name} +** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} +** METHOD: sqlite3_stmt +** +** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, +** literals may be replaced by a [parameter] that matches one of following +** templates: +** +**
    +**
  • ? +**
  • ?NNN +**
  • :VVV +**
  • @VVV +**
  • $VVV +**
+** +** In the templates above, NNN represents an integer literal, +** and VVV represents an alphanumeric identifier.)^ ^The values of these +** parameters (also called "host parameter names" or "SQL parameters") +** can be set using the sqlite3_bind_*() routines defined here. +** +** ^The first argument to the sqlite3_bind_*() routines is always +** a pointer to the [sqlite3_stmt] object returned from +** [sqlite3_prepare_v2()] or its variants. +** +** ^The second argument is the index of the SQL parameter to be set. +** ^The leftmost SQL parameter has an index of 1. ^When the same named +** SQL parameter is used more than once, second and subsequent +** occurrences have the same index as the first occurrence. +** ^The index for named parameters can be looked up using the +** [sqlite3_bind_parameter_index()] API if desired. ^The index +** for "?NNN" parameters is the value of NNN. +** ^The NNN value must be between 1 and the [sqlite3_limit()] +** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). +** +** ^The third argument is the value to bind to the parameter. +** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() +** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter +** is ignored and the end result is the same as sqlite3_bind_null(). +** +** ^(In those routines that have a fourth argument, its value is the +** number of bytes in the parameter. To be clear: the value is the +** number of bytes in the value, not the number of characters.)^ +** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() +** is negative, then the length of the string is +** the number of bytes up to the first zero terminator. +** If the fourth parameter to sqlite3_bind_blob() is negative, then +** the behavior is undefined. +** If a non-negative fourth parameter is provided to sqlite3_bind_text() +** or sqlite3_bind_text16() or sqlite3_bind_text64() then +** that parameter must be the byte offset +** where the NUL terminator would occur assuming the string were NUL +** terminated. If any NUL characters occur at byte offsets less than +** the value of the fourth parameter then the resulting string value will +** contain embedded NULs. The result of expressions involving strings +** with embedded NULs is undefined. +** +** ^The fifth argument to the BLOB and string binding interfaces +** is a destructor used to dispose of the BLOB or +** string after SQLite has finished with it. ^The destructor is called +** to dispose of the BLOB or string even if the call to bind API fails. +** ^If the fifth argument is +** the special value [SQLITE_STATIC], then SQLite assumes that the +** information is in static, unmanaged space and does not need to be freed. +** ^If the fifth argument has the value [SQLITE_TRANSIENT], then +** SQLite makes its own private copy of the data immediately, before +** the sqlite3_bind_*() routine returns. +** +** ^The sixth argument to sqlite3_bind_text64() must be one of +** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] +** to specify the encoding of the text in the third parameter. If +** the sixth argument to sqlite3_bind_text64() is not one of the +** allowed values shown above, or if the text encoding is different +** from the encoding specified by the sixth parameter, then the behavior +** is undefined. +** +** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that +** is filled with zeroes. ^A zeroblob uses a fixed amount of memory +** (just an integer to hold its size) while it is being processed. +** Zeroblobs are intended to serve as placeholders for BLOBs whose +** content is later written using +** [sqlite3_blob_open | incremental BLOB I/O] routines. +** ^A negative value for the zeroblob results in a zero-length BLOB. +** +** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer +** for the [prepared statement] or with a prepared statement for which +** [sqlite3_step()] has been called more recently than [sqlite3_reset()], +** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_() +** routine is passed a [prepared statement] that has been finalized, the +** result is undefined and probably harmful. +** +** ^Bindings are not cleared by the [sqlite3_reset()] routine. +** ^Unbound parameters are interpreted as NULL. +** +** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an +** [error code] if anything goes wrong. +** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB +** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or +** [SQLITE_MAX_LENGTH]. +** ^[SQLITE_RANGE] is returned if the parameter +** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. +** +** See also: [sqlite3_bind_parameter_count()], +** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, + void(*)(void*)); +SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); +SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); +SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); +SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); +SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); +SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, + void(*)(void*), unsigned char encoding); +SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); +SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); + +/* +** CAPI3REF: Number Of SQL Parameters +** METHOD: sqlite3_stmt +** +** ^This routine can be used to find the number of [SQL parameters] +** in a [prepared statement]. SQL parameters are tokens of the +** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as +** placeholders for values that are [sqlite3_bind_blob | bound] +** to the parameters at a later time. +** +** ^(This routine actually returns the index of the largest (rightmost) +** parameter. For all forms except ?NNN, this will correspond to the +** number of unique parameters. If parameters of the ?NNN form are used, +** there may be gaps in the list.)^ +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_name()], and +** [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); + +/* +** CAPI3REF: Name Of A Host Parameter +** METHOD: sqlite3_stmt +** +** ^The sqlite3_bind_parameter_name(P,N) interface returns +** the name of the N-th [SQL parameter] in the [prepared statement] P. +** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" +** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" +** respectively. +** In other words, the initial ":" or "$" or "@" or "?" +** is included as part of the name.)^ +** ^Parameters of the form "?" without a following integer have no name +** and are referred to as "nameless" or "anonymous parameters". +** +** ^The first host parameter has an index of 1, not 0. +** +** ^If the value N is out of range or if the N-th parameter is +** nameless, then NULL is returned. ^The returned string is +** always in UTF-8 encoding even if the named parameter was +** originally specified as UTF-16 in [sqlite3_prepare16()] or +** [sqlite3_prepare16_v2()]. +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_count()], and +** [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); + +/* +** CAPI3REF: Index Of A Parameter With A Given Name +** METHOD: sqlite3_stmt +** +** ^Return the index of an SQL parameter given its name. ^The +** index value returned is suitable for use as the second +** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero +** is returned if no matching parameter is found. ^The parameter +** name must be given in UTF-8 even if the original statement +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_count()], and +** [sqlite3_bind_parameter_name()]. +*/ +SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); + +/* +** CAPI3REF: Reset All Bindings On A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset +** the [sqlite3_bind_blob | bindings] on a [prepared statement]. +** ^Use this routine to reset all host parameters to NULL. +*/ +SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); + +/* +** CAPI3REF: Number Of Columns In A Result Set +** METHOD: sqlite3_stmt +** +** ^Return the number of columns in the result set returned by the +** [prepared statement]. ^If this routine returns 0, that means the +** [prepared statement] returns no data (for example an [UPDATE]). +** ^However, just because this routine returns a positive number does not +** mean that one or more rows of data will be returned. ^A SELECT statement +** will always have a positive sqlite3_column_count() but depending on the +** WHERE clause constraints and the table content, it might return no rows. +** +** See also: [sqlite3_data_count()] +*/ +SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Column Names In A Result Set +** METHOD: sqlite3_stmt +** +** ^These routines return the name assigned to a particular column +** in the result set of a [SELECT] statement. ^The sqlite3_column_name() +** interface returns a pointer to a zero-terminated UTF-8 string +** and sqlite3_column_name16() returns a pointer to a zero-terminated +** UTF-16 string. ^The first parameter is the [prepared statement] +** that implements the [SELECT] statement. ^The second parameter is the +** column number. ^The leftmost column is number 0. +** +** ^The returned string pointer is valid until either the [prepared statement] +** is destroyed by [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the next call to +** sqlite3_column_name() or sqlite3_column_name16() on the same column. +** +** ^If sqlite3_malloc() fails during the processing of either routine +** (for example during a conversion from UTF-8 to UTF-16) then a +** NULL pointer is returned. +** +** ^The name of a result column is the value of the "AS" clause for +** that column, if there is an AS clause. If there is no AS clause +** then the name of the column is unspecified and may change from +** one release of SQLite to the next. +*/ +SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); +SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); + +/* +** CAPI3REF: Source Of Data In A Query Result +** METHOD: sqlite3_stmt +** +** ^These routines provide a means to determine the database, table, and +** table column that is the origin of a particular result column in +** [SELECT] statement. +** ^The name of the database or table or column can be returned as +** either a UTF-8 or UTF-16 string. ^The _database_ routines return +** the database name, the _table_ routines return the table name, and +** the origin_ routines return the column name. +** ^The returned string is valid until the [prepared statement] is destroyed +** using [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the same information is requested +** again in a different encoding. +** +** ^The names returned are the original un-aliased names of the +** database, table, and column. +** +** ^The first argument to these interfaces is a [prepared statement]. +** ^These functions return information about the Nth result column returned by +** the statement, where N is the second function argument. +** ^The left-most column is column 0 for these routines. +** +** ^If the Nth column returned by the statement is an expression or +** subquery and is not a column value, then all of these functions return +** NULL. ^These routine might also return NULL if a memory allocation error +** occurs. ^Otherwise, they return the name of the attached database, table, +** or column that query result column was extracted from. +** +** ^As with all other SQLite APIs, those whose names end with "16" return +** UTF-16 encoded strings and the other functions return UTF-8. +** +** ^These APIs are only available if the library was compiled with the +** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. +** +** If two or more threads call one or more of these routines against the same +** prepared statement and column at the same time then the results are +** undefined. +** +** If two or more threads call one or more +** [sqlite3_column_database_name | column metadata interfaces] +** for the same [prepared statement] and result column +** at the same time then the results are undefined. +*/ +SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); + +/* +** CAPI3REF: Declared Datatype Of A Query Result +** METHOD: sqlite3_stmt +** +** ^(The first parameter is a [prepared statement]. +** If this statement is a [SELECT] statement and the Nth column of the +** returned result set of that [SELECT] is a table column (not an +** expression or subquery) then the declared type of the table +** column is returned.)^ ^If the Nth column of the result set is an +** expression or subquery, then a NULL pointer is returned. +** ^The returned string is always UTF-8 encoded. +** +** ^(For example, given the database schema: +** +** CREATE TABLE t1(c1 VARIANT); +** +** and the following statement to be compiled: +** +** SELECT c1 + 1, c1 FROM t1; +** +** this routine would return the string "VARIANT" for the second result +** column (i==1), and a NULL pointer for the first result column (i==0).)^ +** +** ^SQLite uses dynamic run-time typing. ^So just because a column +** is declared to contain a particular type does not mean that the +** data stored in that column is of the declared type. SQLite is +** strongly typed, but the typing is dynamic not static. ^Type +** is associated with individual values, not with the containers +** used to hold those values. +*/ +SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); + +/* +** CAPI3REF: Evaluate An SQL Statement +** METHOD: sqlite3_stmt +** +** After a [prepared statement] has been prepared using either +** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function +** must be called one or more times to evaluate the statement. +** +** The details of the behavior of the sqlite3_step() interface depend +** on whether the statement was prepared using the newer "v2" interface +** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy +** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "v2" interface is recommended for new applications but the legacy +** interface will continue to be supported. +** +** ^In the legacy interface, the return value will be either [SQLITE_BUSY], +** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. +** ^With the "v2" interface, any of the other [result codes] or +** [extended result codes] might be returned as well. +** +** ^[SQLITE_BUSY] means that the database engine was unable to acquire the +** database locks it needs to do its job. ^If the statement is a [COMMIT] +** or occurs outside of an explicit transaction, then you can retry the +** statement. If the statement is not a [COMMIT] and occurs within an +** explicit transaction then you should rollback the transaction before +** continuing. +** +** ^[SQLITE_DONE] means that the statement has finished executing +** successfully. sqlite3_step() should not be called again on this virtual +** machine without first calling [sqlite3_reset()] to reset the virtual +** machine back to its initial state. +** +** ^If the SQL statement being executed returns any data, then [SQLITE_ROW] +** is returned each time a new row of data is ready for processing by the +** caller. The values may be accessed using the [column access functions]. +** sqlite3_step() is called again to retrieve the next row of data. +** +** ^[SQLITE_ERROR] means that a run-time error (such as a constraint +** violation) has occurred. sqlite3_step() should not be called again on +** the VM. More information may be found by calling [sqlite3_errmsg()]. +** ^With the legacy interface, a more specific error code (for example, +** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) +** can be obtained by calling [sqlite3_reset()] on the +** [prepared statement]. ^In the "v2" interface, +** the more specific error code is returned directly by sqlite3_step(). +** +** [SQLITE_MISUSE] means that the this routine was called inappropriately. +** Perhaps it was called on a [prepared statement] that has +** already been [sqlite3_finalize | finalized] or on one that had +** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could +** be the case that the same database connection is being used by two or +** more threads at the same moment in time. +** +** For all versions of SQLite up to and including 3.6.23.1, a call to +** [sqlite3_reset()] was required after sqlite3_step() returned anything +** other than [SQLITE_ROW] before any subsequent invocation of +** sqlite3_step(). Failure to reset the prepared statement using +** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step() began +** calling [sqlite3_reset()] automatically in this circumstance rather +** than returning [SQLITE_MISUSE]. This is not considered a compatibility +** break because any application that ever receives an SQLITE_MISUSE error +** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option +** can be used to restore the legacy behavior. +** +** Goofy Interface Alert: In the legacy interface, the sqlite3_step() +** API always returns a generic error code, [SQLITE_ERROR], following any +** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call +** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the +** specific [error codes] that better describes the error. +** We admit that this is a goofy design. The problem has been fixed +** with the "v2" interface. If you prepare all of your SQL statements +** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, +** then the more specific [error codes] are returned directly +** by sqlite3_step(). The use of the "v2" interface is recommended. +*/ +SQLITE_API int sqlite3_step(sqlite3_stmt*); + +/* +** CAPI3REF: Number of columns in a result set +** METHOD: sqlite3_stmt +** +** ^The sqlite3_data_count(P) interface returns the number of columns in the +** current row of the result set of [prepared statement] P. +** ^If prepared statement P does not have results ready to return +** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of +** interfaces) then sqlite3_data_count(P) returns 0. +** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. +** ^The sqlite3_data_count(P) routine returns 0 if the previous call to +** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) +** will return non-zero if previous call to [sqlite3_step](P) returned +** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] +** where it always returns zero since each step of that multi-step +** pragma returns 0 columns of data. +** +** See also: [sqlite3_column_count()] +*/ +SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Fundamental Datatypes +** KEYWORDS: SQLITE_TEXT +** +** ^(Every value in SQLite has one of five fundamental datatypes: +** +**
    +**
  • 64-bit signed integer +**
  • 64-bit IEEE floating point number +**
  • string +**
  • BLOB +**
  • NULL +**
)^ +** +** These constants are codes for each of those types. +** +** Note that the SQLITE_TEXT constant was also used in SQLite version 2 +** for a completely different meaning. Software that links against both +** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not +** SQLITE_TEXT. +*/ +#define SQLITE_INTEGER 1 +#define SQLITE_FLOAT 2 +#define SQLITE_BLOB 4 +#define SQLITE_NULL 5 +#ifdef SQLITE_TEXT +# undef SQLITE_TEXT +#else +# define SQLITE_TEXT 3 +#endif +#define SQLITE3_TEXT 3 + +/* +** CAPI3REF: Result Values From A Query +** KEYWORDS: {column access functions} +** METHOD: sqlite3_stmt +** +** ^These routines return information about a single column of the current +** result row of a query. ^In every case the first argument is a pointer +** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] +** that was returned from [sqlite3_prepare_v2()] or one of its variants) +** and the second argument is the index of the column for which information +** should be returned. ^The leftmost column of the result set has the index 0. +** ^The number of columns in the result can be determined using +** [sqlite3_column_count()]. +** +** If the SQL statement does not currently point to a valid row, or if the +** column index is out of range, the result is undefined. +** These routines may only be called when the most recent call to +** [sqlite3_step()] has returned [SQLITE_ROW] and neither +** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. +** If any of these routines are called after [sqlite3_reset()] or +** [sqlite3_finalize()] or after [sqlite3_step()] has returned +** something other than [SQLITE_ROW], the results are undefined. +** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] +** are called from a different thread while any of these routines +** are pending, then the results are undefined. +** +** ^The sqlite3_column_type() routine returns the +** [SQLITE_INTEGER | datatype code] for the initial data type +** of the result column. ^The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value +** returned by sqlite3_column_type() is only meaningful if no type +** conversions have occurred as described below. After a type conversion, +** the value returned by sqlite3_column_type() is undefined. Future +** versions of SQLite may change the behavior of sqlite3_column_type() +** following a type conversion. +** +** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() +** routine returns the number of bytes in that BLOB or string. +** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts +** the string to UTF-8 and then returns the number of bytes. +** ^If the result is a numeric value then sqlite3_column_bytes() uses +** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns +** the number of bytes in that string. +** ^If the result is NULL, then sqlite3_column_bytes() returns zero. +** +** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16() +** routine returns the number of bytes in that BLOB or string. +** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts +** the string to UTF-16 and then returns the number of bytes. +** ^If the result is a numeric value then sqlite3_column_bytes16() uses +** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns +** the number of bytes in that string. +** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. +** +** ^The values returned by [sqlite3_column_bytes()] and +** [sqlite3_column_bytes16()] do not include the zero terminators at the end +** of the string. ^For clarity: the values returned by +** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of +** bytes in the string, not the number of characters. +** +** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), +** even empty strings, are always zero-terminated. ^The return +** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. +** +** Warning: ^The object returned by [sqlite3_column_value()] is an +** [unprotected sqlite3_value] object. In a multithreaded environment, +** an unprotected sqlite3_value object may only be used safely with +** [sqlite3_bind_value()] and [sqlite3_result_value()]. +** If the [unprotected sqlite3_value] object returned by +** [sqlite3_column_value()] is used in any other way, including calls +** to routines like [sqlite3_value_int()], [sqlite3_value_text()], +** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** +** These routines attempt to convert the value where appropriate. ^For +** example, if the internal representation is FLOAT and a text result +** is requested, [sqlite3_snprintf()] is used internally to perform the +** conversion automatically. ^(The following table details the conversions +** that are applied: +** +**
+** +**
Internal
Type
Requested
Type
Conversion +** +**
NULL INTEGER Result is 0 +**
NULL FLOAT Result is 0.0 +**
NULL TEXT Result is a NULL pointer +**
NULL BLOB Result is a NULL pointer +**
INTEGER FLOAT Convert from integer to float +**
INTEGER TEXT ASCII rendering of the integer +**
INTEGER BLOB Same as INTEGER->TEXT +**
FLOAT INTEGER [CAST] to INTEGER +**
FLOAT TEXT ASCII rendering of the float +**
FLOAT BLOB [CAST] to BLOB +**
TEXT INTEGER [CAST] to INTEGER +**
TEXT FLOAT [CAST] to REAL +**
TEXT BLOB No change +**
BLOB INTEGER [CAST] to INTEGER +**
BLOB FLOAT [CAST] to REAL +**
BLOB TEXT Add a zero terminator if needed +**
+**
)^ +** +** Note that when type conversions occur, pointers returned by prior +** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or +** sqlite3_column_text16() may be invalidated. +** Type conversions and pointer invalidations might occur +** in the following cases: +** +**
    +**
  • The initial content is a BLOB and sqlite3_column_text() or +** sqlite3_column_text16() is called. A zero-terminator might +** need to be added to the string.
  • +**
  • The initial content is UTF-8 text and sqlite3_column_bytes16() or +** sqlite3_column_text16() is called. The content must be converted +** to UTF-16.
  • +**
  • The initial content is UTF-16 text and sqlite3_column_bytes() or +** sqlite3_column_text() is called. The content must be converted +** to UTF-8.
  • +**
+** +** ^Conversions between UTF-16be and UTF-16le are always done in place and do +** not invalidate a prior pointer, though of course the content of the buffer +** that the prior pointer references will have been modified. Other kinds +** of conversion are done in place when it is possible, but sometimes they +** are not possible and in those cases prior pointers are invalidated. +** +** The safest policy is to invoke these routines +** in one of the following ways: +** +**
    +**
  • sqlite3_column_text() followed by sqlite3_column_bytes()
  • +**
  • sqlite3_column_blob() followed by sqlite3_column_bytes()
  • +**
  • sqlite3_column_text16() followed by sqlite3_column_bytes16()
  • +**
+** +** In other words, you should call sqlite3_column_text(), +** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result +** into the desired format, then invoke sqlite3_column_bytes() or +** sqlite3_column_bytes16() to find the size of the result. Do not mix calls +** to sqlite3_column_text() or sqlite3_column_blob() with calls to +** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() +** with calls to sqlite3_column_bytes(). +** +** ^The pointers returned are valid until a type conversion occurs as +** described above, or until [sqlite3_step()] or [sqlite3_reset()] or +** [sqlite3_finalize()] is called. ^The memory space used to hold strings +** and BLOBs is freed automatically. Do not pass the pointers returned +** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into +** [sqlite3_free()]. +** +** ^(If a memory allocation error occurs during the evaluation of any +** of these routines, a default value is returned. The default value +** is either the integer 0, the floating point number 0.0, or a NULL +** pointer. Subsequent calls to [sqlite3_errcode()] will return +** [SQLITE_NOMEM].)^ +*/ +SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); +SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); +SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); + +/* +** CAPI3REF: Destroy A Prepared Statement Object +** DESTRUCTOR: sqlite3_stmt +** +** ^The sqlite3_finalize() function is called to delete a [prepared statement]. +** ^If the most recent evaluation of the statement encountered no errors +** or if the statement is never been evaluated, then sqlite3_finalize() returns +** SQLITE_OK. ^If the most recent evaluation of statement S failed, then +** sqlite3_finalize(S) returns the appropriate [error code] or +** [extended error code]. +** +** ^The sqlite3_finalize(S) routine can be called at any point during +** the life cycle of [prepared statement] S: +** before statement S is ever evaluated, after +** one or more calls to [sqlite3_reset()], or after any call +** to [sqlite3_step()] regardless of whether or not the statement has +** completed execution. +** +** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. +** +** The application must finalize every [prepared statement] in order to avoid +** resource leaks. It is a grievous error for the application to try to use +** a prepared statement after it has been finalized. Any use of a prepared +** statement after it has been finalized can result in undefined and +** undesirable behavior such as segfaults and heap corruption. +*/ +SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Reset A Prepared Statement Object +** METHOD: sqlite3_stmt +** +** The sqlite3_reset() function is called to reset a [prepared statement] +** object back to its initial state, ready to be re-executed. +** ^Any SQL statement variables that had values bound to them using +** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. +** Use [sqlite3_clear_bindings()] to reset the bindings. +** +** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S +** back to the beginning of its program. +** +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], +** or if [sqlite3_step(S)] has never before been called on S, +** then [sqlite3_reset(S)] returns [SQLITE_OK]. +** +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S indicated an error, then +** [sqlite3_reset(S)] returns an appropriate [error code]. +** +** ^The [sqlite3_reset(S)] interface does not change the values +** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. +*/ +SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Create Or Redefine SQL Functions +** KEYWORDS: {function creation routines} +** KEYWORDS: {application-defined SQL function} +** KEYWORDS: {application-defined SQL functions} +** METHOD: sqlite3 +** +** ^These functions (collectively known as "function creation routines") +** are used to add SQL functions or aggregates or to redefine the behavior +** of existing SQL functions or aggregates. The only differences between +** these routines are the text encoding expected for +** the second parameter (the name of the function being created) +** and the presence or absence of a destructor callback for +** the application data pointer. +** +** ^The first parameter is the [database connection] to which the SQL +** function is to be added. ^If an application uses more than one database +** connection then application-defined SQL functions must be added +** to each database connection separately. +** +** ^The second parameter is the name of the SQL function to be created or +** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 +** representation, exclusive of the zero-terminator. ^Note that the name +** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. +** ^Any attempt to create a function with a longer name +** will result in [SQLITE_MISUSE] being returned. +** +** ^The third parameter (nArg) +** is the number of arguments that the SQL function or +** aggregate takes. ^If this parameter is -1, then the SQL function or +** aggregate may take any number of arguments between 0 and the limit +** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third +** parameter is less than -1 or greater than 127 then the behavior is +** undefined. +** +** ^The fourth parameter, eTextRep, specifies what +** [SQLITE_UTF8 | text encoding] this SQL function prefers for +** its parameters. The application should set this parameter to +** [SQLITE_UTF16LE] if the function implementation invokes +** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the +** implementation invokes [sqlite3_value_text16be()] on an input, or +** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] +** otherwise. ^The same SQL function may be registered multiple times using +** different preferred text encodings, with different implementations for +** each encoding. +** ^When multiple implementations of the same function are available, SQLite +** will pick the one that involves the least amount of data conversion. +** +** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] +** to signal that the function will always return the same result given +** the same inputs within a single SQL statement. Most SQL functions are +** deterministic. The built-in [random()] SQL function is an example of a +** function that is not deterministic. The SQLite query planner is able to +** perform additional optimizations on deterministic functions, so use +** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. +** +** ^(The fifth parameter is an arbitrary pointer. The implementation of the +** function can gain access to this pointer using [sqlite3_user_data()].)^ +** +** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are +** pointers to C-language functions that implement the SQL function or +** aggregate. ^A scalar SQL function requires an implementation of the xFunc +** callback only; NULL pointers must be passed as the xStep and xFinal +** parameters. ^An aggregate SQL function requires an implementation of xStep +** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing +** SQL function or aggregate, pass NULL pointers for all three function +** callbacks. +** +** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, +** then it is destructor for the application data pointer. +** The destructor is invoked when the function is deleted, either by being +** overloaded or when the database connection closes.)^ +** ^The destructor is also invoked if the call to +** sqlite3_create_function_v2() fails. +** ^When the destructor callback of the tenth parameter is invoked, it +** is passed a single argument which is a copy of the application data +** pointer which was the fifth parameter to sqlite3_create_function_v2(). +** +** ^It is permitted to register multiple implementations of the same +** functions with the same name but with either differing numbers of +** arguments or differing preferred text encodings. ^SQLite will use +** the implementation that most closely matches the way in which the +** SQL function is used. ^A function implementation with a non-negative +** nArg parameter is a better match than a function implementation with +** a negative nArg. ^A function where the preferred text encoding +** matches the database encoding is a better +** match than a function where the encoding is different. +** ^A function where the encoding difference is between UTF16le and UTF16be +** is a closer match than a function where the encoding difference is +** between UTF8 and UTF16. +** +** ^Built-in functions may be overloaded by new application-defined functions. +** +** ^An application-defined function is permitted to call other +** SQLite interfaces. However, such calls must not +** close the database connection nor finalize or reset the prepared +** statement in which the function is running. +*/ +SQLITE_API int sqlite3_create_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); +SQLITE_API int sqlite3_create_function16( + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); +SQLITE_API int sqlite3_create_function_v2( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*) +); + +/* +** CAPI3REF: Text Encodings +** +** These constant define integer codes that represent the various +** text encodings supported by SQLite. +*/ +#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ +#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ +#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */ +#define SQLITE_UTF16 4 /* Use native byte order */ +#define SQLITE_ANY 5 /* Deprecated */ +#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ + +/* +** CAPI3REF: Function Flags +** +** These constants may be ORed together with the +** [SQLITE_UTF8 | preferred text encoding] as the fourth argument +** to [sqlite3_create_function()], [sqlite3_create_function16()], or +** [sqlite3_create_function_v2()]. +*/ +#define SQLITE_DETERMINISTIC 0x800 + +/* +** CAPI3REF: Deprecated Functions +** DEPRECATED +** +** These functions are [deprecated]. In order to maintain +** backwards compatibility with older code, these functions continue +** to be supported. However, new applications should avoid +** the use of these functions. To encourage programmers to avoid +** these functions, we will not explain what they do. +*/ +#ifndef SQLITE_OMIT_DEPRECATED +SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); +SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); +SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), + void*,sqlite3_int64); +#endif + +/* +** CAPI3REF: Obtaining SQL Values +** METHOD: sqlite3_value +** +** The C-language implementation of SQL functions and aggregates uses +** this set of interface routines to access the parameter values on +** the function or aggregate. +** +** The xFunc (for scalar functions) or xStep (for aggregates) parameters +** to [sqlite3_create_function()] and [sqlite3_create_function16()] +** define callbacks that implement the SQL functions and aggregates. +** The 3rd parameter to these callbacks is an array of pointers to +** [protected sqlite3_value] objects. There is one [sqlite3_value] object for +** each parameter to the SQL function. These routines are used to +** extract values from the [sqlite3_value] objects. +** +** These routines work only with [protected sqlite3_value] objects. +** Any attempt to use these routines on an [unprotected sqlite3_value] +** object results in undefined behavior. +** +** ^These routines work just like the corresponding [column access functions] +** except that these routines take a single [protected sqlite3_value] object +** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. +** +** ^The sqlite3_value_text16() interface extracts a UTF-16 string +** in the native byte-order of the host machine. ^The +** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces +** extract UTF-16 strings as big-endian and little-endian respectively. +** +** ^(The sqlite3_value_numeric_type() interface attempts to apply +** numeric affinity to the value. This means that an attempt is +** made to convert the value to an integer or floating point. If +** such a conversion is possible without loss of information (in other +** words, if the value is a string that looks like a number) +** then the conversion is performed. Otherwise no conversion occurs. +** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ +** +** Please pay particular attention to the fact that the pointer returned +** from [sqlite3_value_blob()], [sqlite3_value_text()], or +** [sqlite3_value_text16()] can be invalidated by a subsequent call to +** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], +** or [sqlite3_value_text16()]. +** +** These routines must be called from the same thread as +** the SQL function that supplied the [sqlite3_value*] parameters. +*/ +SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); +SQLITE_API double sqlite3_value_double(sqlite3_value*); +SQLITE_API int sqlite3_value_int(sqlite3_value*); +SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_type(sqlite3_value*); +SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); + +/* +** CAPI3REF: Finding The Subtype Of SQL Values +** METHOD: sqlite3_value +** +** The sqlite3_value_subtype(V) function returns the subtype for +** an [application-defined SQL function] argument V. The subtype +** information can be used to pass a limited amount of context from +** one SQL function to another. Use the [sqlite3_result_subtype()] +** routine to set the subtype for the return value of an SQL function. +** +** SQLite makes no use of subtype itself. It merely passes the subtype +** from the result of one [application-defined SQL function] into the +** input of another. +*/ +SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); + +/* +** CAPI3REF: Copy And Free SQL Values +** METHOD: sqlite3_value +** +** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] +** object D and returns a pointer to that copy. ^The [sqlite3_value] returned +** is a [protected sqlite3_value] object even if the input is not. +** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a +** memory allocation fails. +** +** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object +** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer +** then sqlite3_value_free(V) is a harmless no-op. +*/ +SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*); +SQLITE_API void sqlite3_value_free(sqlite3_value*); + +/* +** CAPI3REF: Obtain Aggregate Function Context +** METHOD: sqlite3_context +** +** Implementations of aggregate SQL functions use this +** routine to allocate memory for storing their state. +** +** ^The first time the sqlite3_aggregate_context(C,N) routine is called +** for a particular aggregate function, SQLite +** allocates N of memory, zeroes out that memory, and returns a pointer +** to the new memory. ^On second and subsequent calls to +** sqlite3_aggregate_context() for the same aggregate function instance, +** the same buffer is returned. Sqlite3_aggregate_context() is normally +** called once for each invocation of the xStep callback and then one +** last time when the xFinal callback is invoked. ^(When no rows match +** an aggregate query, the xStep() callback of the aggregate function +** implementation is never called and xFinal() is called exactly once. +** In those cases, sqlite3_aggregate_context() might be called for the +** first time from within xFinal().)^ +** +** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer +** when first called if N is less than or equal to zero or if a memory +** allocate error occurs. +** +** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is +** determined by the N parameter on first successful call. Changing the +** value of N in subsequent call to sqlite3_aggregate_context() within +** the same aggregate function instance will not resize the memory +** allocation.)^ Within the xFinal callback, it is customary to set +** N=0 in calls to sqlite3_aggregate_context(C,N) so that no +** pointless memory allocations occur. +** +** ^SQLite automatically frees the memory allocated by +** sqlite3_aggregate_context() when the aggregate query concludes. +** +** The first parameter must be a copy of the +** [sqlite3_context | SQL function context] that is the first parameter +** to the xStep or xFinal callback routine that implements the aggregate +** function. +** +** This routine must be called from the same thread in which +** the aggregate SQL function is running. +*/ +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); + +/* +** CAPI3REF: User Data For Functions +** METHOD: sqlite3_context +** +** ^The sqlite3_user_data() interface returns a copy of +** the pointer that was the pUserData parameter (the 5th parameter) +** of the [sqlite3_create_function()] +** and [sqlite3_create_function16()] routines that originally +** registered the application defined function. +** +** This routine must be called from the same thread in which +** the application-defined function is running. +*/ +SQLITE_API void *sqlite3_user_data(sqlite3_context*); + +/* +** CAPI3REF: Database Connection For Functions +** METHOD: sqlite3_context +** +** ^The sqlite3_context_db_handle() interface returns a copy of +** the pointer to the [database connection] (the 1st parameter) +** of the [sqlite3_create_function()] +** and [sqlite3_create_function16()] routines that originally +** registered the application defined function. +*/ +SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); + +/* +** CAPI3REF: Function Auxiliary Data +** METHOD: sqlite3_context +** +** These functions may be used by (non-aggregate) SQL functions to +** associate metadata with argument values. If the same value is passed to +** multiple invocations of the same SQL function during query execution, under +** some circumstances the associated metadata may be preserved. An example +** of where this might be useful is in a regular-expression matching +** function. The compiled version of the regular expression can be stored as +** metadata associated with the pattern string. +** Then as long as the pattern string remains the same, +** the compiled regular expression can be reused on multiple +** invocations of the same function. +** +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument +** value to the application-defined function. ^N is zero for the left-most +** function argument. ^If there is no metadata +** associated with the function argument, the sqlite3_get_auxdata(C,N) interface +** returns a NULL pointer. +** +** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th +** argument of the application-defined function. ^Subsequent +** calls to sqlite3_get_auxdata(C,N) return P from the most recent +** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or +** NULL if the metadata has been discarded. +** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, +** SQLite will invoke the destructor function X with parameter P exactly +** once, when the metadata is discarded. +** SQLite is free to discard the metadata at any time, including:
    +**
  • ^(when the corresponding function parameter changes)^, or +**
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the +** SQL statement)^, or +**
  • ^(when sqlite3_set_auxdata() is invoked again on the same +** parameter)^, or +**
  • ^(during the original sqlite3_set_auxdata() call when a memory +** allocation error occurs.)^
+** +** Note the last bullet in particular. The destructor X in +** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the +** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() +** should be called near the end of the function implementation and the +** function implementation should not make any use of P after +** sqlite3_set_auxdata() has been called. +** +** ^(In practice, metadata is preserved between function calls for +** function parameters that are compile-time constants, including literal +** values and [parameters] and expressions composed from the same.)^ +** +** The value of the N parameter to these interfaces should be non-negative. +** Future enhancements may make use of negative N values to define new +** kinds of function caching behavior. +** +** These routines must be called from the same thread in which +** the SQL function is running. +*/ +SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); +SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); + + +/* +** CAPI3REF: Constants Defining Special Destructor Behavior +** +** These are special values for the destructor that is passed in as the +** final argument to routines like [sqlite3_result_blob()]. ^If the destructor +** argument is SQLITE_STATIC, it means that the content pointer is constant +** and will never change. It does not need to be destroyed. ^The +** SQLITE_TRANSIENT value means that the content will likely change in +** the near future and that SQLite should make its own private copy of +** the content before returning. +** +** The typedef is necessary to work around problems in certain +** C++ compilers. +*/ +typedef void (*sqlite3_destructor_type)(void*); +#define SQLITE_STATIC ((sqlite3_destructor_type)0) +#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) + +/* +** CAPI3REF: Setting The Result Of An SQL Function +** METHOD: sqlite3_context +** +** These routines are used by the xFunc or xFinal callbacks that +** implement SQL functions and aggregates. See +** [sqlite3_create_function()] and [sqlite3_create_function16()] +** for additional information. +** +** These functions work very much like the [parameter binding] family of +** functions used to bind values to host parameters in prepared statements. +** Refer to the [SQL parameter] documentation for additional information. +** +** ^The sqlite3_result_blob() interface sets the result from +** an application-defined function to be the BLOB whose content is pointed +** to by the second parameter and which is N bytes long where N is the +** third parameter. +** +** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N) +** interfaces set the result of the application-defined function to be +** a BLOB containing all zero bytes and N bytes in size. +** +** ^The sqlite3_result_double() interface sets the result from +** an application-defined function to be a floating point value specified +** by its 2nd argument. +** +** ^The sqlite3_result_error() and sqlite3_result_error16() functions +** cause the implemented SQL function to throw an exception. +** ^SQLite uses the string pointed to by the +** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() +** as the text of an error message. ^SQLite interprets the error +** message string from sqlite3_result_error() as UTF-8. ^SQLite +** interprets the string from sqlite3_result_error16() as UTF-16 in native +** byte order. ^If the third parameter to sqlite3_result_error() +** or sqlite3_result_error16() is negative then SQLite takes as the error +** message all text up through the first zero character. +** ^If the third parameter to sqlite3_result_error() or +** sqlite3_result_error16() is non-negative then SQLite takes that many +** bytes (not characters) from the 2nd parameter as the error message. +** ^The sqlite3_result_error() and sqlite3_result_error16() +** routines make a private copy of the error message text before +** they return. Hence, the calling function can deallocate or +** modify the text after they return without harm. +** ^The sqlite3_result_error_code() function changes the error code +** returned by SQLite as a result of an error in a function. ^By default, +** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error() +** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. +** +** ^The sqlite3_result_error_toobig() interface causes SQLite to throw an +** error indicating that a string or BLOB is too long to represent. +** +** ^The sqlite3_result_error_nomem() interface causes SQLite to throw an +** error indicating that a memory allocation failed. +** +** ^The sqlite3_result_int() interface sets the return value +** of the application-defined function to be the 32-bit signed integer +** value given in the 2nd argument. +** ^The sqlite3_result_int64() interface sets the return value +** of the application-defined function to be the 64-bit signed integer +** value given in the 2nd argument. +** +** ^The sqlite3_result_null() interface sets the return value +** of the application-defined function to be NULL. +** +** ^The sqlite3_result_text(), sqlite3_result_text16(), +** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces +** set the return value of the application-defined function to be +** a text string which is represented as UTF-8, UTF-16 native byte order, +** UTF-16 little endian, or UTF-16 big endian, respectively. +** ^The sqlite3_result_text64() interface sets the return value of an +** application-defined function to be a text string in an encoding +** specified by the fifth (and last) parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. +** ^SQLite takes the text result from the application from +** the 2nd parameter of the sqlite3_result_text* interfaces. +** ^If the 3rd parameter to the sqlite3_result_text* interfaces +** is negative, then SQLite takes result text from the 2nd parameter +** through the first zero character. +** ^If the 3rd parameter to the sqlite3_result_text* interfaces +** is non-negative, then as many bytes (not characters) of the text +** pointed to by the 2nd parameter are taken as the application-defined +** function result. If the 3rd parameter is non-negative, then it +** must be the byte offset into the string where the NUL terminator would +** appear if the string where NUL terminated. If any NUL characters occur +** in the string at a byte offset that is less than the value of the 3rd +** parameter, then the resulting string will contain embedded NULs and the +** result of expressions operating on strings with embedded NULs is undefined. +** ^If the 4th parameter to the sqlite3_result_text* interfaces +** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that +** function as the destructor on the text or BLOB result when it has +** finished using that result. +** ^If the 4th parameter to the sqlite3_result_text* interfaces or to +** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite +** assumes that the text or BLOB result is in constant space and does not +** copy the content of the parameter nor call a destructor on the content +** when it has finished using that result. +** ^If the 4th parameter to the sqlite3_result_text* interfaces +** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT +** then SQLite makes a copy of the result into space obtained from +** from [sqlite3_malloc()] before it returns. +** +** ^The sqlite3_result_value() interface sets the result of +** the application-defined function to be a copy of the +** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The +** sqlite3_result_value() interface makes a copy of the [sqlite3_value] +** so that the [sqlite3_value] specified in the parameter may change or +** be deallocated after sqlite3_result_value() returns without harm. +** ^A [protected sqlite3_value] object may always be used where an +** [unprotected sqlite3_value] object is required, so either +** kind of [sqlite3_value] object can be used with this interface. +** +** If these routines are called from within the different thread +** than the one containing the application-defined function that received +** the [sqlite3_context] pointer, the results are undefined. +*/ +SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*, + sqlite3_uint64,void(*)(void*)); +SQLITE_API void sqlite3_result_double(sqlite3_context*, double); +SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); +SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); +SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); +SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); +SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); +SQLITE_API void sqlite3_result_null(sqlite3_context*); +SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, + void(*)(void*), unsigned char encoding); +SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); +SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); + + +/* +** CAPI3REF: Setting The Subtype Of An SQL Function +** METHOD: sqlite3_context +** +** The sqlite3_result_subtype(C,T) function causes the subtype of +** the result from the [application-defined SQL function] with +** [sqlite3_context] C to be the value T. Only the lower 8 bits +** of the subtype T are preserved in current versions of SQLite; +** higher order bits are discarded. +** The number of subtype bytes preserved by SQLite might increase +** in future releases of SQLite. +*/ +SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); + +/* +** CAPI3REF: Define New Collating Sequences +** METHOD: sqlite3 +** +** ^These functions add, remove, or modify a [collation] associated +** with the [database connection] specified as the first argument. +** +** ^The name of the collation is a UTF-8 string +** for sqlite3_create_collation() and sqlite3_create_collation_v2() +** and a UTF-16 string in native byte order for sqlite3_create_collation16(). +** ^Collation names that compare equal according to [sqlite3_strnicmp()] are +** considered to be the same name. +** +** ^(The third argument (eTextRep) must be one of the constants: +**
    +**
  • [SQLITE_UTF8], +**
  • [SQLITE_UTF16LE], +**
  • [SQLITE_UTF16BE], +**
  • [SQLITE_UTF16], or +**
  • [SQLITE_UTF16_ALIGNED]. +**
)^ +** ^The eTextRep argument determines the encoding of strings passed +** to the collating function callback, xCallback. +** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep +** force strings to be UTF16 with native byte order. +** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin +** on an even byte address. +** +** ^The fourth argument, pArg, is an application data pointer that is passed +** through as the first argument to the collating function callback. +** +** ^The fifth argument, xCallback, is a pointer to the collating function. +** ^Multiple collating functions can be registered using the same name but +** with different eTextRep parameters and SQLite will use whichever +** function requires the least amount of data transformation. +** ^If the xCallback argument is NULL then the collating function is +** deleted. ^When all collating functions having the same name are deleted, +** that collation is no longer usable. +** +** ^The collating function callback is invoked with a copy of the pArg +** application data pointer and with two strings in the encoding specified +** by the eTextRep argument. The collating function must return an +** integer that is negative, zero, or positive +** if the first string is less than, equal to, or greater than the second, +** respectively. A collating function must always return the same answer +** given the same inputs. If two or more collating functions are registered +** to the same collation name (using different eTextRep values) then all +** must give an equivalent answer when invoked with equivalent strings. +** The collating function must obey the following properties for all +** strings A, B, and C: +** +**
    +**
  1. If A==B then B==A. +**
  2. If A==B and B==C then A==C. +**
  3. If A<B THEN B>A. +**
  4. If A<B and B<C then A<C. +**
+** +** If a collating function fails any of the above constraints and that +** collating function is registered and used, then the behavior of SQLite +** is undefined. +** +** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() +** with the addition that the xDestroy callback is invoked on pArg when +** the collating function is deleted. +** ^Collating functions are deleted when they are overridden by later +** calls to the collation creation functions or when the +** [database connection] is closed using [sqlite3_close()]. +** +** ^The xDestroy callback is not called if the +** sqlite3_create_collation_v2() function fails. Applications that invoke +** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should +** check the return code and dispose of the application data pointer +** themselves rather than expecting SQLite to deal with it for them. +** This is different from every other SQLite interface. The inconsistency +** is unfortunate but cannot be changed without breaking backwards +** compatibility. +** +** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. +*/ +SQLITE_API int sqlite3_create_collation( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); +SQLITE_API int sqlite3_create_collation_v2( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDestroy)(void*) +); +SQLITE_API int sqlite3_create_collation16( + sqlite3*, + const void *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); + +/* +** CAPI3REF: Collation Needed Callbacks +** METHOD: sqlite3 +** +** ^To avoid having to register all collation sequences before a database +** can be used, a single callback function may be registered with the +** [database connection] to be invoked whenever an undefined collation +** sequence is required. +** +** ^If the function is registered using the sqlite3_collation_needed() API, +** then it is passed the names of undefined collation sequences as strings +** encoded in UTF-8. ^If sqlite3_collation_needed16() is used, +** the names are passed as UTF-16 in machine native byte order. +** ^A call to either function replaces the existing collation-needed callback. +** +** ^(When the callback is invoked, the first argument passed is a copy +** of the second argument to sqlite3_collation_needed() or +** sqlite3_collation_needed16(). The second argument is the database +** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE], indicating the most desirable form of the collation +** sequence function required. The fourth parameter is the name of the +** required collation sequence.)^ +** +** The callback function should register the desired collation using +** [sqlite3_create_collation()], [sqlite3_create_collation16()], or +** [sqlite3_create_collation_v2()]. +*/ +SQLITE_API int sqlite3_collation_needed( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const char*) +); +SQLITE_API int sqlite3_collation_needed16( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const void*) +); + +#ifdef SQLITE_HAS_CODEC +/* +** Specify the key for an encrypted database. This routine should be +** called right after sqlite3_open(). +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_key( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The key */ +); +SQLITE_API int sqlite3_key_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The key */ +); + +/* +** Change the key on an open database. If the current database is not +** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the +** database is decrypted. +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_rekey( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The new key */ +); +SQLITE_API int sqlite3_rekey_v2( + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The new key */ +); + +/* +** Specify the activation key for a SEE database. Unless +** activated, none of the SEE routines will work. +*/ +SQLITE_API void sqlite3_activate_see( + const char *zPassPhrase /* Activation phrase */ +); +#endif + +#ifdef SQLITE_ENABLE_CEROD +/* +** Specify the activation key for a CEROD database. Unless +** activated, none of the CEROD routines will work. +*/ +SQLITE_API void sqlite3_activate_cerod( + const char *zPassPhrase /* Activation phrase */ +); +#endif + +/* +** CAPI3REF: Suspend Execution For A Short Time +** +** The sqlite3_sleep() function causes the current thread to suspend execution +** for at least a number of milliseconds specified in its parameter. +** +** If the operating system does not support sleep requests with +** millisecond time resolution, then the time will be rounded up to +** the nearest second. The number of milliseconds of sleep actually +** requested from the operating system is returned. +** +** ^SQLite implements this interface by calling the xSleep() +** method of the default [sqlite3_vfs] object. If the xSleep() method +** of the default VFS is not implemented correctly, or not implemented at +** all, then the behavior of sqlite3_sleep() may deviate from the description +** in the previous paragraphs. +*/ +SQLITE_API int sqlite3_sleep(int); + +/* +** CAPI3REF: Name Of The Folder Holding Temporary Files +** +** ^(If this global variable is made to point to a string which is +** the name of a folder (a.k.a. directory), then all temporary files +** created by SQLite when using a built-in [sqlite3_vfs | VFS] +** will be placed in that directory.)^ ^If this variable +** is a NULL pointer, then SQLite performs a search for an appropriate +** temporary file directory. +** +** Applications are strongly discouraged from using this global variable. +** It is required to set a temporary folder on Windows Runtime (WinRT). +** But for all other platforms, it is highly recommended that applications +** neither read nor write this variable. This global variable is a relic +** that exists for backwards compatibility of legacy applications and should +** be avoided in new projects. +** +** It is not safe to read or modify this variable in more than one +** thread at a time. It is not safe to read or modify this variable +** if a [database connection] is being used at the same time in a separate +** thread. +** It is intended that this variable be set once +** as part of process initialization and before any SQLite interface +** routines have been called and that this variable remain unchanged +** thereafter. +** +** ^The [temp_store_directory pragma] may modify this variable and cause +** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, +** the [temp_store_directory pragma] always assumes that any string +** that this variable points to is held in memory obtained from +** [sqlite3_malloc] and the pragma may attempt to free that memory +** using [sqlite3_free]. +** Hence, if this variable is modified directly, either it should be +** made NULL or made to point to memory obtained from [sqlite3_malloc] +** or else the use of the [temp_store_directory pragma] should be avoided. +** Except when requested by the [temp_store_directory pragma], SQLite +** does not free the memory that sqlite3_temp_directory points to. If +** the application wants that memory to be freed, it must do +** so itself, taking care to only do so after all [database connection] +** objects have been destroyed. +** +** Note to Windows Runtime users: The temporary directory must be set +** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various +** features that require the use of temporary files may fail. Here is an +** example of how to do this using C++ with the Windows Runtime: +** +**
+** LPCWSTR zPath = Windows::Storage::ApplicationData::Current->
+**       TemporaryFolder->Path->Data();
+** char zPathBuf[MAX_PATH + 1];
+** memset(zPathBuf, 0, sizeof(zPathBuf));
+** WideCharToMultiByte(CP_UTF8, 0, zPath, -1, zPathBuf, sizeof(zPathBuf),
+**       NULL, NULL);
+** sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
+** 
+*/ +SQLITE_API char *sqlite3_temp_directory; + +/* +** CAPI3REF: Name Of The Folder Holding Database Files +** +** ^(If this global variable is made to point to a string which is +** the name of a folder (a.k.a. directory), then all database files +** specified with a relative pathname and created or accessed by +** SQLite when using a built-in windows [sqlite3_vfs | VFS] will be assumed +** to be relative to that directory.)^ ^If this variable is a NULL +** pointer, then SQLite assumes that all database files specified +** with a relative pathname are relative to the current directory +** for the process. Only the windows VFS makes use of this global +** variable; it is ignored by the unix VFS. +** +** Changing the value of this variable while a database connection is +** open can result in a corrupt database. +** +** It is not safe to read or modify this variable in more than one +** thread at a time. It is not safe to read or modify this variable +** if a [database connection] is being used at the same time in a separate +** thread. +** It is intended that this variable be set once +** as part of process initialization and before any SQLite interface +** routines have been called and that this variable remain unchanged +** thereafter. +** +** ^The [data_store_directory pragma] may modify this variable and cause +** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, +** the [data_store_directory pragma] always assumes that any string +** that this variable points to is held in memory obtained from +** [sqlite3_malloc] and the pragma may attempt to free that memory +** using [sqlite3_free]. +** Hence, if this variable is modified directly, either it should be +** made NULL or made to point to memory obtained from [sqlite3_malloc] +** or else the use of the [data_store_directory pragma] should be avoided. +*/ +SQLITE_API char *sqlite3_data_directory; + +/* +** CAPI3REF: Test For Auto-Commit Mode +** KEYWORDS: {autocommit mode} +** METHOD: sqlite3 +** +** ^The sqlite3_get_autocommit() interface returns non-zero or +** zero if the given database connection is or is not in autocommit mode, +** respectively. ^Autocommit mode is on by default. +** ^Autocommit mode is disabled by a [BEGIN] statement. +** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK]. +** +** If certain kinds of errors occur on a statement within a multi-statement +** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR], +** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the +** transaction might be rolled back automatically. The only way to +** find out whether SQLite automatically rolled back the transaction after +** an error is to use this function. +** +** If another thread changes the autocommit status of the database +** connection while this routine is running, then the return value +** is undefined. +*/ +SQLITE_API int sqlite3_get_autocommit(sqlite3*); + +/* +** CAPI3REF: Find The Database Handle Of A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_db_handle interface returns the [database connection] handle +** to which a [prepared statement] belongs. ^The [database connection] +** returned by sqlite3_db_handle is the same [database connection] +** that was the first argument +** to the [sqlite3_prepare_v2()] call (or its variants) that was used to +** create the statement in the first place. +*/ +SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); + +/* +** CAPI3REF: Return The Filename For A Database Connection +** METHOD: sqlite3 +** +** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename +** associated with database N of connection D. ^The main database file +** has the name "main". If there is no attached database N on the database +** connection D, or if database N is a temporary or in-memory database, then +** a NULL pointer is returned. +** +** ^The filename returned by this function is the output of the +** xFullPathname method of the [VFS]. ^In other words, the filename +** will be an absolute pathname, even if the filename used +** to open the database originally was a URI or relative pathname. +*/ +SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); + +/* +** CAPI3REF: Determine if a database is read-only +** METHOD: sqlite3 +** +** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N +** of connection D is read-only, 0 if it is read/write, or -1 if N is not +** the name of a database on connection D. +*/ +SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); + +/* +** CAPI3REF: Find the next prepared statement +** METHOD: sqlite3 +** +** ^This interface returns a pointer to the next [prepared statement] after +** pStmt associated with the [database connection] pDb. ^If pStmt is NULL +** then this interface returns a pointer to the first prepared statement +** associated with the database connection pDb. ^If no prepared statement +** satisfies the conditions of this routine, it returns NULL. +** +** The [database connection] pointer D in a call to +** [sqlite3_next_stmt(D,S)] must refer to an open database +** connection and in particular must not be a NULL pointer. +*/ +SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Commit And Rollback Notification Callbacks +** METHOD: sqlite3 +** +** ^The sqlite3_commit_hook() interface registers a callback +** function to be invoked whenever a transaction is [COMMIT | committed]. +** ^Any callback set by a previous call to sqlite3_commit_hook() +** for the same database connection is overridden. +** ^The sqlite3_rollback_hook() interface registers a callback +** function to be invoked whenever a transaction is [ROLLBACK | rolled back]. +** ^Any callback set by a previous call to sqlite3_rollback_hook() +** for the same database connection is overridden. +** ^The pArg argument is passed through to the callback. +** ^If the callback on a commit hook function returns non-zero, +** then the commit is converted into a rollback. +** +** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions +** return the P argument from the previous call of the same function +** on the same [database connection] D, or NULL for +** the first call for each function on D. +** +** The commit and rollback hook callbacks are not reentrant. +** The callback implementation must not do anything that will modify +** the database connection that invoked the callback. Any actions +** to modify the database connection must be deferred until after the +** completion of the [sqlite3_step()] call that triggered the commit +** or rollback hook in the first place. +** Note that running any other SQL statements, including SELECT statements, +** or merely calling [sqlite3_prepare_v2()] and [sqlite3_step()] will modify +** the database connections for the meaning of "modify" in this paragraph. +** +** ^Registering a NULL function disables the callback. +** +** ^When the commit hook callback routine returns zero, the [COMMIT] +** operation is allowed to continue normally. ^If the commit hook +** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK]. +** ^The rollback hook is invoked on a rollback that results from a commit +** hook returning non-zero, just as it would be with any other rollback. +** +** ^For the purposes of this API, a transaction is said to have been +** rolled back if an explicit "ROLLBACK" statement is executed, or +** an error or constraint causes an implicit rollback to occur. +** ^The rollback callback is not invoked if a transaction is +** automatically rolled back because the database connection is closed. +** +** See also the [sqlite3_update_hook()] interface. +*/ +SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); +SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); + +/* +** CAPI3REF: Data Change Notification Callbacks +** METHOD: sqlite3 +** +** ^The sqlite3_update_hook() interface registers a callback function +** with the [database connection] identified by the first argument +** to be invoked whenever a row is updated, inserted or deleted in +** a [rowid table]. +** ^Any callback set by a previous call to this function +** for the same database connection is overridden. +** +** ^The second argument is a pointer to the function to invoke when a +** row is updated, inserted or deleted in a rowid table. +** ^The first argument to the callback is a copy of the third argument +** to sqlite3_update_hook(). +** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], +** or [SQLITE_UPDATE], depending on the operation that caused the callback +** to be invoked. +** ^The third and fourth arguments to the callback contain pointers to the +** database and table name containing the affected row. +** ^The final callback parameter is the [rowid] of the row. +** ^In the case of an update, this is the [rowid] after the update takes place. +** +** ^(The update hook is not invoked when internal system tables are +** modified (i.e. sqlite_master and sqlite_sequence).)^ +** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. +** +** ^In the current implementation, the update hook +** is not invoked when conflicting rows are deleted because of an +** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook +** invoked when rows are deleted using the [truncate optimization]. +** The exceptions defined in this paragraph might change in a future +** release of SQLite. +** +** The update hook implementation must not do anything that will modify +** the database connection that invoked the update hook. Any actions +** to modify the database connection must be deferred until after the +** completion of the [sqlite3_step()] call that triggered the update hook. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +** ^The sqlite3_update_hook(D,C,P) function +** returns the P argument from the previous call +** on the same [database connection] D, or NULL for +** the first call on D. +** +** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()], +** and [sqlite3_preupdate_hook()] interfaces. +*/ +SQLITE_API void *sqlite3_update_hook( + sqlite3*, + void(*)(void *,int ,char const *,char const *,sqlite3_int64), + void* +); + +/* +** CAPI3REF: Enable Or Disable Shared Pager Cache +** +** ^(This routine enables or disables the sharing of the database cache +** and schema data structures between [database connection | connections] +** to the same database. Sharing is enabled if the argument is true +** and disabled if the argument is false.)^ +** +** ^Cache sharing is enabled and disabled for an entire process. +** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). +** In prior versions of SQLite, +** sharing was enabled or disabled for each thread separately. +** +** ^(The cache sharing mode set by this interface effects all subsequent +** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. +** Existing database connections continue use the sharing mode +** that was in effect at the time they were opened.)^ +** +** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled +** successfully. An [error code] is returned otherwise.)^ +** +** ^Shared cache is disabled by default. But this might change in +** future releases of SQLite. Applications that care about shared +** cache setting should set it explicitly. +** +** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 +** and will always return SQLITE_MISUSE. On those systems, +** shared cache mode should be enabled per-database connection via +** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. +** +** This interface is threadsafe on processors where writing a +** 32-bit integer is atomic. +** +** See Also: [SQLite Shared-Cache Mode] +*/ +SQLITE_API int sqlite3_enable_shared_cache(int); + +/* +** CAPI3REF: Attempt To Free Heap Memory +** +** ^The sqlite3_release_memory() interface attempts to free N bytes +** of heap memory by deallocating non-essential memory allocations +** held by the database library. Memory used to cache database +** pages to improve performance is an example of non-essential memory. +** ^sqlite3_release_memory() returns the number of bytes actually freed, +** which might be more or less than the amount requested. +** ^The sqlite3_release_memory() routine is a no-op returning zero +** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. +** +** See also: [sqlite3_db_release_memory()] +*/ +SQLITE_API int sqlite3_release_memory(int); + +/* +** CAPI3REF: Free Memory Used By A Database Connection +** METHOD: sqlite3 +** +** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap +** memory as possible from database connection D. Unlike the +** [sqlite3_release_memory()] interface, this interface is in effect even +** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is +** omitted. +** +** See also: [sqlite3_release_memory()] +*/ +SQLITE_API int sqlite3_db_release_memory(sqlite3*); + +/* +** CAPI3REF: Impose A Limit On Heap Size +** +** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the +** soft limit on the amount of heap memory that may be allocated by SQLite. +** ^SQLite strives to keep heap memory utilization below the soft heap +** limit by reducing the number of pages held in the page cache +** as heap memory usages approaches the limit. +** ^The soft heap limit is "soft" because even though SQLite strives to stay +** below the limit, it will exceed the limit rather than generate +** an [SQLITE_NOMEM] error. In other words, the soft heap limit +** is advisory only. +** +** ^The return value from sqlite3_soft_heap_limit64() is the size of +** the soft heap limit prior to the call, or negative in the case of an +** error. ^If the argument N is negative +** then no change is made to the soft heap limit. Hence, the current +** size of the soft heap limit can be determined by invoking +** sqlite3_soft_heap_limit64() with a negative argument. +** +** ^If the argument N is zero then the soft heap limit is disabled. +** +** ^(The soft heap limit is not enforced in the current implementation +** if one or more of following conditions are true: +** +**
    +**
  • The soft heap limit is set to zero. +**
  • Memory accounting is disabled using a combination of the +** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and +** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. +**
  • An alternative page cache implementation is specified using +** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...). +**
  • The page cache allocates from its own memory pool supplied +** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than +** from the heap. +**
)^ +** +** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), +** the soft heap limit is enforced +** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] +** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], +** the soft heap limit is enforced on every memory allocation. Without +** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced +** when memory is allocated by the page cache. Testing suggests that because +** the page cache is the predominate memory user in SQLite, most +** applications will achieve adequate soft heap limit enforcement without +** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. +** +** The circumstances under which SQLite will enforce the soft heap limit may +** changes in future releases of SQLite. +*/ +SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); + +/* +** CAPI3REF: Deprecated Soft Heap Limit Interface +** DEPRECATED +** +** This is a deprecated version of the [sqlite3_soft_heap_limit64()] +** interface. This routine is provided for historical compatibility +** only. All new applications should use the +** [sqlite3_soft_heap_limit64()] interface rather than this one. +*/ +SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); + + +/* +** CAPI3REF: Extract Metadata About A Column Of A Table +** METHOD: sqlite3 +** +** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns +** information about column C of table T in database D +** on [database connection] X.)^ ^The sqlite3_table_column_metadata() +** interface returns SQLITE_OK and fills in the non-NULL pointers in +** the final five arguments with appropriate values if the specified +** column exists. ^The sqlite3_table_column_metadata() interface returns +** SQLITE_ERROR and if the specified column does not exist. +** ^If the column-name parameter to sqlite3_table_column_metadata() is a +** NULL pointer, then this routine simply checks for the existence of the +** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it +** does not. +** +** ^The column is identified by the second, third and fourth parameters to +** this function. ^(The second parameter is either the name of the database +** (i.e. "main", "temp", or an attached database) containing the specified +** table or NULL.)^ ^If it is NULL, then all attached databases are searched +** for the table using the same algorithm used by the database engine to +** resolve unqualified table references. +** +** ^The third and fourth parameters to this function are the table and column +** name of the desired column, respectively. +** +** ^Metadata is returned by writing to the memory locations passed as the 5th +** and subsequent parameters to this function. ^Any of these arguments may be +** NULL, in which case the corresponding element of metadata is omitted. +** +** ^(
+** +**
Parameter Output
Type
Description +** +**
5th const char* Data type +**
6th const char* Name of default collation sequence +**
7th int True if column has a NOT NULL constraint +**
8th int True if column is part of the PRIMARY KEY +**
9th int True if column is [AUTOINCREMENT] +**
+**
)^ +** +** ^The memory pointed to by the character pointers returned for the +** declaration type and collation sequence is valid until the next +** call to any SQLite API function. +** +** ^If the specified table is actually a view, an [error code] is returned. +** +** ^If the specified column is "rowid", "oid" or "_rowid_" and the table +** is not a [WITHOUT ROWID] table and an +** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output +** parameters are set for the explicitly declared column. ^(If there is no +** [INTEGER PRIMARY KEY] column, then the outputs +** for the [rowid] are set as follows: +** +**
+**     data type: "INTEGER"
+**     collation sequence: "BINARY"
+**     not null: 0
+**     primary key: 1
+**     auto increment: 0
+** 
)^ +** +** ^This function causes all database schemas to be read from disk and +** parsed, if that has not already been done, and returns an error if +** any errors are encountered while loading the schema. +*/ +SQLITE_API int sqlite3_table_column_metadata( + sqlite3 *db, /* Connection handle */ + const char *zDbName, /* Database name or NULL */ + const char *zTableName, /* Table name */ + const char *zColumnName, /* Column name */ + char const **pzDataType, /* OUTPUT: Declared data type */ + char const **pzCollSeq, /* OUTPUT: Collation sequence name */ + int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int *pPrimaryKey, /* OUTPUT: True if column part of PK */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ +); + +/* +** CAPI3REF: Load An Extension +** METHOD: sqlite3 +** +** ^This interface loads an SQLite extension library from the named file. +** +** ^The sqlite3_load_extension() interface attempts to load an +** [SQLite extension] library contained in the file zFile. If +** the file cannot be loaded directly, attempts are made to load +** with various operating-system specific extensions added. +** So for example, if "samplelib" cannot be loaded, then names like +** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might +** be tried also. +** +** ^The entry point is zProc. +** ^(zProc may be 0, in which case SQLite will try to come up with an +** entry point name on its own. It first tries "sqlite3_extension_init". +** If that does not work, it constructs a name "sqlite3_X_init" where the +** X is consists of the lower-case equivalent of all ASCII alphabetic +** characters in the filename from the last "/" to the first following +** "." and omitting any initial "lib".)^ +** ^The sqlite3_load_extension() interface returns +** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. +** ^If an error occurs and pzErrMsg is not 0, then the +** [sqlite3_load_extension()] interface shall attempt to +** fill *pzErrMsg with error message text stored in memory +** obtained from [sqlite3_malloc()]. The calling function +** should free this memory by calling [sqlite3_free()]. +** +** ^Extension loading must be enabled using +** [sqlite3_enable_load_extension()] or +** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL) +** prior to calling this API, +** otherwise an error will be returned. +** +** Security warning: It is recommended that the +** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this +** interface. The use of the [sqlite3_enable_load_extension()] interface +** should be avoided. This will keep the SQL function [load_extension()] +** disabled and prevent SQL injections from giving attackers +** access to extension loading capabilities. +** +** See also the [load_extension() SQL function]. +*/ +SQLITE_API int sqlite3_load_extension( + sqlite3 *db, /* Load the extension into this database connection */ + const char *zFile, /* Name of the shared library containing extension */ + const char *zProc, /* Entry point. Derived from zFile if 0 */ + char **pzErrMsg /* Put error message here if not 0 */ +); + +/* +** CAPI3REF: Enable Or Disable Extension Loading +** METHOD: sqlite3 +** +** ^So as not to open security holes in older applications that are +** unprepared to deal with [extension loading], and as a means of disabling +** [extension loading] while evaluating user-entered SQL, the following API +** is provided to turn the [sqlite3_load_extension()] mechanism on and off. +** +** ^Extension loading is off by default. +** ^Call the sqlite3_enable_load_extension() routine with onoff==1 +** to turn extension loading on and call it with onoff==0 to turn +** it back off again. +** +** ^This interface enables or disables both the C-API +** [sqlite3_load_extension()] and the SQL function [load_extension()]. +** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) +** to enable or disable only the C-API.)^ +** +** Security warning: It is recommended that extension loading +** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method +** rather than this interface, so the [load_extension()] SQL function +** remains disabled. This will prevent SQL injections from giving attackers +** access to extension loading capabilities. +*/ +SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); + +/* +** CAPI3REF: Automatically Load Statically Linked Extensions +** +** ^This interface causes the xEntryPoint() function to be invoked for +** each new [database connection] that is created. The idea here is that +** xEntryPoint() is the entry point for a statically linked [SQLite extension] +** that is to be automatically loaded into all new database connections. +** +** ^(Even though the function prototype shows that xEntryPoint() takes +** no arguments and returns void, SQLite invokes xEntryPoint() with three +** arguments and expects an integer result as if the signature of the +** entry point where as follows: +** +**
+**    int xEntryPoint(
+**      sqlite3 *db,
+**      const char **pzErrMsg,
+**      const struct sqlite3_api_routines *pThunk
+**    );
+** 
)^ +** +** If the xEntryPoint routine encounters an error, it should make *pzErrMsg +** point to an appropriate error message (obtained from [sqlite3_mprintf()]) +** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg +** is NULL before calling the xEntryPoint(). ^SQLite will invoke +** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any +** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], +** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. +** +** ^Calling sqlite3_auto_extension(X) with an entry point X that is already +** on the list of automatic extensions is a harmless no-op. ^No entry point +** will be called more than once for each database connection that is opened. +** +** See also: [sqlite3_reset_auto_extension()] +** and [sqlite3_cancel_auto_extension()] +*/ +SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)); + +/* +** CAPI3REF: Cancel Automatic Extension Loading +** +** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the +** initialization routine X that was registered using a prior call to +** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] +** routine returns 1 if initialization routine X was successfully +** unregistered and it returns 0 if X was not on the list of initialization +** routines. +*/ +SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); + +/* +** CAPI3REF: Reset Automatic Extension Loading +** +** ^This interface disables all automatic extensions previously +** registered using [sqlite3_auto_extension()]. +*/ +SQLITE_API void sqlite3_reset_auto_extension(void); + +/* +** The interface to the virtual-table mechanism is currently considered +** to be experimental. The interface might change in incompatible ways. +** If this is a problem for you, do not use the interface at this time. +** +** When the virtual-table mechanism stabilizes, we will declare the +** interface fixed, support it indefinitely, and remove this comment. +*/ + +/* +** Structures used by the virtual table interface +*/ +typedef struct sqlite3_vtab sqlite3_vtab; +typedef struct sqlite3_index_info sqlite3_index_info; +typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; +typedef struct sqlite3_module sqlite3_module; + +/* +** CAPI3REF: Virtual Table Object +** KEYWORDS: sqlite3_module {virtual table module} +** +** This structure, sometimes called a "virtual table module", +** defines the implementation of a [virtual tables]. +** This structure consists mostly of methods for the module. +** +** ^A virtual table module is created by filling in a persistent +** instance of this structure and passing a pointer to that instance +** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. +** ^The registration remains valid until it is replaced by a different +** module or until the [database connection] closes. The content +** of this structure must not change while it is registered with +** any database connection. +*/ +struct sqlite3_module { + int iVersion; + int (*xCreate)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xConnect)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); + int (*xDisconnect)(sqlite3_vtab *pVTab); + int (*xDestroy)(sqlite3_vtab *pVTab); + int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); + int (*xClose)(sqlite3_vtab_cursor*); + int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, + int argc, sqlite3_value **argv); + int (*xNext)(sqlite3_vtab_cursor*); + int (*xEof)(sqlite3_vtab_cursor*); + int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); + int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); + int (*xBegin)(sqlite3_vtab *pVTab); + int (*xSync)(sqlite3_vtab *pVTab); + int (*xCommit)(sqlite3_vtab *pVTab); + int (*xRollback)(sqlite3_vtab *pVTab); + int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg); + int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + /* The methods above are in version 1 of the sqlite_module object. Those + ** below are for version 2 and greater. */ + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); +}; + +/* +** CAPI3REF: Virtual Table Indexing Information +** KEYWORDS: sqlite3_index_info +** +** The sqlite3_index_info structure and its substructures is used as part +** of the [virtual table] interface to +** pass information into and receive the reply from the [xBestIndex] +** method of a [virtual table module]. The fields under **Inputs** are the +** inputs to xBestIndex and are read-only. xBestIndex inserts its +** results into the **Outputs** fields. +** +** ^(The aConstraint[] array records WHERE clause constraints of the form: +** +**
column OP expr
+** +** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is +** stored in aConstraint[].op using one of the +** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^ +** ^(The index of the column is stored in +** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the +** expr on the right-hand side can be evaluated (and thus the constraint +** is usable) and false if it cannot.)^ +** +** ^The optimizer automatically inverts terms of the form "expr OP column" +** and makes other simplifications to the WHERE clause in an attempt to +** get as many WHERE clause terms into the form shown above as possible. +** ^The aConstraint[] array only reports WHERE clause terms that are +** relevant to the particular virtual table being queried. +** +** ^Information about the ORDER BY clause is stored in aOrderBy[]. +** ^Each term of aOrderBy records a column of the ORDER BY clause. +** +** The colUsed field indicates which columns of the virtual table may be +** required by the current scan. Virtual table columns are numbered from +** zero in the order in which they appear within the CREATE TABLE statement +** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62), +** the corresponding bit is set within the colUsed mask if the column may be +** required by SQLite. If the table has at least 64 columns and any column +** to the right of the first 63 is required, then bit 63 of colUsed is also +** set. In other words, column iCol may be required if the expression +** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to +** non-zero. +** +** The [xBestIndex] method must fill aConstraintUsage[] with information +** about what parameters to pass to xFilter. ^If argvIndex>0 then +** the right-hand side of the corresponding aConstraint[] is evaluated +** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit +** is true, then the constraint is assumed to be fully handled by the +** virtual table and is not checked again by SQLite.)^ +** +** ^The idxNum and idxPtr values are recorded and passed into the +** [xFilter] method. +** ^[sqlite3_free()] is used to free idxPtr if and only if +** needToFreeIdxPtr is true. +** +** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in +** the correct order to satisfy the ORDER BY clause so that no separate +** sorting step is required. +** +** ^The estimatedCost value is an estimate of the cost of a particular +** strategy. A cost of N indicates that the cost of the strategy is similar +** to a linear scan of an SQLite table with N rows. A cost of log(N) +** indicates that the expense of the operation is similar to that of a +** binary search on a unique indexed field of an SQLite table with N rows. +** +** ^The estimatedRows value is an estimate of the number of rows that +** will be returned by the strategy. +** +** The xBestIndex method may optionally populate the idxFlags field with a +** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - +** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite +** assumes that the strategy may visit at most one row. +** +** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then +** SQLite also assumes that if a call to the xUpdate() method is made as +** part of the same statement to delete or update a virtual table row and the +** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback +** any database changes. In other words, if the xUpdate() returns +** SQLITE_CONSTRAINT, the database contents must be exactly as they were +** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not +** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by +** the xUpdate method are automatically rolled back by SQLite. +** +** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info +** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). +** If a virtual table extension is +** used with an SQLite version earlier than 3.8.2, the results of attempting +** to read or write the estimatedRows field are undefined (but are likely +** to included crashing the application). The estimatedRows field should +** therefore only be used if [sqlite3_libversion_number()] returns a +** value greater than or equal to 3008002. Similarly, the idxFlags field +** was added for [version 3.9.0] ([dateof:3.9.0]). +** It may therefore only be used if +** sqlite3_libversion_number() returns a value greater than or equal to +** 3009000. +*/ +struct sqlite3_index_info { + /* Inputs */ + int nConstraint; /* Number of entries in aConstraint */ + struct sqlite3_index_constraint { + int iColumn; /* Column constrained. -1 for ROWID */ + unsigned char op; /* Constraint operator */ + unsigned char usable; /* True if this constraint is usable */ + int iTermOffset; /* Used internally - xBestIndex should ignore */ + } *aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct sqlite3_index_orderby { + int iColumn; /* Column number */ + unsigned char desc; /* True for DESC. False for ASC. */ + } *aOrderBy; /* The ORDER BY clause */ + /* Outputs */ + struct sqlite3_index_constraint_usage { + int argvIndex; /* if >0, constraint is part of argv to xFilter */ + unsigned char omit; /* Do not code a test for this constraint */ + } *aConstraintUsage; + int idxNum; /* Number used to identify the index */ + char *idxStr; /* String, possibly obtained from sqlite3_malloc */ + int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ + int orderByConsumed; /* True if output is already ordered */ + double estimatedCost; /* Estimated cost of using this index */ + /* Fields below are only available in SQLite 3.8.2 and later */ + sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ + /* Fields below are only available in SQLite 3.9.0 and later */ + int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ + /* Fields below are only available in SQLite 3.10.0 and later */ + sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ +}; + +/* +** CAPI3REF: Virtual Table Scan Flags +*/ +#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ + +/* +** CAPI3REF: Virtual Table Constraint Operator Codes +** +** These macros defined the allowed values for the +** [sqlite3_index_info].aConstraint[].op field. Each value represents +** an operator that is part of a constraint term in the wHERE clause of +** 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 + +/* +** CAPI3REF: Register A Virtual Table Implementation +** METHOD: sqlite3 +** +** ^These routines are used to register a new [virtual table module] name. +** ^Module names must be registered before +** creating a new [virtual table] using the module and before using a +** preexisting [virtual table] for the module. +** +** ^The module name is registered on the [database connection] specified +** by the first parameter. ^The name of the module is given by the +** second parameter. ^The third parameter is a pointer to +** the implementation of the [virtual table module]. ^The fourth +** parameter is an arbitrary client data pointer that is passed through +** into the [xCreate] and [xConnect] methods of the virtual table module +** when a new virtual table is be being created or reinitialized. +** +** ^The sqlite3_create_module_v2() interface has a fifth parameter which +** is a pointer to a destructor for the pClientData. ^SQLite will +** invoke the destructor function (if it is not NULL) when SQLite +** no longer needs the pClientData pointer. ^The destructor will also +** be invoked if the call to sqlite3_create_module_v2() fails. +** ^The sqlite3_create_module() +** interface is equivalent to sqlite3_create_module_v2() with a NULL +** destructor. +*/ +SQLITE_API int sqlite3_create_module( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData /* Client data for xCreate/xConnect */ +); +SQLITE_API int sqlite3_create_module_v2( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData, /* Client data for xCreate/xConnect */ + void(*xDestroy)(void*) /* Module destructor function */ +); + +/* +** CAPI3REF: Virtual Table Instance Object +** KEYWORDS: sqlite3_vtab +** +** Every [virtual table module] implementation uses a subclass +** of this object to describe a particular instance +** of the [virtual table]. Each subclass will +** be tailored to the specific needs of the module implementation. +** The purpose of this superclass is to define certain fields that are +** common to all module implementations. +** +** ^Virtual tables methods can set an error message by assigning a +** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should +** take care that any prior string is freed by a call to [sqlite3_free()] +** prior to assigning a new string to zErrMsg. ^After the error message +** is delivered up to the client application, the string will be automatically +** freed by sqlite3_free() and the zErrMsg field will be zeroed. +*/ +struct sqlite3_vtab { + const sqlite3_module *pModule; /* The module for this virtual table */ + int nRef; /* Number of open cursors */ + char *zErrMsg; /* Error message from sqlite3_mprintf() */ + /* Virtual table implementations will typically add additional fields */ +}; + +/* +** CAPI3REF: Virtual Table Cursor Object +** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} +** +** Every [virtual table module] implementation uses a subclass of the +** following structure to describe cursors that point into the +** [virtual table] and are used +** to loop through the virtual table. Cursors are created using the +** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed +** by the [sqlite3_module.xClose | xClose] method. Cursors are used +** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods +** of the module. Each module implementation will define +** the content of a cursor structure to suit its own needs. +** +** This superclass exists in order to define fields of the cursor that +** are common to all implementations. +*/ +struct sqlite3_vtab_cursor { + sqlite3_vtab *pVtab; /* Virtual table of this cursor */ + /* Virtual table implementations will typically add additional fields */ +}; + +/* +** CAPI3REF: Declare The Schema Of A Virtual Table +** +** ^The [xCreate] and [xConnect] methods of a +** [virtual table module] call this interface +** to declare the format (the names and datatypes of the columns) of +** the virtual tables they implement. +*/ +SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); + +/* +** CAPI3REF: Overload A Function For A Virtual Table +** METHOD: sqlite3 +** +** ^(Virtual tables can provide alternative implementations of functions +** using the [xFindFunction] method of the [virtual table module]. +** But global versions of those functions +** must exist in order to be overloaded.)^ +** +** ^(This API makes sure a global version of a function with a particular +** name and number of parameters exists. If no such function exists +** before this API is called, a new function is created.)^ ^The implementation +** of the new function always causes an exception to be thrown. So +** the new function is not good for anything by itself. Its only +** purpose is to be a placeholder function that can be overloaded +** by a [virtual table]. +*/ +SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); + +/* +** The interface to the virtual-table mechanism defined above (back up +** to a comment remarkably similar to this one) is currently considered +** to be experimental. The interface might change in incompatible ways. +** If this is a problem for you, do not use the interface at this time. +** +** When the virtual-table mechanism stabilizes, we will declare the +** interface fixed, support it indefinitely, and remove this comment. +*/ + +/* +** CAPI3REF: A Handle To An Open BLOB +** KEYWORDS: {BLOB handle} {BLOB handles} +** +** An instance of this object represents an open BLOB on which +** [sqlite3_blob_open | incremental BLOB I/O] can be performed. +** ^Objects of this type are created by [sqlite3_blob_open()] +** and destroyed by [sqlite3_blob_close()]. +** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces +** can be used to read or write small subsections of the BLOB. +** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes. +*/ +typedef struct sqlite3_blob sqlite3_blob; + +/* +** CAPI3REF: Open A BLOB For Incremental I/O +** METHOD: sqlite3 +** CONSTRUCTOR: sqlite3_blob +** +** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located +** in row iRow, column zColumn, table zTable in database zDb; +** in other words, the same BLOB that would be selected by: +** +**
+**     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
+** 
)^ +** +** ^(Parameter zDb is not the filename that contains the database, but +** rather the symbolic name of the database. For attached databases, this is +** the name that appears after the AS keyword in the [ATTACH] statement. +** For the main database file, the database name is "main". For TEMP +** tables, the database name is "temp".)^ +** +** ^If the flags parameter is non-zero, then the BLOB is opened for read +** and write access. ^If the flags parameter is zero, the BLOB is opened for +** read-only access. +** +** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored +** in *ppBlob. Otherwise an [error code] is returned and, unless the error +** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided +** the API is not misused, it is always safe to call [sqlite3_blob_close()] +** on *ppBlob after this function it returns. +** +** This function fails with SQLITE_ERROR if any of the following are true: +**
    +**
  • ^(Database zDb does not exist)^, +**
  • ^(Table zTable does not exist within database zDb)^, +**
  • ^(Table zTable is a WITHOUT ROWID table)^, +**
  • ^(Column zColumn does not exist)^, +**
  • ^(Row iRow is not present in the table)^, +**
  • ^(The specified column of row iRow contains a value that is not +** a TEXT or BLOB value)^, +**
  • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE +** constraint and the blob is being opened for read/write access)^, +**
  • ^([foreign key constraints | Foreign key constraints] are enabled, +** column zColumn is part of a [child key] definition and the blob is +** being opened for read/write access)^. +**
+** +** ^Unless it returns SQLITE_MISUSE, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** +** A BLOB referenced by sqlite3_blob_open() may be read using the +** [sqlite3_blob_read()] interface and modified by using +** [sqlite3_blob_write()]. The [BLOB handle] can be moved to a +** different row of the same table using the [sqlite3_blob_reopen()] +** interface. However, the column, table, or database of a [BLOB handle] +** cannot be changed after the [BLOB handle] is opened. +** +** ^(If the row that a BLOB handle points to is modified by an +** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects +** then the BLOB handle is marked as "expired". +** This is true if any column of the row is changed, even a column +** other than the one the BLOB handle is open on.)^ +** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for +** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. +** ^(Changes written into a BLOB prior to the BLOB expiring are not +** rolled back by the expiration of the BLOB. Such changes will eventually +** commit if the transaction continues to completion.)^ +** +** ^Use the [sqlite3_blob_bytes()] interface to determine the size of +** the opened blob. ^The size of a blob may not be changed by this +** interface. Use the [UPDATE] SQL command to change the size of a +** blob. +** +** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces +** and the built-in [zeroblob] SQL function may be used to create a +** zero-filled blob to read or write using the incremental-blob interface. +** +** To avoid a resource leak, every open [BLOB handle] should eventually +** be released by a call to [sqlite3_blob_close()]. +** +** See also: [sqlite3_blob_close()], +** [sqlite3_blob_reopen()], [sqlite3_blob_read()], +** [sqlite3_blob_bytes()], [sqlite3_blob_write()]. +*/ +SQLITE_API int sqlite3_blob_open( + sqlite3*, + const char *zDb, + const char *zTable, + const char *zColumn, + sqlite3_int64 iRow, + int flags, + sqlite3_blob **ppBlob +); + +/* +** CAPI3REF: Move a BLOB Handle to a New Row +** METHOD: sqlite3_blob +** +** ^This function is used to move an existing [BLOB handle] so that it points +** to a different row of the same database table. ^The new row is identified +** by the rowid value passed as the second argument. Only the row can be +** changed. ^The database, table and column on which the blob handle is open +** remain the same. Moving an existing [BLOB handle] to a new row is +** faster than closing the existing handle and opening a new one. +** +** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] - +** it must exist and there must be either a blob or text value stored in +** the nominated column.)^ ^If the new row is not present in the table, or if +** it does not contain a blob or text value, or if another error occurs, an +** SQLite error code is returned and the blob handle is considered aborted. +** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or +** [sqlite3_blob_reopen()] on an aborted blob handle immediately return +** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle +** always returns zero. +** +** ^This function sets the database handle error code and message. +*/ +SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); + +/* +** CAPI3REF: Close A BLOB Handle +** DESTRUCTOR: sqlite3_blob +** +** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed +** unconditionally. Even if this routine returns an error code, the +** handle is still closed.)^ +** +** ^If the blob handle being closed was opened for read-write access, and if +** the database is in auto-commit mode and there are no other open read-write +** blob handles or active write statements, the current transaction is +** committed. ^If an error occurs while committing the transaction, an error +** code is returned and the transaction rolled back. +** +** Calling this function with an argument that is not a NULL pointer or an +** open blob handle results in undefined behaviour. ^Calling this routine +** with a null pointer (such as would be returned by a failed call to +** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function +** is passed a valid open blob handle, the values returned by the +** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. +*/ +SQLITE_API int sqlite3_blob_close(sqlite3_blob *); + +/* +** CAPI3REF: Return The Size Of An Open BLOB +** METHOD: sqlite3_blob +** +** ^Returns the size in bytes of the BLOB accessible via the +** successfully opened [BLOB handle] in its only argument. ^The +** incremental blob I/O routines can only read or overwriting existing +** blob content; they cannot change the size of a blob. +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +*/ +SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *); + +/* +** CAPI3REF: Read Data From A BLOB Incrementally +** METHOD: sqlite3_blob +** +** ^(This function is used to read data from an open [BLOB handle] into a +** caller-supplied buffer. N bytes of data are copied into buffer Z +** from the open BLOB, starting at offset iOffset.)^ +** +** ^If offset iOffset is less than N bytes from the end of the BLOB, +** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is +** less than zero, [SQLITE_ERROR] is returned and no data is read. +** ^The size of the blob (and hence the maximum value of N+iOffset) +** can be determined using the [sqlite3_blob_bytes()] interface. +** +** ^An attempt to read from an expired [BLOB handle] fails with an +** error code of [SQLITE_ABORT]. +** +** ^(On success, sqlite3_blob_read() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +** +** See also: [sqlite3_blob_write()]. +*/ +SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); + +/* +** CAPI3REF: Write Data Into A BLOB Incrementally +** METHOD: sqlite3_blob +** +** ^(This function is used to write data into an open [BLOB handle] from a +** caller-supplied buffer. N bytes of data are copied from the buffer Z +** into the open BLOB, starting at offset iOffset.)^ +** +** ^(On success, sqlite3_blob_write() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** ^Unless SQLITE_MISUSE is returned, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** +** ^If the [BLOB handle] passed as the first argument was not opened for +** writing (the flags parameter to [sqlite3_blob_open()] was zero), +** this function returns [SQLITE_READONLY]. +** +** This function may only modify the contents of the BLOB; it is +** not possible to increase the size of a BLOB using this API. +** ^If offset iOffset is less than N bytes from the end of the BLOB, +** [SQLITE_ERROR] is returned and no data is written. The size of the +** BLOB (and hence the maximum value of N+iOffset) can be determined +** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less +** than zero [SQLITE_ERROR] is returned and no data is written. +** +** ^An attempt to write to an expired [BLOB handle] fails with an +** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred +** before the [BLOB handle] expired are not rolled back by the +** expiration of the handle, though of course those changes might +** have been overwritten by the statement that expired the BLOB handle +** or by other independent statements. +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +** +** See also: [sqlite3_blob_read()]. +*/ +SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); + +/* +** CAPI3REF: Virtual File System Objects +** +** A virtual filesystem (VFS) is an [sqlite3_vfs] object +** that SQLite uses to interact +** with the underlying operating system. Most SQLite builds come with a +** single default VFS that is appropriate for the host computer. +** New VFSes can be registered and existing VFSes can be unregistered. +** The following interfaces are provided. +** +** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name. +** ^Names are case sensitive. +** ^Names are zero-terminated UTF-8 strings. +** ^If there is no match, a NULL pointer is returned. +** ^If zVfsName is NULL then the default VFS is returned. +** +** ^New VFSes are registered with sqlite3_vfs_register(). +** ^Each new VFS becomes the default VFS if the makeDflt flag is set. +** ^The same VFS can be registered multiple times without injury. +** ^To make an existing VFS into the default VFS, register it again +** with the makeDflt flag set. If two different VFSes with the +** same name are registered, the behavior is undefined. If a +** VFS is registered with a name that is NULL or an empty string, +** then the behavior is undefined. +** +** ^Unregister a VFS with the sqlite3_vfs_unregister() interface. +** ^(If the default VFS is unregistered, another VFS is chosen as +** the default. The choice for the new VFS is arbitrary.)^ +*/ +SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); +SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); +SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); + +/* +** CAPI3REF: Mutexes +** +** The SQLite core uses these routines for thread +** synchronization. Though they are intended for internal +** use by SQLite, code that links against SQLite is +** permitted to use any of these routines. +** +** The SQLite source code contains multiple implementations +** of these mutex routines. An appropriate implementation +** is selected automatically at compile-time. The following +** implementations are available in the SQLite core: +** +**
    +**
  • SQLITE_MUTEX_PTHREADS +**
  • SQLITE_MUTEX_W32 +**
  • SQLITE_MUTEX_NOOP +**
+** +** The SQLITE_MUTEX_NOOP implementation is a set of routines +** that does no real locking and is appropriate for use in +** a single-threaded application. The SQLITE_MUTEX_PTHREADS and +** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix +** and Windows. +** +** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor +** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex +** implementation is included with the library. In this case the +** application must supply a custom mutex implementation using the +** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function +** before calling sqlite3_initialize() or any other public sqlite3_ +** function that calls sqlite3_initialize(). +** +** ^The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() +** routine returns NULL if it is unable to allocate the requested +** mutex. The argument to sqlite3_mutex_alloc() must one of these +** integer constants: +** +**
    +**
  • SQLITE_MUTEX_FAST +**
  • SQLITE_MUTEX_RECURSIVE +**
  • SQLITE_MUTEX_STATIC_MASTER +**
  • SQLITE_MUTEX_STATIC_MEM +**
  • SQLITE_MUTEX_STATIC_OPEN +**
  • SQLITE_MUTEX_STATIC_PRNG +**
  • SQLITE_MUTEX_STATIC_LRU +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 +**
  • SQLITE_MUTEX_STATIC_VFS1 +**
  • SQLITE_MUTEX_STATIC_VFS2 +**
  • SQLITE_MUTEX_STATIC_VFS3 +**
+** +** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) +** cause sqlite3_mutex_alloc() to create +** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other +** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return +** a pointer to a static preexisting mutex. ^Nine static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. ^For the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +** +** ^The sqlite3_mutex_free() routine deallocates a previously +** allocated dynamic mutex. Attempting to deallocate a static +** mutex results in undefined behavior. +** +** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. ^If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] +** upon successful entry. ^(Mutexes created using +** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. +** In such cases, the +** mutex must be exited an equal number of times before another thread +** can enter.)^ If the same thread tries to enter any mutex other +** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. +** +** ^(Some systems (for example, Windows 95) do not support the operation +** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable +** behavior.)^ +** +** ^The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered by the +** calling thread or is not currently allocated. +** +** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or +** sqlite3_mutex_leave() is a NULL pointer, then all three routines +** behave as no-ops. +** +** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. +*/ +SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); +SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); +SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); +SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); +SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); + +/* +** CAPI3REF: Mutex Methods Object +** +** An instance of this structure defines the low-level routines +** used to allocate and use mutexes. +** +** Usually, the default mutex implementations provided by SQLite are +** sufficient, however the application has the option of substituting a custom +** implementation for specialized deployments or systems for which SQLite +** does not provide a suitable implementation. In this case, the application +** creates and populates an instance of this structure to pass +** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. +** Additionally, an instance of this structure can be used as an +** output variable when querying the system for the current mutex +** implementation, using the [SQLITE_CONFIG_GETMUTEX] option. +** +** ^The xMutexInit method defined by this structure is invoked as +** part of system initialization by the sqlite3_initialize() function. +** ^The xMutexInit routine is called by SQLite exactly once for each +** effective call to [sqlite3_initialize()]. +** +** ^The xMutexEnd method defined by this structure is invoked as +** part of system shutdown by the sqlite3_shutdown() function. The +** implementation of this method is expected to release all outstanding +** resources obtained by the mutex methods implementation, especially +** those obtained by the xMutexInit method. ^The xMutexEnd() +** interface is invoked exactly once for each call to [sqlite3_shutdown()]. +** +** ^(The remaining seven methods defined by this structure (xMutexAlloc, +** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and +** xMutexNotheld) implement the following interfaces (respectively): +** +**
    +**
  • [sqlite3_mutex_alloc()]
  • +**
  • [sqlite3_mutex_free()]
  • +**
  • [sqlite3_mutex_enter()]
  • +**
  • [sqlite3_mutex_try()]
  • +**
  • [sqlite3_mutex_leave()]
  • +**
  • [sqlite3_mutex_held()]
  • +**
  • [sqlite3_mutex_notheld()]
  • +**
)^ +** +** The only difference is that the public sqlite3_XXX functions enumerated +** above silently ignore any invocations that pass a NULL pointer instead +** of a valid mutex handle. The implementations of the methods defined +** by this structure are not required to handle this case, the results +** of passing a NULL pointer instead of a valid mutex handle are undefined +** (i.e. it is acceptable to provide an implementation that segfaults if +** it is passed a NULL pointer). +** +** The xMutexInit() method must be threadsafe. It must be harmless to +** invoke xMutexInit() multiple times within the same process and without +** intervening calls to xMutexEnd(). Second and subsequent calls to +** xMutexInit() must be no-ops. +** +** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] +** and its associates). Similarly, xMutexAlloc() must not use SQLite memory +** allocation for a static mutex. ^However xMutexAlloc() may use SQLite +** memory allocation for a fast or recursive mutex. +** +** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is +** called, but only if the prior call to xMutexInit returned SQLITE_OK. +** If xMutexInit fails in any way, it is expected to clean up after itself +** prior to returning. +*/ +typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; +struct sqlite3_mutex_methods { + int (*xMutexInit)(void); + int (*xMutexEnd)(void); + sqlite3_mutex *(*xMutexAlloc)(int); + void (*xMutexFree)(sqlite3_mutex *); + void (*xMutexEnter)(sqlite3_mutex *); + int (*xMutexTry)(sqlite3_mutex *); + void (*xMutexLeave)(sqlite3_mutex *); + int (*xMutexHeld)(sqlite3_mutex *); + int (*xMutexNotheld)(sqlite3_mutex *); +}; + +/* +** CAPI3REF: Mutex Verification Routines +** +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines +** are intended for use inside assert() statements. The SQLite core +** never uses these routines except inside an assert() and applications +** are advised to follow the lead of the core. The SQLite core only +** provides implementations for these routines when it is compiled +** with the SQLITE_DEBUG flag. External mutex implementations +** are only required to provide these routines if SQLITE_DEBUG is +** defined and if NDEBUG is not defined. +** +** These routines should return true if the mutex in their argument +** is held or not held, respectively, by the calling thread. +** +** The implementation is not required to provide versions of these +** routines that actually work. If the implementation does not provide working +** versions of these routines, it should at least provide stubs that always +** return true so that one does not get spurious assertion failures. +** +** If the argument to sqlite3_mutex_held() is a NULL pointer then +** the routine should return 1. This seems counter-intuitive since +** clearly the mutex cannot be held if it does not exist. But +** the reason the mutex does not exist is because the build is not +** using mutexes. And we do not want the assert() containing the +** call to sqlite3_mutex_held() to fail, so a non-zero return is +** the appropriate thing to do. The sqlite3_mutex_notheld() +** interface should also return 1 when given a NULL pointer. +*/ +#ifndef NDEBUG +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); +SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); +#endif + +/* +** CAPI3REF: Mutex Types +** +** The [sqlite3_mutex_alloc()] interface takes a single argument +** which is one of these integer constants. +** +** The set of static mutexes may change from one SQLite release to the +** next. Applications that override the built-in mutex logic must be +** prepared to accommodate additional static mutexes. +*/ +#define SQLITE_MUTEX_FAST 0 +#define SQLITE_MUTEX_RECURSIVE 1 +#define SQLITE_MUTEX_STATIC_MASTER 2 +#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ +#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ +#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */ +#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ +#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ +#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ +#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */ +#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ +#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ + +/* +** CAPI3REF: Retrieve the mutex for a database connection +** METHOD: sqlite3 +** +** ^This interface returns a pointer the [sqlite3_mutex] object that +** serializes access to the [database connection] given in the argument +** when the [threading mode] is Serialized. +** ^If the [threading mode] is Single-thread or Multi-thread then this +** routine returns a NULL pointer. +*/ +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); + +/* +** CAPI3REF: Low-Level Control Of Database Files +** METHOD: sqlite3 +** +** ^The [sqlite3_file_control()] interface makes a direct call to the +** xFileControl method for the [sqlite3_io_methods] object associated +** with a particular database identified by the second argument. ^The +** name of the database is "main" for the main database or "temp" for the +** TEMP database, or the name that appears after the AS keyword for +** databases that are added using the [ATTACH] SQL command. +** ^A NULL pointer can be used in place of "main" to refer to the +** main database file. +** ^The third and fourth parameters to this routine +** are passed directly through to the second and third parameters of +** the xFileControl method. ^The return value of the xFileControl +** method becomes the return value of this routine. +** +** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes +** a pointer to the underlying [sqlite3_file] object to be written into +** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER +** case is a short-circuit path which does not actually invoke the +** underlying sqlite3_io_methods.xFileControl method. +** +** ^If the second parameter (zDbName) does not match the name of any +** open database file, then SQLITE_ERROR is returned. ^This error +** code is not remembered and will not be recalled by [sqlite3_errcode()] +** or [sqlite3_errmsg()]. The underlying xFileControl method might +** also return SQLITE_ERROR. There is no way to distinguish between +** an incorrect zDbName and an SQLITE_ERROR return from the underlying +** xFileControl method. +** +** See also: [SQLITE_FCNTL_LOCKSTATE] +*/ +SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); + +/* +** CAPI3REF: Testing Interface +** +** ^The sqlite3_test_control() interface is used to read out internal +** state of SQLite and to inject faults into SQLite for testing +** purposes. ^The first parameter is an operation code that determines +** the number, meaning, and operation of all subsequent parameters. +** +** This interface is not for use by applications. It exists solely +** for verifying the correct operation of the SQLite library. Depending +** on how the SQLite library is compiled, this interface might not exist. +** +** The details of the operation codes, their meanings, the parameters +** they take, and what they do are all subject to change without notice. +** Unlike most of the SQLite API, this function is not guaranteed to +** operate consistently from one release to the next. +*/ +SQLITE_API int sqlite3_test_control(int op, ...); + +/* +** CAPI3REF: Testing Interface Operation Codes +** +** These constants are the valid operation code parameters used +** as the first argument to [sqlite3_test_control()]. +** +** These parameters and their meanings are subject to change +** without notice. These values are for testing purposes only. +** Applications should not use any of these parameters or the +** [sqlite3_test_control()] interface. +*/ +#define SQLITE_TESTCTRL_FIRST 5 +#define SQLITE_TESTCTRL_PRNG_SAVE 5 +#define SQLITE_TESTCTRL_PRNG_RESTORE 6 +#define SQLITE_TESTCTRL_PRNG_RESET 7 +#define SQLITE_TESTCTRL_BITVEC_TEST 8 +#define SQLITE_TESTCTRL_FAULT_INSTALL 9 +#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 +#define SQLITE_TESTCTRL_PENDING_BYTE 11 +#define SQLITE_TESTCTRL_ASSERT 12 +#define SQLITE_TESTCTRL_ALWAYS 13 +#define SQLITE_TESTCTRL_RESERVE 14 +#define SQLITE_TESTCTRL_OPTIMIZATIONS 15 +#define SQLITE_TESTCTRL_ISKEYWORD 16 +#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 +#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 +#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ +#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 +#define SQLITE_TESTCTRL_NEVER_CORRUPT 20 +#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 +#define SQLITE_TESTCTRL_BYTEORDER 22 +#define SQLITE_TESTCTRL_ISINIT 23 +#define SQLITE_TESTCTRL_SORTER_MMAP 24 +#define SQLITE_TESTCTRL_IMPOSTER 25 +#define SQLITE_TESTCTRL_LAST 25 + +/* +** CAPI3REF: SQLite Runtime Status +** +** ^These interfaces are used to retrieve runtime status information +** about the performance of SQLite, and optionally to reset various +** highwater marks. ^The first argument is an integer code for +** the specific parameter to measure. ^(Recognized integer codes +** are of the form [status parameters | SQLITE_STATUS_...].)^ +** ^The current value of the parameter is returned into *pCurrent. +** ^The highest recorded value is returned in *pHighwater. ^If the +** resetFlag is true, then the highest record value is reset after +** *pHighwater is written. ^(Some parameters do not record the highest +** value. For those parameters +** nothing is written into *pHighwater and the resetFlag is ignored.)^ +** ^(Other parameters record only the highwater mark and not the current +** value. For these latter parameters nothing is written into *pCurrent.)^ +** +** ^The sqlite3_status() and sqlite3_status64() routines return +** SQLITE_OK on success and a non-zero [error code] on failure. +** +** If either the current value or the highwater mark is too large to +** be represented by a 32-bit integer, then the values returned by +** sqlite3_status() are undefined. +** +** See also: [sqlite3_db_status()] +*/ +SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); +SQLITE_API int sqlite3_status64( + int op, + sqlite3_int64 *pCurrent, + sqlite3_int64 *pHighwater, + int resetFlag +); + + +/* +** CAPI3REF: Status Parameters +** KEYWORDS: {status parameters} +** +** These integer constants designate various run-time status parameters +** that can be returned by [sqlite3_status()]. +** +**
+** [[SQLITE_STATUS_MEMORY_USED]] ^(
SQLITE_STATUS_MEMORY_USED
+**
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 +** 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].
)^ +** +** [[SQLITE_STATUS_MALLOC_SIZE]] ^(
SQLITE_STATUS_MALLOC_SIZE
+**
This parameter records the largest memory allocation request +** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their +** internal equivalents). Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. +** The value written into the *pCurrent parameter is undefined.
)^ +** +** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
SQLITE_STATUS_MALLOC_COUNT
+**
This parameter records the number of separate memory allocations +** currently checked out.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
SQLITE_STATUS_PAGECACHE_USED
+**
This parameter returns the number of pages used out of the +** [pagecache memory allocator] that was configured using +** [SQLITE_CONFIG_PAGECACHE]. The +** value returned is in pages, not in bytes.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] +** ^(
SQLITE_STATUS_PAGECACHE_OVERFLOW
+**
This parameter returns the number of bytes of page cache +** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] +** buffer and where forced to overflow to [sqlite3_malloc()]. The +** returned value includes allocations that overflowed because they +** where too large (they were larger than the "sz" parameter to +** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because +** no space was left in the page cache.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
SQLITE_STATUS_PAGECACHE_SIZE
+**
This parameter records the largest memory allocation request +** handed to [pagecache 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.
)^ +** +** [[SQLITE_STATUS_SCRATCH_USED]] ^(
SQLITE_STATUS_SCRATCH_USED
+**
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.
)^ +** +** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
SQLITE_STATUS_SCRATCH_OVERFLOW
+**
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. +**
)^ +** +** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
SQLITE_STATUS_SCRATCH_SIZE
+**
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.
)^ +** +** [[SQLITE_STATUS_PARSER_STACK]] ^(
SQLITE_STATUS_PARSER_STACK
+**
The *pHighwater parameter records the deepest parser stack. +** The *pCurrent value is undefined. The *pHighwater value is only +** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
)^ +**
+** +** New status parameters may be added from time to time. +*/ +#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_MALLOC_SIZE 5 +#define SQLITE_STATUS_PARSER_STACK 6 +#define SQLITE_STATUS_PAGECACHE_SIZE 7 +#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_MALLOC_COUNT 9 + +/* +** CAPI3REF: Database Connection Status +** METHOD: sqlite3 +** +** ^This interface is used to retrieve runtime status information +** about a single [database connection]. ^The first argument is the +** database connection object to be interrogated. ^The second argument +** is an integer constant, taken from the set of +** [SQLITE_DBSTATUS options], that +** determines the parameter to interrogate. The set of +** [SQLITE_DBSTATUS options] is likely +** to grow in future releases of SQLite. +** +** ^The current value of the requested parameter is written into *pCur +** and the highest instantaneous value is written into *pHiwtr. ^If +** the resetFlg is true, then the highest instantaneous value is +** reset back down to the current value. +** +** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a +** non-zero [error code] on failure. +** +** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. +*/ +SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); + +/* +** CAPI3REF: Status Parameters for database connections +** KEYWORDS: {SQLITE_DBSTATUS options} +** +** These constants are the available integer "verbs" that can be passed as +** the second argument to the [sqlite3_db_status()] interface. +** +** New verbs may be added in future releases of SQLite. Existing verbs +** might be discontinued. Applications should check the return code from +** [sqlite3_db_status()] to make sure that the call worked. +** The [sqlite3_db_status()] interface will return a non-zero error code +** if a discontinued or unsupported verb is invoked. +** +**
+** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(
SQLITE_DBSTATUS_LOOKASIDE_USED
+**
This parameter returns the number of lookaside memory slots currently +** checked out.
)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
SQLITE_DBSTATUS_LOOKASIDE_HIT
+**
This parameter returns the number malloc attempts that were +** satisfied using lookaside memory. Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] +** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
+**
This parameter returns the number malloc attempts that might have +** been satisfied using lookaside memory but failed due to the amount of +** memory requested being larger than the lookaside slot size. +** Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] +** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
+**
This parameter returns the number malloc attempts that might have +** been satisfied using lookaside memory but failed due to all lookaside +** memory already being in use. +** Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
SQLITE_DBSTATUS_CACHE_USED
+**
This parameter returns the approximate number of bytes of heap +** memory used by all pager caches associated with the database connection.)^ +** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. +** +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** ^(
SQLITE_DBSTATUS_CACHE_USED_SHARED
+**
This parameter is similar to DBSTATUS_CACHE_USED, except that if a +** pager cache is shared between two or more connections the bytes of heap +** memory used by that pager cache is divided evenly between the attached +** connections.)^ In other words, if none of the pager caches associated +** with the database connection are shared, this request returns the same +** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** shared, the value returned by this call will be smaller than that returned +** by DBSTATUS_CACHE_USED. ^The highwater mark associated with +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** +** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
SQLITE_DBSTATUS_SCHEMA_USED
+**
This parameter returns the approximate number of bytes of heap +** memory used to store the schema for all databases associated +** with the connection - main, temp, and any [ATTACH]-ed databases.)^ +** ^The full amount of memory used by the schemas is reported, even if the +** schema memory is shared with other database connections due to +** [shared cache mode] being enabled. +** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. +** +** [[SQLITE_DBSTATUS_STMT_USED]] ^(
SQLITE_DBSTATUS_STMT_USED
+**
This parameter returns the approximate number of bytes of heap +** and lookaside memory used by all prepared statements associated with +** the database connection.)^ +** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. +**
+** +** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(
SQLITE_DBSTATUS_CACHE_HIT
+**
This parameter returns the number of pager cache hits that have +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT +** is always 0. +**
+** +** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(
SQLITE_DBSTATUS_CACHE_MISS
+**
This parameter returns the number of pager cache misses that have +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS +** is always 0. +**
+** +** [[SQLITE_DBSTATUS_CACHE_WRITE]] ^(
SQLITE_DBSTATUS_CACHE_WRITE
+**
This parameter returns the number of dirty cache entries that have +** been written to disk. Specifically, the number of pages written to the +** wal file in wal mode databases, or the number of pages written to the +** database file in rollback mode databases. Any pages written as part of +** transaction rollback or database recovery operations are not included. +** If an IO or other error occurs while writing a page to disk, the effect +** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The +** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. +**
+** +** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(
SQLITE_DBSTATUS_DEFERRED_FKS
+**
This parameter returns zero for the current value if and only if +** all foreign key constraints (deferred or immediate) have been +** resolved.)^ ^The highwater mark is always 0. +**
+**
+*/ +#define SQLITE_DBSTATUS_LOOKASIDE_USED 0 +#define SQLITE_DBSTATUS_CACHE_USED 1 +#define SQLITE_DBSTATUS_SCHEMA_USED 2 +#define SQLITE_DBSTATUS_STMT_USED 3 +#define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 +#define SQLITE_DBSTATUS_CACHE_HIT 7 +#define SQLITE_DBSTATUS_CACHE_MISS 8 +#define SQLITE_DBSTATUS_CACHE_WRITE 9 +#define SQLITE_DBSTATUS_DEFERRED_FKS 10 +#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 +#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ + + +/* +** CAPI3REF: Prepared Statement Status +** METHOD: sqlite3_stmt +** +** ^(Each prepared statement maintains various +** [SQLITE_STMTSTATUS counters] that measure the number +** of times it has performed specific operations.)^ These counters can +** be used to monitor the performance characteristics of the prepared +** statements. For example, if the number of table steps greatly exceeds +** the number of table searches or result rows, that would tend to indicate +** that the prepared statement is using a full table scan rather than +** an index. +** +** ^(This interface is used to retrieve and reset counter values from +** a [prepared statement]. The first argument is the prepared statement +** object to be interrogated. The second argument +** is an integer code for a specific [SQLITE_STMTSTATUS counter] +** to be interrogated.)^ +** ^The current value of the requested counter is returned. +** ^If the resetFlg is true, then the counter is reset to zero after this +** interface call returns. +** +** See also: [sqlite3_status()] and [sqlite3_db_status()]. +*/ +SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); + +/* +** CAPI3REF: Status Parameters for prepared statements +** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} +** +** These preprocessor macros define integer codes that name counter +** values associated with the [sqlite3_stmt_status()] interface. +** The meanings of the various counters are as follows: +** +**
+** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
SQLITE_STMTSTATUS_FULLSCAN_STEP
+**
^This is the number of times that SQLite has stepped forward in +** a table as part of a full table scan. Large numbers for this counter +** may indicate opportunities for performance improvement through +** careful use of indices.
+** +** [[SQLITE_STMTSTATUS_SORT]]
SQLITE_STMTSTATUS_SORT
+**
^This is the number of sort operations that have occurred. +** A non-zero value in this counter may indicate an opportunity to +** improvement performance through careful use of indices.
+** +** [[SQLITE_STMTSTATUS_AUTOINDEX]]
SQLITE_STMTSTATUS_AUTOINDEX
+**
^This is the number of rows inserted into transient indices that +** were created automatically in order to help joins run faster. +** A non-zero value in this counter may indicate an opportunity to +** improvement performance by adding permanent indices that do not +** need to be reinitialized each time the statement is run.
+** +** [[SQLITE_STMTSTATUS_VM_STEP]]
SQLITE_STMTSTATUS_VM_STEP
+**
^This is the number of virtual machine operations executed +** by the prepared statement if that number is less than or equal +** to 2147483647. The number of virtual machine operations can be +** used as a proxy for the total work done by the prepared statement. +** If the number of virtual machine operations exceeds 2147483647 +** then the value returned by this statement status code is undefined. +**
+**
+*/ +#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 +#define SQLITE_STMTSTATUS_SORT 2 +#define SQLITE_STMTSTATUS_AUTOINDEX 3 +#define SQLITE_STMTSTATUS_VM_STEP 4 + +/* +** CAPI3REF: Custom Page Cache Object +** +** The sqlite3_pcache type is opaque. It is implemented by +** the pluggable module. The SQLite core has no knowledge of +** its size or internal structure and never deals with the +** sqlite3_pcache object except by holding and passing pointers +** to the object. +** +** See [sqlite3_pcache_methods2] for additional information. +*/ +typedef struct sqlite3_pcache sqlite3_pcache; + +/* +** CAPI3REF: Custom Page Cache Object +** +** The sqlite3_pcache_page object represents a single page in the +** page cache. The page cache will allocate instances of this +** object. Various methods of the page cache use pointers to instances +** of this object as parameters or as their return value. +** +** See [sqlite3_pcache_methods2] for additional information. +*/ +typedef struct sqlite3_pcache_page sqlite3_pcache_page; +struct sqlite3_pcache_page { + void *pBuf; /* The content of the page */ + void *pExtra; /* Extra information associated with the page */ +}; + +/* +** CAPI3REF: Application Defined Page Cache. +** KEYWORDS: {page cache} +** +** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can +** register an alternative page cache implementation by passing in an +** instance of the sqlite3_pcache_methods2 structure.)^ +** In many applications, most of the heap memory allocated by +** SQLite is used for the page cache. +** By implementing a +** custom page cache using this API, an application can better control +** the amount of memory consumed by SQLite, the way in which +** that memory is allocated and released, and the policies used to +** determine exactly which parts of a database file are cached and for +** how long. +** +** The alternative page cache mechanism is an +** extreme measure that is only needed by the most demanding applications. +** The built-in page cache is recommended for most uses. +** +** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an +** internal buffer by SQLite within the call to [sqlite3_config]. Hence +** the application may discard the parameter after the call to +** [sqlite3_config()] returns.)^ +** +** [[the xInit() page cache method]] +** ^(The xInit() method is called once for each effective +** call to [sqlite3_initialize()])^ +** (usually only once during the lifetime of the process). ^(The xInit() +** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^ +** The intent of the xInit() method is to set up global data structures +** required by the custom page cache implementation. +** ^(If the xInit() method is NULL, then the +** built-in default page cache is used instead of the application defined +** page cache.)^ +** +** [[the xShutdown() page cache method]] +** ^The xShutdown() method is called by [sqlite3_shutdown()]. +** It can be used to clean up +** any outstanding resources before process shutdown, if required. +** ^The xShutdown() method may be NULL. +** +** ^SQLite automatically serializes calls to the xInit method, +** so the xInit method need not be threadsafe. ^The +** xShutdown method is only called from [sqlite3_shutdown()] so it does +** not need to be threadsafe either. All other methods must be threadsafe +** in multithreaded applications. +** +** ^SQLite will never invoke xInit() more than once without an intervening +** call to xShutdown(). +** +** [[the xCreate() page cache methods]] +** ^SQLite invokes the xCreate() method to construct a new cache instance. +** SQLite will typically create one cache instance for each open database file, +** though this is not guaranteed. ^The +** first parameter, szPage, is the size in bytes of the pages that must +** be allocated by the cache. ^szPage will always a power of two. ^The +** second parameter szExtra is a number of bytes of extra storage +** associated with each page cache entry. ^The szExtra parameter will +** a number less than 250. SQLite will use the +** extra szExtra bytes on each page to store metadata about the underlying +** database page on disk. The value passed into szExtra depends +** on the SQLite version, the target platform, and how SQLite was compiled. +** ^The third argument to xCreate(), bPurgeable, is true if the cache being +** created will be used to cache database pages of a file stored on disk, or +** false if it is used for an in-memory database. The cache implementation +** does not have to do anything special based with the value of bPurgeable; +** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will +** never invoke xUnpin() except to deliberately delete a page. +** ^In other words, calls to xUnpin() on a cache with bPurgeable set to +** false will always have the "discard" flag set to true. +** ^Hence, a cache created with bPurgeable false will +** never contain any unpinned pages. +** +** [[the xCachesize() page cache method]] +** ^(The xCachesize() method may be called at any time by SQLite to set the +** suggested maximum cache-size (number of pages stored by) the cache +** instance passed as the first argument. This is the value configured using +** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable +** parameter, the implementation is not required to do anything with this +** value; it is advisory only. +** +** [[the xPagecount() page cache methods]] +** The xPagecount() method must return the number of pages currently +** stored in the cache, both pinned and unpinned. +** +** [[the xFetch() page cache methods]] +** The xFetch() method locates a page in the cache and returns a pointer to +** an sqlite3_pcache_page object associated with that page, or a NULL pointer. +** The pBuf element of the returned sqlite3_pcache_page object will be a +** pointer to a buffer of szPage bytes used to store the content of a +** single database page. The pExtra element of sqlite3_pcache_page will be +** a pointer to the szExtra bytes of extra storage that SQLite has requested +** for each entry in the page cache. +** +** The page to be fetched is determined by the key. ^The minimum key value +** is 1. After it has been retrieved using xFetch, the page is considered +** to be "pinned". +** +** If the requested page is already in the page cache, then the page cache +** implementation must return a pointer to the page buffer with its content +** intact. If the requested page is not already in the cache, then the +** cache implementation should use the value of the createFlag +** parameter to help it determined what action to take: +** +** +**
createFlag Behavior when page is not already in cache +**
0 Do not allocate a new page. Return NULL. +**
1 Allocate a new page if it easy and convenient to do so. +** Otherwise return NULL. +**
2 Make every effort to allocate a new page. Only return +** NULL if allocating a new page is effectively impossible. +**
+** +** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite +** will only use a createFlag of 2 after a prior call with a createFlag of 1 +** failed.)^ In between the to xFetch() calls, SQLite may +** attempt to unpin one or more cache pages by spilling the content of +** pinned pages to disk and synching the operating system disk cache. +** +** [[the xUnpin() page cache method]] +** ^xUnpin() is called by SQLite with a pointer to a currently pinned page +** as its second argument. If the third parameter, discard, is non-zero, +** then the page must be evicted from the cache. +** ^If the discard parameter is +** zero, then the page may be discarded or retained at the discretion of +** page cache implementation. ^The page cache implementation +** may choose to evict unpinned pages at any time. +** +** The cache must not perform any reference counting. A single +** call to xUnpin() unpins the page regardless of the number of prior calls +** to xFetch(). +** +** [[the xRekey() page cache methods]] +** The xRekey() method is used to change the key value associated with the +** page passed as the second argument. If the cache +** previously contains an entry associated with newKey, it must be +** discarded. ^Any prior cache entry associated with newKey is guaranteed not +** to be pinned. +** +** When SQLite calls the xTruncate() method, the cache must discard all +** existing cache entries with page numbers (keys) greater than or equal +** to the value of the iLimit parameter passed to xTruncate(). If any +** of these pages are pinned, they are implicitly unpinned, meaning that +** they can be safely discarded. +** +** [[the xDestroy() page cache method]] +** ^The xDestroy() method is used to delete a cache allocated by xCreate(). +** All resources associated with the specified cache should be freed. ^After +** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] +** handle invalid, and will not use it with any other sqlite3_pcache_methods2 +** functions. +** +** [[the xShrink() page cache method]] +** ^SQLite invokes the xShrink() method when it wants the page cache to +** free up as much of heap memory as possible. The page cache implementation +** is not obligated to free any memory, but well-behaved implementations should +** do their best. +*/ +typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; +struct sqlite3_pcache_methods2 { + int iVersion; + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, + unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); + void (*xShrink)(sqlite3_pcache*); +}; + +/* +** This is the obsolete pcache_methods object that has now been replaced +** by sqlite3_pcache_methods2. This object is not used by SQLite. It is +** retained in the header file for backwards compatibility only. +*/ +typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; +struct sqlite3_pcache_methods { + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, void*, int discard); + void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); +}; + + +/* +** CAPI3REF: Online Backup Object +** +** The sqlite3_backup object records state information about an ongoing +** online backup operation. ^The sqlite3_backup object is created by +** a call to [sqlite3_backup_init()] and is destroyed by a call to +** [sqlite3_backup_finish()]. +** +** See Also: [Using the SQLite Online Backup API] +*/ +typedef struct sqlite3_backup sqlite3_backup; + +/* +** CAPI3REF: Online Backup API. +** +** The backup API copies the content of one database into another. +** It is useful either for creating backups of databases or +** for copying in-memory databases to or from persistent files. +** +** See Also: [Using the SQLite Online Backup API] +** +** ^SQLite holds a write transaction open on the destination database file +** for the duration of the backup operation. +** ^The source database is read-locked only while it is being read; +** it is not locked continuously for the entire backup operation. +** ^Thus, the backup may be performed on a live source database without +** preventing other database connections from +** reading or writing to the source database while the backup is underway. +** +** ^(To perform a backup operation: +**
    +**
  1. sqlite3_backup_init() is called once to initialize the +** backup, +**
  2. sqlite3_backup_step() is called one or more times to transfer +** the data between the two databases, and finally +**
  3. sqlite3_backup_finish() is called to release all resources +** associated with the backup operation. +**
)^ +** There should be exactly one call to sqlite3_backup_finish() for each +** successful call to sqlite3_backup_init(). +** +** [[sqlite3_backup_init()]] sqlite3_backup_init() +** +** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the +** [database connection] associated with the destination database +** and the database name, respectively. +** ^The database name is "main" for the main database, "temp" for the +** temporary database, or the name specified after the AS keyword in +** an [ATTACH] statement for an attached database. +** ^The S and M arguments passed to +** sqlite3_backup_init(D,N,S,M) identify the [database connection] +** and database name of the source database, respectively. +** ^The source and destination [database connections] (parameters S and D) +** must be different or else sqlite3_backup_init(D,N,S,M) will fail with +** an error. +** +** ^A call to sqlite3_backup_init() will fail, returning NULL, if +** there is already a read or read-write transaction open on the +** destination database. +** +** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is +** returned and an error code and error message are stored in the +** destination [database connection] D. +** ^The error code and message for the failed call to sqlite3_backup_init() +** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or +** [sqlite3_errmsg16()] functions. +** ^A successful call to sqlite3_backup_init() returns a pointer to an +** [sqlite3_backup] object. +** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and +** sqlite3_backup_finish() functions to perform the specified backup +** operation. +** +** [[sqlite3_backup_step()]] sqlite3_backup_step() +** +** ^Function sqlite3_backup_step(B,N) will copy up to N pages between +** the source and destination databases specified by [sqlite3_backup] object B. +** ^If N is negative, all remaining source pages are copied. +** ^If sqlite3_backup_step(B,N) successfully copies N pages and there +** are still more pages to be copied, then the function returns [SQLITE_OK]. +** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages +** from source to destination, then it returns [SQLITE_DONE]. +** ^If an error occurs while running sqlite3_backup_step(B,N), +** then an [error code] is returned. ^As well as [SQLITE_OK] and +** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], +** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an +** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. +** +** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if +**
    +**
  1. the destination database was opened read-only, or +**
  2. the destination database is using write-ahead-log journaling +** and the destination and source page sizes differ, or +**
  3. the destination database is an in-memory database and the +** destination and source page sizes differ. +**
)^ +** +** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then +** the [sqlite3_busy_handler | busy-handler function] +** is invoked (if one is specified). ^If the +** busy-handler returns non-zero before the lock is available, then +** [SQLITE_BUSY] is returned to the caller. ^In this case the call to +** sqlite3_backup_step() can be retried later. ^If the source +** [database connection] +** is being used to write to the source database when sqlite3_backup_step() +** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this +** case the call to sqlite3_backup_step() can be retried later on. ^(If +** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or +** [SQLITE_READONLY] is returned, then +** there is no point in retrying the call to sqlite3_backup_step(). These +** errors are considered fatal.)^ The application must accept +** that the backup operation has failed and pass the backup operation handle +** to the sqlite3_backup_finish() to release associated resources. +** +** ^The first call to sqlite3_backup_step() obtains an exclusive lock +** on the destination file. ^The exclusive lock is not released until either +** sqlite3_backup_finish() is called or the backup operation is complete +** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to +** sqlite3_backup_step() obtains a [shared lock] on the source database that +** lasts for the duration of the sqlite3_backup_step() call. +** ^Because the source database is not locked between calls to +** sqlite3_backup_step(), the source database may be modified mid-way +** through the backup process. ^If the source database is modified by an +** external process or via a database connection other than the one being +** used by the backup operation, then the backup will be automatically +** restarted by the next call to sqlite3_backup_step(). ^If the source +** database is modified by the using the same database connection as is used +** by the backup operation, then the backup database is automatically +** updated at the same time. +** +** [[sqlite3_backup_finish()]] sqlite3_backup_finish() +** +** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the +** application wishes to abandon the backup operation, the application +** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). +** ^The sqlite3_backup_finish() interfaces releases all +** resources associated with the [sqlite3_backup] object. +** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any +** active write-transaction on the destination database is rolled back. +** The [sqlite3_backup] object is invalid +** and may not be used following a call to sqlite3_backup_finish(). +** +** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no +** sqlite3_backup_step() errors occurred, regardless or whether or not +** sqlite3_backup_step() completed. +** ^If an out-of-memory condition or IO error occurred during any prior +** sqlite3_backup_step() call on the same [sqlite3_backup] object, then +** sqlite3_backup_finish() returns the corresponding [error code]. +** +** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() +** is not a permanent error and does not affect the return value of +** sqlite3_backup_finish(). +** +** [[sqlite3_backup_remaining()]] [[sqlite3_backup_pagecount()]] +** sqlite3_backup_remaining() and sqlite3_backup_pagecount() +** +** ^The sqlite3_backup_remaining() routine returns the number of pages still +** to be backed up at the conclusion of the most recent sqlite3_backup_step(). +** ^The sqlite3_backup_pagecount() routine returns the total number of pages +** in the source database at the conclusion of the most recent +** sqlite3_backup_step(). +** ^(The values returned by these functions are only updated by +** sqlite3_backup_step(). If the source database is modified in a way that +** changes the size of the source database or the number of pages remaining, +** those changes are not reflected in the output of sqlite3_backup_pagecount() +** and sqlite3_backup_remaining() until after the next +** sqlite3_backup_step().)^ +** +** Concurrent Usage of Database Handles +** +** ^The source [database connection] may be used by the application for other +** purposes while a backup operation is underway or being initialized. +** ^If SQLite is compiled and configured to support threadsafe database +** connections, then the source database connection may be used concurrently +** from within other threads. +** +** However, the application must guarantee that the destination +** [database connection] is not passed to any other API (by any thread) after +** sqlite3_backup_init() is called and before the corresponding call to +** sqlite3_backup_finish(). SQLite does not currently check to see +** if the application incorrectly accesses the destination [database connection] +** and so no error code is reported, but the operations may malfunction +** nevertheless. Use of the destination database connection while a +** backup is in progress might also also cause a mutex deadlock. +** +** If running in [shared cache mode], the application must +** guarantee that the shared cache used by the destination database +** is not accessed while the backup is running. In practice this means +** that the application must guarantee that the disk file being +** backed up to is not accessed by any connection within the process, +** not just the specific connection that was passed to sqlite3_backup_init(). +** +** The [sqlite3_backup] object itself is partially threadsafe. Multiple +** threads may safely make multiple concurrent calls to sqlite3_backup_step(). +** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() +** APIs are not strictly speaking threadsafe. If they are invoked at the +** same time as another thread is invoking sqlite3_backup_step() it is +** possible that they return invalid values. +*/ +SQLITE_API sqlite3_backup *sqlite3_backup_init( + sqlite3 *pDest, /* Destination database handle */ + const char *zDestName, /* Destination database name */ + sqlite3 *pSource, /* Source database handle */ + const char *zSourceName /* Source database name */ +); +SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); +SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); + +/* +** CAPI3REF: Unlock Notification +** METHOD: sqlite3 +** +** ^When running in shared-cache mode, a database operation may fail with +** an [SQLITE_LOCKED] error if the required locks on the shared-cache or +** individual tables within the shared-cache cannot be obtained. See +** [SQLite Shared-Cache Mode] for a description of shared-cache locking. +** ^This API may be used to register a callback that SQLite will invoke +** when the connection currently holding the required lock relinquishes it. +** ^This API is only available if the library was compiled with the +** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. +** +** See Also: [Using the SQLite Unlock Notification Feature]. +** +** ^Shared-cache locks are released when a database connection concludes +** its current transaction, either by committing it or rolling it back. +** +** ^When a connection (known as the blocked connection) fails to obtain a +** shared-cache lock and SQLITE_LOCKED is returned to the caller, the +** identity of the database connection (the blocking connection) that +** has locked the required resource is stored internally. ^After an +** application receives an SQLITE_LOCKED error, it may call the +** sqlite3_unlock_notify() method with the blocked connection handle as +** the first argument to register for a callback that will be invoked +** when the blocking connections current transaction is concluded. ^The +** callback is invoked from within the [sqlite3_step] or [sqlite3_close] +** call that concludes the blocking connections transaction. +** +** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, +** there is a chance that the blocking connection will have already +** concluded its transaction by the time sqlite3_unlock_notify() is invoked. +** If this happens, then the specified callback is invoked immediately, +** from within the call to sqlite3_unlock_notify().)^ +** +** ^If the blocked connection is attempting to obtain a write-lock on a +** shared-cache table, and more than one other connection currently holds +** a read-lock on the same table, then SQLite arbitrarily selects one of +** the other connections to use as the blocking connection. +** +** ^(There may be at most one unlock-notify callback registered by a +** blocked connection. If sqlite3_unlock_notify() is called when the +** blocked connection already has a registered unlock-notify callback, +** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is +** called with a NULL pointer as its second argument, then any existing +** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback may also be canceled by closing the blocked +** connection using [sqlite3_close()]. +** +** The unlock-notify callback is not reentrant. If an application invokes +** any sqlite3_xxx API functions from within an unlock-notify callback, a +** crash or deadlock may be the result. +** +** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always +** returns SQLITE_OK. +** +** Callback Invocation Details +** +** When an unlock-notify callback is registered, the application provides a +** single void* pointer that is passed to the callback when it is invoked. +** However, the signature of the callback function allows SQLite to pass +** it an array of void* context pointers. The first argument passed to +** an unlock-notify callback is a pointer to an array of void* pointers, +** and the second is the number of entries in the array. +** +** When a blocking connections transaction is concluded, there may be +** more than one blocked connection that has registered for an unlock-notify +** callback. ^If two or more such blocked connections have specified the +** same callback function, then instead of invoking the callback function +** multiple times, it is invoked once with the set of void* context pointers +** specified by the blocked connections bundled together into an array. +** This gives the application an opportunity to prioritize any actions +** related to the set of unblocked database connections. +** +** Deadlock Detection +** +** Assuming that after registering for an unlock-notify callback a +** database waits for the callback to be issued before taking any further +** action (a reasonable assumption), then using this API may cause the +** application to deadlock. For example, if connection X is waiting for +** connection Y's transaction to be concluded, and similarly connection +** Y is waiting on connection X's transaction, then neither connection +** will proceed and the system may remain deadlocked indefinitely. +** +** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock +** detection. ^If a given call to sqlite3_unlock_notify() would put the +** system in a deadlocked state, then SQLITE_LOCKED is returned and no +** unlock-notify callback is registered. The system is said to be in +** a deadlocked state if connection A has registered for an unlock-notify +** callback on the conclusion of connection B's transaction, and connection +** B has itself registered for an unlock-notify callback when connection +** A's transaction is concluded. ^Indirect deadlock is also detected, so +** the system is also considered to be deadlocked if connection B has +** registered for an unlock-notify callback on the conclusion of connection +** C's transaction, where connection C is waiting on connection A. ^Any +** number of levels of indirection are allowed. +** +** The "DROP TABLE" Exception +** +** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost +** always appropriate to call sqlite3_unlock_notify(). There is however, +** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, +** SQLite checks if there are any currently executing SELECT statements +** that belong to the same connection. If there are, SQLITE_LOCKED is +** returned. In this case there is no "blocking connection", so invoking +** sqlite3_unlock_notify() results in the unlock-notify callback being +** invoked immediately. If the application then re-attempts the "DROP TABLE" +** or "DROP INDEX" query, an infinite loop might be the result. +** +** One way around this problem is to check the extended error code returned +** by an sqlite3_step() call. ^(If there is a blocking connection, then the +** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in +** the special "DROP TABLE/INDEX" case, the extended error code is just +** SQLITE_LOCKED.)^ +*/ +SQLITE_API int sqlite3_unlock_notify( + sqlite3 *pBlocked, /* Waiting connection */ + void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ + void *pNotifyArg /* Argument to pass to xNotify */ +); + + +/* +** CAPI3REF: String Comparison +** +** ^The [sqlite3_stricmp()] and [sqlite3_strnicmp()] APIs allow applications +** and extensions to compare the contents of two buffers containing UTF-8 +** strings in a case-independent fashion, using the same definition of "case +** independence" that SQLite uses internally when comparing identifiers. +*/ +SQLITE_API int sqlite3_stricmp(const char *, const char *); +SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); + +/* +** CAPI3REF: String Globbing +* +** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if +** string X matches the [GLOB] pattern P. +** ^The definition of [GLOB] pattern matching used in +** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the +** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function +** is case sensitive. +** +** Note that this routine returns zero on a match and non-zero if the strings +** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. +** +** See also: [sqlite3_strlike()]. +*/ +SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr); + +/* +** CAPI3REF: String LIKE Matching +* +** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if +** string X matches the [LIKE] pattern P with escape character E. +** ^The definition of [LIKE] pattern matching used in +** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E" +** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without +** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0. +** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case +** insensitive - equivalent upper and lower case ASCII characters match +** one another. +** +** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though +** only ASCII characters are case folded. +** +** Note that this routine returns zero on a match and non-zero if the strings +** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()]. +** +** See also: [sqlite3_strglob()]. +*/ +SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc); + +/* +** CAPI3REF: Error Logging Interface +** +** ^The [sqlite3_log()] interface writes a message into the [error log] +** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. +** ^If logging is enabled, the zFormat string and subsequent arguments are +** used with [sqlite3_snprintf()] to generate the final output string. +** +** The sqlite3_log() interface is intended for use by extensions such as +** virtual tables, collating functions, and SQL functions. While there is +** nothing to prevent an application from calling sqlite3_log(), doing so +** is considered bad form. +** +** The zFormat string must not be NULL. +** +** To avoid deadlocks and other threading problems, the sqlite3_log() routine +** will not use dynamically allocated memory. The log message is stored in +** a fixed-length buffer on the stack. If the log message is longer than +** a few hundred characters, it will be truncated to the length of the +** buffer. +*/ +SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); + +/* +** CAPI3REF: Write-Ahead Log Commit Hook +** METHOD: sqlite3 +** +** ^The [sqlite3_wal_hook()] function is used to register a callback that +** is invoked each time data is committed to a database in wal mode. +** +** ^(The callback is invoked by SQLite after the commit has taken place and +** the associated write-lock on the database released)^, so the implementation +** may read, write or [checkpoint] the database as required. +** +** ^The first parameter passed to the callback function when it is invoked +** is a copy of the third parameter passed to sqlite3_wal_hook() when +** registering the callback. ^The second is a copy of the database handle. +** ^The third parameter is the name of the database that was written to - +** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter +** is the number of pages currently in the write-ahead log file, +** including those that were just committed. +** +** The callback function should normally return [SQLITE_OK]. ^If an error +** code is returned, that error will propagate back up through the +** SQLite code base to cause the statement that provoked the callback +** to report an error, though the commit will have still occurred. If the +** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value +** that does not correspond to any valid SQLite error code, the results +** are undefined. +** +** A single database handle may have at most a single write-ahead log callback +** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any +** previously registered write-ahead log callback. ^Note that the +** [sqlite3_wal_autocheckpoint()] interface and the +** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will +** overwrite any prior [sqlite3_wal_hook()] settings. +*/ +SQLITE_API void *sqlite3_wal_hook( + sqlite3*, + int(*)(void *,sqlite3*,const char*,int), + void* +); + +/* +** CAPI3REF: Configure an auto-checkpoint +** METHOD: sqlite3 +** +** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around +** [sqlite3_wal_hook()] that causes any database on [database connection] D +** to automatically [checkpoint] +** after committing a transaction if there are N or +** more frames in the [write-ahead log] file. ^Passing zero or +** a negative value as the nFrame parameter disables automatic +** checkpoints entirely. +** +** ^The callback registered by this function replaces any existing callback +** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback +** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism +** configured by this function. +** +** ^The [wal_autocheckpoint pragma] can be used to invoke this interface +** from SQL. +** +** ^Checkpoints initiated by this mechanism are +** [sqlite3_wal_checkpoint_v2|PASSIVE]. +** +** ^Every new [database connection] defaults to having the auto-checkpoint +** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] +** pages. The use of this interface +** is only necessary if the default setting is found to be suboptimal +** for a particular application. +*/ +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); + +/* +** CAPI3REF: Checkpoint a database +** METHOD: sqlite3 +** +** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to +** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ +** +** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the +** [write-ahead log] for database X on [database connection] D to be +** transferred into the database file and for the write-ahead log to +** be reset. See the [checkpointing] documentation for addition +** information. +** +** This interface used to be the only way to cause a checkpoint to +** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()] +** interface was added. This interface is retained for backwards +** compatibility and as a convenience for applications that need to manually +** start a callback but which do not need the full power (and corresponding +** complication) of [sqlite3_wal_checkpoint_v2()]. +*/ +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); + +/* +** CAPI3REF: Checkpoint a database +** METHOD: sqlite3 +** +** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint +** operation on database X of [database connection] D in mode M. Status +** information is written back into integers pointed to by L and C.)^ +** ^(The M parameter must be a valid [checkpoint mode]:)^ +** +**
+**
SQLITE_CHECKPOINT_PASSIVE
+** ^Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish, then sync the database file if all frames +** in the log were checkpointed. ^The [busy-handler callback] +** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. +** ^On the other hand, passive mode might leave the checkpoint unfinished +** if there are concurrent readers or writers. +** +**
SQLITE_CHECKPOINT_FULL
+** ^This mode blocks (it invokes the +** [sqlite3_busy_handler|busy-handler callback]) until there is no +** database writer and all readers are reading from the most recent database +** snapshot. ^It then checkpoints all frames in the log file and syncs the +** database file. ^This mode blocks new database writers while it is pending, +** but new database readers are allowed to continue unimpeded. +** +**
SQLITE_CHECKPOINT_RESTART
+** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition +** that after checkpointing the log file it blocks (calls the +** [busy-handler callback]) +** until all readers are reading from the database file only. ^This ensures +** that the next writer will restart the log file from the beginning. +** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new +** database writer attempts while it is pending, but does not impede readers. +** +**
SQLITE_CHECKPOINT_TRUNCATE
+** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the +** addition that it also truncates the log file to zero bytes just prior +** to a successful return. +**
+** +** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in +** the log file or to -1 if the checkpoint could not run because +** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not +** NULL,then *pnCkpt is set to the total number of checkpointed frames in the +** log file (including any that were already checkpointed before the function +** was called) or to -1 if the checkpoint could not run due to an error or +** because the database is not in WAL mode. ^Note that upon successful +** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been +** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. +** +** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If +** any other process is running a checkpoint operation at the same time, the +** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a +** busy-handler configured, it will not be invoked in this case. +** +** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the +** exclusive "writer" lock on the database file. ^If the writer lock cannot be +** obtained immediately, and a busy-handler is configured, it is invoked and +** the writer lock retried until either the busy-handler returns 0 or the lock +** is successfully obtained. ^The busy-handler is also invoked while waiting for +** database readers as described above. ^If the busy-handler returns 0 before +** the writer lock is obtained or while waiting for database readers, the +** checkpoint operation proceeds from that point in the same way as +** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible +** without blocking any further. ^SQLITE_BUSY is returned in this case. +** +** ^If parameter zDb is NULL or points to a zero length string, then the +** specified operation is attempted on all WAL databases [attached] to +** [database connection] db. In this case the +** values written to output parameters *pnLog and *pnCkpt are undefined. ^If +** an SQLITE_BUSY error is encountered when processing one or more of the +** attached WAL databases, the operation is still attempted on any remaining +** attached databases and SQLITE_BUSY is returned at the end. ^If any other +** error occurs while processing an attached database, processing is abandoned +** and the error code is returned to the caller immediately. ^If no error +** (SQLITE_BUSY or otherwise) is encountered while processing the attached +** databases, SQLITE_OK is returned. +** +** ^If database zDb is the name of an attached database that is not in WAL +** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If +** zDb is not NULL (or a zero length string) and is not the name of any +** attached database, SQLITE_ERROR is returned to the caller. +** +** ^Unless it returns SQLITE_MISUSE, +** the sqlite3_wal_checkpoint_v2() interface +** sets the error information that is queried by +** [sqlite3_errcode()] and [sqlite3_errmsg()]. +** +** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface +** from SQL. +*/ +SQLITE_API int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +); + +/* +** CAPI3REF: Checkpoint Mode Values +** KEYWORDS: {checkpoint mode} +** +** These constants define all valid values for the "checkpoint mode" passed +** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. +** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the +** meaning of each of these checkpoint modes. +*/ +#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ +#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ +#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */ +#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ + +/* +** CAPI3REF: Virtual Table Interface Configuration +** +** This function may be called by either the [xConnect] or [xCreate] method +** of a [virtual table] implementation to configure +** various facets of the virtual table interface. +** +** If this interface is invoked outside the context of an xConnect or +** xCreate virtual table method then the behavior is undefined. +** +** At present, there is only one option that may be configured using +** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options +** may be added in the future. +*/ +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Virtual Table Configuration Options +** +** These macros define the various options to the +** [sqlite3_vtab_config()] interface that [virtual table] implementations +** can use to customize and optimize their behavior. +** +**
+**
SQLITE_VTAB_CONSTRAINT_SUPPORT +**
Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, +** where X is an integer. If X is zero, then the [virtual table] whose +** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not +** support constraints. In this configuration (which is the default) if +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been +** specified as part of the users SQL statement, regardless of the actual +** ON CONFLICT mode specified. +** +** If X is non-zero, then the virtual table implementation guarantees +** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before +** any modifications to internal or persistent data structures have been made. +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite +** is able to roll back a statement or database transaction, and abandon +** or continue processing the current SQL statement as appropriate. +** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns +** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode +** had been ABORT. +** +** Virtual table implementations that are required to handle OR REPLACE +** must do so within the [xUpdate] method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should +** silently replace the appropriate rows within the xUpdate callback and +** return SQLITE_OK. Or, if this is not possible, it may return +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** constraint handling. +**
+*/ +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 + +/* +** CAPI3REF: Determine The Virtual Table Conflict Policy +** +** This function may only be called from within a call to the [xUpdate] method +** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The +** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], +** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode +** of the SQL statement that triggered the call to the [xUpdate] method of the +** [virtual table]. +*/ +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); + +/* +** CAPI3REF: Conflict resolution modes +** KEYWORDS: {conflict resolution mode} +** +** These constants are returned by [sqlite3_vtab_on_conflict()] to +** inform a [virtual table] implementation what the [ON CONFLICT] mode +** is for the SQL statement being evaluated. +** +** Note that the [SQLITE_IGNORE] constant is also used as a potential +** return value from the [sqlite3_set_authorizer()] callback and that +** [SQLITE_ABORT] is also a [result code]. +*/ +#define SQLITE_ROLLBACK 1 +/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ +#define SQLITE_FAIL 3 +/* #define SQLITE_ABORT 4 // Also an error code */ +#define SQLITE_REPLACE 5 + +/* +** CAPI3REF: Prepared Statement Scan Status Opcodes +** KEYWORDS: {scanstatus options} +** +** The following constants can be used for the T parameter to the +** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a +** different metric for sqlite3_stmt_scanstatus() to return. +** +** When the value returned to V is a string, space to hold that string is +** managed by the prepared statement S and will be automatically freed when +** S is finalized. +** +**
+** [[SQLITE_SCANSTAT_NLOOP]]
SQLITE_SCANSTAT_NLOOP
+**
^The [sqlite3_int64] variable pointed to by the T parameter will be +** set to the total number of times that the X-th loop has run.
+** +** [[SQLITE_SCANSTAT_NVISIT]]
SQLITE_SCANSTAT_NVISIT
+**
^The [sqlite3_int64] variable pointed to by the T parameter will be set +** to the total number of rows examined by all iterations of the X-th loop.
+** +** [[SQLITE_SCANSTAT_EST]]
SQLITE_SCANSTAT_EST
+**
^The "double" variable pointed to by the T parameter will be set to the +** query planner's estimate for the average number of rows output from each +** iteration of the X-th loop. If the query planner's estimates was accurate, +** then this value will approximate the quotient NVISIT/NLOOP and the +** product of this value for all prior loops with the same SELECTID will +** be the NLOOP value for the current loop. +** +** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
+**
^The "const char *" variable pointed to by the T parameter will be set +** to a zero-terminated UTF-8 string containing the name of the index or table +** used for the X-th loop. +** +** [[SQLITE_SCANSTAT_EXPLAIN]]
SQLITE_SCANSTAT_EXPLAIN
+**
^The "const char *" variable pointed to by the T parameter will be set +** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] +** description for the X-th loop. +** +** [[SQLITE_SCANSTAT_SELECTID]]
SQLITE_SCANSTAT_SELECT
+**
^The "int" variable pointed to by the T parameter will be set to the +** "select-id" for the X-th loop. The select-id identifies which query or +** subquery the loop is part of. The main query has a select-id of zero. +** The select-id is the same value as is output in the first column +** of an [EXPLAIN QUERY PLAN] query. +**
+*/ +#define SQLITE_SCANSTAT_NLOOP 0 +#define SQLITE_SCANSTAT_NVISIT 1 +#define SQLITE_SCANSTAT_EST 2 +#define SQLITE_SCANSTAT_NAME 3 +#define SQLITE_SCANSTAT_EXPLAIN 4 +#define SQLITE_SCANSTAT_SELECTID 5 + +/* +** CAPI3REF: Prepared Statement Scan Status +** METHOD: sqlite3_stmt +** +** This interface returns information about the predicted and measured +** performance for pStmt. Advanced applications can use this +** interface to compare the predicted and the measured performance and +** issue warnings and/or rerun [ANALYZE] if discrepancies are found. +** +** Since this interface is expected to be rarely used, it is only +** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS] +** compile-time option. +** +** The "iScanStatusOp" parameter determines which status information to return. +** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior +** of this interface is undefined. +** ^The requested measurement is written into a variable pointed to by +** the "pOut" parameter. +** Parameter "idx" identifies the specific loop to retrieve statistics for. +** Loops are numbered starting from zero. ^If idx is out of range - less than +** zero or greater than or equal to the total number of loops used to implement +** the statement - a non-zero value is returned and the variable that pOut +** points to is unchanged. +** +** ^Statistics might not be available for all loops in all statements. ^In cases +** where there exist loops with no available statistics, this function behaves +** as if the loop did not exist - it returns non-zero and leave the variable +** that pOut points to unchanged. +** +** See also: [sqlite3_stmt_scanstatus_reset()] +*/ +SQLITE_API int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ + int idx, /* Index of loop to report on */ + int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ + void *pOut /* Result written here */ +); + +/* +** CAPI3REF: Zero Scan-Status Counters +** METHOD: sqlite3_stmt +** +** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. +** +** This API is only available if the library is built with pre-processor +** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. +*/ +SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); + +/* +** CAPI3REF: Flush caches to disk mid-transaction +** +** ^If a write-transaction is open on [database connection] D when the +** [sqlite3_db_cacheflush(D)] interface invoked, any dirty +** pages in the pager-cache that are not currently in use are written out +** to disk. A dirty page may be in use if a database cursor created by an +** active SQL statement is reading from it, or if it is page 1 of a database +** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] +** interface flushes caches for all schemas - "main", "temp", and +** any [attached] databases. +** +** ^If this function needs to obtain extra database locks before dirty pages +** can be flushed to disk, it does so. ^If those locks cannot be obtained +** immediately and there is a busy-handler callback configured, it is invoked +** in the usual manner. ^If the required lock still cannot be obtained, then +** the database is skipped and an attempt made to flush any dirty pages +** belonging to the next (if any) database. ^If any databases are skipped +** because locks cannot be obtained, but no other error occurs, this +** function returns SQLITE_BUSY. +** +** ^If any other error occurs while flushing dirty pages to disk (for +** example an IO error or out-of-memory condition), then processing is +** abandoned and an SQLite [error code] is returned to the caller immediately. +** +** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK. +** +** ^This function does not set the database handle error code or message +** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions. +*/ +SQLITE_API int sqlite3_db_cacheflush(sqlite3*); + +/* +** CAPI3REF: The pre-update hook. +** +** ^These interfaces are only available if SQLite is compiled using the +** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. +** +** ^The [sqlite3_preupdate_hook()] interface registers a callback function +** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation +** on a database table. +** ^At most one preupdate hook may be registered at a time on a single +** [database connection]; each call to [sqlite3_preupdate_hook()] overrides +** the previous setting. +** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()] +** with a NULL pointer as the second parameter. +** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as +** the first parameter to callbacks. +** +** ^The preupdate hook only fires for changes to real database tables; the +** preupdate hook is not invoked for changes to [virtual tables] or to +** system tables like sqlite_master or sqlite_stat1. +** +** ^The second parameter to the preupdate callback is a pointer to +** the [database connection] that registered the preupdate hook. +** ^The third parameter to the preupdate callback is one of the constants +** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the +** kind of update operation that is about to occur. +** ^(The fourth parameter to the preupdate callback is the name of the +** database within the database connection that is being modified. This +** will be "main" for the main database or "temp" for TEMP tables or +** the name given after the AS keyword in the [ATTACH] statement for attached +** databases.)^ +** ^The fifth parameter to the preupdate callback is the name of the +** table that is being modified. +** +** For an UPDATE or DELETE operation on a [rowid table], the sixth +** parameter passed to the preupdate callback is the initial [rowid] of the +** row being modified or deleted. For an INSERT operation on a rowid table, +** or any operation on a WITHOUT ROWID table, the value of the sixth +** parameter is undefined. For an INSERT or UPDATE on a rowid table the +** seventh parameter is the final rowid value of the row being inserted +** or updated. The value of the seventh parameter passed to the callback +** function is not defined for operations on WITHOUT ROWID tables, or for +** INSERT operations on rowid tables. +** +** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], +** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces +** provide additional information about a preupdate event. These routines +** may only be called from within a preupdate callback. Invoking any of +** these routines from outside of a preupdate callback or with a +** [database connection] pointer that is different from the one supplied +** to the preupdate callback results in undefined and probably undesirable +** behavior. +** +** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns +** in the row that is being inserted, updated, or deleted. +** +** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row before it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE +** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to +** a [protected sqlite3_value] that contains the value of the Nth column of +** the table row after it is updated. The N parameter must be between 0 +** and one less than the number of columns or the behavior will be +** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE +** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the +** behavior is undefined. The [sqlite3_value] that P points to +** will be destroyed when the preupdate callback returns. +** +** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate +** callback was invoked as a result of a direct insert, update, or delete +** operation; or 1 for inserts, updates, or deletes invoked by top-level +** triggers; or 2 for changes resulting from triggers called by top-level +** triggers; and so forth. +** +** See also: [sqlite3_update_hook()] +*/ +#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, + void(*xPreUpdate)( + void *pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3 *db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const *zDb, /* Database name */ + char const *zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ + ), + void* +); +SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); +SQLITE_API int sqlite3_preupdate_count(sqlite3 *); +SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); +SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); +#endif + +/* +** CAPI3REF: Low-level system error code +** +** ^Attempt to return the underlying operating system error code or error +** number that caused the most recent I/O error or failure to open a file. +** The return value is OS-dependent. For example, on unix systems, after +** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be +** called to get back the underlying "errno" that caused the problem, such +** as ENOSPC, EAUTH, EISDIR, and so forth. +*/ +SQLITE_API int sqlite3_system_errno(sqlite3*); + +/* +** CAPI3REF: Database Snapshot +** KEYWORDS: {snapshot} {sqlite3_snapshot} +** EXPERIMENTAL +** +** An instance of the snapshot object records the state of a [WAL mode] +** database for some specific point in history. +** +** In [WAL mode], multiple [database connections] that are open on the +** same database file can each be reading a different historical version +** of the database file. When a [database connection] begins a read +** transaction, that connection sees an unchanging copy of the database +** as it existed for the point in time when the transaction first started. +** Subsequent changes to the database from other connections are not seen +** by the reader until a new read transaction is started. +** +** The sqlite3_snapshot object records state information about an historical +** version of the database file so that it is possible to later open a new read +** transaction that sees that historical version of the database rather than +** the most recent version. +** +** The constructor for this object is [sqlite3_snapshot_get()]. The +** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer +** to an historical snapshot (if possible). The destructor for +** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. +*/ +typedef struct sqlite3_snapshot { + unsigned char hidden[48]; +} sqlite3_snapshot; + +/* +** CAPI3REF: Record A Database Snapshot +** EXPERIMENTAL +** +** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a +** new [sqlite3_snapshot] object that records the current state of +** schema S in database connection D. ^On success, the +** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly +** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. +** If there is not already a read-transaction open on schema S when +** this function is called, one is opened automatically. +** +** The following must be true for this function to succeed. If any of +** the following statements are false when sqlite3_snapshot_get() is +** called, SQLITE_ERROR is returned. The final value of *P is undefined +** in this case. +** +**
    +**
  • The database handle must be in [autocommit mode]. +** +**
  • Schema S of [database connection] D must be a [WAL mode] database. +** +**
  • There must not be a write transaction open on schema S of database +** connection D. +** +**
  • One or more transactions must have been written to the current wal +** file since it was created on disk (by any connection). This means +** that a snapshot cannot be taken on a wal mode database with no wal +** file immediately after it is first opened. At least one transaction +** must be written to it first. +**
+** +** This function may also return SQLITE_NOMEM. If it is called with the +** database handle in autocommit mode but fails for some other reason, +** whether or not a read transaction is opened on schema S is undefined. +** +** The [sqlite3_snapshot] object returned from a successful call to +** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] +** to avoid a memory leak. +** +** The [sqlite3_snapshot_get()] interface is only available when the +** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot **ppSnapshot +); + +/* +** CAPI3REF: Start a read transaction on an historical snapshot +** EXPERIMENTAL +** +** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a +** read transaction for schema S of +** [database connection] D such that the read transaction +** refers to historical [snapshot] P, rather than the most +** recent change to the database. +** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success +** or an appropriate [error code] if it fails. +** +** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be +** the first operation following the [BEGIN] that takes the schema S +** out of [autocommit mode]. +** ^In other words, schema S must not currently be in +** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the +** database connection D must be out of [autocommit mode]. +** ^A [snapshot] will fail to open if it has been overwritten by a +** [checkpoint]. +** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the +** database connection D does not know that the database file for +** schema S is in [WAL mode]. A database connection might not know +** that the database file is in [WAL mode] if there has been no prior +** I/O on that database connection, or if the database entered [WAL mode] +** after the most recent I/O on the database connection.)^ +** (Hint: Run "[PRAGMA application_id]" against a newly opened +** database connection in order to make it ready to use snapshots.) +** +** The [sqlite3_snapshot_open()] interface is only available when the +** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot *pSnapshot +); + +/* +** CAPI3REF: Destroy a snapshot +** EXPERIMENTAL +** +** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. +** The application must eventually free every [sqlite3_snapshot] object +** using this routine to avoid a memory leak. +** +** The [sqlite3_snapshot_free()] interface is only available when the +** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +*/ +SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); + +/* +** CAPI3REF: Compare the ages of two snapshot handles. +** EXPERIMENTAL +** +** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages +** of two valid snapshot handles. +** +** If the two snapshot handles are not associated with the same database +** file, the result of the comparison is undefined. +** +** Additionally, the result of the comparison is only valid if both of the +** snapshot handles were obtained by calling sqlite3_snapshot_get() since the +** last time the wal file was deleted. The wal file is deleted when the +** database is changed back to rollback mode or when the number of database +** clients drops to zero. If either snapshot handle was obtained before the +** wal file was last deleted, the value returned by this function +** is undefined. +** +** Otherwise, this API returns a negative value if P1 refers to an older +** snapshot than P2, zero if the two handles refer to the same database +** snapshot, and a positive value if P1 is a newer snapshot than P2. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( + sqlite3_snapshot *p1, + sqlite3_snapshot *p2 +); + +/* +** CAPI3REF: Recover snapshots from a wal file +** EXPERIMENTAL +** +** If all connections disconnect from a database file but do not perform +** a checkpoint, the existing wal file is opened along with the database +** file the next time the database is opened. At this point it is only +** possible to successfully call sqlite3_snapshot_open() to open the most +** recent snapshot of the database (the one at the head of the wal file), +** even though the wal file may contain other valid snapshots for which +** clients have sqlite3_snapshot handles. +** +** This function attempts to scan the wal file associated with database zDb +** of database handle db and make all valid snapshots available to +** sqlite3_snapshot_open(). It is an error if there is already a read +** transaction open on the database, or if the database is not a wal mode +** database. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); + +/* +** Undo the hack that converts floating point types to integer for +** builds on processors without floating point support. +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# undef double +#endif + +#if 0 +} /* End of the 'extern "C"' block */ +#endif +#endif /* SQLITE3_H */ + +/******** Begin file sqlite3rtree.h *********/ +/* +** 2010 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. +** +************************************************************************* +*/ + +#ifndef _SQLITE3RTREE_H_ +#define _SQLITE3RTREE_H_ + + +#if 0 +extern "C" { +#endif + +typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; +typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; + +/* The double-precision datatype used by RTree depends on the +** SQLITE_RTREE_INT_ONLY compile-time option. +*/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 sqlite3_rtree_dbl; +#else + typedef double sqlite3_rtree_dbl; +#endif + +/* +** Register a geometry callback named zGeom that can be used as part of an +** R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zGeom(... params ...) +*/ +SQLITE_API int sqlite3_rtree_geometry_callback( + sqlite3 *db, + const char *zGeom, + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), + void *pContext +); + + +/* +** A pointer to a structure of the following type is passed as the first +** argument to callbacks registered using rtree_geometry_callback(). +*/ +struct sqlite3_rtree_geometry { + void *pContext; /* Copy of pContext passed to s_r_g_c() */ + int nParam; /* Size of array aParam[] */ + sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ + void *pUser; /* Callback implementation user data */ + void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ +}; + +/* +** Register a 2nd-generation geometry callback named zScore that can be +** used as part of an R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) +*/ +SQLITE_API int sqlite3_rtree_query_callback( + sqlite3 *db, + const char *zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void *pContext, + void (*xDestructor)(void*) +); + + +/* +** A pointer to a structure of the following type is passed as the +** argument to scored geometry callback registered using +** sqlite3_rtree_query_callback(). +** +** Note that the first 5 fields of this structure are identical to +** sqlite3_rtree_geometry. This structure is a subclass of +** sqlite3_rtree_geometry. +*/ +struct sqlite3_rtree_query_info { + void *pContext; /* pContext from when function registered */ + int nParam; /* Number of function parameters */ + sqlite3_rtree_dbl *aParam; /* value of function parameters */ + void *pUser; /* callback can use this, if desired */ + void (*xDelUser)(void*); /* function to free pUser */ + sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ + unsigned int *anQueue; /* Number of pending entries in the queue */ + int nCoord; /* Number of coordinates */ + int iLevel; /* Level of current node or entry */ + int mxLevel; /* The largest iLevel value in the tree */ + sqlite3_int64 iRowid; /* Rowid for current entry */ + sqlite3_rtree_dbl rParentScore; /* Score of parent node */ + int eParentWithin; /* Visibility of parent node */ + int eWithin; /* OUT: Visiblity */ + sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ + /* The following fields are only available in 3.8.11 and later */ + sqlite3_value **apSqlParam; /* Original SQL values of parameters */ +}; + +/* +** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin. +*/ +#define NOT_WITHIN 0 /* Object completely outside of query region */ +#define PARTLY_WITHIN 1 /* Object partially overlaps query region */ +#define FULLY_WITHIN 2 /* Object fully contained within query region */ + + +#if 0 +} /* end of the 'extern "C"' block */ +#endif + +#endif /* ifndef _SQLITE3RTREE_H_ */ + +/******** End of sqlite3rtree.h *********/ +/******** Begin file sqlite3session.h *********/ + +#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) +#define __SQLITESESSION_H_ 1 + +/* +** Make sure we can call this stuff from C++. +*/ +#if 0 +extern "C" { +#endif + + +/* +** CAPI3REF: Session Object Handle +*/ +typedef struct sqlite3_session sqlite3_session; + +/* +** CAPI3REF: Changeset Iterator Handle +*/ +typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; + +/* +** CAPI3REF: Create A New Session Object +** +** Create a new session object attached to database handle db. If successful, +** a pointer to the new object is written to *ppSession and SQLITE_OK is +** returned. If an error occurs, *ppSession is set to NULL and an SQLite +** error code (e.g. SQLITE_NOMEM) is returned. +** +** It is possible to create multiple session objects attached to a single +** database handle. +** +** Session objects created using this function should be deleted using the +** [sqlite3session_delete()] function before the database handle that they +** are attached to is itself closed. If the database handle is closed before +** the session object is deleted, then the results of calling any session +** module function, including [sqlite3session_delete()] on the session object +** are undefined. +** +** Because the session module uses the [sqlite3_preupdate_hook()] API, it +** is not possible for an application to register a pre-update hook on a +** database handle that has one or more session objects attached. Nor is +** it possible to create a session object attached to a database handle for +** which a pre-update hook is already defined. The results of attempting +** either of these things are undefined. +** +** The session object will be used to create changesets for tables in +** database zDb, where zDb is either "main", or "temp", or the name of an +** attached database. It is not an error if database zDb is not attached +** to the database when the session object is created. +*/ +SQLITE_API int sqlite3session_create( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (e.g. "main") */ + sqlite3_session **ppSession /* OUT: New session object */ +); + +/* +** CAPI3REF: Delete A Session Object +** +** Delete a session object previously allocated using +** [sqlite3session_create()]. Once a session object has been deleted, the +** results of attempting to use pSession with any other session module +** function are undefined. +** +** Session objects must be deleted before the database handle to which they +** are attached is closed. Refer to the documentation for +** [sqlite3session_create()] for details. +*/ +SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); + + +/* +** CAPI3REF: Enable Or Disable A Session Object +** +** Enable or disable the recording of changes by a session object. When +** enabled, a session object records changes made to the database. When +** disabled - it does not. A newly created session object is enabled. +** Refer to the documentation for [sqlite3session_changeset()] for further +** details regarding how enabling and disabling a session object affects +** the eventual changesets. +** +** Passing zero to this function disables the session. Passing a value +** greater than zero enables it. Passing a value less than zero is a +** no-op, and may be used to query the current state of the session. +** +** The return value indicates the final state of the session object: 0 if +** the session is disabled, or 1 if it is enabled. +*/ +SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); + +/* +** CAPI3REF: Set Or Clear the Indirect Change Flag +** +** Each change recorded by a session object is marked as either direct or +** indirect. A change is marked as indirect if either: +** +**
    +**
  • The session object "indirect" flag is set when the change is +** made, or +**
  • The change is made by an SQL trigger or foreign key action +** instead of directly as a result of a users SQL statement. +**
+** +** If a single row is affected by more than one operation within a session, +** then the change is considered indirect if all operations meet the criteria +** for an indirect change above, or direct otherwise. +** +** This function is used to set, clear or query the session object indirect +** flag. If the second argument passed to this function is zero, then the +** indirect flag is cleared. If it is greater than zero, the indirect flag +** is set. Passing a value less than zero does not modify the current value +** of the indirect flag, and may be used to query the current state of the +** indirect flag for the specified session object. +** +** The return value indicates the final state of the indirect flag: 0 if +** it is clear, or 1 if it is set. +*/ +SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); + +/* +** CAPI3REF: Attach A Table To A Session Object +** +** If argument zTab is not NULL, then it is the name of a table to attach +** to the session object passed as the first argument. All subsequent changes +** made to the table while the session object is enabled will be recorded. See +** documentation for [sqlite3session_changeset()] for further details. +** +** Or, if argument zTab is NULL, then changes are recorded for all tables +** in the database. If additional tables are added to the database (by +** executing "CREATE TABLE" statements) after this call is made, changes for +** the new tables are also recorded. +** +** Changes can only be recorded for tables that have a PRIMARY KEY explicitly +** defined as part of their CREATE TABLE statement. It does not matter if the +** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY +** KEY may consist of a single column, or may be a composite key. +** +** It is not an error if the named table does not exist in the database. Nor +** is it an error if the named table does not have a PRIMARY KEY. However, +** no changes will be recorded in either of these scenarios. +** +** Changes are not recorded for individual rows that have NULL values stored +** in one or more of their PRIMARY KEY columns. +** +** SQLITE_OK is returned if the call completes without error. Or, if an error +** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. +*/ +SQLITE_API int sqlite3session_attach( + sqlite3_session *pSession, /* Session object */ + const char *zTab /* Table name */ +); + +/* +** CAPI3REF: Set a table filter on a Session Object. +** +** The second argument (xFilter) is the "filter callback". For changes to rows +** in tables that are not attached to the Session object, the filter is called +** to determine whether changes to the table's rows should be tracked or not. +** If xFilter returns 0, changes is not tracked. Note that once a table is +** attached, xFilter will not be called again. +*/ +SQLITE_API void sqlite3session_table_filter( + sqlite3_session *pSession, /* Session object */ + int(*xFilter)( + void *pCtx, /* Copy of third arg to _filter_table() */ + const char *zTab /* Table name */ + ), + void *pCtx /* First argument passed to xFilter */ +); + +/* +** CAPI3REF: Generate A Changeset From A Session Object +** +** Obtain a changeset containing changes to the tables attached to the +** session object passed as the first argument. If successful, +** set *ppChangeset to point to a buffer containing the changeset +** and *pnChangeset to the size of the changeset in bytes before returning +** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to +** zero and return an SQLite error code. +** +** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes, +** each representing a change to a single row of an attached table. An INSERT +** change contains the values of each field of a new database row. A DELETE +** contains the original values of each field of a deleted database row. An +** UPDATE change contains the original values of each field of an updated +** database row along with the updated values for each updated non-primary-key +** column. It is not possible for an UPDATE change to represent a change that +** modifies the values of primary key columns. If such a change is made, it +** is represented in a changeset as a DELETE followed by an INSERT. +** +** Changes are not recorded for rows that have NULL values stored in one or +** more of their PRIMARY KEY columns. If such a row is inserted or deleted, +** no corresponding change is present in the changesets returned by this +** function. If an existing row with one or more NULL values stored in +** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL, +** only an INSERT is appears in the changeset. Similarly, if an existing row +** with non-NULL PRIMARY KEY values is updated so that one or more of its +** PRIMARY KEY columns are set to NULL, the resulting changeset contains a +** DELETE change only. +** +** The contents of a changeset may be traversed using an iterator created +** using the [sqlite3changeset_start()] API. A changeset may be applied to +** a database with a compatible schema using the [sqlite3changeset_apply()] +** API. +** +** Within a changeset generated by this function, all changes related to a +** single table are grouped together. In other words, when iterating through +** a changeset or when applying a changeset to a database, all changes related +** to a single table are processed before moving on to the next table. Tables +** are sorted in the same order in which they were attached (or auto-attached) +** to the sqlite3_session object. The order in which the changes related to +** a single table are stored is undefined. +** +** Following a successful call to this function, it is the responsibility of +** the caller to eventually free the buffer that *ppChangeset points to using +** [sqlite3_free()]. +** +**

Changeset Generation

+** +** Once a table has been attached to a session object, the session object +** records the primary key values of all new rows inserted into the table. +** It also records the original primary key and other column values of any +** deleted or updated rows. For each unique primary key value, data is only +** recorded once - the first time a row with said primary key is inserted, +** updated or deleted in the lifetime of the session. +** +** There is one exception to the previous paragraph: when a row is inserted, +** updated or deleted, if one or more of its primary key columns contain a +** NULL value, no record of the change is made. +** +** The session object therefore accumulates two types of records - those +** that consist of primary key values only (created when the user inserts +** a new record) and those that consist of the primary key values and the +** original values of other table columns (created when the users deletes +** or updates a record). +** +** When this function is called, the requested changeset is created using +** both the accumulated records and the current contents of the database +** file. Specifically: +** +**
    +**
  • For each record generated by an insert, the database is queried +** for a row with a matching primary key. If one is found, an INSERT +** change is added to the changeset. If no such row is found, no change +** is added to the changeset. +** +**
  • For each record generated by an update or delete, the database is +** queried for a row with a matching primary key. If such a row is +** found and one or more of the non-primary key fields have been +** modified from their original values, an UPDATE change is added to +** the changeset. Or, if no such row is found in the table, a DELETE +** change is added to the changeset. If there is a row with a matching +** primary key in the database, but all fields contain their original +** values, no change is added to the changeset. +**
+** +** This means, amongst other things, that if a row is inserted and then later +** deleted while a session object is active, neither the insert nor the delete +** will be present in the changeset. Or if a row is deleted and then later a +** row with the same primary key values inserted while a session object is +** active, the resulting changeset will contain an UPDATE change instead of +** a DELETE and an INSERT. +** +** When a session object is disabled (see the [sqlite3session_enable()] API), +** it does not accumulate records when rows are inserted, updated or deleted. +** This may appear to have some counter-intuitive effects if a single row +** is written to more than once during a session. For example, if a row +** is inserted while a session object is enabled, then later deleted while +** the same session object is disabled, no INSERT record will appear in the +** changeset, even though the delete took place while the session was disabled. +** Or, if one field of a row is updated while a session is disabled, and +** another field of the same row is updated while the session is enabled, the +** resulting changeset will contain an UPDATE change that updates both fields. +*/ +SQLITE_API int sqlite3session_changeset( + sqlite3_session *pSession, /* Session object */ + int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void **ppChangeset /* OUT: Buffer containing changeset */ +); + +/* +** CAPI3REF: Load The Difference Between Tables Into A Session +** +** If it is not already attached to the session object passed as the first +** argument, this function attaches table zTbl in the same manner as the +** [sqlite3session_attach()] function. If zTbl does not exist, or if it +** does not have a primary key, this function is a no-op (but does not return +** an error). +** +** Argument zFromDb must be the name of a database ("main", "temp" etc.) +** attached to the same database handle as the session object that contains +** a table compatible with the table attached to the session by this function. +** A table is considered compatible if it: +** +**
    +**
  • Has the same name, +**
  • Has the same set of columns declared in the same order, and +**
  • Has the same PRIMARY KEY definition. +**
+** +** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables +** are compatible but do not have any PRIMARY KEY columns, it is not an error +** but no changes are added to the session object. As with other session +** APIs, tables without PRIMARY KEYs are simply ignored. +** +** This function adds a set of changes to the session object that could be +** used to update the table in database zFrom (call this the "from-table") +** so that its content is the same as the table attached to the session +** object (call this the "to-table"). Specifically: +** +**
    +**
  • For each row (primary key) that exists in the to-table but not in +** the from-table, an INSERT record is added to the session object. +** +**
  • For each row (primary key) that exists in the to-table but not in +** the from-table, a DELETE record is added to the session object. +** +**
  • For each row (primary key) that exists in both tables, but features +** different non-PK values in each, an UPDATE record is added to the +** session. +**
+** +** To clarify, if this function is called and then a changeset constructed +** using [sqlite3session_changeset()], then after applying that changeset to +** database zFrom the contents of the two compatible tables would be +** identical. +** +** It an error if database zFrom does not exist or does not contain the +** required compatible table. +** +** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite +** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg +** may be set to point to a buffer containing an English language error +** message. It is the responsibility of the caller to free this buffer using +** sqlite3_free(). +*/ +SQLITE_API int sqlite3session_diff( + sqlite3_session *pSession, + const char *zFromDb, + const char *zTbl, + char **pzErrMsg +); + + +/* +** CAPI3REF: Generate A Patchset From A Session Object +** +** The differences between a patchset and a changeset are that: +** +**
    +**
  • DELETE records consist of the primary key fields only. The +** original values of other fields are omitted. +**
  • The original values of any modified fields are omitted from +** UPDATE records. +**
+** +** A patchset blob may be used with up to date versions of all +** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), +** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, +** attempting to use a patchset blob with old versions of the +** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. +** +** Because the non-primary key "old.*" fields are omitted, no +** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset +** is passed to the sqlite3changeset_apply() API. Other conflict types work +** in the same way as for changesets. +** +** Changes within a patchset are ordered in the same way as for changesets +** generated by the sqlite3session_changeset() function (i.e. all changes for +** a single table are grouped together, tables appear in the order in which +** they were attached to the session object). +*/ +SQLITE_API int sqlite3session_patchset( + sqlite3_session *pSession, /* Session object */ + int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ + void **ppPatchset /* OUT: Buffer containing changeset */ +); + +/* +** CAPI3REF: Test if a changeset has recorded any changes. +** +** Return non-zero if no changes to attached tables have been recorded by +** the session object passed as the first argument. Otherwise, if one or +** more changes have been recorded, return zero. +** +** Even if this function returns zero, it is possible that calling +** [sqlite3session_changeset()] on the session handle may still return a +** changeset that contains no changes. This can happen when a row in +** an attached table is modified and then later on the original values +** are restored. However, if this function returns non-zero, then it is +** guaranteed that a call to sqlite3session_changeset() will return a +** changeset containing zero changes. +*/ +SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); + +/* +** CAPI3REF: Create An Iterator To Traverse A Changeset +** +** Create an iterator used to iterate through the contents of a changeset. +** If successful, *pp is set to point to the iterator handle and SQLITE_OK +** is returned. Otherwise, if an error occurs, *pp is set to zero and an +** SQLite error code is returned. +** +** The following functions can be used to advance and query a changeset +** iterator created by this function: +** +**
    +**
  • [sqlite3changeset_next()] +**
  • [sqlite3changeset_op()] +**
  • [sqlite3changeset_new()] +**
  • [sqlite3changeset_old()] +**
+** +** It is the responsibility of the caller to eventually destroy the iterator +** by passing it to [sqlite3changeset_finalize()]. The buffer containing the +** changeset (pChangeset) must remain valid until after the iterator is +** destroyed. +** +** Assuming the changeset blob was created by one of the +** [sqlite3session_changeset()], [sqlite3changeset_concat()] or +** [sqlite3changeset_invert()] functions, all changes within the changeset +** that apply to a single table are grouped together. This means that when +** an application iterates through a changeset using an iterator created by +** this function, all changes that relate to a single table are visited +** consecutively. There is no chance that the iterator will visit a change +** the applies to table X, then one for table Y, and then later on visit +** another change for table X. +*/ +SQLITE_API int sqlite3changeset_start( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset /* Pointer to blob containing changeset */ +); + + +/* +** CAPI3REF: Advance A Changeset Iterator +** +** This function may only be used with iterators created by function +** [sqlite3changeset_start()]. If it is called on an iterator passed to +** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE +** is returned and the call has no effect. +** +** Immediately after an iterator is created by sqlite3changeset_start(), it +** does not point to any change in the changeset. Assuming the changeset +** is not empty, the first call to this function advances the iterator to +** point to the first change in the changeset. Each subsequent call advances +** the iterator to point to the next change in the changeset (if any). If +** no error occurs and the iterator points to a valid change after a call +** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. +** Otherwise, if all changes in the changeset have already been visited, +** SQLITE_DONE is returned. +** +** If an error occurs, an SQLite error code is returned. Possible error +** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or +** SQLITE_NOMEM. +*/ +SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Obtain The Current Operation From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this +** is not the case, this function returns [SQLITE_MISUSE]. +** +** If argument pzTab is not NULL, then *pzTab is set to point to a +** nul-terminated utf-8 encoded string containing the name of the table +** affected by the current change. The buffer remains valid until either +** sqlite3changeset_next() is called on the iterator or until the +** conflict-handler function returns. If pnCol is not NULL, then *pnCol is +** set to the number of columns in the table affected by the change. If +** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change +** is an indirect change, or false (0) otherwise. See the documentation for +** [sqlite3session_indirect()] for a description of direct and indirect +** changes. Finally, if pOp is not NULL, then *pOp is set to one of +** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the +** type of change that the iterator currently points to. +** +** If no error occurs, SQLITE_OK is returned. If an error does occur, an +** SQLite error code is returned. The values of the output variables may not +** be trusted in this case. +*/ +SQLITE_API int sqlite3changeset_op( + sqlite3_changeset_iter *pIter, /* Iterator object */ + const char **pzTab, /* OUT: Pointer to table name */ + int *pnCol, /* OUT: Number of columns in table */ + int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ + int *pbIndirect /* OUT: True for an 'indirect' change */ +); + +/* +** CAPI3REF: Obtain The Primary Key Definition Of A Table +** +** For each modified table, a changeset includes the following: +** +**
    +**
  • The number of columns in the table, and +**
  • Which of those columns make up the tables PRIMARY KEY. +**
+** +** This function is used to find which columns comprise the PRIMARY KEY of +** the table modified by the change that iterator pIter currently points to. +** If successful, *pabPK is set to point to an array of nCol entries, where +** nCol is the number of columns in the table. Elements of *pabPK are set to +** 0x01 if the corresponding column is part of the tables primary key, or +** 0x00 if it is not. +** +** If argument pnCol is not NULL, then *pnCol is set to the number of columns +** in the table. +** +** If this function is called when the iterator does not point to a valid +** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise, +** SQLITE_OK is returned and the output variables populated as described +** above. +*/ +SQLITE_API int sqlite3changeset_pk( + sqlite3_changeset_iter *pIter, /* Iterator object */ + unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ + int *pnCol /* OUT: Number of entries in output array */ +); + +/* +** CAPI3REF: Obtain old.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** original row values stored as part of the UPDATE or DELETE change and +** returns SQLITE_OK. The name of the function comes from the fact that this +** is similar to the "old.*" columns available to update or delete triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_old( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain new.* Values From A Changeset Iterator +** +** The pIter argument passed to this function may either be an iterator +** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator +** created by [sqlite3changeset_start()]. In the latter case, the most recent +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** Furthermore, it may only be called if the type of change that the iterator +** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, +** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the vector of +** new row values stored as part of the UPDATE or INSERT change and +** returns SQLITE_OK. If the change is an UPDATE and does not include +** a new value for the requested column, *ppValue is set to NULL and +** SQLITE_OK returned. The name of the function comes from the fact that +** this is similar to the "new.*" columns available to update or delete +** triggers. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_new( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ +); + +/* +** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator +** +** This function should only be used with iterator objects passed to a +** conflict-handler callback by [sqlite3changeset_apply()] with either +** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function +** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue +** is set to NULL. +** +** Argument iVal must be greater than or equal to 0, and less than the number +** of columns in the table affected by the current change. Otherwise, +** [SQLITE_RANGE] is returned and *ppValue is set to NULL. +** +** If successful, this function sets *ppValue to point to a protected +** sqlite3_value object containing the iVal'th value from the +** "conflicting row" associated with the current conflict-handler callback +** and returns SQLITE_OK. +** +** If some other error occurs (e.g. an OOM condition), an SQLite error code +** is returned and *ppValue is set to NULL. +*/ +SQLITE_API int sqlite3changeset_conflict( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Value from conflicting row */ +); + +/* +** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations +** +** This function may only be called with an iterator passed to an +** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case +** it sets the output variable to the total number of known foreign key +** violations in the destination database and returns SQLITE_OK. +** +** In all other cases this function returns SQLITE_MISUSE. +*/ +SQLITE_API int sqlite3changeset_fk_conflicts( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int *pnOut /* OUT: Number of FK violations */ +); + + +/* +** CAPI3REF: Finalize A Changeset Iterator +** +** This function is used to finalize an iterator allocated with +** [sqlite3changeset_start()]. +** +** This function should only be called on iterators created using the +** [sqlite3changeset_start()] function. If an application calls this +** function with an iterator passed to a conflict-handler by +** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the +** call has no effect. +** +** If an error was encountered within a call to an sqlite3changeset_xxx() +** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an +** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding +** to that error is returned by this function. Otherwise, SQLITE_OK is +** returned. This is to allow the following pattern (pseudo-code): +** +** sqlite3changeset_start(); +** while( SQLITE_ROW==sqlite3changeset_next() ){ +** // Do something with change. +** } +** rc = sqlite3changeset_finalize(); +** if( rc!=SQLITE_OK ){ +** // An error has occurred +** } +*/ +SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); + +/* +** CAPI3REF: Invert A Changeset +** +** This function is used to "invert" a changeset object. Applying an inverted +** changeset to a database reverses the effects of applying the uninverted +** changeset. Specifically: +** +**
    +**
  • Each DELETE change is changed to an INSERT, and +**
  • Each INSERT change is changed to a DELETE, and +**
  • For each UPDATE change, the old.* and new.* values are exchanged. +**
+** +** This function does not change the order in which changes appear within +** the changeset. It merely reverses the sense of each individual change. +** +** If successful, a pointer to a buffer containing the inverted changeset +** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and +** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are +** zeroed and an SQLite error code returned. +** +** It is the responsibility of the caller to eventually call sqlite3_free() +** on the *ppOut pointer to free the buffer allocation following a successful +** call to this function. +** +** WARNING/TODO: This function currently assumes that the input is a valid +** changeset. If it is not, the results are undefined. +*/ +SQLITE_API int sqlite3changeset_invert( + int nIn, const void *pIn, /* Input changeset */ + int *pnOut, void **ppOut /* OUT: Inverse of input */ +); + +/* +** CAPI3REF: Concatenate Two Changeset Objects +** +** This function is used to concatenate two changesets, A and B, into a +** single changeset. The result is a changeset equivalent to applying +** changeset A followed by changeset B. +** +** This function combines the two input changesets using an +** sqlite3_changegroup object. Calling it produces similar results as the +** following code fragment: +** +** sqlite3_changegroup *pGrp; +** rc = sqlite3_changegroup_new(&pGrp); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA); +** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB); +** if( rc==SQLITE_OK ){ +** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); +** }else{ +** *ppOut = 0; +** *pnOut = 0; +** } +** +** Refer to the sqlite3_changegroup documentation below for details. +*/ +SQLITE_API int sqlite3changeset_concat( + int nA, /* Number of bytes in buffer pA */ + void *pA, /* Pointer to buffer containing changeset A */ + int nB, /* Number of bytes in buffer pB */ + void *pB, /* Pointer to buffer containing changeset B */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: Buffer containing output changeset */ +); + + +/* +** CAPI3REF: Changegroup Handle +*/ +typedef struct sqlite3_changegroup sqlite3_changegroup; + +/* +** CAPI3REF: Create A New Changegroup Object +** +** An sqlite3_changegroup object is used to combine two or more changesets +** (or patchsets) into a single changeset (or patchset). A single changegroup +** object may combine changesets or patchsets, but not both. The output is +** always in the same format as the input. +** +** If successful, this function returns SQLITE_OK and populates (*pp) with +** a pointer to a new sqlite3_changegroup object before returning. The caller +** should eventually free the returned object using a call to +** sqlite3changegroup_delete(). If an error occurs, an SQLite error code +** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. +** +** The usual usage pattern for an sqlite3_changegroup object is as follows: +** +**
    +**
  • It is created using a call to sqlite3changegroup_new(). +** +**
  • Zero or more changesets (or patchsets) are added to the object +** by calling sqlite3changegroup_add(). +** +**
  • The result of combining all input changesets together is obtained +** by the application via a call to sqlite3changegroup_output(). +** +**
  • The object is deleted using a call to sqlite3changegroup_delete(). +**
+** +** Any number of calls to add() and output() may be made between the calls to +** new() and delete(), and in any order. +** +** As well as the regular sqlite3changegroup_add() and +** sqlite3changegroup_output() functions, also available are the streaming +** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). +*/ +SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); + +/* +** CAPI3REF: Add A Changeset To A Changegroup +** +** Add all changes within the changeset (or patchset) in buffer pData (size +** nData bytes) to the changegroup. +** +** If the buffer contains a patchset, then all prior calls to this function +** on the same changegroup object must also have specified patchsets. Or, if +** the buffer contains a changeset, so must have the earlier calls to this +** function. Otherwise, SQLITE_ERROR is returned and no changes are added +** to the changegroup. +** +** Rows within the changeset and changegroup are identified by the values in +** their PRIMARY KEY columns. A change in the changeset is considered to +** apply to the same row as a change already present in the changegroup if +** the two rows have the same primary key. +** +** Changes to rows that do not already appear in the changegroup are +** simply copied into it. Or, if both the new changeset and the changegroup +** contain changes that apply to a single row, the final contents of the +** changegroup depends on the type of each change, as follows: +** +** +** +** +**
Existing Change New Change Output Change +**
INSERT INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
INSERT UPDATE +** The INSERT change remains in the changegroup. The values in the +** INSERT change are modified as if the row was inserted by the +** existing change and then updated according to the new change. +**
INSERT DELETE +** The existing INSERT is removed from the changegroup. The DELETE is +** not added. +**
UPDATE INSERT +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
UPDATE UPDATE +** The existing UPDATE remains within the changegroup. It is amended +** so that the accompanying values are as if the row was updated once +** by the existing change and then again by the new change. +**
UPDATE DELETE +** The existing UPDATE is replaced by the new DELETE within the +** changegroup. +**
DELETE INSERT +** If one or more of the column values in the row inserted by the +** new change differ from those in the row deleted by the existing +** change, the existing DELETE is replaced by an UPDATE within the +** changegroup. Otherwise, if the inserted row is exactly the same +** as the deleted row, the existing DELETE is simply discarded. +**
DELETE UPDATE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
DELETE DELETE +** The new change is ignored. This case does not occur if the new +** changeset was recorded immediately after the changesets already +** added to the changegroup. +**
+** +** If the new changeset contains changes to a table that is already present +** in the changegroup, then the number of columns and the position of the +** primary key columns for the table must be consistent. If this is not the +** case, this function fails with SQLITE_SCHEMA. If the input changeset +** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is +** returned. Or, if an out-of-memory condition occurs during processing, this +** function returns SQLITE_NOMEM. In all cases, if an error occurs the +** final contents of the changegroup is undefined. +** +** If no error occurs, SQLITE_OK is returned. +*/ +SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); + +/* +** CAPI3REF: Obtain A Composite Changeset From A Changegroup +** +** Obtain a buffer containing a changeset (or patchset) representing the +** current contents of the changegroup. If the inputs to the changegroup +** were themselves changesets, the output is a changeset. Or, if the +** inputs were patchsets, the output is also a patchset. +** +** As with the output of the sqlite3session_changeset() and +** sqlite3session_patchset() functions, all changes related to a single +** table are grouped together in the output of this function. Tables appear +** in the same order as for the very first changeset added to the changegroup. +** If the second or subsequent changesets added to the changegroup contain +** changes for tables that do not appear in the first changeset, they are +** appended onto the end of the output changeset, again in the order in +** which they are first encountered. +** +** If an error occurs, an SQLite error code is returned and the output +** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK +** is returned and the output variables are set to the size of and a +** pointer to the output buffer, respectively. In this case it is the +** responsibility of the caller to eventually free the buffer using a +** call to sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_output( + sqlite3_changegroup*, + int *pnData, /* OUT: Size of output buffer in bytes */ + void **ppData /* OUT: Pointer to output buffer */ +); + +/* +** CAPI3REF: Delete A Changegroup Object +*/ +SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); + +/* +** CAPI3REF: Apply A Changeset To A Database +** +** Apply a changeset to a database. This function attempts to update the +** "main" database attached to handle db with the changes found in the +** changeset passed via the second and third arguments. +** +** The fourth argument (xFilter) passed to this function is the "filter +** callback". If it is not NULL, then for each table affected by at least one +** change in the changeset, the filter callback is invoked with +** the table name as the second argument, and a copy of the context pointer +** passed as the sixth argument to this function as the first. If the "filter +** callback" returns zero, then no attempt is made to apply any changes to +** the table. Otherwise, if the return value is non-zero or the xFilter +** argument to this function is NULL, all changes related to the table are +** attempted. +** +** For each table that is not excluded by the filter callback, this function +** tests that the target database contains a compatible table. A table is +** considered compatible if all of the following are true: +** +**
    +**
  • The table has the same name as the name recorded in the +** changeset, and +**
  • The table has at least as many columns as recorded in the +** changeset, and +**
  • The table has primary key columns in the same position as +** recorded in the changeset. +**
+** +** If there is no compatible table, it is not an error, but none of the +** changes associated with the table are applied. A warning message is issued +** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most +** one such warning is issued for each table in the changeset. +** +** For each change for which there is a compatible table, an attempt is made +** to modify the table contents according to the UPDATE, INSERT or DELETE +** change. If a change cannot be applied cleanly, the conflict handler +** function passed as the fifth argument to sqlite3changeset_apply() may be +** invoked. A description of exactly when the conflict handler is invoked for +** each type of change is below. +** +** Unlike the xFilter argument, xConflict may not be passed NULL. The results +** of passing anything other than a valid function pointer as the xConflict +** argument are undefined. +** +** Each time the conflict handler function is invoked, it must return one +** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or +** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned +** if the second argument passed to the conflict handler is either +** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler +** returns an illegal value, any changes already made are rolled back and +** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different +** actions are taken by sqlite3changeset_apply() depending on the value +** returned by each invocation of the conflict-handler function. Refer to +** the documentation for the three +** [SQLITE_CHANGESET_OMIT|available return values] for details. +** +**
+**
DELETE Changes
+** For each DELETE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all non-primary key columns also match the values stored in +** the changeset the row is deleted from the target database. +** +** If a row with matching primary key values is found, but one or more of +** the non-primary key fields contains a value different from the original +** row value stored in the changeset, the conflict-handler function is +** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the +** database table has more columns than are recorded in the changeset, +** only the values of those non-primary key fields are compared against +** the current database contents - any trailing database table columns +** are ignored. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT +** (which can only happen if a foreign key constraint is violated), the +** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT] +** passed as the second argument. This includes the case where the DELETE +** operation is attempted because an earlier call to the conflict handler +** function returned [SQLITE_CHANGESET_REPLACE]. +** +**
INSERT Changes
+** For each INSERT change, an attempt is made to insert the new row into +** the database. If the changeset row contains fewer fields than the +** database table, the trailing fields are populated with their default +** values. +** +** If the attempt to insert the row fails because the database already +** contains a row with the same primary key values, the conflict handler +** function is invoked with the second argument set to +** [SQLITE_CHANGESET_CONFLICT]. +** +** If the attempt to insert the row fails because of some other constraint +** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is +** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. +** This includes the case where the INSERT operation is re-attempted because +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +** +**
UPDATE Changes
+** For each UPDATE change, this function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all modified non-primary key columns also match the values +** stored in the changeset the row is updated within the target database. +** +** If a row with matching primary key values is found, but one or more of +** the modified non-primary key fields contains a value different from an +** original row value stored in the changeset, the conflict-handler function +** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since +** UPDATE changes only contain values for non-primary key fields that are +** to be modified, only those fields need to match the original values to +** avoid the SQLITE_CHANGESET_DATA conflict-handler callback. +** +** If no row with matching primary key values is found in the database, +** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] +** passed as the second argument. +** +** If the UPDATE operation is attempted, but SQLite returns +** SQLITE_CONSTRAINT, the conflict-handler function is invoked with +** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. +** This includes the case where the UPDATE operation is attempted after +** an earlier call to the conflict handler function returned +** [SQLITE_CHANGESET_REPLACE]. +**
+** +** It is safe to execute SQL statements, including those that write to the +** table that the callback related to, from within the xConflict callback. +** This can be used to further customize the applications conflict +** resolution strategy. +** +** All changes made by this function are enclosed in a savepoint transaction. +** If any other error (aside from a constraint failure when attempting to +** write to the target database) occurs, then the savepoint transaction is +** rolled back, restoring the target database to its original state, and an +** SQLite error code returned. +*/ +SQLITE_API int sqlite3changeset_apply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); + +/* +** CAPI3REF: Constants Passed To The Conflict Handler +** +** Values that may be passed as the second argument to a conflict-handler. +** +**
+**
SQLITE_CHANGESET_DATA
+** The conflict handler is invoked with CHANGESET_DATA as the second argument +** when processing a DELETE or UPDATE change if a row with the required +** PRIMARY KEY fields is present in the database, but one or more other +** (non primary-key) fields modified by the update do not contain the +** expected "before" values. +** +** The conflicting row, in this case, is the database row with the matching +** primary key. +** +**
SQLITE_CHANGESET_NOTFOUND
+** The conflict handler is invoked with CHANGESET_NOTFOUND as the second +** argument when processing a DELETE or UPDATE change if a row with the +** required PRIMARY KEY fields is not present in the database. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
SQLITE_CHANGESET_CONFLICT
+** CHANGESET_CONFLICT is passed as the second argument to the conflict +** handler while processing an INSERT change if the operation would result +** in duplicate primary key values. +** +** The conflicting row in this case is the database row with the matching +** primary key. +** +**
SQLITE_CHANGESET_FOREIGN_KEY
+** If foreign key handling is enabled, and applying a changeset leaves the +** database in a state containing foreign key violations, the conflict +** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument +** exactly once before the changeset is committed. If the conflict handler +** returns CHANGESET_OMIT, the changes, including those that caused the +** foreign key constraint violation, are committed. Or, if it returns +** CHANGESET_ABORT, the changeset is rolled back. +** +** No current or conflicting row information is provided. The only function +** it is possible to call on the supplied sqlite3_changeset_iter handle +** is sqlite3changeset_fk_conflicts(). +** +**
SQLITE_CHANGESET_CONSTRAINT
+** If any other constraint violation occurs while applying a change (i.e. +** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is +** invoked with CHANGESET_CONSTRAINT as the second argument. +** +** There is no conflicting row in this case. The results of invoking the +** sqlite3changeset_conflict() API are undefined. +** +**
+*/ +#define SQLITE_CHANGESET_DATA 1 +#define SQLITE_CHANGESET_NOTFOUND 2 +#define SQLITE_CHANGESET_CONFLICT 3 +#define SQLITE_CHANGESET_CONSTRAINT 4 +#define SQLITE_CHANGESET_FOREIGN_KEY 5 + +/* +** CAPI3REF: Constants Returned By The Conflict Handler +** +** A conflict handler callback must return one of the following three values. +** +**
+**
SQLITE_CHANGESET_OMIT
+** If a conflict handler returns this value no special action is taken. The +** change that caused the conflict is not applied. The session module +** continues to the next change in the changeset. +** +**
SQLITE_CHANGESET_REPLACE
+** This value may only be returned if the second argument to the conflict +** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this +** is not the case, any changes applied so far are rolled back and the +** call to sqlite3changeset_apply() returns SQLITE_MISUSE. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict +** handler, then the conflicting row is either updated or deleted, depending +** on the type of change. +** +** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict +** handler, then the conflicting row is removed from the database and a +** second attempt to apply the change is made. If this second attempt fails, +** the original row is restored to the database before continuing. +** +**
SQLITE_CHANGESET_ABORT
+** If this value is returned, any changes applied so far are rolled back +** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. +**
+*/ +#define SQLITE_CHANGESET_OMIT 0 +#define SQLITE_CHANGESET_REPLACE 1 +#define SQLITE_CHANGESET_ABORT 2 + +/* +** CAPI3REF: Streaming Versions of API functions. +** +** The six streaming API xxx_strm() functions serve similar purposes to the +** corresponding non-streaming API functions: +** +** +** +**
Streaming functionNon-streaming equivalent
sqlite3changeset_apply_str[sqlite3changeset_apply] +**
sqlite3changeset_concat_str[sqlite3changeset_concat] +**
sqlite3changeset_invert_str[sqlite3changeset_invert] +**
sqlite3changeset_start_str[sqlite3changeset_start] +**
sqlite3session_changeset_str[sqlite3session_changeset] +**
sqlite3session_patchset_str[sqlite3session_patchset] +**
+** +** Non-streaming functions that accept changesets (or patchsets) as input +** require that the entire changeset be stored in a single buffer in memory. +** Similarly, those that return a changeset or patchset do so by returning +** a pointer to a single large buffer allocated using sqlite3_malloc(). +** Normally this is convenient. However, if an application running in a +** low-memory environment is required to handle very large changesets, the +** large contiguous memory allocations required can become onerous. +** +** In order to avoid this problem, instead of a single large buffer, input +** is passed to a streaming API functions by way of a callback function that +** the sessions module invokes to incrementally request input data as it is +** required. In all cases, a pair of API function parameters such as +** +**
+**        int nChangeset,
+**        void *pChangeset,
+**  
+** +** Is replaced by: +** +**
+**        int (*xInput)(void *pIn, void *pData, int *pnData),
+**        void *pIn,
+**  
+** +** Each time the xInput callback is invoked by the sessions module, the first +** argument passed is a copy of the supplied pIn context pointer. The second +** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no +** error occurs the xInput method should copy up to (*pnData) bytes of data +** into the buffer and set (*pnData) to the actual number of bytes copied +** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) +** should be set to zero to indicate this. Or, if an error occurs, an SQLite +** error code should be returned. In all cases, if an xInput callback returns +** an error, all processing is abandoned and the streaming API function +** returns a copy of the error code to the caller. +** +** In the case of sqlite3changeset_start_strm(), the xInput callback may be +** invoked by the sessions module at any point during the lifetime of the +** iterator. If such an xInput callback returns an error, the iterator enters +** an error state, whereby all subsequent calls to iterator functions +** immediately fail with the same error code as returned by xInput. +** +** Similarly, streaming API functions that return changesets (or patchsets) +** return them in chunks by way of a callback function instead of via a +** pointer to a single large buffer. In this case, a pair of parameters such +** as: +** +**
+**        int *pnChangeset,
+**        void **ppChangeset,
+**  
+** +** Is replaced by: +** +**
+**        int (*xOutput)(void *pOut, const void *pData, int nData),
+**        void *pOut
+**  
+** +** The xOutput callback is invoked zero or more times to return data to +** the application. The first parameter passed to each call is a copy of the +** pOut pointer supplied by the application. The second parameter, pData, +** points to a buffer nData bytes in size containing the chunk of output +** data being returned. If the xOutput callback successfully processes the +** supplied data, it should return SQLITE_OK to indicate success. Otherwise, +** it should return some other SQLite error code. In this case processing +** is immediately abandoned and the streaming API function returns a copy +** of the xOutput error code to the application. +** +** The sessions module never invokes an xOutput callback with the third +** parameter set to a value less than or equal to zero. Other than this, +** no guarantees are made as to the size of the chunks of data returned. +*/ +SQLITE_API int sqlite3changeset_apply_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +); +SQLITE_API int sqlite3changeset_concat_strm( + int (*xInputA)(void *pIn, void *pData, int *pnData), + void *pInA, + int (*xInputB)(void *pIn, void *pData, int *pnData), + void *pInB, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changeset_invert_strm( + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changeset_start_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +SQLITE_API int sqlite3session_changeset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3session_patchset_strm( + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn +); +SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); + + +/* +** Make sure we can call this stuff from C++. +*/ +#if 0 +} +#endif + +#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ + +/******** End of sqlite3session.h *********/ +/******** Begin file fts5.h *********/ +/* +** 2014 May 31 +** +** 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. +** +****************************************************************************** +** +** Interfaces to extend FTS5. Using the interfaces defined in this file, +** FTS5 may be extended with: +** +** * custom tokenizers, and +** * custom auxiliary functions. +*/ + + +#ifndef _FTS5_H +#define _FTS5_H + + +#if 0 +extern "C" { +#endif + +/************************************************************************* +** CUSTOM AUXILIARY FUNCTIONS +** +** Virtual table implementations may overload SQL functions by implementing +** the sqlite3_module.xFindFunction() method. +*/ + +typedef struct Fts5ExtensionApi Fts5ExtensionApi; +typedef struct Fts5Context Fts5Context; +typedef struct Fts5PhraseIter Fts5PhraseIter; + +typedef void (*fts5_extension_function)( + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ +); + +struct Fts5PhraseIter { + const unsigned char *a; + const unsigned char *b; +}; + +/* +** EXTENSION API FUNCTIONS +** +** xUserData(pFts): +** Return a copy of the context pointer the extension function was +** registered with. +** +** xColumnTotalSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the FTS5 table. Or, if iCol is +** non-negative but less than the number of columns in the table, return +** the total number of tokens in column iCol, considering all rows in +** the FTS5 table. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** xColumnCount(pFts): +** Return the number of columns in the table. +** +** xColumnSize(pFts, iCol, pnToken): +** If parameter iCol is less than zero, set output variable *pnToken +** to the total number of tokens in the current row. Or, if iCol is +** non-negative but less than the number of columns in the table, set +** *pnToken to the number of tokens in column iCol of the current row. +** +** If parameter iCol is greater than or equal to the number of columns +** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. +** an OOM condition or IO error), an appropriate SQLite error code is +** returned. +** +** This function may be quite inefficient if used with an FTS5 table +** created with the "columnsize=0" option. +** +** xColumnText: +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer +** containing the text in utf-8 encoding, (*pn) is set to the size in bytes +** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, +** if an error occurs, an SQLite error code is returned and the final values +** of (*pz) and (*pn) are undefined. +** +** xPhraseCount: +** Returns the number of phrases in the current query expression. +** +** xPhraseSize: +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. +** +** xInstCount: +** Set *pnInst to the total number of occurrences of all phrases within +** the query within the current row. Return SQLITE_OK if successful, or +** an error code (i.e. SQLITE_NOMEM) if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always returns 0. +** +** xInst: +** Query for the details of phrase match iIdx within the current row. +** Phrase matches are numbered starting from zero, so the iIdx argument +** should be greater than or equal to zero and smaller than the value +** output by xInstCount(). +** +** Usually, output parameter *piPhrase is set to the phrase number, *piCol +** to the column in which it occurs and *piOff the token offset of the +** first token of the phrase. The exception is if the table was created +** with the offsets=0 option specified. In this case *piOff is always +** set to -1. +** +** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) +** if an error occurs. +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. +** +** xRowid: +** Returns the rowid of the current row. +** +** xTokenize: +** Tokenize text using the tokenizer belonging to the FTS5 table. +** +** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): +** This API function is used to query the FTS table for phrase iPhrase +** of the current query. Specifically, a query equivalent to: +** +** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid +** +** with $p set to a phrase equivalent to the phrase iPhrase of the +** current query is executed. Any column filter that applies to +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback +** function may be used to access the properties of each matched row. +** Invoking Api.xUserData() returns a copy of the pointer passed as +** the third argument to pUserData. +** +** If the callback function returns any value other than SQLITE_OK, the +** query is abandoned and the xQueryPhrase function returns immediately. +** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. +** Otherwise, the error code is propagated upwards. +** +** If the query runs to completion without incident, SQLITE_OK is returned. +** Or, if some error occurs before the query completes or is aborted by +** the callback, an SQLite error code is returned. +** +** +** xSetAuxdata(pFts5, pAux, xDelete) +** +** Save the pointer passed as the second argument as the extension functions +** "auxiliary data". The pointer may then be retrieved by the current or any +** future invocation of the same fts5 extension function made as part of +** of the same MATCH query using the xGetAuxdata() API. +** +** Each extension function is allocated a single auxiliary data slot for +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a +** single auxiliary data context. +** +** If there is already an auxiliary data pointer when this function is +** invoked, then it is replaced by the new pointer. If an xDelete callback +** was specified along with the original pointer, it is invoked at this +** point. +** +** The xDelete callback, if one is specified, is also invoked on the +** auxiliary data pointer after the FTS5 query has finished. +** +** If an error (e.g. an OOM condition) occurs within this function, an +** the auxiliary data is set to NULL and an error code returned. If the +** xDelete parameter was not NULL, it is invoked on the auxiliary data +** pointer before returning. +** +** +** xGetAuxdata(pFts5, bClear) +** +** Returns the current auxiliary data pointer for the fts5 extension +** function. See the xSetAuxdata() method for details. +** +** If the bClear argument is non-zero, then the auxiliary data is cleared +** (set to NULL) before this function returns. In this case the xDelete, +** if any, is not invoked. +** +** +** xRowCount(pFts5, pnRow) +** +** This function is used to retrieve the total number of rows in the table. +** In other words, the same value that would be returned by: +** +** SELECT count(*) FROM ftstable; +** +** xPhraseFirst() +** This function is used, along with type Fts5PhraseIter and the xPhraseNext +** method, to iterate through all instances of a single query phrase within +** the current row. This is the same information as is accessible via the +** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient +** to use, this API may be faster under some circumstances. To iterate +** through instances of phrase iPhrase, use the following code: +** +** Fts5PhraseIter iter; +** int iCol, iOff; +** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); +** iCol>=0; +** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) +** ){ +** // An instance of phrase iPhrase at offset iOff of column iCol +** } +** +** The Fts5PhraseIter structure is defined above. Applications should not +** modify this structure directly - it should only be used as shown above +** with the xPhraseFirst() and xPhraseNext() API methods (and by +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option +** (i.e. if it is a contentless table), then this API always iterates +** through an empty set (all calls to xPhraseFirst() set iCol to -1). +** +** xPhraseNext() +** See xPhraseFirst above. +** +** xPhraseFirstColumn() +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() +** and xPhraseNext() APIs described above. The difference is that instead +** of iterating through all instances of a phrase in the current row, these +** APIs are used to iterate through the set of columns in the current row +** that contain one or more instances of a specified phrase. For example: +** +** Fts5PhraseIter iter; +** int iCol; +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); +** iCol>=0; +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) +** ){ +** // Column iCol contains at least one instance of phrase iPhrase +** } +** +** This API can be quite slow if used with an FTS5 table created with the +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to +** xPhraseFirstColumn() set iCol to -1). +** +** The information accessed using this API and its companion +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext +** (or xInst/xInstCount). The chief advantage of this API is that it is +** significantly more efficient than those alternatives when used with +** "detail=column" tables. +** +** xPhraseNextColumn() +** See xPhraseFirstColumn above. +*/ +struct Fts5ExtensionApi { + int iVersion; /* Currently always set to 3 */ + + void *(*xUserData)(Fts5Context*); + + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); + + int (*xTokenize)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); + + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); + + int (*xInstCount)(Fts5Context*, int *pnInst); + int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); + + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); + + int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, + int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) + ); + int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); + void *(*xGetAuxdata)(Fts5Context*, int bClear); + + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); +}; + +/* +** CUSTOM AUXILIARY FUNCTIONS +*************************************************************************/ + +/************************************************************************* +** CUSTOM TOKENIZERS +** +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the +** following structure. All structure methods must be defined, setting +** any member of the fts5_tokenizer struct to NULL leads to undefined +** behaviour. The structure methods are expected to function as follows: +** +** xCreate: +** This function is used to allocate and initialize a tokenizer instance. +** A tokenizer instance is required to actually tokenize text. +** +** The first argument passed to this function is a copy of the (void*) +** pointer provided by the application when the fts5_tokenizer object +** was registered with FTS5 (the third argument to xCreateTokenizer()). +** The second and third arguments are an array of nul-terminated strings +** containing the tokenizer arguments, if any, specified following the +** tokenizer name as part of the CREATE VIRTUAL TABLE statement used +** to create the FTS5 table. +** +** The final argument is an output variable. If successful, (*ppOut) +** should be set to point to the new tokenizer handle and SQLITE_OK +** returned. If an error occurs, some value other than SQLITE_OK should +** be returned. In this case, fts5 assumes that the final value of *ppOut +** is undefined. +** +** xDelete: +** This function is invoked to delete a tokenizer handle previously +** allocated using xCreate(). Fts5 guarantees that this function will +** be invoked exactly once for each successful call to xCreate(). +** +** xTokenize: +** This function is expected to tokenize the nText byte string indicated +** by argument pText. pText may or may not be nul-terminated. The first +** argument passed to this function is a pointer to an Fts5Tokenizer object +** returned by an earlier call to xCreate(). +** +** The second argument indicates the reason that FTS5 is requesting +** tokenization of the supplied text. This is always one of the following +** four values: +** +**
  • FTS5_TOKENIZE_DOCUMENT - A document is being inserted into +** or removed from the FTS table. The tokenizer is being invoked to +** determine the set of tokens to add to (or delete from) the +** FTS index. +** +**
  • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize +** a bareword or quoted string specified as part of the query. +** +**
  • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as +** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is +** followed by a "*" character, indicating that the last token +** returned by the tokenizer will be treated as a token prefix. +** +**
  • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +** satisfy an fts5_api.xTokenize() request made by an auxiliary +** function. Or an fts5_api.xColumnSize() request made by the same +** on a columnsize=0 database. +**
+** +** For each token in the input string, the supplied callback xToken() must +** be invoked. The first argument to it should be a copy of the pointer +** passed as the second argument to xTokenize(). The third and fourth +** arguments are a pointer to a buffer containing the token text, and the +** size of the token in bytes. The 4th and 5th arguments are the byte offsets +** of the first byte of and first byte immediately following the text from +** which the token is derived within the input. +** +** The second argument passed to the xToken() callback ("tflags") should +** normally be set to 0. The exception is if the tokenizer supports +** synonyms. In this case see the discussion below for details. +** +** FTS5 assumes the xToken() callback is invoked for each token in the +** order that they occur within the input text. +** +** If an xToken() callback returns any value other than SQLITE_OK, then +** the tokenization should be abandoned and the xTokenize() method should +** immediately return a copy of the xToken() return value. Or, if the +** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, +** if an error occurs with the xTokenize() implementation itself, it +** may abandon the tokenization and return any error code other than +** SQLITE_OK or SQLITE_DONE. +** +** SYNONYM SUPPORT +** +** Custom tokenizers may also support synonyms. Consider a case in which a +** user wishes to query for a phrase such as "first place". Using the +** built-in tokenizers, the FTS5 query 'first + place' will match instances +** of "first place" within the document set, but not alternative forms +** such as "1st place". In some applications, it would be better to match +** all instances of "first place" or "1st place" regardless of which form +** the user specified in the MATCH query text. +** +** There are several ways to approach this in FTS5: +** +**
  1. By mapping all synonyms to a single token. In this case, the +** In the above example, this means that the tokenizer returns the +** same token for inputs "first" and "1st". Say that token is in +** fact "first", so that when the user inserts the document "I won +** 1st place" entries are added to the index for tokens "i", "won", +** "first" and "place". If the user then queries for '1st + place', +** the tokenizer substitutes "first" for "1st" and the query works +** as expected. +** +**
  2. By adding multiple synonyms for a single term to the FTS index. +** In this case, when tokenizing query text, the tokenizer may +** provide multiple synonyms for a single term within the document. +** FTS5 then queries the index for each synonym individually. For +** example, faced with the query: +** +** +** ... MATCH 'first place' +** +** the tokenizer offers both "1st" and "first" as synonyms for the +** first token in the MATCH query and FTS5 effectively runs a query +** similar to: +** +** +** ... MATCH '(first OR 1st) place' +** +** except that, for the purposes of auxiliary functions, the query +** still appears to contain just two phrases - "(first OR 1st)" +** being treated as a single phrase. +** +**
  3. By adding multiple synonyms for a single term to the FTS index. +** Using this method, when tokenizing document text, the tokenizer +** provides multiple synonyms for each token. So that when a +** document such as "I won first place" is tokenized, entries are +** added to the FTS index for "i", "won", "first", "1st" and +** "place". +** +** This way, even if the tokenizer does not provide synonyms +** when tokenizing query text (it should not - to do would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entires in the +** FTS index corresponding to both forms of the first token. +**
+** +** Whether it is parsing document or query text, any call to xToken that +** specifies a tflags argument with the FTS5_TOKEN_COLOCATED bit +** is considered to supply a synonym for the previous token. For example, +** when parsing the document "I won first place", a tokenizer that supports +** synonyms would call xToken() 5 times, as follows: +** +** +** xToken(pCtx, 0, "i", 1, 0, 1); +** xToken(pCtx, 0, "won", 3, 2, 5); +** xToken(pCtx, 0, "first", 5, 6, 11); +** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11); +** xToken(pCtx, 0, "place", 5, 12, 17); +** +** +** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time +** xToken() is called. Multiple synonyms may be specified for a single token +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** There is no limit to the number of synonyms that may be provided for a +** single token. +** +** In many cases, method (1) above is the best approach. It does not add +** extra data to the FTS index or require FTS5 to query for multiple terms, +** so it is efficient in terms of disk space and query speed. However, it +** does not support prefix queries very well. If, as suggested above, the +** token "first" is subsituted for "1st" by the tokenizer, then the query: +** +** +** ... MATCH '1s*' +** +** will not match documents that contain the token "1st" (as the tokenizer +** will probably not map "1s" to any prefix of "first"). +** +** For full prefix support, method (3) may be preferred. In this case, +** because the index contains entries for both "first" and "1st", prefix +** queries such as 'fi*' or '1s*' will match correctly. However, because +** extra entries are added to the FTS index, this method uses more space +** within the database. +** +** Method (2) offers a midpoint between (1) and (3). Using this method, +** a query such as '1s*' will match documents that contain the literal +** token "1st", but not "first" (assuming the tokenizer is not able to +** provide synonyms for prefixes). However, a non-prefix query like '1st' +** will match against "1st" and "first". This method does not require +** extra disk space, as no extra entries are added to the FTS index. +** On the other hand, it may require more CPU cycles to run MATCH queries, +** as separate queries of the FTS index are required for each synonym. +** +** When using methods (2) or (3), it is important that the tokenizer only +** provide synonyms when tokenizing document text (method (2)) or query +** text (method (3)), not both. Doing so will not cause any errors, but is +** inefficient. +*/ +typedef struct Fts5Tokenizer Fts5Tokenizer; +typedef struct fts5_tokenizer fts5_tokenizer; +struct fts5_tokenizer { + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); +}; + +/* Flags that may be passed as the third argument to xTokenize() */ +#define FTS5_TOKENIZE_QUERY 0x0001 +#define FTS5_TOKENIZE_PREFIX 0x0002 +#define FTS5_TOKENIZE_DOCUMENT 0x0004 +#define FTS5_TOKENIZE_AUX 0x0008 + +/* Flags that may be passed by the tokenizer implementation back to FTS5 +** as the third argument to the supplied xToken callback. */ +#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */ + +/* +** END OF CUSTOM TOKENIZERS +*************************************************************************/ + +/************************************************************************* +** FTS5 EXTENSION REGISTRATION API +*/ +typedef struct fts5_api fts5_api; +struct fts5_api { + int iVersion; /* Currently always set to 2 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_tokenizer *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer)( + fts5_api *pApi, + const char *zName, + void **ppContext, + fts5_tokenizer *pTokenizer + ); + + /* Create a new auxiliary function */ + int (*xCreateFunction)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*) + ); +}; + +/* +** END OF REGISTRATION API +*************************************************************************/ + +#if 0 +} /* end of the 'extern "C"' block */ +#endif + +#endif /* _FTS5_H */ + +/******** End of fts5.h *********/ + +/************** End of sqlite3.h *********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ + +/* +** Include the configuration header output by 'configure' if we're using the +** autoconf-based build +*/ +#ifdef _HAVE_SQLITE_CONFIG_H +#include "config.h" +#endif + +/************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ +/************** Begin file sqliteLimit.h *************************************/ +/* +** 2007 May 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 defines various limits of what SQLite can process. +*/ + +/* +** The maximum length of a TEXT or BLOB in bytes. This also +** limits the size of a row in a table or index. +** +** The hard limit is the ability of a 32-bit signed integer +** to count the size: 2^31-1 or 2147483647. +*/ +#ifndef SQLITE_MAX_LENGTH +# define SQLITE_MAX_LENGTH 1000000000 +#endif + +/* +** This is the maximum number of +** +** * Columns in a table +** * Columns in an index +** * Columns in a view +** * Terms in the SET clause of an UPDATE statement +** * Terms in the result set of a SELECT statement +** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. +** * Terms in the VALUES clause of an INSERT statement +** +** The hard upper limit here is 32676. Most database people will +** tell you that in a well-normalized database, you usually should +** not have more than a dozen or so columns in any table. And if +** that is the case, there is no point in having more than a few +** dozen values in any of the other situations described above. +*/ +#ifndef SQLITE_MAX_COLUMN +# define SQLITE_MAX_COLUMN 2000 +#endif + +/* +** The maximum length of a single SQL statement in bytes. +** +** It used to be the case that setting this value to zero would +** turn the limit off. That is no longer true. It is not possible +** to turn this limit off. +*/ +#ifndef SQLITE_MAX_SQL_LENGTH +# define SQLITE_MAX_SQL_LENGTH 1000000000 +#endif + +/* +** The maximum depth of an expression tree. This is limited to +** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might +** want to place more severe limits on the complexity of an +** expression. +** +** A value of 0 used to mean that the limit was not enforced. +** But that is no longer true. The limit is now strictly enforced +** at all times. +*/ +#ifndef SQLITE_MAX_EXPR_DEPTH +# define SQLITE_MAX_EXPR_DEPTH 1000 +#endif + +/* +** The maximum number of terms in a compound SELECT statement. +** The code generator for compound SELECT statements does one +** level of recursion for each term. A stack overflow can result +** if the number of terms is too large. In practice, most SQL +** never has more than 3 or 4 terms. Use a value of 0 to disable +** any limit on the number of terms in a compount SELECT. +*/ +#ifndef SQLITE_MAX_COMPOUND_SELECT +# define SQLITE_MAX_COMPOUND_SELECT 500 +#endif + +/* +** The maximum number of opcodes in a VDBE program. +** Not currently enforced. +*/ +#ifndef SQLITE_MAX_VDBE_OP +# define SQLITE_MAX_VDBE_OP 250000000 +#endif + +/* +** The maximum number of arguments to an SQL function. +*/ +#ifndef SQLITE_MAX_FUNCTION_ARG +# define SQLITE_MAX_FUNCTION_ARG 127 +#endif + +/* +** The suggested maximum number of in-memory pages to use for +** the main database table and for temporary tables. +** +** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000, +** which means the cache size is limited to 2048000 bytes of memory. +** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be +** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options. +*/ +#ifndef SQLITE_DEFAULT_CACHE_SIZE +# define SQLITE_DEFAULT_CACHE_SIZE -2000 +#endif + +/* +** The default number of frames to accumulate in the log file before +** checkpointing the database in WAL mode. +*/ +#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT +# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000 +#endif + +/* +** The maximum number of attached databases. This must be between 0 +** and 125. The upper bound of 125 is because the attached databases are +** counted using a signed 8-bit integer which has a maximum value of 127 +** and we have to allow 2 extra counts for the "main" and "temp" databases. +*/ +#ifndef SQLITE_MAX_ATTACHED +# define SQLITE_MAX_ATTACHED 10 +#endif + + +/* +** The maximum value of a ?nnn wildcard that the parser will accept. +*/ +#ifndef SQLITE_MAX_VARIABLE_NUMBER +# define SQLITE_MAX_VARIABLE_NUMBER 999 +#endif + +/* Maximum page size. The upper bound on this value is 65536. This a limit +** imposed by the use of 16-bit offsets within each page. +** +** Earlier versions of SQLite allowed the user to change this value at +** compile time. This is no longer permitted, on the grounds that it creates +** a library that is technically incompatible with an SQLite library +** compiled with a different limit. If a process operating on a database +** with a page-size of 65536 bytes crashes, then an instance of SQLite +** compiled with the default page-size limit will not be able to rollback +** the aborted transaction. This could lead to database corruption. +*/ +#ifdef SQLITE_MAX_PAGE_SIZE +# undef SQLITE_MAX_PAGE_SIZE +#endif +#define SQLITE_MAX_PAGE_SIZE 65536 + + +/* +** The default size of a database page. +*/ +#ifndef SQLITE_DEFAULT_PAGE_SIZE +# define SQLITE_DEFAULT_PAGE_SIZE 4096 +#endif +#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE +# undef SQLITE_DEFAULT_PAGE_SIZE +# define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE +#endif + +/* +** Ordinarily, if no value is explicitly provided, SQLite creates databases +** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain +** device characteristics (sector-size and atomic write() support), +** SQLite may choose a larger value. This constant is the maximum value +** SQLite will choose on its own. +*/ +#ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE +# define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192 +#endif +#if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE +# undef SQLITE_MAX_DEFAULT_PAGE_SIZE +# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE +#endif + + +/* +** Maximum number of pages in one database file. +** +** This is really just the default value for the max_page_count pragma. +** This value can be lowered (or raised) at run-time using that the +** max_page_count macro. +*/ +#ifndef SQLITE_MAX_PAGE_COUNT +# define SQLITE_MAX_PAGE_COUNT 1073741823 +#endif + +/* +** Maximum length (in bytes) of the pattern in a LIKE or GLOB +** operator. +*/ +#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH +# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 +#endif + +/* +** Maximum depth of recursion for triggers. +** +** A value of 1 means that a trigger program will not be able to itself +** fire any triggers. A value of 0 means that no trigger programs at all +** may be executed. +*/ +#ifndef SQLITE_MAX_TRIGGER_DEPTH +# define SQLITE_MAX_TRIGGER_DEPTH 1000 +#endif + +/************** End of sqliteLimit.h *****************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ + +/* Disable nuisance warnings on Borland compilers */ +#if defined(__BORLANDC__) +#pragma warn -rch /* unreachable code */ +#pragma warn -ccc /* Condition is always true or false */ +#pragma warn -aus /* Assigned value is never used */ +#pragma warn -csu /* Comparing signed and unsigned */ +#pragma warn -spa /* Suspicious pointer arithmetic */ +#endif + +/* +** Include standard header files as necessary +*/ +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_INTTYPES_H +#include +#endif + +/* +** The following macros are used to cast pointers to integers and +** integers to pointers. The way you do this varies from one compiler +** to the next, so we have developed the following set of #if statements +** to generate appropriate macros for a wide range of compilers. +** +** The correct "ANSI" way to do this is to use the intptr_t type. +** Unfortunately, that typedef is not available on all compilers, or +** if it is available, it requires an #include of specific headers +** that vary from one machine to the next. +** +** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on +** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)). +** So we have to define the macros in different ways depending on the +** compiler. +*/ +#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ +# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) +# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) +#elif !defined(__GNUC__) /* Works for compilers other than LLVM */ +# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X]) +# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) +#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */ +# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X)) +# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X)) +#else /* Generates a warning - but it always works */ +# define SQLITE_INT_TO_PTR(X) ((void*)(X)) +# define SQLITE_PTR_TO_INT(X) ((int)(X)) +#endif + +/* +** A macro to hint to the compiler that a function should not be +** inlined. +*/ +#if defined(__GNUC__) +# define SQLITE_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define SQLITE_NOINLINE __declspec(noinline) +#else +# define SQLITE_NOINLINE +#endif + +/* +** Make sure that the compiler intrinsics we desire are enabled when +** compiling with an appropriate version of MSVC unless prevented by +** the SQLITE_DISABLE_INTRINSIC define. +*/ +#if !defined(SQLITE_DISABLE_INTRINSIC) +# if defined(_MSC_VER) && _MSC_VER>=1400 +# if !defined(_WIN32_WCE) +# include +# pragma intrinsic(_byteswap_ushort) +# pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_byteswap_uint64) +# pragma intrinsic(_ReadWriteBarrier) +# else +# include +# endif +# endif +#endif + +/* +** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. +** 0 means mutexes are permanently disable and the library is never +** threadsafe. 1 means the library is serialized which is the highest +** level of threadsafety. 2 means the library is multithreaded - multiple +** threads can use SQLite as long as no two threads try to use the same +** database connection at the same time. +** +** Older versions of SQLite used an optional THREADSAFE macro. +** We support that for legacy. +*/ +#if !defined(SQLITE_THREADSAFE) +# if defined(THREADSAFE) +# define SQLITE_THREADSAFE THREADSAFE +# else +# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */ +# endif +#endif + +/* +** Powersafe overwrite is on by default. But can be turned off using +** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option. +*/ +#ifndef SQLITE_POWERSAFE_OVERWRITE +# define SQLITE_POWERSAFE_OVERWRITE 1 +#endif + +/* +** EVIDENCE-OF: R-25715-37072 Memory allocation statistics are enabled by +** default unless SQLite is compiled with SQLITE_DEFAULT_MEMSTATUS=0 in +** which case memory allocation statistics are disabled by default. +*/ +#if !defined(SQLITE_DEFAULT_MEMSTATUS) +# define SQLITE_DEFAULT_MEMSTATUS 1 +#endif + +/* +** Exactly one of the following macros must be defined in order to +** specify which memory allocation subsystem to use. +** +** SQLITE_SYSTEM_MALLOC // Use normal system malloc() +** SQLITE_WIN32_MALLOC // Use Win32 native heap API +** SQLITE_ZERO_MALLOC // Use a stub allocator that always fails +** SQLITE_MEMDEBUG // Debugging version of system malloc() +** +** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the +** assert() macro is enabled, each call into the Win32 native heap subsystem +** will cause HeapValidate to be called. If heap validation should fail, an +** assertion will be triggered. +** +** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as +** the default. +*/ +#if defined(SQLITE_SYSTEM_MALLOC) \ + + defined(SQLITE_WIN32_MALLOC) \ + + defined(SQLITE_ZERO_MALLOC) \ + + defined(SQLITE_MEMDEBUG)>1 +# error "Two or more of the following compile-time configuration options\ + are defined but at most one is allowed:\ + SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG,\ + SQLITE_ZERO_MALLOC" +#endif +#if defined(SQLITE_SYSTEM_MALLOC) \ + + defined(SQLITE_WIN32_MALLOC) \ + + defined(SQLITE_ZERO_MALLOC) \ + + defined(SQLITE_MEMDEBUG)==0 +# define SQLITE_SYSTEM_MALLOC 1 +#endif + +/* +** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the +** sizes of memory allocations below this value where possible. +*/ +#if !defined(SQLITE_MALLOC_SOFT_LIMIT) +# define SQLITE_MALLOC_SOFT_LIMIT 1024 +#endif + +/* +** We need to define _XOPEN_SOURCE as follows in order to enable +** recursive mutexes on most Unix systems and fchmod() on OpenBSD. +** But _XOPEN_SOURCE define causes problems for Mac OS X, so omit +** it. +*/ +#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) +# define _XOPEN_SOURCE 600 +#endif + +/* +** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that +** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true, +** make it true by defining or undefining NDEBUG. +** +** Setting NDEBUG makes the code smaller and faster by disabling the +** assert() statements in the code. So we want the default action +** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG +** is set. Thus NDEBUG becomes an opt-in rather than an opt-out +** feature. +*/ +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif +#if defined(NDEBUG) && defined(SQLITE_DEBUG) +# undef NDEBUG +#endif + +/* +** Enable SQLITE_ENABLE_EXPLAIN_COMMENTS if SQLITE_DEBUG is turned on. +*/ +#if !defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) && defined(SQLITE_DEBUG) +# define SQLITE_ENABLE_EXPLAIN_COMMENTS 1 +#endif + +/* +** The testcase() macro is used to aid in coverage testing. When +** doing coverage testing, the condition inside the argument to +** testcase() must be evaluated both true and false in order to +** get full branch coverage. The testcase() macro is inserted +** to help ensure adequate test coverage in places where simple +** condition/decision coverage is inadequate. For example, testcase() +** can be used to make sure boundary values are tested. For +** bitmask tests, testcase() can be used to make sure each bit +** is significant and used at least once. On switch statements +** where multiple cases go to the same block of code, testcase() +** can insure that all cases are evaluated. +** +*/ +#ifdef SQLITE_COVERAGE_TEST +SQLITE_PRIVATE void sqlite3Coverage(int); +# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); } +#else +# define testcase(X) +#endif + +/* +** The TESTONLY macro is used to enclose variable declarations or +** other bits of code that are needed to support the arguments +** within testcase() and assert() macros. +*/ +#if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST) +# define TESTONLY(X) X +#else +# define TESTONLY(X) +#endif + +/* +** Sometimes we need a small amount of code such as a variable initialization +** to setup for a later assert() statement. We do not want this code to +** appear when assert() is disabled. The following macro is therefore +** used to contain that setup code. The "VVA" acronym stands for +** "Verification, Validation, and Accreditation". In other words, the +** code within VVA_ONLY() will only run during verification processes. +*/ +#ifndef NDEBUG +# define VVA_ONLY(X) X +#else +# define VVA_ONLY(X) +#endif + +/* +** The ALWAYS and NEVER macros surround boolean expressions which +** are intended to always be true or false, respectively. Such +** expressions could be omitted from the code completely. But they +** are included in a few cases in order to enhance the resilience +** of SQLite to unexpected behavior - to make the code "self-healing" +** or "ductile" rather than being "brittle" and crashing at the first +** hint of unplanned behavior. +** +** In other words, ALWAYS and NEVER are added for defensive code. +** +** When doing coverage testing ALWAYS and NEVER are hard-coded to +** be true and false so that the unreachable code they specify will +** not be counted as untested code. +*/ +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# 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 + +/* +** 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 +** during a normal build. The following macro can be used to disable tests +** that are always false except when SQLITE_TEST_REALLOC_STRESS is set. +*/ +#if defined(SQLITE_TEST_REALLOC_STRESS) +# define ONLY_IF_REALLOC_STRESS(X) (X) +#elif !defined(NDEBUG) +# define ONLY_IF_REALLOC_STRESS(X) ((X)?(assert(0),1):0) +#else +# define ONLY_IF_REALLOC_STRESS(X) (0) +#endif + +/* +** Declarations used for tracing the operating system interfaces. +*/ +#if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \ + (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) + extern int sqlite3OSTrace; +# define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X +# define SQLITE_HAVE_OS_TRACE +#else +# define OSTRACE(X) +# undef SQLITE_HAVE_OS_TRACE +#endif + +/* +** Is the sqlite3ErrName() function needed in the build? Currently, +** it is needed by "mutex_w32.c" (when debugging), "os_win.c" (when +** OSTRACE is enabled), and by several "test*.c" files (which are +** compiled using SQLITE_TEST). +*/ +#if defined(SQLITE_HAVE_OS_TRACE) || defined(SQLITE_TEST) || \ + (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) +# define SQLITE_NEED_ERR_NAME +#else +# undef SQLITE_NEED_ERR_NAME +#endif + +/* +** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN +*/ +#ifdef SQLITE_OMIT_EXPLAIN +# undef SQLITE_ENABLE_EXPLAIN_COMMENTS +#endif + +/* +** Return true (non-zero) if the input is an integer that is too large +** to fit in 32-bits. This macro is used inside of various testcase() +** macros to verify that we have tested SQLite for large-file support. +*/ +#define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0) + +/* +** The macro unlikely() is a hint that surrounds a boolean +** expression that is usually false. Macro likely() surrounds +** a boolean expression that is usually true. These hints could, +** in theory, be used by the compiler to generate better code, but +** currently they are just comments for human readers. +*/ +#define likely(X) (X) +#define unlikely(X) (X) + +/************** Include hash.h in the middle of sqliteInt.h ******************/ +/************** Begin file hash.h ********************************************/ +/* +** 2001 September 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This is the header file for the generic hash-table implementation +** used in SQLite. +*/ +#ifndef SQLITE_HASH_H +#define SQLITE_HASH_H + +/* Forward declarations of structures. */ +typedef struct Hash Hash; +typedef struct HashElem HashElem; + +/* A complete hash table is an instance of the following structure. +** The internals of this structure are intended to be opaque -- client +** code should not attempt to access or modify the fields of this structure +** directly. Change this structure only by using the routines below. +** However, some of the "procedures" and "functions" for modifying and +** accessing this structure are really macros, so we can't really make +** this structure opaque. +** +** All elements of the hash table are on a single doubly-linked list. +** Hash.first points to the head of this list. +** +** There are Hash.htsize buckets. Each bucket points to a spot in +** the global doubly-linked list. The contents of the bucket are the +** element pointed to plus the next _ht.count-1 elements in the list. +** +** Hash.htsize and Hash.ht may be zero. In that case lookup is done +** by a linear search of the global list. For small tables, the +** Hash.ht table is never allocated because if there are few elements +** in the table, it is faster to do a linear search than to manage +** the hash table. +*/ +struct Hash { + unsigned int htsize; /* Number of buckets in the hash table */ + unsigned int count; /* Number of entries in this table */ + HashElem *first; /* The first element of the array */ + struct _ht { /* the hash table */ + int count; /* Number of entries with this hash */ + HashElem *chain; /* Pointer to first entry with this hash */ + } *ht; +}; + +/* Each element in the hash table is an instance of the following +** structure. All elements are stored on a single doubly-linked list. +** +** Again, this structure is intended to be opaque, but it can't really +** be opaque because it is used by macros. +*/ +struct HashElem { + HashElem *next, *prev; /* Next and previous elements in the table */ + void *data; /* Data associated with this element */ + const char *pKey; /* Key associated with this element */ +}; + +/* +** Access routines. To delete, insert a NULL pointer. +*/ +SQLITE_PRIVATE void sqlite3HashInit(Hash*); +SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const char *pKey, void *pData); +SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const char *pKey); +SQLITE_PRIVATE void sqlite3HashClear(Hash*); + +/* +** Macros for looping over all elements of a hash table. The idiom is +** like this: +** +** Hash h; +** HashElem *p; +** ... +** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){ +** SomeStructure *pData = sqliteHashData(p); +** // do something with pData +** } +*/ +#define sqliteHashFirst(H) ((H)->first) +#define sqliteHashNext(E) ((E)->next) +#define sqliteHashData(E) ((E)->data) +/* #define sqliteHashKey(E) ((E)->pKey) // NOT USED */ +/* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */ + +/* +** Number of entries in a hash table +*/ +/* #define sqliteHashCount(H) ((H)->count) // NOT USED */ + +#endif /* SQLITE_HASH_H */ + +/************** End of hash.h ************************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ +/************** Include parse.h in the middle of sqliteInt.h *****************/ +/************** Begin file parse.h *******************************************/ +#define TK_SEMI 1 +#define TK_EXPLAIN 2 +#define TK_QUERY 3 +#define TK_PLAN 4 +#define TK_BEGIN 5 +#define TK_TRANSACTION 6 +#define TK_DEFERRED 7 +#define TK_IMMEDIATE 8 +#define TK_EXCLUSIVE 9 +#define TK_COMMIT 10 +#define TK_END 11 +#define TK_ROLLBACK 12 +#define TK_SAVEPOINT 13 +#define TK_RELEASE 14 +#define TK_TO 15 +#define TK_TABLE 16 +#define TK_CREATE 17 +#define TK_IF 18 +#define TK_NOT 19 +#define TK_EXISTS 20 +#define TK_TEMP 21 +#define TK_LP 22 +#define TK_RP 23 +#define TK_AS 24 +#define TK_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_BITAND 84 +#define TK_BITOR 85 +#define TK_LSHIFT 86 +#define TK_RSHIFT 87 +#define TK_PLUS 88 +#define TK_MINUS 89 +#define TK_STAR 90 +#define TK_SLASH 91 +#define TK_REM 92 +#define TK_CONCAT 93 +#define TK_COLLATE 94 +#define TK_BITNOT 95 +#define TK_INDEXED 96 +#define TK_STRING 97 +#define TK_JOIN_KW 98 +#define TK_CONSTRAINT 99 +#define TK_DEFAULT 100 +#define TK_NULL 101 +#define TK_PRIMARY 102 +#define TK_UNIQUE 103 +#define TK_CHECK 104 +#define TK_REFERENCES 105 +#define TK_AUTOINCR 106 +#define TK_ON 107 +#define TK_INSERT 108 +#define TK_DELETE 109 +#define TK_UPDATE 110 +#define TK_SET 111 +#define TK_DEFERRABLE 112 +#define TK_FOREIGN 113 +#define TK_DROP 114 +#define TK_UNION 115 +#define TK_ALL 116 +#define TK_EXCEPT 117 +#define TK_INTERSECT 118 +#define TK_SELECT 119 +#define TK_VALUES 120 +#define TK_DISTINCT 121 +#define TK_DOT 122 +#define TK_FROM 123 +#define TK_JOIN 124 +#define TK_USING 125 +#define TK_ORDER 126 +#define TK_GROUP 127 +#define TK_HAVING 128 +#define TK_LIMIT 129 +#define TK_WHERE 130 +#define TK_INTO 131 +#define TK_FLOAT 132 +#define TK_BLOB 133 +#define TK_INTEGER 134 +#define TK_VARIABLE 135 +#define TK_CASE 136 +#define TK_WHEN 137 +#define TK_THEN 138 +#define TK_ELSE 139 +#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 + +/* The token codes above must all fit in 8 bits */ +#define TKFLG_MASK 0xff + +/* Flags that can be added to a token code when it is not +** being stored in a u8: */ +#define TKFLG_DONTFOLD 0x100 /* Omit constant folding optimizations */ + +/************** End of parse.h ***********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ +#include +#include +#include +#include +#include + +/* +** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY. +** This allows better measurements of where memcpy() is used when running +** cachegrind. But this macro version of memcpy() is very slow so it +** should not be used in production. This is a performance measurement +** hack only. +*/ +#ifdef SQLITE_INLINE_MEMCPY +# define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\ + int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);} +#endif + +/* +** If compiling for a processor that lacks floating point support, +** substitute integer for floating-point +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# define double sqlite_int64 +# define float sqlite_int64 +# define LONGDOUBLE_TYPE sqlite_int64 +# ifndef SQLITE_BIG_DBL +# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) +# endif +# define SQLITE_OMIT_DATETIME_FUNCS 1 +# define SQLITE_OMIT_TRACE 1 +# undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT +# undef SQLITE_HAVE_ISNAN +#endif +#ifndef SQLITE_BIG_DBL +# define SQLITE_BIG_DBL (1e99) +#endif + +/* +** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0 +** afterward. Having this macro allows us to cause the C compiler +** to omit code used by TEMP tables without messy #ifndef statements. +*/ +#ifdef SQLITE_OMIT_TEMPDB +#define OMIT_TEMPDB 1 +#else +#define OMIT_TEMPDB 0 +#endif + +/* +** The "file format" number is an integer that is incremented whenever +** the VDBE-level file format changes. The following macros define the +** the default file format for new databases and the maximum file format +** that the library can read. +*/ +#define SQLITE_MAX_FILE_FORMAT 4 +#ifndef SQLITE_DEFAULT_FILE_FORMAT +# define SQLITE_DEFAULT_FILE_FORMAT 4 +#endif + +/* +** Determine whether triggers are recursive by default. This can be +** changed at run-time using a pragma. +*/ +#ifndef SQLITE_DEFAULT_RECURSIVE_TRIGGERS +# define SQLITE_DEFAULT_RECURSIVE_TRIGGERS 0 +#endif + +/* +** Provide a default value for SQLITE_TEMP_STORE in case it is not specified +** on the command-line +*/ +#ifndef SQLITE_TEMP_STORE +# define SQLITE_TEMP_STORE 1 +# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ +#endif + +/* +** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if +** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it +** to zero. +*/ +#if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0 +# undef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS 0 +#endif +#ifndef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS 8 +#endif +#ifndef SQLITE_DEFAULT_WORKER_THREADS +# define SQLITE_DEFAULT_WORKER_THREADS 0 +#endif +#if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS +# undef SQLITE_MAX_WORKER_THREADS +# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS +#endif + +/* +** The default initial allocation for the pagecache when using separate +** pagecaches for each database connection. A positive number is the +** number of pages. A negative number N translations means that a buffer +** of -1024*N bytes is allocated and used for as many pages as it will hold. +** +** The default value of "20" was choosen to minimize the run-time of the +** speedtest1 test program with options: --shrink-memory --reprepare +*/ +#ifndef SQLITE_DEFAULT_PCACHE_INITSZ +# define SQLITE_DEFAULT_PCACHE_INITSZ 20 +#endif + +/* +** GCC does not define the offsetof() macro so we'll have to do it +** ourselves. +*/ +#ifndef offsetof +#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) +#endif + +/* +** Macros to compute minimum and maximum of two numbers. +*/ +#ifndef MIN +# define MIN(A,B) ((A)<(B)?(A):(B)) +#endif +#ifndef MAX +# define MAX(A,B) ((A)>(B)?(A):(B)) +#endif + +/* +** Swap two objects of type TYPE. +*/ +#define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} + +/* +** Check to see if this machine uses EBCDIC. (Yes, believe it or +** not, there are still machines out there that use EBCDIC.) +*/ +#if 'A' == '\301' +# define SQLITE_EBCDIC 1 +#else +# define SQLITE_ASCII 1 +#endif + +/* +** Integers of known sizes. These typedefs might change for architectures +** where the sizes very. Preprocessor macros are available so that the +** types can be conveniently redefined at compile-type. Like this: +** +** cc '-DUINTPTR_TYPE=long long int' ... +*/ +#ifndef UINT32_TYPE +# ifdef HAVE_UINT32_T +# define UINT32_TYPE uint32_t +# else +# define UINT32_TYPE unsigned int +# endif +#endif +#ifndef UINT16_TYPE +# ifdef HAVE_UINT16_T +# define UINT16_TYPE uint16_t +# else +# define UINT16_TYPE unsigned short int +# endif +#endif +#ifndef INT16_TYPE +# ifdef HAVE_INT16_T +# define INT16_TYPE int16_t +# else +# define INT16_TYPE short int +# endif +#endif +#ifndef UINT8_TYPE +# ifdef HAVE_UINT8_T +# define UINT8_TYPE uint8_t +# else +# define UINT8_TYPE unsigned char +# endif +#endif +#ifndef INT8_TYPE +# ifdef HAVE_INT8_T +# define INT8_TYPE int8_t +# else +# define INT8_TYPE signed char +# endif +#endif +#ifndef LONGDOUBLE_TYPE +# define LONGDOUBLE_TYPE long double +#endif +typedef sqlite_int64 i64; /* 8-byte signed integer */ +typedef sqlite_uint64 u64; /* 8-byte unsigned integer */ +typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ +typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ +typedef INT16_TYPE i16; /* 2-byte signed integer */ +typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ +typedef INT8_TYPE i8; /* 1-byte signed integer */ + +/* +** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value +** that can be stored in a u32 without loss of data. The value +** is 0x00000000ffffffff. But because of quirks of some compilers, we +** have to specify the value in the less intuitive manner shown: +*/ +#define SQLITE_MAX_U32 ((((u64)1)<<32)-1) + +/* +** The datatype used to store estimates of the number of rows in a +** table or index. This is an unsigned integer type. For 99.9% of +** the world, a 32-bit integer is sufficient. But a 64-bit integer +** can be used at compile-time if desired. +*/ +#ifdef SQLITE_64BIT_STATS + typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */ +#else + typedef u32 tRowcnt; /* 32-bit is the default */ +#endif + +/* +** Estimated quantities used for query planning are stored as 16-bit +** logarithms. For quantity X, the value stored is 10*log2(X). This +** gives a possible range of values of approximately 1.0e986 to 1e-986. +** But the allowed values are "grainy". Not every value is representable. +** For example, quantities 16 and 17 are both represented by a LogEst +** of 40. However, since LogEst quantities are suppose to be estimates, +** not exact values, this imprecision is not a problem. +** +** "LogEst" is short for "Logarithmic Estimate". +** +** Examples: +** 1 -> 0 20 -> 43 10000 -> 132 +** 2 -> 10 25 -> 46 25000 -> 146 +** 3 -> 16 100 -> 66 1000000 -> 199 +** 4 -> 20 1000 -> 99 1048576 -> 200 +** 10 -> 33 1024 -> 100 4294967296 -> 320 +** +** The LogEst can be negative to indicate fractional values. +** Examples: +** +** 0.5 -> -10 0.1 -> -33 0.0625 -> -40 +*/ +typedef INT16_TYPE LogEst; + +/* +** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer +*/ +#ifndef SQLITE_PTRSIZE +# if defined(__SIZEOF_POINTER__) +# define SQLITE_PTRSIZE __SIZEOF_POINTER__ +# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(_M_ARM) || defined(__arm__) || defined(__x86) +# define SQLITE_PTRSIZE 4 +# else +# define SQLITE_PTRSIZE 8 +# endif +#endif + +/* The uptr type is an unsigned integer large enough to hold a pointer +*/ +#if defined(HAVE_STDINT_H) + typedef uintptr_t uptr; +#elif SQLITE_PTRSIZE==4 + typedef u32 uptr; +#else + typedef u64 uptr; +#endif + +/* +** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to +** something between S (inclusive) and E (exclusive). +** +** In other words, S is a buffer and E is a pointer to the first byte after +** the end of buffer S. This macro returns true if P points to something +** contained within the buffer S. +*/ +#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E))) + + +/* +** 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 +** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined +** at run-time. +*/ +#ifndef SQLITE_BYTEORDER +# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__) +# define SQLITE_BYTEORDER 1234 +# elif defined(sparc) || defined(__ppc__) +# define SQLITE_BYTEORDER 4321 +# else +# define SQLITE_BYTEORDER 0 +# endif +#endif +#if SQLITE_BYTEORDER==4321 +# define SQLITE_BIGENDIAN 1 +# define SQLITE_LITTLEENDIAN 0 +# define SQLITE_UTF16NATIVE SQLITE_UTF16BE +#elif SQLITE_BYTEORDER==1234 +# define SQLITE_BIGENDIAN 0 +# define SQLITE_LITTLEENDIAN 1 +# define SQLITE_UTF16NATIVE SQLITE_UTF16LE +#else +# ifdef SQLITE_AMALGAMATION + const int sqlite3one = 1; +# else + extern const int sqlite3one; +# endif +# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) +# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) +# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) +#endif + +/* +** Constants for the largest and smallest possible 64-bit signed integers. +** These macros are designed to work correctly on both 32-bit and 64-bit +** compilers. +*/ +#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) +#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) + +/* +** Round up a number to the next larger multiple of 8. This is used +** to force 8-byte alignment on 64-bit architectures. +*/ +#define ROUND8(x) (((x)+7)&~7) + +/* +** Round down to the nearest multiple of 8 +*/ +#define ROUNDDOWN8(x) ((x)&~7) + +/* +** Assert that the pointer X is aligned to an 8-byte boundary. This +** macro is used only within assert() to verify that the code gets +** all alignment restrictions correct. +** +** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the +** underlying malloc() implementation might return us 4-byte aligned +** pointers. In that case, only verify 4-byte alignment. +*/ +#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC +# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0) +#else +# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0) +#endif + +/* +** Disable MMAP on platforms where it is known to not work +*/ +#if defined(__OpenBSD__) || defined(__QNXNTO__) +# undef SQLITE_MAX_MMAP_SIZE +# define SQLITE_MAX_MMAP_SIZE 0 +#endif + +/* +** Default maximum size of memory used by memory-mapped I/O in the VFS +*/ +#ifdef __APPLE__ +# include +#endif +#ifndef SQLITE_MAX_MMAP_SIZE +# if defined(__linux__) \ + || defined(_WIN32) \ + || (defined(__APPLE__) && defined(__MACH__)) \ + || defined(__sun) \ + || defined(__FreeBSD__) \ + || defined(__DragonFly__) +# define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */ +# else +# define SQLITE_MAX_MMAP_SIZE 0 +# endif +# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */ +#endif + +/* +** The default MMAP_SIZE is zero on all platforms. Or, even if a larger +** default MMAP_SIZE is specified at compile-time, make sure that it does +** not exceed the maximum mmap size. +*/ +#ifndef SQLITE_DEFAULT_MMAP_SIZE +# define SQLITE_DEFAULT_MMAP_SIZE 0 +# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */ +#endif +#if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE +# undef SQLITE_DEFAULT_MMAP_SIZE +# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE +#endif + +/* +** Only one of SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4 can be defined. +** Priority is given to SQLITE_ENABLE_STAT4. If either are defined, also +** define SQLITE_ENABLE_STAT3_OR_STAT4 +*/ +#ifdef SQLITE_ENABLE_STAT4 +# undef SQLITE_ENABLE_STAT3 +# define SQLITE_ENABLE_STAT3_OR_STAT4 1 +#elif SQLITE_ENABLE_STAT3 +# define SQLITE_ENABLE_STAT3_OR_STAT4 1 +#elif SQLITE_ENABLE_STAT3_OR_STAT4 +# undef SQLITE_ENABLE_STAT3_OR_STAT4 +#endif + +/* +** 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) +# define SELECTTRACE_ENABLED 1 +#else +# define SELECTTRACE_ENABLED 0 +#endif + +/* +** An instance of the following structure is used to store the busy-handler +** callback for a given sqlite handle. +** +** The sqlite.busyHandler member of the sqlite struct contains the busy +** callback for the database handle. Each pager opened via the sqlite +** handle is passed a pointer to sqlite.busyHandler. The busy-handler +** callback is currently invoked only from within pager.c. +*/ +typedef struct BusyHandler BusyHandler; +struct BusyHandler { + int (*xFunc)(void *,int); /* The busy callback */ + void *pArg; /* First arg to busy callback */ + int nBusy; /* Incremented with each busy call */ +}; + +/* +** Name of the master database table. The master database table +** is a special table that holds the names and attributes of all +** user tables and indices. +*/ +#define MASTER_NAME "sqlite_master" +#define TEMP_MASTER_NAME "sqlite_temp_master" + +/* +** The root-page of the master database table. +*/ +#define MASTER_ROOT 1 + +/* +** The name of the schema table. +*/ +#define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME) + +/* +** A convenience macro that returns the number of elements in +** an array. +*/ +#define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) + +/* +** Determine if the argument is a power of two +*/ +#define IsPowerOfTwo(X) (((X)&((X)-1))==0) + +/* +** The following value as a destructor means to use sqlite3DbFree(). +** The sqlite3DbFree() routine requires two parameters instead of the +** one parameter that destructors normally want. So we have to introduce +** this magic value that the code knows to handle differently. Any +** pointer will work here as long as it is distinct from SQLITE_STATIC +** and SQLITE_TRANSIENT. +*/ +#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize) + +/* +** When SQLITE_OMIT_WSD is defined, it means that the target platform does +** not support Writable Static Data (WSD) such as global and static variables. +** All variables must either be on the stack or dynamically allocated from +** the heap. When WSD is unsupported, the variable declarations scattered +** throughout the SQLite code must become constants instead. The SQLITE_WSD +** macro is used for this purpose. And instead of referencing the variable +** directly, we use its constant as a key to lookup the run-time allocated +** buffer that holds real variable. The constant is also the initializer +** for the run-time allocated buffer. +** +** In the usual case where WSD is supported, the SQLITE_WSD and GLOBAL +** macros become no-ops and have zero performance impact. +*/ +#ifdef SQLITE_OMIT_WSD + #define SQLITE_WSD const + #define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v))) + #define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config) +SQLITE_API int sqlite3_wsd_init(int N, int J); +SQLITE_API void *sqlite3_wsd_find(void *K, int L); +#else + #define SQLITE_WSD + #define GLOBAL(t,v) v + #define sqlite3GlobalConfig sqlite3Config +#endif + +/* +** The following macros are used to suppress compiler warnings and to +** make it clear to human readers when a function parameter is deliberately +** left unused within the body of a function. This usually happens when +** a function is called via a function pointer. For example the +** implementation of an SQL aggregate step callback may not use the +** parameter indicating the number of arguments passed to the aggregate, +** if it knows that this is enforced elsewhere. +** +** When a function parameter is not used at all within the body of a function, +** it is generally named "NotUsed" or "NotUsed2" to make things even clearer. +** However, these macros may also be used to suppress warnings related to +** parameters that may or may not be used depending on compilation options. +** For example those parameters only used in assert() statements. In these +** cases the parameters are named as per the usual conventions. +*/ +#define UNUSED_PARAMETER(x) (void)(x) +#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y) + +/* +** Forward references to structures +*/ +typedef struct AggInfo AggInfo; +typedef struct AuthContext AuthContext; +typedef struct AutoincInfo AutoincInfo; +typedef struct Bitvec Bitvec; +typedef struct CollSeq CollSeq; +typedef struct Column Column; +typedef struct Db Db; +typedef struct Schema Schema; +typedef struct Expr Expr; +typedef struct ExprList ExprList; +typedef struct ExprSpan ExprSpan; +typedef struct FKey FKey; +typedef struct FuncDestructor FuncDestructor; +typedef struct FuncDef FuncDef; +typedef struct FuncDefHash FuncDefHash; +typedef struct IdList IdList; +typedef struct Index Index; +typedef struct IndexSample IndexSample; +typedef struct KeyClass KeyClass; +typedef struct KeyInfo KeyInfo; +typedef struct Lookaside Lookaside; +typedef struct LookasideSlot LookasideSlot; +typedef struct Module Module; +typedef struct NameContext NameContext; +typedef struct Parse Parse; +typedef struct PreUpdate PreUpdate; +typedef struct PrintfArguments PrintfArguments; +typedef struct RowSet RowSet; +typedef struct Savepoint Savepoint; +typedef struct Select Select; +typedef struct SQLiteThread SQLiteThread; +typedef struct SelectDest SelectDest; +typedef struct SrcList SrcList; +typedef struct StrAccum StrAccum; +typedef struct Table Table; +typedef struct TableLock TableLock; +typedef struct Token Token; +typedef struct TreeView TreeView; +typedef struct Trigger Trigger; +typedef struct TriggerPrg TriggerPrg; +typedef struct TriggerStep TriggerStep; +typedef struct UnpackedRecord UnpackedRecord; +typedef struct VTable VTable; +typedef struct VtabCtx VtabCtx; +typedef struct Walker Walker; +typedef struct WhereInfo WhereInfo; +typedef struct With With; + +/* A VList object records a mapping between parameters/variables/wildcards +** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer +** variable number associated with that parameter. See the format description +** on the sqlite3VListAdd() routine for more information. A VList is really +** just an array of integers. +*/ +typedef int VList; + +/* +** Defer sourcing vdbe.h and btree.h until after the "u8" and +** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque +** pointer types (i.e. FuncDef) defined above. +*/ +/************** Include btree.h in the middle of sqliteInt.h *****************/ +/************** Begin file btree.h *******************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface that the sqlite B-Tree file +** subsystem. See comments in the source code for a detailed description +** of what each interface routine does. +*/ +#ifndef SQLITE_BTREE_H +#define SQLITE_BTREE_H + +/* TODO: This definition is just included so other modules compile. It +** needs to be revisited. +*/ +#define SQLITE_N_BTREE_META 16 + +/* +** If defined as non-zero, auto-vacuum is enabled by default. Otherwise +** it must be turned on for each database using "PRAGMA auto_vacuum = 1". +*/ +#ifndef SQLITE_DEFAULT_AUTOVACUUM + #define SQLITE_DEFAULT_AUTOVACUUM 0 +#endif + +#define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */ +#define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */ +#define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */ + +/* +** Forward declarations of structure +*/ +typedef struct Btree Btree; +typedef struct BtCursor BtCursor; +typedef struct BtShared BtShared; +typedef struct BtreePayload BtreePayload; + + +SQLITE_PRIVATE int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ + const char *zFilename, /* Name of database file to open */ + sqlite3 *db, /* Associated database connection */ + Btree **ppBtree, /* Return open Btree* here */ + int flags, /* Flags */ + int vfsFlags /* Flags passed through to VFS open */ +); + +/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the +** following values. +** +** NOTE: These values must match the corresponding PAGER_ values in +** pager.h. +*/ +#define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ +#define BTREE_MEMORY 2 /* This is an in-memory DB */ +#define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */ +#define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */ + +SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); +SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); +SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree*,int); +#if SQLITE_MAX_MMAP_SIZE>0 +SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); +#endif +SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned); +SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); +SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); +SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); +SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*); +SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int); +SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*); +SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p); +SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); +SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); +SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); +SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int); +SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); +SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags); +SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); +SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); +SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); +SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); +SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree); +#ifndef SQLITE_OMIT_SHARED_CACHE +SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); +#endif +SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int); + +SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); +SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); +SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); + +SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); + +/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR +** of the flags shown below. +** +** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set. +** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data +** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With +** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored +** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL +** indices.) +*/ +#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ +#define BTREE_BLOBKEY 2 /* Table has keys only - no data */ + +SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); +SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); +SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int); + +SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); +SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); + +SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); + +/* +** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta +** should be one of the following values. The integer values are assigned +** to constants so that the offset of the corresponding field in an +** SQLite database header may be found using the following formula: +** +** offset = 36 + (idx * 4) +** +** For example, the free-page-count field is located at byte offset 36 of +** the database file header. The incr-vacuum-flag field is located at +** byte offset 64 (== 36+4*7). +** +** The BTREE_DATA_VERSION value is not really a value stored in the header. +** It is a read-only number computed by the pager. But we merge it with +** the header value access routines since its access pattern is the same. +** Call it a "virtual meta value". +*/ +#define BTREE_FREE_PAGE_COUNT 0 +#define BTREE_SCHEMA_VERSION 1 +#define BTREE_FILE_FORMAT 2 +#define BTREE_DEFAULT_CACHE_SIZE 3 +#define BTREE_LARGEST_ROOT_PAGE 4 +#define BTREE_TEXT_ENCODING 5 +#define BTREE_USER_VERSION 6 +#define BTREE_INCR_VACUUM 7 +#define BTREE_APPLICATION_ID 8 +#define BTREE_DATA_VERSION 15 /* A virtual meta-value */ + +/* +** Kinds of hints that can be passed into the sqlite3BtreeCursorHint() +** interface. +** +** BTREE_HINT_RANGE (arguments: Expr*, Mem*) +** +** The first argument is an Expr* (which is guaranteed to be constant for +** the lifetime of the cursor) that defines constraints on which rows +** might be fetched with this cursor. The Expr* tree may contain +** TK_REGISTER nodes that refer to values stored in the array of registers +** passed as the second parameter. In other words, if Expr.op==TK_REGISTER +** then the value of the node is the value in Mem[pExpr.iTable]. Any +** TK_COLUMN node in the expression tree refers to the Expr.iColumn-th +** column of the b-tree of the cursor. The Expr tree will not contain +** any function calls nor subqueries nor references to b-trees other than +** the cursor being hinted. +** +** The design of the _RANGE hint is aid b-tree implementations that try +** to prefetch content from remote machines - to provide those +** implementations with limits on what needs to be prefetched and thereby +** reduce network bandwidth. +** +** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by +** standard SQLite. The other hints are provided for extentions that use +** the SQLite parser and code generator but substitute their own storage +** engine. +*/ +#define BTREE_HINT_RANGE 0 /* Range constraints on queries */ + +/* +** Values that may be OR'd together to form the argument to the +** BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint(): +** +** The BTREE_BULKLOAD flag is set on index cursors when the index is going +** to be filled with content that is already in sorted order. +** +** The BTREE_SEEK_EQ flag is set on cursors that will get OP_SeekGE or +** OP_SeekLE opcodes for a range search, but where the range of entries +** selected will all have the same key. In other words, the cursor will +** be used only for equality key searches. +** +*/ +#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */ +#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */ + +/* +** Flags passed as the third argument to sqlite3BtreeCursor(). +** +** For read-only cursors the wrFlag argument is always zero. For read-write +** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or just +** (BTREE_WRCSR). If the BTREE_FORDELETE bit is set, then the cursor will +** only be used by SQLite for the following: +** +** * to seek to and then delete specific entries, and/or +** +** * to read values that will be used to create keys that other +** BTREE_FORDELETE cursors will seek to and delete. +** +** The BTREE_FORDELETE flag is an optimization hint. It is not used by +** by this, the native b-tree engine of SQLite, but it is available to +** alternative storage engines that might be substituted in place of this +** b-tree system. For alternative storage engines in which a delete of +** the main table row automatically deletes corresponding index rows, +** the FORDELETE flag hint allows those alternative storage engines to +** skip a lot of work. Namely: FORDELETE cursors may treat all SEEK +** and DELETE operations as no-ops, and any READ operation against a +** FORDELETE cursor may return a null row: 0x01 0x00. +*/ +#define BTREE_WRCSR 0x00000004 /* read-write cursor */ +#define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */ + +SQLITE_PRIVATE int sqlite3BtreeCursor( + Btree*, /* BTree containing table to open */ + int iTable, /* Index of root page */ + int wrFlag, /* 1 for writing. 0 for read-only */ + struct KeyInfo*, /* First argument to compare function */ + BtCursor *pCursor /* Space to write cursor structure */ +); +SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); +SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); +SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); +#ifdef SQLITE_ENABLE_CURSOR_HINTS +SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...); +#endif + +SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( + BtCursor*, + UnpackedRecord *pUnKey, + i64 intKey, + int bias, + int *pRes +); +SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*); +SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags); + +/* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */ +#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ +#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ +#define BTREE_APPEND 0x08 /* Insert is likely an append */ + +/* An instance of the BtreePayload object describes the content of a single +** entry in either an index or table btree. +** +** Index btrees (used for indexes and also WITHOUT ROWID tables) contain +** an arbitrary key and no data. These btrees have pKey,nKey set to their +** key and pData,nData,nZero set to zero. +** +** Table btrees (used for rowid tables) contain an integer rowid used as +** the key and passed in the nKey field. The pKey field is zero. +** pData,nData hold the content of the new entry. nZero extra zero bytes +** are appended to the end of the content when constructing the entry. +** +** This object is used to pass information into sqlite3BtreeInsert(). The +** same information used to be passed as five separate parameters. But placing +** the information into this object helps to keep the interface more +** organized and understandable, and it also helps the resulting code to +** run a little faster by using fewer registers for parameter passing. +*/ +struct BtreePayload { + const void *pKey; /* Key content for indexes. NULL for tables */ + sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */ + const void *pData; /* Data for tables. NULL for indexes */ + sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */ + u16 nMem; /* Number of aMem[] value. Might be zero */ + int nData; /* Size of pData. 0 if none. */ + int nZero; /* Extra zero data appended after pData,nData */ +}; + +SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, + int flags, int seekResult); +SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes); +SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); +SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); +SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*); + +SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); +SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); +SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*); + +#ifndef SQLITE_OMIT_INCRBLOB +SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*); +SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); +SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *); +#endif +SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *); +SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); +SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); +SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt); +SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void); + +#ifndef NDEBUG +SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); +#endif +SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*); + +#ifndef SQLITE_OMIT_BTREECOUNT +SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *); +#endif + +#ifdef SQLITE_TEST +SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int); +SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*); +#endif + +#ifndef SQLITE_OMIT_WAL +SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); +#endif + +/* +** If we are not using shared cache, then there is no need to +** use mutexes to access the BtShared structures. So make the +** Enter and Leave procedures no-ops. +*/ +#ifndef SQLITE_OMIT_SHARED_CACHE +SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); +SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); +SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); +SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*); +#else +# define sqlite3BtreeEnter(X) +# define sqlite3BtreeEnterAll(X) +# define sqlite3BtreeSharable(X) 0 +# define sqlite3BtreeEnterCursor(X) +# define sqlite3BtreeConnectionCount(X) 1 +#endif + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE +SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); +SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); +SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*); +#ifndef NDEBUG + /* These routines are used inside assert() statements only. */ +SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*); +SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*); +SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); +#endif +#else + +# define sqlite3BtreeLeave(X) +# define sqlite3BtreeLeaveCursor(X) +# define sqlite3BtreeLeaveAll(X) + +# define sqlite3BtreeHoldsMutex(X) 1 +# define sqlite3BtreeHoldsAllMutexes(X) 1 +# define sqlite3SchemaMutexHeld(X,Y,Z) 1 +#endif + + +#endif /* SQLITE_BTREE_H */ + +/************** End of btree.h ***********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ +/************** Include vdbe.h in the middle of sqliteInt.h ******************/ +/************** Begin file vdbe.h ********************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** Header file for the Virtual DataBase Engine (VDBE) +** +** This header defines the interface to the virtual database engine +** or VDBE. The VDBE implements an abstract machine that runs a +** simple program to access and modify the underlying database. +*/ +#ifndef SQLITE_VDBE_H +#define SQLITE_VDBE_H +/* #include */ + +/* +** A single VDBE is an opaque structure named "Vdbe". Only routines +** in the source file sqliteVdbe.c are allowed to see the insides +** of this structure. +*/ +typedef struct Vdbe Vdbe; + +/* +** The names of the following types declared in vdbeInt.h are required +** for the VdbeOp definition. +*/ +typedef struct sqlite3_value Mem; +typedef struct SubProgram SubProgram; + +/* +** A single instruction of the virtual machine has an opcode +** and as many as three operands. The instruction is recorded +** as an instance of the following structure: +*/ +struct VdbeOp { + u8 opcode; /* What operation to perform */ + signed char p4type; /* One of the P4_xxx constants for p4 */ + u16 p5; /* Fifth parameter is an unsigned 16-bit integer */ + int p1; /* First operand */ + int p2; /* Second parameter (often the jump destination) */ + int p3; /* The third parameter */ + union p4union { /* fourth parameter */ + int i; /* Integer value if p4type==P4_INT32 */ + void *p; /* Generic pointer */ + char *z; /* Pointer to data for string (char array) types */ + i64 *pI64; /* Used when p4type is P4_INT64 */ + double *pReal; /* Used when p4type is P4_REAL */ + FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ + sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */ + CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ + Mem *pMem; /* Used when p4type is P4_MEM */ + VTable *pVtab; /* Used when p4type is P4_VTAB */ + KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ + int *ai; /* Used when p4type is P4_INTARRAY */ + SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ + Table *pTab; /* Used when p4type is P4_TABLE */ +#ifdef SQLITE_ENABLE_CURSOR_HINTS + Expr *pExpr; /* Used when p4type is P4_EXPR */ +#endif + int (*xAdvance)(BtCursor *, int *); + } p4; +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + char *zComment; /* Comment to improve readability */ +#endif +#ifdef VDBE_PROFILE + u32 cnt; /* Number of times this instruction was executed */ + u64 cycles; /* Total time spent executing this instruction */ +#endif +#ifdef SQLITE_VDBE_COVERAGE + int iSrcLine; /* Source-code line that generated this opcode */ +#endif +}; +typedef struct VdbeOp VdbeOp; + + +/* +** A sub-routine used to implement a trigger program. +*/ +struct SubProgram { + VdbeOp *aOp; /* Array of opcodes for sub-program */ + int nOp; /* Elements in aOp[] */ + int nMem; /* Number of memory cells required */ + int nCsr; /* Number of cursors required */ + u8 *aOnce; /* Array of OP_Once flags */ + void *token; /* id that may be used to recursive triggers */ + SubProgram *pNext; /* Next sub-program already visited */ +}; + +/* +** A smaller version of VdbeOp used for the VdbeAddOpList() function because +** it takes up less space. +*/ +struct VdbeOpList { + u8 opcode; /* What operation to perform */ + signed char p1; /* First operand */ + signed char p2; /* Second parameter (often the jump destination) */ + signed char p3; /* Third parameter */ +}; +typedef struct VdbeOpList VdbeOpList; + +/* +** Allowed values of VdbeOp.p4type +*/ +#define P4_NOTUSED 0 /* The P4 parameter is not used */ +#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ +#define P4_STATIC (-2) /* Pointer to a static string */ +#define P4_COLLSEQ (-3) /* P4 is a pointer to a CollSeq structure */ +#define P4_FUNCDEF (-4) /* P4 is a pointer to a FuncDef structure */ +#define P4_KEYINFO (-5) /* P4 is a pointer to a KeyInfo structure */ +#define P4_EXPR (-6) /* P4 is a pointer to an Expr tree */ +#define P4_MEM (-7) /* P4 is a pointer to a Mem* structure */ +#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ +#define P4_VTAB (-8) /* P4 is a pointer to an sqlite3_vtab structure */ +#define P4_REAL (-9) /* P4 is a 64-bit floating point value */ +#define P4_INT64 (-10) /* P4 is a 64-bit signed integer */ +#define P4_INT32 (-11) /* P4 is a 32-bit signed integer */ +#define P4_INTARRAY (-12) /* P4 is a vector of 32-bit integers */ +#define P4_SUBPROGRAM (-13) /* P4 is a pointer to a SubProgram structure */ +#define P4_ADVANCE (-14) /* P4 is a pointer to BtreeNext() or BtreePrev() */ +#define P4_TABLE (-15) /* P4 is a pointer to a Table structure */ +#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ + +/* Error message codes for OP_Halt */ +#define P5_ConstraintNotNull 1 +#define P5_ConstraintUnique 2 +#define P5_ConstraintCheck 3 +#define P5_ConstraintFK 4 + +/* +** The Vdbe.aColName array contains 5n Mem structures, where n is the +** number of columns of data returned by the statement. +*/ +#define COLNAME_NAME 0 +#define COLNAME_DECLTYPE 1 +#define COLNAME_DATABASE 2 +#define COLNAME_TABLE 3 +#define COLNAME_COLUMN 4 +#ifdef SQLITE_ENABLE_COLUMN_METADATA +# define COLNAME_N 5 /* Number of COLNAME_xxx symbols */ +#else +# ifdef SQLITE_OMIT_DECLTYPE +# define COLNAME_N 1 /* Store only the name */ +# else +# define COLNAME_N 2 /* Store the name and decltype */ +# endif +#endif + +/* +** The following macro converts a relative address in the p2 field +** of a VdbeOp structure into a negative number so that +** sqlite3VdbeAddOpList() knows that the address is relative. Calling +** the macro again restores the address. +*/ +#define ADDR(X) (-1-(X)) + +/* +** The makefile scans the vdbe.c source file and creates the "opcodes.h" +** header file that defines a number for each opcode used by the VDBE. +*/ +/************** Include opcodes.h in the middle of vdbe.h ********************/ +/************** Begin file opcodes.h *****************************************/ +/* Automatically generated. Do not edit */ +/* See the tool/mkopcodeh.tcl script for details */ +#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_Checkpoint 8 +#define OP_JournalMode 9 +#define OP_Vacuum 10 +#define OP_VFilter 11 /* 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_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_Function0 69 /* synopsis: r[P3]=func(r[P2@P5]) */ +#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_Function 72 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_AddImm 73 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 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_ElseNotEq 83 /* same as TK_ESCAPE */ +#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] */ +#define OP_Add 88 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 89 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 90 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 91 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 92 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 93 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_Cast 94 /* synopsis: affinity(r[P1]) */ +#define OP_BitNot 95 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ +#define OP_Permutation 96 +#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ +#define OP_Compare 98 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_Column 99 /* synopsis: r[P3]=PX */ +#define OP_Affinity 100 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 101 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 102 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 103 +#define OP_SetCookie 104 +#define OP_ReopenIdx 105 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 106 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 107 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenDup 108 +#define OP_OpenAutoindex 109 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 110 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 111 +#define OP_SequenceTest 112 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 113 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 114 +#define OP_ColumnsUsed 115 +#define OP_Sequence 116 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 117 /* synopsis: r[P2]=rowid */ +#define OP_Insert 118 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 119 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 120 +#define OP_ResetCount 121 +#define OP_SorterCompare 122 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 123 /* synopsis: r[P2]=data */ +#define OP_RowData 124 /* synopsis: r[P2]=data */ +#define OP_Rowid 125 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 126 +#define OP_SorterInsert 127 /* synopsis: key=r[P2] */ +#define OP_IdxInsert 128 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 129 /* synopsis: key=r[P2@P3] */ +#define OP_Seek 130 /* synopsis: Move P3 to P1.rowid */ +#define OP_IdxRowid 131 /* synopsis: r[P2]=rowid */ +#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_Destroy 133 +#define OP_Clear 134 +#define OP_ResetSorter 135 +#define OP_CreateIndex 136 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_CreateTable 137 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_SqlExec 138 +#define OP_ParseSchema 139 +#define OP_LoadAnalysis 140 +#define OP_DropTable 141 +#define OP_DropIndex 142 +#define OP_DropTrigger 143 +#define OP_IntegrityCk 144 +#define OP_RowSetAdd 145 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 146 +#define OP_FkCounter 147 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 148 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 149 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggStep0 150 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep 151 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggFinal 152 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 153 +#define OP_TableLock 154 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 155 +#define OP_VCreate 156 +#define OP_VDestroy 157 +#define OP_VOpen 158 +#define OP_VColumn 159 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 160 +#define OP_Pagecount 161 +#define OP_MaxPgcnt 162 +#define OP_CursorHint 163 +#define OP_Noop 164 +#define OP_Explain 165 + +/* Properties such as "out2" or "jump" that are specified in +** comments following the "case" for each opcode in the vdbe.c +** are encoded into bitvectors as follows: +*/ +#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */ +#define OPFLG_IN1 0x02 /* in1: P1 is an input */ +#define OPFLG_IN2 0x04 /* in2: P2 is an input */ +#define OPFLG_IN3 0x08 /* in3: P3 is an input */ +#define OPFLG_OUT2 0x10 /* out2: P2 is an output */ +#define OPFLG_OUT3 0x20 /* out3: P3 is an output */ +#define OPFLG_INITIALIZER {\ +/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\ +/* 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, 0x00, 0x26, 0x26,\ +/* 72 */ 0x00, 0x02, 0x02, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ +/* 80 */ 0x0b, 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26,\ +/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x02, 0x12,\ +/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\ +/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04,\ +/* 128 */ 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\ +/* 136 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 144 */ 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 160 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,} + +/* The sqlite3P2Values() routine is able to run faster if it knows +** the value of the largest JUMP opcode. The smaller the maximum +** JUMP opcode the better, so the mkopcodeh.tcl script that +** generated this include file strives to group all JUMP opcodes +** together near the beginning of the list. +*/ +#define SQLITE_MX_JUMP_OPCODE 83 /* Maximum JUMP opcode */ + +/************** End of opcodes.h *********************************************/ +/************** Continuing where we left off in vdbe.h ***********************/ + +/* +** Prototypes for the VDBE interface. See comments on the implementation +** for a description of what each of these routines does. +*/ +SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*); +SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int); +SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); +SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); +SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe*,int); +SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe*,int,const char*); +SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...); +SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); +SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); +SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); +SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); +SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int); +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) +SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N); +SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p); +#else +# define sqlite3VdbeVerifyNoMallocRequired(A,B) +# define sqlite3VdbeVerifyNoResultRow(A) +#endif +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); +SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); +SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); +SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); +SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); +SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); +SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5); +SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); +SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr); +SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); +SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); +SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); +SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); +SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); +SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); +SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); +SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); +SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *, int); +#endif +SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe*); +SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int); +SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); +SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); +SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); +SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); +SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); +SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); +SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); +#ifndef SQLITE_OMIT_TRACE +SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); +#endif +SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); + +SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); +SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); +SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); +SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); + +typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); +SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); + +#ifndef SQLITE_OMIT_TRIGGER +SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); +#endif + +/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on +** each VDBE opcode. +** +** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op +** comments in VDBE programs that show key decision points in the code +** generator. +*/ +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS +SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe*, const char*, ...); +# define VdbeComment(X) sqlite3VdbeComment X +SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); +# define VdbeNoopComment(X) sqlite3VdbeNoopComment X +# ifdef SQLITE_ENABLE_MODULE_COMMENTS +# define VdbeModuleComment(X) sqlite3VdbeNoopComment X +# else +# define VdbeModuleComment(X) +# endif +#else +# define VdbeComment(X) +# define VdbeNoopComment(X) +# define VdbeModuleComment(X) +#endif + +/* +** The VdbeCoverage macros are used to set a coverage testing point +** for VDBE branch instructions. The coverage testing points are line +** numbers in the sqlite3.c source file. VDBE branch coverage testing +** only works with an amalagmation build. That's ok since a VDBE branch +** coverage build designed for testing the test suite only. No application +** should ever ship with VDBE branch coverage measuring turned on. +** +** VdbeCoverage(v) // Mark the previously coded instruction +** // as a branch +** +** VdbeCoverageIf(v, conditional) // Mark previous if conditional true +** +** VdbeCoverageAlwaysTaken(v) // Previous branch is always taken +** +** VdbeCoverageNeverTaken(v) // Previous branch is never taken +** +** Every VDBE branch operation must be tagged with one of the macros above. +** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and +** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch() +** routine in vdbe.c, alerting the developer to the missed tag. +*/ +#ifdef SQLITE_VDBE_COVERAGE +SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int); +# define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__) +# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__) +# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2); +# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1); +# define VDBE_OFFSET_LINENO(x) (__LINE__+x) +#else +# define VdbeCoverage(v) +# define VdbeCoverageIf(v,x) +# define VdbeCoverageAlwaysTaken(v) +# define VdbeCoverageNeverTaken(v) +# define VDBE_OFFSET_LINENO(x) 0 +#endif + +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); +#else +# define sqlite3VdbeScanStatus(a,b,c,d,e) +#endif + +#endif /* SQLITE_VDBE_H */ + +/************** End of vdbe.h ************************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ +/************** Include pager.h in the middle of sqliteInt.h *****************/ +/************** Begin file pager.h *******************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface that the sqlite page cache +** subsystem. The page cache subsystem reads and writes a file a page +** at a time and provides a journal for rollback. +*/ + +#ifndef SQLITE_PAGER_H +#define SQLITE_PAGER_H + +/* +** Default maximum size for persistent journal files. A negative +** value means no limit. This value may be overridden using the +** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit". +*/ +#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT + #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1 +#endif + +/* +** The type used to represent a page number. The first page in a file +** is called page 1. 0 is used to represent "not a page". +*/ +typedef u32 Pgno; + +/* +** Each open file is managed by a separate instance of the "Pager" structure. +*/ +typedef struct Pager Pager; + +/* +** Handle type for pages. +*/ +typedef struct PgHdr DbPage; + +/* +** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is +** reserved for working around a windows/posix incompatibility). It is +** used in the journal to signify that the remainder of the journal file +** is devoted to storing a master journal name - there are no more pages to +** roll back. See comments for function writeMasterJournal() in pager.c +** for details. +*/ +#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) + +/* +** Allowed values for the flags parameter to sqlite3PagerOpen(). +** +** NOTE: These values must match the corresponding BTREE_ values in btree.h. +*/ +#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ +#define PAGER_MEMORY 0x0002 /* In-memory database */ + +/* +** Valid values for the second argument to sqlite3PagerLockingMode(). +*/ +#define PAGER_LOCKINGMODE_QUERY -1 +#define PAGER_LOCKINGMODE_NORMAL 0 +#define PAGER_LOCKINGMODE_EXCLUSIVE 1 + +/* +** Numeric constants that encode the journalmode. +** +** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY) +** are exposed in the API via the "PRAGMA journal_mode" command and +** therefore cannot be changed without a compatibility break. +*/ +#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ +#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ +#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ +#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ +#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ +#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ +#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ + +/* +** Flags that make up the mask passed to sqlite3PagerGet(). +*/ +#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */ +#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */ + +/* +** Flags for sqlite3PagerSetFlags() +** +** Value constraints (enforced via assert()): +** PAGER_FULLFSYNC == SQLITE_FullFSync +** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync +** PAGER_CACHE_SPILL == SQLITE_CacheSpill +*/ +#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */ +#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */ +#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */ +#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */ +#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */ +#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */ +#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */ +#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */ +#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */ + +/* +** The remainder of this file contains the declarations of the functions +** that make up the Pager sub-system API. See source code comments for +** a detailed description of each routine. +*/ + +/* Open and close a Pager connection. */ +SQLITE_PRIVATE int sqlite3PagerOpen( + sqlite3_vfs*, + Pager **ppPager, + const char*, + int, + int, + int, + void(*)(DbPage*) +); +SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*); +SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); + +/* Functions used to configure a Pager object. */ +SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); +SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); +#ifdef SQLITE_HAS_CODEC +SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*); +#endif +SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int); +SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); +SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); +SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); +SQLITE_PRIVATE void sqlite3PagerShrink(Pager*); +SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned); +SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int); +SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int); +SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*); +SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*); +SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64); +SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*); +SQLITE_PRIVATE int sqlite3PagerFlush(Pager*); + +/* Functions used to obtain and release page references. */ +SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); +SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); +SQLITE_PRIVATE void sqlite3PagerRef(DbPage*); +SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*); +SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*); + +/* Operations on page references. */ +SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); +SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*); +SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int); +SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*); +SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *); +SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *); + +/* Functions used to manage pager transactions and savepoints. */ +SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*); +SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int); +SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); +SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*); +SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster); +SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*); +SQLITE_PRIVATE int sqlite3PagerRollback(Pager*); +SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n); +SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); +SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); + +#ifndef SQLITE_OMIT_WAL +SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*); +SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); +SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); +# ifdef SQLITE_DIRECT_OVERFLOW_READ +SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno); +# endif +# ifdef SQLITE_ENABLE_SNAPSHOT +SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot); +SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager); +# endif +#else +# define sqlite3PagerUseWal(x,y) 0 +#endif + +#ifdef SQLITE_ENABLE_ZIPVFS +SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager); +#endif + +/* Functions used to query pager state and configuration. */ +SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); +SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); +#endif +SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); +SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int); +SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*); +SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); +SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); +SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); +SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); +SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); +SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); +SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); + +/* Functions used to truncate the database file. */ +SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); + +SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); + +#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) +SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); +#endif + +/* Functions to support testing and debugging. */ +#if !defined(NDEBUG) || defined(SQLITE_TEST) +SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); +SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*); +#endif +#ifdef SQLITE_TEST +SQLITE_PRIVATE int *sqlite3PagerStats(Pager*); +SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); + void disable_simulated_io_errors(void); + void enable_simulated_io_errors(void); +#else +# define disable_simulated_io_errors() +# define enable_simulated_io_errors() +#endif + +#endif /* SQLITE_PAGER_H */ + +/************** End of pager.h ***********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ +/************** Include pcache.h in the middle of sqliteInt.h ****************/ +/************** Begin file pcache.h ******************************************/ +/* +** 2008 August 05 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface that the sqlite page cache +** subsystem. +*/ + +#ifndef _PCACHE_H_ + +typedef struct PgHdr PgHdr; +typedef struct PCache PCache; + +/* +** Every page in the cache is controlled by an instance of the following +** structure. +*/ +struct PgHdr { + sqlite3_pcache_page *pPage; /* Pcache object page handle */ + void *pData; /* Page data */ + void *pExtra; /* Extra content */ + PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ + Pager *pPager; /* The pager this page is part of */ + Pgno pgno; /* Page number for this page */ +#ifdef SQLITE_CHECK_PAGES + u32 pageHash; /* Hash of page content */ +#endif + u16 flags; /* PGHDR flags defined below */ + + /********************************************************************** + ** Elements above are public. All that follows is private to pcache.c + ** and should not be accessed by other modules. + */ + i16 nRef; /* Number of users of this page */ + PCache *pCache; /* Cache that owns this page */ + + PgHdr *pDirtyNext; /* Next element in list of dirty pages */ + PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ +}; + +/* Bit values for PgHdr.flags */ +#define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */ +#define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */ +#define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */ +#define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before + ** writing this page to the database */ +#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */ +#define PGHDR_MMAP 0x020 /* This is an mmap page object */ + +#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */ + +/* Initialize and shutdown the page cache subsystem */ +SQLITE_PRIVATE int sqlite3PcacheInitialize(void); +SQLITE_PRIVATE void sqlite3PcacheShutdown(void); + +/* Page cache buffer management: +** These routines implement SQLITE_CONFIG_PAGECACHE. +*/ +SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, int sz, int n); + +/* Create a new pager cache. +** Under memory stress, invoke xStress to try to make pages clean. +** Only clean and unpinned pages can be reclaimed. +*/ +SQLITE_PRIVATE int sqlite3PcacheOpen( + int szPage, /* Size of every page */ + int szExtra, /* Extra space associated with each page */ + int bPurgeable, /* True if pages are on backing store */ + int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */ + void *pStress, /* Argument to xStress */ + PCache *pToInit /* Preallocated space for the PCache */ +); + +/* Modify the page-size after the cache has been created. */ +SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *, int); + +/* Return the size in bytes of a PCache object. Used to preallocate +** storage space. +*/ +SQLITE_PRIVATE int sqlite3PcacheSize(void); + +/* One release per successful fetch. Page is pinned until released. +** Reference counted. +*/ +SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag); +SQLITE_PRIVATE int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**); +SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(PCache*, Pgno, sqlite3_pcache_page *pPage); +SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr*); + +SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */ +SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */ +SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */ +SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */ +SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache*); + +/* Change a page number. Used by incr-vacuum. */ +SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno); + +/* Remove all pages with pgno>x. Reset the cache if x==0 */ +SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache*, Pgno x); + +/* Get a list of all dirty pages in the cache, sorted by page number */ +SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache*); + +/* Reset and close the cache object */ +SQLITE_PRIVATE void sqlite3PcacheClose(PCache*); + +/* Clear flags from pages of the page cache */ +SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *); + +/* Discard the contents of the cache */ +SQLITE_PRIVATE void sqlite3PcacheClear(PCache*); + +/* Return the total number of outstanding page references */ +SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache*); + +/* Increment the reference count of an existing page */ +SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr*); + +SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr*); + +/* Return the total number of pages stored in the cache */ +SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*); + +#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) +/* Iterate through all dirty pages currently stored in the cache. This +** interface is only available if SQLITE_CHECK_PAGES is defined when the +** library is built. +*/ +SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); +#endif + +#if defined(SQLITE_DEBUG) +/* Check invariants on a PgHdr object */ +SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr*); +#endif + +/* Set and get the suggested cache-size for the specified pager-cache. +** +** If no global maximum is configured, then the system attempts to limit +** the total number of pages cached by purgeable pager-caches to the sum +** of the suggested cache-sizes. +*/ +SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int); +#ifdef SQLITE_TEST +SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *); +#endif + +/* Set or get the suggested spill-size for the specified pager-cache. +** +** The spill-size is the minimum number of pages in cache before the cache +** will attempt to spill dirty pages by calling xStress. +*/ +SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *, int); + +/* Free up as much memory as possible from the page cache */ +SQLITE_PRIVATE void sqlite3PcacheShrink(PCache*); + +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT +/* Try to return memory used by the pcache module to the main memory heap */ +SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int); +#endif + +#ifdef SQLITE_TEST +SQLITE_PRIVATE void sqlite3PcacheStats(int*,int*,int*,int*); +#endif + +SQLITE_PRIVATE void sqlite3PCacheSetDefault(void); + +/* Return the header size */ +SQLITE_PRIVATE int sqlite3HeaderSizePcache(void); +SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); + +/* Number of dirty pages as a percentage of the configured cache size */ +SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); + +#endif /* _PCACHE_H_ */ + +/************** End of pcache.h **********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ +/************** Include os.h in the middle of sqliteInt.h ********************/ +/************** Begin file os.h **********************************************/ +/* +** 2001 September 16 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file (together with is companion C source-code file +** "os.c") attempt to abstract the underlying operating system so that +** the SQLite library will work on both POSIX and windows systems. +** +** This header file is #include-ed by sqliteInt.h and thus ends up +** being included by every source file. +*/ +#ifndef _SQLITE_OS_H_ +#define _SQLITE_OS_H_ + +/* +** Attempt to automatically detect the operating system and setup the +** necessary pre-processor macros for it. +*/ +/************** Include os_setup.h in the middle of os.h *********************/ +/************** Begin file os_setup.h ****************************************/ +/* +** 2013 November 25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains pre-processor directives related to operating system +** detection and/or setup. +*/ +#ifndef SQLITE_OS_SETUP_H +#define SQLITE_OS_SETUP_H + +/* +** Figure out if we are dealing with Unix, Windows, or some other operating +** system. +** +** After the following block of preprocess macros, all of SQLITE_OS_UNIX, +** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of +** the three will be 1. The other two will be 0. +*/ +#if defined(SQLITE_OS_OTHER) +# if SQLITE_OS_OTHER==1 +# undef SQLITE_OS_UNIX +# define SQLITE_OS_UNIX 0 +# undef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# else +# undef SQLITE_OS_OTHER +# endif +#endif +#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) +# define SQLITE_OS_OTHER 0 +# ifndef SQLITE_OS_WIN +# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \ + defined(__MINGW32__) || defined(__BORLANDC__) +# define SQLITE_OS_WIN 1 +# define SQLITE_OS_UNIX 0 +# else +# define SQLITE_OS_WIN 0 +# define SQLITE_OS_UNIX 1 +# endif +# else +# define SQLITE_OS_UNIX 0 +# endif +#else +# ifndef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# endif +#endif + +#endif /* SQLITE_OS_SETUP_H */ + +/************** End of os_setup.h ********************************************/ +/************** Continuing where we left off in os.h *************************/ + +/* If the SET_FULLSYNC macro is not defined above, then make it +** a no-op +*/ +#ifndef SET_FULLSYNC +# define SET_FULLSYNC(x,y) +#endif + +/* +** The default size of a disk sector +*/ +#ifndef SQLITE_DEFAULT_SECTOR_SIZE +# define SQLITE_DEFAULT_SECTOR_SIZE 4096 +#endif + +/* +** Temporary files are named starting with this prefix followed by 16 random +** alphanumeric characters, and no file extension. They are stored in the +** OS's standard temporary file directory, and are deleted prior to exit. +** If sqlite is being embedded in another program, you may wish to change the +** prefix to reflect your program's name, so that if your program exits +** prematurely, old temporary files can be easily identified. This can be done +** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line. +** +** 2006-10-31: The default prefix used to be "sqlite_". But then +** Mcafee started using SQLite in their anti-virus product and it +** started putting files with the "sqlite" name in the c:/temp folder. +** This annoyed many windows users. Those users would then do a +** Google search for "sqlite", find the telephone numbers of the +** developers and call to wake them up at night and complain. +** For this reason, the default name prefix is changed to be "sqlite" +** spelled backwards. So the temp files are still identified, but +** anybody smart enough to figure out the code is also likely smart +** enough to know that calling the developer will not help get rid +** of the file. +*/ +#ifndef SQLITE_TEMP_FILE_PREFIX +# define SQLITE_TEMP_FILE_PREFIX "etilqs_" +#endif + +/* +** The following values may be passed as the second argument to +** sqlite3OsLock(). The various locks exhibit the following semantics: +** +** SHARED: Any number of processes may hold a SHARED lock simultaneously. +** RESERVED: A single process may hold a RESERVED lock on a file at +** any time. Other processes may hold and obtain new SHARED locks. +** PENDING: A single process may hold a PENDING lock on a file at +** any one time. Existing SHARED locks may persist, but no new +** SHARED locks may be obtained by other processes. +** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks. +** +** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a +** process that requests an EXCLUSIVE lock may actually obtain a PENDING +** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to +** sqlite3OsLock(). +*/ +#define NO_LOCK 0 +#define SHARED_LOCK 1 +#define RESERVED_LOCK 2 +#define PENDING_LOCK 3 +#define EXCLUSIVE_LOCK 4 + +/* +** File Locking Notes: (Mostly about windows but also some info for Unix) +** +** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because +** those functions are not available. So we use only LockFile() and +** UnlockFile(). +** +** LockFile() prevents not just writing but also reading by other processes. +** A SHARED_LOCK is obtained by locking a single randomly-chosen +** byte out of a specific range of bytes. The lock byte is obtained at +** random so two separate readers can probably access the file at the +** same time, unless they are unlucky and choose the same lock byte. +** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range. +** There can only be one writer. A RESERVED_LOCK is obtained by locking +** a single byte of the file that is designated as the reserved lock byte. +** A PENDING_LOCK is obtained by locking a designated byte different from +** the RESERVED_LOCK byte. +** +** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available, +** which means we can use reader/writer locks. When reader/writer locks +** are used, the lock is placed on the same range of bytes that is used +** for probabilistic locking in Win95/98/ME. Hence, the locking scheme +** will support two or more Win95 readers or two or more WinNT readers. +** But a single Win95 reader will lock out all WinNT readers and a single +** WinNT reader will lock out all other Win95 readers. +** +** The following #defines specify the range of bytes used for locking. +** SHARED_SIZE is the number of bytes available in the pool from which +** a random byte is selected for a shared lock. The pool of bytes for +** shared locks begins at SHARED_FIRST. +** +** The same locking strategy and +** byte ranges are used for Unix. This leaves open the possibility of having +** clients on win95, winNT, and unix all talking to the same shared file +** and all locking correctly. To do so would require that samba (or whatever +** tool is being used for file sharing) implements locks correctly between +** windows and unix. I'm guessing that isn't likely to happen, but by +** using the same locking range we are at least open to the possibility. +** +** Locking in windows is manditory. For this reason, we cannot store +** actual data in the bytes used for locking. The pager never allocates +** the pages involved in locking therefore. SHARED_SIZE is selected so +** that all locks will fit on a single page even at the minimum page size. +** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE +** is set high so that we don't have to allocate an unused page except +** for very large databases. But one should test the page skipping logic +** by setting PENDING_BYTE low and running the entire regression suite. +** +** Changing the value of PENDING_BYTE results in a subtly incompatible +** file format. Depending on how it is changed, you might not notice +** the incompatibility right away, even running a full regression test. +** The default location of PENDING_BYTE is the first byte past the +** 1GB boundary. +** +*/ +#ifdef SQLITE_OMIT_WSD +# define PENDING_BYTE (0x40000000) +#else +# define PENDING_BYTE sqlite3PendingByte +#endif +#define RESERVED_BYTE (PENDING_BYTE+1) +#define SHARED_FIRST (PENDING_BYTE+2) +#define SHARED_SIZE 510 + +/* +** Wrapper around OS specific sqlite3_os_init() function. +*/ +SQLITE_PRIVATE int sqlite3OsInit(void); + +/* +** Functions for accessing sqlite3_file methods +*/ +SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*); +SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); +SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); +SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size); +SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int); +SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize); +SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int); +SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int); +SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut); +SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*); +SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*); +#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 +SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id); +SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); +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); +SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); +SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *); + + +/* +** Functions for accessing sqlite3_vfs methods +*/ +SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); +SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int); +SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut); +SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *); +#ifndef SQLITE_OMIT_LOAD_EXTENSION +SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *); +SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *); +SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void); +SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *); +#endif /* SQLITE_OMIT_LOAD_EXTENSION */ +SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *); +SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int); +SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*); +SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); + +/* +** Convenience functions for opening and closing files using +** sqlite3_malloc() to obtain space for the file-handle structure. +*/ +SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); +SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *); + +#endif /* _SQLITE_OS_H_ */ + +/************** End of os.h **************************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ +/************** Include mutex.h in the middle of sqliteInt.h *****************/ +/************** Begin file mutex.h *******************************************/ +/* +** 2007 August 28 +** +** 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 the common header for all mutex implementations. +** The sqliteInt.h header #includes this file so that it is available +** to all source files. We break it out in an effort to keep the code +** better organized. +** +** NOTE: source files should *not* #include this header file directly. +** Source files should #include the sqliteInt.h file and let that file +** include this one indirectly. +*/ + + +/* +** Figure out what version of the code to use. The choices are +** +** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The +** mutexes implementation cannot be overridden +** at start-time. +** +** SQLITE_MUTEX_NOOP For single-threaded applications. No +** mutual exclusion is provided. But this +** implementation can be overridden at +** start-time. +** +** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix. +** +** SQLITE_MUTEX_W32 For multi-threaded applications on Win32. +*/ +#if !SQLITE_THREADSAFE +# define SQLITE_MUTEX_OMIT +#endif +#if SQLITE_THREADSAFE && !defined(SQLITE_MUTEX_NOOP) +# if SQLITE_OS_UNIX +# define SQLITE_MUTEX_PTHREADS +# elif SQLITE_OS_WIN +# define SQLITE_MUTEX_W32 +# else +# define SQLITE_MUTEX_NOOP +# endif +#endif + +#ifdef SQLITE_MUTEX_OMIT +/* +** If this is a no-op implementation, implement everything as macros. +*/ +#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) +#define sqlite3_mutex_free(X) +#define sqlite3_mutex_enter(X) +#define sqlite3_mutex_try(X) SQLITE_OK +#define sqlite3_mutex_leave(X) +#define sqlite3_mutex_held(X) ((void)(X),1) +#define sqlite3_mutex_notheld(X) ((void)(X),1) +#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) +#define sqlite3MutexInit() SQLITE_OK +#define sqlite3MutexEnd() +#define MUTEX_LOGIC(X) +#else +#define MUTEX_LOGIC(X) X +#endif /* defined(SQLITE_MUTEX_OMIT) */ + +/************** End of mutex.h ***********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ + +/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default +** synchronous setting to EXTRA. It is no longer supported. +*/ +#ifdef SQLITE_EXTRA_DURABLE +# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE +# define SQLITE_DEFAULT_SYNCHRONOUS 3 +#endif + +/* +** Default synchronous levels. +** +** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ +** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1. +** +** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS +** OFF 1 0 +** NORMAL 2 1 +** FULL 3 2 +** EXTRA 4 3 +** +** The "PRAGMA synchronous" statement also uses the zero-based numbers. +** In other words, the zero-based numbers are used for all external interfaces +** and the one-based values are used internally. +*/ +#ifndef SQLITE_DEFAULT_SYNCHRONOUS +# define SQLITE_DEFAULT_SYNCHRONOUS 2 +#endif +#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS +# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS +#endif + +/* +** Each database file to be accessed by the system is an instance +** of the following structure. There are normally two of these structures +** in the sqlite.aDb[] array. aDb[0] is the main database file and +** aDb[1] is the database file used to hold temporary tables. Additional +** databases may be attached. +*/ +struct Db { + char *zDbSName; /* Name of this database. (schema name, not filename) */ + Btree *pBt; /* The B*Tree structure for this database file */ + u8 safety_level; /* How aggressive at syncing data to disk */ + u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ + Schema *pSchema; /* Pointer to database schema (possibly shared) */ +}; + +/* +** An instance of the following structure stores a database schema. +** +** Most Schema objects are associated with a Btree. The exception is +** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing. +** In shared cache mode, a single Schema object can be shared by multiple +** Btrees that refer to the same underlying BtShared object. +** +** Schema objects are automatically deallocated when the last Btree that +** references them is destroyed. The TEMP Schema is manually freed by +** sqlite3_close(). +* +** A thread must be holding a mutex on the corresponding Btree in order +** to access Schema content. This implies that the thread must also be +** holding a mutex on the sqlite3 connection pointer that owns the Btree. +** For a TEMP Schema, only the connection mutex is required. +*/ +struct Schema { + int schema_cookie; /* Database schema version number for this file */ + int iGeneration; /* Generation counter. Incremented with each change */ + Hash tblHash; /* All tables indexed by name */ + Hash idxHash; /* All (named) indices indexed by name */ + Hash trigHash; /* All triggers indexed by name */ + Hash fkeyHash; /* All foreign keys by referenced table name */ + Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ + u8 file_format; /* Schema format version for this file */ + u8 enc; /* Text encoding used by this database */ + u16 schemaFlags; /* Flags associated with this schema */ + int cache_size; /* Number of pages to use in the cache */ +}; + +/* +** These macros can be used to test, set, or clear bits in the +** Db.pSchema->flags field. +*/ +#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) +#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0) +#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P) +#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P) + +/* +** Allowed values for the DB.pSchema->flags field. +** +** The DB_SchemaLoaded flag is set after the database schema has been +** read into internal hash tables. +** +** DB_UnresetViews means that one or more views have column names that +** have been filled out. If the schema changes, these column names might +** changes and so the view will need to be reset. +*/ +#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) */ + +/* +** The number of different kinds of things that can be limited +** using the sqlite3_limit() interface. +*/ +#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) + +/* +** Lookaside malloc is a set of fixed-size buffers that can be used +** to satisfy small transient memory allocation requests for objects +** associated with a particular database connection. The use of +** lookaside malloc provides a significant performance enhancement +** (approx 10%) by avoiding numerous malloc/free requests while parsing +** SQL statements. +** +** The Lookaside structure holds configuration information about the +** lookaside malloc subsystem. Each available memory allocation in +** the lookaside subsystem is stored on a linked list of LookasideSlot +** objects. +** +** Lookaside allocations are only allowed for objects that are associated +** with a particular database connection. Hence, schema information cannot +** be stored in lookaside because in shared cache mode the schema information +** is shared by multiple database connections. Therefore, while parsing +** schema information, the Lookaside.bEnabled flag is cleared so that +** lookaside allocations are not used to construct the schema objects. +*/ +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 */ + LookasideSlot *pFree; /* List of available buffers */ + void *pStart; /* First byte of available memory space */ + void *pEnd; /* First byte past end of available space */ +}; +struct LookasideSlot { + LookasideSlot *pNext; /* Next buffer in the list of free buffers */ +}; + +/* +** A hash table for built-in function definitions. (Application-defined +** functions use a regular table table from hash.h.) +** +** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. +** Collisions are on the FuncDef.u.pHash chain. +*/ +#define SQLITE_FUNC_HASH_SZ 23 +struct FuncDefHash { + FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ +}; + +#ifdef SQLITE_USER_AUTHENTICATION +/* +** Information held in the "sqlite3" database connection object and used +** to manage user authentication. +*/ +typedef struct sqlite3_userauth sqlite3_userauth; +struct sqlite3_userauth { + u8 authLevel; /* Current authentication level */ + int nAuthPW; /* Size of the zAuthPW in bytes */ + char *zAuthPW; /* Password used to authenticate */ + char *zAuthUser; /* User name used to authenticate */ +}; + +/* Allowed values for sqlite3_userauth.authLevel */ +#define UAUTH_Unknown 0 /* Authentication not yet checked */ +#define UAUTH_Fail 1 /* User authentication failed */ +#define UAUTH_User 2 /* Authenticated as a normal user */ +#define UAUTH_Admin 3 /* Authenticated as an administrator */ + +/* Functions used only by user authorization logic */ +SQLITE_PRIVATE int sqlite3UserAuthTable(const char*); +SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); +SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*); +SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); + +#endif /* SQLITE_USER_AUTHENTICATION */ + +/* +** typedef for the authorization callback function. +*/ +#ifdef SQLITE_USER_AUTHENTICATION + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*, const char*); +#else + typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*); +#endif + +#ifndef SQLITE_OMIT_DEPRECATED +/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing +** in the style of sqlite3_trace() +*/ +#define SQLITE_TRACE_LEGACY 0x80 +#else +#define SQLITE_TRACE_LEGACY 0 +#endif /* SQLITE_OMIT_DEPRECATED */ + + +/* +** Each database connection is an instance of the following structure. +*/ +struct sqlite3 { + sqlite3_vfs *pVfs; /* OS Interface */ + struct Vdbe *pVdbe; /* List of active virtual machines */ + CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ + sqlite3_mutex *mutex; /* Connection mutex */ + Db *aDb; /* All backends */ + int nDb; /* Number of backends currently in use */ + int flags; /* Miscellaneous flags. See below */ + i64 lastRowid; /* ROWID of most recent insert (see above) */ + i64 szMmap; /* Default mmap_size setting */ + unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ + int errCode; /* Most recent error code (SQLITE_*) */ + int errMask; /* & result codes with this before returning */ + int iSysErrno; /* Errno value from last system error */ + u16 dbOptFlags; /* Flags to enable/disable optimizations */ + u8 enc; /* Text encoding */ + u8 autoCommit; /* The auto-commit flag. */ + u8 temp_store; /* 1: file 2: memory 0: default */ + u8 mallocFailed; /* True if we have seen a malloc failure */ + u8 bBenignMalloc; /* Do not require OOMs if true */ + u8 dfltLockMode; /* Default locking-mode for attached dbs */ + signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ + u8 suppressErr; /* Do not issue error messages if true */ + u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ + u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ + u8 mTrace; /* zero or more SQLITE_TRACE flags */ + u8 skipBtreeMutex; /* True if no shared-cache backends */ + u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ + int nextPagesize; /* Pagesize after VACUUM if >0 */ + u32 magic; /* Magic number for detect library misuse */ + int nChange; /* Value returned by sqlite3_changes() */ + int nTotalChange; /* Value returned by sqlite3_total_changes() */ + int aLimit[SQLITE_N_LIMIT]; /* Limits */ + int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ + struct sqlite3InitInfo { /* Information used during initialization */ + int newTnum; /* Rootpage of table being initialized */ + u8 iDb; /* Which db file is being initialized */ + u8 busy; /* TRUE if currently initializing */ + u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ + u8 imposterTable; /* Building an imposter table */ + } init; + int nVdbeActive; /* Number of VDBEs currently running */ + int nVdbeRead; /* Number of active VDBEs that read or write */ + int nVdbeWrite; /* Number of active VDBEs that read and write */ + int nVdbeExec; /* Number of nested calls to VdbeExec() */ + int nVDestroy; /* Number of active OP_VDestroy operations */ + int nExtension; /* Number of loaded extensions */ + void **aExtension; /* Array of shared library handles */ + int (*xTrace)(u32,void*,void*,void*); /* Trace function */ + void *pTraceArg; /* Argument to the trace function */ + void (*xProfile)(void*,const char*,u64); /* Profiling function */ + void *pProfileArg; /* Argument to profile function */ + void *pCommitArg; /* Argument to xCommitCallback() */ + int (*xCommitCallback)(void*); /* Invoked at every commit. */ + void *pRollbackArg; /* Argument to xRollbackCallback() */ + void (*xRollbackCallback)(void*); /* Invoked at every commit. */ + void *pUpdateArg; + void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ + void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ + void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64 + ); + PreUpdate *pPreUpdate; /* Context for active pre-update callback */ +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ +#ifndef SQLITE_OMIT_WAL + int (*xWalCallback)(void *, sqlite3 *, const char *, int); + void *pWalArg; +#endif + void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); + void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); + void *pCollNeededArg; + sqlite3_value *pErr; /* Most recent error message */ + union { + volatile int isInterrupted; /* True if sqlite3_interrupt has been called */ + double notUsed1; /* Spacer */ + } u1; + Lookaside lookaside; /* Lookaside malloc configuration */ +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth; /* Access authorization function */ + void *pAuthArg; /* 1st argument to the access auth function */ +#endif +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + int (*xProgress)(void *); /* The progress callback */ + void *pProgressArg; /* Argument to the progress callback */ + unsigned nProgressOps; /* Number of opcodes for progress callback */ +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + int nVTrans; /* Allocated size of aVTrans */ + Hash aModule; /* populated by sqlite3_create_module() */ + VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ + VTable **aVTrans; /* Virtual tables with open transactions */ + VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ +#endif + Hash aFunc; /* Hash table of connection functions */ + Hash aCollSeq; /* All collating sequences */ + BusyHandler busyHandler; /* Busy callback */ + Db aDbStatic[2]; /* Static space for the 2 default backends */ + Savepoint *pSavepoint; /* List of active savepoints */ + int busyTimeout; /* Busy handler timeout, in msec */ + int nSavepoint; /* Number of non-transaction savepoints */ + int nStatement; /* Number of nested statement-transactions */ + i64 nDeferredCons; /* Net deferred constraints this transaction. */ + i64 nDeferredImmCons; /* Net deferred immediate constraints */ + int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY + /* The following variables are all protected by the STATIC_MASTER + ** mutex, not by sqlite3.mutex. They are used by code in notify.c. + ** + ** When X.pUnlockConnection==Y, that means that X is waiting for Y to + ** unlock so that it can proceed. + ** + ** When X.pBlockingConnection==Y, that means that something that X tried + ** tried to do recently failed with an SQLITE_LOCKED error due to locks + ** held by Y. + */ + sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */ + sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ + void *pUnlockArg; /* Argument to xUnlockNotify */ + void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ + sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ +#endif +#ifdef SQLITE_USER_AUTHENTICATION + sqlite3_userauth auth; /* User authentication information */ +#endif +}; + +/* +** A macro to discover the encoding of a database. +*/ +#define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) +#define ENC(db) ((db)->enc) + +/* +** Possible values for the sqlite3.flags. +** +** Value constraints (enforced via assert()): +** SQLITE_FullFSync == PAGER_FULLFSYNC +** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC +** SQLITE_CacheSpill == PAGER_CACHE_SPILL +*/ +#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ +#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */ +#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ +#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */ +#define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */ +#define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */ +#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */ +#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */ + /* DELETE, or UPDATE and return */ + /* the count using a callback. */ +#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ + /* result set is empty */ +#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ +#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ +#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */ +#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ +#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */ +#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ +#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */ +#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */ +#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */ +#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */ +#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */ +#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */ +#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */ +#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */ +#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */ +#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */ +#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */ +#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */ +#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */ +#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */ +#define SQLITE_NoCkptOnClose 0x80000000 /* No checkpoint on close()/DETACH */ + + +/* +** Bits of the sqlite3.dbOptFlags field that are used by the +** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to +** selectively disable various optimizations. +*/ +#define SQLITE_QueryFlattener 0x0001 /* Query flattening */ +#define SQLITE_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_Stat34 0x0800 /* Use STAT3 or STAT4 data */ +#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */ +#define SQLITE_AllOpts 0xffff /* All optimizations */ + +/* +** Macros for testing whether or not optimizations are enabled or disabled. +*/ +#define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) +#define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) + +/* +** Return true if it OK to factor constant expressions into the initialization +** code. The argument is a Parse object for the code generator. +*/ +#define ConstFactorOk(P) ((P)->okConstFactor) + +/* +** Possible values for the sqlite.magic field. +** The numbers are obtained at random and have no special meaning, other +** than being distinct from one another. +*/ +#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ +#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ +#define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */ +#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ +#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ +#define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* Close with last statement close */ + +/* +** Each SQL function is defined by an instance of the following +** structure. For global built-in functions (ex: substr(), max(), count()) +** a pointer to this structure is held in the sqlite3BuiltinFunctions object. +** For per-connection application-defined functions, a pointer to this +** structure is held in the db->aHash hash table. +** +** The u.pHash field is used by the global built-ins. The u.pDestructor +** field is used by per-connection app-def functions. +*/ +struct FuncDef { + i8 nArg; /* Number of arguments. -1 means unlimited */ + u16 funcFlags; /* Some combination of SQLITE_FUNC_* */ + void *pUserData; /* User data parameter */ + FuncDef *pNext; /* Next function with same name */ + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */ + void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ + const char *zName; /* SQL name of the function. */ + union { + FuncDef *pHash; /* Next with a different name but the same hash */ + FuncDestructor *pDestructor; /* Reference counted destructor function */ + } u; +}; + +/* +** This structure encapsulates a user-function destructor callback (as +** configured using create_function_v2()) and a reference counter. When +** create_function_v2() is called to create a function with a destructor, +** a single object of this type is allocated. FuncDestructor.nRef is set to +** the number of FuncDef objects created (either 1 or 3, depending on whether +** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor +** member of each of the new FuncDef objects is set to point to the allocated +** FuncDestructor. +** +** Thereafter, when one of the FuncDef objects is deleted, the reference +** count on this object is decremented. When it reaches 0, the destructor +** is invoked and the FuncDestructor structure freed. +*/ +struct FuncDestructor { + int nRef; + void (*xDestroy)(void *); + void *pUserData; +}; + +/* +** Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF +** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And +** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There +** are assert() statements in the code to verify this. +** +** Value constraints (enforced via assert()): +** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg +** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG +** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG +** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API +** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API +*/ +#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ +#define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */ +#define SQLITE_FUNC_CASE 0x0008 /* Case-sensitive LIKE-type function */ +#define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */ +#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/ +#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */ +#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */ +#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */ +#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */ +#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */ +#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ +#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ +#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a + ** single query - might change over time */ +#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */ + +/* +** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are +** used to create the initializers for the FuncDef structures. +** +** FUNCTION(zName, nArg, iArg, bNC, xFunc) +** Used to create a scalar function definition of a function zName +** implemented by C function xFunc that accepts nArg arguments. The +** value passed as iArg is cast to a (void*) and made available +** as the user-data (sqlite3_user_data()) for the function. If +** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set. +** +** VFUNCTION(zName, nArg, iArg, bNC, xFunc) +** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag. +** +** DFUNCTION(zName, nArg, iArg, bNC, xFunc) +** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and +** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions +** and functions like sqlite_version() that can change, but not during +** a single query. +** +** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) +** Used to create an aggregate function definition implemented by +** the C functions xStep and xFinal. The first four parameters +** are interpreted in the same way as the first 4 parameters to +** FUNCTION(). +** +** LIKEFUNC(zName, nArg, pArg, flags) +** Used to create a scalar function definition of a function zName +** that accepts nArg arguments and is implemented by a call to C +** function likeFunc. Argument pArg is cast to a (void *) and made +** available as the function user-data (sqlite3_user_data()). The +** FuncDef.flags variable is set to the value passed as the flags +** parameter. +*/ +#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } +#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } +#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } +#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ + {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } +#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + pArg, 0, xFunc, 0, #zName, } +#define LIKEFUNC(zName, nArg, arg, flags) \ + {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ + (void *)arg, 0, likeFunc, 0, #zName, {0} } +#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ + {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} +#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ + {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} + +/* +** All current savepoints are stored in a linked list starting at +** sqlite3.pSavepoint. The first element in the list is the most recently +** opened savepoint. Savepoints are added to the list by the vdbe +** OP_Savepoint instruction. +*/ +struct Savepoint { + char *zName; /* Savepoint name (nul-terminated) */ + i64 nDeferredCons; /* Number of deferred fk violations */ + i64 nDeferredImmCons; /* Number of deferred imm fk. */ + Savepoint *pNext; /* Parent savepoint (if any) */ +}; + +/* +** The following are used as the second parameter to sqlite3Savepoint(), +** and as the P1 argument to the OP_Savepoint instruction. +*/ +#define SAVEPOINT_BEGIN 0 +#define SAVEPOINT_RELEASE 1 +#define SAVEPOINT_ROLLBACK 2 + + +/* +** Each SQLite module (virtual table definition) is defined by an +** instance of the following structure, stored in the sqlite3.aModule +** hash table. +*/ +struct Module { + const sqlite3_module *pModule; /* Callback pointers */ + const char *zName; /* Name passed to create_module() */ + void *pAux; /* pAux passed to create_module() */ + void (*xDestroy)(void *); /* Module destructor function */ + Table *pEpoTab; /* Eponymous table for this module */ +}; + +/* +** information about each column of an SQL table is held in an instance +** of this structure. +*/ +struct Column { + char *zName; /* Name of this column, \000, then the type */ + Expr *pDflt; /* Default value of this column */ + char *zColl; /* Collating sequence. If NULL, use the default */ + u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ + char affinity; /* One of the SQLITE_AFF_... values */ + u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ + u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */ +}; + +/* Allowed values for Column.colFlags: +*/ +#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ +#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ +#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ + +/* +** A "Collating Sequence" is defined by an instance of the following +** structure. Conceptually, a collating sequence consists of a name and +** a comparison routine that defines the order of that sequence. +** +** If CollSeq.xCmp is NULL, it means that the +** collating sequence is undefined. Indices built on an undefined +** collating sequence may not be read or written. +*/ +struct CollSeq { + char *zName; /* Name of the collating sequence, UTF-8 encoded */ + u8 enc; /* Text encoding handled by xCmp() */ + void *pUser; /* First argument to xCmp() */ + int (*xCmp)(void*,int, const void*, int, const void*); + void (*xDel)(void*); /* Destructor for pUser */ +}; + +/* +** A sort order can be either ASC or DESC. +*/ +#define SQLITE_SO_ASC 0 /* Sort in ascending order */ +#define SQLITE_SO_DESC 1 /* Sort in ascending order */ +#define SQLITE_SO_UNDEFINED -1 /* No sort order specified */ + +/* +** Column affinity types. +** +** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and +** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve +** the speed a little by numbering the values consecutively. +** +** But rather than start with 0 or 1, we begin with 'A'. That way, +** when multiple affinity types are concatenated into a string and +** used as the P4 operand, they will be more readable. +** +** Note also that the numeric types are grouped together so that testing +** for a numeric type is a single comparison. And the BLOB type is first. +*/ +#define SQLITE_AFF_BLOB 'A' +#define SQLITE_AFF_TEXT 'B' +#define SQLITE_AFF_NUMERIC 'C' +#define SQLITE_AFF_INTEGER 'D' +#define SQLITE_AFF_REAL 'E' + +#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) + +/* +** The SQLITE_AFF_MASK values masks off the significant bits of an +** affinity value. +*/ +#define SQLITE_AFF_MASK 0x47 + +/* +** Additional bit values that can be ORed with an affinity without +** changing the affinity. +** +** The SQLITE_NOTNULL flag is a combination of NULLEQ and JUMPIFNULL. +** It causes an assert() to fire if either operand to a comparison +** operator is NULL. It is added to certain comparison operators to +** prove that the operands are always NOT NULL. +*/ +#define SQLITE_KEEPNULL 0x08 /* Used by vector == or <> */ +#define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ +#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */ +#define SQLITE_NULLEQ 0x80 /* NULL=NULL */ +#define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ + +/* +** An object of this type is created for each virtual table present in +** the database schema. +** +** If the database schema is shared, then there is one instance of this +** structure for each database connection (sqlite3*) that uses the shared +** schema. This is because each database connection requires its own unique +** instance of the sqlite3_vtab* handle used to access the virtual table +** implementation. sqlite3_vtab* handles can not be shared between +** database connections, even when the rest of the in-memory database +** schema is shared, as the implementation often stores the database +** connection handle passed to it via the xConnect() or xCreate() method +** during initialization internally. This database connection handle may +** then be used by the virtual table implementation to access real tables +** within the database. So that they appear as part of the callers +** transaction, these accesses need to be made via the same database +** connection as that used to execute SQL operations on the virtual table. +** +** All VTable objects that correspond to a single table in a shared +** database schema are initially stored in a linked-list pointed to by +** the Table.pVTable member variable of the corresponding Table object. +** When an sqlite3_prepare() operation is required to access the virtual +** table, it searches the list for the VTable that corresponds to the +** database connection doing the preparing so as to use the correct +** sqlite3_vtab* handle in the compiled query. +** +** When an in-memory Table object is deleted (for example when the +** schema is being reloaded for some reason), the VTable objects are not +** deleted and the sqlite3_vtab* handles are not xDisconnect()ed +** immediately. Instead, they are moved from the Table.pVTable list to +** another linked list headed by the sqlite3.pDisconnect member of the +** corresponding sqlite3 structure. They are then deleted/xDisconnected +** next time a statement is prepared using said sqlite3*. This is done +** to avoid deadlock issues involving multiple sqlite3.mutex mutexes. +** Refer to comments above function sqlite3VtabUnlockList() for an +** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect +** list without holding the corresponding sqlite3.mutex mutex. +** +** The memory for objects of this type is always allocated by +** sqlite3DbMalloc(), using the connection handle stored in VTable.db as +** the first argument. +*/ +struct VTable { + sqlite3 *db; /* Database connection associated with this table */ + Module *pMod; /* Pointer to module implementation */ + sqlite3_vtab *pVtab; /* Pointer to vtab instance */ + int nRef; /* Number of pointers to this structure */ + u8 bConstraint; /* True if constraints are supported */ + int iSavepoint; /* Depth of the SAVEPOINT stack */ + VTable *pNext; /* Next in linked list (see above) */ +}; + +/* +** The schema for each SQL table and view is represented in memory +** by an instance of the following structure. +*/ +struct Table { + char *zName; /* Name of the table or view */ + Column *aCol; /* Information about each column */ + Index *pIndex; /* List of SQL indexes on this table. */ + Select *pSelect; /* NULL for tables. Points to definition if a view. */ + FKey *pFKey; /* Linked list of all foreign keys in this table */ + char *zColAff; /* String defining the affinity of each column */ + ExprList *pCheck; /* All CHECK constraints */ + /* ... also used as column name list in a VIEW */ + int tnum; /* Root BTree page for this table */ + u32 nTabRef; /* Number of pointers to this Table */ + u32 tabFlags; /* Mask of TF_* values */ + i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ + i16 nCol; /* Number of columns in this table */ + LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ + LogEst szTabRow; /* Estimated size of each table row in bytes */ +#ifdef SQLITE_ENABLE_COSTMULT + LogEst costMult; /* Cost multiplier for using this table */ +#endif + u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ +#ifndef SQLITE_OMIT_ALTERTABLE + int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + int nModuleArg; /* Number of arguments to the module */ + char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */ + VTable *pVTable; /* List of VTable objects. */ +#endif + Trigger *pTrigger; /* List of triggers stored in pSchema */ + Schema *pSchema; /* Schema that contains this table */ + Table *pNextZombie; /* Next on the Parse.pZombieTab list */ +}; + +/* +** Allowed values for Table.tabFlags. +** +** TF_OOOHidden applies to tables or view that have hidden columns that are +** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING +** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, +** the TF_OOOHidden attribute would apply in this case. Such tables require +** special handling during INSERT processing. +*/ +#define TF_Readonly 0x0001 /* Read-only system table */ +#define TF_Ephemeral 0x0002 /* An ephemeral table */ +#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */ +#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */ +#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */ +#define TF_WithoutRowid 0x0020 /* No rowid. PRIMARY KEY is the key */ +#define TF_NoVisibleRowid 0x0040 /* No user-visible "rowid" column */ +#define TF_OOOHidden 0x0080 /* Out-of-Order hidden columns */ +#define TF_StatsUsed 0x0100 /* Query planner decisions affected by + ** Index.aiRowLogEst[] values */ +#define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */ + +/* +** Test to see whether or not a table is a virtual table. This is +** done as a macro so that it will be optimized out when virtual +** table support is omitted from the build. +*/ +#ifndef SQLITE_OMIT_VIRTUALTABLE +# define IsVirtual(X) ((X)->nModuleArg) +#else +# define IsVirtual(X) 0 +#endif + +/* +** Macros to determine if a column is hidden. IsOrdinaryHiddenColumn() +** only works for non-virtual tables (ordinary tables and views) and is +** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined. The +** IsHiddenColumn() macro is general purpose. +*/ +#if defined(SQLITE_ENABLE_HIDDEN_COLUMNS) +# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) +# define IsOrdinaryHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) +#elif !defined(SQLITE_OMIT_VIRTUALTABLE) +# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) +# define IsOrdinaryHiddenColumn(X) 0 +#else +# define IsHiddenColumn(X) 0 +# define IsOrdinaryHiddenColumn(X) 0 +#endif + + +/* Does the table have a rowid */ +#define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) +#define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0) + +/* +** Each foreign key constraint is an instance of the following structure. +** +** A foreign key is associated with two tables. The "from" table is +** the table that contains the REFERENCES clause that creates the foreign +** key. The "to" table is the table that is named in the REFERENCES clause. +** Consider this example: +** +** CREATE TABLE ex1( +** a INTEGER PRIMARY KEY, +** b INTEGER CONSTRAINT fk1 REFERENCES ex2(x) +** ); +** +** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2". +** Equivalent names: +** +** from-table == child-table +** to-table == parent-table +** +** Each REFERENCES clause generates an instance of the following structure +** which is attached to the from-table. The to-table need not exist when +** the from-table is created. The existence of the to-table is not checked. +** +** The list of all parents for child Table X is held at X.pFKey. +** +** A list of all children for a table named Z (which might not even exist) +** is held in Schema.fkeyHash with a hash key of Z. +*/ +struct FKey { + Table *pFrom; /* Table containing the REFERENCES clause (aka: Child) */ + FKey *pNextFrom; /* Next FKey with the same in pFrom. Next parent of pFrom */ + char *zTo; /* Name of table that the key points to (aka: Parent) */ + FKey *pNextTo; /* Next with the same zTo. Next child of zTo. */ + FKey *pPrevTo; /* Previous with the same zTo */ + int nCol; /* Number of columns in this key */ + /* EV: R-30323-21917 */ + u8 isDeferred; /* True if constraint checking is deferred till COMMIT */ + u8 aAction[2]; /* ON DELETE and ON UPDATE actions, respectively */ + Trigger *apTrigger[2];/* Triggers for aAction[] actions */ + struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ + int iFrom; /* Index of column in pFrom */ + char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */ + } aCol[1]; /* One entry for each of nCol columns */ +}; + +/* +** SQLite supports many different ways to resolve a constraint +** error. ROLLBACK processing means that a constraint violation +** causes the operation in process to fail and for the current transaction +** to be rolled back. ABORT processing means the operation in process +** fails and any prior changes from that one operation are backed out, +** but the transaction is not rolled back. FAIL processing means that +** the operation in progress stops and returns an error code. But prior +** changes due to the same operation are not backed out and no rollback +** occurs. IGNORE means that the particular row that caused the constraint +** error is not inserted or updated. Processing continues and no error +** is returned. REPLACE means that preexisting database rows that caused +** a UNIQUE constraint violation are removed so that the new insert or +** update can proceed. Processing continues and no error is reported. +** +** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys. +** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the +** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign +** key is set to NULL. CASCADE means that a DELETE or UPDATE of the +** referenced table row is propagated into the row that holds the +** foreign key. +** +** The following symbolic values are used to record which type +** of action to take. +*/ +#define OE_None 0 /* There is no constraint to check */ +#define OE_Rollback 1 /* Fail the operation and rollback the transaction */ +#define OE_Abort 2 /* Back out changes but do no rollback transaction */ +#define OE_Fail 3 /* Stop the operation but leave all prior changes */ +#define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ +#define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ + +#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ +#define OE_SetNull 7 /* Set the foreign key value to NULL */ +#define OE_SetDflt 8 /* Set the foreign key value to its default */ +#define OE_Cascade 9 /* Cascade the changes */ + +#define OE_Default 10 /* Do whatever the default action is */ + + +/* +** An instance of the following structure is passed as the first +** argument to sqlite3VdbeKeyCompare and is used to control the +** comparison of the two index keys. +** +** Note that aSortOrder[] and aColl[] have nField+1 slots. There +** are nField slots for the columns of an index then one extra slot +** for the rowid at the end. +*/ +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 */ + sqlite3 *db; /* The database connection */ + u8 *aSortOrder; /* Sort order for each column. */ + CollSeq *aColl[1]; /* Collating sequence for each term of the key */ +}; + +/* +** This object holds a record which has been parsed out into individual +** fields, for the purposes of doing a comparison. +** +** A record is an object that contains one or more fields of data. +** Records are used to store the content of a table row and to store +** the key of an index. A blob encoding of a record is created by +** the OP_MakeRecord opcode of the VDBE and is disassembled by the +** OP_Column opcode. +** +** An instance of this object serves as a "key" for doing a search on +** an index b+tree. The goal of the search is to find the entry that +** is closed to the key described by this object. This object might hold +** just a prefix of the key. The number of fields is given by +** pKeyInfo->nField. +** +** The r1 and r2 fields are the values to return if this key is less than +** or greater than a key in the btree, respectively. These are normally +** -1 and +1 respectively, but might be inverted to +1 and -1 if the b-tree +** is in DESC order. +** +** The key comparison functions actually return default_rc when they find +** an equals comparison. default_rc can be -1, 0, or +1. If there are +** multiple entries in the b-tree with the same key (when only looking +** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to +** cause the search to find the last match, or +1 to cause the search to +** find the first match. +** +** The key comparison functions will set eqSeen to true if they ever +** get and equal results when comparing this structure to a b-tree record. +** When default_rc!=0, the search might end up on the record immediately +** before the first match or immediately after the last match. The +** eqSeen field will indicate whether or not an exact match exists in the +** b-tree. +*/ +struct UnpackedRecord { + KeyInfo *pKeyInfo; /* Collation and sort-order information */ + Mem *aMem; /* Values */ + 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) */ + u8 eqSeen; /* True if an equality comparison has been seen */ +}; + + +/* +** Each SQL index is represented in memory by an +** instance of the following structure. +** +** The columns of the table that are to be indexed are described +** by the aiColumn[] field of this structure. For example, suppose +** we have the following table and index: +** +** CREATE TABLE Ex1(c1 int, c2 int, c3 text); +** CREATE INDEX Ex2 ON Ex1(c3,c1); +** +** In the Table structure describing Ex1, nCol==3 because there are +** three columns in the table. In the Index structure describing +** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. +** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the +** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. +** The second column to be indexed (c1) has an index of 0 in +** Ex1.aCol[], hence Ex2.aiColumn[1]==0. +** +** The Index.onError field determines whether or not the indexed columns +** must be unique and what to do if they are not. When Index.onError=OE_None, +** it means this is not a unique index. Otherwise it is a unique index +** and the value of Index.onError indicate the which conflict resolution +** algorithm to employ whenever an attempt is made to insert a non-unique +** element. +** +** While parsing a CREATE TABLE or CREATE INDEX statement in order to +** generate VDBE code (as opposed to parsing one read from an sqlite_master +** table as part of parsing an existing database schema), transient instances +** of this structure may be created. In this case the Index.tnum variable is +** used to store the address of a VDBE instruction, not a database page +** number (it cannot - the database page is not allocated until the VDBE +** program is executed). See convertToWithoutRowidTable() for details. +*/ +struct Index { + char *zName; /* Name of this index */ + i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */ + LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */ + Table *pTable; /* The SQL table being indexed */ + char *zColAff; /* String defining the affinity of each column */ + Index *pNext; /* The next index associated with the same table */ + Schema *pSchema; /* Schema containing this index */ + u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ + const char **azColl; /* Array of collation sequence names for index */ + Expr *pPartIdxWhere; /* WHERE clause for partial indices */ + ExprList *aColExpr; /* Column expressions */ + int tnum; /* DB Page containing root of this index */ + LogEst szIdxRow; /* Estimated average row size in bytes */ + u16 nKeyCol; /* Number of columns forming the key */ + u16 nColumn; /* Number of columns stored in the index */ + u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ + unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ + unsigned bUnordered:1; /* Use this index for == or IN queries only */ + unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ + unsigned isResized:1; /* True if resizeIndexObject() has been called */ + unsigned isCovering:1; /* True if this is a covering index */ + unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ + unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + int nSample; /* Number of elements in aSample[] */ + int nSampleCol; /* Size of IndexSample.anEq[] and so on */ + tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ + IndexSample *aSample; /* Samples of the left-most key */ + tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ + tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ +#endif +}; + +/* +** Allowed values for Index.idxType +*/ +#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ +#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ +#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ + +/* Return true if index X is a PRIMARY KEY index */ +#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) + +/* Return true if index X is a UNIQUE index */ +#define IsUniqueIndex(X) ((X)->onError!=OE_None) + +/* The Index.aiColumn[] values are normally positive integer. But +** there are some negative values that have special meaning: +*/ +#define XN_ROWID (-1) /* Indexed column is the rowid */ +#define XN_EXPR (-2) /* Indexed column is an expression */ + +/* +** Each sample stored in the sqlite_stat3 table is represented in memory +** using a structure of this type. See documentation at the top of the +** analyze.c source file for additional information. +*/ +struct IndexSample { + void *p; /* Pointer to sampled record */ + int n; /* Size of record in bytes */ + tRowcnt *anEq; /* Est. number of rows where the key equals this sample */ + tRowcnt *anLt; /* Est. number of rows where key is less than this sample */ + tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ +}; + +/* +** Each token coming out of the lexer is an instance of +** this structure. Tokens are also used as part of an expression. +** +** Note if Token.z==0 then Token.dyn and Token.n are undefined and +** may contain random values. Do not make any assumptions about Token.dyn +** and Token.n when Token.z==0. +*/ +struct Token { + const char *z; /* Text of the token. Not NULL-terminated! */ + unsigned int n; /* Number of characters in this token */ +}; + +/* +** An instance of this structure contains information needed to generate +** code for a SELECT that contains aggregate functions. +** +** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a +** pointer to this structure. The Expr.iColumn field is the index in +** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate +** code for that node. +** +** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the +** original Select structure that describes the SELECT statement. These +** fields do not need to be freed when deallocating the AggInfo structure. +*/ +struct AggInfo { + u8 directMode; /* Direct rendering mode means take data directly + ** from source tables rather than from accumulators */ + u8 useSortingIdx; /* In direct mode, reference the sorting index rather + ** than the source table */ + int sortingIdx; /* Cursor number of the sorting index */ + int sortingIdxPTab; /* Cursor number of pseudo-table */ + int nSortingColumn; /* Number of columns in the sorting index */ + int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */ + ExprList *pGroupBy; /* The group by clause */ + struct AggInfo_col { /* For each column used in source tables */ + Table *pTab; /* Source table */ + int iTable; /* Cursor number of the source table */ + int iColumn; /* Column number within the source table */ + int iSorterColumn; /* Column number in the sorting index */ + int iMem; /* Memory location that acts as accumulator */ + Expr *pExpr; /* The original expression */ + } *aCol; + int nColumn; /* Number of used entries in aCol[] */ + int nAccumulator; /* Number of columns that show through to the output. + ** Additional columns are used only as parameters to + ** aggregate functions */ + struct AggInfo_func { /* For each aggregate function */ + Expr *pExpr; /* Expression encoding the function */ + FuncDef *pFunc; /* The aggregate function implementation */ + int iMem; /* Memory location that acts as accumulator */ + int iDistinct; /* Ephemeral table used to enforce DISTINCT */ + } *aFunc; + int nFunc; /* Number of entries in aFunc[] */ +}; + +/* +** The datatype ynVar is a signed integer, either 16-bit or 32-bit. +** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater +** than 32767 we have to make it 32-bit. 16-bit is preferred because +** it uses less memory in the Expr object, which is a big memory user +** in systems with lots of prepared statements. And few applications +** need more than about 10 or 20 variables. But some extreme users want +** to have prepared statements with over 32767 variables, and for them +** the option is available (at compile-time). +*/ +#if SQLITE_MAX_VARIABLE_NUMBER<=32767 +typedef i16 ynVar; +#else +typedef int ynVar; +#endif + +/* +** Each node of an expression in the parse tree is an instance +** of this structure. +** +** Expr.op is the opcode. The integer parser token codes are reused +** as opcodes here. For example, the parser defines TK_GE to be an integer +** code representing the ">=" operator. This same integer code is reused +** to represent the greater-than-or-equal-to operator in the expression +** tree. +** +** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, +** or TK_STRING), then Expr.token contains the text of the SQL literal. If +** the expression is a variable (TK_VARIABLE), then Expr.token contains the +** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), +** then Expr.token contains the name of the function. +** +** Expr.pRight and Expr.pLeft are the left and right subexpressions of a +** binary operator. Either or both may be NULL. +** +** Expr.x.pList is a list of arguments if the expression is an SQL function, +** a CASE expression or an IN expression of the form " IN (, ...)". +** Expr.x.pSelect is used if the expression is a sub-select or an expression of +** the form " IN (SELECT ...)". If the EP_xIsSelect bit is set in the +** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is +** valid. +** +** An expression of the form ID or ID.ID refers to a column in a table. +** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is +** the integer cursor number of a VDBE cursor pointing to that table and +** Expr.iColumn is the column number for the specific column. If the +** expression is used as a result in an aggregate SELECT, then the +** value is also stored in the Expr.iAgg column in the aggregate so that +** it can be accessed after all aggregates are computed. +** +** If the expression is an unbound variable marker (a question mark +** character '?' in the original SQL) then the Expr.iTable holds the index +** number for that variable. +** +** If the expression is a subquery then Expr.iColumn holds an integer +** register number containing the result of the subquery. If the +** subquery gives a constant result, then iTable is -1. If the subquery +** gives a different answer at different times during statement processing +** then iTable is the address of a subroutine that computes the subquery. +** +** If the Expr is of type OP_Column, and the table it is selecting from +** is a disk table or the "old.*" pseudo-table, then pTab points to the +** corresponding table definition. +** +** ALLOCATION NOTES: +** +** Expr objects can use a lot of memory space in database schema. To +** help reduce memory requirements, sometimes an Expr object will be +** truncated. And to reduce the number of memory allocations, sometimes +** two or more Expr objects will be stored in a single memory allocation, +** together with Expr.zToken strings. +** +** If the EP_Reduced and EP_TokenOnly flags are set when +** an Expr object is truncated. When EP_Reduced is set, then all +** the child Expr objects in the Expr.pLeft and Expr.pRight subtrees +** are contained within the same memory allocation. Note, however, that +** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately +** allocated, regardless of whether or not EP_Reduced is set. +*/ +struct Expr { + u8 op; /* Operation performed by this node */ + char affinity; /* The affinity of the column or 0 if not a column */ + u32 flags; /* Various flags. EP_* See below */ + union { + char *zToken; /* Token value. Zero terminated and dequoted */ + int iValue; /* Non-negative integer value if EP_IntValue */ + } u; + + /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no + ** space is allocated for the fields below this point. An attempt to + ** access them will result in a segfault or malfunction. + *********************************************************************/ + + Expr *pLeft; /* Left subnode */ + Expr *pRight; /* Right subnode */ + union { + ExprList *pList; /* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN */ + Select *pSelect; /* EP_xIsSelect and op = IN, EXISTS, SELECT */ + } x; + + /* If the EP_Reduced flag is set in the Expr.flags mask, then no + ** space is allocated for the fields below this point. An attempt to + ** access them will result in a segfault or malfunction. + *********************************************************************/ + +#if SQLITE_MAX_EXPR_DEPTH>0 + int nHeight; /* Height of the tree headed by this node */ +#endif + int iTable; /* TK_COLUMN: cursor number of table holding column + ** TK_REGISTER: register number + ** TK_TRIGGER: 1 -> new, 0 -> old + ** EP_Unlikely: 134217728 times likelihood + ** TK_SELECT: 1st register of result vector */ + ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. + ** TK_VARIABLE: variable number (always >= 1). + ** TK_SELECT_COLUMN: column of the result vector */ + i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ + i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ + u8 op2; /* TK_REGISTER: original value of Expr.op + ** 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. */ +}; + +/* +** The following are the meanings of bits in the Expr.flags field. +*/ +#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ +#define EP_Agg 0x000002 /* Contains one or more aggregate functions */ +#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ +#define EP_Error 0x000008 /* Expression contains one or more errors */ +#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ +#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ +#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ +#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ +#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ +#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ +#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ +#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ +#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ +#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ +#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ +#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */ +#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ +#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ +#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ +#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ +#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ +#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ +#define EP_Alias 0x400000 /* Is an alias for a result set column */ +#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ + +/* +** Combinations of two or more EP_* flags +*/ +#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */ + +/* +** These macros can be used to test, set, or clear bits in the +** Expr.flags field. +*/ +#define ExprHasProperty(E,P) (((E)->flags&(P))!=0) +#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) +#define ExprSetProperty(E,P) (E)->flags|=(P) +#define ExprClearProperty(E,P) (E)->flags&=~(P) + +/* The ExprSetVVAProperty() macro is used for Verification, Validation, +** and Accreditation only. It works like ExprSetProperty() during VVA +** processes but is a no-op for delivery. +*/ +#ifdef SQLITE_DEBUG +# define ExprSetVVAProperty(E,P) (E)->flags|=(P) +#else +# define ExprSetVVAProperty(E,P) +#endif + +/* +** Macros to determine the number of bytes required by a normal Expr +** struct, an Expr struct with the EP_Reduced flag set in Expr.flags +** and an Expr struct with the EP_TokenOnly flag set. +*/ +#define EXPR_FULLSIZE sizeof(Expr) /* Full size */ +#define EXPR_REDUCEDSIZE offsetof(Expr,iTable) /* Common features */ +#define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */ + +/* +** Flags passed to the sqlite3ExprDup() function. See the header comment +** above sqlite3ExprDup() for details. +*/ +#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */ + +/* +** A list of expressions. Each expression may optionally have a +** name. An expr/name combination can be used in several ways, such +** as the list of "expr AS ID" fields following a "SELECT" or in the +** list of "ID = expr" items in an UPDATE. A list of expressions can +** also be used as the argument to a function, in which case the a.zName +** field is not used. +** +** By default the Expr.zSpan field holds a human-readable description of +** the expression that is used in the generation of error messages and +** column labels. In this case, Expr.zSpan is typically the text of a +** column expression as it exists in a SELECT statement. However, if +** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name +** of the result column in the form: DATABASE.TABLE.COLUMN. This later +** form is used for name resolution with nested FROM clauses. +*/ +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 */ + char *zSpan; /* Original text of the expression */ + u8 sortOrder; /* 1 for DESC or 0 for ASC */ + unsigned done :1; /* A flag to indicate when processing is finished */ + unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */ + unsigned reusable :1; /* Constant expression is reusable */ + union { + struct { + u16 iOrderByCol; /* For ORDER BY, column number in result set */ + u16 iAlias; /* Index into Parse.aAlias[] for zName */ + } x; + int iConstExprReg; /* Register in which Expr value is cached */ + } u; + } a[1]; /* One slot for each expression in the list */ +}; + +/* +** An instance of this structure is used by the parser to record both +** the parse tree for an expression and the span of input text for an +** expression. +*/ +struct ExprSpan { + Expr *pExpr; /* The expression parse tree */ + const char *zStart; /* First character of input text */ + const char *zEnd; /* One character past the end of input text */ +}; + +/* +** An instance of this structure can hold a simple list of identifiers, +** such as the list "a,b,c" in the following statements: +** +** INSERT INTO t(a,b,c) VALUES ...; +** CREATE INDEX idx ON t(a,b,c); +** CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...; +** +** The IdList.a.idx field is used when the IdList represents the list of +** column names after a table name in an INSERT statement. In the statement +** +** INSERT INTO t(a,b,c) ... +** +** If "a" is the k-th column of table "t", then IdList.a[0].idx==k. +*/ +struct IdList { + struct IdList_item { + char *zName; /* Name of the identifier */ + int idx; /* Index in some Table.aCol[] of a column named zName */ + } *a; + int nId; /* Number of identifiers on the list */ +}; + +/* +** The bitmask datatype defined below is used for various optimizations. +** +** Changing this from a 64-bit to a 32-bit type limits the number of +** tables in a join to 32 instead of 64. But it also reduces the size +** of the library by 738 bytes on ix86. +*/ +#ifdef SQLITE_BITMASK_TYPE + typedef SQLITE_BITMASK_TYPE Bitmask; +#else + typedef u64 Bitmask; +#endif + +/* +** The number of bits in a Bitmask. "BMS" means "BitMask Size". +*/ +#define BMS ((int)(sizeof(Bitmask)*8)) + +/* +** A bit in a Bitmask +*/ +#define MASKBIT(n) (((Bitmask)1)<<(n)) +#define MASKBIT32(n) (((unsigned int)1)<<(n)) +#define ALLBITS ((Bitmask)-1) + +/* +** The following structure describes the FROM clause of a SELECT statement. +** Each table or subquery in the FROM clause is a separate element of +** the SrcList.a[] array. +** +** With the addition of multiple database support, the following structure +** can also be used to describe a particular table such as the table that +** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL, +** such a table must be a simple name: ID. But in SQLite, the table can +** now be identified by a database name, a dot, then the table name: ID.ID. +** +** The jointype starts out showing the join type between the current table +** and the next table on the list. The parser builds the list this way. +** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each +** jointype expresses the join between the table and the previous table. +** +** In the colUsed field, the high-order bit (bit 63) is set if the table +** contains more than 63 columns and the 64-th or later column is used. +*/ +struct SrcList { + int nSrc; /* Number of tables or subqueries in the FROM clause */ + u32 nAlloc; /* Number of entries allocated in a[] below */ + struct SrcList_item { + Schema *pSchema; /* Schema to which this item is fixed */ + char *zDatabase; /* Name of database holding this table */ + char *zName; /* Name of the table */ + char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ + Table *pTab; /* An SQL table corresponding to zName */ + Select *pSelect; /* A SELECT statement used in place of a table name */ + int addrFillSub; /* Address of subroutine to manifest a subquery */ + int regReturn; /* Register holding return address of addrFillSub */ + int regResult; /* Registers holding results of a co-routine */ + struct { + u8 jointype; /* Type of join between this table and the previous */ + unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ + unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ + unsigned isTabFunc :1; /* True if table-valued-function syntax */ + unsigned isCorrelated :1; /* True if sub-query is correlated */ + unsigned viaCoroutine :1; /* Implemented as a co-routine */ + unsigned isRecursive :1; /* True for recursive reference in WITH */ + } fg; +#ifndef SQLITE_OMIT_EXPLAIN + u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ +#endif + int iCursor; /* The VDBE cursor number used to access this table */ + Expr *pOn; /* The ON clause of a join */ + IdList *pUsing; /* The USING clause of a join */ + Bitmask colUsed; /* Bit N (1<" clause */ + ExprList *pFuncArg; /* Arguments to table-valued-function */ + } u1; + Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ + } a[1]; /* One entry for each identifier on the list */ +}; + +/* +** Permitted values of the SrcList.a.jointype field +*/ +#define JT_INNER 0x0001 /* Any kind of inner or cross join */ +#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */ +#define JT_NATURAL 0x0004 /* True for a "natural" join */ +#define JT_LEFT 0x0008 /* Left outer join */ +#define JT_RIGHT 0x0010 /* Right outer join */ +#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */ +#define JT_ERROR 0x0040 /* unknown or unsupported join type */ + + +/* +** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin() +** and the WhereInfo.wctrlFlags member. +** +** Value constraints (enforced via assert()): +** WHERE_USE_LIMIT == SF_FixedLimit +*/ +#define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ +#define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ +#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ +#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ +#define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */ +#define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */ +#define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of + ** the OR optimization */ +#define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */ +#define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ +#define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ +#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ +#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */ +#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ +#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */ + /* 0x2000 not currently used */ +#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ + /* 0x8000 not currently used */ + +/* Allowed return values from sqlite3WhereIsDistinct() +*/ +#define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ +#define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ +#define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */ +#define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */ + +/* +** A NameContext defines a context in which to resolve table and column +** names. The context consists of a list of tables (the pSrcList) field and +** a list of named expression (pEList). The named expression list may +** be NULL. The pSrc corresponds to the FROM clause of a SELECT or +** to the table being operated on by INSERT, UPDATE, or DELETE. The +** pEList corresponds to the result set of a SELECT and is NULL for +** other statements. +** +** NameContexts can be nested. When resolving names, the inner-most +** context is searched first. If no match is found, the next outer +** context is checked. If there is still no match, the next context +** is checked. This process continues until either a match is found +** or all contexts are check. When a match is found, the nRef member of +** the context containing the match is incremented. +** +** Each subquery gets a new NameContext. The pNext field points to the +** NameContext in the parent query. Thus the process of scanning the +** NameContext list corresponds to searching through successively outer +** subqueries looking for a match. +*/ +struct NameContext { + Parse *pParse; /* The parser */ + SrcList *pSrcList; /* One or more tables used to resolve names */ + ExprList *pEList; /* Optional list of result-set columns */ + AggInfo *pAggInfo; /* Information about aggregates at this level */ + NameContext *pNext; /* Next outer name context. NULL for outermost */ + int nRef; /* Number of names resolved by this context */ + int nErr; /* Number of errors encountered while resolving names */ + u16 ncFlags; /* Zero or more NC_* flags defined below */ +}; + +/* +** Allowed values for the NameContext, ncFlags field. +** +** Value constraints (all checked via assert()): +** NC_HasAgg == SF_HasAgg +** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** +*/ +#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ +#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ +#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ +#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ +#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ +#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ +#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */ +#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ + +/* +** An instance of the following structure contains all information +** needed to generate code for a single SELECT statement. +** +** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. +** If there is a LIMIT clause, the parser sets nLimit to the value of the +** limit and nOffset to the value of the offset (or 0 if there is not +** offset). But later on, nLimit and nOffset become the memory locations +** in the VDBE that record the limit and offset counters. +** +** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. +** These addresses must be stored so that we can go back and fill in +** the P4_KEYINFO and P2 parameters later. Neither the KeyInfo nor +** the number of columns in P2 can be computed at the same time +** as the OP_OpenEphm instruction is coded because not +** enough information about the compound query is known at that point. +** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences +** for the result set. The KeyInfo for addrOpenEphm[2] contains collating +** sequences for the ORDER BY clause. +*/ +struct Select { + ExprList *pEList; /* The fields of the result */ + u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ + LogEst nSelectRow; /* Estimated number of result rows */ + u32 selFlags; /* Various SF_* values */ + int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ +#if SELECTTRACE_ENABLED + char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ +#endif + int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ + SrcList *pSrc; /* The FROM clause */ + Expr *pWhere; /* The WHERE clause */ + ExprList *pGroupBy; /* The GROUP BY clause */ + Expr *pHaving; /* The HAVING clause */ + ExprList *pOrderBy; /* The ORDER BY clause */ + Select *pPrior; /* Prior select in a compound select statement */ + Select *pNext; /* Next select to the left in a compound */ + Expr *pLimit; /* LIMIT expression. NULL means not used. */ + Expr *pOffset; /* OFFSET expression. NULL means not used. */ + With *pWith; /* WITH clause attached to this select. Or NULL. */ +}; + +/* +** Allowed values for Select.selFlags. The "SF" prefix stands for +** "Select Flag". +** +** Value constraints (all checked via assert()) +** SF_HasAgg == NC_HasAgg +** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX +** SF_FixedLimit == WHERE_USE_LIMIT +*/ +#define SF_Distinct 0x00001 /* Output should be DISTINCT */ +#define SF_All 0x00002 /* Includes the ALL keyword */ +#define SF_Resolved 0x00004 /* Identifiers have been resolved */ +#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */ +#define SF_HasAgg 0x00010 /* Contains aggregate functions */ +#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */ +#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */ +#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */ +#define SF_Compound 0x00100 /* Part of a compound query */ +#define SF_Values 0x00200 /* Synthesized from VALUES clause */ +#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */ +#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */ +#define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */ +#define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */ +#define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */ +#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ +#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ +#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ + + +/* +** The results of a SELECT can be distributed in several ways, as defined +** by one of the following macros. The "SRT" prefix means "SELECT Result +** Type". +** +** SRT_Union Store results as a key in a temporary index +** identified by pDest->iSDParm. +** +** SRT_Except Remove results from the temporary index pDest->iSDParm. +** +** SRT_Exists Store a 1 in memory cell pDest->iSDParm if the result +** set is not empty. +** +** SRT_Discard Throw the results away. This is used by SELECT +** statements within triggers whose only purpose is +** the side-effects of functions. +** +** All of the above are free to ignore their ORDER BY clause. Those that +** follow must honor the ORDER BY clause. +** +** SRT_Output Generate a row of output (using the OP_ResultRow +** opcode) for each row in the result set. +** +** SRT_Mem Only valid if the result is a single column. +** Store the first column of the first result row +** in register pDest->iSDParm then abandon the rest +** of the query. This destination implies "LIMIT 1". +** +** SRT_Set The result must be a single column. Store each +** row of result as the key in table pDest->iSDParm. +** Apply the affinity pDest->affSdst before storing +** results. Used to implement "IN (SELECT ...)". +** +** SRT_EphemTab Create an temporary table pDest->iSDParm and store +** the result there. The cursor is left open after +** returning. This is like SRT_Table except that +** this destination uses OP_OpenEphemeral to create +** the table first. +** +** SRT_Coroutine Generate a co-routine that returns a new row of +** results each time it is invoked. The entry point +** of the co-routine is stored in register pDest->iSDParm +** and the result row is stored in pDest->nDest registers +** starting with pDest->iSdst. +** +** SRT_Table Store results in temporary table pDest->iSDParm. +** SRT_Fifo This is like SRT_EphemTab except that the table +** is assumed to already be open. SRT_Fifo has +** the additional property of being able to ignore +** the ORDER BY clause. +** +** SRT_DistFifo Store results in a temporary table pDest->iSDParm. +** But also use temporary table pDest->iSDParm+1 as +** a record of all prior results and ignore any duplicate +** rows. Name means: "Distinct Fifo". +** +** SRT_Queue Store results in priority queue pDest->iSDParm (really +** an index). Append a sequence number so that all entries +** are distinct. +** +** SRT_DistQueue Store results in priority queue pDest->iSDParm only if +** the same record has never been stored before. The +** index at pDest->iSDParm+1 hold all prior stores. +*/ +#define SRT_Union 1 /* Store result as keys in an index */ +#define SRT_Except 2 /* Remove result from a UNION index */ +#define SRT_Exists 3 /* Store 1 if the result is not empty */ +#define SRT_Discard 4 /* Do not save the results anywhere */ +#define SRT_Fifo 5 /* Store result as data with an automatic rowid */ +#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */ +#define SRT_Queue 7 /* Store result in an queue */ +#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */ + +/* The ORDER BY clause is ignored for all of the above */ +#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue) + +#define SRT_Output 9 /* Output each row of result */ +#define SRT_Mem 10 /* Store result in a memory cell */ +#define SRT_Set 11 /* Store results as keys in an index */ +#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ +#define SRT_Coroutine 13 /* Generate a single row of result */ +#define SRT_Table 14 /* Store result as data with an automatic rowid */ + +/* +** An instance of this object describes where to put of the results of +** a SELECT statement. +*/ +struct SelectDest { + u8 eDest; /* How to dispose of the results. On of SRT_* above. */ + char *zAffSdst; /* Affinity used when eDest==SRT_Set */ + int iSDParm; /* A parameter used by the eDest disposal method */ + int iSdst; /* Base register where results are written */ + int nSdst; /* Number of registers allocated */ + ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ +}; + +/* +** During code generation of statements that do inserts into AUTOINCREMENT +** tables, the following information is attached to the Table.u.autoInc.p +** pointer of each autoincrement table to record some side information that +** the code generator needs. We have to keep per-table autoincrement +** information in case inserts are done within triggers. Triggers do not +** normally coordinate their activities, but we do need to coordinate the +** loading and saving of autoincrement information. +*/ +struct AutoincInfo { + AutoincInfo *pNext; /* Next info block in a list of them all */ + Table *pTab; /* Table this info block refers to */ + int iDb; /* Index in sqlite3.aDb[] of database holding pTab */ + int regCtr; /* Memory register holding the rowid counter */ +}; + +/* +** Size of the column cache +*/ +#ifndef SQLITE_N_COLCACHE +# define SQLITE_N_COLCACHE 10 +#endif + +/* +** At least one instance of the following structure is created for each +** trigger that may be fired while parsing an INSERT, UPDATE or DELETE +** statement. All such objects are stored in the linked list headed at +** Parse.pTriggerPrg and deleted once statement compilation has been +** completed. +** +** A Vdbe sub-program that implements the body and WHEN clause of trigger +** TriggerPrg.pTrigger, assuming a default ON CONFLICT clause of +** TriggerPrg.orconf, is stored in the TriggerPrg.pProgram variable. +** The Parse.pTriggerPrg list never contains two entries with the same +** values for both pTrigger and orconf. +** +** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns +** accessed (or set to 0 for triggers fired as a result of INSERT +** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to +** a mask of new.* columns used by the program. +*/ +struct TriggerPrg { + Trigger *pTrigger; /* Trigger this program was coded from */ + TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */ + SubProgram *pProgram; /* Program implementing pTrigger/orconf */ + int orconf; /* Default ON CONFLICT policy */ + u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */ +}; + +/* +** The yDbMask datatype for the bitmask of all attached databases. +*/ +#if SQLITE_MAX_ATTACHED>30 + typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED+9)/8]; +# define DbMaskTest(M,I) (((M)[(I)/8]&(1<<((I)&7)))!=0) +# define DbMaskZero(M) memset((M),0,sizeof(M)) +# define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) +# define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) +# define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) +#else + typedef unsigned int yDbMask; +# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) +# define DbMaskZero(M) (M)=0 +# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I)) +# define DbMaskAllZero(M) (M)==0 +# define DbMaskNonZero(M) (M)!=0 +#endif + +/* +** An SQL parser context. A copy of this structure is passed through +** the parser and down into all the parser action routine in order to +** carry around information that is global to the entire parse. +** +** The structure is divided into two parts. When the parser and code +** generate call themselves recursively, the first part of the structure +** is constant but the second part is reset at the beginning and end of +** each recursion. +** +** The nTableLock and aTableLock variables are only used if the shared-cache +** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are +** used to store the set of table-locks required by the statement being +** compiled. Function sqlite3TableLock() is used to add entries to the +** list. +*/ +struct Parse { + sqlite3 *db; /* The main database structure */ + char *zErrMsg; /* An error message */ + Vdbe *pVdbe; /* An engine for executing database bytecode */ + int rc; /* Return code from execution */ + u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ + u8 checkSchema; /* Causes schema cookie check after an error */ + u8 nested; /* Number of nested calls to the parser/code generator */ + u8 nTempReg; /* Number of temporary registers in aTempReg[] */ + u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ + u8 mayAbort; /* True if statement may throw an ABORT exception */ + u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ + u8 okConstFactor; /* OK to factor out constants */ + u8 disableLookaside; /* Number of times lookaside has been disabled */ + u8 nColCache; /* Number of entries in aColCache[] */ + int nRangeReg; /* Size of the temporary register block */ + int iRangeReg; /* First register in temporary register block */ + int nErr; /* Number of errors seen */ + int nTab; /* Number of previously allocated VDBE cursors */ + int nMem; /* Number of memory cells used so far */ + int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ + int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ + int ckBase; /* Base register of data during check constraints */ + int iSelfTab; /* Table of an index whose exprs are being coded */ + int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ + int iCacheCnt; /* Counter used to generate aColCache[].lru values */ + int nLabel; /* Number of labels used */ + int *aLabel; /* Space to hold the labels */ + ExprList *pConstExpr;/* Constant expressions */ + Token constraintName;/* Name of the constraint currently being parsed */ + yDbMask writeMask; /* Start a write transaction on these databases */ + yDbMask cookieMask; /* Bitmask of schema verified databases */ + int regRowid; /* Register holding rowid of CREATE TABLE entry */ + int regRoot; /* Register holding root page number for new objects */ + int nMaxArg; /* Max args passed to user function by sub-program */ +#if SELECTTRACE_ENABLED + int nSelect; /* Number of SELECT statements seen */ + int nSelectIndent; /* How far to indent SELECTTRACE() output */ +#endif +#ifndef SQLITE_OMIT_SHARED_CACHE + int nTableLock; /* Number of locks in aTableLock */ + TableLock *aTableLock; /* Required table locks for shared-cache mode */ +#endif + AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ + Parse *pToplevel; /* Parse structure for main program (or NULL) */ + Table *pTriggerTab; /* Table triggers are being coded for */ + int addrCrTab; /* Address of OP_CreateTable 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 */ + u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ + u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ + u8 disableTriggers; /* True to disable triggers */ + + /************************************************************************** + ** Fields above must be initialized to zero. The fields that follow, + ** down to the beginning of the recursive section, do not need to be + ** initialized as they will be set before being used. The boundary is + ** determined by offsetof(Parse,aColCache). + **************************************************************************/ + + struct yColCache { + int iTable; /* Table cursor number */ + i16 iColumn; /* Table column number */ + u8 tempReg; /* iReg is a temp register that needs to be freed */ + int iLevel; /* Nesting level */ + int iReg; /* Reg with value of this column. 0 means none. */ + int lru; /* Least recently used entry has the smallest value */ + } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ + int aTempReg[8]; /* Holding area for temporary registers */ + Token sNameToken; /* Token with unqualified schema object name */ + + /************************************************************************ + ** Above is constant between recursions. Below is reset before and after + ** each recursion. The boundary between these two regions is determined + ** using offsetof(Parse,sLastToken) so the sLastToken field must be the + ** first field in the recursive region. + ************************************************************************/ + + Token sLastToken; /* The last token parsed */ + ynVar nVar; /* Number of '?' variables seen in the SQL so far */ + u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ + u8 explain; /* True if the EXPLAIN flag is found on the query */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ + int nVtabLock; /* Number of virtual tables to lock */ +#endif + int nHeight; /* Expression tree height of current sub-select */ +#ifndef SQLITE_OMIT_EXPLAIN + int iSelectId; /* ID of current select for EXPLAIN output */ + int iNextSelectId; /* Next available select ID for EXPLAIN output */ +#endif + VList *pVList; /* Mapping between variable names and numbers */ + Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ + const char *zTail; /* All SQL text past the last semicolon parsed */ + Table *pNewTable; /* A table being constructed by CREATE TABLE */ + Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ + const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + Token sArg; /* Complete text of a module argument */ + Table **apVtabLock; /* Pointer to virtual tables needing locking */ +#endif + Table *pZombieTab; /* List of Table objects to delete after code gen */ + TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ + With *pWith; /* Current WITH clause, or NULL */ + With *pWithToFree; /* Free this WITH object at the end of the parse */ +}; + +/* +** Sizes and pointers of various parts of the Parse object. +*/ +#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/ +#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ +#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ +#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ + +/* +** Return true if currently inside an sqlite3_declare_vtab() call. +*/ +#ifdef SQLITE_OMIT_VIRTUALTABLE + #define IN_DECLARE_VTAB 0 +#else + #define IN_DECLARE_VTAB (pParse->declareVtab) +#endif + +/* +** An instance of the following structure can be declared on a stack and used +** to save the Parse.zAuthContext value so that it can be restored later. +*/ +struct AuthContext { + const char *zAuthContext; /* Put saved Parse.zAuthContext here */ + Parse *pParse; /* The Parse structure */ +}; + +/* +** Bitfield flags for P5 value in various opcodes. +** +** Value constraints (enforced via assert()): +** OPFLAG_LENGTHARG == SQLITE_FUNC_LENGTH +** OPFLAG_TYPEOFARG == SQLITE_FUNC_TYPEOF +** OPFLAG_BULKCSR == BTREE_BULKLOAD +** OPFLAG_SEEKEQ == BTREE_SEEK_EQ +** OPFLAG_FORDELETE == BTREE_FORDELETE +** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION +** OPFLAG_AUXDELETE == BTREE_AUXDELETE +*/ +#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ + /* Also used in P2 (not P5) of OP_Delete */ +#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ +#define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ +#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ +#define OPFLAG_APPEND 0x08 /* This is likely to be an append */ +#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ +#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */ +#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ +#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ +#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ +#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ +#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */ +#define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ +#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ +#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ +#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ + +/* + * Each trigger present in the database schema is stored as an instance of + * struct Trigger. + * + * Pointers to instances of struct Trigger are stored in two ways. + * 1. In the "trigHash" hash table (part of the sqlite3* that represents the + * database). This allows Trigger structures to be retrieved by name. + * 2. All triggers associated with a single table form a linked list, using the + * pNext member of struct Trigger. A pointer to the first element of the + * linked list is stored as the "pTrigger" member of the associated + * struct Table. + * + * The "step_list" member points to the first element of a linked list + * containing the SQL statements specified as the trigger program. + */ +struct Trigger { + char *zName; /* The name of the trigger */ + char *table; /* The table or view to which the trigger applies */ + u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ + u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ + Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ + IdList *pColumns; /* If this is an UPDATE OF trigger, + the is stored here */ + Schema *pSchema; /* Schema containing the trigger */ + Schema *pTabSchema; /* Schema containing the table */ + TriggerStep *step_list; /* Link list of trigger program steps */ + Trigger *pNext; /* Next trigger associated with the table */ +}; + +/* +** A trigger is either a BEFORE or an AFTER trigger. The following constants +** determine which. +** +** If there are multiple triggers, you might of some BEFORE and some AFTER. +** In that cases, the constants below can be ORed together. +*/ +#define TRIGGER_BEFORE 1 +#define TRIGGER_AFTER 2 + +/* + * An instance of struct TriggerStep is used to store a single SQL statement + * that is a part of a trigger-program. + * + * Instances of struct TriggerStep are stored in a singly linked list (linked + * using the "pNext" member) referenced by the "step_list" member of the + * associated struct Trigger instance. The first element of the linked list is + * the first step of the trigger-program. + * + * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or + * "SELECT" statement. The meanings of the other members is determined by the + * value of "op" as follows: + * + * (op == TK_INSERT) + * orconf -> stores the ON CONFLICT algorithm + * pSelect -> If this is an INSERT INTO ... SELECT ... statement, then + * this stores a pointer to the SELECT statement. Otherwise NULL. + * zTarget -> Dequoted name of the table to insert into. + * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then + * this stores values to be inserted. Otherwise NULL. + * pIdList -> If this is an INSERT INTO ... () VALUES ... + * statement, then this stores the column-names to be + * inserted into. + * + * (op == TK_DELETE) + * zTarget -> Dequoted name of the table to delete from. + * pWhere -> The WHERE clause of the DELETE statement if one is specified. + * Otherwise NULL. + * + * (op == TK_UPDATE) + * zTarget -> Dequoted name of the table to update. + * pWhere -> The WHERE clause of the UPDATE statement if one is specified. + * Otherwise NULL. + * pExprList -> A list of the columns to update and the expressions to update + * them to. See sqlite3Update() documentation of "pChanges" + * argument. + * + */ +struct TriggerStep { + u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ + u8 orconf; /* OE_Rollback etc. */ + Trigger *pTrig; /* The trigger that this step is a part of */ + Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ + char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ + Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ + ExprList *pExprList; /* SET clause for UPDATE. */ + IdList *pIdList; /* Column names for INSERT */ + TriggerStep *pNext; /* Next in the link-list */ + TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ +}; + +/* +** The following structure contains information used by the sqliteFix... +** routines as they walk the parse tree to make database references +** explicit. +*/ +typedef struct DbFixer DbFixer; +struct DbFixer { + Parse *pParse; /* The parsing context. Error messages written here */ + Schema *pSchema; /* Fix items to this schema */ + int bVarOnly; /* Check for variable references only */ + const char *zDb; /* Make sure all objects are contained in this database */ + const char *zType; /* Type of the container - used for error messages */ + const Token *pName; /* Name of the container - used for error messages */ +}; + +/* +** An objected used to accumulate the text of a string where we +** do not necessarily know how big the string will be in the end. +*/ +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 */ + u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */ + u8 printfFlags; /* SQLITE_PRINTF flags below */ +}; +#define STRACCUM_NOMEM 1 +#define STRACCUM_TOOBIG 2 +#define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */ +#define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */ +#define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */ + +#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0) + + +/* +** A pointer to this structure is used to communicate information +** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback. +*/ +typedef struct { + sqlite3 *db; /* The database being initialized */ + char **pzErrMsg; /* Error message stored here */ + int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ + int rc; /* Result code stored here */ +} InitData; + +/* +** Structure containing global configuration data for the SQLite library. +** +** This structure also contains some state information. +*/ +struct Sqlite3Config { + int bMemstat; /* True to enable memory status */ + int bCoreMutex; /* True to enable core mutexing */ + int bFullMutex; /* True to enable full mutexing */ + int bOpenUri; /* True to interpret filenames as URIs */ + int bUseCis; /* Use covering indices for full-scans */ + int mxStrlen; /* Maximum string length */ + int neverCorrupt; /* Database is always well-formed */ + int szLookaside; /* Default lookaside buffer size */ + int nLookaside; /* Default lookaside buffer count */ + int nStmtSpill; /* Stmt-journal spill-to-disk threshold */ + sqlite3_mem_methods m; /* Low-level memory allocation interface */ + sqlite3_mutex_methods mutex; /* Low-level mutex interface */ + sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */ + void *pHeap; /* Heap storage space */ + int nHeap; /* Size of pHeap[] */ + 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[] */ + int mxParserStack; /* maximum depth of the parser stack */ + int sharedCacheEnabled; /* true if shared-cache mode enabled */ + u32 szPma; /* Maximum Sorter PMA size */ + /* The above might be initialized to non-zero. The following need to always + ** initially be zero, however. */ + int isInit; /* True after initialization has finished */ + int inProgress; /* True while initialization in progress */ + int isMutexInit; /* True after mutexes are initialized */ + int isMallocInit; /* True after malloc is initialized */ + int isPCacheInit; /* True after malloc is initialized */ + int nRefInitMutex; /* Number of users of pInitMutex */ + sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ + void (*xLog)(void*,int,const char*); /* Function for logging */ + void *pLogArg; /* First argument to xLog() */ +#ifdef SQLITE_ENABLE_SQLLOG + void(*xSqllog)(void*,sqlite3*,const char*, int); + void *pSqllogArg; +#endif +#ifdef SQLITE_VDBE_COVERAGE + /* The following callback (if not NULL) is invoked on every VDBE branch + ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. + */ + void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ + void *pVdbeBranchArg; /* 1st argument */ +#endif +#ifndef SQLITE_UNTESTABLE + int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ +#endif + int bLocaltimeFault; /* True to fail localtime() calls */ + int iOnceResetThreshold; /* When to reset OP_Once counters */ +}; + +/* +** This macro is used inside of assert() statements to indicate that +** the assert is only valid on a well-formed database. Instead of: +** +** assert( X ); +** +** One writes: +** +** assert( X || CORRUPT_DB ); +** +** CORRUPT_DB is true during normal operation. CORRUPT_DB does not indicate +** that the database is definitely corrupt, only that it might be corrupt. +** For most test cases, CORRUPT_DB is set to false using a special +** sqlite3_test_control(). This enables assert() statements to prove +** things that are always true for well-formed databases. +*/ +#define CORRUPT_DB (sqlite3Config.neverCorrupt==0) + +/* +** Context pointer passed down through the tree-walk. +*/ +struct Walker { + Parse *pParse; /* Parser context. */ + int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ + int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ + void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ + int walkerDepth; /* Number of subqueries */ + u8 eCode; /* A small processing code */ + union { /* Extra data for callback */ + NameContext *pNC; /* Naming context */ + int n; /* A counter */ + int iCur; /* A cursor number */ + SrcList *pSrcList; /* FROM clause */ + struct SrcCount *pSrcCount; /* Counting column references */ + struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ + int *aiCol; /* array of column indexes */ + struct IdxCover *pIdxCover; /* Check for index coverage */ + struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */ + ExprList *pGroupBy; /* GROUP BY clause */ + struct HavingToWhereCtx *pHavingCtx; /* HAVING to WHERE clause ctx */ + } u; +}; + +/* Forward declarations */ +SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*); +SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*); +SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*); +SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*); +SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*); +SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*); + +/* +** Return code from the parse-tree walking primitives and their +** callbacks. +*/ +#define WRC_Continue 0 /* Continue down into children */ +#define WRC_Prune 1 /* Omit children but continue walking siblings */ +#define WRC_Abort 2 /* Abandon the tree walk */ + +/* +** An instance of this structure represents a set of one or more CTEs +** (common table expressions) created by a single WITH clause. +*/ +struct With { + int nCte; /* Number of CTEs in the WITH clause */ + With *pOuter; /* Containing WITH clause, or NULL */ + struct Cte { /* For each CTE in the WITH clause.... */ + char *zName; /* Name of this CTE */ + ExprList *pCols; /* List of explicit column names, or NULL */ + Select *pSelect; /* The definition of this CTE */ + const char *zCteErr; /* Error message for circular references */ + } a[1]; +}; + +#ifdef SQLITE_DEBUG +/* +** An instance of the TreeView object is used for printing the content of +** data structures on sqlite3DebugPrintf() using a tree-like view. +*/ +struct TreeView { + int iLevel; /* Which level of the tree we are on */ + u8 bLine[100]; /* Draw vertical in column i if bLine[i] is true */ +}; +#endif /* SQLITE_DEBUG */ + +/* +** Assuming zIn points to the first byte of a UTF-8 character, +** advance zIn to point to the first byte of the next UTF-8 character. +*/ +#define SQLITE_SKIP_UTF8(zIn) { \ + if( (*(zIn++))>=0xc0 ){ \ + while( (*zIn & 0xc0)==0x80 ){ zIn++; } \ + } \ +} + +/* +** The SQLITE_*_BKPT macros are substitutes for the error codes with +** the same name but without the _BKPT suffix. These macros invoke +** routines that report the line-number on which the error originated +** using sqlite3_log(). The routines also provide a convenient place +** to set a debugger breakpoint. +*/ +SQLITE_PRIVATE int sqlite3CorruptError(int); +SQLITE_PRIVATE int sqlite3MisuseError(int); +SQLITE_PRIVATE int sqlite3CantopenError(int); +#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) +#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) +#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NomemError(int); +SQLITE_PRIVATE int sqlite3IoerrnomemError(int); +# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__) +# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__) +#else +# define SQLITE_NOMEM_BKPT SQLITE_NOMEM +# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM +#endif + +/* +** FTS3 and FTS4 both require virtual table support +*/ +#if defined(SQLITE_OMIT_VIRTUALTABLE) +# undef SQLITE_ENABLE_FTS3 +# undef SQLITE_ENABLE_FTS4 +#endif + +/* +** FTS4 is really an extension for FTS3. It is enabled using the +** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also call +** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3. +*/ +#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) +# define SQLITE_ENABLE_FTS3 1 +#endif + +/* +** The ctype.h header is needed for non-ASCII systems. It is also +** needed by FTS3 when FTS3 is included in the amalgamation. +*/ +#if !defined(SQLITE_ASCII) || \ + (defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_AMALGAMATION)) +# include +#endif + +/* +** The following macros mimic the standard library functions toupper(), +** isspace(), isalnum(), isdigit() and isxdigit(), respectively. The +** sqlite versions only work for ASCII characters, regardless of locale. +*/ +#ifdef SQLITE_ASCII +# define sqlite3Toupper(x) ((x)&~(sqlite3CtypeMap[(unsigned char)(x)]&0x20)) +# define sqlite3Isspace(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x01) +# define sqlite3Isalnum(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x06) +# define sqlite3Isalpha(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x02) +# define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04) +# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08) +# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)]) +# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80) +#else +# define sqlite3Toupper(x) toupper((unsigned char)(x)) +# define sqlite3Isspace(x) isspace((unsigned char)(x)) +# define sqlite3Isalnum(x) isalnum((unsigned char)(x)) +# define sqlite3Isalpha(x) isalpha((unsigned char)(x)) +# define sqlite3Isdigit(x) isdigit((unsigned char)(x)) +# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) +# define sqlite3Tolower(x) tolower((unsigned char)(x)) +# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') +#endif +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_PRIVATE int sqlite3IsIdChar(u8); +#endif + +/* +** Internal function prototypes +*/ +SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*); +SQLITE_PRIVATE int sqlite3Strlen30(const char*); +SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*); +#define sqlite3StrNICmp sqlite3_strnicmp + +SQLITE_PRIVATE int sqlite3MallocInit(void); +SQLITE_PRIVATE void sqlite3MallocEnd(void); +SQLITE_PRIVATE void *sqlite3Malloc(u64); +SQLITE_PRIVATE void *sqlite3MallocZero(u64); +SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64); +SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64); +SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64); +SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*); +SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64); +SQLITE_PRIVATE void *sqlite3Realloc(void*, u64); +SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); +SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); +SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); +SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); +SQLITE_PRIVATE int sqlite3MallocSize(void*); +SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*); +SQLITE_PRIVATE void *sqlite3ScratchMalloc(int); +SQLITE_PRIVATE void sqlite3ScratchFree(void*); +SQLITE_PRIVATE void *sqlite3PageMalloc(int); +SQLITE_PRIVATE void sqlite3PageFree(void*); +SQLITE_PRIVATE void sqlite3MemSetDefault(void); +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); +#endif +SQLITE_PRIVATE int sqlite3HeapNearlyFull(void); + +/* +** On systems with ample stack space and that support alloca(), make +** use of alloca() to obtain space for large automatic objects. By default, +** obtain space from malloc(). +** +** The alloca() routine never returns NULL. This will cause code paths +** that deal with sqlite3StackAlloc() failures to be unreachable. +*/ +#ifdef SQLITE_USE_ALLOCA +# define sqlite3StackAllocRaw(D,N) alloca(N) +# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N) +# define sqlite3StackFree(D,P) +#else +# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) +# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) +# define sqlite3StackFree(D,P) sqlite3DbFree(D,P) +#endif + +/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they +** are, disable MEMSYS3 +*/ +#ifdef SQLITE_ENABLE_MEMSYS5 +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); +#undef SQLITE_ENABLE_MEMSYS3 +#endif +#ifdef SQLITE_ENABLE_MEMSYS3 +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); +#endif + + +#ifndef SQLITE_MUTEX_OMIT +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void); +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void); +SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int); +SQLITE_PRIVATE int sqlite3MutexInit(void); +SQLITE_PRIVATE int sqlite3MutexEnd(void); +#endif +#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP) +SQLITE_PRIVATE void sqlite3MemoryBarrier(void); +#else +# define sqlite3MemoryBarrier() +#endif + +SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int); +SQLITE_PRIVATE void sqlite3StatusUp(int, int); +SQLITE_PRIVATE void sqlite3StatusDown(int, int); +SQLITE_PRIVATE void sqlite3StatusHighwater(int, int); + +/* Access to mutexes used by sqlite3_status() */ +SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void); +SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void); + +#ifndef SQLITE_OMIT_FLOATING_POINT +SQLITE_PRIVATE int sqlite3IsNaN(double); +#else +# define sqlite3IsNaN(X) 0 +#endif + +/* +** An instance of the following structure holds information about SQL +** functions arguments that are the parameters to the printf() function. +*/ +struct PrintfArguments { + int nArg; /* Total number of arguments */ + int nUsed; /* Number of arguments used so far */ + sqlite3_value **apArg; /* The argument values */ +}; + +SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list); +SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...); +SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...); +SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list); +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) +SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...); +#endif +#if defined(SQLITE_TEST) +SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); +#endif + +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); +SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*); +SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); +SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8); +SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); +#endif + + +SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); +SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); +SQLITE_PRIVATE void sqlite3Dequote(char*); +SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); +SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); +SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **); +SQLITE_PRIVATE void sqlite3FinishCoding(Parse*); +SQLITE_PRIVATE int sqlite3GetTempReg(Parse*); +SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int); +SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int); +SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int); +SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int); +#endif +SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); +SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); +SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); +SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); +SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); +SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); +SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); +SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); +SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); +SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); +SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int); +SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); +SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); +SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); +SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); +SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); +SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); +SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); +#ifndef SQLITE_OMIT_VIRTUALTABLE +SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); +#endif +SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*); +SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int); +SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*); +SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); +SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); +SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); +SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*); +SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*); +SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int); +SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); +SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index*, i16); +SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); +#if SQLITE_ENABLE_HIDDEN_COLUMNS +SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*); +#else +# define sqlite3ColumnPropertiesFromName(T,C) /* no-op */ +#endif +SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*); +SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); +SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); +SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*); +SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); +SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); +SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, + sqlite3_vfs**,char**,char **); +SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); + +#ifdef SQLITE_UNTESTABLE +# define sqlite3FaultSim(X) SQLITE_OK +#else +SQLITE_PRIVATE int sqlite3FaultSim(int); +#endif + +SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); +SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); +SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec*, u32); +SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); +SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); +SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*); +SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); +#endif + +SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); +SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*); +SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); +SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64); +SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*); + +SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int); + +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) +SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*); +#else +# define sqlite3ViewGetColumnNames(A,B) 0 +#endif + +#if SQLITE_MAX_ATTACHED>30 +SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); +#endif +SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); +SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); +SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); +#ifndef SQLITE_OMIT_AUTOINCREMENT +SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); +SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); +#else +# define sqlite3AutoincrementBegin(X) +# define sqlite3AutoincrementEnd(X) +#endif +SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int); +SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); +SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); +SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); +SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); +SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); +SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, + Token*, Select*, Expr*, IdList*); +SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); +SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); +SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); +SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*); +SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); +SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); +SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); +SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); +SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, + Expr*, int, int, u8); +SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); +SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); +SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, + Expr*,ExprList*,u32,Expr*,Expr*); +SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); +SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); +SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int); +SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); +#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) +SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*); +#endif +SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); +SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); +SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); +SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); +SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); +#define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */ +#define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */ +#define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ +SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); +SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); +SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(Parse*, Table*, int, int, int); +SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); +SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); +SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); +SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); +SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*); +SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); +SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*); +SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int); +SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); +SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); +SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCodeAtInit(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); +SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); +SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); +#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ +#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ +#define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ +#define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */ +SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int); +SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int); +SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); +SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*); +#define LOCATE_VIEW 0x01 +#define LOCATE_NOERR 0x02 +SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); +SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); +SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*); +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); +SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*); +SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int); +SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); +SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int); +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int); +SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); +SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); +SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); +SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); +SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE void sqlite3PrngSaveState(void); +SQLITE_PRIVATE void sqlite3PrngRestoreState(void); +#endif +SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); +SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); +SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); +SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); +SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); +SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); +SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); +SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); +SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); +SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); +SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); +SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); +SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); +SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int); +#ifdef SQLITE_ENABLE_CURSOR_HINTS +SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); +#endif +SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*); +SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); +SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); +SQLITE_PRIVATE int sqlite3IsRowid(const char*); +SQLITE_PRIVATE void sqlite3GenerateRowDelete( + Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); +SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); +SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); +SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); +SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, + u8,u8,int,int*,int*); +#ifdef SQLITE_ENABLE_NULL_TRIM +SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe*,Table*); +#else +# define sqlite3SetMakeRecordP5(A,B) +#endif +SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); +SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*); +SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int); +SQLITE_PRIVATE void sqlite3MultiWrite(Parse*); +SQLITE_PRIVATE void sqlite3MayAbort(Parse*); +SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); +SQLITE_PRIVATE void sqlite3UniqueConstraint(Parse*, int, Index*); +SQLITE_PRIVATE void sqlite3RowidConstraint(Parse*, int, Table*); +SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int); +SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); +SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); +SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); +#if SELECTTRACE_ENABLED +SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*); +#else +# define sqlite3SelectSetName(A,B) +#endif +SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); +SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); +SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); +SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); +SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); +SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); +SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); +SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); + +#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) +SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, int); +#endif + +#ifndef SQLITE_OMIT_TRIGGER +SQLITE_PRIVATE void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, + Expr*,int, int); +SQLITE_PRIVATE void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*); +SQLITE_PRIVATE void sqlite3DropTrigger(Parse*, SrcList*, int); +SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse*, Trigger*); +SQLITE_PRIVATE Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask); +SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *, Table *); +SQLITE_PRIVATE void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *, + int, int, int); +SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int); + void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); +SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*, + Select*,u8); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); +SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*); +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); +SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); +# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) +# define sqlite3IsToplevel(p) ((p)->pToplevel==0) +#else +# define sqlite3TriggersExist(B,C,D,E,F) 0 +# define sqlite3DeleteTrigger(A,B) +# define sqlite3DropTriggerPtr(A,B) +# define sqlite3UnlinkAndDeleteTrigger(A,B,C) +# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) +# define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F) +# define sqlite3TriggerList(X, Y) 0 +# define sqlite3ParseToplevel(p) p +# define sqlite3IsToplevel(p) 1 +# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 +#endif + +SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*); +SQLITE_PRIVATE void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); +SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse*, int); +#ifndef SQLITE_OMIT_AUTHORIZATION +SQLITE_PRIVATE void sqlite3AuthRead(Parse*,Expr*,Schema*,SrcList*); +SQLITE_PRIVATE int sqlite3AuthCheck(Parse*,int, const char*, const char*, const char*); +SQLITE_PRIVATE void sqlite3AuthContextPush(Parse*, AuthContext*, const char*); +SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext*); +SQLITE_PRIVATE int sqlite3AuthReadCol(Parse*, const char *, const char *, int); +#else +# define sqlite3AuthRead(a,b,c,d) +# define sqlite3AuthCheck(a,b,c,d,e) SQLITE_OK +# define sqlite3AuthContextPush(a,b,c) +# define sqlite3AuthContextPop(a) ((void)(a)) +#endif +SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*); +SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); +SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); +SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); +SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); +SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); +SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); +SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); +SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); +SQLITE_PRIVATE int sqlite3Atoi(const char*); +SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); +SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); +SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); +SQLITE_PRIVATE LogEst sqlite3LogEst(u64); +SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); +#ifndef SQLITE_OMIT_VIRTUALTABLE +SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); +#endif +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ + defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \ + defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) +SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); +#endif +SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); +SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int); +SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int); + +/* +** Routines to read and write variable-length integers. These used to +** be defined locally, but now we use the varint routines in the util.c +** file. +*/ +SQLITE_PRIVATE int sqlite3PutVarint(unsigned char*, u64); +SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *, u64 *); +SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *, u32 *); +SQLITE_PRIVATE int sqlite3VarintLen(u64 v); + +/* +** The common case is for a varint to be a single byte. They following +** macros handle the common case without a procedure call, but then call +** the procedure for larger varints. +*/ +#define getVarint32(A,B) \ + (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B))) +#define putVarint32(A,B) \ + (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ + sqlite3PutVarint((A),(B))) +#define getVarint sqlite3GetVarint +#define putVarint sqlite3PutVarint + + +SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*); +SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); +SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); +SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); +SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int); +SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); +SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); +SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); +SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); +SQLITE_PRIVATE void sqlite3Error(sqlite3*,int); +SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int); +SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); +SQLITE_PRIVATE u8 sqlite3HexToInt(int h); +SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); + +#if defined(SQLITE_NEED_ERR_NAME) +SQLITE_PRIVATE const char *sqlite3ErrName(int); +#endif + +SQLITE_PRIVATE const char *sqlite3ErrStr(int); +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 Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); +SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); +SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); +SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); +SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); +SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); +SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); +SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); +SQLITE_PRIVATE int sqlite3AbsInt32(int); +#ifdef SQLITE_ENABLE_8_3_NAMES +SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); +#else +# define sqlite3FileSuffix3(X,Y) +#endif +SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8); + +SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); +SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); +SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, + void(*)(void*)); +SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*); +SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); +SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); +SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); +SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); +SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); +#ifndef SQLITE_AMALGAMATION +SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[]; +SQLITE_PRIVATE const char sqlite3StrBINARY[]; +SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; +SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[]; +SQLITE_PRIVATE const Token sqlite3IntTokens[]; +SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config; +SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; +#ifndef SQLITE_OMIT_WSD +SQLITE_PRIVATE int sqlite3PendingByte; +#endif +#endif +SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int); +SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); +SQLITE_PRIVATE void sqlite3AlterFunctions(void); +SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); +SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); +SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); +SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*); +SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int); +SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); +SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); +SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); +SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*); +SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*); +SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); +SQLITE_PRIVATE void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); +SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); +SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int); +SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); +SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); +SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); +SQLITE_PRIVATE char sqlite3AffinityType(const char*, u8*); +SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); +SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*); +SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); +SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *); +SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB); +SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*); +SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*); +SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int); +SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); +SQLITE_PRIVATE void sqlite3SchemaClear(void *); +SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *); +SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *); +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); +SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo*); +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo*); +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*); +#endif +SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, + void (*)(sqlite3_context*,int,sqlite3_value **), + void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), + FuncDestructor *pDestructor +); +SQLITE_PRIVATE void sqlite3OomFault(sqlite3*); +SQLITE_PRIVATE void sqlite3OomClear(sqlite3*); +SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); +SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); + +SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); +SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int); +SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum*,const char*); +SQLITE_PRIVATE void sqlite3AppendChar(StrAccum*,int,char); +SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); +SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*); +SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int); +SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); + +SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *); +SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); + +#ifndef SQLITE_OMIT_SUBQUERY +SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*); +#else +# define sqlite3ExprCheckIN(x,y) SQLITE_OK +#endif + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void); +SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( + Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*); +SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); +SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord*); +SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); +SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int); +#endif + +/* +** The interface to the LEMON-generated parser +*/ +#ifndef SQLITE_AMALGAMATION +SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64)); +SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); +#endif +SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*); +#ifdef YYTRACKMAXSTACKDEPTH +SQLITE_PRIVATE int sqlite3ParserStackPeak(void*); +#endif + +SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3*); +#ifndef SQLITE_OMIT_LOAD_EXTENSION +SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3*); +#else +# define sqlite3CloseExtensions(X) +#endif + +#ifndef SQLITE_OMIT_SHARED_CACHE +SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, int, u8, const char *); +#else + #define sqlite3TableLock(v,w,x,y,z) +#endif + +#ifdef SQLITE_TEST +SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*); +#endif + +#ifdef SQLITE_OMIT_VIRTUALTABLE +# define sqlite3VtabClear(Y) +# define sqlite3VtabSync(X,Y) SQLITE_OK +# define sqlite3VtabRollback(X) +# define sqlite3VtabCommit(X) +# define sqlite3VtabInSync(db) 0 +# define sqlite3VtabLock(X) +# define sqlite3VtabUnlock(X) +# define sqlite3VtabUnlockList(X) +# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK +# define sqlite3GetVTable(X,Y) ((VTable*)0) +#else +SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table*); +SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p); +SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe*); +SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); +SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); +SQLITE_PRIVATE void sqlite3VtabLock(VTable *); +SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); +SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); +SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); +SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); +SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*); +SQLITE_PRIVATE Module *sqlite3VtabCreateModule( + sqlite3*, + const char*, + const sqlite3_module*, + void*, + void(*)(void*) + ); +# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) +#endif +SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*); +SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*); +SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); +SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); +SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); +SQLITE_PRIVATE void sqlite3VtabArgInit(Parse*); +SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse*, Token*); +SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); +SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*); +SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); +SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *); +SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); +SQLITE_PRIVATE void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); +SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); +SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); +SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); +SQLITE_PRIVATE void sqlite3ParserReset(Parse*); +SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*); +SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); +SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); +SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*); +SQLITE_PRIVATE const char *sqlite3JournalModename(int); +#ifndef SQLITE_OMIT_WAL +SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); +SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); +#endif +#ifndef SQLITE_OMIT_CTE +SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*); +SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*); +SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8); +#else +#define sqlite3WithPush(x,y,z) +#define sqlite3WithDelete(x,y) +#endif + +/* Declarations for functions in fkey.c. All of these are replaced by +** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign +** key functionality is available. If OMIT_TRIGGER is defined but +** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In +** this case foreign keys are parsed, but no other functionality is +** provided (enforcement of FK constraints requires the triggers sub-system). +*/ +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) +SQLITE_PRIVATE void sqlite3FkCheck(Parse*, Table*, int, int, int*, int); +SQLITE_PRIVATE void sqlite3FkDropTable(Parse*, SrcList *, Table*); +SQLITE_PRIVATE void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int); +SQLITE_PRIVATE int sqlite3FkRequired(Parse*, Table*, int*, int); +SQLITE_PRIVATE u32 sqlite3FkOldmask(Parse*, Table*); +SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *); +#else + #define sqlite3FkActions(a,b,c,d,e,f) + #define sqlite3FkCheck(a,b,c,d,e,f) + #define sqlite3FkDropTable(a,b,c) + #define sqlite3FkOldmask(a,b) 0 + #define sqlite3FkRequired(a,b,c,d) 0 + #define sqlite3FkReferences(a) 0 +#endif +#ifndef SQLITE_OMIT_FOREIGN_KEY +SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*); +SQLITE_PRIVATE int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**); +#else + #define sqlite3FkDelete(a,b) + #define sqlite3FkLocateIndex(a,b,c,d,e) +#endif + + +/* +** Available fault injectors. Should be numbered beginning with 0. +*/ +#define SQLITE_FAULTINJECTOR_MALLOC 0 +#define SQLITE_FAULTINJECTOR_COUNT 1 + +/* +** The interface to the code in fault.c used for identifying "benign" +** malloc failures. This is only present if SQLITE_UNTESTABLE +** is not defined. +*/ +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void); +SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); +#else + #define sqlite3BeginBenignMalloc() + #define sqlite3EndBenignMalloc() +#endif + +/* +** Allowed return values from sqlite3FindInIndex() +*/ +#define IN_INDEX_ROWID 1 /* Search the rowid of the table */ +#define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ +#define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ +#define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ +#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ +/* +** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). +*/ +#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ +#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ +#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ +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 +SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *); +#endif + +SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p); +SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *); + +SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); +#if SQLITE_MAX_EXPR_DEPTH>0 +SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *); +SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int); +#else + #define sqlite3SelectExprHeight(x) 0 + #define sqlite3ExprCheckHeight(x,y) +#endif + +SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*); +SQLITE_PRIVATE void sqlite3Put4byte(u8*, u32); + +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY +SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *, sqlite3 *); +SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db); +SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db); +#else + #define sqlite3ConnectionBlocked(x,y) + #define sqlite3ConnectionUnlocked(x) + #define sqlite3ConnectionClosed(x) +#endif + +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *); +#endif + +/* +** If the SQLITE_ENABLE IOTRACE exists then the global variable +** sqlite3IoTrace is a pointer to a printf-like routine used to +** print I/O tracing messages. +*/ +#ifdef SQLITE_ENABLE_IOTRACE +# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; } +SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe*); +SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...); +#else +# define IOTRACE(A) +# define sqlite3VdbeIOTraceSql(X) +#endif + +/* +** These routines are available for the mem2.c debugging memory allocator +** only. They are used to verify that different "types" of memory +** allocations are properly tracked by the system. +** +** sqlite3MemdebugSetType() sets the "type" of an allocation to one of +** the MEMTYPE_* macros defined below. The type must be a bitmask with +** a single bit set. +** +** sqlite3MemdebugHasType() returns true if any of the bits in its second +** argument match the type set by the previous sqlite3MemdebugSetType(). +** sqlite3MemdebugHasType() is intended for use inside assert() statements. +** +** sqlite3MemdebugNoType() returns true if none of the bits in its second +** argument match the type set by the previous sqlite3MemdebugSetType(). +** +** Perhaps the most important point is the difference between MEMTYPE_HEAP +** and MEMTYPE_LOOKASIDE. If an allocation is MEMTYPE_LOOKASIDE, that means +** it might have been allocated by lookaside, except the allocation was +** too large or lookaside was already full. It is important to verify +** that allocations that might have been satisfied by lookaside are not +** passed back to non-lookaside free() routines. Asserts such as the +** example above are placed on the non-lookaside free() routines to verify +** this constraint. +** +** All of this is no-op for a production build. It only comes into +** play when the SQLITE_MEMDEBUG compile-time option is used. +*/ +#ifdef SQLITE_MEMDEBUG +SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8); +SQLITE_PRIVATE int sqlite3MemdebugHasType(void*,u8); +SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); +#else +# define sqlite3MemdebugSetType(X,Y) /* no-op */ +# define sqlite3MemdebugHasType(X,Y) 1 +# define sqlite3MemdebugNoType(X,Y) 1 +#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 */ + +/* +** Threading interface +*/ +#if SQLITE_MAX_WORKER_THREADS>0 +SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**); +#endif + +#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) +SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*); +#endif + +SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr); +SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); +SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int); +SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); + +#endif /* SQLITEINT_H */ + +/************** End of sqliteInt.h *******************************************/ +/************** Begin file global.c ******************************************/ +/* +** 2008 June 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 definitions of global variables and constants. +*/ +/* #include "sqliteInt.h" */ + +/* An array to map all upper-case characters into their corresponding +** lower-case character. +** +** SQLite only considers US-ASCII (or EBCDIC) characters. We do not +** handle case conversions for the UTF character set since the tables +** involved are nearly as big or bigger than SQLite itself. +*/ +SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = { +#ifdef SQLITE_ASCII + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, + 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, + 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, + 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, + 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, + 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, + 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, + 252,253,254,255 +#endif +#ifdef SQLITE_EBCDIC + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */ + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */ + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */ + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */ + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */ + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */ + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */ + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */ + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */ + 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */ + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */ + 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */ + 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */ + 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ +#endif +}; + +/* +** The following 256 byte lookup table is used to support SQLites built-in +** equivalents to the following standard library functions: +** +** isspace() 0x01 +** isalpha() 0x02 +** isdigit() 0x04 +** isalnum() 0x06 +** isxdigit() 0x08 +** toupper() 0x20 +** SQLite identifier character 0x40 +** Quote character 0x80 +** +** Bit 0x20 is set if the mapped character requires translation to upper +** case. i.e. if the character is a lower-case ASCII character. +** If x is a lower-case ASCII character, then its upper-case equivalent +** is (x - 0x20). Therefore toupper() can be implemented as: +** +** (x & ~(map[x]&0x20)) +** +** The equivalent of tolower() is implemented using the sqlite3UpperToLower[] +** array. tolower() is used more often than toupper() by SQLite. +** +** Bit 0x40 is set if the character is non-alphanumeric and can be used in an +** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any +** non-ASCII UTF character. Hence the test for whether or not a character is +** part of an identifier is 0x46. +*/ +#ifdef SQLITE_ASCII +SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */ + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */ + 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */ + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */ + 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */ + + 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */ + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */ + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */ + 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */ + 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */ + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */ + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */ + 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */ + + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */ + + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ +}; +#endif + +/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards +** compatibility for legacy applications, the URI filename capability is +** disabled by default. +** +** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled +** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. +** +** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** SQLITE_USE_URI symbol defined. +** +** URI filenames are enabled by default if SQLITE_HAS_CODEC is +** enabled. +*/ +#ifndef SQLITE_USE_URI +# ifdef SQLITE_HAS_CODEC +# define SQLITE_USE_URI 1 +# else +# define SQLITE_USE_URI 0 +# endif +#endif + +/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the +** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if +** that compile-time option is omitted. +*/ +#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN +# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 +#endif + +/* The minimum PMA size is set to this value multiplied by the database +** page size in bytes. +*/ +#ifndef SQLITE_SORTER_PMASZ +# define SQLITE_SORTER_PMASZ 250 +#endif + +/* Statement journals spill to disk when their size exceeds the following +** threshold (in bytes). 0 means that statement journals are created and +** written to disk immediately (the default behavior for SQLite versions +** before 3.12.0). -1 means always keep the entire statement journal in +** memory. (The statement journal is also always held entirely in memory +** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this +** setting.) +*/ +#ifndef SQLITE_STMTJRNL_SPILL +# define SQLITE_STMTJRNL_SPILL (64*1024) +#endif + +/* +** The default lookaside-configuration, the format "SZ,N". SZ is the +** number of bytes in each lookaside slot (should be a multiple of 8) +** and N is the number of slots. The lookaside-configuration can be +** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE) +** or at run-time for an individual database connection using +** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE); +*/ +#ifndef SQLITE_DEFAULT_LOOKASIDE +# define SQLITE_DEFAULT_LOOKASIDE 1200,100 +#endif + + +/* +** The following singleton contains the global configuration for +** the SQLite library. +*/ +SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { + SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ + 1, /* bCoreMutex */ + SQLITE_THREADSAFE==1, /* bFullMutex */ + SQLITE_USE_URI, /* bOpenUri */ + SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ + 0x7ffffffe, /* mxStrlen */ + 0, /* neverCorrupt */ + SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ + SQLITE_STMTJRNL_SPILL, /* nStmtSpill */ + {0,0,0,0,0,0,0,0}, /* m */ + {0,0,0,0,0,0,0,0,0}, /* mutex */ + {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */ + (void*)0, /* pHeap */ + 0, /* nHeap */ + 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 */ + 0, /* mxParserStack */ + 0, /* sharedCacheEnabled */ + SQLITE_SORTER_PMASZ, /* szPma */ + /* All the rest should always be initialized to zero */ + 0, /* isInit */ + 0, /* inProgress */ + 0, /* isMutexInit */ + 0, /* isMallocInit */ + 0, /* isPCacheInit */ + 0, /* nRefInitMutex */ + 0, /* pInitMutex */ + 0, /* xLog */ + 0, /* pLogArg */ +#ifdef SQLITE_ENABLE_SQLLOG + 0, /* xSqllog */ + 0, /* pSqllogArg */ +#endif +#ifdef SQLITE_VDBE_COVERAGE + 0, /* xVdbeBranch */ + 0, /* pVbeBranchArg */ +#endif +#ifndef SQLITE_UNTESTABLE + 0, /* xTestCallback */ +#endif + 0, /* bLocaltimeFault */ + 0x7ffffffe /* iOnceResetThreshold */ +}; + +/* +** Hash table for global functions - functions common to all +** database connections. After initialization, this table is +** read-only. +*/ +SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; + +/* +** Constant tokens for values 0 and 1. +*/ +SQLITE_PRIVATE const Token sqlite3IntTokens[] = { + { "0", 1 }, + { "1", 1 } +}; + + +/* +** The value of the "pending" byte must be 0x40000000 (1 byte past the +** 1-gibabyte boundary) in a compatible database. SQLite never uses +** the database page that contains the pending byte. It never attempts +** to read or write that page. The pending byte page is set aside +** for use by the VFS layers as space for managing file locks. +** +** During testing, it is often desirable to move the pending byte to +** a different position in the file. This allows code that has to +** deal with the pending byte to run on files that are much smaller +** than 1 GiB. The sqlite3_test_control() interface can be used to +** move the pending byte. +** +** IMPORTANT: Changing the pending byte to any value other than +** 0x40000000 results in an incompatible database file format! +** Changing the pending byte during operation will result in undefined +** and incorrect behavior. +*/ +#ifndef SQLITE_OMIT_WSD +SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000; +#endif + +/* #include "opcodes.h" */ +/* +** Properties of opcodes. The OPFLG_INITIALIZER macro is +** created by mkopcodeh.awk during compilation. Data is obtained +** from the comments following the "case OP_xxxx:" statements in +** the vdbe.c file. +*/ +SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; + +/* +** Name of the default collating sequence +*/ +SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY"; + +/************** End of global.c **********************************************/ +/************** Begin file ctime.c *******************************************/ +/* +** 2010 February 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file implements routines used to report what compile-time options +** SQLite was built with. +*/ + +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS + +/* #include "sqliteInt.h" */ + +/* +** An array of names of all compile-time options. This array should +** be sorted A-Z. +** +** This array looks large, but in a typical installation actually uses +** only a handful of compile-time options, so most times this array is usually +** rather short and uses little memory space. +*/ +static const char * const azCompileOpt[] = { + +/* These macros are provided to "stringify" the value of the define +** for those options in which the value is meaningful. */ +#define CTIMEOPT_VAL_(opt) #opt +#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) + +#if SQLITE_32BIT_ROWID + "32BIT_ROWID", +#endif +#if SQLITE_4_BYTE_ALIGNED_MALLOC + "4_BYTE_ALIGNED_MALLOC", +#endif +#if SQLITE_CASE_SENSITIVE_LIKE + "CASE_SENSITIVE_LIKE", +#endif +#if SQLITE_CHECK_PAGES + "CHECK_PAGES", +#endif +#if defined(__clang__) && defined(__clang_major__) + "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." + CTIMEOPT_VAL(__clang_minor__) "." + CTIMEOPT_VAL(__clang_patchlevel__), +#elif defined(_MSC_VER) + "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), +#elif defined(__GNUC__) && defined(__VERSION__) + "COMPILER=gcc-" __VERSION__, +#endif +#if SQLITE_COVERAGE_TEST + "COVERAGE_TEST", +#endif +#ifdef SQLITE_DEBUG + "DEBUG", +#endif +#if SQLITE_DEFAULT_LOCKING_MODE + "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), +#endif +#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) + "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), +#endif +#if SQLITE_DEFAULT_SYNCHRONOUS + "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), +#endif +#if SQLITE_DEFAULT_WAL_SYNCHRONOUS + "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), +#endif +#if SQLITE_DIRECT_OVERFLOW_READ + "DIRECT_OVERFLOW_READ", +#endif +#if SQLITE_DISABLE_DIRSYNC + "DISABLE_DIRSYNC", +#endif +#if SQLITE_DISABLE_LFS + "DISABLE_LFS", +#endif +#if SQLITE_ENABLE_8_3_NAMES + "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), +#endif +#if SQLITE_ENABLE_API_ARMOR + "ENABLE_API_ARMOR", +#endif +#if SQLITE_ENABLE_ATOMIC_WRITE + "ENABLE_ATOMIC_WRITE", +#endif +#if SQLITE_ENABLE_CEROD + "ENABLE_CEROD", +#endif +#if SQLITE_ENABLE_COLUMN_METADATA + "ENABLE_COLUMN_METADATA", +#endif +#if SQLITE_ENABLE_DBSTAT_VTAB + "ENABLE_DBSTAT_VTAB", +#endif +#if SQLITE_ENABLE_EXPENSIVE_ASSERT + "ENABLE_EXPENSIVE_ASSERT", +#endif +#if SQLITE_ENABLE_FTS1 + "ENABLE_FTS1", +#endif +#if SQLITE_ENABLE_FTS2 + "ENABLE_FTS2", +#endif +#if SQLITE_ENABLE_FTS3 + "ENABLE_FTS3", +#endif +#if SQLITE_ENABLE_FTS3_PARENTHESIS + "ENABLE_FTS3_PARENTHESIS", +#endif +#if SQLITE_ENABLE_FTS4 + "ENABLE_FTS4", +#endif +#if SQLITE_ENABLE_FTS5 + "ENABLE_FTS5", +#endif +#if SQLITE_ENABLE_ICU + "ENABLE_ICU", +#endif +#if SQLITE_ENABLE_IOTRACE + "ENABLE_IOTRACE", +#endif +#if SQLITE_ENABLE_JSON1 + "ENABLE_JSON1", +#endif +#if SQLITE_ENABLE_LOAD_EXTENSION + "ENABLE_LOAD_EXTENSION", +#endif +#if SQLITE_ENABLE_LOCKING_STYLE + "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), +#endif +#if SQLITE_ENABLE_MEMORY_MANAGEMENT + "ENABLE_MEMORY_MANAGEMENT", +#endif +#if SQLITE_ENABLE_MEMSYS3 + "ENABLE_MEMSYS3", +#endif +#if SQLITE_ENABLE_MEMSYS5 + "ENABLE_MEMSYS5", +#endif +#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK + "ENABLE_OVERSIZE_CELL_CHECK", +#endif +#if SQLITE_ENABLE_RTREE + "ENABLE_RTREE", +#endif +#if defined(SQLITE_ENABLE_STAT4) + "ENABLE_STAT4", +#elif defined(SQLITE_ENABLE_STAT3) + "ENABLE_STAT3", +#endif +#if SQLITE_ENABLE_UNLOCK_NOTIFY + "ENABLE_UNLOCK_NOTIFY", +#endif +#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT + "ENABLE_UPDATE_DELETE_LIMIT", +#endif +#if defined(SQLITE_ENABLE_URI_00_ERROR) + "ENABLE_URI_00_ERROR", +#endif +#if SQLITE_HAS_CODEC + "HAS_CODEC", +#endif +#if HAVE_ISNAN || SQLITE_HAVE_ISNAN + "HAVE_ISNAN", +#endif +#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX + "HOMEGROWN_RECURSIVE_MUTEX", +#endif +#if SQLITE_IGNORE_AFP_LOCK_ERRORS + "IGNORE_AFP_LOCK_ERRORS", +#endif +#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS + "IGNORE_FLOCK_LOCK_ERRORS", +#endif +#ifdef SQLITE_INT64_TYPE + "INT64_TYPE", +#endif +#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS + "LIKE_DOESNT_MATCH_BLOBS", +#endif +#if SQLITE_LOCK_TRACE + "LOCK_TRACE", +#endif +#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc) + "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), +#endif +#ifdef SQLITE_MAX_SCHEMA_RETRY + "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), +#endif +#if SQLITE_MEMDEBUG + "MEMDEBUG", +#endif +#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT + "MIXED_ENDIAN_64BIT_FLOAT", +#endif +#if SQLITE_NO_SYNC + "NO_SYNC", +#endif +#if SQLITE_OMIT_ALTERTABLE + "OMIT_ALTERTABLE", +#endif +#if SQLITE_OMIT_ANALYZE + "OMIT_ANALYZE", +#endif +#if SQLITE_OMIT_ATTACH + "OMIT_ATTACH", +#endif +#if SQLITE_OMIT_AUTHORIZATION + "OMIT_AUTHORIZATION", +#endif +#if SQLITE_OMIT_AUTOINCREMENT + "OMIT_AUTOINCREMENT", +#endif +#if SQLITE_OMIT_AUTOINIT + "OMIT_AUTOINIT", +#endif +#if SQLITE_OMIT_AUTOMATIC_INDEX + "OMIT_AUTOMATIC_INDEX", +#endif +#if SQLITE_OMIT_AUTORESET + "OMIT_AUTORESET", +#endif +#if SQLITE_OMIT_AUTOVACUUM + "OMIT_AUTOVACUUM", +#endif +#if SQLITE_OMIT_BETWEEN_OPTIMIZATION + "OMIT_BETWEEN_OPTIMIZATION", +#endif +#if SQLITE_OMIT_BLOB_LITERAL + "OMIT_BLOB_LITERAL", +#endif +#if SQLITE_OMIT_BTREECOUNT + "OMIT_BTREECOUNT", +#endif +#if SQLITE_OMIT_CAST + "OMIT_CAST", +#endif +#if SQLITE_OMIT_CHECK + "OMIT_CHECK", +#endif +#if SQLITE_OMIT_COMPLETE + "OMIT_COMPLETE", +#endif +#if SQLITE_OMIT_COMPOUND_SELECT + "OMIT_COMPOUND_SELECT", +#endif +#if SQLITE_OMIT_CTE + "OMIT_CTE", +#endif +#if SQLITE_OMIT_DATETIME_FUNCS + "OMIT_DATETIME_FUNCS", +#endif +#if SQLITE_OMIT_DECLTYPE + "OMIT_DECLTYPE", +#endif +#if SQLITE_OMIT_DEPRECATED + "OMIT_DEPRECATED", +#endif +#if SQLITE_OMIT_DISKIO + "OMIT_DISKIO", +#endif +#if SQLITE_OMIT_EXPLAIN + "OMIT_EXPLAIN", +#endif +#if SQLITE_OMIT_FLAG_PRAGMAS + "OMIT_FLAG_PRAGMAS", +#endif +#if SQLITE_OMIT_FLOATING_POINT + "OMIT_FLOATING_POINT", +#endif +#if SQLITE_OMIT_FOREIGN_KEY + "OMIT_FOREIGN_KEY", +#endif +#if SQLITE_OMIT_GET_TABLE + "OMIT_GET_TABLE", +#endif +#if SQLITE_OMIT_INCRBLOB + "OMIT_INCRBLOB", +#endif +#if SQLITE_OMIT_INTEGRITY_CHECK + "OMIT_INTEGRITY_CHECK", +#endif +#if SQLITE_OMIT_LIKE_OPTIMIZATION + "OMIT_LIKE_OPTIMIZATION", +#endif +#if SQLITE_OMIT_LOAD_EXTENSION + "OMIT_LOAD_EXTENSION", +#endif +#if SQLITE_OMIT_LOCALTIME + "OMIT_LOCALTIME", +#endif +#if SQLITE_OMIT_LOOKASIDE + "OMIT_LOOKASIDE", +#endif +#if SQLITE_OMIT_MEMORYDB + "OMIT_MEMORYDB", +#endif +#if SQLITE_OMIT_OR_OPTIMIZATION + "OMIT_OR_OPTIMIZATION", +#endif +#if SQLITE_OMIT_PAGER_PRAGMAS + "OMIT_PAGER_PRAGMAS", +#endif +#if SQLITE_OMIT_PRAGMA + "OMIT_PRAGMA", +#endif +#if SQLITE_OMIT_PROGRESS_CALLBACK + "OMIT_PROGRESS_CALLBACK", +#endif +#if SQLITE_OMIT_QUICKBALANCE + "OMIT_QUICKBALANCE", +#endif +#if SQLITE_OMIT_REINDEX + "OMIT_REINDEX", +#endif +#if SQLITE_OMIT_SCHEMA_PRAGMAS + "OMIT_SCHEMA_PRAGMAS", +#endif +#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS + "OMIT_SCHEMA_VERSION_PRAGMAS", +#endif +#if SQLITE_OMIT_SHARED_CACHE + "OMIT_SHARED_CACHE", +#endif +#if SQLITE_OMIT_SUBQUERY + "OMIT_SUBQUERY", +#endif +#if SQLITE_OMIT_TCL_VARIABLE + "OMIT_TCL_VARIABLE", +#endif +#if SQLITE_OMIT_TEMPDB + "OMIT_TEMPDB", +#endif +#if SQLITE_OMIT_TRACE + "OMIT_TRACE", +#endif +#if SQLITE_OMIT_TRIGGER + "OMIT_TRIGGER", +#endif +#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION + "OMIT_TRUNCATE_OPTIMIZATION", +#endif +#if SQLITE_OMIT_UTF16 + "OMIT_UTF16", +#endif +#if SQLITE_OMIT_VACUUM + "OMIT_VACUUM", +#endif +#if SQLITE_OMIT_VIEW + "OMIT_VIEW", +#endif +#if SQLITE_OMIT_VIRTUALTABLE + "OMIT_VIRTUALTABLE", +#endif +#if SQLITE_OMIT_WAL + "OMIT_WAL", +#endif +#if SQLITE_OMIT_WSD + "OMIT_WSD", +#endif +#if SQLITE_OMIT_XFER_OPT + "OMIT_XFER_OPT", +#endif +#if SQLITE_PERFORMANCE_TRACE + "PERFORMANCE_TRACE", +#endif +#if SQLITE_PROXY_DEBUG + "PROXY_DEBUG", +#endif +#if SQLITE_RTREE_INT_ONLY + "RTREE_INT_ONLY", +#endif +#if SQLITE_SECURE_DELETE + "SECURE_DELETE", +#endif +#if SQLITE_SMALL_STACK + "SMALL_STACK", +#endif +#if SQLITE_SOUNDEX + "SOUNDEX", +#endif +#if SQLITE_SYSTEM_MALLOC + "SYSTEM_MALLOC", +#endif +#if SQLITE_TCL + "TCL", +#endif +#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc) + "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), +#endif +#if SQLITE_TEST + "TEST", +#endif +#if defined(SQLITE_THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), +#endif +#if SQLITE_UNTESTABLE + "UNTESTABLE" +#endif +#if SQLITE_USE_ALLOCA + "USE_ALLOCA", +#endif +#if SQLITE_USER_AUTHENTICATION + "USER_AUTHENTICATION", +#endif +#if SQLITE_WIN32_MALLOC + "WIN32_MALLOC", +#endif +#if SQLITE_ZERO_MALLOC + "ZERO_MALLOC" +#endif +}; + +/* +** Given the name of a compile-time option, return true if that option +** was used and false if not. +** +** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix +** is not required for a match. +*/ +SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ + int i, n; + +#if SQLITE_ENABLE_API_ARMOR + if( zOptName==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; + n = sqlite3Strlen30(zOptName); + + /* Since ArraySize(azCompileOpt) is normally in single digits, a + ** linear search is adequate. No need for a binary search. */ + for(i=0; i=0 && NaDb[] (or -1) */ + u8 nullRow; /* True if pointing to a row with no data */ + u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ + u8 isTable; /* True for rowid tables. False for indexes */ +#ifdef SQLITE_DEBUG + u8 seekOp; /* Most recent seek operation on this cursor */ + u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */ +#endif + Bool isEphemeral:1; /* True for an ephemeral table */ + Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ + Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ + Btree *pBtx; /* Separate file holding temporary table */ + i64 seqCount; /* Sequence counter */ + int *aAltMap; /* Mapping from table to index column numbers */ + + /* Cached OP_Column parse information is only valid if cacheStatus matches + ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of + ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that + ** the cache is out of date. */ + 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". */ + + /* 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 */ + } uc; + KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ + u32 iHdrOffset; /* Offset to next unparsed byte of the header */ + Pgno pgnoRoot; /* Root page of the open btree cursor */ + i16 nField; /* Number of fields in the header */ + u16 nHdrParsed; /* Number of header fields parsed so far */ + i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ + u32 *aOffset; /* Pointer to aType[nField] */ + const u8 *aRow; /* Data for the current row, if all on one page */ + u32 payloadSize; /* Total number of bytes in the record */ + u32 szRow; /* Byte available in aRow */ +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + u64 maskUsed; /* Mask of columns used by this cursor */ +#endif + + /* 2*nField extra array elements allocated for aType[], beyond the one + ** static element declared in the structure. nField total array slots for + ** aType[] and nField+1 array slots for aOffset[] */ + u32 aType[1]; /* Type values record decode. MUST BE LAST */ +}; + + +/* +** A value for VdbeCursor.cacheStatus that means the cache is always invalid. +*/ +#define CACHE_STALE 0 + +/* +** When a sub-program is executed (OP_Program), a structure of this type +** is allocated to store the current value of the program counter, as +** well as the current memory cell array and various other frame specific +** values stored in the Vdbe struct. When the sub-program is finished, +** these values are copied back to the Vdbe from the VdbeFrame structure, +** restoring the state of the VM to as it was before the sub-program +** began executing. +** +** The memory for a VdbeFrame object is allocated and managed by a memory +** cell in the parent (calling) frame. When the memory cell is deleted or +** overwritten, the VdbeFrame object is not freed immediately. Instead, it +** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame +** list is deleted when the VM is reset in VdbeHalt(). The reason for doing +** this instead of deleting the VdbeFrame immediately is to avoid recursive +** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the +** child frame are released. +** +** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is +** set to NULL if the currently executing frame is the main program. +*/ +typedef struct VdbeFrame VdbeFrame; +struct VdbeFrame { + Vdbe *v; /* VM this frame belongs to */ + VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ + Op *aOp; /* Program instructions for parent frame */ + i64 *anExec; /* Event counters from parent frame */ + Mem *aMem; /* Array of memory cells for parent frame */ + VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ + u8 *aOnce; /* Bitmask used by OP_Once */ + void *token; /* Copy of SubProgram.token */ + i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ + AuxData *pAuxData; /* Linked list of auxdata allocations */ + int nCursor; /* Number of entries in apCsr */ + int pc; /* Program Counter in parent (calling) frame */ + int nOp; /* Size of aOp array */ + int nMem; /* Number of entries in aMem */ + int nChildMem; /* Number of memory cells for child frame */ + int nChildCsr; /* Number of cursors for child frame */ + int nChange; /* Statement changes (Vdbe.nChange) */ + int nDbChange; /* Value of db->nChange */ +}; + +#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) + +/* +** Internally, the vdbe manipulates nearly all SQL values as Mem +** structures. Each Mem struct may cache multiple representations (string, +** integer etc.) of the same value. +*/ +struct sqlite3_value { + union MemValue { + double r; /* Real value used when MEM_Real is set in flags */ + i64 i; /* Integer value used when MEM_Int is set in flags */ + int nZero; /* Used when bit MEM_Zero is set in flags */ + FuncDef *pDef; /* Used only when flags==MEM_Agg */ + RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ + VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ + } u; + u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ + u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ + u8 eSubtype; /* Subtype for this value */ + int n; /* Number of characters in string value, excluding '\0' */ + char *z; /* String or BLOB value */ + /* ShallowCopy only needs to copy the information above */ + char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ + int szMalloc; /* Size of the zMalloc allocation */ + u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ + sqlite3 *db; /* The associated database connection */ + void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ +#ifdef SQLITE_DEBUG + Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ + void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */ +#endif +}; + +/* +** Size of struct Mem not including the Mem.zMalloc member or anything that +** follows. +*/ +#define MEMCELLSIZE offsetof(Mem,zMalloc) + +/* One or more of the following flags are set to indicate the validOK +** representations of the value stored in the Mem struct. +** +** If the MEM_Null flag is set, then the value is an SQL NULL value. +** No other flags may be set in this case. +** +** If the MEM_Str flag is set then Mem.z points at a string representation. +** Usually this is encoded in the same unicode encoding as the main +** database (see below for exceptions). If the MEM_Term flag is also +** set, then the string is nul terminated. The MEM_Int and MEM_Real +** flags may coexist with the MEM_Str flag. +*/ +#define MEM_Null 0x0001 /* Value is NULL */ +#define MEM_Str 0x0002 /* Value is a string */ +#define MEM_Int 0x0004 /* Value is an integer */ +#define MEM_Real 0x0008 /* Value is a real number */ +#define MEM_Blob 0x0010 /* Value is a BLOB */ +#define MEM_AffMask 0x001f /* Mask of affinity bits */ +#define MEM_RowSet 0x0020 /* Value is a RowSet object */ +#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ +#define MEM_Undefined 0x0080 /* Value is undefined */ +#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ +#define MEM_TypeMask 0x81ff /* Mask of type bits */ + + +/* Whenever Mem contains a valid string or blob representation, one of +** the following flags must be set to determine the memory management +** policy for Mem.z. The MEM_Term flag tells us whether or not the +** string is \000 or \u0000 terminated +*/ +#define MEM_Term 0x0200 /* String rep is nul terminated */ +#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ +#define MEM_Static 0x0800 /* Mem.z points to a static string */ +#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ +#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ +#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ +#define MEM_Subtype 0x8000 /* Mem.eSubtype is valid */ +#ifdef SQLITE_OMIT_INCRBLOB + #undef MEM_Zero + #define MEM_Zero 0x0000 +#endif + +/* Return TRUE if Mem X contains dynamically allocated content - anything +** that needs to be deallocated to avoid a leak. +*/ +#define VdbeMemDynamic(X) \ + (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) + +/* +** Clear any existing type flags from a Mem and replace them with f +*/ +#define MemSetTypeFlag(p, f) \ + ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) + +/* +** Return true if a memory cell is not marked as invalid. This macro +** is for use inside assert() statements only. +*/ +#ifdef SQLITE_DEBUG +#define memIsValid(M) ((M)->flags & MEM_Undefined)==0 +#endif + +/* +** Each auxiliary data pointer stored by a user defined function +** implementation calling sqlite3_set_auxdata() is stored in an instance +** of this structure. All such structures associated with a single VM +** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed +** when the VM is halted (if not before). +*/ +struct AuxData { + int iAuxOp; /* Instruction number of OP_Function opcode */ + int iAuxArg; /* Index of function argument. */ + void *pAux; /* Aux data pointer */ + void (*xDeleteAux)(void*); /* Destructor for the aux data */ + AuxData *pNextAux; /* Next element in list */ +}; + +/* +** The "context" argument for an installable function. A pointer to an +** instance of this structure is the first argument to the routines used +** implement the SQL functions. +** +** There is a typedef for this structure in sqlite.h. So all routines, +** even the public interface to SQLite, can use a pointer to this structure. +** But this file is the only place where the internal details of this +** structure are known. +** +** This structure is defined inside of vdbeInt.h because it uses substructures +** (Mem) which are only defined there. +*/ +struct sqlite3_context { + Mem *pOut; /* The return value is stored here */ + FuncDef *pFunc; /* Pointer to function information */ + Mem *pMem; /* Memory cell used to store aggregate context */ + Vdbe *pVdbe; /* The VM that owns this context */ + int iOp; /* Instruction number of OP_Function */ + int isError; /* Error code returned by the function. */ + u8 skipFlag; /* Skip accumulator loading if true */ + u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */ + u8 argc; /* Number of arguments */ + sqlite3_value *argv[1]; /* Argument set */ +}; + +/* A bitfield type for use inside of structures. Always follow with :N where +** N is the number of bits. +*/ +typedef unsigned bft; /* Bit Field Type */ + +typedef struct ScanStatus ScanStatus; +struct ScanStatus { + int addrExplain; /* OP_Explain for loop */ + int addrLoop; /* Address of "loops" counter */ + int addrVisit; /* Address of "rows visited" counter */ + int iSelectID; /* The "Select-ID" for this loop */ + LogEst nEst; /* Estimated output rows per loop */ + char *zName; /* Name of table or index */ +}; + +/* +** An instance of the virtual machine. This structure contains the complete +** state of the virtual machine. +** +** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() +** is really a pointer to an instance of this structure. +*/ +struct Vdbe { + sqlite3 *db; /* The database connection that owns this statement */ + Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ + Parse *pParse; /* Parsing context used to create this Vdbe */ + ynVar nVar; /* Number of entries in aVar[] */ + u32 magic; /* Magic number for sanity checking */ + int nMem; /* Number of memory locations currently allocated */ + int nCursor; /* Number of slots in apCsr[] */ + u32 cacheCtr; /* VdbeCursor row cache generation counter */ + int pc; /* The program counter */ + int rc; /* Value to return */ + int nChange; /* Number of db changes made since last reset */ + int iStatement; /* Statement number (or 0 if has not opened stmt) */ + i64 iCurrentTime; /* Value of julianday('now') for this statement */ + i64 nFkConstraint; /* Number of imm. FK constraints this VM */ + i64 nStmtDefCons; /* Number of def. constraints when stmt started */ + i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ + + /* When allocating a new Vdbe object, all of the fields below should be + ** initialized to zero or NULL */ + + Op *aOp; /* Space to hold the virtual machine's program */ + Mem *aMem; /* The memory locations */ + Mem **apArg; /* Arguments to currently executing user function */ + Mem *aColName; /* Column names to return */ + Mem *pResultSet; /* Pointer to an array of results */ + char *zErrMsg; /* Error message written here */ + VdbeCursor **apCsr; /* One element of this array for each open cursor */ + Mem *aVar; /* Values for the OP_Variable opcode. */ + VList *pVList; /* Name of variables */ +#ifndef SQLITE_OMIT_TRACE + i64 startTime; /* Time when query started - used for profiling */ +#endif + int nOp; /* Number of instructions in the program */ +#ifdef SQLITE_DEBUG + int rcApp; /* errcode set by sqlite3_result_error_code() */ +#endif + u16 nResColumn; /* Number of columns in one row of the result set */ + u8 errorAction; /* Recovery action to do in case of an error */ + u8 minWriteFileFormat; /* Minimum file format for writable database files */ + bft expired:1; /* True if the VM needs to be recompiled */ + bft doingRerun:1; /* True if rerunning after an auto-reprepare */ + bft explain:2; /* True if EXPLAIN present on SQL command */ + bft changeCntOn:1; /* True to update the change-counter */ + bft runOnlyOnce:1; /* Automatically expire on reset */ + bft usesStmtJournal:1; /* True if uses a statement journal */ + bft readOnly:1; /* True for statements that do not write */ + bft bIsReader:1; /* True for statements that read */ + bft isPrepareV2:1; /* True if prepared with prepare_v2() */ + yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ + yDbMask lockMask; /* Subset of btreeMask that requires a lock */ + u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */ + char *zSql; /* Text of the SQL statement that generated this */ + void *pFree; /* Free this when deleting the vdbe */ + VdbeFrame *pFrame; /* Parent frame */ + VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ + int nFrame; /* Number of frames in pFrame list */ + u32 expmask; /* Binding to these vars invalidates VM */ + SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ + AuxData *pAuxData; /* Linked list of auxdata allocations */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + i64 *anExec; /* Number of times each op has been executed */ + int nScan; /* Entries in aScan[] */ + ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ +#endif +}; + +/* +** The following are allowed values for Vdbe.magic +*/ +#define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */ +#define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */ +#define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */ +#define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */ +#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */ + +/* +** Structure used to store the context required by the +** sqlite3_preupdate_*() API functions. +*/ +struct PreUpdate { + Vdbe *v; + VdbeCursor *pCsr; /* Cursor to read old values from */ + int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ + u8 *aRecord; /* old.* database record */ + KeyInfo keyinfo; + UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ + UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ + int iNewReg; /* Register for new.* values */ + i64 iKey1; /* First key value passed to hook */ + i64 iKey2; /* Second key value passed to hook */ + Mem *aNew; /* Array of new.* values */ + Table *pTab; /* Schema object being upated */ + Index *pPk; /* PK index if pTab is WITHOUT ROWID */ +}; + +/* +** Function prototypes +*/ +SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...); +SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); +void sqliteVdbePopStack(Vdbe*,int); +SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*); +SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) +SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); +#endif +SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); +SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8); +SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*); +SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); +SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); +SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int); + +int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); +SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); +SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); +SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); +SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); +SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); +SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int); +SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*); +SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); +SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); +SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); +#ifdef SQLITE_OMIT_FLOATING_POINT +# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64 +#else +SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double); +#endif +SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); +SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); +SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); +SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); +SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); +SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); +SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); +SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8); +SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); +SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); +SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); +SQLITE_PRIVATE const char *sqlite3OpcodeName(int); +SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); +SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); +SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); +SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); +SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int); +#endif +SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); + +SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); +SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); +SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); +SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); +SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); +SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); +SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); + +#if !defined(SQLITE_OMIT_SHARED_CACHE) +SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); +#else +# define sqlite3VdbeEnter(X) +#endif + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); +#else +# define sqlite3VdbeLeave(X) +#endif + +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*); +SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*); +#endif + +#ifndef SQLITE_OMIT_FOREIGN_KEY +SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); +#else +# define sqlite3VdbeCheckFk(p,i) 0 +#endif + +SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); +#endif +SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); + +#ifndef SQLITE_OMIT_INCRBLOB +SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *); + #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) +#else + #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK + #define ExpandBlob(P) SQLITE_OK +#endif + +#endif /* !defined(SQLITE_VDBEINT_H) */ + +/************** End of vdbeInt.h *********************************************/ +/************** Continuing where we left off in status.c *********************/ + +/* +** Variables in which to record status information. +*/ +#if SQLITE_PTRSIZE>4 +typedef sqlite3_int64 sqlite3StatValueType; +#else +typedef u32 sqlite3StatValueType; +#endif +typedef struct sqlite3StatType sqlite3StatType; +static SQLITE_WSD struct sqlite3StatType { + sqlite3StatValueType nowValue[10]; /* Current value */ + sqlite3StatValueType mxValue[10]; /* Maximum value */ +} sqlite3Stat = { {0,}, {0,} }; + +/* +** Elements of sqlite3Stat[] are protected by either the memory allocator +** mutex, or by the pcache1 mutex. The following array determines which. +*/ +static const char statMutex[] = { + 0, /* SQLITE_STATUS_MEMORY_USED */ + 1, /* SQLITE_STATUS_PAGECACHE_USED */ + 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */ + 0, /* SQLITE_STATUS_SCRATCH_USED */ + 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */ + 0, /* SQLITE_STATUS_MALLOC_SIZE */ + 0, /* SQLITE_STATUS_PARSER_STACK */ + 1, /* SQLITE_STATUS_PAGECACHE_SIZE */ + 0, /* SQLITE_STATUS_SCRATCH_SIZE */ + 0, /* SQLITE_STATUS_MALLOC_COUNT */ +}; + + +/* The "wsdStat" macro will resolve to the status information +** state vector. If writable static data is unsupported on the target, +** we have to locate the state vector at run-time. In the more common +** case where writable static data is supported, wsdStat can refer directly +** to the "sqlite3Stat" state vector declared above. +*/ +#ifdef SQLITE_OMIT_WSD +# define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat) +# define wsdStat x[0] +#else +# define wsdStatInit +# define wsdStat sqlite3Stat +#endif + +/* +** Return the current value of a status parameter. The caller must +** be holding the appropriate mutex. +*/ +SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int op){ + wsdStatInit; + assert( op>=0 && op=0 && op=0 && op=0 && opwsdStat.mxValue[op] ){ + wsdStat.mxValue[op] = wsdStat.nowValue[op]; + } +} +SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){ + wsdStatInit; + assert( N>=0 ); + assert( op>=0 && op=0 && op=0 ); + newValue = (sqlite3StatValueType)X; + assert( op>=0 && op=0 && opwsdStat.mxValue[op] ){ + wsdStat.mxValue[op] = newValue; + } +} + +/* +** Query status information. +*/ +SQLITE_API int sqlite3_status64( + int op, + sqlite3_int64 *pCurrent, + sqlite3_int64 *pHighwater, + int resetFlag +){ + sqlite3_mutex *pMutex; + wsdStatInit; + if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ + return SQLITE_MISUSE_BKPT; + } +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; +#endif + pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex(); + sqlite3_mutex_enter(pMutex); + *pCurrent = wsdStat.nowValue[op]; + *pHighwater = wsdStat.mxValue[op]; + if( resetFlag ){ + wsdStat.mxValue[op] = wsdStat.nowValue[op]; + } + sqlite3_mutex_leave(pMutex); + (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ + return SQLITE_OK; +} +SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ + sqlite3_int64 iCur = 0, iHwtr = 0; + int rc; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; +#endif + rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag); + if( rc==0 ){ + *pCurrent = (int)iCur; + *pHighwater = (int)iHwtr; + } + return rc; +} + +/* +** Query status information for a single database connection +*/ +SQLITE_API int sqlite3_db_status( + sqlite3 *db, /* The database connection whose status is desired */ + int op, /* Status verb */ + int *pCurrent, /* Write current value here */ + int *pHighwater, /* Write high-water mark here */ + int resetFlag /* Reset high-water mark if true */ +){ + int rc = SQLITE_OK; /* Return code */ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + switch( op ){ + case SQLITE_DBSTATUS_LOOKASIDE_USED: { + *pCurrent = db->lookaside.nOut; + *pHighwater = db->lookaside.mxOut; + if( resetFlag ){ + db->lookaside.mxOut = db->lookaside.nOut; + } + break; + } + + case SQLITE_DBSTATUS_LOOKASIDE_HIT: + case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: + case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { + testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT ); + testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE ); + testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL ); + assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); + assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); + *pCurrent = 0; + *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; + if( resetFlag ){ + db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; + } + break; + } + + /* + ** Return an approximation for the amount of memory currently used + ** by all pagers associated with the given database connection. The + ** highwater mark is meaningless and is returned as zero. + */ + case SQLITE_DBSTATUS_CACHE_USED_SHARED: + case SQLITE_DBSTATUS_CACHE_USED: { + int totalUsed = 0; + int i; + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + Pager *pPager = sqlite3BtreePager(pBt); + int nByte = sqlite3PagerMemUsed(pPager); + if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){ + nByte = nByte / sqlite3BtreeConnectionCount(pBt); + } + totalUsed += nByte; + } + } + sqlite3BtreeLeaveAll(db); + *pCurrent = totalUsed; + *pHighwater = 0; + break; + } + + /* + ** *pCurrent gets an accurate estimate of the amount of memory used + ** to store the schema for all databases (main, temp, and any ATTACHed + ** databases. *pHighwater is set to zero. + */ + case SQLITE_DBSTATUS_SCHEMA_USED: { + int i; /* Used to iterate through schemas */ + int nByte = 0; /* Used to accumulate return value */ + + sqlite3BtreeEnterAll(db); + db->pnBytesFreed = &nByte; + for(i=0; inDb; i++){ + Schema *pSchema = db->aDb[i].pSchema; + if( ALWAYS(pSchema!=0) ){ + HashElem *p; + + nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( + pSchema->tblHash.count + + pSchema->trigHash.count + + pSchema->idxHash.count + + pSchema->fkeyHash.count + ); + nByte += sqlite3_msize(pSchema->tblHash.ht); + nByte += sqlite3_msize(pSchema->trigHash.ht); + nByte += sqlite3_msize(pSchema->idxHash.ht); + nByte += sqlite3_msize(pSchema->fkeyHash.ht); + + for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ + sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); + } + for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ + sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); + } + } + } + db->pnBytesFreed = 0; + sqlite3BtreeLeaveAll(db); + + *pHighwater = 0; + *pCurrent = nByte; + break; + } + + /* + ** *pCurrent gets an accurate estimate of the amount of memory used + ** to store all prepared statements. + ** *pHighwater is set to zero. + */ + case SQLITE_DBSTATUS_STMT_USED: { + struct Vdbe *pVdbe; /* Used to iterate through VMs */ + int nByte = 0; /* Used to accumulate return value */ + + db->pnBytesFreed = &nByte; + for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ + sqlite3VdbeClearObject(db, pVdbe); + sqlite3DbFree(db, pVdbe); + } + db->pnBytesFreed = 0; + + *pHighwater = 0; /* IMP: R-64479-57858 */ + *pCurrent = nByte; + + break; + } + + /* + ** Set *pCurrent to the total cache hits or misses encountered by all + ** pagers the database handle is connected to. *pHighwater is always set + ** to zero. + */ + case SQLITE_DBSTATUS_CACHE_HIT: + case SQLITE_DBSTATUS_CACHE_MISS: + case SQLITE_DBSTATUS_CACHE_WRITE:{ + int i; + int nRet = 0; + assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); + assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); + + for(i=0; inDb; i++){ + if( db->aDb[i].pBt ){ + Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); + sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); + } + } + *pHighwater = 0; /* IMP: R-42420-56072 */ + /* IMP: R-54100-20147 */ + /* IMP: R-29431-39229 */ + *pCurrent = nRet; + break; + } + + /* Set *pCurrent to non-zero if there are unresolved deferred foreign + ** key constraints. Set *pCurrent to zero if all foreign key constraints + ** have been satisfied. The *pHighwater is always set to zero. + */ + case SQLITE_DBSTATUS_DEFERRED_FKS: { + *pHighwater = 0; /* IMP: R-11967-56545 */ + *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; + break; + } + + default: { + rc = SQLITE_ERROR; + } + } + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/************** End of status.c **********************************************/ +/************** Begin file date.c ********************************************/ +/* +** 2003 October 31 +** +** 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 the C functions that implement date and time +** functions for SQLite. +** +** There is only one exported symbol in this file - the function +** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. +** All other code has file scope. +** +** SQLite processes all times and dates as julian day numbers. The +** dates and times are stored as the number of days since noon +** in Greenwich on November 24, 4714 B.C. according to the Gregorian +** calendar system. +** +** 1970-01-01 00:00:00 is JD 2440587.5 +** 2000-01-01 00:00:00 is JD 2451544.5 +** +** This implementation requires years to be expressed as a 4-digit number +** which means that only dates between 0000-01-01 and 9999-12-31 can +** be represented, even though julian day numbers allow a much wider +** range of dates. +** +** The Gregorian calendar system is used for all dates and times, +** even those that predate the Gregorian calendar. Historians usually +** use the julian calendar for dates prior to 1582-10-15 and for some +** dates afterwards, depending on locale. Beware of this difference. +** +** The conversion algorithms are implemented based on descriptions +** in the following text: +** +** Jean Meeus +** Astronomical Algorithms, 2nd Edition, 1998 +** ISBM 0-943396-61-1 +** Willmann-Bell, Inc +** Richmond, Virginia (USA) +*/ +/* #include "sqliteInt.h" */ +/* #include */ +/* #include */ +#include + +#ifndef SQLITE_OMIT_DATETIME_FUNCS + +/* +** The MSVC CRT on Windows CE may not have a localtime() function. +** So declare a substitute. The substitute function itself is +** defined in "os_win.c". +*/ +#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ + (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) +struct tm *__cdecl localtime(const time_t *); +#endif + +/* +** A structure for holding a single date and time. +*/ +typedef struct DateTime DateTime; +struct DateTime { + sqlite3_int64 iJD; /* The julian day number times 86400000 */ + int Y, M, D; /* Year, month, and day */ + int h, m; /* Hour and minutes */ + int tz; /* Timezone offset in minutes */ + double s; /* Seconds */ + char validJD; /* True (1) if iJD is valid */ + char rawS; /* Raw numeric value stored in s */ + char validYMD; /* True (1) if Y,M,D are valid */ + char validHMS; /* True (1) if h,m,s are valid */ + char validTZ; /* True (1) if tz is valid */ + char tzSet; /* Timezone was set explicitly */ + char isError; /* An overflow has occurred */ +}; + + +/* +** Convert zDate into one or more integers according to the conversion +** specifier zFormat. +** +** zFormat[] contains 4 characters for each integer converted, except for +** the last integer which is specified by three characters. The meaning +** of a four-character format specifiers ABCD is: +** +** A: number of digits to convert. Always "2" or "4". +** B: minimum value. Always "0" or "1". +** C: maximum value, decoded as: +** a: 12 +** b: 14 +** c: 24 +** d: 31 +** e: 59 +** f: 9999 +** D: the separator character, or \000 to indicate this is the +** last number to convert. +** +** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would +** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-". +** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates +** the 2-digit day which is the last integer in the set. +** +** The function returns the number of successful conversions. +*/ +static int getDigits(const char *zDate, const char *zFormat, ...){ + /* The aMx[] array translates the 3rd character of each format + ** spec into a max size: a b c d e f */ + static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 }; + va_list ap; + int cnt = 0; + char nextC; + va_start(ap, zFormat); + do{ + char N = zFormat[0] - '0'; + char min = zFormat[1] - '0'; + int val = 0; + u16 max; + + assert( zFormat[2]>='a' && zFormat[2]<='f' ); + max = aMx[zFormat[2] - 'a']; + nextC = zFormat[3]; + val = 0; + while( N-- ){ + if( !sqlite3Isdigit(*zDate) ){ + goto end_getDigits; + } + val = val*10 + *zDate - '0'; + zDate++; + } + if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){ + goto end_getDigits; + } + *va_arg(ap,int*) = val; + zDate++; + cnt++; + zFormat += 4; + }while( nextC ); +end_getDigits: + va_end(ap); + return cnt; +} + +/* +** Parse a timezone extension on the end of a date-time. +** The extension is of the form: +** +** (+/-)HH:MM +** +** Or the "zulu" notation: +** +** Z +** +** If the parse is successful, write the number of minutes +** of change in p->tz and return 0. If a parser error occurs, +** return non-zero. +** +** A missing specifier is not considered an error. +*/ +static int parseTimezone(const char *zDate, DateTime *p){ + int sgn = 0; + int nHr, nMn; + int c; + while( sqlite3Isspace(*zDate) ){ zDate++; } + p->tz = 0; + c = *zDate; + if( c=='-' ){ + sgn = -1; + }else if( c=='+' ){ + sgn = +1; + }else if( c=='Z' || c=='z' ){ + zDate++; + goto zulu_time; + }else{ + return c!=0; + } + zDate++; + if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){ + return 1; + } + zDate += 5; + p->tz = sgn*(nMn + nHr*60); +zulu_time: + while( sqlite3Isspace(*zDate) ){ zDate++; } + p->tzSet = 1; + return *zDate!=0; +} + +/* +** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF. +** The HH, MM, and SS must each be exactly 2 digits. The +** fractional seconds FFFF can be one or more digits. +** +** Return 1 if there is a parsing error and 0 on success. +*/ +static int parseHhMmSs(const char *zDate, DateTime *p){ + int h, m, s; + double ms = 0.0; + if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){ + return 1; + } + zDate += 5; + if( *zDate==':' ){ + zDate++; + if( getDigits(zDate, "20e", &s)!=1 ){ + return 1; + } + zDate += 2; + if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){ + double rScale = 1.0; + zDate++; + while( sqlite3Isdigit(*zDate) ){ + ms = ms*10.0 + *zDate - '0'; + rScale *= 10.0; + zDate++; + } + ms /= rScale; + } + }else{ + s = 0; + } + p->validJD = 0; + p->rawS = 0; + p->validHMS = 1; + p->h = h; + p->m = m; + p->s = s + ms; + if( parseTimezone(zDate, p) ) return 1; + p->validTZ = (p->tz!=0)?1:0; + return 0; +} + +/* +** Put the DateTime object into its error state. +*/ +static void datetimeError(DateTime *p){ + memset(p, 0, sizeof(*p)); + p->isError = 1; +} + +/* +** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume +** that the YYYY-MM-DD is according to the Gregorian calendar. +** +** Reference: Meeus page 61 +*/ +static void computeJD(DateTime *p){ + int Y, M, D, A, B, X1, X2; + + if( p->validJD ) return; + if( p->validYMD ){ + Y = p->Y; + M = p->M; + D = p->D; + }else{ + Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */ + M = 1; + D = 1; + } + if( Y<-4713 || Y>9999 || p->rawS ){ + datetimeError(p); + return; + } + if( M<=2 ){ + Y--; + M += 12; + } + A = Y/100; + B = 2 - A + (A/4); + X1 = 36525*(Y+4716)/100; + X2 = 306001*(M+1)/10000; + p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); + p->validJD = 1; + if( p->validHMS ){ + p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000); + if( p->validTZ ){ + p->iJD -= p->tz*60000; + p->validYMD = 0; + p->validHMS = 0; + p->validTZ = 0; + } + } +} + +/* +** Parse dates of the form +** +** YYYY-MM-DD HH:MM:SS.FFF +** YYYY-MM-DD HH:MM:SS +** YYYY-MM-DD HH:MM +** YYYY-MM-DD +** +** Write the result into the DateTime structure and return 0 +** on success and 1 if the input string is not a well-formed +** date. +*/ +static int parseYyyyMmDd(const char *zDate, DateTime *p){ + int Y, M, D, neg; + + if( zDate[0]=='-' ){ + zDate++; + neg = 1; + }else{ + neg = 0; + } + if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){ + return 1; + } + zDate += 10; + while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; } + if( parseHhMmSs(zDate, p)==0 ){ + /* We got the time */ + }else if( *zDate==0 ){ + p->validHMS = 0; + }else{ + return 1; + } + p->validJD = 0; + p->validYMD = 1; + p->Y = neg ? -Y : Y; + p->M = M; + p->D = D; + if( p->validTZ ){ + computeJD(p); + } + return 0; +} + +/* +** Set the time to the current time reported by the VFS. +** +** Return the number of errors. +*/ +static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ + p->iJD = sqlite3StmtCurrentTime(context); + if( p->iJD>0 ){ + p->validJD = 1; + return 0; + }else{ + return 1; + } +} + +/* +** Input "r" is a numeric quantity which might be a julian day number, +** or the number of seconds since 1970. If the value if r is within +** range of a julian day number, install it as such and set validJD. +** If the value is a valid unix timestamp, put it in p->s and set p->rawS. +*/ +static void setRawDateNumber(DateTime *p, double r){ + p->s = r; + p->rawS = 1; + if( r>=0.0 && r<5373484.5 ){ + p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); + p->validJD = 1; + } +} + +/* +** Attempt to parse the given string into a julian day number. Return +** the number of errors. +** +** The following are acceptable forms for the input string: +** +** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM +** DDDD.DD +** now +** +** In the first form, the +/-HH:MM is always optional. The fractional +** seconds extension (the ".FFF") is optional. The seconds portion +** (":SS.FFF") is option. The year and date can be omitted as long +** as there is a time string. The time string can be omitted as long +** as there is a year and date. +*/ +static int parseDateOrTime( + sqlite3_context *context, + const char *zDate, + DateTime *p +){ + double r; + if( parseYyyyMmDd(zDate,p)==0 ){ + return 0; + }else if( parseHhMmSs(zDate, p)==0 ){ + return 0; + }else if( sqlite3StrICmp(zDate,"now")==0){ + return setDateTimeToCurrent(context, p); + }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ + setRawDateNumber(p, r); + return 0; + } + return 1; +} + +/* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999. +** Multiplying this by 86400000 gives 464269060799999 as the maximum value +** for DateTime.iJD. +** +** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with +** such a large integer literal, so we have to encode it. +*/ +#define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff) + +/* +** Return TRUE if the given julian day number is within range. +** +** The input is the JulianDay times 86400000. +*/ +static int validJulianDay(sqlite3_int64 iJD){ + return iJD>=0 && iJD<=INT_464269060799999; +} + +/* +** Compute the Year, Month, and Day from the julian day number. +*/ +static void computeYMD(DateTime *p){ + int Z, A, B, C, D, E, X1; + if( p->validYMD ) return; + if( !p->validJD ){ + p->Y = 2000; + p->M = 1; + p->D = 1; + }else if( !validJulianDay(p->iJD) ){ + datetimeError(p); + return; + }else{ + Z = (int)((p->iJD + 43200000)/86400000); + A = (int)((Z - 1867216.25)/36524.25); + A = Z + 1 + A - (A/4); + B = A + 1524; + C = (int)((B - 122.1)/365.25); + D = (36525*(C&32767))/100; + E = (int)((B-D)/30.6001); + X1 = (int)(30.6001*E); + p->D = B - D - X1; + p->M = E<14 ? E-1 : E-13; + p->Y = p->M>2 ? C - 4716 : C - 4715; + } + p->validYMD = 1; +} + +/* +** Compute the Hour, Minute, and Seconds from the julian day number. +*/ +static void computeHMS(DateTime *p){ + int s; + if( p->validHMS ) return; + computeJD(p); + s = (int)((p->iJD + 43200000) % 86400000); + p->s = s/1000.0; + s = (int)p->s; + p->s -= s; + p->h = s/3600; + s -= p->h*3600; + p->m = s/60; + p->s += s - p->m*60; + p->rawS = 0; + p->validHMS = 1; +} + +/* +** Compute both YMD and HMS +*/ +static void computeYMD_HMS(DateTime *p){ + computeYMD(p); + computeHMS(p); +} + +/* +** Clear the YMD and HMS and the TZ +*/ +static void clearYMD_HMS_TZ(DateTime *p){ + p->validYMD = 0; + p->validHMS = 0; + p->validTZ = 0; +} + +#ifndef SQLITE_OMIT_LOCALTIME +/* +** On recent Windows platforms, the localtime_s() function is available +** as part of the "Secure CRT". It is essentially equivalent to +** localtime_r() available under most POSIX platforms, except that the +** order of the parameters is reversed. +** +** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx. +** +** If the user has not indicated to use localtime_r() or localtime_s() +** already, check for an MSVC build environment that provides +** localtime_s(). +*/ +#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \ + && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE) +#undef HAVE_LOCALTIME_S +#define HAVE_LOCALTIME_S 1 +#endif + +/* +** The following routine implements the rough equivalent of localtime_r() +** using whatever operating-system specific localtime facility that +** is available. This routine returns 0 on success and +** non-zero on any kind of error. +** +** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this +** routine will always fail. +** +** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C +** library function localtime_r() is used to assist in the calculation of +** local time. +*/ +static int osLocaltime(time_t *t, struct tm *pTm){ + int rc; +#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S + struct tm *pX; +#if SQLITE_THREADSAFE>0 + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif + sqlite3_mutex_enter(mutex); + pX = localtime(t); +#ifndef SQLITE_UNTESTABLE + if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; +#endif + if( pX ) *pTm = *pX; + sqlite3_mutex_leave(mutex); + rc = pX==0; +#else +#ifndef SQLITE_UNTESTABLE + if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; +#endif +#if HAVE_LOCALTIME_R + rc = localtime_r(t, pTm)==0; +#else + rc = localtime_s(pTm, t); +#endif /* HAVE_LOCALTIME_R */ +#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */ + return rc; +} +#endif /* SQLITE_OMIT_LOCALTIME */ + + +#ifndef SQLITE_OMIT_LOCALTIME +/* +** Compute the difference (in milliseconds) between localtime and UTC +** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs, +** return this value and set *pRc to SQLITE_OK. +** +** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value +** is undefined in this case. +*/ +static sqlite3_int64 localtimeOffset( + DateTime *p, /* Date at which to calculate offset */ + sqlite3_context *pCtx, /* Write error here if one occurs */ + int *pRc /* OUT: Error code. SQLITE_OK or ERROR */ +){ + DateTime x, y; + time_t t; + struct tm sLocal; + + /* Initialize the contents of sLocal to avoid a compiler warning. */ + memset(&sLocal, 0, sizeof(sLocal)); + + x = *p; + computeYMD_HMS(&x); + if( x.Y<1971 || x.Y>=2038 ){ + /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only + ** works for years between 1970 and 2037. For dates outside this range, + ** SQLite attempts to map the year into an equivalent year within this + ** range, do the calculation, then map the year back. + */ + x.Y = 2000; + x.M = 1; + x.D = 1; + x.h = 0; + x.m = 0; + x.s = 0.0; + } else { + int s = (int)(x.s + 0.5); + x.s = s; + } + x.tz = 0; + x.validJD = 0; + computeJD(&x); + t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); + if( osLocaltime(&t, &sLocal) ){ + sqlite3_result_error(pCtx, "local time unavailable", -1); + *pRc = SQLITE_ERROR; + return 0; + } + y.Y = sLocal.tm_year + 1900; + y.M = sLocal.tm_mon + 1; + y.D = sLocal.tm_mday; + y.h = sLocal.tm_hour; + y.m = sLocal.tm_min; + y.s = sLocal.tm_sec; + y.validYMD = 1; + y.validHMS = 1; + y.validJD = 0; + y.rawS = 0; + y.validTZ = 0; + y.isError = 0; + computeJD(&y); + *pRc = SQLITE_OK; + return y.iJD - x.iJD; +} +#endif /* SQLITE_OMIT_LOCALTIME */ + +/* +** The following table defines various date transformations of the form +** +** 'NNN days' +** +** Where NNN is an arbitrary floating-point number and "days" can be one +** of several units of time. +*/ +static const struct { + u8 eType; /* Transformation type code */ + u8 nName; /* Length of th name */ + char *zName; /* Name of the transformation */ + double rLimit; /* Maximum NNN value for this transform */ + double rXform; /* Constant used for this transform */ +} aXformType[] = { + { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) }, + { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) }, + { 0, 4, "hour", 128963628.0, 86400000.0/24.0 }, + { 0, 3, "day", 5373485.0, 86400000.0 }, + { 1, 5, "month", 176546.0, 30.0*86400000.0 }, + { 2, 4, "year", 14713.0, 365.0*86400000.0 }, +}; + +/* +** Process a modifier to a date-time stamp. The modifiers are +** as follows: +** +** NNN days +** NNN hours +** NNN minutes +** NNN.NNNN seconds +** NNN months +** NNN years +** start of month +** start of year +** start of week +** start of day +** weekday N +** unixepoch +** localtime +** utc +** +** Return 0 on success and 1 if there is any kind of error. If the error +** is in a system call (i.e. localtime()), then an error message is written +** to context pCtx. If the error is an unrecognized modifier, no error is +** written to pCtx. +*/ +static int parseModifier( + sqlite3_context *pCtx, /* Function context */ + const char *z, /* The text of the modifier */ + int n, /* Length of zMod in bytes */ + DateTime *p /* The date/time value to be modified */ +){ + int rc = 1; + double r; + switch(sqlite3UpperToLower[(u8)z[0]] ){ +#ifndef SQLITE_OMIT_LOCALTIME + case 'l': { + /* localtime + ** + ** Assuming the current time value is UTC (a.k.a. GMT), shift it to + ** show local time. + */ + if( sqlite3_stricmp(z, "localtime")==0 ){ + computeJD(p); + p->iJD += localtimeOffset(p, pCtx, &rc); + clearYMD_HMS_TZ(p); + } + break; + } +#endif + case 'u': { + /* + ** unixepoch + ** + ** Treat the current value of p->s as the number of + ** seconds since 1970. Convert to a real julian day number. + */ + if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ + r = p->s*1000.0 + 210866760000000.0; + if( r>=0.0 && r<464269060800000.0 ){ + clearYMD_HMS_TZ(p); + p->iJD = (sqlite3_int64)r; + p->validJD = 1; + p->rawS = 0; + rc = 0; + } + } +#ifndef SQLITE_OMIT_LOCALTIME + else if( sqlite3_stricmp(z, "utc")==0 ){ + if( p->tzSet==0 ){ + sqlite3_int64 c1; + computeJD(p); + c1 = localtimeOffset(p, pCtx, &rc); + if( rc==SQLITE_OK ){ + p->iJD -= c1; + clearYMD_HMS_TZ(p); + p->iJD += c1 - localtimeOffset(p, pCtx, &rc); + } + p->tzSet = 1; + }else{ + rc = SQLITE_OK; + } + } +#endif + break; + } + case 'w': { + /* + ** weekday N + ** + ** Move the date to the same time on the next occurrence of + ** weekday N where 0==Sunday, 1==Monday, and so forth. If the + ** date is already on the appropriate weekday, this is a no-op. + */ + if( sqlite3_strnicmp(z, "weekday ", 8)==0 + && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) + && (n=(int)r)==r && n>=0 && r<7 ){ + sqlite3_int64 Z; + computeYMD_HMS(p); + p->validTZ = 0; + p->validJD = 0; + computeJD(p); + Z = ((p->iJD + 129600000)/86400000) % 7; + if( Z>n ) Z -= 7; + p->iJD += (n - Z)*86400000; + clearYMD_HMS_TZ(p); + rc = 0; + } + break; + } + case 's': { + /* + ** start of TTTTT + ** + ** Move the date backwards to the beginning of the current day, + ** or month or year. + */ + if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break; + if( !p->validJD && !p->validYMD && !p->validHMS ) break; + z += 9; + computeYMD(p); + p->validHMS = 1; + p->h = p->m = 0; + p->s = 0.0; + p->rawS = 0; + p->validTZ = 0; + p->validJD = 0; + if( sqlite3_stricmp(z,"month")==0 ){ + p->D = 1; + rc = 0; + }else if( sqlite3_stricmp(z,"year")==0 ){ + p->M = 1; + p->D = 1; + rc = 0; + }else if( sqlite3_stricmp(z,"day")==0 ){ + rc = 0; + } + break; + } + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + double rRounder; + int i; + for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} + if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ + rc = 1; + break; + } + if( z[n]==':' ){ + /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the + ** specified number of hours, minutes, seconds, and fractional seconds + ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be + ** omitted. + */ + const char *z2 = z; + DateTime tx; + sqlite3_int64 day; + if( !sqlite3Isdigit(*z2) ) z2++; + memset(&tx, 0, sizeof(tx)); + if( parseHhMmSs(z2, &tx) ) break; + computeJD(&tx); + tx.iJD -= 43200000; + day = tx.iJD/86400000; + tx.iJD -= day*86400000; + if( z[0]=='-' ) tx.iJD = -tx.iJD; + computeJD(p); + clearYMD_HMS_TZ(p); + p->iJD += tx.iJD; + rc = 0; + break; + } + + /* If control reaches this point, it means the transformation is + ** one of the forms like "+NNN days". */ + z += n; + while( sqlite3Isspace(*z) ) z++; + n = sqlite3Strlen30(z); + if( n>10 || n<3 ) break; + if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; + computeJD(p); + rc = 1; + rRounder = r<0 ? -0.5 : +0.5; + for(i=0; i-aXformType[i].rLimit && rM += (int)r; + x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; + p->Y += x; + p->M -= x*12; + p->validJD = 0; + r -= (int)r; + break; + } + case 2: { /* Special processing to add years */ + int y = (int)r; + computeYMD_HMS(p); + p->Y += y; + p->validJD = 0; + r -= (int)r; + break; + } + } + computeJD(p); + p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder); + rc = 0; + break; + } + } + clearYMD_HMS_TZ(p); + break; + } + default: { + break; + } + } + return rc; +} + +/* +** Process time function arguments. argv[0] is a date-time stamp. +** argv[1] and following are modifiers. Parse them all and write +** the resulting time into the DateTime structure p. Return 0 +** on success and 1 if there are any errors. +** +** If there are zero parameters (if even argv[0] is undefined) +** then assume a default value of "now" for argv[0]. +*/ +static int isDate( + sqlite3_context *context, + int argc, + sqlite3_value **argv, + DateTime *p +){ + int i, n; + const unsigned char *z; + int eType; + memset(p, 0, sizeof(*p)); + if( argc==0 ){ + return setDateTimeToCurrent(context, p); + } + if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT + || eType==SQLITE_INTEGER ){ + setRawDateNumber(p, sqlite3_value_double(argv[0])); + }else{ + z = sqlite3_value_text(argv[0]); + if( !z || parseDateOrTime(context, (char*)z, p) ){ + return 1; + } + } + for(i=1; iisError || !validJulianDay(p->iJD) ) return 1; + return 0; +} + + +/* +** The following routines implement the various date and time functions +** of SQLite. +*/ + +/* +** julianday( TIMESTRING, MOD, MOD, ...) +** +** Return the julian day number of the date specified in the arguments +*/ +static void juliandayFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + DateTime x; + if( isDate(context, argc, argv, &x)==0 ){ + computeJD(&x); + sqlite3_result_double(context, x.iJD/86400000.0); + } +} + +/* +** datetime( TIMESTRING, MOD, MOD, ...) +** +** Return YYYY-MM-DD HH:MM:SS +*/ +static void datetimeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + DateTime x; + if( isDate(context, argc, argv, &x)==0 ){ + char zBuf[100]; + computeYMD_HMS(&x); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", + x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + } +} + +/* +** time( TIMESTRING, MOD, MOD, ...) +** +** Return HH:MM:SS +*/ +static void timeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + DateTime x; + if( isDate(context, argc, argv, &x)==0 ){ + char zBuf[100]; + computeHMS(&x); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + } +} + +/* +** date( TIMESTRING, MOD, MOD, ...) +** +** Return YYYY-MM-DD +*/ +static void dateFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + DateTime x; + if( isDate(context, argc, argv, &x)==0 ){ + char zBuf[100]; + computeYMD(&x); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + } +} + +/* +** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) +** +** Return a string described by FORMAT. Conversions as follows: +** +** %d day of month +** %f ** fractional seconds SS.SSS +** %H hour 00-24 +** %j day of year 000-366 +** %J ** julian day number +** %m month 01-12 +** %M minute 00-59 +** %s seconds since 1970-01-01 +** %S seconds 00-59 +** %w day of week 0-6 sunday==0 +** %W week of year 00-53 +** %Y year 0000-9999 +** %% % +*/ +static void strftimeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + DateTime x; + u64 n; + size_t i,j; + char *z; + sqlite3 *db; + const char *zFmt; + char zBuf[100]; + if( argc==0 ) return; + zFmt = (const char*)sqlite3_value_text(argv[0]); + if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; + db = sqlite3_context_db_handle(context); + for(i=0, n=1; zFmt[i]; i++, n++){ + if( zFmt[i]=='%' ){ + switch( zFmt[i+1] ){ + case 'd': + case 'H': + case 'm': + case 'M': + case 'S': + case 'W': + n++; + /* fall thru */ + case 'w': + case '%': + break; + case 'f': + n += 8; + break; + case 'j': + n += 3; + break; + case 'Y': + n += 8; + break; + case 's': + case 'J': + n += 50; + break; + default: + return; /* ERROR. return a NULL */ + } + i++; + } + } + testcase( n==sizeof(zBuf)-1 ); + testcase( n==sizeof(zBuf) ); + testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); + testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ); + if( n(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + sqlite3_result_error_toobig(context); + return; + }else{ + z = sqlite3DbMallocRawNN(db, (int)n); + if( z==0 ){ + sqlite3_result_error_nomem(context); + return; + } + } + computeJD(&x); + computeYMD_HMS(&x); + for(i=j=0; zFmt[i]; i++){ + if( zFmt[i]!='%' ){ + z[j++] = zFmt[i]; + }else{ + i++; + switch( zFmt[i] ){ + case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; + case 'f': { + double s = x.s; + if( s>59.999 ) s = 59.999; + sqlite3_snprintf(7, &z[j],"%06.3f", s); + j += sqlite3Strlen30(&z[j]); + break; + } + case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; + case 'W': /* Fall thru */ + case 'j': { + int nDay; /* Number of days since 1st day of year */ + DateTime y = x; + y.validJD = 0; + y.M = 1; + y.D = 1; + computeJD(&y); + nDay = (int)((x.iJD-y.iJD+43200000)/86400000); + if( zFmt[i]=='W' ){ + int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ + wd = (int)(((x.iJD+43200000)/86400000)%7); + sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); + j += 2; + }else{ + sqlite3_snprintf(4, &z[j],"%03d",nDay+1); + j += 3; + } + break; + } + case 'J': { + sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); + j+=sqlite3Strlen30(&z[j]); + break; + } + case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; + case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; + case 's': { + sqlite3_snprintf(30,&z[j],"%lld", + (i64)(x.iJD/1000 - 21086676*(i64)10000)); + j += sqlite3Strlen30(&z[j]); + break; + } + case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; + case 'w': { + z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; + break; + } + case 'Y': { + sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); + break; + } + default: z[j++] = '%'; break; + } + } + } + z[j] = 0; + sqlite3_result_text(context, z, -1, + z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC); +} + +/* +** current_time() +** +** This function returns the same value as time('now'). +*/ +static void ctimeFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **NotUsed2 +){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + timeFunc(context, 0, 0); +} + +/* +** current_date() +** +** This function returns the same value as date('now'). +*/ +static void cdateFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **NotUsed2 +){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + dateFunc(context, 0, 0); +} + +/* +** current_timestamp() +** +** This function returns the same value as datetime('now'). +*/ +static void ctimestampFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **NotUsed2 +){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + datetimeFunc(context, 0, 0); +} +#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */ + +#ifdef SQLITE_OMIT_DATETIME_FUNCS +/* +** If the library is compiled to omit the full-scale date and time +** handling (to get a smaller binary), the following minimal version +** of the functions current_time(), current_date() and current_timestamp() +** are included instead. This is to support column declarations that +** include "DEFAULT CURRENT_TIME" etc. +** +** This function uses the C-library functions time(), gmtime() +** and strftime(). The format string to pass to strftime() is supplied +** as the user-data for the function. +*/ +static void currentTimeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + time_t t; + char *zFormat = (char *)sqlite3_user_data(context); + sqlite3_int64 iT; + struct tm *pTm; + struct tm sNow; + char zBuf[20]; + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + + iT = sqlite3StmtCurrentTime(context); + if( iT<=0 ) return; + t = iT/1000 - 10000*(sqlite3_int64)21086676; +#if HAVE_GMTIME_R + pTm = gmtime_r(&t, &sNow); +#else + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); + pTm = gmtime(&t); + if( pTm ) memcpy(&sNow, pTm, sizeof(sNow)); + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); +#endif + if( pTm ){ + strftime(zBuf, 20, zFormat, &sNow); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + } +} +#endif + +/* +** This function registered all of the above C functions as SQL +** functions. This should be the only routine in this file with +** external linkage. +*/ +SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){ + static FuncDef aDateTimeFuncs[] = { +#ifndef SQLITE_OMIT_DATETIME_FUNCS + DFUNCTION(julianday, -1, 0, 0, juliandayFunc ), + DFUNCTION(date, -1, 0, 0, dateFunc ), + DFUNCTION(time, -1, 0, 0, timeFunc ), + DFUNCTION(datetime, -1, 0, 0, datetimeFunc ), + DFUNCTION(strftime, -1, 0, 0, strftimeFunc ), + DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), + DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), + DFUNCTION(current_date, 0, 0, 0, cdateFunc ), +#else + STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc), + STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc), + STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc), +#endif + }; + sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs)); +} + +/************** End of date.c ************************************************/ +/************** Begin file os.c **********************************************/ +/* +** 2005 November 29 +** +** 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 OS interface code that is common to all +** architectures. +*/ +/* #include "sqliteInt.h" */ + +/* +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. +*/ +#if defined(SQLITE_TEST) +SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */ +SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */ +SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */ +SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */ +SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */ +SQLITE_API int sqlite3_diskfull_pending = 0; +SQLITE_API int sqlite3_diskfull = 0; +#endif /* defined(SQLITE_TEST) */ + +/* +** When testing, also keep a count of the number of open files. +*/ +#if defined(SQLITE_TEST) +SQLITE_API int sqlite3_open_file_count = 0; +#endif /* defined(SQLITE_TEST) */ + +/* +** The default SQLite sqlite3_vfs implementations do not allocate +** memory (actually, os_unix.c allocates a small amount of memory +** from within OsOpen()), but some third-party implementations may. +** So we test the effects of a malloc() failing and the sqlite3OsXXX() +** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro. +** +** The following functions are instrumented for malloc() failure +** testing: +** +** sqlite3OsRead() +** sqlite3OsWrite() +** sqlite3OsSync() +** sqlite3OsFileSize() +** sqlite3OsLock() +** sqlite3OsCheckReservedLock() +** sqlite3OsFileControl() +** sqlite3OsShmMap() +** sqlite3OsOpen() +** sqlite3OsDelete() +** sqlite3OsAccess() +** sqlite3OsFullPathname() +** +*/ +#if defined(SQLITE_TEST) +SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1; + #define DO_OS_MALLOC_TEST(x) \ + if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \ + void *pTstAlloc = sqlite3Malloc(10); \ + if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT; \ + sqlite3_free(pTstAlloc); \ + } +#else + #define DO_OS_MALLOC_TEST(x) +#endif + +/* +** The following routines are convenience wrappers around methods +** of the sqlite3_file object. This is mostly just syntactic sugar. All +** of this would be completely automatic if SQLite were coded using +** C++ instead of plain old C. +*/ +SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){ + if( pId->pMethods ){ + pId->pMethods->xClose(pId); + pId->pMethods = 0; + } +} +SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xRead(id, pBuf, amt, offset); +} +SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xWrite(id, pBuf, amt, offset); +} +SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){ + return id->pMethods->xTruncate(id, size); +} +SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xSync(id, flags); +} +SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xFileSize(id, pSize); +} +SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xLock(id, lockType); +} +SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){ + return id->pMethods->xUnlock(id, lockType); +} +SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xCheckReservedLock(id, pResOut); +} + +/* +** Use sqlite3OsFileControl() when we are doing something that might fail +** and we need to know about the failures. Use sqlite3OsFileControlHint() +** when simply tossing information over the wall to the VFS and we do not +** really care if the VFS receives and understands the information since it +** is only a hint and can be safely ignored. The sqlite3OsFileControlHint() +** routine has no return value since the return value would be meaningless. +*/ +SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ +#ifdef SQLITE_TEST + if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){ + /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite + ** is using a regular VFS, it is called after the corresponding + ** transaction has been committed. Injecting a fault at this point + ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM + ** but the transaction is committed anyway. + ** + ** The core must call OsFileControl() though, not OsFileControlHint(), + ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably + ** means the commit really has failed and an error should be returned + ** to the user. */ + DO_OS_MALLOC_TEST(id); + } +#endif + return id->pMethods->xFileControl(id, op, pArg); +} +SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){ + (void)id->pMethods->xFileControl(id, op, pArg); +} + +SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){ + int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; + return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); +} +SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ + return id->pMethods->xDeviceCharacteristics(id); +} +SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ + return id->pMethods->xShmLock(id, offset, n, flags); +} +SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){ + id->pMethods->xShmBarrier(id); +} +SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){ + return id->pMethods->xShmUnmap(id, deleteFlag); +} +SQLITE_PRIVATE int sqlite3OsShmMap( + sqlite3_file *id, /* Database file handle */ + int iPage, + int pgsz, + int bExtend, /* True to extend file if necessary */ + void volatile **pp /* OUT: Pointer to mapping */ +){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); +} + +#if SQLITE_MAX_MMAP_SIZE>0 +/* The real implementation of xFetch and xUnfetch */ +SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ + DO_OS_MALLOC_TEST(id); + return id->pMethods->xFetch(id, iOff, iAmt, pp); +} +SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ + return id->pMethods->xUnfetch(id, iOff, p); +} +#else +/* No-op stubs to use when memory-mapped I/O is disabled */ +SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ + *pp = 0; + return SQLITE_OK; +} +SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ + return SQLITE_OK; +} +#endif + +/* +** The next group of routines are convenience wrappers around the +** VFS methods. +*/ +SQLITE_PRIVATE int sqlite3OsOpen( + sqlite3_vfs *pVfs, + const char *zPath, + sqlite3_file *pFile, + int flags, + int *pFlagsOut +){ + int rc; + DO_OS_MALLOC_TEST(0); + /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed + ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, + ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before + ** reaching the VFS. */ + rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut); + assert( rc==SQLITE_OK || pFile->pMethods==0 ); + return rc; +} +SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + DO_OS_MALLOC_TEST(0); + assert( dirSync==0 || dirSync==1 ); + return pVfs->xDelete(pVfs, zPath, dirSync); +} +SQLITE_PRIVATE int sqlite3OsAccess( + sqlite3_vfs *pVfs, + const char *zPath, + int flags, + int *pResOut +){ + DO_OS_MALLOC_TEST(0); + return pVfs->xAccess(pVfs, zPath, flags, pResOut); +} +SQLITE_PRIVATE int sqlite3OsFullPathname( + sqlite3_vfs *pVfs, + const char *zPath, + int nPathOut, + char *zPathOut +){ + DO_OS_MALLOC_TEST(0); + zPathOut[0] = 0; + return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut); +} +#ifndef SQLITE_OMIT_LOAD_EXTENSION +SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ + return pVfs->xDlOpen(pVfs, zPath); +} +SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ + pVfs->xDlError(pVfs, nByte, zBufOut); +} +SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){ + return pVfs->xDlSym(pVfs, pHdle, zSym); +} +SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ + pVfs->xDlClose(pVfs, pHandle); +} +#endif /* SQLITE_OMIT_LOAD_EXTENSION */ +SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ + return pVfs->xRandomness(pVfs, nByte, zBufOut); +} +SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ + return pVfs->xSleep(pVfs, nMicro); +} +SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){ + return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0; +} +SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ + int rc; + /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64() + ** method to get the current date and time if that method is available + ** (if iVersion is 2 or greater and the function pointer is not NULL) and + ** will fall back to xCurrentTime() if xCurrentTimeInt64() is + ** unavailable. + */ + if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ + rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut); + }else{ + double r; + rc = pVfs->xCurrentTime(pVfs, &r); + *pTimeOut = (sqlite3_int64)(r*86400000.0); + } + return rc; +} + +SQLITE_PRIVATE int sqlite3OsOpenMalloc( + sqlite3_vfs *pVfs, + const char *zFile, + sqlite3_file **ppFile, + int flags, + int *pOutFlags +){ + int rc; + sqlite3_file *pFile; + pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); + if( pFile ){ + rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); + if( rc!=SQLITE_OK ){ + sqlite3_free(pFile); + }else{ + *ppFile = pFile; + } + }else{ + rc = SQLITE_NOMEM_BKPT; + } + return rc; +} +SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){ + assert( pFile ); + sqlite3OsClose(pFile); + sqlite3_free(pFile); +} + +/* +** This function is a wrapper around the OS specific implementation of +** sqlite3_os_init(). The purpose of the wrapper is to provide the +** ability to simulate a malloc failure, so that the handling of an +** error in sqlite3_os_init() by the upper layers can be tested. +*/ +SQLITE_PRIVATE int sqlite3OsInit(void){ + void *p = sqlite3_malloc(10); + if( p==0 ) return SQLITE_NOMEM_BKPT; + sqlite3_free(p); + return sqlite3_os_init(); +} + +/* +** The list of all registered VFS implementations. +*/ +static sqlite3_vfs * SQLITE_WSD vfsList = 0; +#define vfsList GLOBAL(sqlite3_vfs *, vfsList) + +/* +** Locate a VFS by name. If no name is given, simply return the +** first VFS on the list. +*/ +SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ + sqlite3_vfs *pVfs = 0; +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex; +#endif +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return 0; +#endif +#if SQLITE_THREADSAFE + mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif + sqlite3_mutex_enter(mutex); + for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ + if( zVfs==0 ) break; + if( strcmp(zVfs, pVfs->zName)==0 ) break; + } + sqlite3_mutex_leave(mutex); + return pVfs; +} + +/* +** Unlink a VFS from the linked list +*/ +static void vfsUnlink(sqlite3_vfs *pVfs){ + assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) ); + if( pVfs==0 ){ + /* No-op */ + }else if( vfsList==pVfs ){ + vfsList = pVfs->pNext; + }else if( vfsList ){ + sqlite3_vfs *p = vfsList; + while( p->pNext && p->pNext!=pVfs ){ + p = p->pNext; + } + if( p->pNext==pVfs ){ + p->pNext = pVfs->pNext; + } + } +} + +/* +** Register a VFS with the system. It is harmless to register the same +** VFS multiple times. The new VFS becomes the default if makeDflt is +** true. +*/ +SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ + MUTEX_LOGIC(sqlite3_mutex *mutex;) +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return rc; +#endif +#ifdef SQLITE_ENABLE_API_ARMOR + if( pVfs==0 ) return SQLITE_MISUSE_BKPT; +#endif + + MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) + sqlite3_mutex_enter(mutex); + vfsUnlink(pVfs); + if( makeDflt || vfsList==0 ){ + pVfs->pNext = vfsList; + vfsList = pVfs; + }else{ + pVfs->pNext = vfsList->pNext; + vfsList->pNext = pVfs; + } + assert(vfsList); + sqlite3_mutex_leave(mutex); + return SQLITE_OK; +} + +/* +** Unregister a VFS so that it is no longer accessible. +*/ +SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif + sqlite3_mutex_enter(mutex); + vfsUnlink(pVfs); + sqlite3_mutex_leave(mutex); + return SQLITE_OK; +} + +/************** End of os.c **************************************************/ +/************** Begin file fault.c *******************************************/ +/* +** 2008 Jan 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file contains code to support the concept of "benign" +** malloc failures (when the xMalloc() or xRealloc() method of the +** sqlite3_mem_methods structure fails to allocate a block of memory +** and returns 0). +** +** Most malloc failures are non-benign. After they occur, SQLite +** abandons the current operation and returns an error code (usually +** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily +** fatal. For example, if a malloc fails while resizing a hash table, this +** is completely recoverable simply by not carrying out the resize. The +** hash table will continue to function normally. So a malloc failure +** during a hash table resize is a benign fault. +*/ + +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_UNTESTABLE + +/* +** Global variables. +*/ +typedef struct BenignMallocHooks BenignMallocHooks; +static SQLITE_WSD struct BenignMallocHooks { + void (*xBenignBegin)(void); + void (*xBenignEnd)(void); +} sqlite3Hooks = { 0, 0 }; + +/* The "wsdHooks" macro will resolve to the appropriate BenignMallocHooks +** structure. If writable static data is unsupported on the target, +** we have to locate the state vector at run-time. In the more common +** case where writable static data is supported, wsdHooks can refer directly +** to the "sqlite3Hooks" state vector declared above. +*/ +#ifdef SQLITE_OMIT_WSD +# define wsdHooksInit \ + BenignMallocHooks *x = &GLOBAL(BenignMallocHooks,sqlite3Hooks) +# define wsdHooks x[0] +#else +# define wsdHooksInit +# define wsdHooks sqlite3Hooks +#endif + + +/* +** Register hooks to call when sqlite3BeginBenignMalloc() and +** sqlite3EndBenignMalloc() are called, respectively. +*/ +SQLITE_PRIVATE void sqlite3BenignMallocHooks( + void (*xBenignBegin)(void), + void (*xBenignEnd)(void) +){ + wsdHooksInit; + wsdHooks.xBenignBegin = xBenignBegin; + wsdHooks.xBenignEnd = xBenignEnd; +} + +/* +** This (sqlite3EndBenignMalloc()) is called by SQLite code to indicate that +** subsequent malloc failures are benign. A call to sqlite3EndBenignMalloc() +** indicates that subsequent malloc failures are non-benign. +*/ +SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){ + wsdHooksInit; + if( wsdHooks.xBenignBegin ){ + wsdHooks.xBenignBegin(); + } +} +SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){ + wsdHooksInit; + if( wsdHooks.xBenignEnd ){ + wsdHooks.xBenignEnd(); + } +} + +#endif /* #ifndef SQLITE_UNTESTABLE */ + +/************** End of fault.c ***********************************************/ +/************** Begin file mem0.c ********************************************/ +/* +** 2008 October 28 +** +** 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 a no-op memory allocation drivers for use when +** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented +** here always fail. SQLite will not operate with these drivers. These +** are merely placeholders. Real drivers must be substituted using +** sqlite3_config() before SQLite will operate. +*/ +/* #include "sqliteInt.h" */ + +/* +** This version of the memory allocator is the default. It is +** used when no other memory allocator is specified using compile-time +** macros. +*/ +#ifdef SQLITE_ZERO_MALLOC + +/* +** No-op versions of all memory allocation routines +*/ +static void *sqlite3MemMalloc(int nByte){ return 0; } +static void sqlite3MemFree(void *pPrior){ return; } +static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; } +static int sqlite3MemSize(void *pPrior){ return 0; } +static int sqlite3MemRoundup(int n){ return n; } +static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; } +static void sqlite3MemShutdown(void *NotUsed){ return; } + +/* +** This routine is the only routine in this file with external linkage. +** +** Populate the low-level memory allocation function pointers in +** sqlite3GlobalConfig.m with pointers to the routines in this file. +*/ +SQLITE_PRIVATE void sqlite3MemSetDefault(void){ + static const sqlite3_mem_methods defaultMethods = { + sqlite3MemMalloc, + sqlite3MemFree, + sqlite3MemRealloc, + sqlite3MemSize, + sqlite3MemRoundup, + sqlite3MemInit, + sqlite3MemShutdown, + 0 + }; + sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); +} + +#endif /* SQLITE_ZERO_MALLOC */ + +/************** End of mem0.c ************************************************/ +/************** Begin file mem1.c ********************************************/ +/* +** 2007 August 14 +** +** 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 low-level memory allocation drivers for when +** SQLite will use the standard C-library malloc/realloc/free interface +** to obtain the memory it needs. +** +** This file contains implementations of the low-level memory allocation +** routines specified in the sqlite3_mem_methods object. The content of +** this file is only used if SQLITE_SYSTEM_MALLOC is defined. The +** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the +** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined. The +** default configuration is to use memory allocation routines in this +** file. +** +** C-preprocessor macro summary: +** +** HAVE_MALLOC_USABLE_SIZE The configure script sets this symbol if +** the malloc_usable_size() interface exists +** on the target platform. Or, this symbol +** can be set manually, if desired. +** If an equivalent interface exists by +** a different name, using a separate -D +** option to rename it. +** +** SQLITE_WITHOUT_ZONEMALLOC Some older macs lack support for the zone +** memory allocator. Set this symbol to enable +** building on older macs. +** +** SQLITE_WITHOUT_MSIZE Set this symbol to disable the use of +** _msize() on windows systems. This might +** be necessary when compiling for Delphi, +** for example. +*/ +/* #include "sqliteInt.h" */ + +/* +** This version of the memory allocator is the default. It is +** used when no other memory allocator is specified using compile-time +** macros. +*/ +#ifdef SQLITE_SYSTEM_MALLOC +#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) + +/* +** Use the zone allocator available on apple products unless the +** SQLITE_WITHOUT_ZONEMALLOC symbol is defined. +*/ +#include +#include +#ifdef SQLITE_MIGHT_BE_SINGLE_CORE +#include +#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */ +static malloc_zone_t* _sqliteZone_; +#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) +#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); +#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y)) +#define SQLITE_MALLOCSIZE(x) \ + (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x)) + +#else /* if not __APPLE__ */ + +/* +** Use standard C library malloc and free on non-Apple systems. +** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined. +*/ +#define SQLITE_MALLOC(x) malloc(x) +#define SQLITE_FREE(x) free(x) +#define SQLITE_REALLOC(x,y) realloc((x),(y)) + +/* +** The malloc.h header file is needed for malloc_usable_size() function +** on some systems (e.g. Linux). +*/ +#if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE +# define SQLITE_USE_MALLOC_H 1 +# define SQLITE_USE_MALLOC_USABLE_SIZE 1 +/* +** The MSVCRT has malloc_usable_size(), but it is called _msize(). The +** use of _msize() is automatic, but can be disabled by compiling with +** -DSQLITE_WITHOUT_MSIZE. Using the _msize() function also requires +** the malloc.h header file. +*/ +#elif defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE) +# define SQLITE_USE_MALLOC_H +# define SQLITE_USE_MSIZE +#endif + +/* +** Include the malloc.h header file, if necessary. Also set define macro +** SQLITE_MALLOCSIZE to the appropriate function name, which is _msize() +** for MSVC and malloc_usable_size() for most other systems (e.g. Linux). +** The memory size function can always be overridden manually by defining +** the macro SQLITE_MALLOCSIZE to the desired function name. +*/ +#if defined(SQLITE_USE_MALLOC_H) +# include +# if defined(SQLITE_USE_MALLOC_USABLE_SIZE) +# if !defined(SQLITE_MALLOCSIZE) +# define SQLITE_MALLOCSIZE(x) malloc_usable_size(x) +# endif +# elif defined(SQLITE_USE_MSIZE) +# if !defined(SQLITE_MALLOCSIZE) +# define SQLITE_MALLOCSIZE _msize +# endif +# endif +#endif /* defined(SQLITE_USE_MALLOC_H) */ + +#endif /* __APPLE__ or not __APPLE__ */ + +/* +** Like malloc(), but remember the size of the allocation +** so that we can find it later using sqlite3MemSize(). +** +** For this low-level routine, we are guaranteed that nByte>0 because +** cases of nByte<=0 will be intercepted and dealt with by higher level +** routines. +*/ +static void *sqlite3MemMalloc(int nByte){ +#ifdef SQLITE_MALLOCSIZE + void *p; + testcase( ROUND8(nByte)==nByte ); + p = SQLITE_MALLOC( nByte ); + if( p==0 ){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); + } + return p; +#else + sqlite3_int64 *p; + assert( nByte>0 ); + testcase( ROUND8(nByte)!=nByte ); + p = SQLITE_MALLOC( nByte+8 ); + if( p ){ + p[0] = nByte; + p++; + }else{ + testcase( sqlite3GlobalConfig.xLog!=0 ); + sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); + } + return (void *)p; +#endif +} + +/* +** Like free() but works for allocations obtained from sqlite3MemMalloc() +** or sqlite3MemRealloc(). +** +** For this low-level routine, we already know that pPrior!=0 since +** cases where pPrior==0 will have been intecepted and dealt with +** by higher-level routines. +*/ +static void sqlite3MemFree(void *pPrior){ +#ifdef SQLITE_MALLOCSIZE + SQLITE_FREE(pPrior); +#else + sqlite3_int64 *p = (sqlite3_int64*)pPrior; + assert( pPrior!=0 ); + p--; + SQLITE_FREE(p); +#endif +} + +/* +** Report the allocated size of a prior return from xMalloc() +** or xRealloc(). +*/ +static int sqlite3MemSize(void *pPrior){ +#ifdef SQLITE_MALLOCSIZE + assert( pPrior!=0 ); + return (int)SQLITE_MALLOCSIZE(pPrior); +#else + sqlite3_int64 *p; + assert( pPrior!=0 ); + p = (sqlite3_int64*)pPrior; + p--; + return (int)p[0]; +#endif +} + +/* +** Like realloc(). Resize an allocation previously obtained from +** sqlite3MemMalloc(). +** +** For this low-level interface, we know that pPrior!=0. Cases where +** pPrior==0 while have been intercepted by higher-level routine and +** redirected to xMalloc. Similarly, we know that nByte>0 because +** cases where nByte<=0 will have been intercepted by higher-level +** routines and redirected to xFree. +*/ +static void *sqlite3MemRealloc(void *pPrior, int nByte){ +#ifdef SQLITE_MALLOCSIZE + void *p = SQLITE_REALLOC(pPrior, nByte); + if( p==0 ){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + sqlite3_log(SQLITE_NOMEM, + "failed memory resize %u to %u bytes", + SQLITE_MALLOCSIZE(pPrior), nByte); + } + return p; +#else + sqlite3_int64 *p = (sqlite3_int64*)pPrior; + assert( pPrior!=0 && nByte>0 ); + assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */ + p--; + p = SQLITE_REALLOC(p, nByte+8 ); + if( p ){ + p[0] = nByte; + p++; + }else{ + testcase( sqlite3GlobalConfig.xLog!=0 ); + sqlite3_log(SQLITE_NOMEM, + "failed memory resize %u to %u bytes", + sqlite3MemSize(pPrior), nByte); + } + return (void*)p; +#endif +} + +/* +** Round up a request size to the next valid allocation size. +*/ +static int sqlite3MemRoundup(int n){ + return ROUND8(n); +} + +/* +** Initialize this module. +*/ +static int sqlite3MemInit(void *NotUsed){ +#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) + int cpuCount; + size_t len; + if( _sqliteZone_ ){ + return SQLITE_OK; + } + len = sizeof(cpuCount); + /* One usually wants to use hw.acctivecpu for MT decisions, but not here */ + sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0); + if( cpuCount>1 ){ + /* defer MT decisions to system malloc */ + _sqliteZone_ = malloc_default_zone(); + }else{ + /* only 1 core, use our own zone to contention over global locks, + ** e.g. we have our own dedicated locks */ + _sqliteZone_ = malloc_create_zone(4096, 0); + malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap"); + } +#endif /* defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */ + UNUSED_PARAMETER(NotUsed); + return SQLITE_OK; +} + +/* +** Deinitialize this module. +*/ +static void sqlite3MemShutdown(void *NotUsed){ + UNUSED_PARAMETER(NotUsed); + return; +} + +/* +** This routine is the only routine in this file with external linkage. +** +** Populate the low-level memory allocation function pointers in +** sqlite3GlobalConfig.m with pointers to the routines in this file. +*/ +SQLITE_PRIVATE void sqlite3MemSetDefault(void){ + static const sqlite3_mem_methods defaultMethods = { + sqlite3MemMalloc, + sqlite3MemFree, + sqlite3MemRealloc, + sqlite3MemSize, + sqlite3MemRoundup, + sqlite3MemInit, + sqlite3MemShutdown, + 0 + }; + sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); +} + +#endif /* SQLITE_SYSTEM_MALLOC */ + +/************** End of mem1.c ************************************************/ +/************** Begin file mem2.c ********************************************/ +/* +** 2007 August 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 low-level memory allocation drivers for when +** SQLite will use the standard C-library malloc/realloc/free interface +** to obtain the memory it needs while adding lots of additional debugging +** information to each allocation in order to help detect and fix memory +** leaks and memory usage errors. +** +** This file contains implementations of the low-level memory allocation +** routines specified in the sqlite3_mem_methods object. +*/ +/* #include "sqliteInt.h" */ + +/* +** This version of the memory allocator is used only if the +** SQLITE_MEMDEBUG macro is defined +*/ +#ifdef SQLITE_MEMDEBUG + +/* +** The backtrace functionality is only available with GLIBC +*/ +#ifdef __GLIBC__ + extern int backtrace(void**,int); + extern void backtrace_symbols_fd(void*const*,int,int); +#else +# define backtrace(A,B) 1 +# define backtrace_symbols_fd(A,B,C) +#endif +/* #include */ + +/* +** Each memory allocation looks like this: +** +** ------------------------------------------------------------------------ +** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | +** ------------------------------------------------------------------------ +** +** The application code sees only a pointer to the allocation. We have +** to back up from the allocation pointer to find the MemBlockHdr. The +** MemBlockHdr tells us the size of the allocation and the number of +** backtrace pointers. There is also a guard word at the end of the +** MemBlockHdr. +*/ +struct MemBlockHdr { + i64 iSize; /* Size of this allocation */ + struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ + char nBacktrace; /* Number of backtraces on this alloc */ + char nBacktraceSlots; /* Available backtrace slots */ + u8 nTitle; /* Bytes of title; includes '\0' */ + u8 eType; /* Allocation type code */ + int iForeGuard; /* Guard word for sanity */ +}; + +/* +** Guard words +*/ +#define FOREGUARD 0x80F5E153 +#define REARGUARD 0xE4676B53 + +/* +** Number of malloc size increments to track. +*/ +#define NCSIZE 1000 + +/* +** All of the static variables used by this module are collected +** into a single structure named "mem". This is to keep the +** static variables organized and to reduce namespace pollution +** when this module is combined with other in the amalgamation. +*/ +static struct { + + /* + ** Mutex to control access to the memory allocation subsystem. + */ + sqlite3_mutex *mutex; + + /* + ** Head and tail of a linked list of all outstanding allocations + */ + struct MemBlockHdr *pFirst; + struct MemBlockHdr *pLast; + + /* + ** The number of levels of backtrace to save in new allocations. + */ + int nBacktrace; + void (*xBacktrace)(int, int, void **); + + /* + ** Title text to insert in front of each block + */ + int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ + char zTitle[100]; /* The title text */ + + /* + ** sqlite3MallocDisallow() increments the following counter. + ** sqlite3MallocAllow() decrements it. + */ + int disallow; /* Do not allow memory allocation */ + + /* + ** Gather statistics on the sizes of memory allocations. + ** nAlloc[i] is the number of allocation attempts of i*8 + ** bytes. i==NCSIZE is the number of allocation attempts for + ** sizes more than NCSIZE*8 bytes. + */ + int nAlloc[NCSIZE]; /* Total number of allocations */ + int nCurrent[NCSIZE]; /* Current number of allocations */ + int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */ + +} mem; + + +/* +** Adjust memory usage statistics +*/ +static void adjustStats(int iSize, int increment){ + int i = ROUND8(iSize)/8; + if( i>NCSIZE-1 ){ + i = NCSIZE - 1; + } + if( increment>0 ){ + mem.nAlloc[i]++; + mem.nCurrent[i]++; + if( mem.nCurrent[i]>mem.mxCurrent[i] ){ + mem.mxCurrent[i] = mem.nCurrent[i]; + } + }else{ + mem.nCurrent[i]--; + assert( mem.nCurrent[i]>=0 ); + } +} + +/* +** Given an allocation, find the MemBlockHdr for that allocation. +** +** This routine checks the guards at either end of the allocation and +** if they are incorrect it asserts. +*/ +static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ + struct MemBlockHdr *p; + int *pInt; + u8 *pU8; + int nReserve; + + p = (struct MemBlockHdr*)pAllocation; + p--; + assert( p->iForeGuard==(int)FOREGUARD ); + nReserve = ROUND8(p->iSize); + pInt = (int*)pAllocation; + pU8 = (u8*)pAllocation; + assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD ); + /* This checks any of the "extra" bytes allocated due + ** to rounding up to an 8 byte boundary to ensure + ** they haven't been overwritten. + */ + while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 ); + return p; +} + +/* +** Return the number of bytes currently allocated at address p. +*/ +static int sqlite3MemSize(void *p){ + struct MemBlockHdr *pHdr; + if( !p ){ + return 0; + } + pHdr = sqlite3MemsysGetHeader(p); + return (int)pHdr->iSize; +} + +/* +** Initialize the memory allocation subsystem. +*/ +static int sqlite3MemInit(void *NotUsed){ + UNUSED_PARAMETER(NotUsed); + assert( (sizeof(struct MemBlockHdr)&7) == 0 ); + if( !sqlite3GlobalConfig.bMemstat ){ + /* If memory status is enabled, then the malloc.c wrapper will already + ** hold the STATIC_MEM mutex when the routines here are invoked. */ + mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); + } + return SQLITE_OK; +} + +/* +** Deinitialize the memory allocation subsystem. +*/ +static void sqlite3MemShutdown(void *NotUsed){ + UNUSED_PARAMETER(NotUsed); + mem.mutex = 0; +} + +/* +** Round up a request size to the next valid allocation size. +*/ +static int sqlite3MemRoundup(int n){ + return ROUND8(n); +} + +/* +** Fill a buffer with pseudo-random bytes. This is used to preset +** the content of a new memory allocation to unpredictable values and +** to clear the content of a freed allocation to unpredictable values. +*/ +static void randomFill(char *pBuf, int nByte){ + unsigned int x, y, r; + x = SQLITE_PTR_TO_INT(pBuf); + y = nByte | 1; + while( nByte >= 4 ){ + x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); + y = y*1103515245 + 12345; + r = x ^ y; + *(int*)pBuf = r; + pBuf += 4; + nByte -= 4; + } + while( nByte-- > 0 ){ + x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); + y = y*1103515245 + 12345; + r = x ^ y; + *(pBuf++) = r & 0xff; + } +} + +/* +** Allocate nByte bytes of memory. +*/ +static void *sqlite3MemMalloc(int nByte){ + struct MemBlockHdr *pHdr; + void **pBt; + char *z; + int *pInt; + void *p = 0; + int totalSize; + int nReserve; + sqlite3_mutex_enter(mem.mutex); + assert( mem.disallow==0 ); + nReserve = ROUND8(nByte); + totalSize = nReserve + sizeof(*pHdr) + sizeof(int) + + mem.nBacktrace*sizeof(void*) + mem.nTitle; + p = malloc(totalSize); + if( p ){ + z = p; + pBt = (void**)&z[mem.nTitle]; + pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; + pHdr->pNext = 0; + pHdr->pPrev = mem.pLast; + if( mem.pLast ){ + mem.pLast->pNext = pHdr; + }else{ + mem.pFirst = pHdr; + } + mem.pLast = pHdr; + pHdr->iForeGuard = FOREGUARD; + pHdr->eType = MEMTYPE_HEAP; + pHdr->nBacktraceSlots = mem.nBacktrace; + pHdr->nTitle = mem.nTitle; + if( mem.nBacktrace ){ + void *aAddr[40]; + pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; + memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); + assert(pBt[0]); + if( mem.xBacktrace ){ + mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]); + } + }else{ + pHdr->nBacktrace = 0; + } + if( mem.nTitle ){ + memcpy(z, mem.zTitle, mem.nTitle); + } + pHdr->iSize = nByte; + adjustStats(nByte, +1); + pInt = (int*)&pHdr[1]; + pInt[nReserve/sizeof(int)] = REARGUARD; + randomFill((char*)pInt, nByte); + memset(((char*)pInt)+nByte, 0x65, nReserve-nByte); + p = (void*)pInt; + } + sqlite3_mutex_leave(mem.mutex); + return p; +} + +/* +** Free memory. +*/ +static void sqlite3MemFree(void *pPrior){ + struct MemBlockHdr *pHdr; + void **pBt; + char *z; + assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0 + || mem.mutex!=0 ); + pHdr = sqlite3MemsysGetHeader(pPrior); + pBt = (void**)pHdr; + pBt -= pHdr->nBacktraceSlots; + sqlite3_mutex_enter(mem.mutex); + if( pHdr->pPrev ){ + assert( pHdr->pPrev->pNext==pHdr ); + pHdr->pPrev->pNext = pHdr->pNext; + }else{ + assert( mem.pFirst==pHdr ); + mem.pFirst = pHdr->pNext; + } + if( pHdr->pNext ){ + assert( pHdr->pNext->pPrev==pHdr ); + pHdr->pNext->pPrev = pHdr->pPrev; + }else{ + assert( mem.pLast==pHdr ); + mem.pLast = pHdr->pPrev; + } + z = (char*)pBt; + z -= pHdr->nTitle; + adjustStats((int)pHdr->iSize, -1); + randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + + (int)pHdr->iSize + sizeof(int) + pHdr->nTitle); + free(z); + sqlite3_mutex_leave(mem.mutex); +} + +/* +** Change the size of an existing memory allocation. +** +** For this debugging implementation, we *always* make a copy of the +** allocation into a new place in memory. In this way, if the +** higher level code is using pointer to the old allocation, it is +** much more likely to break and we are much more liking to find +** the error. +*/ +static void *sqlite3MemRealloc(void *pPrior, int nByte){ + struct MemBlockHdr *pOldHdr; + void *pNew; + assert( mem.disallow==0 ); + assert( (nByte & 7)==0 ); /* EV: R-46199-30249 */ + pOldHdr = sqlite3MemsysGetHeader(pPrior); + pNew = sqlite3MemMalloc(nByte); + if( pNew ){ + memcpy(pNew, pPrior, (int)(nByteiSize ? nByte : pOldHdr->iSize)); + if( nByte>pOldHdr->iSize ){ + randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - (int)pOldHdr->iSize); + } + sqlite3MemFree(pPrior); + } + return pNew; +} + +/* +** Populate the low-level memory allocation function pointers in +** sqlite3GlobalConfig.m with pointers to the routines in this file. +*/ +SQLITE_PRIVATE void sqlite3MemSetDefault(void){ + static const sqlite3_mem_methods defaultMethods = { + sqlite3MemMalloc, + sqlite3MemFree, + sqlite3MemRealloc, + sqlite3MemSize, + sqlite3MemRoundup, + sqlite3MemInit, + sqlite3MemShutdown, + 0 + }; + sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); +} + +/* +** Set the "type" of an allocation. +*/ +SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){ + if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ + struct MemBlockHdr *pHdr; + pHdr = sqlite3MemsysGetHeader(p); + assert( pHdr->iForeGuard==FOREGUARD ); + pHdr->eType = eType; + } +} + +/* +** Return TRUE if the mask of type in eType matches the type of the +** allocation p. Also return true if p==NULL. +** +** This routine is designed for use within an assert() statement, to +** verify the type of an allocation. For example: +** +** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); +*/ +SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ + int rc = 1; + if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ + struct MemBlockHdr *pHdr; + pHdr = sqlite3MemsysGetHeader(p); + assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ + if( (pHdr->eType&eType)==0 ){ + rc = 0; + } + } + return rc; +} + +/* +** Return TRUE if the mask of type in eType matches no bits of the type of the +** allocation p. Also return true if p==NULL. +** +** This routine is designed for use within an assert() statement, to +** verify the type of an allocation. For example: +** +** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); +*/ +SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){ + int rc = 1; + if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ + struct MemBlockHdr *pHdr; + pHdr = sqlite3MemsysGetHeader(p); + assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ + if( (pHdr->eType&eType)!=0 ){ + rc = 0; + } + } + return rc; +} + +/* +** Set the number of backtrace levels kept for each allocation. +** A value of zero turns off backtracing. The number is always rounded +** up to a multiple of 2. +*/ +SQLITE_PRIVATE void sqlite3MemdebugBacktrace(int depth){ + if( depth<0 ){ depth = 0; } + if( depth>20 ){ depth = 20; } + depth = (depth+1)&0xfe; + mem.nBacktrace = depth; +} + +SQLITE_PRIVATE void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){ + mem.xBacktrace = xBacktrace; +} + +/* +** Set the title string for subsequent allocations. +*/ +SQLITE_PRIVATE void sqlite3MemdebugSettitle(const char *zTitle){ + unsigned int n = sqlite3Strlen30(zTitle) + 1; + sqlite3_mutex_enter(mem.mutex); + if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; + memcpy(mem.zTitle, zTitle, n); + mem.zTitle[n] = 0; + mem.nTitle = ROUND8(n); + sqlite3_mutex_leave(mem.mutex); +} + +SQLITE_PRIVATE void sqlite3MemdebugSync(){ + struct MemBlockHdr *pHdr; + for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ + void **pBt = (void**)pHdr; + pBt -= pHdr->nBacktraceSlots; + mem.xBacktrace((int)pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]); + } +} + +/* +** Open the file indicated and write a log of all unfreed memory +** allocations into that log. +*/ +SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){ + FILE *out; + struct MemBlockHdr *pHdr; + void **pBt; + int i; + out = fopen(zFilename, "w"); + if( out==0 ){ + fprintf(stderr, "** Unable to output memory debug output log: %s **\n", + zFilename); + return; + } + for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ + char *z = (char*)pHdr; + z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; + fprintf(out, "**** %lld bytes at %p from %s ****\n", + pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); + if( pHdr->nBacktrace ){ + fflush(out); + pBt = (void**)pHdr; + pBt -= pHdr->nBacktraceSlots; + backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); + fprintf(out, "\n"); + } + } + fprintf(out, "COUNTS:\n"); + for(i=0; i=1 ); + size = mem3.aPool[i-1].u.hdr.size4x/4; + assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); + assert( size>=2 ); + if( size <= MX_SMALL ){ + memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]); + }else{ + hash = size % N_HASH; + memsys3UnlinkFromList(i, &mem3.aiHash[hash]); + } +} + +/* +** Link the chunk at mem3.aPool[i] so that is on the list rooted +** at *pRoot. +*/ +static void memsys3LinkIntoList(u32 i, u32 *pRoot){ + assert( sqlite3_mutex_held(mem3.mutex) ); + mem3.aPool[i].u.list.next = *pRoot; + mem3.aPool[i].u.list.prev = 0; + if( *pRoot ){ + mem3.aPool[*pRoot].u.list.prev = i; + } + *pRoot = i; +} + +/* +** Link the chunk at index i into either the appropriate +** small chunk list, or into the large chunk hash table. +*/ +static void memsys3Link(u32 i){ + u32 size, hash; + assert( sqlite3_mutex_held(mem3.mutex) ); + assert( i>=1 ); + assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 ); + size = mem3.aPool[i-1].u.hdr.size4x/4; + assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); + assert( size>=2 ); + if( size <= MX_SMALL ){ + memsys3LinkIntoList(i, &mem3.aiSmall[size-2]); + }else{ + hash = size % N_HASH; + memsys3LinkIntoList(i, &mem3.aiHash[hash]); + } +} + +/* +** If the STATIC_MEM mutex is not already held, obtain it now. The mutex +** will already be held (obtained by code in malloc.c) if +** sqlite3GlobalConfig.bMemStat is true. +*/ +static void memsys3Enter(void){ + if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){ + mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); + } + sqlite3_mutex_enter(mem3.mutex); +} +static void memsys3Leave(void){ + sqlite3_mutex_leave(mem3.mutex); +} + +/* +** Called when we are unable to satisfy an allocation of nBytes. +*/ +static void memsys3OutOfMemory(int nByte){ + if( !mem3.alarmBusy ){ + mem3.alarmBusy = 1; + assert( sqlite3_mutex_held(mem3.mutex) ); + sqlite3_mutex_leave(mem3.mutex); + sqlite3_release_memory(nByte); + sqlite3_mutex_enter(mem3.mutex); + mem3.alarmBusy = 0; + } +} + + +/* +** Chunk i is a free chunk that has been unlinked. Adjust its +** size parameters for check-out and return a pointer to the +** user portion of the chunk. +*/ +static void *memsys3Checkout(u32 i, u32 nBlock){ + u32 x; + assert( sqlite3_mutex_held(mem3.mutex) ); + assert( i>=1 ); + assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ); + assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock ); + x = mem3.aPool[i-1].u.hdr.size4x; + mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); + mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; + mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2; + return &mem3.aPool[i]; +} + +/* +** Carve a piece off of the end of the mem3.iMaster free chunk. +** Return a pointer to the new allocation. Or, if the master chunk +** is not large enough, return 0. +*/ +static void *memsys3FromMaster(u32 nBlock){ + assert( sqlite3_mutex_held(mem3.mutex) ); + assert( mem3.szMaster>=nBlock ); + if( nBlock>=mem3.szMaster-1 ){ + /* Use the entire master */ + void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster); + mem3.iMaster = 0; + mem3.szMaster = 0; + mem3.mnMaster = 0; + return p; + }else{ + /* Split the master block. Return the tail. */ + u32 newi, x; + newi = mem3.iMaster + mem3.szMaster - nBlock; + assert( newi > mem3.iMaster+1 ); + mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock; + mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2; + mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; + mem3.szMaster -= nBlock; + mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster; + x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; + mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; + if( mem3.szMaster < mem3.mnMaster ){ + mem3.mnMaster = mem3.szMaster; + } + return (void*)&mem3.aPool[newi]; + } +} + +/* +** *pRoot is the head of a list of free chunks of the same size +** or same size hash. In other words, *pRoot is an entry in either +** mem3.aiSmall[] or mem3.aiHash[]. +** +** This routine examines all entries on the given list and tries +** to coalesce each entries with adjacent free chunks. +** +** If it sees a chunk that is larger than mem3.iMaster, it replaces +** the current mem3.iMaster with the new larger chunk. In order for +** this mem3.iMaster replacement to work, the master chunk must be +** linked into the hash tables. That is not the normal state of +** affairs, of course. The calling routine must link the master +** chunk before invoking this routine, then must unlink the (possibly +** changed) master chunk once this routine has finished. +*/ +static void memsys3Merge(u32 *pRoot){ + u32 iNext, prev, size, i, x; + + assert( sqlite3_mutex_held(mem3.mutex) ); + for(i=*pRoot; i>0; i=iNext){ + iNext = mem3.aPool[i].u.list.next; + size = mem3.aPool[i-1].u.hdr.size4x; + assert( (size&1)==0 ); + if( (size&2)==0 ){ + memsys3UnlinkFromList(i, pRoot); + assert( i > mem3.aPool[i-1].u.hdr.prevSize ); + prev = i - mem3.aPool[i-1].u.hdr.prevSize; + if( prev==iNext ){ + iNext = mem3.aPool[prev].u.list.next; + } + memsys3Unlink(prev); + size = i + size/4 - prev; + x = mem3.aPool[prev-1].u.hdr.size4x & 2; + mem3.aPool[prev-1].u.hdr.size4x = size*4 | x; + mem3.aPool[prev+size-1].u.hdr.prevSize = size; + memsys3Link(prev); + i = prev; + }else{ + size /= 4; + } + if( size>mem3.szMaster ){ + mem3.iMaster = i; + mem3.szMaster = size; + } + } +} + +/* +** Return a block of memory of at least nBytes in size. +** Return NULL if unable. +** +** This function assumes that the necessary mutexes, if any, are +** already held by the caller. Hence "Unsafe". +*/ +static void *memsys3MallocUnsafe(int nByte){ + u32 i; + u32 nBlock; + u32 toFree; + + assert( sqlite3_mutex_held(mem3.mutex) ); + assert( sizeof(Mem3Block)==8 ); + if( nByte<=12 ){ + nBlock = 2; + }else{ + nBlock = (nByte + 11)/8; + } + assert( nBlock>=2 ); + + /* STEP 1: + ** Look for an entry of the correct size in either the small + ** chunk table or in the large chunk hash table. This is + ** successful most of the time (about 9 times out of 10). + */ + if( nBlock <= MX_SMALL ){ + i = mem3.aiSmall[nBlock-2]; + if( i>0 ){ + memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]); + return memsys3Checkout(i, nBlock); + } + }else{ + int hash = nBlock % N_HASH; + for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){ + if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){ + memsys3UnlinkFromList(i, &mem3.aiHash[hash]); + return memsys3Checkout(i, nBlock); + } + } + } + + /* STEP 2: + ** Try to satisfy the allocation by carving a piece off of the end + ** of the master chunk. This step usually works if step 1 fails. + */ + if( mem3.szMaster>=nBlock ){ + return memsys3FromMaster(nBlock); + } + + + /* STEP 3: + ** Loop through the entire memory pool. Coalesce adjacent free + ** chunks. Recompute the master chunk as the largest free chunk. + ** Then try again to satisfy the allocation by carving a piece off + ** of the end of the master chunk. This step happens very + ** rarely (we hope!) + */ + for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){ + memsys3OutOfMemory(toFree); + if( mem3.iMaster ){ + memsys3Link(mem3.iMaster); + mem3.iMaster = 0; + mem3.szMaster = 0; + } + for(i=0; i=nBlock ){ + return memsys3FromMaster(nBlock); + } + } + } + + /* If none of the above worked, then we fail. */ + return 0; +} + +/* +** Free an outstanding memory allocation. +** +** This function assumes that the necessary mutexes, if any, are +** already held by the caller. Hence "Unsafe". +*/ +static void memsys3FreeUnsafe(void *pOld){ + Mem3Block *p = (Mem3Block*)pOld; + int i; + u32 size, x; + assert( sqlite3_mutex_held(mem3.mutex) ); + assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] ); + i = p - mem3.aPool; + assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 ); + size = mem3.aPool[i-1].u.hdr.size4x/4; + assert( i+size<=mem3.nPool+1 ); + mem3.aPool[i-1].u.hdr.size4x &= ~1; + mem3.aPool[i+size-1].u.hdr.prevSize = size; + mem3.aPool[i+size-1].u.hdr.size4x &= ~2; + memsys3Link(i); + + /* Try to expand the master using the newly freed chunk */ + if( mem3.iMaster ){ + while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){ + size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize; + mem3.iMaster -= size; + mem3.szMaster += size; + memsys3Unlink(mem3.iMaster); + x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; + mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; + mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; + } + x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; + while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){ + memsys3Unlink(mem3.iMaster+mem3.szMaster); + mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4; + mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; + mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; + } + } +} + +/* +** Return the size of an outstanding allocation, in bytes. The +** size returned omits the 8-byte header overhead. This only +** works for chunks that are currently checked out. +*/ +static int memsys3Size(void *p){ + Mem3Block *pBlock; + assert( p!=0 ); + pBlock = (Mem3Block*)p; + assert( (pBlock[-1].u.hdr.size4x&1)!=0 ); + return (pBlock[-1].u.hdr.size4x&~3)*2 - 4; +} + +/* +** Round up a request size to the next valid allocation size. +*/ +static int memsys3Roundup(int n){ + if( n<=12 ){ + return 12; + }else{ + return ((n+11)&~7) - 4; + } +} + +/* +** Allocate nBytes of memory. +*/ +static void *memsys3Malloc(int nBytes){ + sqlite3_int64 *p; + assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */ + memsys3Enter(); + p = memsys3MallocUnsafe(nBytes); + memsys3Leave(); + return (void*)p; +} + +/* +** Free memory. +*/ +static void memsys3Free(void *pPrior){ + assert( pPrior ); + memsys3Enter(); + memsys3FreeUnsafe(pPrior); + memsys3Leave(); +} + +/* +** Change the size of an existing memory allocation +*/ +static void *memsys3Realloc(void *pPrior, int nBytes){ + int nOld; + void *p; + if( pPrior==0 ){ + return sqlite3_malloc(nBytes); + } + if( nBytes<=0 ){ + sqlite3_free(pPrior); + return 0; + } + nOld = memsys3Size(pPrior); + if( nBytes<=nOld && nBytes>=nOld-128 ){ + return pPrior; + } + memsys3Enter(); + p = memsys3MallocUnsafe(nBytes); + if( p ){ + if( nOld>1)!=(size&1) ){ + fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]); + assert( 0 ); + break; + } + if( size&1 ){ + fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8); + }else{ + fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8, + i==mem3.iMaster ? " **master**" : ""); + } + } + for(i=0; i0; j=mem3.aPool[j].u.list.next){ + fprintf(out, " %p(%d)", &mem3.aPool[j], + (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); + } + fprintf(out, "\n"); + } + for(i=0; i0; j=mem3.aPool[j].u.list.next){ + fprintf(out, " %p(%d)", &mem3.aPool[j], + (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); + } + fprintf(out, "\n"); + } + fprintf(out, "master=%d\n", mem3.iMaster); + fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8); + fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8); + sqlite3_mutex_leave(mem3.mutex); + if( out==stdout ){ + fflush(stdout); + }else{ + fclose(out); + } +#else + UNUSED_PARAMETER(zFilename); +#endif +} + +/* +** This routine is the only routine in this file with external +** linkage. +** +** Populate the low-level memory allocation function pointers in +** sqlite3GlobalConfig.m with pointers to the routines in this file. The +** arguments specify the block of memory to manage. +** +** This routine is only called by sqlite3_config(), and therefore +** is not required to be threadsafe (it is not). +*/ +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){ + static const sqlite3_mem_methods mempoolMethods = { + memsys3Malloc, + memsys3Free, + memsys3Realloc, + memsys3Size, + memsys3Roundup, + memsys3Init, + memsys3Shutdown, + 0 + }; + return &mempoolMethods; +} + +#endif /* SQLITE_ENABLE_MEMSYS3 */ + +/************** End of mem3.c ************************************************/ +/************** Begin file mem5.c ********************************************/ +/* +** 2007 October 14 +** +** 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 the C functions that implement a memory +** allocation subsystem for use by SQLite. +** +** This version of the memory allocation subsystem omits all +** use of malloc(). The application gives SQLite a block of memory +** before calling sqlite3_initialize() from which allocations +** are made and returned by the xMalloc() and xRealloc() +** implementations. Once sqlite3_initialize() has been called, +** the amount of memory available to SQLite is fixed and cannot +** be changed. +** +** This version of the memory allocation subsystem is included +** in the build only if SQLITE_ENABLE_MEMSYS5 is defined. +** +** This memory allocator uses the following algorithm: +** +** 1. All memory allocation sizes are rounded up to a power of 2. +** +** 2. If two adjacent free blocks are the halves of a larger block, +** then the two blocks are coalesced into the single larger block. +** +** 3. New memory is allocated from the first available free block. +** +** This algorithm is described in: J. M. Robson. "Bounds for Some Functions +** Concerning Dynamic Storage Allocation". Journal of the Association for +** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499. +** +** Let n be the size of the largest allocation divided by the minimum +** allocation size (after rounding all sizes up to a power of 2.) Let M +** be the maximum amount of memory ever outstanding at one time. Let +** N be the total amount of memory available for allocation. Robson +** proved that this memory allocator will never breakdown due to +** fragmentation as long as the following constraint holds: +** +** N >= M*(1 + log2(n)/2) - n + 1 +** +** The sqlite3_status() logic tracks the maximum values of n and M so +** that an application can, at any time, verify this constraint. +*/ +/* #include "sqliteInt.h" */ + +/* +** This version of the memory allocator is used only when +** SQLITE_ENABLE_MEMSYS5 is defined. +*/ +#ifdef SQLITE_ENABLE_MEMSYS5 + +/* +** A minimum allocation is an instance of the following structure. +** Larger allocations are an array of these structures where the +** size of the array is a power of 2. +** +** The size of this object must be a power of two. That fact is +** verified in memsys5Init(). +*/ +typedef struct Mem5Link Mem5Link; +struct Mem5Link { + int next; /* Index of next free chunk */ + int prev; /* Index of previous free chunk */ +}; + +/* +** Maximum size of any allocation is ((1<=0 && i=0 && iLogsize<=LOGMAX ); + assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize ); + + next = MEM5LINK(i)->next; + prev = MEM5LINK(i)->prev; + if( prev<0 ){ + mem5.aiFreelist[iLogsize] = next; + }else{ + MEM5LINK(prev)->next = next; + } + if( next>=0 ){ + MEM5LINK(next)->prev = prev; + } +} + +/* +** Link the chunk at mem5.aPool[i] so that is on the iLogsize +** free list. +*/ +static void memsys5Link(int i, int iLogsize){ + int x; + assert( sqlite3_mutex_held(mem5.mutex) ); + assert( i>=0 && i=0 && iLogsize<=LOGMAX ); + assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize ); + + x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize]; + MEM5LINK(i)->prev = -1; + if( x>=0 ){ + assert( xprev = i; + } + mem5.aiFreelist[iLogsize] = i; +} + +/* +** Obtain or release the mutex needed to access global data structures. +*/ +static void memsys5Enter(void){ + sqlite3_mutex_enter(mem5.mutex); +} +static void memsys5Leave(void){ + sqlite3_mutex_leave(mem5.mutex); +} + +/* +** Return the size of an outstanding allocation, in bytes. +** This only works for chunks that are currently checked out. +*/ +static int memsys5Size(void *p){ + int iSize, i; + assert( p!=0 ); + i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom); + assert( i>=0 && i0 ); + + /* No more than 1GiB per allocation */ + if( nByte > 0x40000000 ) return 0; + +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + /* Keep track of the maximum allocation request. Even unfulfilled + ** requests are counted */ + if( (u32)nByte>mem5.maxRequest ){ + mem5.maxRequest = nByte; + } +#endif + + + /* Round nByte up to the next valid power of two */ + for(iFullSz=mem5.szAtom,iLogsize=0; iFullSzLOGMAX ){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte); + return 0; + } + i = mem5.aiFreelist[iBin]; + memsys5Unlink(i, iBin); + while( iBin>iLogsize ){ + int newSize; + + iBin--; + newSize = 1 << iBin; + mem5.aCtrl[i+newSize] = CTRL_FREE | iBin; + memsys5Link(i+newSize, iBin); + } + mem5.aCtrl[i] = iLogsize; + +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + /* Update allocator performance statistics. */ + mem5.nAlloc++; + mem5.totalAlloc += iFullSz; + mem5.totalExcess += iFullSz - nByte; + mem5.currentCount++; + mem5.currentOut += iFullSz; + if( mem5.maxCount=0 && iBlock0 ); + assert( mem5.currentOut>=(size*mem5.szAtom) ); + mem5.currentCount--; + mem5.currentOut -= size*mem5.szAtom; + assert( mem5.currentOut>0 || mem5.currentCount==0 ); + assert( mem5.currentCount>0 || mem5.currentOut==0 ); +#endif + + mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; + while( ALWAYS(iLogsize>iLogsize) & 1 ){ + iBuddy = iBlock - size; + assert( iBuddy>=0 ); + }else{ + iBuddy = iBlock + size; + if( iBuddy>=mem5.nBlock ) break; + } + if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break; + memsys5Unlink(iBuddy, iLogsize); + iLogsize++; + if( iBuddy0 ){ + memsys5Enter(); + p = memsys5MallocUnsafe(nBytes); + memsys5Leave(); + } + return (void*)p; +} + +/* +** Free memory. +** +** The outer layer memory allocator prevents this routine from +** being called with pPrior==0. +*/ +static void memsys5Free(void *pPrior){ + assert( pPrior!=0 ); + memsys5Enter(); + memsys5FreeUnsafe(pPrior); + memsys5Leave(); +} + +/* +** Change the size of an existing memory allocation. +** +** The outer layer memory allocator prevents this routine from +** being called with pPrior==0. +** +** nBytes is always a value obtained from a prior call to +** memsys5Round(). Hence nBytes is always a non-negative power +** of two. If nBytes==0 that means that an oversize allocation +** (an allocation larger than 0x40000000) was requested and this +** routine should return 0 without freeing pPrior. +*/ +static void *memsys5Realloc(void *pPrior, int nBytes){ + int nOld; + void *p; + assert( pPrior!=0 ); + assert( (nBytes&(nBytes-1))==0 ); /* EV: R-46199-30249 */ + assert( nBytes>=0 ); + if( nBytes==0 ){ + return 0; + } + nOld = memsys5Size(pPrior); + if( nBytes<=nOld ){ + return pPrior; + } + p = memsys5Malloc(nBytes); + if( p ){ + memcpy(p, pPrior, nOld); + memsys5Free(pPrior); + } + return p; +} + +/* +** Round up a request size to the next valid allocation size. If +** the allocation is too large to be handled by this allocation system, +** return 0. +** +** All allocations must be a power of two and must be expressed by a +** 32-bit signed integer. Hence the largest allocation is 0x40000000 +** or 1073741824 bytes. +*/ +static int memsys5Roundup(int n){ + int iFullSz; + if( n > 0x40000000 ) return 0; + for(iFullSz=mem5.szAtom; iFullSz 0 +** memsys5Log(2) -> 1 +** memsys5Log(4) -> 2 +** memsys5Log(5) -> 3 +** memsys5Log(8) -> 3 +** memsys5Log(9) -> 4 +*/ +static int memsys5Log(int iValue){ + int iLog; + for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<mem5.szAtom ){ + mem5.szAtom = mem5.szAtom << 1; + } + + mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8))); + mem5.zPool = zByte; + mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom]; + + for(ii=0; ii<=LOGMAX; ii++){ + mem5.aiFreelist[ii] = -1; + } + + iOffset = 0; + for(ii=LOGMAX; ii>=0; ii--){ + int nAlloc = (1<mem5.nBlock); + } + + /* If a mutex is required for normal operation, allocate one */ + if( sqlite3GlobalConfig.bMemstat==0 ){ + mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); + } + + return SQLITE_OK; +} + +/* +** Deinitialize this module. +*/ +static void memsys5Shutdown(void *NotUsed){ + UNUSED_PARAMETER(NotUsed); + mem5.mutex = 0; + return; +} + +#ifdef SQLITE_TEST +/* +** Open the file indicated and write a log of all unfreed memory +** allocations into that log. +*/ +SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){ + FILE *out; + int i, j, n; + int nMinLog; + + if( zFilename==0 || zFilename[0]==0 ){ + out = stdout; + }else{ + out = fopen(zFilename, "w"); + if( out==0 ){ + fprintf(stderr, "** Unable to output memory debug output log: %s **\n", + zFilename); + return; + } + } + memsys5Enter(); + nMinLog = memsys5Log(mem5.szAtom); + for(i=0; i<=LOGMAX && i+nMinLog<32; i++){ + for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){} + fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n); + } + fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc); + fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc); + fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess); + fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut); + fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount); + fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut); + fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount); + fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest); + memsys5Leave(); + if( out==stdout ){ + fflush(stdout); + }else{ + fclose(out); + } +} +#endif + +/* +** This routine is the only routine in this file with external +** linkage. It returns a pointer to a static sqlite3_mem_methods +** struct populated with the memsys5 methods. +*/ +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){ + static const sqlite3_mem_methods memsys5Methods = { + memsys5Malloc, + memsys5Free, + memsys5Realloc, + memsys5Size, + memsys5Roundup, + memsys5Init, + memsys5Shutdown, + 0 + }; + return &memsys5Methods; +} + +#endif /* SQLITE_ENABLE_MEMSYS5 */ + +/************** End of mem5.c ************************************************/ +/************** Begin file mutex.c *******************************************/ +/* +** 2007 August 14 +** +** 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 the C functions that implement mutexes. +** +** This file contains code that is common across all mutex implementations. +*/ +/* #include "sqliteInt.h" */ + +#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT) +/* +** For debugging purposes, record when the mutex subsystem is initialized +** and uninitialized so that we can assert() if there is an attempt to +** allocate a mutex while the system is uninitialized. +*/ +static SQLITE_WSD int mutexIsInit = 0; +#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */ + + +#ifndef SQLITE_MUTEX_OMIT +/* +** Initialize the mutex system. +*/ +SQLITE_PRIVATE int sqlite3MutexInit(void){ + int rc = SQLITE_OK; + if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){ + /* If the xMutexAlloc method has not been set, then the user did not + ** install a mutex implementation via sqlite3_config() prior to + ** sqlite3_initialize() being called. This block copies pointers to + ** the default implementation into the sqlite3GlobalConfig structure. + */ + sqlite3_mutex_methods const *pFrom; + sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; + + if( sqlite3GlobalConfig.bCoreMutex ){ + pFrom = sqlite3DefaultMutex(); + }else{ + pFrom = sqlite3NoopMutex(); + } + pTo->xMutexInit = pFrom->xMutexInit; + pTo->xMutexEnd = pFrom->xMutexEnd; + pTo->xMutexFree = pFrom->xMutexFree; + pTo->xMutexEnter = pFrom->xMutexEnter; + pTo->xMutexTry = pFrom->xMutexTry; + pTo->xMutexLeave = pFrom->xMutexLeave; + pTo->xMutexHeld = pFrom->xMutexHeld; + pTo->xMutexNotheld = pFrom->xMutexNotheld; + sqlite3MemoryBarrier(); + pTo->xMutexAlloc = pFrom->xMutexAlloc; + } + assert( sqlite3GlobalConfig.mutex.xMutexInit ); + rc = sqlite3GlobalConfig.mutex.xMutexInit(); + +#ifdef SQLITE_DEBUG + GLOBAL(int, mutexIsInit) = 1; +#endif + + return rc; +} + +/* +** Shutdown the mutex system. This call frees resources allocated by +** sqlite3MutexInit(). +*/ +SQLITE_PRIVATE int sqlite3MutexEnd(void){ + int rc = SQLITE_OK; + if( sqlite3GlobalConfig.mutex.xMutexEnd ){ + rc = sqlite3GlobalConfig.mutex.xMutexEnd(); + } + +#ifdef SQLITE_DEBUG + GLOBAL(int, mutexIsInit) = 0; +#endif + + return rc; +} + +/* +** Retrieve a pointer to a static mutex or allocate a new dynamic one. +*/ +SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){ +#ifndef SQLITE_OMIT_AUTOINIT + if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; + if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0; +#endif + assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); + return sqlite3GlobalConfig.mutex.xMutexAlloc(id); +} + +SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){ + if( !sqlite3GlobalConfig.bCoreMutex ){ + return 0; + } + assert( GLOBAL(int, mutexIsInit) ); + assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); + return sqlite3GlobalConfig.mutex.xMutexAlloc(id); +} + +/* +** Free a dynamic mutex. +*/ +SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ + if( p ){ + assert( sqlite3GlobalConfig.mutex.xMutexFree ); + sqlite3GlobalConfig.mutex.xMutexFree(p); + } +} + +/* +** Obtain the mutex p. If some other thread already has the mutex, block +** until it can be obtained. +*/ +SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ + if( p ){ + assert( sqlite3GlobalConfig.mutex.xMutexEnter ); + sqlite3GlobalConfig.mutex.xMutexEnter(p); + } +} + +/* +** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another +** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY. +*/ +SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ + int rc = SQLITE_OK; + if( p ){ + assert( sqlite3GlobalConfig.mutex.xMutexTry ); + return sqlite3GlobalConfig.mutex.xMutexTry(p); + } + return rc; +} + +/* +** The sqlite3_mutex_leave() routine exits a mutex that was previously +** entered by the same thread. The behavior is undefined if the mutex +** is not currently entered. If a NULL pointer is passed as an argument +** this function is a no-op. +*/ +SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ + if( p ){ + assert( sqlite3GlobalConfig.mutex.xMutexLeave ); + sqlite3GlobalConfig.mutex.xMutexLeave(p); + } +} + +#ifndef NDEBUG +/* +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are +** intended for use inside assert() statements. +*/ +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ + assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld ); + return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); +} +SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ + assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld ); + return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); +} +#endif + +#endif /* !defined(SQLITE_MUTEX_OMIT) */ + +/************** End of mutex.c ***********************************************/ +/************** Begin file mutex_noop.c **************************************/ +/* +** 2008 October 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 contains the C functions that implement mutexes. +** +** This implementation in this file does not provide any mutual +** exclusion and is thus suitable for use only in applications +** that use SQLite in a single thread. The routines defined +** here are place-holders. Applications can substitute working +** mutex routines at start-time using the +** +** sqlite3_config(SQLITE_CONFIG_MUTEX,...) +** +** interface. +** +** If compiled with SQLITE_DEBUG, then additional logic is inserted +** that does error checking on mutexes to make sure they are being +** called correctly. +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_MUTEX_OMIT + +#ifndef SQLITE_DEBUG +/* +** Stub routines for all mutex methods. +** +** This routines provide no mutual exclusion or error checking. +*/ +static int noopMutexInit(void){ return SQLITE_OK; } +static int noopMutexEnd(void){ return SQLITE_OK; } +static sqlite3_mutex *noopMutexAlloc(int id){ + UNUSED_PARAMETER(id); + return (sqlite3_mutex*)8; +} +static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } +static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } +static int noopMutexTry(sqlite3_mutex *p){ + UNUSED_PARAMETER(p); + return SQLITE_OK; +} +static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } + +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){ + static const sqlite3_mutex_methods sMutex = { + noopMutexInit, + noopMutexEnd, + noopMutexAlloc, + noopMutexFree, + noopMutexEnter, + noopMutexTry, + noopMutexLeave, + + 0, + 0, + }; + + return &sMutex; +} +#endif /* !SQLITE_DEBUG */ + +#ifdef SQLITE_DEBUG +/* +** In this implementation, error checking is provided for testing +** and debugging purposes. The mutexes still do not provide any +** mutual exclusion. +*/ + +/* +** The mutex object +*/ +typedef struct sqlite3_debug_mutex { + int id; /* The mutex type */ + int cnt; /* Number of entries without a matching leave */ +} sqlite3_debug_mutex; + +/* +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are +** intended for use inside assert() statements. +*/ +static int debugMutexHeld(sqlite3_mutex *pX){ + sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; + return p==0 || p->cnt>0; +} +static int debugMutexNotheld(sqlite3_mutex *pX){ + sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; + return p==0 || p->cnt==0; +} + +/* +** Initialize and deinitialize the mutex subsystem. +*/ +static int debugMutexInit(void){ return SQLITE_OK; } +static int debugMutexEnd(void){ return SQLITE_OK; } + +/* +** The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. If it returns NULL +** that means that a mutex could not be allocated. +*/ +static sqlite3_mutex *debugMutexAlloc(int id){ + static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1]; + sqlite3_debug_mutex *pNew = 0; + switch( id ){ + case SQLITE_MUTEX_FAST: + case SQLITE_MUTEX_RECURSIVE: { + pNew = sqlite3Malloc(sizeof(*pNew)); + if( pNew ){ + pNew->id = id; + pNew->cnt = 0; + } + break; + } + default: { +#ifdef SQLITE_ENABLE_API_ARMOR + if( id-2<0 || id-2>=ArraySize(aStatic) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + pNew = &aStatic[id-2]; + pNew->id = id; + break; + } + } + return (sqlite3_mutex*)pNew; +} + +/* +** This routine deallocates a previously allocated mutex. +*/ +static void debugMutexFree(sqlite3_mutex *pX){ + sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; + assert( p->cnt==0 ); + if( p->id==SQLITE_MUTEX_RECURSIVE || p->id==SQLITE_MUTEX_FAST ){ + sqlite3_free(p); + }else{ +#ifdef SQLITE_ENABLE_API_ARMOR + (void)SQLITE_MISUSE_BKPT; +#endif + } +} + +/* +** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK +** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can +** be entered multiple times by the same thread. In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter. If the same thread tries to enter any other kind of mutex +** more than once, the behavior is undefined. +*/ +static void debugMutexEnter(sqlite3_mutex *pX){ + sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; + assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); + p->cnt++; +} +static int debugMutexTry(sqlite3_mutex *pX){ + sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; + assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); + p->cnt++; + return SQLITE_OK; +} + +/* +** The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered or +** is not currently allocated. SQLite will never do either. +*/ +static void debugMutexLeave(sqlite3_mutex *pX){ + sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; + assert( debugMutexHeld(pX) ); + p->cnt--; + assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); +} + +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){ + static const sqlite3_mutex_methods sMutex = { + debugMutexInit, + debugMutexEnd, + debugMutexAlloc, + debugMutexFree, + debugMutexEnter, + debugMutexTry, + debugMutexLeave, + + debugMutexHeld, + debugMutexNotheld + }; + + return &sMutex; +} +#endif /* SQLITE_DEBUG */ + +/* +** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation +** is used regardless of the run-time threadsafety setting. +*/ +#ifdef SQLITE_MUTEX_NOOP +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ + return sqlite3NoopMutex(); +} +#endif /* defined(SQLITE_MUTEX_NOOP) */ +#endif /* !defined(SQLITE_MUTEX_OMIT) */ + +/************** End of mutex_noop.c ******************************************/ +/************** Begin file mutex_unix.c **************************************/ +/* +** 2007 August 28 +** +** 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 the C functions that implement mutexes for pthreads +*/ +/* #include "sqliteInt.h" */ + +/* +** The code in this file is only used if we are compiling threadsafe +** under unix with pthreads. +** +** Note that this implementation requires a version of pthreads that +** supports recursive mutexes. +*/ +#ifdef SQLITE_MUTEX_PTHREADS + +#include + +/* +** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields +** are necessary under two condidtions: (1) Debug builds and (2) using +** home-grown mutexes. Encapsulate these conditions into a single #define. +*/ +#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX) +# define SQLITE_MUTEX_NREF 1 +#else +# define SQLITE_MUTEX_NREF 0 +#endif + +/* +** Each recursive mutex is an instance of the following structure. +*/ +struct sqlite3_mutex { + pthread_mutex_t mutex; /* Mutex controlling the lock */ +#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) + int id; /* Mutex type */ +#endif +#if SQLITE_MUTEX_NREF + volatile int nRef; /* Number of entrances */ + volatile pthread_t owner; /* Thread that is within this mutex */ + int trace; /* True to trace changes */ +#endif +}; +#if SQLITE_MUTEX_NREF +#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0} +#elif defined(SQLITE_ENABLE_API_ARMOR) +#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 } +#else +#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER } +#endif + +/* +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are +** intended for use only inside assert() statements. On some platforms, +** there might be race conditions that can cause these routines to +** deliver incorrect results. In particular, if pthread_equal() is +** not an atomic operation, then these routines might delivery +** incorrect results. On most platforms, pthread_equal() is a +** comparison of two integers and is therefore atomic. But we are +** told that HPUX is not such a platform. If so, then these routines +** will not always work correctly on HPUX. +** +** On those platforms where pthread_equal() is not atomic, SQLite +** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to +** make sure no assert() statements are evaluated and hence these +** routines are never called. +*/ +#if !defined(NDEBUG) || defined(SQLITE_DEBUG) +static int pthreadMutexHeld(sqlite3_mutex *p){ + return (p->nRef!=0 && pthread_equal(p->owner, pthread_self())); +} +static int pthreadMutexNotheld(sqlite3_mutex *p){ + return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0; +} +#endif + +/* +** Try to provide a memory barrier operation, needed for initialization +** and also for the implementation of xShmBarrier in the VFS in cases +** where SQLite is compiled without mutexes. +*/ +SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ +#if defined(SQLITE_MEMORY_BARRIER) + SQLITE_MEMORY_BARRIER; +#elif defined(__GNUC__) && GCC_VERSION>=4001000 + __sync_synchronize(); +#endif +} + +/* +** Initialize and deinitialize the mutex subsystem. +*/ +static int pthreadMutexInit(void){ return SQLITE_OK; } +static int pthreadMutexEnd(void){ return SQLITE_OK; } + +/* +** The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. If it returns NULL +** that means that a mutex could not be allocated. SQLite +** will unwind its stack and return an error. The argument +** to sqlite3_mutex_alloc() is one of these integer constants: +** +**
    +**
  • SQLITE_MUTEX_FAST +**
  • SQLITE_MUTEX_RECURSIVE +**
  • SQLITE_MUTEX_STATIC_MASTER +**
  • SQLITE_MUTEX_STATIC_MEM +**
  • SQLITE_MUTEX_STATIC_OPEN +**
  • SQLITE_MUTEX_STATIC_PRNG +**
  • SQLITE_MUTEX_STATIC_LRU +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 +**
  • SQLITE_MUTEX_STATIC_VFS1 +**
  • SQLITE_MUTEX_STATIC_VFS2 +**
  • SQLITE_MUTEX_STATIC_VFS3 +**
+** +** The first two constants cause sqlite3_mutex_alloc() to create +** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. But SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** The other allowed parameters to sqlite3_mutex_alloc() each return +** a pointer to a static preexisting mutex. Six static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. But for the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +*/ +static sqlite3_mutex *pthreadMutexAlloc(int iType){ + static sqlite3_mutex staticMutexes[] = { + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER + }; + sqlite3_mutex *p; + switch( iType ){ + case SQLITE_MUTEX_RECURSIVE: { + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ +#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX + /* If recursive mutexes are not available, we will have to + ** build our own. See below. */ + pthread_mutex_init(&p->mutex, 0); +#else + /* Use a recursive mutex if it is available */ + pthread_mutexattr_t recursiveAttr; + pthread_mutexattr_init(&recursiveAttr); + pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&p->mutex, &recursiveAttr); + pthread_mutexattr_destroy(&recursiveAttr); +#endif + } + break; + } + case SQLITE_MUTEX_FAST: { + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ + pthread_mutex_init(&p->mutex, 0); + } + break; + } + default: { +#ifdef SQLITE_ENABLE_API_ARMOR + if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + p = &staticMutexes[iType-2]; + break; + } + } +#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) + if( p ) p->id = iType; +#endif + return p; +} + + +/* +** This routine deallocates a previously +** allocated mutex. SQLite is careful to deallocate every +** mutex that it allocates. +*/ +static void pthreadMutexFree(sqlite3_mutex *p){ + assert( p->nRef==0 ); +#if SQLITE_ENABLE_API_ARMOR + if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ) +#endif + { + pthread_mutex_destroy(&p->mutex); + sqlite3_free(p); + } +#ifdef SQLITE_ENABLE_API_ARMOR + else{ + (void)SQLITE_MISUSE_BKPT; + } +#endif +} + +/* +** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK +** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can +** be entered multiple times by the same thread. In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter. If the same thread tries to enter any other kind of mutex +** more than once, the behavior is undefined. +*/ +static void pthreadMutexEnter(sqlite3_mutex *p){ + assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) ); + +#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX + /* If recursive mutexes are not available, then we have to grow + ** our own. This implementation assumes that pthread_equal() + ** is atomic - that it cannot be deceived into thinking self + ** and p->owner are equal if p->owner changes between two values + ** that are not equal to self while the comparison is taking place. + ** This implementation also assumes a coherent cache - that + ** separate processes cannot read different values from the same + ** address at the same time. If either of these two conditions + ** are not met, then the mutexes will fail and problems will result. + */ + { + pthread_t self = pthread_self(); + if( p->nRef>0 && pthread_equal(p->owner, self) ){ + p->nRef++; + }else{ + pthread_mutex_lock(&p->mutex); + assert( p->nRef==0 ); + p->owner = self; + p->nRef = 1; + } + } +#else + /* Use the built-in recursive mutexes if they are available. + */ + pthread_mutex_lock(&p->mutex); +#if SQLITE_MUTEX_NREF + assert( p->nRef>0 || p->owner==0 ); + p->owner = pthread_self(); + p->nRef++; +#endif +#endif + +#ifdef SQLITE_DEBUG + if( p->trace ){ + printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + } +#endif +} +static int pthreadMutexTry(sqlite3_mutex *p){ + int rc; + assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) ); + +#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX + /* If recursive mutexes are not available, then we have to grow + ** our own. This implementation assumes that pthread_equal() + ** is atomic - that it cannot be deceived into thinking self + ** and p->owner are equal if p->owner changes between two values + ** that are not equal to self while the comparison is taking place. + ** This implementation also assumes a coherent cache - that + ** separate processes cannot read different values from the same + ** address at the same time. If either of these two conditions + ** are not met, then the mutexes will fail and problems will result. + */ + { + pthread_t self = pthread_self(); + if( p->nRef>0 && pthread_equal(p->owner, self) ){ + p->nRef++; + rc = SQLITE_OK; + }else if( pthread_mutex_trylock(&p->mutex)==0 ){ + assert( p->nRef==0 ); + p->owner = self; + p->nRef = 1; + rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; + } + } +#else + /* Use the built-in recursive mutexes if they are available. + */ + if( pthread_mutex_trylock(&p->mutex)==0 ){ +#if SQLITE_MUTEX_NREF + p->owner = pthread_self(); + p->nRef++; +#endif + rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; + } +#endif + +#ifdef SQLITE_DEBUG + if( rc==SQLITE_OK && p->trace ){ + printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + } +#endif + return rc; +} + +/* +** The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered or +** is not currently allocated. SQLite will never do either. +*/ +static void pthreadMutexLeave(sqlite3_mutex *p){ + assert( pthreadMutexHeld(p) ); +#if SQLITE_MUTEX_NREF + p->nRef--; + if( p->nRef==0 ) p->owner = 0; +#endif + assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); + +#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX + if( p->nRef==0 ){ + pthread_mutex_unlock(&p->mutex); + } +#else + pthread_mutex_unlock(&p->mutex); +#endif + +#ifdef SQLITE_DEBUG + if( p->trace ){ + printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + } +#endif +} + +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ + static const sqlite3_mutex_methods sMutex = { + pthreadMutexInit, + pthreadMutexEnd, + pthreadMutexAlloc, + pthreadMutexFree, + pthreadMutexEnter, + pthreadMutexTry, + pthreadMutexLeave, +#ifdef SQLITE_DEBUG + pthreadMutexHeld, + pthreadMutexNotheld +#else + 0, + 0 +#endif + }; + + return &sMutex; +} + +#endif /* SQLITE_MUTEX_PTHREADS */ + +/************** End of mutex_unix.c ******************************************/ +/************** Begin file mutex_w32.c ***************************************/ +/* +** 2007 August 14 +** +** 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 the C functions that implement mutexes for Win32. +*/ +/* #include "sqliteInt.h" */ + +#if SQLITE_OS_WIN +/* +** Include code that is common to all os_*.c files +*/ +/************** Include os_common.h in the middle of mutex_w32.c *************/ +/************** Begin file os_common.h ***************************************/ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains macros and a little bit of code that is common to +** all of the platform-specific files (os_*.c) and is #included into those +** files. +** +** This file should be #included by the os_*.c files only. It is not a +** general purpose header file. +*/ +#ifndef _OS_COMMON_H_ +#define _OS_COMMON_H_ + +/* +** At least two bugs have slipped in because we changed the MEMORY_DEBUG +** macro to SQLITE_DEBUG and some older makefiles have not yet made the +** switch. The following code should catch this problem at compile-time. +*/ +#ifdef MEMORY_DEBUG +# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." +#endif + +/* +** Macros for performance tracing. Normally turned off. Only works +** on i486 hardware. +*/ +#ifdef SQLITE_PERFORMANCE_TRACE + +/* +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. +*/ +/************** Include hwtime.h in the middle of os_common.h ****************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 class CPUs. +*/ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H + +/* +** The following routine only works on pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } + +#elif (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + #error Need implementation of sqlite3Hwtime() for your platform. + + /* + ** To compile without implementing sqlite3Hwtime() for your platform, + ** you can remove the above #error and use the following + ** stub function. You will lose timing support for many + ** of the debugging and testing utilities, but it should at + ** least compile and run. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in os_common.h ******************/ + +static sqlite_uint64 g_start; +static sqlite_uint64 g_elapsed; +#define TIMER_START g_start=sqlite3Hwtime() +#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start +#define TIMER_ELAPSED g_elapsed +#else +#define TIMER_START +#define TIMER_END +#define TIMER_ELAPSED ((sqlite_uint64)0) +#endif + +/* +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; +#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) +#define SimulateIOError(CODE) \ + if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ + || sqlite3_io_error_pending-- == 1 ) \ + { local_ioerr(); CODE; } +static void local_ioerr(){ + IOTRACE(("IOERR\n")); + sqlite3_io_error_hit++; + if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; +} +#define SimulateDiskfullError(CODE) \ + if( sqlite3_diskfull_pending ){ \ + if( sqlite3_diskfull_pending == 1 ){ \ + local_ioerr(); \ + sqlite3_diskfull = 1; \ + sqlite3_io_error_hit = 1; \ + CODE; \ + }else{ \ + sqlite3_diskfull_pending--; \ + } \ + } +#else +#define SimulateIOErrorBenign(X) +#define SimulateIOError(A) +#define SimulateDiskfullError(A) +#endif /* defined(SQLITE_TEST) */ + +/* +** When testing, keep a count of the number of open files. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; +#define OpenCounter(X) sqlite3_open_file_count+=(X) +#else +#define OpenCounter(X) +#endif /* defined(SQLITE_TEST) */ + +#endif /* !defined(_OS_COMMON_H_) */ + +/************** End of os_common.h *******************************************/ +/************** Continuing where we left off in mutex_w32.c ******************/ + +/* +** Include the header file for the Windows VFS. +*/ +/************** Include os_win.h in the middle of mutex_w32.c ****************/ +/************** Begin file os_win.h ******************************************/ +/* +** 2013 November 25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code that is specific to Windows. +*/ +#ifndef SQLITE_OS_WIN_H +#define SQLITE_OS_WIN_H + +/* +** Include the primary Windows SDK header file. +*/ +#include "windows.h" + +#ifdef __CYGWIN__ +# include +# include /* amalgamator: dontcache */ +#endif + +/* +** Determine if we are dealing with Windows NT. +** +** We ought to be able to determine if we are compiling for Windows 9x or +** Windows NT using the _WIN32_WINNT macro as follows: +** +** #if defined(_WIN32_WINNT) +** # define SQLITE_OS_WINNT 1 +** #else +** # define SQLITE_OS_WINNT 0 +** #endif +** +** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as +** it ought to, so the above test does not work. We'll just assume that +** everything is Windows NT unless the programmer explicitly says otherwise +** by setting SQLITE_OS_WINNT to 0. +*/ +#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) +# define SQLITE_OS_WINNT 1 +#endif + +/* +** Determine if we are dealing with Windows CE - which has a much reduced +** API. +*/ +#if defined(_WIN32_WCE) +# define SQLITE_OS_WINCE 1 +#else +# define SQLITE_OS_WINCE 0 +#endif + +/* +** Determine if we are dealing with WinRT, which provides only a subset of +** the full Win32 API. +*/ +#if !defined(SQLITE_OS_WINRT) +# define SQLITE_OS_WINRT 0 +#endif + +/* +** For WinCE, some API function parameters do not appear to be declared as +** volatile. +*/ +#if SQLITE_OS_WINCE +# define SQLITE_WIN32_VOLATILE +#else +# define SQLITE_WIN32_VOLATILE volatile +#endif + +/* +** For some Windows sub-platforms, the _beginthreadex() / _endthreadex() +** functions are not available (e.g. those not using MSVC, Cygwin, etc). +*/ +#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ + SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) +# define SQLITE_OS_WIN_THREADS 1 +#else +# define SQLITE_OS_WIN_THREADS 0 +#endif + +#endif /* SQLITE_OS_WIN_H */ + +/************** End of os_win.h **********************************************/ +/************** Continuing where we left off in mutex_w32.c ******************/ +#endif + +/* +** The code in this file is only used if we are compiling multithreaded +** on a Win32 system. +*/ +#ifdef SQLITE_MUTEX_W32 + +/* +** Each recursive mutex is an instance of the following structure. +*/ +struct sqlite3_mutex { + CRITICAL_SECTION mutex; /* Mutex controlling the lock */ + int id; /* Mutex type */ +#ifdef SQLITE_DEBUG + volatile int nRef; /* Number of enterances */ + volatile DWORD owner; /* Thread holding this mutex */ + volatile int trace; /* True to trace changes */ +#endif +}; + +/* +** These are the initializer values used when declaring a "static" mutex +** on Win32. It should be noted that all mutexes require initialization +** on the Win32 platform. +*/ +#define SQLITE_W32_MUTEX_INITIALIZER { 0 } + +#ifdef SQLITE_DEBUG +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \ + 0L, (DWORD)0, 0 } +#else +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } +#endif + +#ifdef SQLITE_DEBUG +/* +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are +** intended for use only inside assert() statements. +*/ +static int winMutexHeld(sqlite3_mutex *p){ + return p->nRef!=0 && p->owner==GetCurrentThreadId(); +} + +static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){ + return p->nRef==0 || p->owner!=tid; +} + +static int winMutexNotheld(sqlite3_mutex *p){ + DWORD tid = GetCurrentThreadId(); + return winMutexNotheld2(p, tid); +} +#endif + +/* +** Try to provide a memory barrier operation, needed for initialization +** and also for the xShmBarrier method of the VFS in cases when SQLite is +** compiled without mutexes (SQLITE_THREADSAFE=0). +*/ +SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ +#if defined(SQLITE_MEMORY_BARRIER) + SQLITE_MEMORY_BARRIER; +#elif defined(__GNUC__) + __sync_synchronize(); +#elif MSVC_VERSION>=1300 + _ReadWriteBarrier(); +#elif defined(MemoryBarrier) + MemoryBarrier(); +#endif +} + +/* +** Initialize and deinitialize the mutex subsystem. +*/ +static sqlite3_mutex winMutex_staticMutexes[] = { + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER +}; + +static int winMutex_isInit = 0; +static int winMutex_isNt = -1; /* <0 means "need to query" */ + +/* As the winMutexInit() and winMutexEnd() functions are called as part +** of the sqlite3_initialize() and sqlite3_shutdown() processing, the +** "interlocked" magic used here is probably not strictly necessary. +*/ +static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0; + +SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */ +SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ + +static int winMutexInit(void){ + /* The first to increment to 1 does actual initialization */ + if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ + int i; + for(i=0; i +**
  • SQLITE_MUTEX_FAST +**
  • SQLITE_MUTEX_RECURSIVE +**
  • SQLITE_MUTEX_STATIC_MASTER +**
  • SQLITE_MUTEX_STATIC_MEM +**
  • SQLITE_MUTEX_STATIC_OPEN +**
  • SQLITE_MUTEX_STATIC_PRNG +**
  • SQLITE_MUTEX_STATIC_LRU +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 +**
  • SQLITE_MUTEX_STATIC_VFS1 +**
  • SQLITE_MUTEX_STATIC_VFS2 +**
  • SQLITE_MUTEX_STATIC_VFS3 +** +** +** The first two constants cause sqlite3_mutex_alloc() to create +** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. But SQLite will only request a recursive mutex in +** cases where it really needs one. If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** The other allowed parameters to sqlite3_mutex_alloc() each return +** a pointer to a static preexisting mutex. Six static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. But for the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +*/ +static sqlite3_mutex *winMutexAlloc(int iType){ + sqlite3_mutex *p; + + switch( iType ){ + case SQLITE_MUTEX_FAST: + case SQLITE_MUTEX_RECURSIVE: { + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ + p->id = iType; +#ifdef SQLITE_DEBUG +#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC + p->trace = 1; +#endif +#endif +#if SQLITE_OS_WINRT + InitializeCriticalSectionEx(&p->mutex, 0, 0); +#else + InitializeCriticalSection(&p->mutex); +#endif + } + break; + } + default: { +#ifdef SQLITE_ENABLE_API_ARMOR + if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + p = &winMutex_staticMutexes[iType-2]; + p->id = iType; +#ifdef SQLITE_DEBUG +#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC + p->trace = 1; +#endif +#endif + break; + } + } + return p; +} + + +/* +** This routine deallocates a previously +** allocated mutex. SQLite is careful to deallocate every +** mutex that it allocates. +*/ +static void winMutexFree(sqlite3_mutex *p){ + assert( p ); + assert( p->nRef==0 && p->owner==0 ); + if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){ + DeleteCriticalSection(&p->mutex); + sqlite3_free(p); + }else{ +#ifdef SQLITE_ENABLE_API_ARMOR + (void)SQLITE_MISUSE_BKPT; +#endif + } +} + +/* +** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK +** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can +** be entered multiple times by the same thread. In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter. If the same thread tries to enter any other kind of mutex +** more than once, the behavior is undefined. +*/ +static void winMutexEnter(sqlite3_mutex *p){ +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); +#endif +#ifdef SQLITE_DEBUG + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); +#else + assert( p ); +#endif + assert( winMutex_isInit==1 ); + EnterCriticalSection(&p->mutex); +#ifdef SQLITE_DEBUG + assert( p->nRef>0 || p->owner==0 ); + p->owner = tid; + p->nRef++; + if( p->trace ){ + OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", + tid, p->id, p, p->trace, p->nRef)); + } +#endif +} + +static int winMutexTry(sqlite3_mutex *p){ +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); +#endif + int rc = SQLITE_BUSY; + assert( p ); + assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); + /* + ** The sqlite3_mutex_try() routine is very rarely used, and when it + ** is used it is merely an optimization. So it is OK for it to always + ** fail. + ** + ** The TryEnterCriticalSection() interface is only available on WinNT. + ** And some windows compilers complain if you try to use it without + ** first doing some #defines that prevent SQLite from building on Win98. + ** For that reason, we will omit this optimization for now. See + ** ticket #2685. + */ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 + assert( winMutex_isInit==1 ); + assert( winMutex_isNt>=-1 && winMutex_isNt<=1 ); + if( winMutex_isNt<0 ){ + winMutex_isNt = sqlite3_win32_is_nt(); + } + assert( winMutex_isNt==0 || winMutex_isNt==1 ); + if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){ +#ifdef SQLITE_DEBUG + p->owner = tid; + p->nRef++; +#endif + rc = SQLITE_OK; + } +#else + UNUSED_PARAMETER(p); +#endif +#ifdef SQLITE_DEBUG + if( p->trace ){ + OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n", + tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); + } +#endif + return rc; +} + +/* +** The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. The behavior +** is undefined if the mutex is not currently entered or +** is not currently allocated. SQLite will never do either. +*/ +static void winMutexLeave(sqlite3_mutex *p){ +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); +#endif + assert( p ); +#ifdef SQLITE_DEBUG + assert( p->nRef>0 ); + assert( p->owner==tid ); + p->nRef--; + if( p->nRef==0 ) p->owner = 0; + assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); +#endif + assert( winMutex_isInit==1 ); + LeaveCriticalSection(&p->mutex); +#ifdef SQLITE_DEBUG + if( p->trace ){ + OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", + tid, p->id, p, p->trace, p->nRef)); + } +#endif +} + +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ + static const sqlite3_mutex_methods sMutex = { + winMutexInit, + winMutexEnd, + winMutexAlloc, + winMutexFree, + winMutexEnter, + winMutexTry, + winMutexLeave, +#ifdef SQLITE_DEBUG + winMutexHeld, + winMutexNotheld +#else + 0, + 0 +#endif + }; + return &sMutex; +} + +#endif /* SQLITE_MUTEX_W32 */ + +/************** End of mutex_w32.c *******************************************/ +/************** Begin file malloc.c ******************************************/ +/* +** 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. +** +************************************************************************* +** +** Memory allocation functions used throughout sqlite. +*/ +/* #include "sqliteInt.h" */ +/* #include */ + +/* +** Attempt to release up to n bytes of non-essential memory currently +** held by SQLite. An example of non-essential memory is memory used to +** cache database pages that are not currently in use. +*/ +SQLITE_API int sqlite3_release_memory(int n){ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + return sqlite3PcacheReleaseMemory(n); +#else + /* IMPLEMENTATION-OF: R-34391-24921 The sqlite3_release_memory() routine + ** is a no-op returning zero if SQLite is not compiled with + ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */ + UNUSED_PARAMETER(n); + return 0; +#endif +} + +/* +** 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 { + sqlite3_mutex *mutex; /* Mutex to serialize access */ + 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 }; + +#define mem0 GLOBAL(struct Mem0Global, mem0) + +/* +** Return the memory allocator mutex. sqlite3_status() needs it. +*/ +SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){ + return mem0.mutex; +} + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** Deprecated external interface. It used to set an alarm callback +** that was invoked when memory usage grew too large. Now it is a +** no-op. +*/ +SQLITE_API int sqlite3_memory_alarm( + void(*xCallback)(void *pArg, sqlite3_int64 used,int N), + void *pArg, + sqlite3_int64 iThreshold +){ + (void)xCallback; + (void)pArg; + (void)iThreshold; + return SQLITE_OK; +} +#endif + +/* +** Set the soft heap-size limit for the library. Passing a zero or +** negative value indicates no limit. +*/ +SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ + sqlite3_int64 priorLimit; + sqlite3_int64 excess; + sqlite3_int64 nUsed; +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return -1; +#endif + sqlite3_mutex_enter(mem0.mutex); + priorLimit = mem0.alarmThreshold; + if( n<0 ){ + sqlite3_mutex_leave(mem0.mutex); + return priorLimit; + } + mem0.alarmThreshold = n; + nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); + mem0.nearlyFull = (n>0 && n<=nUsed); + sqlite3_mutex_leave(mem0.mutex); + excess = sqlite3_memory_used() - n; + if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); + return priorLimit; +} +SQLITE_API void sqlite3_soft_heap_limit(int n){ + if( n<0 ) n = 0; + sqlite3_soft_heap_limit64(n); +} + +/* +** Initialize the memory allocation subsystem. +*/ +SQLITE_PRIVATE int sqlite3MallocInit(void){ + int rc; + if( sqlite3GlobalConfig.m.xMalloc==0 ){ + sqlite3MemSetDefault(); + } + 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; ipNext = (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; + sqlite3GlobalConfig.szPage = 0; + } + rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData); + if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0)); + return rc; +} + +/* +** Return true if the heap is currently under memory pressure - in other +** words if the amount of heap used is close to the limit set by +** sqlite3_soft_heap_limit(). +*/ +SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){ + return mem0.nearlyFull; +} + +/* +** Deinitialize the memory allocation subsystem. +*/ +SQLITE_PRIVATE void sqlite3MallocEnd(void){ + if( sqlite3GlobalConfig.m.xShutdown ){ + sqlite3GlobalConfig.m.xShutdown(sqlite3GlobalConfig.m.pAppData); + } + memset(&mem0, 0, sizeof(mem0)); +} + +/* +** Return the amount of memory currently checked out. +*/ +SQLITE_API sqlite3_int64 sqlite3_memory_used(void){ + sqlite3_int64 res, mx; + sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, 0); + return res; +} + +/* +** Return the maximum amount of memory that has ever been +** checked out since either the beginning of this process +** or since the most recent reset. +*/ +SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ + sqlite3_int64 res, mx; + sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, resetFlag); + return mx; +} + +/* +** Trigger the alarm +*/ +static void sqlite3MallocAlarm(int nByte){ + if( mem0.alarmThreshold<=0 ) return; + sqlite3_mutex_leave(mem0.mutex); + sqlite3_release_memory(nByte); + sqlite3_mutex_enter(mem0.mutex); +} + +/* +** Do a memory allocation with statistics and alarms. Assume the +** lock is already held. +*/ +static void mallocWithAlarm(int n, void **pp){ + void *p; + int nFull; + assert( sqlite3_mutex_held(mem0.mutex) ); + assert( n>0 ); + + /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal + ** implementation of malloc_good_size(), which must be called in debug + ** mode and specifically when the DMD "Dark Matter Detector" is enabled + ** or else a crash results. Hence, do not attempt to optimize out the + ** following xRoundup() call. */ + nFull = sqlite3GlobalConfig.m.xRoundup(n); + +#ifdef SQLITE_MAX_MEMORY + if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){ + *pp = 0; + return; + } +#endif + + sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n); + if( mem0.alarmThreshold>0 ){ + sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); + if( nUsed >= mem0.alarmThreshold - nFull ){ + mem0.nearlyFull = 1; + sqlite3MallocAlarm(nFull); + }else{ + mem0.nearlyFull = 0; + } + } + p = sqlite3GlobalConfig.m.xMalloc(nFull); +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + if( p==0 && mem0.alarmThreshold>0 ){ + sqlite3MallocAlarm(nFull); + p = sqlite3GlobalConfig.m.xMalloc(nFull); + } +#endif + if( p ){ + nFull = sqlite3MallocSize(p); + sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull); + sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1); + } + *pp = p; +} + +/* +** Allocate memory. This routine is like sqlite3_malloc() except that it +** assumes the memory subsystem has already been initialized. +*/ +SQLITE_PRIVATE void *sqlite3Malloc(u64 n){ + void *p; + if( n==0 || n>=0x7fffff00 ){ + /* A memory allocation of a number of bytes which is near the maximum + ** signed integer value might cause an integer overflow inside of the + ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving + ** 255 bytes of overhead. SQLite itself will never use anything near + ** this amount. The only way to reach the limit is with sqlite3_malloc() */ + p = 0; + }else if( sqlite3GlobalConfig.bMemstat ){ + sqlite3_mutex_enter(mem0.mutex); + mallocWithAlarm((int)n, &p); + sqlite3_mutex_leave(mem0.mutex); + }else{ + p = sqlite3GlobalConfig.m.xMalloc((int)n); + } + assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */ + return p; +} + +/* +** This version of the memory allocation is for use by the application. +** First make sure the memory subsystem is initialized, then do the +** allocation. +*/ +SQLITE_API void *sqlite3_malloc(int n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return n<=0 ? 0 : sqlite3Malloc(n); +} +SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return sqlite3Malloc(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 +static int isLookaside(sqlite3 *db, void *p){ + return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd); +} +#else +#define isLookaside(A,B) 0 +#endif + +/* +** Return the size of a memory allocation previously obtained from +** sqlite3Malloc() or sqlite3_malloc(). +*/ +SQLITE_PRIVATE int sqlite3MallocSize(void *p){ + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + return sqlite3GlobalConfig.m.xSize(p); +} +SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ + assert( p!=0 ); + if( db==0 || !isLookaside(db,p) ){ +#ifdef SQLITE_DEBUG + if( db==0 ){ + assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + }else{ + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + } +#endif + return sqlite3GlobalConfig.m.xSize(p); + }else{ + assert( sqlite3_mutex_held(db->mutex) ); + return db->lookaside.sz; + } +} +SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ + assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + return p ? sqlite3GlobalConfig.m.xSize(p) : 0; +} + +/* +** Free memory previously obtained from sqlite3Malloc(). +*/ +SQLITE_API void sqlite3_free(void *p){ + if( p==0 ) return; /* IMP: R-49053-54554 */ + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); + if( sqlite3GlobalConfig.bMemstat ){ + sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p)); + sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); + sqlite3GlobalConfig.m.xFree(p); + sqlite3_mutex_leave(mem0.mutex); + }else{ + sqlite3GlobalConfig.m.xFree(p); + } +} + +/* +** Add the size of memory allocation "p" to the count in +** *db->pnBytesFreed. +*/ +static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ + *db->pnBytesFreed += sqlite3DbMallocSize(db,p); +} + +/* +** Free memory that might be associated with a particular database +** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. +** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. +*/ +SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){ + assert( db==0 || sqlite3_mutex_held(db->mutex) ); + assert( p!=0 ); + if( db ){ + if( db->pnBytesFreed ){ + measureAllocationSize(db, p); + return; + } + if( isLookaside(db, p) ){ + LookasideSlot *pBuf = (LookasideSlot*)p; +#ifdef SQLITE_DEBUG + /* Trash all content in the buffer being freed */ + memset(p, 0xaa, db->lookaside.sz); +#endif + pBuf->pNext = db->lookaside.pFree; + db->lookaside.pFree = pBuf; + db->lookaside.nOut--; + return; + } + } + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); + sqlite3_free(p); +} +SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ + assert( db==0 || sqlite3_mutex_held(db->mutex) ); + if( p ) sqlite3DbFreeNN(db, p); +} + +/* +** Change the size of an existing memory allocation +*/ +SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ + int nOld, nNew, nDiff; + void *pNew; + assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); + assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) ); + if( pOld==0 ){ + return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */ + } + if( nBytes==0 ){ + sqlite3_free(pOld); /* IMP: R-26507-47431 */ + return 0; + } + if( nBytes>=0x7fffff00 ){ + /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ + return 0; + } + nOld = sqlite3MallocSize(pOld); + /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second + ** argument to xRealloc is always a value returned by a prior call to + ** xRoundup. */ + nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes); + if( nOld==nNew ){ + pNew = pOld; + }else if( sqlite3GlobalConfig.bMemstat ){ + sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); + nDiff = nNew - nOld; + if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= + mem0.alarmThreshold-nDiff ){ + sqlite3MallocAlarm(nDiff); + } + pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); + if( pNew==0 && mem0.alarmThreshold>0 ){ + sqlite3MallocAlarm((int)nBytes); + pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); + } + if( pNew ){ + nNew = sqlite3MallocSize(pNew); + sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld); + } + sqlite3_mutex_leave(mem0.mutex); + }else{ + pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); + } + assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */ + return pNew; +} + +/* +** The public interface to sqlite3Realloc. Make sure that the memory +** subsystem is initialized prior to invoking sqliteRealloc. +*/ +SQLITE_API void *sqlite3_realloc(void *pOld, int n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + if( n<0 ) n = 0; /* IMP: R-26507-47431 */ + return sqlite3Realloc(pOld, n); +} +SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return sqlite3Realloc(pOld, n); +} + + +/* +** Allocate and zero memory. +*/ +SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){ + void *p = sqlite3Malloc(n); + if( p ){ + memset(p, 0, (size_t)n); + } + return p; +} + +/* +** Allocate and zero memory. If the allocation fails, make +** the mallocFailed flag in the connection pointer. +*/ +SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){ + void *p; + testcase( db==0 ); + p = sqlite3DbMallocRaw(db, n); + if( p ) memset(p, 0, (size_t)n); + return p; +} + + +/* Finish the work of sqlite3DbMallocRawNN for the unusual and +** slower case when the allocation cannot be fulfilled using lookaside. +*/ +static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){ + void *p; + assert( db!=0 ); + p = sqlite3Malloc(n); + if( !p ) sqlite3OomFault(db); + sqlite3MemdebugSetType(p, + (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); + return p; +} + +/* +** Allocate memory, either lookaside (if possible) or heap. +** If the allocation fails, set the mallocFailed flag in +** the connection pointer. +** +** If db!=0 and db->mallocFailed is true (indicating a prior malloc +** failure on the same database connection) then always return 0. +** Hence for a particular database connection, once malloc starts +** failing, it fails consistently until mallocFailed is reset. +** This is an important assumption. There are many places in the +** code that do things like this: +** +** int *a = (int*)sqlite3DbMallocRaw(db, 100); +** int *b = (int*)sqlite3DbMallocRaw(db, 200); +** if( b ) a[10] = 9; +** +** In other words, if a subsequent malloc (ex: "b") worked, it is assumed +** that all prior mallocs (ex: "a") worked too. +** +** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is +** not a NULL pointer. +*/ +SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){ + void *p; + if( db ) return sqlite3DbMallocRawNN(db, n); + p = sqlite3Malloc(n); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); + return p; +} +SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ +#ifndef SQLITE_OMIT_LOOKASIDE + LookasideSlot *pBuf; + assert( db!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); + assert( db->pnBytesFreed==0 ); + if( db->lookaside.bDisable==0 ){ + 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{ + 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( db->mallocFailed ){ + return 0; + } +#else + assert( db!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); + assert( db->pnBytesFreed==0 ); + if( db->mallocFailed ){ + return 0; + } +#endif + return dbMallocRawFinish(db, n); +} + +/* Forward declaration */ +static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n); + +/* +** Resize the block of memory pointed to by p to n bytes. If the +** resize fails, set the mallocFailed flag in the connection object. +*/ +SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ + assert( db!=0 ); + if( p==0 ) return sqlite3DbMallocRawNN(db, n); + assert( sqlite3_mutex_held(db->mutex) ); + if( isLookaside(db,p) && n<=db->lookaside.sz ) return p; + return dbReallocFinish(db, p, n); +} +static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){ + void *pNew = 0; + assert( db!=0 ); + assert( p!=0 ); + if( db->mallocFailed==0 ){ + if( isLookaside(db, p) ){ + pNew = sqlite3DbMallocRawNN(db, n); + if( pNew ){ + memcpy(pNew, p, db->lookaside.sz); + sqlite3DbFree(db, p); + } + }else{ + assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); + pNew = sqlite3_realloc64(p, n); + if( !pNew ){ + sqlite3OomFault(db); + } + sqlite3MemdebugSetType(pNew, + (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); + } + } + return pNew; +} + +/* +** Attempt to reallocate p. If the reallocation fails, then free p +** and set the mallocFailed flag in the database connection. +*/ +SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){ + void *pNew; + pNew = sqlite3DbRealloc(db, p, n); + if( !pNew ){ + sqlite3DbFree(db, p); + } + return pNew; +} + +/* +** Make a copy of a string in memory obtained from sqliteMalloc(). These +** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This +** is because when memory debugging is turned on, these two functions are +** called via macros that record the current file and line number in the +** ThreadData structure. +*/ +SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ + char *zNew; + size_t n; + if( z==0 ){ + return 0; + } + n = strlen(z) + 1; + zNew = sqlite3DbMallocRaw(db, n); + if( zNew ){ + memcpy(zNew, z, n); + } + return zNew; +} +SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ + char *zNew; + assert( db!=0 ); + if( z==0 ){ + return 0; + } + assert( (n&0x7fffffff)==n ); + zNew = sqlite3DbMallocRawNN(db, n+1); + if( zNew ){ + memcpy(zNew, z, (size_t)n); + zNew[n] = 0; + } + return zNew; +} + +/* +** Free any prior content in *pz and replace it with a copy of zNew. +*/ +SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ + sqlite3DbFree(db, *pz); + *pz = sqlite3DbStrDup(db, zNew); +} + +/* +** Call this routine to record the fact that an OOM (out-of-memory) error +** has happened. This routine will set db->mallocFailed, and also +** temporarily disable the lookaside memory allocator and interrupt +** any running VDBEs. +*/ +SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ + if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ + db->mallocFailed = 1; + if( db->nVdbeExec>0 ){ + db->u1.isInterrupted = 1; + } + db->lookaside.bDisable++; + } +} + +/* +** This routine reactivates the memory allocator and clears the +** db->mallocFailed flag as necessary. +** +** The memory allocator is not restarted if there are running +** VDBEs. +*/ +SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){ + if( db->mallocFailed && db->nVdbeExec==0 ){ + db->mallocFailed = 0; + db->u1.isInterrupted = 0; + assert( db->lookaside.bDisable>0 ); + db->lookaside.bDisable--; + } +} + +/* +** Take actions at the end of an API call to indicate an OOM error +*/ +static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ + sqlite3OomClear(db); + sqlite3Error(db, SQLITE_NOMEM); + return SQLITE_NOMEM_BKPT; +} + +/* +** This function must be called before exiting any API function (i.e. +** returning control to the user) that has called sqlite3_malloc or +** sqlite3_realloc. +** +** The returned value is normally a copy of the second argument to this +** function. However, if a malloc() failure has occurred since the previous +** invocation SQLITE_NOMEM is returned instead. +** +** If an OOM as occurred, then the connection error-code (the value +** returned by sqlite3_errcode()) is set to SQLITE_NOMEM. +*/ +SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ + /* If the db handle must hold the connection handle mutex here. + ** Otherwise the read (and possible write) of db->mallocFailed + ** is unsafe, as is the call to sqlite3Error(). + */ + assert( db!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); + if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ + return apiOomError(db); + } + return rc & db->errMask; +} + +/************** End of malloc.c **********************************************/ +/************** Begin file printf.c ******************************************/ +/* +** The "printf" code that follows dates from the 1980's. It is in +** the public domain. +** +************************************************************************** +** +** This file contains code for a set of "printf"-like routines. These +** routines format strings much like the printf() from the standard C +** library, though the implementation here has enhancements to support +** SQLite. +*/ +/* #include "sqliteInt.h" */ + +/* +** Conversion types fall into various categories as defined by the +** following enumeration. +*/ +#define etRADIX 0 /* non-decimal integer types. %x %o */ +#define etFLOAT 1 /* Floating point. %f */ +#define etEXP 2 /* Exponentional notation. %e and %E */ +#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */ +#define etSIZE 4 /* Return number of characters processed so far. %n */ +#define etSTRING 5 /* Strings. %s */ +#define etDYNSTRING 6 /* Dynamically allocated strings. %z */ +#define etPERCENT 7 /* Percent symbol. %% */ +#define etCHARX 8 /* Characters. %c */ +/* The rest are extensions, not normally found in printf() */ +#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ +#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', + NULL pointers replaced by SQL NULL. %Q */ +#define etTOKEN 11 /* a pointer to a Token structure */ +#define etSRCLIST 12 /* a pointer to a SrcList */ +#define etPOINTER 13 /* The %p conversion */ +#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ +#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ +#define etDECIMAL 16 /* %d or %u, but not %x, %o */ + +#define etINVALID 17 /* Any unrecognized conversion type */ + + +/* +** An "etByte" is an 8-bit unsigned value. +*/ +typedef unsigned char etByte; + +/* +** Each builtin conversion character (ex: the 'd' in "%d") is described +** by an instance of the following structure +*/ +typedef struct et_info { /* Information about each format field */ + char fmttype; /* The format field code letter */ + etByte base; /* The base for radix conversion */ + etByte flags; /* One or more of FLAG_ constants below */ + etByte type; /* Conversion paradigm */ + etByte charset; /* Offset into aDigits[] of the digits string */ + etByte prefix; /* Offset into aPrefix[] of the prefix string */ +} et_info; + +/* +** Allowed values for et_info.flags +*/ +#define FLAG_SIGNED 1 /* True if the value to convert is signed */ +#define FLAG_STRING 4 /* Allow infinite precision */ + + +/* +** The following table is searched linearly, so it is good to put the +** most frequently used conversion types first. +*/ +static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; +static const char aPrefix[] = "-x0\000X0"; +static const et_info fmtinfo[] = { + { 'd', 10, 1, etDECIMAL, 0, 0 }, + { 's', 0, 4, etSTRING, 0, 0 }, + { 'g', 0, 1, etGENERIC, 30, 0 }, + { 'z', 0, 4, etDYNSTRING, 0, 0 }, + { 'q', 0, 4, etSQLESCAPE, 0, 0 }, + { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, + { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, + { 'c', 0, 0, etCHARX, 0, 0 }, + { 'o', 8, 0, etRADIX, 0, 2 }, + { 'u', 10, 0, etDECIMAL, 0, 0 }, + { 'x', 16, 0, etRADIX, 16, 1 }, + { 'X', 16, 0, etRADIX, 0, 4 }, +#ifndef SQLITE_OMIT_FLOATING_POINT + { 'f', 0, 1, etFLOAT, 0, 0 }, + { 'e', 0, 1, etEXP, 30, 0 }, + { 'E', 0, 1, etEXP, 14, 0 }, + { 'G', 0, 1, etGENERIC, 14, 0 }, +#endif + { 'i', 10, 1, etDECIMAL, 0, 0 }, + { 'n', 0, 0, etSIZE, 0, 0 }, + { '%', 0, 0, etPERCENT, 0, 0 }, + { 'p', 16, 0, etPOINTER, 0, 1 }, + + /* All the rest are undocumented and are for internal use only */ + { 'T', 0, 0, etTOKEN, 0, 0 }, + { 'S', 0, 0, etSRCLIST, 0, 0 }, + { 'r', 10, 1, etORDINAL, 0, 0 }, +}; + +/* +** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point +** conversions will work. +*/ +#ifndef SQLITE_OMIT_FLOATING_POINT +/* +** "*val" is a double such that 0.1 <= *val < 10.0 +** Return the ascii code for the leading digit of *val, then +** multiply "*val" by 10.0 to renormalize. +** +** Example: +** input: *val = 3.14159 +** output: *val = 1.4159 function return = '3' +** +** The counter *cnt is incremented each time. After counter exceeds +** 16 (the number of significant digits in a 64-bit float) '0' is +** always returned. +*/ +static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ + int digit; + LONGDOUBLE_TYPE d; + if( (*cnt)<=0 ) return '0'; + (*cnt)--; + digit = (int)*val; + d = digit; + digit += '0'; + *val = (*val - d)*10.0; + return (char)digit; +} +#endif /* SQLITE_OMIT_FLOATING_POINT */ + +/* +** Set the StrAccum object to an error mode. +*/ +static void setStrAccumError(StrAccum *p, u8 eError){ + assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG ); + p->accError = eError; + p->nAlloc = 0; +} + +/* +** Extra argument values from a PrintfArguments object +*/ +static sqlite3_int64 getIntArg(PrintfArguments *p){ + if( p->nArg<=p->nUsed ) return 0; + return sqlite3_value_int64(p->apArg[p->nUsed++]); +} +static double getDoubleArg(PrintfArguments *p){ + if( p->nArg<=p->nUsed ) return 0.0; + return sqlite3_value_double(p->apArg[p->nUsed++]); +} +static char *getTextArg(PrintfArguments *p){ + if( p->nArg<=p->nUsed ) return 0; + return (char*)sqlite3_value_text(p->apArg[p->nUsed++]); +} + + +/* +** On machines with a small stack size, you can redefine the +** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired. +*/ +#ifndef SQLITE_PRINT_BUF_SIZE +# define SQLITE_PRINT_BUF_SIZE 70 +#endif +#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ + +/* +** Render a string given by "fmt" into the StrAccum object. +*/ +SQLITE_PRIVATE void sqlite3VXPrintf( + StrAccum *pAccum, /* Accumulate results here */ + const char *fmt, /* Format string */ + va_list ap /* arguments */ +){ + int c; /* Next character in the format string */ + char *bufpt; /* Pointer to the conversion buffer */ + int precision; /* Precision of the current field */ + int length; /* Length of the field */ + int idx; /* A general purpose loop counter */ + int width; /* Width of the current field */ + etByte flag_leftjustify; /* True if "-" flag is present */ + etByte flag_prefix; /* '+' or ' ' or 0 for prefix */ + etByte flag_alternateform; /* True if "#" flag is present */ + etByte flag_altform2; /* True if "!" flag is present */ + etByte flag_zeropad; /* True if field width constant starts with zero */ + etByte flag_long; /* 1 for the "l" flag, 2 for "ll", 0 by default */ + etByte done; /* Loop termination flag */ + etByte cThousand; /* Thousands separator for %d and %u */ + etByte xtype = etINVALID; /* Conversion paradigm */ + u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ + char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ + sqlite_uint64 longvalue; /* Value for integer types */ + LONGDOUBLE_TYPE realvalue; /* Value for real types */ + const et_info *infop; /* Pointer to the appropriate info structure */ + char *zOut; /* Rendering buffer */ + int nOut; /* Size of the rendering buffer */ + char *zExtra = 0; /* Malloced memory used by some conversion */ +#ifndef SQLITE_OMIT_FLOATING_POINT + int exp, e2; /* exponent of real numbers */ + int nsd; /* Number of significant digits returned */ + double rounder; /* Used for rounding floating point values */ + etByte flag_dp; /* True if decimal point should be shown */ + etByte flag_rtz; /* True if trailing zeros should be removed */ +#endif + PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ + char buf[etBUFSIZE]; /* Conversion buffer */ + + bufpt = 0; + if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){ + pArgList = va_arg(ap, PrintfArguments*); + bArgList = 1; + }else{ + bArgList = 0; + } + for(; (c=(*fmt))!=0; ++fmt){ + if( c!='%' ){ + bufpt = (char *)fmt; +#if HAVE_STRCHRNUL + fmt = strchrnul(fmt, '%'); +#else + do{ fmt++; }while( *fmt && *fmt != '%' ); +#endif + sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); + if( *fmt==0 ) break; + } + if( (c=(*++fmt))==0 ){ + sqlite3StrAccumAppend(pAccum, "%", 1); + break; + } + /* Find out what flags are present */ + flag_leftjustify = flag_prefix = cThousand = + flag_alternateform = flag_altform2 = flag_zeropad = 0; + done = 0; + do{ + switch( c ){ + case '-': flag_leftjustify = 1; break; + case '+': flag_prefix = '+'; break; + case ' ': flag_prefix = ' '; break; + case '#': flag_alternateform = 1; break; + case '!': flag_altform2 = 1; break; + case '0': flag_zeropad = 1; break; + case ',': cThousand = ','; break; + default: done = 1; break; + } + }while( !done && (c=(*++fmt))!=0 ); + /* Get the field width */ + if( c=='*' ){ + if( bArgList ){ + width = (int)getIntArg(pArgList); + }else{ + width = va_arg(ap,int); + } + if( width<0 ){ + flag_leftjustify = 1; + width = width >= -2147483647 ? -width : 0; + } + c = *++fmt; + }else{ + unsigned wx = 0; + while( c>='0' && c<='9' ){ + wx = wx*10 + c - '0'; + c = *++fmt; + } + testcase( wx>0x7fffffff ); + width = wx & 0x7fffffff; + } + assert( width>=0 ); +#ifdef SQLITE_PRINTF_PRECISION_LIMIT + if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ + width = SQLITE_PRINTF_PRECISION_LIMIT; + } +#endif + + /* Get the precision */ + if( c=='.' ){ + c = *++fmt; + if( c=='*' ){ + if( bArgList ){ + precision = (int)getIntArg(pArgList); + }else{ + precision = va_arg(ap,int); + } + c = *++fmt; + if( precision<0 ){ + precision = precision >= -2147483647 ? -precision : -1; + } + }else{ + unsigned px = 0; + while( c>='0' && c<='9' ){ + px = px*10 + c - '0'; + c = *++fmt; + } + testcase( px>0x7fffffff ); + precision = px & 0x7fffffff; + } + }else{ + precision = -1; + } + assert( precision>=(-1) ); +#ifdef SQLITE_PRINTF_PRECISION_LIMIT + if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ + precision = SQLITE_PRINTF_PRECISION_LIMIT; + } +#endif + + + /* Get the conversion type modifier */ + if( c=='l' ){ + flag_long = 1; + c = *++fmt; + if( c=='l' ){ + flag_long = 2; + c = *++fmt; + } + }else{ + flag_long = 0; + } + /* Fetch the info entry for the field */ + infop = &fmtinfo[0]; + xtype = etINVALID; + for(idx=0; idxtype; + break; + } + } + + /* + ** At this point, variables are initialized as follows: + ** + ** flag_alternateform TRUE if a '#' is present. + ** flag_altform2 TRUE if a '!' is present. + ** flag_prefix '+' or ' ' or zero + ** flag_leftjustify TRUE if a '-' is present or if the + ** field width was negative. + ** flag_zeropad TRUE if the width began with 0. + ** flag_long 1 for "l", 2 for "ll" + ** width The specified field width. This is + ** always non-negative. Zero is the default. + ** precision The specified precision. The default + ** is -1. + ** xtype The class of the conversion. + ** infop Pointer to the appropriate info struct. + */ + switch( xtype ){ + case etPOINTER: + flag_long = sizeof(char*)==sizeof(i64) ? 2 : + sizeof(char*)==sizeof(long int) ? 1 : 0; + /* Fall through into the next case */ + case etORDINAL: + case etRADIX: + cThousand = 0; + /* Fall through into the next case */ + case etDECIMAL: + if( infop->flags & FLAG_SIGNED ){ + i64 v; + if( bArgList ){ + v = getIntArg(pArgList); + }else if( flag_long ){ + if( flag_long==2 ){ + v = va_arg(ap,i64) ; + }else{ + v = va_arg(ap,long int); + } + }else{ + v = va_arg(ap,int); + } + if( v<0 ){ + if( v==SMALLEST_INT64 ){ + longvalue = ((u64)1)<<63; + }else{ + longvalue = -v; + } + prefix = '-'; + }else{ + longvalue = v; + prefix = flag_prefix; + } + }else{ + if( bArgList ){ + longvalue = (u64)getIntArg(pArgList); + }else if( flag_long ){ + if( flag_long==2 ){ + longvalue = va_arg(ap,u64); + }else{ + longvalue = va_arg(ap,unsigned long int); + } + }else{ + longvalue = va_arg(ap,unsigned int); + } + prefix = 0; + } + if( longvalue==0 ) flag_alternateform = 0; + if( flag_zeropad && precision=4 || (longvalue/10)%10==1 ){ + x = 0; + } + *(--bufpt) = zOrd[x*2+1]; + *(--bufpt) = zOrd[x*2]; + } + { + const char *cset = &aDigits[infop->charset]; + u8 base = infop->base; + do{ /* Convert to ascii */ + *(--bufpt) = cset[longvalue%base]; + longvalue = longvalue/base; + }while( longvalue>0 ); + } + length = (int)(&zOut[nOut-1]-bufpt); + while( precision>length ){ + *(--bufpt) = '0'; /* Zero pad */ + length++; + } + if( cThousand ){ + int nn = (length - 1)/3; /* Number of "," to insert */ + int ix = (length - 1)%3 + 1; + bufpt -= nn; + for(idx=0; nn>0; idx++){ + bufpt[idx] = bufpt[idx+nn]; + ix--; + if( ix==0 ){ + bufpt[++idx] = cThousand; + nn--; + ix = 3; + } + } + } + if( prefix ) *(--bufpt) = prefix; /* Add sign */ + if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ + const char *pre; + char x; + pre = &aPrefix[infop->prefix]; + for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; + } + length = (int)(&zOut[nOut-1]-bufpt); + break; + case etFLOAT: + case etEXP: + case etGENERIC: + if( bArgList ){ + realvalue = getDoubleArg(pArgList); + }else{ + realvalue = va_arg(ap,double); + } +#ifdef SQLITE_OMIT_FLOATING_POINT + length = 0; +#else + if( precision<0 ) precision = 6; /* Set default precision */ + if( realvalue<0.0 ){ + realvalue = -realvalue; + prefix = '-'; + }else{ + prefix = flag_prefix; + } + if( xtype==etGENERIC && precision>0 ) precision--; + testcase( precision>0xfff ); + for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} + if( xtype==etFLOAT ) realvalue += rounder; + /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ + exp = 0; + if( sqlite3IsNaN((double)realvalue) ){ + bufpt = "NaN"; + length = 3; + break; + } + if( realvalue>0.0 ){ + LONGDOUBLE_TYPE scale = 1.0; + while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;} + while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; } + while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; } + realvalue /= scale; + while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; } + while( realvalue<1.0 ){ realvalue *= 10.0; exp--; } + if( exp>350 ){ + bufpt = buf; + buf[0] = prefix; + memcpy(buf+(prefix!=0),"Inf",4); + length = 3+(prefix!=0); + break; + } + } + bufpt = buf; + /* + ** If the field type is etGENERIC, then convert to either etEXP + ** or etFLOAT, as appropriate. + */ + if( xtype!=etFLOAT ){ + realvalue += rounder; + if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } + } + if( xtype==etGENERIC ){ + flag_rtz = !flag_alternateform; + if( exp<-4 || exp>precision ){ + xtype = etEXP; + }else{ + precision = precision - exp; + xtype = etFLOAT; + } + }else{ + flag_rtz = flag_altform2; + } + if( xtype==etEXP ){ + e2 = 0; + }else{ + e2 = exp; + } + if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){ + bufpt = zExtra + = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 ); + if( bufpt==0 ){ + setStrAccumError(pAccum, STRACCUM_NOMEM); + return; + } + } + zOut = bufpt; + nsd = 16 + flag_altform2*10; + flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; + /* The sign in front of the number */ + if( prefix ){ + *(bufpt++) = prefix; + } + /* Digits prior to the decimal point */ + if( e2<0 ){ + *(bufpt++) = '0'; + }else{ + for(; e2>=0; e2--){ + *(bufpt++) = et_getdigit(&realvalue,&nsd); + } + } + /* The decimal point */ + if( flag_dp ){ + *(bufpt++) = '.'; + } + /* "0" digits after the decimal point but before the first + ** significant digit of the number */ + for(e2++; e2<0; precision--, e2++){ + assert( precision>0 ); + *(bufpt++) = '0'; + } + /* Significant digits after the decimal point */ + while( (precision--)>0 ){ + *(bufpt++) = et_getdigit(&realvalue,&nsd); + } + /* Remove trailing zeros and the "." if no digits follow the "." */ + if( flag_rtz && flag_dp ){ + while( bufpt[-1]=='0' ) *(--bufpt) = 0; + assert( bufpt>zOut ); + if( bufpt[-1]=='.' ){ + if( flag_altform2 ){ + *(bufpt++) = '0'; + }else{ + *(--bufpt) = 0; + } + } + } + /* Add the "eNNN" suffix */ + if( xtype==etEXP ){ + *(bufpt++) = aDigits[infop->charset]; + if( exp<0 ){ + *(bufpt++) = '-'; exp = -exp; + }else{ + *(bufpt++) = '+'; + } + if( exp>=100 ){ + *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */ + exp %= 100; + } + *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ + *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ + } + *bufpt = 0; + + /* The converted number is in buf[] and zero terminated. Output it. + ** Note that the number is in the usual order, not reversed as with + ** integer conversions. */ + length = (int)(bufpt-zOut); + bufpt = zOut; + + /* Special case: Add leading zeros if the flag_zeropad flag is + ** set and we are not left justified */ + if( flag_zeropad && !flag_leftjustify && length < width){ + int i; + int nPad = width - length; + for(i=width; i>=nPad; i--){ + bufpt[i] = bufpt[i-nPad]; + } + i = prefix!=0; + while( nPad-- ) bufpt[i++] = '0'; + length = width; + } +#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */ + break; + case etSIZE: + if( !bArgList ){ + *(va_arg(ap,int*)) = pAccum->nChar; + } + length = width = 0; + break; + case etPERCENT: + buf[0] = '%'; + bufpt = buf; + length = 1; + break; + case etCHARX: + if( bArgList ){ + bufpt = getTextArg(pArgList); + c = bufpt ? bufpt[0] : 0; + }else{ + c = va_arg(ap,int); + } + if( precision>1 ){ + width -= precision-1; + if( width>1 && !flag_leftjustify ){ + sqlite3AppendChar(pAccum, width-1, ' '); + width = 0; + } + sqlite3AppendChar(pAccum, precision-1, c); + } + length = 1; + buf[0] = c; + bufpt = buf; + break; + case etSTRING: + case etDYNSTRING: + if( bArgList ){ + bufpt = getTextArg(pArgList); + xtype = etSTRING; + }else{ + bufpt = va_arg(ap,char*); + } + if( bufpt==0 ){ + bufpt = ""; + }else if( xtype==etDYNSTRING ){ + zExtra = bufpt; + } + if( precision>=0 ){ + for(length=0; lengthetBUFSIZE ){ + bufpt = zExtra = sqlite3Malloc( n ); + if( bufpt==0 ){ + setStrAccumError(pAccum, STRACCUM_NOMEM); + return; + } + }else{ + bufpt = buf; + } + j = 0; + if( needQuote ) bufpt[j++] = q; + k = i; + for(i=0; i=0 && precisionprintfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; + pToken = va_arg(ap, Token*); + assert( bArgList==0 ); + if( pToken && pToken->n ){ + sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n); + } + length = width = 0; + break; + } + case etSRCLIST: { + SrcList *pSrc; + int k; + struct SrcList_item *pItem; + if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; + pSrc = va_arg(ap, SrcList*); + k = va_arg(ap, int); + pItem = &pSrc->a[k]; + assert( bArgList==0 ); + assert( k>=0 && knSrc ); + if( pItem->zDatabase ){ + sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase); + sqlite3StrAccumAppend(pAccum, ".", 1); + } + sqlite3StrAccumAppendAll(pAccum, pItem->zName); + length = width = 0; + break; + } + default: { + assert( xtype==etINVALID ); + return; + } + }/* End switch over the format type */ + /* + ** The text of the conversion is pointed to by "bufpt" and is + ** "length" characters long. The field width is "width". Do + ** the output. + */ + width -= length; + if( width>0 ){ + if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); + sqlite3StrAccumAppend(pAccum, bufpt, length); + if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); + }else{ + sqlite3StrAccumAppend(pAccum, bufpt, length); + } + + if( zExtra ){ + sqlite3DbFree(pAccum->db, zExtra); + zExtra = 0; + } + }/* End for loop over the format string */ +} /* End of function */ + +/* +** Enlarge the memory allocation on a StrAccum object so that it is +** able to accept at least N more bytes of text. +** +** Return the number of bytes of text that StrAccum is able to accept +** after the attempted enlargement. The value returned might be zero. +*/ +static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ + char *zNew; + assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ + if( p->accError ){ + testcase(p->accError==STRACCUM_TOOBIG); + testcase(p->accError==STRACCUM_NOMEM); + return 0; + } + if( p->mxAlloc==0 ){ + N = p->nAlloc - p->nChar - 1; + setStrAccumError(p, STRACCUM_TOOBIG); + return 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, + ** to avoid having to call this routine too often */ + szNew += p->nChar; + } + if( szNew > p->mxAlloc ){ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_TOOBIG); + return 0; + }else{ + p->nAlloc = (int)szNew; + } + if( p->db ){ + zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); + }else{ + zNew = sqlite3_realloc64(zOld, p->nAlloc); + } + if( zNew ){ + assert( p->zText!=0 || p->nChar==0 ); + if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); + p->zText = zNew; + p->nAlloc = sqlite3DbMallocSize(p->db, zNew); + p->printfFlags |= SQLITE_PRINTF_MALLOCED; + }else{ + sqlite3StrAccumReset(p); + setStrAccumError(p, STRACCUM_NOMEM); + return 0; + } + } + return N; +} + +/* +** Append N copies of character c to the given string buffer. +*/ +SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ + testcase( p->nChar + (i64)N > 0x7fffffff ); + 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; +} + +/* +** The StrAccum "p" is not large enough to accept N new bytes of z[]. +** So enlarge if first, then do the append. +** +** This is a helper routine to sqlite3StrAccumAppend() that does special-case +** work (enlarging the buffer) using tail recursion, so that the +** sqlite3StrAccumAppend() routine can use fast calling semantics. +*/ +static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ + N = sqlite3StrAccumEnlarge(p, N); + if( N>0 ){ + memcpy(&p->zText[p->nChar], z, N); + p->nChar += N; + } + assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); +} + +/* +** Append N bytes of text from z to the StrAccum object. Increase the +** size of the memory allocation for StrAccum if necessary. +*/ +SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ + assert( z!=0 || N==0 ); + assert( p->zText!=0 || p->nChar==0 || p->accError ); + assert( N>=0 ); + assert( p->accError==0 || p->nAlloc==0 ); + if( p->nChar+N >= p->nAlloc ){ + enlargeAndAppend(p,z,N); + }else if( N ){ + assert( p->zText ); + p->nChar += N; + memcpy(&p->zText[p->nChar-N], z, N); + } +} + +/* +** Append the complete text of zero-terminated string z[] to the p string. +*/ +SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ + sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z)); +} + + +/* +** Finish off a string by making sure it is zero-terminated. +** Return a pointer to the resulting string. Return a NULL +** pointer if any kind of error was encountered. +*/ +static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ + 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); + p->printfFlags |= SQLITE_PRINTF_MALLOCED; + }else{ + setStrAccumError(p, STRACCUM_NOMEM); + } + return p->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); + } + } + return p->zText; +} + +/* +** 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; + } + p->zText = 0; +} + +/* +** Initialize a string accumulator. +** +** p: The accumulator to be initialized. +** db: Pointer to a database connection. May be NULL. Lookaside +** memory is used if not NULL. db->mallocFailed is set appropriately +** when not NULL. +** zBase: An initial buffer. May be NULL in which case the initial buffer +** is malloced. +** n: Size of zBase in bytes. If total space requirements never exceed +** n then no memory allocations ever occur. +** mx: Maximum number of bytes to accumulate. If mx==0 then no memory +** allocations will ever occur. +*/ +SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ + p->zText = p->zBase = zBase; + p->db = db; + p->nChar = 0; + p->nAlloc = n; + p->mxAlloc = mx; + p->accError = 0; + p->printfFlags = 0; +} + +/* +** Print into memory obtained from sqliteMalloc(). Use the internal +** %-conversion extensions. +*/ +SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ + char *z; + char zBase[SQLITE_PRINT_BUF_SIZE]; + StrAccum acc; + assert( db!=0 ); + sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), + db->aLimit[SQLITE_LIMIT_LENGTH]); + acc.printfFlags = SQLITE_PRINTF_INTERNAL; + sqlite3VXPrintf(&acc, zFormat, ap); + z = sqlite3StrAccumFinish(&acc); + if( acc.accError==STRACCUM_NOMEM ){ + sqlite3OomFault(db); + } + return z; +} + +/* +** Print into memory obtained from sqliteMalloc(). Use the internal +** %-conversion extensions. +*/ +SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ + va_list ap; + char *z; + va_start(ap, zFormat); + z = sqlite3VMPrintf(db, zFormat, ap); + va_end(ap); + return z; +} + +/* +** Print into memory obtained from sqlite3_malloc(). Omit the internal +** %-conversion extensions. +*/ +SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ + char *z; + char zBase[SQLITE_PRINT_BUF_SIZE]; + StrAccum acc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( zFormat==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); + sqlite3VXPrintf(&acc, zFormat, ap); + z = sqlite3StrAccumFinish(&acc); + return z; +} + +/* +** Print into memory obtained from sqlite3_malloc()(). Omit the internal +** %-conversion extensions. +*/ +SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){ + va_list ap; + char *z; +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + va_start(ap, zFormat); + z = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + return z; +} + +/* +** sqlite3_snprintf() works like snprintf() except that it ignores the +** current locale settings. This is important for SQLite because we +** are not able to use a "," as the decimal point in place of "." as +** specified by some locales. +** +** Oops: The first two arguments of sqlite3_snprintf() are backwards +** from the snprintf() standard. Unfortunately, it is too late to change +** this without breaking compatibility, so we just have to live with the +** mistake. +** +** sqlite3_vsnprintf() is the varargs version. +*/ +SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ + StrAccum acc; + if( n<=0 ) return zBuf; +#ifdef SQLITE_ENABLE_API_ARMOR + if( zBuf==0 || zFormat==0 ) { + (void)SQLITE_MISUSE_BKPT; + if( zBuf ) zBuf[0] = 0; + return zBuf; + } +#endif + sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); + sqlite3VXPrintf(&acc, zFormat, ap); + zBuf[acc.nChar] = 0; + return zBuf; +} +SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ + char *z; + va_list ap; + va_start(ap,zFormat); + z = sqlite3_vsnprintf(n, zBuf, zFormat, ap); + va_end(ap); + return z; +} + +/* +** This is the routine that actually formats the sqlite3_log() message. +** We house it in a separate routine from sqlite3_log() to avoid using +** stack space on small-stack systems when logging is disabled. +** +** sqlite3_log() must render into a static buffer. It cannot dynamically +** allocate memory because it might be called while the memory allocator +** mutex is held. +** +** sqlite3VXPrintf() might ask for *temporary* memory allocations for +** certain format characters (%q) or for very large precisions or widths. +** Care must be taken that any sqlite3_log() calls that occur while the +** memory mutex is held do not use these mechanisms. +*/ +static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ + StrAccum acc; /* String accumulator */ + char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ + + sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); + sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, + sqlite3StrAccumFinish(&acc)); +} + +/* +** Format and write a message to the log if logging is enabled. +*/ +SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){ + va_list ap; /* Vararg list */ + if( sqlite3GlobalConfig.xLog ){ + va_start(ap, zFormat); + renderLogMsg(iErrCode, zFormat, ap); + va_end(ap); + } +} + +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) +/* +** A version of printf() that understands %lld. Used for debugging. +** The printf() built into some versions of windows does not understand %lld +** and segfaults if you give it a long long int. +*/ +SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ + va_list ap; + StrAccum acc; + char zBuf[500]; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); + va_start(ap,zFormat); + sqlite3VXPrintf(&acc, zFormat, ap); + va_end(ap); + sqlite3StrAccumFinish(&acc); + fprintf(stdout,"%s", zBuf); + fflush(stdout); +} +#endif + + +/* +** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument +** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats. +*/ +SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){ + va_list ap; + va_start(ap,zFormat); + sqlite3VXPrintf(p, zFormat, ap); + va_end(ap); +} + +/************** End of printf.c **********************************************/ +/************** Begin file treeview.c ****************************************/ +/* +** 2015-06-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 file contains C code to implement the TreeView debugging routines. +** These routines print a parse tree to standard output for debugging and +** analysis. +** +** The interfaces in this file is only available when compiling +** with SQLITE_DEBUG. +*/ +/* #include "sqliteInt.h" */ +#ifdef SQLITE_DEBUG + +/* +** Add a new subitem to the tree. The moreToFollow flag indicates that this +** is not the last item in the tree. +*/ +static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ + if( p==0 ){ + p = sqlite3_malloc64( sizeof(*p) ); + if( p==0 ) return 0; + memset(p, 0, sizeof(*p)); + }else{ + p->iLevel++; + } + assert( moreToFollow==0 || moreToFollow==1 ); + if( p->iLevelbLine) ) p->bLine[p->iLevel] = moreToFollow; + return p; +} + +/* +** Finished with one layer of the tree +*/ +static void sqlite3TreeViewPop(TreeView *p){ + if( p==0 ) return; + p->iLevel--; + if( p->iLevel<0 ) sqlite3_free(p); +} + +/* +** Generate a single line of output for the tree, with a prefix that contains +** all the appropriate tree lines +*/ +static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ + va_list ap; + int i; + StrAccum acc; + char zBuf[500]; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); + if( p ){ + for(i=0; iiLevel && ibLine)-1; i++){ + sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); + } + sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); + } + va_start(ap, zFormat); + sqlite3VXPrintf(&acc, zFormat, ap); + va_end(ap); + assert( acc.nChar>0 ); + if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); + sqlite3StrAccumFinish(&acc); + fprintf(stdout,"%s", zBuf); + fflush(stdout); +} + +/* +** Shorthand for starting a new tree item that consists of a single label +*/ +static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ + p = sqlite3TreeViewPush(p, moreFollows); + sqlite3TreeViewLine(p, "%s", zLabel); +} + +/* +** Generate a human-readable description of a WITH clause. +*/ +SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){ + int i; + if( pWith==0 ) return; + if( pWith->nCte==0 ) return; + if( pWith->pOuter ){ + sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter); + }else{ + sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith); + } + if( pWith->nCte>0 ){ + pView = sqlite3TreeViewPush(pView, 1); + for(i=0; inCte; i++){ + StrAccum x; + char zLine[1000]; + const struct Cte *pCte = &pWith->a[i]; + sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); + sqlite3XPrintf(&x, "%s", pCte->zName); + if( pCte->pCols && pCte->pCols->nExpr>0 ){ + char cSep = '('; + int j; + for(j=0; jpCols->nExpr; j++){ + sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName); + cSep = ','; + } + sqlite3XPrintf(&x, ")"); + } + sqlite3XPrintf(&x, " AS"); + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, inCte-1); + sqlite3TreeViewSelect(pView, pCte->pSelect, 0); + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); + } +} + + +/* +** Generate a human-readable description of a Select object. +*/ +SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ + int n = 0; + int cnt = 0; + if( p==0 ){ + sqlite3TreeViewLine(pView, "nil-SELECT"); + return; + } + pView = sqlite3TreeViewPush(pView, moreToFollow); + if( p->pWith ){ + sqlite3TreeViewWith(pView, p->pWith, 1); + cnt = 1; + sqlite3TreeViewPush(pView, 1); + } + do{ + sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, + (int)p->nSelectRow + ); + if( cnt++ ) sqlite3TreeViewPop(pView); + if( p->pPrior ){ + n = 1000; + }else{ + n = 0; + if( p->pSrc && p->pSrc->nSrc ) n++; + if( p->pWhere ) n++; + if( p->pGroupBy ) n++; + if( p->pHaving ) n++; + if( p->pOrderBy ) n++; + if( p->pLimit ) n++; + if( p->pOffset ) n++; + } + sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); + if( p->pSrc && p->pSrc->nSrc ){ + int i; + pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewLine(pView, "FROM"); + for(i=0; ipSrc->nSrc; i++){ + struct SrcList_item *pItem = &p->pSrc->a[i]; + StrAccum x; + char zLine[100]; + sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); + sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor); + if( pItem->zDatabase ){ + sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName); + }else if( pItem->zName ){ + sqlite3XPrintf(&x, " %s", pItem->zName); + } + if( pItem->pTab ){ + sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName); + } + if( pItem->zAlias ){ + sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias); + } + if( pItem->fg.jointype & JT_LEFT ){ + sqlite3XPrintf(&x, " LEFT-JOIN"); + } + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + if( pItem->fg.isTabFunc ){ + sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); + } + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); + } + if( p->pWhere ){ + sqlite3TreeViewItem(pView, "WHERE", (n--)>0); + sqlite3TreeViewExpr(pView, p->pWhere, 0); + sqlite3TreeViewPop(pView); + } + if( p->pGroupBy ){ + sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); + } + if( p->pHaving ){ + sqlite3TreeViewItem(pView, "HAVING", (n--)>0); + sqlite3TreeViewExpr(pView, p->pHaving, 0); + sqlite3TreeViewPop(pView); + } + if( p->pOrderBy ){ + sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); + } + if( p->pLimit ){ + sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); + sqlite3TreeViewExpr(pView, p->pLimit, 0); + sqlite3TreeViewPop(pView); + } + if( p->pOffset ){ + sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); + sqlite3TreeViewExpr(pView, p->pOffset, 0); + sqlite3TreeViewPop(pView); + } + if( p->pPrior ){ + const char *zOp = "UNION"; + switch( p->op ){ + case TK_ALL: zOp = "UNION ALL"; break; + case TK_INTERSECT: zOp = "INTERSECT"; break; + case TK_EXCEPT: zOp = "EXCEPT"; break; + } + sqlite3TreeViewItem(pView, zOp, 1); + } + p = p->pPrior; + }while( p!=0 ); + sqlite3TreeViewPop(pView); +} + +/* +** Generate a human-readable explanation of an expression tree. +*/ +SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ + const char *zBinOp = 0; /* Binary operator */ + const char *zUniOp = 0; /* Unary operator */ + char zFlgs[60]; + pView = sqlite3TreeViewPush(pView, moreToFollow); + if( pExpr==0 ){ + sqlite3TreeViewLine(pView, "nil"); + sqlite3TreeViewPop(pView); + return; + } + if( pExpr->flags ){ + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d", + pExpr->flags, pExpr->iRightJoinTable); + }else{ + sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags); + } + }else{ + zFlgs[0] = 0; + } + switch( pExpr->op ){ + case TK_AGG_COLUMN: { + sqlite3TreeViewLine(pView, "AGG{%d:%d}%s", + pExpr->iTable, pExpr->iColumn, zFlgs); + break; + } + case TK_COLUMN: { + if( pExpr->iTable<0 ){ + /* This only happens when coding check constraints */ + sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs); + }else{ + sqlite3TreeViewLine(pView, "{%d:%d}%s", + pExpr->iTable, pExpr->iColumn, zFlgs); + } + break; + } + case TK_INTEGER: { + if( pExpr->flags & EP_IntValue ){ + sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); + }else{ + sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); + } + break; + } +#ifndef SQLITE_OMIT_FLOATING_POINT + case TK_FLOAT: { + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); + break; + } +#endif + case TK_STRING: { + sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); + break; + } + case TK_NULL: { + sqlite3TreeViewLine(pView,"NULL"); + break; + } +#ifndef SQLITE_OMIT_BLOB_LITERAL + case TK_BLOB: { + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); + break; + } +#endif + case TK_VARIABLE: { + sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", + pExpr->u.zToken, pExpr->iColumn); + break; + } + case TK_REGISTER: { + sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); + break; + } + case TK_ID: { + sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); + break; + } +#ifndef SQLITE_OMIT_CAST + case TK_CAST: { + /* Expressions of the form: CAST(pLeft AS token) */ + sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } +#endif /* SQLITE_OMIT_CAST */ + case TK_LT: zBinOp = "LT"; break; + case TK_LE: zBinOp = "LE"; break; + case TK_GT: zBinOp = "GT"; break; + case TK_GE: zBinOp = "GE"; break; + case TK_NE: zBinOp = "NE"; break; + case TK_EQ: zBinOp = "EQ"; break; + case TK_IS: zBinOp = "IS"; break; + case TK_ISNOT: zBinOp = "ISNOT"; break; + case TK_AND: zBinOp = "AND"; break; + case TK_OR: zBinOp = "OR"; break; + case TK_PLUS: zBinOp = "ADD"; break; + case TK_STAR: zBinOp = "MUL"; break; + case TK_MINUS: zBinOp = "SUB"; break; + case TK_REM: zBinOp = "REM"; break; + case TK_BITAND: zBinOp = "BITAND"; break; + case TK_BITOR: zBinOp = "BITOR"; break; + case TK_SLASH: zBinOp = "DIV"; break; + case TK_LSHIFT: zBinOp = "LSHIFT"; break; + case TK_RSHIFT: zBinOp = "RSHIFT"; break; + case TK_CONCAT: zBinOp = "CONCAT"; break; + case TK_DOT: zBinOp = "DOT"; break; + + case TK_UMINUS: zUniOp = "UMINUS"; break; + case TK_UPLUS: zUniOp = "UPLUS"; break; + case TK_BITNOT: zUniOp = "BITNOT"; break; + case TK_NOT: zUniOp = "NOT"; break; + case TK_ISNULL: zUniOp = "ISNULL"; break; + case TK_NOTNULL: zUniOp = "NOTNULL"; break; + + case TK_SPAN: { + sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + + case TK_COLLATE: { + sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + + case TK_AGG_FUNCTION: + case TK_FUNCTION: { + ExprList *pFarg; /* List of function arguments */ + if( ExprHasProperty(pExpr, EP_TokenOnly) ){ + pFarg = 0; + }else{ + pFarg = pExpr->x.pList; + } + if( pExpr->op==TK_AGG_FUNCTION ){ + sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", + pExpr->op2, pExpr->u.zToken); + }else{ + sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); + } + if( pFarg ){ + sqlite3TreeViewExprList(pView, pFarg, 0, 0); + } + break; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_EXISTS: { + sqlite3TreeViewLine(pView, "EXISTS-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); + break; + } + case TK_SELECT: { + sqlite3TreeViewLine(pView, "SELECT-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); + break; + } + case TK_IN: { + sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); + }else{ + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); + } + break; + } +#endif /* SQLITE_OMIT_SUBQUERY */ + + /* + ** x BETWEEN y AND z + ** + ** This is equivalent to + ** + ** x>=y AND x<=z + ** + ** X is stored in pExpr->pLeft. + ** Y is stored in pExpr->pList->a[0].pExpr. + ** Z is stored in pExpr->pList->a[1].pExpr. + */ + case TK_BETWEEN: { + Expr *pX = pExpr->pLeft; + Expr *pY = pExpr->x.pList->a[0].pExpr; + Expr *pZ = pExpr->x.pList->a[1].pExpr; + sqlite3TreeViewLine(pView, "BETWEEN"); + sqlite3TreeViewExpr(pView, pX, 1); + sqlite3TreeViewExpr(pView, pY, 1); + sqlite3TreeViewExpr(pView, pZ, 0); + break; + } + case TK_TRIGGER: { + /* If the opcode is TK_TRIGGER, then the expression is a reference + ** to a column in the new.* or old.* pseudo-tables available to + ** trigger programs. In this case Expr.iTable is set to 1 for the + ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn + ** is set to the column of the pseudo-table to read, or to -1 to + ** read the rowid field. + */ + sqlite3TreeViewLine(pView, "%s(%d)", + pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); + break; + } + case TK_CASE: { + sqlite3TreeViewLine(pView, "CASE"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); + break; + } +#ifndef SQLITE_OMIT_TRIGGER + case TK_RAISE: { + const char *zType = "unk"; + switch( pExpr->affinity ){ + case OE_Rollback: zType = "rollback"; break; + case OE_Abort: zType = "abort"; break; + case OE_Fail: zType = "fail"; break; + case OE_Ignore: zType = "ignore"; break; + } + sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); + break; + } +#endif + case TK_MATCH: { + sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", + pExpr->iTable, pExpr->iColumn, zFlgs); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); + break; + } + case TK_VECTOR: { + sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR"); + break; + } + case TK_SELECT_COLUMN: { + sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn); + sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); + break; + } + case TK_IF_NULL_ROW: { + sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + default: { + sqlite3TreeViewLine(pView, "op=%d", pExpr->op); + break; + } + } + if( zBinOp ){ + sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); + }else if( zUniOp ){ + sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + } + sqlite3TreeViewPop(pView); +} + + +/* +** Generate a human-readable explanation of an expression list. +*/ +SQLITE_PRIVATE void sqlite3TreeViewBareExprList( + TreeView *pView, + const ExprList *pList, + const char *zLabel +){ + if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; + if( pList==0 ){ + sqlite3TreeViewLine(pView, "%s (empty)", zLabel); + }else{ + int i; + sqlite3TreeViewLine(pView, "%s", zLabel); + for(i=0; inExpr; i++){ + int j = pList->a[i].u.x.iOrderByCol; + if( j ){ + sqlite3TreeViewPush(pView, 0); + sqlite3TreeViewLine(pView, "iOrderByCol=%d", j); + } + sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); + if( j ) sqlite3TreeViewPop(pView); + } + } +} +SQLITE_PRIVATE void sqlite3TreeViewExprList( + TreeView *pView, + const ExprList *pList, + u8 moreToFollow, + const char *zLabel +){ + pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewBareExprList(pView, pList, zLabel); + sqlite3TreeViewPop(pView); +} + +#endif /* SQLITE_DEBUG */ + +/************** End of treeview.c ********************************************/ +/************** Begin file random.c ******************************************/ +/* +** 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 a pseudo-random number +** generator (PRNG) for SQLite. +** +** Random numbers are used by some of the database backends in order +** to generate random integer keys for tables or random filenames. +*/ +/* #include "sqliteInt.h" */ + + +/* All threads share a single random number generator. +** This structure is the current state of the generator. +*/ +static SQLITE_WSD struct sqlite3PrngType { + unsigned char isInit; /* True if initialized */ + unsigned char i, j; /* State variables */ + unsigned char s[256]; /* State variables */ +} sqlite3Prng; + +/* +** Return N random bytes. +*/ +SQLITE_API void sqlite3_randomness(int N, void *pBuf){ + unsigned char t; + unsigned char *zBuf = pBuf; + + /* The "wsdPrng" macro will resolve to the pseudo-random number generator + ** state vector. If writable static data is unsupported on the target, + ** we have to locate the state vector at run-time. In the more common + ** case where writable static data is supported, wsdPrng can refer directly + ** to the "sqlite3Prng" state vector declared above. + */ +#ifdef SQLITE_OMIT_WSD + struct sqlite3PrngType *p = &GLOBAL(struct sqlite3PrngType, sqlite3Prng); +# define wsdPrng p[0] +#else +# define wsdPrng sqlite3Prng +#endif + +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex; +#endif + +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return; +#endif + +#if SQLITE_THREADSAFE + mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); +#endif + + sqlite3_mutex_enter(mutex); + if( N<=0 || pBuf==0 ){ + wsdPrng.isInit = 0; + sqlite3_mutex_leave(mutex); + return; + } + + /* Initialize the state of the random number generator once, + ** the first time this routine is called. The seed value does + ** not need to contain a lot of randomness since we are not + ** trying to do secure encryption or anything like that... + ** + ** Nothing in this file or anywhere else in SQLite does any kind of + ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random + ** number generator) not as an encryption device. + */ + if( !wsdPrng.isInit ){ + int i; + char k[256]; + wsdPrng.j = 0; + wsdPrng.i = 0; + sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k); + for(i=0; i<256; i++){ + wsdPrng.s[i] = (u8)i; + } + for(i=0; i<256; i++){ + wsdPrng.j += wsdPrng.s[i] + k[i]; + t = wsdPrng.s[wsdPrng.j]; + wsdPrng.s[wsdPrng.j] = wsdPrng.s[i]; + wsdPrng.s[i] = t; + } + wsdPrng.isInit = 1; + } + + assert( N>0 ); + do{ + wsdPrng.i++; + t = wsdPrng.s[wsdPrng.i]; + wsdPrng.j += t; + wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; + wsdPrng.s[wsdPrng.j] = t; + t += wsdPrng.s[wsdPrng.i]; + *(zBuf++) = wsdPrng.s[t]; + }while( --N ); + sqlite3_mutex_leave(mutex); +} + +#ifndef SQLITE_UNTESTABLE +/* +** For testing purposes, we sometimes want to preserve the state of +** PRNG and restore the PRNG to its saved state at a later time, or +** to reset the PRNG to its initial state. These routines accomplish +** those tasks. +** +** The sqlite3_test_control() interface calls these routines to +** control the PRNG. +*/ +static SQLITE_WSD struct sqlite3PrngType sqlite3SavedPrng; +SQLITE_PRIVATE void sqlite3PrngSaveState(void){ + memcpy( + &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), + &GLOBAL(struct sqlite3PrngType, sqlite3Prng), + sizeof(sqlite3Prng) + ); +} +SQLITE_PRIVATE void sqlite3PrngRestoreState(void){ + memcpy( + &GLOBAL(struct sqlite3PrngType, sqlite3Prng), + &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), + sizeof(sqlite3Prng) + ); +} +#endif /* SQLITE_UNTESTABLE */ + +/************** End of random.c **********************************************/ +/************** Begin file threads.c *****************************************/ +/* +** 2012 July 21 +** +** 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 presents a simple cross-platform threading interface for +** use internally by SQLite. +** +** A "thread" can be created using sqlite3ThreadCreate(). This thread +** runs independently of its creator until it is joined using +** sqlite3ThreadJoin(), at which point it terminates. +** +** Threads do not have to be real. It could be that the work of the +** "thread" is done by the main thread at either the sqlite3ThreadCreate() +** or sqlite3ThreadJoin() call. This is, in fact, what happens in +** single threaded systems. Nothing in SQLite requires multiple threads. +** This interface exists so that applications that want to take advantage +** of multiple cores can do so, while also allowing applications to stay +** single-threaded if desired. +*/ +/* #include "sqliteInt.h" */ +#if SQLITE_OS_WIN +/* # include "os_win.h" */ +#endif + +#if SQLITE_MAX_WORKER_THREADS>0 + +/********************************* Unix Pthreads ****************************/ +#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 + +#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ +/* #include */ + +/* A running thread */ +struct SQLiteThread { + pthread_t tid; /* Thread ID */ + int done; /* Set to true when thread finishes */ + void *pOut; /* Result returned by the thread */ + void *(*xTask)(void*); /* The thread routine */ + void *pIn; /* Argument to the thread */ +}; + +/* Create a new thread */ +SQLITE_PRIVATE int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + int rc; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + /* This routine is never used in single-threaded mode */ + assert( sqlite3GlobalConfig.bCoreMutex!=0 ); + + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM_BKPT; + memset(p, 0, sizeof(*p)); + p->xTask = xTask; + p->pIn = pIn; + /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a + ** function that returns SQLITE_ERROR when passed the argument 200, that + ** forces worker threads to run sequentially and deterministically + ** for testing purposes. */ + if( sqlite3FaultSim(200) ){ + rc = 1; + }else{ + rc = pthread_create(&p->tid, 0, xTask, pIn); + } + if( rc ){ + p->done = 1; + p->pOut = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +/* Get the results of the thread */ +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + int rc; + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; + if( p->done ){ + *ppOut = p->pOut; + rc = SQLITE_OK; + }else{ + rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK; + } + sqlite3_free(p); + return rc; +} + +#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ +/******************************** End Unix Pthreads *************************/ + + +/********************************* Win32 Threads ****************************/ +#if SQLITE_OS_WIN_THREADS + +#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ +#include + +/* A running thread */ +struct SQLiteThread { + void *tid; /* The thread handle */ + unsigned id; /* The thread identifier */ + void *(*xTask)(void*); /* The routine to run as a thread */ + void *pIn; /* Argument to xTask */ + void *pResult; /* Result of xTask */ +}; + +/* Thread procedure Win32 compatibility shim */ +static unsigned __stdcall sqlite3ThreadProc( + void *pArg /* IN: Pointer to the SQLiteThread structure */ +){ + SQLiteThread *p = (SQLiteThread *)pArg; + + assert( p!=0 ); +#if 0 + /* + ** This assert appears to trigger spuriously on certain + ** versions of Windows, possibly due to _beginthreadex() + ** and/or CreateThread() not fully setting their thread + ** ID parameter before starting the thread. + */ + assert( p->id==GetCurrentThreadId() ); +#endif + assert( p->xTask!=0 ); + p->pResult = p->xTask(p->pIn); + + _endthreadex(0); + return 0; /* NOT REACHED */ +} + +/* Create a new thread */ +SQLITE_PRIVATE int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM_BKPT; + /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a + ** function that returns SQLITE_ERROR when passed the argument 200, that + ** forces worker threads to run sequentially and deterministically + ** (via the sqlite3FaultSim() term of the conditional) for testing + ** purposes. */ + if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){ + memset(p, 0, sizeof(*p)); + }else{ + p->xTask = xTask; + p->pIn = pIn; + p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); + if( p->tid==0 ){ + memset(p, 0, sizeof(*p)); + } + } + if( p->xTask==0 ){ + p->id = GetCurrentThreadId(); + p->pResult = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ + +/* Get the results of the thread */ +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + DWORD rc; + BOOL bRc; + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; + if( p->xTask==0 ){ + /* assert( p->id==GetCurrentThreadId() ); */ + rc = WAIT_OBJECT_0; + assert( p->tid==0 ); + }else{ + assert( p->id!=0 && p->id!=GetCurrentThreadId() ); + rc = sqlite3Win32Wait((HANDLE)p->tid); + assert( rc!=WAIT_IO_COMPLETION ); + bRc = CloseHandle((HANDLE)p->tid); + assert( bRc ); + } + if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; + sqlite3_free(p); + return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; +} + +#endif /* SQLITE_OS_WIN_THREADS */ +/******************************** End Win32 Threads *************************/ + + +/********************************* Single-Threaded **************************/ +#ifndef SQLITE_THREADS_IMPLEMENTED +/* +** This implementation does not actually create a new thread. It does the +** work of the thread in the main thread, when either the thread is created +** or when it is joined +*/ + +/* A running thread */ +struct SQLiteThread { + void *(*xTask)(void*); /* The routine to run as a thread */ + void *pIn; /* Argument to xTask */ + void *pResult; /* Result of xTask */ +}; + +/* Create a new thread */ +SQLITE_PRIVATE int sqlite3ThreadCreate( + SQLiteThread **ppThread, /* OUT: Write the thread object here */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + SQLiteThread *p; + + assert( ppThread!=0 ); + assert( xTask!=0 ); + *ppThread = 0; + p = sqlite3Malloc(sizeof(*p)); + if( p==0 ) return SQLITE_NOMEM_BKPT; + if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ + p->xTask = xTask; + p->pIn = pIn; + }else{ + p->xTask = 0; + p->pResult = xTask(pIn); + } + *ppThread = p; + return SQLITE_OK; +} + +/* Get the results of the thread */ +SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ + + assert( ppOut!=0 ); + if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; + if( p->xTask ){ + *ppOut = p->xTask(p->pIn); + }else{ + *ppOut = p->pResult; + } + sqlite3_free(p); + +#if defined(SQLITE_TEST) + { + void *pTstAlloc = sqlite3Malloc(10); + if (!pTstAlloc) return SQLITE_NOMEM_BKPT; + sqlite3_free(pTstAlloc); + } +#endif + + return SQLITE_OK; +} + +#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ +/****************************** End Single-Threaded *************************/ +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + +/************** End of threads.c *********************************************/ +/************** Begin file utf.c *********************************************/ +/* +** 2004 April 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 routines used to translate between UTF-8, +** UTF-16, UTF-16BE, and UTF-16LE. +** +** Notes on UTF-8: +** +** Byte-0 Byte-1 Byte-2 Byte-3 Value +** 0xxxxxxx 00000000 00000000 0xxxxxxx +** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx +** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx +** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx +** +** +** Notes on UTF-16: (with wwww+1==uuuuu) +** +** Word-0 Word-1 Value +** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx +** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx +** +** +** BOM or Byte Order Mark: +** 0xff 0xfe little-endian utf-16 follows +** 0xfe 0xff big-endian utf-16 follows +** +*/ +/* #include "sqliteInt.h" */ +/* #include */ +/* #include "vdbeInt.h" */ + +#if !defined(SQLITE_AMALGAMATION) && SQLITE_BYTEORDER==0 +/* +** The following constant value is used by the SQLITE_BIGENDIAN and +** SQLITE_LITTLEENDIAN macros. +*/ +SQLITE_PRIVATE const int sqlite3one = 1; +#endif /* SQLITE_AMALGAMATION && SQLITE_BYTEORDER==0 */ + +/* +** This lookup table is used to help decode the first byte of +** a multi-byte UTF8 character. +*/ +static const unsigned char sqlite3Utf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + + +#define WRITE_UTF8(zOut, c) { \ + if( c<0x00080 ){ \ + *zOut++ = (u8)(c&0xFF); \ + } \ + else if( c<0x00800 ){ \ + *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + } \ + else if( c<0x10000 ){ \ + *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \ + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + }else{ \ + *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \ + *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \ + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + } \ +} + +#define WRITE_UTF16LE(zOut, c) { \ + if( c<=0xFFFF ){ \ + *zOut++ = (u8)(c&0x00FF); \ + *zOut++ = (u8)((c>>8)&0x00FF); \ + }else{ \ + *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ + *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ + *zOut++ = (u8)(c&0x00FF); \ + *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ + } \ +} + +#define WRITE_UTF16BE(zOut, c) { \ + if( c<=0xFFFF ){ \ + *zOut++ = (u8)((c>>8)&0x00FF); \ + *zOut++ = (u8)(c&0x00FF); \ + }else{ \ + *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ + *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ + *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ + *zOut++ = (u8)(c&0x00FF); \ + } \ +} + +#define READ_UTF16LE(zIn, TERM, c){ \ + c = (*zIn++); \ + c += ((*zIn++)<<8); \ + if( c>=0xD800 && c<0xE000 && TERM ){ \ + int c2 = (*zIn++); \ + c2 += ((*zIn++)<<8); \ + c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ + } \ +} + +#define READ_UTF16BE(zIn, TERM, c){ \ + c = ((*zIn++)<<8); \ + c += (*zIn++); \ + if( c>=0xD800 && c<0xE000 && TERM ){ \ + int c2 = ((*zIn++)<<8); \ + c2 += (*zIn++); \ + c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ + } \ +} + +/* +** Translate a single UTF-8 character. Return the unicode value. +** +** During translation, assume that the byte that zTerm points +** is a 0x00. +** +** Write a pointer to the next unread byte back into *pzNext. +** +** Notes On Invalid UTF-8: +** +** * This routine never allows a 7-bit character (0x00 through 0x7f) to +** be encoded as a multi-byte character. Any multi-byte character that +** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd. +** +** * This routine never allows a UTF16 surrogate value to be encoded. +** If a multi-byte character attempts to encode a value between +** 0xd800 and 0xe000 then it is rendered as 0xfffd. +** +** * Bytes in the range of 0x80 through 0xbf which occur as the first +** byte of a character are interpreted as single-byte characters +** and rendered as themselves even though they are technically +** invalid characters. +** +** * This routine accepts over-length UTF8 encodings +** for unicode values 0x80 and greater. It does not change over-length +** encodings to 0xfffd as some systems recommend. +*/ +#define READ_UTF8(zIn, zTerm, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = sqlite3Utf8Trans1[c-0xc0]; \ + while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + if( c<0x80 \ + || (c&0xFFFFF800)==0xD800 \ + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ + } +SQLITE_PRIVATE u32 sqlite3Utf8Read( + const unsigned char **pz /* Pointer to string from which to read char */ +){ + unsigned int c; + + /* Same as READ_UTF8() above but without the zTerm parameter. + ** For this routine, we assume the UTF8 string is always zero-terminated. + */ + c = *((*pz)++); + if( c>=0xc0 ){ + c = sqlite3Utf8Trans1[c-0xc0]; + while( (*(*pz) & 0xc0)==0x80 ){ + c = (c<<6) + (0x3f & *((*pz)++)); + } + if( c<0x80 + || (c&0xFFFFF800)==0xD800 + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } + } + return c; +} + + + + +/* +** If the TRANSLATE_TRACE macro is defined, the value of each Mem is +** printed on stderr on the way into and out of sqlite3VdbeMemTranslate(). +*/ +/* #define TRANSLATE_TRACE 1 */ + +#ifndef SQLITE_OMIT_UTF16 +/* +** This routine transforms the internal text encoding used by pMem to +** desiredEnc. It is an error if the string is already of the desired +** encoding, or if *pMem does not contain a string value. +*/ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ + int len; /* Maximum length of output string in bytes */ + unsigned char *zOut; /* Output buffer */ + unsigned char *zIn; /* Input iterator */ + unsigned char *zTerm; /* End of input */ + unsigned char *z; /* Output iterator */ + unsigned int c; + + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( pMem->flags&MEM_Str ); + assert( pMem->enc!=desiredEnc ); + assert( pMem->enc!=0 ); + assert( pMem->n>=0 ); + +#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) + { + char zBuf[100]; + sqlite3VdbeMemPrettyPrint(pMem, zBuf); + fprintf(stderr, "INPUT: %s\n", zBuf); + } +#endif + + /* If the translation is between UTF-16 little and big endian, then + ** all that is required is to swap the byte order. This case is handled + ** differently from the others. + */ + if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){ + u8 temp; + int rc; + rc = sqlite3VdbeMemMakeWriteable(pMem); + if( rc!=SQLITE_OK ){ + assert( rc==SQLITE_NOMEM ); + return SQLITE_NOMEM_BKPT; + } + zIn = (u8*)pMem->z; + zTerm = &zIn[pMem->n&~1]; + while( zInenc = desiredEnc; + goto translate_out; + } + + /* Set len to the maximum number of bytes required in the output buffer. */ + if( desiredEnc==SQLITE_UTF8 ){ + /* When converting from UTF-16, the maximum growth results from + ** translating a 2-byte character to a 4-byte UTF-8 character. + ** A single byte is required for the output string + ** nul-terminator. + */ + pMem->n &= ~1; + len = pMem->n * 2 + 1; + }else{ + /* When converting from UTF-8 to UTF-16 the maximum growth is caused + ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 + ** character. Two bytes are required in the output buffer for the + ** nul-terminator. + */ + len = pMem->n * 2 + 2; + } + + /* Set zIn to point at the start of the input buffer and zTerm to point 1 + ** byte past the end. + ** + ** Variable zOut is set to point at the output buffer, space obtained + ** from sqlite3_malloc(). + */ + zIn = (u8*)pMem->z; + zTerm = &zIn[pMem->n]; + zOut = sqlite3DbMallocRaw(pMem->db, len); + if( !zOut ){ + return SQLITE_NOMEM_BKPT; + } + z = zOut; + + if( pMem->enc==SQLITE_UTF8 ){ + if( desiredEnc==SQLITE_UTF16LE ){ + /* UTF-8 -> UTF-16 Little-endian */ + while( zIn UTF-16 Big-endian */ + while( zInn = (int)(z - zOut); + *z++ = 0; + }else{ + assert( desiredEnc==SQLITE_UTF8 ); + if( pMem->enc==SQLITE_UTF16LE ){ + /* UTF-16 Little-endian -> UTF-8 */ + while( zIn UTF-8 */ + while( zInn = (int)(z - zOut); + } + *z = 0; + assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); + + c = pMem->flags; + sqlite3VdbeMemRelease(pMem); + pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype)); + pMem->enc = desiredEnc; + pMem->z = (char*)zOut; + pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z); + +translate_out: +#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) + { + char zBuf[100]; + sqlite3VdbeMemPrettyPrint(pMem, zBuf); + fprintf(stderr, "OUTPUT: %s\n", zBuf); + } +#endif + return SQLITE_OK; +} + +/* +** This routine checks for a byte-order mark at the beginning of the +** UTF-16 string stored in *pMem. If one is present, it is removed and +** the encoding of the Mem adjusted. This routine does not do any +** byte-swapping, it just sets Mem.enc appropriately. +** +** The allocation (static, dynamic etc.) and encoding of the Mem may be +** changed by this function. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){ + int rc = SQLITE_OK; + u8 bom = 0; + + assert( pMem->n>=0 ); + if( pMem->n>1 ){ + u8 b1 = *(u8 *)pMem->z; + u8 b2 = *(((u8 *)pMem->z) + 1); + if( b1==0xFE && b2==0xFF ){ + bom = SQLITE_UTF16BE; + } + if( b1==0xFF && b2==0xFE ){ + bom = SQLITE_UTF16LE; + } + } + + if( bom ){ + rc = sqlite3VdbeMemMakeWriteable(pMem); + if( rc==SQLITE_OK ){ + pMem->n -= 2; + memmove(pMem->z, &pMem->z[2], pMem->n); + pMem->z[pMem->n] = '\0'; + pMem->z[pMem->n+1] = '\0'; + pMem->flags |= MEM_Term; + pMem->enc = bom; + } + } + return rc; +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** pZ is a UTF-8 encoded unicode string. If nByte is less than zero, +** return the number of unicode characters in pZ up to (but not including) +** the first 0x00 byte. If nByte is not less than zero, return the +** number of unicode characters in the first nByte of pZ (or up to +** the first 0x00, whichever comes first). +*/ +SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){ + int r = 0; + const u8 *z = (const u8*)zIn; + const u8 *zTerm; + if( nByte>=0 ){ + zTerm = &z[nByte]; + }else{ + zTerm = (const u8*)(-1); + } + assert( z<=zTerm ); + while( *z!=0 && zmallocFailed ){ + sqlite3VdbeMemRelease(&m); + m.z = 0; + } + assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); + assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); + assert( m.z || db->mallocFailed ); + return m.z; +} + +/* +** zIn is a UTF-16 encoded unicode string at least nChar characters long. +** Return the number of bytes in the first nChar unicode characters +** in pZ. nChar must be non-negative. +*/ +SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){ + int c; + unsigned char const *z = zIn; + int n = 0; + + if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){ + while( n0 && n<=4 ); + z[0] = 0; + z = zBuf; + c = sqlite3Utf8Read((const u8**)&z); + t = i; + if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD; + if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD; + assert( c==t ); + assert( (z-zBuf)==n ); + } + for(i=0; i<0x00110000; i++){ + if( i>=0xD800 && i<0xE000 ) continue; + z = zBuf; + WRITE_UTF16LE(z, i); + n = (int)(z-zBuf); + assert( n>0 && n<=4 ); + z[0] = 0; + z = zBuf; + READ_UTF16LE(z, 1, c); + assert( c==i ); + assert( (z-zBuf)==n ); + } + for(i=0; i<0x00110000; i++){ + if( i>=0xD800 && i<0xE000 ) continue; + z = zBuf; + WRITE_UTF16BE(z, i); + n = (int)(z-zBuf); + assert( n>0 && n<=4 ); + z[0] = 0; + z = zBuf; + READ_UTF16BE(z, 1, c); + assert( c==i ); + assert( (z-zBuf)==n ); + } +} +#endif /* SQLITE_TEST */ +#endif /* SQLITE_OMIT_UTF16 */ + +/************** End of utf.c *************************************************/ +/************** Begin file util.c ********************************************/ +/* +** 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. +** +************************************************************************* +** Utility functions used throughout sqlite. +** +** This file contains functions for allocating memory, comparing +** strings, and stuff like that. +** +*/ +/* #include "sqliteInt.h" */ +/* #include */ +#if HAVE_ISNAN || SQLITE_HAVE_ISNAN +# include +#endif + +/* +** Routine needed to support the testcase() macro. +*/ +#ifdef SQLITE_COVERAGE_TEST +SQLITE_PRIVATE void sqlite3Coverage(int x){ + static unsigned dummy = 0; + dummy += (unsigned)x; +} +#endif + +/* +** Give a callback to the test harness that can be used to simulate faults +** in places where it is difficult or expensive to do so purely by means +** of inputs. +** +** The intent of the integer argument is to let the fault simulator know +** which of multiple sqlite3FaultSim() calls has been hit. +** +** Return whatever integer value the test callback returns, or return +** SQLITE_OK if no test callback is installed. +*/ +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ + int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; + return xCallback ? xCallback(iTest) : SQLITE_OK; +} +#endif + +#ifndef SQLITE_OMIT_FLOATING_POINT +/* +** Return true if the floating point value is Not a Number (NaN). +** +** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. +** Otherwise, we have our own implementation that works on most systems. +*/ +SQLITE_PRIVATE int sqlite3IsNaN(double x){ + int rc; /* The value return */ +#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN + /* + ** Systems that support the isnan() library function should probably + ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have + ** found that many systems do not have a working isnan() function so + ** this implementation is provided as an alternative. + ** + ** This NaN test sometimes fails if compiled on GCC with -ffast-math. + ** On the other hand, the use of -ffast-math comes with the following + ** warning: + ** + ** This option [-ffast-math] should never be turned on by any + ** -O option since it can result in incorrect output for programs + ** which depend on an exact implementation of IEEE or ISO + ** rules/specifications for math functions. + ** + ** Under MSVC, this NaN test may fail if compiled with a floating- + ** point precision mode other than /fp:precise. From the MSDN + ** documentation: + ** + ** The compiler [with /fp:precise] will properly handle comparisons + ** involving NaN. For example, x != x evaluates to true if x is NaN + ** ... + */ +#ifdef __FAST_MATH__ +# error SQLite will not work correctly with the -ffast-math option of GCC. +#endif + volatile double y = x; + volatile double z = y; + rc = (y!=z); +#else /* if HAVE_ISNAN */ + rc = isnan(x); +#endif /* HAVE_ISNAN */ + testcase( rc ); + return rc; +} +#endif /* SQLITE_OMIT_FLOATING_POINT */ + +/* +** Compute a string length that is limited to what can be stored in +** lower 30 bits of a 32-bit signed integer. +** +** The value returned will never be negative. Nor will it ever be greater +** than the actual length of the string. For very long strings (greater +** than 1GiB) the value returned might be less than the true string length. +*/ +SQLITE_PRIVATE int sqlite3Strlen30(const char *z){ + if( z==0 ) return 0; + return 0x3fffffff & (int)strlen(z); +} + +/* +** Return the declared type of a column. Or return zDflt if the column +** has no declared type. +** +** The column type is an extra string stored after the zero-terminator on +** the column name if and only if the COLFLAG_HASTYPE flag is set. +*/ +SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){ + if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt; + return pCol->zName + strlen(pCol->zName) + 1; +} + +/* +** Helper function for sqlite3Error() - called rarely. Broken out into +** a separate routine to avoid unnecessary register saves on entry to +** sqlite3Error(). +*/ +static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){ + if( db->pErr ) sqlite3ValueSetNull(db->pErr); + sqlite3SystemError(db, err_code); +} + +/* +** Set the current error code to err_code and clear any prior error message. +** Also set iSysErrno (by calling sqlite3System) if the err_code indicates +** that would be appropriate. +*/ +SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ + assert( db!=0 ); + db->errCode = err_code; + if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code); +} + +/* +** Load the sqlite3.iSysErrno field if that is an appropriate thing +** to do based on the SQLite error code in rc. +*/ +SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){ + if( rc==SQLITE_IOERR_NOMEM ) return; + rc &= 0xff; + if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){ + db->iSysErrno = sqlite3OsGetLastError(db->pVfs); + } +} + +/* +** Set the most recent error code and error string for the sqlite +** handle "db". The error code is set to "err_code". +** +** If it is not NULL, string zFormat specifies the format of the +** error string in the style of the printf functions: The following +** format characters are allowed: +** +** %s Insert a string +** %z A string that should be freed after use +** %d Insert an integer +** %T Insert a token +** %S Insert the first element of a SrcList +** +** zFormat and any string tokens that follow it are assumed to be +** encoded in UTF-8. +** +** To clear the most recent error for sqlite handle "db", sqlite3Error +** should be called with err_code set to SQLITE_OK and zFormat set +** to NULL. +*/ +SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){ + assert( db!=0 ); + db->errCode = err_code; + sqlite3SystemError(db, err_code); + if( zFormat==0 ){ + sqlite3Error(db, err_code); + }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){ + char *z; + va_list ap; + va_start(ap, zFormat); + z = sqlite3VMPrintf(db, zFormat, ap); + va_end(ap); + sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC); + } +} + +/* +** Add an error message to pParse->zErrMsg and increment pParse->nErr. +** The following formatting characters are allowed: +** +** %s Insert a string +** %z A string that should be freed after use +** %d Insert an integer +** %T Insert a token +** %S Insert the first element of a SrcList +** +** This function should be used to report any error that occurs while +** compiling an SQL statement (i.e. within sqlite3_prepare()). The +** last thing the sqlite3_prepare() function does is copy the error +** stored by this function into the database handle using sqlite3Error(). +** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used +** during statement execution (sqlite3_step() etc.). +*/ +SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ + char *zMsg; + va_list ap; + sqlite3 *db = pParse->db; + va_start(ap, zFormat); + zMsg = sqlite3VMPrintf(db, zFormat, ap); + va_end(ap); + if( db->suppressErr ){ + sqlite3DbFree(db, zMsg); + }else{ + pParse->nErr++; + sqlite3DbFree(db, pParse->zErrMsg); + pParse->zErrMsg = zMsg; + pParse->rc = SQLITE_ERROR; + } +} + +/* +** Convert an SQL-style quoted string into a normal string by removing +** the quote characters. The conversion is done in-place. If the +** input does not begin with a quote character, then this routine +** is a no-op. +** +** The input string must be zero-terminated. A new zero-terminator +** is added to the dequoted string. +** +** The return value is -1 if no dequoting occurs or the length of the +** dequoted string, exclusive of the zero terminator, if dequoting does +** occur. +** +** 2002-Feb-14: This routine is extended to remove MS-Access style +** brackets from around identifiers. For example: "[a-b-c]" becomes +** "a-b-c". +*/ +SQLITE_PRIVATE void sqlite3Dequote(char *z){ + char quote; + int i, j; + if( z==0 ) return; + quote = z[0]; + if( !sqlite3Isquote(quote) ) return; + if( quote=='[' ) quote = ']'; + for(i=1, j=0;; i++){ + assert( z[i] ); + if( z[i]==quote ){ + if( z[i+1]==quote ){ + z[j++] = quote; + i++; + }else{ + break; + } + }else{ + z[j++] = z[i]; + } + } + z[j] = 0; +} + +/* +** Generate a Token object from a string +*/ +SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){ + p->z = z; + p->n = sqlite3Strlen30(z); +} + +/* Convenient short-hand */ +#define UpperToLower sqlite3UpperToLower + +/* +** Some systems have stricmp(). Others have strcasecmp(). Because +** there is no consistency, we will define our own. +** +** IMPLEMENTATION-OF: R-30243-02494 The sqlite3_stricmp() and +** sqlite3_strnicmp() APIs allow applications and extensions to compare +** the contents of two buffers containing UTF-8 strings in a +** case-independent fashion, using the same definition of "case +** independence" that SQLite uses internally when comparing identifiers. +*/ +SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){ + if( zLeft==0 ){ + return zRight ? -1 : 0; + }else if( zRight==0 ){ + return 1; + } + return sqlite3StrICmp(zLeft, zRight); +} +SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ + unsigned char *a, *b; + int c; + a = (unsigned char *)zLeft; + b = (unsigned char *)zRight; + for(;;){ + c = (int)UpperToLower[*a] - (int)UpperToLower[*b]; + if( c || *a==0 ) break; + a++; + b++; + } + return c; +} +SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ + register unsigned char *a, *b; + if( zLeft==0 ){ + return zRight ? -1 : 0; + }else if( zRight==0 ){ + return 1; + } + a = (unsigned char *)zLeft; + b = (unsigned char *)zRight; + while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } + return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; +} + +/* +** The string z[] is an text representation of a real number. +** Convert this string to a double and write it into *pResult. +** +** The string z[] is length bytes in length (bytes, not characters) and +** uses the encoding enc. The string is not necessarily zero-terminated. +** +** Return TRUE if the result is a valid real number (or integer) and FALSE +** if the string is empty or contains extraneous text. Valid numbers +** are in one of these formats: +** +** [+-]digits[E[+-]digits] +** [+-]digits.[digits][E[+-]digits] +** [+-].digits[E[+-]digits] +** +** Leading and trailing whitespace is ignored for the purpose of determining +** validity. +** +** If some prefix of the input string is a valid number, this routine +** returns FALSE but it still converts the prefix and writes the result +** into *pResult. +*/ +SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ +#ifndef SQLITE_OMIT_FLOATING_POINT + int incr; + const char *zEnd = z + length; + /* sign * significand * (10 ^ (esign * exponent)) */ + int sign = 1; /* sign of significand */ + i64 s = 0; /* significand */ + int d = 0; /* adjust exponent for shifting decimal point */ + int esign = 1; /* sign of exponent */ + int e = 0; /* exponent */ + int eValid = 1; /* True exponent is either not used or is well-formed */ + double result; + int nDigits = 0; + int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + + assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); + *pResult = 0.0; /* Default return value, in case of an error */ + + if( enc==SQLITE_UTF8 ){ + incr = 1; + }else{ + int i; + incr = 2; + assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + for(i=3-enc; i=zEnd ) return 0; + + /* get sign of significand */ + if( *z=='-' ){ + sign = -1; + z+=incr; + }else if( *z=='+' ){ + z+=incr; + } + + /* copy max significant digits to significand */ + while( z=zEnd ) goto do_atof_calc; + + /* if decimal point is present */ + if( *z=='.' ){ + z+=incr; + /* copy digits from after decimal to significand + ** (decrease exponent by d to shift decimal right) */ + while( z=zEnd ) goto do_atof_calc; + + /* if exponent is present */ + if( *z=='e' || *z=='E' ){ + z+=incr; + eValid = 0; + + /* This branch is needed to avoid a (harmless) buffer overread. The + ** special comment alerts the mutation tester that the correct answer + ** is obtained even if the branch is omitted */ + if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ + + /* get sign of exponent */ + if( *z=='-' ){ + esign = -1; + z+=incr; + }else if( *z=='+' ){ + z+=incr; + } + /* copy digits to exponent */ + while( z0 ){ /*OPTIMIZATION-IF-TRUE*/ + if( esign>0 ){ + if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/ + s *= 10; + }else{ + if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/ + s /= 10; + } + e--; + } + + /* adjust the sign of significand */ + s = sign<0 ? -s : s; + + if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/ + result = (double)s; + }else{ + LONGDOUBLE_TYPE scale = 1.0; + /* attempt to handle extremely small/large numbers better */ + if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/ + if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/ + while( e%308 ) { scale *= 1.0e+1; e -= 1; } + if( esign<0 ){ + result = s / scale; + result /= 1.0e+308; + }else{ + result = s * scale; + result *= 1.0e+308; + } + }else{ assert( e>=342 ); + if( esign<0 ){ + result = 0.0*s; + }else{ + result = 1e308*1e308*s; /* Infinity */ + } + } + }else{ + /* 1.0e+22 is the largest power of 10 than can be + ** represented exactly. */ + while( e%22 ) { scale *= 1.0e+1; e -= 1; } + while( e>0 ) { scale *= 1.0e+22; e -= 22; } + if( esign<0 ){ + result = s / scale; + }else{ + result = s * scale; + } + } + } + } + + /* store the result */ + *pResult = result; + + /* return true if number and no extra non-whitespace chracters after */ + return z==zEnd && nDigits>0 && eValid && nonNum==0; +#else + return !sqlite3Atoi64(z, pResult, length, enc); +#endif /* SQLITE_OMIT_FLOATING_POINT */ +} + +/* +** Compare the 19-character string zNum against the text representation +** value 2^63: 9223372036854775808. Return negative, zero, or positive +** if zNum is less than, equal to, or greater than the string. +** Note that zNum must contain exactly 19 characters. +** +** Unlike memcmp() this routine is guaranteed to return the difference +** in the values of the last digit if the only difference is in the +** last digit. So, for example, +** +** compare2pow63("9223372036854775800", 1) +** +** will return -8. +*/ +static int compare2pow63(const char *zNum, int incr){ + int c = 0; + int i; + /* 012345678901234567 */ + const char *pow63 = "922337203685477580"; + for(i=0; c==0 && i<18; i++){ + c = (zNum[i*incr]-pow63[i])*10; + } + if( c==0 ){ + c = zNum[18*incr] - '8'; + testcase( c==(-1) ); + testcase( c==0 ); + testcase( c==(+1) ); + } + return c; +} + +/* +** 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. +** +** 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. +** +** length is the number of bytes in the string (bytes, not characters). +** The string is not necessarily zero-terminated. The encoding is +** given by enc. +*/ +SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ + int incr; + u64 u = 0; + int neg = 0; /* assume positive */ + int i; + int c = 0; + int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + const char *zStart; + const char *zEnd = zNum + length; + assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); + if( enc==SQLITE_UTF8 ){ + incr = 1; + }else{ + incr = 2; + assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + for(i=3-enc; i='0' && c<='9'; i+=incr){ + u = u*10 + c - '0'; + } + if( u>LARGEST_INT64 ){ + *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; + }else if( neg ){ + *pNum = -(i64)u; + }else{ + *pNum = (i64)u; + } + testcase( i==18 ); + testcase( i==19 ); + testcase( i==20 ); + if( &zNum[i]19*incr /* Too many digits */ + || nonNum /* UTF16 with high-order bytes non-zero */ + ){ + /* zNum is empty or contains non-numeric text or is longer + ** than 19 digits (thus guaranteeing that it is too large) */ + return 1; + }else if( i<19*incr ){ + /* Less than 19 digits, so we know that it fits in 64 bits */ + assert( u<=LARGEST_INT64 ); + return 0; + }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; + }else if( c>0 ){ + /* zNum is greater than 9223372036854775808 so it overflows */ + return 1; + }else{ + /* zNum is exactly 9223372036854775808. Fits if negative. The + ** special case 2 overflow if positive */ + assert( u-1==LARGEST_INT64 ); + return neg ? 0 : 2; + } + } +} + +/* +** Transform a UTF-8 integer literal, in either decimal or hexadecimal, +** into a 64-bit signed integer. This routine accepts hexadecimal literals, +** whereas sqlite3Atoi64() does not. +** +** 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 +*/ +SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' + && (z[1]=='x' || z[1]=='X') + ){ + u64 u = 0; + int i, k; + for(i=2; z[i]=='0'; i++){} + for(k=i; sqlite3Isxdigit(z[k]); k++){ + u = u*16 + sqlite3HexToInt(z[k]); + } + memcpy(pOut, &u, 8); + return (z[k]==0 && k-i<=16) ? 0 : 1; + }else +#endif /* SQLITE_OMIT_HEX_INTEGER */ + { + return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); + } +} + +/* +** If zNum represents an integer that will fit in 32-bits, then set +** *pValue to that integer and return true. Otherwise return false. +** +** This routine accepts both decimal and hexadecimal notation for integers. +** +** Any non-numeric characters that following zNum are ignored. +** This is different from sqlite3Atoi64() which requires the +** input number to be zero-terminated. +*/ +SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ + sqlite_int64 v = 0; + int i, c; + int neg = 0; + if( zNum[0]=='-' ){ + neg = 1; + zNum++; + }else if( zNum[0]=='+' ){ + zNum++; + } +#ifndef SQLITE_OMIT_HEX_INTEGER + else if( zNum[0]=='0' + && (zNum[1]=='x' || zNum[1]=='X') + && sqlite3Isxdigit(zNum[2]) + ){ + u32 u = 0; + zNum += 2; + while( zNum[0]=='0' ) zNum++; + for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){ + u = u*16 + sqlite3HexToInt(zNum[i]); + } + if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ + memcpy(pValue, &u, 4); + return 1; + }else{ + return 0; + } + } +#endif + if( !sqlite3Isdigit(zNum[0]) ) return 0; + while( zNum[0]=='0' ) zNum++; + for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ + v = v*10 + c; + } + + /* The longest decimal representation of a 32 bit integer is 10 digits: + ** + ** 1234567890 + ** 2^31 -> 2147483648 + */ + testcase( i==10 ); + if( i>10 ){ + return 0; + } + testcase( v-neg==2147483647 ); + if( v-neg>2147483647 ){ + return 0; + } + if( neg ){ + v = -v; + } + *pValue = (int)v; + return 1; +} + +/* +** Return a 32-bit integer value extracted from a string. If the +** string is not an integer, just return 0. +*/ +SQLITE_PRIVATE int sqlite3Atoi(const char *z){ + int x = 0; + if( z ) sqlite3GetInt32(z, &x); + return x; +} + +/* +** The variable-length integer encoding is as follows: +** +** KEY: +** A = 0xxxxxxx 7 bits of data and one flag bit +** B = 1xxxxxxx 7 bits of data and one flag bit +** C = xxxxxxxx 8 bits of data +** +** 7 bits - A +** 14 bits - BA +** 21 bits - BBA +** 28 bits - BBBA +** 35 bits - BBBBA +** 42 bits - BBBBBA +** 49 bits - BBBBBBA +** 56 bits - BBBBBBBA +** 64 bits - BBBBBBBBC +*/ + +/* +** Write a 64-bit variable-length integer to memory starting at p[0]. +** The length of data write will be between 1 and 9 bytes. The number +** of bytes written is returned. +** +** A variable-length integer consists of the lower 7 bits of each byte +** for all bytes that have the 8th bit set and one byte with the 8th +** bit clear. Except, if we get to the 9th byte, it stores the full +** 8 bits and is the last byte. +*/ +static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){ + int i, j, n; + u8 buf[10]; + if( v & (((u64)0xff000000)<<32) ){ + p[8] = (u8)v; + v >>= 8; + for(i=7; i>=0; i--){ + p[i] = (u8)((v & 0x7f) | 0x80); + v >>= 7; + } + return 9; + } + n = 0; + do{ + buf[n++] = (u8)((v & 0x7f) | 0x80); + v >>= 7; + }while( v!=0 ); + buf[0] &= 0x7f; + assert( n<=9 ); + for(i=0, j=n-1; j>=0; j--, i++){ + p[i] = buf[j]; + } + return n; +} +SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ + if( v<=0x7f ){ + p[0] = v&0x7f; + return 1; + } + if( v<=0x3fff ){ + p[0] = ((v>>7)&0x7f)|0x80; + p[1] = v&0x7f; + return 2; + } + return putVarint64(p,v); +} + +/* +** Bitmasks used by sqlite3GetVarint(). These precomputed constants +** are defined here rather than simply putting the constant expressions +** inline in order to work around bugs in the RVT compiler. +** +** SLOT_2_0 A mask for (0x7f<<14) | 0x7f +** +** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 +*/ +#define SLOT_2_0 0x001fc07f +#define SLOT_4_2_0 0xf01fc07f + + +/* +** Read a 64-bit variable-length integer from memory starting at p[0]. +** Return the number of bytes read. The value is stored in *v. +*/ +SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ + u32 a,b,s; + + a = *p; + /* a: p0 (unmasked) */ + if (!(a&0x80)) + { + *v = a; + return 1; + } + + p++; + b = *p; + /* b: p1 (unmasked) */ + if (!(b&0x80)) + { + a &= 0x7f; + a = a<<7; + a |= b; + *v = a; + return 2; + } + + /* Verify that constants are precomputed correctly */ + assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); + assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); + + p++; + a = a<<14; + a |= *p; + /* a: p0<<14 | p2 (unmasked) */ + if (!(a&0x80)) + { + a &= SLOT_2_0; + b &= 0x7f; + b = b<<7; + a |= b; + *v = a; + return 3; + } + + /* CSE1 from below */ + a &= SLOT_2_0; + p++; + b = b<<14; + b |= *p; + /* b: p1<<14 | p3 (unmasked) */ + if (!(b&0x80)) + { + b &= SLOT_2_0; + /* moved CSE1 up */ + /* a &= (0x7f<<14)|(0x7f); */ + a = a<<7; + a |= b; + *v = a; + return 4; + } + + /* a: p0<<14 | p2 (masked) */ + /* b: p1<<14 | p3 (unmasked) */ + /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + /* moved CSE1 up */ + /* a &= (0x7f<<14)|(0x7f); */ + b &= SLOT_2_0; + s = a; + /* s: p0<<14 | p2 (masked) */ + + p++; + a = a<<14; + a |= *p; + /* a: p0<<28 | p2<<14 | p4 (unmasked) */ + if (!(a&0x80)) + { + /* we can skip these cause they were (effectively) done above + ** while calculating s */ + /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ + /* b &= (0x7f<<14)|(0x7f); */ + b = b<<7; + a |= b; + s = s>>18; + *v = ((u64)s)<<32 | a; + return 5; + } + + /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + s = s<<7; + s |= b; + /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ + + p++; + b = b<<14; + b |= *p; + /* b: p1<<28 | p3<<14 | p5 (unmasked) */ + if (!(b&0x80)) + { + /* we can skip this cause it was (effectively) done above in calc'ing s */ + /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ + a &= SLOT_2_0; + a = a<<7; + a |= b; + s = s>>18; + *v = ((u64)s)<<32 | a; + return 6; + } + + p++; + a = a<<14; + a |= *p; + /* a: p2<<28 | p4<<14 | p6 (unmasked) */ + if (!(a&0x80)) + { + a &= SLOT_4_2_0; + b &= SLOT_2_0; + b = b<<7; + a |= b; + s = s>>11; + *v = ((u64)s)<<32 | a; + return 7; + } + + /* CSE2 from below */ + a &= SLOT_2_0; + p++; + b = b<<14; + b |= *p; + /* b: p3<<28 | p5<<14 | p7 (unmasked) */ + if (!(b&0x80)) + { + b &= SLOT_4_2_0; + /* moved CSE2 up */ + /* a &= (0x7f<<14)|(0x7f); */ + a = a<<7; + a |= b; + s = s>>4; + *v = ((u64)s)<<32 | a; + return 8; + } + + p++; + a = a<<15; + a |= *p; + /* a: p4<<29 | p6<<15 | p8 (unmasked) */ + + /* moved CSE2 up */ + /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ + b &= SLOT_2_0; + b = b<<8; + a |= b; + + s = s<<4; + b = p[-4]; + b &= 0x7f; + b = b>>3; + s |= b; + + *v = ((u64)s)<<32 | a; + + return 9; +} + +/* +** Read a 32-bit variable-length integer from memory starting at p[0]. +** Return the number of bytes read. The value is stored in *v. +** +** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned +** integer, then set *v to 0xffffffff. +** +** A MACRO version, getVarint32, is provided which inlines the +** single-byte case. All code should use the MACRO version as +** this function assumes the single-byte case has already been handled. +*/ +SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ + u32 a,b; + + /* The 1-byte case. Overwhelmingly the most common. Handled inline + ** by the getVarin32() macro */ + a = *p; + /* a: p0 (unmasked) */ +#ifndef getVarint32 + if (!(a&0x80)) + { + /* Values between 0 and 127 */ + *v = a; + return 1; + } +#endif + + /* The 2-byte case */ + p++; + b = *p; + /* b: p1 (unmasked) */ + if (!(b&0x80)) + { + /* Values between 128 and 16383 */ + a &= 0x7f; + a = a<<7; + *v = a | b; + return 2; + } + + /* The 3-byte case */ + p++; + a = a<<14; + a |= *p; + /* a: p0<<14 | p2 (unmasked) */ + if (!(a&0x80)) + { + /* Values between 16384 and 2097151 */ + a &= (0x7f<<14)|(0x7f); + b &= 0x7f; + b = b<<7; + *v = a | b; + return 3; + } + + /* A 32-bit varint is used to store size information in btrees. + ** Objects are rarely larger than 2MiB limit of a 3-byte varint. + ** A 3-byte varint is sufficient, for example, to record the size + ** of a 1048569-byte BLOB or string. + ** + ** We only unroll the first 1-, 2-, and 3- byte cases. The very + ** rare larger cases can be handled by the slower 64-bit varint + ** routine. + */ +#if 1 + { + u64 v64; + u8 n; + + p -= 2; + n = sqlite3GetVarint(p, &v64); + assert( n>3 && n<=9 ); + if( (v64 & SQLITE_MAX_U32)!=v64 ){ + *v = 0xffffffff; + }else{ + *v = (u32)v64; + } + return n; + } + +#else + /* For following code (kept for historical record only) shows an + ** unrolling for the 3- and 4-byte varint cases. This code is + ** slightly faster, but it is also larger and much harder to test. + */ + p++; + b = b<<14; + b |= *p; + /* b: p1<<14 | p3 (unmasked) */ + if (!(b&0x80)) + { + /* Values between 2097152 and 268435455 */ + b &= (0x7f<<14)|(0x7f); + a &= (0x7f<<14)|(0x7f); + a = a<<7; + *v = a | b; + return 4; + } + + p++; + a = a<<14; + a |= *p; + /* a: p0<<28 | p2<<14 | p4 (unmasked) */ + if (!(a&0x80)) + { + /* Values between 268435456 and 34359738367 */ + a &= SLOT_4_2_0; + b &= SLOT_4_2_0; + b = b<<7; + *v = a | b; + return 5; + } + + /* We can only reach this point when reading a corrupt database + ** file. In that case we are not in any hurry. Use the (relatively + ** slow) general-purpose sqlite3GetVarint() routine to extract the + ** value. */ + { + u64 v64; + u8 n; + + p -= 4; + n = sqlite3GetVarint(p, &v64); + assert( n>5 && n<=9 ); + *v = (u32)v64; + return n; + } +#endif +} + +/* +** Return the number of bytes that will be needed to store the given +** 64-bit integer. +*/ +SQLITE_PRIVATE int sqlite3VarintLen(u64 v){ + int i; + for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); } + return i; +} + + +/* +** Read or write a four-byte big-endian integer value. +*/ +SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ +#if SQLITE_BYTEORDER==4321 + u32 x; + memcpy(&x,p,4); + return x; +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + u32 x; + memcpy(&x,p,4); + return __builtin_bswap32(x); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + u32 x; + memcpy(&x,p,4); + return _byteswap_ulong(x); +#else + testcase( p[0]&0x80 ); + return ((unsigned)p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; +#endif +} +SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ +#if SQLITE_BYTEORDER==4321 + memcpy(p,&v,4); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + u32 x = __builtin_bswap32(v); + memcpy(p,&x,4); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + u32 x = _byteswap_ulong(v); + memcpy(p,&x,4); +#else + p[0] = (u8)(v>>24); + p[1] = (u8)(v>>16); + p[2] = (u8)(v>>8); + p[3] = (u8)v; +#endif +} + + + +/* +** Translate a single byte of Hex into an integer. +** This routine only works if h really is a valid hexadecimal +** character: 0..9a..fA..F +*/ +SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ + assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); +#ifdef SQLITE_ASCII + h += 9*(1&(h>>6)); +#endif +#ifdef SQLITE_EBCDIC + h += 9*(1&~(h>>4)); +#endif + return (u8)(h & 0xf); +} + +#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) +/* +** Convert a BLOB literal of the form "x'hhhhhh'" into its binary +** value. Return a pointer to its binary value. Space to hold the +** binary value has been obtained from malloc and must be freed by +** the calling routine. +*/ +SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ + char *zBlob; + int i; + + zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1); + n--; + if( zBlob ){ + for(i=0; imagic; + if( magic!=SQLITE_MAGIC_OPEN ){ + if( sqlite3SafetyCheckSickOrOk(db) ){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + logBadConnection("unopened"); + } + return 0; + }else{ + return 1; + } +} +SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ + u32 magic; + magic = db->magic; + if( magic!=SQLITE_MAGIC_SICK && + magic!=SQLITE_MAGIC_OPEN && + magic!=SQLITE_MAGIC_BUSY ){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + logBadConnection("invalid"); + return 0; + }else{ + return 1; + } +} + +/* +** Attempt to add, substract, or multiply the 64-bit signed value iB against +** the other 64-bit signed integer at *pA and store the result in *pA. +** Return 0 on success. Or if the operation would have resulted in an +** overflow, leave *pA unchanged and return 1. +*/ +SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ +#if GCC_VERSION>=5004000 + return __builtin_add_overflow(*pA, iB, pA); +#else + i64 iA = *pA; + testcase( iA==0 ); testcase( iA==1 ); + testcase( iB==-1 ); testcase( iB==0 ); + if( iB>=0 ){ + testcase( iA>0 && LARGEST_INT64 - iA == iB ); + testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 ); + if( iA>0 && LARGEST_INT64 - iA < iB ) return 1; + }else{ + testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 ); + testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 ); + if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1; + } + *pA += iB; + return 0; +#endif +} +SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ +#if GCC_VERSION>=5004000 + return __builtin_sub_overflow(*pA, iB, pA); +#else + testcase( iB==SMALLEST_INT64+1 ); + if( iB==SMALLEST_INT64 ){ + testcase( (*pA)==(-1) ); testcase( (*pA)==0 ); + if( (*pA)>=0 ) return 1; + *pA -= iB; + return 0; + }else{ + return sqlite3AddInt64(pA, -iB); + } +#endif +} +SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ +#if GCC_VERSION>=5004000 + return __builtin_mul_overflow(*pA, iB, pA); +#else + i64 iA = *pA; + if( iB>0 ){ + if( iA>LARGEST_INT64/iB ) return 1; + if( iA0 ){ + if( iBLARGEST_INT64/-iB ) return 1; + } + } + *pA = iA*iB; + return 0; +#endif +} + +/* +** Compute the absolute value of a 32-bit signed integer, of possible. Or +** if the integer has a value of -2147483648, return +2147483647 +*/ +SQLITE_PRIVATE int sqlite3AbsInt32(int x){ + if( x>=0 ) return x; + if( x==(int)0x80000000 ) return 0x7fffffff; + return -x; +} + +#ifdef SQLITE_ENABLE_8_3_NAMES +/* +** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database +** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and +** if filename in z[] has a suffix (a.k.a. "extension") that is longer than +** three characters, then shorten the suffix on z[] to be the last three +** characters of the original suffix. +** +** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always +** do the suffix shortening regardless of URI parameter. +** +** Examples: +** +** test.db-journal => test.nal +** test.db-wal => test.wal +** test.db-shm => test.shm +** test.db-mj7f3319fa => test.9fa +*/ +SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ +#if SQLITE_ENABLE_8_3_NAMES<2 + if( sqlite3_uri_boolean(zBaseFilename, "8_3_names", 0) ) +#endif + { + int i, sz; + sz = sqlite3Strlen30(z); + for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} + if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); + } +} +#endif + +/* +** Find (an approximate) sum of two LogEst values. This computation is +** not a simple "+" operator because LogEst is stored as a logarithmic +** value. +** +*/ +SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){ + static const unsigned char x[] = { + 10, 10, /* 0,1 */ + 9, 9, /* 2,3 */ + 8, 8, /* 4,5 */ + 7, 7, 7, /* 6,7,8 */ + 6, 6, 6, /* 9,10,11 */ + 5, 5, 5, /* 12-14 */ + 4, 4, 4, 4, /* 15-18 */ + 3, 3, 3, 3, 3, 3, /* 19-24 */ + 2, 2, 2, 2, 2, 2, 2, /* 25-31 */ + }; + if( a>=b ){ + if( a>b+49 ) return a; + if( a>b+31 ) return a+1; + return a+x[a-b]; + }else{ + if( b>a+49 ) return b; + if( b>a+31 ) return b+1; + return b+x[b-a]; + } +} + +/* +** Convert an integer into a LogEst. In other words, compute an +** approximation for 10*log2(x). +*/ +SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ + static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; + LogEst y = 40; + if( x<8 ){ + if( x<2 ) return 0; + while( x<8 ){ y -= 10; x <<= 1; } + }else{ + while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ + while( x>15 ){ y += 10; x >>= 1; } + } + return a[x&7] + y - 10; +} + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Convert a double into a LogEst +** In other words, compute an approximation for 10*log2(x). +*/ +SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){ + u64 a; + LogEst e; + assert( sizeof(x)==8 && sizeof(a)==8 ); + if( x<=1 ) return 0; + if( x<=2000000000 ) return sqlite3LogEst((u64)x); + memcpy(&a, &x, 8); + e = (a>>52) - 1022; + return e*10; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ + defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \ + defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) +/* +** Convert a LogEst into an integer. +** +** Note that this routine is only used when one or more of various +** non-standard compile-time options is enabled. +*/ +SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ + u64 n; + n = x%10; + x /= 10; + if( n>=5 ) n -= 2; + else if( n>=1 ) n -= 1; +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ + defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) + if( x>60 ) return (u64)LARGEST_INT64; +#else + /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input + ** possible to this routine is 310, resulting in a maximum x of 31 */ + assert( x<=60 ); +#endif + return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); +} +#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */ + +/* +** Add a new name/number pair to a VList. This might require that the +** VList object be reallocated, so return the new VList. If an OOM +** error occurs, the original VList returned and the +** db->mallocFailed flag is set. +** +** A VList is really just an array of integers. To destroy a VList, +** simply pass it to sqlite3DbFree(). +** +** The first integer is the number of integers allocated for the whole +** VList. The second integer is the number of integers actually used. +** Each name/number pair is encoded by subsequent groups of 3 or more +** integers. +** +** Each name/number pair starts with two integers which are the numeric +** value for the pair and the size of the name/number pair, respectively. +** The text name overlays one or more following integers. The text name +** is always zero-terminated. +** +** Conceptually: +** +** struct VList { +** int nAlloc; // Number of allocated slots +** int nUsed; // Number of used slots +** struct VListEntry { +** int iValue; // Value for this entry +** int nSlot; // Slots used by this entry +** // ... variable name goes here +** } a[0]; +** } +** +** During code generation, pointers to the variable names within the +** VList are taken. When that happens, nAlloc is set to zero as an +** indication that the VList may never again be enlarged, since the +** accompanying realloc() would invalidate the pointers. +*/ +SQLITE_PRIVATE VList *sqlite3VListAdd( + sqlite3 *db, /* The database connection used for malloc() */ + VList *pIn, /* The input VList. Might be NULL */ + const char *zName, /* Name of symbol to add */ + int nName, /* Bytes of text in zName */ + int iVal /* Value to associate with zName */ +){ + int nInt; /* number of sizeof(int) objects needed for zName */ + char *z; /* Pointer to where zName will be stored */ + int i; /* Index in pIn[] where zName is stored */ + + nInt = nName/4 + 3; + assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ + if( pIn==0 || pIn[1]+nInt > pIn[0] ){ + /* Enlarge the allocation */ + int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt; + VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); + if( pOut==0 ) return pIn; + if( pIn==0 ) pOut[1] = 2; + pIn = pOut; + pIn[0] = nAlloc; + } + i = pIn[1]; + pIn[i] = iVal; + pIn[i+1] = nInt; + z = (char*)&pIn[i+2]; + pIn[1] = i+nInt; + assert( pIn[1]<=pIn[0] ); + memcpy(z, zName, nName); + z[nName] = 0; + return pIn; +} + +/* +** Return a pointer to the name of a variable in the given VList that +** has the value iVal. Or return a NULL if there is no such variable in +** the list +*/ +SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){ + int i, mx; + if( pIn==0 ) return 0; + mx = pIn[1]; + i = 2; + do{ + if( pIn[i]==iVal ) return (char*)&pIn[i+2]; + i += pIn[i+1]; + }while( i */ + +/* Turn bulk memory into a hash table object by initializing the +** fields of the Hash structure. +** +** "pNew" is a pointer to the hash table that is to be initialized. +*/ +SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){ + assert( pNew!=0 ); + pNew->first = 0; + pNew->count = 0; + pNew->htsize = 0; + pNew->ht = 0; +} + +/* Remove all entries from a hash table. Reclaim all memory. +** Call this routine to delete a hash table or to reset a hash table +** to the empty state. +*/ +SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ + HashElem *elem; /* For looping over all elements of the table */ + + assert( pH!=0 ); + elem = pH->first; + pH->first = 0; + sqlite3_free(pH->ht); + pH->ht = 0; + pH->htsize = 0; + while( elem ){ + HashElem *next_elem = elem->next; + sqlite3_free(elem); + elem = next_elem; + } + pH->count = 0; +} + +/* +** The hashing function. +*/ +static unsigned int strHash(const char *z){ + unsigned int h = 0; + unsigned char c; + while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/ + /* Knuth multiplicative hashing. (Sorting & Searching, p. 510). + ** 0x9e3779b1 is 2654435761 which is the closest prime number to + ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */ + h += sqlite3UpperToLower[c]; + h *= 0x9e3779b1; + } + return h; +} + + +/* Link pNew element into the hash table pH. If pEntry!=0 then also +** insert pNew into the pEntry hash bucket. +*/ +static void insertElement( + Hash *pH, /* The complete hash table */ + struct _ht *pEntry, /* The entry into which pNew is inserted */ + HashElem *pNew /* The element to be inserted */ +){ + HashElem *pHead; /* First element already in pEntry */ + if( pEntry ){ + pHead = pEntry->count ? pEntry->chain : 0; + pEntry->count++; + pEntry->chain = pNew; + }else{ + pHead = 0; + } + if( pHead ){ + pNew->next = pHead; + pNew->prev = pHead->prev; + if( pHead->prev ){ pHead->prev->next = pNew; } + else { pH->first = pNew; } + pHead->prev = pNew; + }else{ + pNew->next = pH->first; + if( pH->first ){ pH->first->prev = pNew; } + pNew->prev = 0; + pH->first = pNew; + } +} + + +/* Resize the hash table so that it cantains "new_size" buckets. +** +** The hash table might fail to resize if sqlite3_malloc() fails or +** if the new size is the same as the prior size. +** Return TRUE if the resize occurs and false if not. +*/ +static int rehash(Hash *pH, unsigned int new_size){ + struct _ht *new_ht; /* The new hash table */ + HashElem *elem, *next_elem; /* For looping over existing elements */ + +#if SQLITE_MALLOC_SOFT_LIMIT>0 + if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){ + new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht); + } + if( new_size==pH->htsize ) return 0; +#endif + + /* The inability to allocates space for a larger hash table is + ** a performance hit but it is not a fatal error. So mark the + ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of + ** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero() + ** only zeroes the requested number of bytes whereas this module will + ** use the actual amount of space allocated for the hash table (which + ** may be larger than the requested amount). + */ + sqlite3BeginBenignMalloc(); + new_ht = (struct _ht *)sqlite3Malloc( new_size*sizeof(struct _ht) ); + sqlite3EndBenignMalloc(); + + if( new_ht==0 ) return 0; + sqlite3_free(pH->ht); + pH->ht = new_ht; + pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); + memset(new_ht, 0, new_size*sizeof(struct _ht)); + for(elem=pH->first, pH->first=0; elem; elem = next_elem){ + unsigned int h = strHash(elem->pKey) % new_size; + next_elem = elem->next; + insertElement(pH, &new_ht[h], elem); + } + return 1; +} + +/* This function (for internal use only) locates an element in an +** hash table that matches the given key. The hash for this key is +** also computed and returned in the *pH parameter. +*/ +static HashElem *findElementWithHash( + const Hash *pH, /* The pH to be searched */ + const char *pKey, /* The key we are searching for */ + unsigned int *pHash /* Write the hash value here */ +){ + HashElem *elem; /* Used to loop thru the element list */ + int count; /* Number of elements left to test */ + unsigned int h; /* The computed hash */ + + if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ + struct _ht *pEntry; + h = strHash(pKey) % pH->htsize; + pEntry = &pH->ht[h]; + elem = pEntry->chain; + count = pEntry->count; + }else{ + h = 0; + elem = pH->first; + count = pH->count; + } + *pHash = h; + while( count-- ){ + assert( elem!=0 ); + if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ + return elem; + } + elem = elem->next; + } + return 0; +} + +/* Remove a single entry from the hash table given a pointer to that +** element and a hash on the element's key. +*/ +static void removeElementGivenHash( + Hash *pH, /* The pH containing "elem" */ + HashElem* elem, /* The element to be removed from the pH */ + unsigned int h /* Hash value for the element */ +){ + struct _ht *pEntry; + if( elem->prev ){ + elem->prev->next = elem->next; + }else{ + pH->first = elem->next; + } + if( elem->next ){ + elem->next->prev = elem->prev; + } + if( pH->ht ){ + pEntry = &pH->ht[h]; + if( pEntry->chain==elem ){ + pEntry->chain = elem->next; + } + pEntry->count--; + assert( pEntry->count>=0 ); + } + sqlite3_free( elem ); + pH->count--; + if( pH->count==0 ){ + assert( pH->first==0 ); + assert( pH->count==0 ); + sqlite3HashClear(pH); + } +} + +/* Attempt to locate an element of the hash table pH with a key +** that matches pKey. Return the data for this element if it is +** found, or NULL if there is no match. +*/ +SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ + HashElem *elem; /* The element that matches key */ + unsigned int h; /* A hash on key */ + + assert( pH!=0 ); + assert( pKey!=0 ); + elem = findElementWithHash(pH, pKey, &h); + return elem ? elem->data : 0; +} + +/* Insert an element into the hash table pH. The key is pKey +** and the data is "data". +** +** If no element exists with a matching key, then a new +** element is created and NULL is returned. +** +** If another element already exists with the same key, then the +** new data replaces the old data and the old data is returned. +** The key is not copied in this instance. If a malloc fails, then +** the new data is returned and the hash table is unchanged. +** +** If the "data" parameter to this function is NULL, then the +** element corresponding to "key" is removed from the hash table. +*/ +SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ + unsigned int h; /* the hash of the key modulo hash table size */ + HashElem *elem; /* Used to loop thru the element list */ + HashElem *new_elem; /* New element added to the pH */ + + assert( pH!=0 ); + assert( pKey!=0 ); + elem = findElementWithHash(pH,pKey,&h); + if( elem ){ + void *old_data = elem->data; + if( data==0 ){ + removeElementGivenHash(pH,elem,h); + }else{ + elem->data = data; + elem->pKey = pKey; + } + return old_data; + } + if( data==0 ) return 0; + new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); + if( new_elem==0 ) return data; + new_elem->pKey = pKey; + new_elem->data = data; + pH->count++; + if( pH->count>=10 && pH->count > 2*pH->htsize ){ + if( rehash(pH, pH->count*2) ){ + assert( pH->htsize>0 ); + h = strHash(pKey) % pH->htsize; + } + } + insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); + return 0; +} + +/************** End of hash.c ************************************************/ +/************** Begin file opcodes.c *****************************************/ +/* Automatically generated. Do not edit */ +/* See the tool/mkopcodec.tcl script for details. */ +#if !defined(SQLITE_OMIT_EXPLAIN) \ + || defined(VDBE_PROFILE) \ + || defined(SQLITE_DEBUG) +#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) || defined(SQLITE_DEBUG) +# define OpHelp(X) "\0" X +#else +# define OpHelp(X) +#endif +SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ + static const char *const azName[] = { + /* 0 */ "Savepoint" OpHelp(""), + /* 1 */ "AutoCommit" OpHelp(""), + /* 2 */ "Transaction" OpHelp(""), + /* 3 */ "SorterNext" OpHelp(""), + /* 4 */ "PrevIfOpen" OpHelp(""), + /* 5 */ "NextIfOpen" OpHelp(""), + /* 6 */ "Prev" OpHelp(""), + /* 7 */ "Next" OpHelp(""), + /* 8 */ "Checkpoint" OpHelp(""), + /* 9 */ "JournalMode" OpHelp(""), + /* 10 */ "Vacuum" OpHelp(""), + /* 11 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), + /* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"), + /* 13 */ "Goto" OpHelp(""), + /* 14 */ "Gosub" OpHelp(""), + /* 15 */ "InitCoroutine" OpHelp(""), + /* 16 */ "Yield" OpHelp(""), + /* 17 */ "MustBeInt" OpHelp(""), + /* 18 */ "Jump" OpHelp(""), + /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), + /* 20 */ "Once" OpHelp(""), + /* 21 */ "If" OpHelp(""), + /* 22 */ "IfNot" OpHelp(""), + /* 23 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), + /* 24 */ "SeekLT" OpHelp("key=r[P3@P4]"), + /* 25 */ "SeekLE" OpHelp("key=r[P3@P4]"), + /* 26 */ "SeekGE" OpHelp("key=r[P3@P4]"), + /* 27 */ "SeekGT" OpHelp("key=r[P3@P4]"), + /* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 29 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 30 */ "Found" OpHelp("key=r[P3@P4]"), + /* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"), + /* 32 */ "NotExists" OpHelp("intkey=r[P3]"), + /* 33 */ "Last" OpHelp(""), + /* 34 */ "IfSmaller" OpHelp(""), + /* 35 */ "SorterSort" OpHelp(""), + /* 36 */ "Sort" OpHelp(""), + /* 37 */ "Rewind" OpHelp(""), + /* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 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 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 70 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), + /* 71 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), + /* 72 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), + /* 73 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 74 */ "RealAffinity" 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]"), + /* 83 */ "ElseNotEq" 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]"), + /* 88 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 89 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 90 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 91 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 92 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 93 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 94 */ "Cast" OpHelp("affinity(r[P1])"), + /* 95 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), + /* 96 */ "Permutation" OpHelp(""), + /* 97 */ "String8" OpHelp("r[P2]='P4'"), + /* 98 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 99 */ "Column" OpHelp("r[P3]=PX"), + /* 100 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 101 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 102 */ "Count" OpHelp("r[P2]=count()"), + /* 103 */ "ReadCookie" OpHelp(""), + /* 104 */ "SetCookie" OpHelp(""), + /* 105 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 106 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 107 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 108 */ "OpenDup" OpHelp(""), + /* 109 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 110 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 111 */ "SorterOpen" OpHelp(""), + /* 112 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 113 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 114 */ "Close" OpHelp(""), + /* 115 */ "ColumnsUsed" OpHelp(""), + /* 116 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 117 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 118 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 119 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 120 */ "Delete" OpHelp(""), + /* 121 */ "ResetCount" OpHelp(""), + /* 122 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 123 */ "SorterData" OpHelp("r[P2]=data"), + /* 124 */ "RowData" OpHelp("r[P2]=data"), + /* 125 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 126 */ "NullRow" OpHelp(""), + /* 127 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 128 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 129 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 130 */ "Seek" OpHelp("Move P3 to P1.rowid"), + /* 131 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 132 */ "Real" OpHelp("r[P2]=P4"), + /* 133 */ "Destroy" OpHelp(""), + /* 134 */ "Clear" OpHelp(""), + /* 135 */ "ResetSorter" OpHelp(""), + /* 136 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), + /* 137 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), + /* 138 */ "SqlExec" OpHelp(""), + /* 139 */ "ParseSchema" OpHelp(""), + /* 140 */ "LoadAnalysis" OpHelp(""), + /* 141 */ "DropTable" OpHelp(""), + /* 142 */ "DropIndex" OpHelp(""), + /* 143 */ "DropTrigger" OpHelp(""), + /* 144 */ "IntegrityCk" OpHelp(""), + /* 145 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 146 */ "Param" OpHelp(""), + /* 147 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 148 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 149 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 150 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 151 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 152 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 153 */ "Expire" OpHelp(""), + /* 154 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 155 */ "VBegin" OpHelp(""), + /* 156 */ "VCreate" OpHelp(""), + /* 157 */ "VDestroy" OpHelp(""), + /* 158 */ "VOpen" OpHelp(""), + /* 159 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 160 */ "VRename" OpHelp(""), + /* 161 */ "Pagecount" OpHelp(""), + /* 162 */ "MaxPgcnt" OpHelp(""), + /* 163 */ "CursorHint" OpHelp(""), + /* 164 */ "Noop" OpHelp(""), + /* 165 */ "Explain" OpHelp(""), + }; + return azName[i]; +} +#endif + +/************** End of opcodes.c *********************************************/ +/************** Begin file os_unix.c *****************************************/ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains the VFS implementation for unix-like operating systems +** include Linux, MacOSX, *BSD, QNX, VxWorks, AIX, HPUX, and others. +** +** There are actually several different VFS implementations in this file. +** The differences are in the way that file locking is done. The default +** implementation uses Posix Advisory Locks. Alternative implementations +** use flock(), dot-files, various proprietary locking schemas, or simply +** skip locking all together. +** +** This source file is organized into divisions where the logic for various +** subfunctions is contained within the appropriate division. PLEASE +** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed +** in the correct division and should be clearly labeled. +** +** The layout of divisions is as follows: +** +** * General-purpose declarations and utility functions. +** * Unique file ID logic used by VxWorks. +** * Various locking primitive implementations (all except proxy locking): +** + for Posix Advisory Locks +** + for no-op locks +** + for dot-file locks +** + for flock() locking +** + for named semaphore locks (VxWorks only) +** + for AFP filesystem locks (MacOSX only) +** * sqlite3_file methods not associated with locking. +** * Definitions of sqlite3_io_methods objects for all locking +** methods plus "finder" functions for each locking method. +** * sqlite3_vfs method implementations. +** * Locking primitives for the proxy uber-locking-method. (MacOSX only) +** * Definitions of sqlite3_vfs objects for all locking methods +** plus implementations of sqlite3_os_init() and sqlite3_os_end(). +*/ +/* #include "sqliteInt.h" */ +#if SQLITE_OS_UNIX /* This file is used on unix only */ + +/* +** There are various methods for file locking used for concurrency +** control: +** +** 1. POSIX locking (the default), +** 2. No locking, +** 3. Dot-file locking, +** 4. flock() locking, +** 5. AFP locking (OSX only), +** 6. Named POSIX semaphores (VXWorks only), +** 7. proxy locking. (OSX only) +** +** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE +** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic +** selection of the appropriate locking style based on the filesystem +** where the database is located. +*/ +#if !defined(SQLITE_ENABLE_LOCKING_STYLE) +# if defined(__APPLE__) +# define SQLITE_ENABLE_LOCKING_STYLE 1 +# else +# define SQLITE_ENABLE_LOCKING_STYLE 0 +# endif +#endif + +/* Use pread() and pwrite() if they are available */ +#if defined(__APPLE__) +# define HAVE_PREAD 1 +# define HAVE_PWRITE 1 +#endif +#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64) +# undef USE_PREAD +# define USE_PREAD64 1 +#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE) +# undef USE_PREAD64 +# define USE_PREAD 1 +#endif + +/* +** standard include files. +*/ +#include +#include +#include +#include +/* #include */ +#include +#include +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 +# include +#endif + +#if SQLITE_ENABLE_LOCKING_STYLE +# include +# include +# include +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + +#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ + (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) +# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ + && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0)) +# define HAVE_GETHOSTUUID 1 +# else +# warning "gethostuuid() is disabled." +# endif +#endif + + +#if OS_VXWORKS +/* # include */ +# include +# include +#endif /* OS_VXWORKS */ + +#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE +# include +#endif + +#ifdef HAVE_UTIME +# include +#endif + +/* +** Allowed values of unixFile.fsFlags +*/ +#define SQLITE_FSFLAGS_IS_MSDOS 0x1 + +/* +** If we are to be thread-safe, include the pthreads header and define +** the SQLITE_UNIX_THREADS macro. +*/ +#if SQLITE_THREADSAFE +/* # include */ +# define SQLITE_UNIX_THREADS 1 +#endif + +/* +** Default permissions when creating a new file +*/ +#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS +# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 +#endif + +/* +** Default permissions when creating auto proxy dir +*/ +#ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS +# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755 +#endif + +/* +** Maximum supported path-length. +*/ +#define MAX_PATHNAME 512 + +/* +** Maximum supported symbolic links +*/ +#define SQLITE_MAX_SYMLINKS 100 + +/* Always cast the getpid() return type for compatibility with +** kernel modules in VxWorks. */ +#define osGetpid(X) (pid_t)getpid() + +/* +** Only set the lastErrno if the error code is a real error and not +** a normal expected return code of SQLITE_BUSY or SQLITE_OK +*/ +#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY)) + +/* Forward references */ +typedef struct unixShm unixShm; /* Connection shared memory */ +typedef struct unixShmNode unixShmNode; /* Shared memory instance */ +typedef struct unixInodeInfo unixInodeInfo; /* An i-node */ +typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */ + +/* +** Sometimes, after a file handle is closed by SQLite, the file descriptor +** cannot be closed immediately. In these cases, instances of the following +** structure are used to store the file descriptor while waiting for an +** opportunity to either close or reuse it. +*/ +struct UnixUnusedFd { + int fd; /* File descriptor to close */ + int flags; /* Flags this file descriptor was opened with */ + UnixUnusedFd *pNext; /* Next unused file descriptor on same file */ +}; + +/* +** The unixFile structure is subclass of sqlite3_file specific to the unix +** VFS implementations. +*/ +typedef struct unixFile unixFile; +struct unixFile { + sqlite3_io_methods const *pMethod; /* Always the first entry */ + sqlite3_vfs *pVfs; /* The VFS that created this unixFile */ + unixInodeInfo *pInode; /* Info about locks on this inode */ + int h; /* The file descriptor */ + unsigned char eFileLock; /* The type of lock held on this fd */ + 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 */ + const char *zPath; /* Name of the file */ + unixShm *pShm; /* Shared memory segment information */ + int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ +#if SQLITE_MAX_MMAP_SIZE>0 + int nFetchOut; /* Number of outstanding xFetch refs */ + sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */ + sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */ + 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 +#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) + unsigned fsFlags; /* cached details from statfs() */ +#endif +#if OS_VXWORKS + struct vxworksFileId *pId; /* Unique file ID */ +#endif +#ifdef SQLITE_DEBUG + /* The next group of variables are used to track whether or not the + ** transaction counter in bytes 24-27 of database files are updated + ** whenever any part of the database changes. An assertion fault will + ** occur if a file is updated without also updating the transaction + ** counter. This test is made to avoid new problems similar to the + ** one described by ticket #3584. + */ + unsigned char transCntrChng; /* True if the transaction counter changed */ + unsigned char dbUpdate; /* True if any part of database file changed */ + unsigned char inNormalWrite; /* True if in a normal write operation */ + +#endif + +#ifdef SQLITE_TEST + /* In test mode, increase the size of this structure a bit so that + ** it is larger than the struct CrashFile defined in test6.c. + */ + char aPadding[32]; +#endif +}; + +/* This variable holds the process id (pid) from when the xRandomness() +** method was called. If xOpen() is called from a different process id, +** indicating that a fork() has occurred, the PRNG will be reset. +*/ +static pid_t randomnessPid = 0; + +/* +** Allowed values for the unixFile.ctrlFlags bitmask: +*/ +#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ +#define UNIXFILE_RDONLY 0x02 /* Connection is read only */ +#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ +#ifndef SQLITE_DISABLE_DIRSYNC +# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ +#else +# define UNIXFILE_DIRSYNC 0x00 +#endif +#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ +#define UNIXFILE_DELETE 0x20 /* Delete on close */ +#define UNIXFILE_URI 0x40 /* Filename might have query parameters */ +#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ + +/* +** Include code that is common to all os_*.c files +*/ +/************** Include os_common.h in the middle of os_unix.c ***************/ +/************** Begin file os_common.h ***************************************/ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains macros and a little bit of code that is common to +** all of the platform-specific files (os_*.c) and is #included into those +** files. +** +** This file should be #included by the os_*.c files only. It is not a +** general purpose header file. +*/ +#ifndef _OS_COMMON_H_ +#define _OS_COMMON_H_ + +/* +** At least two bugs have slipped in because we changed the MEMORY_DEBUG +** macro to SQLITE_DEBUG and some older makefiles have not yet made the +** switch. The following code should catch this problem at compile-time. +*/ +#ifdef MEMORY_DEBUG +# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." +#endif + +/* +** Macros for performance tracing. Normally turned off. Only works +** on i486 hardware. +*/ +#ifdef SQLITE_PERFORMANCE_TRACE + +/* +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. +*/ +/************** Include hwtime.h in the middle of os_common.h ****************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 class CPUs. +*/ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H + +/* +** The following routine only works on pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } + +#elif (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + #error Need implementation of sqlite3Hwtime() for your platform. + + /* + ** To compile without implementing sqlite3Hwtime() for your platform, + ** you can remove the above #error and use the following + ** stub function. You will lose timing support for many + ** of the debugging and testing utilities, but it should at + ** least compile and run. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in os_common.h ******************/ + +static sqlite_uint64 g_start; +static sqlite_uint64 g_elapsed; +#define TIMER_START g_start=sqlite3Hwtime() +#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start +#define TIMER_ELAPSED g_elapsed +#else +#define TIMER_START +#define TIMER_END +#define TIMER_ELAPSED ((sqlite_uint64)0) +#endif + +/* +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; +#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) +#define SimulateIOError(CODE) \ + if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ + || sqlite3_io_error_pending-- == 1 ) \ + { local_ioerr(); CODE; } +static void local_ioerr(){ + IOTRACE(("IOERR\n")); + sqlite3_io_error_hit++; + if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; +} +#define SimulateDiskfullError(CODE) \ + if( sqlite3_diskfull_pending ){ \ + if( sqlite3_diskfull_pending == 1 ){ \ + local_ioerr(); \ + sqlite3_diskfull = 1; \ + sqlite3_io_error_hit = 1; \ + CODE; \ + }else{ \ + sqlite3_diskfull_pending--; \ + } \ + } +#else +#define SimulateIOErrorBenign(X) +#define SimulateIOError(A) +#define SimulateDiskfullError(A) +#endif /* defined(SQLITE_TEST) */ + +/* +** When testing, keep a count of the number of open files. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; +#define OpenCounter(X) sqlite3_open_file_count+=(X) +#else +#define OpenCounter(X) +#endif /* defined(SQLITE_TEST) */ + +#endif /* !defined(_OS_COMMON_H_) */ + +/************** End of os_common.h *******************************************/ +/************** Continuing where we left off in os_unix.c ********************/ + +/* +** Define various macros that are missing from some systems. +*/ +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif +#ifdef SQLITE_DISABLE_LFS +# undef O_LARGEFILE +# define O_LARGEFILE 0 +#endif +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +/* +** The threadid macro resolves to the thread-id or to 0. Used for +** testing and debugging only. +*/ +#if SQLITE_THREADSAFE +#define threadid pthread_self() +#else +#define threadid 0 +#endif + +/* +** HAVE_MREMAP defaults to true on Linux and false everywhere else. +*/ +#if !defined(HAVE_MREMAP) +# if defined(__linux__) && defined(_GNU_SOURCE) +# define HAVE_MREMAP 1 +# else +# define HAVE_MREMAP 0 +# endif +#endif + +/* +** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek() +** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined. +*/ +#ifdef __ANDROID__ +# define lseek lseek64 +#endif + +/* +** Different Unix systems declare open() in different ways. Same use +** open(const char*,int,mode_t). Others use open(const char*,int,...). +** The difference is important when using a pointer to the function. +** +** The safest way to deal with the problem is to always use this wrapper +** which always has the same well-defined interface. +*/ +static int posixOpen(const char *zFile, int flags, int mode){ + return open(zFile, flags, mode); +} + +/* Forward reference */ +static int openDirectory(const char*, int*); +static int unixGetpagesize(void); + +/* +** Many system calls are accessed through pointer-to-functions so that +** they may be overridden at runtime to facilitate fault injection during +** testing and sandboxing. The following array holds the names and pointers +** to all overrideable system calls. +*/ +static struct unix_syscall { + const char *zName; /* Name of the system call */ + sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ + sqlite3_syscall_ptr pDefault; /* Default value */ +} aSyscall[] = { + { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, +#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) + + { "close", (sqlite3_syscall_ptr)close, 0 }, +#define osClose ((int(*)(int))aSyscall[1].pCurrent) + + { "access", (sqlite3_syscall_ptr)access, 0 }, +#define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent) + + { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 }, +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent) + + { "stat", (sqlite3_syscall_ptr)stat, 0 }, +#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent) + +/* +** The DJGPP compiler environment looks mostly like Unix, but it +** lacks the fcntl() system call. So redefine fcntl() to be something +** that always succeeds. This means that locking does not occur under +** DJGPP. But it is DOS - what did you expect? +*/ +#ifdef __DJGPP__ + { "fstat", 0, 0 }, +#define osFstat(a,b,c) 0 +#else + { "fstat", (sqlite3_syscall_ptr)fstat, 0 }, +#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent) +#endif + + { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 }, +#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent) + + { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 }, +#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) + + { "read", (sqlite3_syscall_ptr)read, 0 }, +#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) + +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE + { "pread", (sqlite3_syscall_ptr)pread, 0 }, +#else + { "pread", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) + +#if defined(USE_PREAD64) + { "pread64", (sqlite3_syscall_ptr)pread64, 0 }, +#else + { "pread64", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent) + + { "write", (sqlite3_syscall_ptr)write, 0 }, +#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) + +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE + { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, +#else + { "pwrite", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ + aSyscall[12].pCurrent) + +#if defined(USE_PREAD64) + { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, +#else + { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ + aSyscall[13].pCurrent) + + { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, +#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) + +#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE + { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, +#else + { "fallocate", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent) + + { "unlink", (sqlite3_syscall_ptr)unlink, 0 }, +#define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent) + + { "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 }, +#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent) + + { "mkdir", (sqlite3_syscall_ptr)mkdir, 0 }, +#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent) + + { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, +#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) + +#if defined(HAVE_FCHOWN) + { "fchown", (sqlite3_syscall_ptr)fchown, 0 }, +#else + { "fchown", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) + + { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, +#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) + +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 + { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, +#else + { "mmap", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) + +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 + { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, +#else + { "munmap", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent) + +#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) + { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, +#else + { "mremap", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent) + +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 + { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, +#else + { "getpagesize", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent) + +#if defined(HAVE_READLINK) + { "readlink", (sqlite3_syscall_ptr)readlink, 0 }, +#else + { "readlink", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent) + +#if defined(HAVE_LSTAT) + { "lstat", (sqlite3_syscall_ptr)lstat, 0 }, +#else + { "lstat", (sqlite3_syscall_ptr)0, 0 }, +#endif +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) + +}; /* End of the overrideable system calls */ + + +/* +** On some systems, calls to fchown() will trigger a message in a security +** log if they come from non-root processes. So avoid calling fchown() if +** we are not running as root. +*/ +static int robustFchown(int fd, uid_t uid, gid_t gid){ +#if defined(HAVE_FCHOWN) + return osGeteuid() ? 0 : osFchown(fd,uid,gid); +#else + return 0; +#endif +} + +/* +** This is the xSetSystemCall() method of sqlite3_vfs for all of the +** "unix" VFSes. Return SQLITE_OK opon successfully updating the +** system call pointer, or SQLITE_NOTFOUND if there is no configurable +** system call named zName. +*/ +static int unixSetSystemCall( + sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */ + const char *zName, /* Name of system call to override */ + sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */ +){ + unsigned int i; + int rc = SQLITE_NOTFOUND; + + UNUSED_PARAMETER(pNotUsed); + if( zName==0 ){ + /* If no zName is given, restore all system calls to their default + ** settings and return NULL + */ + rc = SQLITE_OK; + for(i=0; i=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; + osClose(fd); + sqlite3_log(SQLITE_WARNING, + "attempt to open \"%s\" as file descriptor %d", z, fd); + fd = -1; + if( osOpen("/dev/null", f, m)<0 ) break; + } + if( fd>=0 ){ + if( m!=0 ){ + struct stat statbuf; + if( osFstat(fd, &statbuf)==0 + && statbuf.st_size==0 + && (statbuf.st_mode&0777)!=m + ){ + osFchmod(fd, m); + } + } +#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) + osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); +#endif + } + return fd; +} + +/* +** Helper functions to obtain and relinquish the global mutex. The +** global mutex is used to protect the unixInodeInfo and +** vxworksFileId objects used by this file, all of which may be +** shared by multiple threads. +** +** Function unixMutexHeld() is used to assert() that the global mutex +** is held when required. This function is only used as part of assert() +** statements. e.g. +** +** unixEnterMutex() +** assert( unixMutexHeld() ); +** unixEnterLeave() +*/ +static void unixEnterMutex(void){ + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); +} +static void unixLeaveMutex(void){ + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); +} +#ifdef SQLITE_DEBUG +static int unixMutexHeld(void) { + return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); +} +#endif + + +#ifdef SQLITE_HAVE_OS_TRACE +/* +** Helper function for printing out trace information from debugging +** binaries. This returns the string representation of the supplied +** integer lock-type. +*/ +static const char *azFileLock(int eFileLock){ + switch( eFileLock ){ + case NO_LOCK: return "NONE"; + case SHARED_LOCK: return "SHARED"; + case RESERVED_LOCK: return "RESERVED"; + case PENDING_LOCK: return "PENDING"; + case EXCLUSIVE_LOCK: return "EXCLUSIVE"; + } + return "ERROR"; +} +#endif + +#ifdef SQLITE_LOCK_TRACE +/* +** Print out information about all locking operations. +** +** This routine is used for troubleshooting locks on multithreaded +** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE +** command-line option on the compiler. This code is normally +** turned off. +*/ +static int lockTrace(int fd, int op, struct flock *p){ + char *zOpName, *zType; + int s; + int savedErrno; + if( op==F_GETLK ){ + zOpName = "GETLK"; + }else if( op==F_SETLK ){ + zOpName = "SETLK"; + }else{ + s = osFcntl(fd, op, p); + sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); + return s; + } + if( p->l_type==F_RDLCK ){ + zType = "RDLCK"; + }else if( p->l_type==F_WRLCK ){ + zType = "WRLCK"; + }else if( p->l_type==F_UNLCK ){ + zType = "UNLCK"; + }else{ + assert( 0 ); + } + assert( p->l_whence==SEEK_SET ); + s = osFcntl(fd, op, p); + savedErrno = errno; + sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", + threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, + (int)p->l_pid, s); + if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ + struct flock l2; + l2 = *p; + osFcntl(fd, F_GETLK, &l2); + if( l2.l_type==F_RDLCK ){ + zType = "RDLCK"; + }else if( l2.l_type==F_WRLCK ){ + zType = "WRLCK"; + }else if( l2.l_type==F_UNLCK ){ + zType = "UNLCK"; + }else{ + assert( 0 ); + } + sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", + zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); + } + errno = savedErrno; + return s; +} +#undef osFcntl +#define osFcntl lockTrace +#endif /* SQLITE_LOCK_TRACE */ + +/* +** Retry ftruncate() calls that fail due to EINTR +** +** All calls to ftruncate() within this file should be made through +** this wrapper. On the Android platform, bypassing the logic below +** could lead to a corrupt database. +*/ +static int robust_ftruncate(int h, sqlite3_int64 sz){ + int rc; +#ifdef __ANDROID__ + /* On Android, ftruncate() always uses 32-bit offsets, even if + ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to + ** truncate a file to any size larger than 2GiB. Silently ignore any + ** such attempts. */ + if( sz>(sqlite3_int64)0x7FFFFFFF ){ + rc = SQLITE_OK; + }else +#endif + do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); + return rc; +} + +/* +** This routine translates a standard POSIX errno code into something +** useful to the clients of the sqlite3 functions. Specifically, it is +** intended to translate a variety of "try again" errors into SQLITE_BUSY +** and a variety of "please close the file descriptor NOW" errors into +** SQLITE_IOERR +** +** Errors during initialization of locks, or file system support for locks, +** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. +*/ +static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { + assert( (sqliteIOErr == SQLITE_IOERR_LOCK) || + (sqliteIOErr == SQLITE_IOERR_UNLOCK) || + (sqliteIOErr == SQLITE_IOERR_RDLOCK) || + (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ); + switch (posixError) { + case EACCES: + case EAGAIN: + case ETIMEDOUT: + case EBUSY: + case EINTR: + case ENOLCK: + /* random NFS retry error, unless during file system support + * introspection, in which it actually means what it says */ + return SQLITE_BUSY; + + case EPERM: + return SQLITE_PERM; + + default: + return sqliteIOErr; + } +} + + +/****************************************************************************** +****************** Begin Unique File ID Utility Used By VxWorks *************** +** +** On most versions of unix, we can get a unique ID for a file by concatenating +** the device number and the inode number. But this does not work on VxWorks. +** On VxWorks, a unique file id must be based on the canonical filename. +** +** A pointer to an instance of the following structure can be used as a +** unique file ID in VxWorks. Each instance of this structure contains +** a copy of the canonical filename. There is also a reference count. +** The structure is reclaimed when the number of pointers to it drops to +** zero. +** +** There are never very many files open at one time and lookups are not +** a performance-critical path, so it is sufficient to put these +** structures on a linked list. +*/ +struct vxworksFileId { + struct vxworksFileId *pNext; /* Next in a list of them all */ + int nRef; /* Number of references to this one */ + int nName; /* Length of the zCanonicalName[] string */ + char *zCanonicalName; /* Canonical filename */ +}; + +#if OS_VXWORKS +/* +** All unique filenames are held on a linked list headed by this +** variable: +*/ +static struct vxworksFileId *vxworksFileList = 0; + +/* +** Simplify a filename into its canonical form +** by making the following changes: +** +** * removing any trailing and duplicate / +** * convert /./ into just / +** * convert /A/../ where A is any simple name into just / +** +** Changes are made in-place. Return the new name length. +** +** The original filename is in z[0..n-1]. Return the number of +** characters in the simplified name. +*/ +static int vxworksSimplifyName(char *z, int n){ + int i, j; + while( n>1 && z[n-1]=='/' ){ n--; } + for(i=j=0; i0 && z[j-1]!='/' ){ j--; } + if( j>0 ){ j--; } + i += 2; + continue; + } + } + z[j++] = z[i]; + } + z[j] = 0; + return j; +} + +/* +** Find a unique file ID for the given absolute pathname. Return +** a pointer to the vxworksFileId object. This pointer is the unique +** file ID. +** +** The nRef field of the vxworksFileId object is incremented before +** the object is returned. A new vxworksFileId object is created +** and added to the global list if necessary. +** +** If a memory allocation error occurs, return NULL. +*/ +static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ + struct vxworksFileId *pNew; /* search key and new file ID */ + struct vxworksFileId *pCandidate; /* For looping over existing file IDs */ + int n; /* Length of zAbsoluteName string */ + + assert( zAbsoluteName[0]=='/' ); + n = (int)strlen(zAbsoluteName); + pNew = sqlite3_malloc64( sizeof(*pNew) + (n+1) ); + if( pNew==0 ) return 0; + pNew->zCanonicalName = (char*)&pNew[1]; + memcpy(pNew->zCanonicalName, zAbsoluteName, n+1); + n = vxworksSimplifyName(pNew->zCanonicalName, n); + + /* Search for an existing entry that matching the canonical name. + ** If found, increment the reference count and return a pointer to + ** the existing file ID. + */ + unixEnterMutex(); + for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){ + if( pCandidate->nName==n + && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0 + ){ + sqlite3_free(pNew); + pCandidate->nRef++; + unixLeaveMutex(); + return pCandidate; + } + } + + /* No match was found. We will make a new file ID */ + pNew->nRef = 1; + pNew->nName = n; + pNew->pNext = vxworksFileList; + vxworksFileList = pNew; + unixLeaveMutex(); + return pNew; +} + +/* +** Decrement the reference count on a vxworksFileId object. Free +** the object when the reference count reaches zero. +*/ +static void vxworksReleaseFileId(struct vxworksFileId *pId){ + unixEnterMutex(); + assert( pId->nRef>0 ); + pId->nRef--; + if( pId->nRef==0 ){ + struct vxworksFileId **pp; + for(pp=&vxworksFileList; *pp && *pp!=pId; pp = &((*pp)->pNext)){} + assert( *pp==pId ); + *pp = pId->pNext; + sqlite3_free(pId); + } + unixLeaveMutex(); +} +#endif /* OS_VXWORKS */ +/*************** End of Unique File ID Utility Used By VxWorks **************** +******************************************************************************/ + + +/****************************************************************************** +*************************** Posix Advisory Locking **************************** +** +** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996) +** section 6.5.2.2 lines 483 through 490 specify that when a process +** sets or clears a lock, that operation overrides any prior locks set +** by the same process. It does not explicitly say so, but this implies +** that it overrides locks set by the same process using a different +** file descriptor. Consider this test case: +** +** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); +** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); +** +** Suppose ./file1 and ./file2 are really the same file (because +** one is a hard or symbolic link to the other) then if you set +** an exclusive lock on fd1, then try to get an exclusive lock +** on fd2, it works. I would have expected the second lock to +** fail since there was already a lock on the file due to fd1. +** But not so. Since both locks came from the same process, the +** second overrides the first, even though they were on different +** file descriptors opened on different file names. +** +** This means that we cannot use POSIX locks to synchronize file access +** among competing threads of the same process. POSIX locks will work fine +** to synchronize access for threads in separate processes, but not +** threads within the same process. +** +** To work around the problem, SQLite has to manage file locks internally +** on its own. Whenever a new database is opened, we have to find the +** specific inode of the database file (the inode is determined by the +** st_dev and st_ino fields of the stat structure that fstat() fills in) +** and check for locks already existing on that inode. When locks are +** created or removed, we have to look at our own internal record of the +** locks to see if another thread has previously set a lock on that same +** inode. +** +** (Aside: The use of inode numbers as unique IDs does not work on VxWorks. +** For VxWorks, we have to use the alternative unique ID system based on +** canonical filename and implemented in the previous division.) +** +** The sqlite3_file structure for POSIX is no longer just an integer file +** descriptor. It is now a structure that holds the integer file +** descriptor and a pointer to a structure that describes the internal +** locks on the corresponding inode. There is one locking structure +** per inode, so if the same inode is opened twice, both unixFile structures +** point to the same locking structure. The locking structure keeps +** a reference count (so we will know when to delete it) and a "cnt" +** field that tells us its internal lock status. cnt==0 means the +** file is unlocked. cnt==-1 means the file has an exclusive lock. +** cnt>0 means there are cnt shared locks on the file. +** +** Any attempt to lock or unlock a file first checks the locking +** structure. The fcntl() system call is only invoked to set a +** POSIX lock if the internal lock structure transitions between +** a locked and an unlocked state. +** +** But wait: there are yet more problems with POSIX advisory locks. +** +** If you close a file descriptor that points to a file that has locks, +** all locks on that file that are owned by the current process are +** released. To work around this problem, each unixInodeInfo object +** maintains a count of the number of pending locks on tha inode. +** When an attempt is made to close an unixFile, if there are +** other unixFile open on the same inode that are holding locks, the call +** to close() the file descriptor is deferred until all of the locks clear. +** The unixInodeInfo structure keeps a list of file descriptors that need to +** be closed and that list is walked (and cleared) when the last lock +** clears. +** +** Yet another problem: LinuxThreads do not play well with posix locks. +** +** Many older versions of linux use the LinuxThreads library which is +** not posix compliant. Under LinuxThreads, a lock created by thread +** A cannot be modified or overridden by a different thread B. +** Only thread A can modify the lock. Locking behavior is correct +** if the appliation uses the newer Native Posix Thread Library (NPTL) +** on linux - with NPTL a lock created by thread A can override locks +** in thread B. But there is no way to know at compile-time which +** threading library is being used. So there is no way to know at +** compile-time whether or not thread A can override locks on thread B. +** One has to do a run-time check to discover the behavior of the +** current process. +** +** SQLite used to support LinuxThreads. But support for LinuxThreads +** was dropped beginning with version 3.7.0. SQLite will still work with +** LinuxThreads provided that (1) there is no more than one connection +** per database file in the same process and (2) database connections +** do not move across threads. +*/ + +/* +** An instance of the following structure serves as the key used +** to locate a particular unixInodeInfo object. +*/ +struct unixFileId { + dev_t dev; /* Device number */ +#if OS_VXWORKS + struct vxworksFileId *pId; /* Unique file ID for vxworks. */ +#else + /* We are told that some versions of Android contain a bug that + ** sizes ino_t at only 32-bits instead of 64-bits. (See + ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c) + ** To work around this, always allocate 64-bits for the inode number. + ** On small machines that only have 32-bit inodes, this wastes 4 bytes, + ** but that should not be a big deal. */ + /* WAS: ino_t ino; */ + u64 ino; /* Inode number */ +#endif +}; + +/* +** An instance of the following structure is allocated for each open +** inode. Or, on LinuxThreads, there is one of these structures for +** each inode opened by each thread. +** +** A single inode can have multiple file descriptors, so each unixFile +** structure contains a pointer to an instance of this object and this +** object keeps a count of the number of unixFile pointing to it. +*/ +struct unixInodeInfo { + struct unixFileId fileId; /* The lookup key */ + int nShared; /* Number of SHARED locks held */ + unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ + unsigned char bProcessLock; /* An exclusive process lock is held */ + int nRef; /* Number of pointers to this structure */ + unixShmNode *pShmNode; /* Shared memory associated with this inode */ + int nLock; /* Number of outstanding file locks */ + UnixUnusedFd *pUnused; /* Unused file descriptors to close */ + unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ + unixInodeInfo *pPrev; /* .... doubly linked */ +#if SQLITE_ENABLE_LOCKING_STYLE + unsigned long long sharedByte; /* for AFP simulated shared lock */ +#endif +#if OS_VXWORKS + sem_t *pSem; /* Named POSIX semaphore */ + char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ +#endif +}; + +/* +** A lists of all unixInodeInfo objects. +*/ +static unixInodeInfo *inodeList = 0; + +/* +** +** This function - unixLogErrorAtLine(), is only ever called via the macro +** unixLogError(). +** +** It is invoked after an error occurs in an OS function and errno has been +** set. It logs a message using sqlite3_log() containing the current value of +** errno and, if possible, the human-readable equivalent from strerror() or +** strerror_r(). +** +** The first argument passed to the macro should be the error code that +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). +** The two subsequent arguments should be the name of the OS function that +** failed (e.g. "unlink", "open") and the associated file-system path, +** if any. +*/ +#define unixLogError(a,b,c) unixLogErrorAtLine(a,b,c,__LINE__) +static int unixLogErrorAtLine( + int errcode, /* SQLite error code */ + const char *zFunc, /* Name of OS function that failed */ + const char *zPath, /* File path associated with error */ + int iLine /* Source line number where error occurred */ +){ + char *zErr; /* Message from strerror() or equivalent */ + int iErrno = errno; /* Saved syscall error number */ + + /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use + ** the strerror() function to obtain the human-readable error message + ** equivalent to errno. Otherwise, use strerror_r(). + */ +#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R) + char aErr[80]; + memset(aErr, 0, sizeof(aErr)); + zErr = aErr; + + /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, + ** assume that the system provides the GNU version of strerror_r() that + ** returns a pointer to a buffer containing the error message. That pointer + ** may point to aErr[], or it may point to some static storage somewhere. + ** Otherwise, assume that the system provides the POSIX version of + ** strerror_r(), which always writes an error message into aErr[]. + ** + ** If the code incorrectly assumes that it is the POSIX version that is + ** available, the error message will often be an empty string. Not a + ** huge problem. Incorrectly concluding that the GNU version is available + ** could lead to a segfault though. + */ +#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) + zErr = +# endif + strerror_r(iErrno, aErr, sizeof(aErr)-1); + +#elif SQLITE_THREADSAFE + /* This is a threadsafe build, but strerror_r() is not available. */ + zErr = ""; +#else + /* Non-threadsafe build, use strerror(). */ + zErr = strerror(iErrno); +#endif + + if( zPath==0 ) zPath = ""; + sqlite3_log(errcode, + "os_unix.c:%d: (%d) %s(%s) - %s", + iLine, iErrno, zFunc, zPath, zErr + ); + + return errcode; +} + +/* +** Close a file descriptor. +** +** We assume that close() almost always works, since it is only in a +** very sick application or on a very sick platform that it might fail. +** If it does fail, simply leak the file descriptor, but do log the +** error. +** +** Note that it is not safe to retry close() after EINTR since the +** file descriptor might have already been reused by another thread. +** So we don't even try to recover from an EINTR. Just log the error +** and move on. +*/ +static void robust_close(unixFile *pFile, int h, int lineno){ + if( osClose(h) ){ + unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close", + pFile ? pFile->zPath : 0, lineno); + } +} + +/* +** Set the pFile->lastErrno. Do this in a subroutine as that provides +** a convenient place to set a breakpoint. +*/ +static void storeLastErrno(unixFile *pFile, int error){ + pFile->lastErrno = error; +} + +/* +** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. +*/ +static void closePendingFds(unixFile *pFile){ + unixInodeInfo *pInode = pFile->pInode; + UnixUnusedFd *p; + UnixUnusedFd *pNext; + for(p=pInode->pUnused; p; p=pNext){ + pNext = p->pNext; + robust_close(pFile, p->fd, __LINE__); + sqlite3_free(p); + } + pInode->pUnused = 0; +} + +/* +** Release a unixInodeInfo structure previously allocated by findInodeInfo(). +** +** The mutex entered using the unixEnterMutex() function must be held +** when this function is called. +*/ +static void releaseInodeInfo(unixFile *pFile){ + unixInodeInfo *pInode = pFile->pInode; + assert( unixMutexHeld() ); + if( ALWAYS(pInode) ){ + pInode->nRef--; + if( pInode->nRef==0 ){ + assert( pInode->pShmNode==0 ); + closePendingFds(pFile); + if( pInode->pPrev ){ + assert( pInode->pPrev->pNext==pInode ); + pInode->pPrev->pNext = pInode->pNext; + }else{ + assert( inodeList==pInode ); + inodeList = pInode->pNext; + } + if( pInode->pNext ){ + assert( pInode->pNext->pPrev==pInode ); + pInode->pNext->pPrev = pInode->pPrev; + } + sqlite3_free(pInode); + } + } +} + +/* +** Given a file descriptor, locate the unixInodeInfo object that +** describes that file descriptor. Create a new one if necessary. The +** return value might be uninitialized if an error occurs. +** +** The mutex entered using the unixEnterMutex() function must be held +** when this function is called. +** +** Return an appropriate error code. +*/ +static int findInodeInfo( + unixFile *pFile, /* Unix file with file desc used in the key */ + unixInodeInfo **ppInode /* Return the unixInodeInfo object here */ +){ + int rc; /* System call return code */ + int fd; /* The file descriptor for pFile */ + struct unixFileId fileId; /* Lookup key for the unixInodeInfo */ + struct stat statbuf; /* Low-level file information */ + unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */ + + assert( unixMutexHeld() ); + + /* Get low-level information about the file that we can used to + ** create a unique name for the file. + */ + fd = pFile->h; + rc = osFstat(fd, &statbuf); + if( rc!=0 ){ + storeLastErrno(pFile, errno); +#if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) + if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; +#endif + return SQLITE_IOERR; + } + +#ifdef __APPLE__ + /* On OS X on an msdos filesystem, the inode number is reported + ** incorrectly for zero-size files. See ticket #3260. To work + ** around this problem (we consider it a bug in OS X, not SQLite) + ** we always increase the file size to 1 by writing a single byte + ** prior to accessing the inode number. The one byte written is + ** an ASCII 'S' character which also happens to be the first byte + ** in the header of every SQLite database. In this way, if there + ** is a race condition such that another thread has already populated + ** the first page of the database, no damage is done. + */ + if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){ + do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); + if( rc!=1 ){ + storeLastErrno(pFile, errno); + return SQLITE_IOERR; + } + rc = osFstat(fd, &statbuf); + if( rc!=0 ){ + storeLastErrno(pFile, errno); + return SQLITE_IOERR; + } + } +#endif + + memset(&fileId, 0, sizeof(fileId)); + fileId.dev = statbuf.st_dev; +#if OS_VXWORKS + fileId.pId = pFile->pId; +#else + fileId.ino = (u64)statbuf.st_ino; +#endif + pInode = inodeList; + while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ + pInode = pInode->pNext; + } + if( pInode==0 ){ + pInode = sqlite3_malloc64( sizeof(*pInode) ); + if( pInode==0 ){ + return SQLITE_NOMEM_BKPT; + } + memset(pInode, 0, sizeof(*pInode)); + memcpy(&pInode->fileId, &fileId, sizeof(fileId)); + pInode->nRef = 1; + pInode->pNext = inodeList; + pInode->pPrev = 0; + if( inodeList ) inodeList->pPrev = pInode; + inodeList = pInode; + }else{ + pInode->nRef++; + } + *ppInode = pInode; + return SQLITE_OK; +} + +/* +** Return TRUE if pFile has been renamed or unlinked since it was first opened. +*/ +static int fileHasMoved(unixFile *pFile){ +#if OS_VXWORKS + return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId; +#else + struct stat buf; + return pFile->pInode!=0 && + (osStat(pFile->zPath, &buf)!=0 + || (u64)buf.st_ino!=pFile->pInode->fileId.ino); +#endif +} + + +/* +** Check a unixFile that is a database. Verify the following: +** +** (1) There is exactly one hard link on the file +** (2) The file is not a symbolic link +** (3) The file has not been renamed or unlinked +** +** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right. +*/ +static void verifyDbFile(unixFile *pFile){ + struct stat buf; + int rc; + + /* These verifications occurs for the main database only */ + if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return; + + rc = osFstat(pFile->h, &buf); + if( rc!=0 ){ + sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath); + return; + } + if( buf.st_nlink==0 ){ + sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath); + return; + } + if( buf.st_nlink>1 ){ + sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath); + return; + } + if( fileHasMoved(pFile) ){ + sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath); + return; + } +} + + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ +static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ + int rc = SQLITE_OK; + int reserved = 0; + unixFile *pFile = (unixFile*)id; + + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); + + assert( pFile ); + assert( pFile->eFileLock<=SHARED_LOCK ); + unixEnterMutex(); /* Because pFile->pInode is shared across threads */ + + /* Check if a thread in this process holds such a lock */ + if( pFile->pInode->eFileLock>SHARED_LOCK ){ + reserved = 1; + } + + /* Otherwise see if some other process holds it. + */ +#ifndef __DJGPP__ + if( !reserved && !pFile->pInode->bProcessLock ){ + struct flock lock; + lock.l_whence = SEEK_SET; + lock.l_start = RESERVED_BYTE; + lock.l_len = 1; + lock.l_type = F_WRLCK; + if( osFcntl(pFile->h, F_GETLK, &lock) ){ + rc = SQLITE_IOERR_CHECKRESERVEDLOCK; + storeLastErrno(pFile, errno); + } else if( lock.l_type!=F_UNLCK ){ + reserved = 1; + } + } +#endif + + unixLeaveMutex(); + OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); + + *pResOut = reserved; + return rc; +} + +/* +** Attempt to set a system-lock on the file pFile. The lock is +** described by pLock. +** +** If the pFile was opened read/write from unix-excl, then the only lock +** ever obtained is an exclusive lock, and it is obtained exactly once +** the first time any lock is attempted. All subsequent system locking +** operations become no-ops. Locking operations still happen internally, +** in order to coordinate access between separate database connections +** within this process, but all of that is handled in memory and the +** operating system does not participate. +** +** This function is a pass-through to fcntl(F_SETLK) if pFile is using +** any VFS other than "unix-excl" or if pFile is opened on "unix-excl" +** and is read-only. +** +** Zero is returned if the call completes successfully, or -1 if a call +** to fcntl() fails. In this case, errno is set appropriately (by fcntl()). +*/ +static int unixFileLock(unixFile *pFile, struct flock *pLock){ + int rc; + unixInodeInfo *pInode = pFile->pInode; + assert( unixMutexHeld() ); + assert( pInode!=0 ); + if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ + if( pInode->bProcessLock==0 ){ + struct flock lock; + assert( pInode->nLock==0 ); + lock.l_whence = SEEK_SET; + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; + lock.l_type = F_WRLCK; + rc = osFcntl(pFile->h, F_SETLK, &lock); + if( rc<0 ) return rc; + pInode->bProcessLock = 1; + pInode->nLock++; + }else{ + rc = 0; + } + }else{ + rc = osFcntl(pFile->h, F_SETLK, pLock); + } + return rc; +} + +/* +** Lock the file with the lock specified by parameter eFileLock - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ +static int unixLock(sqlite3_file *id, int eFileLock){ + /* The following describes the implementation of the various locks and + ** lock transitions in terms of the POSIX advisory shared and exclusive + ** lock primitives (called read-locks and write-locks below, to avoid + ** confusion with SQLite lock names). The algorithms are complicated + ** slightly in order to be compatible with Windows95 systems simultaneously + ** accessing the same database file, in case that is ever required. + ** + ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved + ** byte', each single bytes at well known offsets, and the 'shared byte + ** range', a range of 510 bytes at a well known offset. + ** + ** To obtain a SHARED lock, a read-lock is obtained on the 'pending + ** byte'. If this is successful, 'shared byte range' is read-locked + ** and the lock on the 'pending byte' released. (Legacy note: When + ** SQLite was first developed, Windows95 systems were still very common, + ** and Widnows95 lacks a shared-lock capability. So on Windows95, a + ** single randomly selected by from the 'shared byte range' is locked. + ** Windows95 is now pretty much extinct, but this work-around for the + ** lack of shared-locks on Windows95 lives on, for backwards + ** compatibility.) + ** + ** A process may only obtain a RESERVED lock after it has a SHARED lock. + ** A RESERVED lock is implemented by grabbing a write-lock on the + ** 'reserved byte'. + ** + ** A process may only obtain a PENDING lock after it has obtained a + ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock + ** on the 'pending byte'. This ensures that no new SHARED locks can be + ** obtained, but existing SHARED locks are allowed to persist. A process + ** does not have to obtain a RESERVED lock on the way to a PENDING lock. + ** This property is used by the algorithm for rolling back a journal file + ** after a crash. + ** + ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is + ** implemented by obtaining a write-lock on the entire 'shared byte + ** range'. Since all other locks require a read-lock on one of the bytes + ** within this range, this ensures that no other locks are held on the + ** database. + */ + int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; + unixInodeInfo *pInode; + struct flock lock; + int tErrno = 0; + + assert( pFile ); + OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, + azFileLock(eFileLock), azFileLock(pFile->eFileLock), + azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared, + osGetpid(0))); + + /* If there is already a lock of this type or more restrictive on the + ** unixFile, do nothing. Don't use the end_lock: exit path, as + ** unixEnterMutex() hasn't been called yet. + */ + if( pFile->eFileLock>=eFileLock ){ + OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, + azFileLock(eFileLock))); + return SQLITE_OK; + } + + /* Make sure the locking sequence is correct. + ** (1) We never move from unlocked to anything higher than shared lock. + ** (2) SQLite never explicitly requests a pendig lock. + ** (3) A shared lock is always held when a reserve lock is requested. + */ + assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); + assert( eFileLock!=PENDING_LOCK ); + assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); + + /* This mutex is needed because pFile->pInode is shared across threads + */ + unixEnterMutex(); + pInode = pFile->pInode; + + /* If some thread using this PID has a lock via a different unixFile* + ** handle that precludes the requested lock, return BUSY. + */ + if( (pFile->eFileLock!=pInode->eFileLock && + (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) + ){ + rc = SQLITE_BUSY; + goto end_lock; + } + + /* If a SHARED lock is requested, and some thread using this PID already + ** has a SHARED or RESERVED lock, then increment reference counts and + ** return SQLITE_OK. + */ + if( eFileLock==SHARED_LOCK && + (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ + assert( eFileLock==SHARED_LOCK ); + assert( pFile->eFileLock==0 ); + assert( pInode->nShared>0 ); + pFile->eFileLock = SHARED_LOCK; + pInode->nShared++; + pInode->nLock++; + goto end_lock; + } + + + /* A PENDING lock is needed before acquiring a SHARED lock and before + ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will + ** be released. + */ + lock.l_len = 1L; + lock.l_whence = SEEK_SET; + if( eFileLock==SHARED_LOCK + || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLocknShared==0 ); + assert( pInode->eFileLock==0 ); + assert( rc==SQLITE_OK ); + + /* Now get the read-lock */ + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; + if( unixFileLock(pFile, &lock) ){ + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + } + + /* Drop the temporary PENDING lock */ + lock.l_start = PENDING_BYTE; + lock.l_len = 1L; + lock.l_type = F_UNLCK; + if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){ + /* This could happen with a network mount */ + tErrno = errno; + rc = SQLITE_IOERR_UNLOCK; + } + + if( rc ){ + if( rc!=SQLITE_BUSY ){ + storeLastErrno(pFile, tErrno); + } + goto end_lock; + }else{ + pFile->eFileLock = SHARED_LOCK; + pInode->nLock++; + pInode->nShared = 1; + } + }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ + /* We are trying for an exclusive lock but another thread in this + ** same process is still holding a shared lock. */ + rc = SQLITE_BUSY; + }else{ + /* The request was for a RESERVED or EXCLUSIVE lock. It is + ** assumed that there is a SHARED or greater lock on the file + ** already. + */ + assert( 0!=pFile->eFileLock ); + lock.l_type = F_WRLCK; + + assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK ); + if( eFileLock==RESERVED_LOCK ){ + lock.l_start = RESERVED_BYTE; + lock.l_len = 1L; + }else{ + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; + } + + if( unixFileLock(pFile, &lock) ){ + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if( rc!=SQLITE_BUSY ){ + storeLastErrno(pFile, tErrno); + } + } + } + + +#ifdef SQLITE_DEBUG + /* Set up the transaction-counter change checking flags when + ** transitioning from a SHARED to a RESERVED lock. The change + ** from SHARED to RESERVED marks the beginning of a normal + ** write operation (not a hot journal rollback). + */ + if( rc==SQLITE_OK + && pFile->eFileLock<=SHARED_LOCK + && eFileLock==RESERVED_LOCK + ){ + pFile->transCntrChng = 0; + pFile->dbUpdate = 0; + pFile->inNormalWrite = 1; + } +#endif + + + if( rc==SQLITE_OK ){ + pFile->eFileLock = eFileLock; + pInode->eFileLock = eFileLock; + }else if( eFileLock==EXCLUSIVE_LOCK ){ + pFile->eFileLock = PENDING_LOCK; + pInode->eFileLock = PENDING_LOCK; + } + +end_lock: + unixLeaveMutex(); + OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), + rc==SQLITE_OK ? "ok" : "failed")); + return rc; +} + +/* +** Add the file descriptor used by file handle pFile to the corresponding +** pUnused list. +*/ +static void setPendingFd(unixFile *pFile){ + unixInodeInfo *pInode = pFile->pInode; + UnixUnusedFd *p = pFile->pUnused; + p->pNext = pInode->pUnused; + pInode->pUnused = p; + pFile->h = -1; + pFile->pUnused = 0; +} + +/* +** Lower the locking level on file descriptor pFile to eFileLock. eFileLock +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +** +** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED +** the byte range is divided into 2 parts and the first part is unlocked then +** set to a read lock, then the other part is simply unlocked. This works +** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to +** remove the write lock on a region when a read lock is set. +*/ +static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ + unixFile *pFile = (unixFile*)id; + unixInodeInfo *pInode; + struct flock lock; + int rc = SQLITE_OK; + + assert( pFile ); + OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, + pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, + osGetpid(0))); + + assert( eFileLock<=SHARED_LOCK ); + if( pFile->eFileLock<=eFileLock ){ + return SQLITE_OK; + } + unixEnterMutex(); + pInode = pFile->pInode; + assert( pInode->nShared!=0 ); + if( pFile->eFileLock>SHARED_LOCK ){ + assert( pInode->eFileLock==pFile->eFileLock ); + +#ifdef SQLITE_DEBUG + /* When reducing a lock such that other processes can start + ** reading the database file again, make sure that the + ** transaction counter was updated if any part of the database + ** file changed. If the transaction counter is not updated, + ** other connections to the same file might not realize that + ** the file has changed and hence might not know to flush their + ** cache. The use of a stale cache can lead to database corruption. + */ + pFile->inNormalWrite = 0; +#endif + + /* downgrading to a shared lock on NFS involves clearing the write lock + ** before establishing the readlock - to avoid a race condition we downgrade + ** the lock in 2 blocks, so that part of the range will be covered by a + ** write lock until the rest is covered by a read lock: + ** 1: [WWWWW] + ** 2: [....W] + ** 3: [RRRRW] + ** 4: [RRRR.] + */ + if( eFileLock==SHARED_LOCK ){ +#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE + (void)handleNFSUnlock; + assert( handleNFSUnlock==0 ); +#endif +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE + if( handleNFSUnlock ){ + int tErrno; /* Error code from system call errors */ + off_t divSize = SHARED_SIZE - 1; + + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = SHARED_FIRST; + lock.l_len = divSize; + if( unixFileLock(pFile, &lock)==(-1) ){ + tErrno = errno; + rc = SQLITE_IOERR_UNLOCK; + storeLastErrno(pFile, tErrno); + goto end_unlock; + } + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = SHARED_FIRST; + lock.l_len = divSize; + if( unixFileLock(pFile, &lock)==(-1) ){ + tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); + if( IS_LOCK_ERROR(rc) ){ + storeLastErrno(pFile, tErrno); + } + goto end_unlock; + } + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = SHARED_FIRST+divSize; + lock.l_len = SHARED_SIZE-divSize; + if( unixFileLock(pFile, &lock)==(-1) ){ + tErrno = errno; + rc = SQLITE_IOERR_UNLOCK; + storeLastErrno(pFile, tErrno); + goto end_unlock; + } + }else +#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ + { + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; + if( unixFileLock(pFile, &lock) ){ + /* In theory, the call to unixFileLock() cannot fail because another + ** process is holding an incompatible lock. If it does, this + ** indicates that the other process is not following the locking + ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning + ** SQLITE_BUSY would confuse the upper layer (in practice it causes + ** an assert to fail). */ + rc = SQLITE_IOERR_RDLOCK; + storeLastErrno(pFile, errno); + goto end_unlock; + } + } + } + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = PENDING_BYTE; + lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); + if( unixFileLock(pFile, &lock)==0 ){ + pInode->eFileLock = SHARED_LOCK; + }else{ + rc = SQLITE_IOERR_UNLOCK; + storeLastErrno(pFile, errno); + goto end_unlock; + } + } + if( eFileLock==NO_LOCK ){ + /* Decrement the shared lock counter. Release the lock using an + ** OS call only when all threads in this same process have released + ** the lock. + */ + pInode->nShared--; + if( pInode->nShared==0 ){ + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + if( unixFileLock(pFile, &lock)==0 ){ + pInode->eFileLock = NO_LOCK; + }else{ + rc = SQLITE_IOERR_UNLOCK; + storeLastErrno(pFile, errno); + pInode->eFileLock = NO_LOCK; + pFile->eFileLock = NO_LOCK; + } + } + + /* Decrement the count of locks against this same file. When the + ** count reaches zero, close any other file descriptors whose close + ** was deferred because of outstanding locks. + */ + pInode->nLock--; + assert( pInode->nLock>=0 ); + if( pInode->nLock==0 ){ + closePendingFds(pFile); + } + } + +end_unlock: + unixLeaveMutex(); + if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; + return rc; +} + +/* +** Lower the locking level on file descriptor pFile to eFileLock. eFileLock +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ +static int unixUnlock(sqlite3_file *id, int eFileLock){ +#if SQLITE_MAX_MMAP_SIZE>0 + assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 ); +#endif + return posixUnlock(id, eFileLock, 0); +} + +#if SQLITE_MAX_MMAP_SIZE>0 +static int unixMapfile(unixFile *pFd, i64 nByte); +static void unixUnmapfile(unixFile *pFd); +#endif + +/* +** This function performs the parts of the "close file" operation +** common to all locking schemes. It closes the directory and file +** handles, if they are valid, and sets all fields of the unixFile +** structure to 0. +** +** It is *not* necessary to hold the mutex when this routine is called, +** even on VxWorks. A mutex will be acquired on VxWorks by the +** vxworksReleaseFileId() routine. +*/ +static int closeUnixFile(sqlite3_file *id){ + unixFile *pFile = (unixFile*)id; +#if SQLITE_MAX_MMAP_SIZE>0 + unixUnmapfile(pFile); +#endif + if( pFile->h>=0 ){ + robust_close(pFile, pFile->h, __LINE__); + pFile->h = -1; + } +#if OS_VXWORKS + if( pFile->pId ){ + if( pFile->ctrlFlags & UNIXFILE_DELETE ){ + osUnlink(pFile->pId->zCanonicalName); + } + vxworksReleaseFileId(pFile->pId); + pFile->pId = 0; + } +#endif +#ifdef SQLITE_UNLINK_AFTER_CLOSE + if( pFile->ctrlFlags & UNIXFILE_DELETE ){ + osUnlink(pFile->zPath); + sqlite3_free(*(char**)&pFile->zPath); + pFile->zPath = 0; + } +#endif + OSTRACE(("CLOSE %-3d\n", pFile->h)); + OpenCounter(-1); + sqlite3_free(pFile->pUnused); + memset(pFile, 0, sizeof(unixFile)); + return SQLITE_OK; +} + +/* +** Close a file. +*/ +static int unixClose(sqlite3_file *id){ + int rc = SQLITE_OK; + unixFile *pFile = (unixFile *)id; + verifyDbFile(pFile); + unixUnlock(id, NO_LOCK); + unixEnterMutex(); + + /* unixFile.pInode is always valid here. Otherwise, a different close + ** routine (e.g. nolockClose()) would be called instead. + */ + assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); + if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pInode->pUnused list. It will be automatically closed + ** when the last lock is cleared. + */ + setPendingFd(pFile); + } + releaseInodeInfo(pFile); + rc = closeUnixFile(id); + unixLeaveMutex(); + return rc; +} + +/************** End of the posix advisory lock implementation ***************** +******************************************************************************/ + +/****************************************************************************** +****************************** No-op Locking ********************************** +** +** Of the various locking implementations available, this is by far the +** simplest: locking is ignored. No attempt is made to lock the database +** file for reading or writing. +** +** This locking mode is appropriate for use on read-only databases +** (ex: databases that are burned into CD-ROM, for example.) It can +** also be used if the application employs some external mechanism to +** prevent simultaneous access of the same database by two or more +** database connections. But there is a serious risk of database +** corruption if this locking mode is used in situations where multiple +** database connections are accessing the same database file at the same +** time and one or more of those connections are writing. +*/ + +static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){ + UNUSED_PARAMETER(NotUsed); + *pResOut = 0; + return SQLITE_OK; +} +static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + return SQLITE_OK; +} +static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + return SQLITE_OK; +} + +/* +** Close the file. +*/ +static int nolockClose(sqlite3_file *id) { + return closeUnixFile(id); +} + +/******************* End of the no-op lock implementation ********************* +******************************************************************************/ + +/****************************************************************************** +************************* Begin dot-file Locking ****************************** +** +** The dotfile locking implementation uses the existence of separate lock +** files (really a directory) to control access to the database. This works +** on just about every filesystem imaginable. But there are serious downsides: +** +** (1) There is zero concurrency. A single reader blocks all other +** connections from reading or writing the database. +** +** (2) An application crash or power loss can leave stale lock files +** sitting around that need to be cleared manually. +** +** Nevertheless, a dotlock is an appropriate locking mode for use if no +** other locking strategy is available. +** +** Dotfile locking works by creating a subdirectory in the same directory as +** the database and with the same name but with a ".lock" extension added. +** The existence of a lock directory implies an EXCLUSIVE lock. All other +** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE. +*/ + +/* +** The file suffix added to the data base filename in order to create the +** lock directory. +*/ +#define DOTLOCK_SUFFIX ".lock" + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +** +** In dotfile locking, either a lock exists or it does not. So in this +** variation of CheckReservedLock(), *pResOut is set to true if any lock +** is held on the file and false if the file is unlocked. +*/ +static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) { + int rc = SQLITE_OK; + int reserved = 0; + unixFile *pFile = (unixFile*)id; + + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); + + assert( pFile ); + reserved = osAccess((const char*)pFile->lockingContext, 0)==0; + OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved)); + *pResOut = reserved; + return rc; +} + +/* +** Lock the file with the lock specified by parameter eFileLock - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +** +** With dotfile locking, we really only support state (4): EXCLUSIVE. +** But we track the other locking levels internally. +*/ +static int dotlockLock(sqlite3_file *id, int eFileLock) { + unixFile *pFile = (unixFile*)id; + char *zLockFile = (char *)pFile->lockingContext; + int rc = SQLITE_OK; + + + /* If we have any lock, then the lock file already exists. All we have + ** to do is adjust our internal record of the lock level. + */ + if( pFile->eFileLock > NO_LOCK ){ + pFile->eFileLock = eFileLock; + /* Always update the timestamp on the old file */ +#ifdef HAVE_UTIME + utime(zLockFile, NULL); +#else + utimes(zLockFile, NULL); +#endif + return SQLITE_OK; + } + + /* grab an exclusive lock */ + rc = osMkdir(zLockFile, 0777); + if( rc<0 ){ + /* failed to open/create the lock directory */ + int tErrno = errno; + if( EEXIST == tErrno ){ + rc = SQLITE_BUSY; + } else { + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if( rc!=SQLITE_BUSY ){ + storeLastErrno(pFile, tErrno); + } + } + return rc; + } + + /* got it, set the type and return ok */ + pFile->eFileLock = eFileLock; + return rc; +} + +/* +** Lower the locking level on file descriptor pFile to eFileLock. eFileLock +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +** +** When the locking level reaches NO_LOCK, delete the lock file. +*/ +static int dotlockUnlock(sqlite3_file *id, int eFileLock) { + unixFile *pFile = (unixFile*)id; + char *zLockFile = (char *)pFile->lockingContext; + int rc; + + assert( pFile ); + OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, + pFile->eFileLock, osGetpid(0))); + assert( eFileLock<=SHARED_LOCK ); + + /* no-op if possible */ + if( pFile->eFileLock==eFileLock ){ + return SQLITE_OK; + } + + /* To downgrade to shared, simply update our internal notion of the + ** lock state. No need to mess with the file on disk. + */ + if( eFileLock==SHARED_LOCK ){ + pFile->eFileLock = SHARED_LOCK; + return SQLITE_OK; + } + + /* To fully unlock the database, delete the lock file */ + assert( eFileLock==NO_LOCK ); + rc = osRmdir(zLockFile); + if( rc<0 ){ + int tErrno = errno; + if( tErrno==ENOENT ){ + rc = SQLITE_OK; + }else{ + rc = SQLITE_IOERR_UNLOCK; + storeLastErrno(pFile, tErrno); + } + return rc; + } + pFile->eFileLock = NO_LOCK; + return SQLITE_OK; +} + +/* +** Close a file. Make sure the lock has been released before closing. +*/ +static int dotlockClose(sqlite3_file *id) { + unixFile *pFile = (unixFile*)id; + assert( id!=0 ); + dotlockUnlock(id, NO_LOCK); + sqlite3_free(pFile->lockingContext); + return closeUnixFile(id); +} +/****************** End of the dot-file lock implementation ******************* +******************************************************************************/ + +/****************************************************************************** +************************** Begin flock Locking ******************************** +** +** Use the flock() system call to do file locking. +** +** flock() locking is like dot-file locking in that the various +** fine-grain locking levels supported by SQLite are collapsed into +** a single exclusive lock. In other words, SHARED, RESERVED, and +** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite +** still works when you do this, but concurrency is reduced since +** only a single process can be reading the database at a time. +** +** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off +*/ +#if SQLITE_ENABLE_LOCKING_STYLE + +/* +** Retry flock() calls that fail with EINTR +*/ +#ifdef EINTR +static int robust_flock(int fd, int op){ + int rc; + do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR ); + return rc; +} +#else +# define robust_flock(a,b) flock(a,b) +#endif + + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ +static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ + int rc = SQLITE_OK; + int reserved = 0; + unixFile *pFile = (unixFile*)id; + + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); + + assert( pFile ); + + /* Check if a thread in this process holds such a lock */ + if( pFile->eFileLock>SHARED_LOCK ){ + reserved = 1; + } + + /* Otherwise see if some other process holds it. */ + if( !reserved ){ + /* attempt to get the lock */ + int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB); + if( !lrc ){ + /* got the lock, unlock it */ + lrc = robust_flock(pFile->h, LOCK_UN); + if ( lrc ) { + int tErrno = errno; + /* unlock failed with an error */ + lrc = SQLITE_IOERR_UNLOCK; + storeLastErrno(pFile, tErrno); + rc = lrc; + } + } else { + int tErrno = errno; + reserved = 1; + /* someone else might have it reserved */ + lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if( IS_LOCK_ERROR(lrc) ){ + storeLastErrno(pFile, tErrno); + rc = lrc; + } + } + } + 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 ){ + rc = SQLITE_OK; + reserved=1; + } +#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ + *pResOut = reserved; + return rc; +} + +/* +** Lock the file with the lock specified by parameter eFileLock - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** flock() only really support EXCLUSIVE locks. We track intermediate +** lock states in the sqlite3_file structure, but all locks SHARED or +** above are really EXCLUSIVE locks and exclude all other processes from +** access the file. +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ +static int flockLock(sqlite3_file *id, int eFileLock) { + int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; + + assert( pFile ); + + /* if we already have a lock, it is exclusive. + ** Just adjust level and punt on outta here. */ + if (pFile->eFileLock > NO_LOCK) { + pFile->eFileLock = eFileLock; + return SQLITE_OK; + } + + /* grab an exclusive lock */ + + if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) { + int tErrno = errno; + /* didn't get, must be busy */ + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + if( IS_LOCK_ERROR(rc) ){ + storeLastErrno(pFile, tErrno); + } + } else { + /* got it, set the type and return ok */ + pFile->eFileLock = 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 ){ + rc = SQLITE_BUSY; + } +#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ + return rc; +} + + +/* +** Lower the locking level on file descriptor pFile to eFileLock. eFileLock +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ +static int flockUnlock(sqlite3_file *id, int eFileLock) { + unixFile *pFile = (unixFile*)id; + + assert( pFile ); + OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, + pFile->eFileLock, osGetpid(0))); + assert( eFileLock<=SHARED_LOCK ); + + /* no-op if possible */ + if( pFile->eFileLock==eFileLock ){ + return SQLITE_OK; + } + + /* shared can just be set because we always have an exclusive */ + if (eFileLock==SHARED_LOCK) { + pFile->eFileLock = eFileLock; + return SQLITE_OK; + } + + /* no, really, unlock. */ + if( robust_flock(pFile->h, LOCK_UN) ){ +#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS + return SQLITE_OK; +#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ + return SQLITE_IOERR_UNLOCK; + }else{ + pFile->eFileLock = NO_LOCK; + return SQLITE_OK; + } +} + +/* +** Close a file. +*/ +static int flockClose(sqlite3_file *id) { + assert( id!=0 ); + flockUnlock(id, NO_LOCK); + return closeUnixFile(id); +} + +#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */ + +/******************* End of the flock lock implementation ********************* +******************************************************************************/ + +/****************************************************************************** +************************ Begin Named Semaphore Locking ************************ +** +** Named semaphore locking is only supported on VxWorks. +** +** Semaphore locking is like dot-lock and flock in that it really only +** supports EXCLUSIVE locking. Only a single process can read or write +** the database file at a time. This reduces potential concurrency, but +** makes the lock implementation much easier. +*/ +#if OS_VXWORKS + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ +static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) { + int rc = SQLITE_OK; + int reserved = 0; + unixFile *pFile = (unixFile*)id; + + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); + + assert( pFile ); + + /* Check if a thread in this process holds such a lock */ + if( pFile->eFileLock>SHARED_LOCK ){ + reserved = 1; + } + + /* Otherwise see if some other process holds it. */ + if( !reserved ){ + sem_t *pSem = pFile->pInode->pSem; + + if( sem_trywait(pSem)==-1 ){ + int tErrno = errno; + if( EAGAIN != tErrno ){ + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK); + storeLastErrno(pFile, tErrno); + } else { + /* someone else has the lock when we are in NO_LOCK */ + reserved = (pFile->eFileLock < SHARED_LOCK); + } + }else{ + /* we could have it if we want it */ + sem_post(pSem); + } + } + OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved)); + + *pResOut = reserved; + return rc; +} + +/* +** Lock the file with the lock specified by parameter eFileLock - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** Semaphore locks only really support EXCLUSIVE locks. We track intermediate +** lock states in the sqlite3_file structure, but all locks SHARED or +** above are really EXCLUSIVE locks and exclude all other processes from +** access the file. +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ +static int semXLock(sqlite3_file *id, int eFileLock) { + unixFile *pFile = (unixFile*)id; + sem_t *pSem = pFile->pInode->pSem; + int rc = SQLITE_OK; + + /* if we already have a lock, it is exclusive. + ** Just adjust level and punt on outta here. */ + if (pFile->eFileLock > NO_LOCK) { + pFile->eFileLock = eFileLock; + rc = SQLITE_OK; + goto sem_end_lock; + } + + /* lock semaphore now but bail out when already locked. */ + if( sem_trywait(pSem)==-1 ){ + rc = SQLITE_BUSY; + goto sem_end_lock; + } + + /* got it, set the type and return ok */ + pFile->eFileLock = eFileLock; + + sem_end_lock: + return rc; +} + +/* +** Lower the locking level on file descriptor pFile to eFileLock. eFileLock +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ +static int semXUnlock(sqlite3_file *id, int eFileLock) { + unixFile *pFile = (unixFile*)id; + sem_t *pSem = pFile->pInode->pSem; + + assert( pFile ); + assert( pSem ); + OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, + pFile->eFileLock, osGetpid(0))); + assert( eFileLock<=SHARED_LOCK ); + + /* no-op if possible */ + if( pFile->eFileLock==eFileLock ){ + return SQLITE_OK; + } + + /* shared can just be set because we always have an exclusive */ + if (eFileLock==SHARED_LOCK) { + pFile->eFileLock = eFileLock; + return SQLITE_OK; + } + + /* no, really unlock. */ + if ( sem_post(pSem)==-1 ) { + int rc, tErrno = errno; + rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); + if( IS_LOCK_ERROR(rc) ){ + storeLastErrno(pFile, tErrno); + } + return rc; + } + pFile->eFileLock = NO_LOCK; + return SQLITE_OK; +} + +/* + ** Close a file. + */ +static int semXClose(sqlite3_file *id) { + if( id ){ + unixFile *pFile = (unixFile*)id; + semXUnlock(id, NO_LOCK); + assert( pFile ); + unixEnterMutex(); + releaseInodeInfo(pFile); + unixLeaveMutex(); + closeUnixFile(id); + } + return SQLITE_OK; +} + +#endif /* OS_VXWORKS */ +/* +** Named semaphore locking is only available on VxWorks. +** +*************** End of the named semaphore lock implementation **************** +******************************************************************************/ + + +/****************************************************************************** +*************************** Begin AFP Locking ********************************* +** +** AFP is the Apple Filing Protocol. AFP is a network filesystem found +** on Apple Macintosh computers - both OS9 and OSX. +** +** Third-party implementations of AFP are available. But this code here +** only works on OSX. +*/ + +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE +/* +** The afpLockingContext structure contains all afp lock specific state +*/ +typedef struct afpLockingContext afpLockingContext; +struct afpLockingContext { + int reserved; + const char *dbPath; /* Name of the open file */ +}; + +struct ByteRangeLockPB2 +{ + unsigned long long offset; /* offset to first byte to lock */ + unsigned long long length; /* nbr of bytes to lock */ + unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */ + unsigned char unLockFlag; /* 1 = unlock, 0 = lock */ + unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */ + int fd; /* file desc to assoc this lock with */ +}; + +#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) + +/* +** This is a utility for setting or clearing a bit-range lock on an +** AFP filesystem. +** +** Return SQLITE_OK on success, SQLITE_BUSY on failure. +*/ +static int afpSetLock( + const char *path, /* Name of the file to be locked or unlocked */ + unixFile *pFile, /* Open file descriptor on path */ + unsigned long long offset, /* First byte to be locked */ + unsigned long long length, /* Number of bytes to lock */ + int setLockFlag /* True to set lock. False to clear lock */ +){ + struct ByteRangeLockPB2 pb; + int err; + + pb.unLockFlag = setLockFlag ? 0 : 1; + pb.startEndFlag = 0; + pb.offset = offset; + pb.length = length; + pb.fd = pFile->h; + + OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n", + (setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""), + offset, length)); + err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); + if ( err==-1 ) { + int rc; + int tErrno = errno; + OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n", + path, tErrno, strerror(tErrno))); +#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS + rc = SQLITE_BUSY; +#else + rc = sqliteErrorFromPosixError(tErrno, + setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK); +#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */ + if( IS_LOCK_ERROR(rc) ){ + storeLastErrno(pFile, tErrno); + } + return rc; + } else { + return SQLITE_OK; + } +} + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ +static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ + int rc = SQLITE_OK; + int reserved = 0; + unixFile *pFile = (unixFile*)id; + afpLockingContext *context; + + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); + + assert( pFile ); + context = (afpLockingContext *) pFile->lockingContext; + if( context->reserved ){ + *pResOut = 1; + return SQLITE_OK; + } + unixEnterMutex(); /* Because pFile->pInode is shared across threads */ + + /* Check if a thread in this process holds such a lock */ + if( pFile->pInode->eFileLock>SHARED_LOCK ){ + reserved = 1; + } + + /* Otherwise see if some other process holds it. + */ + if( !reserved ){ + /* lock the RESERVED byte */ + int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); + if( SQLITE_OK==lrc ){ + /* if we succeeded in taking the reserved lock, unlock it to restore + ** the original state */ + lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); + } else { + /* if we failed to get the lock then someone else must have it */ + reserved = 1; + } + if( IS_LOCK_ERROR(lrc) ){ + rc=lrc; + } + } + + unixLeaveMutex(); + OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved)); + + *pResOut = reserved; + return rc; +} + +/* +** Lock the file with the lock specified by parameter eFileLock - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ +static int afpLock(sqlite3_file *id, int eFileLock){ + int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; + unixInodeInfo *pInode = pFile->pInode; + afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; + + assert( pFile ); + OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, + azFileLock(eFileLock), azFileLock(pFile->eFileLock), + azFileLock(pInode->eFileLock), pInode->nShared , osGetpid(0))); + + /* If there is already a lock of this type or more restrictive on the + ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as + ** unixEnterMutex() hasn't been called yet. + */ + if( pFile->eFileLock>=eFileLock ){ + OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h, + azFileLock(eFileLock))); + return SQLITE_OK; + } + + /* Make sure the locking sequence is correct + ** (1) We never move from unlocked to anything higher than shared lock. + ** (2) SQLite never explicitly requests a pendig lock. + ** (3) A shared lock is always held when a reserve lock is requested. + */ + assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); + assert( eFileLock!=PENDING_LOCK ); + assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); + + /* This mutex is needed because pFile->pInode is shared across threads + */ + unixEnterMutex(); + pInode = pFile->pInode; + + /* If some thread using this PID has a lock via a different unixFile* + ** handle that precludes the requested lock, return BUSY. + */ + if( (pFile->eFileLock!=pInode->eFileLock && + (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) + ){ + rc = SQLITE_BUSY; + goto afp_end_lock; + } + + /* If a SHARED lock is requested, and some thread using this PID already + ** has a SHARED or RESERVED lock, then increment reference counts and + ** return SQLITE_OK. + */ + if( eFileLock==SHARED_LOCK && + (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ + assert( eFileLock==SHARED_LOCK ); + assert( pFile->eFileLock==0 ); + assert( pInode->nShared>0 ); + pFile->eFileLock = SHARED_LOCK; + pInode->nShared++; + pInode->nLock++; + goto afp_end_lock; + } + + /* A PENDING lock is needed before acquiring a SHARED lock and before + ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will + ** be released. + */ + if( eFileLock==SHARED_LOCK + || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLockdbPath, pFile, PENDING_BYTE, 1, 1); + if (failed) { + rc = failed; + goto afp_end_lock; + } + } + + /* If control gets to this point, then actually go ahead and make + ** operating system calls for the specified lock. + */ + if( eFileLock==SHARED_LOCK ){ + int lrc1, lrc2, lrc1Errno = 0; + long lk, mask; + + assert( pInode->nShared==0 ); + assert( pInode->eFileLock==0 ); + + mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff; + /* Now get the read-lock SHARED_LOCK */ + /* note that the quality of the randomness doesn't matter that much */ + lk = random(); + pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1); + lrc1 = afpSetLock(context->dbPath, pFile, + SHARED_FIRST+pInode->sharedByte, 1, 1); + if( IS_LOCK_ERROR(lrc1) ){ + lrc1Errno = pFile->lastErrno; + } + /* Drop the temporary PENDING lock */ + lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); + + if( IS_LOCK_ERROR(lrc1) ) { + storeLastErrno(pFile, lrc1Errno); + rc = lrc1; + goto afp_end_lock; + } else if( IS_LOCK_ERROR(lrc2) ){ + rc = lrc2; + goto afp_end_lock; + } else if( lrc1 != SQLITE_OK ) { + rc = lrc1; + } else { + pFile->eFileLock = SHARED_LOCK; + pInode->nLock++; + pInode->nShared = 1; + } + }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ + /* We are trying for an exclusive lock but another thread in this + ** same process is still holding a shared lock. */ + rc = SQLITE_BUSY; + }else{ + /* The request was for a RESERVED or EXCLUSIVE lock. It is + ** assumed that there is a SHARED or greater lock on the file + ** already. + */ + int failed = 0; + assert( 0!=pFile->eFileLock ); + if (eFileLock >= RESERVED_LOCK && pFile->eFileLock < RESERVED_LOCK) { + /* Acquire a RESERVED lock */ + failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); + if( !failed ){ + context->reserved = 1; + } + } + if (!failed && eFileLock == EXCLUSIVE_LOCK) { + /* Acquire an EXCLUSIVE lock */ + + /* Remove the shared lock before trying the range. we'll need to + ** reestablish the shared lock if we can't get the afpUnlock + */ + if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST + + pInode->sharedByte, 1, 0)) ){ + int failed2 = SQLITE_OK; + /* now attemmpt to get the exclusive lock range */ + failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST, + SHARED_SIZE, 1); + if( failed && (failed2 = afpSetLock(context->dbPath, pFile, + SHARED_FIRST + pInode->sharedByte, 1, 1)) ){ + /* Can't reestablish the shared lock. Sqlite can't deal, this is + ** a critical I/O error + */ + rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 : + SQLITE_IOERR_LOCK; + goto afp_end_lock; + } + }else{ + rc = failed; + } + } + if( failed ){ + rc = failed; + } + } + + if( rc==SQLITE_OK ){ + pFile->eFileLock = eFileLock; + pInode->eFileLock = eFileLock; + }else if( eFileLock==EXCLUSIVE_LOCK ){ + pFile->eFileLock = PENDING_LOCK; + pInode->eFileLock = PENDING_LOCK; + } + +afp_end_lock: + unixLeaveMutex(); + OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), + rc==SQLITE_OK ? "ok" : "failed")); + return rc; +} + +/* +** Lower the locking level on file descriptor pFile to eFileLock. eFileLock +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ +static int afpUnlock(sqlite3_file *id, int eFileLock) { + int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; + unixInodeInfo *pInode; + afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; + int skipShared = 0; +#ifdef SQLITE_TEST + int h = pFile->h; +#endif + + assert( pFile ); + OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, + pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, + osGetpid(0))); + + assert( eFileLock<=SHARED_LOCK ); + if( pFile->eFileLock<=eFileLock ){ + return SQLITE_OK; + } + unixEnterMutex(); + pInode = pFile->pInode; + assert( pInode->nShared!=0 ); + if( pFile->eFileLock>SHARED_LOCK ){ + assert( pInode->eFileLock==pFile->eFileLock ); + SimulateIOErrorBenign(1); + SimulateIOError( h=(-1) ) + SimulateIOErrorBenign(0); + +#ifdef SQLITE_DEBUG + /* When reducing a lock such that other processes can start + ** reading the database file again, make sure that the + ** transaction counter was updated if any part of the database + ** file changed. If the transaction counter is not updated, + ** other connections to the same file might not realize that + ** the file has changed and hence might not know to flush their + ** cache. The use of a stale cache can lead to database corruption. + */ + assert( pFile->inNormalWrite==0 + || pFile->dbUpdate==0 + || pFile->transCntrChng==1 ); + pFile->inNormalWrite = 0; +#endif + + if( pFile->eFileLock==EXCLUSIVE_LOCK ){ + rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0); + if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){ + /* only re-establish the shared lock if necessary */ + int sharedLockByte = SHARED_FIRST+pInode->sharedByte; + rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1); + } else { + skipShared = 1; + } + } + if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){ + rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); + } + if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){ + rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); + if( !rc ){ + context->reserved = 0; + } + } + if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){ + pInode->eFileLock = SHARED_LOCK; + } + } + if( rc==SQLITE_OK && eFileLock==NO_LOCK ){ + + /* Decrement the shared lock counter. Release the lock using an + ** OS call only when all threads in this same process have released + ** the lock. + */ + unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte; + pInode->nShared--; + if( pInode->nShared==0 ){ + SimulateIOErrorBenign(1); + SimulateIOError( h=(-1) ) + SimulateIOErrorBenign(0); + if( !skipShared ){ + rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0); + } + if( !rc ){ + pInode->eFileLock = NO_LOCK; + pFile->eFileLock = NO_LOCK; + } + } + if( rc==SQLITE_OK ){ + pInode->nLock--; + assert( pInode->nLock>=0 ); + if( pInode->nLock==0 ){ + closePendingFds(pFile); + } + } + } + + unixLeaveMutex(); + if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; + return rc; +} + +/* +** Close a file & cleanup AFP specific locking context +*/ +static int afpClose(sqlite3_file *id) { + int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; + assert( id!=0 ); + afpUnlock(id, NO_LOCK); + unixEnterMutex(); + if( pFile->pInode && pFile->pInode->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pInode->aPending. It will be automatically closed when + ** the last lock is cleared. + */ + setPendingFd(pFile); + } + releaseInodeInfo(pFile); + sqlite3_free(pFile->lockingContext); + rc = closeUnixFile(id); + unixLeaveMutex(); + return rc; +} + +#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ +/* +** The code above is the AFP lock implementation. The code is specific +** to MacOSX and does not work on other unix platforms. No alternative +** is available. If you don't compile for a mac, then the "unix-afp" +** VFS is not available. +** +********************* End of the AFP lock implementation ********************** +******************************************************************************/ + +/****************************************************************************** +*************************** Begin NFS Locking ********************************/ + +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE +/* + ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock + ** must be either NO_LOCK or SHARED_LOCK. + ** + ** If the locking level of the file descriptor is already at or below + ** the requested locking level, this routine is a no-op. + */ +static int nfsUnlock(sqlite3_file *id, int eFileLock){ + return posixUnlock(id, eFileLock, 1); +} + +#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ +/* +** The code above is the NFS lock implementation. The code is specific +** to MacOSX and does not work on other unix platforms. No alternative +** is available. +** +********************* End of the NFS lock implementation ********************** +******************************************************************************/ + +/****************************************************************************** +**************** Non-locking sqlite3_file methods ***************************** +** +** The next division contains implementations for all methods of the +** sqlite3_file object other than the locking methods. The locking +** methods were defined in divisions above (one locking method per +** division). Those methods that are common to all locking modes +** are gather together into this division. +*/ + +/* +** Seek to the offset passed as the second argument, then read cnt +** bytes into pBuf. Return the number of bytes actually read. +** +** NB: If you define USE_PREAD or USE_PREAD64, then it might also +** be necessary to define _XOPEN_SOURCE to be 500. This varies from +** one system to another. Since SQLite does not define USE_PREAD +** in any form by default, we will not attempt to define _XOPEN_SOURCE. +** See tickets #2741 and #2681. +** +** To avoid stomping the errno value on a failed read the lastErrno value +** is set before returning. +*/ +static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ + int got; + int prior = 0; +#if (!defined(USE_PREAD) && !defined(USE_PREAD64)) + i64 newOffset; +#endif + TIMER_START; + assert( cnt==(cnt&0x1ffff) ); + assert( id->h>2 ); + do{ +#if defined(USE_PREAD) + got = osPread(id->h, pBuf, cnt, offset); + SimulateIOError( got = -1 ); +#elif defined(USE_PREAD64) + got = osPread64(id->h, pBuf, cnt, offset); + SimulateIOError( got = -1 ); +#else + newOffset = lseek(id->h, offset, SEEK_SET); + SimulateIOError( newOffset = -1 ); + if( newOffset<0 ){ + storeLastErrno((unixFile*)id, errno); + return -1; + } + got = osRead(id->h, pBuf, cnt); +#endif + if( got==cnt ) break; + if( got<0 ){ + if( errno==EINTR ){ got = 1; continue; } + prior = 0; + storeLastErrno((unixFile*)id, errno); + break; + }else if( got>0 ){ + cnt -= got; + offset += got; + prior += got; + pBuf = (void*)(got + (char*)pBuf); + } + }while( got>0 ); + TIMER_END; + OSTRACE(("READ %-3d %5d %7lld %llu\n", + id->h, got+prior, offset-prior, TIMER_ELAPSED)); + return got+prior; +} + +/* +** Read data from a file into a buffer. Return SQLITE_OK if all +** bytes were read successfully and SQLITE_IOERR if anything goes +** wrong. +*/ +static int unixRead( + sqlite3_file *id, + void *pBuf, + int amt, + sqlite3_int64 offset +){ + unixFile *pFile = (unixFile *)id; + int got; + assert( id ); + assert( offset>=0 ); + assert( amt>0 ); + + /* 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 + || offset>=PENDING_BYTE+512 + || offset+amt<=PENDING_BYTE + ); +#endif + +#if SQLITE_MAX_MMAP_SIZE>0 + /* Deal with as much of this read request as possible by transfering + ** data from the memory mapping using memcpy(). */ + if( offsetmmapSize ){ + if( offset+amt <= pFile->mmapSize ){ + memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); + return SQLITE_OK; + }else{ + int nCopy = pFile->mmapSize - offset; + memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); + pBuf = &((u8 *)pBuf)[nCopy]; + amt -= nCopy; + offset += nCopy; + } + } +#endif + + got = seekAndRead(pFile, offset, pBuf, amt); + if( got==amt ){ + return SQLITE_OK; + }else if( got<0 ){ + /* lastErrno set by seekAndRead */ + return SQLITE_IOERR_READ; + }else{ + storeLastErrno(pFile, 0); /* not a system error */ + /* Unread parts of the buffer must be zero-filled */ + memset(&((char*)pBuf)[got], 0, amt-got); + return SQLITE_IOERR_SHORT_READ; + } +} + +/* +** Attempt to seek the file-descriptor passed as the first argument to +** absolute offset iOff, then attempt to write nBuf bytes of data from +** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise, +** return the actual number of bytes written (which may be less than +** nBuf). +*/ +static int seekAndWriteFd( + int fd, /* File descriptor to write to */ + i64 iOff, /* File offset to begin writing at */ + const void *pBuf, /* Copy data from this buffer to the file */ + int nBuf, /* Size of buffer pBuf in bytes */ + int *piErrno /* OUT: Error number if error occurs */ +){ + int rc = 0; /* Value returned by system call */ + + assert( nBuf==(nBuf&0x1ffff) ); + assert( fd>2 ); + assert( piErrno!=0 ); + nBuf &= 0x1ffff; + TIMER_START; + +#if defined(USE_PREAD) + do{ rc = (int)osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); +#elif defined(USE_PREAD64) + do{ rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); +#else + do{ + i64 iSeek = lseek(fd, iOff, SEEK_SET); + SimulateIOError( iSeek = -1 ); + if( iSeek<0 ){ + rc = -1; + break; + } + rc = osWrite(fd, pBuf, nBuf); + }while( rc<0 && errno==EINTR ); +#endif + + TIMER_END; + OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED)); + + if( rc<0 ) *piErrno = errno; + return rc; +} + + +/* +** Seek to the offset in id->offset then read cnt bytes into pBuf. +** Return the number of bytes actually read. Update the offset. +** +** To avoid stomping the errno value on a failed write the lastErrno value +** is set before returning. +*/ +static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ + return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno); +} + + +/* +** Write data from a buffer into a file. Return SQLITE_OK on success +** or some other error code on failure. +*/ +static int unixWrite( + sqlite3_file *id, + const void *pBuf, + int amt, + sqlite3_int64 offset +){ + unixFile *pFile = (unixFile*)id; + int wrote = 0; + assert( id ); + assert( amt>0 ); + + /* If this is a database file (not a journal, master-journal or temp + ** file), the bytes in the locking range should never be read or written. */ +#if 0 + assert( pFile->pUnused==0 + || offset>=PENDING_BYTE+512 + || offset+amt<=PENDING_BYTE + ); +#endif + +#ifdef SQLITE_DEBUG + /* If we are doing a normal write to a database file (as opposed to + ** doing a hot-journal rollback or a write to some file other than a + ** normal database file) then record the fact that the database + ** has changed. If the transaction counter is modified, record that + ** fact too. + */ + if( pFile->inNormalWrite ){ + pFile->dbUpdate = 1; /* The database has been modified */ + if( offset<=24 && offset+amt>=27 ){ + int rc; + char oldCntr[4]; + SimulateIOErrorBenign(1); + rc = seekAndRead(pFile, 24, oldCntr, 4); + SimulateIOErrorBenign(0); + if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ + pFile->transCntrChng = 1; /* The transaction counter has changed */ + } + } + } +#endif + +#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 + /* Deal with as much of this write request as possible by transfering + ** data from the memory mapping using memcpy(). */ + if( offsetmmapSize ){ + if( offset+amt <= pFile->mmapSize ){ + memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); + return SQLITE_OK; + }else{ + int nCopy = pFile->mmapSize - offset; + memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); + pBuf = &((u8 *)pBuf)[nCopy]; + amt -= nCopy; + offset += nCopy; + } + } +#endif + + while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))0 ){ + amt -= wrote; + offset += wrote; + pBuf = &((char*)pBuf)[wrote]; + } + SimulateIOError(( wrote=(-1), amt=1 )); + SimulateDiskfullError(( wrote=0, amt=1 )); + + if( amt>wrote ){ + if( wrote<0 && pFile->lastErrno!=ENOSPC ){ + /* lastErrno set by seekAndWrite */ + return SQLITE_IOERR_WRITE; + }else{ + storeLastErrno(pFile, 0); /* not a system error */ + return SQLITE_FULL; + } + } + + return SQLITE_OK; +} + +#ifdef SQLITE_TEST +/* +** Count the number of fullsyncs and normal syncs. This is used to test +** that syncs and fullsyncs are occurring at the right times. +*/ +SQLITE_API int sqlite3_sync_count = 0; +SQLITE_API int sqlite3_fullsync_count = 0; +#endif + +/* +** We do not trust systems to provide a working fdatasync(). Some do. +** Others do no. To be safe, we will stick with the (slightly slower) +** fsync(). If you know that your system does support fdatasync() correctly, +** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC +*/ +#if !defined(fdatasync) && !HAVE_FDATASYNC +# define fdatasync fsync +#endif + +/* +** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not +** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently +** only available on Mac OS X. But that could change. +*/ +#ifdef F_FULLFSYNC +# define HAVE_FULLFSYNC 1 +#else +# define HAVE_FULLFSYNC 0 +#endif + + +/* +** The fsync() system call does not work as advertised on many +** unix systems. The following procedure is an attempt to make +** it work better. +** +** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful +** for testing when we want to run through the test suite quickly. +** You are strongly advised *not* to deploy with SQLITE_NO_SYNC +** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash +** or power failure will likely corrupt the database file. +** +** SQLite sets the dataOnly flag if the size of the file is unchanged. +** The idea behind dataOnly is that it should only write the file content +** to disk, not the inode. We only set dataOnly if the file size is +** unchanged since the file size is part of the inode. However, +** Ted Ts'o tells us that fdatasync() will also write the inode if the +** file size has changed. The only real difference between fdatasync() +** and fsync(), Ted tells us, is that fdatasync() will not flush the +** inode if the mtime or owner or other inode attributes have changed. +** We only care about the file size, not the other file attributes, so +** as far as SQLite is concerned, an fdatasync() is always adequate. +** So, we always use fdatasync() if it is available, regardless of +** the value of the dataOnly flag. +*/ +static int full_fsync(int fd, int fullSync, int dataOnly){ + int rc; + + /* The following "ifdef/elif/else/" block has the same structure as + ** the one below. It is replicated here solely to avoid cluttering + ** up the real code with the UNUSED_PARAMETER() macros. + */ +#ifdef SQLITE_NO_SYNC + UNUSED_PARAMETER(fd); + UNUSED_PARAMETER(fullSync); + UNUSED_PARAMETER(dataOnly); +#elif HAVE_FULLFSYNC + UNUSED_PARAMETER(dataOnly); +#else + UNUSED_PARAMETER(fullSync); + UNUSED_PARAMETER(dataOnly); +#endif + + /* Record the number of times that we do a normal fsync() and + ** FULLSYNC. This is used during testing to verify that this procedure + ** gets called with the correct arguments. + */ +#ifdef SQLITE_TEST + if( fullSync ) sqlite3_fullsync_count++; + sqlite3_sync_count++; +#endif + + /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a + ** no-op. But go ahead and call fstat() to validate the file + ** descriptor as we need a method to provoke a failure during + ** coverate testing. + */ +#ifdef SQLITE_NO_SYNC + { + struct stat buf; + rc = osFstat(fd, &buf); + } +#elif HAVE_FULLFSYNC + if( fullSync ){ + rc = osFcntl(fd, F_FULLFSYNC, 0); + }else{ + rc = 1; + } + /* If the FULLFSYNC failed, fall back to attempting an fsync(). + ** It shouldn't be possible for fullfsync to fail on the local + ** file system (on OSX), so failure indicates that FULLFSYNC + ** isn't supported for this file system. So, attempt an fsync + ** and (for now) ignore the overhead of a superfluous fcntl call. + ** It'd be better to detect fullfsync support once and avoid + ** the fcntl call every time sync is called. + */ + if( rc ) rc = fsync(fd); + +#elif defined(__APPLE__) + /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly + ** so currently we default to the macro that redefines fdatasync to fsync + */ + rc = fsync(fd); +#else + rc = fdatasync(fd); +#if OS_VXWORKS + if( rc==-1 && errno==ENOTSUP ){ + rc = fsync(fd); + } +#endif /* OS_VXWORKS */ +#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */ + + if( OS_VXWORKS && rc!= -1 ){ + rc = 0; + } + return rc; +} + +/* +** Open a file descriptor to the directory containing file zFilename. +** If successful, *pFd is set to the opened file descriptor and +** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM +** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined +** value. +** +** The directory file descriptor is used for only one thing - to +** fsync() a directory to make sure file creation and deletion events +** are flushed to disk. Such fsyncs are not needed on newer +** journaling filesystems, but are required on older filesystems. +** +** This routine can be overridden using the xSetSysCall interface. +** The ability to override this routine was added in support of the +** chromium sandbox. Opening a directory is a security risk (we are +** told) so making it overrideable allows the chromium sandbox to +** replace this routine with a harmless no-op. To make this routine +** a no-op, replace it with a stub that returns SQLITE_OK but leaves +** *pFd set to a negative number. +** +** If SQLITE_OK is returned, the caller is responsible for closing +** the file descriptor *pFd using close(). +*/ +static int openDirectory(const char *zFilename, int *pFd){ + int ii; + int fd = -1; + char zDirname[MAX_PATHNAME+1]; + + sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); + for(ii=(int)strlen(zDirname); ii>0 && zDirname[ii]!='/'; ii--); + if( ii>0 ){ + zDirname[ii] = '\0'; + }else{ + if( zDirname[0]!='/' ) zDirname[0] = '.'; + zDirname[1] = 0; + } + fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); + if( fd>=0 ){ + OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); + } + *pFd = fd; + if( fd>=0 ) return SQLITE_OK; + return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname); +} + +/* +** Make sure all writes to a particular file are committed to disk. +** +** If dataOnly==0 then both the file itself and its metadata (file +** size, access time, etc) are synced. If dataOnly!=0 then only the +** file data is synced. +** +** Under Unix, also make sure that the directory entry for the file +** has been created by fsync-ing the directory that contains the file. +** If we do not do this and we encounter a power failure, the directory +** entry for the journal might not exist after we reboot. The next +** SQLite to access the file will not know that the journal exists (because +** the directory entry for the journal was never created) and the transaction +** will not roll back - possibly leading to database corruption. +*/ +static int unixSync(sqlite3_file *id, int flags){ + int rc; + unixFile *pFile = (unixFile*)id; + + int isDataOnly = (flags&SQLITE_SYNC_DATAONLY); + int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL; + + /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ + assert((flags&0x0F)==SQLITE_SYNC_NORMAL + || (flags&0x0F)==SQLITE_SYNC_FULL + ); + + /* Unix cannot, but some systems may return SQLITE_FULL from here. This + ** line is to test that doing so does not cause any problems. + */ + SimulateDiskfullError( return SQLITE_FULL ); + + assert( pFile ); + OSTRACE(("SYNC %-3d\n", pFile->h)); + rc = full_fsync(pFile->h, isFullsync, isDataOnly); + SimulateIOError( rc=1 ); + if( rc ){ + storeLastErrno(pFile, errno); + return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); + } + + /* Also fsync the directory containing the file if the DIRSYNC flag + ** is set. This is a one-time occurrence. Many systems (examples: AIX) + ** are unable to fsync a directory, so ignore errors on the fsync. + */ + if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ + int dirfd; + OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, + HAVE_FULLFSYNC, isFullsync)); + rc = osOpenDirectory(pFile->zPath, &dirfd); + if( rc==SQLITE_OK ){ + full_fsync(dirfd, 0, 0); + robust_close(pFile, dirfd, __LINE__); + }else{ + assert( rc==SQLITE_CANTOPEN ); + rc = SQLITE_OK; + } + pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; + } + return rc; +} + +/* +** Truncate an open file to a specified size +*/ +static int unixTruncate(sqlite3_file *id, i64 nByte){ + unixFile *pFile = (unixFile *)id; + int rc; + assert( pFile ); + SimulateIOError( return SQLITE_IOERR_TRUNCATE ); + + /* If the user has configured a chunk-size for this file, truncate the + ** file so that it consists of an integer number of chunks (i.e. the + ** actual file size after the operation may be larger than the requested + ** size). + */ + if( pFile->szChunk>0 ){ + nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; + } + + rc = robust_ftruncate(pFile->h, nByte); + if( rc ){ + storeLastErrno(pFile, errno); + return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); + }else{ +#ifdef SQLITE_DEBUG + /* If we are doing a normal write to a database file (as opposed to + ** doing a hot-journal rollback or a write to some file other than a + ** normal database file) and we truncate the file to zero length, + ** that effectively updates the change counter. This might happen + ** when restoring a database using the backup API from a zero-length + ** source. + */ + if( pFile->inNormalWrite && nByte==0 ){ + pFile->transCntrChng = 1; + } +#endif + +#if SQLITE_MAX_MMAP_SIZE>0 + /* If the file was just truncated to a size smaller than the currently + ** mapped region, reduce the effective mapping size as well. SQLite will + ** use read() and write() to access data beyond this point from now on. + */ + if( nBytemmapSize ){ + pFile->mmapSize = nByte; + } +#endif + + return SQLITE_OK; + } +} + +/* +** Determine the current size of a file in bytes +*/ +static int unixFileSize(sqlite3_file *id, i64 *pSize){ + int rc; + struct stat buf; + assert( id ); + rc = osFstat(((unixFile*)id)->h, &buf); + SimulateIOError( rc=1 ); + if( rc!=0 ){ + storeLastErrno((unixFile*)id, errno); + return SQLITE_IOERR_FSTAT; + } + *pSize = buf.st_size; + + /* When opening a zero-size database, the findInodeInfo() procedure + ** writes a single byte into that file in order to work around a bug + ** in the OS-X msdos filesystem. In order to avoid problems with upper + ** layers, we need to report this file size as zero even though it is + ** really 1. Ticket #3260. + */ + if( *pSize==1 ) *pSize = 0; + + + return SQLITE_OK; +} + +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) +/* +** Handler for proxy-locking file-control verbs. Defined below in the +** proxying locking division. +*/ +static int proxyFileControl(sqlite3_file*,int,void*); +#endif + +/* +** This function is called to handle the SQLITE_FCNTL_SIZE_HINT +** file-control operation. Enlarge the database to nBytes in size +** (rounded up to the next chunk-size). If the database is already +** nBytes or larger, this routine is a no-op. +*/ +static int fcntlSizeHint(unixFile *pFile, i64 nByte){ + if( pFile->szChunk>0 ){ + i64 nSize; /* Required file size */ + struct stat buf; /* Used to hold return values of fstat() */ + + if( osFstat(pFile->h, &buf) ){ + return SQLITE_IOERR_FSTAT; + } + + nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk; + if( nSize>(i64)buf.st_size ){ + +#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE + /* The code below is handling the return value of osFallocate() + ** correctly. posix_fallocate() is defined to "returns zero on success, + ** or an error number on failure". See the manpage for details. */ + int err; + do{ + err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); + }while( err==EINTR ); + if( err ) return SQLITE_IOERR_WRITE; +#else + /* If the OS does not have posix_fallocate(), fake it. Write a + ** single byte to the last byte in each block that falls entirely + ** within the extended region. Then, if required, a single byte + ** at offset (nSize-1), to set the size of the file correctly. + ** This is a similar technique to that used by glibc on systems + ** that do not have a real fallocate() call. + */ + int nBlk = buf.st_blksize; /* File-system block size */ + int nWrite = 0; /* Number of bytes written by seekAndWrite */ + i64 iWrite; /* Next offset to write to */ + + iWrite = (buf.st_size/nBlk)*nBlk + nBlk - 1; + assert( iWrite>=buf.st_size ); + assert( ((iWrite+1)%nBlk)==0 ); + for(/*no-op*/; iWrite=nSize ) iWrite = nSize - 1; + nWrite = seekAndWrite(pFile, iWrite, "", 1); + if( nWrite!=1 ) return SQLITE_IOERR_WRITE; + } +#endif + } + } + +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){ + int rc; + if( pFile->szChunk<=0 ){ + if( robust_ftruncate(pFile->h, nByte) ){ + storeLastErrno(pFile, errno); + return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); + } + } + + rc = unixMapfile(pFile, nByte); + return rc; + } +#endif + + return SQLITE_OK; +} + +/* +** If *pArg is initially negative then this is a query. Set *pArg to +** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. +** +** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. +*/ +static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ + if( *pArg<0 ){ + *pArg = (pFile->ctrlFlags & mask)!=0; + }else if( (*pArg)==0 ){ + pFile->ctrlFlags &= ~mask; + }else{ + pFile->ctrlFlags |= mask; + } +} + +/* Forward declaration */ +static int unixGetTempname(int nBuf, char *zBuf); + +/* +** Information and control of an open file handle. +*/ +static int unixFileControl(sqlite3_file *id, int op, void *pArg){ + unixFile *pFile = (unixFile*)id; + switch( op ){ + case SQLITE_FCNTL_LOCKSTATE: { + *(int*)pArg = pFile->eFileLock; + return SQLITE_OK; + } + case SQLITE_FCNTL_LAST_ERRNO: { + *(int*)pArg = pFile->lastErrno; + return SQLITE_OK; + } + case SQLITE_FCNTL_CHUNK_SIZE: { + pFile->szChunk = *(int *)pArg; + return SQLITE_OK; + } + case SQLITE_FCNTL_SIZE_HINT: { + int rc; + SimulateIOErrorBenign(1); + rc = fcntlSizeHint(pFile, *(i64 *)pArg); + SimulateIOErrorBenign(0); + return rc; + } + case SQLITE_FCNTL_PERSIST_WAL: { + unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg); + return SQLITE_OK; + } + case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { + unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg); + return SQLITE_OK; + } + case SQLITE_FCNTL_VFSNAME: { + *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName); + return SQLITE_OK; + } + case SQLITE_FCNTL_TEMPFILENAME: { + char *zTFile = sqlite3_malloc64( pFile->pVfs->mxPathname ); + if( zTFile ){ + unixGetTempname(pFile->pVfs->mxPathname, zTFile); + *(char**)pArg = zTFile; + } + return SQLITE_OK; + } + case SQLITE_FCNTL_HAS_MOVED: { + *(int*)pArg = fileHasMoved(pFile); + return SQLITE_OK; + } +#if SQLITE_MAX_MMAP_SIZE>0 + case SQLITE_FCNTL_MMAP_SIZE: { + i64 newLimit = *(i64*)pArg; + int rc = SQLITE_OK; + if( newLimit>sqlite3GlobalConfig.mxMmap ){ + newLimit = sqlite3GlobalConfig.mxMmap; + } + *(i64*)pArg = pFile->mmapSizeMax; + if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ + pFile->mmapSizeMax = newLimit; + if( pFile->mmapSize>0 ){ + unixUnmapfile(pFile); + rc = unixMapfile(pFile, -1); + } + } + return rc; + } +#endif +#ifdef SQLITE_DEBUG + /* The pager calls this method to signal that it has done + ** a rollback and that the database is therefore unchanged and + ** it hence it is OK for the transaction change counter to be + ** unchanged. + */ + case SQLITE_FCNTL_DB_UNCHANGED: { + ((unixFile*)id)->dbUpdate = 0; + return SQLITE_OK; + } +#endif +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) + case SQLITE_FCNTL_SET_LOCKPROXYFILE: + case SQLITE_FCNTL_GET_LOCKPROXYFILE: { + return proxyFileControl(id,op,pArg); + } +#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ + } + return SQLITE_NOTFOUND; +} + +/* +** 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. +*/ +#ifndef __QNXNTO__ +static int unixSectorSize(sqlite3_file *NotUsed){ + UNUSED_PARAMETER(NotUsed); + return SQLITE_DEFAULT_SECTOR_SIZE; +} +#endif + +/* +** The following version of unixSectorSize() is optimized for QNX. +*/ +#ifdef __QNXNTO__ +#include +#include +static int unixSectorSize(sqlite3_file *id){ + unixFile *pFile = (unixFile*)id; + if( pFile->sectorSize == 0 ){ + struct statvfs fsInfo; + + /* Set defaults for non-supported filesystems */ + pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; + pFile->deviceCharacteristics = 0; + if( fstatvfs(pFile->h, &fsInfo) == -1 ) { + return pFile->sectorSize; + } + + if( !strcmp(fsInfo.f_basetype, "tmp") ) { + pFile->sectorSize = fsInfo.f_bsize; + pFile->deviceCharacteristics = + SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */ + SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until + ** the write succeeds */ + SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind + ** so it is ordered */ + 0; + }else if( strstr(fsInfo.f_basetype, "etfs") ){ + pFile->sectorSize = fsInfo.f_bsize; + pFile->deviceCharacteristics = + /* etfs cluster size writes are atomic */ + (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) | + SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until + ** the write succeeds */ + SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind + ** so it is ordered */ + 0; + }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){ + pFile->sectorSize = fsInfo.f_bsize; + pFile->deviceCharacteristics = + SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */ + SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until + ** the write succeeds */ + SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind + ** so it is ordered */ + 0; + }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){ + pFile->sectorSize = fsInfo.f_bsize; + pFile->deviceCharacteristics = + /* full bitset of atomics from max sector size and smaller */ + ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | + SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind + ** so it is ordered */ + 0; + }else if( strstr(fsInfo.f_basetype, "dos") ){ + pFile->sectorSize = fsInfo.f_bsize; + pFile->deviceCharacteristics = + /* full bitset of atomics from max sector size and smaller */ + ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | + SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind + ** so it is ordered */ + 0; + }else{ + pFile->deviceCharacteristics = + SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */ + SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until + ** the write succeeds */ + 0; + } + } + /* Last chance verification. If the sector size isn't a multiple of 512 + ** then it isn't valid.*/ + if( pFile->sectorSize % 512 != 0 ){ + pFile->deviceCharacteristics = 0; + pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; + } + return pFile->sectorSize; +} +#endif /* __QNXNTO__ */ + +/* +** Return the device characteristics for the file. +** +** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default. +** However, that choice is controversial since technically the underlying +** file system does not always provide powersafe overwrites. (In other +** words, after a power-loss event, parts of the file that were never +** written might end up being altered.) However, non-PSOW behavior is very, +** very rare. And asserting PSOW makes a large reduction in the amount +** of required I/O for journaling, since a lot of padding is eliminated. +** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control +** 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; +} + +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 + +/* +** Return the system page size. +** +** This function should not be called directly by other code in this file. +** Instead, it should be called via macro osGetpagesize(). +*/ +static int unixGetpagesize(void){ +#if OS_VXWORKS + return 1024; +#elif defined(_BSD_SOURCE) + return getpagesize(); +#else + return (int)sysconf(_SC_PAGESIZE); +#endif +} + +#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */ + +#ifndef SQLITE_OMIT_WAL + +/* +** Object used to represent an shared memory buffer. +** +** When multiple threads all reference the same wal-index, each thread +** has its own unixShm object, but they all point to a single instance +** of this unixShmNode object. In other words, each wal-index is opened +** only once per process. +** +** Each unixShmNode object is connected to a single unixInodeInfo object. +** We could coalesce this object into unixInodeInfo, but that would mean +** every open file that does not use shared memory (in other words, most +** open files) would have to carry around this extra information. So +** the unixInodeInfo object contains a pointer to this unixShmNode object +** and the unixShmNode object is created only when needed. +** +** unixMutexHeld() must be true when creating or destroying +** this object or while reading or writing the following fields: +** +** nRef +** +** The following fields are read-only after the object is created: +** +** fid +** zFilename +** +** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and +** unixMutexHeld() is true when reading or writing any other field +** in this structure. +*/ +struct unixShmNode { + unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ + sqlite3_mutex *mutex; /* Mutex to access this object */ + char *zFilename; /* Name of the mmapped file */ + int h; /* Open file descriptor */ + int szRegion; /* Size of shared-memory regions */ + u16 nRegion; /* Size of array apRegion */ + u8 isReadonly; /* True if read-only */ + char **apRegion; /* Array of mapped shared-memory regions */ + int nRef; /* Number of unixShm objects pointing to this */ + unixShm *pFirst; /* All unixShm objects pointing to this */ +#ifdef SQLITE_DEBUG + u8 exclMask; /* Mask of exclusive locks held */ + u8 sharedMask; /* Mask of shared locks held */ + u8 nextShmId; /* Next available unixShm.id value */ +#endif +}; + +/* +** Structure used internally by this VFS to record the state of an +** open shared memory connection. +** +** The following fields are initialized when this object is created and +** are read-only thereafter: +** +** unixShm.pFile +** unixShm.id +** +** All other fields are read/write. The unixShm.pFile->mutex must be held +** while accessing any read/write fields. +*/ +struct unixShm { + unixShmNode *pShmNode; /* The underlying unixShmNode object */ + unixShm *pNext; /* Next unixShm with the same unixShmNode */ + u8 hasMutex; /* True if holding the unixShmNode mutex */ + u8 id; /* Id of this connection within its unixShmNode */ + u16 sharedMask; /* Mask of shared locks held */ + u16 exclMask; /* Mask of exclusive locks held */ +}; + +/* +** Constants used for locking +*/ +#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ +#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ + +/* +** Apply posix advisory locks for all bytes from ofst through ofst+n-1. +** +** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking +** otherwise. +*/ +static int unixShmSystemLock( + unixFile *pFile, /* Open connection to the WAL file */ + int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */ + int ofst, /* First byte of the locking range */ + int n /* Number of bytes to lock */ +){ + unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */ + struct flock f; /* The posix advisory locking structure */ + int rc = SQLITE_OK; /* Result code form fcntl() */ + + /* Access to the unixShmNode object is serialized by the caller */ + pShmNode = pFile->pInode->pShmNode; + assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 ); + + /* Shared locks never span more than one byte */ + assert( n==1 || lockType!=F_RDLCK ); + + /* Locks are within range */ + assert( n>=1 && n<=SQLITE_SHM_NLOCK ); + + if( pShmNode->h>=0 ){ + /* Initialize the locking parameters */ + memset(&f, 0, sizeof(f)); + f.l_type = lockType; + f.l_whence = SEEK_SET; + f.l_start = ofst; + f.l_len = n; + + rc = osFcntl(pShmNode->h, F_SETLK, &f); + rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; + } + + /* Update the global lock state and do debug tracing */ +#ifdef SQLITE_DEBUG + { u16 mask; + OSTRACE(("SHM-LOCK ")); + mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<exclMask &= ~mask; + pShmNode->sharedMask &= ~mask; + }else if( lockType==F_RDLCK ){ + OSTRACE(("read-lock %d ok", ofst)); + pShmNode->exclMask &= ~mask; + pShmNode->sharedMask |= mask; + }else{ + assert( lockType==F_WRLCK ); + OSTRACE(("write-lock %d ok", ofst)); + pShmNode->exclMask |= mask; + pShmNode->sharedMask &= ~mask; + } + }else{ + if( lockType==F_UNLCK ){ + OSTRACE(("unlock %d failed", ofst)); + }else if( lockType==F_RDLCK ){ + OSTRACE(("read-lock failed")); + }else{ + assert( lockType==F_WRLCK ); + OSTRACE(("write-lock %d failed", ofst)); + } + } + OSTRACE((" - afterwards %03x,%03x\n", + pShmNode->sharedMask, pShmNode->exclMask)); + } +#endif + + return rc; +} + +/* +** Return the minimum number of 32KB shm regions that should be mapped at +** a time, assuming that each mapping must be an integer multiple of the +** current system page-size. +** +** Usually, this is 1. The exception seems to be systems that are configured +** to use 64KB pages - in this case each mapping must cover at least two +** shm regions. +*/ +static int unixShmRegionPerMap(void){ + int shmsz = 32*1024; /* SHM region size */ + int pgsz = osGetpagesize(); /* System page size */ + assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */ + if( pgszpInode->pShmNode; + assert( unixMutexHeld() ); + if( p && ALWAYS(p->nRef==0) ){ + int nShmPerMap = unixShmRegionPerMap(); + int i; + assert( p->pInode==pFd->pInode ); + sqlite3_mutex_free(p->mutex); + for(i=0; inRegion; i+=nShmPerMap){ + if( p->h>=0 ){ + osMunmap(p->apRegion[i], p->szRegion); + }else{ + sqlite3_free(p->apRegion[i]); + } + } + sqlite3_free(p->apRegion); + if( p->h>=0 ){ + robust_close(pFd, p->h, __LINE__); + p->h = -1; + } + p->pInode->pShmNode = 0; + sqlite3_free(p); + } +} + +/* +** Open a shared-memory area associated with open database file pDbFd. +** This particular implementation uses mmapped files. +** +** The file used to implement shared-memory is in the same directory +** as the open database file and has the same name as the open database +** file with the "-shm" suffix added. For example, if the database file +** is "/home/user1/config.db" then the file that is created and mmapped +** for shared memory will be called "/home/user1/config.db-shm". +** +** Another approach to is to use files in /dev/shm or /dev/tmp or an +** some other tmpfs mount. But if a file in a different directory +** from the database file is used, then differing access permissions +** or a chroot() might cause two different processes on the same +** database to end up using different files for shared memory - +** meaning that their memory would not really be shared - resulting +** in database corruption. Nevertheless, this tmpfs file usage +** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm" +** or the equivalent. The use of the SQLITE_SHM_DIRECTORY compile-time +** option results in an incompatible build of SQLite; builds of SQLite +** that with differing SQLITE_SHM_DIRECTORY settings attempt to use the +** same database file at the same time, database corruption will likely +** result. The SQLITE_SHM_DIRECTORY compile-time option is considered +** "unsupported" and may go away in a future SQLite release. +** +** When opening a new shared-memory file, if no other instances of that +** file are currently open, in this process or in other processes, then +** the file must be truncated to zero length or have its header cleared. +** +** If the original database file (pDbFd) is using the "unix-excl" VFS +** that means that an exclusive lock is held on the database file and +** that no other processes are able to read or write the database. In +** that case, we do not really need shared memory. No shared memory +** file is created. The shared memory will be simulated with heap memory. +*/ +static int unixOpenSharedMemory(unixFile *pDbFd){ + struct unixShm *p = 0; /* The connection to be opened */ + struct unixShmNode *pShmNode; /* The underlying mmapped file */ + int rc; /* Result code */ + unixInodeInfo *pInode; /* The inode of fd */ + char *zShmFilename; /* Name of the file used for SHM */ + int nShmFilename; /* Size of the SHM filename in bytes */ + + /* Allocate space for the new unixShm object. */ + p = sqlite3_malloc64( sizeof(*p) ); + if( p==0 ) return SQLITE_NOMEM_BKPT; + memset(p, 0, sizeof(*p)); + assert( pDbFd->pShm==0 ); + + /* Check to see if a unixShmNode object already exists. Reuse an existing + ** one if present. Create a new one if necessary. + */ + unixEnterMutex(); + pInode = pDbFd->pInode; + pShmNode = pInode->pShmNode; + if( pShmNode==0 ){ + struct stat sStat; /* fstat() info for database file */ +#ifndef SQLITE_SHM_DIRECTORY + const char *zBasePath = pDbFd->zPath; +#endif + + /* Call fstat() to figure out the permissions on the database file. If + ** a new *-shm file is created, an attempt will be made to create it + ** with the same permissions. + */ + if( osFstat(pDbFd->h, &sStat) ){ + rc = SQLITE_IOERR_FSTAT; + goto shm_open_err; + } + +#ifdef SQLITE_SHM_DIRECTORY + nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31; +#else + nShmFilename = 6 + (int)strlen(zBasePath); +#endif + pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename ); + if( pShmNode==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto shm_open_err; + } + memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename); + zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1]; +#ifdef SQLITE_SHM_DIRECTORY + sqlite3_snprintf(nShmFilename, zShmFilename, + SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", + (u32)sStat.st_ino, (u32)sStat.st_dev); +#else + sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath); + sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); +#endif + pShmNode->h = -1; + pDbFd->pInode->pShmNode = pShmNode; + pShmNode->pInode = pDbFd->pInode; + if( sqlite3GlobalConfig.bCoreMutex ){ + pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->mutex==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto shm_open_err; + } + } + + if( pInode->bProcessLock==0 ){ + int openFlags = O_RDWR | O_CREAT; + if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ + openFlags = O_RDONLY; + pShmNode->isReadonly = 1; + } + pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777)); + if( pShmNode->h<0 ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename); + goto shm_open_err; + } + + /* If this process is running as root, make sure that the SHM file + ** is owned by the same user that owns the original database. Otherwise, + ** the original owner will not be able to connect. + */ + robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); + + /* Check to see if another process is holding the dead-man switch. + ** If not, truncate the file to zero length. + */ + rc = SQLITE_OK; + if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ + if( robust_ftruncate(pShmNode->h, 0) ){ + rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename); + } + } + if( rc==SQLITE_OK ){ + rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); + } + if( rc ) goto shm_open_err; + } + } + + /* Make the new connection a child of the unixShmNode */ + p->pShmNode = pShmNode; +#ifdef SQLITE_DEBUG + p->id = pShmNode->nextShmId++; +#endif + pShmNode->nRef++; + pDbFd->pShm = p; + unixLeaveMutex(); + + /* The reference count on pShmNode has already been incremented under + ** the cover of the unixEnterMutex() mutex and the pointer from the + ** new (struct unixShm) object to the pShmNode has been set. All that is + ** left to do is to link the new object into the linked list starting + ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex + ** mutex. + */ + sqlite3_mutex_enter(pShmNode->mutex); + p->pNext = pShmNode->pFirst; + pShmNode->pFirst = p; + sqlite3_mutex_leave(pShmNode->mutex); + return SQLITE_OK; + + /* Jump here on any error */ +shm_open_err: + unixShmPurge(pDbFd); /* This call frees pShmNode if required */ + sqlite3_free(p); + unixLeaveMutex(); + return rc; +} + +/* +** This function is called to obtain a pointer to region iRegion of the +** shared-memory associated with the database file fd. Shared-memory regions +** are numbered starting from zero. Each shared-memory region is szRegion +** bytes in size. +** +** If an error occurs, an error code is returned and *pp is set to NULL. +** +** Otherwise, if the bExtend parameter is 0 and the requested shared-memory +** region has not been allocated (by any client, including one running in a +** separate process), then *pp is set to NULL and SQLITE_OK returned. If +** bExtend is non-zero and the requested shared-memory region has not yet +** been allocated, it is allocated by this function. +** +** If the shared-memory region has already been allocated or is allocated by +** this call as described above, then it is mapped into this processes +** address space (if it is not already), *pp is set to point to the mapped +** memory and SQLITE_OK returned. +*/ +static int unixShmMap( + sqlite3_file *fd, /* Handle open on database file */ + int iRegion, /* Region to retrieve */ + int szRegion, /* Size of regions */ + int bExtend, /* True to extend file if necessary */ + void volatile **pp /* OUT: Mapped memory */ +){ + unixFile *pDbFd = (unixFile*)fd; + unixShm *p; + unixShmNode *pShmNode; + int rc = SQLITE_OK; + int nShmPerMap = unixShmRegionPerMap(); + int nReqRegion; + + /* If the shared-memory file has not yet been opened, open it now. */ + if( pDbFd->pShm==0 ){ + rc = unixOpenSharedMemory(pDbFd); + if( rc!=SQLITE_OK ) return rc; + } + + p = pDbFd->pShm; + pShmNode = p->pShmNode; + sqlite3_mutex_enter(pShmNode->mutex); + assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); + assert( pShmNode->pInode==pDbFd->pInode ); + assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + + /* Minimum number of regions required to be mapped. */ + nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; + + if( pShmNode->nRegionszRegion = szRegion; + + if( pShmNode->h>=0 ){ + /* The requested region is not mapped into this processes address space. + ** Check to see if it has been allocated (i.e. if the wal-index file is + ** large enough to contain the requested region). + */ + if( osFstat(pShmNode->h, &sStat) ){ + rc = SQLITE_IOERR_SHMSIZE; + goto shmpage_out; + } + + if( sStat.st_sizeh, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){ + const char *zFile = pShmNode->zFilename; + rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); + goto shmpage_out; + } + } + } + } + } + + /* Map the requested memory region into this processes address space. */ + apNew = (char **)sqlite3_realloc( + pShmNode->apRegion, nReqRegion*sizeof(char *) + ); + if( !apNew ){ + rc = SQLITE_IOERR_NOMEM_BKPT; + goto shmpage_out; + } + pShmNode->apRegion = apNew; + while( pShmNode->nRegionh>=0 ){ + pMem = osMmap(0, nMap, + pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, + MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion + ); + if( pMem==MAP_FAILED ){ + rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); + goto shmpage_out; + } + }else{ + pMem = sqlite3_malloc64(szRegion); + if( pMem==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto shmpage_out; + } + memset(pMem, 0, szRegion); + } + + for(i=0; iapRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i]; + } + pShmNode->nRegion += nShmPerMap; + } + } + +shmpage_out: + if( pShmNode->nRegion>iRegion ){ + *pp = pShmNode->apRegion[iRegion]; + }else{ + *pp = 0; + } + if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; + sqlite3_mutex_leave(pShmNode->mutex); + return rc; +} + +/* +** Change the lock state for a shared-memory segment. +** +** Note that the relationship between SHAREd and EXCLUSIVE locks is a little +** different here than in posix. In xShmLock(), one can go from unlocked +** to shared and back or from unlocked to exclusive and back. But one may +** not go from shared to exclusive or from exclusive to shared. +*/ +static int unixShmLock( + sqlite3_file *fd, /* Database file holding the shared memory */ + int ofst, /* First lock to acquire or release */ + int n, /* Number of locks to acquire or release */ + int flags /* What to do with the lock */ +){ + unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ + unixShm *p = pDbFd->pShm; /* The shared memory being locked */ + unixShm *pX; /* For looping over all siblings */ + unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ + int rc = SQLITE_OK; /* Result code */ + u16 mask; /* Mask of locks to take or release */ + + assert( pShmNode==pDbFd->pInode->pShmNode ); + assert( pShmNode->pInode==pDbFd->pInode ); + assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); + assert( n>=1 ); + assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) + || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); + assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); + assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + + mask = (1<<(ofst+n)) - (1<1 || mask==(1<mutex); + if( flags & SQLITE_SHM_UNLOCK ){ + u16 allMask = 0; /* Mask of locks held by siblings */ + + /* See if any siblings hold this same lock */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( pX==p ) continue; + assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); + allMask |= pX->sharedMask; + } + + /* Unlock the system-level locks */ + if( (mask & allMask)==0 ){ + rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); + }else{ + rc = SQLITE_OK; + } + + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; + } + }else if( flags & SQLITE_SHM_SHARED ){ + u16 allShared = 0; /* Union of locks held by connections other than "p" */ + + /* Find out which shared locks are already held by sibling connections. + ** If any sibling already holds an exclusive lock, go ahead and return + ** SQLITE_BUSY. + */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( (pX->exclMask & mask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + allShared |= pX->sharedMask; + } + + /* Get shared locks at the system level, if necessary */ + if( rc==SQLITE_OK ){ + if( (allShared & mask)==0 ){ + rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); + }else{ + rc = SQLITE_OK; + } + } + + /* Get the local shared locks */ + if( rc==SQLITE_OK ){ + p->sharedMask |= mask; + } + }else{ + /* Make sure no sibling connections hold locks that will block this + ** lock. If any do, return SQLITE_BUSY right away. + */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + } + + /* Get the exclusive locks at the system level. Then if successful + ** also mark the local connection as being locked. + */ + if( rc==SQLITE_OK ){ + rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); + if( rc==SQLITE_OK ){ + assert( (p->sharedMask & mask)==0 ); + p->exclMask |= mask; + } + } + } + sqlite3_mutex_leave(pShmNode->mutex); + OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", + p->id, osGetpid(0), p->sharedMask, p->exclMask)); + return rc; +} + +/* +** Implement a memory barrier or memory fence on shared memory. +** +** All loads and stores begun before the barrier must complete before +** any load or store begun after the barrier. +*/ +static void unixShmBarrier( + sqlite3_file *fd /* Database file holding the shared memory */ +){ + UNUSED_PARAMETER(fd); + sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ + unixEnterMutex(); /* Also mutex, for redundancy */ + unixLeaveMutex(); +} + +/* +** Close a connection to shared-memory. Delete the underlying +** storage if deleteFlag is true. +** +** If there is no shared memory associated with the connection then this +** routine is a harmless no-op. +*/ +static int unixShmUnmap( + sqlite3_file *fd, /* The underlying database file */ + int deleteFlag /* Delete shared-memory if true */ +){ + unixShm *p; /* The connection to be closed */ + unixShmNode *pShmNode; /* The underlying shared-memory file */ + unixShm **pp; /* For looping over sibling connections */ + unixFile *pDbFd; /* The underlying database file */ + + pDbFd = (unixFile*)fd; + p = pDbFd->pShm; + if( p==0 ) return SQLITE_OK; + pShmNode = p->pShmNode; + + assert( pShmNode==pDbFd->pInode->pShmNode ); + assert( pShmNode->pInode==pDbFd->pInode ); + + /* Remove connection p from the set of connections associated + ** with pShmNode */ + sqlite3_mutex_enter(pShmNode->mutex); + for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} + *pp = p->pNext; + + /* Free the connection p */ + sqlite3_free(p); + pDbFd->pShm = 0; + sqlite3_mutex_leave(pShmNode->mutex); + + /* If pShmNode->nRef has reached 0, then close the underlying + ** shared-memory file, too */ + unixEnterMutex(); + assert( pShmNode->nRef>0 ); + pShmNode->nRef--; + if( pShmNode->nRef==0 ){ + if( deleteFlag && pShmNode->h>=0 ){ + osUnlink(pShmNode->zFilename); + } + unixShmPurge(pDbFd); + } + unixLeaveMutex(); + + return SQLITE_OK; +} + + +#else +# define unixShmMap 0 +# define unixShmLock 0 +# define unixShmBarrier 0 +# define unixShmUnmap 0 +#endif /* #ifndef SQLITE_OMIT_WAL */ + +#if SQLITE_MAX_MMAP_SIZE>0 +/* +** If it is currently memory mapped, unmap file pFd. +*/ +static void unixUnmapfile(unixFile *pFd){ + assert( pFd->nFetchOut==0 ); + if( pFd->pMapRegion ){ + osMunmap(pFd->pMapRegion, pFd->mmapSizeActual); + pFd->pMapRegion = 0; + pFd->mmapSize = 0; + pFd->mmapSizeActual = 0; + } +} + +/* +** Attempt to set the size of the memory mapping maintained by file +** descriptor pFd to nNew bytes. Any existing mapping is discarded. +** +** If successful, this function sets the following variables: +** +** unixFile.pMapRegion +** unixFile.mmapSize +** unixFile.mmapSizeActual +** +** If unsuccessful, an error message is logged via sqlite3_log() and +** the three variables above are zeroed. In this case SQLite should +** continue accessing the database using the xRead() and xWrite() +** methods. +*/ +static void unixRemapfile( + unixFile *pFd, /* File descriptor object */ + i64 nNew /* Required mapping size */ +){ + const char *zErr = "mmap"; + int h = pFd->h; /* File descriptor open on db file */ + u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */ + i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */ + u8 *pNew = 0; /* Location of new mapping */ + int flags = PROT_READ; /* Flags to pass to mmap() */ + + assert( pFd->nFetchOut==0 ); + assert( nNew>pFd->mmapSize ); + assert( nNew<=pFd->mmapSizeMax ); + assert( nNew>0 ); + assert( pFd->mmapSizeActual>=pFd->mmapSize ); + assert( MAP_FAILED!=0 ); + +#ifdef SQLITE_MMAP_READWRITE + if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; +#endif + + if( pOrig ){ +#if HAVE_MREMAP + i64 nReuse = pFd->mmapSize; +#else + const int szSyspage = osGetpagesize(); + i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); +#endif + u8 *pReq = &pOrig[nReuse]; + + /* Unmap any pages of the existing mapping that cannot be reused. */ + if( nReuse!=nOrig ){ + osMunmap(pReq, nOrig-nReuse); + } + +#if HAVE_MREMAP + pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE); + zErr = "mremap"; +#else + pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse); + if( pNew!=MAP_FAILED ){ + if( pNew!=pReq ){ + osMunmap(pNew, nNew - nReuse); + pNew = 0; + }else{ + pNew = pOrig; + } + } +#endif + + /* The attempt to extend the existing mapping failed. Free it. */ + if( pNew==MAP_FAILED || pNew==0 ){ + osMunmap(pOrig, nReuse); + } + } + + /* If pNew is still NULL, try to create an entirely new mapping. */ + if( pNew==0 ){ + pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0); + } + + if( pNew==MAP_FAILED ){ + pNew = 0; + nNew = 0; + unixLogError(SQLITE_OK, zErr, pFd->zPath); + + /* If the mmap() above failed, assume that all subsequent mmap() calls + ** will probably fail too. Fall back to using xRead/xWrite exclusively + ** in this case. */ + pFd->mmapSizeMax = 0; + } + pFd->pMapRegion = (void *)pNew; + pFd->mmapSize = pFd->mmapSizeActual = nNew; +} + +/* +** Memory map or remap the file opened by file-descriptor pFd (if the file +** is already mapped, the existing mapping is replaced by the new). Or, if +** there already exists a mapping for this file, and there are still +** outstanding xFetch() references to it, this function is a no-op. +** +** If parameter nByte is non-negative, then it is the requested size of +** the mapping to create. Otherwise, if nByte is less than zero, then the +** requested size is the size of the file on disk. The actual size of the +** created mapping is either the requested size or the value configured +** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller. +** +** SQLITE_OK is returned if no error occurs (even if the mapping is not +** recreated as a result of outstanding references) or an SQLite error +** code otherwise. +*/ +static int unixMapfile(unixFile *pFd, i64 nMap){ + assert( nMap>=0 || pFd->nFetchOut==0 ); + assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) ); + if( pFd->nFetchOut>0 ) return SQLITE_OK; + + if( nMap<0 ){ + struct stat statbuf; /* Low-level file information */ + if( osFstat(pFd->h, &statbuf) ){ + return SQLITE_IOERR_FSTAT; + } + nMap = statbuf.st_size; + } + if( nMap>pFd->mmapSizeMax ){ + nMap = pFd->mmapSizeMax; + } + + assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) ); + if( nMap!=pFd->mmapSize ){ + unixRemapfile(pFd, nMap); + } + + return SQLITE_OK; +} +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + +/* +** If possible, return a pointer to a mapping of file fd starting at offset +** iOff. The mapping must be valid for at least nAmt bytes. +** +** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. +** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. +** Finally, if an error does occur, return an SQLite error code. The final +** value of *pp is undefined in this case. +** +** If this function does return a pointer, the caller must eventually +** release the reference by calling unixUnfetch(). +*/ +static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ +#if SQLITE_MAX_MMAP_SIZE>0 + unixFile *pFd = (unixFile *)fd; /* The underlying database file */ +#endif + *pp = 0; + +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFd->mmapSizeMax>0 ){ + if( pFd->pMapRegion==0 ){ + int rc = unixMapfile(pFd, -1); + if( rc!=SQLITE_OK ) return rc; + } + if( pFd->mmapSize >= iOff+nAmt ){ + *pp = &((u8 *)pFd->pMapRegion)[iOff]; + pFd->nFetchOut++; + } + } +#endif + return SQLITE_OK; +} + +/* +** If the third argument is non-NULL, then this function releases a +** reference obtained by an earlier call to unixFetch(). The second +** argument passed to this function must be the same as the corresponding +** argument that was passed to the unixFetch() invocation. +** +** Or, if the third argument is NULL, then this function is being called +** to inform the VFS layer that, according to POSIX, any existing mapping +** may now be invalid and should be unmapped. +*/ +static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ +#if SQLITE_MAX_MMAP_SIZE>0 + unixFile *pFd = (unixFile *)fd; /* The underlying database file */ + UNUSED_PARAMETER(iOff); + + /* If p==0 (unmap the entire file) then there must be no outstanding + ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), + ** then there must be at least one outstanding. */ + assert( (p==0)==(pFd->nFetchOut==0) ); + + /* If p!=0, it must match the iOff value. */ + assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); + + if( p ){ + pFd->nFetchOut--; + }else{ + unixUnmapfile(pFd); + } + + assert( pFd->nFetchOut>=0 ); +#else + UNUSED_PARAMETER(fd); + UNUSED_PARAMETER(p); + UNUSED_PARAMETER(iOff); +#endif + return SQLITE_OK; +} + +/* +** Here ends the implementation of all sqlite3_file methods. +** +********************** End sqlite3_file Methods ******************************* +******************************************************************************/ + +/* +** This division contains definitions of sqlite3_io_methods objects that +** implement various file locking strategies. It also contains definitions +** of "finder" functions. A finder-function is used to locate the appropriate +** sqlite3_io_methods object for a particular database file. The pAppData +** field of the sqlite3_vfs VFS objects are initialized to be pointers to +** the correct finder-function for that VFS. +** +** Most finder functions return a pointer to a fixed sqlite3_io_methods +** object. The only interesting finder-function is autolockIoFinder, which +** looks at the filesystem type and tries to guess the best locking +** strategy from that. +** +** For finder-function F, two objects are created: +** +** (1) The real finder-function named "FImpt()". +** +** (2) A constant pointer to this function named just "F". +** +** +** A pointer to the F pointer is used as the pAppData value for VFS +** objects. We have to do this instead of letting pAppData point +** directly at the finder-function since C90 rules prevent a void* +** from be cast into a function pointer. +** +** +** Each instance of this macro generates two objects: +** +** * A constant sqlite3_io_methods object call METHOD that has locking +** methods CLOSE, LOCK, UNLOCK, CKRESLOCK. +** +** * An I/O method finder function called FINDER that returns a pointer +** to the METHOD object in the previous bullet. +*/ +#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \ +static const sqlite3_io_methods METHOD = { \ + VERSION, /* iVersion */ \ + CLOSE, /* xClose */ \ + unixRead, /* xRead */ \ + unixWrite, /* xWrite */ \ + unixTruncate, /* xTruncate */ \ + unixSync, /* xSync */ \ + unixFileSize, /* xFileSize */ \ + LOCK, /* xLock */ \ + UNLOCK, /* xUnlock */ \ + CKLOCK, /* xCheckReservedLock */ \ + unixFileControl, /* xFileControl */ \ + unixSectorSize, /* xSectorSize */ \ + unixDeviceCharacteristics, /* xDeviceCapabilities */ \ + SHMMAP, /* xShmMap */ \ + unixShmLock, /* xShmLock */ \ + unixShmBarrier, /* xShmBarrier */ \ + unixShmUnmap, /* xShmUnmap */ \ + unixFetch, /* xFetch */ \ + unixUnfetch, /* xUnfetch */ \ +}; \ +static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ + UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ + return &METHOD; \ +} \ +static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ + = FINDER##Impl; + +/* +** Here are all of the sqlite3_io_methods objects for each of the +** locking strategies. Functions that return pointers to these methods +** are also created. +*/ +IOMETHODS( + posixIoFinder, /* Finder function name */ + posixIoMethods, /* sqlite3_io_methods object name */ + 3, /* shared memory and mmap are enabled */ + unixClose, /* xClose method */ + unixLock, /* xLock method */ + unixUnlock, /* xUnlock method */ + unixCheckReservedLock, /* xCheckReservedLock method */ + unixShmMap /* xShmMap method */ +) +IOMETHODS( + nolockIoFinder, /* Finder function name */ + nolockIoMethods, /* sqlite3_io_methods object name */ + 3, /* shared memory is disabled */ + nolockClose, /* xClose method */ + nolockLock, /* xLock method */ + nolockUnlock, /* xUnlock method */ + nolockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ +) +IOMETHODS( + dotlockIoFinder, /* Finder function name */ + dotlockIoMethods, /* sqlite3_io_methods object name */ + 1, /* shared memory is disabled */ + dotlockClose, /* xClose method */ + dotlockLock, /* xLock method */ + dotlockUnlock, /* xUnlock method */ + dotlockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ +) + +#if SQLITE_ENABLE_LOCKING_STYLE +IOMETHODS( + flockIoFinder, /* Finder function name */ + flockIoMethods, /* sqlite3_io_methods object name */ + 1, /* shared memory is disabled */ + flockClose, /* xClose method */ + flockLock, /* xLock method */ + flockUnlock, /* xUnlock method */ + flockCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ +) +#endif + +#if OS_VXWORKS +IOMETHODS( + semIoFinder, /* Finder function name */ + semIoMethods, /* sqlite3_io_methods object name */ + 1, /* shared memory is disabled */ + semXClose, /* xClose method */ + semXLock, /* xLock method */ + semXUnlock, /* xUnlock method */ + semXCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ +) +#endif + +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE +IOMETHODS( + afpIoFinder, /* Finder function name */ + afpIoMethods, /* sqlite3_io_methods object name */ + 1, /* shared memory is disabled */ + afpClose, /* xClose method */ + afpLock, /* xLock method */ + afpUnlock, /* xUnlock method */ + afpCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ +) +#endif + +/* +** The proxy locking method is a "super-method" in the sense that it +** opens secondary file descriptors for the conch and lock files and +** it uses proxy, dot-file, AFP, and flock() locking methods on those +** secondary files. For this reason, the division that implements +** proxy locking is located much further down in the file. But we need +** to go ahead and define the sqlite3_io_methods and finder function +** for proxy locking here. So we forward declare the I/O methods. +*/ +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE +static int proxyClose(sqlite3_file*); +static int proxyLock(sqlite3_file*, int); +static int proxyUnlock(sqlite3_file*, int); +static int proxyCheckReservedLock(sqlite3_file*, int*); +IOMETHODS( + proxyIoFinder, /* Finder function name */ + proxyIoMethods, /* sqlite3_io_methods object name */ + 1, /* shared memory is disabled */ + proxyClose, /* xClose method */ + proxyLock, /* xLock method */ + proxyUnlock, /* xUnlock method */ + proxyCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ +) +#endif + +/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */ +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE +IOMETHODS( + nfsIoFinder, /* Finder function name */ + nfsIoMethods, /* sqlite3_io_methods object name */ + 1, /* shared memory is disabled */ + unixClose, /* xClose method */ + unixLock, /* xLock method */ + nfsUnlock, /* xUnlock method */ + unixCheckReservedLock, /* xCheckReservedLock method */ + 0 /* xShmMap method */ +) +#endif + +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE +/* +** This "finder" function attempts to determine the best locking strategy +** for the database file "filePath". It then returns the sqlite3_io_methods +** object that implements that strategy. +** +** This is for MacOSX only. +*/ +static const sqlite3_io_methods *autolockIoFinderImpl( + const char *filePath, /* name of the database file */ + unixFile *pNew /* open file object for the database file */ +){ + static const struct Mapping { + const char *zFilesystem; /* Filesystem type name */ + const sqlite3_io_methods *pMethods; /* Appropriate locking method */ + } aMap[] = { + { "hfs", &posixIoMethods }, + { "ufs", &posixIoMethods }, + { "afpfs", &afpIoMethods }, + { "smbfs", &afpIoMethods }, + { "webdav", &nolockIoMethods }, + { 0, 0 } + }; + int i; + struct statfs fsInfo; + struct flock lockInfo; + + if( !filePath ){ + /* If filePath==NULL that means we are dealing with a transient file + ** that does not need to be locked. */ + return &nolockIoMethods; + } + if( statfs(filePath, &fsInfo) != -1 ){ + if( fsInfo.f_flags & MNT_RDONLY ){ + return &nolockIoMethods; + } + for(i=0; aMap[i].zFilesystem; i++){ + if( strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem)==0 ){ + return aMap[i].pMethods; + } + } + } + + /* Default case. Handles, amongst others, "nfs". + ** Test byte-range lock using fcntl(). If the call succeeds, + ** assume that the file-system supports POSIX style locks. + */ + lockInfo.l_len = 1; + lockInfo.l_start = 0; + lockInfo.l_whence = SEEK_SET; + lockInfo.l_type = F_RDLCK; + if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { + if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){ + return &nfsIoMethods; + } else { + return &posixIoMethods; + } + }else{ + return &dotlockIoMethods; + } +} +static const sqlite3_io_methods + *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; + +#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ + +#if OS_VXWORKS +/* +** This "finder" function for VxWorks checks to see if posix advisory +** locking works. If it does, then that is what is used. If it does not +** work, then fallback to named semaphore locking. +*/ +static const sqlite3_io_methods *vxworksIoFinderImpl( + const char *filePath, /* name of the database file */ + unixFile *pNew /* the open file object */ +){ + struct flock lockInfo; + + if( !filePath ){ + /* If filePath==NULL that means we are dealing with a transient file + ** that does not need to be locked. */ + return &nolockIoMethods; + } + + /* Test if fcntl() is supported and use POSIX style locks. + ** Otherwise fall back to the named semaphore method. + */ + lockInfo.l_len = 1; + lockInfo.l_start = 0; + lockInfo.l_whence = SEEK_SET; + lockInfo.l_type = F_RDLCK; + if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { + return &posixIoMethods; + }else{ + return &semIoMethods; + } +} +static const sqlite3_io_methods + *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl; + +#endif /* OS_VXWORKS */ + +/* +** An abstract type for a pointer to an IO method finder function: +*/ +typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); + + +/**************************************************************************** +**************************** sqlite3_vfs methods **************************** +** +** This division contains the implementation of methods on the +** sqlite3_vfs object. +*/ + +/* +** Initialize the contents of the unixFile structure pointed to by pId. +*/ +static int fillInUnixFile( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + int h, /* Open file descriptor of file being opened */ + sqlite3_file *pId, /* Write to the unixFile structure here */ + const char *zFilename, /* Name of the file being opened */ + int ctrlFlags /* Zero or more UNIXFILE_* values */ +){ + const sqlite3_io_methods *pLockingStyle; + unixFile *pNew = (unixFile *)pId; + int rc = SQLITE_OK; + + 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 ); + + OSTRACE(("OPEN %-3d %s\n", h, zFilename)); + pNew->h = h; + pNew->pVfs = pVfs; + pNew->zPath = zFilename; + pNew->ctrlFlags = (u8)ctrlFlags; +#if SQLITE_MAX_MMAP_SIZE>0 + pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap; +#endif + if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), + "psow", SQLITE_POWERSAFE_OVERWRITE) ){ + pNew->ctrlFlags |= UNIXFILE_PSOW; + } + if( strcmp(pVfs->zName,"unix-excl")==0 ){ + pNew->ctrlFlags |= UNIXFILE_EXCL; + } + +#if OS_VXWORKS + pNew->pId = vxworksFindFileId(zFilename); + if( pNew->pId==0 ){ + ctrlFlags |= UNIXFILE_NOLOCK; + rc = SQLITE_NOMEM_BKPT; + } +#endif + + if( ctrlFlags & UNIXFILE_NOLOCK ){ + pLockingStyle = &nolockIoMethods; + }else{ + pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew); +#if SQLITE_ENABLE_LOCKING_STYLE + /* Cache zFilename in the locking context (AFP and dotlock override) for + ** proxyLock activation is possible (remote proxy is based on db name) + ** zFilename remains valid until file is closed, to support */ + pNew->lockingContext = (void*)zFilename; +#endif + } + + if( pLockingStyle == &posixIoMethods +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE + || pLockingStyle == &nfsIoMethods +#endif + ){ + unixEnterMutex(); + rc = findInodeInfo(pNew, &pNew->pInode); + if( rc!=SQLITE_OK ){ + /* If an error occurred in findInodeInfo(), close the file descriptor + ** immediately, before releasing the mutex. findInodeInfo() may fail + ** in two scenarios: + ** + ** (a) A call to fstat() failed. + ** (b) A malloc failed. + ** + ** Scenario (b) may only occur if the process is holding no other + ** file descriptors open on the same file. If there were other file + ** descriptors on this file, then no malloc would be required by + ** findInodeInfo(). If this is the case, it is quite safe to close + ** handle h - as it is guaranteed that no posix locks will be released + ** by doing so. + ** + ** If scenario (a) caused the error then things are not so safe. The + ** implicit assumption here is that if fstat() fails, things are in + ** such bad shape that dropping a lock or two doesn't matter much. + */ + robust_close(pNew, h, __LINE__); + h = -1; + } + unixLeaveMutex(); + } + +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) + else if( pLockingStyle == &afpIoMethods ){ + /* AFP locking uses the file path so it needs to be included in + ** the afpLockingContext. + */ + afpLockingContext *pCtx; + pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) ); + if( pCtx==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + /* NB: zFilename exists and remains valid until the file is closed + ** according to requirement F11141. So we do not need to make a + ** copy of the filename. */ + pCtx->dbPath = zFilename; + pCtx->reserved = 0; + srandomdev(); + unixEnterMutex(); + rc = findInodeInfo(pNew, &pNew->pInode); + if( rc!=SQLITE_OK ){ + sqlite3_free(pNew->lockingContext); + robust_close(pNew, h, __LINE__); + h = -1; + } + unixLeaveMutex(); + } + } +#endif + + else if( pLockingStyle == &dotlockIoMethods ){ + /* Dotfile locking uses the file path so it needs to be included in + ** the dotlockLockingContext + */ + char *zLockFile; + int nFilename; + assert( zFilename!=0 ); + nFilename = (int)strlen(zFilename) + 6; + zLockFile = (char *)sqlite3_malloc64(nFilename); + if( zLockFile==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename); + } + pNew->lockingContext = zLockFile; + } + +#if OS_VXWORKS + else if( pLockingStyle == &semIoMethods ){ + /* Named semaphore locking uses the file path so it needs to be + ** included in the semLockingContext + */ + unixEnterMutex(); + rc = findInodeInfo(pNew, &pNew->pInode); + if( (rc==SQLITE_OK) && (pNew->pInode->pSem==NULL) ){ + char *zSemName = pNew->pInode->aSemName; + int n; + sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem", + pNew->pId->zCanonicalName); + for( n=1; zSemName[n]; n++ ) + if( zSemName[n]=='/' ) zSemName[n] = '_'; + pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1); + if( pNew->pInode->pSem == SEM_FAILED ){ + rc = SQLITE_NOMEM_BKPT; + pNew->pInode->aSemName[0] = '\0'; + } + } + unixLeaveMutex(); + } +#endif + + storeLastErrno(pNew, 0); +#if OS_VXWORKS + if( rc!=SQLITE_OK ){ + if( h>=0 ) robust_close(pNew, h, __LINE__); + h = -1; + osUnlink(zFilename); + pNew->ctrlFlags |= UNIXFILE_DELETE; + } +#endif + if( rc!=SQLITE_OK ){ + if( h>=0 ) robust_close(pNew, h, __LINE__); + }else{ + pNew->pMethod = pLockingStyle; + OpenCounter(+1); + verifyDbFile(pNew); + } + return rc; +} + +/* +** Return the name of a directory in which to put temporary files. +** If no suitable temporary file directory can be found, return NULL. +*/ +static const char *unixTempFileDir(void){ + static const char *azDirs[] = { + 0, + 0, + "/var/tmp", + "/usr/tmp", + "/tmp", + "." + }; + unsigned int i = 0; + struct stat buf; + const char *zDir = sqlite3_temp_directory; + + if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); + if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); + while(1){ + if( zDir!=0 + && osStat(zDir, &buf)==0 + && S_ISDIR(buf.st_mode) + && osAccess(zDir, 03)==0 + ){ + return zDir; + } + if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; + zDir = azDirs[i++]; + } + return 0; +} + +/* +** Create a temporary file name in zBuf. zBuf must be allocated +** by the calling process and must be big enough to hold at least +** pVfs->mxPathname bytes. +*/ +static int unixGetTempname(int nBuf, char *zBuf){ + const char *zDir; + int iLimit = 0; + + /* It's odd to simulate an io-error here, but really this is just + ** using the io-error infrastructure to test that SQLite handles this + ** function failing. + */ + zBuf[0] = 0; + SimulateIOError( return SQLITE_IOERR ); + + zDir = unixTempFileDir(); + if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH; + do{ + u64 r; + sqlite3_randomness(sizeof(r), &r); + assert( nBuf>2 ); + zBuf[nBuf-2] = 0; + sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c", + zDir, r, 0); + if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR; + }while( osAccess(zBuf,0)==0 ); + return SQLITE_OK; +} + +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) +/* +** Routine to transform a unixFile into a proxy-locking unixFile. +** Implementation in the proxy-lock division, but used by unixOpen() +** if SQLITE_PREFER_PROXY_LOCKING is defined. +*/ +static int proxyTransformUnixFile(unixFile*, const char*); +#endif + +/* +** Search for an unused file descriptor that was opened on the database +** file (not a journal or master-journal file) identified by pathname +** zPath with SQLITE_OPEN_XXX flags matching those passed as the second +** argument to this function. +** +** Such a file descriptor may exist if a database connection was closed +** but the associated file descriptor could not be closed because some +** other file descriptor open on the same file is holding a file-lock. +** Refer to comments in the unixClose() function and the lengthy comment +** describing "Posix Advisory Locking" at the start of this file for +** further details. Also, ticket #4018. +** +** If a suitable file descriptor is found, then it is returned. If no +** such file descriptor is located, -1 is returned. +*/ +static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ + UnixUnusedFd *pUnused = 0; + + /* Do not search for an unused file descriptor on vxworks. Not because + ** vxworks would not benefit from the change (it might, we're not sure), + ** but because no way to test it is currently available. It is better + ** not to risk breaking vxworks support for the sake of such an obscure + ** feature. */ +#if !OS_VXWORKS + struct stat sStat; /* Results of stat() call */ + + /* 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 + ** ignored and -1 is returned. The caller will try to open a new file + ** descriptor on the same path, fail, and return an error to SQLite. + ** + ** 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) ){ + unixInodeInfo *pInode; + + unixEnterMutex(); + pInode = inodeList; + while( pInode && (pInode->fileId.dev!=sStat.st_dev + || pInode->fileId.ino!=(u64)sStat.st_ino) ){ + pInode = pInode->pNext; + } + if( pInode ){ + UnixUnusedFd **pp; + for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); + pUnused = *pp; + if( pUnused ){ + *pp = pUnused->pNext; + } + } + unixLeaveMutex(); + } +#endif /* if !OS_VXWORKS */ + return pUnused; +} + +/* +** Find the mode, uid and gid of file zFile. +*/ +static int getFileMode( + const char *zFile, /* File name */ + mode_t *pMode, /* OUT: Permissions of zFile */ + uid_t *pUid, /* OUT: uid of zFile. */ + gid_t *pGid /* OUT: gid of zFile. */ +){ + struct stat sStat; /* Output of stat() on database file */ + int rc = SQLITE_OK; + if( 0==osStat(zFile, &sStat) ){ + *pMode = sStat.st_mode & 0777; + *pUid = sStat.st_uid; + *pGid = sStat.st_gid; + }else{ + rc = SQLITE_IOERR_FSTAT; + } + return rc; +} + +/* +** This function is called by unixOpen() to determine the unix permissions +** to create new files with. If no error occurs, then SQLITE_OK is returned +** and a value suitable for passing as the third argument to open(2) is +** written to *pMode. If an IO error occurs, an SQLite error code is +** returned and the value of *pMode is not modified. +** +** In most cases, this routine sets *pMode to 0, which will become +** an indication to robust_open() to create the file using +** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask. +** But if the file being opened is a WAL or regular journal file, then +** this function queries the file-system for the permissions on the +** corresponding database file and sets *pMode to this value. Whenever +** possible, WAL and journal files are created using the same permissions +** as the associated database file. +** +** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the +** original filename is unavailable. But 8_3_NAMES is only used for +** FAT filesystems and permissions do not matter there, so just use +** the default permissions. +*/ +static int findCreateFileMode( + const char *zPath, /* Path of file (possibly) being created */ + int flags, /* Flags passed as 4th argument to xOpen() */ + mode_t *pMode, /* OUT: Permissions to open file with */ + uid_t *pUid, /* OUT: uid to set on the file */ + gid_t *pGid /* OUT: gid to set on the file */ +){ + int rc = SQLITE_OK; /* Return Code */ + *pMode = 0; + *pUid = 0; + *pGid = 0; + if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ + char zDb[MAX_PATHNAME+1]; /* Database file path */ + int nDb; /* Number of valid bytes in zDb */ + + /* zPath is a path to a WAL or journal file. The following block derives + ** the path to the associated database file from zPath. This block handles + ** the following naming conventions: + ** + ** "-journal" + ** "-wal" + ** "-journalNN" + ** "-walNN" + ** + ** where NN is a decimal number. The NN naming schemes are + ** used by the test_multiplex.c module. + */ + 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. */ + if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; +#endif + nDb--; + } + memcpy(zDb, zPath, nDb); + zDb[nDb] = '\0'; + + rc = getFileMode(zDb, pMode, pUid, pGid); + }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ + *pMode = 0600; + }else if( flags & SQLITE_OPEN_URI ){ + /* If this is a main database file and the file was opened using a URI + ** filename, check for the "modeof" parameter. If present, interpret + ** its value as a filename and try to copy the mode, uid and gid from + ** that file. */ + const char *z = sqlite3_uri_parameter(zPath, "modeof"); + if( z ){ + rc = getFileMode(z, pMode, pUid, pGid); + } + } + return rc; +} + +/* +** Open the file zPath. +** +** Previously, the SQLite OS layer used three functions in place of this +** one: +** +** sqlite3OsOpenReadWrite(); +** sqlite3OsOpenReadOnly(); +** sqlite3OsOpenExclusive(); +** +** These calls correspond to the following combinations of flags: +** +** ReadWrite() -> (READWRITE | CREATE) +** ReadOnly() -> (READONLY) +** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) +** +** The old OpenExclusive() accepted a boolean argument - "delFlag". If +** true, the file was configured to be automatically deleted when the +** file handle closed. To achieve the same effect using this new +** interface, add the DELETEONCLOSE flag to those specified above for +** OpenExclusive(). +*/ +static int unixOpen( + sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */ + const char *zPath, /* Pathname of file to be opened */ + sqlite3_file *pFile, /* The file descriptor to be filled in */ + int flags, /* Input flags to control the opening */ + int *pOutFlags /* Output flags returned to SQLite core */ +){ + unixFile *p = (unixFile *)pFile; + int fd = -1; /* File descriptor returned by open() */ + int openFlags = 0; /* Flags to pass to open() */ + int eType = flags&0xFFFFFF00; /* Type of file to open */ + int noLock; /* True to omit locking primitives */ + int rc = SQLITE_OK; /* Function Return Code */ + int ctrlFlags = 0; /* UNIXFILE_* flags */ + + int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); + int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); + int isCreate = (flags & SQLITE_OPEN_CREATE); + int isReadonly = (flags & SQLITE_OPEN_READONLY); + int isReadWrite = (flags & SQLITE_OPEN_READWRITE); +#if SQLITE_ENABLE_LOCKING_STYLE + int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY); +#endif +#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE + struct statfs fsInfo; +#endif + + /* If creating a master or main-file journal, this function will open + ** a file-descriptor on the directory too. The first time unixSync() + ** is called the directory file descriptor will be fsync()ed and close()d. + */ + int syncDir = (isCreate && ( + eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_MAIN_JOURNAL + || eType==SQLITE_OPEN_WAL + )); + + /* If argument zPath is a NULL pointer, this function is required to open + ** a temporary file. Use this buffer to store the file name in. + */ + char zTmpname[MAX_PATHNAME+2]; + const char *zName = zPath; + + /* Check the following statements are true: + ** + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (b) if CREATE is set, then READWRITE must also be set, and + ** (c) if EXCLUSIVE is set, then CREATE must also be set. + ** (d) if DELETEONCLOSE is set, then CREATE must also be set. + */ + assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); + assert(isCreate==0 || isReadWrite); + assert(isExclusive==0 || isCreate); + assert(isDelete==0 || isCreate); + + /* The main DB, main journal, WAL file and master journal are never + ** automatically deleted. Nor are they ever temporary files. */ + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); + + /* Assert that the upper layer has set one of the "file-type" flags. */ + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL + ); + + /* Detect a pid change and reset the PRNG. There is a race condition + ** here such that two or more threads all trying to open databases at + ** the same instant might all reset the PRNG. But multiple resets + ** are harmless. + */ + if( randomnessPid!=osGetpid(0) ){ + randomnessPid = osGetpid(0); + sqlite3_randomness(0,0); + } + + memset(p, 0, sizeof(unixFile)); + + if( eType==SQLITE_OPEN_MAIN_DB ){ + UnixUnusedFd *pUnused; + pUnused = findReusableFd(zName, flags); + if( pUnused ){ + fd = pUnused->fd; + }else{ + pUnused = sqlite3_malloc64(sizeof(*pUnused)); + if( !pUnused ){ + return SQLITE_NOMEM_BKPT; + } + } + p->pUnused = pUnused; + + /* Database filenames are double-zero terminated if they are not + ** URIs with parameters. Hence, they can always be passed into + ** sqlite3_uri_parameter(). */ + assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 ); + + }else if( !zName ){ + /* If zName is NULL, the upper layer is requesting a temp file. */ + assert(isDelete && !syncDir); + rc = unixGetTempname(pVfs->mxPathname, zTmpname); + if( rc!=SQLITE_OK ){ + return rc; + } + zName = zTmpname; + + /* Generated temporary filenames are always double-zero terminated + ** for use by sqlite3_uri_parameter(). */ + assert( zName[strlen(zName)+1]==0 ); + } + + /* Determine the value of the flags parameter passed to POSIX function + ** open(). These must be calculated even if open() is not called, as + ** they may be stored as part of the file handle and used by the + ** 'conch file' locking functions later on. */ + if( isReadonly ) openFlags |= O_RDONLY; + if( isReadWrite ) openFlags |= O_RDWR; + if( isCreate ) openFlags |= O_CREAT; + if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW); + openFlags |= (O_LARGEFILE|O_BINARY); + + if( fd<0 ){ + mode_t openMode; /* Permissions to create file with */ + uid_t uid; /* Userid for the file */ + gid_t gid; /* Groupid for the file */ + rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid); + if( rc!=SQLITE_OK ){ + assert( !p->pUnused ); + assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); + return rc; + } + fd = robust_open(zName, openFlags, openMode); + OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags)); + assert( !isExclusive || (openFlags & O_CREAT)!=0 ); + if( fd<0 && errno!=EISDIR && isReadWrite ){ + /* Failed to open the file for read/write access. Try read-only. */ + flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); + openFlags &= ~(O_RDWR|O_CREAT); + flags |= SQLITE_OPEN_READONLY; + openFlags |= O_RDONLY; + isReadonly = 1; + fd = robust_open(zName, openFlags, openMode); + } + if( fd<0 ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); + goto open_finished; + } + + /* If this process is running as root and if creating a new rollback + ** journal or WAL file, set the ownership of the journal or WAL to be + ** the same as the original database. + */ + if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ + robustFchown(fd, uid, gid); + } + } + assert( fd>=0 ); + if( pOutFlags ){ + *pOutFlags = flags; + } + + if( p->pUnused ){ + p->pUnused->fd = fd; + p->pUnused->flags = flags; + } + + if( isDelete ){ +#if OS_VXWORKS + zPath = zName; +#elif defined(SQLITE_UNLINK_AFTER_CLOSE) + zPath = sqlite3_mprintf("%s", zName); + if( zPath==0 ){ + robust_close(p, fd, __LINE__); + return SQLITE_NOMEM_BKPT; + } +#else + osUnlink(zName); +#endif + } +#if SQLITE_ENABLE_LOCKING_STYLE + else{ + p->openFlags = openFlags; + } +#endif + +#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE + if( fstatfs(fd, &fsInfo) == -1 ){ + storeLastErrno(p, errno); + robust_close(p, fd, __LINE__); + return SQLITE_IOERR_ACCESS; + } + if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { + ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; + } + if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) { + ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; + } +#endif + + /* Set up appropriate ctrlFlags */ + if( isDelete ) ctrlFlags |= UNIXFILE_DELETE; + if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY; + noLock = eType!=SQLITE_OPEN_MAIN_DB; + if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK; + if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC; + if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI; + +#if SQLITE_ENABLE_LOCKING_STYLE +#if SQLITE_PREFER_PROXY_LOCKING + isAutoProxy = 1; +#endif + if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){ + char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING"); + int useProxy = 0; + + /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means + ** never use proxy, NULL means use proxy for non-local files only. */ + if( envforce!=NULL ){ + useProxy = atoi(envforce)>0; + }else{ + useProxy = !(fsInfo.f_flags&MNT_LOCAL); + } + if( useProxy ){ + rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); + if( rc==SQLITE_OK ){ + rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); + if( rc!=SQLITE_OK ){ + /* Use unixClose to clean up the resources added in fillInUnixFile + ** and clear all the structure's references. Specifically, + ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op + */ + unixClose(pFile); + return rc; + } + } + goto open_finished; + } + } +#endif + + rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); + +open_finished: + if( rc!=SQLITE_OK ){ + sqlite3_free(p->pUnused); + } + return rc; +} + + +/* +** Delete the file at zPath. If the dirSync argument is true, fsync() +** the directory after deleting the file. +*/ +static int unixDelete( + sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */ + const char *zPath, /* Name of file to be deleted */ + int dirSync /* If true, fsync() directory after deleting file */ +){ + int rc = SQLITE_OK; + UNUSED_PARAMETER(NotUsed); + SimulateIOError(return SQLITE_IOERR_DELETE); + if( osUnlink(zPath)==(-1) ){ + if( errno==ENOENT +#if OS_VXWORKS + || osAccess(zPath,0)!=0 +#endif + ){ + rc = SQLITE_IOERR_DELETE_NOENT; + }else{ + rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); + } + return rc; + } +#ifndef SQLITE_DISABLE_DIRSYNC + if( (dirSync & 1)!=0 ){ + int fd; + rc = osOpenDirectory(zPath, &fd); + if( rc==SQLITE_OK ){ + if( full_fsync(fd,0,0) ){ + rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); + } + robust_close(0, fd, __LINE__); + }else{ + assert( rc==SQLITE_CANTOPEN ); + rc = SQLITE_OK; + } + } +#endif + return rc; +} + +/* +** Test the existence of or access permissions of file zPath. The +** test performed depends on the value of flags: +** +** SQLITE_ACCESS_EXISTS: Return 1 if the file exists +** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. +** SQLITE_ACCESS_READONLY: Return 1 if the file is readable. +** +** Otherwise return 0. +*/ +static int unixAccess( + sqlite3_vfs *NotUsed, /* The VFS containing this xAccess method */ + const char *zPath, /* Path of the file to examine */ + int flags, /* What do we want to learn about the zPath file? */ + int *pResOut /* Write result boolean here */ +){ + UNUSED_PARAMETER(NotUsed); + SimulateIOError( return SQLITE_IOERR_ACCESS; ); + assert( pResOut!=0 ); + + /* The spec says there are three possible values for flags. But only + ** two of them are actually used */ + assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE ); + + if( flags==SQLITE_ACCESS_EXISTS ){ + struct stat buf; + *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0); + }else{ + *pResOut = osAccess(zPath, W_OK|R_OK)==0; + } + return SQLITE_OK; +} + +/* +** +*/ +static int mkFullPathname( + const char *zPath, /* Input path */ + char *zOut, /* Output buffer */ + int nOut /* Allocated size of buffer zOut */ +){ + int nPath = sqlite3Strlen30(zPath); + int iOff = 0; + if( zPath[0]!='/' ){ + if( osGetcwd(zOut, nOut-2)==0 ){ + return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); + } + iOff = sqlite3Strlen30(zOut); + zOut[iOff++] = '/'; + } + if( (iOff+nPath+1)>nOut ){ + /* SQLite assumes that xFullPathname() nul-terminates the output buffer + ** even if it returns an error. */ + zOut[iOff] = '\0'; + return SQLITE_CANTOPEN_BKPT; + } + sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + return SQLITE_OK; +} + +/* +** Turn a relative pathname into a full pathname. The relative path +** is stored as a nul-terminated string in the buffer pointed to by +** zPath. +** +** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes +** (in this case, MAX_PATHNAME bytes). The full-path is written to +** this buffer before returning. +*/ +static int unixFullPathname( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + const char *zPath, /* Possibly relative input path */ + int nOut, /* Size of output buffer in bytes */ + char *zOut /* Output buffer */ +){ +#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) + return mkFullPathname(zPath, zOut, nOut); +#else + int rc = SQLITE_OK; + int nByte; + int nLink = 1; /* Number of symbolic links followed so far */ + const char *zIn = zPath; /* Input path for each iteration of loop */ + char *zDel = 0; + + assert( pVfs->mxPathname==MAX_PATHNAME ); + UNUSED_PARAMETER(pVfs); + + /* It's odd to simulate an io-error here, but really this is just + ** using the io-error infrastructure to test that SQLite handles this + ** function failing. This function could fail if, for example, the + ** current working directory has been unlinked. + */ + SimulateIOError( return SQLITE_ERROR ); + + do { + + /* Call stat() on path zIn. Set bLink to true if the path is a symbolic + ** link, or false otherwise. */ + int bLink = 0; + struct stat buf; + if( osLstat(zIn, &buf)!=0 ){ + if( errno!=ENOENT ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); + } + }else{ + bLink = S_ISLNK(buf.st_mode); + } + + if( bLink ){ + if( zDel==0 ){ + zDel = sqlite3_malloc(nOut); + if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; + }else if( ++nLink>SQLITE_MAX_SYMLINKS ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + if( rc==SQLITE_OK ){ + nByte = osReadlink(zIn, zDel, nOut-1); + if( nByte<0 ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); + }else{ + if( zDel[0]!='/' ){ + int n; + for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); + if( nByte+n+1>nOut ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + memmove(&zDel[n], zDel, nByte+1); + memcpy(zDel, zIn, n); + nByte += n; + } + } + zDel[nByte] = '\0'; + } + } + + zIn = zDel; + } + + assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); + if( rc==SQLITE_OK && zIn!=zOut ){ + rc = mkFullPathname(zIn, zOut, nOut); + } + if( bLink==0 ) break; + zIn = zOut; + }while( rc==SQLITE_OK ); + + sqlite3_free(zDel); + return rc; +#endif /* HAVE_READLINK && HAVE_LSTAT */ +} + + +#ifndef SQLITE_OMIT_LOAD_EXTENSION +/* +** Interfaces for opening a shared library, finding entry points +** within the shared library, and closing the shared library. +*/ +#include +static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){ + UNUSED_PARAMETER(NotUsed); + return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL); +} + +/* +** SQLite calls this function immediately after a call to unixDlSym() or +** unixDlOpen() fails (returns a null pointer). If a more detailed error +** message is available, it is written to zBufOut. If no error message +** is available, zBufOut is left unmodified and SQLite uses a default +** error message. +*/ +static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){ + const char *zErr; + UNUSED_PARAMETER(NotUsed); + unixEnterMutex(); + zErr = dlerror(); + if( zErr ){ + sqlite3_snprintf(nBuf, zBufOut, "%s", zErr); + } + unixLeaveMutex(); +} +static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){ + /* + ** GCC with -pedantic-errors says that C90 does not allow a void* to be + ** cast into a pointer to a function. And yet the library dlsym() routine + ** returns a void* which is really a pointer to a function. So how do we + ** use dlsym() with -pedantic-errors? + ** + ** Variable x below is defined to be a pointer to a function taking + ** parameters void* and const char* and returning a pointer to a function. + ** We initialize x by assigning it a pointer to the dlsym() function. + ** (That assignment requires a cast.) Then we call the function that + ** x points to. + ** + ** This work-around is unlikely to work correctly on any system where + ** you really cannot cast a function pointer into void*. But then, on the + ** other hand, dlsym() will not work on such a system either, so we have + ** not really lost anything. + */ + void (*(*x)(void*,const char*))(void); + UNUSED_PARAMETER(NotUsed); + x = (void(*(*)(void*,const char*))(void))dlsym; + return (*x)(p, zSym); +} +static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){ + UNUSED_PARAMETER(NotUsed); + dlclose(pHandle); +} +#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ + #define unixDlOpen 0 + #define unixDlError 0 + #define unixDlSym 0 + #define unixDlClose 0 +#endif + +/* +** Write nBuf bytes of random data to the supplied buffer zBuf. +*/ +static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){ + UNUSED_PARAMETER(NotUsed); + assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int))); + + /* We have to initialize zBuf to prevent valgrind from reporting + ** errors. The reports issued by valgrind are incorrect - we would + ** prefer that the randomness be increased by making use of the + ** uninitialized space in zBuf - but valgrind errors tend to worry + ** some users. Rather than argue, it seems easier just to initialize + ** the whole array and silence valgrind, even if that means less randomness + ** in the random seed. + ** + ** When testing, initializing zBuf[] to zero is all we do. That means + ** that we always use the same random number sequence. This makes the + ** tests repeatable. + */ + memset(zBuf, 0, nBuf); + randomnessPid = osGetpid(0); +#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) + { + int fd, got; + fd = robust_open("/dev/urandom", O_RDONLY, 0); + if( fd<0 ){ + time_t t; + time(&t); + memcpy(zBuf, &t, sizeof(t)); + memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); + assert( sizeof(t)+sizeof(randomnessPid)<=(size_t)nBuf ); + nBuf = sizeof(t) + sizeof(randomnessPid); + }else{ + do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR ); + robust_close(0, fd, __LINE__); + } + } +#endif + return nBuf; +} + + +/* +** Sleep for a little while. Return the amount of time slept. +** The argument is the number of microseconds we want to sleep. +** The return value is the number of microseconds of sleep actually +** requested from the underlying operating system, a number which +** might be greater than or equal to the argument, but not less +** than the argument. +*/ +static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ +#if OS_VXWORKS + struct timespec sp; + + sp.tv_sec = microseconds / 1000000; + sp.tv_nsec = (microseconds % 1000000) * 1000; + nanosleep(&sp, NULL); + UNUSED_PARAMETER(NotUsed); + return microseconds; +#elif defined(HAVE_USLEEP) && HAVE_USLEEP + usleep(microseconds); + UNUSED_PARAMETER(NotUsed); + return microseconds; +#else + int seconds = (microseconds+999999)/1000000; + sleep(seconds); + UNUSED_PARAMETER(NotUsed); + return seconds*1000000; +#endif +} + +/* +** The following variable, if set to a non-zero value, is interpreted as +** the number of seconds since 1970 and is used to set the result of +** sqlite3OsCurrentTime() during testing. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ +#endif + +/* +** Find the current time (in Universal Coordinated Time). Write into *piNow +** the current time and date as a Julian Day number times 86_400_000. In +** other words, write into *piNow the number of milliseconds since the Julian +** epoch of noon in Greenwich on November 24, 4714 B.C according to the +** proleptic Gregorian calendar. +** +** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date +** cannot be found. +*/ +static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ + static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; + int rc = SQLITE_OK; +#if defined(NO_GETTOD) + time_t t; + time(&t); + *piNow = ((sqlite3_int64)t)*1000 + unixEpoch; +#elif OS_VXWORKS + struct timespec sNow; + clock_gettime(CLOCK_REALTIME, &sNow); + *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000; +#else + struct timeval sNow; + (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */ + *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; +#endif + +#ifdef SQLITE_TEST + if( sqlite3_current_time ){ + *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; + } +#endif + UNUSED_PARAMETER(NotUsed); + return rc; +} + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** Find the current time (in Universal Coordinated Time). Write the +** current time and date as a Julian Day number into *prNow and +** return 0. Return 1 if the time and date cannot be found. +*/ +static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){ + sqlite3_int64 i = 0; + int rc; + UNUSED_PARAMETER(NotUsed); + rc = unixCurrentTimeInt64(0, &i); + *prNow = i/86400000.0; + return rc; +} +#else +# define unixCurrentTime 0 +#endif + +/* +** The xGetLastError() method is designed to return a better +** low-level error message when operating-system problems come up +** during SQLite operation. Only the integer return code is currently +** used. +*/ +static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ + UNUSED_PARAMETER(NotUsed); + UNUSED_PARAMETER(NotUsed2); + UNUSED_PARAMETER(NotUsed3); + return errno; +} + + +/* +************************ End of sqlite3_vfs methods *************************** +******************************************************************************/ + +/****************************************************************************** +************************** Begin Proxy Locking ******************************** +** +** Proxy locking is a "uber-locking-method" in this sense: It uses the +** other locking methods on secondary lock files. Proxy locking is a +** meta-layer over top of the primitive locking implemented above. For +** this reason, the division that implements of proxy locking is deferred +** until late in the file (here) after all of the other I/O methods have +** been defined - so that the primitive locking methods are available +** as services to help with the implementation of proxy locking. +** +**** +** +** The default locking schemes in SQLite use byte-range locks on the +** database file to coordinate safe, concurrent access by multiple readers +** and writers [http://sqlite.org/lockingv3.html]. The five file locking +** states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented +** as POSIX read & write locks over fixed set of locations (via fsctl), +** on AFP and SMB only exclusive byte-range locks are available via fsctl +** with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states. +** To simulate a F_RDLCK on the shared range, on AFP a randomly selected +** address in the shared range is taken for a SHARED lock, the entire +** shared range is taken for an EXCLUSIVE lock): +** +** PENDING_BYTE 0x40000000 +** RESERVED_BYTE 0x40000001 +** SHARED_RANGE 0x40000002 -> 0x40000200 +** +** This works well on the local file system, but shows a nearly 100x +** slowdown in read performance on AFP because the AFP client disables +** the read cache when byte-range locks are present. Enabling the read +** cache exposes a cache coherency problem that is present on all OS X +** supported network file systems. NFS and AFP both observe the +** close-to-open semantics for ensuring cache coherency +** [http://nfs.sourceforge.net/#faq_a8], which does not effectively +** address the requirements for concurrent database access by multiple +** readers and writers +** [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html]. +** +** To address the performance and cache coherency issues, proxy file locking +** changes the way database access is controlled by limiting access to a +** single host at a time and moving file locks off of the database file +** and onto a proxy file on the local file system. +** +** +** Using proxy locks +** ----------------- +** +** C APIs +** +** sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE, +** | ":auto:"); +** sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE, +** &); +** +** +** SQL pragmas +** +** PRAGMA [database.]lock_proxy_file= | :auto: +** PRAGMA [database.]lock_proxy_file +** +** Specifying ":auto:" means that if there is a conch file with a matching +** host ID in it, the proxy path in the conch file will be used, otherwise +** a proxy path based on the user's temp dir +** (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the +** actual proxy file name is generated from the name and path of the +** database file. For example: +** +** For database path "/Users/me/foo.db" +** The lock path will be "/sqliteplocks/_Users_me_foo.db:auto:") +** +** Once a lock proxy is configured for a database connection, it can not +** be removed, however it may be switched to a different proxy path via +** the above APIs (assuming the conch file is not being held by another +** connection or process). +** +** +** How proxy locking works +** ----------------------- +** +** Proxy file locking relies primarily on two new supporting files: +** +** * conch file to limit access to the database file to a single host +** at a time +** +** * proxy file to act as a proxy for the advisory locks normally +** taken on the database +** +** The conch file - to use a proxy file, sqlite must first "hold the conch" +** by taking an sqlite-style shared lock on the conch file, reading the +** contents and comparing the host's unique host ID (see below) and lock +** proxy path against the values stored in the conch. The conch file is +** stored in the same directory as the database file and the file name +** is patterned after the database file name as ".-conch". +** If the conch file does not exist, or its contents do not match the +** host ID and/or proxy path, then the lock is escalated to an exclusive +** lock and the conch file contents is updated with the host ID and proxy +** path and the lock is downgraded to a shared lock again. If the conch +** is held by another process (with a shared lock), the exclusive lock +** will fail and SQLITE_BUSY is returned. +** +** The proxy file - a single-byte file used for all advisory file locks +** normally taken on the database file. This allows for safe sharing +** of the database file for multiple readers and writers on the same +** host (the conch ensures that they all use the same local lock file). +** +** Requesting the lock proxy does not immediately take the conch, it is +** only taken when the first request to lock database file is made. +** This matches the semantics of the traditional locking behavior, where +** opening a connection to a database file does not take a lock on it. +** The shared lock and an open file descriptor are maintained until +** the connection to the database is closed. +** +** The proxy file and the lock file are never deleted so they only need +** to be created the first time they are used. +** +** Configuration options +** --------------------- +** +** SQLITE_PREFER_PROXY_LOCKING +** +** Database files accessed on non-local file systems are +** automatically configured for proxy locking, lock files are +** named automatically using the same logic as +** PRAGMA lock_proxy_file=":auto:" +** +** SQLITE_PROXY_DEBUG +** +** Enables the logging of error messages during host id file +** retrieval and creation +** +** LOCKPROXYDIR +** +** Overrides the default directory used for lock proxy files that +** are named automatically via the ":auto:" setting +** +** SQLITE_DEFAULT_PROXYDIR_PERMISSIONS +** +** Permissions to use when creating a directory for storing the +** lock proxy files, only used when LOCKPROXYDIR is not set. +** +** +** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING, +** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will +** force proxy locking to be used for every database file opened, and 0 +** will force automatic proxy locking to be disabled for all database +** files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or +** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). +*/ + +/* +** Proxy locking is only available on MacOSX +*/ +#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE + +/* +** The proxyLockingContext has the path and file structures for the remote +** and local proxy files in it +*/ +typedef struct proxyLockingContext proxyLockingContext; +struct proxyLockingContext { + unixFile *conchFile; /* Open conch file */ + char *conchFilePath; /* Name of the conch file */ + unixFile *lockProxy; /* Open proxy lock file */ + char *lockProxyPath; /* Name of the proxy lock file */ + char *dbPath; /* Name of the open file */ + int conchHeld; /* 1 if the conch is held, -1 if lockless */ + int nFails; /* Number of conch taking failures */ + void *oldLockingContext; /* Original lockingcontext to restore on close */ + sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */ +}; + +/* +** The proxy lock file path for the database at dbPath is written into lPath, +** which must point to valid, writable memory large enough for a maxLen length +** file path. +*/ +static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ + int len; + int dbLen; + int i; + +#ifdef LOCKPROXYDIR + len = strlcpy(lPath, LOCKPROXYDIR, maxLen); +#else +# ifdef _CS_DARWIN_USER_TEMP_DIR + { + if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ + OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", + lPath, errno, osGetpid(0))); + return SQLITE_IOERR_LOCK; + } + len = strlcat(lPath, "sqliteplocks", maxLen); + } +# else + len = strlcpy(lPath, "/tmp/", maxLen); +# endif +#endif + + if( lPath[len-1]!='/' ){ + len = strlcat(lPath, "/", maxLen); + } + + /* transform the db path to a unique cache name */ + dbLen = (int)strlen(dbPath); + for( i=0; i 0) ){ + /* only mkdir if leaf dir != "." or "/" or ".." */ + if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/') + || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){ + buf[i]='\0'; + if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ + int err=errno; + if( err!=EEXIST ) { + OSTRACE(("CREATELOCKPATH FAILED creating %s, " + "'%s' proxy lock path=%s pid=%d\n", + buf, strerror(err), lockPath, osGetpid(0))); + return err; + } + } + } + start=i+1; + } + buf[i] = lockPath[i]; + } + OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n",lockPath,osGetpid(0))); + return 0; +} + +/* +** Create a new VFS file descriptor (stored in memory obtained from +** sqlite3_malloc) and open the file named "path" in the file descriptor. +** +** The caller is responsible not only for closing the file descriptor +** but also for freeing the memory associated with the file descriptor. +*/ +static int proxyCreateUnixFile( + const char *path, /* path for the new unixFile */ + unixFile **ppFile, /* unixFile created and returned by ref */ + int islockfile /* if non zero missing dirs will be created */ +) { + int fd = -1; + unixFile *pNew; + int rc = SQLITE_OK; + int openFlags = O_RDWR | O_CREAT; + sqlite3_vfs dummyVfs; + int terrno = 0; + UnixUnusedFd *pUnused = NULL; + + /* 1. first try to open/create the file + ** 2. if that fails, and this is a lock file (not-conch), try creating + ** the parent directories and then try again. + ** 3. if that fails, try to open the file read-only + ** otherwise return BUSY (if lock file) or CANTOPEN for the conch file + */ + pUnused = findReusableFd(path, openFlags); + if( pUnused ){ + fd = pUnused->fd; + }else{ + pUnused = sqlite3_malloc64(sizeof(*pUnused)); + if( !pUnused ){ + return SQLITE_NOMEM_BKPT; + } + } + if( fd<0 ){ + fd = robust_open(path, openFlags, 0); + terrno = errno; + if( fd<0 && errno==ENOENT && islockfile ){ + if( proxyCreateLockPath(path) == SQLITE_OK ){ + fd = robust_open(path, openFlags, 0); + } + } + } + if( fd<0 ){ + openFlags = O_RDONLY; + fd = robust_open(path, openFlags, 0); + terrno = errno; + } + if( fd<0 ){ + if( islockfile ){ + return SQLITE_BUSY; + } + switch (terrno) { + case EACCES: + return SQLITE_PERM; + case EIO: + return SQLITE_IOERR_LOCK; /* even though it is the conch */ + default: + return SQLITE_CANTOPEN_BKPT; + } + } + + pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew)); + if( pNew==NULL ){ + rc = SQLITE_NOMEM_BKPT; + goto end_create_proxy; + } + memset(pNew, 0, sizeof(unixFile)); + pNew->openFlags = openFlags; + memset(&dummyVfs, 0, sizeof(dummyVfs)); + dummyVfs.pAppData = (void*)&autolockIoFinder; + dummyVfs.zName = "dummy"; + pUnused->fd = fd; + pUnused->flags = openFlags; + pNew->pUnused = pUnused; + + rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); + if( rc==SQLITE_OK ){ + *ppFile = pNew; + return SQLITE_OK; + } +end_create_proxy: + robust_close(pNew, fd, __LINE__); + sqlite3_free(pNew); + sqlite3_free(pUnused); + return rc; +} + +#ifdef SQLITE_TEST +/* simulate multiple hosts by creating unique hostid file paths */ +SQLITE_API int sqlite3_hostid_num = 0; +#endif + +#define PROXY_HOSTIDLEN 16 /* conch file host id length */ + +#ifdef HAVE_GETHOSTUUID +/* Not always defined in the headers as it ought to be */ +extern int gethostuuid(uuid_t id, const struct timespec *wait); +#endif + +/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN +** bytes of writable memory. +*/ +static int proxyGetHostID(unsigned char *pHostID, int *pError){ + assert(PROXY_HOSTIDLEN == sizeof(uuid_t)); + memset(pHostID, 0, PROXY_HOSTIDLEN); +#ifdef HAVE_GETHOSTUUID + { + struct timespec timeout = {1, 0}; /* 1 sec timeout */ + if( gethostuuid(pHostID, &timeout) ){ + int err = errno; + if( pError ){ + *pError = err; + } + return SQLITE_IOERR; + } + } +#else + UNUSED_PARAMETER(pError); +#endif +#ifdef SQLITE_TEST + /* simulate multiple hosts by creating unique hostid file paths */ + if( sqlite3_hostid_num != 0){ + pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF)); + } +#endif + + return SQLITE_OK; +} + +/* The conch file contains the header, host id and lock file path + */ +#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */ +#define PROXY_HEADERLEN 1 /* conch file header length */ +#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN) +#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN) + +/* +** Takes an open conch file, copies the contents to a new path and then moves +** it back. The newly created file's file descriptor is assigned to the +** conch file structure and finally the original conch file descriptor is +** closed. Returns zero if successful. +*/ +static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + unixFile *conchFile = pCtx->conchFile; + char tPath[MAXPATHLEN]; + char buf[PROXY_MAXCONCHLEN]; + char *cPath = pCtx->conchFilePath; + size_t readLen = 0; + size_t pathLen = 0; + char errmsg[64] = ""; + int fd = -1; + int rc = -1; + UNUSED_PARAMETER(myHostID); + + /* create a new path by replace the trailing '-conch' with '-break' */ + pathLen = strlcpy(tPath, cPath, MAXPATHLEN); + if( pathLen>MAXPATHLEN || pathLen<6 || + (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){ + sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen); + goto end_breaklock; + } + /* read the conch content */ + readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0); + if( readLenh, __LINE__); + conchFile->h = fd; + conchFile->openFlags = O_RDWR | O_CREAT; + +end_breaklock: + if( rc ){ + if( fd>=0 ){ + osUnlink(tPath); + robust_close(pFile, fd, __LINE__); + } + fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg); + } + return rc; +} + +/* Take the requested lock on the conch file and break a stale lock if the +** host id matches. +*/ +static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + unixFile *conchFile = pCtx->conchFile; + int rc = SQLITE_OK; + int nTries = 0; + struct timespec conchModTime; + + memset(&conchModTime, 0, sizeof(conchModTime)); + do { + rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); + nTries ++; + if( rc==SQLITE_BUSY ){ + /* If the lock failed (busy): + * 1st try: get the mod time of the conch, wait 0.5s and try again. + * 2nd try: fail if the mod time changed or host id is different, wait + * 10 sec and try again + * 3rd try: break the lock unless the mod time has changed. + */ + struct stat buf; + if( osFstat(conchFile->h, &buf) ){ + storeLastErrno(pFile, errno); + return SQLITE_IOERR_LOCK; + } + + if( nTries==1 ){ + conchModTime = buf.st_mtimespec; + usleep(500000); /* wait 0.5 sec and try the lock again*/ + continue; + } + + assert( nTries>1 ); + if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || + conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){ + return SQLITE_BUSY; + } + + if( nTries==2 ){ + char tBuf[PROXY_MAXCONCHLEN]; + int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); + if( len<0 ){ + storeLastErrno(pFile, errno); + return SQLITE_IOERR_LOCK; + } + if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ + /* don't break the lock if the host id doesn't match */ + if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){ + return SQLITE_BUSY; + } + }else{ + /* don't break the lock on short read or a version mismatch */ + return SQLITE_BUSY; + } + usleep(10000000); /* wait 10 sec and try the lock again */ + continue; + } + + assert( nTries==3 ); + if( 0==proxyBreakConchLock(pFile, myHostID) ){ + rc = SQLITE_OK; + if( lockType==EXCLUSIVE_LOCK ){ + rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK); + } + if( !rc ){ + rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); + } + } + } + } while( rc==SQLITE_BUSY && nTries<3 ); + + return rc; +} + +/* Takes the conch by taking a shared lock and read the contents conch, if +** lockPath is non-NULL, the host ID and lock file path must match. A NULL +** lockPath means that the lockPath in the conch file will be used if the +** host IDs match, or a new lock path will be generated automatically +** and written to the conch file. +*/ +static int proxyTakeConch(unixFile *pFile){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + + if( pCtx->conchHeld!=0 ){ + return SQLITE_OK; + }else{ + unixFile *conchFile = pCtx->conchFile; + uuid_t myHostID; + int pError = 0; + char readBuf[PROXY_MAXCONCHLEN]; + char lockPath[MAXPATHLEN]; + char *tempLockPath = NULL; + int rc = SQLITE_OK; + int createConch = 0; + int hostIdMatch = 0; + int readLen = 0; + int tryOldLockPath = 0; + int forceNewLockPath = 0; + + OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, + (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), + osGetpid(0))); + + rc = proxyGetHostID(myHostID, &pError); + if( (rc&0xff)==SQLITE_IOERR ){ + storeLastErrno(pFile, pError); + goto end_takeconch; + } + rc = proxyConchLock(pFile, myHostID, SHARED_LOCK); + if( rc!=SQLITE_OK ){ + goto end_takeconch; + } + /* read the existing conch file */ + readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN); + if( readLen<0 ){ + /* I/O error: lastErrno set by seekAndRead */ + storeLastErrno(pFile, conchFile->lastErrno); + rc = SQLITE_IOERR_READ; + goto end_takeconch; + }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || + readBuf[0]!=(char)PROXY_CONCHVERSION ){ + /* a short read or version format mismatch means we need to create a new + ** conch file. + */ + createConch = 1; + } + /* if the host id matches and the lock path already exists in the conch + ** we'll try to use the path there, if we can't open that path, we'll + ** retry with a new auto-generated path + */ + do { /* in case we need to try again for an :auto: named lock file */ + + if( !createConch && !forceNewLockPath ){ + hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID, + PROXY_HOSTIDLEN); + /* if the conch has data compare the contents */ + if( !pCtx->lockProxyPath ){ + /* for auto-named local lock file, just check the host ID and we'll + ** use the local lock file path that's already in there + */ + if( hostIdMatch ){ + size_t pathLen = (readLen - PROXY_PATHINDEX); + + if( pathLen>=MAXPATHLEN ){ + pathLen=MAXPATHLEN-1; + } + memcpy(lockPath, &readBuf[PROXY_PATHINDEX], pathLen); + lockPath[pathLen] = 0; + tempLockPath = lockPath; + tryOldLockPath = 1; + /* create a copy of the lock path if the conch is taken */ + goto end_takeconch; + } + }else if( hostIdMatch + && !strncmp(pCtx->lockProxyPath, &readBuf[PROXY_PATHINDEX], + readLen-PROXY_PATHINDEX) + ){ + /* conch host and lock path match */ + goto end_takeconch; + } + } + + /* if the conch isn't writable and doesn't match, we can't take it */ + if( (conchFile->openFlags&O_RDWR) == 0 ){ + rc = SQLITE_BUSY; + goto end_takeconch; + } + + /* either the conch didn't match or we need to create a new one */ + if( !pCtx->lockProxyPath ){ + proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN); + tempLockPath = lockPath; + /* create a copy of the lock path _only_ if the conch is taken */ + } + + /* update conch with host and path (this will fail if other process + ** has a shared lock already), if the host id matches, use the big + ** stick. + */ + futimes(conchFile->h, NULL); + if( hostIdMatch && !createConch ){ + if( conchFile->pInode && conchFile->pInode->nShared>1 ){ + /* We are trying for an exclusive lock but another thread in this + ** same process is still holding a shared lock. */ + rc = SQLITE_BUSY; + } else { + rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); + } + }else{ + rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); + } + if( rc==SQLITE_OK ){ + char writeBuffer[PROXY_MAXCONCHLEN]; + int writeSize = 0; + + writeBuffer[0] = (char)PROXY_CONCHVERSION; + memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); + if( pCtx->lockProxyPath!=NULL ){ + strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, + MAXPATHLEN); + }else{ + strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN); + } + writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]); + robust_ftruncate(conchFile->h, writeSize); + rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0); + full_fsync(conchFile->h,0,0); + /* If we created a new conch file (not just updated the contents of a + ** valid conch file), try to match the permissions of the database + */ + if( rc==SQLITE_OK && createConch ){ + struct stat buf; + int err = osFstat(pFile->h, &buf); + if( err==0 ){ + mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | + S_IROTH|S_IWOTH); + /* try to match the database file R/W permissions, ignore failure */ +#ifndef SQLITE_PROXY_DEBUG + osFchmod(conchFile->h, cmode); +#else + do{ + rc = osFchmod(conchFile->h, cmode); + }while( rc==(-1) && errno==EINTR ); + if( rc!=0 ){ + int code = errno; + fprintf(stderr, "fchmod %o FAILED with %d %s\n", + cmode, code, strerror(code)); + } else { + fprintf(stderr, "fchmod %o SUCCEDED\n",cmode); + } + }else{ + int code = errno; + fprintf(stderr, "STAT FAILED[%d] with %d %s\n", + err, code, strerror(code)); +#endif + } + } + } + conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK); + + end_takeconch: + OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); + if( rc==SQLITE_OK && pFile->openFlags ){ + int fd; + if( pFile->h>=0 ){ + robust_close(pFile, pFile->h, __LINE__); + } + pFile->h = -1; + fd = robust_open(pCtx->dbPath, pFile->openFlags, 0); + OSTRACE(("TRANSPROXY: OPEN %d\n", fd)); + if( fd>=0 ){ + pFile->h = fd; + }else{ + rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called + during locking */ + } + } + if( rc==SQLITE_OK && !pCtx->lockProxy ){ + char *path = tempLockPath ? tempLockPath : pCtx->lockProxyPath; + rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1); + if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){ + /* we couldn't create the proxy lock file with the old lock file path + ** so try again via auto-naming + */ + forceNewLockPath = 1; + tryOldLockPath = 0; + continue; /* go back to the do {} while start point, try again */ + } + } + if( rc==SQLITE_OK ){ + /* Need to make a copy of path if we extracted the value + ** from the conch file or the path was allocated on the stack + */ + if( tempLockPath ){ + pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath); + if( !pCtx->lockProxyPath ){ + rc = SQLITE_NOMEM_BKPT; + } + } + } + if( rc==SQLITE_OK ){ + pCtx->conchHeld = 1; + + if( pCtx->lockProxy->pMethod == &afpIoMethods ){ + afpLockingContext *afpCtx; + afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext; + afpCtx->dbPath = pCtx->lockProxyPath; + } + } else { + conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); + } + OSTRACE(("TAKECONCH %d %s\n", conchFile->h, + rc==SQLITE_OK?"ok":"failed")); + return rc; + } while (1); /* in case we need to retry the :auto: lock file - + ** we should never get here except via the 'continue' call. */ + } +} + +/* +** If pFile holds a lock on a conch file, then release that lock. +*/ +static int proxyReleaseConch(unixFile *pFile){ + int rc = SQLITE_OK; /* Subroutine return code */ + proxyLockingContext *pCtx; /* The locking context for the proxy lock */ + unixFile *conchFile; /* Name of the conch file */ + + pCtx = (proxyLockingContext *)pFile->lockingContext; + conchFile = pCtx->conchFile; + OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, + (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), + osGetpid(0))); + if( pCtx->conchHeld>0 ){ + rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); + } + pCtx->conchHeld = 0; + OSTRACE(("RELEASECONCH %d %s\n", conchFile->h, + (rc==SQLITE_OK ? "ok" : "failed"))); + return rc; +} + +/* +** Given the name of a database file, compute the name of its conch file. +** Store the conch filename in memory obtained from sqlite3_malloc64(). +** Make *pConchPath point to the new name. Return SQLITE_OK on success +** or SQLITE_NOMEM if unable to obtain memory. +** +** The caller is responsible for ensuring that the allocated memory +** space is eventually freed. +** +** *pConchPath is set to NULL if a memory allocation error occurs. +*/ +static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ + int i; /* Loop counter */ + int len = (int)strlen(dbPath); /* Length of database filename - dbPath */ + char *conchPath; /* buffer in which to construct conch name */ + + /* Allocate space for the conch filename and initialize the name to + ** the name of the original database file. */ + *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8); + if( conchPath==0 ){ + return SQLITE_NOMEM_BKPT; + } + memcpy(conchPath, dbPath, len+1); + + /* now insert a "." before the last / character */ + for( i=(len-1); i>=0; i-- ){ + if( conchPath[i]=='/' ){ + i++; + break; + } + } + conchPath[i]='.'; + while ( ilockingContext; + char *oldPath = pCtx->lockProxyPath; + int rc = SQLITE_OK; + + if( pFile->eFileLock!=NO_LOCK ){ + return SQLITE_BUSY; + } + + /* nothing to do if the path is NULL, :auto: or matches the existing path */ + if( !path || path[0]=='\0' || !strcmp(path, ":auto:") || + (oldPath && !strncmp(oldPath, path, MAXPATHLEN)) ){ + return SQLITE_OK; + }else{ + unixFile *lockProxy = pCtx->lockProxy; + pCtx->lockProxy=NULL; + pCtx->conchHeld = 0; + if( lockProxy!=NULL ){ + rc=lockProxy->pMethod->xClose((sqlite3_file *)lockProxy); + if( rc ) return rc; + sqlite3_free(lockProxy); + } + sqlite3_free(oldPath); + pCtx->lockProxyPath = sqlite3DbStrDup(0, path); + } + + return rc; +} + +/* +** pFile is a file that has been opened by a prior xOpen call. dbPath +** is a string buffer at least MAXPATHLEN+1 characters in size. +** +** This routine find the filename associated with pFile and writes it +** int dbPath. +*/ +static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ +#if defined(__APPLE__) + if( pFile->pMethod == &afpIoMethods ){ + /* afp style keeps a reference to the db path in the filePath field + ** of the struct */ + assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); + strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, + MAXPATHLEN); + } else +#endif + if( pFile->pMethod == &dotlockIoMethods ){ + /* dot lock style uses the locking context to store the dot lock + ** file path */ + int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX); + memcpy(dbPath, (char *)pFile->lockingContext, len + 1); + }else{ + /* all other styles use the locking context to store the db file path */ + assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); + strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN); + } + return SQLITE_OK; +} + +/* +** Takes an already filled in unix file and alters it so all file locking +** will be performed on the local proxy lock file. The following fields +** are preserved in the locking context so that they can be restored and +** the unix structure properly cleaned up at close time: +** ->lockingContext +** ->pMethod +*/ +static int proxyTransformUnixFile(unixFile *pFile, const char *path) { + proxyLockingContext *pCtx; + char dbPath[MAXPATHLEN+1]; /* Name of the database file */ + char *lockPath=NULL; + int rc = SQLITE_OK; + + if( pFile->eFileLock!=NO_LOCK ){ + return SQLITE_BUSY; + } + proxyGetDbPathForUnixFile(pFile, dbPath); + if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){ + lockPath=NULL; + }else{ + lockPath=(char *)path; + } + + OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, + (lockPath ? lockPath : ":auto:"), osGetpid(0))); + + pCtx = sqlite3_malloc64( sizeof(*pCtx) ); + if( pCtx==0 ){ + return SQLITE_NOMEM_BKPT; + } + memset(pCtx, 0, sizeof(*pCtx)); + + rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath); + if( rc==SQLITE_OK ){ + rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile, 0); + if( rc==SQLITE_CANTOPEN && ((pFile->openFlags&O_RDWR) == 0) ){ + /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and + ** (c) the file system is read-only, then enable no-locking access. + ** Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts + ** that openFlags will have only one of O_RDONLY or O_RDWR. + */ + struct statfs fsInfo; + struct stat conchInfo; + int goLockless = 0; + + if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) { + int err = errno; + if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){ + goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY; + } + } + if( goLockless ){ + pCtx->conchHeld = -1; /* read only FS/ lockless */ + rc = SQLITE_OK; + } + } + } + if( rc==SQLITE_OK && lockPath ){ + pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath); + } + + if( rc==SQLITE_OK ){ + pCtx->dbPath = sqlite3DbStrDup(0, dbPath); + if( pCtx->dbPath==NULL ){ + rc = SQLITE_NOMEM_BKPT; + } + } + if( rc==SQLITE_OK ){ + /* all memory is allocated, proxys are created and assigned, + ** switch the locking context and pMethod then return. + */ + pCtx->oldLockingContext = pFile->lockingContext; + pFile->lockingContext = pCtx; + pCtx->pOldMethod = pFile->pMethod; + pFile->pMethod = &proxyIoMethods; + }else{ + if( pCtx->conchFile ){ + pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile); + sqlite3_free(pCtx->conchFile); + } + sqlite3DbFree(0, pCtx->lockProxyPath); + sqlite3_free(pCtx->conchFilePath); + sqlite3_free(pCtx); + } + OSTRACE(("TRANSPROXY %d %s\n", pFile->h, + (rc==SQLITE_OK ? "ok" : "failed"))); + return rc; +} + + +/* +** This routine handles sqlite3_file_control() calls that are specific +** to proxy locking. +*/ +static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ + switch( op ){ + case SQLITE_FCNTL_GET_LOCKPROXYFILE: { + unixFile *pFile = (unixFile*)id; + if( pFile->pMethod == &proxyIoMethods ){ + proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; + proxyTakeConch(pFile); + if( pCtx->lockProxyPath ){ + *(const char **)pArg = pCtx->lockProxyPath; + }else{ + *(const char **)pArg = ":auto: (not held)"; + } + } else { + *(const char **)pArg = NULL; + } + return SQLITE_OK; + } + case SQLITE_FCNTL_SET_LOCKPROXYFILE: { + unixFile *pFile = (unixFile*)id; + int rc = SQLITE_OK; + int isProxyStyle = (pFile->pMethod == &proxyIoMethods); + if( pArg==NULL || (const char *)pArg==0 ){ + if( isProxyStyle ){ + /* turn off proxy locking - not supported. If support is added for + ** switching proxy locking mode off then it will need to fail if + ** the journal mode is WAL mode. + */ + rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/; + }else{ + /* turn off proxy locking - already off - NOOP */ + rc = SQLITE_OK; + } + }else{ + const char *proxyPath = (const char *)pArg; + if( isProxyStyle ){ + proxyLockingContext *pCtx = + (proxyLockingContext*)pFile->lockingContext; + if( !strcmp(pArg, ":auto:") + || (pCtx->lockProxyPath && + !strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN)) + ){ + rc = SQLITE_OK; + }else{ + rc = switchLockProxyPath(pFile, proxyPath); + } + }else{ + /* turn on proxy file locking */ + rc = proxyTransformUnixFile(pFile, proxyPath); + } + } + return rc; + } + default: { + assert( 0 ); /* The call assures that only valid opcodes are sent */ + } + } + /*NOTREACHED*/ + return SQLITE_ERROR; +} + +/* +** Within this division (the proxying locking implementation) the procedures +** above this point are all utilities. The lock-related methods of the +** proxy-locking sqlite3_io_method object follow. +*/ + + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, set *pResOut +** to a non-zero value otherwise *pResOut is set to zero. The return value +** is set to SQLITE_OK unless an I/O error occurs during lock checking. +*/ +static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) { + unixFile *pFile = (unixFile*)id; + int rc = proxyTakeConch(pFile); + if( rc==SQLITE_OK ){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + if( pCtx->conchHeld>0 ){ + unixFile *proxy = pCtx->lockProxy; + return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut); + }else{ /* conchHeld < 0 is lockless */ + pResOut=0; + } + } + return rc; +} + +/* +** Lock the file with the lock specified by parameter eFileLock - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. Use the sqlite3OsUnlock() +** routine to lower a locking level. +*/ +static int proxyLock(sqlite3_file *id, int eFileLock) { + unixFile *pFile = (unixFile*)id; + int rc = proxyTakeConch(pFile); + if( rc==SQLITE_OK ){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + if( pCtx->conchHeld>0 ){ + unixFile *proxy = pCtx->lockProxy; + rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock); + pFile->eFileLock = proxy->eFileLock; + }else{ + /* conchHeld < 0 is lockless */ + } + } + return rc; +} + + +/* +** Lower the locking level on file descriptor pFile to eFileLock. eFileLock +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +*/ +static int proxyUnlock(sqlite3_file *id, int eFileLock) { + unixFile *pFile = (unixFile*)id; + int rc = proxyTakeConch(pFile); + if( rc==SQLITE_OK ){ + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + if( pCtx->conchHeld>0 ){ + unixFile *proxy = pCtx->lockProxy; + rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock); + pFile->eFileLock = proxy->eFileLock; + }else{ + /* conchHeld < 0 is lockless */ + } + } + return rc; +} + +/* +** Close a file that uses proxy locks. +*/ +static int proxyClose(sqlite3_file *id) { + if( ALWAYS(id) ){ + unixFile *pFile = (unixFile*)id; + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + unixFile *lockProxy = pCtx->lockProxy; + unixFile *conchFile = pCtx->conchFile; + int rc = SQLITE_OK; + + if( lockProxy ){ + rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK); + if( rc ) return rc; + rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy); + if( rc ) return rc; + sqlite3_free(lockProxy); + pCtx->lockProxy = 0; + } + if( conchFile ){ + if( pCtx->conchHeld ){ + rc = proxyReleaseConch(pFile); + if( rc ) return rc; + } + rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile); + if( rc ) return rc; + sqlite3_free(conchFile); + } + sqlite3DbFree(0, pCtx->lockProxyPath); + sqlite3_free(pCtx->conchFilePath); + sqlite3DbFree(0, pCtx->dbPath); + /* restore the original locking context and pMethod then close it */ + pFile->lockingContext = pCtx->oldLockingContext; + pFile->pMethod = pCtx->pOldMethod; + sqlite3_free(pCtx); + return pFile->pMethod->xClose(id); + } + return SQLITE_OK; +} + + + +#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ +/* +** The proxy locking style is intended for use with AFP filesystems. +** And since AFP is only supported on MacOSX, the proxy locking is also +** restricted to MacOSX. +** +** +******************* End of the proxy lock implementation ********************** +******************************************************************************/ + +/* +** Initialize the operating system interface. +** +** This routine registers all VFS implementations for unix-like operating +** systems. This routine, and the sqlite3_os_end() routine that follows, +** should be the only routines in this file that are visible from other +** files. +** +** This routine is called once during SQLite initialization and by a +** single thread. The memory allocation and mutex subsystems have not +** necessarily been initialized when this routine is called, and so they +** should not be used. +*/ +SQLITE_API int sqlite3_os_init(void){ + /* + ** The following macro defines an initializer for an sqlite3_vfs object. + ** The name of the VFS is NAME. The pAppData is a pointer to a pointer + ** to the "finder" function. (pAppData is a pointer to a pointer because + ** silly C90 rules prohibit a void* from being cast to a function pointer + ** and so we have to go through the intermediate pointer to avoid problems + ** when compiling with -pedantic-errors on GCC.) + ** + ** The FINDER parameter to this macro is the name of the pointer to the + ** finder-function. The finder-function returns a pointer to the + ** sqlite_io_methods object that implements the desired locking + ** behaviors. See the division above that contains the IOMETHODS + ** macro for addition information on finder-functions. + ** + ** Most finders simply return a pointer to a fixed sqlite3_io_methods + ** object. But the "autolockIoFinder" available on MacOSX does a little + ** more than that; it looks at the filesystem type that hosts the + ** database file and tries to choose an locking method appropriate for + ** that filesystem time. + */ + #define UNIXVFS(VFSNAME, FINDER) { \ + 3, /* iVersion */ \ + sizeof(unixFile), /* szOsFile */ \ + MAX_PATHNAME, /* mxPathname */ \ + 0, /* pNext */ \ + VFSNAME, /* zName */ \ + (void*)&FINDER, /* pAppData */ \ + unixOpen, /* xOpen */ \ + unixDelete, /* xDelete */ \ + unixAccess, /* xAccess */ \ + unixFullPathname, /* xFullPathname */ \ + unixDlOpen, /* xDlOpen */ \ + unixDlError, /* xDlError */ \ + unixDlSym, /* xDlSym */ \ + unixDlClose, /* xDlClose */ \ + unixRandomness, /* xRandomness */ \ + unixSleep, /* xSleep */ \ + unixCurrentTime, /* xCurrentTime */ \ + unixGetLastError, /* xGetLastError */ \ + unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \ + unixSetSystemCall, /* xSetSystemCall */ \ + unixGetSystemCall, /* xGetSystemCall */ \ + unixNextSystemCall, /* xNextSystemCall */ \ + } + + /* + ** All default VFSes for unix are contained in the following array. + ** + ** Note that the sqlite3_vfs.pNext field of the VFS object is modified + ** by the SQLite core when the VFS is registered. So the following + ** array cannot be const. + */ + static sqlite3_vfs aVfs[] = { +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) + UNIXVFS("unix", autolockIoFinder ), +#elif OS_VXWORKS + UNIXVFS("unix", vxworksIoFinder ), +#else + UNIXVFS("unix", posixIoFinder ), +#endif + UNIXVFS("unix-none", nolockIoFinder ), + UNIXVFS("unix-dotfile", dotlockIoFinder ), + UNIXVFS("unix-excl", posixIoFinder ), +#if OS_VXWORKS + UNIXVFS("unix-namedsem", semIoFinder ), +#endif +#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS + UNIXVFS("unix-posix", posixIoFinder ), +#endif +#if SQLITE_ENABLE_LOCKING_STYLE + UNIXVFS("unix-flock", flockIoFinder ), +#endif +#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) + UNIXVFS("unix-afp", afpIoFinder ), + UNIXVFS("unix-nfs", nfsIoFinder ), + UNIXVFS("unix-proxy", proxyIoFinder ), +#endif + }; + unsigned int i; /* Loop counter */ + + /* Double-check that the aSyscall[] array has been constructed + ** correctly. See ticket [bb3a86e890c8e96ab] */ + assert( ArraySize(aSyscall)==28 ); + + /* Register all VFSes defined in the aVfs[] array */ + for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ + sqlite3_vfs_register(&aVfs[i], i==0); + } + return SQLITE_OK; +} + +/* +** Shutdown the operating system interface. +** +** Some operating systems might need to do some cleanup in this routine, +** to release dynamically allocated objects. But not on unix. +** This routine is a no-op for unix. +*/ +SQLITE_API int sqlite3_os_end(void){ + return SQLITE_OK; +} + +#endif /* SQLITE_OS_UNIX */ + +/************** End of os_unix.c *********************************************/ +/************** Begin file os_win.c ******************************************/ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code that is specific to Windows. +*/ +/* #include "sqliteInt.h" */ +#if SQLITE_OS_WIN /* This file is used for Windows only */ + +/* +** Include code that is common to all os_*.c files +*/ +/************** Include os_common.h in the middle of os_win.c ****************/ +/************** Begin file os_common.h ***************************************/ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains macros and a little bit of code that is common to +** all of the platform-specific files (os_*.c) and is #included into those +** files. +** +** This file should be #included by the os_*.c files only. It is not a +** general purpose header file. +*/ +#ifndef _OS_COMMON_H_ +#define _OS_COMMON_H_ + +/* +** At least two bugs have slipped in because we changed the MEMORY_DEBUG +** macro to SQLITE_DEBUG and some older makefiles have not yet made the +** switch. The following code should catch this problem at compile-time. +*/ +#ifdef MEMORY_DEBUG +# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." +#endif + +/* +** Macros for performance tracing. Normally turned off. Only works +** on i486 hardware. +*/ +#ifdef SQLITE_PERFORMANCE_TRACE + +/* +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. +*/ +/************** Include hwtime.h in the middle of os_common.h ****************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 class CPUs. +*/ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H + +/* +** The following routine only works on pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } + +#elif (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + #error Need implementation of sqlite3Hwtime() for your platform. + + /* + ** To compile without implementing sqlite3Hwtime() for your platform, + ** you can remove the above #error and use the following + ** stub function. You will lose timing support for many + ** of the debugging and testing utilities, but it should at + ** least compile and run. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in os_common.h ******************/ + +static sqlite_uint64 g_start; +static sqlite_uint64 g_elapsed; +#define TIMER_START g_start=sqlite3Hwtime() +#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start +#define TIMER_ELAPSED g_elapsed +#else +#define TIMER_START +#define TIMER_END +#define TIMER_ELAPSED ((sqlite_uint64)0) +#endif + +/* +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; +#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) +#define SimulateIOError(CODE) \ + if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ + || sqlite3_io_error_pending-- == 1 ) \ + { local_ioerr(); CODE; } +static void local_ioerr(){ + IOTRACE(("IOERR\n")); + sqlite3_io_error_hit++; + if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; +} +#define SimulateDiskfullError(CODE) \ + if( sqlite3_diskfull_pending ){ \ + if( sqlite3_diskfull_pending == 1 ){ \ + local_ioerr(); \ + sqlite3_diskfull = 1; \ + sqlite3_io_error_hit = 1; \ + CODE; \ + }else{ \ + sqlite3_diskfull_pending--; \ + } \ + } +#else +#define SimulateIOErrorBenign(X) +#define SimulateIOError(A) +#define SimulateDiskfullError(A) +#endif /* defined(SQLITE_TEST) */ + +/* +** When testing, keep a count of the number of open files. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; +#define OpenCounter(X) sqlite3_open_file_count+=(X) +#else +#define OpenCounter(X) +#endif /* defined(SQLITE_TEST) */ + +#endif /* !defined(_OS_COMMON_H_) */ + +/************** End of os_common.h *******************************************/ +/************** Continuing where we left off in os_win.c *********************/ + +/* +** Include the header file for the Windows VFS. +*/ +/* #include "os_win.h" */ + +/* +** Compiling and using WAL mode requires several APIs that are only +** available in Windows platforms based on the NT kernel. +*/ +#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL) +# error "WAL mode requires support from the Windows NT kernel, compile\ + with SQLITE_OMIT_WAL." +#endif + +#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0 +# error "Memory mapped files require support from the Windows NT kernel,\ + compile with SQLITE_MAX_MMAP_SIZE=0." +#endif + +/* +** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions +** based on the sub-platform)? +*/ +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI) +# define SQLITE_WIN32_HAS_ANSI +#endif + +/* +** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions +** based on the sub-platform)? +*/ +#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT) && \ + !defined(SQLITE_WIN32_NO_WIDE) +# define SQLITE_WIN32_HAS_WIDE +#endif + +/* +** Make sure at least one set of Win32 APIs is available. +*/ +#if !defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_WIN32_HAS_WIDE) +# error "At least one of SQLITE_WIN32_HAS_ANSI and SQLITE_WIN32_HAS_WIDE\ + must be defined." +#endif + +/* +** Define the required Windows SDK version constants if they are not +** already available. +*/ +#ifndef NTDDI_WIN8 +# define NTDDI_WIN8 0x06020000 +#endif + +#ifndef NTDDI_WINBLUE +# define NTDDI_WINBLUE 0x06030000 +#endif + +#ifndef NTDDI_WINTHRESHOLD +# define NTDDI_WINTHRESHOLD 0x06040000 +#endif + +/* +** Check to see if the GetVersionEx[AW] functions are deprecated on the +** target system. GetVersionEx was first deprecated in Win8.1. +*/ +#ifndef SQLITE_WIN32_GETVERSIONEX +# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE +# define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */ +# else +# define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */ +# endif +#endif + +/* +** Check to see if the CreateFileMappingA function is supported on the +** target system. It is unavailable when using "mincore.lib" on Win10. +** When compiling for Windows 10, always assume "mincore.lib" is in use. +*/ +#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA +# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD +# define SQLITE_WIN32_CREATEFILEMAPPINGA 0 +# else +# define SQLITE_WIN32_CREATEFILEMAPPINGA 1 +# endif +#endif + +/* +** This constant should already be defined (in the "WinDef.h" SDK file). +*/ +#ifndef MAX_PATH +# define MAX_PATH (260) +#endif + +/* +** Maximum pathname length (in chars) for Win32. This should normally be +** MAX_PATH. +*/ +#ifndef SQLITE_WIN32_MAX_PATH_CHARS +# define SQLITE_WIN32_MAX_PATH_CHARS (MAX_PATH) +#endif + +/* +** This constant should already be defined (in the "WinNT.h" SDK file). +*/ +#ifndef UNICODE_STRING_MAX_CHARS +# define UNICODE_STRING_MAX_CHARS (32767) +#endif + +/* +** Maximum pathname length (in chars) for WinNT. This should normally be +** UNICODE_STRING_MAX_CHARS. +*/ +#ifndef SQLITE_WINNT_MAX_PATH_CHARS +# define SQLITE_WINNT_MAX_PATH_CHARS (UNICODE_STRING_MAX_CHARS) +#endif + +/* +** Maximum pathname length (in bytes) for Win32. The MAX_PATH macro is in +** characters, so we allocate 4 bytes per character assuming worst-case of +** 4-bytes-per-character for UTF8. +*/ +#ifndef SQLITE_WIN32_MAX_PATH_BYTES +# define SQLITE_WIN32_MAX_PATH_BYTES (SQLITE_WIN32_MAX_PATH_CHARS*4) +#endif + +/* +** Maximum pathname length (in bytes) for WinNT. This should normally be +** UNICODE_STRING_MAX_CHARS * sizeof(WCHAR). +*/ +#ifndef SQLITE_WINNT_MAX_PATH_BYTES +# define SQLITE_WINNT_MAX_PATH_BYTES \ + (sizeof(WCHAR) * SQLITE_WINNT_MAX_PATH_CHARS) +#endif + +/* +** Maximum error message length (in chars) for WinRT. +*/ +#ifndef SQLITE_WIN32_MAX_ERRMSG_CHARS +# define SQLITE_WIN32_MAX_ERRMSG_CHARS (1024) +#endif + +/* +** Returns non-zero if the character should be treated as a directory +** separator. +*/ +#ifndef winIsDirSep +# define winIsDirSep(a) (((a) == '/') || ((a) == '\\')) +#endif + +/* +** This macro is used when a local variable is set to a value that is +** [sometimes] not used by the code (e.g. via conditional compilation). +*/ +#ifndef UNUSED_VARIABLE_VALUE +# define UNUSED_VARIABLE_VALUE(x) (void)(x) +#endif + +/* +** Returns the character that should be used as the directory separator. +*/ +#ifndef winGetDirSep +# define winGetDirSep() '\\' +#endif + +/* +** Do we need to manually define the Win32 file mapping APIs for use with WAL +** mode or memory mapped files (e.g. these APIs are available in the Windows +** CE SDK; however, they are not present in the header file)? +*/ +#if SQLITE_WIN32_FILEMAPPING_API && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) +/* +** Two of the file mapping APIs are different under WinRT. Figure out which +** set we need. +*/ +#if SQLITE_OS_WINRT +WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \ + LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR); + +WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T); +#else +#if defined(SQLITE_WIN32_HAS_ANSI) +WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \ + DWORD, DWORD, DWORD, LPCSTR); +#endif /* defined(SQLITE_WIN32_HAS_ANSI) */ + +#if defined(SQLITE_WIN32_HAS_WIDE) +WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \ + DWORD, DWORD, DWORD, LPCWSTR); +#endif /* defined(SQLITE_WIN32_HAS_WIDE) */ + +WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); +#endif /* SQLITE_OS_WINRT */ + +/* +** These file mapping APIs are common to both Win32 and WinRT. +*/ + +WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T); +WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); +#endif /* SQLITE_WIN32_FILEMAPPING_API */ + +/* +** Some Microsoft compilers lack this definition. +*/ +#ifndef INVALID_FILE_ATTRIBUTES +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +#ifndef FILE_FLAG_MASK +# define FILE_FLAG_MASK (0xFF3C0000) +#endif + +#ifndef FILE_ATTRIBUTE_MASK +# define FILE_ATTRIBUTE_MASK (0x0003FFF7) +#endif + +#ifndef SQLITE_OMIT_WAL +/* Forward references to structures used for WAL */ +typedef struct winShm winShm; /* A connection to shared-memory */ +typedef struct winShmNode winShmNode; /* A region of shared-memory */ +#endif + +/* +** WinCE lacks native support for file locking so we have to fake it +** with some code of our own. +*/ +#if SQLITE_OS_WINCE +typedef struct winceLock { + int nReaders; /* Number of reader locks obtained */ + BOOL bPending; /* Indicates a pending lock has been obtained */ + BOOL bReserved; /* Indicates a reserved lock has been obtained */ + BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ +} winceLock; +#endif + +/* +** The winFile structure is a subclass of sqlite3_file* specific to the win32 +** portability layer. +*/ +typedef struct winFile winFile; +struct winFile { + const sqlite3_io_methods *pMethod; /*** Must be first ***/ + sqlite3_vfs *pVfs; /* The VFS used to open this file */ + HANDLE h; /* Handle for accessing the file */ + u8 locktype; /* Type of lock currently held on this file */ + short sharedLockByte; /* Randomly chosen byte used as a shared lock */ + u8 ctrlFlags; /* Flags. See WINFILE_* below */ + DWORD lastErrno; /* The Windows errno from the last I/O error */ +#ifndef SQLITE_OMIT_WAL + winShm *pShm; /* Instance of shared memory on this file */ +#endif + const char *zPath; /* Full pathname of this file */ + int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ +#if SQLITE_OS_WINCE + LPWSTR zDeleteOnClose; /* Name of file to delete when closing */ + HANDLE hMutex; /* Mutex used to control access to shared lock */ + HANDLE hShared; /* Shared memory segment used for locking */ + winceLock local; /* Locks obtained by this instance of winFile */ + winceLock *shared; /* Global shared lock memory for the file */ +#endif +#if SQLITE_MAX_MMAP_SIZE>0 + int nFetchOut; /* Number of outstanding xFetch references */ + HANDLE hMap; /* Handle for accessing memory mapping */ + void *pMapRegion; /* Area memory mapped */ + sqlite3_int64 mmapSize; /* Usable size of mapped region */ + sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ + sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ +#endif +}; + +/* +** The winVfsAppData structure is used for the pAppData member for all of the +** Win32 VFS variants. +*/ +typedef struct winVfsAppData winVfsAppData; +struct winVfsAppData { + const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */ + void *pAppData; /* The extra pAppData, if any. */ + BOOL bNoLock; /* Non-zero if locking is disabled. */ +}; + +/* +** Allowed values for winFile.ctrlFlags +*/ +#define WINFILE_RDONLY 0x02 /* Connection is read only */ +#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ +#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ + +/* + * The size of the buffer used by sqlite3_win32_write_debug(). + */ +#ifndef SQLITE_WIN32_DBG_BUF_SIZE +# define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD))) +#endif + +/* + * The value used with sqlite3_win32_set_directory() to specify that + * the data directory should be changed. + */ +#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE +# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1) +#endif + +/* + * The value used with sqlite3_win32_set_directory() to specify that + * the temporary directory should be changed. + */ +#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE +# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2) +#endif + +/* + * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the + * various Win32 API heap functions instead of our own. + */ +#ifdef SQLITE_WIN32_MALLOC + +/* + * If this is non-zero, an isolated heap will be created by the native Win32 + * allocator subsystem; otherwise, the default process heap will be used. This + * setting has no effect when compiling for WinRT. By default, this is enabled + * and an isolated heap will be created to store all allocated data. + * + ****************************************************************************** + * WARNING: It is important to note that when this setting is non-zero and the + * winMemShutdown function is called (e.g. by the sqlite3_shutdown + * function), all data that was allocated using the isolated heap will + * be freed immediately and any attempt to access any of that freed + * data will almost certainly result in an immediate access violation. + ****************************************************************************** + */ +#ifndef SQLITE_WIN32_HEAP_CREATE +# define SQLITE_WIN32_HEAP_CREATE (TRUE) +#endif + +/* + * This is the maximum possible initial size of the Win32-specific heap, in + * bytes. + */ +#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE +# define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U) +#endif + +/* + * This is the extra space for the initial size of the Win32-specific heap, + * in bytes. This value may be zero. + */ +#ifndef SQLITE_WIN32_HEAP_INIT_EXTRA +# define SQLITE_WIN32_HEAP_INIT_EXTRA (4194304) +#endif + +/* + * Calculate the maximum legal cache size, in pages, based on the maximum + * possible initial heap size and the default page size, setting aside the + * needed extra space. + */ +#ifndef SQLITE_WIN32_MAX_CACHE_SIZE +# define SQLITE_WIN32_MAX_CACHE_SIZE (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \ + (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \ + (SQLITE_DEFAULT_PAGE_SIZE)) +#endif + +/* + * This is cache size used in the calculation of the initial size of the + * Win32-specific heap. It cannot be negative. + */ +#ifndef SQLITE_WIN32_CACHE_SIZE +# if SQLITE_DEFAULT_CACHE_SIZE>=0 +# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE) +# else +# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE)) +# endif +#endif + +/* + * Make sure that the calculated cache size, in pages, cannot cause the + * initial size of the Win32-specific heap to exceed the maximum amount + * of memory that can be specified in the call to HeapCreate. + */ +#if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE +# undef SQLITE_WIN32_CACHE_SIZE +# define SQLITE_WIN32_CACHE_SIZE (2000) +#endif + +/* + * The initial size of the Win32-specific heap. This value may be zero. + */ +#ifndef SQLITE_WIN32_HEAP_INIT_SIZE +# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \ + (SQLITE_DEFAULT_PAGE_SIZE) + \ + (SQLITE_WIN32_HEAP_INIT_EXTRA)) +#endif + +/* + * The maximum size of the Win32-specific heap. This value may be zero. + */ +#ifndef SQLITE_WIN32_HEAP_MAX_SIZE +# define SQLITE_WIN32_HEAP_MAX_SIZE (0) +#endif + +/* + * The extra flags to use in calls to the Win32 heap APIs. This value may be + * zero for the default behavior. + */ +#ifndef SQLITE_WIN32_HEAP_FLAGS +# define SQLITE_WIN32_HEAP_FLAGS (0) +#endif + + +/* +** The winMemData structure stores information required by the Win32-specific +** sqlite3_mem_methods implementation. +*/ +typedef struct winMemData winMemData; +struct winMemData { +#ifndef NDEBUG + u32 magic1; /* Magic number to detect structure corruption. */ +#endif + HANDLE hHeap; /* The handle to our heap. */ + BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */ +#ifndef NDEBUG + u32 magic2; /* Magic number to detect structure corruption. */ +#endif +}; + +#ifndef NDEBUG +#define WINMEM_MAGIC1 0x42b2830b +#define WINMEM_MAGIC2 0xbd4d7cf4 +#endif + +static struct winMemData win_mem_data = { +#ifndef NDEBUG + WINMEM_MAGIC1, +#endif + NULL, FALSE +#ifndef NDEBUG + ,WINMEM_MAGIC2 +#endif +}; + +#ifndef NDEBUG +#define winMemAssertMagic1() assert( win_mem_data.magic1==WINMEM_MAGIC1 ) +#define winMemAssertMagic2() assert( win_mem_data.magic2==WINMEM_MAGIC2 ) +#define winMemAssertMagic() winMemAssertMagic1(); winMemAssertMagic2(); +#else +#define winMemAssertMagic() +#endif + +#define winMemGetDataPtr() &win_mem_data +#define winMemGetHeap() win_mem_data.hHeap +#define winMemGetOwned() win_mem_data.bOwned + +static void *winMemMalloc(int nBytes); +static void winMemFree(void *pPrior); +static void *winMemRealloc(void *pPrior, int nBytes); +static int winMemSize(void *p); +static int winMemRoundup(int n); +static int winMemInit(void *pAppData); +static void winMemShutdown(void *pAppData); + +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void); +#endif /* SQLITE_WIN32_MALLOC */ + +/* +** The following variable is (normally) set once and never changes +** thereafter. It records whether the operating system is Win9x +** or WinNT. +** +** 0: Operating system unknown. +** 1: Operating system is Win9x. +** 2: Operating system is WinNT. +** +** In order to facilitate testing on a WinNT system, the test fixture +** can manually set this value to 1 to emulate Win98 behavior. +*/ +#ifdef SQLITE_TEST +SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; +#else +static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; +#endif + +#ifndef SYSCALL +# define SYSCALL sqlite3_syscall_ptr +#endif + +/* +** This function is not available on Windows CE or WinRT. + */ + +#if SQLITE_OS_WINCE || SQLITE_OS_WINRT +# define osAreFileApisANSI() 1 +#endif + +/* +** Many system calls are accessed through pointer-to-functions so that +** they may be overridden at runtime to facilitate fault injection during +** testing and sandboxing. The following array holds the names and pointers +** to all overrideable system calls. +*/ +static struct win_syscall { + const char *zName; /* Name of the system call */ + sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ + sqlite3_syscall_ptr pDefault; /* Default value */ +} aSyscall[] = { +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT + { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, +#else + { "AreFileApisANSI", (SYSCALL)0, 0 }, +#endif + +#ifndef osAreFileApisANSI +#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent) +#endif + +#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) + { "CharLowerW", (SYSCALL)CharLowerW, 0 }, +#else + { "CharLowerW", (SYSCALL)0, 0 }, +#endif + +#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent) + +#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) + { "CharUpperW", (SYSCALL)CharUpperW, 0 }, +#else + { "CharUpperW", (SYSCALL)0, 0 }, +#endif + +#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent) + + { "CloseHandle", (SYSCALL)CloseHandle, 0 }, + +#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) + { "CreateFileA", (SYSCALL)CreateFileA, 0 }, +#else + { "CreateFileA", (SYSCALL)0, 0 }, +#endif + +#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \ + LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent) + +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) + { "CreateFileW", (SYSCALL)CreateFileW, 0 }, +#else + { "CreateFileW", (SYSCALL)0, 0 }, +#endif + +#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ + LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) + +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \ + SQLITE_WIN32_CREATEFILEMAPPINGA + { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, +#else + { "CreateFileMappingA", (SYSCALL)0, 0 }, +#endif + +#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ + DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) + +#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) + { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, +#else + { "CreateFileMappingW", (SYSCALL)0, 0 }, +#endif + +#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ + DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent) + +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) + { "CreateMutexW", (SYSCALL)CreateMutexW, 0 }, +#else + { "CreateMutexW", (SYSCALL)0, 0 }, +#endif + +#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \ + LPCWSTR))aSyscall[8].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) + { "DeleteFileA", (SYSCALL)DeleteFileA, 0 }, +#else + { "DeleteFileA", (SYSCALL)0, 0 }, +#endif + +#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) + { "DeleteFileW", (SYSCALL)DeleteFileW, 0 }, +#else + { "DeleteFileW", (SYSCALL)0, 0 }, +#endif + +#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent) + +#if SQLITE_OS_WINCE + { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 }, +#else + { "FileTimeToLocalFileTime", (SYSCALL)0, 0 }, +#endif + +#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \ + LPFILETIME))aSyscall[11].pCurrent) + +#if SQLITE_OS_WINCE + { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 }, +#else + { "FileTimeToSystemTime", (SYSCALL)0, 0 }, +#endif + +#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \ + LPSYSTEMTIME))aSyscall[12].pCurrent) + + { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, + +#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) + { "FormatMessageA", (SYSCALL)FormatMessageA, 0 }, +#else + { "FormatMessageA", (SYSCALL)0, 0 }, +#endif + +#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \ + DWORD,va_list*))aSyscall[14].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) + { "FormatMessageW", (SYSCALL)FormatMessageW, 0 }, +#else + { "FormatMessageW", (SYSCALL)0, 0 }, +#endif + +#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \ + DWORD,va_list*))aSyscall[15].pCurrent) + +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) + { "FreeLibrary", (SYSCALL)FreeLibrary, 0 }, +#else + { "FreeLibrary", (SYSCALL)0, 0 }, +#endif + +#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent) + + { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 }, + +#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent) + +#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) + { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 }, +#else + { "GetDiskFreeSpaceA", (SYSCALL)0, 0 }, +#endif + +#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \ + LPDWORD))aSyscall[18].pCurrent) + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) + { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 }, +#else + { "GetDiskFreeSpaceW", (SYSCALL)0, 0 }, +#endif + +#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \ + LPDWORD))aSyscall[19].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) + { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 }, +#else + { "GetFileAttributesA", (SYSCALL)0, 0 }, +#endif + +#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent) + +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) + { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, +#else + { "GetFileAttributesW", (SYSCALL)0, 0 }, +#endif + +#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) + { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 }, +#else + { "GetFileAttributesExW", (SYSCALL)0, 0 }, +#endif + +#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ + LPVOID))aSyscall[22].pCurrent) + +#if !SQLITE_OS_WINRT + { "GetFileSize", (SYSCALL)GetFileSize, 0 }, +#else + { "GetFileSize", (SYSCALL)0, 0 }, +#endif + +#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent) + +#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) + { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 }, +#else + { "GetFullPathNameA", (SYSCALL)0, 0 }, +#endif + +#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \ + LPSTR*))aSyscall[24].pCurrent) + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) + { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, +#else + { "GetFullPathNameW", (SYSCALL)0, 0 }, +#endif + +#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ + LPWSTR*))aSyscall[25].pCurrent) + + { "GetLastError", (SYSCALL)GetLastError, 0 }, + +#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) + +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) +#if SQLITE_OS_WINCE + /* The GetProcAddressA() routine is only available on Windows CE. */ + { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 }, +#else + /* All other Windows platforms expect GetProcAddress() to take + ** an ANSI string regardless of the _UNICODE setting */ + { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 }, +#endif +#else + { "GetProcAddressA", (SYSCALL)0, 0 }, +#endif + +#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ + LPCSTR))aSyscall[27].pCurrent) + +#if !SQLITE_OS_WINRT + { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, +#else + { "GetSystemInfo", (SYSCALL)0, 0 }, +#endif + +#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent) + + { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, + +#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent) + +#if !SQLITE_OS_WINCE + { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 }, +#else + { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 }, +#endif + +#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \ + LPFILETIME))aSyscall[30].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) + { "GetTempPathA", (SYSCALL)GetTempPathA, 0 }, +#else + { "GetTempPathA", (SYSCALL)0, 0 }, +#endif + +#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent) + +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) + { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, +#else + { "GetTempPathW", (SYSCALL)0, 0 }, +#endif + +#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent) + +#if !SQLITE_OS_WINRT + { "GetTickCount", (SYSCALL)GetTickCount, 0 }, +#else + { "GetTickCount", (SYSCALL)0, 0 }, +#endif + +#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX + { "GetVersionExA", (SYSCALL)GetVersionExA, 0 }, +#else + { "GetVersionExA", (SYSCALL)0, 0 }, +#endif + +#define osGetVersionExA ((BOOL(WINAPI*)( \ + LPOSVERSIONINFOA))aSyscall[34].pCurrent) + +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ + SQLITE_WIN32_GETVERSIONEX + { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, +#else + { "GetVersionExW", (SYSCALL)0, 0 }, +#endif + +#define osGetVersionExW ((BOOL(WINAPI*)( \ + LPOSVERSIONINFOW))aSyscall[35].pCurrent) + + { "HeapAlloc", (SYSCALL)HeapAlloc, 0 }, + +#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ + SIZE_T))aSyscall[36].pCurrent) + +#if !SQLITE_OS_WINRT + { "HeapCreate", (SYSCALL)HeapCreate, 0 }, +#else + { "HeapCreate", (SYSCALL)0, 0 }, +#endif + +#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ + SIZE_T))aSyscall[37].pCurrent) + +#if !SQLITE_OS_WINRT + { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, +#else + { "HeapDestroy", (SYSCALL)0, 0 }, +#endif + +#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent) + + { "HeapFree", (SYSCALL)HeapFree, 0 }, + +#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent) + + { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 }, + +#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \ + SIZE_T))aSyscall[40].pCurrent) + + { "HeapSize", (SYSCALL)HeapSize, 0 }, + +#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ + LPCVOID))aSyscall[41].pCurrent) + +#if !SQLITE_OS_WINRT + { "HeapValidate", (SYSCALL)HeapValidate, 0 }, +#else + { "HeapValidate", (SYSCALL)0, 0 }, +#endif + +#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ + LPCVOID))aSyscall[42].pCurrent) + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT + { "HeapCompact", (SYSCALL)HeapCompact, 0 }, +#else + { "HeapCompact", (SYSCALL)0, 0 }, +#endif + +#define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[43].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION) + { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 }, +#else + { "LoadLibraryA", (SYSCALL)0, 0 }, +#endif + +#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent) + +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ + !defined(SQLITE_OMIT_LOAD_EXTENSION) + { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, +#else + { "LoadLibraryW", (SYSCALL)0, 0 }, +#endif + +#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent) + +#if !SQLITE_OS_WINRT + { "LocalFree", (SYSCALL)LocalFree, 0 }, +#else + { "LocalFree", (SYSCALL)0, 0 }, +#endif + +#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent) + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT + { "LockFile", (SYSCALL)LockFile, 0 }, +#else + { "LockFile", (SYSCALL)0, 0 }, +#endif + +#ifndef osLockFile +#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ + DWORD))aSyscall[47].pCurrent) +#endif + +#if !SQLITE_OS_WINCE + { "LockFileEx", (SYSCALL)LockFileEx, 0 }, +#else + { "LockFileEx", (SYSCALL)0, 0 }, +#endif + +#ifndef osLockFileEx +#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ + LPOVERLAPPED))aSyscall[48].pCurrent) +#endif + +#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) + { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, +#else + { "MapViewOfFile", (SYSCALL)0, 0 }, +#endif + +#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ + SIZE_T))aSyscall[49].pCurrent) + + { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, + +#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \ + int))aSyscall[50].pCurrent) + + { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 }, + +#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \ + LARGE_INTEGER*))aSyscall[51].pCurrent) + + { "ReadFile", (SYSCALL)ReadFile, 0 }, + +#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \ + LPOVERLAPPED))aSyscall[52].pCurrent) + + { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 }, + +#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent) + +#if !SQLITE_OS_WINRT + { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, +#else + { "SetFilePointer", (SYSCALL)0, 0 }, +#endif + +#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ + DWORD))aSyscall[54].pCurrent) + +#if !SQLITE_OS_WINRT + { "Sleep", (SYSCALL)Sleep, 0 }, +#else + { "Sleep", (SYSCALL)0, 0 }, +#endif + +#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent) + + { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, + +#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ + LPFILETIME))aSyscall[56].pCurrent) + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT + { "UnlockFile", (SYSCALL)UnlockFile, 0 }, +#else + { "UnlockFile", (SYSCALL)0, 0 }, +#endif + +#ifndef osUnlockFile +#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ + DWORD))aSyscall[57].pCurrent) +#endif + +#if !SQLITE_OS_WINCE + { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 }, +#else + { "UnlockFileEx", (SYSCALL)0, 0 }, +#endif + +#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ + LPOVERLAPPED))aSyscall[58].pCurrent) + +#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 + { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, +#else + { "UnmapViewOfFile", (SYSCALL)0, 0 }, +#endif + +#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[59].pCurrent) + + { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 }, + +#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \ + LPCSTR,LPBOOL))aSyscall[60].pCurrent) + + { "WriteFile", (SYSCALL)WriteFile, 0 }, + +#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ + LPOVERLAPPED))aSyscall[61].pCurrent) + +#if SQLITE_OS_WINRT + { "CreateEventExW", (SYSCALL)CreateEventExW, 0 }, +#else + { "CreateEventExW", (SYSCALL)0, 0 }, +#endif + +#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ + DWORD,DWORD))aSyscall[62].pCurrent) + +#if !SQLITE_OS_WINRT + { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, +#else + { "WaitForSingleObject", (SYSCALL)0, 0 }, +#endif + +#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ + DWORD))aSyscall[63].pCurrent) + +#if !SQLITE_OS_WINCE + { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, +#else + { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, +#endif + +#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ + BOOL))aSyscall[64].pCurrent) + +#if SQLITE_OS_WINRT + { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, +#else + { "SetFilePointerEx", (SYSCALL)0, 0 }, +#endif + +#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \ + PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent) + +#if SQLITE_OS_WINRT + { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 }, +#else + { "GetFileInformationByHandleEx", (SYSCALL)0, 0 }, +#endif + +#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ + FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) + +#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) + { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, +#else + { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, +#endif + +#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ + SIZE_T))aSyscall[67].pCurrent) + +#if SQLITE_OS_WINRT + { "CreateFile2", (SYSCALL)CreateFile2, 0 }, +#else + { "CreateFile2", (SYSCALL)0, 0 }, +#endif + +#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ + LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent) + +#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION) + { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, +#else + { "LoadPackagedLibrary", (SYSCALL)0, 0 }, +#endif + +#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \ + DWORD))aSyscall[69].pCurrent) + +#if SQLITE_OS_WINRT + { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, +#else + { "GetTickCount64", (SYSCALL)0, 0 }, +#endif + +#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent) + +#if SQLITE_OS_WINRT + { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, +#else + { "GetNativeSystemInfo", (SYSCALL)0, 0 }, +#endif + +#define osGetNativeSystemInfo ((VOID(WINAPI*)( \ + LPSYSTEM_INFO))aSyscall[71].pCurrent) + +#if defined(SQLITE_WIN32_HAS_ANSI) + { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, +#else + { "OutputDebugStringA", (SYSCALL)0, 0 }, +#endif + +#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) + { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, +#else + { "OutputDebugStringW", (SYSCALL)0, 0 }, +#endif + +#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent) + + { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, + +#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) + +#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) + { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, +#else + { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, +#endif + +#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ + LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) + +/* +** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" +** is really just a macro that uses a compiler intrinsic (e.g. x64). +** So do not try to make this is into a redefinable interface. +*/ +#if defined(InterlockedCompareExchange) + { "InterlockedCompareExchange", (SYSCALL)0, 0 }, + +#define osInterlockedCompareExchange InterlockedCompareExchange +#else + { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, + +#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ + SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) +#endif /* defined(InterlockedCompareExchange) */ + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID + { "UuidCreate", (SYSCALL)UuidCreate, 0 }, +#else + { "UuidCreate", (SYSCALL)0, 0 }, +#endif + +#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent) + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID + { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, +#else + { "UuidCreateSequential", (SYSCALL)0, 0 }, +#endif + +#define osUuidCreateSequential \ + ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent) + +#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 + { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, +#else + { "FlushViewOfFile", (SYSCALL)0, 0 }, +#endif + +#define osFlushViewOfFile \ + ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) + +}; /* End of the overrideable system calls */ + +/* +** This is the xSetSystemCall() method of sqlite3_vfs for all of the +** "win32" VFSes. Return SQLITE_OK opon successfully updating the +** system call pointer, or SQLITE_NOTFOUND if there is no configurable +** system call named zName. +*/ +static int winSetSystemCall( + sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */ + const char *zName, /* Name of system call to override */ + sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */ +){ + unsigned int i; + int rc = SQLITE_NOTFOUND; + + UNUSED_PARAMETER(pNotUsed); + if( zName==0 ){ + /* If no zName is given, restore all system calls to their default + ** settings and return NULL + */ + rc = SQLITE_OK; + for(i=0; i0 ){ + memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); + memcpy(zDbgBuf, zBuf, nMin); + osOutputDebugStringA(zDbgBuf); + }else{ + osOutputDebugStringA(zBuf); + } +#elif defined(SQLITE_WIN32_HAS_WIDE) + memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); + if ( osMultiByteToWideChar( + osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf, + nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){ + return; + } + osOutputDebugStringW((LPCWSTR)zDbgBuf); +#else + if( nMin>0 ){ + memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); + memcpy(zDbgBuf, zBuf, nMin); + fprintf(stderr, "%s", zDbgBuf); + }else{ + fprintf(stderr, "%s", zBuf); + } +#endif +} + +/* +** The following routine suspends the current thread for at least ms +** milliseconds. This is equivalent to the Win32 Sleep() interface. +*/ +#if SQLITE_OS_WINRT +static HANDLE sleepObj = NULL; +#endif + +SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ +#if SQLITE_OS_WINRT + if ( sleepObj==NULL ){ + sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET, + SYNCHRONIZE); + } + assert( sleepObj!=NULL ); + osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); +#else + osSleep(milliseconds); +#endif +} + +#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ + SQLITE_THREADSAFE>0 +SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ + DWORD rc; + while( (rc = osWaitForSingleObjectEx(hObject, INFINITE, + TRUE))==WAIT_IO_COMPLETION ){} + return rc; +} +#endif + +/* +** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, +** or WinCE. Return false (zero) for Win95, Win98, or WinME. +** +** Here is an interesting observation: Win95, Win98, and WinME lack +** the LockFileEx() API. But we can still statically link against that +** API as long as we don't call it when running Win95/98/ME. A call to +** this routine is used to determine if the host is Win95/98/ME or +** WinNT/2K/XP so that we will know whether or not we can safely call +** the LockFileEx() API. +*/ + +#if !SQLITE_WIN32_GETVERSIONEX +# define osIsNT() (1) +#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) +# define osIsNT() (1) +#elif !defined(SQLITE_WIN32_HAS_WIDE) +# define osIsNT() (0) +#else +# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt()) +#endif + +/* +** This function determines if the machine is running a version of Windows +** based on the NT kernel. +*/ +SQLITE_API int sqlite3_win32_is_nt(void){ +#if SQLITE_OS_WINRT + /* + ** NOTE: The WinRT sub-platform is always assumed to be based on the NT + ** kernel. + */ + return 1; +#elif SQLITE_WIN32_GETVERSIONEX + if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ +#if defined(SQLITE_WIN32_HAS_ANSI) + OSVERSIONINFOA sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExA(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); +#elif defined(SQLITE_WIN32_HAS_WIDE) + OSVERSIONINFOW sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExW(&sInfo); + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); +#endif + } + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; +#elif SQLITE_TEST + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; +#else + /* + ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are + ** deprecated are always assumed to be based on the NT kernel. + */ + return 1; +#endif +} + +#ifdef SQLITE_WIN32_MALLOC +/* +** Allocate nBytes of memory. +*/ +static void *winMemMalloc(int nBytes){ + HANDLE hHeap; + void *p; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) + assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); +#endif + assert( nBytes>=0 ); + p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); + if( !p ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p", + nBytes, osGetLastError(), (void*)hHeap); + } + return p; +} + +/* +** Free memory. +*/ +static void winMemFree(void *pPrior){ + HANDLE hHeap; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) + assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); +#endif + if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ + if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p", + pPrior, osGetLastError(), (void*)hHeap); + } +} + +/* +** Change the size of an existing memory allocation +*/ +static void *winMemRealloc(void *pPrior, int nBytes){ + HANDLE hHeap; + void *p; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) + assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); +#endif + assert( nBytes>=0 ); + if( !pPrior ){ + p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); + }else{ + p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes); + } + if( !p ){ + sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p", + pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(), + (void*)hHeap); + } + return p; +} + +/* +** Return the size of an outstanding allocation, in bytes. +*/ +static int winMemSize(void *p){ + HANDLE hHeap; + SIZE_T n; + + winMemAssertMagic(); + hHeap = winMemGetHeap(); + assert( hHeap!=0 ); + assert( hHeap!=INVALID_HANDLE_VALUE ); +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) + assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) ); +#endif + if( !p ) return 0; + n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p); + if( n==(SIZE_T)-1 ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p", + p, osGetLastError(), (void*)hHeap); + return 0; + } + return (int)n; +} + +/* +** Round up a request size to the next valid allocation size. +*/ +static int winMemRoundup(int n){ + return n; +} + +/* +** Initialize this module. +*/ +static int winMemInit(void *pAppData){ + winMemData *pWinMemData = (winMemData *)pAppData; + + if( !pWinMemData ) return SQLITE_ERROR; + assert( pWinMemData->magic1==WINMEM_MAGIC1 ); + assert( pWinMemData->magic2==WINMEM_MAGIC2 ); + +#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE + if( !pWinMemData->hHeap ){ + DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE; + DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap; + if( dwMaximumSize==0 ){ + dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE; + }else if( dwInitialSize>dwMaximumSize ){ + dwInitialSize = dwMaximumSize; + } + pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS, + dwInitialSize, dwMaximumSize); + if( !pWinMemData->hHeap ){ + sqlite3_log(SQLITE_NOMEM, + "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu", + osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize, + dwMaximumSize); + return SQLITE_NOMEM_BKPT; + } + pWinMemData->bOwned = TRUE; + assert( pWinMemData->bOwned ); + } +#else + pWinMemData->hHeap = osGetProcessHeap(); + if( !pWinMemData->hHeap ){ + sqlite3_log(SQLITE_NOMEM, + "failed to GetProcessHeap (%lu)", osGetLastError()); + return SQLITE_NOMEM_BKPT; + } + pWinMemData->bOwned = FALSE; + assert( !pWinMemData->bOwned ); +#endif + assert( pWinMemData->hHeap!=0 ); + assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) + assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); +#endif + return SQLITE_OK; +} + +/* +** Deinitialize this module. +*/ +static void winMemShutdown(void *pAppData){ + winMemData *pWinMemData = (winMemData *)pAppData; + + if( !pWinMemData ) return; + assert( pWinMemData->magic1==WINMEM_MAGIC1 ); + assert( pWinMemData->magic2==WINMEM_MAGIC2 ); + + if( pWinMemData->hHeap ){ + assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); +#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) + assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); +#endif + if( pWinMemData->bOwned ){ + if( !osHeapDestroy(pWinMemData->hHeap) ){ + sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p", + osGetLastError(), (void*)pWinMemData->hHeap); + } + pWinMemData->bOwned = FALSE; + } + pWinMemData->hHeap = NULL; + } +} + +/* +** Populate the low-level memory allocation function pointers in +** sqlite3GlobalConfig.m with pointers to the routines in this file. The +** arguments specify the block of memory to manage. +** +** This routine is only called by sqlite3_config(), and therefore +** is not required to be threadsafe (it is not). +*/ +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){ + static const sqlite3_mem_methods winMemMethods = { + winMemMalloc, + winMemFree, + winMemRealloc, + winMemSize, + winMemRoundup, + winMemInit, + winMemShutdown, + &win_mem_data + }; + return &winMemMethods; +} + +SQLITE_PRIVATE void sqlite3MemSetDefault(void){ + sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32()); +} +#endif /* SQLITE_WIN32_MALLOC */ + +/* +** Convert a UTF-8 string to Microsoft Unicode. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). +*/ +static LPWSTR winUtf8ToUnicode(const char *zText){ + int nChar; + LPWSTR zWideText; + + nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0); + if( nChar==0 ){ + return 0; + } + zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) ); + if( zWideText==0 ){ + return 0; + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, + nChar); + if( nChar==0 ){ + sqlite3_free(zWideText); + zWideText = 0; + } + return zWideText; +} + +/* +** Convert a Microsoft Unicode string to UTF-8. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). +*/ +static char *winUnicodeToUtf8(LPCWSTR zWideText){ + int nByte; + char *zText; + + nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0); + if( nByte == 0 ){ + return 0; + } + zText = sqlite3MallocZero( nByte ); + if( zText==0 ){ + return 0; + } + nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, + 0, 0); + if( nByte == 0 ){ + sqlite3_free(zText); + zText = 0; + } + return zText; +} + +/* +** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM +** code page. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). +*/ +static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ + int nByte; + LPWSTR zMbcsText; + int codepage = useAnsi ? CP_ACP : CP_OEMCP; + + nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, + 0)*sizeof(WCHAR); + if( nByte==0 ){ + return 0; + } + zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); + if( zMbcsText==0 ){ + return 0; + } + nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, + nByte); + if( nByte==0 ){ + sqlite3_free(zMbcsText); + zMbcsText = 0; + } + return zMbcsText; +} + +/* +** Convert a Microsoft Unicode string to a multi-byte character string, +** using the ANSI or OEM code page. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). +*/ +static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ + int nByte; + char *zText; + int codepage = useAnsi ? CP_ACP : CP_OEMCP; + + nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0); + if( nByte == 0 ){ + return 0; + } + zText = sqlite3MallocZero( nByte ); + if( zText==0 ){ + return 0; + } + nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText, + nByte, 0, 0); + if( nByte == 0 ){ + sqlite3_free(zText); + zText = 0; + } + return zText; +} + +/* +** Convert a multi-byte character string to UTF-8. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). +*/ +static char *winMbcsToUtf8(const char *zText, int useAnsi){ + char *zTextUtf8; + LPWSTR zTmpWide; + + zTmpWide = winMbcsToUnicode(zText, useAnsi); + if( zTmpWide==0 ){ + return 0; + } + zTextUtf8 = winUnicodeToUtf8(zTmpWide); + sqlite3_free(zTmpWide); + return zTextUtf8; +} + +/* +** Convert a UTF-8 string to a multi-byte character string. +** +** Space to hold the returned string is obtained from sqlite3_malloc(). +*/ +static char *winUtf8ToMbcs(const char *zText, int useAnsi){ + char *zTextMbcs; + LPWSTR zTmpWide; + + zTmpWide = winUtf8ToUnicode(zText); + if( zTmpWide==0 ){ + return 0; + } + zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi); + sqlite3_free(zTmpWide); + return zTextMbcs; +} + +/* +** This is a public wrapper for the winUtf8ToUnicode() function. +*/ +SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUtf8ToUnicode(zText); +} + +/* +** This is a public wrapper for the winUnicodeToUtf8() function. +*/ +SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zWideText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUnicodeToUtf8(zWideText); +} + +/* +** This is a public wrapper for the winMbcsToUtf8() function. +*/ +SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winMbcsToUtf8(zText, osAreFileApisANSI()); +} + +/* +** This is a public wrapper for the winMbcsToUtf8() function. +*/ +SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winMbcsToUtf8(zText, useAnsi); +} + +/* +** This is a public wrapper for the winUtf8ToMbcs() function. +*/ +SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUtf8ToMbcs(zText, osAreFileApisANSI()); +} + +/* +** This is a public wrapper for the winUtf8ToMbcs() function. +*/ +SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zText ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize() ) return 0; +#endif + return winUtf8ToMbcs(zText, useAnsi); +} + +/* +** This function sets the data directory or the temporary directory based on +** the provided arguments. The type argument must be 1 in order to set the +** data directory or 2 in order to set the temporary directory. The zValue +** argument is the name of the directory to use. The return value will be +** SQLITE_OK if successful. +*/ +SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ + char **ppDirectory = 0; +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return rc; +#endif + if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){ + ppDirectory = &sqlite3_data_directory; + }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){ + ppDirectory = &sqlite3_temp_directory; + } + assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE + || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE + ); + assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) ); + if( ppDirectory ){ + char *zValueUtf8 = 0; + if( zValue && zValue[0] ){ + zValueUtf8 = winUnicodeToUtf8(zValue); + if ( zValueUtf8==0 ){ + return SQLITE_NOMEM_BKPT; + } + } + sqlite3_free(*ppDirectory); + *ppDirectory = zValueUtf8; + return SQLITE_OK; + } + return SQLITE_ERROR; +} + +/* +** The return value of winGetLastErrorMsg +** is zero if the error message fits in the buffer, or non-zero +** otherwise (if the message was truncated). +*/ +static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ + /* FormatMessage returns 0 on failure. Otherwise it + ** returns the number of TCHARs written to the output + ** buffer, excluding the terminating null char. + */ + DWORD dwLen = 0; + char *zOut = 0; + + if( osIsNT() ){ +#if SQLITE_OS_WINRT + WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1]; + dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastErrno, + 0, + zTempWide, + SQLITE_WIN32_MAX_ERRMSG_CHARS, + 0); +#else + LPWSTR zTempWide = NULL; + dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastErrno, + 0, + (LPWSTR) &zTempWide, + 0, + 0); +#endif + if( dwLen > 0 ){ + /* allocate a buffer and convert to UTF8 */ + sqlite3BeginBenignMalloc(); + zOut = winUnicodeToUtf8(zTempWide); + sqlite3EndBenignMalloc(); +#if !SQLITE_OS_WINRT + /* free the system buffer allocated by FormatMessage */ + osLocalFree(zTempWide); +#endif + } + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + char *zTemp = NULL; + dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastErrno, + 0, + (LPSTR) &zTemp, + 0, + 0); + if( dwLen > 0 ){ + /* allocate a buffer and convert to UTF8 */ + sqlite3BeginBenignMalloc(); + zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); + sqlite3EndBenignMalloc(); + /* free the system buffer allocated by FormatMessage */ + osLocalFree(zTemp); + } + } +#endif + if( 0 == dwLen ){ + sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno); + }else{ + /* copy a maximum of nBuf chars to output buffer */ + sqlite3_snprintf(nBuf, zBuf, "%s", zOut); + /* free the UTF8 buffer */ + sqlite3_free(zOut); + } + return 0; +} + +/* +** +** This function - winLogErrorAtLine() - is only ever called via the macro +** winLogError(). +** +** This routine is invoked after an error occurs in an OS function. +** It logs a message using sqlite3_log() containing the current value of +** error code and, if possible, the human-readable equivalent from +** FormatMessage. +** +** The first argument passed to the macro should be the error code that +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). +** The two subsequent arguments should be the name of the OS function that +** failed and the associated file-system path, if any. +*/ +#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__) +static int winLogErrorAtLine( + int errcode, /* SQLite error code */ + DWORD lastErrno, /* Win32 last error */ + const char *zFunc, /* Name of OS function that failed */ + const char *zPath, /* File path associated with error */ + int iLine /* Source line number where error occurred */ +){ + char zMsg[500]; /* Human readable error text */ + int i; /* Loop counter */ + + zMsg[0] = 0; + winGetLastErrorMsg(lastErrno, sizeof(zMsg), zMsg); + assert( errcode!=SQLITE_OK ); + if( zPath==0 ) zPath = ""; + for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} + zMsg[i] = 0; + sqlite3_log(errcode, + "os_win.c:%d: (%lu) %s(%s) - %s", + iLine, lastErrno, zFunc, zPath, zMsg + ); + + return errcode; +} + +/* +** The number of times that a ReadFile(), WriteFile(), and DeleteFile() +** will be retried following a locking error - probably caused by +** antivirus software. Also the initial delay before the first retry. +** The delay increases linearly with each retry. +*/ +#ifndef SQLITE_WIN32_IOERR_RETRY +# define SQLITE_WIN32_IOERR_RETRY 10 +#endif +#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY +# define SQLITE_WIN32_IOERR_RETRY_DELAY 25 +#endif +static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY; +static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; + +/* +** The "winIoerrCanRetry1" macro is used to determine if a particular I/O +** error code obtained via GetLastError() is eligible to be retried. It +** must accept the error code DWORD as its only argument and should return +** non-zero if the error code is transient in nature and the operation +** responsible for generating the original error might succeed upon being +** retried. The argument to this macro should be a variable. +** +** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it +** is defined, it will be consulted only when the macro "winIoerrCanRetry1" +** returns zero. The "winIoerrCanRetry2" macro is completely optional and +** may be used to include additional error codes in the set that should +** result in the failing I/O operation being retried by the caller. If +** defined, the "winIoerrCanRetry2" macro must exhibit external semantics +** identical to those of the "winIoerrCanRetry1" macro. +*/ +#if !defined(winIoerrCanRetry1) +#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \ + ((a)==ERROR_SHARING_VIOLATION) || \ + ((a)==ERROR_LOCK_VIOLATION) || \ + ((a)==ERROR_DEV_NOT_EXIST) || \ + ((a)==ERROR_NETNAME_DELETED) || \ + ((a)==ERROR_SEM_TIMEOUT) || \ + ((a)==ERROR_NETWORK_UNREACHABLE)) +#endif + +/* +** If a ReadFile() or WriteFile() error occurs, invoke this routine +** to see if it should be retried. Return TRUE to retry. Return FALSE +** to give up with an error. +*/ +static int winRetryIoerr(int *pnRetry, DWORD *pError){ + DWORD e = osGetLastError(); + if( *pnRetry>=winIoerrRetry ){ + if( pError ){ + *pError = e; + } + return 0; + } + if( winIoerrCanRetry1(e) ){ + sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); + ++*pnRetry; + return 1; + } +#if defined(winIoerrCanRetry2) + else if( winIoerrCanRetry2(e) ){ + sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); + ++*pnRetry; + return 1; + } +#endif + if( pError ){ + *pError = e; + } + return 0; +} + +/* +** Log a I/O error retry episode. +*/ +static void winLogIoerr(int nRetry, int lineno){ + if( nRetry ){ + sqlite3_log(SQLITE_NOTICE, + "delayed %dms for lock/sharing conflict at line %d", + winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno + ); + } +} + +/* +** This #if does not rely on the SQLITE_OS_WINCE define because the +** corresponding section in "date.c" cannot use it. +*/ +#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ + (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) +/* +** The MSVC CRT on Windows CE may not have a localtime() function. +** So define a substitute. +*/ +/* # include */ +struct tm *__cdecl localtime(const time_t *t) +{ + static struct tm y; + FILETIME uTm, lTm; + SYSTEMTIME pTm; + sqlite3_int64 t64; + t64 = *t; + t64 = (t64 + 11644473600)*10000000; + uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF); + uTm.dwHighDateTime= (DWORD)(t64 >> 32); + osFileTimeToLocalFileTime(&uTm,&lTm); + osFileTimeToSystemTime(&lTm,&pTm); + y.tm_year = pTm.wYear - 1900; + y.tm_mon = pTm.wMonth - 1; + y.tm_wday = pTm.wDayOfWeek; + y.tm_mday = pTm.wDay; + y.tm_hour = pTm.wHour; + y.tm_min = pTm.wMinute; + y.tm_sec = pTm.wSecond; + return &y; +} +#endif + +#if SQLITE_OS_WINCE +/************************************************************************* +** This section contains code for WinCE only. +*/ +#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] + +/* +** Acquire a lock on the handle h +*/ +static void winceMutexAcquire(HANDLE h){ + DWORD dwErr; + do { + dwErr = osWaitForSingleObject(h, INFINITE); + } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); +} +/* +** Release a lock acquired by winceMutexAcquire() +*/ +#define winceMutexRelease(h) ReleaseMutex(h) + +/* +** Create the mutex and shared memory used for locking in the file +** descriptor pFile +*/ +static int winceCreateLock(const char *zFilename, winFile *pFile){ + LPWSTR zTok; + LPWSTR zName; + DWORD lastErrno; + BOOL bLogged = FALSE; + BOOL bInit = TRUE; + + zName = winUtf8ToUnicode(zFilename); + if( zName==0 ){ + /* out of memory */ + return SQLITE_IOERR_NOMEM_BKPT; + } + + /* Initialize the local lockdata */ + memset(&pFile->local, 0, sizeof(pFile->local)); + + /* Replace the backslashes from the filename and lowercase it + ** to derive a mutex name. */ + zTok = osCharLowerW(zName); + for (;*zTok;zTok++){ + if (*zTok == '\\') *zTok = '_'; + } + + /* Create/open the named mutex */ + pFile->hMutex = osCreateMutexW(NULL, FALSE, zName); + if (!pFile->hMutex){ + pFile->lastErrno = osGetLastError(); + sqlite3_free(zName); + return winLogError(SQLITE_IOERR, pFile->lastErrno, + "winceCreateLock1", zFilename); + } + + /* Acquire the mutex before continuing */ + winceMutexAcquire(pFile->hMutex); + + /* Since the names of named mutexes, semaphores, file mappings etc are + ** case-sensitive, take advantage of that by uppercasing the mutex name + ** and using that as the shared filemapping name. + */ + osCharUpperW(zName); + pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(winceLock), + zName); + + /* Set a flag that indicates we're the first to create the memory so it + ** must be zero-initialized */ + lastErrno = osGetLastError(); + if (lastErrno == ERROR_ALREADY_EXISTS){ + bInit = FALSE; + } + + sqlite3_free(zName); + + /* If we succeeded in making the shared memory handle, map it. */ + if( pFile->hShared ){ + pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, + FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); + /* If mapping failed, close the shared memory handle and erase it */ + if( !pFile->shared ){ + pFile->lastErrno = osGetLastError(); + winLogError(SQLITE_IOERR, pFile->lastErrno, + "winceCreateLock2", zFilename); + bLogged = TRUE; + osCloseHandle(pFile->hShared); + pFile->hShared = NULL; + } + } + + /* If shared memory could not be created, then close the mutex and fail */ + if( pFile->hShared==NULL ){ + if( !bLogged ){ + pFile->lastErrno = lastErrno; + winLogError(SQLITE_IOERR, pFile->lastErrno, + "winceCreateLock3", zFilename); + bLogged = TRUE; + } + winceMutexRelease(pFile->hMutex); + osCloseHandle(pFile->hMutex); + pFile->hMutex = NULL; + return SQLITE_IOERR; + } + + /* Initialize the shared memory if we're supposed to */ + if( bInit ){ + memset(pFile->shared, 0, sizeof(winceLock)); + } + + winceMutexRelease(pFile->hMutex); + return SQLITE_OK; +} + +/* +** Destroy the part of winFile that deals with wince locks +*/ +static void winceDestroyLock(winFile *pFile){ + if (pFile->hMutex){ + /* Acquire the mutex */ + winceMutexAcquire(pFile->hMutex); + + /* The following blocks should probably assert in debug mode, but they + are to cleanup in case any locks remained open */ + if (pFile->local.nReaders){ + pFile->shared->nReaders --; + } + if (pFile->local.bReserved){ + pFile->shared->bReserved = FALSE; + } + if (pFile->local.bPending){ + pFile->shared->bPending = FALSE; + } + if (pFile->local.bExclusive){ + pFile->shared->bExclusive = FALSE; + } + + /* De-reference and close our copy of the shared memory handle */ + osUnmapViewOfFile(pFile->shared); + osCloseHandle(pFile->hShared); + + /* Done with the mutex */ + winceMutexRelease(pFile->hMutex); + osCloseHandle(pFile->hMutex); + pFile->hMutex = NULL; + } +} + +/* +** An implementation of the LockFile() API of Windows for CE +*/ +static BOOL winceLockFile( + LPHANDLE phFile, + DWORD dwFileOffsetLow, + DWORD dwFileOffsetHigh, + DWORD nNumberOfBytesToLockLow, + DWORD nNumberOfBytesToLockHigh +){ + winFile *pFile = HANDLE_TO_WINFILE(phFile); + BOOL bReturn = FALSE; + + UNUSED_PARAMETER(dwFileOffsetHigh); + UNUSED_PARAMETER(nNumberOfBytesToLockHigh); + + if (!pFile->hMutex) return TRUE; + winceMutexAcquire(pFile->hMutex); + + /* Wanting an exclusive lock? */ + if (dwFileOffsetLow == (DWORD)SHARED_FIRST + && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){ + if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ + pFile->shared->bExclusive = TRUE; + pFile->local.bExclusive = TRUE; + bReturn = TRUE; + } + } + + /* Want a read-only lock? */ + else if (dwFileOffsetLow == (DWORD)SHARED_FIRST && + nNumberOfBytesToLockLow == 1){ + if (pFile->shared->bExclusive == 0){ + pFile->local.nReaders ++; + if (pFile->local.nReaders == 1){ + pFile->shared->nReaders ++; + } + bReturn = TRUE; + } + } + + /* Want a pending lock? */ + else if (dwFileOffsetLow == (DWORD)PENDING_BYTE + && nNumberOfBytesToLockLow == 1){ + /* If no pending lock has been acquired, then acquire it */ + if (pFile->shared->bPending == 0) { + pFile->shared->bPending = TRUE; + pFile->local.bPending = TRUE; + bReturn = TRUE; + } + } + + /* Want a reserved lock? */ + else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE + && nNumberOfBytesToLockLow == 1){ + if (pFile->shared->bReserved == 0) { + pFile->shared->bReserved = TRUE; + pFile->local.bReserved = TRUE; + bReturn = TRUE; + } + } + + winceMutexRelease(pFile->hMutex); + return bReturn; +} + +/* +** An implementation of the UnlockFile API of Windows for CE +*/ +static BOOL winceUnlockFile( + LPHANDLE phFile, + DWORD dwFileOffsetLow, + DWORD dwFileOffsetHigh, + DWORD nNumberOfBytesToUnlockLow, + DWORD nNumberOfBytesToUnlockHigh +){ + winFile *pFile = HANDLE_TO_WINFILE(phFile); + BOOL bReturn = FALSE; + + UNUSED_PARAMETER(dwFileOffsetHigh); + UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh); + + if (!pFile->hMutex) return TRUE; + winceMutexAcquire(pFile->hMutex); + + /* Releasing a reader lock or an exclusive lock */ + if (dwFileOffsetLow == (DWORD)SHARED_FIRST){ + /* Did we have an exclusive lock? */ + if (pFile->local.bExclusive){ + assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE); + pFile->local.bExclusive = FALSE; + pFile->shared->bExclusive = FALSE; + bReturn = TRUE; + } + + /* Did we just have a reader lock? */ + else if (pFile->local.nReaders){ + assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE + || nNumberOfBytesToUnlockLow == 1); + pFile->local.nReaders --; + if (pFile->local.nReaders == 0) + { + pFile->shared->nReaders --; + } + bReturn = TRUE; + } + } + + /* Releasing a pending lock */ + else if (dwFileOffsetLow == (DWORD)PENDING_BYTE + && nNumberOfBytesToUnlockLow == 1){ + if (pFile->local.bPending){ + pFile->local.bPending = FALSE; + pFile->shared->bPending = FALSE; + bReturn = TRUE; + } + } + /* Releasing a reserved lock */ + else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE + && nNumberOfBytesToUnlockLow == 1){ + if (pFile->local.bReserved) { + pFile->local.bReserved = FALSE; + pFile->shared->bReserved = FALSE; + bReturn = TRUE; + } + } + + winceMutexRelease(pFile->hMutex); + return bReturn; +} +/* +** End of the special code for wince +*****************************************************************************/ +#endif /* SQLITE_OS_WINCE */ + +/* +** Lock a file region. +*/ +static BOOL winLockFile( + LPHANDLE phFile, + DWORD flags, + DWORD offsetLow, + DWORD offsetHigh, + DWORD numBytesLow, + DWORD numBytesHigh +){ +#if SQLITE_OS_WINCE + /* + ** NOTE: Windows CE is handled differently here due its lack of the Win32 + ** API LockFile. + */ + return winceLockFile(phFile, offsetLow, offsetHigh, + numBytesLow, numBytesHigh); +#else + if( osIsNT() ){ + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offsetLow; + ovlp.OffsetHigh = offsetHigh; + return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); + }else{ + return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, + numBytesHigh); + } +#endif +} + +/* +** Unlock a file region. + */ +static BOOL winUnlockFile( + LPHANDLE phFile, + DWORD offsetLow, + DWORD offsetHigh, + DWORD numBytesLow, + DWORD numBytesHigh +){ +#if SQLITE_OS_WINCE + /* + ** NOTE: Windows CE is handled differently here due its lack of the Win32 + ** API UnlockFile. + */ + return winceUnlockFile(phFile, offsetLow, offsetHigh, + numBytesLow, numBytesHigh); +#else + if( osIsNT() ){ + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offsetLow; + ovlp.OffsetHigh = offsetHigh; + return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); + }else{ + return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, + numBytesHigh); + } +#endif +} + +/***************************************************************************** +** The next group of routines implement the I/O methods specified +** by the sqlite3_io_methods object. +******************************************************************************/ + +/* +** Some Microsoft compilers lack this definition. +*/ +#ifndef INVALID_SET_FILE_POINTER +# define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +/* +** Move the current position of the file handle passed as the first +** argument to offset iOffset within the file. If successful, return 0. +** Otherwise, set pFile->lastErrno and return non-zero. +*/ +static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ +#if !SQLITE_OS_WINRT + LONG upperBits; /* Most sig. 32 bits of new offset */ + LONG lowerBits; /* Least sig. 32 bits of new offset */ + DWORD dwRet; /* Value returned by SetFilePointer() */ + DWORD lastErrno; /* Value returned by GetLastError() */ + + OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset)); + + upperBits = (LONG)((iOffset>>32) & 0x7fffffff); + lowerBits = (LONG)(iOffset & 0xffffffff); + + /* API oddity: If successful, SetFilePointer() returns a dword + ** containing the lower 32-bits of the new file-offset. Or, if it fails, + ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, + ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine + ** whether an error has actually occurred, it is also necessary to call + ** GetLastError(). + */ + dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); + + if( (dwRet==INVALID_SET_FILE_POINTER + && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ + pFile->lastErrno = lastErrno; + winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, + "winSeekFile", pFile->zPath); + OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); + return 1; + } + + OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); + return 0; +#else + /* + ** Same as above, except that this implementation works for WinRT. + */ + + LARGE_INTEGER x; /* The new offset */ + BOOL bRet; /* Value returned by SetFilePointerEx() */ + + x.QuadPart = iOffset; + bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); + + if(!bRet){ + pFile->lastErrno = osGetLastError(); + winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, + "winSeekFile", pFile->zPath); + OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); + return 1; + } + + OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); + return 0; +#endif +} + +#if SQLITE_MAX_MMAP_SIZE>0 +/* Forward references to VFS helper methods used for memory mapped files */ +static int winMapfile(winFile*, sqlite3_int64); +static int winUnmapfile(winFile*); +#endif + +/* +** Close a file. +** +** It is reported that an attempt to close a handle might sometimes +** fail. This is a very unreasonable result, but Windows is notorious +** for being unreasonable so I do not doubt that it might happen. If +** the close fails, we pause for 100 milliseconds and try again. As +** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before +** giving up and returning an error. +*/ +#define MX_CLOSE_ATTEMPT 3 +static int winClose(sqlite3_file *id){ + int rc, cnt = 0; + winFile *pFile = (winFile*)id; + + assert( id!=0 ); +#ifndef SQLITE_OMIT_WAL + assert( pFile->pShm==0 ); +#endif + assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); + OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n", + osGetCurrentProcessId(), pFile, pFile->h)); + +#if SQLITE_MAX_MMAP_SIZE>0 + winUnmapfile(pFile); +#endif + + do{ + rc = osCloseHandle(pFile->h); + /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ + }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); +#if SQLITE_OS_WINCE +#define WINCE_DELETION_ATTEMPTS 3 + { + winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData; + if( pAppData==NULL || !pAppData->bNoLock ){ + winceDestroyLock(pFile); + } + } + if( pFile->zDeleteOnClose ){ + int cnt = 0; + while( + osDeleteFileW(pFile->zDeleteOnClose)==0 + && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff + && cnt++ < WINCE_DELETION_ATTEMPTS + ){ + sqlite3_win32_sleep(100); /* Wait a little before trying again */ + } + sqlite3_free(pFile->zDeleteOnClose); + } +#endif + if( rc ){ + pFile->h = NULL; + } + OpenCounter(-1); + OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n", + osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed")); + return rc ? SQLITE_OK + : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(), + "winClose", pFile->zPath); +} + +/* +** Read data from a file into a buffer. Return SQLITE_OK if all +** bytes were read successfully and SQLITE_IOERR if anything goes +** wrong. +*/ +static int winRead( + sqlite3_file *id, /* File to read from */ + void *pBuf, /* Write content into this buffer */ + int amt, /* Number of bytes to read */ + sqlite3_int64 offset /* Begin reading at this offset */ +){ +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) + OVERLAPPED overlapped; /* The offset for ReadFile. */ +#endif + winFile *pFile = (winFile*)id; /* file handle */ + DWORD nRead; /* Number of bytes actually read from file */ + int nRetry = 0; /* Number of retrys */ + + assert( id!=0 ); + assert( amt>0 ); + assert( offset>=0 ); + SimulateIOError(return SQLITE_IOERR_READ); + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " + "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, + pFile->h, pBuf, amt, offset, pFile->locktype)); + +#if SQLITE_MAX_MMAP_SIZE>0 + /* Deal with as much of this read request as possible by transfering + ** data from the memory mapping using memcpy(). */ + if( offsetmmapSize ){ + if( offset+amt <= pFile->mmapSize ){ + memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); + OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_OK; + }else{ + int nCopy = (int)(pFile->mmapSize - offset); + memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); + pBuf = &((u8 *)pBuf)[nCopy]; + amt -= nCopy; + offset += nCopy; + } + } +#endif + +#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) + if( winSeekFile(pFile, offset) ){ + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_FULL; + } + while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ +#else + memset(&overlapped, 0, sizeof(OVERLAPPED)); + overlapped.Offset = (LONG)(offset & 0xffffffff); + overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); + while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) && + osGetLastError()!=ERROR_HANDLE_EOF ){ +#endif + DWORD lastErrno; + if( winRetryIoerr(&nRetry, &lastErrno) ) continue; + pFile->lastErrno = lastErrno; + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return winLogError(SQLITE_IOERR_READ, pFile->lastErrno, + "winRead", pFile->zPath); + } + winLogIoerr(nRetry, __LINE__); + if( nRead<(DWORD)amt ){ + /* Unread parts of the buffer must be zero-filled */ + memset(&((char*)pBuf)[nRead], 0, amt-nRead); + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_IOERR_SHORT_READ; + } + + OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_OK; +} + +/* +** Write data from a buffer into a file. Return SQLITE_OK on success +** or some other error code on failure. +*/ +static int winWrite( + sqlite3_file *id, /* File to write into */ + const void *pBuf, /* The bytes to be written */ + int amt, /* Number of bytes to write */ + sqlite3_int64 offset /* Offset into the file to begin writing at */ +){ + int rc = 0; /* True if error has occurred, else false */ + winFile *pFile = (winFile*)id; /* File handle */ + int nRetry = 0; /* Number of retries */ + + assert( amt>0 ); + assert( pFile ); + SimulateIOError(return SQLITE_IOERR_WRITE); + SimulateDiskfullError(return SQLITE_FULL); + + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " + "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, + pFile->h, pBuf, amt, offset, pFile->locktype)); + +#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 + /* Deal with as much of this write request as possible by transfering + ** data from the memory mapping using memcpy(). */ + if( offsetmmapSize ){ + if( offset+amt <= pFile->mmapSize ){ + memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); + OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_OK; + }else{ + int nCopy = (int)(pFile->mmapSize - offset); + memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); + pBuf = &((u8 *)pBuf)[nCopy]; + amt -= nCopy; + offset += nCopy; + } + } +#endif + +#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) + rc = winSeekFile(pFile, offset); + if( rc==0 ){ +#else + { +#endif +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) + OVERLAPPED overlapped; /* The offset for WriteFile. */ +#endif + u8 *aRem = (u8 *)pBuf; /* Data yet to be written */ + int nRem = amt; /* Number of bytes yet to be written */ + DWORD nWrite; /* Bytes written by each WriteFile() call */ + DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */ + +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) + memset(&overlapped, 0, sizeof(OVERLAPPED)); + overlapped.Offset = (LONG)(offset & 0xffffffff); + overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); +#endif + + while( nRem>0 ){ +#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) + if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){ +#else + if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){ +#endif + if( winRetryIoerr(&nRetry, &lastErrno) ) continue; + break; + } + assert( nWrite==0 || nWrite<=(DWORD)nRem ); + if( nWrite==0 || nWrite>(DWORD)nRem ){ + lastErrno = osGetLastError(); + break; + } +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) + offset += nWrite; + overlapped.Offset = (LONG)(offset & 0xffffffff); + overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); +#endif + aRem += nWrite; + nRem -= nWrite; + } + if( nRem>0 ){ + pFile->lastErrno = lastErrno; + rc = 1; + } + } + + if( rc ){ + if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) + || ( pFile->lastErrno==ERROR_DISK_FULL )){ + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return winLogError(SQLITE_FULL, pFile->lastErrno, + "winWrite1", pFile->zPath); + } + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, + "winWrite2", pFile->zPath); + }else{ + winLogIoerr(nRetry, __LINE__); + } + OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_OK; +} + +/* +** Truncate an open file to a specified size +*/ +static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ + winFile *pFile = (winFile*)id; /* File handle object */ + int rc = SQLITE_OK; /* Return code for this function */ + DWORD lastErrno; + + assert( pFile ); + SimulateIOError(return SQLITE_IOERR_TRUNCATE); + OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n", + osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype)); + + /* If the user has configured a chunk-size for this file, truncate the + ** file so that it consists of an integer number of chunks (i.e. the + ** actual file size after the operation may be larger than the requested + ** size). + */ + if( pFile->szChunk>0 ){ + nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; + } + + /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ + if( winSeekFile(pFile, nByte) ){ + rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, + "winTruncate1", pFile->zPath); + }else if( 0==osSetEndOfFile(pFile->h) && + ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){ + pFile->lastErrno = lastErrno; + rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, + "winTruncate2", pFile->zPath); + } + +#if SQLITE_MAX_MMAP_SIZE>0 + /* If the file was truncated to a size smaller than the currently + ** mapped region, reduce the effective mapping size as well. SQLite will + ** use read() and write() to access data beyond this point from now on. + */ + if( pFile->pMapRegion && nBytemmapSize ){ + pFile->mmapSize = nByte; + } +#endif + + OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n", + osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc))); + return rc; +} + +#ifdef SQLITE_TEST +/* +** Count the number of fullsyncs and normal syncs. This is used to test +** that syncs and fullsyncs are occuring at the right times. +*/ +SQLITE_API int sqlite3_sync_count = 0; +SQLITE_API int sqlite3_fullsync_count = 0; +#endif + +/* +** Make sure all writes to a particular file are committed to disk. +*/ +static int winSync(sqlite3_file *id, int flags){ +#ifndef SQLITE_NO_SYNC + /* + ** Used only when SQLITE_NO_SYNC is not defined. + */ + BOOL rc; +#endif +#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \ + defined(SQLITE_HAVE_OS_TRACE) + /* + ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or + ** OSTRACE() macros. + */ + winFile *pFile = (winFile*)id; +#else + UNUSED_PARAMETER(id); +#endif + + assert( pFile ); + /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ + assert((flags&0x0F)==SQLITE_SYNC_NORMAL + || (flags&0x0F)==SQLITE_SYNC_FULL + ); + + /* Unix cannot, but some systems may return SQLITE_FULL from here. This + ** line is to test that doing so does not cause any problems. + */ + SimulateDiskfullError( return SQLITE_FULL ); + + OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n", + osGetCurrentProcessId(), pFile, pFile->h, flags, + pFile->locktype)); + +#ifndef SQLITE_TEST + UNUSED_PARAMETER(flags); +#else + if( (flags&0x0F)==SQLITE_SYNC_FULL ){ + sqlite3_fullsync_count++; + } + sqlite3_sync_count++; +#endif + + /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a + ** no-op + */ +#ifdef SQLITE_NO_SYNC + OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_OK; +#else +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->pMapRegion ){ + if( osFlushViewOfFile(pFile->pMapRegion, 0) ){ + OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " + "rc=SQLITE_OK\n", osGetCurrentProcessId(), + pFile, pFile->pMapRegion)); + }else{ + pFile->lastErrno = osGetLastError(); + OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " + "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), + pFile, pFile->pMapRegion)); + return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, + "winSync1", pFile->zPath); + } + } +#endif + rc = osFlushFileBuffers(pFile->h); + SimulateIOError( rc=FALSE ); + if( rc ){ + OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return SQLITE_OK; + }else{ + pFile->lastErrno = osGetLastError(); + OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n", + osGetCurrentProcessId(), pFile, pFile->h)); + return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno, + "winSync2", pFile->zPath); + } +#endif +} + +/* +** Determine the current size of a file in bytes +*/ +static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ + winFile *pFile = (winFile*)id; + int rc = SQLITE_OK; + + assert( id!=0 ); + assert( pSize!=0 ); + SimulateIOError(return SQLITE_IOERR_FSTAT); + OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); + +#if SQLITE_OS_WINRT + { + FILE_STANDARD_INFO info; + if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo, + &info, sizeof(info)) ){ + *pSize = info.EndOfFile.QuadPart; + }else{ + pFile->lastErrno = osGetLastError(); + rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, + "winFileSize", pFile->zPath); + } + } +#else + { + DWORD upperBits; + DWORD lowerBits; + DWORD lastErrno; + + lowerBits = osGetFileSize(pFile->h, &upperBits); + *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; + if( (lowerBits == INVALID_FILE_SIZE) + && ((lastErrno = osGetLastError())!=NO_ERROR) ){ + pFile->lastErrno = lastErrno; + rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, + "winFileSize", pFile->zPath); + } + } +#endif + OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", + pFile->h, pSize, *pSize, sqlite3ErrName(rc))); + return rc; +} + +/* +** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. +*/ +#ifndef LOCKFILE_FAIL_IMMEDIATELY +# define LOCKFILE_FAIL_IMMEDIATELY 1 +#endif + +#ifndef LOCKFILE_EXCLUSIVE_LOCK +# define LOCKFILE_EXCLUSIVE_LOCK 2 +#endif + +/* +** Historically, SQLite has used both the LockFile and LockFileEx functions. +** When the LockFile function was used, it was always expected to fail +** immediately if the lock could not be obtained. Also, it always expected to +** obtain an exclusive lock. These flags are used with the LockFileEx function +** and reflect those expectations; therefore, they should not be changed. +*/ +#ifndef SQLITE_LOCKFILE_FLAGS +# define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \ + LOCKFILE_EXCLUSIVE_LOCK) +#endif + +/* +** Currently, SQLite never calls the LockFileEx function without wanting the +** call to fail immediately if the lock cannot be obtained. +*/ +#ifndef SQLITE_LOCKFILEEX_FLAGS +# define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY) +#endif + +/* +** Acquire a reader lock. +** Different API routines are called depending on whether or not this +** is Win9x or WinNT. +*/ +static int winGetReadLock(winFile *pFile){ + int res; + OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); + if( osIsNT() ){ +#if SQLITE_OS_WINCE + /* + ** NOTE: Windows CE is handled differently here due its lack of the Win32 + ** API LockFileEx. + */ + res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); +#else + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0, + SHARED_SIZE, 0); +#endif + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + int lk; + sqlite3_randomness(sizeof(lk), &lk); + pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, + SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); + } +#endif + if( res == 0 ){ + pFile->lastErrno = osGetLastError(); + /* No need to log a failure to lock */ + } + OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res)); + return res; +} + +/* +** Undo a readlock +*/ +static int winUnlockReadLock(winFile *pFile){ + int res; + DWORD lastErrno; + OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); + if( osIsNT() ){ + res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); + } +#endif + if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ + pFile->lastErrno = lastErrno; + winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, + "winUnlockReadLock", pFile->zPath); + } + OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res)); + return res; +} + +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** (1) SHARED_LOCK +** (2) RESERVED_LOCK +** (3) PENDING_LOCK +** (4) EXCLUSIVE_LOCK +** +** Sometimes when requesting one lock state, additional lock states +** are inserted in between. The locking might fail on one of the later +** transitions leaving the lock state different from what it started but +** still short of its goal. The following chart shows the allowed +** transitions and the inserted intermediate states: +** +** UNLOCKED -> SHARED +** SHARED -> RESERVED +** SHARED -> (PENDING) -> EXCLUSIVE +** RESERVED -> (PENDING) -> EXCLUSIVE +** PENDING -> EXCLUSIVE +** +** This routine will only increase a lock. The winUnlock() routine +** erases all locks at once and returns us immediately to locking level 0. +** It is not possible to lower the locking level one step at a time. You +** must go straight to locking level 0. +*/ +static int winLock(sqlite3_file *id, int locktype){ + int rc = SQLITE_OK; /* Return code from subroutines */ + int res = 1; /* Result of a Windows lock call */ + int newLocktype; /* Set pFile->locktype to this value before exiting */ + int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ + winFile *pFile = (winFile*)id; + DWORD lastErrno = NO_ERROR; + + assert( id!=0 ); + OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n", + pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); + + /* If there is already a lock of this type or more restrictive on the + ** OsFile, do nothing. Don't use the end_lock: exit path, as + ** sqlite3OsEnterMutex() hasn't been called yet. + */ + if( pFile->locktype>=locktype ){ + OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + + /* Do not allow any kind of write-lock on a read-only database + */ + if( (pFile->ctrlFlags & WINFILE_RDONLY)!=0 && locktype>=RESERVED_LOCK ){ + return SQLITE_IOERR_LOCK; + } + + /* Make sure the locking sequence is correct + */ + assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); + assert( locktype!=PENDING_LOCK ); + assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); + + /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or + ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of + ** the PENDING_LOCK byte is temporary. + */ + newLocktype = pFile->locktype; + if( pFile->locktype==NO_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK) + ){ + int cnt = 3; + while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, + PENDING_BYTE, 0, 1, 0))==0 ){ + /* Try 3 times to get the pending lock. This is needed to work + ** around problems caused by indexing and/or anti-virus software on + ** Windows systems. + ** If you are using this code as a model for alternative VFSes, do not + ** copy this retry logic. It is a hack intended for Windows only. + */ + lastErrno = osGetLastError(); + OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", + pFile->h, cnt, res)); + if( lastErrno==ERROR_INVALID_HANDLE ){ + pFile->lastErrno = lastErrno; + rc = SQLITE_IOERR_LOCK; + OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", + pFile->h, cnt, sqlite3ErrName(rc))); + return rc; + } + if( cnt ) sqlite3_win32_sleep(1); + } + gotPendingLock = res; + if( !res ){ + lastErrno = osGetLastError(); + } + } + + /* Acquire a shared lock + */ + if( locktype==SHARED_LOCK && res ){ + assert( pFile->locktype==NO_LOCK ); + res = winGetReadLock(pFile); + if( res ){ + newLocktype = SHARED_LOCK; + }else{ + lastErrno = osGetLastError(); + } + } + + /* Acquire a RESERVED lock + */ + if( locktype==RESERVED_LOCK && res ){ + assert( pFile->locktype==SHARED_LOCK ); + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0); + if( res ){ + newLocktype = RESERVED_LOCK; + }else{ + lastErrno = osGetLastError(); + } + } + + /* Acquire a PENDING lock + */ + if( locktype==EXCLUSIVE_LOCK && res ){ + newLocktype = PENDING_LOCK; + gotPendingLock = 0; + } + + /* Acquire an EXCLUSIVE lock + */ + if( locktype==EXCLUSIVE_LOCK && res ){ + assert( pFile->locktype>=SHARED_LOCK ); + res = winUnlockReadLock(pFile); + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0, + SHARED_SIZE, 0); + if( res ){ + newLocktype = EXCLUSIVE_LOCK; + }else{ + lastErrno = osGetLastError(); + winGetReadLock(pFile); + } + } + + /* If we are holding a PENDING lock that ought to be released, then + ** release it now. + */ + if( gotPendingLock && locktype==SHARED_LOCK ){ + winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); + } + + /* Update the state of the lock has held in the file descriptor then + ** return the appropriate result code. + */ + if( res ){ + rc = SQLITE_OK; + }else{ + pFile->lastErrno = lastErrno; + rc = SQLITE_BUSY; + OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n", + pFile->h, locktype, newLocktype)); + } + pFile->locktype = (u8)newLocktype; + OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n", + pFile->h, pFile->locktype, sqlite3ErrName(rc))); + return rc; +} + +/* +** This routine checks if there is a RESERVED lock held on the specified +** file by this or any other process. If such a lock is held, return +** non-zero, otherwise zero. +*/ +static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ + int res; + winFile *pFile = (winFile*)id; + + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); + OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut)); + + assert( id!=0 ); + if( pFile->locktype>=RESERVED_LOCK ){ + res = 1; + OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res)); + }else{ + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0); + if( res ){ + winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); + } + res = !res; + OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res)); + } + *pResOut = res; + OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", + pFile->h, pResOut, *pResOut)); + return SQLITE_OK; +} + +/* +** Lower the locking level on file descriptor id to locktype. locktype +** must be either NO_LOCK or SHARED_LOCK. +** +** If the locking level of the file descriptor is already at or below +** the requested locking level, this routine is a no-op. +** +** It is not possible for this routine to fail if the second argument +** is NO_LOCK. If the second argument is SHARED_LOCK then this routine +** might return SQLITE_IOERR; +*/ +static int winUnlock(sqlite3_file *id, int locktype){ + int type; + winFile *pFile = (winFile*)id; + int rc = SQLITE_OK; + assert( pFile!=0 ); + assert( locktype<=SHARED_LOCK ); + OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n", + pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); + type = pFile->locktype; + if( type>=EXCLUSIVE_LOCK ){ + winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){ + /* This should never happen. We should always be able to + ** reacquire the read lock */ + rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), + "winUnlock", pFile->zPath); + } + } + if( type>=RESERVED_LOCK ){ + winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); + } + if( locktype==NO_LOCK && type>=SHARED_LOCK ){ + winUnlockReadLock(pFile); + } + if( type>=PENDING_LOCK ){ + winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); + } + pFile->locktype = (u8)locktype; + OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n", + pFile->h, pFile->locktype, sqlite3ErrName(rc))); + return rc; +} + +/****************************************************************************** +****************************** No-op Locking ********************************** +** +** Of the various locking implementations available, this is by far the +** simplest: locking is ignored. No attempt is made to lock the database +** file for reading or writing. +** +** This locking mode is appropriate for use on read-only databases +** (ex: databases that are burned into CD-ROM, for example.) It can +** also be used if the application employs some external mechanism to +** prevent simultaneous access of the same database by two or more +** database connections. But there is a serious risk of database +** corruption if this locking mode is used in situations where multiple +** database connections are accessing the same database file at the same +** time and one or more of those connections are writing. +*/ + +static int winNolockLock(sqlite3_file *id, int locktype){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(locktype); + return SQLITE_OK; +} + +static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(pResOut); + return SQLITE_OK; +} + +static int winNolockUnlock(sqlite3_file *id, int locktype){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(locktype); + return SQLITE_OK; +} + +/******************* End of the no-op lock implementation ********************* +******************************************************************************/ + +/* +** If *pArg is initially negative then this is a query. Set *pArg to +** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. +** +** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. +*/ +static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ + if( *pArg<0 ){ + *pArg = (pFile->ctrlFlags & mask)!=0; + }else if( (*pArg)==0 ){ + pFile->ctrlFlags &= ~mask; + }else{ + pFile->ctrlFlags |= mask; + } +} + +/* Forward references to VFS helper methods used for temporary files */ +static int winGetTempname(sqlite3_vfs *, char **); +static int winIsDir(const void *); +static BOOL winIsDriveLetterAndColon(const char *); + +/* +** Control and query of the open file handle. +*/ +static int winFileControl(sqlite3_file *id, int op, void *pArg){ + winFile *pFile = (winFile*)id; + OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg)); + switch( op ){ + case SQLITE_FCNTL_LOCKSTATE: { + *(int*)pArg = pFile->locktype; + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_LAST_ERRNO: { + *(int*)pArg = (int)pFile->lastErrno; + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_CHUNK_SIZE: { + pFile->szChunk = *(int *)pArg; + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_SIZE_HINT: { + if( pFile->szChunk>0 ){ + sqlite3_int64 oldSz; + int rc = winFileSize(id, &oldSz); + if( rc==SQLITE_OK ){ + sqlite3_int64 newSz = *(sqlite3_int64*)pArg; + if( newSz>oldSz ){ + SimulateIOErrorBenign(1); + rc = winTruncate(id, newSz); + SimulateIOErrorBenign(0); + } + } + OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); + return rc; + } + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_PERSIST_WAL: { + winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg); + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { + winModeBit(pFile, WINFILE_PSOW, (int*)pArg); + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_VFSNAME: { + *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName); + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_WIN32_AV_RETRY: { + int *a = (int*)pArg; + if( a[0]>0 ){ + winIoerrRetry = a[0]; + }else{ + a[0] = winIoerrRetry; + } + if( a[1]>0 ){ + winIoerrRetryDelay = a[1]; + }else{ + a[1] = winIoerrRetryDelay; + } + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } + case SQLITE_FCNTL_WIN32_GET_HANDLE: { + LPHANDLE phFile = (LPHANDLE)pArg; + *phFile = pFile->h; + OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); + return SQLITE_OK; + } +#ifdef SQLITE_TEST + case SQLITE_FCNTL_WIN32_SET_HANDLE: { + LPHANDLE phFile = (LPHANDLE)pArg; + HANDLE hOldFile = pFile->h; + pFile->h = *phFile; + *phFile = hOldFile; + OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n", + hOldFile, pFile->h)); + return SQLITE_OK; + } +#endif + case SQLITE_FCNTL_TEMPFILENAME: { + char *zTFile = 0; + int rc = winGetTempname(pFile->pVfs, &zTFile); + if( rc==SQLITE_OK ){ + *(char**)pArg = zTFile; + } + OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); + return rc; + } +#if SQLITE_MAX_MMAP_SIZE>0 + case SQLITE_FCNTL_MMAP_SIZE: { + i64 newLimit = *(i64*)pArg; + int rc = SQLITE_OK; + if( newLimit>sqlite3GlobalConfig.mxMmap ){ + newLimit = sqlite3GlobalConfig.mxMmap; + } + *(i64*)pArg = pFile->mmapSizeMax; + if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ + pFile->mmapSizeMax = newLimit; + if( pFile->mmapSize>0 ){ + winUnmapfile(pFile); + rc = winMapfile(pFile, -1); + } + } + OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); + return rc; + } +#endif + } + OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h)); + return SQLITE_NOTFOUND; +} + +/* +** 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 winSectorSize(sqlite3_file *id){ + (void)id; + return SQLITE_DEFAULT_SECTOR_SIZE; +} + +/* +** Return a vector of device characteristics. +*/ +static int winDeviceCharacteristics(sqlite3_file *id){ + winFile *p = (winFile*)id; + return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | + ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); +} + +/* +** Windows will only let you create file view mappings +** on allocation size granularity boundaries. +** During sqlite3_os_init() we do a GetSystemInfo() +** to get the granularity size. +*/ +static SYSTEM_INFO winSysInfo; + +#ifndef SQLITE_OMIT_WAL + +/* +** Helper functions to obtain and relinquish the global mutex. The +** global mutex is used to protect the winLockInfo objects used by +** this file, all of which may be shared by multiple threads. +** +** Function winShmMutexHeld() is used to assert() that the global mutex +** is held when required. This function is only used as part of assert() +** statements. e.g. +** +** winShmEnterMutex() +** assert( winShmMutexHeld() ); +** winShmLeaveMutex() +*/ +static void winShmEnterMutex(void){ + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); +} +static void winShmLeaveMutex(void){ + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); +} +#ifndef NDEBUG +static int winShmMutexHeld(void) { + return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); +} +#endif + +/* +** Object used to represent a single file opened and mmapped to provide +** shared memory. When multiple threads all reference the same +** log-summary, each thread has its own winFile object, but they all +** point to a single instance of this object. In other words, each +** log-summary is opened only once per process. +** +** winShmMutexHeld() must be true when creating or destroying +** this object or while reading or writing the following fields: +** +** nRef +** pNext +** +** The following fields are read-only after the object is created: +** +** fid +** zFilename +** +** Either winShmNode.mutex must be held or winShmNode.nRef==0 and +** winShmMutexHeld() is true when reading or writing any other field +** in this structure. +** +*/ +struct winShmNode { + sqlite3_mutex *mutex; /* Mutex to access this object */ + char *zFilename; /* Name of the file */ + winFile hFile; /* File handle from winOpen */ + + int szRegion; /* Size of shared-memory regions */ + int nRegion; /* Size of array apRegion */ + struct ShmRegion { + HANDLE hMap; /* File handle from CreateFileMapping */ + void *pMap; + } *aRegion; + DWORD lastErrno; /* The Windows errno from the last I/O error */ + + int nRef; /* Number of winShm objects pointing to this */ + winShm *pFirst; /* All winShm objects pointing to this */ + winShmNode *pNext; /* Next in list of all winShmNode objects */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) + u8 nextShmId; /* Next available winShm.id value */ +#endif +}; + +/* +** A global array of all winShmNode objects. +** +** The winShmMutexHeld() must be true while reading or writing this list. +*/ +static winShmNode *winShmNodeList = 0; + +/* +** Structure used internally by this VFS to record the state of an +** open shared memory connection. +** +** The following fields are initialized when this object is created and +** are read-only thereafter: +** +** winShm.pShmNode +** winShm.id +** +** All other fields are read/write. The winShm.pShmNode->mutex must be held +** while accessing any read/write fields. +*/ +struct winShm { + winShmNode *pShmNode; /* The underlying winShmNode object */ + winShm *pNext; /* Next winShm with the same winShmNode */ + u8 hasMutex; /* True if holding the winShmNode mutex */ + u16 sharedMask; /* Mask of shared locks held */ + u16 exclMask; /* Mask of exclusive locks held */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) + u8 id; /* Id of this connection with its winShmNode */ +#endif +}; + +/* +** Constants used for locking +*/ +#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ +#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ + +/* +** Apply advisory locks for all n bytes beginning at ofst. +*/ +#define WINSHM_UNLCK 1 +#define WINSHM_RDLCK 2 +#define WINSHM_WRLCK 3 +static int winShmSystemLock( + winShmNode *pFile, /* Apply locks to this open shared-memory segment */ + int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ + int ofst, /* Offset to first byte to be locked/unlocked */ + int nByte /* Number of bytes to lock or unlock */ +){ + int rc = 0; /* Result code form Lock/UnlockFileEx() */ + + /* Access to the winShmNode object is serialized by the caller */ + assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 ); + + OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", + pFile->hFile.h, lockType, ofst, nByte)); + + /* Release/Acquire the system-level lock */ + if( lockType==WINSHM_UNLCK ){ + rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); + }else{ + /* Initialize the locking parameters */ + DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; + if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); + } + + if( rc!= 0 ){ + rc = SQLITE_OK; + }else{ + pFile->lastErrno = osGetLastError(); + rc = SQLITE_BUSY; + } + + OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", + pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : + "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); + + return rc; +} + +/* Forward references to VFS methods */ +static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); +static int winDelete(sqlite3_vfs *,const char*,int); + +/* +** Purge the winShmNodeList list of all entries with winShmNode.nRef==0. +** +** This is not a VFS shared-memory method; it is a utility function called +** by VFS shared-memory methods. +*/ +static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ + winShmNode **pp; + winShmNode *p; + assert( winShmMutexHeld() ); + OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n", + osGetCurrentProcessId(), deleteFlag)); + pp = &winShmNodeList; + while( (p = *pp)!=0 ){ + if( p->nRef==0 ){ + int i; + if( p->mutex ){ sqlite3_mutex_free(p->mutex); } + for(i=0; inRegion; i++){ + BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap); + OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n", + osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); + UNUSED_VARIABLE_VALUE(bRc); + bRc = osCloseHandle(p->aRegion[i].hMap); + OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n", + osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); + UNUSED_VARIABLE_VALUE(bRc); + } + if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ + SimulateIOErrorBenign(1); + winClose((sqlite3_file *)&p->hFile); + SimulateIOErrorBenign(0); + } + if( deleteFlag ){ + SimulateIOErrorBenign(1); + sqlite3BeginBenignMalloc(); + winDelete(pVfs, p->zFilename, 0); + sqlite3EndBenignMalloc(); + SimulateIOErrorBenign(0); + } + *pp = p->pNext; + sqlite3_free(p->aRegion); + sqlite3_free(p); + }else{ + pp = &p->pNext; + } + } +} + +/* +** Open the shared-memory area associated with database file pDbFd. +** +** When opening a new shared-memory file, if no other instances of that +** file are currently open, in this process or in other processes, then +** the file must be truncated to zero length or have its header cleared. +*/ +static int winOpenSharedMemory(winFile *pDbFd){ + struct winShm *p; /* The connection to be opened */ + struct winShmNode *pShmNode = 0; /* The underlying mmapped file */ + int rc; /* Result code */ + struct winShmNode *pNew; /* Newly allocated winShmNode */ + int nName; /* Size of zName in bytes */ + + assert( pDbFd->pShm==0 ); /* Not previously opened */ + + /* Allocate space for the new sqlite3_shm object. Also speculatively + ** allocate space for a new winShmNode and filename. + */ + p = sqlite3MallocZero( sizeof(*p) ); + if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT; + nName = sqlite3Strlen30(pDbFd->zPath); + pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 ); + if( pNew==0 ){ + sqlite3_free(p); + return SQLITE_IOERR_NOMEM_BKPT; + } + pNew->zFilename = (char*)&pNew[1]; + sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); + sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); + + /* Look to see if there is an existing winShmNode that can be used. + ** If no matching winShmNode currently exists, create a new one. + */ + winShmEnterMutex(); + for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){ + /* TBD need to come up with better match here. Perhaps + ** use FILE_ID_BOTH_DIR_INFO Structure. + */ + if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break; + } + if( pShmNode ){ + sqlite3_free(pNew); + }else{ + pShmNode = pNew; + pNew = 0; + ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE; + pShmNode->pNext = winShmNodeList; + winShmNodeList = pShmNode; + + if( sqlite3GlobalConfig.bCoreMutex ){ + pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->mutex==0 ){ + rc = SQLITE_IOERR_NOMEM_BKPT; + goto shm_open_err; + } + } + + rc = winOpen(pDbFd->pVfs, + pShmNode->zFilename, /* Name of the file (UTF-8) */ + (sqlite3_file*)&pShmNode->hFile, /* File handle here */ + SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, + 0); + if( SQLITE_OK!=rc ){ + goto shm_open_err; + } + + /* Check to see if another process is holding the dead-man switch. + ** If not, truncate the file to zero length. + */ + if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ + rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); + if( rc!=SQLITE_OK ){ + rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), + "winOpenShm", pDbFd->zPath); + } + } + if( rc==SQLITE_OK ){ + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); + } + if( rc ) goto shm_open_err; + } + + /* Make the new connection a child of the winShmNode */ + p->pShmNode = pShmNode; +#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) + p->id = pShmNode->nextShmId++; +#endif + pShmNode->nRef++; + pDbFd->pShm = p; + winShmLeaveMutex(); + + /* The reference count on pShmNode has already been incremented under + ** the cover of the winShmEnterMutex() mutex and the pointer from the + ** new (struct winShm) object to the pShmNode has been set. All that is + ** left to do is to link the new object into the linked list starting + ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex + ** mutex. + */ + sqlite3_mutex_enter(pShmNode->mutex); + p->pNext = pShmNode->pFirst; + pShmNode->pFirst = p; + sqlite3_mutex_leave(pShmNode->mutex); + return SQLITE_OK; + + /* Jump here on any error */ +shm_open_err: + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ + sqlite3_free(p); + sqlite3_free(pNew); + winShmLeaveMutex(); + return rc; +} + +/* +** Close a connection to shared-memory. Delete the underlying +** storage if deleteFlag is true. +*/ +static int winShmUnmap( + sqlite3_file *fd, /* Database holding shared memory */ + int deleteFlag /* Delete after closing if true */ +){ + winFile *pDbFd; /* Database holding shared-memory */ + winShm *p; /* The connection to be closed */ + winShmNode *pShmNode; /* The underlying shared-memory file */ + winShm **pp; /* For looping over sibling connections */ + + pDbFd = (winFile*)fd; + p = pDbFd->pShm; + if( p==0 ) return SQLITE_OK; + pShmNode = p->pShmNode; + + /* Remove connection p from the set of connections associated + ** with pShmNode */ + sqlite3_mutex_enter(pShmNode->mutex); + for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} + *pp = p->pNext; + + /* Free the connection p */ + sqlite3_free(p); + pDbFd->pShm = 0; + sqlite3_mutex_leave(pShmNode->mutex); + + /* If pShmNode->nRef has reached 0, then close the underlying + ** shared-memory file, too */ + winShmEnterMutex(); + assert( pShmNode->nRef>0 ); + pShmNode->nRef--; + if( pShmNode->nRef==0 ){ + winShmPurge(pDbFd->pVfs, deleteFlag); + } + winShmLeaveMutex(); + + return SQLITE_OK; +} + +/* +** Change the lock state for a shared-memory segment. +*/ +static int winShmLock( + sqlite3_file *fd, /* Database file holding the shared memory */ + int ofst, /* First lock to acquire or release */ + int n, /* Number of locks to acquire or release */ + int flags /* What to do with the lock */ +){ + winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ + winShm *p = pDbFd->pShm; /* The shared memory being locked */ + winShm *pX; /* For looping over all siblings */ + winShmNode *pShmNode = p->pShmNode; + int rc = SQLITE_OK; /* Result code */ + u16 mask; /* Mask of locks to take or release */ + + assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); + assert( n>=1 ); + assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) + || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); + assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); + + mask = (u16)((1U<<(ofst+n)) - (1U<1 || mask==(1<mutex); + if( flags & SQLITE_SHM_UNLOCK ){ + u16 allMask = 0; /* Mask of locks held by siblings */ + + /* See if any siblings hold this same lock */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( pX==p ) continue; + assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); + allMask |= pX->sharedMask; + } + + /* Unlock the system-level locks */ + if( (mask & allMask)==0 ){ + rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n); + }else{ + rc = SQLITE_OK; + } + + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; + } + }else if( flags & SQLITE_SHM_SHARED ){ + u16 allShared = 0; /* Union of locks held by connections other than "p" */ + + /* Find out which shared locks are already held by sibling connections. + ** If any sibling already holds an exclusive lock, go ahead and return + ** SQLITE_BUSY. + */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( (pX->exclMask & mask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + allShared |= pX->sharedMask; + } + + /* Get shared locks at the system level, if necessary */ + if( rc==SQLITE_OK ){ + if( (allShared & mask)==0 ){ + rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); + }else{ + rc = SQLITE_OK; + } + } + + /* Get the local shared locks */ + if( rc==SQLITE_OK ){ + p->sharedMask |= mask; + } + }else{ + /* Make sure no sibling connections hold locks that will block this + ** lock. If any do, return SQLITE_BUSY right away. + */ + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ + rc = SQLITE_BUSY; + break; + } + } + + /* Get the exclusive locks at the system level. Then if successful + ** also mark the local connection as being locked. + */ + if( rc==SQLITE_OK ){ + rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); + if( rc==SQLITE_OK ){ + assert( (p->sharedMask & mask)==0 ); + p->exclMask |= mask; + } + } + } + sqlite3_mutex_leave(pShmNode->mutex); + OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n", + osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, + sqlite3ErrName(rc))); + return rc; +} + +/* +** Implement a memory barrier or memory fence on shared memory. +** +** All loads and stores begun before the barrier must complete before +** any load or store begun after the barrier. +*/ +static void winShmBarrier( + sqlite3_file *fd /* Database holding the shared memory */ +){ + UNUSED_PARAMETER(fd); + sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ + winShmEnterMutex(); /* Also mutex, for redundancy */ + winShmLeaveMutex(); +} + +/* +** This function is called to obtain a pointer to region iRegion of the +** shared-memory associated with the database file fd. Shared-memory regions +** are numbered starting from zero. Each shared-memory region is szRegion +** bytes in size. +** +** If an error occurs, an error code is returned and *pp is set to NULL. +** +** Otherwise, if the isWrite parameter is 0 and the requested shared-memory +** region has not been allocated (by any client, including one running in a +** separate process), then *pp is set to NULL and SQLITE_OK returned. If +** isWrite is non-zero and the requested shared-memory region has not yet +** been allocated, it is allocated by this function. +** +** If the shared-memory region has already been allocated or is allocated by +** this call as described above, then it is mapped into this processes +** address space (if it is not already), *pp is set to point to the mapped +** memory and SQLITE_OK returned. +*/ +static int winShmMap( + sqlite3_file *fd, /* Handle open on database file */ + int iRegion, /* Region to retrieve */ + int szRegion, /* Size of regions */ + int isWrite, /* True to extend file if necessary */ + void volatile **pp /* OUT: Mapped memory */ +){ + winFile *pDbFd = (winFile*)fd; + winShm *pShm = pDbFd->pShm; + winShmNode *pShmNode; + int rc = SQLITE_OK; + + if( !pShm ){ + rc = winOpenSharedMemory(pDbFd); + if( rc!=SQLITE_OK ) return rc; + pShm = pDbFd->pShm; + } + pShmNode = pShm->pShmNode; + + sqlite3_mutex_enter(pShmNode->mutex); + assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); + + if( pShmNode->nRegion<=iRegion ){ + struct ShmRegion *apNew; /* New aRegion[] array */ + int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ + sqlite3_int64 sz; /* Current size of wal-index file */ + + pShmNode->szRegion = szRegion; + + /* The requested region is not mapped into this processes address space. + ** Check to see if it has been allocated (i.e. if the wal-index file is + ** large enough to contain the requested region). + */ + rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); + if( rc!=SQLITE_OK ){ + rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), + "winShmMap1", pDbFd->zPath); + goto shmpage_out; + } + + if( szhFile, nByte); + if( rc!=SQLITE_OK ){ + rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), + "winShmMap2", pDbFd->zPath); + goto shmpage_out; + } + } + + /* Map the requested memory region into this processes address space. */ + apNew = (struct ShmRegion *)sqlite3_realloc64( + pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) + ); + if( !apNew ){ + rc = SQLITE_IOERR_NOMEM_BKPT; + goto shmpage_out; + } + pShmNode->aRegion = apNew; + + while( pShmNode->nRegion<=iRegion ){ + HANDLE hMap = NULL; /* file-mapping handle */ + void *pMap = 0; /* Mapped memory region */ + +#if SQLITE_OS_WINRT + hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, + NULL, PAGE_READWRITE, nByte, NULL + ); +#elif defined(SQLITE_WIN32_HAS_WIDE) + hMap = osCreateFileMappingW(pShmNode->hFile.h, + NULL, PAGE_READWRITE, 0, nByte, NULL + ); +#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA + hMap = osCreateFileMappingA(pShmNode->hFile.h, + NULL, PAGE_READWRITE, 0, nByte, NULL + ); +#endif + OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", + osGetCurrentProcessId(), pShmNode->nRegion, nByte, + hMap ? "ok" : "failed")); + if( hMap ){ + int iOffset = pShmNode->nRegion*szRegion; + int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; +#if SQLITE_OS_WINRT + pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ, + iOffset - iOffsetShift, szRegion + iOffsetShift + ); +#else + pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, + 0, iOffset - iOffsetShift, szRegion + iOffsetShift + ); +#endif + OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", + osGetCurrentProcessId(), pShmNode->nRegion, iOffset, + szRegion, pMap ? "ok" : "failed")); + } + if( !pMap ){ + pShmNode->lastErrno = osGetLastError(); + rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno, + "winShmMap3", pDbFd->zPath); + if( hMap ) osCloseHandle(hMap); + goto shmpage_out; + } + + pShmNode->aRegion[pShmNode->nRegion].pMap = pMap; + pShmNode->aRegion[pShmNode->nRegion].hMap = hMap; + pShmNode->nRegion++; + } + } + +shmpage_out: + if( pShmNode->nRegion>iRegion ){ + int iOffset = iRegion*szRegion; + int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; + char *p = (char *)pShmNode->aRegion[iRegion].pMap; + *pp = (void *)&p[iOffsetShift]; + }else{ + *pp = 0; + } + sqlite3_mutex_leave(pShmNode->mutex); + return rc; +} + +#else +# define winShmMap 0 +# define winShmLock 0 +# define winShmBarrier 0 +# define winShmUnmap 0 +#endif /* #ifndef SQLITE_OMIT_WAL */ + +/* +** Cleans up the mapped region of the specified file, if any. +*/ +#if SQLITE_MAX_MMAP_SIZE>0 +static int winUnmapfile(winFile *pFile){ + assert( pFile!=0 ); + OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, " + "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n", + osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion, + pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax)); + if( pFile->pMapRegion ){ + if( !osUnmapViewOfFile(pFile->pMapRegion) ){ + pFile->lastErrno = osGetLastError(); + OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, " + "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile, + pFile->pMapRegion)); + return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, + "winUnmapfile1", pFile->zPath); + } + pFile->pMapRegion = 0; + pFile->mmapSize = 0; + pFile->mmapSizeActual = 0; + } + if( pFile->hMap!=NULL ){ + if( !osCloseHandle(pFile->hMap) ){ + pFile->lastErrno = osGetLastError(); + OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n", + osGetCurrentProcessId(), pFile, pFile->hMap)); + return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, + "winUnmapfile2", pFile->zPath); + } + pFile->hMap = NULL; + } + OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFile)); + return SQLITE_OK; +} + +/* +** Memory map or remap the file opened by file-descriptor pFd (if the file +** is already mapped, the existing mapping is replaced by the new). Or, if +** there already exists a mapping for this file, and there are still +** outstanding xFetch() references to it, this function is a no-op. +** +** If parameter nByte is non-negative, then it is the requested size of +** the mapping to create. Otherwise, if nByte is less than zero, then the +** requested size is the size of the file on disk. The actual size of the +** created mapping is either the requested size or the value configured +** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller. +** +** SQLITE_OK is returned if no error occurs (even if the mapping is not +** recreated as a result of outstanding references) or an SQLite error +** code otherwise. +*/ +static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ + sqlite3_int64 nMap = nByte; + int rc; + + assert( nMap>=0 || pFd->nFetchOut==0 ); + OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n", + osGetCurrentProcessId(), pFd, nByte)); + + if( pFd->nFetchOut>0 ) return SQLITE_OK; + + if( nMap<0 ){ + rc = winFileSize((sqlite3_file*)pFd, &nMap); + if( rc ){ + OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n", + osGetCurrentProcessId(), pFd)); + return SQLITE_IOERR_FSTAT; + } + } + if( nMap>pFd->mmapSizeMax ){ + nMap = pFd->mmapSizeMax; + } + nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1); + + if( nMap==0 && pFd->mmapSize>0 ){ + winUnmapfile(pFd); + } + if( nMap!=pFd->mmapSize ){ + void *pNew = 0; + DWORD protect = PAGE_READONLY; + DWORD flags = FILE_MAP_READ; + + winUnmapfile(pFd); +#ifdef SQLITE_MMAP_READWRITE + if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){ + protect = PAGE_READWRITE; + flags |= FILE_MAP_WRITE; + } +#endif +#if SQLITE_OS_WINRT + pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); +#elif defined(SQLITE_WIN32_HAS_WIDE) + pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, + (DWORD)((nMap>>32) & 0xffffffff), + (DWORD)(nMap & 0xffffffff), NULL); +#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA + pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect, + (DWORD)((nMap>>32) & 0xffffffff), + (DWORD)(nMap & 0xffffffff), NULL); +#endif + if( pFd->hMap==NULL ){ + pFd->lastErrno = osGetLastError(); + rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, + "winMapfile1", pFd->zPath); + /* Log the error, but continue normal operation using xRead/xWrite */ + OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=%s\n", + osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); + return SQLITE_OK; + } + assert( (nMap % winSysInfo.dwPageSize)==0 ); + assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); +#if SQLITE_OS_WINRT + pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); +#else + pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); +#endif + if( pNew==NULL ){ + osCloseHandle(pFd->hMap); + pFd->hMap = NULL; + pFd->lastErrno = osGetLastError(); + rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, + "winMapfile2", pFd->zPath); + /* Log the error, but continue normal operation using xRead/xWrite */ + OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=%s\n", + osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); + return SQLITE_OK; + } + pFd->pMapRegion = pNew; + pFd->mmapSize = nMap; + pFd->mmapSizeActual = nMap; + } + + OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), pFd)); + return SQLITE_OK; +} +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + +/* +** If possible, return a pointer to a mapping of file fd starting at offset +** iOff. The mapping must be valid for at least nAmt bytes. +** +** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. +** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. +** Finally, if an error does occur, return an SQLite error code. The final +** value of *pp is undefined in this case. +** +** If this function does return a pointer, the caller must eventually +** release the reference by calling winUnfetch(). +*/ +static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ +#if SQLITE_MAX_MMAP_SIZE>0 + winFile *pFd = (winFile*)fd; /* The underlying database file */ +#endif + *pp = 0; + + OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n", + osGetCurrentProcessId(), fd, iOff, nAmt, pp)); + +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFd->mmapSizeMax>0 ){ + if( pFd->pMapRegion==0 ){ + int rc = winMapfile(pFd, -1); + if( rc!=SQLITE_OK ){ + OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n", + osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); + return rc; + } + } + if( pFd->mmapSize >= iOff+nAmt ){ + *pp = &((u8 *)pFd->pMapRegion)[iOff]; + pFd->nFetchOut++; + } + } +#endif + + OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), fd, pp, *pp)); + return SQLITE_OK; +} + +/* +** If the third argument is non-NULL, then this function releases a +** reference obtained by an earlier call to winFetch(). The second +** argument passed to this function must be the same as the corresponding +** argument that was passed to the winFetch() invocation. +** +** Or, if the third argument is NULL, then this function is being called +** to inform the VFS layer that, according to POSIX, any existing mapping +** may now be invalid and should be unmapped. +*/ +static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ +#if SQLITE_MAX_MMAP_SIZE>0 + winFile *pFd = (winFile*)fd; /* The underlying database file */ + + /* If p==0 (unmap the entire file) then there must be no outstanding + ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), + ** then there must be at least one outstanding. */ + assert( (p==0)==(pFd->nFetchOut==0) ); + + /* If p!=0, it must match the iOff value. */ + assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); + + OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n", + osGetCurrentProcessId(), pFd, iOff, p)); + + if( p ){ + pFd->nFetchOut--; + }else{ + /* FIXME: If Windows truly always prevents truncating or deleting a + ** file while a mapping is held, then the following winUnmapfile() call + ** is unnecessary can be omitted - potentially improving + ** performance. */ + winUnmapfile(pFd); + } + + assert( pFd->nFetchOut>=0 ); +#endif + + OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n", + osGetCurrentProcessId(), fd)); + return SQLITE_OK; +} + +/* +** Here ends the implementation of all sqlite3_file methods. +** +********************** End sqlite3_file Methods ******************************* +******************************************************************************/ + +/* +** This vector defines all the methods that can operate on an +** sqlite3_file for win32. +*/ +static const sqlite3_io_methods winIoMethod = { + 3, /* iVersion */ + winClose, /* xClose */ + winRead, /* xRead */ + winWrite, /* xWrite */ + winTruncate, /* xTruncate */ + winSync, /* xSync */ + winFileSize, /* xFileSize */ + winLock, /* xLock */ + winUnlock, /* xUnlock */ + winCheckReservedLock, /* xCheckReservedLock */ + winFileControl, /* xFileControl */ + winSectorSize, /* xSectorSize */ + winDeviceCharacteristics, /* xDeviceCharacteristics */ + winShmMap, /* xShmMap */ + winShmLock, /* xShmLock */ + winShmBarrier, /* xShmBarrier */ + winShmUnmap, /* xShmUnmap */ + winFetch, /* xFetch */ + winUnfetch /* xUnfetch */ +}; + +/* +** This vector defines all the methods that can operate on an +** sqlite3_file for win32 without performing any locking. +*/ +static const sqlite3_io_methods winIoNolockMethod = { + 3, /* iVersion */ + winClose, /* xClose */ + winRead, /* xRead */ + winWrite, /* xWrite */ + winTruncate, /* xTruncate */ + winSync, /* xSync */ + winFileSize, /* xFileSize */ + winNolockLock, /* xLock */ + winNolockUnlock, /* xUnlock */ + winNolockCheckReservedLock, /* xCheckReservedLock */ + winFileControl, /* xFileControl */ + winSectorSize, /* xSectorSize */ + winDeviceCharacteristics, /* xDeviceCharacteristics */ + winShmMap, /* xShmMap */ + winShmLock, /* xShmLock */ + winShmBarrier, /* xShmBarrier */ + winShmUnmap, /* xShmUnmap */ + winFetch, /* xFetch */ + winUnfetch /* xUnfetch */ +}; + +static winVfsAppData winAppData = { + &winIoMethod, /* pMethod */ + 0, /* pAppData */ + 0 /* bNoLock */ +}; + +static winVfsAppData winNolockAppData = { + &winIoNolockMethod, /* pMethod */ + 0, /* pAppData */ + 1 /* bNoLock */ +}; + +/**************************************************************************** +**************************** sqlite3_vfs methods **************************** +** +** This division contains the implementation of methods on the +** sqlite3_vfs object. +*/ + +#if defined(__CYGWIN__) +/* +** Convert a filename from whatever the underlying operating system +** supports for filenames into UTF-8. Space to hold the result is +** obtained from malloc and must be freed by the calling function. +*/ +static char *winConvertToUtf8Filename(const void *zFilename){ + char *zConverted = 0; + if( osIsNT() ){ + zConverted = winUnicodeToUtf8(zFilename); + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI()); + } +#endif + /* caller will handle out of memory */ + return zConverted; +} +#endif + +/* +** Convert a UTF-8 filename into whatever form the underlying +** operating system wants filenames in. Space to hold the result +** is obtained from malloc and must be freed by the calling +** function. +*/ +static void *winConvertFromUtf8Filename(const char *zFilename){ + void *zConverted = 0; + if( osIsNT() ){ + zConverted = winUtf8ToUnicode(zFilename); + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); + } +#endif + /* caller will handle out of memory */ + return zConverted; +} + +/* +** This function returns non-zero if the specified UTF-8 string buffer +** ends with a directory separator character or one was successfully +** added to it. +*/ +static int winMakeEndInDirSep(int nBuf, char *zBuf){ + if( zBuf ){ + int nLen = sqlite3Strlen30(zBuf); + if( nLen>0 ){ + if( winIsDirSep(zBuf[nLen-1]) ){ + return 1; + }else if( nLen+1mxPathname; nBuf = nMax + 2; + zBuf = sqlite3MallocZero( nBuf ); + if( !zBuf ){ + OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); + return SQLITE_IOERR_NOMEM_BKPT; + } + + /* Figure out the effective temporary directory. First, check if one + ** has been explicitly set by the application; otherwise, use the one + ** configured by the operating system. + */ + nDir = nMax - (nPre + 15); + assert( nDir>0 ); + if( sqlite3_temp_directory ){ + int nDirLen = sqlite3Strlen30(sqlite3_temp_directory); + if( nDirLen>0 ){ + if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){ + nDirLen++; + } + if( nDirLen>nDir ){ + sqlite3_free(zBuf); + OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); + return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0); + } + sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory); + } + } +#if defined(__CYGWIN__) + else{ + static const char *azDirs[] = { + 0, /* getenv("SQLITE_TMPDIR") */ + 0, /* getenv("TMPDIR") */ + 0, /* getenv("TMP") */ + 0, /* getenv("TEMP") */ + 0, /* getenv("USERPROFILE") */ + "/var/tmp", + "/usr/tmp", + "/tmp", + ".", + 0 /* List terminator */ + }; + unsigned int i; + const char *zDir = 0; + + if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); + if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); + if( !azDirs[2] ) azDirs[2] = getenv("TMP"); + if( !azDirs[3] ) azDirs[3] = getenv("TEMP"); + if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE"); + for(i=0; i/etilqs_XXXXXXXXXXXXXXX\0\0" + ** + ** If not, return SQLITE_ERROR. The number 17 is used here in order to + ** account for the space used by the 15 character random suffix and the + ** two trailing NUL characters. The final directory separator character + ** has already added if it was not already present. + */ + nLen = sqlite3Strlen30(zBuf); + if( (nLen + nPre + 17) > nBuf ){ + sqlite3_free(zBuf); + OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); + return winLogError(SQLITE_ERROR, 0, "winGetTempname5", 0); + } + + sqlite3_snprintf(nBuf-16-nLen, zBuf+nLen, SQLITE_TEMP_FILE_PREFIX); + + j = sqlite3Strlen30(zBuf); + sqlite3_randomness(15, &zBuf[j]); + for(i=0; i<15; i++, j++){ + zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; + } + zBuf[j] = 0; + zBuf[j+1] = 0; + *pzBuf = zBuf; + + OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf)); + return SQLITE_OK; +} + +/* +** Return TRUE if the named file is really a directory. Return false if +** it is something other than a directory, or if there is any kind of memory +** allocation failure. +*/ +static int winIsDir(const void *zConverted){ + DWORD attr; + int rc = 0; + DWORD lastErrno; + + if( osIsNT() ){ + int cnt = 0; + WIN32_FILE_ATTRIBUTE_DATA sAttrData; + memset(&sAttrData, 0, sizeof(sAttrData)); + while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, + GetFileExInfoStandard, + &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} + if( !rc ){ + return 0; /* Invalid name? */ + } + attr = sAttrData.dwFileAttributes; +#if SQLITE_OS_WINCE==0 + }else{ + attr = osGetFileAttributesA((char*)zConverted); +#endif + } + return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); +} + +/* +** Open a file. +*/ +static int winOpen( + sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */ + const char *zName, /* Name of the file (UTF-8) */ + sqlite3_file *id, /* Write the SQLite file handle here */ + int flags, /* Open mode flags */ + int *pOutFlags /* Status return flags */ +){ + HANDLE h; + DWORD lastErrno = 0; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes = 0; +#if SQLITE_OS_WINCE + int isTemp = 0; +#endif + winVfsAppData *pAppData; + winFile *pFile = (winFile*)id; + void *zConverted; /* Filename in OS encoding */ + const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ + int cnt = 0; + + /* If argument zPath is a NULL pointer, this function is required to open + ** a temporary file. Use this buffer to store the file name in. + */ + char *zTmpname = 0; /* For temporary filename, if necessary. */ + + int rc = SQLITE_OK; /* Function Return Code */ +#if !defined(NDEBUG) || SQLITE_OS_WINCE + int eType = flags&0xFFFFFF00; /* Type of file to open */ +#endif + + int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); + int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); + int isCreate = (flags & SQLITE_OPEN_CREATE); + int isReadonly = (flags & SQLITE_OPEN_READONLY); + int isReadWrite = (flags & SQLITE_OPEN_READWRITE); + +#ifndef NDEBUG + int isOpenJournal = (isCreate && ( + eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_MAIN_JOURNAL + || eType==SQLITE_OPEN_WAL + )); +#endif + + OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n", + zUtf8Name, id, flags, pOutFlags)); + + /* Check the following statements are true: + ** + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (b) if CREATE is set, then READWRITE must also be set, and + ** (c) if EXCLUSIVE is set, then CREATE must also be set. + ** (d) if DELETEONCLOSE is set, then CREATE must also be set. + */ + assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); + assert(isCreate==0 || isReadWrite); + assert(isExclusive==0 || isCreate); + assert(isDelete==0 || isCreate); + + /* The main DB, main journal, WAL file and master journal are never + ** automatically deleted. Nor are they ever temporary files. */ + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); + + /* Assert that the upper layer has set one of the "file-type" flags. */ + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL + ); + + assert( pFile!=0 ); + memset(pFile, 0, sizeof(winFile)); + pFile->h = INVALID_HANDLE_VALUE; + +#if SQLITE_OS_WINRT + if( !zUtf8Name && !sqlite3_temp_directory ){ + sqlite3_log(SQLITE_ERROR, + "sqlite3_temp_directory variable should be set for WinRT"); + } +#endif + + /* If the second argument to this function is NULL, generate a + ** temporary file name to use + */ + if( !zUtf8Name ){ + assert( isDelete && !isOpenJournal ); + rc = winGetTempname(pVfs, &zTmpname); + if( rc!=SQLITE_OK ){ + OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc))); + return rc; + } + zUtf8Name = zTmpname; + } + + /* Database filenames are double-zero terminated if they are not + ** URIs with parameters. Hence, they can always be passed into + ** sqlite3_uri_parameter(). + */ + assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || + zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 ); + + /* Convert the filename to the system encoding. */ + zConverted = winConvertFromUtf8Filename(zUtf8Name); + if( zConverted==0 ){ + sqlite3_free(zTmpname); + OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name)); + return SQLITE_IOERR_NOMEM_BKPT; + } + + if( winIsDir(zConverted) ){ + sqlite3_free(zConverted); + sqlite3_free(zTmpname); + OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name)); + return SQLITE_CANTOPEN_ISDIR; + } + + if( isReadWrite ){ + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + }else{ + dwDesiredAccess = GENERIC_READ; + } + + /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is + ** created. SQLite doesn't use it to indicate "exclusive access" + ** as it is usually understood. + */ + if( isExclusive ){ + /* Creates a new file, only if it does not already exist. */ + /* If the file exists, it fails. */ + dwCreationDisposition = CREATE_NEW; + }else if( isCreate ){ + /* Open existing file, or create if it doesn't exist */ + dwCreationDisposition = OPEN_ALWAYS; + }else{ + /* Opens a file, only if it exists. */ + dwCreationDisposition = OPEN_EXISTING; + } + + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + if( isDelete ){ +#if SQLITE_OS_WINCE + dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN; + isTemp = 1; +#else + dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY + | FILE_ATTRIBUTE_HIDDEN + | FILE_FLAG_DELETE_ON_CLOSE; +#endif + }else{ + dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + } + /* Reports from the internet are that performance is always + ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */ +#if SQLITE_OS_WINCE + dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS; +#endif + + if( osIsNT() ){ +#if SQLITE_OS_WINRT + CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; + extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); + extendedParameters.dwFileAttributes = + dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; + extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; + 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 */ + } +#else + while( (h = osCreateFileW((LPCWSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL))==INVALID_HANDLE_VALUE && + winRetryIoerr(&cnt, &lastErrno) ){ + /* Noop */ + } +#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 */ + } + } +#endif + winLogIoerr(cnt, __LINE__); + + OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name, + 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 ){ + return winOpen(pVfs, zName, id, + ((flags|SQLITE_OPEN_READONLY) & + ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), + pOutFlags); + }else{ + return SQLITE_CANTOPEN_BKPT; + } + } + + if( pOutFlags ){ + if( isReadWrite ){ + *pOutFlags = SQLITE_OPEN_READWRITE; + }else{ + *pOutFlags = SQLITE_OPEN_READONLY; + } + } + + OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, " + "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? + *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); + + pAppData = (winVfsAppData*)pVfs->pAppData; + +#if SQLITE_OS_WINCE + { + if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB + && ((pAppData==NULL) || !pAppData->bNoLock) + && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK + ){ + osCloseHandle(h); + sqlite3_free(zConverted); + sqlite3_free(zTmpname); + OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); + return rc; + } + } + if( isTemp ){ + pFile->zDeleteOnClose = zConverted; + }else +#endif + { + sqlite3_free(zConverted); + } + + sqlite3_free(zTmpname); + pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod; + pFile->pVfs = pVfs; + pFile->h = h; + if( isReadonly ){ + pFile->ctrlFlags |= WINFILE_RDONLY; + } + if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ + pFile->ctrlFlags |= WINFILE_PSOW; + } + pFile->lastErrno = NO_ERROR; + pFile->zPath = zName; +#if SQLITE_MAX_MMAP_SIZE>0 + pFile->hMap = NULL; + pFile->pMapRegion = 0; + pFile->mmapSize = 0; + pFile->mmapSizeActual = 0; + pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap; +#endif + + OpenCounter(+1); + return rc; +} + +/* +** Delete the named file. +** +** Note that Windows does not allow a file to be deleted if some other +** process has it open. Sometimes a virus scanner or indexing program +** will open a journal file shortly after it is created in order to do +** whatever it does. While this other process is holding the +** file open, we will be unable to delete it. To work around this +** problem, we delay 100 milliseconds and try to delete again. Up +** to MX_DELETION_ATTEMPTs deletion attempts are run before giving +** up and returning an error. +*/ +static int winDelete( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to delete */ + int syncDir /* Not used on win32 */ +){ + int cnt = 0; + int rc; + DWORD attr; + DWORD lastErrno = 0; + void *zConverted; + UNUSED_PARAMETER(pVfs); + UNUSED_PARAMETER(syncDir); + + SimulateIOError(return SQLITE_IOERR_DELETE); + OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir)); + + zConverted = winConvertFromUtf8Filename(zFilename); + if( zConverted==0 ){ + OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); + return SQLITE_IOERR_NOMEM_BKPT; + } + if( osIsNT() ){ + do { +#if SQLITE_OS_WINRT + WIN32_FILE_ATTRIBUTE_DATA sAttrData; + memset(&sAttrData, 0, sizeof(sAttrData)); + if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, + &sAttrData) ){ + attr = sAttrData.dwFileAttributes; + }else{ + lastErrno = osGetLastError(); + if( lastErrno==ERROR_FILE_NOT_FOUND + || lastErrno==ERROR_PATH_NOT_FOUND ){ + rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ + }else{ + rc = SQLITE_ERROR; + } + break; + } +#else + attr = osGetFileAttributesW(zConverted); +#endif + if ( attr==INVALID_FILE_ATTRIBUTES ){ + lastErrno = osGetLastError(); + if( lastErrno==ERROR_FILE_NOT_FOUND + || lastErrno==ERROR_PATH_NOT_FOUND ){ + rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ + }else{ + rc = SQLITE_ERROR; + } + break; + } + if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ + rc = SQLITE_ERROR; /* Files only. */ + break; + } + if ( osDeleteFileW(zConverted) ){ + rc = SQLITE_OK; /* Deleted OK. */ + break; + } + if ( !winRetryIoerr(&cnt, &lastErrno) ){ + rc = SQLITE_ERROR; /* No more retries. */ + break; + } + } while(1); + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + do { + attr = osGetFileAttributesA(zConverted); + if ( attr==INVALID_FILE_ATTRIBUTES ){ + lastErrno = osGetLastError(); + if( lastErrno==ERROR_FILE_NOT_FOUND + || lastErrno==ERROR_PATH_NOT_FOUND ){ + rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ + }else{ + rc = SQLITE_ERROR; + } + break; + } + if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ + rc = SQLITE_ERROR; /* Files only. */ + break; + } + if ( osDeleteFileA(zConverted) ){ + rc = SQLITE_OK; /* Deleted OK. */ + break; + } + if ( !winRetryIoerr(&cnt, &lastErrno) ){ + rc = SQLITE_ERROR; /* No more retries. */ + break; + } + } while(1); + } +#endif + if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){ + rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); + }else{ + winLogIoerr(cnt, __LINE__); + } + sqlite3_free(zConverted); + OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc))); + return rc; +} + +/* +** Check the existence and status of a file. +*/ +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 */ +){ + DWORD attr; + int rc = 0; + DWORD lastErrno = 0; + void *zConverted; + UNUSED_PARAMETER(pVfs); + + SimulateIOError( return SQLITE_IOERR_ACCESS; ); + OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", + zFilename, flags, pResOut)); + + zConverted = winConvertFromUtf8Filename(zFilename); + if( zConverted==0 ){ + OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); + return SQLITE_IOERR_NOMEM_BKPT; + } + if( osIsNT() ){ + int cnt = 0; + WIN32_FILE_ATTRIBUTE_DATA sAttrData; + memset(&sAttrData, 0, sizeof(sAttrData)); + while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, + GetFileExInfoStandard, + &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} + if( rc ){ + /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file + ** as if it does not exist. + */ + if( flags==SQLITE_ACCESS_EXISTS + && sAttrData.nFileSizeHigh==0 + && sAttrData.nFileSizeLow==0 ){ + attr = INVALID_FILE_ATTRIBUTES; + }else{ + attr = sAttrData.dwFileAttributes; + } + }else{ + winLogIoerr(cnt, __LINE__); + if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ + sqlite3_free(zConverted); + return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", + zFilename); + }else{ + attr = INVALID_FILE_ATTRIBUTES; + } + } + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + attr = osGetFileAttributesA((char*)zConverted); + } +#endif + sqlite3_free(zConverted); + switch( flags ){ + case SQLITE_ACCESS_READ: + case SQLITE_ACCESS_EXISTS: + rc = attr!=INVALID_FILE_ATTRIBUTES; + break; + case SQLITE_ACCESS_READWRITE: + rc = attr!=INVALID_FILE_ATTRIBUTES && + (attr & FILE_ATTRIBUTE_READONLY)==0; + break; + default: + assert(!"Invalid flags argument"); + } + *pResOut = rc; + OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", + zFilename, pResOut, *pResOut)); + return SQLITE_OK; +} + +/* +** Returns non-zero if the specified path name starts with a drive letter +** followed by a colon character. +*/ +static BOOL winIsDriveLetterAndColon( + const char *zPathname +){ + return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ); +} + +/* +** Returns non-zero if the specified path name should be used verbatim. If +** non-zero is returned from this function, the calling function must simply +** use the provided path name verbatim -OR- resolve it into a full path name +** using the GetFullPathName Win32 API function (if available). +*/ +static BOOL winIsVerbatimPathname( + const char *zPathname +){ + /* + ** If the path name starts with a forward slash or a backslash, it is either + ** a legal UNC name, a volume relative path, or an absolute path name in the + ** "Unix" format on Windows. There is no easy way to differentiate between + ** the final two cases; therefore, we return the safer return value of TRUE + ** so that callers of this function will simply use it verbatim. + */ + if ( winIsDirSep(zPathname[0]) ){ + return TRUE; + } + + /* + ** If the path name starts with a letter and a colon it is either a volume + ** relative path or an absolute path. Callers of this function must not + ** attempt to treat it as a relative path name (i.e. they should simply use + ** it verbatim). + */ + if ( winIsDriveLetterAndColon(zPathname) ){ + return TRUE; + } + + /* + ** If we get to this point, the path name should almost certainly be a purely + ** relative one (i.e. not a UNC name, not absolute, and not volume relative). + */ + return FALSE; +} + +/* +** Turn a relative pathname into a full pathname. Write the full +** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname +** bytes in size. +*/ +static int winFullPathname( + sqlite3_vfs *pVfs, /* Pointer to vfs object */ + const char *zRelative, /* Possibly relative input path */ + int nFull, /* Size of output buffer in bytes */ + char *zFull /* Output buffer */ +){ +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) + DWORD nByte; + void *zConverted; + char *zOut; +#endif + + /* If this path name begins with "/X:", where "X" is any alphabetic + ** character, discard the initial "/" from the pathname. + */ + if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ + zRelative++; + } + +#if defined(__CYGWIN__) + SimulateIOError( return SQLITE_ERROR ); + UNUSED_PARAMETER(nFull); + assert( nFull>=pVfs->mxPathname ); + if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ + /* + ** NOTE: We are dealing with a relative path name and the data + ** directory has been set. Therefore, use it as the basis + ** for converting the relative path name to an absolute + ** one by prepending the data directory and a slash. + */ + char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); + if( !zOut ){ + return SQLITE_IOERR_NOMEM_BKPT; + } + if( cygwin_conv_path( + (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) | + CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){ + sqlite3_free(zOut); + return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, + "winFullPathname1", zRelative); + }else{ + char *zUtf8 = winConvertToUtf8Filename(zOut); + if( !zUtf8 ){ + sqlite3_free(zOut); + return SQLITE_IOERR_NOMEM_BKPT; + } + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", + sqlite3_data_directory, winGetDirSep(), zUtf8); + sqlite3_free(zUtf8); + sqlite3_free(zOut); + } + }else{ + char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); + if( !zOut ){ + return SQLITE_IOERR_NOMEM_BKPT; + } + if( cygwin_conv_path( + (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A), + zRelative, zOut, pVfs->mxPathname+1)<0 ){ + sqlite3_free(zOut); + return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, + "winFullPathname2", zRelative); + }else{ + char *zUtf8 = winConvertToUtf8Filename(zOut); + if( !zUtf8 ){ + sqlite3_free(zOut); + return SQLITE_IOERR_NOMEM_BKPT; + } + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8); + sqlite3_free(zUtf8); + sqlite3_free(zOut); + } + } + return SQLITE_OK; +#endif + +#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) + SimulateIOError( return SQLITE_ERROR ); + /* WinCE has no concept of a relative pathname, or so I am told. */ + /* WinRT has no way to convert a relative path to an absolute one. */ + if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ + /* + ** NOTE: We are dealing with a relative path name and the data + ** directory has been set. Therefore, use it as the basis + ** for converting the relative path name to an absolute + ** one by prepending the data directory and a backslash. + */ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", + sqlite3_data_directory, winGetDirSep(), zRelative); + }else{ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); + } + return SQLITE_OK; +#endif + +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) + /* It's odd to simulate an io-error here, but really this is just + ** using the io-error infrastructure to test that SQLite handles this + ** function failing. This function could fail if, for example, the + ** current working directory has been unlinked. + */ + SimulateIOError( return SQLITE_ERROR ); + if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ + /* + ** NOTE: We are dealing with a relative path name and the data + ** directory has been set. Therefore, use it as the basis + ** for converting the relative path name to an absolute + ** one by prepending the data directory and a backslash. + */ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", + sqlite3_data_directory, winGetDirSep(), zRelative); + return SQLITE_OK; + } + zConverted = winConvertFromUtf8Filename(zRelative); + if( zConverted==0 ){ + return SQLITE_IOERR_NOMEM_BKPT; + } + if( osIsNT() ){ + LPWSTR zTemp; + nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0); + if( nByte==0 ){ + sqlite3_free(zConverted); + return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), + "winFullPathname1", zRelative); + } + nByte += 3; + zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); + if( zTemp==0 ){ + sqlite3_free(zConverted); + return SQLITE_IOERR_NOMEM_BKPT; + } + nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0); + if( nByte==0 ){ + sqlite3_free(zConverted); + sqlite3_free(zTemp); + return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), + "winFullPathname2", zRelative); + } + sqlite3_free(zConverted); + zOut = winUnicodeToUtf8(zTemp); + sqlite3_free(zTemp); + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + char *zTemp; + nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0); + if( nByte==0 ){ + sqlite3_free(zConverted); + return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), + "winFullPathname3", zRelative); + } + nByte += 3; + zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); + if( zTemp==0 ){ + sqlite3_free(zConverted); + return SQLITE_IOERR_NOMEM_BKPT; + } + nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0); + if( nByte==0 ){ + sqlite3_free(zConverted); + sqlite3_free(zTemp); + return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), + "winFullPathname4", zRelative); + } + sqlite3_free(zConverted); + zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); + sqlite3_free(zTemp); + } +#endif + if( zOut ){ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); + sqlite3_free(zOut); + return SQLITE_OK; + }else{ + return SQLITE_IOERR_NOMEM_BKPT; + } +#endif +} + +#ifndef SQLITE_OMIT_LOAD_EXTENSION +/* +** Interfaces for opening a shared library, finding entry points +** within the shared library, and closing the shared library. +*/ +static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ + HANDLE h; +#if defined(__CYGWIN__) + int nFull = pVfs->mxPathname+1; + char *zFull = sqlite3MallocZero( nFull ); + void *zConverted = 0; + if( zFull==0 ){ + OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); + return 0; + } + if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){ + sqlite3_free(zFull); + OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); + return 0; + } + zConverted = winConvertFromUtf8Filename(zFull); + sqlite3_free(zFull); +#else + void *zConverted = winConvertFromUtf8Filename(zFilename); + UNUSED_PARAMETER(pVfs); +#endif + if( zConverted==0 ){ + OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); + return 0; + } + if( osIsNT() ){ +#if SQLITE_OS_WINRT + h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); +#else + h = osLoadLibraryW((LPCWSTR)zConverted); +#endif + } +#ifdef SQLITE_WIN32_HAS_ANSI + else{ + h = osLoadLibraryA((char*)zConverted); + } +#endif + OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h)); + sqlite3_free(zConverted); + return (void*)h; +} +static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ + UNUSED_PARAMETER(pVfs); + winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut); +} +static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ + FARPROC proc; + UNUSED_PARAMETER(pVfs); + proc = osGetProcAddressA((HANDLE)pH, zSym); + OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n", + (void*)pH, zSym, (void*)proc)); + return (void(*)(void))proc; +} +static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ + UNUSED_PARAMETER(pVfs); + osFreeLibrary((HANDLE)pHandle); + OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle)); +} +#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ + #define winDlOpen 0 + #define winDlError 0 + #define winDlSym 0 + #define winDlClose 0 +#endif + +/* State information for the randomness gatherer. */ +typedef struct EntropyGatherer EntropyGatherer; +struct EntropyGatherer { + unsigned char *a; /* Gather entropy into this buffer */ + int na; /* Size of a[] in bytes */ + int i; /* XOR next input into a[i] */ + int nXor; /* Number of XOR operations done */ +}; + +#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) +/* Mix sz bytes of entropy into p. */ +static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){ + int j, k; + for(j=0, k=p->i; ja[k++] ^= x[j]; + if( k>=p->na ) k = 0; + } + p->i = k; + p->nXor += sz; +} +#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */ + +/* +** Write up to nBuf bytes of randomness into zBuf. +*/ +static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ +#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) + UNUSED_PARAMETER(pVfs); + memset(zBuf, 0, nBuf); + return nBuf; +#else + 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; + e.i = 0; + { + SYSTEMTIME x; + osGetSystemTime(&x); + xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME)); + } + { + DWORD pid = osGetCurrentProcessId(); + xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); + } +#if SQLITE_OS_WINRT + { + ULONGLONG cnt = osGetTickCount64(); + xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG)); + } +#else + { + DWORD cnt = osGetTickCount(); + xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); + } +#endif /* SQLITE_OS_WINRT */ + { + LARGE_INTEGER i; + osQueryPerformanceCounter(&i); + xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); + } +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID + { + UUID id; + memset(&id, 0, sizeof(UUID)); + osUuidCreate(&id); + xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); + memset(&id, 0, sizeof(UUID)); + osUuidCreateSequential(&id); + xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); + } +#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */ + return e.nXor>nBuf ? nBuf : e.nXor; +#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ +} + + +/* +** Sleep for a little while. Return the amount of time slept. +*/ +static int winSleep(sqlite3_vfs *pVfs, int microsec){ + sqlite3_win32_sleep((microsec+999)/1000); + UNUSED_PARAMETER(pVfs); + return ((microsec+999)/1000)*1000; +} + +/* +** The following variable, if set to a non-zero value, is interpreted as +** the number of seconds since 1970 and is used to set the result of +** sqlite3OsCurrentTime() during testing. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ +#endif + +/* +** Find the current time (in Universal Coordinated Time). Write into *piNow +** the current time and date as a Julian Day number times 86_400_000. In +** other words, write into *piNow the number of milliseconds since the Julian +** epoch of noon in Greenwich on November 24, 4714 B.C according to the +** proleptic Gregorian calendar. +** +** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date +** cannot be found. +*/ +static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ + /* FILETIME structure is a 64-bit value representing the number of + 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). + */ + FILETIME ft; + static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000; +#ifdef SQLITE_TEST + static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; +#endif + /* 2^32 - to avoid use of LL and warnings in gcc */ + static const sqlite3_int64 max32BitValue = + (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + + (sqlite3_int64)294967296; + +#if SQLITE_OS_WINCE + SYSTEMTIME time; + osGetSystemTime(&time); + /* if SystemTimeToFileTime() fails, it returns zero. */ + if (!osSystemTimeToFileTime(&time,&ft)){ + return SQLITE_ERROR; + } +#else + osGetSystemTimeAsFileTime( &ft ); +#endif + + *piNow = winFiletimeEpoch + + ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + + (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000; + +#ifdef SQLITE_TEST + if( sqlite3_current_time ){ + *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; + } +#endif + UNUSED_PARAMETER(pVfs); + return SQLITE_OK; +} + +/* +** Find the current time (in Universal Coordinated Time). Write the +** current time and date as a Julian Day number into *prNow and +** return 0. Return 1 if the time and date cannot be found. +*/ +static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ + int rc; + sqlite3_int64 i; + rc = winCurrentTimeInt64(pVfs, &i); + if( !rc ){ + *prNow = i/86400000.0; + } + return rc; +} + +/* +** The idea is that this function works like a combination of +** GetLastError() and FormatMessage() on Windows (or errno and +** strerror_r() on Unix). After an error is returned by an OS +** function, SQLite calls this function with zBuf pointing to +** a buffer of nBuf bytes. The OS layer should populate the +** buffer with a nul-terminated UTF-8 encoded error message +** describing the last IO error to have occurred within the calling +** thread. +** +** If the error message is too large for the supplied buffer, +** it should be truncated. The return value of xGetLastError +** is zero if the error message fits in the buffer, or non-zero +** otherwise (if the message was truncated). If non-zero is returned, +** then it is not necessary to include the nul-terminator character +** in the output buffer. +** +** Not supplying an error message will have no adverse effect +** on SQLite. It is fine to have an implementation that never +** returns an error message: +** +** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ +** assert(zBuf[0]=='\0'); +** return 0; +** } +** +** However if an error message is supplied, it will be incorporated +** by sqlite into the error message available to the user using +** sqlite3_errmsg(), possibly making IO errors easier to debug. +*/ +static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ + DWORD e = osGetLastError(); + UNUSED_PARAMETER(pVfs); + if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf); + return e; +} + +/* +** Initialize and deinitialize the operating system interface. +*/ +SQLITE_API int sqlite3_os_init(void){ + static sqlite3_vfs winVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32", /* zName */ + &winAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#if defined(SQLITE_WIN32_HAS_WIDE) + static sqlite3_vfs winLongPathVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-longpath", /* zName */ + &winAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#endif + static sqlite3_vfs winNolockVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-none", /* zName */ + &winNolockAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#if defined(SQLITE_WIN32_HAS_WIDE) + static sqlite3_vfs winLongPathNolockVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-longpath-none", /* zName */ + &winNolockAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#endif + + /* Double-check that the aSyscall[] array has been constructed + ** correctly. See ticket [bb3a86e890c8e96ab] */ + assert( ArraySize(aSyscall)==80 ); + + /* get memory map allocation granularity */ + memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); +#if SQLITE_OS_WINRT + osGetNativeSystemInfo(&winSysInfo); +#else + osGetSystemInfo(&winSysInfo); +#endif + assert( winSysInfo.dwAllocationGranularity>0 ); + assert( winSysInfo.dwPageSize>0 ); + + sqlite3_vfs_register(&winVfs, 1); + +#if defined(SQLITE_WIN32_HAS_WIDE) + sqlite3_vfs_register(&winLongPathVfs, 0); +#endif + + sqlite3_vfs_register(&winNolockVfs, 0); + +#if defined(SQLITE_WIN32_HAS_WIDE) + sqlite3_vfs_register(&winLongPathNolockVfs, 0); +#endif + + return SQLITE_OK; +} + +SQLITE_API int sqlite3_os_end(void){ +#if SQLITE_OS_WINRT + if( sleepObj!=NULL ){ + osCloseHandle(sleepObj); + sleepObj = NULL; + } +#endif + return SQLITE_OK; +} + +#endif /* SQLITE_OS_WIN */ + +/************** End of os_win.c **********************************************/ +/************** Begin file bitvec.c ******************************************/ +/* +** 2008 February 16 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file implements an object that represents a fixed-length +** bitmap. Bits are numbered starting with 1. +** +** A bitmap is used to record which pages of a database file have been +** journalled during a transaction, or which pages have the "dont-write" +** property. Usually only a few pages are meet either condition. +** So the bitmap is usually sparse and has low cardinality. +** But sometimes (for example when during a DROP of a large table) most +** or all of the pages in a database can get journalled. In those cases, +** the bitmap becomes dense with high cardinality. The algorithm needs +** to handle both cases well. +** +** The size of the bitmap is fixed when the object is created. +** +** All bits are clear when the bitmap is created. Individual bits +** may be set or cleared one at a time. +** +** Test operations are about 100 times more common that set operations. +** Clear operations are exceedingly rare. There are usually between +** 5 and 500 set operations per Bitvec object, though the number of sets can +** sometimes grow into tens of thousands or larger. The size of the +** Bitvec object is the number of pages in the database file at the +** start of a transaction, and is thus usually less than a few thousand, +** but can be as large as 2 billion for a really big database. +*/ +/* #include "sqliteInt.h" */ + +/* Size of the Bitvec structure in bytes. */ +#define BITVEC_SZ 512 + +/* Round the union size down to the nearest pointer boundary, since that's how +** it will be aligned within the Bitvec struct. */ +#define BITVEC_USIZE \ + (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*)) + +/* Type of the array "element" for the bitmap representation. +** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE. +** Setting this to the "natural word" size of your CPU may improve +** performance. */ +#define BITVEC_TELEM u8 +/* Size, in bits, of the bitmap element. */ +#define BITVEC_SZELEM 8 +/* Number of elements in a bitmap array. */ +#define BITVEC_NELEM (BITVEC_USIZE/sizeof(BITVEC_TELEM)) +/* Number of bits in the bitmap array. */ +#define BITVEC_NBIT (BITVEC_NELEM*BITVEC_SZELEM) + +/* Number of u32 values in hash table. */ +#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32)) +/* Maximum number of entries in hash table before +** sub-dividing and re-hashing. */ +#define BITVEC_MXHASH (BITVEC_NINT/2) +/* Hashing function for the aHash representation. +** Empirical testing showed that the *37 multiplier +** (an arbitrary prime)in the hash function provided +** no fewer collisions than the no-op *1. */ +#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT) + +#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *)) + + +/* +** A bitmap is an instance of the following structure. +** +** This bitmap records the existence of zero or more bits +** with values between 1 and iSize, inclusive. +** +** There are three possible representations of the bitmap. +** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight +** bitmap. The least significant bit is bit 1. +** +** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is +** a hash table that will hold up to BITVEC_MXHASH distinct values. +** +** Otherwise, the value i is redirected into one of BITVEC_NPTR +** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap +** handles up to iDivisor separate values of i. apSub[0] holds +** values between 1 and iDivisor. apSub[1] holds values between +** iDivisor+1 and 2*iDivisor. apSub[N] holds values between +** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized +** to hold deal with values between 1 and iDivisor. +*/ +struct Bitvec { + u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */ + u32 nSet; /* Number of bits that are set - only valid for aHash + ** element. Max is BITVEC_NINT. For BITVEC_SZ of 512, + ** this would be 125. */ + u32 iDivisor; /* Number of bits handled by each apSub[] entry. */ + /* Should >=0 for apSub element. */ + /* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */ + /* For a BITVEC_SZ of 512, this would be 34,359,739. */ + union { + BITVEC_TELEM aBitmap[BITVEC_NELEM]; /* Bitmap representation */ + u32 aHash[BITVEC_NINT]; /* Hash table representation */ + Bitvec *apSub[BITVEC_NPTR]; /* Recursive representation */ + } u; +}; + +/* +** Create a new bitmap object able to handle bits between 0 and iSize, +** inclusive. Return a pointer to the new object. Return NULL if +** malloc fails. +*/ +SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){ + Bitvec *p; + assert( sizeof(*p)==BITVEC_SZ ); + p = sqlite3MallocZero( sizeof(*p) ); + if( p ){ + p->iSize = iSize; + } + return p; +} + +/* +** Check to see if the i-th bit is set. Return true or false. +** If p is NULL (if the bitmap has not been created) or if +** i is out of range, then return false. +*/ +SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec *p, u32 i){ + assert( p!=0 ); + i--; + if( i>=p->iSize ) return 0; + while( p->iDivisor ){ + u32 bin = i/p->iDivisor; + i = i%p->iDivisor; + p = p->u.apSub[bin]; + if (!p) { + return 0; + } + } + if( p->iSize<=BITVEC_NBIT ){ + return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0; + } else{ + u32 h = BITVEC_HASH(i++); + while( p->u.aHash[h] ){ + if( p->u.aHash[h]==i ) return 1; + h = (h+1) % BITVEC_NINT; + } + return 0; + } +} +SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){ + return p!=0 && sqlite3BitvecTestNotNull(p,i); +} + +/* +** Set the i-th bit. Return 0 on success and an error code if +** anything goes wrong. +** +** This routine might cause sub-bitmaps to be allocated. Failing +** to get the memory needed to hold the sub-bitmap is the only +** that can go wrong with an insert, assuming p and i are valid. +** +** The calling function must ensure that p is a valid Bitvec object +** and that the value for "i" is within range of the Bitvec object. +** Otherwise the behavior is undefined. +*/ +SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){ + u32 h; + if( p==0 ) return SQLITE_OK; + assert( i>0 ); + assert( i<=p->iSize ); + i--; + while((p->iSize > BITVEC_NBIT) && p->iDivisor) { + u32 bin = i/p->iDivisor; + i = i%p->iDivisor; + if( p->u.apSub[bin]==0 ){ + p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor ); + if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT; + } + p = p->u.apSub[bin]; + } + if( p->iSize<=BITVEC_NBIT ){ + p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1)); + return SQLITE_OK; + } + h = BITVEC_HASH(i++); + /* if there wasn't a hash collision, and this doesn't */ + /* completely fill the hash, then just add it without */ + /* worring about sub-dividing and re-hashing. */ + if( !p->u.aHash[h] ){ + if (p->nSet<(BITVEC_NINT-1)) { + goto bitvec_set_end; + } else { + goto bitvec_set_rehash; + } + } + /* there was a collision, check to see if it's already */ + /* in hash, if not, try to find a spot for it */ + do { + if( p->u.aHash[h]==i ) return SQLITE_OK; + h++; + if( h>=BITVEC_NINT ) h = 0; + } while( p->u.aHash[h] ); + /* we didn't find it in the hash. h points to the first */ + /* available free spot. check to see if this is going to */ + /* make our hash too "full". */ +bitvec_set_rehash: + if( p->nSet>=BITVEC_MXHASH ){ + unsigned int j; + int rc; + u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash)); + if( aiValues==0 ){ + return SQLITE_NOMEM_BKPT; + }else{ + memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); + memset(p->u.apSub, 0, sizeof(p->u.apSub)); + p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR; + rc = sqlite3BitvecSet(p, i); + for(j=0; jnSet++; + p->u.aHash[h] = i; + return SQLITE_OK; +} + +/* +** Clear the i-th bit. +** +** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage +** that BitvecClear can use to rebuilt its hash table. +*/ +SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ + if( p==0 ) return; + assert( i>0 ); + i--; + while( p->iDivisor ){ + u32 bin = i/p->iDivisor; + i = i%p->iDivisor; + p = p->u.apSub[bin]; + if (!p) { + return; + } + } + if( p->iSize<=BITVEC_NBIT ){ + p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1))); + }else{ + unsigned int j; + u32 *aiValues = pBuf; + memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); + memset(p->u.aHash, 0, sizeof(p->u.aHash)); + p->nSet = 0; + for(j=0; jnSet++; + while( p->u.aHash[h] ){ + h++; + if( h>=BITVEC_NINT ) h = 0; + } + p->u.aHash[h] = aiValues[j]; + } + } + } +} + +/* +** Destroy a bitmap object. Reclaim all memory used. +*/ +SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec *p){ + if( p==0 ) return; + if( p->iDivisor ){ + unsigned int i; + for(i=0; iu.apSub[i]); + } + } + sqlite3_free(p); +} + +/* +** Return the value of the iSize parameter specified when Bitvec *p +** was created. +*/ +SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ + return p->iSize; +} + +#ifndef SQLITE_UNTESTABLE +/* +** Let V[] be an array of unsigned characters sufficient to hold +** up to N bits. Let I be an integer between 0 and N. 0<=I>3] |= (1<<(I&7)) +#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7)) +#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0 + +/* +** This routine runs an extensive test of the Bitvec code. +** +** The input is an array of integers that acts as a program +** to test the Bitvec. The integers are opcodes followed +** by 0, 1, or 3 operands, depending on the opcode. Another +** opcode follows immediately after the last operand. +** +** There are 6 opcodes numbered from 0 through 5. 0 is the +** "halt" opcode and causes the test to end. +** +** 0 Halt and return the number of errors +** 1 N S X Set N bits beginning with S and incrementing by X +** 2 N S X Clear N bits beginning with S and incrementing by X +** 3 N Set N randomly chosen bits +** 4 N Clear N randomly chosen bits +** 5 N S X Set N bits from S increment X in array only, not in bitvec +** +** The opcodes 1 through 4 perform set and clear operations are performed +** on both a Bitvec object and on a linear array of bits obtained from malloc. +** Opcode 5 works on the linear array only, not on the Bitvec. +** Opcode 5 is used to deliberately induce a fault in order to +** confirm that error detection works. +** +** At the conclusion of the test the linear array is compared +** against the Bitvec object. If there are any differences, +** an error is returned. If they are the same, zero is returned. +** +** If a memory allocation error occurs, return -1. +*/ +SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ + Bitvec *pBitvec = 0; + unsigned char *pV = 0; + int rc = -1; + int i, nx, pc, op; + void *pTmpSpace; + + /* Allocate the Bitvec to be tested and a linear array of + ** bits to act as the reference */ + pBitvec = sqlite3BitvecCreate( sz ); + pV = sqlite3MallocZero( (sz+7)/8 + 1 ); + pTmpSpace = sqlite3_malloc64(BITVEC_SZ); + if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; + + /* NULL pBitvec tests */ + sqlite3BitvecSet(0, 1); + sqlite3BitvecClear(0, 1, pTmpSpace); + + /* Run the program */ + pc = 0; + while( (op = aOp[pc])!=0 ){ + switch( op ){ + case 1: + case 2: + case 5: { + nx = 4; + i = aOp[pc+2] - 1; + aOp[pc+2] += aOp[pc+3]; + break; + } + case 3: + case 4: + default: { + nx = 2; + sqlite3_randomness(sizeof(i), &i); + break; + } + } + if( (--aOp[pc+1]) > 0 ) nx = 0; + pc += nx; + i = (i & 0x7fffffff)%sz; + if( (op & 1)!=0 ){ + SETBIT(pV, (i+1)); + if( op!=5 ){ + if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end; + } + }else{ + CLEARBIT(pV, (i+1)); + sqlite3BitvecClear(pBitvec, i+1, pTmpSpace); + } + } + + /* Test to make sure the linear array exactly matches the + ** Bitvec object. Start with the assumption that they do + ** match (rc==0). Change rc to non-zero if a discrepancy + ** is found. + */ + rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1) + + sqlite3BitvecTest(pBitvec, 0) + + (sqlite3BitvecSize(pBitvec) - sz); + for(i=1; i<=sz; i++){ + if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){ + rc = i; + break; + } + } + + /* Free allocated structure */ +bitvec_end: + sqlite3_free(pTmpSpace); + sqlite3_free(pV); + sqlite3BitvecDestroy(pBitvec); + return rc; +} +#endif /* SQLITE_UNTESTABLE */ + +/************** End of bitvec.c **********************************************/ +/************** Begin file pcache.c ******************************************/ +/* +** 2008 August 05 +** +** 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 that page cache. +*/ +/* #include "sqliteInt.h" */ + +/* +** A complete page cache is an instance of this structure. Every +** entry in the cache holds a single page of the database file. The +** btree layer only operates on the cached copy of the database pages. +** +** A page cache entry is "clean" if it exactly matches what is currently +** on disk. A page is "dirty" if it has been modified and needs to be +** persisted to disk. +** +** pDirty, pDirtyTail, pSynced: +** All dirty pages are linked into the doubly linked list using +** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order +** such that p was added to the list more recently than p->pDirtyNext. +** PCache.pDirty points to the first (newest) element in the list and +** pDirtyTail to the last (oldest). +** +** The PCache.pSynced variable is used to optimize searching for a dirty +** page to eject from the cache mid-transaction. It is better to eject +** a page that does not require a journal sync than one that does. +** Therefore, pSynced is maintained to that it *almost* always points +** to either the oldest page in the pDirty/pDirtyTail list that has a +** clear PGHDR_NEED_SYNC flag or to a page that is older than this one +** (so that the right page to eject can be found by following pDirtyPrev +** pointers). +*/ +struct PCache { + PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ + PgHdr *pSynced; /* Last synced page in dirty page list */ + int nRefSum; /* Sum of ref counts over all pages */ + int szCache; /* Configured cache size */ + int szSpill; /* Size before spilling occurs */ + int szPage; /* Size of every page in this cache */ + int szExtra; /* Size of extra space for each page */ + u8 bPurgeable; /* True if pages are on backing store */ + u8 eCreate; /* eCreate value for for xFetch() */ + int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ + void *pStress; /* Argument to xStress */ + sqlite3_pcache *pCache; /* Pluggable cache module */ +}; + +/********************************** Test and Debug Logic **********************/ +/* +** Debug tracing macros. Enable by by changing the "0" to "1" and +** recompiling. +** +** When sqlite3PcacheTrace is 1, single line trace messages are issued. +** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries +** is displayed for many operations, resulting in a lot of output. +*/ +#if defined(SQLITE_DEBUG) && 0 + int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ + int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ +# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} + void pcacheDump(PCache *pCache){ + int N; + int i, j; + sqlite3_pcache_page *pLower; + PgHdr *pPg; + unsigned char *a; + + if( sqlite3PcacheTrace<2 ) return; + if( pCache->pCache==0 ) return; + N = sqlite3PcachePagecount(pCache); + if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; + for(i=1; i<=N; i++){ + pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); + if( pLower==0 ) continue; + pPg = (PgHdr*)pLower->pExtra; + printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); + a = (unsigned char *)pLower->pBuf; + for(j=0; j<12; j++) printf("%02x", a[j]); + printf("\n"); + if( pPg->pPage==0 ){ + sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); + } + } + } + #else +# define pcacheTrace(X) +# define pcacheDump(X) +#endif + +/* +** Check invariants on a PgHdr entry. Return true if everything is OK. +** Return false if any invariant is violated. +** +** This routine is for use inside of assert() statements only. For +** example: +** +** assert( sqlite3PcachePageSanity(pPg) ); +*/ +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){ + PCache *pCache; + assert( pPg!=0 ); + assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */ + pCache = pPg->pCache; + assert( pCache!=0 ); /* Every page has an associated PCache */ + if( pPg->flags & PGHDR_CLEAN ){ + assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ + assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */ + assert( pCache->pDirtyTail!=pPg ); + } + /* WRITEABLE pages must also be DIRTY */ + if( pPg->flags & PGHDR_WRITEABLE ){ + assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */ + } + /* NEED_SYNC can be set independently of WRITEABLE. This can happen, + ** for example, when using the sqlite3PagerDontWrite() optimization: + ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK. + ** (2) Page X moved to freelist, WRITEABLE is cleared + ** (3) Page X reused, WRITEABLE is set again + ** If NEED_SYNC had been cleared in step 2, then it would not be reset + ** in step 3, and page might be written into the database without first + ** syncing the rollback journal, which might cause corruption on a power + ** loss. + ** + ** Another example is when the database page size is smaller than the + ** disk sector size. When any page of a sector is journalled, all pages + ** in that sector are marked NEED_SYNC even if they are still CLEAN, just + ** in case they are later modified, since all pages in the same sector + ** must be journalled and synced before any of those pages can be safely + ** written. + */ + return 1; +} +#endif /* SQLITE_DEBUG */ + + +/********************************** Linked List Management ********************/ + +/* Allowed values for second argument to pcacheManageDirtyList() */ +#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ +#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ +#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ + +/* +** Manage pPage's participation on the dirty list. Bits of the addRemove +** argument determines what operation to do. The 0x01 bit means first +** remove pPage from the dirty list. The 0x02 means add pPage back to +** the dirty list. Doing both moves pPage to the front of the dirty list. +*/ +static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ + PCache *p = pPage->pCache; + + pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, + addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT", + pPage->pgno)); + if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ + assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); + assert( pPage->pDirtyPrev || pPage==p->pDirty ); + + /* Update the PCache1.pSynced variable if necessary. */ + if( p->pSynced==pPage ){ + p->pSynced = pPage->pDirtyPrev; + } + + if( pPage->pDirtyNext ){ + pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; + }else{ + assert( pPage==p->pDirtyTail ); + p->pDirtyTail = pPage->pDirtyPrev; + } + if( pPage->pDirtyPrev ){ + pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; + }else{ + /* If there are now no dirty pages in the cache, set eCreate to 2. + ** This is an optimization that allows sqlite3PcacheFetch() to skip + ** searching for a dirty page to eject from the cache when it might + ** otherwise have to. */ + assert( pPage==p->pDirty ); + p->pDirty = pPage->pDirtyNext; + assert( p->bPurgeable || p->eCreate==2 ); + if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/ + assert( p->bPurgeable==0 || p->eCreate==1 ); + 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->pDirtyNext = p->pDirty; + if( pPage->pDirtyNext ){ + assert( pPage->pDirtyNext->pDirtyPrev==0 ); + pPage->pDirtyNext->pDirtyPrev = pPage; + }else{ + p->pDirtyTail = pPage; + if( p->bPurgeable ){ + assert( p->eCreate==2 ); + p->eCreate = 1; + } + } + p->pDirty = pPage; + + /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set + ** pSynced to point to it. Checking the NEED_SYNC flag is an + ** optimization, as if pSynced points to a page with the NEED_SYNC + ** flag set sqlite3PcacheFetchStress() searches through all newer + ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */ + if( !p->pSynced + && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ + ){ + p->pSynced = pPage; + } + } + pcacheDump(p); +} + +/* +** Wrapper around the pluggable caches xUnpin method. If the cache is +** being used for an in-memory database, this function is a no-op. +*/ +static void pcacheUnpin(PgHdr *p){ + if( p->pCache->bPurgeable ){ + pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno)); + sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); + pcacheDump(p->pCache); + } +} + +/* +** Compute the number of pages of cache requested. p->szCache is the +** cache size requested by the "PRAGMA cache_size" statement. +*/ +static int numberOfCachePages(PCache *p){ + if( p->szCache>=0 ){ + /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the + ** suggested cache size is set to N. */ + return p->szCache; + }else{ + /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then + ** the number of cache pages is adjusted to use approximately abs(N*1024) + ** bytes of memory. */ + return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); + } +} + +/*************************************************** General Interfaces ****** +** +** Initialize and shutdown the page cache subsystem. Neither of these +** functions are threadsafe. +*/ +SQLITE_PRIVATE int sqlite3PcacheInitialize(void){ + if( sqlite3GlobalConfig.pcache2.xInit==0 ){ + /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the + ** built-in default page cache is used instead of the application defined + ** page cache. */ + sqlite3PCacheSetDefault(); + } + return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg); +} +SQLITE_PRIVATE void sqlite3PcacheShutdown(void){ + if( sqlite3GlobalConfig.pcache2.xShutdown ){ + /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */ + sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg); + } +} + +/* +** Return the size in bytes of a PCache object. +*/ +SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); } + +/* +** Create a new PCache object. Storage space to hold the object +** has already been allocated and is passed in as the p pointer. +** The caller discovers how much space needs to be allocated by +** calling sqlite3PcacheSize(). +** +** szExtra is some extra space allocated for each page. The first +** 8 bytes of the extra space will be zeroed as the page is allocated, +** but remaining content will be uninitialized. Though it is opaque +** to this module, the extra space really ends up being the MemPage +** structure in the pager. +*/ +SQLITE_PRIVATE int sqlite3PcacheOpen( + int szPage, /* Size of every page */ + int szExtra, /* Extra space associated with each page */ + int bPurgeable, /* True if pages are on backing store */ + int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */ + void *pStress, /* Argument to xStress */ + PCache *p /* Preallocated space for the PCache */ +){ + memset(p, 0, sizeof(PCache)); + p->szPage = 1; + p->szExtra = szExtra; + assert( szExtra>=8 ); /* First 8 bytes will be zeroed */ + p->bPurgeable = bPurgeable; + p->eCreate = 2; + p->xStress = xStress; + p->pStress = pStress; + p->szCache = 100; + p->szSpill = 1; + pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable)); + return sqlite3PcacheSetPageSize(p, szPage); +} + +/* +** Change the page size for PCache object. The caller must ensure that there +** are no outstanding page references when this function is called. +*/ +SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ + assert( pCache->nRefSum==0 && pCache->pDirty==0 ); + if( pCache->szPage ){ + sqlite3_pcache *pNew; + pNew = sqlite3GlobalConfig.pcache2.xCreate( + szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), + pCache->bPurgeable + ); + if( pNew==0 ) return SQLITE_NOMEM_BKPT; + sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); + if( pCache->pCache ){ + sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); + } + pCache->pCache = pNew; + pCache->szPage = szPage; + pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage)); + } + return SQLITE_OK; +} + +/* +** Try to obtain a page from the cache. +** +** This routine returns a pointer to an sqlite3_pcache_page object if +** such an object is already in cache, or if a new one is created. +** This routine returns a NULL pointer if the object was not in cache +** and could not be created. +** +** The createFlags should be 0 to check for existing pages and should +** be 3 (not 1, but 3) to try to create a new page. +** +** If the createFlag is 0, then NULL is always returned if the page +** is not already in the cache. If createFlag is 1, then a new page +** is created only if that can be done without spilling dirty pages +** and without exceeding the cache size limit. +** +** The caller needs to invoke sqlite3PcacheFetchFinish() to properly +** initialize the sqlite3_pcache_page object and convert it into a +** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish() +** routines are split this way for performance reasons. When separated +** they can both (usually) operate without having to push values to +** the stack on entry and pop them back off on exit, which saves a +** lot of pushing and popping. +*/ +SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number to obtain */ + int createFlag /* If true, create page if it does not exist already */ +){ + int eCreate; + sqlite3_pcache_page *pRes; + + assert( pCache!=0 ); + assert( pCache->pCache!=0 ); + assert( createFlag==3 || createFlag==0 ); + assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); + + /* eCreate defines what to do if the page does not exist. + ** 0 Do not allocate a new page. (createFlag==0) + ** 1 Allocate a new page if doing so is inexpensive. + ** (createFlag==1 AND bPurgeable AND pDirty) + ** 2 Allocate a new page even it doing so is difficult. + ** (createFlag==1 AND !(bPurgeable AND pDirty) + */ + eCreate = createFlag & pCache->eCreate; + assert( eCreate==0 || eCreate==1 || eCreate==2 ); + assert( createFlag==0 || pCache->eCreate==eCreate ); + assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); + pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); + pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno, + createFlag?" create":"",pRes)); + return pRes; +} + +/* +** If the sqlite3PcacheFetch() routine is unable to allocate a new +** page because no clean pages are available for reuse and the cache +** size limit has been reached, then this routine can be invoked to +** try harder to allocate a page. This routine might invoke the stress +** callback to spill dirty pages to the journal. It will then try to +** allocate the new page and will only fail to allocate a new page on +** an OOM error. +** +** This routine should be invoked only after sqlite3PcacheFetch() fails. +*/ +SQLITE_PRIVATE int sqlite3PcacheFetchStress( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number to obtain */ + sqlite3_pcache_page **ppPage /* Write result here */ +){ + PgHdr *pPg; + if( pCache->eCreate==2 ) return 0; + + if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ + /* Find a dirty page to write-out and recycle. First try to find a + ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC + ** cleared), but if that is not possible settle for any other + ** unreferenced dirty page. + ** + ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC + ** flag is currently referenced, then the following may leave pSynced + ** set incorrectly (pointing to other than the LRU page with NEED_SYNC + ** cleared). This is Ok, as pSynced is just an optimization. */ + for(pPg=pCache->pSynced; + pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); + pPg=pPg->pDirtyPrev + ); + pCache->pSynced = pPg; + if( !pPg ){ + for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); + } + if( pPg ){ + int rc; +#ifdef SQLITE_LOG_CACHE_SPILL + sqlite3_log(SQLITE_FULL, + "spill page %d making room for %d - cache used: %d/%d", + pPg->pgno, pgno, + sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), + numberOfCachePages(pCache)); +#endif + pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno)); + rc = pCache->xStress(pCache->pStress, pPg); + pcacheDump(pCache); + if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ + return rc; + } + } + } + *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); + return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; +} + +/* +** This is a helper routine for sqlite3PcacheFetchFinish() +** +** In the uncommon case where the page being fetched has not been +** initialized, this routine is invoked to do the initialization. +** This routine is broken out into a separate function since it +** requires extra stack manipulation that can be avoided in the common +** case. +*/ +static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number obtained */ + sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ +){ + PgHdr *pPgHdr; + assert( pPage!=0 ); + pPgHdr = (PgHdr*)pPage->pExtra; + assert( pPgHdr->pPage==0 ); + memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty)); + pPgHdr->pPage = pPage; + pPgHdr->pData = pPage->pBuf; + pPgHdr->pExtra = (void *)&pPgHdr[1]; + memset(pPgHdr->pExtra, 0, 8); + pPgHdr->pCache = pCache; + pPgHdr->pgno = pgno; + pPgHdr->flags = PGHDR_CLEAN; + return sqlite3PcacheFetchFinish(pCache,pgno,pPage); +} + +/* +** This routine converts the sqlite3_pcache_page object returned by +** sqlite3PcacheFetch() into an initialized PgHdr object. This routine +** must be called after sqlite3PcacheFetch() in order to get a usable +** result. +*/ +SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish( + PCache *pCache, /* Obtain the page from this cache */ + Pgno pgno, /* Page number obtained */ + sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ +){ + PgHdr *pPgHdr; + + assert( pPage!=0 ); + pPgHdr = (PgHdr *)pPage->pExtra; + + if( !pPgHdr->pPage ){ + return pcacheFetchFinishWithInit(pCache, pgno, pPage); + } + pCache->nRefSum++; + pPgHdr->nRef++; + assert( sqlite3PcachePageSanity(pPgHdr) ); + return pPgHdr; +} + +/* +** Decrement the reference count on a page. If the page is clean and the +** reference count drops to 0, then it is made eligible for recycling. +*/ +SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ + assert( p->nRef>0 ); + p->pCache->nRefSum--; + 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. */ + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); + } + } +} + +/* +** Increase the reference count of a supplied page by 1. +*/ +SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){ + assert(p->nRef>0); + assert( sqlite3PcachePageSanity(p) ); + p->nRef++; + p->pCache->nRefSum++; +} + +/* +** Drop a page from the cache. There must be exactly one reference to the +** page. This function deletes that reference, so after it returns the +** page pointed to by p is invalid. +*/ +SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){ + assert( p->nRef==1 ); + assert( sqlite3PcachePageSanity(p) ); + if( p->flags&PGHDR_DIRTY ){ + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); + } + p->pCache->nRefSum--; + sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); +} + +/* +** Make sure the page is marked as dirty. If it isn't dirty already, +** make it so. +*/ +SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ + assert( p->nRef>0 ); + assert( sqlite3PcachePageSanity(p) ); + if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ + p->flags &= ~PGHDR_DONT_WRITE; + if( p->flags & PGHDR_CLEAN ){ + p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); + pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); + assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); + } + assert( sqlite3PcachePageSanity(p) ); + } +} + +/* +** Make sure the page is marked as clean. If it isn't clean already, +** make it so. +*/ +SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){ + assert( sqlite3PcachePageSanity(p) ); + if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){ + assert( (p->flags & PGHDR_CLEAN)==0 ); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); + p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); + p->flags |= PGHDR_CLEAN; + pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); + assert( sqlite3PcachePageSanity(p) ); + if( p->nRef==0 ){ + pcacheUnpin(p); + } + } +} + +/* +** Make every page in the cache clean. +*/ +SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){ + PgHdr *p; + pcacheTrace(("%p.CLEAN-ALL\n",pCache)); + while( (p = pCache->pDirty)!=0 ){ + sqlite3PcacheMakeClean(p); + } +} + +/* +** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages. +*/ +SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){ + PgHdr *p; + pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache)); + for(p=pCache->pDirty; p; p=p->pDirtyNext){ + p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE); + } + pCache->pSynced = pCache->pDirtyTail; +} + +/* +** Clear the PGHDR_NEED_SYNC flag from all dirty pages. +*/ +SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){ + PgHdr *p; + for(p=pCache->pDirty; p; p=p->pDirtyNext){ + p->flags &= ~PGHDR_NEED_SYNC; + } + pCache->pSynced = pCache->pDirtyTail; +} + +/* +** Change the page number of page p to newPgno. +*/ +SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ + PCache *pCache = p->pCache; + assert( p->nRef>0 ); + assert( newPgno>0 ); + assert( sqlite3PcachePageSanity(p) ); + pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); + sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); + p->pgno = newPgno; + if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); + } +} + +/* +** Drop every cache entry whose page number is greater than "pgno". The +** caller must ensure that there are no outstanding references to any pages +** other than page 1 with a page number greater than pgno. +** +** If there is a reference to page 1 and the pgno parameter passed to this +** function is 0, then the data area associated with page 1 is zeroed, but +** the page object is not dropped. +*/ +SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ + if( pCache->pCache ){ + PgHdr *p; + PgHdr *pNext; + pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno)); + for(p=pCache->pDirty; p; p=pNext){ + pNext = p->pDirtyNext; + /* This routine never gets call with a positive pgno except right + ** after sqlite3PcacheCleanAll(). So if there are dirty pages, + ** it must be that pgno==0. + */ + assert( p->pgno>0 ); + if( p->pgno>pgno ){ + assert( p->flags&PGHDR_DIRTY ); + sqlite3PcacheMakeClean(p); + } + } + if( pgno==0 && pCache->nRefSum ){ + sqlite3_pcache_page *pPage1; + pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0); + if( ALWAYS(pPage1) ){ /* Page 1 is always available in cache, because + ** pCache->nRefSum>0 */ + memset(pPage1->pBuf, 0, pCache->szPage); + pgno = 1; + } + } + sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1); + } +} + +/* +** Close a cache. +*/ +SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){ + assert( pCache->pCache!=0 ); + pcacheTrace(("%p.CLOSE\n",pCache)); + sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); +} + +/* +** Discard the contents of the cache. +*/ +SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){ + sqlite3PcacheTruncate(pCache, 0); +} + +/* +** Merge two lists of pages connected by pDirty and in pgno order. +** Do not bother fixing the pDirtyPrev pointers. +*/ +static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ + PgHdr result, *pTail; + pTail = &result; + assert( pA!=0 && pB!=0 ); + for(;;){ + if( pA->pgnopgno ){ + pTail->pDirty = pA; + pTail = pA; + pA = pA->pDirty; + if( pA==0 ){ + pTail->pDirty = pB; + break; + } + }else{ + pTail->pDirty = pB; + pTail = pB; + pB = pB->pDirty; + if( pB==0 ){ + pTail->pDirty = pA; + break; + } + } + } + return result.pDirty; +} + +/* +** Sort the list of pages in accending order by pgno. Pages are +** connected by pDirty pointers. The pDirtyPrev pointers are +** corrupted by this sort. +** +** Since there cannot be more than 2^31 distinct pages in a database, +** there cannot be more than 31 buckets required by the merge sorter. +** One extra bucket is added to catch overflow in case something +** ever changes to make the previous sentence incorrect. +*/ +#define N_SORT_BUCKET 32 +static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ + PgHdr *a[N_SORT_BUCKET], *p; + int i; + memset(a, 0, sizeof(a)); + while( pIn ){ + p = pIn; + pIn = p->pDirty; + p->pDirty = 0; + for(i=0; ALWAYS(ipDirty; p; p=p->pDirtyNext){ + p->pDirty = p->pDirtyNext; + } + return pcacheSortDirtyList(pCache->pDirty); +} + +/* +** Return the total number of references to all pages held by the cache. +** +** This is not the total number of pages referenced, but the sum of the +** reference count for all pages. +*/ +SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){ + return pCache->nRefSum; +} + +/* +** Return the number of references to the page supplied as an argument. +*/ +SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){ + return p->nRef; +} + +/* +** Return the total number of pages in the cache. +*/ +SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){ + assert( pCache->pCache!=0 ); + return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); +} + +#ifdef SQLITE_TEST +/* +** Get the suggested cache-size value. +*/ +SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){ + return numberOfCachePages(pCache); +} +#endif + +/* +** Set the suggested cache-size value. +*/ +SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ + assert( pCache->pCache!=0 ); + pCache->szCache = mxPage; + sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, + numberOfCachePages(pCache)); +} + +/* +** Set the suggested cache-spill value. Make no changes if if the +** argument is zero. Return the effective cache-spill size, which will +** be the larger of the szSpill and szCache. +*/ +SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){ + int res; + assert( p->pCache!=0 ); + if( mxPage ){ + if( mxPage<0 ){ + mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra)); + } + p->szSpill = mxPage; + } + res = numberOfCachePages(p); + if( resszSpill ) res = p->szSpill; + return res; +} + +/* +** Free up as much memory as possible from the page cache. +*/ +SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){ + assert( pCache->pCache!=0 ); + sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); +} + +/* +** Return the size of the header added by this middleware layer +** in the page-cache hierarchy. +*/ +SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); } + +/* +** Return the number of dirty pages currently in the cache, as a percentage +** of the configured cache size. +*/ +SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){ + PgHdr *pDirty; + int nDirty = 0; + int nCache = numberOfCachePages(pCache); + for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++; + return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; +} + +#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) +/* +** For all dirty pages currently in the cache, invoke the specified +** callback. This is only used if the SQLITE_CHECK_PAGES macro is +** defined. +*/ +SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){ + PgHdr *pDirty; + for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){ + xIter(pDirty); + } +} +#endif + +/************** End of pcache.c **********************************************/ +/************** Begin file pcache1.c *****************************************/ +/* +** 2008 November 05 +** +** 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 the default page cache implementation (the +** sqlite3_pcache interface). It also contains part of the implementation +** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features. +** If the default page cache implementation is overridden, then neither of +** these two features are available. +** +** A Page cache line looks like this: +** +** ------------------------------------------------------------- +** | database page content | PgHdr1 | MemPage | PgHdr | +** ------------------------------------------------------------- +** +** The database page content is up front (so that buffer overreads tend to +** flow harmlessly into the PgHdr1, MemPage, and PgHdr extensions). MemPage +** is the extension added by the btree.c module containing information such +** as the database page number and how that database page is used. PgHdr +** is added by the pcache.c layer and contains information used to keep track +** of which pages are "dirty". PgHdr1 is an extension added by this +** module (pcache1.c). The PgHdr1 header is a subclass of sqlite3_pcache_page. +** PgHdr1 contains information needed to look up a page by its page number. +** The superclass sqlite3_pcache_page.pBuf points to the start of the +** database page content and sqlite3_pcache_page.pExtra points to PgHdr. +** +** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at +** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The +** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this +** size can vary according to architecture, compile-time options, and +** SQLite library version number. +** +** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained +** using a separate memory allocation from the database page content. This +** seeks to overcome the "clownshoe" problem (also called "internal +** fragmentation" in academic literature) of allocating a few bytes more +** than a power of two with the memory allocator rounding up to the next +** power of two, and leaving the rounded-up space unused. +** +** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates +** with this module. Information is passed back and forth as PgHdr1 pointers. +** +** The pcache.c and pager.c modules deal pointers to PgHdr objects. +** The btree.c module deals with pointers to MemPage objects. +** +** SOURCE OF PAGE CACHE MEMORY: +** +** Memory for a page might come from any of three sources: +** +** (1) The general-purpose memory allocator - sqlite3Malloc() +** (2) Global page-cache memory provided using sqlite3_config() with +** SQLITE_CONFIG_PAGECACHE. +** (3) PCache-local bulk allocation. +** +** The third case is a chunk of heap memory (defaulting to 100 pages worth) +** that is allocated when the page cache is created. The size of the local +** bulk allocation can be adjusted using +** +** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N). +** +** If N is positive, then N pages worth of memory are allocated using a single +** sqlite3Malloc() call and that memory is used for the first N pages allocated. +** Or if N is negative, then -1024*N bytes of memory are allocated and used +** for as many pages as can be accomodated. +** +** Only one of (2) or (3) can be used. Once the memory available to (2) or +** (3) is exhausted, subsequent allocations fail over to the general-purpose +** memory allocator (1). +** +** Earlier versions of SQLite used only methods (1) and (2). But experiments +** show that method (3) with N==100 provides about a 5% performance boost for +** common workloads. +*/ +/* #include "sqliteInt.h" */ + +typedef struct PCache1 PCache1; +typedef struct PgHdr1 PgHdr1; +typedef struct PgFreeslot PgFreeslot; +typedef struct PGroup PGroup; + +/* +** Each cache entry is represented by an instance of the following +** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of +** PgHdr1.pCache->szPage bytes is allocated directly before this structure +** in memory. +*/ +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 */ + PCache1 *pCache; /* Cache that currently owns this page */ + PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */ + PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ +}; + +/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set +** of one or more PCaches that are able to recycle each other's unpinned +** pages when they are under memory pressure. A PGroup is an instance of +** the following object. +** +** This page cache implementation works in one of two modes: +** +** (1) Every PCache is the sole member of its own PGroup. There is +** one PGroup per PCache. +** +** (2) There is a single global PGroup that all PCaches are a member +** of. +** +** Mode 1 uses more memory (since PCache instances are not able to rob +** unused pages from other PCaches) but it also operates without a mutex, +** and is therefore often faster. Mode 2 requires a mutex in order to be +** threadsafe, but recycles pages more efficiently. +** +** For mode (1), PGroup.mutex is NULL. For mode (2) there is only a single +** PGroup which is the pcache1.grp global variable and its mutex is +** SQLITE_MUTEX_STATIC_LRU. +*/ +struct PGroup { + sqlite3_mutex *mutex; /* MUTEX_STATIC_LRU or NULL */ + 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 */ + PgHdr1 lru; /* The beginning and end of the LRU list */ +}; + +/* Each page cache is an instance of the following object. Every +** open database file (including each in-memory database and each +** temporary or transient database) has a single page cache which +** is an instance of this object. +** +** Pointers to structures of this type are cast and returned as +** opaque sqlite3_pcache* handles. +*/ +struct PCache1 { + /* Cache configuration parameters. Page size (szPage) and the purgeable + ** flag (bPurgeable) are set when the cache is created. 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 */ + int szPage; /* Size of database content section */ + int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ + int szAlloc; /* Total size of one pcache line */ + int bPurgeable; /* True if cache is purgeable */ + unsigned int nMin; /* Minimum number of pages reserved */ + unsigned int nMax; /* Configured "cache_size" value */ + unsigned int n90pct; /* nMax*9/10 */ + unsigned int iMaxKey; /* Largest key seen since xTruncate() */ + + /* Hash table of all pages. The following variables may only be accessed + ** when the accessor is holding the PGroup mutex. + */ + unsigned int nRecyclable; /* Number of pages in the LRU list */ + unsigned int nPage; /* Total number of pages in apHash */ + unsigned int nHash; /* Number of slots in apHash[] */ + PgHdr1 **apHash; /* Hash table for fast lookup by key */ + PgHdr1 *pFree; /* List of unused pcache-local pages */ + void *pBulk; /* Bulk memory used by pcache-local */ +}; + +/* +** Free slots in the allocator used to divide up the global page cache +** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism. +*/ +struct PgFreeslot { + PgFreeslot *pNext; /* Next free slot */ +}; + +/* +** Global data used by this cache. +*/ +static SQLITE_WSD struct PCacheGlobal { + PGroup grp; /* The global PGroup for mode (2) */ + + /* Variables related to SQLITE_CONFIG_PAGECACHE settings. The + ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all + ** fixed at sqlite3_initialize() time and do not require mutex protection. + ** The nFreeSlot and pFree values do require mutex protection. + */ + int isInit; /* True if initialized */ + int separateCache; /* Use a new PGroup for each PCache */ + int nInitPage; /* Initial bulk allocation size */ + int szSlot; /* Size of each free slot */ + int nSlot; /* The number of pcache slots */ + int nReserve; /* Try to keep nFreeSlot above this */ + void *pStart, *pEnd; /* Bounds of global page cache memory */ + /* Above requires no mutex. Use mutex below for variable that follow. */ + sqlite3_mutex *mutex; /* Mutex for accessing the following: */ + PgFreeslot *pFree; /* Free page blocks */ + int nFreeSlot; /* Number of unused pcache slots */ + /* The following value requires a mutex to change. We skip the mutex on + ** reading because (1) most platforms read a 32-bit integer atomically and + ** (2) even if an incorrect value is read, no great harm is done since this + ** is really just an optimization. */ + int bUnderPressure; /* True if low on PAGECACHE memory */ +} pcache1_g; + +/* +** All code in this file should access the global structure above via the +** alias "pcache1". This ensures that the WSD emulation is used when +** compiling for systems that do not support real WSD. +*/ +#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g)) + +/* +** Macros to enter and leave the PCache LRU mutex. +*/ +#if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0 +# define pcache1EnterMutex(X) assert((X)->mutex==0) +# define pcache1LeaveMutex(X) assert((X)->mutex==0) +# define PCACHE1_MIGHT_USE_GROUP_MUTEX 0 +#else +# define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex) +# define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex) +# define PCACHE1_MIGHT_USE_GROUP_MUTEX 1 +#endif + +/******************************************************************************/ +/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/ + + +/* +** This function is called during initialization if a static buffer is +** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE +** verb to sqlite3_config(). Parameter pBuf points to an allocation large +** enough to contain 'n' buffers of 'sz' bytes each. +** +** This routine is called from sqlite3_initialize() and so it is guaranteed +** to be serialized already. There is no need for further mutexing. +*/ +SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ + if( pcache1.isInit ){ + PgFreeslot *p; + if( pBuf==0 ) sz = n = 0; + sz = ROUNDDOWN8(sz); + pcache1.szSlot = sz; + pcache1.nSlot = pcache1.nFreeSlot = n; + pcache1.nReserve = n>90 ? 10 : (n/10 + 1); + pcache1.pStart = pBuf; + pcache1.pFree = 0; + pcache1.bUnderPressure = 0; + while( n-- ){ + p = (PgFreeslot*)pBuf; + p->pNext = pcache1.pFree; + pcache1.pFree = p; + pBuf = (void*)&((char*)pBuf)[sz]; + } + pcache1.pEnd = pBuf; + } +} + +/* +** Try to initialize the pCache->pFree and pCache->pBulk fields. Return +** true if pCache->pFree ends up containing one or more free pages. +*/ +static int pcache1InitBulk(PCache1 *pCache){ + i64 szBulk; + char *zBulk; + if( pcache1.nInitPage==0 ) return 0; + /* Do not bother with a bulk allocation if the cache size very small */ + if( pCache->nMax<3 ) return 0; + sqlite3BeginBenignMalloc(); + if( pcache1.nInitPage>0 ){ + szBulk = pCache->szAlloc * (i64)pcache1.nInitPage; + }else{ + szBulk = -1024 * (i64)pcache1.nInitPage; + } + if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){ + szBulk = pCache->szAlloc*(i64)pCache->nMax; + } + zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); + sqlite3EndBenignMalloc(); + if( zBulk ){ + int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; + do{ + PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; + pX->page.pBuf = zBulk; + pX->page.pExtra = &pX[1]; + pX->isBulkLocal = 1; + pX->isAnchor = 0; + pX->pNext = pCache->pFree; + pCache->pFree = pX; + zBulk += pCache->szAlloc; + }while( --nBulk ); + } + return pCache->pFree!=0; +} + +/* +** Malloc function used within this file to allocate space from the buffer +** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no +** such buffer exists or there is no space left in it, this function falls +** back to sqlite3Malloc(). +** +** Multiple threads can run this routine at the same time. Global variables +** in pcache1 need to be protected via mutex. +*/ +static void *pcache1Alloc(int nByte){ + void *p = 0; + assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); + if( nByte<=pcache1.szSlot ){ + sqlite3_mutex_enter(pcache1.mutex); + p = (PgHdr1 *)pcache1.pFree; + if( p ){ + pcache1.pFree = pcache1.pFree->pNext; + pcache1.nFreeSlot--; + pcache1.bUnderPressure = pcache1.nFreeSlot=0 ); + sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte); + sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1); + } + sqlite3_mutex_leave(pcache1.mutex); + } + if( p==0 ){ + /* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get + ** it from sqlite3Malloc instead. + */ + p = sqlite3Malloc(nByte); +#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS + if( p ){ + int sz = sqlite3MallocSize(p); + sqlite3_mutex_enter(pcache1.mutex); + sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte); + sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); + sqlite3_mutex_leave(pcache1.mutex); + } +#endif + sqlite3MemdebugSetType(p, MEMTYPE_PCACHE); + } + return p; +} + +/* +** Free an allocated buffer obtained from pcache1Alloc(). +*/ +static void pcache1Free(void *p){ + if( p==0 ) return; + if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){ + PgFreeslot *pSlot; + sqlite3_mutex_enter(pcache1.mutex); + sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1); + pSlot = (PgFreeslot*)p; + pSlot->pNext = pcache1.pFree; + pcache1.pFree = pSlot; + pcache1.nFreeSlot++; + pcache1.bUnderPressure = pcache1.nFreeSlot=pcache1.pStart && ppGroup->mutex) ); + if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){ + p = pCache->pFree; + pCache->pFree = p->pNext; + p->pNext = 0; + }else{ +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + /* The group mutex must be released before pcache1Alloc() is called. This + ** is because it might call sqlite3_release_memory(), which assumes that + ** this mutex is not held. */ + assert( pcache1.separateCache==0 ); + assert( pCache->pGroup==&pcache1.grp ); + pcache1LeaveMutex(pCache->pGroup); +#endif + if( benignMalloc ){ sqlite3BeginBenignMalloc(); } +#ifdef SQLITE_PCACHE_SEPARATE_HEADER + pPg = pcache1Alloc(pCache->szPage); + p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra); + if( !pPg || !p ){ + pcache1Free(pPg); + sqlite3_free(p); + pPg = 0; + } +#else + pPg = pcache1Alloc(pCache->szAlloc); + p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; +#endif + if( benignMalloc ){ sqlite3EndBenignMalloc(); } +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + pcache1EnterMutex(pCache->pGroup); +#endif + if( pPg==0 ) return 0; + p->page.pBuf = pPg; + p->page.pExtra = &p[1]; + p->isBulkLocal = 0; + p->isAnchor = 0; + } + if( pCache->bPurgeable ){ + pCache->pGroup->nCurrentPage++; + } + return p; +} + +/* +** Free a page object allocated by pcache1AllocPage(). +*/ +static void pcache1FreePage(PgHdr1 *p){ + PCache1 *pCache; + assert( p!=0 ); + pCache = p->pCache; + assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) ); + if( p->isBulkLocal ){ + p->pNext = pCache->pFree; + pCache->pFree = p; + }else{ + pcache1Free(p->page.pBuf); +#ifdef SQLITE_PCACHE_SEPARATE_HEADER + sqlite3_free(p); +#endif + } + if( pCache->bPurgeable ){ + pCache->pGroup->nCurrentPage--; + } +} + +/* +** Malloc function used by SQLite to obtain space from the buffer configured +** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer +** exists, this function falls back to sqlite3Malloc(). +*/ +SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){ + return pcache1Alloc(sz); +} + +/* +** Free an allocated buffer obtained from sqlite3PageMalloc(). +*/ +SQLITE_PRIVATE void sqlite3PageFree(void *p){ + pcache1Free(p); +} + + +/* +** Return true if it desirable to avoid allocating a new page cache +** entry. +** +** If memory was allocated specifically to the page cache using +** SQLITE_CONFIG_PAGECACHE but that memory has all been used, then +** it is desirable to avoid allocating a new page cache entry because +** presumably SQLITE_CONFIG_PAGECACHE was suppose to be sufficient +** for all page cache needs and we should not need to spill the +** allocation onto the heap. +** +** Or, the heap is used for all page cache memory but the heap is +** under memory pressure, then again it is desirable to avoid +** allocating a new page cache entry in order to avoid stressing +** the heap even further. +*/ +static int pcache1UnderMemoryPressure(PCache1 *pCache){ + if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){ + return pcache1.bUnderPressure; + }else{ + return sqlite3HeapNearlyFull(); + } +} + +/******************************************************************************/ +/******** General Implementation Functions ************************************/ + +/* +** This function is used to resize the hash table used by the cache passed +** as the first argument. +** +** The PCache mutex must be held when this function is called. +*/ +static void pcache1ResizeHash(PCache1 *p){ + PgHdr1 **apNew; + unsigned int nNew; + unsigned int i; + + assert( sqlite3_mutex_held(p->pGroup->mutex) ); + + nNew = p->nHash*2; + if( nNew<256 ){ + nNew = 256; + } + + pcache1LeaveMutex(p->pGroup); + if( p->nHash ){ sqlite3BeginBenignMalloc(); } + apNew = (PgHdr1 **)sqlite3MallocZero(sizeof(PgHdr1 *)*nNew); + if( p->nHash ){ sqlite3EndBenignMalloc(); } + pcache1EnterMutex(p->pGroup); + if( apNew ){ + for(i=0; inHash; i++){ + PgHdr1 *pPage; + PgHdr1 *pNext = p->apHash[i]; + while( (pPage = pNext)!=0 ){ + unsigned int h = pPage->iKey % nNew; + pNext = pPage->pNext; + pPage->pNext = apNew[h]; + apNew[h] = pPage; + } + } + sqlite3_free(p->apHash); + p->apHash = apNew; + p->nHash = nNew; + } +} + +/* +** This function is used internally to remove the page pPage from the +** PGroup LRU list, if is part of it. If pPage is not part of the PGroup +** LRU list, then this function is a no-op. +** +** 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( pPage->pLruNext ); + assert( pPage->pLruPrev ); + assert( sqlite3_mutex_held(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--; + return pPage; +} + + +/* +** Remove the page supplied as an argument from the hash table +** (PCache1.apHash structure) that it is currently stored in. +** Also free the page if freePage is true. +** +** The PGroup mutex must be held when this function is called. +*/ +static void pcache1RemoveFromHash(PgHdr1 *pPage, int freeFlag){ + unsigned int h; + PCache1 *pCache = pPage->pCache; + PgHdr1 **pp; + + assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); + h = pPage->iKey % pCache->nHash; + for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext); + *pp = (*pp)->pNext; + + pCache->nPage--; + if( freeFlag ) pcache1FreePage(pPage); +} + +/* +** If there are currently more than nMaxPage pages allocated, try +** to recycle pages to reduce the number allocated to nMaxPage. +*/ +static void pcache1EnforceMaxPage(PCache1 *pCache){ + PGroup *pGroup = pCache->pGroup; + PgHdr1 *p; + assert( sqlite3_mutex_held(pGroup->mutex) ); + while( pGroup->nCurrentPage>pGroup->nMaxPage + && (p=pGroup->lru.pLruPrev)->isAnchor==0 + ){ + assert( p->pCache->pGroup==pGroup ); + assert( p->isPinned==0 ); + pcache1PinPage(p); + pcache1RemoveFromHash(p, 1); + } + if( pCache->nPage==0 && pCache->pBulk ){ + sqlite3_free(pCache->pBulk); + pCache->pBulk = pCache->pFree = 0; + } +} + +/* +** Discard all pages from cache pCache with a page number (key value) +** greater than or equal to iLimit. Any pinned pages that meet this +** criteria are unpinned before they are discarded. +** +** The PCache mutex must be held when this function is called. +*/ +static void pcache1TruncateUnsafe( + PCache1 *pCache, /* The cache to truncate */ + unsigned int iLimit /* Drop pages with this pgno or larger */ +){ + TESTONLY( int nPage = 0; ) /* To assert pCache->nPage is correct */ + unsigned int h, iStop; + assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); + assert( pCache->iMaxKey >= iLimit ); + assert( pCache->nHash > 0 ); + if( pCache->iMaxKey - iLimit < pCache->nHash ){ + /* If we are just shaving the last few pages off the end of the + ** cache, then there is no point in scanning the entire hash table. + ** Only scan those hash slots that might contain pages that need to + ** be removed. */ + h = iLimit % pCache->nHash; + iStop = pCache->iMaxKey % pCache->nHash; + TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */ + }else{ + /* This is the general case where many pages are being removed. + ** It is necessary to scan the entire hash table */ + h = pCache->nHash/2; + iStop = h - 1; + } + for(;;){ + PgHdr1 **pp; + PgHdr1 *pPage; + assert( hnHash ); + pp = &pCache->apHash[h]; + while( (pPage = *pp)!=0 ){ + if( pPage->iKey>=iLimit ){ + pCache->nPage--; + *pp = pPage->pNext; + if( !pPage->isPinned ) pcache1PinPage(pPage); + pcache1FreePage(pPage); + }else{ + pp = &pPage->pNext; + TESTONLY( if( nPage>=0 ) nPage++; ) + } + } + if( h==iStop ) break; + h = (h+1) % pCache->nHash; + } + assert( nPage<0 || pCache->nPage==(unsigned)nPage ); +} + +/******************************************************************************/ +/******** sqlite3_pcache Methods **********************************************/ + +/* +** Implementation of the sqlite3_pcache.xInit method. +*/ +static int pcache1Init(void *NotUsed){ + UNUSED_PARAMETER(NotUsed); + assert( pcache1.isInit==0 ); + memset(&pcache1, 0, sizeof(pcache1)); + + + /* + ** The pcache1.separateCache variable is true if each PCache has its own + ** private PGroup (mode-1). pcache1.separateCache is false if the single + ** PGroup in pcache1.grp is used for all page caches (mode-2). + ** + ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT + ** + ** * Use a unified cache in single-threaded applications that have + ** configured a start-time buffer for use as page-cache memory using + ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL + ** pBuf argument. + ** + ** * Otherwise use separate caches (mode-1) + */ +#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) + pcache1.separateCache = 0; +#elif SQLITE_THREADSAFE + pcache1.separateCache = sqlite3GlobalConfig.pPage==0 + || sqlite3GlobalConfig.bCoreMutex>0; +#else + pcache1.separateCache = sqlite3GlobalConfig.pPage==0; +#endif + +#if SQLITE_THREADSAFE + if( sqlite3GlobalConfig.bCoreMutex ){ + pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU); + pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM); + } +#endif + if( pcache1.separateCache + && sqlite3GlobalConfig.nPage!=0 + && sqlite3GlobalConfig.pPage==0 + ){ + pcache1.nInitPage = sqlite3GlobalConfig.nPage; + }else{ + pcache1.nInitPage = 0; + } + pcache1.grp.mxPinned = 10; + pcache1.isInit = 1; + return SQLITE_OK; +} + +/* +** Implementation of the sqlite3_pcache.xShutdown method. +** Note that the static mutex allocated in xInit does +** not need to be freed. +*/ +static void pcache1Shutdown(void *NotUsed){ + UNUSED_PARAMETER(NotUsed); + assert( pcache1.isInit!=0 ); + memset(&pcache1, 0, sizeof(pcache1)); +} + +/* forward declaration */ +static void pcache1Destroy(sqlite3_pcache *p); + +/* +** Implementation of the sqlite3_pcache.xCreate method. +** +** Allocate a new cache. +*/ +static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ + PCache1 *pCache; /* The newly created page cache */ + PGroup *pGroup; /* The group the new page cache will belong to */ + int sz; /* Bytes of memory required to allocate the new cache */ + + assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 ); + assert( szExtra < 300 ); + + sz = sizeof(PCache1) + sizeof(PGroup)*pcache1.separateCache; + pCache = (PCache1 *)sqlite3MallocZero(sz); + if( pCache ){ + if( pcache1.separateCache ){ + pGroup = (PGroup*)&pCache[1]; + pGroup->mxPinned = 10; + }else{ + pGroup = &pcache1.grp; + } + if( pGroup->lru.isAnchor==0 ){ + pGroup->lru.isAnchor = 1; + pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru; + } + pCache->pGroup = pGroup; + pCache->szPage = szPage; + pCache->szExtra = szExtra; + pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1)); + pCache->bPurgeable = (bPurgeable ? 1 : 0); + pcache1EnterMutex(pGroup); + pcache1ResizeHash(pCache); + if( bPurgeable ){ + pCache->nMin = 10; + pGroup->nMinPage += pCache->nMin; + pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; + } + pcache1LeaveMutex(pGroup); + if( pCache->nHash==0 ){ + pcache1Destroy((sqlite3_pcache*)pCache); + pCache = 0; + } + } + return (sqlite3_pcache *)pCache; +} + +/* +** Implementation of the sqlite3_pcache.xCachesize method. +** +** Configure the cache_size limit for a cache. +*/ +static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ + PCache1 *pCache = (PCache1 *)p; + if( pCache->bPurgeable ){ + PGroup *pGroup = pCache->pGroup; + pcache1EnterMutex(pGroup); + pGroup->nMaxPage += (nMax - pCache->nMax); + pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; + pCache->nMax = nMax; + pCache->n90pct = pCache->nMax*9/10; + pcache1EnforceMaxPage(pCache); + pcache1LeaveMutex(pGroup); + } +} + +/* +** Implementation of the sqlite3_pcache.xShrink method. +** +** Free up as much memory as possible. +*/ +static void pcache1Shrink(sqlite3_pcache *p){ + PCache1 *pCache = (PCache1*)p; + if( pCache->bPurgeable ){ + PGroup *pGroup = pCache->pGroup; + int savedMaxPage; + pcache1EnterMutex(pGroup); + savedMaxPage = pGroup->nMaxPage; + pGroup->nMaxPage = 0; + pcache1EnforceMaxPage(pCache); + pGroup->nMaxPage = savedMaxPage; + pcache1LeaveMutex(pGroup); + } +} + +/* +** Implementation of the sqlite3_pcache.xPagecount method. +*/ +static int pcache1Pagecount(sqlite3_pcache *p){ + int n; + PCache1 *pCache = (PCache1*)p; + pcache1EnterMutex(pCache->pGroup); + n = pCache->nPage; + pcache1LeaveMutex(pCache->pGroup); + return n; +} + + +/* +** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described +** in the header of the pcache1Fetch() procedure. +** +** This steps are broken out into a separate procedure because they are +** usually not needed, and by avoiding the stack initialization required +** for these steps, the main pcache1Fetch() procedure can run faster. +*/ +static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( + PCache1 *pCache, + unsigned int iKey, + int createFlag +){ + unsigned int nPinned; + PGroup *pGroup = pCache->pGroup; + PgHdr1 *pPage = 0; + + /* Step 3: Abort if createFlag is 1 but the cache is nearly full */ + assert( pCache->nPage >= pCache->nRecyclable ); + nPinned = pCache->nPage - pCache->nRecyclable; + assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage ); + assert( pCache->n90pct == pCache->nMax*9/10 ); + if( createFlag==1 && ( + nPinned>=pGroup->mxPinned + || nPinned>=pCache->n90pct + || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclablenPage>=pCache->nHash ) pcache1ResizeHash(pCache); + assert( pCache->nHash>0 && pCache->apHash ); + + /* Step 4. Try to recycle a page. */ + if( pCache->bPurgeable + && !pGroup->lru.pLruPrev->isAnchor + && ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache)) + ){ + PCache1 *pOther; + pPage = pGroup->lru.pLruPrev; + assert( pPage->isPinned==0 ); + pcache1RemoveFromHash(pPage, 0); + pcache1PinPage(pPage); + pOther = pPage->pCache; + if( pOther->szAlloc != pCache->szAlloc ){ + pcache1FreePage(pPage); + pPage = 0; + }else{ + pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); + } + } + + /* Step 5. If a usable page buffer has still not been found, + ** attempt to allocate a new one. + */ + if( !pPage ){ + pPage = pcache1AllocPage(pCache, createFlag==1); + } + + if( pPage ){ + unsigned int h = iKey % pCache->nHash; + pCache->nPage++; + pPage->iKey = iKey; + pPage->pNext = pCache->apHash[h]; + 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 ){ + pCache->iMaxKey = iKey; + } + } + return pPage; +} + +/* +** Implementation of the sqlite3_pcache.xFetch method. +** +** Fetch a page by key value. +** +** Whether or not a new page may be allocated by this function depends on +** the value of the createFlag argument. 0 means do not allocate a new +** page. 1 means allocate a new page if space is easily available. 2 +** means to try really hard to allocate a new page. +** +** For a non-purgeable cache (a cache used as the storage for an in-memory +** database) there is really no difference between createFlag 1 and 2. So +** the calling function (pcache.c) will never have a createFlag of 1 on +** a non-purgeable cache. +** +** There are three different approaches to obtaining space for a page, +** depending on the value of parameter createFlag (which may be 0, 1 or 2). +** +** 1. Regardless of the value of createFlag, the cache is searched for a +** copy of the requested page. If one is found, it is returned. +** +** 2. If createFlag==0 and the page is not already in the cache, NULL is +** returned. +** +** 3. If createFlag is 1, and the page is not already in the cache, then +** return NULL (do not allocate a new page) if any of the following +** conditions are true: +** +** (a) the number of pages pinned by the cache is greater than +** PCache1.nMax, or +** +** (b) the number of pages pinned by the cache is greater than +** the sum of nMax for all purgeable caches, less the sum of +** nMin for all other purgeable caches, or +** +** 4. If none of the first three conditions apply and the cache is marked +** as purgeable, and if one of the following is true: +** +** (a) The number of pages allocated for the cache is already +** PCache1.nMax, or +** +** (b) The number of pages allocated for all purgeable caches is +** already equal to or greater than the sum of nMax for all +** purgeable caches, +** +** (c) The system is under memory pressure and wants to avoid +** unnecessary pages cache entry allocations +** +** then attempt to recycle a page from the LRU list. If it is the right +** size, return the recycled buffer. Otherwise, free the buffer and +** proceed to step 5. +** +** 5. Otherwise, allocate and return a new page buffer. +** +** There are two versions of this routine. pcache1FetchWithMutex() is +** the general case. pcache1FetchNoMutex() is a faster implementation for +** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper +** invokes the appropriate routine. +*/ +static PgHdr1 *pcache1FetchNoMutex( + sqlite3_pcache *p, + unsigned int iKey, + int createFlag +){ + PCache1 *pCache = (PCache1 *)p; + PgHdr1 *pPage = 0; + + /* Step 1: Search the hash table for an existing entry. */ + pPage = pCache->apHash[iKey % pCache->nHash]; + while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; } + + /* Step 2: If the page was found in the hash table, then return it. + ** If the page was not in the hash table and createFlag is 0, abort. + ** Otherwise (page not in hash and createFlag!=0) continue with + ** subsequent steps to try to create the page. */ + if( pPage ){ + if( !pPage->isPinned ){ + return pcache1PinPage(pPage); + }else{ + return pPage; + } + }else if( createFlag ){ + /* Steps 3, 4, and 5 implemented by this subroutine */ + return pcache1FetchStage2(pCache, iKey, createFlag); + }else{ + return 0; + } +} +#if PCACHE1_MIGHT_USE_GROUP_MUTEX +static PgHdr1 *pcache1FetchWithMutex( + sqlite3_pcache *p, + unsigned int iKey, + int createFlag +){ + PCache1 *pCache = (PCache1 *)p; + PgHdr1 *pPage; + + pcache1EnterMutex(pCache->pGroup); + pPage = pcache1FetchNoMutex(p, iKey, createFlag); + assert( pPage==0 || pCache->iMaxKey>=iKey ); + pcache1LeaveMutex(pCache->pGroup); + return pPage; +} +#endif +static sqlite3_pcache_page *pcache1Fetch( + sqlite3_pcache *p, + unsigned int iKey, + int createFlag +){ +#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG) + PCache1 *pCache = (PCache1 *)p; +#endif + + assert( offsetof(PgHdr1,page)==0 ); + assert( pCache->bPurgeable || createFlag!=1 ); + assert( pCache->bPurgeable || pCache->nMin==0 ); + assert( pCache->bPurgeable==0 || pCache->nMin==10 ); + assert( pCache->nMin==0 || pCache->bPurgeable ); + assert( pCache->nHash>0 ); +#if PCACHE1_MIGHT_USE_GROUP_MUTEX + if( pCache->pGroup->mutex ){ + return (sqlite3_pcache_page*)pcache1FetchWithMutex(p, iKey, createFlag); + }else +#endif + { + return (sqlite3_pcache_page*)pcache1FetchNoMutex(p, iKey, createFlag); + } +} + + +/* +** Implementation of the sqlite3_pcache.xUnpin method. +** +** Mark a page as unpinned (eligible for asynchronous recycling). +*/ +static void pcache1Unpin( + sqlite3_pcache *p, + sqlite3_pcache_page *pPg, + int reuseUnlikely +){ + PCache1 *pCache = (PCache1 *)p; + PgHdr1 *pPage = (PgHdr1 *)pPg; + PGroup *pGroup = pCache->pGroup; + + assert( pPage->pCache==pCache ); + pcache1EnterMutex(pGroup); + + /* It is an error to call this function if the page is already + ** part of the PGroup LRU list. + */ + assert( pPage->pLruPrev==0 && pPage->pLruNext==0 ); + assert( pPage->isPinned==1 ); + + if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){ + pcache1RemoveFromHash(pPage, 1); + }else{ + /* Add the page to the PGroup LRU list. */ + PgHdr1 **ppFirst = &pGroup->lru.pLruNext; + pPage->pLruPrev = &pGroup->lru; + (pPage->pLruNext = *ppFirst)->pLruPrev = pPage; + *ppFirst = pPage; + pCache->nRecyclable++; + pPage->isPinned = 0; + } + + pcache1LeaveMutex(pCache->pGroup); +} + +/* +** Implementation of the sqlite3_pcache.xRekey method. +*/ +static void pcache1Rekey( + sqlite3_pcache *p, + sqlite3_pcache_page *pPg, + unsigned int iOld, + unsigned int iNew +){ + PCache1 *pCache = (PCache1 *)p; + PgHdr1 *pPage = (PgHdr1 *)pPg; + PgHdr1 **pp; + unsigned int h; + assert( pPage->iKey==iOld ); + assert( pPage->pCache==pCache ); + + pcache1EnterMutex(pCache->pGroup); + + h = iOld%pCache->nHash; + pp = &pCache->apHash[h]; + while( (*pp)!=pPage ){ + pp = &(*pp)->pNext; + } + *pp = pPage->pNext; + + h = iNew%pCache->nHash; + pPage->iKey = iNew; + pPage->pNext = pCache->apHash[h]; + pCache->apHash[h] = pPage; + if( iNew>pCache->iMaxKey ){ + pCache->iMaxKey = iNew; + } + + pcache1LeaveMutex(pCache->pGroup); +} + +/* +** Implementation of the sqlite3_pcache.xTruncate method. +** +** Discard all unpinned pages in the cache with a page number equal to +** or greater than parameter iLimit. Any pinned pages with a page number +** equal to or greater than iLimit are implicitly unpinned. +*/ +static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){ + PCache1 *pCache = (PCache1 *)p; + pcache1EnterMutex(pCache->pGroup); + if( iLimit<=pCache->iMaxKey ){ + pcache1TruncateUnsafe(pCache, iLimit); + pCache->iMaxKey = iLimit-1; + } + pcache1LeaveMutex(pCache->pGroup); +} + +/* +** Implementation of the sqlite3_pcache.xDestroy method. +** +** Destroy a cache allocated using pcache1Create(). +*/ +static void pcache1Destroy(sqlite3_pcache *p){ + PCache1 *pCache = (PCache1 *)p; + PGroup *pGroup = pCache->pGroup; + assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) ); + pcache1EnterMutex(pGroup); + if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0); + assert( pGroup->nMaxPage >= pCache->nMax ); + pGroup->nMaxPage -= pCache->nMax; + assert( pGroup->nMinPage >= pCache->nMin ); + pGroup->nMinPage -= pCache->nMin; + pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; + pcache1EnforceMaxPage(pCache); + pcache1LeaveMutex(pGroup); + sqlite3_free(pCache->pBulk); + sqlite3_free(pCache->apHash); + sqlite3_free(pCache); +} + +/* +** This function is called during initialization (sqlite3_initialize()) to +** install the default pluggable cache module, assuming the user has not +** already provided an alternative. +*/ +SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){ + static const sqlite3_pcache_methods2 defaultMethods = { + 1, /* iVersion */ + 0, /* pArg */ + pcache1Init, /* xInit */ + pcache1Shutdown, /* xShutdown */ + pcache1Create, /* xCreate */ + pcache1Cachesize, /* xCachesize */ + pcache1Pagecount, /* xPagecount */ + pcache1Fetch, /* xFetch */ + pcache1Unpin, /* xUnpin */ + pcache1Rekey, /* xRekey */ + pcache1Truncate, /* xTruncate */ + pcache1Destroy, /* xDestroy */ + pcache1Shrink /* xShrink */ + }; + sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods); +} + +/* +** Return the size of the header on each page of this PCACHE implementation. +*/ +SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); } + +/* +** Return the global mutex used by this PCACHE implementation. The +** sqlite3_status() routine needs access to this mutex. +*/ +SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){ + return pcache1.mutex; +} + +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT +/* +** This function is called to free superfluous dynamically allocated memory +** held by the pager system. Memory in use by any SQLite pager allocated +** by the current thread may be sqlite3_free()ed. +** +** nReq is the number of bytes of memory required. Once this much has +** been released, the function returns. The return value is the total number +** of bytes of memory released. +*/ +SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){ + int nFree = 0; + assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); + assert( sqlite3_mutex_notheld(pcache1.mutex) ); + if( sqlite3GlobalConfig.pPage==0 ){ + PgHdr1 *p; + pcache1EnterMutex(&pcache1.grp); + while( (nReq<0 || nFreeisAnchor==0 + ){ + nFree += pcache1MemSize(p->page.pBuf); +#ifdef SQLITE_PCACHE_SEPARATE_HEADER + nFree += sqlite3MemSize(p); +#endif + assert( p->isPinned==0 ); + pcache1PinPage(p); + pcache1RemoveFromHash(p, 1); + } + pcache1LeaveMutex(&pcache1.grp); + } + return nFree; +} +#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */ + +#ifdef SQLITE_TEST +/* +** This function is used by test procedures to inspect the internal state +** of the global cache. +*/ +SQLITE_PRIVATE void sqlite3PcacheStats( + int *pnCurrent, /* OUT: Total number of pages cached */ + int *pnMax, /* OUT: Global maximum cache size */ + int *pnMin, /* OUT: Sum of PCache1.nMin for purgeable caches */ + int *pnRecyclable /* OUT: Total number of pages available for recycling */ +){ + PgHdr1 *p; + int nRecyclable = 0; + for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){ + assert( p->isPinned==0 ); + nRecyclable++; + } + *pnCurrent = pcache1.grp.nCurrentPage; + *pnMax = (int)pcache1.grp.nMaxPage; + *pnMin = (int)pcache1.grp.nMinPage; + *pnRecyclable = nRecyclable; +} +#endif + +/************** End of pcache1.c *********************************************/ +/************** Begin file rowset.c ******************************************/ +/* +** 2008 December 3 +** +** 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 implements an object we call a "RowSet". +** +** The RowSet object is a collection of rowids. Rowids +** are inserted into the RowSet in an arbitrary order. Inserts +** can be intermixed with tests to see if a given rowid has been +** previously inserted into the RowSet. +** +** After all inserts are finished, it is possible to extract the +** elements of the RowSet in sorted order. Once this extraction +** process has started, no new elements may be inserted. +** +** Hence, the primitive operations for a RowSet are: +** +** CREATE +** INSERT +** TEST +** SMALLEST +** DESTROY +** +** The CREATE and DESTROY primitives are the constructor and destructor, +** obviously. The INSERT primitive adds a new element to the RowSet. +** TEST checks to see if an element is already in the RowSet. SMALLEST +** extracts the least value from the RowSet. +** +** The INSERT primitive might allocate additional memory. Memory is +** allocated in chunks so most INSERTs do no allocation. There is an +** upper bound on the size of allocated memory. No memory is freed +** until DESTROY. +** +** The TEST primitive includes a "batch" number. The TEST primitive +** will only see elements that were inserted before the last change +** in the batch number. In other words, if an INSERT occurs between +** two TESTs where the TESTs have the same batch nubmer, then the +** value added by the INSERT will not be visible to the second TEST. +** The initial batch number is zero, so if the very first TEST contains +** a non-zero batch number, it will see all prior INSERTs. +** +** No INSERTs may occurs after a SMALLEST. An assertion will fail if +** that is attempted. +** +** The cost of an INSERT is roughly constant. (Sometimes new memory +** has to be allocated on an INSERT.) The cost of a TEST with a new +** batch number is O(NlogN) where N is the number of elements in the RowSet. +** The cost of a TEST using the same batch number is O(logN). The cost +** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST +** primitives are constant time. The cost of DESTROY is O(N). +** +** TEST and SMALLEST may not be used by the same RowSet. This used to +** be possible, but the feature was not used, so it was removed in order +** to simplify the code. +*/ +/* #include "sqliteInt.h" */ + + +/* +** Target size for allocation chunks. +*/ +#define ROWSET_ALLOCATION_SIZE 1024 + +/* +** The number of rowset entries per allocation chunk. +*/ +#define ROWSET_ENTRY_PER_CHUNK \ + ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry)) + +/* +** Each entry in a RowSet is an instance of the following object. +** +** This same object is reused to store a linked list of trees of RowSetEntry +** objects. In that alternative use, pRight points to the next entry +** in the list, pLeft points to the tree, and v is unused. The +** RowSet.pForest value points to the head of this forest list. +*/ +struct RowSetEntry { + i64 v; /* ROWID value for this entry */ + struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */ + struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */ +}; + +/* +** RowSetEntry objects are allocated in large chunks (instances of the +** following structure) to reduce memory allocation overhead. The +** chunks are kept on a linked list so that they can be deallocated +** when the RowSet is destroyed. +*/ +struct RowSetChunk { + struct RowSetChunk *pNextChunk; /* Next chunk on list of them all */ + struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */ +}; + +/* +** A RowSet in an instance of the following structure. +** +** A typedef of this structure if found in sqliteInt.h. +*/ +struct RowSet { + struct RowSetChunk *pChunk; /* List of all chunk allocations */ + sqlite3 *db; /* The database connection */ + struct RowSetEntry *pEntry; /* List of entries using pRight */ + struct RowSetEntry *pLast; /* Last entry on the pEntry list */ + struct RowSetEntry *pFresh; /* Source of new entry objects */ + struct RowSetEntry *pForest; /* List of binary trees of entries */ + u16 nFresh; /* Number of objects on pFresh */ + u16 rsFlags; /* Various flags */ + int iBatch; /* Current insert batch */ +}; + +/* +** Allowed values for RowSet.rsFlags +*/ +#define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */ +#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ + +/* +** Turn bulk memory into a RowSet object. N bytes of memory +** are available at pSpace. The db pointer is used as a memory context +** for any subsequent allocations that need to occur. +** Return a pointer to the new RowSet object. +** +** It must be the case that N is sufficient to make a Rowset. If not +** an assertion fault occurs. +** +** If N is larger than the minimum, use the surplus as an initial +** allocation of entries available to be filled. +*/ +SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){ + RowSet *p; + assert( N >= ROUND8(sizeof(*p)) ); + p = pSpace; + p->pChunk = 0; + p->db = db; + p->pEntry = 0; + p->pLast = 0; + p->pForest = 0; + p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); + p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); + p->rsFlags = ROWSET_SORTED; + p->iBatch = 0; + return p; +} + +/* +** Deallocate all chunks from a RowSet. This frees all memory that +** the RowSet has allocated over its lifetime. This routine is +** the destructor for the RowSet. +*/ +SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){ + struct RowSetChunk *pChunk, *pNextChunk; + for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ + pNextChunk = pChunk->pNextChunk; + sqlite3DbFree(p->db, pChunk); + } + p->pChunk = 0; + p->nFresh = 0; + p->pEntry = 0; + p->pLast = 0; + p->pForest = 0; + p->rsFlags = ROWSET_SORTED; +} + +/* +** Allocate a new RowSetEntry object that is associated with the +** given RowSet. Return a pointer to the new and completely uninitialized +** objected. +** +** In an OOM situation, the RowSet.db->mallocFailed flag is set and this +** routine returns NULL. +*/ +static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){ + assert( p!=0 ); + if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/ + /* We could allocate a fresh RowSetEntry each time one is needed, but it + ** is more efficient to pull a preallocated entry from the pool */ + struct RowSetChunk *pNew; + pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew)); + if( pNew==0 ){ + return 0; + } + pNew->pNextChunk = p->pChunk; + p->pChunk = pNew; + p->pFresh = pNew->aEntry; + p->nFresh = ROWSET_ENTRY_PER_CHUNK; + } + p->nFresh--; + return p->pFresh++; +} + +/* +** Insert a new value into a RowSet. +** +** The mallocFailed flag of the database connection is set if a +** memory allocation fails. +*/ +SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){ + struct RowSetEntry *pEntry; /* The new entry */ + struct RowSetEntry *pLast; /* The last prior entry */ + + /* This routine is never called after sqlite3RowSetNext() */ + assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 ); + + pEntry = rowSetEntryAlloc(p); + if( pEntry==0 ) return; + pEntry->v = rowid; + pEntry->pRight = 0; + pLast = p->pLast; + if( pLast ){ + if( rowid<=pLast->v ){ /*OPTIMIZATION-IF-FALSE*/ + /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags + ** where possible */ + p->rsFlags &= ~ROWSET_SORTED; + } + pLast->pRight = pEntry; + }else{ + p->pEntry = pEntry; + } + p->pLast = pEntry; +} + +/* +** Merge two lists of RowSetEntry objects. Remove duplicates. +** +** The input lists are connected via pRight pointers and are +** assumed to each already be in sorted order. +*/ +static struct RowSetEntry *rowSetEntryMerge( + struct RowSetEntry *pA, /* First sorted list to be merged */ + struct RowSetEntry *pB /* Second sorted list to be merged */ +){ + struct RowSetEntry head; + struct RowSetEntry *pTail; + + pTail = &head; + assert( pA!=0 && pB!=0 ); + for(;;){ + assert( pA->pRight==0 || pA->v<=pA->pRight->v ); + assert( pB->pRight==0 || pB->v<=pB->pRight->v ); + if( pA->v<=pB->v ){ + if( pA->vv ) pTail = pTail->pRight = pA; + pA = pA->pRight; + if( pA==0 ){ + pTail->pRight = pB; + break; + } + }else{ + pTail = pTail->pRight = pB; + pB = pB->pRight; + if( pB==0 ){ + pTail->pRight = pA; + break; + } + } + } + return head.pRight; +} + +/* +** Sort all elements on the list of RowSetEntry objects into order of +** increasing v. +*/ +static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){ + unsigned int i; + struct RowSetEntry *pNext, *aBucket[40]; + + memset(aBucket, 0, sizeof(aBucket)); + while( pIn ){ + pNext = pIn->pRight; + pIn->pRight = 0; + for(i=0; aBucket[i]; i++){ + pIn = rowSetEntryMerge(aBucket[i], pIn); + aBucket[i] = 0; + } + aBucket[i] = pIn; + pIn = pNext; + } + pIn = aBucket[0]; + for(i=1; ipLeft ){ + struct RowSetEntry *p; + rowSetTreeToList(pIn->pLeft, ppFirst, &p); + p->pRight = pIn; + }else{ + *ppFirst = pIn; + } + if( pIn->pRight ){ + rowSetTreeToList(pIn->pRight, &pIn->pRight, ppLast); + }else{ + *ppLast = pIn; + } + assert( (*ppLast)->pRight==0 ); +} + + +/* +** Convert a sorted list of elements (connected by pRight) into a binary +** tree with depth of iDepth. A depth of 1 means the tree contains a single +** node taken from the head of *ppList. A depth of 2 means a tree with +** three nodes. And so forth. +** +** Use as many entries from the input list as required and update the +** *ppList to point to the unused elements of the list. If the input +** list contains too few elements, then construct an incomplete tree +** and leave *ppList set to NULL. +** +** Return a pointer to the root of the constructed binary tree. +*/ +static struct RowSetEntry *rowSetNDeepTree( + struct RowSetEntry **ppList, + int iDepth +){ + struct RowSetEntry *p; /* Root of the new tree */ + struct RowSetEntry *pLeft; /* Left subtree */ + if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/ + /* Prevent unnecessary deep recursion when we run out of entries */ + return 0; + } + if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/ + /* This branch causes a *balanced* tree to be generated. A valid tree + ** is still generated without this branch, but the tree is wildly + ** unbalanced and inefficient. */ + pLeft = rowSetNDeepTree(ppList, iDepth-1); + p = *ppList; + if( p==0 ){ /*OPTIMIZATION-IF-FALSE*/ + /* It is safe to always return here, but the resulting tree + ** would be unbalanced */ + return pLeft; + } + p->pLeft = pLeft; + *ppList = p->pRight; + p->pRight = rowSetNDeepTree(ppList, iDepth-1); + }else{ + p = *ppList; + *ppList = p->pRight; + p->pLeft = p->pRight = 0; + } + return p; +} + +/* +** Convert a sorted list of elements into a binary tree. Make the tree +** as deep as it needs to be in order to contain the entire list. +*/ +static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){ + int iDepth; /* Depth of the tree so far */ + struct RowSetEntry *p; /* Current tree root */ + struct RowSetEntry *pLeft; /* Left subtree */ + + assert( pList!=0 ); + p = pList; + pList = p->pRight; + p->pLeft = p->pRight = 0; + for(iDepth=1; pList; iDepth++){ + pLeft = p; + p = pList; + pList = p->pRight; + p->pLeft = pLeft; + p->pRight = rowSetNDeepTree(&pList, iDepth); + } + return p; +} + +/* +** Extract the smallest element from the RowSet. +** Write the element into *pRowid. Return 1 on success. Return +** 0 if the RowSet is already empty. +** +** After this routine has been called, the sqlite3RowSetInsert() +** routine may not be called again. +** +** This routine may not be called after sqlite3RowSetTest() has +** been used. Older versions of RowSet allowed that, but as the +** capability was not used by the code generator, it was removed +** for code economy. +*/ +SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ + assert( p!=0 ); + assert( p->pForest==0 ); /* Cannot be used with sqlite3RowSetText() */ + + /* Merge the forest into a single sorted list on first call */ + if( (p->rsFlags & ROWSET_NEXT)==0 ){ /*OPTIMIZATION-IF-FALSE*/ + if( (p->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ + p->pEntry = rowSetEntrySort(p->pEntry); + } + p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT; + } + + /* Return the next entry on the list */ + if( p->pEntry ){ + *pRowid = p->pEntry->v; + p->pEntry = p->pEntry->pRight; + if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/ + /* Free memory immediately, rather than waiting on sqlite3_finalize() */ + sqlite3RowSetClear(p); + } + return 1; + }else{ + return 0; + } +} + +/* +** Check to see if element iRowid was inserted into the rowset as +** part of any insert batch prior to iBatch. Return 1 or 0. +** +** If this is the first test of a new batch and if there exist entries +** on pRowSet->pEntry, then sort those entries into the forest at +** pRowSet->pForest so that they can be tested. +*/ +SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ + struct RowSetEntry *p, *pTree; + + /* This routine is never called after sqlite3RowSetNext() */ + assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 ); + + /* Sort entries into the forest on the first test of a new batch. + ** To save unnecessary work, only do this when the batch number changes. + */ + if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/ + p = pRowSet->pEntry; + if( p ){ + struct RowSetEntry **ppPrevTree = &pRowSet->pForest; + if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ + /* Only sort the current set of entiries if they need it */ + p = rowSetEntrySort(p); + } + for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ + ppPrevTree = &pTree->pRight; + if( pTree->pLeft==0 ){ + pTree->pLeft = rowSetListToTree(p); + break; + }else{ + struct RowSetEntry *pAux, *pTail; + rowSetTreeToList(pTree->pLeft, &pAux, &pTail); + pTree->pLeft = 0; + p = rowSetEntryMerge(pAux, p); + } + } + if( pTree==0 ){ + *ppPrevTree = pTree = rowSetEntryAlloc(pRowSet); + if( pTree ){ + pTree->v = 0; + pTree->pRight = 0; + pTree->pLeft = rowSetListToTree(p); + } + } + pRowSet->pEntry = 0; + pRowSet->pLast = 0; + pRowSet->rsFlags |= ROWSET_SORTED; + } + pRowSet->iBatch = iBatch; + } + + /* Test to see if the iRowid value appears anywhere in the forest. + ** Return 1 if it does and 0 if not. + */ + for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ + p = pTree->pLeft; + while( p ){ + if( p->vpRight; + }else if( p->v>iRowid ){ + p = p->pLeft; + }else{ + return 1; + } + } + } + return 0; +} + +/************** End of rowset.c **********************************************/ +/************** Begin file pager.c *******************************************/ +/* +** 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 is the implementation of the page cache subsystem or "pager". +** +** The pager is used to access a database disk file. It implements +** atomic commit and rollback through the use of a journal file that +** is separate from the database file. The pager also implements file +** locking to prevent two processes from writing the same database +** file simultaneously, or one process from reading the database while +** another is writing. +*/ +#ifndef SQLITE_OMIT_DISKIO +/* #include "sqliteInt.h" */ +/************** Include wal.h in the middle of pager.c ***********************/ +/************** Begin file wal.h *********************************************/ +/* +** 2010 February 1 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface to the write-ahead logging +** system. Refer to the comments below and the header comment attached to +** the implementation of each function in log.c for further details. +*/ + +#ifndef SQLITE_WAL_H +#define SQLITE_WAL_H + +/* #include "sqliteInt.h" */ + +/* Additional values that can be added to the sync_flags argument of +** sqlite3WalFrames(): +*/ +#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */ +#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */ + +#ifdef SQLITE_OMIT_WAL +# define sqlite3WalOpen(x,y,z) 0 +# define sqlite3WalLimit(x,y) +# define sqlite3WalClose(v,w,x,y,z) 0 +# define sqlite3WalBeginReadTransaction(y,z) 0 +# define sqlite3WalEndReadTransaction(z) +# define sqlite3WalDbsize(y) 0 +# define sqlite3WalBeginWriteTransaction(y) 0 +# define sqlite3WalEndWriteTransaction(x) 0 +# define sqlite3WalUndo(x,y,z) 0 +# define sqlite3WalSavepoint(y,z) +# define sqlite3WalSavepointUndo(y,z) 0 +# define sqlite3WalFrames(u,v,w,x,y,z) 0 +# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0 +# define sqlite3WalCallback(z) 0 +# define sqlite3WalExclusiveMode(y,z) 0 +# define sqlite3WalHeapMemory(z) 0 +# define sqlite3WalFramesize(z) 0 +# define sqlite3WalFindFrame(x,y,z) 0 +# define sqlite3WalFile(x) 0 +#else + +#define WAL_SAVEPOINT_NDATA 4 + +/* Connection to a write-ahead log (WAL) file. +** There is one object of this type for each pager. +*/ +typedef struct Wal Wal; + +/* Open and close a connection to a write-ahead log. */ +SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**); +SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *); + +/* Set the limiting size of a WAL file. */ +SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64); + +/* Used by readers to open (lock) and close (unlock) a snapshot. A +** snapshot is like a read-transaction. It is the state of the database +** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and +** preserves the current state even if the other threads or processes +** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the +** transaction and releases the lock. +*/ +SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *); +SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal); + +/* Read a page from the write-ahead log, if it is present. */ +SQLITE_PRIVATE int sqlite3WalFindFrame(Wal *, Pgno, u32 *); +SQLITE_PRIVATE int sqlite3WalReadFrame(Wal *, u32, int, u8 *); + +/* If the WAL is not empty, return the size of the database. */ +SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal); + +/* Obtain or release the WRITER lock. */ +SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal); +SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal); + +/* Undo any frames written (but not committed) to the log */ +SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx); + +/* Return an integer that records the current (uncommitted) write +** position in the WAL */ +SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData); + +/* Move the write position of the WAL back to iFrame. Called in +** response to a ROLLBACK TO command. */ +SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData); + +/* Write a frame or frames to the log. */ +SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int); + +/* Copy pages from the log to the database file */ +SQLITE_PRIVATE int sqlite3WalCheckpoint( + Wal *pWal, /* Write-ahead log connection */ + sqlite3 *db, /* Check this handle's interrupt flag */ + int eMode, /* One of PASSIVE, FULL and RESTART */ + int (*xBusy)(void*), /* Function to call when busy */ + void *pBusyArg, /* Context argument for xBusyHandler */ + int sync_flags, /* Flags to sync db file with (or 0) */ + int nBuf, /* Size of buffer nBuf */ + u8 *zBuf, /* Temporary buffer to use */ + int *pnLog, /* OUT: Number of frames in WAL */ + int *pnCkpt /* OUT: Number of backfilled frames in WAL */ +); + +/* Return the value to pass to a sqlite3_wal_hook callback, the +** number of frames in the WAL at the point of the last commit since +** sqlite3WalCallback() was called. If no commits have occurred since +** the last call, then return 0. +*/ +SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal); + +/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released) +** by the pager layer on the database file. +*/ +SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op); + +/* Return true if the argument is non-NULL and the WAL module is using +** heap-memory for the wal-index. Otherwise, if the argument is NULL or the +** WAL module is using shared-memory, return false. +*/ +SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); + +#ifdef SQLITE_ENABLE_SNAPSHOT +SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); +SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal); +#endif + +#ifdef SQLITE_ENABLE_ZIPVFS +/* If the WAL file is not empty, return the number of bytes of content +** stored in each frame (i.e. the db page-size when the WAL was created). +*/ +SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal); +#endif + +/* Return the sqlite3_file object for the WAL file */ +SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal); + +#endif /* ifndef SQLITE_OMIT_WAL */ +#endif /* SQLITE_WAL_H */ + +/************** End of wal.h *************************************************/ +/************** Continuing where we left off in pager.c **********************/ + + +/******************* NOTES ON THE DESIGN OF THE PAGER ************************ +** +** This comment block describes invariants that hold when using a rollback +** journal. These invariants do not apply for journal_mode=WAL, +** journal_mode=MEMORY, or journal_mode=OFF. +** +** Within this comment block, a page is deemed to have been synced +** automatically as soon as it is written when PRAGMA synchronous=OFF. +** Otherwise, the page is not synced until the xSync method of the VFS +** is called successfully on the file containing the page. +** +** Definition: A page of the database file is said to be "overwriteable" if +** one or more of the following are true about the page: +** +** (a) The original content of the page as it was at the beginning of +** the transaction has been written into the rollback journal and +** synced. +** +** (b) The page was a freelist leaf page at the start of the transaction. +** +** (c) The page number is greater than the largest page that existed in +** the database file at the start of the transaction. +** +** (1) A page of the database file is never overwritten unless one of the +** following are true: +** +** (a) The page and all other pages on the same sector are overwriteable. +** +** (b) The atomic page write optimization is enabled, and the entire +** transaction other than the update of the transaction sequence +** number consists of a single page change. +** +** (2) The content of a page written into the rollback journal exactly matches +** both the content in the database when the rollback journal was written +** and the content in the database at the beginning of the current +** transaction. +** +** (3) Writes to the database file are an integer multiple of the page size +** in length and are aligned on a page boundary. +** +** (4) Reads from the database file are either aligned on a page boundary and +** an integer multiple of the page size in length or are taken from the +** first 100 bytes of the database file. +** +** (5) All writes to the database file are synced prior to the rollback journal +** being deleted, truncated, or zeroed. +** +** (6) If a master journal file is used, then all writes to the database file +** are synced prior to the master journal being deleted. +** +** Definition: Two databases (or the same database at two points it time) +** are said to be "logically equivalent" if they give the same answer to +** all queries. Note in particular the content of freelist leaf +** pages can be changed arbitrarily without affecting the logical equivalence +** of the database. +** +** (7) At any time, if any subset, including the empty set and the total set, +** of the unsynced changes to a rollback journal are removed and the +** journal is rolled back, the resulting database file will be logically +** equivalent to the database file at the beginning of the transaction. +** +** (8) When a transaction is rolled back, the xTruncate method of the VFS +** is called to restore the database file to the same size it was at +** the beginning of the transaction. (In some VFSes, the xTruncate +** method is a no-op, but that does not change the fact the SQLite will +** invoke it.) +** +** (9) Whenever the database file is modified, at least one bit in the range +** of bytes from 24 through 39 inclusive will be changed prior to releasing +** the EXCLUSIVE lock, thus signaling other connections on the same +** database to flush their caches. +** +** (10) The pattern of bits in bytes 24 through 39 shall not repeat in less +** than one billion transactions. +** +** (11) A database file is well-formed at the beginning and at the conclusion +** of every transaction. +** +** (12) An EXCLUSIVE lock is held on the database file when writing to +** the database file. +** +** (13) A SHARED lock is held on the database file while reading any +** content out of the database file. +** +******************************************************************************/ + +/* +** Macros for troubleshooting. Normally turned off +*/ +#if 0 +int sqlite3PagerTrace=1; /* True to enable tracing */ +#define sqlite3DebugPrintf printf +#define PAGERTRACE(X) if( sqlite3PagerTrace ){ sqlite3DebugPrintf X; } +#else +#define PAGERTRACE(X) +#endif + +/* +** The following two macros are used within the PAGERTRACE() macros above +** to print out file-descriptors. +** +** PAGERID() takes a pointer to a Pager struct as its argument. The +** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file +** struct as its argument. +*/ +#define PAGERID(p) ((int)(p->fd)) +#define FILEHANDLEID(fd) ((int)fd) + +/* +** The Pager.eState variable stores the current 'state' of a pager. A +** pager may be in any one of the seven states shown in the following +** state diagram. +** +** OPEN <------+------+ +** | | | +** V | | +** +---------> READER-------+ | +** | | | +** | V | +** |<-------WRITER_LOCKED------> ERROR +** | | ^ +** | V | +** |<------WRITER_CACHEMOD-------->| +** | | | +** | V | +** |<-------WRITER_DBMOD---------->| +** | | | +** | V | +** +<------WRITER_FINISHED-------->+ +** +** +** List of state transitions and the C [function] that performs each: +** +** OPEN -> READER [sqlite3PagerSharedLock] +** READER -> OPEN [pager_unlock] +** +** READER -> WRITER_LOCKED [sqlite3PagerBegin] +** WRITER_LOCKED -> WRITER_CACHEMOD [pager_open_journal] +** WRITER_CACHEMOD -> WRITER_DBMOD [syncJournal] +** WRITER_DBMOD -> WRITER_FINISHED [sqlite3PagerCommitPhaseOne] +** WRITER_*** -> READER [pager_end_transaction] +** +** WRITER_*** -> ERROR [pager_error] +** ERROR -> OPEN [pager_unlock] +** +** +** OPEN: +** +** The pager starts up in this state. Nothing is guaranteed in this +** state - the file may or may not be locked and the database size is +** unknown. The database may not be read or written. +** +** * No read or write transaction is active. +** * Any lock, or no lock at all, may be held on the database file. +** * The dbSize, dbOrigSize and dbFileSize variables may not be trusted. +** +** READER: +** +** In this state all the requirements for reading the database in +** rollback (non-WAL) mode are met. Unless the pager is (or recently +** was) in exclusive-locking mode, a user-level read transaction is +** open. The database size is known in this state. +** +** A connection running with locking_mode=normal enters this state when +** it opens a read-transaction on the database and returns to state +** OPEN after the read-transaction is completed. However a connection +** running in locking_mode=exclusive (including temp databases) remains in +** this state even after the read-transaction is closed. The only way +** a locking_mode=exclusive connection can transition from READER to OPEN +** is via the ERROR state (see below). +** +** * A read transaction may be active (but a write-transaction cannot). +** * A SHARED or greater lock is held on the database file. +** * The dbSize variable may be trusted (even if a user-level read +** transaction is not active). The dbOrigSize and dbFileSize variables +** may not be trusted at this point. +** * If the database is a WAL database, then the WAL connection is open. +** * Even if a read-transaction is not open, it is guaranteed that +** there is no hot-journal in the file-system. +** +** WRITER_LOCKED: +** +** The pager moves to this state from READER when a write-transaction +** is first opened on the database. In WRITER_LOCKED state, all locks +** required to start a write-transaction are held, but no actual +** modifications to the cache or database have taken place. +** +** In rollback mode, a RESERVED or (if the transaction was opened with +** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when +** moving to this state, but the journal file is not written to or opened +** to in this state. If the transaction is committed or rolled back while +** in WRITER_LOCKED state, all that is required is to unlock the database +** file. +** +** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file. +** If the connection is running with locking_mode=exclusive, an attempt +** is made to obtain an EXCLUSIVE lock on the database file. +** +** * A write transaction is active. +** * If the connection is open in rollback-mode, a RESERVED or greater +** lock is held on the database file. +** * If the connection is open in WAL-mode, a WAL write transaction +** is open (i.e. sqlite3WalBeginWriteTransaction() has been successfully +** called). +** * The dbSize, dbOrigSize and dbFileSize variables are all valid. +** * The contents of the pager cache have not been modified. +** * The journal file may or may not be open. +** * Nothing (not even the first header) has been written to the journal. +** +** WRITER_CACHEMOD: +** +** A pager moves from WRITER_LOCKED state to this state when a page is +** first modified by the upper layer. In rollback mode the journal file +** is opened (if it is not already open) and a header written to the +** start of it. The database file on disk has not been modified. +** +** * A write transaction is active. +** * A RESERVED or greater lock is held on the database file. +** * The journal file is open and the first header has been written +** to it, but the header has not been synced to disk. +** * The contents of the page cache have been modified. +** +** WRITER_DBMOD: +** +** The pager transitions from WRITER_CACHEMOD into WRITER_DBMOD state +** when it modifies the contents of the database file. WAL connections +** never enter this state (since they do not modify the database file, +** just the log file). +** +** * A write transaction is active. +** * An EXCLUSIVE or greater lock is held on the database file. +** * The journal file is open and the first header has been written +** and synced to disk. +** * The contents of the page cache have been modified (and possibly +** written to disk). +** +** WRITER_FINISHED: +** +** It is not possible for a WAL connection to enter this state. +** +** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD +** state after the entire transaction has been successfully written into the +** database file. In this state the transaction may be committed simply +** by finalizing the journal file. Once in WRITER_FINISHED state, it is +** not possible to modify the database further. At this point, the upper +** layer must either commit or rollback the transaction. +** +** * A write transaction is active. +** * An EXCLUSIVE or greater lock is held on the database file. +** * All writing and syncing of journal and database data has finished. +** If no error occurred, all that remains is to finalize the journal to +** commit the transaction. If an error did occur, the caller will need +** to rollback the transaction. +** +** ERROR: +** +** The ERROR state is entered when an IO or disk-full error (including +** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it +** difficult to be sure that the in-memory pager state (cache contents, +** db size etc.) are consistent with the contents of the file-system. +** +** Temporary pager files may enter the ERROR state, but in-memory pagers +** cannot. +** +** For example, if an IO error occurs while performing a rollback, +** the contents of the page-cache may be left in an inconsistent state. +** At this point it would be dangerous to change back to READER state +** (as usually happens after a rollback). Any subsequent readers might +** report database corruption (due to the inconsistent cache), and if +** they upgrade to writers, they may inadvertently corrupt the database +** file. To avoid this hazard, the pager switches into the ERROR state +** instead of READER following such an error. +** +** Once it has entered the ERROR state, any attempt to use the pager +** to read or write data returns an error. Eventually, once all +** outstanding transactions have been abandoned, the pager is able to +** transition back to OPEN state, discarding the contents of the +** page-cache and any other in-memory state at the same time. Everything +** is reloaded from disk (and, if necessary, hot-journal rollback peformed) +** when a read-transaction is next opened on the pager (transitioning +** the pager into READER state). At that point the system has recovered +** from the error. +** +** Specifically, the pager jumps into the ERROR state if: +** +** 1. An error occurs while attempting a rollback. This happens in +** function sqlite3PagerRollback(). +** +** 2. An error occurs while attempting to finalize a journal file +** following a commit in function sqlite3PagerCommitPhaseTwo(). +** +** 3. An error occurs while attempting to write to the journal or +** database file in function pagerStress() in order to free up +** memory. +** +** In other cases, the error is returned to the b-tree layer. The b-tree +** layer then attempts a rollback operation. If the error condition +** persists, the pager enters the ERROR state via condition (1) above. +** +** Condition (3) is necessary because it can be triggered by a read-only +** statement executed within a transaction. In this case, if the error +** code were simply returned to the user, the b-tree layer would not +** automatically attempt a rollback, as it assumes that an error in a +** read-only statement cannot leave the pager in an internally inconsistent +** state. +** +** * The Pager.errCode variable is set to something other than SQLITE_OK. +** * There are one or more outstanding references to pages (after the +** last reference is dropped the pager should move back to OPEN state). +** * The pager is not an in-memory pager. +** +** +** Notes: +** +** * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the +** connection is open in WAL mode. A WAL connection is always in one +** of the first four states. +** +** * Normally, a connection open in exclusive mode is never in PAGER_OPEN +** state. There are two exceptions: immediately after exclusive-mode has +** been turned on (and before any read or write transactions are +** executed), and when the pager is leaving the "error state". +** +** * See also: assert_pager_state(). +*/ +#define PAGER_OPEN 0 +#define PAGER_READER 1 +#define PAGER_WRITER_LOCKED 2 +#define PAGER_WRITER_CACHEMOD 3 +#define PAGER_WRITER_DBMOD 4 +#define PAGER_WRITER_FINISHED 5 +#define PAGER_ERROR 6 + +/* +** The Pager.eLock variable is almost always set to one of the +** following locking-states, according to the lock currently held on +** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK. +** This variable is kept up to date as locks are taken and released by +** the pagerLockDb() and pagerUnlockDb() wrappers. +** +** If the VFS xLock() or xUnlock() returns an error other than SQLITE_BUSY +** (i.e. one of the SQLITE_IOERR subtypes), it is not clear whether or not +** the operation was successful. In these circumstances pagerLockDb() and +** pagerUnlockDb() take a conservative approach - eLock is always updated +** when unlocking the file, and only updated when locking the file if the +** VFS call is successful. This way, the Pager.eLock variable may be set +** to a less exclusive (lower) value than the lock that is actually held +** at the system level, but it is never set to a more exclusive value. +** +** This is usually safe. If an xUnlock fails or appears to fail, there may +** be a few redundant xLock() calls or a lock may be held for longer than +** required, but nothing really goes wrong. +** +** The exception is when the database file is unlocked as the pager moves +** from ERROR to OPEN state. At this point there may be a hot-journal file +** in the file-system that needs to be rolled back (as part of an OPEN->SHARED +** transition, by the same pager or any other). If the call to xUnlock() +** fails at this point and the pager is left holding an EXCLUSIVE lock, this +** can confuse the call to xCheckReservedLock() call made later as part +** of hot-journal detection. +** +** xCheckReservedLock() is defined as returning true "if there is a RESERVED +** lock held by this process or any others". So xCheckReservedLock may +** return true because the caller itself is holding an EXCLUSIVE lock (but +** doesn't know it because of a previous error in xUnlock). If this happens +** a hot-journal may be mistaken for a journal being created by an active +** transaction in another process, causing SQLite to read from the database +** without rolling it back. +** +** To work around this, if a call to xUnlock() fails when unlocking the +** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It +** is only changed back to a real locking state after a successful call +** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition +** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK +** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE +** lock on the database file before attempting to roll it back. See function +** PagerSharedLock() for more detail. +** +** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in +** PAGER_OPEN state. +*/ +#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) + +/* +** A macro used for invoking the codec if there is one +*/ +#ifdef SQLITE_HAS_CODEC +# define CODEC1(P,D,N,X,E) \ + if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; } +# define CODEC2(P,D,N,X,E,O) \ + if( P->xCodec==0 ){ O=(char*)D; }else \ + if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; } +#else +# define CODEC1(P,D,N,X,E) /* NO-OP */ +# define CODEC2(P,D,N,X,E,O) O=(char*)D +#endif + +/* +** The maximum allowed sector size. 64KiB. If the xSectorsize() method +** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. +** This could conceivably cause corruption following a power failure on +** such a system. This is currently an undocumented limit. +*/ +#define MAX_SECTOR_SIZE 0x10000 + + +/* +** An instance of the following structure is allocated for each active +** savepoint and statement transaction in the system. All such structures +** are stored in the Pager.aSavepoint[] array, which is allocated and +** resized using sqlite3Realloc(). +** +** When a savepoint is created, the PagerSavepoint.iHdrOffset field is +** set to 0. If a journal-header is written into the main journal while +** the savepoint is active, then iHdrOffset is set to the byte offset +** immediately following the last journal record written into the main +** journal before the journal-header. This is required during savepoint +** rollback (see pagerPlaybackSavepoint()). +*/ +typedef struct PagerSavepoint PagerSavepoint; +struct PagerSavepoint { + i64 iOffset; /* Starting offset in main journal */ + i64 iHdrOffset; /* See above */ + Bitvec *pInSavepoint; /* Set of pages in this savepoint */ + Pgno nOrig; /* Original number of pages in file */ + Pgno iSubRec; /* Index of first record in sub-journal */ +#ifndef SQLITE_OMIT_WAL + u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */ +#endif +}; + +/* +** Bits of the Pager.doNotSpill flag. See further description below. +*/ +#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */ +#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */ +#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */ + +/* +** An open page cache is an instance of struct Pager. A description of +** some of the more important member variables follows: +** +** eState +** +** The current 'state' of the pager object. See the comment and state +** diagram above for a description of the pager state. +** +** eLock +** +** For a real on-disk database, the current lock held on the database file - +** NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK. +** +** For a temporary or in-memory database (neither of which require any +** locks), this variable is always set to EXCLUSIVE_LOCK. Since such +** databases always have Pager.exclusiveMode==1, this tricks the pager +** logic into thinking that it already has all the locks it will ever +** need (and no reason to release them). +** +** In some (obscure) circumstances, this variable may also be set to +** UNKNOWN_LOCK. See the comment above the #define of UNKNOWN_LOCK for +** details. +** +** changeCountDone +** +** This boolean variable is used to make sure that the change-counter +** (the 4-byte header field at byte offset 24 of the database file) is +** not updated more often than necessary. +** +** It is set to true when the change-counter field is updated, which +** can only happen if an exclusive lock is held on the database file. +** It is cleared (set to false) whenever an exclusive lock is +** relinquished on the database file. Each time a transaction is committed, +** The changeCountDone flag is inspected. If it is true, the work of +** updating the change-counter is omitted for the current transaction. +** +** This mechanism means that when running in exclusive mode, a connection +** need only update the change-counter once, for the first transaction +** committed. +** +** setMaster +** +** When PagerCommitPhaseOne() is called to commit a transaction, it may +** (or may not) specify a master-journal name to be written into the +** journal file before it is synced to disk. +** +** Whether or not a journal file contains a master-journal pointer affects +** the way in which the journal file is finalized after the transaction is +** committed or rolled back when running in "journal_mode=PERSIST" mode. +** If a journal file does not contain a master-journal pointer, it is +** finalized by overwriting the first journal header with zeroes. If +** it does contain a master-journal pointer the journal file is finalized +** by truncating it to zero bytes, just as if the connection were +** running in "journal_mode=truncate" mode. +** +** Journal files that contain master journal pointers cannot be finalized +** simply by overwriting the first journal-header with zeroes, as the +** master journal pointer could interfere with hot-journal rollback of any +** subsequently interrupted transaction that reuses the journal file. +** +** The flag is cleared as soon as the journal file is finalized (either +** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the +** journal file from being successfully finalized, the setMaster flag +** is cleared anyway (and the pager will move to ERROR state). +** +** doNotSpill +** +** This variables control the behavior of cache-spills (calls made by +** the pcache module to the pagerStress() routine to write cached data +** to the file-system in order to free up memory). +** +** When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set, +** writing to the database from pagerStress() is disabled altogether. +** The SPILLFLAG_ROLLBACK case is done in a very obscure case that +** comes up during savepoint rollback that requires the pcache module +** to allocate a new page to prevent the journal file from being written +** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF +** case is a user preference. +** +** If the SPILLFLAG_NOSYNC bit is set, writing to the database from +** pagerStress() is permitted, but syncing the journal file is not. +** This flag is set by sqlite3PagerWrite() when the file-system sector-size +** is larger than the database page-size in order to prevent a journal sync +** from happening in between the journalling of two pages on the same sector. +** +** subjInMemory +** +** This is a boolean variable. If true, then any required sub-journal +** is opened as an in-memory journal file. If false, then in-memory +** sub-journals are only used for in-memory pager files. +** +** This variable is updated by the upper layer each time a new +** write-transaction is opened. +** +** dbSize, dbOrigSize, dbFileSize +** +** Variable dbSize is set to the number of pages in the database file. +** It is valid in PAGER_READER and higher states (all states except for +** OPEN and ERROR). +** +** dbSize is set based on the size of the database file, which may be +** larger than the size of the database (the value stored at offset +** 28 of the database header by the btree). If the size of the file +** is not an integer multiple of the page-size, the value stored in +** dbSize is rounded down (i.e. a 5KB file with 2K page-size has dbSize==2). +** Except, any file that is greater than 0 bytes in size is considered +** to have at least one page. (i.e. a 1KB file with 2K page-size leads +** to dbSize==1). +** +** During a write-transaction, if pages with page-numbers greater than +** dbSize are modified in the cache, dbSize is updated accordingly. +** Similarly, if the database is truncated using PagerTruncateImage(), +** dbSize is updated. +** +** Variables dbOrigSize and dbFileSize are valid in states +** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize +** variable at the start of the transaction. It is used during rollback, +** and to determine whether or not pages need to be journalled before +** being modified. +** +** Throughout a write-transaction, dbFileSize contains the size of +** the file on disk in pages. It is set to a copy of dbSize when the +** write-transaction is first opened, and updated when VFS calls are made +** to write or truncate the database file on disk. +** +** The only reason the dbFileSize variable is required is to suppress +** unnecessary calls to xTruncate() after committing a transaction. If, +** when a transaction is committed, the dbFileSize variable indicates +** that the database file is larger than the database image (Pager.dbSize), +** pager_truncate() is called. The pager_truncate() call uses xFilesize() +** to measure the database file on disk, and then truncates it if required. +** dbFileSize is not used when rolling back a transaction. In this case +** pager_truncate() is called unconditionally (which means there may be +** a call to xFilesize() that is not strictly required). In either case, +** pager_truncate() may cause the file to become smaller or larger. +** +** dbHintSize +** +** The dbHintSize variable is used to limit the number of calls made to +** the VFS xFileControl(FCNTL_SIZE_HINT) method. +** +** dbHintSize is set to a copy of the dbSize variable when a +** write-transaction is opened (at the same time as dbFileSize and +** dbOrigSize). If the xFileControl(FCNTL_SIZE_HINT) method is called, +** dbHintSize is increased to the number of pages that correspond to the +** size-hint passed to the method call. See pager_write_pagelist() for +** details. +** +** errCode +** +** The Pager.errCode variable is only ever used in PAGER_ERROR state. It +** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode +** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX +** sub-codes. +*/ +struct Pager { + sqlite3_vfs *pVfs; /* OS functions to use for IO */ + u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */ + u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */ + u8 useJournal; /* Use a rollback journal on this file */ + 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 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 */ + u8 memDb; /* True to inhibit all file I/O */ + + /************************************************************************** + ** The following block contains those class members that change during + ** routine operation. Class members not in this block are either fixed + ** when the pager is first created or else only change when there is a + ** significant mode change (such as changing the page_size, locking_mode, + ** or the journal_mode). From another view, these class members describe + ** the "state" of the pager, while other class members describe the + ** "configuration" of the pager. + */ + u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */ + u8 eLock; /* Current lock held on database file */ + u8 changeCountDone; /* Set after incrementing the change-counter */ + u8 setMaster; /* True if a m-j name has been written to jrnl */ + u8 doNotSpill; /* Do not spill the cache when non-zero */ + u8 subjInMemory; /* True to use in-memory sub-journals */ + u8 bUseFetch; /* True to use xFetch() */ + u8 hasHeldSharedLock; /* True if a shared lock has ever been held */ + Pgno dbSize; /* Number of pages in the database */ + Pgno dbOrigSize; /* dbSize before the current transaction */ + Pgno dbFileSize; /* Number of pages in the database file */ + Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */ + int errCode; /* One of several kinds of errors */ + int nRec; /* Pages journalled since last j-header written */ + u32 cksumInit; /* Quasi-random value added to every checksum */ + u32 nSubRec; /* Number of records written to sub-journal */ + Bitvec *pInJournal; /* One bit for each page in the database file */ + sqlite3_file *fd; /* File descriptor for database */ + sqlite3_file *jfd; /* File descriptor for main journal */ + sqlite3_file *sjfd; /* File descriptor for sub-journal */ + i64 journalOff; /* Current write offset in the journal file */ + i64 journalHdr; /* Byte offset to previous journal header */ + sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ + PagerSavepoint *aSavepoint; /* Array of active savepoints */ + int nSavepoint; /* Number of elements in aSavepoint[] */ + u32 iDataVersion; /* Changes whenever database content changes */ + char dbFileVers[16]; /* Changes whenever database file changes */ + + int nMmapOut; /* Number of mmap pages currently outstanding */ + sqlite3_int64 szMmap; /* Desired maximum mmap size */ + PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */ + /* + ** End of the routinely-changing class members + ***************************************************************************/ + + u16 nExtra; /* Add this many bytes to each in-memory page */ + i16 nReserve; /* Number of unused bytes at end of each page */ + u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ + u32 sectorSize; /* Assumed sector size during rollback */ + int pageSize; /* Number of bytes in a page */ + Pgno mxPgno; /* Maximum allowed size of the database */ + i64 journalSizeLimit; /* Size limit for persistent journal files */ + char *zFilename; /* Name of the database file */ + char *zJournal; /* Name of the journal file */ + int (*xBusyHandler)(void*); /* Function to call when busy */ + void *pBusyHandlerArg; /* Context argument for xBusyHandler */ + int aStat[3]; /* Total cache hits, misses and writes */ +#ifdef SQLITE_TEST + int nRead; /* Database pages read */ +#endif + void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ + int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ +#ifdef SQLITE_HAS_CODEC + void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ + void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ + void (*xCodecFree)(void*); /* Destructor for the codec */ + void *pCodec; /* First argument to xCodec... methods */ +#endif + char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ + PCache *pPCache; /* Pointer to page cache object */ +#ifndef SQLITE_OMIT_WAL + Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ + char *zWal; /* File name for write-ahead log */ +#endif +}; + +/* +** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains +** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS +** or CACHE_WRITE to sqlite3_db_status(). +*/ +#define PAGER_STAT_HIT 0 +#define PAGER_STAT_MISS 1 +#define PAGER_STAT_WRITE 2 + +/* +** The following global variables hold counters used for +** testing purposes only. These variables do not exist in +** a non-testing build. These variables are not thread-safe. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */ +SQLITE_API int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */ +SQLITE_API int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */ +# define PAGER_INCR(v) v++ +#else +# define PAGER_INCR(v) +#endif + + + +/* +** Journal files begin with the following magic string. The data +** was obtained from /dev/random. It is used only as a sanity check. +** +** Since version 2.8.0, the journal format contains additional sanity +** checking information. If the power fails while the journal is being +** written, semi-random garbage data might appear in the journal +** file after power is restored. If an attempt is then made +** to roll the journal back, the database could be corrupted. The additional +** sanity checking data is an attempt to discover the garbage in the +** journal and ignore it. +** +** The sanity checking information for the new journal format consists +** of a 32-bit checksum on each page of data. The checksum covers both +** the page number and the pPager->pageSize bytes of data for the page. +** This cksum is initialized to a 32-bit random value that appears in the +** journal file right after the header. The random initializer is important, +** because garbage data that appears at the end of a journal is likely +** data that was once in other files that have now been deleted. If the +** garbage data came from an obsolete journal file, the checksums might +** be correct. But by initializing the checksum to random value which +** is different for every journal, we minimize that risk. +*/ +static const unsigned char aJournalMagic[] = { + 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7, +}; + +/* +** The size of the of each page record in the journal is given by +** the following macro. +*/ +#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8) + +/* +** The journal header size for this pager. This is usually the same +** size as a single disk sector. See also setSectorSize(). +*/ +#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize) + +/* +** The macro MEMDB is true if we are dealing with an in-memory database. +** We do this as a macro so that if the SQLITE_OMIT_MEMORYDB macro is set, +** the value of MEMDB will be a constant and the compiler will optimize +** out code that would never execute. +*/ +#ifdef SQLITE_OMIT_MEMORYDB +# define MEMDB 0 +#else +# define MEMDB pPager->memDb +#endif + +/* +** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch +** interfaces to access the database using memory-mapped I/O. +*/ +#if SQLITE_MAX_MMAP_SIZE>0 +# define USEFETCH(x) ((x)->bUseFetch) +#else +# define USEFETCH(x) 0 +#endif + +/* +** The maximum legal page number is (2^31 - 1). +*/ +#define PAGER_MAX_PGNO 2147483647 + +/* +** The argument to this macro is a file descriptor (type sqlite3_file*). +** Return 0 if it is not open, or non-zero (but not 1) if it is. +** +** This is so that expressions can be written as: +** +** if( isOpen(pPager->jfd) ){ ... +** +** instead of +** +** if( pPager->jfd->pMethods ){ ... +*/ +#define isOpen(pFd) ((pFd)->pMethods!=0) + +/* +** Return true if this pager uses a write-ahead log to read page pgno. +** Return false if the pager reads pgno directly from the database. +*/ +#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_DIRECT_OVERFLOW_READ) +SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){ + u32 iRead = 0; + int rc; + if( pPager->pWal==0 ) return 0; + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); + return rc || iRead; +} +#endif +#ifndef SQLITE_OMIT_WAL +# define pagerUseWal(x) ((x)->pWal!=0) +#else +# define pagerUseWal(x) 0 +# define pagerRollbackWal(x) 0 +# define pagerWalFrames(v,w,x,y) 0 +# define pagerOpenWalIfPresent(z) SQLITE_OK +# define pagerBeginReadTransaction(z) SQLITE_OK +#endif + +#ifndef NDEBUG +/* +** Usage: +** +** assert( assert_pager_state(pPager) ); +** +** This function runs many asserts to try to find inconsistencies in +** the internal state of the Pager object. +*/ +static int assert_pager_state(Pager *p){ + Pager *pPager = p; + + /* State must be valid. */ + assert( p->eState==PAGER_OPEN + || p->eState==PAGER_READER + || p->eState==PAGER_WRITER_LOCKED + || p->eState==PAGER_WRITER_CACHEMOD + || p->eState==PAGER_WRITER_DBMOD + || p->eState==PAGER_WRITER_FINISHED + || p->eState==PAGER_ERROR + ); + + /* Regardless of the current state, a temp-file connection always behaves + ** as if it has an exclusive lock on the database file. It never updates + ** the change-counter field, so the changeCountDone flag is always set. + */ + assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK ); + assert( p->tempFile==0 || pPager->changeCountDone ); + + /* If the useJournal flag is clear, the journal-mode must be "OFF". + ** And if the journal-mode is "OFF", the journal file must not be open. + */ + assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal ); + assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) ); + + /* Check that MEMDB implies noSync. And an in-memory journal. Since + ** this means an in-memory pager performs no IO at all, it cannot encounter + ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing + ** a journal file. (although the in-memory journal implementation may + ** return SQLITE_IOERR_NOMEM while the journal file is being written). It + ** is therefore not possible for an in-memory pager to enter the ERROR + ** state. + */ + if( MEMDB ){ + assert( !isOpen(p->fd) ); + assert( p->noSync ); + assert( p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_MEMORY + ); + assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN ); + assert( pagerUseWal(p)==0 ); + } + + /* If changeCountDone is set, a RESERVED lock or greater must be held + ** on the file. + */ + assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK ); + assert( p->eLock!=PENDING_LOCK ); + + switch( p->eState ){ + case PAGER_OPEN: + assert( !MEMDB ); + assert( pPager->errCode==SQLITE_OK ); + assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile ); + break; + + case PAGER_READER: + assert( pPager->errCode==SQLITE_OK ); + assert( p->eLock!=UNKNOWN_LOCK ); + assert( p->eLock>=SHARED_LOCK ); + break; + + case PAGER_WRITER_LOCKED: + assert( p->eLock!=UNKNOWN_LOCK ); + assert( pPager->errCode==SQLITE_OK ); + if( !pagerUseWal(pPager) ){ + assert( p->eLock>=RESERVED_LOCK ); + } + assert( pPager->dbSize==pPager->dbOrigSize ); + assert( pPager->dbOrigSize==pPager->dbFileSize ); + assert( pPager->dbOrigSize==pPager->dbHintSize ); + assert( pPager->setMaster==0 ); + break; + + case PAGER_WRITER_CACHEMOD: + assert( p->eLock!=UNKNOWN_LOCK ); + assert( pPager->errCode==SQLITE_OK ); + if( !pagerUseWal(pPager) ){ + /* It is possible that if journal_mode=wal here that neither the + ** journal file nor the WAL file are open. This happens during + ** a rollback transaction that switches from journal_mode=off + ** to journal_mode=wal. + */ + assert( p->eLock>=RESERVED_LOCK ); + assert( isOpen(p->jfd) + || p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_WAL + ); + } + assert( pPager->dbOrigSize==pPager->dbFileSize ); + assert( pPager->dbOrigSize==pPager->dbHintSize ); + break; + + case PAGER_WRITER_DBMOD: + assert( p->eLock==EXCLUSIVE_LOCK ); + assert( pPager->errCode==SQLITE_OK ); + assert( !pagerUseWal(pPager) ); + assert( p->eLock>=EXCLUSIVE_LOCK ); + assert( isOpen(p->jfd) + || p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_WAL + ); + assert( pPager->dbOrigSize<=pPager->dbHintSize ); + break; + + case PAGER_WRITER_FINISHED: + assert( p->eLock==EXCLUSIVE_LOCK ); + assert( pPager->errCode==SQLITE_OK ); + assert( !pagerUseWal(pPager) ); + assert( isOpen(p->jfd) + || p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_WAL + ); + break; + + case PAGER_ERROR: + /* There must be at least one outstanding reference to the pager if + ** in ERROR state. Otherwise the pager should have already dropped + ** back to OPEN state. + */ + assert( pPager->errCode!=SQLITE_OK ); + assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile ); + break; + } + + return 1; +} +#endif /* ifndef NDEBUG */ + +#ifdef SQLITE_DEBUG +/* +** Return a pointer to a human readable string in a static buffer +** containing the state of the Pager object passed as an argument. This +** is intended to be used within debuggers. For example, as an alternative +** to "print *pPager" in gdb: +** +** (gdb) printf "%s", print_pager_state(pPager) +*/ +static char *print_pager_state(Pager *p){ + static char zRet[1024]; + + sqlite3_snprintf(1024, zRet, + "Filename: %s\n" + "State: %s errCode=%d\n" + "Lock: %s\n" + "Locking mode: locking_mode=%s\n" + "Journal mode: journal_mode=%s\n" + "Backing store: tempFile=%d memDb=%d useJournal=%d\n" + "Journal: journalOff=%lld journalHdr=%lld\n" + "Size: dbsize=%d dbOrigSize=%d dbFileSize=%d\n" + , p->zFilename + , p->eState==PAGER_OPEN ? "OPEN" : + p->eState==PAGER_READER ? "READER" : + p->eState==PAGER_WRITER_LOCKED ? "WRITER_LOCKED" : + p->eState==PAGER_WRITER_CACHEMOD ? "WRITER_CACHEMOD" : + p->eState==PAGER_WRITER_DBMOD ? "WRITER_DBMOD" : + p->eState==PAGER_WRITER_FINISHED ? "WRITER_FINISHED" : + p->eState==PAGER_ERROR ? "ERROR" : "?error?" + , (int)p->errCode + , p->eLock==NO_LOCK ? "NO_LOCK" : + p->eLock==RESERVED_LOCK ? "RESERVED" : + p->eLock==EXCLUSIVE_LOCK ? "EXCLUSIVE" : + p->eLock==SHARED_LOCK ? "SHARED" : + p->eLock==UNKNOWN_LOCK ? "UNKNOWN" : "?error?" + , p->exclusiveMode ? "exclusive" : "normal" + , p->journalMode==PAGER_JOURNALMODE_MEMORY ? "memory" : + p->journalMode==PAGER_JOURNALMODE_OFF ? "off" : + p->journalMode==PAGER_JOURNALMODE_DELETE ? "delete" : + p->journalMode==PAGER_JOURNALMODE_PERSIST ? "persist" : + p->journalMode==PAGER_JOURNALMODE_TRUNCATE ? "truncate" : + p->journalMode==PAGER_JOURNALMODE_WAL ? "wal" : "?error?" + , (int)p->tempFile, (int)p->memDb, (int)p->useJournal + , p->journalOff, p->journalHdr + , (int)p->dbSize, (int)p->dbOrigSize, (int)p->dbFileSize + ); + + return zRet; +} +#endif + +/* Forward references to the various page getters */ +static int getPageNormal(Pager*,Pgno,DbPage**,int); +static int getPageError(Pager*,Pgno,DbPage**,int); +#if SQLITE_MAX_MMAP_SIZE>0 +static int getPageMMap(Pager*,Pgno,DbPage**,int); +#endif + +/* +** Set the Pager.xGet method for the appropriate routine used to fetch +** content from the pager. +*/ +static void setGetterMethod(Pager *pPager){ + if( pPager->errCode ){ + pPager->xGet = getPageError; +#if SQLITE_MAX_MMAP_SIZE>0 + }else if( USEFETCH(pPager) +#ifdef SQLITE_HAS_CODEC + && pPager->xCodec==0 +#endif + ){ + pPager->xGet = getPageMMap; +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + }else{ + pPager->xGet = getPageNormal; + } +} + +/* +** Return true if it is necessary to write page *pPg into the sub-journal. +** A page needs to be written into the sub-journal if there exists one +** or more open savepoints for which: +** +** * The page-number is less than or equal to PagerSavepoint.nOrig, and +** * The bit corresponding to the page-number is not set in +** PagerSavepoint.pInSavepoint. +*/ +static int subjRequiresPage(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + PagerSavepoint *p; + Pgno pgno = pPg->pgno; + int i; + for(i=0; inSavepoint; i++){ + p = &pPager->aSavepoint[i]; + if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){ + return 1; + } + } + return 0; +} + +#ifdef SQLITE_DEBUG +/* +** Return true if the page is already in the journal file. +*/ +static int pageInJournal(Pager *pPager, PgHdr *pPg){ + return sqlite3BitvecTest(pPager->pInJournal, pPg->pgno); +} +#endif + +/* +** Read a 32-bit integer from the given file descriptor. Store the integer +** that is read in *pRes. Return SQLITE_OK if everything worked, or an +** error code is something goes wrong. +** +** All values are stored on disk as big-endian. +*/ +static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){ + unsigned char ac[4]; + int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset); + if( rc==SQLITE_OK ){ + *pRes = sqlite3Get4byte(ac); + } + return rc; +} + +/* +** Write a 32-bit integer into a string buffer in big-endian byte order. +*/ +#define put32bits(A,B) sqlite3Put4byte((u8*)A,B) + + +/* +** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK +** on success or an error code is something goes wrong. +*/ +static int write32bits(sqlite3_file *fd, i64 offset, u32 val){ + char ac[4]; + put32bits(ac, val); + return sqlite3OsWrite(fd, ac, 4, offset); +} + +/* +** Unlock the database file to level eLock, which must be either NO_LOCK +** or SHARED_LOCK. Regardless of whether or not the call to xUnlock() +** succeeds, set the Pager.eLock variable to match the (attempted) new lock. +** +** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is +** called, do not modify it. See the comment above the #define of +** UNKNOWN_LOCK for an explanation of this. +*/ +static int pagerUnlockDb(Pager *pPager, int eLock){ + int rc = SQLITE_OK; + + assert( !pPager->exclusiveMode || pPager->eLock==eLock ); + assert( eLock==NO_LOCK || eLock==SHARED_LOCK ); + assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 ); + if( isOpen(pPager->fd) ){ + assert( pPager->eLock>=eLock ); + rc = pPager->noLock ? SQLITE_OK : sqlite3OsUnlock(pPager->fd, eLock); + if( pPager->eLock!=UNKNOWN_LOCK ){ + pPager->eLock = (u8)eLock; + } + IOTRACE(("UNLOCK %p %d\n", pPager, eLock)) + } + return rc; +} + +/* +** Lock the database file to level eLock, which must be either SHARED_LOCK, +** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the +** Pager.eLock variable to the new locking state. +** +** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is +** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK. +** See the comment above the #define of UNKNOWN_LOCK for an explanation +** of this. +*/ +static int pagerLockDb(Pager *pPager, int eLock){ + int rc = SQLITE_OK; + + assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK ); + if( pPager->eLockeLock==UNKNOWN_LOCK ){ + rc = pPager->noLock ? SQLITE_OK : sqlite3OsLock(pPager->fd, eLock); + if( rc==SQLITE_OK && (pPager->eLock!=UNKNOWN_LOCK||eLock==EXCLUSIVE_LOCK) ){ + pPager->eLock = (u8)eLock; + IOTRACE(("LOCK %p %d\n", pPager, eLock)) + } + } + return rc; +} + +/* +** This function determines whether or not the atomic-write optimization +** can be used with this pager. The 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 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. +*/ +#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; + + assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); + assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); + if( 0==(dc&(SQLITE_IOCAP_ATOMIC|(szPage>>8)) || nSector>szPage) ){ + return 0; + } + } + + return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); +} +#else +# define jrnlBufferSize(x) 0 +#endif + +/* +** If SQLITE_CHECK_PAGES is defined then we do some sanity checking +** on the cache using a hash function. This is used for testing +** and debugging only. +*/ +#ifdef SQLITE_CHECK_PAGES +/* +** Return a 32-bit hash of the page data for pPage. +*/ +static u32 pager_datahash(int nByte, unsigned char *pData){ + u32 hash = 0; + int i; + for(i=0; ipPager->pageSize, (unsigned char *)pPage->pData); +} +static void pager_set_pagehash(PgHdr *pPage){ + pPage->pageHash = pager_pagehash(pPage); +} + +/* +** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES +** is defined, and NDEBUG is not defined, an assert() statement checks +** that the page is either dirty or still matches the calculated page-hash. +*/ +#define CHECK_PAGE(x) checkPage(x) +static void checkPage(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + assert( pPager->eState!=PAGER_ERROR ); + assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); +} + +#else +#define pager_datahash(X,Y) 0 +#define pager_pagehash(X) 0 +#define pager_set_pagehash(X) +#define CHECK_PAGE(x) +#endif /* SQLITE_CHECK_PAGES */ + +/* +** When this is called the journal file for pager pPager must be open. +** This function attempts to read a master journal file name from the +** end of the file and, if successful, copies it into memory supplied +** by the caller. See comments above writeMasterJournal() for the format +** used to store a master journal file name at the end of a journal file. +** +** zMaster must point to a buffer of at least nMaster bytes allocated by +** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is +** enough space to write the master journal name). If the master journal +** name in the journal is longer than nMaster bytes (including a +** nul-terminator), then this is handled as if no master journal name +** were present in the journal. +** +** If a master journal file name is present at the end of the journal +** file, then it is copied into the buffer pointed to by zMaster. A +** nul-terminator byte is appended to the buffer following the master +** journal file name. +** +** If it is determined that no master journal file name is present +** zMaster[0] is set to 0 and SQLITE_OK returned. +** +** If an error occurs while reading from the journal file, an SQLite +** error code is returned. +*/ +static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){ + int rc; /* Return code */ + u32 len; /* Length in bytes of master journal name */ + i64 szJ; /* Total size in bytes of journal file pJrnl */ + u32 cksum; /* MJ checksum value read from journal */ + u32 u; /* Unsigned loop counter */ + unsigned char aMagic[8]; /* A buffer to hold the magic header */ + zMaster[0] = '\0'; + + if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) + || szJ<16 + || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) + || len>=nMaster + || len==0 + || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) + || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) + || memcmp(aMagic, aJournalMagic, 8) + || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len)) + ){ + return rc; + } + + /* See if the checksum matches the master journal name */ + for(u=0; ujournalOff, assuming a sector +** size of pPager->sectorSize bytes. +** +** i.e for a sector size of 512: +** +** Pager.journalOff Return value +** --------------------------------------- +** 0 0 +** 512 512 +** 100 512 +** 2000 2048 +** +*/ +static i64 journalHdrOffset(Pager *pPager){ + i64 offset = 0; + i64 c = pPager->journalOff; + if( c ){ + offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager); + } + assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); + assert( offset>=c ); + assert( (offset-c)jfd) ); + assert( !sqlite3JournalIsInMemory(pPager->jfd) ); + if( pPager->journalOff ){ + const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */ + + IOTRACE(("JZEROHDR %p\n", pPager)) + if( doTruncate || iLimit==0 ){ + rc = sqlite3OsTruncate(pPager->jfd, 0); + }else{ + static const char zeroHdr[28] = {0}; + rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0); + } + if( rc==SQLITE_OK && !pPager->noSync ){ + rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags); + } + + /* At this point the transaction is committed but the write lock + ** is still held on the file. If there is a size limit configured for + ** the persistent journal and the journal file currently consumes more + ** space than that limit allows for, truncate it now. There is no need + ** to sync the file following this operation. + */ + if( rc==SQLITE_OK && iLimit>0 ){ + i64 sz; + rc = sqlite3OsFileSize(pPager->jfd, &sz); + if( rc==SQLITE_OK && sz>iLimit ){ + rc = sqlite3OsTruncate(pPager->jfd, iLimit); + } + } + } + return rc; +} + +/* +** The journal file must be open when this routine is called. A journal +** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the +** current location. +** +** The format for the journal header is as follows: +** - 8 bytes: Magic identifying journal format. +** - 4 bytes: Number of records in journal, or -1 no-sync mode is on. +** - 4 bytes: Random number used for page hash. +** - 4 bytes: Initial database page count. +** - 4 bytes: Sector size used by the process that wrote this journal. +** - 4 bytes: Database page size. +** +** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space. +*/ +static int writeJournalHdr(Pager *pPager){ + int rc = SQLITE_OK; /* Return code */ + char *zHeader = pPager->pTmpSpace; /* Temporary space used to build header */ + u32 nHeader = (u32)pPager->pageSize;/* Size of buffer pointed to by zHeader */ + u32 nWrite; /* Bytes of header sector written */ + int ii; /* Loop counter */ + + assert( isOpen(pPager->jfd) ); /* Journal file must be open. */ + + if( nHeader>JOURNAL_HDR_SZ(pPager) ){ + nHeader = JOURNAL_HDR_SZ(pPager); + } + + /* If there are active savepoints and any of them were created + ** since the most recent journal header was written, update the + ** PagerSavepoint.iHdrOffset fields now. + */ + for(ii=0; iinSavepoint; ii++){ + if( pPager->aSavepoint[ii].iHdrOffset==0 ){ + pPager->aSavepoint[ii].iHdrOffset = pPager->journalOff; + } + } + + pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager); + + /* + ** Write the nRec Field - the number of page records that follow this + ** journal header. Normally, zero is written to this value at this time. + ** After the records are added to the journal (and the journal synced, + ** if in full-sync mode), the zero is overwritten with the true number + ** of records (see syncJournal()). + ** + ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When + ** reading the journal this value tells SQLite to assume that the + ** rest of the journal file contains valid page records. This assumption + ** is dangerous, as if a failure occurred whilst writing to the journal + ** file it may contain some garbage data. There are two scenarios + ** where this risk can be ignored: + ** + ** * When the pager is in no-sync mode. Corruption can follow a + ** power failure in this case anyway. + ** + ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees + ** that garbage data is never appended to the journal file. + */ + assert( isOpen(pPager->fd) || pPager->noSync ); + if( pPager->noSync || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY) + || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) + ){ + memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); + put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); + }else{ + memset(zHeader, 0, sizeof(aJournalMagic)+4); + } + + /* The random check-hash initializer */ + sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); + put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); + /* The initial database size */ + put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize); + /* The assumed sector size for this process */ + put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize); + + /* The page size */ + put32bits(&zHeader[sizeof(aJournalMagic)+16], pPager->pageSize); + + /* Initializing the tail of the buffer is not necessary. Everything + ** works find if the following memset() is omitted. But initializing + ** the memory prevents valgrind from complaining, so we are willing to + ** take the performance hit. + */ + memset(&zHeader[sizeof(aJournalMagic)+20], 0, + nHeader-(sizeof(aJournalMagic)+20)); + + /* In theory, it is only necessary to write the 28 bytes that the + ** journal header consumes to the journal file here. Then increment the + ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next + ** record is written to the following sector (leaving a gap in the file + ** that will be implicitly filled in by the OS). + ** + ** However it has been discovered that on some systems this pattern can + ** be significantly slower than contiguously writing data to the file, + ** even if that means explicitly writing data to the block of + ** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what + ** is done. + ** + ** The loop is required here in case the sector-size is larger than the + ** database page size. Since the zHeader buffer is only Pager.pageSize + ** bytes in size, more than one call to sqlite3OsWrite() may be required + ** to populate the entire journal header sector. + */ + for(nWrite=0; rc==SQLITE_OK&&nWritejournalHdr, nHeader)) + rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff); + assert( pPager->journalHdr <= pPager->journalOff ); + pPager->journalOff += nHeader; + } + + return rc; +} + +/* +** The journal file must be open when this is called. A journal header file +** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal +** file. The current location in the journal file is given by +** pPager->journalOff. See comments above function writeJournalHdr() for +** a description of the journal header format. +** +** If the header is read successfully, *pNRec is set to the number of +** page records following this header and *pDbSize is set to the size of the +** database before the transaction began, in pages. Also, pPager->cksumInit +** is set to the value read from the journal header. SQLITE_OK is returned +** in this case. +** +** If the journal header file appears to be corrupted, SQLITE_DONE is +** returned and *pNRec and *PDbSize are undefined. If JOURNAL_HDR_SZ bytes +** cannot be read from the journal file an error code is returned. +*/ +static int readJournalHdr( + Pager *pPager, /* Pager object */ + int isHot, + i64 journalSize, /* Size of the open journal file in bytes */ + u32 *pNRec, /* OUT: Value read from the nRec field */ + u32 *pDbSize /* OUT: Value of original database size field */ +){ + int rc; /* Return code */ + unsigned char aMagic[8]; /* A buffer to hold the magic header */ + i64 iHdrOff; /* Offset of journal header being read */ + + assert( isOpen(pPager->jfd) ); /* Journal file must be open. */ + + /* Advance Pager.journalOff to the start of the next sector. If the + ** journal file is too small for there to be a header stored at this + ** point, return SQLITE_DONE. + */ + pPager->journalOff = journalHdrOffset(pPager); + if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ + return SQLITE_DONE; + } + iHdrOff = pPager->journalOff; + + /* Read in the first 8 bytes of the journal header. If they do not match + ** the magic string found at the start of each journal header, return + ** SQLITE_DONE. If an IO error occurs, return an error code. Otherwise, + ** proceed. + */ + if( isHot || iHdrOff!=pPager->journalHdr ){ + rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), iHdrOff); + if( rc ){ + return rc; + } + if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ + return SQLITE_DONE; + } + } + + /* Read the first three 32-bit fields of the journal header: The nRec + ** field, the checksum-initializer and the database size at the start + ** of the transaction. Return an error code if anything goes wrong. + */ + if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+8, pNRec)) + || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+12, &pPager->cksumInit)) + || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+16, pDbSize)) + ){ + return rc; + } + + if( pPager->journalOff==0 ){ + u32 iPageSize; /* Page-size field of journal header */ + u32 iSectorSize; /* Sector-size field of journal header */ + + /* Read the page-size and sector-size journal header fields. */ + if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+20, &iSectorSize)) + || SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+24, &iPageSize)) + ){ + return rc; + } + + /* Versions of SQLite prior to 3.5.8 set the page-size field of the + ** journal header to zero. In this case, assume that the Pager.pageSize + ** variable is already set to the correct page size. + */ + if( iPageSize==0 ){ + iPageSize = pPager->pageSize; + } + + /* Check that the values read from the page-size and sector-size fields + ** are within range. To be 'in range', both values need to be a power + ** of two greater than or equal to 512 or 32, and not greater than their + ** respective compile time maximum limits. + */ + if( iPageSize<512 || iSectorSize<32 + || iPageSize>SQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE + || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0 + ){ + /* If the either the page-size or sector-size in the journal-header is + ** invalid, then the process that wrote the journal-header must have + ** crashed before the header was synced. In this case stop reading + ** the journal file here. + */ + return SQLITE_DONE; + } + + /* Update the page-size to match the value read from the journal. + ** Use a testcase() macro to make sure that malloc failure within + ** PagerSetPagesize() is tested. + */ + rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1); + testcase( rc!=SQLITE_OK ); + + /* Update the assumed sector-size to match the value used by + ** the process that created this journal. If this journal was + ** created by a process other than this one, then this routine + ** is being called from within pager_playback(). The local value + ** of Pager.sectorSize is restored at the end of that routine. + */ + pPager->sectorSize = iSectorSize; + } + + pPager->journalOff += JOURNAL_HDR_SZ(pPager); + return rc; +} + + +/* +** Write the supplied master journal name into the journal file for pager +** pPager at the current location. The master journal name must be the last +** thing written to a journal file. If the pager is in full-sync mode, the +** journal file descriptor is advanced to the next sector boundary before +** anything is written. The format is: +** +** + 4 bytes: PAGER_MJ_PGNO. +** + N bytes: Master journal filename in utf-8. +** + 4 bytes: N (length of master journal name in bytes, no nul-terminator). +** + 4 bytes: Master journal name checksum. +** + 8 bytes: aJournalMagic[]. +** +** The master journal page checksum is the sum of the bytes in the master +** journal name, where each byte is interpreted as a signed 8-bit integer. +** +** If zMaster is a NULL pointer (occurs for a single database transaction), +** this call is a no-op. +*/ +static int writeMasterJournal(Pager *pPager, const char *zMaster){ + int rc; /* Return code */ + int nMaster; /* Length of string zMaster */ + i64 iHdrOff; /* Offset of header in journal file */ + i64 jrnlSize; /* Size of journal file on disk */ + u32 cksum = 0; /* Checksum of string zMaster */ + + assert( pPager->setMaster==0 ); + assert( !pagerUseWal(pPager) ); + + if( !zMaster + || pPager->journalMode==PAGER_JOURNALMODE_MEMORY + || !isOpen(pPager->jfd) + ){ + return SQLITE_OK; + } + pPager->setMaster = 1; + assert( pPager->journalHdr <= pPager->journalOff ); + + /* Calculate the length in bytes and the checksum of zMaster */ + for(nMaster=0; zMaster[nMaster]; nMaster++){ + cksum += zMaster[nMaster]; + } + + /* If in full-sync mode, advance to the next disk sector before writing + ** the master journal name. This is in case the previous page written to + ** the journal has already been synced. + */ + if( pPager->fullSync ){ + pPager->journalOff = journalHdrOffset(pPager); + } + iHdrOff = pPager->journalOff; + + /* Write the master journal data to the end of the journal file. If + ** an error occurs, return the error code to the caller. + */ + if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager)))) + || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4))) + || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster))) + || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum))) + || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, + iHdrOff+4+nMaster+8))) + ){ + return rc; + } + pPager->journalOff += (nMaster+20); + + /* If the pager is in peristent-journal mode, then the physical + ** journal-file may extend past the end of the master-journal name + ** and 8 bytes of magic data just written to the file. This is + ** dangerous because the code to rollback a hot-journal file + ** will not be able to find the master-journal name to determine + ** whether or not the journal is hot. + ** + ** Easiest thing to do in this scenario is to truncate the journal + ** file to the required size. + */ + if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize)) + && jrnlSize>pPager->journalOff + ){ + rc = sqlite3OsTruncate(pPager->jfd, pPager->journalOff); + } + return rc; +} + +/* +** Discard the entire contents of the in-memory page-cache. +*/ +static void pager_reset(Pager *pPager){ + pPager->iDataVersion++; + sqlite3BackupRestart(pPager->pBackup); + sqlite3PcacheClear(pPager->pPCache); +} + +/* +** Return the pPager->iDataVersion value +*/ +SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){ + assert( pPager->eState>PAGER_OPEN ); + return pPager->iDataVersion; +} + +/* +** Free all structures in the Pager.aSavepoint[] array and set both +** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal +** if it is open and the pager is not in exclusive mode. +*/ +static void releaseAllSavepoints(Pager *pPager){ + int ii; /* Iterator for looping through Pager.aSavepoint */ + for(ii=0; iinSavepoint; ii++){ + sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); + } + if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){ + sqlite3OsClose(pPager->sjfd); + } + sqlite3_free(pPager->aSavepoint); + pPager->aSavepoint = 0; + pPager->nSavepoint = 0; + pPager->nSubRec = 0; +} + +/* +** Set the bit number pgno in the PagerSavepoint.pInSavepoint +** bitvecs of all open savepoints. Return SQLITE_OK if successful +** or SQLITE_NOMEM if a malloc failure occurs. +*/ +static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){ + int ii; /* Loop counter */ + int rc = SQLITE_OK; /* Result code */ + + for(ii=0; iinSavepoint; ii++){ + PagerSavepoint *p = &pPager->aSavepoint[ii]; + if( pgno<=p->nOrig ){ + rc |= sqlite3BitvecSet(p->pInSavepoint, pgno); + testcase( rc==SQLITE_NOMEM ); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + } + } + return rc; +} + +/* +** This function is a no-op if the pager is in exclusive mode and not +** in the ERROR state. Otherwise, it switches the pager to PAGER_OPEN +** state. +** +** If the pager is not in exclusive-access mode, the database file is +** completely unlocked. If the file is unlocked and the file-system does +** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is +** closed (if it is open). +** +** If the pager is in ERROR state when this function is called, the +** contents of the pager cache are discarded before switching back to +** the OPEN state. Regardless of whether the pager is in exclusive-mode +** or not, any journal file left in the file-system will be treated +** as a hot-journal and rolled back the next time a read-transaction +** is opened (by this or by any other connection). +*/ +static void pager_unlock(Pager *pPager){ + + assert( pPager->eState==PAGER_READER + || pPager->eState==PAGER_OPEN + || pPager->eState==PAGER_ERROR + ); + + sqlite3BitvecDestroy(pPager->pInJournal); + pPager->pInJournal = 0; + releaseAllSavepoints(pPager); + + if( pagerUseWal(pPager) ){ + assert( !isOpen(pPager->jfd) ); + sqlite3WalEndReadTransaction(pPager->pWal); + pPager->eState = PAGER_OPEN; + }else if( !pPager->exclusiveMode ){ + int rc; /* Error code returned by pagerUnlockDb() */ + int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0; + + /* If the operating system support deletion of open files, then + ** close the journal file when dropping the database lock. Otherwise + ** another connection with journal_mode=delete might delete the file + ** out from under us. + */ + assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 ); + assert( (PAGER_JOURNALMODE_OFF & 5)!=1 ); + assert( (PAGER_JOURNALMODE_WAL & 5)!=1 ); + assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 ); + assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 ); + assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 ); + if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN) + || 1!=(pPager->journalMode & 5) + ){ + sqlite3OsClose(pPager->jfd); + } + + /* If the pager is in the ERROR state and the call to unlock the database + ** file fails, set the current lock to UNKNOWN_LOCK. See the comment + ** above the #define for UNKNOWN_LOCK for an explanation of why this + ** is necessary. + */ + rc = pagerUnlockDb(pPager, NO_LOCK); + if( rc!=SQLITE_OK && pPager->eState==PAGER_ERROR ){ + pPager->eLock = UNKNOWN_LOCK; + } + + /* The pager state may be changed from PAGER_ERROR to PAGER_OPEN here + ** without clearing the error code. This is intentional - the error + ** code is cleared and the cache reset in the block below. + */ + assert( pPager->errCode || pPager->eState!=PAGER_ERROR ); + pPager->changeCountDone = 0; + pPager->eState = PAGER_OPEN; + } + + /* If Pager.errCode is set, the contents of the pager cache cannot be + ** trusted. Now that there are no outstanding references to the pager, + ** it can safely move back to PAGER_OPEN state. This happens in both + ** normal and exclusive-locking mode. + */ + assert( pPager->errCode==SQLITE_OK || !MEMDB ); + if( pPager->errCode ){ + if( pPager->tempFile==0 ){ + pager_reset(pPager); + pPager->changeCountDone = 0; + pPager->eState = PAGER_OPEN; + }else{ + pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER); + } + if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); + pPager->errCode = SQLITE_OK; + setGetterMethod(pPager); + } + + pPager->journalOff = 0; + pPager->journalHdr = 0; + pPager->setMaster = 0; +} + +/* +** This function is called whenever an IOERR or FULL error that requires +** the pager to transition into the ERROR state may ahve occurred. +** The first argument is a pointer to the pager structure, the second +** the error-code about to be returned by a pager API function. The +** value returned is a copy of the second argument to this function. +** +** If the second argument is SQLITE_FULL, SQLITE_IOERR or one of the +** IOERR sub-codes, the pager enters the ERROR state and the error code +** is stored in Pager.errCode. While the pager remains in the ERROR state, +** all major API calls on the Pager will immediately return Pager.errCode. +** +** The ERROR state indicates that the contents of the pager-cache +** cannot be trusted. This state can be cleared by completely discarding +** the contents of the pager-cache. If a transaction was active when +** the persistent error occurred, then the rollback journal may need +** to be replayed to restore the contents of the database file (as if +** it were a hot-journal). +*/ +static int pager_error(Pager *pPager, int rc){ + int rc2 = rc & 0xff; + assert( rc==SQLITE_OK || !MEMDB ); + assert( + pPager->errCode==SQLITE_FULL || + pPager->errCode==SQLITE_OK || + (pPager->errCode & 0xff)==SQLITE_IOERR + ); + if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){ + pPager->errCode = rc; + pPager->eState = PAGER_ERROR; + setGetterMethod(pPager); + } + return rc; +} + +static int pager_truncate(Pager *pPager, Pgno nPage); + +/* +** The write transaction open on pPager is being committed (bCommit==1) +** or rolled back (bCommit==0). +** +** Return TRUE if and only if all dirty pages should be flushed to disk. +** +** Rules: +** +** * For non-TEMP databases, always sync to disk. This is necessary +** for transactions to be durable. +** +** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing +** file has been created already (via a spill on pagerStress()) and +** when the number of dirty pages in memory exceeds 25% of the total +** cache size. +*/ +static int pagerFlushOnCommit(Pager *pPager, int bCommit){ + if( pPager->tempFile==0 ) return 1; + if( !bCommit ) return 0; + if( !isOpen(pPager->fd) ) return 0; + return (sqlite3PCachePercentDirty(pPager->pPCache)>=25); +} + +/* +** This routine ends a transaction. A transaction is usually ended by +** either a COMMIT or a ROLLBACK operation. This routine may be called +** after rollback of a hot-journal, or if an error occurs while opening +** the journal file or writing the very first journal-header of a +** database transaction. +** +** This routine is never called in PAGER_ERROR state. If it is called +** in PAGER_NONE or PAGER_SHARED state and the lock held is less +** exclusive than a RESERVED lock, it is a no-op. +** +** Otherwise, any active savepoints are released. +** +** If the journal file is open, then it is "finalized". Once a journal +** file has been finalized it is not possible to use it to roll back a +** transaction. Nor will it be considered to be a hot-journal by this +** or any other database connection. Exactly how a journal is finalized +** depends on whether or not the pager is running in exclusive mode and +** the current journal-mode (Pager.journalMode value), as follows: +** +** journalMode==MEMORY +** Journal file descriptor is simply closed. This destroys an +** in-memory journal. +** +** journalMode==TRUNCATE +** Journal file is truncated to zero bytes in size. +** +** journalMode==PERSIST +** The first 28 bytes of the journal file are zeroed. This invalidates +** the first journal header in the file, and hence the entire journal +** file. An invalid journal file cannot be rolled back. +** +** journalMode==DELETE +** The journal file is closed and deleted using sqlite3OsDelete(). +** +** If the pager is running in exclusive mode, this method of finalizing +** the journal file is never used. Instead, if the journalMode is +** DELETE and the pager is in exclusive mode, the method described under +** journalMode==PERSIST is used instead. +** +** After the journal is finalized, the pager moves to PAGER_READER state. +** If running in non-exclusive rollback mode, the lock on the file is +** downgraded to a SHARED_LOCK. +** +** SQLITE_OK is returned if no error occurs. If an error occurs during +** any of the IO operations to finalize the journal file or unlock the +** database then the IO error code is returned to the user. If the +** operation to finalize the journal file fails, then the code still +** tries to unlock the database file if not in exclusive mode. If the +** unlock operation fails as well, then the first error code related +** to the first error encountered (the journal finalization one) is +** returned. +*/ +static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ + int rc = SQLITE_OK; /* Error code from journal finalization operation */ + int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ + + /* Do nothing if the pager does not have an open write transaction + ** or at least a RESERVED lock. This function may be called when there + ** is no write-transaction active but a RESERVED or greater lock is + ** held under two circumstances: + ** + ** 1. After a successful hot-journal rollback, it is called with + ** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK. + ** + ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE + ** lock switches back to locking_mode=normal and then executes a + ** read-transaction, this function is called with eState==PAGER_READER + ** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed. + */ + assert( assert_pager_state(pPager) ); + assert( pPager->eState!=PAGER_ERROR ); + if( pPager->eStateeLockjfd) || pPager->pInJournal==0 ); + if( isOpen(pPager->jfd) ){ + assert( !pagerUseWal(pPager) ); + + /* Finalize the journal file. */ + if( sqlite3JournalIsInMemory(pPager->jfd) ){ + /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */ + sqlite3OsClose(pPager->jfd); + }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){ + if( pPager->journalOff==0 ){ + rc = SQLITE_OK; + }else{ + rc = sqlite3OsTruncate(pPager->jfd, 0); + if( rc==SQLITE_OK && pPager->fullSync ){ + /* Make sure the new file size is written into the inode right away. + ** Otherwise the journal might resurrect following a power loss and + ** cause the last transaction to roll back. See + ** https://bugzilla.mozilla.org/show_bug.cgi?id=1072773 + */ + rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); + } + } + pPager->journalOff = 0; + }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST + || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) + ){ + rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile); + pPager->journalOff = 0; + }else{ + /* This branch may be executed with Pager.journalMode==MEMORY if + ** a hot-journal was just rolled back. In this case the journal + ** file should be closed and deleted. If this connection writes to + ** the database file, it will do so using an in-memory journal. + */ + int bDelete = !pPager->tempFile; + assert( sqlite3JournalIsInMemory(pPager->jfd)==0 ); + assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE + || pPager->journalMode==PAGER_JOURNALMODE_MEMORY + || pPager->journalMode==PAGER_JOURNALMODE_WAL + ); + sqlite3OsClose(pPager->jfd); + if( bDelete ){ + rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, pPager->extraSync); + } + } + } + +#ifdef SQLITE_CHECK_PAGES + sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash); + if( pPager->dbSize==0 && sqlite3PcacheRefCount(pPager->pPCache)>0 ){ + PgHdr *p = sqlite3PagerLookup(pPager, 1); + if( p ){ + p->pageHash = 0; + sqlite3PagerUnrefNotNull(p); + } + } +#endif + + sqlite3BitvecDestroy(pPager->pInJournal); + pPager->pInJournal = 0; + pPager->nRec = 0; + if( rc==SQLITE_OK ){ + if( MEMDB || pagerFlushOnCommit(pPager, bCommit) ){ + sqlite3PcacheCleanAll(pPager->pPCache); + }else{ + sqlite3PcacheClearWritable(pPager->pPCache); + } + sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); + } + + if( pagerUseWal(pPager) ){ + /* Drop the WAL write-lock, if any. Also, if the connection was in + ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE + ** lock held on the database file. + */ + rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); + assert( rc2==SQLITE_OK ); + }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){ + /* This branch is taken when committing a transaction in rollback-journal + ** mode if the database file on disk is larger than the database image. + ** At this point the journal has been finalized and the transaction + ** successfully committed, but the EXCLUSIVE lock is still held on the + ** file. So it is safe to truncate the database file to its minimum + ** required size. */ + assert( pPager->eLock==EXCLUSIVE_LOCK ); + rc = pager_truncate(pPager, pPager->dbSize); + } + + if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){ + rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; + } + + if( !pPager->exclusiveMode + && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) + ){ + rc2 = pagerUnlockDb(pPager, SHARED_LOCK); + pPager->changeCountDone = 0; + } + pPager->eState = PAGER_READER; + pPager->setMaster = 0; + + return (rc==SQLITE_OK?rc2:rc); +} + +/* +** Execute a rollback if a transaction is active and unlock the +** database file. +** +** If the pager has already entered the ERROR state, do not attempt +** the rollback at this time. Instead, pager_unlock() is called. The +** call to pager_unlock() will discard all in-memory pages, unlock +** the database file and move the pager back to OPEN state. If this +** means that there is a hot-journal left in the file-system, the next +** connection to obtain a shared lock on the pager (which may be this one) +** will roll it back. +** +** If the pager has not already entered the ERROR state, but an IO or +** malloc error occurs during a rollback, then this will itself cause +** the pager to enter the ERROR state. Which will be cleared by the +** call to pager_unlock(), as described above. +*/ +static void pagerUnlockAndRollback(Pager *pPager){ + if( pPager->eState!=PAGER_ERROR && pPager->eState!=PAGER_OPEN ){ + assert( assert_pager_state(pPager) ); + if( pPager->eState>=PAGER_WRITER_LOCKED ){ + sqlite3BeginBenignMalloc(); + sqlite3PagerRollback(pPager); + sqlite3EndBenignMalloc(); + }else if( !pPager->exclusiveMode ){ + assert( pPager->eState==PAGER_READER ); + pager_end_transaction(pPager, 0, 0); + } + } + pager_unlock(pPager); +} + +/* +** Parameter aData must point to a buffer of pPager->pageSize bytes +** of data. Compute and return a checksum based ont the contents of the +** page of data and the current value of pPager->cksumInit. +** +** This is not a real checksum. It is really just the sum of the +** random initial value (pPager->cksumInit) and every 200th byte +** of the page data, starting with byte offset (pPager->pageSize%200). +** Each byte is interpreted as an 8-bit unsigned integer. +** +** Changing the formula used to compute this checksum results in an +** incompatible journal file format. +** +** If journal corruption occurs due to a power failure, the most likely +** scenario is that one end or the other of the record will be changed. +** It is much less likely that the two ends of the journal record will be +** correct and the middle be corrupt. Thus, this "checksum" scheme, +** though fast and simple, catches the mostly likely kind of corruption. +*/ +static u32 pager_cksum(Pager *pPager, const u8 *aData){ + u32 cksum = pPager->cksumInit; /* Checksum value to return */ + int i = pPager->pageSize-200; /* Loop counter */ + while( i>0 ){ + cksum += aData[i]; + i -= 200; + } + return cksum; +} + +/* +** Report the current page size and number of reserved bytes back +** to the codec. +*/ +#ifdef SQLITE_HAS_CODEC +static void pagerReportSize(Pager *pPager){ + if( pPager->xCodecSizeChng ){ + pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize, + (int)pPager->nReserve); + } +} +#else +# define pagerReportSize(X) /* No-op if we do not support a codec */ +#endif + +#ifdef SQLITE_HAS_CODEC +/* +** Make sure the number of reserved bits is the same in the destination +** pager as it is in the source. This comes up when a VACUUM changes the +** number of reserved bits to the "optimal" amount. +*/ +SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ + if( pDest->nReserve!=pSrc->nReserve ){ + pDest->nReserve = pSrc->nReserve; + pagerReportSize(pDest); + } +} +#endif + +/* +** Read a single page from either the journal file (if isMainJrnl==1) or +** from the sub-journal (if isMainJrnl==0) and playback that page. +** The page begins at offset *pOffset into the file. The *pOffset +** value is increased to the start of the next page in the journal. +** +** The main rollback journal uses checksums - the statement journal does +** not. +** +** If the page number of the page record read from the (sub-)journal file +** is greater than the current value of Pager.dbSize, then playback is +** skipped and SQLITE_OK is returned. +** +** If pDone is not NULL, then it is a record of pages that have already +** been played back. If the page at *pOffset has already been played back +** (if the corresponding pDone bit is set) then skip the playback. +** Make sure the pDone bit corresponding to the *pOffset page is set +** prior to returning. +** +** If the page record is successfully read from the (sub-)journal file +** and played back, then SQLITE_OK is returned. If an IO error occurs +** while reading the record from the (sub-)journal file or while writing +** to the database file, then the IO error code is returned. If data +** is successfully read from the (sub-)journal file but appears to be +** corrupted, SQLITE_DONE is returned. Data is considered corrupted in +** two circumstances: +** +** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or +** * If the record is being rolled back from the main journal file +** and the checksum field does not match the record content. +** +** Neither of these two scenarios are possible during a savepoint rollback. +** +** If this is a savepoint rollback, then memory may have to be dynamically +** allocated by this function. If this is the case and an allocation fails, +** SQLITE_NOMEM is returned. +*/ +static int pager_playback_one_page( + Pager *pPager, /* The pager being played back */ + i64 *pOffset, /* Offset of record to playback */ + Bitvec *pDone, /* Bitvec of pages already played back */ + int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */ + int isSavepnt /* True for a savepoint rollback */ +){ + int rc; + PgHdr *pPg; /* An existing page in the cache */ + Pgno pgno; /* The page number of a page in journal */ + u32 cksum; /* Checksum used for sanity checking */ + char *aData; /* Temporary storage for the page */ + sqlite3_file *jfd; /* The file descriptor for the journal file */ + int isSynced; /* True if journal page is synced */ +#ifdef SQLITE_HAS_CODEC + /* The jrnlEnc flag is true if Journal pages should be passed through + ** the codec. It is false for pure in-memory journals. */ + const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0); +#endif + + assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */ + assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ + assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */ + assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */ + + aData = pPager->pTmpSpace; + assert( aData ); /* Temp storage must have already been allocated */ + assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) ); + + /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction + ** or savepoint rollback done at the request of the caller) or this is + ** a hot-journal rollback. If it is a hot-journal rollback, the pager + ** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback + ** only reads from the main journal, not the sub-journal. + */ + assert( pPager->eState>=PAGER_WRITER_CACHEMOD + || (pPager->eState==PAGER_OPEN && pPager->eLock==EXCLUSIVE_LOCK) + ); + assert( pPager->eState>=PAGER_WRITER_CACHEMOD || isMainJrnl ); + + /* Read the page number and page data from the journal or sub-journal + ** file. Return an error code to the caller if an IO error occurs. + */ + jfd = isMainJrnl ? pPager->jfd : pPager->sjfd; + rc = read32bits(jfd, *pOffset, &pgno); + if( rc!=SQLITE_OK ) return rc; + rc = sqlite3OsRead(jfd, (u8*)aData, pPager->pageSize, (*pOffset)+4); + if( rc!=SQLITE_OK ) return rc; + *pOffset += pPager->pageSize + 4 + isMainJrnl*4; + + /* Sanity checking on the page. This is more important that I originally + ** thought. If a power failure occurs while the journal is being written, + ** it could cause invalid data to be written into the journal. We need to + ** detect this invalid data (with high probability) and ignore it. + */ + if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ + assert( !isSavepnt ); + return SQLITE_DONE; + } + if( pgno>(Pgno)pPager->dbSize || sqlite3BitvecTest(pDone, pgno) ){ + return SQLITE_OK; + } + if( isMainJrnl ){ + rc = read32bits(jfd, (*pOffset)-4, &cksum); + if( rc ) return rc; + if( !isSavepnt && pager_cksum(pPager, (u8*)aData)!=cksum ){ + return SQLITE_DONE; + } + } + + /* If this page has already been played back before during the current + ** rollback, then don't bother to play it back again. + */ + if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){ + return rc; + } + + /* When playing back page 1, restore the nReserve setting + */ + if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ + pPager->nReserve = ((u8*)aData)[20]; + pagerReportSize(pPager); + } + + /* If the pager is in CACHEMOD state, then there must be a copy of this + ** page in the pager cache. In this case just update the pager cache, + ** not the database file. The page is left marked dirty in this case. + ** + ** An exception to the above rule: If the database is in no-sync mode + ** and a page is moved during an incremental vacuum then the page may + ** not be in the pager cache. Later: if a malloc() or IO error occurs + ** during a Movepage() call, then the page may not be in the cache + ** either. So the condition described in the above paragraph is not + ** assert()able. + ** + ** If in WRITER_DBMOD, WRITER_FINISHED or OPEN state, then we update the + ** pager cache if it exists and the main file. The page is then marked + ** not dirty. Since this code is only executed in PAGER_OPEN state for + ** a hot-journal rollback, it is guaranteed that the page-cache is empty + ** if the pager is in OPEN state. + ** + ** Ticket #1171: The statement journal might contain page content that is + ** different from the page content at the start of the transaction. + ** This occurs when a page is changed prior to the start of a statement + ** then changed again within the statement. When rolling back such a + ** statement we must not write to the original database unless we know + ** for certain that original page contents are synced into the main rollback + ** journal. Otherwise, a power loss might leave modified data in the + ** database file without an entry in the rollback journal that can + ** restore the database to its original form. Two conditions must be + ** met before writing to the database files. (1) the database must be + ** locked. (2) we know that the original page content is fully synced + ** in the main journal either because the page is not in cache or else + ** the page is marked as needSync==0. + ** + ** 2008-04-14: When attempting to vacuum a corrupt database file, it + ** is possible to fail a statement on a database that does not yet exist. + ** Do not attempt to write if database file has never been opened. + */ + if( pagerUseWal(pPager) ){ + pPg = 0; + }else{ + pPg = sqlite3PagerLookup(pPager, pgno); + } + assert( pPg || !MEMDB ); + assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile ); + PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n", + PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData), + (isMainJrnl?"main-journal":"sub-journal") + )); + if( isMainJrnl ){ + isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr); + }else{ + isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC)); + } + if( isOpen(pPager->fd) + && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) + && isSynced + ){ + i64 ofst = (pgno-1)*(i64)pPager->pageSize; + testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); + assert( !pagerUseWal(pPager) ); + + /* Write the data read from the journal back into the database file. + ** This is usually safe even for an encrypted database - as the data + ** was encrypted before it was written to the journal file. The exception + ** is if the data was just read from an in-memory sub-journal. In that + ** case it must be encrypted here before it is copied into the database + ** file. */ +#ifdef SQLITE_HAS_CODEC + if( !jrnlEnc ){ + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); + rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + }else +#endif + rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + + if( pgno>pPager->dbFileSize ){ + pPager->dbFileSize = pgno; + } + if( pPager->pBackup ){ +#ifdef SQLITE_HAS_CODEC + if( jrnlEnc ){ + CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); + sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); + CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); + }else +#endif + sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); + } + }else if( !isMainJrnl && pPg==0 ){ + /* If this is a rollback of a savepoint and data was not written to + ** the database and the page is not in-memory, there is a potential + ** problem. When the page is next fetched by the b-tree layer, it + ** will be read from the database file, which may or may not be + ** current. + ** + ** There are a couple of different ways this can happen. All are quite + ** obscure. When running in synchronous mode, this can only happen + ** if the page is on the free-list at the start of the transaction, then + ** populated, then moved using sqlite3PagerMovepage(). + ** + ** The solution is to add an in-memory page to the cache containing + ** the data just read from the sub-journal. Mark the page as dirty + ** and if the pager requires a journal-sync, then mark the page as + ** requiring a journal-sync before it is written. + */ + assert( isSavepnt ); + assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 ); + pPager->doNotSpill |= SPILLFLAG_ROLLBACK; + rc = sqlite3PagerGet(pPager, pgno, &pPg, 1); + assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 ); + pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK; + if( rc!=SQLITE_OK ) return rc; + sqlite3PcacheMakeDirty(pPg); + } + if( pPg ){ + /* No page should ever be explicitly rolled back that is in use, except + ** for page 1 which is held in use in order to keep the lock on the + ** database active. However such a page may be rolled back as a result + ** of an internal error resulting in an automatic call to + ** sqlite3PagerRollback(). + */ + void *pData; + pData = pPg->pData; + memcpy(pData, (u8*)aData, pPager->pageSize); + pPager->xReiniter(pPg); + /* It used to be that sqlite3PcacheMakeClean(pPg) was called here. But + ** that call was dangerous and had no detectable benefit since the cache + ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so + ** has been removed. */ + pager_set_pagehash(pPg); + + /* If this was page 1, then restore the value of Pager.dbFileVers. + ** Do this before any decoding. */ + if( pgno==1 ){ + memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); + } + + /* Decode the page just read from disk */ +#if SQLITE_HAS_CODEC + if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } +#endif + sqlite3PcacheRelease(pPg); + } + return rc; +} + +/* +** Parameter zMaster is the name of a master journal file. A single journal +** file that referred to the master journal file has just been rolled back. +** This routine checks if it is possible to delete the master journal file, +** and does so if it is. +** +** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not +** available for use within this function. +** +** When a master journal file is created, it is populated with the names +** of all of its child journals, one after another, formatted as utf-8 +** encoded text. The end of each child journal file is marked with a +** nul-terminator byte (0x00). i.e. the entire contents of a master journal +** file for a transaction involving two databases might be: +** +** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00" +** +** A master journal file may only be deleted once all of its child +** journals have been rolled back. +** +** This function reads the contents of the master-journal file into +** memory and loops through each of the child journal names. For +** each child journal, it checks if: +** +** * if the child journal exists, and if so +** * if the child journal contains a reference to master journal +** file zMaster +** +** If a child journal can be found that matches both of the criteria +** above, this function returns without doing anything. Otherwise, if +** no such child journal can be found, file zMaster is deleted from +** the file-system using sqlite3OsDelete(). +** +** If an IO error within this function, an error code is returned. This +** function allocates memory by calling sqlite3Malloc(). If an allocation +** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors +** occur, SQLITE_OK is returned. +** +** TODO: This function allocates a single block of memory to load +** the entire contents of the master journal file. This could be +** a couple of kilobytes or so - potentially larger than the page +** size. +*/ +static int pager_delmaster(Pager *pPager, const char *zMaster){ + sqlite3_vfs *pVfs = pPager->pVfs; + int rc; /* Return code */ + sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */ + sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */ + char *zMasterJournal = 0; /* Contents of master journal file */ + i64 nMasterJournal; /* Size of master journal file */ + char *zJournal; /* Pointer to one journal within MJ file */ + char *zMasterPtr; /* Space to hold MJ filename from a journal file */ + int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */ + + /* Allocate space for both the pJournal and pMaster file descriptors. + ** If successful, open the master journal file for reading. + */ + pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); + pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile); + if( !pMaster ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL); + rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0); + } + if( rc!=SQLITE_OK ) goto delmaster_out; + + /* Load the entire master journal file into space obtained from + ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain + ** sufficient space (in zMasterPtr) to hold the names of master + ** journal files extracted from regular rollback-journals. + */ + rc = sqlite3OsFileSize(pMaster, &nMasterJournal); + if( rc!=SQLITE_OK ) goto delmaster_out; + nMasterPtr = pVfs->mxPathname+1; + zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1); + if( !zMasterJournal ){ + rc = SQLITE_NOMEM_BKPT; + goto delmaster_out; + } + zMasterPtr = &zMasterJournal[nMasterJournal+1]; + rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0); + if( rc!=SQLITE_OK ) goto delmaster_out; + zMasterJournal[nMasterJournal] = 0; + + zJournal = zMasterJournal; + while( (zJournal-zMasterJournal)pageSize bytes). +** If the file on disk is currently larger than nPage pages, then use the VFS +** xTruncate() method to truncate it. +** +** Or, it might be the case that the file on disk is smaller than +** nPage pages. Some operating system implementations can get confused if +** you try to truncate a file to some size that is larger than it +** currently is, so detect this case and write a single zero byte to +** the end of the new file instead. +** +** If successful, return SQLITE_OK. If an IO error occurs while modifying +** the database file, return the error code to the caller. +*/ +static int pager_truncate(Pager *pPager, Pgno nPage){ + int rc = SQLITE_OK; + assert( pPager->eState!=PAGER_ERROR ); + assert( pPager->eState!=PAGER_READER ); + + if( isOpen(pPager->fd) + && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) + ){ + i64 currentSize, newSize; + int szPage = pPager->pageSize; + assert( pPager->eLock==EXCLUSIVE_LOCK ); + /* TODO: Is it safe to use Pager.dbFileSize here? */ + rc = sqlite3OsFileSize(pPager->fd, ¤tSize); + newSize = szPage*(i64)nPage; + if( rc==SQLITE_OK && currentSize!=newSize ){ + if( currentSize>newSize ){ + rc = sqlite3OsTruncate(pPager->fd, newSize); + }else if( (currentSize+szPage)<=newSize ){ + char *pTmp = pPager->pTmpSpace; + memset(pTmp, 0, szPage); + testcase( (newSize-szPage) == currentSize ); + testcase( (newSize-szPage) > currentSize ); + rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); + } + if( rc==SQLITE_OK ){ + pPager->dbFileSize = nPage; + } + } + } + return rc; +} + +/* +** Return a sanitized version of the sector-size of OS file pFile. The +** return value is guaranteed to lie between 32 and MAX_SECTOR_SIZE. +*/ +SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){ + int iRet = sqlite3OsSectorSize(pFile); + if( iRet<32 ){ + iRet = 512; + }else if( iRet>MAX_SECTOR_SIZE ){ + assert( MAX_SECTOR_SIZE>=512 ); + iRet = MAX_SECTOR_SIZE; + } + return iRet; +} + +/* +** Set the value of the Pager.sectorSize variable for the given +** pager based on the value returned by the xSectorSize method +** of the open database file. The sector size will be used +** to determine the size and alignment of journal header and +** master journal pointers within created journal files. +** +** For temporary files the effective sector size is always 512 bytes. +** +** Otherwise, for non-temporary files, the effective sector size is +** the value returned by the xSectorSize() method rounded up to 32 if +** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it +** is greater than MAX_SECTOR_SIZE. +** +** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set +** the effective sector size to its minimum value (512). The purpose of +** pPager->sectorSize is to define the "blast radius" of bytes that +** might change if a crash occurs while writing to a single byte in +** that range. But with POWERSAFE_OVERWRITE, the blast radius is zero +** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector +** size. For backwards compatibility of the rollback journal file format, +** we cannot reduce the effective sector size below 512. +*/ +static void setSectorSize(Pager *pPager){ + assert( isOpen(pPager->fd) || pPager->tempFile ); + + if( pPager->tempFile + || (sqlite3OsDeviceCharacteristics(pPager->fd) & + SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0 + ){ + /* Sector size doesn't matter for temporary files. Also, the file + ** may not have been opened yet, in which case the OsSectorSize() + ** call will segfault. */ + pPager->sectorSize = 512; + }else{ + pPager->sectorSize = sqlite3SectorSize(pPager->fd); + } +} + +/* +** Playback the journal and thus restore the database file to +** the state it was in before we started making changes. +** +** The journal file format is as follows: +** +** (1) 8 byte prefix. A copy of aJournalMagic[]. +** (2) 4 byte big-endian integer which is the number of valid page records +** in the journal. If this value is 0xffffffff, then compute the +** number of page records from the journal size. +** (3) 4 byte big-endian integer which is the initial value for the +** sanity checksum. +** (4) 4 byte integer which is the number of pages to truncate the +** database to during a rollback. +** (5) 4 byte big-endian integer which is the sector size. The header +** is this many bytes in size. +** (6) 4 byte big-endian integer which is the page size. +** (7) zero padding out to the next sector size. +** (8) Zero or more pages instances, each as follows: +** + 4 byte page number. +** + pPager->pageSize bytes of data. +** + 4 byte checksum +** +** When we speak of the journal header, we mean the first 7 items above. +** Each entry in the journal is an instance of the 8th item. +** +** Call the value from the second bullet "nRec". nRec is the number of +** valid page entries in the journal. In most cases, you can compute the +** value of nRec from the size of the journal file. But if a power +** failure occurred while the journal was being written, it could be the +** case that the size of the journal file had already been increased but +** the extra entries had not yet made it safely to disk. In such a case, +** the value of nRec computed from the file size would be too large. For +** that reason, we always use the nRec value in the header. +** +** If the nRec value is 0xffffffff it means that nRec should be computed +** from the file size. This value is used when the user selects the +** no-sync option for the journal. A power failure could lead to corruption +** in this case. But for things like temporary table (which will be +** deleted when the power is restored) we don't care. +** +** If the file opened as the journal file is not a well-formed +** journal file then all pages up to the first corrupted page are rolled +** back (or no pages if the journal header is corrupted). The journal file +** is then deleted and SQLITE_OK returned, just as if no corruption had +** been encountered. +** +** If an I/O or malloc() error occurs, the journal-file is not deleted +** and an error code is returned. +** +** The isHot parameter indicates that we are trying to rollback a journal +** that might be a hot journal. Or, it could be that the journal is +** preserved because of JOURNALMODE_PERSIST or JOURNALMODE_TRUNCATE. +** If the journal really is hot, reset the pager cache prior rolling +** back any content. If the journal is merely persistent, no reset is +** needed. +*/ +static int pager_playback(Pager *pPager, int isHot){ + sqlite3_vfs *pVfs = pPager->pVfs; + i64 szJ; /* Size of the journal file in bytes */ + u32 nRec; /* Number of Records in the journal */ + u32 u; /* Unsigned loop counter */ + Pgno mxPg = 0; /* Size of the original file in pages */ + int rc; /* Result code of a subroutine */ + int res = 1; /* Value returned by sqlite3OsAccess() */ + char *zMaster = 0; /* Name of master journal file if any */ + int needPagerReset; /* True to reset page prior to first page rollback */ + int nPlayback = 0; /* Total number of pages restored from journal */ + + /* Figure out how many records are in the journal. Abort early if + ** the journal is empty. + */ + assert( isOpen(pPager->jfd) ); + rc = sqlite3OsFileSize(pPager->jfd, &szJ); + if( rc!=SQLITE_OK ){ + goto end_playback; + } + + /* Read the master journal name from the journal, if it is present. + ** If a master journal file name is specified, but the file is not + ** present on disk, then the journal is not hot and does not need to be + ** played back. + ** + ** TODO: Technically the following is an error because it assumes that + ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that + ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c, + ** mxPathname is 512, which is the same as the minimum allowable value + ** for pageSize. + */ + zMaster = pPager->pTmpSpace; + rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); + if( rc==SQLITE_OK && zMaster[0] ){ + rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); + } + zMaster = 0; + if( rc!=SQLITE_OK || !res ){ + goto end_playback; + } + pPager->journalOff = 0; + needPagerReset = isHot; + + /* This loop terminates either when a readJournalHdr() or + ** pager_playback_one_page() call returns SQLITE_DONE or an IO error + ** occurs. + */ + while( 1 ){ + /* Read the next journal header from the journal file. If there are + ** not enough bytes left in the journal file for a complete header, or + ** it is corrupted, then a process must have failed while writing it. + ** This indicates nothing more needs to be rolled back. + */ + rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + } + goto end_playback; + } + + /* If nRec is 0xffffffff, then this journal was created by a process + ** working in no-sync mode. This means that the rest of the journal + ** file consists of pages, there are no more journal headers. Compute + ** the value of nRec based on this assumption. + */ + if( nRec==0xffffffff ){ + assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); + nRec = (int)((szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager)); + } + + /* If nRec is 0 and this rollback is of a transaction created by this + ** process and if this is the final header in the journal, then it means + ** that this part of the journal was being filled but has not yet been + ** synced to disk. Compute the number of pages based on the remaining + ** size of the file. + ** + ** The third term of the test was added to fix ticket #2565. + ** When rolling back a hot journal, nRec==0 always means that the next + ** chunk of the journal contains zero pages to be rolled back. But + ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in + ** the journal, it means that the journal might contain additional + ** pages that need to be rolled back and that the number of pages + ** should be computed based on the journal file size. + */ + if( nRec==0 && !isHot && + pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ + nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager)); + } + + /* If this is the first header read from the journal, truncate the + ** database file back to its original size. + */ + if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ + rc = pager_truncate(pPager, mxPg); + if( rc!=SQLITE_OK ){ + goto end_playback; + } + pPager->dbSize = mxPg; + } + + /* Copy original pages out of the journal and back into the + ** database file and/or page cache. + */ + for(u=0; ujournalOff,0,1,0); + if( rc==SQLITE_OK ){ + nPlayback++; + }else{ + if( rc==SQLITE_DONE ){ + pPager->journalOff = szJ; + break; + }else if( rc==SQLITE_IOERR_SHORT_READ ){ + /* If the journal has been truncated, simply stop reading and + ** processing the journal. This might happen if the journal was + ** not completely written and synced prior to a crash. In that + ** case, the database should have never been written in the + ** first place so it is OK to simply abandon the rollback. */ + rc = SQLITE_OK; + goto end_playback; + }else{ + /* If we are unable to rollback, quit and return the error + ** code. This will cause the pager to enter the error state + ** so that no further harm will be done. Perhaps the next + ** process to come along will be able to rollback the database. + */ + goto end_playback; + } + } + } + } + /*NOTREACHED*/ + assert( 0 ); + +end_playback: + /* 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 + ** assertion that the transaction counter was modified. + */ +#ifdef SQLITE_DEBUG + if( pPager->fd->pMethods ){ + sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0); + } +#endif + + /* If this playback is happening automatically as a result of an IO or + ** malloc error that occurred after the change-counter was updated but + ** before the transaction was committed, then the change-counter + ** modification may just have been reverted. If this happens in exclusive + ** mode, then subsequent transactions performed by the connection will not + ** update the change-counter at all. This may lead to cache inconsistency + ** problems for other processes at some point in the future. So, just + ** in case this has happened, clear the changeCountDone flag now. + */ + pPager->changeCountDone = pPager->tempFile; + + if( rc==SQLITE_OK ){ + zMaster = pPager->pTmpSpace; + rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); + testcase( rc!=SQLITE_OK ); + } + if( rc==SQLITE_OK + && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) + ){ + rc = sqlite3PagerSync(pPager, 0); + } + if( rc==SQLITE_OK ){ + rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0); + testcase( rc!=SQLITE_OK ); + } + if( rc==SQLITE_OK && zMaster[0] && res ){ + /* If there was a master journal and this routine will return success, + ** see if it is possible to delete the master journal. + */ + rc = pager_delmaster(pPager, zMaster); + testcase( rc!=SQLITE_OK ); + } + if( isHot && nPlayback ){ + sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s", + nPlayback, pPager->zJournal); + } + + /* The Pager.sectorSize variable may have been updated while rolling + ** back a journal created by a process with a different sector size + ** value. Reset it to the correct value for this process. + */ + setSectorSize(pPager); + return rc; +} + + +/* +** Read the content for page pPg out of the database file and into +** pPg->pData. A shared lock or greater must be held on the database +** file before this function is called. +** +** If page 1 is read, then the value of Pager.dbFileVers[] is set to +** the value read from the database file. +** +** 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){ + 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 */ + + assert( pPager->eState>=PAGER_READER && !MEMDB ); + assert( isOpen(pPager->fd) ); + +#ifndef SQLITE_OMIT_WAL + if( iFrame ){ + /* Try to pull the page from the write-ahead log. */ + rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); + }else +#endif + { + i64 iOffset = (pgno-1)*(i64)pPager->pageSize; + rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); + if( rc==SQLITE_IOERR_SHORT_READ ){ + rc = SQLITE_OK; + } + } + + if( 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 + ** of bytes 24..39 of the database. Bytes 28..31 should always be + ** zero or the size of the database in page. Bytes 32..35 and 35..39 + ** should be page numbers which are never 0xffffffff. So filling + ** pPager->dbFileVers[] with all 0xff bytes should suffice. + ** + ** For an encrypted database, the situation is more complex: bytes + ** 24..39 of the database are white noise. But the probability of + ** white noise equaling 16 bytes of 0xff is vanishingly small so + ** we should still be ok. + */ + memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers)); + }else{ + u8 *dbFileVers = &((u8*)pPg->pData)[24]; + memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); + } + } + CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT); + + PAGER_INCR(sqlite3_pager_readdb_count); + PAGER_INCR(pPager->nRead); + IOTRACE(("PGIN %p %d\n", pPager, pgno)); + PAGERTRACE(("FETCH %d page %d hash(%08x)\n", + PAGERID(pPager), pgno, pager_pagehash(pPg))); + + return rc; +} + +/* +** Update the value of the change-counter at offsets 24 and 92 in +** the header and the sqlite version number at offset 96. +** +** This is an unconditional update. See also the pager_incr_changecounter() +** routine which only updates the change-counter if the update is actually +** needed, as determined by the pPager->changeCountDone state variable. +*/ +static void pager_write_changecounter(PgHdr *pPg){ + u32 change_counter; + + /* Increment the value just read and write it back to byte 24. */ + change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1; + put32bits(((char*)pPg->pData)+24, change_counter); + + /* Also store the SQLite version number in bytes 96..99 and in + ** bytes 92..95 store the change counter for which the version number + ** is valid. */ + put32bits(((char*)pPg->pData)+92, change_counter); + put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER); +} + +#ifndef SQLITE_OMIT_WAL +/* +** This function is invoked once for each page that has already been +** written into the log file when a WAL transaction is rolled back. +** Parameter iPg is the page number of said page. The pCtx argument +** is actually a pointer to the Pager structure. +** +** If page iPg is present in the cache, and has no outstanding references, +** it is discarded. Otherwise, if there are one or more outstanding +** references, the page content is reloaded from the database. If the +** attempt to reload content from the database is required and fails, +** return an SQLite error code. Otherwise, SQLITE_OK. +*/ +static int pagerUndoCallback(void *pCtx, Pgno iPg){ + int rc = SQLITE_OK; + Pager *pPager = (Pager *)pCtx; + PgHdr *pPg; + + assert( pagerUseWal(pPager) ); + pPg = sqlite3PagerLookup(pPager, iPg); + if( pPg ){ + 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); + } + if( rc==SQLITE_OK ){ + pPager->xReiniter(pPg); + } + sqlite3PagerUnrefNotNull(pPg); + } + } + + /* Normally, if a transaction is rolled back, any backup processes are + ** updated as data is copied out of the rollback journal and into the + ** database. This is not generally possible with a WAL database, as + ** rollback involves simply truncating the log file. Therefore, if one + ** or more frames have already been written to the log (and therefore + ** also copied into the backup databases) as part of this transaction, + ** the backups must be restarted. + */ + sqlite3BackupRestart(pPager->pBackup); + + return rc; +} + +/* +** This function is called to rollback a transaction on a WAL database. +*/ +static int pagerRollbackWal(Pager *pPager){ + int rc; /* Return Code */ + PgHdr *pList; /* List of dirty pages to revert */ + + /* For all pages in the cache that are currently dirty or have already + ** been written (but not committed) to the log file, do one of the + ** following: + ** + ** + Discard the cached page (if refcount==0), or + ** + Reload page content from the database (if refcount>0). + */ + pPager->dbSize = pPager->dbOrigSize; + rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager); + pList = sqlite3PcacheDirtyList(pPager->pPCache); + while( pList && rc==SQLITE_OK ){ + PgHdr *pNext = pList->pDirty; + rc = pagerUndoCallback((void *)pPager, pList->pgno); + pList = pNext; + } + + return rc; +} + +/* +** This function is a wrapper around sqlite3WalFrames(). As well as logging +** the contents of the list of pages headed by pList (connected by pDirty), +** this function notifies any active backup processes that the pages have +** changed. +** +** The list of pages passed into this routine is always sorted by page number. +** Hence, if page 1 appears anywhere on the list, it will be the first page. +*/ +static int pagerWalFrames( + Pager *pPager, /* Pager object */ + PgHdr *pList, /* List of frames to log */ + Pgno nTruncate, /* Database size after this commit */ + int isCommit /* True if this is a commit */ +){ + int rc; /* Return code */ + int nList; /* Number of pages in pList */ + PgHdr *p; /* For looping over pages */ + + assert( pPager->pWal ); + assert( pList ); +#ifdef SQLITE_DEBUG + /* Verify that the page list is in accending order */ + for(p=pList; p && p->pDirty; p=p->pDirty){ + assert( p->pgno < p->pDirty->pgno ); + } +#endif + + assert( pList->pDirty==0 || isCommit ); + if( isCommit ){ + /* If a WAL transaction is being committed, there is no point in writing + ** any pages with page numbers greater than nTruncate into the WAL file. + ** They will never be read by any client. So remove them from the pDirty + ** list here. */ + PgHdr **ppNext = &pList; + nList = 0; + for(p=pList; (*ppNext = p)!=0; p=p->pDirty){ + if( p->pgno<=nTruncate ){ + ppNext = &p->pDirty; + nList++; + } + } + assert( pList ); + }else{ + nList = 1; + } + pPager->aStat[PAGER_STAT_WRITE] += nList; + + if( pList->pgno==1 ) pager_write_changecounter(pList); + rc = sqlite3WalFrames(pPager->pWal, + pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags + ); + if( rc==SQLITE_OK && pPager->pBackup ){ + for(p=pList; p; p=p->pDirty){ + sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData); + } + } + +#ifdef SQLITE_CHECK_PAGES + pList = sqlite3PcacheDirtyList(pPager->pPCache); + for(p=pList; p; p=p->pDirty){ + pager_set_pagehash(p); + } +#endif + + return rc; +} + +/* +** Begin a read transaction on the WAL. +** +** This routine used to be called "pagerOpenSnapshot()" because it essentially +** makes a snapshot of the database at the current point in time and preserves +** that snapshot for use by the reader in spite of concurrently changes by +** other writers or checkpointers. +*/ +static int pagerBeginReadTransaction(Pager *pPager){ + int rc; /* Return code */ + int changed = 0; /* True if cache must be reset */ + + assert( pagerUseWal(pPager) ); + assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER ); + + /* sqlite3WalEndReadTransaction() was not called for the previous + ** transaction in locking_mode=EXCLUSIVE. So call it now. If we + ** are in locking_mode=NORMAL and EndRead() was previously called, + ** the duplicate call is harmless. + */ + sqlite3WalEndReadTransaction(pPager->pWal); + + rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); + if( rc!=SQLITE_OK || changed ){ + pager_reset(pPager); + if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); + } + + return rc; +} +#endif + +/* +** This function is called as part of the transition from PAGER_OPEN +** to PAGER_READER state to determine the size of the database file +** in pages (assuming the page size currently stored in Pager.pageSize). +** +** If no error occurs, SQLITE_OK is returned and the size of the database +** in pages is stored in *pnPage. Otherwise, an error code (perhaps +** SQLITE_IOERR_FSTAT) is returned and *pnPage is left unmodified. +*/ +static int pagerPagecount(Pager *pPager, Pgno *pnPage){ + Pgno nPage; /* Value to return via *pnPage */ + + /* Query the WAL sub-system for the database size. The WalDbsize() + ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or + ** if the database size is not available. The database size is not + ** available from the WAL sub-system if the log file is empty or + ** contains no valid committed transactions. + */ + assert( pPager->eState==PAGER_OPEN ); + assert( pPager->eLock>=SHARED_LOCK ); + assert( isOpen(pPager->fd) ); + assert( pPager->tempFile==0 ); + nPage = sqlite3WalDbsize(pPager->pWal); + + /* If the number of pages in the database is not available from the + ** WAL sub-system, determine the page counte based on the size of + ** the database file. If the size of the database file is not an + ** integer multiple of the page-size, round up the result. + */ + if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){ + i64 n = 0; /* Size of db file in bytes */ + int rc = sqlite3OsFileSize(pPager->fd, &n); + if( rc!=SQLITE_OK ){ + return rc; + } + nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize); + } + + /* If the current number of pages in the file is greater than the + ** configured maximum pager number, increase the allowed limit so + ** that the file can be read. + */ + if( nPage>pPager->mxPgno ){ + pPager->mxPgno = (Pgno)nPage; + } + + *pnPage = nPage; + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_WAL +/* +** Check if the *-wal file that corresponds to the database opened by pPager +** exists if the database is not empy, or verify that the *-wal file does +** not exist (by deleting it) if the database file is empty. +** +** If the database is not empty and the *-wal file exists, open the pager +** in WAL mode. If the database is empty or if no *-wal file exists and +** if no error occurs, make sure Pager.journalMode is not set to +** PAGER_JOURNALMODE_WAL. +** +** Return SQLITE_OK or an error code. +** +** The caller must hold a SHARED lock on the database file to call this +** function. Because an EXCLUSIVE lock on the db file is required to delete +** a WAL on a none-empty database, this ensures there is no race condition +** between the xAccess() below and an xDelete() being executed by some +** other connection. +*/ +static int pagerOpenWalIfPresent(Pager *pPager){ + int rc = SQLITE_OK; + assert( pPager->eState==PAGER_OPEN ); + assert( pPager->eLock>=SHARED_LOCK ); + + if( !pPager->tempFile ){ + int isWal; /* True if WAL file exists */ + Pgno nPage; /* Size of the database file */ + + rc = pagerPagecount(pPager, &nPage); + if( rc ) return rc; + if( nPage==0 ){ + rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); + if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK; + isWal = 0; + }else{ + rc = sqlite3OsAccess( + pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal + ); + } + if( rc==SQLITE_OK ){ + if( isWal ){ + testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); + rc = sqlite3PagerOpenWal(pPager, 0); + }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ + pPager->journalMode = PAGER_JOURNALMODE_DELETE; + } + } + } + return rc; +} +#endif + +/* +** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback +** the entire master journal file. The case pSavepoint==NULL occurs when +** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction +** savepoint. +** +** When pSavepoint is not NULL (meaning a non-transaction savepoint is +** being rolled back), then the rollback consists of up to three stages, +** performed in the order specified: +** +** * Pages are played back from the main journal starting at byte +** offset PagerSavepoint.iOffset and continuing to +** PagerSavepoint.iHdrOffset, or to the end of the main journal +** file if PagerSavepoint.iHdrOffset is zero. +** +** * If PagerSavepoint.iHdrOffset is not zero, then pages are played +** back starting from the journal header immediately following +** PagerSavepoint.iHdrOffset to the end of the main journal file. +** +** * Pages are then played back from the sub-journal file, starting +** with the PagerSavepoint.iSubRec and continuing to the end of +** the journal file. +** +** Throughout the rollback process, each time a page is rolled back, the +** corresponding bit is set in a bitvec structure (variable pDone in the +** implementation below). This is used to ensure that a page is only +** rolled back the first time it is encountered in either journal. +** +** If pSavepoint is NULL, then pages are only played back from the main +** journal file. There is no need for a bitvec in this case. +** +** In either case, before playback commences the Pager.dbSize variable +** is reset to the value that it held at the start of the savepoint +** (or transaction). No page with a page-number greater than this value +** is played back. If one is encountered it is simply skipped. +*/ +static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ + i64 szJ; /* Effective size of the main journal */ + i64 iHdrOff; /* End of first segment of main-journal records */ + int rc = SQLITE_OK; /* Return code */ + Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */ + + assert( pPager->eState!=PAGER_ERROR ); + assert( pPager->eState>=PAGER_WRITER_LOCKED ); + + /* Allocate a bitvec to use to store the set of pages rolled back */ + if( pSavepoint ){ + pDone = sqlite3BitvecCreate(pSavepoint->nOrig); + if( !pDone ){ + return SQLITE_NOMEM_BKPT; + } + } + + /* Set the database size back to the value it was before the savepoint + ** being reverted was opened. + */ + pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize; + pPager->changeCountDone = pPager->tempFile; + + if( !pSavepoint && pagerUseWal(pPager) ){ + return pagerRollbackWal(pPager); + } + + /* Use pPager->journalOff as the effective size of the main rollback + ** journal. The actual file might be larger than this in + ** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything + ** past pPager->journalOff is off-limits to us. + */ + szJ = pPager->journalOff; + assert( pagerUseWal(pPager)==0 || szJ==0 ); + + /* Begin by rolling back records from the main journal starting at + ** PagerSavepoint.iOffset and continuing to the next journal header. + ** There might be records in the main journal that have a page number + ** greater than the current database size (pPager->dbSize) but those + ** will be skipped automatically. Pages are added to pDone as they + ** are played back. + */ + if( pSavepoint && !pagerUseWal(pPager) ){ + iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ; + pPager->journalOff = pSavepoint->iOffset; + while( rc==SQLITE_OK && pPager->journalOffjournalOff, pDone, 1, 1); + } + assert( rc!=SQLITE_DONE ); + }else{ + pPager->journalOff = 0; + } + + /* Continue rolling back records out of the main journal starting at + ** the first journal header seen and continuing until the effective end + ** of the main journal file. Continue to skip out-of-range pages and + ** continue adding pages rolled back to pDone. + */ + while( rc==SQLITE_OK && pPager->journalOffjournalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff" + ** test is related to ticket #2565. See the discussion in the + ** pager_playback() function for additional information. + */ + if( nJRec==0 + && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff + ){ + nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager)); + } + for(ii=0; rc==SQLITE_OK && iijournalOffjournalOff, pDone, 1, 1); + } + assert( rc!=SQLITE_DONE ); + } + assert( rc!=SQLITE_OK || pPager->journalOff>=szJ ); + + /* Finally, rollback pages from the sub-journal. Page that were + ** previously rolled back out of the main journal (and are hence in pDone) + ** will be skipped. Out-of-range pages are also skipped. + */ + if( pSavepoint ){ + u32 ii; /* Loop counter */ + i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize); + + if( pagerUseWal(pPager) ){ + rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData); + } + for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && iinSubRec; ii++){ + assert( offset==(i64)ii*(4+pPager->pageSize) ); + rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1); + } + assert( rc!=SQLITE_DONE ); + } + + sqlite3BitvecDestroy(pDone); + if( rc==SQLITE_OK ){ + pPager->journalOff = szJ; + } + + return rc; +} + +/* +** Change the maximum number of in-memory pages that are allowed +** before attempting to recycle clean and unused pages. +*/ +SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ + sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); +} + +/* +** Change the maximum number of in-memory pages that are allowed +** before attempting to spill pages to journal. +*/ +SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){ + return sqlite3PcacheSetSpillsize(pPager->pPCache, mxPage); +} + +/* +** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap. +*/ +static void pagerFixMaplimit(Pager *pPager){ +#if SQLITE_MAX_MMAP_SIZE>0 + sqlite3_file *fd = pPager->fd; + if( isOpen(fd) && fd->pMethods->iVersion>=3 ){ + sqlite3_int64 sz; + sz = pPager->szMmap; + pPager->bUseFetch = (sz>0); + setGetterMethod(pPager); + sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz); + } +#endif +} + +/* +** Change the maximum size of any memory mapping made of the database file. +*/ +SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){ + pPager->szMmap = szMmap; + pagerFixMaplimit(pPager); +} + +/* +** Free as much memory as possible from the pager. +*/ +SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){ + sqlite3PcacheShrink(pPager->pPCache); +} + +/* +** Adjust settings of the pager to those specified in the pgFlags parameter. +** +** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness +** of the database to damage due to OS crashes or power failures by +** changing the number of syncs()s when writing the journals. +** There are four levels: +** +** OFF sqlite3OsSync() is never called. This is the default +** for temporary and transient files. +** +** NORMAL The journal is synced once before writes begin on the +** database. This is normally adequate protection, but +** it is theoretically possible, though very unlikely, +** that an inopertune power failure could leave the journal +** in a state which would cause damage to the database +** when it is rolled back. +** +** FULL The journal is synced twice before writes begin on the +** database (with some additional information - the nRec field +** of the journal header - being written in between the two +** syncs). If we assume that writing a +** single disk sector is atomic, then this mode provides +** assurance that the journal will not be corrupted to the +** point of causing damage to the database during rollback. +** +** EXTRA This is like FULL except that is also syncs the directory +** that contains the rollback journal after the rollback +** journal is unlinked. +** +** The above is for a rollback-journal mode. For WAL mode, OFF continues +** to mean that no syncs ever occur. NORMAL means that the WAL is synced +** prior to the start of checkpoint and that the database file is synced +** at the conclusion of the checkpoint if the entire content of the WAL +** was written back into the database. But no sync operations occur for +** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL +** file is synced following each commit operation, in addition to the +** syncs associated with NORMAL. There is no difference between FULL +** and EXTRA for WAL mode. +** +** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The +** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync +** using fcntl(F_FULLFSYNC). SQLITE_SYNC_NORMAL means to do an +** ordinary fsync() call. There is no difference between SQLITE_SYNC_FULL +** and SQLITE_SYNC_NORMAL on platforms other than MacOSX. But the +** synchronous=FULL versus synchronous=NORMAL setting determines when +** the xSync primitive is called and is relevant to all platforms. +** +** Numeric values associated with these states are OFF==1, NORMAL=2, +** and FULL=3. +*/ +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +SQLITE_PRIVATE void sqlite3PagerSetFlags( + Pager *pPager, /* The pager to set safety level for */ + unsigned pgFlags /* Various flags */ +){ + unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK; + if( pPager->tempFile ){ + pPager->noSync = 1; + pPager->fullSync = 0; + pPager->extraSync = 0; + }else{ + pPager->noSync = level==PAGER_SYNCHRONOUS_OFF ?1:0; + pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0; + pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0; + } + 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; + if( pPager->fullSync ){ + pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS; + } + if( pgFlags & PAGER_CACHESPILL ){ + pPager->doNotSpill &= ~SPILLFLAG_OFF; + }else{ + pPager->doNotSpill |= SPILLFLAG_OFF; + } +} +#endif + +/* +** The following global variable is incremented whenever the library +** attempts to open a temporary file. This information is used for +** testing and analysis only. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_opentemp_count = 0; +#endif + +/* +** Open a temporary file. +** +** Write the file descriptor into *pFile. Return SQLITE_OK on success +** or some other error code if we fail. The OS will automatically +** delete the temporary file when it is closed. +** +** The flags passed to the VFS layer xOpen() call are those specified +** by parameter vfsFlags ORed with the following: +** +** SQLITE_OPEN_READWRITE +** SQLITE_OPEN_CREATE +** SQLITE_OPEN_EXCLUSIVE +** SQLITE_OPEN_DELETEONCLOSE +*/ +static int pagerOpentemp( + Pager *pPager, /* The pager object */ + sqlite3_file *pFile, /* Write the file descriptor here */ + int vfsFlags /* Flags passed through to the VFS */ +){ + int rc; /* Return code */ + +#ifdef SQLITE_TEST + sqlite3_opentemp_count++; /* Used for testing and analysis only */ +#endif + + vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; + rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0); + assert( rc!=SQLITE_OK || isOpen(pFile) ); + return rc; +} + +/* +** Set the busy handler function. +** +** The pager invokes the busy-handler if sqlite3OsLock() returns +** SQLITE_BUSY when trying to upgrade from no-lock to a SHARED lock, +** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE +** lock. It does *not* invoke the busy handler when upgrading from +** SHARED to RESERVED, or when upgrading from SHARED to EXCLUSIVE +** (which occurs during hot-journal rollback). Summary: +** +** Transition | Invokes xBusyHandler +** -------------------------------------------------------- +** NO_LOCK -> SHARED_LOCK | Yes +** SHARED_LOCK -> RESERVED_LOCK | No +** SHARED_LOCK -> EXCLUSIVE_LOCK | No +** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes +** +** If the busy-handler callback returns non-zero, the lock is +** retried. If it returns zero, then the SQLITE_BUSY error is +** returned to the caller of the pager API function. +*/ +SQLITE_PRIVATE void sqlite3PagerSetBusyhandler( + Pager *pPager, /* Pager object */ + int (*xBusyHandler)(void *), /* Pointer to busy-handler function */ + void *pBusyHandlerArg /* Argument to pass to xBusyHandler */ +){ + pPager->xBusyHandler = xBusyHandler; + pPager->pBusyHandlerArg = pBusyHandlerArg; + + if( isOpen(pPager->fd) ){ + void **ap = (void **)&pPager->xBusyHandler; + assert( ((int(*)(void *))(ap[0]))==xBusyHandler ); + assert( ap[1]==pBusyHandlerArg ); + sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap); + } +} + +/* +** Change the page size used by the Pager object. The new page size +** is passed in *pPageSize. +** +** If the pager is in the error state when this function is called, it +** is a no-op. The value returned is the error state error code (i.e. +** one of SQLITE_IOERR, an SQLITE_IOERR_xxx sub-code or SQLITE_FULL). +** +** Otherwise, if all of the following are true: +** +** * the new page size (value of *pPageSize) is valid (a power +** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and +** +** * there are no outstanding page references, and +** +** * the database is either not an in-memory database or it is +** an in-memory database that currently consists of zero pages. +** +** then the pager object page size is set to *pPageSize. +** +** If the page size is changed, then this function uses sqlite3PagerMalloc() +** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt +** fails, SQLITE_NOMEM is returned and the page size remains unchanged. +** In all other cases, SQLITE_OK is returned. +** +** If the page size is not changed, either because one of the enumerated +** conditions above is not true, the pager was in error state when this +** function was called, or because the memory allocation attempt failed, +** then *pPageSize is set to the old, retained page size before returning. +*/ +SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){ + int rc = SQLITE_OK; + + /* It is not possible to do a full assert_pager_state() here, as this + ** function may be called from within PagerOpen(), before the state + ** of the Pager object is internally consistent. + ** + ** At one point this function returned an error if the pager was in + ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that + ** there is at least one outstanding page reference, this function + ** is a no-op for that case anyhow. + */ + + u32 pageSize = *pPageSize; + assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); + if( (pPager->memDb==0 || pPager->dbSize==0) + && sqlite3PcacheRefCount(pPager->pPCache)==0 + && pageSize && pageSize!=(u32)pPager->pageSize + ){ + char *pNew = NULL; /* New temp space */ + i64 nByte = 0; + + if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){ + rc = sqlite3OsFileSize(pPager->fd, &nByte); + } + if( rc==SQLITE_OK ){ + pNew = (char *)sqlite3PageMalloc(pageSize); + if( !pNew ) rc = SQLITE_NOMEM_BKPT; + } + + if( rc==SQLITE_OK ){ + pager_reset(pPager); + rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); + } + if( rc==SQLITE_OK ){ + sqlite3PageFree(pPager->pTmpSpace); + pPager->pTmpSpace = pNew; + pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); + pPager->pageSize = pageSize; + }else{ + sqlite3PageFree(pNew); + } + } + + *pPageSize = pPager->pageSize; + if( rc==SQLITE_OK ){ + if( nReserve<0 ) nReserve = pPager->nReserve; + assert( nReserve>=0 && nReserve<1000 ); + pPager->nReserve = (i16)nReserve; + pagerReportSize(pPager); + pagerFixMaplimit(pPager); + } + return rc; +} + +/* +** Return a pointer to the "temporary page" buffer held internally +** by the pager. This is a buffer that is big enough to hold the +** entire content of a database page. This buffer is used internally +** during rollback and will be overwritten whenever a rollback +** occurs. But other modules are free to use it too, as long as +** no rollbacks are happening. +*/ +SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){ + return pPager->pTmpSpace; +} + +/* +** Attempt to set the maximum database page count if mxPage is positive. +** Make no changes if mxPage is zero or negative. And never reduce the +** maximum page count below the current size of the database. +** +** Regardless of mxPage, return the current maximum page count. +*/ +SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){ + if( mxPage>0 ){ + pPager->mxPgno = mxPage; + } + assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */ + assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */ + return pPager->mxPgno; +} + +/* +** The following set of routines are used to disable the simulated +** I/O error mechanism. These routines are used to avoid simulated +** errors in places where we do not care about errors. +** +** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops +** and generate no code. +*/ +#ifdef SQLITE_TEST +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_hit; +static int saved_cnt; +void disable_simulated_io_errors(void){ + saved_cnt = sqlite3_io_error_pending; + sqlite3_io_error_pending = -1; +} +void enable_simulated_io_errors(void){ + sqlite3_io_error_pending = saved_cnt; +} +#else +# define disable_simulated_io_errors() +# define enable_simulated_io_errors() +#endif + +/* +** Read the first N bytes from the beginning of the file into memory +** that pDest points to. +** +** If the pager was opened on a transient file (zFilename==""), or +** opened on a file less than N bytes in size, the output buffer is +** zeroed and SQLITE_OK returned. The rationale for this is that this +** function is used to read database headers, and a new transient or +** zero sized database has a header than consists entirely of zeroes. +** +** If any IO error apart from SQLITE_IOERR_SHORT_READ is encountered, +** the error code is returned to the caller and the contents of the +** output buffer undefined. +*/ +SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){ + int rc = SQLITE_OK; + memset(pDest, 0, N); + assert( isOpen(pPager->fd) || pPager->tempFile ); + + /* This routine is only called by btree immediately after creating + ** the Pager object. There has not been an opportunity to transition + ** to WAL mode yet. + */ + assert( !pagerUseWal(pPager) ); + + if( isOpen(pPager->fd) ){ + IOTRACE(("DBHDR %p 0 %d\n", pPager, N)) + rc = sqlite3OsRead(pPager->fd, pDest, N, 0); + if( rc==SQLITE_IOERR_SHORT_READ ){ + rc = SQLITE_OK; + } + } + return rc; +} + +/* +** This function may only be called when a read-transaction is open on +** the pager. It returns the total number of pages in the database. +** +** However, if the file is between 1 and bytes in size, then +** this is considered a 1 page file. +*/ +SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){ + assert( pPager->eState>=PAGER_READER ); + assert( pPager->eState!=PAGER_WRITER_FINISHED ); + *pnPage = (int)pPager->dbSize; +} + + +/* +** Try to obtain a lock of type locktype on the database file. If +** a similar or greater lock is already held, this function is a no-op +** (returning SQLITE_OK immediately). +** +** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke +** the busy callback if the lock is currently not available. Repeat +** until the busy callback returns false or until the attempt to +** obtain the lock succeeds. +** +** Return SQLITE_OK on success and an error code if we cannot obtain +** the lock. If the lock is obtained successfully, set the Pager.state +** variable to locktype before returning. +*/ +static int pager_wait_on_lock(Pager *pPager, int locktype){ + int rc; /* Return code */ + + /* Check that this is either a no-op (because the requested lock is + ** already held), or one of the transitions that the busy-handler + ** may be invoked during, according to the comment above + ** sqlite3PagerSetBusyhandler(). + */ + assert( (pPager->eLock>=locktype) + || (pPager->eLock==NO_LOCK && locktype==SHARED_LOCK) + || (pPager->eLock==RESERVED_LOCK && locktype==EXCLUSIVE_LOCK) + ); + + do { + rc = pagerLockDb(pPager, locktype); + }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) ); + return rc; +} + +/* +** Function assertTruncateConstraint(pPager) checks that one of the +** following is true for all dirty pages currently in the page-cache: +** +** a) The page number is less than or equal to the size of the +** current database image, in pages, OR +** +** b) if the page content were written at this time, it would not +** be necessary to write the current content out to the sub-journal +** (as determined by function subjRequiresPage()). +** +** If the condition asserted by this function were not true, and the +** dirty page were to be discarded from the cache via the pagerStress() +** routine, pagerStress() would not write the current page content to +** the database file. If a savepoint transaction were rolled back after +** this happened, the correct behavior would be to restore the current +** content of the page. However, since this content is not present in either +** the database file or the portion of the rollback journal and +** sub-journal rolled back the content could not be restored and the +** database image would become corrupt. It is therefore fortunate that +** this circumstance cannot arise. +*/ +#if defined(SQLITE_DEBUG) +static void assertTruncateConstraintCb(PgHdr *pPg){ + assert( pPg->flags&PGHDR_DIRTY ); + assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize ); +} +static void assertTruncateConstraint(Pager *pPager){ + sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb); +} +#else +# define assertTruncateConstraint(pPager) +#endif + +/* +** Truncate the in-memory database file image to nPage pages. This +** function does not actually modify the database file on disk. It +** just sets the internal state of the pager object so that the +** truncation will be done when the current transaction is committed. +** +** This function is only called right before committing a transaction. +** Once this function has been called, the transaction must either be +** rolled back or committed. It is not safe to call this function and +** then continue writing to the database. +*/ +SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ + assert( pPager->dbSize>=nPage ); + assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); + pPager->dbSize = nPage; + + /* At one point the code here called assertTruncateConstraint() to + ** ensure that all pages being truncated away by this operation are, + ** if one or more savepoints are open, present in the savepoint + ** journal so that they can be restored if the savepoint is rolled + ** back. This is no longer necessary as this function is now only + ** called right before committing a transaction. So although the + ** Pager object may still have open savepoints (Pager.nSavepoint!=0), + ** they cannot be rolled back. So the assertTruncateConstraint() call + ** is no longer correct. */ +} + + +/* +** This function is called before attempting a hot-journal rollback. It +** syncs the journal file to disk, then sets pPager->journalHdr to the +** size of the journal file so that the pager_playback() routine knows +** that the entire journal file has been synced. +** +** Syncing a hot-journal to disk before attempting to roll it back ensures +** that if a power-failure occurs during the rollback, the process that +** attempts rollback following system recovery sees the same journal +** content as this process. +** +** If everything goes as planned, SQLITE_OK is returned. Otherwise, +** an SQLite error code. +*/ +static int pagerSyncHotJournal(Pager *pPager){ + int rc = SQLITE_OK; + if( !pPager->noSync ){ + rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL); + } + if( rc==SQLITE_OK ){ + rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr); + } + return rc; +} + +#if SQLITE_MAX_MMAP_SIZE>0 +/* +** Obtain a reference to a memory mapped page object for page number pgno. +** The new object will use the pointer pData, obtained from xFetch(). +** If successful, set *ppPage to point to the new page reference +** and return SQLITE_OK. Otherwise, return an SQLite error code and set +** *ppPage to zero. +** +** Page references obtained by calling this function should be released +** by calling pagerReleaseMapPage(). +*/ +static int pagerAcquireMapPage( + Pager *pPager, /* Pager object */ + Pgno pgno, /* Page number */ + void *pData, /* xFetch()'d data for this page */ + PgHdr **ppPage /* OUT: Acquired page object */ +){ + PgHdr *p; /* Memory mapped page to return */ + + if( pPager->pMmapFreelist ){ + *ppPage = p = pPager->pMmapFreelist; + pPager->pMmapFreelist = p->pDirty; + p->pDirty = 0; + assert( pPager->nExtra>=8 ); + memset(p->pExtra, 0, 8); + }else{ + *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra); + if( p==0 ){ + sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData); + return SQLITE_NOMEM_BKPT; + } + p->pExtra = (void *)&p[1]; + p->flags = PGHDR_MMAP; + p->nRef = 1; + p->pPager = pPager; + } + + assert( p->pExtra==(void *)&p[1] ); + assert( p->pPage==0 ); + assert( p->flags==PGHDR_MMAP ); + assert( p->pPager==pPager ); + assert( p->nRef==1 ); + + p->pgno = pgno; + p->pData = pData; + pPager->nMmapOut++; + + return SQLITE_OK; +} +#endif + +/* +** Release a reference to page pPg. pPg must have been returned by an +** earlier call to pagerAcquireMapPage(). +*/ +static void pagerReleaseMapPage(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + pPager->nMmapOut--; + pPg->pDirty = pPager->pMmapFreelist; + pPager->pMmapFreelist = pPg; + + assert( pPager->fd->pMethods->iVersion>=3 ); + sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData); +} + +/* +** Free all PgHdr objects stored in the Pager.pMmapFreelist list. +*/ +static void pagerFreeMapHdrs(Pager *pPager){ + PgHdr *p; + PgHdr *pNext; + for(p=pPager->pMmapFreelist; p; p=pNext){ + pNext = p->pDirty; + sqlite3_free(p); + } +} + + +/* +** Shutdown the page cache. Free all memory and close all files. +** +** If a transaction was in progress when this routine is called, that +** transaction is rolled back. All outstanding pages are invalidated +** and their memory is freed. Any attempt to use a page associated +** with this page cache after this function returns will likely +** result in a coredump. +** +** This function always succeeds. If a transaction is active an attempt +** is made to roll it back. If an error occurs during the rollback +** a hot journal may be left in the filesystem but no error is returned +** to the caller. +*/ +SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ + u8 *pTmp = (u8 *)pPager->pTmpSpace; + + assert( db || pagerUseWal(pPager)==0 ); + assert( assert_pager_state(pPager) ); + disable_simulated_io_errors(); + sqlite3BeginBenignMalloc(); + pagerFreeMapHdrs(pPager); + /* pPager->errCode = 0; */ + pPager->exclusiveMode = 0; +#ifndef SQLITE_OMIT_WAL + assert( db || pPager->pWal==0 ); + sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, pPager->pageSize, + (db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp) + ); + pPager->pWal = 0; +#endif + pager_reset(pPager); + if( MEMDB ){ + pager_unlock(pPager); + }else{ + /* If it is open, sync the journal file before calling UnlockAndRollback. + ** If this is not done, then an unsynced portion of the open journal + ** file may be played back into the database. If a power failure occurs + ** while this is happening, the database could become corrupt. + ** + ** If an error occurs while trying to sync the journal, shift the pager + ** into the ERROR state. This causes UnlockAndRollback to unlock the + ** database and close the journal file without attempting to roll it + ** back or finalize it. The next database user will have to do hot-journal + ** rollback before accessing the database file. + */ + if( isOpen(pPager->jfd) ){ + pager_error(pPager, pagerSyncHotJournal(pPager)); + } + pagerUnlockAndRollback(pPager); + } + sqlite3EndBenignMalloc(); + enable_simulated_io_errors(); + PAGERTRACE(("CLOSE %d\n", PAGERID(pPager))); + IOTRACE(("CLOSE %p\n", pPager)) + sqlite3OsClose(pPager->jfd); + sqlite3OsClose(pPager->fd); + sqlite3PageFree(pTmp); + sqlite3PcacheClose(pPager->pPCache); + +#ifdef SQLITE_HAS_CODEC + if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); +#endif + + assert( !pPager->aSavepoint && !pPager->pInJournal ); + assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); + + sqlite3_free(pPager); + return SQLITE_OK; +} + +#if !defined(NDEBUG) || defined(SQLITE_TEST) +/* +** Return the page number for page pPg. +*/ +SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage *pPg){ + return pPg->pgno; +} +#endif + +/* +** Increment the reference count for page pPg. +*/ +SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){ + sqlite3PcacheRef(pPg); +} + +/* +** Sync the journal. In other words, make sure all the pages that have +** been written to the journal have actually reached the surface of the +** disk and can be restored in the event of a hot-journal rollback. +** +** If the Pager.noSync flag is set, then this function is a no-op. +** Otherwise, the actions required depend on the journal-mode and the +** device characteristics of the file-system, as follows: +** +** * If the journal file is an in-memory journal file, no action need +** be taken. +** +** * Otherwise, if the device does not support the SAFE_APPEND property, +** then the nRec field of the most recently written journal header +** is updated to contain the number of journal records that have +** been written following it. If the pager is operating in full-sync +** mode, then the journal file is synced before this field is updated. +** +** * If the device does not support the SEQUENTIAL property, then +** journal file is synced. +** +** Or, in pseudo-code: +** +** if( NOT ){ +** if( NOT SAFE_APPEND ){ +** if( ) xSync(); +** +** } +** if( NOT SEQUENTIAL ) xSync(); +** } +** +** If successful, this routine clears the PGHDR_NEED_SYNC flag of every +** page currently held in memory before returning SQLITE_OK. If an IO +** error is encountered, then the IO error code is returned to the caller. +*/ +static int syncJournal(Pager *pPager, int newHdr){ + int rc; /* Return code */ + + assert( pPager->eState==PAGER_WRITER_CACHEMOD + || pPager->eState==PAGER_WRITER_DBMOD + ); + assert( assert_pager_state(pPager) ); + assert( !pagerUseWal(pPager) ); + + rc = sqlite3PagerExclusiveLock(pPager); + if( rc!=SQLITE_OK ) return rc; + + if( !pPager->noSync ){ + assert( !pPager->tempFile ); + if( isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){ + const int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); + assert( isOpen(pPager->jfd) ); + + if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ + /* This block deals with an obscure problem. If the last connection + ** that wrote to this database was operating in persistent-journal + ** mode, then the journal file may at this point actually be larger + ** than Pager.journalOff bytes. If the next thing in the journal + ** file happens to be a journal-header (written as part of the + ** previous connection's transaction), and a crash or power-failure + ** occurs after nRec is updated but before this connection writes + ** anything else to the journal file (or commits/rolls back its + ** transaction), then SQLite may become confused when doing the + ** hot-journal rollback following recovery. It may roll back all + ** of this connections data, then proceed to rolling back the old, + ** out-of-date data that follows it. Database corruption. + ** + ** To work around this, if the journal file does appear to contain + ** a valid header following Pager.journalOff, then write a 0x00 + ** byte to the start of it to prevent it from being recognized. + ** + ** Variable iNextHdrOffset is set to the offset at which this + ** problematic header will occur, if it exists. aMagic is used + ** as a temporary buffer to inspect the first couple of bytes of + ** the potential journal header. + */ + i64 iNextHdrOffset; + u8 aMagic[8]; + u8 zHeader[sizeof(aJournalMagic)+4]; + + memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); + put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec); + + iNextHdrOffset = journalHdrOffset(pPager); + rc = sqlite3OsRead(pPager->jfd, aMagic, 8, iNextHdrOffset); + if( rc==SQLITE_OK && 0==memcmp(aMagic, aJournalMagic, 8) ){ + static const u8 zerobyte = 0; + rc = sqlite3OsWrite(pPager->jfd, &zerobyte, 1, iNextHdrOffset); + } + if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ + return rc; + } + + /* Write the nRec value into the journal file header. If in + ** full-synchronous mode, sync the journal first. This ensures that + ** all data has really hit the disk before nRec is updated to mark + ** it as a candidate for rollback. + ** + ** This is not required if the persistent media supports the + ** SAFE_APPEND property. Because in this case it is not possible + ** for garbage data to be appended to the file, the nRec field + ** is populated with 0xFFFFFFFF when the journal header is written + ** and never needs to be updated. + */ + if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ + PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager))); + IOTRACE(("JSYNC %p\n", pPager)) + rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); + if( rc!=SQLITE_OK ) return rc; + } + IOTRACE(("JHDR %p %lld\n", pPager, pPager->journalHdr)); + rc = sqlite3OsWrite( + pPager->jfd, zHeader, sizeof(zHeader), pPager->journalHdr + ); + if( rc!=SQLITE_OK ) return rc; + } + if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ + PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager))); + IOTRACE(("JSYNC %p\n", pPager)) + rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags| + (pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0) + ); + if( rc!=SQLITE_OK ) return rc; + } + + pPager->journalHdr = pPager->journalOff; + if( newHdr && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ + pPager->nRec = 0; + rc = writeJournalHdr(pPager); + if( rc!=SQLITE_OK ) return rc; + } + }else{ + pPager->journalHdr = pPager->journalOff; + } + } + + /* Unless the pager is in noSync mode, the journal file was just + ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on + ** all pages. + */ + sqlite3PcacheClearSyncFlags(pPager->pPCache); + pPager->eState = PAGER_WRITER_DBMOD; + assert( assert_pager_state(pPager) ); + return SQLITE_OK; +} + +/* +** The argument is the first in a linked list of dirty pages connected +** by the PgHdr.pDirty pointer. This function writes each one of the +** in-memory pages in the list to the database file. The argument may +** be NULL, representing an empty list. In this case this function is +** a no-op. +** +** The pager must hold at least a RESERVED lock when this function +** is called. Before writing anything to the database file, this lock +** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained, +** SQLITE_BUSY is returned and no data is written to the database file. +** +** If the pager is a temp-file pager and the actual file-system file +** is not yet open, it is created and opened before any data is +** written out. +** +** Once the lock has been upgraded and, if necessary, the file opened, +** the pages are written out to the database file in list order. Writing +** a page is skipped if it meets either of the following criteria: +** +** * The page number is greater than Pager.dbSize, or +** * The PGHDR_DONT_WRITE flag is set on the page. +** +** If writing out a page causes the database file to grow, Pager.dbFileSize +** is updated accordingly. If page 1 is written out, then the value cached +** in Pager.dbFileVers[] is updated to match the new value stored in +** the database file. +** +** If everything is successful, SQLITE_OK is returned. If an IO error +** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot +** be obtained, SQLITE_BUSY is returned. +*/ +static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ + int rc = SQLITE_OK; /* Return code */ + + /* This function is only called for rollback pagers in WRITER_DBMOD state. */ + assert( !pagerUseWal(pPager) ); + assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD ); + assert( pPager->eLock==EXCLUSIVE_LOCK ); + assert( isOpen(pPager->fd) || pList->pDirty==0 ); + + /* If the file is a temp-file has not yet been opened, open it now. It + ** is not possible for rc to be other than SQLITE_OK if this branch + ** is taken, as pager_wait_on_lock() is a no-op for temp-files. + */ + if( !isOpen(pPager->fd) ){ + assert( pPager->tempFile && rc==SQLITE_OK ); + rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags); + } + + /* Before the first write, give the VFS a hint of what the final + ** file size will be. + */ + assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); + if( rc==SQLITE_OK + && pPager->dbHintSizedbSize + && (pList->pDirty || pList->pgno>pPager->dbHintSize) + ){ + sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; + sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); + pPager->dbHintSize = pPager->dbSize; + } + + while( rc==SQLITE_OK && pList ){ + Pgno pgno = pList->pgno; + + /* If there are dirty pages in the page cache with page numbers greater + ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to + ** make the file smaller (presumably by auto-vacuum code). Do not write + ** any such pages to the file. + ** + ** Also, do not write out any page that has the PGHDR_DONT_WRITE flag + ** set (set by sqlite3PagerDontWrite()). + */ + if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ + i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */ + char *pData; /* Data to write */ + + assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); + if( pList->pgno==1 ) pager_write_changecounter(pList); + + /* Encode the database */ + CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData); + + /* Write out the page data. */ + rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); + + /* If page 1 was just written, update Pager.dbFileVers to match + ** the value now stored in the database file. If writing this + ** page caused the database file to grow, update dbFileSize. + */ + if( pgno==1 ){ + memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers)); + } + if( pgno>pPager->dbFileSize ){ + pPager->dbFileSize = pgno; + } + pPager->aStat[PAGER_STAT_WRITE]++; + + /* Update any backup objects copying the contents of this pager. */ + sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)pList->pData); + + PAGERTRACE(("STORE %d page %d hash(%08x)\n", + PAGERID(pPager), pgno, pager_pagehash(pList))); + IOTRACE(("PGOUT %p %d\n", pPager, pgno)); + PAGER_INCR(sqlite3_pager_writedb_count); + }else{ + PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno)); + } + pager_set_pagehash(pList); + pList = pList->pDirty; + } + + return rc; +} + +/* +** Ensure that the sub-journal file is open. If it is already open, this +** function is a no-op. +** +** SQLITE_OK is returned if everything goes according to plan. An +** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen() +** fails. +*/ +static int openSubJournal(Pager *pPager){ + int rc = SQLITE_OK; + if( !isOpen(pPager->sjfd) ){ + const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE + | SQLITE_OPEN_DELETEONCLOSE; + int nStmtSpill = sqlite3Config.nStmtSpill; + if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){ + nStmtSpill = -1; + } + rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill); + } + return rc; +} + +/* +** Append a record of the current state of page pPg to the sub-journal. +** +** If successful, set the bit corresponding to pPg->pgno in the bitvecs +** for all open savepoints before returning. +** +** This function returns SQLITE_OK if everything is successful, an IO +** error code if the attempt to write to the sub-journal fails, or +** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint +** bitvec. +*/ +static int subjournalPage(PgHdr *pPg){ + int rc = SQLITE_OK; + Pager *pPager = pPg->pPager; + if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ + + /* Open the sub-journal, if it has not already been opened */ + assert( pPager->useJournal ); + assert( isOpen(pPager->jfd) || pagerUseWal(pPager) ); + assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 ); + assert( pagerUseWal(pPager) + || pageInJournal(pPager, pPg) + || pPg->pgno>pPager->dbOrigSize + ); + rc = openSubJournal(pPager); + + /* If the sub-journal was opened successfully (or was already open), + ** write the journal record into the file. */ + if( rc==SQLITE_OK ){ + void *pData = pPg->pData; + i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); + char *pData2; + +#if SQLITE_HAS_CODEC + if( !pPager->subjInMemory ){ + CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + }else +#endif + pData2 = pData; + PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); + rc = write32bits(pPager->sjfd, offset, pPg->pgno); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4); + } + } + } + if( rc==SQLITE_OK ){ + pPager->nSubRec++; + assert( pPager->nSavepoint>0 ); + rc = addToSavepointBitvecs(pPager, pPg->pgno); + } + return rc; +} +static int subjournalPageIfRequired(PgHdr *pPg){ + if( subjRequiresPage(pPg) ){ + return subjournalPage(pPg); + }else{ + return SQLITE_OK; + } +} + +/* +** This function is called by the pcache layer when it has reached some +** soft memory limit. The first argument is a pointer to a Pager object +** (cast as a void*). The pager is always 'purgeable' (not an in-memory +** database). The second argument is a reference to a page that is +** currently dirty but has no outstanding references. The page +** is always associated with the Pager object passed as the first +** argument. +** +** The job of this function is to make pPg clean by writing its contents +** out to the database file, if possible. This may involve syncing the +** journal file. +** +** If successful, sqlite3PcacheMakeClean() is called on the page and +** SQLITE_OK returned. If an IO error occurs while trying to make the +** page clean, the IO error code is returned. If the page cannot be +** made clean for some other reason, but no error occurs, then SQLITE_OK +** is returned by sqlite3PcacheMakeClean() is not called. +*/ +static int pagerStress(void *p, PgHdr *pPg){ + Pager *pPager = (Pager *)p; + int rc = SQLITE_OK; + + assert( pPg->pPager==pPager ); + assert( pPg->flags&PGHDR_DIRTY ); + + /* The doNotSpill NOSYNC bit is set during times when doing a sync of + ** journal (and adding a new header) is not allowed. This occurs + ** during calls to sqlite3PagerWrite() while trying to journal multiple + ** pages belonging to the same sector. + ** + ** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling + ** regardless of whether or not a sync is required. This is set during + ** a rollback or by user request, respectively. + ** + ** Spilling is also prohibited when in an error state since that could + ** lead to database corruption. In the current implementation it + ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3 + ** while in the error state, hence it is impossible for this routine to + ** be called in the error state. Nevertheless, we include a NEVER() + ** test for the error state as a safeguard against future changes. + */ + if( NEVER(pPager->errCode) ) return SQLITE_OK; + testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK ); + testcase( pPager->doNotSpill & SPILLFLAG_OFF ); + testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC ); + if( pPager->doNotSpill + && ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0 + || (pPg->flags & PGHDR_NEED_SYNC)!=0) + ){ + return SQLITE_OK; + } + + pPg->pDirty = 0; + if( pagerUseWal(pPager) ){ + /* Write a single frame for this page to the log. */ + rc = subjournalPageIfRequired(pPg); + if( rc==SQLITE_OK ){ + rc = pagerWalFrames(pPager, pPg, 0, 0); + } + }else{ + + /* Sync the journal file if required. */ + if( pPg->flags&PGHDR_NEED_SYNC + || pPager->eState==PAGER_WRITER_CACHEMOD + ){ + rc = syncJournal(pPager, 1); + } + + /* Write the contents of the page out to the database file. */ + if( rc==SQLITE_OK ){ + assert( (pPg->flags&PGHDR_NEED_SYNC)==0 ); + rc = pager_write_pagelist(pPager, pPg); + } + } + + /* Mark the page as clean. */ + if( rc==SQLITE_OK ){ + PAGERTRACE(("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno)); + sqlite3PcacheMakeClean(pPg); + } + + return pager_error(pPager, rc); +} + +/* +** Flush all unreferenced dirty pages to disk. +*/ +SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){ + int rc = pPager->errCode; + if( !MEMDB ){ + PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); + assert( assert_pager_state(pPager) ); + while( rc==SQLITE_OK && pList ){ + PgHdr *pNext = pList->pDirty; + if( pList->nRef==0 ){ + rc = pagerStress((void*)pPager, pList); + } + pList = pNext; + } + } + + return rc; +} + +/* +** Allocate and initialize a new Pager object and put a pointer to it +** in *ppPager. The pager should eventually be freed by passing it +** to sqlite3PagerClose(). +** +** The zFilename argument is the path to the database file to open. +** If zFilename is NULL then a randomly-named temporary file is created +** and used as the file to be cached. Temporary files are be deleted +** automatically when they are closed. If zFilename is ":memory:" then +** all information is held in cache. It is never written to disk. +** This can be used to implement an in-memory database. +** +** The nExtra parameter specifies the number of bytes of space allocated +** along with each page reference. This space is available to the user +** via the sqlite3PagerGetExtra() API. When a new page is allocated, the +** first 8 bytes of this space are zeroed but the remainder is uninitialized. +** (The extra space is used by btree as the MemPage object.) +** +** The flags argument is used to specify properties that affect the +** operation of the pager. It should be passed some bitwise combination +** of the PAGER_* flags. +** +** The vfsFlags parameter is a bitmask to pass to the flags parameter +** of the xOpen() method of the supplied VFS when opening files. +** +** If the pager object is allocated and the specified file opened +** successfully, SQLITE_OK is returned and *ppPager set to point to +** the new pager object. If an error occurs, *ppPager is set to NULL +** and error code returned. This function may return SQLITE_NOMEM +** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or +** various SQLITE_IO_XXX errors. +*/ +SQLITE_PRIVATE int sqlite3PagerOpen( + sqlite3_vfs *pVfs, /* The virtual file system to use */ + Pager **ppPager, /* OUT: Return the Pager structure here */ + const char *zFilename, /* Name of the database file to open */ + int nExtra, /* Extra bytes append to each in-memory page */ + int flags, /* flags controlling this file */ + int vfsFlags, /* flags passed through to sqlite3_vfs.xOpen() */ + void (*xReinit)(DbPage*) /* Function to reinitialize pages */ +){ + u8 *pPtr; + Pager *pPager = 0; /* Pager object to allocate and return */ + int rc = SQLITE_OK; /* Return code */ + int tempFile = 0; /* True for temp files (incl. in-memory files) */ + int memDb = 0; /* True if this is an in-memory file */ + int readOnly = 0; /* True if this is a read-only file */ + int journalFileSize; /* Bytes to allocate for each journal fd */ + char *zPathname = 0; /* Full path to database file */ + int nPathname = 0; /* Number of bytes in zPathname */ + int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ + int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ + u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ + const char *zUri = 0; /* URI args to copy */ + int nUri = 0; /* Number of bytes of URI args at *zUri */ + + /* Figure out how much space is required for each journal file-handle + ** (there are two of them, the main journal and the sub-journal). */ + journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); + + /* Set the output variable to NULL in case an error occurs. */ + *ppPager = 0; + +#ifndef SQLITE_OMIT_MEMORYDB + if( flags & PAGER_MEMORY ){ + memDb = 1; + if( zFilename && zFilename[0] ){ + zPathname = sqlite3DbStrDup(0, zFilename); + if( zPathname==0 ) return SQLITE_NOMEM_BKPT; + nPathname = sqlite3Strlen30(zPathname); + zFilename = 0; + } + } +#endif + + /* Compute and store the full pathname in an allocated buffer pointed + ** to by zPathname, length nPathname. Or, if this is a temporary file, + ** leave both nPathname and zPathname set to 0. + */ + if( zFilename && zFilename[0] ){ + const char *z; + nPathname = pVfs->mxPathname+1; + zPathname = sqlite3DbMallocRaw(0, nPathname*2); + if( zPathname==0 ){ + return SQLITE_NOMEM_BKPT; + } + zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ + rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); + nPathname = sqlite3Strlen30(zPathname); + z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; + while( *z ){ + z += sqlite3Strlen30(z)+1; + z += sqlite3Strlen30(z)+1; + } + nUri = (int)(&z[1] - zUri); + assert( nUri>=0 ); + if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ + /* This branch is taken when the journal path required by + ** the database being opened will be more than pVfs->mxPathname + ** bytes in length. This means the database cannot be opened, + ** as it will not be possible to open the journal file or even + ** check for a hot-journal before reading. + */ + rc = SQLITE_CANTOPEN_BKPT; + } + if( rc!=SQLITE_OK ){ + sqlite3DbFree(0, zPathname); + return rc; + } + } + + /* Allocate memory for the Pager structure, PCache object, the + ** three file descriptors, the database file name and the journal + ** file name. The layout in memory is as follows: + ** + ** Pager object (sizeof(Pager) bytes) + ** PCache object (sqlite3PcacheSize() bytes) + ** Database file handle (pVfs->szOsFile bytes) + ** Sub-journal file handle (journalFileSize bytes) + ** Main journal file handle (journalFileSize bytes) + ** Database file name (nPathname+1 bytes) + ** Journal file name (nPathname+8+1 bytes) + */ + pPtr = (u8 *)sqlite3MallocZero( + ROUND8(sizeof(*pPager)) + /* Pager structure */ + ROUND8(pcacheSize) + /* PCache object */ + ROUND8(pVfs->szOsFile) + /* The main db file */ + journalFileSize * 2 + /* The two journal files */ + nPathname + 1 + nUri + /* zFilename */ + nPathname + 8 + 2 /* zJournal */ +#ifndef SQLITE_OMIT_WAL + + nPathname + 4 + 2 /* zWal */ +#endif + ); + assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); + if( !pPtr ){ + sqlite3DbFree(0, zPathname); + return SQLITE_NOMEM_BKPT; + } + pPager = (Pager*)(pPtr); + pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager))); + pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize)); + pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile)); + pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize); + pPager->zFilename = (char*)(pPtr += journalFileSize); + assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); + + /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ + if( zPathname ){ + assert( nPathname>0 ); + pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri); + memcpy(pPager->zFilename, zPathname, nPathname); + if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri); + memcpy(pPager->zJournal, zPathname, nPathname); + memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2); + sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal); +#ifndef SQLITE_OMIT_WAL + pPager->zWal = &pPager->zJournal[nPathname+8+1]; + memcpy(pPager->zWal, zPathname, nPathname); + memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1); + sqlite3FileSuffix3(pPager->zFilename, pPager->zWal); +#endif + sqlite3DbFree(0, zPathname); + } + pPager->pVfs = pVfs; + pPager->vfsFlags = vfsFlags; + + /* Open the pager file. + */ + if( zFilename && zFilename[0] ){ + int fout = 0; /* VFS flags returned by xOpen() */ + rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); + assert( !memDb ); + readOnly = (fout&SQLITE_OPEN_READONLY); + + /* If the file was successfully opened for read/write access, + ** choose a default page size in case we have to create the + ** database file. The default page size is the maximum of: + ** + ** + SQLITE_DEFAULT_PAGE_SIZE, + ** + The value returned by sqlite3OsSectorSize() + ** + The largest page size that can be written atomically. + */ + if( rc==SQLITE_OK ){ + int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); + if( !readOnly ){ + setSectorSize(pPager); + assert(SQLITE_DEFAULT_PAGE_SIZE<=SQLITE_MAX_DEFAULT_PAGE_SIZE); + if( szPageDfltsectorSize ){ + if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){ + szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE; + }else{ + szPageDflt = (u32)pPager->sectorSize; + } + } +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + { + int ii; + assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); + assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); + assert(SQLITE_MAX_DEFAULT_PAGE_SIZE<=65536); + for(ii=szPageDflt; ii<=SQLITE_MAX_DEFAULT_PAGE_SIZE; ii=ii*2){ + if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ + szPageDflt = ii; + } + } + } +#endif + } + pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0); + if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 + || sqlite3_uri_boolean(zFilename, "immutable", 0) ){ + vfsFlags |= SQLITE_OPEN_READONLY; + goto act_like_temp_file; + } + } + }else{ + /* If a temporary file is requested, it is not opened immediately. + ** In this case we accept the default page size and delay actually + ** opening the file until the first call to OsWrite(). + ** + ** This branch is also run for an in-memory database. An in-memory + ** database is the same as a temp-file that is never written out to + ** disk and uses an in-memory rollback journal. + ** + ** This branch also runs for files marked as immutable. + */ +act_like_temp_file: + tempFile = 1; + pPager->eState = PAGER_READER; /* Pretend we already have a lock */ + pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE mode */ + pPager->noLock = 1; /* Do no locking */ + readOnly = (vfsFlags&SQLITE_OPEN_READONLY); + } + + /* The following call to PagerSetPagesize() serves to set the value of + ** Pager.pageSize and to allocate the Pager.pTmpSpace buffer. + */ + if( rc==SQLITE_OK ){ + assert( pPager->memDb==0 ); + rc = sqlite3PagerSetPagesize(pPager, &szPageDflt, -1); + testcase( rc!=SQLITE_OK ); + } + + /* Initialize the PCache object. */ + if( rc==SQLITE_OK ){ + nExtra = ROUND8(nExtra); + assert( nExtra>=8 && nExtra<1000 ); + rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, + !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); + } + + /* If an error occurred above, free the Pager structure and close the file. + */ + if( rc!=SQLITE_OK ){ + sqlite3OsClose(pPager->fd); + sqlite3PageFree(pPager->pTmpSpace); + sqlite3_free(pPager); + return rc; + } + + PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename)); + IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) + + pPager->useJournal = (u8)useJournal; + /* pPager->stmtOpen = 0; */ + /* pPager->stmtInUse = 0; */ + /* pPager->nRef = 0; */ + /* pPager->stmtSize = 0; */ + /* pPager->stmtJSize = 0; */ + /* pPager->nPage = 0; */ + pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; + /* pPager->state = PAGER_UNLOCK; */ + /* pPager->errMask = 0; */ + pPager->tempFile = (u8)tempFile; + assert( tempFile==PAGER_LOCKINGMODE_NORMAL + || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); + assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); + pPager->exclusiveMode = (u8)tempFile; + pPager->changeCountDone = pPager->tempFile; + pPager->memDb = (u8)memDb; + pPager->readOnly = (u8)readOnly; + assert( useJournal || pPager->tempFile ); + pPager->noSync = pPager->tempFile; + if( pPager->noSync ){ + assert( pPager->fullSync==0 ); + assert( pPager->extraSync==0 ); + assert( pPager->syncFlags==0 ); + assert( pPager->walSyncFlags==0 ); + 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->pFirst = 0; */ + /* pPager->pFirstSynced = 0; */ + /* pPager->pLast = 0; */ + pPager->nExtra = (u16)nExtra; + pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT; + assert( isOpen(pPager->fd) || tempFile ); + setSectorSize(pPager); + if( !useJournal ){ + pPager->journalMode = PAGER_JOURNALMODE_OFF; + }else if( memDb ){ + pPager->journalMode = PAGER_JOURNALMODE_MEMORY; + } + /* pPager->xBusyHandler = 0; */ + /* pPager->pBusyHandlerArg = 0; */ + pPager->xReiniter = xReinit; + setGetterMethod(pPager); + /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ + /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ + + *ppPager = pPager; + return SQLITE_OK; +} + + +/* Verify that the database file has not be deleted or renamed out from +** under the pager. Return SQLITE_OK if the database is still were it ought +** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error +** code from sqlite3OsAccess()) if the database has gone missing. +*/ +static int databaseIsUnmoved(Pager *pPager){ + int bHasMoved = 0; + int rc; + + if( pPager->tempFile ) return SQLITE_OK; + if( pPager->dbSize==0 ) return SQLITE_OK; + assert( pPager->zFilename && pPager->zFilename[0] ); + rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved); + if( rc==SQLITE_NOTFOUND ){ + /* If the HAS_MOVED file-control is unimplemented, assume that the file + ** has not been moved. That is the historical behavior of SQLite: prior to + ** version 3.8.3, it never checked */ + rc = SQLITE_OK; + }else if( rc==SQLITE_OK && bHasMoved ){ + rc = SQLITE_READONLY_DBMOVED; + } + return rc; +} + + +/* +** This function is called after transitioning from PAGER_UNLOCK to +** PAGER_SHARED state. It tests if there is a hot journal present in +** the file-system for the given pager. A hot journal is one that +** needs to be played back. According to this function, a hot-journal +** file exists if the following criteria are met: +** +** * The journal file exists in the file system, and +** * No process holds a RESERVED or greater lock on the database file, and +** * The database file itself is greater than 0 bytes in size, and +** * The first byte of the journal file exists and is not 0x00. +** +** If the current size of the database file is 0 but a journal file +** exists, that is probably an old journal left over from a prior +** database with the same name. In this case the journal file is +** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK +** is returned. +** +** This routine does not check if there is a master journal filename +** at the end of the file. If there is, and that master journal file +** does not exist, then the journal file is not really hot. In this +** case this routine will return a false-positive. The pager_playback() +** routine will discover that the journal file is not really hot and +** will not roll it back. +** +** If a hot-journal file is found to exist, *pExists is set to 1 and +** SQLITE_OK returned. If no hot-journal file is present, *pExists is +** set to 0 and SQLITE_OK returned. If an IO error occurs while trying +** to determine whether or not a hot-journal file exists, the IO error +** code is returned and the value of *pExists is undefined. +*/ +static int hasHotJournal(Pager *pPager, int *pExists){ + sqlite3_vfs * const pVfs = pPager->pVfs; + int rc = SQLITE_OK; /* Return code */ + int exists = 1; /* True if a journal file is present */ + int jrnlOpen = !!isOpen(pPager->jfd); + + assert( pPager->useJournal ); + assert( isOpen(pPager->fd) ); + assert( pPager->eState==PAGER_OPEN ); + + assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) & + SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN + )); + + *pExists = 0; + if( !jrnlOpen ){ + rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists); + } + if( rc==SQLITE_OK && exists ){ + int locked = 0; /* True if some process holds a RESERVED lock */ + + /* Race condition here: Another process might have been holding the + ** the RESERVED lock and have a journal open at the sqlite3OsAccess() + ** call above, but then delete the journal and drop the lock before + ** we get to the following sqlite3OsCheckReservedLock() call. If that + ** is the case, this routine might think there is a hot journal when + ** in fact there is none. This results in a false-positive which will + ** be dealt with by the playback routine. Ticket #3883. + */ + rc = sqlite3OsCheckReservedLock(pPager->fd, &locked); + if( rc==SQLITE_OK && !locked ){ + Pgno nPage; /* Number of pages in database file */ + + assert( pPager->tempFile==0 ); + rc = pagerPagecount(pPager, &nPage); + if( rc==SQLITE_OK ){ + /* If the database is zero pages in size, that means that either (1) the + ** journal is a remnant from a prior database with the same name where + ** the database file but not the journal was deleted, or (2) the initial + ** transaction that populates a new database is being rolled back. + ** In either case, the journal file can be deleted. However, take care + ** not to delete the journal file if it is already open due to + ** journal_mode=PERSIST. + */ + if( nPage==0 && !jrnlOpen ){ + sqlite3BeginBenignMalloc(); + if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){ + sqlite3OsDelete(pVfs, pPager->zJournal, 0); + if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); + } + sqlite3EndBenignMalloc(); + }else{ + /* The journal file exists and no other connection has a reserved + ** or greater lock on the database file. Now check that there is + ** at least one non-zero bytes at the start of the journal file. + ** If there is, then we consider this journal to be hot. If not, + ** it can be ignored. + */ + if( !jrnlOpen ){ + int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL; + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f); + } + if( rc==SQLITE_OK ){ + u8 first = 0; + rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0); + if( rc==SQLITE_IOERR_SHORT_READ ){ + rc = SQLITE_OK; + } + if( !jrnlOpen ){ + sqlite3OsClose(pPager->jfd); + } + *pExists = (first!=0); + }else if( rc==SQLITE_CANTOPEN ){ + /* If we cannot open the rollback journal file in order to see if + ** it has a zero header, that might be due to an I/O error, or + ** it might be due to the race condition described above and in + ** ticket #3883. Either way, assume that the journal is hot. + ** This might be a false positive. But if it is, then the + ** automatic journal playback and recovery mechanism will deal + ** with it under an EXCLUSIVE lock where we do not need to + ** worry so much with race conditions. + */ + *pExists = 1; + rc = SQLITE_OK; + } + } + } + } + } + + return rc; +} + +/* +** This function is called to obtain a shared lock on the database file. +** It is illegal to call sqlite3PagerGet() until after this function +** has been successfully called. If a shared-lock is already held when +** this function is called, it is a no-op. +** +** The following operations are also performed by this function. +** +** 1) If the pager is currently in PAGER_OPEN state (no lock held +** on the database file), then an attempt is made to obtain a +** SHARED lock on the database file. Immediately after obtaining +** the SHARED lock, the file-system is checked for a hot-journal, +** which is played back if present. Following any hot-journal +** rollback, the contents of the cache are validated by checking +** the 'change-counter' field of the database file header and +** discarded if they are found to be invalid. +** +** 2) If the pager is running in exclusive-mode, and there are currently +** no outstanding references to any pages, and is in the error state, +** then an attempt is made to clear the error state by discarding +** the contents of the page cache and rolling back any open journal +** file. +** +** If everything is successful, SQLITE_OK is returned. If an IO error +** occurs while locking the database, checking for a hot-journal file or +** rolling back a journal file, the IO error code is returned. +*/ +SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ + int rc = SQLITE_OK; /* Return code */ + + /* This routine is only called from b-tree and only when there are no + ** outstanding pages. This implies that the pager state should either + ** be OPEN or READER. READER is only possible if the pager is or was in + ** exclusive access mode. */ + assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); + assert( assert_pager_state(pPager) ); + assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER ); + assert( pPager->errCode==SQLITE_OK ); + + if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){ + int bHotJournal = 1; /* True if there exists a hot journal-file */ + + assert( !MEMDB ); + assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK ); + + rc = pager_wait_on_lock(pPager, SHARED_LOCK); + if( rc!=SQLITE_OK ){ + assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK ); + goto failed; + } + + /* If a journal file exists, and there is no RESERVED lock on the + ** database file, then it either needs to be played back or deleted. + */ + if( pPager->eLock<=SHARED_LOCK ){ + rc = hasHotJournal(pPager, &bHotJournal); + } + if( rc!=SQLITE_OK ){ + goto failed; + } + if( bHotJournal ){ + if( pPager->readOnly ){ + rc = SQLITE_READONLY_ROLLBACK; + goto failed; + } + + /* Get an EXCLUSIVE lock on the database file. At this point it is + ** important that a RESERVED lock is not obtained on the way to the + ** EXCLUSIVE lock. If it were, another process might open the + ** database file, detect the RESERVED lock, and conclude that the + ** database is safe to read while this process is still rolling the + ** hot-journal back. + ** + ** Because the intermediate RESERVED lock is not requested, any + ** other process attempting to access the database file will get to + ** this point in the code and fail to obtain its own EXCLUSIVE lock + ** on the database file. + ** + ** Unless the pager is in locking_mode=exclusive mode, the lock is + ** downgraded to SHARED_LOCK before this function returns. + */ + rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); + if( rc!=SQLITE_OK ){ + goto failed; + } + + /* If it is not already open and the file exists on disk, open the + ** journal for read/write access. Write access is required because + ** in exclusive-access mode the file descriptor will be kept open + ** and possibly used for a transaction later on. Also, write-access + ** is usually required to finalize the journal in journal_mode=persist + ** mode (and also for journal_mode=truncate on some systems). + ** + ** If the journal does not exist, it usually means that some + ** other connection managed to get in and roll it back before + ** this connection obtained the exclusive lock above. Or, it + ** may mean that the pager was in the error-state when this + ** function was called and the journal file does not exist. + */ + if( !isOpen(pPager->jfd) ){ + sqlite3_vfs * const pVfs = pPager->pVfs; + int bExists; /* True if journal file exists */ + rc = sqlite3OsAccess( + pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists); + if( rc==SQLITE_OK && bExists ){ + int fout = 0; + int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; + assert( !pPager->tempFile ); + rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout); + assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); + if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){ + rc = SQLITE_CANTOPEN_BKPT; + sqlite3OsClose(pPager->jfd); + } + } + } + + /* Playback and delete the journal. Drop the database write + ** lock and reacquire the read lock. Purge the cache before + ** playing back the hot-journal so that we don't end up with + ** an inconsistent cache. Sync the hot journal before playing + ** it back since the process that crashed and left the hot journal + ** probably did not sync it and we are required to always sync + ** the journal before playing it back. + */ + if( isOpen(pPager->jfd) ){ + assert( rc==SQLITE_OK ); + rc = pagerSyncHotJournal(pPager); + if( rc==SQLITE_OK ){ + rc = pager_playback(pPager, !pPager->tempFile); + pPager->eState = PAGER_OPEN; + } + }else if( !pPager->exclusiveMode ){ + pagerUnlockDb(pPager, SHARED_LOCK); + } + + if( rc!=SQLITE_OK ){ + /* This branch is taken if an error occurs while trying to open + ** or roll back a hot-journal while holding an EXCLUSIVE lock. The + ** pager_unlock() routine will be called before returning to unlock + ** the file. If the unlock attempt fails, then Pager.eLock must be + ** set to UNKNOWN_LOCK (see the comment above the #define for + ** UNKNOWN_LOCK above for an explanation). + ** + ** In order to get pager_unlock() to do this, set Pager.eState to + ** PAGER_ERROR now. This is not actually counted as a transition + ** to ERROR state in the state diagram at the top of this file, + ** since we know that the same call to pager_unlock() will very + ** shortly transition the pager object to the OPEN state. Calling + ** assert_pager_state() would fail now, as it should not be possible + ** to be in ERROR state when there are zero outstanding page + ** references. + */ + pager_error(pPager, rc); + goto failed; + } + + assert( pPager->eState==PAGER_OPEN ); + assert( (pPager->eLock==SHARED_LOCK) + || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) + ); + } + + if( !pPager->tempFile && pPager->hasHeldSharedLock ){ + /* The shared-lock has just been acquired then check to + ** see if the database has been modified. If the database has changed, + ** flush the cache. The hasHeldSharedLock flag prevents this from + ** occurring on the very first access to a file, in order to save a + ** single unnecessary sqlite3OsRead() call at the start-up. + ** + ** Database changes are detected by looking at 15 bytes beginning + ** at offset 24 into the file. The first 4 of these 16 bytes are + ** a 32-bit counter that is incremented with each change. The + ** other bytes change randomly with each file change when + ** a codec is in use. + ** + ** There is a vanishingly small chance that a change will not be + ** detected. The chance of an undetected change is so small that + ** it can be neglected. + */ + Pgno nPage = 0; + char dbFileVers[sizeof(pPager->dbFileVers)]; + + rc = pagerPagecount(pPager, &nPage); + if( rc ) goto failed; + + if( nPage>0 ){ + IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); + rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); + if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ + goto failed; + } + }else{ + memset(dbFileVers, 0, sizeof(dbFileVers)); + } + + if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ + pager_reset(pPager); + + /* Unmap the database file. It is possible that external processes + ** may have truncated the database file and then extended it back + ** to its original size while this process was not holding a lock. + ** In this case there may exist a Pager.pMap mapping that appears + ** to be the right size but is not actually valid. Avoid this + ** possibility by unmapping the db here. */ + if( USEFETCH(pPager) ){ + sqlite3OsUnfetch(pPager->fd, 0, 0); + } + } + } + + /* If there is a WAL file in the file-system, open this database in WAL + ** mode. Otherwise, the following function call is a no-op. + */ + rc = pagerOpenWalIfPresent(pPager); +#ifndef SQLITE_OMIT_WAL + assert( pPager->pWal==0 || rc==SQLITE_OK ); +#endif + } + + if( pagerUseWal(pPager) ){ + assert( rc==SQLITE_OK ); + rc = pagerBeginReadTransaction(pPager); + } + + if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){ + rc = pagerPagecount(pPager, &pPager->dbSize); + } + + failed: + if( rc!=SQLITE_OK ){ + assert( !MEMDB ); + pager_unlock(pPager); + assert( pPager->eState==PAGER_OPEN ); + }else{ + pPager->eState = PAGER_READER; + pPager->hasHeldSharedLock = 1; + } + return rc; +} + +/* +** If the reference count has reached zero, rollback any active +** transaction and unlock the pager. +** +** Except, in locking_mode=EXCLUSIVE when there is nothing to in +** the rollback journal, the unlock is not performed and there is +** nothing to rollback, so this routine is a no-op. +*/ +static void pagerUnlockIfUnused(Pager *pPager){ + if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ + pagerUnlockAndRollback(pPager); + } +} + +/* +** The page getter methods each try to acquire a reference to a +** page with page number pgno. If the requested reference is +** successfully obtained, it is copied to *ppPage and SQLITE_OK returned. +** +** There are different implementations of the getter method depending +** on the current state of the pager. +** +** getPageNormal() -- The normal getter +** getPageError() -- Used if the pager is in an error state +** getPageMmap() -- Used if memory-mapped I/O is enabled +** +** If the requested page is already in the cache, it is returned. +** Otherwise, a new page object is allocated and populated with data +** read from the database file. In some cases, the pcache module may +** choose not to allocate a new page object and may reuse an existing +** object with no outstanding references. +** +** The extra data appended to a page is always initialized to zeros the +** first time a page is loaded into memory. If the page requested is +** already in the cache when this function is called, then the extra +** data is left as it was when the page object was last used. +** +** If the database image is smaller than the requested page or if +** the flags parameter contains the PAGER_GET_NOCONTENT bit and the +** requested page is not already stored in the cache, then no +** actual disk read occurs. In this case the memory image of the +** page is initialized to all zeros. +** +** If PAGER_GET_NOCONTENT is true, it means that we do not care about +** the contents of the page. This occurs in two scenarios: +** +** a) When reading a free-list leaf page from the database, and +** +** b) When a savepoint is being rolled back and we need to load +** a new page into the cache to be filled with the data read +** from the savepoint journal. +** +** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead +** of being read from the database. Additionally, the bits corresponding +** to pgno in Pager.pInJournal (bitvec of pages already written to the +** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open +** savepoints are set. This means if the page is made writable at any +** point in the future, using a call to sqlite3PagerWrite(), its contents +** will not be journaled. This saves IO. +** +** The acquisition might fail for several reasons. In all cases, +** an appropriate error code is returned and *ppPage is set to NULL. +** +** See also sqlite3PagerLookup(). Both this routine and Lookup() attempt +** to find a page in the in-memory cache first. If the page is not already +** in memory, this routine goes to disk to read it in whereas Lookup() +** just returns 0. This routine acquires a read-lock the first time it +** has to go to disk, and could also playback an old journal if necessary. +** Since Lookup() never goes to disk, it never has to deal with locks +** or journal files. +*/ +static int getPageNormal( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int flags /* PAGER_GET_XXX flags */ +){ + int rc = SQLITE_OK; + PgHdr *pPg; + u8 noContent; /* True if PAGER_GET_NOCONTENT is set */ + sqlite3_pcache_page *pBase; + + assert( pPager->errCode==SQLITE_OK ); + assert( pPager->eState>=PAGER_READER ); + assert( assert_pager_state(pPager) ); + assert( pPager->hasHeldSharedLock==1 ); + + if( pgno==0 ) return SQLITE_CORRUPT_BKPT; + pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); + if( pBase==0 ){ + pPg = 0; + rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase); + if( rc!=SQLITE_OK ) goto pager_acquire_err; + if( pBase==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto pager_acquire_err; + } + } + pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase); + assert( pPg==(*ppPage) ); + assert( pPg->pgno==pgno ); + assert( pPg->pPager==pPager || pPg->pPager==0 ); + + noContent = (flags & PAGER_GET_NOCONTENT)!=0; + if( pPg->pPager && !noContent ){ + /* In this case the pcache already contains an initialized copy of + ** the page. Return without further ado. */ + assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) ); + pPager->aStat[PAGER_STAT_HIT]++; + return SQLITE_OK; + + }else{ + /* The pager cache has created a new page. Its content needs to + ** be initialized. But first some error checks: + ** + ** (1) The maximum page number is 2^31 + ** (2) Never try to fetch the locking page + */ + if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){ + rc = SQLITE_CORRUPT_BKPT; + goto pager_acquire_err; + } + + pPg->pPager = pPager; + + assert( !isOpen(pPager->fd) || !MEMDB ); + if( !isOpen(pPager->fd) || pPager->dbSizepPager->mxPgno ){ + rc = SQLITE_FULL; + goto pager_acquire_err; + } + if( noContent ){ + /* Failure to set the bits in the InJournal bit-vectors is benign. + ** It merely means that we might do some extra work to journal a + ** page that does not need to be journaled. Nevertheless, be sure + ** to test the case where a malloc error occurs while trying to set + ** a bit in a bit vector. + */ + sqlite3BeginBenignMalloc(); + if( pgno<=pPager->dbOrigSize ){ + TESTONLY( rc = ) sqlite3BitvecSet(pPager->pInJournal, pgno); + testcase( rc==SQLITE_NOMEM ); + } + TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno); + testcase( rc==SQLITE_NOMEM ); + sqlite3EndBenignMalloc(); + } + 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); + if( rc!=SQLITE_OK ){ + goto pager_acquire_err; + } + } + pager_set_pagehash(pPg); + } + return SQLITE_OK; + +pager_acquire_err: + assert( rc!=SQLITE_OK ); + if( pPg ){ + sqlite3PcacheDrop(pPg); + } + pagerUnlockIfUnused(pPager); + *ppPage = 0; + return rc; +} + +#if SQLITE_MAX_MMAP_SIZE>0 +/* The page getter for when memory-mapped I/O is enabled */ +static int getPageMMap( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int flags /* PAGER_GET_XXX flags */ +){ + int rc = SQLITE_OK; + PgHdr *pPg = 0; + u32 iFrame = 0; /* Frame to read from WAL file */ + + /* It is acceptable to use a read-only (mmap) page for any page except + ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY + ** flag was specified by the caller. And so long as the db is not a + ** temporary or in-memory database. */ + const int bMmapOk = (pgno>1 + && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) + ); + + assert( USEFETCH(pPager) ); +#ifdef SQLITE_HAS_CODEC + assert( pPager->xCodec==0 ); +#endif + + /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here + ** allows the compiler optimizer to reuse the results of the "pgno>1" + ** test in the previous statement, and avoid testing pgno==0 in the + ** common case where pgno is large. */ + if( pgno<=1 && pgno==0 ){ + return SQLITE_CORRUPT_BKPT; + } + assert( pPager->eState>=PAGER_READER ); + assert( assert_pager_state(pPager) ); + assert( pPager->hasHeldSharedLock==1 ); + assert( pPager->errCode==SQLITE_OK ); + + if( bMmapOk && pagerUseWal(pPager) ){ + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); + if( rc!=SQLITE_OK ){ + *ppPage = 0; + return rc; + } + } + if( bMmapOk && iFrame==0 ){ + void *pData = 0; + rc = sqlite3OsFetch(pPager->fd, + (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData + ); + if( rc==SQLITE_OK && pData ){ + if( pPager->eState>PAGER_READER || pPager->tempFile ){ + pPg = sqlite3PagerLookup(pPager, pgno); + } + if( pPg==0 ){ + rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); + }else{ + sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData); + } + if( pPg ){ + assert( rc==SQLITE_OK ); + *ppPage = pPg; + return SQLITE_OK; + } + } + if( rc!=SQLITE_OK ){ + *ppPage = 0; + return rc; + } + } + return getPageNormal(pPager, pgno, ppPage, flags); +} +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + +/* The page getter method for when the pager is an error state */ +static int getPageError( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int flags /* PAGER_GET_XXX flags */ +){ + UNUSED_PARAMETER(pgno); + UNUSED_PARAMETER(flags); + assert( pPager->errCode!=SQLITE_OK ); + *ppPage = 0; + return pPager->errCode; +} + + +/* Dispatch all page fetch requests to the appropriate getter method. +*/ +SQLITE_PRIVATE int sqlite3PagerGet( + Pager *pPager, /* The pager open on the database file */ + Pgno pgno, /* Page number to fetch */ + DbPage **ppPage, /* Write a pointer to the page here */ + int flags /* PAGER_GET_XXX flags */ +){ + return pPager->xGet(pPager, pgno, ppPage, flags); +} + +/* +** Acquire a page if it is already in the in-memory cache. Do +** not read the page from disk. Return a pointer to the page, +** or 0 if the page is not in cache. +** +** See also sqlite3PagerGet(). The difference between this routine +** and sqlite3PagerGet() is that _get() will go to the disk and read +** in the page if the page is not already in cache. This routine +** returns NULL if the page is not in cache or if a disk I/O error +** has ever happened. +*/ +SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ + sqlite3_pcache_page *pPage; + assert( pPager!=0 ); + assert( pgno!=0 ); + assert( pPager->pPCache!=0 ); + pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0); + assert( pPage==0 || pPager->hasHeldSharedLock ); + if( pPage==0 ) return 0; + return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage); +} + +/* +** 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. +*/ +SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){ + Pager *pPager; + assert( pPg!=0 ); + pPager = pPg->pPager; + if( pPg->flags & PGHDR_MMAP ){ + pagerReleaseMapPage(pPg); + }else{ + sqlite3PcacheRelease(pPg); + } + pagerUnlockIfUnused(pPager); +} +SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){ + if( pPg ) sqlite3PagerUnrefNotNull(pPg); +} + +/* +** This function is called at the start of every write transaction. +** There must already be a RESERVED or EXCLUSIVE lock on the database +** file when this routine is called. +** +** Open the journal file for pager pPager and write a journal header +** to the start of it. If there are active savepoints, open the sub-journal +** as well. This function is only used when the journal file is being +** opened to write a rollback log for a transaction. It is not used +** when opening a hot journal file to roll it back. +** +** If the journal file is already open (as it may be in exclusive mode), +** then this function just writes a journal header to the start of the +** already open file. +** +** Whether or not the journal file is opened by this function, the +** Pager.pInJournal bitvec structure is allocated. +** +** Return SQLITE_OK if everything is successful. Otherwise, return +** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or +** an IO error code if opening or writing the journal file fails. +*/ +static int pager_open_journal(Pager *pPager){ + int rc = SQLITE_OK; /* Return code */ + sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */ + + assert( pPager->eState==PAGER_WRITER_LOCKED ); + assert( assert_pager_state(pPager) ); + assert( pPager->pInJournal==0 ); + + /* If already in the error state, this function is a no-op. But on + ** the other hand, this routine is never called if we are already in + ** an error state. */ + if( NEVER(pPager->errCode) ) return pPager->errCode; + + if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ + pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize); + if( pPager->pInJournal==0 ){ + return SQLITE_NOMEM_BKPT; + } + + /* Open the journal file if it is not already open. */ + if( !isOpen(pPager->jfd) ){ + if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){ + sqlite3MemJournalOpen(pPager->jfd); + }else{ + int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; + int nSpill; + + if( pPager->tempFile ){ + flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); + nSpill = sqlite3Config.nStmtSpill; + }else{ + flags |= SQLITE_OPEN_MAIN_JOURNAL; + nSpill = jrnlBufferSize(pPager); + } + + /* Verify that the database still has the same name as it did when + ** it was originally opened. */ + rc = databaseIsUnmoved(pPager); + if( rc==SQLITE_OK ){ + rc = sqlite3JournalOpen ( + pVfs, pPager->zJournal, pPager->jfd, flags, nSpill + ); + } + } + assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); + } + + + /* Write the first journal header to the journal file and open + ** the sub-journal if necessary. + */ + if( rc==SQLITE_OK ){ + /* TODO: Check if all of these are really required. */ + pPager->nRec = 0; + pPager->journalOff = 0; + pPager->setMaster = 0; + pPager->journalHdr = 0; + rc = writeJournalHdr(pPager); + } + } + + if( rc!=SQLITE_OK ){ + sqlite3BitvecDestroy(pPager->pInJournal); + pPager->pInJournal = 0; + }else{ + assert( pPager->eState==PAGER_WRITER_LOCKED ); + pPager->eState = PAGER_WRITER_CACHEMOD; + } + + return rc; +} + +/* +** Begin a write-transaction on the specified pager object. If a +** write-transaction has already been opened, this function is a no-op. +** +** If the exFlag argument is false, then acquire at least a RESERVED +** lock on the database file. If exFlag is true, then acquire at least +** an EXCLUSIVE lock. If such a lock is already held, no locking +** functions need be called. +** +** If the subjInMemory argument is non-zero, then any sub-journal opened +** within this transaction will be opened as an in-memory file. This +** has no effect if the sub-journal is already opened (as it may be when +** running in exclusive mode) or if the transaction does not require a +** sub-journal. If the subjInMemory argument is zero, then any required +** sub-journal is implemented in-memory if pPager is an in-memory database, +** or using a temporary file otherwise. +*/ +SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){ + int rc = SQLITE_OK; + + if( pPager->errCode ) return pPager->errCode; + assert( pPager->eState>=PAGER_READER && pPager->eStatesubjInMemory = (u8)subjInMemory; + + if( ALWAYS(pPager->eState==PAGER_READER) ){ + assert( pPager->pInJournal==0 ); + + if( pagerUseWal(pPager) ){ + /* If the pager is configured to use locking_mode=exclusive, and an + ** exclusive lock on the database is not already held, obtain it now. + */ + if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ + rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); + if( rc!=SQLITE_OK ){ + return rc; + } + (void)sqlite3WalExclusiveMode(pPager->pWal, 1); + } + + /* Grab the write lock on the log file. If successful, upgrade to + ** PAGER_RESERVED state. Otherwise, return an error code to the caller. + ** The busy-handler is not invoked if another connection already + ** holds the write-lock. If possible, the upper layer will call it. + */ + rc = sqlite3WalBeginWriteTransaction(pPager->pWal); + }else{ + /* Obtain a RESERVED lock on the database file. If the exFlag parameter + ** is true, then immediately upgrade this to an EXCLUSIVE lock. The + ** busy-handler callback can be used when upgrading to the EXCLUSIVE + ** lock, but not when obtaining the RESERVED lock. + */ + rc = pagerLockDb(pPager, RESERVED_LOCK); + if( rc==SQLITE_OK && exFlag ){ + rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); + } + } + + if( rc==SQLITE_OK ){ + /* Change to WRITER_LOCKED state. + ** + ** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD + ** when it has an open transaction, but never to DBMOD or FINISHED. + ** This is because in those states the code to roll back savepoint + ** transactions may copy data from the sub-journal into the database + ** file as well as into the page cache. Which would be incorrect in + ** WAL mode. + */ + pPager->eState = PAGER_WRITER_LOCKED; + pPager->dbHintSize = pPager->dbSize; + pPager->dbFileSize = pPager->dbSize; + pPager->dbOrigSize = pPager->dbSize; + pPager->journalOff = 0; + } + + assert( rc==SQLITE_OK || pPager->eState==PAGER_READER ); + assert( rc!=SQLITE_OK || pPager->eState==PAGER_WRITER_LOCKED ); + assert( assert_pager_state(pPager) ); + } + + PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager))); + return rc; +} + +/* +** Write page pPg onto the end of the rollback journal. +*/ +static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + int rc; + u32 cksum; + char *pData2; + i64 iOff = pPager->journalOff; + + /* We should never write to the journal file the page that + ** contains the database locks. The following assert verifies + ** that we do not. */ + assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); + + assert( pPager->journalHdr<=pPager->journalOff ); + CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + cksum = pager_cksum(pPager, (u8*)pData2); + + /* Even if an IO or diskfull error occurs while journalling the + ** page in the block above, set the need-sync flag for the page. + ** Otherwise, when the transaction is rolled back, the logic in + ** playback_one_page() will think that the page needs to be restored + ** in the database file. And if an IO error occurs while doing so, + ** then corruption may follow. + */ + pPg->flags |= PGHDR_NEED_SYNC; + + rc = write32bits(pPager->jfd, iOff, pPg->pgno); + if( rc!=SQLITE_OK ) return rc; + rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, iOff+4); + if( rc!=SQLITE_OK ) return rc; + rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum); + if( rc!=SQLITE_OK ) return rc; + + IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, + pPager->journalOff, pPager->pageSize)); + PAGER_INCR(sqlite3_pager_writej_count); + PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n", + PAGERID(pPager), pPg->pgno, + ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg))); + + pPager->journalOff += 8 + pPager->pageSize; + pPager->nRec++; + assert( pPager->pInJournal!=0 ); + rc = sqlite3BitvecSet(pPager->pInJournal, pPg->pgno); + testcase( rc==SQLITE_NOMEM ); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + rc |= addToSavepointBitvecs(pPager, pPg->pgno); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + return rc; +} + +/* +** Mark a single data page as writeable. The page is written into the +** main journal or sub-journal as required. If the page is written into +** one of the journals, the corresponding bit is set in the +** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs +** of any open savepoints as appropriate. +*/ +static int pager_write(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + int rc = SQLITE_OK; + + /* This routine is not called unless a write-transaction has already + ** been started. The journal file may or may not be open at this point. + ** It is never called in the ERROR state. + */ + assert( pPager->eState==PAGER_WRITER_LOCKED + || pPager->eState==PAGER_WRITER_CACHEMOD + || pPager->eState==PAGER_WRITER_DBMOD + ); + assert( assert_pager_state(pPager) ); + assert( pPager->errCode==0 ); + assert( pPager->readOnly==0 ); + CHECK_PAGE(pPg); + + /* The journal file needs to be opened. Higher level routines have already + ** obtained the necessary locks to begin the write-transaction, but the + ** rollback journal might not yet be open. Open it now if this is the case. + ** + ** This is done before calling sqlite3PcacheMakeDirty() on the page. + ** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then + ** an error might occur and the pager would end up in WRITER_LOCKED state + ** with pages marked as dirty in the cache. + */ + if( pPager->eState==PAGER_WRITER_LOCKED ){ + rc = pager_open_journal(pPager); + if( rc!=SQLITE_OK ) return rc; + } + assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); + assert( assert_pager_state(pPager) ); + + /* Mark the page that is about to be modified as dirty. */ + sqlite3PcacheMakeDirty(pPg); + + /* If a rollback journal is in use, them make sure the page that is about + ** to change is in the rollback journal, or if the page is a new page off + ** then end of the file, make sure it is marked as PGHDR_NEED_SYNC. + */ + assert( (pPager->pInJournal!=0) == isOpen(pPager->jfd) ); + if( pPager->pInJournal!=0 + && sqlite3BitvecTestNotNull(pPager->pInJournal, pPg->pgno)==0 + ){ + assert( pagerUseWal(pPager)==0 ); + if( pPg->pgno<=pPager->dbOrigSize ){ + rc = pagerAddPageToRollbackJournal(pPg); + if( rc!=SQLITE_OK ){ + return rc; + } + }else{ + if( pPager->eState!=PAGER_WRITER_DBMOD ){ + pPg->flags |= PGHDR_NEED_SYNC; + } + PAGERTRACE(("APPEND %d page %d needSync=%d\n", + PAGERID(pPager), pPg->pgno, + ((pPg->flags&PGHDR_NEED_SYNC)?1:0))); + } + } + + /* The PGHDR_DIRTY bit is set above when the page was added to the dirty-list + ** and before writing the page into the rollback journal. Wait until now, + ** after the page has been successfully journalled, before setting the + ** PGHDR_WRITEABLE bit that indicates that the page can be safely modified. + */ + pPg->flags |= PGHDR_WRITEABLE; + + /* If the statement journal is open and the page is not in it, + ** then write the page into the statement journal. + */ + if( pPager->nSavepoint>0 ){ + rc = subjournalPageIfRequired(pPg); + } + + /* Update the database size and return. */ + if( pPager->dbSizepgno ){ + pPager->dbSize = pPg->pgno; + } + return rc; +} + +/* +** This is a variant of sqlite3PagerWrite() that runs when the sector size +** is larger than the page size. SQLite makes the (reasonable) assumption that +** all bytes of a sector are written together by hardware. Hence, all bytes of +** a sector need to be journalled in case of a power loss in the middle of +** a write. +** +** Usually, the sector size is less than or equal to the page size, in which +** case pages can be individually written. This routine only runs in the +** exceptional case where the page size is smaller than the sector size. +*/ +static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){ + int rc = SQLITE_OK; /* Return code */ + Pgno nPageCount; /* Total number of pages in database file */ + Pgno pg1; /* First page of the sector pPg is located on. */ + int nPage = 0; /* Number of pages starting at pg1 to journal */ + int ii; /* Loop counter */ + int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */ + Pager *pPager = pPg->pPager; /* The pager that owns pPg */ + Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); + + /* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow + ** a journal header to be written between the pages journaled by + ** this function. + */ + assert( !MEMDB ); + assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 ); + pPager->doNotSpill |= SPILLFLAG_NOSYNC; + + /* This trick assumes that both the page-size and sector-size are + ** an integer power of 2. It sets variable pg1 to the identifier + ** of the first page of the sector pPg is located on. + */ + pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1; + + nPageCount = pPager->dbSize; + if( pPg->pgno>nPageCount ){ + nPage = (pPg->pgno - pg1)+1; + }else if( (pg1+nPagePerSector-1)>nPageCount ){ + nPage = nPageCount+1-pg1; + }else{ + nPage = nPagePerSector; + } + assert(nPage>0); + assert(pg1<=pPg->pgno); + assert((pg1+nPage)>pPg->pgno); + + for(ii=0; iipgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ + if( pg!=PAGER_MJ_PGNO(pPager) ){ + rc = sqlite3PagerGet(pPager, pg, &pPage, 0); + if( rc==SQLITE_OK ){ + rc = pager_write(pPage); + if( pPage->flags&PGHDR_NEED_SYNC ){ + needSync = 1; + } + sqlite3PagerUnrefNotNull(pPage); + } + } + }else if( (pPage = sqlite3PagerLookup(pPager, pg))!=0 ){ + if( pPage->flags&PGHDR_NEED_SYNC ){ + needSync = 1; + } + sqlite3PagerUnrefNotNull(pPage); + } + } + + /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages + ** starting at pg1, then it needs to be set for all of them. Because + ** writing to any of these nPage pages may damage the others, the + ** journal file must contain sync()ed copies of all of them + ** before any of them can be written out to the database file. + */ + if( rc==SQLITE_OK && needSync ){ + assert( !MEMDB ); + for(ii=0; iiflags |= PGHDR_NEED_SYNC; + sqlite3PagerUnrefNotNull(pPage); + } + } + } + + assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 ); + pPager->doNotSpill &= ~SPILLFLAG_NOSYNC; + return rc; +} + +/* +** Mark a data page as writeable. This routine must be called before +** making changes to a page. The caller must check the return value +** of this function and be careful not to change any page data unless +** this routine returns SQLITE_OK. +** +** The difference between this function and pager_write() is that this +** function also deals with the special case where 2 or more pages +** fit on a single disk sector. In this case all co-resident pages +** must have been written to the journal file before returning. +** +** If an error occurs, SQLITE_NOMEM or an IO error code is returned +** as appropriate. Otherwise, SQLITE_OK. +*/ +SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + assert( (pPg->flags & PGHDR_MMAP)==0 ); + assert( pPager->eState>=PAGER_WRITER_LOCKED ); + assert( assert_pager_state(pPager) ); + if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){ + if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg); + return SQLITE_OK; + }else if( pPager->errCode ){ + return pPager->errCode; + }else if( pPager->sectorSize > (u32)pPager->pageSize ){ + assert( pPager->tempFile==0 ); + return pagerWriteLargeSector(pPg); + }else{ + return pager_write(pPg); + } +} + +/* +** Return TRUE if the page given in the argument was previously passed +** to sqlite3PagerWrite(). In other words, return TRUE if it is ok +** to change the content of the page. +*/ +#ifndef NDEBUG +SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){ + return pPg->flags & PGHDR_WRITEABLE; +} +#endif + +/* +** A call to this routine tells the pager that it is not necessary to +** write the information on page pPg back to the disk, even though +** that page might be marked as dirty. This happens, for example, when +** the page has been added as a leaf of the freelist and so its +** content no longer matters. +** +** The overlying software layer calls this routine when all of the data +** on the given page is unused. The pager marks the page as clean so +** that it does not get written to disk. +** +** Tests show that this optimization can quadruple the speed of large +** DELETE operations. +** +** This optimization cannot be used with a temp-file, as the page may +** have been dirty at the start of the transaction. In that case, if +** memory pressure forces page pPg out of the cache, the data does need +** to be written out to disk so that it may be read back in if the +** current transaction is rolled back. +*/ +SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){ + PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager))); + IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) + pPg->flags |= PGHDR_DONT_WRITE; + pPg->flags &= ~PGHDR_WRITEABLE; + testcase( pPg->flags & PGHDR_NEED_SYNC ); + pager_set_pagehash(pPg); + } +} + +/* +** This routine is called to increment the value of the database file +** change-counter, stored as a 4-byte big-endian integer starting at +** byte offset 24 of the pager file. The secondary change counter at +** 92 is also updated, as is the SQLite version number at offset 96. +** +** But this only happens if the pPager->changeCountDone flag is false. +** To avoid excess churning of page 1, the update only happens once. +** See also the pager_write_changecounter() routine that does an +** unconditional update of the change counters. +** +** If the isDirectMode flag is zero, then this is done by calling +** sqlite3PagerWrite() on page 1, then modifying the contents of the +** page data. In this case the file will be updated when the current +** transaction is committed. +** +** The isDirectMode flag may only be non-zero if the library was compiled +** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case, +** if isDirect is non-zero, then the database file is updated directly +** by writing an updated version of page 1 using a call to the +** sqlite3OsWrite() function. +*/ +static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ + int rc = SQLITE_OK; + + assert( pPager->eState==PAGER_WRITER_CACHEMOD + || pPager->eState==PAGER_WRITER_DBMOD + ); + assert( assert_pager_state(pPager) ); + + /* Declare and initialize constant integer 'isDirect'. If the + ** atomic-write optimization is enabled in this build, then isDirect + ** is initialized to the value passed as the isDirectMode parameter + ** to this function. Otherwise, it is always set to zero. + ** + ** The idea is that if the atomic-write optimization is not + ** enabled at compile time, the compiler can omit the tests of + ** 'isDirect' below, as well as the block enclosed in the + ** "if( isDirect )" condition. + */ +#ifndef SQLITE_ENABLE_ATOMIC_WRITE +# define DIRECT_MODE 0 + assert( isDirectMode==0 ); + UNUSED_PARAMETER(isDirectMode); +#else +# define DIRECT_MODE isDirectMode +#endif + + if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){ + PgHdr *pPgHdr; /* Reference to page 1 */ + + assert( !pPager->tempFile && isOpen(pPager->fd) ); + + /* Open page 1 of the file for writing. */ + rc = sqlite3PagerGet(pPager, 1, &pPgHdr, 0); + assert( pPgHdr==0 || rc==SQLITE_OK ); + + /* If page one was fetched successfully, and this function is not + ** operating in direct-mode, make page 1 writable. When not in + ** direct mode, page 1 is always held in cache and hence the PagerGet() + ** above is always successful - hence the ALWAYS on rc==SQLITE_OK. + */ + if( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){ + rc = sqlite3PagerWrite(pPgHdr); + } + + if( rc==SQLITE_OK ){ + /* Actually do the update of the change counter */ + pager_write_changecounter(pPgHdr); + + /* If running in direct mode, write the contents of page 1 to the file. */ + if( DIRECT_MODE ){ + const void *zBuf; + assert( pPager->dbFileSize>0 ); + CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); + pPager->aStat[PAGER_STAT_WRITE]++; + } + if( rc==SQLITE_OK ){ + /* Update the pager's copy of the change-counter. Otherwise, the + ** next time a read transaction is opened the cache will be + ** flushed (as the change-counter values will not match). */ + const void *pCopy = (const void *)&((const char *)zBuf)[24]; + memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers)); + pPager->changeCountDone = 1; + } + }else{ + pPager->changeCountDone = 1; + } + } + + /* Release the page reference. */ + sqlite3PagerUnref(pPgHdr); + } + return rc; +} + +/* +** Sync the database file to disk. This is a no-op for in-memory databases +** or pages with the Pager.noSync flag set. +** +** If successful, or if called on a pager for which it is a no-op, this +** function returns SQLITE_OK. Otherwise, an IO error code is returned. +*/ +SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){ + int rc = SQLITE_OK; + + if( isOpen(pPager->fd) ){ + void *pArg = (void*)zMaster; + rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg); + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; + } + if( rc==SQLITE_OK && !pPager->noSync ){ + assert( !MEMDB ); + rc = sqlite3OsSync(pPager->fd, pPager->syncFlags); + } + return rc; +} + +/* +** This function may only be called while a write-transaction is active in +** rollback. If the connection is in WAL mode, this call is a no-op. +** Otherwise, if the connection does not already have an EXCLUSIVE lock on +** the database file, an attempt is made to obtain one. +** +** If the EXCLUSIVE lock is already held or the attempt to obtain it is +** successful, or the connection is in WAL mode, SQLITE_OK is returned. +** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is +** returned. +*/ +SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){ + int rc = pPager->errCode; + assert( assert_pager_state(pPager) ); + if( rc==SQLITE_OK ){ + assert( pPager->eState==PAGER_WRITER_CACHEMOD + || pPager->eState==PAGER_WRITER_DBMOD + || pPager->eState==PAGER_WRITER_LOCKED + ); + assert( assert_pager_state(pPager) ); + if( 0==pagerUseWal(pPager) ){ + rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); + } + } + return rc; +} + +/* +** Sync the database file for the pager pPager. zMaster points to the name +** of a master journal file that should be written into the individual +** journal file. zMaster may be NULL, which is interpreted as no master +** journal (a single database transaction). +** +** This routine ensures that: +** +** * The database file change-counter is updated, +** * the journal is synced (unless the atomic-write optimization is used), +** * all dirty pages are written to the database file, +** * the database file is truncated (if required), and +** * the database file synced. +** +** The only thing that remains to commit the transaction is to finalize +** (delete, truncate or zero the first part of) the journal file (or +** delete the master journal file if specified). +** +** Note that if zMaster==NULL, this does not overwrite a previous value +** passed to an sqlite3PagerCommitPhaseOne() call. +** +** If the final parameter - noSync - is true, then the database file itself +** is not synced. The caller must call sqlite3PagerSync() directly to +** sync the database file before calling CommitPhaseTwo() to delete the +** journal file in this case. +*/ +SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( + Pager *pPager, /* Pager object */ + const char *zMaster, /* If not NULL, the master journal name */ + int noSync /* True to omit the xSync on the db file */ +){ + int rc = SQLITE_OK; /* Return code */ + + assert( pPager->eState==PAGER_WRITER_LOCKED + || pPager->eState==PAGER_WRITER_CACHEMOD + || pPager->eState==PAGER_WRITER_DBMOD + || pPager->eState==PAGER_ERROR + ); + assert( assert_pager_state(pPager) ); + + /* If a prior error occurred, report that error again. */ + if( NEVER(pPager->errCode) ) return pPager->errCode; + + /* Provide the ability to easily simulate an I/O error during testing */ + if( sqlite3FaultSim(400) ) return SQLITE_IOERR; + + PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", + pPager->zFilename, zMaster, pPager->dbSize)); + + /* If no database changes have been made, return early. */ + if( pPager->eStatetempFile ); + assert( isOpen(pPager->fd) || pPager->tempFile ); + if( 0==pagerFlushOnCommit(pPager, 1) ){ + /* If this is an in-memory db, or no pages have been written to, or this + ** function has already been called, it is mostly a no-op. However, any + ** backup in progress needs to be restarted. */ + sqlite3BackupRestart(pPager->pBackup); + }else{ + if( pagerUseWal(pPager) ){ + PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); + PgHdr *pPageOne = 0; + if( pList==0 ){ + /* Must have at least one page for the WAL commit flag. + ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ + rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0); + pList = pPageOne; + pList->pDirty = 0; + } + assert( rc==SQLITE_OK ); + if( ALWAYS(pList) ){ + rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1); + } + sqlite3PagerUnref(pPageOne); + if( rc==SQLITE_OK ){ + sqlite3PcacheCleanAll(pPager->pPCache); + } + }else{ + /* The following block updates the change-counter. Exactly how it + ** does this depends on whether or not the atomic-update optimization + ** was enabled at compile time, and if this transaction meets the + ** runtime criteria to use the operation: + ** + ** * The file-system supports the atomic-write property for + ** blocks of size page-size, and + ** * This commit is not part of a multi-file transaction, and + ** * Exactly one page has been modified and store in the journal file. + ** + ** If the optimization was not enabled at compile time, then the + ** pager_incr_changecounter() function is called to update the change + ** counter in 'indirect-mode'. If the optimization is compiled in but + ** is not applicable to this transaction, call sqlite3JournalCreate() + ** to make sure the journal file has actually been created, then call + ** pager_incr_changecounter() to update the change-counter in indirect + ** mode. + ** + ** Otherwise, if the optimization is both enabled and applicable, + ** then call pager_incr_changecounter() to update the change-counter + ** 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); + } + } + #else + rc = pager_incr_changecounter(pPager, 0); + #endif + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + + /* Write the master journal name into the journal file. If a master + ** journal file name has already been written to the journal file, + ** or if zMaster is NULL (no master journal), then this call is a no-op. + */ + rc = writeMasterJournal(pPager, zMaster); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + + /* Sync the journal file and write all dirty pages to the database. + ** If the atomic-update optimization is being used, this sync will not + ** create the journal file or perform any real IO. + ** + ** Because the change-counter page was just modified, unless the + ** atomic-update optimization is used it is almost certain that the + ** journal requires a sync here. However, in locking_mode=exclusive + ** on a system under memory pressure it is just possible that this is + ** not the case. In this case it is likely enough that the redundant + ** xSync() call will be changed to a no-op by the OS anyhow. + */ + rc = syncJournal(pPager, 0); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + + rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache)); + if( rc!=SQLITE_OK ){ + assert( rc!=SQLITE_IOERR_BLOCKED ); + goto commit_phase_one_exit; + } + sqlite3PcacheCleanAll(pPager->pPCache); + + /* If the file on disk is smaller than the database image, use + ** pager_truncate to grow the file here. This can happen if the database + ** image was extended as part of the current transaction and then the + ** last page in the db image moved to the free-list. In this case the + ** last page is never written out to disk, leaving the database file + ** undersized. Fix this now if it is the case. */ + if( pPager->dbSize>pPager->dbFileSize ){ + Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager)); + assert( pPager->eState==PAGER_WRITER_DBMOD ); + rc = pager_truncate(pPager, nNew); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + } + + /* Finally, sync the database file. */ + if( !noSync ){ + rc = sqlite3PagerSync(pPager, zMaster); + } + IOTRACE(("DBSYNC %p\n", pPager)) + } + } + +commit_phase_one_exit: + if( rc==SQLITE_OK && !pagerUseWal(pPager) ){ + pPager->eState = PAGER_WRITER_FINISHED; + } + return rc; +} + + +/* +** When this function is called, the database file has been completely +** updated to reflect the changes made by the current transaction and +** synced to disk. The journal file still exists in the file-system +** though, and if a failure occurs at this point it will eventually +** be used as a hot-journal and the current transaction rolled back. +** +** This function finalizes the journal file, either by deleting, +** truncating or partially zeroing it, so that it cannot be used +** for hot-journal rollback. Once this is done the transaction is +** irrevocably committed. +** +** If an error occurs, an IO error code is returned and the pager +** moves into the error state. Otherwise, SQLITE_OK is returned. +*/ +SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ + int rc = SQLITE_OK; /* Return code */ + + /* This routine should not be called if a prior error has occurred. + ** But if (due to a coding error elsewhere in the system) it does get + ** called, just return the same error code without doing anything. */ + if( NEVER(pPager->errCode) ) return pPager->errCode; + + assert( pPager->eState==PAGER_WRITER_LOCKED + || pPager->eState==PAGER_WRITER_FINISHED + || (pagerUseWal(pPager) && pPager->eState==PAGER_WRITER_CACHEMOD) + ); + assert( assert_pager_state(pPager) ); + + /* An optimization. If the database was not actually modified during + ** this transaction, the pager is running in exclusive-mode and is + ** using persistent journals, then this function is a no-op. + ** + ** The start of the journal file currently contains a single journal + ** header with the nRec field set to 0. If such a journal is used as + ** a hot-journal during hot-journal rollback, 0 changes will be made + ** to the database file. So there is no need to zero the journal + ** header. Since the pager is in exclusive mode, there is no need + ** to drop any locks either. + */ + if( pPager->eState==PAGER_WRITER_LOCKED + && pPager->exclusiveMode + && pPager->journalMode==PAGER_JOURNALMODE_PERSIST + ){ + assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); + pPager->eState = PAGER_READER; + return SQLITE_OK; + } + + PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); + pPager->iDataVersion++; + rc = pager_end_transaction(pPager, pPager->setMaster, 1); + return pager_error(pPager, rc); +} + +/* +** If a write transaction is open, then all changes made within the +** transaction are reverted and the current write-transaction is closed. +** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR +** state if an error occurs. +** +** If the pager is already in PAGER_ERROR state when this function is called, +** it returns Pager.errCode immediately. No work is performed in this case. +** +** Otherwise, in rollback mode, this function performs two functions: +** +** 1) It rolls back the journal file, restoring all database file and +** in-memory cache pages to the state they were in when the transaction +** was opened, and +** +** 2) It finalizes the journal file, so that it is not used for hot +** rollback at any point in the future. +** +** Finalization of the journal file (task 2) is only performed if the +** rollback is successful. +** +** In WAL mode, all cache-entries containing data modified within the +** current transaction are either expelled from the cache or reverted to +** their pre-transaction state by re-reading data from the database or +** WAL files. The WAL transaction is then closed. +*/ +SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){ + int rc = SQLITE_OK; /* Return code */ + PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager))); + + /* PagerRollback() is a no-op if called in READER or OPEN state. If + ** the pager is already in the ERROR state, the rollback is not + ** attempted here. Instead, the error code is returned to the caller. + */ + assert( assert_pager_state(pPager) ); + if( pPager->eState==PAGER_ERROR ) return pPager->errCode; + if( pPager->eState<=PAGER_READER ) return SQLITE_OK; + + if( pagerUseWal(pPager) ){ + int rc2; + rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); + rc2 = pager_end_transaction(pPager, pPager->setMaster, 0); + if( rc==SQLITE_OK ) rc = rc2; + }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){ + int eState = pPager->eState; + rc = pager_end_transaction(pPager, 0, 0); + if( !MEMDB && eState>PAGER_WRITER_LOCKED ){ + /* This can happen using journal_mode=off. Move the pager to the error + ** state to indicate that the contents of the cache may not be trusted. + ** Any active readers will get SQLITE_ABORT. + */ + pPager->errCode = SQLITE_ABORT; + pPager->eState = PAGER_ERROR; + setGetterMethod(pPager); + return rc; + } + }else{ + rc = pager_playback(pPager, 0); + } + + assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); + assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT + || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR + || rc==SQLITE_CANTOPEN + ); + + /* If an error occurs during a ROLLBACK, we can no longer trust the pager + ** cache. So call pager_error() on the way out to make any error persistent. + */ + return pager_error(pPager, rc); +} + +/* +** Return TRUE if the database file is opened read-only. Return FALSE +** if the database is (in theory) writable. +*/ +SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){ + return pPager->readOnly; +} + +#ifdef SQLITE_DEBUG +/* +** Return the sum of the reference counts for all pages held by pPager. +*/ +SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){ + return sqlite3PcacheRefCount(pPager->pPCache); +} +#endif + +/* +** Return the approximate number of bytes of memory currently +** used by the pager and its associated cache. +*/ +SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){ + int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr) + + 5*sizeof(void*); + return perPageSize*sqlite3PcachePagecount(pPager->pPCache) + + sqlite3MallocSize(pPager) + + pPager->pageSize; +} + +/* +** Return the number of references to the specified page. +*/ +SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){ + return sqlite3PcachePageRefcount(pPage); +} + +#ifdef SQLITE_TEST +/* +** This routine is used for testing and analysis only. +*/ +SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){ + static int a[11]; + a[0] = sqlite3PcacheRefCount(pPager->pPCache); + a[1] = sqlite3PcachePagecount(pPager->pPCache); + a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); + a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize; + a[4] = pPager->eState; + a[5] = pPager->errCode; + a[6] = pPager->aStat[PAGER_STAT_HIT]; + a[7] = pPager->aStat[PAGER_STAT_MISS]; + a[8] = 0; /* Used to be pPager->nOvfl */ + a[9] = pPager->nRead; + a[10] = pPager->aStat[PAGER_STAT_WRITE]; + return a; +} +#endif + +/* +** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or +** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the +** current cache hit or miss count, according to the value of eStat. If the +** reset parameter is non-zero, the cache hit or miss count is zeroed before +** returning. +*/ +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ + + assert( eStat==SQLITE_DBSTATUS_CACHE_HIT + || eStat==SQLITE_DBSTATUS_CACHE_MISS + || eStat==SQLITE_DBSTATUS_CACHE_WRITE + ); + + assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS ); + assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE ); + assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 ); + + *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT]; + if( reset ){ + pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0; + } +} + +/* +** Return true if this is an in-memory or temp-file backed pager. +*/ +SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){ + return pPager->tempFile; +} + +/* +** Check that there are at least nSavepoint savepoints open. If there are +** currently less than nSavepoints open, then open one or more savepoints +** to make up the difference. If the number of savepoints is already +** equal to nSavepoint, then this function is a no-op. +** +** If a memory allocation fails, SQLITE_NOMEM is returned. If an error +** occurs while opening the sub-journal file, then an IO error code is +** returned. Otherwise, SQLITE_OK. +*/ +static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){ + int rc = SQLITE_OK; /* Return code */ + int nCurrent = pPager->nSavepoint; /* Current number of savepoints */ + int ii; /* Iterator variable */ + PagerSavepoint *aNew; /* New Pager.aSavepoint array */ + + assert( pPager->eState>=PAGER_WRITER_LOCKED ); + assert( assert_pager_state(pPager) ); + assert( nSavepoint>nCurrent && pPager->useJournal ); + + /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM + ** if the allocation fails. Otherwise, zero the new portion in case a + ** malloc failure occurs while populating it in the for(...) loop below. + */ + aNew = (PagerSavepoint *)sqlite3Realloc( + pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint + ); + if( !aNew ){ + return SQLITE_NOMEM_BKPT; + } + memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint)); + pPager->aSavepoint = aNew; + + /* Populate the PagerSavepoint structures just allocated. */ + for(ii=nCurrent; iidbSize; + if( isOpen(pPager->jfd) && pPager->journalOff>0 ){ + aNew[ii].iOffset = pPager->journalOff; + }else{ + aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager); + } + aNew[ii].iSubRec = pPager->nSubRec; + aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize); + if( !aNew[ii].pInSavepoint ){ + return SQLITE_NOMEM_BKPT; + } + if( pagerUseWal(pPager) ){ + sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData); + } + pPager->nSavepoint = ii+1; + } + assert( pPager->nSavepoint==nSavepoint ); + assertTruncateConstraint(pPager); + return rc; +} +SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){ + assert( pPager->eState>=PAGER_WRITER_LOCKED ); + assert( assert_pager_state(pPager) ); + + if( nSavepoint>pPager->nSavepoint && pPager->useJournal ){ + return pagerOpenSavepoint(pPager, nSavepoint); + }else{ + return SQLITE_OK; + } +} + + +/* +** This function is called to rollback or release (commit) a savepoint. +** The savepoint to release or rollback need not be the most recently +** created savepoint. +** +** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE. +** If it is SAVEPOINT_RELEASE, then release and destroy the savepoint with +** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes +** that have occurred since the specified savepoint was created. +** +** The savepoint to rollback or release is identified by parameter +** iSavepoint. A value of 0 means to operate on the outermost savepoint +** (the first created). A value of (Pager.nSavepoint-1) means operate +** on the most recently created savepoint. If iSavepoint is greater than +** (Pager.nSavepoint-1), then this function is a no-op. +** +** If a negative value is passed to this function, then the current +** transaction is rolled back. This is different to calling +** sqlite3PagerRollback() because this function does not terminate +** the transaction or unlock the database, it just restores the +** contents of the database to its original state. +** +** In any case, all savepoints with an index greater than iSavepoint +** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE), +** then savepoint iSavepoint is also destroyed. +** +** This function may return SQLITE_NOMEM if a memory allocation fails, +** or an IO error code if an IO error occurs while rolling back a +** savepoint. If no errors occur, SQLITE_OK is returned. +*/ +SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ + int rc = pPager->errCode; + +#ifdef SQLITE_ENABLE_ZIPVFS + if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK; +#endif + + assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); + assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK ); + + if( rc==SQLITE_OK && iSavepointnSavepoint ){ + int ii; /* Iterator variable */ + int nNew; /* Number of remaining savepoints after this op. */ + + /* Figure out how many savepoints will still be active after this + ** operation. Store this value in nNew. Then free resources associated + ** with any savepoints that are destroyed by this operation. + */ + nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1); + for(ii=nNew; iinSavepoint; ii++){ + sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); + } + pPager->nSavepoint = nNew; + + /* If this is a release of the outermost savepoint, truncate + ** the sub-journal to zero bytes in size. */ + if( op==SAVEPOINT_RELEASE ){ + if( nNew==0 && isOpen(pPager->sjfd) ){ + /* Only truncate if it is an in-memory sub-journal. */ + if( sqlite3JournalIsInMemory(pPager->sjfd) ){ + rc = sqlite3OsTruncate(pPager->sjfd, 0); + assert( rc==SQLITE_OK ); + } + pPager->nSubRec = 0; + } + } + /* Else this is a rollback operation, playback the specified savepoint. + ** If this is a temp-file, it is possible that the journal file has + ** not yet been opened. In this case there have been no changes to + ** the database file, so the playback operation can be skipped. + */ + else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){ + PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1]; + rc = pagerPlaybackSavepoint(pPager, pSavepoint); + assert(rc!=SQLITE_DONE); + } + +#ifdef SQLITE_ENABLE_ZIPVFS + /* If the cache has been modified but the savepoint cannot be rolled + ** back journal_mode=off, put the pager in the error state. This way, + ** if the VFS used by this pager includes ZipVFS, the entire transaction + ** can be rolled back at the ZipVFS level. */ + else if( + pPager->journalMode==PAGER_JOURNALMODE_OFF + && pPager->eState>=PAGER_WRITER_CACHEMOD + ){ + pPager->errCode = SQLITE_ABORT; + pPager->eState = PAGER_ERROR; + setGetterMethod(pPager); + } +#endif + } + + return rc; +} + +/* +** Return the full pathname of the database file. +** +** Except, if the pager is in-memory only, then return an empty string if +** nullIfMemDb is true. This routine is called with nullIfMemDb==1 when +** used to report the filename to the user, for compatibility with legacy +** behavior. But when the Btree needs to know the filename for matching to +** shared cache, it uses nullIfMemDb==0 so that in-memory databases can +** participate in shared-cache. +*/ +SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){ + return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename; +} + +/* +** Return the VFS structure for the pager. +*/ +SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){ + return pPager->pVfs; +} + +/* +** Return the file handle for the database file associated +** with the pager. This might return NULL if the file has +** not yet been opened. +*/ +SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ + return pPager->fd; +} + +/* +** Return the file handle for the journal file (if it exists). +** This will be either the rollback journal or the WAL file. +*/ +SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){ +#if SQLITE_OMIT_WAL + return pPager->jfd; +#else + return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd; +#endif +} + +/* +** Return the full pathname of the journal file. +*/ +SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ + return pPager->zJournal; +} + +#ifdef SQLITE_HAS_CODEC +/* +** Set or retrieve the codec for this pager +*/ +SQLITE_PRIVATE void sqlite3PagerSetCodec( + Pager *pPager, + void *(*xCodec)(void*,void*,Pgno,int), + void (*xCodecSizeChng)(void*,int,int), + void (*xCodecFree)(void*), + void *pCodec +){ + if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); + pPager->xCodec = pPager->memDb ? 0 : xCodec; + pPager->xCodecSizeChng = xCodecSizeChng; + pPager->xCodecFree = xCodecFree; + pPager->pCodec = pCodec; + setGetterMethod(pPager); + pagerReportSize(pPager); +} +SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){ + return pPager->pCodec; +} + +/* +** This function is called by the wal module when writing page content +** into the log file. +** +** This function returns a pointer to a buffer containing the encrypted +** page content. If a malloc fails, this function may return NULL. +*/ +SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){ + void *aData = 0; + CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); + return aData; +} + +/* +** Return the current pager state +*/ +SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){ + return pPager->eState; +} +#endif /* SQLITE_HAS_CODEC */ + +#ifndef SQLITE_OMIT_AUTOVACUUM +/* +** Move the page pPg to location pgno in the file. +** +** There must be no references to the page previously located at +** pgno (which we call pPgOld) though that page is allowed to be +** in cache. If the page previously located at pgno is not already +** in the rollback journal, it is not put there by by this routine. +** +** References to the page pPg remain valid. Updating any +** meta-data associated with pPg (i.e. data stored in the nExtra bytes +** allocated along with the page) is the responsibility of the caller. +** +** A transaction must be active when this routine is called. It used to be +** required that a statement transaction was not active, but this restriction +** has been removed (CREATE INDEX needs to move a page when a statement +** transaction is active). +** +** If the fourth argument, isCommit, is non-zero, then this page is being +** moved as part of a database reorganization just before the transaction +** is being committed. In this case, it is guaranteed that the database page +** pPg refers to will not be written to again within this transaction. +** +** This function may return SQLITE_NOMEM or an IO error code if an error +** occurs. Otherwise, it returns SQLITE_OK. +*/ +SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ + PgHdr *pPgOld; /* The page being overwritten. */ + Pgno needSyncPgno = 0; /* Old value of pPg->pgno, if sync is required */ + int rc; /* Return code */ + Pgno origPgno; /* The original page number */ + + assert( pPg->nRef>0 ); + assert( pPager->eState==PAGER_WRITER_CACHEMOD + || pPager->eState==PAGER_WRITER_DBMOD + ); + assert( assert_pager_state(pPager) ); + + /* In order to be able to rollback, an in-memory database must journal + ** the page we are moving from. + */ + assert( pPager->tempFile || !MEMDB ); + if( pPager->tempFile ){ + rc = sqlite3PagerWrite(pPg); + if( rc ) return rc; + } + + /* If the page being moved is dirty and has not been saved by the latest + ** savepoint, then save the current contents of the page into the + ** sub-journal now. This is required to handle the following scenario: + ** + ** BEGIN; + ** + ** SAVEPOINT one; + ** + ** ROLLBACK TO one; + ** + ** If page X were not written to the sub-journal here, it would not + ** be possible to restore its contents when the "ROLLBACK TO one" + ** statement were is processed. + ** + ** subjournalPage() may need to allocate space to store pPg->pgno into + ** one or more savepoint bitvecs. This is the reason this function + ** may return SQLITE_NOMEM. + */ + if( (pPg->flags & PGHDR_DIRTY)!=0 + && SQLITE_OK!=(rc = subjournalPageIfRequired(pPg)) + ){ + return rc; + } + + PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n", + PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno)); + IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno)) + + /* If the journal needs to be sync()ed before page pPg->pgno can + ** be written to, store pPg->pgno in local variable needSyncPgno. + ** + ** If the isCommit flag is set, there is no need to remember that + ** the journal needs to be sync()ed before database page pPg->pgno + ** can be written to. The caller has already promised not to write to it. + */ + if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){ + needSyncPgno = pPg->pgno; + assert( pPager->journalMode==PAGER_JOURNALMODE_OFF || + pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize ); + assert( pPg->flags&PGHDR_DIRTY ); + } + + /* If the cache contains a page with page-number pgno, remove it + ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for + ** page pgno before the 'move' operation, it needs to be retained + ** for the page moved there. + */ + pPg->flags &= ~PGHDR_NEED_SYNC; + pPgOld = sqlite3PagerLookup(pPager, pgno); + assert( !pPgOld || pPgOld->nRef==1 ); + if( pPgOld ){ + pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); + if( pPager->tempFile ){ + /* Do not discard pages from an in-memory database since we might + ** need to rollback later. Just move the page out of the way. */ + sqlite3PcacheMove(pPgOld, pPager->dbSize+1); + }else{ + sqlite3PcacheDrop(pPgOld); + } + } + + origPgno = pPg->pgno; + sqlite3PcacheMove(pPg, pgno); + sqlite3PcacheMakeDirty(pPg); + + /* For an in-memory database, make sure the original page continues + ** to exist, in case the transaction needs to roll back. Use pPgOld + ** as the original page since it has already been allocated. + */ + if( pPager->tempFile && pPgOld ){ + sqlite3PcacheMove(pPgOld, origPgno); + sqlite3PagerUnrefNotNull(pPgOld); + } + + if( needSyncPgno ){ + /* If needSyncPgno is non-zero, then the journal file needs to be + ** sync()ed before any data is written to database file page needSyncPgno. + ** Currently, no such page exists in the page-cache and the + ** "is journaled" bitvec flag has been set. This needs to be remedied by + ** loading the page into the pager-cache and setting the PGHDR_NEED_SYNC + ** flag. + ** + ** If the attempt to load the page into the page-cache fails, (due + ** to a malloc() or IO failure), clear the bit in the pInJournal[] + ** array. Otherwise, if the page is loaded and written again in + ** this transaction, it may be written to the database file before + ** it is synced into the journal file. This way, it may end up in + ** the journal file twice, but that is not a problem. + */ + PgHdr *pPgHdr; + rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr, 0); + if( rc!=SQLITE_OK ){ + if( needSyncPgno<=pPager->dbOrigSize ){ + assert( pPager->pTmpSpace!=0 ); + sqlite3BitvecClear(pPager->pInJournal, needSyncPgno, pPager->pTmpSpace); + } + return rc; + } + pPgHdr->flags |= PGHDR_NEED_SYNC; + sqlite3PcacheMakeDirty(pPgHdr); + sqlite3PagerUnrefNotNull(pPgHdr); + } + + return SQLITE_OK; +} +#endif + +/* +** The page handle passed as the first argument refers to a dirty page +** with a page number other than iNew. This function changes the page's +** page number to iNew and sets the value of the PgHdr.flags field to +** the value passed as the third parameter. +*/ +SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){ + assert( pPg->pgno!=iNew ); + pPg->flags = flags; + sqlite3PcacheMove(pPg, iNew); +} + +/* +** Return a pointer to the data for the specified page. +*/ +SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){ + assert( pPg->nRef>0 || pPg->pPager->memDb ); + return pPg->pData; +} + +/* +** Return a pointer to the Pager.nExtra bytes of "extra" space +** allocated along with the specified page. +*/ +SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){ + return pPg->pExtra; +} + +/* +** Get/set the locking-mode for this pager. Parameter eMode must be one +** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or +** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then +** the locking-mode is set to the value specified. +** +** The returned value is either PAGER_LOCKINGMODE_NORMAL or +** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated) +** locking-mode. +*/ +SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){ + assert( eMode==PAGER_LOCKINGMODE_QUERY + || eMode==PAGER_LOCKINGMODE_NORMAL + || eMode==PAGER_LOCKINGMODE_EXCLUSIVE ); + assert( PAGER_LOCKINGMODE_QUERY<0 ); + assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 ); + assert( pPager->exclusiveMode || 0==sqlite3WalHeapMemory(pPager->pWal) ); + if( eMode>=0 && !pPager->tempFile && !sqlite3WalHeapMemory(pPager->pWal) ){ + pPager->exclusiveMode = (u8)eMode; + } + return (int)pPager->exclusiveMode; +} + +/* +** Set the journal-mode for this pager. Parameter eMode must be one of: +** +** PAGER_JOURNALMODE_DELETE +** PAGER_JOURNALMODE_TRUNCATE +** PAGER_JOURNALMODE_PERSIST +** PAGER_JOURNALMODE_OFF +** PAGER_JOURNALMODE_MEMORY +** PAGER_JOURNALMODE_WAL +** +** The journalmode is set to the value specified if the change is allowed. +** The change may be disallowed for the following reasons: +** +** * An in-memory database can only have its journal_mode set to _OFF +** or _MEMORY. +** +** * Temporary databases cannot have _WAL journalmode. +** +** The returned indicate the current (possibly updated) journal-mode. +*/ +SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ + u8 eOld = pPager->journalMode; /* Prior journalmode */ + +#ifdef SQLITE_DEBUG + /* The print_pager_state() routine is intended to be used by the debugger + ** only. We invoke it once here to suppress a compiler warning. */ + print_pager_state(pPager); +#endif + + + /* The eMode parameter is always valid */ + assert( eMode==PAGER_JOURNALMODE_DELETE + || eMode==PAGER_JOURNALMODE_TRUNCATE + || eMode==PAGER_JOURNALMODE_PERSIST + || eMode==PAGER_JOURNALMODE_OFF + || eMode==PAGER_JOURNALMODE_WAL + || eMode==PAGER_JOURNALMODE_MEMORY ); + + /* This routine is only called from the OP_JournalMode opcode, and + ** the logic there will never allow a temporary file to be changed + ** to WAL mode. + */ + assert( pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL ); + + /* Do allow the journalmode of an in-memory database to be set to + ** anything other than MEMORY or OFF + */ + if( MEMDB ){ + assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF ); + if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){ + eMode = eOld; + } + } + + if( eMode!=eOld ){ + + /* Change the journal mode. */ + assert( pPager->eState!=PAGER_ERROR ); + pPager->journalMode = (u8)eMode; + + /* When transistioning from TRUNCATE or PERSIST to any other journal + ** mode except WAL, unless the pager is in locking_mode=exclusive mode, + ** delete the journal file. + */ + assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 ); + assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 ); + assert( (PAGER_JOURNALMODE_DELETE & 5)==0 ); + assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 ); + assert( (PAGER_JOURNALMODE_OFF & 5)==0 ); + assert( (PAGER_JOURNALMODE_WAL & 5)==5 ); + + assert( isOpen(pPager->fd) || pPager->exclusiveMode ); + if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ + + /* In this case we would like to delete the journal file. If it is + ** not possible, then that is not a problem. Deleting the journal file + ** here is an optimization only. + ** + ** Before deleting the journal file, obtain a RESERVED lock on the + ** database file. This ensures that the journal file is not deleted + ** while it is in use by some other client. + */ + sqlite3OsClose(pPager->jfd); + if( pPager->eLock>=RESERVED_LOCK ){ + sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); + }else{ + int rc = SQLITE_OK; + int state = pPager->eState; + assert( state==PAGER_OPEN || state==PAGER_READER ); + if( state==PAGER_OPEN ){ + rc = sqlite3PagerSharedLock(pPager); + } + if( pPager->eState==PAGER_READER ){ + assert( rc==SQLITE_OK ); + rc = pagerLockDb(pPager, RESERVED_LOCK); + } + if( rc==SQLITE_OK ){ + sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); + } + if( rc==SQLITE_OK && state==PAGER_READER ){ + pagerUnlockDb(pPager, SHARED_LOCK); + }else if( state==PAGER_OPEN ){ + pager_unlock(pPager); + } + assert( state==pPager->eState ); + } + }else if( eMode==PAGER_JOURNALMODE_OFF ){ + sqlite3OsClose(pPager->jfd); + } + } + + /* Return the new journal mode */ + return (int)pPager->journalMode; +} + +/* +** Return the current journal mode. +*/ +SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){ + return (int)pPager->journalMode; +} + +/* +** Return TRUE if the pager is in a state where it is OK to change the +** journalmode. Journalmode changes can only happen when the database +** is unmodified. +*/ +SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){ + assert( assert_pager_state(pPager) ); + if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0; + if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0; + return 1; +} + +/* +** Get/set the size-limit used for persistent journal files. +** +** Setting the size limit to -1 means no limit is enforced. +** An attempt to set a limit smaller than -1 is a no-op. +*/ +SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){ + if( iLimit>=-1 ){ + pPager->journalSizeLimit = iLimit; + sqlite3WalLimit(pPager->pWal, iLimit); + } + return pPager->journalSizeLimit; +} + +/* +** Return a pointer to the pPager->pBackup variable. The backup module +** in backup.c maintains the content of this variable. This module +** uses it opaquely as an argument to sqlite3BackupRestart() and +** sqlite3BackupUpdate() only. +*/ +SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){ + return &pPager->pBackup; +} + +#ifndef SQLITE_OMIT_VACUUM +/* +** Unless this is an in-memory or temporary database, clear the pager cache. +*/ +SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){ + assert( MEMDB==0 || pPager->tempFile ); + if( pPager->tempFile==0 ) pager_reset(pPager); +} +#endif + + +#ifndef SQLITE_OMIT_WAL +/* +** This function is called when the user invokes "PRAGMA wal_checkpoint", +** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint() +** or wal_blocking_checkpoint() API functions. +** +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. +*/ +SQLITE_PRIVATE int sqlite3PagerCheckpoint( + Pager *pPager, /* Checkpoint on this pager */ + sqlite3 *db, /* Db handle used to check for interrupts */ + int eMode, /* Type of checkpoint */ + int *pnLog, /* OUT: Final number of frames in log */ + int *pnCkpt /* OUT: Final number of checkpointed frames */ +){ + int rc = SQLITE_OK; + if( pPager->pWal ){ + rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, + (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), + pPager->pBusyHandlerArg, + pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, + pnLog, pnCkpt + ); + } + return rc; +} + +SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){ + return sqlite3WalCallback(pPager->pWal); +} + +/* +** Return true if the underlying VFS for the given pager supports the +** primitives necessary for write-ahead logging. +*/ +SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){ + const sqlite3_io_methods *pMethods = pPager->fd->pMethods; + if( pPager->noLock ) return 0; + return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap); +} + +/* +** Attempt to take an exclusive lock on the database file. If a PENDING lock +** is obtained instead, immediately release it. +*/ +static int pagerExclusiveLock(Pager *pPager){ + int rc; /* Return code */ + + assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); + rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); + if( rc!=SQLITE_OK ){ + /* If the attempt to grab the exclusive lock failed, release the + ** pending lock that may have been obtained instead. */ + pagerUnlockDb(pPager, SHARED_LOCK); + } + + return rc; +} + +/* +** Call sqlite3WalOpen() to open the WAL handle. If the pager is in +** exclusive-locking mode when this function is called, take an EXCLUSIVE +** lock on the database file and use heap-memory to store the wal-index +** in. Otherwise, use the normal shared-memory. +*/ +static int pagerOpenWal(Pager *pPager){ + int rc = SQLITE_OK; + + assert( pPager->pWal==0 && pPager->tempFile==0 ); + assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); + + /* If the pager is already in exclusive-mode, the WAL module will use + ** heap-memory for the wal-index instead of the VFS shared-memory + ** implementation. Take the exclusive lock now, before opening the WAL + ** file, to make sure this is safe. + */ + if( pPager->exclusiveMode ){ + rc = pagerExclusiveLock(pPager); + } + + /* Open the connection to the log file. If this operation fails, + ** (e.g. due to malloc() failure), return an error code. + */ + if( rc==SQLITE_OK ){ + rc = sqlite3WalOpen(pPager->pVfs, + pPager->fd, pPager->zWal, pPager->exclusiveMode, + pPager->journalSizeLimit, &pPager->pWal + ); + } + pagerFixMaplimit(pPager); + + return rc; +} + + +/* +** The caller must be holding a SHARED lock on the database file to call +** this function. +** +** If the pager passed as the first argument is open on a real database +** file (not a temp file or an in-memory database), and the WAL file +** is not already open, make an attempt to open it now. If successful, +** return SQLITE_OK. If an error occurs or the VFS used by the pager does +** not support the xShmXXX() methods, return an error code. *pbOpen is +** not modified in either case. +** +** If the pager is open on a temp-file (or in-memory database), or if +** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK +** without doing anything. +*/ +SQLITE_PRIVATE int sqlite3PagerOpenWal( + Pager *pPager, /* Pager object */ + int *pbOpen /* OUT: Set to true if call is a no-op */ +){ + int rc = SQLITE_OK; /* Return code */ + + assert( assert_pager_state(pPager) ); + assert( pPager->eState==PAGER_OPEN || pbOpen ); + assert( pPager->eState==PAGER_READER || !pbOpen ); + assert( pbOpen==0 || *pbOpen==0 ); + assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) ); + + if( !pPager->tempFile && !pPager->pWal ){ + if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN; + + /* Close any rollback journal previously open */ + sqlite3OsClose(pPager->jfd); + + rc = pagerOpenWal(pPager); + if( rc==SQLITE_OK ){ + pPager->journalMode = PAGER_JOURNALMODE_WAL; + pPager->eState = PAGER_OPEN; + } + }else{ + *pbOpen = 1; + } + + return rc; +} + +/* +** This function is called to close the connection to the log file prior +** to switching from WAL to rollback mode. +** +** Before closing the log file, this function attempts to take an +** EXCLUSIVE lock on the database file. If this cannot be obtained, an +** error (SQLITE_BUSY) is returned and the log connection is not closed. +** If successful, the EXCLUSIVE lock is not released before returning. +*/ +SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ + int rc = SQLITE_OK; + + assert( pPager->journalMode==PAGER_JOURNALMODE_WAL ); + + /* If the log file is not already open, but does exist in the file-system, + ** it may need to be checkpointed before the connection can switch to + ** rollback mode. Open it now so this can happen. + */ + if( !pPager->pWal ){ + int logexists = 0; + rc = pagerLockDb(pPager, SHARED_LOCK); + if( rc==SQLITE_OK ){ + rc = sqlite3OsAccess( + pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists + ); + } + if( rc==SQLITE_OK && logexists ){ + rc = pagerOpenWal(pPager); + } + } + + /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on + ** the database file, the log and log-summary files will be deleted. + */ + if( rc==SQLITE_OK && pPager->pWal ){ + rc = pagerExclusiveLock(pPager); + if( rc==SQLITE_OK ){ + rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, + pPager->pageSize, (u8*)pPager->pTmpSpace); + pPager->pWal = 0; + pagerFixMaplimit(pPager); + if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); + } + } + return rc; +} + +#ifdef SQLITE_ENABLE_SNAPSHOT +/* +** If this is a WAL database, obtain a snapshot handle for the snapshot +** currently open. Otherwise, return an error. +*/ +SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){ + int rc = SQLITE_ERROR; + if( pPager->pWal ){ + rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot); + } + return rc; +} + +/* +** If this is a WAL database, store a pointer to pSnapshot. Next time a +** read transaction is opened, attempt to read from the snapshot it +** identifies. If this is not a WAL database, return an error. +*/ +SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){ + int rc = SQLITE_OK; + if( pPager->pWal ){ + sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot); + }else{ + rc = SQLITE_ERROR; + } + return rc; +} + +/* +** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this +** is not a WAL database, return an error. +*/ +SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){ + int rc; + if( pPager->pWal ){ + rc = sqlite3WalSnapshotRecover(pPager->pWal); + }else{ + rc = SQLITE_ERROR; + } + return rc; +} +#endif /* SQLITE_ENABLE_SNAPSHOT */ +#endif /* !SQLITE_OMIT_WAL */ + +#ifdef SQLITE_ENABLE_ZIPVFS +/* +** A read-lock must be held on the pager when this function is called. If +** the pager is in WAL mode and the WAL file currently contains one or more +** frames, return the size in bytes of the page images stored within the +** WAL frames. Otherwise, if this is not a WAL database or the WAL file +** is empty, return 0. +*/ +SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ + assert( pPager->eState>=PAGER_READER ); + return sqlite3WalFramesize(pPager->pWal); +} +#endif + +#endif /* SQLITE_OMIT_DISKIO */ + +/************** End of pager.c ***********************************************/ +/************** Begin file wal.c *********************************************/ +/* +** 2010 February 1 +** +** 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 the implementation of a write-ahead log (WAL) used in +** "journal_mode=WAL" mode. +** +** WRITE-AHEAD LOG (WAL) FILE FORMAT +** +** A WAL file consists of a header followed by zero or more "frames". +** Each frame records the revised content of a single page from the +** database file. All changes to the database are recorded by writing +** frames into the WAL. Transactions commit when a frame is written that +** contains a commit marker. A single WAL can and usually does record +** multiple transactions. Periodically, the content of the WAL is +** transferred back into the database file in an operation called a +** "checkpoint". +** +** A single WAL file can be used multiple times. In other words, the +** WAL can fill up with frames and then be checkpointed and then new +** frames can overwrite the old ones. A WAL always grows from beginning +** toward the end. Checksums and counters attached to each frame are +** used to determine which frames within the WAL are valid and which +** are leftovers from prior checkpoints. +** +** The WAL header is 32 bytes in size and consists of the following eight +** big-endian 32-bit unsigned integer values: +** +** 0: Magic number. 0x377f0682 or 0x377f0683 +** 4: File format version. Currently 3007000 +** 8: Database page size. Example: 1024 +** 12: Checkpoint sequence number +** 16: Salt-1, random integer incremented with each checkpoint +** 20: Salt-2, a different random integer changing with each ckpt +** 24: Checksum-1 (first part of checksum for first 24 bytes of header). +** 28: Checksum-2 (second part of checksum for first 24 bytes of header). +** +** Immediately following the wal-header are zero or more frames. Each +** frame consists of a 24-byte frame-header followed by a bytes +** of page data. The frame-header is six big-endian 32-bit unsigned +** integer values, as follows: +** +** 0: Page number. +** 4: For commit records, the size of the database image in pages +** after the commit. For all other records, zero. +** 8: Salt-1 (copied from the header) +** 12: Salt-2 (copied from the header) +** 16: Checksum-1. +** 20: Checksum-2. +** +** A frame is considered valid if and only if the following conditions are +** true: +** +** (1) The salt-1 and salt-2 values in the frame-header match +** salt values in the wal-header +** +** (2) The checksum values in the final 8 bytes of the frame-header +** exactly match the checksum computed consecutively on the +** WAL header and the first 8 bytes and the content of all frames +** up to and including the current frame. +** +** The checksum is computed using 32-bit big-endian integers if the +** magic number in the first 4 bytes of the WAL is 0x377f0683 and it +** is computed using little-endian if the magic number is 0x377f0682. +** The checksum values are always stored in the frame header in a +** big-endian format regardless of which byte order is used to compute +** the checksum. The checksum is computed by interpreting the input as +** an even number of unsigned 32-bit integers: x[0] through x[N]. The +** algorithm used for the checksum is as follows: +** +** for i from 0 to n-1 step 2: +** s0 += x[i] + s1; +** s1 += x[i+1] + s0; +** endfor +** +** Note that s0 and s1 are both weighted checksums using fibonacci weights +** in reverse order (the largest fibonacci weight occurs on the first element +** of the sequence being summed.) The s1 value spans all 32-bit +** terms of the sequence whereas s0 omits the final term. +** +** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the +** WAL is transferred into the database, then the database is VFS.xSync-ed. +** The VFS.xSync operations serve as write barriers - all writes launched +** before the xSync must complete before any write that launches after the +** xSync begins. +** +** After each checkpoint, the salt-1 value is incremented and the salt-2 +** value is randomized. This prevents old and new frames in the WAL from +** being considered valid at the same time and being checkpointing together +** following a crash. +** +** READER ALGORITHM +** +** To read a page from the database (call it page number P), a reader +** first checks the WAL to see if it contains page P. If so, then the +** last valid instance of page P that is a followed by a commit frame +** or is a commit frame itself becomes the value read. If the WAL +** contains no copies of page P that are valid and which are a commit +** frame or are followed by a commit frame, then page P is read from +** the database file. +** +** To start a read transaction, the reader records the index of the last +** valid frame in the WAL. The reader uses this recorded "mxFrame" value +** for all subsequent read operations. New transactions can be appended +** to the WAL, but as long as the reader uses its original mxFrame value +** and ignores the newly appended content, it will see a consistent snapshot +** of the database from a single point in time. This technique allows +** multiple concurrent readers to view different versions of the database +** content simultaneously. +** +** The reader algorithm in the previous paragraphs works correctly, but +** because frames for page P can appear anywhere within the WAL, the +** reader has to scan the entire WAL looking for page P frames. If the +** WAL is large (multiple megabytes is typical) that scan can be slow, +** and read performance suffers. To overcome this problem, a separate +** data structure called the wal-index is maintained to expedite the +** search for frames of a particular page. +** +** WAL-INDEX FORMAT +** +** Conceptually, the wal-index is shared memory, though VFS implementations +** might choose to implement the wal-index using a mmapped file. Because +** the wal-index is shared memory, SQLite does not support journal_mode=WAL +** on a network filesystem. All users of the database must be able to +** share memory. +** +** The wal-index is transient. After a crash, the wal-index can (and should +** be) reconstructed from the original WAL file. In fact, the VFS is required +** to either truncate or zero the header of the wal-index when the last +** connection to it closes. Because the wal-index is transient, it can +** use an architecture-specific format; it does not have to be cross-platform. +** Hence, unlike the database and WAL file formats which store all values +** as big endian, the wal-index can store multi-byte values in the native +** byte order of the host computer. +** +** The purpose of the wal-index is to answer this question quickly: Given +** a page number P and a maximum frame index M, return the index of the +** last frame in the wal before frame M for page P in the WAL, or return +** NULL if there are no frames for page P in the WAL prior to M. +** +** The wal-index consists of a header region, followed by an one or +** more index blocks. +** +** The wal-index header contains the total number of frames within the WAL +** in the mxFrame field. +** +** Each index block except for the first contains information on +** HASHTABLE_NPAGE frames. The first index block contains information on +** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and +** HASHTABLE_NPAGE are selected so that together the wal-index header and +** first index block are the same size as all other index blocks in the +** wal-index. +** +** Each index block contains two sections, a page-mapping that contains the +** database page number associated with each wal frame, and a hash-table +** that allows readers to query an index block for a specific page number. +** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE +** for the first index block) 32-bit page numbers. The first entry in the +** first index-block contains the database page number corresponding to the +** first frame in the WAL file. The first entry in the second index block +** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in +** the log, and so on. +** +** The last index block in a wal-index usually contains less than the full +** complement of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE) page-numbers, +** depending on the contents of the WAL file. This does not change the +** allocated size of the page-mapping array - the page-mapping array merely +** contains unused entries. +** +** Even without using the hash table, the last frame for page P +** can be found by scanning the page-mapping sections of each index block +** starting with the last index block and moving toward the first, and +** within each index block, starting at the end and moving toward the +** beginning. The first entry that equals P corresponds to the frame +** holding the content for that page. +** +** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers. +** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the +** hash table for each page number in the mapping section, so the hash +** table is never more than half full. The expected number of collisions +** prior to finding a match is 1. Each entry of the hash table is an +** 1-based index of an entry in the mapping section of the same +** index block. Let K be the 1-based index of the largest entry in +** the mapping section. (For index blocks other than the last, K will +** always be exactly HASHTABLE_NPAGE (4096) and for the last index block +** K will be (mxFrame%HASHTABLE_NPAGE).) Unused slots of the hash table +** contain a value of 0. +** +** To look for page P in the hash table, first compute a hash iKey on +** P as follows: +** +** iKey = (P * 383) % HASHTABLE_NSLOT +** +** Then start scanning entries of the hash table, starting with iKey +** (wrapping around to the beginning when the end of the hash table is +** reached) until an unused hash slot is found. Let the first unused slot +** be at index iUnused. (iUnused might be less than iKey if there was +** wrap-around.) Because the hash table is never more than half full, +** the search is guaranteed to eventually hit an unused entry. Let +** iMax be the value between iKey and iUnused, closest to iUnused, +** where aHash[iMax]==P. If there is no iMax entry (if there exists +** no hash slot such that aHash[i]==p) then page P is not in the +** current index block. Otherwise the iMax-th mapping entry of the +** current index block corresponds to the last entry that references +** page P. +** +** A hash search begins with the last index block and moves toward the +** first index block, looking for entries corresponding to page P. On +** average, only two or three slots in each index block need to be +** examined in order to either find the last entry for page P, or to +** establish that no such entry exists in the block. Each index block +** holds over 4000 entries. So two or three index blocks are sufficient +** to cover a typical 10 megabyte WAL file, assuming 1K pages. 8 or 10 +** comparisons (on average) suffice to either locate a frame in the +** WAL or to establish that the frame does not exist in the WAL. This +** is much faster than scanning the entire 10MB WAL. +** +** Note that entries are added in order of increasing K. Hence, one +** reader might be using some value K0 and a second reader that started +** at a later time (after additional transactions were added to the WAL +** and to the wal-index) might be using a different value K1, where K1>K0. +** Both readers can use the same hash table and mapping section to get +** the correct result. There may be entries in the hash table with +** K>K0 but to the first reader, those entries will appear to be unused +** slots in the hash table and so the first reader will get an answer as +** if no values greater than K0 had ever been inserted into the hash table +** in the first place - which is what reader one wants. Meanwhile, the +** second reader using K1 will see additional values that were inserted +** later, which is exactly what reader two wants. +** +** When a rollback occurs, the value of K is decreased. Hash table entries +** that correspond to frames greater than the new K value are removed +** from the hash table at this point. +*/ +#ifndef SQLITE_OMIT_WAL + +/* #include "wal.h" */ + +/* +** Trace output macros +*/ +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) +SQLITE_PRIVATE int sqlite3WalTrace = 0; +# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X +#else +# define WALTRACE(X) +#endif + +/* +** The maximum (and only) versions of the wal and wal-index formats +** that may be interpreted by this version of SQLite. +** +** If a client begins recovering a WAL file and finds that (a) the checksum +** values in the wal-header are correct and (b) the version field is not +** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN. +** +** Similarly, if a client successfully reads a wal-index header (i.e. the +** checksum test is successful) and finds that the version field is not +** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite +** returns SQLITE_CANTOPEN. +*/ +#define WAL_MAX_VERSION 3007000 +#define WALINDEX_MAX_VERSION 3007000 + +/* +** Indices of various locking bytes. WAL_NREADER is the number +** of available reader locks and should be at least 3. The default +** is SQLITE_SHM_NLOCK==8 and WAL_NREADER==5. +*/ +#define WAL_WRITE_LOCK 0 +#define WAL_ALL_BUT_WRITE 1 +#define WAL_CKPT_LOCK 1 +#define WAL_RECOVER_LOCK 2 +#define WAL_READ_LOCK(I) (3+(I)) +#define WAL_NREADER (SQLITE_SHM_NLOCK-3) + + +/* Object declarations */ +typedef struct WalIndexHdr WalIndexHdr; +typedef struct WalIterator WalIterator; +typedef struct WalCkptInfo WalCkptInfo; + + +/* +** The following object holds a copy of the wal-index header content. +** +** The actual header in the wal-index consists of two copies of this +** object followed by one instance of the WalCkptInfo object. +** For all versions of SQLite through 3.10.0 and probably beyond, +** the locking bytes (WalCkptInfo.aLock) start at offset 120 and +** the total header size is 136 bytes. +** +** The szPage value can be any power of 2 between 512 and 32768, inclusive. +** Or it can be 1 to represent a 65536-byte page. The latter case was +** added in 3.7.1 when support for 64K pages was added. +*/ +struct WalIndexHdr { + u32 iVersion; /* Wal-index version */ + u32 unused; /* Unused (padding) field */ + u32 iChange; /* Counter incremented each transaction */ + u8 isInit; /* 1 when initialized */ + u8 bigEndCksum; /* True if checksums in WAL are big-endian */ + u16 szPage; /* Database page size in bytes. 1==64K */ + u32 mxFrame; /* Index of last valid frame in the WAL */ + u32 nPage; /* Size of database in pages */ + u32 aFrameCksum[2]; /* Checksum of last frame in log */ + u32 aSalt[2]; /* Two salt values copied from WAL header */ + u32 aCksum[2]; /* Checksum over all prior fields */ +}; + +/* +** A copy of the following object occurs in the wal-index immediately +** following the second copy of the WalIndexHdr. This object stores +** information used by checkpoint. +** +** nBackfill is the number of frames in the WAL that have been written +** back into the database. (We call the act of moving content from WAL to +** database "backfilling".) The nBackfill number is never greater than +** WalIndexHdr.mxFrame. nBackfill can only be increased by threads +** holding the WAL_CKPT_LOCK lock (which includes a recovery thread). +** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from +** mxFrame back to zero when the WAL is reset. +** +** nBackfillAttempted is the largest value of nBackfill that a checkpoint +** has attempted to achieve. Normally nBackfill==nBackfillAtempted, however +** the nBackfillAttempted is set before any backfilling is done and the +** nBackfill is only set after all backfilling completes. So if a checkpoint +** crashes, nBackfillAttempted might be larger than nBackfill. The +** WalIndexHdr.mxFrame must never be less than nBackfillAttempted. +** +** The aLock[] field is a set of bytes used for locking. These bytes should +** never be read or written. +** +** There is one entry in aReadMark[] for each reader lock. If a reader +** holds read-lock K, then the value in aReadMark[K] is no greater than +** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff) +** for any aReadMark[] means that entry is unused. aReadMark[0] is +** a special case; its value is never used and it exists as a place-holder +** to avoid having to offset aReadMark[] indexs by one. Readers holding +** WAL_READ_LOCK(0) always ignore the entire WAL and read all content +** directly from the database. +** +** The value of aReadMark[K] may only be changed by a thread that +** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of +** aReadMark[K] cannot changed while there is a reader is using that mark +** since the reader will be holding a shared lock on WAL_READ_LOCK(K). +** +** The checkpointer may only transfer frames from WAL to database where +** the frame numbers are less than or equal to every aReadMark[] that is +** in use (that is, every aReadMark[j] for which there is a corresponding +** WAL_READ_LOCK(j)). New readers (usually) pick the aReadMark[] with the +** largest value and will increase an unused aReadMark[] to mxFrame if there +** is not already an aReadMark[] equal to mxFrame. The exception to the +** previous sentence is when nBackfill equals mxFrame (meaning that everything +** in the WAL has been backfilled into the database) then new readers +** will choose aReadMark[0] which has value 0 and hence such reader will +** get all their all content directly from the database file and ignore +** the WAL. +** +** Writers normally append new frames to the end of the WAL. However, +** if nBackfill equals mxFrame (meaning that all WAL content has been +** written back into the database) and if no readers are using the WAL +** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then +** the writer will first "reset" the WAL back to the beginning and start +** writing new content beginning at frame 1. +** +** We assume that 32-bit loads are atomic and so no locks are needed in +** order to read from any aReadMark[] entries. +*/ +struct WalCkptInfo { + u32 nBackfill; /* Number of WAL frames backfilled into DB */ + u32 aReadMark[WAL_NREADER]; /* Reader marks */ + u8 aLock[SQLITE_SHM_NLOCK]; /* Reserved space for locks */ + u32 nBackfillAttempted; /* WAL frames perhaps written, or maybe not */ + u32 notUsed0; /* Available for future enhancements */ +}; +#define READMARK_NOT_USED 0xffffffff + + +/* A block of WALINDEX_LOCK_RESERVED bytes beginning at +** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems +** only support mandatory file-locks, we do not read or write data +** from the region of the file on which locks are applied. +*/ +#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2+offsetof(WalCkptInfo,aLock)) +#define WALINDEX_HDR_SIZE (sizeof(WalIndexHdr)*2+sizeof(WalCkptInfo)) + +/* Size of header before each frame in wal */ +#define WAL_FRAME_HDRSIZE 24 + +/* Size of write ahead log header, including checksum. */ +/* #define WAL_HDRSIZE 24 */ +#define WAL_HDRSIZE 32 + +/* WAL magic value. Either this value, or the same value with the least +** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit +** big-endian format in the first 4 bytes of a WAL file. +** +** If the LSB is set, then the checksums for each frame within the WAL +** file are calculated by treating all data as an array of 32-bit +** big-endian words. Otherwise, they are calculated by interpreting +** all data as 32-bit little-endian words. +*/ +#define WAL_MAGIC 0x377f0682 + +/* +** Return the offset of frame iFrame in the write-ahead log file, +** assuming a database page size of szPage bytes. The offset returned +** is to the start of the write-ahead log frame-header. +*/ +#define walFrameOffset(iFrame, szPage) ( \ + WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \ +) + +/* +** An open write-ahead log file is represented by an instance of the +** following object. +*/ +struct Wal { + sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ + sqlite3_file *pDbFd; /* File handle for the database file */ + sqlite3_file *pWalFd; /* File handle for WAL file */ + u32 iCallback; /* Value to pass to log callback (or 0) */ + i64 mxWalSize; /* Truncate WAL to this size upon reset */ + int nWiData; /* Size of array apWiData */ + int szFirstBlock; /* Size of first block written to WAL file */ + volatile u32 **apWiData; /* Pointer to wal-index content in memory */ + u32 szPage; /* Database page size */ + i16 readLock; /* Which read lock is being held. -1 for none */ + u8 syncFlags; /* Flags to use to sync header writes */ + u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */ + u8 writeLock; /* True if in a write transaction */ + u8 ckptLock; /* True if holding a checkpoint lock */ + u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */ + u8 truncateOnCommit; /* True to truncate WAL file on commit */ + u8 syncHeader; /* Fsync the WAL header if true */ + u8 padToSectorBoundary; /* Pad transactions out to the next sector */ + WalIndexHdr hdr; /* Wal-index header for current transaction */ + u32 minFrame; /* Ignore wal frames before this one */ + u32 iReCksum; /* On commit, recalculate checksums from here */ + const char *zWalName; /* Name of WAL file */ + u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ +#ifdef SQLITE_DEBUG + u8 lockError; /* True if a locking error has occurred */ +#endif +#ifdef SQLITE_ENABLE_SNAPSHOT + WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ +#endif +}; + +/* +** Candidate values for Wal.exclusiveMode. +*/ +#define WAL_NORMAL_MODE 0 +#define WAL_EXCLUSIVE_MODE 1 +#define WAL_HEAPMEMORY_MODE 2 + +/* +** Possible values for WAL.readOnly +*/ +#define WAL_RDWR 0 /* Normal read/write connection */ +#define WAL_RDONLY 1 /* The WAL file is readonly */ +#define WAL_SHM_RDONLY 2 /* The SHM file is readonly */ + +/* +** Each page of the wal-index mapping contains a hash-table made up of +** an array of HASHTABLE_NSLOT elements of the following type. +*/ +typedef u16 ht_slot; + +/* +** This structure is used to implement an iterator that loops through +** all frames in the WAL in database page order. Where two or more frames +** correspond to the same database page, the iterator visits only the +** frame most recently written to the WAL (in other words, the frame with +** the largest index). +** +** The internals of this structure are only accessed by: +** +** walIteratorInit() - Create a new iterator, +** walIteratorNext() - Step an iterator, +** walIteratorFree() - Free an iterator. +** +** This functionality is used by the checkpoint code (see walCheckpoint()). +*/ +struct WalIterator { + int iPrior; /* Last result returned from the iterator */ + int nSegment; /* Number of entries in aSegment[] */ + struct WalSegment { + int iNext; /* Next slot in aIndex[] not yet returned */ + ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */ + u32 *aPgno; /* Array of page numbers. */ + int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */ + int iZero; /* Frame number associated with aPgno[0] */ + } aSegment[1]; /* One for every 32KB page in the wal-index */ +}; + +/* +** Define the parameters of the hash tables in the wal-index file. There +** is a hash-table following every HASHTABLE_NPAGE page numbers in the +** wal-index. +** +** Changing any of these constants will alter the wal-index format and +** create incompatibilities. +*/ +#define HASHTABLE_NPAGE 4096 /* Must be power of 2 */ +#define HASHTABLE_HASH_1 383 /* Should be prime */ +#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */ + +/* +** The block of page numbers associated with the first hash-table in a +** wal-index is smaller than usual. This is so that there is a complete +** hash-table on each aligned 32KB page of the wal-index. +*/ +#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32))) + +/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */ +#define WALINDEX_PGSZ ( \ + sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \ +) + +/* +** Obtain a pointer to the iPage'th page of the wal-index. The wal-index +** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are +** numbered from zero. +** +** If this call is successful, *ppPage is set to point to the wal-index +** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs, +** then an SQLite error code is returned and *ppPage is set to 0. +*/ +static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ + int rc = SQLITE_OK; + + /* Enlarge the pWal->apWiData[] array if required */ + if( pWal->nWiData<=iPage ){ + int nByte = sizeof(u32*)*(iPage+1); + volatile u32 **apNew; + apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte); + if( !apNew ){ + *ppPage = 0; + return SQLITE_NOMEM_BKPT; + } + memset((void*)&apNew[pWal->nWiData], 0, + sizeof(u32*)*(iPage+1-pWal->nWiData)); + pWal->apWiData = apNew; + pWal->nWiData = iPage+1; + } + + /* Request a pointer to the required page from the VFS */ + if( pWal->apWiData[iPage]==0 ){ + if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ + pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); + if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, + pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] + ); + if( rc==SQLITE_READONLY ){ + pWal->readOnly |= WAL_SHM_RDONLY; + rc = SQLITE_OK; + } + } + } + + *ppPage = pWal->apWiData[iPage]; + assert( iPage==0 || *ppPage || rc!=SQLITE_OK ); + return rc; +} + +/* +** Return a pointer to the WalCkptInfo structure in the wal-index. +*/ +static volatile WalCkptInfo *walCkptInfo(Wal *pWal){ + assert( pWal->nWiData>0 && pWal->apWiData[0] ); + return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]); +} + +/* +** Return a pointer to the WalIndexHdr structure in the wal-index. +*/ +static volatile WalIndexHdr *walIndexHdr(Wal *pWal){ + assert( pWal->nWiData>0 && pWal->apWiData[0] ); + return (volatile WalIndexHdr*)pWal->apWiData[0]; +} + +/* +** The argument to this macro must be of type u32. On a little-endian +** architecture, it returns the u32 value that results from interpreting +** the 4 bytes as a big-endian value. On a big-endian architecture, it +** returns the value that would be produced by interpreting the 4 bytes +** of the input value as a little-endian integer. +*/ +#define BYTESWAP32(x) ( \ + (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ + + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ +) + +/* +** Generate or extend an 8 byte checksum based on the data in +** array aByte[] and the initial values of aIn[0] and aIn[1] (or +** initial values of 0 and 0 if aIn==NULL). +** +** The checksum is written back into aOut[] before returning. +** +** nByte must be a positive multiple of 8. +*/ +static void walChecksumBytes( + int nativeCksum, /* True for native byte-order, false for non-native */ + u8 *a, /* Content to be checksummed */ + int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ + const u32 *aIn, /* Initial checksum value input */ + u32 *aOut /* OUT: Final checksum value output */ +){ + u32 s1, s2; + u32 *aData = (u32 *)a; + u32 *aEnd = (u32 *)&a[nByte]; + + if( aIn ){ + s1 = aIn[0]; + s2 = aIn[1]; + }else{ + s1 = s2 = 0; + } + + assert( nByte>=8 ); + assert( (nByte&0x00000007)==0 ); + + if( nativeCksum ){ + do { + s1 += *aData++ + s2; + s2 += *aData++ + s1; + }while( aDataexclusiveMode!=WAL_HEAPMEMORY_MODE ){ + sqlite3OsShmBarrier(pWal->pDbFd); + } +} + +/* +** Write the header information in pWal->hdr into the wal-index. +** +** The checksum on pWal->hdr is updated before it is written. +*/ +static void walIndexWriteHdr(Wal *pWal){ + volatile WalIndexHdr *aHdr = walIndexHdr(pWal); + const int nCksum = offsetof(WalIndexHdr, aCksum); + + assert( pWal->writeLock ); + pWal->hdr.isInit = 1; + pWal->hdr.iVersion = WALINDEX_MAX_VERSION; + walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum); + memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); + walShmBarrier(pWal); + memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); +} + +/* +** This function encodes a single frame header and writes it to a buffer +** supplied by the caller. A frame-header is made up of a series of +** 4-byte big-endian integers, as follows: +** +** 0: Page number. +** 4: For commit records, the size of the database image in pages +** after the commit. For all other records, zero. +** 8: Salt-1 (copied from the wal-header) +** 12: Salt-2 (copied from the wal-header) +** 16: Checksum-1. +** 20: Checksum-2. +*/ +static void walEncodeFrame( + Wal *pWal, /* The write-ahead log */ + u32 iPage, /* Database page number for frame */ + u32 nTruncate, /* New db size (or 0 for non-commit frames) */ + u8 *aData, /* Pointer to page data */ + u8 *aFrame /* OUT: Write encoded frame here */ +){ + int nativeCksum; /* True for native byte-order checksums */ + u32 *aCksum = pWal->hdr.aFrameCksum; + assert( WAL_FRAME_HDRSIZE==24 ); + sqlite3Put4byte(&aFrame[0], iPage); + sqlite3Put4byte(&aFrame[4], nTruncate); + if( pWal->iReCksum==0 ){ + memcpy(&aFrame[8], pWal->hdr.aSalt, 8); + + nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); + walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); + walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); + + sqlite3Put4byte(&aFrame[16], aCksum[0]); + sqlite3Put4byte(&aFrame[20], aCksum[1]); + }else{ + memset(&aFrame[8], 0, 16); + } +} + +/* +** Check to see if the frame with header in aFrame[] and content +** in aData[] is valid. If it is a valid frame, fill *piPage and +** *pnTruncate and return true. Return if the frame is not valid. +*/ +static int walDecodeFrame( + Wal *pWal, /* The write-ahead log */ + u32 *piPage, /* OUT: Database page number for frame */ + u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */ + u8 *aData, /* Pointer to page data (for checksum) */ + u8 *aFrame /* Frame data */ +){ + int nativeCksum; /* True for native byte-order checksums */ + u32 *aCksum = pWal->hdr.aFrameCksum; + u32 pgno; /* Page number of the frame */ + assert( WAL_FRAME_HDRSIZE==24 ); + + /* A frame is only valid if the salt values in the frame-header + ** match the salt values in the wal-header. + */ + if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){ + return 0; + } + + /* A frame is only valid if the page number is creater than zero. + */ + pgno = sqlite3Get4byte(&aFrame[0]); + if( pgno==0 ){ + return 0; + } + + /* A frame is only valid if a checksum of the WAL header, + ** all prior frams, the first 16 bytes of this frame-header, + ** and the frame-data matches the checksum in the last 8 + ** bytes of this frame-header. + */ + nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); + walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); + walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); + if( aCksum[0]!=sqlite3Get4byte(&aFrame[16]) + || aCksum[1]!=sqlite3Get4byte(&aFrame[20]) + ){ + /* Checksum failed. */ + return 0; + } + + /* If we reach this point, the frame is valid. Return the page number + ** and the new database size. + */ + *piPage = pgno; + *pnTruncate = sqlite3Get4byte(&aFrame[4]); + return 1; +} + + +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) +/* +** Names of locks. This routine is used to provide debugging output and is not +** a part of an ordinary build. +*/ +static const char *walLockName(int lockIdx){ + if( lockIdx==WAL_WRITE_LOCK ){ + return "WRITE-LOCK"; + }else if( lockIdx==WAL_CKPT_LOCK ){ + return "CKPT-LOCK"; + }else if( lockIdx==WAL_RECOVER_LOCK ){ + return "RECOVER-LOCK"; + }else{ + static char zName[15]; + sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]", + lockIdx-WAL_READ_LOCK(0)); + return zName; + } +} +#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */ + + +/* +** Set or release locks on the WAL. Locks are either shared or exclusive. +** A lock cannot be moved directly between shared and exclusive - it must go +** through the unlocked state first. +** +** In locking_mode=EXCLUSIVE, all of these routines become no-ops. +*/ +static int walLockShared(Wal *pWal, int lockIdx){ + int rc; + if( pWal->exclusiveMode ) return SQLITE_OK; + rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1, + SQLITE_SHM_LOCK | SQLITE_SHM_SHARED); + WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal, + walLockName(lockIdx), rc ? "failed" : "ok")); + VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); ) + return rc; +} +static void walUnlockShared(Wal *pWal, int lockIdx){ + if( pWal->exclusiveMode ) return; + (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1, + SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED); + WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx))); +} +static int walLockExclusive(Wal *pWal, int lockIdx, int n){ + int rc; + if( pWal->exclusiveMode ) return SQLITE_OK; + rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, + SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE); + WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal, + walLockName(lockIdx), n, rc ? "failed" : "ok")); + VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); ) + return rc; +} +static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){ + if( pWal->exclusiveMode ) return; + (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n, + SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE); + WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal, + walLockName(lockIdx), n)); +} + +/* +** Compute a hash on a page number. The resulting hash value must land +** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances +** the hash to the next value in the event of a collision. +*/ +static int walHash(u32 iPage){ + assert( iPage>0 ); + assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 ); + return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1); +} +static int walNextHash(int iPriorHash){ + return (iPriorHash+1)&(HASHTABLE_NSLOT-1); +} + +/* +** Return pointers to the hash table and page number array stored on +** page iHash of the wal-index. The wal-index is broken into 32KB pages +** numbered starting from 0. +** +** Set output variable *paHash to point to the start of the hash table +** in the wal-index file. Set *piZero to one less than the frame +** number of the first frame indexed by this hash table. If a +** slot in the hash table is set to N, it refers to frame number +** (*piZero+N) in the log. +** +** Finally, set *paPgno so that *paPgno[1] is the page number of the +** first frame indexed by the hash table, frame (*piZero+1). +*/ +static int walHashGet( + Wal *pWal, /* WAL handle */ + int iHash, /* Find the iHash'th table */ + volatile ht_slot **paHash, /* OUT: Pointer to hash index */ + volatile u32 **paPgno, /* OUT: Pointer to page number array */ + u32 *piZero /* OUT: Frame associated with *paPgno[0] */ +){ + int rc; /* Return code */ + volatile u32 *aPgno; + + rc = walIndexPage(pWal, iHash, &aPgno); + assert( rc==SQLITE_OK || iHash>0 ); + + if( rc==SQLITE_OK ){ + u32 iZero; + volatile ht_slot *aHash; + + aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE]; + if( iHash==0 ){ + aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; + iZero = 0; + }else{ + iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; + } + + *paPgno = &aPgno[-1]; + *paHash = aHash; + *piZero = iZero; + } + return rc; +} + +/* +** Return the number of the wal-index page that contains the hash-table +** and page-number array that contain entries corresponding to WAL frame +** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages +** are numbered starting from 0. +*/ +static int walFramePage(u32 iFrame){ + int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE; + assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE) + && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE) + && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)) + && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE) + && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE)) + ); + return iHash; +} + +/* +** Return the page number associated with frame iFrame in this WAL. +*/ +static u32 walFramePgno(Wal *pWal, u32 iFrame){ + int iHash = walFramePage(iFrame); + if( iHash==0 ){ + return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1]; + } + return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE]; +} + +/* +** Remove entries from the hash table that point to WAL slots greater +** than pWal->hdr.mxFrame. +** +** This function is called whenever pWal->hdr.mxFrame is decreased due +** to a rollback or savepoint. +** +** At most only the hash table containing pWal->hdr.mxFrame needs to be +** updated. Any later hash tables will be automatically cleared when +** pWal->hdr.mxFrame advances to the point where those hash tables are +** actually needed. +*/ +static void walCleanupHash(Wal *pWal){ + volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */ + volatile u32 *aPgno = 0; /* Page number array for hash table */ + u32 iZero = 0; /* frame == (aHash[x]+iZero) */ + int iLimit = 0; /* Zero values greater than this */ + int nByte; /* Number of bytes to zero in aPgno[] */ + int i; /* Used to iterate through aHash[] */ + + assert( pWal->writeLock ); + testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 ); + testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE ); + testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 ); + + if( pWal->hdr.mxFrame==0 ) return; + + /* Obtain pointers to the hash-table and page-number array containing + ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed + ** that the page said hash-table and array reside on is already mapped. + */ + assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) ); + assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] ); + walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero); + + /* Zero all hash-table entries that correspond to frame numbers greater + ** than pWal->hdr.mxFrame. + */ + iLimit = pWal->hdr.mxFrame - iZero; + assert( iLimit>0 ); + for(i=0; iiLimit ){ + aHash[i] = 0; + } + } + + /* Zero the entries in the aPgno array that correspond to frames with + ** frame numbers greater than pWal->hdr.mxFrame. + */ + nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]); + memset((void *)&aPgno[iLimit+1], 0, nByte); + +#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT + /* Verify that the every entry in the mapping region is still reachable + ** via the hash table even after the cleanup. + */ + if( iLimit ){ + int j; /* Loop counter */ + int iKey; /* Hash key */ + for(j=1; j<=iLimit; j++){ + for(iKey=walHash(aPgno[j]); aHash[iKey]; iKey=walNextHash(iKey)){ + if( aHash[iKey]==j ) break; + } + assert( aHash[iKey]==j ); + } + } +#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */ +} + + +/* +** Set an entry in the wal-index that will map database page number +** pPage into WAL frame iFrame. +*/ +static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ + int rc; /* Return code */ + u32 iZero = 0; /* One less than frame number of aPgno[1] */ + volatile u32 *aPgno = 0; /* Page number array */ + volatile ht_slot *aHash = 0; /* Hash table */ + + rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero); + + /* Assuming the wal-index file was successfully mapped, populate the + ** page number array and hash table entry. + */ + if( rc==SQLITE_OK ){ + int iKey; /* Hash table key */ + int idx; /* Value to write to hash-table slot */ + int nCollide; /* Number of hash collisions */ + + idx = iFrame - iZero; + assert( idx <= HASHTABLE_NSLOT/2 + 1 ); + + /* If this is the first entry to be added to this hash-table, zero the + ** entire hash table and aPgno[] array before proceeding. + */ + if( idx==1 ){ + int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]); + memset((void*)&aPgno[1], 0, nByte); + } + + /* If the entry in aPgno[] is already set, then the previous writer + ** must have exited unexpectedly in the middle of a transaction (after + ** writing one or more dirty pages to the WAL to free up memory). + ** Remove the remnants of that writers uncommitted transaction from + ** the hash-table before writing any new entries. + */ + if( aPgno[idx] ){ + walCleanupHash(pWal); + assert( !aPgno[idx] ); + } + + /* Write the aPgno[] array entry and the hash-table slot. */ + nCollide = idx; + for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){ + if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; + } + aPgno[idx] = iPage; + aHash[iKey] = (ht_slot)idx; + +#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT + /* Verify that the number of entries in the hash table exactly equals + ** the number of entries in the mapping region. + */ + { + int i; /* Loop counter */ + int nEntry = 0; /* Number of entries in the hash table */ + for(i=0; ickptLock==1 || pWal->ckptLock==0 ); + assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 ); + assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE ); + assert( pWal->writeLock ); + iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; + nLock = SQLITE_SHM_NLOCK - iLock; + rc = walLockExclusive(pWal, iLock, nLock); + if( rc ){ + return rc; + } + WALTRACE(("WAL%p: recovery begin...\n", pWal)); + + memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); + + rc = sqlite3OsFileSize(pWal->pWalFd, &nSize); + if( rc!=SQLITE_OK ){ + goto recovery_error; + } + + if( nSize>WAL_HDRSIZE ){ + u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */ + u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */ + int szFrame; /* Number of bytes in buffer aFrame[] */ + u8 *aData; /* Pointer to data part of aFrame buffer */ + int iFrame; /* Index of last frame read */ + i64 iOffset; /* Next offset to read from log file */ + int szPage; /* Page size according to the log */ + u32 magic; /* Magic value read from WAL header */ + u32 version; /* Magic value read from WAL header */ + int isValid; /* True if this frame is valid */ + + /* Read in the WAL header. */ + rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0); + if( rc!=SQLITE_OK ){ + goto recovery_error; + } + + /* If the database page size is not a power of two, or is greater than + ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid + ** data. Similarly, if the 'magic' value is invalid, ignore the whole + ** WAL file. + */ + magic = sqlite3Get4byte(&aBuf[0]); + szPage = sqlite3Get4byte(&aBuf[8]); + if( (magic&0xFFFFFFFE)!=WAL_MAGIC + || szPage&(szPage-1) + || szPage>SQLITE_MAX_PAGE_SIZE + || szPage<512 + ){ + goto finished; + } + pWal->hdr.bigEndCksum = (u8)(magic&0x00000001); + pWal->szPage = szPage; + pWal->nCkpt = sqlite3Get4byte(&aBuf[12]); + memcpy(&pWal->hdr.aSalt, &aBuf[16], 8); + + /* Verify that the WAL header checksum is correct */ + walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN, + aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum + ); + if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24]) + || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28]) + ){ + goto finished; + } + + /* Verify that the version number on the WAL format is one that + ** are able to understand */ + version = sqlite3Get4byte(&aBuf[4]); + if( version!=WAL_MAX_VERSION ){ + rc = SQLITE_CANTOPEN_BKPT; + goto finished; + } + + /* Malloc a buffer to read frames into. */ + szFrame = szPage + WAL_FRAME_HDRSIZE; + aFrame = (u8 *)sqlite3_malloc64(szFrame); + if( !aFrame ){ + rc = SQLITE_NOMEM_BKPT; + goto recovery_error; + } + aData = &aFrame[WAL_FRAME_HDRSIZE]; + + /* Read all frames from the log file. */ + iFrame = 0; + for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){ + u32 pgno; /* Database page number for frame */ + u32 nTruncate; /* dbsize field from frame header */ + + /* Read and decode the next log frame. */ + iFrame++; + rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); + if( rc!=SQLITE_OK ) break; + isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame); + if( !isValid ) break; + rc = walIndexAppend(pWal, iFrame, pgno); + if( rc!=SQLITE_OK ) break; + + /* If nTruncate is non-zero, this is a commit record. */ + if( nTruncate ){ + pWal->hdr.mxFrame = iFrame; + pWal->hdr.nPage = nTruncate; + pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); + testcase( szPage<=32768 ); + testcase( szPage>=65536 ); + aFrameCksum[0] = pWal->hdr.aFrameCksum[0]; + aFrameCksum[1] = pWal->hdr.aFrameCksum[1]; + } + } + + sqlite3_free(aFrame); + } + +finished: + if( rc==SQLITE_OK ){ + volatile WalCkptInfo *pInfo; + int i; + pWal->hdr.aFrameCksum[0] = aFrameCksum[0]; + pWal->hdr.aFrameCksum[1] = aFrameCksum[1]; + walIndexWriteHdr(pWal); + + /* Reset the checkpoint-header. This is safe because this thread is + ** currently holding locks that exclude all other readers, writers and + ** checkpointers. + */ + pInfo = walCkptInfo(pWal); + pInfo->nBackfill = 0; + pInfo->nBackfillAttempted = pWal->hdr.mxFrame; + pInfo->aReadMark[0] = 0; + for(i=1; iaReadMark[i] = READMARK_NOT_USED; + if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame; + + /* If more than one frame was recovered from the log file, report an + ** event via sqlite3_log(). This is to help with identifying performance + ** problems caused by applications routinely shutting down without + ** checkpointing the log file. + */ + if( pWal->hdr.nPage ){ + sqlite3_log(SQLITE_NOTICE_RECOVER_WAL, + "recovered %d frames from WAL file %s", + pWal->hdr.mxFrame, pWal->zWalName + ); + } + } + +recovery_error: + WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok")); + walUnlockExclusive(pWal, iLock, nLock); + return rc; +} + +/* +** Close an open wal-index. +*/ +static void walIndexClose(Wal *pWal, int isDelete){ + if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ + int i; + for(i=0; inWiData; i++){ + sqlite3_free((void *)pWal->apWiData[i]); + pWal->apWiData[i] = 0; + } + }else{ + sqlite3OsShmUnmap(pWal->pDbFd, isDelete); + } +} + +/* +** Open a connection to the WAL file zWalName. The database file must +** already be opened on connection pDbFd. The buffer that zWalName points +** to must remain valid for the lifetime of the returned Wal* handle. +** +** A SHARED lock should be held on the database file when this function +** is called. The purpose of this SHARED lock is to prevent any other +** client from unlinking the WAL or wal-index file. If another process +** were to do this just after this client opened one of these files, the +** system would be badly broken. +** +** If the log file is successfully opened, SQLITE_OK is returned and +** *ppWal is set to point to a new WAL handle. If an error occurs, +** an SQLite error code is returned and *ppWal is left unmodified. +*/ +SQLITE_PRIVATE int sqlite3WalOpen( + sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ + sqlite3_file *pDbFd, /* The open database file */ + const char *zWalName, /* Name of the WAL file */ + int bNoShm, /* True to run in heap-memory mode */ + i64 mxWalSize, /* Truncate WAL to this size on reset */ + Wal **ppWal /* OUT: Allocated Wal handle */ +){ + int rc; /* Return Code */ + Wal *pRet; /* Object to allocate and return */ + int flags; /* Flags passed to OsOpen() */ + + assert( zWalName && zWalName[0] ); + assert( pDbFd ); + + /* In the amalgamation, the os_unix.c and os_win.c source files come before + ** this source file. Verify that the #defines of the locking byte offsets + ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value. + ** For that matter, if the lock offset ever changes from its initial design + ** value of 120, we need to know that so there is an assert() to check it. + */ + assert( 120==WALINDEX_LOCK_OFFSET ); + assert( 136==WALINDEX_HDR_SIZE ); +#ifdef WIN_SHM_BASE + assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET ); +#endif +#ifdef UNIX_SHM_BASE + assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET ); +#endif + + + /* Allocate an instance of struct Wal to return. */ + *ppWal = 0; + pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile); + if( !pRet ){ + return SQLITE_NOMEM_BKPT; + } + + pRet->pVfs = pVfs; + pRet->pWalFd = (sqlite3_file *)&pRet[1]; + pRet->pDbFd = pDbFd; + pRet->readLock = -1; + pRet->mxWalSize = mxWalSize; + pRet->zWalName = zWalName; + pRet->syncHeader = 1; + pRet->padToSectorBoundary = 1; + pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); + + /* Open file handle on the write-ahead log file. */ + flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); + rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags); + if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){ + pRet->readOnly = WAL_RDONLY; + } + + if( rc!=SQLITE_OK ){ + walIndexClose(pRet, 0); + sqlite3OsClose(pRet->pWalFd); + sqlite3_free(pRet); + }else{ + int iDC = sqlite3OsDeviceCharacteristics(pDbFd); + if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; } + if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){ + pRet->padToSectorBoundary = 0; + } + *ppWal = pRet; + WALTRACE(("WAL%d: opened\n", pRet)); + } + return rc; +} + +/* +** Change the size to which the WAL file is trucated on each reset. +*/ +SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){ + if( pWal ) pWal->mxWalSize = iLimit; +} + +/* +** Find the smallest page number out of all pages held in the WAL that +** has not been returned by any prior invocation of this method on the +** same WalIterator object. Write into *piFrame the frame index where +** that page was last written into the WAL. Write into *piPage the page +** number. +** +** Return 0 on success. If there are no pages in the WAL with a page +** number larger than *piPage, then return 1. +*/ +static int walIteratorNext( + WalIterator *p, /* Iterator */ + u32 *piPage, /* OUT: The page number of the next page */ + u32 *piFrame /* OUT: Wal frame index of next page */ +){ + u32 iMin; /* Result pgno must be greater than iMin */ + u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */ + int i; /* For looping through segments */ + + iMin = p->iPrior; + assert( iMin<0xffffffff ); + for(i=p->nSegment-1; i>=0; i--){ + struct WalSegment *pSegment = &p->aSegment[i]; + while( pSegment->iNextnEntry ){ + u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]]; + if( iPg>iMin ){ + if( iPgiZero + pSegment->aIndex[pSegment->iNext]; + } + break; + } + pSegment->iNext++; + } + } + + *piPage = p->iPrior = iRet; + return (iRet==0xFFFFFFFF); +} + +/* +** This function merges two sorted lists into a single sorted list. +** +** aLeft[] and aRight[] are arrays of indices. The sort key is +** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following +** is guaranteed for all J0 && nRight>0 ); + while( iRight=nRight || aContent[aLeft[iLeft]]=nLeft || aContent[aLeft[iLeft]]>dbpage ); + assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage ); + } + + *paRight = aLeft; + *pnRight = iOut; + memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut); +} + +/* +** Sort the elements in list aList using aContent[] as the sort key. +** Remove elements with duplicate keys, preferring to keep the +** larger aList[] values. +** +** The aList[] entries are indices into aContent[]. The values in +** aList[] are to be sorted so that for all J0 ); + assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) ); + + for(iList=0; iListaList && p->nList<=(1<aList==&aList[iList&~((2<aList, p->nList, &aMerge, &nMerge, aBuffer); + } + aSub[iSub].aList = aMerge; + aSub[iSub].nList = nMerge; + } + + for(iSub++; iSubnList<=(1<aList==&aList[nList&~((2<aList, p->nList, &aMerge, &nMerge, aBuffer); + } + } + assert( aMerge==aList ); + *pnList = nMerge; + +#ifdef SQLITE_DEBUG + { + int i; + for(i=1; i<*pnList; i++){ + assert( aContent[aList[i]] > aContent[aList[i-1]] ); + } + } +#endif +} + +/* +** Free an iterator allocated by walIteratorInit(). +*/ +static void walIteratorFree(WalIterator *p){ + sqlite3_free(p); +} + +/* +** Construct a WalInterator object that can be used to loop over all +** pages in the WAL in ascending order. The caller must hold the checkpoint +** lock. +** +** On success, make *pp point to the newly allocated WalInterator object +** return SQLITE_OK. Otherwise, return an error code. If this routine +** returns an error, the value of *pp is undefined. +** +** The calling routine should invoke walIteratorFree() to destroy the +** WalIterator object when it has finished with it. +*/ +static int walIteratorInit(Wal *pWal, WalIterator **pp){ + WalIterator *p; /* Return value */ + int nSegment; /* Number of segments to merge */ + u32 iLast; /* Last frame in log */ + int nByte; /* Number of bytes to allocate */ + int i; /* Iterator variable */ + ht_slot *aTmp; /* Temp space used by merge-sort */ + int rc = SQLITE_OK; /* Return Code */ + + /* This routine only runs while holding the checkpoint lock. And + ** it only runs if there is actually content in the log (mxFrame>0). + */ + assert( pWal->ckptLock && pWal->hdr.mxFrame>0 ); + iLast = pWal->hdr.mxFrame; + + /* Allocate space for the WalIterator object. */ + nSegment = walFramePage(iLast) + 1; + nByte = sizeof(WalIterator) + + (nSegment-1)*sizeof(struct WalSegment) + + iLast*sizeof(ht_slot); + p = (WalIterator *)sqlite3_malloc64(nByte); + if( !p ){ + return SQLITE_NOMEM_BKPT; + } + memset(p, 0, nByte); + p->nSegment = nSegment; + + /* Allocate temporary space used by the merge-sort routine. This block + ** of memory will be freed before this function returns. + */ + aTmp = (ht_slot *)sqlite3_malloc64( + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) + ); + if( !aTmp ){ + rc = SQLITE_NOMEM_BKPT; + } + + for(i=0; rc==SQLITE_OK && iaSegment[p->nSegment])[iZero]; + iZero++; + + for(j=0; jaSegment[i].iZero = iZero; + p->aSegment[i].nEntry = nEntry; + p->aSegment[i].aIndex = aIndex; + p->aSegment[i].aPgno = (u32 *)aPgno; + } + } + sqlite3_free(aTmp); + + if( rc!=SQLITE_OK ){ + walIteratorFree(p); + } + *pp = p; + return rc; +} + +/* +** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and +** n. If the attempt fails and parameter xBusy is not NULL, then it is a +** busy-handler function. Invoke it and retry the lock until either the +** lock is successfully obtained or the busy-handler returns 0. +*/ +static int walBusyLock( + Wal *pWal, /* WAL connection */ + int (*xBusy)(void*), /* Function to call when busy */ + void *pBusyArg, /* Context argument for xBusyHandler */ + int lockIdx, /* Offset of first byte to lock */ + int n /* Number of bytes to lock */ +){ + int rc; + do { + rc = walLockExclusive(pWal, lockIdx, n); + }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) ); + return rc; +} + +/* +** The cache of the wal-index header must be valid to call this function. +** Return the page-size in bytes used by the database. +*/ +static int walPagesize(Wal *pWal){ + return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); +} + +/* +** The following is guaranteed when this function is called: +** +** a) the WRITER lock is held, +** b) the entire log file has been checkpointed, and +** c) any existing readers are reading exclusively from the database +** file - there are no readers that may attempt to read a frame from +** the log file. +** +** This function updates the shared-memory structures so that the next +** client to write to the database (which may be this one) does so by +** writing frames into the start of the log file. +** +** The value of parameter salt1 is used as the aSalt[1] value in the +** new wal-index header. It should be passed a pseudo-random value (i.e. +** one obtained from sqlite3_randomness()). +*/ +static void walRestartHdr(Wal *pWal, u32 salt1){ + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + int i; /* Loop counter */ + u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ + pWal->nCkpt++; + pWal->hdr.mxFrame = 0; + sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); + memcpy(&pWal->hdr.aSalt[1], &salt1, 4); + walIndexWriteHdr(pWal); + pInfo->nBackfill = 0; + pInfo->nBackfillAttempted = 0; + pInfo->aReadMark[1] = 0; + for(i=2; iaReadMark[i] = READMARK_NOT_USED; + assert( pInfo->aReadMark[0]==0 ); +} + +/* +** Copy as much content as we can from the WAL back into the database file +** in response to an sqlite3_wal_checkpoint() request or the equivalent. +** +** The amount of information copies from WAL to database might be limited +** by active readers. This routine will never overwrite a database page +** that a concurrent reader might be using. +** +** All I/O barrier operations (a.k.a fsyncs) occur in this routine when +** SQLite is in WAL-mode in synchronous=NORMAL. That means that if +** checkpoints are always run by a background thread or background +** process, foreground threads will never block on a lengthy fsync call. +** +** Fsync is called on the WAL before writing content out of the WAL and +** into the database. This ensures that if the new content is persistent +** in the WAL and can be recovered following a power-loss or hard reset. +** +** Fsync is also called on the database file if (and only if) the entire +** WAL content is copied into the database file. This second fsync makes +** it safe to delete the WAL since the new content will persist in the +** database file. +** +** This routine uses and updates the nBackfill field of the wal-index header. +** This is the only routine that will increase the value of nBackfill. +** (A WAL reset or recovery will revert nBackfill to zero, but not increase +** its value.) +** +** The caller must be holding sufficient locks to ensure that no other +** checkpoint is running (in any other thread or process) at the same +** time. +*/ +static int walCheckpoint( + Wal *pWal, /* Wal connection */ + sqlite3 *db, /* Check for interrupts on this handle */ + int eMode, /* One of PASSIVE, FULL or RESTART */ + int (*xBusy)(void*), /* Function to call when busy */ + void *pBusyArg, /* Context argument for xBusyHandler */ + int sync_flags, /* Flags for OsSync() (or 0) */ + u8 *zBuf /* Temporary buffer to use */ +){ + int rc = SQLITE_OK; /* Return code */ + int szPage; /* Database page-size */ + WalIterator *pIter = 0; /* Wal iterator context */ + u32 iDbpage = 0; /* Next database page to write */ + u32 iFrame = 0; /* Wal frame containing data for iDbpage */ + u32 mxSafeFrame; /* Max frame that can be backfilled */ + u32 mxPage; /* Max database page to write */ + int i; /* Loop counter */ + volatile WalCkptInfo *pInfo; /* The checkpoint status information */ + + szPage = walPagesize(pWal); + testcase( szPage<=32768 ); + testcase( szPage>=65536 ); + pInfo = walCkptInfo(pWal); + if( pInfo->nBackfillhdr.mxFrame ){ + + /* Allocate the iterator */ + rc = walIteratorInit(pWal, &pIter); + if( rc!=SQLITE_OK ){ + return rc; + } + assert( pIter ); + + /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked + ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ + assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); + + /* Compute in mxSafeFrame the index of the last frame of the WAL that is + ** safe to write into the database. Frames beyond mxSafeFrame might + ** overwrite database pages that are in use by active readers and thus + ** cannot be backfilled from the WAL. + */ + mxSafeFrame = pWal->hdr.mxFrame; + mxPage = pWal->hdr.nPage; + for(i=1; iaReadMark[i]; + if( mxSafeFrame>y ){ + assert( y<=pWal->hdr.mxFrame ); + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); + if( rc==SQLITE_OK ){ + pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED); + walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); + }else if( rc==SQLITE_BUSY ){ + mxSafeFrame = y; + xBusy = 0; + }else{ + goto walcheckpoint_out; + } + } + } + + if( pInfo->nBackfillnBackfill; + + pInfo->nBackfillAttempted = mxSafeFrame; + + /* Sync the WAL to disk */ + if( sync_flags ){ + rc = sqlite3OsSync(pWal->pWalFd, 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. + */ + if( rc==SQLITE_OK ){ + i64 nReq = ((i64)mxPage * szPage); + rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); + if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + } + } + + + /* Iterate through the contents of the WAL, copying data to the db file */ + while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ + i64 iOffset; + assert( walFramePgno(pWal, iFrame)==iDbpage ); + if( db->u1.isInterrupted ){ + rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; + break; + } + if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ + continue; + } + iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; + /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ + rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + iOffset = (iDbpage-1)*(i64)szPage; + testcase( IS_BIG_INT(iOffset) ); + rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + } + + /* If work was actually accomplished... */ + if( rc==SQLITE_OK ){ + if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ + 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 ){ + pInfo->nBackfill = mxSafeFrame; + } + } + + /* Release the reader lock held while backfilling */ + walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); + } + + if( rc==SQLITE_BUSY ){ + /* Reset the return code so as not to report a checkpoint failure + ** just because there are active readers. */ + rc = SQLITE_OK; + } + } + + /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the + ** entire wal file has been copied into the database file, then block + ** until all readers have finished using the wal file. This ensures that + ** the next process to write to the database restarts the wal file. + */ + if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ + assert( pWal->writeLock ); + if( pInfo->nBackfillhdr.mxFrame ){ + rc = SQLITE_BUSY; + }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ + u32 salt1; + sqlite3_randomness(4, &salt1); + assert( pInfo->nBackfill==pWal->hdr.mxFrame ); + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); + if( rc==SQLITE_OK ){ + if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ + /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as + ** SQLITE_CHECKPOINT_RESTART with the addition that it also + ** truncates the log file to zero bytes just prior to a + ** successful return. + ** + ** In theory, it might be safe to do this without updating the + ** wal-index header in shared memory, as all subsequent reader or + ** writer clients should see that the entire log file has been + ** checkpointed and behave accordingly. This seems unsafe though, + ** as it would leave the system in a state where the contents of + ** the wal-index header do not match the contents of the + ** file-system. To avoid this, update the wal-index header to + ** indicate that the log file contains zero valid frames. */ + walRestartHdr(pWal, salt1); + rc = sqlite3OsTruncate(pWal->pWalFd, 0); + } + walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); + } + } + } + + walcheckpoint_out: + walIteratorFree(pIter); + return rc; +} + +/* +** If the WAL file is currently larger than nMax bytes in size, truncate +** it to exactly nMax bytes. If an error occurs while doing so, ignore it. +*/ +static void walLimitSize(Wal *pWal, i64 nMax){ + i64 sz; + int rx; + sqlite3BeginBenignMalloc(); + rx = sqlite3OsFileSize(pWal->pWalFd, &sz); + if( rx==SQLITE_OK && (sz > nMax ) ){ + rx = sqlite3OsTruncate(pWal->pWalFd, nMax); + } + sqlite3EndBenignMalloc(); + if( rx ){ + sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName); + } +} + +/* +** Close a connection to a log file. +*/ +SQLITE_PRIVATE int sqlite3WalClose( + Wal *pWal, /* Wal to close */ + sqlite3 *db, /* For interrupt flag */ + int sync_flags, /* Flags to pass to OsSync() (or 0) */ + int nBuf, + u8 *zBuf /* Buffer of at least nBuf bytes */ +){ + int rc = SQLITE_OK; + if( pWal ){ + int isDelete = 0; /* True to unlink wal and wal-index files */ + + /* If an EXCLUSIVE lock can be obtained on the database file (using the + ** ordinary, rollback-mode locking methods, this guarantees that the + ** connection associated with this log file is the only connection to + ** the database. In this case checkpoint the database and unlink both + ** the wal and wal-index files. + ** + ** The EXCLUSIVE lock is not released before returning. + */ + if( zBuf!=0 + && SQLITE_OK==(rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE)) + ){ + if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ + pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; + } + rc = sqlite3WalCheckpoint(pWal, db, + SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 + ); + if( rc==SQLITE_OK ){ + int bPersist = -1; + sqlite3OsFileControlHint( + pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist + ); + if( bPersist!=1 ){ + /* Try to delete the WAL file if the checkpoint completed and + ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal + ** mode (!bPersist) */ + isDelete = 1; + }else if( pWal->mxWalSize>=0 ){ + /* Try to truncate the WAL file to zero bytes if the checkpoint + ** completed and fsynced (rc==SQLITE_OK) and we are in persistent + ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a + ** non-negative value (pWal->mxWalSize>=0). Note that we truncate + ** to zero bytes as truncating to the journal_size_limit might + ** leave a corrupt WAL file on disk. */ + walLimitSize(pWal, 0); + } + } + } + + walIndexClose(pWal, isDelete); + sqlite3OsClose(pWal->pWalFd); + if( isDelete ){ + sqlite3BeginBenignMalloc(); + sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0); + sqlite3EndBenignMalloc(); + } + WALTRACE(("WAL%p: closed\n", pWal)); + sqlite3_free((void *)pWal->apWiData); + sqlite3_free(pWal); + } + return rc; +} + +/* +** Try to read the wal-index header. Return 0 on success and 1 if +** there is a problem. +** +** The wal-index is in shared memory. Another thread or process might +** be writing the header at the same time this procedure is trying to +** read it, which might result in inconsistency. A dirty read is detected +** by verifying that both copies of the header are the same and also by +** a checksum on the header. +** +** If and only if the read is consistent and the header is different from +** pWal->hdr, then pWal->hdr is updated to the content of the new header +** and *pChanged is set to 1. +** +** If the checksum cannot be verified return non-zero. If the header +** is read successfully and the checksum verified, return zero. +*/ +static int walIndexTryHdr(Wal *pWal, int *pChanged){ + u32 aCksum[2]; /* Checksum on the header content */ + WalIndexHdr h1, h2; /* Two copies of the header content */ + WalIndexHdr volatile *aHdr; /* Header in shared memory */ + + /* The first page of the wal-index must be mapped at this point. */ + assert( pWal->nWiData>0 && pWal->apWiData[0] ); + + /* Read the header. This might happen concurrently with a write to the + ** same area of shared memory on a different CPU in a SMP, + ** meaning it is possible that an inconsistent snapshot is read + ** from the file. If this happens, return non-zero. + ** + ** There are two copies of the header at the beginning of the wal-index. + ** When reading, read [0] first then [1]. Writes are in the reverse order. + ** Memory barriers are used to prevent the compiler or the hardware from + ** reordering the reads and writes. + */ + aHdr = walIndexHdr(pWal); + memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); + walShmBarrier(pWal); + memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); + + if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ + return 1; /* Dirty read */ + } + if( h1.isInit==0 ){ + return 1; /* Malformed header - probably all zeros */ + } + walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum); + if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){ + return 1; /* Checksum does not match */ + } + + if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){ + *pChanged = 1; + memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr)); + pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); + testcase( pWal->szPage<=32768 ); + testcase( pWal->szPage>=65536 ); + } + + /* The header was successfully read. Return zero. */ + return 0; +} + +/* +** Read the wal-index header from the wal-index and into pWal->hdr. +** If the wal-header appears to be corrupt, try to reconstruct the +** wal-index from the WAL before returning. +** +** Set *pChanged to 1 if the wal-index header value in pWal->hdr is +** changed by this operation. If pWal->hdr is unchanged, set *pChanged +** to 0. +** +** If the wal-index header is successfully read, return SQLITE_OK. +** Otherwise an SQLite error code. +*/ +static int walIndexReadHdr(Wal *pWal, int *pChanged){ + int rc; /* Return code */ + int badHdr; /* True if a header read failed */ + volatile u32 *page0; /* Chunk of wal-index containing header */ + + /* Ensure that page 0 of the wal-index (the page that contains the + ** wal-index header) is mapped. Return early if an error occurs here. + */ + assert( pChanged ); + rc = walIndexPage(pWal, 0, &page0); + if( rc!=SQLITE_OK ){ + return rc; + }; + assert( page0 || pWal->writeLock==0 ); + + /* If the first page of the wal-index has been mapped, try to read the + ** wal-index header immediately, without holding any lock. This usually + ** works, but may fail if the wal-index header is corrupt or currently + ** being modified by another thread or process. + */ + badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1); + + /* If the first attempt failed, it might have been due to a race + ** with a writer. So get a WRITE lock and try again. + */ + assert( badHdr==0 || pWal->writeLock==0 ); + if( badHdr ){ + if( pWal->readOnly & WAL_SHM_RDONLY ){ + if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){ + walUnlockShared(pWal, WAL_WRITE_LOCK); + rc = SQLITE_READONLY_RECOVERY; + } + }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ + pWal->writeLock = 1; + if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ + badHdr = walIndexTryHdr(pWal, pChanged); + if( badHdr ){ + /* If the wal-index header is still malformed even while holding + ** a WRITE lock, it can only mean that the header is corrupted and + ** needs to be reconstructed. So run recovery to do exactly that. + */ + rc = walIndexRecover(pWal); + *pChanged = 1; + } + } + pWal->writeLock = 0; + walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); + } + } + + /* If the header is read successfully, check the version number to make + ** sure the wal-index was not constructed with some future format that + ** this version of SQLite cannot understand. + */ + if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + return rc; +} + +/* +** This is the value that walTryBeginRead returns when it needs to +** be retried. +*/ +#define WAL_RETRY (-1) + +/* +** Attempt to start a read transaction. This might fail due to a race or +** other transient condition. When that happens, it returns WAL_RETRY to +** indicate to the caller that it is safe to retry immediately. +** +** On success return SQLITE_OK. On a permanent failure (such an +** I/O error or an SQLITE_BUSY because another process is running +** recovery) return a positive error code. +** +** The useWal parameter is true to force the use of the WAL and disable +** the case where the WAL is bypassed because it has been completely +** checkpointed. If useWal==0 then this routine calls walIndexReadHdr() +** to make a copy of the wal-index header into pWal->hdr. If the +** wal-index header has changed, *pChanged is set to 1 (as an indication +** to the caller that the local paget cache is obsolete and needs to be +** flushed.) When useWal==1, the wal-index header is assumed to already +** be loaded and the pChanged parameter is unused. +** +** The caller must set the cnt parameter to the number of prior calls to +** this routine during the current read attempt that returned WAL_RETRY. +** This routine will start taking more aggressive measures to clear the +** race conditions after multiple WAL_RETRY returns, and after an excessive +** number of errors will ultimately return SQLITE_PROTOCOL. The +** SQLITE_PROTOCOL return indicates that some other process has gone rogue +** and is not honoring the locking protocol. There is a vanishingly small +** chance that SQLITE_PROTOCOL could be returned because of a run of really +** bad luck when there is lots of contention for the wal-index, but that +** possibility is so small that it can be safely neglected, we believe. +** +** On success, this routine obtains a read lock on +** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is +** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1) +** that means the Wal does not hold any read lock. The reader must not +** access any database page that is modified by a WAL frame up to and +** including frame number aReadMark[pWal->readLock]. The reader will +** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0 +** Or if pWal->readLock==0, then the reader will ignore the WAL +** completely and get all content directly from the database file. +** If the useWal parameter is 1 then the WAL will never be ignored and +** this routine will always set pWal->readLock>0 on success. +** When the read transaction is completed, the caller must release the +** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1. +** +** This routine uses the nBackfill and aReadMark[] fields of the header +** to select a particular WAL_READ_LOCK() that strives to let the +** checkpoint process do as much work as possible. This routine might +** update values of the aReadMark[] array in the header, but if it does +** so it takes care to hold an exclusive lock on the corresponding +** WAL_READ_LOCK() while changing values. +*/ +static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ + volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ + u32 mxReadMark; /* Largest aReadMark[] value */ + int mxI; /* Index of largest aReadMark[] value */ + int i; /* Loop counter */ + int rc = SQLITE_OK; /* Return code */ + u32 mxFrame; /* Wal frame to lock to */ + + assert( pWal->readLock<0 ); /* Not currently locked */ + + /* Take steps to avoid spinning forever if there is a protocol error. + ** + ** Circumstances that cause a RETRY should only last for the briefest + ** instances of time. No I/O or other system calls are done while the + ** locks are held, so the locks should not be held for very long. But + ** if we are unlucky, another process that is holding a lock might get + ** paged out or take a page-fault that is time-consuming to resolve, + ** during the few nanoseconds that it is holding the lock. In that case, + ** it might take longer than normal for the lock to free. + ** + ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few + ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this + ** is more of a scheduler yield than an actual delay. But on the 10th + ** an subsequent retries, the delays start becoming longer and longer, + ** so that on the 100th (and last) RETRY we delay for 323 milliseconds. + ** The total delay time before giving up is less than 10 seconds. + */ + if( cnt>5 ){ + int nDelay = 1; /* Pause time in microseconds */ + if( cnt>100 ){ + VVA_ONLY( pWal->lockError = 1; ) + return SQLITE_PROTOCOL; + } + if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; + sqlite3OsSleep(pWal->pVfs, nDelay); + } + + if( !useWal ){ + rc = walIndexReadHdr(pWal, pChanged); + if( rc==SQLITE_BUSY ){ + /* If there is not a recovery running in another thread or process + ** then convert BUSY errors to WAL_RETRY. If recovery is known to + ** be running, convert BUSY to BUSY_RECOVERY. There is a race here + ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY + ** would be technically correct. But the race is benign since with + ** WAL_RETRY this routine will be called again and will probably be + ** right on the second iteration. + */ + if( pWal->apWiData[0]==0 ){ + /* This branch is taken when the xShmMap() method returns SQLITE_BUSY. + ** We assume this is a transient condition, so return WAL_RETRY. The + ** xShmMap() implementation used by the default unix and win32 VFS + ** modules may return SQLITE_BUSY due to a race condition in the + ** code that determines whether or not the shared-memory region + ** must be zeroed before the requested page is returned. + */ + rc = WAL_RETRY; + }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){ + walUnlockShared(pWal, WAL_RECOVER_LOCK); + rc = WAL_RETRY; + }else if( rc==SQLITE_BUSY ){ + rc = SQLITE_BUSY_RECOVERY; + } + } + if( rc!=SQLITE_OK ){ + return rc; + } + } + + pInfo = walCkptInfo(pWal); + if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame +#ifdef SQLITE_ENABLE_SNAPSHOT + && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0 + || 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr))) +#endif + ){ + /* The WAL has been completely backfilled (or it is empty). + ** and can be safely ignored. + */ + rc = walLockShared(pWal, WAL_READ_LOCK(0)); + walShmBarrier(pWal); + if( rc==SQLITE_OK ){ + if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ + /* It is not safe to allow the reader to continue here if frames + ** may have been appended to the log before READ_LOCK(0) was obtained. + ** When holding READ_LOCK(0), the reader ignores the entire log file, + ** which implies that the database file contains a trustworthy + ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from + ** happening, this is usually correct. + ** + ** However, if frames have been appended to the log (or if the log + ** is wrapped and written for that matter) before the READ_LOCK(0) + ** is obtained, that is not necessarily true. A checkpointer may + ** have started to backfill the appended frames but crashed before + ** it finished. Leaving a corrupt image in the database file. + */ + walUnlockShared(pWal, WAL_READ_LOCK(0)); + return WAL_RETRY; + } + pWal->readLock = 0; + return SQLITE_OK; + }else if( rc!=SQLITE_BUSY ){ + return rc; + } + } + + /* If we get this far, it means that the reader will want to use + ** the WAL to get at content from recent commits. The job now is + ** to select one of the aReadMark[] entries that is closest to + ** but not exceeding pWal->hdr.mxFrame and lock that entry. + */ + mxReadMark = 0; + mxI = 0; + mxFrame = pWal->hdr.mxFrame; +#ifdef SQLITE_ENABLE_SNAPSHOT + if( pWal->pSnapshot && pWal->pSnapshot->mxFramepSnapshot->mxFrame; + } +#endif + for(i=1; iaReadMark[i]; + if( mxReadMark<=thisMark && thisMark<=mxFrame ){ + assert( thisMark!=READMARK_NOT_USED ); + mxReadMark = thisMark; + mxI = i; + } + } + if( (pWal->readOnly & WAL_SHM_RDONLY)==0 + && (mxReadMarkaReadMark[i] = mxFrame; + mxI = i; + walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); + break; + }else if( rc!=SQLITE_BUSY ){ + return rc; + } + } + } + if( mxI==0 ){ + assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 ); + return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK; + } + + rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); + if( rc ){ + return rc==SQLITE_BUSY ? WAL_RETRY : rc; + } + /* Now that the read-lock has been obtained, check that neither the + ** value in the aReadMark[] array or the contents of the wal-index + ** header have changed. + ** + ** It is necessary to check that the wal-index header did not change + ** between the time it was read and when the shared-lock was obtained + ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility + ** that the log file may have been wrapped by a writer, or that frames + ** that occur later in the log than pWal->hdr.mxFrame may have been + ** copied into the database by a checkpointer. If either of these things + ** happened, then reading the database with the current value of + ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry + ** instead. + ** + ** Before checking that the live wal-index header has not changed + ** since it was read, set Wal.minFrame to the first frame in the wal + ** file that has not yet been checkpointed. This client will not need + ** to read any frames earlier than minFrame from the wal file - they + ** can be safely read directly from the database file. + ** + ** Because a ShmBarrier() call is made between taking the copy of + ** nBackfill and checking that the wal-header in shared-memory still + ** matches the one cached in pWal->hdr, it is guaranteed that the + ** checkpointer that set nBackfill was not working with a wal-index + ** header newer than that cached in pWal->hdr. If it were, that could + ** cause a problem. The checkpointer could omit to checkpoint + ** a version of page X that lies before pWal->minFrame (call that version + ** A) on the basis that there is a newer version (version B) of the same + ** page later in the wal file. But if version B happens to like past + ** frame pWal->hdr.mxFrame - then the client would incorrectly assume + ** that it can read version A from the database file. However, since + ** we can guarantee that the checkpointer that set nBackfill could not + ** see any pages past pWal->hdr.mxFrame, this problem does not come up. + */ + pWal->minFrame = pInfo->nBackfill+1; + walShmBarrier(pWal); + if( pInfo->aReadMark[mxI]!=mxReadMark + || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) + ){ + walUnlockShared(pWal, WAL_READ_LOCK(mxI)); + return WAL_RETRY; + }else{ + assert( mxReadMark<=pWal->hdr.mxFrame ); + pWal->readLock = (i16)mxI; + } + return rc; +} + +#ifdef SQLITE_ENABLE_SNAPSHOT +/* +** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted +** variable so that older snapshots can be accessed. To do this, loop +** through all wal frames from nBackfillAttempted to (nBackfill+1), +** comparing their content to the corresponding page with the database +** file, if any. Set nBackfillAttempted to the frame number of the +** first frame for which the wal file content matches the db file. +** +** This is only really safe if the file-system is such that any page +** writes made by earlier checkpointers were atomic operations, which +** is not always true. It is also possible that nBackfillAttempted +** may be left set to a value larger than expected, if a wal frame +** contains content that duplicate of an earlier version of the same +** page. +** +** SQLITE_OK is returned if successful, or an SQLite error code if an +** error occurs. It is not an error if nBackfillAttempted cannot be +** decreased at all. +*/ +SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ + int rc; + + assert( pWal->readLock>=0 ); + rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); + if( rc==SQLITE_OK ){ + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + int szPage = (int)pWal->szPage; + i64 szDb; /* Size of db file in bytes */ + + rc = sqlite3OsFileSize(pWal->pDbFd, &szDb); + if( rc==SQLITE_OK ){ + void *pBuf1 = sqlite3_malloc(szPage); + void *pBuf2 = sqlite3_malloc(szPage); + if( pBuf1==0 || pBuf2==0 ){ + rc = SQLITE_NOMEM; + }else{ + u32 i = pInfo->nBackfillAttempted; + for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){ + volatile ht_slot *dummy; + volatile u32 *aPgno; /* Array of page numbers */ + u32 iZero; /* Frame corresponding to aPgno[0] */ + u32 pgno; /* Page number in db file */ + i64 iDbOff; /* Offset of db file entry */ + i64 iWalOff; /* Offset of wal file entry */ + + rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero); + if( rc!=SQLITE_OK ) break; + pgno = aPgno[i-iZero]; + iDbOff = (i64)(pgno-1) * szPage; + + if( iDbOff+szPage<=szDb ){ + iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE; + rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff); + + if( rc==SQLITE_OK ){ + rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff); + } + + if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){ + break; + } + } + + pInfo->nBackfillAttempted = i-1; + } + } + + sqlite3_free(pBuf1); + sqlite3_free(pBuf2); + } + walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); + } + + return rc; +} +#endif /* SQLITE_ENABLE_SNAPSHOT */ + +/* +** Begin a read transaction on the database. +** +** This routine used to be called sqlite3OpenSnapshot() and with good reason: +** it takes a snapshot of the state of the WAL and wal-index for the current +** instant in time. The current thread will continue to use this snapshot. +** Other threads might append new content to the WAL and wal-index but +** that extra content is ignored by the current thread. +** +** If the database contents have changes since the previous read +** transaction, then *pChanged is set to 1 before returning. The +** Pager layer will use this to know that is cache is stale and +** needs to be flushed. +*/ +SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ + int rc; /* Return code */ + int cnt = 0; /* Number of TryBeginRead attempts */ + +#ifdef SQLITE_ENABLE_SNAPSHOT + int bChanged = 0; + WalIndexHdr *pSnapshot = pWal->pSnapshot; + if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ + bChanged = 1; + } +#endif + + do{ + rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); + }while( rc==WAL_RETRY ); + testcase( (rc&0xff)==SQLITE_BUSY ); + testcase( (rc&0xff)==SQLITE_IOERR ); + testcase( rc==SQLITE_PROTOCOL ); + testcase( rc==SQLITE_OK ); + +#ifdef SQLITE_ENABLE_SNAPSHOT + if( rc==SQLITE_OK ){ + if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ + /* At this point the client has a lock on an aReadMark[] slot holding + ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr + ** is populated with the wal-index header corresponding to the head + ** of the wal file. Verify that pSnapshot is still valid before + ** continuing. Reasons why pSnapshot might no longer be valid: + ** + ** (1) The WAL file has been reset since the snapshot was taken. + ** In this case, the salt will have changed. + ** + ** (2) A checkpoint as been attempted that wrote frames past + ** pSnapshot->mxFrame into the database file. Note that the + ** checkpoint need not have completed for this to cause problems. + */ + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + + assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 ); + assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame ); + + /* It is possible that there is a checkpointer thread running + ** concurrent with this code. If this is the case, it may be that the + ** checkpointer has already determined that it will checkpoint + ** snapshot X, where X is later in the wal file than pSnapshot, but + ** has not yet set the pInfo->nBackfillAttempted variable to indicate + ** its intent. To avoid the race condition this leads to, ensure that + ** there is no checkpointer process by taking a shared CKPT lock + ** before checking pInfo->nBackfillAttempted. + ** + ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing + ** this already? + */ + rc = walLockShared(pWal, WAL_CKPT_LOCK); + + if( rc==SQLITE_OK ){ + /* Check that the wal file has not been wrapped. Assuming that it has + ** not, also check that no checkpointer has attempted to checkpoint any + ** frames beyond pSnapshot->mxFrame. If either of these conditions are + ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr + ** with *pSnapshot and set *pChanged as appropriate for opening the + ** snapshot. */ + if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) + && pSnapshot->mxFrame>=pInfo->nBackfillAttempted + ){ + assert( pWal->readLock>0 ); + memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); + *pChanged = bChanged; + }else{ + rc = SQLITE_BUSY_SNAPSHOT; + } + + /* Release the shared CKPT lock obtained above. */ + walUnlockShared(pWal, WAL_CKPT_LOCK); + } + + + if( rc!=SQLITE_OK ){ + sqlite3WalEndReadTransaction(pWal); + } + } + } +#endif + return rc; +} + +/* +** Finish with a read transaction. All this does is release the +** read-lock. +*/ +SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){ + sqlite3WalEndWriteTransaction(pWal); + if( pWal->readLock>=0 ){ + walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); + pWal->readLock = -1; + } +} + +/* +** Search the wal file for page pgno. If found, set *piRead to the frame that +** contains the page. Otherwise, if pgno is not in the wal file, set *piRead +** to zero. +** +** Return SQLITE_OK if successful, or an error code if an error occurs. If an +** error does occur, the final value of *piRead is undefined. +*/ +SQLITE_PRIVATE int sqlite3WalFindFrame( + Wal *pWal, /* WAL handle */ + Pgno pgno, /* Database page number to read data for */ + u32 *piRead /* OUT: Frame number (or zero) */ +){ + u32 iRead = 0; /* If !=0, WAL frame to return data from */ + u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */ + int iHash; /* Used to loop through N hash tables */ + int iMinHash; + + /* This routine is only be called from within a read transaction. */ + assert( pWal->readLock>=0 || pWal->lockError ); + + /* If the "last page" field of the wal-index header snapshot is 0, then + ** no data will be read from the wal under any circumstances. Return early + ** in this case as an optimization. Likewise, if pWal->readLock==0, + ** then the WAL is ignored by the reader so return early, as if the + ** WAL were empty. + */ + if( iLast==0 || pWal->readLock==0 ){ + *piRead = 0; + return SQLITE_OK; + } + + /* Search the hash table or tables for an entry matching page number + ** pgno. Each iteration of the following for() loop searches one + ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames). + ** + ** This code might run concurrently to the code in walIndexAppend() + ** that adds entries to the wal-index (and possibly to this hash + ** table). This means the value just read from the hash + ** slot (aHash[iKey]) may have been added before or after the + ** current read transaction was opened. Values added after the + ** read transaction was opened may have been written incorrectly - + ** i.e. these slots may contain garbage data. However, we assume + ** that any slots written before the current read transaction was + ** opened remain unmodified. + ** + ** For the reasons above, the if(...) condition featured in the inner + ** loop of the following block is more stringent that would be required + ** if we had exclusive access to the hash-table: + ** + ** (aPgno[iFrame]==pgno): + ** This condition filters out normal hash-table collisions. + ** + ** (iFrame<=iLast): + ** This condition filters out entries that were added to the hash + ** table after the current read-transaction had started. + */ + iMinHash = walFramePage(pWal->minFrame); + for(iHash=walFramePage(iLast); iHash>=iMinHash && iRead==0; iHash--){ + volatile ht_slot *aHash; /* Pointer to hash table */ + volatile u32 *aPgno; /* Pointer to array of page numbers */ + u32 iZero; /* Frame number corresponding to aPgno[0] */ + int iKey; /* Hash slot index */ + int nCollide; /* Number of hash collisions remaining */ + int rc; /* Error code */ + + rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero); + if( rc!=SQLITE_OK ){ + return rc; + } + nCollide = HASHTABLE_NSLOT; + for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){ + u32 iFrame = aHash[iKey] + iZero; + if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){ + assert( iFrame>iRead || CORRUPT_DB ); + iRead = iFrame; + } + if( (nCollide--)==0 ){ + return SQLITE_CORRUPT_BKPT; + } + } + } + +#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT + /* If expensive assert() statements are available, do a linear search + ** of the wal-index file content. Make sure the results agree with the + ** result obtained using the hash indexes above. */ + { + u32 iRead2 = 0; + u32 iTest; + assert( pWal->minFrame>0 ); + for(iTest=iLast; iTest>=pWal->minFrame; iTest--){ + if( walFramePgno(pWal, iTest)==pgno ){ + iRead2 = iTest; + break; + } + } + assert( iRead==iRead2 ); + } +#endif + + *piRead = iRead; + return SQLITE_OK; +} + +/* +** Read the contents of frame iRead from the wal file into buffer pOut +** (which is nOut bytes in size). Return SQLITE_OK if successful, or an +** error code otherwise. +*/ +SQLITE_PRIVATE int sqlite3WalReadFrame( + Wal *pWal, /* WAL handle */ + u32 iRead, /* Frame to read */ + int nOut, /* Size of buffer pOut in bytes */ + u8 *pOut /* Buffer to write page data to */ +){ + int sz; + i64 iOffset; + sz = pWal->hdr.szPage; + sz = (sz&0xfe00) + ((sz&0x0001)<<16); + testcase( sz<=32768 ); + testcase( sz>=65536 ); + iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE; + /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */ + return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset); +} + +/* +** Return the size of the database in pages (or zero, if unknown). +*/ +SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){ + if( pWal && ALWAYS(pWal->readLock>=0) ){ + return pWal->hdr.nPage; + } + return 0; +} + + +/* +** This function starts a write transaction on the WAL. +** +** A read transaction must have already been started by a prior call +** to sqlite3WalBeginReadTransaction(). +** +** If another thread or process has written into the database since +** the read transaction was started, then it is not possible for this +** thread to write as doing so would cause a fork. So this routine +** returns SQLITE_BUSY in that case and no write transaction is started. +** +** There can only be a single writer active at a time. +*/ +SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ + int rc; + + /* Cannot start a write transaction without first holding a read + ** transaction. */ + assert( pWal->readLock>=0 ); + assert( pWal->writeLock==0 && pWal->iReCksum==0 ); + + if( pWal->readOnly ){ + return SQLITE_READONLY; + } + + /* Only one writer allowed at a time. Get the write lock. Return + ** SQLITE_BUSY if unable. + */ + rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); + if( rc ){ + return rc; + } + pWal->writeLock = 1; + + /* If another connection has written to the database file since the + ** time the read transaction on this connection was started, then + ** the write is disallowed. + */ + if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){ + walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); + pWal->writeLock = 0; + rc = SQLITE_BUSY_SNAPSHOT; + } + + return rc; +} + +/* +** End a write transaction. The commit has already been done. This +** routine merely releases the lock. +*/ +SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){ + if( pWal->writeLock ){ + walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); + pWal->writeLock = 0; + pWal->iReCksum = 0; + pWal->truncateOnCommit = 0; + } + return SQLITE_OK; +} + +/* +** If any data has been written (but not committed) to the log file, this +** function moves the write-pointer back to the start of the transaction. +** +** Additionally, the callback function is invoked for each frame written +** to the WAL since the start of the transaction. If the callback returns +** other than SQLITE_OK, it is not invoked again and the error code is +** returned to the caller. +** +** Otherwise, if the callback function does not return an error, this +** function returns SQLITE_OK. +*/ +SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){ + int rc = SQLITE_OK; + if( ALWAYS(pWal->writeLock) ){ + Pgno iMax = pWal->hdr.mxFrame; + Pgno iFrame; + + /* Restore the clients cache of the wal-index header to the state it + ** was in before the client began writing to the database. + */ + memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); + + for(iFrame=pWal->hdr.mxFrame+1; + ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; + iFrame++ + ){ + /* This call cannot fail. Unless the page for which the page number + ** is passed as the second argument is (a) in the cache and + ** (b) has an outstanding reference, then xUndo is either a no-op + ** (if (a) is false) or simply expels the page from the cache (if (b) + ** is false). + ** + ** If the upper layer is doing a rollback, it is guaranteed that there + ** are no outstanding references to any page other than page 1. And + ** page 1 is never written to the log until the transaction is + ** committed. As a result, the call to xUndo may not fail. + */ + assert( walFramePgno(pWal, iFrame)!=1 ); + rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame)); + } + if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); + } + return rc; +} + +/* +** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 +** values. This function populates the array with values required to +** "rollback" the write position of the WAL handle back to the current +** point in the event of a savepoint rollback (via WalSavepointUndo()). +*/ +SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){ + assert( pWal->writeLock ); + aWalData[0] = pWal->hdr.mxFrame; + aWalData[1] = pWal->hdr.aFrameCksum[0]; + aWalData[2] = pWal->hdr.aFrameCksum[1]; + aWalData[3] = pWal->nCkpt; +} + +/* +** Move the write position of the WAL back to the point identified by +** the values in the aWalData[] array. aWalData must point to an array +** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated +** by a call to WalSavepoint(). +*/ +SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){ + int rc = SQLITE_OK; + + assert( pWal->writeLock ); + assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame ); + + if( aWalData[3]!=pWal->nCkpt ){ + /* This savepoint was opened immediately after the write-transaction + ** was started. Right after that, the writer decided to wrap around + ** to the start of the log. Update the savepoint values to match. + */ + aWalData[0] = 0; + aWalData[3] = pWal->nCkpt; + } + + if( aWalData[0]hdr.mxFrame ){ + pWal->hdr.mxFrame = aWalData[0]; + pWal->hdr.aFrameCksum[0] = aWalData[1]; + pWal->hdr.aFrameCksum[1] = aWalData[2]; + walCleanupHash(pWal); + } + + return rc; +} + +/* +** This function is called just before writing a set of frames to the log +** file (see sqlite3WalFrames()). It checks to see if, instead of appending +** to the current log file, it is possible to overwrite the start of the +** existing log file with the new frames (i.e. "reset" the log). If so, +** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left +** unchanged. +** +** SQLITE_OK is returned if no error is encountered (regardless of whether +** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned +** if an error occurs. +*/ +static int walRestartLog(Wal *pWal){ + int rc = SQLITE_OK; + int cnt; + + if( pWal->readLock==0 ){ + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + assert( pInfo->nBackfill==pWal->hdr.mxFrame ); + if( pInfo->nBackfill>0 ){ + u32 salt1; + sqlite3_randomness(4, &salt1); + rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); + if( rc==SQLITE_OK ){ + /* If all readers are using WAL_READ_LOCK(0) (in other words if no + ** readers are currently using the WAL), then the transactions + ** frames will overwrite the start of the existing log. Update the + ** wal-index header to reflect this. + ** + ** In theory it would be Ok to update the cache of the header only + ** at this point. But updating the actual wal-index header is also + ** safe and means there is no special case for sqlite3WalUndo() + ** to handle if this transaction is rolled back. */ + walRestartHdr(pWal, salt1); + walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); + }else if( rc!=SQLITE_BUSY ){ + return rc; + } + } + walUnlockShared(pWal, WAL_READ_LOCK(0)); + pWal->readLock = -1; + cnt = 0; + do{ + int notUsed; + rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt); + }while( rc==WAL_RETRY ); + assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */ + testcase( (rc&0xff)==SQLITE_IOERR ); + testcase( rc==SQLITE_PROTOCOL ); + testcase( rc==SQLITE_OK ); + } + return rc; +} + +/* +** Information about the current state of the WAL file and where +** the next fsync should occur - passed from sqlite3WalFrames() into +** walWriteToLog(). +*/ +typedef struct WalWriter { + Wal *pWal; /* The complete WAL information */ + sqlite3_file *pFd; /* The WAL file to which we write */ + sqlite3_int64 iSyncPoint; /* Fsync at this offset */ + int syncFlags; /* Flags for the fsync */ + int szPage; /* Size of one page */ +} WalWriter; + +/* +** Write iAmt bytes of content into the WAL file beginning at iOffset. +** Do a sync when crossing the p->iSyncPoint boundary. +** +** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt, +** first write the part before iSyncPoint, then sync, then write the +** rest. +*/ +static int walWriteToLog( + WalWriter *p, /* WAL to write to */ + void *pContent, /* Content to be written */ + int iAmt, /* Number of bytes to write */ + sqlite3_int64 iOffset /* Start writing at this offset */ +){ + int rc; + if( iOffsetiSyncPoint && iOffset+iAmt>=p->iSyncPoint ){ + int iFirstAmt = (int)(p->iSyncPoint - iOffset); + rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset); + if( rc ) return rc; + 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); + if( iAmt==0 || rc ) return rc; + } + rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); + return rc; +} + +/* +** Write out a single frame of the WAL +*/ +static int walWriteOneFrame( + WalWriter *p, /* Where to write the frame */ + PgHdr *pPage, /* The page of the frame to be written */ + int nTruncate, /* The commit flag. Usually 0. >0 for commit */ + sqlite3_int64 iOffset /* Byte offset at which to write */ +){ + int rc; /* Result code from subfunctions */ + void *pData; /* Data actually written */ + u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ +#if defined(SQLITE_HAS_CODEC) + if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; +#else + pData = pPage->pData; +#endif + walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); + rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); + if( rc ) return rc; + /* Write the page data */ + rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame)); + return rc; +} + +/* +** This function is called as part of committing a transaction within which +** one or more frames have been overwritten. It updates the checksums for +** all frames written to the wal file by the current transaction starting +** with the earliest to have been overwritten. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int walRewriteChecksums(Wal *pWal, u32 iLast){ + const int szPage = pWal->szPage;/* Database page size */ + int rc = SQLITE_OK; /* Return code */ + u8 *aBuf; /* Buffer to load data from wal file into */ + u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */ + u32 iRead; /* Next frame to read from wal file */ + i64 iCksumOff; + + aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE); + if( aBuf==0 ) return SQLITE_NOMEM_BKPT; + + /* Find the checksum values to use as input for the recalculating the + ** first checksum. If the first frame is frame 1 (implying that the current + ** transaction restarted the wal file), these values must be read from the + ** wal-file header. Otherwise, read them from the frame header of the + ** previous frame. */ + assert( pWal->iReCksum>0 ); + if( pWal->iReCksum==1 ){ + iCksumOff = 24; + }else{ + iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16; + } + rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff); + pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf); + pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]); + + iRead = pWal->iReCksum; + pWal->iReCksum = 0; + for(; rc==SQLITE_OK && iRead<=iLast; iRead++){ + i64 iOff = walFrameOffset(iRead, szPage); + rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff); + if( rc==SQLITE_OK ){ + u32 iPgno, nDbSize; + iPgno = sqlite3Get4byte(aBuf); + nDbSize = sqlite3Get4byte(&aBuf[4]); + + walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame); + rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff); + } + } + + sqlite3_free(aBuf); + return rc; +} + +/* +** Write a set of frames to the log. The caller must hold the write-lock +** on the log file (obtained using sqlite3WalBeginWriteTransaction()). +*/ +SQLITE_PRIVATE int sqlite3WalFrames( + Wal *pWal, /* Wal handle to write to */ + int szPage, /* Database page-size in bytes */ + PgHdr *pList, /* List of dirty pages to write */ + Pgno nTruncate, /* Database size after this commit */ + int isCommit, /* True if this is a commit */ + int sync_flags /* Flags to pass to OsSync() (or 0) */ +){ + int rc; /* Used to catch return codes */ + u32 iFrame; /* Next frame address */ + PgHdr *p; /* Iterator to run through pList with. */ + PgHdr *pLast = 0; /* Last frame in list */ + int nExtra = 0; /* Number of extra copies of last page */ + int szFrame; /* The size of a single frame */ + i64 iOffset; /* Next byte to write in WAL file */ + WalWriter w; /* The writer */ + u32 iFirst = 0; /* First frame that may be overwritten */ + WalIndexHdr *pLive; /* Pointer to shared header */ + + assert( pList ); + assert( pWal->writeLock ); + + /* If this frame set completes a transaction, then nTruncate>0. If + ** nTruncate==0 then this frame set does not complete the transaction. */ + assert( (isCommit!=0)==(nTruncate!=0) ); + +#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) + { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){} + WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n", + pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill")); + } +#endif + + pLive = (WalIndexHdr*)walIndexHdr(pWal); + if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){ + iFirst = pLive->mxFrame+1; + } + + /* See if it is possible to write these frames into the start of the + ** log file, instead of appending to it at pWal->hdr.mxFrame. + */ + if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){ + return rc; + } + + /* If this is the first frame written into the log, write the WAL + ** header to the start of the WAL file. See comments at the top of + ** this source file for a description of the WAL header format. + */ + iFrame = pWal->hdr.mxFrame; + if( iFrame==0 ){ + u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */ + u32 aCksum[2]; /* Checksum for wal-header */ + + sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN)); + sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION); + sqlite3Put4byte(&aWalHdr[8], szPage); + sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt); + if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt); + memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8); + walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum); + sqlite3Put4byte(&aWalHdr[24], aCksum[0]); + sqlite3Put4byte(&aWalHdr[28], aCksum[1]); + + pWal->szPage = szPage; + pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN; + pWal->hdr.aFrameCksum[0] = aCksum[0]; + pWal->hdr.aFrameCksum[1] = aCksum[1]; + pWal->truncateOnCommit = 1; + + rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0); + WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok")); + if( rc!=SQLITE_OK ){ + return rc; + } + + /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless + ** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise + ** an out-of-order write following a WAL restart could result in + ** database corruption. See the ticket: + ** + ** http://localhost:591/sqlite/info/ff5be73dee + */ + if( pWal->syncHeader && sync_flags ){ + rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK); + if( rc ) return rc; + } + } + assert( (int)pWal->szPage==szPage ); + + /* Setup information needed to write frames into the WAL */ + w.pWal = pWal; + w.pFd = pWal->pWalFd; + w.iSyncPoint = 0; + w.syncFlags = sync_flags; + w.szPage = szPage; + iOffset = walFrameOffset(iFrame+1, szPage); + szFrame = szPage + WAL_FRAME_HDRSIZE; + + /* Write all frames into the log file exactly once */ + for(p=pList; p; p=p->pDirty){ + int nDbSize; /* 0 normally. Positive == commit flag */ + + /* Check if this page has already been written into the wal file by + ** the current transaction. If so, overwrite the existing frame and + ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that + ** checksums must be recomputed when the transaction is committed. */ + if( iFirst && (p->pDirty || isCommit==0) ){ + u32 iWrite = 0; + VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite); + assert( rc==SQLITE_OK || iWrite==0 ); + if( iWrite>=iFirst ){ + i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; + void *pData; + if( pWal->iReCksum==0 || iWriteiReCksum ){ + pWal->iReCksum = iWrite; + } +#if defined(SQLITE_HAS_CODEC) + if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; +#else + pData = p->pData; +#endif + rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); + if( rc ) return rc; + p->flags &= ~PGHDR_WAL_APPEND; + continue; + } + } + + iFrame++; + assert( iOffset==walFrameOffset(iFrame, szPage) ); + nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0; + rc = walWriteOneFrame(&w, p, nDbSize, iOffset); + if( rc ) return rc; + pLast = p; + iOffset += szFrame; + p->flags |= PGHDR_WAL_APPEND; + } + + /* Recalculate checksums within the wal file if required. */ + if( isCommit && pWal->iReCksum ){ + rc = walRewriteChecksums(pWal, iFrame); + if( rc ) return rc; + } + + /* If this is the end of a transaction, then we might need to pad + ** the transaction and/or sync the WAL file. + ** + ** Padding and syncing only occur if this set of frames complete a + ** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL + ** or synchronous==OFF, then no padding or syncing are needed. + ** + ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not + ** needed and only the sync is done. If padding is needed, then the + ** final frame is repeated (with its commit mark) until the next sector + ** boundary is crossed. Only the part of the WAL prior to the last + ** 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 ){ + int bSync = 1; + if( pWal->padToSectorBoundary ){ + int sectorSize = sqlite3SectorSize(pWal->pWalFd); + w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; + bSync = (w.iSyncPoint==iOffset); + testcase( bSync ); + while( iOffsettruncateOnCommit && pWal->mxWalSize>=0 ){ + i64 sz = pWal->mxWalSize; + if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){ + sz = walFrameOffset(iFrame+nExtra+1, szPage); + } + walLimitSize(pWal, sz); + pWal->truncateOnCommit = 0; + } + + /* Append data to the wal-index. It is not necessary to lock the + ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index + ** guarantees that there are no other writers, and no data that may + ** be in use by existing readers is being overwritten. + */ + iFrame = pWal->hdr.mxFrame; + for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){ + if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; + iFrame++; + rc = walIndexAppend(pWal, iFrame, p->pgno); + } + while( rc==SQLITE_OK && nExtra>0 ){ + iFrame++; + nExtra--; + rc = walIndexAppend(pWal, iFrame, pLast->pgno); + } + + if( rc==SQLITE_OK ){ + /* Update the private copy of the header. */ + pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); + testcase( szPage<=32768 ); + testcase( szPage>=65536 ); + pWal->hdr.mxFrame = iFrame; + if( isCommit ){ + pWal->hdr.iChange++; + pWal->hdr.nPage = nTruncate; + } + /* If this is a commit, update the wal-index header too. */ + if( isCommit ){ + walIndexWriteHdr(pWal); + pWal->iCallback = iFrame; + } + } + + WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok")); + return rc; +} + +/* +** This routine is called to implement sqlite3_wal_checkpoint() and +** related interfaces. +** +** Obtain a CHECKPOINT lock and then backfill as much information as +** we can from WAL into the database. +** +** If parameter xBusy is not NULL, it is a pointer to a busy-handler +** callback. In this case this function runs a blocking checkpoint. +*/ +SQLITE_PRIVATE int sqlite3WalCheckpoint( + Wal *pWal, /* Wal connection */ + sqlite3 *db, /* Check this handle's interrupt flag */ + int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */ + int (*xBusy)(void*), /* Function to call when busy */ + void *pBusyArg, /* Context argument for xBusyHandler */ + int sync_flags, /* Flags to sync db file with (or 0) */ + int nBuf, /* Size of temporary buffer */ + u8 *zBuf, /* Temporary buffer to use */ + int *pnLog, /* OUT: Number of frames in WAL */ + int *pnCkpt /* OUT: Number of backfilled frames in WAL */ +){ + int rc; /* Return code */ + int isChanged = 0; /* True if a new wal-index header is loaded */ + int eMode2 = eMode; /* Mode to pass to walCheckpoint() */ + int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */ + + assert( pWal->ckptLock==0 ); + assert( pWal->writeLock==0 ); + + /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked + ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ + assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); + + if( pWal->readOnly ) return SQLITE_READONLY; + WALTRACE(("WAL%p: checkpoint begins\n", pWal)); + + /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive + ** "checkpoint" lock on the database file. */ + rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); + if( rc ){ + /* EVIDENCE-OF: R-10421-19736 If any other process is running a + ** checkpoint operation at the same time, the lock cannot be obtained and + ** SQLITE_BUSY is returned. + ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, + ** it will not be invoked in this case. + */ + testcase( rc==SQLITE_BUSY ); + testcase( xBusy!=0 ); + return rc; + } + pWal->ckptLock = 1; + + /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and + ** TRUNCATE modes also obtain the exclusive "writer" lock on the database + ** file. + ** + ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained + ** immediately, and a busy-handler is configured, it is invoked and the + ** writer lock retried until either the busy-handler returns 0 or the + ** lock is successfully obtained. + */ + if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1); + if( rc==SQLITE_OK ){ + pWal->writeLock = 1; + }else if( rc==SQLITE_BUSY ){ + eMode2 = SQLITE_CHECKPOINT_PASSIVE; + xBusy2 = 0; + rc = SQLITE_OK; + } + } + + /* Read the wal-index header. */ + if( rc==SQLITE_OK ){ + rc = walIndexReadHdr(pWal, &isChanged); + if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ + sqlite3OsUnfetch(pWal->pDbFd, 0, 0); + } + } + + /* Copy data from the log to the database file. */ + if( rc==SQLITE_OK ){ + + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); + } + + /* If no error occurred, set the output variables. */ + if( rc==SQLITE_OK || rc==SQLITE_BUSY ){ + if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame; + if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill); + } + } + + if( isChanged ){ + /* If a new wal-index header was loaded before the checkpoint was + ** performed, then the pager-cache associated with pWal is now + ** out of date. So zero the cached wal-index header to ensure that + ** next time the pager opens a snapshot on this database it knows that + ** the cache needs to be reset. + */ + memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); + } + + /* Release the locks. */ + sqlite3WalEndWriteTransaction(pWal); + walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); + pWal->ckptLock = 0; + WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); + return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc); +} + +/* Return the value to pass to a sqlite3_wal_hook callback, the +** number of frames in the WAL at the point of the last commit since +** sqlite3WalCallback() was called. If no commits have occurred since +** the last call, then return 0. +*/ +SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){ + u32 ret = 0; + if( pWal ){ + ret = pWal->iCallback; + pWal->iCallback = 0; + } + return (int)ret; +} + +/* +** This function is called to change the WAL subsystem into or out +** of locking_mode=EXCLUSIVE. +** +** If op is zero, then attempt to change from locking_mode=EXCLUSIVE +** into locking_mode=NORMAL. This means that we must acquire a lock +** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL +** or if the acquisition of the lock fails, then return 0. If the +** transition out of exclusive-mode is successful, return 1. This +** operation must occur while the pager is still holding the exclusive +** lock on the main database file. +** +** If op is one, then change from locking_mode=NORMAL into +** locking_mode=EXCLUSIVE. This means that the pWal->readLock must +** be released. Return 1 if the transition is made and 0 if the +** WAL is already in exclusive-locking mode - meaning that this +** routine is a no-op. The pager must already hold the exclusive lock +** on the main database file before invoking this operation. +** +** If op is negative, then do a dry-run of the op==1 case but do +** not actually change anything. The pager uses this to see if it +** should acquire the database exclusive lock prior to invoking +** the op==1 case. +*/ +SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){ + int rc; + assert( pWal->writeLock==0 ); + assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 ); + + /* pWal->readLock is usually set, but might be -1 if there was a + ** prior error while attempting to acquire are read-lock. This cannot + ** happen if the connection is actually in exclusive mode (as no xShmLock + ** locks are taken in this case). Nor should the pager attempt to + ** upgrade to exclusive-mode following such an error. + */ + assert( pWal->readLock>=0 || pWal->lockError ); + assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) ); + + if( op==0 ){ + if( pWal->exclusiveMode ){ + pWal->exclusiveMode = 0; + if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){ + pWal->exclusiveMode = 1; + } + rc = pWal->exclusiveMode==0; + }else{ + /* Already in locking_mode=NORMAL */ + rc = 0; + } + }else if( op>0 ){ + assert( pWal->exclusiveMode==0 ); + assert( pWal->readLock>=0 ); + walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); + pWal->exclusiveMode = 1; + rc = 1; + }else{ + rc = pWal->exclusiveMode==0; + } + return rc; +} + +/* +** Return true if the argument is non-NULL and the WAL module is using +** heap-memory for the wal-index. Otherwise, if the argument is NULL or the +** WAL module is using shared-memory, return false. +*/ +SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){ + return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ); +} + +#ifdef SQLITE_ENABLE_SNAPSHOT +/* Create a snapshot object. The content of a snapshot is opaque to +** every other subsystem, so the WAL module can put whatever it needs +** in the object. +*/ +SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){ + int rc = SQLITE_OK; + WalIndexHdr *pRet; + static const u32 aZero[4] = { 0, 0, 0, 0 }; + + assert( pWal->readLock>=0 && pWal->writeLock==0 ); + + if( memcmp(&pWal->hdr.aFrameCksum[0],aZero,16)==0 ){ + *ppSnapshot = 0; + return SQLITE_ERROR; + } + pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr)); + if( pRet==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr)); + *ppSnapshot = (sqlite3_snapshot*)pRet; + } + + return rc; +} + +/* Try to open on pSnapshot when the next read-transaction starts +*/ +SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){ + pWal->pSnapshot = (WalIndexHdr*)pSnapshot; +} + +/* +** Return a +ve value if snapshot p1 is newer than p2. A -ve value if +** p1 is older than p2 and zero if p1 and p2 are the same snapshot. +*/ +SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){ + WalIndexHdr *pHdr1 = (WalIndexHdr*)p1; + WalIndexHdr *pHdr2 = (WalIndexHdr*)p2; + + /* aSalt[0] is a copy of the value stored in the wal file header. It + ** is incremented each time the wal file is restarted. */ + if( pHdr1->aSalt[0]aSalt[0] ) return -1; + if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1; + if( pHdr1->mxFramemxFrame ) return -1; + if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1; + return 0; +} +#endif /* SQLITE_ENABLE_SNAPSHOT */ + +#ifdef SQLITE_ENABLE_ZIPVFS +/* +** If the argument is not NULL, it points to a Wal object that holds a +** read-lock. This function returns the database page-size if it is known, +** or zero if it is not (or if pWal is NULL). +*/ +SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){ + assert( pWal==0 || pWal->readLock>=0 ); + return (pWal ? pWal->szPage : 0); +} +#endif + +/* Return the sqlite3_file object for the WAL file +*/ +SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){ + return pWal->pWalFd; +} + +#endif /* #ifndef SQLITE_OMIT_WAL */ + +/************** End of wal.c *************************************************/ +/************** Begin file btmutex.c *****************************************/ +/* +** 2007 August 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file contains code used to implement mutexes on Btree objects. +** This code really belongs in btree.c. But btree.c is getting too +** big and we want to break it down some. This packaged seemed like +** a good breakout. +*/ +/************** Include btreeInt.h in the middle of btmutex.c ****************/ +/************** Begin file btreeInt.h ****************************************/ +/* +** 2004 April 6 +** +** 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 external (disk-based) database using BTrees. +** For a detailed discussion of BTrees, refer to +** +** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: +** "Sorting And Searching", pages 473-480. Addison-Wesley +** Publishing Company, Reading, Massachusetts. +** +** The basic idea is that each page of the file contains N database +** entries and N+1 pointers to subpages. +** +** ---------------------------------------------------------------- +** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) | +** ---------------------------------------------------------------- +** +** All of the keys on the page that Ptr(0) points to have values less +** than Key(0). All of the keys on page Ptr(1) and its subpages have +** values greater than Key(0) and less than Key(1). All of the keys +** on Ptr(N) and its subpages have values greater than Key(N-1). And +** so forth. +** +** Finding a particular key requires reading O(log(M)) pages from the +** disk where M is the number of entries in the tree. +** +** In this implementation, a single file can hold one or more separate +** BTrees. Each BTree is identified by the index of its root page. The +** key and data for any entry are combined to form the "payload". A +** fixed amount of payload can be carried directly on the database +** page. If the payload is larger than the preset amount then surplus +** bytes are stored on overflow pages. The payload for an entry +** and the preceding pointer are combined to form a "Cell". Each +** page has a small header which contains the Ptr(N) pointer and other +** information such as the size of key and data. +** +** FORMAT DETAILS +** +** The file is divided into pages. The first page is called page 1, +** the second is page 2, and so forth. A page number of zero indicates +** "no such page". The page size can be any power of 2 between 512 and 65536. +** Each page can be either a btree page, a freelist page, an overflow +** page, or a pointer-map page. +** +** The first page is always a btree page. The first 100 bytes of the first +** page contain a special header (the "file header") that describes the file. +** The format of the file header is as follows: +** +** OFFSET SIZE DESCRIPTION +** 0 16 Header string: "SQLite format 3\000" +** 16 2 Page size in bytes. (1 means 65536) +** 18 1 File format write version +** 19 1 File format read version +** 20 1 Bytes of unused space at the end of each page +** 21 1 Max embedded payload fraction (must be 64) +** 22 1 Min embedded payload fraction (must be 32) +** 23 1 Min leaf payload fraction (must be 32) +** 24 4 File change counter +** 28 4 Reserved for future use +** 32 4 First freelist page +** 36 4 Number of freelist pages in the file +** 40 60 15 4-byte meta values passed to higher layers +** +** 40 4 Schema cookie +** 44 4 File format of schema layer +** 48 4 Size of page cache +** 52 4 Largest root-page (auto/incr_vacuum) +** 56 4 1=UTF-8 2=UTF16le 3=UTF16be +** 60 4 User version +** 64 4 Incremental vacuum mode +** 68 4 Application-ID +** 72 20 unused +** 92 4 The version-valid-for number +** 96 4 SQLITE_VERSION_NUMBER +** +** All of the integer values are big-endian (most significant byte first). +** +** The file change counter is incremented when the database is changed +** This counter allows other processes to know when the file has changed +** and thus when they need to flush their cache. +** +** The max embedded payload fraction is the amount of the total usable +** space in a page that can be consumed by a single cell for standard +** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default +** is to limit the maximum cell size so that at least 4 cells will fit +** on one page. Thus the default max embedded payload fraction is 64. +** +** If the payload for a cell is larger than the max payload, then extra +** payload is spilled to overflow pages. Once an overflow page is allocated, +** as many bytes as possible are moved into the overflow pages without letting +** the cell size drop below the min embedded payload fraction. +** +** The min leaf payload fraction is like the min embedded payload fraction +** except that it applies to leaf nodes in a LEAFDATA tree. The maximum +** payload fraction for a LEAFDATA tree is always 100% (or 255) and it +** not specified in the header. +** +** Each btree pages is divided into three sections: The header, the +** cell pointer array, and the cell content area. Page 1 also has a 100-byte +** file header that occurs before the page header. +** +** |----------------| +** | file header | 100 bytes. Page 1 only. +** |----------------| +** | page header | 8 bytes for leaves. 12 bytes for interior nodes +** |----------------| +** | cell pointer | | 2 bytes per cell. Sorted order. +** | array | | Grows downward +** | | v +** |----------------| +** | unallocated | +** | space | +** |----------------| ^ Grows upwards +** | cell content | | Arbitrary order interspersed with freeblocks. +** | area | | and free space fragments. +** |----------------| +** +** The page headers looks like this: +** +** OFFSET SIZE DESCRIPTION +** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf +** 1 2 byte offset to the first freeblock +** 3 2 number of cells on this page +** 5 2 first byte of the cell content area +** 7 1 number of fragmented free bytes +** 8 4 Right child (the Ptr(N) value). Omitted on leaves. +** +** The flags define the format of this btree page. The leaf flag means that +** this page has no children. The zerodata flag means that this page carries +** only keys and no data. The intkey flag means that the key is an integer +** which is stored in the key size entry of the cell header rather than in +** the payload area. +** +** The cell pointer array begins on the first byte after the page header. +** The cell pointer array contains zero or more 2-byte numbers which are +** offsets from the beginning of the page to the cell content in the cell +** content area. The cell pointers occur in sorted order. The system strives +** to keep free space after the last cell pointer so that new cells can +** be easily added without having to defragment the page. +** +** Cell content is stored at the very end of the page and grows toward the +** beginning of the page. +** +** Unused space within the cell content area is collected into a linked list of +** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset +** to the first freeblock is given in the header. Freeblocks occur in +** increasing order. Because a freeblock must be at least 4 bytes in size, +** any group of 3 or fewer unused bytes in the cell content area cannot +** exist on the freeblock chain. A group of 3 or fewer free bytes is called +** a fragment. The total number of bytes in all fragments is recorded. +** in the page header at offset 7. +** +** SIZE DESCRIPTION +** 2 Byte offset of the next freeblock +** 2 Bytes in this freeblock +** +** Cells are of variable length. Cells are stored in the cell content area at +** the end of the page. Pointers to the cells are in the cell pointer array +** that immediately follows the page header. Cells is not necessarily +** contiguous or in order, but cell pointers are contiguous and in order. +** +** Cell content makes use of variable length integers. A variable +** length integer is 1 to 9 bytes where the lower 7 bits of each +** byte are used. The integer consists of all bytes that have bit 8 set and +** the first byte with bit 8 clear. The most significant byte of the integer +** appears first. A variable-length integer may not be more than 9 bytes long. +** As a special case, all 8 bytes of the 9th byte are used as data. This +** allows a 64-bit integer to be encoded in 9 bytes. +** +** 0x00 becomes 0x00000000 +** 0x7f becomes 0x0000007f +** 0x81 0x00 becomes 0x00000080 +** 0x82 0x00 becomes 0x00000100 +** 0x80 0x7f becomes 0x0000007f +** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678 +** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081 +** +** Variable length integers are used for rowids and to hold the number of +** bytes of key and data in a btree cell. +** +** The content of a cell looks like this: +** +** SIZE DESCRIPTION +** 4 Page number of the left child. Omitted if leaf flag is set. +** var Number of bytes of data. Omitted if the zerodata flag is set. +** var Number of bytes of key. Or the key itself if intkey flag is set. +** * Payload +** 4 First page of the overflow chain. Omitted if no overflow +** +** Overflow pages form a linked list. Each page except the last is completely +** filled with data (pagesize - 4 bytes). The last page can have as little +** as 1 byte of data. +** +** SIZE DESCRIPTION +** 4 Page number of next overflow page +** * Data +** +** Freelist pages come in two subtypes: trunk pages and leaf pages. The +** file header points to the first in a linked list of trunk page. Each trunk +** page points to multiple leaf pages. The content of a leaf page is +** unspecified. A trunk page looks like this: +** +** SIZE DESCRIPTION +** 4 Page number of next trunk page +** 4 Number of leaf pointers on this page +** * zero or more pages numbers of leaves +*/ +/* #include "sqliteInt.h" */ + + +/* The following value is the maximum cell size assuming a maximum page +** size give above. +*/ +#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8)) + +/* The maximum number of cells on a single page of the database. This +** assumes a minimum cell size of 6 bytes (4 bytes for the cell itself +** plus 2 bytes for the index to the cell in the page header). Such +** small cells will be rare, but they are possible. +*/ +#define MX_CELL(pBt) ((pBt->pageSize-8)/6) + +/* Forward declarations */ +typedef struct MemPage MemPage; +typedef struct BtLock BtLock; +typedef struct CellInfo CellInfo; + +/* +** This is a magic string that appears at the beginning of every +** SQLite database in order to identify the file as a real database. +** +** You can change this value at compile-time by specifying a +** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The +** header must be exactly 16 bytes including the zero-terminator so +** the string itself should be 15 characters long. If you change +** the header, then your custom library will not be able to read +** databases generated by the standard tools and the standard tools +** will not be able to read databases created by your custom library. +*/ +#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */ +# define SQLITE_FILE_HEADER "SQLite format 3" +#endif + +/* +** Page type flags. An ORed combination of these flags appear as the +** first byte of on-disk image of every BTree page. +*/ +#define PTF_INTKEY 0x01 +#define PTF_ZERODATA 0x02 +#define PTF_LEAFDATA 0x04 +#define PTF_LEAF 0x08 + +/* +** An instance of this object stores information about each a single database +** page that has been loaded into memory. The information in this object +** is derived from the raw on-disk page content. +** +** As each database page is loaded into memory, the pager allocats an +** instance of this object and zeros the first 8 bytes. (This is the +** "extra" information associated with each page of the pager.) +** +** Access to all fields of this structure is controlled by the mutex +** stored in MemPage.pBt->mutex. +*/ +struct MemPage { + u8 isInit; /* True if previously initialized. MUST BE FIRST! */ + u8 bBusy; /* Prevent endless loops on corrupt database files */ + u8 intKey; /* True if table b-trees. False for index b-trees */ + u8 intKeyLeaf; /* True if the leaf of an intKey table */ + Pgno pgno; /* Page number for this page */ + /* Only the first 8 bytes (above) are zeroed by pager.c when a new page + ** is allocated. All fields that follow must be initialized before use */ + u8 leaf; /* True if a leaf page */ + u8 hdrOffset; /* 100 for page 1. 0 otherwise */ + u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ + u8 max1bytePayload; /* min(maxLocal,127) */ + u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ + u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ + u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ + u16 cellOffset; /* Index in aData of first cell pointer */ + u16 nFree; /* Number of free bytes on the page */ + u16 nCell; /* Number of cells on this page, local and ovfl */ + u16 maskPage; /* Mask for page offset */ + u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th + ** non-overflow cell */ + u8 *apOvfl[4]; /* Pointers to the body of overflow cells */ + BtShared *pBt; /* Pointer to BtShared that this page is part of */ + u8 *aData; /* Pointer to disk image of the page data */ + u8 *aDataEnd; /* One byte past the end of usable data */ + u8 *aCellIdx; /* The cell index area */ + u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */ + DbPage *pDbPage; /* Pager page handle */ + u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */ + void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */ +}; + +/* +** A linked list of the following structures is stored at BtShared.pLock. +** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor +** is opened on the table with root page BtShared.iTable. Locks are removed +** from this list when a transaction is committed or rolled back, or when +** a btree handle is closed. +*/ +struct BtLock { + Btree *pBtree; /* Btree handle holding this lock */ + Pgno iTable; /* Root page of table */ + u8 eLock; /* READ_LOCK or WRITE_LOCK */ + BtLock *pNext; /* Next in BtShared.pLock list */ +}; + +/* Candidate values for BtLock.eLock */ +#define READ_LOCK 1 +#define WRITE_LOCK 2 + +/* A Btree handle +** +** A database connection contains a pointer to an instance of +** this object for every database file that it has open. This structure +** is opaque to the database connection. The database connection cannot +** see the internals of this structure and only deals with pointers to +** this structure. +** +** For some database files, the same underlying database cache might be +** shared between multiple connections. In that case, each connection +** has it own instance of this object. But each instance of this object +** points to the same BtShared object. The database cache and the +** schema associated with the database file are all contained within +** the BtShared object. +** +** All fields in this structure are accessed under sqlite3.mutex. +** The pBt pointer itself may not be changed while there exists cursors +** in the referenced BtShared that point back to this Btree since those +** cursors have to go through this Btree to find their BtShared and +** they often do so without holding sqlite3.mutex. +*/ +struct Btree { + sqlite3 *db; /* The database connection holding this btree */ + BtShared *pBt; /* Sharable content of this btree */ + u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ + u8 sharable; /* True if we can share pBt with another db */ + u8 locked; /* True if db currently has pBt locked */ + u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */ + int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ + int nBackup; /* Number of backup operations reading this btree */ + u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */ + Btree *pNext; /* List of other sharable Btrees from the same db */ + Btree *pPrev; /* Back pointer of the same list */ +#ifndef SQLITE_OMIT_SHARED_CACHE + BtLock lock; /* Object used to lock page 1 */ +#endif +}; + +/* +** Btree.inTrans may take one of the following values. +** +** If the shared-data extension is enabled, there may be multiple users +** of the Btree structure. At most one of these may open a write transaction, +** but any number may have active read transactions. +*/ +#define TRANS_NONE 0 +#define TRANS_READ 1 +#define TRANS_WRITE 2 + +/* +** An instance of this object represents a single database file. +** +** A single database file can be in use at the same time by two +** or more database connections. When two or more connections are +** sharing the same database file, each connection has it own +** private Btree object for the file and each of those Btrees points +** to this one BtShared object. BtShared.nRef is the number of +** connections currently sharing this database file. +** +** Fields in this structure are accessed under the BtShared.mutex +** mutex, except for nRef and pNext which are accessed under the +** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field +** may not be modified once it is initially set as long as nRef>0. +** The pSchema field may be set once under BtShared.mutex and +** thereafter is unchanged as long as nRef>0. +** +** isPending: +** +** If a BtShared client fails to obtain a write-lock on a database +** table (because there exists one or more read-locks on the table), +** the shared-cache enters 'pending-lock' state and isPending is +** set to true. +** +** The shared-cache leaves the 'pending lock' state when either of +** the following occur: +** +** 1) The current writer (BtShared.pWriter) concludes its transaction, OR +** 2) The number of locks held by other connections drops to zero. +** +** while in the 'pending-lock' state, no connection may start a new +** transaction. +** +** This feature is included to help prevent writer-starvation. +*/ +struct BtShared { + Pager *pPager; /* The page cache */ + sqlite3 *db; /* Database connection currently using this Btree */ + BtCursor *pCursor; /* A list of all open cursors */ + MemPage *pPage1; /* First page of the database */ + u8 openFlags; /* Flags to sqlite3BtreeOpen() */ +#ifndef SQLITE_OMIT_AUTOVACUUM + u8 autoVacuum; /* True if auto-vacuum is enabled */ + u8 incrVacuum; /* True if incr-vacuum is enabled */ + u8 bDoTruncate; /* True to truncate db on commit */ +#endif + u8 inTransaction; /* Transaction state */ + u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ +#ifdef SQLITE_HAS_CODEC + u8 optimalReserve; /* Desired amount of reserved space per page */ +#endif + u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ + u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ + u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ + u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */ + u16 minLeaf; /* Minimum local payload in a LEAFDATA table */ + u32 pageSize; /* Total number of bytes on a page */ + u32 usableSize; /* Number of usable bytes on each page */ + int nTransaction; /* Number of open transactions (read + write) */ + u32 nPage; /* Number of pages in the database */ + void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ + void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ + sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */ + Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */ +#ifndef SQLITE_OMIT_SHARED_CACHE + int nRef; /* Number of references to this structure */ + BtShared *pNext; /* Next on a list of sharable BtShared structs */ + BtLock *pLock; /* List of locks held on this shared-btree struct */ + Btree *pWriter; /* Btree with currently open write transaction */ +#endif + u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ +}; + +/* +** Allowed values for BtShared.btsFlags +*/ +#define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ +#define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ +#define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */ +#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */ +#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */ +#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */ +#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */ + +/* +** An instance of the following structure is used to hold information +** about a cell. The parseCellPtr() function fills in this structure +** based on information extract from the raw disk page. +*/ +struct CellInfo { + i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */ + u8 *pPayload; /* Pointer to the start of payload */ + u32 nPayload; /* Bytes of payload */ + u16 nLocal; /* Amount of payload held locally, not on overflow */ + u16 nSize; /* Size of the cell content on the main b-tree page */ +}; + +/* +** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than +** this will be declared corrupt. This value is calculated based on a +** maximum database size of 2^31 pages a minimum fanout of 2 for a +** root-node and 3 for all other internal nodes. +** +** If a tree that appears to be taller than this is encountered, it is +** assumed that the database is corrupt. +*/ +#define BTCURSOR_MAX_DEPTH 20 + +/* +** A cursor is a pointer to a particular entry within a particular +** b-tree within a database file. +** +** The entry is identified by its MemPage and the index in +** MemPage.aCell[] of the entry. +** +** A single database file can be shared by two more database connections, +** but cursors cannot be shared. Each cursor is associated with a +** particular database connection identified BtCursor.pBtree.db. +** +** Fields in this structure are accessed under the BtShared.mutex +** found at self->pBt->mutex. +** +** skipNext meaning: +** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op. +** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op. +** eState==FAULT: Cursor fault with skipNext as error code. +*/ +struct BtCursor { + 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 */ + Pgno *aOverflow; /* Cache of overflow page locations */ + CellInfo info; /* A parse of the cell we are pointing at */ + 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. */ + i8 iPage; /* Index of current page in apPage */ + u8 curIntKey; /* Value of apPage[0]->intKey */ + 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 */ +}; + +/* +** Legal values for BtCursor.curFlags +*/ +#define BTCF_WriteFlag 0x01 /* True if a write cursor */ +#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */ +#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */ +#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ +#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ +#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */ + +/* +** Potential values for BtCursor.eState. +** +** CURSOR_INVALID: +** Cursor does not point to a valid entry. This can happen (for example) +** because the table is empty or because BtreeCursorFirst() has not been +** called. +** +** CURSOR_VALID: +** Cursor points to a valid entry. getPayload() etc. may be called. +** +** CURSOR_SKIPNEXT: +** Cursor is valid except that the Cursor.skipNext field is non-zero +** indicating that the next sqlite3BtreeNext() or sqlite3BtreePrevious() +** operation should be a no-op. +** +** CURSOR_REQUIRESEEK: +** The table that this cursor was opened on still exists, but has been +** modified since the cursor was last used. The cursor position is saved +** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in +** this state, restoreCursorPosition() can be called to attempt to +** seek the cursor to the saved position. +** +** CURSOR_FAULT: +** An unrecoverable error (an I/O error or a malloc failure) has occurred +** on a different connection that shares the BtShared cache with this +** cursor. The error has left the cache in an inconsistent state. +** Do nothing else with this cursor. Any attempt to use the cursor +** should return the error code stored in BtCursor.skipNext +*/ +#define CURSOR_INVALID 0 +#define CURSOR_VALID 1 +#define CURSOR_SKIPNEXT 2 +#define CURSOR_REQUIRESEEK 3 +#define CURSOR_FAULT 4 + +/* +** The database page the PENDING_BYTE occupies. This page is never used. +*/ +# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt) + +/* +** These macros define the location of the pointer-map entry for a +** database page. The first argument to each is the number of usable +** bytes on each page of the database (often 1024). The second is the +** page number to look up in the pointer map. +** +** PTRMAP_PAGENO returns the database page number of the pointer-map +** page that stores the required pointer. PTRMAP_PTROFFSET returns +** the offset of the requested map entry. +** +** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page, +** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be +** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements +** this test. +*/ +#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno) +#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1)) +#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno)) + +/* +** The pointer map is a lookup table that identifies the parent page for +** each child page in the database file. The parent page is the page that +** contains a pointer to the child. Every page in the database contains +** 0 or 1 parent pages. (In this context 'database page' refers +** to any page that is not part of the pointer map itself.) Each pointer map +** entry consists of a single byte 'type' and a 4 byte parent page number. +** The PTRMAP_XXX identifiers below are the valid types. +** +** The purpose of the pointer map is to facility moving pages from one +** position in the file to another as part of autovacuum. When a page +** is moved, the pointer in its parent must be updated to point to the +** new location. The pointer map is used to locate the parent page quickly. +** +** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not +** used in this case. +** +** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number +** is not used in this case. +** +** PTRMAP_OVERFLOW1: The database page is the first page in a list of +** overflow pages. The page number identifies the page that +** contains the cell with a pointer to this overflow page. +** +** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of +** overflow pages. The page-number identifies the previous +** page in the overflow page list. +** +** PTRMAP_BTREE: The database page is a non-root btree page. The page number +** identifies the parent page in the btree. +*/ +#define PTRMAP_ROOTPAGE 1 +#define PTRMAP_FREEPAGE 2 +#define PTRMAP_OVERFLOW1 3 +#define PTRMAP_OVERFLOW2 4 +#define PTRMAP_BTREE 5 + +/* A bunch of assert() statements to check the transaction state variables +** of handle p (type Btree*) are internally consistent. +*/ +#define btreeIntegrity(p) \ + assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ + assert( p->pBt->inTransaction>=p->inTrans ); + + +/* +** The ISAUTOVACUUM macro is used within balance_nonroot() to determine +** if the database supports auto-vacuum or not. Because it is used +** within an expression that is an argument to another macro +** (sqliteMallocRaw), it is not possible to use conditional compilation. +** So, this macro is defined instead. +*/ +#ifndef SQLITE_OMIT_AUTOVACUUM +#define ISAUTOVACUUM (pBt->autoVacuum) +#else +#define ISAUTOVACUUM 0 +#endif + + +/* +** This structure is passed around through all the sanity checking routines +** in order to keep track of some global state information. +** +** The aRef[] array is allocated so that there is 1 bit for each page in +** the database. As the integrity-check proceeds, for each page used in +** the database the corresponding bit is set. This allows integrity-check to +** detect pages that are used twice and orphaned pages (both of which +** indicate corruption). +*/ +typedef struct IntegrityCk IntegrityCk; +struct IntegrityCk { + BtShared *pBt; /* The tree being checked out */ + Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ + u8 *aPgRef; /* 1 bit per page in the db (see above) */ + Pgno nPage; /* Number of pages in the database */ + int mxErr; /* Stop accumulating errors when this reaches zero */ + int nErr; /* Number of messages written to zErrMsg so far */ + int mallocFailed; /* A memory allocation error has occurred */ + const char *zPfx; /* Error message prefix */ + int v1, v2; /* Values for up to two %d fields in zPfx */ + StrAccum errMsg; /* Accumulate the error message text here */ + u32 *heap; /* Min-heap used for analyzing cell coverage */ +}; + +/* +** Routines to read or write a two- and four-byte big-endian integer values. +*/ +#define get2byte(x) ((x)[0]<<8 | (x)[1]) +#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v)) +#define get4byte sqlite3Get4byte +#define put4byte sqlite3Put4byte + +/* +** get2byteAligned(), unlike get2byte(), requires that its argument point to a +** two-byte aligned address. get2bytea() is only used for accessing the +** cell addresses in a btree header. +*/ +#if SQLITE_BYTEORDER==4321 +# define get2byteAligned(x) (*(u16*)(x)) +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000 +# define get2byteAligned(x) __builtin_bswap16(*(u16*)(x)) +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 +# define get2byteAligned(x) _byteswap_ushort(*(u16*)(x)) +#else +# define get2byteAligned(x) ((x)[0]<<8 | (x)[1]) +#endif + +/************** End of btreeInt.h ********************************************/ +/************** Continuing where we left off in btmutex.c ********************/ +#ifndef SQLITE_OMIT_SHARED_CACHE +#if SQLITE_THREADSAFE + +/* +** Obtain the BtShared mutex associated with B-Tree handle p. Also, +** set BtShared.db to the database handle associated with p and the +** p->locked boolean to true. +*/ +static void lockBtreeMutex(Btree *p){ + assert( p->locked==0 ); + assert( sqlite3_mutex_notheld(p->pBt->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); + + sqlite3_mutex_enter(p->pBt->mutex); + p->pBt->db = p->db; + p->locked = 1; +} + +/* +** Release the BtShared mutex associated with B-Tree handle p and +** clear the p->locked boolean. +*/ +static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){ + BtShared *pBt = p->pBt; + assert( p->locked==1 ); + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( sqlite3_mutex_held(p->db->mutex) ); + assert( p->db==pBt->db ); + + sqlite3_mutex_leave(pBt->mutex); + p->locked = 0; +} + +/* Forward reference */ +static void SQLITE_NOINLINE btreeLockCarefully(Btree *p); + +/* +** Enter a mutex on the given BTree object. +** +** If the object is not sharable, then no mutex is ever required +** and this routine is a no-op. The underlying mutex is non-recursive. +** But we keep a reference count in Btree.wantToLock so the behavior +** of this interface is recursive. +** +** To avoid deadlocks, multiple Btrees are locked in the same order +** by all database connections. The p->pNext is a list of other +** Btrees belonging to the same database connection as the p Btree +** which need to be locked after p. If we cannot get a lock on +** p, then first unlock all of the others on p->pNext, then wait +** for the lock to become available on p, then relock all of the +** subsequent Btrees that desire a lock. +*/ +SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ + /* Some basic sanity checking on the Btree. The list of Btrees + ** connected by pNext and pPrev should be in sorted order by + ** Btree.pBt value. All elements of the list should belong to + ** the same connection. Only shared Btrees are on the list. */ + assert( p->pNext==0 || p->pNext->pBt>p->pBt ); + assert( p->pPrev==0 || p->pPrev->pBtpBt ); + assert( p->pNext==0 || p->pNext->db==p->db ); + assert( p->pPrev==0 || p->pPrev->db==p->db ); + assert( p->sharable || (p->pNext==0 && p->pPrev==0) ); + + /* Check for locking consistency */ + assert( !p->locked || p->wantToLock>0 ); + assert( p->sharable || p->wantToLock==0 ); + + /* We should already hold a lock on the database connection */ + assert( sqlite3_mutex_held(p->db->mutex) ); + + /* Unless the database is sharable and unlocked, then BtShared.db + ** should already be set correctly. */ + assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db ); + + if( !p->sharable ) return; + p->wantToLock++; + if( p->locked ) return; + btreeLockCarefully(p); +} + +/* This is a helper function for sqlite3BtreeLock(). By moving +** complex, but seldom used logic, out of sqlite3BtreeLock() and +** into this routine, we avoid unnecessary stack pointer changes +** and thus help the sqlite3BtreeLock() routine to run much faster +** in the common case. +*/ +static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){ + Btree *pLater; + + /* In most cases, we should be able to acquire the lock we + ** want without having to go through the ascending lock + ** procedure that follows. Just be sure not to block. + */ + if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ + p->pBt->db = p->db; + p->locked = 1; + return; + } + + /* To avoid deadlock, first release all locks with a larger + ** BtShared address. Then acquire our lock. Then reacquire + ** the other BtShared locks that we used to hold in ascending + ** order. + */ + for(pLater=p->pNext; pLater; pLater=pLater->pNext){ + assert( pLater->sharable ); + assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); + assert( !pLater->locked || pLater->wantToLock>0 ); + if( pLater->locked ){ + unlockBtreeMutex(pLater); + } + } + lockBtreeMutex(p); + for(pLater=p->pNext; pLater; pLater=pLater->pNext){ + if( pLater->wantToLock ){ + lockBtreeMutex(pLater); + } + } +} + + +/* +** Exit the recursive mutex on a Btree. +*/ +SQLITE_PRIVATE void sqlite3BtreeLeave(Btree *p){ + assert( sqlite3_mutex_held(p->db->mutex) ); + if( p->sharable ){ + assert( p->wantToLock>0 ); + p->wantToLock--; + if( p->wantToLock==0 ){ + unlockBtreeMutex(p); + } + } +} + +#ifndef NDEBUG +/* +** Return true if the BtShared mutex is held on the btree, or if the +** B-Tree is not marked as sharable. +** +** This routine is used only from within assert() statements. +*/ +SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ + assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 ); + assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db ); + assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) ); + assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) ); + + return (p->sharable==0 || p->locked); +} +#endif + + +/* +** Enter the mutex on every Btree associated with a database +** connection. This is needed (for example) prior to parsing +** a statement since we will be comparing table and column names +** against all schemas and we do not want those schemas being +** reset out from under us. +** +** There is a corresponding leave-all procedures. +** +** Enter the mutexes in accending order by BtShared pointer address +** to avoid the possibility of deadlock when two threads with +** two or more btrees in common both try to lock all their btrees +** at the same instant. +*/ +static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ + int i; + int skipOk = 1; + Btree *p; + assert( sqlite3_mutex_held(db->mutex) ); + for(i=0; inDb; i++){ + p = db->aDb[i].pBt; + if( p && p->sharable ){ + sqlite3BtreeEnter(p); + skipOk = 0; + } + } + db->skipBtreeMutex = skipOk; +} +SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ + if( db->skipBtreeMutex==0 ) btreeEnterAll(db); +} +static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){ + int i; + Btree *p; + assert( sqlite3_mutex_held(db->mutex) ); + for(i=0; inDb; i++){ + p = db->aDb[i].pBt; + if( p ) sqlite3BtreeLeave(p); + } +} +SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ + if( db->skipBtreeMutex==0 ) btreeLeaveAll(db); +} + +#ifndef NDEBUG +/* +** Return true if the current thread holds the database connection +** mutex and all required BtShared mutexes. +** +** This routine is used inside assert() statements only. +*/ +SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){ + int i; + if( !sqlite3_mutex_held(db->mutex) ){ + return 0; + } + for(i=0; inDb; i++){ + Btree *p; + p = db->aDb[i].pBt; + if( p && p->sharable && + (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){ + return 0; + } + } + return 1; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Return true if the correct mutexes are held for accessing the +** db->aDb[iDb].pSchema structure. The mutexes required for schema +** access are: +** +** (1) The mutex on db +** (2) if iDb!=1, then the mutex on db->aDb[iDb].pBt. +** +** If pSchema is not NULL, then iDb is computed from pSchema and +** db using sqlite3SchemaToIndex(). +*/ +SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){ + Btree *p; + assert( db!=0 ); + if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema); + assert( iDb>=0 && iDbnDb ); + if( !sqlite3_mutex_held(db->mutex) ) return 0; + if( iDb==1 ) return 1; + p = db->aDb[iDb].pBt; + assert( p!=0 ); + return p->sharable==0 || p->locked==1; +} +#endif /* NDEBUG */ + +#else /* SQLITE_THREADSAFE>0 above. SQLITE_THREADSAFE==0 below */ +/* +** The following are special cases for mutex enter routines for use +** in single threaded applications that use shared cache. Except for +** these two routines, all mutex operations are no-ops in that case and +** are null #defines in btree.h. +** +** If shared cache is disabled, then all btree mutex routines, including +** the ones below, are no-ops and are null #defines in btree.h. +*/ + +SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){ + p->pBt->db = p->db; +} +SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ + int i; + for(i=0; inDb; i++){ + Btree *p = db->aDb[i].pBt; + if( p ){ + p->pBt->db = p->db; + } + } +} +#endif /* if SQLITE_THREADSAFE */ + +#ifndef SQLITE_OMIT_INCRBLOB +/* +** Enter a mutex on a Btree given a cursor owned by that Btree. +** +** These entry points are used by incremental I/O only. Enter() is required +** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not +** the build is threadsafe. Leave() is only required by threadsafe builds. +*/ +SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ + sqlite3BtreeEnter(pCur->pBtree); +} +# if SQLITE_THREADSAFE +SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ + sqlite3BtreeLeave(pCur->pBtree); +} +# endif +#endif /* ifndef SQLITE_OMIT_INCRBLOB */ + +#endif /* ifndef SQLITE_OMIT_SHARED_CACHE */ + +/************** End of btmutex.c *********************************************/ +/************** Begin file btree.c *******************************************/ +/* +** 2004 April 6 +** +** 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 external (disk-based) database using BTrees. +** See the header comment on "btreeInt.h" for additional information. +** Including a description of file format and an overview of operation. +*/ +/* #include "btreeInt.h" */ + +/* +** The header string that appears at the beginning of every +** SQLite database. +*/ +static const char zMagicHeader[] = SQLITE_FILE_HEADER; + +/* +** Set this global variable to 1 to enable tracing using the TRACE +** macro. +*/ +#if 0 +int sqlite3BtreeTrace=1; /* True to enable tracing */ +# define TRACE(X) if(sqlite3BtreeTrace){printf X;fflush(stdout);} +#else +# define TRACE(X) +#endif + +/* +** Extract a 2-byte big-endian integer from an array of unsigned bytes. +** But if the value is zero, make it 65536. +** +** This routine is used to extract the "offset to cell content area" value +** from the header of a btree page. If the page size is 65536 and the page +** is empty, the offset should be 65536, but the 2-byte value stores zero. +** This routine makes the necessary adjustment to 65536. +*/ +#define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1) + +/* +** Values passed as the 5th argument to allocateBtreePage() +*/ +#define BTALLOC_ANY 0 /* Allocate any page */ +#define BTALLOC_EXACT 1 /* Allocate exact page if possible */ +#define BTALLOC_LE 2 /* Allocate any page <= the parameter */ + +/* +** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not +** defined, or 0 if it is. For example: +** +** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum); +*/ +#ifndef SQLITE_OMIT_AUTOVACUUM +#define IfNotOmitAV(expr) (expr) +#else +#define IfNotOmitAV(expr) 0 +#endif + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** A list of BtShared objects that are eligible for participation +** in shared cache. This variable has file scope during normal builds, +** but the test harness needs to access it so we make it global for +** test builds. +** +** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER. +*/ +#ifdef SQLITE_TEST +SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; +#else +static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; +#endif +#endif /* SQLITE_OMIT_SHARED_CACHE */ + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Enable or disable the shared pager and schema features. +** +** This routine has no effect on existing database connections. +** The shared cache setting effects only future calls to +** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). +*/ +SQLITE_API int sqlite3_enable_shared_cache(int enable){ + sqlite3GlobalConfig.sharedCacheEnabled = enable; + return SQLITE_OK; +} +#endif + + + +#ifdef SQLITE_OMIT_SHARED_CACHE + /* + ** The functions querySharedCacheTableLock(), setSharedCacheTableLock(), + ** and clearAllSharedCacheTableLocks() + ** manipulate entries in the BtShared.pLock linked list used to store + ** shared-cache table level locks. If the library is compiled with the + ** shared-cache feature disabled, then there is only ever one user + ** of each BtShared structure and so this locking is not necessary. + ** So define the lock related functions as no-ops. + */ + #define querySharedCacheTableLock(a,b,c) SQLITE_OK + #define setSharedCacheTableLock(a,b,c) SQLITE_OK + #define clearAllSharedCacheTableLocks(a) + #define downgradeAllSharedCacheTableLocks(a) + #define hasSharedCacheTableLock(a,b,c,d) 1 + #define hasReadConflicts(a, b) 0 +#endif + +#ifndef SQLITE_OMIT_SHARED_CACHE + +#ifdef SQLITE_DEBUG +/* +**** This function is only used as part of an assert() statement. *** +** +** Check to see if pBtree holds the required locks to read or write to the +** table with root page iRoot. Return 1 if it does and 0 if not. +** +** For example, when writing to a table with root-page iRoot via +** Btree connection pBtree: +** +** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) ); +** +** When writing to an index that resides in a sharable database, the +** caller should have first obtained a lock specifying the root page of +** the corresponding table. This makes things a bit more complicated, +** as this module treats each table as a separate structure. To determine +** the table corresponding to the index being written, this +** function has to search through the database schema. +** +** Instead of a lock on the table/index rooted at page iRoot, the caller may +** hold a write-lock on the schema table (root page 1). This is also +** acceptable. +*/ +static int hasSharedCacheTableLock( + Btree *pBtree, /* Handle that must hold lock */ + Pgno iRoot, /* Root page of b-tree */ + int isIndex, /* True if iRoot is the root of an index b-tree */ + int eLockType /* Required lock type (READ_LOCK or WRITE_LOCK) */ +){ + Schema *pSchema = (Schema *)pBtree->pBt->pSchema; + Pgno iTab = 0; + BtLock *pLock; + + /* If this database is not shareable, or if the client is reading + ** and has the read-uncommitted flag set, then no lock is required. + ** Return true immediately. + */ + if( (pBtree->sharable==0) + || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) + ){ + return 1; + } + + /* If the client is reading or writing an index and the schema is + ** not loaded, then it is too difficult to actually check to see if + ** the correct locks are held. So do not bother - just return true. + ** This case does not come up very often anyhow. + */ + if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){ + return 1; + } + + /* Figure out the root-page that the lock should be held on. For table + ** b-trees, this is just the root page of the b-tree being read or + ** written. For index b-trees, it is the root page of the associated + ** table. */ + if( isIndex ){ + HashElem *p; + for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ + Index *pIdx = (Index *)sqliteHashData(p); + if( pIdx->tnum==(int)iRoot ){ + if( iTab ){ + /* Two or more indexes share the same root page. There must + ** be imposter tables. So just return true. The assert is not + ** useful in that case. */ + return 1; + } + iTab = pIdx->pTable->tnum; + } + } + }else{ + iTab = iRoot; + } + + /* Search for the required lock. Either a write-lock on root-page iTab, a + ** write-lock on the schema table, or (if the client is reading) a + ** read-lock on iTab will suffice. Return 1 if any of these are found. */ + for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){ + if( pLock->pBtree==pBtree + && (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1)) + && pLock->eLock>=eLockType + ){ + return 1; + } + } + + /* Failed to find the required lock. */ + return 0; +} +#endif /* SQLITE_DEBUG */ + +#ifdef SQLITE_DEBUG +/* +**** This function may be used as part of assert() statements only. **** +** +** Return true if it would be illegal for pBtree to write into the +** table or index rooted at iRoot because other shared connections are +** simultaneously reading that same table or index. +** +** It is illegal for pBtree to write if some other Btree object that +** shares the same BtShared object is currently reading or writing +** the iRoot table. Except, if the other Btree object has the +** read-uncommitted flag set, then it is OK for the other object to +** have a read cursor. +** +** For example, before writing to any part of the table or index +** rooted at page iRoot, one should call: +** +** assert( !hasReadConflicts(pBtree, iRoot) ); +*/ +static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ + BtCursor *p; + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + if( p->pgnoRoot==iRoot + && p->pBtree!=pBtree + && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted) + ){ + return 1; + } + } + return 0; +} +#endif /* #ifdef SQLITE_DEBUG */ + +/* +** Query to see if Btree handle p may obtain a lock of type eLock +** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return +** SQLITE_OK if the lock may be obtained (by calling +** setSharedCacheTableLock()), or SQLITE_LOCKED if not. +*/ +static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ + BtShared *pBt = p->pBt; + BtLock *pIter; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); + assert( p->db!=0 ); + assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 ); + + /* If requesting a write-lock, then the Btree must have an open write + ** transaction on this file. And, obviously, for this to be so there + ** must be an open write transaction on the file itself. + */ + assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) ); + assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE ); + + /* This routine is a no-op if the shared-cache is not enabled */ + if( !p->sharable ){ + return SQLITE_OK; + } + + /* If some other connection is holding an exclusive lock, the + ** requested lock may not be obtained. + */ + if( pBt->pWriter!=p && (pBt->btsFlags & BTS_EXCLUSIVE)!=0 ){ + sqlite3ConnectionBlocked(p->db, pBt->pWriter->db); + return SQLITE_LOCKED_SHAREDCACHE; + } + + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + /* The condition (pIter->eLock!=eLock) in the following if(...) + ** statement is a simplification of: + ** + ** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK) + ** + ** since we know that if eLock==WRITE_LOCK, then no other connection + ** may hold a WRITE_LOCK on any table in this file (since there can + ** only be a single writer). + */ + assert( pIter->eLock==READ_LOCK || pIter->eLock==WRITE_LOCK ); + assert( eLock==READ_LOCK || pIter->pBtree==p || pIter->eLock==READ_LOCK); + if( pIter->pBtree!=p && pIter->iTable==iTab && pIter->eLock!=eLock ){ + sqlite3ConnectionBlocked(p->db, pIter->pBtree->db); + if( eLock==WRITE_LOCK ){ + assert( p==pBt->pWriter ); + pBt->btsFlags |= BTS_PENDING; + } + return SQLITE_LOCKED_SHAREDCACHE; + } + } + return SQLITE_OK; +} +#endif /* !SQLITE_OMIT_SHARED_CACHE */ + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Add a lock on the table with root-page iTable to the shared-btree used +** by Btree handle p. Parameter eLock must be either READ_LOCK or +** WRITE_LOCK. +** +** This function assumes the following: +** +** (a) The specified Btree object p is connected to a sharable +** database (one with the BtShared.sharable flag set), and +** +** (b) No other Btree objects hold a lock that conflicts +** with the requested lock (i.e. querySharedCacheTableLock() has +** already been called and returned SQLITE_OK). +** +** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM +** is returned if a malloc attempt fails. +*/ +static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ + BtShared *pBt = p->pBt; + BtLock *pLock = 0; + BtLock *pIter; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); + assert( p->db!=0 ); + + /* A connection with the read-uncommitted flag set will never try to + ** obtain a read-lock using this function. The only read-lock obtained + ** by a connection in read-uncommitted mode is on the sqlite_master + ** table, and that lock is obtained in BtreeBeginTrans(). */ + assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK ); + + /* This function should only be called on a sharable b-tree after it + ** has been determined that no other b-tree holds a conflicting lock. */ + assert( p->sharable ); + assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) ); + + /* First search the list for an existing lock on this table. */ + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->iTable==iTable && pIter->pBtree==p ){ + pLock = pIter; + break; + } + } + + /* If the above search did not find a BtLock struct associating Btree p + ** with table iTable, allocate one and link it into the list. + */ + if( !pLock ){ + pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); + if( !pLock ){ + return SQLITE_NOMEM_BKPT; + } + pLock->iTable = iTable; + pLock->pBtree = p; + pLock->pNext = pBt->pLock; + pBt->pLock = pLock; + } + + /* Set the BtLock.eLock variable to the maximum of the current lock + ** and the requested lock. This means if a write-lock was already held + ** and a read-lock requested, we don't incorrectly downgrade the lock. + */ + assert( WRITE_LOCK>READ_LOCK ); + if( eLock>pLock->eLock ){ + pLock->eLock = eLock; + } + + return SQLITE_OK; +} +#endif /* !SQLITE_OMIT_SHARED_CACHE */ + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Release all the table locks (locks obtained via calls to +** the setSharedCacheTableLock() procedure) held by Btree object p. +** +** This function assumes that Btree p has an open read or write +** transaction. If it does not, then the BTS_PENDING flag +** may be incorrectly cleared. +*/ +static void clearAllSharedCacheTableLocks(Btree *p){ + BtShared *pBt = p->pBt; + BtLock **ppIter = &pBt->pLock; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( p->sharable || 0==*ppIter ); + assert( p->inTrans>0 ); + + while( *ppIter ){ + BtLock *pLock = *ppIter; + assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree ); + assert( pLock->pBtree->inTrans>=pLock->eLock ); + if( pLock->pBtree==p ){ + *ppIter = pLock->pNext; + assert( pLock->iTable!=1 || pLock==&p->lock ); + if( pLock->iTable!=1 ){ + sqlite3_free(pLock); + } + }else{ + ppIter = &pLock->pNext; + } + } + + assert( (pBt->btsFlags & BTS_PENDING)==0 || pBt->pWriter ); + if( pBt->pWriter==p ){ + pBt->pWriter = 0; + pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); + }else if( pBt->nTransaction==2 ){ + /* This function is called when Btree p is concluding its + ** transaction. If there currently exists a writer, and p is not + ** that writer, then the number of locks held by connections other + ** than the writer must be about to drop to zero. In this case + ** set the BTS_PENDING flag to 0. + ** + ** If there is not currently a writer, then BTS_PENDING must + ** be zero already. So this next line is harmless in that case. + */ + pBt->btsFlags &= ~BTS_PENDING; + } +} + +/* +** This function changes all write-locks held by Btree p into read-locks. +*/ +static void downgradeAllSharedCacheTableLocks(Btree *p){ + BtShared *pBt = p->pBt; + if( pBt->pWriter==p ){ + BtLock *pLock; + pBt->pWriter = 0; + pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); + for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){ + assert( pLock->eLock==READ_LOCK || pLock->pBtree==p ); + pLock->eLock = READ_LOCK; + } + } +} + +#endif /* SQLITE_OMIT_SHARED_CACHE */ + +static void releasePage(MemPage *pPage); /* Forward reference */ + +/* +***** This routine is used inside of assert() only **** +** +** Verify that the cursor holds the mutex on its BtShared +*/ +#ifdef SQLITE_DEBUG +static int cursorHoldsMutex(BtCursor *p){ + return sqlite3_mutex_held(p->pBt->mutex); +} + +/* Verify that the cursor and the BtShared agree about what is the current +** database connetion. This is important in shared-cache mode. If the database +** connection pointers get out-of-sync, it is possible for routines like +** btreeInitPage() to reference an stale connection pointer that references a +** a connection that has already closed. This routine is used inside assert() +** statements only and for the purpose of double-checking that the btree code +** does keep the database connection pointers up-to-date. +*/ +static int cursorOwnsBtShared(BtCursor *p){ + assert( cursorHoldsMutex(p) ); + return (p->pBtree->db==p->pBt->db); +} +#endif + +/* +** Invalidate the overflow cache of the cursor passed as the first argument. +** on the shared btree structure pBt. +*/ +#define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl) + +/* +** Invalidate the overflow page-list cache for all cursors opened +** on the shared btree structure pBt. +*/ +static void invalidateAllOverflowCache(BtShared *pBt){ + BtCursor *p; + assert( sqlite3_mutex_held(pBt->mutex) ); + for(p=pBt->pCursor; p; p=p->pNext){ + invalidateOverflowCache(p); + } +} + +#ifndef SQLITE_OMIT_INCRBLOB +/* +** This function is called before modifying the contents of a table +** to invalidate any incrblob cursors that are open on the +** row or one of the rows being modified. +** +** If argument isClearTable is true, then the entire contents of the +** table is about to be deleted. In this case invalidate all incrblob +** cursors open on any row within the table with root-page pgnoRoot. +** +** Otherwise, if argument isClearTable is false, then the row with +** rowid iRow is being replaced or deleted. In this case invalidate +** only those incrblob cursors open on that specific row. +*/ +static void invalidateIncrblobCursors( + Btree *pBtree, /* The database file to check */ + Pgno pgnoRoot, /* The table that might be changing */ + i64 iRow, /* The rowid that might be changing */ + int isClearTable /* True if all rows are being deleted */ +){ + BtCursor *p; + if( pBtree->hasIncrblobCur==0 ) return; + assert( sqlite3BtreeHoldsMutex(pBtree) ); + pBtree->hasIncrblobCur = 0; + for(p=pBtree->pBt->pCursor; p; p=p->pNext){ + if( (p->curFlags & BTCF_Incrblob)!=0 ){ + pBtree->hasIncrblobCur = 1; + if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){ + p->eState = CURSOR_INVALID; + } + } + } +} + +#else + /* Stub function when INCRBLOB is omitted */ + #define invalidateIncrblobCursors(w,x,y,z) +#endif /* SQLITE_OMIT_INCRBLOB */ + +/* +** Set bit pgno of the BtShared.pHasContent bitvec. This is called +** when a page that previously contained data becomes a free-list leaf +** page. +** +** The BtShared.pHasContent bitvec exists to work around an obscure +** bug caused by the interaction of two useful IO optimizations surrounding +** free-list leaf pages: +** +** 1) When all data is deleted from a page and the page becomes +** a free-list leaf page, the page is not written to the database +** (as free-list leaf pages contain no meaningful data). Sometimes +** such a page is not even journalled (as it will not be modified, +** why bother journalling it?). +** +** 2) When a free-list leaf page is reused, its content is not read +** from the database or written to the journal file (why should it +** be, if it is not at all meaningful?). +** +** By themselves, these optimizations work fine and provide a handy +** performance boost to bulk delete or insert operations. However, if +** a page is moved to the free-list and then reused within the same +** transaction, a problem comes up. If the page is not journalled when +** it is moved to the free-list and it is also not journalled when it +** is extracted from the free-list and reused, then the original data +** may be lost. In the event of a rollback, it may not be possible +** to restore the database to its original configuration. +** +** The solution is the BtShared.pHasContent bitvec. Whenever a page is +** moved to become a free-list leaf page, the corresponding bit is +** set in the bitvec. Whenever a leaf page is extracted from the free-list, +** optimization 2 above is omitted if the corresponding bit is already +** set in BtShared.pHasContent. The contents of the bitvec are cleared +** at the end of every transaction. +*/ +static int btreeSetHasContent(BtShared *pBt, Pgno pgno){ + int rc = SQLITE_OK; + if( !pBt->pHasContent ){ + assert( pgno<=pBt->nPage ); + pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage); + if( !pBt->pHasContent ){ + rc = SQLITE_NOMEM_BKPT; + } + } + if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){ + rc = sqlite3BitvecSet(pBt->pHasContent, pgno); + } + return rc; +} + +/* +** Query the BtShared.pHasContent vector. +** +** This function is called when a free-list leaf page is removed from the +** free-list for reuse. It returns false if it is safe to retrieve the +** page from the pager layer with the 'no-content' flag set. True otherwise. +*/ +static int btreeGetHasContent(BtShared *pBt, Pgno pgno){ + Bitvec *p = pBt->pHasContent; + return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno))); +} + +/* +** Clear (destroy) the BtShared.pHasContent bitvec. This should be +** invoked at the conclusion of each write-transaction. +*/ +static void btreeClearHasContent(BtShared *pBt){ + sqlite3BitvecDestroy(pBt->pHasContent); + pBt->pHasContent = 0; +} + +/* +** Release all of the apPage[] pages for a cursor. +*/ +static void btreeReleaseAllCursorPages(BtCursor *pCur){ + int i; + for(i=0; i<=pCur->iPage; i++){ + releasePage(pCur->apPage[i]); + pCur->apPage[i] = 0; + } + pCur->iPage = -1; +} + +/* +** The cursor passed as the only argument must point to a valid entry +** when this function is called (i.e. have eState==CURSOR_VALID). This +** function saves the current cursor key in variables pCur->nKey and +** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error +** code otherwise. +** +** If the cursor is open on an intkey table, then the integer key +** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to +** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is +** set to point to a malloced buffer pCur->nKey bytes in size containing +** the key. +*/ +static int saveCursorKey(BtCursor *pCur){ + int rc = SQLITE_OK; + assert( CURSOR_VALID==pCur->eState ); + assert( 0==pCur->pKey ); + assert( cursorHoldsMutex(pCur) ); + + if( pCur->curIntKey ){ + /* Only the rowid is required for a table btree */ + pCur->nKey = sqlite3BtreeIntegerKey(pCur); + }else{ + /* For an index btree, save the complete key content */ + void *pKey; + pCur->nKey = sqlite3BtreePayloadSize(pCur); + pKey = sqlite3Malloc( pCur->nKey ); + if( pKey ){ + rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); + if( rc==SQLITE_OK ){ + pCur->pKey = pKey; + }else{ + sqlite3_free(pKey); + } + }else{ + rc = SQLITE_NOMEM_BKPT; + } + } + assert( !pCur->curIntKey || !pCur->pKey ); + return rc; +} + +/* +** Save the current cursor position in the variables BtCursor.nKey +** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. +** +** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) +** prior to calling this routine. +*/ +static int saveCursorPosition(BtCursor *pCur){ + int rc; + + assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState ); + assert( 0==pCur->pKey ); + assert( cursorHoldsMutex(pCur) ); + + if( pCur->eState==CURSOR_SKIPNEXT ){ + pCur->eState = CURSOR_VALID; + }else{ + pCur->skipNext = 0; + } + + rc = saveCursorKey(pCur); + if( rc==SQLITE_OK ){ + btreeReleaseAllCursorPages(pCur); + pCur->eState = CURSOR_REQUIRESEEK; + } + + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl|BTCF_AtLast); + return rc; +} + +/* Forward reference */ +static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*); + +/* +** Save the positions of all cursors (except pExcept) that are open on +** the table with root-page iRoot. "Saving the cursor position" means that +** the location in the btree is remembered in such a way that it can be +** moved back to the same spot after the btree has been modified. This +** routine is called just before cursor pExcept is used to modify the +** table, for example in BtreeDelete() or BtreeInsert(). +** +** If there are two or more cursors on the same btree, then all such +** cursors should have their BTCF_Multiple flag set. The btreeCursor() +** routine enforces that rule. This routine only needs to be called in +** the uncommon case when pExpect has the BTCF_Multiple flag set. +** +** If pExpect!=NULL and if no other cursors are found on the same root-page, +** then the BTCF_Multiple flag on pExpect is cleared, to avoid another +** pointless call to this routine. +** +** Implementation note: This routine merely checks to see if any cursors +** need to be saved. It calls out to saveCursorsOnList() in the (unusual) +** event that cursors are in need to being saved. +*/ +static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ + BtCursor *p; + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pExcept==0 || pExcept->pBt==pBt ); + for(p=pBt->pCursor; p; p=p->pNext){ + if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break; + } + if( p ) return saveCursorsOnList(p, iRoot, pExcept); + if( pExcept ) pExcept->curFlags &= ~BTCF_Multiple; + return SQLITE_OK; +} + +/* This helper routine to saveAllCursors does the actual work of saving +** the cursors if and when a cursor is found that actually requires saving. +** The common case is that no cursors need to be saved, so this routine is +** broken out from its caller to avoid unnecessary stack pointer movement. +*/ +static int SQLITE_NOINLINE saveCursorsOnList( + BtCursor *p, /* The first cursor that needs saving */ + Pgno iRoot, /* Only save cursor with this iRoot. Save all if zero */ + BtCursor *pExcept /* Do not save this cursor */ +){ + do{ + if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){ + if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ + int rc = saveCursorPosition(p); + if( SQLITE_OK!=rc ){ + return rc; + } + }else{ + testcase( p->iPage>0 ); + btreeReleaseAllCursorPages(p); + } + } + p = p->pNext; + }while( p ); + return SQLITE_OK; +} + +/* +** Clear the current cursor position. +*/ +SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + sqlite3_free(pCur->pKey); + pCur->pKey = 0; + pCur->eState = CURSOR_INVALID; +} + +/* +** In this version of BtreeMoveto, pKey is a packed index record +** such as is generated by the OP_MakeRecord opcode. Unpack the +** record and then call BtreeMovetoUnpacked() to do the work. +*/ +static int btreeMoveto( + BtCursor *pCur, /* Cursor open on the btree to be searched */ + const void *pKey, /* Packed key if the btree is an index */ + i64 nKey, /* Integer key for tables. Size of pKey for indices */ + int bias, /* Bias search to the high end */ + int *pRes /* Write search results here */ +){ + int rc; /* Status code */ + UnpackedRecord *pIdxKey; /* Unpacked index key */ + + if( pKey ){ + assert( nKey==(i64)(int)nKey ); + pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); + if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; + sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey); + if( pIdxKey->nField==0 ){ + rc = SQLITE_CORRUPT_BKPT; + goto moveto_done; + } + }else{ + pIdxKey = 0; + } + rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); +moveto_done: + if( pIdxKey ){ + sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); + } + return rc; +} + +/* +** Restore the cursor to the position it was in (or as close to as possible) +** when saveCursorPosition() was called. Note that this call deletes the +** saved position info stored by saveCursorPosition(), so there can be +** at most one effective restoreCursorPosition() call after each +** saveCursorPosition(). +*/ +static int btreeRestoreCursorPosition(BtCursor *pCur){ + int rc; + int skipNext; + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState>=CURSOR_REQUIRESEEK ); + if( pCur->eState==CURSOR_FAULT ){ + return pCur->skipNext; + } + pCur->eState = CURSOR_INVALID; + rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + if( rc==SQLITE_OK ){ + sqlite3_free(pCur->pKey); + pCur->pKey = 0; + assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); + pCur->skipNext |= skipNext; + if( pCur->skipNext && pCur->eState==CURSOR_VALID ){ + pCur->eState = CURSOR_SKIPNEXT; + } + } + return rc; +} + +#define restoreCursorPosition(p) \ + (p->eState>=CURSOR_REQUIRESEEK ? \ + btreeRestoreCursorPosition(p) : \ + SQLITE_OK) + +/* +** Determine whether or not a cursor has moved from the position where +** it was last placed, or has been invalidated for any other reason. +** Cursors can move when the row they are pointing at is deleted out +** from under them, for example. Cursor might also move if a btree +** is rebalanced. +** +** Calling this routine with a NULL cursor pointer returns false. +** +** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor +** back to where it ought to be if this routine returns true. +*/ +SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ + return pCur->eState!=CURSOR_VALID; +} + +/* +** 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). +** +** On success, the *pDifferentRow parameter is false if the cursor is left +** pointing at exactly the same row. *pDifferntRow is the row the cursor +** was pointing to has been deleted, forcing the cursor to point to some +** nearby row. +** +** This routine should only be called for a cursor that just returned +** TRUE from sqlite3BtreeCursorHasMoved(). +*/ +SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ + int rc; + + assert( pCur!=0 ); + assert( pCur->eState!=CURSOR_VALID ); + rc = restoreCursorPosition(pCur); + if( rc ){ + *pDifferentRow = 1; + return rc; + } + if( pCur->eState!=CURSOR_VALID ){ + *pDifferentRow = 1; + }else{ + assert( pCur->skipNext==0 ); + *pDifferentRow = 0; + } + return SQLITE_OK; +} + +#ifdef SQLITE_ENABLE_CURSOR_HINTS +/* +** Provide hints to the cursor. The particular hint given (and the type +** and number of the varargs parameters) is determined by the eHintType +** parameter. See the definitions of the BTREE_HINT_* macros for details. +*/ +SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){ + /* Used only by system that substitute their own storage engine */ +} +#endif + +/* +** Provide flag hints to the cursor. +*/ +SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){ + assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); + pCur->hints = x; +} + + +#ifndef SQLITE_OMIT_AUTOVACUUM +/* +** Given a page number of a regular database page, return the page +** number for the pointer-map page that contains the entry for the +** input page number. +** +** Return 0 (not a valid page) for pgno==1 since there is +** no pointer map associated with page 1. The integrity_check logic +** requires that ptrmapPageno(*,1)!=1. +*/ +static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ + int nPagesPerMapPage; + Pgno iPtrMap, ret; + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pgno<2 ) return 0; + nPagesPerMapPage = (pBt->usableSize/5)+1; + iPtrMap = (pgno-2)/nPagesPerMapPage; + ret = (iPtrMap*nPagesPerMapPage) + 2; + if( ret==PENDING_BYTE_PAGE(pBt) ){ + ret++; + } + return ret; +} + +/* +** Write an entry into the pointer map. +** +** This routine updates the pointer map entry for page number 'key' +** so that it maps to type 'eType' and parent page number 'pgno'. +** +** If *pRC is initially non-zero (non-SQLITE_OK) then this routine is +** a no-op. If an error occurs, the appropriate error code is written +** into *pRC. +*/ +static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ + DbPage *pDbPage; /* The pointer map page */ + u8 *pPtrmap; /* The pointer map data */ + Pgno iPtrmap; /* The pointer map page number */ + int offset; /* Offset in pointer map page */ + int rc; /* Return code from subfunctions */ + + if( *pRC ) return; + + assert( sqlite3_mutex_held(pBt->mutex) ); + /* The master-journal page number must never be used as a pointer map page */ + assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); + + assert( pBt->autoVacuum ); + if( key==0 ){ + *pRC = SQLITE_CORRUPT_BKPT; + return; + } + iPtrmap = PTRMAP_PAGENO(pBt, key); + rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); + if( rc!=SQLITE_OK ){ + *pRC = rc; + return; + } + offset = PTRMAP_PTROFFSET(iPtrmap, key); + if( offset<0 ){ + *pRC = SQLITE_CORRUPT_BKPT; + goto ptrmap_exit; + } + assert( offset <= (int)pBt->usableSize-5 ); + pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); + + if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ + TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); + *pRC= rc = sqlite3PagerWrite(pDbPage); + if( rc==SQLITE_OK ){ + pPtrmap[offset] = eType; + put4byte(&pPtrmap[offset+1], parent); + } + } + +ptrmap_exit: + sqlite3PagerUnref(pDbPage); +} + +/* +** Read an entry from the pointer map. +** +** This routine retrieves the pointer map entry for page 'key', writing +** the type and parent page number to *pEType and *pPgno respectively. +** An error code is returned if something goes wrong, otherwise SQLITE_OK. +*/ +static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ + DbPage *pDbPage; /* The pointer map page */ + int iPtrmap; /* Pointer map page index */ + u8 *pPtrmap; /* Pointer map page data */ + int offset; /* Offset of entry in pointer map */ + int rc; + + assert( sqlite3_mutex_held(pBt->mutex) ); + + iPtrmap = PTRMAP_PAGENO(pBt, key); + rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); + if( rc!=0 ){ + return rc; + } + pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); + + offset = PTRMAP_PTROFFSET(iPtrmap, key); + if( offset<0 ){ + sqlite3PagerUnref(pDbPage); + return SQLITE_CORRUPT_BKPT; + } + assert( offset <= (int)pBt->usableSize-5 ); + assert( pEType!=0 ); + *pEType = pPtrmap[offset]; + if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); + + sqlite3PagerUnref(pDbPage); + if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; + return SQLITE_OK; +} + +#else /* if defined SQLITE_OMIT_AUTOVACUUM */ + #define ptrmapPut(w,x,y,z,rc) + #define ptrmapGet(w,x,y,z) SQLITE_OK + #define ptrmapPutOvflPtr(x, y, rc) +#endif + +/* +** Given a btree page and a cell index (0 means the first cell on +** the page, 1 means the second cell, and so forth) return a pointer +** to the cell content. +** +** findCellPastPtr() does the same except it skips past the initial +** 4-byte child pointer found on interior pages, if there is one. +** +** This routine works only for pages that do not contain overflow cells. +*/ +#define findCell(P,I) \ + ((P)->aData + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)]))) +#define findCellPastPtr(P,I) \ + ((P)->aDataOfst + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)]))) + + +/* +** This is common tail processing for btreeParseCellPtr() and +** btreeParseCellPtrIndex() for the case when the cell does not fit entirely +** on a single B-tree page. Make necessary adjustments to the CellInfo +** structure. +*/ +static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( + MemPage *pPage, /* Page containing the cell */ + u8 *pCell, /* Pointer to the cell text. */ + CellInfo *pInfo /* Fill in this structure */ +){ + /* If the payload will not fit completely on the local page, we have + ** to decide how much to store locally and how much to spill onto + ** overflow pages. The strategy is to minimize the amount of unused + ** space on overflow pages while keeping the amount of local storage + ** in between minLocal and maxLocal. + ** + ** Warning: changing the way overflow payload is distributed in any + ** way will result in an incompatible file format. + */ + int minLocal; /* Minimum amount of payload held locally */ + int maxLocal; /* Maximum amount of payload held locally */ + int surplus; /* Overflow payload available for local storage */ + + minLocal = pPage->minLocal; + maxLocal = pPage->maxLocal; + surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4); + testcase( surplus==maxLocal ); + testcase( surplus==maxLocal+1 ); + if( surplus <= maxLocal ){ + pInfo->nLocal = (u16)surplus; + }else{ + pInfo->nLocal = (u16)minLocal; + } + pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; +} + +/* +** The following routines are implementations of the MemPage.xParseCell() +** method. +** +** Parse a cell content block and fill in the CellInfo structure. +** +** btreeParseCellPtr() => table btree leaf nodes +** btreeParseCellNoPayload() => table btree internal nodes +** btreeParseCellPtrIndex() => index btree nodes +** +** There is also a wrapper function btreeParseCell() that works for +** all MemPage types and that references the cell by index rather than +** by pointer. +*/ +static void btreeParseCellPtrNoPayload( + MemPage *pPage, /* Page containing the cell */ + u8 *pCell, /* Pointer to the cell text. */ + CellInfo *pInfo /* Fill in this structure */ +){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->leaf==0 ); + assert( pPage->childPtrSize==4 ); +#ifndef SQLITE_DEBUG + UNUSED_PARAMETER(pPage); +#endif + pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); + pInfo->nPayload = 0; + pInfo->nLocal = 0; + pInfo->pPayload = 0; + return; +} +static void btreeParseCellPtr( + MemPage *pPage, /* Page containing the cell */ + u8 *pCell, /* Pointer to the cell text. */ + CellInfo *pInfo /* Fill in this structure */ +){ + u8 *pIter; /* For scanning through pCell */ + u32 nPayload; /* Number of bytes of cell payload */ + u64 iKey; /* Extracted Key value */ + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->leaf==0 || pPage->leaf==1 ); + assert( pPage->intKeyLeaf ); + assert( pPage->childPtrSize==0 ); + pIter = pCell; + + /* The next block of code is equivalent to: + ** + ** pIter += getVarint32(pIter, nPayload); + ** + ** The code is inlined to avoid a function call. + */ + nPayload = *pIter; + if( nPayload>=0x80 ){ + u8 *pEnd = &pIter[8]; + nPayload &= 0x7f; + do{ + nPayload = (nPayload<<7) | (*++pIter & 0x7f); + }while( (*pIter)>=0x80 && pIternKey); + ** + ** The code is inlined to avoid a function call. + */ + iKey = *pIter; + if( iKey>=0x80 ){ + u8 *pEnd = &pIter[7]; + iKey &= 0x7f; + while(1){ + iKey = (iKey<<7) | (*++pIter & 0x7f); + if( (*pIter)<0x80 ) break; + if( pIter>=pEnd ){ + iKey = (iKey<<8) | *++pIter; + break; + } + } + } + pIter++; + + pInfo->nKey = *(i64*)&iKey; + pInfo->nPayload = nPayload; + pInfo->pPayload = pIter; + testcase( nPayload==pPage->maxLocal ); + testcase( nPayload==pPage->maxLocal+1 ); + if( nPayload<=pPage->maxLocal ){ + /* This is the (easy) common case where the entire payload fits + ** on the local page. No overflow is required. + */ + pInfo->nSize = nPayload + (u16)(pIter - pCell); + if( pInfo->nSize<4 ) pInfo->nSize = 4; + pInfo->nLocal = (u16)nPayload; + }else{ + btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); + } +} +static void btreeParseCellPtrIndex( + MemPage *pPage, /* Page containing the cell */ + u8 *pCell, /* Pointer to the cell text. */ + CellInfo *pInfo /* Fill in this structure */ +){ + u8 *pIter; /* For scanning through pCell */ + u32 nPayload; /* Number of bytes of cell payload */ + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->leaf==0 || pPage->leaf==1 ); + assert( pPage->intKeyLeaf==0 ); + pIter = pCell + pPage->childPtrSize; + nPayload = *pIter; + if( nPayload>=0x80 ){ + u8 *pEnd = &pIter[8]; + nPayload &= 0x7f; + do{ + nPayload = (nPayload<<7) | (*++pIter & 0x7f); + }while( *(pIter)>=0x80 && pIternKey = nPayload; + pInfo->nPayload = nPayload; + pInfo->pPayload = pIter; + testcase( nPayload==pPage->maxLocal ); + testcase( nPayload==pPage->maxLocal+1 ); + if( nPayload<=pPage->maxLocal ){ + /* This is the (easy) common case where the entire payload fits + ** on the local page. No overflow is required. + */ + pInfo->nSize = nPayload + (u16)(pIter - pCell); + if( pInfo->nSize<4 ) pInfo->nSize = 4; + pInfo->nLocal = (u16)nPayload; + }else{ + btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); + } +} +static void btreeParseCell( + MemPage *pPage, /* Page containing the cell */ + int iCell, /* The cell index. First cell is 0 */ + CellInfo *pInfo /* Fill in this structure */ +){ + pPage->xParseCell(pPage, findCell(pPage, iCell), pInfo); +} + +/* +** The following routines are implementations of the MemPage.xCellSize +** method. +** +** Compute the total number of bytes that a Cell needs in the cell +** data area of the btree-page. The return number includes the cell +** data header and the local payload, but not any overflow page or +** the space used by the cell pointer. +** +** cellSizePtrNoPayload() => table internal nodes +** cellSizePtr() => all index nodes & table leaf nodes +*/ +static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ + u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */ + u8 *pEnd; /* End mark for a varint */ + u32 nSize; /* Size value to return */ + +#ifdef SQLITE_DEBUG + /* The value returned by this function should always be the same as + ** the (CellInfo.nSize) value found by doing a full parse of the + ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of + ** this function verifies that this invariant is not violated. */ + CellInfo debuginfo; + pPage->xParseCell(pPage, pCell, &debuginfo); +#endif + + nSize = *pIter; + if( nSize>=0x80 ){ + pEnd = &pIter[8]; + nSize &= 0x7f; + do{ + nSize = (nSize<<7) | (*++pIter & 0x7f); + }while( *(pIter)>=0x80 && pIterintKey ){ + /* pIter now points at the 64-bit integer key value, a variable length + ** integer. The following block moves pIter to point at the first byte + ** past the end of the key value. */ + pEnd = &pIter[9]; + while( (*pIter++)&0x80 && pItermaxLocal ); + testcase( nSize==pPage->maxLocal+1 ); + if( nSize<=pPage->maxLocal ){ + nSize += (u32)(pIter - pCell); + if( nSize<4 ) nSize = 4; + }else{ + int minLocal = pPage->minLocal; + nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); + testcase( nSize==pPage->maxLocal ); + testcase( nSize==pPage->maxLocal+1 ); + if( nSize>pPage->maxLocal ){ + nSize = minLocal; + } + nSize += 4 + (u16)(pIter - pCell); + } + assert( nSize==debuginfo.nSize || CORRUPT_DB ); + return (u16)nSize; +} +static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){ + u8 *pIter = pCell + 4; /* For looping over bytes of pCell */ + u8 *pEnd; /* End mark for a varint */ + +#ifdef SQLITE_DEBUG + /* The value returned by this function should always be the same as + ** the (CellInfo.nSize) value found by doing a full parse of the + ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of + ** this function verifies that this invariant is not violated. */ + CellInfo debuginfo; + pPage->xParseCell(pPage, pCell, &debuginfo); +#else + UNUSED_PARAMETER(pPage); +#endif + + assert( pPage->childPtrSize==4 ); + pEnd = pIter + 9; + while( (*pIter++)&0x80 && pIterxCellSize(pPage, findCell(pPage, iCell)); +} +#endif + +#ifndef SQLITE_OMIT_AUTOVACUUM +/* +** If the cell pCell, part of page pPage contains a pointer +** to an overflow page, insert an entry into the pointer-map +** for the overflow page. +*/ +static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ + CellInfo info; + if( *pRC ) return; + assert( pCell!=0 ); + pPage->xParseCell(pPage, pCell, &info); + if( info.nLocalpBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); + } +} +#endif + + +/* +** Defragment the page given. This routine reorganizes cells within the +** page so that there are no free-blocks on the free-block list. +** +** Parameter nMaxFrag is the maximum amount of fragmented space that may be +** present in the page after this routine returns. +** +** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a +** b-tree page so that there are no freeblocks or fragment bytes, all +** unused bytes are contained in the unallocated space region, and all +** cells are packed tightly at the end of the page. +*/ +static int defragmentPage(MemPage *pPage, int nMaxFrag){ + int i; /* Loop counter */ + int pc; /* Address of the i-th cell */ + int hdr; /* Offset to the page header */ + int size; /* Size of a cell */ + int usableSize; /* Number of usable bytes on a page */ + int cellOffset; /* Offset to the cell pointer array */ + int cbrk; /* Offset to the cell content area */ + int nCell; /* Number of cells on the page */ + unsigned char *data; /* The page data */ + unsigned char *temp; /* Temp area for cell content */ + unsigned char *src; /* Source of content */ + int iCellFirst; /* First allowable cell index */ + int iCellLast; /* Last possible cell index */ + + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( pPage->pBt!=0 ); + assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); + assert( pPage->nOverflow==0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + temp = 0; + src = data = pPage->aData; + hdr = pPage->hdrOffset; + cellOffset = pPage->cellOffset; + nCell = pPage->nCell; + assert( nCell==get2byte(&data[hdr+3]) ); + iCellFirst = cellOffset + 2*nCell; + usableSize = pPage->pBt->usableSize; + + /* This block handles pages with two or fewer free blocks and nMaxFrag + ** or fewer fragmented bytes. In this case it is faster to move the + ** two (or one) blocks of cells using memmove() and add the required + ** offsets to each pointer in the cell-pointer array than it is to + ** reconstruct the entire page. */ + if( (int)data[hdr+7]<=nMaxFrag ){ + int iFree = get2byte(&data[hdr+1]); + if( iFree ){ + int iFree2 = get2byte(&data[iFree]); + + /* pageFindSlot() has already verified that free blocks are sorted + ** in order of offset within the page, and that no block extends + ** past the end of the page. Provided the two free slots do not + ** overlap, this guarantees that the memmove() calls below will not + ** overwrite the usableSize byte buffer, even if the database page + ** is corrupt. */ + assert( iFree2==0 || iFree2>iFree ); + assert( iFree+get2byte(&data[iFree+2]) <= usableSize ); + assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize ); + + if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ + u8 *pEnd = &data[cellOffset + nCell*2]; + u8 *pAddr; + int sz2 = 0; + int sz = get2byte(&data[iFree+2]); + int top = get2byte(&data[hdr+5]); + if( iFree2 ){ + if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_BKPT; + sz2 = get2byte(&data[iFree2+2]); + assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize ); + memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); + sz += sz2; + } + cbrk = top+sz; + assert( cbrk+(iFree-top) <= usableSize ); + memmove(&data[cbrk], &data[top], iFree-top); + for(pAddr=&data[cellOffset]; pAddriCellLast ){ + return SQLITE_CORRUPT_BKPT; + } + assert( pc>=iCellFirst && pc<=iCellLast ); + size = pPage->xCellSize(pPage, &src[pc]); + cbrk -= size; + if( cbrkusableSize ){ + return SQLITE_CORRUPT_BKPT; + } + assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); + testcase( cbrk+size==usableSize ); + testcase( pc+size==usableSize ); + put2byte(pAddr, cbrk); + if( temp==0 ){ + int x; + if( cbrk==pc ) continue; + temp = sqlite3PagerTempSpace(pPage->pBt->pPager); + x = get2byte(&data[hdr+5]); + memcpy(&temp[x], &data[x], (cbrk+size) - x); + src = temp; + } + memcpy(&data[cbrk], &src[pc], size); + } + data[hdr+7] = 0; + + defragment_out: + if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ + return SQLITE_CORRUPT_BKPT; + } + assert( cbrk>=iCellFirst ); + put2byte(&data[hdr+5], cbrk); + data[hdr+1] = 0; + data[hdr+2] = 0; + memset(&data[iCellFirst], 0, cbrk-iCellFirst); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + return SQLITE_OK; +} + +/* +** Search the free-list on page pPg for space to store a cell nByte bytes in +** size. If one can be found, return a pointer to the space and remove it +** from the free-list. +** +** If no suitable space can be found on the free-list, return NULL. +** +** This function may detect corruption within pPg. If corruption is +** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned. +** +** Slots on the free list that are between 1 and 3 bytes larger than nByte +** will be ignored if adding the extra space to the fragmentation count +** causes the fragmentation count to exceed 60. +*/ +static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ + const int hdr = pPg->hdrOffset; + u8 * const aData = pPg->aData; + int iAddr = hdr + 1; + int pc = get2byte(&aData[iAddr]); + int x; + int usableSize = pPg->pBt->usableSize; + + 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=0 ){ + testcase( x==4 ); + testcase( x==3 ); + if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){ + *pRc = SQLITE_CORRUPT_BKPT; + return 0; + }else if( x<4 ){ + /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total + ** number of bytes in fragments may not exceed 60. */ + if( aData[hdr+7]>57 ) return 0; + + /* Remove the slot from the free-list. Update the number of + ** fragmented bytes within the page. */ + memcpy(&aData[iAddr], &aData[pc], 2); + aData[hdr+7] += (u8)x; + }else{ + /* The slot remains on the free-list. Reduce its size to account + ** for the portion used by the new allocation. */ + put2byte(&aData[pc+2], x); + } + return &aData[pc + x]; + } + iAddr = pc; + pc = get2byte(&aData[pc]); + }while( pc ); + + return 0; +} + +/* +** Allocate nByte bytes of space from within the B-Tree page passed +** as the first argument. Write into *pIdx the index into pPage->aData[] +** of the first byte of allocated space. Return either SQLITE_OK or +** an error code (usually SQLITE_CORRUPT). +** +** The caller guarantees that there is sufficient space to make the +** allocation. This routine might need to defragment in order to bring +** all the space together, however. This routine will avoid using +** the first two bytes past the cell pointer area since presumably this +** allocation is being made in order to insert a new cell, so we will +** also end up needing a new cell pointer. +*/ +static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ + const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ + u8 * const data = pPage->aData; /* Local cache of pPage->aData */ + int top; /* First byte of cell content area */ + int rc = SQLITE_OK; /* Integer return code */ + int gap; /* First byte of gap between cell pointers and cell content */ + + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( pPage->pBt ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( nByte>=0 ); /* Minimum cell size is 4 */ + assert( pPage->nFree>=nByte ); + assert( pPage->nOverflow==0 ); + assert( nByte < (int)(pPage->pBt->usableSize-8) ); + + assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); + gap = pPage->cellOffset + 2*pPage->nCell; + assert( gap<=65536 ); + /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size + ** and the reserved space is zero (the usual value for reserved space) + ** then the cell content offset of an empty page wants to be 65536. + ** However, that integer is too large to be stored in a 2-byte unsigned + ** integer, so a value of 0 is used in its place. */ + top = get2byte(&data[hdr+5]); + assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */ + if( gap>top ){ + if( top==0 && pPage->pBt->usableSize==65536 ){ + top = 65536; + }else{ + return SQLITE_CORRUPT_BKPT; + } + } + + /* If there is enough space between gap and top for one more cell pointer + ** array entry offset, and if the freelist is not empty, then search the + ** freelist looking for a free slot big enough to satisfy the request. + */ + testcase( gap+2==top ); + testcase( gap+1==top ); + testcase( gap==top ); + if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){ + u8 *pSpace = pageFindSlot(pPage, nByte, &rc); + if( pSpace ){ + assert( pSpace>=data && (pSpace - data)<65536 ); + *pIdx = (int)(pSpace - data); + return SQLITE_OK; + }else if( rc ){ + return rc; + } + } + + /* The request could not be fulfilled using a freelist slot. Check + ** to see if defragmentation is necessary. + */ + testcase( gap+2+nByte==top ); + if( gap+2+nByte>top ){ + assert( pPage->nCell>0 || CORRUPT_DB ); + rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); + if( rc ) return rc; + top = get2byteNotZero(&data[hdr+5]); + assert( gap+2+nByte<=top ); + } + + + /* Allocate memory from the gap in between the cell pointer array + ** and the cell content area. The btreeInitPage() call has already + ** validated the freelist. Given that the freelist is valid, there + ** is no way that the allocation can extend off the end of the page. + ** The assert() below verifies the previous sentence. + */ + top -= nByte; + put2byte(&data[hdr+5], top); + assert( top+nByte <= (int)pPage->pBt->usableSize ); + *pIdx = top; + return SQLITE_OK; +} + +/* +** Return a section of the pPage->aData to the freelist. +** The first byte of the new free block is pPage->aData[iStart] +** and the size of the block is iSize bytes. +** +** Adjacent freeblocks are coalesced. +** +** Note that even though the freeblock list was checked by btreeInitPage(), +** that routine will not detect overlap between cells or freeblocks. Nor +** does it detect cells or freeblocks that encrouch into the reserved bytes +** at the end of the page. So do additional corruption checks inside this +** routine and return SQLITE_CORRUPT if any problems are found. +*/ +static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ + u16 iPtr; /* Address of ptr to next freeblock */ + u16 iFreeBlk; /* Address of the next freeblock */ + u8 hdr; /* Page header size. 0 or 100 */ + u8 nFrag = 0; /* Reduction in fragmentation */ + u16 iOrigSize = iSize; /* Original value of iSize */ + u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */ + u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ + unsigned char *data = pPage->aData; /* Page content */ + + assert( pPage->pBt!=0 ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( CORRUPT_DB || iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); + 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_SECURE_DELETE ){ + memset(&data[iStart], 0, iSize); + } + + /* The list of freeblocks must be in ascending order. Find the + ** spot on the list where iStart should be inserted. + */ + hdr = pPage->hdrOffset; + iPtr = hdr + 1; + if( data[iPtr+1]==0 && data[iPtr]==0 ){ + iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */ + }else{ + while( (iFreeBlk = get2byte(&data[iPtr]))iLast ) return SQLITE_CORRUPT_BKPT; + assert( iFreeBlk>iPtr || iFreeBlk==0 ); + + /* At this point: + ** iFreeBlk: First freeblock after iStart, or zero if none + ** iPtr: The address of a pointer to iFreeBlk + ** + ** Check to see if iFreeBlk should be coalesced onto the end of iStart. + */ + if( iFreeBlk && iEnd+3>=iFreeBlk ){ + nFrag = iFreeBlk - iEnd; + if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT; + iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); + if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT; + iSize = iEnd - iStart; + iFreeBlk = get2byte(&data[iFreeBlk]); + } + + /* If iPtr is another freeblock (that is, if iPtr is not the freelist + ** pointer in the page header) then check to see if iStart should be + ** coalesced onto the end of iPtr. + */ + if( iPtr>hdr+1 ){ + int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); + if( iPtrEnd+3>=iStart ){ + if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT; + nFrag += iStart - iPtrEnd; + iSize = iEnd - iPtr; + iStart = iPtr; + } + } + if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT; + data[hdr+7] -= nFrag; + } + if( iStart==get2byte(&data[hdr+5]) ){ + /* 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_BKPT; + 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); + } + pPage->nFree += iOrigSize; + return SQLITE_OK; +} + +/* +** Decode the flags byte (the first byte of the header) for a page +** and initialize fields of the MemPage structure accordingly. +** +** Only the following combinations are supported. Anything different +** indicates a corrupt database files: +** +** PTF_ZERODATA +** PTF_ZERODATA | PTF_LEAF +** PTF_LEAFDATA | PTF_INTKEY +** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF +*/ +static int decodeFlags(MemPage *pPage, int flagByte){ + BtShared *pBt; /* A copy of pPage->pBt */ + + assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 ); + flagByte &= ~PTF_LEAF; + pPage->childPtrSize = 4-4*pPage->leaf; + pPage->xCellSize = cellSizePtr; + pBt = pPage->pBt; + if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ + /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an + ** interior table b-tree page. */ + assert( (PTF_LEAFDATA|PTF_INTKEY)==5 ); + /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a + ** leaf table b-tree page. */ + assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 ); + pPage->intKey = 1; + if( pPage->leaf ){ + pPage->intKeyLeaf = 1; + pPage->xParseCell = btreeParseCellPtr; + }else{ + pPage->intKeyLeaf = 0; + pPage->xCellSize = cellSizePtrNoPayload; + pPage->xParseCell = btreeParseCellPtrNoPayload; + } + pPage->maxLocal = pBt->maxLeaf; + pPage->minLocal = pBt->minLeaf; + }else if( flagByte==PTF_ZERODATA ){ + /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an + ** interior index b-tree page. */ + assert( (PTF_ZERODATA)==2 ); + /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a + ** leaf index b-tree page. */ + assert( (PTF_ZERODATA|PTF_LEAF)==10 ); + pPage->intKey = 0; + pPage->intKeyLeaf = 0; + pPage->xParseCell = btreeParseCellPtrIndex; + pPage->maxLocal = pBt->maxLocal; + pPage->minLocal = pBt->minLocal; + }else{ + /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is + ** an error. */ + return SQLITE_CORRUPT_BKPT; + } + pPage->max1bytePayload = pBt->max1bytePayload; + return SQLITE_OK; +} + +/* +** Initialize the auxiliary information for a disk block. +** +** Return SQLITE_OK on success. If we see that the page does +** not contain a well-formed database page, then return +** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not +** guarantee that the page is well-formed. It only shows that +** we failed to detect any corruption. +*/ +static int btreeInitPage(MemPage *pPage){ + + assert( pPage->pBt!=0 ); + assert( pPage->pBt->db!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + + if( !pPage->isInit ){ + int pc; /* Address of a freeblock within pPage->aData[] */ + u8 hdr; /* Offset to beginning of page header */ + u8 *data; /* Equal to pPage->aData */ + BtShared *pBt; /* The main btree structure */ + int usableSize; /* Amount of usable space on each page */ + u16 cellOffset; /* Offset from start of page to first cell pointer */ + int nFree; /* Number of unused bytes on the page */ + int top; /* First byte of the cell content area */ + int iCellFirst; /* First allowable cell or freeblock offset */ + int iCellLast; /* Last possible cell or freeblock offset */ + + pBt = pPage->pBt; + + hdr = pPage->hdrOffset; + data = pPage->aData; + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ + if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nOverflow = 0; + usableSize = pBt->usableSize; + pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; + pPage->aDataEnd = &data[usableSize]; + pPage->aCellIdx = &data[cellOffset]; + pPage->aDataOfst = &data[pPage->childPtrSize]; + /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates + ** the start of the cell content area. A zero value for this integer is + ** interpreted as 65536. */ + top = get2byteNotZero(&data[hdr+5]); + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ + pPage->nCell = get2byte(&data[hdr+3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* To many cells for a single page. The page must be corrupt */ + return SQLITE_CORRUPT_BKPT; + } + testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only + ** possible for a root page of a table that contains no rows) then the + ** offset to the cell content area will equal the page size minus the + ** bytes of reserved space. */ + assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); + + /* A malformed database page might cause us to read past the end + ** of page when parsing a cell. + ** + ** The following block of code checks early to see if a cell extends + ** past the end of a page boundary and causes SQLITE_CORRUPT to be + ** returned if it does. + */ + iCellFirst = cellOffset + 2*pPage->nCell; + iCellLast = usableSize - 4; + if( pBt->db->flags & SQLITE_CellSizeCk ){ + int i; /* Index into the cell pointer array */ + int sz; /* Size of a cell */ + + if( !pPage->leaf ) iCellLast--; + for(i=0; inCell; i++){ + pc = get2byteAligned(&data[cellOffset+i*2]); + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); + if( pciCellLast ){ + return SQLITE_CORRUPT_BKPT; + } + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ + return SQLITE_CORRUPT_BKPT; + } + } + if( !pPage->leaf ) iCellLast++; + } + + /* Compute the total free space on the page + ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the + ** start of the first freeblock on the page, or is zero if there are no + ** freeblocks. */ + pc = get2byte(&data[hdr+1]); + nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ + if( pc>0 ){ + u32 next, size; + if( pciCellLast ){ + return SQLITE_CORRUPT_BKPT; /* Freeblock off the end of the page */ + } + next = get2byte(&data[pc]); + size = get2byte(&data[pc+2]); + nFree = nFree + size; + if( next<=pc+size+3 ) break; + pc = next; + } + if( next>0 ){ + return SQLITE_CORRUPT_BKPT; /* Freeblock not in ascending order */ + } + if( pc+size>(unsigned int)usableSize ){ + return SQLITE_CORRUPT_BKPT; /* Last freeblock extends past page end */ + } + } + + /* At this point, nFree contains the sum of the offset to the start + ** of the cell-content area plus the number of free bytes within + ** the cell-content area. If this is greater than the usable-size + ** of the page, then the page must be corrupted. This check also + ** serves to verify that the offset to the start of the cell-content + ** area, according to the page header, lies within the page. + */ + if( nFree>usableSize ){ + return SQLITE_CORRUPT_BKPT; + } + pPage->nFree = (u16)(nFree - iCellFirst); + pPage->isInit = 1; + } + return SQLITE_OK; +} + +/* +** Set up a raw page so that it looks like a database page holding +** no entries. +*/ +static void zeroPage(MemPage *pPage, int flags){ + unsigned char *data = pPage->aData; + BtShared *pBt = pPage->pBt; + u8 hdr = pPage->hdrOffset; + u16 first; + + assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage) == data ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pBt->btsFlags & BTS_SECURE_DELETE ){ + memset(&data[hdr], 0, pBt->usableSize - hdr); + } + data[hdr] = (char)flags; + first = hdr + ((flags&PTF_LEAF)==0 ? 12 : 8); + memset(&data[hdr+1], 0, 4); + data[hdr+7] = 0; + put2byte(&data[hdr+5], pBt->usableSize); + pPage->nFree = (u16)(pBt->usableSize - first); + decodeFlags(pPage, flags); + pPage->cellOffset = first; + pPage->aDataEnd = &data[pBt->usableSize]; + pPage->aCellIdx = &data[first]; + pPage->aDataOfst = &data[pPage->childPtrSize]; + pPage->nOverflow = 0; + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nCell = 0; + pPage->isInit = 1; +} + + +/* +** Convert a DbPage obtained from the pager into a MemPage used by +** the btree layer. +*/ +static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){ + MemPage *pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); + if( pgno!=pPage->pgno ){ + pPage->aData = sqlite3PagerGetData(pDbPage); + pPage->pDbPage = pDbPage; + pPage->pBt = pBt; + pPage->pgno = pgno; + pPage->hdrOffset = pgno==1 ? 100 : 0; + } + assert( pPage->aData==sqlite3PagerGetData(pDbPage) ); + return pPage; +} + +/* +** Get a page from the pager. Initialize the MemPage.pBt and +** MemPage.aData elements if needed. See also: btreeGetUnusedPage(). +** +** If the PAGER_GET_NOCONTENT flag is set, it means that we do not care +** about the content of the page at this time. So do not go to the disk +** to fetch the content. Just fill in the content with zeros for now. +** If in the future we call sqlite3PagerWrite() on this page, that +** means we have started to be concerned about content and the disk +** read should occur at that point. +*/ +static int btreeGetPage( + BtShared *pBt, /* The btree */ + Pgno pgno, /* Number of the page to fetch */ + MemPage **ppPage, /* Return the page in this parameter */ + int flags /* PAGER_GET_NOCONTENT or PAGER_GET_READONLY */ +){ + int rc; + DbPage *pDbPage; + + assert( flags==0 || flags==PAGER_GET_NOCONTENT || flags==PAGER_GET_READONLY ); + assert( sqlite3_mutex_held(pBt->mutex) ); + rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, flags); + if( rc ) return rc; + *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt); + return SQLITE_OK; +} + +/* +** Retrieve a page from the pager cache. If the requested page is not +** already in the pager cache return NULL. Initialize the MemPage.pBt and +** MemPage.aData elements if needed. +*/ +static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){ + DbPage *pDbPage; + assert( sqlite3_mutex_held(pBt->mutex) ); + pDbPage = sqlite3PagerLookup(pBt->pPager, pgno); + if( pDbPage ){ + return btreePageFromDbPage(pDbPage, pgno, pBt); + } + return 0; +} + +/* +** Return the size of the database file in pages. If there is any kind of +** error, return ((unsigned int)-1). +*/ +static Pgno btreePagecount(BtShared *pBt){ + return pBt->nPage; +} +SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){ + assert( sqlite3BtreeHoldsMutex(p) ); + assert( ((p->pBt->nPage)&0x8000000)==0 ); + return btreePagecount(p->pBt); +} + +/* +** Get a page from the pager and initialize it. +** +** If pCur!=0 then the page is being fetched as part of a moveToChild() +** call. Do additional sanity checking on the page in this case. +** And if the fetch fails, this routine must decrement pCur->iPage. +** +** The page is fetched as read-write unless pCur is not NULL and is +** a read-only cursor. +** +** If an error occurs, then *ppPage is undefined. It +** may remain unchanged, or it may be set to an invalid value. +*/ +static int getAndInitPage( + BtShared *pBt, /* The database file */ + Pgno pgno, /* Number of the page to get */ + MemPage **ppPage, /* Write the page pointer here */ + BtCursor *pCur, /* Cursor to receive the page, or NULL */ + int bReadOnly /* True for a read-only page */ +){ + int rc; + DbPage *pDbPage; + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] ); + assert( pCur==0 || bReadOnly==pCur->curPagerFlags ); + assert( pCur==0 || pCur->iPage>0 ); + + if( pgno>btreePagecount(pBt) ){ + rc = SQLITE_CORRUPT_BKPT; + goto getAndInitPage_error; + } + rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); + if( rc ){ + goto getAndInitPage_error; + } + *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); + if( (*ppPage)->isInit==0 ){ + btreePageFromDbPage(pDbPage, pgno, pBt); + rc = btreeInitPage(*ppPage); + if( rc!=SQLITE_OK ){ + releasePage(*ppPage); + goto getAndInitPage_error; + } + } + assert( (*ppPage)->pgno==pgno ); + assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) ); + + /* If obtaining a child page for a cursor, we must verify that the page is + ** compatible with the root page. */ + if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ + rc = SQLITE_CORRUPT_BKPT; + releasePage(*ppPage); + goto getAndInitPage_error; + } + return SQLITE_OK; + +getAndInitPage_error: + if( pCur ) pCur->iPage--; + testcase( pgno==0 ); + assert( pgno!=0 || rc==SQLITE_CORRUPT ); + return rc; +} + +/* +** Release a MemPage. This should be called once for each prior +** call to btreeGetPage. +*/ +static void releasePageNotNull(MemPage *pPage){ + 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) ); + sqlite3PagerUnrefNotNull(pPage->pDbPage); +} +static void releasePage(MemPage *pPage){ + if( pPage ) releasePageNotNull(pPage); +} + +/* +** Get an unused page. +** +** This works just like btreeGetPage() with the addition: +** +** * If the page is already in use for some other purpose, immediately +** release it and return an SQLITE_CURRUPT error. +** * Make sure the isInit flag is clear +*/ +static int btreeGetUnusedPage( + BtShared *pBt, /* The btree */ + Pgno pgno, /* Number of the page to fetch */ + MemPage **ppPage, /* Return the page in this parameter */ + int flags /* PAGER_GET_NOCONTENT or PAGER_GET_READONLY */ +){ + int rc = btreeGetPage(pBt, pgno, ppPage, flags); + if( rc==SQLITE_OK ){ + if( sqlite3PagerPageRefcount((*ppPage)->pDbPage)>1 ){ + releasePage(*ppPage); + *ppPage = 0; + return SQLITE_CORRUPT_BKPT; + } + (*ppPage)->isInit = 0; + }else{ + *ppPage = 0; + } + return rc; +} + + +/* +** During a rollback, when the pager reloads information into the cache +** so that the cache is restored to its original state at the start of +** the transaction, for each page restored this routine is called. +** +** This routine needs to reset the extra data section at the end of the +** page to agree with the restored data. +*/ +static void pageReinit(DbPage *pData){ + MemPage *pPage; + pPage = (MemPage *)sqlite3PagerGetExtra(pData); + assert( sqlite3PagerPageRefcount(pData)>0 ); + if( pPage->isInit ){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pPage->isInit = 0; + if( sqlite3PagerPageRefcount(pData)>1 ){ + /* pPage might not be a btree page; it might be an overflow page + ** or ptrmap page or a free page. In those cases, the following + ** call to btreeInitPage() will likely return SQLITE_CORRUPT. + ** But no harm is done by this. And it is very important that + ** btreeInitPage() be called on every btree page so we make + ** the call for every page that comes in for re-initing. */ + btreeInitPage(pPage); + } + } +} + +/* +** Invoke the busy handler for a btree. +*/ +static int btreeInvokeBusyHandler(void *pArg){ + BtShared *pBt = (BtShared*)pArg; + assert( pBt->db ); + assert( sqlite3_mutex_held(pBt->db->mutex) ); + return sqlite3InvokeBusyHandler(&pBt->db->busyHandler); +} + +/* +** Open a database file. +** +** zFilename is the name of the database file. If zFilename is NULL +** then an ephemeral database is created. The ephemeral database might +** be exclusively in memory, or it might use a disk-based memory cache. +** Either way, the ephemeral database will be automatically deleted +** when sqlite3BtreeClose() is called. +** +** If zFilename is ":memory:" then an in-memory database is created +** that is automatically destroyed when it is closed. +** +** The "flags" parameter is a bitmask that might contain bits like +** BTREE_OMIT_JOURNAL and/or BTREE_MEMORY. +** +** If the database is already opened in the same database connection +** and we are in shared cache mode, then the open will fail with an +** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared +** objects in the same database connection since doing so will lead +** to problems with locking. +*/ +SQLITE_PRIVATE int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ + const char *zFilename, /* Name of the file containing the BTree database */ + sqlite3 *db, /* Associated database handle */ + Btree **ppBtree, /* Pointer to new Btree object written here */ + int flags, /* Options */ + int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ +){ + BtShared *pBt = 0; /* Shared part of btree structure */ + Btree *p; /* Handle to return */ + sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */ + int rc = SQLITE_OK; /* Result code from this function */ + u8 nReserve; /* Byte of unused space on each page */ + unsigned char zDbHeader[100]; /* Database header content */ + + /* True if opening an ephemeral, temporary database */ + const int isTempDb = zFilename==0 || zFilename[0]==0; + + /* Set the variable isMemdb to true for an in-memory database, or + ** false for a file-based database. + */ +#ifdef SQLITE_OMIT_MEMORYDB + const int isMemdb = 0; +#else + const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0) + || (isTempDb && sqlite3TempInMemory(db)) + || (vfsFlags & SQLITE_OPEN_MEMORY)!=0; +#endif + + assert( db!=0 ); + assert( pVfs!=0 ); + assert( sqlite3_mutex_held(db->mutex) ); + assert( (flags&0xff)==flags ); /* flags fit in 8 bits */ + + /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ + assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 ); + + /* A BTREE_SINGLE database is always a temporary and/or ephemeral */ + assert( (flags & BTREE_SINGLE)==0 || isTempDb ); + + if( isMemdb ){ + flags |= BTREE_MEMORY; + } + if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){ + vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; + } + p = sqlite3MallocZero(sizeof(Btree)); + if( !p ){ + return SQLITE_NOMEM_BKPT; + } + p->inTrans = TRANS_NONE; + p->db = db; +#ifndef SQLITE_OMIT_SHARED_CACHE + p->lock.pBtree = p; + p->lock.iTable = 1; +#endif + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) + /* + ** If this Btree is a candidate for shared cache, try to find an + ** existing BtShared object that we can share with + */ + if( isTempDb==0 && (isMemdb==0 || (vfsFlags&SQLITE_OPEN_URI)!=0) ){ + if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){ + int nFilename = sqlite3Strlen30(zFilename)+1; + int nFullPathname = pVfs->mxPathname+1; + char *zFullPathname = sqlite3Malloc(MAX(nFullPathname,nFilename)); + MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) + + p->sharable = 1; + if( !zFullPathname ){ + sqlite3_free(p); + return SQLITE_NOMEM_BKPT; + } + if( isMemdb ){ + memcpy(zFullPathname, zFilename, nFilename); + }else{ + rc = sqlite3OsFullPathname(pVfs, zFilename, + nFullPathname, zFullPathname); + if( rc ){ + sqlite3_free(zFullPathname); + sqlite3_free(p); + return rc; + } + } +#if SQLITE_THREADSAFE + mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); + sqlite3_mutex_enter(mutexOpen); + mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex_enter(mutexShared); +#endif + for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){ + assert( pBt->nRef>0 ); + if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager, 0)) + && sqlite3PagerVfs(pBt->pPager)==pVfs ){ + int iDb; + for(iDb=db->nDb-1; iDb>=0; iDb--){ + Btree *pExisting = db->aDb[iDb].pBt; + if( pExisting && pExisting->pBt==pBt ){ + sqlite3_mutex_leave(mutexShared); + sqlite3_mutex_leave(mutexOpen); + sqlite3_free(zFullPathname); + sqlite3_free(p); + return SQLITE_CONSTRAINT; + } + } + p->pBt = pBt; + pBt->nRef++; + break; + } + } + sqlite3_mutex_leave(mutexShared); + sqlite3_free(zFullPathname); + } +#ifdef SQLITE_DEBUG + else{ + /* In debug mode, we mark all persistent databases as sharable + ** even when they are not. This exercises the locking code and + ** gives more opportunity for asserts(sqlite3_mutex_held()) + ** statements to find locking problems. + */ + p->sharable = 1; + } +#endif + } +#endif + if( pBt==0 ){ + /* + ** The following asserts make sure that structures used by the btree are + ** the right size. This is to guard against size changes that result + ** when compiling on a different architecture. + */ + assert( sizeof(i64)==8 ); + assert( sizeof(u64)==8 ); + assert( sizeof(u32)==4 ); + assert( sizeof(u16)==2 ); + assert( sizeof(Pgno)==4 ); + + pBt = sqlite3MallocZero( sizeof(*pBt) ); + if( pBt==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto btree_open_out; + } + rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, + sizeof(MemPage), flags, vfsFlags, pageReinit); + if( rc==SQLITE_OK ){ + sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap); + rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); + } + if( rc!=SQLITE_OK ){ + goto btree_open_out; + } + pBt->openFlags = (u8)flags; + pBt->db = db; + sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt); + p->pBt = pBt; + + pBt->pCursor = 0; + pBt->pPage1 = 0; + if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY; +#ifdef SQLITE_SECURE_DELETE + pBt->btsFlags |= BTS_SECURE_DELETE; +#endif + /* EVIDENCE-OF: R-51873-39618 The page size for a database file is + ** determined by the 2-byte integer located at an offset of 16 bytes from + ** the beginning of the database file. */ + pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16); + if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE + || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ + pBt->pageSize = 0; +#ifndef SQLITE_OMIT_AUTOVACUUM + /* If the magic name ":memory:" will create an in-memory database, then + ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if + ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if + ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a + ** regular file-name. In this case the auto-vacuum applies as per normal. + */ + if( zFilename && !isMemdb ){ + pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0); + pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0); + } +#endif + nReserve = 0; + }else{ + /* EVIDENCE-OF: R-37497-42412 The size of the reserved region is + ** determined by the one-byte unsigned integer found at an offset of 20 + ** into the database file header. */ + nReserve = zDbHeader[20]; + pBt->btsFlags |= BTS_PAGESIZE_FIXED; +#ifndef SQLITE_OMIT_AUTOVACUUM + pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0); + pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0); +#endif + } + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); + if( rc ) goto btree_open_out; + pBt->usableSize = pBt->pageSize - nReserve; + assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) + /* Add the new BtShared object to the linked list sharable BtShareds. + */ + pBt->nRef = 1; + if( p->sharable ){ + MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) + MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);) + if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ + pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); + if( pBt->mutex==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto btree_open_out; + } + } + sqlite3_mutex_enter(mutexShared); + pBt->pNext = GLOBAL(BtShared*,sqlite3SharedCacheList); + GLOBAL(BtShared*,sqlite3SharedCacheList) = pBt; + sqlite3_mutex_leave(mutexShared); + } +#endif + } + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) + /* If the new Btree uses a sharable pBtShared, then link the new + ** Btree into the list of all sharable Btrees for the same connection. + ** The list is kept in ascending order by pBt address. + */ + if( p->sharable ){ + int i; + Btree *pSib; + for(i=0; inDb; i++){ + if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){ + while( pSib->pPrev ){ pSib = pSib->pPrev; } + if( (uptr)p->pBt<(uptr)pSib->pBt ){ + p->pNext = pSib; + p->pPrev = 0; + pSib->pPrev = p; + }else{ + while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){ + pSib = pSib->pNext; + } + p->pNext = pSib->pNext; + p->pPrev = pSib; + if( p->pNext ){ + p->pNext->pPrev = p; + } + pSib->pNext = p; + } + break; + } + } + } +#endif + *ppBtree = p; + +btree_open_out: + if( rc!=SQLITE_OK ){ + if( pBt && pBt->pPager ){ + sqlite3PagerClose(pBt->pPager, 0); + } + sqlite3_free(pBt); + sqlite3_free(p); + *ppBtree = 0; + }else{ + sqlite3_file *pFile; + + /* If the B-Tree was successfully opened, set the pager-cache size to the + ** default value. Except, when opening on an existing shared pager-cache, + ** do not change the pager-cache size. + */ + if( sqlite3BtreeSchema(p, 0, 0)==0 ){ + sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE); + } + + pFile = sqlite3PagerFile(pBt->pPager); + if( pFile->pMethods ){ + sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db); + } + } + if( mutexOpen ){ + assert( sqlite3_mutex_held(mutexOpen) ); + sqlite3_mutex_leave(mutexOpen); + } + assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 ); + return rc; +} + +/* +** Decrement the BtShared.nRef counter. When it reaches zero, +** remove the BtShared structure from the sharing list. Return +** true if the BtShared.nRef counter reaches zero and return +** false if it is still positive. +*/ +static int removeFromSharingList(BtShared *pBt){ +#ifndef SQLITE_OMIT_SHARED_CACHE + MUTEX_LOGIC( sqlite3_mutex *pMaster; ) + BtShared *pList; + int removed = 0; + + assert( sqlite3_mutex_notheld(pBt->mutex) ); + MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) + sqlite3_mutex_enter(pMaster); + pBt->nRef--; + if( pBt->nRef<=0 ){ + if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){ + GLOBAL(BtShared*,sqlite3SharedCacheList) = pBt->pNext; + }else{ + pList = GLOBAL(BtShared*,sqlite3SharedCacheList); + while( ALWAYS(pList) && pList->pNext!=pBt ){ + pList=pList->pNext; + } + if( ALWAYS(pList) ){ + pList->pNext = pBt->pNext; + } + } + if( SQLITE_THREADSAFE ){ + sqlite3_mutex_free(pBt->mutex); + } + removed = 1; + } + sqlite3_mutex_leave(pMaster); + return removed; +#else + return 1; +#endif +} + +/* +** Make sure pBt->pTmpSpace points to an allocation of +** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child +** pointer. +*/ +static void allocateTempSpace(BtShared *pBt){ + if( !pBt->pTmpSpace ){ + pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); + + /* One of the uses of pBt->pTmpSpace is to format cells before + ** inserting them into a leaf page (function fillInCell()). If + ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes + ** by the various routines that manipulate binary cells. Which + ** can mean that fillInCell() only initializes the first 2 or 3 + ** bytes of pTmpSpace, but that the first 4 bytes are copied from + ** it into a database page. This is not actually a problem, but it + ** does cause a valgrind error when the 1 or 2 bytes of unitialized + ** data is passed to system call write(). So to avoid this error, + ** zero the first 4 bytes of temp space here. + ** + ** Also: Provide four bytes of initialized space before the + ** beginning of pTmpSpace as an area available to prepend the + ** left-child pointer to the beginning of a cell. + */ + if( pBt->pTmpSpace ){ + memset(pBt->pTmpSpace, 0, 8); + pBt->pTmpSpace += 4; + } + } +} + +/* +** Free the pBt->pTmpSpace allocation +*/ +static void freeTempSpace(BtShared *pBt){ + if( pBt->pTmpSpace ){ + pBt->pTmpSpace -= 4; + sqlite3PageFree(pBt->pTmpSpace); + pBt->pTmpSpace = 0; + } +} + +/* +** Close an open database and invalidate all cursors. +*/ +SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ + BtShared *pBt = p->pBt; + BtCursor *pCur; + + /* Close all cursors opened via this handle. */ + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + pCur = pBt->pCursor; + while( pCur ){ + BtCursor *pTmp = pCur; + pCur = pCur->pNext; + if( pTmp->pBtree==p ){ + sqlite3BtreeCloseCursor(pTmp); + } + } + + /* Rollback any active transaction and free the handle structure. + ** The call to sqlite3BtreeRollback() drops any table-locks held by + ** this handle. + */ + sqlite3BtreeRollback(p, SQLITE_OK, 0); + sqlite3BtreeLeave(p); + + /* If there are still other outstanding references to the shared-btree + ** structure, return now. The remainder of this procedure cleans + ** up the shared-btree. + */ + assert( p->wantToLock==0 && p->locked==0 ); + if( !p->sharable || removeFromSharingList(pBt) ){ + /* The pBt is no longer on the sharing list, so we can access + ** it without having to hold the mutex. + ** + ** Clean out and delete the BtShared object. + */ + assert( !pBt->pCursor ); + sqlite3PagerClose(pBt->pPager, p->db); + if( pBt->xFreeSchema && pBt->pSchema ){ + pBt->xFreeSchema(pBt->pSchema); + } + sqlite3DbFree(0, pBt->pSchema); + freeTempSpace(pBt); + sqlite3_free(pBt); + } + +#ifndef SQLITE_OMIT_SHARED_CACHE + assert( p->wantToLock==0 ); + assert( p->locked==0 ); + if( p->pPrev ) p->pPrev->pNext = p->pNext; + if( p->pNext ) p->pNext->pPrev = p->pPrev; +#endif + + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Change the "soft" limit on the number of pages in the cache. +** Unused and unmodified pages will be recycled when the number of +** pages in the cache exceeds this soft limit. But the size of the +** cache is allowed to grow larger than this limit if it contains +** dirty pages or pages still in active use. +*/ +SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ + BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + sqlite3PagerSetCachesize(pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return SQLITE_OK; +} + +/* +** Change the "spill" limit on the number of pages in the cache. +** If the number of pages exceeds this limit during a write transaction, +** the pager might attempt to "spill" pages to the journal early in +** order to free up memory. +** +** The value returned is the current spill size. If zero is passed +** as an argument, no changes are made to the spill size setting, so +** using mxPage of 0 is a way to query the current spill size. +*/ +SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){ + BtShared *pBt = p->pBt; + int res; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return res; +} + +#if SQLITE_MAX_MMAP_SIZE>0 +/* +** Change the limit on the amount of the database file that may be +** memory mapped. +*/ +SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){ + BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + sqlite3PagerSetMmapLimit(pBt->pPager, szMmap); + sqlite3BtreeLeave(p); + return SQLITE_OK; +} +#endif /* SQLITE_MAX_MMAP_SIZE>0 */ + +/* +** Change the way data is synced to disk in order to increase or decrease +** how well the database resists damage due to OS crashes and power +** failures. Level 1 is the same as asynchronous (no syncs() occur and +** there is a high probability of damage) Level 2 is the default. There +** is a very low but non-zero probability of damage. Level 3 reduces the +** probability of damage to near zero but with a write performance reduction. +*/ +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags( + Btree *p, /* The btree to set the safety level on */ + unsigned pgFlags /* Various PAGER_* flags */ +){ + BtShared *pBt = p->pBt; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + sqlite3PagerSetFlags(pBt->pPager, pgFlags); + sqlite3BtreeLeave(p); + return SQLITE_OK; +} +#endif + +/* +** Change the default pages size and the number of reserved bytes per page. +** Or, if the page size has already been fixed, return SQLITE_READONLY +** without changing anything. +** +** The page size must be a power of 2 between 512 and 65536. If the page +** size supplied does not meet this constraint then the page size is not +** changed. +** +** Page sizes are constrained to be a power of two so that the region +** of the database file used for locking (beginning at PENDING_BYTE, +** the first byte past the 1GB boundary, 0x40000000) needs to occur +** at the beginning of a page. +** +** If parameter nReserve is less than zero, then the number of reserved +** bytes per page is left unchanged. +** +** If the iFix!=0 then the BTS_PAGESIZE_FIXED flag is set so that the page size +** and autovacuum mode can no longer be changed. +*/ +SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ + int rc = SQLITE_OK; + BtShared *pBt = p->pBt; + assert( nReserve>=-1 && nReserve<=255 ); + sqlite3BtreeEnter(p); +#if SQLITE_HAS_CODEC + if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve; +#endif + if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){ + sqlite3BtreeLeave(p); + return SQLITE_READONLY; + } + if( nReserve<0 ){ + nReserve = pBt->pageSize - pBt->usableSize; + } + assert( nReserve>=0 && nReserve<=255 ); + if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && + ((pageSize-1)&pageSize)==0 ){ + assert( (pageSize & 7)==0 ); + assert( !pBt->pCursor ); + pBt->pageSize = (u32)pageSize; + freeTempSpace(pBt); + } + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve); + pBt->usableSize = pBt->pageSize - (u16)nReserve; + if( iFix ) pBt->btsFlags |= BTS_PAGESIZE_FIXED; + sqlite3BtreeLeave(p); + return rc; +} + +/* +** Return the currently defined page size +*/ +SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){ + return p->pBt->pageSize; +} + +/* +** This function is similar to sqlite3BtreeGetReserve(), except that it +** may only be called if it is guaranteed that the b-tree mutex is already +** held. +** +** This is useful in one special case in the backup API code where it is +** known that the shared b-tree mutex is held, but the mutex on the +** database handle that owns *p is not. In this case if sqlite3BtreeEnter() +** were to be called, it might collide with some other operation on the +** database handle that owns *p, causing undefined behavior. +*/ +SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){ + int n; + assert( sqlite3_mutex_held(p->pBt->mutex) ); + n = p->pBt->pageSize - p->pBt->usableSize; + return n; +} + +/* +** Return the number of bytes of space at the end of every page that +** are intentually left unused. This is the "reserved" space that is +** sometimes used by extensions. +** +** If SQLITE_HAS_MUTEX is defined then the number returned is the +** greater of the current reserved space and the maximum requested +** reserve space. +*/ +SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){ + int n; + sqlite3BtreeEnter(p); + n = sqlite3BtreeGetReserveNoMutex(p); +#ifdef SQLITE_HAS_CODEC + if( npBt->optimalReserve ) n = p->pBt->optimalReserve; +#endif + sqlite3BtreeLeave(p); + return n; +} + + +/* +** Set the maximum page count for a database if mxPage is positive. +** No changes are made if mxPage is 0 or negative. +** Regardless of the value of mxPage, return the maximum page count. +*/ +SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ + int n; + sqlite3BtreeEnter(p); + n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return n; +} + +/* +** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1. If newFlag is -1, +** then make no changes. Always return the value of the BTS_SECURE_DELETE +** setting after the change. +*/ +SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ + int b; + if( p==0 ) return 0; + sqlite3BtreeEnter(p); + if( newFlag>=0 ){ + p->pBt->btsFlags &= ~BTS_SECURE_DELETE; + if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE; + } + b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0; + sqlite3BtreeLeave(p); + return b; +} + +/* +** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' +** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it +** is disabled. The default value for the auto-vacuum property is +** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. +*/ +SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ +#ifdef SQLITE_OMIT_AUTOVACUUM + return SQLITE_READONLY; +#else + BtShared *pBt = p->pBt; + int rc = SQLITE_OK; + u8 av = (u8)autoVacuum; + + sqlite3BtreeEnter(p); + if( (pBt->btsFlags & BTS_PAGESIZE_FIXED)!=0 && (av ?1:0)!=pBt->autoVacuum ){ + rc = SQLITE_READONLY; + }else{ + pBt->autoVacuum = av ?1:0; + pBt->incrVacuum = av==2 ?1:0; + } + sqlite3BtreeLeave(p); + return rc; +#endif +} + +/* +** Return the value of the 'auto-vacuum' property. If auto-vacuum is +** enabled 1 is returned. Otherwise 0. +*/ +SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ +#ifdef SQLITE_OMIT_AUTOVACUUM + return BTREE_AUTOVACUUM_NONE; +#else + int rc; + sqlite3BtreeEnter(p); + rc = ( + (!p->pBt->autoVacuum)?BTREE_AUTOVACUUM_NONE: + (!p->pBt->incrVacuum)?BTREE_AUTOVACUUM_FULL: + BTREE_AUTOVACUUM_INCR + ); + sqlite3BtreeLeave(p); + return rc; +#endif +} + +/* +** If the user has not set the safety-level for this database connection +** using "PRAGMA synchronous", and if the safety-level is not already +** set to the value passed to this function as the second parameter, +** set it so. +*/ +#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS +static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){ + sqlite3 *db; + Db *pDb; + if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){ + while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; } + if( pDb->bSyncSet==0 + && pDb->safety_level!=safety_level + && pDb!=&db->aDb[1] + ){ + pDb->safety_level = safety_level; + sqlite3PagerSetFlags(pBt->pPager, + pDb->safety_level | (db->flags & PAGER_FLAGS_MASK)); + } + } +} +#else +# define setDefaultSyncFlag(pBt,safety_level) +#endif + +/* +** Get a reference to pPage1 of the database file. This will +** also acquire a readlock on that file. +** +** SQLITE_OK is returned on success. If the file is not a +** well-formed database file, then SQLITE_CORRUPT is returned. +** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM +** is returned if we run out of memory. +*/ +static int lockBtree(BtShared *pBt){ + int rc; /* Result code from subfunctions */ + MemPage *pPage1; /* Page 1 of the database file */ + int nPage; /* Number of pages in the database */ + int nPageFile = 0; /* Number of pages in the database file */ + int nPageHeader; /* Number of pages in the database according to hdr */ + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pBt->pPage1==0 ); + rc = sqlite3PagerSharedLock(pBt->pPager); + if( rc!=SQLITE_OK ) return rc; + rc = btreeGetPage(pBt, 1, &pPage1, 0); + if( rc!=SQLITE_OK ) return rc; + + /* Do some checking to help insure the file we opened really is + ** a valid database file. + */ + nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData); + sqlite3PagerPagecount(pBt->pPager, &nPageFile); + if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ + nPage = nPageFile; + } + if( nPage>0 ){ + u32 pageSize; + u32 usableSize; + u8 *page1 = pPage1->aData; + rc = SQLITE_NOTADB; + /* EVIDENCE-OF: R-43737-39999 Every valid SQLite database file begins + ** with the following 16 bytes (in hex): 53 51 4c 69 74 65 20 66 6f 72 6d + ** 61 74 20 33 00. */ + if( memcmp(page1, zMagicHeader, 16)!=0 ){ + goto page1_init_failed; + } + +#ifdef SQLITE_OMIT_WAL + if( page1[18]>1 ){ + pBt->btsFlags |= BTS_READ_ONLY; + } + if( page1[19]>1 ){ + goto page1_init_failed; + } +#else + if( page1[18]>2 ){ + pBt->btsFlags |= BTS_READ_ONLY; + } + if( page1[19]>2 ){ + goto page1_init_failed; + } + + /* If the write version is set to 2, this database should be accessed + ** in WAL mode. If the log is not already open, open it now. Then + ** return SQLITE_OK and return without populating BtShared.pPage1. + ** The caller detects this and calls this function again. This is + ** required as the version of page 1 currently in the page1 buffer + ** may not be the latest version - there may be a newer one in the log + ** file. + */ + if( page1[19]==2 && (pBt->btsFlags & BTS_NO_WAL)==0 ){ + int isOpen = 0; + rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen); + if( rc!=SQLITE_OK ){ + goto page1_init_failed; + }else{ + setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1); + if( isOpen==0 ){ + releasePage(pPage1); + return SQLITE_OK; + } + } + rc = SQLITE_NOTADB; + }else{ + setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1); + } +#endif + + /* EVIDENCE-OF: R-15465-20813 The maximum and minimum embedded payload + ** fractions and the leaf payload fraction values must be 64, 32, and 32. + ** + ** The original design allowed these amounts to vary, but as of + ** version 3.6.0, we require them to be fixed. + */ + if( memcmp(&page1[21], "\100\040\040",3)!=0 ){ + goto page1_init_failed; + } + /* EVIDENCE-OF: R-51873-39618 The page size for a database file is + ** determined by the 2-byte integer located at an offset of 16 bytes from + ** the beginning of the database file. */ + pageSize = (page1[16]<<8) | (page1[17]<<16); + /* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two + ** between 512 and 65536 inclusive. */ + if( ((pageSize-1)&pageSize)!=0 + || pageSize>SQLITE_MAX_PAGE_SIZE + || pageSize<=256 + ){ + goto page1_init_failed; + } + assert( (pageSize & 7)==0 ); + /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte + ** integer at offset 20 is the number of bytes of space at the end of + ** each page to reserve for extensions. + ** + ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is + ** determined by the one-byte unsigned integer found at an offset of 20 + ** into the database file header. */ + usableSize = pageSize - page1[20]; + if( (u32)pageSize!=pBt->pageSize ){ + /* After reading the first page of the database assuming a page size + ** of BtShared.pageSize, we have discovered that the page-size is + ** actually pageSize. Unlock the database, leave pBt->pPage1 at + ** zero and return SQLITE_OK. The caller will call this function + ** again with the correct page-size. + */ + releasePage(pPage1); + pBt->usableSize = usableSize; + pBt->pageSize = pageSize; + freeTempSpace(pBt); + rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, + pageSize-usableSize); + return rc; + } + if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){ + rc = SQLITE_CORRUPT_BKPT; + goto page1_init_failed; + } + /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to + ** be less than 480. In other words, if the page size is 512, then the + ** reserved space size cannot exceed 32. */ + if( usableSize<480 ){ + goto page1_init_failed; + } + pBt->pageSize = pageSize; + pBt->usableSize = usableSize; +#ifndef SQLITE_OMIT_AUTOVACUUM + pBt->autoVacuum = (get4byte(&page1[36 + 4*4])?1:0); + pBt->incrVacuum = (get4byte(&page1[36 + 7*4])?1:0); +#endif + } + + /* maxLocal is the maximum amount of payload to store locally for + ** a cell. Make sure it is small enough so that at least minFanout + ** cells can will fit on one page. We assume a 10-byte page header. + ** Besides the payload, the cell must store: + ** 2-byte pointer to the cell + ** 4-byte child pointer + ** 9-byte nKey value + ** 4-byte nData value + ** 4-byte overflow page pointer + ** So a cell consists of a 2-byte pointer, a header which is as much as + ** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow + ** page pointer. + */ + pBt->maxLocal = (u16)((pBt->usableSize-12)*64/255 - 23); + pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23); + pBt->maxLeaf = (u16)(pBt->usableSize - 35); + pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23); + if( pBt->maxLocal>127 ){ + pBt->max1bytePayload = 127; + }else{ + pBt->max1bytePayload = (u8)pBt->maxLocal; + } + assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) ); + pBt->pPage1 = pPage1; + pBt->nPage = nPage; + return SQLITE_OK; + +page1_init_failed: + releasePage(pPage1); + pBt->pPage1 = 0; + return rc; +} + +#ifndef NDEBUG +/* +** Return the number of cursors open on pBt. This is for use +** in assert() expressions, so it is only compiled if NDEBUG is not +** defined. +** +** Only write cursors are counted if wrOnly is true. If wrOnly is +** false then all cursors are counted. +** +** For the purposes of this routine, a cursor is any cursor that +** is capable of reading or writing to the database. Cursors that +** have been tripped into the CURSOR_FAULT state are not counted. +*/ +static int countValidCursors(BtShared *pBt, int wrOnly){ + BtCursor *pCur; + int r = 0; + for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ + if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0) + && pCur->eState!=CURSOR_FAULT ) r++; + } + return r; +} +#endif + +/* +** If there are no outstanding cursors and we are not in the middle +** of a transaction but there is a read lock on the database, then +** this routine unrefs the first page of the database file which +** has the effect of releasing the read lock. +** +** If there is a transaction in progress, this routine is a no-op. +*/ +static void unlockBtreeIfUnused(BtShared *pBt){ + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE ); + if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){ + MemPage *pPage1 = pBt->pPage1; + assert( pPage1->aData ); + assert( sqlite3PagerRefcount(pBt->pPager)==1 ); + pBt->pPage1 = 0; + releasePageNotNull(pPage1); + } +} + +/* +** If pBt points to an empty file then convert that empty file +** into a new empty database by initializing the first page of +** the database. +*/ +static int newDatabase(BtShared *pBt){ + MemPage *pP1; + unsigned char *data; + int rc; + + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pBt->nPage>0 ){ + return SQLITE_OK; + } + pP1 = pBt->pPage1; + assert( pP1!=0 ); + data = pP1->aData; + rc = sqlite3PagerWrite(pP1->pDbPage); + if( rc ) return rc; + memcpy(data, zMagicHeader, sizeof(zMagicHeader)); + assert( sizeof(zMagicHeader)==16 ); + data[16] = (u8)((pBt->pageSize>>8)&0xff); + data[17] = (u8)((pBt->pageSize>>16)&0xff); + data[18] = 1; + data[19] = 1; + assert( pBt->usableSize<=pBt->pageSize && pBt->usableSize+255>=pBt->pageSize); + data[20] = (u8)(pBt->pageSize - pBt->usableSize); + data[21] = 64; + data[22] = 32; + data[23] = 32; + memset(&data[24], 0, 100-24); + zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA ); + pBt->btsFlags |= BTS_PAGESIZE_FIXED; +#ifndef SQLITE_OMIT_AUTOVACUUM + assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 ); + assert( pBt->incrVacuum==1 || pBt->incrVacuum==0 ); + put4byte(&data[36 + 4*4], pBt->autoVacuum); + put4byte(&data[36 + 7*4], pBt->incrVacuum); +#endif + pBt->nPage = 1; + data[31] = 1; + return SQLITE_OK; +} + +/* +** Initialize the first page of the database file (creating a database +** consisting of a single page and no schema objects). Return SQLITE_OK +** if successful, or an SQLite error code otherwise. +*/ +SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ + int rc; + sqlite3BtreeEnter(p); + p->pBt->nPage = 0; + rc = newDatabase(p->pBt); + sqlite3BtreeLeave(p); + return rc; +} + +/* +** Attempt to start a new transaction. A write-transaction +** is started if the second argument is nonzero, otherwise a read- +** transaction. If the second argument is 2 or more and exclusive +** transaction is started, meaning that no other process is allowed +** to access the database. A preexisting transaction may not be +** upgraded to exclusive by calling this routine a second time - the +** exclusivity flag only works for a new transaction. +** +** A write-transaction must be started before attempting any +** changes to the database. None of the following routines +** will work unless a transaction is started first: +** +** sqlite3BtreeCreateTable() +** sqlite3BtreeCreateIndex() +** sqlite3BtreeClearTable() +** sqlite3BtreeDropTable() +** sqlite3BtreeInsert() +** sqlite3BtreeDelete() +** sqlite3BtreeUpdateMeta() +** +** If an initial attempt to acquire the lock fails because of lock contention +** and the database was previously unlocked, then invoke the busy handler +** if there is one. But if there was previously a read-lock, do not +** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is +** returned when there is already a read-lock in order to avoid a deadlock. +** +** Suppose there are two processes A and B. A has a read lock and B has +** a reserved lock. B tries to promote to exclusive but is blocked because +** of A's read lock. A tries to promote to reserved but is blocked by B. +** One or the other of the two processes must give way or there can be +** no progress. By returning SQLITE_BUSY and not invoking the busy callback +** when A already has a read lock, we encourage A to give up and let B +** proceed. +*/ +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ + BtShared *pBt = p->pBt; + int rc = SQLITE_OK; + + sqlite3BtreeEnter(p); + btreeIntegrity(p); + + /* If the btree is already in a write-transaction, or it + ** is already in a read-transaction and a read-transaction + ** is requested, this is a no-op. + */ + if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ + goto trans_begun; + } + assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 ); + + /* Write transactions are not possible on a read-only database */ + if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ + rc = SQLITE_READONLY; + goto trans_begun; + } + +#ifndef SQLITE_OMIT_SHARED_CACHE + { + sqlite3 *pBlock = 0; + /* If another database handle has already opened a write transaction + ** on this shared-btree structure and a second write transaction is + ** requested, return SQLITE_LOCKED. + */ + if( (wrflag && pBt->inTransaction==TRANS_WRITE) + || (pBt->btsFlags & BTS_PENDING)!=0 + ){ + pBlock = pBt->pWriter->db; + }else if( wrflag>1 ){ + BtLock *pIter; + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->pBtree!=p ){ + pBlock = pIter->pBtree->db; + break; + } + } + } + if( pBlock ){ + sqlite3ConnectionBlocked(p->db, pBlock); + rc = SQLITE_LOCKED_SHAREDCACHE; + goto trans_begun; + } + } +#endif + + /* Any read-only or read-write transaction implies a read-lock on + ** page 1. So if some other shared-cache client already has a write-lock + ** on page 1, the transaction cannot be opened. */ + rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK); + if( SQLITE_OK!=rc ) goto trans_begun; + + pBt->btsFlags &= ~BTS_INITIALLY_EMPTY; + if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY; + do { + /* Call lockBtree() until either pBt->pPage1 is populated or + ** lockBtree() returns something other than SQLITE_OK. lockBtree() + ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after + ** reading page 1 it discovers that the page-size of the database + ** file is not pBt->pageSize. In this case lockBtree() will update + ** pBt->pageSize to the page-size of the file on disk. + */ + while( pBt->pPage1==0 && SQLITE_OK==(rc = lockBtree(pBt)) ); + + if( rc==SQLITE_OK && wrflag ){ + if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){ + rc = SQLITE_READONLY; + }else{ + rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db)); + if( rc==SQLITE_OK ){ + rc = newDatabase(pBt); + } + } + } + + if( rc!=SQLITE_OK ){ + unlockBtreeIfUnused(pBt); + } + }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && + btreeInvokeBusyHandler(pBt) ); + + if( rc==SQLITE_OK ){ + if( p->inTrans==TRANS_NONE ){ + pBt->nTransaction++; +#ifndef SQLITE_OMIT_SHARED_CACHE + if( p->sharable ){ + assert( p->lock.pBtree==p && p->lock.iTable==1 ); + p->lock.eLock = READ_LOCK; + p->lock.pNext = pBt->pLock; + pBt->pLock = &p->lock; + } +#endif + } + p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); + if( p->inTrans>pBt->inTransaction ){ + pBt->inTransaction = p->inTrans; + } + if( wrflag ){ + MemPage *pPage1 = pBt->pPage1; +#ifndef SQLITE_OMIT_SHARED_CACHE + assert( !pBt->pWriter ); + pBt->pWriter = p; + pBt->btsFlags &= ~BTS_EXCLUSIVE; + if( wrflag>1 ) pBt->btsFlags |= BTS_EXCLUSIVE; +#endif + + /* If the db-size header field is incorrect (as it may be if an old + ** client has been writing the database file), update it now. Doing + ** this sooner rather than later means the database size can safely + ** re-read the database size from page 1 if a savepoint or transaction + ** rollback occurs within the transaction. + */ + if( pBt->nPage!=get4byte(&pPage1->aData[28]) ){ + rc = sqlite3PagerWrite(pPage1->pDbPage); + if( rc==SQLITE_OK ){ + put4byte(&pPage1->aData[28], pBt->nPage); + } + } + } + } + + +trans_begun: + if( rc==SQLITE_OK && wrflag ){ + /* This call makes sure that the pager has the correct number of + ** open savepoints. If the second parameter is greater than 0 and + ** the sub-journal is not already open, then it will be opened here. + */ + rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); + } + + btreeIntegrity(p); + sqlite3BtreeLeave(p); + return rc; +} + +#ifndef SQLITE_OMIT_AUTOVACUUM + +/* +** Set the pointer-map entries for all children of page pPage. Also, if +** pPage contains cells that point to overflow pages, set the pointer +** map entries for the overflow pages as well. +*/ +static int setChildPtrmaps(MemPage *pPage){ + int i; /* Counter variable */ + int nCell; /* Number of cells in page pPage */ + int rc; /* Return code */ + BtShared *pBt = pPage->pBt; + Pgno pgno = pPage->pgno; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + rc = btreeInitPage(pPage); + if( rc!=SQLITE_OK ) return rc; + nCell = pPage->nCell; + + for(i=0; ileaf ){ + Pgno childPgno = get4byte(pCell); + ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc); + } + } + + if( !pPage->leaf ){ + Pgno childPgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); + ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc); + } + + return rc; +} + +/* +** Somewhere on pPage is a pointer to page iFrom. Modify this pointer so +** that it points to iTo. Parameter eType describes the type of pointer to +** be modified, as follows: +** +** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child +** page of pPage. +** +** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow +** page pointed to by one of the cells on pPage. +** +** PTRMAP_OVERFLOW2: pPage is an overflow-page. The pointer points at the next +** overflow page in the list. +*/ +static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + if( eType==PTRMAP_OVERFLOW2 ){ + /* The pointer is always the first 4 bytes of the page in this case. */ + if( get4byte(pPage->aData)!=iFrom ){ + return SQLITE_CORRUPT_BKPT; + } + put4byte(pPage->aData, iTo); + }else{ + int i; + int nCell; + int rc; + + rc = btreeInitPage(pPage); + if( rc ) return rc; + nCell = pPage->nCell; + + for(i=0; ixParseCell(pPage, pCell, &info); + if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ + return SQLITE_CORRUPT_BKPT; + } + if( iFrom==get4byte(pCell+info.nSize-4) ){ + put4byte(pCell+info.nSize-4, iTo); + break; + } + } + }else{ + if( get4byte(pCell)==iFrom ){ + put4byte(pCell, iTo); + break; + } + } + } + + if( i==nCell ){ + if( eType!=PTRMAP_BTREE || + get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ + return SQLITE_CORRUPT_BKPT; + } + put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); + } + } + return SQLITE_OK; +} + + +/* +** Move the open database page pDbPage to location iFreePage in the +** database. The pDbPage reference remains valid. +** +** The isCommit flag indicates that there is no need to remember that +** the journal needs to be sync()ed before database page pDbPage->pgno +** can be written to. The caller has already promised not to write to that +** page. +*/ +static int relocatePage( + BtShared *pBt, /* Btree */ + MemPage *pDbPage, /* Open page to move */ + u8 eType, /* Pointer map 'type' entry for pDbPage */ + Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ + Pgno iFreePage, /* The location to move pDbPage to */ + int isCommit /* isCommit flag passed to sqlite3PagerMovepage */ +){ + MemPage *pPtrPage; /* The page that contains a pointer to pDbPage */ + Pgno iDbPage = pDbPage->pgno; + Pager *pPager = pBt->pPager; + int rc; + + assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || + eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( pDbPage->pBt==pBt ); + + /* Move page iDbPage from its current location to page number iFreePage */ + TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", + iDbPage, iFreePage, iPtrPage, eType)); + rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit); + if( rc!=SQLITE_OK ){ + return rc; + } + pDbPage->pgno = iFreePage; + + /* If pDbPage was a btree-page, then it may have child pages and/or cells + ** that point to overflow pages. The pointer map entries for all these + ** pages need to be changed. + ** + ** If pDbPage is an overflow page, then the first 4 bytes may store a + ** pointer to a subsequent overflow page. If this is the case, then + ** the pointer map needs to be updated for the subsequent overflow page. + */ + if( eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ){ + rc = setChildPtrmaps(pDbPage); + if( rc!=SQLITE_OK ){ + return rc; + } + }else{ + Pgno nextOvfl = get4byte(pDbPage->aData); + if( nextOvfl!=0 ){ + ptrmapPut(pBt, nextOvfl, PTRMAP_OVERFLOW2, iFreePage, &rc); + if( rc!=SQLITE_OK ){ + return rc; + } + } + } + + /* Fix the database pointer on page iPtrPage that pointed at iDbPage so + ** that it points at iFreePage. Also fix the pointer map entry for + ** iPtrPage. + */ + if( eType!=PTRMAP_ROOTPAGE ){ + rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + rc = sqlite3PagerWrite(pPtrPage->pDbPage); + if( rc!=SQLITE_OK ){ + releasePage(pPtrPage); + return rc; + } + rc = modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType); + releasePage(pPtrPage); + if( rc==SQLITE_OK ){ + ptrmapPut(pBt, iFreePage, eType, iPtrPage, &rc); + } + } + return rc; +} + +/* Forward declaration required by incrVacuumStep(). */ +static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); + +/* +** Perform a single step of an incremental-vacuum. If successful, return +** SQLITE_OK. If there is no work to do (and therefore no point in +** calling this function again), return SQLITE_DONE. Or, if an error +** occurs, return some other error code. +** +** More specifically, this function attempts to re-organize the database so +** that the last page of the file currently in use is no longer in use. +** +** Parameter nFin is the number of pages that this database would contain +** were this function called until it returns SQLITE_DONE. +** +** If the bCommit parameter is non-zero, this function assumes that the +** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE +** or an error. bCommit is passed true for an auto-vacuum-on-commit +** operation, or false for an incremental vacuum. +*/ +static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ + Pgno nFreeList; /* Number of pages still on the free-list */ + int rc; + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( iLastPg>nFin ); + + if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){ + u8 eType; + Pgno iPtrPage; + + nFreeList = get4byte(&pBt->pPage1->aData[36]); + if( nFreeList==0 ){ + return SQLITE_DONE; + } + + rc = ptrmapGet(pBt, iLastPg, &eType, &iPtrPage); + if( rc!=SQLITE_OK ){ + return rc; + } + if( eType==PTRMAP_ROOTPAGE ){ + return SQLITE_CORRUPT_BKPT; + } + + if( eType==PTRMAP_FREEPAGE ){ + if( bCommit==0 ){ + /* Remove the page from the files free-list. This is not required + ** if bCommit is non-zero. In that case, the free-list will be + ** truncated to zero after this function returns, so it doesn't + ** matter if it still contains some garbage entries. + */ + Pgno iFreePg; + MemPage *pFreePg; + rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT); + if( rc!=SQLITE_OK ){ + return rc; + } + assert( iFreePg==iLastPg ); + releasePage(pFreePg); + } + } else { + Pgno iFreePg; /* Index of free page to move pLastPg to */ + MemPage *pLastPg; + u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ + Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ + + rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + + /* If bCommit is zero, this loop runs exactly once and page pLastPg + ** is swapped with the first free page pulled off the free list. + ** + ** On the other hand, if bCommit is greater than zero, then keep + ** looping until a free-page located within the first nFin pages + ** of the file is found. + */ + if( bCommit==0 ){ + eMode = BTALLOC_LE; + iNear = nFin; + } + do { + MemPage *pFreePg; + rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode); + if( rc!=SQLITE_OK ){ + releasePage(pLastPg); + return rc; + } + releasePage(pFreePg); + }while( bCommit && iFreePg>nFin ); + assert( iFreePgbDoTruncate = 1; + pBt->nPage = iLastPg; + } + return SQLITE_OK; +} + +/* +** The database opened by the first argument is an auto-vacuum database +** nOrig pages in size containing nFree free pages. Return the expected +** size of the database in pages following an auto-vacuum operation. +*/ +static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){ + int nEntry; /* Number of entries on one ptrmap page */ + Pgno nPtrmap; /* Number of PtrMap pages to be freed */ + Pgno nFin; /* Return value */ + + nEntry = pBt->usableSize/5; + nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry; + nFin = nOrig - nFree - nPtrmap; + if( nOrig>PENDING_BYTE_PAGE(pBt) && nFinpBt; + + sqlite3BtreeEnter(p); + assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); + if( !pBt->autoVacuum ){ + rc = SQLITE_DONE; + }else{ + Pgno nOrig = btreePagecount(pBt); + Pgno nFree = get4byte(&pBt->pPage1->aData[36]); + Pgno nFin = finalDbSize(pBt, nOrig, nFree); + + if( nOrig0 ){ + rc = saveAllCursors(pBt, 0, 0); + if( rc==SQLITE_OK ){ + invalidateAllOverflowCache(pBt); + rc = incrVacuumStep(pBt, nFin, nOrig, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + put4byte(&pBt->pPage1->aData[28], pBt->nPage); + } + }else{ + rc = SQLITE_DONE; + } + } + sqlite3BtreeLeave(p); + return rc; +} + +/* +** This routine is called prior to sqlite3PagerCommit when a transaction +** is committed for an auto-vacuum database. +** +** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages +** the database file should be truncated to during the commit process. +** i.e. the database has been reorganized so that only the first *pnTrunc +** pages are in use. +*/ +static int autoVacuumCommit(BtShared *pBt){ + int rc = SQLITE_OK; + Pager *pPager = pBt->pPager; + VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); ) + + assert( sqlite3_mutex_held(pBt->mutex) ); + invalidateAllOverflowCache(pBt); + assert(pBt->autoVacuum); + if( !pBt->incrVacuum ){ + 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 */ + Pgno nOrig; /* Database size before freeing */ + + nOrig = btreePagecount(pBt); + if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){ + /* It is not possible to create a database for which the final page + ** is either a pointer-map page or the pending-byte page. If one + ** is encountered, this indicates corruption. + */ + return SQLITE_CORRUPT_BKPT; + } + + nFree = get4byte(&pBt->pPage1->aData[36]); + nFin = finalDbSize(pBt, nOrig, nFree); + if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; + if( nFinnFin && rc==SQLITE_OK; iFree--){ + rc = incrVacuumStep(pBt, nFin, iFree, 1); + } + if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + put4byte(&pBt->pPage1->aData[32], 0); + put4byte(&pBt->pPage1->aData[36], 0); + put4byte(&pBt->pPage1->aData[28], nFin); + pBt->bDoTruncate = 1; + pBt->nPage = nFin; + } + if( rc!=SQLITE_OK ){ + sqlite3PagerRollback(pPager); + } + } + + assert( nRef>=sqlite3PagerRefcount(pPager) ); + return rc; +} + +#else /* ifndef SQLITE_OMIT_AUTOVACUUM */ +# define setChildPtrmaps(x) SQLITE_OK +#endif + +/* +** This routine does the first phase of a two-phase commit. This routine +** causes a rollback journal to be created (if it does not already exist) +** and populated with enough information so that if a power loss occurs +** the database can be restored to its original state by playing back +** the journal. Then the contents of the journal are flushed out to +** the disk. After the journal is safely on oxide, the changes to the +** database are written into the database file and flushed to oxide. +** At the end of this call, the rollback journal still exists on the +** disk and we are still holding all locks, so the transaction has not +** committed. See sqlite3BtreeCommitPhaseTwo() for the second phase of the +** commit process. +** +** This call is a no-op if no write-transaction is currently active on pBt. +** +** Otherwise, sync the database file for the btree pBt. zMaster points to +** the name of a master journal file that should be written into the +** individual journal file, or is NULL, indicating no master journal file +** (single database transaction). +** +** When this is called, the master journal should already have been +** created, populated with this journal pointer and synced to disk. +** +** Once this is routine has returned, the only thing required to commit +** the write-transaction for this database file is to delete the journal. +*/ +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ + int rc = SQLITE_OK; + if( p->inTrans==TRANS_WRITE ){ + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum ){ + rc = autoVacuumCommit(pBt); + if( rc!=SQLITE_OK ){ + sqlite3BtreeLeave(p); + return rc; + } + } + if( pBt->bDoTruncate ){ + sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); + } +#endif + rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); + sqlite3BtreeLeave(p); + } + return rc; +} + +/* +** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback() +** at the conclusion of a transaction. +*/ +static void btreeEndTransaction(Btree *p){ + BtShared *pBt = p->pBt; + sqlite3 *db = p->db; + assert( sqlite3BtreeHoldsMutex(p) ); + +#ifndef SQLITE_OMIT_AUTOVACUUM + pBt->bDoTruncate = 0; +#endif + if( p->inTrans>TRANS_NONE && db->nVdbeRead>1 ){ + /* If there are other active statements that belong to this database + ** handle, downgrade to a read-only transaction. The other statements + ** may still be reading from the database. */ + downgradeAllSharedCacheTableLocks(p); + p->inTrans = TRANS_READ; + }else{ + /* If the handle had any kind of transaction open, decrement the + ** transaction count of the shared btree. If the transaction count + ** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused() + ** call below will unlock the pager. */ + if( p->inTrans!=TRANS_NONE ){ + clearAllSharedCacheTableLocks(p); + pBt->nTransaction--; + if( 0==pBt->nTransaction ){ + pBt->inTransaction = TRANS_NONE; + } + } + + /* Set the current transaction state to TRANS_NONE and unlock the + ** pager if this call closed the only read or write transaction. */ + p->inTrans = TRANS_NONE; + unlockBtreeIfUnused(pBt); + } + + btreeIntegrity(p); +} + +/* +** Commit the transaction currently in progress. +** +** This routine implements the second phase of a 2-phase commit. The +** sqlite3BtreeCommitPhaseOne() routine does the first phase and should +** be invoked prior to calling this routine. The sqlite3BtreeCommitPhaseOne() +** routine did all the work of writing information out to disk and flushing the +** contents so that they are written onto the disk platter. All this +** routine has to do is delete or truncate or zero the header in the +** the rollback journal (which causes the transaction to commit) and +** drop locks. +** +** Normally, if an error occurs while the pager layer is attempting to +** finalize the underlying journal file, this function returns an error and +** the upper layer will attempt a rollback. However, if the second argument +** is non-zero then this b-tree transaction is part of a multi-file +** transaction. In this case, the transaction has already been committed +** (by deleting a master journal file) and the caller will ignore this +** functions return code. So, even if an error occurs in the pager layer, +** reset the b-tree objects internal state to indicate that the write +** transaction has been closed. This is quite safe, as the pager will have +** transitioned to the error state. +** +** This will release the write lock on the database file. If there +** are no active cursors, it also releases the read lock. +*/ +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ + + if( p->inTrans==TRANS_NONE ) return SQLITE_OK; + sqlite3BtreeEnter(p); + btreeIntegrity(p); + + /* If the handle has a write-transaction open, commit the shared-btrees + ** transaction and set the shared state to TRANS_READ. + */ + if( p->inTrans==TRANS_WRITE ){ + int rc; + BtShared *pBt = p->pBt; + assert( pBt->inTransaction==TRANS_WRITE ); + assert( pBt->nTransaction>0 ); + rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); + if( rc!=SQLITE_OK && bCleanup==0 ){ + sqlite3BtreeLeave(p); + return rc; + } + p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */ + pBt->inTransaction = TRANS_READ; + btreeClearHasContent(pBt); + } + + btreeEndTransaction(p); + sqlite3BtreeLeave(p); + return SQLITE_OK; +} + +/* +** Do both phases of a commit. +*/ +SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){ + int rc; + sqlite3BtreeEnter(p); + rc = sqlite3BtreeCommitPhaseOne(p, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeCommitPhaseTwo(p, 0); + } + sqlite3BtreeLeave(p); + return rc; +} + +/* +** This routine sets the state to CURSOR_FAULT and the error +** code to errCode for every cursor on any BtShared that pBtree +** references. Or if the writeOnly flag is set to 1, then only +** trip write cursors and leave read cursors unchanged. +** +** Every cursor is a candidate to be tripped, including cursors +** that belong to other database connections that happen to be +** sharing the cache with pBtree. +** +** This routine gets called when a rollback occurs. If the writeOnly +** flag is true, then only write-cursors need be tripped - read-only +** cursors save their current positions so that they may continue +** following the rollback. Or, if writeOnly is false, all cursors are +** tripped. In general, writeOnly is false if the transaction being +** rolled back modified the database schema. In this case b-tree root +** pages may be moved or deleted from the database altogether, making +** it unsafe for read cursors to continue. +** +** If the writeOnly flag is true and an error is encountered while +** saving the current position of a read-only cursor, all cursors, +** including all read-cursors are tripped. +** +** SQLITE_OK is returned if successful, or if an error occurs while +** saving a cursor position, an SQLite error code. +*/ +SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){ + BtCursor *p; + int rc = SQLITE_OK; + + assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 ); + 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); + if( rc!=SQLITE_OK ){ + (void)sqlite3BtreeTripAllCursors(pBtree, rc, 0); + break; + } + } + }else{ + sqlite3BtreeClearCursor(p); + p->eState = CURSOR_FAULT; + p->skipNext = errCode; + } + for(i=0; i<=p->iPage; i++){ + releasePage(p->apPage[i]); + p->apPage[i] = 0; + } + } + sqlite3BtreeLeave(pBtree); + } + return rc; +} + +/* +** Rollback the transaction in progress. +** +** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). +** Only write cursors are tripped if writeOnly is true but all cursors are +** tripped if writeOnly is false. Any attempt to use +** a tripped cursor will result in an error. +** +** This will release the write lock on the database file. If there +** are no active cursors, it also releases the read lock. +*/ +SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ + int rc; + BtShared *pBt = p->pBt; + MemPage *pPage1; + + assert( writeOnly==1 || writeOnly==0 ); + assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK ); + sqlite3BtreeEnter(p); + if( tripCode==SQLITE_OK ){ + rc = tripCode = saveAllCursors(pBt, 0, 0); + if( rc ) writeOnly = 0; + }else{ + rc = SQLITE_OK; + } + if( tripCode ){ + int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly); + assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) ); + if( rc2!=SQLITE_OK ) rc = rc2; + } + btreeIntegrity(p); + + if( p->inTrans==TRANS_WRITE ){ + int rc2; + + assert( TRANS_WRITE==pBt->inTransaction ); + rc2 = sqlite3PagerRollback(pBt->pPager); + if( rc2!=SQLITE_OK ){ + rc = rc2; + } + + /* The rollback may have destroyed the pPage1->aData value. So + ** call btreeGetPage() on page 1 again to make + ** sure pPage1->aData is set correctly. */ + if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ + int nPage = get4byte(28+(u8*)pPage1->aData); + testcase( nPage==0 ); + if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); + testcase( pBt->nPage!=nPage ); + pBt->nPage = nPage; + releasePage(pPage1); + } + assert( countValidCursors(pBt, 1)==0 ); + pBt->inTransaction = TRANS_READ; + btreeClearHasContent(pBt); + } + + btreeEndTransaction(p); + sqlite3BtreeLeave(p); + return rc; +} + +/* +** Start a statement subtransaction. The subtransaction can be rolled +** back independently of the main transaction. You must start a transaction +** before starting a subtransaction. The subtransaction is ended automatically +** if the main transaction commits or rolls back. +** +** Statement subtransactions are used around individual SQL statements +** that are contained within a BEGIN...COMMIT block. If a constraint +** error occurs within the statement, the effect of that one statement +** can be rolled back without having to rollback the entire transaction. +** +** A statement sub-transaction is implemented as an anonymous savepoint. The +** value passed as the second parameter is the total number of savepoints, +** including the new anonymous savepoint, open on the B-Tree. i.e. if there +** are no active savepoints and no other statement-transactions open, +** iStatement is 1. This anonymous savepoint can be released or rolled back +** using the sqlite3BtreeSavepoint() function. +*/ +SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){ + int rc; + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + assert( p->inTrans==TRANS_WRITE ); + assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); + assert( iStatement>0 ); + assert( iStatement>p->db->nSavepoint ); + assert( pBt->inTransaction==TRANS_WRITE ); + /* At the pager level, a statement transaction is a savepoint with + ** an index greater than all savepoints created explicitly using + ** SQL statements. It is illegal to open, release or rollback any + ** such savepoints while the statement transaction savepoint is active. + */ + rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement); + sqlite3BtreeLeave(p); + return rc; +} + +/* +** The second argument to this function, op, is always SAVEPOINT_ROLLBACK +** or SAVEPOINT_RELEASE. This function either releases or rolls back the +** savepoint identified by parameter iSavepoint, depending on the value +** of op. +** +** Normally, iSavepoint is greater than or equal to zero. However, if op is +** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the +** contents of the entire transaction are rolled back. This is different +** from a normal transaction rollback, as no locks are released and the +** transaction remains open. +*/ +SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ + int rc = SQLITE_OK; + if( p && p->inTrans==TRANS_WRITE ){ + BtShared *pBt = p->pBt; + assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); + assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) ); + sqlite3BtreeEnter(p); + if( op==SAVEPOINT_ROLLBACK ){ + rc = saveAllCursors(pBt, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); + } + if( rc==SQLITE_OK ){ + if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){ + pBt->nPage = 0; + } + rc = newDatabase(pBt); + pBt->nPage = get4byte(28 + pBt->pPage1->aData); + + /* The database size was written into the offset 28 of the header + ** when the transaction started, so we know that the value at offset + ** 28 is nonzero. */ + assert( pBt->nPage>0 ); + } + sqlite3BtreeLeave(p); + } + return rc; +} + +/* +** Create a new cursor for the BTree whose root is on the page +** iTable. If a read-only cursor is requested, it is assumed that +** the caller already has at least a read-only transaction open +** on the database already. If a write-cursor is requested, then +** the caller is assumed to have an open write transaction. +** +** If the BTREE_WRCSR bit of wrFlag is clear, then the cursor can only +** be used for reading. If the BTREE_WRCSR bit is set, then the cursor +** can be used for reading or for writing if other conditions for writing +** are also met. These are the conditions that must be met in order +** for writing to be allowed: +** +** 1: The cursor must have been opened with wrFlag containing BTREE_WRCSR +** +** 2: Other database connections that share the same pager cache +** but which are not in the READ_UNCOMMITTED state may not have +** cursors open with wrFlag==0 on the same table. Otherwise +** the changes made by this write cursor would be visible to +** the read cursors in the other database connection. +** +** 3: The database must be writable (not on read-only media) +** +** 4: There must be an active transaction. +** +** The BTREE_FORDELETE bit of wrFlag may optionally be set if BTREE_WRCSR +** is set. If FORDELETE is set, that is a hint to the implementation that +** this cursor will only be used to seek to and delete entries of an index +** as part of a larger DELETE statement. The FORDELETE hint is not used by +** this implementation. But in a hypothetical alternative storage engine +** in which index entries are automatically deleted when corresponding table +** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE +** operations on this cursor can be no-ops and all READ operations can +** return a null row (2-bytes: 0x01 0x00). +** +** No checking is done to make sure that page iTable really is the +** root page of a b-tree. If it is not, then the cursor acquired +** will not work correctly. +** +** It is assumed that the sqlite3BtreeCursorZero() has been called +** on pCur to initialize the memory space prior to invoking this routine. +*/ +static int btreeCursor( + Btree *p, /* The btree */ + int iTable, /* Root page of table to open */ + int wrFlag, /* 1 to write. 0 read-only */ + struct KeyInfo *pKeyInfo, /* First arg to comparison function */ + BtCursor *pCur /* Space for new cursor */ +){ + BtShared *pBt = p->pBt; /* Shared b-tree handle */ + BtCursor *pX; /* Looping over other all cursors */ + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( wrFlag==0 + || wrFlag==BTREE_WRCSR + || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) + ); + + /* The following assert statements verify that if this is a sharable + ** b-tree database, the connection is holding the required table locks, + ** and that no other connection has any open cursor that conflicts with + ** this lock. */ + assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) ); + assert( wrFlag==0 || !hasReadConflicts(p, iTable) ); + + /* Assert that the caller has opened the required transaction. */ + assert( p->inTrans>TRANS_NONE ); + assert( wrFlag==0 || p->inTrans==TRANS_WRITE ); + assert( pBt->pPage1 && pBt->pPage1->aData ); + assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 ); + + if( wrFlag ){ + allocateTempSpace(pBt); + if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT; + } + if( iTable==1 && btreePagecount(pBt)==0 ){ + assert( wrFlag==0 ); + iTable = 0; + } + + /* Now that no other errors can occur, finish filling in the BtCursor + ** variables and link the cursor into the BtShared list. */ + pCur->pgnoRoot = (Pgno)iTable; + pCur->iPage = -1; + pCur->pKeyInfo = pKeyInfo; + pCur->pBtree = p; + pCur->pBt = pBt; + pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0; + pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY; + /* If there are two or more cursors on the same btree, then all such + ** cursors *must* have the BTCF_Multiple flag set. */ + for(pX=pBt->pCursor; pX; pX=pX->pNext){ + if( pX->pgnoRoot==(Pgno)iTable ){ + pX->curFlags |= BTCF_Multiple; + pCur->curFlags |= BTCF_Multiple; + } + } + pCur->pNext = pBt->pCursor; + pBt->pCursor = pCur; + pCur->eState = CURSOR_INVALID; + return SQLITE_OK; +} +SQLITE_PRIVATE int sqlite3BtreeCursor( + Btree *p, /* The btree */ + int iTable, /* Root page of table to open */ + int wrFlag, /* 1 to write. 0 read-only */ + struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ + BtCursor *pCur /* Write new cursor here */ +){ + int rc; + if( iTable<1 ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + sqlite3BtreeEnter(p); + rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); + sqlite3BtreeLeave(p); + } + return rc; +} + +/* +** Return the size of a BtCursor object in bytes. +** +** This interfaces is needed so that users of cursors can preallocate +** sufficient storage to hold a cursor. The BtCursor object is opaque +** to users so they cannot do the sizeof() themselves - they must call +** this routine. +*/ +SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){ + return ROUND8(sizeof(BtCursor)); +} + +/* +** Initialize memory that will be converted into a BtCursor object. +** +** The simple approach here would be to memset() the entire object +** to zero. But it turns out that the apPage[] and aiIdx[] arrays +** do not need to be zeroed and they are large, so we can save a lot +** of run-time by skipping the initialization of those elements. +*/ +SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ + memset(p, 0, offsetof(BtCursor, iPage)); +} + +/* +** Close a cursor. The read lock on the database file is released +** when the last cursor is closed. +*/ +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; + }else{ + BtCursor *pPrev = pBt->pCursor; + do{ + if( pPrev->pNext==pCur ){ + pPrev->pNext = pCur->pNext; + break; + } + pPrev = pPrev->pNext; + }while( ALWAYS(pPrev) ); + } + for(i=0; i<=pCur->iPage; i++){ + releasePage(pCur->apPage[i]); + } + unlockBtreeIfUnused(pBt); + sqlite3_free(pCur->aOverflow); + /* sqlite3_free(pCur); */ + sqlite3BtreeLeave(pBtree); + } + return SQLITE_OK; +} + +/* +** Make sure the BtCursor* given in the argument has a valid +** BtCursor.info structure. If it is not already valid, call +** btreeParseCell() to fill it in. +** +** BtCursor.info is a cache of the information in the current cell. +** Using this cache reduces the number of calls to btreeParseCell(). +*/ +#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); + assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 ); + } +#else + #define assertCellInfo(x) +#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); + }else{ + assertCellInfo(pCur); + } +} + +#ifndef NDEBUG /* The next routine used only within assert() statements */ +/* +** Return true if the given BtCursor is valid. A valid cursor is one +** that is currently pointing to a row in a (non-empty) table. +** This is a verification routine is used only within assert() statements. +*/ +SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){ + return pCur && pCur->eState==CURSOR_VALID; +} +#endif /* NDEBUG */ +SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){ + assert( pCur!=0 ); + return pCur->eState==CURSOR_VALID; +} + +/* +** Return the value of the integer key or "rowid" for a table btree. +** This routine is only valid for a cursor that is pointing into a +** ordinary table btree. If the cursor points to an index btree or +** is invalid, the result of this routine is undefined. +*/ +SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->curIntKey ); + getCellInfo(pCur); + return pCur->info.nKey; +} + +/* +** Return the number of bytes of payload for the entry that pCur is +** currently pointing to. For table btrees, this will be the amount +** of data. For index btrees, this will be the size of the key. +** +** The caller must guarantee that the cursor is pointing to a non-NULL +** valid entry. In other words, the calling procedure must guarantee +** that the cursor has Cursor.eState==CURSOR_VALID. +*/ +SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + getCellInfo(pCur); + return pCur->info.nPayload; +} + +/* +** Given the page number of an overflow page in the database (parameter +** ovfl), this function finds the page number of the next page in the +** linked list of overflow pages. If possible, it uses the auto-vacuum +** pointer-map data instead of reading the content of page ovfl to do so. +** +** If an error occurs an SQLite error code is returned. Otherwise: +** +** The page number of the next overflow page in the linked list is +** written to *pPgnoNext. If page ovfl is the last page in its linked +** list, *pPgnoNext is set to zero. +** +** If ppPage is not NULL, and a reference to the MemPage object corresponding +** to page number pOvfl was obtained, then *ppPage is set to point to that +** reference. It is the responsibility of the caller to call releasePage() +** on *ppPage to free the reference. In no reference was obtained (because +** the pointer-map was used to obtain the value for *pPgnoNext), then +** *ppPage is set to zero. +*/ +static int getOverflowPage( + BtShared *pBt, /* The database file */ + Pgno ovfl, /* Current overflow page number */ + MemPage **ppPage, /* OUT: MemPage handle (may be NULL) */ + Pgno *pPgnoNext /* OUT: Next overflow page number */ +){ + Pgno next = 0; + MemPage *pPage = 0; + int rc = SQLITE_OK; + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert(pPgnoNext); + +#ifndef SQLITE_OMIT_AUTOVACUUM + /* Try to find the next page in the overflow list using the + ** autovacuum pointer-map pages. Guess that the next page in + ** the overflow list is page number (ovfl+1). If that guess turns + ** out to be wrong, fall back to loading the data of page + ** number ovfl to determine the next page number. + */ + if( pBt->autoVacuum ){ + Pgno pgno; + Pgno iGuess = ovfl+1; + u8 eType; + + while( PTRMAP_ISPAGE(pBt, iGuess) || iGuess==PENDING_BYTE_PAGE(pBt) ){ + iGuess++; + } + + if( iGuess<=btreePagecount(pBt) ){ + rc = ptrmapGet(pBt, iGuess, &eType, &pgno); + if( rc==SQLITE_OK && eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){ + next = iGuess; + rc = SQLITE_DONE; + } + } + } +#endif + + assert( next==0 || rc==SQLITE_DONE ); + if( rc==SQLITE_OK ){ + rc = btreeGetPage(pBt, ovfl, &pPage, (ppPage==0) ? PAGER_GET_READONLY : 0); + assert( rc==SQLITE_OK || pPage==0 ); + if( rc==SQLITE_OK ){ + next = get4byte(pPage->aData); + } + } + + *pPgnoNext = next; + if( ppPage ){ + *ppPage = pPage; + }else{ + releasePage(pPage); + } + return (rc==SQLITE_DONE ? SQLITE_OK : rc); +} + +/* +** Copy data from a buffer to a page, or from a page to a buffer. +** +** pPayload is a pointer to data stored on database page pDbPage. +** If argument eOp is false, then nByte bytes of data are copied +** from pPayload to the buffer pointed at by pBuf. If eOp is true, +** then sqlite3PagerWrite() is called on pDbPage and nByte bytes +** of data are copied from the buffer pBuf to pPayload. +** +** SQLITE_OK is returned on success, otherwise an error code. +*/ +static int copyPayload( + void *pPayload, /* Pointer to page data */ + void *pBuf, /* Pointer to buffer */ + int nByte, /* Number of bytes to copy */ + int eOp, /* 0 -> copy from page, 1 -> copy to page */ + DbPage *pDbPage /* Page containing pPayload */ +){ + if( eOp ){ + /* Copy data from buffer to page (a write operation) */ + int rc = sqlite3PagerWrite(pDbPage); + if( rc!=SQLITE_OK ){ + return rc; + } + memcpy(pPayload, pBuf, nByte); + }else{ + /* Copy data from page to buffer (a read operation) */ + memcpy(pBuf, pPayload, nByte); + } + return SQLITE_OK; +} + +/* +** This function is used to read or overwrite payload information +** for the entry that the pCur cursor is pointing to. The eOp +** argument is interpreted as follows: +** +** 0: The operation is a read. Populate the overflow cache. +** 1: The operation is a write. Populate the overflow cache. +** +** A total of "amt" bytes are read or written beginning at "offset". +** Data is read to or from the buffer pBuf. +** +** The content being read or written might appear on the main page +** or be scattered out on multiple overflow pages. +** +** If the current cursor entry uses one or more overflow pages +** this function may allocate space for and lazily populate +** the overflow page-list cache array (BtCursor.aOverflow). +** Subsequent calls use this cache to make seeking to the supplied offset +** more efficient. +** +** Once an overflow page-list cache has been allocated, it must be +** invalidated if some other cursor writes to the same table, or if +** the cursor is moved to a different row. Additionally, in auto-vacuum +** mode, the following events may invalidate an overflow page-list cache. +** +** * An incremental vacuum, +** * A commit in auto_vacuum="full" mode, +** * Creating a table (may require moving an overflow page). +*/ +static int accessPayload( + BtCursor *pCur, /* Cursor pointing to entry to read from */ + u32 offset, /* Begin reading this far into payload */ + u32 amt, /* Read this many bytes */ + unsigned char *pBuf, /* Write the bytes into this buffer */ + int eOp /* zero to read. non-zero to write. */ +){ + unsigned char *aPayload; + int rc = SQLITE_OK; + int iIdx = 0; + MemPage *pPage = pCur->apPage[pCur->iPage]; /* 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 */ +#endif + + assert( pPage ); + assert( eOp==0 || eOp==1 ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->ixnCell ); + assert( cursorHoldsMutex(pCur) ); + + getCellInfo(pCur); + aPayload = pCur->info.pPayload; + assert( offset+amt <= pCur->info.nPayload ); + + assert( aPayload > pPage->aData ); + if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){ + /* Trying to read or write past the end of the data is an error. The + ** conditional above is really: + ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] + ** but is recast into its current form to avoid integer overflow problems + */ + return SQLITE_CORRUPT_BKPT; + } + + /* Check if data must be read/written to/from the btree page itself. */ + if( offsetinfo.nLocal ){ + int a = amt; + if( a+offset>pCur->info.nLocal ){ + a = pCur->info.nLocal - offset; + } + rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage); + offset = 0; + pBuf += a; + amt -= a; + }else{ + offset -= pCur->info.nLocal; + } + + + if( rc==SQLITE_OK && amt>0 ){ + const u32 ovflSize = pBt->usableSize - 4; /* Bytes content per ovfl page */ + Pgno nextPage; + + nextPage = get4byte(&aPayload[pCur->info.nLocal]); + + /* If the BtCursor.aOverflow[] has not been allocated, allocate it now. + ** + ** The aOverflow[] array is sized at one entry for each overflow page + ** in the overflow chain. The page number of the first overflow page is + ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array + ** means "not yet known" (the cache is lazily populated). + */ + if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ + int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; + if( nOvfl>pCur->nOvflAlloc ){ + Pgno *aNew = (Pgno*)sqlite3Realloc( + pCur->aOverflow, nOvfl*2*sizeof(Pgno) + ); + if( aNew==0 ){ + return SQLITE_NOMEM_BKPT; + }else{ + pCur->nOvflAlloc = nOvfl*2; + pCur->aOverflow = aNew; + } + } + memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); + pCur->curFlags |= BTCF_ValidOvfl; + }else{ + /* If the overflow page-list cache has been allocated and the + ** entry for the first required overflow page is valid, skip + ** directly to it. + */ + if( pCur->aOverflow[offset/ovflSize] ){ + iIdx = (offset/ovflSize); + nextPage = pCur->aOverflow[iIdx]; + offset = (offset%ovflSize); + } + } + + assert( rc==SQLITE_OK && amt>0 ); + while( nextPage ){ + /* If required, populate the overflow page-list cache. */ + assert( pCur->aOverflow[iIdx]==0 + || pCur->aOverflow[iIdx]==nextPage + || CORRUPT_DB ); + pCur->aOverflow[iIdx] = nextPage; + + if( offset>=ovflSize ){ + /* The only reason to read this page is to obtain the page + ** number for the next page in the overflow chain. The page + ** data is not required. So first try to lookup the overflow + ** page-list cache, if any, then fall back to the getOverflowPage() + ** function. + */ + assert( pCur->curFlags & BTCF_ValidOvfl ); + assert( pCur->pBtree->db==pBt->db ); + if( pCur->aOverflow[iIdx+1] ){ + nextPage = pCur->aOverflow[iIdx+1]; + }else{ + rc = getOverflowPage(pBt, nextPage, 0, &nextPage); + } + offset -= ovflSize; + }else{ + /* Need to read this page properly. It contains some of the + ** range of data that is being read (eOp==0) or written (eOp!=0). + */ +#ifdef SQLITE_DIRECT_OVERFLOW_READ + sqlite3_file *fd; /* File from which to do direct overflow read */ +#endif + int a = amt; + if( a + offset > ovflSize ){ + a = ovflSize - offset; + } + +#ifdef SQLITE_DIRECT_OVERFLOW_READ + /* If all the following are true: + ** + ** 1) this is a read operation, and + ** 2) data is required from the start of this overflow page, and + ** 3) there is no open write-transaction, and + ** 4) the database is file-backed, and + ** 5) the page is not in the WAL file + ** 6) at least 4 bytes have already been read into the output buffer + ** + ** then data can be read directly from the database file into the + ** output buffer, bypassing the page-cache altogether. This speeds + ** up loading large records that span many overflow pages. + */ + if( eOp==0 /* (1) */ + && offset==0 /* (2) */ + && pBt->inTransaction==TRANS_READ /* (3) */ + && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (4) */ + && 0==sqlite3PagerUseWal(pBt->pPager, nextPage) /* (5) */ + && &pBuf[-4]>=pBufStart /* (6) */ + ){ + u8 aSave[4]; + u8 *aWrite = &pBuf[-4]; + assert( aWrite>=pBufStart ); /* due to (6) */ + memcpy(aSave, aWrite, 4); + rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); + nextPage = get4byte(aWrite); + memcpy(aWrite, aSave, 4); + }else +#endif + + { + DbPage *pDbPage; + rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage, + (eOp==0 ? PAGER_GET_READONLY : 0) + ); + if( rc==SQLITE_OK ){ + aPayload = sqlite3PagerGetData(pDbPage); + nextPage = get4byte(aPayload); + rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); + sqlite3PagerUnref(pDbPage); + offset = 0; + } + } + amt -= a; + if( amt==0 ) return rc; + pBuf += a; + } + if( rc ) break; + iIdx++; + } + } + + if( rc==SQLITE_OK && amt>0 ){ + return SQLITE_CORRUPT_BKPT; /* Overflow chain ends prematurely */ + } + return rc; +} + +/* +** Read part of the payload for the row at which that cursor pCur is currently +** pointing. "amt" bytes will be transferred into pBuf[]. The transfer +** begins at "offset". +** +** pCur can be pointing to either a table or an index b-tree. +** If pointing to a table btree, then the content section is read. If +** pCur is pointing to an index b-tree then the key section is read. +** +** For sqlite3BtreePayload(), the caller must ensure that pCur is pointing +** to a valid row in the table. For sqlite3BtreePayloadChecked(), the +** cursor might be invalid or might need to be restored before being read. +** +** Return SQLITE_OK on success or an error code if anything goes +** wrong. An error is returned if "offset+amt" is larger than +** the available payload. +*/ +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->ixapPage[pCur->iPage]->nCell ); + return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); +} + +/* +** This variant of sqlite3BtreePayload() works even if the cursor has not +** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read() +** interface. +*/ +#ifndef SQLITE_OMIT_INCRBLOB +static SQLITE_NOINLINE int accessPayloadChecked( + BtCursor *pCur, + u32 offset, + u32 amt, + void *pBuf +){ + int rc; + if ( pCur->eState==CURSOR_INVALID ){ + return SQLITE_ABORT; + } + assert( cursorOwnsBtShared(pCur) ); + rc = btreeRestoreCursorPosition(pCur); + return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0); +} +SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ + if( pCur->eState==CURSOR_VALID ){ + assert( cursorOwnsBtShared(pCur) ); + return accessPayload(pCur, offset, amt, pBuf, 0); + }else{ + return accessPayloadChecked(pCur, offset, amt, pBuf); + } +} +#endif /* SQLITE_OMIT_INCRBLOB */ + +/* +** Return a pointer to payload information from the entry that the +** pCur cursor is pointing to. The pointer is to the beginning of +** the key if index btrees (pPage->intKey==0) and is the data for +** table btrees (pPage->intKey==1). The number of bytes of available +** key/data is written into *pAmt. If *pAmt==0, then the value +** returned will not be a valid pointer. +** +** This routine is an optimization. It is common for the entire key +** and data to fit on the local page and for there to be no overflow +** pages. When that is so, this routine can be used to access the +** key and data without making a copy. If the key and/or data spills +** onto overflow pages, then accessPayload() must be used to reassemble +** the key/data and copy it into a preallocated buffer. +** +** The pointer returned by this routine looks directly into the cached +** page of the database. The data might change or move the next time +** any btree routine is called. +*/ +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]); + assert( pCur->eState==CURSOR_VALID ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->ixapPage[pCur->iPage]->nCell ); + assert( pCur->info.nSize>0 ); + assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); + assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); + amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); + if( pCur->info.nLocalinfo.nLocal; + *pAmt = amt; + return (void*)pCur->info.pPayload; +} + + +/* +** For the entry that cursor pCur is point to, return as +** many bytes of the key or data as are available on the local +** b-tree page. Write the number of available bytes into *pAmt. +** +** The pointer returned is ephemeral. The key/data may move +** or be destroyed on the next call to any Btree routine, +** including calls from other threads against the same cache. +** Hence, a mutex on the BtShared should be held prior to calling +** this routine. +** +** These routines is used to get quick access to key and data +** in the common case where no overflow pages are used. +*/ +SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ + return fetchPayload(pCur, pAmt); +} + + +/* +** Move the cursor down to a new child page. The newPgno argument is the +** page number of the child page to move to. +** +** This function returns SQLITE_CORRUPT if the page-header flags field of +** the new child page does not match the flags field of the parent (i.e. +** if an intkey page appears to be the parent of a non-intkey page, or +** vice-versa). +*/ +static int moveToChild(BtCursor *pCur, u32 newPgno){ + BtShared *pBt = pCur->pBt; + + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->iPageiPage>=0 ); + if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ + return SQLITE_CORRUPT_BKPT; + } + pCur->info.nSize = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->aiIdx[pCur->iPage++] = pCur->ix; + pCur->ix = 0; + return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage], + pCur, pCur->curPagerFlags); +} + +#ifdef SQLITE_DEBUG +/* +** Page pParent is an internal (non-leaf) tree page. This function +** asserts that page number iChild is the left-child if the iIdx'th +** cell in page pParent. Or, if iIdx is equal to the total number of +** cells in pParent, that page number iChild is the right-child of +** the page. +*/ +static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ + if( CORRUPT_DB ) return; /* The conditions tested below might not be true + ** in a corrupt database */ + assert( iIdx<=pParent->nCell ); + if( iIdx==pParent->nCell ){ + assert( get4byte(&pParent->aData[pParent->hdrOffset+8])==iChild ); + }else{ + assert( get4byte(findCell(pParent, iIdx))==iChild ); + } +} +#else +# define assertParentIndex(x,y,z) +#endif + +/* +** Move the cursor up to the parent page. +** +** pCur->idx is set to the cell index that contains the pointer +** to the page we are coming from. If we are coming from the +** right-most child page then pCur->idx is set to one more than +** the largest cell index. +*/ +static void moveToParent(BtCursor *pCur){ + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->iPage>0 ); + assert( pCur->apPage[pCur->iPage] ); + assertParentIndex( + pCur->apPage[pCur->iPage-1], + pCur->aiIdx[pCur->iPage-1], + pCur->apPage[pCur->iPage]->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--]); +} + +/* +** Move the cursor to point to the root page of its b-tree structure. +** +** If the table has a virtual root page, then the cursor is moved to point +** to the virtual root page instead of the actual root page. A table has a +** virtual root page when the actual root page contains no cells and a +** 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. +** +** If this function returns successfully, it may be assumed that the +** page-header flags indicate that the [virtual] root-page is the expected +** kind of b-tree page (i.e. if when opening the cursor the caller did not +** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D, +** indicating a table b-tree, or if the caller did specify a KeyInfo +** structure the flags byte is set to 0x02 or 0x0A, indicating an index +** b-tree). +*/ +static int moveToRoot(BtCursor *pCur){ + MemPage *pRoot; + int rc = SQLITE_OK; + + assert( cursorOwnsBtShared(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); + } + + if( pCur->iPage>=0 ){ + if( pCur->iPage ){ + do{ + assert( pCur->apPage[pCur->iPage]!=0 ); + releasePageNotNull(pCur->apPage[pCur->iPage--]); + }while( pCur->iPage); + goto skip_init; + } + }else if( pCur->pgnoRoot==0 ){ + pCur->eState = CURSOR_INVALID; + return SQLITE_OK; + }else{ + assert( pCur->iPage==(-1) ); + rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], + 0, pCur->curPagerFlags); + if( rc!=SQLITE_OK ){ + pCur->eState = CURSOR_INVALID; + return rc; + } + pCur->iPage = 0; + pCur->curIntKey = pCur->apPage[0]->intKey; + } + pRoot = pCur->apPage[0]; + assert( pRoot->pgno==pCur->pgnoRoot ); + + /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor + ** expected to open it on an index b-tree. Otherwise, if pKeyInfo is + ** NULL, the caller expects a table b-tree. If this is not the case, + ** return an SQLITE_CORRUPT error. + ** + ** Earlier versions of SQLite assumed that this test could not fail + ** if the root page was already loaded when this function was called (i.e. + ** if pCur->iPage>=0). But this is not so if the database is corrupted + ** in such a way that page pRoot is linked into a second b-tree table + ** (or the freelist). */ + assert( pRoot->intKey==1 || pRoot->intKey==0 ); + if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ + return SQLITE_CORRUPT_BKPT; + } + +skip_init: + pCur->ix = 0; + pCur->info.nSize = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); + + pRoot = pCur->apPage[0]; + if( pRoot->nCell>0 ){ + pCur->eState = CURSOR_VALID; + }else if( !pRoot->leaf ){ + Pgno subpage; + if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT; + subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); + pCur->eState = CURSOR_VALID; + rc = moveToChild(pCur, subpage); + }else{ + pCur->eState = CURSOR_INVALID; + } + return rc; +} + +/* +** Move the cursor down to the left-most leaf entry beneath the +** entry to which it is currently pointing. +** +** The left-most leaf is the one with the smallest key - the first +** in ascending order. +*/ +static int moveToLeftmost(BtCursor *pCur){ + Pgno pgno; + int rc = SQLITE_OK; + MemPage *pPage; + + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + assert( pCur->ixnCell ); + pgno = get4byte(findCell(pPage, pCur->ix)); + rc = moveToChild(pCur, pgno); + } + return rc; +} + +/* +** Move the cursor down to the right-most leaf entry beneath the +** page to which it is currently pointing. Notice the difference +** between moveToLeftmost() and moveToRightmost(). moveToLeftmost() +** finds the left-most entry beneath the *entry* whereas moveToRightmost() +** finds the right-most entry beneath the *page*. +** +** The right-most entry is the one with the largest key - the last +** key in ascending order. +*/ +static int moveToRightmost(BtCursor *pCur){ + Pgno pgno; + int rc = SQLITE_OK; + MemPage *pPage = 0; + + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); + pCur->ix = pPage->nCell; + rc = moveToChild(pCur, pgno); + if( rc ) return rc; + } + pCur->ix = pPage->nCell-1; + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & BTCF_ValidNKey)==0 ); + return SQLITE_OK; +} + +/* Move the cursor to the first entry in the table. Return SQLITE_OK +** on success. Set *pRes to 0 if the cursor actually points to something +** or set *pRes to 1 if the table is empty. +*/ +SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ + int rc; + + assert( cursorOwnsBtShared(pCur) ); + 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); + } + } + return rc; +} + +/* Move the cursor to the last entry in the table. Return SQLITE_OK +** on success. Set *pRes to 0 if the cursor actually points to something +** or set *pRes to 1 if the table is empty. +*/ +SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ + int rc; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + + /* If the cursor already points to the last entry, this is a no-op. */ + if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ +#ifdef SQLITE_DEBUG + /* This block serves to assert() that the cursor really does point + ** to the last entry in the b-tree. */ + int ii; + for(ii=0; iiiPage; ii++){ + assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); + } + assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 ); + assert( pCur->apPage[pCur->iPage]->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; + }else{ + assert( pCur->eState==CURSOR_VALID ); + *pRes = 0; + rc = moveToRightmost(pCur); + if( rc==SQLITE_OK ){ + pCur->curFlags |= BTCF_AtLast; + }else{ + pCur->curFlags &= ~BTCF_AtLast; + } + + } + } + return rc; +} + +/* Move the cursor so that it points to an entry near the key +** specified by pIdxKey or intKey. Return a success code. +** +** For INTKEY tables, the intKey parameter is used. pIdxKey +** must be NULL. For index tables, pIdxKey is used and intKey +** is ignored. +** +** If an exact match is not found, then the cursor is always +** left pointing at a leaf page which would hold the entry if it +** were present. The cursor might point to an entry that comes +** before or after the key. +** +** An integer is written into *pRes which is the result of +** comparing the key with the entry to which the cursor is +** pointing. The meaning of the integer written into +** *pRes is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than intKey/pIdxKey or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches intKey/pIdxKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than intKey/pIdxKey. +** +** For index tables, the pIdxKey->eqSeen field is set to 1 if there +** exists an entry in the table that exactly matches pIdxKey. +*/ +SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( + BtCursor *pCur, /* The cursor to be moved */ + UnpackedRecord *pIdxKey, /* Unpacked index key */ + i64 intKey, /* The table key */ + int biasRight, /* If true, bias the search to the high end */ + int *pRes /* Write search results here */ +){ + int rc; + RecordCompare xRecordCompare; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + assert( pRes ); + assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); + assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) ); + + /* If the cursor is already positioned at the point we are trying + ** to move to, then just return without doing any work */ + if( pIdxKey==0 + && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 + ){ + if( pCur->info.nKey==intKey ){ + *pRes = 0; + return SQLITE_OK; + } + if( pCur->info.nKeycurFlags & BTCF_AtLast)!=0 ){ + *pRes = -1; + return SQLITE_OK; + } + /* If the requested key is one more than the previous key, then + ** try to get there using sqlite3BtreeNext() rather than a full + ** binary search. This is an optimization only. The correct answer + ** is still obtained without this ase, only a little more slowely */ + if( pCur->info.nKey+1==intKey && !pCur->skipNext ){ + *pRes = 0; + rc = sqlite3BtreeNext(pCur, pRes); + if( rc ) return rc; + if( *pRes==0 ){ + getCellInfo(pCur); + if( pCur->info.nKey==intKey ){ + return SQLITE_OK; + } + } + } + } + } + + if( pIdxKey ){ + xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); + pIdxKey->errCode = 0; + assert( pIdxKey->default_rc==1 + || pIdxKey->default_rc==0 + || pIdxKey->default_rc==-1 + ); + }else{ + xRecordCompare = 0; /* All keys are integers */ + } + + rc = moveToRoot(pCur); + if( rc ){ + 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->curIntKey || pIdxKey ); + for(;;){ + int lwr, upr, idx, c; + Pgno chldPg; + MemPage *pPage = pCur->apPage[pCur->iPage]; + u8 *pCell; /* Pointer to current cell in pPage */ + + /* pPage->nCell must be greater than zero. If this is the root-page + ** the cursor would have been INVALID above and this for(;;) loop + ** not run. If this is not the root-page, then the moveToChild() routine + ** would have already detected db corruption. Similarly, pPage must + ** be the right kind (index or table) of b-tree page. Otherwise + ** a moveToChild() or moveToRoot() call would have detected corruption. */ + assert( pPage->nCell>0 ); + assert( pPage->intKey==(pIdxKey==0) ); + lwr = 0; + upr = pPage->nCell-1; + assert( biasRight==0 || biasRight==1 ); + idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ + pCur->ix = (u16)idx; + if( xRecordCompare==0 ){ + for(;;){ + i64 nCellKey; + pCell = findCellPastPtr(pPage, idx); + if( pPage->intKeyLeaf ){ + while( 0x80 <= *(pCell++) ){ + if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; + } + } + getVarint(pCell, (u64*)&nCellKey); + if( nCellKeyupr ){ c = -1; break; } + }else if( nCellKey>intKey ){ + upr = idx-1; + if( lwr>upr ){ c = +1; break; } + }else{ + assert( nCellKey==intKey ); + pCur->ix = (u16)idx; + if( !pPage->leaf ){ + lwr = idx; + goto moveto_next_layer; + }else{ + pCur->curFlags |= BTCF_ValidNKey; + pCur->info.nKey = nCellKey; + pCur->info.nSize = 0; + *pRes = 0; + return SQLITE_OK; + } + } + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ + } + }else{ + for(;;){ + int nCell; /* Size of the pCell cell in bytes */ + pCell = findCellPastPtr(pPage, idx); + + /* The maximum supported page-size is 65536 bytes. This means that + ** the maximum number of record bytes stored on an index B-Tree + ** page is less than 16384 bytes and may be stored as a 2-byte + ** varint. This information is used to attempt to avoid parsing + ** the entire cell by checking for the cases where the record is + ** stored entirely within the b-tree page by inspecting the first + ** 2 bytes of the cell. + */ + nCell = pCell[0]; + if( nCell<=pPage->max1bytePayload ){ + /* This branch runs if the record-size field of the cell is a + ** single byte varint and the record fits entirely on the main + ** b-tree page. */ + testcase( pCell+nCell+1==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + }else if( !(pCell[1] & 0x80) + && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + ){ + /* The record-size field is a 2 byte varint and the record + ** fits entirely on the main b-tree page. */ + testcase( pCell+nCell+2==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + }else{ + /* The record flows over onto one or more overflow pages. In + ** this case the whole cell needs to be parsed, a buffer allocated + ** and accessPayload() used to retrieve the record into the + ** buffer before VdbeRecordCompare() can be called. + ** + ** If the record is corrupt, the xRecordCompare routine may read + ** up to two varints past the end of the buffer. An extra 18 + ** bytes of padding is allocated at the end of the buffer in + ** case this happens. */ + void *pCellKey; + u8 * const pCellBody = pCell - pPage->childPtrSize; + pPage->xParseCell(pPage, pCellBody, &pCur->info); + nCell = (int)pCur->info.nKey; + testcase( nCell<0 ); /* True if key size is 2^32 or more */ + testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ + testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ + testcase( nCell==2 ); /* Minimum legal index key size */ + if( nCell<2 ){ + rc = SQLITE_CORRUPT_BKPT; + goto moveto_finish; + } + pCellKey = sqlite3Malloc( nCell+18 ); + if( pCellKey==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto moveto_finish; + } + pCur->ix = (u16)idx; + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + pCur->curFlags &= ~BTCF_ValidOvfl; + if( rc ){ + sqlite3_free(pCellKey); + goto moveto_finish; + } + c = xRecordCompare(nCell, pCellKey, pIdxKey); + sqlite3_free(pCellKey); + } + assert( + (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) + && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) + ); + if( c<0 ){ + lwr = idx+1; + }else if( c>0 ){ + upr = idx-1; + }else{ + assert( c==0 ); + *pRes = 0; + rc = SQLITE_OK; + pCur->ix = (u16)idx; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT; + goto moveto_finish; + } + if( lwr>upr ) break; + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ + } + } + assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); + assert( pPage->isInit ); + if( pPage->leaf ){ + assert( pCur->ixapPage[pCur->iPage]->nCell ); + pCur->ix = (u16)idx; + *pRes = c; + rc = SQLITE_OK; + goto moveto_finish; + } +moveto_next_layer: + if( lwr>=pPage->nCell ){ + chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); + }else{ + chldPg = get4byte(findCell(pPage, lwr)); + } + pCur->ix = (u16)lwr; + rc = moveToChild(pCur, chldPg); + if( rc ) break; + } +moveto_finish: + pCur->info.nSize = 0; + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); + return rc; +} + + +/* +** Return TRUE if the cursor is not pointing at an entry of the table. +** +** TRUE will be returned after a call to sqlite3BtreeNext() moves +** past the last entry in the table or sqlite3BtreePrev() moves past +** the first entry. TRUE is also returned if the table is empty. +*/ +SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ + /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries + ** have been deleted? This API will need to change to return an error code + ** as well as the boolean result value. + */ + return (CURSOR_VALID!=pCur->eState); +} + +/* +** Return an estimate for the number of rows in the table that pCur is +** pointing to. Return a negative number if no estimate is currently +** available. +*/ +SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ + i64 n; + u8 i; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + + /* Currently this interface is only called by the OP_IfSmaller + ** 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; + + for(n=1, i=0; i<=pCur->iPage; i++){ + n *= pCur->apPage[i]->nCell; + } + return n; +} + +/* +** Advance the cursor to the next entry in the database. If +** successful then set *pRes=0. If the cursor +** was already pointing to the last entry in the database before +** this routine was called, then set *pRes=1. +** +** The main entry point is sqlite3BtreeNext(). That routine is optimized +** for the common case of merely incrementing the cell counter BtCursor.aiIdx +** to the next cell on the current page. The (slower) btreeNext() helper +** routine is called when it is necessary to move to a different page or +** to restore the cursor. +** +** The calling function will set *pRes to 0 or 1. The initial *pRes value +** will be 1 if the cursor being stepped corresponds to an SQL index and +** if this routine could have been skipped if that SQL index had been +** a unique index. Otherwise the caller will have set *pRes to zero. +** Zero is the common case. The btree implementation is free to use the +** initial *pRes value as a hint to improve performance, but the current +** SQLite btree implementation does not. (Note that the comdb2 btree +** implementation does use this hint, however.) +*/ +static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ + int rc; + int idx; + MemPage *pPage; + + assert( cursorOwnsBtShared(pCur) ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + assert( *pRes==0 ); + if( pCur->eState!=CURSOR_VALID ){ + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); + rc = restoreCursorPosition(pCur); + if( rc!=SQLITE_OK ){ + return rc; + } + if( CURSOR_INVALID==pCur->eState ){ + *pRes = 1; + return SQLITE_OK; + } + if( pCur->skipNext ){ + assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); + pCur->eState = CURSOR_VALID; + if( pCur->skipNext>0 ){ + pCur->skipNext = 0; + return SQLITE_OK; + } + pCur->skipNext = 0; + } + } + + pPage = pCur->apPage[pCur->iPage]; + idx = ++pCur->ix; + assert( pPage->isInit ); + + /* If the database file is corrupt, it is possible for the value of idx + ** to be invalid here. This can only occur if a second cursor modifies + ** the page while cursor pCur is holding a reference to it. Which can + ** only happen if the database is corrupt in such a way as to link the + ** page into more than one b-tree structure. */ + testcase( idx>pPage->nCell ); + + if( idx>=pPage->nCell ){ + if( !pPage->leaf ){ + rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); + if( rc ) return rc; + return moveToLeftmost(pCur); + } + do{ + if( pCur->iPage==0 ){ + *pRes = 1; + pCur->eState = CURSOR_INVALID; + return SQLITE_OK; + } + moveToParent(pCur); + pPage = pCur->apPage[pCur->iPage]; + }while( pCur->ix>=pPage->nCell ); + if( pPage->intKey ){ + return sqlite3BtreeNext(pCur, pRes); + }else{ + return SQLITE_OK; + } + } + if( pPage->leaf ){ + return SQLITE_OK; + }else{ + return moveToLeftmost(pCur); + } +} +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ + MemPage *pPage; + assert( cursorOwnsBtShared(pCur) ); + assert( pRes!=0 ); + assert( *pRes==0 || *pRes==1 ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + pCur->info.nSize = 0; + pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + *pRes = 0; + if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); + pPage = pCur->apPage[pCur->iPage]; + if( (++pCur->ix)>=pPage->nCell ){ + pCur->ix--; + return btreeNext(pCur, pRes); + } + if( pPage->leaf ){ + return SQLITE_OK; + }else{ + return moveToLeftmost(pCur); + } +} + +/* +** Step the cursor to the back to the previous entry in the database. If +** successful then set *pRes=0. If the cursor +** was already pointing to the first entry in the database before +** this routine was called, then set *pRes=1. +** +** The main entry point is sqlite3BtreePrevious(). That routine is optimized +** for the common case of merely decrementing the cell counter BtCursor.aiIdx +** to the previous cell on the current page. The (slower) btreePrevious() +** helper routine is called when it is necessary to move to a different page +** or to restore the cursor. +** +** The calling function will set *pRes to 0 or 1. The initial *pRes value +** will be 1 if the cursor being stepped corresponds to an SQL index and +** if this routine could have been skipped if that SQL index had been +** a unique index. Otherwise the caller will have set *pRes to zero. +** Zero is the common case. The btree implementation is free to use the +** initial *pRes value as a hint to improve performance, but the current +** SQLite btree implementation does not. (Note that the comdb2 btree +** implementation does use this hint, however.) +*/ +static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ + int rc; + MemPage *pPage; + + assert( cursorOwnsBtShared(pCur) ); + assert( pRes!=0 ); + assert( *pRes==0 ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); + assert( pCur->info.nSize==0 ); + if( pCur->eState!=CURSOR_VALID ){ + rc = restoreCursorPosition(pCur); + if( rc!=SQLITE_OK ){ + return rc; + } + if( CURSOR_INVALID==pCur->eState ){ + *pRes = 1; + return SQLITE_OK; + } + if( pCur->skipNext ){ + assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); + pCur->eState = CURSOR_VALID; + if( pCur->skipNext<0 ){ + pCur->skipNext = 0; + return SQLITE_OK; + } + pCur->skipNext = 0; + } + } + + pPage = pCur->apPage[pCur->iPage]; + assert( pPage->isInit ); + if( !pPage->leaf ){ + int idx = pCur->ix; + rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); + if( rc ) return rc; + rc = moveToRightmost(pCur); + }else{ + while( pCur->ix==0 ){ + if( pCur->iPage==0 ){ + pCur->eState = CURSOR_INVALID; + *pRes = 1; + return SQLITE_OK; + } + moveToParent(pCur); + } + assert( pCur->info.nSize==0 ); + assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 ); + + pCur->ix--; + pPage = pCur->apPage[pCur->iPage]; + if( pPage->intKey && !pPage->leaf ){ + rc = sqlite3BtreePrevious(pCur, pRes); + }else{ + rc = SQLITE_OK; + } + } + return rc; +} +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ + assert( cursorOwnsBtShared(pCur) ); + assert( pRes!=0 ); + assert( *pRes==0 || *pRes==1 ); + assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + *pRes = 0; + pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); + pCur->info.nSize = 0; + if( pCur->eState!=CURSOR_VALID + || pCur->ix==0 + || pCur->apPage[pCur->iPage]->leaf==0 + ){ + return btreePrevious(pCur, pRes); + } + pCur->ix--; + return SQLITE_OK; +} + +/* +** Allocate a new page from the database file. +** +** The new page is marked as dirty. (In other words, sqlite3PagerWrite() +** has already been called on the new page.) The new page has also +** been referenced and the calling routine is responsible for calling +** sqlite3PagerUnref() on the new page when it is done. +** +** SQLITE_OK is returned on success. Any other return value indicates +** an error. *ppPage is set to NULL in the event of an error. +** +** If the "nearby" parameter is not 0, then an effort is made to +** locate a page close to the page number "nearby". This can be used in an +** attempt to keep related pages close to each other in the database file, +** which in turn can make database access faster. +** +** If the eMode parameter is BTALLOC_EXACT and the nearby page exists +** anywhere on the free-list, then it is guaranteed to be returned. If +** eMode is BTALLOC_LT then the page returned will be less than or equal +** to nearby if any such page exists. If eMode is BTALLOC_ANY then there +** are no restrictions on which page is returned. +*/ +static int allocateBtreePage( + BtShared *pBt, /* The btree */ + MemPage **ppPage, /* Store pointer to the allocated page here */ + Pgno *pPgno, /* Store the page number here */ + Pgno nearby, /* Search for a page near this one */ + u8 eMode /* BTALLOC_EXACT, BTALLOC_LT, or BTALLOC_ANY */ +){ + MemPage *pPage1; + int rc; + u32 n; /* Number of pages on the freelist */ + u32 k; /* Number of leaves on the trunk of the freelist */ + MemPage *pTrunk = 0; + MemPage *pPrevTrunk = 0; + Pgno mxPage; /* Total size of the database file */ + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) ); + pPage1 = pBt->pPage1; + mxPage = btreePagecount(pBt); + /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36 + ** stores stores the total number of pages on the freelist. */ + n = get4byte(&pPage1->aData[36]); + testcase( n==mxPage-1 ); + if( n>=mxPage ){ + return SQLITE_CORRUPT_BKPT; + } + if( n>0 ){ + /* There are pages on the freelist. Reuse one of those pages. */ + Pgno iTrunk; + u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ + u32 nSearch = 0; /* Count of the number of search attempts */ + + /* If eMode==BTALLOC_EXACT and a query of the pointer-map + ** shows that the page 'nearby' is somewhere on the free-list, then + ** the entire-list will be searched for that page. + */ +#ifndef SQLITE_OMIT_AUTOVACUUM + if( eMode==BTALLOC_EXACT ){ + if( nearby<=mxPage ){ + u8 eType; + assert( nearby>0 ); + assert( pBt->autoVacuum ); + rc = ptrmapGet(pBt, nearby, &eType, 0); + if( rc ) return rc; + if( eType==PTRMAP_FREEPAGE ){ + searchList = 1; + } + } + }else if( eMode==BTALLOC_LE ){ + searchList = 1; + } +#endif + + /* Decrement the free-list count by 1. Set iTrunk to the index of the + ** first free-list trunk page. iPrevTrunk is initially 1. + */ + rc = sqlite3PagerWrite(pPage1->pDbPage); + if( rc ) return rc; + put4byte(&pPage1->aData[36], n-1); + + /* The code within this loop is run only once if the 'searchList' variable + ** is not true. Otherwise, it runs once for each trunk-page on the + ** free-list until the page 'nearby' is located (eMode==BTALLOC_EXACT) + ** or until a page less than 'nearby' is located (eMode==BTALLOC_LT) + */ + do { + pPrevTrunk = pTrunk; + if( pPrevTrunk ){ + /* EVIDENCE-OF: R-01506-11053 The first integer on a freelist trunk page + ** is the page number of the next freelist trunk page in the list or + ** zero if this is the last freelist trunk page. */ + iTrunk = get4byte(&pPrevTrunk->aData[0]); + }else{ + /* EVIDENCE-OF: R-59841-13798 The 4-byte big-endian integer at offset 32 + ** stores the page number of the first page of the freelist, or zero if + ** the freelist is empty. */ + iTrunk = get4byte(&pPage1->aData[32]); + } + testcase( iTrunk==mxPage ); + if( iTrunk>mxPage || nSearch++ > n ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); + } + if( rc ){ + pTrunk = 0; + goto end_allocate_page; + } + assert( pTrunk!=0 ); + assert( pTrunk->aData!=0 ); + /* EVIDENCE-OF: R-13523-04394 The second integer on a freelist trunk page + ** is the number of leaf page pointers to follow. */ + k = get4byte(&pTrunk->aData[4]); + if( k==0 && !searchList ){ + /* The trunk has no leaves and the list is not being searched. + ** So extract the trunk page itself and use it as the newly + ** allocated page */ + assert( pPrevTrunk==0 ); + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc ){ + goto end_allocate_page; + } + *pPgno = iTrunk; + memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); + *ppPage = pTrunk; + pTrunk = 0; + TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); + }else if( k>(u32)(pBt->usableSize/4 - 2) ){ + /* Value of k is out of range. Database corruption */ + rc = SQLITE_CORRUPT_BKPT; + goto end_allocate_page; +#ifndef SQLITE_OMIT_AUTOVACUUM + }else if( searchList + && (nearby==iTrunk || (iTrunkpDbPage); + if( rc ){ + goto end_allocate_page; + } + if( k==0 ){ + if( !pPrevTrunk ){ + memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4); + }else{ + rc = sqlite3PagerWrite(pPrevTrunk->pDbPage); + if( rc!=SQLITE_OK ){ + goto end_allocate_page; + } + memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4); + } + }else{ + /* The trunk page is required by the caller but it contains + ** pointers to free-list leaves. The first leaf becomes a trunk + ** page in this case. + */ + MemPage *pNewTrunk; + Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); + if( iNewTrunk>mxPage ){ + rc = SQLITE_CORRUPT_BKPT; + goto end_allocate_page; + } + testcase( iNewTrunk==mxPage ); + rc = btreeGetUnusedPage(pBt, iNewTrunk, &pNewTrunk, 0); + if( rc!=SQLITE_OK ){ + goto end_allocate_page; + } + rc = sqlite3PagerWrite(pNewTrunk->pDbPage); + if( rc!=SQLITE_OK ){ + releasePage(pNewTrunk); + goto end_allocate_page; + } + memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4); + put4byte(&pNewTrunk->aData[4], k-1); + memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4); + releasePage(pNewTrunk); + if( !pPrevTrunk ){ + assert( sqlite3PagerIswriteable(pPage1->pDbPage) ); + put4byte(&pPage1->aData[32], iNewTrunk); + }else{ + rc = sqlite3PagerWrite(pPrevTrunk->pDbPage); + if( rc ){ + goto end_allocate_page; + } + put4byte(&pPrevTrunk->aData[0], iNewTrunk); + } + } + pTrunk = 0; + TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); +#endif + }else if( k>0 ){ + /* Extract a leaf from the trunk */ + u32 closest; + Pgno iPage; + unsigned char *aData = pTrunk->aData; + if( nearby>0 ){ + u32 i; + closest = 0; + if( eMode==BTALLOC_LE ){ + for(i=0; imxPage ){ + rc = SQLITE_CORRUPT_BKPT; + goto end_allocate_page; + } + testcase( iPage==mxPage ); + if( !searchList + || (iPage==nearby || (iPagepgno, n-1)); + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc ) goto end_allocate_page; + if( closestpDbPage); + if( rc!=SQLITE_OK ){ + releasePage(*ppPage); + *ppPage = 0; + } + } + searchList = 0; + } + } + releasePage(pPrevTrunk); + pPrevTrunk = 0; + }while( searchList ); + }else{ + /* There are no pages on the freelist, so append a new page to the + ** database image. + ** + ** Normally, new pages allocated by this block can be requested from the + ** pager layer with the 'no-content' flag set. This prevents the pager + ** from trying to read the pages content from disk. However, if the + ** current transaction has already run one or more incremental-vacuum + ** steps, then the page we are about to allocate may contain content + ** that is required in the event of a rollback. In this case, do + ** not set the no-content flag. This causes the pager to load and journal + ** the current page content before overwriting it. + ** + ** Note that the pager will not actually attempt to load or journal + ** content for any page that really does lie past the end of the database + ** file on disk. So the effects of disabling the no-content optimization + ** here are confined to those pages that lie between the end of the + ** database image and the end of the database file. + */ + int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate))? PAGER_GET_NOCONTENT:0; + + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + if( rc ) return rc; + pBt->nPage++; + if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++; + +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){ + /* If *pPgno refers to a pointer-map page, allocate two new pages + ** at the end of the file instead of one. The first allocated page + ** becomes a new pointer-map page, the second is used by the caller. + */ + MemPage *pPg = 0; + TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); + assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); + rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pPg->pDbPage); + releasePage(pPg); + } + if( rc ) return rc; + pBt->nPage++; + if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; } + } +#endif + put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage); + *pPgno = pBt->nPage; + + assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); + rc = btreeGetUnusedPage(pBt, *pPgno, ppPage, bNoContent); + if( rc ) return rc; + rc = sqlite3PagerWrite((*ppPage)->pDbPage); + if( rc!=SQLITE_OK ){ + releasePage(*ppPage); + *ppPage = 0; + } + TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); + } + + assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); + +end_allocate_page: + releasePage(pTrunk); + releasePage(pPrevTrunk); + assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 ); + assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 ); + return rc; +} + +/* +** This function is used to add page iPage to the database file free-list. +** It is assumed that the page is not already a part of the free-list. +** +** The value passed as the second argument to this function is optional. +** If the caller happens to have a pointer to the MemPage object +** corresponding to page iPage handy, it may pass it as the second value. +** Otherwise, it may pass NULL. +** +** If a pointer to a MemPage object is passed as the second argument, +** its reference count is not altered by this function. +*/ +static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ + MemPage *pTrunk = 0; /* Free-list trunk page */ + Pgno iTrunk = 0; /* Page number of free-list trunk page */ + MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */ + MemPage *pPage; /* Page being freed. May be NULL. */ + int rc; /* Return Code */ + int nFree; /* Initial number of pages on free-list */ + + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( CORRUPT_DB || iPage>1 ); + assert( !pMemPage || pMemPage->pgno==iPage ); + + if( iPage<2 ) return SQLITE_CORRUPT_BKPT; + if( pMemPage ){ + pPage = pMemPage; + sqlite3PagerRef(pPage->pDbPage); + }else{ + pPage = btreePageLookup(pBt, iPage); + } + + /* Increment the free page count on pPage1 */ + rc = sqlite3PagerWrite(pPage1->pDbPage); + if( rc ) goto freepage_out; + nFree = get4byte(&pPage1->aData[36]); + put4byte(&pPage1->aData[36], nFree+1); + + if( pBt->btsFlags & BTS_SECURE_DELETE ){ + /* If the secure_delete option is enabled, then + ** always fully overwrite deleted information with zeros. + */ + if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) ) + || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0) + ){ + goto freepage_out; + } + memset(pPage->aData, 0, pPage->pBt->pageSize); + } + + /* If the database supports auto-vacuum, write an entry in the pointer-map + ** to indicate that the page is free. + */ + if( ISAUTOVACUUM ){ + ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc); + if( rc ) goto freepage_out; + } + + /* Now manipulate the actual database free-list structure. There are two + ** possibilities. If the free-list is currently empty, or if the first + ** trunk page in the free-list is full, then this page will become a + ** new free-list trunk page. Otherwise, it will become a leaf of the + ** first trunk page in the current free-list. This block tests if it + ** is possible to add the page as a new free-list leaf. + */ + if( nFree!=0 ){ + u32 nLeaf; /* Initial number of leaf cells on trunk page */ + + iTrunk = get4byte(&pPage1->aData[32]); + rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); + if( rc!=SQLITE_OK ){ + goto freepage_out; + } + + nLeaf = get4byte(&pTrunk->aData[4]); + assert( pBt->usableSize>32 ); + if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ + rc = SQLITE_CORRUPT_BKPT; + goto freepage_out; + } + if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ + /* In this case there is room on the trunk page to insert the page + ** being freed as a new leaf. + ** + ** Note that the trunk page is not really full until it contains + ** usableSize/4 - 2 entries, not usableSize/4 - 8 entries as we have + ** coded. But due to a coding error in versions of SQLite prior to + ** 3.6.0, databases with freelist trunk pages holding more than + ** usableSize/4 - 8 entries will be reported as corrupt. In order + ** to maintain backwards compatibility with older versions of SQLite, + ** we will continue to restrict the number of entries to usableSize/4 - 8 + ** for now. At some point in the future (once everyone has upgraded + ** to 3.6.0 or later) we should consider fixing the conditional above + ** to read "usableSize/4-2" instead of "usableSize/4-8". + ** + ** EVIDENCE-OF: R-19920-11576 However, newer versions of SQLite still + ** avoid using the last six entries in the freelist trunk page array in + ** order that database files created by newer versions of SQLite can be + ** read by older versions of SQLite. + */ + rc = sqlite3PagerWrite(pTrunk->pDbPage); + if( rc==SQLITE_OK ){ + put4byte(&pTrunk->aData[4], nLeaf+1); + put4byte(&pTrunk->aData[8+nLeaf*4], iPage); + if( pPage && (pBt->btsFlags & BTS_SECURE_DELETE)==0 ){ + sqlite3PagerDontWrite(pPage->pDbPage); + } + rc = btreeSetHasContent(pBt, iPage); + } + TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno)); + goto freepage_out; + } + } + + /* If control flows to this point, then it was not possible to add the + ** the page being freed as a leaf page of the first trunk in the free-list. + ** Possibly because the free-list is empty, or possibly because the + ** first trunk in the free-list is full. Either way, the page being freed + ** will become the new first trunk page in the free-list. + */ + if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){ + goto freepage_out; + } + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc!=SQLITE_OK ){ + goto freepage_out; + } + put4byte(pPage->aData, iTrunk); + put4byte(&pPage->aData[4], 0); + put4byte(&pPage1->aData[32], iPage); + TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk)); + +freepage_out: + if( pPage ){ + pPage->isInit = 0; + } + releasePage(pPage); + releasePage(pTrunk); + return rc; +} +static void freePage(MemPage *pPage, int *pRC){ + if( (*pRC)==SQLITE_OK ){ + *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); + } +} + +/* +** Free any overflow pages associated with the given Cell. Write the +** local Cell size (the number of bytes on the original page, omitting +** overflow) into *pnSize. +*/ +static int clearCell( + MemPage *pPage, /* The page that contains the Cell */ + unsigned char *pCell, /* First byte of the Cell */ + CellInfo *pInfo /* Size information about the cell */ +){ + BtShared *pBt = pPage->pBt; + Pgno ovflPgno; + int rc; + int nOvfl; + u32 ovflPageSize; + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + pPage->xParseCell(pPage, pCell, pInfo); + if( pInfo->nLocal==pInfo->nPayload ){ + return SQLITE_OK; /* No overflow pages. Return without doing anything */ + } + if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){ + return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */ + } + ovflPgno = get4byte(pCell + pInfo->nSize - 4); + assert( pBt->usableSize > 4 ); + ovflPageSize = pBt->usableSize - 4; + nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize; + assert( nOvfl>0 || + (CORRUPT_DB && (pInfo->nPayload + ovflPageSize)btreePagecount(pBt) ){ + /* 0 is not a legal page number and page 1 cannot be an + ** overflow page. Therefore if ovflPgno<2 or past the end of the + ** file the database must be corrupt. */ + return SQLITE_CORRUPT_BKPT; + } + if( nOvfl ){ + rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); + if( rc ) return rc; + } + + if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) ) + && sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1 + ){ + /* There is no reason any cursor should have an outstanding reference + ** to an overflow page belonging to a cell that is being deleted/updated. + ** So if there exists more than one reference to this page, then it + ** must not really be an overflow page and the database must be corrupt. + ** It is helpful to detect this before calling freePage2(), as + ** freePage2() may zero the page contents if secure-delete mode is + ** enabled. If this 'overflow' page happens to be a page that the + ** caller is iterating through or using in some other way, this + ** can be problematic. + */ + rc = SQLITE_CORRUPT_BKPT; + }else{ + rc = freePage2(pBt, pOvfl, ovflPgno); + } + + if( pOvfl ){ + sqlite3PagerUnref(pOvfl->pDbPage); + } + if( rc ) return rc; + ovflPgno = iNext; + } + return SQLITE_OK; +} + +/* +** Create the byte sequence used to represent a cell on page pPage +** and write that byte sequence into pCell[]. Overflow pages are +** allocated and filled in as necessary. The calling procedure +** is responsible for making sure sufficient space has been allocated +** for pCell[]. +** +** Note that pCell does not necessary need to point to the pPage->aData +** area. pCell might point to some temporary storage. The cell will +** be constructed in this temporary area then copied into pPage->aData +** later. +*/ +static int fillInCell( + MemPage *pPage, /* The page that contains the cell */ + unsigned char *pCell, /* Complete text of the cell */ + const BtreePayload *pX, /* Payload with which to construct the cell */ + int *pnSize /* Write cell size here */ +){ + int nPayload; + const u8 *pSrc; + int nSrc, n, rc; + int spaceLeft; + MemPage *pOvfl = 0; + MemPage *pToRelease = 0; + unsigned char *pPrior; + unsigned char *pPayload; + BtShared *pBt = pPage->pBt; + Pgno pgnoOvfl = 0; + 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( pCellaData || pCell>=&pPage->aData[pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + /* Fill in the header. */ + nHeader = pPage->childPtrSize; + if( pPage->intKey ){ + nPayload = pX->nData + pX->nZero; + pSrc = pX->pData; + nSrc = pX->nData; + assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */ + nHeader += putVarint32(&pCell[nHeader], nPayload); + nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey); + }else{ + assert( pX->nKey<=0x7fffffff && pX->pKey!=0 ); + nSrc = nPayload = (int)pX->nKey; + pSrc = pX->pKey; + nHeader += putVarint32(&pCell[nHeader], nPayload); + } + + /* Fill in the payload */ + if( nPayload<=pPage->maxLocal ){ + 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]; + } + pPayload = &pCell[nHeader]; + + /* At this point variables should be set as follows: + ** + ** nPayload Total payload size in bytes + ** pPayload Begin writing payload here + ** spaceLeft Space available at pPayload. If nPayload>spaceLeft, + ** that means content must spill into overflow pages. + ** *pnSize Size of the local cell (not counting overflow pages) + ** pPrior Where to write the pgno of the first overflow page + ** + ** Use a call to btreeParseCellPtr() to verify that the values above + ** were computed correctly. + */ +#ifdef SQLITE_DEBUG + { + CellInfo info; + pPage->xParseCell(pPage, pCell, &info); + assert( nHeader==(int)(info.pPayload - pCell) ); + assert( info.nKey==pX->nKey ); + assert( *pnSize == info.nSize ); + assert( spaceLeft == info.nLocal ); + } +#endif + + /* Write the payload into the local Cell and any extra into overflow pages */ + while( nPayload>0 ){ + if( spaceLeft==0 ){ +#ifndef SQLITE_OMIT_AUTOVACUUM + Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */ + if( pBt->autoVacuum ){ + do{ + pgnoOvfl++; + } while( + PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt) + ); + } +#endif + rc = allocateBtreePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, 0); +#ifndef SQLITE_OMIT_AUTOVACUUM + /* If the database supports auto-vacuum, and the second or subsequent + ** overflow page is being allocated, add an entry to the pointer-map + ** for that page now. + ** + ** If this is the first overflow page, then write a partial entry + ** to the pointer-map. If we write nothing to this pointer-map slot, + ** then the optimistic overflow chain processing in clearCell() + ** may misinterpret the uninitialized values and delete the + ** wrong pages from the database. + */ + if( pBt->autoVacuum && rc==SQLITE_OK ){ + u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1); + ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap, &rc); + if( rc ){ + releasePage(pOvfl); + } + } +#endif + if( rc ){ + releasePage(pToRelease); + return rc; + } + + /* If pToRelease is not zero than pPrior points into the data area + ** of pToRelease. Make sure pToRelease is still writeable. */ + assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); + + /* If pPrior is part of the data area of pPage, then make sure pPage + ** is still writeable */ + assert( pPrioraData || pPrior>=&pPage->aData[pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + put4byte(pPrior, pgnoOvfl); + releasePage(pToRelease); + pToRelease = pOvfl; + pPrior = pOvfl->aData; + put4byte(pPrior, 0); + 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( pPayloadaData || 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; +} + +/* +** Remove the i-th cell from pPage. This routine effects pPage only. +** The cell content is not freed or deallocated. It is assumed that +** the cell content has been copied someplace else. This routine just +** removes the reference to the cell from pPage. +** +** "sz" must be the number of bytes in the cell. +*/ +static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ + u32 pc; /* Offset to cell content of cell being deleted */ + u8 *data; /* pPage->aData */ + u8 *ptr; /* Used to move bytes around within data[] */ + int rc; /* The return code */ + int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ + + if( *pRC ) return; + assert( idx>=0 && idxnCell ); + assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + data = pPage->aData; + ptr = &pPage->aCellIdx[2*idx]; + pc = get2byte(ptr); + 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 ){ + *pRC = SQLITE_CORRUPT_BKPT; + return; + } + rc = freeSpace(pPage, pc, sz); + if( rc ){ + *pRC = rc; + return; + } + pPage->nCell--; + if( pPage->nCell==0 ){ + memset(&data[hdr+1], 0, 4); + data[hdr+7] = 0; + put2byte(&data[hdr+5], pPage->pBt->usableSize); + pPage->nFree = pPage->pBt->usableSize - pPage->hdrOffset + - pPage->childPtrSize - 8; + }else{ + memmove(ptr, ptr+2, 2*(pPage->nCell - idx)); + put2byte(&data[hdr+3], pPage->nCell); + pPage->nFree += 2; + } +} + +/* +** Insert a new cell on pPage at cell index "i". pCell points to the +** content of the cell. +** +** If the cell content will fit on the page, then put it there. If it +** will not fit, then make a copy of the cell content into pTemp if +** pTemp is not null. Regardless of pTemp, allocate a new entry +** in pPage->apOvfl[] and make it point to the cell content (either +** in pTemp or the original pCell) and also record its index. +** Allocating a new entry in pPage->aCell[] implies that +** pPage->nOverflow is incremented. +** +** *pRC must be SQLITE_OK when this routine is called. +*/ +static void insertCell( + MemPage *pPage, /* Page into which we are copying */ + int i, /* New cell becomes the i-th cell of the page */ + u8 *pCell, /* Content of the new cell */ + int sz, /* Bytes of content in pCell */ + u8 *pTemp, /* Temp storage space for pCell, if needed */ + Pgno iChild, /* If non-zero, replace first 4 bytes with this value */ + int *pRC /* Read and write return code from here */ +){ + int idx = 0; /* Where to write new cell content in data[] */ + int j; /* Loop counter */ + u8 *data; /* The content of the whole page */ + u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ + + assert( *pRC==SQLITE_OK ); + assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); + assert( MX_CELL(pPage->pBt)<=10921 ); + assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); + assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); + assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + /* The cell should normally be sized correctly. However, when moving a + ** malformed cell from a leaf page to an interior page, if the cell size + ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size + ** might be less than 8 (leaf-size + pointer) on the interior node. Hence + ** the term after the || in the following assert(). */ + assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) ); + if( pPage->nOverflow || sz+2>pPage->nFree ){ + if( pTemp ){ + memcpy(pTemp, pCell, sz); + pCell = pTemp; + } + if( iChild ){ + put4byte(pCell, iChild); + } + j = pPage->nOverflow++; + /* Comparison against ArraySize-1 since we hold back one extra slot + ** as a contingency. In other words, never need more than 3 overflow + ** slots but 4 are allocated, just to be safe. */ + assert( j < ArraySize(pPage->apOvfl)-1 ); + pPage->apOvfl[j] = pCell; + pPage->aiOvfl[j] = (u16)i; + + /* When multiple overflows occur, they are always sequential and in + ** sorted order. This invariants arise because multiple overflows can + ** only occur when inserting divider cells into the parent page during + ** balancing, and the dividers are adjacent and sorted. + */ + assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */ + assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */ + }else{ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc!=SQLITE_OK ){ + *pRC = rc; + return; + } + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + data = pPage->aData; + assert( &data[pPage->cellOffset]==pPage->aCellIdx ); + rc = allocateSpace(pPage, sz, &idx); + if( rc ){ *pRC = rc; return; } + /* The allocateSpace() routine guarantees the following properties + ** if it returns successfully */ + assert( idx >= 0 ); + assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); + assert( idx+sz <= (int)pPage->pBt->usableSize ); + pPage->nFree -= (u16)(2 + sz); + memcpy(&data[idx], pCell, sz); + if( iChild ){ + put4byte(&data[idx], iChild); + } + pIns = pPage->aCellIdx + i*2; + memmove(pIns+2, pIns, 2*(pPage->nCell - i)); + put2byte(pIns, idx); + pPage->nCell++; + /* increment the cell count */ + if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; + assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell ); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pPage->pBt->autoVacuum ){ + /* The cell may contain a pointer to an overflow page. If so, write + ** the entry for the overflow page into the pointer map. + */ + ptrmapPutOvflPtr(pPage, pCell, pRC); + } +#endif + } +} + +/* +** A CellArray object contains a cache of pointers and sizes for a +** consecutive sequence of cells that might be held on multiple pages. +*/ +typedef struct CellArray CellArray; +struct CellArray { + int nCell; /* Number of cells in apCell[] */ + MemPage *pRef; /* Reference page */ + u8 **apCell; /* All cells begin balanced */ + u16 *szCell; /* Local size of all cells in apCell[] */ +}; + +/* +** Make sure the cell sizes at idx, idx+1, ..., idx+N-1 have been +** computed. +*/ +static void populateCellCache(CellArray *p, int idx, int N){ + assert( idx>=0 && idx+N<=p->nCell ); + while( N>0 ){ + assert( p->apCell[idx]!=0 ); + if( p->szCell[idx]==0 ){ + p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]); + }else{ + assert( CORRUPT_DB || + p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) ); + } + idx++; + N--; + } +} + +/* +** Return the size of the Nth element of the cell array +*/ +static SQLITE_NOINLINE u16 computeCellSize(CellArray *p, int N){ + assert( N>=0 && NnCell ); + assert( p->szCell[N]==0 ); + p->szCell[N] = p->pRef->xCellSize(p->pRef, p->apCell[N]); + return p->szCell[N]; +} +static u16 cachedCellSize(CellArray *p, int N){ + assert( N>=0 && NnCell ); + if( p->szCell[N] ) return p->szCell[N]; + return computeCellSize(p, N); +} + +/* +** Array apCell[] contains pointers to nCell b-tree page cells. The +** szCell[] array contains the size in bytes of each cell. This function +** replaces the current contents of page pPg with the contents of the cell +** array. +** +** Some of the cells in apCell[] may currently be stored in pPg. This +** function works around problems caused by this by making a copy of any +** such cells before overwriting the page data. +** +** The MemPage.nFree field is invalidated by this function. It is the +** responsibility of the caller to set it correctly. +*/ +static int rebuildPage( + MemPage *pPg, /* Edit this page */ + int nCell, /* Final number of cells on page */ + u8 **apCell, /* Array of cells */ + u16 *szCell /* Array of cell sizes */ +){ + const int hdr = pPg->hdrOffset; /* Offset of header on pPg */ + u8 * const aData = pPg->aData; /* Pointer to data for pPg */ + const int usableSize = pPg->pBt->usableSize; + u8 * const pEnd = &aData[usableSize]; + int i; + u8 *pCellptr = pPg->aCellIdx; + u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); + u8 *pData; + + i = get2byte(&aData[hdr+5]); + memcpy(&pTmp[i], &aData[i], usableSize - i); + + pData = pEnd; + for(i=0; ixCellSize(pPg, pCell) || CORRUPT_DB ); + testcase( szCell[i]!=pPg->xCellSize(pPg,pCell) ); + } + + /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ + pPg->nCell = nCell; + pPg->nOverflow = 0; + + put2byte(&aData[hdr+1], 0); + put2byte(&aData[hdr+3], pPg->nCell); + put2byte(&aData[hdr+5], pData - aData); + aData[hdr+7] = 0x00; + return SQLITE_OK; +} + +/* +** Array apCell[] contains nCell pointers to b-tree cells. Array szCell +** contains the size in bytes of each such cell. This function attempts to +** add the cells stored in the array to page pPg. If it cannot (because +** the page needs to be defragmented before the cells will fit), non-zero +** is returned. Otherwise, if the cells are added successfully, zero is +** returned. +** +** Argument pCellptr points to the first entry in the cell-pointer array +** (part of page pPg) to populate. After cell apCell[0] is written to the +** page body, a 16-bit offset is written to pCellptr. And so on, for each +** cell in the array. It is the responsibility of the caller to ensure +** that it is safe to overwrite this part of the cell-pointer array. +** +** When this function is called, *ppData points to the start of the +** content area on page pPg. If the size of the content area is extended, +** *ppData is updated to point to the new start of the content area +** before returning. +** +** Finally, argument pBegin points to the byte immediately following the +** end of the space required by this page for the cell-pointer area (for +** all cells - not just those inserted by the current call). If the content +** area must be extended to before this point in order to accomodate all +** cells in apCell[], then the cells do not fit and non-zero is returned. +*/ +static int pageInsertArray( + MemPage *pPg, /* Page to add cells to */ + u8 *pBegin, /* End of cell-pointer array */ + u8 **ppData, /* IN/OUT: Page content -area pointer */ + u8 *pCellptr, /* Pointer to cell-pointer area */ + int iFirst, /* Index of first cell to add */ + int nCell, /* Number of cells to add to pPg */ + CellArray *pCArray /* Array of cells */ +){ + int i; + u8 *aData = pPg->aData; + u8 *pData = *ppData; + int iEnd = iFirst + nCell; + assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */ + for(i=iFirst; iapCell[i] will never overlap on a well-formed + ** database. But they might for a corrupt database. Hence use memmove() + ** since memcpy() sends SIGABORT with overlapping buffers on OpenBSD */ + assert( (pSlot+sz)<=pCArray->apCell[i] + || pSlot>=(pCArray->apCell[i]+sz) + || CORRUPT_DB ); + memmove(pSlot, pCArray->apCell[i], sz); + put2byte(pCellptr, (pSlot - aData)); + pCellptr += 2; + } + *ppData = pData; + return 0; +} + +/* +** Array apCell[] contains nCell pointers to b-tree cells. Array szCell +** contains the size in bytes of each such cell. This function adds the +** space associated with each cell in the array that is currently stored +** within the body of pPg to the pPg free-list. The cell-pointers and other +** fields of the page are not updated. +** +** This function returns the total number of cells added to the free-list. +*/ +static int pageFreeArray( + MemPage *pPg, /* Page to edit */ + int iFirst, /* First cell to delete */ + int nCell, /* Cells to delete */ + CellArray *pCArray /* Array of cells */ +){ + u8 * const aData = pPg->aData; + u8 * const pEnd = &aData[pPg->pBt->usableSize]; + u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; + int nRet = 0; + int i; + int iEnd = iFirst + nCell; + u8 *pFree = 0; + int szFree = 0; + + for(i=iFirst; iapCell[i]; + if( SQLITE_WITHIN(pCell, pStart, pEnd) ){ + int sz; + /* No need to use cachedCellSize() here. The sizes of all cells that + ** are to be freed have already been computing while deciding which + ** cells need freeing */ + sz = pCArray->szCell[i]; assert( sz>0 ); + if( pFree!=(pCell + sz) ){ + if( pFree ){ + assert( pFree>aData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } + pFree = pCell; + szFree = sz; + if( pFree+sz>pEnd ) return 0; + }else{ + pFree = pCell; + szFree += sz; + } + nRet++; + } + } + if( pFree ){ + assert( pFree>aData && (pFree - aData)<65536 ); + freeSpace(pPg, (u16)(pFree - aData), szFree); + } + return nRet; +} + +/* +** apCell[] and szCell[] contains pointers to and sizes of all cells in the +** pages being balanced. The current page, pPg, has pPg->nCell cells starting +** with apCell[iOld]. After balancing, this page should hold nNew cells +** starting at apCell[iNew]. +** +** This routine makes the necessary adjustments to pPg so that it contains +** the correct cells after being balanced. +** +** The pPg->nFree field is invalid when this function returns. It is the +** responsibility of the caller to set it correctly. +*/ +static int editPage( + MemPage *pPg, /* Edit this page */ + int iOld, /* Index of first cell currently on page */ + int iNew, /* Index of new first cell on page */ + int nNew, /* Final number of cells on page */ + CellArray *pCArray /* Array of cells and sizes */ +){ + u8 * const aData = pPg->aData; + const int hdr = pPg->hdrOffset; + u8 *pBegin = &pPg->aCellIdx[nNew * 2]; + int nCell = pPg->nCell; /* Cells stored on pPg */ + u8 *pData; + u8 *pCellptr; + int i; + int iOldEnd = iOld + pPg->nCell + pPg->nOverflow; + int iNewEnd = iNew + nNew; + +#ifdef SQLITE_DEBUG + u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); + memcpy(pTmp, aData, pPg->pBt->usableSize); +#endif + + /* Remove cells from the start and end of the page */ + if( iOldaCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); + nCell -= nShift; + } + if( iNewEnd < iOldEnd ){ + nCell -= pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); + } + + pData = &aData[get2byteNotZero(&aData[hdr+5])]; + if( pDataaCellIdx; + memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + iNew, nAdd, pCArray + ) ) goto editpage_fail; + nCell += nAdd; + } + + /* Add any overflow cells */ + for(i=0; inOverflow; i++){ + int iCell = (iOld + pPg->aiOvfl[i]) - iNew; + if( iCell>=0 && iCellaCellIdx[iCell * 2]; + memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + nCell++; + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + iCell+iNew, 1, pCArray + ) ) goto editpage_fail; + } + } + + /* Append cells to the end of the page */ + pCellptr = &pPg->aCellIdx[nCell*2]; + if( pageInsertArray( + pPg, pBegin, &pData, pCellptr, + iNew+nCell, nNew-nCell, pCArray + ) ) goto editpage_fail; + + pPg->nCell = nNew; + pPg->nOverflow = 0; + + put2byte(&aData[hdr+3], pPg->nCell); + put2byte(&aData[hdr+5], pData - aData); + +#ifdef SQLITE_DEBUG + for(i=0; iapCell[i+iNew]; + int iOff = get2byteAligned(&pPg->aCellIdx[i*2]); + if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){ + pCell = &pTmp[pCell - aData]; + } + assert( 0==memcmp(pCell, &aData[iOff], + pCArray->pRef->xCellSize(pCArray->pRef, pCArray->apCell[i+iNew])) ); + } +#endif + + return SQLITE_OK; + editpage_fail: + /* Unable to edit this page. Rebuild it from scratch instead. */ + populateCellCache(pCArray, iNew, nNew); + return rebuildPage(pPg, nNew, &pCArray->apCell[iNew], &pCArray->szCell[iNew]); +} + +/* +** The following parameters determine how many adjacent pages get involved +** in a balancing operation. NN is the number of neighbors on either side +** of the page that participate in the balancing operation. NB is the +** total number of pages that participate, including the target page and +** NN neighbors on either side. +** +** The minimum value of NN is 1 (of course). Increasing NN above 1 +** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance +** in exchange for a larger degradation in INSERT and UPDATE performance. +** The value of NN appears to give the best results overall. +*/ +#define NN 1 /* Number of neighbors on either side of pPage */ +#define NB (NN*2+1) /* Total pages involved in the balance */ + + +#ifndef SQLITE_OMIT_QUICKBALANCE +/* +** This version of balance() handles the common special case where +** a new entry is being inserted on the extreme right-end of the +** tree, in other words, when the new entry will become the largest +** entry in the tree. +** +** Instead of trying to balance the 3 right-most leaf pages, just add +** a new page to the right-hand side and put the one new entry in +** that page. This leaves the right side of the tree somewhat +** unbalanced. But odds are that we will be inserting new entries +** at the end soon afterwards so the nearly empty page will quickly +** fill up. On average. +** +** pPage is the leaf page which is the right-most page in the tree. +** pParent is its parent. pPage must have a single overflow entry +** which is also the right-most entry on the page. +** +** The pSpace buffer is used to store a temporary copy of the divider +** cell that will be inserted into pParent. Such a cell consists of a 4 +** byte page number followed by a variable length integer. In other +** words, at most 13 bytes. Hence the pSpace buffer must be at +** least 13 bytes in size. +*/ +static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ + BtShared *const pBt = pPage->pBt; /* B-Tree Database */ + MemPage *pNew; /* Newly allocated page */ + int rc; /* Return Code */ + Pgno pgnoNew; /* Page number of pNew */ + + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + assert( pPage->nOverflow==1 ); + + /* This error condition is now caught prior to reaching this function */ + if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT; + + /* Allocate a new page. This page will become the right-sibling of + ** pPage. Make the parent page writable, so that the new divider cell + ** may be inserted. If both these operations are successful, proceed. + */ + rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); + + if( rc==SQLITE_OK ){ + + u8 *pOut = &pSpace[4]; + u8 *pCell = pPage->apOvfl[0]; + u16 szCell = pPage->xCellSize(pPage, pCell); + u8 *pStop; + + assert( sqlite3PagerIswriteable(pNew->pDbPage) ); + assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); + zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF); + rc = rebuildPage(pNew, 1, &pCell, &szCell); + if( NEVER(rc) ) return rc; + pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; + + /* If this is an auto-vacuum database, update the pointer map + ** with entries for the new page, and any pointer from the + ** cell on the page to an overflow page. If either of these + ** operations fails, the return code is set, but the contents + ** of the parent page are still manipulated by thh code below. + ** That is Ok, at this point the parent page is guaranteed to + ** be marked as dirty. Returning an error code will cause a + ** rollback, undoing any changes made to the parent page. + */ + if( ISAUTOVACUUM ){ + ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc); + if( szCell>pNew->minLocal ){ + ptrmapPutOvflPtr(pNew, pCell, &rc); + } + } + + /* Create a divider cell to insert into pParent. The divider cell + ** consists of a 4-byte page number (the page number of pPage) and + ** a variable length key value (which must be the same value as the + ** largest key on pPage). + ** + ** To find the largest key value on pPage, first find the right-most + ** cell on pPage. The first two fields of this cell are the + ** record-length (a variable length integer at most 32-bits in size) + ** and the key value (a variable length integer, may have any value). + ** The first of the while(...) loops below skips over the record-length + ** field. The second while(...) loop copies the key value from the + ** cell on pPage into the pSpace buffer. + */ + pCell = findCell(pPage, pPage->nCell-1); + pStop = &pCell[9]; + while( (*(pCell++)&0x80) && pCellnCell, pSpace, (int)(pOut-pSpace), + 0, pPage->pgno, &rc); + } + + /* Set the right-child pointer of pParent to point to the new page. */ + put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); + + /* Release the reference to the new page. */ + releasePage(pNew); + } + + return rc; +} +#endif /* SQLITE_OMIT_QUICKBALANCE */ + +#if 0 +/* +** This function does not contribute anything to the operation of SQLite. +** it is sometimes activated temporarily while debugging code responsible +** for setting pointer-map entries. +*/ +static int ptrmapCheckPages(MemPage **apPage, int nPage){ + int i, j; + for(i=0; ipBt; + assert( pPage->isInit ); + + for(j=0; jnCell; j++){ + CellInfo info; + u8 *z; + + z = findCell(pPage, j); + pPage->xParseCell(pPage, z, &info); + if( info.nLocalpgno && e==PTRMAP_OVERFLOW1 ); + } + if( !pPage->leaf ){ + Pgno child = get4byte(z); + ptrmapGet(pBt, child, &e, &n); + assert( n==pPage->pgno && e==PTRMAP_BTREE ); + } + } + if( !pPage->leaf ){ + Pgno child = get4byte(&pPage->aData[pPage->hdrOffset+8]); + ptrmapGet(pBt, child, &e, &n); + assert( n==pPage->pgno && e==PTRMAP_BTREE ); + } + } + return 1; +} +#endif + +/* +** This function is used to copy the contents of the b-tree node stored +** on page pFrom to page pTo. If page pFrom was not a leaf page, then +** the pointer-map entries for each child page are updated so that the +** parent page stored in the pointer map is page pTo. If pFrom contained +** any cells with overflow page pointers, then the corresponding pointer +** map entries are also updated so that the parent page is page pTo. +** +** If pFrom is currently carrying any overflow cells (entries in the +** MemPage.apOvfl[] array), they are not copied to pTo. +** +** Before returning, page pTo is reinitialized using btreeInitPage(). +** +** The performance of this function is not critical. It is only used by +** the balance_shallower() and balance_deeper() procedures, neither of +** which are called often under normal circumstances. +*/ +static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ + if( (*pRC)==SQLITE_OK ){ + BtShared * const pBt = pFrom->pBt; + u8 * const aFrom = pFrom->aData; + u8 * const aTo = pTo->aData; + int const iFromHdr = pFrom->hdrOffset; + int const iToHdr = ((pTo->pgno==1) ? 100 : 0); + int rc; + int iData; + + + assert( pFrom->isInit ); + assert( pFrom->nFree>=iToHdr ); + assert( get2byte(&aFrom[iFromHdr+5]) <= (int)pBt->usableSize ); + + /* Copy the b-tree node content from page pFrom to page pTo. */ + iData = get2byte(&aFrom[iFromHdr+5]); + memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData); + memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell); + + /* Reinitialize page pTo so that the contents of the MemPage structure + ** match the new data. The initialization of pTo can actually fail under + ** fairly obscure circumstances, even though it is a copy of initialized + ** page pFrom. + */ + pTo->isInit = 0; + rc = btreeInitPage(pTo); + if( rc!=SQLITE_OK ){ + *pRC = rc; + return; + } + + /* If this is an auto-vacuum database, update the pointer-map entries + ** for any b-tree or overflow pages that pTo now contains the pointers to. + */ + if( ISAUTOVACUUM ){ + *pRC = setChildPtrmaps(pTo); + } + } +} + +/* +** This routine redistributes cells on the iParentIdx'th child of pParent +** (hereafter "the page") and up to 2 siblings so that all pages have about the +** same amount of free space. Usually a single sibling on either side of the +** page are used in the balancing, though both siblings might come from one +** side if the page is the first or last child of its parent. If the page +** has fewer than 2 siblings (something which can only happen if the page +** is a root page or a child of a root page) then all available siblings +** participate in the balancing. +** +** The number of siblings of the page might be increased or decreased by +** one or two in an effort to keep pages nearly full but not over full. +** +** Note that when this routine is called, some of the cells on the page +** might not actually be stored in MemPage.aData[]. This can happen +** if the page is overfull. This routine ensures that all cells allocated +** to the page and its siblings fit into MemPage.aData[] before returning. +** +** In the course of balancing the page and its siblings, cells may be +** inserted into or removed from the parent page (pParent). Doing so +** may cause the parent page to become overfull or underfull. If this +** happens, it is the responsibility of the caller to invoke the correct +** balancing routine to fix this problem (see the balance() routine). +** +** If this routine fails for any reason, it might leave the database +** in a corrupted state. So if this routine fails, the database should +** be rolled back. +** +** The third argument to this function, aOvflSpace, is a pointer to a +** buffer big enough to hold one page. If while inserting cells into the parent +** page (pParent) the parent page becomes overfull, this buffer is +** used to store the parent's overflow cells. Because this function inserts +** a maximum of four divider cells into the parent page, and the maximum +** size of a cell stored within an internal node is always less than 1/4 +** of the page-size, the aOvflSpace[] buffer is guaranteed to be large +** enough for all overflow cells. +** +** If aOvflSpace is set to a null pointer, this function returns +** SQLITE_NOMEM. +*/ +static int balance_nonroot( + MemPage *pParent, /* Parent page of siblings being balanced */ + int iParentIdx, /* Index of "the page" in pParent */ + u8 *aOvflSpace, /* page-size bytes of space for parent ovfl */ + int isRoot, /* True if pParent is a root-page */ + int bBulk /* True if this call is part of a bulk load */ +){ + BtShared *pBt; /* The whole database */ + int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ + int nNew = 0; /* Number of pages in apNew[] */ + int nOld; /* Number of pages in apOld[] */ + int i, j, k; /* Loop counters */ + int nxDiv; /* Next divider slot in pParent->aCell[] */ + int rc = SQLITE_OK; /* The return code */ + u16 leafCorrection; /* 4 if pPage is a leaf. 0 if not */ + int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ + int usableSpace; /* Bytes in pPage beyond the header */ + int pageFlags; /* Value of pPage->aData[0] */ + int iSpace1 = 0; /* First unused byte of aSpace1[] */ + int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ + int szScratch; /* Size of scratch memory requested */ + MemPage *apOld[NB]; /* pPage and up to two siblings */ + MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ + u8 *pRight; /* Location in parent of right-sibling pointer */ + u8 *apDiv[NB-1]; /* Divider cells in pParent */ + int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */ + int cntOld[NB+2]; /* Old index in b.apCell[] */ + int szNew[NB+2]; /* Combined size of cells placed on i-th page */ + u8 *aSpace1; /* Space for copies of dividers cells */ + Pgno pgno; /* Temp var to store a page number in */ + u8 abDone[NB+2]; /* True after i'th new page is populated */ + Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ + Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ + u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ + CellArray b; /* Parsed information on cells being balanced */ + + memset(abDone, 0, sizeof(abDone)); + b.nCell = 0; + b.apCell = 0; + pBt = pParent->pBt; + assert( sqlite3_mutex_held(pBt->mutex) ); + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + +#if 0 + TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); +#endif + + /* At this point pParent may have at most one overflow cell. And if + ** this overflow cell is present, it must be the cell with + ** index iParentIdx. This scenario comes about when this function + ** is called (indirectly) from sqlite3BtreeDelete(). + */ + assert( pParent->nOverflow==0 || pParent->nOverflow==1 ); + assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx ); + + if( !aOvflSpace ){ + return SQLITE_NOMEM_BKPT; + } + + /* Find the sibling pages to balance. Also locate the cells in pParent + ** that divide the siblings. An attempt is made to find NN siblings on + ** either side of pPage. More siblings are taken from one side, however, + ** if there are fewer than NN siblings on the other side. If pParent + ** has NB or fewer children then all children of pParent are taken. + ** + ** This loop also drops the divider cells from the parent page. This + ** way, the remainder of the function does not have to deal with any + ** overflow cells in the parent page, since if any existed they will + ** have already been removed. + */ + i = pParent->nOverflow + pParent->nCell; + if( i<2 ){ + nxDiv = 0; + }else{ + assert( bBulk==0 || bBulk==1 ); + if( iParentIdx==0 ){ + nxDiv = 0; + }else if( iParentIdx==i ){ + nxDiv = i-2+bBulk; + }else{ + nxDiv = iParentIdx-1; + } + i = 2-bBulk; + } + nOld = i+1; + if( (i+nxDiv-pParent->nOverflow)==pParent->nCell ){ + pRight = &pParent->aData[pParent->hdrOffset+8]; + }else{ + pRight = findCell(pParent, i+nxDiv-pParent->nOverflow); + } + pgno = get4byte(pRight); + while( 1 ){ + rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); + if( rc ){ + memset(apOld, 0, (i+1)*sizeof(MemPage*)); + goto balance_cleanup; + } + nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; + if( (i--)==0 ) break; + + if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ + apDiv[i] = pParent->apOvfl[0]; + pgno = get4byte(apDiv[i]); + szNew[i] = pParent->xCellSize(pParent, apDiv[i]); + pParent->nOverflow = 0; + }else{ + apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow); + pgno = get4byte(apDiv[i]); + szNew[i] = pParent->xCellSize(pParent, apDiv[i]); + + /* Drop the cell from the parent page. apDiv[i] still points to + ** the cell within the parent, even though it has been dropped. + ** This is safe because dropping a cell only overwrites the first + ** four bytes of it, and this function does not need the first + ** four bytes of the divider cell. So the pointer is safe to use + ** later on. + ** + ** But not if we are in secure-delete mode. In secure-delete mode, + ** the dropCell() routine will overwrite the entire cell with zeroes. + ** In this case, temporarily copy the cell into the aOvflSpace[] + ** buffer. It will be copied out again as soon as the aSpace[] buffer + ** is allocated. */ + if( pBt->btsFlags & BTS_SECURE_DELETE ){ + int iOff; + + iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); + if( (iOff+szNew[i])>(int)pBt->usableSize ){ + rc = SQLITE_CORRUPT_BKPT; + memset(apOld, 0, (i+1)*sizeof(MemPage*)); + goto balance_cleanup; + }else{ + memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]); + apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData]; + } + } + dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc); + } + } + + /* Make nMaxCells a multiple of 4 in order to preserve 8-byte + ** alignment */ + nMaxCells = (nMaxCells + 3)&~3; + + /* + ** Allocate space for memory structures + */ + szScratch = + nMaxCells*sizeof(u8*) /* b.apCell */ + + 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 ); + if( b.apCell==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto balance_cleanup; + } + b.szCell = (u16*)&b.apCell[nMaxCells]; + aSpace1 = (u8*)&b.szCell[nMaxCells]; + assert( EIGHT_BYTE_ALIGNMENT(aSpace1) ); + + /* + ** Load pointers to all cells on sibling pages and the divider cells + ** into the local b.apCell[] array. Make copies of the divider cells + ** into space obtained from aSpace1[]. The divider cells have already + ** been removed from pParent. + ** + ** If the siblings are on leaf pages, then the child pointers of the + ** divider cells are stripped from the cells before they are copied + ** into aSpace1[]. In this way, all cells in b.apCell[] are without + ** child pointers. If siblings are not leaves, then all cell in + ** b.apCell[] include child pointers. Either way, all cells in b.apCell[] + ** are alike. + ** + ** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf. + ** leafData: 1 if pPage holds key+data and pParent holds only keys. + */ + b.pRef = apOld[0]; + leafCorrection = b.pRef->leaf*4; + leafData = b.pRef->intKeyLeaf; + for(i=0; inCell; + u8 *aData = pOld->aData; + u16 maskPage = pOld->maskPage; + u8 *piCell = aData + pOld->cellOffset; + u8 *piEnd; + + /* Verify that all sibling pages are of the same "type" (table-leaf, + ** table-interior, index-leaf, or index-interior). + */ + if( pOld->aData[0]!=apOld[0]->aData[0] ){ + rc = SQLITE_CORRUPT_BKPT; + goto balance_cleanup; + } + + /* Load b.apCell[] with pointers to all cells in pOld. If pOld + ** constains overflow cells, include them in the b.apCell[] array + ** in the correct spot. + ** + ** Note that when there are multiple overflow cells, it is always the + ** case that they are sequential and adjacent. This invariant arises + ** because multiple overflows can only occurs when inserting divider + ** cells into a parent on a prior balance, and divider cells are always + ** adjacent and are inserted in order. There is an assert() tagged + ** with "NOTE 1" in the overflow cell insertion loop to prove this + ** invariant. + ** + ** This must be done in advance. Once the balance starts, the cell + ** offset section of the btree page will be overwritten and we will no + ** long be able to find the cells if a pointer to each cell is not saved + ** first. + */ + memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); + if( pOld->nOverflow>0 ){ + limit = pOld->aiOvfl[0]; + for(j=0; jnOverflow; k++){ + assert( k==0 || pOld->aiOvfl[k-1]+1==pOld->aiOvfl[k] );/* NOTE 1 */ + b.apCell[b.nCell] = pOld->apOvfl[k]; + b.nCell++; + } + } + piEnd = aData + pOld->cellOffset + 2*pOld->nCell; + while( piCellmaxLocal+23 ); + assert( iSpace1 <= (int)pBt->pageSize ); + memcpy(pTemp, apDiv[i], sz); + b.apCell[b.nCell] = pTemp+leafCorrection; + assert( leafCorrection==0 || leafCorrection==4 ); + b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection; + if( !pOld->leaf ){ + assert( leafCorrection==0 ); + assert( pOld->hdrOffset==0 ); + /* The right pointer of the child page pOld becomes the left + ** pointer of the divider cell */ + memcpy(b.apCell[b.nCell], &pOld->aData[8], 4); + }else{ + assert( leafCorrection==4 ); + while( b.szCell[b.nCell]<4 ){ + /* Do not allow any cells smaller than 4 bytes. If a smaller cell + ** does exist, pad it with 0x00 bytes. */ + assert( b.szCell[b.nCell]==3 || CORRUPT_DB ); + assert( b.apCell[b.nCell]==&aSpace1[iSpace1-3] || CORRUPT_DB ); + aSpace1[iSpace1++] = 0x00; + b.szCell[b.nCell]++; + } + } + b.nCell++; + } + } + + /* + ** Figure out the number of pages needed to hold all b.nCell cells. + ** Store this number in "k". Also compute szNew[] which is the total + ** size of all cells on the i-th page and cntNew[] which is the index + ** in b.apCell[] of the cell that divides page i from page i+1. + ** cntNew[k] should equal b.nCell. + ** + ** Values computed by this block: + ** + ** k: The total number of sibling pages + ** szNew[i]: Spaced used on the i-th sibling page. + ** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to + ** the right of the i-th sibling page. + ** usableSpace: Number of bytes of space available on each sibling. + ** + */ + usableSpace = pBt->usableSize - 12 + leafCorrection; + for(i=0; inFree; + for(j=0; jnOverflow; j++){ + szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); + } + cntNew[i] = cntOld[i]; + } + k = nOld; + for(i=0; iusableSpace ){ + if( i+1>=k ){ + k = i+2; + if( k>NB+2 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } + szNew[k-1] = 0; + cntNew[k-1] = b.nCell; + } + sz = 2 + cachedCellSize(&b, cntNew[i]-1); + szNew[i] -= sz; + if( !leafData ){ + if( cntNew[i]usableSpace ) break; + szNew[i] += sz; + cntNew[i]++; + if( !leafData ){ + if( cntNew[i]=b.nCell ){ + k = i+1; + }else if( cntNew[i] <= (i>0 ? cntNew[i-1] : 0) ){ + rc = SQLITE_CORRUPT_BKPT; + goto balance_cleanup; + } + } + + /* + ** The packing computed by the previous block is biased toward the siblings + ** on the left side (siblings with smaller keys). The left siblings are + ** always nearly full, while the right-most sibling might be nearly empty. + ** The next block of code attempts to adjust the packing of siblings to + ** get a better balance. + ** + ** This adjustment is more than an optimization. The packing above might + ** be so out of balance as to be illegal. For example, the right-most + ** sibling might be completely empty. This adjustment is not optional. + */ + for(i=k-1; i>0; i--){ + int szRight = szNew[i]; /* Size of sibling on the right */ + int szLeft = szNew[i-1]; /* Size of sibling on the left */ + int r; /* Index of right-most cell in left sibling */ + int d; /* Index of first cell to the left of right sibling */ + + r = cntNew[i-1] - 1; + d = r + 1 - leafData; + (void)cachedCellSize(&b, d); + do{ + assert( d szLeft-(b.szCell[r]+(i==k-1?0:2)))){ + break; + } + szRight += b.szCell[d] + 2; + szLeft -= b.szCell[r] + 2; + cntNew[i-1] = r; + r--; + d--; + }while( r>=0 ); + szNew[i] = szRight; + szNew[i-1] = szLeft; + if( cntNew[i-1] <= (i>1 ? cntNew[i-2] : 0) ){ + rc = SQLITE_CORRUPT_BKPT; + goto balance_cleanup; + } + } + + /* Sanity check: For a non-corrupt database file one of the follwing + ** must be true: + ** (1) We found one or more cells (cntNew[0])>0), or + ** (2) pPage is a virtual root page. A virtual root page is when + ** the real root page is page 1 and we are the only child of + ** that page. + */ + assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB); + TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n", + apOld[0]->pgno, apOld[0]->nCell, + nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0, + nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0 + )); + + /* + ** Allocate k new pages. Reuse old pages where possible. + */ + pageFlags = apOld[0]->aData[0]; + for(i=0; ipDbPage); + nNew++; + if( rc ) goto balance_cleanup; + }else{ + assert( i>0 ); + rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); + if( rc ) goto balance_cleanup; + zeroPage(pNew, pageFlags); + apNew[i] = pNew; + nNew++; + cntOld[i] = b.nCell; + + /* Set the pointer-map entry for the new sibling page. */ + if( ISAUTOVACUUM ){ + ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc); + if( rc!=SQLITE_OK ){ + goto balance_cleanup; + } + } + } + } + + /* + ** Reassign page numbers so that the new pages are in ascending order. + ** This helps to keep entries in the disk file in order so that a scan + ** of the table is closer to a linear scan through the file. That in turn + ** helps the operating system to deliver pages from the disk more rapidly. + ** + ** An O(n^2) insertion sort algorithm is used, but since n is never more + ** than (NB+2) (a small constant), that should not be a problem. + ** + ** When NB==3, this one optimization makes the database about 25% faster + ** for large insertions and deletions. + */ + for(i=0; ipgno; + aPgFlags[i] = apNew[i]->pDbPage->flags; + for(j=0; ji ){ + sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0); + } + sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]); + apNew[i]->pgno = pgno; + } + } + + TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) " + "%d(%d nc=%d) %d(%d nc=%d)\n", + apNew[0]->pgno, szNew[0], cntNew[0], + nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0, + nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0, + nNew>=3 ? apNew[2]->pgno : 0, nNew>=3 ? szNew[2] : 0, + nNew>=3 ? cntNew[2] - cntNew[1] - !leafData : 0, + nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0, + nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0, + nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0, + nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0 + )); + + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + put4byte(pRight, apNew[nNew-1]->pgno); + + /* If the sibling pages are not leaves, ensure that the right-child pointer + ** of the right-most new sibling page is set to the value that was + ** originally in the same field of the right-most old sibling page. */ + if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ + MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; + memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4); + } + + /* Make any required updates to pointer map entries associated with + ** cells stored on sibling pages following the balance operation. Pointer + ** map entries associated with divider cells are set by the insertCell() + ** routine. The associated pointer map entries are: + ** + ** a) if the cell contains a reference to an overflow chain, the + ** entry associated with the first page in the overflow chain, and + ** + ** b) if the sibling pages are not leaves, the child page associated + ** with the cell. + ** + ** If the sibling pages are not leaves, then the pointer map entry + ** associated with the right-child of each sibling may also need to be + ** updated. This happens below, after the sibling pages have been + ** populated, not here. + */ + if( ISAUTOVACUUM ){ + MemPage *pNew = apNew[0]; + u8 *aOld = pNew->aData; + int cntOldNext = pNew->nCell + pNew->nOverflow; + int usableSize = pBt->usableSize; + int iNew = 0; + int iOld = 0; + + for(i=0; inCell + pOld->nOverflow + !leafData; + aOld = pOld->aData; + } + if( i==cntNew[iNew] ){ + pNew = apNew[++iNew]; + if( !leafData ) continue; + } + + /* Cell pCell is destined for new sibling page pNew. Originally, it + ** was either part of sibling page iOld (possibly an overflow cell), + ** or else the divider cell to the left of sibling page iOld. So, + ** if sibling page iOld had the same page number as pNew, and if + ** pCell really was a part of sibling page iOld (not a divider or + ** overflow cell), we can skip updating the pointer map entries. */ + if( iOld>=nNew + || pNew->pgno!=aPgno[iOld] + || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize]) + ){ + if( !leafCorrection ){ + ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); + } + if( cachedCellSize(&b,i)>pNew->minLocal ){ + ptrmapPutOvflPtr(pNew, pCell, &rc); + } + if( rc ) goto balance_cleanup; + } + } + } + + /* Insert new divider cells into pParent. */ + for(i=0; ileaf ){ + memcpy(&pNew->aData[8], pCell, 4); + }else if( leafData ){ + /* If the tree is a leaf-data tree, and the siblings are leaves, + ** then there is no divider cell in b.apCell[]. Instead, the divider + ** cell consists of the integer key for the right-most cell of + ** the sibling-page assembled above only. + */ + CellInfo info; + j--; + pNew->xParseCell(pNew, b.apCell[j], &info); + pCell = pTemp; + sz = 4 + putVarint(&pCell[4], info.nKey); + pTemp = 0; + }else{ + pCell -= 4; + /* Obscure case for non-leaf-data trees: If the cell at pCell was + ** previously stored on a leaf node, and its reported size was 4 + ** bytes, then it may actually be smaller than this + ** (see btreeParseCellPtr(), 4 bytes is the minimum size of + ** any cell). But it is important to pass the correct size to + ** insertCell(), so reparse the cell now. + ** + ** This can only happen for b-trees used to evaluate "IN (SELECT ...)" + ** and WITHOUT ROWID tables with exactly one column which is the + ** primary key. + */ + if( b.szCell[j]==4 ){ + assert(leafCorrection==4); + sz = pParent->xCellSize(pParent, pCell); + } + } + iOvflSpace += sz; + assert( sz<=pBt->maxLocal+23 ); + assert( iOvflSpace <= (int)pBt->pageSize ); + insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc); + if( rc!=SQLITE_OK ) goto balance_cleanup; + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + } + + /* Now update the actual sibling pages. The order in which they are updated + ** is important, as this code needs to avoid disrupting any page from which + ** cells may still to be read. In practice, this means: + ** + ** (1) If cells are moving left (from apNew[iPg] to apNew[iPg-1]) + ** then it is not safe to update page apNew[iPg] until after + ** the left-hand sibling apNew[iPg-1] has been updated. + ** + ** (2) If cells are moving right (from apNew[iPg] to apNew[iPg+1]) + ** then it is not safe to update page apNew[iPg] until after + ** the right-hand sibling apNew[iPg+1] has been updated. + ** + ** If neither of the above apply, the page is safe to update. + ** + ** The iPg value in the following loop starts at nNew-1 goes down + ** to 0, then back up to nNew-1 again, thus making two passes over + ** the pages. On the initial downward pass, only condition (1) above + ** needs to be tested because (2) will always be true from the previous + ** step. On the upward pass, both conditions are always true, so the + ** upwards pass simply processes pages that were missed on the downward + ** pass. + */ + for(i=1-nNew; i=0 && iPg=0 /* On the upwards pass, or... */ + || cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */ + ){ + int iNew; + int iOld; + int nNewCell; + + /* Verify condition (1): If cells are moving left, update iPg + ** only after iPg-1 has already been updated. */ + assert( iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1] ); + + /* Verify condition (2): If cells are moving right, update iPg + ** only after iPg+1 has already been updated. */ + assert( cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1] ); + + if( iPg==0 ){ + iNew = iOld = 0; + nNewCell = cntNew[0]; + }else{ + iOld = iPgnFree = usableSpace-szNew[iPg]; + assert( apNew[iPg]->nOverflow==0 ); + assert( apNew[iPg]->nCell==nNewCell ); + } + } + + /* All pages have been processed exactly once */ + assert( memcmp(abDone, "\01\01\01\01\01", nNew)==0 ); + + assert( nOld>0 ); + assert( nNew>0 ); + + if( isRoot && pParent->nCell==0 && pParent->hdrOffset<=apNew[0]->nFree ){ + /* The root page of the b-tree now contains no cells. The only sibling + ** page is the right-child of the parent. Copy the contents of the + ** child page into the parent, decreasing the overall height of the + ** b-tree structure by one. This is described as the "balance-shallower" + ** sub-algorithm in some documentation. + ** + ** If this is an auto-vacuum database, the call to copyNodeContent() + ** sets all pointer-map entries corresponding to database image pages + ** for which the pointer is stored within the content being copied. + ** + ** It is critical that the child page be defragmented before being + ** copied into the parent, because if the parent is page 1 then it will + ** by smaller than the child due to the database header, and so all the + ** free space needs to be up front. + */ + assert( nNew==1 || CORRUPT_DB ); + rc = defragmentPage(apNew[0], -1); + testcase( rc!=SQLITE_OK ); + assert( apNew[0]->nFree == + (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) + || rc!=SQLITE_OK + ); + copyNodeContent(apNew[0], pParent, &rc); + freePage(apNew[0], &rc); + }else if( ISAUTOVACUUM && !leafCorrection ){ + /* Fix the pointer map entries associated with the right-child of each + ** sibling page. All other pointer map entries have already been taken + ** care of. */ + for(i=0; iaData[8]); + ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); + } + } + + assert( pParent->isInit ); + TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", + nOld, nNew, b.nCell)); + + /* Free any old pages that were not reused as new pages. + */ + for(i=nNew; iisInit ){ + /* The ptrmapCheckPages() contains assert() statements that verify that + ** all pointer map pages are set correctly. This is helpful while + ** debugging. This is usually disabled because a corrupt database may + ** cause an assert() statement to fail. */ + ptrmapCheckPages(apNew, nNew); + ptrmapCheckPages(&pParent, 1); + } +#endif + + /* + ** Cleanup before returning. + */ +balance_cleanup: + sqlite3ScratchFree(b.apCell); + for(i=0; ipBt; /* The BTree */ + + assert( pRoot->nOverflow>0 ); + assert( sqlite3_mutex_held(pBt->mutex) ); + + /* Make pRoot, the root page of the b-tree, writable. Allocate a new + ** page that will become the new right-child of pPage. Copy the contents + ** of the node stored on pRoot into the new child page. + */ + rc = sqlite3PagerWrite(pRoot->pDbPage); + if( rc==SQLITE_OK ){ + rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0); + copyNodeContent(pRoot, pChild, &rc); + if( ISAUTOVACUUM ){ + ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc); + } + } + if( rc ){ + *ppChild = 0; + releasePage(pChild); + return rc; + } + assert( sqlite3PagerIswriteable(pChild->pDbPage) ); + assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); + assert( pChild->nCell==pRoot->nCell ); + + TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno)); + + /* Copy the overflow cells from pRoot to pChild */ + memcpy(pChild->aiOvfl, pRoot->aiOvfl, + pRoot->nOverflow*sizeof(pRoot->aiOvfl[0])); + memcpy(pChild->apOvfl, pRoot->apOvfl, + pRoot->nOverflow*sizeof(pRoot->apOvfl[0])); + pChild->nOverflow = pRoot->nOverflow; + + /* Zero the contents of pRoot. Then install pChild as the right-child. */ + zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF); + put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild); + + *ppChild = pChild; + return SQLITE_OK; +} + +/* +** The page that pCur currently points to has just been modified in +** some way. This function figures out if this modification means the +** tree needs to be balanced, and if so calls the appropriate balancing +** routine. Balancing routines are: +** +** balance_quick() +** balance_deeper() +** balance_nonroot() +*/ +static int balance(BtCursor *pCur){ + int rc = SQLITE_OK; + const int nMin = pCur->pBt->usableSize * 2 / 3; + u8 aBalanceQuickSpace[13]; + u8 *pFree = 0; + + VVA_ONLY( int balance_quick_called = 0 ); + VVA_ONLY( int balance_deeper_called = 0 ); + + do { + int iPage = pCur->iPage; + MemPage *pPage = pCur->apPage[iPage]; + + if( iPage==0 ){ + if( pPage->nOverflow ){ + /* The root page of the b-tree is overfull. In this case call the + ** balance_deeper() function to create a new child for the root-page + ** and copy the current contents of the root-page to it. The + ** next iteration of the do-loop will balance the child page. + */ + assert( balance_deeper_called==0 ); + VVA_ONLY( balance_deeper_called++ ); + rc = balance_deeper(pPage, &pCur->apPage[1]); + if( rc==SQLITE_OK ){ + pCur->iPage = 1; + pCur->ix = 0; + pCur->aiIdx[0] = 0; + assert( pCur->apPage[1]->nOverflow ); + } + }else{ + break; + } + }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ + break; + }else{ + MemPage * const pParent = pCur->apPage[iPage-1]; + int const iIdx = pCur->aiIdx[iPage-1]; + + rc = sqlite3PagerWrite(pParent->pDbPage); + if( rc==SQLITE_OK ){ +#ifndef SQLITE_OMIT_QUICKBALANCE + if( pPage->intKeyLeaf + && pPage->nOverflow==1 + && pPage->aiOvfl[0]==pPage->nCell + && pParent->pgno!=1 + && pParent->nCell==iIdx + ){ + /* Call balance_quick() to create a new sibling of pPage on which + ** to store the overflow cell. balance_quick() inserts a new cell + ** into pParent, which may cause pParent overflow. If this + ** happens, the next iteration of the do-loop will balance pParent + ** use either balance_nonroot() or balance_deeper(). Until this + ** happens, the overflow cell is stored in the aBalanceQuickSpace[] + ** buffer. + ** + ** The purpose of the following assert() is to check that only a + ** single call to balance_quick() is made for each call to this + ** function. If this were not verified, a subtle bug involving reuse + ** of the aBalanceQuickSpace[] might sneak in. + */ + assert( balance_quick_called==0 ); + VVA_ONLY( balance_quick_called++ ); + rc = balance_quick(pParent, pPage, aBalanceQuickSpace); + }else +#endif + { + /* In this case, call balance_nonroot() to redistribute cells + ** between pPage and up to 2 of its sibling pages. This involves + ** modifying the contents of pParent, which may cause pParent to + ** become overfull or underfull. The next iteration of the do-loop + ** will balance the parent page to correct this. + ** + ** If the parent page becomes overfull, the overflow cell or cells + ** are stored in the pSpace buffer allocated immediately below. + ** A subsequent iteration of the do-loop will deal with this by + ** calling balance_nonroot() (balance_deeper() may be called first, + ** but it doesn't deal with overflow cells - just moves them to a + ** different page). Once this subsequent call to balance_nonroot() + ** has completed, it is safe to release the pSpace buffer used by + ** the previous call, as the overflow cell data will have been + ** copied either into the body of a database page or into the new + ** pSpace buffer passed to the latter call to balance_nonroot(). + */ + u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize); + rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, + pCur->hints&BTREE_BULKLOAD); + if( pFree ){ + /* If pFree is not NULL, it points to the pSpace buffer used + ** by a previous call to balance_nonroot(). Its contents are + ** now stored either on real database pages or within the + ** new pSpace buffer, so it may be safely freed here. */ + sqlite3PageFree(pFree); + } + + /* The pSpace buffer will be freed after the next call to + ** balance_nonroot(), or just before this function returns, whichever + ** comes first. */ + pFree = pSpace; + } + } + + pPage->nOverflow = 0; + + /* The next iteration of the do-loop balances the parent page. */ + releasePage(pPage); + pCur->iPage--; + assert( pCur->iPage>=0 ); + } + }while( rc==SQLITE_OK ); + + if( pFree ){ + sqlite3PageFree(pFree); + } + return rc; +} + + +/* +** Insert a new record into the BTree. The content of the new record +** is described by the pX object. The pCur cursor is used only to +** define what table the record should be inserted into, and is left +** pointing at a random location. +** +** For a table btree (used for rowid tables), only the pX.nKey value of +** the key is used. The pX.pKey value must be NULL. The pX.nKey is the +** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields +** hold the content of the row. +** +** For an index btree (used for indexes and WITHOUT ROWID tables), the +** key is an arbitrary byte sequence stored in pX.pKey,nKey. The +** pX.pData,nData,nZero fields must be zero. +** +** If the seekResult parameter is non-zero, then a successful call to +** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already +** been performed. In other words, if seekResult!=0 then the cursor +** is currently pointing to a cell that will be adjacent to the cell +** to be inserted. If seekResult<0 then pCur points to a cell that is +** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell +** that is larger than (pKey,nKey). +** +** If seekResult==0, that means pCur is pointing at some unknown location. +** In that case, this routine must seek the cursor to the correct insertion +** point for (pKey,nKey) before doing the insertion. For index btrees, +** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked +** key values and pX->aMem can be used instead of pX->pKey to avoid having +** to decode the key. +*/ +SQLITE_PRIVATE int sqlite3BtreeInsert( + BtCursor *pCur, /* Insert data into the table of this cursor */ + const BtreePayload *pX, /* Content of the row to be inserted */ + int flags, /* True if this is likely an append */ + int seekResult /* Result of prior MovetoUnpacked() call */ +){ + int rc; + int loc = seekResult; /* -1: before desired location +1: after */ + int szNew = 0; + int idx; + MemPage *pPage; + Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; + unsigned char *oldCell; + unsigned char *newCell = 0; + + assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags ); + + if( pCur->eState==CURSOR_FAULT ){ + assert( pCur->skipNext!=SQLITE_OK ); + return pCur->skipNext; + } + + assert( cursorOwnsBtShared(pCur) ); + assert( (pCur->curFlags & BTCF_WriteFlag)!=0 + && pBt->inTransaction==TRANS_WRITE + && (pBt->btsFlags & BTS_READ_ONLY)==0 ); + assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); + + /* Assert that the caller has been consistent. If this cursor was opened + ** expecting an index b-tree, then the caller should be inserting blob + ** keys with no associated data. If the cursor was opened expecting an + ** intkey table, the caller should be inserting integer keys with a + ** blob of associated data. */ + assert( (pX->pKey==0)==(pCur->pKeyInfo==0) ); + + /* Save the positions of any other cursors open on this table. + ** + ** In some cases, the call to btreeMoveto() below is a no-op. For + ** example, when inserting data into a table with auto-generated integer + ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the + ** integer key to use. It then calls this function to actually insert the + ** data into the intkey B-Tree. In this case btreeMoveto() recognizes + ** that the cursor is already where it needs to be and returns without + ** doing any work. To avoid thwarting these optimizations, it is important + ** not to clear the cursor here. + */ + if( pCur->curFlags & BTCF_Multiple ){ + rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); + if( rc ) return rc; + } + + if( pCur->pKeyInfo==0 ){ + assert( pX->pKey==0 ); + /* If this is an insert into a table b-tree, invalidate any incrblob + ** cursors open on the row being replaced */ + invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); + + /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing + ** to a row with the same key as the new entry being inserted. */ + assert( (flags & BTREE_SAVEPOSITION)==0 || + ((pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey) ); + + /* If the cursor is currently on the last row and we are appending a + ** new row onto the end, set the "loc" to avoid an unnecessary + ** btreeMoveto() call */ + if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){ + loc = 0; + }else if( loc==0 ){ + rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); + if( rc ) return rc; + } + }else if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ + if( pX->nMem ){ + UnpackedRecord r; + r.pKeyInfo = pCur->pKeyInfo; + r.aMem = pX->aMem; + r.nField = pX->nMem; + r.default_rc = 0; + r.errCode = 0; + r.r1 = 0; + r.r2 = 0; + r.eqSeen = 0; + rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); + }else{ + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + } + if( rc ) return rc; + } + assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); + + pPage = pCur->apPage[pCur->iPage]; + assert( pPage->intKey || pX->nKey>=0 ); + assert( pPage->leaf || !pPage->intKey ); + + TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", + pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, + loc==0 ? "overwrite" : "new entry")); + assert( pPage->isInit ); + newCell = pBt->pTmpSpace; + assert( newCell!=0 ); + rc = fillInCell(pPage, newCell, pX, &szNew); + if( rc ) goto end_insert; + assert( szNew==pPage->xCellSize(pPage, newCell) ); + assert( szNew <= MX_CELL_SIZE(pBt) ); + idx = pCur->ix; + if( loc==0 ){ + CellInfo info; + assert( idxnCell ); + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ){ + goto end_insert; + } + oldCell = findCell(pPage, idx); + if( !pPage->leaf ){ + memcpy(newCell, oldCell, 4); + } + rc = clearCell(pPage, oldCell, &info); + if( info.nSize==szNew && info.nLocal==info.nPayload + && (!ISAUTOVACUUM || szNewminLocal) + ){ + /* Overwrite the old cell with the new if they are the same size. + ** We could also try to do this if the old cell is smaller, then add + ** the leftover space to the free list. But experiments show that + ** doing that is no faster then skipping this optimization and just + ** calling dropCell() and insertCell(). + ** + ** This optimization cannot be used on an autovacuum database if the + ** new entry uses overflow pages, as the insertCell() call below is + ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */ + assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */ + if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; + memcpy(oldCell, newCell, szNew); + return SQLITE_OK; + } + dropCell(pPage, idx, info.nSize, &rc); + if( rc ) goto end_insert; + }else if( loc<0 && pPage->nCell>0 ){ + assert( pPage->leaf ); + idx = ++pCur->ix; + pCur->curFlags &= ~BTCF_ValidNKey; + }else{ + assert( pPage->leaf ); + } + insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); + assert( pPage->nOverflow==0 || rc==SQLITE_OK ); + assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); + + /* If no error has occurred and pPage has an overflow cell, call balance() + ** to redistribute the cells within the tree. Since balance() may move + ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey + ** variables. + ** + ** Previous versions of SQLite called moveToRoot() to move the cursor + ** back to the root page as balance() used to invalidate the contents + ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that, + ** set the cursor state to "invalid". This makes common insert operations + ** slightly faster. + ** + ** There is a subtle but important optimization here too. When inserting + ** multiple records into an intkey b-tree using a single cursor (as can + ** happen while processing an "INSERT INTO ... SELECT" statement), it + ** is advantageous to leave the cursor pointing to the last entry in + ** the b-tree if possible. If the cursor is left pointing to the last + ** entry in the table, and the next row inserted has an integer key + ** larger than the largest existing key, it is possible to insert the + ** row without seeking the cursor. This can be a big performance boost. + */ + pCur->info.nSize = 0; + if( pPage->nOverflow ){ + assert( rc==SQLITE_OK ); + pCur->curFlags &= ~(BTCF_ValidNKey); + rc = balance(pCur); + + /* Must make sure nOverflow is reset to zero even if the balance() + ** fails. Internal data structure corruption will result otherwise. + ** 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->eState = CURSOR_INVALID; + if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){ + rc = moveToRoot(pCur); + if( pCur->pKeyInfo ){ + assert( pCur->pKey==0 ); + pCur->pKey = sqlite3Malloc( pX->nKey ); + if( pCur->pKey==0 ){ + rc = SQLITE_NOMEM; + }else{ + memcpy(pCur->pKey, pX->pKey, pX->nKey); + } + } + pCur->eState = CURSOR_REQUIRESEEK; + pCur->nKey = pX->nKey; + } + } + assert( pCur->apPage[pCur->iPage]->nOverflow==0 ); + +end_insert: + return rc; +} + +/* +** Delete the entry that the cursor is pointing to. +** +** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then +** the cursor is left pointing at an arbitrary location after the delete. +** But if that bit is set, then the cursor is left in a state such that +** the next call to BtreeNext() or BtreePrev() moves it to the same row +** as it would have been on if the call to BtreeDelete() had been omitted. +** +** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes +** associated with a single table entry and its indexes. Only one of those +** deletes is considered the "primary" delete. The primary delete occurs +** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete +** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag. +** The BTREE_AUXDELETE bit is a hint that is not used by this implementation, +** but which might be used by alternative storage engines. +*/ +SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ + Btree *p = pCur->pBtree; + BtShared *pBt = p->pBt; + int rc; /* Return code */ + MemPage *pPage; /* Page to delete cell from */ + unsigned char *pCell; /* Pointer to cell to delete */ + int iCellIdx; /* Index of cell to delete */ + int iCellDepth; /* Depth of node containing pCell */ + CellInfo info; /* Size of the cell being deleted */ + int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */ + u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */ + + assert( cursorOwnsBtShared(pCur) ); + assert( pBt->inTransaction==TRANS_WRITE ); + assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); + assert( pCur->curFlags & BTCF_WriteFlag ); + assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); + assert( !hasReadConflicts(p, pCur->pgnoRoot) ); + assert( pCur->ixapPage[pCur->iPage]->nCell ); + assert( pCur->eState==CURSOR_VALID ); + assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); + + iCellDepth = pCur->iPage; + iCellIdx = pCur->ix; + pPage = pCur->apPage[iCellDepth]; + pCell = findCell(pPage, iCellIdx); + + /* If the bPreserve flag is set to true, then the cursor position must + ** be preserved following this delete operation. If the current delete + ** will cause a b-tree rebalance, then this is done by saving the cursor + ** key and leaving the cursor in CURSOR_REQUIRESEEK state before + ** returning. + ** + ** Or, if the current delete will not cause a rebalance, then the cursor + ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately + ** before or after the deleted entry. In this case set bSkipnext to true. */ + if( bPreserve ){ + if( !pPage->leaf + || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) + ){ + /* A b-tree rebalance will be required after deleting this entry. + ** Save the cursor key. */ + rc = saveCursorKey(pCur); + if( rc ) return rc; + }else{ + bSkipnext = 1; + } + } + + /* If the page containing the entry to delete is not a leaf page, move + ** the cursor to the largest entry in the tree that is smaller than + ** the entry being deleted. This cell will replace the cell being deleted + ** from the internal node. The 'previous' entry is used for this instead + ** of the 'next' entry, as the previous entry is always a part of the + ** sub-tree headed by the child page of the cell being deleted. This makes + ** balancing the tree following the delete operation easier. */ + if( !pPage->leaf ){ + int notUsed = 0; + rc = sqlite3BtreePrevious(pCur, ¬Used); + if( rc ) return rc; + } + + /* Save the positions of any other cursors open on this table before + ** making any modifications. */ + if( pCur->curFlags & BTCF_Multiple ){ + rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); + if( rc ) return rc; + } + + /* If this is a delete operation to remove a row from a table b-tree, + ** invalidate any incrblob cursors open on the row being deleted. */ + if( pCur->pKeyInfo==0 ){ + invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0); + } + + /* Make the page containing the entry to be deleted writable. Then free any + ** overflow pages associated with the entry and finally remove the cell + ** itself from within the page. */ + rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + rc = clearCell(pPage, pCell, &info); + dropCell(pPage, iCellIdx, info.nSize, &rc); + if( rc ) return rc; + + /* If the cell deleted was not located on a leaf page, then the cursor + ** is currently pointing to the largest entry in the sub-tree headed + ** by the child-page of the cell that was just deleted from an internal + ** 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]; + int nCell; + Pgno n = pCur->apPage[iCellDepth+1]->pgno; + unsigned char *pTmp; + + pCell = findCell(pLeaf, pLeaf->nCell-1); + if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; + nCell = pLeaf->xCellSize(pLeaf, pCell); + assert( MX_CELL_SIZE(pBt) >= nCell ); + pTmp = pBt->pTmpSpace; + assert( pTmp!=0 ); + rc = sqlite3PagerWrite(pLeaf->pDbPage); + if( rc==SQLITE_OK ){ + insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); + } + dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); + if( rc ) return rc; + } + + /* Balance the tree. If the entry deleted was located on a leaf page, + ** then the cursor still points to that page. In this case the first + ** call to balance() repairs the tree, and the if(...) condition is + ** never true. + ** + ** Otherwise, if the entry deleted was on an internal node page, then + ** pCur is pointing to the leaf page from which a cell was removed to + ** replace the cell deleted from the internal node. This is slightly + ** tricky as the leaf node may be underfull, and the internal node may + ** be either under or overfull. In this case run the balancing algorithm + ** on the leaf node first. If the balance proceeds far enough up the + ** tree that we can be sure that any problem in the internal node has + ** been corrected, so be it. Otherwise, after balancing the leaf node, + ** walk the cursor up the tree to the internal node and balance it as + ** well. */ + rc = balance(pCur); + if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ + while( pCur->iPage>iCellDepth ){ + releasePage(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->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell ); + pCur->eState = CURSOR_SKIPNEXT; + if( iCellIdx>=pPage->nCell ){ + pCur->skipNext = -1; + pCur->ix = pPage->nCell-1; + }else{ + pCur->skipNext = 1; + } + }else{ + rc = moveToRoot(pCur); + if( bPreserve ){ + pCur->eState = CURSOR_REQUIRESEEK; + } + } + } + return rc; +} + +/* +** Create a new BTree table. Write into *piTable the page +** number for the root page of the new table. +** +** The type of type is determined by the flags parameter. Only the +** following values of flags are currently in use. Other values for +** flags might not work: +** +** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys +** BTREE_ZERODATA Used for SQL indices +*/ +static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ + BtShared *pBt = p->pBt; + MemPage *pRoot; + Pgno pgnoRoot; + int rc; + int ptfFlags; /* Page-type flage for the root page of new table */ + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( pBt->inTransaction==TRANS_WRITE ); + assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); + +#ifdef SQLITE_OMIT_AUTOVACUUM + rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); + if( rc ){ + return rc; + } +#else + if( pBt->autoVacuum ){ + Pgno pgnoMove; /* Move a page here to make room for the root-page */ + MemPage *pPageMove; /* The page to move to. */ + + /* Creating a new table may probably require moving an existing database + ** to make room for the new tables root page. In case this page turns + ** out to be an overflow page, delete all overflow page-map caches + ** held by open cursors. + */ + invalidateAllOverflowCache(pBt); + + /* Read the value of meta[3] from the database to determine where the + ** root page of the new table should go. meta[3] is the largest root-page + ** created so far, so the new root-page is (meta[3]+1). + */ + sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); + pgnoRoot++; + + /* The new root-page may not be allocated on a pointer-map page, or the + ** PENDING_BYTE page. + */ + while( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) || + pgnoRoot==PENDING_BYTE_PAGE(pBt) ){ + pgnoRoot++; + } + assert( pgnoRoot>=3 || CORRUPT_DB ); + testcase( pgnoRoot<3 ); + + /* Allocate a page. The page that currently resides at pgnoRoot will + ** be moved to the allocated page (unless the allocated page happens + ** to reside at pgnoRoot). + */ + rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT); + if( rc!=SQLITE_OK ){ + return rc; + } + + if( pgnoMove!=pgnoRoot ){ + /* pgnoRoot is the page that will be used for the root-page of + ** the new table (assuming an error did not occur). But we were + ** allocated pgnoMove. If required (i.e. if it was not allocated + ** by extending the file), the current page at position pgnoMove + ** is already journaled. + */ + u8 eType = 0; + Pgno iPtrPage = 0; + + /* Save the positions of any open cursors. This is required in + ** case they are holding a reference to an xFetch reference + ** corresponding to page pgnoRoot. */ + rc = saveAllCursors(pBt, 0, 0); + releasePage(pPageMove); + if( rc!=SQLITE_OK ){ + return rc; + } + + /* Move the page currently at pgnoRoot to pgnoMove. */ + rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); + if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ + rc = SQLITE_CORRUPT_BKPT; + } + if( rc!=SQLITE_OK ){ + releasePage(pRoot); + return rc; + } + assert( eType!=PTRMAP_ROOTPAGE ); + assert( eType!=PTRMAP_FREEPAGE ); + rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0); + releasePage(pRoot); + + /* Obtain the page at pgnoRoot */ + if( rc!=SQLITE_OK ){ + return rc; + } + rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + rc = sqlite3PagerWrite(pRoot->pDbPage); + if( rc!=SQLITE_OK ){ + releasePage(pRoot); + return rc; + } + }else{ + pRoot = pPageMove; + } + + /* Update the pointer-map and meta-data with the new root-page number. */ + ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc); + if( rc ){ + releasePage(pRoot); + return rc; + } + + /* When the new root page was allocated, page 1 was made writable in + ** order either to increase the database filesize, or to decrement the + ** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail. + */ + assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) ); + rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot); + if( NEVER(rc) ){ + releasePage(pRoot); + return rc; + } + + }else{ + rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); + if( rc ) return rc; + } +#endif + assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); + if( createTabFlags & BTREE_INTKEY ){ + ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF; + }else{ + ptfFlags = PTF_ZERODATA | PTF_LEAF; + } + zeroPage(pRoot, ptfFlags); + sqlite3PagerUnref(pRoot->pDbPage); + assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 ); + *piTable = (int)pgnoRoot; + return SQLITE_OK; +} +SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeCreateTable(p, piTable, flags); + sqlite3BtreeLeave(p); + return rc; +} + +/* +** Erase the given database page and all its children. Return +** the page to the freelist. +*/ +static int clearDatabasePage( + BtShared *pBt, /* The BTree that contains the table */ + Pgno pgno, /* Page number to clear */ + int freePageFlag, /* Deallocate page if true */ + int *pnChange /* Add number of Cells freed to this counter */ +){ + MemPage *pPage; + int rc; + unsigned char *pCell; + int i; + int hdr; + CellInfo info; + + assert( sqlite3_mutex_held(pBt->mutex) ); + if( pgno>btreePagecount(pBt) ){ + return SQLITE_CORRUPT_BKPT; + } + rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); + if( rc ) return rc; + if( pPage->bBusy ){ + rc = SQLITE_CORRUPT_BKPT; + goto cleardatabasepage_out; + } + pPage->bBusy = 1; + hdr = pPage->hdrOffset; + for(i=0; inCell; i++){ + pCell = findCell(pPage, i); + if( !pPage->leaf ){ + rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); + if( rc ) goto cleardatabasepage_out; + } + rc = clearCell(pPage, pCell, &info); + if( rc ) goto cleardatabasepage_out; + } + if( !pPage->leaf ){ + rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); + if( rc ) goto cleardatabasepage_out; + }else if( pnChange ){ + assert( pPage->intKey || CORRUPT_DB ); + testcase( !pPage->intKey ); + *pnChange += pPage->nCell; + } + if( freePageFlag ){ + freePage(pPage, &rc); + }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ + zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF); + } + +cleardatabasepage_out: + pPage->bBusy = 0; + releasePage(pPage); + return rc; +} + +/* +** Delete all information from a single table in the database. iTable is +** the page number of the root of the table. After this routine returns, +** the root page is empty, but still exists. +** +** This routine will fail with SQLITE_LOCKED if there are any open +** read cursors on the table. Open write cursors are moved to the +** root of the table. +** +** If pnChange is not NULL, then table iTable must be an intkey table. The +** integer value pointed to by pnChange is incremented by the number of +** entries in the table. +*/ +SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ + int rc; + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + assert( p->inTrans==TRANS_WRITE ); + + rc = saveAllCursors(pBt, (Pgno)iTable, 0); + + if( SQLITE_OK==rc ){ + /* Invalidate all incrblob cursors open on table iTable (assuming iTable + ** is the root of a table b-tree - if it is not, the following call is + ** a no-op). */ + invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); + rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); + } + sqlite3BtreeLeave(p); + return rc; +} + +/* +** Delete all information from the single table that pCur is open on. +** +** This routine only work for pCur on an ephemeral table. +*/ +SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){ + return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0); +} + +/* +** Erase all information in a table and add the root of the table to +** the freelist. Except, the root of the principle table (the one on +** page 1) is never added to the freelist. +** +** This routine will fail with SQLITE_LOCKED if there are any open +** cursors on the table. +** +** If AUTOVACUUM is enabled and the page at iTable is not the last +** root page in the database file, then the last root page +** in the database file is moved into the slot formerly occupied by +** iTable and that last slot formerly occupied by the last root page +** is added to the freelist instead of iTable. In this say, all +** root pages are kept at the beginning of the database file, which +** is necessary for AUTOVACUUM to work right. *piMoved is set to the +** page number that used to be the last root page in the file before +** the move. If no page gets moved, *piMoved is set to 0. +** The last root page is recorded in meta[3] and the value of +** meta[3] is updated by this procedure. +*/ +static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ + int rc; + MemPage *pPage = 0; + BtShared *pBt = p->pBt; + + assert( sqlite3BtreeHoldsMutex(p) ); + assert( p->inTrans==TRANS_WRITE ); + assert( iTable>=2 ); + + rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); + if( rc ) return rc; + rc = sqlite3BtreeClearTable(p, iTable, 0); + if( rc ){ + releasePage(pPage); + return rc; + } + + *piMoved = 0; + +#ifdef SQLITE_OMIT_AUTOVACUUM + freePage(pPage, &rc); + releasePage(pPage); +#else + if( pBt->autoVacuum ){ + Pgno maxRootPgno; + sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno); + + if( iTable==maxRootPgno ){ + /* If the table being dropped is the table with the largest root-page + ** number in the database, put the root page on the free list. + */ + freePage(pPage, &rc); + releasePage(pPage); + if( rc!=SQLITE_OK ){ + return rc; + } + }else{ + /* The table being dropped does not have the largest root-page + ** number in the database. So move the page that does into the + ** gap left by the deleted root-page. + */ + MemPage *pMove; + releasePage(pPage); + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); + releasePage(pMove); + if( rc!=SQLITE_OK ){ + return rc; + } + pMove = 0; + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); + freePage(pMove, &rc); + releasePage(pMove); + if( rc!=SQLITE_OK ){ + return rc; + } + *piMoved = maxRootPgno; + } + + /* Set the new 'max-root-page' value in the database header. This + ** is the old value less one, less one more if that happens to + ** be a root-page number, less one again if that is the + ** PENDING_BYTE_PAGE. + */ + maxRootPgno--; + while( maxRootPgno==PENDING_BYTE_PAGE(pBt) + || PTRMAP_ISPAGE(pBt, maxRootPgno) ){ + maxRootPgno--; + } + assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); + + rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); + }else{ + freePage(pPage, &rc); + releasePage(pPage); + } +#endif + return rc; +} +SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeDropTable(p, iTable, piMoved); + sqlite3BtreeLeave(p); + return rc; +} + + +/* +** This function may only be called if the b-tree connection already +** has a read or write transaction open on the database. +** +** Read the meta-information out of a database file. Meta[0] +** is the number of free pages currently in the database. Meta[1] +** through meta[15] are available for use by higher layers. Meta[0] +** is read-only, the others are read/write. +** +** The schema layer numbers meta values differently. At the schema +** layer (and the SetCookie and ReadCookie opcodes) the number of +** free pages is not visible. So Cookie[0] is the same as Meta[1]. +** +** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead +** of reading the value out of the header, it instead loads the "DataVersion" +** from the pager. The BTREE_DATA_VERSION value is not actually stored in the +** database file. It is a number computed by the pager. But its access +** pattern is the same as header meta values, and so it is convenient to +** read it from this routine. +*/ +SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ + BtShared *pBt = p->pBt; + + sqlite3BtreeEnter(p); + assert( p->inTrans>TRANS_NONE ); + assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) ); + assert( pBt->pPage1 ); + assert( idx>=0 && idx<=15 ); + + if( idx==BTREE_DATA_VERSION ){ + *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion; + }else{ + *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); + } + + /* If auto-vacuum is disabled in this build and this is an auto-vacuum + ** database, mark the database as read-only. */ +#ifdef SQLITE_OMIT_AUTOVACUUM + if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ){ + pBt->btsFlags |= BTS_READ_ONLY; + } +#endif + + sqlite3BtreeLeave(p); +} + +/* +** Write meta-information back into the database. Meta[0] is +** read-only and may not be written. +*/ +SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ + BtShared *pBt = p->pBt; + unsigned char *pP1; + int rc; + assert( idx>=1 && idx<=15 ); + sqlite3BtreeEnter(p); + assert( p->inTrans==TRANS_WRITE ); + assert( pBt->pPage1!=0 ); + pP1 = pBt->pPage1->aData; + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + if( rc==SQLITE_OK ){ + put4byte(&pP1[36 + idx*4], iMeta); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( idx==BTREE_INCR_VACUUM ){ + assert( pBt->autoVacuum || iMeta==0 ); + assert( iMeta==0 || iMeta==1 ); + pBt->incrVacuum = (u8)iMeta; + } +#endif + } + sqlite3BtreeLeave(p); + return rc; +} + +#ifndef SQLITE_OMIT_BTREECOUNT +/* +** The first argument, pCur, is a cursor opened on some b-tree. Count the +** number of entries in the b-tree and write the result to *pnEntry. +** +** SQLITE_OK is returned if the operation is successfully executed. +** Otherwise, if an error is encountered (i.e. an IO error or database +** corruption) an SQLite error code is returned. +*/ +SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ + i64 nEntry = 0; /* Value to return in *pnEntry */ + int rc; /* Return code */ + + if( pCur->pgnoRoot==0 ){ + *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). + */ + while( rc==SQLITE_OK ){ + int iIdx; /* Index of child node in parent */ + MemPage *pPage; /* Current page of the b-tree */ + + /* If this is a leaf page or the tree is not an int-key tree, then + ** this page contains countable entries. Increment the entry counter + ** accordingly. + */ + pPage = pCur->apPage[pCur->iPage]; + if( pPage->leaf || !pPage->intKey ){ + nEntry += pPage->nCell; + } + + /* pPage is a leaf node. This loop navigates the cursor so that it + ** points to the first interior cell that it points to the parent of + ** the next page in the tree that has not yet been visited. The + ** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell + ** of the page, or to the number of cells in the page if the next page + ** to visit is the right-child of its parent. + ** + ** If all pages in the tree have been visited, return SQLITE_OK to the + ** caller. + */ + if( pPage->leaf ){ + do { + if( pCur->iPage==0 ){ + /* All pages of the b-tree have been visited. Return successfully. */ + *pnEntry = nEntry; + return moveToRoot(pCur); + } + moveToParent(pCur); + }while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell ); + + pCur->ix++; + pPage = pCur->apPage[pCur->iPage]; + } + + /* Descend to the child node of the cell that the cursor currently + ** points at. This is the right-child if (iIdx==pPage->nCell). + */ + iIdx = pCur->ix; + if( iIdx==pPage->nCell ){ + rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); + }else{ + rc = moveToChild(pCur, get4byte(findCell(pPage, iIdx))); + } + } + + /* An error has occurred. Return an error code. */ + return rc; +} +#endif + +/* +** Return the pager associated with a BTree. This routine is used for +** testing and debugging only. +*/ +SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){ + return p->pBt->pPager; +} + +#ifndef SQLITE_OMIT_INTEGRITY_CHECK +/* +** Append a message to the error message string. +*/ +static void checkAppendMsg( + IntegrityCk *pCheck, + const char *zFormat, + ... +){ + va_list ap; + if( !pCheck->mxErr ) return; + pCheck->mxErr--; + pCheck->nErr++; + va_start(ap, zFormat); + if( pCheck->errMsg.nChar ){ + sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1); + } + if( pCheck->zPfx ){ + sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); + } + sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap); + va_end(ap); + if( pCheck->errMsg.accError==STRACCUM_NOMEM ){ + pCheck->mallocFailed = 1; + } +} +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ + +#ifndef SQLITE_OMIT_INTEGRITY_CHECK + +/* +** Return non-zero if the bit in the IntegrityCk.aPgRef[] array that +** corresponds to page iPg is already set. +*/ +static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){ + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07))); +} + +/* +** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg. +*/ +static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ + assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 ); + pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07)); +} + + +/* +** Add 1 to the reference count for page iPage. If this is the second +** reference to the page, add an error message to pCheck->zErrMsg. +** Return 1 if there are 2 or more references to the page and 0 if +** if this is the first reference to the page. +** +** Also check that the page number is in bounds. +*/ +static int checkRef(IntegrityCk *pCheck, Pgno iPage){ + if( iPage==0 ) return 1; + if( iPage>pCheck->nPage ){ + checkAppendMsg(pCheck, "invalid page number %d", iPage); + return 1; + } + if( getPageReferenced(pCheck, iPage) ){ + checkAppendMsg(pCheck, "2nd reference to page %d", iPage); + return 1; + } + setPageReferenced(pCheck, iPage); + return 0; +} + +#ifndef SQLITE_OMIT_AUTOVACUUM +/* +** Check that the entry in the pointer-map for page iChild maps to +** page iParent, pointer type ptrType. If not, append an error message +** to pCheck. +*/ +static void checkPtrmap( + IntegrityCk *pCheck, /* Integrity check context */ + Pgno iChild, /* Child page number */ + u8 eType, /* Expected pointer map type */ + Pgno iParent /* Expected pointer map parent page number */ +){ + int rc; + u8 ePtrmapType; + Pgno iPtrmapParent; + + rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1; + checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild); + return; + } + + if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ + checkAppendMsg(pCheck, + "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", + iChild, eType, iParent, ePtrmapType, iPtrmapParent); + } +} +#endif + +/* +** Check the integrity of the freelist or of an overflow page list. +** Verify that the number of pages on the list is N. +*/ +static void checkList( + IntegrityCk *pCheck, /* Integrity checking context */ + int isFreeList, /* True for a freelist. False for overflow page list */ + int iPage, /* Page number for first page in the list */ + int N /* Expected number of pages in the list */ +){ + int i; + int expected = N; + int iFirst = iPage; + while( N-- > 0 && pCheck->mxErr ){ + DbPage *pOvflPage; + unsigned char *pOvflData; + if( iPage<1 ){ + checkAppendMsg(pCheck, + "%d of %d pages missing from overflow list starting at %d", + N+1, expected, iFirst); + break; + } + if( checkRef(pCheck, iPage) ) break; + if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ + checkAppendMsg(pCheck, "failed to get page %d", iPage); + break; + } + pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); + if( isFreeList ){ + int n = get4byte(&pOvflData[4]); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pCheck->pBt->autoVacuum ){ + checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0); + } +#endif + if( n>(int)pCheck->pBt->usableSize/4-2 ){ + checkAppendMsg(pCheck, + "freelist leaf count too big on page %d", iPage); + N--; + }else{ + for(i=0; ipBt->autoVacuum ){ + checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0); + } +#endif + checkRef(pCheck, iFreePage); + } + N -= n; + } + } +#ifndef SQLITE_OMIT_AUTOVACUUM + else{ + /* If this database supports auto-vacuum and iPage is not the last + ** page in this overflow list, check that the pointer-map entry for + ** the following page matches iPage. + */ + if( pCheck->pBt->autoVacuum && N>0 ){ + i = get4byte(pOvflData); + checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage); + } + } +#endif + iPage = get4byte(pOvflData); + sqlite3PagerUnref(pOvflPage); + + if( isFreeList && N<(iPage!=0) ){ + checkAppendMsg(pCheck, "free-page count in header is too small"); + } + } +} +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ + +/* +** An implementation of a min-heap. +** +** aHeap[0] is the number of elements on the heap. aHeap[1] is the +** root element. The daughter nodes of aHeap[N] are aHeap[N*2] +** and aHeap[N*2+1]. +** +** The heap property is this: Every node is less than or equal to both +** of its daughter nodes. A consequence of the heap property is that the +** root node aHeap[1] is always the minimum value currently in the heap. +** +** The btreeHeapInsert() routine inserts an unsigned 32-bit number onto +** the heap, preserving the heap property. The btreeHeapPull() routine +** removes the root element from the heap (the minimum value in the heap) +** and then moves other nodes around as necessary to preserve the heap +** property. +** +** This heap is used for cell overlap and coverage testing. Each u32 +** entry represents the span of a cell or freeblock on a btree page. +** The upper 16 bits are the index of the first byte of a range and the +** lower 16 bits are the index of the last byte of that range. +*/ +static void btreeHeapInsert(u32 *aHeap, u32 x){ + u32 j, i = ++aHeap[0]; + aHeap[i] = x; + while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){ + x = aHeap[j]; + aHeap[j] = aHeap[i]; + aHeap[i] = x; + i = j; + } +} +static int btreeHeapPull(u32 *aHeap, u32 *pOut){ + u32 j, i, x; + if( (x = aHeap[0])==0 ) return 0; + *pOut = aHeap[1]; + aHeap[1] = aHeap[x]; + aHeap[x] = 0xffffffff; + aHeap[0]--; + i = 1; + while( (j = i*2)<=aHeap[0] ){ + if( aHeap[j]>aHeap[j+1] ) j++; + if( aHeap[i]zPfx; + int saved_v1 = pCheck->v1; + int saved_v2 = pCheck->v2; + u8 savedIsInit = 0; + + /* Check that the page exists + */ + pBt = pCheck->pBt; + usableSize = pBt->usableSize; + if( iPage==0 ) return 0; + if( checkRef(pCheck, iPage) ) return 0; + pCheck->zPfx = "Page %d: "; + pCheck->v1 = iPage; + if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ + checkAppendMsg(pCheck, + "unable to get the page. error code=%d", rc); + goto end_of_check; + } + + /* Clear MemPage.isInit to make sure the corruption detection code in + ** btreeInitPage() is executed. */ + savedIsInit = pPage->isInit; + pPage->isInit = 0; + if( (rc = btreeInitPage(pPage))!=0 ){ + assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */ + checkAppendMsg(pCheck, + "btreeInitPage() returns error code %d", rc); + goto end_of_check; + } + data = pPage->aData; + hdr = pPage->hdrOffset; + + /* Set up for cell analysis */ + pCheck->zPfx = "On tree page %d cell %d: "; + contentOffset = get2byteNotZero(&data[hdr+5]); + assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ + + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ + nCell = get2byte(&data[hdr+3]); + assert( pPage->nCell==nCell ); + + /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page + ** immediately follows the b-tree page header. */ + cellStart = hdr + 12 - 4*pPage->leaf; + assert( pPage->aCellIdx==&data[cellStart] ); + pCellIdx = &data[cellStart + 2*(nCell-1)]; + + if( !pPage->leaf ){ + /* Analyze the right-child page of internal pages */ + pgno = get4byte(&data[hdr+8]); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum ){ + pCheck->zPfx = "On page %d at right child: "; + checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); + } +#endif + depth = checkTreePage(pCheck, pgno, &maxKey, maxKey); + keyCanBeEqual = 0; + }else{ + /* For leaf pages, the coverage check will occur in the same loop + ** as the other cell checks, so initialize the heap. */ + heap = pCheck->heap; + heap[0] = 0; + } + + /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte + ** integer offsets to the cell contents. */ + for(i=nCell-1; i>=0 && pCheck->mxErr; i--){ + CellInfo info; + + /* Check cell size */ + pCheck->v2 = i; + assert( pCellIdx==&data[cellStart + i*2] ); + pc = get2byteAligned(pCellIdx); + pCellIdx -= 2; + if( pcusableSize-4 ){ + checkAppendMsg(pCheck, "Offset %d out of range %d..%d", + pc, contentOffset, usableSize-4); + doCoverageCheck = 0; + continue; + } + pCell = &data[pc]; + pPage->xParseCell(pPage, pCell, &info); + if( pc+info.nSize>usableSize ){ + checkAppendMsg(pCheck, "Extends off end of page"); + doCoverageCheck = 0; + continue; + } + + /* Check for integer primary key out of range */ + if( pPage->intKey ){ + if( keyCanBeEqual ? (info.nKey > maxKey) : (info.nKey >= maxKey) ){ + checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey); + } + maxKey = info.nKey; + keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */ + } + + /* Check the content overflow list */ + if( info.nPayload>info.nLocal ){ + int nPage; /* Number of pages on the overflow chain */ + Pgno pgnoOvfl; /* First page of the overflow chain */ + assert( pc + info.nSize - 4 <= usableSize ); + nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4); + pgnoOvfl = get4byte(&pCell[info.nSize - 4]); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum ){ + checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage); + } +#endif + checkList(pCheck, 0, pgnoOvfl, nPage); + } + + if( !pPage->leaf ){ + /* Check sanity of left child page for internal pages */ + pgno = get4byte(pCell); +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum ){ + checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); + } +#endif + d2 = checkTreePage(pCheck, pgno, &maxKey, maxKey); + keyCanBeEqual = 0; + if( d2!=depth ){ + checkAppendMsg(pCheck, "Child page depth differs"); + depth = d2; + } + }else{ + /* Populate the coverage-checking heap for leaf pages */ + btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1)); + } + } + *piMinKey = maxKey; + + /* Check for complete coverage of the page + */ + pCheck->zPfx = 0; + if( doCoverageCheck && pCheck->mxErr>0 ){ + /* For leaf pages, the min-heap has already been initialized and the + ** cells have already been inserted. But for internal pages, that has + ** not yet been done, so do it now */ + if( !pPage->leaf ){ + heap = pCheck->heap; + heap[0] = 0; + for(i=nCell-1; i>=0; i--){ + u32 size; + pc = get2byteAligned(&data[cellStart+i*2]); + size = pPage->xCellSize(pPage, &data[pc]); + btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); + } + } + /* Add the freeblocks to the min-heap + ** + ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header + ** is the offset of the first freeblock, or zero if there are no + ** freeblocks on the page. + */ + i = get2byte(&data[hdr+1]); + while( i>0 ){ + int size, j; + assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */ + size = get2byte(&data[i+2]); + assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */ + btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); + /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a + ** big-endian integer which is the offset in the b-tree page of the next + ** freeblock in the chain, or zero if the freeblock is the last on the + ** chain. */ + j = get2byte(&data[i]); + /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of + ** increasing offset. */ + assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */ + assert( (u32)j<=usableSize-4 ); /* Enforced by btreeInitPage() */ + i = j; + } + /* Analyze the min-heap looking for overlap between cells and/or + ** freeblocks, and counting the number of untracked bytes in nFrag. + ** + ** Each min-heap entry is of the form: (start_address<<16)|end_address. + ** There is an implied first entry the covers the page header, the cell + ** pointer index, and the gap between the cell pointer index and the start + ** of cell content. + ** + ** The loop below pulls entries from the min-heap in order and compares + ** the start_address against the previous end_address. If there is an + ** overlap, that means bytes are used multiple times. If there is a gap, + ** that gap is added to the fragmentation count. + */ + nFrag = 0; + prev = contentOffset - 1; /* Implied first min-heap entry */ + while( btreeHeapPull(heap,&x) ){ + if( (prev&0xffff)>=(x>>16) ){ + checkAppendMsg(pCheck, + "Multiple uses for byte %u of page %d", x>>16, iPage); + break; + }else{ + nFrag += (x>>16) - (prev&0xffff) - 1; + prev = x; + } + } + nFrag += usableSize - (prev&0xffff) - 1; + /* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments + ** is stored in the fifth field of the b-tree page header. + ** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the + ** number of fragmented free bytes within the cell content area. + */ + if( heap[0]==0 && nFrag!=data[hdr+7] ){ + checkAppendMsg(pCheck, + "Fragmentation of %d bytes reported as %d on page %d", + nFrag, data[hdr+7], iPage); + } + } + +end_of_check: + if( !doCoverageCheck ) pPage->isInit = savedIsInit; + releasePage(pPage); + pCheck->zPfx = saved_zPfx; + pCheck->v1 = saved_v1; + pCheck->v2 = saved_v2; + return depth+1; +} +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ + +#ifndef SQLITE_OMIT_INTEGRITY_CHECK +/* +** This routine does a complete check of the given BTree file. aRoot[] is +** an array of pages numbers were each page number is the root page of +** a table. nRoot is the number of entries in aRoot. +** +** A read-only or read-write transaction must be opened before calling +** this function. +** +** Write the number of error seen in *pnErr. Except for some memory +** allocation errors, an error message held in memory obtained from +** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is +** returned. If a memory allocation error occurs, NULL is returned. +*/ +SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( + Btree *p, /* The btree to be checked */ + int *aRoot, /* An array of root pages numbers for individual trees */ + int nRoot, /* Number of entries in aRoot[] */ + int mxErr, /* Stop reporting errors after this many */ + int *pnErr /* Write number of errors seen to this variable */ +){ + Pgno i; + IntegrityCk sCheck; + BtShared *pBt = p->pBt; + int savedDbFlags = pBt->db->flags; + char zErr[100]; + VVA_ONLY( int nRef ); + + sqlite3BtreeEnter(p); + assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); + VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) ); + assert( nRef>=0 ); + sCheck.pBt = pBt; + sCheck.pPager = pBt->pPager; + sCheck.nPage = btreePagecount(sCheck.pBt); + sCheck.mxErr = mxErr; + sCheck.nErr = 0; + sCheck.mallocFailed = 0; + sCheck.zPfx = 0; + sCheck.v1 = 0; + sCheck.v2 = 0; + sCheck.aPgRef = 0; + sCheck.heap = 0; + sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); + sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL; + if( sCheck.nPage==0 ){ + goto integrity_ck_cleanup; + } + + sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); + if( !sCheck.aPgRef ){ + sCheck.mallocFailed = 1; + goto integrity_ck_cleanup; + } + sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); + if( sCheck.heap==0 ){ + sCheck.mallocFailed = 1; + goto integrity_ck_cleanup; + } + + i = PENDING_BYTE_PAGE(pBt); + if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); + + /* Check the integrity of the freelist + */ + sCheck.zPfx = "Main freelist: "; + checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), + get4byte(&pBt->pPage1->aData[36])); + sCheck.zPfx = 0; + + /* Check all the tables. + */ + testcase( pBt->db->flags & SQLITE_CellSizeCk ); + pBt->db->flags &= ~SQLITE_CellSizeCk; + for(i=0; (int)iautoVacuum && aRoot[i]>1 ){ + checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); + } +#endif + checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); + } + pBt->db->flags = savedDbFlags; + + /* Make sure every page in the file is referenced + */ + for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ +#ifdef SQLITE_OMIT_AUTOVACUUM + if( getPageReferenced(&sCheck, i)==0 ){ + checkAppendMsg(&sCheck, "Page %d is never used", i); + } +#else + /* If the database supports auto-vacuum, make sure no tables contain + ** references to pointer-map pages. + */ + if( getPageReferenced(&sCheck, i)==0 && + (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Page %d is never used", i); + } + if( getPageReferenced(&sCheck, i)!=0 && + (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); + } +#endif + } + + /* Clean up and report errors. + */ +integrity_ck_cleanup: + sqlite3PageFree(sCheck.heap); + sqlite3_free(sCheck.aPgRef); + if( sCheck.mallocFailed ){ + sqlite3StrAccumReset(&sCheck.errMsg); + sCheck.nErr++; + } + *pnErr = sCheck.nErr; + if( sCheck.nErr==0 ) sqlite3StrAccumReset(&sCheck.errMsg); + /* Make sure this analysis did not leave any unref() pages. */ + assert( nRef==sqlite3PagerRefcount(pBt->pPager) ); + sqlite3BtreeLeave(p); + return sqlite3StrAccumFinish(&sCheck.errMsg); +} +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ + +/* +** Return the full pathname of the underlying database file. Return +** an empty string if the database is in-memory or a TEMP database. +** +** The pager filename is invariant as long as the pager is +** open so it is safe to access without the BtShared mutex. +*/ +SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *p){ + assert( p->pBt->pPager!=0 ); + return sqlite3PagerFilename(p->pBt->pPager, 1); +} + +/* +** Return the pathname of the journal file for this database. The return +** value of this routine is the same regardless of whether the journal file +** has been created or not. +** +** The pager journal filename is invariant as long as the pager is +** open so it is safe to access without the BtShared mutex. +*/ +SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *p){ + assert( p->pBt->pPager!=0 ); + return sqlite3PagerJournalname(p->pBt->pPager); +} + +/* +** Return non-zero if a transaction is active. +*/ +SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){ + assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); + return (p && (p->inTrans==TRANS_WRITE)); +} + +#ifndef SQLITE_OMIT_WAL +/* +** Run a checkpoint on the Btree passed as the first argument. +** +** Return SQLITE_LOCKED if this or any other connection has an open +** transaction on the shared-cache the argument Btree is connected to. +** +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. +*/ +SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){ + int rc = SQLITE_OK; + if( p ){ + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + if( pBt->inTransaction!=TRANS_NONE ){ + rc = SQLITE_LOCKED; + }else{ + rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt); + } + sqlite3BtreeLeave(p); + } + return rc; +} +#endif + +/* +** Return non-zero if a read (or write) transaction is active. +*/ +SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree *p){ + assert( p ); + assert( sqlite3_mutex_held(p->db->mutex) ); + return p->inTrans!=TRANS_NONE; +} + +SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ + assert( p ); + assert( sqlite3_mutex_held(p->db->mutex) ); + return p->nBackup!=0; +} + +/* +** This function returns a pointer to a blob of memory associated with +** a single shared-btree. The memory is used by client code for its own +** purposes (for example, to store a high-level schema associated with +** the shared-btree). The btree layer manages reference counting issues. +** +** The first time this is called on a shared-btree, nBytes bytes of memory +** are allocated, zeroed, and returned to the caller. For each subsequent +** call the nBytes parameter is ignored and a pointer to the same blob +** of memory returned. +** +** If the nBytes parameter is 0 and the blob of memory has not yet been +** allocated, a null pointer is returned. If the blob has already been +** allocated, it is returned as normal. +** +** Just before the shared-btree is closed, the function passed as the +** xFree argument when the memory allocation was made is invoked on the +** blob of allocated memory. The xFree function should not call sqlite3_free() +** on the memory, the btree layer does that. +*/ +SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ + BtShared *pBt = p->pBt; + sqlite3BtreeEnter(p); + if( !pBt->pSchema && nBytes ){ + pBt->pSchema = sqlite3DbMallocZero(0, nBytes); + pBt->xFreeSchema = xFree; + } + sqlite3BtreeLeave(p); + return pBt->pSchema; +} + +/* +** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared +** btree as the argument handle holds an exclusive lock on the +** sqlite_master table. Otherwise SQLITE_OK. +*/ +SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){ + int rc; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK); + assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE ); + sqlite3BtreeLeave(p); + return rc; +} + + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Obtain a lock on the table whose root page is iTab. The +** lock is a write lock if isWritelock is true or a read lock +** if it is false. +*/ +SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ + int rc = SQLITE_OK; + assert( p->inTrans!=TRANS_NONE ); + if( p->sharable ){ + u8 lockType = READ_LOCK + isWriteLock; + assert( READ_LOCK+1==WRITE_LOCK ); + assert( isWriteLock==0 || isWriteLock==1 ); + + sqlite3BtreeEnter(p); + rc = querySharedCacheTableLock(p, iTab, lockType); + if( rc==SQLITE_OK ){ + rc = setSharedCacheTableLock(p, iTab, lockType); + } + sqlite3BtreeLeave(p); + } + return rc; +} +#endif + +#ifndef SQLITE_OMIT_INCRBLOB +/* +** Argument pCsr must be a cursor opened for writing on an +** INTKEY table currently pointing at a valid table entry. +** This function modifies the data stored as part of that entry. +** +** Only the data content may only be modified, it is not possible to +** change the length of the data stored. If this function is called with +** parameters that attempt to write past the end of the existing data, +** no modifications are made and SQLITE_CORRUPT is returned. +*/ +SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ + int rc; + assert( cursorOwnsBtShared(pCsr) ); + assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); + assert( pCsr->curFlags & BTCF_Incrblob ); + + rc = restoreCursorPosition(pCsr); + if( rc!=SQLITE_OK ){ + return rc; + } + assert( pCsr->eState!=CURSOR_REQUIRESEEK ); + if( pCsr->eState!=CURSOR_VALID ){ + return SQLITE_ABORT; + } + + /* Save the positions of all other cursors open on this table. This is + ** required in case any of them are holding references to an xFetch + ** version of the b-tree page modified by the accessPayload call below. + ** + ** Note that pCsr must be open on a INTKEY table and saveCursorPosition() + ** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence + ** saveAllCursors can only return SQLITE_OK. + */ + VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr); + assert( rc==SQLITE_OK ); + + /* Check some assumptions: + ** (a) the cursor is open for writing, + ** (b) there is a read/write transaction open, + ** (c) the connection holds a write-lock on the table (if required), + ** (d) there are no conflicting read-locks, and + ** (e) the cursor points at a valid row of an intKey table. + */ + if( (pCsr->curFlags & BTCF_WriteFlag)==0 ){ + return SQLITE_READONLY; + } + assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 + && 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 ); + + return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); +} + +/* +** Mark this cursor as an incremental blob cursor. +*/ +SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ + pCur->curFlags |= BTCF_Incrblob; + pCur->pBtree->hasIncrblobCur = 1; +} +#endif + +/* +** Set both the "read version" (single byte at byte offset 18) and +** "write version" (single byte at byte offset 19) fields in the database +** header to iVersion. +*/ +SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ + BtShared *pBt = pBtree->pBt; + int rc; /* Return code */ + + assert( iVersion==1 || iVersion==2 ); + + /* If setting the version fields to 1, do not automatically open the + ** WAL connection, even if the version fields are currently set to 2. + */ + pBt->btsFlags &= ~BTS_NO_WAL; + if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL; + + rc = sqlite3BtreeBeginTrans(pBtree, 0); + if( rc==SQLITE_OK ){ + u8 *aData = pBt->pPage1->aData; + if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){ + rc = sqlite3BtreeBeginTrans(pBtree, 2); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); + if( rc==SQLITE_OK ){ + aData[18] = (u8)iVersion; + aData[19] = (u8)iVersion; + } + } + } + } + + pBt->btsFlags &= ~BTS_NO_WAL; + return rc; +} + +/* +** Return true if the cursor has a hint specified. This routine is +** only used from within assert() statements +*/ +SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){ + return (pCsr->hints & mask)!=0; +} + +/* +** Return true if the given Btree is read-only. +*/ +SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){ + return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; +} + +/* +** Return the size of the header added to each page by this module. +*/ +SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } + +#if !defined(SQLITE_OMIT_SHARED_CACHE) +/* +** Return true if the Btree passed as the only argument is sharable. +*/ +SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ + return p->sharable; +} + +/* +** Return the number of connections to the BtShared object accessed by +** the Btree handle passed as the only argument. For private caches +** this is always 1. For shared caches it may be 1 or greater. +*/ +SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ + testcase( p->sharable ); + return p->pBt->nRef; +} +#endif + +/************** End of btree.c ***********************************************/ +/************** Begin file backup.c ******************************************/ +/* +** 2009 January 28 +** +** 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 the implementation of the sqlite3_backup_XXX() +** API functions and the related features. +*/ +/* #include "sqliteInt.h" */ +/* #include "btreeInt.h" */ + +/* +** Structure allocated for each backup operation. +*/ +struct sqlite3_backup { + sqlite3* pDestDb; /* Destination database handle */ + Btree *pDest; /* Destination b-tree file */ + u32 iDestSchema; /* Original schema cookie in destination */ + int bDestLocked; /* True once a write-transaction is open on pDest */ + + Pgno iNext; /* Page number of the next source page to copy */ + sqlite3* pSrcDb; /* Source database handle */ + Btree *pSrc; /* Source b-tree file */ + + int rc; /* Backup process error code */ + + /* These two variables are set by every call to backup_step(). They are + ** read by calls to backup_remaining() and backup_pagecount(). + */ + Pgno nRemaining; /* Number of pages left to copy */ + Pgno nPagecount; /* Total number of pages to copy */ + + int isAttached; /* True once backup has been registered with pager */ + sqlite3_backup *pNext; /* Next backup associated with source pager */ +}; + +/* +** THREAD SAFETY NOTES: +** +** Once it has been created using backup_init(), a single sqlite3_backup +** structure may be accessed via two groups of thread-safe entry points: +** +** * Via the sqlite3_backup_XXX() API function backup_step() and +** backup_finish(). Both these functions obtain the source database +** handle mutex and the mutex associated with the source BtShared +** structure, in that order. +** +** * Via the BackupUpdate() and BackupRestart() functions, which are +** invoked by the pager layer to report various state changes in +** the page cache associated with the source database. The mutex +** associated with the source database BtShared structure will always +** be held when either of these functions are invoked. +** +** The other sqlite3_backup_XXX() API functions, backup_remaining() and +** backup_pagecount() are not thread-safe functions. If they are called +** while some other thread is calling backup_step() or backup_finish(), +** the values returned may be invalid. There is no way for a call to +** BackupUpdate() or BackupRestart() to interfere with backup_remaining() +** or backup_pagecount(). +** +** Depending on the SQLite configuration, the database handles and/or +** the Btree objects may have their own mutexes that require locking. +** Non-sharable Btrees (in-memory databases for example), do not have +** associated mutexes. +*/ + +/* +** Return a pointer corresponding to database zDb (i.e. "main", "temp") +** in connection handle pDb. If such a database cannot be found, return +** a NULL pointer and write an error message to pErrorDb. +** +** If the "temp" database is requested, it may need to be opened by this +** function. If an error occurs while doing so, return 0 and write an +** error message to pErrorDb. +*/ +static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ + int i = sqlite3FindDbName(pDb, zDb); + + if( i==1 ){ + Parse sParse; + int rc = 0; + memset(&sParse, 0, sizeof(sParse)); + sParse.db = pDb; + if( sqlite3OpenTempDatabase(&sParse) ){ + sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); + rc = SQLITE_ERROR; + } + sqlite3DbFree(pErrorDb, sParse.zErrMsg); + sqlite3ParserReset(&sParse); + if( rc ){ + return 0; + } + } + + if( i<0 ){ + sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb); + return 0; + } + + return pDb->aDb[i].pBt; +} + +/* +** Attempt to set the page size of the destination to match the page size +** of the source. +*/ +static int setDestPgsz(sqlite3_backup *p){ + int rc; + rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0); + return rc; +} + +/* +** Check that there is no open read-transaction on the b-tree passed as the +** second argument. If there is not, return SQLITE_OK. Otherwise, if there +** is an open read-transaction, return SQLITE_ERROR and leave an error +** message in database handle db. +*/ +static int checkReadTransaction(sqlite3 *db, Btree *p){ + if( sqlite3BtreeIsInReadTrans(p) ){ + sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +/* +** Create an sqlite3_backup process to copy the contents of zSrcDb from +** connection handle pSrcDb to zDestDb in pDestDb. If successful, return +** a pointer to the new sqlite3_backup object. +** +** If an error occurs, NULL is returned and an error code and error message +** stored in database handle pDestDb. +*/ +SQLITE_API sqlite3_backup *sqlite3_backup_init( + sqlite3* pDestDb, /* Database to write to */ + const char *zDestDb, /* Name of database within pDestDb */ + sqlite3* pSrcDb, /* Database connection to read from */ + const char *zSrcDb /* Name of database within pSrcDb */ +){ + sqlite3_backup *p; /* Value to return */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(pSrcDb)||!sqlite3SafetyCheckOk(pDestDb) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + + /* Lock the source database handle. The destination database + ** handle is not locked in this routine, but it is locked in + ** sqlite3_backup_step(). The user is required to ensure that no + ** other thread accesses the destination handle for the duration + ** of the backup operation. Any attempt to use the destination + ** database connection while a backup is in progress may cause + ** a malfunction or a deadlock. + */ + sqlite3_mutex_enter(pSrcDb->mutex); + sqlite3_mutex_enter(pDestDb->mutex); + + if( pSrcDb==pDestDb ){ + sqlite3ErrorWithMsg( + pDestDb, SQLITE_ERROR, "source and destination must be distinct" + ); + p = 0; + }else { + /* Allocate space for a new sqlite3_backup object... + ** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a + ** call to sqlite3_backup_init() and is destroyed by a call to + ** sqlite3_backup_finish(). */ + p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup)); + if( !p ){ + sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT); + } + } + + /* If the allocation succeeded, populate the new object. */ + if( p ){ + p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb); + p->pDest = findBtree(pDestDb, pDestDb, zDestDb); + p->pDestDb = pDestDb; + p->pSrcDb = pSrcDb; + p->iNext = 1; + p->isAttached = 0; + + if( 0==p->pSrc || 0==p->pDest + || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK + ){ + /* One (or both) of the named databases did not exist or an OOM + ** error was hit. Or there is a transaction open on the destination + ** database. The error has already been written into the pDestDb + ** handle. All that is left to do here is free the sqlite3_backup + ** structure. */ + sqlite3_free(p); + p = 0; + } + } + if( p ){ + p->pSrc->nBackup++; + } + + sqlite3_mutex_leave(pDestDb->mutex); + sqlite3_mutex_leave(pSrcDb->mutex); + return p; +} + +/* +** Argument rc is an SQLite error code. Return true if this error is +** considered fatal if encountered during a backup operation. All errors +** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED. +*/ +static int isFatalError(int rc){ + return (rc!=SQLITE_OK && rc!=SQLITE_BUSY && ALWAYS(rc!=SQLITE_LOCKED)); +} + +/* +** Parameter zSrcData points to a buffer containing the data for +** page iSrcPg from the source database. Copy this data into the +** destination database. +*/ +static int backupOnePage( + sqlite3_backup *p, /* Backup handle */ + Pgno iSrcPg, /* Source database page to backup */ + const u8 *zSrcData, /* Source database page data */ + int bUpdate /* True for an update, false otherwise */ +){ + Pager * const pDestPager = sqlite3BtreePager(p->pDest); + const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); + int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); + const int nCopy = MIN(nSrcPgsz, nDestPgsz); + const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; +#ifdef SQLITE_HAS_CODEC + /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is + ** guaranteed that the shared-mutex is held by this thread, handle + ** p->pSrc may not actually be the owner. */ + int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); + int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest); +#endif + int rc = SQLITE_OK; + i64 iOff; + + assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 ); + assert( p->bDestLocked ); + assert( !isFatalError(p->rc) ); + assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); + assert( zSrcData ); + + /* Catch the case where the destination is an in-memory database and the + ** page sizes of the source and destination differ. + */ + if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){ + rc = SQLITE_READONLY; + } + +#ifdef SQLITE_HAS_CODEC + /* Backup is not possible if the page size of the destination is changing + ** and a codec is in use. + */ + if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ + rc = SQLITE_READONLY; + } + + /* Backup is not possible if the number of bytes of reserve space differ + ** between source and destination. If there is a difference, try to + ** fix the destination to agree with the source. If that is not possible, + ** then the backup cannot proceed. + */ + if( nSrcReserve!=nDestReserve ){ + u32 newPgsz = nSrcPgsz; + rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); + if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; + } +#endif + + /* This loop runs once for each destination page spanned by the source + ** page. For each iteration, variable iOff is set to the byte offset + ** of the destination page. + */ + for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOffpDest->pBt) ) continue; + if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0)) + && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg)) + ){ + const u8 *zIn = &zSrcData[iOff%nSrcPgsz]; + u8 *zDestData = sqlite3PagerGetData(pDestPg); + u8 *zOut = &zDestData[iOff%nDestPgsz]; + + /* Copy the data from the source page into the destination page. + ** Then clear the Btree layer MemPage.isInit flag. Both this module + ** and the pager code use this trick (clearing the first byte + ** of the page 'extra' space to invalidate the Btree layers + ** cached parse of the page). MemPage.isInit is marked + ** "MUST BE FIRST" for this purpose. + */ + memcpy(zOut, zIn, nCopy); + ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; + if( iOff==0 && bUpdate==0 ){ + sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc)); + } + } + sqlite3PagerUnref(pDestPg); + } + + return rc; +} + +/* +** If pFile is currently larger than iSize bytes, then truncate it to +** exactly iSize bytes. If pFile is not larger than iSize bytes, then +** this function is a no-op. +** +** Return SQLITE_OK if everything is successful, or an SQLite error +** code if an error occurs. +*/ +static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){ + i64 iCurrent; + int rc = sqlite3OsFileSize(pFile, &iCurrent); + if( rc==SQLITE_OK && iCurrent>iSize ){ + rc = sqlite3OsTruncate(pFile, iSize); + } + return rc; +} + +/* +** Register this backup object with the associated source pager for +** callbacks when pages are changed or the cache invalidated. +*/ +static void attachBackupObject(sqlite3_backup *p){ + sqlite3_backup **pp; + assert( sqlite3BtreeHoldsMutex(p->pSrc) ); + pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); + p->pNext = *pp; + *pp = p; + p->isAttached = 1; +} + +/* +** Copy nPage pages from the source b-tree to the destination. +*/ +SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ + int rc; + int destMode; /* Destination journal mode */ + int pgszSrc = 0; /* Source page size */ + int pgszDest = 0; /* Destination page size */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(p->pSrcDb->mutex); + sqlite3BtreeEnter(p->pSrc); + if( p->pDestDb ){ + sqlite3_mutex_enter(p->pDestDb->mutex); + } + + rc = p->rc; + if( !isFatalError(rc) ){ + Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ + Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ + int ii; /* Iterator variable */ + int nSrcPage = -1; /* Size of source db in pages */ + int bCloseTrans = 0; /* True if src db requires unlocking */ + + /* If the source pager is currently in a write-transaction, return + ** SQLITE_BUSY immediately. + */ + if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){ + rc = SQLITE_BUSY; + }else{ + rc = SQLITE_OK; + } + + /* If there is no open read-transaction on the source database, open + ** one now. If a transaction is opened here, then it will be closed + ** before this function exits. + */ + if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){ + rc = sqlite3BtreeBeginTrans(p->pSrc, 0); + bCloseTrans = 1; + } + + /* If the destination database has not yet been locked (i.e. if this + ** is the first call to backup_step() for the current backup operation), + ** try to set its page size to the same as the source database. This + ** is especially important on ZipVFS systems, as in that case it is + ** not possible to create a database file that uses one page size by + ** writing to it with another. */ + if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){ + rc = SQLITE_NOMEM; + } + + /* Lock the destination database, if it is not locked already. */ + if( SQLITE_OK==rc && p->bDestLocked==0 + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) + ){ + p->bDestLocked = 1; + sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); + } + + /* Do not allow backup if the destination database is in WAL mode + ** and the page sizes are different between source and destination */ + pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); + pgszDest = sqlite3BtreeGetPageSize(p->pDest); + destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); + if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){ + rc = SQLITE_READONLY; + } + + /* Now that there is a read-lock on the source database, query the + ** source pager for the number of pages in the database. + */ + nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc); + assert( nSrcPage>=0 ); + for(ii=0; (nPage<0 || iiiNext<=(Pgno)nSrcPage && !rc; ii++){ + const Pgno iSrcPg = p->iNext; /* Source page number */ + if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ + DbPage *pSrcPg; /* Source page object */ + rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY); + if( rc==SQLITE_OK ){ + rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0); + sqlite3PagerUnref(pSrcPg); + } + } + p->iNext++; + } + if( rc==SQLITE_OK ){ + p->nPagecount = nSrcPage; + p->nRemaining = nSrcPage+1-p->iNext; + if( p->iNext>(Pgno)nSrcPage ){ + rc = SQLITE_DONE; + }else if( !p->isAttached ){ + attachBackupObject(p); + } + } + + /* Update the schema version field in the destination database. This + ** is to make sure that the schema-version really does change in + ** the case where the source and destination databases have the + ** same schema version. + */ + if( rc==SQLITE_DONE ){ + if( nSrcPage==0 ){ + rc = sqlite3BtreeNewDb(p->pDest); + nSrcPage = 1; + } + if( rc==SQLITE_OK || rc==SQLITE_DONE ){ + rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); + } + if( rc==SQLITE_OK ){ + if( p->pDestDb ){ + sqlite3ResetAllSchemasOfConnection(p->pDestDb); + } + if( destMode==PAGER_JOURNALMODE_WAL ){ + rc = sqlite3BtreeSetVersion(p->pDest, 2); + } + } + if( rc==SQLITE_OK ){ + int nDestTruncate; + /* Set nDestTruncate to the final number of pages in the destination + ** database. The complication here is that the destination page + ** size may be different to the source page size. + ** + ** If the source page size is smaller than the destination page size, + ** round up. In this case the call to sqlite3OsTruncate() below will + ** fix the size of the file. However it is important to call + ** sqlite3PagerTruncateImage() here so that any pages in the + ** destination file that lie beyond the nDestTruncate page mark are + ** journalled by PagerCommitPhaseOne() before they are destroyed + ** by the file truncation. + */ + assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) ); + assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) ); + if( pgszSrcpDest->pBt) ){ + nDestTruncate--; + } + }else{ + nDestTruncate = nSrcPage * (pgszSrc/pgszDest); + } + assert( nDestTruncate>0 ); + + if( pgszSrc= iSize || ( + nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) + && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest + )); + + /* This block ensures that all data required to recreate the original + ** database has been stored in the journal for pDestPager and the + ** journal synced to disk. So at this point we may safely modify + ** the database file in any way, knowing that if a power failure + ** occurs, the original database will be reconstructed from the + ** journal file. */ + sqlite3PagerPagecount(pDestPager, &nDstPage); + for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){ + if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){ + DbPage *pPg; + rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pPg); + sqlite3PagerUnref(pPg); + } + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); + } + + /* Write the extra pages and truncate the database file as required */ + iEnd = MIN(PENDING_BYTE + pgszDest, iSize); + for( + iOff=PENDING_BYTE+pgszSrc; + rc==SQLITE_OK && iOffpDest, 0)) + ){ + rc = SQLITE_DONE; + } + } + } + + /* If bCloseTrans is true, then this function opened a read transaction + ** on the source database. Close the read transaction here. There is + ** no need to check the return values of the btree methods here, as + ** "committing" a read-only transaction cannot fail. + */ + if( bCloseTrans ){ + TESTONLY( int rc2 ); + TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0); + TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0); + assert( rc2==SQLITE_OK ); + } + + if( rc==SQLITE_IOERR_NOMEM ){ + rc = SQLITE_NOMEM_BKPT; + } + p->rc = rc; + } + if( p->pDestDb ){ + sqlite3_mutex_leave(p->pDestDb->mutex); + } + sqlite3BtreeLeave(p->pSrc); + sqlite3_mutex_leave(p->pSrcDb->mutex); + return rc; +} + +/* +** Release all resources associated with an sqlite3_backup* handle. +*/ +SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){ + sqlite3_backup **pp; /* Ptr to head of pagers backup list */ + sqlite3 *pSrcDb; /* Source database connection */ + int rc; /* Value to return */ + + /* Enter the mutexes */ + if( p==0 ) return SQLITE_OK; + pSrcDb = p->pSrcDb; + sqlite3_mutex_enter(pSrcDb->mutex); + sqlite3BtreeEnter(p->pSrc); + if( p->pDestDb ){ + sqlite3_mutex_enter(p->pDestDb->mutex); + } + + /* Detach this backup from the source pager. */ + if( p->pDestDb ){ + p->pSrc->nBackup--; + } + if( p->isAttached ){ + pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); + while( *pp!=p ){ + pp = &(*pp)->pNext; + } + *pp = p->pNext; + } + + /* If a transaction is still open on the Btree, roll it back. */ + sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); + + /* Set the error code of the destination database handle. */ + rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; + if( p->pDestDb ){ + sqlite3Error(p->pDestDb, rc); + + /* Exit the mutexes and free the backup context structure. */ + sqlite3LeaveMutexAndCloseZombie(p->pDestDb); + } + sqlite3BtreeLeave(p->pSrc); + if( p->pDestDb ){ + /* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a + ** call to sqlite3_backup_init() and is destroyed by a call to + ** sqlite3_backup_finish(). */ + sqlite3_free(p); + } + sqlite3LeaveMutexAndCloseZombie(pSrcDb); + return rc; +} + +/* +** Return the number of pages still to be backed up as of the most recent +** call to sqlite3_backup_step(). +*/ +SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return p->nRemaining; +} + +/* +** Return the total number of pages in the source database as of the most +** recent call to sqlite3_backup_step(). +*/ +SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( p==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return p->nPagecount; +} + +/* +** This function is called after the contents of page iPage of the +** source database have been modified. If page iPage has already been +** copied into the destination database, then the data written to the +** destination is now invalidated. The destination copy of iPage needs +** to be updated with the new data before the backup operation is +** complete. +** +** It is assumed that the mutex associated with the BtShared object +** corresponding to the source database is held when this function is +** called. +*/ +static SQLITE_NOINLINE void backupUpdate( + sqlite3_backup *p, + Pgno iPage, + const u8 *aData +){ + assert( p!=0 ); + do{ + assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); + if( !isFatalError(p->rc) && iPageiNext ){ + /* The backup process p has already copied page iPage. But now it + ** has been modified by a transaction on the source pager. Copy + ** the new data into the backup. + */ + int rc; + assert( p->pDestDb ); + sqlite3_mutex_enter(p->pDestDb->mutex); + rc = backupOnePage(p, iPage, aData, 1); + sqlite3_mutex_leave(p->pDestDb->mutex); + assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); + if( rc!=SQLITE_OK ){ + p->rc = rc; + } + } + }while( (p = p->pNext)!=0 ); +} +SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){ + if( pBackup ) backupUpdate(pBackup, iPage, aData); +} + +/* +** Restart the backup process. This is called when the pager layer +** detects that the database has been modified by an external database +** connection. In this case there is no way of knowing which of the +** pages that have been copied into the destination database are still +** valid and which are not, so the entire process needs to be restarted. +** +** It is assumed that the mutex associated with the BtShared object +** corresponding to the source database is held when this function is +** called. +*/ +SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *pBackup){ + sqlite3_backup *p; /* Iterator variable */ + for(p=pBackup; p; p=p->pNext){ + assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); + p->iNext = 1; + } +} + +#ifndef SQLITE_OMIT_VACUUM +/* +** Copy the complete content of pBtFrom into pBtTo. A transaction +** must be active for both files. +** +** The size of file pTo may be reduced by this operation. If anything +** goes wrong, the transaction on pTo is rolled back. If successful, the +** transaction is committed before returning. +*/ +SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ + int rc; + sqlite3_file *pFd; /* File descriptor for database pTo */ + sqlite3_backup b; + sqlite3BtreeEnter(pTo); + sqlite3BtreeEnter(pFrom); + + assert( sqlite3BtreeIsInTrans(pTo) ); + pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); + if( pFd->pMethods ){ + i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); + rc = sqlite3OsFileControl(pFd, SQLITE_FCNTL_OVERWRITE, &nByte); + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; + if( rc ) goto copy_finished; + } + + /* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set + ** to 0. This is used by the implementations of sqlite3_backup_step() + ** and sqlite3_backup_finish() to detect that they are being called + ** from this function, not directly by the user. + */ + memset(&b, 0, sizeof(b)); + b.pSrcDb = pFrom->db; + b.pSrc = pFrom; + b.pDest = pTo; + b.iNext = 1; + +#ifdef SQLITE_HAS_CODEC + sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom)); +#endif + + /* 0x7FFFFFFF is the hard limit for the number of pages in a database + ** file. By passing this as the number of pages to copy to + ** sqlite3_backup_step(), we can guarantee that the copy finishes + ** within a single call (unless an error occurs). The assert() statement + ** checks this assumption - (p->rc) should be set to either SQLITE_DONE + ** or an error code. */ + sqlite3_backup_step(&b, 0x7FFFFFFF); + assert( b.rc!=SQLITE_OK ); + + rc = sqlite3_backup_finish(&b); + if( rc==SQLITE_OK ){ + pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; + }else{ + sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); + } + + assert( sqlite3BtreeIsInTrans(pTo)==0 ); +copy_finished: + sqlite3BtreeLeave(pFrom); + sqlite3BtreeLeave(pTo); + return rc; +} +#endif /* SQLITE_OMIT_VACUUM */ + +/************** End of backup.c **********************************************/ +/************** Begin file vdbemem.c *****************************************/ +/* +** 2004 May 26 +** +** 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 use to manipulate "Mem" structure. A "Mem" +** stores a single value in the VDBE. Mem is an opaque structure visible +** only within the VDBE. Interface routines refer to a Mem using the +** name sqlite_value +*/ +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +#ifdef SQLITE_DEBUG +/* +** Check invariants on a Mem object. +** +** This routine is intended for use inside of assert() statements, like +** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); +*/ +SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ + /* If MEM_Dyn is set then Mem.xDel!=0. + ** Mem.xDel is might not be initialized if MEM_Dyn is clear. + */ + assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); + + /* MEM_Dyn may only be set if Mem.szMalloc==0. In this way we + ** ensure that if Mem.szMalloc>0 then it is safe to do + ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn. + ** That saves a few cycles in inner loops. */ + assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); + + /* Cannot be both MEM_Int and MEM_Real at the same time */ + assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); + + /* Cannot be both MEM_Null and some other type */ + assert( (p->flags & MEM_Null)==0 || + (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob))==0 ); + + /* The szMalloc field holds the correct memory allocation size */ + assert( p->szMalloc==0 + || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) ); + + /* If p holds a string or blob, the Mem.z must point to exactly + ** one of the following: + ** + ** (1) Memory in Mem.zMalloc and managed by the Mem object + ** (2) Memory to be freed using Mem.xDel + ** (3) An ephemeral string or blob + ** (4) A static string or blob + */ + if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){ + assert( + ((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) + + ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + + ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 + ); + } + return 1; +} +#endif + + +/* +** If pMem is an object with a valid string representation, this routine +** ensures the internal encoding for the string representation is +** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE. +** +** If pMem is not a string object, or the encoding of the string +** representation is already stored using the requested encoding, then this +** routine is a no-op. +** +** SQLITE_OK is returned if the conversion is successful (or not required). +** SQLITE_NOMEM may be returned if a malloc() fails during conversion +** between formats. +*/ +SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ +#ifndef SQLITE_OMIT_UTF16 + int rc; +#endif + assert( (pMem->flags&MEM_RowSet)==0 ); + assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE + || desiredEnc==SQLITE_UTF16BE ); + if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ + return SQLITE_OK; + } + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); +#ifdef SQLITE_OMIT_UTF16 + return SQLITE_ERROR; +#else + + /* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned, + ** then the encoding of the value may not have changed. + */ + rc = sqlite3VdbeMemTranslate(pMem, (u8)desiredEnc); + assert(rc==SQLITE_OK || rc==SQLITE_NOMEM); + assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); + assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); + return rc; +#endif +} + +/* +** Make sure pMem->z points to a writable allocation of at least +** min(n,32) bytes. +** +** If the bPreserve argument is true, then copy of the content of +** pMem->z into the new allocation. pMem must be either a string or +** blob if bPreserve is true. If bPreserve is false, any prior content +** in pMem->z is discarded. +*/ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ + assert( sqlite3VdbeCheckMemInvariants(pMem) ); + assert( (pMem->flags&MEM_RowSet)==0 ); + testcase( pMem->db==0 ); + + /* If the bPreserve flag is set to true, then the memory cell must already + ** contain a valid string or blob value. */ + assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) ); + testcase( bPreserve && pMem->z==0 ); + + 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 ){ + pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); + bPreserve = 0; + }else{ + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); + pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); + } + if( pMem->zMalloc==0 ){ + sqlite3VdbeMemSetNull(pMem); + pMem->z = 0; + pMem->szMalloc = 0; + return SQLITE_NOMEM_BKPT; + }else{ + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + } + + if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){ + memcpy(pMem->zMalloc, pMem->z, pMem->n); + } + if( (pMem->flags&MEM_Dyn)!=0 ){ + assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC ); + pMem->xDel((void *)(pMem->z)); + } + + pMem->z = pMem->zMalloc; + pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static); + return SQLITE_OK; +} + +/* +** Change the pMem->zMalloc allocation to be at least szNew bytes. +** If pMem->zMalloc already meets or exceeds the requested size, this +** routine is a no-op. +** +** Any prior string or blob content in the pMem object may be discarded. +** The pMem->xDel destructor is called, if it exists. Though MEM_Str +** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null +** values are preserved. +** +** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) +** if unable to complete the resizing. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ + assert( szNew>0 ); + assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); + if( pMem->szMallocflags & MEM_Dyn)==0 ); + pMem->z = pMem->zMalloc; + pMem->flags &= (MEM_Null|MEM_Int|MEM_Real); + 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. +** +** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( (pMem->flags&MEM_RowSet)==0 ); + 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; + } + } + pMem->flags &= ~MEM_Ephem; +#ifdef SQLITE_DEBUG + pMem->pScopyFrom = 0; +#endif + + return SQLITE_OK; +} + +/* +** If the given Mem* has a zero-filled tail, turn it into an ordinary +** blob stored in dynamically allocated space. +*/ +#ifndef SQLITE_OMIT_INCRBLOB +SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ + int nByte; + assert( pMem->flags & MEM_Zero ); + assert( pMem->flags&MEM_Blob ); + assert( (pMem->flags&MEM_RowSet)==0 ); + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + + /* Set nByte to the number of bytes required to store the expanded blob. */ + nByte = pMem->n + pMem->u.nZero; + if( nByte<=0 ){ + nByte = 1; + } + if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ + return SQLITE_NOMEM_BKPT; + } + + memset(&pMem->z[pMem->n], 0, pMem->u.nZero); + pMem->n += pMem->u.nZero; + pMem->flags &= ~(MEM_Zero|MEM_Term); + return SQLITE_OK; +} +#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){ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); + testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 ); + if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){ + return SQLITE_OK; /* Nothing to do */ + }else{ + return vdbeMemAddTerminator(pMem); + } +} + +/* +** Add MEM_Str to the set of representations for the given Mem. Numbers +** are converted using sqlite3_snprintf(). Converting a BLOB to a string +** is a no-op. +** +** Existing representations MEM_Int and MEM_Real are invalidated if +** bForce is true but are retained if bForce is false. +** +** A MEM_Null value will never be passed to this function. This function is +** used for converting values to text for returning to the user (i.e. via +** sqlite3_value_text()), or for ensuring that values to be used as btree +** keys are strings. In the former case a NULL pointer is returned the +** user and the latter is an internal programming error. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ + int fg = pMem->flags; + const int nByte = 32; + + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( !(fg&MEM_Zero) ); + assert( !(fg&(MEM_Str|MEM_Blob)) ); + assert( fg&(MEM_Int|MEM_Real) ); + assert( (pMem->flags&MEM_RowSet)==0 ); + assert( EIGHT_BYTE_ALIGNMENT(pMem) ); + + + if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ + pMem->enc = 0; + return SQLITE_NOMEM_BKPT; + } + + /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 + ** string representation of the value. Then, if the required encoding + ** is UTF-16le or UTF-16be do a translation. + ** + ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. + */ + if( fg & MEM_Int ){ + sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); + }else{ + assert( fg & MEM_Real ); + sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); + } + pMem->n = sqlite3Strlen30(pMem->z); + pMem->enc = SQLITE_UTF8; + pMem->flags |= MEM_Str|MEM_Term; + if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); + sqlite3VdbeChangeEncoding(pMem, enc); + return SQLITE_OK; +} + +/* +** Memory cell pMem contains the context of an aggregate function. +** This routine calls the finalize method for that function. The +** result of the aggregate is stored back into pMem. +** +** Return SQLITE_ERROR if the finalizer reports an error. SQLITE_OK +** otherwise. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ + int rc = SQLITE_OK; + if( ALWAYS(pFunc && pFunc->xFinalize) ){ + sqlite3_context ctx; + Mem t; + assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + memset(&ctx, 0, sizeof(ctx)); + memset(&t, 0, sizeof(t)); + t.flags = MEM_Null; + t.db = pMem->db; + ctx.pOut = &t; + ctx.pMem = pMem; + ctx.pFunc = pFunc; + pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ + assert( (pMem->flags & MEM_Dyn)==0 ); + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); + memcpy(pMem, &t, sizeof(t)); + rc = ctx.isError; + } + return rc; +} + +/* +** If the memory cell contains a value that must be freed by +** invoking the external callback in Mem.xDel, then this routine +** will free that value. It also sets Mem.flags to MEM_Null. +** +** This is a helper routine for sqlite3VdbeMemSetNull() and +** for sqlite3VdbeMemRelease(). Use those other routines as the +** entry point for releasing Mem resources. +*/ +static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ + assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); + assert( VdbeMemDynamic(p) ); + if( p->flags&MEM_Agg ){ + sqlite3VdbeMemFinalize(p, p->u.pDef); + assert( (p->flags & MEM_Agg)==0 ); + testcase( p->flags & MEM_Dyn ); + } + if( p->flags&MEM_Dyn ){ + assert( (p->flags&MEM_RowSet)==0 ); + assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); + p->xDel((void *)p->z); + }else if( p->flags&MEM_RowSet ){ + sqlite3RowSetClear(p->u.pRowSet); + }else if( p->flags&MEM_Frame ){ + VdbeFrame *pFrame = p->u.pFrame; + pFrame->pParent = pFrame->v->pDelFrame; + pFrame->v->pDelFrame = pFrame; + } + p->flags = MEM_Null; +} + +/* +** Release memory held by the Mem p, both external memory cleared +** by p->xDel and memory in p->zMalloc. +** +** This is a helper routine invoked by sqlite3VdbeMemRelease() in +** the unusual case where there really is memory in p that needs +** to be freed. +*/ +static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ + if( VdbeMemDynamic(p) ){ + vdbeMemClearExternAndSetNull(p); + } + if( p->szMalloc ){ + sqlite3DbFreeNN(p->db, p->zMalloc); + p->szMalloc = 0; + } + p->z = 0; +} + +/* +** Release any memory resources held by the Mem. Both the memory that is +** free by Mem.xDel and the Mem.zMalloc allocation are freed. +** +** Use this routine prior to clean up prior to abandoning a Mem, or to +** reset a Mem back to its minimum memory utilization. +** +** Use sqlite3VdbeMemSetNull() to release just the Mem.xDel space +** prior to inserting new content into the Mem. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ + assert( sqlite3VdbeCheckMemInvariants(p) ); + if( VdbeMemDynamic(p) || p->szMalloc ){ + vdbeMemClear(p); + } +} + +/* +** Convert a 64-bit IEEE double into a 64-bit signed integer. +** If the double is out of range of a 64-bit signed integer then +** return the closest available 64-bit signed integer. +*/ +static SQLITE_NOINLINE i64 doubleToInt64(double r){ +#ifdef SQLITE_OMIT_FLOATING_POINT + /* When floating-point is omitted, double and int64 are the same thing */ + return r; +#else + /* + ** Many compilers we encounter do not define constants for the + ** minimum and maximum 64-bit integers, or they define them + ** inconsistently. And many do not understand the "LL" notation. + ** So we define our own static constants here using nothing + ** larger than a 32-bit integer constant. + */ + static const i64 maxInt = LARGEST_INT64; + static const i64 minInt = SMALLEST_INT64; + + if( r<=(double)minInt ){ + return minInt; + }else if( r>=(double)maxInt ){ + return maxInt; + }else{ + return (i64)r; + } +#endif +} + +/* +** Return some kind of integer value which is the best we can do +** at representing the value that *pMem describes as an integer. +** If pMem is an integer, then the value is exact. If pMem is +** a floating-point then the value returned is the integer part. +** If pMem is a string or blob, then we make an attempt to convert +** it into an integer and return that. If pMem represents an +** an SQL-NULL value, return 0. +** +** If pMem represents a string value, its encoding might be changed. +*/ +static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){ + i64 value = 0; + sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); + return value; +} +SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ + int flags; + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( EIGHT_BYTE_ALIGNMENT(pMem) ); + flags = pMem->flags; + if( flags & MEM_Int ){ + return pMem->u.i; + }else if( flags & MEM_Real ){ + return doubleToInt64(pMem->u.r); + }else if( flags & (MEM_Str|MEM_Blob) ){ + assert( pMem->z || pMem->n==0 ); + return memIntValue(pMem); + }else{ + return 0; + } +} + +/* +** Return the best representation of pMem that we can get into a +** double. If pMem is already a double or an integer, return its +** value. If it is a string or blob, try to convert it to a double. +** If it is a NULL, return 0.0. +*/ +static SQLITE_NOINLINE double memRealValue(Mem *pMem){ + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + double val = (double)0; + sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); + return val; +} +SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( EIGHT_BYTE_ALIGNMENT(pMem) ); + if( pMem->flags & MEM_Real ){ + return pMem->u.r; + }else if( pMem->flags & MEM_Int ){ + return (double)pMem->u.i; + }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ + return memRealValue(pMem); + }else{ + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + return (double)0; + } +} + +/* +** The MEM structure is already a MEM_Real. Try to also make it a +** MEM_Int if we can. +*/ +SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ + i64 ix; + assert( pMem->flags & MEM_Real ); + assert( (pMem->flags & MEM_RowSet)==0 ); + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( EIGHT_BYTE_ALIGNMENT(pMem) ); + + ix = doubleToInt64(pMem->u.r); + + /* Only mark the value as an integer if + ** + ** (1) the round-trip conversion real->int->real is a no-op, and + ** (2) The integer is neither the largest nor the smallest + ** possible integer (ticket #3922) + ** + ** The second and third terms in the following conditional enforces + ** the second condition under the assumption that addition overflow causes + ** values to wrap around. + */ + if( pMem->u.r==ix && ix>SMALLEST_INT64 && ixu.i = ix; + MemSetTypeFlag(pMem, MEM_Int); + } +} + +/* +** Convert pMem to type integer. Invalidate any prior representations. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( (pMem->flags & MEM_RowSet)==0 ); + assert( EIGHT_BYTE_ALIGNMENT(pMem) ); + + pMem->u.i = sqlite3VdbeIntValue(pMem); + MemSetTypeFlag(pMem, MEM_Int); + return SQLITE_OK; +} + +/* +** Convert pMem so that it is of type MEM_Real. +** Invalidate any prior representations. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( EIGHT_BYTE_ALIGNMENT(pMem) ); + + pMem->u.r = sqlite3VdbeRealValue(pMem); + MemSetTypeFlag(pMem, MEM_Real); + return SQLITE_OK; +} + +/* +** Convert pMem so that it has types MEM_Real or MEM_Int or both. +** Invalidate any prior representations. +** +** Every effort is made to force the conversion, even if the input +** is a string that does not look completely like a number. Convert +** as much of the string as we can and ignore the rest. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ + if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ + 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) ){ + MemSetTypeFlag(pMem, MEM_Int); + }else{ + pMem->u.r = sqlite3VdbeRealValue(pMem); + MemSetTypeFlag(pMem, MEM_Real); + sqlite3VdbeIntegerAffinity(pMem); + } + } + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); + pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero); + return SQLITE_OK; +} + +/* +** Cast the datatype of the value in pMem according to the affinity +** "aff". Casting is different from applying affinity in that a cast +** is forced. In other words, the value is converted into the desired +** affinity even if that results in loss of data. This routine is +** used (for example) to implement the SQL "cast()" operator. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ + if( pMem->flags & MEM_Null ) return; + switch( aff ){ + case SQLITE_AFF_BLOB: { /* Really a cast to BLOB */ + if( (pMem->flags & MEM_Blob)==0 ){ + sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); + assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); + if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob); + }else{ + pMem->flags &= ~(MEM_TypeMask&~MEM_Blob); + } + break; + } + case SQLITE_AFF_NUMERIC: { + sqlite3VdbeMemNumerify(pMem); + break; + } + case SQLITE_AFF_INTEGER: { + sqlite3VdbeMemIntegerify(pMem); + break; + } + case SQLITE_AFF_REAL: { + sqlite3VdbeMemRealify(pMem); + break; + } + default: { + assert( aff==SQLITE_AFF_TEXT ); + assert( MEM_Str==(MEM_Blob>>3) ); + pMem->flags |= (pMem->flags&MEM_Blob)>>3; + sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); + assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); + pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); + break; + } + } +} + +/* +** Initialize bulk memory to be a consistent Mem object. +** +** The minimum amount of initialization feasible is performed. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){ + assert( (flags & ~MEM_TypeMask)==0 ); + pMem->flags = flags; + pMem->db = db; + pMem->szMalloc = 0; +} + + +/* +** Delete any previous value and set the value stored in *pMem to NULL. +** +** This routine calls the Mem.xDel destructor to dispose of values that +** require the destructor. But it preserves the Mem.zMalloc memory allocation. +** To free all resources, use sqlite3VdbeMemRelease(), which both calls this +** routine to invoke the destructor and deallocates Mem.zMalloc. +** +** Use this routine to reset the Mem prior to insert a new value. +** +** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){ + if( VdbeMemDynamic(pMem) ){ + vdbeMemClearExternAndSetNull(pMem); + }else{ + pMem->flags = MEM_Null; + } +} +SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){ + sqlite3VdbeMemSetNull((Mem*)p); +} + +/* +** Delete any previous value and set the value to be a BLOB of length +** n containing all zeros. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ + sqlite3VdbeMemRelease(pMem); + pMem->flags = MEM_Blob|MEM_Zero; + pMem->n = 0; + if( n<0 ) n = 0; + pMem->u.nZero = n; + pMem->enc = SQLITE_UTF8; + pMem->z = 0; +} + +/* +** The pMem is known to contain content that needs to be destroyed prior +** to a value change. So invoke the destructor, then set the value to +** a 64-bit integer. +*/ +static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){ + sqlite3VdbeMemSetNull(pMem); + pMem->u.i = val; + pMem->flags = MEM_Int; +} + +/* +** Delete any previous value and set the value stored in *pMem to val, +** manifest type INTEGER. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ + if( VdbeMemDynamic(pMem) ){ + vdbeReleaseAndSetInt64(pMem, val); + }else{ + pMem->u.i = val; + pMem->flags = MEM_Int; + } +} + +#ifndef SQLITE_OMIT_FLOATING_POINT +/* +** Delete any previous value and set the value stored in *pMem to val, +** manifest type REAL. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ + sqlite3VdbeMemSetNull(pMem); + if( !sqlite3IsNaN(val) ){ + pMem->u.r = val; + pMem->flags = MEM_Real; + } +} +#endif + +/* +** Delete any previous value and set the value of pMem to be an +** empty boolean index. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){ + sqlite3 *db = pMem->db; + assert( db!=0 ); + assert( (pMem->flags & MEM_RowSet)==0 ); + sqlite3VdbeMemRelease(pMem); + pMem->zMalloc = sqlite3DbMallocRawNN(db, 64); + if( db->mallocFailed ){ + pMem->flags = MEM_Null; + pMem->szMalloc = 0; + }else{ + assert( pMem->zMalloc ); + pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc); + pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc); + assert( pMem->u.pRowSet!=0 ); + pMem->flags = MEM_RowSet; + } +} + +/* +** Return true if the Mem object contains a TEXT or BLOB that is +** too large - whose size exceeds SQLITE_MAX_LENGTH. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ + assert( p->db!=0 ); + if( p->flags & (MEM_Str|MEM_Blob) ){ + int n = p->n; + if( p->flags & MEM_Zero ){ + n += p->u.nZero; + } + return n>p->db->aLimit[SQLITE_LIMIT_LENGTH]; + } + return 0; +} + +#ifdef SQLITE_DEBUG +/* +** This routine prepares a memory cell for modification by breaking +** its link to a shallow copy and by marking any current shallow +** copies of this cell as invalid. +** +** This is used for testing and debugging only - to make sure shallow +** copies are not misused. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ + int i; + Mem *pX; + for(i=0, pX=pVdbe->aMem; inMem; i++, pX++){ + if( pX->pScopyFrom==pMem ){ + pX->flags |= MEM_Undefined; + pX->pScopyFrom = 0; + } + } + pMem->pScopyFrom = 0; +} +#endif /* SQLITE_DEBUG */ + + +/* +** Make an shallow copy of pFrom into pTo. Prior contents of +** pTo are freed. The pFrom->z field is not duplicated. If +** pFrom->z is used, then pTo->z points to the same thing as pFrom->z +** and flags gets srcType (either MEM_Ephem or MEM_Static). +*/ +static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){ + vdbeMemClearExternAndSetNull(pTo); + assert( !VdbeMemDynamic(pTo) ); + sqlite3VdbeMemShallowCopy(pTo, pFrom, eType); +} +SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ + assert( (pFrom->flags & MEM_RowSet)==0 ); + assert( pTo->db==pFrom->db ); + if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; } + memcpy(pTo, pFrom, MEMCELLSIZE); + if( (pFrom->flags&MEM_Static)==0 ){ + pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); + assert( srcType==MEM_Ephem || srcType==MEM_Static ); + pTo->flags |= srcType; + } +} + +/* +** Make a full copy of pFrom into pTo. Prior contents of pTo are +** freed before the copy is made. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ + int rc = SQLITE_OK; + + assert( (pFrom->flags & MEM_RowSet)==0 ); + if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); + memcpy(pTo, pFrom, MEMCELLSIZE); + pTo->flags &= ~MEM_Dyn; + if( pTo->flags&(MEM_Str|MEM_Blob) ){ + if( 0==(pFrom->flags&MEM_Static) ){ + pTo->flags |= MEM_Ephem; + rc = sqlite3VdbeMemMakeWriteable(pTo); + } + } + + return rc; +} + +/* +** Transfer the contents of pFrom to pTo. Any existing value in pTo is +** freed. If pFrom contains ephemeral data, a copy is made. +** +** pFrom contains an SQL NULL when this routine returns. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ + assert( pFrom->db==0 || sqlite3_mutex_held(pFrom->db->mutex) ); + assert( pTo->db==0 || sqlite3_mutex_held(pTo->db->mutex) ); + assert( pFrom->db==0 || pTo->db==0 || pFrom->db==pTo->db ); + + sqlite3VdbeMemRelease(pTo); + memcpy(pTo, pFrom, sizeof(Mem)); + pFrom->flags = MEM_Null; + pFrom->szMalloc = 0; +} + +/* +** Change the value of a Mem to be a string or a BLOB. +** +** The memory management strategy depends on the value of the xDel +** parameter. If the value passed is SQLITE_TRANSIENT, then the +** string is copied into a (possibly existing) buffer managed by the +** Mem structure. Otherwise, any existing buffer is freed and the +** pointer copied. +** +** If the string is too large (if it exceeds the SQLITE_LIMIT_LENGTH +** size limit) then no memory allocation occurs. If the string can be +** stored without allocating memory, then it is. If a memory allocation +** is required to store the string, then value of pMem is unchanged. In +** either case, SQLITE_TOOBIG is returned. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemSetStr( + Mem *pMem, /* Memory cell to set to string value */ + const char *z, /* String pointer */ + int n, /* Bytes in string, or negative */ + u8 enc, /* Encoding of z. 0 for BLOBs */ + void (*xDel)(void*) /* Destructor function */ +){ + int nByte = n; /* New value for pMem->n */ + int iLimit; /* Maximum allowed string or blob size */ + u16 flags = 0; /* New value for pMem->flags */ + + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( (pMem->flags & MEM_RowSet)==0 ); + + /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ + if( !z ){ + sqlite3VdbeMemSetNull(pMem); + return SQLITE_OK; + } + + if( pMem->db ){ + iLimit = pMem->db->aLimit[SQLITE_LIMIT_LENGTH]; + }else{ + iLimit = SQLITE_MAX_LENGTH; + } + flags = (enc==0?MEM_Blob:MEM_Str); + if( nByte<0 ){ + assert( enc!=0 ); + if( enc==SQLITE_UTF8 ){ + nByte = sqlite3Strlen30(z); + if( nByte>iLimit ) nByte = iLimit+1; + }else{ + for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} + } + flags |= MEM_Term; + } + + /* The following block sets the new values of Mem.z and Mem.xDel. It + ** also sets a flag in local variable "flags" to indicate the memory + ** management (one of MEM_Dyn or MEM_Static). + */ + if( xDel==SQLITE_TRANSIENT ){ + int nAlloc = nByte; + if( flags&MEM_Term ){ + nAlloc += (enc==SQLITE_UTF8?1:2); + } + if( nByte>iLimit ){ + return SQLITE_TOOBIG; + } + testcase( nAlloc==0 ); + testcase( nAlloc==31 ); + testcase( nAlloc==32 ); + if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ + return SQLITE_NOMEM_BKPT; + } + memcpy(pMem->z, z, nAlloc); + }else if( xDel==SQLITE_DYNAMIC ){ + sqlite3VdbeMemRelease(pMem); + pMem->zMalloc = pMem->z = (char *)z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + }else{ + sqlite3VdbeMemRelease(pMem); + pMem->z = (char *)z; + pMem->xDel = xDel; + flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + } + + pMem->n = nByte; + pMem->flags = flags; + pMem->enc = (enc==0 ? SQLITE_UTF8 : enc); + +#ifndef SQLITE_OMIT_UTF16 + if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ + return SQLITE_NOMEM_BKPT; + } +#endif + + if( nByte>iLimit ){ + return SQLITE_TOOBIG; + } + + return SQLITE_OK; +} + +/* +** Move data out of a btree key or data field and into a Mem structure. +** The data is payload from the entry that pCur is currently pointing +** to. offset and amt determine what portion of the data or key to retrieve. +** The result is written into the pMem element. +** +** The pMem object must have been initialized. This routine will use +** pMem->zMalloc to hold the content from the btree, if possible. New +** pMem->zMalloc space will be allocated if necessary. The calling routine +** is responsible for making sure that the pMem object is eventually +** destroyed. +** +** If this routine fails for any reason (malloc returns NULL or unable +** to read from the disk) then the pMem is left in an inconsistent state. +*/ +static SQLITE_NOINLINE int vdbeMemFromBtreeResize( + BtCursor *pCur, /* Cursor pointing at record to retrieve. */ + u32 offset, /* Offset from the start of data to return bytes from. */ + u32 amt, /* Number of bytes to return. */ + Mem *pMem /* OUT: Return data in this Mem structure. */ +){ + int rc; + pMem->flags = MEM_Null; + if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){ + 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->n = (int)amt; + }else{ + sqlite3VdbeMemRelease(pMem); + } + } + return rc; +} +SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( + BtCursor *pCur, /* Cursor pointing at record to retrieve. */ + u32 offset, /* Offset from the start of data to return bytes from. */ + u32 amt, /* Number of bytes to return. */ + Mem *pMem /* OUT: Return data in this Mem structure. */ +){ + char *zData; /* Data from the btree layer */ + u32 available = 0; /* Number of bytes available on the local btree page */ + int rc = SQLITE_OK; /* Return code */ + + assert( sqlite3BtreeCursorIsValid(pCur) ); + assert( !VdbeMemDynamic(pMem) ); + + /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() + ** that both the BtShared and database handle mutexes are held. */ + assert( (pMem->flags & MEM_RowSet)==0 ); + zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); + assert( zData!=0 ); + + if( offset+amt<=available ){ + pMem->z = &zData[offset]; + pMem->flags = MEM_Blob|MEM_Ephem; + pMem->n = (int)amt; + }else{ + rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem); + } + + return rc; +} + +/* +** The pVal argument is known to be a value other than NULL. +** Convert it into a string with encoding enc and return a pointer +** to a zero-terminated version of that string. +*/ +static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ + assert( pVal!=0 ); + assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); + assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); + assert( (pVal->flags & MEM_RowSet)==0 ); + assert( (pVal->flags & (MEM_Null))==0 ); + if( pVal->flags & (MEM_Blob|MEM_Str) ){ + if( ExpandBlob(pVal) ) return 0; + pVal->flags |= MEM_Str; + if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){ + sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); + } + if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&SQLITE_PTR_TO_INT(pVal->z)) ){ + assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); + if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){ + return 0; + } + } + sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-31275-44060 */ + }else{ + sqlite3VdbeMemStringify(pVal, enc, 0); + assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); + } + assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 + || pVal->db->mallocFailed ); + if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ + return pVal->z; + }else{ + return 0; + } +} + +/* This function is only available internally, it is not part of the +** external API. It works in a similar way to sqlite3_value_text(), +** except the data returned is in the encoding specified by the second +** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or +** SQLITE_UTF8. +** +** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED. +** If that is the case, then the result must be aligned on an even byte +** boundary. +*/ +SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ + if( !pVal ) return 0; + assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); + assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); + assert( (pVal->flags & MEM_RowSet)==0 ); + if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ + return pVal->z; + } + if( pVal->flags&MEM_Null ){ + return 0; + } + return valueToText(pVal, enc); +} + +/* +** Create a new sqlite3_value object. +*/ +SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){ + Mem *p = sqlite3DbMallocZero(db, sizeof(*p)); + if( p ){ + p->flags = MEM_Null; + p->db = db; + } + return p; +} + +/* +** Context object passed by sqlite3Stat4ProbeSetValue() through to +** valueNew(). See comments above valueNew() for details. +*/ +struct ValueNewStat4Ctx { + Parse *pParse; + Index *pIdx; + UnpackedRecord **ppRec; + int iVal; +}; + +/* +** Allocate and return a pointer to a new sqlite3_value object. If +** the second argument to this function is NULL, the object is allocated +** by calling sqlite3ValueNew(). +** +** Otherwise, if the second argument is non-zero, then this function is +** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not +** already been allocated, allocate the UnpackedRecord structure that +** that function will return to its caller here. Then return a pointer to +** an sqlite3_value within the UnpackedRecord.a[] array. +*/ +static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( p ){ + UnpackedRecord *pRec = p->ppRec[0]; + + if( pRec==0 ){ + Index *pIdx = p->pIdx; /* Index being probed */ + int nByte; /* Bytes of space to allocate */ + int i; /* Counter variable */ + int nCol = pIdx->nColumn; /* Number of index columns including rowid */ + + nByte = sizeof(Mem) * nCol + ROUND8(sizeof(UnpackedRecord)); + pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte); + if( pRec ){ + pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx); + if( pRec->pKeyInfo ){ + assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol ); + assert( pRec->pKeyInfo->enc==ENC(db) ); + pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord))); + for(i=0; iaMem[i].flags = MEM_Null; + pRec->aMem[i].db = db; + } + }else{ + sqlite3DbFreeNN(db, pRec); + pRec = 0; + } + } + if( pRec==0 ) return 0; + p->ppRec[0] = pRec; + } + + pRec->nField = p->iVal+1; + return &pRec->aMem[p->iVal]; + } +#else + UNUSED_PARAMETER(p); +#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */ + return sqlite3ValueNew(db); +} + +/* +** The expression object indicated by the second argument is guaranteed +** to be a scalar SQL function. If +** +** * all function arguments are SQL literals, +** * one of the SQLITE_FUNC_CONSTANT or _SLOCHNG function flags is set, and +** * the SQLITE_FUNC_NEEDCOLL function flag is not set, +** +** then this routine attempts to invoke the SQL function. Assuming no +** error occurs, output parameter (*ppVal) is set to point to a value +** object containing the result before returning SQLITE_OK. +** +** Affinity aff is applied to the result of the function before returning. +** If the result is a text value, the sqlite3_value object uses encoding +** enc. +** +** If the conditions above are not met, this function returns SQLITE_OK +** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to +** NULL and an SQLite error code returned. +*/ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +static int valueFromFunction( + sqlite3 *db, /* The database connection */ + Expr *p, /* The expression to evaluate */ + u8 enc, /* Encoding to use */ + u8 aff, /* Affinity to use */ + sqlite3_value **ppVal, /* Write the new value here */ + struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */ +){ + sqlite3_context ctx; /* Context object for function invocation */ + sqlite3_value **apVal = 0; /* Function arguments */ + int nVal = 0; /* Size of apVal[] array */ + FuncDef *pFunc = 0; /* Function definition */ + sqlite3_value *pVal = 0; /* New value */ + int rc = SQLITE_OK; /* Return code */ + ExprList *pList = 0; /* Function arguments */ + int i; /* Iterator variable */ + + assert( pCtx!=0 ); + assert( (p->flags & EP_TokenOnly)==0 ); + pList = p->x.pList; + if( pList ) nVal = pList->nExpr; + pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0); + assert( pFunc ); + if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 + || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) + ){ + return SQLITE_OK; + } + + if( pList ){ + apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal); + if( apVal==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto value_from_function_out; + } + for(i=0; ia[i].pExpr, enc, aff, &apVal[i]); + if( apVal[i]==0 || rc!=SQLITE_OK ) goto value_from_function_out; + } + } + + pVal = valueNew(db, pCtx); + if( pVal==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto value_from_function_out; + } + + assert( pCtx->pParse->rc==SQLITE_OK ); + memset(&ctx, 0, sizeof(ctx)); + ctx.pOut = pVal; + ctx.pFunc = pFunc; + pFunc->xSFunc(&ctx, nVal, apVal); + if( ctx.isError ){ + rc = ctx.isError; + sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); + }else{ + sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); + assert( rc==SQLITE_OK ); + rc = sqlite3VdbeChangeEncoding(pVal, enc); + if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){ + rc = SQLITE_TOOBIG; + pCtx->pParse->nErr++; + } + } + pCtx->pParse->rc = rc; + + value_from_function_out: + if( rc!=SQLITE_OK ){ + pVal = 0; + } + if( apVal ){ + for(i=0; iop)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft; + if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; + + /* Compressed expressions only appear when parsing the DEFAULT clause + ** on a table column definition, and hence only when pCtx==0. This + ** check ensures that an EP_TokenOnly expression is never passed down + ** into valueFromFunction(). */ + assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 ); + + if( op==TK_CAST ){ + u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); + rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); + testcase( rc!=SQLITE_OK ); + if( *ppVal ){ + sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8); + sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8); + } + return rc; + } + + /* Handle negative integers in a single step. This is needed in the + ** case when the value is -9223372036854775808. + */ + if( op==TK_UMINUS + && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){ + pExpr = pExpr->pLeft; + op = pExpr->op; + negInt = -1; + zNeg = "-"; + } + + if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ + pVal = valueNew(db, pCtx); + if( pVal==0 ) goto no_mem; + if( ExprHasProperty(pExpr, EP_IntValue) ){ + sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); + }else{ + zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); + if( zVal==0 ) goto no_mem; + sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); + } + if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){ + sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); + }else{ + sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); + } + if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str; + if( enc!=SQLITE_UTF8 ){ + rc = sqlite3VdbeChangeEncoding(pVal, enc); + } + }else if( op==TK_UMINUS ) { + /* This branch happens for multiple negative signs. Ex: -(-5) */ + if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) + && pVal!=0 + ){ + sqlite3VdbeMemNumerify(pVal); + if( pVal->flags & MEM_Real ){ + pVal->u.r = -pVal->u.r; + }else if( pVal->u.i==SMALLEST_INT64 ){ + pVal->u.r = -(double)SMALLEST_INT64; + MemSetTypeFlag(pVal, MEM_Real); + }else{ + pVal->u.i = -pVal->u.i; + } + sqlite3ValueApplyAffinity(pVal, affinity, enc); + } + }else if( op==TK_NULL ){ + pVal = valueNew(db, pCtx); + if( pVal==0 ) goto no_mem; + sqlite3VdbeMemNumerify(pVal); + } +#ifndef SQLITE_OMIT_BLOB_LITERAL + else if( op==TK_BLOB ){ + int nVal; + assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); + assert( pExpr->u.zToken[1]=='\'' ); + pVal = valueNew(db, pCtx); + if( !pVal ) goto no_mem; + zVal = &pExpr->u.zToken[2]; + nVal = sqlite3Strlen30(zVal)-1; + assert( zVal[nVal]=='\'' ); + sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2, + 0, SQLITE_DYNAMIC); + } +#endif + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + else if( op==TK_FUNCTION && pCtx!=0 ){ + rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx); + } +#endif + + *ppVal = pVal; + return rc; + +no_mem: + sqlite3OomFault(db); + sqlite3DbFree(db, zVal); + assert( *ppVal==0 ); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( pCtx==0 ) sqlite3ValueFree(pVal); +#else + assert( pCtx==0 ); sqlite3ValueFree(pVal); +#endif + return SQLITE_NOMEM_BKPT; +} + +/* +** Create a new sqlite3_value object, containing the value of pExpr. +** +** This only works for very simple expressions that consist of one constant +** token (i.e. "5", "5.1", "'a string'"). If the expression can +** be converted directly into a value, then the value is allocated and +** a pointer written to *ppVal. The caller is responsible for deallocating +** the value by passing it to sqlite3ValueFree() later on. If the expression +** cannot be converted to a value, then *ppVal is set to NULL. +*/ +SQLITE_PRIVATE int sqlite3ValueFromExpr( + sqlite3 *db, /* The database connection */ + Expr *pExpr, /* The expression to evaluate */ + u8 enc, /* Encoding to use */ + u8 affinity, /* Affinity to use */ + sqlite3_value **ppVal /* Write the new value here */ +){ + return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0; +} + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** The implementation of the sqlite_record() function. This function accepts +** a single argument of any type. The return value is a formatted database +** record (a blob) containing the argument value. +** +** This is used to convert the value stored in the 'sample' column of the +** sqlite_stat3 table to the record format SQLite uses internally. +*/ +static void recordFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const int file_format = 1; + u32 iSerial; /* Serial type */ + int nSerial; /* Bytes of space for iSerial as varint */ + u32 nVal; /* Bytes of space required for argv[0] */ + int nRet; + sqlite3 *db; + u8 *aRet; + + UNUSED_PARAMETER( argc ); + iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal); + nSerial = sqlite3VarintLen(iSerial); + db = sqlite3_context_db_handle(context); + + nRet = 1 + nSerial + nVal; + aRet = sqlite3DbMallocRawNN(db, nRet); + if( aRet==0 ){ + sqlite3_result_error_nomem(context); + }else{ + aRet[0] = nSerial+1; + putVarint32(&aRet[1], iSerial); + sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial); + sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT); + sqlite3DbFreeNN(db, aRet); + } +} + +/* +** Register built-in functions used to help read ANALYZE data. +*/ +SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){ + static FuncDef aAnalyzeTableFuncs[] = { + FUNCTION(sqlite_record, 1, 0, 0, recordFunc), + }; + sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs)); +} + +/* +** Attempt to extract a value from pExpr and use it to construct *ppVal. +** +** If pAlloc is not NULL, then an UnpackedRecord object is created for +** pAlloc if one does not exist and the new value is added to the +** UnpackedRecord object. +** +** A value is extracted in the following cases: +** +** * (pExpr==0). In this case the value is assumed to be an SQL NULL, +** +** * The expression is a bound variable, and this is a reprepare, or +** +** * The expression is a literal value. +** +** On success, *ppVal is made to point to the extracted value. The caller +** is responsible for ensuring that the value is eventually freed. +*/ +static int stat4ValueFromExpr( + Parse *pParse, /* Parse context */ + Expr *pExpr, /* The expression to extract a value from */ + u8 affinity, /* Affinity to use */ + struct ValueNewStat4Ctx *pAlloc,/* How to allocate space. Or NULL */ + sqlite3_value **ppVal /* OUT: New value object (or NULL) */ +){ + int rc = SQLITE_OK; + sqlite3_value *pVal = 0; + sqlite3 *db = pParse->db; + + /* Skip over any TK_COLLATE nodes */ + pExpr = sqlite3ExprSkipCollate(pExpr); + + if( !pExpr ){ + pVal = valueNew(db, pAlloc); + if( pVal ){ + sqlite3VdbeMemSetNull((Mem*)pVal); + } + }else if( pExpr->op==TK_VARIABLE + || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) + ){ + Vdbe *v; + int iBindVar = pExpr->iColumn; + sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); + if( (v = pParse->pReprepare)!=0 ){ + pVal = valueNew(db, pAlloc); + if( pVal ){ + rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); + if( rc==SQLITE_OK ){ + sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); + } + pVal->db = pParse->db; + } + } + }else{ + rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, pAlloc); + } + + assert( pVal==0 || pVal->db==db ); + *ppVal = pVal; + return rc; +} + +/* +** This function is used to allocate and populate UnpackedRecord +** structures intended to be compared against sample index keys stored +** in the sqlite_stat4 table. +** +** A single call to this function populates zero or more fields of the +** record starting with field iVal (fields are numbered from left to +** right starting with 0). A single field is populated if: +** +** * (pExpr==0). In this case the value is assumed to be an SQL NULL, +** +** * The expression is a bound variable, and this is a reprepare, or +** +** * The sqlite3ValueFromExpr() function is able to extract a value +** from the expression (i.e. the expression is a literal value). +** +** Or, if pExpr is a TK_VECTOR, one field is populated for each of the +** vector components that match either of the two latter criteria listed +** above. +** +** Before any value is appended to the record, the affinity of the +** corresponding column within index pIdx is applied to it. Before +** this function returns, output parameter *pnExtract is set to the +** number of values appended to the record. +** +** When this function is called, *ppRec must either point to an object +** allocated by an earlier call to this function, or must be NULL. If it +** is NULL and a value can be successfully extracted, a new UnpackedRecord +** is allocated (and *ppRec set to point to it) before returning. +** +** Unless an error is encountered, SQLITE_OK is returned. It is not an +** error if a value cannot be extracted from pExpr. If an error does +** occur, an SQLite error code is returned. +*/ +SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( + Parse *pParse, /* Parse context */ + Index *pIdx, /* Index being probed */ + UnpackedRecord **ppRec, /* IN/OUT: Probe record */ + Expr *pExpr, /* The expression to extract a value from */ + int nElem, /* Maximum number of values to append */ + int iVal, /* Array element to populate */ + int *pnExtract /* OUT: Values appended to the record */ +){ + int rc = SQLITE_OK; + int nExtract = 0; + + if( pExpr==0 || pExpr->op!=TK_SELECT ){ + int i; + struct ValueNewStat4Ctx alloc; + + alloc.pParse = pParse; + alloc.pIdx = pIdx; + alloc.ppRec = ppRec; + + for(i=0; idb, pIdx, iVal+i); + alloc.iVal = iVal+i; + rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal); + if( !pVal ) break; + nExtract++; + } + } + + *pnExtract = nExtract; + return rc; +} + +/* +** Attempt to extract a value from expression pExpr using the methods +** as described for sqlite3Stat4ProbeSetValue() above. +** +** If successful, set *ppVal to point to a new value object and return +** SQLITE_OK. If no value can be extracted, but no other error occurs +** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error +** does occur, return an SQLite error code. The final value of *ppVal +** is undefined in this case. +*/ +SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr( + Parse *pParse, /* Parse context */ + Expr *pExpr, /* The expression to extract a value from */ + u8 affinity, /* Affinity to use */ + sqlite3_value **ppVal /* OUT: New value object (or NULL) */ +){ + return stat4ValueFromExpr(pParse, pExpr, affinity, 0, ppVal); +} + +/* +** Extract the iCol-th column from the nRec-byte record in pRec. Write +** the column value into *ppVal. If *ppVal is initially NULL then a new +** sqlite3_value object is allocated. +** +** If *ppVal is initially NULL then the caller is responsible for +** ensuring that the value written into *ppVal is eventually freed. +*/ +SQLITE_PRIVATE int sqlite3Stat4Column( + sqlite3 *db, /* Database handle */ + const void *pRec, /* Pointer to buffer containing record */ + int nRec, /* Size of buffer pRec in bytes */ + int iCol, /* Column to extract */ + sqlite3_value **ppVal /* OUT: Extracted value */ +){ + u32 t; /* a column type code */ + int nHdr; /* Size of the header in the record */ + int iHdr; /* Next unread header byte */ + int iField; /* Next unread data byte */ + int szField; /* Size of the current data field */ + int i; /* Column index */ + u8 *a = (u8*)pRec; /* Typecast byte array */ + Mem *pMem = *ppVal; /* Write result into this Mem object */ + + assert( iCol>0 ); + iHdr = getVarint32(a, nHdr); + if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; + iField = nHdr; + for(i=0; i<=iCol; i++){ + iHdr += getVarint32(&a[iHdr], t); + testcase( iHdr==nHdr ); + testcase( iHdr==nHdr+1 ); + if( iHdr>nHdr ) return SQLITE_CORRUPT_BKPT; + szField = sqlite3VdbeSerialTypeLen(t); + iField += szField; + } + testcase( iField==nRec ); + testcase( iField==nRec+1 ); + if( iField>nRec ) return SQLITE_CORRUPT_BKPT; + if( pMem==0 ){ + pMem = *ppVal = sqlite3ValueNew(db); + if( pMem==0 ) return SQLITE_NOMEM_BKPT; + } + sqlite3VdbeSerialGet(&a[iField-szField], t, pMem); + pMem->enc = ENC(db); + return SQLITE_OK; +} + +/* +** Unless it is NULL, the argument must be an UnpackedRecord object returned +** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes +** the object. +*/ +SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ + if( pRec ){ + int i; + int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField; + Mem *aMem = pRec->aMem; + sqlite3 *db = aMem[0].db; + for(i=0; ipKeyInfo); + sqlite3DbFreeNN(db, pRec); + } +} +#endif /* ifdef SQLITE_ENABLE_STAT4 */ + +/* +** Change the string value of an sqlite3_value object +*/ +SQLITE_PRIVATE void sqlite3ValueSetStr( + sqlite3_value *v, /* Value to be set */ + int n, /* Length of string z */ + const void *z, /* Text of the new string */ + u8 enc, /* Encoding to use */ + void (*xDel)(void*) /* Destructor for the string */ +){ + if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel); +} + +/* +** Free an sqlite3_value object +*/ +SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){ + if( !v ) return; + sqlite3VdbeMemRelease((Mem *)v); + sqlite3DbFreeNN(((Mem*)v)->db, v); +} + +/* +** The sqlite3ValueBytes() routine returns the number of bytes in the +** sqlite3_value object assuming that it uses the encoding "enc". +** The valueBytes() routine is a helper function. +*/ +static SQLITE_NOINLINE int valueBytes(sqlite3_value *pVal, u8 enc){ + return valueToText(pVal, enc)!=0 ? pVal->n : 0; +} +SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ + Mem *p = (Mem*)pVal; + assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 ); + if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){ + return p->n; + } + if( (p->flags & MEM_Blob)!=0 ){ + if( p->flags & MEM_Zero ){ + return p->n + p->u.nZero; + }else{ + return p->n; + } + } + if( p->flags & MEM_Null ) return 0; + return valueBytes(pVal, enc); +} + +/************** End of vdbemem.c *********************************************/ +/************** Begin file vdbeaux.c *****************************************/ +/* +** 2003 September 6 +** +** 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 used for creating, destroying, and populating +** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) +*/ +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +/* +** Create a new virtual database engine. +*/ +SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ + sqlite3 *db = pParse->db; + Vdbe *p; + p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) ); + if( p==0 ) return 0; + memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp)); + p->db = db; + if( db->pVdbe ){ + db->pVdbe->pPrev = p; + } + p->pNext = db->pVdbe; + p->pPrev = 0; + db->pVdbe = p; + p->magic = VDBE_MAGIC_INIT; + p->pParse = pParse; + assert( pParse->aLabel==0 ); + assert( pParse->nLabel==0 ); + assert( pParse->nOpAlloc==0 ); + assert( pParse->szOpAlloc==0 ); + return p; +} + +/* +** Change the error string stored in Vdbe.zErrMsg +*/ +SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){ + va_list ap; + sqlite3DbFree(p->db, p->zErrMsg); + va_start(ap, zFormat); + p->zErrMsg = sqlite3VMPrintf(p->db, zFormat, ap); + va_end(ap); +} + +/* +** Remember the SQL string for a prepared statement. +*/ +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ + assert( isPrepareV2==1 || isPrepareV2==0 ); + if( p==0 ) return; + if( !isPrepareV2 ) p->expmask = 0; +#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG) + if( !isPrepareV2 ) return; +#endif + assert( p->zSql==0 ); + p->zSql = sqlite3DbStrNDup(p->db, z, n); + p->isPrepareV2 = (u8)isPrepareV2; +} + +/* +** Swap all content between two VDBE structures. +*/ +SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ + Vdbe tmp, *pTmp; + char *zTmp; + assert( pA->db==pB->db ); + tmp = *pA; + *pA = *pB; + *pB = tmp; + pTmp = pA->pNext; + pA->pNext = pB->pNext; + pB->pNext = pTmp; + pTmp = pA->pPrev; + pA->pPrev = pB->pPrev; + pB->pPrev = pTmp; + zTmp = pA->zSql; + pA->zSql = pB->zSql; + pB->zSql = zTmp; + pB->isPrepareV2 = pA->isPrepareV2; + pB->expmask = pA->expmask; +} + +/* +** Resize the Vdbe.aOp array so that it is at least nOp elements larger +** than its current size. nOp is guaranteed to be less than or equal +** to 1024/sizeof(Op). +** +** If an out-of-memory error occurs while resizing the array, return +** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain +** unchanged (this is so that any opcodes already allocated can be +** correctly deallocated along with the rest of the Vdbe). +*/ +static int growOpArray(Vdbe *v, int nOp){ + VdbeOp *pNew; + Parse *p = v->pParse; + + /* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force + ** more frequent reallocs and hence provide more opportunities for + ** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used + ** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array + ** by the minimum* amount required until the size reaches 512. Normal + ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current + ** size of the op array or add 1KB of space, whichever is smaller. */ +#ifdef SQLITE_TEST_REALLOC_STRESS + int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp); +#else + int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); + UNUSED_PARAMETER(nOp); +#endif + + /* Ensure that the size of a VDBE does not grow too large */ + if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){ + sqlite3OomFault(p->db); + return SQLITE_NOMEM; + } + + assert( nOp<=(1024/sizeof(Op)) ); + assert( nNew>=(p->nOpAlloc+nOp) ); + pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); + if( pNew ){ + p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew); + p->nOpAlloc = p->szOpAlloc/sizeof(Op); + v->aOp = pNew; + } + return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); +} + +#ifdef SQLITE_DEBUG +/* This routine is just a convenient place to set a breakpoint that will +** fire after each opcode is inserted and displayed using +** "PRAGMA vdbe_addoptrace=on". +*/ +static void test_addop_breakpoint(void){ + static int n = 0; + n++; +} +#endif + +/* +** Add a new instruction to the list of instructions current in the +** VDBE. Return the address of the new instruction. +** +** Parameters: +** +** p Pointer to the VDBE +** +** op The opcode for this instruction +** +** p1, p2, p3 Operands +** +** Use the sqlite3VdbeResolveLabel() function to fix an address and +** the sqlite3VdbeChangeP4() function to change the value of the P4 +** operand. +*/ +static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){ + assert( p->pParse->nOpAlloc<=p->nOp ); + if( growOpArray(p, 1) ) return 1; + assert( p->pParse->nOpAlloc>p->nOp ); + return sqlite3VdbeAddOp3(p, op, p1, p2, p3); +} +SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ + int i; + VdbeOp *pOp; + + i = p->nOp; + assert( p->magic==VDBE_MAGIC_INIT ); + assert( op>=0 && op<0xff ); + if( p->pParse->nOpAlloc<=i ){ + return growOp3(p, op, p1, p2, p3); + } + p->nOp++; + pOp = &p->aOp[i]; + pOp->opcode = (u8)op; + pOp->p5 = 0; + pOp->p1 = p1; + pOp->p2 = p2; + pOp->p3 = p3; + pOp->p4.p = 0; + pOp->p4type = P4_NOTUSED; +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + pOp->zComment = 0; +#endif +#ifdef SQLITE_DEBUG + if( p->db->flags & SQLITE_VdbeAddopTrace ){ + int jj, kk; + Parse *pParse = p->pParse; + for(jj=kk=0; jjnColCache; jj++){ + struct yColCache *x = pParse->aColCache + jj; + printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn); + kk++; + } + if( kk ) printf("\n"); + sqlite3VdbePrintOp(0, i, &p->aOp[i]); + test_addop_breakpoint(); + } +#endif +#ifdef VDBE_PROFILE + pOp->cycles = 0; + pOp->cnt = 0; +#endif +#ifdef SQLITE_VDBE_COVERAGE + pOp->iSrcLine = 0; +#endif + return i; +} +SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){ + return sqlite3VdbeAddOp3(p, op, 0, 0, 0); +} +SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){ + return sqlite3VdbeAddOp3(p, op, p1, 0, 0); +} +SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){ + return sqlite3VdbeAddOp3(p, op, p1, p2, 0); +} + +/* Generate code for an unconditional jump to instruction iDest +*/ +SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe *p, int iDest){ + return sqlite3VdbeAddOp3(p, OP_Goto, 0, iDest, 0); +} + +/* Generate code to cause the string zStr to be loaded into +** register iDest +*/ +SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){ + return sqlite3VdbeAddOp4(p, OP_String8, 0, iDest, 0, zStr, 0); +} + +/* +** Generate code that initializes multiple registers to string or integer +** constants. The registers begin with iDest and increase consecutively. +** One register is initialized for each characgter in zTypes[]. For each +** "s" character in zTypes[], the register is a string if the argument is +** not NULL, or OP_Null if the value is a null pointer. For each "i" character +** in zTypes[], the register is initialized to an integer. +*/ +SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){ + va_list ap; + int i; + char c; + va_start(ap, zTypes); + for(i=0; (c = zTypes[i])!=0; i++){ + if( c=='s' ){ + const char *z = va_arg(ap, const char*); + sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0); + }else{ + assert( c=='i' ); + sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++); + } + } + va_end(ap); +} + +/* +** Add an opcode that includes the p4 value as a pointer. +*/ +SQLITE_PRIVATE int sqlite3VdbeAddOp4( + Vdbe *p, /* Add the opcode to this VM */ + int op, /* The new opcode */ + int p1, /* The P1 operand */ + int p2, /* The P2 operand */ + int p3, /* The P3 operand */ + const char *zP4, /* The P4 operand */ + int p4type /* P4 operand type */ +){ + int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); + sqlite3VdbeChangeP4(p, addr, zP4, p4type); + return addr; +} + +/* +** Add an opcode that includes the p4 value with a P4_INT64 or +** P4_REAL type. +*/ +SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( + Vdbe *p, /* Add the opcode to this VM */ + int op, /* The new opcode */ + int p1, /* The P1 operand */ + int p2, /* The P2 operand */ + int p3, /* The P3 operand */ + const u8 *zP4, /* The P4 operand */ + int p4type /* P4 operand type */ +){ + char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8); + if( p4copy ) memcpy(p4copy, zP4, 8); + return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); +} + +/* +** Add an OP_ParseSchema opcode. This routine is broken out from +** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees +** as having been used. +** +** The zWhere string must have been obtained from sqlite3_malloc(). +** This routine will take ownership of the allocated memory. +*/ +SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){ + int j; + sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); + for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j); +} + +/* +** Add an opcode that includes the p4 value as an integer. +*/ +SQLITE_PRIVATE int sqlite3VdbeAddOp4Int( + Vdbe *p, /* Add the opcode to this VM */ + int op, /* The new opcode */ + int p1, /* The P1 operand */ + int p2, /* The P2 operand */ + int p3, /* The P3 operand */ + int p4 /* The P4 operand as an integer */ +){ + int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); + if( p->db->mallocFailed==0 ){ + VdbeOp *pOp = &p->aOp[addr]; + pOp->p4type = P4_INT32; + pOp->p4.i = p4; + } + return addr; +} + +/* Insert the end of a co-routine +*/ +SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){ + sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield); + + /* Clear the temporary register cache, thereby ensuring that each + ** co-routine has its own independent set of registers, because co-routines + ** might expect their registers to be preserved across an OP_Yield, and + ** that could cause problems if two or more co-routines are using the same + ** temporary register. + */ + v->pParse->nTempReg = 0; + v->pParse->nRangeReg = 0; +} + +/* +** Create a new symbolic label for an instruction that has yet to be +** coded. The symbolic label is really just a negative number. The +** label can be used as the P2 value of an operation. Later, when +** the label is resolved to a specific address, the VDBE will scan +** through its operation list and change all values of P2 which match +** the label into the resolved address. +** +** The VDBE knows that a P2 value is a label because labels are +** always negative and P2 values are suppose to be non-negative. +** Hence, a negative P2 value is a label that has yet to be resolved. +** +** Zero is returned if a malloc() fails. +*/ +SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){ + Parse *p = v->pParse; + int i = p->nLabel++; + assert( v->magic==VDBE_MAGIC_INIT ); + if( (i & (i-1))==0 ){ + p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, + (i*2+1)*sizeof(p->aLabel[0])); + } + if( p->aLabel ){ + p->aLabel[i] = -1; + } + return ADDR(i); +} + +/* +** Resolve label "x" to be the address of the next instruction to +** be inserted. The parameter "x" must have been obtained from +** a prior call to sqlite3VdbeMakeLabel(). +*/ +SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ + Parse *p = v->pParse; + int j = ADDR(x); + assert( v->magic==VDBE_MAGIC_INIT ); + assert( jnLabel ); + assert( j>=0 ); + if( p->aLabel ){ + p->aLabel[j] = v->nOp; + } +} + +/* +** Mark the VDBE as one that can only be run one time. +*/ +SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){ + p->runOnlyOnce = 1; +} + +/* +** Mark the VDBE as one that can only be run multiple times. +*/ +SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){ + p->runOnlyOnce = 0; +} + +#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */ + +/* +** The following type and function are used to iterate through all opcodes +** in a Vdbe main program and each of the sub-programs (triggers) it may +** invoke directly or indirectly. It should be used as follows: +** +** Op *pOp; +** VdbeOpIter sIter; +** +** memset(&sIter, 0, sizeof(sIter)); +** sIter.v = v; // v is of type Vdbe* +** while( (pOp = opIterNext(&sIter)) ){ +** // Do something with pOp +** } +** sqlite3DbFree(v->db, sIter.apSub); +** +*/ +typedef struct VdbeOpIter VdbeOpIter; +struct VdbeOpIter { + Vdbe *v; /* Vdbe to iterate through the opcodes of */ + SubProgram **apSub; /* Array of subprograms */ + int nSub; /* Number of entries in apSub */ + int iAddr; /* Address of next instruction to return */ + int iSub; /* 0 = main program, 1 = first sub-program etc. */ +}; +static Op *opIterNext(VdbeOpIter *p){ + Vdbe *v = p->v; + Op *pRet = 0; + Op *aOp; + int nOp; + + if( p->iSub<=p->nSub ){ + + if( p->iSub==0 ){ + aOp = v->aOp; + nOp = v->nOp; + }else{ + aOp = p->apSub[p->iSub-1]->aOp; + nOp = p->apSub[p->iSub-1]->nOp; + } + assert( p->iAddriAddr]; + p->iAddr++; + if( p->iAddr==nOp ){ + p->iSub++; + p->iAddr = 0; + } + + if( pRet->p4type==P4_SUBPROGRAM ){ + int nByte = (p->nSub+1)*sizeof(SubProgram*); + int j; + for(j=0; jnSub; j++){ + if( p->apSub[j]==pRet->p4.pProgram ) break; + } + if( j==p->nSub ){ + p->apSub = sqlite3DbReallocOrFree(v->db, p->apSub, nByte); + if( !p->apSub ){ + pRet = 0; + }else{ + p->apSub[p->nSub++] = pRet->p4.pProgram; + } + } + } + } + + return pRet; +} + +/* +** Check if the program stored in the VM associated with pParse may +** throw an ABORT exception (causing the statement, but not entire transaction +** to be rolled back). This condition is true if the main program or any +** sub-programs contains any of the following: +** +** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort. +** * OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort. +** * OP_Destroy +** * OP_VUpdate +** * OP_VRename +** * OP_FkCounter with P2==0 (immediate foreign key constraint) +** * OP_CreateTable 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 +** match, or false otherwise. This function is intended to be used as +** part of an assert statement in the compiler. Similar to: +** +** assert( sqlite3VdbeAssertMayAbort(pParse->pVdbe, pParse->mayAbort) ); +*/ +SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ + int hasAbort = 0; + int hasFkCounter = 0; + int hasCreateTable = 0; + int hasInitCoroutine = 0; + Op *pOp; + VdbeOpIter sIter; + memset(&sIter, 0, sizeof(sIter)); + sIter.v = v; + + while( (pOp = opIterNext(&sIter))!=0 ){ + int opcode = pOp->opcode; + if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename + || ((opcode==OP_Halt || opcode==OP_HaltIfNull) + && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort)) + ){ + hasAbort = 1; + break; + } + if( opcode==OP_CreateTable ) hasCreateTable = 1; + if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; +#ifndef SQLITE_OMIT_FOREIGN_KEY + if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ + hasFkCounter = 1; + } +#endif + } + sqlite3DbFree(v->db, sIter.apSub); + + /* Return true if hasAbort==mayAbort. Or if a malloc failure occurred. + ** If malloc failed, then the while() loop above may not have iterated + ** through all opcodes and hasAbort may be set incorrectly. Return + ** true for this case to prevent the assert() in the callers frame + ** from failing. */ + return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter + || (hasCreateTable && hasInitCoroutine) ); +} +#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ + +/* +** This routine is called after all opcodes have been inserted. It loops +** through all the opcodes and fixes up some details. +** +** (1) For each jump instruction with a negative P2 value (a label) +** resolve the P2 value to an actual address. +** +** (2) Compute the maximum number of arguments used by any SQL function +** and store that value in *pMaxFuncArgs. +** +** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately +** indicate what the prepared statement actually does. +** +** (4) Initialize the p4.xAdvance pointer on opcodes that use it. +** +** (5) Reclaim the memory allocated for storing labels. +** +** This routine will only function correctly if the mkopcodeh.tcl generator +** script numbers the opcodes correctly. Changes to this routine must be +** coordinated with changes to mkopcodeh.tcl. +*/ +static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ + int nMaxArgs = *pMaxFuncArgs; + Op *pOp; + Parse *pParse = p->pParse; + int *aLabel = pParse->aLabel; + p->readOnly = 1; + p->bIsReader = 0; + pOp = &p->aOp[p->nOp-1]; + while(1){ + + /* Only JUMP opcodes and the short list of special opcodes in the switch + ** below need to be considered. The mkopcodeh.tcl generator script groups + ** all these opcodes together near the front of the opcode list. Skip + ** any opcode that does not need processing by virtual of the fact that + ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization. + */ + if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){ + /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing + ** cases from this switch! */ + switch( pOp->opcode ){ + case OP_Transaction: { + if( pOp->p2!=0 ) p->readOnly = 0; + /* fall thru */ + } + case OP_AutoCommit: + case OP_Savepoint: { + p->bIsReader = 1; + break; + } +#ifndef SQLITE_OMIT_WAL + case OP_Checkpoint: +#endif + case OP_Vacuum: + case OP_JournalMode: { + p->readOnly = 0; + p->bIsReader = 1; + break; + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + case OP_VUpdate: { + if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; + break; + } + case OP_VFilter: { + int n; + assert( (pOp - p->aOp) >= 3 ); + assert( pOp[-1].opcode==OP_Integer ); + n = pOp[-1].p1; + if( n>nMaxArgs ) nMaxArgs = n; + break; + } +#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; + break; + } + } + if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){ + assert( ADDR(pOp->p2)nLabel ); + pOp->p2 = aLabel[ADDR(pOp->p2)]; + } + } + if( pOp==p->aOp ) break; + pOp--; + } + sqlite3DbFree(p->db, pParse->aLabel); + pParse->aLabel = 0; + pParse->nLabel = 0; + *pMaxFuncArgs = nMaxArgs; + assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); +} + +/* +** Return the address of the next instruction to be inserted. +*/ +SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ + assert( p->magic==VDBE_MAGIC_INIT ); + return p->nOp; +} + +/* +** Verify that at least N opcode slots are available in p without +** having to malloc for more space (except when compiled using +** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing +** to verify that certain calls to sqlite3VdbeAddOpList() can never +** fail due to a OOM fault and hence that the return value from +** sqlite3VdbeAddOpList() will always be non-NULL. +*/ +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) +SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ + assert( p->nOp + N <= p->pParse->nOpAlloc ); +} +#endif + +/* +** Verify that the VM passed as the only argument does not contain +** an OP_ResultRow opcode. Fail an assert() if it does. This is used +** by code in pragma.c to ensure that the implementation of certain +** pragmas comports with the flags specified in the mkpragmatab.tcl +** script. +*/ +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) +SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){ + int i; + for(i=0; inOp; i++){ + assert( p->aOp[i].opcode!=OP_ResultRow ); + } +} +#endif + +/* +** This function returns a pointer to the array of opcodes associated with +** the Vdbe passed as the first argument. It is the callers responsibility +** to arrange for the returned array to be eventually freed using the +** vdbeFreeOpArray() function. +** +** Before returning, *pnOp is set to the number of entries in the returned +** array. Also, *pnMaxArg is set to the larger of its current value and +** the number of entries in the Vdbe.apArg[] array required to execute the +** returned program. +*/ +SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){ + VdbeOp *aOp = p->aOp; + assert( aOp && !p->db->mallocFailed ); + + /* Check that sqlite3VdbeUsesBtree() was not called on this VM */ + assert( DbMaskAllZero(p->btreeMask) ); + + resolveP2Values(p, pnMaxArg); + *pnOp = p->nOp; + p->aOp = 0; + return aOp; +} + +/* +** Add a whole list of operations to the operation stack. Return a +** pointer to the first operation inserted. +** +** Non-zero P2 arguments to jump instructions are automatically adjusted +** so that the jump target is relative to the first operation inserted. +*/ +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList( + Vdbe *p, /* Add opcodes to the prepared statement */ + int nOp, /* Number of opcodes to add */ + VdbeOpList const *aOp, /* The opcodes to be added */ + int iLineno /* Source-file line number of first opcode */ +){ + int i; + VdbeOp *pOut, *pFirst; + assert( nOp>0 ); + assert( p->magic==VDBE_MAGIC_INIT ); + if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ + return 0; + } + pFirst = pOut = &p->aOp[p->nOp]; + for(i=0; iopcode = aOp->opcode; + pOut->p1 = aOp->p1; + pOut->p2 = aOp->p2; + assert( aOp->p2>=0 ); + if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){ + pOut->p2 += p->nOp; + } + pOut->p3 = aOp->p3; + pOut->p4type = P4_NOTUSED; + pOut->p4.p = 0; + pOut->p5 = 0; +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + pOut->zComment = 0; +#endif +#ifdef SQLITE_VDBE_COVERAGE + pOut->iSrcLine = iLineno+i; +#else + (void)iLineno; +#endif +#ifdef SQLITE_DEBUG + if( p->db->flags & SQLITE_VdbeAddopTrace ){ + sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]); + } +#endif + } + p->nOp += nOp; + return pFirst; +} + +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) +/* +** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). +*/ +SQLITE_PRIVATE void sqlite3VdbeScanStatus( + Vdbe *p, /* VM to add scanstatus() to */ + int addrExplain, /* Address of OP_Explain (or 0) */ + int addrLoop, /* Address of loop counter */ + int addrVisit, /* Address of rows visited counter */ + LogEst nEst, /* Estimated number of output rows */ + const char *zName /* Name of table or index being scanned */ +){ + int nByte = (p->nScan+1) * sizeof(ScanStatus); + ScanStatus *aNew; + aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); + if( aNew ){ + ScanStatus *pNew = &aNew[p->nScan++]; + pNew->addrExplain = addrExplain; + pNew->addrLoop = addrLoop; + pNew->addrVisit = addrVisit; + pNew->nEst = nEst; + pNew->zName = sqlite3DbStrDup(p->db, zName); + p->aScan = aNew; + } +} +#endif + + +/* +** Change the value of the opcode, or P1, P2, P3, or P5 operands +** for a specific instruction. +*/ +SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){ + sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode; +} +SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){ + sqlite3VdbeGetOp(p,addr)->p1 = val; +} +SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){ + sqlite3VdbeGetOp(p,addr)->p2 = val; +} +SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){ + sqlite3VdbeGetOp(p,addr)->p3 = val; +} +SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ + assert( p->nOp>0 || p->db->mallocFailed ); + if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5; +} + +/* +** Change the P2 operand of instruction addr so that it points to +** the address of the next instruction to be coded. +*/ +SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ + sqlite3VdbeChangeP2(p, addr, p->nOp); +} + + +/* +** If the input FuncDef structure is ephemeral, then free it. If +** the FuncDef is not ephermal, then do nothing. +*/ +static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ + if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ + sqlite3DbFreeNN(db, pDef); + } +} + +static void vdbeFreeOpArray(sqlite3 *, Op *, int); + +/* +** Delete a P4 value if necessary. +*/ +static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); + sqlite3DbFreeNN(db, p); +} +static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ + freeEphemeralFunction(db, p->pFunc); + sqlite3DbFreeNN(db, p); +} +static void freeP4(sqlite3 *db, int p4type, void *p4){ + assert( db ); + switch( p4type ){ + case P4_FUNCCTX: { + freeP4FuncCtx(db, (sqlite3_context*)p4); + break; + } + case P4_REAL: + case P4_INT64: + case P4_DYNAMIC: + case P4_INTARRAY: { + sqlite3DbFree(db, p4); + break; + } + case P4_KEYINFO: { + if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); + break; + } +#ifdef SQLITE_ENABLE_CURSOR_HINTS + case P4_EXPR: { + sqlite3ExprDelete(db, (Expr*)p4); + break; + } +#endif + case P4_FUNCDEF: { + freeEphemeralFunction(db, (FuncDef*)p4); + break; + } + case P4_MEM: { + if( db->pnBytesFreed==0 ){ + sqlite3ValueFree((sqlite3_value*)p4); + }else{ + freeP4Mem(db, (Mem*)p4); + } + break; + } + case P4_VTAB : { + if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); + break; + } + } +} + +/* +** Free the space allocated for aOp and any p4 values allocated for the +** opcodes contained within. If aOp is not NULL it is assumed to contain +** nOp entries. +*/ +static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ + if( aOp ){ + Op *pOp; + for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){ + if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p); +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + sqlite3DbFree(db, pOp->zComment); +#endif + } + sqlite3DbFreeNN(db, aOp); + } +} + +/* +** Link the SubProgram object passed as the second argument into the linked +** list at Vdbe.pSubProgram. This list is used to delete all sub-program +** objects when the VM is no longer required. +*/ +SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ + p->pNext = pVdbe->pProgram; + pVdbe->pProgram = p; +} + +/* +** Change the opcode at addr into OP_Noop +*/ +SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ + VdbeOp *pOp; + if( p->db->mallocFailed ) return 0; + assert( addr>=0 && addrnOp ); + pOp = &p->aOp[addr]; + freeP4(p->db, pOp->p4type, pOp->p4.p); + pOp->p4type = P4_NOTUSED; + pOp->p4.z = 0; + pOp->opcode = OP_Noop; + return 1; +} + +/* +** If the last opcode is "op" and it is not a jump destination, +** then remove it. Return true if and only if an opcode was removed. +*/ +SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ + if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){ + return sqlite3VdbeChangeToNoop(p, p->nOp-1); + }else{ + return 0; + } +} + +/* +** Change the value of the P4 operand for a specific instruction. +** This routine is useful when a large program is loaded from a +** static array using sqlite3VdbeAddOpList but we want to make a +** few minor changes to the program. +** +** If n>=0 then the P4 operand is dynamic, meaning that a copy of +** the string is made into memory obtained from sqlite3_malloc(). +** A value of n==0 means copy bytes of zP4 up to and including the +** first null byte. If n>0 then copy n+1 bytes of zP4. +** +** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points +** to a string or structure that is guaranteed to exist for the lifetime of +** the Vdbe. In these cases we can just copy the pointer. +** +** If addr<0 then change P4 on the most recently inserted instruction. +*/ +static void SQLITE_NOINLINE vdbeChangeP4Full( + Vdbe *p, + Op *pOp, + const char *zP4, + int n +){ + if( pOp->p4type ){ + freeP4(p->db, pOp->p4type, pOp->p4.p); + pOp->p4type = 0; + pOp->p4.p = 0; + } + if( n<0 ){ + sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n); + }else{ + if( n==0 ) n = sqlite3Strlen30(zP4); + pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); + pOp->p4type = P4_DYNAMIC; + } +} +SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ + Op *pOp; + sqlite3 *db; + assert( p!=0 ); + db = p->db; + assert( p->magic==VDBE_MAGIC_INIT ); + assert( p->aOp!=0 || db->mallocFailed ); + if( db->mallocFailed ){ + if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4); + return; + } + assert( p->nOp>0 ); + assert( addrnOp ); + if( addr<0 ){ + addr = p->nOp - 1; + } + pOp = &p->aOp[addr]; + if( n>=0 || pOp->p4type ){ + vdbeChangeP4Full(p, pOp, zP4, n); + return; + } + if( n==P4_INT32 ){ + /* Note: this cast is safe, because the origin data point was an int + ** that was cast to a (const char *). */ + pOp->p4.i = SQLITE_PTR_TO_INT(zP4); + pOp->p4type = P4_INT32; + }else if( zP4!=0 ){ + assert( n<0 ); + pOp->p4.p = (void*)zP4; + pOp->p4type = (signed char)n; + if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4); + } +} + +/* +** Change the P4 operand of the most recently coded instruction +** to the value defined by the arguments. This is a high-speed +** version of sqlite3VdbeChangeP4(). +** +** The P4 operand must not have been previously defined. And the new +** P4 must not be P4_INT32. Use sqlite3VdbeChangeP4() in either of +** those cases. +*/ +SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){ + VdbeOp *pOp; + assert( n!=P4_INT32 && n!=P4_VTAB ); + assert( n<=0 ); + if( p->db->mallocFailed ){ + freeP4(p->db, n, pP4); + }else{ + assert( pP4!=0 ); + assert( p->nOp>0 ); + pOp = &p->aOp[p->nOp-1]; + assert( pOp->p4type==P4_NOTUSED ); + pOp->p4type = n; + pOp->p4.p = pP4; + } +} + +/* +** Set the P4 on the most recently added opcode to the KeyInfo for the +** index given. +*/ +SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){ + Vdbe *v = pParse->pVdbe; + KeyInfo *pKeyInfo; + assert( v!=0 ); + assert( pIdx!=0 ); + pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx); + if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); +} + +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS +/* +** Change the comment on the most recently coded instruction. Or +** insert a No-op and add the comment to that new instruction. This +** makes the code easier to read during debugging. None of this happens +** in a production build. +*/ +static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ + assert( p->nOp>0 || p->aOp==0 ); + assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); + if( p->nOp ){ + assert( p->aOp ); + sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment); + p->aOp[p->nOp-1].zComment = sqlite3VMPrintf(p->db, zFormat, ap); + } +} +SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ + va_list ap; + if( p ){ + va_start(ap, zFormat); + vdbeVComment(p, zFormat, ap); + va_end(ap); + } +} +SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){ + va_list ap; + if( p ){ + sqlite3VdbeAddOp0(p, OP_Noop); + va_start(ap, zFormat); + vdbeVComment(p, zFormat, ap); + va_end(ap); + } +} +#endif /* NDEBUG */ + +#ifdef SQLITE_VDBE_COVERAGE +/* +** Set the value if the iSrcLine field for the previously coded instruction. +*/ +SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ + sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine; +} +#endif /* SQLITE_VDBE_COVERAGE */ + +/* +** Return the opcode for a given address. If the address is -1, then +** return the most recently inserted opcode. +** +** If a memory allocation error has occurred prior to the calling of this +** routine, then a pointer to a dummy VdbeOp will be returned. That opcode +** is readable but not writable, though it is cast to a writable value. +** The return of a dummy opcode allows the call to continue functioning +** after an OOM fault without having to check to see if the return from +** this routine is a valid pointer. But because the dummy.opcode is 0, +** dummy will never be written to. This is verified by code inspection and +** by running with Valgrind. +*/ +SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ + /* C89 specifies that the constant "dummy" will be initialized to all + ** zeros, which is correct. MSVC generates a warning, nevertheless. */ + static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ + assert( p->magic==VDBE_MAGIC_INIT ); + if( addr<0 ){ + addr = p->nOp - 1; + } + assert( (addr>=0 && addrnOp) || p->db->mallocFailed ); + if( p->db->mallocFailed ){ + return (VdbeOp*)&dummy; + }else{ + return &p->aOp[addr]; + } +} + +#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) +/* +** Return an integer value for one of the parameters to the opcode pOp +** determined by character c. +*/ +static int translateP(char c, const Op *pOp){ + if( c=='1' ) return pOp->p1; + if( c=='2' ) return pOp->p2; + if( c=='3' ) return pOp->p3; + if( c=='4' ) return pOp->p4.i; + return pOp->p5; +} + +/* +** Compute a string for the "comment" field of a VDBE opcode listing. +** +** The Synopsis: field in comments in the vdbe.c source file gets converted +** to an extra string that is appended to the sqlite3OpcodeName(). In the +** absence of other comments, this synopsis becomes the comment on the opcode. +** Some translation occurs: +** +** "PX" -> "r[X]" +** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1 +** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0 +** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x +*/ +static int displayComment( + const Op *pOp, /* The opcode to be commented */ + const char *zP4, /* Previously obtained value for P4 */ + char *zTemp, /* Write result here */ + int nTemp /* Space available in zTemp[] */ +){ + const char *zOpName; + const char *zSynopsis; + int nOpName; + int ii, jj; + char zAlt[50]; + zOpName = sqlite3OpcodeName(pOp->opcode); + nOpName = sqlite3Strlen30(zOpName); + if( zOpName[nOpName+1] ){ + int seenCom = 0; + char c; + zSynopsis = zOpName += nOpName + 1; + if( strncmp(zSynopsis,"IF ",3)==0 ){ + if( pOp->p5 & SQLITE_STOREP2 ){ + sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3); + }else{ + sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); + } + zSynopsis = zAlt; + } + for(ii=jj=0; jjzComment); + seenCom = 1; + }else{ + int v1 = translateP(c, pOp); + int v2; + sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1); + if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){ + ii += 3; + jj += sqlite3Strlen30(zTemp+jj); + v2 = translateP(zSynopsis[ii], pOp); + if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){ + ii += 2; + v2++; + } + if( v2>1 ){ + sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1); + } + }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){ + ii += 4; + } + } + jj += sqlite3Strlen30(zTemp+jj); + }else{ + zTemp[jj++] = c; + } + } + if( !seenCom && jjzComment ){ + sqlite3_snprintf(nTemp-jj, zTemp+jj, "; %s", pOp->zComment); + jj += sqlite3Strlen30(zTemp+jj); + } + if( jjzComment ){ + sqlite3_snprintf(nTemp, zTemp, "%s", pOp->zComment); + jj = sqlite3Strlen30(zTemp); + }else{ + zTemp[0] = 0; + jj = 0; + } + return jj; +} +#endif /* SQLITE_DEBUG */ + +#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) +/* +** Translate the P4.pExpr value for an OP_CursorHint opcode into text +** that can be displayed in the P4 column of EXPLAIN output. +*/ +static void displayP4Expr(StrAccum *p, Expr *pExpr){ + const char *zOp = 0; + switch( pExpr->op ){ + case TK_STRING: + sqlite3XPrintf(p, "%Q", pExpr->u.zToken); + break; + case TK_INTEGER: + sqlite3XPrintf(p, "%d", pExpr->u.iValue); + break; + case TK_NULL: + sqlite3XPrintf(p, "NULL"); + break; + case TK_REGISTER: { + sqlite3XPrintf(p, "r[%d]", pExpr->iTable); + break; + } + case TK_COLUMN: { + if( pExpr->iColumn<0 ){ + sqlite3XPrintf(p, "rowid"); + }else{ + sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn); + } + break; + } + case TK_LT: zOp = "LT"; break; + case TK_LE: zOp = "LE"; break; + case TK_GT: zOp = "GT"; break; + case TK_GE: zOp = "GE"; break; + case TK_NE: zOp = "NE"; break; + case TK_EQ: zOp = "EQ"; break; + case TK_IS: zOp = "IS"; break; + case TK_ISNOT: zOp = "ISNOT"; break; + case TK_AND: zOp = "AND"; break; + case TK_OR: zOp = "OR"; break; + case TK_PLUS: zOp = "ADD"; break; + case TK_STAR: zOp = "MUL"; break; + case TK_MINUS: zOp = "SUB"; break; + case TK_REM: zOp = "REM"; break; + case TK_BITAND: zOp = "BITAND"; break; + case TK_BITOR: zOp = "BITOR"; break; + case TK_SLASH: zOp = "DIV"; break; + case TK_LSHIFT: zOp = "LSHIFT"; break; + case TK_RSHIFT: zOp = "RSHIFT"; break; + case TK_CONCAT: zOp = "CONCAT"; break; + case TK_UMINUS: zOp = "MINUS"; break; + case TK_UPLUS: zOp = "PLUS"; break; + case TK_BITNOT: zOp = "BITNOT"; break; + case TK_NOT: zOp = "NOT"; break; + case TK_ISNULL: zOp = "ISNULL"; break; + case TK_NOTNULL: zOp = "NOTNULL"; break; + + default: + sqlite3XPrintf(p, "%s", "expr"); + break; + } + + if( zOp ){ + sqlite3XPrintf(p, "%s(", zOp); + displayP4Expr(p, pExpr->pLeft); + if( pExpr->pRight ){ + sqlite3StrAccumAppend(p, ",", 1); + displayP4Expr(p, pExpr->pRight); + } + sqlite3StrAccumAppend(p, ")", 1); + } +} +#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */ + + +#if VDBE_DISPLAY_P4 +/* +** Compute a string that describes the P4 parameter for an opcode. +** Use zTemp for any required temporary buffer space. +*/ +static char *displayP4(Op *pOp, char *zTemp, int nTemp){ + char *zP4 = zTemp; + StrAccum x; + assert( nTemp>=20 ); + sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0); + switch( pOp->p4type ){ + case P4_KEYINFO: { + int j; + KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; + assert( pKeyInfo->aSortOrder!=0 ); + sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField); + for(j=0; jnField; j++){ + CollSeq *pColl = pKeyInfo->aColl[j]; + const char *zColl = pColl ? pColl->zName : ""; + if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; + sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl); + } + sqlite3StrAccumAppend(&x, ")", 1); + break; + } +#ifdef SQLITE_ENABLE_CURSOR_HINTS + case P4_EXPR: { + displayP4Expr(&x, pOp->p4.pExpr); + break; + } +#endif + case P4_COLLSEQ: { + CollSeq *pColl = pOp->p4.pColl; + sqlite3XPrintf(&x, "(%.20s)", pColl->zName); + break; + } + case P4_FUNCDEF: { + FuncDef *pDef = pOp->p4.pFunc; + sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); + break; + } +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + case P4_FUNCCTX: { + FuncDef *pDef = pOp->p4.pCtx->pFunc; + sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); + break; + } +#endif + case P4_INT64: { + sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64); + break; + } + case P4_INT32: { + sqlite3XPrintf(&x, "%d", pOp->p4.i); + break; + } + case P4_REAL: { + sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal); + break; + } + case P4_MEM: { + Mem *pMem = pOp->p4.pMem; + if( pMem->flags & MEM_Str ){ + zP4 = pMem->z; + }else if( pMem->flags & MEM_Int ){ + sqlite3XPrintf(&x, "%lld", pMem->u.i); + }else if( pMem->flags & MEM_Real ){ + sqlite3XPrintf(&x, "%.16g", pMem->u.r); + }else if( pMem->flags & MEM_Null ){ + zP4 = "NULL"; + }else{ + assert( pMem->flags & MEM_Blob ); + zP4 = "(blob)"; + } + break; + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + case P4_VTAB: { + sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; + sqlite3XPrintf(&x, "vtab:%p", pVtab); + break; + } +#endif + case P4_INTARRAY: { + int i; + int *ai = pOp->p4.ai; + int n = ai[0]; /* The first element of an INTARRAY is always the + ** count of the number of elements to follow */ + for(i=1; ip4.pTab->zName); + break; + } + default: { + zP4 = pOp->p4.z; + if( zP4==0 ){ + zP4 = zTemp; + zTemp[0] = 0; + } + } + } + sqlite3StrAccumFinish(&x); + assert( zP4!=0 ); + return zP4; +} +#endif /* VDBE_DISPLAY_P4 */ + +/* +** Declare to the Vdbe that the BTree object at db->aDb[i] is used. +** +** The prepared statements need to know in advance the complete set of +** attached databases that will be use. A mask of these databases +** is maintained in p->btreeMask. The p->lockMask value is the subset of +** p->btreeMask of databases that will require a lock. +*/ +SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){ + assert( i>=0 && idb->nDb && i<(int)sizeof(yDbMask)*8 ); + assert( i<(int)sizeof(p->btreeMask)*8 ); + DbMaskSet(p->btreeMask, i); + if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){ + DbMaskSet(p->lockMask, i); + } +} + +#if !defined(SQLITE_OMIT_SHARED_CACHE) +/* +** If SQLite is compiled to support shared-cache mode and to be threadsafe, +** this routine obtains the mutex associated with each BtShared structure +** that may be accessed by the VM passed as an argument. In doing so it also +** sets the BtShared.db member of each of the BtShared structures, ensuring +** that the correct busy-handler callback is invoked if required. +** +** If SQLite is not threadsafe but does support shared-cache mode, then +** sqlite3BtreeEnter() is invoked to set the BtShared.db variables +** of all of BtShared structures accessible via the database handle +** associated with the VM. +** +** If SQLite is not threadsafe and does not support shared-cache mode, this +** function is a no-op. +** +** The p->btreeMask field is a bitmask of all btrees that the prepared +** statement p will ever use. Let N be the number of bits in p->btreeMask +** corresponding to btrees that use shared cache. Then the runtime of +** this routine is N*N. But as N is rarely more than 1, this should not +** be a problem. +*/ +SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){ + int i; + sqlite3 *db; + Db *aDb; + int nDb; + if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ + db = p->db; + aDb = db->aDb; + nDb = db->nDb; + for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ + sqlite3BtreeEnter(aDb[i].pBt); + } + } +} +#endif + +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 +/* +** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter(). +*/ +static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){ + int i; + sqlite3 *db; + Db *aDb; + int nDb; + db = p->db; + aDb = db->aDb; + nDb = db->nDb; + for(i=0; ilockMask,i) && ALWAYS(aDb[i].pBt!=0) ){ + sqlite3BtreeLeave(aDb[i].pBt); + } + } +} +SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){ + if( DbMaskAllZero(p->lockMask) ) return; /* The common case */ + vdbeLeave(p); +} +#endif + +#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) +/* +** Print a single opcode. This routine is used for debugging only. +*/ +SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ + char *zP4; + char zPtr[50]; + char zCom[100]; + static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n"; + if( pOut==0 ) pOut = stdout; + zP4 = displayP4(pOp, zPtr, sizeof(zPtr)); +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + displayComment(pOp, zP4, zCom, sizeof(zCom)); +#else + zCom[0] = 0; +#endif + /* NB: The sqlite3OpcodeName() function is implemented by code created + ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the + ** information from the vdbe.c source text */ + fprintf(pOut, zFormat1, pc, + sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5, + zCom + ); + fflush(pOut); +} +#endif + +/* +** Initialize an array of N Mem element. +*/ +static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ + while( (N--)>0 ){ + p->db = db; + p->flags = flags; + p->szMalloc = 0; +#ifdef SQLITE_DEBUG + p->pScopyFrom = 0; +#endif + p++; + } +} + +/* +** Release an array of N Mem elements +*/ +static void releaseMemArray(Mem *p, int N){ + if( p && N ){ + Mem *pEnd = &p[N]; + sqlite3 *db = p->db; + if( db->pnBytesFreed ){ + do{ + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); + }while( (++p)flags & MEM_Agg ); + testcase( p->flags & MEM_Dyn ); + testcase( p->flags & MEM_Frame ); + testcase( p->flags & MEM_RowSet ); + if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ + sqlite3VdbeMemRelease(p); + }else if( p->szMalloc ){ + sqlite3DbFreeNN(db, p->zMalloc); + p->szMalloc = 0; + } + + p->flags = MEM_Undefined; + }while( (++p)nChildMem]; + for(i=0; inChildCsr; i++){ + sqlite3VdbeFreeCursor(p->v, apCsr[i]); + } + releaseMemArray(aMem, p->nChildMem); + sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0); + sqlite3DbFree(p->v->db, p); +} + +#ifndef SQLITE_OMIT_EXPLAIN +/* +** Give a listing of the program in the virtual machine. +** +** The interface is the same as sqlite3VdbeExec(). But instead of +** running the code, it invokes the callback once for each instruction. +** This feature is used to implement "EXPLAIN". +** +** When p->explain==1, each instruction is listed. When +** p->explain==2, only OP_Explain instructions are listed and these +** are shown in a different format. p->explain==2 is used to implement +** EXPLAIN QUERY PLAN. +** +** When p->explain==1, first the main program is listed, then each of +** the trigger subprograms are listed one by one. +*/ +SQLITE_PRIVATE int sqlite3VdbeList( + Vdbe *p /* The VDBE */ +){ + int nRow; /* Stop when row count reaches this */ + int nSub = 0; /* Number of sub-vdbes seen so far */ + SubProgram **apSub = 0; /* Array of sub-vdbes */ + Mem *pSub = 0; /* Memory cell hold array of subprogs */ + sqlite3 *db = p->db; /* The database connection */ + int i; /* Loop counter */ + int rc = SQLITE_OK; /* Return code */ + Mem *pMem = &p->aMem[1]; /* First Mem of result set */ + + assert( p->explain ); + assert( p->magic==VDBE_MAGIC_RUN ); + assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM ); + + /* Even though this opcode does not use dynamic strings for + ** the result, result columns may become dynamic if the user calls + ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. + */ + releaseMemArray(pMem, 8); + p->pResultSet = 0; + + if( p->rc==SQLITE_NOMEM_BKPT ){ + /* This happens if a malloc() inside a call to sqlite3_column_text() or + ** sqlite3_column_text16() failed. */ + sqlite3OomFault(db); + return SQLITE_ERROR; + } + + /* When the number of output rows reaches nRow, that means the + ** listing has finished and sqlite3_step() should return SQLITE_DONE. + ** nRow is the sum of the number of rows in the main program, plus + ** the sum of the number of rows in all trigger subprograms encountered + ** so far. The nRow value will increase as new trigger subprograms are + ** encountered, but p->pc will eventually catch up to nRow. + */ + nRow = p->nOp; + if( p->explain==1 ){ + /* The first 8 memory cells are used for the result set. So we will + ** commandeer the 9th cell to use as storage for an array of pointers + ** to trigger subprograms. The VDBE is guaranteed to have at least 9 + ** cells. */ + assert( p->nMem>9 ); + pSub = &p->aMem[9]; + if( pSub->flags&MEM_Blob ){ + /* On the first call to sqlite3_step(), pSub will hold a NULL. It is + ** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */ + nSub = pSub->n/sizeof(Vdbe*); + apSub = (SubProgram **)pSub->z; + } + for(i=0; inOp; + } + } + + do{ + i = p->pc++; + }while( iexplain==2 && p->aOp[i].opcode!=OP_Explain ); + if( i>=nRow ){ + p->rc = SQLITE_OK; + rc = SQLITE_DONE; + }else if( db->u1.isInterrupted ){ + p->rc = SQLITE_INTERRUPT; + rc = SQLITE_ERROR; + sqlite3VdbeError(p, sqlite3ErrStr(p->rc)); + }else{ + char *zP4; + Op *pOp; + if( inOp ){ + /* The output line number is small enough that we are still in the + ** main program. */ + pOp = &p->aOp[i]; + }else{ + /* We are currently listing subprograms. Figure out which one and + ** pick up the appropriate opcode. */ + int j; + i -= p->nOp; + for(j=0; i>=apSub[j]->nOp; j++){ + i -= apSub[j]->nOp; + } + pOp = &apSub[j]->aOp[i]; + } + if( p->explain==1 ){ + pMem->flags = MEM_Int; + pMem->u.i = i; /* Program counter */ + pMem++; + + pMem->flags = MEM_Static|MEM_Str|MEM_Term; + pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */ + assert( pMem->z!=0 ); + pMem->n = sqlite3Strlen30(pMem->z); + pMem->enc = SQLITE_UTF8; + pMem++; + + /* When an OP_Program opcode is encounter (the only opcode that has + ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms + ** kept in p->aMem[9].z to hold the new program - assuming this subprogram + ** has not already been seen. + */ + if( pOp->p4type==P4_SUBPROGRAM ){ + int nByte = (nSub+1)*sizeof(SubProgram*); + int j; + for(j=0; jp4.pProgram ) break; + } + if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){ + apSub = (SubProgram **)pSub->z; + apSub[nSub++] = pOp->p4.pProgram; + pSub->flags |= MEM_Blob; + pSub->n = nSub*sizeof(SubProgram*); + } + } + } + + pMem->flags = MEM_Int; + pMem->u.i = pOp->p1; /* P1 */ + pMem++; + + pMem->flags = MEM_Int; + pMem->u.i = pOp->p2; /* P2 */ + pMem++; + + pMem->flags = MEM_Int; + pMem->u.i = pOp->p3; /* P3 */ + pMem++; + + if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */ + assert( p->db->mallocFailed ); + return SQLITE_ERROR; + } + pMem->flags = MEM_Str|MEM_Term; + zP4 = displayP4(pOp, pMem->z, pMem->szMalloc); + if( zP4!=pMem->z ){ + pMem->n = 0; + sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0); + }else{ + assert( pMem->z!=0 ); + pMem->n = sqlite3Strlen30(pMem->z); + pMem->enc = SQLITE_UTF8; + } + pMem++; + + if( p->explain==1 ){ + if( sqlite3VdbeMemClearAndResize(pMem, 4) ){ + assert( p->db->mallocFailed ); + return SQLITE_ERROR; + } + pMem->flags = MEM_Str|MEM_Term; + pMem->n = 2; + sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */ + pMem->enc = SQLITE_UTF8; + pMem++; + +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + if( sqlite3VdbeMemClearAndResize(pMem, 500) ){ + assert( p->db->mallocFailed ); + return SQLITE_ERROR; + } + pMem->flags = MEM_Str|MEM_Term; + pMem->n = displayComment(pOp, zP4, pMem->z, 500); + pMem->enc = SQLITE_UTF8; +#else + pMem->flags = MEM_Null; /* Comment */ +#endif + } + + p->nResColumn = 8 - 4*(p->explain-1); + p->pResultSet = &p->aMem[1]; + p->rc = SQLITE_OK; + rc = SQLITE_ROW; + } + return rc; +} +#endif /* SQLITE_OMIT_EXPLAIN */ + +#ifdef SQLITE_DEBUG +/* +** Print the SQL that was used to generate a VDBE program. +*/ +SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe *p){ + const char *z = 0; + if( p->zSql ){ + z = p->zSql; + }else if( p->nOp>=1 ){ + const VdbeOp *pOp = &p->aOp[0]; + if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){ + z = pOp->p4.z; + while( sqlite3Isspace(*z) ) z++; + } + } + if( z ) printf("SQL: [%s]\n", z); +} +#endif + +#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) +/* +** Print an IOTRACE message showing SQL content. +*/ +SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){ + int nOp = p->nOp; + VdbeOp *pOp; + if( sqlite3IoTrace==0 ) return; + if( nOp<1 ) return; + pOp = &p->aOp[0]; + if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){ + int i, j; + char z[1000]; + sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.z); + for(i=0; sqlite3Isspace(z[i]); i++){} + for(j=0; z[i]; i++){ + if( sqlite3Isspace(z[i]) ){ + if( z[i-1]!=' ' ){ + z[j++] = ' '; + } + }else{ + z[j++] = z[i]; + } + } + z[j] = 0; + sqlite3IoTrace("SQL %s\n", z); + } +} +#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */ + +/* An instance of this object describes bulk memory available for use +** by subcomponents of a prepared statement. Space is allocated out +** of a ReusableSpace object by the allocSpace() routine below. +*/ +struct ReusableSpace { + u8 *pSpace; /* Available memory */ + int nFree; /* Bytes of available memory */ + int nNeeded; /* Total bytes that could not be allocated */ +}; + +/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf +** from the ReusableSpace object. Return a pointer to the allocated +** memory on success. If insufficient memory is available in the +** ReusableSpace object, increase the ReusableSpace.nNeeded +** value by the amount needed and return NULL. +** +** If pBuf is not initially NULL, that means that the memory has already +** been allocated by a prior call to this routine, so just return a copy +** of pBuf and leave ReusableSpace unchanged. +** +** This allocator is employed to repurpose unused slots at the end of the +** opcode array of prepared state for other memory needs of the prepared +** statement. +*/ +static void *allocSpace( + struct ReusableSpace *p, /* Bulk memory available for allocation */ + void *pBuf, /* Pointer to a prior allocation */ + int nByte /* Bytes of memory needed */ +){ + assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); + if( pBuf==0 ){ + nByte = ROUND8(nByte); + if( nByte <= p->nFree ){ + p->nFree -= nByte; + pBuf = &p->pSpace[p->nFree]; + }else{ + p->nNeeded += nByte; + } + } + assert( EIGHT_BYTE_ALIGNMENT(pBuf) ); + return pBuf; +} + +/* +** Rewind the VDBE back to the beginning in preparation for +** running it. +*/ +SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + int i; +#endif + assert( p!=0 ); + assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET ); + + /* There should be at least one opcode. + */ + assert( p->nOp>0 ); + + /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */ + p->magic = VDBE_MAGIC_RUN; + +#ifdef SQLITE_DEBUG + for(i=0; inMem; i++){ + assert( p->aMem[i].db==p->db ); + } +#endif + p->pc = -1; + p->rc = SQLITE_OK; + p->errorAction = OE_Abort; + p->nChange = 0; + p->cacheCtr = 1; + p->minWriteFileFormat = 255; + p->iStatement = 0; + p->nFkConstraint = 0; +#ifdef VDBE_PROFILE + for(i=0; inOp; i++){ + p->aOp[i].cnt = 0; + p->aOp[i].cycles = 0; + } +#endif +} + +/* +** Prepare a virtual machine for execution for the first time after +** creating the virtual machine. This involves things such +** as allocating registers and initializing the program counter. +** After the VDBE has be prepped, it can be executed by one or more +** calls to sqlite3VdbeExec(). +** +** This function may be called exactly once on each virtual machine. +** After this routine is called the VM has been "packaged" and is ready +** to run. After this routine is called, further calls to +** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects +** the Vdbe from the Parse object that helped generate it so that the +** the Vdbe becomes an independent entity and the Parse object can be +** destroyed. +** +** Use the sqlite3VdbeRewind() procedure to restore a virtual machine back +** to its initial state after it has been run. +*/ +SQLITE_PRIVATE void sqlite3VdbeMakeReady( + Vdbe *p, /* The VDBE */ + Parse *pParse /* Parsing context */ +){ + sqlite3 *db; /* The database connection */ + int nVar; /* Number of parameters */ + int nMem; /* Number of VM memory registers */ + int nCursor; /* Number of cursors required */ + int nArg; /* Number of arguments in subprograms */ + int n; /* Loop counter */ + struct ReusableSpace x; /* Reusable bulk memory */ + + assert( p!=0 ); + assert( p->nOp>0 ); + assert( pParse!=0 ); + assert( p->magic==VDBE_MAGIC_INIT ); + assert( pParse==p->pParse ); + db = p->db; + assert( db->mallocFailed==0 ); + nVar = pParse->nVar; + nMem = pParse->nMem; + nCursor = pParse->nTab; + nArg = pParse->nMaxArg; + + /* Each cursor uses a memory cell. The first cursor (cursor 0) can + ** use aMem[0] which is not otherwise used by the VDBE program. Allocate + ** space at the end of aMem[] for cursors 1 and greater. + ** See also: allocateCursor(). + */ + nMem += nCursor; + if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */ + + /* Figure out how much reusable memory is available at the end of the + ** opcode array. This extra memory will be reallocated for other elements + ** of the prepared statement. + */ + n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ + x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */ + assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); + x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */ + assert( x.nFree>=0 ); + assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) ); + + resolveP2Values(p, &nArg); + p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); + if( pParse->explain && nMem<10 ){ + nMem = 10; + } + p->expired = 0; + + /* Memory for registers, parameters, cursor, etc, is allocated in one or two + ** passes. On the first pass, we try to reuse unused memory at the + ** end of the opcode array. If we are unable to satisfy all memory + ** requirements by reusing the opcode array tail, then the second + ** pass will fill in the remainder using a fresh memory allocation. + ** + ** This two-pass approach that reuses as much memory as possible from + ** the leftover memory at the end of the opcode array. This can significantly + ** reduce the amount of memory held by a prepared statement. + */ + do { + x.nNeeded = 0; + p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); + p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); + p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); + p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); +#endif + if( x.nNeeded==0 ) break; + x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded); + x.nFree = x.nNeeded; + }while( !db->mallocFailed ); + + p->pVList = pParse->pVList; + pParse->pVList = 0; + p->explain = pParse->explain; + if( db->mallocFailed ){ + p->nVar = 0; + p->nCursor = 0; + p->nMem = 0; + }else{ + p->nCursor = nCursor; + p->nVar = (ynVar)nVar; + initMemArray(p->aVar, nVar, db, MEM_Null); + p->nMem = nMem; + initMemArray(p->aMem, nMem, db, MEM_Undefined); + memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*)); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + memset(p->anExec, 0, p->nOp*sizeof(i64)); +#endif + } + sqlite3VdbeRewind(p); +} + +/* +** Close a VDBE cursor and release all the resources that cursor +** happens to hold. +*/ +SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ + if( pCx==0 ){ + return; + } + assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE ); + switch( pCx->eCurType ){ + case CURTYPE_SORTER: { + sqlite3VdbeSorterClose(p->db, pCx); + break; + } + case CURTYPE_BTREE: { + if( pCx->isEphemeral ){ + if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx); + /* The pCx->pCursor will be close automatically, if it exists, by + ** the call above. */ + }else{ + assert( pCx->uc.pCursor!=0 ); + sqlite3BtreeCloseCursor(pCx->uc.pCursor); + } + break; + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + case CURTYPE_VTAB: { + sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur; + const sqlite3_module *pModule = pVCur->pVtab->pModule; + assert( pVCur->pVtab->nRef>0 ); + pVCur->pVtab->nRef--; + pModule->xClose(pVCur); + break; + } +#endif + } +} + +/* +** Close all cursors in the current frame. +*/ +static void closeCursorsInFrame(Vdbe *p){ + if( p->apCsr ){ + int i; + for(i=0; inCursor; i++){ + VdbeCursor *pC = p->apCsr[i]; + if( pC ){ + sqlite3VdbeFreeCursor(p, pC); + p->apCsr[i] = 0; + } + } + } +} + +/* +** Copy the values stored in the VdbeFrame structure to its Vdbe. This +** is used, for example, when a trigger sub-program is halted to restore +** control to the main program. +*/ +SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ + Vdbe *v = pFrame->v; + closeCursorsInFrame(v); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + v->anExec = pFrame->anExec; +#endif + v->aOp = pFrame->aOp; + v->nOp = pFrame->nOp; + v->aMem = pFrame->aMem; + v->nMem = pFrame->nMem; + v->apCsr = pFrame->apCsr; + v->nCursor = pFrame->nCursor; + v->db->lastRowid = pFrame->lastRowid; + v->nChange = pFrame->nChange; + v->db->nChange = pFrame->nDbChange; + sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0); + v->pAuxData = pFrame->pAuxData; + pFrame->pAuxData = 0; + return pFrame->pc; +} + +/* +** Close all cursors. +** +** Also release any dynamic memory held by the VM in the Vdbe.aMem memory +** cell array. This is necessary as the memory cell array may contain +** pointers to VdbeFrame objects, which may in turn contain pointers to +** open cursors. +*/ +static void closeAllCursors(Vdbe *p){ + if( p->pFrame ){ + VdbeFrame *pFrame; + for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); + sqlite3VdbeFrameRestore(pFrame); + p->pFrame = 0; + p->nFrame = 0; + } + assert( p->nFrame==0 ); + closeCursorsInFrame(p); + if( p->aMem ){ + releaseMemArray(p->aMem, p->nMem); + } + while( p->pDelFrame ){ + VdbeFrame *pDel = p->pDelFrame; + p->pDelFrame = pDel->pParent; + sqlite3VdbeFrameDelete(pDel); + } + + /* Delete any auxdata allocations made by the VM */ + if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0); + assert( p->pAuxData==0 ); +} + +/* +** 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; inCursor; i++) assert( p->apCsr[i]==0 ); + if( p->aMem ){ + for(i=0; inMem; 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 +** be called on an SQL statement before sqlite3_step(). +*/ +SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ + Mem *pColName; + int n; + sqlite3 *db = p->db; + + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + sqlite3DbFree(db, p->aColName); + n = nResColumn*COLNAME_N; + p->nResColumn = (u16)nResColumn; + p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); + if( p->aColName==0 ) return; + initMemArray(p->aColName, n, p->db, MEM_Null); +} + +/* +** Set the name of the idx'th column to be returned by the SQL statement. +** zName must be a pointer to a nul terminated string. +** +** This call must be made after a call to sqlite3VdbeSetNumCols(). +** +** The final parameter, xDel, must be one of SQLITE_DYNAMIC, SQLITE_STATIC +** or SQLITE_TRANSIENT. If it is SQLITE_DYNAMIC, then the buffer pointed +** to by zName will be freed by sqlite3DbFree() when the vdbe is destroyed. +*/ +SQLITE_PRIVATE int sqlite3VdbeSetColName( + Vdbe *p, /* Vdbe being configured */ + int idx, /* Index of column zName applies to */ + int var, /* One of the COLNAME_* constants */ + const char *zName, /* Pointer to buffer containing name */ + void (*xDel)(void*) /* Memory management strategy for zName */ +){ + int rc; + Mem *pColName; + assert( idxnResColumn ); + assert( vardb->mallocFailed ){ + assert( !zName || xDel!=SQLITE_DYNAMIC ); + return SQLITE_NOMEM_BKPT; + } + assert( p->aColName!=0 ); + pColName = &(p->aColName[idx+var*p->nResColumn]); + rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel); + assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 ); + return rc; +} + +/* +** A read or write transaction may or may not be active on database handle +** db. If a transaction is active, commit it. If there is a +** write-transaction spanning more than one database file, this routine +** takes care of the master journal trickery. +*/ +static int vdbeCommit(sqlite3 *db, Vdbe *p){ + int i; + int nTrans = 0; /* Number of databases with an active write-transaction + ** that are candidates for a two-phase commit using a + ** master-journal */ + int rc = SQLITE_OK; + int needXcommit = 0; + +#ifdef SQLITE_OMIT_VIRTUALTABLE + /* With this option, sqlite3VtabSync() is defined to be simply + ** SQLITE_OK so p is not used. + */ + UNUSED_PARAMETER(p); +#endif + + /* Before doing anything else, call the xSync() callback for any + ** virtual module tables written in this transaction. This has to + ** be done before determining whether a master journal file is + ** required, as an xSync() callback may add an attached database + ** to the transaction. + */ + rc = sqlite3VtabSync(db, p); + + /* This loop determines (a) if the commit hook should be invoked and + ** (b) how many database files have open write transactions, not + ** including the temp database. (b) is important because if more than + ** one database file has an open write transaction, a master journal + ** file is required for an atomic commit. + */ + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( sqlite3BtreeIsInTrans(pBt) ){ + /* Whether or not a database might need a master journal depends upon + ** its journal mode (among other things). This matrix determines which + ** journal modes use a master journal and which do not */ + static const u8 aMJNeeded[] = { + /* DELETE */ 1, + /* PERSIST */ 1, + /* OFF */ 0, + /* TRUNCATE */ 1, + /* MEMORY */ 0, + /* WAL */ 0 + }; + Pager *pPager; /* Pager associated with pBt */ + needXcommit = 1; + sqlite3BtreeEnter(pBt); + pPager = sqlite3BtreePager(pBt); + if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF + && aMJNeeded[sqlite3PagerGetJournalMode(pPager)] + ){ + assert( i!=1 ); + nTrans++; + } + rc = sqlite3PagerExclusiveLock(pPager); + sqlite3BtreeLeave(pBt); + } + } + if( rc!=SQLITE_OK ){ + return rc; + } + + /* If there are any write-transactions at all, invoke the commit hook */ + if( needXcommit && db->xCommitCallback ){ + rc = db->xCommitCallback(db->pCommitArg); + if( rc ){ + return SQLITE_CONSTRAINT_COMMITHOOK; + } + } + + /* The simple case - no more than one database file (not counting the + ** TEMP database) has a transaction active. There is no need for the + ** master-journal. + ** + ** If the return value of sqlite3BtreeGetFilename() is a zero length + ** string, it means the main database is :memory: or a temp file. In + ** that case we do not support atomic multi-file commits, so use the + ** simple case then too. + */ + if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt)) + || nTrans<=1 + ){ + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + rc = sqlite3BtreeCommitPhaseOne(pBt, 0); + } + } + + /* Do the commit only if all databases successfully complete phase 1. + ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an + ** IO error while deleting or truncating a journal file. It is unlikely, + ** but could happen. In this case abandon processing and return the error. + */ + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + rc = sqlite3BtreeCommitPhaseTwo(pBt, 0); + } + } + if( rc==SQLITE_OK ){ + sqlite3VtabCommit(db); + } + } + + /* The complex case - There is a multi-file write-transaction active. + ** This requires a master journal file to ensure the transaction is + ** committed atomically. + */ +#ifndef SQLITE_OMIT_DISKIO + else{ + sqlite3_vfs *pVfs = db->pVfs; + char *zMaster = 0; /* File-name for the master journal */ + char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); + sqlite3_file *pMaster = 0; + i64 offset = 0; + int res; + int retryCount = 0; + int nMainFile; + + /* Select a master journal file name */ + nMainFile = sqlite3Strlen30(zMainFile); + zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile); + if( zMaster==0 ) return SQLITE_NOMEM_BKPT; + do { + u32 iRandom; + if( retryCount ){ + if( retryCount>100 ){ + sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster); + sqlite3OsDelete(pVfs, zMaster, 0); + break; + }else if( retryCount==1 ){ + sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster); + } + } + retryCount++; + sqlite3_randomness(sizeof(iRandom), &iRandom); + sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X", + (iRandom>>8)&0xffffff, iRandom&0xff); + /* The antipenultimate character of the master journal name must + ** be "9" to avoid name collisions when using 8+3 filenames. */ + assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' ); + sqlite3FileSuffix3(zMainFile, zMaster); + rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); + }while( rc==SQLITE_OK && res ); + if( rc==SQLITE_OK ){ + /* Open the master journal. */ + rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, + SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE| + SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0 + ); + } + if( rc!=SQLITE_OK ){ + sqlite3DbFree(db, zMaster); + return rc; + } + + /* Write the name of each database file in the transaction into the new + ** master journal file. If an error occurs at this point close + ** and delete the master journal file. All the individual journal files + ** still have 'null' as the master journal pointer, so they will roll + ** back independently if a failure occurs. + */ + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( sqlite3BtreeIsInTrans(pBt) ){ + char const *zFile = sqlite3BtreeGetJournalname(pBt); + if( zFile==0 ){ + continue; /* Ignore TEMP and :memory: databases */ + } + assert( zFile[0]!=0 ); + rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset); + offset += sqlite3Strlen30(zFile)+1; + if( rc!=SQLITE_OK ){ + sqlite3OsCloseFree(pMaster); + sqlite3OsDelete(pVfs, zMaster, 0); + sqlite3DbFree(db, zMaster); + return rc; + } + } + } + + /* Sync the master journal file. If the IOCAP_SEQUENTIAL device + ** flag is set this is not required. + */ + if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL) + && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL)) + ){ + sqlite3OsCloseFree(pMaster); + sqlite3OsDelete(pVfs, zMaster, 0); + sqlite3DbFree(db, zMaster); + return rc; + } + + /* Sync all the db files involved in the transaction. The same call + ** sets the master journal pointer in each individual journal. If + ** an error occurs here, do not delete the master journal file. + ** + ** If the error occurs during the first call to + ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the + ** master journal file will be orphaned. But we cannot delete it, + ** in case the master journal file name was written into the journal + ** file before the failure occurred. + */ + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster); + } + } + sqlite3OsCloseFree(pMaster); + assert( rc!=SQLITE_BUSY ); + if( rc!=SQLITE_OK ){ + sqlite3DbFree(db, zMaster); + return rc; + } + + /* Delete the master journal file. This commits the transaction. After + ** doing this the directory is synced again before any individual + ** transaction files are deleted. + */ + rc = sqlite3OsDelete(pVfs, zMaster, 1); + sqlite3DbFree(db, zMaster); + zMaster = 0; + if( rc ){ + return rc; + } + + /* All files and directories have already been synced, so the following + ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and + ** deleting or truncating journals. If something goes wrong while + ** this is happening we don't really care. The integrity of the + ** transaction is already guaranteed, but some stray 'cold' journals + ** may be lying around. Returning an error code won't help matters. + */ + disable_simulated_io_errors(); + sqlite3BeginBenignMalloc(); + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + sqlite3BtreeCommitPhaseTwo(pBt, 1); + } + } + sqlite3EndBenignMalloc(); + enable_simulated_io_errors(); + + sqlite3VtabCommit(db); + } +#endif + + return rc; +} + +/* +** This routine checks that the sqlite3.nVdbeActive count variable +** matches the number of vdbe's in the list sqlite3.pVdbe that are +** currently active. An assertion fails if the two counts do not match. +** This is an internal self-check only - it is not an essential processing +** step. +** +** This is a no-op if NDEBUG is defined. +*/ +#ifndef NDEBUG +static void checkActiveVdbeCnt(sqlite3 *db){ + Vdbe *p; + int cnt = 0; + int nWrite = 0; + int nRead = 0; + p = db->pVdbe; + while( p ){ + if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){ + cnt++; + if( p->readOnly==0 ) nWrite++; + if( p->bIsReader ) nRead++; + } + p = p->pNext; + } + assert( cnt==db->nVdbeActive ); + assert( nWrite==db->nVdbeWrite ); + assert( nRead==db->nVdbeRead ); +} +#else +#define checkActiveVdbeCnt(x) +#endif + +/* +** If the Vdbe passed as the first argument opened a statement-transaction, +** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or +** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement +** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the +** statement transaction is committed. +** +** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. +** Otherwise SQLITE_OK. +*/ +static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){ + sqlite3 *const db = p->db; + int rc = SQLITE_OK; + int i; + const int iSavepoint = p->iStatement-1; + + assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); + assert( db->nStatement>0 ); + assert( p->iStatement==(db->nStatement+db->nSavepoint) ); + + for(i=0; inDb; i++){ + int rc2 = SQLITE_OK; + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + if( eOp==SAVEPOINT_ROLLBACK ){ + rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint); + } + if( rc2==SQLITE_OK ){ + rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint); + } + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + db->nStatement--; + p->iStatement = 0; + + if( rc==SQLITE_OK ){ + if( eOp==SAVEPOINT_ROLLBACK ){ + rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); + } + if( rc==SQLITE_OK ){ + rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); + } + } + + /* If the statement transaction is being rolled back, also restore the + ** database handles deferred constraint counter to the value it had when + ** the statement transaction was opened. */ + if( eOp==SAVEPOINT_ROLLBACK ){ + db->nDeferredCons = p->nStmtDefCons; + db->nDeferredImmCons = p->nStmtDefImmCons; + } + return rc; +} +SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ + if( p->db->nStatement && p->iStatement ){ + return vdbeCloseStatement(p, eOp); + } + return SQLITE_OK; +} + + +/* +** This function is called when a transaction opened by the database +** handle associated with the VM passed as an argument is about to be +** committed. If there are outstanding deferred foreign key constraint +** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK. +** +** If there are outstanding FK violations and this function returns +** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY +** and write an error message to it. Then return SQLITE_ERROR. +*/ +#ifndef SQLITE_OMIT_FOREIGN_KEY +SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ + sqlite3 *db = p->db; + if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) + || (!deferred && p->nFkConstraint>0) + ){ + p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; + p->errorAction = OE_Abort; + sqlite3VdbeError(p, "FOREIGN KEY constraint failed"); + return SQLITE_ERROR; + } + return SQLITE_OK; +} +#endif + +/* +** This routine is called the when a VDBE tries to halt. If the VDBE +** has made changes and is in autocommit mode, then commit those +** changes. If a rollback is needed, then do the rollback. +** +** This routine is the only way to move the state of a VM from +** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to +** call this on a VM that is in the SQLITE_MAGIC_HALT state. +** +** Return an error code. If the commit could not complete because of +** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it +** means the close did not happen and needs to be repeated. +*/ +SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ + int rc; /* Used to store transient return codes */ + sqlite3 *db = p->db; + + /* This function contains the logic that determines if a statement or + ** transaction will be committed or rolled back as a result of the + ** execution of this virtual machine. + ** + ** If any of the following errors occur: + ** + ** SQLITE_NOMEM + ** SQLITE_IOERR + ** SQLITE_FULL + ** SQLITE_INTERRUPT + ** + ** Then the internal cache might have been left in an inconsistent + ** state. We need to rollback the statement transaction, if there is + ** one, or the complete transaction if there is no statement transaction. + */ + + if( p->magic!=VDBE_MAGIC_RUN ){ + return SQLITE_OK; + } + if( db->mallocFailed ){ + p->rc = SQLITE_NOMEM_BKPT; + } + closeAllCursors(p); + checkActiveVdbeCnt(db); + + /* No commit or rollback needed if the program never started or if the + ** SQL statement does not read or write a database file. */ + if( p->pc>=0 && p->bIsReader ){ + int mrc; /* Primary error code from p->rc */ + int eStatementOp = 0; + int isSpecialError; /* Set to true if a 'special' error */ + + /* Lock all btrees used by the statement */ + sqlite3VdbeEnter(p); + + /* Check for one of the special errors */ + mrc = p->rc & 0xff; + isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR + || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; + if( isSpecialError ){ + /* If the query was read-only and the error code is SQLITE_INTERRUPT, + ** no rollback is necessary. Otherwise, at least a savepoint + ** transaction must be rolled back to restore the database to a + ** consistent state. + ** + ** Even if the statement is read-only, it is important to perform + ** a statement or transaction rollback operation. If the error + ** occurred while writing to the journal, sub-journal or database + ** file as part of an effort to free up cache space (see function + ** pagerStress() in pager.c), the rollback is required to restore + ** the pager to a consistent state. + */ + if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){ + if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){ + eStatementOp = SAVEPOINT_ROLLBACK; + }else{ + /* We are forced to roll back the active transaction. Before doing + ** so, abort any other statements this handle currently has active. + */ + sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); + sqlite3CloseSavepoints(db); + db->autoCommit = 1; + p->nChange = 0; + } + } + } + + /* Check for immediate foreign key violations. */ + if( p->rc==SQLITE_OK ){ + sqlite3VdbeCheckFk(p, 0); + } + + /* If the auto-commit flag is set and this is the only active writer + ** VM, then we do either a commit or rollback of the current transaction. + ** + ** Note: This block also runs if one of the special errors handled + ** above has occurred. + */ + if( !sqlite3VtabInSync(db) + && db->autoCommit + && db->nVdbeWrite==(p->readOnly==0) + ){ + if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ + rc = sqlite3VdbeCheckFk(p, 1); + if( rc!=SQLITE_OK ){ + if( NEVER(p->readOnly) ){ + sqlite3VdbeLeave(p); + return SQLITE_ERROR; + } + rc = SQLITE_CONSTRAINT_FOREIGNKEY; + }else{ + /* The auto-commit flag is true, the vdbe program was successful + ** or hit an 'OR FAIL' constraint and there are no deferred foreign + ** key constraints to hold up the transaction. This means a commit + ** is required. */ + rc = vdbeCommit(db, p); + } + if( rc==SQLITE_BUSY && p->readOnly ){ + sqlite3VdbeLeave(p); + return SQLITE_BUSY; + }else if( rc!=SQLITE_OK ){ + p->rc = rc; + sqlite3RollbackAll(db, SQLITE_OK); + p->nChange = 0; + }else{ + db->nDeferredCons = 0; + db->nDeferredImmCons = 0; + db->flags &= ~SQLITE_DeferFKs; + sqlite3CommitInternalChanges(db); + } + }else{ + sqlite3RollbackAll(db, SQLITE_OK); + p->nChange = 0; + } + db->nStatement = 0; + }else if( eStatementOp==0 ){ + if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ + eStatementOp = SAVEPOINT_RELEASE; + }else if( p->errorAction==OE_Abort ){ + eStatementOp = SAVEPOINT_ROLLBACK; + }else{ + sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); + sqlite3CloseSavepoints(db); + db->autoCommit = 1; + p->nChange = 0; + } + } + + /* If eStatementOp is non-zero, then a statement transaction needs to + ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to + ** do so. If this operation returns an error, and the current statement + ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the + ** current statement error code. + */ + if( eStatementOp ){ + rc = sqlite3VdbeCloseStatement(p, eStatementOp); + if( rc ){ + if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){ + p->rc = rc; + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = 0; + } + sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); + sqlite3CloseSavepoints(db); + db->autoCommit = 1; + p->nChange = 0; + } + } + + /* If this was an INSERT, UPDATE or DELETE and no statement transaction + ** has been rolled back, update the database connection change-counter. + */ + if( p->changeCntOn ){ + if( eStatementOp!=SAVEPOINT_ROLLBACK ){ + sqlite3VdbeSetChanges(db, p->nChange); + }else{ + sqlite3VdbeSetChanges(db, 0); + } + p->nChange = 0; + } + + /* Release the locks */ + sqlite3VdbeLeave(p); + } + + /* We have successfully halted and closed the VM. Record this fact. */ + if( p->pc>=0 ){ + db->nVdbeActive--; + if( !p->readOnly ) db->nVdbeWrite--; + if( p->bIsReader ) db->nVdbeRead--; + assert( db->nVdbeActive>=db->nVdbeRead ); + assert( db->nVdbeRead>=db->nVdbeWrite ); + assert( db->nVdbeWrite>=0 ); + } + p->magic = VDBE_MAGIC_HALT; + checkActiveVdbeCnt(db); + if( db->mallocFailed ){ + p->rc = SQLITE_NOMEM_BKPT; + } + + /* If the auto-commit flag is set to true, then any locks that were held + ** by connection db have now been released. Call sqlite3ConnectionUnlocked() + ** to invoke any required unlock-notify callbacks. + */ + if( db->autoCommit ){ + sqlite3ConnectionUnlocked(db); + } + + assert( db->nVdbeActive>0 || db->autoCommit==0 || db->nStatement==0 ); + return (p->rc==SQLITE_BUSY ? SQLITE_BUSY : SQLITE_OK); +} + + +/* +** Each VDBE holds the result of the most recent sqlite3_step() call +** in p->rc. This routine sets that result back to SQLITE_OK. +*/ +SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){ + p->rc = SQLITE_OK; +} + +/* +** Copy the error code and error message belonging to the VDBE passed +** as the first argument to its database handle (so that they will be +** returned by calls to sqlite3_errcode() and sqlite3_errmsg()). +** +** This function does not clear the VDBE error code or message, just +** copies them to the database handle. +*/ +SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){ + sqlite3 *db = p->db; + int rc = p->rc; + if( p->zErrMsg ){ + db->bBenignMalloc++; + sqlite3BeginBenignMalloc(); + if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db); + sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); + sqlite3EndBenignMalloc(); + db->bBenignMalloc--; + db->errCode = rc; + }else{ + sqlite3Error(db, rc); + } + return rc; +} + +#ifdef SQLITE_ENABLE_SQLLOG +/* +** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run, +** invoke it. +*/ +static void vdbeInvokeSqllog(Vdbe *v){ + if( sqlite3GlobalConfig.xSqllog && v->rc==SQLITE_OK && v->zSql && v->pc>=0 ){ + char *zExpanded = sqlite3VdbeExpandSql(v, v->zSql); + assert( v->db->init.busy==0 ); + if( zExpanded ){ + sqlite3GlobalConfig.xSqllog( + sqlite3GlobalConfig.pSqllogArg, v->db, zExpanded, 1 + ); + sqlite3DbFree(v->db, zExpanded); + } + } +} +#else +# define vdbeInvokeSqllog(x) +#endif + +/* +** Clean up a VDBE after execution but do not delete the VDBE just yet. +** Write any error messages into *pzErrMsg. Return the result code. +** +** After this routine is run, the VDBE should be ready to be executed +** again. +** +** To look at it another way, this routine resets the state of the +** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to +** VDBE_MAGIC_INIT. +*/ +SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ + sqlite3 *db; + db = p->db; + + /* If the VM did not run to completion or if it encountered an + ** error, then it might not have been halted properly. So halt + ** it now. + */ + sqlite3VdbeHalt(p); + + /* If the VDBE has be run even partially, then transfer the error code + ** and error message from the VDBE into the main database structure. But + ** if the VDBE has just been set to run but has not actually executed any + ** instructions yet, leave the main database error information unchanged. + */ + 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 + ** to sqlite3_step(). For consistency (since sqlite3_step() was + ** called), set the database error in this case as well. + */ + sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = 0; + } + + /* Reclaim all memory used by the VDBE + */ + Cleanup(p); + + /* Save profiling information from this VDBE run. + */ +#ifdef VDBE_PROFILE + { + FILE *out = fopen("vdbe_profile.out", "a"); + if( out ){ + int i; + fprintf(out, "---- "); + for(i=0; inOp; i++){ + fprintf(out, "%02x", p->aOp[i].opcode); + } + fprintf(out, "\n"); + if( p->zSql ){ + char c, pc = 0; + fprintf(out, "-- "); + for(i=0; (c = p->zSql[i])!=0; i++){ + if( pc=='\n' ) fprintf(out, "-- "); + putc(c, out); + pc = c; + } + if( pc!='\n' ) fprintf(out, "\n"); + } + for(i=0; inOp; i++){ + char zHdr[100]; + sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ", + p->aOp[i].cnt, + p->aOp[i].cycles, + p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 + ); + fprintf(out, "%s", zHdr); + sqlite3VdbePrintOp(out, i, &p->aOp[i]); + } + fclose(out); + } + } +#endif + p->magic = VDBE_MAGIC_RESET; + return p->rc & db->errMask; +} + +/* +** Clean up and delete a VDBE after execution. Return an integer which is +** the result code. Write any error message text into *pzErrMsg. +*/ +SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){ + int rc = SQLITE_OK; + if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){ + rc = sqlite3VdbeReset(p); + assert( (rc & p->db->errMask)==rc ); + } + sqlite3VdbeDelete(p); + return rc; +} + +/* +** If parameter iOp is less than zero, then invoke the destructor for +** all auxiliary data pointers currently cached by the VM passed as +** the first argument. +** +** Or, if iOp is greater than or equal to zero, then the destructor is +** only invoked for those auxiliary data pointers created by the user +** function invoked by the OP_Function opcode at instruction iOp of +** VM pVdbe, and only then if: +** +** * the associated function parameter is the 32nd or later (counting +** from left to right), or +** +** * the corresponding bit in argument mask is clear (where the first +** function parameter corresponds to bit 0 etc.). +*/ +SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){ + while( *pp ){ + AuxData *pAux = *pp; + if( (iOp<0) + || (pAux->iAuxOp==iOp + && pAux->iAuxArg>=0 + && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg)))) + ){ + testcase( pAux->iAuxArg==31 ); + if( pAux->xDeleteAux ){ + pAux->xDeleteAux(pAux->pAux); + } + *pp = pAux->pNextAux; + sqlite3DbFree(db, pAux); + }else{ + pp= &pAux->pNextAux; + } + } +} + +/* +** Free all memory associated with the Vdbe passed as the second argument, +** except for object itself, which is preserved. +** +** The difference between this function and sqlite3VdbeDelete() is that +** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with +** the database connection and frees the object itself. +*/ +SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ + SubProgram *pSub, *pNext; + assert( p->db==0 || p->db==db ); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + for(pSub=p->pProgram; pSub; pSub=pNext){ + pNext = pSub->pNext; + vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); + sqlite3DbFree(db, pSub); + } + if( p->magic!=VDBE_MAGIC_INIT ){ + releaseMemArray(p->aVar, p->nVar); + sqlite3DbFree(db, p->pVList); + sqlite3DbFree(db, p->pFree); + } + vdbeFreeOpArray(db, p->aOp, p->nOp); + sqlite3DbFree(db, p->aColName); + sqlite3DbFree(db, p->zSql); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + { + int i; + for(i=0; inScan; i++){ + sqlite3DbFree(db, p->aScan[i].zName); + } + sqlite3DbFree(db, p->aScan); + } +#endif +} + +/* +** Delete an entire VDBE. +*/ +SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ + sqlite3 *db; + + if( NEVER(p==0) ) return; + db = p->db; + assert( sqlite3_mutex_held(db->mutex) ); + sqlite3VdbeClearObject(db, p); + if( p->pPrev ){ + p->pPrev->pNext = p->pNext; + }else{ + assert( db->pVdbe==p ); + db->pVdbe = p->pNext; + } + if( p->pNext ){ + p->pNext->pPrev = p->pPrev; + } + p->magic = VDBE_MAGIC_DEAD; + p->db = 0; + sqlite3DbFreeNN(db, p); +} + +/* +** The cursor "p" has a pending seek operation that has not yet been +** carried out. Seek the cursor now. If an error occurs, return +** the appropriate error code. +*/ +static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){ + int res, rc; +#ifdef SQLITE_TEST + extern int sqlite3_search_count; +#endif + assert( p->deferredMoveto ); + assert( p->isTable ); + assert( p->eCurType==CURTYPE_BTREE ); + rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res); + if( rc ) return rc; + if( res!=0 ) return SQLITE_CORRUPT_BKPT; +#ifdef SQLITE_TEST + sqlite3_search_count++; +#endif + p->deferredMoveto = 0; + p->cacheStatus = CACHE_STALE; + return SQLITE_OK; +} + +/* +** Something has moved cursor "p" out of place. Maybe the row it was +** pointed to was deleted out from under it. Or maybe the btree was +** rebalanced. Whatever the cause, try to restore "p" to the place it +** is supposed to be pointing. If the row was deleted out from under the +** cursor, set the cursor to point to a NULL row. +*/ +static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){ + int isDifferentRow, rc; + assert( p->eCurType==CURTYPE_BTREE ); + assert( p->uc.pCursor!=0 ); + assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ); + rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow); + p->cacheStatus = CACHE_STALE; + if( isDifferentRow ) p->nullRow = 1; + return rc; +} + +/* +** Check to ensure that the cursor is valid. Restore the cursor +** if need be. Return any I/O error from the restore operation. +*/ +SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){ + assert( p->eCurType==CURTYPE_BTREE ); + if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ + return handleMovedCursor(p); + } + return SQLITE_OK; +} + +/* +** Make sure the cursor p is ready to read or write the row to which it +** was last positioned. Return an error code if an OOM fault or I/O error +** prevents us from positioning the cursor to its correct position. +** +** If a MoveTo operation is pending on the given cursor, then do that +** MoveTo now. If no move is pending, check to see if the row has been +** deleted out from under the cursor and if it has, mark the row as +** a NULL row. +** +** If the cursor is already pointing to the correct row and that row has +** not been deleted out from under the cursor, then this routine is a no-op. +*/ +SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ + VdbeCursor *p = *pp; + 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); + } + } + return SQLITE_OK; +} + +/* +** The following functions: +** +** sqlite3VdbeSerialType() +** sqlite3VdbeSerialTypeLen() +** sqlite3VdbeSerialLen() +** sqlite3VdbeSerialPut() +** sqlite3VdbeSerialGet() +** +** encapsulate the code that serializes values for storage in SQLite +** data and index records. Each serialized value consists of a +** 'serial-type' and a blob of data. The serial type is an 8-byte unsigned +** integer, stored as a varint. +** +** In an SQLite index record, the serial type is stored directly before +** the blob of data that it corresponds to. In a table record, all serial +** types are stored at the start of the record, and the blobs of data at +** the end. Hence these functions allow the caller to handle the +** serial-type and data blob separately. +** +** The following table describes the various storage classes for data: +** +** serial type bytes of data type +** -------------- --------------- --------------- +** 0 0 NULL +** 1 1 signed integer +** 2 2 signed integer +** 3 3 signed integer +** 4 4 signed integer +** 5 6 signed integer +** 6 8 signed integer +** 7 8 IEEE float +** 8 0 Integer constant 0 +** 9 0 Integer constant 1 +** 10,11 reserved for expansion +** N>=12 and even (N-12)/2 BLOB +** N>=13 and odd (N-13)/2 text +** +** The 8 and 9 types were added in 3.3.0, file format 4. Prior versions +** of SQLite will not understand those serial types. +*/ + +/* +** Return the serial-type for the value stored in pMem. +*/ +SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ + int flags = pMem->flags; + u32 n; + + assert( pLen!=0 ); + if( flags&MEM_Null ){ + *pLen = 0; + return 0; + } + if( flags&MEM_Int ){ + /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ +# define MAX_6BYTE ((((i64)0x00008000)<<32)-1) + i64 i = pMem->u.i; + u64 u; + if( i<0 ){ + u = ~i; + }else{ + u = i; + } + if( u<=127 ){ + if( (i&1)==i && file_format>=4 ){ + *pLen = 0; + return 8+(u32)u; + }else{ + *pLen = 1; + return 1; + } + } + if( u<=32767 ){ *pLen = 2; return 2; } + if( u<=8388607 ){ *pLen = 3; return 3; } + if( u<=2147483647 ){ *pLen = 4; return 4; } + if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } + *pLen = 8; + return 6; + } + if( flags&MEM_Real ){ + *pLen = 8; + return 7; + } + assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); + assert( pMem->n>=0 ); + n = (u32)pMem->n; + if( flags & MEM_Zero ){ + n += pMem->u.nZero; + } + *pLen = n; + return ((n*2) + 12 + ((flags&MEM_Str)!=0)); +} + +/* +** The sizes for serial types less than 128 +*/ +static const u8 sqlite3SmallTypeSizes[] = { + /* 0 1 2 3 4 5 6 7 8 9 */ +/* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, +/* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, +/* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, +/* 30 */ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, +/* 40 */ 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, +/* 50 */ 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, +/* 60 */ 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, +/* 70 */ 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, +/* 80 */ 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, +/* 90 */ 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, +/* 100 */ 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, +/* 110 */ 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, +/* 120 */ 54, 54, 55, 55, 56, 56, 57, 57 +}; + +/* +** Return the length of the data corresponding to the supplied serial-type. +*/ +SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){ + if( serial_type>=128 ){ + return (serial_type-12)/2; + }else{ + assert( serial_type<12 + || sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 ); + return sqlite3SmallTypeSizes[serial_type]; + } +} +SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){ + assert( serial_type<128 ); + return sqlite3SmallTypeSizes[serial_type]; +} + +/* +** If we are on an architecture with mixed-endian floating +** points (ex: ARM7) then swap the lower 4 bytes with the +** upper 4 bytes. Return the result. +** +** For most architectures, this is a no-op. +** +** (later): It is reported to me that the mixed-endian problem +** on ARM7 is an issue with GCC, not with the ARM7 chip. It seems +** that early versions of GCC stored the two words of a 64-bit +** float in the wrong order. And that error has been propagated +** ever since. The blame is not necessarily with GCC, though. +** GCC might have just copying the problem from a prior compiler. +** I am also told that newer versions of GCC that follow a different +** ABI get the byte order right. +** +** Developers using SQLite on an ARM7 should compile and run their +** application using -DSQLITE_DEBUG=1 at least once. With DEBUG +** enabled, some asserts below will ensure that the byte order of +** floating point values is correct. +** +** (2007-08-30) Frank van Vugt has studied this problem closely +** and has send his findings to the SQLite developers. Frank +** writes that some Linux kernels offer floating point hardware +** emulation that uses only 32-bit mantissas instead of a full +** 48-bits as required by the IEEE standard. (This is the +** CONFIG_FPE_FASTFPE option.) On such systems, floating point +** byte swapping becomes very complicated. To avoid problems, +** the necessary byte swapping is carried out using a 64-bit integer +** rather than a 64-bit float. Frank assures us that the code here +** works for him. We, the developers, have no way to independently +** verify this, but Frank seems to know what he is talking about +** so we trust him. +*/ +#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT +static u64 floatSwap(u64 in){ + union { + u64 r; + u32 i[2]; + } u; + u32 t; + + u.r = in; + t = u.i[0]; + u.i[0] = u.i[1]; + u.i[1] = t; + return u.r; +} +# define swapMixedEndianFloat(X) X = floatSwap(X) +#else +# define swapMixedEndianFloat(X) +#endif + +/* +** Write the serialized data blob for the value stored in pMem into +** buf. It is assumed that the caller has allocated sufficient space. +** Return the number of bytes written. +** +** nBuf is the amount of space left in buf[]. The caller is responsible +** for allocating enough space to buf[] to hold the entire field, exclusive +** of the pMem->u.nZero bytes for a MEM_Zero value. +** +** Return the number of bytes actually written into buf[]. The number +** of bytes in the zero-filled tail is included in the return value only +** if those bytes were zeroed in buf[]. +*/ +SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ + u32 len; + + /* Integer and Real */ + if( serial_type<=7 && serial_type>0 ){ + u64 v; + u32 i; + if( serial_type==7 ){ + assert( sizeof(v)==sizeof(pMem->u.r) ); + memcpy(&v, &pMem->u.r, sizeof(v)); + swapMixedEndianFloat(v); + }else{ + v = pMem->u.i; + } + len = i = sqlite3SmallTypeSizes[serial_type]; + assert( i>0 ); + do{ + buf[--i] = (u8)(v&0xFF); + v >>= 8; + }while( i ); + return len; + } + + /* String or blob */ + if( serial_type>=12 ){ + assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0) + == (int)sqlite3VdbeSerialTypeLen(serial_type) ); + len = pMem->n; + if( len>0 ) memcpy(buf, pMem->z, len); + return len; + } + + /* NULL or constants 0 or 1 */ + return 0; +} + +/* Input "x" is a sequence of unsigned characters that represent a +** big-endian integer. Return the equivalent native integer +*/ +#define ONE_BYTE_INT(x) ((i8)(x)[0]) +#define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) +#define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) +#define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) +#define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) + +/* +** Deserialize the data blob pointed to by buf as serial type serial_type +** and store the result in pMem. Return the number of bytes read. +** +** This function is implemented as two separate routines for performance. +** The few cases that require local variables are broken out into a separate +** routine so that in most cases the overhead of moving the stack pointer +** is avoided. +*/ +static u32 SQLITE_NOINLINE serialGet( + const unsigned char *buf, /* Buffer to deserialize from */ + u32 serial_type, /* Serial type to deserialize */ + Mem *pMem /* Memory cell to write value into */ +){ + u64 x = FOUR_BYTE_UINT(buf); + u32 y = FOUR_BYTE_UINT(buf+4); + x = (x<<32) + y; + if( serial_type==6 ){ + /* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit + ** twos-complement integer. */ + pMem->u.i = *(i64*)&x; + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + }else{ + /* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit + ** floating point number. */ +#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT) + /* Verify that integers and floating point values use the same + ** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is + ** defined that 64-bit floating point values really are mixed + ** endian. + */ + static const u64 t1 = ((u64)0x3ff00000)<<32; + static const double r1 = 1.0; + u64 t2 = t1; + swapMixedEndianFloat(t2); + assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 ); +#endif + assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); + swapMixedEndianFloat(x); + memcpy(&pMem->u.r, &x, sizeof(x)); + pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real; + } + return 8; +} +SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( + const unsigned char *buf, /* Buffer to deserialize from */ + u32 serial_type, /* Serial type to deserialize */ + Mem *pMem /* Memory cell to write value into */ +){ + switch( serial_type ){ + case 10: /* Reserved for future use */ + case 11: /* Reserved for future use */ + case 0: { /* Null */ + /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */ + pMem->flags = MEM_Null; + break; + } + case 1: { + /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement + ** integer. */ + pMem->u.i = ONE_BYTE_INT(buf); + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + return 1; + } + case 2: { /* 2-byte signed integer */ + /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit + ** twos-complement integer. */ + pMem->u.i = TWO_BYTE_INT(buf); + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + return 2; + } + case 3: { /* 3-byte signed integer */ + /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit + ** twos-complement integer. */ + pMem->u.i = THREE_BYTE_INT(buf); + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + return 3; + } + case 4: { /* 4-byte signed integer */ + /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit + ** twos-complement integer. */ + pMem->u.i = FOUR_BYTE_INT(buf); +#ifdef __HP_cc + /* Work around a sign-extension bug in the HP compiler for HP/UX */ + if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL; +#endif + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + return 4; + } + case 5: { /* 6-byte signed integer */ + /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit + ** twos-complement integer. */ + pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf); + pMem->flags = MEM_Int; + testcase( pMem->u.i<0 ); + return 6; + } + case 6: /* 8-byte signed integer */ + case 7: { /* IEEE floating point */ + /* These use local variables, so do them in a separate routine + ** to avoid having to move the frame pointer in the common case */ + return serialGet(buf,serial_type,pMem); + } + case 8: /* Integer 0 */ + case 9: { /* Integer 1 */ + /* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */ + /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */ + pMem->u.i = serial_type-8; + pMem->flags = MEM_Int; + return 0; + } + default: { + /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in + ** length. + ** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and + ** (N-13)/2 bytes in length. */ + static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem }; + pMem->z = (char *)buf; + pMem->n = (serial_type-12)/2; + pMem->flags = aFlag[serial_type&1]; + return pMem->n; + } + } + return 0; +} +/* +** This routine is used to allocate sufficient space for an UnpackedRecord +** structure large enough to be used with sqlite3VdbeRecordUnpack() if +** the first argument is a pointer to KeyInfo structure pKeyInfo. +** +** The space is either allocated using sqlite3DbMallocRaw() or from within +** the unaligned buffer passed via the second and third arguments (presumably +** stack space). If the former, then *ppFree is set to a pointer that should +** be eventually freed by the caller using sqlite3DbFree(). Or, if the +** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL +** before returning. +** +** If an OOM error occurs, NULL is returned. +*/ +SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( + KeyInfo *pKeyInfo /* Description of the record */ +){ + UnpackedRecord *p; /* Unpacked record to return */ + int nByte; /* Number of bytes required for *p */ + nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+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; + return p; +} + +/* +** Given the nKey-byte encoding of a record in pKey[], populate the +** UnpackedRecord structure indicated by the fourth argument with the +** contents of the decoded record. +*/ +SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( + KeyInfo *pKeyInfo, /* Information about the record format */ + int nKey, /* Size of the binary record */ + const void *pKey, /* The binary record */ + UnpackedRecord *p /* Populate this structure before returning. */ +){ + const unsigned char *aKey = (const unsigned char *)pKey; + int d; + u32 idx; /* Offset in aKey[] to read from */ + u16 u; /* Unsigned loop counter */ + u32 szHdr; + Mem *pMem = p->aMem; + + p->default_rc = 0; + assert( EIGHT_BYTE_ALIGNMENT(pMem) ); + idx = getVarint32(aKey, szHdr); + d = szHdr; + u = 0; + while( idxenc = pKeyInfo->enc; + pMem->db = pKeyInfo->db; + /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */ + pMem->szMalloc = 0; + pMem->z = 0; + d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); + pMem++; + if( (++u)>=p->nField ) break; + } + assert( u<=pKeyInfo->nField + 1 ); + p->nField = u; +} + +#ifdef SQLITE_DEBUG +/* +** This function compares two index or table record keys in the same way +** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(), +** this function deserializes and compares values using the +** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used +** in assert() statements to ensure that the optimized code in +** sqlite3VdbeRecordCompare() returns results with these two primitives. +** +** Return true if the result of comparison is equivalent to desiredResult. +** Return false if there is a disagreement. +*/ +static int vdbeRecordCompareDebug( + int nKey1, const void *pKey1, /* Left key */ + const UnpackedRecord *pPKey2, /* Right key */ + int desiredResult /* Correct answer */ +){ + u32 d1; /* Offset into aKey[] of next data element */ + u32 idx1; /* Offset into aKey[] of next header element */ + u32 szHdr1; /* Number of bytes in header */ + int i = 0; + int rc = 0; + const unsigned char *aKey1 = (const unsigned char *)pKey1; + KeyInfo *pKeyInfo; + Mem mem1; + + pKeyInfo = pPKey2->pKeyInfo; + if( pKeyInfo->db==0 ) return 1; + mem1.enc = pKeyInfo->enc; + mem1.db = pKeyInfo->db; + /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ + VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ + + /* Compilers may complain that mem1.u.i is potentially uninitialized. + ** We could initialize it, as shown here, to silence those complaints. + ** But in fact, mem1.u.i will never actually be used uninitialized, and doing + ** the unnecessary initialization has a measurable negative performance + ** impact, since this routine is a very high runner. And so, we choose + ** to ignore the compiler warnings and leave this variable uninitialized. + */ + /* mem1.u.i = 0; // not needed, here to silence compiler warning */ + + idx1 = getVarint32(aKey1, szHdr1); + if( szHdr1>98307 ) return SQLITE_CORRUPT; + d1 = szHdr1; + assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); + assert( pKeyInfo->aSortOrder!=0 ); + assert( pKeyInfo->nField>0 ); + assert( idx1<=szHdr1 || CORRUPT_DB ); + do{ + u32 serial_type1; + + /* Read the serial types for the next element in each key. */ + idx1 += getVarint32( aKey1+idx1, serial_type1 ); + + /* Verify that there is enough key space remaining to avoid + ** a buffer overread. The "d1+serial_type1+2" subexpression will + ** always be greater than or equal to the amount of required key space. + ** Use that approximation to avoid the more expensive call to + ** sqlite3VdbeSerialTypeLen() in the common case. + */ + if( d1+serial_type1+2>(u32)nKey1 + && d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 + ){ + break; + } + + /* Extract the values to be compared. + */ + d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); + + /* Do the comparison + */ + rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); + if( rc!=0 ){ + assert( mem1.szMalloc==0 ); /* See comment below */ + if( pKeyInfo->aSortOrder[i] ){ + rc = -rc; /* Invert the result for DESC sort order. */ + } + goto debugCompareEnd; + } + i++; + }while( idx1nField ); + + /* No memory allocation is ever used on mem1. Prove this using + ** the following assert(). If the assert() fails, it indicates a + ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). + */ + assert( mem1.szMalloc==0 ); + + /* rc==0 here means that one of the keys ran out of fields and + ** all the fields up to that point were equal. Return the default_rc + ** value. */ + rc = pPKey2->default_rc; + +debugCompareEnd: + if( desiredResult==0 && rc==0 ) return 1; + if( desiredResult<0 && rc<0 ) return 1; + if( desiredResult>0 && rc>0 ) return 1; + if( CORRUPT_DB ) return 1; + if( pKeyInfo->db->mallocFailed ) return 1; + return 0; +} +#endif + +#ifdef SQLITE_DEBUG +/* +** 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. +** +** 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 +** incorrectly. +*/ +static void vdbeAssertFieldCountWithinLimits( + int nKey, const void *pKey, /* The record to verify */ + const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */ +){ + int nField = 0; + u32 szHdr; + u32 idx; + u32 notUsed; + const unsigned char *aKey = (const unsigned char*)pKey; + + if( CORRUPT_DB ) return; + idx = getVarint32(aKey, szHdr); + assert( nKey>=0 ); + assert( szHdr<=(u32)nKey ); + while( idxnField+pKeyInfo->nXField ); +} +#else +# define vdbeAssertFieldCountWithinLimits(A,B,C) +#endif + +/* +** Both *pMem1 and *pMem2 contain string values. Compare the two values +** using the collation sequence pColl. As usual, return a negative , zero +** or positive value if *pMem1 is less than, equal to or greater than +** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);". +*/ +static int vdbeCompareMemString( + const Mem *pMem1, + const Mem *pMem2, + const CollSeq *pColl, + u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */ +){ + if( pMem1->enc==pColl->enc ){ + /* The strings are already in the correct encoding. Call the + ** comparison function directly */ + return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); + }else{ + int rc; + const void *v1, *v2; + int n1, n2; + Mem c1; + Mem c2; + sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); + sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null); + sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); + sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); + v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); + n1 = v1==0 ? 0 : c1.n; + v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); + n2 = v2==0 ? 0 : c2.n; + rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); + if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT; + sqlite3VdbeMemRelease(&c1); + sqlite3VdbeMemRelease(&c2); + return rc; + } +} + +/* +** The input pBlob is guaranteed to be a Blob that is not marked +** with MEM_Zero. Return true if it could be a zero-blob. +*/ +static int isAllZero(const char *z, int n){ + int i; + for(i=0; in; + int n2 = pB2->n; + + /* It is possible to have a Blob value that has some non-zero content + ** followed by zero content. But that only comes up for Blobs formed + ** by the OP_MakeRecord opcode, and such Blobs never get passed into + ** sqlite3MemCompare(). */ + assert( (pB1->flags & MEM_Zero)==0 || n1==0 ); + assert( (pB2->flags & MEM_Zero)==0 || n2==0 ); + + if( (pB1->flags|pB2->flags) & MEM_Zero ){ + if( pB1->flags & pB2->flags & MEM_Zero ){ + return pB1->u.nZero - pB2->u.nZero; + }else if( pB1->flags & MEM_Zero ){ + if( !isAllZero(pB2->z, pB2->n) ) return -1; + return pB1->u.nZero - n2; + }else{ + if( !isAllZero(pB1->z, pB1->n) ) return +1; + return n1 - pB2->u.nZero; + } + } + c = memcmp(pB1->z, pB2->z, n1>n2 ? n2 : n1); + if( c ) return c; + return n1 - n2; +} + +/* +** Do a comparison between a 64-bit signed integer and a 64-bit floating-point +** number. Return negative, zero, or positive if the first (i64) is less than, +** equal to, or greater than the second (double). +*/ +static int sqlite3IntFloatCompare(i64 i, double r){ + if( sizeof(LONGDOUBLE_TYPE)>8 ){ + LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; + if( xr ) return +1; + return 0; + }else{ + i64 y; + double s; + if( r<-9223372036854775808.0 ) return +1; + if( r>9223372036854775807.0 ) return -1; + y = (i64)r; + if( iy ){ + if( y==SMALLEST_INT64 && r>0.0 ) return -1; + return +1; + } + s = (double)i; + if( sr ) return +1; + return 0; + } +} + +/* +** Compare the values contained by the two memory cells, returning +** negative, zero or positive if pMem1 is less than, equal to, or greater +** than pMem2. Sorting order is NULL's first, followed by numbers (integers +** and reals) sorted numerically, followed by text ordered by the collating +** sequence pColl and finally blob's ordered by memcmp(). +** +** Two NULL values are considered equal by this function. +*/ +SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ + int f1, f2; + int combined_flags; + + f1 = pMem1->flags; + f2 = pMem2->flags; + combined_flags = f1|f2; + assert( (combined_flags & MEM_RowSet)==0 ); + + /* If one value is NULL, it is less than the other. If both values + ** are NULL, return 0. + */ + if( combined_flags&MEM_Null ){ + return (f2&MEM_Null) - (f1&MEM_Null); + } + + /* At least one of the two values is a number + */ + if( combined_flags&(MEM_Int|MEM_Real) ){ + if( (f1 & f2 & MEM_Int)!=0 ){ + if( pMem1->u.i < pMem2->u.i ) return -1; + if( pMem1->u.i > pMem2->u.i ) return +1; + return 0; + } + if( (f1 & f2 & MEM_Real)!=0 ){ + if( pMem1->u.r < pMem2->u.r ) return -1; + if( pMem1->u.r > pMem2->u.r ) return +1; + return 0; + } + if( (f1&MEM_Int)!=0 ){ + if( (f2&MEM_Real)!=0 ){ + return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); + }else{ + return -1; + } + } + if( (f1&MEM_Real)!=0 ){ + if( (f2&MEM_Int)!=0 ){ + return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); + }else{ + return -1; + } + } + return +1; + } + + /* If one value is a string and the other is a blob, the string is less. + ** If both are strings, compare using the collating functions. + */ + if( combined_flags&MEM_Str ){ + if( (f1 & MEM_Str)==0 ){ + return 1; + } + if( (f2 & MEM_Str)==0 ){ + return -1; + } + + assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed ); + assert( pMem1->enc==SQLITE_UTF8 || + pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); + + /* The collation sequence must be defined at this point, even if + ** the user deletes the collation sequence after the vdbe program is + ** compiled (this was not always the case). + */ + assert( !pColl || pColl->xCmp ); + + if( pColl ){ + return vdbeCompareMemString(pMem1, pMem2, pColl, 0); + } + /* If a NULL pointer was passed as the collate function, fall through + ** to the blob case and use memcmp(). */ + } + + /* Both values must be blobs. Compare using memcmp(). */ + return sqlite3BlobCompare(pMem1, pMem2); +} + + +/* +** The first argument passed to this function is a serial-type that +** corresponds to an integer - all values between 1 and 9 inclusive +** except 7. The second points to a buffer containing an integer value +** serialized according to serial_type. This function deserializes +** and returns the value. +*/ +static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ + u32 y; + assert( CORRUPT_DB || (serial_type>=1 && serial_type<=9 && serial_type!=7) ); + switch( serial_type ){ + case 0: + case 1: + testcase( aKey[0]&0x80 ); + return ONE_BYTE_INT(aKey); + case 2: + testcase( aKey[0]&0x80 ); + return TWO_BYTE_INT(aKey); + case 3: + testcase( aKey[0]&0x80 ); + return THREE_BYTE_INT(aKey); + case 4: { + testcase( aKey[0]&0x80 ); + y = FOUR_BYTE_UINT(aKey); + return (i64)*(int*)&y; + } + case 5: { + testcase( aKey[0]&0x80 ); + return FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey); + } + case 6: { + u64 x = FOUR_BYTE_UINT(aKey); + testcase( aKey[0]&0x80 ); + x = (x<<32) | FOUR_BYTE_UINT(aKey+4); + return (i64)*(i64*)&x; + } + } + + return (serial_type - 8); +} + +/* +** This function compares the two table rows or index records +** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero +** or positive integer if key1 is less than, equal to or +** greater than key2. The {nKey1, pKey1} key must be a blob +** created by the OP_MakeRecord opcode of the VDBE. The pPKey2 +** key must be a parsed key such as obtained from +** sqlite3VdbeParseRecord. +** +** If argument bSkip is non-zero, it is assumed that the caller has already +** determined that the first fields of the keys are equal. +** +** Key1 and Key2 do not have to contain the same number of fields. If all +** fields that appear in both keys are equal, then pPKey2->default_rc is +** returned. +** +** If database corruption is discovered, set pPKey2->errCode to +** SQLITE_CORRUPT and return 0. If an OOM error is encountered, +** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the +** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db). +*/ +SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2, /* Right key */ + int bSkip /* If true, skip the first field */ +){ + u32 d1; /* Offset into aKey[] of next data element */ + int i; /* Index of next field to compare */ + u32 szHdr1; /* Size of record header in bytes */ + u32 idx1; /* Offset of first type in header */ + int rc = 0; /* Return value */ + Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */ + KeyInfo *pKeyInfo = pPKey2->pKeyInfo; + const unsigned char *aKey1 = (const unsigned char *)pKey1; + Mem mem1; + + /* If bSkip is true, then the caller has already determined that the first + ** two elements in the keys are equal. Fix the various stack variables so + ** that this routine begins comparing at the second field. */ + if( bSkip ){ + u32 s1; + idx1 = 1 + getVarint32(&aKey1[1], s1); + szHdr1 = aKey1[0]; + d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1); + i = 1; + pRhs++; + }else{ + idx1 = getVarint32(aKey1, szHdr1); + d1 = szHdr1; + if( d1>(unsigned)nKey1 ){ + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } + i = 0; + } + + VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ + assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField + || CORRUPT_DB ); + assert( pPKey2->pKeyInfo->aSortOrder!=0 ); + assert( pPKey2->pKeyInfo->nField>0 ); + assert( idx1<=szHdr1 || CORRUPT_DB ); + do{ + u32 serial_type; + + /* RHS is an integer */ + if( pRhs->flags & MEM_Int ){ + serial_type = aKey1[idx1]; + testcase( serial_type==12 ); + if( serial_type>=10 ){ + rc = +1; + }else if( serial_type==0 ){ + rc = -1; + }else if( serial_type==7 ){ + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); + rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r); + }else{ + i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); + i64 rhs = pRhs->u.i; + if( lhsrhs ){ + rc = +1; + } + } + } + + /* RHS is real */ + else if( pRhs->flags & MEM_Real ){ + serial_type = aKey1[idx1]; + if( serial_type>=10 ){ + /* Serial types 12 or greater are strings and blobs (greater than + ** numbers). Types 10 and 11 are currently "reserved for future + ** use", so it doesn't really matter what the results of comparing + ** them to numberic values are. */ + rc = +1; + }else if( serial_type==0 ){ + rc = -1; + }else{ + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); + if( serial_type==7 ){ + if( mem1.u.ru.r ){ + rc = -1; + }else if( mem1.u.r>pRhs->u.r ){ + rc = +1; + } + }else{ + rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); + } + } + } + + /* RHS is a string */ + else if( pRhs->flags & MEM_Str ){ + getVarint32(&aKey1[idx1], serial_type); + testcase( serial_type==12 ); + if( serial_type<12 ){ + rc = -1; + }else if( !(serial_type & 0x01) ){ + rc = +1; + }else{ + mem1.n = (serial_type - 12) / 2; + testcase( (d1+mem1.n)==(unsigned)nKey1 ); + testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); + if( (d1+mem1.n) > (unsigned)nKey1 ){ + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + }else if( pKeyInfo->aColl[i] ){ + mem1.enc = pKeyInfo->enc; + mem1.db = pKeyInfo->db; + mem1.flags = MEM_Str; + mem1.z = (char*)&aKey1[d1]; + rc = vdbeCompareMemString( + &mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode + ); + }else{ + int nCmp = MIN(mem1.n, pRhs->n); + rc = memcmp(&aKey1[d1], pRhs->z, nCmp); + if( rc==0 ) rc = mem1.n - pRhs->n; + } + } + } + + /* RHS is a blob */ + else if( pRhs->flags & MEM_Blob ){ + assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); + getVarint32(&aKey1[idx1], serial_type); + testcase( serial_type==12 ); + if( serial_type<12 || (serial_type & 0x01) ){ + rc = -1; + }else{ + int nStr = (serial_type - 12) / 2; + testcase( (d1+nStr)==(unsigned)nKey1 ); + testcase( (d1+nStr+1)==(unsigned)nKey1 ); + if( (d1+nStr) > (unsigned)nKey1 ){ + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + }else if( pRhs->flags & MEM_Zero ){ + if( !isAllZero((const char*)&aKey1[d1],nStr) ){ + rc = 1; + }else{ + rc = nStr - pRhs->u.nZero; + } + }else{ + int nCmp = MIN(nStr, pRhs->n); + rc = memcmp(&aKey1[d1], pRhs->z, nCmp); + if( rc==0 ) rc = nStr - pRhs->n; + } + } + } + + /* RHS is null */ + else{ + serial_type = aKey1[idx1]; + rc = (serial_type!=0); + } + + if( rc!=0 ){ + if( pKeyInfo->aSortOrder[i] ){ + rc = -rc; + } + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); + assert( mem1.szMalloc==0 ); /* See comment below */ + return rc; + } + + i++; + pRhs++; + d1 += sqlite3VdbeSerialTypeLen(serial_type); + idx1 += sqlite3VarintLen(serial_type); + }while( idx1<(unsigned)szHdr1 && inField && d1<=(unsigned)nKey1 ); + + /* No memory allocation is ever used on mem1. Prove this using + ** the following assert(). If the assert() fails, it indicates a + ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ + assert( mem1.szMalloc==0 ); + + /* rc==0 here means that one or both of the keys ran out of fields and + ** all the fields up to that point were equal. Return the default_rc + ** value. */ + assert( CORRUPT_DB + || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) + || pKeyInfo->db->mallocFailed + ); + pPKey2->eqSeen = 1; + return pPKey2->default_rc; +} +SQLITE_PRIVATE int sqlite3VdbeRecordCompare( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0); +} + + +/* +** This function is an optimized version of sqlite3VdbeRecordCompare() +** that (a) the first field of pPKey2 is an integer, and (b) the +** size-of-header varint at the start of (pKey1/nKey1) fits in a single +** byte (i.e. is less than 128). +** +** To avoid concerns about buffer overreads, this routine is only used +** on schemas where the maximum valid header size is 63 bytes or less. +*/ +static int vdbeRecordCompareInt( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F]; + int serial_type = ((const u8*)pKey1)[1]; + int res; + u32 y; + u64 x; + i64 v; + i64 lhs; + + vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); + assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB ); + switch( serial_type ){ + case 1: { /* 1-byte signed integer */ + lhs = ONE_BYTE_INT(aKey); + testcase( lhs<0 ); + break; + } + case 2: { /* 2-byte signed integer */ + lhs = TWO_BYTE_INT(aKey); + testcase( lhs<0 ); + break; + } + case 3: { /* 3-byte signed integer */ + lhs = THREE_BYTE_INT(aKey); + testcase( lhs<0 ); + break; + } + case 4: { /* 4-byte signed integer */ + y = FOUR_BYTE_UINT(aKey); + lhs = (i64)*(int*)&y; + testcase( lhs<0 ); + break; + } + case 5: { /* 6-byte signed integer */ + lhs = FOUR_BYTE_UINT(aKey+2) + (((i64)1)<<32)*TWO_BYTE_INT(aKey); + testcase( lhs<0 ); + break; + } + case 6: { /* 8-byte signed integer */ + x = FOUR_BYTE_UINT(aKey); + x = (x<<32) | FOUR_BYTE_UINT(aKey+4); + lhs = *(i64*)&x; + testcase( lhs<0 ); + break; + } + case 8: + lhs = 0; + break; + case 9: + lhs = 1; + break; + + /* This case could be removed without changing the results of running + ** this code. Including it causes gcc to generate a faster switch + ** statement (since the range of switch targets now starts at zero and + ** is contiguous) but does not cause any duplicate code to be generated + ** (as gcc is clever enough to combine the two like cases). Other + ** compilers might be similar. */ + case 0: case 7: + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); + + default: + return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); + } + + v = pPKey2->aMem[0].u.i; + if( v>lhs ){ + res = pPKey2->r1; + }else if( vr2; + }else if( pPKey2->nField>1 ){ + /* The first fields of the two keys are equal. Compare the trailing + ** fields. */ + res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); + }else{ + /* The first fields of the two keys are equal and there are no trailing + ** fields. Return pPKey2->default_rc in this case. */ + res = pPKey2->default_rc; + pPKey2->eqSeen = 1; + } + + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) ); + return res; +} + +/* +** This function is an optimized version of sqlite3VdbeRecordCompare() +** that (a) the first field of pPKey2 is a string, that (b) the first field +** uses the collation sequence BINARY and (c) that the size-of-header varint +** at the start of (pKey1/nKey1) fits in a single byte. +*/ +static int vdbeRecordCompareString( + int nKey1, const void *pKey1, /* Left key */ + UnpackedRecord *pPKey2 /* Right key */ +){ + const u8 *aKey1 = (const u8*)pKey1; + int serial_type; + int res; + + assert( pPKey2->aMem[0].flags & MEM_Str ); + vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); + getVarint32(&aKey1[1], serial_type); + if( serial_type<12 ){ + res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ + }else if( !(serial_type & 0x01) ){ + res = pPKey2->r2; /* (pKey1/nKey1) is a blob */ + }else{ + int nCmp; + int nStr; + int szHdr = aKey1[0]; + + nStr = (serial_type-12) / 2; + if( (szHdr + nStr) > nKey1 ){ + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } + nCmp = MIN( pPKey2->aMem[0].n, nStr ); + res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); + + if( res==0 ){ + res = nStr - pPKey2->aMem[0].n; + if( res==0 ){ + if( pPKey2->nField>1 ){ + res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); + }else{ + res = pPKey2->default_rc; + pPKey2->eqSeen = 1; + } + }else if( res>0 ){ + res = pPKey2->r2; + }else{ + res = pPKey2->r1; + } + }else if( res>0 ){ + res = pPKey2->r2; + }else{ + res = pPKey2->r1; + } + } + + assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) + || CORRUPT_DB + || pPKey2->pKeyInfo->db->mallocFailed + ); + return res; +} + +/* +** Return a pointer to an sqlite3VdbeRecordCompare() compatible function +** suitable for comparing serialized records to the unpacked record passed +** as the only argument. +*/ +SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ + /* varintRecordCompareInt() and varintRecordCompareString() both assume + ** that the size-of-header varint that occurs at the start of each record + ** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt() + ** also assumes that it is safe to overread a buffer by at least the + ** maximum possible legal header size plus 8 bytes. Because there is + ** guaranteed to be at least 74 (but not 136) bytes of padding following each + ** buffer passed to varintRecordCompareInt() this makes it convenient to + ** limit the size of the header to 64 bytes in cases where the first field + ** is an integer. + ** + ** 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 ){ + int flags = p->aMem[0].flags; + if( p->pKeyInfo->aSortOrder[0] ){ + p->r1 = 1; + p->r2 = -1; + }else{ + p->r1 = -1; + p->r2 = 1; + } + if( (flags & MEM_Int) ){ + return vdbeRecordCompareInt; + } + testcase( flags & MEM_Real ); + testcase( flags & MEM_Null ); + testcase( flags & MEM_Blob ); + if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ + assert( flags & MEM_Str ); + return vdbeRecordCompareString; + } + } + + return sqlite3VdbeRecordCompare; +} + +/* +** pCur points at an index entry created using the OP_MakeRecord opcode. +** Read the rowid (the last field in the record) and store it in *rowid. +** Return SQLITE_OK if everything works, or an error code otherwise. +** +** pCur might be pointing to text obtained from a corrupt database file. +** So the content cannot be trusted. Do appropriate checks on the content. +*/ +SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ + i64 nCellKey = 0; + int rc; + u32 szHdr; /* Size of the header */ + u32 typeRowid; /* Serial type of the rowid */ + u32 lenRowid; /* Size of the rowid */ + Mem m, v; + + /* Get the size of the index entry. Only indices entries of less + ** than 2GiB are support - anything large must be database corruption. + ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so + ** this code can safely assume that nCellKey is 32-bits + */ + assert( sqlite3BtreeCursorIsValid(pCur) ); + nCellKey = sqlite3BtreePayloadSize(pCur); + assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); + + /* Read in the complete content of the index entry */ + sqlite3VdbeMemInit(&m, db, 0); + rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); + if( rc ){ + return rc; + } + + /* The index entry must begin with a header size */ + (void)getVarint32((u8*)m.z, szHdr); + testcase( szHdr==3 ); + testcase( szHdr==m.n ); + if( unlikely(szHdr<3 || (int)szHdr>m.n) ){ + goto idx_rowid_corruption; + } + + /* The last field of the index should be an integer - the ROWID. + ** Verify that the last entry really is an integer. */ + (void)getVarint32((u8*)&m.z[szHdr-1], typeRowid); + testcase( typeRowid==1 ); + testcase( typeRowid==2 ); + testcase( typeRowid==3 ); + testcase( typeRowid==4 ); + testcase( typeRowid==5 ); + testcase( typeRowid==6 ); + testcase( typeRowid==8 ); + testcase( typeRowid==9 ); + if( unlikely(typeRowid<1 || typeRowid>9 || typeRowid==7) ){ + goto idx_rowid_corruption; + } + lenRowid = sqlite3SmallTypeSizes[typeRowid]; + testcase( (u32)m.n==szHdr+lenRowid ); + if( unlikely((u32)m.neCurType==CURTYPE_BTREE ); + pCur = pC->uc.pCursor; + assert( sqlite3BtreeCursorIsValid(pCur) ); + nCellKey = sqlite3BtreePayloadSize(pCur); + /* nCellKey will always be between 0 and 0xffffffff because of the way + ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ + if( nCellKey<=0 || nCellKey>0x7fffffff ){ + *res = 0; + return SQLITE_CORRUPT_BKPT; + } + sqlite3VdbeMemInit(&m, db, 0); + rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); + if( rc ){ + return rc; + } + *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); + sqlite3VdbeMemRelease(&m); + return SQLITE_OK; +} + +/* +** This routine sets the value to be returned by subsequent calls to +** sqlite3_changes() on the database handle 'db'. +*/ +SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){ + assert( sqlite3_mutex_held(db->mutex) ); + db->nChange = nChange; + db->nTotalChange += nChange; +} + +/* +** Set a flag in the vdbe to update the change counter when it is finalised +** or reset. +*/ +SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){ + v->changeCntOn = 1; +} + +/* +** Mark every prepared statement associated with a database connection +** as expired. +** +** An expired statement means that recompilation of the statement is +** recommend. Statements expire when things happen that make their +** programs obsolete. Removing user-defined functions or collating +** sequences, or changing an authorization function are the types of +** things that make prepared statements obsolete. +*/ +SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db){ + Vdbe *p; + for(p = db->pVdbe; p; p=p->pNext){ + p->expired = 1; + } +} + +/* +** Return the database associated with the Vdbe. +*/ +SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){ + return v->db; +} + +/* +** Return a pointer to an sqlite3_value structure containing the value bound +** parameter iVar of VM v. Except, if the value is an SQL NULL, return +** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_* +** constants) to the value before returning it. +** +** The returned value must be freed by the caller using sqlite3ValueFree(). +*/ +SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){ + assert( iVar>0 ); + if( v ){ + Mem *pMem = &v->aVar[iVar-1]; + if( 0==(pMem->flags & MEM_Null) ){ + sqlite3_value *pRet = sqlite3ValueNew(v->db); + if( pRet ){ + sqlite3VdbeMemCopy((Mem *)pRet, pMem); + sqlite3ValueApplyAffinity(pRet, aff, SQLITE_UTF8); + } + return pRet; + } + } + return 0; +} + +/* +** Configure SQL variable iVar so that binding a new value to it signals +** to sqlite3_reoptimize() that re-preparing the statement may result +** in a better query plan. +*/ +SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ + assert( iVar>0 ); + if( iVar>=32 ){ + v->expmask |= 0x80000000; + }else{ + v->expmask |= ((u32)1 << (iVar-1)); + } +} + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored +** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored +** in memory obtained from sqlite3DbMalloc). +*/ +SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){ + if( pVtab->zErrMsg ){ + sqlite3 *db = p->db; + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); + sqlite3_free(pVtab->zErrMsg); + pVtab->zErrMsg = 0; + } +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + +/* +** If the second argument is not NULL, release any allocations associated +** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord +** structure itself, using sqlite3DbFree(). +** +** This function is used to free UnpackedRecord structures allocated by +** the vdbeUnpackRecord() function found in vdbeapi.c. +*/ +static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ + if( p ){ + int i; + for(i=0; iaMem[i]; + if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem); + } + sqlite3DbFreeNN(db, p); + } +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call, +** then cursor passed as the second argument should point to the row about +** to be update or deleted. If the application calls sqlite3_preupdate_old(), +** the required value will be read from the row the cursor points to. +*/ +SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( + Vdbe *v, /* Vdbe pre-update hook is invoked by */ + VdbeCursor *pCsr, /* Cursor to grab old.* values from */ + int op, /* SQLITE_INSERT, UPDATE or DELETE */ + const char *zDb, /* Database name */ + Table *pTab, /* Modified table */ + i64 iKey1, /* Initial key value */ + int iReg /* Register for new.* record */ +){ + sqlite3 *db = v->db; + i64 iKey2; + PreUpdate preupdate; + const char *zTbl = pTab->zName; + static const u8 fakeSortOrder = 0; + + assert( db->pPreUpdate==0 ); + memset(&preupdate, 0, sizeof(PreUpdate)); + if( HasRowid(pTab)==0 ){ + iKey1 = iKey2 = 0; + preupdate.pPk = sqlite3PrimaryKeyIndex(pTab); + }else{ + if( op==SQLITE_UPDATE ){ + iKey2 = v->aMem[iReg].u.i; + }else{ + iKey2 = iKey1; + } + } + + assert( pCsr->nField==pTab->nCol + || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) + ); + + preupdate.v = v; + preupdate.pCsr = pCsr; + preupdate.op = op; + preupdate.iNewReg = iReg; + preupdate.keyinfo.db = db; + preupdate.keyinfo.enc = ENC(db); + preupdate.keyinfo.nField = pTab->nCol; + preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder; + preupdate.iKey1 = iKey1; + preupdate.iKey2 = iKey2; + preupdate.pTab = pTab; + + db->pPreUpdate = &preupdate; + 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); + if( preupdate.aNew ){ + int i; + for(i=0; inField; i++){ + sqlite3VdbeMemRelease(&preupdate.aNew[i]); + } + sqlite3DbFreeNN(db, preupdate.aNew); + } +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +/************** End of vdbeaux.c *********************************************/ +/************** Begin file vdbeapi.c *****************************************/ +/* +** 2004 May 26 +** +** 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 use to implement APIs that are part of the +** VDBE. +*/ +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** Return TRUE (non-zero) of the statement supplied as an argument needs +** to be recompiled. A statement needs to be recompiled whenever the +** execution environment changes in a way that would alter the program +** that sqlite3_prepare() generates. For example, if new functions or +** collating sequences are registered or if an authorizer function is +** added or changed. +*/ +SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe*)pStmt; + return p==0 || p->expired; +} +#endif + +/* +** Check on a Vdbe to make sure it has not been finalized. Log +** an error and return true if it has been finalized (or is otherwise +** invalid). Return false if it is ok. +*/ +static int vdbeSafety(Vdbe *p){ + if( p->db==0 ){ + sqlite3_log(SQLITE_MISUSE, "API called with finalized prepared statement"); + return 1; + }else{ + return 0; + } +} +static int vdbeSafetyNotNull(Vdbe *p){ + if( p==0 ){ + sqlite3_log(SQLITE_MISUSE, "API called with NULL prepared statement"); + return 1; + }else{ + return vdbeSafety(p); + } +} + +#ifndef SQLITE_OMIT_TRACE +/* +** Invoke the profile callback. This routine is only called if we already +** know that the profile callback is defined and needs to be invoked. +*/ +static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ + sqlite3_int64 iNow; + sqlite3_int64 iElapse; + assert( p->startTime>0 ); + assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 ); + assert( db->init.busy==0 ); + assert( p->zSql!=0 ); + sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); + iElapse = (iNow - p->startTime)*1000000; + if( db->xProfile ){ + db->xProfile(db->pProfileArg, p->zSql, iElapse); + } + if( db->mTrace & SQLITE_TRACE_PROFILE ){ + db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); + } + p->startTime = 0; +} +/* +** The checkProfileCallback(DB,P) macro checks to see if a profile callback +** is needed, and it invokes the callback if it is needed. +*/ +# define checkProfileCallback(DB,P) \ + if( ((P)->startTime)>0 ){ invokeProfileCallback(DB,P); } +#else +# define checkProfileCallback(DB,P) /*no-op*/ +#endif + +/* +** The following routine destroys a virtual machine that is created by +** the sqlite3_compile() routine. The integer returned is an SQLITE_ +** success/failure code that describes the result of executing the virtual +** machine. +** +** This routine sets the error code and string returned by +** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). +*/ +SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){ + int rc; + if( pStmt==0 ){ + /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL + ** pointer is a harmless no-op. */ + rc = SQLITE_OK; + }else{ + Vdbe *v = (Vdbe*)pStmt; + sqlite3 *db = v->db; + if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT; + sqlite3_mutex_enter(db->mutex); + checkProfileCallback(db, v); + rc = sqlite3VdbeFinalize(v); + rc = sqlite3ApiExit(db, rc); + sqlite3LeaveMutexAndCloseZombie(db); + } + return rc; +} + +/* +** Terminate the current execution of an SQL statement and reset it +** back to its starting state so that it can be reused. A success code from +** the prior execution is returned. +** +** This routine sets the error code and string returned by +** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16(). +*/ +SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){ + int rc; + if( pStmt==0 ){ + rc = SQLITE_OK; + }else{ + Vdbe *v = (Vdbe*)pStmt; + sqlite3 *db = v->db; + sqlite3_mutex_enter(db->mutex); + checkProfileCallback(db, v); + rc = sqlite3VdbeReset(v); + sqlite3VdbeRewind(v); + assert( (rc & (db->errMask))==rc ); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + } + return rc; +} + +/* +** Set all the parameters in the compiled SQL statement to NULL. +*/ +SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ + int i; + int rc = SQLITE_OK; + Vdbe *p = (Vdbe*)pStmt; +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex; +#endif + sqlite3_mutex_enter(mutex); + for(i=0; inVar; i++){ + sqlite3VdbeMemRelease(&p->aVar[i]); + p->aVar[i].flags = MEM_Null; + } + assert( p->isPrepareV2 || p->expmask==0 ); + if( p->expmask ){ + p->expired = 1; + } + sqlite3_mutex_leave(mutex); + return rc; +} + + +/**************************** sqlite3_value_ ******************************* +** The following routines extract information from a Mem or sqlite3_value +** structure. +*/ +SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){ + Mem *p = (Mem*)pVal; + if( p->flags & (MEM_Blob|MEM_Str) ){ + if( ExpandBlob(p)!=SQLITE_OK ){ + assert( p->flags==MEM_Null && p->z==0 ); + return 0; + } + p->flags |= MEM_Blob; + return p->n ? p->z : 0; + }else{ + return sqlite3_value_text(pVal); + } +} +SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){ + return sqlite3ValueBytes(pVal, SQLITE_UTF8); +} +SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){ + return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE); +} +SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){ + return sqlite3VdbeRealValue((Mem*)pVal); +} +SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){ + return (int)sqlite3VdbeIntValue((Mem*)pVal); +} +SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){ + return sqlite3VdbeIntValue((Mem*)pVal); +} +SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){ + Mem *pMem = (Mem*)pVal; + return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0); +} +SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ + return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){ + return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); +} +SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){ + return sqlite3ValueText(pVal, SQLITE_UTF16BE); +} +SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ + return sqlite3ValueText(pVal, SQLITE_UTF16LE); +} +#endif /* SQLITE_OMIT_UTF16 */ +/* EVIDENCE-OF: R-12793-43283 Every value in SQLite has one of five +** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating +** point number string BLOB NULL +*/ +SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ + static const u8 aType[] = { + SQLITE_BLOB, /* 0x00 */ + SQLITE_NULL, /* 0x01 */ + SQLITE_TEXT, /* 0x02 */ + SQLITE_NULL, /* 0x03 */ + SQLITE_INTEGER, /* 0x04 */ + SQLITE_NULL, /* 0x05 */ + SQLITE_INTEGER, /* 0x06 */ + SQLITE_NULL, /* 0x07 */ + SQLITE_FLOAT, /* 0x08 */ + SQLITE_NULL, /* 0x09 */ + SQLITE_FLOAT, /* 0x0a */ + SQLITE_NULL, /* 0x0b */ + SQLITE_INTEGER, /* 0x0c */ + SQLITE_NULL, /* 0x0d */ + SQLITE_INTEGER, /* 0x0e */ + SQLITE_NULL, /* 0x0f */ + SQLITE_BLOB, /* 0x10 */ + SQLITE_NULL, /* 0x11 */ + SQLITE_TEXT, /* 0x12 */ + SQLITE_NULL, /* 0x13 */ + SQLITE_INTEGER, /* 0x14 */ + SQLITE_NULL, /* 0x15 */ + SQLITE_INTEGER, /* 0x16 */ + SQLITE_NULL, /* 0x17 */ + SQLITE_FLOAT, /* 0x18 */ + SQLITE_NULL, /* 0x19 */ + SQLITE_FLOAT, /* 0x1a */ + SQLITE_NULL, /* 0x1b */ + SQLITE_INTEGER, /* 0x1c */ + SQLITE_NULL, /* 0x1d */ + SQLITE_INTEGER, /* 0x1e */ + SQLITE_NULL, /* 0x1f */ + }; + return aType[pVal->flags&MEM_AffMask]; +} + +/* Make a copy of an sqlite3_value object +*/ +SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ + sqlite3_value *pNew; + if( pOrig==0 ) return 0; + pNew = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return 0; + memset(pNew, 0, sizeof(*pNew)); + memcpy(pNew, pOrig, MEMCELLSIZE); + pNew->flags &= ~MEM_Dyn; + pNew->db = 0; + if( pNew->flags&(MEM_Str|MEM_Blob) ){ + pNew->flags &= ~(MEM_Static|MEM_Dyn); + pNew->flags |= MEM_Ephem; + if( sqlite3VdbeMemMakeWriteable(pNew)!=SQLITE_OK ){ + sqlite3ValueFree(pNew); + pNew = 0; + } + } + return pNew; +} + +/* Destroy an sqlite3_value object previously obtained from +** sqlite3_value_dup(). +*/ +SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){ + sqlite3ValueFree(pOld); +} + + +/**************************** sqlite3_result_ ******************************* +** The following routines are used by user-defined functions to specify +** the function result. +** +** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the +** result as a string or blob but if the string or blob is too large, it +** then sets the error code to SQLITE_TOOBIG +** +** The invokeValueDestructor(P,X) routine invokes destructor function X() +** on value P is not going to be used and need to be destroyed. +*/ +static void setResultStrOrError( + sqlite3_context *pCtx, /* Function context */ + const char *z, /* String pointer */ + int n, /* Bytes in string, or negative */ + u8 enc, /* Encoding of z. 0 for BLOBs */ + void (*xDel)(void*) /* Destructor function */ +){ + if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){ + sqlite3_result_error_toobig(pCtx); + } +} +static int invokeValueDestructor( + const void *p, /* Value to destroy */ + void (*xDel)(void*), /* The destructor */ + sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */ +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( xDel==0 ){ + /* noop */ + }else if( xDel==SQLITE_TRANSIENT ){ + /* noop */ + }else{ + xDel((void*)p); + } + if( pCtx ) sqlite3_result_error_toobig(pCtx); + return SQLITE_TOOBIG; +} +SQLITE_API void sqlite3_result_blob( + sqlite3_context *pCtx, + const void *z, + int n, + void (*xDel)(void *) +){ + assert( n>=0 ); + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + setResultStrOrError(pCtx, z, n, 0, xDel); +} +SQLITE_API void sqlite3_result_blob64( + sqlite3_context *pCtx, + const void *z, + sqlite3_uint64 n, + void (*xDel)(void *) +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( xDel!=SQLITE_DYNAMIC ); + if( n>0x7fffffff ){ + (void)invokeValueDestructor(z, xDel, pCtx); + }else{ + setResultStrOrError(pCtx, z, (int)n, 0, xDel); + } +} +SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); +} +SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + pCtx->isError = SQLITE_ERROR; + pCtx->fErrorOrAux = 1; + sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + pCtx->isError = SQLITE_ERROR; + pCtx->fErrorOrAux = 1; + sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); +} +#endif +SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal); +} +SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetInt64(pCtx->pOut, iVal); +} +SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetNull(pCtx->pOut); +} +SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + pOut->eSubtype = eSubtype & 0xff; + pOut->flags |= MEM_Subtype; +} +SQLITE_API void sqlite3_result_text( + sqlite3_context *pCtx, + const char *z, + int n, + void (*xDel)(void *) +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); +} +SQLITE_API void sqlite3_result_text64( + sqlite3_context *pCtx, + const char *z, + sqlite3_uint64 n, + void (*xDel)(void *), + unsigned char enc +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( xDel!=SQLITE_DYNAMIC ); + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + if( n>0x7fffffff ){ + (void)invokeValueDestructor(z, xDel, pCtx); + }else{ + setResultStrOrError(pCtx, z, (int)n, enc, xDel); + } +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API void sqlite3_result_text16( + sqlite3_context *pCtx, + const void *z, + int n, + void (*xDel)(void *) +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); +} +SQLITE_API void sqlite3_result_text16be( + sqlite3_context *pCtx, + const void *z, + int n, + void (*xDel)(void *) +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); +} +SQLITE_API void sqlite3_result_text16le( + sqlite3_context *pCtx, + const void *z, + int n, + void (*xDel)(void *) +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel); +} +#endif /* SQLITE_OMIT_UTF16 */ +SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemCopy(pCtx->pOut, pValue); +} +SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n); +} +SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ + return SQLITE_TOOBIG; + } + sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); + return SQLITE_OK; +} +SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ + pCtx->isError = errCode; + pCtx->fErrorOrAux = 1; +#ifdef SQLITE_DEBUG + if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode; +#endif + if( pCtx->pOut->flags & MEM_Null ){ + sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, + SQLITE_UTF8, SQLITE_STATIC); + } +} + +/* Force an SQLITE_TOOBIG error. */ +SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + pCtx->isError = SQLITE_TOOBIG; + pCtx->fErrorOrAux = 1; + sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, + SQLITE_UTF8, SQLITE_STATIC); +} + +/* An SQLITE_NOMEM error. */ +SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + sqlite3VdbeMemSetNull(pCtx->pOut); + pCtx->isError = SQLITE_NOMEM_BKPT; + pCtx->fErrorOrAux = 1; + sqlite3OomFault(pCtx->pOut->db); +} + +/* +** This function is called after a transaction has been committed. It +** invokes callbacks registered with sqlite3_wal_hook() as required. +*/ +static int doWalCallbacks(sqlite3 *db){ + int rc = SQLITE_OK; +#ifndef SQLITE_OMIT_WAL + int i; + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + int nEntry; + sqlite3BtreeEnter(pBt); + nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); + sqlite3BtreeLeave(pBt); + if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ + rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry); + } + } + } +#endif + return rc; +} + + +/* +** Execute the statement pStmt, either until a row of data is ready, the +** statement is completely executed or an error occurs. +** +** This routine implements the bulk of the logic behind the sqlite_step() +** API. The only thing omitted is the automatic recompile if a +** schema change has occurred. That detail is handled by the +** outer sqlite3_step() wrapper procedure. +*/ +static int sqlite3Step(Vdbe *p){ + sqlite3 *db; + int rc; + + assert(p); + if( p->magic!=VDBE_MAGIC_RUN ){ + /* We used to require that sqlite3_reset() be called before retrying + ** sqlite3_step() after any error or after SQLITE_DONE. But beginning + ** with version 3.7.0, we changed this so that sqlite3_reset() would + ** be called automatically instead of throwing the SQLITE_MISUSE error. + ** This "automatic-reset" change is not technically an incompatibility, + ** since any application that receives an SQLITE_MISUSE is broken by + ** definition. + ** + ** Nevertheless, some published applications that were originally written + ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE + ** returns, and those were broken by the automatic-reset change. As a + ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the + ** legacy behavior of returning SQLITE_MISUSE for cases where the + ** previous sqlite3_step() returned something other than a SQLITE_LOCKED + ** or SQLITE_BUSY error. + */ +#ifdef SQLITE_OMIT_AUTORESET + if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){ + sqlite3_reset((sqlite3_stmt*)p); + }else{ + return SQLITE_MISUSE_BKPT; + } +#else + sqlite3_reset((sqlite3_stmt*)p); +#endif + } + + /* Check that malloc() has not failed. If it has, return early. */ + db = p->db; + if( db->mallocFailed ){ + p->rc = SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; + } + + if( p->pc<=0 && p->expired ){ + p->rc = SQLITE_SCHEMA; + rc = SQLITE_ERROR; + goto end_of_step; + } + if( p->pc<0 ){ + /* If there are no other statements currently running, then + ** reset the interrupt flag. This prevents a call to sqlite3_interrupt + ** from interrupting a statement that has not yet started. + */ + if( db->nVdbeActive==0 ){ + db->u1.isInterrupted = 0; + } + + assert( db->nVdbeWrite>0 || db->autoCommit==0 + || (db->nDeferredCons==0 && db->nDeferredImmCons==0) + ); + +#ifndef SQLITE_OMIT_TRACE + if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0) + && !db->init.busy && p->zSql ){ + sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); + }else{ + assert( p->startTime==0 ); + } +#endif + + db->nVdbeActive++; + if( p->readOnly==0 ) db->nVdbeWrite++; + if( p->bIsReader ) db->nVdbeRead++; + p->pc = 0; + } +#ifdef SQLITE_DEBUG + p->rcApp = SQLITE_OK; +#endif +#ifndef SQLITE_OMIT_EXPLAIN + if( p->explain ){ + rc = sqlite3VdbeList(p); + }else +#endif /* SQLITE_OMIT_EXPLAIN */ + { + db->nVdbeExec++; + rc = sqlite3VdbeExec(p); + db->nVdbeExec--; + } + +#ifndef SQLITE_OMIT_TRACE + /* If the statement completed successfully, invoke the profile callback */ + if( rc!=SQLITE_ROW ) checkProfileCallback(db, p); +#endif + + if( rc==SQLITE_DONE ){ + assert( p->rc==SQLITE_OK ); + p->rc = doWalCallbacks(db); + if( p->rc!=SQLITE_OK ){ + rc = SQLITE_ERROR; + } + } + + db->errCode = rc; + if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){ + p->rc = SQLITE_NOMEM_BKPT; + } +end_of_step: + /* At this point local variable rc holds the value that should be + ** returned if this statement was compiled using the legacy + ** sqlite3_prepare() interface. According to the docs, this can only + ** be one of the values in the first assert() below. Variable p->rc + ** contains the value that would be returned if sqlite3_finalize() + ** were called on statement p. + */ + assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR + || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE + ); + assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); + if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ + /* If this statement was prepared using sqlite3_prepare_v2(), and an + ** error has occurred, then return the error code in p->rc to the + ** caller. Set the error code in the database handle to the same value. + */ + rc = sqlite3VdbeTransferError(p); + } + return (rc&db->errMask); +} + +/* +** This is the top-level implementation of sqlite3_step(). Call +** sqlite3Step() to do most of the work. If a schema error occurs, +** call sqlite3Reprepare() and try again. +*/ +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 */ + + if( vdbeSafetyNotNull(v) ){ + return SQLITE_MISUSE_BKPT; + } + db = v->db; + sqlite3_mutex_enter(db->mutex); + v->doingRerun = 0; + while( (rc = sqlite3Step(v))==SQLITE_SCHEMA + && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ + int savedPc = v->pc; + rc2 = rc = sqlite3Reprepare(v); + if( rc!=SQLITE_OK) 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; +} + + +/* +** Extract the user data from a sqlite3_context structure and return a +** pointer to it. +*/ +SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ + assert( p && p->pFunc ); + return p->pFunc->pUserData; +} + +/* +** Extract the user data from a sqlite3_context structure and return a +** pointer to it. +** +** IMPLEMENTATION-OF: R-46798-50301 The sqlite3_context_db_handle() interface +** returns a copy of the pointer to the database connection (the 1st +** parameter) of the sqlite3_create_function() and +** sqlite3_create_function16() routines that originally registered the +** application defined function. +*/ +SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ + assert( p && p->pOut ); + return p->pOut->db; +} + +/* +** Return the current time for a statement. If the current time +** is requested more than once within the same run of a single prepared +** statement, the exact same time is returned for each invocation regardless +** of the amount of time that elapses between invocations. In other words, +** the time returned is always the time of the first call. +*/ +SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ + int rc; +#ifndef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime; + assert( p->pVdbe!=0 ); +#else + sqlite3_int64 iTime = 0; + sqlite3_int64 *piTime = p->pVdbe!=0 ? &p->pVdbe->iCurrentTime : &iTime; +#endif + if( *piTime==0 ){ + rc = sqlite3OsCurrentTimeInt64(p->pOut->db->pVfs, piTime); + if( rc ) *piTime = 0; + } + return *piTime; +} + +/* +** The following is the implementation of an SQL function that always +** fails with an error message stating that the function is used in the +** wrong context. The sqlite3_overload_function() API might construct +** SQL function that use this routine so that the functions will exist +** for name resolution but are actually overloaded by the xFindFunction +** method of virtual tables. +*/ +SQLITE_PRIVATE void sqlite3InvalidFunction( + sqlite3_context *context, /* The function calling context */ + int NotUsed, /* Number of arguments to the function */ + sqlite3_value **NotUsed2 /* Value of each argument */ +){ + const char *zName = context->pFunc->zName; + char *zErr; + UNUSED_PARAMETER2(NotUsed, NotUsed2); + zErr = sqlite3_mprintf( + "unable to use function %s in the requested context", zName); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); +} + +/* +** Create a new aggregate context for p and return a pointer to +** its pMem->z element. +*/ +static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){ + Mem *pMem = p->pMem; + assert( (pMem->flags & MEM_Agg)==0 ); + if( nByte<=0 ){ + sqlite3VdbeMemSetNull(pMem); + pMem->z = 0; + }else{ + sqlite3VdbeMemClearAndResize(pMem, nByte); + pMem->flags = MEM_Agg; + pMem->u.pDef = p->pFunc; + if( pMem->z ){ + memset(pMem->z, 0, nByte); + } + } + return (void*)pMem->z; +} + +/* +** Allocate or return the aggregate context for a user function. A new +** context is allocated on the first call. Subsequent calls return the +** same context that was returned on prior calls. +*/ +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ + assert( p && p->pFunc && p->pFunc->xFinalize ); + assert( sqlite3_mutex_held(p->pOut->db->mutex) ); + testcase( nByte<0 ); + if( (p->pMem->flags & MEM_Agg)==0 ){ + return createAggContext(p, nByte); + }else{ + return (void*)p->pMem->z; + } +} + +/* +** Return the auxiliary data pointer, if any, for the iArg'th argument to +** the user-function defined by pCtx. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then access a cache of +** auxiliary data pointers that is available to all functions within a +** single prepared statement. The iArg values must match. +*/ +SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ + AuxData *pAuxData; + + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); +#if SQLITE_ENABLE_STAT3_OR_STAT4 + if( pCtx->pVdbe==0 ) return 0; +#else + assert( pCtx->pVdbe!=0 ); +#endif + for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + return pAuxData->pAux; + } + } + return 0; +} + +/* +** Set the auxiliary data pointer and delete function, for the iArg'th +** argument to the user-function defined by pCtx. Any previous value is +** deleted by calling the delete function specified when it was set. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then make the data available +** to all functions within the current prepared statement using iArg as an +** access code. +*/ +SQLITE_API void sqlite3_set_auxdata( + sqlite3_context *pCtx, + int iArg, + void *pAux, + void (*xDelete)(void*) +){ + AuxData *pAuxData; + Vdbe *pVdbe = pCtx->pVdbe; + + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( pVdbe==0 ) goto failed; +#else + assert( pVdbe!=0 ); +#endif + + for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + break; + } + } + if( pAuxData==0 ){ + pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData)); + if( !pAuxData ) goto failed; + pAuxData->iAuxOp = pCtx->iOp; + pAuxData->iAuxArg = iArg; + pAuxData->pNextAux = pVdbe->pAuxData; + pVdbe->pAuxData = pAuxData; + if( pCtx->fErrorOrAux==0 ){ + pCtx->isError = 0; + pCtx->fErrorOrAux = 1; + } + }else if( pAuxData->xDeleteAux ){ + pAuxData->xDeleteAux(pAuxData->pAux); + } + + pAuxData->pAux = pAux; + pAuxData->xDeleteAux = xDelete; + return; + +failed: + if( xDelete ){ + xDelete(pAux); + } +} + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** Return the number of times the Step function of an aggregate has been +** called. +** +** This function is deprecated. Do not use it for new code. It is +** provide only to avoid breaking legacy code. New aggregate function +** implementations should keep their own counts within their aggregate +** context. +*/ +SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){ + assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize ); + return p->pMem->n; +} +#endif + +/* +** Return the number of columns in the result set for the statement pStmt. +*/ +SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){ + Vdbe *pVm = (Vdbe *)pStmt; + return pVm ? pVm->nResColumn : 0; +} + +/* +** Return the number of values available from the current row of the +** currently executing statement pStmt. +*/ +SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){ + Vdbe *pVm = (Vdbe *)pStmt; + if( pVm==0 || pVm->pResultSet==0 ) return 0; + return pVm->nResColumn; +} + +/* +** Return a pointer to static memory containing an SQL NULL value. +*/ +static const Mem *columnNullValue(void){ + /* Even though the Mem structure contains an element + ** of type i64, on certain architectures (x86) with certain compiler + ** switches (-Os), gcc may align this Mem object on a 4-byte boundary + ** instead of an 8-byte one. This all works fine, except that when + ** running with SQLITE_DEBUG defined the SQLite code sometimes assert()s + ** that a Mem structure is located on an 8-byte boundary. To prevent + ** these assert()s from failing, when building with SQLITE_DEBUG defined + ** using gcc, we force nullMem to be 8-byte aligned using the magical + ** __attribute__((aligned(8))) macro. */ + static const Mem nullMem +#if defined(SQLITE_DEBUG) && defined(__GNUC__) + __attribute__((aligned(8))) +#endif + = { + /* .u = */ {0}, + /* .flags = */ (u16)MEM_Null, + /* .enc = */ (u8)0, + /* .eSubtype = */ (u8)0, + /* .n = */ (int)0, + /* .z = */ (char*)0, + /* .zMalloc = */ (char*)0, + /* .szMalloc = */ (int)0, + /* .uTemp = */ (u32)0, + /* .db = */ (sqlite3*)0, + /* .xDel = */ (void(*)(void*))0, +#ifdef SQLITE_DEBUG + /* .pScopyFrom = */ (Mem*)0, + /* .pFiller = */ (void*)0, +#endif + }; + return &nullMem; +} + +/* +** Check to see if column iCol of the given statement is valid. If +** it is, return a pointer to the Mem for the value of that column. +** If iCol is not valid, return a pointer to a Mem which has a value +** of NULL. +*/ +static Mem *columnMem(sqlite3_stmt *pStmt, int i){ + Vdbe *pVm; + Mem *pOut; + + pVm = (Vdbe *)pStmt; + if( pVm==0 ) return (Mem*)columnNullValue(); + assert( pVm->db ); + sqlite3_mutex_enter(pVm->db->mutex); + if( pVm->pResultSet!=0 && inResColumn && i>=0 ){ + pOut = &pVm->pResultSet[i]; + }else{ + sqlite3Error(pVm->db, SQLITE_RANGE); + pOut = (Mem*)columnNullValue(); + } + return pOut; +} + +/* +** This function is called after invoking an sqlite3_value_XXX function on a +** column value (i.e. a value returned by evaluating an SQL expression in the +** select list of a SELECT statement) that may cause a malloc() failure. If +** malloc() has failed, the threads mallocFailed flag is cleared and the result +** code of statement pStmt set to SQLITE_NOMEM. +** +** Specifically, this is called from within: +** +** sqlite3_column_int() +** sqlite3_column_int64() +** sqlite3_column_text() +** sqlite3_column_text16() +** sqlite3_column_real() +** sqlite3_column_bytes() +** sqlite3_column_bytes16() +** sqiite3_column_blob() +*/ +static void columnMallocFailure(sqlite3_stmt *pStmt) +{ + /* If malloc() failed during an encoding conversion within an + ** sqlite3_column_XXX API, then set the return code of the statement to + ** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR + ** and _finalize() will return NOMEM. + */ + Vdbe *p = (Vdbe *)pStmt; + if( p ){ + assert( p->db!=0 ); + assert( sqlite3_mutex_held(p->db->mutex) ); + p->rc = sqlite3ApiExit(p->db, p->rc); + sqlite3_mutex_leave(p->db->mutex); + } +} + +/**************************** sqlite3_column_ ******************************* +** The following routines are used to access elements of the current row +** in the result set. +*/ +SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){ + const void *val; + val = sqlite3_value_blob( columnMem(pStmt,i) ); + /* Even though there is no encoding conversion, value_blob() might + ** need to call malloc() to expand the result of a zeroblob() + ** expression. + */ + columnMallocFailure(pStmt); + return val; +} +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){ + int val = sqlite3_value_bytes( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return val; +} +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){ + int val = sqlite3_value_bytes16( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return val; +} +SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){ + double val = sqlite3_value_double( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return val; +} +SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){ + int val = sqlite3_value_int( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return val; +} +SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){ + sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return val; +} +SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ + const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return val; +} +SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){ + Mem *pOut = columnMem(pStmt, i); + if( pOut->flags&MEM_Static ){ + pOut->flags &= ~MEM_Static; + pOut->flags |= MEM_Ephem; + } + columnMallocFailure(pStmt); + return (sqlite3_value *)pOut; +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){ + const void *val = sqlite3_value_text16( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return val; +} +#endif /* SQLITE_OMIT_UTF16 */ +SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ + int iType = sqlite3_value_type( columnMem(pStmt,i) ); + columnMallocFailure(pStmt); + return iType; +} + +/* +** Convert the N-th element of pStmt->pColName[] into a string using +** xFunc() then return that string. If N is out of range, return 0. +** +** There are up to 5 names for each column. useType determines which +** name is returned. Here are the names: +** +** 0 The column name as it should be displayed for output +** 1 The datatype name for the column +** 2 The name of the database that the column derives from +** 3 The name of the table that the column derives from +** 4 The name of the table column that the result column derives from +** +** If the result is not a simple column reference (if it is an expression +** or a constant) then useTypes 2, 3, and 4 return NULL. +*/ +static const void *columnName( + sqlite3_stmt *pStmt, + int N, + const void *(*xFunc)(Mem*), + int useType +){ + const void *ret; + Vdbe *p; + int n; + sqlite3 *db; +#ifdef SQLITE_ENABLE_API_ARMOR + if( pStmt==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + ret = 0; + p = (Vdbe *)pStmt; + db = p->db; + assert( db!=0 ); + n = sqlite3_column_count(pStmt); + if( N=0 ){ + N += useType*n; + sqlite3_mutex_enter(db->mutex); + assert( db->mallocFailed==0 ); + ret = xFunc(&p->aColName[N]); + /* A malloc may have failed inside of the xFunc() call. If this + ** is the case, clear the mallocFailed flag and return NULL. + */ + if( db->mallocFailed ){ + sqlite3OomClear(db); + ret = 0; + } + sqlite3_mutex_leave(db->mutex); + } + return ret; +} + +/* +** Return the name of the Nth column of the result set returned by SQL +** statement pStmt. +*/ +SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME); +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME); +} +#endif + +/* +** Constraint: If you have ENABLE_COLUMN_METADATA then you must +** not define OMIT_DECLTYPE. +*/ +#if defined(SQLITE_OMIT_DECLTYPE) && defined(SQLITE_ENABLE_COLUMN_METADATA) +# error "Must not define both SQLITE_OMIT_DECLTYPE \ + and SQLITE_ENABLE_COLUMN_METADATA" +#endif + +#ifndef SQLITE_OMIT_DECLTYPE +/* +** Return the column declaration type (if applicable) of the 'i'th column +** of the result set of SQL statement pStmt. +*/ +SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE); +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE); +} +#endif /* SQLITE_OMIT_UTF16 */ +#endif /* SQLITE_OMIT_DECLTYPE */ + +#ifdef SQLITE_ENABLE_COLUMN_METADATA +/* +** Return the name of the database from which a result column derives. +** NULL is returned if the result column is an expression or constant or +** anything else which is not an unambiguous reference to a database column. +*/ +SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE); +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE); +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** Return the name of the table from which a result column derives. +** NULL is returned if the result column is an expression or constant or +** anything else which is not an unambiguous reference to a database column. +*/ +SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE); +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE); +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** Return the name of the table column from which a result column derives. +** NULL is returned if the result column is an expression or constant or +** anything else which is not an unambiguous reference to a database column. +*/ +SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN); +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN); +} +#endif /* SQLITE_OMIT_UTF16 */ +#endif /* SQLITE_ENABLE_COLUMN_METADATA */ + + +/******************************* sqlite3_bind_ *************************** +** +** Routines used to attach values to wildcards in a compiled SQL statement. +*/ +/* +** Unbind the value bound to variable i in virtual machine p. This is the +** the same as binding a NULL value to the column. If the "i" parameter is +** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK. +** +** A successful evaluation of this routine acquires the mutex on p. +** the mutex is released if any kind of error occurs. +** +** The error code stored in database p->db is overwritten with the return +** value in any case. +*/ +static int vdbeUnbind(Vdbe *p, int i){ + Mem *pVar; + if( vdbeSafetyNotNull(p) ){ + return SQLITE_MISUSE_BKPT; + } + sqlite3_mutex_enter(p->db->mutex); + if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){ + sqlite3Error(p->db, SQLITE_MISUSE); + sqlite3_mutex_leave(p->db->mutex); + sqlite3_log(SQLITE_MISUSE, + "bind on a busy prepared statement: [%s]", p->zSql); + return SQLITE_MISUSE_BKPT; + } + if( i<1 || i>p->nVar ){ + sqlite3Error(p->db, SQLITE_RANGE); + sqlite3_mutex_leave(p->db->mutex); + return SQLITE_RANGE; + } + i--; + pVar = &p->aVar[i]; + sqlite3VdbeMemRelease(pVar); + pVar->flags = MEM_Null; + sqlite3Error(p->db, SQLITE_OK); + + /* If the bit corresponding to this variable in Vdbe.expmask is set, then + ** binding a new value to this variable invalidates the current query plan. + ** + ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host + ** parameter in the WHERE clause might influence the choice of query plan + ** for a statement, then the statement will be automatically recompiled, + ** as if there had been a schema change, on the first sqlite3_step() call + ** following any change to the bindings of that parameter. + */ + assert( p->isPrepareV2 || p->expmask==0 ); + if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<expired = 1; + } + return SQLITE_OK; +} + +/* +** Bind a text or BLOB value. +*/ +static int bindText( + sqlite3_stmt *pStmt, /* The statement to bind against */ + int i, /* Index of the parameter to bind */ + const void *zData, /* Pointer to the data to be bound */ + int nData, /* Number of bytes of data to be bound */ + void (*xDel)(void*), /* Destructor for the data */ + u8 encoding /* Encoding for the data */ +){ + Vdbe *p = (Vdbe *)pStmt; + Mem *pVar; + int rc; + + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + if( zData!=0 ){ + pVar = &p->aVar[i-1]; + rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); + if( rc==SQLITE_OK && encoding!=0 ){ + rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); + } + sqlite3Error(p->db, rc); + rc = sqlite3ApiExit(p->db, rc); + } + sqlite3_mutex_leave(p->db->mutex); + }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){ + xDel((void*)zData); + } + return rc; +} + + +/* +** Bind a blob value to an SQL statement variable. +*/ +SQLITE_API int sqlite3_bind_blob( + sqlite3_stmt *pStmt, + int i, + const void *zData, + int nData, + void (*xDel)(void*) +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( nData<0 ) return SQLITE_MISUSE_BKPT; +#endif + return bindText(pStmt, i, zData, nData, xDel, 0); +} +SQLITE_API int sqlite3_bind_blob64( + sqlite3_stmt *pStmt, + int i, + const void *zData, + sqlite3_uint64 nData, + void (*xDel)(void*) +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, xDel, 0); + }else{ + return bindText(pStmt, i, zData, (int)nData, xDel, 0); + } +} +SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ + int rc; + Vdbe *p = (Vdbe *)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue); + sqlite3_mutex_leave(p->db->mutex); + } + return rc; +} +SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){ + return sqlite3_bind_int64(p, i, (i64)iValue); +} +SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){ + int rc; + Vdbe *p = (Vdbe *)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue); + sqlite3_mutex_leave(p->db->mutex); + } + return rc; +} +SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ + int rc; + Vdbe *p = (Vdbe*)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3_mutex_leave(p->db->mutex); + } + return rc; +} +SQLITE_API int sqlite3_bind_text( + sqlite3_stmt *pStmt, + int i, + const char *zData, + int nData, + void (*xDel)(void*) +){ + return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); +} +SQLITE_API int sqlite3_bind_text64( + sqlite3_stmt *pStmt, + int i, + const char *zData, + sqlite3_uint64 nData, + void (*xDel)(void*), + unsigned char enc +){ + assert( xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, xDel, 0); + }else{ + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + return bindText(pStmt, i, zData, (int)nData, xDel, enc); + } +} +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API int sqlite3_bind_text16( + sqlite3_stmt *pStmt, + int i, + const void *zData, + int nData, + void (*xDel)(void*) +){ + return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); +} +#endif /* SQLITE_OMIT_UTF16 */ +SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ + int rc; + switch( sqlite3_value_type((sqlite3_value*)pValue) ){ + case SQLITE_INTEGER: { + rc = sqlite3_bind_int64(pStmt, i, pValue->u.i); + break; + } + case SQLITE_FLOAT: { + rc = sqlite3_bind_double(pStmt, i, pValue->u.r); + break; + } + case SQLITE_BLOB: { + if( pValue->flags & MEM_Zero ){ + rc = sqlite3_bind_zeroblob(pStmt, i, pValue->u.nZero); + }else{ + rc = sqlite3_bind_blob(pStmt, i, pValue->z, pValue->n,SQLITE_TRANSIENT); + } + break; + } + case SQLITE_TEXT: { + rc = bindText(pStmt,i, pValue->z, pValue->n, SQLITE_TRANSIENT, + pValue->enc); + break; + } + default: { + rc = sqlite3_bind_null(pStmt, i); + break; + } + } + return rc; +} +SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ + int rc; + Vdbe *p = (Vdbe *)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); + sqlite3_mutex_leave(p->db->mutex); + } + return rc; +} +SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){ + int rc; + Vdbe *p = (Vdbe *)pStmt; + sqlite3_mutex_enter(p->db->mutex); + if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){ + rc = SQLITE_TOOBIG; + }else{ + assert( (n & 0x7FFFFFFF)==n ); + rc = sqlite3_bind_zeroblob(pStmt, i, n); + } + rc = sqlite3ApiExit(p->db, rc); + sqlite3_mutex_leave(p->db->mutex); + return rc; +} + +/* +** Return the number of wildcards that can be potentially bound to. +** This routine is added to support DBD::SQLite. +*/ +SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe*)pStmt; + return p ? p->nVar : 0; +} + +/* +** Return the name of a wildcard parameter. Return NULL if the index +** is out of range or if the wildcard is unnamed. +** +** The result is always UTF-8. +*/ +SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){ + Vdbe *p = (Vdbe*)pStmt; + if( p==0 ) return 0; + return sqlite3VListNumToName(p->pVList, i); +} + +/* +** Given a wildcard parameter name, return the index of the variable +** with that name. If there is no variable with the given name, +** return 0. +*/ +SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){ + if( p==0 || zName==0 ) return 0; + return sqlite3VListNameToNum(p->pVList, zName, nName); +} +SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){ + return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName)); +} + +/* +** Transfer all bindings from the first statement over to the second. +*/ +SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ + Vdbe *pFrom = (Vdbe*)pFromStmt; + Vdbe *pTo = (Vdbe*)pToStmt; + int i; + assert( pTo->db==pFrom->db ); + assert( pTo->nVar==pFrom->nVar ); + sqlite3_mutex_enter(pTo->db->mutex); + for(i=0; inVar; i++){ + sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); + } + sqlite3_mutex_leave(pTo->db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** Deprecated external interface. Internal/core SQLite code +** should call sqlite3TransferBindings. +** +** It is misuse to call this routine with statements from different +** database connections. But as this is a deprecated interface, we +** will not bother to check for that condition. +** +** If the two statements contain a different number of bindings, then +** an SQLITE_ERROR is returned. Nothing else can go wrong, so otherwise +** SQLITE_OK is returned. +*/ +SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ + Vdbe *pFrom = (Vdbe*)pFromStmt; + Vdbe *pTo = (Vdbe*)pToStmt; + if( pFrom->nVar!=pTo->nVar ){ + return SQLITE_ERROR; + } + assert( pTo->isPrepareV2 || pTo->expmask==0 ); + if( pTo->expmask ){ + pTo->expired = 1; + } + assert( pFrom->isPrepareV2 || pFrom->expmask==0 ); + if( pFrom->expmask ){ + pFrom->expired = 1; + } + return sqlite3TransferBindings(pFromStmt, pToStmt); +} +#endif + +/* +** Return the sqlite3* database handle to which the prepared statement given +** in the argument belongs. This is the same database handle that was +** the first argument to the sqlite3_prepare() that was used to create +** the statement in the first place. +*/ +SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){ + return pStmt ? ((Vdbe*)pStmt)->db : 0; +} + +/* +** Return true if the prepared statement is guaranteed to not modify the +** database. +*/ +SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ + return pStmt ? ((Vdbe*)pStmt)->readOnly : 1; +} + +/* +** Return true if the prepared statement is in need of being reset. +*/ +SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ + Vdbe *v = (Vdbe*)pStmt; + return v!=0 && v->magic==VDBE_MAGIC_RUN && v->pc>=0; +} + +/* +** Return a pointer to the next prepared statement after pStmt associated +** with database connection pDb. If pStmt is NULL, return the first +** prepared statement for the database connection. Return NULL if there +** are no more. +*/ +SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ + sqlite3_stmt *pNext; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(pDb) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(pDb->mutex); + if( pStmt==0 ){ + pNext = (sqlite3_stmt*)pDb->pVdbe; + }else{ + pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pNext; + } + sqlite3_mutex_leave(pDb->mutex); + return pNext; +} + +/* +** Return the value of a status counter for a prepared statement +*/ +SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ + Vdbe *pVdbe = (Vdbe*)pStmt; + u32 v; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !pStmt ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + v = pVdbe->aCounter[op]; + if( resetFlag ) pVdbe->aCounter[op] = 0; + return (int)v; +} + +/* +** Return the SQL associated with a prepared statement +*/ +SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + return p ? p->zSql : 0; +} + +/* +** Return the SQL associated with a prepared statement with +** bound parameters expanded. Space to hold the returned string is +** obtained from sqlite3_malloc(). The caller is responsible for +** freeing the returned string by passing it to sqlite3_free(). +** +** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of +** expanded bound parameters. +*/ +SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ +#ifdef SQLITE_OMIT_TRACE + return 0; +#else + char *z = 0; + const char *zSql = sqlite3_sql(pStmt); + if( zSql ){ + Vdbe *p = (Vdbe *)pStmt; + sqlite3_mutex_enter(p->db->mutex); + z = sqlite3VdbeExpandSql(p, zSql); + sqlite3_mutex_leave(p->db->mutex); + } + return z; +#endif +} + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** Allocate and populate an UnpackedRecord structure based on the serialized +** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure +** if successful, or a NULL pointer if an OOM error is encountered. +*/ +static UnpackedRecord *vdbeUnpackRecord( + KeyInfo *pKeyInfo, + int nKey, + const void *pKey +){ + UnpackedRecord *pRet; /* Return value */ + + pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( pRet ){ + memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1)); + sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet); + } + return pRet; +} + +/* +** This function is called from within a pre-update callback to retrieve +** a field of the row currently being updated or deleted. +*/ +SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ + PreUpdate *p = db->pPreUpdate; + Mem *pMem; + int rc = SQLITE_OK; + + /* Test that this call is being made from within an SQLITE_DELETE or + ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */ + if( !p || p->op==SQLITE_INSERT ){ + rc = SQLITE_MISUSE_BKPT; + goto preupdate_old_out; + } + if( p->pPk ){ + iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + } + if( iIdx>=p->pCsr->nField || iIdx<0 ){ + rc = SQLITE_RANGE; + goto preupdate_old_out; + } + + /* If the old.* record has not yet been loaded into memory, do so now. */ + if( p->pUnpacked==0 ){ + u32 nRec; + u8 *aRec; + + nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); + aRec = sqlite3DbMallocRaw(db, nRec); + if( !aRec ) goto preupdate_old_out; + rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); + if( rc==SQLITE_OK ){ + p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); + if( !p->pUnpacked ) rc = SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + sqlite3DbFree(db, aRec); + goto preupdate_old_out; + } + p->aRecord = aRec; + } + + pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; + if( iIdx==p->pTab->iPKey ){ + sqlite3VdbeMemSetInt64(pMem, p->iKey1); + }else if( iIdx>=p->pUnpacked->nField ){ + *ppValue = (sqlite3_value *)columnNullValue(); + }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ + if( pMem->flags & MEM_Int ){ + sqlite3VdbeMemRealify(pMem); + } + } + + preupdate_old_out: + sqlite3Error(db, rc); + return sqlite3ApiExit(db, rc); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is called from within a pre-update callback to retrieve +** the number of columns in the row being updated, deleted or inserted. +*/ +SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ + PreUpdate *p = db->pPreUpdate; + return (p ? p->keyinfo.nField : 0); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is designed to be called from within a pre-update callback +** only. It returns zero if the change that caused the callback was made +** immediately by a user SQL statement. Or, if the change was made by a +** trigger program, it returns the number of trigger programs currently +** on the stack (1 for a top-level trigger, 2 for a trigger fired by a +** top-level trigger etc.). +** +** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL +** or SET DEFAULT action is considered a trigger. +*/ +SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ + PreUpdate *p = db->pPreUpdate; + return (p ? p->v->nFrame : 0); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is called from within a pre-update callback to retrieve +** a field of the row currently being updated or inserted. +*/ +SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ + PreUpdate *p = db->pPreUpdate; + int rc = SQLITE_OK; + Mem *pMem; + + if( !p || p->op==SQLITE_DELETE ){ + rc = SQLITE_MISUSE_BKPT; + goto preupdate_new_out; + } + if( p->pPk && p->op!=SQLITE_UPDATE ){ + iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + } + if( iIdx>=p->pCsr->nField || iIdx<0 ){ + rc = SQLITE_RANGE; + goto preupdate_new_out; + } + + if( p->op==SQLITE_INSERT ){ + /* For an INSERT, memory cell p->iNewReg contains the serialized record + ** that is being inserted. Deserialize it. */ + UnpackedRecord *pUnpack = p->pNewUnpacked; + if( !pUnpack ){ + Mem *pData = &p->v->aMem[p->iNewReg]; + rc = ExpandBlob(pData); + if( rc!=SQLITE_OK ) goto preupdate_new_out; + pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z); + if( !pUnpack ){ + rc = SQLITE_NOMEM; + goto preupdate_new_out; + } + p->pNewUnpacked = pUnpack; + } + pMem = &pUnpack->aMem[iIdx]; + if( iIdx==p->pTab->iPKey ){ + sqlite3VdbeMemSetInt64(pMem, p->iKey2); + }else if( iIdx>=pUnpack->nField ){ + pMem = (sqlite3_value *)columnNullValue(); + } + }else{ + /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required + ** value. Make a copy of the cell contents and return a pointer to it. + ** It is not safe to return a pointer to the memory cell itself as the + ** caller may modify the value text encoding. + */ + assert( p->op==SQLITE_UPDATE ); + if( !p->aNew ){ + p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField); + if( !p->aNew ){ + rc = SQLITE_NOMEM; + goto preupdate_new_out; + } + } + assert( iIdx>=0 && iIdxpCsr->nField ); + pMem = &p->aNew[iIdx]; + if( pMem->flags==0 ){ + if( iIdx==p->pTab->iPKey ){ + sqlite3VdbeMemSetInt64(pMem, p->iKey2); + }else{ + rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]); + if( rc!=SQLITE_OK ) goto preupdate_new_out; + } + } + } + *ppValue = pMem; + + preupdate_new_out: + sqlite3Error(db, rc); + return sqlite3ApiExit(db, rc); +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +/* +** Return status data for a single loop within query pStmt. +*/ +SQLITE_API int sqlite3_stmt_scanstatus( + sqlite3_stmt *pStmt, /* Prepared statement being queried */ + int idx, /* Index of loop to report on */ + int iScanStatusOp, /* Which metric to return */ + void *pOut /* OUT: Write the answer here */ +){ + Vdbe *p = (Vdbe*)pStmt; + ScanStatus *pScan; + if( idx<0 || idx>=p->nScan ) return 1; + pScan = &p->aScan[idx]; + switch( iScanStatusOp ){ + case SQLITE_SCANSTAT_NLOOP: { + *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop]; + break; + } + case SQLITE_SCANSTAT_NVISIT: { + *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit]; + break; + } + case SQLITE_SCANSTAT_EST: { + double r = 1.0; + LogEst x = pScan->nEst; + while( x<100 ){ + x += 10; + r *= 0.5; + } + *(double*)pOut = r*sqlite3LogEstToInt(x); + break; + } + case SQLITE_SCANSTAT_NAME: { + *(const char**)pOut = pScan->zName; + break; + } + case SQLITE_SCANSTAT_EXPLAIN: { + if( pScan->addrExplain ){ + *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z; + }else{ + *(const char**)pOut = 0; + } + break; + } + case SQLITE_SCANSTAT_SELECTID: { + if( pScan->addrExplain ){ + *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; + }else{ + *(int*)pOut = -1; + } + break; + } + default: { + return 1; + } + } + return 0; +} + +/* +** Zero all counters associated with the sqlite3_stmt_scanstatus() data. +*/ +SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe*)pStmt; + memset(p->anExec, 0, p->nOp * sizeof(i64)); +} +#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ + +/************** End of vdbeapi.c *********************************************/ +/************** Begin file vdbetrace.c ***************************************/ +/* +** 2009 November 25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file contains code used to insert the values of host parameters +** (aka "wildcards") into the SQL text output by sqlite3_trace(). +** +** The Vdbe parse-tree explainer is also found here. +*/ +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +#ifndef SQLITE_OMIT_TRACE + +/* +** zSql is a zero-terminated string of UTF-8 SQL text. Return the number of +** bytes in this text up to but excluding the first character in +** a host parameter. If the text contains no host parameters, return +** the total number of bytes in the text. +*/ +static int findNextHostParameter(const char *zSql, int *pnToken){ + int tokenType; + int nTotal = 0; + int n; + + *pnToken = 0; + while( zSql[0] ){ + n = sqlite3GetToken((u8*)zSql, &tokenType); + assert( n>0 && tokenType!=TK_ILLEGAL ); + if( tokenType==TK_VARIABLE ){ + *pnToken = n; + break; + } + nTotal += n; + zSql += n; + } + return nTotal; +} + +/* +** This function returns a pointer to a nul-terminated string in memory +** obtained from sqlite3DbMalloc(). If sqlite3.nVdbeExec is 1, then the +** string contains a copy of zRawSql but with host parameters expanded to +** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1, +** then the returned string holds a copy of zRawSql with "-- " prepended +** to each line of text. +** +** If the SQLITE_TRACE_SIZE_LIMIT macro is defined to an integer, then +** then long strings and blobs are truncated to that many bytes. This +** can be used to prevent unreasonably large trace strings when dealing +** with large (multi-megabyte) strings and blobs. +** +** The calling function is responsible for making sure the memory returned +** is eventually freed. +** +** ALGORITHM: Scan the input string looking for host parameters in any of +** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within +** string literals, quoted identifier names, and comments. For text forms, +** the host parameter index is found by scanning the prepared +** statement for the corresponding OP_Variable opcode. Once the host +** parameter index is known, locate the value in p->aVar[]. Then render +** the value as a literal in place of the host parameter name. +*/ +SQLITE_PRIVATE char *sqlite3VdbeExpandSql( + Vdbe *p, /* The prepared statement being evaluated */ + const char *zRawSql /* Raw text of the SQL statement */ +){ + sqlite3 *db; /* The database connection */ + int idx = 0; /* Index of a host parameter */ + int nextIndex = 1; /* Index of next ? host parameter */ + int n; /* Length of a token prefix */ + int nToken; /* Length of the parameter token */ + int i; /* Loop counter */ + 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 */ +#endif + char zBase[100]; /* Initial working space */ + + db = p->db; + sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), + db->aLimit[SQLITE_LIMIT_LENGTH]); + if( db->nVdbeExec>1 ){ + while( *zRawSql ){ + const char *zStart = zRawSql; + while( *(zRawSql++)!='\n' && *zRawSql ); + sqlite3StrAccumAppend(&out, "-- ", 3); + assert( (zRawSql - zStart) > 0 ); + sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart)); + } + }else if( p->nVar==0 ){ + sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql)); + }else{ + while( zRawSql[0] ){ + n = findNextHostParameter(zRawSql, &nToken); + assert( n>0 ); + sqlite3StrAccumAppend(&out, zRawSql, n); + zRawSql += n; + assert( zRawSql[0] || nToken==0 ); + if( nToken==0 ) break; + if( zRawSql[0]=='?' ){ + if( nToken>1 ){ + assert( sqlite3Isdigit(zRawSql[1]) ); + sqlite3GetInt32(&zRawSql[1], &idx); + }else{ + idx = nextIndex; + } + }else{ + assert( zRawSql[0]==':' || zRawSql[0]=='$' || + zRawSql[0]=='@' || zRawSql[0]=='#' ); + testcase( zRawSql[0]==':' ); + testcase( zRawSql[0]=='$' ); + testcase( zRawSql[0]=='@' ); + testcase( zRawSql[0]=='#' ); + idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); + assert( idx>0 ); + } + zRawSql += nToken; + nextIndex = idx + 1; + assert( idx>0 && idx<=p->nVar ); + pVar = &p->aVar[idx-1]; + if( pVar->flags & MEM_Null ){ + sqlite3StrAccumAppend(&out, "NULL", 4); + }else if( pVar->flags & MEM_Int ){ + sqlite3XPrintf(&out, "%lld", pVar->u.i); + }else if( pVar->flags & MEM_Real ){ + sqlite3XPrintf(&out, "%!.15g", pVar->u.r); + }else if( pVar->flags & MEM_Str ){ + int nOut; /* Number of bytes of the string text to include in output */ +#ifndef SQLITE_OMIT_UTF16 + u8 enc = ENC(db); + if( enc!=SQLITE_UTF8 ){ + memset(&utf8, 0, sizeof(utf8)); + utf8.db = db; + sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); + if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){ + out.accError = STRACCUM_NOMEM; + out.nAlloc = 0; + } + pVar = &utf8; + } +#endif + nOut = pVar->n; +#ifdef SQLITE_TRACE_SIZE_LIMIT + if( nOut>SQLITE_TRACE_SIZE_LIMIT ){ + nOut = SQLITE_TRACE_SIZE_LIMIT; + while( nOutn && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; } + } +#endif + sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z); +#ifdef SQLITE_TRACE_SIZE_LIMIT + if( nOutn ){ + sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); + } +#endif +#ifndef SQLITE_OMIT_UTF16 + if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8); +#endif + }else if( pVar->flags & MEM_Zero ){ + sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero); + }else{ + int nOut; /* Number of bytes of the blob to include in output */ + assert( pVar->flags & MEM_Blob ); + sqlite3StrAccumAppend(&out, "x'", 2); + nOut = pVar->n; +#ifdef SQLITE_TRACE_SIZE_LIMIT + if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT; +#endif + for(i=0; iz[i]&0xff); + } + sqlite3StrAccumAppend(&out, "'", 1); +#ifdef SQLITE_TRACE_SIZE_LIMIT + if( nOutn ){ + sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); + } +#endif + } + } + } + if( out.accError ) sqlite3StrAccumReset(&out); + return sqlite3StrAccumFinish(&out); +} + +#endif /* #ifndef SQLITE_OMIT_TRACE */ + +/************** End of vdbetrace.c *******************************************/ +/************** Begin file vdbe.c ********************************************/ +/* +** 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. +** +************************************************************************* +** The code in this file implements the function that runs the +** bytecode of a prepared statement. +** +** Various scripts scan this source file in order to generate HTML +** documentation, headers files, or other derived files. The formatting +** of the code in this file is, therefore, important. See other comments +** in this file for details. If in doubt, do not deviate from existing +** commenting and indentation practices when changing or adding code. +*/ +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +/* +** Invoke this macro on memory cells just prior to changing the +** value of the cell. This macro verifies that shallow copies are +** not misused. A shallow copy of a string or blob just copies a +** pointer to the string or blob, not the content. If the original +** is changed while the copy is still in use, the string or blob might +** be changed out from under the copy. This macro verifies that nothing +** like that ever happens. +*/ +#ifdef SQLITE_DEBUG +# define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M) +#else +# define memAboutToChange(P,M) +#endif + +/* +** The following global variable is incremented every time a cursor +** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test +** procedures use this information to make sure that indices are +** working correctly. This variable has no function other than to +** help verify the correct operation of the library. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_search_count = 0; +#endif + +/* +** When this global variable is positive, it gets decremented once before +** each instruction in the VDBE. When it reaches zero, the u1.isInterrupted +** field of the sqlite3 structure is set in order to simulate an interrupt. +** +** This facility is used for testing purposes only. It does not function +** in an ordinary build. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_interrupt_count = 0; +#endif + +/* +** The next global variable is incremented each type the OP_Sort opcode +** is executed. The test procedures use this information to make sure that +** sorting is occurring or not occurring at appropriate times. This variable +** has no function other than to help verify the correct operation of the +** library. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_sort_count = 0; +#endif + +/* +** The next global variable records the size of the largest MEM_Blob +** or MEM_Str that has been used by a VDBE opcode. The test procedures +** use this information to make sure that the zero-blob functionality +** is working correctly. This variable has no function other than to +** help verify the correct operation of the library. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_max_blobsize = 0; +static void updateMaxBlobsize(Mem *p){ + if( (p->flags & (MEM_Str|MEM_Blob))!=0 && p->n>sqlite3_max_blobsize ){ + sqlite3_max_blobsize = p->n; + } +} +#endif + +/* +** This macro evaluates to true if either the update hook or the preupdate +** hook are enabled for database connect DB. +*/ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +# define HAS_UPDATE_HOOK(DB) ((DB)->xPreUpdateCallback||(DB)->xUpdateCallback) +#else +# define HAS_UPDATE_HOOK(DB) ((DB)->xUpdateCallback) +#endif + +/* +** The next global variable is incremented each time the OP_Found opcode +** is executed. This is used to test whether or not the foreign key +** operation implemented using OP_FkIsZero is working. This variable +** has no function other than to help verify the correct operation of the +** library. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_found_count = 0; +#endif + +/* +** Test a register to see if it exceeds the current maximum blob size. +** If it does, record the new maximum blob size. +*/ +#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE) +# define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) +#else +# define UPDATE_MAX_BLOBSIZE(P) +#endif + +/* +** Invoke the VDBE coverage callback, if that callback is defined. This +** feature is used for test suite validation only and does not appear an +** production builds. +** +** M is an integer, 2 or 3, that indices how many different ways the +** branch can go. It is usually 2. "I" is the direction the branch +** goes. 0 means falls through. 1 means branch is taken. 2 means the +** second alternative branch is taken. +** +** iSrcLine is the source code line (from the __LINE__ macro) that +** generated the VDBE instruction. This instrumentation assumes that all +** source code is in a single file (the amalgamation). Special values 1 +** and 2 for the iSrcLine parameter mean that this particular branch is +** always taken or never taken, respectively. +*/ +#if !defined(SQLITE_VDBE_COVERAGE) +# define VdbeBranchTaken(I,M) +#else +# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M) + static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){ + if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){ + M = iSrcLine; + /* Assert the truth of VdbeCoverageAlwaysTaken() and + ** VdbeCoverageNeverTaken() */ + assert( (M & I)==I ); + }else{ + if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ + sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, + iSrcLine,I,M); + } + } +#endif + +/* +** Convert the given register into a string if it isn't one +** already. Return non-zero if a malloc() fails. +*/ +#define Stringify(P, enc) \ + if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ + { goto no_mem; } + +/* +** An ephemeral string value (signified by the MEM_Ephem flag) contains +** a pointer to a dynamically allocated string where some other entity +** is responsible for deallocating that string. Because the register +** does not control the string, it might be deleted without the register +** knowing it. +** +** This routine converts an ephemeral string into a dynamically allocated +** string that the register itself controls. In other words, it +** converts an MEM_Ephem string into a string with P.z==P.zMalloc. +*/ +#define Deephemeralize(P) \ + if( ((P)->flags&MEM_Ephem)!=0 \ + && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} + +/* Return true if the cursor was opened using the OP_OpenSorter opcode. */ +#define isSorter(x) ((x)->eCurType==CURTYPE_SORTER) + +/* +** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL +** if we run out of memory. +*/ +static VdbeCursor *allocateCursor( + Vdbe *p, /* The virtual machine */ + int iCur, /* Index of the new VdbeCursor */ + int nField, /* Number of fields in the table or index */ + int iDb, /* Database the cursor belongs to, or -1 */ + u8 eCurType /* Type of the new cursor */ +){ + /* Find the memory cell that will be used to store the blob of memory + ** required for this VdbeCursor structure. It is convenient to use a + ** vdbe memory cell to manage the memory allocation required for a + ** VdbeCursor structure for the following reasons: + ** + ** * Sometimes cursor numbers are used for a couple of different + ** purposes in a vdbe program. The different uses might require + ** different sized allocations. Memory cells provide growable + ** allocations. + ** + ** * When using ENABLE_MEMORY_MANAGEMENT, memory cell buffers can + ** be freed lazily via the sqlite3_release_memory() API. This + ** minimizes the number of malloc calls made by the system. + ** + ** The memory cell for cursor 0 is aMem[0]. The rest are allocated from + ** the top of the register space. Cursor 1 is at Mem[p->nMem-1]. + ** Cursor 2 is at Mem[p->nMem-2]. And so forth. + */ + Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; + + int nByte; + VdbeCursor *pCx = 0; + nByte = + ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + + (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); + + assert( iCur>=0 && iCurnCursor ); + if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ + sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); + p->apCsr[iCur] = 0; + } + if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ + p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; + memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); + pCx->eCurType = eCurType; + pCx->iDb = iDb; + pCx->nField = nField; + pCx->aOffset = &pCx->aType[nField]; + if( eCurType==CURTYPE_BTREE ){ + pCx->uc.pCursor = (BtCursor*) + &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; + sqlite3BtreeCursorZero(pCx->uc.pCursor); + } + } + return pCx; +} + +/* +** Try to convert a value into a numeric representation if we can +** do so without loss of information. In other words, if the string +** looks like a number, convert it into a number. If it does not +** look like a number, leave it alone. +** +** If the bTryForInt flag is true, then extra effort is made to give +** an integer representation. Strings that look like floating point +** values but which have no fractional component (example: '48.00') +** will have a MEM_Int representation when bTryForInt is true. +** +** If bTryForInt is false, then if the input string contains a decimal +** point or exponential notation, the result is only MEM_Real, even +** if there is an exact integer representation of the quantity. +*/ +static void applyNumericAffinity(Mem *pRec, int bTryForInt){ + double rValue; + i64 iValue; + u8 enc = pRec->enc; + assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); + if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; + if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ + pRec->u.i = iValue; + pRec->flags |= MEM_Int; + }else{ + pRec->u.r = rValue; + pRec->flags |= MEM_Real; + if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); + } +} + +/* +** Processing is determine by the affinity parameter: +** +** SQLITE_AFF_INTEGER: +** SQLITE_AFF_REAL: +** SQLITE_AFF_NUMERIC: +** Try to convert pRec to an integer representation or a +** floating-point representation if an integer representation +** is not possible. Note that the integer representation is +** always preferred, even if the affinity is REAL, because +** an integer representation is more space efficient on disk. +** +** SQLITE_AFF_TEXT: +** Convert pRec to a text representation. +** +** SQLITE_AFF_BLOB: +** No-op. pRec is unchanged. +*/ +static void applyAffinity( + Mem *pRec, /* The value to apply affinity to */ + char affinity, /* The affinity to be applied */ + u8 enc /* Use this text encoding */ +){ + if( affinity>=SQLITE_AFF_NUMERIC ){ + assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL + || affinity==SQLITE_AFF_NUMERIC ); + if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/ + if( (pRec->flags & MEM_Real)==0 ){ + if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); + }else{ + sqlite3VdbeIntegerAffinity(pRec); + } + } + }else if( affinity==SQLITE_AFF_TEXT ){ + /* Only attempt the conversion to TEXT if there is an integer or real + ** representation (blob and NULL do not get converted) but no string + ** representation. It would be harmless to repeat the conversion if + ** there is already a string rep, but it is pointless to waste those + ** CPU cycles. */ + if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ + if( (pRec->flags&(MEM_Real|MEM_Int)) ){ + sqlite3VdbeMemStringify(pRec, enc, 1); + } + } + pRec->flags &= ~(MEM_Real|MEM_Int); + } +} + +/* +** Try to convert the type of a function argument or a result column +** into a numeric representation. Use either INTEGER or REAL whichever +** is appropriate. But only do the conversion if it is possible without +** loss of information and return the revised type of the argument. +*/ +SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ + int eType = sqlite3_value_type(pVal); + if( eType==SQLITE_TEXT ){ + Mem *pMem = (Mem*)pVal; + applyNumericAffinity(pMem, 0); + eType = sqlite3_value_type(pVal); + } + return eType; +} + +/* +** Exported version of applyAffinity(). This one works on sqlite3_value*, +** not the internal Mem* type. +*/ +SQLITE_PRIVATE void sqlite3ValueApplyAffinity( + sqlite3_value *pVal, + u8 affinity, + u8 enc +){ + applyAffinity((Mem *)pVal, affinity, enc); +} + +/* +** pMem currently only holds a string type (or maybe a BLOB that we can +** interpret as a string if we want to). Compute its corresponding +** numeric type, if has one. Set the pMem->u.r and pMem->u.i fields +** accordingly. +*/ +static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ + assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); + assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); + 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 ){ + return MEM_Int; + } + return MEM_Real; +} + +/* +** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or +** none. +** +** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. +** But it does set pMem->u.r and pMem->u.i appropriately. +*/ +static u16 numericType(Mem *pMem){ + if( pMem->flags & (MEM_Int|MEM_Real) ){ + return pMem->flags & (MEM_Int|MEM_Real); + } + if( pMem->flags & (MEM_Str|MEM_Blob) ){ + return computeNumericType(pMem); + } + return 0; +} + +#ifdef SQLITE_DEBUG +/* +** Write a nice string representation of the contents of cell pMem +** into buffer zBuf, length nBuf. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ + char *zCsr = zBuf; + int f = pMem->flags; + + static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"}; + + if( f&MEM_Blob ){ + int i; + char c; + if( f & MEM_Dyn ){ + c = 'z'; + assert( (f & (MEM_Static|MEM_Ephem))==0 ); + }else if( f & MEM_Static ){ + c = 't'; + assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); + }else if( f & MEM_Ephem ){ + c = 'e'; + assert( (f & (MEM_Static|MEM_Dyn))==0 ); + }else{ + c = 's'; + } + *(zCsr++) = c; + sqlite3_snprintf(100, zCsr, "%d[", pMem->n); + zCsr += sqlite3Strlen30(zCsr); + for(i=0; i<16 && in; i++){ + sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF)); + zCsr += sqlite3Strlen30(zCsr); + } + for(i=0; i<16 && in; i++){ + char z = pMem->z[i]; + if( z<32 || z>126 ) *zCsr++ = '.'; + else *zCsr++ = z; + } + *(zCsr++) = ']'; + if( f & MEM_Zero ){ + sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero); + zCsr += sqlite3Strlen30(zCsr); + } + *zCsr = '\0'; + }else if( f & MEM_Str ){ + int j, k; + zBuf[0] = ' '; + if( f & MEM_Dyn ){ + zBuf[1] = 'z'; + assert( (f & (MEM_Static|MEM_Ephem))==0 ); + }else if( f & MEM_Static ){ + zBuf[1] = 't'; + assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); + }else if( f & MEM_Ephem ){ + zBuf[1] = 'e'; + assert( (f & (MEM_Static|MEM_Dyn))==0 ); + }else{ + zBuf[1] = 's'; + } + k = 2; + sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n); + k += sqlite3Strlen30(&zBuf[k]); + zBuf[k++] = '['; + for(j=0; j<15 && jn; j++){ + u8 c = pMem->z[j]; + if( c>=0x20 && c<0x7f ){ + zBuf[k++] = c; + }else{ + zBuf[k++] = '.'; + } + } + zBuf[k++] = ']'; + sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]); + k += sqlite3Strlen30(&zBuf[k]); + zBuf[k++] = 0; + } +} +#endif + +#ifdef SQLITE_DEBUG +/* +** Print the value of a register for tracing purposes: +*/ +static void memTracePrint(Mem *p){ + if( p->flags & MEM_Undefined ){ + printf(" undefined"); + }else if( p->flags & MEM_Null ){ + printf(" NULL"); + }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ + printf(" si:%lld", p->u.i); + }else if( p->flags & MEM_Int ){ + printf(" i:%lld", p->u.i); +#ifndef SQLITE_OMIT_FLOATING_POINT + }else if( p->flags & MEM_Real ){ + printf(" r:%g", p->u.r); +#endif + }else if( p->flags & MEM_RowSet ){ + printf(" (rowset)"); + }else{ + char zBuf[200]; + sqlite3VdbeMemPrettyPrint(p, zBuf); + printf(" %s", zBuf); + } + if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype); +} +static void registerTrace(int iReg, Mem *p){ + printf("REG[%d] = ", iReg); + memTracePrint(p); + printf("\n"); + sqlite3VdbeCheckMemInvariants(p); +} +#endif + +#ifdef SQLITE_DEBUG +# define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M) +#else +# define REGISTER_TRACE(R,M) +#endif + + +#ifdef VDBE_PROFILE + +/* +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. +*/ +/************** Include hwtime.h in the middle of vdbe.c *********************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 class CPUs. +*/ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H + +/* +** The following routine only works on pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } + +#elif (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + #error Need implementation of sqlite3Hwtime() for your platform. + + /* + ** To compile without implementing sqlite3Hwtime() for your platform, + ** you can remove the above #error and use the following + ** stub function. You will lose timing support for many + ** of the debugging and testing utilities, but it should at + ** least compile and run. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in vdbe.c ***********************/ + +#endif + +#ifndef NDEBUG +/* +** This function is only called from within an assert() expression. It +** checks that the sqlite3.nTransaction variable is correctly set to +** the number of non-transaction savepoints currently in the +** linked list starting at sqlite3.pSavepoint. +** +** Usage: +** +** assert( checkSavepointCount(db) ); +*/ +static int checkSavepointCount(sqlite3 *db){ + int n = 0; + Savepoint *p; + for(p=db->pSavepoint; p; p=p->pNext) n++; + assert( n==(db->nSavepoint + db->isTransactionSavepoint) ); + return 1; +} +#endif + +/* +** Return the register of pOp->p2 after first preparing it to be +** overwritten with an integer value. +*/ +static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){ + sqlite3VdbeMemSetNull(pOut); + pOut->flags = MEM_Int; + return pOut; +} +static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ + Mem *pOut; + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); + pOut = &p->aMem[pOp->p2]; + memAboutToChange(p, pOut); + if( VdbeMemDynamic(pOut) ){ /*OPTIMIZATION-IF-FALSE*/ + return out2PrereleaseWithClear(pOut); + }else{ + pOut->flags = MEM_Int; + return pOut; + } +} + + +/* +** Execute as much of a VDBE program as we can. +** This is the core of sqlite3_step(). +*/ +SQLITE_PRIVATE int sqlite3VdbeExec( + Vdbe *p /* The VDBE */ +){ + Op *aOp = p->aOp; /* Copy of p->aOp */ + Op *pOp = aOp; /* Current operation */ +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + Op *pOrigOp; /* Value of pOp at the top of the loop */ +#endif +#ifdef SQLITE_DEBUG + int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ +#endif + int rc = SQLITE_OK; /* Value to return */ + sqlite3 *db = p->db; /* The database */ + u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ + u8 encoding = ENC(db); /* The database encoding */ + int iCompare = 0; /* Result of last comparison */ + unsigned nVmStep = 0; /* Number of virtual machine steps */ +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */ +#endif + Mem *aMem = p->aMem; /* Copy of p->aMem */ + Mem *pIn1 = 0; /* 1st input operand */ + Mem *pIn2 = 0; /* 2nd input operand */ + Mem *pIn3 = 0; /* 3rd input operand */ + Mem *pOut = 0; /* Output operand */ +#ifdef VDBE_PROFILE + u64 start; /* CPU clock count at start of opcode */ +#endif + /*** INSERT STACK UNION HERE ***/ + + assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ + sqlite3VdbeEnter(p); + if( p->rc==SQLITE_NOMEM ){ + /* This happens if a malloc() inside a call to sqlite3_column_text() or + ** sqlite3_column_text16() failed. */ + goto no_mem; + } + assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY ); + assert( p->bIsReader || p->readOnly!=0 ); + p->iCurrentTime = 0; + assert( p->explain==0 ); + p->pResultSet = 0; + db->busyHandler.nBusy = 0; + if( db->u1.isInterrupted ) goto abort_due_to_interrupt; + sqlite3VdbeIOTraceSql(p); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + if( db->xProgress ){ + u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; + assert( 0 < db->nProgressOps ); + nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); + } +#endif +#ifdef SQLITE_DEBUG + sqlite3BeginBenignMalloc(); + if( p->pc==0 + && (p->db->flags & (SQLITE_VdbeListing|SQLITE_VdbeEQP|SQLITE_VdbeTrace))!=0 + ){ + int i; + int once = 1; + sqlite3VdbePrintSql(p); + if( p->db->flags & SQLITE_VdbeListing ){ + printf("VDBE Program Listing:\n"); + for(i=0; inOp; i++){ + sqlite3VdbePrintOp(stdout, i, &aOp[i]); + } + } + if( p->db->flags & SQLITE_VdbeEQP ){ + for(i=0; inOp; i++){ + if( aOp[i].opcode==OP_Explain ){ + if( once ) printf("VDBE Query Plan:\n"); + printf("%s\n", aOp[i].p4.z); + once = 0; + } + } + } + if( p->db->flags & SQLITE_VdbeTrace ) printf("VDBE Trace:\n"); + } + sqlite3EndBenignMalloc(); +#endif + for(pOp=&aOp[p->pc]; 1; pOp++){ + /* Errors are detected by individual opcodes, with an immediate + ** jumps to abort_due_to_error. */ + assert( rc==SQLITE_OK ); + + assert( pOp>=aOp && pOp<&aOp[p->nOp]); +#ifdef VDBE_PROFILE + start = sqlite3Hwtime(); +#endif + nVmStep++; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + if( p->anExec ) p->anExec[(int)(pOp-aOp)]++; +#endif + + /* Only allow tracing if SQLITE_DEBUG is defined. + */ +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_VdbeTrace ){ + sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp); + } +#endif + + + /* Check to see if we need to simulate an interrupt. This only happens + ** if we have a special test build. + */ +#ifdef SQLITE_TEST + if( sqlite3_interrupt_count>0 ){ + sqlite3_interrupt_count--; + if( sqlite3_interrupt_count==0 ){ + sqlite3_interrupt(db); + } + } +#endif + + /* Sanity checking on other operands */ +#ifdef SQLITE_DEBUG + { + u8 opProperty = sqlite3OpcodeProperty[pOp->opcode]; + if( (opProperty & OPFLG_IN1)!=0 ){ + assert( pOp->p1>0 ); + assert( pOp->p1<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p1]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); + REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); + } + if( (opProperty & OPFLG_IN2)!=0 ){ + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p2]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); + REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); + } + if( (opProperty & OPFLG_IN3)!=0 ){ + assert( pOp->p3>0 ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p3]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); + REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); + } + if( (opProperty & OPFLG_OUT2)!=0 ){ + assert( pOp->p2>0 ); + assert( pOp->p2<=(p->nMem+1 - p->nCursor) ); + memAboutToChange(p, &aMem[pOp->p2]); + } + if( (opProperty & OPFLG_OUT3)!=0 ){ + assert( pOp->p3>0 ); + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + memAboutToChange(p, &aMem[pOp->p3]); + } + } +#endif +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + pOrigOp = pOp; +#endif + + switch( pOp->opcode ){ + +/***************************************************************************** +** What follows is a massive switch statement where each case implements a +** separate instruction in the virtual machine. If we follow the usual +** indentation conventions, each case should be indented by 6 spaces. But +** that is a lot of wasted space on the left margin. So the code within +** the switch statement will break with convention and be flush-left. Another +** big comment (similar to this one) will mark the point in the code where +** we transition back to normal indentation. +** +** The formatting of each case is important. The makefile for SQLite +** generates two C files "opcodes.h" and "opcodes.c" by scanning this +** file looking for lines that begin with "case OP_". The opcodes.h files +** will be filled with #defines that give unique integer values to each +** opcode and the opcodes.c file is filled with an array of strings where +** each string is the symbolic name for the corresponding opcode. If the +** case statement is followed by a comment of the form "/# same as ... #/" +** that comment is used to determine the particular value of the opcode. +** +** Other keywords in the comment that follows each case are used to +** construct the OPFLG_INITIALIZER value that initializes opcodeProperty[]. +** Keywords include: in1, in2, in3, out2, out3. See +** the mkopcodeh.awk script for additional information. +** +** Documentation about VDBE opcodes is generated by scanning this file +** for lines of that contain "Opcode:". That line and all subsequent +** comment lines are used in the generation of the opcode.html documentation +** file. +** +** SUMMARY: +** +** Formatting is important to scripts that scan this file. +** Do not deviate from the formatting style currently in use. +** +*****************************************************************************/ + +/* Opcode: Goto * P2 * * * +** +** An unconditional jump to address P2. +** The next instruction executed will be +** the one at index P2 from the beginning of +** the program. +** +** The P1 parameter is not actually used by this opcode. However, it +** is sometimes set to 1 instead of 0 as a hint to the command-line shell +** that this Goto is the bottom of a loop and that the lines from P2 down +** to the current line should be indented for EXPLAIN output. +*/ +case OP_Goto: { /* jump */ +jump_to_p2_and_check_for_interrupt: + pOp = &aOp[pOp->p2 - 1]; + + /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, + ** OP_VNext, or OP_SorterNext) all jump here upon + ** completion. Check to see if sqlite3_interrupt() has been called + ** or if the progress callback needs to be invoked. + ** + ** This code uses unstructured "goto" statements and does not look clean. + ** But that is not due to sloppy coding habits. The code is written this + ** way for performance, to avoid having to run the interrupt and progress + ** checks on every opcode. This helps sqlite3_step() to run about 1.5% + ** faster according to "valgrind --tool=cachegrind" */ +check_for_interrupt: + if( db->u1.isInterrupted ) goto abort_due_to_interrupt; +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + /* Call the progress callback if it is configured and the required number + ** of VDBE ops have been executed (either since this invocation of + ** sqlite3VdbeExec() or since last time the progress callback was called). + ** If the progress callback returns non-zero, exit the virtual machine with + ** a return code SQLITE_ABORT. + */ + if( db->xProgress!=0 && nVmStep>=nProgressLimit ){ + assert( db->nProgressOps!=0 ); + nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); + if( db->xProgress(db->pProgressArg) ){ + rc = SQLITE_INTERRUPT; + goto abort_due_to_error; + } + } +#endif + + break; +} + +/* Opcode: Gosub P1 P2 * * * +** +** Write the current address onto register P1 +** and then jump to address P2. +*/ +case OP_Gosub: { /* jump */ + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + pIn1 = &aMem[pOp->p1]; + assert( VdbeMemDynamic(pIn1)==0 ); + memAboutToChange(p, pIn1); + pIn1->flags = MEM_Int; + pIn1->u.i = (int)(pOp-aOp); + REGISTER_TRACE(pOp->p1, pIn1); + + /* Most jump operations do a goto to this spot in order to update + ** the pOp pointer. */ +jump_to_p2: + pOp = &aOp[pOp->p2 - 1]; + break; +} + +/* Opcode: Return P1 * * * * +** +** Jump to the next instruction after the address in register P1. After +** the jump, register P1 becomes undefined. +*/ +case OP_Return: { /* in1 */ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags==MEM_Int ); + pOp = &aOp[pIn1->u.i]; + pIn1->flags = MEM_Undefined; + break; +} + +/* Opcode: InitCoroutine P1 P2 P3 * * +** +** Set up register P1 so that it will Yield to the coroutine +** located at address P3. +** +** If P2!=0 then the coroutine implementation immediately follows +** this opcode. So jump over the coroutine implementation to +** address P2. +** +** See also: EndCoroutine +*/ +case OP_InitCoroutine: { /* jump */ + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + assert( pOp->p2>=0 && pOp->p2nOp ); + assert( pOp->p3>=0 && pOp->p3nOp ); + pOut = &aMem[pOp->p1]; + assert( !VdbeMemDynamic(pOut) ); + pOut->u.i = pOp->p3 - 1; + pOut->flags = MEM_Int; + if( pOp->p2 ) goto jump_to_p2; + break; +} + +/* Opcode: EndCoroutine P1 * * * * +** +** The instruction at the address in register P1 is a Yield. +** Jump to the P2 parameter of that Yield. +** After the jump, register P1 becomes undefined. +** +** See also: InitCoroutine +*/ +case OP_EndCoroutine: { /* in1 */ + VdbeOp *pCaller; + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags==MEM_Int ); + assert( pIn1->u.i>=0 && pIn1->u.inOp ); + pCaller = &aOp[pIn1->u.i]; + assert( pCaller->opcode==OP_Yield ); + assert( pCaller->p2>=0 && pCaller->p2nOp ); + pOp = &aOp[pCaller->p2 - 1]; + pIn1->flags = MEM_Undefined; + break; +} + +/* Opcode: Yield P1 P2 * * * +** +** Swap the program counter with the value in register P1. This +** has the effect of yielding to a coroutine. +** +** If the coroutine that is launched by this instruction ends with +** Yield or Return then continue to the next instruction. But if +** the coroutine launched by this instruction ends with +** EndCoroutine, then jump to P2 rather than continuing with the +** next instruction. +** +** See also: InitCoroutine +*/ +case OP_Yield: { /* in1, jump */ + int pcDest; + pIn1 = &aMem[pOp->p1]; + assert( VdbeMemDynamic(pIn1)==0 ); + pIn1->flags = MEM_Int; + pcDest = (int)pIn1->u.i; + pIn1->u.i = (int)(pOp - aOp); + REGISTER_TRACE(pOp->p1, pIn1); + pOp = &aOp[pcDest]; + break; +} + +/* Opcode: HaltIfNull P1 P2 P3 P4 P5 +** Synopsis: if r[P3]=null halt +** +** Check the value in register P3. If it is NULL then Halt using +** parameter P1, P2, and P4 as if this were a Halt instruction. If the +** value in register P3 is not NULL, then this routine is a no-op. +** The P5 parameter should be 1. +*/ +case OP_HaltIfNull: { /* in3 */ + pIn3 = &aMem[pOp->p3]; + if( (pIn3->flags & MEM_Null)==0 ) break; + /* Fall through into OP_Halt */ +} + +/* Opcode: Halt P1 P2 * P4 P5 +** +** Exit immediately. All open cursors, etc are closed +** automatically. +** +** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(), +** or sqlite3_finalize(). For a normal halt, this should be SQLITE_OK (0). +** For errors, it can be some other value. If P1!=0 then P2 will determine +** whether or not to rollback the current transaction. Do not rollback +** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort, +** then back out all changes that have occurred during this execution of the +** VDBE, but do not rollback the transaction. +** +** If P4 is not null then it is an error message string. +** +** P5 is a value between 0 and 4, inclusive, that modifies the P4 string. +** +** 0: (no change) +** 1: NOT NULL contraint failed: P4 +** 2: UNIQUE constraint failed: P4 +** 3: CHECK constraint failed: P4 +** 4: FOREIGN KEY constraint failed: P4 +** +** If P5 is not zero and P4 is NULL, then everything after the ":" is +** omitted. +** +** There is an implied "Halt 0 0 0" instruction inserted at the very end of +** every program. So a jump past the last instruction of the program +** is the same as executing Halt. +*/ +case OP_Halt: { + VdbeFrame *pFrame; + int pcx; + + pcx = (int)(pOp - aOp); + if( pOp->p1==SQLITE_OK && p->pFrame ){ + /* Halt the sub-program. Return control to the parent frame. */ + pFrame = p->pFrame; + p->pFrame = pFrame->pParent; + p->nFrame--; + sqlite3VdbeSetChanges(db, p->nChange); + pcx = sqlite3VdbeFrameRestore(pFrame); + if( pOp->p2==OE_Ignore ){ + /* Instruction pcx is the OP_Program that invoked the sub-program + ** currently being halted. If the p2 instruction of this OP_Halt + ** instruction is set to OE_Ignore, then the sub-program is throwing + ** an IGNORE exception. In this case jump to the address specified + ** as the p2 of the calling OP_Program. */ + pcx = p->aOp[pcx].p2-1; + } + aOp = p->aOp; + aMem = p->aMem; + pOp = &aOp[pcx]; + break; + } + p->rc = pOp->p1; + p->errorAction = (u8)pOp->p2; + p->pc = pcx; + assert( pOp->p5<=4 ); + if( p->rc ){ + if( pOp->p5 ){ + static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", + "FOREIGN KEY" }; + testcase( pOp->p5==1 ); + testcase( pOp->p5==2 ); + testcase( pOp->p5==3 ); + testcase( pOp->p5==4 ); + sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]); + if( pOp->p4.z ){ + p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z); + } + }else{ + sqlite3VdbeError(p, "%s", pOp->p4.z); + } + sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); + } + rc = sqlite3VdbeHalt(p); + assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); + if( rc==SQLITE_BUSY ){ + p->rc = SQLITE_BUSY; + }else{ + assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ); + assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 ); + rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; + } + goto vdbe_return; +} + +/* Opcode: Integer P1 P2 * * * +** Synopsis: r[P2]=P1 +** +** The 32-bit integer value P1 is written into register P2. +*/ +case OP_Integer: { /* out2 */ + pOut = out2Prerelease(p, pOp); + pOut->u.i = pOp->p1; + break; +} + +/* Opcode: Int64 * P2 * P4 * +** Synopsis: r[P2]=P4 +** +** P4 is a pointer to a 64-bit integer value. +** Write that value into register P2. +*/ +case OP_Int64: { /* out2 */ + pOut = out2Prerelease(p, pOp); + assert( pOp->p4.pI64!=0 ); + pOut->u.i = *pOp->p4.pI64; + break; +} + +#ifndef SQLITE_OMIT_FLOATING_POINT +/* Opcode: Real * P2 * P4 * +** Synopsis: r[P2]=P4 +** +** P4 is a pointer to a 64-bit floating point value. +** Write that value into register P2. +*/ +case OP_Real: { /* same as TK_FLOAT, out2 */ + pOut = out2Prerelease(p, pOp); + pOut->flags = MEM_Real; + assert( !sqlite3IsNaN(*pOp->p4.pReal) ); + pOut->u.r = *pOp->p4.pReal; + break; +} +#endif + +/* Opcode: String8 * P2 * P4 * +** Synopsis: r[P2]='P4' +** +** P4 points to a nul terminated UTF-8 string. This opcode is transformed +** into a String opcode before it is executed for the first time. During +** this transformation, the length of string P4 is computed and stored +** as the P1 parameter. +*/ +case OP_String8: { /* same as TK_STRING, out2 */ + assert( pOp->p4.z!=0 ); + pOut = out2Prerelease(p, pOp); + pOp->opcode = OP_String; + pOp->p1 = sqlite3Strlen30(pOp->p4.z); + +#ifndef SQLITE_OMIT_UTF16 + if( encoding!=SQLITE_UTF8 ){ + rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); + assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); + if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; + assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); + assert( VdbeMemDynamic(pOut)==0 ); + pOut->szMalloc = 0; + pOut->flags |= MEM_Static; + if( pOp->p4type==P4_DYNAMIC ){ + sqlite3DbFree(db, pOp->p4.z); + } + pOp->p4type = P4_DYNAMIC; + pOp->p4.z = pOut->z; + pOp->p1 = pOut->n; + } + testcase( rc==SQLITE_TOOBIG ); +#endif + if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; + } + assert( rc==SQLITE_OK ); + /* Fall through to the next case, OP_String */ +} + +/* Opcode: String P1 P2 P3 P4 P5 +** Synopsis: r[P2]='P4' (len=P1) +** +** The string value P4 of length P1 (bytes) is stored in register P2. +** +** If P3 is not zero and the content of register P3 is equal to P5, then +** the datatype of the register P2 is converted to BLOB. The content is +** the same sequence of bytes, it is merely interpreted as a BLOB instead +** of a string, as if it had been CAST. In other words: +** +** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB) +*/ +case OP_String: { /* out2 */ + assert( pOp->p4.z!=0 ); + pOut = out2Prerelease(p, pOp); + pOut->flags = MEM_Str|MEM_Static|MEM_Term; + pOut->z = pOp->p4.z; + pOut->n = pOp->p1; + pOut->enc = encoding; + UPDATE_MAX_BLOBSIZE(pOut); +#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS + if( pOp->p3>0 ){ + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + pIn3 = &aMem[pOp->p3]; + assert( pIn3->flags & MEM_Int ); + if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; + } +#endif + break; +} + +/* Opcode: Null P1 P2 P3 * * +** Synopsis: r[P2..P3]=NULL +** +** Write a NULL into registers P2. If P3 greater than P2, then also write +** NULL into register P3 and every register in between P2 and P3. If P3 +** is less than P2 (typically P3 is zero) then only register P2 is +** set to NULL. +** +** If the P1 value is non-zero, then also set the MEM_Cleared flag so that +** NULL values will not compare equal even if SQLITE_NULLEQ is set on +** OP_Ne or OP_Eq. +*/ +case OP_Null: { /* out2 */ + int cnt; + u16 nullFlag; + pOut = out2Prerelease(p, pOp); + cnt = pOp->p3-pOp->p2; + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; + pOut->n = 0; + while( cnt>0 ){ + pOut++; + memAboutToChange(p, pOut); + sqlite3VdbeMemSetNull(pOut); + pOut->flags = nullFlag; + pOut->n = 0; + cnt--; + } + break; +} + +/* Opcode: SoftNull P1 * * * * +** Synopsis: r[P1]=NULL +** +** Set register P1 to have the value NULL as seen by the OP_MakeRecord +** instruction, but do not free any string or blob memory associated with +** the register, so that if the value was a string or blob that was +** previously copied using OP_SCopy, the copies will continue to be valid. +*/ +case OP_SoftNull: { + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + pOut = &aMem[pOp->p1]; + pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null; + break; +} + +/* Opcode: Blob P1 P2 * P4 * +** Synopsis: r[P2]=P4 (len=P1) +** +** P4 points to a blob of data P1 bytes long. Store this +** blob in register P2. +*/ +case OP_Blob: { /* out2 */ + assert( pOp->p1 <= SQLITE_MAX_LENGTH ); + pOut = out2Prerelease(p, pOp); + sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0); + pOut->enc = encoding; + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + +/* Opcode: Variable P1 P2 * P4 * +** Synopsis: r[P2]=parameter(P1,P4) +** +** Transfer the values of bound parameter P1 into register P2 +** +** If the parameter is named, then its name appears in P4. +** The P4 value is used by sqlite3_bind_parameter_name(). +*/ +case OP_Variable: { /* out2 */ + Mem *pVar; /* Value being transferred */ + + assert( pOp->p1>0 && pOp->p1<=p->nVar ); + assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); + pVar = &p->aVar[pOp->p1 - 1]; + if( sqlite3VdbeMemTooBig(pVar) ){ + goto too_big; + } + pOut = &aMem[pOp->p2]; + sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static); + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + +/* Opcode: Move P1 P2 P3 * * +** Synopsis: r[P2@P3]=r[P1@P3] +** +** Move the P3 values in register P1..P1+P3-1 over into +** registers P2..P2+P3-1. Registers P1..P1+P3-1 are +** left holding a NULL. It is an error for register ranges +** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error +** for P3 to be less than 1. +*/ +case OP_Move: { + int n; /* Number of registers left to copy */ + int p1; /* Register to copy from */ + int p2; /* Register to copy to */ + + n = pOp->p3; + p1 = pOp->p1; + p2 = pOp->p2; + assert( n>0 && p1>0 && p2>0 ); + assert( p1+n<=p2 || p2+n<=p1 ); + + pIn1 = &aMem[p1]; + pOut = &aMem[p2]; + do{ + assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] ); + assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] ); + assert( memIsValid(pIn1) ); + memAboutToChange(p, pOut); + sqlite3VdbeMemMove(pOut, pIn1); +#ifdef SQLITE_DEBUG + if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrompScopyFrom += pOp->p2 - p1; + } +#endif + Deephemeralize(pOut); + REGISTER_TRACE(p2++, pOut); + pIn1++; + pOut++; + }while( --n ); + break; +} + +/* Opcode: Copy P1 P2 P3 * * +** Synopsis: r[P2@P3+1]=r[P1@P3+1] +** +** Make a copy of registers P1..P1+P3 into registers P2..P2+P3. +** +** This instruction makes a deep copy of the value. A duplicate +** is made of any string or blob constant. See also OP_SCopy. +*/ +case OP_Copy: { + int n; + + n = pOp->p3; + pIn1 = &aMem[pOp->p1]; + pOut = &aMem[pOp->p2]; + assert( pOut!=pIn1 ); + while( 1 ){ + sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); + Deephemeralize(pOut); +#ifdef SQLITE_DEBUG + pOut->pScopyFrom = 0; +#endif + REGISTER_TRACE(pOp->p2+pOp->p3-n, pOut); + if( (n--)==0 ) break; + pOut++; + pIn1++; + } + break; +} + +/* Opcode: SCopy P1 P2 * * * +** Synopsis: r[P2]=r[P1] +** +** Make a shallow copy of register P1 into register P2. +** +** This instruction makes a shallow copy of the value. If the value +** is a string or blob, then the copy is only a pointer to the +** original and hence if the original changes so will the copy. +** Worse, if the original is deallocated, the copy becomes invalid. +** Thus the program must guarantee that the original will not change +** during the lifetime of the copy. Use OP_Copy to make a complete +** copy. +*/ +case OP_SCopy: { /* out2 */ + pIn1 = &aMem[pOp->p1]; + pOut = &aMem[pOp->p2]; + assert( pOut!=pIn1 ); + sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); +#ifdef SQLITE_DEBUG + if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1; +#endif + break; +} + +/* Opcode: IntCopy P1 P2 * * * +** Synopsis: r[P2]=r[P1] +** +** Transfer the integer value held in register P1 into register P2. +** +** This is an optimized version of SCopy that works only for integer +** values. +*/ +case OP_IntCopy: { /* out2 */ + pIn1 = &aMem[pOp->p1]; + assert( (pIn1->flags & MEM_Int)!=0 ); + pOut = &aMem[pOp->p2]; + sqlite3VdbeMemSetInt64(pOut, pIn1->u.i); + break; +} + +/* Opcode: ResultRow P1 P2 * * * +** Synopsis: output=r[P1@P2] +** +** The registers P1 through P1+P2-1 contain a single row of +** results. This opcode causes the sqlite3_step() call to terminate +** with an SQLITE_ROW return code and it sets up the sqlite3_stmt +** structure to provide access to the r(P1)..r(P1+P2-1) values as +** the result row. +*/ +case OP_ResultRow: { + Mem *pMem; + int i; + assert( p->nResColumn==pOp->p2 ); + assert( pOp->p1>0 ); + assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); + +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + /* Run the progress counter just before returning. + */ + if( db->xProgress!=0 + && nVmStep>=nProgressLimit + && db->xProgress(db->pProgressArg)!=0 + ){ + rc = SQLITE_INTERRUPT; + goto abort_due_to_error; + } +#endif + + /* If this statement has violated immediate foreign key constraints, do + ** not return the number of rows modified. And do not RELEASE the statement + ** transaction. It needs to be rolled back. */ + if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){ + assert( db->flags&SQLITE_CountRows ); + assert( p->usesStmtJournal ); + goto abort_due_to_error; + } + + /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then + ** DML statements invoke this opcode to return the number of rows + ** modified to the user. This is the only way that a VM that + ** opens a statement transaction may invoke this opcode. + ** + ** In case this is such a statement, close any statement transaction + ** opened by this VM before returning control to the user. This is to + ** ensure that statement-transactions are always nested, not overlapping. + ** If the open statement-transaction is not closed here, then the user + ** may step another VM that opens its own statement transaction. This + ** may lead to overlapping statement transactions. + ** + ** The statement transaction is never a top-level transaction. Hence + ** the RELEASE call below can never fail. + */ + assert( p->iStatement==0 || db->flags&SQLITE_CountRows ); + rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE); + assert( rc==SQLITE_OK ); + + /* Invalidate all ephemeral cursor row caches */ + p->cacheCtr = (p->cacheCtr + 2)|1; + + /* Make sure the results of the current row are \000 terminated + ** and have an assigned type. The results are de-ephemeralized as + ** a side effect. + */ + pMem = p->pResultSet = &aMem[pOp->p1]; + for(i=0; ip2; i++){ + assert( memIsValid(&pMem[i]) ); + Deephemeralize(&pMem[i]); + assert( (pMem[i].flags & MEM_Ephem)==0 + || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); + sqlite3VdbeMemNulTerminate(&pMem[i]); + REGISTER_TRACE(pOp->p1+i, &pMem[i]); + } + if( db->mallocFailed ) goto no_mem; + + if( db->mTrace & SQLITE_TRACE_ROW ){ + db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); + } + + /* Return SQLITE_ROW + */ + p->pc = (int)(pOp - aOp) + 1; + rc = SQLITE_ROW; + goto vdbe_return; +} + +/* Opcode: Concat P1 P2 P3 * * +** Synopsis: r[P3]=r[P2]+r[P1] +** +** Add the text in register P1 onto the end of the text in +** register P2 and store the result in register P3. +** If either the P1 or P2 text are NULL then store NULL in P3. +** +** P3 = P2 || P1 +** +** It is illegal for P1 and P3 to be the same register. Sometimes, +** if P3 is the same register as P2, the implementation is able +** to avoid a memcpy(). +*/ +case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ + i64 nByte; + + pIn1 = &aMem[pOp->p1]; + pIn2 = &aMem[pOp->p2]; + pOut = &aMem[pOp->p3]; + assert( pIn1!=pOut ); + if( (pIn1->flags | pIn2->flags) & MEM_Null ){ + sqlite3VdbeMemSetNull(pOut); + break; + } + if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem; + Stringify(pIn1, encoding); + Stringify(pIn2, encoding); + nByte = pIn1->n + pIn2->n; + if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; + } + if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ + goto no_mem; + } + MemSetTypeFlag(pOut, MEM_Str); + if( pOut!=pIn2 ){ + memcpy(pOut->z, pIn2->z, pIn2->n); + } + memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); + pOut->z[nByte]=0; + pOut->z[nByte+1] = 0; + pOut->flags |= MEM_Term; + pOut->n = (int)nByte; + pOut->enc = encoding; + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + +/* Opcode: Add P1 P2 P3 * * +** Synopsis: r[P3]=r[P1]+r[P2] +** +** Add the value in register P1 to the value in register P2 +** and store the result in register P3. +** If either input is NULL, the result is NULL. +*/ +/* Opcode: Multiply P1 P2 P3 * * +** Synopsis: r[P3]=r[P1]*r[P2] +** +** +** Multiply the value in register P1 by the value in register P2 +** and store the result in register P3. +** If either input is NULL, the result is NULL. +*/ +/* Opcode: Subtract P1 P2 P3 * * +** Synopsis: r[P3]=r[P2]-r[P1] +** +** Subtract the value in register P1 from the value in register P2 +** and store the result in register P3. +** If either input is NULL, the result is NULL. +*/ +/* Opcode: Divide P1 P2 P3 * * +** Synopsis: r[P3]=r[P2]/r[P1] +** +** Divide the value in register P1 by the value in register P2 +** and store the result in register P3 (P3=P2/P1). If the value in +** register P1 is zero, then the result is NULL. If either input is +** NULL, the result is NULL. +*/ +/* Opcode: Remainder P1 P2 P3 * * +** Synopsis: r[P3]=r[P2]%r[P1] +** +** Compute the remainder after integer register P2 is divided by +** register P1 and store the result in register P3. +** If the value in register P1 is zero the result is NULL. +** If either operand is NULL, the result is NULL. +*/ +case OP_Add: /* same as TK_PLUS, in1, in2, out3 */ +case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ +case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ +case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ +case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ + char bIntint; /* Started out as two integer operands */ + u16 flags; /* Combined MEM_* flags from both inputs */ + u16 type1; /* Numeric type of left operand */ + u16 type2; /* Numeric type of right operand */ + i64 iA; /* Integer value of left operand */ + i64 iB; /* Integer value of right operand */ + double rA; /* Real value of left operand */ + double rB; /* Real value of right operand */ + + pIn1 = &aMem[pOp->p1]; + type1 = numericType(pIn1); + pIn2 = &aMem[pOp->p2]; + type2 = numericType(pIn2); + pOut = &aMem[pOp->p3]; + flags = pIn1->flags | pIn2->flags; + if( (type1 & type2 & MEM_Int)!=0 ){ + iA = pIn1->u.i; + iB = pIn2->u.i; + bIntint = 1; + switch( pOp->opcode ){ + case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; + case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; + case OP_Multiply: if( sqlite3MulInt64(&iB,iA) ) goto fp_math; break; + case OP_Divide: { + if( iA==0 ) goto arithmetic_result_is_null; + if( iA==-1 && iB==SMALLEST_INT64 ) goto fp_math; + iB /= iA; + break; + } + default: { + if( iA==0 ) goto arithmetic_result_is_null; + if( iA==-1 ) iA = 1; + iB %= iA; + break; + } + } + pOut->u.i = iB; + MemSetTypeFlag(pOut, MEM_Int); + }else if( (flags & MEM_Null)!=0 ){ + goto arithmetic_result_is_null; + }else{ + bIntint = 0; +fp_math: + rA = sqlite3VdbeRealValue(pIn1); + rB = sqlite3VdbeRealValue(pIn2); + switch( pOp->opcode ){ + case OP_Add: rB += rA; break; + case OP_Subtract: rB -= rA; break; + case OP_Multiply: rB *= rA; break; + case OP_Divide: { + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + if( rA==(double)0 ) goto arithmetic_result_is_null; + rB /= rA; + break; + } + default: { + iA = (i64)rA; + iB = (i64)rB; + if( iA==0 ) goto arithmetic_result_is_null; + if( iA==-1 ) iA = 1; + rB = (double)(iB % iA); + break; + } + } +#ifdef SQLITE_OMIT_FLOATING_POINT + pOut->u.i = rB; + MemSetTypeFlag(pOut, MEM_Int); +#else + if( sqlite3IsNaN(rB) ){ + goto arithmetic_result_is_null; + } + pOut->u.r = rB; + MemSetTypeFlag(pOut, MEM_Real); + if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ + sqlite3VdbeIntegerAffinity(pOut); + } +#endif + } + break; + +arithmetic_result_is_null: + sqlite3VdbeMemSetNull(pOut); + break; +} + +/* Opcode: CollSeq P1 * * P4 +** +** P4 is a pointer to a CollSeq object. If the next call to a user function +** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will +** be returned. This is used by the built-in min(), max() and nullif() +** functions. +** +** If P1 is not zero, then it is a register that a subsequent min() or +** max() aggregate will set to 1 if the current row is not the minimum or +** maximum. The P1 register is initialized to 0 by this instruction. +** +** The interface used by the implementation of the aforementioned functions +** to retrieve the collation sequence set by this opcode is not available +** publicly. Only built-in functions have access to this feature. +*/ +case OP_CollSeq: { + assert( pOp->p4type==P4_COLLSEQ ); + if( pOp->p1 ){ + sqlite3VdbeMemSetInt64(&aMem[pOp->p1], 0); + } + break; +} + +/* Opcode: Function0 P1 P2 P3 P4 P5 +** Synopsis: r[P3]=func(r[P2@P5]) +** +** Invoke a user function (P4 is a pointer to a FuncDef object that +** defines the function) with P5 arguments taken from register P2 and +** successors. The result of the function is stored in register P3. +** Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** See also: Function, AggStep, AggFinal +*/ +/* Opcode: Function P1 P2 P3 P4 P5 +** Synopsis: r[P3]=func(r[P2@P5]) +** +** Invoke a user function (P4 is a pointer to an sqlite3_context object that +** contains a pointer to the function to be run) with P5 arguments taken +** from register P2 and successors. The result of the function is stored +** in register P3. Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** SQL functions are initially coded as OP_Function0 with P4 pointing +** to a FuncDef object. But on first evaluation, the P4 operand is +** automatically converted into an sqlite3_context object and the operation +** changed to this OP_Function opcode. In this way, the initialization of +** the sqlite3_context object occurs only once, rather than once for each +** evaluation of the function. +** +** See also: Function0, AggStep, AggFinal +*/ +case OP_Function0: { + int n; + sqlite3_context *pCtx; + + assert( pOp->p4type==P4_FUNCDEF ); + n = pOp->p5; + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); + assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); + pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); + if( pCtx==0 ) goto no_mem; + pCtx->pOut = 0; + pCtx->pFunc = pOp->p4.pFunc; + pCtx->iOp = (int)(pOp - aOp); + pCtx->pVdbe = p; + pCtx->argc = n; + pOp->p4type = P4_FUNCCTX; + pOp->p4.pCtx = pCtx; + pOp->opcode = OP_Function; + /* Fall through into OP_Function */ +} +case OP_Function: { + int i; + sqlite3_context *pCtx; + + assert( pOp->p4type==P4_FUNCCTX ); + pCtx = pOp->p4.pCtx; + + /* If this function is inside of a trigger, the register array in aMem[] + ** might change from one evaluation to the next. The next block of code + ** checks to see if the register array has changed, and if so it + ** reinitializes the relavant parts of the sqlite3_context object */ + pOut = &aMem[pOp->p3]; + if( pCtx->pOut != pOut ){ + pCtx->pOut = pOut; + for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; + } + + memAboutToChange(p, pOut); +#ifdef SQLITE_DEBUG + for(i=0; iargc; i++){ + assert( memIsValid(pCtx->argv[i]) ); + REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); + } +#endif + MemSetTypeFlag(pOut, MEM_Null); + pCtx->fErrorOrAux = 0; + (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ + + /* If the function returned an error, throw an exception */ + if( pCtx->fErrorOrAux ){ + if( pCtx->isError ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut)); + rc = pCtx->isError; + } + sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); + if( rc ) goto abort_due_to_error; + } + + /* Copy the result of the function into register P3 */ + if( pOut->flags & (MEM_Str|MEM_Blob) ){ + sqlite3VdbeChangeEncoding(pOut, encoding); + if( sqlite3VdbeMemTooBig(pOut) ) goto too_big; + } + + REGISTER_TRACE(pOp->p3, pOut); + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + +/* Opcode: BitAnd P1 P2 P3 * * +** Synopsis: r[P3]=r[P1]&r[P2] +** +** Take the bit-wise AND of the values in register P1 and P2 and +** store the result in register P3. +** If either input is NULL, the result is NULL. +*/ +/* Opcode: BitOr P1 P2 P3 * * +** Synopsis: r[P3]=r[P1]|r[P2] +** +** Take the bit-wise OR of the values in register P1 and P2 and +** store the result in register P3. +** If either input is NULL, the result is NULL. +*/ +/* Opcode: ShiftLeft P1 P2 P3 * * +** Synopsis: r[P3]=r[P2]<>r[P1] +** +** Shift the integer value in register P2 to the right by the +** number of bits specified by the integer in register P1. +** Store the result in register P3. +** If either input is NULL, the result is NULL. +*/ +case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */ +case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */ +case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */ +case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ + i64 iA; + u64 uA; + i64 iB; + u8 op; + + pIn1 = &aMem[pOp->p1]; + pIn2 = &aMem[pOp->p2]; + pOut = &aMem[pOp->p3]; + if( (pIn1->flags | pIn2->flags) & MEM_Null ){ + sqlite3VdbeMemSetNull(pOut); + break; + } + iA = sqlite3VdbeIntValue(pIn2); + iB = sqlite3VdbeIntValue(pIn1); + op = pOp->opcode; + if( op==OP_BitAnd ){ + iA &= iB; + }else if( op==OP_BitOr ){ + iA |= iB; + }else if( iB!=0 ){ + assert( op==OP_ShiftRight || op==OP_ShiftLeft ); + + /* If shifting by a negative amount, shift in the other direction */ + if( iB<0 ){ + assert( OP_ShiftRight==OP_ShiftLeft+1 ); + op = 2*OP_ShiftLeft + 1 - op; + iB = iB>(-64) ? -iB : 64; + } + + if( iB>=64 ){ + iA = (iA>=0 || op==OP_ShiftLeft) ? 0 : -1; + }else{ + memcpy(&uA, &iA, sizeof(uA)); + if( op==OP_ShiftLeft ){ + uA <<= iB; + }else{ + uA >>= iB; + /* Sign-extend on a right shift of a negative number */ + if( iA<0 ) uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-iB); + } + memcpy(&iA, &uA, sizeof(iA)); + } + } + pOut->u.i = iA; + MemSetTypeFlag(pOut, MEM_Int); + break; +} + +/* Opcode: AddImm P1 P2 * * * +** Synopsis: r[P1]=r[P1]+P2 +** +** Add the constant P2 to the value in register P1. +** The result is always an integer. +** +** To force any register to be an integer, just add 0. +*/ +case OP_AddImm: { /* in1 */ + pIn1 = &aMem[pOp->p1]; + memAboutToChange(p, pIn1); + sqlite3VdbeMemIntegerify(pIn1); + pIn1->u.i += pOp->p2; + break; +} + +/* Opcode: MustBeInt P1 P2 * * * +** +** Force the value in register P1 to be an integer. If the value +** in P1 is not an integer and cannot be converted into an integer +** without data loss, then jump immediately to P2, or if P2==0 +** raise an SQLITE_MISMATCH exception. +*/ +case OP_MustBeInt: { /* jump, in1 */ + pIn1 = &aMem[pOp->p1]; + if( (pIn1->flags & MEM_Int)==0 ){ + applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); + VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); + if( (pIn1->flags & MEM_Int)==0 ){ + if( pOp->p2==0 ){ + rc = SQLITE_MISMATCH; + goto abort_due_to_error; + }else{ + goto jump_to_p2; + } + } + } + MemSetTypeFlag(pIn1, MEM_Int); + break; +} + +#ifndef SQLITE_OMIT_FLOATING_POINT +/* Opcode: RealAffinity P1 * * * * +** +** If register P1 holds an integer convert it to a real value. +** +** This opcode is used when extracting information from a column that +** has REAL affinity. Such column values may still be stored as +** integers, for space efficiency, but after extraction we want them +** to have only a real value. +*/ +case OP_RealAffinity: { /* in1 */ + pIn1 = &aMem[pOp->p1]; + if( pIn1->flags & MEM_Int ){ + sqlite3VdbeMemRealify(pIn1); + } + break; +} +#endif + +#ifndef SQLITE_OMIT_CAST +/* Opcode: Cast P1 P2 * * * +** Synopsis: affinity(r[P1]) +** +** Force the value in register P1 to be the type defined by P2. +** +**
      +**
    • P2=='A' → BLOB +**
    • P2=='B' → TEXT +**
    • P2=='C' → NUMERIC +**
    • P2=='D' → INTEGER +**
    • P2=='E' → REAL +**
    +** +** A NULL value is not changed by this routine. It remains NULL. +*/ +case OP_Cast: { /* in1 */ + assert( pOp->p2>=SQLITE_AFF_BLOB && pOp->p2<=SQLITE_AFF_REAL ); + testcase( pOp->p2==SQLITE_AFF_TEXT ); + testcase( pOp->p2==SQLITE_AFF_BLOB ); + testcase( pOp->p2==SQLITE_AFF_NUMERIC ); + testcase( pOp->p2==SQLITE_AFF_INTEGER ); + testcase( pOp->p2==SQLITE_AFF_REAL ); + pIn1 = &aMem[pOp->p1]; + memAboutToChange(p, pIn1); + rc = ExpandBlob(pIn1); + sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); + UPDATE_MAX_BLOBSIZE(pIn1); + if( rc ) goto abort_due_to_error; + break; +} +#endif /* SQLITE_OMIT_CAST */ + +/* Opcode: Eq P1 P2 P3 P4 P5 +** Synopsis: IF r[P3]==r[P1] +** +** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then +** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, then +** store the result of comparison in register P2. +** +** The SQLITE_AFF_MASK portion of P5 must be an affinity character - +** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made +** to coerce both inputs according to this affinity before the +** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric +** affinity is used. Note that the affinity conversions are stored +** back into the input registers P1 and P3. So this opcode can cause +** persistent changes to registers P1 and P3. +** +** Once any conversions have taken place, and neither value is NULL, +** the values are compared. If both values are blobs then memcmp() is +** used to determine the results of the comparison. If both values +** are text, then the appropriate collating function specified in +** P4 is used to do the comparison. If P4 is not specified then +** memcmp() is used to compare text string. If both values are +** numeric, then a numeric comparison is used. If the two values +** are of different types, then numbers are considered less than +** strings and strings are considered less than blobs. +** +** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either +** true or false and is never NULL. If both operands are NULL then the result +** of comparison is true. If either operand is NULL then the result is false. +** If neither operand is NULL the result is the same as it would be if +** the SQLITE_NULLEQ flag were omitted from P5. +** +** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the +** content of r[P2] is only changed if the new value is NULL or 0 (false). +** In other words, a prior r[P2] value will not be overwritten by 1 (true). +*/ +/* Opcode: Ne P1 P2 P3 P4 P5 +** Synopsis: IF r[P3]!=r[P1] +** +** This works just like the Eq opcode except that the jump is taken if +** the operands in registers P1 and P3 are not equal. See the Eq opcode for +** additional information. +** +** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the +** content of r[P2] is only changed if the new value is NULL or 1 (true). +** In other words, a prior r[P2] value will not be overwritten by 0 (false). +*/ +/* Opcode: Lt P1 P2 P3 P4 P5 +** Synopsis: IF r[P3]r[P1] +** +** This works just like the Lt opcode except that the jump is taken if +** the content of register P3 is greater than the content of +** register P1. See the Lt opcode for additional information. +*/ +/* Opcode: Ge P1 P2 P3 P4 P5 +** Synopsis: IF r[P3]>=r[P1] +** +** This works just like the Lt opcode except that the jump is taken if +** the content of register P3 is greater than or equal to the content of +** register P1. See the Lt opcode for additional information. +*/ +case OP_Eq: /* same as TK_EQ, jump, in1, in3 */ +case OP_Ne: /* same as TK_NE, jump, in1, in3 */ +case OP_Lt: /* same as TK_LT, jump, in1, in3 */ +case OP_Le: /* same as TK_LE, jump, in1, in3 */ +case OP_Gt: /* same as TK_GT, jump, in1, in3 */ +case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ + int res, res2; /* Result of the comparison of pIn1 against pIn3 */ + char affinity; /* Affinity to use for comparison */ + u16 flags1; /* Copy of initial value of pIn1->flags */ + u16 flags3; /* Copy of initial value of pIn3->flags */ + + pIn1 = &aMem[pOp->p1]; + pIn3 = &aMem[pOp->p3]; + flags1 = pIn1->flags; + flags3 = pIn3->flags; + if( (flags1 | flags3)&MEM_Null ){ + /* One or both operands are NULL */ + if( pOp->p5 & SQLITE_NULLEQ ){ + /* If SQLITE_NULLEQ is set (which will only happen if the operator is + ** OP_Eq or OP_Ne) then take the jump or not depending on whether + ** or not both operands are null. + */ + assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); + assert( (flags1 & MEM_Cleared)==0 ); + assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 ); + if( (flags1&flags3&MEM_Null)!=0 + && (flags3&MEM_Cleared)==0 + ){ + res = 0; /* Operands are equal */ + }else{ + res = 1; /* Operands are not equal */ + } + }else{ + /* SQLITE_NULLEQ is clear and at least one operand is NULL, + ** then the result is always NULL. + ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. + */ + if( pOp->p5 & SQLITE_STOREP2 ){ + pOut = &aMem[pOp->p2]; + iCompare = 1; /* Operands are not equal */ + memAboutToChange(p, pOut); + MemSetTypeFlag(pOut, MEM_Null); + REGISTER_TRACE(pOp->p2, pOut); + }else{ + VdbeBranchTaken(2,3); + if( pOp->p5 & SQLITE_JUMPIFNULL ){ + goto jump_to_p2; + } + } + break; + } + }else{ + /* Neither operand is NULL. Do a comparison. */ + affinity = pOp->p5 & SQLITE_AFF_MASK; + if( affinity>=SQLITE_AFF_NUMERIC ){ + if( (flags1 | flags3)&MEM_Str ){ + if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn1,0); + testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */ + flags3 = pIn3->flags; + } + if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn3,0); + } + } + /* Handle the common case of integer comparison here, as an + ** optimization, to avoid a call to sqlite3MemCompare() */ + if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){ + if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; } + if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; } + res = 0; + goto compare_op; + } + }else if( affinity==SQLITE_AFF_TEXT ){ + if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ + testcase( pIn1->flags & MEM_Int ); + testcase( pIn1->flags & MEM_Real ); + sqlite3VdbeMemStringify(pIn1, encoding, 1); + testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); + flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); + assert( pIn1!=pIn3 ); + } + if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ + testcase( pIn3->flags & MEM_Int ); + testcase( pIn3->flags & MEM_Real ); + sqlite3VdbeMemStringify(pIn3, encoding, 1); + testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); + flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); + } + } + assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); + 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; + } + + /* Undo any changes made by applyAffinity() to the input registers. */ + assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); + pIn1->flags = flags1; + assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); + pIn3->flags = flags3; + + 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 + ** is only used in contexts where either: + ** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0) + ** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1) + ** Therefore it is not necessary to check the content of r[P2] for + ** NULL. */ + assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq ); + assert( res2==0 || res2==1 ); + testcase( res2==0 && pOp->opcode==OP_Eq ); + testcase( res2==1 && pOp->opcode==OP_Eq ); + testcase( res2==0 && pOp->opcode==OP_Ne ); + testcase( res2==1 && pOp->opcode==OP_Ne ); + if( (pOp->opcode==OP_Eq)==res2 ) break; + } + memAboutToChange(p, pOut); + MemSetTypeFlag(pOut, MEM_Int); + pOut->u.i = res2; + REGISTER_TRACE(pOp->p2, pOut); + }else{ + VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); + if( res2 ){ + goto jump_to_p2; + } + } + break; +} + +/* Opcode: ElseNotEq * P2 * * * +** +** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator. +** If result of an OP_Eq comparison on the same two operands +** would have be NULL or false (0), then then jump to P2. +** If the result of an OP_Eq comparison on the two previous operands +** would have been true (1), then fall through. +*/ +case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */ + assert( pOp>aOp ); + assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt ); + assert( pOp[-1].p5 & SQLITE_STOREP2 ); + VdbeBranchTaken(iCompare!=0, 2); + if( iCompare!=0 ) goto jump_to_p2; + break; +} + + +/* Opcode: Permutation * * * P4 * +** +** Set the permutation used by the OP_Compare operator in the next +** instruction. The permutation is stored in the P4 operand. +** +** The permutation is only valid until the next OP_Compare that has +** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should +** occur immediately prior to the OP_Compare. +** +** The first integer in the P4 integer array is the length of the array +** and does not become part of the permutation. +*/ +case OP_Permutation: { + assert( pOp->p4type==P4_INTARRAY ); + assert( pOp->p4.ai ); + assert( pOp[1].opcode==OP_Compare ); + assert( pOp[1].p5 & OPFLAG_PERMUTE ); + break; +} + +/* Opcode: Compare P1 P2 P3 P4 P5 +** Synopsis: r[P1@P3] <-> r[P2@P3] +** +** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this +** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of +** the comparison for use by the next OP_Jump instruct. +** +** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is +** determined by the most recent OP_Permutation operator. If the +** OPFLAG_PERMUTE bit is clear, then register are compared in sequential +** order. +** +** P4 is a KeyInfo structure that defines collating sequences and sort +** orders for the comparison. The permutation applies to registers +** only. The KeyInfo elements are used sequentially. +** +** The comparison is a sort comparison, so NULLs compare equal, +** NULLs are less than numbers, numbers are less than strings, +** and strings are less than blobs. +*/ +case OP_Compare: { + int n; + int i; + int p1; + int p2; + const KeyInfo *pKeyInfo; + int idx; + CollSeq *pColl; /* Collating sequence to use on this term */ + int bRev; /* True for DESCENDING sort order */ + int *aPermute; /* The permutation */ + + if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){ + aPermute = 0; + }else{ + assert( pOp>aOp ); + assert( pOp[-1].opcode==OP_Permutation ); + assert( pOp[-1].p4type==P4_INTARRAY ); + aPermute = pOp[-1].p4.ai + 1; + assert( aPermute!=0 ); + } + n = pOp->p3; + pKeyInfo = pOp->p4.pKeyInfo; + assert( n>0 ); + assert( pKeyInfo!=0 ); + p1 = pOp->p1; + p2 = pOp->p2; +#ifdef SQLITE_DEBUG + if( aPermute ){ + int k, mx = 0; + for(k=0; kmx ) mx = aPermute[k]; + assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 ); + assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 ); + }else{ + assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 ); + assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 ); + } +#endif /* SQLITE_DEBUG */ + for(i=0; inField ); + pColl = pKeyInfo->aColl[i]; + bRev = pKeyInfo->aSortOrder[i]; + iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); + if( iCompare ){ + if( bRev ) iCompare = -iCompare; + break; + } + } + break; +} + +/* Opcode: Jump P1 P2 P3 * * +** +** Jump to the instruction at address P1, P2, or P3 depending on whether +** in the most recent OP_Compare instruction the P1 vector was less than +** equal to, or greater than the P2 vector, respectively. +*/ +case OP_Jump: { /* jump */ + if( iCompare<0 ){ + VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1]; + }else if( iCompare==0 ){ + VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1]; + }else{ + VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1]; + } + break; +} + +/* Opcode: And P1 P2 P3 * * +** Synopsis: r[P3]=(r[P1] && r[P2]) +** +** Take the logical AND of the values in registers P1 and P2 and +** write the result into register P3. +** +** If either P1 or P2 is 0 (false) then the result is 0 even if +** the other input is NULL. A NULL and true or two NULLs give +** a NULL output. +*/ +/* Opcode: Or P1 P2 P3 * * +** Synopsis: r[P3]=(r[P1] || r[P2]) +** +** Take the logical OR of the values in register P1 and P2 and +** store the answer in register P3. +** +** If either P1 or P2 is nonzero (true) then the result is 1 (true) +** even if the other input is NULL. A NULL and false or two NULLs +** give a NULL output. +*/ +case OP_And: /* same as TK_AND, in1, in2, out3 */ +case OP_Or: { /* same as TK_OR, in1, in2, out3 */ + int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ + int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ + + pIn1 = &aMem[pOp->p1]; + if( pIn1->flags & MEM_Null ){ + v1 = 2; + }else{ + v1 = sqlite3VdbeIntValue(pIn1)!=0; + } + pIn2 = &aMem[pOp->p2]; + if( pIn2->flags & MEM_Null ){ + v2 = 2; + }else{ + v2 = sqlite3VdbeIntValue(pIn2)!=0; + } + if( pOp->opcode==OP_And ){ + static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; + v1 = and_logic[v1*3+v2]; + }else{ + static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; + v1 = or_logic[v1*3+v2]; + } + pOut = &aMem[pOp->p3]; + if( v1==2 ){ + MemSetTypeFlag(pOut, MEM_Null); + }else{ + pOut->u.i = v1; + MemSetTypeFlag(pOut, MEM_Int); + } + break; +} + +/* Opcode: Not P1 P2 * * * +** Synopsis: r[P2]= !r[P1] +** +** Interpret the value in register P1 as a boolean value. Store the +** boolean complement in register P2. If the value in register P1 is +** NULL, then a NULL is stored in P2. +*/ +case OP_Not: { /* same as TK_NOT, in1, out2 */ + pIn1 = &aMem[pOp->p1]; + pOut = &aMem[pOp->p2]; + sqlite3VdbeMemSetNull(pOut); + if( (pIn1->flags & MEM_Null)==0 ){ + pOut->flags = MEM_Int; + pOut->u.i = !sqlite3VdbeIntValue(pIn1); + } + break; +} + +/* Opcode: BitNot P1 P2 * * * +** Synopsis: r[P1]= ~r[P1] +** +** Interpret the content of register P1 as an integer. Store the +** ones-complement of the P1 value into register P2. If P1 holds +** a NULL then store a NULL in P2. +*/ +case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ + pIn1 = &aMem[pOp->p1]; + pOut = &aMem[pOp->p2]; + sqlite3VdbeMemSetNull(pOut); + if( (pIn1->flags & MEM_Null)==0 ){ + pOut->flags = MEM_Int; + pOut->u.i = ~sqlite3VdbeIntValue(pIn1); + } + break; +} + +/* Opcode: Once P1 P2 * * * +** +** Fall through to the next instruction the first time this opcode is +** encountered on each invocation of the byte-code program. Jump to P2 +** on the second and all subsequent encounters during the same invocation. +** +** Top-level programs determine first invocation by comparing the P1 +** operand against the P1 operand on the OP_Init opcode at the beginning +** of the program. If the P1 values differ, then fall through and make +** the P1 of this opcode equal to the P1 of OP_Init. If P1 values are +** the same then take the jump. +** +** For subprograms, there is a bitmask in the VdbeFrame that determines +** whether or not the jump should be taken. The bitmask is necessary +** because the self-altering code trick does not work for recursive +** triggers. +*/ +case OP_Once: { /* jump */ + u32 iAddr; /* Address of this instruction */ + assert( p->aOp[0].opcode==OP_Init ); + if( p->pFrame ){ + iAddr = (int)(pOp - p->aOp); + if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){ + VdbeBranchTaken(1, 2); + goto jump_to_p2; + } + p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7); + }else{ + if( p->aOp[0].p1==pOp->p1 ){ + VdbeBranchTaken(1, 2); + goto jump_to_p2; + } + } + VdbeBranchTaken(0, 2); + pOp->p1 = p->aOp[0].p1; + break; +} + +/* Opcode: If P1 P2 P3 * * +** +** Jump to P2 if the value in register P1 is true. The value +** is considered true if it is numeric and non-zero. If the value +** in P1 is NULL then take the jump if and only if P3 is non-zero. +*/ +/* Opcode: IfNot P1 P2 P3 * * +** +** Jump to P2 if the value in register P1 is False. The value +** is considered false if it has a numeric value of zero. If the value +** in P1 is NULL then take the jump if and only if P3 is non-zero. +*/ +case OP_If: /* jump, in1 */ +case OP_IfNot: { /* jump, in1 */ + int c; + pIn1 = &aMem[pOp->p1]; + if( pIn1->flags & MEM_Null ){ + c = pOp->p3; + }else{ +#ifdef SQLITE_OMIT_FLOATING_POINT + c = sqlite3VdbeIntValue(pIn1)!=0; +#else + c = sqlite3VdbeRealValue(pIn1)!=0.0; +#endif + if( pOp->opcode==OP_IfNot ) c = !c; + } + VdbeBranchTaken(c!=0, 2); + if( c ){ + goto jump_to_p2; + } + break; +} + +/* Opcode: IsNull P1 P2 * * * +** Synopsis: if r[P1]==NULL goto P2 +** +** Jump to P2 if the value in register P1 is NULL. +*/ +case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ + pIn1 = &aMem[pOp->p1]; + VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); + if( (pIn1->flags & MEM_Null)!=0 ){ + goto jump_to_p2; + } + break; +} + +/* Opcode: NotNull P1 P2 * * * +** Synopsis: if r[P1]!=NULL goto P2 +** +** Jump to P2 if the value in register P1 is not NULL. +*/ +case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ + pIn1 = &aMem[pOp->p1]; + VdbeBranchTaken( (pIn1->flags & MEM_Null)==0, 2); + if( (pIn1->flags & MEM_Null)==0 ){ + goto jump_to_p2; + } + break; +} + +/* Opcode: IfNullRow P1 P2 P3 * * +** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 +** +** Check the cursor P1 to see if it is currently pointing at a NULL row. +** If it is, then set register P3 to NULL and jump immediately to P2. +** If P1 is not on a NULL row, then fall through without making any +** changes. +*/ +case OP_IfNullRow: { /* jump */ + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( p->apCsr[pOp->p1]!=0 ); + if( p->apCsr[pOp->p1]->nullRow ){ + sqlite3VdbeMemSetNull(aMem + pOp->p3); + goto jump_to_p2; + } + break; +} + +/* Opcode: Column P1 P2 P3 P4 P5 +** Synopsis: r[P3]=PX +** +** Interpret the data that cursor P1 points to as a structure built using +** the MakeRecord instruction. (See the MakeRecord opcode for additional +** information about the format of the data.) Extract the P2-th column +** from this record. If there are less that (P2+1) +** values in the record, extract a NULL. +** +** The value extracted is stored in register P3. +** +** If the record contains fewer than P2 fields, then extract a NULL. Or, +** if the P4 argument is a P4_MEM use the value of the P4 argument as +** the result. +** +** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor, +** then the cache of the cursor is reset prior to extracting the column. +** The first OP_Column against a pseudo-table after the value of the content +** register has changed should have this bit set. +** +** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then +** the result is guaranteed to only be used as the argument of a length() +** or typeof() function, respectively. The loading of large blobs can be +** skipped for length() and all content loading can be skipped for typeof(). +*/ +case OP_Column: { + int p2; /* column number to retrieve */ + VdbeCursor *pC; /* The VDBE cursor */ + BtCursor *pCrsr; /* The BTree cursor */ + u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ + int len; /* The length of the serialized data for the column */ + int i; /* Loop counter */ + Mem *pDest; /* Where to write the extracted value */ + Mem sMem; /* For storing the record being decoded */ + 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 */ + + pC = p->apCsr[pOp->p1]; + p2 = pOp->p2; + + /* If the cursor cache is stale, bring it up-to-date */ + rc = sqlite3VdbeCursorMoveto(&pC, &p2); + if( rc ) goto abort_due_to_error; + + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + pDest = &aMem[pOp->p3]; + memAboutToChange(p, pDest); + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pC!=0 ); + assert( p2nField ); + aOffset = pC->aOffset; + assert( pC->eCurType!=CURTYPE_VTAB ); + assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); + assert( pC->eCurType!=CURTYPE_SORTER ); + + if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ + if( pC->nullRow ){ + if( pC->eCurType==CURTYPE_PSEUDO ){ + assert( pC->uc.pseudoTableReg>0 ); + pReg = &aMem[pC->uc.pseudoTableReg]; + assert( pReg->flags & MEM_Blob ); + assert( memIsValid(pReg) ); + pC->payloadSize = pC->szRow = avail = pReg->n; + pC->aRow = (u8*)pReg->z; + }else{ + sqlite3VdbeMemSetNull(pDest); + goto op_column_out; + } + }else{ + pCrsr = pC->uc.pCursor; + assert( pC->eCurType==CURTYPE_BTREE ); + 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] ){ + goto too_big; + }else{ + pC->szRow = avail; + } + } + pC->cacheStatus = p->cacheCtr; + pC->iHdrOffset = getVarint32(pC->aRow, offset); + pC->nHdrParsed = 0; + aOffset[0] = offset; + + + if( availaRow 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 + ** dynamically allocated. */ + pC->aRow = 0; + pC->szRow = 0; + + /* Make sure a corrupt database has not given us an oversize header. + ** Do this now to avoid an oversize memory allocation. + ** + ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte + ** types use so much data space that there can only be 4096 and 32 of + ** them, respectively. So the maximum header length results from a + ** 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; + } + }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. + */ + zData = pC->aRow; + assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + goto op_column_read_header; + } + } + + /* Make sure at least the first p2+1 entries of the header have been + ** parsed and valid information is in aOffset[] and pC->aType[]. + */ + if( pC->nHdrParsed<=p2 ){ + /* If there is more header available for parsing in the record, try + ** to extract additional fields up through the p2+1-th field + */ + if( pC->iHdrOffsetaRow==0 ){ + memset(&sMem, 0, sizeof(sMem)); + rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + zData = (u8*)sMem.z; + }else{ + zData = pC->aRow; + } + + /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ + op_column_read_header: + i = pC->nHdrParsed; + offset64 = aOffset[i]; + zHdr = zData + pC->iHdrOffset; + zEndHdr = zData + aOffset[0]; + do{ + if( (t = zHdr[0])<0x80 ){ + zHdr++; + offset64 += sqlite3VdbeOneByteSerialTypeLen(t); + }else{ + zHdr += sqlite3GetVarint32(zHdr, &t); + offset64 += sqlite3VdbeSerialTypeLen(t); + } + pC->aType[i++] = t; + aOffset[i] = (u32)(offset64 & 0xffffffff); + }while( i<=p2 && 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; + } + + pC->nHdrParsed = i; + pC->iHdrOffset = (u32)(zHdr - zData); + if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); + }else{ + t = 0; + } + + /* If after trying to extract new entries from the header, nHdrParsed is + ** still not up to p2, that means that the record has fewer than p2 + ** columns. So the result will be either the default value or a NULL. + */ + if( pC->nHdrParsed<=p2 ){ + if( pOp->p4type==P4_MEM ){ + sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); + }else{ + sqlite3VdbeMemSetNull(pDest); + } + goto op_column_out; + } + }else{ + t = pC->aType[p2]; + } + + /* Extract the content for the p2+1-th column. Control can only + ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are + ** all valid. + */ + assert( p2nHdrParsed ); + assert( rc==SQLITE_OK ); + assert( sqlite3VdbeCheckMemInvariants(pDest) ); + if( VdbeMemDynamic(pDest) ){ + sqlite3VdbeMemSetNull(pDest); + } + assert( t==pC->aType[p2] ); + if( pC->szRow>=aOffset[p2+1] ){ + /* This is the common case where the desired content fits on the original + ** page - where the content is not on an overflow page */ + zData = pC->aRow + aOffset[p2]; + if( t<12 ){ + sqlite3VdbeSerialGet(zData, t, pDest); + }else{ + /* If the column value is a string, we need a persistent value, not + ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent + ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). + */ + static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; + pDest->n = len = (t-12)/2; + pDest->enc = encoding; + if( pDest->szMalloc < len+2 ){ + pDest->flags = MEM_Null; + if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; + }else{ + pDest->z = pDest->zMalloc; + } + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = aFlag[t&1]; + } + }else{ + pDest->enc = encoding; + /* This branch happens only when content is on overflow pages */ + if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 + && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) + || (len = sqlite3VdbeSerialTypeLen(t))==0 + ){ + /* Content is irrelevant for + ** 1. the typeof() function, + ** 2. the length(X) function if X is a blob, and + ** 3. if the content length is zero. + ** So we might as well use bogus content rather than reading + ** content from disk. + ** + ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the + ** buffer passed to it, debugging function VdbeMemPrettyPrint() may + ** read up to 16. So 16 bytes of bogus content is supplied. + */ + static u8 aZero[16]; /* This is the bogus content */ + sqlite3VdbeSerialGet(aZero, t, pDest); + }else{ + rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); + pDest->flags &= ~MEM_Ephem; + } + } + +op_column_out: + UPDATE_MAX_BLOBSIZE(pDest); + REGISTER_TRACE(pOp->p3, pDest); + break; +} + +/* Opcode: Affinity P1 P2 * P4 * +** Synopsis: affinity(r[P1@P2]) +** +** Apply affinities to a range of P2 registers starting with P1. +** +** P4 is a string that is P2 characters long. The N-th character of the +** string indicates the column affinity that should be used for the N-th +** memory cell in the range. +*/ +case OP_Affinity: { + const char *zAffinity; /* The affinity to be applied */ + + zAffinity = pOp->p4.z; + assert( zAffinity!=0 ); + assert( pOp->p2>0 ); + assert( zAffinity[pOp->p2]==0 ); + pIn1 = &aMem[pOp->p1]; + do{ + assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); + assert( memIsValid(pIn1) ); + applyAffinity(pIn1, *(zAffinity++), encoding); + pIn1++; + }while( zAffinity[0] ); + break; +} + +/* Opcode: MakeRecord P1 P2 P3 P4 * +** Synopsis: r[P3]=mkrec(r[P1@P2]) +** +** Convert P2 registers beginning with P1 into the [record format] +** use as a data record in a database table or as a key +** in an index. The OP_Column opcode can decode the record later. +** +** P4 may be a string that is P2 characters long. The N-th character of the +** string indicates the column affinity that should be used for the N-th +** field of the index key. +** +** The mapping from character to affinity is given by the SQLITE_AFF_ +** macros defined in sqliteInt.h. +** +** If P4 is NULL then all index fields have the affinity BLOB. +*/ +case OP_MakeRecord: { + u8 *zNewRecord; /* A buffer to hold the data for the new record */ + Mem *pRec; /* The new record */ + u64 nData; /* Number of bytes of data space */ + int nHdr; /* Number of bytes of header space */ + i64 nByte; /* Data space required for this record */ + i64 nZero; /* Number of zero bytes at the end of the record */ + int nVarint; /* Number of bytes in a varint */ + u32 serial_type; /* Type field */ + Mem *pData0; /* First field to be combined into the record */ + Mem *pLast; /* Last field of the record */ + int nField; /* Number of fields in the record */ + char *zAffinity; /* The affinity string for the record */ + int file_format; /* File format to use for encoding */ + int i; /* Space used in zNewRecord[] header */ + int j; /* Space used in zNewRecord[] content */ + u32 len; /* Length of a field */ + + /* Assuming the record contains N fields, the record format looks + ** like this: + ** + ** ------------------------------------------------------------------------ + ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | + ** ------------------------------------------------------------------------ + ** + ** Data(0) is taken from register P1. Data(1) comes from register P1+1 + ** and so forth. + ** + ** Each type field is a varint representing the serial type of the + ** corresponding data element (see sqlite3VdbeSerialType()). The + ** hdr-size field is also a varint which is the offset from the beginning + ** of the record to data0. + */ + nData = 0; /* Number of bytes of data space */ + nHdr = 0; /* Number of bytes of header space */ + nZero = 0; /* Number of zero bytes at the end of the record */ + nField = pOp->p1; + zAffinity = pOp->p4.z; + assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 ); + pData0 = &aMem[nField]; + nField = pOp->p2; + pLast = &pData0[nField-1]; + file_format = p->minWriteFileFormat; + + /* Identify the output register */ + assert( pOp->p3p1 || pOp->p3>=pOp->p1+pOp->p2 ); + pOut = &aMem[pOp->p3]; + memAboutToChange(p, pOut); + + /* Apply the requested affinity to all inputs + */ + assert( pData0<=pLast ); + if( zAffinity ){ + pRec = pData0; + do{ + applyAffinity(pRec++, *(zAffinity++), encoding); + assert( zAffinity[0]==0 || pRec<=pLast ); + }while( zAffinity[0] ); + } + +#ifdef SQLITE_ENABLE_NULL_TRIM + /* NULLs can be safely trimmed from the end of the record, as long as + ** as the schema format is 2 or more and none of the omitted columns + ** have a non-NULL default value. Also, the record must be left with + ** at least one field. If P5>0 then it will be one more than the + ** index of the right-most column with a non-NULL default value */ + if( pOp->p5 ){ + while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){ + pLast--; + nField--; + } + } +#endif + + /* Loop through the elements that will make up the record to figure + ** out how much space is required for the new record. + */ + pRec = pLast; + do{ + assert( memIsValid(pRec) ); + pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format, &len); + if( pRec->flags & MEM_Zero ){ + if( nData ){ + if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; + }else{ + nZero += pRec->u.nZero; + len -= pRec->u.nZero; + } + } + nData += len; + testcase( serial_type==127 ); + testcase( serial_type==128 ); + nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type); + if( pRec==pData0 ) break; + pRec--; + }while(1); + + /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint + ** which determines the total number of bytes in the header. The varint + ** value is the size of the header in bytes including the size varint + ** itself. */ + testcase( nHdr==126 ); + testcase( nHdr==127 ); + if( nHdr<=126 ){ + /* The common case */ + nHdr += 1; + }else{ + /* Rare case of a really large header */ + nVarint = sqlite3VarintLen(nHdr); + nHdr += nVarint; + if( nVarintdb->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; + } + + /* Make sure the output register has a buffer large enough to store + ** the new record. The output register (pOp->p3) is not allowed to + ** be one of the input registers (because the following call to + ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). + */ + if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ + goto no_mem; + } + zNewRecord = (u8 *)pOut->z; + + /* Write the record */ + i = putVarint32(zNewRecord, nHdr); + j = nHdr; + assert( pData0<=pLast ); + pRec = pData0; + do{ + serial_type = pRec->uTemp; + /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more + ** additional varints, one per column. */ + i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ + /* EVIDENCE-OF: R-64536-51728 The values for each column in the record + ** immediately follow the header. */ + j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ + }while( (++pRec)<=pLast ); + assert( i==nHdr ); + assert( j==nByte ); + + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + pOut->n = (int)nByte; + pOut->flags = MEM_Blob; + if( nZero ){ + pOut->u.nZero = nZero; + pOut->flags |= MEM_Zero; + } + REGISTER_TRACE(pOp->p3, pOut); + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + +/* Opcode: Count P1 P2 * * * +** Synopsis: r[P2]=count() +** +** Store the number of entries (an integer value) in the table or index +** opened by cursor P1 in register P2 +*/ +#ifndef SQLITE_OMIT_BTREECOUNT +case OP_Count: { /* out2 */ + i64 nEntry; + BtCursor *pCrsr; + + assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE ); + pCrsr = p->apCsr[pOp->p1]->uc.pCursor; + assert( pCrsr ); + nEntry = 0; /* Not needed. Only used to silence a warning. */ + rc = sqlite3BtreeCount(pCrsr, &nEntry); + if( rc ) goto abort_due_to_error; + pOut = out2Prerelease(p, pOp); + pOut->u.i = nEntry; + break; +} +#endif + +/* Opcode: Savepoint P1 * * P4 * +** +** Open, release or rollback the savepoint named by parameter P4, depending +** on the value of P1. To open a new savepoint, P1==0. To release (commit) an +** existing savepoint, P1==1, or to rollback an existing savepoint P1==2. +*/ +case OP_Savepoint: { + int p1; /* Value of P1 operand */ + char *zName; /* Name of savepoint */ + int nName; + Savepoint *pNew; + Savepoint *pSavepoint; + Savepoint *pTmp; + int iSavepoint; + int ii; + + p1 = pOp->p1; + zName = pOp->p4.z; + + /* Assert that the p1 parameter is valid. Also that if there is no open + ** transaction, then there cannot be any savepoints. + */ + assert( db->pSavepoint==0 || db->autoCommit==0 ); + assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK ); + assert( db->pSavepoint || db->isTransactionSavepoint==0 ); + assert( checkSavepointCount(db) ); + assert( p->bIsReader ); + + if( p1==SAVEPOINT_BEGIN ){ + if( db->nVdbeWrite>0 ){ + /* A new savepoint cannot be created if there are active write + ** statements (i.e. open read/write incremental blob handles). + */ + sqlite3VdbeError(p, "cannot open savepoint - SQL statements in progress"); + rc = SQLITE_BUSY; + }else{ + nName = sqlite3Strlen30(zName); + +#ifndef SQLITE_OMIT_VIRTUALTABLE + /* This call is Ok even if this savepoint is actually a transaction + ** savepoint (and therefore should not prompt xSavepoint()) callbacks. + ** If this is a transaction savepoint being opened, it is guaranteed + ** that the db->aVTrans[] array is empty. */ + assert( db->autoCommit==0 || db->nVTrans==0 ); + rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, + db->nStatement+db->nSavepoint); + if( rc!=SQLITE_OK ) goto abort_due_to_error; +#endif + + /* Create a new savepoint structure. */ + pNew = sqlite3DbMallocRawNN(db, sizeof(Savepoint)+nName+1); + if( pNew ){ + pNew->zName = (char *)&pNew[1]; + memcpy(pNew->zName, zName, nName+1); + + /* If there is no open transaction, then mark this as a special + ** "transaction savepoint". */ + if( db->autoCommit ){ + db->autoCommit = 0; + db->isTransactionSavepoint = 1; + }else{ + db->nSavepoint++; + } + + /* Link the new savepoint into the database handle's list. */ + pNew->pNext = db->pSavepoint; + db->pSavepoint = pNew; + pNew->nDeferredCons = db->nDeferredCons; + pNew->nDeferredImmCons = db->nDeferredImmCons; + } + } + }else{ + iSavepoint = 0; + + /* Find the named savepoint. If there is no such savepoint, then an + ** an error is returned to the user. */ + for( + pSavepoint = db->pSavepoint; + pSavepoint && sqlite3StrICmp(pSavepoint->zName, zName); + pSavepoint = pSavepoint->pNext + ){ + iSavepoint++; + } + if( !pSavepoint ){ + sqlite3VdbeError(p, "no such savepoint: %s", zName); + rc = SQLITE_ERROR; + }else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){ + /* It is not possible to release (commit) a savepoint if there are + ** active write statements. + */ + sqlite3VdbeError(p, "cannot release savepoint - " + "SQL statements in progress"); + rc = SQLITE_BUSY; + }else{ + + /* Determine whether or not this is a transaction savepoint. If so, + ** and this is a RELEASE command, then the current transaction + ** is committed. + */ + int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; + if( isTransaction && p1==SAVEPOINT_RELEASE ){ + if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ + goto vdbe_return; + } + db->autoCommit = 1; + if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ + p->pc = (int)(pOp - aOp); + db->autoCommit = 0; + p->rc = rc = SQLITE_BUSY; + goto vdbe_return; + } + db->isTransactionSavepoint = 0; + rc = p->rc; + }else{ + int isSchemaChange; + iSavepoint = db->nSavepoint - iSavepoint - 1; + if( p1==SAVEPOINT_ROLLBACK ){ + isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; + for(ii=0; iinDb; ii++){ + rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, + SQLITE_ABORT_ROLLBACK, + isSchemaChange==0); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + } + }else{ + isSchemaChange = 0; + } + for(ii=0; iinDb; ii++){ + rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + } + if( isSchemaChange ){ + sqlite3ExpirePreparedStatements(db); + sqlite3ResetAllSchemasOfConnection(db); + db->flags = (db->flags | SQLITE_InternChanges); + } + } + + /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all + ** savepoints nested inside of the savepoint being operated on. */ + while( db->pSavepoint!=pSavepoint ){ + pTmp = db->pSavepoint; + db->pSavepoint = pTmp->pNext; + sqlite3DbFree(db, pTmp); + db->nSavepoint--; + } + + /* If it is a RELEASE, then destroy the savepoint being operated on + ** too. If it is a ROLLBACK TO, then set the number of deferred + ** constraint violations present in the database to the value stored + ** when the savepoint was created. */ + if( p1==SAVEPOINT_RELEASE ){ + assert( pSavepoint==db->pSavepoint ); + db->pSavepoint = pSavepoint->pNext; + sqlite3DbFree(db, pSavepoint); + if( !isTransaction ){ + db->nSavepoint--; + } + }else{ + db->nDeferredCons = pSavepoint->nDeferredCons; + db->nDeferredImmCons = pSavepoint->nDeferredImmCons; + } + + if( !isTransaction || p1==SAVEPOINT_ROLLBACK ){ + rc = sqlite3VtabSavepoint(db, p1, iSavepoint); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + } + } + } + if( rc ) goto abort_due_to_error; + + break; +} + +/* Opcode: AutoCommit P1 P2 * * * +** +** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll +** back any currently active btree transactions. If there are any active +** VMs (apart from this one), then a ROLLBACK fails. A COMMIT fails if +** there are active writing VMs or active VMs that use shared cache. +** +** This instruction causes the VM to halt. +*/ +case OP_AutoCommit: { + int desiredAutoCommit; + int iRollback; + + desiredAutoCommit = pOp->p1; + iRollback = pOp->p2; + assert( desiredAutoCommit==1 || desiredAutoCommit==0 ); + assert( desiredAutoCommit==1 || iRollback==0 ); + assert( db->nVdbeActive>0 ); /* At least this one VM is active */ + assert( p->bIsReader ); + + if( desiredAutoCommit!=db->autoCommit ){ + if( iRollback ){ + assert( desiredAutoCommit==1 ); + sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); + db->autoCommit = 1; + }else if( desiredAutoCommit && db->nVdbeWrite>0 ){ + /* If this instruction implements a COMMIT and other VMs are writing + ** return an error indicating that the other VMs must complete first. + */ + sqlite3VdbeError(p, "cannot commit transaction - " + "SQL statements in progress"); + rc = SQLITE_BUSY; + goto abort_due_to_error; + }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ + goto vdbe_return; + }else{ + db->autoCommit = (u8)desiredAutoCommit; + } + if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ + p->pc = (int)(pOp - aOp); + db->autoCommit = (u8)(1-desiredAutoCommit); + p->rc = rc = SQLITE_BUSY; + goto vdbe_return; + } + assert( db->nStatement==0 ); + sqlite3CloseSavepoints(db); + if( p->rc==SQLITE_OK ){ + rc = SQLITE_DONE; + }else{ + rc = SQLITE_ERROR; + } + goto vdbe_return; + }else{ + sqlite3VdbeError(p, + (!desiredAutoCommit)?"cannot start a transaction within a transaction":( + (iRollback)?"cannot rollback - no transaction is active": + "cannot commit - no transaction is active")); + + rc = SQLITE_ERROR; + goto abort_due_to_error; + } + break; +} + +/* Opcode: Transaction P1 P2 P3 P4 P5 +** +** Begin a transaction on database P1 if a transaction is not already +** active. +** If P2 is non-zero, then a write-transaction is started, or if a +** read-transaction is already active, it is upgraded to a write-transaction. +** If P2 is zero, then a read-transaction is started. +** +** P1 is the index of the database file on which the transaction is +** started. Index 0 is the main database file and index 1 is the +** file used for temporary tables. Indices of 2 or more are used for +** attached databases. +** +** If a write-transaction is started and the Vdbe.usesStmtJournal flag is +** true (this flag is set if the Vdbe may modify more than one row and may +** throw an ABORT exception), a statement transaction may also be opened. +** More specifically, a statement transaction is opened iff the database +** connection is currently not in autocommit mode, or if there are other +** active statements. A statement transaction allows the changes made by this +** VDBE to be rolled back after an error without having to roll back the +** entire transaction. If no error is encountered, the statement transaction +** will automatically commit when the VDBE halts. +** +** If P5!=0 then this opcode also checks the schema cookie against P3 +** and the schema generation counter against P4. +** The cookie changes its value whenever the database schema changes. +** This operation is used to detect when that the cookie has changed +** and that the current process needs to reread the schema. If the schema +** cookie in P3 differs from the schema cookie in the database header or +** if the schema generation counter in P4 differs from the current +** generation counter, then an SQLITE_SCHEMA error is raised and execution +** halts. The sqlite3_step() wrapper function might then reprepare the +** statement and rerun it from the beginning. +*/ +case OP_Transaction: { + Btree *pBt; + int iMeta; + int iGen; + + assert( p->bIsReader ); + assert( p->readOnly==0 || pOp->p2==0 ); + assert( pOp->p1>=0 && pOp->p1nDb ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); + if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ + rc = SQLITE_READONLY; + goto abort_due_to_error; + } + pBt = db->aDb[pOp->p1].pBt; + + if( pBt ){ + rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); + testcase( rc==SQLITE_BUSY_SNAPSHOT ); + testcase( rc==SQLITE_BUSY_RECOVERY ); + if( rc!=SQLITE_OK ){ + if( (rc&0xff)==SQLITE_BUSY ){ + p->pc = (int)(pOp - aOp); + p->rc = rc; + goto vdbe_return; + } + goto abort_due_to_error; + } + + if( pOp->p2 && p->usesStmtJournal + && (db->autoCommit==0 || db->nVdbeRead>1) + ){ + assert( sqlite3BtreeIsInTrans(pBt) ); + if( p->iStatement==0 ){ + assert( db->nStatement>=0 && db->nSavepoint>=0 ); + db->nStatement++; + p->iStatement = db->nSavepoint + db->nStatement; + } + + rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); + } + + /* Store the current value of the database handles deferred constraint + ** counter. If the statement transaction needs to be rolled back, + ** the value of this counter needs to be restored too. */ + p->nStmtDefCons = db->nDeferredCons; + p->nStmtDefImmCons = db->nDeferredImmCons; + } + + /* Gather the schema version number for checking: + ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema + ** version is checked to ensure that the schema has not changed since the + ** SQL statement was prepared. + */ + sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); + iGen = db->aDb[pOp->p1].pSchema->iGeneration; + }else{ + iGen = iMeta = 0; + } + assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); + if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){ + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); + /* If the schema-cookie from the database file matches the cookie + ** stored with the in-memory representation of the schema, do + ** not reload the schema from the database file. + ** + ** If virtual-tables are in use, this is not just an optimization. + ** Often, v-tables store their data in other SQLite tables, which + ** are queried from within xNext() and other v-table methods using + ** prepared queries. If such a query is out-of-date, we do not want to + ** discard the database schema, as the user code implementing the + ** v-table would have to be ready for the sqlite3_vtab structure itself + ** to be invalidated whenever sqlite3_step() is called from within + ** a v-table method. + */ + if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ + sqlite3ResetOneSchema(db, pOp->p1); + } + p->expired = 1; + rc = SQLITE_SCHEMA; + } + if( rc ) goto abort_due_to_error; + break; +} + +/* Opcode: ReadCookie P1 P2 P3 * * +** +** Read cookie number P3 from database P1 and write it into register P2. +** P3==1 is the schema version. P3==2 is the database format. +** P3==3 is the recommended pager cache size, and so forth. P1==0 is +** the main database file and P1==1 is the database file used to store +** temporary tables. +** +** There must be a read-lock on the database (either a transaction +** must be started or there must be an open cursor) before +** executing this instruction. +*/ +case OP_ReadCookie: { /* out2 */ + int iMeta; + int iDb; + int iCookie; + + assert( p->bIsReader ); + iDb = pOp->p1; + iCookie = pOp->p3; + assert( pOp->p3=0 && iDbnDb ); + assert( db->aDb[iDb].pBt!=0 ); + assert( DbMaskTest(p->btreeMask, iDb) ); + + sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); + pOut = out2Prerelease(p, pOp); + pOut->u.i = iMeta; + break; +} + +/* Opcode: SetCookie P1 P2 P3 * * +** +** Write the integer value P3 into cookie number P2 of database P1. +** P2==1 is the schema version. P2==2 is the database format. +** P2==3 is the recommended pager cache +** size, and so forth. P1==0 is the main database file and P1==1 is the +** database file used to store temporary tables. +** +** A transaction must be started before executing this opcode. +*/ +case OP_SetCookie: { + Db *pDb; + assert( pOp->p2p1>=0 && pOp->p1nDb ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); + assert( p->readOnly==0 ); + pDb = &db->aDb[pOp->p1]; + assert( pDb->pBt!=0 ); + assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); + /* See note about index shifting on OP_ReadCookie */ + rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3); + if( pOp->p2==BTREE_SCHEMA_VERSION ){ + /* When the schema cookie changes, record the new cookie internally */ + pDb->pSchema->schema_cookie = pOp->p3; + db->flags |= SQLITE_InternChanges; + }else if( pOp->p2==BTREE_FILE_FORMAT ){ + /* Record changes in the file format */ + pDb->pSchema->file_format = pOp->p3; + } + if( pOp->p1==1 ){ + /* Invalidate all prepared statements whenever the TEMP database + ** schema is changed. Ticket #1644 */ + sqlite3ExpirePreparedStatements(db); + p->expired = 0; + } + if( rc ) goto abort_due_to_error; + break; +} + +/* Opcode: OpenRead P1 P2 P3 P4 P5 +** Synopsis: root=P2 iDb=P3 +** +** Open a read-only cursor for the database table whose root page is +** P2 in a database file. The database file is determined by P3. +** P3==0 means the main database, P3==1 means the database used for +** temporary tables, and P3>1 means used the corresponding attached +** database. Give the new cursor an identifier of P1. The P1 +** values need not be contiguous but all P1 values should be small integers. +** It is an error for P1 to be negative. +** +** If P5!=0 then use the content of register P2 as the root page, not +** the value of P2 itself. +** +** There will be a read lock on the database whenever there is an +** open cursor. If the database was unlocked prior to this instruction +** then a read lock is acquired as part of this instruction. A read +** lock allows other processes to read the database but prohibits +** any other process from modifying the database. The read lock is +** released when all cursors are closed. If this instruction attempts +** to get a read lock but fails, the script terminates with an +** SQLITE_BUSY error code. +** +** The P4 value may be either an integer (P4_INT32) or a pointer to +** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo +** structure, then said structure defines the content and collating +** sequence of the index being opened. Otherwise, if P4 is an integer +** value, it is set to the number of columns in the table. +** +** See also: OpenWrite, ReopenIdx +*/ +/* Opcode: ReopenIdx P1 P2 P3 P4 P5 +** Synopsis: root=P2 iDb=P3 +** +** The ReopenIdx opcode works exactly like ReadOpen except that it first +** checks to see if the cursor on P1 is already open with a root page +** number of P2 and if it is this opcode becomes a no-op. In other words, +** if the cursor is already open, do not reopen it. +** +** The ReopenIdx opcode may only be used with P5==0 and with P4 being +** a P4_KEYINFO object. Furthermore, the P3 value must be the same as +** every other ReopenIdx or OpenRead for the same cursor number. +** +** See the OpenRead opcode documentation for additional information. +*/ +/* Opcode: OpenWrite P1 P2 P3 P4 P5 +** Synopsis: root=P2 iDb=P3 +** +** Open a read/write cursor named P1 on the table or index whose root +** page is P2. Or if P5!=0 use the content of register P2 to find the +** root page. +** +** The P4 value may be either an integer (P4_INT32) or a pointer to +** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo +** structure, then said structure defines the content and collating +** sequence of the index being opened. Otherwise, if P4 is an integer +** value, it is set to the number of columns in the table, or to the +** largest index of any column of the table that is actually used. +** +** This instruction works just like OpenRead except that it opens the cursor +** in read/write mode. For a given table, there can be one or more read-only +** cursors or a single read/write cursor but not both. +** +** See also OpenRead. +*/ +case OP_ReopenIdx: { + int nField; + KeyInfo *pKeyInfo; + int p2; + int iDb; + int wrFlag; + Btree *pX; + VdbeCursor *pCur; + Db *pDb; + + assert( pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); + assert( pOp->p4type==P4_KEYINFO ); + pCur = p->apCsr[pOp->p1]; + if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ + assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ + goto open_cursor_set_hints; + } + /* If the cursor is not currently open or is open on a different + ** index, then fall through into OP_OpenRead to force a reopen */ +case OP_OpenRead: +case OP_OpenWrite: + + assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); + assert( p->bIsReader ); + assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx + || p->readOnly==0 ); + + if( p->expired ){ + rc = SQLITE_ABORT_ROLLBACK; + goto abort_due_to_error; + } + + nField = 0; + pKeyInfo = 0; + p2 = pOp->p2; + iDb = pOp->p3; + assert( iDb>=0 && iDbnDb ); + assert( DbMaskTest(p->btreeMask, iDb) ); + pDb = &db->aDb[iDb]; + pX = pDb->pBt; + assert( pX!=0 ); + if( pOp->opcode==OP_OpenWrite ){ + assert( OPFLAG_FORDELETE==BTREE_FORDELETE ); + wrFlag = BTREE_WRCSR | (pOp->p5 & OPFLAG_FORDELETE); + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( pDb->pSchema->file_format < p->minWriteFileFormat ){ + p->minWriteFileFormat = pDb->pSchema->file_format; + } + }else{ + wrFlag = 0; + } + if( pOp->p5 & OPFLAG_P2ISREG ){ + assert( p2>0 ); + assert( p2<=(p->nMem+1 - p->nCursor) ); + pIn2 = &aMem[p2]; + assert( memIsValid(pIn2) ); + 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 + ** 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. */ + assert( p2>=2 ); + } + if( pOp->p4type==P4_KEYINFO ){ + pKeyInfo = pOp->p4.pKeyInfo; + assert( pKeyInfo->enc==ENC(db) ); + assert( pKeyInfo->db==db ); + nField = pKeyInfo->nField+pKeyInfo->nXField; + }else if( pOp->p4type==P4_INT32 ){ + nField = pOp->p4.i; + } + assert( pOp->p1>=0 ); + assert( nField>=0 ); + testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ + pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE); + if( pCur==0 ) goto no_mem; + pCur->nullRow = 1; + pCur->isOrdered = 1; + pCur->pgnoRoot = p2; +#ifdef SQLITE_DEBUG + pCur->wrFlag = wrFlag; +#endif + rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor); + pCur->pKeyInfo = pKeyInfo; + /* Set the VdbeCursor.isTable variable. Previous versions of + ** SQLite used to check if the root-page flags were sane at this point + ** and report database corruption if they were not, but this check has + ** since moved into the btree layer. */ + pCur->isTable = pOp->p4type!=P4_KEYINFO; + +open_cursor_set_hints: + assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); + assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ ); + testcase( pOp->p5 & OPFLAG_BULKCSR ); +#ifdef SQLITE_ENABLE_CURSOR_HINTS + testcase( pOp->p2 & OPFLAG_SEEKEQ ); +#endif + sqlite3BtreeCursorHintFlags(pCur->uc.pCursor, + (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); + if( rc ) goto abort_due_to_error; + break; +} + +/* Opcode: OpenDup P1 P2 * * * +** +** Open a new cursor P1 that points to the same ephemeral table as +** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral +** opcode. Only ephemeral cursors may be duplicated. +** +** Duplicate ephemeral cursors are used for self-joins of materialized views. +*/ +case OP_OpenDup: { + VdbeCursor *pOrig; /* The original cursor to be duplicated */ + VdbeCursor *pCx; /* The new cursor */ + + pOrig = p->apCsr[pOp->p2]; + assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */ + + pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE); + if( pCx==0 ) goto no_mem; + pCx->nullRow = 1; + pCx->isEphemeral = 1; + pCx->pKeyInfo = pOrig->pKeyInfo; + pCx->isTable = pOrig->isTable; + rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR, + pCx->pKeyInfo, pCx->uc.pCursor); + /* The sqlite3BtreeCursor() routine can only fail for the first cursor + ** opened for a database. Since there is already an open cursor when this + ** opcode is run, the sqlite3BtreeCursor() cannot fail */ + assert( rc==SQLITE_OK ); + break; +} + + +/* Opcode: OpenEphemeral P1 P2 * P4 P5 +** Synopsis: nColumn=P2 +** +** Open a new cursor P1 to a transient table. +** The cursor is always opened read/write even if +** the main database is read-only. The ephemeral +** table is deleted automatically when the cursor is closed. +** +** P2 is the number of columns in the ephemeral table. +** The cursor points to a BTree table if P4==0 and to a BTree index +** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure +** that defines the format of keys in the index. +** +** The P5 parameter can be a mask of the BTREE_* flags defined +** in btree.h. These flags control aspects of the operation of +** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are +** added automatically. +*/ +/* Opcode: OpenAutoindex P1 P2 * P4 * +** Synopsis: nColumn=P2 +** +** This opcode works the same as OP_OpenEphemeral. It has a +** different name to distinguish its use. Tables created using +** by this opcode will be used for automatically created transient +** indices in joins. +*/ +case OP_OpenAutoindex: +case OP_OpenEphemeral: { + VdbeCursor *pCx; + KeyInfo *pKeyInfo; + + static const int vfsFlags = + SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | + SQLITE_OPEN_DELETEONCLOSE | + SQLITE_OPEN_TRANSIENT_DB; + assert( pOp->p1>=0 ); + assert( pOp->p2>=0 ); + pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE); + if( pCx==0 ) goto no_mem; + pCx->nullRow = 1; + pCx->isEphemeral = 1; + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, + BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1); + } + if( rc==SQLITE_OK ){ + /* If a transient index is required, create it by calling + ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before + ** opening it. If a transient table is required, just use the + ** automatically created table with root-page 1 (an BLOB_INTKEY table). + */ + if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ + int pgno; + assert( pOp->p4type==P4_KEYINFO ); + rc = sqlite3BtreeCreateTable(pCx->pBtx, &pgno, BTREE_BLOBKEY | pOp->p5); + if( rc==SQLITE_OK ){ + assert( pgno==MASTER_ROOT+1 ); + assert( pKeyInfo->db==db ); + assert( pKeyInfo->enc==ENC(db) ); + rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR, + pKeyInfo, pCx->uc.pCursor); + } + pCx->isTable = 0; + }else{ + rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR, + 0, pCx->uc.pCursor); + pCx->isTable = 1; + } + } + if( rc ) goto abort_due_to_error; + pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); + break; +} + +/* Opcode: SorterOpen P1 P2 P3 P4 * +** +** This opcode works like OP_OpenEphemeral except that it opens +** a transient index that is specifically designed to sort large +** tables using an external merge-sort algorithm. +** +** If argument P3 is non-zero, then it indicates that the sorter may +** assume that a stable sort considering the first P3 fields of each +** key is sufficient to produce the required results. +*/ +case OP_SorterOpen: { + VdbeCursor *pCx; + + assert( pOp->p1>=0 ); + assert( pOp->p2>=0 ); + pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER); + if( pCx==0 ) goto no_mem; + pCx->pKeyInfo = pOp->p4.pKeyInfo; + assert( pCx->pKeyInfo->db==db ); + assert( pCx->pKeyInfo->enc==ENC(db) ); + rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx); + if( rc ) goto abort_due_to_error; + break; +} + +/* Opcode: SequenceTest P1 P2 * * * +** Synopsis: if( cursor[P1].ctr++ ) pc = P2 +** +** P1 is a sorter cursor. If the sequence counter is currently zero, jump +** to P2. Regardless of whether or not the jump is taken, increment the +** the sequence value. +*/ +case OP_SequenceTest: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( isSorter(pC) ); + if( (pC->seqCount++)==0 ){ + goto jump_to_p2; + } + break; +} + +/* Opcode: OpenPseudo P1 P2 P3 * * +** Synopsis: P3 columns in r[P2] +** +** Open a new cursor that points to a fake table that contains a single +** row of data. The content of that one row is the content of memory +** register P2. In other words, cursor P1 becomes an alias for the +** MEM_Blob content contained in register P2. +** +** A pseudo-table created by this opcode is used to hold a single +** row output from the sorter so that the row can be decomposed into +** individual columns using the OP_Column opcode. The OP_Column opcode +** is the only cursor opcode that works with a pseudo-table. +** +** P3 is the number of fields in the records that will be stored by +** the pseudo-table. +*/ +case OP_OpenPseudo: { + VdbeCursor *pCx; + + assert( pOp->p1>=0 ); + assert( pOp->p3>=0 ); + 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->isTable = 1; + assert( pOp->p5==0 ); + break; +} + +/* Opcode: Close P1 * * * * +** +** Close a cursor previously opened as P1. If P1 is not +** currently open, this instruction is a no-op. +*/ +case OP_Close: { + assert( pOp->p1>=0 && pOp->p1nCursor ); + sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]); + p->apCsr[pOp->p1] = 0; + break; +} + +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK +/* Opcode: ColumnsUsed P1 * * P4 * +** +** This opcode (which only exists if SQLite was compiled with +** SQLITE_ENABLE_COLUMN_USED_MASK) identifies which columns of the +** table or index for cursor P1 are used. P4 is a 64-bit integer +** (P4_INT64) in which the first 63 bits are one for each of the +** first 63 columns of the table or index that are actually used +** by the cursor. The high-order bit is set if any column after +** the 64th is used. +*/ +case OP_ColumnsUsed: { + VdbeCursor *pC; + pC = p->apCsr[pOp->p1]; + assert( pC->eCurType==CURTYPE_BTREE ); + pC->maskUsed = *(u64*)pOp->p4.pI64; + break; +} +#endif + +/* Opcode: SeekGE P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as the key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. +** +** Reposition cursor P1 so that it points to the smallest entry that +** is greater than or equal to the key value. If there are no records +** greater than or equal to the key and P2 is not zero, then jump to P2. +** +** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this +** opcode will always land on a record that equally equals the key, or +** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this +** opcode must be followed by an IdxLE opcode with the same arguments. +** The IdxLE opcode will be skipped if this opcode succeeds, but the +** IdxLE opcode will be used on subsequent loop iterations. +** +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. +** +** See also: Found, NotFound, SeekLt, SeekGt, SeekLe +*/ +/* Opcode: SeekGT P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. +** +** Reposition cursor P1 so that it points to the smallest entry that +** is greater than the key value. If there are no records greater than +** the key and P2 is not zero, then jump to P2. +** +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. +** +** See also: Found, NotFound, SeekLt, SeekGe, SeekLe +*/ +/* Opcode: SeekLT P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. +** +** Reposition cursor P1 so that it points to the largest entry that +** is less than the key value. If there are no records less than +** the key and P2 is not zero, then jump to P2. +** +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. +** +** See also: Found, NotFound, SeekGt, SeekGe, SeekLe +*/ +/* Opcode: SeekLE P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. +** +** Reposition cursor P1 so that it points to the largest entry that +** is less than or equal to the key value. If there are no records +** less than or equal to the key and P2 is not zero, then jump to P2. +** +** This opcode leaves the cursor configured to move in reverse order, +** from the end toward the beginning. In other words, the cursor is +** configured to use Prev, not Next. +** +** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this +** opcode will always land on a record that equally equals the key, or +** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this +** opcode must be followed by an IdxGE opcode with the same arguments. +** The IdxGE opcode will be skipped if this opcode succeeds, but the +** IdxGE opcode will be used on subsequent loop iterations. +** +** See also: Found, NotFound, SeekGt, SeekGe, SeekLt +*/ +case OP_SeekLT: /* jump, in3 */ +case OP_SeekLE: /* jump, in3 */ +case OP_SeekGE: /* jump, in3 */ +case OP_SeekGT: { /* jump, in3 */ + int res; /* Comparison result */ + int oc; /* Opcode */ + VdbeCursor *pC; /* The cursor to seek */ + UnpackedRecord r; /* The key to seek for */ + int nField; /* Number of columns or fields in the key */ + i64 iKey; /* The rowid we are to seek to */ + int eqOnly; /* Only interested in == results */ + + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pOp->p2!=0 ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( OP_SeekLE == OP_SeekLT+1 ); + assert( OP_SeekGE == OP_SeekLT+2 ); + assert( OP_SeekGT == OP_SeekLT+3 ); + assert( pC->isOrdered ); + assert( pC->uc.pCursor!=0 ); + oc = pOp->opcode; + eqOnly = 0; + pC->nullRow = 0; +#ifdef SQLITE_DEBUG + pC->seekOp = pOp->opcode; +#endif + + if( pC->isTable ){ + /* The BTREE_SEEK_EQ flag is only set on index cursors */ + assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 + || CORRUPT_DB ); + + /* The input value in P3 might be of any type: integer, real, string, + ** blob, or NULL. But it needs to be an integer before we can do + ** the seek, so convert it. */ + pIn3 = &aMem[pOp->p3]; + if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + applyNumericAffinity(pIn3, 0); + } + iKey = sqlite3VdbeIntValue(pIn3); + + /* If the P3 value could not be converted into an integer without + ** loss of information, then special processing is required... */ + if( (pIn3->flags & MEM_Int)==0 ){ + if( (pIn3->flags & MEM_Real)==0 ){ + /* If the P3 value cannot be converted into any kind of a number, + ** then the seek is not possible, so jump to P2 */ + VdbeBranchTaken(1,2); goto jump_to_p2; + break; + } + + /* If the approximation iKey is larger than the actual real search + ** term, substitute >= for > and < for <=. e.g. if the search term + ** is 4.9 and the integer approximation 5: + ** + ** (x > 4.9) -> (x >= 5) + ** (x <= 4.9) -> (x < 5) + */ + if( pIn3->u.r<(double)iKey ){ + assert( OP_SeekGE==(OP_SeekGT-1) ); + assert( OP_SeekLT==(OP_SeekLE-1) ); + assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); + if( (oc & 0x0001)==(OP_SeekGT & 0x0001) ) oc--; + } + + /* If the approximation iKey is smaller than the actual real search + ** term, substitute <= for < and > for >=. */ + else if( pIn3->u.r>(double)iKey ){ + assert( OP_SeekLE==(OP_SeekLT+1) ); + assert( OP_SeekGT==(OP_SeekGE+1) ); + assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); + if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; + } + } + rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res); + pC->movetoTarget = iKey; /* Used by OP_Delete */ + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + }else{ + /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and + ** OP_SeekLE opcodes are allowed, and these must be immediately followed + ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key. + */ + if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){ + eqOnly = 1; + assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE ); + assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); + assert( pOp[1].p1==pOp[0].p1 ); + assert( pOp[1].p2==pOp[0].p2 ); + assert( pOp[1].p3==pOp[0].p3 ); + assert( pOp[1].p4.i==pOp[0].p4.i ); + } + + nField = pOp->p4.i; + assert( pOp->p4type==P4_INT32 ); + assert( nField>0 ); + r.pKeyInfo = pC->pKeyInfo; + r.nField = (u16)nField; + + /* The next line of code computes as follows, only faster: + ** if( oc==OP_SeekGT || oc==OP_SeekLE ){ + ** r.default_rc = -1; + ** }else{ + ** r.default_rc = +1; + ** } + */ + r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1); + assert( oc!=OP_SeekGT || r.default_rc==-1 ); + assert( oc!=OP_SeekLE || r.default_rc==-1 ); + assert( oc!=OP_SeekGE || r.default_rc==+1 ); + assert( oc!=OP_SeekLT || r.default_rc==+1 ); + + r.aMem = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + { int i; for(i=0; iuc.pCursor, &r, 0, 0, &res); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + if( eqOnly && r.eqSeen==0 ){ + assert( res!=0 ); + goto seek_not_found; + } + } + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; +#ifdef SQLITE_TEST + sqlite3_search_count++; +#endif + if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); + if( res<0 || (res==0 && oc==OP_SeekGT) ){ + res = 0; + rc = sqlite3BtreeNext(pC->uc.pCursor, &res); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + }else{ + res = 0; + } + }else{ + assert( oc==OP_SeekLT || oc==OP_SeekLE ); + if( res>0 || (res==0 && oc==OP_SeekLT) ){ + res = 0; + rc = sqlite3BtreePrevious(pC->uc.pCursor, &res); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + }else{ + /* res might be negative because the table is empty. Check to + ** see if this is the case. + */ + res = sqlite3BtreeEof(pC->uc.pCursor); + } + } +seek_not_found: + assert( pOp->p2>0 ); + VdbeBranchTaken(res!=0,2); + if( res ){ + goto jump_to_p2; + }else if( eqOnly ){ + assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); + pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */ + } + break; +} + +/* Opcode: Found P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** If P4==0 then register P3 holds a blob constructed by MakeRecord. If +** P4>0 then register P3 is the first of P4 registers that form an unpacked +** record. +** +** Cursor P1 is on an index btree. If the record identified by P3 and P4 +** is a prefix of any entry in P1 then a jump is made to P2 and +** P1 is left pointing at the matching entry. +** +** This operation leaves the cursor in a state where it can be +** advanced in the forward direction. The Next instruction will work, +** but not the Prev instruction. +** +** See also: NotFound, NoConflict, NotExists. SeekGe +*/ +/* Opcode: NotFound P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** If P4==0 then register P3 holds a blob constructed by MakeRecord. If +** P4>0 then register P3 is the first of P4 registers that form an unpacked +** record. +** +** Cursor P1 is on an index btree. If the record identified by P3 and P4 +** is not the prefix of any entry in P1 then a jump is made to P2. If P1 +** does contain an entry whose prefix matches the P3/P4 record then control +** falls through to the next instruction and P1 is left pointing at the +** matching entry. +** +** This operation leaves the cursor in a state where it cannot be +** advanced in either direction. In other words, the Next and Prev +** opcodes do not work after this operation. +** +** See also: Found, NotExists, NoConflict +*/ +/* Opcode: NoConflict P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** If P4==0 then register P3 holds a blob constructed by MakeRecord. If +** P4>0 then register P3 is the first of P4 registers that form an unpacked +** record. +** +** Cursor P1 is on an index btree. If the record identified by P3 and P4 +** contains any NULL value, jump immediately to P2. If all terms of the +** record are not-NULL then a check is done to determine if any row in the +** P1 index btree has a matching key prefix. If there are no matches, jump +** immediately to P2. If there is a match, fall through and leave the P1 +** cursor pointing to the matching row. +** +** This opcode is similar to OP_NotFound with the exceptions that the +** branch is always taken if any part of the search key input is NULL. +** +** This operation leaves the cursor in a state where it cannot be +** advanced in either direction. In other words, the Next and Prev +** opcodes do not work after this operation. +** +** See also: NotFound, Found, NotExists +*/ +case OP_NoConflict: /* jump, in3 */ +case OP_NotFound: /* jump, in3 */ +case OP_Found: { /* jump, in3 */ + int alreadyExists; + int takeJump; + int ii; + VdbeCursor *pC; + int res; + UnpackedRecord *pFree; + UnpackedRecord *pIdxKey; + UnpackedRecord r; + +#ifdef SQLITE_TEST + if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++; +#endif + + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pOp->p4type==P4_INT32 ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); +#ifdef SQLITE_DEBUG + pC->seekOp = pOp->opcode; +#endif + pIn3 = &aMem[pOp->p3]; + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + assert( pC->isTable==0 ); + if( pOp->p4.i>0 ){ + r.pKeyInfo = pC->pKeyInfo; + r.nField = (u16)pOp->p4.i; + r.aMem = pIn3; +#ifdef SQLITE_DEBUG + for(ii=0; iip3+ii, &r.aMem[ii]); + } +#endif + pIdxKey = &r; + pFree = 0; + }else{ + assert( pIn3->flags & MEM_Blob ); + rc = ExpandBlob(pIn3); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc ) goto no_mem; + pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo); + if( pIdxKey==0 ) goto no_mem; + sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); + } + pIdxKey->default_rc = 0; + takeJump = 0; + if( pOp->opcode==OP_NoConflict ){ + /* For the OP_NoConflict opcode, take the jump if any of the + ** input fields are NULL, since any key with a NULL will not + ** conflict */ + for(ii=0; iinField; ii++){ + if( pIdxKey->aMem[ii].flags & MEM_Null ){ + takeJump = 1; + break; + } + } + } + rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res); + if( pFree ) sqlite3DbFreeNN(db, pFree); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + pC->seekResult = res; + alreadyExists = (res==0); + pC->nullRow = 1-alreadyExists; + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + if( pOp->opcode==OP_Found ){ + VdbeBranchTaken(alreadyExists!=0,2); + if( alreadyExists ) goto jump_to_p2; + }else{ + VdbeBranchTaken(takeJump||alreadyExists==0,2); + if( takeJump || !alreadyExists ) goto jump_to_p2; + } + break; +} + +/* Opcode: SeekRowid P1 P2 P3 * * +** Synopsis: intkey=r[P3] +** +** P1 is the index of a cursor open on an SQL table btree (with integer +** keys). If register P3 does not contain an integer or if P1 does not +** contain a record with rowid P3 then jump immediately to P2. +** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain +** a record with rowid P3 then +** leave the cursor pointing at that record and fall through to the next +** instruction. +** +** The OP_NotExists opcode performs the same operation, but with OP_NotExists +** the P3 register must be guaranteed to contain an integer value. With this +** opcode, register P3 might not contain an integer. +** +** The OP_NotFound opcode performs the same operation on index btrees +** (with arbitrary multi-value keys). +** +** This opcode leaves the cursor in a state where it cannot be advanced +** in either direction. In other words, the Next and Prev opcodes will +** not work following this opcode. +** +** See also: Found, NotFound, NoConflict, SeekRowid +*/ +/* Opcode: NotExists P1 P2 P3 * * +** Synopsis: intkey=r[P3] +** +** P1 is the index of a cursor open on an SQL table btree (with integer +** keys). P3 is an integer rowid. If P1 does not contain a record with +** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an +** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then +** leave the cursor pointing at that record and fall through to the next +** instruction. +** +** The OP_SeekRowid opcode performs the same operation but also allows the +** P3 register to contain a non-integer value, in which case the jump is +** always taken. This opcode requires that P3 always contain an integer. +** +** The OP_NotFound opcode performs the same operation on index btrees +** (with arbitrary multi-value keys). +** +** This opcode leaves the cursor in a state where it cannot be advanced +** in either direction. In other words, the Next and Prev opcodes will +** not work following this opcode. +** +** See also: Found, NotFound, NoConflict, SeekRowid +*/ +case OP_SeekRowid: { /* jump, in3 */ + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + u64 iKey; + + pIn3 = &aMem[pOp->p3]; + if( (pIn3->flags & MEM_Int)==0 ){ + applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); + if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2; + } + /* Fall through into OP_NotExists */ +case OP_NotExists: /* jump, in3 */ + pIn3 = &aMem[pOp->p3]; + assert( pIn3->flags & MEM_Int ); + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); +#ifdef SQLITE_DEBUG + pC->seekOp = 0; +#endif + assert( pC->isTable ); + assert( pC->eCurType==CURTYPE_BTREE ); + pCrsr = pC->uc.pCursor; + assert( pCrsr!=0 ); + res = 0; + iKey = pIn3->u.i; + rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); + assert( rc==SQLITE_OK || res==0 ); + pC->movetoTarget = iKey; /* Used by OP_Delete */ + pC->nullRow = 0; + pC->cacheStatus = CACHE_STALE; + pC->deferredMoveto = 0; + VdbeBranchTaken(res!=0,2); + pC->seekResult = res; + if( res!=0 ){ + assert( rc==SQLITE_OK ); + if( pOp->p2==0 ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + goto jump_to_p2; + } + } + if( rc ) goto abort_due_to_error; + break; +} + +/* Opcode: Sequence P1 P2 * * * +** Synopsis: r[P2]=cursor[P1].ctr++ +** +** Find the next available sequence number for cursor P1. +** Write the sequence number into register P2. +** The sequence number on the cursor is incremented after this +** instruction. +*/ +case OP_Sequence: { /* out2 */ + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( p->apCsr[pOp->p1]!=0 ); + assert( p->apCsr[pOp->p1]->eCurType!=CURTYPE_VTAB ); + pOut = out2Prerelease(p, pOp); + pOut->u.i = p->apCsr[pOp->p1]->seqCount++; + break; +} + + +/* Opcode: NewRowid P1 P2 P3 * * +** Synopsis: r[P2]=rowid +** +** Get a new integer record number (a.k.a "rowid") used as the key to a table. +** The record number is not previously used as a key in the database +** table that cursor P1 points to. The new record number is written +** written to register P2. +** +** If P3>0 then P3 is a register in the root frame of this VDBE that holds +** the largest previously generated record number. No new record numbers are +** allowed to be less than this value. When this value reaches its maximum, +** an SQLITE_FULL error is generated. The P3 register is updated with the ' +** generated record number. This P3 mechanism is used to help implement the +** AUTOINCREMENT feature. +*/ +case OP_NewRowid: { /* out2 */ + i64 v; /* The new rowid */ + VdbeCursor *pC; /* Cursor of table to get the new rowid */ + int res; /* Result of an sqlite3BtreeLast() */ + int cnt; /* Counter to limit the number of searches */ + Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ + VdbeFrame *pFrame; /* Root frame of VDBE */ + + v = 0; + res = 0; + pOut = out2Prerelease(p, pOp); + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + { + /* The next rowid or record number (different terms for the same + ** thing) is obtained in a two-step algorithm. + ** + ** First we attempt to find the largest existing rowid and add one + ** to that. But if the largest existing rowid is already the maximum + ** positive integer, we have to fall through to the second + ** probabilistic algorithm + ** + ** The second algorithm is to select a rowid at random and see if + ** it already exists in the table. If it does not exist, we have + ** succeeded. If the random rowid does exist, we select a new one + ** and try again, up to 100 times. + */ + assert( pC->isTable ); + +#ifdef SQLITE_32BIT_ROWID +# define MAX_ROWID 0x7fffffff +#else + /* Some compilers complain about constants of the form 0x7fffffffffffffff. + ** Others complain about 0x7ffffffffffffffffLL. The following macro seems + ** to provide the constant while making all compilers happy. + */ +# define MAX_ROWID (i64)( (((u64)0x7fffffff)<<32) | (u64)0xffffffff ) +#endif + + if( !pC->useRandomRowid ){ + rc = sqlite3BtreeLast(pC->uc.pCursor, &res); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + if( res ){ + v = 1; /* IMP: R-61914-48074 */ + }else{ + assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); + v = sqlite3BtreeIntegerKey(pC->uc.pCursor); + if( v>=MAX_ROWID ){ + pC->useRandomRowid = 1; + }else{ + v++; /* IMP: R-29538-34987 */ + } + } + } + +#ifndef SQLITE_OMIT_AUTOINCREMENT + if( pOp->p3 ){ + /* Assert that P3 is a valid memory cell. */ + assert( pOp->p3>0 ); + if( p->pFrame ){ + for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); + /* Assert that P3 is a valid memory cell. */ + assert( pOp->p3<=pFrame->nMem ); + pMem = &pFrame->aMem[pOp->p3]; + }else{ + /* Assert that P3 is a valid memory cell. */ + assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); + pMem = &aMem[pOp->p3]; + memAboutToChange(p, pMem); + } + assert( memIsValid(pMem) ); + + REGISTER_TRACE(pOp->p3, pMem); + sqlite3VdbeMemIntegerify(pMem); + assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ + if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ + rc = SQLITE_FULL; /* IMP: R-17817-00630 */ + goto abort_due_to_error; + } + if( vu.i+1 ){ + v = pMem->u.i + 1; + } + pMem->u.i = v; + } +#endif + if( pC->useRandomRowid ){ + /* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the + ** largest possible integer (9223372036854775807) then the database + ** engine starts picking positive candidate ROWIDs at random until + ** it finds one that is not previously used. */ + assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is + ** an AUTOINCREMENT table. */ + cnt = 0; + do{ + sqlite3_randomness(sizeof(v), &v); + v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ + }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v, + 0, &res))==SQLITE_OK) + && (res==0) + && (++cnt<100)); + if( rc ) goto abort_due_to_error; + if( res==0 ){ + rc = SQLITE_FULL; /* IMP: R-38219-53002 */ + goto abort_due_to_error; + } + assert( v>0 ); /* EV: R-40812-03570 */ + } + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + } + pOut->u.i = v; + break; +} + +/* Opcode: Insert P1 P2 P3 P4 P5 +** Synopsis: intkey=r[P3] data=r[P2] +** +** Write an entry into the table of cursor P1. A new entry is +** created if it doesn't already exist or the data for an existing +** entry is overwritten. The data is the value MEM_Blob stored in register +** number P2. The key is stored in register P3. The key must +** be a MEM_Int. +** +** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is +** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, +** then rowid is stored for subsequent return by the +** sqlite3_last_insert_rowid() function (otherwise it is unmodified). +** +** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might +** run faster by avoiding an unnecessary seek on cursor P1. However, +** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior +** seeks on the cursor or if the most recent seek used a key equal to P3. +** +** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an +** UPDATE operation. Otherwise (if the flag is clear) then this opcode +** is part of an INSERT operation. The difference is only important to +** the update hook. +** +** Parameter P4 may point to a Table structure, or may be NULL. If it is +** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked +** following a successful insert. +** +** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically +** allocated, then ownership of P2 is transferred to the pseudo-cursor +** and register P2 becomes ephemeral. If the cursor is changed, the +** value of register P2 will then change. Make sure this does not +** cause any problems.) +** +** This instruction only works on tables. The equivalent instruction +** for indices is OP_IdxInsert. +*/ +/* Opcode: InsertInt P1 P2 P3 P4 P5 +** Synopsis: intkey=P3 data=r[P2] +** +** This works exactly like OP_Insert except that the key is the +** integer value P3, not the value of the integer stored in register P3. +*/ +case OP_Insert: +case OP_InsertInt: { + Mem *pData; /* MEM cell holding data for the record to be inserted */ + Mem *pKey; /* MEM cell holding key for the record */ + VdbeCursor *pC; /* Cursor to table into which insert is written */ + int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ + const char *zDb; /* database name - used by the update hook */ + Table *pTab; /* Table structure - used by update and pre-update hooks */ + int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ + BtreePayload x; /* Payload to be inserted */ + + op = 0; + pData = &aMem[pOp->p2]; + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( memIsValid(pData) ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable ); + assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); + REGISTER_TRACE(pOp->p2, pData); + + if( pOp->opcode==OP_Insert ){ + pKey = &aMem[pOp->p3]; + assert( pKey->flags & MEM_Int ); + assert( memIsValid(pKey) ); + REGISTER_TRACE(pOp->p3, pKey); + x.nKey = pKey->u.i; + }else{ + assert( pOp->opcode==OP_InsertInt ); + x.nKey = pOp->p3; + } + + if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ + assert( pC->iDb>=0 ); + zDb = db->aDb[pC->iDb].zDbSName; + pTab = pOp->p4.pTab; + assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) ); + op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); + }else{ + pTab = 0; /* Not needed. Silence a compiler warning. */ + zDb = 0; /* Not needed. Silence a compiler warning. */ + } + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + /* Invoke the pre-update hook, if any */ + if( db->xPreUpdateCallback + && pOp->p4type==P4_TABLE + && !(pOp->p5 & OPFLAG_ISUPDATE) + ){ + sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2); + } + if( pOp->p5 & OPFLAG_ISNOOP ) break; +#endif + + 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; + } + seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); + if( pData->flags & MEM_Zero ){ + x.nZero = pData->u.nZero; + }else{ + x.nZero = 0; + } + x.pKey = 0; + rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, + (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult + ); + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + + /* Invoke the update-hook if required. */ + if( rc ) goto abort_due_to_error; + if( db->xUpdateCallback && op ){ + db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey); + } + break; +} + +/* Opcode: Delete P1 P2 P3 P4 P5 +** +** Delete the record at which the P1 cursor is currently pointing. +** +** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then +** the cursor will be left pointing at either the next or the previous +** record in the table. If it is left pointing at the next record, then +** the next Next instruction will be a no-op. As a result, in this case +** it is ok to delete a record from within a Next loop. If +** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be +** left in an undefined state. +** +** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this +** delete one of several associated with deleting a table row and all its +** associated index entries. Exactly one of those deletes is the "primary" +** delete. The others are all on OPFLAG_FORDELETE cursors or else are +** marked with the AUXDELETE flag. +** +** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row +** change count is incremented (otherwise not). +** +** P1 must not be pseudo-table. It has to be a real table with +** multiple rows. +** +** If P4 is not NULL then it points to a Table object. In this case either +** the update or pre-update hook, or both, may be invoked. The P1 cursor must +** have been positioned using OP_NotFound prior to invoking this opcode in +** this case. Specifically, if one is configured, the pre-update hook is +** invoked if P4 is not NULL. The update-hook is invoked if one is configured, +** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2. +** +** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address +** of the memory cell that contains the value that the rowid of the row will +** be set to by the update. +*/ +case OP_Delete: { + VdbeCursor *pC; + const char *zDb; + Table *pTab; + int opflags; + + opflags = pOp->p2; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + assert( pC->deferredMoveto==0 ); + +#ifdef SQLITE_DEBUG + if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ + /* If p5 is zero, the seek operation that positioned the cursor prior to + ** OP_Delete will have also set the pC->movetoTarget field to the rowid of + ** the row that is being deleted */ + i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); + assert( pC->movetoTarget==iKey ); + } +#endif + + /* If the update-hook or pre-update-hook will be invoked, set zDb to + ** the name of the db to pass as to it. Also set local pTab to a copy + ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was + ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set + ** VdbeCursor.movetoTarget to the current rowid. */ + if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ + assert( pC->iDb>=0 ); + assert( pOp->p4.pTab!=0 ); + zDb = db->aDb[pC->iDb].zDbSName; + pTab = pOp->p4.pTab; + if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ + pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); + } + }else{ + zDb = 0; /* Not needed. Silence a compiler warning. */ + pTab = 0; /* Not needed. Silence a compiler warning. */ + } + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + /* Invoke the pre-update-hook if required. */ + if( db->xPreUpdateCallback && pOp->p4.pTab ){ + assert( !(opflags & OPFLAG_ISUPDATE) + || HasRowid(pTab)==0 + || (aMem[pOp->p3].flags & MEM_Int) + ); + sqlite3VdbePreUpdateHook(p, pC, + (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, + zDb, pTab, pC->movetoTarget, + pOp->p3 + ); + } + if( opflags & OPFLAG_ISNOOP ) break; +#endif + + /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ + assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 ); + assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION ); + assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE ); + +#ifdef SQLITE_DEBUG + if( p->pFrame==0 ){ + if( pC->isEphemeral==0 + && (pOp->p5 & OPFLAG_AUXDELETE)==0 + && (pC->wrFlag & OPFLAG_FORDELETE)==0 + ){ + nExtraDelete++; + } + if( pOp->p2 & OPFLAG_NCHANGE ){ + nExtraDelete--; + } + } +#endif + + rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5); + pC->cacheStatus = CACHE_STALE; + pC->seekResult = 0; + if( rc ) goto abort_due_to_error; + + /* Invoke the update-hook if required. */ + if( opflags & OPFLAG_NCHANGE ){ + p->nChange++; + if( db->xUpdateCallback && HasRowid(pTab) ){ + db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName, + pC->movetoTarget); + assert( pC->iDb>=0 ); + } + } + + break; +} +/* Opcode: ResetCount * * * * * +** +** The value of the change counter is copied to the database handle +** change counter (returned by subsequent calls to sqlite3_changes()). +** Then the VMs internal change counter resets to 0. +** This is used by trigger programs. +*/ +case OP_ResetCount: { + sqlite3VdbeSetChanges(db, p->nChange); + p->nChange = 0; + break; +} + +/* Opcode: SorterCompare P1 P2 P3 P4 +** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 +** +** P1 is a sorter cursor. This instruction compares a prefix of the +** record blob in register P3 against a prefix of the entry that +** the sorter cursor currently points to. Only the first P4 fields +** of r[P3] and the sorter record are compared. +** +** If either P3 or the sorter contains a NULL in one of their significant +** fields (not counting the P4 fields at the end which are ignored) then +** the comparison is assumed to be equal. +** +** Fall through to next instruction if the two records compare equal to +** each other. Jump to P2 if they are different. +*/ +case OP_SorterCompare: { + VdbeCursor *pC; + int res; + int nKeyCol; + + pC = p->apCsr[pOp->p1]; + assert( isSorter(pC) ); + assert( pOp->p4type==P4_INT32 ); + pIn3 = &aMem[pOp->p3]; + nKeyCol = pOp->p4.i; + res = 0; + rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); + VdbeBranchTaken(res!=0,2); + if( rc ) goto abort_due_to_error; + if( res ) goto jump_to_p2; + break; +}; + +/* Opcode: SorterData P1 P2 P3 * * +** Synopsis: r[P2]=data +** +** Write into register P2 the current sorter data for sorter cursor P1. +** Then clear the column header cache on cursor P3. +** +** This opcode is normally use to move a record out of the sorter and into +** a register that is the source for a pseudo-table cursor created using +** OpenPseudo. That pseudo-table cursor is the one that is identified by +** parameter P3. Clearing the P3 column cache as part of this opcode saves +** us from having to issue a separate NullRow instruction to clear that cache. +*/ +case OP_SorterData: { + VdbeCursor *pC; + + pOut = &aMem[pOp->p2]; + pC = p->apCsr[pOp->p1]; + assert( isSorter(pC) ); + rc = sqlite3VdbeSorterRowkey(pC, pOut); + assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); + assert( pOp->p1>=0 && pOp->p1nCursor ); + if( rc ) goto abort_due_to_error; + p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; + break; +} + +/* Opcode: RowData P1 P2 P3 * * +** Synopsis: r[P2]=data +** +** Write into register P2 the complete row content for the row at +** which cursor P1 is currently pointing. +** There is no interpretation of the data. +** It is just copied onto the P2 register exactly as +** it is found in the database file. +** +** If cursor P1 is an index, then the content is the key of the row. +** If cursor P2 is a table, then the content extracted is the data. +** +** If the P1 cursor must be pointing to a valid row (not a NULL row) +** of a real table, not a pseudo-table. +** +** If P3!=0 then this opcode is allowed to make an ephermeral pointer +** into the database page. That means that the content of the output +** register will be invalidated as soon as the cursor moves - including +** moves caused by other cursors that "save" the the current cursors +** position in order that they can write to the same table. If P3==0 +** then a copy of the data is made into memory. P3!=0 is faster, but +** P3==0 is safer. +** +** If P3!=0 then the content of the P2 register is unsuitable for use +** in OP_Result and any OP_Result will invalidate the P2 register content. +** The P2 register content is invalidated by opcodes like OP_Function or +** by any use of another cursor pointing to the same table. +*/ +case OP_RowData: { + VdbeCursor *pC; + BtCursor *pCrsr; + u32 n; + + pOut = out2Prerelease(p, pOp); + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( isSorter(pC)==0 ); + assert( pC->nullRow==0 ); + assert( pC->uc.pCursor!=0 ); + pCrsr = pC->uc.pCursor; + + /* The OP_RowData opcodes always follow OP_NotExists or + ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions + ** that might invalidate the cursor. + ** If this where not the case, on of the following assert()s + ** would fail. Should this ever change (because of changes in the code + ** generator) then the fix would be to insert a call to + ** sqlite3VdbeCursorMoveto(). + */ + assert( pC->deferredMoveto==0 ); + assert( sqlite3BtreeCursorIsValid(pCrsr) ); +#if 0 /* Not required due to the previous to assert() statements */ + rc = sqlite3VdbeCursorMoveto(pC); + if( rc!=SQLITE_OK ) goto abort_due_to_error; +#endif + + n = sqlite3BtreePayloadSize(pCrsr); + if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; + } + testcase( n==0 ); + rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut); + if( rc ) goto abort_due_to_error; + if( !pOp->p3 ) Deephemeralize(pOut); + UPDATE_MAX_BLOBSIZE(pOut); + REGISTER_TRACE(pOp->p2, pOut); + break; +} + +/* Opcode: Rowid P1 P2 * * * +** Synopsis: r[P2]=rowid +** +** Store in register P2 an integer which is the key of the table entry that +** P1 is currently point to. +** +** P1 can be either an ordinary table or a virtual table. There used to +** be a separate OP_VRowid opcode for use with virtual tables, but this +** one opcode now works for both table types. +*/ +case OP_Rowid: { /* out2 */ + VdbeCursor *pC; + i64 v; + sqlite3_vtab *pVtab; + const sqlite3_module *pModule; + + pOut = out2Prerelease(p, pOp); + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); + if( pC->nullRow ){ + pOut->flags = MEM_Null; + break; + }else if( pC->deferredMoveto ){ + v = pC->movetoTarget; +#ifndef SQLITE_OMIT_VIRTUALTABLE + }else if( pC->eCurType==CURTYPE_VTAB ){ + assert( pC->uc.pVCur!=0 ); + pVtab = pC->uc.pVCur->pVtab; + pModule = pVtab->pModule; + assert( pModule->xRowid ); + rc = pModule->xRowid(pC->uc.pVCur, &v); + sqlite3VtabImportErrmsg(p, pVtab); + if( rc ) goto abort_due_to_error; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + }else{ + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + rc = sqlite3VdbeCursorRestore(pC); + if( rc ) goto abort_due_to_error; + if( pC->nullRow ){ + pOut->flags = MEM_Null; + break; + } + v = sqlite3BtreeIntegerKey(pC->uc.pCursor); + } + pOut->u.i = v; + break; +} + +/* Opcode: NullRow P1 * * * * +** +** Move the cursor P1 to a null row. Any OP_Column operations +** that occur while the cursor is on the null row will always +** write a NULL. +*/ +case OP_NullRow: { + VdbeCursor *pC; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + pC->nullRow = 1; + pC->cacheStatus = CACHE_STALE; + if( pC->eCurType==CURTYPE_BTREE ){ + assert( pC->uc.pCursor!=0 ); + sqlite3BtreeClearCursor(pC->uc.pCursor); + } + break; +} + +/* Opcode: Last P1 P2 P3 * * +** +** The next use of the Rowid or Column or Prev instruction for P1 +** will refer to the last entry in the database table or index. +** If the table or index is empty and P2>0, then jump immediately to P2. +** If P2 is 0 or if the table or index is not empty, fall through +** to the following instruction. +** +** 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_Last: { /* jump */ + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + pCrsr = pC->uc.pCursor; + res = 0; + assert( pCrsr!=0 ); + pC->seekResult = pOp->p3; +#ifdef SQLITE_DEBUG + pC->seekOp = OP_Last; +#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{ + assert( pOp->p2==0 ); + } + break; +} + +/* Opcode: IfSmaller P1 P2 P3 * * +** +** Estimate the number of rows in the table P1. Jump to P2 if that +** estimate is less than approximately 2**(0.1*P3). +*/ +case OP_IfSmaller: { /* jump */ + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + i64 sz; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + pCrsr = pC->uc.pCursor; + assert( pCrsr ); + rc = sqlite3BtreeFirst(pCrsr, &res); + if( rc ) goto abort_due_to_error; + if( res==0 ){ + sz = sqlite3BtreeRowCountEst(pCrsr); + if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)p3 ) res = 1; + } + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; + break; +} + + +/* Opcode: SorterSort P1 P2 * * * +** +** After all records have been inserted into the Sorter object +** identified by P1, invoke this opcode to actually do the sorting. +** Jump to P2 if there are no records to be sorted. +** +** This opcode is an alias for OP_Sort and OP_Rewind that is used +** for Sorter objects. +*/ +/* Opcode: Sort P1 P2 * * * +** +** This opcode does exactly the same thing as OP_Rewind except that +** it increments an undocumented global variable used for testing. +** +** Sorting is accomplished by writing records into a sorting index, +** then rewinding that index and playing it back from beginning to +** end. We use the OP_Sort opcode instead of OP_Rewind to do the +** rewinding so that the global variable will be incremented and +** regression tests can determine whether or not the optimizer is +** correctly optimizing out sorts. +*/ +case OP_SorterSort: /* jump */ +case OP_Sort: { /* jump */ +#ifdef SQLITE_TEST + sqlite3_sort_count++; + sqlite3_search_count--; +#endif + p->aCounter[SQLITE_STMTSTATUS_SORT]++; + /* Fall through into OP_Rewind */ +} +/* Opcode: Rewind P1 P2 * * * +** +** The next use of the Rowid or Column or Next instruction for P1 +** will refer to the first entry in the database table or index. +** If the table or index is empty, jump immediately to P2. +** If the table or index is not empty, fall through to the following +** instruction. +** +** This opcode leaves the cursor configured to move in forward order, +** from the beginning toward the end. In other words, the cursor is +** configured to use Next, not Prev. +*/ +case OP_Rewind: { /* jump */ + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); + res = 1; +#ifdef SQLITE_DEBUG + pC->seekOp = OP_Rewind; +#endif + if( isSorter(pC) ){ + rc = sqlite3VdbeSorterRewind(pC, &res); + }else{ + assert( pC->eCurType==CURTYPE_BTREE ); + pCrsr = pC->uc.pCursor; + assert( pCrsr ); + rc = sqlite3BtreeFirst(pCrsr, &res); + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + } + if( rc ) goto abort_due_to_error; + pC->nullRow = (u8)res; + assert( pOp->p2>0 && pOp->p2nOp ); + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; + break; +} + +/* Opcode: Next P1 P2 P3 P4 P5 +** +** Advance cursor P1 so that it points to the next key/data pair in its +** table or index. If there are no more key/value pairs then fall through +** to the following instruction. But if the cursor advance was successful, +** jump immediately to P2. +** +** The Next opcode is only valid following an SeekGT, SeekGE, or +** OP_Rewind opcode used to position the cursor. Next is not allowed +** to follow SeekLT, SeekLE, or OP_Last. +** +** The P1 cursor must be for a real table, not a pseudo-table. P1 must have +** been opened prior to this opcode or the program will segfault. +** +** The P3 value is a hint to the btree implementation. If P3==1, that +** means P1 is an SQL index and that this instruction could have been +** omitted if that index had been unique. P3 is usually 0. P3 is +** always either 0 or 1. +** +** P4 is always of type P4_ADVANCE. The function pointer points to +** sqlite3BtreeNext(). +** +** If P5 is positive and the jump is taken, then event counter +** number P5-1 in the prepared statement is incremented. +** +** See also: Prev, NextIfOpen +*/ +/* Opcode: NextIfOpen P1 P2 P3 P4 P5 +** +** This opcode works just like Next except that if cursor P1 is not +** open it behaves a no-op. +*/ +/* Opcode: Prev P1 P2 P3 P4 P5 +** +** Back up cursor P1 so that it points to the previous key/data pair in its +** table or index. If there is no previous key/value pairs then fall through +** to the following instruction. But if the cursor backup was successful, +** jump immediately to P2. +** +** +** The Prev opcode is only valid following an SeekLT, SeekLE, or +** OP_Last opcode used to position the cursor. Prev is not allowed +** to follow SeekGT, SeekGE, or OP_Rewind. +** +** The P1 cursor must be for a real table, not a pseudo-table. If P1 is +** not open then the behavior is undefined. +** +** The P3 value is a hint to the btree implementation. If P3==1, that +** means P1 is an SQL index and that this instruction could have been +** omitted if that index had been unique. P3 is usually 0. P3 is +** always either 0 or 1. +** +** P4 is always of type P4_ADVANCE. The function pointer points to +** sqlite3BtreePrevious(). +** +** If P5 is positive and the jump is taken, then event counter +** number P5-1 in the prepared statement is incremented. +*/ +/* Opcode: PrevIfOpen P1 P2 P3 P4 P5 +** +** This opcode works just like Prev except that if cursor P1 is not +** open it behaves a no-op. +*/ +/* Opcode: SorterNext P1 P2 * * P5 +** +** This opcode works just like OP_Next except that P1 must be a +** sorter object for which the OP_SorterSort opcode has been +** invoked. This opcode advances the cursor to the next sorted +** record, or jumps to P2 if there are no more sorted records. +*/ +case OP_SorterNext: { /* jump */ + VdbeCursor *pC; + int res; + + pC = p->apCsr[pOp->p1]; + assert( isSorter(pC) ); + res = 0; + rc = sqlite3VdbeSorterNext(db, pC, &res); + goto next_tail; +case OP_PrevIfOpen: /* jump */ +case OP_NextIfOpen: /* jump */ + if( p->apCsr[pOp->p1]==0 ) break; + /* Fall through */ +case OP_Prev: /* jump */ +case OP_Next: /* jump */ + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pOp->p5aCounter) ); + pC = p->apCsr[pOp->p1]; + res = pOp->p3; + assert( pC!=0 ); + assert( pC->deferredMoveto==0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( res==0 || (res==1 && pC->isTable==0) ); + testcase( res==1 ); + assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); + assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); + assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); + assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious); + + /* The Next opcode is only used after SeekGT, SeekGE, and Rewind. + ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ + assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen + || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE + || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found); + assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen + || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE + || pC->seekOp==OP_Last ); + + rc = pOp->p4.xAdvance(pC->uc.pCursor, &res); +next_tail: + pC->cacheStatus = CACHE_STALE; + VdbeBranchTaken(res==0,2); + if( rc ) goto abort_due_to_error; + if( res==0 ){ + pC->nullRow = 0; + p->aCounter[pOp->p5]++; +#ifdef SQLITE_TEST + sqlite3_search_count++; +#endif + goto jump_to_p2_and_check_for_interrupt; + }else{ + pC->nullRow = 1; + } + goto check_for_interrupt; +} + +/* Opcode: IdxInsert P1 P2 P3 P4 P5 +** Synopsis: key=r[P2] +** +** Register P2 holds an SQL index key made using the +** MakeRecord instructions. This opcode writes that key +** into the index P1. Data for the entry is nil. +** +** If P4 is not zero, then it is the number of values in the unpacked +** key of reg(P2). In that case, P3 is the index of the first register +** for the unpacked key. The availability of the unpacked key can sometimes +** be an optimization. +** +** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer +** that this insert is likely to be an append. +** +** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is +** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear, +** then the change counter is unchanged. +** +** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might +** run faster by avoiding an unnecessary seek on cursor P1. However, +** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior +** seeks on the cursor or if the most recent seek used a key equivalent +** to P2. +** +** This instruction only works for indices. The equivalent instruction +** for tables is OP_Insert. +*/ +/* Opcode: SorterInsert P1 P2 * * * +** Synopsis: key=r[P2] +** +** Register P2 holds an SQL index key made using the +** MakeRecord instructions. This opcode writes that key +** into the sorter P1. Data for the entry is nil. +*/ +case OP_SorterInsert: /* in2 */ +case OP_IdxInsert: { /* in2 */ + VdbeCursor *pC; + BtreePayload x; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) ); + pIn2 = &aMem[pOp->p2]; + assert( pIn2->flags & MEM_Blob ); + if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; + assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert ); + assert( pC->isTable==0 ); + rc = ExpandBlob(pIn2); + if( rc ) goto abort_due_to_error; + if( pOp->opcode==OP_SorterInsert ){ + rc = sqlite3VdbeSorterWrite(pC, pIn2); + }else{ + x.nKey = pIn2->n; + x.pKey = pIn2->z; + x.aMem = aMem + pOp->p3; + x.nMem = (u16)pOp->p4.i; + rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, + (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), + ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) + ); + assert( pC->deferredMoveto==0 ); + pC->cacheStatus = CACHE_STALE; + } + if( rc) goto abort_due_to_error; + break; +} + +/* Opcode: IdxDelete P1 P2 P3 * * +** Synopsis: key=r[P2@P3] +** +** The content of P3 registers starting at register P2 form +** an unpacked index key. This opcode removes that entry from the +** index opened by cursor P1. +*/ +case OP_IdxDelete: { + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + UnpackedRecord r; + + assert( pOp->p3>0 ); + assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 ); + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + pCrsr = pC->uc.pCursor; + assert( pCrsr!=0 ); + assert( pOp->p5==0 ); + r.pKeyInfo = pC->pKeyInfo; + r.nField = (u16)pOp->p3; + r.default_rc = 0; + r.aMem = &aMem[pOp->p2]; + rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res); + if( rc ) goto abort_due_to_error; + if( res==0 ){ + rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); + if( rc ) goto abort_due_to_error; + } + assert( pC->deferredMoveto==0 ); + pC->cacheStatus = CACHE_STALE; + pC->seekResult = 0; + break; +} + +/* Opcode: Seek P1 * P3 P4 * +** Synopsis: Move P3 to P1.rowid +** +** P1 is an open index cursor and P3 is a cursor on the corresponding +** table. This opcode does a deferred seek of the P3 table cursor +** to the row that corresponds to the current row of P1. +** +** This is a deferred seek. Nothing actually happens until +** the cursor is used to read a record. That way, if no reads +** occur, no unnecessary I/O happens. +** +** P4 may be an array of integers (type P4_INTARRAY) containing +** one entry for each column in the P3 table. If array entry a(i) +** is non-zero, then reading column a(i)-1 from cursor P3 is +** equivalent to performing the deferred seek and then reading column i +** from P1. This information is stored in P3 and used to redirect +** reads against P3 over to P1, thus possibly avoiding the need to +** seek and read cursor P3. +*/ +/* Opcode: IdxRowid P1 P2 * * * +** Synopsis: r[P2]=rowid +** +** Write into register P2 an integer which is the last entry in the record at +** the end of the index key pointed to by cursor P1. This integer should be +** the rowid of the table entry to which this index entry points. +** +** See also: Rowid, MakeRecord. +*/ +case OP_Seek: +case OP_IdxRowid: { /* out2 */ + VdbeCursor *pC; /* The P1 index cursor */ + VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */ + i64 rowid; /* Rowid that P1 current points to */ + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + assert( pC->isTable==0 ); + assert( pC->deferredMoveto==0 ); + assert( !pC->nullRow || pOp->opcode==OP_IdxRowid ); + + /* The IdxRowid and Seek opcodes are combined because of the commonality + ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */ + rc = sqlite3VdbeCursorRestore(pC); + + /* sqlite3VbeCursorRestore() can only fail if the record has been deleted + ** out from under the cursor. That will never happens for an IdxRowid + ** or Seek opcode */ + if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; + + if( !pC->nullRow ){ + rowid = 0; /* Not needed. Only used to silence a warning. */ + rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid); + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } + if( pOp->opcode==OP_Seek ){ + assert( pOp->p3>=0 && pOp->p3nCursor ); + pTabCur = p->apCsr[pOp->p3]; + assert( pTabCur!=0 ); + assert( pTabCur->eCurType==CURTYPE_BTREE ); + assert( pTabCur->uc.pCursor!=0 ); + assert( pTabCur->isTable ); + pTabCur->nullRow = 0; + pTabCur->movetoTarget = rowid; + pTabCur->deferredMoveto = 1; + assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); + pTabCur->aAltMap = pOp->p4.ai; + pTabCur->pAltCursor = pC; + }else{ + pOut = out2Prerelease(p, pOp); + pOut->u.i = rowid; + } + }else{ + assert( pOp->opcode==OP_IdxRowid ); + sqlite3VdbeMemSetNull(&aMem[pOp->p2]); + } + break; +} + +/* Opcode: IdxGE P1 P2 P3 P4 P5 +** Synopsis: key=r[P3@P4] +** +** The P4 register values beginning with P3 form an unpacked index +** key that omits the PRIMARY KEY. Compare this key value against the index +** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID +** fields at the end. +** +** If the P1 index entry is greater than or equal to the key value +** then jump to P2. Otherwise fall through to the next instruction. +*/ +/* Opcode: IdxGT P1 P2 P3 P4 P5 +** Synopsis: key=r[P3@P4] +** +** The P4 register values beginning with P3 form an unpacked index +** key that omits the PRIMARY KEY. Compare this key value against the index +** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID +** fields at the end. +** +** If the P1 index entry is greater than the key value +** then jump to P2. Otherwise fall through to the next instruction. +*/ +/* Opcode: IdxLT P1 P2 P3 P4 P5 +** Synopsis: key=r[P3@P4] +** +** The P4 register values beginning with P3 form an unpacked index +** key that omits the PRIMARY KEY or ROWID. Compare this key value against +** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or +** ROWID on the P1 index. +** +** If the P1 index entry is less than the key value then jump to P2. +** Otherwise fall through to the next instruction. +*/ +/* Opcode: IdxLE P1 P2 P3 P4 P5 +** Synopsis: key=r[P3@P4] +** +** The P4 register values beginning with P3 form an unpacked index +** key that omits the PRIMARY KEY or ROWID. Compare this key value against +** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or +** ROWID on the P1 index. +** +** If the P1 index entry is less than or equal to the key value then jump +** to P2. Otherwise fall through to the next instruction. +*/ +case OP_IdxLE: /* jump */ +case OP_IdxGT: /* jump */ +case OP_IdxLT: /* jump */ +case OP_IdxGE: { /* jump */ + VdbeCursor *pC; + int res; + UnpackedRecord r; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->isOrdered ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0); + assert( pC->deferredMoveto==0 ); + assert( pOp->p5==0 || pOp->p5==1 ); + assert( pOp->p4type==P4_INT32 ); + r.pKeyInfo = pC->pKeyInfo; + r.nField = (u16)pOp->p4.i; + if( pOp->opcodeopcode==OP_IdxLE || pOp->opcode==OP_IdxGT ); + r.default_rc = -1; + }else{ + assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); + r.default_rc = 0; + } + r.aMem = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + { int i; for(i=0; iopcode&1)==(OP_IdxLT&1) ){ + assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); + res = -res; + }else{ + assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxGT ); + res++; + } + VdbeBranchTaken(res>0,2); + if( rc ) goto abort_due_to_error; + if( res>0 ) goto jump_to_p2; + break; +} + +/* Opcode: Destroy P1 P2 P3 * * +** +** Delete an entire database table or index whose root page in the database +** file is given by P1. +** +** The table being destroyed is in the main database file if P3==0. If +** P3==1 then the table to be clear is in the auxiliary database file +** that is used to store tables create using CREATE TEMPORARY TABLE. +** +** If AUTOVACUUM is enabled then it is possible that another root page +** might be moved into the newly deleted root page in order to keep all +** root pages contiguous at the beginning of the database. The former +** value of the root page that moved - its value before the move occurred - +** is stored in register P2. If no page movement was required (because the +** table being dropped was already the last one in the database) then a +** zero is stored in register P2. If AUTOVACUUM is disabled then a zero +** is stored in register P2. +** +** This opcode throws an error if there are any active reader VMs when +** it is invoked. This is done to avoid the difficulty associated with +** updating existing cursors when a root page is moved in an AUTOVACUUM +** database. This error is thrown even if the database is not an AUTOVACUUM +** db in order to avoid introducing an incompatibility between autovacuum +** and non-autovacuum modes. +** +** See also: Clear +*/ +case OP_Destroy: { /* out2 */ + int iMoved; + int iDb; + + assert( p->readOnly==0 ); + assert( pOp->p1>1 ); + pOut = out2Prerelease(p, pOp); + pOut->flags = MEM_Null; + if( db->nVdbeRead > db->nVDestroy+1 ){ + rc = SQLITE_LOCKED; + p->errorAction = OE_Abort; + goto abort_due_to_error; + }else{ + iDb = pOp->p3; + assert( DbMaskTest(p->btreeMask, iDb) ); + iMoved = 0; /* Not needed. Only to silence a warning. */ + rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved); + pOut->flags = MEM_Int; + pOut->u.i = iMoved; + if( rc ) goto abort_due_to_error; +#ifndef SQLITE_OMIT_AUTOVACUUM + if( iMoved!=0 ){ + sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1); + /* All OP_Destroy operations occur on the same btree */ + assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 ); + resetSchemaOnFault = iDb+1; + } +#endif + } + break; +} + +/* Opcode: Clear P1 P2 P3 +** +** Delete all contents of the database table or index whose root page +** in the database file is given by P1. But, unlike Destroy, do not +** remove the table or index from the database file. +** +** The table being clear is in the main database file if P2==0. If +** P2==1 then the table to be clear is in the auxiliary database file +** that is used to store tables create using CREATE TEMPORARY TABLE. +** +** If the P3 value is non-zero, then the table referred to must be an +** intkey table (an SQL table, not an index). In this case the row change +** count is incremented by the number of rows in the table being cleared. +** If P3 is greater than zero, then the value stored in register P3 is +** also incremented by the number of rows in the table being cleared. +** +** See also: Destroy +*/ +case OP_Clear: { + int nChange; + + nChange = 0; + assert( p->readOnly==0 ); + assert( DbMaskTest(p->btreeMask, pOp->p2) ); + rc = sqlite3BtreeClearTable( + db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) + ); + if( pOp->p3 ){ + p->nChange += nChange; + if( pOp->p3>0 ){ + assert( memIsValid(&aMem[pOp->p3]) ); + memAboutToChange(p, &aMem[pOp->p3]); + aMem[pOp->p3].u.i += nChange; + } + } + if( rc ) goto abort_due_to_error; + break; +} + +/* Opcode: ResetSorter P1 * * * * +** +** Delete all contents from the ephemeral table or sorter +** that is open on cursor P1. +** +** This opcode only works for cursors used for sorting and +** opened with OP_OpenEphemeral or OP_SorterOpen. +*/ +case OP_ResetSorter: { + VdbeCursor *pC; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + if( isSorter(pC) ){ + sqlite3VdbeSorterReset(db, pC->uc.pSorter); + }else{ + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->isEphemeral ); + rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor); + if( rc ) goto abort_due_to_error; + } + 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. +** +** See documentation on OP_CreateTable for additional information. +*/ +case OP_CreateIndex: /* out2 */ +case OP_CreateTable: { /* out2 */ + int pgno; + int flags; + Db *pDb; + + pOut = out2Prerelease(p, pOp); + pgno = 0; + assert( pOp->p1>=0 && pOp->p1nDb ); + 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); + if( rc ) goto abort_due_to_error; + pOut->u.i = pgno; + break; +} + +/* Opcode: SqlExec * * * P4 * +** +** Run the SQL statement or statements specified in the P4 string. +*/ +case OP_SqlExec: { + db->nSqlExec++; + rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); + db->nSqlExec--; + if( rc ) goto abort_due_to_error; + break; +} + +/* Opcode: ParseSchema P1 * * P4 * +** +** Read and parse all entries from the SQLITE_MASTER table of database P1 +** that match the WHERE clause P4. +** +** This opcode invokes the parser to create a new virtual machine, +** then runs the new virtual machine. It is thus a re-entrant opcode. +*/ +case OP_ParseSchema: { + int iDb; + const char *zMaster; + char *zSql; + InitData initData; + + /* Any prepared statement that invokes this opcode will hold mutexes + ** on every btree. This is a prerequisite for invoking + ** sqlite3InitCallback(). + */ +#ifdef SQLITE_DEBUG + for(iDb=0; iDbnDb; iDb++){ + assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); + } +#endif + + iDb = pOp->p1; + assert( iDb>=0 && iDbnDb ); + assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); + /* Used to be a conditional */ { + zMaster = MASTER_NAME; + initData.db = db; + initData.iDb = pOp->p1; + initData.pzErrMsg = &p->zErrMsg; + zSql = sqlite3MPrintf(db, + "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", + db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); + if( zSql==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + assert( db->init.busy==0 ); + db->init.busy = 1; + initData.rc = SQLITE_OK; + assert( !db->mallocFailed ); + rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); + if( rc==SQLITE_OK ) rc = initData.rc; + sqlite3DbFreeNN(db, zSql); + db->init.busy = 0; + } + } + if( rc ){ + sqlite3ResetAllSchemasOfConnection(db); + if( rc==SQLITE_NOMEM ){ + goto no_mem; + } + goto abort_due_to_error; + } + break; +} + +#if !defined(SQLITE_OMIT_ANALYZE) +/* Opcode: LoadAnalysis P1 * * * * +** +** Read the sqlite_stat1 table for database P1 and load the content +** of that table into the internal index hash table. This will cause +** the analysis to be used when preparing all subsequent queries. +*/ +case OP_LoadAnalysis: { + assert( pOp->p1>=0 && pOp->p1nDb ); + rc = sqlite3AnalysisLoad(db, pOp->p1); + if( rc ) goto abort_due_to_error; + break; +} +#endif /* !defined(SQLITE_OMIT_ANALYZE) */ + +/* Opcode: DropTable P1 * * P4 * +** +** Remove the internal (in-memory) data structures that describe +** the table named P4 in database P1. This is called after a table +** is dropped from disk (using the Destroy opcode) in order to keep +** the internal representation of the +** schema consistent with what is on disk. +*/ +case OP_DropTable: { + sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z); + break; +} + +/* Opcode: DropIndex P1 * * P4 * +** +** Remove the internal (in-memory) data structures that describe +** the index named P4 in database P1. This is called after an index +** is dropped from disk (using the Destroy opcode) +** in order to keep the internal representation of the +** schema consistent with what is on disk. +*/ +case OP_DropIndex: { + sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z); + break; +} + +/* Opcode: DropTrigger P1 * * P4 * +** +** Remove the internal (in-memory) data structures that describe +** the trigger named P4 in database P1. This is called after a trigger +** is dropped from disk (using the Destroy opcode) in order to keep +** the internal representation of the +** schema consistent with what is on disk. +*/ +case OP_DropTrigger: { + sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z); + break; +} + + +#ifndef SQLITE_OMIT_INTEGRITY_CHECK +/* Opcode: IntegrityCk P1 P2 P3 P4 P5 +** +** Do an analysis of the currently open database. Store in +** register P1 the text of an error message describing any problems. +** If no problems are found, store a NULL in register P1. +** +** The register P3 contains one less than the maximum number of allowed errors. +** At most reg(P3) errors will be reported. +** In other words, the analysis stops as soon as reg(P1) errors are +** seen. Reg(P1) is updated with the number of errors remaining. +** +** The root page numbers of all tables in the database are integers +** stored in P4_INTARRAY argument. +** +** If P5 is not zero, the check is done on the auxiliary database +** file, not the main database file. +** +** This opcode is used to implement the integrity_check pragma. +*/ +case OP_IntegrityCk: { + int nRoot; /* Number of tables to check. (Number of root pages.) */ + int *aRoot; /* Array of rootpage numbers for tables to be checked */ + int nErr; /* Number of errors reported */ + char *z; /* Text of the error report */ + Mem *pnErr; /* Register keeping track of errors remaining */ + + assert( p->bIsReader ); + nRoot = pOp->p2; + aRoot = pOp->p4.ai; + assert( nRoot>0 ); + assert( aRoot[nRoot]==0 ); + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + pnErr = &aMem[pOp->p3]; + assert( (pnErr->flags & MEM_Int)!=0 ); + assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 ); + pIn1 = &aMem[pOp->p1]; + assert( pOp->p5nDb ); + assert( DbMaskTest(p->btreeMask, pOp->p5) ); + z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, + (int)pnErr->u.i+1, &nErr); + sqlite3VdbeMemSetNull(pIn1); + if( nErr==0 ){ + assert( z==0 ); + }else if( z==0 ){ + goto no_mem; + }else{ + pnErr->u.i -= nErr-1; + sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); + } + UPDATE_MAX_BLOBSIZE(pIn1); + sqlite3VdbeChangeEncoding(pIn1, encoding); + break; +} +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ + +/* Opcode: RowSetAdd P1 P2 * * * +** Synopsis: rowset(P1)=r[P2] +** +** Insert the integer value held by register P2 into a RowSet object +** held in register P1. +** +** An assertion fails if P2 is not an integer. +*/ +case OP_RowSetAdd: { /* in1, in2 */ + pIn1 = &aMem[pOp->p1]; + pIn2 = &aMem[pOp->p2]; + assert( (pIn2->flags & MEM_Int)!=0 ); + if( (pIn1->flags & MEM_RowSet)==0 ){ + sqlite3VdbeMemSetRowSet(pIn1); + if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + } + sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i); + break; +} + +/* Opcode: RowSetRead P1 P2 P3 * * +** Synopsis: r[P3]=rowset(P1) +** +** Extract the smallest value from the RowSet object in P1 +** and put that value into register P3. +** Or, if RowSet object P1 is initially empty, leave P3 +** unchanged and jump to instruction P2. +*/ +case OP_RowSetRead: { /* jump, in1, out3 */ + i64 val; + + pIn1 = &aMem[pOp->p1]; + if( (pIn1->flags & MEM_RowSet)==0 + || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 + ){ + /* The boolean index is empty */ + sqlite3VdbeMemSetNull(pIn1); + VdbeBranchTaken(1,2); + goto jump_to_p2_and_check_for_interrupt; + }else{ + /* A value was pulled from the index */ + VdbeBranchTaken(0,2); + sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val); + } + goto check_for_interrupt; +} + +/* Opcode: RowSetTest P1 P2 P3 P4 +** Synopsis: if r[P3] in rowset(P1) goto P2 +** +** Register P3 is assumed to hold a 64-bit integer value. If register P1 +** contains a RowSet object and that RowSet object contains +** the value held in P3, jump to register P2. Otherwise, insert the +** integer in P3 into the RowSet and continue on to the +** next opcode. +** +** The RowSet object is optimized for the case where sets of integers +** are inserted in distinct phases, which each set contains no duplicates. +** Each set is identified by a unique P4 value. The first set +** must have P4==0, the final set must have P4==-1, and for all other sets +** must have P4>0. +** +** This allows optimizations: (a) when P4==0 there is no need to test +** the RowSet object for P3, as it is guaranteed not to contain it, +** (b) when P4==-1 there is no need to insert the value, as it will +** never be tested for, and (c) when a value that is part of set X is +** inserted, there is no need to search to see if the same value was +** previously inserted as part of set X (only if it was previously +** inserted as part of some other set). +*/ +case OP_RowSetTest: { /* jump, in1, in3 */ + int iSet; + int exists; + + pIn1 = &aMem[pOp->p1]; + pIn3 = &aMem[pOp->p3]; + iSet = pOp->p4.i; + assert( pIn3->flags&MEM_Int ); + + /* If there is anything other than a rowset object in memory cell P1, + ** delete it now and initialize P1 with an empty rowset + */ + if( (pIn1->flags & MEM_RowSet)==0 ){ + sqlite3VdbeMemSetRowSet(pIn1); + if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + } + + assert( pOp->p4type==P4_INT32 ); + assert( iSet==-1 || iSet>=0 ); + if( iSet ){ + exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); + VdbeBranchTaken(exists!=0,2); + if( exists ) goto jump_to_p2; + } + if( iSet>=0 ){ + sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); + } + break; +} + + +#ifndef SQLITE_OMIT_TRIGGER + +/* Opcode: Program P1 P2 P3 P4 P5 +** +** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). +** +** P1 contains the address of the memory cell that contains the first memory +** cell in an array of values used as arguments to the sub-program. P2 +** contains the address to jump to if the sub-program throws an IGNORE +** exception using the RAISE() function. Register P3 contains the address +** of a memory cell in this (the parent) VM that is used to allocate the +** memory required by the sub-vdbe at runtime. +** +** P4 is a pointer to the VM containing the trigger program. +** +** If P5 is non-zero, then recursive program invocation is enabled. +*/ +case OP_Program: { /* jump */ + int nMem; /* Number of memory registers for sub-program */ + int nByte; /* Bytes of runtime space required for sub-program */ + Mem *pRt; /* Register to allocate runtime space */ + Mem *pMem; /* Used to iterate through memory cells */ + Mem *pEnd; /* Last memory cell in new array */ + VdbeFrame *pFrame; /* New vdbe frame to execute in */ + SubProgram *pProgram; /* Sub-program to execute */ + void *t; /* Token identifying trigger */ + + pProgram = pOp->p4.pProgram; + pRt = &aMem[pOp->p3]; + assert( pProgram->nOp>0 ); + + /* If the p5 flag is clear, then recursive invocation of triggers is + ** disabled for backwards compatibility (p5 is set if this sub-program + ** is really a trigger, not a foreign key action, and the flag set + ** and cleared by the "PRAGMA recursive_triggers" command is clear). + ** + ** It is recursive invocation of triggers, at the SQL level, that is + ** disabled. In some cases a single trigger may generate more than one + ** SubProgram (if the trigger may be executed with more than one different + ** ON CONFLICT algorithm). SubProgram structures associated with a + ** single trigger all have the same value for the SubProgram.token + ** variable. */ + if( pOp->p5 ){ + t = pProgram->token; + for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent); + if( pFrame ) break; + } + + if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ + rc = SQLITE_ERROR; + sqlite3VdbeError(p, "too many levels of trigger recursion"); + goto abort_due_to_error; + } + + /* Register pRt is used to store the memory required to save the state + ** of the current program, and the memory required at runtime to execute + ** the trigger program. If this trigger has been fired before, then pRt + ** is already allocated. Otherwise, it must be initialized. */ + if( (pRt->flags&MEM_Frame)==0 ){ + /* SubProgram.nMem is set to the number of memory cells used by the + ** program stored in SubProgram.aOp. As well as these, one memory + ** cell is required for each cursor used by the program. Set local + ** variable nMem (and later, VdbeFrame.nChildMem) to this value. + */ + nMem = pProgram->nMem + pProgram->nCsr; + assert( nMem>0 ); + if( pProgram->nCsr==0 ) nMem++; + nByte = ROUND8(sizeof(VdbeFrame)) + + nMem * sizeof(Mem) + + pProgram->nCsr * sizeof(VdbeCursor*) + + (pProgram->nOp + 7)/8; + pFrame = sqlite3DbMallocZero(db, nByte); + if( !pFrame ){ + goto no_mem; + } + sqlite3VdbeMemRelease(pRt); + pRt->flags = MEM_Frame; + pRt->u.pFrame = pFrame; + + pFrame->v = p; + pFrame->nChildMem = nMem; + pFrame->nChildCsr = pProgram->nCsr; + pFrame->pc = (int)(pOp - aOp); + pFrame->aMem = p->aMem; + pFrame->nMem = p->nMem; + pFrame->apCsr = p->apCsr; + pFrame->nCursor = p->nCursor; + pFrame->aOp = p->aOp; + pFrame->nOp = p->nOp; + pFrame->token = pProgram->token; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + pFrame->anExec = p->anExec; +#endif + + pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; + for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ + pMem->flags = MEM_Undefined; + pMem->db = db; + } + }else{ + pFrame = pRt->u.pFrame; + assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem + || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) ); + assert( pProgram->nCsr==pFrame->nChildCsr ); + assert( (int)(pOp - aOp)==pFrame->pc ); + } + + p->nFrame++; + pFrame->pParent = p->pFrame; + pFrame->lastRowid = db->lastRowid; + pFrame->nChange = p->nChange; + pFrame->nDbChange = p->db->nChange; + assert( pFrame->pAuxData==0 ); + pFrame->pAuxData = p->pAuxData; + p->pAuxData = 0; + p->nChange = 0; + p->pFrame = pFrame; + p->aMem = aMem = VdbeFrameMem(pFrame); + p->nMem = pFrame->nChildMem; + p->nCursor = (u16)pFrame->nChildCsr; + p->apCsr = (VdbeCursor **)&aMem[p->nMem]; + pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr]; + memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8); + p->aOp = aOp = pProgram->aOp; + p->nOp = pProgram->nOp; +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + p->anExec = 0; +#endif + pOp = &aOp[-1]; + + break; +} + +/* Opcode: Param P1 P2 * * * +** +** This opcode is only ever present in sub-programs called via the +** OP_Program instruction. Copy a value currently stored in a memory +** cell of the calling (parent) frame to cell P2 in the current frames +** address space. This is used by trigger programs to access the new.* +** and old.* values. +** +** The address of the cell in the parent frame is determined by adding +** the value of the P1 argument to the value of the P1 argument to the +** calling OP_Program instruction. +*/ +case OP_Param: { /* out2 */ + VdbeFrame *pFrame; + Mem *pIn; + pOut = out2Prerelease(p, pOp); + pFrame = p->pFrame; + pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; + sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem); + break; +} + +#endif /* #ifndef SQLITE_OMIT_TRIGGER */ + +#ifndef SQLITE_OMIT_FOREIGN_KEY +/* Opcode: FkCounter P1 P2 * * * +** Synopsis: fkctr[P1]+=P2 +** +** Increment a "constraint counter" by P2 (P2 may be negative or positive). +** If P1 is non-zero, the database constraint counter is incremented +** (deferred foreign key constraints). Otherwise, if P1 is zero, the +** statement counter is incremented (immediate foreign key constraints). +*/ +case OP_FkCounter: { + if( db->flags & SQLITE_DeferFKs ){ + db->nDeferredImmCons += pOp->p2; + }else if( pOp->p1 ){ + db->nDeferredCons += pOp->p2; + }else{ + p->nFkConstraint += pOp->p2; + } + break; +} + +/* Opcode: FkIfZero P1 P2 * * * +** Synopsis: if fkctr[P1]==0 goto P2 +** +** This opcode tests if a foreign key constraint-counter is currently zero. +** If so, jump to instruction P2. Otherwise, fall through to the next +** instruction. +** +** If P1 is non-zero, then the jump is taken if the database constraint-counter +** is zero (the one that counts deferred constraint violations). If P1 is +** zero, the jump is taken if the statement constraint-counter is zero +** (immediate foreign key constraint violations). +*/ +case OP_FkIfZero: { /* jump */ + if( pOp->p1 ){ + VdbeBranchTaken(db->nDeferredCons==0 && db->nDeferredImmCons==0, 2); + if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) goto jump_to_p2; + }else{ + VdbeBranchTaken(p->nFkConstraint==0 && db->nDeferredImmCons==0, 2); + if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) goto jump_to_p2; + } + break; +} +#endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */ + +#ifndef SQLITE_OMIT_AUTOINCREMENT +/* Opcode: MemMax P1 P2 * * * +** Synopsis: r[P1]=max(r[P1],r[P2]) +** +** P1 is a register in the root frame of this VM (the root frame is +** different from the current frame if this instruction is being executed +** within a sub-program). Set the value of register P1 to the maximum of +** its current value and the value in register P2. +** +** This instruction throws an error if the memory cell is not initially +** an integer. +*/ +case OP_MemMax: { /* in2 */ + VdbeFrame *pFrame; + if( p->pFrame ){ + for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); + pIn1 = &pFrame->aMem[pOp->p1]; + }else{ + pIn1 = &aMem[pOp->p1]; + } + assert( memIsValid(pIn1) ); + sqlite3VdbeMemIntegerify(pIn1); + pIn2 = &aMem[pOp->p2]; + sqlite3VdbeMemIntegerify(pIn2); + if( pIn1->u.iu.i){ + pIn1->u.i = pIn2->u.i; + } + break; +} +#endif /* SQLITE_OMIT_AUTOINCREMENT */ + +/* Opcode: IfPos P1 P2 P3 * * +** Synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 +** +** Register P1 must contain an integer. +** If the value of register P1 is 1 or greater, subtract P3 from the +** value in P1 and jump to P2. +** +** If the initial value of register P1 is less than 1, then the +** value is unchanged and control passes through to the next instruction. +*/ +case OP_IfPos: { /* jump, in1 */ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags&MEM_Int ); + VdbeBranchTaken( pIn1->u.i>0, 2); + if( pIn1->u.i>0 ){ + pIn1->u.i -= pOp->p3; + goto jump_to_p2; + } + break; +} + +/* Opcode: OffsetLimit P1 P2 P3 * * +** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) +** +** This opcode performs a commonly used computation associated with +** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3] +** holds the offset counter. The opcode computes the combined value +** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2] +** value computed is the total number of rows that will need to be +** visited in order to complete the query. +** +** If r[P3] is zero or negative, that means there is no OFFSET +** and r[P2] is set to be the value of the LIMIT, r[P1]. +** +** if r[P1] is zero or negative, that means there is no LIMIT +** and r[P2] is set to -1. +** +** Otherwise, r[P2] is set to the sum of r[P1] and r[P3]. +*/ +case OP_OffsetLimit: { /* in1, out2, in3 */ + i64 x; + pIn1 = &aMem[pOp->p1]; + pIn3 = &aMem[pOp->p3]; + pOut = out2Prerelease(p, pOp); + assert( pIn1->flags & MEM_Int ); + assert( pIn3->flags & MEM_Int ); + x = pIn1->u.i; + if( x<=0 || sqlite3AddInt64(&x, pIn3->u.i>0?pIn3->u.i:0) ){ + /* If the LIMIT is less than or equal to zero, loop forever. This + ** is documented. But also, if the LIMIT+OFFSET exceeds 2^63 then + ** also loop forever. This is undocumented. In fact, one could argue + ** that the loop should terminate. But assuming 1 billion iterations + ** per second (far exceeding the capabilities of any current hardware) + ** it would take nearly 300 years to actually reach the limit. So + ** looping forever is a reasonable approximation. */ + pOut->u.i = -1; + }else{ + pOut->u.i = x; + } + break; +} + +/* Opcode: IfNotZero P1 P2 * * * +** Synopsis: if r[P1]!=0 then r[P1]--, goto P2 +** +** Register P1 must contain an integer. If the content of register P1 is +** initially greater than zero, then decrement the value in register P1. +** If it is non-zero (negative or positive) and then also jump to P2. +** If register P1 is initially zero, leave it unchanged and fall through. +*/ +case OP_IfNotZero: { /* jump, in1 */ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags&MEM_Int ); + VdbeBranchTaken(pIn1->u.i<0, 2); + if( pIn1->u.i ){ + if( pIn1->u.i>0 ) pIn1->u.i--; + goto jump_to_p2; + } + break; +} + +/* Opcode: DecrJumpZero P1 P2 * * * +** Synopsis: if (--r[P1])==0 goto P2 +** +** Register P1 must hold an integer. Decrement the value in P1 +** and jump to P2 if the new value is exactly zero. +*/ +case OP_DecrJumpZero: { /* jump, in1 */ + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags&MEM_Int ); + if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; + VdbeBranchTaken(pIn1->u.i==0, 2); + if( pIn1->u.i==0 ) goto jump_to_p2; + break; +} + + +/* Opcode: AggStep0 * P2 P3 P4 P5 +** Synopsis: accum=r[P3] step(r[P2@P5]) +** +** Execute the step function for an aggregate. The +** function has P5 arguments. P4 is a pointer to the FuncDef +** structure that specifies the function. Register P3 is the +** accumulator. +** +** The P5 arguments are taken from register P2 and its +** successors. +*/ +/* Opcode: AggStep * P2 P3 P4 P5 +** Synopsis: accum=r[P3] step(r[P2@P5]) +** +** Execute the step function for an aggregate. The +** function has P5 arguments. P4 is a pointer to an sqlite3_context +** object that is used to run the function. Register P3 is +** as the accumulator. +** +** The P5 arguments are taken from register P2 and its +** successors. +** +** This opcode is initially coded as OP_AggStep0. On first evaluation, +** the FuncDef stored in P4 is converted into an sqlite3_context and +** the opcode is changed. In this way, the initialization of the +** sqlite3_context only happens once, instead of on each call to the +** step function. +*/ +case OP_AggStep0: { + int n; + sqlite3_context *pCtx; + + assert( pOp->p4type==P4_FUNCDEF ); + n = pOp->p5; + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); + assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); + pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); + if( pCtx==0 ) goto no_mem; + pCtx->pMem = 0; + pCtx->pFunc = pOp->p4.pFunc; + pCtx->iOp = (int)(pOp - aOp); + pCtx->pVdbe = p; + pCtx->argc = n; + pOp->p4type = P4_FUNCCTX; + pOp->p4.pCtx = pCtx; + pOp->opcode = OP_AggStep; + /* Fall through into OP_AggStep */ +} +case OP_AggStep: { + int i; + sqlite3_context *pCtx; + Mem *pMem; + Mem t; + + assert( pOp->p4type==P4_FUNCCTX ); + pCtx = pOp->p4.pCtx; + pMem = &aMem[pOp->p3]; + + /* If this function is inside of a trigger, the register array in aMem[] + ** might change from one evaluation to the next. The next block of code + ** checks to see if the register array has changed, and if so it + ** reinitializes the relavant parts of the sqlite3_context object */ + if( pCtx->pMem != pMem ){ + pCtx->pMem = pMem; + for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; + } + +#ifdef SQLITE_DEBUG + for(i=0; iargc; i++){ + assert( memIsValid(pCtx->argv[i]) ); + REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); + } +#endif + + pMem->n++; + sqlite3VdbeMemInit(&t, db, MEM_Null); + pCtx->pOut = &t; + pCtx->fErrorOrAux = 0; + pCtx->skipFlag = 0; + (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ + if( pCtx->fErrorOrAux ){ + if( pCtx->isError ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(&t)); + rc = pCtx->isError; + } + sqlite3VdbeMemRelease(&t); + if( rc ) goto abort_due_to_error; + }else{ + assert( t.flags==MEM_Null ); + } + if( pCtx->skipFlag ){ + assert( pOp[-1].opcode==OP_CollSeq ); + i = pOp[-1].p1; + if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); + } + break; +} + +/* Opcode: AggFinal P1 P2 * P4 * +** Synopsis: accum=r[P1] N=P2 +** +** Execute the finalizer function for an aggregate. P1 is +** the memory location that is the accumulator for the aggregate. +** +** P2 is the number of arguments that the step function takes and +** P4 is a pointer to the FuncDef for this function. The P2 +** argument is not used by this opcode. It is only there to disambiguate +** functions that can take varying numbers of arguments. The +** P4 argument is only needed for the degenerate case where +** the step function was not previously called. +*/ +case OP_AggFinal: { + Mem *pMem; + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + pMem = &aMem[pOp->p1]; + assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); + rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); + if( rc ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); + goto abort_due_to_error; + } + sqlite3VdbeChangeEncoding(pMem, encoding); + UPDATE_MAX_BLOBSIZE(pMem); + if( sqlite3VdbeMemTooBig(pMem) ){ + goto too_big; + } + break; +} + +#ifndef SQLITE_OMIT_WAL +/* Opcode: Checkpoint P1 P2 P3 * * +** +** Checkpoint database P1. This is a no-op if P1 is not currently in +** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL, +** RESTART, or TRUNCATE. Write 1 or 0 into mem[P3] if the checkpoint returns +** SQLITE_BUSY or not, respectively. Write the number of pages in the +** WAL after the checkpoint into mem[P3+1] and the number of pages +** in the WAL that have been checkpointed after the checkpoint +** completes into mem[P3+2]. However on an error, mem[P3+1] and +** mem[P3+2] are initialized to -1. +*/ +case OP_Checkpoint: { + int i; /* Loop counter */ + int aRes[3]; /* Results */ + Mem *pMem; /* Write results here */ + + assert( p->readOnly==0 ); + aRes[0] = 0; + aRes[1] = aRes[2] = -1; + assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE + || pOp->p2==SQLITE_CHECKPOINT_FULL + || pOp->p2==SQLITE_CHECKPOINT_RESTART + || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE + ); + rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]); + if( rc ){ + if( rc!=SQLITE_BUSY ) goto abort_due_to_error; + rc = SQLITE_OK; + aRes[0] = 1; + } + for(i=0, pMem = &aMem[pOp->p3]; i<3; i++, pMem++){ + sqlite3VdbeMemSetInt64(pMem, (i64)aRes[i]); + } + break; +}; +#endif + +#ifndef SQLITE_OMIT_PRAGMA +/* Opcode: JournalMode P1 P2 P3 * * +** +** Change the journal mode of database P1 to P3. P3 must be one of the +** PAGER_JOURNALMODE_XXX values. If changing between the various rollback +** modes (delete, truncate, persist, off and memory), this is a simple +** operation. No IO is required. +** +** If changing into or out of WAL mode the procedure is more complicated. +** +** Write a string containing the final journal-mode to register P2. +*/ +case OP_JournalMode: { /* out2 */ + Btree *pBt; /* Btree to change journal mode of */ + Pager *pPager; /* Pager associated with pBt */ + int eNew; /* New journal mode */ + int eOld; /* The old journal mode */ +#ifndef SQLITE_OMIT_WAL + const char *zFilename; /* Name of database file for pPager */ +#endif + + pOut = out2Prerelease(p, pOp); + eNew = pOp->p3; + assert( eNew==PAGER_JOURNALMODE_DELETE + || eNew==PAGER_JOURNALMODE_TRUNCATE + || eNew==PAGER_JOURNALMODE_PERSIST + || eNew==PAGER_JOURNALMODE_OFF + || eNew==PAGER_JOURNALMODE_MEMORY + || eNew==PAGER_JOURNALMODE_WAL + || eNew==PAGER_JOURNALMODE_QUERY + ); + assert( pOp->p1>=0 && pOp->p1nDb ); + assert( p->readOnly==0 ); + + pBt = db->aDb[pOp->p1].pBt; + pPager = sqlite3BtreePager(pBt); + eOld = sqlite3PagerGetJournalMode(pPager); + if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; + if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; + +#ifndef SQLITE_OMIT_WAL + zFilename = sqlite3PagerFilename(pPager, 1); + + /* Do not allow a transition to journal_mode=WAL for a database + ** in temporary storage or if the VFS does not support shared memory + */ + if( eNew==PAGER_JOURNALMODE_WAL + && (sqlite3Strlen30(zFilename)==0 /* Temp file */ + || !sqlite3PagerWalSupported(pPager)) /* No shared-memory support */ + ){ + eNew = eOld; + } + + if( (eNew!=eOld) + && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL) + ){ + if( !db->autoCommit || db->nVdbeRead>1 ){ + rc = SQLITE_ERROR; + sqlite3VdbeError(p, + "cannot change %s wal mode from within a transaction", + (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of") + ); + goto abort_due_to_error; + }else{ + + if( eOld==PAGER_JOURNALMODE_WAL ){ + /* If leaving WAL mode, close the log file. If successful, the call + ** to PagerCloseWal() checkpoints and deletes the write-ahead-log + ** file. An EXCLUSIVE lock may still be held on the database file + ** after a successful return. + */ + rc = sqlite3PagerCloseWal(pPager, db); + if( rc==SQLITE_OK ){ + sqlite3PagerSetJournalMode(pPager, eNew); + } + }else if( eOld==PAGER_JOURNALMODE_MEMORY ){ + /* Cannot transition directly from MEMORY to WAL. Use mode OFF + ** as an intermediate */ + sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF); + } + + /* Open a transaction on the database file. Regardless of the journal + ** mode, this transaction always uses a rollback journal. + */ + assert( sqlite3BtreeIsInTrans(pBt)==0 ); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); + } + } + } +#endif /* ifndef SQLITE_OMIT_WAL */ + + if( rc ) eNew = eOld; + eNew = sqlite3PagerSetJournalMode(pPager, eNew); + + pOut->flags = MEM_Str|MEM_Static|MEM_Term; + pOut->z = (char *)sqlite3JournalModename(eNew); + pOut->n = sqlite3Strlen30(pOut->z); + pOut->enc = SQLITE_UTF8; + sqlite3VdbeChangeEncoding(pOut, encoding); + if( rc ) goto abort_due_to_error; + break; +}; +#endif /* SQLITE_OMIT_PRAGMA */ + +#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) +/* Opcode: Vacuum P1 * * * * +** +** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more +** for an attached database. The "temp" database may not be vacuumed. +*/ +case OP_Vacuum: { + assert( p->readOnly==0 ); + rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1); + if( rc ) goto abort_due_to_error; + break; +} +#endif + +#if !defined(SQLITE_OMIT_AUTOVACUUM) +/* Opcode: IncrVacuum P1 P2 * * * +** +** Perform a single step of the incremental vacuum procedure on +** the P1 database. If the vacuum has finished, jump to instruction +** P2. Otherwise, fall through to the next instruction. +*/ +case OP_IncrVacuum: { /* jump */ + Btree *pBt; + + assert( pOp->p1>=0 && pOp->p1nDb ); + assert( DbMaskTest(p->btreeMask, pOp->p1) ); + assert( p->readOnly==0 ); + pBt = db->aDb[pOp->p1].pBt; + rc = sqlite3BtreeIncrVacuum(pBt); + VdbeBranchTaken(rc==SQLITE_DONE,2); + if( rc ){ + if( rc!=SQLITE_DONE ) goto abort_due_to_error; + rc = SQLITE_OK; + goto jump_to_p2; + } + break; +} +#endif + +/* Opcode: Expire P1 * * * * +** +** Cause precompiled statements to expire. When an expired statement +** is executed using sqlite3_step() it will either automatically +** reprepare itself (if it was originally created using sqlite3_prepare_v2()) +** or it will fail with SQLITE_SCHEMA. +** +** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, +** then only the currently executing statement is expired. +*/ +case OP_Expire: { + if( !pOp->p1 ){ + sqlite3ExpirePreparedStatements(db); + }else{ + p->expired = 1; + } + break; +} + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* Opcode: TableLock P1 P2 P3 P4 * +** Synopsis: iDb=P1 root=P2 write=P3 +** +** Obtain a lock on a particular table. This instruction is only used when +** the shared-cache feature is enabled. +** +** P1 is the index of the database in sqlite3.aDb[] of the database +** on which the lock is acquired. A readlock is obtained if P3==0 or +** a write lock if P3==1. +** +** P2 contains the root-page of the table to lock. +** +** P4 contains a pointer to the name of the table being locked. This is only +** used to generate an error message if the lock cannot be obtained. +*/ +case OP_TableLock: { + u8 isWriteLock = (u8)pOp->p3; + if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ + int p1 = pOp->p1; + assert( p1>=0 && p1nDb ); + assert( DbMaskTest(p->btreeMask, p1) ); + assert( isWriteLock==0 || isWriteLock==1 ); + rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); + if( rc ){ + if( (rc&0xFF)==SQLITE_LOCKED ){ + const char *z = pOp->p4.z; + sqlite3VdbeError(p, "database table is locked: %s", z); + } + goto abort_due_to_error; + } + } + break; +} +#endif /* SQLITE_OMIT_SHARED_CACHE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VBegin * * * P4 * +** +** P4 may be a pointer to an sqlite3_vtab structure. If so, call the +** xBegin method for that table. +** +** Also, whether or not P4 is set, check that this is not being called from +** within a callback to a virtual table xSync() method. If it is, the error +** code will be set to SQLITE_LOCKED. +*/ +case OP_VBegin: { + VTable *pVTab; + pVTab = pOp->p4.pVtab; + rc = sqlite3VtabBegin(db, pVTab); + if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab); + if( rc ) goto abort_due_to_error; + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VCreate P1 P2 * * * +** +** P2 is a register that holds the name of a virtual table in database +** P1. Call the xCreate method for that table. +*/ +case OP_VCreate: { + Mem sMem; /* For storing the record being decoded */ + const char *zTab; /* Name of the virtual table */ + + memset(&sMem, 0, sizeof(sMem)); + sMem.db = db; + /* Because P2 is always a static string, it is impossible for the + ** sqlite3VdbeMemCopy() to fail */ + assert( (aMem[pOp->p2].flags & MEM_Str)!=0 ); + assert( (aMem[pOp->p2].flags & MEM_Static)!=0 ); + rc = sqlite3VdbeMemCopy(&sMem, &aMem[pOp->p2]); + assert( rc==SQLITE_OK ); + zTab = (const char*)sqlite3_value_text(&sMem); + assert( zTab || db->mallocFailed ); + if( zTab ){ + rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg); + } + sqlite3VdbeMemRelease(&sMem); + if( rc ) goto abort_due_to_error; + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VDestroy P1 * * P4 * +** +** P4 is the name of a virtual table in database P1. Call the xDestroy method +** of that table. +*/ +case OP_VDestroy: { + db->nVDestroy++; + rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); + db->nVDestroy--; + if( rc ) goto abort_due_to_error; + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VOpen P1 * * P4 * +** +** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. +** P1 is a cursor number. This opcode opens a cursor to the virtual +** table and stores that cursor in P1. +*/ +case OP_VOpen: { + VdbeCursor *pCur; + sqlite3_vtab_cursor *pVCur; + sqlite3_vtab *pVtab; + const sqlite3_module *pModule; + + assert( p->bIsReader ); + pCur = 0; + pVCur = 0; + pVtab = pOp->p4.pVtab->pVtab; + if( pVtab==0 || NEVER(pVtab->pModule==0) ){ + rc = SQLITE_LOCKED; + goto abort_due_to_error; + } + pModule = pVtab->pModule; + rc = pModule->xOpen(pVtab, &pVCur); + sqlite3VtabImportErrmsg(p, pVtab); + if( rc ) goto abort_due_to_error; + + /* Initialize sqlite3_vtab_cursor base class */ + pVCur->pVtab = pVtab; + + /* Initialize vdbe cursor object */ + pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB); + if( pCur ){ + pCur->uc.pVCur = pVCur; + pVtab->nRef++; + }else{ + assert( db->mallocFailed ); + pModule->xClose(pVCur); + goto no_mem; + } + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VFilter P1 P2 P3 P4 * +** Synopsis: iplan=r[P3] zplan='P4' +** +** P1 is a cursor opened using VOpen. P2 is an address to jump to if +** the filtered result set is empty. +** +** P4 is either NULL or a string that was generated by the xBestIndex +** method of the module. The interpretation of the P4 string is left +** to the module implementation. +** +** This opcode invokes the xFilter method on the virtual table specified +** by P1. The integer query plan parameter to xFilter is stored in register +** P3. Register P3+1 stores the argc parameter to be passed to the +** xFilter method. Registers P3+2..P3+1+argc are the argc +** additional parameters which are passed to +** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter. +** +** A jump is made to P2 if the result set after filtering would be empty. +*/ +case OP_VFilter: { /* jump */ + int nArg; + int iQuery; + const sqlite3_module *pModule; + Mem *pQuery; + Mem *pArgc; + sqlite3_vtab_cursor *pVCur; + sqlite3_vtab *pVtab; + VdbeCursor *pCur; + int res; + int i; + Mem **apArg; + + pQuery = &aMem[pOp->p3]; + pArgc = &pQuery[1]; + pCur = p->apCsr[pOp->p1]; + assert( memIsValid(pQuery) ); + REGISTER_TRACE(pOp->p3, pQuery); + assert( pCur->eCurType==CURTYPE_VTAB ); + pVCur = pCur->uc.pVCur; + pVtab = pVCur->pVtab; + pModule = pVtab->pModule; + + /* Grab the index number and argc parameters */ + assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int ); + nArg = (int)pArgc->u.i; + iQuery = (int)pQuery->u.i; + + /* Invoke the xFilter method */ + res = 0; + apArg = p->apArg; + for(i = 0; ixFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg); + sqlite3VtabImportErrmsg(p, pVtab); + if( rc ) goto abort_due_to_error; + res = pModule->xEof(pVCur); + pCur->nullRow = 0; + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VColumn P1 P2 P3 * * +** Synopsis: r[P3]=vcolumn(P2) +** +** Store the value of the P2-th column of +** the row of the virtual-table that the +** P1 cursor is pointing to into register P3. +*/ +case OP_VColumn: { + sqlite3_vtab *pVtab; + const sqlite3_module *pModule; + Mem *pDest; + sqlite3_context sContext; + + VdbeCursor *pCur = p->apCsr[pOp->p1]; + assert( pCur->eCurType==CURTYPE_VTAB ); + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + pDest = &aMem[pOp->p3]; + memAboutToChange(p, pDest); + if( pCur->nullRow ){ + sqlite3VdbeMemSetNull(pDest); + break; + } + pVtab = pCur->uc.pVCur->pVtab; + pModule = pVtab->pModule; + assert( pModule->xColumn ); + memset(&sContext, 0, sizeof(sContext)); + sContext.pOut = pDest; + MemSetTypeFlag(pDest, MEM_Null); + rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); + sqlite3VtabImportErrmsg(p, pVtab); + if( sContext.isError ){ + rc = sContext.isError; + } + sqlite3VdbeChangeEncoding(pDest, encoding); + REGISTER_TRACE(pOp->p3, pDest); + UPDATE_MAX_BLOBSIZE(pDest); + + if( sqlite3VdbeMemTooBig(pDest) ){ + goto too_big; + } + if( rc ) goto abort_due_to_error; + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VNext P1 P2 * * * +** +** Advance virtual table P1 to the next row in its result set and +** jump to instruction P2. Or, if the virtual table has reached +** the end of its result set, then fall through to the next instruction. +*/ +case OP_VNext: { /* jump */ + sqlite3_vtab *pVtab; + const sqlite3_module *pModule; + int res; + VdbeCursor *pCur; + + res = 0; + pCur = p->apCsr[pOp->p1]; + assert( pCur->eCurType==CURTYPE_VTAB ); + if( pCur->nullRow ){ + break; + } + pVtab = pCur->uc.pVCur->pVtab; + pModule = pVtab->pModule; + assert( pModule->xNext ); + + /* Invoke the xNext() method of the module. There is no way for the + ** underlying implementation to return an error if one occurs during + ** xNext(). Instead, if an error occurs, true is returned (indicating that + ** data is available) and the error code returned when xColumn or + ** some other method is next invoked on the save virtual table cursor. + */ + rc = pModule->xNext(pCur->uc.pVCur); + sqlite3VtabImportErrmsg(p, pVtab); + if( rc ) goto abort_due_to_error; + res = pModule->xEof(pCur->uc.pVCur); + VdbeBranchTaken(!res,2); + if( !res ){ + /* If there is data, jump to P2 */ + goto jump_to_p2_and_check_for_interrupt; + } + goto check_for_interrupt; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VRename P1 * * P4 * +** +** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. +** This opcode invokes the corresponding xRename method. The value +** in register P1 is passed as the zName argument to the xRename method. +*/ +case OP_VRename: { + sqlite3_vtab *pVtab; + Mem *pName; + + pVtab = pOp->p4.pVtab->pVtab; + pName = &aMem[pOp->p1]; + assert( pVtab->pModule->xRename ); + assert( memIsValid(pName) ); + assert( p->readOnly==0 ); + REGISTER_TRACE(pOp->p1, pName); + assert( pName->flags & MEM_Str ); + testcase( pName->enc==SQLITE_UTF8 ); + testcase( pName->enc==SQLITE_UTF16BE ); + testcase( pName->enc==SQLITE_UTF16LE ); + rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); + if( rc ) goto abort_due_to_error; + rc = pVtab->pModule->xRename(pVtab, pName->z); + sqlite3VtabImportErrmsg(p, pVtab); + p->expired = 0; + if( rc ) goto abort_due_to_error; + break; +} +#endif + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VUpdate P1 P2 P3 P4 P5 +** Synopsis: data=r[P3@P2] +** +** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. +** This opcode invokes the corresponding xUpdate method. P2 values +** are contiguous memory cells starting at P3 to pass to the xUpdate +** invocation. The value in register (P3+P2-1) corresponds to the +** p2th element of the argv array passed to xUpdate. +** +** The xUpdate method will do a DELETE or an INSERT or both. +** The argv[0] element (which corresponds to memory cell P3) +** is the rowid of a row to delete. If argv[0] is NULL then no +** deletion occurs. The argv[1] element is the rowid of the new +** row. This can be NULL to have the virtual table select the new +** rowid for itself. The subsequent elements in the array are +** the values of columns in the new row. +** +** If P2==1 then no insert is performed. argv[0] is the rowid of +** a row to delete. +** +** P1 is a boolean flag. If it is set to true and the xUpdate call +** is successful, then the value returned by sqlite3_last_insert_rowid() +** is set to the value of the rowid for the row just inserted. +** +** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to +** apply in the case of a constraint failure on an insert or update. +*/ +case OP_VUpdate: { + sqlite3_vtab *pVtab; + const sqlite3_module *pModule; + int nArg; + int i; + sqlite_int64 rowid; + Mem **apArg; + Mem *pX; + + assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback + || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace + ); + assert( p->readOnly==0 ); + pVtab = pOp->p4.pVtab->pVtab; + if( pVtab==0 || NEVER(pVtab->pModule==0) ){ + rc = SQLITE_LOCKED; + goto abort_due_to_error; + } + pModule = pVtab->pModule; + nArg = pOp->p2; + assert( pOp->p4type==P4_VTAB ); + if( ALWAYS(pModule->xUpdate) ){ + u8 vtabOnConflict = db->vtabOnConflict; + apArg = p->apArg; + pX = &aMem[pOp->p3]; + for(i=0; ivtabOnConflict = pOp->p5; + rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); + db->vtabOnConflict = vtabOnConflict; + sqlite3VtabImportErrmsg(p, pVtab); + if( rc==SQLITE_OK && pOp->p1 ){ + assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); + db->lastRowid = rowid; + } + if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ + if( pOp->p5==OE_Ignore ){ + rc = SQLITE_OK; + }else{ + p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); + } + }else{ + p->nChange++; + } + if( rc ) goto abort_due_to_error; + } + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +/* Opcode: Pagecount P1 P2 * * * +** +** Write the current number of pages in database P1 to memory cell P2. +*/ +case OP_Pagecount: { /* out2 */ + pOut = out2Prerelease(p, pOp); + pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt); + break; +} +#endif + + +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +/* Opcode: MaxPgcnt P1 P2 P3 * * +** +** Try to set the maximum page count for database P1 to the value in P3. +** Do not let the maximum page count fall below the current page count and +** do not change the maximum page count value if P3==0. +** +** Store the maximum page count after the change in register P2. +*/ +case OP_MaxPgcnt: { /* out2 */ + unsigned int newMax; + Btree *pBt; + + pOut = out2Prerelease(p, pOp); + pBt = db->aDb[pOp->p1].pBt; + newMax = 0; + if( pOp->p3 ){ + newMax = sqlite3BtreeLastPage(pBt); + if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3; + } + pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax); + break; +} +#endif + + +/* Opcode: Init P1 P2 * P4 * +** Synopsis: Start at P2 +** +** Programs contain a single instance of this opcode as the very first +** opcode. +** +** If tracing is enabled (by the sqlite3_trace()) interface, then +** the UTF-8 string contained in P4 is emitted on the trace callback. +** Or if P4 is blank, use the string returned by sqlite3_sql(). +** +** If P2 is not zero, jump to instruction P2. +** +** Increment the value of P1 so that OP_Once opcodes will jump the +** first time they are evaluated for this run. +*/ +case OP_Init: { /* jump */ + char *zTrace; + int i; + + /* If the P4 argument is not NULL, then it must be an SQL comment string. + ** The "--" string is broken up to prevent false-positives with srcck1.c. + ** + ** This assert() provides evidence for: + ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that + ** would have been returned by the legacy sqlite3_trace() interface by + ** using the X argument when X begins with "--" and invoking + ** sqlite3_expanded_sql(P) otherwise. + */ + assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); + assert( pOp==p->aOp ); /* Always instruction 0 */ + +#ifndef SQLITE_OMIT_TRACE + if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 + && !p->doingRerun + && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 + ){ +#ifndef SQLITE_OMIT_DEPRECATED + if( db->mTrace & SQLITE_TRACE_LEGACY ){ + void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace; + char *z = sqlite3VdbeExpandSql(p, zTrace); + x(db->pTraceArg, z); + sqlite3_free(z); + }else +#endif + if( db->nVdbeExec>1 ){ + char *z = sqlite3MPrintf(db, "-- %s", zTrace); + (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z); + sqlite3DbFree(db, z); + }else{ + (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); + } + } +#ifdef SQLITE_USE_FCNTL_TRACE + zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); + if( zTrace ){ + int j; + for(j=0; jnDb; j++){ + if( DbMaskTest(p->btreeMask, j)==0 ) continue; + sqlite3_file_control(db, db->aDb[j].zDbSName, SQLITE_FCNTL_TRACE, zTrace); + } + } +#endif /* SQLITE_USE_FCNTL_TRACE */ +#ifdef SQLITE_DEBUG + if( (db->flags & SQLITE_SqlTrace)!=0 + && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 + ){ + sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); + } +#endif /* SQLITE_DEBUG */ +#endif /* SQLITE_OMIT_TRACE */ + assert( pOp->p2>0 ); + if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){ + for(i=1; inOp; i++){ + if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0; + } + pOp->p1 = 0; + } + pOp->p1++; + goto jump_to_p2; +} + +#ifdef SQLITE_ENABLE_CURSOR_HINTS +/* Opcode: CursorHint P1 * * P4 * +** +** Provide a hint to cursor P1 that it only needs to return rows that +** satisfy the Expr in P4. TK_REGISTER terms in the P4 expression refer +** to values currently held in registers. TK_COLUMN terms in the P4 +** expression refer to columns in the b-tree to which cursor P1 is pointing. +*/ +case OP_CursorHint: { + VdbeCursor *pC; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pOp->p4type==P4_EXPR ); + pC = p->apCsr[pOp->p1]; + if( pC ){ + assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE, + pOp->p4.pExpr, aMem); + } + break; +} +#endif /* SQLITE_ENABLE_CURSOR_HINTS */ + +/* Opcode: Noop * * * * * +** +** Do nothing. This instruction is often useful as a jump +** destination. +*/ +/* +** The magic Explain opcode are only inserted when explain==2 (which +** is to say when the EXPLAIN QUERY PLAN syntax is used.) +** This opcode records information from the optimizer. It is the +** the same as a no-op. This opcodesnever appears in a real VM program. +*/ +default: { /* This is really OP_Noop and OP_Explain */ + assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain ); + break; +} + +/***************************************************************************** +** The cases of the switch statement above this line should all be indented +** by 6 spaces. But the left-most 6 spaces have been removed to improve the +** readability. From this point on down, the normal indentation rules are +** restored. +*****************************************************************************/ + } + +#ifdef VDBE_PROFILE + { + u64 endTime = sqlite3Hwtime(); + if( endTime>start ) pOrigOp->cycles += endTime - start; + pOrigOp->cnt++; + } +#endif + + /* The following code adds nothing to the actual functionality + ** of the program. It is only here for testing and debugging. + ** On the other hand, it does burn CPU cycles every time through + ** the evaluator loop. So we can leave it out when NDEBUG is defined. + */ +#ifndef NDEBUG + assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp-1] ); + +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_VdbeTrace ){ + u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode]; + if( rc!=0 ) printf("rc=%d\n",rc); + if( opProperty & (OPFLG_OUT2) ){ + registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]); + } + if( opProperty & OPFLG_OUT3 ){ + registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); + } + } +#endif /* SQLITE_DEBUG */ +#endif /* NDEBUG */ + } /* The end of the for(;;) loop the loops through opcodes */ + + /* If we reach this point, it means that execution is finished with + ** an error of some kind. + */ +abort_due_to_error: + if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT; + assert( rc ); + if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ + sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); + } + p->rc = rc; + sqlite3SystemError(db, rc); + testcase( sqlite3GlobalConfig.xLog!=0 ); + sqlite3_log(rc, "statement aborts at %d: [%s] %s", + (int)(pOp - aOp), p->zSql, p->zErrMsg); + sqlite3VdbeHalt(p); + if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); + rc = SQLITE_ERROR; + if( resetSchemaOnFault>0 ){ + sqlite3ResetOneSchema(db, resetSchemaOnFault-1); + } + + /* This is the only way out of this procedure. We have to + ** release the mutexes on btrees that were acquired at the + ** top. */ +vdbe_return: + testcase( nVmStep>0 ); + p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; + sqlite3VdbeLeave(p); + assert( rc!=SQLITE_OK || nExtraDelete==0 + || sqlite3_strlike("DELETE%",p->zSql,0)!=0 + ); + return rc; + + /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH + ** is encountered. + */ +too_big: + sqlite3VdbeError(p, "string or blob too big"); + rc = SQLITE_TOOBIG; + goto abort_due_to_error; + + /* Jump to here if a malloc() fails. + */ +no_mem: + sqlite3OomFault(db); + sqlite3VdbeError(p, "out of memory"); + rc = SQLITE_NOMEM_BKPT; + goto abort_due_to_error; + + /* Jump to here if the sqlite3_interrupt() API sets the interrupt + ** flag. + */ +abort_due_to_interrupt: + assert( db->u1.isInterrupted ); + rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; + p->rc = rc; + sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); + goto abort_due_to_error; +} + + +/************** End of vdbe.c ************************************************/ +/************** Begin file vdbeblob.c ****************************************/ +/* +** 2007 May 1 +** +** 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 used to implement incremental BLOB I/O. +*/ + +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +#ifndef SQLITE_OMIT_INCRBLOB + +/* +** Valid sqlite3_blob* handles point to Incrblob structures. +*/ +typedef struct Incrblob Incrblob; +struct Incrblob { + int nByte; /* Size of open blob, in bytes */ + int iOffset; /* Byte offset of blob in cursor data */ + u16 iCol; /* Table column this handle is open on */ + BtCursor *pCsr; /* Cursor pointing at blob row */ + sqlite3_stmt *pStmt; /* Statement holding cursor open */ + sqlite3 *db; /* The associated database */ + char *zDb; /* Database name */ + Table *pTab; /* Table object */ +}; + + +/* +** This function is used by both blob_open() and blob_reopen(). It seeks +** the b-tree cursor associated with blob handle p to point to row iRow. +** If successful, SQLITE_OK is returned and subsequent calls to +** sqlite3_blob_read() or sqlite3_blob_write() access the specified row. +** +** If an error occurs, or if the specified row does not exist or does not +** contain a value of type TEXT or BLOB in the column nominated when the +** blob handle was opened, then an error code is returned and *pzErr may +** be set to point to a buffer containing an error message. It is the +** responsibility of the caller to free the error message buffer using +** sqlite3DbFree(). +** +** If an error does occur, then the b-tree cursor is closed. All subsequent +** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will +** immediately return SQLITE_ABORT. +*/ +static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ + int rc; /* Error code */ + char *zErr = 0; /* Error message */ + Vdbe *v = (Vdbe *)p->pStmt; + + /* Set the value of register r[1] in the SQL statement to integer iRow. + ** This is done directly as a performance optimization + */ + v->aMem[1].flags = MEM_Int; + v->aMem[1].u.i = iRow; + + /* 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 + ** have been down with an extra OP_Goto, but simply setting the program + ** counter is faster. */ + if( v->pc>3 ){ + v->pc = 3; + rc = sqlite3VdbeExec(v); + }else{ + rc = sqlite3_step(p->pStmt); + } + if( rc==SQLITE_ROW ){ + VdbeCursor *pC = v->apCsr[0]; + u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; + testcase( pC->nHdrParsed==p->iCol ); + testcase( pC->nHdrParsed==p->iCol+1 ); + if( type<12 ){ + zErr = sqlite3MPrintf(p->db, "cannot open value of type %s", + type==0?"null": type==7?"real": "integer" + ); + rc = SQLITE_ERROR; + sqlite3_finalize(p->pStmt); + p->pStmt = 0; + }else{ + p->iOffset = pC->aType[p->iCol + pC->nField]; + p->nByte = sqlite3VdbeSerialTypeLen(type); + p->pCsr = pC->uc.pCursor; + sqlite3BtreeIncrblobCursor(p->pCsr); + } + } + + if( rc==SQLITE_ROW ){ + rc = SQLITE_OK; + }else if( p->pStmt ){ + rc = sqlite3_finalize(p->pStmt); + p->pStmt = 0; + if( rc==SQLITE_OK ){ + zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow); + rc = SQLITE_ERROR; + }else{ + zErr = sqlite3MPrintf(p->db, "%s", sqlite3_errmsg(p->db)); + } + } + + assert( rc!=SQLITE_OK || zErr==0 ); + assert( rc!=SQLITE_ROW && rc!=SQLITE_DONE ); + + *pzErr = zErr; + return rc; +} + +/* +** Open a blob handle. +*/ +SQLITE_API int sqlite3_blob_open( + sqlite3* db, /* The database connection */ + const char *zDb, /* The attached database containing the blob */ + const char *zTable, /* The table containing the blob */ + const char *zColumn, /* The column containing the blob */ + sqlite_int64 iRow, /* The row containing the glob */ + int wrFlag, /* True -> read/write access, false -> read-only */ + sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */ +){ + int nAttempt = 0; + int iCol; /* Index of zColumn in row-record */ + int rc = SQLITE_OK; + char *zErr = 0; + Table *pTab; + Parse *pParse = 0; + Incrblob *pBlob = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppBlob==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + *ppBlob = 0; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zTable==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */ + + 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; + sqlite3DbFree(db, zErr); + zErr = 0; + + sqlite3BtreeEnterAll(db); + pTab = sqlite3LocateTable(pParse, 0, zTable, zDb); + if( pTab && IsVirtual(pTab) ){ + pTab = 0; + sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable); + } + if( pTab && !HasRowid(pTab) ){ + pTab = 0; + sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable); + } +#ifndef SQLITE_OMIT_VIEW + if( pTab && pTab->pSelect ){ + pTab = 0; + sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable); + } +#endif + if( !pTab ){ + if( pParse->zErrMsg ){ + sqlite3DbFree(db, zErr); + zErr = pParse->zErrMsg; + pParse->zErrMsg = 0; + } + rc = SQLITE_ERROR; + sqlite3BtreeLeaveAll(db); + goto blob_open_out; + } + pBlob->pTab = pTab; + pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + + /* Now search pTab for the exact column. */ + for(iCol=0; iColnCol; iCol++) { + if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){ + break; + } + } + if( iCol==pTab->nCol ){ + sqlite3DbFree(db, zErr); + zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn); + rc = SQLITE_ERROR; + sqlite3BtreeLeaveAll(db); + goto blob_open_out; + } + + /* If the value is being opened for writing, check that the + ** column is not indexed, and that it is not part of a foreign key. + */ + if( wrFlag ){ + const char *zFault = 0; + Index *pIdx; +#ifndef SQLITE_OMIT_FOREIGN_KEY + if( db->flags&SQLITE_ForeignKeys ){ + /* Check that the column is not part of an FK child key definition. It + ** is not necessary to check if it is part of a parent key, as parent + ** key columns must be indexed. The check below will pick up this + ** case. */ + FKey *pFKey; + for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + int j; + for(j=0; jnCol; j++){ + if( pFKey->aCol[j].iFrom==iCol ){ + zFault = "foreign key"; + } + } + } + } +#endif + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int j; + for(j=0; jnKeyCol; j++){ + /* FIXME: Be smarter about indexes that use expressions */ + if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==XN_EXPR ){ + zFault = "indexed"; + } + } + } + if( zFault ){ + sqlite3DbFree(db, zErr); + zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault); + rc = SQLITE_ERROR; + sqlite3BtreeLeaveAll(db); + goto blob_open_out; + } + } + + pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse); + assert( pBlob->pStmt || db->mallocFailed ); + if( pBlob->pStmt ){ + + /* This VDBE program seeks a btree cursor to the identified + ** db/table/row entry. The reason for using a vdbe program instead + ** of writing code to use the b-tree layer directly is that the + ** vdbe program will take advantage of the various transaction, + ** locking and error handling infrastructure built into the vdbe. + ** + ** After seeking the cursor, the vdbe executes an OP_ResultRow. + ** Code external to the Vdbe then "borrows" the b-tree cursor and + ** uses it to implement the blob_read(), blob_write() and + ** blob_bytes() functions. + ** + ** The sqlite3_blob_close() function finalizes the vdbe program, + ** which closes the b-tree cursor and (possibly) commits the + ** transaction. + */ + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList openBlob[] = { + {OP_TableLock, 0, 0, 0}, /* 0: Acquire a read or write lock */ + {OP_OpenRead, 0, 0, 0}, /* 1: Open a cursor */ + /* blobSeekToRow() will initialize r[1] to the desired rowid */ + {OP_NotExists, 0, 5, 1}, /* 2: Seek the cursor to rowid=r[1] */ + {OP_Column, 0, 0, 1}, /* 3 */ + {OP_ResultRow, 1, 0, 0}, /* 4 */ + {OP_Halt, 0, 0, 0}, /* 5 */ + }; + Vdbe *v = (Vdbe *)pBlob->pStmt; + int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + VdbeOp *aOp; + + sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, + pTab->pSchema->schema_cookie, + pTab->pSchema->iGeneration); + sqlite3VdbeChangeP5(v, 1); + aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); + + /* Make sure a mutex is held on the table to be accessed */ + sqlite3VdbeUsesBtree(v, iDb); + + if( db->mallocFailed==0 ){ + assert( aOp!=0 ); + /* Configure the OP_TableLock instruction */ +#ifdef SQLITE_OMIT_SHARED_CACHE + aOp[0].opcode = OP_Noop; +#else + aOp[0].p1 = iDb; + aOp[0].p2 = pTab->tnum; + aOp[0].p3 = wrFlag; + sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); + } + if( db->mallocFailed==0 ){ +#endif + + /* Remove either the OP_OpenWrite or OpenRead. Set the P2 + ** parameter of the other to pTab->tnum. */ + if( wrFlag ) aOp[1].opcode = OP_OpenWrite; + aOp[1].p2 = pTab->tnum; + aOp[1].p3 = iDb; + + /* Configure the number of columns. Configure the cursor to + ** think that the table has one more column than it really + ** does. An OP_Column to retrieve this imaginary column will + ** always return an SQL NULL. This is useful because it means + ** we can invoke OP_Column to fill in the vdbe cursors type + ** and offset cache without causing any IO. + */ + aOp[1].p4type = P4_INT32; + aOp[1].p4.i = pTab->nCol+1; + aOp[3].p2 = pTab->nCol; + + pParse->nVar = 0; + pParse->nMem = 1; + pParse->nTab = 1; + sqlite3VdbeMakeReady(v, pParse); + } + } + + pBlob->iCol = iCol; + pBlob->db = db; + sqlite3BtreeLeaveAll(db); + if( db->mallocFailed ){ + goto blob_open_out; + } + rc = blobSeekToRow(pBlob, iRow, &zErr); + } while( (++nAttempt)mallocFailed==0 ){ + *ppBlob = (sqlite3_blob *)pBlob; + }else{ + if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); + sqlite3DbFree(db, pBlob); + } + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); + sqlite3DbFree(db, zErr); + sqlite3ParserReset(pParse); + sqlite3StackFree(db, pParse); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Close a blob handle that was previously created using +** sqlite3_blob_open(). +*/ +SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){ + Incrblob *p = (Incrblob *)pBlob; + int rc; + sqlite3 *db; + + if( p ){ + db = p->db; + sqlite3_mutex_enter(db->mutex); + rc = sqlite3_finalize(p->pStmt); + sqlite3DbFree(db, p); + sqlite3_mutex_leave(db->mutex); + }else{ + rc = SQLITE_OK; + } + return rc; +} + +/* +** Perform a read or write operation on a blob +*/ +static int blobReadWrite( + sqlite3_blob *pBlob, + void *z, + int n, + int iOffset, + int (*xCall)(BtCursor*, u32, u32, void*) +){ + int rc; + Incrblob *p = (Incrblob *)pBlob; + Vdbe *v; + sqlite3 *db; + + if( p==0 ) return SQLITE_MISUSE_BKPT; + db = p->db; + sqlite3_mutex_enter(db->mutex); + v = (Vdbe*)p->pStmt; + + if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){ + /* Request is out of range. Return a transient error. */ + rc = SQLITE_ERROR; + }else if( v==0 ){ + /* If there is no statement handle, then the blob-handle has + ** already been invalidated. Return SQLITE_ABORT in this case. + */ + rc = SQLITE_ABORT; + }else{ + /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is + ** returned, clean-up the statement handle. + */ + assert( db == v->db ); + sqlite3BtreeEnterCursor(p->pCsr); + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){ + /* If a pre-update hook is registered and this is a write cursor, + ** invoke it here. + ** + ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this + ** operation should really be an SQLITE_UPDATE. This is probably + ** incorrect, but is convenient because at this point the new.* values + ** are not easily obtainable. And for the sessions module, an + ** SQLITE_UPDATE where the PK columns do not change is handled in the + ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually + ** slightly more efficient). Since you cannot write to a PK column + ** using the incremental-blob API, this works. For the sessions module + ** anyhow. + */ + sqlite3_int64 iKey; + iKey = sqlite3BtreeIntegerKey(p->pCsr); + sqlite3VdbePreUpdateHook( + v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 + ); + } +#endif + + rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); + sqlite3BtreeLeaveCursor(p->pCsr); + if( rc==SQLITE_ABORT ){ + sqlite3VdbeFinalize(v); + p->pStmt = 0; + }else{ + v->rc = rc; + } + } + sqlite3Error(db, rc); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Read data from a blob handle. +*/ +SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){ + return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreePayloadChecked); +} + +/* +** Write data to a blob handle. +*/ +SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){ + return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData); +} + +/* +** Query a blob handle for the size of the data. +** +** The Incrblob.nByte field is fixed for the lifetime of the Incrblob +** so no mutex is required for access. +*/ +SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){ + Incrblob *p = (Incrblob *)pBlob; + return (p && p->pStmt) ? p->nByte : 0; +} + +/* +** Move an existing blob handle to point to a different row of the same +** database table. +** +** If an error occurs, or if the specified row does not exist or does not +** contain a blob or text value, then an error code is returned and the +** database handle error code and message set. If this happens, then all +** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) +** immediately return SQLITE_ABORT. +*/ +SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ + int rc; + Incrblob *p = (Incrblob *)pBlob; + sqlite3 *db; + + if( p==0 ) return SQLITE_MISUSE_BKPT; + db = p->db; + sqlite3_mutex_enter(db->mutex); + + if( p->pStmt==0 ){ + /* If there is no statement handle, then the blob-handle has + ** already been invalidated. Return SQLITE_ABORT in this case. + */ + rc = SQLITE_ABORT; + }else{ + char *zErr; + rc = blobSeekToRow(p, iRow, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); + sqlite3DbFree(db, zErr); + } + assert( rc!=SQLITE_SCHEMA ); + } + + rc = sqlite3ApiExit(db, rc); + assert( rc==SQLITE_OK || p->pStmt==0 ); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +#endif /* #ifndef SQLITE_OMIT_INCRBLOB */ + +/************** End of vdbeblob.c ********************************************/ +/************** Begin file vdbesort.c ****************************************/ +/* +** 2011-07-09 +** +** 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 for the VdbeSorter object, used in concert with +** a VdbeCursor to sort large numbers of keys for CREATE INDEX statements +** or by SELECT statements with ORDER BY clauses that cannot be satisfied +** using indexes and without LIMIT clauses. +** +** The VdbeSorter object implements a multi-threaded external merge sort +** algorithm that is efficient even if the number of elements being sorted +** exceeds the available memory. +** +** Here is the (internal, non-API) interface between this module and the +** rest of the SQLite system: +** +** sqlite3VdbeSorterInit() Create a new VdbeSorter object. +** +** sqlite3VdbeSorterWrite() Add a single new row to the VdbeSorter +** object. The row is a binary blob in the +** OP_MakeRecord format that contains both +** the ORDER BY key columns and result columns +** in the case of a SELECT w/ ORDER BY, or +** the complete record for an index entry +** in the case of a CREATE INDEX. +** +** sqlite3VdbeSorterRewind() Sort all content previously added. +** Position the read cursor on the +** first sorted element. +** +** sqlite3VdbeSorterNext() Advance the read cursor to the next sorted +** element. +** +** sqlite3VdbeSorterRowkey() Return the complete binary blob for the +** row currently under the read cursor. +** +** sqlite3VdbeSorterCompare() Compare the binary blob for the row +** currently under the read cursor against +** another binary blob X and report if +** X is strictly less than the read cursor. +** Used to enforce uniqueness in a +** CREATE UNIQUE INDEX statement. +** +** sqlite3VdbeSorterClose() Close the VdbeSorter object and reclaim +** all resources. +** +** sqlite3VdbeSorterReset() Refurbish the VdbeSorter for reuse. This +** is like Close() followed by Init() only +** much faster. +** +** The interfaces above must be called in a particular order. Write() can +** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and +** Compare() can only occur in between Rewind() and Close()/Reset(). i.e. +** +** Init() +** for each record: Write() +** Rewind() +** Rowkey()/Compare() +** Next() +** Close() +** +** Algorithm: +** +** Records passed to the sorter via calls to Write() are initially held +** unsorted in main memory. Assuming the amount of memory used never exceeds +** a threshold, when Rewind() is called the set of records is sorted using +** an in-memory merge sort. In this case, no temporary files are required +** and subsequent calls to Rowkey(), Next() and Compare() read records +** directly from main memory. +** +** If the amount of space used to store records in main memory exceeds the +** threshold, then the set of records currently in memory are sorted and +** written to a temporary file in "Packed Memory Array" (PMA) format. +** A PMA created at this point is known as a "level-0 PMA". Higher levels +** of PMAs may be created by merging existing PMAs together - for example +** merging two or more level-0 PMAs together creates a level-1 PMA. +** +** The threshold for the amount of main memory to use before flushing +** records to a PMA is roughly the same as the limit configured for the +** page-cache of the main database. Specifically, the threshold is set to +** the value returned by "PRAGMA main.page_size" multipled by +** that returned by "PRAGMA main.cache_size", in bytes. +** +** If the sorter is running in single-threaded mode, then all PMAs generated +** are appended to a single temporary file. Or, if the sorter is running in +** multi-threaded mode then up to (N+1) temporary files may be opened, where +** N is the configured number of worker threads. In this case, instead of +** sorting the records and writing the PMA to a temporary file itself, the +** calling thread usually launches a worker thread to do so. Except, if +** there are already N worker threads running, the main thread does the work +** itself. +** +** The sorter is running in multi-threaded mode if (a) the library was built +** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater +** than zero, and (b) worker threads have been enabled at runtime by calling +** "PRAGMA threads=N" with some value of N greater than 0. +** +** When Rewind() is called, any data remaining in memory is flushed to a +** final PMA. So at this point the data is stored in some number of sorted +** PMAs within temporary files on disk. +** +** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the +** sorter is running in single-threaded mode, then these PMAs are merged +** incrementally as keys are retreived from the sorter by the VDBE. The +** MergeEngine object, described in further detail below, performs this +** merge. +** +** Or, if running in multi-threaded mode, then a background thread is +** launched to merge the existing PMAs. Once the background thread has +** merged T bytes of data into a single sorted PMA, the main thread +** begins reading keys from that PMA while the background thread proceeds +** with merging the next T bytes of data. And so on. +** +** Parameter T is set to half the value of the memory threshold used +** by Write() above to determine when to create a new PMA. +** +** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when +** Rewind() is called, then a hierarchy of incremental-merges is used. +** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on +** disk are merged together. Then T bytes of data from the second set, and +** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT +** PMAs at a time. This done is to improve locality. +** +** If running in multi-threaded mode and there are more than +** SORTER_MAX_MERGE_COUNT PMAs on disk when Rewind() is called, then more +** than one background thread may be created. Specifically, there may be +** one background thread for each temporary file on disk, and one background +** thread to merge the output of each of the others to a single PMA for +** the main thread to read from. +*/ +/* #include "sqliteInt.h" */ +/* #include "vdbeInt.h" */ + +/* +** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various +** messages to stderr that may be helpful in understanding the performance +** characteristics of the sorter in multi-threaded mode. +*/ +#if 0 +# define SQLITE_DEBUG_SORTER_THREADS 1 +#endif + +/* +** Hard-coded maximum amount of data to accumulate in memory before flushing +** to a level 0 PMA. The purpose of this limit is to prevent various integer +** overflows. 512MiB. +*/ +#define SQLITE_MAX_PMASZ (1<<29) + +/* +** Private objects used by the sorter +*/ +typedef struct MergeEngine MergeEngine; /* Merge PMAs together */ +typedef struct PmaReader PmaReader; /* Incrementally read one PMA */ +typedef struct PmaWriter PmaWriter; /* Incrementally write one PMA */ +typedef struct SorterRecord SorterRecord; /* A record being sorted */ +typedef struct SortSubtask SortSubtask; /* A sub-task in the sort process */ +typedef struct SorterFile SorterFile; /* Temporary file object wrapper */ +typedef struct SorterList SorterList; /* In-memory list of records */ +typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */ + +/* +** A container for a temp file handle and the current amount of data +** stored in the file. +*/ +struct SorterFile { + sqlite3_file *pFd; /* File handle */ + i64 iEof; /* Bytes of data stored in pFd */ +}; + +/* +** An in-memory list of objects to be sorted. +** +** If aMemory==0 then each object is allocated separately and the objects +** are connected using SorterRecord.u.pNext. If aMemory!=0 then all objects +** are stored in the aMemory[] bulk memory, one right after the other, and +** are connected using SorterRecord.u.iNext. +*/ +struct SorterList { + SorterRecord *pList; /* Linked list of records */ + u8 *aMemory; /* If non-NULL, bulk memory to hold pList */ + int szPMA; /* Size of pList as PMA in bytes */ +}; + +/* +** The MergeEngine object is used to combine two or more smaller PMAs into +** one big PMA using a merge operation. Separate PMAs all need to be +** combined into one big PMA in order to be able to step through the sorted +** records in order. +** +** The aReadr[] array contains a PmaReader object for each of the PMAs being +** merged. An aReadr[] object either points to a valid key or else is at EOF. +** ("EOF" means "End Of File". When aReadr[] is at EOF there is no more data.) +** For the purposes of the paragraphs below, we assume that the array is +** actually N elements in size, where N is the smallest power of 2 greater +** to or equal to the number of PMAs being merged. The extra aReadr[] elements +** are treated as if they are empty (always at EOF). +** +** The aTree[] array is also N elements in size. The value of N is stored in +** the MergeEngine.nTree variable. +** +** The final (N/2) elements of aTree[] contain the results of comparing +** pairs of PMA keys together. Element i contains the result of +** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the +** aTree element is set to the index of it. +** +** For the purposes of this comparison, EOF is considered greater than any +** other key value. If the keys are equal (only possible with two EOF +** values), it doesn't matter which index is stored. +** +** The (N/4) elements of aTree[] that precede the final (N/2) described +** above contains the index of the smallest of each block of 4 PmaReaders +** And so on. So that aTree[1] contains the index of the PmaReader that +** currently points to the smallest key value. aTree[0] is unused. +** +** Example: +** +** aReadr[0] -> Banana +** aReadr[1] -> Feijoa +** aReadr[2] -> Elderberry +** aReadr[3] -> Currant +** aReadr[4] -> Grapefruit +** aReadr[5] -> Apple +** aReadr[6] -> Durian +** aReadr[7] -> EOF +** +** aTree[] = { X, 5 0, 5 0, 3, 5, 6 } +** +** The current element is "Apple" (the value of the key indicated by +** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will +** be advanced to the next key in its segment. Say the next key is +** "Eggplant": +** +** aReadr[5] -> Eggplant +** +** The contents of aTree[] are updated first by comparing the new PmaReader +** 5 key to the current key of PmaReader 4 (still "Grapefruit"). The PmaReader +** 5 value is still smaller, so aTree[6] is set to 5. And so on up the tree. +** The value of PmaReader 6 - "Durian" - is now smaller than that of PmaReader +** 5, so aTree[3] is set to 6. Key 0 is smaller than key 6 (Bananafile2. And instead of using a +** background thread to prepare data for the PmaReader, with a single +** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with +** keys from pMerger by the calling thread whenever the PmaReader runs out +** of data. +*/ +struct IncrMerger { + SortSubtask *pTask; /* Task that owns this merger */ + MergeEngine *pMerger; /* Merge engine thread reads data from */ + i64 iStartOff; /* Offset to start writing file at */ + int mxSz; /* Maximum bytes of data to store */ + int bEof; /* Set to true when merge is finished */ + int bUseThread; /* True to use a bg thread for this object */ + SorterFile aFile[2]; /* aFile[0] for reading, [1] for writing */ +}; + +/* +** An instance of this object is used for writing a PMA. +** +** The PMA is written one record at a time. Each record is of an arbitrary +** size. But I/O is more efficient if it occurs in page-sized blocks where +** each block is aligned on a page boundary. This object caches writes to +** the PMA so that aligned, page-size blocks are written. +*/ +struct PmaWriter { + int eFWErr; /* Non-zero if in an error state */ + u8 *aBuffer; /* Pointer to write buffer */ + int nBuffer; /* Size of write buffer in bytes */ + int iBufStart; /* First byte of buffer to write */ + int iBufEnd; /* Last byte of buffer to write */ + i64 iWriteOff; /* Offset of start of buffer in file */ + sqlite3_file *pFd; /* File handle to write to */ +}; + +/* +** This object is the header on a single record while that record is being +** held in memory and prior to being written out as part of a PMA. +** +** How the linked list is connected depends on how memory is being managed +** by this module. If using a separate allocation for each in-memory record +** (VdbeSorter.list.aMemory==0), then the list is always connected using the +** SorterRecord.u.pNext pointers. +** +** Or, if using the single large allocation method (VdbeSorter.list.aMemory!=0), +** then while records are being accumulated the list is linked using the +** SorterRecord.u.iNext offset. This is because the aMemory[] array may +** be sqlite3Realloc()ed while records are being accumulated. Once the VM +** has finished passing records to the sorter, or when the in-memory buffer +** is full, the list is sorted. As part of the sorting process, it is +** converted to use the SorterRecord.u.pNext pointers. See function +** vdbeSorterSort() for details. +*/ +struct SorterRecord { + int nVal; /* Size of the record in bytes */ + union { + SorterRecord *pNext; /* Pointer to next record in list */ + int iNext; /* Offset within aMemory of next record */ + } u; + /* The data for the record immediately follows this header */ +}; + +/* Return a pointer to the buffer containing the record data for SorterRecord +** object p. Should be used as if: +** +** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; } +*/ +#define SRVAL(p) ((void*)((SorterRecord*)(p) + 1)) + + +/* Maximum number of PMAs that a single MergeEngine can merge */ +#define SORTER_MAX_MERGE_COUNT 16 + +static int vdbeIncrSwap(IncrMerger*); +static void vdbeIncrFree(IncrMerger *); + +/* +** Free all memory belonging to the PmaReader object passed as the +** argument. All structure fields are set to zero before returning. +*/ +static void vdbePmaReaderClear(PmaReader *pReadr){ + sqlite3_free(pReadr->aAlloc); + sqlite3_free(pReadr->aBuffer); + if( pReadr->aMap ) sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); + vdbeIncrFree(pReadr->pIncr); + memset(pReadr, 0, sizeof(PmaReader)); +} + +/* +** Read the next nByte bytes of data from the PMA p. +** If successful, set *ppOut to point to a buffer containing the data +** and return SQLITE_OK. Otherwise, if an error occurs, return an SQLite +** error code. +** +** The buffer returned in *ppOut is only valid until the +** next call to this function. +*/ +static int vdbePmaReadBlob( + PmaReader *p, /* PmaReader from which to take the blob */ + int nByte, /* Bytes of data to read */ + u8 **ppOut /* OUT: Pointer to buffer containing data */ +){ + int iBuf; /* Offset within buffer to read from */ + int nAvail; /* Bytes of data available in buffer */ + + if( p->aMap ){ + *ppOut = &p->aMap[p->iReadOff]; + p->iReadOff += nByte; + return SQLITE_OK; + } + + assert( p->aBuffer ); + + /* If there is no more data to be read from the buffer, read the next + ** p->nBuffer bytes of data from the file into it. Or, if there are less + ** than p->nBuffer bytes remaining in the PMA, read all remaining data. */ + iBuf = p->iReadOff % p->nBuffer; + if( iBuf==0 ){ + int nRead; /* Bytes to read from disk */ + int rc; /* sqlite3OsRead() return code */ + + /* Determine how many bytes of data to read. */ + if( (p->iEof - p->iReadOff) > (i64)p->nBuffer ){ + nRead = p->nBuffer; + }else{ + nRead = (int)(p->iEof - p->iReadOff); + } + assert( nRead>0 ); + + /* Readr data from the file. Return early if an error occurs. */ + rc = sqlite3OsRead(p->pFd, p->aBuffer, nRead, p->iReadOff); + assert( rc!=SQLITE_IOERR_SHORT_READ ); + if( rc!=SQLITE_OK ) return rc; + } + nAvail = p->nBuffer - iBuf; + + if( nByte<=nAvail ){ + /* The requested data is available in the in-memory buffer. In this + ** case there is no need to make a copy of the data, just return a + ** pointer into the buffer to the caller. */ + *ppOut = &p->aBuffer[iBuf]; + p->iReadOff += nByte; + }else{ + /* The requested data is not all available in the in-memory buffer. + ** In this case, allocate space at p->aAlloc[] to copy the requested + ** range into. Then return a copy of pointer p->aAlloc to the caller. */ + int nRem; /* Bytes remaining to copy */ + + /* Extend the p->aAlloc[] allocation if required. */ + if( p->nAllocnAlloc*2); + while( nByte>nNew ) nNew = nNew*2; + aNew = sqlite3Realloc(p->aAlloc, nNew); + if( !aNew ) return SQLITE_NOMEM_BKPT; + p->nAlloc = nNew; + p->aAlloc = aNew; + } + + /* Copy as much data as is available in the buffer into the start of + ** p->aAlloc[]. */ + memcpy(p->aAlloc, &p->aBuffer[iBuf], nAvail); + p->iReadOff += nAvail; + nRem = nByte - nAvail; + + /* The following loop copies up to p->nBuffer bytes per iteration into + ** the p->aAlloc[] buffer. */ + while( nRem>0 ){ + int rc; /* vdbePmaReadBlob() return code */ + int nCopy; /* Number of bytes to copy */ + u8 *aNext; /* Pointer to buffer to copy data from */ + + nCopy = nRem; + if( nRem>p->nBuffer ) nCopy = p->nBuffer; + rc = vdbePmaReadBlob(p, nCopy, &aNext); + if( rc!=SQLITE_OK ) return rc; + assert( aNext!=p->aAlloc ); + memcpy(&p->aAlloc[nByte - nRem], aNext, nCopy); + nRem -= nCopy; + } + + *ppOut = p->aAlloc; + } + + return SQLITE_OK; +} + +/* +** Read a varint from the stream of data accessed by p. Set *pnOut to +** the value read. +*/ +static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){ + int iBuf; + + if( p->aMap ){ + p->iReadOff += sqlite3GetVarint(&p->aMap[p->iReadOff], pnOut); + }else{ + iBuf = p->iReadOff % p->nBuffer; + if( iBuf && (p->nBuffer-iBuf)>=9 ){ + p->iReadOff += sqlite3GetVarint(&p->aBuffer[iBuf], pnOut); + }else{ + u8 aVarint[16], *a; + int i = 0, rc; + do{ + rc = vdbePmaReadBlob(p, 1, &a); + if( rc ) return rc; + aVarint[(i++)&0xf] = a[0]; + }while( (a[0]&0x80)!=0 ); + sqlite3GetVarint(aVarint, pnOut); + } + } + + return SQLITE_OK; +} + +/* +** Attempt to memory map file pFile. If successful, set *pp to point to the +** new mapping and return SQLITE_OK. If the mapping is not attempted +** (because the file is too large or the VFS layer is configured not to use +** mmap), return SQLITE_OK and set *pp to NULL. +** +** Or, if an error occurs, return an SQLite error code. The final value of +** *pp is undefined in this case. +*/ +static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){ + int rc = SQLITE_OK; + if( pFile->iEof<=(i64)(pTask->pSorter->db->nMaxSorterMmap) ){ + sqlite3_file *pFd = pFile->pFd; + if( pFd->pMethods->iVersion>=3 ){ + rc = sqlite3OsFetch(pFd, 0, (int)pFile->iEof, (void**)pp); + testcase( rc!=SQLITE_OK ); + } + } + return rc; +} + +/* +** Attach PmaReader pReadr to file pFile (if it is not already attached to +** that file) and seek it to offset iOff within the file. Return SQLITE_OK +** if successful, or an SQLite error code if an error occurs. +*/ +static int vdbePmaReaderSeek( + SortSubtask *pTask, /* Task context */ + PmaReader *pReadr, /* Reader whose cursor is to be moved */ + SorterFile *pFile, /* Sorter file to read from */ + i64 iOff /* Offset in pFile */ +){ + int rc = SQLITE_OK; + + assert( pReadr->pIncr==0 || pReadr->pIncr->bEof==0 ); + + if( sqlite3FaultSim(201) ) return SQLITE_IOERR_READ; + if( pReadr->aMap ){ + sqlite3OsUnfetch(pReadr->pFd, 0, pReadr->aMap); + pReadr->aMap = 0; + } + pReadr->iReadOff = iOff; + pReadr->iEof = pFile->iEof; + pReadr->pFd = pFile->pFd; + + rc = vdbeSorterMapFile(pTask, pFile, &pReadr->aMap); + if( rc==SQLITE_OK && pReadr->aMap==0 ){ + int pgsz = pTask->pSorter->pgsz; + int iBuf = pReadr->iReadOff % pgsz; + if( pReadr->aBuffer==0 ){ + pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz); + if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM_BKPT; + pReadr->nBuffer = pgsz; + } + if( rc==SQLITE_OK && iBuf ){ + int nRead = pgsz - iBuf; + if( (pReadr->iReadOff + nRead) > pReadr->iEof ){ + nRead = (int)(pReadr->iEof - pReadr->iReadOff); + } + rc = sqlite3OsRead( + pReadr->pFd, &pReadr->aBuffer[iBuf], nRead, pReadr->iReadOff + ); + testcase( rc!=SQLITE_OK ); + } + } + + return rc; +} + +/* +** Advance PmaReader pReadr to the next key in its PMA. Return SQLITE_OK if +** no error occurs, or an SQLite error code if one does. +*/ +static int vdbePmaReaderNext(PmaReader *pReadr){ + int rc = SQLITE_OK; /* Return Code */ + u64 nRec = 0; /* Size of record in bytes */ + + + if( pReadr->iReadOff>=pReadr->iEof ){ + IncrMerger *pIncr = pReadr->pIncr; + int bEof = 1; + if( pIncr ){ + rc = vdbeIncrSwap(pIncr); + if( rc==SQLITE_OK && pIncr->bEof==0 ){ + rc = vdbePmaReaderSeek( + pIncr->pTask, pReadr, &pIncr->aFile[0], pIncr->iStartOff + ); + bEof = 0; + } + } + + if( bEof ){ + /* This is an EOF condition */ + vdbePmaReaderClear(pReadr); + testcase( rc!=SQLITE_OK ); + return rc; + } + } + + if( rc==SQLITE_OK ){ + rc = vdbePmaReadVarint(pReadr, &nRec); + } + if( rc==SQLITE_OK ){ + pReadr->nKey = (int)nRec; + rc = vdbePmaReadBlob(pReadr, (int)nRec, &pReadr->aKey); + testcase( rc!=SQLITE_OK ); + } + + return rc; +} + +/* +** Initialize PmaReader pReadr to scan through the PMA stored in file pFile +** starting at offset iStart and ending at offset iEof-1. This function +** leaves the PmaReader pointing to the first key in the PMA (or EOF if the +** PMA is empty). +** +** If the pnByte parameter is NULL, then it is assumed that the file +** contains a single PMA, and that that PMA omits the initial length varint. +*/ +static int vdbePmaReaderInit( + SortSubtask *pTask, /* Task context */ + SorterFile *pFile, /* Sorter file to read from */ + i64 iStart, /* Start offset in pFile */ + PmaReader *pReadr, /* PmaReader to populate */ + i64 *pnByte /* IN/OUT: Increment this value by PMA size */ +){ + int rc; + + assert( pFile->iEof>iStart ); + assert( pReadr->aAlloc==0 && pReadr->nAlloc==0 ); + assert( pReadr->aBuffer==0 ); + assert( pReadr->aMap==0 ); + + rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart); + if( rc==SQLITE_OK ){ + u64 nByte = 0; /* Size of PMA in bytes */ + rc = vdbePmaReadVarint(pReadr, &nByte); + pReadr->iEof = pReadr->iReadOff + nByte; + *pnByte += nByte; + } + + if( rc==SQLITE_OK ){ + rc = vdbePmaReaderNext(pReadr); + } + return rc; +} + +/* +** A version of vdbeSorterCompare() that assumes that it has already been +** determined that the first field of key1 is equal to the first field of +** key2. +*/ +static int vdbeSorterCompareTail( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + UnpackedRecord *r2 = pTask->pUnpacked; + if( *pbKey2Cached==0 ){ + sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); + *pbKey2Cached = 1; + } + return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1); +} + +/* +** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, +** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences +** used by the comparison. Return the result of the comparison. +** +** If IN/OUT parameter *pbKey2Cached is true when this function is called, +** it is assumed that (pTask->pUnpacked) contains the unpacked version +** of key2. If it is false, (pTask->pUnpacked) is populated with the unpacked +** version of key2 and *pbKey2Cached set to true before returning. +** +** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set +** to SQLITE_NOMEM. +*/ +static int vdbeSorterCompare( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + UnpackedRecord *r2 = pTask->pUnpacked; + if( !*pbKey2Cached ){ + sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); + *pbKey2Cached = 1; + } + return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); +} + +/* +** A specially optimized version of vdbeSorterCompare() that assumes that +** the first field of each key is a TEXT value and that the collation +** sequence to compare them with is BINARY. +*/ +static int vdbeSorterCompareText( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + const u8 * const p1 = (const u8 * const)pKey1; + const u8 * const p2 = (const u8 * const)pKey2; + const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ + const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ + + int n1; + int n2; + int res; + + getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2; + getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2; + res = memcmp(v1, v2, MIN(n1, n2)); + if( res==0 ){ + res = n1 - n2; + } + + if( res==0 ){ + if( pTask->pSorter->pKeyInfo->nField>1 ){ + res = vdbeSorterCompareTail( + pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 + ); + } + }else{ + if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ + res = res * -1; + } + } + + return res; +} + +/* +** A specially optimized version of vdbeSorterCompare() that assumes that +** the first field of each key is an INTEGER value. +*/ +static int vdbeSorterCompareInt( + SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ + int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ + const void *pKey1, int nKey1, /* Left side of comparison */ + const void *pKey2, int nKey2 /* Right side of comparison */ +){ + const u8 * const p1 = (const u8 * const)pKey1; + const u8 * const p2 = (const u8 * const)pKey2; + const int s1 = p1[1]; /* Left hand serial type */ + const int s2 = p2[1]; /* Right hand serial type */ + const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ + const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ + int res; /* Return value */ + + assert( (s1>0 && s1<7) || s1==8 || s1==9 ); + assert( (s2>0 && s2<7) || s2==8 || s2==9 ); + + if( s1==s2 ){ + /* The two values have the same sign. Compare using memcmp(). */ + static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 }; + const u8 n = aLen[s1]; + int i; + res = 0; + for(i=0; i7 && s2>7 ){ + res = s1 - s2; + }else{ + if( s2>7 ){ + res = +1; + }else if( s1>7 ){ + res = -1; + }else{ + res = s1 - s2; + } + assert( res!=0 ); + + if( res>0 ){ + if( *v1 & 0x80 ) res = -1; + }else{ + if( *v2 & 0x80 ) res = +1; + } + } + + if( res==0 ){ + if( pTask->pSorter->pKeyInfo->nField>1 ){ + res = vdbeSorterCompareTail( + pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 + ); + } + }else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ + res = res * -1; + } + + return res; +} + +/* +** Initialize the temporary index cursor just opened as a sorter cursor. +** +** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) +** 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 +** is used instead. This is used when sorting records for a CREATE INDEX +** statement. In this case, keys are always delivered to the sorter in +** order of the primary key, which happens to be make up the final part +** of the records being sorted. So if the sort is stable, there is never +** any reason to compare PK fields and they can be ignored for a small +** performance boost. +** +** The sorter can guarantee a stable sort when running in single-threaded +** mode, but not in multi-threaded mode. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +SQLITE_PRIVATE int sqlite3VdbeSorterInit( + sqlite3 *db, /* Database connection (for malloc()) */ + int nField, /* Number of key fields in each record */ + VdbeCursor *pCsr /* Cursor that holds the new sorter */ +){ + int pgsz; /* Page size of main database */ + int i; /* Used to iterate through aTask[] */ + VdbeSorter *pSorter; /* The new sorter */ + KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ + int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ + int sz; /* Size of pSorter in bytes */ + int rc = SQLITE_OK; +#if SQLITE_MAX_WORKER_THREADS==0 +# define nWorker 0 +#else + int nWorker; +#endif + + /* Initialize the upper limit on the number of worker threads */ +#if SQLITE_MAX_WORKER_THREADS>0 + if( sqlite3TempInMemory(db) || sqlite3GlobalConfig.bCoreMutex==0 ){ + nWorker = 0; + }else{ + nWorker = db->aLimit[SQLITE_LIMIT_WORKER_THREADS]; + } +#endif + + /* Do not allow the total number of threads (main thread + all workers) + ** to exceed the maximum merge count */ +#if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT + if( nWorker>=SORTER_MAX_MERGE_COUNT ){ + nWorker = SORTER_MAX_MERGE_COUNT-1; + } +#endif + + assert( pCsr->pKeyInfo && pCsr->pBtx==0 ); + assert( pCsr->eCurType==CURTYPE_SORTER ); + szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); + sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); + + pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); + pCsr->uc.pSorter = pSorter; + if( pSorter==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); + memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); + pKeyInfo->db = 0; + if( nField && nWorker==0 ){ + pKeyInfo->nXField += (pKeyInfo->nField - nField); + pKeyInfo->nField = nField; + } + pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); + pSorter->nTask = nWorker + 1; + pSorter->iPrev = (u8)(nWorker - 1); + pSorter->bUseThreads = (pSorter->nTask>1); + pSorter->db = db; + for(i=0; inTask; i++){ + SortSubtask *pTask = &pSorter->aTask[i]; + pTask->pSorter = pSorter; + } + + if( !sqlite3TempInMemory(db) ){ + i64 mxCache; /* Cache size in bytes*/ + u32 szPma = sqlite3GlobalConfig.szPma; + pSorter->mnPmaSize = szPma * pgsz; + + mxCache = db->aDb[0].pSchema->cache_size; + if( mxCache<0 ){ + /* A negative cache-size value C indicates that the cache is abs(C) + ** KiB in size. */ + mxCache = mxCache * -1024; + }else{ + mxCache = mxCache * pgsz; + } + 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 ){ + assert( pSorter->iMemory==0 ); + pSorter->nMemory = pgsz; + pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); + if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT; + } + } + + if( (pKeyInfo->nField+pKeyInfo->nXField)<13 + && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) + ){ + pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; + } + } + + return rc; +} +#undef nWorker /* Defined at the top of this function */ + +/* +** Free the list of sorted records starting at pRecord. +*/ +static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ + SorterRecord *p; + SorterRecord *pNext; + for(p=pRecord; p; p=pNext){ + pNext = p->u.pNext; + sqlite3DbFree(db, p); + } +} + +/* +** Free all resources owned by the object indicated by argument pTask. All +** fields of *pTask are zeroed before returning. +*/ +static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ + sqlite3DbFree(db, pTask->pUnpacked); +#if SQLITE_MAX_WORKER_THREADS>0 + /* pTask->list.aMemory can only be non-zero if it was handed memory + ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */ + if( pTask->list.aMemory ){ + sqlite3_free(pTask->list.aMemory); + }else +#endif + { + assert( pTask->list.aMemory==0 ); + vdbeSorterRecordFree(0, pTask->list.pList); + } + if( pTask->file.pFd ){ + sqlite3OsCloseFree(pTask->file.pFd); + } + if( pTask->file2.pFd ){ + sqlite3OsCloseFree(pTask->file2.pFd); + } + memset(pTask, 0, sizeof(SortSubtask)); +} + +#ifdef SQLITE_DEBUG_SORTER_THREADS +static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ + i64 t; + int iTask = (pTask - pTask->pSorter->aTask); + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); +} +static void vdbeSorterRewindDebug(const char *zEvent){ + i64 t; + sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t); + fprintf(stderr, "%lld:X %s\n", t, zEvent); +} +static void vdbeSorterPopulateDebug( + SortSubtask *pTask, + const char *zEvent +){ + i64 t; + int iTask = (pTask - pTask->pSorter->aTask); + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:bg%d %s\n", t, iTask, zEvent); +} +static void vdbeSorterBlockDebug( + SortSubtask *pTask, + int bBlocked, + const char *zEvent +){ + if( bBlocked ){ + i64 t; + sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); + fprintf(stderr, "%lld:main %s\n", t, zEvent); + } +} +#else +# define vdbeSorterWorkDebug(x,y) +# define vdbeSorterRewindDebug(y) +# define vdbeSorterPopulateDebug(x,y) +# define vdbeSorterBlockDebug(x,y,z) +#endif + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** Join thread pTask->thread. +*/ +static int vdbeSorterJoinThread(SortSubtask *pTask){ + int rc = SQLITE_OK; + if( pTask->pThread ){ +#ifdef SQLITE_DEBUG_SORTER_THREADS + int bDone = pTask->bDone; +#endif + void *pRet = SQLITE_INT_TO_PTR(SQLITE_ERROR); + vdbeSorterBlockDebug(pTask, !bDone, "enter"); + (void)sqlite3ThreadJoin(pTask->pThread, &pRet); + vdbeSorterBlockDebug(pTask, !bDone, "exit"); + rc = SQLITE_PTR_TO_INT(pRet); + assert( pTask->bDone==1 ); + pTask->bDone = 0; + pTask->pThread = 0; + } + return rc; +} + +/* +** Launch a background thread to run xTask(pIn). +*/ +static int vdbeSorterCreateThread( + SortSubtask *pTask, /* Thread will use this task object */ + void *(*xTask)(void*), /* Routine to run in a separate thread */ + void *pIn /* Argument passed into xTask() */ +){ + assert( pTask->pThread==0 && pTask->bDone==0 ); + return sqlite3ThreadCreate(&pTask->pThread, xTask, pIn); +} + +/* +** Join all outstanding threads launched by SorterWrite() to create +** level-0 PMAs. +*/ +static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ + int rc = rcin; + int i; + + /* This function is always called by the main user thread. + ** + ** If this function is being called after SorterRewind() has been called, + ** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread + ** is currently attempt to join one of the other threads. To avoid a race + ** condition where this thread also attempts to join the same object, join + ** thread pSorter->aTask[pSorter->nTask-1].pThread first. */ + for(i=pSorter->nTask-1; i>=0; i--){ + SortSubtask *pTask = &pSorter->aTask[i]; + int rc2 = vdbeSorterJoinThread(pTask); + if( rc==SQLITE_OK ) rc = rc2; + } + return rc; +} +#else +# define vdbeSorterJoinAll(x,rcin) (rcin) +# define vdbeSorterJoinThread(pTask) SQLITE_OK +#endif + +/* +** Allocate a new MergeEngine object capable of handling up to +** nReader PmaReader inputs. +** +** nReader is automatically rounded up to the next power of two. +** nReader may not exceed SORTER_MAX_MERGE_COUNT even after rounding up. +*/ +static MergeEngine *vdbeMergeEngineNew(int nReader){ + int N = 2; /* Smallest power of two >= nReader */ + int nByte; /* Total bytes of space to allocate */ + MergeEngine *pNew; /* Pointer to allocated object to return */ + + assert( nReader<=SORTER_MAX_MERGE_COUNT ); + + while( NnTree = N; + pNew->pTask = 0; + pNew->aReadr = (PmaReader*)&pNew[1]; + pNew->aTree = (int*)&pNew->aReadr[N]; + } + return pNew; +} + +/* +** Free the MergeEngine object passed as the only argument. +*/ +static void vdbeMergeEngineFree(MergeEngine *pMerger){ + int i; + if( pMerger ){ + for(i=0; inTree; i++){ + vdbePmaReaderClear(&pMerger->aReadr[i]); + } + } + sqlite3_free(pMerger); +} + +/* +** Free all resources associated with the IncrMerger object indicated by +** the first argument. +*/ +static void vdbeIncrFree(IncrMerger *pIncr){ + if( pIncr ){ +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + vdbeSorterJoinThread(pIncr->pTask); + if( pIncr->aFile[0].pFd ) sqlite3OsCloseFree(pIncr->aFile[0].pFd); + if( pIncr->aFile[1].pFd ) sqlite3OsCloseFree(pIncr->aFile[1].pFd); + } +#endif + vdbeMergeEngineFree(pIncr->pMerger); + sqlite3_free(pIncr); + } +} + +/* +** Reset a sorting cursor back to its original empty state. +*/ +SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ + int i; + (void)vdbeSorterJoinAll(pSorter, SQLITE_OK); + assert( pSorter->bUseThreads || pSorter->pReader==0 ); +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->pReader ){ + vdbePmaReaderClear(pSorter->pReader); + sqlite3DbFree(db, pSorter->pReader); + pSorter->pReader = 0; + } +#endif + vdbeMergeEngineFree(pSorter->pMerger); + pSorter->pMerger = 0; + for(i=0; inTask; i++){ + SortSubtask *pTask = &pSorter->aTask[i]; + vdbeSortSubtaskCleanup(db, pTask); + pTask->pSorter = pSorter; + } + if( pSorter->list.aMemory==0 ){ + vdbeSorterRecordFree(0, pSorter->list.pList); + } + pSorter->list.pList = 0; + pSorter->list.szPMA = 0; + pSorter->bUsePMA = 0; + pSorter->iMemory = 0; + pSorter->mxKeysize = 0; + sqlite3DbFree(db, pSorter->pUnpacked); + pSorter->pUnpacked = 0; +} + +/* +** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. +*/ +SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ + VdbeSorter *pSorter; + assert( pCsr->eCurType==CURTYPE_SORTER ); + pSorter = pCsr->uc.pSorter; + if( pSorter ){ + sqlite3VdbeSorterReset(db, pSorter); + sqlite3_free(pSorter->list.aMemory); + sqlite3DbFree(db, pSorter); + pCsr->uc.pSorter = 0; + } +} + +#if SQLITE_MAX_MMAP_SIZE>0 +/* +** The first argument is a file-handle open on a temporary file. The file +** is guaranteed to be nByte bytes or smaller in size. This function +** attempts to extend the file to nByte bytes in size and to ensure that +** the VFS has memory mapped it. +** +** Whether or not the file does end up memory mapped of course depends on +** the specific VFS implementation. +*/ +static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ + if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ + void *p = 0; + int chunksize = 4*1024; + sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); + sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); + sqlite3OsFetch(pFd, 0, (int)nByte, &p); + sqlite3OsUnfetch(pFd, 0, p); + } +} +#else +# define vdbeSorterExtendFile(x,y,z) +#endif + +/* +** Allocate space for a file-handle and open a temporary file. If successful, +** set *ppFd to point to the malloc'd file-handle and return SQLITE_OK. +** Otherwise, set *ppFd to 0 and return an SQLite error code. +*/ +static int vdbeSorterOpenTempFile( + sqlite3 *db, /* Database handle doing sort */ + i64 nExtend, /* Attempt to extend file to this size */ + sqlite3_file **ppFd +){ + int rc; + if( sqlite3FaultSim(202) ) return SQLITE_IOERR_ACCESS; + rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd, + SQLITE_OPEN_TEMP_JOURNAL | + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &rc + ); + if( rc==SQLITE_OK ){ + i64 max = SQLITE_MAX_MMAP_SIZE; + sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max); + if( nExtend>0 ){ + vdbeSorterExtendFile(db, *ppFd, nExtend); + } + } + return rc; +} + +/* +** If it has not already been allocated, allocate the UnpackedRecord +** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or +** if no allocation was required), or SQLITE_NOMEM otherwise. +*/ +static int vdbeSortAllocUnpacked(SortSubtask *pTask){ + 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->errCode = 0; + } + return SQLITE_OK; +} + + +/* +** Merge the two sorted lists p1 and p2 into a single list. +*/ +static SorterRecord *vdbeSorterMerge( + SortSubtask *pTask, /* Calling thread context */ + SorterRecord *p1, /* First list to merge */ + SorterRecord *p2 /* Second list to merge */ +){ + SorterRecord *pFinal = 0; + SorterRecord **pp = &pFinal; + int bCached = 0; + + assert( p1!=0 && p2!=0 ); + for(;;){ + int res; + res = pTask->xCompare( + pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal + ); + + if( res<=0 ){ + *pp = p1; + pp = &p1->u.pNext; + p1 = p1->u.pNext; + if( p1==0 ){ + *pp = p2; + break; + } + }else{ + *pp = p2; + pp = &p2->u.pNext; + p2 = p2->u.pNext; + bCached = 0; + if( p2==0 ){ + *pp = p1; + break; + } + } + } + return pFinal; +} + +/* +** Return the SorterCompare function to compare values collected by the +** sorter object passed as the only argument. +*/ +static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){ + if( p->typeMask==SORTER_TYPE_INTEGER ){ + return vdbeSorterCompareInt; + }else if( p->typeMask==SORTER_TYPE_TEXT ){ + return vdbeSorterCompareText; + } + return vdbeSorterCompare; +} + +/* +** Sort the linked list of records headed at pTask->pList. Return +** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if +** an error occurs. +*/ +static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ + int i; + SorterRecord **aSlot; + SorterRecord *p; + int rc; + + rc = vdbeSortAllocUnpacked(pTask); + if( rc!=SQLITE_OK ) return rc; + + p = pList->pList; + pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter); + + aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); + if( !aSlot ){ + return SQLITE_NOMEM_BKPT; + } + + while( p ){ + SorterRecord *pNext; + if( pList->aMemory ){ + if( (u8*)p==pList->aMemory ){ + pNext = 0; + }else{ + assert( p->u.iNextaMemory) ); + pNext = (SorterRecord*)&pList->aMemory[p->u.iNext]; + } + }else{ + pNext = p->u.pNext; + } + + p->u.pNext = 0; + for(i=0; aSlot[i]; i++){ + p = vdbeSorterMerge(pTask, p, aSlot[i]); + aSlot[i] = 0; + } + aSlot[i] = p; + p = pNext; + } + + p = 0; + for(i=0; i<64; i++){ + if( aSlot[i]==0 ) continue; + p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i]; + } + pList->pList = p; + + sqlite3_free(aSlot); + assert( pTask->pUnpacked->errCode==SQLITE_OK + || pTask->pUnpacked->errCode==SQLITE_NOMEM + ); + return pTask->pUnpacked->errCode; +} + +/* +** Initialize a PMA-writer object. +*/ +static void vdbePmaWriterInit( + sqlite3_file *pFd, /* File handle to write to */ + PmaWriter *p, /* Object to populate */ + int nBuf, /* Buffer size */ + i64 iStart /* Offset of pFd to begin writing at */ +){ + memset(p, 0, sizeof(PmaWriter)); + p->aBuffer = (u8*)sqlite3Malloc(nBuf); + if( !p->aBuffer ){ + p->eFWErr = SQLITE_NOMEM_BKPT; + }else{ + p->iBufEnd = p->iBufStart = (iStart % nBuf); + p->iWriteOff = iStart - p->iBufStart; + p->nBuffer = nBuf; + p->pFd = pFd; + } +} + +/* +** Write nData bytes of data to the PMA. Return SQLITE_OK +** if successful, or an SQLite error code if an error occurs. +*/ +static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ + int nRem = nData; + while( nRem>0 && p->eFWErr==0 ){ + int nCopy = nRem; + if( nCopy>(p->nBuffer - p->iBufEnd) ){ + nCopy = p->nBuffer - p->iBufEnd; + } + + memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy); + p->iBufEnd += nCopy; + if( p->iBufEnd==p->nBuffer ){ + p->eFWErr = sqlite3OsWrite(p->pFd, + &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, + p->iWriteOff + p->iBufStart + ); + p->iBufStart = p->iBufEnd = 0; + p->iWriteOff += p->nBuffer; + } + assert( p->iBufEndnBuffer ); + + nRem -= nCopy; + } +} + +/* +** Flush any buffered data to disk and clean up the PMA-writer object. +** The results of using the PMA-writer after this call are undefined. +** Return SQLITE_OK if flushing the buffered data succeeds or is not +** required. Otherwise, return an SQLite error code. +** +** Before returning, set *piEof to the offset immediately following the +** last byte written to the file. +*/ +static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){ + int rc; + if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){ + p->eFWErr = sqlite3OsWrite(p->pFd, + &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, + p->iWriteOff + p->iBufStart + ); + } + *piEof = (p->iWriteOff + p->iBufEnd); + sqlite3_free(p->aBuffer); + rc = p->eFWErr; + memset(p, 0, sizeof(PmaWriter)); + return rc; +} + +/* +** Write value iVal encoded as a varint to the PMA. Return +** SQLITE_OK if successful, or an SQLite error code if an error occurs. +*/ +static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){ + int nByte; + u8 aByte[10]; + nByte = sqlite3PutVarint(aByte, iVal); + vdbePmaWriteBlob(p, aByte, nByte); +} + +/* +** Write the current contents of in-memory linked-list pList to a level-0 +** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if +** successful, or an SQLite error code otherwise. +** +** The format of a PMA is: +** +** * A varint. This varint contains the total number of bytes of content +** in the PMA (not including the varint itself). +** +** * One or more records packed end-to-end in order of ascending keys. +** Each record consists of a varint followed by a blob of data (the +** key). The varint is the number of bytes in the blob of data. +*/ +static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){ + sqlite3 *db = pTask->pSorter->db; + int rc = SQLITE_OK; /* Return code */ + PmaWriter writer; /* Object used to write to the file */ + +#ifdef SQLITE_DEBUG + /* Set iSz to the expected size of file pTask->file after writing the PMA. + ** This is used by an assert() statement at the end of this function. */ + i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof; +#endif + + vdbeSorterWorkDebug(pTask, "enter"); + memset(&writer, 0, sizeof(PmaWriter)); + assert( pList->szPMA>0 ); + + /* If the first temporary PMA file has not been opened, open it now. */ + if( pTask->file.pFd==0 ){ + rc = vdbeSorterOpenTempFile(db, 0, &pTask->file.pFd); + assert( rc!=SQLITE_OK || pTask->file.pFd ); + assert( pTask->file.iEof==0 ); + assert( pTask->nPMA==0 ); + } + + /* Try to get the file to memory map */ + if( rc==SQLITE_OK ){ + vdbeSorterExtendFile(db, pTask->file.pFd, pTask->file.iEof+pList->szPMA+9); + } + + /* Sort the list */ + if( rc==SQLITE_OK ){ + rc = vdbeSorterSort(pTask, pList); + } + + if( rc==SQLITE_OK ){ + SorterRecord *p; + SorterRecord *pNext = 0; + + vdbePmaWriterInit(pTask->file.pFd, &writer, pTask->pSorter->pgsz, + pTask->file.iEof); + pTask->nPMA++; + vdbePmaWriteVarint(&writer, pList->szPMA); + for(p=pList->pList; p; p=pNext){ + pNext = p->u.pNext; + vdbePmaWriteVarint(&writer, p->nVal); + vdbePmaWriteBlob(&writer, SRVAL(p), p->nVal); + if( pList->aMemory==0 ) sqlite3_free(p); + } + pList->pList = p; + rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof); + } + + vdbeSorterWorkDebug(pTask, "exit"); + assert( rc!=SQLITE_OK || pList->pList==0 ); + assert( rc!=SQLITE_OK || pTask->file.iEof==iSz ); + return rc; +} + +/* +** Advance the MergeEngine to its next entry. +** Set *pbEof to true there is no next entry because +** the MergeEngine has reached the end of all its inputs. +** +** Return SQLITE_OK if successful or an error code if an error occurs. +*/ +static int vdbeMergeEngineStep( + MergeEngine *pMerger, /* The merge engine to advance to the next row */ + int *pbEof /* Set TRUE at EOF. Set false for more content */ +){ + int rc; + int iPrev = pMerger->aTree[1];/* Index of PmaReader to advance */ + SortSubtask *pTask = pMerger->pTask; + + /* Advance the current PmaReader */ + rc = vdbePmaReaderNext(&pMerger->aReadr[iPrev]); + + /* Update contents of aTree[] */ + if( rc==SQLITE_OK ){ + int i; /* Index of aTree[] to recalculate */ + PmaReader *pReadr1; /* First PmaReader to compare */ + PmaReader *pReadr2; /* Second PmaReader to compare */ + int bCached = 0; + + /* Find the first two PmaReaders to compare. The one that was just + ** advanced (iPrev) and the one next to it in the array. */ + pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)]; + pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)]; + + for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){ + /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */ + int iRes; + if( pReadr1->pFd==0 ){ + iRes = +1; + }else if( pReadr2->pFd==0 ){ + iRes = -1; + }else{ + iRes = pTask->xCompare(pTask, &bCached, + pReadr1->aKey, pReadr1->nKey, pReadr2->aKey, pReadr2->nKey + ); + } + + /* If pReadr1 contained the smaller value, set aTree[i] to its index. + ** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this + ** case there is no cache of pReadr2 in pTask->pUnpacked, so set + ** pKey2 to point to the record belonging to pReadr2. + ** + ** Alternatively, if pReadr2 contains the smaller of the two values, + ** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare() + ** was actually called above, then pTask->pUnpacked now contains + ** a value equivalent to pReadr2. So set pKey2 to NULL to prevent + ** vdbeSorterCompare() from decoding pReadr2 again. + ** + ** If the two values were equal, then the value from the oldest + ** PMA should be considered smaller. The VdbeSorter.aReadr[] array + ** is sorted from oldest to newest, so pReadr1 contains older values + ** than pReadr2 iff (pReadr1aTree[i] = (int)(pReadr1 - pMerger->aReadr); + pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; + bCached = 0; + }else{ + if( pReadr1->pFd ) bCached = 0; + pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr); + pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; + } + } + *pbEof = (pMerger->aReadr[pMerger->aTree[1]].pFd==0); + } + + return (rc==SQLITE_OK ? pTask->pUnpacked->errCode : rc); +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for background threads that write level-0 PMAs. +*/ +static void *vdbeSorterFlushThread(void *pCtx){ + SortSubtask *pTask = (SortSubtask*)pCtx; + int rc; /* Return code */ + assert( pTask->bDone==0 ); + rc = vdbeSorterListToPMA(pTask, &pTask->list); + pTask->bDone = 1; + return SQLITE_INT_TO_PTR(rc); +} +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + +/* +** Flush the current contents of VdbeSorter.list to a new PMA, possibly +** using a background thread. +*/ +static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ +#if SQLITE_MAX_WORKER_THREADS==0 + pSorter->bUsePMA = 1; + return vdbeSorterListToPMA(&pSorter->aTask[0], &pSorter->list); +#else + int rc = SQLITE_OK; + int i; + SortSubtask *pTask = 0; /* Thread context used to create new PMA */ + int nWorker = (pSorter->nTask-1); + + /* Set the flag to indicate that at least one PMA has been written. + ** Or will be, anyhow. */ + pSorter->bUsePMA = 1; + + /* Select a sub-task to sort and flush the current list of in-memory + ** records to disk. If the sorter is running in multi-threaded mode, + ** round-robin between the first (pSorter->nTask-1) tasks. Except, if + ** the background thread from a sub-tasks previous turn is still running, + ** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy, + ** fall back to using the final sub-task. The first (pSorter->nTask-1) + ** sub-tasks are prefered as they use background threads - the final + ** sub-task uses the main thread. */ + for(i=0; iiPrev + i + 1) % nWorker; + pTask = &pSorter->aTask[iTest]; + if( pTask->bDone ){ + rc = vdbeSorterJoinThread(pTask); + } + if( rc!=SQLITE_OK || pTask->pThread==0 ) break; + } + + if( rc==SQLITE_OK ){ + if( i==nWorker ){ + /* Use the foreground thread for this operation */ + rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list); + }else{ + /* Launch a background thread for this operation */ + u8 *aMem = pTask->list.aMemory; + void *pCtx = (void*)pTask; + + assert( pTask->pThread==0 && pTask->bDone==0 ); + assert( pTask->list.pList==0 ); + assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 ); + + pSorter->iPrev = (u8)(pTask - pSorter->aTask); + pTask->list = pSorter->list; + pSorter->list.pList = 0; + pSorter->list.szPMA = 0; + if( aMem ){ + pSorter->list.aMemory = aMem; + pSorter->nMemory = sqlite3MallocSize(aMem); + }else if( pSorter->list.aMemory ){ + pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory); + if( !pSorter->list.aMemory ) return SQLITE_NOMEM_BKPT; + } + + rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx); + } + } + + return rc; +#endif /* SQLITE_MAX_WORKER_THREADS!=0 */ +} + +/* +** Add a record to the sorter. +*/ +SQLITE_PRIVATE int sqlite3VdbeSorterWrite( + const VdbeCursor *pCsr, /* Sorter cursor */ + Mem *pVal /* Memory cell containing record */ +){ + VdbeSorter *pSorter; + int rc = SQLITE_OK; /* Return Code */ + SorterRecord *pNew; /* New list element */ + int bFlush; /* True to flush contents of memory to PMA */ + int nReq; /* Bytes of memory required */ + int nPMA; /* Bytes of PMA space required */ + int t; /* serial type of first record field */ + + assert( pCsr->eCurType==CURTYPE_SORTER ); + pSorter = pCsr->uc.pSorter; + getVarint32((const u8*)&pVal->z[1], t); + if( t>0 && t<10 && t!=7 ){ + pSorter->typeMask &= SORTER_TYPE_INTEGER; + }else if( t>10 && (t & 0x01) ){ + pSorter->typeMask &= SORTER_TYPE_TEXT; + }else{ + pSorter->typeMask = 0; + } + + assert( pSorter ); + + /* Figure out whether or not the current contents of memory should be + ** flushed to a PMA before continuing. If so, do so. + ** + ** If using the single large allocation mode (pSorter->aMemory!=0), then + ** flush the contents of memory to a new PMA if (a) at least one value is + ** already in memory and (b) the new value will not fit in memory. + ** + ** Or, if using separate allocations for each record, flush the contents + ** of memory to a PMA if either of the following are true: + ** + ** * The total memory allocated for the in-memory list is greater + ** than (page-size * cache-size), or + ** + ** * The total memory allocated for the in-memory list is greater + ** than (page-size * 10) and sqlite3HeapNearlyFull() returns true. + */ + nReq = pVal->n + sizeof(SorterRecord); + nPMA = pVal->n + sqlite3VarintLen(pVal->n); + if( pSorter->mxPmaSize ){ + if( pSorter->list.aMemory ){ + bFlush = pSorter->iMemory && (pSorter->iMemory+nReq) > pSorter->mxPmaSize; + }else{ + bFlush = ( + (pSorter->list.szPMA > pSorter->mxPmaSize) + || (pSorter->list.szPMA > pSorter->mnPmaSize && sqlite3HeapNearlyFull()) + ); + } + if( bFlush ){ + rc = vdbeSorterFlushPMA(pSorter); + pSorter->list.szPMA = 0; + pSorter->iMemory = 0; + assert( rc!=SQLITE_OK || pSorter->list.pList==0 ); + } + } + + pSorter->list.szPMA += nPMA; + if( nPMA>pSorter->mxKeysize ){ + pSorter->mxKeysize = nPMA; + } + + if( pSorter->list.aMemory ){ + int nMin = pSorter->iMemory + nReq; + + if( nMin>pSorter->nMemory ){ + u8 *aNew; + int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; + int nNew = pSorter->nMemory * 2; + while( nNew < nMin ) nNew = nNew*2; + if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; + if( nNew < nMin ) nNew = nMin; + + aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); + if( !aNew ) return SQLITE_NOMEM_BKPT; + pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; + pSorter->list.aMemory = aNew; + pSorter->nMemory = nNew; + } + + pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory]; + pSorter->iMemory += ROUND8(nReq); + if( pSorter->list.pList ){ + pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory); + } + }else{ + pNew = (SorterRecord *)sqlite3Malloc(nReq); + if( pNew==0 ){ + return SQLITE_NOMEM_BKPT; + } + pNew->u.pNext = pSorter->list.pList; + } + + memcpy(SRVAL(pNew), pVal->z, pVal->n); + pNew->nVal = pVal->n; + pSorter->list.pList = pNew; + + return rc; +} + +/* +** Read keys from pIncr->pMerger and populate pIncr->aFile[1]. The format +** of the data stored in aFile[1] is the same as that used by regular PMAs, +** except that the number-of-bytes varint is omitted from the start. +*/ +static int vdbeIncrPopulate(IncrMerger *pIncr){ + int rc = SQLITE_OK; + int rc2; + i64 iStart = pIncr->iStartOff; + SorterFile *pOut = &pIncr->aFile[1]; + SortSubtask *pTask = pIncr->pTask; + MergeEngine *pMerger = pIncr->pMerger; + PmaWriter writer; + assert( pIncr->bEof==0 ); + + vdbeSorterPopulateDebug(pTask, "enter"); + + vdbePmaWriterInit(pOut->pFd, &writer, pTask->pSorter->pgsz, iStart); + while( rc==SQLITE_OK ){ + int dummy; + PmaReader *pReader = &pMerger->aReadr[ pMerger->aTree[1] ]; + int nKey = pReader->nKey; + i64 iEof = writer.iWriteOff + writer.iBufEnd; + + /* Check if the output file is full or if the input has been exhausted. + ** In either case exit the loop. */ + if( pReader->pFd==0 ) break; + if( (iEof + nKey + sqlite3VarintLen(nKey))>(iStart + pIncr->mxSz) ) break; + + /* Write the next key to the output. */ + vdbePmaWriteVarint(&writer, nKey); + vdbePmaWriteBlob(&writer, pReader->aKey, nKey); + assert( pIncr->pMerger->pTask==pTask ); + rc = vdbeMergeEngineStep(pIncr->pMerger, &dummy); + } + + rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof); + if( rc==SQLITE_OK ) rc = rc2; + vdbeSorterPopulateDebug(pTask, "exit"); + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for background threads that populate aFile[1] of +** multi-threaded IncrMerger objects. +*/ +static void *vdbeIncrPopulateThread(void *pCtx){ + IncrMerger *pIncr = (IncrMerger*)pCtx; + void *pRet = SQLITE_INT_TO_PTR( vdbeIncrPopulate(pIncr) ); + pIncr->pTask->bDone = 1; + return pRet; +} + +/* +** Launch a background thread to populate aFile[1] of pIncr. +*/ +static int vdbeIncrBgPopulate(IncrMerger *pIncr){ + void *p = (void*)pIncr; + assert( pIncr->bUseThread ); + return vdbeSorterCreateThread(pIncr->pTask, vdbeIncrPopulateThread, p); +} +#endif + +/* +** This function is called when the PmaReader corresponding to pIncr has +** finished reading the contents of aFile[0]. Its purpose is to "refill" +** aFile[0] such that the PmaReader should start rereading it from the +** beginning. +** +** For single-threaded objects, this is accomplished by literally reading +** keys from pIncr->pMerger and repopulating aFile[0]. +** +** For multi-threaded objects, all that is required is to wait until the +** background thread is finished (if it is not already) and then swap +** aFile[0] and aFile[1] in place. If the contents of pMerger have not +** been exhausted, this function also launches a new background thread +** to populate the new aFile[1]. +** +** SQLITE_OK is returned on success, or an SQLite error code otherwise. +*/ +static int vdbeIncrSwap(IncrMerger *pIncr){ + int rc = SQLITE_OK; + +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + rc = vdbeSorterJoinThread(pIncr->pTask); + + if( rc==SQLITE_OK ){ + SorterFile f0 = pIncr->aFile[0]; + pIncr->aFile[0] = pIncr->aFile[1]; + pIncr->aFile[1] = f0; + } + + if( rc==SQLITE_OK ){ + if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ + pIncr->bEof = 1; + }else{ + rc = vdbeIncrBgPopulate(pIncr); + } + } + }else +#endif + { + rc = vdbeIncrPopulate(pIncr); + pIncr->aFile[0] = pIncr->aFile[1]; + if( pIncr->aFile[0].iEof==pIncr->iStartOff ){ + pIncr->bEof = 1; + } + } + + return rc; +} + +/* +** Allocate and return a new IncrMerger object to read data from pMerger. +** +** If an OOM condition is encountered, return NULL. In this case free the +** pMerger argument before returning. +*/ +static int vdbeIncrMergerNew( + SortSubtask *pTask, /* The thread that will be using the new IncrMerger */ + MergeEngine *pMerger, /* The MergeEngine that the IncrMerger will control */ + IncrMerger **ppOut /* Write the new IncrMerger here */ +){ + int rc = SQLITE_OK; + IncrMerger *pIncr = *ppOut = (IncrMerger*) + (sqlite3FaultSim(100) ? 0 : sqlite3MallocZero(sizeof(*pIncr))); + if( pIncr ){ + pIncr->pMerger = pMerger; + pIncr->pTask = pTask; + pIncr->mxSz = MAX(pTask->pSorter->mxKeysize+9,pTask->pSorter->mxPmaSize/2); + pTask->file2.iEof += pIncr->mxSz; + }else{ + vdbeMergeEngineFree(pMerger); + rc = SQLITE_NOMEM_BKPT; + } + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** Set the "use-threads" flag on object pIncr. +*/ +static void vdbeIncrMergerSetThreads(IncrMerger *pIncr){ + pIncr->bUseThread = 1; + pIncr->pTask->file2.iEof -= pIncr->mxSz; +} +#endif /* SQLITE_MAX_WORKER_THREADS>0 */ + + + +/* +** Recompute pMerger->aTree[iOut] by comparing the next keys on the +** two PmaReaders that feed that entry. Neither of the PmaReaders +** are advanced. This routine merely does the comparison. +*/ +static void vdbeMergeEngineCompare( + MergeEngine *pMerger, /* Merge engine containing PmaReaders to compare */ + int iOut /* Store the result in pMerger->aTree[iOut] */ +){ + int i1; + int i2; + int iRes; + PmaReader *p1; + PmaReader *p2; + + assert( iOutnTree && iOut>0 ); + + if( iOut>=(pMerger->nTree/2) ){ + i1 = (iOut - pMerger->nTree/2) * 2; + i2 = i1 + 1; + }else{ + i1 = pMerger->aTree[iOut*2]; + i2 = pMerger->aTree[iOut*2+1]; + } + + p1 = &pMerger->aReadr[i1]; + p2 = &pMerger->aReadr[i2]; + + if( p1->pFd==0 ){ + iRes = i2; + }else if( p2->pFd==0 ){ + iRes = i1; + }else{ + SortSubtask *pTask = pMerger->pTask; + int bCached = 0; + int res; + assert( pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ + res = pTask->xCompare( + pTask, &bCached, p1->aKey, p1->nKey, p2->aKey, p2->nKey + ); + if( res<=0 ){ + iRes = i1; + }else{ + iRes = i2; + } + } + + pMerger->aTree[iOut] = iRes; +} + +/* +** Allowed values for the eMode parameter to vdbeMergeEngineInit() +** and vdbePmaReaderIncrMergeInit(). +** +** Only INCRINIT_NORMAL is valid in single-threaded builds (when +** SQLITE_MAX_WORKER_THREADS==0). The other values are only used +** when there exists one or more separate worker threads. +*/ +#define INCRINIT_NORMAL 0 +#define INCRINIT_TASK 1 +#define INCRINIT_ROOT 2 + +/* +** Forward reference required as the vdbeIncrMergeInit() and +** vdbePmaReaderIncrInit() routines are called mutually recursively when +** building a merge tree. +*/ +static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode); + +/* +** Initialize the MergeEngine object passed as the second argument. Once this +** function returns, the first key of merged data may be read from the +** MergeEngine object in the usual fashion. +** +** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge +** objects attached to the PmaReader objects that the merger reads from have +** already been populated, but that they have not yet populated aFile[0] and +** set the PmaReader objects up to read from it. In this case all that is +** required is to call vdbePmaReaderNext() on each PmaReader to point it at +** its first key. +** +** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use +** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data +** to pMerger. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbeMergeEngineInit( + SortSubtask *pTask, /* Thread that will run pMerger */ + MergeEngine *pMerger, /* MergeEngine to initialize */ + int eMode /* One of the INCRINIT_XXX constants */ +){ + int rc = SQLITE_OK; /* Return code */ + int i; /* For looping over PmaReader objects */ + int nTree = pMerger->nTree; + + /* eMode is always INCRINIT_NORMAL in single-threaded mode */ + assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); + + /* Verify that the MergeEngine is assigned to a single thread */ + assert( pMerger->pTask==0 ); + pMerger->pTask = pTask; + + for(i=0; i0 && eMode==INCRINIT_ROOT ){ + /* PmaReaders should be normally initialized in order, as if they are + ** reading from the same temp file this makes for more linear file IO. + ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is + ** in use it will block the vdbePmaReaderNext() call while it uses + ** the main thread to fill its buffer. So calling PmaReaderNext() + ** on this PmaReader before any of the multi-threaded PmaReaders takes + ** better advantage of multi-processor hardware. */ + rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]); + }else{ + rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i], INCRINIT_NORMAL); + } + if( rc!=SQLITE_OK ) return rc; + } + + for(i=pMerger->nTree-1; i>0; i--){ + vdbeMergeEngineCompare(pMerger, i); + } + return pTask->pUnpacked->errCode; +} + +/* +** The PmaReader passed as the first argument is guaranteed to be an +** incremental-reader (pReadr->pIncr!=0). This function serves to open +** and/or initialize the temp file related fields of the IncrMerge +** object at (pReadr->pIncr). +** +** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders +** in the sub-tree headed by pReadr are also initialized. Data is then +** loaded into the buffers belonging to pReadr and it is set to point to +** the first key in its range. +** +** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed +** to be a multi-threaded PmaReader and this function is being called in a +** background thread. In this case all PmaReaders in the sub-tree are +** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to +** pReadr is populated. However, pReadr itself is not set up to point +** to its first key. A call to vdbePmaReaderNext() is still required to do +** that. +** +** The reason this function does not call vdbePmaReaderNext() immediately +** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has +** to block on thread (pTask->thread) before accessing aFile[1]. But, since +** this entire function is being run by thread (pTask->thread), that will +** lead to the current background thread attempting to join itself. +** +** Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed +** that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all +** child-trees have already been initialized using IncrInit(INCRINIT_TASK). +** In this case vdbePmaReaderNext() is called on all child PmaReaders and +** the current PmaReader set to point to the first key in its range. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ + int rc = SQLITE_OK; + IncrMerger *pIncr = pReadr->pIncr; + SortSubtask *pTask = pIncr->pTask; + sqlite3 *db = pTask->pSorter->db; + + /* eMode is always INCRINIT_NORMAL in single-threaded mode */ + assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); + + rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); + + /* Set up the required files for pIncr. A multi-theaded IncrMerge object + ** requires two temp files to itself, whereas a single-threaded object + ** only requires a region of pTask->file2. */ + if( rc==SQLITE_OK ){ + int mxSz = pIncr->mxSz; +#if SQLITE_MAX_WORKER_THREADS>0 + if( pIncr->bUseThread ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); + if( rc==SQLITE_OK ){ + rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); + } + }else +#endif + /*if( !pIncr->bUseThread )*/{ + if( pTask->file2.pFd==0 ){ + assert( pTask->file2.iEof>0 ); + rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); + pTask->file2.iEof = 0; + } + if( rc==SQLITE_OK ){ + pIncr->aFile[1].pFd = pTask->file2.pFd; + pIncr->iStartOff = pTask->file2.iEof; + pTask->file2.iEof += mxSz; + } + } + } + +#if SQLITE_MAX_WORKER_THREADS>0 + if( rc==SQLITE_OK && pIncr->bUseThread ){ + /* Use the current thread to populate aFile[1], even though this + ** PmaReader is multi-threaded. If this is an INCRINIT_TASK object, + ** then this function is already running in background thread + ** pIncr->pTask->thread. + ** + ** If this is the INCRINIT_ROOT object, then it is running in the + ** main VDBE thread. But that is Ok, as that thread cannot return + ** control to the VDBE or proceed with anything useful until the + ** first results are ready from this merger object anyway. + */ + assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); + rc = vdbeIncrPopulate(pIncr); + } +#endif + + if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){ + rc = vdbePmaReaderNext(pReadr); + } + + return rc; +} + +#if SQLITE_MAX_WORKER_THREADS>0 +/* +** The main routine for vdbePmaReaderIncrMergeInit() operations run in +** background threads. +*/ +static void *vdbePmaReaderBgIncrInit(void *pCtx){ + PmaReader *pReader = (PmaReader*)pCtx; + void *pRet = SQLITE_INT_TO_PTR( + vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK) + ); + pReader->pIncr->pTask->bDone = 1; + return pRet; +} +#endif + +/* +** If the PmaReader passed as the first argument is not an incremental-reader +** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes +** the vdbePmaReaderIncrMergeInit() function with the parameters passed to +** this routine to initialize the incremental merge. +** +** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1), +** then a background thread is launched to call vdbePmaReaderIncrMergeInit(). +** Or, if the IncrMerger is single threaded, the same function is called +** using the current thread. +*/ +static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){ + IncrMerger *pIncr = pReadr->pIncr; /* Incremental merger */ + int rc = SQLITE_OK; /* Return code */ + if( pIncr ){ +#if SQLITE_MAX_WORKER_THREADS>0 + assert( pIncr->bUseThread==0 || eMode==INCRINIT_TASK ); + if( pIncr->bUseThread ){ + void *pCtx = (void*)pReadr; + rc = vdbeSorterCreateThread(pIncr->pTask, vdbePmaReaderBgIncrInit, pCtx); + }else +#endif + { + rc = vdbePmaReaderIncrMergeInit(pReadr, eMode); + } + } + return rc; +} + +/* +** Allocate a new MergeEngine object to merge the contents of nPMA level-0 +** PMAs from pTask->file. If no error occurs, set *ppOut to point to +** the new object and return SQLITE_OK. Or, if an error does occur, set *ppOut +** to NULL and return an SQLite error code. +** +** When this function is called, *piOffset is set to the offset of the +** first PMA to read from pTask->file. Assuming no error occurs, it is +** set to the offset immediately following the last byte of the last +** PMA before returning. If an error does occur, then the final value of +** *piOffset is undefined. +*/ +static int vdbeMergeEngineLevel0( + SortSubtask *pTask, /* Sorter task to read from */ + int nPMA, /* Number of PMAs to read */ + i64 *piOffset, /* IN/OUT: Readr offset in pTask->file */ + MergeEngine **ppOut /* OUT: New merge-engine */ +){ + MergeEngine *pNew; /* Merge engine to return */ + i64 iOff = *piOffset; + int i; + int rc = SQLITE_OK; + + *ppOut = pNew = vdbeMergeEngineNew(nPMA); + if( pNew==0 ) rc = SQLITE_NOMEM_BKPT; + + for(i=0; iaReadr[i]; + rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy); + iOff = pReadr->iEof; + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pNew); + *ppOut = 0; + } + *piOffset = iOff; + return rc; +} + +/* +** Return the depth of a tree comprising nPMA PMAs, assuming a fanout of +** SORTER_MAX_MERGE_COUNT. The returned value does not include leaf nodes. +** +** i.e. +** +** nPMA<=16 -> TreeDepth() == 0 +** nPMA<=256 -> TreeDepth() == 1 +** nPMA<=65536 -> TreeDepth() == 2 +*/ +static int vdbeSorterTreeDepth(int nPMA){ + int nDepth = 0; + i64 nDiv = SORTER_MAX_MERGE_COUNT; + while( nDiv < (i64)nPMA ){ + nDiv = nDiv * SORTER_MAX_MERGE_COUNT; + nDepth++; + } + return nDepth; +} + +/* +** pRoot is the root of an incremental merge-tree with depth nDepth (according +** to vdbeSorterTreeDepth()). pLeaf is the iSeq'th leaf to be added to the +** tree, counting from zero. This function adds pLeaf to the tree. +** +** If successful, SQLITE_OK is returned. If an error occurs, an SQLite error +** code is returned and pLeaf is freed. +*/ +static int vdbeSorterAddToTree( + SortSubtask *pTask, /* Task context */ + int nDepth, /* Depth of tree according to TreeDepth() */ + int iSeq, /* Sequence number of leaf within tree */ + MergeEngine *pRoot, /* Root of tree */ + MergeEngine *pLeaf /* Leaf to add to tree */ +){ + int rc = SQLITE_OK; + int nDiv = 1; + int i; + MergeEngine *p = pRoot; + IncrMerger *pIncr; + + rc = vdbeIncrMergerNew(pTask, pLeaf, &pIncr); + + for(i=1; iaReadr[iIter]; + + if( pReadr->pIncr==0 ){ + MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); + if( pNew==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr); + } + } + if( rc==SQLITE_OK ){ + p = pReadr->pIncr->pMerger; + nDiv = nDiv / SORTER_MAX_MERGE_COUNT; + } + } + + if( rc==SQLITE_OK ){ + p->aReadr[iSeq % SORTER_MAX_MERGE_COUNT].pIncr = pIncr; + }else{ + vdbeIncrFree(pIncr); + } + return rc; +} + +/* +** This function is called as part of a SorterRewind() operation on a sorter +** that has already written two or more level-0 PMAs to one or more temp +** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that +** can be used to incrementally merge all PMAs on disk. +** +** If successful, SQLITE_OK is returned and *ppOut set to point to the +** MergeEngine object at the root of the tree before returning. Or, if an +** error occurs, an SQLite error code is returned and the final value +** of *ppOut is undefined. +*/ +static int vdbeSorterMergeTreeBuild( + VdbeSorter *pSorter, /* The VDBE cursor that implements the sort */ + MergeEngine **ppOut /* Write the MergeEngine here */ +){ + MergeEngine *pMain = 0; + int rc = SQLITE_OK; + int iTask; + +#if SQLITE_MAX_WORKER_THREADS>0 + /* If the sorter uses more than one task, then create the top-level + ** MergeEngine here. This MergeEngine will read data from exactly + ** one PmaReader per sub-task. */ + assert( pSorter->bUseThreads || pSorter->nTask==1 ); + if( pSorter->nTask>1 ){ + pMain = vdbeMergeEngineNew(pSorter->nTask); + if( pMain==0 ) rc = SQLITE_NOMEM_BKPT; + } +#endif + + for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ + SortSubtask *pTask = &pSorter->aTask[iTask]; + assert( pTask->nPMA>0 || SQLITE_MAX_WORKER_THREADS>0 ); + if( SQLITE_MAX_WORKER_THREADS==0 || pTask->nPMA ){ + MergeEngine *pRoot = 0; /* Root node of tree for this task */ + int nDepth = vdbeSorterTreeDepth(pTask->nPMA); + i64 iReadOff = 0; + + if( pTask->nPMA<=SORTER_MAX_MERGE_COUNT ){ + rc = vdbeMergeEngineLevel0(pTask, pTask->nPMA, &iReadOff, &pRoot); + }else{ + int i; + int iSeq = 0; + pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT); + if( pRoot==0 ) rc = SQLITE_NOMEM_BKPT; + for(i=0; inPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){ + MergeEngine *pMerger = 0; /* New level-0 PMA merger */ + int nReader; /* Number of level-0 PMAs to merge */ + + nReader = MIN(pTask->nPMA - i, SORTER_MAX_MERGE_COUNT); + rc = vdbeMergeEngineLevel0(pTask, nReader, &iReadOff, &pMerger); + if( rc==SQLITE_OK ){ + rc = vdbeSorterAddToTree(pTask, nDepth, iSeq++, pRoot, pMerger); + } + } + } + + if( rc==SQLITE_OK ){ +#if SQLITE_MAX_WORKER_THREADS>0 + if( pMain!=0 ){ + rc = vdbeIncrMergerNew(pTask, pRoot, &pMain->aReadr[iTask].pIncr); + }else +#endif + { + assert( pMain==0 ); + pMain = pRoot; + } + }else{ + vdbeMergeEngineFree(pRoot); + } + } + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pMain); + pMain = 0; + } + *ppOut = pMain; + return rc; +} + +/* +** This function is called as part of an sqlite3VdbeSorterRewind() operation +** on a sorter that has written two or more PMAs to temporary files. It sets +** up either VdbeSorter.pMerger (for single threaded sorters) or pReader +** (for multi-threaded sorters) so that it can be used to iterate through +** all records stored in the sorter. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ + int rc; /* Return code */ + SortSubtask *pTask0 = &pSorter->aTask[0]; + MergeEngine *pMain = 0; +#if SQLITE_MAX_WORKER_THREADS + sqlite3 *db = pTask0->pSorter->db; + int i; + SorterCompare xCompare = vdbeSorterGetCompare(pSorter); + for(i=0; inTask; i++){ + pSorter->aTask[i].xCompare = xCompare; + } +#endif + + rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); + if( rc==SQLITE_OK ){ +#if SQLITE_MAX_WORKER_THREADS + assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); + if( pSorter->bUseThreads ){ + int iTask; + PmaReader *pReadr = 0; + SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; + rc = vdbeSortAllocUnpacked(pLast); + if( rc==SQLITE_OK ){ + pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); + pSorter->pReader = pReadr; + if( pReadr==0 ) rc = SQLITE_NOMEM_BKPT; + } + if( rc==SQLITE_OK ){ + rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr); + if( rc==SQLITE_OK ){ + vdbeIncrMergerSetThreads(pReadr->pIncr); + for(iTask=0; iTask<(pSorter->nTask-1); iTask++){ + IncrMerger *pIncr; + if( (pIncr = pMain->aReadr[iTask].pIncr) ){ + vdbeIncrMergerSetThreads(pIncr); + assert( pIncr->pTask!=pLast ); + } + } + for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ + /* Check that: + ** + ** a) The incremental merge object is configured to use the + ** right task, and + ** b) If it is using task (nTask-1), it is configured to run + ** in single-threaded mode. This is important, as the + ** root merge (INCRINIT_ROOT) will be using the same task + ** object. + */ + PmaReader *p = &pMain->aReadr[iTask]; + assert( p->pIncr==0 || ( + (p->pIncr->pTask==&pSorter->aTask[iTask]) /* a */ + && (iTask!=pSorter->nTask-1 || p->pIncr->bUseThread==0) /* b */ + )); + rc = vdbePmaReaderIncrInit(p, INCRINIT_TASK); + } + } + pMain = 0; + } + if( rc==SQLITE_OK ){ + rc = vdbePmaReaderIncrMergeInit(pReadr, INCRINIT_ROOT); + } + }else +#endif + { + rc = vdbeMergeEngineInit(pTask0, pMain, INCRINIT_NORMAL); + pSorter->pMerger = pMain; + pMain = 0; + } + } + + if( rc!=SQLITE_OK ){ + vdbeMergeEngineFree(pMain); + } + return rc; +} + + +/* +** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite, +** this function is called to prepare for iterating through the records +** in sorted order. +*/ +SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ + VdbeSorter *pSorter; + int rc = SQLITE_OK; /* Return code */ + + assert( pCsr->eCurType==CURTYPE_SORTER ); + pSorter = pCsr->uc.pSorter; + assert( pSorter ); + + /* If no data has been written to disk, then do not do so now. Instead, + ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly + ** from the in-memory list. */ + if( pSorter->bUsePMA==0 ){ + if( pSorter->list.pList ){ + *pbEof = 0; + rc = vdbeSorterSort(&pSorter->aTask[0], &pSorter->list); + }else{ + *pbEof = 1; + } + return rc; + } + + /* Write the current in-memory list to a PMA. When the VdbeSorterWrite() + ** function flushes the contents of memory to disk, it immediately always + ** creates a new list consisting of a single key immediately afterwards. + ** So the list is never empty at this point. */ + assert( pSorter->list.pList ); + rc = vdbeSorterFlushPMA(pSorter); + + /* Join all threads */ + rc = vdbeSorterJoinAll(pSorter, rc); + + vdbeSorterRewindDebug("rewind"); + + /* Assuming no errors have occurred, set up a merger structure to + ** incrementally read and merge all remaining PMAs. */ + assert( pSorter->pReader==0 ); + if( rc==SQLITE_OK ){ + rc = vdbeSorterSetupMerge(pSorter); + *pbEof = 0; + } + + vdbeSorterRewindDebug("rewinddone"); + return rc; +} + +/* +** Advance to the next element in the sorter. +*/ +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ + VdbeSorter *pSorter; + int rc; /* Return code */ + + assert( pCsr->eCurType==CURTYPE_SORTER ); + pSorter = pCsr->uc.pSorter; + assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) ); + if( pSorter->bUsePMA ){ + assert( pSorter->pReader==0 || pSorter->pMerger==0 ); + assert( pSorter->bUseThreads==0 || pSorter->pReader ); + assert( pSorter->bUseThreads==1 || pSorter->pMerger ); +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->bUseThreads ){ + rc = vdbePmaReaderNext(pSorter->pReader); + *pbEof = (pSorter->pReader->pFd==0); + }else +#endif + /*if( !pSorter->bUseThreads )*/ { + assert( pSorter->pMerger!=0 ); + assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); + rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); + } + }else{ + SorterRecord *pFree = pSorter->list.pList; + pSorter->list.pList = pFree->u.pNext; + pFree->u.pNext = 0; + if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); + *pbEof = !pSorter->list.pList; + rc = SQLITE_OK; + } + return rc; +} + +/* +** Return a pointer to a buffer owned by the sorter that contains the +** current key. +*/ +static void *vdbeSorterRowkey( + const VdbeSorter *pSorter, /* Sorter object */ + int *pnKey /* OUT: Size of current key in bytes */ +){ + void *pKey; + if( pSorter->bUsePMA ){ + PmaReader *pReader; +#if SQLITE_MAX_WORKER_THREADS>0 + if( pSorter->bUseThreads ){ + pReader = pSorter->pReader; + }else +#endif + /*if( !pSorter->bUseThreads )*/{ + pReader = &pSorter->pMerger->aReadr[pSorter->pMerger->aTree[1]]; + } + *pnKey = pReader->nKey; + pKey = pReader->aKey; + }else{ + *pnKey = pSorter->list.pList->nVal; + pKey = SRVAL(pSorter->list.pList); + } + return pKey; +} + +/* +** Copy the current sorter key into the memory cell pOut. +*/ +SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ + VdbeSorter *pSorter; + void *pKey; int nKey; /* Sorter key to copy into pOut */ + + assert( pCsr->eCurType==CURTYPE_SORTER ); + pSorter = pCsr->uc.pSorter; + pKey = vdbeSorterRowkey(pSorter, &nKey); + if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ + return SQLITE_NOMEM_BKPT; + } + pOut->n = nKey; + MemSetTypeFlag(pOut, MEM_Blob); + memcpy(pOut->z, pKey, nKey); + + return SQLITE_OK; +} + +/* +** Compare the key in memory cell pVal with the key that the sorter cursor +** passed as the first argument currently points to. For the purposes of +** the comparison, ignore the rowid field at the end of each record. +** +** If the sorter cursor key contains any NULL values, consider it to be +** less than pVal. Even if pVal also contains NULL values. +** +** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM). +** Otherwise, set *pRes to a negative, zero or positive value if the +** key in pVal is smaller than, equal to or larger than the current sorter +** key. +** +** This routine forms the core of the OP_SorterCompare opcode, which in +** turn is used to verify uniqueness when constructing a UNIQUE INDEX. +*/ +SQLITE_PRIVATE int sqlite3VdbeSorterCompare( + const VdbeCursor *pCsr, /* Sorter cursor */ + Mem *pVal, /* Value to compare to current sorter key */ + int nKeyCol, /* Compare this many columns */ + int *pRes /* OUT: Result of comparison */ +){ + VdbeSorter *pSorter; + UnpackedRecord *r2; + KeyInfo *pKeyInfo; + int i; + void *pKey; int nKey; /* Sorter key to compare pVal with */ + + assert( pCsr->eCurType==CURTYPE_SORTER ); + pSorter = pCsr->uc.pSorter; + r2 = pSorter->pUnpacked; + pKeyInfo = pCsr->pKeyInfo; + if( r2==0 ){ + r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); + if( r2==0 ) return SQLITE_NOMEM_BKPT; + r2->nField = nKeyCol; + } + assert( r2->nField==nKeyCol ); + + pKey = vdbeSorterRowkey(pSorter, &nKey); + sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); + for(i=0; iaMem[i].flags & MEM_Null ){ + *pRes = -1; + return SQLITE_OK; + } + } + + *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2); + return SQLITE_OK; +} + +/************** End of vdbesort.c ********************************************/ +/************** Begin file memjournal.c **************************************/ +/* +** 2008 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 contains code use to implement an in-memory rollback journal. +** The in-memory rollback journal is used to journal transactions for +** ":memory:" databases and when the journal_mode=MEMORY pragma is used. +** +** Update: The in-memory journal is also used to temporarily cache +** smaller journals that are not critical for power-loss recovery. +** For example, statement journals that are not too big will be held +** entirely in memory, thus reducing the number of file I/O calls, and +** more importantly, reducing temporary file creation events. If these +** journals become too large for memory, they are spilled to disk. But +** in the common case, they are usually small and no file I/O needs to +** occur. +*/ +/* #include "sqliteInt.h" */ + +/* Forward references to internal structures */ +typedef struct MemJournal MemJournal; +typedef struct FilePoint FilePoint; +typedef struct FileChunk FileChunk; + +/* +** The rollback journal is composed of a linked list of these structures. +** +** The zChunk array is always at least 8 bytes in size - usually much more. +** Its actual size is stored in the MemJournal.nChunkSize variable. +*/ +struct FileChunk { + FileChunk *pNext; /* Next chunk in the journal */ + u8 zChunk[8]; /* Content of this chunk */ +}; + +/* +** By default, allocate this many bytes of memory for each FileChunk object. +*/ +#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024 + +/* +** For chunk size nChunkSize, return the number of bytes that should +** be allocated for each FileChunk structure. +*/ +#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8)) + +/* +** An instance of this object serves as a cursor into the rollback journal. +** The cursor can be either for reading or writing. +*/ +struct FilePoint { + sqlite3_int64 iOffset; /* Offset from the beginning of the file */ + FileChunk *pChunk; /* Specific chunk into which cursor points */ +}; + +/* +** This structure is a subclass of sqlite3_file. Each open memory-journal +** is an instance of this class. +*/ +struct MemJournal { + const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */ + int nChunkSize; /* In-memory chunk-size */ + + int nSpill; /* Bytes of data before flushing */ + int nSize; /* Bytes of data currently in memory */ + FileChunk *pFirst; /* Head of in-memory chunk-list */ + FilePoint endpoint; /* Pointer to the end of the file */ + FilePoint readpoint; /* Pointer to the end of the last xRead() */ + + int flags; /* xOpen flags */ + sqlite3_vfs *pVfs; /* The "real" underlying VFS */ + const char *zJournal; /* Name of the journal file */ +}; + +/* +** Read data from the in-memory journal file. This is the implementation +** of the sqlite3_vfs.xRead method. +*/ +static int memjrnlRead( + sqlite3_file *pJfd, /* The journal file from which to read */ + void *zBuf, /* Put the results here */ + int iAmt, /* Number of bytes to read */ + sqlite_int64 iOfst /* Begin reading at this offset */ +){ + MemJournal *p = (MemJournal *)pJfd; + u8 *zOut = zBuf; + int nRead = iAmt; + int iChunkOffset; + FileChunk *pChunk; + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + if( (iAmt+iOfst)>p->endpoint.iOffset ){ + return SQLITE_IOERR_SHORT_READ; + } +#endif + + assert( (iAmt+iOfst)<=p->endpoint.iOffset ); + assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 ); + if( p->readpoint.iOffset!=iOfst || iOfst==0 ){ + sqlite3_int64 iOff = 0; + for(pChunk=p->pFirst; + ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst; + pChunk=pChunk->pNext + ){ + iOff += p->nChunkSize; + } + }else{ + pChunk = p->readpoint.pChunk; + assert( pChunk!=0 ); + } + + iChunkOffset = (int)(iOfst%p->nChunkSize); + do { + int iSpace = p->nChunkSize - iChunkOffset; + int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset)); + memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy); + zOut += nCopy; + nRead -= iSpace; + iChunkOffset = 0; + } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 ); + p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0; + p->readpoint.pChunk = pChunk; + + return SQLITE_OK; +} + +/* +** Free the list of FileChunk structures headed at MemJournal.pFirst. +*/ +static void memjrnlFreeChunks(MemJournal *p){ + FileChunk *pIter; + FileChunk *pNext; + for(pIter=p->pFirst; pIter; pIter=pNext){ + pNext = pIter->pNext; + sqlite3_free(pIter); + } + p->pFirst = 0; +} + +/* +** Flush the contents of memory to a real file on disk. +*/ +static int memjrnlCreateFile(MemJournal *p){ + int rc; + sqlite3_file *pReal = (sqlite3_file*)p; + MemJournal copy = *p; + + memset(p, 0, sizeof(MemJournal)); + rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0); + if( rc==SQLITE_OK ){ + int nChunk = copy.nChunkSize; + i64 iOff = 0; + FileChunk *pIter; + for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){ + if( iOff + nChunk > copy.endpoint.iOffset ){ + nChunk = copy.endpoint.iOffset - iOff; + } + rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff); + if( rc ) break; + iOff += nChunk; + } + if( rc==SQLITE_OK ){ + /* No error has occurred. Free the in-memory buffers. */ + memjrnlFreeChunks(©); + } + } + if( rc!=SQLITE_OK ){ + /* If an error occurred while creating or writing to the file, restore + ** the original before returning. This way, SQLite uses the in-memory + ** journal data to roll back changes made to the internal page-cache + ** before this function was called. */ + sqlite3OsClose(pReal); + *p = copy; + } + return rc; +} + + +/* +** Write data to the file. +*/ +static int memjrnlWrite( + sqlite3_file *pJfd, /* The journal file into which to write */ + const void *zBuf, /* Take data to be written from here */ + int iAmt, /* Number of bytes to write */ + sqlite_int64 iOfst /* Begin writing at this offset into the file */ +){ + MemJournal *p = (MemJournal *)pJfd; + int nWrite = iAmt; + u8 *zWrite = (u8 *)zBuf; + + /* If the file should be created now, create it and write the new data + ** into the file on disk. */ + if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){ + int rc = memjrnlCreateFile(p); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst); + } + return rc; + } + + /* If the contents of this write should be stored in memory */ + else{ + /* An in-memory journal file should only ever be appended to. Random + ** access writes are not required. The only exception to this is when + ** the in-memory journal is being used by a connection using the + ** atomic-write optimization. In this case the first 28 bytes of the + ** journal file may be written as part of committing the transaction. */ + assert( iOfst==p->endpoint.iOffset || iOfst==0 ); +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + if( iOfst==0 && p->pFirst ){ + assert( p->nChunkSize>iAmt ); + memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt); + }else +#else + assert( iOfst>0 || p->pFirst==0 ); +#endif + { + while( nWrite>0 ){ + FileChunk *pChunk = p->endpoint.pChunk; + int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize); + int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset); + + if( iChunkOffset==0 ){ + /* New chunk is required to extend the file. */ + FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize)); + if( !pNew ){ + return SQLITE_IOERR_NOMEM_BKPT; + } + pNew->pNext = 0; + if( pChunk ){ + assert( p->pFirst ); + pChunk->pNext = pNew; + }else{ + assert( !p->pFirst ); + p->pFirst = pNew; + } + p->endpoint.pChunk = pNew; + } + + memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace); + zWrite += iSpace; + nWrite -= iSpace; + p->endpoint.iOffset += iSpace; + } + p->nSize = iAmt + iOfst; + } + } + + return SQLITE_OK; +} + +/* +** Truncate the file. +** +** If the journal file is already on disk, truncate it there. Or, if it +** is still in main memory but is being truncated to zero bytes in size, +** ignore +*/ +static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ + MemJournal *p = (MemJournal *)pJfd; + if( ALWAYS(size==0) ){ + memjrnlFreeChunks(p); + p->nSize = 0; + p->endpoint.pChunk = 0; + p->endpoint.iOffset = 0; + p->readpoint.pChunk = 0; + p->readpoint.iOffset = 0; + } + return SQLITE_OK; +} + +/* +** Close the file. +*/ +static int memjrnlClose(sqlite3_file *pJfd){ + MemJournal *p = (MemJournal *)pJfd; + memjrnlFreeChunks(p); + return SQLITE_OK; +} + +/* +** Sync the file. +** +** If the real file has been created, call its xSync method. Otherwise, +** syncing an in-memory journal is a no-op. +*/ +static int memjrnlSync(sqlite3_file *pJfd, int flags){ + UNUSED_PARAMETER2(pJfd, flags); + return SQLITE_OK; +} + +/* +** Query the size of the file in bytes. +*/ +static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ + MemJournal *p = (MemJournal *)pJfd; + *pSize = (sqlite_int64) p->endpoint.iOffset; + return SQLITE_OK; +} + +/* +** Table of methods for MemJournal sqlite3_file object. +*/ +static const struct sqlite3_io_methods MemJournalMethods = { + 1, /* iVersion */ + memjrnlClose, /* xClose */ + memjrnlRead, /* xRead */ + memjrnlWrite, /* xWrite */ + memjrnlTruncate, /* xTruncate */ + memjrnlSync, /* xSync */ + memjrnlFileSize, /* xFileSize */ + 0, /* xLock */ + 0, /* xUnlock */ + 0, /* xCheckReservedLock */ + 0, /* xFileControl */ + 0, /* xSectorSize */ + 0, /* xDeviceCharacteristics */ + 0, /* xShmMap */ + 0, /* xShmLock */ + 0, /* xShmBarrier */ + 0, /* xShmUnmap */ + 0, /* xFetch */ + 0 /* xUnfetch */ +}; + +/* +** Open a journal file. +** +** The behaviour of the journal file depends on the value of parameter +** nSpill. If nSpill is 0, then the journal file is always create and +** accessed using the underlying VFS. If nSpill is less than zero, then +** all content is always stored in main-memory. Finally, if nSpill is a +** positive value, then the journal file is initially created in-memory +** but may be flushed to disk later on. In this case the journal file is +** flushed to disk either when it grows larger than nSpill bytes in size, +** or when sqlite3JournalCreate() is called. +*/ +SQLITE_PRIVATE int sqlite3JournalOpen( + sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */ + const char *zName, /* Name of the journal file */ + sqlite3_file *pJfd, /* Preallocated, blank file handle */ + int flags, /* Opening flags */ + int nSpill /* Bytes buffered before opening the file */ +){ + MemJournal *p = (MemJournal*)pJfd; + + /* Zero the file-handle object. If nSpill was passed zero, initialize + ** it using the sqlite3OsOpen() function of the underlying VFS. In this + ** case none of the code in this module is executed as a result of calls + ** made on the journal file-handle. */ + memset(p, 0, sizeof(MemJournal)); + if( nSpill==0 ){ + return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); + } + + if( nSpill>0 ){ + p->nChunkSize = nSpill; + }else{ + p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk); + assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) ); + } + + p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods; + p->nSpill = nSpill; + p->flags = flags; + p->zJournal = zName; + p->pVfs = pVfs; + return SQLITE_OK; +} + +/* +** Open an in-memory journal file. +*/ +SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){ + sqlite3JournalOpen(0, 0, pJfd, 0, -1); +} + +#ifdef SQLITE_ENABLE_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. +*/ +SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){ + int rc = SQLITE_OK; + if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){ + rc = memjrnlCreateFile((MemJournal*)p); + } + return rc; +} +#endif + +/* +** The file-handle passed as the only argument is open on a journal file. +** Return true if this "journal file" is currently stored in heap memory, +** or false otherwise. +*/ +SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){ + return p->pMethods==&MemJournalMethods; +} + +/* +** Return the number of bytes required to store a JournalFile that uses vfs +** pVfs to create the underlying on-disk files. +*/ +SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ + return MAX(pVfs->szOsFile, (int)sizeof(MemJournal)); +} + +/************** End of memjournal.c ******************************************/ +/************** Begin file walker.c ******************************************/ +/* +** 2008 August 16 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains routines used for walking the parser tree for +** an SQL statement. +*/ +/* #include "sqliteInt.h" */ +/* #include */ +/* #include */ + + +/* +** Walk an expression tree. Invoke the callback once for each node +** of the expression, while descending. (In other words, the callback +** is invoked before visiting children.) +** +** The return value from the callback should be one of the WRC_* +** constants to specify how to proceed with the walk. +** +** WRC_Continue Continue descending down the tree. +** +** WRC_Prune Do not descend into child nodes, but allow +** the walk to continue with sibling nodes. +** +** WRC_Abort Do no more callbacks. Unwind the stack and +** return from the top-level walk call. +** +** The return value from this routine is WRC_Abort to abandon the tree walk +** and WRC_Continue to continue. +*/ +static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ + int rc; + testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); + testcase( ExprHasProperty(pExpr, EP_Reduced) ); + rc = pWalker->xExprCallback(pWalker, pExpr); + if( rc || ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ + return rc & WRC_Abort; + } + if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; + if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; + 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; + } + return WRC_Continue; +} +SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ + return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; +} + +/* +** Call sqlite3WalkExpr() for every expression in list p or until +** an abort request is seen. +*/ +SQLITE_PRIVATE int sqlite3WalkExprList(Walker *pWalker, ExprList *p){ + int i; + struct ExprList_item *pItem; + if( p ){ + for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ + if( sqlite3WalkExpr(pWalker, pItem->pExpr) ) return WRC_Abort; + } + } + return WRC_Continue; +} + +/* +** Walk all expressions associated with SELECT statement p. Do +** not invoke the SELECT callback on p, but do (of course) invoke +** any expr callbacks and SELECT callbacks that come from subqueries. +** Return WRC_Abort or WRC_Continue. +*/ +SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ + if( sqlite3WalkExprList(pWalker, p->pEList) ) return WRC_Abort; + if( sqlite3WalkExpr(pWalker, p->pWhere) ) return WRC_Abort; + if( sqlite3WalkExprList(pWalker, p->pGroupBy) ) return WRC_Abort; + if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort; + if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort; + if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort; + if( sqlite3WalkExpr(pWalker, p->pOffset) ) return WRC_Abort; + return WRC_Continue; +} + +/* +** Walk the parse trees associated with all subqueries in the +** FROM clause of SELECT statement p. Do not invoke the select +** callback on p, but do invoke it on each FROM clause subquery +** and on any subqueries further down in the tree. Return +** WRC_Abort or WRC_Continue; +*/ +SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ + SrcList *pSrc; + int i; + struct SrcList_item *pItem; + + pSrc = p->pSrc; + if( ALWAYS(pSrc) ){ + for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ + if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){ + return WRC_Abort; + } + if( pItem->fg.isTabFunc + && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg) + ){ + return WRC_Abort; + } + } + } + return WRC_Continue; +} + +/* +** Call sqlite3WalkExpr() for every expression in Select statement p. +** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and +** on the compound select chain, p->pPrior. +** +** If it is not NULL, the xSelectCallback() callback is invoked before +** the walk of the expressions and FROM clause. The xSelectCallback2() +** method, if it is not NULL, is invoked following the walk of the +** expressions and FROM clause. +** +** Return WRC_Continue under normal conditions. Return WRC_Abort if +** there is an abort request. +** +** If the Walker does not have an xSelectCallback() then this routine +** is a no-op returning WRC_Continue. +*/ +SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ + int rc; + if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){ + return WRC_Continue; + } + rc = WRC_Continue; + pWalker->walkerDepth++; + while( p ){ + if( pWalker->xSelectCallback ){ + rc = pWalker->xSelectCallback(pWalker, p); + if( rc ) break; + } + if( sqlite3WalkSelectExpr(pWalker, p) + || sqlite3WalkSelectFrom(pWalker, p) + ){ + pWalker->walkerDepth--; + return WRC_Abort; + } + if( pWalker->xSelectCallback2 ){ + pWalker->xSelectCallback2(pWalker, p); + } + p = p->pPrior; + } + pWalker->walkerDepth--; + return rc & WRC_Abort; +} + +/************** End of walker.c **********************************************/ +/************** Begin file resolve.c *****************************************/ +/* +** 2008 August 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. +** +************************************************************************* +** +** This file contains routines used for walking the parser tree and +** resolve all identifiers by associating them with a particular +** table and column. +*/ +/* #include "sqliteInt.h" */ + +/* +** Walk the expression tree pExpr and increase the aggregate function +** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node. +** This needs to occur when copying a TK_AGG_FUNCTION node from an +** outer query into an inner subquery. +** +** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) +** is a helper function - a callback for the tree walker. +*/ +static int incrAggDepth(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; + return WRC_Continue; +} +static void incrAggFunctionDepth(Expr *pExpr, int N){ + if( N>0 ){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = incrAggDepth; + w.u.n = N; + sqlite3WalkExpr(&w, pExpr); + } +} + +/* +** Turn the pExpr expression into an alias for the iCol-th column of the +** result set in pEList. +** +** If the reference is followed by a COLLATE operator, then make sure +** the COLLATE operator is preserved. For example: +** +** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase; +** +** Should be transformed into: +** +** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase; +** +** The nSubquery parameter specifies how many levels of subquery the +** alias is removed from the original expression. The usual value is +** zero but it might be more if the alias is contained within a subquery +** of the original expression. The Expr.op2 field of TK_AGG_FUNCTION +** structures must be increased by the nSubquery amount. +*/ +static void resolveAlias( + Parse *pParse, /* Parsing context */ + ExprList *pEList, /* A result set */ + int iCol, /* A column in the result set. 0..pEList->nExpr-1 */ + Expr *pExpr, /* Transform this into an alias to the result set */ + const char *zType, /* "GROUP" or "ORDER" or "" */ + int nSubquery /* Number of subqueries that the label is moving */ +){ + Expr *pOrig; /* The iCol-th column of the result set */ + Expr *pDup; /* Copy of pOrig */ + sqlite3 *db; /* The database connection */ + + assert( iCol>=0 && iColnExpr ); + pOrig = pEList->a[iCol].pExpr; + assert( pOrig!=0 ); + db = pParse->db; + pDup = sqlite3ExprDup(db, pOrig, 0); + if( pDup==0 ) return; + if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); + if( pExpr->op==TK_COLLATE ){ + pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); + } + ExprSetProperty(pDup, EP_Alias); + + /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This + ** prevents ExprDelete() from deleting the Expr structure itself, + ** allowing it to be repopulated by the memcpy() on the following line. + ** The pExpr->u.zToken might point into memory that will be freed by the + ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to + ** make a copy of the token before doing the sqlite3DbFree(). + */ + ExprSetProperty(pExpr, EP_Static); + sqlite3ExprDelete(db, pExpr); + memcpy(pExpr, pDup, sizeof(*pExpr)); + if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ + assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); + pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); + pExpr->flags |= EP_MemToken; + } + sqlite3DbFree(db, pDup); +} + + +/* +** Return TRUE if the name zCol occurs anywhere in the USING clause. +** +** Return FALSE if the USING clause is NULL or if it does not contain +** zCol. +*/ +static int nameInUsingClause(IdList *pUsing, const char *zCol){ + if( pUsing ){ + int k; + for(k=0; knId; k++){ + if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1; + } + } + return 0; +} + +/* +** Subqueries stores the original database, table and column names for their +** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN". +** Check to see if the zSpan given to this routine matches the zDb, zTab, +** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will +** match anything. +*/ +SQLITE_PRIVATE int sqlite3MatchSpanName( + const char *zSpan, + const char *zCol, + const char *zTab, + const char *zDb +){ + int n; + for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} + if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){ + return 0; + } + zSpan += n+1; + for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} + if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){ + return 0; + } + zSpan += n+1; + if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){ + return 0; + } + return 1; +} + +/* +** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up +** that name in the set of source tables in pSrcList and make the pExpr +** expression node refer back to that source column. The following changes +** are made to pExpr: +** +** pExpr->iDb Set the index in db->aDb[] of the database X +** (even if X is implied). +** pExpr->iTable Set to the cursor number for the table obtained +** from pSrcList. +** pExpr->pTab Points to the Table structure of X.Y (even if +** X and/or Y are implied.) +** pExpr->iColumn Set to the column number within the table. +** pExpr->op Set to TK_COLUMN. +** pExpr->pLeft Any expression this points to is deleted +** pExpr->pRight Any expression this points to is deleted. +** +** The zDb variable is the name of the database (the "X"). This value may be +** NULL meaning that name is of the form Y.Z or Z. Any available database +** can be used. The zTable variable is the name of the table (the "Y"). This +** value can be NULL if zDb is also NULL. If zTable is NULL it +** means that the form of the name is Z and that columns from any table +** can be used. +** +** If the name cannot be resolved unambiguously, leave an error message +** in pParse and return WRC_Abort. Return WRC_Prune on success. +*/ +static int lookupName( + Parse *pParse, /* The parsing context */ + const char *zDb, /* Name of the database containing table, or NULL */ + const char *zTab, /* Name of table containing column, or NULL */ + const char *zCol, /* Name of the column. */ + NameContext *pNC, /* The name context used to resolve the name */ + Expr *pExpr /* Make this EXPR node point to the selected column */ +){ + int i, j; /* Loop counters */ + int cnt = 0; /* Number of matching column names */ + int cntTab = 0; /* Number of matching table names */ + int nSubquery = 0; /* How many levels of subquery */ + sqlite3 *db = pParse->db; /* The database connection */ + struct SrcList_item *pItem; /* Use for looping over pSrcList items */ + struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ + NameContext *pTopNC = pNC; /* First namecontext in the list */ + Schema *pSchema = 0; /* Schema of the expression */ + int isTrigger = 0; /* True if resolved to a trigger column */ + Table *pTab = 0; /* Table hold the row */ + Column *pCol; /* A column of pTab */ + + assert( pNC ); /* the name context cannot be NULL. */ + assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ + assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); + + /* Initialize the node to no-match */ + pExpr->iTable = -1; + pExpr->pTab = 0; + ExprSetVVAProperty(pExpr, EP_NoReduce); + + /* Translate the schema name in zDb into a pointer to the corresponding + ** schema. If not found, pSchema will remain NULL and nothing will match + ** resulting in an appropriate error message toward the end of this routine + */ + if( zDb ){ + testcase( pNC->ncFlags & NC_PartIdx ); + testcase( pNC->ncFlags & NC_IsCheck ); + if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){ + /* Silently ignore database qualifiers inside CHECK constraints and + ** partial indices. Do not raise errors because that might break + ** legacy and because it does not hurt anything to just ignore the + ** database name. */ + zDb = 0; + }else{ + for(i=0; inDb; i++){ + assert( db->aDb[i].zDbSName ); + if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){ + pSchema = db->aDb[i].pSchema; + break; + } + } + } + } + + /* Start at the inner-most context and move outward until a match is found */ + assert( pNC && cnt==0 ); + do{ + ExprList *pEList; + SrcList *pSrcList = pNC->pSrcList; + + if( pSrcList ){ + for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ + pTab = pItem->pTab; + assert( pTab!=0 && pTab->zName!=0 ); + assert( pTab->nCol>0 ); + if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ + int hit = 0; + pEList = pItem->pSelect->pEList; + for(j=0; jnExpr; j++){ + if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){ + cnt++; + cntTab = 2; + pMatch = pItem; + pExpr->iColumn = j; + hit = 1; + } + } + if( hit || zTab==0 ) continue; + } + if( zDb && pTab->pSchema!=pSchema ){ + continue; + } + if( zTab ){ + const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; + assert( zTabName!=0 ); + if( sqlite3StrICmp(zTabName, zTab)!=0 ){ + continue; + } + } + if( 0==(cntTab++) ){ + pMatch = pItem; + } + for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ + if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ + /* If there has been exactly one prior match and this match + ** is for the right-hand table of a NATURAL JOIN or is in a + ** USING clause, then skip this match. + */ + if( cnt==1 ){ + if( pItem->fg.jointype & JT_NATURAL ) continue; + if( nameInUsingClause(pItem->pUsing, zCol) ) continue; + } + cnt++; + pMatch = pItem; + /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ + pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; + break; + } + } + } + if( pMatch ){ + pExpr->iTable = pMatch->iCursor; + pExpr->pTab = pMatch->pTab; + /* RIGHT JOIN not (yet) supported */ + assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); + if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ + ExprSetProperty(pExpr, EP_CanBeNull); + } + pSchema = pExpr->pTab->pSchema; + } + } /* if( pSrcList ) */ + +#ifndef SQLITE_OMIT_TRIGGER + /* If we have not already resolved the name, then maybe + ** it is a new.* or old.* trigger argument reference + */ + if( zDb==0 && zTab!=0 && cntTab==0 && pParse->pTriggerTab!=0 ){ + int op = pParse->eTriggerOp; + assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); + if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){ + pExpr->iTable = 1; + pTab = pParse->pTriggerTab; + }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ + pExpr->iTable = 0; + pTab = pParse->pTriggerTab; + }else{ + pTab = 0; + } + + if( pTab ){ + int iCol; + pSchema = pTab->pSchema; + cntTab++; + for(iCol=0, pCol=pTab->aCol; iColnCol; iCol++, pCol++){ + if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ + if( iCol==pTab->iPKey ){ + iCol = -1; + } + break; + } + } + if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ + /* IMP: R-51414-32910 */ + iCol = -1; + } + if( iColnCol ){ + cnt++; + if( iCol<0 ){ + pExpr->affinity = SQLITE_AFF_INTEGER; + }else if( pExpr->iTable==0 ){ + testcase( iCol==31 ); + testcase( iCol==32 ); + pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<iColumn = (i16)iCol; + pExpr->pTab = pTab; + isTrigger = 1; + } + } + } +#endif /* !defined(SQLITE_OMIT_TRIGGER) */ + + /* + ** Perhaps the name is a reference to the ROWID + */ + if( cnt==0 + && cntTab==1 + && pMatch + && (pNC->ncFlags & NC_IdxExpr)==0 + && sqlite3IsRowid(zCol) + && VisibleRowid(pMatch->pTab) + ){ + cnt = 1; + pExpr->iColumn = -1; + pExpr->affinity = SQLITE_AFF_INTEGER; + } + + /* + ** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z + ** might refer to an result-set alias. This happens, for example, when + ** we are resolving names in the WHERE clause of the following command: + ** + ** SELECT a+b AS x FROM table WHERE x<10; + ** + ** In cases like this, replace pExpr with a copy of the expression that + ** forms the result set entry ("a+b" in the example) and return immediately. + ** Note that the expression in the result set should have already been + ** resolved by the time the WHERE clause is resolved. + ** + ** The ability to use an output result-set column in the WHERE, GROUP BY, + ** or HAVING clauses, or as part of a larger expression in the ORDER BY + ** clause is not standard SQL. This is a (goofy) SQLite extension, that + ** is supported for backwards compatibility only. Hence, we issue a warning + ** on sqlite3_log() whenever the capability is used. + */ + if( (pEList = pNC->pEList)!=0 + && zTab==0 + && cnt==0 + ){ + for(j=0; jnExpr; j++){ + char *zAs = pEList->a[j].zName; + if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ + Expr *pOrig; + assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + assert( pExpr->x.pList==0 ); + assert( pExpr->x.pSelect==0 ); + pOrig = pEList->a[j].pExpr; + if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){ + sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); + return WRC_Abort; + } + if( sqlite3ExprVectorSize(pOrig)!=1 ){ + sqlite3ErrorMsg(pParse, "row value misused"); + return WRC_Abort; + } + resolveAlias(pParse, pEList, j, pExpr, "", nSubquery); + cnt = 1; + pMatch = 0; + assert( zTab==0 && zDb==0 ); + goto lookupname_end; + } + } + } + + /* Advance to the next name context. The loop will exit when either + ** we have a match (cnt>0) or when we run out of name contexts. + */ + if( cnt ) break; + pNC = pNC->pNext; + nSubquery++; + }while( pNC ); + + + /* + ** If X and Y are NULL (in other words if only the column name Z is + ** supplied) and the value of Z is enclosed in double-quotes, then + ** Z is a string literal if it doesn't match any column names. In that + ** case, we need to return right away and not make any changes to + ** pExpr. + ** + ** Because no reference was made to outer contexts, the pNC->nRef + ** fields are not changed in any context. + */ + if( cnt==0 && zTab==0 && ExprHasProperty(pExpr,EP_DblQuoted) ){ + pExpr->op = TK_STRING; + pExpr->pTab = 0; + return WRC_Prune; + } + + /* + ** cnt==0 means there was not match. cnt>1 means there were two or + ** more matches. Either way, we have an error. + */ + if( cnt!=1 ){ + const char *zErr; + zErr = cnt==0 ? "no such column" : "ambiguous column name"; + if( zDb ){ + sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol); + }else if( zTab ){ + sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol); + }else{ + sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); + } + pParse->checkSchema = 1; + pTopNC->nErr++; + } + + /* If a column from a table in pSrcList is referenced, then record + ** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes + ** bit 0 to be set. Column 1 sets bit 1. And so forth. If the + ** column number is greater than the number of bits in the bitmask + ** then set the high-order bit of the bitmask. + */ + if( pExpr->iColumn>=0 && pMatch!=0 ){ + int n = pExpr->iColumn; + testcase( n==BMS-1 ); + if( n>=BMS ){ + n = BMS-1; + } + assert( pMatch->iCursor==pExpr->iTable ); + pMatch->colUsed |= ((Bitmask)1)<pLeft); + pExpr->pLeft = 0; + sqlite3ExprDelete(db, pExpr->pRight); + pExpr->pRight = 0; + pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); +lookupname_end: + if( cnt==1 ){ + assert( pNC!=0 ); + if( !ExprHasProperty(pExpr, EP_Alias) ){ + sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); + } + /* Increment the nRef value on all name contexts from TopNC up to + ** the point where the name matched. */ + for(;;){ + assert( pTopNC!=0 ); + pTopNC->nRef++; + if( pTopNC==pNC ) break; + pTopNC = pTopNC->pNext; + } + return WRC_Prune; + } else { + return WRC_Abort; + } +} + +/* +** Allocate and return a pointer to an expression to load the column iCol +** from datasource iSrc in SrcList pSrc. +*/ +SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ + Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); + if( p ){ + struct SrcList_item *pItem = &pSrc->a[iSrc]; + p->pTab = pItem->pTab; + p->iTable = pItem->iCursor; + if( p->pTab->iPKey==iCol ){ + p->iColumn = -1; + }else{ + p->iColumn = (ynVar)iCol; + testcase( iCol==BMS ); + testcase( iCol==BMS-1 ); + pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); + } + ExprSetProperty(p, EP_Resolved); + } + return p; +} + +/* +** Report an error that an expression is not valid for some set of +** pNC->ncFlags values determined by validMask. +*/ +static void notValid( + Parse *pParse, /* Leave error message here */ + NameContext *pNC, /* The name context */ + const char *zMsg, /* Type of error */ + int validMask /* Set of contexts for which prohibited */ +){ + assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 ); + if( (pNC->ncFlags & validMask)!=0 ){ + const char *zIn = "partial index WHERE clauses"; + if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; +#ifndef SQLITE_OMIT_CHECK + else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; +#endif + sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); + } +} + +/* +** Expression p should encode a floating point value between 1.0 and 0.0. +** Return 1024 times this value. Or return -1 if p is not a floating point +** value between 1.0 and 0.0. +*/ +static int exprProbability(Expr *p){ + double r = -1.0; + if( p->op!=TK_FLOAT ) return -1; + sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); + assert( r>=0.0 ); + if( r>1.0 ) return -1; + return (int)(r*134217728.0); +} + +/* +** This routine is callback for sqlite3WalkExpr(). +** +** Resolve symbolic names into TK_COLUMN operators for the current +** node in the expression tree. Return 0 to continue the search down +** the tree or 2 to abort the tree walk. +** +** This routine also does error checking and name resolution for +** function names. The operator for aggregate functions is changed +** to TK_AGG_FUNCTION. +*/ +static int resolveExprStep(Walker *pWalker, Expr *pExpr){ + NameContext *pNC; + Parse *pParse; + + pNC = pWalker->u.pNC; + assert( pNC!=0 ); + pParse = pNC->pParse; + assert( pParse==pWalker->pParse ); + + if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune; + ExprSetProperty(pExpr, EP_Resolved); +#ifndef NDEBUG + if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ + SrcList *pSrcList = pNC->pSrcList; + int i; + for(i=0; ipSrcList->nSrc; i++){ + assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursornTab); + } + } +#endif + switch( pExpr->op ){ + +#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) + /* The special operator TK_ROW means use the rowid for the first + ** column in the FROM clause. This is used by the LIMIT and ORDER BY + ** clause processing on UPDATE and DELETE statements. + */ + case TK_ROW: { + SrcList *pSrcList = pNC->pSrcList; + struct SrcList_item *pItem; + assert( pSrcList && pSrcList->nSrc==1 ); + pItem = pSrcList->a; + pExpr->op = TK_COLUMN; + pExpr->pTab = pItem->pTab; + pExpr->iTable = pItem->iCursor; + pExpr->iColumn = -1; + pExpr->affinity = SQLITE_AFF_INTEGER; + break; + } +#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) + && !defined(SQLITE_OMIT_SUBQUERY) */ + + /* A column name: ID + ** Or table name and column name: ID.ID + ** Or a database, table and column: ID.ID.ID + ** + ** The TK_ID and TK_OUT cases are combined so that there will only + ** be one call to lookupName(). Then the compiler will in-line + ** lookupName() for a size reduction and performance increase. + */ + case TK_ID: + case TK_DOT: { + const char *zColumn; + const char *zTable; + const char *zDb; + Expr *pRight; + + if( pExpr->op==TK_ID ){ + zDb = 0; + zTable = 0; + zColumn = pExpr->u.zToken; + }else{ + notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); + pRight = pExpr->pRight; + if( pRight->op==TK_ID ){ + zDb = 0; + zTable = pExpr->pLeft->u.zToken; + zColumn = pRight->u.zToken; + }else{ + assert( pRight->op==TK_DOT ); + zDb = pExpr->pLeft->u.zToken; + zTable = pRight->pLeft->u.zToken; + zColumn = pRight->pRight->u.zToken; + } + } + return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); + } + + /* Resolve function names + */ + case TK_FUNCTION: { + ExprList *pList = pExpr->x.pList; /* The argument list */ + int n = pList ? pList->nExpr : 0; /* Number of arguments */ + int no_such_func = 0; /* True if no such function exists */ + int wrong_num_args = 0; /* True if wrong number of arguments */ + int is_agg = 0; /* True if is an aggregate function */ + int nId; /* Number of characters in function name */ + const char *zId; /* The function name. */ + FuncDef *pDef; /* Information about the function */ + u8 enc = ENC(pParse->db); /* The database encoding */ + + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + zId = pExpr->u.zToken; + nId = sqlite3Strlen30(zId); + pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); + if( pDef==0 ){ + pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0); + if( pDef==0 ){ + no_such_func = 1; + }else{ + wrong_num_args = 1; + } + }else{ + is_agg = pDef->xFinalize!=0; + if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ + ExprSetProperty(pExpr, EP_Unlikely|EP_Skip); + if( n==2 ){ + pExpr->iTable = exprProbability(pList->a[1].pExpr); + if( pExpr->iTable<0 ){ + sqlite3ErrorMsg(pParse, + "second argument to likelihood() must be a " + "constant between 0.0 and 1.0"); + pNC->nErr++; + } + }else{ + /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is + ** equivalent to likelihood(X, 0.0625). + ** EVIDENCE-OF: R-01283-11636 The unlikely(X) function is + ** short-hand for likelihood(X,0.0625). + ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand + ** for likelihood(X,0.9375). + ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent + ** to likelihood(X,0.9375). */ + /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ + pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120; + } + } +#ifndef SQLITE_OMIT_AUTHORIZATION + { + int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0); + if( auth!=SQLITE_OK ){ + if( auth==SQLITE_DENY ){ + sqlite3ErrorMsg(pParse, "not authorized to use function: %s", + pDef->zName); + pNC->nErr++; + } + pExpr->op = TK_NULL; + return WRC_Prune; + } + } +#endif + if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ + /* For the purposes of the EP_ConstFunc flag, date and time + ** functions and other functions that change slowly are considered + ** constant because they are constant for the duration of one query */ + ExprSetProperty(pExpr,EP_ConstFunc); + } + if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ + /* Date/time functions that use 'now', and other functions like + ** sqlite_version() that might change over time cannot be used + ** in an index. */ + notValid(pParse, pNC, "non-deterministic functions", + NC_IdxExpr|NC_PartIdx); + } + } + if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ + sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); + pNC->nErr++; + is_agg = 0; + }else if( no_such_func && pParse->db->init.busy==0 +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + && pParse->explain==0 +#endif + ){ + sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); + pNC->nErr++; + }else if( wrong_num_args ){ + sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", + nId, zId); + pNC->nErr++; + } + if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg; + sqlite3WalkExprList(pWalker, pList); + if( is_agg ){ + NameContext *pNC2 = pNC; + pExpr->op = TK_AGG_FUNCTION; + pExpr->op2 = 0; + while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ + pExpr->op2++; + pNC2 = pNC2->pNext; + } + assert( pDef!=0 ); + if( pNC2 ){ + assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); + testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); + pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); + + } + pNC->ncFlags |= NC_AllowAgg; + } + /* FIX ME: Compute pExpr->affinity based on the expected return + ** type of the function + */ + return WRC_Prune; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_SELECT: + case TK_EXISTS: testcase( pExpr->op==TK_EXISTS ); +#endif + case TK_IN: { + testcase( pExpr->op==TK_IN ); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + int nRef = pNC->nRef; + notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); + sqlite3WalkSelect(pWalker, pExpr->x.pSelect); + assert( pNC->nRef>=nRef ); + if( nRef!=pNC->nRef ){ + ExprSetProperty(pExpr, EP_VarSelect); + pNC->ncFlags |= NC_VarSelect; + } + } + break; + } + case TK_VARIABLE: { + notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); + break; + } + case TK_BETWEEN: + case TK_EQ: + case TK_NE: + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_IS: + case TK_ISNOT: { + int nLeft, nRight; + if( pParse->db->mallocFailed ) break; + assert( pExpr->pLeft!=0 ); + nLeft = sqlite3ExprVectorSize(pExpr->pLeft); + if( pExpr->op==TK_BETWEEN ){ + nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); + if( nRight==nLeft ){ + nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr); + } + }else{ + assert( pExpr->pRight!=0 ); + nRight = sqlite3ExprVectorSize(pExpr->pRight); + } + if( nLeft!=nRight ){ + testcase( pExpr->op==TK_EQ ); + testcase( pExpr->op==TK_NE ); + testcase( pExpr->op==TK_LT ); + testcase( pExpr->op==TK_LE ); + testcase( pExpr->op==TK_GT ); + testcase( pExpr->op==TK_GE ); + testcase( pExpr->op==TK_IS ); + testcase( pExpr->op==TK_ISNOT ); + testcase( pExpr->op==TK_BETWEEN ); + sqlite3ErrorMsg(pParse, "row value misused"); + } + break; + } + } + return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; +} + +/* +** pEList is a list of expressions which are really the result set of the +** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause. +** This routine checks to see if pE is a simple identifier which corresponds +** to the AS-name of one of the terms of the expression list. If it is, +** this routine return an integer between 1 and N where N is the number of +** elements in pEList, corresponding to the matching entry. If there is +** no match, or if pE is not a simple identifier, then this routine +** return 0. +** +** pEList has been resolved. pE has not. +*/ +static int resolveAsName( + Parse *pParse, /* Parsing context for error messages */ + ExprList *pEList, /* List of expressions to scan */ + Expr *pE /* Expression we are trying to match */ +){ + int i; /* Loop counter */ + + UNUSED_PARAMETER(pParse); + + if( pE->op==TK_ID ){ + char *zCol = pE->u.zToken; + for(i=0; inExpr; i++){ + char *zAs = pEList->a[i].zName; + if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ + return i+1; + } + } + } + return 0; +} + +/* +** pE is a pointer to an expression which is a single term in the +** ORDER BY of a compound SELECT. The expression has not been +** name resolved. +** +** At the point this routine is called, we already know that the +** ORDER BY term is not an integer index into the result set. That +** case is handled by the calling routine. +** +** Attempt to match pE against result set columns in the left-most +** SELECT statement. Return the index i of the matching column, +** as an indication to the caller that it should sort by the i-th column. +** The left-most column is 1. In other words, the value returned is the +** same integer value that would be used in the SQL statement to indicate +** the column. +** +** If there is no match, return 0. Return -1 if an error occurs. +*/ +static int resolveOrderByTermToExprList( + Parse *pParse, /* Parsing context for error messages */ + Select *pSelect, /* The SELECT statement with the ORDER BY clause */ + Expr *pE /* The specific ORDER BY term */ +){ + int i; /* Loop counter */ + ExprList *pEList; /* The columns of the result set */ + NameContext nc; /* Name context for resolving pE */ + sqlite3 *db; /* Database connection */ + int rc; /* Return code from subprocedures */ + u8 savedSuppErr; /* Saved value of db->suppressErr */ + + assert( sqlite3ExprIsInteger(pE, &i)==0 ); + pEList = pSelect->pEList; + + /* Resolve all names in the ORDER BY term expression + */ + memset(&nc, 0, sizeof(nc)); + nc.pParse = pParse; + nc.pSrcList = pSelect->pSrc; + nc.pEList = pEList; + nc.ncFlags = NC_AllowAgg; + nc.nErr = 0; + db = pParse->db; + savedSuppErr = db->suppressErr; + db->suppressErr = 1; + rc = sqlite3ResolveExprNames(&nc, pE); + db->suppressErr = savedSuppErr; + if( rc ) return 0; + + /* Try to match the ORDER BY expression against an expression + ** in the result set. Return an 1-based index of the matching + ** result-set entry. + */ + for(i=0; inExpr; i++){ + if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){ + return i+1; + } + } + + /* If no match, return 0. */ + return 0; +} + +/* +** Generate an ORDER BY or GROUP BY term out-of-range error. +*/ +static void resolveOutOfRangeError( + Parse *pParse, /* The error context into which to write the error */ + const char *zType, /* "ORDER" or "GROUP" */ + int i, /* The index (1-based) of the term out of range */ + int mx /* Largest permissible value of i */ +){ + sqlite3ErrorMsg(pParse, + "%r %s BY term out of range - should be " + "between 1 and %d", i, zType, mx); +} + +/* +** Analyze the ORDER BY clause in a compound SELECT statement. Modify +** each term of the ORDER BY clause is a constant integer between 1 +** and N where N is the number of columns in the compound SELECT. +** +** ORDER BY terms that are already an integer between 1 and N are +** unmodified. ORDER BY terms that are integers outside the range of +** 1 through N generate an error. ORDER BY terms that are expressions +** are matched against result set expressions of compound SELECT +** beginning with the left-most SELECT and working toward the right. +** At the first match, the ORDER BY expression is transformed into +** the integer column number. +** +** Return the number of errors seen. +*/ +static int resolveCompoundOrderBy( + Parse *pParse, /* Parsing context. Leave error messages here */ + Select *pSelect /* The SELECT statement containing the ORDER BY */ +){ + int i; + ExprList *pOrderBy; + ExprList *pEList; + sqlite3 *db; + int moreToDo = 1; + + 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; inExpr; i++){ + pOrderBy->a[i].done = 0; + } + pSelect->pNext = 0; + while( pSelect->pPrior ){ + pSelect->pPrior->pNext = pSelect; + pSelect = pSelect->pPrior; + } + while( pSelect && moreToDo ){ + struct ExprList_item *pItem; + moreToDo = 0; + pEList = pSelect->pEList; + assert( pEList!=0 ); + for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ + int iCol = -1; + Expr *pE, *pDup; + if( pItem->done ) continue; + pE = sqlite3ExprSkipCollate(pItem->pExpr); + if( sqlite3ExprIsInteger(pE, &iCol) ){ + if( iCol<=0 || iCol>pEList->nExpr ){ + resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr); + return 1; + } + }else{ + iCol = resolveAsName(pParse, pEList, pE); + if( iCol==0 ){ + pDup = sqlite3ExprDup(db, pE, 0); + if( !db->mallocFailed ){ + assert(pDup); + iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup); + } + sqlite3ExprDelete(db, pDup); + } + } + if( iCol>0 ){ + /* Convert the ORDER BY term into an integer column number iCol, + ** taking care to preserve the COLLATE clause if it exists */ + Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + if( pNew==0 ) return 1; + pNew->flags |= EP_IntValue; + pNew->u.iValue = iCol; + if( pItem->pExpr==pE ){ + pItem->pExpr = pNew; + }else{ + Expr *pParent = pItem->pExpr; + assert( pParent->op==TK_COLLATE ); + while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; + assert( pParent->pLeft==pE ); + pParent->pLeft = pNew; + } + sqlite3ExprDelete(db, pE); + pItem->u.x.iOrderByCol = (u16)iCol; + pItem->done = 1; + }else{ + moreToDo = 1; + } + } + pSelect = pSelect->pNext; + } + for(i=0; inExpr; i++){ + if( pOrderBy->a[i].done==0 ){ + sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any " + "column in the result set", i+1); + return 1; + } + } + return 0; +} + +/* +** Check every term in the ORDER BY or GROUP BY clause pOrderBy of +** the SELECT statement pSelect. If any term is reference to a +** result set expression (as determined by the ExprList.a.u.x.iOrderByCol +** field) then convert that term into a copy of the corresponding result set +** column. +** +** If any errors are detected, add an error message to pParse and +** return non-zero. Return zero if no errors are seen. +*/ +SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy( + Parse *pParse, /* Parsing context. Leave error messages here */ + Select *pSelect, /* The SELECT statement containing the clause */ + ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */ + const char *zType /* "ORDER" or "GROUP" */ +){ + int i; + sqlite3 *db = pParse->db; + ExprList *pEList; + 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; inExpr; i++, pItem++){ + if( pItem->u.x.iOrderByCol ){ + if( pItem->u.x.iOrderByCol>pEList->nExpr ){ + resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr); + return 1; + } + resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, + zType,0); + } + } + return 0; +} + +/* +** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect. +** The Name context of the SELECT statement is pNC. zType is either +** "ORDER" or "GROUP" depending on which type of clause pOrderBy is. +** +** This routine resolves each term of the clause into an expression. +** If the order-by term is an integer I between 1 and N (where N is the +** number of columns in the result set of the SELECT) then the expression +** in the resolution is a copy of the I-th result-set expression. If +** the order-by term is an identifier that corresponds to the AS-name of +** a result-set expression, then the term resolves to a copy of the +** result-set expression. Otherwise, the expression is resolved in +** the usual way - using sqlite3ResolveExprNames(). +** +** This routine returns the number of errors. If errors occur, then +** an appropriate error message might be left in pParse. (OOM errors +** excepted.) +*/ +static int resolveOrderGroupBy( + NameContext *pNC, /* The name context of the SELECT statement */ + Select *pSelect, /* The SELECT statement holding pOrderBy */ + ExprList *pOrderBy, /* An ORDER BY or GROUP BY clause to resolve */ + const char *zType /* Either "ORDER" or "GROUP", as appropriate */ +){ + int i, j; /* Loop counters */ + int iCol; /* Column number */ + struct ExprList_item *pItem; /* A term of the ORDER BY clause */ + Parse *pParse; /* Parsing context */ + int nResult; /* Number of terms in the result set */ + + if( pOrderBy==0 ) return 0; + nResult = pSelect->pEList->nExpr; + pParse = pNC->pParse; + for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ + Expr *pE = pItem->pExpr; + Expr *pE2 = sqlite3ExprSkipCollate(pE); + if( zType[0]!='G' ){ + iCol = resolveAsName(pParse, pSelect->pEList, pE2); + if( iCol>0 ){ + /* If an AS-name match is found, mark this ORDER BY column as being + ** a copy of the iCol-th result-set column. The subsequent call to + ** sqlite3ResolveOrderGroupBy() will convert the expression to a + ** copy of the iCol-th result-set expression. */ + pItem->u.x.iOrderByCol = (u16)iCol; + continue; + } + } + if( sqlite3ExprIsInteger(pE2, &iCol) ){ + /* The ORDER BY term is an integer constant. Again, set the column + ** number so that sqlite3ResolveOrderGroupBy() will convert the + ** order-by term to a copy of the result-set expression */ + if( iCol<1 || iCol>0xffff ){ + resolveOutOfRangeError(pParse, zType, i+1, nResult); + return 1; + } + pItem->u.x.iOrderByCol = (u16)iCol; + continue; + } + + /* Otherwise, treat the ORDER BY term as an ordinary expression */ + pItem->u.x.iOrderByCol = 0; + if( sqlite3ResolveExprNames(pNC, pE) ){ + return 1; + } + for(j=0; jpEList->nExpr; j++){ + if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ + pItem->u.x.iOrderByCol = j+1; + } + } + } + return sqlite3ResolveOrderGroupBy(pParse, pSelect, pOrderBy, zType); +} + +/* +** Resolve names in the SELECT statement p and all of its descendants. +*/ +static int resolveSelectStep(Walker *pWalker, Select *p){ + NameContext *pOuterNC; /* Context that contains this SELECT */ + NameContext sNC; /* Name context of this SELECT */ + int isCompound; /* True if p is a compound select */ + int nCompound; /* Number of compound terms processed so far */ + Parse *pParse; /* Parsing context */ + int i; /* Loop counter */ + ExprList *pGroupBy; /* The GROUP BY clause */ + Select *pLeftmost; /* Left-most of SELECT of a compound */ + sqlite3 *db; /* Database connection */ + + + assert( p!=0 ); + if( p->selFlags & SF_Resolved ){ + return WRC_Prune; + } + pOuterNC = pWalker->u.pNC; + pParse = pWalker->pParse; + db = pParse->db; + + /* Normally sqlite3SelectExpand() will be called first and will have + ** already expanded this SELECT. However, if this is a subquery within + ** an expression, sqlite3ResolveExprNames() will be called without a + ** prior call to sqlite3SelectExpand(). When that happens, let + ** sqlite3SelectPrep() do all of the processing for this SELECT. + ** sqlite3SelectPrep() will invoke both sqlite3SelectExpand() and + ** this routine in the correct order. + */ + if( (p->selFlags & SF_Expanded)==0 ){ + sqlite3SelectPrep(pParse, p, pOuterNC); + return (pParse->nErr || db->mallocFailed) ? WRC_Abort : WRC_Prune; + } + + isCompound = p->pPrior!=0; + nCompound = 0; + pLeftmost = p; + while( p ){ + assert( (p->selFlags & SF_Expanded)!=0 ); + assert( (p->selFlags & SF_Resolved)==0 ); + p->selFlags |= SF_Resolved; + + /* Resolve the expressions in the LIMIT and OFFSET clauses. These + ** are not allowed to refer to any names, so pass an empty NameContext. + */ + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + if( sqlite3ResolveExprNames(&sNC, p->pLimit) || + sqlite3ResolveExprNames(&sNC, p->pOffset) ){ + return WRC_Abort; + } + + /* If the SF_Converted flags is set, then this Select object was + ** was created by the convertCompoundSelectToSubquery() function. + ** In this case the ORDER BY clause (p->pOrderBy) should be resolved + ** as if it were part of the sub-query, not the parent. This block + ** moves the pOrderBy down to the sub-query. It will be moved back + ** after the names have been resolved. */ + if( p->selFlags & SF_Converted ){ + Select *pSub = p->pSrc->a[0].pSelect; + assert( p->pSrc->nSrc==1 && p->pOrderBy ); + assert( pSub->pPrior && pSub->pOrderBy==0 ); + pSub->pOrderBy = p->pOrderBy; + p->pOrderBy = 0; + } + + /* Recursively resolve names in all subqueries + */ + for(i=0; ipSrc->nSrc; i++){ + struct SrcList_item *pItem = &p->pSrc->a[i]; + if( pItem->pSelect ){ + NameContext *pNC; /* Used to iterate name contexts */ + int nRef = 0; /* Refcount for pOuterNC and outer contexts */ + const char *zSavedContext = pParse->zAuthContext; + + /* Count the total number of references to pOuterNC and all of its + ** parent contexts. After resolving references to expressions in + ** pItem->pSelect, check if this value has changed. If so, then + ** SELECT statement pItem->pSelect must be correlated. Set the + ** pItem->fg.isCorrelated flag if this is the case. */ + for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef; + + if( pItem->zName ) pParse->zAuthContext = pItem->zName; + sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); + pParse->zAuthContext = zSavedContext; + if( pParse->nErr || db->mallocFailed ) return WRC_Abort; + + for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef; + assert( pItem->fg.isCorrelated==0 && nRef<=0 ); + pItem->fg.isCorrelated = (nRef!=0); + } + } + + /* Set up the local name-context to pass to sqlite3ResolveExprNames() to + ** resolve the result-set expression list. + */ + sNC.ncFlags = NC_AllowAgg; + sNC.pSrcList = p->pSrc; + sNC.pNext = pOuterNC; + + /* Resolve names in the result set. */ + if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort; + + /* If there are no aggregate functions in the result-set, and no GROUP BY + ** expression, do not allow aggregates in any of the other expressions. + */ + assert( (p->selFlags & SF_Aggregate)==0 ); + pGroupBy = p->pGroupBy; + if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ + assert( NC_MinMaxAgg==SF_MinMaxAgg ); + p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg); + }else{ + sNC.ncFlags &= ~NC_AllowAgg; + } + + /* If a HAVING clause is present, then there must be a GROUP BY clause. + */ + if( p->pHaving && !pGroupBy ){ + sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); + return WRC_Abort; + } + + /* Add the output column list to the name-context before parsing the + ** other expressions in the SELECT statement. This is so that + ** expressions in the WHERE clause (etc.) can refer to expressions by + ** aliases in the result set. + ** + ** Minor point: If this is the case, then the expression will be + ** re-evaluated for each reference to it. + */ + sNC.pEList = p->pEList; + if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; + if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; + + /* Resolve names in table-valued-function arguments */ + for(i=0; ipSrc->nSrc; i++){ + struct SrcList_item *pItem = &p->pSrc->a[i]; + if( pItem->fg.isTabFunc + && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) + ){ + return WRC_Abort; + } + } + + /* The ORDER BY and GROUP BY clauses may not refer to terms in + ** outer queries + */ + sNC.pNext = 0; + sNC.ncFlags |= NC_AllowAgg; + + /* If this is a converted compound query, move the ORDER BY clause from + ** the sub-query back to the parent query. At this point each term + ** within the ORDER BY clause has been transformed to an integer value. + ** These integers will be replaced by copies of the corresponding result + ** set expressions by the call to resolveOrderGroupBy() below. */ + if( p->selFlags & SF_Converted ){ + Select *pSub = p->pSrc->a[0].pSelect; + p->pOrderBy = pSub->pOrderBy; + pSub->pOrderBy = 0; + } + + /* Process the ORDER BY clause for singleton SELECT statements. + ** The ORDER BY clause for compounds SELECT statements is handled + ** below, after all of the result-sets for all of the elements of + ** the compound have been resolved. + ** + ** If there is an ORDER BY clause on a term of a compound-select other + ** than the right-most term, then that is a syntax error. But the error + ** is not detected until much later, and so we need to go ahead and + ** resolve those symbols on the incorrect ORDER BY for consistency. + */ + if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ + && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") + ){ + return WRC_Abort; + } + if( db->mallocFailed ){ + return WRC_Abort; + } + + /* Resolve the GROUP BY clause. At the same time, make sure + ** the GROUP BY clause does not contain aggregate functions. + */ + if( pGroupBy ){ + struct ExprList_item *pItem; + + if( resolveOrderGroupBy(&sNC, p, pGroupBy, "GROUP") || db->mallocFailed ){ + return WRC_Abort; + } + for(i=0, pItem=pGroupBy->a; inExpr; i++, pItem++){ + if( ExprHasProperty(pItem->pExpr, EP_Agg) ){ + sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in " + "the GROUP BY clause"); + return WRC_Abort; + } + } + } + + /* If this is part of a compound SELECT, check that it has the right + ** number of expressions in the select list. */ + if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){ + sqlite3SelectWrongNumTermsError(pParse, p->pNext); + return WRC_Abort; + } + + /* Advance to the next term of the compound + */ + p = p->pPrior; + nCompound++; + } + + /* Resolve the ORDER BY on a compound SELECT after all terms of + ** the compound have been resolved. + */ + if( isCompound && resolveCompoundOrderBy(pParse, pLeftmost) ){ + return WRC_Abort; + } + + return WRC_Prune; +} + +/* +** This routine walks an expression tree and resolves references to +** table columns and result-set columns. At the same time, do error +** checking on function usage and set a flag if any aggregate functions +** are seen. +** +** To resolve table columns references we look for nodes (or subtrees) of the +** form X.Y.Z or Y.Z or just Z where +** +** X: The name of a database. Ex: "main" or "temp" or +** the symbolic name assigned to an ATTACH-ed database. +** +** Y: The name of a table in a FROM clause. Or in a trigger +** one of the special names "old" or "new". +** +** Z: The name of a column in table Y. +** +** The node at the root of the subtree is modified as follows: +** +** Expr.op Changed to TK_COLUMN +** Expr.pTab Points to the Table object for X.Y +** Expr.iColumn The column index in X.Y. -1 for the rowid. +** Expr.iTable The VDBE cursor number for X.Y +** +** +** To resolve result-set references, look for expression nodes of the +** form Z (with no X and Y prefix) where the Z matches the right-hand +** size of an AS clause in the result-set of a SELECT. The Z expression +** is replaced by a copy of the left-hand side of the result-set expression. +** Table-name and function resolution occurs on the substituted expression +** tree. For example, in: +** +** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY x; +** +** The "x" term of the order by is replaced by "a+b" to render: +** +** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY a+b; +** +** Function calls are checked to make sure that the function is +** defined and that the correct number of arguments are specified. +** If the function is an aggregate function, then the NC_HasAgg flag is +** set and the opcode is changed from TK_FUNCTION to TK_AGG_FUNCTION. +** If an expression contains aggregate functions then the EP_Agg +** property on the expression is set. +** +** An error message is left in pParse if anything is amiss. The number +** if errors is returned. +*/ +SQLITE_PRIVATE int sqlite3ResolveExprNames( + NameContext *pNC, /* Namespace to resolve expressions in. */ + Expr *pExpr /* The expression to be analyzed. */ +){ + u16 savedHasAgg; + Walker w; + + if( pExpr==0 ) return 0; +#if SQLITE_MAX_EXPR_DEPTH>0 + { + Parse *pParse = pNC->pParse; + if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){ + return 1; + } + pParse->nHeight += pExpr->nHeight; + } +#endif + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); + w.pParse = pNC->pParse; + w.xExprCallback = resolveExprStep; + w.xSelectCallback = resolveSelectStep; + w.xSelectCallback2 = 0; + w.walkerDepth = 0; + w.eCode = 0; + w.u.pNC = pNC; + sqlite3WalkExpr(&w, pExpr); +#if SQLITE_MAX_EXPR_DEPTH>0 + pNC->pParse->nHeight -= pExpr->nHeight; +#endif + if( pNC->nErr>0 || w.pParse->nErr>0 ){ + ExprSetProperty(pExpr, EP_Error); + } + if( pNC->ncFlags & NC_HasAgg ){ + ExprSetProperty(pExpr, EP_Agg); + } + pNC->ncFlags |= savedHasAgg; + return ExprHasProperty(pExpr, EP_Error); +} + +/* +** Resolve all names for all expression in an expression list. This is +** just like sqlite3ResolveExprNames() except that it works for an expression +** list rather than a single expression. +*/ +SQLITE_PRIVATE int sqlite3ResolveExprListNames( + NameContext *pNC, /* Namespace to resolve expressions in. */ + ExprList *pList /* The expression list to be analyzed. */ +){ + int i; + if( pList ){ + for(i=0; inExpr; i++){ + if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort; + } + } + return WRC_Continue; +} + +/* +** Resolve all names in all expressions of a SELECT and in all +** decendents of the SELECT, including compounds off of p->pPrior, +** subqueries in expressions, and subqueries used as FROM clause +** terms. +** +** See sqlite3ResolveExprNames() for a description of the kinds of +** transformations that occur. +** +** All SELECT statements should have been expanded using +** sqlite3SelectExpand() prior to invoking this routine. +*/ +SQLITE_PRIVATE void sqlite3ResolveSelectNames( + Parse *pParse, /* The parser context */ + Select *p, /* The SELECT statement being coded. */ + NameContext *pOuterNC /* Name context for parent SELECT statement */ +){ + Walker w; + + assert( p!=0 ); + memset(&w, 0, sizeof(w)); + w.xExprCallback = resolveExprStep; + w.xSelectCallback = resolveSelectStep; + w.pParse = pParse; + w.u.pNC = pOuterNC; + sqlite3WalkSelect(&w, p); +} + +/* +** Resolve names in expressions that can only reference a single table: +** +** * CHECK constraints +** * WHERE clauses on partial indices +** +** The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression +** is set to -1 and the Expr.iColumn value is set to the column number. +** +** Any errors cause an error message to be set in pParse. +*/ +SQLITE_PRIVATE void sqlite3ResolveSelfReference( + Parse *pParse, /* Parsing context */ + Table *pTab, /* The table being referenced */ + int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */ + Expr *pExpr, /* Expression to resolve. May be NULL. */ + ExprList *pList /* Expression list to resolve. May be NUL. */ +){ + SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ + NameContext sNC; /* Name context for pParse->pNewTable */ + + assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr ); + memset(&sNC, 0, sizeof(sNC)); + memset(&sSrc, 0, sizeof(sSrc)); + sSrc.nSrc = 1; + sSrc.a[0].zName = pTab->zName; + sSrc.a[0].pTab = pTab; + sSrc.a[0].iCursor = -1; + sNC.pParse = pParse; + sNC.pSrcList = &sSrc; + sNC.ncFlags = type; + if( sqlite3ResolveExprNames(&sNC, pExpr) ) return; + if( pList ) sqlite3ResolveExprListNames(&sNC, pList); +} + +/************** End of resolve.c *********************************************/ +/************** Begin file expr.c ********************************************/ +/* +** 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 routines used for analyzing expressions and +** for generating VDBE code that evaluates expressions in SQLite. +*/ +/* #include "sqliteInt.h" */ + +/* Forward declarations */ +static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int); +static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree); + +/* +** Return the affinity character for a single column of a table. +*/ +SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){ + assert( iColnCol ); + return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER; +} + +/* +** Return the 'affinity' of the expression pExpr if any. +** +** If pExpr is a column, a reference to a column via an 'AS' alias, +** or a sub-select with a column as the return value, then the +** affinity of that column is returned. Otherwise, 0x00 is returned, +** indicating no affinity for the expression. +** +** i.e. the WHERE clause expressions in the following statements all +** have an affinity: +** +** CREATE TABLE t1(a); +** SELECT * FROM t1 WHERE a; +** SELECT a AS b FROM t1 WHERE b; +** SELECT * FROM t1 WHERE (select a from t1); +*/ +SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ + int op; + pExpr = sqlite3ExprSkipCollate(pExpr); + if( pExpr->flags & EP_Generic ) return 0; + op = pExpr->op; + if( op==TK_SELECT ){ + assert( pExpr->flags&EP_xIsSelect ); + return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); + } + if( op==TK_REGISTER ) op = pExpr->op2; +#ifndef SQLITE_OMIT_CAST + if( op==TK_CAST ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + return sqlite3AffinityType(pExpr->u.zToken, 0); + } +#endif + if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){ + return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn); + } + if( op==TK_SELECT_COLUMN ){ + assert( pExpr->pLeft->flags&EP_xIsSelect ); + return sqlite3ExprAffinity( + pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr + ); + } + return pExpr->affinity; +} + +/* +** Set the collating sequence for expression pExpr to be the collating +** sequence named by pToken. Return a pointer to a new Expr node that +** implements the COLLATE operator. +** +** If a memory allocation error occurs, that fact is recorded in pParse->db +** and the pExpr parameter is returned unchanged. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* Add the "COLLATE" clause to this expression */ + const Token *pCollName, /* Name of collating sequence */ + int dequote /* True to dequote pCollName */ +){ + if( pCollName->n>0 ){ + Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); + if( pNew ){ + pNew->pLeft = pExpr; + pNew->flags |= EP_Collate|EP_Skip; + pExpr = pNew; + } + } + return pExpr; +} +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ + Token s; + assert( zC!=0 ); + sqlite3TokenInit(&s, (char*)zC); + return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0); +} + +/* +** Skip over any TK_COLLATE operators and any unlikely() +** or likelihood() function at the root of an expression. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ + while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ + if( ExprHasProperty(pExpr, EP_Unlikely) ){ + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( pExpr->x.pList->nExpr>0 ); + assert( pExpr->op==TK_FUNCTION ); + pExpr = pExpr->x.pList->a[0].pExpr; + }else{ + assert( pExpr->op==TK_COLLATE ); + pExpr = pExpr->pLeft; + } + } + return pExpr; +} + +/* +** Return the collation sequence for the expression pExpr. If +** there is no defined collating sequence, return NULL. +** +** 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 +** precedence over right operands. +*/ +SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ + sqlite3 *db = pParse->db; + CollSeq *pColl = 0; + Expr *p = pExpr; + while( p ){ + int op = p->op; + if( p->flags & EP_Generic ) break; + if( op==TK_CAST || op==TK_UPLUS ){ + p = p->pLeft; + continue; + } + if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){ + pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); + break; + } + if( (op==TK_AGG_COLUMN || op==TK_COLUMN + || op==TK_REGISTER || op==TK_TRIGGER) + && p->pTab!=0 + ){ + /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally + ** a TK_COLUMN but was previously evaluated and cached in a register */ + int j = p->iColumn; + if( j>=0 ){ + const char *zColl = p->pTab->aCol[j].zColl; + pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); + } + break; + } + if( p->flags & EP_Collate ){ + if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){ + p = p->pLeft; + }else{ + Expr *pNext = p->pRight; + /* The Expr.x union is never used at the same time as Expr.pRight */ + assert( p->x.pList==0 || p->pRight==0 ); + /* p->flags holds EP_Collate and p->pLeft->flags does not. And + ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at + ** least one EP_Collate. Thus the following two ALWAYS. */ + if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){ + int i; + for(i=0; ALWAYS(ix.pList->nExpr); i++){ + if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ + pNext = p->x.pList->a[i].pExpr; + break; + } + } + } + p = pNext; + } + }else{ + break; + } + } + if( sqlite3CheckCollSeq(pParse, pColl) ){ + pColl = 0; + } + return pColl; +} + +/* +** 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. +*/ +SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){ + char aff1 = sqlite3ExprAffinity(pExpr); + if( aff1 && aff2 ){ + /* Both sides of the comparison are columns. If one has numeric + ** affinity, use that. Otherwise use no affinity. + */ + if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){ + return SQLITE_AFF_NUMERIC; + }else{ + return SQLITE_AFF_BLOB; + } + }else if( !aff1 && !aff2 ){ + /* Neither side of the comparison is a column. Compare the + ** results directly. + */ + return SQLITE_AFF_BLOB; + }else{ + /* One side is a column, the other is not. Use the columns affinity. */ + assert( aff1==0 || aff2==0 ); + return (aff1 + aff2); + } +} + +/* +** pExpr is a comparison operator. Return the type affinity that should +** be applied to both operands prior to doing the comparison. +*/ +static char comparisonAffinity(Expr *pExpr){ + char aff; + assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT || + pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE || + pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT ); + assert( pExpr->pLeft ); + aff = sqlite3ExprAffinity(pExpr->pLeft); + if( pExpr->pRight ){ + aff = sqlite3CompareAffinity(pExpr->pRight, aff); + }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); + }else if( aff==0 ){ + aff = SQLITE_AFF_BLOB; + } + return aff; +} + +/* +** pExpr is a comparison expression, eg. '=', '<', IN(...) etc. +** idx_affinity is the affinity of an indexed column. Return true +** if the index with affinity idx_affinity may be used to implement +** the comparison in pExpr. +*/ +SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ + char aff = comparisonAffinity(pExpr); + switch( aff ){ + case SQLITE_AFF_BLOB: + return 1; + case SQLITE_AFF_TEXT: + return idx_affinity==SQLITE_AFF_TEXT; + default: + return sqlite3IsNumericAffinity(idx_affinity); + } +} + +/* +** Return the P5 value that should be used for a binary comparison +** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2. +*/ +static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){ + u8 aff = (char)sqlite3ExprAffinity(pExpr2); + aff = (u8)sqlite3CompareAffinity(pExpr1, aff) | (u8)jumpIfNull; + return aff; +} + +/* +** Return a pointer to the collation sequence that should be used by +** a binary comparison operator comparing pLeft and pRight. +** +** If the left hand expression has a collating sequence type, then it is +** used. Otherwise the collation sequence for the right hand expression +** is used, or the default (BINARY) if neither expression has a collating +** type. +** +** Argument pRight (but not pLeft) may be a null pointer. In this case, +** it is not considered. +*/ +SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq( + Parse *pParse, + Expr *pLeft, + Expr *pRight +){ + CollSeq *pColl; + assert( pLeft ); + if( pLeft->flags & EP_Collate ){ + pColl = sqlite3ExprCollSeq(pParse, pLeft); + }else if( pRight && (pRight->flags & EP_Collate)!=0 ){ + pColl = sqlite3ExprCollSeq(pParse, pRight); + }else{ + pColl = sqlite3ExprCollSeq(pParse, pLeft); + if( !pColl ){ + pColl = sqlite3ExprCollSeq(pParse, pRight); + } + } + return pColl; +} + +/* +** Generate code for a comparison operator. +*/ +static int codeCompare( + Parse *pParse, /* The parsing (and code generating) context */ + Expr *pLeft, /* The left operand */ + Expr *pRight, /* The right operand */ + int opcode, /* The comparison opcode */ + int in1, int in2, /* Register holding operands */ + int dest, /* Jump here if true. */ + int jumpIfNull /* If true, jump if either operand is NULL */ +){ + int p5; + int addr; + CollSeq *p4; + + p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight); + p5 = binaryCompareP5(pLeft, pRight, jumpIfNull); + addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1, + (void*)p4, P4_COLLSEQ); + sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5); + return addr; +} + +/* +** Return true if expression pExpr is a vector, or false otherwise. +** +** A vector is defined as any expression that results in two or more +** columns of result. Every TK_VECTOR node is an vector because the +** parser will not generate a TK_VECTOR with fewer than two entries. +** But a TK_SELECT might be either a vector or a scalar. It is only +** considered a vector if it has two or more result columns. +*/ +SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){ + return sqlite3ExprVectorSize(pExpr)>1; +} + +/* +** If the expression passed as the only argument is of type TK_VECTOR +** return the number of expressions in the vector. Or, if the expression +** is a sub-select, return the number of columns in the sub-select. For +** any other type of expression, return 1. +*/ +SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){ + u8 op = pExpr->op; + if( op==TK_REGISTER ) op = pExpr->op2; + if( op==TK_VECTOR ){ + return pExpr->x.pList->nExpr; + }else if( op==TK_SELECT ){ + return pExpr->x.pSelect->pEList->nExpr; + }else{ + return 1; + } +} + +/* +** Return a pointer to a subexpression of pVector that is the i-th +** column of the vector (numbered starting with 0). The caller must +** ensure that i is within range. +** +** If pVector is really a scalar (and "scalar" here includes subqueries +** that return a single column!) then return pVector unmodified. +** +** pVector retains ownership of the returned subexpression. +** +** If the vector is a (SELECT ...) then the expression returned is +** just the expression for the i-th term of the result set, and may +** not be ready for evaluation because the table cursor has not yet +** been positioned. +*/ +SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ + assert( iop2==0 || pVector->op==TK_REGISTER ); + if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){ + return pVector->x.pSelect->pEList->a[i].pExpr; + }else{ + return pVector->x.pList->a[i].pExpr; + } + } + return pVector; +} + +/* +** Compute and return a new Expr object which when passed to +** sqlite3ExprCode() will generate all necessary code to compute +** the iField-th column of the vector expression pVector. +** +** It is ok for pVector to be a scalar (as long as iField==0). +** In that case, this routine works like sqlite3ExprDup(). +** +** The caller owns the returned Expr object and is responsible for +** ensuring that the returned value eventually gets freed. +** +** The caller retains ownership of pVector. If pVector is a TK_SELECT, +** then the returned object will reference pVector and so pVector must remain +** valid for the life of the returned object. If pVector is a TK_VECTOR +** or a scalar expression, then it can be deleted as soon as this routine +** returns. +** +** A trick to cause a TK_SELECT pVector to be deleted together with +** the returned Expr object is to attach the pVector to the pRight field +** of the returned TK_SELECT_COLUMN Expr object. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( + Parse *pParse, /* Parsing context */ + Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ + int iField /* Which column of the vector to return */ +){ + Expr *pRet; + if( pVector->op==TK_SELECT ){ + assert( pVector->flags & EP_xIsSelect ); + /* The TK_SELECT_COLUMN Expr node: + ** + ** pLeft: pVector containing TK_SELECT. Not deleted. + ** pRight: not used. But recursively deleted. + ** iColumn: Index of a column in pVector + ** iTable: 0 or the number of columns on the LHS of an assignment + ** pLeft->iTable: First in an array of register holding result, or 0 + ** if the result is not yet computed. + ** + ** sqlite3ExprDelete() specifically skips the recursive delete of + ** pLeft on TK_SELECT_COLUMN nodes. But pRight is followed, so pVector + ** can be attached to pRight to cause this node to take ownership of + ** pVector. Typically there will be multiple TK_SELECT_COLUMN nodes + ** with the same pLeft pointer to the pVector, but only one of them + ** will own the pVector. + */ + pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); + if( pRet ){ + pRet->iColumn = iField; + pRet->pLeft = pVector; + } + assert( pRet==0 || pRet->iTable==0 ); + }else{ + if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr; + pRet = sqlite3ExprDup(pParse->db, pVector, 0); + } + return pRet; +} + +/* +** If expression pExpr is of type TK_SELECT, generate code to evaluate +** it. Return the register in which the result is stored (or, if the +** sub-select returns more than one column, the first in an array +** of registers in which the result is stored). +** +** If pExpr is not a TK_SELECT expression, return 0. +*/ +static int exprCodeSubselect(Parse *pParse, Expr *pExpr){ + int reg = 0; +#ifndef SQLITE_OMIT_SUBQUERY + if( pExpr->op==TK_SELECT ){ + reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0); + } +#endif + return reg; +} + +/* +** Argument pVector points to a vector expression - either a TK_VECTOR +** or TK_SELECT that returns more than one column. This function returns +** the register number of a register that contains the value of +** element iField of the vector. +** +** If pVector is a TK_SELECT expression, then code for it must have +** already been generated using the exprCodeSubselect() routine. In this +** case parameter regSelect should be the first in an array of registers +** containing the results of the sub-select. +** +** If pVector is of type TK_VECTOR, then code for the requested field +** is generated. In this case (*pRegFree) may be set to the number of +** a temporary register to be freed by the caller before returning. +** +** Before returning, output parameter (*ppExpr) is set to point to the +** Expr object corresponding to element iElem of the vector. +*/ +static int exprVectorRegister( + Parse *pParse, /* Parse context */ + Expr *pVector, /* Vector to extract element from */ + int iField, /* Field to extract from pVector */ + int regSelect, /* First in array of registers */ + Expr **ppExpr, /* OUT: Expression element */ + int *pRegFree /* OUT: Temp register to free */ +){ + u8 op = pVector->op; + assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT ); + if( op==TK_REGISTER ){ + *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField); + return pVector->iTable+iField; + } + if( op==TK_SELECT ){ + *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; + return regSelect+iField; + } + *ppExpr = pVector->x.pList->a[iField].pExpr; + return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); +} + +/* +** Expression pExpr is a comparison between two vector values. Compute +** the result of the comparison (1, 0, or NULL) and write that +** result into register dest. +** +** The caller must satisfy the following preconditions: +** +** if pExpr->op==TK_IS: op==TK_EQ and p5==SQLITE_NULLEQ +** if pExpr->op==TK_ISNOT: op==TK_NE and p5==SQLITE_NULLEQ +** otherwise: op==pExpr->op and p5==0 +*/ +static void codeVectorCompare( + Parse *pParse, /* Code generator context */ + Expr *pExpr, /* The comparison operation */ + int dest, /* Write results into this register */ + u8 op, /* Comparison operator */ + u8 p5 /* SQLITE_NULLEQ or zero */ +){ + Vdbe *v = pParse->pVdbe; + Expr *pLeft = pExpr->pLeft; + Expr *pRight = pExpr->pRight; + int nLeft = sqlite3ExprVectorSize(pLeft); + int i; + int regLeft = 0; + int regRight = 0; + u8 opx = op; + int addrDone = sqlite3VdbeMakeLabel(v); + + if( nLeft!=sqlite3ExprVectorSize(pRight) ){ + sqlite3ErrorMsg(pParse, "row value misused"); + return; + } + assert( pExpr->op==TK_EQ || pExpr->op==TK_NE + || pExpr->op==TK_IS || pExpr->op==TK_ISNOT + || pExpr->op==TK_LT || pExpr->op==TK_GT + || pExpr->op==TK_LE || pExpr->op==TK_GE + ); + assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ) + || (pExpr->op==TK_ISNOT && op==TK_NE) ); + assert( p5==0 || pExpr->op!=op ); + assert( p5==SQLITE_NULLEQ || pExpr->op==op ); + + p5 |= SQLITE_STOREP2; + if( opx==TK_LE ) opx = TK_LT; + if( opx==TK_GE ) opx = TK_GT; + + regLeft = exprCodeSubselect(pParse, pLeft); + regRight = exprCodeSubselect(pParse, pRight); + + for(i=0; 1 /*Loop exits by "break"*/; i++){ + int regFree1 = 0, regFree2 = 0; + Expr *pL, *pR; + int r1, r2; + assert( i>=0 && i0 ) sqlite3ExprCachePush(pParse); + r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); + r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); + codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5); + testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); + testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); + testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); + testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); + testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); + testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); + if( i>0 ) sqlite3ExprCachePop(pParse); + if( i==nLeft-1 ){ + break; + } + if( opx==TK_EQ ){ + sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v); + p5 |= SQLITE_KEEPNULL; + }else if( opx==TK_NE ){ + sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v); + p5 |= SQLITE_KEEPNULL; + }else{ + assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE ); + sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone); + VdbeCoverageIf(v, op==TK_LT); + VdbeCoverageIf(v, op==TK_GT); + VdbeCoverageIf(v, op==TK_LE); + VdbeCoverageIf(v, op==TK_GE); + if( i==nLeft-2 ) opx = op; + } + } + sqlite3VdbeResolveLabel(v, addrDone); +} + +#if SQLITE_MAX_EXPR_DEPTH>0 +/* +** Check that argument nHeight is less than or equal to the maximum +** expression depth allowed. If it is not, leave an error message in +** pParse. +*/ +SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){ + int rc = SQLITE_OK; + int mxHeight = pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH]; + if( nHeight>mxHeight ){ + sqlite3ErrorMsg(pParse, + "Expression tree is too large (maximum depth %d)", mxHeight + ); + rc = SQLITE_ERROR; + } + return rc; +} + +/* The following three functions, heightOfExpr(), heightOfExprList() +** and heightOfSelect(), are used to determine the maximum height +** of any expression tree referenced by the structure passed as the +** first argument. +** +** If this maximum height is greater than the current value pointed +** to by pnHeight, the second parameter, then set *pnHeight to that +** value. +*/ +static void heightOfExpr(Expr *p, int *pnHeight){ + if( p ){ + if( p->nHeight>*pnHeight ){ + *pnHeight = p->nHeight; + } + } +} +static void heightOfExprList(ExprList *p, int *pnHeight){ + if( p ){ + int i; + for(i=0; inExpr; i++){ + heightOfExpr(p->a[i].pExpr, pnHeight); + } + } +} +static void heightOfSelect(Select *p, int *pnHeight){ + if( p ){ + heightOfExpr(p->pWhere, pnHeight); + heightOfExpr(p->pHaving, pnHeight); + heightOfExpr(p->pLimit, pnHeight); + heightOfExpr(p->pOffset, pnHeight); + heightOfExprList(p->pEList, pnHeight); + heightOfExprList(p->pGroupBy, pnHeight); + heightOfExprList(p->pOrderBy, pnHeight); + heightOfSelect(p->pPrior, pnHeight); + } +} + +/* +** Set the Expr.nHeight variable in the structure passed as an +** argument. An expression with no children, Expr.pList or +** Expr.pSelect member has a height of 1. Any other expression +** has a height equal to the maximum height of any other +** referenced Expr plus one. +** +** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags, +** if appropriate. +*/ +static void exprSetHeight(Expr *p){ + int nHeight = 0; + heightOfExpr(p->pLeft, &nHeight); + heightOfExpr(p->pRight, &nHeight); + if( ExprHasProperty(p, EP_xIsSelect) ){ + heightOfSelect(p->x.pSelect, &nHeight); + }else if( p->x.pList ){ + heightOfExprList(p->x.pList, &nHeight); + p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); + } + p->nHeight = nHeight + 1; +} + +/* +** Set the Expr.nHeight variable using the exprSetHeight() function. If +** the height is greater than the maximum allowed expression depth, +** leave an error in pParse. +** +** Also propagate all EP_Propagate flags from the Expr.x.pList into +** Expr.flags. +*/ +SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ + if( pParse->nErr ) return; + exprSetHeight(p); + sqlite3ExprCheckHeight(pParse, p->nHeight); +} + +/* +** Return the maximum height of any expression tree referenced +** by the select statement passed as an argument. +*/ +SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){ + int nHeight = 0; + heightOfSelect(p, &nHeight); + return nHeight; +} +#else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */ +/* +** Propagate all EP_Propagate flags from the Expr.x.pList into +** Expr.flags. +*/ +SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ + if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){ + p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); + } +} +#define exprSetHeight(y) +#endif /* SQLITE_MAX_EXPR_DEPTH>0 */ + +/* +** This routine is the core allocator for Expr nodes. +** +** Construct a new expression node and return a pointer to it. Memory +** for this node and for the pToken argument is a single allocation +** obtained from sqlite3DbMalloc(). The calling function +** is responsible for making sure the node eventually gets freed. +** +** If dequote is true, then the token (if it exists) is dequoted. +** If dequote is false, no dequoting is performed. The deQuote +** parameter is ignored if pToken is NULL or if the token does not +** appear to be quoted. If the quotes were of the form "..." (double-quotes) +** then the EP_DblQuoted flag is set on the expression node. +** +** Special case: If op==TK_INTEGER and pToken points to a string that +** can be translated into a 32-bit integer, then the token is not +** stored in u.zToken. Instead, the integer values is written +** into u.iValue and the EP_IntValue flag is set. No extra storage +** is allocated to hold the integer text and the dequote flag is ignored. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprAlloc( + sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */ + int op, /* Expression opcode */ + const Token *pToken, /* Token argument. Might be NULL */ + int dequote /* True to dequote */ +){ + Expr *pNew; + int nExtra = 0; + int iValue = 0; + + assert( db!=0 ); + if( pToken ){ + if( op!=TK_INTEGER || pToken->z==0 + || sqlite3GetInt32(pToken->z, &iValue)==0 ){ + nExtra = pToken->n+1; + assert( iValue>=0 ); + } + } + pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); + if( pNew ){ + memset(pNew, 0, sizeof(Expr)); + pNew->op = (u8)op; + pNew->iAgg = -1; + if( pToken ){ + if( nExtra==0 ){ + pNew->flags |= EP_IntValue; + pNew->u.iValue = iValue; + }else{ + pNew->u.zToken = (char*)&pNew[1]; + assert( pToken->z!=0 || pToken->n==0 ); + if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); + pNew->u.zToken[pToken->n] = 0; + if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ + if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted; + sqlite3Dequote(pNew->u.zToken); + } + } + } +#if SQLITE_MAX_EXPR_DEPTH>0 + pNew->nHeight = 1; +#endif + } + return pNew; +} + +/* +** Allocate a new expression node from a zero-terminated token that has +** already been dequoted. +*/ +SQLITE_PRIVATE Expr *sqlite3Expr( + sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */ + int op, /* Expression opcode */ + const char *zToken /* Token argument. Might be NULL */ +){ + Token x; + x.z = zToken; + x.n = zToken ? sqlite3Strlen30(zToken) : 0; + return sqlite3ExprAlloc(db, op, &x, 0); +} + +/* +** Attach subtrees pLeft and pRight to the Expr node pRoot. +** +** If pRoot==NULL that means that a memory allocation error has occurred. +** In that case, delete the subtrees pLeft and pRight. +*/ +SQLITE_PRIVATE void sqlite3ExprAttachSubtrees( + sqlite3 *db, + Expr *pRoot, + Expr *pLeft, + Expr *pRight +){ + if( pRoot==0 ){ + assert( db->mallocFailed ); + sqlite3ExprDelete(db, pLeft); + sqlite3ExprDelete(db, pRight); + }else{ + if( pRight ){ + pRoot->pRight = pRight; + pRoot->flags |= EP_Propagate & pRight->flags; + } + if( pLeft ){ + pRoot->pLeft = pLeft; + pRoot->flags |= EP_Propagate & pLeft->flags; + } + exprSetHeight(pRoot); + } +} + +/* +** Allocate an Expr node which joins as many as two subtrees. +** +** One or both of the subtrees can be NULL. Return a pointer to the new +** Expr node. Or, if an OOM error occurs, set pParse->db->mallocFailed, +** free the subtrees and return NULL. +*/ +SQLITE_PRIVATE Expr *sqlite3PExpr( + Parse *pParse, /* Parsing context */ + int op, /* Expression opcode */ + Expr *pLeft, /* Left operand */ + Expr *pRight /* Right operand */ +){ + Expr *p; + if( op==TK_AND && pParse->nErr==0 ){ + /* Take advantage of short-circuit false optimization for AND */ + p = sqlite3ExprAnd(pParse->db, pLeft, pRight); + }else{ + p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = op & TKFLG_MASK; + p->iAgg = -1; + } + sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); + } + if( p ) { + sqlite3ExprCheckHeight(pParse, p->nHeight); + } + return p; +} + +/* +** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due +** do a memory allocation failure) then delete the pSelect object. +*/ +SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){ + if( pExpr ){ + pExpr->x.pSelect = pSelect; + ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery); + sqlite3ExprSetHeightAndFlags(pParse, pExpr); + }else{ + assert( pParse->db->mallocFailed ); + sqlite3SelectDelete(pParse->db, pSelect); + } +} + + +/* +** If the expression is always either TRUE or FALSE (respectively), +** then return 1. If one cannot determine the truth value of the +** expression at compile-time return 0. +** +** This is an optimization. If is OK to return 0 here even if +** the expression really is always false or false (a false negative). +** But it is a bug to return 1 if the expression might have different +** boolean values in different circumstances (a false positive.) +** +** Note that if the expression is part of conditional for a +** LEFT JOIN, then we cannot determine at compile-time whether or not +** is it true or false, so always return 0. +*/ +static int exprAlwaysTrue(Expr *p){ + int v = 0; + if( ExprHasProperty(p, EP_FromJoin) ) return 0; + if( !sqlite3ExprIsInteger(p, &v) ) return 0; + return v!=0; +} +static int exprAlwaysFalse(Expr *p){ + int v = 0; + if( ExprHasProperty(p, EP_FromJoin) ) return 0; + if( !sqlite3ExprIsInteger(p, &v) ) return 0; + return v==0; +} + +/* +** Join two expressions using an AND operator. If either expression is +** NULL, then just return the other expression. +** +** If one side or the other of the AND is known to be false, then instead +** of returning an AND expression, just return a constant expression with +** a value of false. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ + if( pLeft==0 ){ + return pRight; + }else if( pRight==0 ){ + return pLeft; + }else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){ + sqlite3ExprDelete(db, pLeft); + sqlite3ExprDelete(db, pRight); + return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0); + }else{ + Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0); + sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight); + return pNew; + } +} + +/* +** Construct a new expression node for a function with multiple +** arguments. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ + Expr *pNew; + sqlite3 *db = pParse->db; + assert( pToken ); + pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1); + if( pNew==0 ){ + sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ + return 0; + } + pNew->x.pList = pList; + assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + sqlite3ExprSetHeightAndFlags(pParse, pNew); + return pNew; +} + +/* +** Assign a variable number to an expression that encodes a wildcard +** in the original SQL statement. +** +** Wildcards consisting of a single "?" are assigned the next sequential +** variable number. +** +** Wildcards of the form "?nnn" are assigned the number "nnn". We make +** sure "nnn" is not too big to avoid a denial of service attack when +** the SQL statement comes from an external source. +** +** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number +** as the previous instance of the same wildcard. Or if this is the first +** instance of the wildcard, the next sequential variable number is +** assigned. +*/ +SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){ + sqlite3 *db = pParse->db; + const char *z; + ynVar x; + + if( pExpr==0 ) return; + assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) ); + z = pExpr->u.zToken; + assert( z!=0 ); + assert( z[0]!=0 ); + assert( n==(u32)sqlite3Strlen30(z) ); + if( z[1]==0 ){ + /* Wildcard of the form "?". Assign the next variable number */ + assert( z[0]=='?' ); + x = (ynVar)(++pParse->nVar); + }else{ + int doAdd = 0; + if( z[0]=='?' ){ + /* Wildcard of the form "?nnn". Convert "nnn" to an integer and + ** use it as the variable number */ + i64 i; + int bOk; + if( n==2 ){ /*OPTIMIZATION-IF-TRUE*/ + i = z[1]-'0'; /* The common case of ?N for a single digit N */ + bOk = 1; + }else{ + bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8); + } + testcase( i==0 ); + testcase( i==1 ); + testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); + testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); + if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ + sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", + db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); + return; + } + x = (ynVar)i; + if( x>pParse->nVar ){ + pParse->nVar = (int)x; + doAdd = 1; + }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){ + doAdd = 1; + } + }else{ + /* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable + ** number as the prior appearance of the same name, or if the name + ** has never appeared before, reuse the same variable number + */ + x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n); + if( x==0 ){ + x = (ynVar)(++pParse->nVar); + doAdd = 1; + } + } + if( doAdd ){ + pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x); + } + } + pExpr->iColumn = x; + if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ + sqlite3ErrorMsg(pParse, "too many SQL variables"); + } +} + +/* +** Recursively delete an expression tree. +*/ +static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ + assert( p!=0 ); + /* Sanity check: Assert that the IntValue is non-negative if it exists */ + assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); +#ifdef SQLITE_DEBUG + if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ + assert( p->pLeft==0 ); + assert( p->pRight==0 ); + assert( p->x.pSelect==0 ); + } +#endif + if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ + /* The Expr.x union is never used at the same time as Expr.pRight */ + assert( p->x.pList==0 || p->pRight==0 ); + if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); + sqlite3ExprDelete(db, p->pRight); + if( ExprHasProperty(p, EP_xIsSelect) ){ + sqlite3SelectDelete(db, p->x.pSelect); + }else{ + sqlite3ExprListDelete(db, p->x.pList); + } + } + if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); + if( !ExprHasProperty(p, EP_Static) ){ + sqlite3DbFreeNN(db, p); + } +} +SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ + if( p ) sqlite3ExprDeleteNN(db, p); +} + +/* +** Return the number of bytes allocated for the expression structure +** passed as the first argument. This is always one of EXPR_FULLSIZE, +** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE. +*/ +static int exprStructSize(Expr *p){ + if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE; + if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE; + return EXPR_FULLSIZE; +} + +/* +** The dupedExpr*Size() routines each return the number of bytes required +** to store a copy of an expression or expression tree. They differ in +** how much of the tree is measured. +** +** dupedExprStructSize() Size of only the Expr structure +** dupedExprNodeSize() Size of Expr + space for token +** dupedExprSize() Expr + token + subtree components +** +*************************************************************************** +** +** The dupedExprStructSize() function returns two values OR-ed together: +** (1) the space required for a copy of the Expr structure only and +** (2) the EP_xxx flags that indicate what the structure size should be. +** The return values is always one of: +** +** EXPR_FULLSIZE +** EXPR_REDUCEDSIZE | EP_Reduced +** EXPR_TOKENONLYSIZE | EP_TokenOnly +** +** The size of the structure can be found by masking the return value +** of this routine with 0xfff. The flags can be found by masking the +** return value with EP_Reduced|EP_TokenOnly. +** +** Note that with flags==EXPRDUP_REDUCE, this routines works on full-size +** (unreduced) Expr objects as they or originally constructed by the parser. +** During expression analysis, extra information is computed and moved into +** later parts of teh Expr object and that extra information might get chopped +** off if the expression is reduced. Note also that it does not work to +** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal +** to reduce a pristine expression tree from the parser. The implementation +** of dupedExprStructSize() contain multiple assert() statements that attempt +** to enforce this constraint. +*/ +static int dupedExprStructSize(Expr *p, int flags){ + int nSize; + assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ + assert( EXPR_FULLSIZE<=0xfff ); + assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); + if( 0==flags || p->op==TK_SELECT_COLUMN ){ + nSize = EXPR_FULLSIZE; + }else{ + assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); + assert( !ExprHasProperty(p, EP_FromJoin) ); + assert( !ExprHasProperty(p, EP_MemToken) ); + assert( !ExprHasProperty(p, EP_NoReduce) ); + if( p->pLeft || p->x.pList ){ + nSize = EXPR_REDUCEDSIZE | EP_Reduced; + }else{ + assert( p->pRight==0 ); + nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly; + } + } + return nSize; +} + +/* +** This function returns the space in bytes required to store the copy +** of the Expr structure and a copy of the Expr.u.zToken string (if that +** string is defined.) +*/ +static int dupedExprNodeSize(Expr *p, int flags){ + int nByte = dupedExprStructSize(p, flags) & 0xfff; + if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ + nByte += sqlite3Strlen30(p->u.zToken)+1; + } + return ROUND8(nByte); +} + +/* +** Return the number of bytes required to create a duplicate of the +** expression passed as the first argument. The second argument is a +** mask containing EXPRDUP_XXX flags. +** +** The value returned includes space to create a copy of the Expr struct +** itself and the buffer referred to by Expr.u.zToken, if any. +** +** If the EXPRDUP_REDUCE flag is set, then the return value includes +** space to duplicate all Expr nodes in the tree formed by Expr.pLeft +** and Expr.pRight variables (but not for any structures pointed to or +** descended from the Expr.x.pList or Expr.x.pSelect variables). +*/ +static int dupedExprSize(Expr *p, int flags){ + int nByte = 0; + if( p ){ + nByte = dupedExprNodeSize(p, flags); + if( flags&EXPRDUP_REDUCE ){ + nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags); + } + } + return nByte; +} + +/* +** This function is similar to sqlite3ExprDup(), except that if pzBuffer +** is not NULL then *pzBuffer is assumed to point to a buffer large enough +** to store the copy of expression p, the copies of p->u.zToken +** (if applicable), and the copies of the p->pLeft and p->pRight expressions, +** if any. Before returning, *pzBuffer is set to the first byte past the +** portion of the buffer copied into by this function. +*/ +static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ + Expr *pNew; /* Value to return */ + u8 *zAlloc; /* Memory space from which to build Expr object */ + u32 staticFlag; /* EP_Static if space not obtained from malloc */ + + assert( db!=0 ); + assert( p ); + assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE ); + assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE ); + + /* Figure out where to write the new Expr structure. */ + if( pzBuffer ){ + zAlloc = *pzBuffer; + staticFlag = EP_Static; + }else{ + zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); + staticFlag = 0; + } + pNew = (Expr *)zAlloc; + + if( pNew ){ + /* Set nNewSize to the size allocated for the structure pointed to + ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or + ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed + ** by the copy of the p->u.zToken string (if any). + */ + const unsigned nStructSize = dupedExprStructSize(p, dupFlags); + const int nNewSize = nStructSize & 0xfff; + int nToken; + if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ + nToken = sqlite3Strlen30(p->u.zToken) + 1; + }else{ + nToken = 0; + } + if( dupFlags ){ + assert( ExprHasProperty(p, EP_Reduced)==0 ); + memcpy(zAlloc, p, nNewSize); + }else{ + u32 nSize = (u32)exprStructSize(p); + memcpy(zAlloc, p, nSize); + if( nSizeflags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); + pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); + pNew->flags |= staticFlag; + + /* Copy the p->u.zToken string, if any. */ + if( nToken ){ + char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize]; + memcpy(zToken, p->u.zToken, nToken); + } + + if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ + /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ + if( ExprHasProperty(p, EP_xIsSelect) ){ + pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); + }else{ + pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); + } + } + + /* Fill in pNew->pLeft and pNew->pRight. */ + if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ + zAlloc += dupedExprNodeSize(p, dupFlags); + if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){ + pNew->pLeft = p->pLeft ? + exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0; + pNew->pRight = p->pRight ? + exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0; + } + if( pzBuffer ){ + *pzBuffer = zAlloc; + } + }else{ + if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ + if( pNew->op==TK_SELECT_COLUMN ){ + pNew->pLeft = p->pLeft; + assert( p->iColumn==0 || p->pRight==0 ); + assert( p->pRight==0 || p->pRight==p->pLeft ); + }else{ + pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); + } + pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); + } + } + } + return pNew; +} + +/* +** Create and return a deep copy of the object passed as the second +** argument. If an OOM condition is encountered, NULL is returned +** and the db->mallocFailed flag set. +*/ +#ifndef SQLITE_OMIT_CTE +static With *withDup(sqlite3 *db, With *p){ + With *pRet = 0; + if( p ){ + int nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); + pRet = sqlite3DbMallocZero(db, nByte); + if( pRet ){ + int i; + pRet->nCte = p->nCte; + for(i=0; inCte; i++){ + pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0); + pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0); + pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName); + } + } + } + return pRet; +} +#else +# define withDup(x,y) 0 +#endif + +/* +** The following group of routines make deep copies of expressions, +** expression lists, ID lists, and select statements. The copies can +** be deleted (by being passed to their respective ...Delete() routines) +** without effecting the originals. +** +** The expression list, ID, and source lists return by sqlite3ExprListDup(), +** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded +** by subsequent calls to sqlite*ListAppend() routines. +** +** Any tables that the SrcList might point to are not duplicated. +** +** The flags parameter contains a combination of the EXPRDUP_XXX flags. +** If the EXPRDUP_REDUCE flag is set, then the structure returned is a +** truncated version of the usual Expr structure that will be stored as +** part of the in-memory representation of the database schema. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){ + assert( flags==0 || flags==EXPRDUP_REDUCE ); + return p ? exprDup(db, p, flags, 0) : 0; +} +SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ + ExprList *pNew; + struct ExprList_item *pItem, *pOldItem; + int i; + Expr *pPriorSelectCol = 0; + assert( db!=0 ); + if( p==0 ) return 0; + pNew = sqlite3DbMallocRawNN(db, + sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) ); + if( pNew==0 ) return 0; + pNew->nAlloc = pNew->nExpr = p->nExpr; + pItem = pNew->a; + pOldItem = p->a; + for(i=0; inExpr; i++, pItem++, pOldItem++){ + Expr *pOldExpr = pOldItem->pExpr; + Expr *pNewExpr; + pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags); + if( pOldExpr + && pOldExpr->op==TK_SELECT_COLUMN + && (pNewExpr = pItem->pExpr)!=0 + ){ + assert( pNewExpr->iColumn==0 || i>0 ); + if( pNewExpr->iColumn==0 ){ + assert( pOldExpr->pLeft==pOldExpr->pRight ); + pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight; + }else{ + assert( i>0 ); + assert( pItem[-1].pExpr!=0 ); + assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 ); + assert( pPriorSelectCol==pItem[-1].pExpr->pLeft ); + pNewExpr->pLeft = pPriorSelectCol; + } + } + pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); + pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan); + pItem->sortOrder = pOldItem->sortOrder; + pItem->done = 0; + pItem->bSpanIsTab = pOldItem->bSpanIsTab; + pItem->u = pOldItem->u; + } + return pNew; +} + +/* +** If cursors, triggers, views and subqueries are all omitted from +** the build, then none of the following routines, except for +** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes +** called with a NULL argument. +*/ +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \ + || !defined(SQLITE_OMIT_SUBQUERY) +SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ + SrcList *pNew; + int i; + int nByte; + assert( db!=0 ); + if( p==0 ) return 0; + nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); + pNew = sqlite3DbMallocRawNN(db, nByte ); + if( pNew==0 ) return 0; + pNew->nSrc = pNew->nAlloc = p->nSrc; + for(i=0; inSrc; i++){ + struct SrcList_item *pNewItem = &pNew->a[i]; + struct SrcList_item *pOldItem = &p->a[i]; + Table *pTab; + pNewItem->pSchema = pOldItem->pSchema; + pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); + pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); + pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); + pNewItem->fg = pOldItem->fg; + pNewItem->iCursor = pOldItem->iCursor; + pNewItem->addrFillSub = pOldItem->addrFillSub; + pNewItem->regReturn = pOldItem->regReturn; + if( pNewItem->fg.isIndexedBy ){ + pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); + } + pNewItem->pIBIndex = pOldItem->pIBIndex; + if( pNewItem->fg.isTabFunc ){ + pNewItem->u1.pFuncArg = + sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); + } + pTab = pNewItem->pTab = pOldItem->pTab; + if( pTab ){ + pTab->nTabRef++; + } + pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); + pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags); + pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing); + pNewItem->colUsed = pOldItem->colUsed; + } + return pNew; +} +SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ + IdList *pNew; + int i; + assert( db!=0 ); + if( p==0 ) return 0; + pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) ); + if( pNew==0 ) return 0; + pNew->nId = p->nId; + pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) ); + if( pNew->a==0 ){ + sqlite3DbFreeNN(db, pNew); + return 0; + } + /* Note that because the size of the allocation for p->a[] is not + ** necessarily a power of two, sqlite3IdListAppend() may not be called + ** on the duplicate created by this function. */ + for(i=0; inId; i++){ + struct IdList_item *pNewItem = &pNew->a[i]; + struct IdList_item *pOldItem = &p->a[i]; + pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); + pNewItem->idx = pOldItem->idx; + } + return pNew; +} +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ + Select *pRet = 0; + Select *pNext = 0; + Select **pp = &pRet; + Select *p; + + assert( db!=0 ); + for(p=pDup; p; p=p->pPrior){ + Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) ); + if( pNew==0 ) break; + pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags); + pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags); + pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags); + pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags); + pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags); + pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags); + pNew->op = p->op; + pNew->pNext = pNext; + pNew->pPrior = 0; + pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); + pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags); + pNew->iLimit = 0; + pNew->iOffset = 0; + pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->nSelectRow = p->nSelectRow; + pNew->pWith = withDup(db, p->pWith); + sqlite3SelectSetName(pNew, p->zSelName); + *pp = pNew; + pp = &pNew->pPrior; + pNext = pNew; + } + + return pRet; +} +#else +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ + assert( p==0 ); + return 0; +} +#endif + + +/* +** Add a new element to the end of an expression list. If pList is +** initially NULL, then create a new expression list. +** +** 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. +*/ +SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to append. Might be NULL */ + Expr *pExpr /* Expression to be appended. Might be NULL */ +){ + struct ExprList_item *pItem; + sqlite3 *db = pParse->db; + assert( db!=0 ); + if( pList==0 ){ + pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) ); + if( pList==0 ){ + goto no_mem; + } + pList->nExpr = 0; + pList->nAlloc = 1; + }else if( pList->nExpr==pList->nAlloc ){ + ExprList *pNew; + pNew = sqlite3DbRealloc(db, pList, + sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0])); + if( pNew==0 ){ + goto no_mem; + } + pList = pNew; + pList->nAlloc *= 2; + } + pItem = &pList->a[pList->nExpr++]; + memset(pItem, 0, sizeof(*pItem)); + pItem->pExpr = pExpr; + return pList; + +no_mem: + /* Avoid leaking memory if malloc has failed. */ + sqlite3ExprDelete(db, pExpr); + sqlite3ExprListDelete(db, pList); + return 0; +} + +/* +** pColumns and pExpr form a vector assignment which is part of the SET +** clause of an UPDATE statement. Like this: +** +** (a,b,c) = (expr1,expr2,expr3) +** Or: (a,b,c) = (SELECT x,y,z FROM ....) +** +** For each term of the vector assignment, append new entries to the +** expression list pList. In the case of a subquery on the RHS, append +** TK_SELECT_COLUMN expressions. +*/ +SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to append. Might be NULL */ + IdList *pColumns, /* List of names of LHS of the assignment */ + Expr *pExpr /* Vector expression to be appended. Might be NULL */ +){ + sqlite3 *db = pParse->db; + int n; + int i; + int iFirst = pList ? pList->nExpr : 0; + /* pColumns can only be NULL due to an OOM but an OOM will cause an + ** exit prior to this routine being invoked */ + if( NEVER(pColumns==0) ) goto vector_append_error; + if( pExpr==0 ) goto vector_append_error; + + /* If the RHS is a vector, then we can immediately check to see that + ** the size of the RHS and LHS match. But if the RHS is a SELECT, + ** wildcards ("*") in the result set of the SELECT must be expanded before + ** we can do the size check, so defer the size check until code generation. + */ + if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){ + sqlite3ErrorMsg(pParse, "%d columns assigned %d values", + pColumns->nId, n); + goto vector_append_error; + } + + for(i=0; inId; i++){ + Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i); + pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); + if( pList ){ + assert( pList->nExpr==iFirst+i+1 ); + pList->a[pList->nExpr-1].zName = pColumns->a[i].zName; + pColumns->a[i].zName = 0; + } + } + + if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){ + Expr *pFirst = pList->a[iFirst].pExpr; + assert( pFirst!=0 ); + assert( pFirst->op==TK_SELECT_COLUMN ); + + /* Store the SELECT statement in pRight so it will be deleted when + ** sqlite3ExprListDelete() is called */ + pFirst->pRight = pExpr; + pExpr = 0; + + /* Remember the size of the LHS in iTable so that we can check that + ** the RHS and LHS sizes match during code generation. */ + pFirst->iTable = pColumns->nId; + } + +vector_append_error: + sqlite3ExprDelete(db, pExpr); + sqlite3IdListDelete(db, pColumns); + return pList; +} + +/* +** Set the sort order for the last element on the given ExprList. +*/ +SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){ + if( p==0 ) return; + assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 ); + assert( p->nExpr>0 ); + if( iSortOrder<0 ){ + assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC ); + return; + } + p->a[p->nExpr-1].sortOrder = (u8)iSortOrder; +} + +/* +** Set the ExprList.a[].zName element of the most recently added item +** on the expression list. +** +** pList might be NULL following an OOM error. But pName should never be +** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag +** is set. +*/ +SQLITE_PRIVATE void sqlite3ExprListSetName( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to add the span. */ + Token *pName, /* Name to be added */ + int dequote /* True to cause the name to be dequoted */ +){ + assert( pList!=0 || pParse->db->mallocFailed!=0 ); + if( pList ){ + struct ExprList_item *pItem; + assert( pList->nExpr>0 ); + pItem = &pList->a[pList->nExpr-1]; + assert( pItem->zName==0 ); + pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); + if( dequote ) sqlite3Dequote(pItem->zName); + } +} + +/* +** Set the ExprList.a[].zSpan element of the most recently added item +** on the expression list. +** +** pList might be NULL following an OOM error. But pSpan should never be +** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag +** is set. +*/ +SQLITE_PRIVATE void sqlite3ExprListSetSpan( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to add the span. */ + ExprSpan *pSpan /* The span to be added */ +){ + sqlite3 *db = pParse->db; + assert( pList!=0 || db->mallocFailed!=0 ); + if( pList ){ + struct ExprList_item *pItem = &pList->a[pList->nExpr-1]; + assert( pList->nExpr>0 ); + assert( db->mallocFailed || pItem->pExpr==pSpan->pExpr ); + sqlite3DbFree(db, pItem->zSpan); + pItem->zSpan = sqlite3DbStrNDup(db, (char*)pSpan->zStart, + (int)(pSpan->zEnd - pSpan->zStart)); + } +} + +/* +** If the expression list pEList contains more than iLimit elements, +** leave an error message in pParse. +*/ +SQLITE_PRIVATE void sqlite3ExprListCheckLength( + Parse *pParse, + ExprList *pEList, + const char *zObject +){ + int mx = pParse->db->aLimit[SQLITE_LIMIT_COLUMN]; + testcase( pEList && pEList->nExpr==mx ); + testcase( pEList && pEList->nExpr==mx+1 ); + if( pEList && pEList->nExpr>mx ){ + sqlite3ErrorMsg(pParse, "too many columns in %s", zObject); + } +} + +/* +** Delete an entire expression list. +*/ +static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ + int i = pList->nExpr; + struct ExprList_item *pItem = pList->a; + assert( pList->nExpr>0 ); + do{ + sqlite3ExprDelete(db, pItem->pExpr); + sqlite3DbFree(db, pItem->zName); + sqlite3DbFree(db, pItem->zSpan); + pItem++; + }while( --i>0 ); + sqlite3DbFreeNN(db, pList); +} +SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ + if( pList ) exprListDeleteNN(db, pList); +} + +/* +** Return the bitwise-OR of all Expr.flags fields in the given +** ExprList. +*/ +SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ + int i; + u32 m = 0; + if( pList ){ + for(i=0; inExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + assert( pExpr!=0 ); + m |= pExpr->flags; + } + } + return m; +} + +/* +** 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 +** for. +** +** These callback routines are used to implement the following: +** +** sqlite3ExprIsConstant() pWalker->eCode==1 +** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2 +** sqlite3ExprIsTableConstant() pWalker->eCode==3 +** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5 +** +** In all cases, the callbacks set Walker.eCode=0 and abort if the expression +** is found to not be a constant. +** +** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions +** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing +** an existing schema and 4 when processing a new statement. A bound +** parameter raises an error for new statements, but is silently converted +** to NULL for existing schemas. This allows sqlite_master tables that +** contain a bound parameter because they were generated by older versions +** of SQLite to be parsed by newer versions of SQLite without raising a +** malformed schema error. +*/ +static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ + + /* If pWalker->eCode is 2 then any term of the expression that comes from + ** the ON or USING clauses of a left join disqualifies the expression + ** from being considered constant. */ + if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ + pWalker->eCode = 0; + return WRC_Abort; + } + + switch( pExpr->op ){ + /* Consider functions to be constant if all their arguments are constant + ** and either pWalker->eCode==4 or 5 or the function has the + ** SQLITE_FUNC_CONST flag. */ + case TK_FUNCTION: + if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){ + return WRC_Continue; + }else{ + pWalker->eCode = 0; + return WRC_Abort; + } + case TK_ID: + case TK_COLUMN: + case TK_AGG_FUNCTION: + case TK_AGG_COLUMN: + testcase( pExpr->op==TK_ID ); + testcase( pExpr->op==TK_COLUMN ); + testcase( pExpr->op==TK_AGG_FUNCTION ); + testcase( pExpr->op==TK_AGG_COLUMN ); + if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ + return WRC_Continue; + } + /* Fall through */ + case TK_IF_NULL_ROW: + testcase( pExpr->op==TK_IF_NULL_ROW ); + pWalker->eCode = 0; + return WRC_Abort; + case TK_VARIABLE: + if( pWalker->eCode==5 ){ + /* Silently convert bound parameters that appear inside of CREATE + ** statements into a NULL when parsing the CREATE statement text out + ** of the sqlite_master table */ + pExpr->op = TK_NULL; + }else if( pWalker->eCode==4 ){ + /* A bound parameter in a CREATE statement that originates from + ** sqlite3_prepare() causes an error */ + pWalker->eCode = 0; + return WRC_Abort; + } + /* Fall through */ + default: + testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */ + testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant 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; + memset(&w, 0, sizeof(w)); + w.eCode = initFlag; + w.xExprCallback = exprNodeIsConstant; + w.xSelectCallback = selectNodeIsConstant; + w.u.iCur = iCur; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + +/* +** Walk an expression tree. Return non-zero if the expression is constant +** and 0 if it involves variables or function calls. +** +** For the purposes of this function, a double-quoted string (ex: "abc") +** is considered a variable but a single-quoted string (ex: 'abc') is +** a constant. +*/ +SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ + return exprIsConst(p, 1, 0); +} + +/* +** Walk an expression tree. Return non-zero if the expression is constant +** that does no originate from the ON or USING clauses of a join. +** Return 0 if it involves variables or function calls or terms from +** an ON or USING clause. +*/ +SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ + return exprIsConst(p, 2, 0); +} + +/* +** Walk an expression tree. Return non-zero if the expression is constant +** for any single row of the table with cursor iCur. In other words, the +** expression must not refer to any non-deterministic function nor any +** table other than iCur. +*/ +SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){ + return exprIsConst(p, 3, iCur); +} + + +/* +** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy(). +*/ +static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ + ExprList *pGroupBy = pWalker->u.pGroupBy; + int i; + + /* Check if pExpr is identical to any GROUP BY term. If so, consider + ** it constant. */ + for(i=0; inExpr; i++){ + Expr *p = pGroupBy->a[i].pExpr; + if( sqlite3ExprCompare(pExpr, p, -1)<2 ){ + CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p); + if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){ + return WRC_Prune; + } + } + } + + /* Check if pExpr is a sub-select. If so, consider it variable. */ + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + pWalker->eCode = 0; + return WRC_Abort; + } + + return exprNodeIsConstant(pWalker, pExpr); +} + +/* +** Walk the expression tree passed as the first argument. Return non-zero +** if the expression consists entirely of constants or copies of terms +** in pGroupBy that sort with the BINARY collation sequence. +** +** This routine is used to determine if a term of the HAVING clause can +** be promoted into the WHERE clause. In order for such a promotion to work, +** the value of the HAVING clause term must be the same for all members of +** a "group". The requirement that the GROUP BY term must be BINARY +** assumes that no other collating sequence will have a finer-grained +** grouping than binary. In other words (A=B COLLATE binary) implies +** A=B in every other collating sequence. The requirement that the +** GROUP BY be BINARY is stricter than necessary. It would also work +** to promote HAVING clauses that use the same alternative collating +** sequence as the GROUP BY term, but that is much harder to check, +** alternative collating sequences are uncommon, and this is only an +** optimization, so we take the easy way out and simply require the +** GROUP BY to use the BINARY collating sequence. +*/ +SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){ + Walker w; + memset(&w, 0, sizeof(w)); + w.eCode = 1; + w.xExprCallback = exprNodeIsConstantOrGroupBy; + w.u.pGroupBy = pGroupBy; + w.pParse = pParse; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + +/* +** Walk an expression tree. Return non-zero if the expression is constant +** or a function call with constant arguments. Return and 0 if there +** are any variables. +** +** For the purposes of this function, a double-quoted string (ex: "abc") +** is considered a variable but a single-quoted string (ex: 'abc') is +** a constant. +*/ +SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ + assert( isInit==0 || isInit==1 ); + return exprIsConst(p, 4+isInit, 0); +} + +#ifdef SQLITE_ENABLE_CURSOR_HINTS +/* +** Walk an expression tree. Return 1 if the expression contains a +** subquery of some kind. Return 0 if there are no subqueries. +*/ +SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ + Walker w; + memset(&w, 0, sizeof(w)); + w.eCode = 1; + w.xExprCallback = sqlite3ExprWalkNoop; + w.xSelectCallback = selectNodeIsConstant; + sqlite3WalkExpr(&w, p); + return w.eCode==0; +} +#endif + +/* +** If the expression p codes a constant integer that is small enough +** to fit in a 32-bit integer, return 1 and put the value of the integer +** in *pValue. If the expression is not an integer or if it is too big +** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. +*/ +SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ + int rc = 0; + if( p==0 ) return 0; /* Can only happen following on OOM */ + + /* If an expression is an integer literal that fits in a signed 32-bit + ** integer, then the EP_IntValue flag will have already been set */ + assert( p->op!=TK_INTEGER || (p->flags & EP_IntValue)!=0 + || sqlite3GetInt32(p->u.zToken, &rc)==0 ); + + if( p->flags & EP_IntValue ){ + *pValue = p->u.iValue; + return 1; + } + switch( p->op ){ + case TK_UPLUS: { + rc = sqlite3ExprIsInteger(p->pLeft, pValue); + break; + } + case TK_UMINUS: { + int v; + if( sqlite3ExprIsInteger(p->pLeft, &v) ){ + assert( v!=(-2147483647-1) ); + *pValue = -v; + rc = 1; + } + break; + } + default: break; + } + return rc; +} + +/* +** Return FALSE if there is no chance that the expression can be NULL. +** +** If the expression might be NULL or if the expression is too complex +** to tell return TRUE. +** +** This routine is used as an optimization, to skip OP_IsNull opcodes +** when we know that a value cannot be NULL. Hence, a false positive +** (returning TRUE when in fact the expression can never be NULL) might +** be a small performance hit but is otherwise harmless. On the other +** hand, a false negative (returning FALSE when the result could be NULL) +** will likely result in an incorrect answer. So when in doubt, return +** TRUE. +*/ +SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ + u8 op; + while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } + op = p->op; + if( op==TK_REGISTER ) op = p->op2; + switch( op ){ + case TK_INTEGER: + case TK_STRING: + case TK_FLOAT: + case TK_BLOB: + return 0; + case TK_COLUMN: + assert( p->pTab!=0 ); + return ExprHasProperty(p, EP_CanBeNull) || + (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0); + default: + return 1; + } +} + +/* +** Return TRUE if the given expression is a constant which would be +** unchanged by OP_Affinity with the affinity given in the second +** argument. +** +** This routine is used to determine if the OP_Affinity operation +** can be omitted. When in doubt return FALSE. A false negative +** is harmless. A false positive, however, can result in the wrong +** answer. +*/ +SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){ + u8 op; + if( aff==SQLITE_AFF_BLOB ) return 1; + while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } + op = p->op; + if( op==TK_REGISTER ) op = p->op2; + switch( op ){ + case TK_INTEGER: { + return aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC; + } + case TK_FLOAT: { + return aff==SQLITE_AFF_REAL || aff==SQLITE_AFF_NUMERIC; + } + case TK_STRING: { + return aff==SQLITE_AFF_TEXT; + } + case TK_BLOB: { + return 1; + } + case TK_COLUMN: { + assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */ + return p->iColumn<0 + && (aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC); + } + default: { + return 0; + } + } +} + +/* +** Return TRUE if the given string is a row-id column name. +*/ +SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ + if( sqlite3StrICmp(z, "_ROWID_")==0 ) return 1; + if( sqlite3StrICmp(z, "ROWID")==0 ) return 1; + if( sqlite3StrICmp(z, "OID")==0 ) return 1; + return 0; +} + +/* +** pX is the RHS of an IN operator. If pX is a SELECT statement +** that can be simplified to a direct table access, then return +** a pointer to the SELECT statement. If pX is not a SELECT statement, +** or if the SELECT statement needs to be manifested into a transient +** table, then return NULL. +*/ +#ifndef SQLITE_OMIT_SUBQUERY +static Select *isCandidateForInOpt(Expr *pX){ + Select *p; + SrcList *pSrc; + ExprList *pEList; + Table *pTab; + int i; + if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */ + if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ + p = pX->x.pSelect; + if( p->pPrior ) return 0; /* Not a compound SELECT */ + if( p->selFlags & (SF_Distinct|SF_Aggregate) ){ + testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); + testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); + return 0; /* No DISTINCT keyword and no aggregate functions */ + } + assert( p->pGroupBy==0 ); /* Has no GROUP BY clause */ + if( p->pLimit ) return 0; /* Has no LIMIT clause */ + assert( p->pOffset==0 ); /* No LIMIT means no OFFSET */ + if( p->pWhere ) return 0; /* Has no WHERE clause */ + pSrc = p->pSrc; + assert( pSrc!=0 ); + if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ + if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ + pTab = pSrc->a[0].pTab; + assert( pTab!=0 ); + assert( pTab->pSelect==0 ); /* FROM clause is not a view */ + if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ + pEList = p->pEList; + assert( pEList!=0 ); + /* All SELECT results must be columns. */ + for(i=0; inExpr; i++){ + Expr *pRes = pEList->a[i].pExpr; + if( pRes->op!=TK_COLUMN ) return 0; + assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */ + } + return p; +} +#endif /* SQLITE_OMIT_SUBQUERY */ + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Generate code that checks the left-most column of index table iCur to see if +** it contains any NULL entries. Cause the register at regHasNull to be set +** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull +** to be set to NULL if iCur contains one or more NULL values. +*/ +static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ + int addr1; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull); + addr1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + VdbeComment((v, "first_entry_in(%d)", iCur)); + sqlite3VdbeJumpHere(v, addr1); +} +#endif + + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** The argument is an IN operator with a list (not a subquery) on the +** right-hand side. Return TRUE if that list is constant. +*/ +static int sqlite3InRhsIsConstant(Expr *pIn){ + Expr *pLHS; + int res; + assert( !ExprHasProperty(pIn, EP_xIsSelect) ); + pLHS = pIn->pLeft; + pIn->pLeft = 0; + res = sqlite3ExprIsConstant(pIn); + pIn->pLeft = pLHS; + return res; +} +#endif + +/* +** This function is used by the implementation of the IN (...) operator. +** The pX parameter is the expression on the RHS of the IN operator, which +** might be either a list of expressions or a subquery. +** +** The job of this routine is to find or create a b-tree object that can +** be used either to test for membership in the RHS set or to iterate through +** all members of the RHS set, skipping duplicates. +** +** A cursor is opened on the b-tree object that is the RHS of the IN operator +** and pX->iTable is set to the index of that cursor. +** +** The returned value of this function indicates the b-tree type, as follows: +** +** IN_INDEX_ROWID - The cursor was opened on a database table. +** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index. +** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. +** IN_INDEX_EPH - The cursor was opened on a specially created and +** populated epheremal table. +** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be +** implemented as a sequence of comparisons. +** +** An existing b-tree might be used if the RHS expression pX is a simple +** subquery such as: +** +** SELECT , ... FROM +** +** If the RHS of the IN operator is a list or a more complex subquery, then +** an ephemeral table might need to be generated from the RHS and then +** pX->iTable made to point to the ephemeral table instead of an +** existing table. +** +** The inFlags parameter must contain exactly one of the bits +** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains +** IN_INDEX_MEMBERSHIP, then the generated table will be used for a +** fast membership test. When the IN_INDEX_LOOP bit is set, the +** IN index will be used to loop over all values of the RHS of the +** IN operator. +** +** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate +** through the set members) then the b-tree must not contain duplicates. +** An epheremal table must be used unless the selected columns are guaranteed +** to be unique - either because it is an INTEGER PRIMARY KEY or due to +** a UNIQUE constraint or index. +** +** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used +** for fast set membership tests) then an epheremal table must +** be used unless is a single INTEGER PRIMARY KEY column or an +** index can be found with the specified as its left-most. +** +** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and +** if the RHS of the IN operator is a list (not a subquery) then this +** routine might decide that creating an ephemeral b-tree for membership +** testing is too expensive and return IN_INDEX_NOOP. In that case, the +** calling routine should implement the IN operator using a sequence +** of Eq or Ne comparison operations. +** +** When the b-tree is being used for membership tests, the calling function +** might need to know whether or not the RHS side of the IN operator +** contains a NULL. If prRhsHasNull is not a NULL pointer and +** if there is any chance that the (...) might contain a NULL value at +** runtime, then a register is allocated and the register number written +** to *prRhsHasNull. If there is no chance that the (...) contains a +** NULL value, then *prRhsHasNull is left unchanged. +** +** If a register is allocated and its location stored in *prRhsHasNull, then +** the value in that register will be NULL if the b-tree contains one or more +** NULL values, and it will be some non-NULL value if the b-tree contains no +** NULL values. +** +** If the aiMap parameter is not NULL, it must point to an array containing +** one element for each column returned by the SELECT statement on the RHS +** of the IN(...) operator. The i'th entry of the array is populated with the +** offset of the index column that matches the i'th column returned by the +** SELECT. For example, if the expression and selected index are: +** +** (?,?,?) IN (SELECT a, b, c FROM t1) +** CREATE INDEX i1 ON t1(b, c, a); +** +** then aiMap[] is populated with {2, 0, 1}. +*/ +#ifndef SQLITE_OMIT_SUBQUERY +SQLITE_PRIVATE int sqlite3FindInIndex( + Parse *pParse, /* Parsing context */ + Expr *pX, /* The right-hand side (RHS) of the IN operator */ + u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */ + int *prRhsHasNull, /* Register holding NULL status. See notes */ + int *aiMap /* Mapping from Index fields to RHS fields */ +){ + Select *p; /* SELECT to the right of IN operator */ + int eType = 0; /* Type of RHS table. IN_INDEX_* */ + int iTab = pParse->nTab++; /* Cursor of the RHS table */ + int mustBeUnique; /* True if RHS must be unique */ + Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ + + assert( pX->op==TK_IN ); + mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; + + /* If the RHS of this IN(...) operator is a SELECT, and if it matters + ** whether or not the SELECT result contains NULL values, check whether + ** or not NULL is actually possible (it may not be, for example, due + ** to NOT NULL constraints in the schema). If no NULL values are possible, + ** set prRhsHasNull to 0 before continuing. */ + if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){ + int i; + ExprList *pEList = pX->x.pSelect->pEList; + for(i=0; inExpr; i++){ + if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break; + } + if( i==pEList->nExpr ){ + prRhsHasNull = 0; + } + } + + /* Check to see if an existing table or index can be used to + ** satisfy the query. This is preferable to generating a new + ** ephemeral table. */ + if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){ + sqlite3 *db = pParse->db; /* Database connection */ + Table *pTab; /* Table
    . */ + i16 iDb; /* Database idx for pTab */ + ExprList *pEList = p->pEList; + int nExpr = pEList->nExpr; + + assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ + assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ + assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ + pTab = p->pSrc->a[0].pTab; + + /* Code an OP_Transaction and OP_TableLock for
    . */ + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + sqlite3CodeVerifySchema(pParse, iDb); + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + + assert(v); /* sqlite3GetVdbe() has always been previously called */ + if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){ + /* The "x IN (SELECT rowid FROM table)" case */ + int iAddr = sqlite3VdbeAddOp0(v, OP_Once); + VdbeCoverage(v); + + sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); + eType = IN_INDEX_ROWID; + + sqlite3VdbeJumpHere(v, iAddr); + }else{ + Index *pIdx; /* Iterator variable */ + int affinity_ok = 1; + int i; + + /* Check that the affinity that will be used to perform each + ** comparison is the same as the affinity of each column in table + ** on the RHS of the IN operator. If it not, it is not possible to + ** use any index of the RHS table. */ + for(i=0; ipLeft, i); + int iCol = pEList->a[i].pExpr->iColumn; + char idxaff = sqlite3TableColumnAffinity(pTab,iCol); /* RHS table */ + char cmpaff = sqlite3CompareAffinity(pLhs, idxaff); + testcase( cmpaff==SQLITE_AFF_BLOB ); + testcase( cmpaff==SQLITE_AFF_TEXT ); + switch( cmpaff ){ + case SQLITE_AFF_BLOB: + break; + case SQLITE_AFF_TEXT: + /* sqlite3CompareAffinity() only returns TEXT if one side or the + ** other has no affinity and the other side is TEXT. Hence, + ** the only way for cmpaff to be TEXT is for idxaff to be TEXT + ** and for the term on the LHS of the IN to have no affinity. */ + assert( idxaff==SQLITE_AFF_TEXT ); + break; + default: + affinity_ok = sqlite3IsNumericAffinity(idxaff); + } + } + + if( affinity_ok ){ + /* Search for an existing index that will work for this IN operator */ + for(pIdx=pTab->pIndex; pIdx && eType==0; pIdx=pIdx->pNext){ + Bitmask colUsed; /* Columns of the index used */ + Bitmask mCol; /* Mask for the current column */ + if( pIdx->nColumnnColumn==BMS-2 ); + testcase( pIdx->nColumn==BMS-1 ); + if( pIdx->nColumn>=BMS-1 ) continue; + if( mustBeUnique ){ + if( pIdx->nKeyCol>nExpr + ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx)) + ){ + continue; /* This index is not unique over the IN RHS columns */ + } + } + + colUsed = 0; /* Columns of index used so far */ + for(i=0; ipLeft, i); + Expr *pRhs = pEList->a[i].pExpr; + CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); + int j; + + assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); + for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; + assert( pIdx->azColl[j] ); + if( pReq!=0 && sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ){ + continue; + } + break; + } + if( j==nExpr ) break; + mCol = MASKBIT(j); + if( mCol & colUsed ) break; /* Each column used only once */ + colUsed |= mCol; + if( aiMap ) aiMap[i] = j; + } + + assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) ); + if( colUsed==(MASKBIT(nExpr)-1) ){ + /* If we reach this point, that means the index pIdx is usable */ + int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); +#ifndef SQLITE_OMIT_EXPLAIN + sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0, + sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName), + P4_DYNAMIC); +#endif + sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + VdbeComment((v, "%s", pIdx->zName)); + assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); + eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; + + if( prRhsHasNull ){ +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + i64 mask = (1<nMem; + if( nExpr==1 ){ + sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); + } + } + sqlite3VdbeJumpHere(v, iAddr); + } + } /* End loop over indexes */ + } /* End if( affinity_ok ) */ + } /* End if not an rowid index */ + } /* End attempt to optimize using an index */ + + /* If no preexisting index is available for the IN clause + ** and IN_INDEX_NOOP is an allowed reply + ** and the RHS of the IN operator is a list, not a subquery + ** and the RHS is not constant or has two or fewer terms, + ** then it is not worth creating an ephemeral table to evaluate + ** the IN operator so return IN_INDEX_NOOP. + */ + if( eType==0 + && (inFlags & IN_INDEX_NOOP_OK) + && !ExprHasProperty(pX, EP_xIsSelect) + && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) + ){ + eType = IN_INDEX_NOOP; + } + + if( eType==0 ){ + /* Could not find an existing table or index to use as the RHS b-tree. + ** We will have to generate an ephemeral table to do the job. + */ + u32 savedNQueryLoop = pParse->nQueryLoop; + int rMayHaveNull = 0; + eType = IN_INDEX_EPH; + if( inFlags & IN_INDEX_LOOP ){ + pParse->nQueryLoop = 0; + if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ + eType = IN_INDEX_ROWID; + } + }else if( prRhsHasNull ){ + *prRhsHasNull = rMayHaveNull = ++pParse->nMem; + } + sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); + pParse->nQueryLoop = savedNQueryLoop; + }else{ + pX->iTable = iTab; + } + + if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){ + int i, n; + n = sqlite3ExprVectorSize(pX->pLeft); + for(i=0; ipLeft; + int nVal = sqlite3ExprVectorSize(pLeft); + Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0; + char *zRet; + + assert( pExpr->op==TK_IN ); + zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); + if( zRet ){ + int i; + for(i=0; ipEList->a[i].pExpr, a); + }else{ + zRet[i] = a; + } + } + zRet[nVal] = '\0'; + } + return zRet; +} +#endif + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Load the Parse object passed as the first argument with an error +** message of the form: +** +** "sub-select returns N columns - expected M" +*/ +SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ + const char *zFmt = "sub-select returns %d columns - expected %d"; + sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); +} +#endif + +/* +** Expression pExpr is a vector that has been used in a context where +** it is not permitted. If pExpr is a sub-select vector, this routine +** loads the Parse object with a message of the form: +** +** "sub-select returns N columns - expected 1" +** +** Or, if it is a regular scalar vector: +** +** "row value misused" +*/ +SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ +#ifndef SQLITE_OMIT_SUBQUERY + if( pExpr->flags & EP_xIsSelect ){ + sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); + }else +#endif + { + sqlite3ErrorMsg(pParse, "row value misused"); + } +} + +/* +** Generate code for scalar subqueries used as a subquery expression, EXISTS, +** or IN operators. Examples: +** +** (SELECT a FROM b) -- subquery +** EXISTS (SELECT a FROM b) -- EXISTS subquery +** x IN (4,5,11) -- IN operator with list on right-hand side +** x IN (SELECT a FROM b) -- IN operator with subquery on the right +** +** The pExpr parameter describes the expression that contains the IN +** operator or subquery. +** +** If parameter isRowid is non-zero, then expression pExpr is guaranteed +** to be of the form " IN (?, ?, ?)", where is a reference +** to some integer key column of a table B-Tree. In this case, use an +** intkey B-Tree to store the set of IN(...) values instead of the usual +** (slower) variable length keys B-Tree. +** +** If rMayHaveNull is non-zero, that means that the operation is an IN +** (not a SELECT or EXISTS) and that the RHS might contains NULLs. +** All this routine does is initialize the register given by rMayHaveNull +** to NULL. Calling routines will take care of changing this register +** value to non-NULL if the RHS is NULL-free. +** +** For a SELECT or EXISTS operator, return the register that holds the +** result. For a multi-column SELECT, the result is stored in a contiguous +** array of registers and the return value is the register of the left-most +** result column. Return 0 for IN operators or if an error occurs. +*/ +#ifndef SQLITE_OMIT_SUBQUERY +SQLITE_PRIVATE int sqlite3CodeSubselect( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ + int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ + int isRowid /* If true, LHS of IN operator is a rowid */ +){ + int jmpIfDynamic = -1; /* One-time test address */ + int rReg = 0; /* Register storing resulting */ + Vdbe *v = sqlite3GetVdbe(pParse); + if( NEVER(v==0) ) return 0; + sqlite3ExprCachePush(pParse); + + /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it + ** is encountered if any of the following is true: + ** + ** * The right-hand side is a correlated subquery + ** * The right-hand side is an expression list containing variables + ** * We are inside a trigger + ** + ** If all of the above are false, then we can run this code just once + ** save the results, and reuse the same result on subsequent invocations. + */ + if( !ExprHasProperty(pExpr, EP_VarSelect) ){ + jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } + +#ifndef SQLITE_OMIT_EXPLAIN + if( pParse->explain==2 ){ + char *zMsg = sqlite3MPrintf(pParse->db, "EXECUTE %s%s SUBQUERY %d", + jmpIfDynamic>=0?"":"CORRELATED ", + pExpr->op==TK_IN?"LIST":"SCALAR", + pParse->iNextSelectId + ); + sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); + } +#endif + + switch( pExpr->op ){ + case TK_IN: { + int addr; /* Address of OP_OpenEphemeral instruction */ + Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ + KeyInfo *pKeyInfo = 0; /* Key information */ + int nVal; /* Size of vector pLeft */ + + nVal = sqlite3ExprVectorSize(pLeft); + assert( !isRowid || nVal==1 ); + + /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' + ** expression it is handled the same way. An ephemeral table is + ** filled with index keys representing the results from the + ** SELECT or the . + ** + ** If the 'x' expression is a column value, or the SELECT... + ** statement returns a column value, then the affinity of that + ** column is used to build the index keys. If both 'x' and the + ** SELECT... statement are columns, then numeric affinity is used + ** if either column has NUMERIC or INTEGER affinity. If neither + ** 'x' nor the SELECT... statement are columns, then numeric affinity + ** is used. + */ + pExpr->iTable = pParse->nTab++; + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, + pExpr->iTable, (isRowid?0:nVal)); + pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1); + + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + /* Case 1: expr IN (SELECT ...) + ** + ** Generate code to write the results of the select into the temporary + ** table allocated and opened above. + */ + Select *pSelect = pExpr->x.pSelect; + ExprList *pEList = pSelect->pEList; + + assert( !isRowid ); + /* If the LHS and RHS of the IN operator do not match, that + ** error will have been caught long before we reach this point. */ + if( ALWAYS(pEList->nExpr==nVal) ){ + SelectDest dest; + int i; + sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); + dest.zAffSdst = exprINAffinity(pParse, pExpr); + pSelect->iLimit = 0; + testcase( pSelect->selFlags & SF_Distinct ); + testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ + if( sqlite3Select(pParse, pSelect, &dest) ){ + sqlite3DbFree(pParse->db, dest.zAffSdst); + sqlite3KeyInfoUnref(pKeyInfo); + return 0; + } + sqlite3DbFree(pParse->db, dest.zAffSdst); + assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ + assert( pEList!=0 ); + assert( pEList->nExpr>0 ); + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( + pParse, p, pEList->a[i].pExpr + ); + } + } + }else if( ALWAYS(pExpr->x.pList!=0) ){ + /* Case 2: expr IN (exprlist) + ** + ** For each expression, build an index key from the evaluation and + ** store it in the temporary table. If is a column, then use + ** that columns affinity when building index keys. If is not + ** a column, use numeric affinity. + */ + char affinity; /* Affinity of the LHS of the IN */ + int i; + ExprList *pList = pExpr->x.pList; + struct ExprList_item *pItem; + int r1, r2, r3; + + affinity = sqlite3ExprAffinity(pLeft); + if( !affinity ){ + affinity = SQLITE_AFF_BLOB; + } + if( pKeyInfo ){ + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + } + + /* Loop through each expression in . */ + r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3GetTempReg(pParse); + if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2); + for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ + Expr *pE2 = pItem->pExpr; + int iValToIns; + + /* If the expression is not constant then we will need to + ** disable the test that was generated above that makes sure + ** this code only executes once. Because for a non-constant + ** expression we need to rerun this code each time. + */ + if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){ + sqlite3VdbeChangeToNoop(v, jmpIfDynamic); + jmpIfDynamic = -1; + } + + /* Evaluate the expression and insert it into the temp table */ + if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){ + sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns); + }else{ + r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); + if( isRowid ){ + sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, + sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); + }else{ + sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); + sqlite3ExprCacheAffinityChange(pParse, r3, 1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1); + } + } + } + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempReg(pParse, r2); + } + if( pKeyInfo ){ + sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); + } + break; + } + + case TK_EXISTS: + case TK_SELECT: + default: { + /* Case 3: (SELECT ... FROM ...) + ** or: EXISTS(SELECT ... FROM ...) + ** + ** For a SELECT, generate code to put the values for all columns of + ** the first row into an array of registers and return the index of + ** the first register. + ** + ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists) + ** into a register and return that register number. + ** + ** In both cases, the query is augmented with "LIMIT 1". Any + ** preexisting limit is discarded in place of the new LIMIT 1. + */ + Select *pSel; /* SELECT statement to encode */ + SelectDest dest; /* How to deal with SELECT result */ + int nReg; /* Registers to allocate */ + + testcase( pExpr->op==TK_EXISTS ); + testcase( pExpr->op==TK_SELECT ); + assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); + assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + + pSel = pExpr->x.pSelect; + nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; + sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); + pParse->nMem += nReg; + if( pExpr->op==TK_SELECT ){ + dest.eDest = SRT_Mem; + dest.iSdst = dest.iSDParm; + dest.nSdst = nReg; + sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); + VdbeComment((v, "Init subquery result")); + }else{ + dest.eDest = SRT_Exists; + sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm); + VdbeComment((v, "Init EXISTS result")); + } + sqlite3ExprDelete(pParse->db, pSel->pLimit); + pSel->pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER, + &sqlite3IntTokens[1], 0); + pSel->iLimit = 0; + pSel->selFlags &= ~SF_MultiValue; + if( sqlite3Select(pParse, pSel, &dest) ){ + return 0; + } + rReg = dest.iSDParm; + ExprSetVVAProperty(pExpr, EP_NoReduce); + break; + } + } + + if( rHasNullFlag ){ + sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); + } + + if( jmpIfDynamic>=0 ){ + sqlite3VdbeJumpHere(v, jmpIfDynamic); + } + sqlite3ExprCachePop(pParse); + + return rReg; +} +#endif /* SQLITE_OMIT_SUBQUERY */ + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Expr pIn is an IN(...) expression. This function checks that the +** sub-select on the RHS of the IN() operator has the same number of +** columns as the vector on the LHS. Or, if the RHS of the IN() is not +** a sub-query, that the LHS is a vector of size 1. +*/ +SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ + int nVector = sqlite3ExprVectorSize(pIn->pLeft); + if( (pIn->flags & EP_xIsSelect) ){ + if( nVector!=pIn->x.pSelect->pEList->nExpr ){ + sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); + return 1; + } + }else if( nVector!=1 ){ + sqlite3VectorErrorMsg(pParse, pIn->pLeft); + return 1; + } + return 0; +} +#endif + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Generate code for an IN expression. +** +** x IN (SELECT ...) +** x IN (value, value, ...) +** +** The left-hand side (LHS) is a scalar or vector expression. The +** right-hand side (RHS) is an array of zero or more scalar values, or a +** subquery. If the RHS is a subquery, the number of result columns must +** match the number of columns in the vector on the LHS. If the RHS is +** a list of values, the LHS must be a scalar. +** +** The IN operator is true if the LHS value is contained within the RHS. +** The result is false if the LHS is definitely not in the RHS. The +** result is NULL if the presence of the LHS in the RHS cannot be +** determined due to NULLs. +** +** This routine generates code that jumps to destIfFalse if the LHS is not +** contained within the RHS. If due to NULLs we cannot determine if the LHS +** is contained in the RHS then jump to destIfNull. If the LHS is contained +** within the RHS then fall through. +** +** See the separate in-operator.md documentation file in the canonical +** SQLite source tree for additional information. +*/ +static void sqlite3ExprCodeIN( + Parse *pParse, /* Parsing and code generating context */ + Expr *pExpr, /* The IN expression */ + int destIfFalse, /* Jump here if LHS is not contained in the RHS */ + int destIfNull /* Jump here if the results are unknown due to NULLs */ +){ + int rRhsHasNull = 0; /* Register that is true if RHS contains NULL values */ + int eType; /* Type of the RHS */ + int rLhs; /* Register(s) holding the LHS values */ + int rLhsOrig; /* LHS values prior to reordering by aiMap[] */ + Vdbe *v; /* Statement under construction */ + int *aiMap = 0; /* Map from vector field to index column */ + char *zAff = 0; /* Affinity string for comparisons */ + int nVector; /* Size of vectors for this IN operator */ + int iDummy; /* Dummy parameter to exprCodeVector() */ + Expr *pLeft; /* The LHS of the IN operator */ + int i; /* loop counter */ + int destStep2; /* Where to jump when NULLs seen in step 2 */ + int destStep6 = 0; /* Start of code for Step 6 */ + int addrTruthOp; /* Address of opcode that determines the IN is true */ + int destNotNull; /* Jump here if a comparison is not true in step 6 */ + int addrTop; /* Top of the step-6 loop */ + + pLeft = pExpr->pLeft; + if( sqlite3ExprCheckIN(pParse, pExpr) ) return; + zAff = exprINAffinity(pParse, pExpr); + nVector = sqlite3ExprVectorSize(pExpr->pLeft); + aiMap = (int*)sqlite3DbMallocZero( + pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1 + ); + if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; + + /* Attempt to compute the RHS. After this step, if anything other than + ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable + ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned, + ** the RHS has not yet been coded. */ + v = pParse->pVdbe; + assert( v!=0 ); /* OOM detected prior to this routine */ + VdbeNoopComment((v, "begin IN expr")); + eType = sqlite3FindInIndex(pParse, pExpr, + IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, + destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap); + + assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH + || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC + ); +#ifdef SQLITE_DEBUG + /* Confirm that aiMap[] contains nVector integer values between 0 and + ** nVector-1. */ + for(i=0; i from " IN (...)". If the LHS is a + ** vector, then it is stored in an array of nVector registers starting + ** at r1. + ** + ** sqlite3FindInIndex() might have reordered the fields of the LHS vector + ** so that the fields are in the same order as an existing index. The + ** aiMap[] array contains a mapping from the original LHS field order to + ** the field order that matches the RHS index. + */ + sqlite3ExprCachePush(pParse); + rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); + for(i=0; ix.pList; + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + int labelOk = sqlite3VdbeMakeLabel(v); + int r2, regToFree; + int regCkNull = 0; + int ii; + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + if( destIfNull!=destIfFalse ){ + regCkNull = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); + } + for(ii=0; iinExpr; ii++){ + r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); + if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){ + sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); + } + if( iinExpr-1 || destIfNull!=destIfFalse ){ + sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2, + (void*)pColl, P4_COLLSEQ); + VdbeCoverageIf(v, iinExpr-1); + VdbeCoverageIf(v, ii==pList->nExpr-1); + sqlite3VdbeChangeP5(v, zAff[0]); + }else{ + assert( destIfNull==destIfFalse ); + sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2, + (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL); + } + sqlite3ReleaseTempReg(pParse, regToFree); + } + if( regCkNull ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); + sqlite3VdbeGoto(v, destIfFalse); + } + sqlite3VdbeResolveLabel(v, labelOk); + sqlite3ReleaseTempReg(pParse, regCkNull); + goto sqlite3ExprCodeIN_finished; + } + + /* Step 2: Check to see if the LHS contains any NULL columns. If the + ** LHS does contain NULLs then the result must be either FALSE or NULL. + ** We will then skip the binary search of the RHS. + */ + if( destIfNull==destIfFalse ){ + destStep2 = destIfFalse; + }else{ + destStep2 = destStep6 = sqlite3VdbeMakeLabel(v); + } + for(i=0; ipLeft, i); + if( sqlite3ExprCanBeNull(p) ){ + sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); + VdbeCoverage(v); + } + } + + /* Step 3. The LHS is now known to be non-NULL. Do the binary search + ** of the RHS using the LHS as a probe. If found, the result is + ** true. + */ + if( eType==IN_INDEX_ROWID ){ + /* In this case, the RHS is the ROWID of table b-tree and so we also + ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4 + ** into a single opcode. */ + sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs); + VdbeCoverage(v); + addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ + }else{ + sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); + if( destIfFalse==destIfNull ){ + /* Combine Step 3 and Step 5 into a single opcode */ + sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, + rLhs, nVector); VdbeCoverage(v); + goto sqlite3ExprCodeIN_finished; + } + /* Ordinary Step 3, for the case where FALSE and NULL are distinct */ + addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, + rLhs, nVector); VdbeCoverage(v); + } + + /* Step 4. If the RHS is known to be non-NULL and we did not find + ** an match on the search above, then the result must be FALSE. + */ + if( rRhsHasNull && nVector==1 ){ + sqlite3VdbeAddOp2(v, OP_NotNull, rRhsHasNull, destIfFalse); + VdbeCoverage(v); + } + + /* Step 5. If we do not care about the difference between NULL and + ** FALSE, then just return false. + */ + if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse); + + /* Step 6: Loop through rows of the RHS. Compare each row to the LHS. + ** If any comparison is NULL, then the result is NULL. If all + ** comparisons are FALSE then the final result is FALSE. + ** + ** For a scalar LHS, it is sufficient to check just the first row + ** of the RHS. + */ + if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + VdbeCoverage(v); + if( nVector>1 ){ + destNotNull = sqlite3VdbeMakeLabel(v); + }else{ + /* For nVector==1, combine steps 6 and 7 by immediately returning + ** FALSE if the first comparison is not NULL */ + destNotNull = destIfFalse; + } + for(i=0; iiTable, i, r3); + sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, + (void*)pColl, P4_COLLSEQ); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, r3); + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); + if( nVector>1 ){ + sqlite3VdbeResolveLabel(v, destNotNull); + sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1); + VdbeCoverage(v); + + /* Step 7: If we reach this point, we know that the result must + ** be false. */ + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + } + + /* Jumps here in order to return true. */ + sqlite3VdbeJumpHere(v, addrTruthOp); + +sqlite3ExprCodeIN_finished: + if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); + sqlite3ExprCachePop(pParse); + VdbeComment((v, "end IN expr")); +sqlite3ExprCodeIN_oom_error: + sqlite3DbFree(pParse->db, aiMap); + sqlite3DbFree(pParse->db, zAff); +} +#endif /* SQLITE_OMIT_SUBQUERY */ + +#ifndef SQLITE_OMIT_FLOATING_POINT +/* +** Generate an instruction that will put the floating point +** value described by z[0..n-1] into register iMem. +** +** The z[] string will probably not be zero-terminated. But the +** z[n] character is guaranteed to be something that does not look +** like the continuation of the number. +*/ +static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ + if( ALWAYS(z!=0) ){ + double value; + sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); + assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ + if( negateFlag ) value = -value; + sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL); + } +} +#endif + + +/* +** Generate an instruction that will put the integer describe by +** text z[0..n-1] into register iMem. +** +** Expr.u.zToken is always UTF8 and zero-terminated. +*/ +static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ + Vdbe *v = pParse->pVdbe; + if( pExpr->flags & EP_IntValue ){ + int i = pExpr->u.iValue; + assert( i>=0 ); + if( negFlag ) i = -i; + sqlite3VdbeAddOp2(v, OP_Integer, i, iMem); + }else{ + int c; + i64 value; + const char *z = pExpr->u.zToken; + assert( z!=0 ); + c = sqlite3DecOrHexToI64(z, &value); + if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){ +#ifdef SQLITE_OMIT_FLOATING_POINT + sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); +#else +#ifndef SQLITE_OMIT_HEX_INTEGER + if( sqlite3_strnicmp(z,"0x",2)==0 ){ + sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z); + }else +#endif + { + codeReal(v, z, negFlag, iMem); + } +#endif + }else{ + if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } + sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); + } + } +} + +/* +** Erase column-cache entry number i +*/ +static void cacheEntryClear(Parse *pParse, int i){ + if( pParse->aColCache[i].tempReg ){ + if( pParse->nTempRegaTempReg) ){ + pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; + } + } + pParse->nColCache--; + if( inColCache ){ + pParse->aColCache[i] = pParse->aColCache[pParse->nColCache]; + } +} + + +/* +** Record in the column cache that a particular column from a +** particular table is stored in a particular register. +*/ +SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){ + int i; + int minLru; + int idxLru; + struct yColCache *p; + + /* Unless an error has occurred, register numbers are always positive. */ + assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed ); + assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */ + + /* The SQLITE_ColumnCache flag disables the column cache. This is used + ** for testing only - to verify that SQLite always gets the same answer + ** with and without the column cache. + */ + if( OptimizationDisabled(pParse->db, SQLITE_ColumnCache) ) return; + + /* First replace any existing entry. + ** + ** Actually, the way the column cache is currently used, we are guaranteed + ** that the object will never already be in cache. Verify this guarantee. + */ +#ifndef NDEBUG + for(i=0, p=pParse->aColCache; inColCache; i++, p++){ + assert( p->iTable!=iTab || p->iColumn!=iCol ); + } +#endif + + /* If the cache is already full, delete the least recently used entry */ + if( pParse->nColCache>=SQLITE_N_COLCACHE ){ + minLru = 0x7fffffff; + idxLru = -1; + for(i=0, p=pParse->aColCache; ilrulru; + } + } + p = &pParse->aColCache[idxLru]; + }else{ + p = &pParse->aColCache[pParse->nColCache++]; + } + + /* Add the new entry to the end of the cache */ + p->iLevel = pParse->iCacheLevel; + p->iTable = iTab; + p->iColumn = iCol; + p->iReg = iReg; + p->tempReg = 0; + p->lru = pParse->iCacheCnt++; +} + +/* +** Indicate that registers between iReg..iReg+nReg-1 are being overwritten. +** Purge the range of registers from the column cache. +*/ +SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){ + int i = 0; + while( inColCache ){ + struct yColCache *p = &pParse->aColCache[i]; + if( p->iReg >= iReg && p->iReg < iReg+nReg ){ + cacheEntryClear(pParse, i); + }else{ + i++; + } + } +} + +/* +** Remember the current column cache context. Any new entries added +** added to the column cache after this call are removed when the +** corresponding pop occurs. +*/ +SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){ + pParse->iCacheLevel++; +#ifdef SQLITE_DEBUG + if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ + printf("PUSH to %d\n", pParse->iCacheLevel); + } +#endif +} + +/* +** Remove from the column cache any entries that were added since the +** the previous sqlite3ExprCachePush operation. In other words, restore +** the cache to the state it was in prior the most recent Push. +*/ +SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ + int i = 0; + assert( pParse->iCacheLevel>=1 ); + pParse->iCacheLevel--; +#ifdef SQLITE_DEBUG + if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ + printf("POP to %d\n", pParse->iCacheLevel); + } +#endif + while( inColCache ){ + if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){ + cacheEntryClear(pParse, i); + }else{ + i++; + } + } +} + +/* +** When a cached column is reused, make sure that its register is +** no longer available as a temp register. ticket #3879: that same +** register might be in the cache in multiple places, so be sure to +** get them all. +*/ +static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){ + int i; + struct yColCache *p; + for(i=0, p=pParse->aColCache; inColCache; i++, p++){ + if( p->iReg==iReg ){ + p->tempReg = 0; + } + } +} + +/* Generate code that will load into register regOut a value that is +** appropriate for the iIdxCol-th column of index pIdx. +*/ +SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn( + Parse *pParse, /* The parsing context */ + Index *pIdx, /* The index whose column is to be loaded */ + int iTabCur, /* Cursor pointing to a table row */ + int iIdxCol, /* The column of the index to be loaded */ + int regOut /* Store the index column value in this register */ +){ + i16 iTabCol = pIdx->aiColumn[iIdxCol]; + if( iTabCol==XN_EXPR ){ + assert( pIdx->aColExpr ); + assert( pIdx->aColExpr->nExpr>iIdxCol ); + pParse->iSelfTab = iTabCur; + sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); + }else{ + sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, + iTabCol, regOut); + } +} + +/* +** Generate code to extract the value of the iCol-th column of a table. +*/ +SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( + Vdbe *v, /* The VDBE under construction */ + Table *pTab, /* The table containing the value */ + int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */ + int iCol, /* Index of the column to extract */ + int regOut /* Extract the value into this register */ +){ + if( pTab==0 ){ + sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut); + return; + } + if( iCol<0 || iCol==pTab->iPKey ){ + sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); + }else{ + int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; + int x = iCol; + if( !HasRowid(pTab) && !IsVirtual(pTab) ){ + x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); + } + sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); + } + if( iCol>=0 ){ + sqlite3ColumnDefault(v, pTab, iCol, regOut); + } +} + +/* +** Generate code that will extract the iColumn-th column from +** table pTab and store the column value in a register. +** +** An effort is made to store the column value in register iReg. This +** is not garanteeed for GetColumn() - the result can be stored in +** any register. But the result is guaranteed to land in register iReg +** for GetColumnToReg(). +** +** There must be an open cursor to pTab in iTable when this routine +** is called. If iColumn<0 then code is generated that extracts the rowid. +*/ +SQLITE_PRIVATE int sqlite3ExprCodeGetColumn( + Parse *pParse, /* Parsing and code generating context */ + Table *pTab, /* Description of the table we are reading from */ + int iColumn, /* Index of the table column */ + int iTable, /* The cursor pointing to the table */ + int iReg, /* Store results here */ + u8 p5 /* P5 value for OP_Column + FLAGS */ +){ + Vdbe *v = pParse->pVdbe; + int i; + struct yColCache *p; + + for(i=0, p=pParse->aColCache; inColCache; i++, p++){ + if( p->iTable==iTable && p->iColumn==iColumn ){ + p->lru = pParse->iCacheCnt++; + sqlite3ExprCachePinRegister(pParse, p->iReg); + return p->iReg; + } + } + assert( v!=0 ); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg); + if( p5 ){ + sqlite3VdbeChangeP5(v, p5); + }else{ + sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg); + } + return iReg; +} +SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg( + Parse *pParse, /* Parsing and code generating context */ + Table *pTab, /* Description of the table we are reading from */ + int iColumn, /* Index of the table column */ + int iTable, /* The cursor pointing to the table */ + int iReg /* Store results here */ +){ + int r1 = sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0); + if( r1!=iReg ) sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg); +} + + +/* +** Clear all column cache entries. +*/ +SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){ + int i; + +#ifdef SQLITE_DEBUG + if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ + printf("CLEAR\n"); + } +#endif + for(i=0; inColCache; i++){ + if( pParse->aColCache[i].tempReg + && pParse->nTempRegaTempReg) + ){ + pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; + } + } + pParse->nColCache = 0; +} + +/* +** Record the fact that an affinity change has occurred on iCount +** registers starting with iStart. +*/ +SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){ + sqlite3ExprCacheRemove(pParse, iStart, iCount); +} + +/* +** Generate code to move content from registers iFrom...iFrom+nReg-1 +** over to iTo..iTo+nReg-1. Keep the column cache up-to-date. +*/ +SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ + assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); + sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); + sqlite3ExprCacheRemove(pParse, iFrom, nReg); +} + +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) +/* +** Return true if any register in the range iFrom..iTo (inclusive) +** is used as part of the column cache. +** +** This routine is used within assert() and testcase() macros only +** and does not appear in a normal build. +*/ +static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ + int i; + struct yColCache *p; + for(i=0, p=pParse->aColCache; inColCache; i++, p++){ + int r = p->iReg; + if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/ + } + return 0; +} +#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */ + + +/* +** Convert a scalar expression node to a TK_REGISTER referencing +** register iReg. The caller must ensure that iReg already contains +** the correct value for the expression. +*/ +static void exprToRegister(Expr *p, int iReg){ + p->op2 = p->op; + p->op = TK_REGISTER; + p->iTable = iReg; + ExprClearProperty(p, EP_Skip); +} + +/* +** Evaluate an expression (either a vector or a scalar expression) and store +** the result in continguous temporary registers. Return the index of +** the first register used to store the result. +** +** If the returned result register is a temporary scalar, then also write +** that register number into *piFreeable. If the returned result register +** is not a temporary or if the expression is a vector set *piFreeable +** to 0. +*/ +static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ + int iResult; + int nResult = sqlite3ExprVectorSize(p); + if( nResult==1 ){ + iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable); + }else{ + *piFreeable = 0; + if( p->op==TK_SELECT ){ +#if SQLITE_OMIT_SUBQUERY + iResult = 0; +#else + iResult = sqlite3CodeSubselect(pParse, p, 0, 0); +#endif + }else{ + int i; + iResult = pParse->nMem+1; + pParse->nMem += nResult; + for(i=0; ix.pList->a[i].pExpr, i+iResult); + } + } + } + return iResult; +} + + +/* +** Generate code into the current Vdbe to evaluate the given +** expression. Attempt to store the results in register "target". +** Return the register where results are stored. +** +** With this routine, there is no guarantee that results will +** be stored in target. The result might be stored in some other +** register if it is convenient to do so. The calling function +** must check the return code and move the results to the desired +** register. +*/ +SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ + Vdbe *v = pParse->pVdbe; /* The VM under construction */ + int op; /* The opcode being coded */ + int inReg = target; /* Results stored in register inReg */ + int regFree1 = 0; /* If non-zero free this temporary register */ + int regFree2 = 0; /* If non-zero free this temporary register */ + int r1, r2; /* Various register numbers */ + Expr tempX; /* Temporary expression node */ + int p5 = 0; + + assert( target>0 && target<=pParse->nMem ); + if( v==0 ){ + assert( pParse->db->mallocFailed ); + return 0; + } + + if( pExpr==0 ){ + op = TK_NULL; + }else{ + op = pExpr->op; + } + switch( op ){ + case TK_AGG_COLUMN: { + AggInfo *pAggInfo = pExpr->pAggInfo; + struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; + if( !pAggInfo->directMode ){ + assert( pCol->iMem>0 ); + return pCol->iMem; + }else if( pAggInfo->useSortingIdx ){ + sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, + pCol->iSorterColumn, target); + return target; + } + /* Otherwise, fall thru into the TK_COLUMN case */ + } + case TK_COLUMN: { + int iTab = pExpr->iTable; + if( iTab<0 ){ + if( pParse->ckBase>0 ){ + /* Generating CHECK constraints or inserting into partial index */ + return pExpr->iColumn + pParse->ckBase; + }else{ + /* Coding an expression that is part of an index where column names + ** in the index refer to the table to which the index belongs */ + iTab = pParse->iSelfTab; + } + } + return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, + pExpr->iColumn, iTab, target, + pExpr->op2); + } + case TK_INTEGER: { + codeInteger(pParse, pExpr, 0, target); + return target; + } +#ifndef SQLITE_OMIT_FLOATING_POINT + case TK_FLOAT: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + codeReal(v, pExpr->u.zToken, 0, target); + return target; + } +#endif + case TK_STRING: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + sqlite3VdbeLoadString(v, target, pExpr->u.zToken); + return target; + } + case TK_NULL: { + sqlite3VdbeAddOp2(v, OP_Null, 0, target); + return target; + } +#ifndef SQLITE_OMIT_BLOB_LITERAL + case TK_BLOB: { + int n; + const char *z; + char *zBlob; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); + assert( pExpr->u.zToken[1]=='\'' ); + z = &pExpr->u.zToken[2]; + n = sqlite3Strlen30(z) - 1; + assert( z[n]=='\'' ); + zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n); + sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC); + return target; + } +#endif + case TK_VARIABLE: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + assert( pExpr->u.zToken!=0 ); + assert( pExpr->u.zToken[0]!=0 ); + sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); + if( pExpr->u.zToken[1]!=0 ){ + const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); + assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 ); + pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */ + sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); + } + return target; + } + case TK_REGISTER: { + return pExpr->iTable; + } +#ifndef SQLITE_OMIT_CAST + case TK_CAST: { + /* Expressions of the form: CAST(pLeft AS token) */ + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + if( inReg!=target ){ + sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); + inReg = target; + } + sqlite3VdbeAddOp2(v, OP_Cast, target, + sqlite3AffinityType(pExpr->u.zToken, 0)); + testcase( usedAsColumnCache(pParse, inReg, inReg) ); + sqlite3ExprCacheAffinityChange(pParse, inReg, 1); + return inReg; + } +#endif /* SQLITE_OMIT_CAST */ + case TK_IS: + case TK_ISNOT: + op = (op==TK_IS) ? TK_EQ : TK_NE; + p5 = SQLITE_NULLEQ; + /* fall-through */ + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_NE: + case TK_EQ: { + Expr *pLeft = pExpr->pLeft; + if( sqlite3ExprIsVector(pLeft) ){ + codeVectorCompare(pParse, pExpr, target, op, p5); + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + codeCompare(pParse, pLeft, pExpr->pRight, op, + r1, r2, inReg, SQLITE_STOREP2 | p5); + assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); + assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); + assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); + assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); + assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); + assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); + testcase( regFree1==0 ); + testcase( regFree2==0 ); + } + break; + } + case TK_AND: + case TK_OR: + case TK_PLUS: + case TK_STAR: + case TK_MINUS: + case TK_REM: + case TK_BITAND: + case TK_BITOR: + case TK_SLASH: + case TK_LSHIFT: + case TK_RSHIFT: + case TK_CONCAT: { + assert( TK_AND==OP_And ); testcase( op==TK_AND ); + assert( TK_OR==OP_Or ); testcase( op==TK_OR ); + assert( TK_PLUS==OP_Add ); testcase( op==TK_PLUS ); + assert( TK_MINUS==OP_Subtract ); testcase( op==TK_MINUS ); + assert( TK_REM==OP_Remainder ); testcase( op==TK_REM ); + assert( TK_BITAND==OP_BitAnd ); testcase( op==TK_BITAND ); + assert( TK_BITOR==OP_BitOr ); testcase( op==TK_BITOR ); + assert( TK_SLASH==OP_Divide ); testcase( op==TK_SLASH ); + assert( TK_LSHIFT==OP_ShiftLeft ); testcase( op==TK_LSHIFT ); + assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT ); + assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT ); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + sqlite3VdbeAddOp3(v, op, r2, r1, target); + testcase( regFree1==0 ); + testcase( regFree2==0 ); + break; + } + case TK_UMINUS: { + Expr *pLeft = pExpr->pLeft; + assert( pLeft ); + if( pLeft->op==TK_INTEGER ){ + codeInteger(pParse, pLeft, 1, target); + return target; +#ifndef SQLITE_OMIT_FLOATING_POINT + }else if( pLeft->op==TK_FLOAT ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + codeReal(v, pLeft->u.zToken, 1, target); + return target; +#endif + }else{ + tempX.op = TK_INTEGER; + tempX.flags = EP_IntValue|EP_TokenOnly; + tempX.u.iValue = 0; + r1 = sqlite3ExprCodeTemp(pParse, &tempX, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); + sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); + testcase( regFree2==0 ); + } + break; + } + case TK_BITNOT: + case TK_NOT: { + assert( TK_BITNOT==OP_BitNot ); testcase( op==TK_BITNOT ); + assert( TK_NOT==OP_Not ); testcase( op==TK_NOT ); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + testcase( regFree1==0 ); + sqlite3VdbeAddOp2(v, op, r1, inReg); + break; + } + case TK_ISNULL: + case TK_NOTNULL: { + int addr; + assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); + assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); + sqlite3VdbeAddOp2(v, OP_Integer, 1, target); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + testcase( regFree1==0 ); + addr = sqlite3VdbeAddOp1(v, op, r1); + VdbeCoverageIf(v, op==TK_ISNULL); + VdbeCoverageIf(v, op==TK_NOTNULL); + sqlite3VdbeAddOp2(v, OP_Integer, 0, target); + sqlite3VdbeJumpHere(v, addr); + break; + } + case TK_AGG_FUNCTION: { + AggInfo *pInfo = pExpr->pAggInfo; + if( pInfo==0 ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken); + }else{ + return pInfo->aFunc[pExpr->iAgg].iMem; + } + break; + } + case TK_FUNCTION: { + ExprList *pFarg; /* List of function arguments */ + int nFarg; /* Number of function arguments */ + FuncDef *pDef; /* The function definition object */ + const char *zId; /* The function name */ + u32 constMask = 0; /* Mask of function arguments that are constant */ + int i; /* Loop counter */ + sqlite3 *db = pParse->db; /* The database connection */ + u8 enc = ENC(db); /* The text encoding used by this database */ + CollSeq *pColl = 0; /* A collating sequence */ + + if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ + /* SQL functions can be expensive. So try to move constant functions + ** out of the inner loop, even if that means an extra OP_Copy. */ + return sqlite3ExprCodeAtInit(pParse, pExpr, -1); + } + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + if( ExprHasProperty(pExpr, EP_TokenOnly) ){ + pFarg = 0; + }else{ + pFarg = pExpr->x.pList; + } + nFarg = pFarg ? pFarg->nExpr : 0; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + zId = pExpr->u.zToken; + pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0); +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + if( pDef==0 && pParse->explain ){ + pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); + } +#endif + if( pDef==0 || pDef->xFinalize!=0 ){ + sqlite3ErrorMsg(pParse, "unknown function: %s()", zId); + break; + } + + /* Attempt a direct implementation of the built-in COALESCE() and + ** IFNULL() functions. This avoids unnecessary evaluation of + ** arguments past the first non-NULL argument. + */ + if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ + int endCoalesce = sqlite3VdbeMakeLabel(v); + assert( nFarg>=2 ); + sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); + for(i=1; ia[i].pExpr, target); + sqlite3ExprCachePop(pParse); + } + sqlite3VdbeResolveLabel(v, endCoalesce); + break; + } + + /* The UNLIKELY() function is a no-op. The result is the value + ** of the first argument. + */ + if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ + assert( nFarg>=1 ); + return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); + } + +#ifdef SQLITE_DEBUG + /* The AFFINITY() function evaluates to a string that describes + ** the type affinity of the argument. This is used for testing of + ** the SQLite type logic. + */ + if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){ + const char *azAff[] = { "blob", "text", "numeric", "integer", "real" }; + char aff; + assert( nFarg==1 ); + aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); + sqlite3VdbeLoadString(v, target, + aff ? azAff[aff-SQLITE_AFF_BLOB] : "none"); + return target; + } +#endif + + for(i=0; ia[i].pExpr) ){ + testcase( i==31 ); + constMask |= MASKBIT32(i); + } + if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){ + pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr); + } + } + if( pFarg ){ + if( constMask ){ + r1 = pParse->nMem+1; + pParse->nMem += nFarg; + }else{ + r1 = sqlite3GetTempRange(pParse, nFarg); + } + + /* For length() and typeof() functions with a column argument, + ** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG + ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data + ** loading. + */ + if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){ + u8 exprOp; + assert( nFarg==1 ); + assert( pFarg->a[0].pExpr!=0 ); + exprOp = pFarg->a[0].pExpr->op; + if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){ + assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG ); + assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG ); + testcase( pDef->funcFlags & OPFLAG_LENGTHARG ); + pFarg->a[0].pExpr->op2 = + pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); + } + } + + sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ + sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, + SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); + sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */ + }else{ + r1 = 0; + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + /* Possibly overload the function if the first argument is + ** a virtual table column. + ** + ** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the + ** second argument, not the first, as the argument to test to + ** see if it is a column in a virtual table. This is done because + ** the left operand of infix functions (the operand we want to + ** control overloading) ends up as the second argument to the + ** function. The expression "A glob B" is equivalent to + ** "glob(B,A). We want to use the A in "A glob B" to test + ** for function overloading. But we use the B term in "glob(B,A)". + */ + if( nFarg>=2 && (pExpr->flags & EP_InfixFunc) ){ + pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr); + }else if( nFarg>0 ){ + pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); + } +#endif + if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){ + if( !pColl ) pColl = db->pDfltColl; + sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); + } + sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target, + (char*)pDef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)nFarg); + if( nFarg && constMask==0 ){ + sqlite3ReleaseTempRange(pParse, r1, nFarg); + } + return target; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_EXISTS: + case TK_SELECT: { + int nCol; + testcase( op==TK_EXISTS ); + testcase( op==TK_SELECT ); + if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){ + sqlite3SubselectError(pParse, nCol, 1); + }else{ + return sqlite3CodeSubselect(pParse, pExpr, 0, 0); + } + break; + } + case TK_SELECT_COLUMN: { + int n; + if( pExpr->pLeft->iTable==0 ){ + pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0); + } + assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT ); + if( pExpr->iTable + && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft)) + ){ + sqlite3ErrorMsg(pParse, "%d columns assigned %d values", + pExpr->iTable, n); + } + return pExpr->pLeft->iTable + pExpr->iColumn; + } + case TK_IN: { + int destIfFalse = sqlite3VdbeMakeLabel(v); + int destIfNull = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp2(v, OP_Null, 0, target); + sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); + sqlite3VdbeAddOp2(v, OP_Integer, 1, target); + sqlite3VdbeResolveLabel(v, destIfFalse); + sqlite3VdbeAddOp2(v, OP_AddImm, target, 0); + sqlite3VdbeResolveLabel(v, destIfNull); + return target; + } +#endif /* SQLITE_OMIT_SUBQUERY */ + + + /* + ** x BETWEEN y AND z + ** + ** This is equivalent to + ** + ** x>=y AND x<=z + ** + ** X is stored in pExpr->pLeft. + ** Y is stored in pExpr->pList->a[0].pExpr. + ** Z is stored in pExpr->pList->a[1].pExpr. + */ + case TK_BETWEEN: { + exprCodeBetween(pParse, pExpr, target, 0, 0); + return target; + } + case TK_SPAN: + case TK_COLLATE: + case TK_UPLUS: { + return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + } + + case TK_TRIGGER: { + /* If the opcode is TK_TRIGGER, then the expression is a reference + ** to a column in the new.* or old.* pseudo-tables available to + ** trigger programs. In this case Expr.iTable is set to 1 for the + ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn + ** is set to the column of the pseudo-table to read, or to -1 to + ** read the rowid field. + ** + ** The expression is implemented using an OP_Param opcode. The p1 + ** parameter is set to 0 for an old.rowid reference, or to (i+1) + ** to reference another column of the old.* pseudo-table, where + ** i is the index of the column. For a new.rowid reference, p1 is + ** set to (n+1), where n is the number of columns in each pseudo-table. + ** For a reference to any other column in the new.* pseudo-table, p1 + ** is set to (n+2+i), where n and i are as defined previously. For + ** example, if the table on which triggers are being fired is + ** declared as: + ** + ** CREATE TABLE t1(a, b); + ** + ** Then p1 is interpreted as follows: + ** + ** p1==0 -> old.rowid p1==3 -> new.rowid + ** p1==1 -> old.a p1==4 -> new.a + ** p1==2 -> old.b p1==5 -> new.b + */ + Table *pTab = pExpr->pTab; + int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; + + assert( pExpr->iTable==0 || pExpr->iTable==1 ); + assert( pExpr->iColumn>=-1 && pExpr->iColumnnCol ); + assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey ); + assert( p1>=0 && p1<(pTab->nCol*2+2) ); + + sqlite3VdbeAddOp2(v, OP_Param, p1, target); + VdbeComment((v, "%s.%s -> $%d", + (pExpr->iTable ? "new" : "old"), + (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName), + target + )); + +#ifndef SQLITE_OMIT_FLOATING_POINT + /* If the column has REAL affinity, it may currently be stored as an + ** integer. Use OP_RealAffinity to make sure it is really real. + ** + ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to + ** floating point when extracting it from the record. */ + if( pExpr->iColumn>=0 + && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL + ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, target); + } +#endif + break; + } + + case TK_VECTOR: { + sqlite3ErrorMsg(pParse, "row value misused"); + break; + } + + case TK_IF_NULL_ROW: { + int addrINR; + addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); + sqlite3ExprCachePush(pParse); + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + sqlite3ExprCachePop(pParse); + sqlite3VdbeJumpHere(v, addrINR); + sqlite3VdbeChangeP3(v, addrINR, inReg); + break; + } + + /* + ** Form A: + ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END + ** + ** Form B: + ** CASE WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END + ** + ** Form A is can be transformed into the equivalent form B as follows: + ** CASE WHEN x=e1 THEN r1 WHEN x=e2 THEN r2 ... + ** WHEN x=eN THEN rN ELSE y END + ** + ** X (if it exists) is in pExpr->pLeft. + ** Y is in the last element of pExpr->x.pList if pExpr->x.pList->nExpr is + ** odd. The Y is also optional. If the number of elements in x.pList + ** is even, then Y is omitted and the "otherwise" result is NULL. + ** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1]. + ** + ** The result of the expression is the Ri for the first matching Ei, + ** or if there is no matching Ei, the ELSE term Y, or if there is + ** no ELSE term, NULL. + */ + default: assert( op==TK_CASE ); { + int endLabel; /* GOTO label for end of CASE stmt */ + int nextCase; /* GOTO label for next WHEN clause */ + int nExpr; /* 2x number of WHEN terms */ + int i; /* Loop counter */ + ExprList *pEList; /* List of WHEN terms */ + struct ExprList_item *aListelem; /* Array of WHEN terms */ + Expr opCompare; /* The X==Ei expression */ + Expr *pX; /* The X expression */ + Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ + VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; ) + + assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); + assert(pExpr->x.pList->nExpr > 0); + pEList = pExpr->x.pList; + aListelem = pEList->a; + nExpr = pEList->nExpr; + endLabel = sqlite3VdbeMakeLabel(v); + if( (pX = pExpr->pLeft)!=0 ){ + tempX = *pX; + testcase( pX->op==TK_COLUMN ); + exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1)); + testcase( regFree1==0 ); + memset(&opCompare, 0, sizeof(opCompare)); + opCompare.op = TK_EQ; + opCompare.pLeft = &tempX; + pTest = &opCompare; + /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001: + ** The value in regFree1 might get SCopy-ed into the file result. + ** So make sure that the regFree1 register is not reused for other + ** purposes and possibly overwritten. */ + regFree1 = 0; + } + for(i=0; iop==TK_COLUMN ); + sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); + testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); + sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); + sqlite3VdbeGoto(v, endLabel); + sqlite3ExprCachePop(pParse); + sqlite3VdbeResolveLabel(v, nextCase); + } + if( (nExpr&1)!=0 ){ + sqlite3ExprCachePush(pParse); + sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); + sqlite3ExprCachePop(pParse); + }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, target); + } + assert( pParse->db->mallocFailed || pParse->nErr>0 + || pParse->iCacheLevel==iCacheLevel ); + sqlite3VdbeResolveLabel(v, endLabel); + break; + } +#ifndef SQLITE_OMIT_TRIGGER + case TK_RAISE: { + assert( pExpr->affinity==OE_Rollback + || pExpr->affinity==OE_Abort + || pExpr->affinity==OE_Fail + || pExpr->affinity==OE_Ignore + ); + if( !pParse->pTriggerTab ){ + sqlite3ErrorMsg(pParse, + "RAISE() may only be used within a trigger-program"); + return 0; + } + if( pExpr->affinity==OE_Abort ){ + sqlite3MayAbort(pParse); + } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + if( pExpr->affinity==OE_Ignore ){ + sqlite3VdbeAddOp4( + v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); + VdbeCoverage(v); + }else{ + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER, + pExpr->affinity, pExpr->u.zToken, 0, 0); + } + + break; + } +#endif + } + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); + return inReg; +} + +/* +** Factor out the code of the given expression to initialization time. +** +** If regDest>=0 then the result is always stored in that register and the +** result is not reusable. If regDest<0 then this routine is free to +** store the value whereever it wants. The register where the expression +** is stored is returned. When regDest<0, two identical expressions will +** code to the same register. +*/ +SQLITE_PRIVATE int sqlite3ExprCodeAtInit( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* The expression to code when the VDBE initializes */ + int regDest /* Store the value in this register */ +){ + ExprList *p; + assert( ConstFactorOk(pParse) ); + p = pParse->pConstExpr; + if( regDest<0 && p ){ + struct ExprList_item *pItem; + int i; + for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ + if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){ + return pItem->u.iConstExprReg; + } + } + } + pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); + p = sqlite3ExprListAppend(pParse, p, pExpr); + if( p ){ + struct ExprList_item *pItem = &p->a[p->nExpr-1]; + pItem->reusable = regDest<0; + if( regDest<0 ) regDest = ++pParse->nMem; + pItem->u.iConstExprReg = regDest; + } + pParse->pConstExpr = p; + return regDest; +} + +/* +** Generate code to evaluate an expression and store the results +** into a register. Return the register number where the results +** are stored. +** +** If the register is a temporary register that can be deallocated, +** then write its number into *pReg. If the result register is not +** a temporary, then set *pReg to zero. +** +** If pExpr is a constant, then this routine might generate this +** code to fill the register in the initialization section of the +** VDBE program, in order to factor it out of the evaluation loop. +*/ +SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ + int r2; + pExpr = sqlite3ExprSkipCollate(pExpr); + if( ConstFactorOk(pParse) + && pExpr->op!=TK_REGISTER + && sqlite3ExprIsConstantNotJoin(pExpr) + ){ + *pReg = 0; + r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1); + }else{ + int r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); + if( r2==r1 ){ + *pReg = r1; + }else{ + sqlite3ReleaseTempReg(pParse, r1); + *pReg = 0; + } + } + return r2; +} + +/* +** Generate code that will evaluate expression pExpr and store the +** results in register target. The results are guaranteed to appear +** in register target. +*/ +SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ + int inReg; + + assert( target>0 && target<=pParse->nMem ); + if( pExpr && pExpr->op==TK_REGISTER ){ + sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target); + }else{ + inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); + assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); + if( inReg!=target && pParse->pVdbe ){ + sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target); + } + } +} + +/* +** Make a transient copy of expression pExpr and then code it using +** sqlite3ExprCode(). This routine works just like sqlite3ExprCode() +** except that the input expression is guaranteed to be unchanged. +*/ +SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){ + sqlite3 *db = pParse->db; + pExpr = sqlite3ExprDup(db, pExpr, 0); + if( !db->mallocFailed ) sqlite3ExprCode(pParse, pExpr, target); + sqlite3ExprDelete(db, pExpr); +} + +/* +** Generate code that will evaluate expression pExpr and store the +** results in register target. The results are guaranteed to appear +** in register target. If the expression is constant, then this routine +** might choose to code the expression at initialization time. +*/ +SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ + if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){ + sqlite3ExprCodeAtInit(pParse, pExpr, target); + }else{ + sqlite3ExprCode(pParse, pExpr, target); + } +} + +/* +** Generate code that evaluates the given expression and puts the result +** in register target. +** +** Also make a copy of the expression results into another "cache" register +** and modify the expression so that the next time it is evaluated, +** the result is a copy of the cache register. +** +** This routine is used for expressions that are used multiple +** times. They are evaluated once and the results of the expression +** are reused. +*/ +SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ + Vdbe *v = pParse->pVdbe; + int iMem; + + assert( target>0 ); + assert( pExpr->op!=TK_REGISTER ); + sqlite3ExprCode(pParse, pExpr, target); + iMem = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); + exprToRegister(pExpr, iMem); +} + +/* +** 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. +** +** The SQLITE_ECEL_DUP flag prevents the arguments from being +** filled using OP_SCopy. OP_Copy must be used instead. +** +** The SQLITE_ECEL_FACTOR argument allows constant arguments to be +** factored out into initialization code. +** +** 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. +*/ +SQLITE_PRIVATE int sqlite3ExprCodeExprList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* The expression list to be coded */ + int target, /* Where to write results */ + int srcReg, /* Source registers if SQLITE_ECEL_REF */ + u8 flags /* SQLITE_ECEL_* flags */ +){ + struct ExprList_item *pItem; + int i, j, n; + u8 copyOp = (flags & SQLITE_ECEL_DUP) ? OP_Copy : OP_SCopy; + Vdbe *v = pParse->pVdbe; + assert( pList!=0 ); + assert( target>0 ); + assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */ + n = pList->nExpr; + if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; + for(pItem=pList->a, i=0; ipExpr; + if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ + if( flags & SQLITE_ECEL_OMITREF ){ + i--; + n--; + }else{ + sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); + } + }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){ + sqlite3ExprCodeAtInit(pParse, pExpr, target+i); + }else{ + int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); + if( inReg!=target+i ){ + VdbeOp *pOp; + if( copyOp==OP_Copy + && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy + && pOp->p1+pOp->p3+1==inReg + && pOp->p2+pOp->p3+1==target+i + ){ + pOp->p3++; + }else{ + sqlite3VdbeAddOp2(v, copyOp, inReg, target+i); + } + } + } + } + return n; +} + +/* +** Generate code for a BETWEEN operator. +** +** x BETWEEN y AND z +** +** The above is equivalent to +** +** x>=y AND x<=z +** +** Code it as such, taking care to do the common subexpression +** elimination of x. +** +** The xJumpIf parameter determines details: +** +** NULL: Store the boolean result in reg[dest] +** sqlite3ExprIfTrue: Jump to dest if true +** sqlite3ExprIfFalse: Jump to dest if false +** +** The jumpIfNull parameter is ignored if xJumpIf is NULL. +*/ +static void exprCodeBetween( + Parse *pParse, /* Parsing and code generating context */ + Expr *pExpr, /* The BETWEEN expression */ + int dest, /* Jump destination or storage location */ + void (*xJump)(Parse*,Expr*,int,int), /* Action to take */ + int jumpIfNull /* Take the jump if the BETWEEN is NULL */ +){ + Expr exprAnd; /* The AND operator in x>=y AND x<=z */ + Expr compLeft; /* The x>=y term */ + Expr compRight; /* The x<=z term */ + Expr exprX; /* The x subexpression */ + int regFree1 = 0; /* Temporary use register */ + + + memset(&compLeft, 0, sizeof(Expr)); + memset(&compRight, 0, sizeof(Expr)); + memset(&exprAnd, 0, sizeof(Expr)); + + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + exprX = *pExpr->pLeft; + exprAnd.op = TK_AND; + exprAnd.pLeft = &compLeft; + exprAnd.pRight = &compRight; + compLeft.op = TK_GE; + compLeft.pLeft = &exprX; + compLeft.pRight = pExpr->x.pList->a[0].pExpr; + compRight.op = TK_LE; + compRight.pLeft = &exprX; + compRight.pRight = pExpr->x.pList->a[1].pExpr; + exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®Free1)); + if( xJump ){ + xJump(pParse, &exprAnd, dest, jumpIfNull); + }else{ + /* Mark the expression is being from the ON or USING clause of a join + ** so that the sqlite3ExprCodeTarget() routine will not attempt to move + ** it into the Parse.pConstExpr list. We should use a new bit for this, + ** for clarity, but we are out of bits in the Expr.flags field so we + ** have to reuse the EP_FromJoin bit. Bummer. */ + exprX.flags |= EP_FromJoin; + sqlite3ExprCodeTarget(pParse, &exprAnd, dest); + } + sqlite3ReleaseTempReg(pParse, regFree1); + + /* Ensure adequate test coverage */ + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1!=0 ); + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1!=0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1!=0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1==0 ); + testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1!=0 ); + testcase( xJump==0 ); +} + +/* +** Generate code for a boolean expression such that a jump is made +** to the label "dest" if the expression is true but execution +** continues straight thru if the expression is false. +** +** If the expression evaluates to NULL (neither true nor false), then +** take the jump if the jumpIfNull flag is SQLITE_JUMPIFNULL. +** +** This code depends on the fact that certain token values (ex: TK_EQ) +** are the same as opcode values (ex: OP_Eq) that implement the corresponding +** operation. Special comments in vdbe.c and the mkopcodeh.awk script in +** the make process cause these values to align. Assert()s in the code +** below verify that the numbers are aligned correctly. +*/ +SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ + Vdbe *v = pParse->pVdbe; + int op = 0; + int regFree1 = 0; + int regFree2 = 0; + int r1, r2; + + assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); + if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ + if( NEVER(pExpr==0) ) return; /* No way this can happen */ + op = pExpr->op; + switch( op ){ + case TK_AND: { + int d2 = sqlite3VdbeMakeLabel(v); + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprCachePush(pParse); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + sqlite3ExprCachePop(pParse); + break; + } + case TK_OR: { + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprCachePush(pParse); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3ExprCachePop(pParse); + break; + } + case TK_NOT: { + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + break; + } + case TK_IS: + case TK_ISNOT: + testcase( op==TK_IS ); + testcase( op==TK_ISNOT ); + op = (op==TK_IS) ? TK_EQ : TK_NE; + jumpIfNull = SQLITE_NULLEQ; + /* Fall thru */ + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_NE: + case TK_EQ: { + if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; + testcase( jumpIfNull==0 ); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + r1, r2, dest, jumpIfNull); + assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); + assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); + assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); + assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); + assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); + assert(TK_NE==OP_Ne); testcase(op==OP_Ne); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); + testcase( regFree1==0 ); + testcase( regFree2==0 ); + break; + } + case TK_ISNULL: + case TK_NOTNULL: { + assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); + assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + sqlite3VdbeAddOp2(v, op, r1, dest); + VdbeCoverageIf(v, op==TK_ISNULL); + VdbeCoverageIf(v, op==TK_NOTNULL); + testcase( regFree1==0 ); + break; + } + case TK_BETWEEN: { + testcase( jumpIfNull==0 ); + exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); + break; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_IN: { + int destIfFalse = sqlite3VdbeMakeLabel(v); + int destIfNull = jumpIfNull ? dest : destIfFalse; + sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); + sqlite3VdbeGoto(v, dest); + sqlite3VdbeResolveLabel(v, destIfFalse); + break; + } +#endif + default: { + default_expr: + if( exprAlwaysTrue(pExpr) ){ + sqlite3VdbeGoto(v, dest); + }else if( exprAlwaysFalse(pExpr) ){ + /* No-op */ + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); + sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); + VdbeCoverage(v); + testcase( regFree1==0 ); + testcase( jumpIfNull==0 ); + } + break; + } + } + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); +} + +/* +** Generate code for a boolean expression such that a jump is made +** to the label "dest" if the expression is false but execution +** continues straight thru if the expression is true. +** +** If the expression evaluates to NULL (neither true nor false) then +** jump if jumpIfNull is SQLITE_JUMPIFNULL or fall through if jumpIfNull +** is 0. +*/ +SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ + Vdbe *v = pParse->pVdbe; + int op = 0; + int regFree1 = 0; + int regFree2 = 0; + int r1, r2; + + assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); + if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ + if( pExpr==0 ) return; + + /* The value of pExpr->op and op are related as follows: + ** + ** pExpr->op op + ** --------- ---------- + ** TK_ISNULL OP_NotNull + ** TK_NOTNULL OP_IsNull + ** TK_NE OP_Eq + ** TK_EQ OP_Ne + ** TK_GT OP_Le + ** TK_LE OP_Gt + ** TK_GE OP_Lt + ** TK_LT OP_Ge + ** + ** For other values of pExpr->op, op is undefined and unused. + ** The value of TK_ and OP_ constants are arranged such that we + ** can compute the mapping above using the following expression. + ** Assert()s verify that the computation is correct. + */ + op = ((pExpr->op+(TK_ISNULL&1))^1)-(TK_ISNULL&1); + + /* Verify correct alignment of TK_ and OP_ constants + */ + assert( pExpr->op!=TK_ISNULL || op==OP_NotNull ); + assert( pExpr->op!=TK_NOTNULL || op==OP_IsNull ); + assert( pExpr->op!=TK_NE || op==OP_Eq ); + assert( pExpr->op!=TK_EQ || op==OP_Ne ); + assert( pExpr->op!=TK_LT || op==OP_Ge ); + assert( pExpr->op!=TK_LE || op==OP_Gt ); + assert( pExpr->op!=TK_GT || op==OP_Le ); + assert( pExpr->op!=TK_GE || op==OP_Lt ); + + switch( pExpr->op ){ + case TK_AND: { + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprCachePush(pParse); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3ExprCachePop(pParse); + break; + } + case TK_OR: { + int d2 = sqlite3VdbeMakeLabel(v); + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprCachePush(pParse); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + sqlite3ExprCachePop(pParse); + break; + } + case TK_NOT: { + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + break; + } + case TK_IS: + case TK_ISNOT: + testcase( pExpr->op==TK_IS ); + testcase( pExpr->op==TK_ISNOT ); + op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; + jumpIfNull = SQLITE_NULLEQ; + /* Fall thru */ + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_NE: + case TK_EQ: { + if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; + testcase( jumpIfNull==0 ); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, + r1, r2, dest, jumpIfNull); + assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); + assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); + assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); + assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); + assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ); + assert(TK_NE==OP_Ne); testcase(op==OP_Ne); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); + VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); + testcase( regFree1==0 ); + testcase( regFree2==0 ); + break; + } + case TK_ISNULL: + case TK_NOTNULL: { + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + sqlite3VdbeAddOp2(v, op, r1, dest); + testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); + testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); + testcase( regFree1==0 ); + break; + } + case TK_BETWEEN: { + testcase( jumpIfNull==0 ); + exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull); + break; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_IN: { + if( jumpIfNull ){ + sqlite3ExprCodeIN(pParse, pExpr, dest, dest); + }else{ + int destIfNull = sqlite3VdbeMakeLabel(v); + sqlite3ExprCodeIN(pParse, pExpr, dest, destIfNull); + sqlite3VdbeResolveLabel(v, destIfNull); + } + break; + } +#endif + default: { + default_expr: + if( exprAlwaysFalse(pExpr) ){ + sqlite3VdbeGoto(v, dest); + }else if( exprAlwaysTrue(pExpr) ){ + /* no-op */ + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); + sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); + VdbeCoverage(v); + testcase( regFree1==0 ); + testcase( jumpIfNull==0 ); + } + break; + } + } + sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ReleaseTempReg(pParse, regFree2); +} + +/* +** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before +** code generation, and that copy is deleted after code generation. This +** ensures that the original pExpr is unchanged. +*/ +SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){ + sqlite3 *db = pParse->db; + Expr *pCopy = sqlite3ExprDup(db, pExpr, 0); + if( db->mallocFailed==0 ){ + sqlite3ExprIfFalse(pParse, pCopy, dest, jumpIfNull); + } + sqlite3ExprDelete(db, pCopy); +} + + +/* +** Do a deep comparison of two expression trees. Return 0 if the two +** expressions are completely identical. Return 1 if they differ only +** by a COLLATE operator at the top level. Return 2 if there are differences +** other than the top-level COLLATE operator. +** +** If any subelement of pB has Expr.iTable==(-1) then it is allowed +** to compare equal to an equivalent element in pA with Expr.iTable==iTab. +** +** The pA side might be using TK_REGISTER. If that is the case and pB is +** not using TK_REGISTER but is otherwise equivalent, then still return 0. +** +** Sometimes this routine will return 2 even if the two expressions +** really are equivalent. If we cannot prove that the expressions are +** identical, we return 2 just to be safe. So if this routine +** returns 2, then you do not really know for certain if the two +** expressions are the same. But if you get a 0 or 1 return, then you +** can be sure the expressions are the same. In the places where +** this routine is used, it does not hurt to get an extra 2 - that +** just might result in some slightly slower code. But returning +** an incorrect 0 or 1 could lead to a malfunction. +*/ +SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ + u32 combinedFlags; + if( pA==0 || pB==0 ){ + return pB==pA ? 0 : 2; + } + combinedFlags = pA->flags | pB->flags; + if( combinedFlags & EP_IntValue ){ + if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){ + return 0; + } + return 2; + } + if( pA->op!=pB->op ){ + if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){ + return 1; + } + if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){ + return 1; + } + return 2; + } + if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ + if( pA->op==TK_FUNCTION ){ + if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; + }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ + return pA->op==TK_COLLATE ? 1 : 2; + } + } + if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; + if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ + if( combinedFlags & EP_xIsSelect ) return 2; + if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; + if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; + if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; + if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ + if( pA->iColumn!=pB->iColumn ) return 2; + if( pA->iTable!=pB->iTable + && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; + } + } + return 0; +} + +/* +** Compare two ExprList objects. Return 0 if they are identical and +** non-zero if they differ in any way. +** +** If any subelement of pB has Expr.iTable==(-1) then it is allowed +** to compare equal to an equivalent element in pA with Expr.iTable==iTab. +** +** This routine might return non-zero for equivalent ExprLists. The +** only consequence will be disabled optimizations. But this routine +** must never return 0 if the two ExprList objects are different, or +** a malfunction will result. +** +** Two NULL pointers are considered to be the same. But a NULL pointer +** always differs from a non-NULL pointer. +*/ +SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ + int i; + if( pA==0 && pB==0 ) return 0; + if( pA==0 || pB==0 ) return 1; + if( pA->nExpr!=pB->nExpr ) return 1; + for(i=0; inExpr; i++){ + Expr *pExprA = pA->a[i].pExpr; + Expr *pExprB = pB->a[i].pExpr; + if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; + if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1; + } + return 0; +} + +/* +** Like sqlite3ExprCompare() except COLLATE operators at the top-level +** are ignored. +*/ +SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ + return sqlite3ExprCompare( + sqlite3ExprSkipCollate(pA), + sqlite3ExprSkipCollate(pB), + iTab); +} + +/* +** Return true if we can prove the pE2 will always be true if pE1 is +** true. Return false if we cannot complete the proof or if pE2 might +** be false. Examples: +** +** pE1: x==5 pE2: x==5 Result: true +** pE1: x>0 pE2: x==5 Result: false +** pE1: x=21 pE2: x=21 OR y=43 Result: true +** pE1: x!=123 pE2: x IS NOT NULL Result: true +** pE1: x!=?1 pE2: x IS NOT NULL Result: true +** pE1: x IS NULL pE2: x IS NOT NULL Result: false +** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false +** +** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has +** Expr.iTable<0 then assume a table number given by iTab. +** +** When in doubt, return false. Returning true might give a performance +** improvement. Returning false might cause a performance reduction, but +** it will always give the correct answer and is hence always safe. +*/ +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){ + if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){ + return 1; + } + if( pE2->op==TK_OR + && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab) + || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) ) + ){ + return 1; + } + if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){ + Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); + testcase( pX!=pE1->pLeft ); + if( sqlite3ExprCompare(pX, pE2->pLeft, iTab)==0 ) return 1; + } + return 0; +} + +/* +** An instance of the following structure is used by the tree walker +** to determine if an expression can be evaluated by reference to the +** index only, without having to do a search for the corresponding +** table entry. The IdxCover.pIdx field is the index. IdxCover.iCur +** is the cursor for the table. +*/ +struct IdxCover { + Index *pIdx; /* The index to be tested for coverage */ + int iCur; /* Cursor number for the table corresponding to the index */ +}; + +/* +** Check to see if there are references to columns in table +** pWalker->u.pIdxCover->iCur can be satisfied using the index +** pWalker->u.pIdxCover->pIdx. +*/ +static int exprIdxCover(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN + && pExpr->iTable==pWalker->u.pIdxCover->iCur + && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 + ){ + pWalker->eCode = 1; + return WRC_Abort; + } + return WRC_Continue; +} + +/* +** Determine if an index pIdx on table with cursor iCur contains will +** the expression pExpr. Return true if the index does cover the +** expression and false if the pExpr expression references table columns +** that are not found in the index pIdx. +** +** An index covering an expression means that the expression can be +** evaluated using only the index and without having to lookup the +** corresponding table entry. +*/ +SQLITE_PRIVATE int sqlite3ExprCoveredByIndex( + Expr *pExpr, /* The index to be tested */ + int iCur, /* The cursor number for the corresponding table */ + Index *pIdx /* The index that might be used for coverage */ +){ + Walker w; + struct IdxCover xcov; + memset(&w, 0, sizeof(w)); + xcov.iCur = iCur; + xcov.pIdx = pIdx; + w.xExprCallback = exprIdxCover; + w.u.pIdxCover = &xcov; + sqlite3WalkExpr(&w, pExpr); + return !w.eCode; +} + + +/* +** An instance of the following structure is used by the tree walker +** to count references to table columns in the arguments of an +** aggregate function, in order to implement the +** sqlite3FunctionThisSrc() routine. +*/ +struct SrcCount { + SrcList *pSrc; /* One particular FROM clause in a nested query */ + int nThis; /* Number of references to columns in pSrcList */ + int nOther; /* Number of references to columns in other FROM clauses */ +}; + +/* +** Count the number of references to columns. +*/ +static int exprSrcCount(Walker *pWalker, Expr *pExpr){ + /* The NEVER() on the second term is because sqlite3FunctionUsesThisSrc() + ** is always called before sqlite3ExprAnalyzeAggregates() and so the + ** TK_COLUMNs have not yet been converted into TK_AGG_COLUMN. If + ** sqlite3FunctionUsesThisSrc() is used differently in the future, the + ** NEVER() will need to be removed. */ + if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){ + int i; + struct SrcCount *p = pWalker->u.pSrcCount; + SrcList *pSrc = p->pSrc; + int nSrc = pSrc ? pSrc->nSrc : 0; + for(i=0; iiTable==pSrc->a[i].iCursor ) break; + } + if( inThis++; + }else{ + p->nOther++; + } + } + return WRC_Continue; +} + +/* +** Determine if any of the arguments to the pExpr Function reference +** pSrcList. Return true if they do. Also return true if the function +** has no arguments or has only constant arguments. Return false if pExpr +** references columns but not columns of tables found in pSrcList. +*/ +SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){ + Walker w; + struct SrcCount cnt; + assert( pExpr->op==TK_AGG_FUNCTION ); + memset(&w, 0, sizeof(w)); + w.xExprCallback = exprSrcCount; + w.u.pSrcCount = &cnt; + cnt.pSrc = pSrcList; + cnt.nThis = 0; + cnt.nOther = 0; + sqlite3WalkExprList(&w, pExpr->x.pList); + return cnt.nThis>0 || cnt.nOther==0; +} + +/* +** Add a new element to the pAggInfo->aCol[] array. Return the index of +** the new element. Return a negative number if malloc fails. +*/ +static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ + int i; + pInfo->aCol = sqlite3ArrayAllocate( + db, + pInfo->aCol, + sizeof(pInfo->aCol[0]), + &pInfo->nColumn, + &i + ); + return i; +} + +/* +** Add a new element to the pAggInfo->aFunc[] array. Return the index of +** the new element. Return a negative number if malloc fails. +*/ +static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){ + int i; + pInfo->aFunc = sqlite3ArrayAllocate( + db, + pInfo->aFunc, + sizeof(pInfo->aFunc[0]), + &pInfo->nFunc, + &i + ); + return i; +} + +/* +** This is the xExprCallback for a tree walker. It is used to +** implement sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates +** for additional information. +*/ +static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ + int i; + NameContext *pNC = pWalker->u.pNC; + Parse *pParse = pNC->pParse; + SrcList *pSrcList = pNC->pSrcList; + AggInfo *pAggInfo = pNC->pAggInfo; + + switch( pExpr->op ){ + case TK_AGG_COLUMN: + case TK_COLUMN: { + testcase( pExpr->op==TK_AGG_COLUMN ); + testcase( pExpr->op==TK_COLUMN ); + /* Check to see if the column is in one of the tables in the FROM + ** clause of the aggregate query */ + if( ALWAYS(pSrcList!=0) ){ + struct SrcList_item *pItem = pSrcList->a; + for(i=0; inSrc; i++, pItem++){ + struct AggInfo_col *pCol; + assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); + if( pExpr->iTable==pItem->iCursor ){ + /* If we reach this point, it means that pExpr refers to a table + ** that is in the FROM clause of the aggregate query. + ** + ** Make an entry for the column in pAggInfo->aCol[] if there + ** is not an entry there already. + */ + int k; + pCol = pAggInfo->aCol; + for(k=0; knColumn; k++, pCol++){ + if( pCol->iTable==pExpr->iTable && + pCol->iColumn==pExpr->iColumn ){ + break; + } + } + if( (k>=pAggInfo->nColumn) + && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 + ){ + pCol = &pAggInfo->aCol[k]; + pCol->pTab = pExpr->pTab; + pCol->iTable = pExpr->iTable; + pCol->iColumn = pExpr->iColumn; + pCol->iMem = ++pParse->nMem; + pCol->iSorterColumn = -1; + pCol->pExpr = pExpr; + if( pAggInfo->pGroupBy ){ + int j, n; + ExprList *pGB = pAggInfo->pGroupBy; + struct ExprList_item *pTerm = pGB->a; + n = pGB->nExpr; + for(j=0; jpExpr; + if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable && + pE->iColumn==pExpr->iColumn ){ + pCol->iSorterColumn = j; + break; + } + } + } + if( pCol->iSorterColumn<0 ){ + pCol->iSorterColumn = pAggInfo->nSortingColumn++; + } + } + /* There is now an entry for pExpr in pAggInfo->aCol[] (either + ** because it was there before or because we just created it). + ** Convert the pExpr to be a TK_AGG_COLUMN referring to that + ** pAggInfo->aCol[] entry. + */ + ExprSetVVAProperty(pExpr, EP_NoReduce); + pExpr->pAggInfo = pAggInfo; + pExpr->op = TK_AGG_COLUMN; + pExpr->iAgg = (i16)k; + break; + } /* endif pExpr->iTable==pItem->iCursor */ + } /* end loop over pSrcList */ + } + return WRC_Prune; + } + case TK_AGG_FUNCTION: { + if( (pNC->ncFlags & NC_InAggFunc)==0 + && pWalker->walkerDepth==pExpr->op2 + ){ + /* Check to see if pExpr is a duplicate of another aggregate + ** function that is already in the pAggInfo structure + */ + struct AggInfo_func *pItem = pAggInfo->aFunc; + for(i=0; inFunc; i++, pItem++){ + if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){ + break; + } + } + if( i>=pAggInfo->nFunc ){ + /* pExpr is original. Make a new entry in pAggInfo->aFunc[] + */ + u8 enc = ENC(pParse->db); + i = addAggInfoFunc(pParse->db, pAggInfo); + if( i>=0 ){ + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + pItem = &pAggInfo->aFunc[i]; + pItem->pExpr = pExpr; + pItem->iMem = ++pParse->nMem; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pItem->pFunc = sqlite3FindFunction(pParse->db, + pExpr->u.zToken, + pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); + if( pExpr->flags & EP_Distinct ){ + pItem->iDistinct = pParse->nTab++; + }else{ + pItem->iDistinct = -1; + } + } + } + /* Make pExpr point to the appropriate pAggInfo->aFunc[] entry + */ + assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); + ExprSetVVAProperty(pExpr, EP_NoReduce); + pExpr->iAgg = (i16)i; + pExpr->pAggInfo = pAggInfo; + return WRC_Prune; + }else{ + return WRC_Continue; + } + } + } + return WRC_Continue; +} +static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pWalker); + UNUSED_PARAMETER(pSelect); + return WRC_Continue; +} + +/* +** Analyze the pExpr expression looking for aggregate functions and +** for variables that need to be added to AggInfo object that pNC->pAggInfo +** points to. Additional entries are made on the AggInfo object as +** necessary. +** +** This routine should only be called after the expression has been +** analyzed by sqlite3ResolveExprNames(). +*/ +SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = analyzeAggregate; + w.xSelectCallback = analyzeAggregatesInSelect; + w.u.pNC = pNC; + assert( pNC->pSrcList!=0 ); + sqlite3WalkExpr(&w, pExpr); +} + +/* +** Call sqlite3ExprAnalyzeAggregates() for every expression in an +** expression list. Return the number of errors. +** +** If an error is found, the analysis is cut short. +*/ +SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){ + struct ExprList_item *pItem; + int i; + if( pList ){ + for(pItem=pList->a, i=0; inExpr; i++, pItem++){ + sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr); + } + } +} + +/* +** Allocate a single new register for use to hold some intermediate result. +*/ +SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){ + if( pParse->nTempReg==0 ){ + return ++pParse->nMem; + } + return pParse->aTempReg[--pParse->nTempReg]; +} + +/* +** Deallocate a register, making available for reuse for some other +** purpose. +** +** If a register is currently being used by the column cache, then +** the deallocation is deferred until the column cache line that uses +** the register becomes stale. +*/ +SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ + if( iReg && pParse->nTempRegaTempReg) ){ + int i; + struct yColCache *p; + for(i=0, p=pParse->aColCache; inColCache; i++, p++){ + if( p->iReg==iReg ){ + p->tempReg = 1; + return; + } + } + pParse->aTempReg[pParse->nTempReg++] = iReg; + } +} + +/* +** Allocate or deallocate a block of nReg consecutive registers. +*/ +SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){ + int i, n; + if( nReg==1 ) return sqlite3GetTempReg(pParse); + i = pParse->iRangeReg; + n = pParse->nRangeReg; + if( nReg<=n ){ + assert( !usedAsColumnCache(pParse, i, i+n-1) ); + pParse->iRangeReg += nReg; + pParse->nRangeReg -= nReg; + }else{ + i = pParse->nMem+1; + pParse->nMem += nReg; + } + return i; +} +SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ + if( nReg==1 ){ + sqlite3ReleaseTempReg(pParse, iReg); + return; + } + sqlite3ExprCacheRemove(pParse, iReg, nReg); + if( nReg>pParse->nRangeReg ){ + pParse->nRangeReg = nReg; + pParse->iRangeReg = iReg; + } +} + +/* +** Mark all temporary registers as being unavailable for reuse. +*/ +SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){ + pParse->nTempReg = 0; + pParse->nRangeReg = 0; +} + +/* +** Validate that no temporary register falls within the range of +** iFirst..iLast, inclusive. This routine is only call from within assert() +** statements. +*/ +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ + int i; + if( pParse->nRangeReg>0 + && pParse->iRangeReg+pParse->nRangeRegiRangeReg>=iFirst + ){ + return 0; + } + for(i=0; inTempReg; i++){ + if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){ + return 0; + } + } + return 1; +} +#endif /* SQLITE_DEBUG */ + +/************** End of expr.c ************************************************/ +/************** Begin file alter.c *******************************************/ +/* +** 2005 February 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 C code routines that used to generate VDBE code +** that implements the ALTER TABLE command. +*/ +/* #include "sqliteInt.h" */ + +/* +** The code in this file only exists if we are not omitting the +** ALTER TABLE logic from the build. +*/ +#ifndef SQLITE_OMIT_ALTERTABLE + + +/* +** This function is used by SQL generated to implement the +** ALTER TABLE command. The first argument is the text of a CREATE TABLE or +** CREATE INDEX command. The second is a table name. The table name in +** the CREATE TABLE or CREATE INDEX statement is replaced with the third +** argument and the result returned. Examples: +** +** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') +** -> 'CREATE TABLE def(a, b, c)' +** +** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') +** -> 'CREATE INDEX i ON def(a, b, c)' +*/ +static void renameTableFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + unsigned char const *zSql = sqlite3_value_text(argv[0]); + unsigned char const *zTableName = sqlite3_value_text(argv[1]); + + int token; + Token tname; + unsigned char const *zCsr = zSql; + int len = 0; + char *zRet; + + sqlite3 *db = sqlite3_context_db_handle(context); + + UNUSED_PARAMETER(NotUsed); + + /* The principle used to locate the table name in the CREATE TABLE + ** statement is that the table name is the first non-space token that + ** is immediately followed by a TK_LP or TK_USING token. + */ + if( zSql ){ + do { + if( !*zCsr ){ + /* Ran out of input before finding an opening bracket. Return NULL. */ + return; + } + + /* Store the token that zCsr points to in tname. */ + tname.z = (char*)zCsr; + tname.n = len; + + /* Advance zCsr to the next token. Store that token type in 'token', + ** and its length in 'len' (to be used next iteration of this loop). + */ + do { + zCsr += len; + len = sqlite3GetToken(zCsr, &token); + } while( token==TK_SPACE ); + assert( len>0 ); + } while( token!=TK_LP && token!=TK_USING ); + + zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), + zSql, zTableName, tname.z+tname.n); + sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); + } +} + +/* +** This C function implements an SQL user function that is used by SQL code +** generated by the ALTER TABLE ... RENAME command to modify the definition +** of any foreign key constraints that use the table being renamed as the +** parent table. It is passed three arguments: +** +** 1) The complete text of the CREATE TABLE statement being modified, +** 2) The old name of the table being renamed, and +** 3) The new name of the table being renamed. +** +** It returns the new CREATE TABLE statement. For example: +** +** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3') +** -> 'CREATE TABLE t1(a REFERENCES t3)' +*/ +#ifndef SQLITE_OMIT_FOREIGN_KEY +static void renameParentFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + char *zOutput = 0; + char *zResult; + unsigned char const *zInput = sqlite3_value_text(argv[0]); + unsigned char const *zOld = sqlite3_value_text(argv[1]); + unsigned char const *zNew = sqlite3_value_text(argv[2]); + + unsigned const char *z; /* Pointer to token */ + int n; /* Length of token z */ + int token; /* Type of token */ + + UNUSED_PARAMETER(NotUsed); + if( zInput==0 || zOld==0 ) return; + for(z=zInput; *z; z=z+n){ + n = sqlite3GetToken(z, &token); + if( token==TK_REFERENCES ){ + char *zParent; + do { + z += n; + n = sqlite3GetToken(z, &token); + }while( token==TK_SPACE ); + + if( token==TK_ILLEGAL ) break; + zParent = sqlite3DbStrNDup(db, (const char *)z, n); + if( zParent==0 ) break; + sqlite3Dequote(zParent); + if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){ + char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"", + (zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew + ); + sqlite3DbFree(db, zOutput); + zOutput = zOut; + zInput = &z[n]; + } + sqlite3DbFree(db, zParent); + } + } + + zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput), + sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC); + sqlite3DbFree(db, zOutput); +} +#endif + +#ifndef SQLITE_OMIT_TRIGGER +/* This function is used by SQL generated to implement the +** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER +** statement. The second is a table name. The table name in the CREATE +** TRIGGER statement is replaced with the third argument and the result +** returned. This is analagous to renameTableFunc() above, except for CREATE +** TRIGGER, not CREATE INDEX and CREATE TABLE. +*/ +static void renameTriggerFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + unsigned char const *zSql = sqlite3_value_text(argv[0]); + unsigned char const *zTableName = sqlite3_value_text(argv[1]); + + int token; + Token tname; + int dist = 3; + unsigned char const *zCsr = zSql; + int len = 0; + char *zRet; + sqlite3 *db = sqlite3_context_db_handle(context); + + UNUSED_PARAMETER(NotUsed); + + /* The principle used to locate the table name in the CREATE TRIGGER + ** statement is that the table name is the first token that is immediately + ** preceded by either TK_ON or TK_DOT and immediately followed by one + ** of TK_WHEN, TK_BEGIN or TK_FOR. + */ + if( zSql ){ + do { + + if( !*zCsr ){ + /* Ran out of input before finding the table name. Return NULL. */ + return; + } + + /* Store the token that zCsr points to in tname. */ + tname.z = (char*)zCsr; + tname.n = len; + + /* Advance zCsr to the next token. Store that token type in 'token', + ** and its length in 'len' (to be used next iteration of this loop). + */ + do { + zCsr += len; + len = sqlite3GetToken(zCsr, &token); + }while( token==TK_SPACE ); + assert( len>0 ); + + /* Variable 'dist' stores the number of tokens read since the most + ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN + ** token is read and 'dist' equals 2, the condition stated above + ** to be met. + ** + ** Note that ON cannot be a database, table or column name, so + ** there is no need to worry about syntax like + ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc. + */ + dist++; + if( token==TK_DOT || token==TK_ON ){ + dist = 0; + } + } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) ); + + /* Variable tname now contains the token that is the old table-name + ** in the CREATE TRIGGER statement. + */ + zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), + zSql, zTableName, tname.z+tname.n); + sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); + } +} +#endif /* !SQLITE_OMIT_TRIGGER */ + +/* +** Register built-in functions used to help implement ALTER TABLE +*/ +SQLITE_PRIVATE void sqlite3AlterFunctions(void){ + static FuncDef aAlterTableFuncs[] = { + FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc), +#ifndef SQLITE_OMIT_TRIGGER + FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc), +#endif +#ifndef SQLITE_OMIT_FOREIGN_KEY + FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc), +#endif + }; + sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); +} + +/* +** This function is used to create the text of expressions of the form: +** +** name= OR name= OR ... +** +** If argument zWhere is NULL, then a pointer string containing the text +** "name=" is returned, where is the quoted version +** of the string passed as argument zConstant. The returned buffer is +** allocated using sqlite3DbMalloc(). It is the responsibility of the +** caller to ensure that it is eventually freed. +** +** If argument zWhere is not NULL, then the string returned is +** " OR name=", where is the contents of zWhere. +** In this case zWhere is passed to sqlite3DbFree() before returning. +** +*/ +static char *whereOrName(sqlite3 *db, char *zWhere, char *zConstant){ + char *zNew; + if( !zWhere ){ + zNew = sqlite3MPrintf(db, "name=%Q", zConstant); + }else{ + zNew = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, zConstant); + sqlite3DbFree(db, zWhere); + } + return zNew; +} + +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) +/* +** Generate the text of a WHERE expression which can be used to select all +** tables that have foreign key constraints that refer to table pTab (i.e. +** constraints for which pTab is the parent table) from the sqlite_master +** table. +*/ +static char *whereForeignKeys(Parse *pParse, Table *pTab){ + FKey *p; + char *zWhere = 0; + for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ + zWhere = whereOrName(pParse->db, zWhere, p->pFrom->zName); + } + return zWhere; +} +#endif + +/* +** Generate the text of a WHERE expression which can be used to select all +** temporary triggers on table pTab from the sqlite_temp_master table. If +** table pTab has no temporary triggers, or is itself stored in the +** temporary database, NULL is returned. +*/ +static char *whereTempTriggers(Parse *pParse, Table *pTab){ + Trigger *pTrig; + char *zWhere = 0; + const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */ + + /* If the table is not located in the temp-db (in which case NULL is + ** returned, loop through the tables list of triggers. For each trigger + ** that is not part of the temp-db schema, add a clause to the WHERE + ** expression being built up in zWhere. + */ + if( pTab->pSchema!=pTempSchema ){ + sqlite3 *db = pParse->db; + for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ + if( pTrig->pSchema==pTempSchema ){ + zWhere = whereOrName(db, zWhere, pTrig->zName); + } + } + } + if( zWhere ){ + char *zNew = sqlite3MPrintf(pParse->db, "type='trigger' AND (%s)", zWhere); + sqlite3DbFree(pParse->db, zWhere); + zWhere = zNew; + } + return zWhere; +} + +/* +** Generate code to drop and reload the internal representation of table +** pTab from the database, including triggers and temporary triggers. +** Argument zName is the name of the table in the database schema at +** the time the generated code is executed. This can be different from +** pTab->zName if this function is being called to code part of an +** "ALTER TABLE RENAME TO" statement. +*/ +static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ + Vdbe *v; + char *zWhere; + int iDb; /* Index of database containing pTab */ +#ifndef SQLITE_OMIT_TRIGGER + Trigger *pTrig; +#endif + + v = sqlite3GetVdbe(pParse); + if( NEVER(v==0) ) return; + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + assert( iDb>=0 ); + +#ifndef SQLITE_OMIT_TRIGGER + /* Drop any table triggers from the internal schema. */ + for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ + int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); + assert( iTrigDb==iDb || iTrigDb==1 ); + sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->zName, 0); + } +#endif + + /* Drop the table and index from the internal schema. */ + sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); + + /* Reload the table, index and permanent trigger schemas. */ + zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName); + if( !zWhere ) return; + sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); + +#ifndef SQLITE_OMIT_TRIGGER + /* Now, if the table is not stored in the temp database, reload any temp + ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. + */ + if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ + sqlite3VdbeAddParseSchemaOp(v, 1, zWhere); + } +#endif +} + +/* +** Parameter zName is the name of a table that is about to be altered +** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). +** If the table is a system table, this function leaves an error message +** in pParse->zErr (system tables may not be altered) and returns non-zero. +** +** Or, if zName is not a system table, zero is returned. +*/ +static int isSystemTable(Parse *pParse, const char *zName){ + if( sqlite3Strlen30(zName)>6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ + sqlite3ErrorMsg(pParse, "table %s may not be altered", zName); + return 1; + } + return 0; +} + +/* +** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" +** command. +*/ +SQLITE_PRIVATE void sqlite3AlterRenameTable( + Parse *pParse, /* Parser context. */ + SrcList *pSrc, /* The table to rename. */ + Token *pName /* The new table name. */ +){ + int iDb; /* Database that contains the table */ + char *zDb; /* Name of database iDb */ + Table *pTab; /* Table being renamed */ + char *zName = 0; /* NULL-terminated version of pName */ + sqlite3 *db = pParse->db; /* Database connection */ + int nTabName; /* Number of UTF-8 characters in zTabName */ + const char *zTabName; /* Original name of the table */ + Vdbe *v; +#ifndef SQLITE_OMIT_TRIGGER + 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 */ + + savedDbFlags = db->flags; + if( NEVER(db->mallocFailed) ) goto exit_rename_table; + assert( pSrc->nSrc==1 ); + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); + + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); + if( !pTab ) goto exit_rename_table; + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + zDb = db->aDb[iDb].zDbSName; + db->flags |= SQLITE_PreferBuiltin; + + /* Get a NULL terminated version of the new table name. */ + zName = sqlite3NameFromToken(db, pName); + if( !zName ) goto exit_rename_table; + + /* Check that a table or index named 'zName' does not already exist + ** in database iDb. If so, this is an error. + */ + if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){ + sqlite3ErrorMsg(pParse, + "there is already another table or index with this name: %s", zName); + goto exit_rename_table; + } + + /* Make sure it is not a system table being altered, or a reserved name + ** that the table is being renamed to. + */ + if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ + goto exit_rename_table; + } + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto + exit_rename_table; + } + +#ifndef SQLITE_OMIT_VIEW + if( pTab->pSelect ){ + sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); + goto exit_rename_table; + } +#endif + +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Invoke the authorization callback. */ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ + goto exit_rename_table; + } +#endif + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( sqlite3ViewGetColumnNames(pParse, pTab) ){ + goto exit_rename_table; + } + if( IsVirtual(pTab) ){ + pVTab = sqlite3GetVTable(db, pTab); + if( pVTab->pVtab->pModule->xRename==0 ){ + pVTab = 0; + } + } +#endif + + /* Begin a transaction for database iDb. + ** Then modify the schema cookie (since the ALTER TABLE modifies the + ** schema). Open a statement transaction if the table is a virtual + ** table. + */ + v = sqlite3GetVdbe(pParse); + if( v==0 ){ + goto exit_rename_table; + } + sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb); + sqlite3ChangeCookie(pParse, iDb); + + /* If this is a virtual table, invoke the xRename() function if + ** one is defined. The xRename() callback will modify the names + ** of any resources used by the v-table implementation (including other + ** SQLite tables) that are identified by the name of the virtual table. + */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( pVTab ){ + int i = ++pParse->nMem; + sqlite3VdbeLoadString(v, i, zName); + sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); + sqlite3MayAbort(pParse); + } +#endif + + /* figure out how many UTF-8 characters are in zName */ + zTabName = pTab->zName; + nTabName = sqlite3Utf8CharLen(zTabName, -1); + +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + if( db->flags&SQLITE_ForeignKeys ){ + /* If foreign-key support is enabled, rewrite the CREATE TABLE + ** statements corresponding to all child tables of foreign key constraints + ** for which the renamed table is the parent table. */ + if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){ + sqlite3NestedParse(pParse, + "UPDATE \"%w\".%s SET " + "sql = sqlite_rename_parent(sql, %Q, %Q) " + "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere); + sqlite3DbFree(db, zWhere); + } + } +#endif + + /* Modify the sqlite_master table to use the new table name. */ + sqlite3NestedParse(pParse, + "UPDATE %Q.%s SET " +#ifdef SQLITE_OMIT_TRIGGER + "sql = sqlite_rename_table(sql, %Q), " +#else + "sql = CASE " + "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" + "ELSE sqlite_rename_table(sql, %Q) END, " +#endif + "tbl_name = %Q, " + "name = CASE " + "WHEN type='table' THEN %Q " + "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " + "'sqlite_autoindex_' || %Q || substr(name,%d+18) " + "ELSE name END " + "WHERE tbl_name=%Q COLLATE nocase AND " + "(type='table' OR type='index' OR type='trigger');", + zDb, MASTER_NAME, zName, zName, zName, +#ifndef SQLITE_OMIT_TRIGGER + zName, +#endif + zName, nTabName, zTabName + ); + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* If the sqlite_sequence table exists in this database, then update + ** it with the new table name. + */ + if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ + sqlite3NestedParse(pParse, + "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q", + zDb, zName, pTab->zName); + } +#endif + +#ifndef SQLITE_OMIT_TRIGGER + /* If there are TEMP triggers on this table, modify the sqlite_temp_master + ** table. Don't do this if the table being ALTERed is itself located in + ** the temp database. + */ + if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ + sqlite3NestedParse(pParse, + "UPDATE sqlite_temp_master SET " + "sql = sqlite_rename_trigger(sql, %Q), " + "tbl_name = %Q " + "WHERE %s;", zName, zName, zWhere); + sqlite3DbFree(db, zWhere); + } +#endif + +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + if( db->flags&SQLITE_ForeignKeys ){ + FKey *p; + for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ + Table *pFrom = p->pFrom; + if( pFrom!=pTab ){ + reloadTableSchema(pParse, p->pFrom, pFrom->zName); + } + } + } +#endif + + /* Drop and reload the internal table schema. */ + reloadTableSchema(pParse, pTab, zName); + +exit_rename_table: + sqlite3SrcListDelete(db, pSrc); + sqlite3DbFree(db, zName); + db->flags = savedDbFlags; +} + +/* +** This function is called after an "ALTER TABLE ... ADD" statement +** has been parsed. Argument pColDef contains the text of the new +** column definition. +** +** The Table structure pParse->pNewTable was extended to include +** the new column during parsing. +*/ +SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ + Table *pNew; /* Copy of pParse->pNewTable */ + Table *pTab; /* Table being altered */ + int iDb; /* Database number */ + const char *zDb; /* Database name */ + const char *zTab; /* Table name */ + char *zCol; /* Null-terminated column definition */ + Column *pCol; /* The new column */ + Expr *pDflt; /* Default value for the new column */ + sqlite3 *db; /* The database connection; */ + Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ + int r1; /* Temporary registers */ + + db = pParse->db; + if( pParse->nErr || db->mallocFailed ) return; + assert( v!=0 ); + pNew = pParse->pNewTable; + assert( pNew ); + + assert( sqlite3BtreeHoldsAllMutexes(db) ); + iDb = sqlite3SchemaToIndex(db, pNew->pSchema); + zDb = db->aDb[iDb].zDbSName; + zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ + pCol = &pNew->aCol[pNew->nCol-1]; + pDflt = pCol->pDflt; + pTab = sqlite3FindTable(db, zTab, zDb); + assert( pTab ); + +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Invoke the authorization callback. */ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ + return; + } +#endif + + /* If the default value for the new column was specified with a + ** literal NULL, then set pDflt to 0. This simplifies checking + ** for an SQL NULL default below. + */ + assert( pDflt==0 || pDflt->op==TK_SPAN ); + if( pDflt && pDflt->pLeft->op==TK_NULL ){ + pDflt = 0; + } + + /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. + ** If there is a NOT NULL constraint, then the default value for the + ** column must not be NULL. + */ + if( pCol->colFlags & COLFLAG_PRIMKEY ){ + sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); + return; + } + if( pNew->pIndex ){ + sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); + return; + } + if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ + sqlite3ErrorMsg(pParse, + "Cannot add a REFERENCES column with non-NULL default value"); + return; + } + if( pCol->notNull && !pDflt ){ + sqlite3ErrorMsg(pParse, + "Cannot add a NOT NULL column with default value NULL"); + return; + } + + /* Ensure the default expression is something that sqlite3ValueFromExpr() + ** can handle (i.e. not CURRENT_TIME etc.) + */ + if( pDflt ){ + sqlite3_value *pVal = 0; + int rc; + rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc!=SQLITE_OK ){ + assert( db->mallocFailed == 1 ); + return; + } + if( !pVal ){ + sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); + return; + } + sqlite3ValueFree(pVal); + } + + /* Modify the CREATE TABLE statement. */ + zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); + if( zCol ){ + char *zEnd = &zCol[pColDef->n-1]; + int savedDbFlags = db->flags; + while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ + *zEnd-- = '\0'; + } + db->flags |= SQLITE_PreferBuiltin; + sqlite3NestedParse(pParse, + "UPDATE \"%w\".%s SET " + "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " + "WHERE type = 'table' AND name = %Q", + zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1, + zTab + ); + sqlite3DbFree(db, zCol); + db->flags = savedDbFlags; + } + + /* Make sure the schema version is at least 3. But do not upgrade + ** from less than 3 to 4, as that will corrupt any preexisting DESC + ** index. + */ + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); + sqlite3VdbeUsesBtree(v, iDb); + sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); + sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); + sqlite3ReleaseTempReg(pParse, r1); + + /* Reload the schema of the modified table. */ + reloadTableSchema(pParse, pTab, pTab->zName); +} + +/* +** This function is called by the parser after the table-name in +** an "ALTER TABLE ADD" statement is parsed. Argument +** pSrc is the full-name of the table being altered. +** +** This routine makes a (partial) copy of the Table structure +** for the table being altered and sets Parse.pNewTable to point +** to it. Routines called by the parser as the column definition +** is parsed (i.e. sqlite3AddColumn()) add the new Column data to +** the copy. The copy of the Table structure is deleted by tokenize.c +** after parsing is finished. +** +** Routine sqlite3AlterFinishAddColumn() will be called to complete +** coding the "ALTER TABLE ... ADD" statement. +*/ +SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ + Table *pNew; + Table *pTab; + Vdbe *v; + int iDb; + int i; + int nAlloc; + sqlite3 *db = pParse->db; + + /* Look up the table being altered. */ + assert( pParse->pNewTable==0 ); + assert( sqlite3BtreeHoldsAllMutexes(db) ); + if( db->mallocFailed ) goto exit_begin_add_column; + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); + if( !pTab ) goto exit_begin_add_column; + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "virtual tables may not be altered"); + goto exit_begin_add_column; + } +#endif + + /* Make sure this is not an attempt to ALTER a view. */ + if( pTab->pSelect ){ + sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); + goto exit_begin_add_column; + } + if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ + goto exit_begin_add_column; + } + + assert( pTab->addColOffset>0 ); + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + + /* Put a copy of the Table struct in Parse.pNewTable for the + ** sqlite3AddColumn() function and friends to modify. But modify + ** the name by adding an "sqlite_altertab_" prefix. By adding this + ** prefix, we insure that the name will not collide with an existing + ** table because user table are not allowed to have the "sqlite_" + ** prefix on their name. + */ + pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table)); + if( !pNew ) goto exit_begin_add_column; + pParse->pNewTable = pNew; + pNew->nTabRef = 1; + pNew->nCol = pTab->nCol; + assert( pNew->nCol>0 ); + nAlloc = (((pNew->nCol-1)/8)*8)+8; + assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); + pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); + pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName); + if( !pNew->aCol || !pNew->zName ){ + assert( db->mallocFailed ); + goto exit_begin_add_column; + } + memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); + for(i=0; inCol; i++){ + Column *pCol = &pNew->aCol[i]; + pCol->zName = sqlite3DbStrDup(db, pCol->zName); + pCol->zColl = 0; + pCol->pDflt = 0; + } + pNew->pSchema = db->aDb[iDb].pSchema; + pNew->addColOffset = pTab->addColOffset; + pNew->nTabRef = 1; + + /* Begin a transaction and increment the schema cookie. */ + sqlite3BeginWriteOperation(pParse, 0, iDb); + v = sqlite3GetVdbe(pParse); + if( !v ) goto exit_begin_add_column; + sqlite3ChangeCookie(pParse, iDb); + +exit_begin_add_column: + sqlite3SrcListDelete(db, pSrc); + return; +} +#endif /* SQLITE_ALTER_TABLE */ + +/************** End of alter.c ***********************************************/ +/************** Begin file analyze.c *****************************************/ +/* +** 2005-07-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 file contains code associated with the ANALYZE command. +** +** The ANALYZE command gather statistics about the content of tables +** and indices. These statistics are made available to the query planner +** to help it make better decisions about how to perform queries. +** +** The following system tables are or have been supported: +** +** CREATE TABLE sqlite_stat1(tbl, idx, stat); +** CREATE TABLE sqlite_stat2(tbl, idx, sampleno, sample); +** CREATE TABLE sqlite_stat3(tbl, idx, nEq, nLt, nDLt, sample); +** CREATE TABLE sqlite_stat4(tbl, idx, nEq, nLt, nDLt, sample); +** +** Additional tables might be added in future releases of SQLite. +** The sqlite_stat2 table is not created or used unless the SQLite version +** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled +** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated. +** The sqlite_stat2 table is superseded by sqlite_stat3, which is only +** created and used by SQLite versions 3.7.9 and later and with +** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3 +** is a superset of sqlite_stat2. The sqlite_stat4 is an enhanced +** version of sqlite_stat3 and is only available when compiled with +** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.1 and later. It is +** not possible to enable both STAT3 and STAT4 at the same time. If they +** are both enabled, then STAT4 takes precedence. +** +** For most applications, sqlite_stat1 provides all the statistics required +** for the query planner to make good choices. +** +** Format of sqlite_stat1: +** +** There is normally one row per index, with the index identified by the +** name in the idx column. The tbl column is the name of the table to +** which the index belongs. In each such row, the stat column will be +** a string consisting of a list of integers. The first integer in this +** list is the number of rows in the index. (This is the same as the +** number of rows in the table, except for partial indices.) The second +** integer is the average number of rows in the index that have the same +** value in the first column of the index. The third integer is the average +** number of rows in the index that have the same value for the first two +** columns. The N-th integer (for N>1) is the average number of rows in +** the index which have the same value for the first N-1 columns. For +** a K-column index, there will be K+1 integers in the stat column. If +** the index is unique, then the last integer will be 1. +** +** The list of integers in the stat column can optionally be followed +** by the keyword "unordered". The "unordered" keyword, if it is present, +** must be separated from the last integer by a single space. If the +** "unordered" keyword is present, then the query planner assumes that +** the index is unordered and will not use the index for a range query. +** +** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat +** column contains a single integer which is the (estimated) number of +** rows in the table identified by sqlite_stat1.tbl. +** +** Format of sqlite_stat2: +** +** The sqlite_stat2 is only created and is only used if SQLite is compiled +** with SQLITE_ENABLE_STAT2 and if the SQLite version number is between +** 3.6.18 and 3.7.8. The "stat2" table contains additional information +** about the distribution of keys within an index. The index is identified by +** the "idx" column and the "tbl" column is the name of the table to which +** the index belongs. There are usually 10 rows in the sqlite_stat2 +** table for each index. +** +** The sqlite_stat2 entries for an index that have sampleno between 0 and 9 +** inclusive are samples of the left-most key value in the index taken at +** evenly spaced points along the index. Let the number of samples be S +** (10 in the standard build) and let C be the number of rows in the index. +** Then the sampled rows are given by: +** +** rownumber = (i*C*2 + C)/(S*2) +** +** For i between 0 and S-1. Conceptually, the index space is divided into +** S uniform buckets and the samples are the middle row from each bucket. +** +** The format for sqlite_stat2 is recorded here for legacy reference. This +** version of SQLite does not support sqlite_stat2. It neither reads nor +** writes the sqlite_stat2 table. This version of SQLite only supports +** sqlite_stat3. +** +** Format for sqlite_stat3: +** +** The sqlite_stat3 format is a subset of sqlite_stat4. Hence, the +** sqlite_stat4 format will be described first. Further information +** about sqlite_stat3 follows the sqlite_stat4 description. +** +** Format for sqlite_stat4: +** +** As with sqlite_stat2, the sqlite_stat4 table contains histogram data +** to aid the query planner in choosing good indices based on the values +** that indexed columns are compared against in the WHERE clauses of +** queries. +** +** The sqlite_stat4 table contains multiple entries for each index. +** The idx column names the index and the tbl column is the table of the +** index. If the idx and tbl columns are the same, then the sample is +** of the INTEGER PRIMARY KEY. The sample column is a blob which is the +** binary encoding of a key from the index. The nEq column is a +** list of integers. The first integer is the approximate number +** of entries in the index whose left-most column exactly matches +** the left-most column of the sample. The second integer in nEq +** is the approximate number of entries in the index where the +** first two columns match the first two columns of the sample. +** And so forth. nLt is another list of integers that show the approximate +** number of entries that are strictly less than the sample. The first +** integer in nLt contains the number of entries in the index where the +** left-most column is less than the left-most column of the sample. +** The K-th integer in the nLt entry is the number of index entries +** where the first K columns are less than the first K columns of the +** sample. The nDLt column is like nLt except that it contains the +** number of distinct entries in the index that are less than the +** sample. +** +** There can be an arbitrary number of sqlite_stat4 entries per index. +** The ANALYZE command will typically generate sqlite_stat4 tables +** that contain between 10 and 40 samples which are distributed across +** the key space, though not uniformly, and which include samples with +** large nEq values. +** +** Format for sqlite_stat3 redux: +** +** The sqlite_stat3 table is like sqlite_stat4 except that it only +** looks at the left-most column of the index. The sqlite_stat3.sample +** column contains the actual value of the left-most column instead +** of a blob encoding of the complete index key as is found in +** sqlite_stat4.sample. The nEq, nLt, and nDLt entries of sqlite_stat3 +** all contain just a single integer which is the same as the first +** integer in the equivalent columns in sqlite_stat4. +*/ +#ifndef SQLITE_OMIT_ANALYZE +/* #include "sqliteInt.h" */ + +#if defined(SQLITE_ENABLE_STAT4) +# define IsStat4 1 +# define IsStat3 0 +#elif defined(SQLITE_ENABLE_STAT3) +# define IsStat4 0 +# define IsStat3 1 +#else +# define IsStat4 0 +# define IsStat3 0 +# undef SQLITE_STAT4_SAMPLES +# define SQLITE_STAT4_SAMPLES 1 +#endif +#define IsStat34 (IsStat3+IsStat4) /* 1 for STAT3 or STAT4. 0 otherwise */ + +/* +** This routine generates code that opens the sqlite_statN tables. +** The sqlite_stat1 table is always relevant. sqlite_stat2 is now +** obsolete. sqlite_stat3 and sqlite_stat4 are only opened when +** appropriate compile-time options are provided. +** +** If the sqlite_statN tables do not previously exist, it is created. +** +** Argument zWhere may be a pointer to a buffer containing a table name, +** or it may be a NULL pointer. If it is not NULL, then all entries in +** the sqlite_statN tables associated with the named table are deleted. +** If zWhere==0, then code is generated to delete all stat table entries. +*/ +static void openStatTable( + Parse *pParse, /* Parsing context */ + int iDb, /* The database we are looking in */ + int iStatCur, /* Open the sqlite_stat1 table on this cursor */ + const char *zWhere, /* Delete entries for this table or index */ + const char *zWhereType /* Either "tbl" or "idx" */ +){ + static const struct { + const char *zName; + const char *zCols; + } aTable[] = { + { "sqlite_stat1", "tbl,idx,stat" }, +#if defined(SQLITE_ENABLE_STAT4) + { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" }, + { "sqlite_stat3", 0 }, +#elif defined(SQLITE_ENABLE_STAT3) + { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" }, + { "sqlite_stat4", 0 }, +#else + { "sqlite_stat3", 0 }, + { "sqlite_stat4", 0 }, +#endif + }; + int i; + sqlite3 *db = pParse->db; + Db *pDb; + Vdbe *v = sqlite3GetVdbe(pParse); + int aRoot[ArraySize(aTable)]; + u8 aCreateTbl[ArraySize(aTable)]; + + if( v==0 ) return; + assert( sqlite3BtreeHoldsAllMutexes(db) ); + assert( sqlite3VdbeDb(v)==db ); + pDb = &db->aDb[iDb]; + + /* Create new statistic tables if they do not exist, or clear them + ** if they do already exist. + */ + for(i=0; izDbSName))==0 ){ + if( aTable[i].zCols ){ + /* The sqlite_statN table does not exist. Create it. Note that a + ** side-effect of the CREATE TABLE statement is to leave the rootpage + ** of the new table in register pParse->regRoot. This is important + ** because the OpenWrite opcode below will be needing it. */ + sqlite3NestedParse(pParse, + "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols + ); + aRoot[i] = pParse->regRoot; + aCreateTbl[i] = OPFLAG_P2ISREG; + } + }else{ + /* The table already exists. If zWhere is not NULL, delete all entries + ** associated with the table zWhere. If zWhere is NULL, delete the + ** entire contents of the table. */ + aRoot[i] = pStat->tnum; + aCreateTbl[i] = 0; + sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); + if( zWhere ){ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.%s WHERE %s=%Q", + pDb->zDbSName, zTab, zWhereType, zWhere + ); + }else{ + /* The sqlite_stat[134] table already exists. Delete all rows. */ + sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); + } + } + } + + /* Open the sqlite_stat[134] tables for writing. */ + for(i=0; aTable[i].zCols; i++){ + assert( inRowid ){ + sqlite3DbFree(db, p->u.aRowid); + p->nRowid = 0; + } +} +#endif + +/* Initialize the BLOB value of a ROWID +*/ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){ + assert( db!=0 ); + if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); + p->u.aRowid = sqlite3DbMallocRawNN(db, n); + if( p->u.aRowid ){ + p->nRowid = n; + memcpy(p->u.aRowid, pData, n); + }else{ + p->nRowid = 0; + } +} +#endif + +/* Initialize the INTEGER value of a ROWID. +*/ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){ + assert( db!=0 ); + if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); + p->nRowid = 0; + p->u.iRowid = iRowid; +} +#endif + + +/* +** Copy the contents of object (*pFrom) into (*pTo). +*/ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){ + pTo->isPSample = pFrom->isPSample; + pTo->iCol = pFrom->iCol; + pTo->iHash = pFrom->iHash; + memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol); + memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol); + memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol); + if( pFrom->nRowid ){ + sampleSetRowid(p->db, pTo, pFrom->nRowid, pFrom->u.aRowid); + }else{ + sampleSetRowidInt64(p->db, pTo, pFrom->u.iRowid); + } +} +#endif + +/* +** Reclaim all memory of a Stat4Accum structure. +*/ +static void stat4Destructor(void *pOld){ + Stat4Accum *p = (Stat4Accum*)pOld; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + int i; + for(i=0; inCol; i++) sampleClear(p->db, p->aBest+i); + for(i=0; imxSample; i++) sampleClear(p->db, p->a+i); + sampleClear(p->db, &p->current); +#endif + sqlite3DbFree(p->db, p); +} + +/* +** Implementation of the stat_init(N,K,C) SQL function. The three parameters +** are: +** N: The number of columns in the index including the rowid/pk (note 1) +** K: The number of columns in the index excluding the rowid/pk. +** C: The number of rows in the index (note 2) +** +** Note 1: In the special case of the covering index that implements a +** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the +** total number of columns in the table. +** +** Note 2: C is only used for STAT3 and STAT4. +** +** For indexes on ordinary rowid tables, N==K+1. But for indexes on +** WITHOUT ROWID tables, N=K+P where P is the number of columns in the +** PRIMARY KEY of the table. The covering index that implements the +** original WITHOUT ROWID table as N==K as a special case. +** +** This routine allocates the Stat4Accum object in heap memory. The return +** value is a pointer to the Stat4Accum object. The datatype of the +** return value is BLOB, but it is really just a pointer to the Stat4Accum +** object. +*/ +static void statInit( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Stat4Accum *p; + int nCol; /* Number of columns in index being sampled */ + int nKeyCol; /* Number of key columns */ + int nColUp; /* nCol rounded up for alignment */ + int n; /* Bytes of space to allocate */ + sqlite3 *db; /* Database connection */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + int mxSample = SQLITE_STAT4_SAMPLES; +#endif + + /* Decode the three function arguments */ + UNUSED_PARAMETER(argc); + nCol = sqlite3_value_int(argv[0]); + assert( nCol>0 ); + nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol; + nKeyCol = sqlite3_value_int(argv[1]); + assert( nKeyCol<=nCol ); + assert( nKeyCol>0 ); + + /* Allocate the space required for the Stat4Accum object */ + n = sizeof(*p) + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */ + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */ + + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */ + + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample) +#endif + ; + db = sqlite3_context_db_handle(context); + p = sqlite3DbMallocZero(db, n); + if( p==0 ){ + sqlite3_result_error_nomem(context); + return; + } + + p->db = db; + p->nRow = 0; + p->nCol = nCol; + p->nKeyCol = nKeyCol; + p->current.anDLt = (tRowcnt*)&p[1]; + p->current.anEq = &p->current.anDLt[nColUp]; + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + { + u8 *pSpace; /* Allocated space not yet assigned */ + int i; /* Used to iterate through p->aSample[] */ + + p->iGet = -1; + p->mxSample = mxSample; + p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1); + p->current.anLt = &p->current.anEq[nColUp]; + p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]); + + /* Set up the Stat4Accum.a[] and aBest[] arrays */ + p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; + p->aBest = &p->a[mxSample]; + pSpace = (u8*)(&p->a[mxSample+nCol]); + for(i=0; i<(mxSample+nCol); i++){ + p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); + p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); + p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); + } + assert( (pSpace - (u8*)p)==n ); + + for(i=0; iaBest[i].iCol = i; + } + } +#endif + + /* Return a pointer to the allocated object to the caller. Note that + ** only the pointer (the 2nd parameter) matters. The size of the object + ** (given by the 3rd parameter) is never used and can be any positive + ** value. */ + sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor); +} +static const FuncDef statInitFuncdef = { + 2+IsStat34, /* nArg */ + SQLITE_UTF8, /* funcFlags */ + 0, /* pUserData */ + 0, /* pNext */ + statInit, /* xSFunc */ + 0, /* xFinalize */ + "stat_init", /* zName */ + {0} +}; + +#ifdef SQLITE_ENABLE_STAT4 +/* +** pNew and pOld are both candidate non-periodic samples selected for +** the same column (pNew->iCol==pOld->iCol). Ignoring this column and +** considering only any trailing columns and the sample hash value, this +** function returns true if sample pNew is to be preferred over pOld. +** In other words, if we assume that the cardinalities of the selected +** column for pNew and pOld are equal, is pNew to be preferred over pOld. +** +** This function assumes that for each argument sample, the contents of +** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. +*/ +static int sampleIsBetterPost( + Stat4Accum *pAccum, + Stat4Sample *pNew, + Stat4Sample *pOld +){ + int nCol = pAccum->nCol; + int i; + assert( pNew->iCol==pOld->iCol ); + for(i=pNew->iCol+1; ianEq[i]>pOld->anEq[i] ) return 1; + if( pNew->anEq[i]anEq[i] ) return 0; + } + if( pNew->iHash>pOld->iHash ) return 1; + return 0; +} +#endif + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** Return true if pNew is to be preferred over pOld. +** +** This function assumes that for each argument sample, the contents of +** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. +*/ +static int sampleIsBetter( + Stat4Accum *pAccum, + Stat4Sample *pNew, + Stat4Sample *pOld +){ + tRowcnt nEqNew = pNew->anEq[pNew->iCol]; + tRowcnt nEqOld = pOld->anEq[pOld->iCol]; + + assert( pOld->isPSample==0 && pNew->isPSample==0 ); + assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) ); + + if( (nEqNew>nEqOld) ) return 1; +#ifdef SQLITE_ENABLE_STAT4 + if( nEqNew==nEqOld ){ + if( pNew->iColiCol ) return 1; + return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld)); + } + return 0; +#else + return (nEqNew==nEqOld && pNew->iHash>pOld->iHash); +#endif +} + +/* +** Copy the contents of sample *pNew into the p->a[] array. If necessary, +** remove the least desirable sample from p->a[] to make room. +*/ +static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ + Stat4Sample *pSample = 0; + int i; + + assert( IsStat4 || nEqZero==0 ); + +#ifdef SQLITE_ENABLE_STAT4 + /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0 + ** values in the anEq[] array of any sample in Stat4Accum.a[]. In + ** other words, if nMaxEqZero is n, then it is guaranteed that there + ** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */ + if( nEqZero>p->nMaxEqZero ){ + p->nMaxEqZero = nEqZero; + } + if( pNew->isPSample==0 ){ + Stat4Sample *pUpgrade = 0; + assert( pNew->anEq[pNew->iCol]>0 ); + + /* This sample is being added because the prefix that ends in column + ** iCol occurs many times in the table. However, if we have already + ** added a sample that shares this prefix, there is no need to add + ** this one. Instead, upgrade the priority of the highest priority + ** existing sample that shares this prefix. */ + for(i=p->nSample-1; i>=0; i--){ + Stat4Sample *pOld = &p->a[i]; + if( pOld->anEq[pNew->iCol]==0 ){ + if( pOld->isPSample ) return; + assert( pOld->iCol>pNew->iCol ); + assert( sampleIsBetter(p, pNew, pOld) ); + if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){ + pUpgrade = pOld; + } + } + } + if( pUpgrade ){ + pUpgrade->iCol = pNew->iCol; + pUpgrade->anEq[pUpgrade->iCol] = pNew->anEq[pUpgrade->iCol]; + goto find_new_min; + } + } +#endif + + /* If necessary, remove sample iMin to make room for the new sample. */ + if( p->nSample>=p->mxSample ){ + Stat4Sample *pMin = &p->a[p->iMin]; + tRowcnt *anEq = pMin->anEq; + tRowcnt *anLt = pMin->anLt; + tRowcnt *anDLt = pMin->anDLt; + sampleClear(p->db, pMin); + memmove(pMin, &pMin[1], sizeof(p->a[0])*(p->nSample-p->iMin-1)); + pSample = &p->a[p->nSample-1]; + pSample->nRowid = 0; + pSample->anEq = anEq; + pSample->anDLt = anDLt; + pSample->anLt = anLt; + p->nSample = p->mxSample-1; + } + + /* The "rows less-than" for the rowid column must be greater than that + ** for the last sample in the p->a[] array. Otherwise, the samples would + ** be out of order. */ +#ifdef SQLITE_ENABLE_STAT4 + assert( p->nSample==0 + || pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] ); +#endif + + /* Insert the new sample */ + pSample = &p->a[p->nSample]; + sampleCopy(p, pSample, pNew); + p->nSample++; + + /* Zero the first nEqZero entries in the anEq[] array. */ + memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero); + +#ifdef SQLITE_ENABLE_STAT4 + find_new_min: +#endif + if( p->nSample>=p->mxSample ){ + int iMin = -1; + for(i=0; imxSample; i++){ + if( p->a[i].isPSample ) continue; + if( iMin<0 || sampleIsBetter(p, &p->a[iMin], &p->a[i]) ){ + iMin = i; + } + } + assert( iMin>=0 ); + p->iMin = iMin; + } +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + +/* +** Field iChng of the index being scanned has changed. So at this point +** p->current contains a sample that reflects the previous row of the +** index. The value of anEq[iChng] and subsequent anEq[] elements are +** correct at this point. +*/ +static void samplePushPrevious(Stat4Accum *p, int iChng){ +#ifdef SQLITE_ENABLE_STAT4 + int i; + + /* Check if any samples from the aBest[] array should be pushed + ** into IndexSample.a[] at this point. */ + for(i=(p->nCol-2); i>=iChng; i--){ + Stat4Sample *pBest = &p->aBest[i]; + pBest->anEq[i] = p->current.anEq[i]; + if( p->nSamplemxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){ + sampleInsert(p, pBest, i); + } + } + + /* Check that no sample contains an anEq[] entry with an index of + ** p->nMaxEqZero or greater set to zero. */ + for(i=p->nSample-1; i>=0; i--){ + int j; + for(j=p->nMaxEqZero; jnCol; j++) assert( p->a[i].anEq[j]>0 ); + } + + /* Update the anEq[] fields of any samples already collected. */ + if( iChngnMaxEqZero ){ + for(i=p->nSample-1; i>=0; i--){ + int j; + for(j=iChng; jnCol; j++){ + if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; + } + } + p->nMaxEqZero = iChng; + } +#endif + +#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4) + if( iChng==0 ){ + tRowcnt nLt = p->current.anLt[0]; + tRowcnt nEq = p->current.anEq[0]; + + /* Check if this is to be a periodic sample. If so, add it. */ + if( (nLt/p->nPSample)!=(nLt+nEq)/p->nPSample ){ + p->current.isPSample = 1; + sampleInsert(p, &p->current, 0); + p->current.isPSample = 0; + }else + + /* Or if it is a non-periodic sample. Add it in this case too. */ + if( p->nSamplemxSample + || sampleIsBetter(p, &p->current, &p->a[p->iMin]) + ){ + sampleInsert(p, &p->current, 0); + } + } +#endif + +#ifndef SQLITE_ENABLE_STAT3_OR_STAT4 + UNUSED_PARAMETER( p ); + UNUSED_PARAMETER( iChng ); +#endif +} + +/* +** Implementation of the stat_push SQL function: stat_push(P,C,R) +** Arguments: +** +** P Pointer to the Stat4Accum object created by stat_init() +** C Index of left-most column to differ from previous row +** R Rowid for the current row. Might be a key record for +** WITHOUT ROWID tables. +** +** This SQL function always returns NULL. It's purpose it to accumulate +** statistical data and/or samples in the Stat4Accum object about the +** index being analyzed. The stat_get() SQL function will later be used to +** extract relevant information for constructing the sqlite_statN tables. +** +** The R parameter is only used for STAT3 and STAT4 +*/ +static void statPush( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int i; + + /* The three function arguments */ + Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]); + int iChng = sqlite3_value_int(argv[1]); + + UNUSED_PARAMETER( argc ); + UNUSED_PARAMETER( context ); + assert( p->nCol>0 ); + assert( iChngnCol ); + + if( p->nRow==0 ){ + /* This is the first call to this function. Do initialization. */ + for(i=0; inCol; i++) p->current.anEq[i] = 1; + }else{ + /* Second and subsequent calls get processed here */ + samplePushPrevious(p, iChng); + + /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply + ** to the current row of the index. */ + for(i=0; icurrent.anEq[i]++; + } + for(i=iChng; inCol; i++){ + p->current.anDLt[i]++; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + p->current.anLt[i] += p->current.anEq[i]; +#endif + p->current.anEq[i] = 1; + } + } + p->nRow++; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){ + sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2])); + }else{ + sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]), + sqlite3_value_blob(argv[2])); + } + p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345; +#endif + +#ifdef SQLITE_ENABLE_STAT4 + { + tRowcnt nLt = p->current.anLt[p->nCol-1]; + + /* Check if this is to be a periodic sample. If so, add it. */ + if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){ + p->current.isPSample = 1; + p->current.iCol = 0; + sampleInsert(p, &p->current, p->nCol-1); + p->current.isPSample = 0; + } + + /* Update the aBest[] array. */ + for(i=0; i<(p->nCol-1); i++){ + p->current.iCol = i; + if( i>=iChng || sampleIsBetterPost(p, &p->current, &p->aBest[i]) ){ + sampleCopy(p, &p->aBest[i], &p->current); + } + } + } +#endif +} +static const FuncDef statPushFuncdef = { + 2+IsStat34, /* nArg */ + SQLITE_UTF8, /* funcFlags */ + 0, /* pUserData */ + 0, /* pNext */ + statPush, /* xSFunc */ + 0, /* xFinalize */ + "stat_push", /* zName */ + {0} +}; + +#define STAT_GET_STAT1 0 /* "stat" column of stat1 table */ +#define STAT_GET_ROWID 1 /* "rowid" column of stat[34] entry */ +#define STAT_GET_NEQ 2 /* "neq" column of stat[34] entry */ +#define STAT_GET_NLT 3 /* "nlt" column of stat[34] entry */ +#define STAT_GET_NDLT 4 /* "ndlt" column of stat[34] entry */ + +/* +** Implementation of the stat_get(P,J) SQL function. This routine is +** used to query statistical information that has been gathered into +** the Stat4Accum object by prior calls to stat_push(). The P parameter +** has type BLOB but it is really just a pointer to the Stat4Accum object. +** The content to returned is determined by the parameter J +** which is one of the STAT_GET_xxxx values defined above. +** +** The stat_get(P,J) function is not available to generic SQL. It is +** inserted as part of a manually constructed bytecode program. (See +** the callStatGet() routine below.) It is guaranteed that the P +** parameter will always be a poiner to a Stat4Accum object, never a +** NULL. +** +** If neither STAT3 nor STAT4 are enabled, then J is always +** STAT_GET_STAT1 and is hence omitted and this routine becomes +** a one-parameter function, stat_get(P), that always returns the +** stat1 table entry information. +*/ +static void statGet( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + /* STAT3 and STAT4 have a parameter on this routine. */ + int eCall = sqlite3_value_int(argv[1]); + assert( argc==2 ); + assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ + || eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT + || eCall==STAT_GET_NDLT + ); + if( eCall==STAT_GET_STAT1 ) +#else + assert( argc==1 ); +#endif + { + /* Return the value to store in the "stat" column of the sqlite_stat1 + ** table for this index. + ** + ** The value is a string composed of a list of integers describing + ** the index. The first integer in the list is the total number of + ** entries in the index. There is one additional integer in the list + ** for each indexed column. This additional integer is an estimate of + ** the number of rows matched by a stabbing query on the index using + ** a key with the corresponding number of fields. In other words, + ** if the index is on columns (a,b) and the sqlite_stat1 value is + ** "100 10 2", then SQLite estimates that: + ** + ** * the index contains 100 rows, + ** * "WHERE a=?" matches 10 rows, and + ** * "WHERE a=? AND b=?" matches 2 rows. + ** + ** If D is the count of distinct values and K is the total number of + ** rows, then each estimate is computed as: + ** + ** I = (K+D-1)/D + */ + char *z; + int i; + + char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 ); + if( zRet==0 ){ + sqlite3_result_error_nomem(context); + return; + } + + sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow); + z = zRet + sqlite3Strlen30(zRet); + for(i=0; inKeyCol; i++){ + u64 nDistinct = p->current.anDLt[i] + 1; + u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; + sqlite3_snprintf(24, z, " %llu", iVal); + z += sqlite3Strlen30(z); + assert( p->current.anEq[i] ); + } + assert( z[0]=='\0' && z>zRet ); + + sqlite3_result_text(context, zRet, -1, sqlite3_free); + } +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + else if( eCall==STAT_GET_ROWID ){ + if( p->iGet<0 ){ + samplePushPrevious(p, 0); + p->iGet = 0; + } + if( p->iGetnSample ){ + Stat4Sample *pS = p->a + p->iGet; + if( pS->nRowid==0 ){ + sqlite3_result_int64(context, pS->u.iRowid); + }else{ + sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid, + SQLITE_TRANSIENT); + } + } + }else{ + tRowcnt *aCnt = 0; + + assert( p->iGetnSample ); + switch( eCall ){ + case STAT_GET_NEQ: aCnt = p->a[p->iGet].anEq; break; + case STAT_GET_NLT: aCnt = p->a[p->iGet].anLt; break; + default: { + aCnt = p->a[p->iGet].anDLt; + p->iGet++; + break; + } + } + + if( IsStat3 ){ + sqlite3_result_int64(context, (i64)aCnt[0]); + }else{ + char *zRet = sqlite3MallocZero(p->nCol * 25); + if( zRet==0 ){ + sqlite3_result_error_nomem(context); + }else{ + int i; + char *z = zRet; + for(i=0; inCol; i++){ + sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]); + z += sqlite3Strlen30(z); + } + assert( z[0]=='\0' && z>zRet ); + z[-1] = '\0'; + sqlite3_result_text(context, zRet, -1, sqlite3_free); + } + } + } +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#ifndef SQLITE_DEBUG + UNUSED_PARAMETER( argc ); +#endif +} +static const FuncDef statGetFuncdef = { + 1+IsStat34, /* nArg */ + SQLITE_UTF8, /* funcFlags */ + 0, /* pUserData */ + 0, /* pNext */ + statGet, /* xSFunc */ + 0, /* xFinalize */ + "stat_get", /* zName */ + {0} +}; + +static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){ + assert( regOut!=regStat4 && regOut!=regStat4+1 ); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1); +#elif SQLITE_DEBUG + assert( iParam==STAT_GET_STAT1 ); +#else + UNUSED_PARAMETER( iParam ); +#endif + sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut, + (char*)&statGetFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 1 + IsStat34); +} + +/* +** Generate code to do an analysis of all indices associated with +** a single table. +*/ +static void analyzeOneTable( + Parse *pParse, /* Parser context */ + Table *pTab, /* Table whose indices are to be analyzed */ + Index *pOnlyIdx, /* If not NULL, only analyze this one index */ + int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */ + int iMem, /* Available memory locations begin here */ + int iTab /* Next available cursor */ +){ + sqlite3 *db = pParse->db; /* Database handle */ + Index *pIdx; /* An index to being analyzed */ + int iIdxCur; /* Cursor open on index being analyzed */ + int iTabCur; /* Table cursor */ + Vdbe *v; /* The virtual machine being built up */ + int i; /* Loop counter */ + int jZeroRows = -1; /* Jump from here if number of rows is zero */ + int iDb; /* Index of database containing pTab */ + u8 needTableCnt = 1; /* True to count the table */ + int regNewRowid = iMem++; /* Rowid for the inserted record */ + int regStat4 = iMem++; /* Register to hold Stat4Accum object */ + int regChng = iMem++; /* Index of changed index field */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + int regRowid = iMem++; /* Rowid argument passed to stat_push() */ +#endif + int regTemp = iMem++; /* Temporary use register */ + int regTabname = iMem++; /* Register containing table name */ + int regIdxname = iMem++; /* Register containing index name */ + int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */ + int regPrev = iMem; /* MUST BE LAST (see below) */ + + pParse->nMem = MAX(pParse->nMem, iMem); + v = sqlite3GetVdbe(pParse); + if( v==0 || NEVER(pTab==0) ){ + return; + } + if( pTab->tnum==0 ){ + /* Do not gather statistics on views or virtual tables */ + return; + } + if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){ + /* Do not gather statistics on system tables */ + return; + } + assert( sqlite3BtreeHoldsAllMutexes(db) ); + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDb>=0 ); + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, + db->aDb[iDb].zDbSName ) ){ + return; + } +#endif + + /* Establish a read-lock on the table at the shared-cache level. + ** Open a read-only cursor on the table. Also allocate a cursor number + ** to use for scanning indexes (iIdxCur). No index cursor is opened at + ** this time though. */ + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + iTabCur = iTab++; + iIdxCur = iTab++; + pParse->nTab = MAX(pParse->nTab, iTab); + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeLoadString(v, regTabname, pTab->zName); + + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int nCol; /* Number of columns in pIdx. "N" */ + int addrRewind; /* Address of "OP_Rewind iIdxCur" */ + int addrNextRow; /* Address of "next_row:" */ + const char *zIdxName; /* Name of the index */ + int nColTest; /* Number of columns to test for changes */ + + if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; + if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0; + if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIdx) ){ + nCol = pIdx->nKeyCol; + zIdxName = pTab->zName; + nColTest = nCol - 1; + }else{ + nCol = pIdx->nColumn; + zIdxName = pIdx->zName; + nColTest = pIdx->uniqNotNull ? pIdx->nKeyCol-1 : nCol-1; + } + + /* Populate the register containing the index name. */ + sqlite3VdbeLoadString(v, regIdxname, zIdxName); + VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName)); + + /* + ** Pseudo-code for loop that calls stat_push(): + ** + ** Rewind csr + ** if eof(csr) goto end_of_scan; + ** regChng = 0 + ** goto chng_addr_0; + ** + ** next_row: + ** regChng = 0 + ** if( idx(0) != regPrev(0) ) goto chng_addr_0 + ** regChng = 1 + ** if( idx(1) != regPrev(1) ) goto chng_addr_1 + ** ... + ** regChng = N + ** goto chng_addr_N + ** + ** chng_addr_0: + ** regPrev(0) = idx(0) + ** chng_addr_1: + ** regPrev(1) = idx(1) + ** ... + ** + ** endDistinctTest: + ** regRowid = idx(rowid) + ** stat_push(P, regChng, regRowid) + ** Next csr + ** if !eof(csr) goto next_row; + ** + ** end_of_scan: + */ + + /* Make sure there are enough memory cells allocated to accommodate + ** the regPrev array and a trailing rowid (the rowid slot is required + ** when building a record to insert into the sample column of + ** the sqlite_stat4 table. */ + pParse->nMem = MAX(pParse->nMem, regPrev+nColTest); + + /* Open a read-only cursor on the index being analyzed. */ + assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); + sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + VdbeComment((v, "%s", pIdx->zName)); + + /* Invoke the stat_init() function. The arguments are: + ** + ** (1) the number of columns in the index including the rowid + ** (or for a WITHOUT ROWID table, the number of PK columns), + ** (2) the number of columns in the key without the rowid/pk + ** (3) the number of rows in the index, + ** + ** + ** The third argument is only used for STAT3 and STAT4 + */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3); +#endif + sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); + sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4, + (char*)&statInitFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 2+IsStat34); + + /* Implementation of the following: + ** + ** Rewind csr + ** if eof(csr) goto end_of_scan; + ** regChng = 0 + ** goto next_push_0; + ** + */ + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); + addrNextRow = sqlite3VdbeCurrentAddr(v); + + if( nColTest>0 ){ + int endDistinctTest = sqlite3VdbeMakeLabel(v); + int *aGotoChng; /* Array of jump instruction addresses */ + aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest); + if( aGotoChng==0 ) continue; + + /* + ** next_row: + ** regChng = 0 + ** if( idx(0) != regPrev(0) ) goto chng_addr_0 + ** regChng = 1 + ** if( idx(1) != regPrev(1) ) goto chng_addr_1 + ** ... + ** regChng = N + ** goto endDistinctTest + */ + sqlite3VdbeAddOp0(v, OP_Goto); + addrNextRow = sqlite3VdbeCurrentAddr(v); + if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){ + /* For a single-column UNIQUE index, once we have found a non-NULL + ** row, we know that all the rest will be distinct, so skip + ** subsequent distinctness tests. */ + sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest); + VdbeCoverage(v); + } + for(i=0; iazColl[i]); + sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); + aGotoChng[i] = + sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + VdbeCoverage(v); + } + sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng); + sqlite3VdbeGoto(v, endDistinctTest); + + + /* + ** chng_addr_0: + ** regPrev(0) = idx(0) + ** chng_addr_1: + ** regPrev(1) = idx(1) + ** ... + */ + sqlite3VdbeJumpHere(v, addrNextRow-1); + for(i=0; ipTable); + int j, k, regKey; + regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); + for(j=0; jnKeyCol; j++){ + k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + assert( k>=0 && knColumn ); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); + VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid); + sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol); + } +#endif + assert( regChng==(regStat4+1) ); + sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp, + (char*)&statPushFuncdef, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, 2+IsStat34); + sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); + + /* Add the entry to the stat1 table. */ + callStatGet(v, regStat4, STAT_GET_STAT1, regStat1); + assert( "BBB"[0]==SQLITE_AFF_TEXT ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + + /* Add the entries to the stat3 or stat4 table. */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + { + int regEq = regStat1; + int regLt = regStat1+1; + int regDLt = regStat1+2; + int regSample = regStat1+3; + int regCol = regStat1+4; + int regSampleRowid = regCol + nCol; + int addrNext; + int addrIsNull; + u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound; + + pParse->nMem = MAX(pParse->nMem, regCol+nCol); + + addrNext = sqlite3VdbeCurrentAddr(v); + callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid); + addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid); + VdbeCoverage(v); + callStatGet(v, regStat4, STAT_GET_NEQ, regEq); + callStatGet(v, regStat4, STAT_GET_NLT, regLt); + callStatGet(v, regStat4, STAT_GET_NDLT, regDLt); + sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); + /* We know that the regSampleRowid row exists because it was read by + ** the previous loop. Thus the not-found jump of seekOp will never + ** be taken */ + VdbeCoverageNeverTaken(v); +#ifdef SQLITE_ENABLE_STAT3 + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample); +#else + for(i=0; izName)); + sqlite3VdbeAddOp2(v, OP_Count, iTabCur, regStat1); + jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); + assert( "BBB"[0]==SQLITE_AFF_TEXT ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + sqlite3VdbeJumpHere(v, jZeroRows); + } +} + + +/* +** Generate code that will cause the most recent index analysis to +** be loaded into internal hash tables where is can be used. +*/ +static void loadAnalysis(Parse *pParse, int iDb){ + Vdbe *v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb); + } +} + +/* +** Generate code that will do an analysis of an entire database +*/ +static void analyzeDatabase(Parse *pParse, int iDb){ + sqlite3 *db = pParse->db; + Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ + HashElem *k; + int iStatCur; + int iMem; + int iTab; + + sqlite3BeginWriteOperation(pParse, 0, iDb); + iStatCur = pParse->nTab; + pParse->nTab += 3; + openStatTable(pParse, iDb, iStatCur, 0, 0); + iMem = pParse->nMem+1; + iTab = pParse->nTab; + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + Table *pTab = (Table*)sqliteHashData(k); + analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab); + } + loadAnalysis(pParse, iDb); +} + +/* +** Generate code that will do an analysis of a single table in +** a database. If pOnlyIdx is not NULL then it is a single index +** in pTab that should be analyzed. +*/ +static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){ + int iDb; + int iStatCur; + + assert( pTab!=0 ); + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + sqlite3BeginWriteOperation(pParse, 0, iDb); + iStatCur = pParse->nTab; + pParse->nTab += 3; + if( pOnlyIdx ){ + openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx"); + }else{ + openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl"); + } + analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab); + loadAnalysis(pParse, iDb); +} + +/* +** Generate code for the ANALYZE command. The parser calls this routine +** when it recognizes an ANALYZE command. +** +** ANALYZE -- 1 +** ANALYZE -- 2 +** ANALYZE ?.? -- 3 +** +** Form 1 causes all indices in all attached databases to be analyzed. +** Form 2 analyzes all indices the single database named. +** Form 3 analyzes all indices associated with the named table. +*/ +SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ + sqlite3 *db = pParse->db; + int iDb; + int i; + char *z, *zDb; + Table *pTab; + Index *pIdx; + Token *pTableName; + Vdbe *v; + + /* Read the database schema. If an error occurs, leave an error message + ** and code in pParse and return NULL. */ + assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + return; + } + + assert( pName2!=0 || pName1==0 ); + if( pName1==0 ){ + /* Form 1: Analyze everything */ + for(i=0; inDb; i++){ + if( i==1 ) continue; /* Do not analyze the TEMP database */ + analyzeDatabase(pParse, i); + } + }else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){ + /* Analyze the schema named as the argument */ + analyzeDatabase(pParse, iDb); + }else{ + /* Form 3: Analyze the table or index named as an argument */ + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); + if( iDb>=0 ){ + zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; + z = sqlite3NameFromToken(db, pTableName); + if( z ){ + if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){ + analyzeTable(pParse, pIdx->pTable, pIdx); + }else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){ + analyzeTable(pParse, pTab, 0); + } + sqlite3DbFree(db, z); + } + } + } + if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){ + sqlite3VdbeAddOp0(v, OP_Expire); + } +} + +/* +** Used to pass information from the analyzer reader through to the +** callback routine. +*/ +typedef struct analysisInfo analysisInfo; +struct analysisInfo { + sqlite3 *db; + const char *zDatabase; +}; + +/* +** The first argument points to a nul-terminated string containing a +** list of space separated integers. Read the first nOut of these into +** the array aOut[]. +*/ +static void decodeIntArray( + char *zIntArray, /* String containing int array to decode */ + int nOut, /* Number of slots in aOut[] */ + tRowcnt *aOut, /* Store integers here */ + LogEst *aLog, /* Or, if aOut==0, here */ + Index *pIndex /* Handle extra flags for this index, if not NULL */ +){ + char *z = zIntArray; + int c; + int i; + tRowcnt v; + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( z==0 ) z = ""; +#else + assert( z!=0 ); +#endif + for(i=0; *z && i='0' && c<='9' ){ + v = v*10 + c - '0'; + z++; + } +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( aOut ) aOut[i] = v; + if( aLog ) aLog[i] = sqlite3LogEst(v); +#else + assert( aOut==0 ); + UNUSED_PARAMETER(aOut); + assert( aLog!=0 ); + aLog[i] = sqlite3LogEst(v); +#endif + if( *z==' ' ) z++; + } +#ifndef SQLITE_ENABLE_STAT3_OR_STAT4 + assert( pIndex!=0 ); { +#else + if( pIndex ){ +#endif + pIndex->bUnordered = 0; + pIndex->noSkipScan = 0; + while( z[0] ){ + if( sqlite3_strglob("unordered*", z)==0 ){ + pIndex->bUnordered = 1; + }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ + pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3)); + }else if( sqlite3_strglob("noskipscan*", z)==0 ){ + pIndex->noSkipScan = 1; + } +#ifdef SQLITE_ENABLE_COSTMULT + else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ + pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); + } +#endif + while( z[0]!=0 && z[0]!=' ' ) z++; + while( z[0]==' ' ) z++; + } + } +} + +/* +** This callback is invoked once for each index when reading the +** sqlite_stat1 table. +** +** argv[0] = name of the table +** argv[1] = name of the index (might be NULL) +** argv[2] = results of analysis - on integer for each column +** +** Entries for which argv[1]==NULL simply record the number of rows in +** the table. +*/ +static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ + analysisInfo *pInfo = (analysisInfo*)pData; + Index *pIndex; + Table *pTable; + const char *z; + + assert( argc==3 ); + UNUSED_PARAMETER2(NotUsed, argc); + + if( argv==0 || argv[0]==0 || argv[2]==0 ){ + return 0; + } + pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase); + if( pTable==0 ){ + return 0; + } + if( argv[1]==0 ){ + pIndex = 0; + }else if( sqlite3_stricmp(argv[0],argv[1])==0 ){ + pIndex = sqlite3PrimaryKeyIndex(pTable); + }else{ + pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); + } + z = argv[2]; + + if( pIndex ){ + tRowcnt *aiRowEst = 0; + int nCol = pIndex->nKeyCol+1; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + /* Index.aiRowEst may already be set here if there are duplicate + ** sqlite_stat1 entries for this index. In that case just clobber + ** the old data with the new instead of allocating a new array. */ + if( pIndex->aiRowEst==0 ){ + pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol); + if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db); + } + aiRowEst = pIndex->aiRowEst; +#endif + pIndex->bUnordered = 0; + decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); + pIndex->hasStat1 = 1; + if( pIndex->pPartIdxWhere==0 ){ + pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + pTable->tabFlags |= TF_HasStat1; + } + }else{ + Index fakeIdx; + fakeIdx.szIdxRow = pTable->szTabRow; +#ifdef SQLITE_ENABLE_COSTMULT + fakeIdx.pTable = pTable; +#endif + decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx); + pTable->szTabRow = fakeIdx.szIdxRow; + pTable->tabFlags |= TF_HasStat1; + } + + return 0; +} + +/* +** If the Index.aSample variable is not NULL, delete the aSample[] array +** and its contents. +*/ +SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( pIdx->aSample ){ + int j; + for(j=0; jnSample; j++){ + IndexSample *p = &pIdx->aSample[j]; + sqlite3DbFree(db, p->p); + } + sqlite3DbFree(db, pIdx->aSample); + } + if( db && db->pnBytesFreed==0 ){ + pIdx->nSample = 0; + pIdx->aSample = 0; + } +#else + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(pIdx); +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +} + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** Populate the pIdx->aAvgEq[] array based on the samples currently +** stored in pIdx->aSample[]. +*/ +static void initAvgEq(Index *pIdx){ + if( pIdx ){ + IndexSample *aSample = pIdx->aSample; + IndexSample *pFinal = &aSample[pIdx->nSample-1]; + int iCol; + int nCol = 1; + if( pIdx->nSampleCol>1 ){ + /* If this is stat4 data, then calculate aAvgEq[] values for all + ** sample columns except the last. The last is always set to 1, as + ** once the trailing PK fields are considered all index keys are + ** unique. */ + nCol = pIdx->nSampleCol-1; + pIdx->aAvgEq[nCol] = 1; + } + for(iCol=0; iColnSample; + int i; /* Used to iterate through samples */ + tRowcnt sumEq = 0; /* Sum of the nEq values */ + tRowcnt avgEq = 0; + tRowcnt nRow; /* Number of rows in index */ + i64 nSum100 = 0; /* Number of terms contributing to sumEq */ + i64 nDist100; /* Number of distinct values in index */ + + if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){ + nRow = pFinal->anLt[iCol]; + nDist100 = (i64)100 * pFinal->anDLt[iCol]; + nSample--; + }else{ + nRow = pIdx->aiRowEst[0]; + nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1]; + } + pIdx->nRowEst0 = nRow; + + /* Set nSum to the number of distinct (iCol+1) field prefixes that + ** occur in the stat4 table for this index. Set sumEq to the sum of + ** the nEq values for column iCol for the same set (adding the value + ** only once where there exist duplicate prefixes). */ + for(i=0; inSample-1) + || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] + ){ + sumEq += aSample[i].anEq[iCol]; + nSum100 += 100; + } + } + + if( nDist100>nSum100 && sumEqaAvgEq[iCol] = avgEq; + } + } +} + +/* +** Look up an index by name. Or, if the name of a WITHOUT ROWID table +** is supplied instead, find the PRIMARY KEY index for that table. +*/ +static Index *findIndexOrPrimaryKey( + sqlite3 *db, + const char *zName, + const char *zDb +){ + Index *pIdx = sqlite3FindIndex(db, zName, zDb); + if( pIdx==0 ){ + Table *pTab = sqlite3FindTable(db, zName, zDb); + if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab); + } + return pIdx; +} + +/* +** Load the content from either the sqlite_stat4 or sqlite_stat3 table +** into the relevant Index.aSample[] arrays. +** +** Arguments zSql1 and zSql2 must point to SQL statements that return +** data equivalent to the following (statements are different for stat3, +** see the caller of this function for details): +** +** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx +** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4 +** +** where %Q is replaced with the database name before the SQL is executed. +*/ +static int loadStatTbl( + sqlite3 *db, /* Database handle */ + int bStat3, /* Assume single column records only */ + const char *zSql1, /* SQL statement 1 (see above) */ + const char *zSql2, /* SQL statement 2 (see above) */ + const char *zDb /* Database name (e.g. "main") */ +){ + int rc; /* Result codes from subroutines */ + sqlite3_stmt *pStmt = 0; /* An SQL statement being run */ + char *zSql; /* Text of the SQL statement */ + Index *pPrevIdx = 0; /* Previous index in the loop */ + IndexSample *pSample; /* A slot in pIdx->aSample[] */ + + assert( db->lookaside.bDisable ); + zSql = sqlite3MPrintf(db, zSql1, zDb); + if( !zSql ){ + return SQLITE_NOMEM_BKPT; + } + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + sqlite3DbFree(db, zSql); + if( rc ) return rc; + + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + int nIdxCol = 1; /* Number of columns in stat4 records */ + + char *zIndex; /* Index name */ + Index *pIdx; /* Pointer to the index object */ + int nSample; /* Number of samples */ + int nByte; /* Bytes of space required */ + int i; /* Bytes of space required */ + tRowcnt *pSpace; + + zIndex = (char *)sqlite3_column_text(pStmt, 0); + if( zIndex==0 ) continue; + nSample = sqlite3_column_int(pStmt, 1); + pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); + assert( pIdx==0 || bStat3 || pIdx->nSample==0 ); + /* Index.nSample is non-zero at this point if data has already been + ** loaded from the stat4 table. In this case ignore stat3 data. */ + if( pIdx==0 || pIdx->nSample ) continue; + if( bStat3==0 ){ + assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 ); + if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ + nIdxCol = pIdx->nKeyCol; + }else{ + nIdxCol = pIdx->nColumn; + } + } + pIdx->nSampleCol = nIdxCol; + nByte = sizeof(IndexSample) * nSample; + nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; + nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ + + pIdx->aSample = sqlite3DbMallocZero(db, nByte); + if( pIdx->aSample==0 ){ + sqlite3_finalize(pStmt); + return SQLITE_NOMEM_BKPT; + } + pSpace = (tRowcnt*)&pIdx->aSample[nSample]; + pIdx->aAvgEq = pSpace; pSpace += nIdxCol; + for(i=0; iaSample[i].anEq = pSpace; pSpace += nIdxCol; + pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol; + pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol; + } + assert( ((u8*)pSpace)-nByte==(u8*)(pIdx->aSample) ); + } + rc = sqlite3_finalize(pStmt); + if( rc ) return rc; + + zSql = sqlite3MPrintf(db, zSql2, zDb); + if( !zSql ){ + return SQLITE_NOMEM_BKPT; + } + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + sqlite3DbFree(db, zSql); + if( rc ) return rc; + + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + char *zIndex; /* Index name */ + Index *pIdx; /* Pointer to the index object */ + int nCol = 1; /* Number of columns in index */ + + zIndex = (char *)sqlite3_column_text(pStmt, 0); + if( zIndex==0 ) continue; + pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); + if( pIdx==0 ) continue; + /* This next condition is true if data has already been loaded from + ** the sqlite_stat4 table. In this case ignore stat3 data. */ + nCol = pIdx->nSampleCol; + if( bStat3 && nCol>1 ) continue; + if( pIdx!=pPrevIdx ){ + initAvgEq(pPrevIdx); + pPrevIdx = pIdx; + } + pSample = &pIdx->aSample[pIdx->nSample]; + decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0); + decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0); + + /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer. + ** This is in case the sample record is corrupted. In that case, the + ** sqlite3VdbeRecordCompare() may read up to two varints past the + ** end of the allocated buffer before it realizes it is dealing with + ** a corrupt record. Adding the two 0x00 bytes prevents this from causing + ** a buffer overread. */ + pSample->n = sqlite3_column_bytes(pStmt, 4); + pSample->p = sqlite3DbMallocZero(db, pSample->n + 2); + if( pSample->p==0 ){ + sqlite3_finalize(pStmt); + return SQLITE_NOMEM_BKPT; + } + if( pSample->n ){ + memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n); + } + pIdx->nSample++; + } + rc = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) initAvgEq(pPrevIdx); + return rc; +} + +/* +** Load content from the sqlite_stat4 and sqlite_stat3 tables into +** the Index.aSample[] arrays of all indices. +*/ +static int loadStat4(sqlite3 *db, const char *zDb){ + int rc = SQLITE_OK; /* Result codes from subroutines */ + + assert( db->lookaside.bDisable ); + if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){ + rc = loadStatTbl(db, 0, + "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", + "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", + zDb + ); + } + + if( rc==SQLITE_OK && sqlite3FindTable(db, "sqlite_stat3", zDb) ){ + rc = loadStatTbl(db, 1, + "SELECT idx,count(*) FROM %Q.sqlite_stat3 GROUP BY idx", + "SELECT idx,neq,nlt,ndlt,sqlite_record(sample) FROM %Q.sqlite_stat3", + zDb + ); + } + + return rc; +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + +/* +** Load the content of the sqlite_stat1 and sqlite_stat3/4 tables. The +** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] +** arrays. The contents of sqlite_stat3/4 are used to populate the +** Index.aSample[] arrays. +** +** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR +** is returned. In this case, even if SQLITE_ENABLE_STAT3/4 was defined +** during compilation and the sqlite_stat3/4 table is present, no data is +** read from it. +** +** If SQLITE_ENABLE_STAT3/4 was defined during compilation and the +** sqlite_stat4 table is not present in the database, SQLITE_ERROR is +** returned. However, in this case, data is read from the sqlite_stat1 +** table (if it is present) before returning. +** +** If an OOM error occurs, this function always sets db->mallocFailed. +** This means if the caller does not care about other errors, the return +** code may be ignored. +*/ +SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ + analysisInfo sInfo; + HashElem *i; + char *zSql; + int rc = SQLITE_OK; + Schema *pSchema = db->aDb[iDb].pSchema; + + assert( iDb>=0 && iDbnDb ); + assert( db->aDb[iDb].pBt!=0 ); + + /* Clear any prior statistics */ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){ + Table *pTab = sqliteHashData(i); + pTab->tabFlags &= ~TF_HasStat1; + } + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ + Index *pIdx = sqliteHashData(i); + pIdx->hasStat1 = 0; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3DeleteIndexSamples(db, pIdx); + pIdx->aSample = 0; +#endif + } + + /* Load new statistics out of the sqlite_stat1 table */ + sInfo.db = db; + sInfo.zDatabase = db->aDb[iDb].zDbSName; + if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ + zSql = sqlite3MPrintf(db, + "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); + if( zSql==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); + sqlite3DbFree(db, zSql); + } + } + + /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ + Index *pIdx = sqliteHashData(i); + if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx); + } + + /* Load the statistics from the sqlite_stat4 table. */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){ + db->lookaside.bDisable++; + rc = loadStat4(db, sInfo.zDatabase); + db->lookaside.bDisable--; + } + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ + Index *pIdx = sqliteHashData(i); + sqlite3_free(pIdx->aiRowEst); + pIdx->aiRowEst = 0; + } +#endif + + if( rc==SQLITE_NOMEM ){ + sqlite3OomFault(db); + } + return rc; +} + + +#endif /* SQLITE_OMIT_ANALYZE */ + +/************** End of analyze.c *********************************************/ +/************** Begin file attach.c ******************************************/ +/* +** 2003 April 6 +** +** 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 used to implement the ATTACH and DETACH commands. +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_ATTACH +/* +** Resolve an expression that was part of an ATTACH or DETACH statement. This +** is slightly different from resolving a normal SQL expression, because simple +** identifiers are treated as strings, not possible column names or aliases. +** +** i.e. if the parser sees: +** +** ATTACH DATABASE abc AS def +** +** it treats the two expressions as literal strings 'abc' and 'def' instead of +** looking for columns of the same name. +** +** This only applies to the root node of pExpr, so the statement: +** +** ATTACH DATABASE abc||def AS 'db2' +** +** will fail because neither abc or def can be resolved. +*/ +static int resolveAttachExpr(NameContext *pName, Expr *pExpr) +{ + int rc = SQLITE_OK; + if( pExpr ){ + if( pExpr->op!=TK_ID ){ + rc = sqlite3ResolveExprNames(pName, pExpr); + }else{ + pExpr->op = TK_STRING; + } + } + return rc; +} + +/* +** An SQL user-function registered to do the work of an ATTACH statement. The +** three arguments to the function come directly from an attach statement: +** +** ATTACH DATABASE x AS y KEY z +** +** SELECT sqlite_attach(x, y, z) +** +** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the +** third argument. +*/ +static void attachFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + int i; + int rc = 0; + sqlite3 *db = sqlite3_context_db_handle(context); + const char *zName; + const char *zFile; + char *zPath = 0; + char *zErr = 0; + unsigned int flags; + Db *aNew; + char *zErrDyn = 0; + sqlite3_vfs *pVfs; + + UNUSED_PARAMETER(NotUsed); + + zFile = (const char *)sqlite3_value_text(argv[0]); + zName = (const char *)sqlite3_value_text(argv[1]); + if( zFile==0 ) zFile = ""; + if( zName==0 ) zName = ""; + + /* Check for the following errors: + ** + ** * Too many attached databases, + ** * Transaction currently open + ** * Specified database name already being used. + */ + if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ + zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", + db->aLimit[SQLITE_LIMIT_ATTACHED] + ); + goto attach_error; + } + if( !db->autoCommit ){ + zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); + goto attach_error; + } + for(i=0; inDb; i++){ + char *z = db->aDb[i].zDbSName; + assert( z && zName ); + if( sqlite3StrICmp(z, zName)==0 ){ + zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); + goto attach_error; + } + } + + /* Allocate the new entry in the db->aDb[] array and initialize the schema + ** hash tables. + */ + if( db->aDb==db->aDbStatic ){ + aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 ); + if( aNew==0 ) return; + memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); + }else{ + aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); + if( aNew==0 ) return; + } + db->aDb = aNew; + aNew = &db->aDb[db->nDb]; + memset(aNew, 0, sizeof(*aNew)); + + /* Open the database file. If the btree is successfully opened, use + ** it to obtain the database schema. At this point the schema may + ** or may not be initialized. + */ + flags = db->openFlags; + rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + return; + } + assert( pVfs ); + flags |= SQLITE_OPEN_MAIN_DB; + rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); + sqlite3_free( zPath ); + db->nDb++; + db->skipBtreeMutex = 0; + if( rc==SQLITE_CONSTRAINT ){ + rc = SQLITE_ERROR; + zErrDyn = sqlite3MPrintf(db, "database is already attached"); + }else if( rc==SQLITE_OK ){ + Pager *pPager; + aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); + if( !aNew->pSchema ){ + rc = SQLITE_NOMEM_BKPT; + }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ + zErrDyn = sqlite3MPrintf(db, + "attached databases must use the same text encoding as main database"); + rc = SQLITE_ERROR; + } + sqlite3BtreeEnter(aNew->pBt); + pPager = sqlite3BtreePager(aNew->pBt); + sqlite3PagerLockingMode(pPager, db->dfltLockMode); + sqlite3BtreeSecureDelete(aNew->pBt, + sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); +#ifndef SQLITE_OMIT_PAGER_PRAGMAS + sqlite3BtreeSetPagerFlags(aNew->pBt, + PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); +#endif + sqlite3BtreeLeave(aNew->pBt); + } + aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; + aNew->zDbSName = sqlite3DbStrDup(db, zName); + if( rc==SQLITE_OK && aNew->zDbSName==0 ){ + rc = SQLITE_NOMEM_BKPT; + } + + +#ifdef SQLITE_HAS_CODEC + if( rc==SQLITE_OK ){ + extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); + int nKey; + char *zKey; + int t = sqlite3_value_type(argv[2]); + switch( t ){ + case SQLITE_INTEGER: + case SQLITE_FLOAT: + zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); + rc = SQLITE_ERROR; + break; + + case SQLITE_TEXT: + case SQLITE_BLOB: + nKey = sqlite3_value_bytes(argv[2]); + zKey = (char *)sqlite3_value_blob(argv[2]); + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + break; + + case SQLITE_NULL: + /* No key specified. Use the key from the main database */ + sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + } + break; + } + } +#endif + + /* If the file was opened successfully, read the schema for the new database. + ** If this fails, or if opening the file failed, then close the file and + ** remove the entry from the db->aDb[] array. i.e. put everything back the way + ** we found it. + */ + if( rc==SQLITE_OK ){ + sqlite3BtreeEnterAll(db); + rc = sqlite3Init(db, &zErrDyn); + sqlite3BtreeLeaveAll(db); + } +#ifdef SQLITE_USER_AUTHENTICATION + if( rc==SQLITE_OK ){ + u8 newAuth = 0; + rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); + if( newAuthauth.authLevel ){ + rc = SQLITE_AUTH_USER; + } + } +#endif + if( rc ){ + int iDb = db->nDb - 1; + assert( iDb>=2 ); + if( db->aDb[iDb].pBt ){ + sqlite3BtreeClose(db->aDb[iDb].pBt); + db->aDb[iDb].pBt = 0; + db->aDb[iDb].pSchema = 0; + } + sqlite3ResetAllSchemasOfConnection(db); + db->nDb = iDb; + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomFault(db); + sqlite3DbFree(db, zErrDyn); + zErrDyn = sqlite3MPrintf(db, "out of memory"); + }else if( zErrDyn==0 ){ + zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile); + } + goto attach_error; + } + + return; + +attach_error: + /* Return an error if we get here */ + if( zErrDyn ){ + sqlite3_result_error(context, zErrDyn, -1); + sqlite3DbFree(db, zErrDyn); + } + if( rc ) sqlite3_result_error_code(context, rc); +} + +/* +** An SQL user-function registered to do the work of an DETACH statement. The +** three arguments to the function come directly from a detach statement: +** +** DETACH DATABASE x +** +** SELECT sqlite_detach(x) +*/ +static void detachFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + const char *zName = (const char *)sqlite3_value_text(argv[0]); + sqlite3 *db = sqlite3_context_db_handle(context); + int i; + Db *pDb = 0; + char zErr[128]; + + UNUSED_PARAMETER(NotUsed); + + if( zName==0 ) zName = ""; + for(i=0; inDb; i++){ + pDb = &db->aDb[i]; + if( pDb->pBt==0 ) continue; + if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break; + } + + if( i>=db->nDb ){ + sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); + goto detach_error; + } + if( i<2 ){ + 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; + } + + sqlite3BtreeClose(pDb->pBt); + pDb->pBt = 0; + pDb->pSchema = 0; + sqlite3CollapseDatabaseArray(db); + return; + +detach_error: + sqlite3_result_error(context, zErr, -1); +} + +/* +** This procedure generates VDBE code for a single invocation of either the +** sqlite_detach() or sqlite_attach() SQL user functions. +*/ +static void codeAttach( + Parse *pParse, /* The parser context */ + int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ + FuncDef const *pFunc,/* FuncDef wrapper for detachFunc() or attachFunc() */ + Expr *pAuthArg, /* Expression to pass to authorization callback */ + Expr *pFilename, /* Name of database file */ + Expr *pDbname, /* Name of the database to use internally */ + Expr *pKey /* Database key for encryption extension */ +){ + int rc; + NameContext sName; + Vdbe *v; + sqlite3* db = pParse->db; + int regArgs; + + if( pParse->nErr ) goto attach_end; + memset(&sName, 0, sizeof(NameContext)); + sName.pParse = pParse; + + if( + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) + ){ + goto attach_end; + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + if( pAuthArg ){ + char *zAuthArg; + if( pAuthArg->op==TK_STRING ){ + zAuthArg = pAuthArg->u.zToken; + }else{ + zAuthArg = 0; + } + rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); + if(rc!=SQLITE_OK ){ + goto attach_end; + } + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ + + + v = sqlite3GetVdbe(pParse); + regArgs = sqlite3GetTempRange(pParse, 4); + sqlite3ExprCode(pParse, pFilename, regArgs); + sqlite3ExprCode(pParse, pDbname, regArgs+1); + sqlite3ExprCode(pParse, pKey, regArgs+2); + + assert( v || db->mallocFailed ); + if( v ){ + sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3, + (char *)pFunc, P4_FUNCDEF); + assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg ); + sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg)); + + /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this + ** statement only). For DETACH, set it to false (expire all existing + ** statements). + */ + sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH)); + } + +attach_end: + sqlite3ExprDelete(db, pFilename); + sqlite3ExprDelete(db, pDbname); + sqlite3ExprDelete(db, pKey); +} + +/* +** Called by the parser to compile a DETACH statement. +** +** DETACH pDbname +*/ +SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){ + static const FuncDef detach_func = { + 1, /* nArg */ + SQLITE_UTF8, /* funcFlags */ + 0, /* pUserData */ + 0, /* pNext */ + detachFunc, /* xSFunc */ + 0, /* xFinalize */ + "sqlite_detach", /* zName */ + {0} + }; + codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname); +} + +/* +** Called by the parser to compile an ATTACH statement. +** +** ATTACH p AS pDbname KEY pKey +*/ +SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ + static const FuncDef attach_func = { + 3, /* nArg */ + SQLITE_UTF8, /* funcFlags */ + 0, /* pUserData */ + 0, /* pNext */ + attachFunc, /* xSFunc */ + 0, /* xFinalize */ + "sqlite_attach", /* zName */ + {0} + }; + codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey); +} +#endif /* SQLITE_OMIT_ATTACH */ + +/* +** Initialize a DbFixer structure. This routine must be called prior +** to passing the structure to one of the sqliteFixAAAA() routines below. +*/ +SQLITE_PRIVATE void sqlite3FixInit( + DbFixer *pFix, /* The fixer to be initialized */ + Parse *pParse, /* Error messages will be written here */ + int iDb, /* This is the database that must be used */ + const char *zType, /* "view", "trigger", or "index" */ + const Token *pName /* Name of the view, trigger, or index */ +){ + sqlite3 *db; + + db = pParse->db; + assert( db->nDb>iDb ); + pFix->pParse = pParse; + pFix->zDb = db->aDb[iDb].zDbSName; + pFix->pSchema = db->aDb[iDb].pSchema; + pFix->zType = zType; + pFix->pName = pName; + pFix->bVarOnly = (iDb==1); +} + +/* +** The following set of routines walk through the parse tree and assign +** a specific database to all table references where the database name +** was left unspecified in the original SQL statement. The pFix structure +** must have been initialized by a prior call to sqlite3FixInit(). +** +** These routines are used to make sure that an index, trigger, or +** view in one database does not refer to objects in a different database. +** (Exception: indices, triggers, and views in the TEMP database are +** allowed to refer to anything.) If a reference is explicitly made +** to an object in a different database, an error message is added to +** pParse->zErrMsg and these routines return non-zero. If everything +** checks out, these routines return 0. +*/ +SQLITE_PRIVATE int sqlite3FixSrcList( + DbFixer *pFix, /* Context of the fixation */ + SrcList *pList /* The Source list to check and modify */ +){ + int i; + const char *zDb; + struct SrcList_item *pItem; + + if( NEVER(pList==0) ) return 0; + zDb = pFix->zDb; + for(i=0, pItem=pList->a; inSrc; i++, pItem++){ + if( pFix->bVarOnly==0 ){ + if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){ + sqlite3ErrorMsg(pFix->pParse, + "%s %T cannot reference objects in database %s", + pFix->zType, pFix->pName, pItem->zDatabase); + return 1; + } + sqlite3DbFree(pFix->pParse->db, pItem->zDatabase); + pItem->zDatabase = 0; + pItem->pSchema = pFix->pSchema; + } +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) + if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; + if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; +#endif + } + return 0; +} +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) +SQLITE_PRIVATE int sqlite3FixSelect( + DbFixer *pFix, /* Context of the fixation */ + Select *pSelect /* The SELECT statement to be fixed to one database */ +){ + while( pSelect ){ + if( sqlite3FixExprList(pFix, pSelect->pEList) ){ + return 1; + } + if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){ + return 1; + } + if( sqlite3FixExpr(pFix, pSelect->pWhere) ){ + return 1; + } + if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){ + return 1; + } + if( sqlite3FixExpr(pFix, pSelect->pHaving) ){ + return 1; + } + if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){ + return 1; + } + if( sqlite3FixExpr(pFix, pSelect->pLimit) ){ + return 1; + } + if( sqlite3FixExpr(pFix, pSelect->pOffset) ){ + return 1; + } + pSelect = pSelect->pPrior; + } + return 0; +} +SQLITE_PRIVATE int sqlite3FixExpr( + DbFixer *pFix, /* Context of the fixation */ + Expr *pExpr /* The expression to be fixed to one database */ +){ + while( pExpr ){ + if( pExpr->op==TK_VARIABLE ){ + if( pFix->pParse->db->init.busy ){ + pExpr->op = TK_NULL; + }else{ + sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType); + return 1; + } + } + if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break; + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; + }else{ + if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1; + } + if( sqlite3FixExpr(pFix, pExpr->pRight) ){ + return 1; + } + pExpr = pExpr->pLeft; + } + return 0; +} +SQLITE_PRIVATE int sqlite3FixExprList( + DbFixer *pFix, /* Context of the fixation */ + ExprList *pList /* The expression to be fixed to one database */ +){ + int i; + struct ExprList_item *pItem; + if( pList==0 ) return 0; + for(i=0, pItem=pList->a; inExpr; i++, pItem++){ + if( sqlite3FixExpr(pFix, pItem->pExpr) ){ + return 1; + } + } + return 0; +} +#endif + +#ifndef SQLITE_OMIT_TRIGGER +SQLITE_PRIVATE int sqlite3FixTriggerStep( + DbFixer *pFix, /* Context of the fixation */ + TriggerStep *pStep /* The trigger step be fixed to one database */ +){ + while( pStep ){ + if( sqlite3FixSelect(pFix, pStep->pSelect) ){ + return 1; + } + if( sqlite3FixExpr(pFix, pStep->pWhere) ){ + return 1; + } + if( sqlite3FixExprList(pFix, pStep->pExprList) ){ + return 1; + } + pStep = pStep->pNext; + } + return 0; +} +#endif + +/************** End of attach.c **********************************************/ +/************** Begin file auth.c ********************************************/ +/* +** 2003 January 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 code used to implement the sqlite3_set_authorizer() +** API. This facility is an optional feature of the library. Embedded +** systems that do not need this facility may omit it by recompiling +** the library with -DSQLITE_OMIT_AUTHORIZATION=1 +*/ +/* #include "sqliteInt.h" */ + +/* +** All of the code in this file may be omitted by defining a single +** macro. +*/ +#ifndef SQLITE_OMIT_AUTHORIZATION + +/* +** Set or clear the access authorization function. +** +** The access authorization function is be called during the compilation +** phase to verify that the user has read and/or write access permission on +** various fields of the database. The first argument to the auth function +** is a copy of the 3rd argument to this routine. The second argument +** to the auth function is one of these constants: +** +** SQLITE_CREATE_INDEX +** SQLITE_CREATE_TABLE +** SQLITE_CREATE_TEMP_INDEX +** SQLITE_CREATE_TEMP_TABLE +** SQLITE_CREATE_TEMP_TRIGGER +** SQLITE_CREATE_TEMP_VIEW +** SQLITE_CREATE_TRIGGER +** SQLITE_CREATE_VIEW +** SQLITE_DELETE +** SQLITE_DROP_INDEX +** SQLITE_DROP_TABLE +** SQLITE_DROP_TEMP_INDEX +** SQLITE_DROP_TEMP_TABLE +** SQLITE_DROP_TEMP_TRIGGER +** SQLITE_DROP_TEMP_VIEW +** SQLITE_DROP_TRIGGER +** SQLITE_DROP_VIEW +** SQLITE_INSERT +** SQLITE_PRAGMA +** SQLITE_READ +** SQLITE_SELECT +** SQLITE_TRANSACTION +** SQLITE_UPDATE +** +** The third and fourth arguments to the auth function are the name of +** the table and the column that are being accessed. The auth function +** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If +** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY +** means that the SQL statement will never-run - the sqlite3_exec() call +** will return with an error. SQLITE_IGNORE means that the SQL statement +** should run but attempts to read the specified column will return NULL +** and attempts to write the column will be ignored. +** +** Setting the auth function to NULL disables this hook. The default +** setting of the auth function is NULL. +*/ +SQLITE_API int sqlite3_set_authorizer( + sqlite3 *db, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pArg +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->xAuth = (sqlite3_xauth)xAuth; + db->pAuthArg = pArg; + sqlite3ExpirePreparedStatements(db); + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +/* +** Write an error message into pParse->zErrMsg that explains that the +** user-supplied authorization function returned an illegal value. +*/ +static void sqliteAuthBadReturnCode(Parse *pParse){ + sqlite3ErrorMsg(pParse, "authorizer malfunction"); + pParse->rc = SQLITE_ERROR; +} + +/* +** Invoke the authorization callback for permission to read column zCol from +** table zTab in database zDb. This function assumes that an authorization +** callback has been registered (i.e. that sqlite3.xAuth is not NULL). +** +** If SQLITE_IGNORE is returned and pExpr is not NULL, then pExpr is changed +** to an SQL NULL expression. Otherwise, if pExpr is NULL, then SQLITE_IGNORE +** is treated as SQLITE_DENY. In this case an error is left in pParse. +*/ +SQLITE_PRIVATE int sqlite3AuthReadCol( + Parse *pParse, /* The parser context */ + const char *zTab, /* Table name */ + const char *zCol, /* Column name */ + int iDb /* Index of containing database. */ +){ + sqlite3 *db = pParse->db; /* Database handle */ + char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */ + int rc; /* Auth callback return code */ + + if( db->init.busy ) return SQLITE_OK; + rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#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); + } + pParse->rc = SQLITE_AUTH; + }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){ + sqliteAuthBadReturnCode(pParse); + } + return rc; +} + +/* +** The pExpr should be a TK_COLUMN expression. The table referred to +** is in pTabList or else it is the NEW or OLD table of a trigger. +** Check to see if it is OK to read this particular column. +** +** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN +** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, +** then generate an error. +*/ +SQLITE_PRIVATE void sqlite3AuthRead( + Parse *pParse, /* The parser context */ + Expr *pExpr, /* The expression to check authorization on */ + Schema *pSchema, /* The schema of the expression */ + SrcList *pTabList /* All table that pExpr might refer to */ +){ + sqlite3 *db = pParse->db; + Table *pTab = 0; /* The table being read */ + const char *zCol; /* Name of the column of the table */ + int iSrc; /* Index in pTabList->a[] of table being read */ + int iDb; /* The index of the database the expression refers to */ + int iCol; /* Index of column in table */ + + if( db->xAuth==0 ) return; + iDb = sqlite3SchemaToIndex(pParse->db, pSchema); + if( iDb<0 ){ + /* An attempt to read a column out of a subquery or other + ** temporary table. */ + return; + } + + assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); + if( pExpr->op==TK_TRIGGER ){ + pTab = pParse->pTriggerTab; + }else{ + assert( pTabList ); + for(iSrc=0; ALWAYS(iSrcnSrc); iSrc++){ + if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ + pTab = pTabList->a[iSrc].pTab; + break; + } + } + } + iCol = pExpr->iColumn; + if( NEVER(pTab==0) ) return; + + if( iCol>=0 ){ + assert( iColnCol ); + zCol = pTab->aCol[iCol].zName; + }else if( pTab->iPKey>=0 ){ + assert( pTab->iPKeynCol ); + zCol = pTab->aCol[pTab->iPKey].zName; + }else{ + zCol = "ROWID"; + } + assert( iDb>=0 && iDbnDb ); + if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){ + pExpr->op = TK_NULL; + } +} + +/* +** Do an authorization check using the code and arguments given. Return +** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY +** is returned, then the error count and error message in pParse are +** modified appropriately. +*/ +SQLITE_PRIVATE int sqlite3AuthCheck( + Parse *pParse, + int code, + const char *zArg1, + const char *zArg2, + const char *zArg3 +){ + sqlite3 *db = pParse->db; + int rc; + + /* Don't do any authorization checks if the database is initialising + ** or if the parser is being invoked from within sqlite3_declare_vtab. + */ + if( db->init.busy || IN_DECLARE_VTAB ){ + return SQLITE_OK; + } + + if( db->xAuth==0 ){ + return SQLITE_OK; + } + + /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the + ** callback are either NULL pointers or zero-terminated strings that + ** contain additional details about the action to be authorized. + ** + ** The following testcase() macros show that any of the 3rd through 6th + ** parameters can be either NULL or a string. */ + testcase( zArg1==0 ); + testcase( zArg2==0 ); + testcase( zArg3==0 ); + testcase( pParse->zAuthContext==0 ); + + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext +#ifdef SQLITE_USER_AUTHENTICATION + ,db->auth.zAuthUser +#endif + ); + if( rc==SQLITE_DENY ){ + sqlite3ErrorMsg(pParse, "not authorized"); + pParse->rc = SQLITE_AUTH; + }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){ + rc = SQLITE_DENY; + sqliteAuthBadReturnCode(pParse); + } + return rc; +} + +/* +** Push an authorization context. After this routine is called, the +** zArg3 argument to authorization callbacks will be zContext until +** popped. Or if pParse==0, this routine is a no-op. +*/ +SQLITE_PRIVATE void sqlite3AuthContextPush( + Parse *pParse, + AuthContext *pContext, + const char *zContext +){ + assert( pParse ); + pContext->pParse = pParse; + pContext->zAuthContext = pParse->zAuthContext; + pParse->zAuthContext = zContext; +} + +/* +** Pop an authorization context that was previously pushed +** by sqlite3AuthContextPush +*/ +SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){ + if( pContext->pParse ){ + pContext->pParse->zAuthContext = pContext->zAuthContext; + pContext->pParse = 0; + } +} + +#endif /* SQLITE_OMIT_AUTHORIZATION */ + +/************** End of auth.c ************************************************/ +/************** Begin file build.c *******************************************/ +/* +** 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 C code routines that are called by the SQLite parser +** when syntax rules are reduced. The routines in this file handle the +** following kinds of SQL syntax: +** +** CREATE TABLE +** DROP TABLE +** CREATE INDEX +** DROP INDEX +** creating ID lists +** BEGIN TRANSACTION +** COMMIT +** ROLLBACK +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** The TableLock structure is only used by the sqlite3TableLock() and +** codeTableLocks() functions. +*/ +struct TableLock { + int iDb; /* The database containing the table to be locked */ + int iTab; /* The root page of the table to be locked */ + u8 isWriteLock; /* True for write lock. False for a read lock */ + const char *zLockName; /* Name of the table */ +}; + +/* +** Record the fact that we want to lock a table at run-time. +** +** The table to be locked has root page iTab and is found in database iDb. +** A read or a write lock can be taken depending on isWritelock. +** +** This routine just records the fact that the lock is desired. The +** code to make the lock occur is generated by a later call to +** codeTableLocks() which occurs during sqlite3FinishCoding(). +*/ +SQLITE_PRIVATE void sqlite3TableLock( + Parse *pParse, /* Parsing context */ + int iDb, /* Index of the database containing the table to lock */ + int iTab, /* Root page number of the table to be locked */ + u8 isWriteLock, /* True for a write lock */ + const char *zName /* Name of the table to be locked */ +){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + int i; + int nBytes; + TableLock *p; + assert( iDb>=0 ); + + if( iDb==1 ) return; + if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; + for(i=0; inTableLock; i++){ + p = &pToplevel->aTableLock[i]; + if( p->iDb==iDb && p->iTab==iTab ){ + p->isWriteLock = (p->isWriteLock || isWriteLock); + return; + } + } + + nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); + pToplevel->aTableLock = + sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); + if( pToplevel->aTableLock ){ + p = &pToplevel->aTableLock[pToplevel->nTableLock++]; + p->iDb = iDb; + p->iTab = iTab; + p->isWriteLock = isWriteLock; + p->zLockName = zName; + }else{ + pToplevel->nTableLock = 0; + sqlite3OomFault(pToplevel->db); + } +} + +/* +** Code an OP_TableLock instruction for each table locked by the +** statement (configured by calls to sqlite3TableLock()). +*/ +static void codeTableLocks(Parse *pParse){ + int i; + Vdbe *pVdbe; + + pVdbe = sqlite3GetVdbe(pParse); + assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */ + + for(i=0; inTableLock; i++){ + TableLock *p = &pParse->aTableLock[i]; + int p1 = p->iDb; + sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock, + p->zLockName, P4_STATIC); + } +} +#else + #define codeTableLocks(x) +#endif + +/* +** Return TRUE if the given yDbMask object is empty - if it contains no +** 1 bits. This routine is used by the DbMaskAllZero() and DbMaskNotZero() +** macros when SQLITE_MAX_ATTACHED is greater than 30. +*/ +#if SQLITE_MAX_ATTACHED>30 +SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){ + int i; + for(i=0; ipToplevel==0 ); + db = pParse->db; + if( pParse->nested ) return; + if( db->mallocFailed || pParse->nErr ){ + if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; + return; + } + + /* Begin by generating some termination code at the end of the + ** vdbe program + */ + v = sqlite3GetVdbe(pParse); + assert( !pParse->isMultiWrite + || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); + if( v ){ + sqlite3VdbeAddOp0(v, OP_Halt); + +#if SQLITE_USER_AUTHENTICATION + if( pParse->nTableLock>0 && db->init.busy==0 ){ + sqlite3UserAuthInit(db); + if( db->auth.authLevelrc = SQLITE_AUTH_USER; + return; + } + } +#endif + + /* The cookie mask contains one bit for each database file open. + ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are + ** set for each database that is used. Generate code to start a + ** transaction on each used database and to verify the schema cookie + ** on each used database. + */ + if( db->mallocFailed==0 + && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr) + ){ + int iDb, i; + assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); + sqlite3VdbeJumpHere(v, 0); + for(iDb=0; iDbnDb; iDb++){ + Schema *pSchema; + if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue; + sqlite3VdbeUsesBtree(v, iDb); + pSchema = db->aDb[iDb].pSchema; + sqlite3VdbeAddOp4Int(v, + OP_Transaction, /* Opcode */ + iDb, /* P1 */ + DbMaskTest(pParse->writeMask,iDb), /* P2 */ + pSchema->schema_cookie, /* P3 */ + pSchema->iGeneration /* P4 */ + ); + if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); + VdbeComment((v, + "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite)); + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + for(i=0; inVtabLock; i++){ + char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]); + sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB); + } + pParse->nVtabLock = 0; +#endif + + /* Once all the cookies have been verified and transactions opened, + ** obtain the required table-locks. This is a no-op unless the + ** shared-cache feature is enabled. + */ + codeTableLocks(pParse); + + /* Initialize any AUTOINCREMENT data structures required. + */ + sqlite3AutoincrementBegin(pParse); + + /* Code constant expressions that where factored out of inner loops */ + if( pParse->pConstExpr ){ + ExprList *pEL = pParse->pConstExpr; + pParse->okConstFactor = 0; + for(i=0; inExpr; i++){ + sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); + } + } + + /* Finally, jump back to the beginning of the executable code. */ + sqlite3VdbeGoto(v, 1); + } + } + + + /* Get the VDBE program ready for execution + */ + if( v && pParse->nErr==0 && !db->mallocFailed ){ + assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ + /* A minimum of one cursor is required if autoincrement is used + * See ticket [a696379c1f08866] */ + if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; + sqlite3VdbeMakeReady(v, pParse); + pParse->rc = SQLITE_DONE; + }else{ + pParse->rc = SQLITE_ERROR; + } +} + +/* +** Run the parser and code generator recursively in order to generate +** code for the SQL statement given onto the end of the pParse context +** currently under construction. When the parser is run recursively +** this way, the final OP_Halt is not appended and other initialization +** and finalization steps are omitted because those are handling by the +** outermost parser. +** +** Not everything is nestable. This facility is designed to permit +** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use +** care if you decide to try to use this routine for some other purposes. +*/ +SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ + va_list ap; + char *zSql; + char *zErrMsg = 0; + sqlite3 *db = pParse->db; + char saveBuf[PARSE_TAIL_SZ]; + + if( pParse->nErr ) return; + assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ + va_start(ap, zFormat); + zSql = sqlite3VMPrintf(db, zFormat, ap); + va_end(ap); + if( zSql==0 ){ + return; /* A malloc must have failed */ + } + pParse->nested++; + memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); + memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); + sqlite3RunParser(pParse, zSql, &zErrMsg); + sqlite3DbFree(db, zErrMsg); + sqlite3DbFree(db, zSql); + memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); + pParse->nested--; +} + +#if SQLITE_USER_AUTHENTICATION +/* +** Return TRUE if zTable is the name of the system table that stores the +** list of users and their access credentials. +*/ +SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){ + return sqlite3_stricmp(zTable, "sqlite_user")==0; +} +#endif + +/* +** Locate the in-memory structure that describes a particular database +** table given the name of that table and (optionally) the name of the +** database containing the table. Return NULL if not found. +** +** If zDatabase is 0, all databases are searched for the table and the +** first matching table is returned. (No checking for duplicate table +** names is done.) The search order is TEMP first, then MAIN, then any +** auxiliary databases added using the ATTACH command. +** +** See also sqlite3LocateTable(). +*/ +SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ + Table *p = 0; + int i; + + /* All mutexes are required for schema access. Make sure we hold them. */ + assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); +#if SQLITE_USER_AUTHENTICATION + /* Only the admin user is allowed to know that the sqlite_user table + ** exists */ + if( db->auth.authLevelnDb; i++){ + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ + if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){ + assert( sqlite3SchemaMutexHeld(db, j, 0) ); + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); + if( p ) return p; + } + } + /* Not found. If the name we were looking for was temp.sqlite_master + ** then change the name to sqlite_temp_master and try again. */ + if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break; + if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break; + zName = TEMP_MASTER_NAME; + } + return 0; +} + +/* +** Locate the in-memory structure that describes a particular database +** table given the name of that table and (optionally) the name of the +** database containing the table. Return NULL if not found. Also leave an +** error message in pParse->zErrMsg. +** +** The difference between this routine and sqlite3FindTable() is that this +** routine leaves an error message in pParse->zErrMsg where +** sqlite3FindTable() does not. +*/ +SQLITE_PRIVATE Table *sqlite3LocateTable( + Parse *pParse, /* context in which to report errors */ + u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */ + const char *zName, /* Name of the table we are looking for */ + const char *zDbase /* Name of the database. Might be NULL */ +){ + Table *p; + + /* Read the database schema. If an error occurs, leave an error message + ** and code in pParse and return NULL. */ + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + return 0; + } + + p = sqlite3FindTable(pParse->db, zName, zDbase); + if( p==0 ){ + const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( sqlite3FindDbName(pParse->db, zDbase)<1 ){ + /* If zName is the not the name of a table in the schema created using + ** CREATE, then check to see if it is the name of an virtual table that + ** can be an eponymous virtual table. */ + Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); + if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ + pMod = sqlite3PragmaVtabRegister(pParse->db, zName); + } + if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ + return pMod->pEpoTab; + } + } +#endif + if( (flags & LOCATE_NOERR)==0 ){ + if( zDbase ){ + sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); + }else{ + sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); + } + pParse->checkSchema = 1; + } + } + + return p; +} + +/* +** Locate the table identified by *p. +** +** This is a wrapper around sqlite3LocateTable(). The difference between +** sqlite3LocateTable() and this function is that this function restricts +** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be +** non-NULL if it is part of a view or trigger program definition. See +** sqlite3FixSrcList() for details. +*/ +SQLITE_PRIVATE Table *sqlite3LocateTableItem( + Parse *pParse, + u32 flags, + struct SrcList_item *p +){ + const char *zDb; + assert( p->pSchema==0 || p->zDatabase==0 ); + if( p->pSchema ){ + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + zDb = pParse->db->aDb[iDb].zDbSName; + }else{ + zDb = p->zDatabase; + } + return sqlite3LocateTable(pParse, flags, p->zName, zDb); +} + +/* +** Locate the in-memory structure that describes +** a particular index given the name of that index +** and the name of the database that contains the index. +** Return NULL if not found. +** +** If zDatabase is 0, all databases are searched for the +** table and the first matching index is returned. (No checking +** for duplicate index names is done.) The search order is +** TEMP first, then MAIN, then any auxiliary databases added +** using the ATTACH command. +*/ +SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){ + Index *p = 0; + int i; + /* All mutexes are required for schema access. Make sure we hold them. */ + assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); + for(i=OMIT_TEMPDB; inDb; i++){ + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ + Schema *pSchema = db->aDb[j].pSchema; + assert( pSchema ); + if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue; + assert( sqlite3SchemaMutexHeld(db, j, 0) ); + p = sqlite3HashFind(&pSchema->idxHash, zName); + if( p ) break; + } + return p; +} + +/* +** Reclaim the memory used by an index +*/ +static void freeIndex(sqlite3 *db, Index *p){ +#ifndef SQLITE_OMIT_ANALYZE + sqlite3DeleteIndexSamples(db, p); +#endif + sqlite3ExprDelete(db, p->pPartIdxWhere); + sqlite3ExprListDelete(db, p->aColExpr); + sqlite3DbFree(db, p->zColAff); + if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl); +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3_free(p->aiRowEst); +#endif + sqlite3DbFree(db, p); +} + +/* +** For the index called zIdxName which is found in the database iDb, +** unlike that index from its Table then remove the index from +** the index hash table and free all memory structures associated +** with the index. +*/ +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ + Index *pIndex; + Hash *pHash; + + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + pHash = &db->aDb[iDb].pSchema->idxHash; + pIndex = sqlite3HashInsert(pHash, zIdxName, 0); + if( ALWAYS(pIndex) ){ + if( pIndex->pTable->pIndex==pIndex ){ + pIndex->pTable->pIndex = pIndex->pNext; + }else{ + Index *p; + /* Justification of ALWAYS(); The index must be on the list of + ** indices. */ + p = pIndex->pTable->pIndex; + while( ALWAYS(p) && p->pNext!=pIndex ){ p = p->pNext; } + if( ALWAYS(p && p->pNext==pIndex) ){ + p->pNext = pIndex->pNext; + } + } + freeIndex(db, pIndex); + } + db->flags |= SQLITE_InternChanges; +} + +/* +** Look through the list of open database files in db->aDb[] and if +** any have been closed, remove them from the list. Reallocate the +** db->aDb[] structure to a smaller size, if possible. +** +** Entry 0 (the "main" database) and entry 1 (the "temp" database) +** are never candidates for being collapsed. +*/ +SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){ + int i, j; + for(i=j=2; inDb; i++){ + struct Db *pDb = &db->aDb[i]; + if( pDb->pBt==0 ){ + sqlite3DbFree(db, pDb->zDbSName); + pDb->zDbSName = 0; + continue; + } + if( jaDb[j] = db->aDb[i]; + } + j++; + } + db->nDb = j; + if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ + memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); + sqlite3DbFree(db, db->aDb); + db->aDb = db->aDbStatic; + } +} + +/* +** Reset the schema for the database at index iDb. Also reset the +** TEMP schema. +*/ +SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ + Db *pDb; + assert( iDbnDb ); + + /* 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 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); + } + return; +} + +/* +** Erase all schema information from all attached databases (including +** "main" and "temp") for a single database connection. +*/ +SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ + int i; + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Db *pDb = &db->aDb[i]; + if( pDb->pSchema ){ + sqlite3SchemaClear(pDb->pSchema); + } + } + db->flags &= ~SQLITE_InternChanges; + sqlite3VtabUnlockList(db); + sqlite3BtreeLeaveAll(db); + sqlite3CollapseDatabaseArray(db); +} + +/* +** This routine is called when a commit occurs. +*/ +SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){ + db->flags &= ~SQLITE_InternChanges; +} + +/* +** Delete memory allocated for the column names of a table or view (the +** Table.aCol[] array). +*/ +SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ + int i; + Column *pCol; + assert( pTable!=0 ); + if( (pCol = pTable->aCol)!=0 ){ + for(i=0; inCol; i++, pCol++){ + sqlite3DbFree(db, pCol->zName); + sqlite3ExprDelete(db, pCol->pDflt); + sqlite3DbFree(db, pCol->zColl); + } + sqlite3DbFree(db, pTable->aCol); + } +} + +/* +** Remove the memory data structures associated with the given +** Table. No changes are made to disk by this routine. +** +** This routine just deletes the data structure. It does not unlink +** the table data structure from the hash table. But it does destroy +** memory structures of the indices and foreign keys associated with +** the table. +** +** The db parameter is optional. It is needed if the Table object +** contains lookaside memory. (Table objects in the schema do not use +** lookaside memory, but some ephemeral Table objects do.) Or the +** db parameter can be used with db->pnBytesFreed to measure the memory +** used by the Table object. +*/ +static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ + Index *pIndex, *pNext; + TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */ + + /* 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 ); + + /* Delete all indices associated with this table. */ + for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ + pNext = pIndex->pNext; + assert( pIndex->pSchema==pTable->pSchema + || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); + if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){ + char *zName = pIndex->zName; + TESTONLY ( Index *pOld = ) sqlite3HashInsert( + &pIndex->pSchema->idxHash, zName, 0 + ); + assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); + assert( pOld==pIndex || pOld==0 ); + } + freeIndex(db, pIndex); + } + + /* Delete any foreign keys attached to this table. */ + sqlite3FkDelete(db, pTable); + + /* Delete the Table structure itself. + */ + sqlite3DeleteColumnNames(db, pTable); + sqlite3DbFree(db, pTable->zName); + sqlite3DbFree(db, pTable->zColAff); + sqlite3SelectDelete(db, pTable->pSelect); + sqlite3ExprListDelete(db, pTable->pCheck); +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3VtabClear(db, pTable); +#endif + sqlite3DbFree(db, pTable); + + /* Verify that no lookaside memory was used by schema tables */ + assert( nLookaside==0 || nLookaside==db->lookaside.nOut ); +} +SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ + /* Do not delete the table until the reference count reaches zero. */ + if( !pTable ) return; + if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return; + deleteTable(db, pTable); +} + + +/* +** Unlink the given table from the hash tables and the delete the +** table structure with all its indices and foreign keys. +*/ +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ + Table *p; + Db *pDb; + + assert( db!=0 ); + assert( iDb>=0 && iDbnDb ); + assert( zTabName ); + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + testcase( zTabName[0]==0 ); /* Zero-length table names are allowed */ + pDb = &db->aDb[iDb]; + p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); + sqlite3DeleteTable(db, p); + db->flags |= SQLITE_InternChanges; +} + +/* +** Given a token, return a string that consists of the text of that +** token. Space to hold the returned string +** is obtained from sqliteMalloc() and must be freed by the calling +** function. +** +** Any quotation marks (ex: "name", 'name', [name], or `name`) that +** surround the body of the token are removed. +** +** Tokens are often just pointers into the original SQL text and so +** are not \000 terminated and are not persistent. The returned string +** is \000 terminated and is persistent. +*/ +SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ + char *zName; + if( pName ){ + zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n); + sqlite3Dequote(zName); + }else{ + zName = 0; + } + return zName; +} + +/* +** Open the sqlite_master table stored in database number iDb for +** writing. The table is opened using cursor 0. +*/ +SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){ + Vdbe *v = sqlite3GetVdbe(p); + sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME); + sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5); + if( p->nTab==0 ){ + p->nTab = 1; + } +} + +/* +** Parameter zName points to a nul-terminated buffer containing the name +** of a database ("main", "temp" or the name of an attached db). This +** function returns the index of the named database in db->aDb[], or +** -1 if the named db cannot be found. +*/ +SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){ + int i = -1; /* Database number */ + if( zName ){ + Db *pDb; + for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ + if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break; + /* "main" is always an acceptable alias for the primary database + ** even if it has been renamed using SQLITE_DBCONFIG_MAINDBNAME. */ + if( i==0 && 0==sqlite3_stricmp("main", zName) ) break; + } + } + return i; +} + +/* +** The token *pName contains the name of a database (either "main" or +** "temp" or the name of an attached db). This routine returns the +** index of the named database in db->aDb[], or -1 if the named db +** does not exist. +*/ +SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){ + int i; /* Database number */ + char *zName; /* Name we are searching for */ + zName = sqlite3NameFromToken(db, pName); + i = sqlite3FindDbName(db, zName); + sqlite3DbFree(db, zName); + return i; +} + +/* The table or view or trigger name is passed to this routine via tokens +** pName1 and pName2. If the table name was fully qualified, for example: +** +** CREATE TABLE xxx.yyy (...); +** +** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if +** the table name is not fully qualified, i.e.: +** +** CREATE TABLE yyy(...); +** +** Then pName1 is set to "yyy" and pName2 is "". +** +** This routine sets the *ppUnqual pointer to point at the token (pName1 or +** pName2) that stores the unqualified table name. The index of the +** database "xxx" is returned. +*/ +SQLITE_PRIVATE int sqlite3TwoPartName( + Parse *pParse, /* Parsing and code generating context */ + Token *pName1, /* The "xxx" in the name "xxx.yyy" or "xxx" */ + Token *pName2, /* The "yyy" in the name "xxx.yyy" */ + Token **pUnqual /* Write the unqualified object name here */ +){ + int iDb; /* Database holding the object */ + sqlite3 *db = pParse->db; + + assert( pName2!=0 ); + if( pName2->n>0 ){ + if( db->init.busy ) { + sqlite3ErrorMsg(pParse, "corrupt database"); + return -1; + } + *pUnqual = pName2; + iDb = sqlite3FindDb(db, pName1); + if( iDb<0 ){ + sqlite3ErrorMsg(pParse, "unknown database %T", pName1); + return -1; + } + }else{ + assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0); + iDb = db->init.iDb; + *pUnqual = pName1; + } + return iDb; +} + +/* +** This routine is used to check if the UTF-8 string zName is a legal +** unqualified name for a new schema object (table, index, view or +** trigger). All names are legal except those that begin with the string +** "sqlite_" (in upper, lower or mixed case). This portion of the namespace +** is reserved for internal use. +*/ +SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){ + if( !pParse->db->init.busy && pParse->nested==0 + && (pParse->db->flags & SQLITE_WriteSchema)==0 + && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ + sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +/* +** Return the PRIMARY KEY index of a table +*/ +SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ + Index *p; + for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} + return p; +} + +/* +** Return the column of index pIdx that corresponds to table +** column iCol. Return -1 if not found. +*/ +SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ + int i; + for(i=0; inColumn; i++){ + if( iCol==pIdx->aiColumn[i] ) return i; + } + return -1; +} + +/* +** Begin constructing a new table representation in memory. This is +** the first of several action routines that get called in response +** to a CREATE TABLE statement. In particular, this routine is called +** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp +** flag is true if the table should be stored in the auxiliary database +** file instead of in the main database file. This is normally the case +** when the "TEMP" or "TEMPORARY" keyword occurs in between +** CREATE and TABLE. +** +** The new table record is initialized and put in pParse->pNewTable. +** As more of the CREATE TABLE statement is parsed, additional action +** routines will be called to add more information to this record. +** At the end of the CREATE TABLE statement, the sqlite3EndTable() routine +** is called to complete the construction of the new table record. +*/ +SQLITE_PRIVATE void sqlite3StartTable( + Parse *pParse, /* Parser context */ + Token *pName1, /* First part of the name of the table or view */ + Token *pName2, /* Second part of the name of the table or view */ + int isTemp, /* True if this is a TEMP table */ + int isView, /* True if this is a VIEW */ + int isVirtual, /* True if this is a VIRTUAL table */ + int noErr /* Do nothing if table already exists */ +){ + Table *pTable; + char *zName = 0; /* The name of the new table */ + sqlite3 *db = pParse->db; + Vdbe *v; + int iDb; /* Database number to create the table in */ + Token *pName; /* Unqualified name of the table to create */ + + if( db->init.busy && db->init.newTnum==1 ){ + /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */ + iDb = db->init.iDb; + zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb)); + pName = pName1; + }else{ + /* The common case */ + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); + if( iDb<0 ) return; + if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ + /* If creating a temp table, the name may not be qualified. Unless + ** the database name is "temp" anyway. */ + sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); + return; + } + if( !OMIT_TEMPDB && isTemp ) iDb = 1; + zName = sqlite3NameFromToken(db, pName); + } + pParse->sNameToken = *pName; + if( zName==0 ) return; + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + goto begin_table_error; + } + if( db->init.iDb==1 ) isTemp = 1; +#ifndef SQLITE_OMIT_AUTHORIZATION + assert( isTemp==0 || isTemp==1 ); + assert( isView==0 || isView==1 ); + { + static const u8 aCode[] = { + SQLITE_CREATE_TABLE, + SQLITE_CREATE_TEMP_TABLE, + SQLITE_CREATE_VIEW, + SQLITE_CREATE_TEMP_VIEW + }; + char *zDb = db->aDb[iDb].zDbSName; + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ + goto begin_table_error; + } + if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView], + zName, 0, zDb) ){ + goto begin_table_error; + } + } +#endif + + /* Make sure the new table name does not collide with an existing + ** index or table name in the same database. Issue an error message if + ** it does. The exception is if the statement being parsed was passed + ** to an sqlite3_declare_vtab() call. In that case only the column names + ** and types will be used, so there is no need to test for namespace + ** collisions. + */ + if( !IN_DECLARE_VTAB ){ + char *zDb = db->aDb[iDb].zDbSName; + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + goto begin_table_error; + } + pTable = sqlite3FindTable(db, zName, zDb); + if( pTable ){ + if( !noErr ){ + sqlite3ErrorMsg(pParse, "table %T already exists", pName); + }else{ + assert( !db->init.busy || CORRUPT_DB ); + sqlite3CodeVerifySchema(pParse, iDb); + } + goto begin_table_error; + } + if( sqlite3FindIndex(db, zName, zDb)!=0 ){ + sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); + goto begin_table_error; + } + } + + pTable = sqlite3DbMallocZero(db, sizeof(Table)); + if( pTable==0 ){ + assert( db->mallocFailed ); + pParse->rc = SQLITE_NOMEM_BKPT; + pParse->nErr++; + goto begin_table_error; + } + pTable->zName = zName; + pTable->iPKey = -1; + pTable->pSchema = db->aDb[iDb].pSchema; + pTable->nTabRef = 1; + pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + assert( pParse->pNewTable==0 ); + pParse->pNewTable = pTable; + + /* If this is the magic sqlite_sequence table used by autoincrement, + ** then record a pointer to this table in the main database structure + ** so that INSERT can find the table easily. + */ +#ifndef SQLITE_OMIT_AUTOINCREMENT + if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + pTable->pSchema->pSeqTab = pTable; + } +#endif + + /* Begin generating the code that will insert the table record into + ** the SQLITE_MASTER table. Note in particular that we must go ahead + ** and allocate the record number for the table entry now. Before any + ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause + ** indices to be created and the table record must come before the + ** indices. Hence, the record number for the table must be allocated + ** now. + */ + if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ + int addr1; + int fileFormat; + int reg1, reg2, reg3; + /* nullRow[] is an OP_Record encoding of a row containing 5 NULLs */ + static const char nullRow[] = { 6, 0, 0, 0, 0, 0 }; + sqlite3BeginWriteOperation(pParse, 1, iDb); + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( isVirtual ){ + sqlite3VdbeAddOp0(v, OP_VBegin); + } +#endif + + /* If the file format and encoding in the database have not been set, + ** set them now. + */ + reg1 = pParse->regRowid = ++pParse->nMem; + reg2 = pParse->regRoot = ++pParse->nMem; + reg3 = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); + sqlite3VdbeUsesBtree(v, iDb); + addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v); + fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ? + 1 : SQLITE_MAX_FILE_FORMAT; + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db)); + sqlite3VdbeJumpHere(v, addr1); + + /* This just creates a place-holder record in the sqlite_master table. + ** The record created does not contain anything yet. It will be replaced + ** by the real entry in code generated at sqlite3EndTable(). + ** + ** The rowid for the new entry is left in register pParse->regRowid. + ** The root page number of the new table is left in reg pParse->regRoot. + ** The rowid and root page number values are needed by the code that + ** sqlite3EndTable will generate. + */ +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) + if( isView || isVirtual ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2); + }else +#endif + { + pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2); + } + sqlite3OpenMasterTable(pParse, iDb); + sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); + sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC); + sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + sqlite3VdbeAddOp0(v, OP_Close); + } + + /* Normal (non-error) return. */ + return; + + /* If an error occurs, we jump here */ +begin_table_error: + sqlite3DbFree(db, zName); + return; +} + +/* Set properties of a table column based on the (magical) +** name of the column. +*/ +#if SQLITE_ENABLE_HIDDEN_COLUMNS +SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ + if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){ + pCol->colFlags |= COLFLAG_HIDDEN; + }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ + pTab->tabFlags |= TF_OOOHidden; + } +} +#endif + + +/* +** Add a new column to the table currently being constructed. +** +** The parser calls this routine once for each column declaration +** in a CREATE TABLE statement. sqlite3StartTable() gets called +** first to get things going. Then this routine is called for each +** column. +*/ +SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ + Table *p; + int i; + char *z; + char *zType; + 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); + z[pName->n] = 0; + sqlite3Dequote(z); + for(i=0; inCol; i++){ + if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ + sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); + sqlite3DbFree(db, z); + return; + } + } + if( (p->nCol & 0x7)==0 ){ + Column *aNew; + aNew = sqlite3DbRealloc(db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0])); + if( aNew==0 ){ + sqlite3DbFree(db, z); + return; + } + p->aCol = aNew; + } + pCol = &p->aCol[p->nCol]; + memset(pCol, 0, sizeof(p->aCol[0])); + pCol->zName = z; + sqlite3ColumnPropertiesFromName(p, pCol); + + if( pType->n==0 ){ + /* If there is no type specified, columns have the default affinity + ** 'BLOB'. */ + pCol->affinity = SQLITE_AFF_BLOB; + pCol->szEst = 1; + }else{ + zType = z + sqlite3Strlen30(z) + 1; + memcpy(zType, pType->z, pType->n); + zType[pType->n] = 0; + sqlite3Dequote(zType); + pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst); + pCol->colFlags |= COLFLAG_HASTYPE; + } + p->nCol++; + pParse->constraintName.n = 0; +} + +/* +** This routine is called by the parser while in the middle of +** parsing a CREATE TABLE statement. A "NOT NULL" constraint has +** been seen on a column. This routine sets the notNull flag on +** the column currently under construction. +*/ +SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){ + Table *p; + p = pParse->pNewTable; + if( p==0 || NEVER(p->nCol<1) ) return; + p->aCol[p->nCol-1].notNull = (u8)onError; + p->tabFlags |= TF_HasNotNull; +} + +/* +** Scan the column type name zType (length nType) and return the +** associated affinity type. +** +** This routine does a case-independent search of zType for the +** substrings in the following table. If one of the substrings is +** found, the corresponding affinity is returned. If zType contains +** more than one of the substrings, entries toward the top of +** the table take priority. For example, if zType is 'BLOBINT', +** SQLITE_AFF_INTEGER is returned. +** +** Substring | Affinity +** -------------------------------- +** 'INT' | SQLITE_AFF_INTEGER +** 'CHAR' | SQLITE_AFF_TEXT +** 'CLOB' | SQLITE_AFF_TEXT +** 'TEXT' | SQLITE_AFF_TEXT +** 'BLOB' | SQLITE_AFF_BLOB +** 'REAL' | SQLITE_AFF_REAL +** 'FLOA' | SQLITE_AFF_REAL +** 'DOUB' | SQLITE_AFF_REAL +** +** If none of the substrings in the above table are found, +** SQLITE_AFF_NUMERIC is returned. +*/ +SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ + u32 h = 0; + char aff = SQLITE_AFF_NUMERIC; + const char *zChar = 0; + + assert( zIn!=0 ); + while( zIn[0] ){ + h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff]; + zIn++; + if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ + aff = SQLITE_AFF_TEXT; + zChar = zIn; + }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ + aff = SQLITE_AFF_TEXT; + }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */ + aff = SQLITE_AFF_TEXT; + }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ + && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ + aff = SQLITE_AFF_BLOB; + if( zIn[0]=='(' ) zChar = zIn; +#ifndef SQLITE_OMIT_FLOATING_POINT + }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ + && aff==SQLITE_AFF_NUMERIC ){ + aff = SQLITE_AFF_REAL; + }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */ + && aff==SQLITE_AFF_NUMERIC ){ + aff = SQLITE_AFF_REAL; + }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */ + && aff==SQLITE_AFF_NUMERIC ){ + aff = SQLITE_AFF_REAL; +#endif + }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */ + aff = SQLITE_AFF_INTEGER; + break; + } + } + + /* If pszEst is not NULL, store an estimate of the field size. The + ** estimate is scaled so that the size of an integer is 1. */ + if( pszEst ){ + *pszEst = 1; /* default size is approx 4 bytes */ + if( aff255 ) v = 255; + *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */ + break; + } + zChar++; + } + }else{ + *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/ + } + } + } + return aff; +} + +/* +** The expression is the default value for the most recently added column +** of the table currently under construction. +** +** Default value expressions must be constant. Raise an exception if this +** is not the case. +** +** This routine is called by the parser while in the middle of +** parsing a CREATE TABLE statement. +*/ +SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){ + Table *p; + Column *pCol; + sqlite3 *db = pParse->db; + p = pParse->pNewTable; + if( p!=0 ){ + pCol = &(p->aCol[p->nCol-1]); + if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){ + sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", + pCol->zName); + }else{ + /* A copy of pExpr is used instead of the original, as pExpr contains + ** tokens that point to volatile memory. The 'span' of the expression + ** is required by pragma table_info. + */ + Expr x; + sqlite3ExprDelete(db, pCol->pDflt); + memset(&x, 0, sizeof(x)); + x.op = TK_SPAN; + x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart, + (int)(pSpan->zEnd - pSpan->zStart)); + x.pLeft = pSpan->pExpr; + x.flags = EP_Skip; + pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); + sqlite3DbFree(db, x.u.zToken); + } + } + sqlite3ExprDelete(db, pSpan->pExpr); +} + +/* +** Backwards Compatibility Hack: +** +** Historical versions of SQLite accepted strings as column names in +** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example: +** +** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim) +** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC); +** +** This is goofy. But to preserve backwards compatibility we continue to +** accept it. This routine does the necessary conversion. It converts +** the expression given in its argument from a TK_STRING into a TK_ID +** if the expression is just a TK_STRING with an optional COLLATE clause. +** If the epxression is anything other than TK_STRING, the expression is +** unchanged. +*/ +static void sqlite3StringToId(Expr *p){ + if( p->op==TK_STRING ){ + p->op = TK_ID; + }else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){ + p->pLeft->op = TK_ID; + } +} + +/* +** Designate the PRIMARY KEY for the table. pList is a list of names +** of columns that form the primary key. If pList is NULL, then the +** most recently added column of the table is the primary key. +** +** A table can have at most one primary key. If the table already has +** a primary key (and this is the second primary key) then create an +** error. +** +** If the PRIMARY KEY is on a single column whose datatype is INTEGER, +** then we will try to use that column as the rowid. Set the Table.iPKey +** field of the table under construction to be the index of the +** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is +** no INTEGER PRIMARY KEY. +** +** If the key is not an INTEGER PRIMARY KEY, then create a unique +** index for the key. No index is created for INTEGER PRIMARY KEYs. +*/ +SQLITE_PRIVATE void sqlite3AddPrimaryKey( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List of field names to be indexed */ + int onError, /* What to do with a uniqueness conflict */ + int autoInc, /* True if the AUTOINCREMENT keyword is present */ + int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ +){ + Table *pTab = pParse->pNewTable; + Column *pCol = 0; + int iCol = -1, i; + int nTerm; + if( pTab==0 ) goto primary_key_exit; + if( pTab->tabFlags & TF_HasPrimaryKey ){ + sqlite3ErrorMsg(pParse, + "table \"%s\" has more than one primary key", pTab->zName); + goto primary_key_exit; + } + pTab->tabFlags |= TF_HasPrimaryKey; + if( pList==0 ){ + iCol = pTab->nCol - 1; + pCol = &pTab->aCol[iCol]; + pCol->colFlags |= COLFLAG_PRIMKEY; + nTerm = 1; + }else{ + nTerm = pList->nExpr; + for(i=0; ia[i].pExpr); + assert( pCExpr!=0 ); + sqlite3StringToId(pCExpr); + if( pCExpr->op==TK_ID ){ + const char *zCName = pCExpr->u.zToken; + for(iCol=0; iColnCol; iCol++){ + if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ + pCol = &pTab->aCol[iCol]; + pCol->colFlags |= COLFLAG_PRIMKEY; + break; + } + } + } + } + } + if( nTerm==1 + && pCol + && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 + && sortOrder!=SQLITE_SO_DESC + ){ + pTab->iPKey = iCol; + pTab->keyConf = (u8)onError; + assert( autoInc==0 || autoInc==1 ); + pTab->tabFlags |= autoInc*TF_Autoincrement; + if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; + }else if( autoInc ){ +#ifndef SQLITE_OMIT_AUTOINCREMENT + sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " + "INTEGER PRIMARY KEY"); +#endif + }else{ + sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, + 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); + pList = 0; + } + +primary_key_exit: + sqlite3ExprListDelete(pParse->db, pList); + return; +} + +/* +** Add a new CHECK constraint to the table currently under construction. +*/ +SQLITE_PRIVATE void sqlite3AddCheckConstraint( + Parse *pParse, /* Parsing context */ + Expr *pCheckExpr /* The check expression */ +){ +#ifndef SQLITE_OMIT_CHECK + Table *pTab = pParse->pNewTable; + sqlite3 *db = pParse->db; + if( pTab && !IN_DECLARE_VTAB + && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) + ){ + pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); + if( pParse->constraintName.n ){ + sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); + } + }else +#endif + { + sqlite3ExprDelete(pParse->db, pCheckExpr); + } +} + +/* +** Set the collation function of the most recently parsed table column +** to the CollSeq given. +*/ +SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){ + Table *p; + int i; + char *zColl; /* Dequoted name of collation sequence */ + sqlite3 *db; + + if( (p = pParse->pNewTable)==0 ) return; + i = p->nCol-1; + db = pParse->db; + zColl = sqlite3NameFromToken(db, pToken); + if( !zColl ) return; + + if( sqlite3LocateCollSeq(pParse, zColl) ){ + Index *pIdx; + sqlite3DbFree(db, p->aCol[i].zColl); + p->aCol[i].zColl = zColl; + + /* If the column is declared as " PRIMARY KEY COLLATE ", + ** then an index may have been created on this column before the + ** collation type was added. Correct this if it is the case. + */ + for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ + assert( pIdx->nKeyCol==1 ); + if( pIdx->aiColumn[0]==i ){ + pIdx->azColl[0] = p->aCol[i].zColl; + } + } + }else{ + sqlite3DbFree(db, zColl); + } +} + +/* +** This function returns the collation sequence for database native text +** encoding identified by the string zName, length nName. +** +** If the requested collation sequence is not available, or not available +** in the database native encoding, the collation factory is invoked to +** request it. If the collation factory does not supply such a sequence, +** and the sequence is available in another text encoding, then that is +** returned instead. +** +** If no versions of the requested collations sequence are available, or +** another error occurs, NULL is returned and an error message written into +** pParse. +** +** This routine is a wrapper around sqlite3FindCollSeq(). This routine +** invokes the collation factory if the named collation cannot be found +** and generates an error message. +** +** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq() +*/ +SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){ + sqlite3 *db = pParse->db; + u8 enc = ENC(db); + u8 initbusy = db->init.busy; + CollSeq *pColl; + + pColl = sqlite3FindCollSeq(db, enc, zName, initbusy); + if( !initbusy && (!pColl || !pColl->xCmp) ){ + pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName); + } + + return pColl; +} + + +/* +** Generate code that will increment the schema cookie. +** +** The schema cookie is used to determine when the schema for the +** database changes. After each schema change, the cookie value +** changes. When a process first reads the schema it records the +** cookie. Thereafter, whenever it goes to access the database, +** it checks the cookie to make sure the schema has not changed +** since it was last read. +** +** This plan is not completely bullet-proof. It is possible for +** the schema to change multiple times and for the cookie to be +** set back to prior value. But schema changes are infrequent +** and the probability of hitting the same cookie value is only +** 1 chance in 2^32. So we're safe enough. +** +** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments +** the schema-version whenever the schema changes. +*/ +SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){ + sqlite3 *db = pParse->db; + Vdbe *v = pParse->pVdbe; + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, + db->aDb[iDb].pSchema->schema_cookie+1); +} + +/* +** Measure the number of characters needed to output the given +** identifier. The number returned includes any quotes used +** but does not include the null terminator. +** +** The estimate is conservative. It might be larger that what is +** really needed. +*/ +static int identLength(const char *z){ + int n; + for(n=0; *z; n++, z++){ + if( *z=='"' ){ n++; } + } + return n + 2; +} + +/* +** The first parameter is a pointer to an output buffer. The second +** parameter is a pointer to an integer that contains the offset at +** which to write into the output buffer. This function copies the +** nul-terminated string pointed to by the third parameter, zSignedIdent, +** to the specified offset in the buffer and updates *pIdx to refer +** to the first byte after the last byte written before returning. +** +** If the string zSignedIdent consists entirely of alpha-numeric +** characters, does not begin with a digit and is not an SQL keyword, +** then it is copied to the output buffer exactly as it is. Otherwise, +** it is quoted using double-quotes. +*/ +static void identPut(char *z, int *pIdx, char *zSignedIdent){ + unsigned char *zIdent = (unsigned char*)zSignedIdent; + int i, j, needQuote; + i = *pIdx; + + for(j=0; zIdent[j]; j++){ + if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break; + } + needQuote = sqlite3Isdigit(zIdent[0]) + || sqlite3KeywordCode(zIdent, j)!=TK_ID + || zIdent[j]!=0 + || j==0; + + if( needQuote ) z[i++] = '"'; + for(j=0; zIdent[j]; j++){ + z[i++] = zIdent[j]; + if( zIdent[j]=='"' ) z[i++] = '"'; + } + if( needQuote ) z[i++] = '"'; + z[i] = 0; + *pIdx = i; +} + +/* +** Generate a CREATE TABLE statement appropriate for the given +** table. Memory to hold the text of the statement is obtained +** from sqliteMalloc() and must be freed by the calling function. +*/ +static char *createTableStmt(sqlite3 *db, Table *p){ + int i, k, n; + char *zStmt; + char *zSep, *zSep2, *zEnd; + Column *pCol; + n = 0; + for(pCol = p->aCol, i=0; inCol; i++, pCol++){ + n += identLength(pCol->zName) + 5; + } + n += identLength(p->zName); + if( n<50 ){ + zSep = ""; + zSep2 = ","; + zEnd = ")"; + }else{ + zSep = "\n "; + zSep2 = ",\n "; + zEnd = "\n)"; + } + n += 35 + 6*p->nCol; + zStmt = sqlite3DbMallocRaw(0, n); + if( zStmt==0 ){ + sqlite3OomFault(db); + return 0; + } + sqlite3_snprintf(n, zStmt, "CREATE TABLE "); + k = sqlite3Strlen30(zStmt); + identPut(zStmt, &k, p->zName); + zStmt[k++] = '('; + for(pCol=p->aCol, i=0; inCol; i++, pCol++){ + static const char * const azType[] = { + /* SQLITE_AFF_BLOB */ "", + /* SQLITE_AFF_TEXT */ " TEXT", + /* SQLITE_AFF_NUMERIC */ " NUM", + /* SQLITE_AFF_INTEGER */ " INT", + /* SQLITE_AFF_REAL */ " REAL" + }; + int len; + const char *zType; + + sqlite3_snprintf(n-k, &zStmt[k], zSep); + k += sqlite3Strlen30(&zStmt[k]); + zSep = zSep2; + identPut(zStmt, &k, pCol->zName); + assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); + assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); + testcase( pCol->affinity==SQLITE_AFF_BLOB ); + testcase( pCol->affinity==SQLITE_AFF_TEXT ); + testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); + testcase( pCol->affinity==SQLITE_AFF_INTEGER ); + testcase( pCol->affinity==SQLITE_AFF_REAL ); + + zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; + len = sqlite3Strlen30(zType); + assert( pCol->affinity==SQLITE_AFF_BLOB + || pCol->affinity==sqlite3AffinityType(zType, 0) ); + memcpy(&zStmt[k], zType, len); + k += len; + assert( k<=n ); + } + sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd); + return zStmt; +} + +/* +** Resize an Index object to hold N columns total. Return SQLITE_OK +** on success and SQLITE_NOMEM on an OOM error. +*/ +static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ + char *zExtra; + int nByte; + if( pIdx->nColumn>=N ) return SQLITE_OK; + assert( pIdx->isResized==0 ); + nByte = (sizeof(char*) + sizeof(i16) + 1)*N; + zExtra = sqlite3DbMallocZero(db, nByte); + if( zExtra==0 ) return SQLITE_NOMEM_BKPT; + memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); + pIdx->azColl = (const char**)zExtra; + zExtra += sizeof(char*)*N; + memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn); + pIdx->aiColumn = (i16*)zExtra; + zExtra += sizeof(i16)*N; + memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn); + pIdx->aSortOrder = (u8*)zExtra; + pIdx->nColumn = N; + pIdx->isResized = 1; + return SQLITE_OK; +} + +/* +** Estimate the total row width for a table. +*/ +static void estimateTableWidth(Table *pTab){ + unsigned wTable = 0; + const Column *pTabCol; + int i; + for(i=pTab->nCol, pTabCol=pTab->aCol; i>0; i--, pTabCol++){ + wTable += pTabCol->szEst; + } + if( pTab->iPKey<0 ) wTable++; + pTab->szTabRow = sqlite3LogEst(wTable*4); +} + +/* +** Estimate the average size of a row for an index. +*/ +static void estimateIndexWidth(Index *pIdx){ + unsigned wIndex = 0; + int i; + const Column *aCol = pIdx->pTable->aCol; + for(i=0; inColumn; i++){ + i16 x = pIdx->aiColumn[i]; + assert( xpTable->nCol ); + wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst; + } + pIdx->szIdxRow = sqlite3LogEst(wIndex*4); +} + +/* Return true if value x is found any of the first nCol entries of aiCol[] +*/ +static int hasColumn(const i16 *aiCol, int nCol, int x){ + while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1; + return 0; +} + +/* +** This routine runs at the end of parsing a CREATE TABLE statement that +** has a WITHOUT ROWID clause. The job of this routine is to convert both +** internal schema data structures and the generated VDBE code so that they +** are appropriate for a WITHOUT ROWID table instead of a rowid table. +** 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. +** (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. +** (4) Set the Index.tnum of the PRIMARY KEY Index object in the +** schema to the rootpage from the main table. +** (5) Add all table columns to the PRIMARY KEY Index object +** so that the PRIMARY KEY is a covering index. The surplus +** columns are part of KeyInfo.nXField 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. +** +** For virtual tables, only (1) is performed. +*/ +static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ + Index *pIdx; + Index *pPk; + int nPk; + int i, j; + sqlite3 *db = pParse->db; + Vdbe *v = pParse->pVdbe; + + /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) + */ + if( !db->init.imposterTable ){ + for(i=0; inCol; i++){ + if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ + pTab->aCol[i].notNull = OE_Abort; + } + } + } + + /* The remaining transformations only apply to b-tree tables, not to + ** 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. + */ + if( pParse->addrCrTab ){ + assert( v ); + sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex); + } + + /* Locate the PRIMARY KEY index. Or, if this table was originally + ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. + */ + if( pTab->iPKey>=0 ){ + ExprList *pList; + Token ipkToken; + sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); + pList = sqlite3ExprListAppend(pParse, 0, + sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); + if( pList==0 ) return; + pList->a[0].sortOrder = pParse->iPkSortOrder; + assert( pParse->pNewTable==pTab ); + sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, + SQLITE_IDXTYPE_PRIMARYKEY); + if( db->mallocFailed ) return; + pPk = sqlite3PrimaryKeyIndex(pTab); + pTab->iPKey = -1; + }else{ + pPk = sqlite3PrimaryKeyIndex(pTab); + + /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master + ** table entry. This is only required if currently generating VDBE + ** code for a CREATE TABLE (not when parsing one as part of reading + ** a database schema). */ + if( v ){ + assert( db->init.busy==0 ); + sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto); + } + + /* + ** Remove all redundant columns from the PRIMARY KEY. For example, change + ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later + ** code assumes the PRIMARY KEY contains no repeated columns. + */ + for(i=j=1; inKeyCol; i++){ + if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){ + pPk->nColumn--; + }else{ + pPk->aiColumn[j++] = pPk->aiColumn[i]; + } + } + pPk->nKeyCol = j; + } + assert( pPk!=0 ); + pPk->isCovering = 1; + if( !db->init.imposterTable ) pPk->uniqNotNull = 1; + nPk = pPk->nKeyCol; + + /* The root page of the PRIMARY KEY is the table root page */ + pPk->tnum = pTab->tnum; + + /* Update the in-memory representation of all UNIQUE indices by converting + ** the final rowid column into one or more columns of the PRIMARY KEY. + */ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int n; + if( IsPrimaryKeyIndex(pIdx) ) continue; + for(i=n=0; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++; + } + if( n==0 ){ + /* This index is a superset of the primary key */ + pIdx->nColumn = pIdx->nKeyCol; + continue; + } + if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; + for(i=0, j=pIdx->nKeyCol; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){ + pIdx->aiColumn[j] = pPk->aiColumn[i]; + pIdx->azColl[j] = pPk->azColl[i]; + j++; + } + } + assert( pIdx->nColumn>=pIdx->nKeyCol+n ); + assert( pIdx->nColumn>=j ); + } + + /* Add all table columns to the PRIMARY KEY index + */ + if( nPknCol ){ + if( resizeIndexObject(db, pPk, pTab->nCol) ) return; + for(i=0, j=nPk; inCol; i++){ + if( !hasColumn(pPk->aiColumn, j, i) ){ + assert( jnColumn ); + pPk->aiColumn[j] = i; + pPk->azColl[j] = sqlite3StrBINARY; + j++; + } + } + assert( pPk->nColumn==j ); + assert( pTab->nCol==j ); + }else{ + pPk->nColumn = pTab->nCol; + } +} + +/* +** This routine is called to report the final ")" that terminates +** a CREATE TABLE statement. +** +** The table structure that other action routines have been building +** is added to the internal hash tables, assuming no errors have +** occurred. +** +** An entry for the table is made in the master table on disk, unless +** this is a temporary table or db->init.busy==1. When db->init.busy==1 +** it means we are reading the sqlite_master table because we just +** connected to the database or because the sqlite_master table has +** recently changed, so the entry for this table already exists in +** the sqlite_master table. We do not want to create it again. +** +** If the pSelect argument is not NULL, it means that this routine +** was called to create a table generated from a +** "CREATE TABLE ... AS SELECT ..." statement. The column names of +** the new table will match the result set of the SELECT. +*/ +SQLITE_PRIVATE void sqlite3EndTable( + Parse *pParse, /* Parse context */ + Token *pCons, /* The ',' token after the last column defn. */ + Token *pEnd, /* The ')' before options in the CREATE TABLE */ + u8 tabOpts, /* Extra table options. Usually 0. */ + Select *pSelect /* Select from a "CREATE ... AS SELECT" */ +){ + Table *p; /* The new table */ + sqlite3 *db = pParse->db; /* The database connection */ + int iDb; /* Database in which the table lives */ + Index *pIdx; /* An implied index of the table */ + + if( pEnd==0 && pSelect==0 ){ + return; + } + assert( !db->mallocFailed ); + p = pParse->pNewTable; + if( p==0 ) return; + + assert( !db->init.busy || !pSelect ); + + /* If the db->init.busy is 1 it means we are reading the SQL off the + ** "sqlite_master" or "sqlite_temp_master" table on the disk. + ** So do not write to the disk again. Extract the root page number + ** for the table from the db->init.newTnum field. (The page number + ** should have been put there by the sqliteOpenCb routine.) + ** + ** If the root page number is 1, that means this is the sqlite_master + ** table itself. So mark it read-only. + */ + if( db->init.busy ){ + p->tnum = db->init.newTnum; + if( p->tnum==1 ) p->tabFlags |= TF_Readonly; + } + + /* Special processing for WITHOUT ROWID Tables */ + if( tabOpts & TF_WithoutRowid ){ + if( (p->tabFlags & TF_Autoincrement) ){ + sqlite3ErrorMsg(pParse, + "AUTOINCREMENT not allowed on WITHOUT ROWID tables"); + return; + } + if( (p->tabFlags & TF_HasPrimaryKey)==0 ){ + sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName); + }else{ + p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; + convertToWithoutRowidTable(pParse, p); + } + } + + iDb = sqlite3SchemaToIndex(db, p->pSchema); + +#ifndef SQLITE_OMIT_CHECK + /* Resolve names in all CHECK constraint expressions. + */ + if( p->pCheck ){ + sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck); + } +#endif /* !defined(SQLITE_OMIT_CHECK) */ + + /* Estimate the average row size for the table and for all implied indices */ + estimateTableWidth(p); + for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ + estimateIndexWidth(pIdx); + } + + /* If not initializing, then create a record for the new table + ** in the SQLITE_MASTER table of the database. + ** + ** If this is a TEMPORARY table, write the entry into the auxiliary + ** file instead of into the main database file. + */ + if( !db->init.busy ){ + int n; + Vdbe *v; + char *zType; /* "view" or "table" */ + char *zType2; /* "VIEW" or "TABLE" */ + char *zStmt; /* Text of the CREATE TABLE or CREATE VIEW statement */ + + v = sqlite3GetVdbe(pParse); + if( NEVER(v==0) ) return; + + sqlite3VdbeAddOp1(v, OP_Close, 0); + + /* + ** Initialize zType for the new view or table. + */ + if( p->pSelect==0 ){ + /* A regular table */ + zType = "table"; + zType2 = "TABLE"; +#ifndef SQLITE_OMIT_VIEW + }else{ + /* A view */ + zType = "view"; + zType2 = "VIEW"; +#endif + } + + /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT + ** statement to populate the new table. The root-page number for the + ** new table is in register pParse->regRoot. + ** + ** Once the SELECT has been coded by sqlite3Select(), it is in a + ** suitable state to query for the column names and types to be used + ** by the new table. + ** + ** A shared-cache write-lock is not required to write to the new table, + ** as a schema-lock must have already been obtained to create it. Since + ** a schema-lock excludes all other database users, the write-lock would + ** be redundant. + */ + if( pSelect ){ + SelectDest dest; /* Where the SELECT should store results */ + int regYield; /* Register holding co-routine entry-point */ + int addrTop; /* Top of the co-routine */ + int regRec; /* A record to be insert into the new table */ + int regRowid; /* Rowid of the next row to insert */ + int addrInsLoop; /* Top of the loop for inserting rows */ + Table *pSelTab; /* A table that describes the SELECT results */ + + regYield = ++pParse->nMem; + regRec = ++pParse->nMem; + regRowid = ++pParse->nMem; + assert(pParse->nTab==1); + sqlite3MayAbort(pParse); + sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); + sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); + pParse->nTab = 2; + addrTop = sqlite3VdbeCurrentAddr(v) + 1; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); + sqlite3Select(pParse, pSelect, &dest); + sqlite3VdbeEndCoroutine(v, regYield); + sqlite3VdbeJumpHere(v, addrTop - 1); + if( pParse->nErr ) return; + pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect); + if( pSelTab==0 ) return; + assert( p->aCol==0 ); + p->nCol = pSelTab->nCol; + p->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + sqlite3DeleteTable(db, pSelTab); + addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec); + sqlite3TableAffinity(v, p, 0); + sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid); + sqlite3VdbeGoto(v, addrInsLoop); + sqlite3VdbeJumpHere(v, addrInsLoop); + sqlite3VdbeAddOp1(v, OP_Close, 1); + } + + /* Compute the complete text of the CREATE statement */ + if( pSelect ){ + zStmt = createTableStmt(db, p); + }else{ + Token *pEnd2 = tabOpts ? &pParse->sLastToken : pEnd; + n = (int)(pEnd2->z - pParse->sNameToken.z); + if( pEnd2->z[0]!=';' ) n += pEnd2->n; + zStmt = sqlite3MPrintf(db, + "CREATE %s %.*s", zType2, n, pParse->sNameToken.z + ); + } + + /* A slot for the record has already been allocated in the + ** SQLITE_MASTER table. We just need to update that slot with all + ** the information we've collected. + */ + sqlite3NestedParse(pParse, + "UPDATE %Q.%s " + "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " + "WHERE rowid=#%d", + db->aDb[iDb].zDbSName, MASTER_NAME, + zType, + p->zName, + p->zName, + pParse->regRoot, + zStmt, + pParse->regRowid + ); + sqlite3DbFree(db, zStmt); + sqlite3ChangeCookie(pParse, iDb); + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* Check to see if we need to create an sqlite_sequence table for + ** keeping track of autoincrement keys. + */ + if( (p->tabFlags & TF_Autoincrement)!=0 ){ + Db *pDb = &db->aDb[iDb]; + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( pDb->pSchema->pSeqTab==0 ){ + sqlite3NestedParse(pParse, + "CREATE TABLE %Q.sqlite_sequence(name,seq)", + pDb->zDbSName + ); + } + } +#endif + + /* Reparse everything to update our internal data structures */ + sqlite3VdbeAddParseSchemaOp(v, iDb, + sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName)); + } + + + /* Add the table to the in-memory representation of the database. + */ + if( db->init.busy ){ + Table *pOld; + Schema *pSchema = p->pSchema; + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); + if( pOld ){ + assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ + sqlite3OomFault(db); + return; + } + pParse->pNewTable = 0; + db->flags |= SQLITE_InternChanges; + +#ifndef SQLITE_OMIT_ALTERTABLE + if( !p->pSelect ){ + const char *zName = (const char *)pParse->sNameToken.z; + int nName; + assert( !pSelect && pCons && pEnd ); + if( pCons->z==0 ){ + pCons = pEnd; + } + nName = (int)((const char *)pCons->z - zName); + p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName); + } +#endif + } +} + +#ifndef SQLITE_OMIT_VIEW +/* +** The parser calls this routine in order to create a new VIEW +*/ +SQLITE_PRIVATE void sqlite3CreateView( + Parse *pParse, /* The parsing context */ + Token *pBegin, /* The CREATE token that begins the statement */ + Token *pName1, /* The token that holds the name of the view */ + Token *pName2, /* The token that holds the name of the view */ + ExprList *pCNames, /* Optional list of view column names */ + Select *pSelect, /* A SELECT statement that will become the new view */ + int isTemp, /* TRUE for a TEMPORARY view */ + int noErr /* Suppress error messages if VIEW already exists */ +){ + Table *p; + int n; + const char *z; + Token sEnd; + DbFixer sFix; + Token *pName = 0; + int iDb; + sqlite3 *db = pParse->db; + + if( pParse->nVar>0 ){ + sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); + goto create_view_fail; + } + sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); + p = pParse->pNewTable; + if( p==0 || pParse->nErr ) goto create_view_fail; + sqlite3TwoPartName(pParse, pName1, pName2, &pName); + iDb = sqlite3SchemaToIndex(db, p->pSchema); + sqlite3FixInit(&sFix, pParse, iDb, "view", pName); + if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; + + /* Make a copy of the entire SELECT statement that defines the view. + ** This will force all the Expr.token.z values to be dynamically + ** allocated rather than point to the input string - which means that + ** they will persist after the current sqlite3_exec() call returns. + */ + p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); + if( db->mallocFailed ) goto create_view_fail; + + /* Locate the end of the CREATE VIEW statement. Make sEnd point to + ** the end. + */ + sEnd = pParse->sLastToken; + assert( sEnd.z[0]!=0 ); + if( sEnd.z[0]!=';' ){ + sEnd.z += sEnd.n; + } + sEnd.n = 0; + n = (int)(sEnd.z - pBegin->z); + assert( n>0 ); + z = pBegin->z; + while( sqlite3Isspace(z[n-1]) ){ n--; } + sEnd.z = &z[n-1]; + sEnd.n = 1; + + /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ + sqlite3EndTable(pParse, 0, &sEnd, 0, 0); + +create_view_fail: + sqlite3SelectDelete(db, pSelect); + sqlite3ExprListDelete(db, pCNames); + return; +} +#endif /* SQLITE_OMIT_VIEW */ + +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) +/* +** The Table structure pTable is really a VIEW. Fill in the names of +** the columns of the view in the pTable structure. Return the number +** of errors. If an error is seen leave an error message in pParse->zErrMsg. +*/ +SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ + Table *pSelTab; /* A fake table from which we get the result set */ + Select *pSel; /* Copy of the SELECT that implements the view */ + int nErr = 0; /* Number of errors encountered */ + int n; /* Temporarily holds the number of cursors assigned */ + sqlite3 *db = pParse->db; /* Database connection for malloc errors */ +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth; /* Saved xAuth pointer */ +#endif + + assert( pTable ); + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( sqlite3VtabCallConnect(pParse, pTable) ){ + return SQLITE_ERROR; + } + if( IsVirtual(pTable) ) return 0; +#endif + +#ifndef SQLITE_OMIT_VIEW + /* A positive nCol means the columns names for this view are + ** already known. + */ + if( pTable->nCol>0 ) return 0; + + /* A negative nCol is a special marker meaning that we are currently + ** trying to compute the column names. If we enter this routine with + ** a negative nCol, it means two or more views form a loop, like this: + ** + ** CREATE VIEW one AS SELECT * FROM two; + ** CREATE VIEW two AS SELECT * FROM one; + ** + ** Actually, the error above is now caught prior to reaching this point. + ** But the following test is still important as it does come up + ** in the following: + ** + ** CREATE TABLE main.ex1(a); + ** CREATE TEMP VIEW ex1 AS SELECT a FROM ex1; + ** SELECT * FROM temp.ex1; + */ + if( pTable->nCol<0 ){ + sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName); + return 1; + } + assert( pTable->nCol>=0 ); + + /* If we get this far, it means we need to compute the table names. + ** Note that the call to sqlite3ResultSetOfSelect() will expand any + ** "*" elements in the results set of the view and will assign cursors + ** to the elements of the FROM clause. But we do not want these changes + ** to be permanent. So the computation is done on a copy of the SELECT + ** statement that defines the view. + */ + assert( pTable->pSelect ); + pSel = sqlite3SelectDup(db, pTable->pSelect, 0); + if( pSel ){ + n = pParse->nTab; + sqlite3SrcListAssignCursors(pParse, pSel->pSrc); + pTable->nCol = -1; + db->lookaside.bDisable++; +#ifndef SQLITE_OMIT_AUTHORIZATION + xAuth = db->xAuth; + db->xAuth = 0; + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); + db->xAuth = xAuth; +#else + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); +#endif + pParse->nTab = n; + if( pTable->pCheck ){ + /* CREATE VIEW name(arglist) AS ... + ** The names of the columns in the table are taken from + ** arglist which is stored in pTable->pCheck. The pCheck field + ** normally holds CHECK constraints on an ordinary table, but for + ** a VIEW it holds the list of column names. + */ + sqlite3ColumnsFromExprList(pParse, pTable->pCheck, + &pTable->nCol, &pTable->aCol); + if( db->mallocFailed==0 + && pParse->nErr==0 + && pTable->nCol==pSel->pEList->nExpr + ){ + sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel); + } + }else if( pSelTab ){ + /* CREATE VIEW name AS... without an argument list. Construct + ** the column names from the SELECT statement that defines the view. + */ + assert( pTable->aCol==0 ); + pTable->nCol = pSelTab->nCol; + pTable->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); + }else{ + pTable->nCol = 0; + nErr++; + } + sqlite3DeleteTable(db, pSelTab); + sqlite3SelectDelete(db, pSel); + db->lookaside.bDisable--; + } else { + nErr++; + } + pTable->pSchema->schemaFlags |= DB_UnresetViews; +#endif /* SQLITE_OMIT_VIEW */ + return nErr; +} +#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ + +#ifndef SQLITE_OMIT_VIEW +/* +** Clear the column names from every VIEW in database idx. +*/ +static void sqliteViewResetAll(sqlite3 *db, int idx){ + HashElem *i; + assert( sqlite3SchemaMutexHeld(db, idx, 0) ); + if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; + for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ + Table *pTab = sqliteHashData(i); + if( pTab->pSelect ){ + sqlite3DeleteColumnNames(db, pTab); + pTab->aCol = 0; + pTab->nCol = 0; + } + } + DbClearProperty(db, idx, DB_UnresetViews); +} +#else +# define sqliteViewResetAll(A,B) +#endif /* SQLITE_OMIT_VIEW */ + +/* +** This function is called by the VDBE to adjust the internal schema +** used by SQLite when the btree layer moves a table root page. The +** root-page of a table or index in database iDb has changed from iFrom +** to iTo. +** +** Ticket #1728: The symbol table might still contain information +** on tables and/or indices that are the process of being deleted. +** If you are unlucky, one of those deleted indices or tables might +** have the same rootpage number as the real table or index that is +** being moved. So we cannot stop searching after the first match +** because the first match might be for one of the deleted indices +** or tables and not the table/index that is actually being moved. +** We must continue looping until all tables and indices with +** rootpage==iFrom have been converted to have a rootpage of iTo +** in order to be certain that we got the right one. +*/ +#ifndef SQLITE_OMIT_AUTOVACUUM +SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){ + HashElem *pElem; + Hash *pHash; + Db *pDb; + + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + pDb = &db->aDb[iDb]; + pHash = &pDb->pSchema->tblHash; + for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ + Table *pTab = sqliteHashData(pElem); + if( pTab->tnum==iFrom ){ + pTab->tnum = iTo; + } + } + pHash = &pDb->pSchema->idxHash; + for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ + Index *pIdx = sqliteHashData(pElem); + if( pIdx->tnum==iFrom ){ + pIdx->tnum = iTo; + } + } +} +#endif + +/* +** Write code to erase the table with root-page iTable from database iDb. +** Also write code to modify the sqlite_master table and internal schema +** if a root-page of another table is moved by the btree-layer whilst +** erasing iTable (this can happen with an auto-vacuum database). +*/ +static void destroyRootPage(Parse *pParse, int iTable, int iDb){ + Vdbe *v = sqlite3GetVdbe(pParse); + int r1 = sqlite3GetTempReg(pParse); + assert( iTable>1 ); + sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); + sqlite3MayAbort(pParse); +#ifndef SQLITE_OMIT_AUTOVACUUM + /* OP_Destroy stores an in integer r1. If this integer + ** is non-zero, then it is the root page number of a table moved to + ** location iTable. The following code modifies the sqlite_master table to + ** reflect this. + ** + ** The "#NNN" in the SQL is a special constant that means whatever value + ** is in register NNN. See grammar rules associated with the TK_REGISTER + ** token for additional information. + */ + sqlite3NestedParse(pParse, + "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d", + pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1); +#endif + sqlite3ReleaseTempReg(pParse, r1); +} + +/* +** Write VDBE code to erase table pTab and all associated indices on disk. +** Code to update the sqlite_master tables and internal schema definitions +** in case a root-page belonging to another table is moved by the btree layer +** is also added (this can happen with an auto-vacuum database). +*/ +static void destroyTable(Parse *pParse, Table *pTab){ +#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 + ** largest root-page number. This guarantees that none of the root-pages + ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the + ** following were coded: + ** + ** OP_Destroy 4 0 + ** ... + ** OP_Destroy 5 0 + ** + ** and root page 5 happened to be the largest root-page number in the + ** database, then root page 5 would be moved to page 4 by the + ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit + ** a free-list page. + */ + int iTab = pTab->tnum; + int iDestroyed = 0; + + while( 1 ){ + Index *pIdx; + int iLargest = 0; + + if( iDestroyed==0 || iTabpIndex; pIdx; pIdx=pIdx->pNext){ + int iIdx = pIdx->tnum; + assert( pIdx->pSchema==pTab->pSchema ); + if( (iDestroyed==0 || (iIdxiLargest ){ + iLargest = iIdx; + } + } + if( iLargest==0 ){ + return; + }else{ + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + assert( iDb>=0 && iDbdb->nDb ); + destroyRootPage(pParse, iLargest, iDb); + iDestroyed = iLargest; + } + } +#endif +} + +/* +** Remove entries from the sqlite_statN tables (for N in (1,2,3)) +** after a DROP INDEX or DROP TABLE command. +*/ +static void sqlite3ClearStatTables( + Parse *pParse, /* The parsing context */ + int iDb, /* The database number */ + const char *zType, /* "idx" or "tbl" */ + const char *zName /* Name of index or table */ +){ + int i; + const char *zDbName = pParse->db->aDb[iDb].zDbSName; + for(i=1; i<=4; i++){ + char zTab[24]; + sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i); + if( sqlite3FindTable(pParse->db, zTab, zDbName) ){ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.%s WHERE %s=%Q", + zDbName, zTab, zType, zName + ); + } + } +} + +/* +** Generate code to drop a table. +*/ +SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){ + Vdbe *v; + sqlite3 *db = pParse->db; + Trigger *pTrigger; + Db *pDb = &db->aDb[iDb]; + + v = sqlite3GetVdbe(pParse); + assert( v!=0 ); + sqlite3BeginWriteOperation(pParse, 1, iDb); + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp0(v, OP_VBegin); + } +#endif + + /* Drop all triggers associated with the table being dropped. Code + ** is generated to remove entries from sqlite_master and/or + ** sqlite_temp_master if required. + */ + pTrigger = sqlite3TriggerList(pParse, pTab); + while( pTrigger ){ + assert( pTrigger->pSchema==pTab->pSchema || + pTrigger->pSchema==db->aDb[1].pSchema ); + sqlite3DropTriggerPtr(pParse, pTrigger); + pTrigger = pTrigger->pNext; + } + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* Remove any entries of the sqlite_sequence table associated with + ** the table being dropped. This is done before the table is dropped + ** at the btree level, in case the sqlite_sequence table needs to + ** move as a result of the drop (can happen in auto-vacuum mode). + */ + if( pTab->tabFlags & TF_Autoincrement ){ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", + pDb->zDbSName, pTab->zName + ); + } +#endif + + /* Drop all SQLITE_MASTER table and index entries that refer to the + ** table. The program name loops through the master table and deletes + ** every row that refers to a table of the same name as the one being + ** dropped. Triggers are handled separately because a trigger can be + ** created in the temp database that refers to a table in another + ** database. + */ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", + pDb->zDbSName, MASTER_NAME, pTab->zName); + if( !isView && !IsVirtual(pTab) ){ + destroyTable(pParse, pTab); + } + + /* Remove the table entry from SQLite's internal schema and modify + ** the schema cookie. + */ + if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); + } + sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); + sqlite3ChangeCookie(pParse, iDb); + sqliteViewResetAll(db, iDb); +} + +/* +** This routine is called to do the work of a DROP TABLE statement. +** pName is the name of the table to be dropped. +*/ +SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ + Table *pTab; + Vdbe *v; + sqlite3 *db = pParse->db; + int iDb; + + if( db->mallocFailed ){ + goto exit_drop_table; + } + assert( pParse->nErr==0 ); + assert( pName->nSrc==1 ); + if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; + if( noErr ) db->suppressErr++; + assert( isView==0 || isView==LOCATE_VIEW ); + pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); + if( noErr ) db->suppressErr--; + + if( pTab==0 ){ + if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + goto exit_drop_table; + } + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDb>=0 && iDbnDb ); + + /* If pTab is a virtual table, call ViewGetColumnNames() to ensure + ** it is initialized. + */ + if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){ + goto exit_drop_table; + } +#ifndef SQLITE_OMIT_AUTHORIZATION + { + int code; + const char *zTab = SCHEMA_TABLE(iDb); + const char *zDb = db->aDb[iDb].zDbSName; + const char *zArg2 = 0; + if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ + goto exit_drop_table; + } + if( isView ){ + if( !OMIT_TEMPDB && iDb==1 ){ + code = SQLITE_DROP_TEMP_VIEW; + }else{ + code = SQLITE_DROP_VIEW; + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + }else if( IsVirtual(pTab) ){ + code = SQLITE_DROP_VTABLE; + zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName; +#endif + }else{ + if( !OMIT_TEMPDB && iDb==1 ){ + code = SQLITE_DROP_TEMP_TABLE; + }else{ + code = SQLITE_DROP_TABLE; + } + } + if( sqlite3AuthCheck(pParse, code, pTab->zName, zArg2, zDb) ){ + goto exit_drop_table; + } + if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ + goto exit_drop_table; + } + } +#endif + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 + && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){ + sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); + goto exit_drop_table; + } + +#ifndef SQLITE_OMIT_VIEW + /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used + ** on a table. + */ + if( isView && pTab->pSelect==0 ){ + sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); + goto exit_drop_table; + } + if( !isView && pTab->pSelect ){ + sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); + goto exit_drop_table; + } +#endif + + /* Generate code to remove the table from the master table + ** on disk. + */ + v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3BeginWriteOperation(pParse, 1, iDb); + sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); + sqlite3FkDropTable(pParse, pName, pTab); + sqlite3CodeDropTable(pParse, pTab, iDb, isView); + } + +exit_drop_table: + sqlite3SrcListDelete(db, pName); +} + +/* +** This routine is called to create a new foreign key on the table +** currently under construction. pFromCol determines which columns +** in the current table point to the foreign key. If pFromCol==0 then +** connect the key to the last column inserted. pTo is the name of +** the table referred to (a.k.a the "parent" table). pToCol is a list +** of tables in the parent pTo table. flags contains all +** information about the conflict resolution algorithms specified +** in the ON DELETE, ON UPDATE and ON INSERT clauses. +** +** An FKey structure is created and added to the table currently +** under construction in the pParse->pNewTable field. +** +** The foreign key is set for IMMEDIATE processing. A subsequent call +** to sqlite3DeferForeignKey() might change this to DEFERRED. +*/ +SQLITE_PRIVATE void sqlite3CreateForeignKey( + Parse *pParse, /* Parsing context */ + ExprList *pFromCol, /* Columns in this table that point to other table */ + Token *pTo, /* Name of the other table */ + ExprList *pToCol, /* Columns in the other table */ + int flags /* Conflict resolution algorithms. */ +){ + sqlite3 *db = pParse->db; +#ifndef SQLITE_OMIT_FOREIGN_KEY + FKey *pFKey = 0; + FKey *pNextTo; + Table *p = pParse->pNewTable; + int nByte; + int i; + int nCol; + char *z; + + assert( pTo!=0 ); + if( p==0 || IN_DECLARE_VTAB ) goto fk_end; + if( pFromCol==0 ){ + int iCol = p->nCol-1; + if( NEVER(iCol<0) ) goto fk_end; + if( pToCol && pToCol->nExpr!=1 ){ + sqlite3ErrorMsg(pParse, "foreign key on %s" + " should reference only one column of table %T", + p->aCol[iCol].zName, pTo); + goto fk_end; + } + nCol = 1; + }else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){ + sqlite3ErrorMsg(pParse, + "number of columns in foreign key does not match the number of " + "columns in the referenced table"); + goto fk_end; + }else{ + nCol = pFromCol->nExpr; + } + nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1; + if( pToCol ){ + for(i=0; inExpr; i++){ + nByte += sqlite3Strlen30(pToCol->a[i].zName) + 1; + } + } + pFKey = sqlite3DbMallocZero(db, nByte ); + if( pFKey==0 ){ + goto fk_end; + } + pFKey->pFrom = p; + pFKey->pNextFrom = p->pFKey; + z = (char*)&pFKey->aCol[nCol]; + pFKey->zTo = z; + memcpy(z, pTo->z, pTo->n); + z[pTo->n] = 0; + sqlite3Dequote(z); + z += pTo->n+1; + pFKey->nCol = nCol; + if( pFromCol==0 ){ + pFKey->aCol[0].iFrom = p->nCol-1; + }else{ + for(i=0; inCol; j++){ + if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){ + pFKey->aCol[i].iFrom = j; + break; + } + } + if( j>=p->nCol ){ + sqlite3ErrorMsg(pParse, + "unknown column \"%s\" in foreign key definition", + pFromCol->a[i].zName); + goto fk_end; + } + } + } + if( pToCol ){ + for(i=0; ia[i].zName); + pFKey->aCol[i].zCol = z; + memcpy(z, pToCol->a[i].zName, n); + z[n] = 0; + z += n+1; + } + } + pFKey->isDeferred = 0; + pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */ + pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */ + + assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); + pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, + pFKey->zTo, (void *)pFKey + ); + if( pNextTo==pFKey ){ + sqlite3OomFault(db); + goto fk_end; + } + if( pNextTo ){ + assert( pNextTo->pPrevTo==0 ); + pFKey->pNextTo = pNextTo; + pNextTo->pPrevTo = pFKey; + } + + /* Link the foreign key to the table as the last step. + */ + p->pFKey = pFKey; + pFKey = 0; + +fk_end: + sqlite3DbFree(db, pFKey); +#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ + sqlite3ExprListDelete(db, pFromCol); + sqlite3ExprListDelete(db, pToCol); +} + +/* +** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED +** clause is seen as part of a foreign key definition. The isDeferred +** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE. +** The behavior of the most recently created foreign key is adjusted +** accordingly. +*/ +SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ +#ifndef SQLITE_OMIT_FOREIGN_KEY + Table *pTab; + FKey *pFKey; + if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return; + assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */ + pFKey->isDeferred = (u8)isDeferred; +#endif +} + +/* +** Generate code that will erase and refill index *pIdx. This is +** used to initialize a newly created index or to recompute the +** content of an index in response to a REINDEX command. +** +** if memRootPage is not negative, it means that the index is newly +** created. The register specified by memRootPage contains the +** root page number of the index. If memRootPage is negative, then +** the index already exists and must be cleared before being refilled and +** the root page number of the index is taken from pIndex->tnum. +*/ +static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ + Table *pTab = pIndex->pTable; /* The table that is indexed */ + int iTab = pParse->nTab++; /* Btree cursor used for pTab */ + int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */ + int iSorter; /* Cursor opened by OpenSorter (if in use) */ + int addr1; /* Address of top of loop */ + int addr2; /* Address to jump to for next iteration */ + int tnum; /* Root page of index */ + int iPartIdxLabel; /* Jump to this label to skip a row */ + Vdbe *v; /* Generate code into this virtual machine */ + KeyInfo *pKey; /* KeyInfo for index */ + int regRecord; /* Register holding assembled index record */ + sqlite3 *db = pParse->db; /* The database connection */ + int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); + +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, + db->aDb[iDb].zDbSName ) ){ + return; + } +#endif + + /* Require a write-lock on the table to perform this operation */ + sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); + + v = sqlite3GetVdbe(pParse); + if( v==0 ) return; + if( memRootPage>=0 ){ + tnum = memRootPage; + }else{ + tnum = pIndex->tnum; + } + pKey = sqlite3KeyInfoOfIndex(pParse, pIndex); + assert( pKey!=0 || db->mallocFailed || pParse->nErr ); + + /* Open the sorter cursor if we are to use one. */ + iSorter = pParse->nTab++; + sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*) + sqlite3KeyInfoRef(pKey), P4_KEYINFO); + + /* Open the table. Loop through all rows of the table, inserting index + ** records into the sorter. */ + sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); + regRecord = sqlite3GetTempReg(pParse); + + sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); + sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addr1); + if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); + sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, + (char *)pKey, P4_KEYINFO); + sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); + + addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); + if( IsUniqueIndex(pIndex) ){ + int j2 = sqlite3VdbeCurrentAddr(v) + 3; + sqlite3VdbeGoto(v, j2); + addr2 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, + pIndex->nKeyCol); VdbeCoverage(v); + sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); + }else{ + addr2 = sqlite3VdbeCurrentAddr(v); + } + sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); + sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + sqlite3ReleaseTempReg(pParse, regRecord); + sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addr1); + + sqlite3VdbeAddOp1(v, OP_Close, iTab); + sqlite3VdbeAddOp1(v, OP_Close, iIdx); + sqlite3VdbeAddOp1(v, OP_Close, iSorter); +} + +/* +** Allocate heap space to hold an Index object with nCol columns. +** +** Increase the allocation size to provide an extra nExtra bytes +** of 8-byte aligned space after the Index object and return a +** pointer to this extra space in *ppExtra. +*/ +SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( + sqlite3 *db, /* Database connection */ + i16 nCol, /* Total number of columns in the index */ + int nExtra, /* Number of bytes of extra space to alloc */ + char **ppExtra /* Pointer to the "extra" space */ +){ + Index *p; /* Allocated index object */ + int nByte; /* Bytes of space for Index object + arrays */ + + nByte = ROUND8(sizeof(Index)) + /* Index structure */ + ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ + ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ + sizeof(i16)*nCol + /* Index.aiColumn */ + sizeof(u8)*nCol); /* Index.aSortOrder */ + p = sqlite3DbMallocZero(db, nByte + nExtra); + if( p ){ + char *pExtra = ((char*)p)+ROUND8(sizeof(Index)); + p->azColl = (const char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol); + p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); + p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; + p->aSortOrder = (u8*)pExtra; + p->nColumn = nCol; + p->nKeyCol = nCol - 1; + *ppExtra = ((char*)p) + nByte; + } + return p; +} + +/* +** Create a new index for an SQL table. pName1.pName2 is the name of the index +** and pTblList is the name of the table that is to be indexed. Both will +** be NULL for a primary key or an index that is created to satisfy a +** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable +** as the table to be indexed. pParse->pNewTable is a table that is +** currently being constructed by a CREATE TABLE statement. +** +** pList is a list of columns to be indexed. pList will be NULL if this +** is a primary key or unique-constraint on the most recent column added +** to the table currently under construction. +*/ +SQLITE_PRIVATE void sqlite3CreateIndex( + Parse *pParse, /* All information about this parse */ + Token *pName1, /* First part of index name. May be NULL */ + Token *pName2, /* Second part of index name. May be NULL */ + SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ + ExprList *pList, /* A list of columns to be indexed */ + int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ + Token *pStart, /* The CREATE token that begins this statement */ + Expr *pPIWhere, /* WHERE clause for partial indices */ + int sortOrder, /* Sort order of primary key when pList==NULL */ + int ifNotExist, /* Omit error if index already exists */ + u8 idxType /* The index type */ +){ + Table *pTab = 0; /* Table to be indexed */ + Index *pIndex = 0; /* The index to be created */ + char *zName = 0; /* Name of the index */ + int nName; /* Number of characters in zName */ + int i, j; + DbFixer sFix; /* For assigning database names to pTable */ + int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ + sqlite3 *db = pParse->db; + Db *pDb; /* The specific table containing the indexed database */ + int iDb; /* Index of the database that is being written */ + Token *pName = 0; /* Unqualified name of the index to create */ + struct ExprList_item *pListItem; /* For looping over pList */ + int nExtra = 0; /* Space allocated for zExtra[] */ + int nExtraCol; /* Number of extra columns needed */ + char *zExtra = 0; /* Extra space after the Index object */ + Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ + + if( db->mallocFailed || pParse->nErr>0 ){ + goto exit_create_index; + } + if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ + goto exit_create_index; + } + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + goto exit_create_index; + } + + /* + ** Find the table that is to be indexed. Return early if not found. + */ + if( pTblName!=0 ){ + + /* Use the two-part index name to determine the database + ** to search for the table. 'Fix' the table name to this db + ** before looking up the table. + */ + assert( pName1 && pName2 ); + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); + if( iDb<0 ) goto exit_create_index; + assert( pName && pName->z ); + +#ifndef SQLITE_OMIT_TEMPDB + /* If the index name was unqualified, check if the table + ** is a temp table. If so, set the database to 1. Do not do this + ** if initialising a database schema. + */ + if( !db->init.busy ){ + pTab = sqlite3SrcListLookup(pParse, pTblName); + if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ + iDb = 1; + } + } +#endif + + sqlite3FixInit(&sFix, pParse, iDb, "index", pName); + if( sqlite3FixSrcList(&sFix, pTblName) ){ + /* Because the parser constructs pTblName from a single identifier, + ** sqlite3FixSrcList can never fail. */ + assert(0); + } + pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]); + assert( db->mallocFailed==0 || pTab==0 ); + if( pTab==0 ) goto exit_create_index; + if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){ + sqlite3ErrorMsg(pParse, + "cannot create a TEMP index on non-TEMP table \"%s\"", + pTab->zName); + goto exit_create_index; + } + if( !HasRowid(pTab) ) pPk = sqlite3PrimaryKeyIndex(pTab); + }else{ + assert( pName==0 ); + assert( pStart==0 ); + pTab = pParse->pNewTable; + if( !pTab ) goto exit_create_index; + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + } + pDb = &db->aDb[iDb]; + + assert( pTab!=0 ); + assert( pParse->nErr==0 ); + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 + && db->init.busy==0 +#if SQLITE_USER_AUTHENTICATION + && sqlite3UserAuthTable(pTab->zName)==0 +#endif + && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ + sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); + goto exit_create_index; + } +#ifndef SQLITE_OMIT_VIEW + if( pTab->pSelect ){ + sqlite3ErrorMsg(pParse, "views may not be indexed"); + goto exit_create_index; + } +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "virtual tables may not be indexed"); + goto exit_create_index; + } +#endif + + /* + ** Find the name of the index. Make sure there is not already another + ** index or table with the same name. + ** + ** Exception: If we are reading the names of permanent indices from the + ** sqlite_master table (because some other process changed the schema) and + ** one of the index names collides with the name of a temporary table or + ** index, then we will continue to process this index. + ** + ** If pName==0 it means that we are + ** dealing with a primary key or UNIQUE constraint. We have to invent our + ** own name. + */ + if( pName ){ + zName = sqlite3NameFromToken(db, pName); + if( zName==0 ) goto exit_create_index; + assert( pName->z!=0 ); + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + goto exit_create_index; + } + if( !db->init.busy ){ + if( sqlite3FindTable(db, zName, 0)!=0 ){ + sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); + goto exit_create_index; + } + } + if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ + if( !ifNotExist ){ + sqlite3ErrorMsg(pParse, "index %s already exists", zName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); + } + goto exit_create_index; + } + }else{ + int n; + Index *pLoop; + for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} + zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n); + if( zName==0 ){ + goto exit_create_index; + } + + /* Automatic index names generated from within sqlite3_declare_vtab() + ** must have names that are distinct from normal automatic index names. + ** The following statement converts "sqlite3_autoindex..." into + ** "sqlite3_butoindex..." in order to make the names distinct. + ** The "vtab_err.test" test demonstrates the need of this statement. */ + if( IN_DECLARE_VTAB ) zName[7]++; + } + + /* Check for authorization to create an index. + */ +#ifndef SQLITE_OMIT_AUTHORIZATION + { + const char *zDb = pDb->zDbSName; + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ + goto exit_create_index; + } + i = SQLITE_CREATE_INDEX; + if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; + if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){ + goto exit_create_index; + } + } +#endif + + /* If pList==0, it means this routine was called to make a primary + ** key out of the last column added to the table under construction. + ** So create a fake list to simulate this. + */ + if( pList==0 ){ + Token prevCol; + sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol-1].zName); + pList = sqlite3ExprListAppend(pParse, 0, + sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); + if( pList==0 ) goto exit_create_index; + assert( pList->nExpr==1 ); + sqlite3ExprListSetSortOrder(pList, sortOrder); + }else{ + sqlite3ExprListCheckLength(pParse, pList, "index"); + } + + /* Figure out how many bytes of space are required to store explicitly + ** specified collation sequence names. + */ + for(i=0; inExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + assert( pExpr!=0 ); + if( pExpr->op==TK_COLLATE ){ + nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); + } + } + + /* + ** Allocate the index structure. + */ + nName = sqlite3Strlen30(zName); + nExtraCol = pPk ? pPk->nKeyCol : 1; + pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, + nName + nExtra + 1, &zExtra); + if( db->mallocFailed ){ + goto exit_create_index; + } + assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) ); + assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); + pIndex->zName = zExtra; + zExtra += nName + 1; + memcpy(pIndex->zName, zName, nName+1); + pIndex->pTable = pTab; + pIndex->onError = (u8)onError; + pIndex->uniqNotNull = onError!=OE_None; + pIndex->idxType = idxType; + pIndex->pSchema = db->aDb[iDb].pSchema; + pIndex->nKeyCol = pList->nExpr; + if( pPIWhere ){ + sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0); + pIndex->pPartIdxWhere = pPIWhere; + pPIWhere = 0; + } + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + + /* Check to see if we should honor DESC requests on index columns + */ + if( pDb->pSchema->file_format>=4 ){ + sortOrderMask = -1; /* Honor DESC */ + }else{ + sortOrderMask = 0; /* Ignore DESC */ + } + + /* Analyze the list of expressions that form the terms of the index and + ** report any errors. In the common case where the expression is exactly + ** a table column, store that column in aiColumn[]. For general expressions, + ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[]. + ** + ** TODO: Issue a warning if two or more columns of the index are identical. + ** TODO: Issue a warning if the table primary key is used as part of the + ** index key. + */ + for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ + Expr *pCExpr; /* The i-th index expression */ + int requestedSortOrder; /* ASC or DESC on the i-th expression */ + const char *zColl; /* Collation sequence name */ + + sqlite3StringToId(pListItem->pExpr); + sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); + if( pParse->nErr ) goto exit_create_index; + pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); + if( pCExpr->op!=TK_COLUMN ){ + if( pTab==pParse->pNewTable ){ + sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and " + "UNIQUE constraints"); + goto exit_create_index; + } + if( pIndex->aColExpr==0 ){ + ExprList *pCopy = sqlite3ExprListDup(db, pList, 0); + pIndex->aColExpr = pCopy; + if( !db->mallocFailed ){ + assert( pCopy!=0 ); + pListItem = &pCopy->a[i]; + } + } + j = XN_EXPR; + pIndex->aiColumn[i] = XN_EXPR; + pIndex->uniqNotNull = 0; + }else{ + j = pCExpr->iColumn; + assert( j<=0x7fff ); + if( j<0 ){ + j = pTab->iPKey; + }else if( pTab->aCol[j].notNull==0 ){ + pIndex->uniqNotNull = 0; + } + pIndex->aiColumn[i] = (i16)j; + } + zColl = 0; + if( pListItem->pExpr->op==TK_COLLATE ){ + int nColl; + zColl = pListItem->pExpr->u.zToken; + nColl = sqlite3Strlen30(zColl) + 1; + assert( nExtra>=nColl ); + memcpy(zExtra, zColl, nColl); + zColl = zExtra; + zExtra += nColl; + nExtra -= nColl; + }else if( j>=0 ){ + zColl = pTab->aCol[j].zColl; + } + if( !zColl ) zColl = sqlite3StrBINARY; + if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ + goto exit_create_index; + } + pIndex->azColl[i] = zColl; + requestedSortOrder = pListItem->sortOrder & sortOrderMask; + pIndex->aSortOrder[i] = (u8)requestedSortOrder; + } + + /* Append the table key to the end of the index. For WITHOUT ROWID + ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For + ** normal tables (when pPk==0) this will be the rowid. + */ + if( pPk ){ + for(j=0; jnKeyCol; j++){ + int x = pPk->aiColumn[j]; + assert( x>=0 ); + if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ + pIndex->nColumn--; + }else{ + pIndex->aiColumn[i] = x; + pIndex->azColl[i] = pPk->azColl[j]; + pIndex->aSortOrder[i] = pPk->aSortOrder[j]; + i++; + } + } + assert( i==pIndex->nColumn ); + }else{ + pIndex->aiColumn[i] = XN_ROWID; + pIndex->azColl[i] = sqlite3StrBINARY; + } + sqlite3DefaultRowEst(pIndex); + if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex); + + /* If this index contains every column of its table, then mark + ** it as a covering index */ + assert( HasRowid(pTab) + || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 ); + if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ + pIndex->isCovering = 1; + for(j=0; jnCol; j++){ + if( j==pTab->iPKey ) continue; + if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue; + pIndex->isCovering = 0; + break; + } + } + + if( pTab==pParse->pNewTable ){ + /* This routine has been called to create an automatic index as a + ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or + ** a PRIMARY KEY or UNIQUE clause following the column definitions. + ** i.e. one of: + ** + ** CREATE TABLE t(x PRIMARY KEY, y); + ** CREATE TABLE t(x, y, UNIQUE(x, y)); + ** + ** Either way, check to see if the table already has such an index. If + ** so, don't bother creating this one. This only applies to + ** automatically created indices. Users can do as they wish with + ** explicit indices. + ** + ** Two UNIQUE or PRIMARY KEY constraints are considered equivalent + ** (and thus suppressing the second one) even if they have different + ** sort orders. + ** + ** If there are different collating sequences or if the columns of + ** the constraint occur in different orders, then the constraints are + ** considered distinct and both result in separate indices. + */ + Index *pIdx; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int k; + assert( IsUniqueIndex(pIdx) ); + assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); + assert( IsUniqueIndex(pIndex) ); + + if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; + for(k=0; knKeyCol; k++){ + const char *z1; + const char *z2; + assert( pIdx->aiColumn[k]>=0 ); + if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; + z1 = pIdx->azColl[k]; + z2 = pIndex->azColl[k]; + if( sqlite3StrICmp(z1, z2) ) break; + } + if( k==pIdx->nKeyCol ){ + if( pIdx->onError!=pIndex->onError ){ + /* This constraint creates the same index as a previous + ** constraint specified somewhere in the CREATE TABLE statement. + ** However the ON CONFLICT clauses are different. If both this + ** constraint and the previous equivalent constraint have explicit + ** ON CONFLICT clauses this is an error. Otherwise, use the + ** explicitly specified behavior for the index. + */ + if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){ + sqlite3ErrorMsg(pParse, + "conflicting ON CONFLICT clauses specified", 0); + } + if( pIdx->onError==OE_Default ){ + pIdx->onError = pIndex->onError; + } + } + if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; + goto exit_create_index; + } + } + } + + /* Link the new Index structure to its table and to the other + ** in-memory database structures. + */ + assert( pParse->nErr==0 ); + if( db->init.busy ){ + Index *p; + assert( !IN_DECLARE_VTAB ); + assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); + p = sqlite3HashInsert(&pIndex->pSchema->idxHash, + pIndex->zName, pIndex); + if( p ){ + assert( p==pIndex ); /* Malloc must have failed */ + sqlite3OomFault(db); + goto exit_create_index; + } + db->flags |= SQLITE_InternChanges; + if( pTblName!=0 ){ + pIndex->tnum = db->init.newTnum; + } + } + + /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the + ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then + ** emit code to allocate the index rootpage on disk and make an entry for + ** the index in the sqlite_master table and populate the index with + ** content. But, do not do this if we are simply reading the sqlite_master + ** table to parse the schema, or if this index is the PRIMARY KEY index + ** of a WITHOUT ROWID table. + ** + ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY + ** or UNIQUE index in a CREATE TABLE statement. Since the table + ** has just been created, it contains no data and the index initialization + ** step can be skipped. + */ + else if( HasRowid(pTab) || pTblName!=0 ){ + Vdbe *v; + char *zStmt; + int iMem = ++pParse->nMem; + + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto exit_create_index; + + sqlite3BeginWriteOperation(pParse, 1, iDb); + + /* Create the rootpage for the index using CreateIndex. But before + ** doing so, code a Noop instruction and store its address in + ** Index.tnum. This is required in case this index is actually a + ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In + ** 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); + + /* Gather the complete text of the CREATE INDEX statement into + ** the zStmt variable + */ + if( pStart ){ + int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; + if( pName->z[n-1]==';' ) n--; + /* A named index with an explicit CREATE INDEX statement */ + zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", + onError==OE_None ? "" : " UNIQUE", n, pName->z); + }else{ + /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ + /* zStmt = sqlite3MPrintf(""); */ + zStmt = 0; + } + + /* Add an entry in sqlite_master for this index + */ + sqlite3NestedParse(pParse, + "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", + db->aDb[iDb].zDbSName, MASTER_NAME, + pIndex->zName, + pTab->zName, + iMem, + zStmt + ); + sqlite3DbFree(db, zStmt); + + /* Fill the index with data and reparse the schema. Code an OP_Expire + ** to invalidate all pre-compiled statements. + */ + if( pTblName ){ + sqlite3RefillIndex(pParse, pIndex, iMem); + sqlite3ChangeCookie(pParse, iDb); + sqlite3VdbeAddParseSchemaOp(v, iDb, + sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); + sqlite3VdbeAddOp0(v, OP_Expire); + } + + sqlite3VdbeJumpHere(v, pIndex->tnum); + } + + /* When adding an index to the list of indices for a table, make + ** sure all indices labeled OE_Replace come after all those labeled + ** OE_Ignore. This is necessary for the correct constraint check + ** processing (in sqlite3GenerateConstraintChecks()) as part of + ** UPDATE and INSERT statements. + */ + if( db->init.busy || pTblName==0 ){ + if( onError!=OE_Replace || pTab->pIndex==0 + || pTab->pIndex->onError==OE_Replace){ + pIndex->pNext = pTab->pIndex; + pTab->pIndex = pIndex; + }else{ + Index *pOther = pTab->pIndex; + while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ + pOther = pOther->pNext; + } + pIndex->pNext = pOther->pNext; + pOther->pNext = pIndex; + } + pIndex = 0; + } + + /* Clean up before exiting */ +exit_create_index: + if( pIndex ) freeIndex(db, pIndex); + sqlite3ExprDelete(db, pPIWhere); + sqlite3ExprListDelete(db, pList); + sqlite3SrcListDelete(db, pTblName); + sqlite3DbFree(db, zName); +} + +/* +** Fill the Index.aiRowEst[] array with default information - information +** to be used when we have not run the ANALYZE command. +** +** aiRowEst[0] is supposed to contain the number of elements in the index. +** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the +** number of rows in the table that match any particular value of the +** first column of the index. aiRowEst[2] is an estimate of the number +** of rows that match any particular combination of the first 2 columns +** of the index. And so forth. It must always be the case that +* +** aiRowEst[N]<=aiRowEst[N-1] +** aiRowEst[N]>=1 +** +** Apart from that, we have little to go on besides intuition as to +** how aiRowEst[] should be initialized. The numbers generated here +** are based on typical values found in actual indices. +*/ +SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ + /* 10, 9, 8, 7, 6 */ + LogEst aVal[] = { 33, 32, 30, 28, 26 }; + LogEst *a = pIdx->aiRowLogEst; + int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); + int i; + + /* Indexes with default row estimates should not have stat1 data */ + assert( !pIdx->hasStat1 ); + + /* Set the first entry (number of rows in the index) to the estimated + ** number of rows in the table, or half the number of rows in the table + ** for a partial index. But do not let the estimate drop below 10. */ + a[0] = pIdx->pTable->nRowLogEst; + if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) ); + if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); + + /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is + ** 6 and each subsequent value (if any) is 5. */ + memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); + for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ + a[i] = 23; assert( 23==sqlite3LogEst(5) ); + } + + assert( 0==sqlite3LogEst(1) ); + if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0; +} + +/* +** This routine will drop an existing named index. This routine +** implements the DROP INDEX statement. +*/ +SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ + Index *pIndex; + Vdbe *v; + sqlite3 *db = pParse->db; + int iDb; + + assert( pParse->nErr==0 ); /* Never called with prior errors */ + if( db->mallocFailed ){ + goto exit_drop_index; + } + assert( pName->nSrc==1 ); + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + goto exit_drop_index; + } + pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); + if( pIndex==0 ){ + if( !ifExists ){ + sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); + }else{ + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + } + pParse->checkSchema = 1; + goto exit_drop_index; + } + if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){ + sqlite3ErrorMsg(pParse, "index associated with UNIQUE " + "or PRIMARY KEY constraint cannot be dropped", 0); + goto exit_drop_index; + } + iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); +#ifndef SQLITE_OMIT_AUTHORIZATION + { + int code = SQLITE_DROP_INDEX; + Table *pTab = pIndex->pTable; + const char *zDb = db->aDb[iDb].zDbSName; + const char *zTab = SCHEMA_TABLE(iDb); + if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ + goto exit_drop_index; + } + if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX; + if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ + goto exit_drop_index; + } + } +#endif + + /* Generate code to remove the index and from the master table */ + v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3BeginWriteOperation(pParse, 1, iDb); + sqlite3NestedParse(pParse, + "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", + db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName + ); + sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); + sqlite3ChangeCookie(pParse, iDb); + destroyRootPage(pParse, pIndex->tnum, iDb); + sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0); + } + +exit_drop_index: + sqlite3SrcListDelete(db, pName); +} + +/* +** pArray is a pointer to an array of objects. Each object in the +** array is szEntry bytes in size. This routine uses sqlite3DbRealloc() +** to extend the array so that there is space for a new object at the end. +** +** When this function is called, *pnEntry contains the current size of +** the array (in entries - so the allocation is ((*pnEntry) * szEntry) bytes +** in total). +** +** If the realloc() is successful (i.e. if no OOM condition occurs), the +** space allocated for the new object is zeroed, *pnEntry updated to +** reflect the new size of the array and a pointer to the new allocation +** returned. *pIdx is set to the index of the new array entry in this case. +** +** Otherwise, if the realloc() fails, *pIdx is set to -1, *pnEntry remains +** unchanged and a copy of pArray returned. +*/ +SQLITE_PRIVATE void *sqlite3ArrayAllocate( + sqlite3 *db, /* Connection to notify of malloc failures */ + void *pArray, /* Array of objects. Might be reallocated */ + int szEntry, /* Size of each object in the array */ + int *pnEntry, /* Number of objects currently in use */ + int *pIdx /* Write the index of a new slot here */ +){ + char *z; + int n = *pnEntry; + if( (n & (n-1))==0 ){ + int sz = (n==0) ? 1 : 2*n; + void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry); + if( pNew==0 ){ + *pIdx = -1; + return pArray; + } + pArray = pNew; + } + z = (char*)pArray; + memset(&z[n * szEntry], 0, szEntry); + *pIdx = n; + ++*pnEntry; + return pArray; +} + +/* +** Append a new element to the given IdList. Create a new IdList if +** need be. +** +** A new IdList is returned, or NULL if malloc() fails. +*/ +SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){ + int i; + if( pList==0 ){ + pList = sqlite3DbMallocZero(db, sizeof(IdList) ); + if( pList==0 ) return 0; + } + pList->a = sqlite3ArrayAllocate( + db, + pList->a, + sizeof(pList->a[0]), + &pList->nId, + &i + ); + if( i<0 ){ + sqlite3IdListDelete(db, pList); + return 0; + } + pList->a[i].zName = sqlite3NameFromToken(db, pToken); + return pList; +} + +/* +** Delete an IdList. +*/ +SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ + int i; + if( pList==0 ) return; + for(i=0; inId; i++){ + sqlite3DbFree(db, pList->a[i].zName); + } + sqlite3DbFree(db, pList->a); + sqlite3DbFreeNN(db, pList); +} + +/* +** Return the index in pList of the identifier named zId. Return -1 +** if not found. +*/ +SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){ + int i; + if( pList==0 ) return -1; + for(i=0; inId; i++){ + if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; + } + return -1; +} + +/* +** Expand the space allocated for the given SrcList object by +** creating nExtra new slots beginning at iStart. iStart is zero based. +** New slots are zeroed. +** +** For example, suppose a SrcList initially contains two entries: A,B. +** To append 3 new entries onto the end, do this: +** +** sqlite3SrcListEnlarge(db, pSrclist, 3, 2); +** +** After the call above it would contain: A, B, nil, nil, nil. +** If the iStart argument had been 1 instead of 2, then the result +** would have been: A, nil, nil, nil, B. To prepend the new slots, +** the iStart value would be 0. The result then would +** be: nil, nil, nil, A, B. +** +** If a memory allocation fails the SrcList is unchanged. The +** db->mallocFailed flag will be set to true. +*/ +SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( + sqlite3 *db, /* Database connection to notify of OOM errors */ + SrcList *pSrc, /* The SrcList to be enlarged */ + int nExtra, /* Number of new slots to add to pSrc->a[] */ + int iStart /* Index in pSrc->a[] of first new slot */ +){ + int i; + + /* Sanity checking on calling parameters */ + assert( iStart>=0 ); + assert( nExtra>=1 ); + assert( pSrc!=0 ); + assert( iStart<=pSrc->nSrc ); + + /* Allocate additional space if needed */ + if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ + SrcList *pNew; + int nAlloc = pSrc->nSrc*2+nExtra; + int nGot; + pNew = sqlite3DbRealloc(db, pSrc, + sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); + if( pNew==0 ){ + assert( db->mallocFailed ); + return pSrc; + } + pSrc = pNew; + nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1; + pSrc->nAlloc = nGot; + } + + /* Move existing slots that come after the newly inserted slots + ** out of the way */ + for(i=pSrc->nSrc-1; i>=iStart; i--){ + pSrc->a[i+nExtra] = pSrc->a[i]; + } + pSrc->nSrc += nExtra; + + /* Zero the newly allocated slots */ + memset(&pSrc->a[iStart], 0, sizeof(pSrc->a[0])*nExtra); + for(i=iStart; ia[i].iCursor = -1; + } + + /* Return a pointer to the enlarged SrcList */ + return pSrc; +} + + +/* +** Append a new table name to the given SrcList. Create a new SrcList if +** need be. A new entry is created in the SrcList even if pTable is NULL. +** +** A SrcList is returned, or NULL if there is an OOM error. The returned +** SrcList might be the same as the SrcList that was input or it might be +** a new one. If an OOM error does occurs, then the prior value of pList +** that is input to this routine is automatically freed. +** +** If pDatabase is not null, it means that the table has an optional +** database name prefix. Like this: "database.table". The pDatabase +** points to the table name and the pTable points to the database name. +** The SrcList.a[].zName field is filled with the table name which might +** come from pTable (if pDatabase is NULL) or from pDatabase. +** SrcList.a[].zDatabase is filled with the database name from pTable, +** or with NULL if no database is specified. +** +** In other words, if call like this: +** +** sqlite3SrcListAppend(D,A,B,0); +** +** Then B is a table name and the database name is unspecified. If called +** like this: +** +** sqlite3SrcListAppend(D,A,B,C); +** +** Then C is the table name and B is the database name. If C is defined +** then so is B. In other words, we never have a case where: +** +** sqlite3SrcListAppend(D,A,0,C); +** +** Both pTable and pDatabase are assumed to be quoted. They are dequoted +** before being added to the SrcList. +*/ +SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( + sqlite3 *db, /* Connection to notify of malloc failures */ + SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */ + Token *pTable, /* Table to append */ + Token *pDatabase /* Database of the table */ +){ + struct SrcList_item *pItem; + assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */ + assert( db!=0 ); + if( pList==0 ){ + pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) ); + if( pList==0 ) return 0; + pList->nAlloc = 1; + pList->nSrc = 1; + memset(&pList->a[0], 0, sizeof(pList->a[0])); + pList->a[0].iCursor = -1; + }else{ + pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc); + } + if( db->mallocFailed ){ + sqlite3SrcListDelete(db, pList); + return 0; + } + pItem = &pList->a[pList->nSrc-1]; + if( pDatabase && pDatabase->z==0 ){ + pDatabase = 0; + } + if( pDatabase ){ + Token *pTemp = pDatabase; + pDatabase = pTable; + pTable = pTemp; + } + pItem->zName = sqlite3NameFromToken(db, pTable); + pItem->zDatabase = sqlite3NameFromToken(db, pDatabase); + return pList; +} + +/* +** Assign VdbeCursor index numbers to all tables in a SrcList +*/ +SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ + int i; + struct SrcList_item *pItem; + assert(pList || pParse->db->mallocFailed ); + if( pList ){ + for(i=0, pItem=pList->a; inSrc; i++, pItem++){ + if( pItem->iCursor>=0 ) break; + pItem->iCursor = pParse->nTab++; + if( pItem->pSelect ){ + sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); + } + } + } +} + +/* +** Delete an entire SrcList including all its substructure. +*/ +SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ + int i; + struct SrcList_item *pItem; + if( pList==0 ) return; + for(pItem=pList->a, i=0; inSrc; i++, pItem++){ + sqlite3DbFree(db, pItem->zDatabase); + sqlite3DbFree(db, pItem->zName); + sqlite3DbFree(db, pItem->zAlias); + if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); + if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); + sqlite3DeleteTable(db, pItem->pTab); + sqlite3SelectDelete(db, pItem->pSelect); + sqlite3ExprDelete(db, pItem->pOn); + sqlite3IdListDelete(db, pItem->pUsing); + } + sqlite3DbFreeNN(db, pList); +} + +/* +** This routine is called by the parser to add a new term to the +** end of a growing FROM clause. The "p" parameter is the part of +** the FROM clause that has already been constructed. "p" is NULL +** if this is the first term of the FROM clause. pTable and pDatabase +** are the name of the table and database named in the FROM clause term. +** pDatabase is NULL if the database name qualifier is missing - the +** usual case. If the term has an alias, then pAlias points to the +** alias token. If the term is a subquery, then pSubquery is the +** SELECT statement that the subquery encodes. The pTable and +** pDatabase parameters are NULL for subqueries. The pOn and pUsing +** parameters are the content of the ON and USING clauses. +** +** Return a new SrcList which encodes is the FROM with the new +** term added. +*/ +SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( + Parse *pParse, /* Parsing context */ + SrcList *p, /* The left part of the FROM clause already seen */ + Token *pTable, /* Name of the table to add to the FROM clause */ + Token *pDatabase, /* Name of the database containing pTable */ + Token *pAlias, /* The right-hand side of the AS subexpression */ + Select *pSubquery, /* A subquery used in place of a table name */ + Expr *pOn, /* The ON clause of a join */ + IdList *pUsing /* The USING clause of a join */ +){ + struct SrcList_item *pItem; + sqlite3 *db = pParse->db; + if( !p && (pOn || pUsing) ){ + sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", + (pOn ? "ON" : "USING") + ); + goto append_from_error; + } + p = sqlite3SrcListAppend(db, p, pTable, pDatabase); + if( p==0 || NEVER(p->nSrc==0) ){ + goto append_from_error; + } + pItem = &p->a[p->nSrc-1]; + assert( pAlias!=0 ); + if( pAlias->n ){ + pItem->zAlias = sqlite3NameFromToken(db, pAlias); + } + pItem->pSelect = pSubquery; + pItem->pOn = pOn; + pItem->pUsing = pUsing; + return p; + + append_from_error: + assert( p==0 ); + sqlite3ExprDelete(db, pOn); + sqlite3IdListDelete(db, pUsing); + sqlite3SelectDelete(db, pSubquery); + return 0; +} + +/* +** Add an INDEXED BY or NOT INDEXED clause to the most recently added +** element of the source-list passed as the second argument. +*/ +SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ + assert( pIndexedBy!=0 ); + if( p && ALWAYS(p->nSrc>0) ){ + struct SrcList_item *pItem = &p->a[p->nSrc-1]; + assert( pItem->fg.notIndexed==0 ); + assert( pItem->fg.isIndexedBy==0 ); + assert( pItem->fg.isTabFunc==0 ); + if( pIndexedBy->n==1 && !pIndexedBy->z ){ + /* A "NOT INDEXED" clause was supplied. See parse.y + ** construct "indexed_opt" for details. */ + pItem->fg.notIndexed = 1; + }else{ + pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); + pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0); + } + } +} + +/* +** Add the list of function arguments to the SrcList entry for a +** table-valued-function. +*/ +SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ + if( p ){ + struct SrcList_item *pItem = &p->a[p->nSrc-1]; + assert( pItem->fg.notIndexed==0 ); + assert( pItem->fg.isIndexedBy==0 ); + assert( pItem->fg.isTabFunc==0 ); + pItem->u1.pFuncArg = pList; + pItem->fg.isTabFunc = 1; + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } +} + +/* +** When building up a FROM clause in the parser, the join operator +** is initially attached to the left operand. But the code generator +** expects the join operator to be on the right operand. This routine +** Shifts all join operators from left to right for an entire FROM +** clause. +** +** Example: Suppose the join is like this: +** +** A natural cross join B +** +** The operator is "natural cross join". The A and B operands are stored +** in p->a[0] and p->a[1], respectively. The parser initially stores the +** operator with A. This routine shifts that operator over to B. +*/ +SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){ + if( p ){ + int i; + for(i=p->nSrc-1; i>0; i--){ + p->a[i].fg.jointype = p->a[i-1].fg.jointype; + } + p->a[0].fg.jointype = 0; + } +} + +/* +** Generate VDBE code for a BEGIN statement. +*/ +SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ + sqlite3 *db; + Vdbe *v; + int i; + + assert( pParse!=0 ); + db = pParse->db; + assert( db!=0 ); + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ + return; + } + v = sqlite3GetVdbe(pParse); + if( !v ) return; + if( type!=TK_DEFERRED ){ + for(i=0; inDb; i++){ + sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); + sqlite3VdbeUsesBtree(v, i); + } + } + sqlite3VdbeAddOp0(v, OP_AutoCommit); +} + +/* +** Generate VDBE code for a COMMIT statement. +*/ +SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){ + Vdbe *v; + + assert( pParse!=0 ); + assert( pParse->db!=0 ); + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){ + return; + } + v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp1(v, OP_AutoCommit, 1); + } +} + +/* +** Generate VDBE code for a ROLLBACK statement. +*/ +SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){ + Vdbe *v; + + assert( pParse!=0 ); + assert( pParse->db!=0 ); + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){ + return; + } + v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1); + } +} + +/* +** This function is called by the parser when it parses a command to create, +** release or rollback an SQL savepoint. +*/ +SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){ + char *zName = sqlite3NameFromToken(pParse->db, pName); + if( zName ){ + Vdbe *v = sqlite3GetVdbe(pParse); +#ifndef SQLITE_OMIT_AUTHORIZATION + static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" }; + assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 ); +#endif + if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){ + sqlite3DbFree(pParse->db, zName); + return; + } + sqlite3VdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC); + } +} + +/* +** Make sure the TEMP database is open and available for use. Return +** the number of errors. Leave any error messages in the pParse structure. +*/ +SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ + sqlite3 *db = pParse->db; + if( db->aDb[1].pBt==0 && !pParse->explain ){ + int rc; + Btree *pBt; + static const int flags = + SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE | + SQLITE_OPEN_EXCLUSIVE | + SQLITE_OPEN_DELETEONCLOSE | + SQLITE_OPEN_TEMP_DB; + + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags); + if( rc!=SQLITE_OK ){ + sqlite3ErrorMsg(pParse, "unable to open a temporary database " + "file for storing temporary tables"); + pParse->rc = rc; + return 1; + } + db->aDb[1].pBt = pBt; + assert( db->aDb[1].pSchema ); + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){ + sqlite3OomFault(db); + return 1; + } + } + return 0; +} + +/* +** Record the fact that the schema cookie will need to be verified +** for database iDb. The code to actually verify the schema cookie +** will occur at the end of the top-level VDBE and will be generated +** later, by sqlite3FinishCoding(). +*/ +SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + + assert( iDb>=0 && iDbdb->nDb ); + assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 ); + assert( iDbdb, iDb, 0) ); + if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ + DbMaskSet(pToplevel->cookieMask, iDb); + if( !OMIT_TEMPDB && iDb==1 ){ + sqlite3OpenTempDatabase(pToplevel); + } + } +} + +/* +** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each +** attached database. Otherwise, invoke it for the database named zDb only. +*/ +SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ + sqlite3 *db = pParse->db; + int i; + for(i=0; inDb; i++){ + Db *pDb = &db->aDb[i]; + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){ + sqlite3CodeVerifySchema(pParse, i); + } + } +} + +/* +** Generate VDBE code that prepares for doing an operation that +** might change the database. +** +** This routine starts a new transaction if we are not already within +** a transaction. If we are already within a transaction, then a checkpoint +** is set if the setStatement parameter is true. A checkpoint should +** be set for operations that might fail (due to a constraint) part of +** the way through and which will need to undo some writes without having to +** rollback the whole transaction. For operations where all constraints +** can be checked before any changes are made to the database, it is never +** necessary to undo a write and the checkpoint should not be set. +*/ +SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + sqlite3CodeVerifySchema(pParse, iDb); + DbMaskSet(pToplevel->writeMask, iDb); + pToplevel->isMultiWrite |= setStatement; +} + +/* +** Indicate that the statement currently under construction might write +** more than one entry (example: deleting one row then inserting another, +** inserting multiple rows in a table, or inserting a row and index entries.) +** If an abort occurs after some of these writes have completed, then it will +** be necessary to undo the completed writes. +*/ +SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + pToplevel->isMultiWrite = 1; +} + +/* +** The code generator calls this routine if is discovers that it is +** possible to abort a statement prior to completion. In order to +** perform this abort without corrupting the database, we need to make +** sure that the statement is protected by a statement transaction. +** +** Technically, we only need to set the mayAbort flag if the +** isMultiWrite flag was previously set. There is a time dependency +** such that the abort must occur after the multiwrite. This makes +** some statements involving the REPLACE conflict resolution algorithm +** go a little faster. But taking advantage of this time dependency +** makes it more difficult to prove that the code is correct (in +** particular, it prevents us from writing an effective +** implementation of sqlite3AssertMayAbort()) and so we have chosen +** to take the safe route and skip the optimization. +*/ +SQLITE_PRIVATE void sqlite3MayAbort(Parse *pParse){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + pToplevel->mayAbort = 1; +} + +/* +** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT +** error. The onError parameter determines which (if any) of the statement +** and/or current transaction is rolled back. +*/ +SQLITE_PRIVATE void sqlite3HaltConstraint( + Parse *pParse, /* Parsing context */ + int errCode, /* extended error code */ + int onError, /* Constraint type */ + char *p4, /* Error message */ + i8 p4type, /* P4_STATIC or P4_TRANSIENT */ + u8 p5Errmsg /* P5_ErrMsg type */ +){ + Vdbe *v = sqlite3GetVdbe(pParse); + assert( (errCode&0xff)==SQLITE_CONSTRAINT ); + if( onError==OE_Abort ){ + sqlite3MayAbort(pParse); + } + sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); + sqlite3VdbeChangeP5(v, p5Errmsg); +} + +/* +** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation. +*/ +SQLITE_PRIVATE void sqlite3UniqueConstraint( + Parse *pParse, /* Parsing context */ + int onError, /* Constraint type */ + Index *pIdx /* The index that triggers the constraint */ +){ + char *zErr; + int j; + StrAccum errMsg; + Table *pTab = pIdx->pTable; + + sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); + if( pIdx->aColExpr ){ + sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName); + }else{ + for(j=0; jnKeyCol; j++){ + char *zCol; + assert( pIdx->aiColumn[j]>=0 ); + zCol = pTab->aCol[pIdx->aiColumn[j]].zName; + if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); + sqlite3XPrintf(&errMsg, "%s.%s", pTab->zName, zCol); + } + } + zErr = sqlite3StrAccumFinish(&errMsg); + sqlite3HaltConstraint(pParse, + IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY + : SQLITE_CONSTRAINT_UNIQUE, + onError, zErr, P4_DYNAMIC, P5_ConstraintUnique); +} + + +/* +** Code an OP_Halt due to non-unique rowid. +*/ +SQLITE_PRIVATE void sqlite3RowidConstraint( + Parse *pParse, /* Parsing context */ + int onError, /* Conflict resolution algorithm */ + Table *pTab /* The table with the non-unique rowid */ +){ + char *zMsg; + int rc; + if( pTab->iPKey>=0 ){ + zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName, + pTab->aCol[pTab->iPKey].zName); + rc = SQLITE_CONSTRAINT_PRIMARYKEY; + }else{ + zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName); + rc = SQLITE_CONSTRAINT_ROWID; + } + sqlite3HaltConstraint(pParse, rc, onError, zMsg, P4_DYNAMIC, + P5_ConstraintUnique); +} + +/* +** Check to see if pIndex uses the collating sequence pColl. Return +** true if it does and false if it does not. +*/ +#ifndef SQLITE_OMIT_REINDEX +static int collationMatch(const char *zColl, Index *pIndex){ + int i; + assert( zColl!=0 ); + for(i=0; inColumn; i++){ + const char *z = pIndex->azColl[i]; + assert( z!=0 || pIndex->aiColumn[i]<0 ); + if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){ + return 1; + } + } + return 0; +} +#endif + +/* +** Recompute all indices of pTab that use the collating sequence pColl. +** If pColl==0 then recompute all indices of pTab. +*/ +#ifndef SQLITE_OMIT_REINDEX +static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ + Index *pIndex; /* An index associated with pTab */ + + for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ + if( zColl==0 || collationMatch(zColl, pIndex) ){ + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3RefillIndex(pParse, pIndex, -1); + } + } +} +#endif + +/* +** Recompute all indices of all tables in all databases where the +** indices use the collating sequence pColl. If pColl==0 then recompute +** all indices everywhere. +*/ +#ifndef SQLITE_OMIT_REINDEX +static void reindexDatabases(Parse *pParse, char const *zColl){ + Db *pDb; /* A single database */ + int iDb; /* The database index number */ + sqlite3 *db = pParse->db; /* The database connection */ + HashElem *k; /* For looping over tables in pDb */ + Table *pTab; /* A table in the database */ + + assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */ + for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ + assert( pDb!=0 ); + for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + reindexTable(pParse, pTab, zColl); + } + } +} +#endif + +/* +** Generate code for the REINDEX command. +** +** REINDEX -- 1 +** REINDEX -- 2 +** REINDEX ?.? -- 3 +** REINDEX ?.? -- 4 +** +** Form 1 causes all indices in all attached databases to be rebuilt. +** Form 2 rebuilds all indices in all databases that use the named +** collating function. Forms 3 and 4 rebuild the named index or all +** indices associated with the named table. +*/ +#ifndef SQLITE_OMIT_REINDEX +SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ + CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */ + char *z; /* Name of a table or index */ + const char *zDb; /* Name of the database */ + Table *pTab; /* A table in the database */ + Index *pIndex; /* An index associated with pTab */ + int iDb; /* The database index number */ + sqlite3 *db = pParse->db; /* The database connection */ + Token *pObjName; /* Name of the table or index to be reindexed */ + + /* Read the database schema. If an error occurs, leave an error message + ** and code in pParse and return NULL. */ + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + return; + } + + if( pName1==0 ){ + reindexDatabases(pParse, 0); + return; + }else if( NEVER(pName2==0) || pName2->z==0 ){ + char *zColl; + assert( pName1->z ); + zColl = sqlite3NameFromToken(pParse->db, pName1); + if( !zColl ) return; + pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); + if( pColl ){ + reindexDatabases(pParse, zColl); + sqlite3DbFree(db, zColl); + return; + } + sqlite3DbFree(db, zColl); + } + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); + if( iDb<0 ) return; + z = sqlite3NameFromToken(db, pObjName); + if( z==0 ) return; + zDb = db->aDb[iDb].zDbSName; + pTab = sqlite3FindTable(db, z, zDb); + if( pTab ){ + reindexTable(pParse, pTab, 0); + sqlite3DbFree(db, z); + return; + } + pIndex = sqlite3FindIndex(db, z, zDb); + sqlite3DbFree(db, z); + if( pIndex ){ + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3RefillIndex(pParse, pIndex, -1); + return; + } + sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); +} +#endif + +/* +** Return a KeyInfo structure that is appropriate for the given Index. +** +** The caller should invoke sqlite3KeyInfoUnref() on the returned object +** when it has finished using it. +*/ +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ + int i; + int nCol = pIdx->nColumn; + int nKey = pIdx->nKeyCol; + KeyInfo *pKey; + if( pParse->nErr ) return 0; + if( pIdx->uniqNotNull ){ + pKey = sqlite3KeyInfoAlloc(pParse->db, nKey, nCol-nKey); + }else{ + pKey = sqlite3KeyInfoAlloc(pParse->db, nCol, 0); + } + if( pKey ){ + assert( sqlite3KeyInfoIsWriteable(pKey) ); + for(i=0; iazColl[i]; + pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : + sqlite3LocateCollSeq(pParse, zColl); + pKey->aSortOrder[i] = pIdx->aSortOrder[i]; + } + if( pParse->nErr ){ + sqlite3KeyInfoUnref(pKey); + pKey = 0; + } + } + return pKey; +} + +#ifndef SQLITE_OMIT_CTE +/* +** This routine is invoked once per CTE by the parser while parsing a +** WITH clause. +*/ +SQLITE_PRIVATE With *sqlite3WithAdd( + Parse *pParse, /* Parsing context */ + With *pWith, /* Existing WITH clause, or NULL */ + Token *pName, /* Name of the common-table */ + ExprList *pArglist, /* Optional column name list for the table */ + Select *pQuery /* Query used to initialize the table */ +){ + sqlite3 *db = pParse->db; + With *pNew; + char *zName; + + /* Check that the CTE name is unique within this WITH clause. If + ** not, store an error in the Parse structure. */ + zName = sqlite3NameFromToken(pParse->db, pName); + if( zName && pWith ){ + int i; + for(i=0; inCte; i++){ + if( sqlite3StrICmp(zName, pWith->a[i].zName)==0 ){ + sqlite3ErrorMsg(pParse, "duplicate WITH table name: %s", zName); + } + } + } + + if( pWith ){ + int nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); + pNew = sqlite3DbRealloc(db, pWith, nByte); + }else{ + pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); + } + assert( (pNew!=0 && zName!=0) || db->mallocFailed ); + + if( db->mallocFailed ){ + sqlite3ExprListDelete(db, pArglist); + sqlite3SelectDelete(db, pQuery); + sqlite3DbFree(db, zName); + pNew = pWith; + }else{ + pNew->a[pNew->nCte].pSelect = pQuery; + pNew->a[pNew->nCte].pCols = pArglist; + pNew->a[pNew->nCte].zName = zName; + pNew->a[pNew->nCte].zCteErr = 0; + pNew->nCte++; + } + + return pNew; +} + +/* +** Free the contents of the With object passed as the second argument. +*/ +SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){ + if( pWith ){ + int i; + for(i=0; inCte; i++){ + struct Cte *pCte = &pWith->a[i]; + sqlite3ExprListDelete(db, pCte->pCols); + sqlite3SelectDelete(db, pCte->pSelect); + sqlite3DbFree(db, pCte->zName); + } + sqlite3DbFree(db, pWith); + } +} +#endif /* !defined(SQLITE_OMIT_CTE) */ + +/************** End of build.c ***********************************************/ +/************** Begin file callback.c ****************************************/ +/* +** 2005 May 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file contains functions used to access the internal hash tables +** of user defined functions and collation sequences. +*/ + +/* #include "sqliteInt.h" */ + +/* +** Invoke the 'collation needed' callback to request a collation sequence +** in the encoding enc of name zName, length nName. +*/ +static void callCollNeeded(sqlite3 *db, int enc, const char *zName){ + assert( !db->xCollNeeded || !db->xCollNeeded16 ); + if( db->xCollNeeded ){ + char *zExternal = sqlite3DbStrDup(db, zName); + if( !zExternal ) return; + db->xCollNeeded(db->pCollNeededArg, db, enc, zExternal); + sqlite3DbFree(db, zExternal); + } +#ifndef SQLITE_OMIT_UTF16 + if( db->xCollNeeded16 ){ + char const *zExternal; + sqlite3_value *pTmp = sqlite3ValueNew(db); + sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC); + zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); + if( zExternal ){ + db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal); + } + sqlite3ValueFree(pTmp); + } +#endif +} + +/* +** This routine is called if the collation factory fails to deliver a +** collation function in the best encoding but there may be other versions +** of this collation function (for other text encodings) available. Use one +** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if +** possible. +*/ +static int synthCollSeq(sqlite3 *db, CollSeq *pColl){ + CollSeq *pColl2; + char *z = pColl->zName; + int i; + static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 }; + for(i=0; i<3; i++){ + pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, 0); + if( pColl2->xCmp!=0 ){ + memcpy(pColl, pColl2, sizeof(CollSeq)); + pColl->xDel = 0; /* Do not copy the destructor */ + return SQLITE_OK; + } + } + return SQLITE_ERROR; +} + +/* +** This function is responsible for invoking the collation factory callback +** or substituting a collation sequence of a different encoding when the +** requested collation sequence is not available in the desired encoding. +** +** If it is not NULL, then pColl must point to the database native encoding +** collation sequence with name zName, length nName. +** +** The return value is either the collation sequence to be used in database +** db for collation type name zName, length nName, or NULL, if no collation +** sequence can be found. If no collation is found, leave an error message. +** +** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq() +*/ +SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( + Parse *pParse, /* Parsing context */ + u8 enc, /* The desired encoding for the collating sequence */ + CollSeq *pColl, /* Collating sequence with native encoding, or NULL */ + const char *zName /* Collating sequence name */ +){ + CollSeq *p; + sqlite3 *db = pParse->db; + + p = pColl; + if( !p ){ + p = sqlite3FindCollSeq(db, enc, zName, 0); + } + if( !p || !p->xCmp ){ + /* No collation sequence of this type for this encoding is registered. + ** Call the collation factory to see if it can supply us with one. + */ + callCollNeeded(db, enc, zName); + p = sqlite3FindCollSeq(db, enc, zName, 0); + } + if( p && !p->xCmp && synthCollSeq(db, p) ){ + p = 0; + } + assert( !p || p->xCmp ); + if( p==0 ){ + sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); + } + return p; +} + +/* +** This routine is called on a collation sequence before it is used to +** check that it is defined. An undefined collation sequence exists when +** a database is loaded that contains references to collation sequences +** that have not been defined by sqlite3_create_collation() etc. +** +** If required, this routine calls the 'collation needed' callback to +** request a definition of the collating sequence. If this doesn't work, +** an equivalent collating sequence that uses a text encoding different +** from the main database is substituted, if one is available. +*/ +SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ + if( pColl ){ + const char *zName = pColl->zName; + sqlite3 *db = pParse->db; + CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName); + if( !p ){ + return SQLITE_ERROR; + } + assert( p==pColl ); + } + return SQLITE_OK; +} + + + +/* +** Locate and return an entry from the db.aCollSeq hash table. If the entry +** specified by zName and nName is not found and parameter 'create' is +** true, then create a new entry. Otherwise return NULL. +** +** Each pointer stored in the sqlite3.aCollSeq hash table contains an +** array of three CollSeq structures. The first is the collation sequence +** preferred for UTF-8, the second UTF-16le, and the third UTF-16be. +** +** Stored immediately after the three collation sequences is a copy of +** the collation sequence name. A pointer to this string is stored in +** each collation sequence structure. +*/ +static CollSeq *findCollSeqEntry( + sqlite3 *db, /* Database connection */ + const char *zName, /* Name of the collating sequence */ + int create /* Create a new entry if true */ +){ + CollSeq *pColl; + pColl = sqlite3HashFind(&db->aCollSeq, zName); + + if( 0==pColl && create ){ + int nName = sqlite3Strlen30(zName); + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1); + if( pColl ){ + CollSeq *pDel = 0; + pColl[0].zName = (char*)&pColl[3]; + pColl[0].enc = SQLITE_UTF8; + pColl[1].zName = (char*)&pColl[3]; + pColl[1].enc = SQLITE_UTF16LE; + pColl[2].zName = (char*)&pColl[3]; + pColl[2].enc = SQLITE_UTF16BE; + memcpy(pColl[0].zName, zName, nName); + pColl[0].zName[nName] = 0; + pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl); + + /* If a malloc() failure occurred in sqlite3HashInsert(), it will + ** return the pColl pointer to be deleted (because it wasn't added + ** to the hash table). + */ + assert( pDel==0 || pDel==pColl ); + if( pDel!=0 ){ + sqlite3OomFault(db); + sqlite3DbFree(db, pDel); + pColl = 0; + } + } + } + return pColl; +} + +/* +** Parameter zName points to a UTF-8 encoded string nName bytes long. +** Return the CollSeq* pointer for the collation sequence named zName +** for the encoding 'enc' from the database 'db'. +** +** If the entry specified is not found and 'create' is true, then create a +** new entry. Otherwise return NULL. +** +** A separate function sqlite3LocateCollSeq() is a wrapper around +** this routine. sqlite3LocateCollSeq() invokes the collation factory +** if necessary and generates an error message if the collating sequence +** cannot be found. +** +** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq() +*/ +SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq( + sqlite3 *db, + u8 enc, + const char *zName, + int create +){ + CollSeq *pColl; + if( zName ){ + pColl = findCollSeqEntry(db, zName, create); + }else{ + pColl = db->pDfltColl; + } + assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); + if( pColl ) pColl += enc-1; + return pColl; +} + +/* During the search for the best function definition, this procedure +** is called to test how well the function passed as the first argument +** matches the request for a function with nArg arguments in a system +** that uses encoding enc. The value returned indicates how well the +** request is matched. A higher value indicates a better match. +** +** If nArg is -1 that means to only return a match (non-zero) if p->nArg +** is also -1. In other words, we are searching for a function that +** takes a variable number of arguments. +** +** If nArg is -2 that means that we are searching for any function +** regardless of the number of arguments it uses, so return a positive +** match score for any +** +** The returned value is always between 0 and 6, as follows: +** +** 0: Not a match. +** 1: UTF8/16 conversion required and function takes any number of arguments. +** 2: UTF16 byte order change required and function takes any number of args. +** 3: encoding matches and function takes any number of arguments +** 4: UTF8/16 conversion required - argument count matches exactly +** 5: UTF16 byte order conversion required - argument count matches exactly +** 6: Perfect match: encoding and argument count match exactly. +** +** If nArg==(-2) then any function with a non-null xSFunc is +** a perfect match and any function with xSFunc NULL is +** a non-match. +*/ +#define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */ +static int matchQuality( + FuncDef *p, /* The function we are evaluating for match quality */ + int nArg, /* Desired number of arguments. (-1)==any */ + u8 enc /* Desired text encoding */ +){ + int match; + + /* nArg of -2 is a special case */ + if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; + + /* Wrong number of arguments means "no match" */ + if( p->nArg!=nArg && p->nArg>=0 ) return 0; + + /* Give a better score to a function with a specific number of arguments + ** than to function that accepts any number of arguments. */ + if( p->nArg==nArg ){ + match = 4; + }else{ + match = 1; + } + + /* Bonus points if the text encoding matches */ + if( enc==(p->funcFlags & SQLITE_FUNC_ENCMASK) ){ + match += 2; /* Exact encoding match */ + }else if( (enc & p->funcFlags & 2)!=0 ){ + match += 1; /* Both are UTF16, but with different byte orders */ + } + + return match; +} + +/* +** Search a FuncDefHash for a function with the given name. Return +** a pointer to the matching FuncDef if found, or 0 if there is no match. +*/ +static FuncDef *functionSearch( + int h, /* Hash of the name */ + const char *zFunc /* Name of function */ +){ + FuncDef *p; + for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ + if( sqlite3StrICmp(p->zName, zFunc)==0 ){ + return p; + } + } + return 0; +} + +/* +** Insert a new FuncDef into a FuncDefHash hash table. +*/ +SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( + FuncDef *aDef, /* List of global functions to be inserted */ + int nDef /* Length of the apDef[] list */ +){ + int i; + for(i=0; ipNext!=&aDef[i] ); + aDef[i].pNext = pOther->pNext; + pOther->pNext = &aDef[i]; + }else{ + aDef[i].pNext = 0; + aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h]; + sqlite3BuiltinFunctions.a[h] = &aDef[i]; + } + } +} + + + +/* +** Locate a user function given a name, a number of arguments and a flag +** indicating whether the function prefers UTF-16 over UTF-8. Return a +** pointer to the FuncDef structure that defines that function, or return +** NULL if the function does not exist. +** +** If the createFlag argument is true, then a new (blank) FuncDef +** structure is created and liked into the "db" structure if a +** no matching function previously existed. +** +** If nArg is -2, then the first valid function found is returned. A +** function is valid if xSFunc is non-zero. The nArg==(-2) +** case is used to see if zName is a valid function name for some number +** of arguments. If nArg is -2, then createFlag must be 0. +** +** If createFlag is false, then a function with the required name and +** number of arguments may be returned even if the eTextRep flag does not +** match that requested. +*/ +SQLITE_PRIVATE FuncDef *sqlite3FindFunction( + sqlite3 *db, /* An open database */ + const char *zName, /* Name of the function. zero-terminated */ + int nArg, /* Number of arguments. -1 means any number */ + u8 enc, /* Preferred text encoding */ + u8 createFlag /* Create new entry if true and does not otherwise exist */ +){ + FuncDef *p; /* Iterator variable */ + FuncDef *pBest = 0; /* Best match found so far */ + int bestScore = 0; /* Score of best match */ + int h; /* Hash value */ + int nName; /* Length of the name */ + + assert( nArg>=(-2) ); + assert( nArg>=(-1) || createFlag==0 ); + nName = sqlite3Strlen30(zName); + + /* First search for a match amongst the application-defined functions. + */ + p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName); + while( p ){ + int score = matchQuality(p, nArg, enc); + if( score>bestScore ){ + pBest = p; + bestScore = score; + } + p = p->pNext; + } + + /* If no match is found, search the built-in functions. + ** + ** If the SQLITE_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. + ** + ** Except, if createFlag is true, that means that we are trying to + ** install a new function. Whatever FuncDef structure is returned it will + ** have fields overwritten with new information appropriate for the + ** new function. But the FuncDefs for built-in functions are read-only. + ** So we must not search for built-ins when creating a new function. + */ + if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){ + bestScore = 0; + h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; + p = functionSearch(h, zName); + while( p ){ + int score = matchQuality(p, nArg, enc); + if( score>bestScore ){ + pBest = p; + bestScore = score; + } + p = p->pNext; + } + } + + /* If the createFlag parameter is true and the search did not reveal an + ** exact match for the name, number of arguments and encoding, then add a + ** new entry to the hash table and return it. + */ + if( createFlag && bestScorezName = (const char*)&pBest[1]; + pBest->nArg = (u16)nArg; + pBest->funcFlags = enc; + memcpy((char*)&pBest[1], zName, nName+1); + pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest); + if( pOther==pBest ){ + sqlite3DbFree(db, pBest); + sqlite3OomFault(db); + return 0; + }else{ + pBest->pNext = pOther; + } + } + + if( pBest && (pBest->xSFunc || createFlag) ){ + return pBest; + } + return 0; +} + +/* +** Free all resources held by the schema structure. The void* argument points +** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the +** pointer itself, it just cleans up subsidiary resources (i.e. the contents +** of the schema hash tables). +** +** The Schema.cache_size variable is not cleared. +*/ +SQLITE_PRIVATE void sqlite3SchemaClear(void *p){ + Hash temp1; + Hash temp2; + HashElem *pElem; + Schema *pSchema = (Schema *)p; + + temp1 = pSchema->tblHash; + temp2 = pSchema->trigHash; + sqlite3HashInit(&pSchema->trigHash); + sqlite3HashClear(&pSchema->idxHash); + for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ + sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem)); + } + sqlite3HashClear(&temp2); + sqlite3HashInit(&pSchema->tblHash); + for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ + Table *pTab = sqliteHashData(pElem); + sqlite3DeleteTable(0, pTab); + } + sqlite3HashClear(&temp1); + sqlite3HashClear(&pSchema->fkeyHash); + pSchema->pSeqTab = 0; + if( pSchema->schemaFlags & DB_SchemaLoaded ){ + pSchema->iGeneration++; + pSchema->schemaFlags &= ~DB_SchemaLoaded; + } +} + +/* +** Find and return the schema associated with a BTree. Create +** a new one if necessary. +*/ +SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ + Schema * p; + if( pBt ){ + p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear); + }else{ + p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema)); + } + if( !p ){ + sqlite3OomFault(db); + }else if ( 0==p->file_format ){ + sqlite3HashInit(&p->tblHash); + sqlite3HashInit(&p->idxHash); + sqlite3HashInit(&p->trigHash); + sqlite3HashInit(&p->fkeyHash); + p->enc = SQLITE_UTF8; + } + return p; +} + +/************** End of callback.c ********************************************/ +/************** Begin file delete.c ******************************************/ +/* +** 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 C code routines that are called by the parser +** in order to generate code for DELETE FROM statements. +*/ +/* #include "sqliteInt.h" */ + +/* +** While a SrcList can in general represent multiple tables and subqueries +** (as in the FROM clause of a SELECT statement) in this case it contains +** the name of a single table, as one might find in an INSERT, DELETE, +** or UPDATE statement. Look up that table in the symbol table and +** return a pointer. Set an error message and return NULL if the table +** name is not found or if any other error occurs. +** +** The following fields are initialized appropriate in pSrc: +** +** pSrc->a[0].pTab Pointer to the Table object +** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one +** +*/ +SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ + struct SrcList_item *pItem = pSrc->a; + Table *pTab; + assert( pItem && pSrc->nSrc==1 ); + pTab = sqlite3LocateTableItem(pParse, 0, pItem); + sqlite3DeleteTable(pParse->db, pItem->pTab); + pItem->pTab = pTab; + if( pTab ){ + pTab->nTabRef++; + } + if( sqlite3IndexedByLookup(pParse, pItem) ){ + pTab = 0; + } + return pTab; +} + +/* +** Check to make sure the given table is writable. If it is not +** writable, generate an error message and return 1. If it is +** writable return 0; +*/ +SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ + /* A table is not writable under the following circumstances: + ** + ** 1) It is a virtual table and no implementation of the xUpdate method + ** has been provided, or + ** 2) It is a system table (i.e. sqlite_master), this call is not + ** part of a nested parse and writable_schema pragma has not + ** been specified. + ** + ** In either case leave an error message in pParse and return non-zero. + */ + if( ( IsVirtual(pTab) + && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ) + || ( (pTab->tabFlags & TF_Readonly)!=0 + && (pParse->db->flags & SQLITE_WriteSchema)==0 + && pParse->nested==0 ) + ){ + sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); + return 1; + } + +#ifndef SQLITE_OMIT_VIEW + if( !viewOk && pTab->pSelect ){ + sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); + return 1; + } +#endif + return 0; +} + + +#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) +/* +** Evaluate a view and store its result in an ephemeral table. The +** pWhere argument is an optional WHERE clause that restricts the +** set of rows in the view that are to be added to the ephemeral table. +*/ +SQLITE_PRIVATE void sqlite3MaterializeView( + Parse *pParse, /* Parsing context */ + Table *pView, /* View definition */ + Expr *pWhere, /* Optional WHERE clause to be added */ + int iCur /* Cursor number for ephemeral table */ +){ + SelectDest dest; + Select *pSel; + SrcList *pFrom; + sqlite3 *db = pParse->db; + int iDb = sqlite3SchemaToIndex(db, pView->pSchema); + pWhere = sqlite3ExprDup(db, pWhere, 0); + pFrom = sqlite3SrcListAppend(db, 0, 0, 0); + if( pFrom ){ + assert( pFrom->nSrc==1 ); + pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); + pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + assert( pFrom->a[0].pOn==0 ); + assert( pFrom->a[0].pUsing==0 ); + } + pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, + SF_IncludeHidden, 0, 0); + sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); + sqlite3Select(pParse, pSel, &dest); + sqlite3SelectDelete(db, pSel); +} +#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */ + +#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) +/* +** Generate an expression tree to implement the WHERE, ORDER BY, +** and LIMIT/OFFSET portion of DELETE and UPDATE statements. +** +** DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1; +** \__________________________/ +** pLimitWhere (pInClause) +*/ +SQLITE_PRIVATE Expr *sqlite3LimitWhere( + Parse *pParse, /* The parser context */ + SrcList *pSrc, /* the FROM clause -- which tables to scan */ + Expr *pWhere, /* The WHERE clause. May be null */ + ExprList *pOrderBy, /* The ORDER BY clause. May be null */ + Expr *pLimit, /* The LIMIT clause. May be null */ + Expr *pOffset, /* The OFFSET clause. May be null */ + char *zStmtType /* Either DELETE or UPDATE. For err msgs. */ +){ + Expr *pWhereRowid = NULL; /* WHERE rowid .. */ + Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */ + Expr *pSelectRowid = NULL; /* SELECT rowid ... */ + ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */ + SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */ + Select *pSelect = NULL; /* Complete SELECT tree */ + + /* Check that there isn't an ORDER BY without a LIMIT clause. + */ + if( pOrderBy && (pLimit == 0) ) { + sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType); + goto limit_where_cleanup; + } + + /* We only need to generate a select expression if there + ** is a limit/offset term to enforce. + */ + if( pLimit == 0 ) { + /* if pLimit is null, pOffset will always be null as well. */ + assert( pOffset == 0 ); + return pWhere; + } + + /* Generate a select expression tree to enforce the limit/offset + ** term for the DELETE or UPDATE statement. For example: + ** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1 + ** becomes: + ** DELETE FROM table_a WHERE rowid IN ( + ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1 + ** ); + */ + + pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0); + if( pSelectRowid == 0 ) goto limit_where_cleanup; + pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid); + if( pEList == 0 ) goto limit_where_cleanup; + + /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree + ** and the SELECT subtree. */ + pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0); + if( pSelectSrc == 0 ) { + sqlite3ExprListDelete(pParse->db, pEList); + goto limit_where_cleanup; + } + + /* generate the SELECT expression tree. */ + pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0, + pOrderBy,0,pLimit,pOffset); + if( pSelect == 0 ) return 0; + + /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */ + pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0); + pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0) : 0; + sqlite3PExprAddSelect(pParse, pInClause, pSelect); + return pInClause; + +limit_where_cleanup: + sqlite3ExprDelete(pParse->db, pWhere); + sqlite3ExprListDelete(pParse->db, pOrderBy); + sqlite3ExprDelete(pParse->db, pLimit); + sqlite3ExprDelete(pParse->db, pOffset); + return 0; +} +#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */ + /* && !defined(SQLITE_OMIT_SUBQUERY) */ + +/* +** Generate code for a DELETE FROM statement. +** +** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL; +** \________/ \________________/ +** pTabList pWhere +*/ +SQLITE_PRIVATE void sqlite3DeleteFrom( + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* The table from which we should delete things */ + Expr *pWhere /* The WHERE clause. May be null */ +){ + Vdbe *v; /* The virtual database engine */ + Table *pTab; /* The table from which records will be deleted */ + int i; /* Loop counter */ + WhereInfo *pWInfo; /* Information about the WHERE clause */ + Index *pIdx; /* For looping over indices of the table */ + int iTabCur; /* Cursor number for the table */ + int iDataCur = 0; /* VDBE cursor for the canonical data source */ + int iIdxCur = 0; /* Cursor number of the first index */ + int nIdx; /* Number of indices */ + sqlite3 *db; /* Main database structure */ + AuthContext sContext; /* Authorization context */ + NameContext sNC; /* Name context to resolve expressions in */ + int iDb; /* Database number */ + int memCnt = -1; /* Memory cell used for change counting */ + int rcauth; /* Value returned by authorization callback */ + int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */ + int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ + u8 *aToOpen = 0; /* Open cursor iTabCur+j if aToOpen[j] is true */ + Index *pPk; /* The PRIMARY KEY index on the table */ + int iPk = 0; /* First of nPk registers holding PRIMARY KEY value */ + i16 nPk = 1; /* Number of columns in the PRIMARY KEY */ + int iKey; /* Memory cell holding key of row to be deleted */ + i16 nKey; /* Number of memory cells in the row key */ + int iEphCur = 0; /* Ephemeral table holding all primary key values */ + int iRowSet = 0; /* Register for rowset of rows to delete */ + int addrBypass = 0; /* Address of jump over the delete logic */ + int addrLoop = 0; /* Top of the delete loop */ + int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ + int bComplex; /* True if there are triggers or FKs or + ** subqueries in the WHERE clause */ + +#ifndef SQLITE_OMIT_TRIGGER + int isView; /* True if attempting to delete from a view */ + Trigger *pTrigger; /* List of table triggers, if required */ +#endif + + memset(&sContext, 0, sizeof(sContext)); + db = pParse->db; + if( pParse->nErr || db->mallocFailed ){ + goto delete_from_cleanup; + } + assert( pTabList->nSrc==1 ); + + /* Locate the table which we want to delete. This table has to be + ** put in an SrcList structure because some of the subroutines we + ** will be calling are designed to work with multiple tables and expect + ** an SrcList* parameter instead of just a Table* parameter. + */ + pTab = sqlite3SrcListLookup(pParse, pTabList); + if( pTab==0 ) goto delete_from_cleanup; + + /* Figure out if we have any triggers and if the table being + ** deleted from is a view + */ +#ifndef SQLITE_OMIT_TRIGGER + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); + isView = pTab->pSelect!=0; + bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); +#else +# define pTrigger 0 +# define isView 0 +#endif +#ifdef SQLITE_OMIT_VIEW +# undef isView +# define isView 0 +#endif + + /* If pTab is really a view, make sure it has been initialized. + */ + if( sqlite3ViewGetColumnNames(pParse, pTab) ){ + goto delete_from_cleanup; + } + + if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){ + goto delete_from_cleanup; + } + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDbnDb ); + rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, + db->aDb[iDb].zDbSName); + assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); + if( rcauth==SQLITE_DENY ){ + goto delete_from_cleanup; + } + assert(!isView || pTrigger); + + /* Assign cursor numbers to the table and all its indices. + */ + assert( pTabList->nSrc==1 ); + iTabCur = pTabList->a[0].iCursor = pParse->nTab++; + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ + pParse->nTab++; + } + + /* Start the view context + */ + if( isView ){ + sqlite3AuthContextPush(pParse, &sContext, pTab->zName); + } + + /* Begin generating code. + */ + v = sqlite3GetVdbe(pParse); + if( v==0 ){ + goto delete_from_cleanup; + } + if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); + sqlite3BeginWriteOperation(pParse, 1, iDb); + + /* If we are trying to delete from a view, realize that view into + ** an ephemeral table. + */ +#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) + if( isView ){ + sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur); + iDataCur = iIdxCur = iTabCur; + } +#endif + + /* Resolve the column names in the WHERE clause. + */ + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + sNC.pSrcList = pTabList; + if( sqlite3ResolveExprNames(&sNC, pWhere) ){ + goto delete_from_cleanup; + } + + /* Initialize the counter of the number of rows deleted, if + ** we are counting rows. + */ + if( db->flags & SQLITE_CountRows ){ + memCnt = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); + } + +#ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION + /* Special case: A DELETE without a WHERE clause deletes everything. + ** It is easier just to erase the whole table. Prior to version 3.6.5, + ** this optimization caused the row change count (the value returned by + ** API function sqlite3_count_changes) to be set incorrectly. + ** + ** The "rcauth==SQLITE_OK" terms is the + ** IMPLEMENATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and + ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but + ** the truncate optimization is disabled and all rows are deleted + ** individually. + */ + if( rcauth==SQLITE_OK + && pWhere==0 + && !bComplex + && !IsVirtual(pTab) +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + && db->xPreUpdateCallback==0 +#endif + ){ + assert( !isView ); + sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt, + pTab->zName, P4_STATIC); + } + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + assert( pIdx->pSchema==pTab->pSchema ); + sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); + } + }else +#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ + { + u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE; + if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; + wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); + if( HasRowid(pTab) ){ + /* For a rowid table, initialize the RowSet to an empty set */ + pPk = 0; + nPk = 1; + iRowSet = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); + }else{ + /* For a WITHOUT ROWID table, create an ephemeral table used to + ** hold all primary keys for rows to be deleted. */ + pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); + nPk = pPk->nKeyCol; + iPk = pParse->nMem+1; + pParse->nMem += nPk; + iEphCur = pParse->nTab++; + addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); + } + + /* Construct a query to find the rowid or primary key for every row + ** to be deleted, based on the WHERE clause. Set variable eOnePass + ** to indicate the strategy used to implement this delete: + ** + ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values. + ** ONEPASS_SINGLE: One-pass approach - at most one row deleted. + ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. + */ + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); + if( pWInfo==0 ) goto delete_from_cleanup; + eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); + assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); + assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); + + /* Keep track of the number of rows to be deleted */ + if( db->flags & SQLITE_CountRows ){ + sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); + } + + /* Extract the rowid or primary key for the current row */ + if( pPk ){ + for(i=0; iaiColumn[i]>=0 ); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, + pPk->aiColumn[i], iPk+i); + } + iKey = iPk; + }else{ + iKey = pParse->nMem + 1; + iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0); + if( iKey>pParse->nMem ) pParse->nMem = iKey; + } + + if( eOnePass!=ONEPASS_OFF ){ + /* For ONEPASS, no need to store the rowid/primary-key. There is only + ** one, so just keep it in its register(s) and fall through to the + ** delete code. */ + nKey = nPk; /* OP_Found will use an unpacked key */ + aToOpen = sqlite3DbMallocRawNN(db, nIdx+2); + if( aToOpen==0 ){ + sqlite3WhereEnd(pWInfo); + goto delete_from_cleanup; + } + memset(aToOpen, 1, nIdx+1); + aToOpen[nIdx+1] = 0; + if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0; + if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0; + if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); + }else{ + if( pPk ){ + /* Add the PK key for this row to the temporary table */ + iKey = ++pParse->nMem; + nKey = 0; /* Zero tells OP_Found to use a composite key */ + sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, + sqlite3IndexAffinityStr(pParse->db, pPk), nPk); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); + }else{ + /* Add the rowid of the row to be deleted to the RowSet */ + nKey = 1; /* OP_Seek always uses a single rowid */ + sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); + } + } + + /* If this DELETE cannot use the ONEPASS strategy, this is the + ** end of the WHERE loop */ + if( eOnePass!=ONEPASS_OFF ){ + addrBypass = sqlite3VdbeMakeLabel(v); + }else{ + sqlite3WhereEnd(pWInfo); + } + + /* Unless this is a view, open cursors for the table we are + ** deleting from and all its indices. If this is a view, then the + ** only effect this statement has is to fire the INSTEAD OF + ** triggers. + */ + if( !isView ){ + int iAddrOnce = 0; + if( eOnePass==ONEPASS_MULTI ){ + iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } + testcase( IsVirtual(pTab) ); + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE, + iTabCur, aToOpen, &iDataCur, &iIdxCur); + assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); + assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); + if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce); + } + + /* Set up a loop over the rowids/primary-keys that were found in the + ** where-clause loop above. + */ + if( eOnePass!=ONEPASS_OFF ){ + assert( nKey==nPk ); /* OP_Found will use an unpacked key */ + if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ + assert( pPk!=0 || pTab->pSelect!=0 ); + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); + VdbeCoverage(v); + } + }else if( pPk ){ + addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); + 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); + VdbeCoverage(v); + assert( nKey==1 ); + } + + /* Delete the row */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); + sqlite3VtabMakeWritable(pParse, pTab); + sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); + sqlite3VdbeChangeP5(v, OE_Abort); + assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); + sqlite3MayAbort(pParse); + if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){ + pParse->isMultiWrite = 0; + } + }else +#endif + { + int count = (pParse->nested==0); /* True to count changes */ + sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, + iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]); + } + + /* End of the loop over all rowids/primary-keys. */ + if( eOnePass!=ONEPASS_OFF ){ + sqlite3VdbeResolveLabel(v, addrBypass); + sqlite3WhereEnd(pWInfo); + }else if( pPk ){ + sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrLoop); + }else{ + sqlite3VdbeGoto(v, addrLoop); + sqlite3VdbeJumpHere(v, addrLoop); + } + } /* End non-truncate path */ + + /* Update the sqlite_sequence table by storing the content of the + ** maximum rowid counter values recorded while inserting into + ** autoincrement tables. + */ + if( pParse->nested==0 && pParse->pTriggerTab==0 ){ + sqlite3AutoincrementEnd(pParse); + } + + /* Return the number of rows that were deleted. If this routine is + ** generating code because of a call to sqlite3NestedParse(), do not + ** invoke the callback function. + */ + if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ + sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1); + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC); + } + +delete_from_cleanup: + sqlite3AuthContextPop(&sContext); + sqlite3SrcListDelete(db, pTabList); + sqlite3ExprDelete(db, pWhere); + sqlite3DbFree(db, aToOpen); + return; +} +/* Make sure "isView" and other macros defined above are undefined. Otherwise +** they may interfere with compilation of other functions in this file +** (or in another file, if this file becomes part of the amalgamation). */ +#ifdef isView + #undef isView +#endif +#ifdef pTrigger + #undef pTrigger +#endif + +/* +** This routine generates VDBE code that causes a single row of a +** single table to be deleted. Both the original table entry and +** all indices are removed. +** +** Preconditions: +** +** 1. iDataCur is an open cursor on the btree that is the canonical data +** store for the table. (This will be either the table itself, +** in the case of a rowid table, or the PRIMARY KEY index in the case +** of a WITHOUT ROWID table.) +** +** 2. Read/write cursors for all indices of pTab must be open as +** cursor number iIdxCur+i for the i-th index. +** +** 3. The primary key for the row to be deleted must be stored in a +** sequence of nPk memory cells starting at iPk. If nPk==0 that means +** that a search record formed from OP_MakeRecord is contained in the +** single memory location iPk. +** +** eMode: +** Parameter eMode may be passed either ONEPASS_OFF (0), ONEPASS_SINGLE, or +** ONEPASS_MULTI. If eMode is not ONEPASS_OFF, then the cursor +** iDataCur already points to the row to delete. If eMode is ONEPASS_OFF +** then this function must seek iDataCur to the entry identified by iPk +** and nPk before reading from it. +** +** If eMode is ONEPASS_MULTI, then this call is being made as part +** of a ONEPASS delete that affects multiple rows. In this case, if +** iIdxNoSeek is a valid cursor number (>=0) and is not the same as +** iDataCur, then its position should be preserved following the delete +** operation. Or, if iIdxNoSeek is not a valid cursor number, the +** position of iDataCur should be preserved instead. +** +** iIdxNoSeek: +** If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur, +** then it identifies an index cursor (from within array of cursors +** starting at iIdxCur) that already points to the index entry to be deleted. +** Except, this optimization is disabled if there are BEFORE triggers since +** the trigger body might have moved the cursor. +*/ +SQLITE_PRIVATE void sqlite3GenerateRowDelete( + Parse *pParse, /* Parsing context */ + Table *pTab, /* Table containing the row to be deleted */ + Trigger *pTrigger, /* List of triggers to (potentially) fire */ + int iDataCur, /* Cursor from which column data is extracted */ + int iIdxCur, /* First index cursor */ + int iPk, /* First memory cell containing the PRIMARY KEY */ + i16 nPk, /* Number of PRIMARY KEY memory cells */ + u8 count, /* If non-zero, increment the row change counter */ + u8 onconf, /* Default ON CONFLICT policy for triggers */ + u8 eMode, /* ONEPASS_OFF, _SINGLE, or _MULTI. See above */ + int iIdxNoSeek /* Cursor number of cursor that does not need seeking */ +){ + Vdbe *v = pParse->pVdbe; /* Vdbe */ + int iOld = 0; /* First register in OLD.* array */ + int iLabel; /* Label resolved to end of generated code */ + u8 opSeek; /* Seek opcode */ + + /* Vdbe is guaranteed to have been allocated by this stage. */ + assert( v ); + VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)", + iDataCur, iIdxCur, iPk, (int)nPk)); + + /* Seek cursor iCur to the row to delete. If this row no longer exists + ** (this can happen if a trigger program has already deleted it), do + ** not attempt to delete it or fire any DELETE triggers. */ + iLabel = sqlite3VdbeMakeLabel(v); + opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound; + if( eMode==ONEPASS_OFF ){ + sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); + VdbeCoverageIf(v, opSeek==OP_NotExists); + VdbeCoverageIf(v, opSeek==OP_NotFound); + } + + /* If there are any triggers to fire, allocate a range of registers to + ** use for the old.* references in the triggers. */ + if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){ + u32 mask; /* Mask of OLD.* columns in use */ + int iCol; /* Iterator used while populating OLD.* */ + int addrStart; /* Start of BEFORE trigger programs */ + + /* TODO: Could use temporary registers here. Also could attempt to + ** avoid copying the contents of the rowid register. */ + mask = sqlite3TriggerColmask( + pParse, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf + ); + mask |= sqlite3FkOldmask(pParse, pTab); + iOld = pParse->nMem+1; + pParse->nMem += (1 + pTab->nCol); + + /* Populate the OLD.* pseudo-table register array. These values will be + ** used by any BEFORE and AFTER triggers that exist. */ + sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld); + for(iCol=0; iColnCol; iCol++){ + testcase( mask!=0xffffffff && iCol==31 ); + testcase( mask!=0xffffffff && iCol==32 ); + if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1); + } + } + + /* Invoke BEFORE DELETE trigger programs. */ + addrStart = sqlite3VdbeCurrentAddr(v); + sqlite3CodeRowTrigger(pParse, pTrigger, + TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel + ); + + /* If any BEFORE triggers were coded, then seek the cursor to the + ** row to be deleted again. It may be that the BEFORE triggers moved + ** the cursor or already deleted the row that the cursor was + ** pointing to. + ** + ** Also disable the iIdxNoSeek optimization since the BEFORE trigger + ** may have moved that cursor. + */ + if( addrStart=0 ); + iIdxNoSeek = -1; + } + + /* Do FK processing. This call checks that any FK constraints that + ** refer to this table (i.e. constraints attached to other tables) + ** are not violated by deleting this row. */ + sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0); + } + + /* Delete the index and table entries. Skip this step if pTab is really + ** a view (in which case the only effect of the DELETE statement is to + ** fire the INSTEAD OF triggers). + ** + ** If variable 'count' is non-zero, then this OP_Delete instruction should + ** invoke the update-hook. The pre-update-hook, on the other hand should + ** be invoked unless table pTab is a system table. The difference is that + ** the update-hook is not invoked for rows removed by REPLACE, but the + ** pre-update-hook is. + */ + if( pTab->pSelect==0 ){ + u8 p5 = 0; + sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); + if( pParse->nested==0 ){ + sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); + } + if( eMode!=ONEPASS_OFF ){ + sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE); + } + if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){ + sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek); + } + if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION; + sqlite3VdbeChangeP5(v, p5); + } + + /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to + ** handle rows (possibly in other tables) that refer via a foreign key + ** to the row just deleted. */ + sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0); + + /* Invoke AFTER DELETE trigger programs. */ + sqlite3CodeRowTrigger(pParse, pTrigger, + TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel + ); + + /* Jump here if the row had already been deleted before any BEFORE + ** trigger programs were invoked. Or if a trigger program throws a + ** RAISE(IGNORE) exception. */ + sqlite3VdbeResolveLabel(v, iLabel); + VdbeModuleComment((v, "END: GenRowDel()")); +} + +/* +** This routine generates VDBE code that causes the deletion of all +** index entries associated with a single row of a single table, pTab +** +** Preconditions: +** +** 1. A read/write cursor "iDataCur" must be open on the canonical storage +** btree for the table pTab. (This will be either the table itself +** for rowid tables or to the primary key index for WITHOUT ROWID +** tables.) +** +** 2. Read/write cursors for all indices of pTab must be open as +** cursor number iIdxCur+i for the i-th index. (The pTab->pIndex +** index is the 0-th index.) +** +** 3. The "iDataCur" cursor must be already be positioned on the row +** that is to be deleted. +*/ +SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( + Parse *pParse, /* Parsing and code generating context */ + Table *pTab, /* Table containing the row to be deleted */ + int iDataCur, /* Cursor of table holding data. */ + int iIdxCur, /* First index cursor */ + int *aRegIdx, /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */ + int iIdxNoSeek /* Do not delete from this cursor */ +){ + int i; /* Index loop counter */ + int r1 = -1; /* Register holding an index key */ + int iPartIdxLabel; /* Jump destination for skipping partial index entries */ + Index *pIdx; /* Current index */ + Index *pPrior = 0; /* Prior index */ + Vdbe *v; /* The prepared statement under construction */ + Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */ + + v = pParse->pVdbe; + pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); + for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ + assert( iIdxCur+i!=iDataCur || pPk==pIdx ); + if( aRegIdx!=0 && aRegIdx[i]==0 ) continue; + if( pIdx==pPk ) continue; + if( iIdxCur+i==iIdxNoSeek ) continue; + VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, + &iPartIdxLabel, pPrior, r1); + sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, + pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); + sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); + pPrior = pIdx; + } +} + +/* +** Generate code that will assemble an index key and stores it in register +** regOut. The key with be for index pIdx which is an index on pTab. +** iCur is the index of a cursor open on the pTab table and pointing to +** the entry that needs indexing. If pTab is a WITHOUT ROWID table, then +** iCur must be the cursor of the PRIMARY KEY index. +** +** Return a register number which is the first in a block of +** registers that holds the elements of the index key. The +** block of registers has already been deallocated by the time +** this routine returns. +** +** If *piPartIdxLabel is not NULL, fill it in with a label and jump +** to that label if pIdx is a partial index that should be skipped. +** The label should be resolved using sqlite3ResolvePartIdxLabel(). +** A partial index should be skipped if its WHERE clause evaluates +** to false or null. If pIdx is not a partial index, *piPartIdxLabel +** will be set to zero which is an empty label that is ignored by +** sqlite3ResolvePartIdxLabel(). +** +** The pPrior and regPrior parameters are used to implement a cache to +** avoid unnecessary register loads. If pPrior is not NULL, then it is +** a pointer to a different index for which an index key has just been +** computed into register regPrior. If the current pIdx index is generating +** its key into the same sequence of registers and if pPrior and pIdx share +** a column in common, then the register corresponding to that column already +** holds the correct value and the loading of that register is skipped. +** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK +** on a table with multiple indices, and especially with the ROWID or +** PRIMARY KEY columns of the index. +*/ +SQLITE_PRIVATE int sqlite3GenerateIndexKey( + Parse *pParse, /* Parsing context */ + Index *pIdx, /* The index for which to generate a key */ + int iDataCur, /* Cursor number from which to take column data */ + int regOut, /* Put the new key into this register if not 0 */ + int prefixOnly, /* Compute only a unique prefix of the key */ + int *piPartIdxLabel, /* OUT: Jump to this label to skip partial index */ + Index *pPrior, /* Previously generated index key */ + int regPrior /* Register holding previous generated key */ +){ + Vdbe *v = pParse->pVdbe; + int j; + int regBase; + int nCol; + + if( piPartIdxLabel ){ + if( pIdx->pPartIdxWhere ){ + *piPartIdxLabel = sqlite3VdbeMakeLabel(v); + pParse->iSelfTab = iDataCur; + sqlite3ExprCachePush(pParse); + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, + SQLITE_JUMPIFNULL); + }else{ + *piPartIdxLabel = 0; + } + } + nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; + regBase = sqlite3GetTempRange(pParse, nCol); + if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; + for(j=0; jaiColumn[j]==pIdx->aiColumn[j] + && pPrior->aiColumn[j]!=XN_EXPR + ){ + /* This column was already computed by the previous index */ + continue; + } + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); + /* If the column affinity is REAL but the number is an integer, then it + ** might be stored in the table as an integer (using a compact + ** representation) then converted to REAL by an OP_RealAffinity opcode. + ** But we are getting ready to store this value back into an index, where + ** it should be converted by to INTEGER again. So omit the OP_RealAffinity + ** opcode if it is present */ + sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); + } + if( regOut ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); + if( pIdx->pTable->pSelect ){ + const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx); + sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT); + } + } + sqlite3ReleaseTempRange(pParse, regBase, nCol); + return regBase; +} + +/* +** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label +** because it was a partial index, then this routine should be called to +** resolve that label. +*/ +SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ + if( iLabel ){ + sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); + sqlite3ExprCachePop(pParse); + } +} + +/************** End of delete.c **********************************************/ +/************** Begin file func.c ********************************************/ +/* +** 2002 February 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains the C-language implementations for many of the SQL +** functions of SQLite. (Some function, and in particular the date and +** time functions, are implemented separately.) +*/ +/* #include "sqliteInt.h" */ +/* #include */ +/* #include */ +/* #include "vdbeInt.h" */ + +/* +** Return the collating function associated with a function. +*/ +static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ + VdbeOp *pOp; + assert( context->pVdbe!=0 ); + pOp = &context->pVdbe->aOp[context->iOp-1]; + assert( pOp->opcode==OP_CollSeq ); + assert( pOp->p4type==P4_COLLSEQ ); + return pOp->p4.pColl; +} + +/* +** Indicate that the accumulator load should be skipped on this +** iteration of the aggregate loop. +*/ +static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){ + context->skipFlag = 1; +} + +/* +** Implementation of the non-aggregate min() and max() functions +*/ +static void minmaxFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int i; + int mask; /* 0 for min() or 0xffffffff for max() */ + int iBest; + CollSeq *pColl; + + assert( argc>1 ); + mask = sqlite3_user_data(context)==0 ? 0 : -1; + pColl = sqlite3GetFuncCollSeq(context); + assert( pColl ); + assert( mask==-1 || mask==0 ); + iBest = 0; + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + for(i=1; i=0 ){ + testcase( mask==0 ); + iBest = i; + } + } + sqlite3_result_value(context, argv[iBest]); +} + +/* +** Return the type of the argument. +*/ +static void typeofFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + const char *z = 0; + UNUSED_PARAMETER(NotUsed); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_INTEGER: z = "integer"; break; + case SQLITE_TEXT: z = "text"; break; + case SQLITE_FLOAT: z = "real"; break; + case SQLITE_BLOB: z = "blob"; break; + default: z = "null"; break; + } + sqlite3_result_text(context, z, -1, SQLITE_STATIC); +} + + +/* +** Implementation of the length() function +*/ +static void lengthFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int len; + + assert( argc==1 ); + UNUSED_PARAMETER(argc); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_BLOB: + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); + break; + } + case SQLITE_TEXT: { + const unsigned char *z = sqlite3_value_text(argv[0]); + if( z==0 ) return; + len = 0; + while( *z ){ + len++; + SQLITE_SKIP_UTF8(z); + } + sqlite3_result_int(context, len); + break; + } + default: { + sqlite3_result_null(context); + break; + } + } +} + +/* +** Implementation of the abs() function. +** +** IMP: R-23979-26855 The abs(X) function returns the absolute value of +** the numeric argument X. +*/ +static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + assert( argc==1 ); + UNUSED_PARAMETER(argc); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_INTEGER: { + i64 iVal = sqlite3_value_int64(argv[0]); + if( iVal<0 ){ + if( iVal==SMALLEST_INT64 ){ + /* IMP: R-31676-45509 If X is the integer -9223372036854775808 + ** then abs(X) throws an integer overflow error since there is no + ** equivalent positive 64-bit two complement value. */ + sqlite3_result_error(context, "integer overflow", -1); + return; + } + iVal = -iVal; + } + sqlite3_result_int64(context, iVal); + break; + } + case SQLITE_NULL: { + /* IMP: R-37434-19929 Abs(X) returns NULL if X is NULL. */ + sqlite3_result_null(context); + break; + } + default: { + /* Because sqlite3_value_double() returns 0.0 if the argument is not + ** something that can be converted into a number, we have: + ** IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob + ** that cannot be converted to a numeric value. + */ + double rVal = sqlite3_value_double(argv[0]); + if( rVal<0 ) rVal = -rVal; + sqlite3_result_double(context, rVal); + break; + } + } +} + +/* +** Implementation of the instr() function. +** +** instr(haystack,needle) finds the first occurrence of needle +** in haystack and returns the number of previous characters plus 1, +** or 0 if needle does not occur within haystack. +** +** If both haystack and needle are BLOBs, then the result is one more than +** the number of bytes in haystack prior to the first occurrence of needle, +** or 0 if needle never occurs in haystack. +*/ +static void instrFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zHaystack; + const unsigned char *zNeedle; + int nHaystack; + int nNeedle; + int typeHaystack, typeNeedle; + int N = 1; + int isText; + + UNUSED_PARAMETER(argc); + typeHaystack = sqlite3_value_type(argv[0]); + typeNeedle = sqlite3_value_type(argv[1]); + if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; + nHaystack = sqlite3_value_bytes(argv[0]); + nNeedle = sqlite3_value_bytes(argv[1]); + if( nNeedle>0 ){ + if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ + zHaystack = sqlite3_value_blob(argv[0]); + zNeedle = sqlite3_value_blob(argv[1]); + isText = 0; + }else{ + zHaystack = sqlite3_value_text(argv[0]); + zNeedle = sqlite3_value_text(argv[1]); + isText = 1; + } + if( zNeedle==0 || (nHaystack && zHaystack==0) ) return; + while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ + N++; + do{ + nHaystack--; + zHaystack++; + }while( isText && (zHaystack[0]&0xc0)==0x80 ); + } + if( nNeedle>nHaystack ) N = 0; + } + sqlite3_result_int(context, N); +} + +/* +** Implementation of the printf() function. +*/ +static void printfFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + PrintfArguments x; + StrAccum str; + const char *zFormat; + int n; + sqlite3 *db = sqlite3_context_db_handle(context); + + if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){ + x.nArg = argc-1; + x.nUsed = 0; + x.apArg = argv+1; + sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); + str.printfFlags = SQLITE_PRINTF_SQLFUNC; + sqlite3XPrintf(&str, zFormat, &x); + n = str.nChar; + sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, + SQLITE_DYNAMIC); + } +} + +/* +** Implementation of the substr() function. +** +** substr(x,p1,p2) returns p2 characters of x[] beginning with p1. +** p1 is 1-indexed. So substr(x,1,1) returns the first character +** of x. If x is text, then we actually count UTF-8 characters. +** If x is a blob, then we count bytes. +** +** If p1 is negative, then we begin abs(p1) from the end of x[]. +** +** If p2 is negative, return the p2 characters preceding p1. +*/ +static void substrFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *z; + const unsigned char *z2; + int len; + int p0type; + i64 p1, p2; + int negP2 = 0; + + assert( argc==3 || argc==2 ); + if( sqlite3_value_type(argv[1])==SQLITE_NULL + || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL) + ){ + return; + } + p0type = sqlite3_value_type(argv[0]); + p1 = sqlite3_value_int(argv[1]); + if( p0type==SQLITE_BLOB ){ + len = sqlite3_value_bytes(argv[0]); + z = sqlite3_value_blob(argv[0]); + if( z==0 ) return; + assert( len==sqlite3_value_bytes(argv[0]) ); + }else{ + z = sqlite3_value_text(argv[0]); + if( z==0 ) return; + len = 0; + if( p1<0 ){ + for(z2=z; *z2; len++){ + SQLITE_SKIP_UTF8(z2); + } + } + } +#ifdef SQLITE_SUBSTR_COMPATIBILITY + /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as + ** as substr(X,1,N) - it returns the first N characters of X. This + ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] + ** from 2009-02-02 for compatibility of applications that exploited the + ** old buggy behavior. */ + if( p1==0 ) p1 = 1; /* */ +#endif + if( argc==3 ){ + p2 = sqlite3_value_int(argv[2]); + if( p2<0 ){ + p2 = -p2; + negP2 = 1; + } + }else{ + p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH]; + } + if( p1<0 ){ + p1 += len; + if( p1<0 ){ + p2 += p1; + if( p2<0 ) p2 = 0; + p1 = 0; + } + }else if( p1>0 ){ + p1--; + }else if( p2>0 ){ + p2--; + } + if( negP2 ){ + p1 -= p2; + if( p1<0 ){ + p2 += p1; + p1 = 0; + } + } + assert( p1>=0 && p2>=0 ); + if( p0type!=SQLITE_BLOB ){ + while( *z && p1 ){ + SQLITE_SKIP_UTF8(z); + p1--; + } + for(z2=z; *z2 && p2; p2--){ + SQLITE_SKIP_UTF8(z2); + } + sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT, + SQLITE_UTF8); + }else{ + if( p1+p2>len ){ + p2 = len-p1; + if( p2<0 ) p2 = 0; + } + sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT); + } +} + +/* +** Implementation of the round() function +*/ +#ifndef SQLITE_OMIT_FLOATING_POINT +static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + int n = 0; + double r; + char *zBuf; + assert( argc==1 || argc==2 ); + if( argc==2 ){ + if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return; + n = sqlite3_value_int(argv[1]); + if( n>30 ) n = 30; + if( n<0 ) n = 0; + } + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + r = sqlite3_value_double(argv[0]); + /* If Y==0 and X will fit in a 64-bit int, + ** handle the rounding directly, + ** otherwise use printf. + */ + if( n==0 && r>=0 && r0 ); + testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] ); + testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); + if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + sqlite3_result_error_toobig(context); + z = 0; + }else{ + z = sqlite3Malloc(nByte); + if( !z ){ + sqlite3_result_error_nomem(context); + } + } + return z; +} + +/* +** Implementation of the upper() and lower() SQL functions. +*/ +static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + char *z1; + const char *z2; + int i, n; + UNUSED_PARAMETER(argc); + z2 = (char*)sqlite3_value_text(argv[0]); + n = sqlite3_value_bytes(argv[0]); + /* Verify that the call to _bytes() does not invalidate the _text() pointer */ + assert( z2==(char*)sqlite3_value_text(argv[0]) ); + if( z2 ){ + z1 = contextMalloc(context, ((i64)n)+1); + if( z1 ){ + for(i=0; imatchOne; /* "?" or "_" */ + u32 matchAll = pInfo->matchAll; /* "*" or "%" */ + u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ + const u8 *zEscaped = 0; /* One past the last escaped input char */ + + while( (c = Utf8Read(zPattern))!=0 ){ + if( c==matchAll ){ /* Match "*" */ + /* Skip over multiple "*" characters in the pattern. If there + ** are also "?" characters, skip those as well, but consume a + ** single character of the input string for each "?" skipped */ + while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){ + if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ + return SQLITE_NOWILDCARDMATCH; + } + } + if( c==0 ){ + return SQLITE_MATCH; /* "*" at the end of the pattern matches */ + }else if( c==matchOther ){ + if( pInfo->matchSet==0 ){ + c = sqlite3Utf8Read(&zPattern); + if( c==0 ) return SQLITE_NOWILDCARDMATCH; + }else{ + /* "[...]" immediately follows the "*". We have to do a slow + ** recursive search in this case, but it is an unusual case. */ + assert( matchOther<0x80 ); /* '[' is a single-byte character */ + while( *zString ){ + int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther); + if( bMatch!=SQLITE_NOMATCH ) return bMatch; + SQLITE_SKIP_UTF8(zString); + } + return SQLITE_NOWILDCARDMATCH; + } + } + + /* At this point variable c contains the first character of the + ** pattern string past the "*". Search in the input string for the + ** first matching character and recursively continue the match from + ** that point. + ** + ** For a case-insensitive search, set variable cx to be the same as + ** c but in the other case and search the input string for either + ** c or cx. + */ + if( c<=0x80 ){ + u32 cx; + int bMatch; + if( noCase ){ + cx = sqlite3Toupper(c); + c = sqlite3Tolower(c); + }else{ + cx = c; + } + while( (c2 = *(zString++))!=0 ){ + if( c2!=c && c2!=cx ) continue; + bMatch = patternCompare(zPattern,zString,pInfo,matchOther); + if( bMatch!=SQLITE_NOMATCH ) return bMatch; + } + }else{ + int bMatch; + while( (c2 = Utf8Read(zString))!=0 ){ + if( c2!=c ) continue; + bMatch = patternCompare(zPattern,zString,pInfo,matchOther); + if( bMatch!=SQLITE_NOMATCH ) return bMatch; + } + } + return SQLITE_NOWILDCARDMATCH; + } + if( c==matchOther ){ + if( pInfo->matchSet==0 ){ + c = sqlite3Utf8Read(&zPattern); + if( c==0 ) return SQLITE_NOMATCH; + zEscaped = zPattern; + }else{ + u32 prior_c = 0; + int seen = 0; + int invert = 0; + c = sqlite3Utf8Read(&zString); + if( c==0 ) return SQLITE_NOMATCH; + c2 = sqlite3Utf8Read(&zPattern); + if( c2=='^' ){ + invert = 1; + c2 = sqlite3Utf8Read(&zPattern); + } + if( c2==']' ){ + if( c==']' ) seen = 1; + c2 = sqlite3Utf8Read(&zPattern); + } + while( c2 && c2!=']' ){ + if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ + c2 = sqlite3Utf8Read(&zPattern); + if( c>=prior_c && c<=c2 ) seen = 1; + prior_c = 0; + }else{ + if( c==c2 ){ + seen = 1; + } + prior_c = c2; + } + c2 = sqlite3Utf8Read(&zPattern); + } + if( c2==0 || (seen ^ invert)==0 ){ + return SQLITE_NOMATCH; + } + continue; + } + } + c2 = Utf8Read(zString); + if( c==c2 ) continue; + if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ + continue; + } + if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; + return SQLITE_NOMATCH; + } + return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH; +} + +/* +** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and +** non-zero if there is no match. +*/ +SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){ + return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '['); +} + +/* +** The sqlite3_strlike() interface. Return 0 on a match and non-zero for +** a miss - like strcmp(). +*/ +SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ + return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc); +} + +/* +** Count the number of times that the LIKE operator (or GLOB which is +** just a variation of LIKE) gets called. This is used for testing +** only. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_like_count = 0; +#endif + + +/* +** Implementation of the like() SQL function. This function implements +** the build-in LIKE operator. The first argument to the function is the +** pattern and the second argument is the string. So, the SQL statements: +** +** A LIKE B +** +** is implemented as like(B,A). +** +** This same function (with a different compareInfo structure) computes +** the GLOB operator. +*/ +static void likeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zA, *zB; + u32 escape; + int nPat; + sqlite3 *db = sqlite3_context_db_handle(context); + struct compareInfo *pInfo = sqlite3_user_data(context); + +#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS + if( sqlite3_value_type(argv[0])==SQLITE_BLOB + || sqlite3_value_type(argv[1])==SQLITE_BLOB + ){ +#ifdef SQLITE_TEST + sqlite3_like_count++; +#endif + sqlite3_result_int(context, 0); + return; + } +#endif + zB = sqlite3_value_text(argv[0]); + zA = sqlite3_value_text(argv[1]); + + /* Limit the length of the LIKE or GLOB pattern to avoid problems + ** of deep recursion and N*N behavior in patternCompare(). + */ + nPat = sqlite3_value_bytes(argv[0]); + testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ); + testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]+1 ); + if( nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){ + sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); + return; + } + assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ + + if( argc==3 ){ + /* The escape character string must consist of a single UTF-8 character. + ** Otherwise, return an error. + */ + const unsigned char *zEsc = sqlite3_value_text(argv[2]); + if( zEsc==0 ) return; + if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ + sqlite3_result_error(context, + "ESCAPE expression must be a single character", -1); + return; + } + escape = sqlite3Utf8Read(&zEsc); + }else{ + escape = pInfo->matchSet; + } + if( zA && zB ){ +#ifdef SQLITE_TEST + sqlite3_like_count++; +#endif + sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); + } +} + +/* +** Implementation of the NULLIF(x,y) function. The result is the first +** argument if the arguments are different. The result is NULL if the +** arguments are equal to each other. +*/ +static void nullifFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + CollSeq *pColl = sqlite3GetFuncCollSeq(context); + UNUSED_PARAMETER(NotUsed); + if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ + sqlite3_result_value(context, argv[0]); + } +} + +/* +** Implementation of the sqlite_version() function. The result is the version +** of the SQLite library that is running. +*/ +static void versionFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **NotUsed2 +){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + /* IMP: R-48699-48617 This function is an SQL wrapper around the + ** sqlite3_libversion() C-interface. */ + sqlite3_result_text(context, sqlite3_libversion(), -1, SQLITE_STATIC); +} + +/* +** Implementation of the sqlite_source_id() function. The result is a string +** that identifies the particular version of the source code used to build +** SQLite. +*/ +static void sourceidFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **NotUsed2 +){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + /* IMP: R-24470-31136 This function is an SQL wrapper around the + ** sqlite3_sourceid() C interface. */ + sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); +} + +/* +** Implementation of the sqlite_log() function. This is a wrapper around +** sqlite3_log(). The return value is NULL. The function exists purely for +** its side-effects. +*/ +static void errlogFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(context); + sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1])); +} + +/* +** Implementation of the sqlite_compileoption_used() function. +** The result is an integer that identifies if the compiler option +** was used to build SQLite. +*/ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +static void compileoptionusedFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zOptName; + assert( argc==1 ); + UNUSED_PARAMETER(argc); + /* IMP: R-39564-36305 The sqlite_compileoption_used() SQL + ** function is a wrapper around the sqlite3_compileoption_used() C/C++ + ** function. + */ + if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){ + sqlite3_result_int(context, sqlite3_compileoption_used(zOptName)); + } +} +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + +/* +** Implementation of the sqlite_compileoption_get() function. +** The result is a string that identifies the compiler options +** used to build SQLite. +*/ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +static void compileoptiongetFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int n; + assert( argc==1 ); + UNUSED_PARAMETER(argc); + /* IMP: R-04922-24076 The sqlite_compileoption_get() SQL function + ** is a wrapper around the sqlite3_compileoption_get() C/C++ function. + */ + n = sqlite3_value_int(argv[0]); + sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC); +} +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + +/* Array for converting from half-bytes (nybbles) into ASCII hex +** digits. */ +static const char hexdigits[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +/* +** Implementation of the QUOTE() function. This function takes a single +** argument. If the argument is numeric, the return value is the same as +** the argument. If the argument is NULL, the return value is the string +** "NULL". Otherwise, the argument is enclosed in single quotes with +** single-quote escapes. +*/ +static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + assert( argc==1 ); + UNUSED_PARAMETER(argc); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_FLOAT: { + double r1, r2; + char zBuf[50]; + r1 = sqlite3_value_double(argv[0]); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1); + sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8); + if( r1!=r2 ){ + sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1); + } + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + break; + } + case SQLITE_INTEGER: { + sqlite3_result_value(context, argv[0]); + break; + } + case SQLITE_BLOB: { + char *zText = 0; + char const *zBlob = sqlite3_value_blob(argv[0]); + int nBlob = sqlite3_value_bytes(argv[0]); + assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ + zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4); + if( zText ){ + int i; + for(i=0; i>4)&0x0F]; + zText[(i*2)+3] = hexdigits[(zBlob[i])&0x0F]; + } + zText[(nBlob*2)+2] = '\''; + zText[(nBlob*2)+3] = '\0'; + zText[0] = 'X'; + zText[1] = '\''; + sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); + sqlite3_free(zText); + } + break; + } + case SQLITE_TEXT: { + int i,j; + u64 n; + const unsigned char *zArg = sqlite3_value_text(argv[0]); + char *z; + + if( zArg==0 ) return; + for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; } + z = contextMalloc(context, ((i64)i)+((i64)n)+3); + if( z ){ + z[0] = '\''; + for(i=0, j=1; zArg[i]; i++){ + z[j++] = zArg[i]; + if( zArg[i]=='\'' ){ + z[j++] = '\''; + } + } + z[j++] = '\''; + z[j] = 0; + sqlite3_result_text(context, z, j, sqlite3_free); + } + break; + } + default: { + assert( sqlite3_value_type(argv[0])==SQLITE_NULL ); + sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); + break; + } + } +} + +/* +** The unicode() function. Return the integer unicode code-point value +** for the first character of the input string. +*/ +static void unicodeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *z = sqlite3_value_text(argv[0]); + (void)argc; + if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z)); +} + +/* +** The char() function takes zero or more arguments, each of which is +** an integer. It constructs a string where each character of the string +** is the unicode character for the corresponding integer argument. +*/ +static void charFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + unsigned char *z, *zOut; + int i; + zOut = z = sqlite3_malloc64( argc*4+1 ); + if( z==0 ){ + sqlite3_result_error_nomem(context); + return; + } + for(i=0; i0x10ffff ) x = 0xfffd; + c = (unsigned)(x & 0x1fffff); + if( c<0x00080 ){ + *zOut++ = (u8)(c&0xFF); + }else if( c<0x00800 ){ + *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); + *zOut++ = 0x80 + (u8)(c & 0x3F); + }else if( c<0x10000 ){ + *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); + *zOut++ = 0x80 + (u8)(c & 0x3F); + }else{ + *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); + *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); + *zOut++ = 0x80 + (u8)(c & 0x3F); + } \ + } + sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); +} + +/* +** The hex() function. Interpret the argument as a blob. Return +** a hexadecimal rendering as text. +*/ +static void hexFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int i, n; + const unsigned char *pBlob; + char *zHex, *z; + assert( argc==1 ); + UNUSED_PARAMETER(argc); + pBlob = sqlite3_value_blob(argv[0]); + n = sqlite3_value_bytes(argv[0]); + assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ + z = zHex = contextMalloc(context, ((i64)n)*2 + 1); + if( zHex ){ + for(i=0; i>4)&0xf]; + *(z++) = hexdigits[c&0xf]; + } + *z = 0; + sqlite3_result_text(context, zHex, n*2, sqlite3_free); + } +} + +/* +** The zeroblob(N) function returns a zero-filled blob of size N bytes. +*/ +static void zeroblobFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + i64 n; + int rc; + assert( argc==1 ); + UNUSED_PARAMETER(argc); + n = sqlite3_value_int64(argv[0]); + if( n<0 ) n = 0; + rc = sqlite3_result_zeroblob64(context, n); /* IMP: R-00293-64994 */ + if( rc ){ + sqlite3_result_error_code(context, rc); + } +} + +/* +** The replace() function. Three arguments are all strings: call +** them A, B, and C. The result is also a string which is derived +** from A by replacing every occurrence of B with C. The match +** must be exact. Collating sequences are not used. +*/ +static void replaceFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zStr; /* The input string A */ + const unsigned char *zPattern; /* The pattern string B */ + const unsigned char *zRep; /* The replacement string C */ + unsigned char *zOut; /* The output */ + int nStr; /* Size of zStr */ + int nPattern; /* Size of zPattern */ + int nRep; /* Size of zRep */ + i64 nOut; /* Maximum size of zOut */ + int loopLimit; /* Last zStr[] that might match zPattern[] */ + int i, j; /* Loop counters */ + + assert( argc==3 ); + UNUSED_PARAMETER(argc); + zStr = sqlite3_value_text(argv[0]); + if( zStr==0 ) return; + nStr = sqlite3_value_bytes(argv[0]); + assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */ + zPattern = sqlite3_value_text(argv[1]); + if( zPattern==0 ){ + assert( sqlite3_value_type(argv[1])==SQLITE_NULL + || sqlite3_context_db_handle(context)->mallocFailed ); + return; + } + if( zPattern[0]==0 ){ + assert( sqlite3_value_type(argv[1])!=SQLITE_NULL ); + sqlite3_result_value(context, argv[0]); + return; + } + nPattern = sqlite3_value_bytes(argv[1]); + assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */ + zRep = sqlite3_value_text(argv[2]); + if( zRep==0 ) return; + nRep = sqlite3_value_bytes(argv[2]); + assert( zRep==sqlite3_value_text(argv[2]) ); + nOut = nStr + 1; + assert( nOutaLimit[SQLITE_LIMIT_LENGTH] ); + testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] ); + if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + sqlite3_result_error_toobig(context); + sqlite3_free(zOut); + return; + } + zOld = zOut; + zOut = sqlite3_realloc64(zOut, (int)nOut); + if( zOut==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(zOld); + return; + } + memcpy(&zOut[j], zRep, nRep); + j += nRep; + i += nPattern-1; + } + } + assert( j+nStr-i+1==nOut ); + memcpy(&zOut[j], &zStr[i], nStr-i); + j += nStr - i; + assert( j<=nOut ); + zOut[j] = 0; + sqlite3_result_text(context, (char*)zOut, j, sqlite3_free); +} + +/* +** Implementation of the TRIM(), LTRIM(), and RTRIM() functions. +** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both. +*/ +static void trimFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zIn; /* Input string */ + const unsigned char *zCharSet; /* Set of characters to trim */ + int nIn; /* Number of bytes in input */ + int flags; /* 1: trimleft 2: trimright 3: trim */ + int i; /* Loop counter */ + unsigned char *aLen = 0; /* Length of each character in zCharSet */ + unsigned char **azChar = 0; /* Individual characters in zCharSet */ + int nChar; /* Number of characters in zCharSet */ + + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + return; + } + zIn = sqlite3_value_text(argv[0]); + if( zIn==0 ) return; + nIn = sqlite3_value_bytes(argv[0]); + assert( zIn==sqlite3_value_text(argv[0]) ); + if( argc==1 ){ + static const unsigned char lenOne[] = { 1 }; + static unsigned char * const azOne[] = { (u8*)" " }; + nChar = 1; + aLen = (u8*)lenOne; + azChar = (unsigned char **)azOne; + zCharSet = 0; + }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ + return; + }else{ + const unsigned char *z; + for(z=zCharSet, nChar=0; *z; nChar++){ + SQLITE_SKIP_UTF8(z); + } + if( nChar>0 ){ + azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+1)); + if( azChar==0 ){ + return; + } + aLen = (unsigned char*)&azChar[nChar]; + for(z=zCharSet, nChar=0; *z; nChar++){ + azChar[nChar] = (unsigned char *)z; + SQLITE_SKIP_UTF8(z); + aLen[nChar] = (u8)(z - azChar[nChar]); + } + } + } + if( nChar>0 ){ + flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); + if( flags & 1 ){ + while( nIn>0 ){ + int len = 0; + for(i=0; i=nChar ) break; + zIn += len; + nIn -= len; + } + } + if( flags & 2 ){ + while( nIn>0 ){ + int len = 0; + for(i=0; i=nChar ) break; + nIn -= len; + } + } + if( zCharSet ){ + sqlite3_free(azChar); + } + } + sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); +} + + +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION +/* +** The "unknown" function is automatically substituted in place of +** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN +** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used. +** When the "sqlite3" command-line shell is built using this functionality, +** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries +** involving application-defined functions to be examined in a generic +** sqlite3 shell. +*/ +static void unknownFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + /* no-op */ +} +#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ + + +/* IMP: R-25361-16150 This function is omitted from SQLite by default. It +** is only available if the SQLITE_SOUNDEX compile-time option is used +** when SQLite is built. +*/ +#ifdef SQLITE_SOUNDEX +/* +** Compute the soundex encoding of a word. +** +** IMP: R-59782-00072 The soundex(X) function returns a string that is the +** soundex encoding of the string X. +*/ +static void soundexFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + char zResult[8]; + const u8 *zIn; + int i, j; + static const unsigned char iCode[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, + 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, + 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, + }; + assert( argc==1 ); + zIn = (u8*)sqlite3_value_text(argv[0]); + if( zIn==0 ) zIn = (u8*)""; + for(i=0; zIn[i] && !sqlite3Isalpha(zIn[i]); i++){} + if( zIn[i] ){ + u8 prevcode = iCode[zIn[i]&0x7f]; + zResult[0] = sqlite3Toupper(zIn[i]); + for(j=1; j<4 && zIn[i]; i++){ + int code = iCode[zIn[i]&0x7f]; + if( code>0 ){ + if( code!=prevcode ){ + prevcode = code; + zResult[j++] = code + '0'; + } + }else{ + prevcode = 0; + } + } + while( j<4 ){ + zResult[j++] = '0'; + } + zResult[j] = 0; + sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT); + }else{ + /* IMP: R-64894-50321 The string "?000" is returned if the argument + ** is NULL or contains no ASCII alphabetic characters. */ + sqlite3_result_text(context, "?000", 4, SQLITE_STATIC); + } +} +#endif /* SQLITE_SOUNDEX */ + +#ifndef SQLITE_OMIT_LOAD_EXTENSION +/* +** A function that loads a shared-library extension then returns NULL. +*/ +static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ + const char *zFile = (const char *)sqlite3_value_text(argv[0]); + const char *zProc; + sqlite3 *db = sqlite3_context_db_handle(context); + char *zErrMsg = 0; + + /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc + ** flag is set. See the sqlite3_enable_load_extension() API. + */ + if( (db->flags & SQLITE_LoadExtFunc)==0 ){ + sqlite3_result_error(context, "not authorized", -1); + return; + } + + if( argc==2 ){ + zProc = (const char *)sqlite3_value_text(argv[1]); + }else{ + zProc = 0; + } + if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){ + sqlite3_result_error(context, zErrMsg, -1); + sqlite3_free(zErrMsg); + } +} +#endif + + +/* +** An instance of the following structure holds the context of a +** sum() or avg() aggregate computation. +*/ +typedef struct SumCtx SumCtx; +struct SumCtx { + double rSum; /* Floating point sum */ + i64 iSum; /* Integer sum */ + i64 cnt; /* Number of elements summed */ + u8 overflow; /* True if integer overflow seen */ + u8 approx; /* True if non-integer value was input to the sum */ +}; + +/* +** Routines used to compute the sum, average, and total. +** +** The SUM() function follows the (broken) SQL standard which means +** that it returns NULL if it sums over no inputs. TOTAL returns +** 0.0 in that case. In addition, TOTAL always returns a float where +** SUM might return an integer if it never encounters a floating point +** value. TOTAL never fails, but SUM might through an exception if +** it overflows an integer. +*/ +static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ + SumCtx *p; + int type; + assert( argc==1 ); + UNUSED_PARAMETER(argc); + p = sqlite3_aggregate_context(context, sizeof(*p)); + type = sqlite3_value_numeric_type(argv[0]); + if( p && type!=SQLITE_NULL ){ + p->cnt++; + if( type==SQLITE_INTEGER ){ + i64 v = sqlite3_value_int64(argv[0]); + p->rSum += v; + if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){ + p->overflow = 1; + } + }else{ + p->rSum += sqlite3_value_double(argv[0]); + p->approx = 1; + } + } +} +static void sumFinalize(sqlite3_context *context){ + SumCtx *p; + p = sqlite3_aggregate_context(context, 0); + if( p && p->cnt>0 ){ + if( p->overflow ){ + sqlite3_result_error(context,"integer overflow",-1); + }else if( p->approx ){ + sqlite3_result_double(context, p->rSum); + }else{ + sqlite3_result_int64(context, p->iSum); + } + } +} +static void avgFinalize(sqlite3_context *context){ + SumCtx *p; + p = sqlite3_aggregate_context(context, 0); + if( p && p->cnt>0 ){ + sqlite3_result_double(context, p->rSum/(double)p->cnt); + } +} +static void totalFinalize(sqlite3_context *context){ + SumCtx *p; + p = sqlite3_aggregate_context(context, 0); + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + sqlite3_result_double(context, p ? p->rSum : (double)0); +} + +/* +** The following structure keeps track of state information for the +** count() aggregate function. +*/ +typedef struct CountCtx CountCtx; +struct CountCtx { + i64 n; +}; + +/* +** Routines to implement the count() aggregate function. +*/ +static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){ + CountCtx *p; + p = sqlite3_aggregate_context(context, sizeof(*p)); + if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){ + p->n++; + } + +#ifndef SQLITE_OMIT_DEPRECATED + /* The sqlite3_aggregate_count() function is deprecated. But just to make + ** sure it still operates correctly, verify that its count agrees with our + ** internal count when using count(*) and when the total count can be + ** expressed as a 32-bit integer. */ + assert( argc==1 || p==0 || p->n>0x7fffffff + || p->n==sqlite3_aggregate_count(context) ); +#endif +} +static void countFinalize(sqlite3_context *context){ + CountCtx *p; + p = sqlite3_aggregate_context(context, 0); + sqlite3_result_int64(context, p ? p->n : 0); +} + +/* +** Routines to implement min() and max() aggregate functions. +*/ +static void minmaxStep( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + Mem *pArg = (Mem *)argv[0]; + Mem *pBest; + UNUSED_PARAMETER(NotUsed); + + pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest)); + if( !pBest ) return; + + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + if( pBest->flags ) sqlite3SkipAccumulatorLoad(context); + }else if( pBest->flags ){ + int max; + int cmp; + CollSeq *pColl = sqlite3GetFuncCollSeq(context); + /* This step function is used for both the min() and max() aggregates, + ** the only difference between the two being that the sense of the + ** comparison is inverted. For the max() aggregate, the + ** sqlite3_user_data() function returns (void *)-1. For min() it + ** returns (void *)db, where db is the sqlite3* database pointer. + ** Therefore the next statement sets variable 'max' to 1 for the max() + ** aggregate, or 0 for min(). + */ + max = sqlite3_user_data(context)!=0; + cmp = sqlite3MemCompare(pBest, pArg, pColl); + if( (max && cmp<0) || (!max && cmp>0) ){ + sqlite3VdbeMemCopy(pBest, pArg); + }else{ + sqlite3SkipAccumulatorLoad(context); + } + }else{ + pBest->db = sqlite3_context_db_handle(context); + sqlite3VdbeMemCopy(pBest, pArg); + } +} +static void minMaxFinalize(sqlite3_context *context){ + sqlite3_value *pRes; + pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); + if( pRes ){ + if( pRes->flags ){ + sqlite3_result_value(context, pRes); + } + sqlite3VdbeMemRelease(pRes); + } +} + +/* +** group_concat(EXPR, ?SEPARATOR?) +*/ +static void groupConcatStep( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zVal; + StrAccum *pAccum; + const char *zSep; + int nVal, nSep; + assert( argc==1 || argc==2 ); + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); + + if( pAccum ){ + sqlite3 *db = sqlite3_context_db_handle(context); + int firstTerm = pAccum->mxAlloc==0; + pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; + if( !firstTerm ){ + if( argc==2 ){ + zSep = (char*)sqlite3_value_text(argv[1]); + nSep = sqlite3_value_bytes(argv[1]); + }else{ + zSep = ","; + nSep = 1; + } + if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep); + } + zVal = (char*)sqlite3_value_text(argv[0]); + nVal = sqlite3_value_bytes(argv[0]); + if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal); + } +} +static void groupConcatFinalize(sqlite3_context *context){ + StrAccum *pAccum; + pAccum = sqlite3_aggregate_context(context, 0); + if( pAccum ){ + if( pAccum->accError==STRACCUM_TOOBIG ){ + sqlite3_result_error_toobig(context); + }else if( pAccum->accError==STRACCUM_NOMEM ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1, + sqlite3_free); + } + } +} + +/* +** This routine does per-connection function registration. Most +** of the built-in functions above are part of the global function set. +** This routine only deals with those that are not global. +*/ +SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ + int rc = sqlite3_overload_function(db, "MATCH", 2); + assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); + if( rc==SQLITE_NOMEM ){ + sqlite3OomFault(db); + } +} + +/* +** Set the LIKEOPT flag on the 2-argument function with the given name. +*/ +static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ + FuncDef *pDef; + pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0); + if( ALWAYS(pDef) ){ + pDef->funcFlags |= flagVal; + } +} + +/* +** Register the built-in LIKE and GLOB functions. The caseSensitive +** parameter determines whether or not the LIKE operator is case +** sensitive. GLOB is always case sensitive. +*/ +SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ + struct compareInfo *pInfo; + if( caseSensitive ){ + pInfo = (struct compareInfo*)&likeInfoAlt; + }else{ + pInfo = (struct compareInfo*)&likeInfoNorm; + } + sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0); + sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0); + sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, + (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0); + setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); + setLikeOptFlag(db, "like", + caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); +} + +/* +** 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. +** +** *pIsNocase is set to true if uppercase and lowercase are equivalent for +** the function (default for LIKE). If the function makes the distinction +** between uppercase and lowercase (as does GLOB) then *pIsNocase is set to +** false. +*/ +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 + ){ + return 0; + } + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0); + if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ + return 0; + } + + /* The memcpy() statement assumes that the wildcard characters are + ** the first three statements in the compareInfo structure. The + ** asserts() that follow verify that assumption + */ + memcpy(aWc, pDef->pUserData, 3); + assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); + assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); + assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); + *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0; + return 1; +} + +/* +** All of the FuncDef structures in the aBuiltinFunc[] array above +** to the global function hash table. This occurs at start-time (as +** a consequence of calling sqlite3_initialize()). +** +** After this routine runs +*/ +SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ + /* + ** The following array holds FuncDef structures for all of the functions + ** defined in this file. + ** + ** The array cannot be constant since changes are made to the + ** FuncDef.pHash elements at start-time. The elements of this array + ** are read-only after initialization is complete. + ** + ** For peak efficiency, put the most frequently used function last. + */ + static FuncDef aBuiltinFunc[] = { +#ifdef SQLITE_SOUNDEX + FUNCTION(soundex, 1, 0, 0, soundexFunc ), +#endif +#ifndef SQLITE_OMIT_LOAD_EXTENSION + VFUNCTION(load_extension, 1, 0, 0, loadExt ), + VFUNCTION(load_extension, 2, 0, 0, loadExt ), +#endif +#if SQLITE_USER_AUTHENTICATION + FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), +#endif +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS + DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), + DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), + FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), + FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), +#ifdef SQLITE_DEBUG + FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY), +#endif + FUNCTION(ltrim, 1, 1, 0, trimFunc ), + FUNCTION(ltrim, 2, 1, 0, trimFunc ), + FUNCTION(rtrim, 1, 2, 0, trimFunc ), + FUNCTION(rtrim, 2, 2, 0, trimFunc ), + FUNCTION(trim, 1, 3, 0, trimFunc ), + FUNCTION(trim, 2, 3, 0, trimFunc ), + FUNCTION(min, -1, 0, 1, minmaxFunc ), + FUNCTION(min, 0, 0, 1, 0 ), + AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize, + SQLITE_FUNC_MINMAX ), + FUNCTION(max, -1, 1, 1, minmaxFunc ), + FUNCTION(max, 0, 1, 1, 0 ), + AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize, + SQLITE_FUNC_MINMAX ), + FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), + FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), + FUNCTION(instr, 2, 0, 0, instrFunc ), + FUNCTION(printf, -1, 0, 0, printfFunc ), + FUNCTION(unicode, 1, 0, 0, unicodeFunc ), + FUNCTION(char, -1, 0, 0, charFunc ), + FUNCTION(abs, 1, 0, 0, absFunc ), +#ifndef SQLITE_OMIT_FLOATING_POINT + FUNCTION(round, 1, 0, 0, roundFunc ), + FUNCTION(round, 2, 0, 0, roundFunc ), +#endif + FUNCTION(upper, 1, 0, 0, upperFunc ), + FUNCTION(lower, 1, 0, 0, lowerFunc ), + FUNCTION(hex, 1, 0, 0, hexFunc ), + FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), + VFUNCTION(random, 0, 0, 0, randomFunc ), + VFUNCTION(randomblob, 1, 0, 0, randomBlob ), + FUNCTION(nullif, 2, 0, 1, nullifFunc ), + DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), + DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), + FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), + FUNCTION(quote, 1, 0, 0, quoteFunc ), + VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), + VFUNCTION(changes, 0, 0, 0, changes ), + VFUNCTION(total_changes, 0, 0, 0, total_changes ), + FUNCTION(replace, 3, 0, 0, replaceFunc ), + FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), + FUNCTION(substr, 2, 0, 0, substrFunc ), + FUNCTION(substr, 3, 0, 0, substrFunc ), + AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), + AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), + AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), + AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, + SQLITE_FUNC_COUNT ), + AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), + AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), + AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), + + LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), +#ifdef SQLITE_CASE_SENSITIVE_LIKE + LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), + LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), +#else + LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), + LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), +#endif +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + FUNCTION(unknown, -1, 0, 0, unknownFunc ), +#endif + FUNCTION(coalesce, 1, 0, 0, 0 ), + FUNCTION(coalesce, 0, 0, 0, 0 ), + FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), + }; +#ifndef SQLITE_OMIT_ALTERTABLE + sqlite3AlterFunctions(); +#endif +#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4) + sqlite3AnalyzeFunctions(); +#endif + sqlite3RegisterDateTimeFunctions(); + sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc)); + +#if 0 /* Enable to print out how the built-in functions are hashed */ + { + int i; + FuncDef *p; + for(i=0; iu.pHash){ + int n = sqlite3Strlen30(p->zName); + int h = p->zName[0] + n; + printf(" %s(%d)", p->zName, h); + } + printf("\n"); + } + } +#endif +} + +/************** End of func.c ************************************************/ +/************** Begin file fkey.c ********************************************/ +/* +** +** 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 used by the compiler to add foreign key +** support to compiled SQL statements. +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_FOREIGN_KEY +#ifndef SQLITE_OMIT_TRIGGER + +/* +** Deferred and Immediate FKs +** -------------------------- +** +** Foreign keys in SQLite come in two flavours: deferred and immediate. +** If an immediate foreign key constraint is violated, +** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current +** statement transaction rolled back. If a +** deferred foreign key constraint is violated, no action is taken +** immediately. However if the application attempts to commit the +** transaction before fixing the constraint violation, the attempt fails. +** +** Deferred constraints are implemented using a simple counter associated +** with the database handle. The counter is set to zero each time a +** database transaction is opened. Each time a statement is executed +** that causes a foreign key violation, the counter is incremented. Each +** time a statement is executed that removes an existing violation from +** the database, the counter is decremented. When the transaction is +** committed, the commit fails if the current value of the counter is +** greater than zero. This scheme has two big drawbacks: +** +** * When a commit fails due to a deferred foreign key constraint, +** there is no way to tell which foreign constraint is not satisfied, +** or which row it is not satisfied for. +** +** * If the database contains foreign key violations when the +** transaction is opened, this may cause the mechanism to malfunction. +** +** Despite these problems, this approach is adopted as it seems simpler +** than the alternatives. +** +** INSERT operations: +** +** I.1) For each FK for which the table is the child table, search +** the parent table for a match. If none is found increment the +** constraint counter. +** +** I.2) For each FK for which the table is the parent table, +** search the child table for rows that correspond to the new +** row in the parent table. Decrement the counter for each row +** found (as the constraint is now satisfied). +** +** DELETE operations: +** +** D.1) For each FK for which the table is the child table, +** search the parent table for a row that corresponds to the +** deleted row in the child table. If such a row is not found, +** decrement the counter. +** +** D.2) For each FK for which the table is the parent table, search +** the child table for rows that correspond to the deleted row +** in the parent table. For each found increment the counter. +** +** UPDATE operations: +** +** An UPDATE command requires that all 4 steps above are taken, but only +** for FK constraints for which the affected columns are actually +** modified (values must be compared at runtime). +** +** Note that I.1 and D.1 are very similar operations, as are I.2 and D.2. +** This simplifies the implementation a bit. +** +** For the purposes of immediate FK constraints, the OR REPLACE conflict +** resolution is considered to delete rows before the new row is inserted. +** If a delete caused by OR REPLACE violates an FK constraint, an exception +** is thrown, even if the FK constraint would be satisfied after the new +** row is inserted. +** +** Immediate constraints are usually handled similarly. The only difference +** is that the counter used is stored as part of each individual statement +** object (struct Vdbe). If, after the statement has run, its immediate +** constraint counter is greater than zero, +** it returns SQLITE_CONSTRAINT_FOREIGNKEY +** and the statement transaction is rolled back. An exception is an INSERT +** statement that inserts a single row only (no triggers). In this case, +** instead of using a counter, an exception is thrown immediately if the +** INSERT violates a foreign key constraint. This is necessary as such +** an INSERT does not open a statement transaction. +** +** TODO: How should dropping a table be handled? How should renaming a +** table be handled? +** +** +** Query API Notes +** --------------- +** +** Before coding an UPDATE or DELETE row operation, the code-generator +** for those two operations needs to know whether or not the operation +** requires any FK processing and, if so, which columns of the original +** row are required by the FK processing VDBE code (i.e. if FKs were +** implemented using triggers, which of the old.* columns would be +** accessed). No information is required by the code-generator before +** coding an INSERT operation. The functions used by the UPDATE/DELETE +** generation code to query for this information are: +** +** sqlite3FkRequired() - Test to see if FK processing is required. +** sqlite3FkOldmask() - Query for the set of required old.* columns. +** +** +** Externally accessible module functions +** -------------------------------------- +** +** sqlite3FkCheck() - Check for foreign key violations. +** sqlite3FkActions() - Code triggers for ON UPDATE/ON DELETE actions. +** sqlite3FkDelete() - Delete an FKey structure. +*/ + +/* +** VDBE Calling Convention +** ----------------------- +** +** Example: +** +** For the following INSERT statement: +** +** CREATE TABLE t1(a, b INTEGER PRIMARY KEY, c); +** INSERT INTO t1 VALUES(1, 2, 3.1); +** +** Register (x): 2 (type integer) +** Register (x+1): 1 (type integer) +** Register (x+2): NULL (type NULL) +** Register (x+3): 3.1 (type real) +*/ + +/* +** A foreign key constraint requires that the key columns in the parent +** table are collectively subject to a UNIQUE or PRIMARY KEY constraint. +** Given that pParent is the parent table for foreign key constraint pFKey, +** search the schema for a unique index on the parent key columns. +** +** If successful, zero is returned. If the parent key is an INTEGER PRIMARY +** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx +** is set to point to the unique index. +** +** If the parent key consists of a single column (the foreign key constraint +** is not a composite foreign key), output variable *paiCol is set to NULL. +** Otherwise, it is set to point to an allocated array of size N, where +** N is the number of columns in the parent key. The first element of the +** array is the index of the child table column that is mapped by the FK +** constraint to the parent table column stored in the left-most column +** of index *ppIdx. The second element of the array is the index of the +** child table column that corresponds to the second left-most column of +** *ppIdx, and so on. +** +** If the required index cannot be found, either because: +** +** 1) The named parent key columns do not exist, or +** +** 2) The named parent key columns do exist, but are not subject to a +** UNIQUE or PRIMARY KEY constraint, or +** +** 3) No parent key columns were provided explicitly as part of the +** foreign key definition, and the parent table does not have a +** PRIMARY KEY, or +** +** 4) No parent key columns were provided explicitly as part of the +** foreign key definition, and the PRIMARY KEY of the parent table +** consists of a different number of columns to the child key in +** the child table. +** +** then non-zero is returned, and a "foreign key mismatch" error loaded +** into pParse. If an OOM error occurs, non-zero is returned and the +** pParse->db->mallocFailed flag is set. +*/ +SQLITE_PRIVATE int sqlite3FkLocateIndex( + Parse *pParse, /* Parse context to store any error in */ + Table *pParent, /* Parent table of FK constraint pFKey */ + FKey *pFKey, /* Foreign key to find index for */ + Index **ppIdx, /* OUT: Unique index on parent table */ + int **paiCol /* OUT: Map of index columns in pFKey */ +){ + Index *pIdx = 0; /* Value to return via *ppIdx */ + int *aiCol = 0; /* Value to return via *paiCol */ + int nCol = pFKey->nCol; /* Number of columns in parent key */ + char *zKey = pFKey->aCol[0].zCol; /* Name of left-most parent key column */ + + /* The caller is responsible for zeroing output parameters. */ + assert( ppIdx && *ppIdx==0 ); + assert( !paiCol || *paiCol==0 ); + assert( pParse ); + + /* If this is a non-composite (single column) foreign key, check if it + ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx + ** and *paiCol set to zero and return early. + ** + ** Otherwise, for a composite foreign key (more than one column), allocate + ** space for the aiCol array (returned via output parameter *paiCol). + ** Non-composite foreign keys do not require the aiCol array. + */ + if( nCol==1 ){ + /* The FK maps to the IPK if any of the following are true: + ** + ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly + ** mapped to the primary key of table pParent, or + ** 2) The FK is explicitly mapped to a column declared as INTEGER + ** PRIMARY KEY. + */ + if( pParent->iPKey>=0 ){ + if( !zKey ) return 0; + if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zName, zKey) ) return 0; + } + }else if( paiCol ){ + assert( nCol>1 ); + aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int)); + if( !aiCol ) return 1; + *paiCol = aiCol; + } + + for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){ + /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number + ** of columns. If each indexed column corresponds to a foreign key + ** column of pFKey, then this index is a winner. */ + + if( zKey==0 ){ + /* If zKey is NULL, then this foreign key is implicitly mapped to + ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be + ** identified by the test. */ + if( IsPrimaryKeyIndex(pIdx) ){ + if( aiCol ){ + int i; + for(i=0; iaCol[i].iFrom; + } + break; + } + }else{ + /* If zKey is non-NULL, then this foreign key was declared to + ** map to an explicit list of columns in table pParent. Check if this + ** index matches those columns. Also, check that the index uses + ** the default collation sequences for each column. */ + int i, j; + for(i=0; iaiColumn[i]; /* Index of column in parent tbl */ + const char *zDfltColl; /* Def. collation for column */ + char *zIdxCol; /* Name of indexed column */ + + if( iCol<0 ) break; /* No foreign keys against expression indexes */ + + /* If the index uses a collation sequence that is different from + ** the default collation sequence for the column, this index is + ** unusable. Bail out early in this case. */ + zDfltColl = pParent->aCol[iCol].zColl; + if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; + if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; + + zIdxCol = pParent->aCol[iCol].zName; + for(j=0; jaCol[j].zCol, zIdxCol)==0 ){ + if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom; + break; + } + } + if( j==nCol ) break; + } + if( i==nCol ) break; /* pIdx is usable */ + } + } + } + + if( !pIdx ){ + if( !pParse->disableTriggers ){ + sqlite3ErrorMsg(pParse, + "foreign key mismatch - \"%w\" referencing \"%w\"", + pFKey->pFrom->zName, pFKey->zTo); + } + sqlite3DbFree(pParse->db, aiCol); + return 1; + } + + *ppIdx = pIdx; + return 0; +} + +/* +** This function is called when a row is inserted into or deleted from the +** child table of foreign key constraint pFKey. If an SQL UPDATE is executed +** on the child table of pFKey, this function is invoked twice for each row +** affected - once to "delete" the old row, and then again to "insert" the +** new row. +** +** Each time it is called, this function generates VDBE code to locate the +** row in the parent table that corresponds to the row being inserted into +** or deleted from the child table. If the parent row can be found, no +** special action is taken. Otherwise, if the parent row can *not* be +** found in the parent table: +** +** Operation | FK type | Action taken +** -------------------------------------------------------------------------- +** INSERT immediate Increment the "immediate constraint counter". +** +** DELETE immediate Decrement the "immediate constraint counter". +** +** INSERT deferred Increment the "deferred constraint counter". +** +** DELETE deferred Decrement the "deferred constraint counter". +** +** These operations are identified in the comment at the top of this file +** (fkey.c) as "I.1" and "D.1". +*/ +static void fkLookupParent( + Parse *pParse, /* Parse context */ + int iDb, /* Index of database housing pTab */ + Table *pTab, /* Parent table of FK pFKey */ + Index *pIdx, /* Unique index on parent key columns in pTab */ + FKey *pFKey, /* Foreign key constraint */ + int *aiCol, /* Map from parent key columns to child table columns */ + int regData, /* Address of array containing child table row */ + int nIncr, /* Increment constraint counter by this */ + int isIgnore /* If true, pretend pTab contains all NULL values */ +){ + int i; /* Iterator variable */ + Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */ + int iCur = pParse->nTab - 1; /* Cursor number to use */ + int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */ + + /* If nIncr is less than zero, then check at runtime if there are any + ** outstanding constraints to resolve. If there are not, there is no need + ** to check if deleting this row resolves any outstanding violations. + ** + ** Check if any of the key columns in the child table row are NULL. If + ** any are, then the constraint is considered satisfied. No need to + ** search for a matching row in the parent table. */ + if( nIncr<0 ){ + sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk); + VdbeCoverage(v); + } + for(i=0; inCol; i++){ + int iReg = aiCol[i] + regData + 1; + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v); + } + + if( isIgnore==0 ){ + if( pIdx==0 ){ + /* If pIdx is NULL, then the parent key is the INTEGER PRIMARY KEY + ** column of the parent table (table pTab). */ + int iMustBeInt; /* Address of MustBeInt instruction */ + int regTemp = sqlite3GetTempReg(pParse); + + /* Invoke MustBeInt to coerce the child key value to an integer (i.e. + ** apply the affinity of the parent key). If this fails, then there + ** is no matching parent key. Before using MustBeInt, make a copy of + ** the value. Otherwise, the value inserted into the child key column + ** will have INTEGER affinity applied to it, which may not be correct. */ + sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp); + iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0); + VdbeCoverage(v); + + /* If the parent table is the same as the child table, and we are about + ** to increment the constraint-counter (i.e. this is an INSERT operation), + ** then check if the row being inserted matches itself. If so, do not + ** increment the constraint-counter. */ + if( pTab==pFKey->pFrom && nIncr==1 ){ + sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + } + + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v); + sqlite3VdbeGoto(v, iOk); + sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); + sqlite3VdbeJumpHere(v, iMustBeInt); + sqlite3ReleaseTempReg(pParse, regTemp); + }else{ + int nCol = pFKey->nCol; + int regTemp = sqlite3GetTempRange(pParse, nCol); + int regRec = sqlite3GetTempReg(pParse); + + sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + for(i=0; ipFrom && nIncr==1 ){ + int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; + for(i=0; iaiColumn[i]+1+regData; + assert( pIdx->aiColumn[i]>=0 ); + assert( aiCol[i]!=pTab->iPKey ); + if( pIdx->aiColumn[i]==pTab->iPKey ){ + /* The parent key is a composite key that includes the IPK column */ + iParent = regData; + } + sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); + } + sqlite3VdbeGoto(v, iOk); + } + + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec, + sqlite3IndexAffinityStr(pParse->db,pIdx), nCol); + sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v); + + sqlite3ReleaseTempReg(pParse, regRec); + sqlite3ReleaseTempRange(pParse, regTemp, nCol); + } + } + + if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel + && !pParse->isMultiWrite + ){ + /* Special case: If this is an INSERT statement that will insert exactly + ** one row into the table, raise a constraint immediately instead of + ** incrementing a counter. This is necessary as the VM code is being + ** generated for will not open a statement transaction. */ + assert( nIncr==1 ); + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, + OE_Abort, 0, P4_STATIC, P5_ConstraintFK); + }else{ + if( nIncr>0 && pFKey->isDeferred==0 ){ + sqlite3MayAbort(pParse); + } + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); + } + + sqlite3VdbeResolveLabel(v, iOk); + sqlite3VdbeAddOp1(v, OP_Close, iCur); +} + + +/* +** Return an Expr object that refers to a memory register corresponding +** to column iCol of table pTab. +** +** regBase is the first of an array of register that contains the data +** for pTab. regBase itself holds the rowid. regBase+1 holds the first +** column. regBase+2 holds the second column, and so forth. +*/ +static Expr *exprTableRegister( + Parse *pParse, /* Parsing and code generating context */ + Table *pTab, /* The table whose content is at r[regBase]... */ + int regBase, /* Contents of table pTab */ + i16 iCol /* Which column of pTab is desired */ +){ + Expr *pExpr; + Column *pCol; + const char *zColl; + sqlite3 *db = pParse->db; + + pExpr = sqlite3Expr(db, TK_REGISTER, 0); + if( pExpr ){ + if( iCol>=0 && iCol!=pTab->iPKey ){ + pCol = &pTab->aCol[iCol]; + pExpr->iTable = regBase + iCol + 1; + pExpr->affinity = pCol->affinity; + zColl = pCol->zColl; + if( zColl==0 ) zColl = db->pDfltColl->zName; + pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); + }else{ + pExpr->iTable = regBase; + pExpr->affinity = SQLITE_AFF_INTEGER; + } + } + return pExpr; +} + +/* +** Return an Expr object that refers to column iCol of table pTab which +** has cursor iCur. +*/ +static Expr *exprTableColumn( + sqlite3 *db, /* The database connection */ + Table *pTab, /* The table whose column is desired */ + int iCursor, /* The open cursor on the table */ + i16 iCol /* The column that is wanted */ +){ + Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); + if( pExpr ){ + pExpr->pTab = pTab; + pExpr->iTable = iCursor; + pExpr->iColumn = iCol; + } + return pExpr; +} + +/* +** This function is called to generate code executed when a row is deleted +** from the parent table of foreign key constraint pFKey and, if pFKey is +** deferred, when a row is inserted into the same table. When generating +** code for an SQL UPDATE operation, this function may be called twice - +** once to "delete" the old row and once to "insert" the new row. +** +** Parameter nIncr is passed -1 when inserting a row (as this may decrease +** the number of FK violations in the db) or +1 when deleting one (as this +** may increase the number of FK constraint problems). +** +** The code generated by this function scans through the rows in the child +** table that correspond to the parent table row being deleted or inserted. +** For each child row found, one of the following actions is taken: +** +** Operation | FK type | Action taken +** -------------------------------------------------------------------------- +** DELETE immediate Increment the "immediate constraint counter". +** Or, if the ON (UPDATE|DELETE) action is RESTRICT, +** throw a "FOREIGN KEY constraint failed" exception. +** +** INSERT immediate Decrement the "immediate constraint counter". +** +** DELETE deferred Increment the "deferred constraint counter". +** Or, if the ON (UPDATE|DELETE) action is RESTRICT, +** throw a "FOREIGN KEY constraint failed" exception. +** +** INSERT deferred Decrement the "deferred constraint counter". +** +** These operations are identified in the comment at the top of this file +** (fkey.c) as "I.2" and "D.2". +*/ +static void fkScanChildren( + Parse *pParse, /* Parse context */ + SrcList *pSrc, /* The child table to be scanned */ + Table *pTab, /* The parent table */ + Index *pIdx, /* Index on parent covering the foreign key */ + FKey *pFKey, /* The foreign key linking pSrc to pTab */ + int *aiCol, /* Map from pIdx cols to child table cols */ + int regData, /* Parent row data starts here */ + int nIncr /* Amount to increment deferred counter by */ +){ + sqlite3 *db = pParse->db; /* Database handle */ + int i; /* Iterator variable */ + Expr *pWhere = 0; /* WHERE clause to scan with */ + NameContext sNameContext; /* Context used to resolve WHERE clause */ + WhereInfo *pWInfo; /* Context used by sqlite3WhereXXX() */ + int iFkIfZero = 0; /* Address of OP_FkIfZero */ + Vdbe *v = sqlite3GetVdbe(pParse); + + assert( pIdx==0 || pIdx->pTable==pTab ); + assert( pIdx==0 || pIdx->nKeyCol==pFKey->nCol ); + assert( pIdx!=0 || pFKey->nCol==1 ); + assert( pIdx!=0 || HasRowid(pTab) ); + + if( nIncr<0 ){ + iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0); + VdbeCoverage(v); + } + + /* Create an Expr object representing an SQL expression like: + ** + ** = AND = ... + ** + ** The collation sequence used for the comparison should be that of + ** the parent key columns. The affinity of the parent key column should + ** be applied to each child key value before the comparison takes place. + */ + for(i=0; inCol; i++){ + Expr *pLeft; /* Value from parent table row */ + Expr *pRight; /* Column ref to child table */ + Expr *pEq; /* Expression (pLeft = pRight) */ + i16 iCol; /* Index of column in child table */ + const char *zCol; /* Name of column in child table */ + + iCol = pIdx ? pIdx->aiColumn[i] : -1; + pLeft = exprTableRegister(pParse, pTab, regData, iCol); + iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; + assert( iCol>=0 ); + zCol = pFKey->pFrom->aCol[iCol].zName; + pRight = sqlite3Expr(db, TK_ID, zCol); + pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); + pWhere = sqlite3ExprAnd(db, pWhere, pEq); + } + + /* If the child table is the same as the parent table, then add terms + ** to the WHERE clause that prevent this entry from being scanned. + ** The added WHERE clause terms are like this: + ** + ** $current_rowid!=rowid + ** NOT( $current_a==a AND $current_b==b AND ... ) + ** + ** The first form is used for rowid tables. The second form is used + ** for WITHOUT ROWID tables. In the second form, the primary key is + ** (a,b,...) + */ + if( pTab==pFKey->pFrom && nIncr>0 ){ + Expr *pNe; /* Expression (pLeft != pRight) */ + Expr *pLeft; /* Value from parent table row */ + Expr *pRight; /* Column ref to child table */ + if( HasRowid(pTab) ){ + pLeft = exprTableRegister(pParse, pTab, regData, -1); + pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1); + pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight); + }else{ + Expr *pEq, *pAll = 0; + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pIdx!=0 ); + for(i=0; inKeyCol; i++){ + i16 iCol = pIdx->aiColumn[i]; + assert( iCol>=0 ); + pLeft = exprTableRegister(pParse, pTab, regData, iCol); + pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol); + pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); + pAll = sqlite3ExprAnd(db, pAll, pEq); + } + pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); + } + pWhere = sqlite3ExprAnd(db, pWhere, pNe); + } + + /* Resolve the references in the WHERE clause. */ + memset(&sNameContext, 0, sizeof(NameContext)); + sNameContext.pSrcList = pSrc; + sNameContext.pParse = pParse; + sqlite3ResolveExprNames(&sNameContext, pWhere); + + /* Create VDBE to loop through the entries in pSrc that match the WHERE + ** clause. For each row found, increment either the deferred or immediate + ** foreign key constraint counter. */ + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); + if( pWInfo ){ + sqlite3WhereEnd(pWInfo); + } + + /* Clean up the WHERE clause constructed above. */ + sqlite3ExprDelete(db, pWhere); + if( iFkIfZero ){ + sqlite3VdbeJumpHere(v, iFkIfZero); + } +} + +/* +** This function returns a linked list of FKey objects (connected by +** FKey.pNextTo) holding all children of table pTab. For example, +** given the following schema: +** +** CREATE TABLE t1(a PRIMARY KEY); +** CREATE TABLE t2(b REFERENCES t1(a); +** +** Calling this function with table "t1" as an argument returns a pointer +** to the FKey structure representing the foreign key constraint on table +** "t2". Calling this function with "t2" as the argument would return a +** NULL pointer (as there are no FK constraints for which t2 is the parent +** table). +*/ +SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){ + return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName); +} + +/* +** The second argument is a Trigger structure allocated by the +** fkActionTrigger() routine. This function deletes the Trigger structure +** and all of its sub-components. +** +** The Trigger structure or any of its sub-components may be allocated from +** the lookaside buffer belonging to database handle dbMem. +*/ +static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ + if( p ){ + TriggerStep *pStep = p->step_list; + sqlite3ExprDelete(dbMem, pStep->pWhere); + sqlite3ExprListDelete(dbMem, pStep->pExprList); + sqlite3SelectDelete(dbMem, pStep->pSelect); + sqlite3ExprDelete(dbMem, p->pWhen); + sqlite3DbFree(dbMem, p); + } +} + +/* +** This function is called to generate code that runs when table pTab is +** being dropped from the database. The SrcList passed as the second argument +** to this function contains a single entry guaranteed to resolve to +** table pTab. +** +** Normally, no code is required. However, if either +** +** (a) The table is the parent table of a FK constraint, or +** (b) The table is the child table of a deferred FK constraint and it is +** determined at runtime that there are outstanding deferred FK +** constraint violations in the database, +** +** then the equivalent of "DELETE FROM " is executed before dropping +** the table from the database. Triggers are disabled while running this +** DELETE, but foreign key actions are not. +*/ +SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ + sqlite3 *db = pParse->db; + if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){ + int iSkip = 0; + Vdbe *v = sqlite3GetVdbe(pParse); + + assert( v ); /* VDBE has already been allocated */ + if( sqlite3FkReferences(pTab)==0 ){ + /* Search for a deferred foreign key constraint for which this table + ** is the child table. If one cannot be found, return without + ** generating any VDBE code. If one can be found, then jump over + ** the entire DELETE if there are no outstanding deferred constraints + ** when this statement is run. */ + FKey *p; + for(p=pTab->pFKey; p; p=p->pNextFrom){ + if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; + } + if( !p ) return; + iSkip = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v); + } + + pParse->disableTriggers = 1; + sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0); + pParse->disableTriggers = 0; + + /* If the DELETE has generated immediate foreign key constraint + ** violations, halt the VDBE and return an error at this point, before + ** any modifications to the schema are made. This is because statement + ** transactions are not able to rollback schema changes. + ** + ** If the SQLITE_DeferFKs flag is set, then this is not required, as + ** the statement transaction will not be rolled back even if FK + ** constraints are violated. + */ + if( (db->flags & SQLITE_DeferFKs)==0 ){ + sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, + OE_Abort, 0, P4_STATIC, P5_ConstraintFK); + } + + if( iSkip ){ + sqlite3VdbeResolveLabel(v, iSkip); + } + } +} + + +/* +** The second argument points to an FKey object representing a foreign key +** for which pTab is the child table. An UPDATE statement against pTab +** is currently being processed. For each column of the table that is +** actually updated, the corresponding element in the aChange[] array +** is zero or greater (if a column is unmodified the corresponding element +** is set to -1). If the rowid column is modified by the UPDATE statement +** the bChngRowid argument is non-zero. +** +** This function returns true if any of the columns that are part of the +** child key for FK constraint *p are modified. +*/ +static int fkChildIsModified( + Table *pTab, /* Table being updated */ + FKey *p, /* Foreign key for which pTab is the child */ + int *aChange, /* Array indicating modified columns */ + int bChngRowid /* True if rowid is modified by this update */ +){ + int i; + for(i=0; inCol; i++){ + int iChildKey = p->aCol[i].iFrom; + if( aChange[iChildKey]>=0 ) return 1; + if( iChildKey==pTab->iPKey && bChngRowid ) return 1; + } + return 0; +} + +/* +** The second argument points to an FKey object representing a foreign key +** for which pTab is the parent table. An UPDATE statement against pTab +** is currently being processed. For each column of the table that is +** actually updated, the corresponding element in the aChange[] array +** is zero or greater (if a column is unmodified the corresponding element +** is set to -1). If the rowid column is modified by the UPDATE statement +** the bChngRowid argument is non-zero. +** +** This function returns true if any of the columns that are part of the +** parent key for FK constraint *p are modified. +*/ +static int fkParentIsModified( + Table *pTab, + FKey *p, + int *aChange, + int bChngRowid +){ + int i; + for(i=0; inCol; i++){ + char *zKey = p->aCol[i].zCol; + int iKey; + for(iKey=0; iKeynCol; iKey++){ + if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){ + Column *pCol = &pTab->aCol[iKey]; + if( zKey ){ + if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1; + }else if( pCol->colFlags & COLFLAG_PRIMKEY ){ + return 1; + } + } + } + } + return 0; +} + +/* +** Return true if the parser passed as the first argument is being +** used to code a trigger that is really a "SET NULL" action belonging +** to trigger pFKey. +*/ +static int isSetNullAction(Parse *pParse, FKey *pFKey){ + Parse *pTop = sqlite3ParseToplevel(pParse); + if( pTop->pTriggerPrg ){ + Trigger *p = pTop->pTriggerPrg->pTrigger; + if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull) + || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull) + ){ + return 1; + } + } + return 0; +} + +/* +** This function is called when inserting, deleting or updating a row of +** table pTab to generate VDBE code to perform foreign key constraint +** processing for the operation. +** +** For a DELETE operation, parameter regOld is passed the index of the +** first register in an array of (pTab->nCol+1) registers containing the +** rowid of the row being deleted, followed by each of the column values +** of the row being deleted, from left to right. Parameter regNew is passed +** zero in this case. +** +** For an INSERT operation, regOld is passed zero and regNew is passed the +** first register of an array of (pTab->nCol+1) registers containing the new +** row data. +** +** For an UPDATE operation, this function is called twice. Once before +** the original record is deleted from the table using the calling convention +** described for DELETE. Then again after the original record is deleted +** but before the new record is inserted using the INSERT convention. +*/ +SQLITE_PRIVATE void sqlite3FkCheck( + Parse *pParse, /* Parse context */ + Table *pTab, /* Row is being deleted from this table */ + int regOld, /* Previous row data is stored here */ + int regNew, /* New row data is stored here */ + int *aChange, /* Array indicating UPDATEd columns (or 0) */ + int bChngRowid /* True if rowid is UPDATEd */ +){ + sqlite3 *db = pParse->db; /* Database handle */ + FKey *pFKey; /* Used to iterate through FKs */ + int iDb; /* Index of database containing pTab */ + const char *zDb; /* Name of database containing pTab */ + int isIgnoreErrors = pParse->disableTriggers; + + /* Exactly one of regOld and regNew should be non-zero. */ + assert( (regOld==0)!=(regNew==0) ); + + /* If foreign-keys are disabled, this function is a no-op. */ + if( (db->flags&SQLITE_ForeignKeys)==0 ) return; + + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + zDb = db->aDb[iDb].zDbSName; + + /* Loop through all the foreign key constraints for which pTab is the + ** child table (the table that the foreign key definition is part of). */ + for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + Table *pTo; /* Parent table of foreign key pFKey */ + Index *pIdx = 0; /* Index on key columns in pTo */ + int *aiFree = 0; + int *aiCol; + int iCol; + int i; + int bIgnore = 0; + + if( aChange + && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0 + && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0 + ){ + continue; + } + + /* Find the parent table of this foreign key. Also find a unique index + ** on the parent key columns in the parent table. If either of these + ** schema items cannot be located, set an error in pParse and return + ** early. */ + if( pParse->disableTriggers ){ + pTo = sqlite3FindTable(db, pFKey->zTo, zDb); + }else{ + pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); + } + if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ + assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); + if( !isIgnoreErrors || db->mallocFailed ) return; + if( pTo==0 ){ + /* If isIgnoreErrors is true, then a table is being dropped. In this + ** case SQLite runs a "DELETE FROM xxx" on the table being dropped + ** before actually dropping it in order to check FK constraints. + ** If the parent table of an FK constraint on the current table is + ** missing, behave as if it is empty. i.e. decrement the relevant + ** FK counter for each row of the current table with non-NULL keys. + */ + Vdbe *v = sqlite3GetVdbe(pParse); + int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; + for(i=0; inCol; i++){ + int iReg = pFKey->aCol[i].iFrom + regOld + 1; + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v); + } + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); + } + continue; + } + assert( pFKey->nCol==1 || (aiFree && pIdx) ); + + if( aiFree ){ + aiCol = aiFree; + }else{ + iCol = pFKey->aCol[0].iFrom; + aiCol = &iCol; + } + for(i=0; inCol; i++){ + if( aiCol[i]==pTab->iPKey ){ + aiCol[i] = -1; + } + assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Request permission to read the parent key columns. If the + ** authorization callback returns SQLITE_IGNORE, behave as if any + ** values read from the parent table are NULL. */ + if( db->xAuth ){ + int rcauth; + char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; + rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); + bIgnore = (rcauth==SQLITE_IGNORE); + } +#endif + } + + /* Take a shared-cache advisory read-lock on the parent table. Allocate + ** a cursor to use to search the unique index on the parent key columns + ** in the parent table. */ + sqlite3TableLock(pParse, iDb, pTo->tnum, 0, pTo->zName); + pParse->nTab++; + + if( regOld!=0 ){ + /* A row is being removed from the child table. Search for the parent. + ** If the parent does not exist, removing the child row resolves an + ** outstanding foreign key constraint violation. */ + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore); + } + if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){ + /* A row is being added to the child table. If a parent row cannot + ** be found, adding the child row has violated the FK constraint. + ** + ** If this operation is being performed as part of a trigger program + ** that is actually a "SET NULL" action belonging to this very + ** foreign key, then omit this scan altogether. As all child key + ** values are guaranteed to be NULL, it is not possible for adding + ** this row to cause an FK violation. */ + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore); + } + + sqlite3DbFree(db, aiFree); + } + + /* Loop through all the foreign key constraints that refer to this table. + ** (the "child" constraints) */ + for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){ + Index *pIdx = 0; /* Foreign key index for pFKey */ + SrcList *pSrc; + int *aiCol = 0; + + if( aChange && fkParentIsModified(pTab, pFKey, aChange, bChngRowid)==0 ){ + continue; + } + + if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel && !pParse->isMultiWrite + ){ + assert( regOld==0 && regNew!=0 ); + /* Inserting a single row into a parent table cannot cause (or fix) + ** an immediate foreign key violation. So do nothing in this case. */ + continue; + } + + if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ + if( !isIgnoreErrors || db->mallocFailed ) return; + continue; + } + assert( aiCol || pFKey->nCol==1 ); + + /* Create a SrcList structure containing the child table. We need the + ** child table as a SrcList for sqlite3WhereBegin() */ + pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + if( pSrc ){ + struct SrcList_item *pItem = pSrc->a; + pItem->pTab = pFKey->pFrom; + pItem->zName = pFKey->pFrom->zName; + pItem->pTab->nTabRef++; + pItem->iCursor = pParse->nTab++; + + if( regNew!=0 ){ + fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); + } + if( regOld!=0 ){ + int eAction = pFKey->aAction[aChange!=0]; + fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1); + /* If this is a deferred FK constraint, or a CASCADE or SET NULL + ** action applies, then any foreign key violations caused by + ** removing the parent key will be rectified by the action trigger. + ** So do not set the "may-abort" flag in this case. + ** + ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the + ** may-abort flag will eventually be set on this statement anyway + ** (when this function is called as part of processing the UPDATE + ** within the action trigger). + ** + ** Note 2: At first glance it may seem like SQLite could simply omit + ** all OP_FkCounter related scans when either CASCADE or SET NULL + ** applies. The trouble starts if the CASCADE or SET NULL action + ** trigger causes other triggers or action rules attached to the + ** child table to fire. In these cases the fk constraint counters + ** might be set incorrectly if any OP_FkCounter related scans are + ** omitted. */ + if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){ + sqlite3MayAbort(pParse); + } + } + pItem->zName = 0; + sqlite3SrcListDelete(db, pSrc); + } + sqlite3DbFree(db, aiCol); + } +} + +#define COLUMN_MASK(x) (((x)>31) ? 0xffffffff : ((u32)1<<(x))) + +/* +** This function is called before generating code to update or delete a +** row contained in table pTab. +*/ +SQLITE_PRIVATE u32 sqlite3FkOldmask( + Parse *pParse, /* Parse context */ + Table *pTab /* Table being modified */ +){ + u32 mask = 0; + if( pParse->db->flags&SQLITE_ForeignKeys ){ + FKey *p; + int i; + for(p=pTab->pFKey; p; p=p->pNextFrom){ + for(i=0; inCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); + } + for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ + Index *pIdx = 0; + sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); + if( pIdx ){ + for(i=0; inKeyCol; i++){ + assert( pIdx->aiColumn[i]>=0 ); + mask |= COLUMN_MASK(pIdx->aiColumn[i]); + } + } + } + } + return mask; +} + + +/* +** This function is called before generating code to update or delete a +** row contained in table pTab. If the operation is a DELETE, then +** parameter aChange is passed a NULL value. For an UPDATE, aChange points +** to an array of size N, where N is the number of columns in table pTab. +** If the i'th column is not modified by the UPDATE, then the corresponding +** entry in the aChange[] array is set to -1. If the column is modified, +** the value is 0 or greater. Parameter chngRowid is set to true if the +** UPDATE statement modifies the rowid fields of the table. +** +** If any foreign key processing will be required, this function returns +** non-zero. If there is no foreign key related processing, this function +** returns zero. +** +** For an UPDATE, this function returns 2 if: +** +** * There are any FKs for which pTab is the child and the parent table, or +** * the UPDATE modifies one or more parent keys for which the action is +** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL). +** +** Or, assuming some other foreign key processing is required, 1. +*/ +SQLITE_PRIVATE int sqlite3FkRequired( + Parse *pParse, /* Parse context */ + Table *pTab, /* Table being modified */ + int *aChange, /* Non-NULL for UPDATE operations */ + int chngRowid /* True for UPDATE that affects rowid */ +){ + int eRet = 0; + if( pParse->db->flags&SQLITE_ForeignKeys ){ + if( !aChange ){ + /* A DELETE operation. Foreign key processing is required if the + ** table in question is either the child or parent table for any + ** foreign key constraint. */ + eRet = (sqlite3FkReferences(pTab) || pTab->pFKey); + }else{ + /* This is an UPDATE. Foreign key processing is only required if the + ** operation modifies one or more child or parent key columns. */ + FKey *p; + + /* Check if any child key columns are being modified. */ + for(p=pTab->pFKey; p; p=p->pNextFrom){ + if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2; + if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ + eRet = 1; + } + } + + /* Check if any parent key columns are being modified. */ + for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ + if( fkParentIsModified(pTab, p, aChange, chngRowid) ){ + if( p->aAction[1]!=OE_None ) return 2; + eRet = 1; + } + } + } + } + return eRet; +} + +/* +** This function is called when an UPDATE or DELETE operation is being +** compiled on table pTab, which is the parent table of foreign-key pFKey. +** If the current operation is an UPDATE, then the pChanges parameter is +** passed a pointer to the list of columns being modified. If it is a +** DELETE, pChanges is passed a NULL pointer. +** +** It returns a pointer to a Trigger structure containing a trigger +** equivalent to the ON UPDATE or ON DELETE action specified by pFKey. +** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is +** returned (these actions require no special handling by the triggers +** sub-system, code for them is created by fkScanChildren()). +** +** For example, if pFKey is the foreign key and pTab is table "p" in +** the following schema: +** +** CREATE TABLE p(pk PRIMARY KEY); +** CREATE TABLE c(ck REFERENCES p ON DELETE CASCADE); +** +** then the returned trigger structure is equivalent to: +** +** CREATE TRIGGER ... DELETE ON p BEGIN +** DELETE FROM c WHERE ck = old.pk; +** END; +** +** The returned pointer is cached as part of the foreign key object. It +** is eventually freed along with the rest of the foreign key object by +** sqlite3FkDelete(). +*/ +static Trigger *fkActionTrigger( + Parse *pParse, /* Parse context */ + Table *pTab, /* Table being updated or deleted from */ + FKey *pFKey, /* Foreign key to get action for */ + ExprList *pChanges /* Change-list for UPDATE, NULL for DELETE */ +){ + sqlite3 *db = pParse->db; /* Database handle */ + int action; /* One of OE_None, OE_Cascade etc. */ + Trigger *pTrigger; /* Trigger definition to return */ + int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */ + + action = pFKey->aAction[iAction]; + if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){ + return 0; + } + pTrigger = pFKey->apTrigger[iAction]; + + if( action!=OE_None && !pTrigger ){ + char const *zFrom; /* Name of child table */ + int nFrom; /* Length in bytes of zFrom */ + Index *pIdx = 0; /* Parent key index for this FK */ + int *aiCol = 0; /* child table cols -> parent key cols */ + TriggerStep *pStep = 0; /* First (only) step of trigger program */ + Expr *pWhere = 0; /* WHERE clause of trigger step */ + ExprList *pList = 0; /* Changes list if ON UPDATE CASCADE */ + Select *pSelect = 0; /* If RESTRICT, "SELECT RAISE(...)" */ + int i; /* Iterator variable */ + Expr *pWhen = 0; /* WHEN clause for the trigger */ + + if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; + assert( aiCol || pFKey->nCol==1 ); + + for(i=0; inCol; i++){ + Token tOld = { "old", 3 }; /* Literal "old" token */ + Token tNew = { "new", 3 }; /* Literal "new" token */ + Token tFromCol; /* Name of column in child table */ + Token tToCol; /* Name of column in parent table */ + int iFromCol; /* Idx of column in child table */ + Expr *pEq; /* tFromCol = OLD.tToCol */ + + iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; + assert( iFromCol>=0 ); + assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKeynCol) ); + assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); + sqlite3TokenInit(&tToCol, + pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName); + sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName); + + /* Create the expression "OLD.zToCol = zFromCol". It is important + ** that the "OLD.zToCol" term is on the LHS of the = operator, so + ** that the affinity and collation sequence associated with the + ** parent table are used for the comparison. */ + pEq = sqlite3PExpr(pParse, TK_EQ, + sqlite3PExpr(pParse, TK_DOT, + sqlite3ExprAlloc(db, TK_ID, &tOld, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), + sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) + ); + pWhere = sqlite3ExprAnd(db, pWhere, pEq); + + /* For ON UPDATE, construct the next term of the WHEN clause. + ** The final WHEN clause will be like this: + ** + ** WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN) + */ + if( pChanges ){ + pEq = sqlite3PExpr(pParse, TK_IS, + sqlite3PExpr(pParse, TK_DOT, + sqlite3ExprAlloc(db, TK_ID, &tOld, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), + sqlite3PExpr(pParse, TK_DOT, + sqlite3ExprAlloc(db, TK_ID, &tNew, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)) + ); + pWhen = sqlite3ExprAnd(db, pWhen, pEq); + } + + if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){ + Expr *pNew; + if( action==OE_Cascade ){ + pNew = sqlite3PExpr(pParse, TK_DOT, + sqlite3ExprAlloc(db, TK_ID, &tNew, 0), + sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)); + }else if( action==OE_SetDflt ){ + Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt; + if( pDflt ){ + pNew = sqlite3ExprDup(db, pDflt, 0); + }else{ + pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); + } + }else{ + pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); + } + pList = sqlite3ExprListAppend(pParse, pList, pNew); + sqlite3ExprListSetName(pParse, pList, &tFromCol, 0); + } + } + sqlite3DbFree(db, aiCol); + + zFrom = pFKey->pFrom->zName; + nFrom = sqlite3Strlen30(zFrom); + + if( action==OE_Restrict ){ + Token tFrom; + Expr *pRaise; + + tFrom.z = zFrom; + tFrom.n = nFrom; + pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); + if( pRaise ){ + pRaise->affinity = OE_Abort; + } + pSelect = sqlite3SelectNew(pParse, + sqlite3ExprListAppend(pParse, 0, pRaise), + sqlite3SrcListAppend(db, 0, &tFrom, 0), + pWhere, + 0, 0, 0, 0, 0, 0 + ); + pWhere = 0; + } + + /* Disable lookaside memory allocation */ + db->lookaside.bDisable++; + + pTrigger = (Trigger *)sqlite3DbMallocZero(db, + sizeof(Trigger) + /* struct Trigger */ + sizeof(TriggerStep) + /* Single step in trigger program */ + nFrom + 1 /* Space for pStep->zTarget */ + ); + if( pTrigger ){ + pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1]; + pStep->zTarget = (char *)&pStep[1]; + memcpy((char *)pStep->zTarget, zFrom, nFrom); + + pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); + pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + if( pWhen ){ + pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0); + pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); + } + } + + /* Re-enable the lookaside buffer, if it was disabled earlier. */ + db->lookaside.bDisable--; + + sqlite3ExprDelete(db, pWhere); + sqlite3ExprDelete(db, pWhen); + sqlite3ExprListDelete(db, pList); + sqlite3SelectDelete(db, pSelect); + if( db->mallocFailed==1 ){ + fkTriggerDelete(db, pTrigger); + return 0; + } + assert( pStep!=0 ); + + switch( action ){ + case OE_Restrict: + pStep->op = TK_SELECT; + break; + case OE_Cascade: + if( !pChanges ){ + pStep->op = TK_DELETE; + break; + } + default: + pStep->op = TK_UPDATE; + } + pStep->pTrig = pTrigger; + pTrigger->pSchema = pTab->pSchema; + pTrigger->pTabSchema = pTab->pSchema; + pFKey->apTrigger[iAction] = pTrigger; + pTrigger->op = (pChanges ? TK_UPDATE : TK_DELETE); + } + + return pTrigger; +} + +/* +** This function is called when deleting or updating a row to implement +** any required CASCADE, SET NULL or SET DEFAULT actions. +*/ +SQLITE_PRIVATE void sqlite3FkActions( + Parse *pParse, /* Parse context */ + Table *pTab, /* Table being updated or deleted from */ + ExprList *pChanges, /* Change-list for UPDATE, NULL for DELETE */ + int regOld, /* Address of array containing old row */ + int *aChange, /* Array indicating UPDATEd columns (or 0) */ + int bChngRowid /* True if rowid is UPDATEd */ +){ + /* If foreign-key support is enabled, iterate through all FKs that + ** refer to table pTab. If there is an action associated with the FK + ** for this operation (either update or delete), invoke the associated + ** trigger sub-program. */ + if( pParse->db->flags&SQLITE_ForeignKeys ){ + FKey *pFKey; /* Iterator variable */ + for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){ + if( aChange==0 || fkParentIsModified(pTab, pFKey, aChange, bChngRowid) ){ + Trigger *pAct = fkActionTrigger(pParse, pTab, pFKey, pChanges); + if( pAct ){ + sqlite3CodeRowTriggerDirect(pParse, pAct, pTab, regOld, OE_Abort, 0); + } + } + } + } +} + +#endif /* ifndef SQLITE_OMIT_TRIGGER */ + +/* +** Free all memory associated with foreign key definitions attached to +** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash +** hash table. +*/ +SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ + FKey *pFKey; /* Iterator variable */ + FKey *pNext; /* Copy of pFKey->pNextFrom */ + + assert( db==0 || IsVirtual(pTab) + || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); + for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ + + /* Remove the FK from the fkeyHash hash table. */ + if( !db || db->pnBytesFreed==0 ){ + if( pFKey->pPrevTo ){ + pFKey->pPrevTo->pNextTo = pFKey->pNextTo; + }else{ + void *p = (void *)pFKey->pNextTo; + const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo); + sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p); + } + if( pFKey->pNextTo ){ + pFKey->pNextTo->pPrevTo = pFKey->pPrevTo; + } + } + + /* EV: R-30323-21917 Each foreign key constraint in SQLite is + ** classified as either immediate or deferred. + */ + assert( pFKey->isDeferred==0 || pFKey->isDeferred==1 ); + + /* Delete any triggers created to implement actions for this FK. */ +#ifndef SQLITE_OMIT_TRIGGER + fkTriggerDelete(db, pFKey->apTrigger[0]); + fkTriggerDelete(db, pFKey->apTrigger[1]); +#endif + + pNext = pFKey->pNextFrom; + sqlite3DbFree(db, pFKey); + } +} +#endif /* ifndef SQLITE_OMIT_FOREIGN_KEY */ + +/************** End of fkey.c ************************************************/ +/************** Begin file insert.c ******************************************/ +/* +** 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 C code routines that are called by the parser +** to handle INSERT statements in SQLite. +*/ +/* #include "sqliteInt.h" */ + +/* +** Generate code that will +** +** (1) acquire a lock for table pTab then +** (2) open pTab as cursor iCur. +** +** If pTab is a WITHOUT ROWID table, then it is the PRIMARY KEY index +** for that table that is actually opened. +*/ +SQLITE_PRIVATE void sqlite3OpenTable( + Parse *pParse, /* Generate code into this VDBE */ + int iCur, /* The cursor number of the table */ + int iDb, /* The database index in sqlite3.aDb[] */ + Table *pTab, /* The table to be opened */ + int opcode /* OP_OpenRead or OP_OpenWrite */ +){ + Vdbe *v; + assert( !IsVirtual(pTab) ); + v = sqlite3GetVdbe(pParse); + assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); + sqlite3TableLock(pParse, iDb, pTab->tnum, + (opcode==OP_OpenWrite)?1:0, pTab->zName); + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol); + VdbeComment((v, "%s", pTab->zName)); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); + assert( pPk->tnum==pTab->tnum ); + sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); + VdbeComment((v, "%s", pTab->zName)); + } +} + +/* +** Return a pointer to the column affinity string associated with index +** pIdx. A column affinity string has one character for each column in +** the table, according to the affinity of the column: +** +** Character Column affinity +** ------------------------------ +** 'A' BLOB +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'F' REAL +** +** An extra 'D' is appended to the end of the string to cover the +** rowid that appears as the last column in every index. +** +** Memory for the buffer containing the column index affinity string +** is managed along with the rest of the Index structure. It will be +** released when sqlite3DeleteIndex() is called. +*/ +SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ + if( !pIdx->zColAff ){ + /* The first time a column affinity string for a particular index is + ** required, it is allocated and populated here. It is then stored as + ** a member of the Index structure for subsequent use. + ** + ** The column affinity string will eventually be deleted by + ** sqliteDeleteIndex() when the Index structure itself is cleaned + ** up. + */ + int n; + Table *pTab = pIdx->pTable; + pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); + if( !pIdx->zColAff ){ + sqlite3OomFault(db); + return 0; + } + for(n=0; nnColumn; n++){ + i16 x = pIdx->aiColumn[n]; + if( x>=0 ){ + pIdx->zColAff[n] = pTab->aCol[x].affinity; + }else if( x==XN_ROWID ){ + pIdx->zColAff[n] = SQLITE_AFF_INTEGER; + }else{ + char aff; + assert( x==XN_EXPR ); + assert( pIdx->aColExpr!=0 ); + aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); + if( aff==0 ) aff = SQLITE_AFF_BLOB; + pIdx->zColAff[n] = aff; + } + } + pIdx->zColAff[n] = 0; + } + + return pIdx->zColAff; +} + +/* +** Compute the affinity string for table pTab, if it has not already been +** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. +** +** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and +** if iReg>0 then code an OP_Affinity opcode that will set the affinities +** for register iReg and following. Or if affinities exists and iReg==0, +** then just set the P4 operand of the previous opcode (which should be +** an OP_MakeRecord) to the affinity string. +** +** A column affinity string has one character per column: +** +** Character Column affinity +** ------------------------------ +** 'A' BLOB +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'E' REAL +*/ +SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ + int i; + char *zColAff = pTab->zColAff; + if( zColAff==0 ){ + sqlite3 *db = sqlite3VdbeDb(v); + zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1); + if( !zColAff ){ + sqlite3OomFault(db); + return; + } + + for(i=0; inCol; i++){ + zColAff[i] = pTab->aCol[i].affinity; + } + do{ + zColAff[i--] = 0; + }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB ); + pTab->zColAff = zColAff; + } + i = sqlite3Strlen30(zColAff); + if( i ){ + if( iReg ){ + sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); + }else{ + sqlite3VdbeChangeP4(v, -1, zColAff, i); + } + } +} + +/* +** Return non-zero if the table pTab in database iDb or any of its indices +** have been opened at any point in the VDBE program. This is used to see if +** a statement of the form "INSERT INTO SELECT ..." can +** run without using a temporary table for the results of the SELECT. +*/ +static int readsTable(Parse *p, int iDb, Table *pTab){ + Vdbe *v = sqlite3GetVdbe(p); + int i; + int iEnd = sqlite3VdbeCurrentAddr(v); +#ifndef SQLITE_OMIT_VIRTUALTABLE + VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0; +#endif + + for(i=1; iopcode==OP_OpenRead && pOp->p3==iDb ){ + Index *pIndex; + int tnum = pOp->p2; + if( tnum==pTab->tnum ){ + return 1; + } + for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ + if( tnum==pIndex->tnum ){ + return 1; + } + } + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pVTab ){ + assert( pOp->p4.pVtab!=0 ); + assert( pOp->p4type==P4_VTAB ); + return 1; + } +#endif + } + return 0; +} + +#ifndef SQLITE_OMIT_AUTOINCREMENT +/* +** Locate or create an AutoincInfo structure associated with table pTab +** which is in database iDb. Return the register number for the register +** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT +** table. (Also return zero when doing a VACUUM since we do not want to +** update the AUTOINCREMENT counters during a VACUUM.) +** +** There is at most one AutoincInfo structure per table even if the +** same table is autoincremented multiple times due to inserts within +** triggers. A new AutoincInfo structure is created if this is the +** first use of table pTab. On 2nd and subsequent uses, the original +** AutoincInfo structure is used. +** +** Three memory locations are allocated: +** +** (1) Register to hold the name of the pTab table. +** (2) Register to hold the maximum ROWID of pTab. +** (3) Register to hold the rowid in sqlite_sequence of pTab +** +** The 2nd register is the one that is returned. That is all the +** insert routine needs to know about. +*/ +static int autoIncBegin( + Parse *pParse, /* Parsing context */ + int iDb, /* Index of the database holding pTab */ + Table *pTab /* The table we are writing to */ +){ + int memId = 0; /* Register holding maximum rowid */ + if( (pTab->tabFlags & TF_Autoincrement)!=0 + && (pParse->db->flags & SQLITE_Vacuum)==0 + ){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + AutoincInfo *pInfo; + + pInfo = pToplevel->pAinc; + while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } + if( pInfo==0 ){ + pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); + if( pInfo==0 ) return 0; + pInfo->pNext = pToplevel->pAinc; + pToplevel->pAinc = pInfo; + pInfo->pTab = pTab; + pInfo->iDb = iDb; + pToplevel->nMem++; /* Register to hold name of table */ + pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */ + pToplevel->nMem++; /* Rowid in sqlite_sequence */ + } + memId = pInfo->regCtr; + } + return memId; +} + +/* +** This routine generates code that will initialize all of the +** register used by the autoincrement tracker. +*/ +SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ + AutoincInfo *p; /* Information about an AUTOINCREMENT */ + sqlite3 *db = pParse->db; /* The database connection */ + Db *pDb; /* Database only autoinc table */ + int memId; /* Register holding max rowid */ + Vdbe *v = pParse->pVdbe; /* VDBE under construction */ + + /* This routine is never called during trigger-generation. It is + ** only called from the top-level */ + assert( pParse->pTriggerTab==0 ); + assert( sqlite3IsToplevel(pParse) ); + + assert( v ); /* We failed long ago if this is not so */ + for(p = pParse->pAinc; p; p = p->pNext){ + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList autoInc[] = { + /* 0 */ {OP_Null, 0, 0, 0}, + /* 1 */ {OP_Rewind, 0, 9, 0}, + /* 2 */ {OP_Column, 0, 0, 0}, + /* 3 */ {OP_Ne, 0, 7, 0}, + /* 4 */ {OP_Rowid, 0, 0, 0}, + /* 5 */ {OP_Column, 0, 1, 0}, + /* 6 */ {OP_Goto, 0, 9, 0}, + /* 7 */ {OP_Next, 0, 2, 0}, + /* 8 */ {OP_Integer, 0, 0, 0}, + /* 9 */ {OP_Close, 0, 0, 0} + }; + VdbeOp *aOp; + pDb = &db->aDb[p->iDb]; + memId = p->regCtr; + assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); + sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); + sqlite3VdbeLoadString(v, memId-1, p->pTab->zName); + aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn); + if( aOp==0 ) break; + aOp[0].p2 = memId; + aOp[0].p3 = memId+1; + aOp[2].p3 = memId; + aOp[3].p1 = memId-1; + aOp[3].p3 = memId; + aOp[3].p5 = SQLITE_JUMPIFNULL; + aOp[4].p2 = memId+1; + aOp[5].p3 = memId; + aOp[8].p2 = memId; + } +} + +/* +** Update the maximum rowid for an autoincrement calculation. +** +** This routine should be called when the regRowid register holds a +** new rowid that is about to be inserted. If that new rowid is +** larger than the maximum rowid in the memId memory cell, then the +** memory cell is updated. +*/ +static void autoIncStep(Parse *pParse, int memId, int regRowid){ + if( memId>0 ){ + sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, regRowid); + } +} + +/* +** This routine generates the code needed to write autoincrement +** maximum rowid values back into the sqlite_sequence register. +** Every statement that might do an INSERT into an autoincrement +** table (either directly or through triggers) needs to call this +** routine just before the "exit" code. +*/ +static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){ + AutoincInfo *p; + Vdbe *v = pParse->pVdbe; + sqlite3 *db = pParse->db; + + assert( v ); + for(p = pParse->pAinc; p; p = p->pNext){ + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList autoIncEnd[] = { + /* 0 */ {OP_NotNull, 0, 2, 0}, + /* 1 */ {OP_NewRowid, 0, 0, 0}, + /* 2 */ {OP_MakeRecord, 0, 2, 0}, + /* 3 */ {OP_Insert, 0, 0, 0}, + /* 4 */ {OP_Close, 0, 0, 0} + }; + VdbeOp *aOp; + Db *pDb = &db->aDb[p->iDb]; + int iRec; + int memId = p->regCtr; + + iRec = sqlite3GetTempReg(pParse); + assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); + sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); + aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn); + if( aOp==0 ) break; + aOp[0].p1 = memId+1; + aOp[1].p2 = memId+1; + aOp[2].p1 = memId-1; + aOp[2].p3 = iRec; + aOp[3].p2 = iRec; + aOp[3].p3 = memId+1; + aOp[3].p5 = OPFLAG_APPEND; + sqlite3ReleaseTempReg(pParse, iRec); + } +} +SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){ + if( pParse->pAinc ) autoIncrementEnd(pParse); +} +#else +/* +** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines +** above are all no-ops +*/ +# define autoIncBegin(A,B,C) (0) +# define autoIncStep(A,B,C) +#endif /* SQLITE_OMIT_AUTOINCREMENT */ + + +/* Forward declaration */ +static int xferOptimization( + Parse *pParse, /* Parser context */ + Table *pDest, /* The table we are inserting into */ + Select *pSelect, /* A SELECT statement to use as the data source */ + int onError, /* How to handle constraint errors */ + int iDbDest /* The database of pDest */ +); + +/* +** This routine is called to handle SQL of the following forms: +** +** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),... +** insert into TABLE (IDLIST) select +** insert into TABLE (IDLIST) default values +** +** The IDLIST following the table name is always optional. If omitted, +** then a list of all (non-hidden) columns for the table is substituted. +** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST +** is omitted. +** +** For the pSelect parameter holds the values to be inserted for the +** first two forms shown above. A VALUES clause is really just short-hand +** for a SELECT statement that omits the FROM clause and everything else +** that follows. If the pSelect parameter is NULL, that means that the +** DEFAULT VALUES form of the INSERT statement is intended. +** +** The code generated follows one of four templates. For a simple +** insert with data coming from a single-row VALUES clause, the code executes +** once straight down through. Pseudo-code follows (we call this +** the "1st template"): +** +** open write cursor to
    and its indices +** put VALUES clause expressions into registers +** write the resulting record into
    +** cleanup +** +** The three remaining templates assume the statement is of the form +** +** INSERT INTO
    SELECT ... +** +** If the SELECT clause is of the restricted form "SELECT * FROM " - +** in other words if the SELECT pulls all columns from a single table +** and there is no WHERE or LIMIT or GROUP BY or ORDER BY clauses, and +** if and are distinct tables but have identical +** schemas, including all the same indices, then a special optimization +** is invoked that copies raw records from over to . +** See the xferOptimization() function for the implementation of this +** template. This is the 2nd template. +** +** open a write cursor to
    +** open read cursor on +** transfer all records in over to
    +** close cursors +** foreach index on
    +** open a write cursor on the
    index +** open a read cursor on the corresponding index +** transfer all records from the read to the write cursors +** close cursors +** end foreach +** +** The 3rd template is for when the second template does not apply +** and the SELECT clause does not read from
    at any time. +** The generated code follows this template: +** +** X <- A +** goto B +** A: setup for the SELECT +** loop over the rows in the SELECT +** load values into registers R..R+n +** yield X +** end loop +** cleanup after the SELECT +** end-coroutine X +** B: open write cursor to
    and its indices +** C: yield X, at EOF goto D +** insert the select result into
    from R..R+n +** goto C +** D: cleanup +** +** The 4th template is used if the insert statement takes its +** values from a SELECT but the data is being inserted into a table +** that is also read as part of the SELECT. In the third form, +** we have to use an intermediate table to store the results of +** the select. The template is like this: +** +** X <- A +** goto B +** A: setup for the SELECT +** loop over the tables in the SELECT +** load value into register R..R+n +** yield X +** end loop +** cleanup after the SELECT +** end co-routine R +** B: open temp table +** L: yield X, at EOF goto M +** insert row from R..R+n into temp table +** goto L +** M: open write cursor to
    and its indices +** rewind temp table +** C: loop over rows of intermediate table +** transfer values form intermediate table into
    +** end loop +** D: cleanup +*/ +SQLITE_PRIVATE void sqlite3Insert( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* Name of table into which we are inserting */ + Select *pSelect, /* A SELECT statement to use as the data source */ + IdList *pColumn, /* Column names corresponding to IDLIST. */ + int onError /* How to handle constraint errors */ +){ + 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 */ + int nColumn; /* Number of columns in the data */ + int nHidden = 0; /* Number of hidden columns if TABLE is virtual */ + int iDataCur = 0; /* VDBE cursor that is the main data repository */ + int iIdxCur = 0; /* First index cursor */ + int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ + int endOfLoop; /* Label for the end of the insertion loop */ + int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ + int addrInsTop = 0; /* Jump to label "D" */ + int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */ + SelectDest dest; /* Destination for SELECT on rhs of INSERT */ + int iDb; /* Index of database holding TABLE */ + u8 useTempTable = 0; /* Store SELECT results in intermediate table */ + u8 appendFlag = 0; /* True if the insert is likely to be an append */ + u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ + u8 bIdListInOrder; /* True if IDLIST is in table order */ + ExprList *pList = 0; /* List of VALUES() to be inserted */ + + /* Register allocations */ + int regFromSelect = 0;/* Base register for data coming from SELECT */ + int regAutoinc = 0; /* Register holding the AUTOINCREMENT counter */ + int regRowCount = 0; /* Memory cell used for the row counter */ + int regIns; /* Block of regs holding rowid+data being inserted */ + int regRowid; /* registers holding insert rowid */ + int regData; /* register holding first column to insert */ + int *aRegIdx = 0; /* One register allocated to each index */ + +#ifndef SQLITE_OMIT_TRIGGER + int isView; /* True if attempting to insert into a view */ + Trigger *pTrigger; /* List of triggers on pTab, if required */ + int tmask; /* Mask of trigger times */ +#endif + + db = pParse->db; + memset(&dest, 0, sizeof(dest)); + if( pParse->nErr || db->mallocFailed ){ + goto insert_cleanup; + } + + /* If the Select object is really just a simple VALUES() list with a + ** single row (the common case) then keep that one row of values + ** and discard the other (unused) parts of the pSelect object + */ + if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){ + pList = pSelect->pEList; + pSelect->pEList = 0; + sqlite3SelectDelete(db, pSelect); + pSelect = 0; + } + + /* 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; + } + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDbnDb ); + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, + db->aDb[iDb].zDbSName) ){ + goto insert_cleanup; + } + withoutRowid = !HasRowid(pTab); + + /* Figure out if we have any triggers and if the table being + ** inserted into is a view + */ +#ifndef SQLITE_OMIT_TRIGGER + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask); + isView = pTab->pSelect!=0; +#else +# define pTrigger 0 +# define tmask 0 +# define isView 0 +#endif +#ifdef SQLITE_OMIT_VIEW +# undef isView +# define isView 0 +#endif + assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) ); + + /* If pTab is really a view, make sure it has been initialized. + ** ViewGetColumnNames() is a no-op if pTab is not a view. + */ + if( sqlite3ViewGetColumnNames(pParse, pTab) ){ + goto insert_cleanup; + } + + /* Cannot insert into a read-only table. + */ + if( sqlite3IsReadOnly(pParse, pTab, tmask) ){ + goto insert_cleanup; + } + + /* Allocate a VDBE + */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto insert_cleanup; + if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); + sqlite3BeginWriteOperation(pParse, pSelect || pTrigger, iDb); + +#ifndef SQLITE_OMIT_XFER_OPT + /* If the statement is of the form + ** + ** INSERT INTO SELECT * FROM ; + ** + ** Then special optimizations can be applied that make the transfer + ** very fast and which reduce fragmentation of indices. + ** + ** This is the 2nd template. + */ + if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ + assert( !pTrigger ); + assert( pList==0 ); + goto insert_end; + } +#endif /* SQLITE_OMIT_XFER_OPT */ + + /* If this is an AUTOINCREMENT table, look up the sequence number in the + ** sqlite_sequence table and store it in memory cell regAutoinc. + */ + regAutoinc = autoIncBegin(pParse, iDb, pTab); + + /* Allocate registers for holding the rowid of the new row, + ** the content of the new row, and the assembled row record. + */ + regRowid = regIns = pParse->nMem+1; + pParse->nMem += pTab->nCol + 1; + if( IsVirtual(pTab) ){ + regRowid++; + pParse->nMem++; + } + regData = regRowid+1; + + /* If the INSERT statement included an IDLIST term, then make sure + ** all elements of the IDLIST really are columns of the table and + ** remember the column indices. + ** + ** If the table has an INTEGER PRIMARY KEY column and that column + ** is named in the IDLIST, then record in the ipkColumn variable + ** the index into IDLIST of the primary key column. ipkColumn is + ** the index of the primary key as it appears in IDLIST, not as + ** is appears in the original table. (The index of the INTEGER + ** PRIMARY KEY in the original table is pTab->iPKey.) + */ + bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0; + if( pColumn ){ + for(i=0; inId; i++){ + pColumn->a[i].idx = -1; + } + for(i=0; inId; i++){ + for(j=0; jnCol; j++){ + if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ + pColumn->a[i].idx = j; + if( i!=j ) bIdListInOrder = 0; + if( j==pTab->iPKey ){ + ipkColumn = i; assert( !withoutRowid ); + } + break; + } + } + if( j>=pTab->nCol ){ + if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ + ipkColumn = i; + bIdListInOrder = 0; + }else{ + sqlite3ErrorMsg(pParse, "table %S has no column named %s", + pTabList, 0, pColumn->a[i].zName); + pParse->checkSchema = 1; + goto insert_cleanup; + } + } + } + } + + /* Figure out how many columns of data are supplied. If the data + ** is coming from a SELECT statement, then generate a co-routine that + ** produces a single row of the SELECT on each invocation. The + ** co-routine is the common header to the 3rd and 4th templates. + */ + if( pSelect ){ + /* Data is coming from a SELECT or from a multi-row VALUES clause. + ** Generate a co-routine to run the SELECT. */ + int regYield; /* Register holding co-routine entry-point */ + int addrTop; /* Top of the co-routine */ + int rc; /* Result code */ + + regYield = ++pParse->nMem; + addrTop = sqlite3VdbeCurrentAddr(v) + 1; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); + dest.iSdst = bIdListInOrder ? regData : 0; + dest.nSdst = pTab->nCol; + rc = sqlite3Select(pParse, pSelect, &dest); + regFromSelect = dest.iSdst; + if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; + sqlite3VdbeEndCoroutine(v, regYield); + sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ + assert( pSelect->pEList ); + nColumn = pSelect->pEList->nExpr; + + /* Set useTempTable to TRUE if the result of the SELECT statement + ** should be written into a temporary table (template 4). Set to + ** FALSE if each output row of the SELECT can be written directly into + ** the destination table (template 3). + ** + ** A temp table must be used if the table being updated is also one + ** of the tables being read by the SELECT statement. Also use a + ** temp table in the case of row triggers. + */ + if( pTrigger || readsTable(pParse, iDb, pTab) ){ + useTempTable = 1; + } + + if( useTempTable ){ + /* Invoke the coroutine to extract information from the SELECT + ** and add it to a transient table srcTab. The code generated + ** here is from the 4th template: + ** + ** B: open temp table + ** L: yield X, goto M at EOF + ** insert row from R..R+n into temp table + ** goto L + ** M: ... + */ + int regRec; /* Register to hold packed record */ + int regTempRowid; /* Register to hold temp table ROWID */ + int addrL; /* Label "L" */ + + srcTab = pParse->nTab++; + regRec = sqlite3GetTempReg(pParse); + regTempRowid = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn); + addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec); + sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid); + sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid); + sqlite3VdbeGoto(v, addrL); + sqlite3VdbeJumpHere(v, addrL); + sqlite3ReleaseTempReg(pParse, regRec); + sqlite3ReleaseTempReg(pParse, regTempRowid); + } + }else{ + /* This is the case if the data for the INSERT is coming from a + ** single-row VALUES clause + */ + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + srcTab = -1; + assert( useTempTable==0 ); + if( pList ){ + nColumn = pList->nExpr; + if( sqlite3ResolveExprListNames(&sNC, pList) ){ + goto insert_cleanup; + } + }else{ + nColumn = 0; + } + } + + /* If there is no IDLIST term but the table has an integer primary + ** key, the set the ipkColumn variable to the integer primary key + ** column index in the original table definition. + */ + if( pColumn==0 && nColumn>0 ){ + ipkColumn = pTab->iPKey; + } + + /* Make sure the number of columns in the source data matches the number + ** of columns to be inserted into the table. + */ + for(i=0; inCol; i++){ + nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0); + } + if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){ + sqlite3ErrorMsg(pParse, + "table %S has %d columns but %d values were supplied", + pTabList, 0, pTab->nCol-nHidden, nColumn); + goto insert_cleanup; + } + if( pColumn!=0 && nColumn!=pColumn->nId ){ + sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); + goto insert_cleanup; + } + + /* Initialize the count of rows to be inserted + */ + if( db->flags & SQLITE_CountRows ){ + regRowCount = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); + } + + /* If this is not a view, open the table and and all indices */ + if( !isView ){ + int nIdx; + nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, + &iDataCur, &iIdxCur); + aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1)); + if( aRegIdx==0 ){ + goto insert_cleanup; + } + for(i=0, pIdx=pTab->pIndex; ipNext, i++){ + assert( pIdx ); + aRegIdx[i] = ++pParse->nMem; + pParse->nMem += pIdx->nColumn; + } + } + + /* This is the top of the main insertion loop */ + if( useTempTable ){ + /* This block codes the top of loop only. The complete loop is the + ** following pseudocode (template 4): + ** + ** rewind temp table, if empty goto D + ** C: loop over rows of intermediate table + ** transfer values form intermediate table into
    + ** end loop + ** D: ... + */ + addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); VdbeCoverage(v); + addrCont = sqlite3VdbeCurrentAddr(v); + }else if( pSelect ){ + /* This block codes the top of loop only. The complete loop is the + ** following pseudocode (template 3): + ** + ** C: yield X, at EOF goto D + ** insert the select result into
    from R..R+n + ** goto C + ** D: ... + */ + addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); + VdbeCoverage(v); + } + + /* Run the BEFORE and INSTEAD OF triggers, if there are any + */ + endOfLoop = sqlite3VdbeMakeLabel(v); + if( tmask & TRIGGER_BEFORE ){ + int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1); + + /* build the NEW.* reference row. Note that if there is an INTEGER + ** PRIMARY KEY into which a NULL is being inserted, that NULL will be + ** translated into a unique ID for the row. But on a BEFORE trigger, + ** we do not know what the unique ID will be (because the insert has + ** not happened yet) so we substitute a rowid of -1 + */ + if( ipkColumn<0 ){ + sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); + }else{ + int addr1; + assert( !withoutRowid ); + if( useTempTable ){ + sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols); + }else{ + assert( pSelect==0 ); /* Otherwise useTempTable is true */ + sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols); + } + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); + sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); + } + + /* Cannot have triggers on a virtual table. If it were possible, + ** this block would have to account for hidden column. + */ + assert( !IsVirtual(pTab) ); + + /* Create the new column data + */ + for(i=j=0; inCol; i++){ + if( pColumn ){ + for(j=0; jnId; j++){ + if( pColumn->a[j].idx==i ) break; + } + } + if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) + || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){ + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1); + }else if( useTempTable ){ + sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); + }else{ + assert( pSelect==0 ); /* Otherwise useTempTable is true */ + sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1); + } + if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++; + } + + /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, + ** do not attempt any conversions before assembling the record. + ** If this is a real table, attempt conversions as required by the + ** table column affinities. + */ + if( !isView ){ + sqlite3TableAffinity(v, pTab, regCols+1); + } + + /* Fire BEFORE or INSTEAD OF triggers */ + sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, + pTab, regCols-pTab->nCol-1, onError, endOfLoop); + + sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1); + } + + /* Compute the content of the next row to insert into a range of + ** registers beginning at regIns. + */ + if( !isView ){ + if( IsVirtual(pTab) ){ + /* The row that the VUpdate opcode will delete: none */ + sqlite3VdbeAddOp2(v, OP_Null, 0, regIns); + } + if( ipkColumn>=0 ){ + if( useTempTable ){ + sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid); + }else if( pSelect ){ + sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); + }else{ + VdbeOp *pOp; + sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); + pOp = sqlite3VdbeGetOp(v, -1); + if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){ + appendFlag = 1; + pOp->opcode = OP_NewRowid; + pOp->p1 = iDataCur; + pOp->p2 = regRowid; + pOp->p3 = regAutoinc; + } + } + /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid + ** to generate a unique primary key value. + */ + if( !appendFlag ){ + int addr1; + if( !IsVirtual(pTab) ){ + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); + sqlite3VdbeJumpHere(v, addr1); + }else{ + addr1 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v); + } + sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v); + } + }else if( IsVirtual(pTab) || withoutRowid ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); + }else{ + sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); + appendFlag = 1; + } + autoIncStep(pParse, regAutoinc, regRowid); + + /* Compute data for all columns of the new entry, beginning + ** with the first column. + */ + nHidden = 0; + for(i=0; inCol; i++){ + int iRegStore = regRowid+1+i; + if( i==pTab->iPKey ){ + /* The value of the INTEGER PRIMARY KEY column is always a NULL. + ** Whenever this column is read, the rowid will be substituted + ** in its place. Hence, fill this column with a NULL to avoid + ** taking up data space with information that will never be used. + ** As there may be shallow copies of this value, make it a soft-NULL */ + sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); + continue; + } + if( pColumn==0 ){ + if( IsHiddenColumn(&pTab->aCol[i]) ){ + j = -1; + nHidden++; + }else{ + j = i - nHidden; + } + }else{ + for(j=0; jnId; j++){ + if( pColumn->a[j].idx==i ) break; + } + } + if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ + sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + }else if( useTempTable ){ + sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); + }else if( pSelect ){ + if( regFromSelect!=regData ){ + sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore); + } + }else{ + sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore); + } + } + + /* Generate code to check constraints and generate index keys and + ** do the insertion. + */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); + sqlite3VtabMakeWritable(pParse, pTab); + sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); + sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); + sqlite3MayAbort(pParse); + }else +#endif + { + int isReplace; /* Set to true if constraints may cause a replace */ + int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ + sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0 + ); + sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); + + /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE + ** constraints or (b) there are no triggers and this table is not a + ** parent table in a foreign key constraint. It is safe to set the + ** flag in the second case as if any REPLACE constraint is hit, an + ** OP_Delete or OP_IdxDelete instruction will be executed on each + ** cursor that is disturbed. And these instructions both clear the + ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT + ** functionality. */ + bUseSeek = (isReplace==0 || (pTrigger==0 && + ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0) + )); + sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, + regIns, aRegIdx, 0, appendFlag, bUseSeek + ); + } + } + + /* Update the count of rows that are inserted + */ + if( (db->flags & SQLITE_CountRows)!=0 ){ + sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); + } + + if( pTrigger ){ + /* Code AFTER triggers */ + sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, + pTab, regData-2-pTab->nCol, onError, endOfLoop); + } + + /* The bottom of the main insertion loop, if the data source + ** is a SELECT statement. + */ + sqlite3VdbeResolveLabel(v, endOfLoop); + if( useTempTable ){ + sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrInsTop); + sqlite3VdbeAddOp1(v, OP_Close, srcTab); + }else if( pSelect ){ + sqlite3VdbeGoto(v, addrCont); + sqlite3VdbeJumpHere(v, addrInsTop); + } + +insert_end: + /* Update the sqlite_sequence table by storing the content of the + ** maximum rowid counter values recorded while inserting into + ** autoincrement tables. + */ + if( pParse->nested==0 && pParse->pTriggerTab==0 ){ + sqlite3AutoincrementEnd(pParse); + } + + /* + ** Return the number of rows inserted. If this routine is + ** generating code because of a call to sqlite3NestedParse(), do not + ** invoke the callback function. + */ + if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ + sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC); + } + +insert_cleanup: + sqlite3SrcListDelete(db, pTabList); + sqlite3ExprListDelete(db, pList); + sqlite3SelectDelete(db, pSelect); + sqlite3IdListDelete(db, pColumn); + sqlite3DbFree(db, aRegIdx); +} + +/* Make sure "isView" and other macros defined above are undefined. Otherwise +** they may interfere with compilation of other functions in this file +** (or in another file, if this file becomes part of the amalgamation). */ +#ifdef isView + #undef isView +#endif +#ifdef pTrigger + #undef pTrigger +#endif +#ifdef tmask + #undef tmask +#endif + +/* +** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged() +*/ +#define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */ +#define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */ + +/* This is the Walker callback from checkConstraintUnchanged(). Set +** bit 0x01 of pWalker->eCode if +** pWalker->eCode to 0 if this expression node references any of the +** columns that are being modifed by an UPDATE statement. +*/ +static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN ){ + assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 ); + if( pExpr->iColumn>=0 ){ + if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){ + pWalker->eCode |= CKCNSTRNT_COLUMN; + } + }else{ + pWalker->eCode |= CKCNSTRNT_ROWID; + } + } + return WRC_Continue; +} + +/* +** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The +** only columns that are modified by the UPDATE are those for which +** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true. +** +** Return true if CHECK constraint pExpr does not use any of the +** changing columns (or the rowid if it is changing). In other words, +** return true if this CHECK constraint can be skipped when validating +** the new row in the UPDATE statement. +*/ +static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ + Walker w; + memset(&w, 0, sizeof(w)); + w.eCode = 0; + w.xExprCallback = checkConstraintExprNode; + w.u.aiCol = aiChng; + sqlite3WalkExpr(&w, pExpr); + if( !chngRowid ){ + testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 ); + w.eCode &= ~CKCNSTRNT_ROWID; + } + testcase( w.eCode==0 ); + testcase( w.eCode==CKCNSTRNT_COLUMN ); + testcase( w.eCode==CKCNSTRNT_ROWID ); + testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); + return !w.eCode; +} + +/* +** Generate code to do constraint checks prior to an INSERT or an UPDATE +** on table pTab. +** +** The regNewData parameter is the first register in a range that contains +** the data to be inserted or the data after the update. There will be +** pTab->nCol+1 registers in this range. The first register (the one +** that regNewData points to) will contain the new rowid, or NULL in the +** case of a WITHOUT ROWID table. The second register in the range will +** contain the content of the first table column. The third register will +** contain the content of the second table column. And so forth. +** +** The regOldData parameter is similar to regNewData except that it contains +** the data prior to an UPDATE rather than afterwards. regOldData is zero +** for an INSERT. This routine can distinguish between UPDATE and INSERT by +** checking regOldData for zero. +** +** For an UPDATE, the pkChng boolean is true if the true primary key (the +** rowid for a normal table or the PRIMARY KEY for a WITHOUT ROWID table) +** might be modified by the UPDATE. If pkChng is false, then the key of +** the iDataCur content table is guaranteed to be unchanged by the UPDATE. +** +** For an INSERT, the pkChng boolean indicates whether or not the rowid +** was explicitly specified as part of the INSERT statement. If pkChng +** is zero, it means that the either rowid is computed automatically or +** that the table is a WITHOUT ROWID table and has no rowid. On an INSERT, +** pkChng will only be true if the INSERT statement provides an integer +** value for either the rowid column or its INTEGER PRIMARY KEY alias. +** +** The code generated by this routine will store new index entries into +** registers identified by aRegIdx[]. No index entry is created for +** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is +** the same as the order of indices on the linked list of indices +** at pTab->pIndex. +** +** The caller must have already opened writeable cursors on the main +** table and all applicable indices (that is to say, all indices for which +** aRegIdx[] is not zero). iDataCur is the cursor for the main table when +** inserting or updating a rowid table, or the cursor for the PRIMARY KEY +** index when operating on a WITHOUT ROWID table. iIdxCur is the cursor +** for the first index in the pTab->pIndex list. Cursors for other indices +** are at iIdxCur+N for the N-th element of the pTab->pIndex list. +** +** This routine also generates code to check constraints. NOT NULL, +** CHECK, and UNIQUE constraints are all checked. If a constraint fails, +** then the appropriate action is performed. There are five possible +** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. +** +** Constraint type Action What Happens +** --------------- ---------- ---------------------------------------- +** any ROLLBACK The current transaction is rolled back and +** sqlite3_step() returns immediately with a +** return code of SQLITE_CONSTRAINT. +** +** any ABORT Back out changes from the current command +** only (do not do a complete rollback) then +** cause sqlite3_step() to return immediately +** with SQLITE_CONSTRAINT. +** +** any FAIL Sqlite3_step() returns immediately with a +** return code of SQLITE_CONSTRAINT. The +** transaction is not rolled back and any +** changes to prior rows are retained. +** +** any IGNORE The attempt in insert or update the current +** row is skipped, without throwing an error. +** Processing continues with the next row. +** (There is an immediate jump to ignoreDest.) +** +** NOT NULL REPLACE The NULL value is replace by the default +** value for that column. If the default value +** is NULL, the action is the same as ABORT. +** +** UNIQUE REPLACE The other row that conflicts with the row +** being inserted is removed. +** +** CHECK REPLACE Illegal. The results in an exception. +** +** Which action to take is determined by the overrideError parameter. +** Or if overrideError==OE_Default, then the pParse->onError parameter +** is used. Or if pParse->onError==OE_Default then the onError value +** for the constraint is used. +*/ +SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( + Parse *pParse, /* The parser context */ + Table *pTab, /* The table being inserted or updated */ + int *aRegIdx, /* Use register aRegIdx[i] for index i. 0 for unused */ + int iDataCur, /* Canonical data cursor (main table or PK index) */ + int iIdxCur, /* First index cursor */ + int regNewData, /* First register in a range holding values to insert */ + int regOldData, /* Previous content. 0 for INSERTs */ + u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */ + u8 overrideError, /* Override onError to this if not OE_Default */ + int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ + int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ + int *aiChng /* column i is unchanged if aiChng[i]<0 */ +){ + Vdbe *v; /* VDBE under constrution */ + Index *pIdx; /* Pointer to one of the indices */ + Index *pPk = 0; /* The PRIMARY KEY index */ + sqlite3 *db; /* Database connection */ + int i; /* loop counter */ + int ix; /* Index loop counter */ + int nCol; /* Number of columns */ + int onError; /* Conflict resolution strategy */ + int addr1; /* Address of jump instruction */ + int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ + int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ + int ipkTop = 0; /* Top of the rowid change constraint check */ + int ipkBottom = 0; /* Bottom of the rowid change constraint check */ + u8 isUpdate; /* True if this is an UPDATE operation */ + u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ + + isUpdate = regOldData!=0; + db = pParse->db; + v = sqlite3GetVdbe(pParse); + assert( v!=0 ); + assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + nCol = pTab->nCol; + + /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for + ** normal rowid tables. nPkField is the number of key fields in the + ** pPk index or 1 for a rowid table. In other words, nPkField is the + ** number of fields in the true primary key of the table. */ + if( HasRowid(pTab) ){ + pPk = 0; + nPkField = 1; + }else{ + pPk = sqlite3PrimaryKeyIndex(pTab); + nPkField = pPk->nKeyCol; + } + + /* Record that this module has started */ + VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)", + iDataCur, iIdxCur, regNewData, regOldData, pkChng)); + + /* Test all NOT NULL constraints. + */ + for(i=0; iiPKey ){ + continue; /* ROWID is never NULL */ + } + if( aiChng && aiChng[i]<0 ){ + /* Don't bother checking for NOT NULL on columns that do not change */ + continue; + } + onError = pTab->aCol[i].notNull; + if( onError==OE_None ) continue; /* This column is allowed to be NULL */ + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( onError==OE_Default ){ + onError = OE_Abort; + } + if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ + onError = OE_Abort; + } + assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail + || onError==OE_Ignore || onError==OE_Replace ); + switch( onError ){ + case OE_Abort: + sqlite3MayAbort(pParse); + /* Fall through */ + case OE_Rollback: + case OE_Fail: { + char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, + pTab->aCol[i].zName); + sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, + regNewData+1+i); + sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); + sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); + VdbeCoverage(v); + break; + } + case OE_Ignore: { + sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); + VdbeCoverage(v); + break; + } + default: { + assert( onError==OE_Replace ); + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); + VdbeCoverage(v); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); + sqlite3VdbeJumpHere(v, addr1); + break; + } + } + } + + /* Test all CHECK constraints + */ +#ifndef SQLITE_OMIT_CHECK + if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ + ExprList *pCheck = pTab->pCheck; + pParse->ckBase = regNewData+1; + onError = overrideError!=OE_Default ? overrideError : OE_Abort; + for(i=0; inExpr; i++){ + int allOk; + Expr *pExpr = pCheck->a[i].pExpr; + if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue; + allOk = sqlite3VdbeMakeLabel(v); + sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); + if( onError==OE_Ignore ){ + sqlite3VdbeGoto(v, ignoreDest); + }else{ + char *zName = pCheck->a[i].zName; + if( zName==0 ) zName = pTab->zName; + if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ + sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, + onError, zName, P4_TRANSIENT, + P5_ConstraintCheck); + } + sqlite3VdbeResolveLabel(v, allOk); + } + } +#endif /* !defined(SQLITE_OMIT_CHECK) */ + + /* If rowid is changing, make sure the new rowid does not previously + ** exist in the table. + */ + if( pkChng && pPk==0 ){ + int addrRowidOk = sqlite3VdbeMakeLabel(v); + + /* Figure out what action to take in case of a rowid collision */ + onError = pTab->keyConf; + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( onError==OE_Default ){ + onError = OE_Abort; + } + + if( isUpdate ){ + /* pkChng!=0 does not mean that the rowid has changed, only that + ** it might have changed. Skip the conflict logic below if the rowid + ** is unchanged. */ + sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + VdbeCoverage(v); + } + + /* If the response to a rowid conflict is REPLACE but the response + ** to some other UNIQUE constraint is FAIL or IGNORE, then we need + ** to defer the running of the rowid conflict checking until after + ** the UNIQUE constraints have run. + */ + if( onError==OE_Replace && overrideError!=OE_Replace ){ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->onError==OE_Ignore || pIdx->onError==OE_Fail ){ + ipkTop = sqlite3VdbeAddOp0(v, OP_Goto); + break; + } + } + } + + /* Check to see if the new rowid already exists in the table. Skip + ** the following conflict logic if it does not. */ + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); + VdbeCoverage(v); + + /* Generate code that deals with a rowid collision */ + switch( onError ){ + default: { + onError = OE_Abort; + /* Fall thru into the next case */ + } + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqlite3RowidConstraint(pParse, onError, pTab); + break; + } + case OE_Replace: { + /* If there are DELETE triggers on this table and the + ** recursive-triggers flag is set, call GenerateRowDelete() to + ** remove the conflicting row from the table. This will fire + ** the triggers and remove both the table and index b-tree entries. + ** + ** Otherwise, if there are no triggers or the recursive-triggers + ** flag is not set, but the table has one or more indexes, call + ** GenerateRowIndexDelete(). This removes the index b-tree entries + ** only. The table b-tree entry will be replaced by the new entry + ** when it is inserted. + ** + ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called, + ** also invoke MultiWrite() to indicate that this VDBE may require + ** statement rollback (if the statement is aborted after the delete + ** takes place). Earlier versions called sqlite3MultiWrite() regardless, + ** but being more selective here allows statements like: + ** + ** REPLACE INTO t(rowid) VALUES($newrowid) + ** + ** to run without a statement journal if there are no indexes on the + ** table. + */ + Trigger *pTrigger = 0; + if( db->flags&SQLITE_RecTriggers ){ + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); + } + if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ + sqlite3MultiWrite(pParse); + sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, + regNewData, 1, 0, OE_Replace, 1, -1); + }else{ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( HasRowid(pTab) ){ + /* This OP_Delete opcode fires the pre-update-hook only. It does + ** not modify the b-tree. It is more efficient to let the coming + ** OP_Insert replace the existing entry than it is to delete the + ** existing entry and then insert a new one. */ + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + } +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + if( pTab->pIndex ){ + sqlite3MultiWrite(pParse); + sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1); + } + } + seenReplace = 1; + break; + } + case OE_Ignore: { + /*assert( seenReplace==0 );*/ + sqlite3VdbeGoto(v, ignoreDest); + break; + } + } + sqlite3VdbeResolveLabel(v, addrRowidOk); + if( ipkTop ){ + ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); + sqlite3VdbeJumpHere(v, ipkTop); + } + } + + /* Test all UNIQUE constraints by creating entries for each UNIQUE + ** index and making sure that duplicate entries do not already exist. + ** Compute the revised record entries for indices as we go. + ** + ** This loop also handles the case of the PRIMARY KEY index for a + ** WITHOUT ROWID table. + */ + for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){ + int regIdx; /* Range of registers hold conent for pIdx */ + int regR; /* Range of registers holding conflicting PK */ + int iThisCur; /* Cursor for this UNIQUE index */ + int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ + + if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ + if( bAffinityDone==0 ){ + sqlite3TableAffinity(v, pTab, regNewData+1); + bAffinityDone = 1; + } + iThisCur = iIdxCur+ix; + addrUniqueOk = sqlite3VdbeMakeLabel(v); + + /* Skip partial indices for which the WHERE clause is not true */ + if( pIdx->pPartIdxWhere ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); + pParse->ckBase = regNewData+1; + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk, + SQLITE_JUMPIFNULL); + pParse->ckBase = 0; + } + + /* Create a record for this index entry as it should appear after + ** the insert or update. Store that record in the aRegIdx[ix] register + */ + regIdx = aRegIdx[ix]+1; + for(i=0; inColumn; i++){ + int iField = pIdx->aiColumn[i]; + int x; + if( iField==XN_EXPR ){ + pParse->ckBase = regNewData+1; + sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); + pParse->ckBase = 0; + VdbeComment((v, "%s column %d", pIdx->zName, i)); + }else{ + if( iField==XN_ROWID || iField==pTab->iPKey ){ + x = regNewData; + }else{ + x = iField + regNewData + 1; + } + sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i); + VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); + } + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); + VdbeComment((v, "for %s", pIdx->zName)); +#ifdef SQLITE_ENABLE_NULL_TRIM + if( pIdx->idxType==2 ) sqlite3SetMakeRecordP5(v, pIdx->pTable); +#endif + + /* In an UPDATE operation, if this index is the PRIMARY KEY index + ** of a WITHOUT ROWID table and there has been no change the + ** primary key, then no collision is possible. The collision detection + ** logic below can all be skipped. */ + if( isUpdate && pPk==pIdx && pkChng==0 ){ + sqlite3VdbeResolveLabel(v, addrUniqueOk); + continue; + } + + /* Find out what action to take in case there is a uniqueness conflict */ + onError = pIdx->onError; + if( onError==OE_None ){ + sqlite3VdbeResolveLabel(v, addrUniqueOk); + continue; /* pIdx is not a UNIQUE index */ + } + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( onError==OE_Default ){ + onError = OE_Abort; + } + + /* Collision detection may be omitted if all of the following are true: + ** (1) The conflict resolution algorithm is REPLACE + ** (2) The table is a WITHOUT ROWID table + ** (3) There are no secondary indexes on the table + ** (4) No delete triggers need to be fired if there is a conflict + ** (5) No FK constraint counters need to be updated if a conflict occurs. + */ + if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ + && pPk==pIdx /* Condition 2 */ + && onError==OE_Replace /* Condition 1 */ + && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ + 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) + && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ + (0==pTab->pFKey && 0==sqlite3FkReferences(pTab))) + ){ + sqlite3VdbeResolveLabel(v, addrUniqueOk); + continue; + } + + /* Check to see if the new index entry will be unique */ + sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, + regIdx, pIdx->nKeyCol); VdbeCoverage(v); + + /* Generate code to handle collisions */ + regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField); + if( isUpdate || onError==OE_Replace ){ + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); + /* Conflict only if the rowid of the existing index entry + ** is different from old-rowid */ + if( isUpdate ){ + sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + VdbeCoverage(v); + } + }else{ + int x; + /* Extract the PRIMARY KEY from the end of the index entry and + ** store it in registers regR..regR+nPk-1 */ + if( pIdx!=pPk ){ + for(i=0; inKeyCol; i++){ + assert( pPk->aiColumn[i]>=0 ); + x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); + sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); + VdbeComment((v, "%s.%s", pTab->zName, + pTab->aCol[pPk->aiColumn[i]].zName)); + } + } + if( isUpdate ){ + /* If currently processing the PRIMARY KEY of a WITHOUT ROWID + ** table, only conflict if the new PRIMARY KEY values are actually + ** different from the old. + ** + ** For a UNIQUE index, only conflict if the PRIMARY KEY values + ** of the matched index row are different from the original PRIMARY + ** KEY values of this row before the update. */ + int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; + int op = OP_Ne; + int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); + + for(i=0; inKeyCol; i++){ + char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); + x = pPk->aiColumn[i]; + assert( x>=0 ); + if( i==(pPk->nKeyCol-1) ){ + addrJump = addrUniqueOk; + op = OP_Eq; + } + sqlite3VdbeAddOp4(v, op, + regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ + ); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + VdbeCoverageIf(v, op==OP_Eq); + VdbeCoverageIf(v, op==OP_Ne); + } + } + } + } + + /* Generate code that executes if the new index entry is not unique */ + assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail + || onError==OE_Ignore || onError==OE_Replace ); + switch( onError ){ + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqlite3UniqueConstraint(pParse, onError, pIdx); + break; + } + case OE_Ignore: { + sqlite3VdbeGoto(v, ignoreDest); + break; + } + default: { + Trigger *pTrigger = 0; + assert( onError==OE_Replace ); + sqlite3MultiWrite(pParse); + if( db->flags&SQLITE_RecTriggers ){ + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); + } + sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, + regR, nPkField, 0, OE_Replace, + (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); + seenReplace = 1; + break; + } + } + sqlite3VdbeResolveLabel(v, addrUniqueOk); + if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); + } + if( ipkTop ){ + sqlite3VdbeGoto(v, ipkTop+1); + sqlite3VdbeJumpHere(v, ipkBottom); + } + + *pbMayReplace = seenReplace; + VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); +} + +#ifdef SQLITE_ENABLE_NULL_TRIM +/* +** Change the P5 operand on the last opcode (which should be an OP_MakeRecord) +** to be the number of columns in table pTab that must not be NULL-trimmed. +** +** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero. +*/ +SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){ + u16 i; + + /* Records with omitted columns are only allowed for schema format + ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */ + if( pTab->pSchema->file_format<2 ) return; + + for(i=pTab->nCol-1; i>0; i--){ + if( pTab->aCol[i].pDflt!=0 ) break; + if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; + } + sqlite3VdbeChangeP5(v, i+1); +} +#endif + +/* +** This routine generates code to finish the INSERT or UPDATE operation +** that was started by a prior call to sqlite3GenerateConstraintChecks. +** A consecutive range of registers starting at regNewData contains the +** rowid and the content to be inserted. +** +** The arguments to this routine should be the same as the first six +** arguments to sqlite3GenerateConstraintChecks. +*/ +SQLITE_PRIVATE void sqlite3CompleteInsertion( + Parse *pParse, /* The parser context */ + Table *pTab, /* the table into which we are inserting */ + int iDataCur, /* Cursor of the canonical data source */ + int iIdxCur, /* First index cursor */ + int regNewData, /* Range of content */ + int *aRegIdx, /* Register used by each index. 0 for unused indices */ + int update_flags, /* True for UPDATE, False for INSERT */ + int appendBias, /* True if this is likely to be an append */ + int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ +){ + Vdbe *v; /* Prepared statements under construction */ + Index *pIdx; /* An index being inserted or updated */ + u8 pik_flags; /* flag values passed to the btree insert */ + int regData; /* Content registers (after the rowid) */ + int regRec; /* Register holding assembled record for the table */ + int i; /* Loop counter */ + u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ + + assert( update_flags==0 + || update_flags==OPFLAG_ISUPDATE + || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION) + ); + + v = sqlite3GetVdbe(pParse); + assert( v!=0 ); + assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ + if( aRegIdx[i]==0 ) continue; + bAffinityDone = 1; + if( pIdx->pPartIdxWhere ){ + sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + } + pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0); + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ + assert( pParse->nested==0 ); + pik_flags |= OPFLAG_NCHANGE; + pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( update_flags==0 ){ + sqlite3VdbeAddOp4(v, OP_InsertInt, + iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE + ); + sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); + } +#endif + } + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i], + aRegIdx[i]+1, + pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn); + sqlite3VdbeChangeP5(v, pik_flags); + } + if( !HasRowid(pTab) ) return; + regData = regNewData + 1; + regRec = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); + sqlite3SetMakeRecordP5(v, pTab); + if( !bAffinityDone ){ + sqlite3TableAffinity(v, pTab, 0); + sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); + } + if( pParse->nested ){ + pik_flags = 0; + }else{ + pik_flags = OPFLAG_NCHANGE; + pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID); + } + if( appendBias ){ + pik_flags |= OPFLAG_APPEND; + } + if( useSeekResult ){ + pik_flags |= OPFLAG_USESEEKRESULT; + } + sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData); + if( !pParse->nested ){ + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + } + sqlite3VdbeChangeP5(v, pik_flags); +} + +/* +** Allocate cursors for the pTab table and all its indices and generate +** code to open and initialized those cursors. +** +** The cursor for the object that contains the complete data (normally +** the table itself, but the PRIMARY KEY index in the case of a WITHOUT +** ROWID table) is returned in *piDataCur. The first index cursor is +** returned in *piIdxCur. The number of indices is returned. +** +** Use iBase as the first cursor (either the *piDataCur for rowid tables +** or the first index for WITHOUT ROWID tables) if it is non-negative. +** If iBase is negative, then allocate the next available cursor. +** +** For a rowid table, *piDataCur will be exactly one less than *piIdxCur. +** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range +** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the +** pTab->pIndex list. +** +** If pTab is a virtual table, then this routine is a no-op and the +** *piDataCur and *piIdxCur values are left uninitialized. +*/ +SQLITE_PRIVATE int sqlite3OpenTableAndIndices( + Parse *pParse, /* Parsing context */ + Table *pTab, /* Table to be opened */ + int op, /* OP_OpenRead or OP_OpenWrite */ + u8 p5, /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */ + int iBase, /* Use this for the table cursor, if there is one */ + u8 *aToOpen, /* If not NULL: boolean for each table and index */ + int *piDataCur, /* Write the database source cursor number here */ + int *piIdxCur /* Write the first index cursor number here */ +){ + int i; + int iDb; + int iDataCur; + Index *pIdx; + Vdbe *v; + + assert( op==OP_OpenRead || op==OP_OpenWrite ); + assert( op==OP_OpenWrite || p5==0 ); + if( IsVirtual(pTab) ){ + /* This routine is a no-op for virtual tables. Leave the output + ** variables *piDataCur and *piIdxCur uninitialized so that valgrind + ** can detect if they are used by mistake in the caller. */ + return 0; + } + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + v = sqlite3GetVdbe(pParse); + assert( v!=0 ); + if( iBase<0 ) iBase = pParse->nTab; + iDataCur = iBase++; + if( piDataCur ) *piDataCur = iDataCur; + if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){ + sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op); + }else{ + sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName); + } + if( piIdxCur ) *piIdxCur = iBase; + for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ + int iIdxCur = iBase++; + assert( pIdx->pSchema==pTab->pSchema ); + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ + if( piDataCur ) *piDataCur = iIdxCur; + p5 = 0; + } + if( aToOpen==0 || aToOpen[i+1] ){ + sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + sqlite3VdbeChangeP5(v, p5); + VdbeComment((v, "%s", pIdx->zName)); + } + } + if( iBase>pParse->nTab ) pParse->nTab = iBase; + return i; +} + + +#ifdef SQLITE_TEST +/* +** The following global variable is incremented whenever the +** transfer optimization is used. This is used for testing +** purposes only - to make sure the transfer optimization really +** is happening when it is supposed to. +*/ +SQLITE_API int sqlite3_xferopt_count; +#endif /* SQLITE_TEST */ + + +#ifndef SQLITE_OMIT_XFER_OPT +/* +** Check to see if index pSrc is compatible as a source of data +** for index pDest in an insert transfer optimization. The rules +** for a compatible index: +** +** * The index is over the same set of columns +** * The same DESC and ASC markings occurs on all columns +** * The same onError processing (OE_Abort, OE_Ignore, etc) +** * The same collating sequence on each column +** * The index has the exact same WHERE clause +*/ +static int xferCompatibleIndex(Index *pDest, Index *pSrc){ + int i; + assert( pDest && pSrc ); + assert( pDest->pTable!=pSrc->pTable ); + if( pDest->nKeyCol!=pSrc->nKeyCol ){ + return 0; /* Different number of columns */ + } + if( pDest->onError!=pSrc->onError ){ + return 0; /* Different conflict resolution strategies */ + } + for(i=0; inKeyCol; i++){ + if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ + return 0; /* Different columns indexed */ + } + if( pSrc->aiColumn[i]==XN_EXPR ){ + assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); + if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, + pDest->aColExpr->a[i].pExpr, -1)!=0 ){ + return 0; /* Different expressions in the index */ + } + } + if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){ + return 0; /* Different sort orders */ + } + if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){ + return 0; /* Different collating sequences */ + } + } + if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ + return 0; /* Different WHERE clauses */ + } + + /* If no test above fails then the indices must be compatible */ + return 1; +} + +/* +** Attempt the transfer optimization on INSERTs of the form +** +** INSERT INTO tab1 SELECT * FROM tab2; +** +** The xfer optimization transfers raw records from tab2 over to tab1. +** Columns are not decoded and reassembled, which greatly improves +** performance. Raw index records are transferred in the same way. +** +** The xfer optimization is only attempted if tab1 and tab2 are compatible. +** There are lots of rules for determining compatibility - see comments +** embedded in the code for details. +** +** This routine returns TRUE if the optimization is guaranteed to be used. +** Sometimes the xfer optimization will only work if the destination table +** is empty - a factor that can only be determined at run-time. In that +** case, this routine generates code for the xfer optimization but also +** does a test to see if the destination table is empty and jumps over the +** xfer optimization code if the test fails. In that case, this routine +** returns FALSE so that the caller will know to go ahead and generate +** an unoptimized transfer. This routine also returns FALSE if there +** is no chance that the xfer optimization can be applied. +** +** This optimization is particularly useful at making VACUUM run faster. +*/ +static int xferOptimization( + Parse *pParse, /* Parser context */ + Table *pDest, /* The table we are inserting into */ + Select *pSelect, /* A SELECT statement to use as the data source */ + int onError, /* How to handle constraint errors */ + int iDbDest /* The database of pDest */ +){ + sqlite3 *db = pParse->db; + ExprList *pEList; /* The result set of the SELECT */ + Table *pSrc; /* The table in the FROM clause of SELECT */ + Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ + struct SrcList_item *pItem; /* An element of pSelect->pSrc */ + int i; /* Loop counter */ + int iDbSrc; /* The database of pSrc */ + int iSrc, iDest; /* Cursors from source and destination */ + int addr1, addr2; /* Loop addresses */ + int emptyDestTest = 0; /* Address of test for empty pDest */ + int emptySrcTest = 0; /* Address of test for empty pSrc */ + Vdbe *v; /* The VDBE we are building */ + int regAutoinc; /* Memory register used by AUTOINC */ + int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */ + int regData, regRowid; /* Registers holding data and rowid */ + + if( pSelect==0 ){ + return 0; /* Must be of the form INSERT INTO ... SELECT ... */ + } + if( pParse->pWith || pSelect->pWith ){ + /* Do not attempt to process this query if there are an WITH clauses + ** attached to it. Proceeding may generate a false "no such table: xxx" + ** error if pSelect reads from a CTE named "xxx". */ + return 0; + } + if( sqlite3TriggerList(pParse, pDest) ){ + return 0; /* tab1 must not have triggers */ + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pDest) ){ + return 0; /* tab1 must not be a virtual table */ + } +#endif + if( onError==OE_Default ){ + if( pDest->iPKey>=0 ) onError = pDest->keyConf; + if( onError==OE_Default ) onError = OE_Abort; + } + assert(pSelect->pSrc); /* allocated even if there is no FROM clause */ + if( pSelect->pSrc->nSrc!=1 ){ + return 0; /* FROM clause must have exactly one term */ + } + if( pSelect->pSrc->a[0].pSelect ){ + return 0; /* FROM clause cannot contain a subquery */ + } + if( pSelect->pWhere ){ + return 0; /* SELECT may not have a WHERE clause */ + } + if( pSelect->pOrderBy ){ + return 0; /* SELECT may not have an ORDER BY clause */ + } + /* Do not need to test for a HAVING clause. If HAVING is present but + ** there is no ORDER BY, we will get an error. */ + if( pSelect->pGroupBy ){ + return 0; /* SELECT may not have a GROUP BY clause */ + } + if( pSelect->pLimit ){ + return 0; /* SELECT may not have a LIMIT clause */ + } + assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */ + if( pSelect->pPrior ){ + return 0; /* SELECT may not be a compound query */ + } + if( pSelect->selFlags & SF_Distinct ){ + return 0; /* SELECT may not be DISTINCT */ + } + pEList = pSelect->pEList; + assert( pEList!=0 ); + if( pEList->nExpr!=1 ){ + return 0; /* The result set must have exactly one column */ + } + assert( pEList->a[0].pExpr ); + if( pEList->a[0].pExpr->op!=TK_ASTERISK ){ + return 0; /* The result set must be the special operator "*" */ + } + + /* At this point we have established that the statement is of the + ** correct syntactic form to participate in this optimization. Now + ** we have to check the semantics. + */ + pItem = pSelect->pSrc->a; + pSrc = sqlite3LocateTableItem(pParse, 0, pItem); + if( pSrc==0 ){ + return 0; /* FROM clause does not contain a real table */ + } + if( pSrc==pDest ){ + return 0; /* tab1 and tab2 may not be the same table */ + } + if( HasRowid(pDest)!=HasRowid(pSrc) ){ + return 0; /* source and destination must both be WITHOUT ROWID or not */ + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pSrc) ){ + return 0; /* tab2 must not be a virtual table */ + } +#endif + if( pSrc->pSelect ){ + return 0; /* tab2 may not be a view */ + } + if( pDest->nCol!=pSrc->nCol ){ + return 0; /* Number of columns must be the same in tab1 and tab2 */ + } + if( pDest->iPKey!=pSrc->iPKey ){ + return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ + } + for(i=0; inCol; i++){ + Column *pDestCol = &pDest->aCol[i]; + Column *pSrcCol = &pSrc->aCol[i]; +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS + if( (db->flags & SQLITE_Vacuum)==0 + && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN + ){ + return 0; /* Neither table may have __hidden__ columns */ + } +#endif + if( pDestCol->affinity!=pSrcCol->affinity ){ + return 0; /* Affinity must be the same on all columns */ + } + if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){ + return 0; /* Collating sequence must be the same on all columns */ + } + if( pDestCol->notNull && !pSrcCol->notNull ){ + return 0; /* tab2 must be NOT NULL if tab1 is */ + } + /* Default values for second and subsequent columns need to match. */ + if( i>0 ){ + assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN ); + assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN ); + if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) + || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken, + pSrcCol->pDflt->u.zToken)!=0) + ){ + return 0; /* Default values must be the same for all columns */ + } + } + } + for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ + if( IsUniqueIndex(pDestIdx) ){ + destHasUniqueIdx = 1; + } + for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ + if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; + } + if( pSrcIdx==0 ){ + return 0; /* pDestIdx has no corresponding index in pSrc */ + } + } +#ifndef SQLITE_OMIT_CHECK + if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ + return 0; /* Tables have different CHECK constraints. Ticket #2252 */ + } +#endif +#ifndef SQLITE_OMIT_FOREIGN_KEY + /* Disallow the transfer optimization if the destination table constains + ** any foreign key constraints. This is more restrictive than necessary. + ** But the main beneficiary of the transfer optimization is the VACUUM + ** command, and the VACUUM command disables foreign key constraints. So + ** the extra complication to make this rule less restrictive is probably + ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] + */ + if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ + return 0; + } +#endif + if( (db->flags & SQLITE_CountRows)!=0 ){ + return 0; /* xfer opt does not play well with PRAGMA count_changes */ + } + + /* If we get this far, it means that the xfer optimization is at + ** least a possibility, though it might only work if the destination + ** table (tab1) is initially empty. + */ +#ifdef SQLITE_TEST + sqlite3_xferopt_count++; +#endif + iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema); + v = sqlite3GetVdbe(pParse); + sqlite3CodeVerifySchema(pParse, iDbSrc); + iSrc = pParse->nTab++; + iDest = pParse->nTab++; + regAutoinc = autoIncBegin(pParse, iDbDest, pDest); + regData = sqlite3GetTempReg(pParse); + regRowid = sqlite3GetTempReg(pParse); + sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); + assert( HasRowid(pDest) || destHasUniqueIdx ); + if( (db->flags & SQLITE_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 + ** table is always empty. + ** + ** Conditions under which the destination must be empty: + ** + ** (1) There is no INTEGER PRIMARY KEY but there are indices. + ** (If the destination is not initially empty, the rowid fields + ** of index entries might need to change.) + ** + ** (2) The destination has a unique index. (The xfer optimization + ** is unable to test uniqueness.) + ** + ** (3) onError is something other than OE_Abort and OE_Rollback. + */ + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v); + emptyDestTest = sqlite3VdbeAddOp0(v, OP_Goto); + sqlite3VdbeJumpHere(v, addr1); + } + if( HasRowid(pSrc) ){ + u8 insFlags; + sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); + emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); + if( pDest->iPKey>=0 ){ + addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); + addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); + VdbeCoverage(v); + sqlite3RowidConstraint(pParse, onError, pDest); + sqlite3VdbeJumpHere(v, addr2); + autoIncStep(pParse, regAutoinc, regRowid); + }else if( pDest->pIndex==0 ){ + addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); + }else{ + addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); + 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); + insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID| + OPFLAG_APPEND|OPFLAG_USESEEKRESULT; + }else{ + insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND; + } + sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, + (char*)pDest, P4_TABLE); + sqlite3VdbeChangeP5(v, insFlags); + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); + sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); + }else{ + sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName); + sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName); + } + for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ + u8 idxInsFlags = 0; + for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){ + if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; + } + assert( pSrcIdx ); + sqlite3VdbeAddOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum, iDbSrc); + sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx); + VdbeComment((v, "%s", pSrcIdx->zName)); + sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest); + sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); + sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); + VdbeComment((v, "%s", pDestIdx->zName)); + addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); + if( db->flags & SQLITE_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 + ** OP_IdxInsert to seek to the point within the b-tree where each key + ** should be inserted. This is faster. + ** + ** If any of the indexed columns use a collation sequence other than + ** BINARY, this optimization is disabled. This is because the user + ** might change the definition of a collation sequence and then run + ** a VACUUM command. In that case keys may not be written in strictly + ** sorted order. */ + for(i=0; inColumn; i++){ + const char *zColl = pSrcIdx->azColl[i]; + if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break; + } + if( i==pSrcIdx->nColumn ){ + idxInsFlags = OPFLAG_USESEEKRESULT; + sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); + } + } + if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){ + idxInsFlags |= OPFLAG_NCHANGE; + } + sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); + sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND); + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); + sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); + } + if( emptySrcTest ) sqlite3VdbeJumpHere(v, emptySrcTest); + sqlite3ReleaseTempReg(pParse, regRowid); + sqlite3ReleaseTempReg(pParse, regData); + if( emptyDestTest ){ + sqlite3AutoincrementEnd(pParse); + sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0); + sqlite3VdbeJumpHere(v, emptyDestTest); + sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); + return 0; + }else{ + return 1; + } +} +#endif /* SQLITE_OMIT_XFER_OPT */ + +/************** End of insert.c **********************************************/ +/************** Begin file legacy.c ******************************************/ +/* +** 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. +** +************************************************************************* +** Main file for the SQLite library. The routines in this file +** implement the programmer interface to the library. Routines in +** other files are for internal use by SQLite and should not be +** accessed by users of the library. +*/ + +/* #include "sqliteInt.h" */ + +/* +** Execute SQL code. Return one of the SQLITE_ success/failure +** codes. Also write an error message into memory obtained from +** malloc() and make *pzErrMsg point to that message. +** +** If the SQL is a query, then for each row in the query result +** the xCallback() function is called. pArg becomes the first +** argument to xCallback(). If xCallback=NULL then no callback +** is invoked, even for queries. +*/ +SQLITE_API int sqlite3_exec( + sqlite3 *db, /* The database on which the SQL executes */ + const char *zSql, /* The SQL to be executed */ + sqlite3_callback xCallback, /* Invoke this callback routine */ + void *pArg, /* First argument to xCallback() */ + char **pzErrMsg /* Write error messages here */ +){ + int rc = SQLITE_OK; /* Return code */ + const char *zLeftover; /* Tail of unprocessed SQL */ + sqlite3_stmt *pStmt = 0; /* The current SQL statement */ + char **azCols = 0; /* Names of result columns */ + int callbackIsInit; /* True if callback data is initialized */ + + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; + if( zSql==0 ) zSql = ""; + + sqlite3_mutex_enter(db->mutex); + sqlite3Error(db, SQLITE_OK); + while( rc==SQLITE_OK && zSql[0] ){ + int nCol; + char **azVals = 0; + + pStmt = 0; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); + assert( rc==SQLITE_OK || pStmt==0 ); + if( rc!=SQLITE_OK ){ + continue; + } + if( !pStmt ){ + /* this happens for a comment or white-space */ + zSql = zLeftover; + continue; + } + + callbackIsInit = 0; + nCol = sqlite3_column_count(pStmt); + + while( 1 ){ + int i; + rc = sqlite3_step(pStmt); + + /* Invoke the callback function if required */ + if( xCallback && (SQLITE_ROW==rc || + (SQLITE_DONE==rc && !callbackIsInit + && db->flags&SQLITE_NullCallback)) ){ + if( !callbackIsInit ){ + azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*)); + if( azCols==0 ){ + goto exec_out; + } + for(i=0; ierrMask)==rc ); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/************** End of legacy.c **********************************************/ +/************** Begin file loadext.c *****************************************/ +/* +** 2006 June 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 contains code used to dynamically load extensions into +** the SQLite library. +*/ + +#ifndef SQLITE_CORE + #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ +#endif +/************** Include sqlite3ext.h in the middle of loadext.c **************/ +/************** Begin file sqlite3ext.h **************************************/ +/* +** 2006 June 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 header file defines the SQLite interface for use by +** shared libraries that want to be imported as extensions into +** an SQLite instance. Shared libraries that intend to be loaded +** as extensions by SQLite should #include this file instead of +** sqlite3.h. +*/ +#ifndef SQLITE3EXT_H +#define SQLITE3EXT_H +/* #include "sqlite3.h" */ + +/* +** The following structure holds pointers to all of the SQLite API +** routines. +** +** WARNING: In order to maintain backwards compatibility, add new +** interfaces to the end of this structure only. If you insert new +** interfaces in the middle of this structure, then older different +** versions of SQLite will not be able to load each other's shared +** libraries! +*/ +struct sqlite3_api_routines { + void * (*aggregate_context)(sqlite3_context*,int nBytes); + int (*aggregate_count)(sqlite3_context*); + int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); + int (*bind_double)(sqlite3_stmt*,int,double); + int (*bind_int)(sqlite3_stmt*,int,int); + int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); + int (*bind_null)(sqlite3_stmt*,int); + int (*bind_parameter_count)(sqlite3_stmt*); + int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); + const char * (*bind_parameter_name)(sqlite3_stmt*,int); + int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); + int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); + int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); + int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); + int (*busy_timeout)(sqlite3*,int ms); + int (*changes)(sqlite3*); + int (*close)(sqlite3*); + int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const char*)); + int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const void*)); + const void * (*column_blob)(sqlite3_stmt*,int iCol); + int (*column_bytes)(sqlite3_stmt*,int iCol); + int (*column_bytes16)(sqlite3_stmt*,int iCol); + int (*column_count)(sqlite3_stmt*pStmt); + const char * (*column_database_name)(sqlite3_stmt*,int); + const void * (*column_database_name16)(sqlite3_stmt*,int); + const char * (*column_decltype)(sqlite3_stmt*,int i); + const void * (*column_decltype16)(sqlite3_stmt*,int); + double (*column_double)(sqlite3_stmt*,int iCol); + int (*column_int)(sqlite3_stmt*,int iCol); + sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); + const char * (*column_name)(sqlite3_stmt*,int); + const void * (*column_name16)(sqlite3_stmt*,int); + const char * (*column_origin_name)(sqlite3_stmt*,int); + const void * (*column_origin_name16)(sqlite3_stmt*,int); + const char * (*column_table_name)(sqlite3_stmt*,int); + const void * (*column_table_name16)(sqlite3_stmt*,int); + const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); + const void * (*column_text16)(sqlite3_stmt*,int iCol); + int (*column_type)(sqlite3_stmt*,int iCol); + sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); + void * (*commit_hook)(sqlite3*,int(*)(void*),void*); + int (*complete)(const char*sql); + int (*complete16)(const void*sql); + int (*create_collation)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_collation16)(sqlite3*,const void*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_function)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_function16)(sqlite3*,const void*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); + int (*data_count)(sqlite3_stmt*pStmt); + sqlite3 * (*db_handle)(sqlite3_stmt*); + int (*declare_vtab)(sqlite3*,const char*); + int (*enable_shared_cache)(int); + int (*errcode)(sqlite3*db); + const char * (*errmsg)(sqlite3*); + const void * (*errmsg16)(sqlite3*); + int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); + int (*expired)(sqlite3_stmt*); + int (*finalize)(sqlite3_stmt*pStmt); + void (*free)(void*); + void (*free_table)(char**result); + int (*get_autocommit)(sqlite3*); + void * (*get_auxdata)(sqlite3_context*,int); + int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); + int (*global_recover)(void); + void (*interruptx)(sqlite3*); + sqlite_int64 (*last_insert_rowid)(sqlite3*); + const char * (*libversion)(void); + int (*libversion_number)(void); + void *(*malloc)(int); + char * (*mprintf)(const char*,...); + int (*open)(const char*,sqlite3**); + int (*open16)(const void*,sqlite3**); + int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); + void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); + void *(*realloc)(void*,int); + int (*reset)(sqlite3_stmt*pStmt); + void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_double)(sqlite3_context*,double); + void (*result_error)(sqlite3_context*,const char*,int); + void (*result_error16)(sqlite3_context*,const void*,int); + void (*result_int)(sqlite3_context*,int); + void (*result_int64)(sqlite3_context*,sqlite_int64); + void (*result_null)(sqlite3_context*); + void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); + void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_value)(sqlite3_context*,sqlite3_value*); + void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + 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*,...); + int (*step)(sqlite3_stmt*); + int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, + char const**,char const**,int*,int*,int*); + void (*thread_cleanup)(void); + int (*total_changes)(sqlite3*); + void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); + int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); + void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, + sqlite_int64),void*); + void * (*user_data)(sqlite3_context*); + const void * (*value_blob)(sqlite3_value*); + int (*value_bytes)(sqlite3_value*); + int (*value_bytes16)(sqlite3_value*); + double (*value_double)(sqlite3_value*); + int (*value_int)(sqlite3_value*); + sqlite_int64 (*value_int64)(sqlite3_value*); + int (*value_numeric_type)(sqlite3_value*); + const unsigned char * (*value_text)(sqlite3_value*); + const void * (*value_text16)(sqlite3_value*); + const void * (*value_text16be)(sqlite3_value*); + const void * (*value_text16le)(sqlite3_value*); + int (*value_type)(sqlite3_value*); + char *(*vmprintf)(const char*,va_list); + /* Added ??? */ + int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); + /* Added by 3.3.13 */ + int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + int (*clear_bindings)(sqlite3_stmt*); + /* Added by 3.4.1 */ + int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, + void (*xDestroy)(void *)); + /* Added by 3.5.0 */ + int (*bind_zeroblob)(sqlite3_stmt*,int,int); + int (*blob_bytes)(sqlite3_blob*); + int (*blob_close)(sqlite3_blob*); + int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, + int,sqlite3_blob**); + int (*blob_read)(sqlite3_blob*,void*,int,int); + int (*blob_write)(sqlite3_blob*,const void*,int,int); + int (*create_collation_v2)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*), + void(*)(void*)); + int (*file_control)(sqlite3*,const char*,int,void*); + sqlite3_int64 (*memory_highwater)(int); + sqlite3_int64 (*memory_used)(void); + sqlite3_mutex *(*mutex_alloc)(int); + void (*mutex_enter)(sqlite3_mutex*); + void (*mutex_free)(sqlite3_mutex*); + void (*mutex_leave)(sqlite3_mutex*); + int (*mutex_try)(sqlite3_mutex*); + int (*open_v2)(const char*,sqlite3**,int,const char*); + int (*release_memory)(int); + void (*result_error_nomem)(sqlite3_context*); + void (*result_error_toobig)(sqlite3_context*); + int (*sleep)(int); + void (*soft_heap_limit)(int); + sqlite3_vfs *(*vfs_find)(const char*); + int (*vfs_register)(sqlite3_vfs*,int); + int (*vfs_unregister)(sqlite3_vfs*); + int (*xthreadsafe)(void); + void (*result_zeroblob)(sqlite3_context*,int); + void (*result_error_code)(sqlite3_context*,int); + int (*test_control)(int, ...); + void (*randomness)(int,void*); + sqlite3 *(*context_db_handle)(sqlite3_context*); + int (*extended_result_codes)(sqlite3*,int); + int (*limit)(sqlite3*,int,int); + sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); + const char *(*sql)(sqlite3_stmt*); + int (*status)(int,int*,int*,int); + int (*backup_finish)(sqlite3_backup*); + sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); + int (*backup_pagecount)(sqlite3_backup*); + int (*backup_remaining)(sqlite3_backup*); + int (*backup_step)(sqlite3_backup*,int); + const char *(*compileoption_get)(int); + int (*compileoption_used)(const char*); + int (*create_function_v2)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*)); + int (*db_config)(sqlite3*,int,...); + sqlite3_mutex *(*db_mutex)(sqlite3*); + int (*db_status)(sqlite3*,int,int*,int*,int); + int (*extended_errcode)(sqlite3*); + void (*log)(int,const char*,...); + sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); + const char *(*sourceid)(void); + int (*stmt_status)(sqlite3_stmt*,int,int); + int (*strnicmp)(const char*,const char*,int); + int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); + int (*wal_autocheckpoint)(sqlite3*,int); + int (*wal_checkpoint)(sqlite3*,const char*); + void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); + int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); + int (*vtab_config)(sqlite3*,int op,...); + int (*vtab_on_conflict)(sqlite3*); + /* Version 3.7.16 and later */ + int (*close_v2)(sqlite3*); + const char *(*db_filename)(sqlite3*,const char*); + int (*db_readonly)(sqlite3*,const char*); + int (*db_release_memory)(sqlite3*); + const char *(*errstr)(int); + int (*stmt_busy)(sqlite3_stmt*); + int (*stmt_readonly)(sqlite3_stmt*); + int (*stricmp)(const char*,const char*); + 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); + int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); + /* Version 3.8.7 and later */ + int (*auto_extension)(void(*)(void)); + int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, + void(*)(void*)); + int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, + void(*)(void*),unsigned char); + int (*cancel_auto_extension)(void(*)(void)); + int (*load_extension)(sqlite3*,const char*,const char*,char**); + void *(*malloc64)(sqlite3_uint64); + sqlite3_uint64 (*msize)(void*); + void *(*realloc64)(void*,sqlite3_uint64); + void (*reset_auto_extension)(void); + void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, + void(*)(void*)); + void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, + void(*)(void*), unsigned char); + int (*strglob)(const char*,const char*); + /* Version 3.8.11 and later */ + sqlite3_value *(*value_dup)(const sqlite3_value*); + void (*value_free)(sqlite3_value*); + int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); + int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); + /* Version 3.9.0 and later */ + unsigned int (*value_subtype)(sqlite3_value*); + void (*result_subtype)(sqlite3_context*,unsigned int); + /* Version 3.10.0 and later */ + int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); + int (*strlike)(const char*,const char*,unsigned int); + int (*db_cacheflush)(sqlite3*); + /* Version 3.12.0 and later */ + int (*system_errno)(sqlite3*); + /* Version 3.14.0 and later */ + int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); + char *(*expanded_sql)(sqlite3_stmt*); + /* Version 3.18.0 and later */ + void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); +}; + +/* +** This is the function signature used for all extension entry points. It +** is also defined in the file "loadext.c". +*/ +typedef int (*sqlite3_loadext_entry)( + sqlite3 *db, /* Handle to the database. */ + char **pzErrMsg, /* Used to set error string on failure. */ + const sqlite3_api_routines *pThunk /* Extension API function pointers. */ +); + +/* +** The following macros redefine the API routines so that they are +** redirected through the global sqlite3_api structure. +** +** This header file is also used by the loadext.c source file +** (part of the main SQLite library - not an extension) so that +** it can get access to the sqlite3_api_routines structure +** definition. But the main library does not want to redefine +** the API. So the redefinition macros are only valid if the +** SQLITE_CORE macros is undefined. +*/ +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) +#define sqlite3_aggregate_context sqlite3_api->aggregate_context +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_aggregate_count sqlite3_api->aggregate_count +#endif +#define sqlite3_bind_blob sqlite3_api->bind_blob +#define sqlite3_bind_double sqlite3_api->bind_double +#define sqlite3_bind_int sqlite3_api->bind_int +#define sqlite3_bind_int64 sqlite3_api->bind_int64 +#define sqlite3_bind_null sqlite3_api->bind_null +#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count +#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index +#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name +#define sqlite3_bind_text sqlite3_api->bind_text +#define sqlite3_bind_text16 sqlite3_api->bind_text16 +#define sqlite3_bind_value sqlite3_api->bind_value +#define sqlite3_busy_handler sqlite3_api->busy_handler +#define sqlite3_busy_timeout sqlite3_api->busy_timeout +#define sqlite3_changes sqlite3_api->changes +#define sqlite3_close sqlite3_api->close +#define sqlite3_collation_needed sqlite3_api->collation_needed +#define sqlite3_collation_needed16 sqlite3_api->collation_needed16 +#define sqlite3_column_blob sqlite3_api->column_blob +#define sqlite3_column_bytes sqlite3_api->column_bytes +#define sqlite3_column_bytes16 sqlite3_api->column_bytes16 +#define sqlite3_column_count sqlite3_api->column_count +#define sqlite3_column_database_name sqlite3_api->column_database_name +#define sqlite3_column_database_name16 sqlite3_api->column_database_name16 +#define sqlite3_column_decltype sqlite3_api->column_decltype +#define sqlite3_column_decltype16 sqlite3_api->column_decltype16 +#define sqlite3_column_double sqlite3_api->column_double +#define sqlite3_column_int sqlite3_api->column_int +#define sqlite3_column_int64 sqlite3_api->column_int64 +#define sqlite3_column_name sqlite3_api->column_name +#define sqlite3_column_name16 sqlite3_api->column_name16 +#define sqlite3_column_origin_name sqlite3_api->column_origin_name +#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 +#define sqlite3_column_table_name sqlite3_api->column_table_name +#define sqlite3_column_table_name16 sqlite3_api->column_table_name16 +#define sqlite3_column_text sqlite3_api->column_text +#define sqlite3_column_text16 sqlite3_api->column_text16 +#define sqlite3_column_type sqlite3_api->column_type +#define sqlite3_column_value sqlite3_api->column_value +#define sqlite3_commit_hook sqlite3_api->commit_hook +#define sqlite3_complete sqlite3_api->complete +#define sqlite3_complete16 sqlite3_api->complete16 +#define sqlite3_create_collation sqlite3_api->create_collation +#define sqlite3_create_collation16 sqlite3_api->create_collation16 +#define sqlite3_create_function sqlite3_api->create_function +#define sqlite3_create_function16 sqlite3_api->create_function16 +#define sqlite3_create_module sqlite3_api->create_module +#define sqlite3_create_module_v2 sqlite3_api->create_module_v2 +#define sqlite3_data_count sqlite3_api->data_count +#define sqlite3_db_handle sqlite3_api->db_handle +#define sqlite3_declare_vtab sqlite3_api->declare_vtab +#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache +#define sqlite3_errcode sqlite3_api->errcode +#define sqlite3_errmsg sqlite3_api->errmsg +#define sqlite3_errmsg16 sqlite3_api->errmsg16 +#define sqlite3_exec sqlite3_api->exec +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_expired sqlite3_api->expired +#endif +#define sqlite3_finalize sqlite3_api->finalize +#define sqlite3_free sqlite3_api->free +#define sqlite3_free_table sqlite3_api->free_table +#define sqlite3_get_autocommit sqlite3_api->get_autocommit +#define sqlite3_get_auxdata sqlite3_api->get_auxdata +#define sqlite3_get_table sqlite3_api->get_table +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_global_recover sqlite3_api->global_recover +#endif +#define sqlite3_interrupt sqlite3_api->interruptx +#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid +#define sqlite3_libversion sqlite3_api->libversion +#define sqlite3_libversion_number sqlite3_api->libversion_number +#define sqlite3_malloc sqlite3_api->malloc +#define sqlite3_mprintf sqlite3_api->mprintf +#define sqlite3_open sqlite3_api->open +#define sqlite3_open16 sqlite3_api->open16 +#define sqlite3_prepare sqlite3_api->prepare +#define sqlite3_prepare16 sqlite3_api->prepare16 +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 +#define sqlite3_profile sqlite3_api->profile +#define sqlite3_progress_handler sqlite3_api->progress_handler +#define sqlite3_realloc sqlite3_api->realloc +#define sqlite3_reset sqlite3_api->reset +#define sqlite3_result_blob sqlite3_api->result_blob +#define sqlite3_result_double sqlite3_api->result_double +#define sqlite3_result_error sqlite3_api->result_error +#define sqlite3_result_error16 sqlite3_api->result_error16 +#define sqlite3_result_int sqlite3_api->result_int +#define sqlite3_result_int64 sqlite3_api->result_int64 +#define sqlite3_result_null sqlite3_api->result_null +#define sqlite3_result_text sqlite3_api->result_text +#define sqlite3_result_text16 sqlite3_api->result_text16 +#define sqlite3_result_text16be sqlite3_api->result_text16be +#define sqlite3_result_text16le sqlite3_api->result_text16le +#define sqlite3_result_value sqlite3_api->result_value +#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_step sqlite3_api->step +#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata +#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup +#define sqlite3_total_changes sqlite3_api->total_changes +#define sqlite3_trace sqlite3_api->trace +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings +#endif +#define sqlite3_update_hook sqlite3_api->update_hook +#define sqlite3_user_data sqlite3_api->user_data +#define sqlite3_value_blob sqlite3_api->value_blob +#define sqlite3_value_bytes sqlite3_api->value_bytes +#define sqlite3_value_bytes16 sqlite3_api->value_bytes16 +#define sqlite3_value_double sqlite3_api->value_double +#define sqlite3_value_int sqlite3_api->value_int +#define sqlite3_value_int64 sqlite3_api->value_int64 +#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type +#define sqlite3_value_text sqlite3_api->value_text +#define sqlite3_value_text16 sqlite3_api->value_text16 +#define sqlite3_value_text16be sqlite3_api->value_text16be +#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_overload_function sqlite3_api->overload_function +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 +#define sqlite3_clear_bindings sqlite3_api->clear_bindings +#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob +#define sqlite3_blob_bytes sqlite3_api->blob_bytes +#define sqlite3_blob_close sqlite3_api->blob_close +#define sqlite3_blob_open sqlite3_api->blob_open +#define sqlite3_blob_read sqlite3_api->blob_read +#define sqlite3_blob_write sqlite3_api->blob_write +#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 +#define sqlite3_file_control sqlite3_api->file_control +#define sqlite3_memory_highwater sqlite3_api->memory_highwater +#define sqlite3_memory_used sqlite3_api->memory_used +#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc +#define sqlite3_mutex_enter sqlite3_api->mutex_enter +#define sqlite3_mutex_free sqlite3_api->mutex_free +#define sqlite3_mutex_leave sqlite3_api->mutex_leave +#define sqlite3_mutex_try sqlite3_api->mutex_try +#define sqlite3_open_v2 sqlite3_api->open_v2 +#define sqlite3_release_memory sqlite3_api->release_memory +#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem +#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig +#define sqlite3_sleep sqlite3_api->sleep +#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit +#define sqlite3_vfs_find sqlite3_api->vfs_find +#define sqlite3_vfs_register sqlite3_api->vfs_register +#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister +#define sqlite3_threadsafe sqlite3_api->xthreadsafe +#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob +#define sqlite3_result_error_code sqlite3_api->result_error_code +#define sqlite3_test_control sqlite3_api->test_control +#define sqlite3_randomness sqlite3_api->randomness +#define sqlite3_context_db_handle sqlite3_api->context_db_handle +#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes +#define sqlite3_limit sqlite3_api->limit +#define sqlite3_next_stmt sqlite3_api->next_stmt +#define sqlite3_sql sqlite3_api->sql +#define sqlite3_status sqlite3_api->status +#define sqlite3_backup_finish sqlite3_api->backup_finish +#define sqlite3_backup_init sqlite3_api->backup_init +#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount +#define sqlite3_backup_remaining sqlite3_api->backup_remaining +#define sqlite3_backup_step sqlite3_api->backup_step +#define sqlite3_compileoption_get sqlite3_api->compileoption_get +#define sqlite3_compileoption_used sqlite3_api->compileoption_used +#define sqlite3_create_function_v2 sqlite3_api->create_function_v2 +#define sqlite3_db_config sqlite3_api->db_config +#define sqlite3_db_mutex sqlite3_api->db_mutex +#define sqlite3_db_status sqlite3_api->db_status +#define sqlite3_extended_errcode sqlite3_api->extended_errcode +#define sqlite3_log sqlite3_api->log +#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 +#define sqlite3_sourceid sqlite3_api->sourceid +#define sqlite3_stmt_status sqlite3_api->stmt_status +#define sqlite3_strnicmp sqlite3_api->strnicmp +#define sqlite3_unlock_notify sqlite3_api->unlock_notify +#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint +#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint +#define sqlite3_wal_hook sqlite3_api->wal_hook +#define sqlite3_blob_reopen sqlite3_api->blob_reopen +#define sqlite3_vtab_config sqlite3_api->vtab_config +#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict +/* Version 3.7.16 and later */ +#define sqlite3_close_v2 sqlite3_api->close_v2 +#define sqlite3_db_filename sqlite3_api->db_filename +#define sqlite3_db_readonly sqlite3_api->db_readonly +#define sqlite3_db_release_memory sqlite3_api->db_release_memory +#define sqlite3_errstr sqlite3_api->errstr +#define sqlite3_stmt_busy sqlite3_api->stmt_busy +#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly +#define sqlite3_stricmp sqlite3_api->stricmp +#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_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 +/* Version 3.8.7 and later */ +#define sqlite3_auto_extension sqlite3_api->auto_extension +#define sqlite3_bind_blob64 sqlite3_api->bind_blob64 +#define sqlite3_bind_text64 sqlite3_api->bind_text64 +#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension +#define sqlite3_load_extension sqlite3_api->load_extension +#define sqlite3_malloc64 sqlite3_api->malloc64 +#define sqlite3_msize sqlite3_api->msize +#define sqlite3_realloc64 sqlite3_api->realloc64 +#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension +#define sqlite3_result_blob64 sqlite3_api->result_blob64 +#define sqlite3_result_text64 sqlite3_api->result_text64 +#define sqlite3_strglob sqlite3_api->strglob +/* Version 3.8.11 and later */ +#define sqlite3_value_dup sqlite3_api->value_dup +#define sqlite3_value_free sqlite3_api->value_free +#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 +#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64 +/* Version 3.9.0 and later */ +#define sqlite3_value_subtype sqlite3_api->value_subtype +#define sqlite3_result_subtype sqlite3_api->result_subtype +/* Version 3.10.0 and later */ +#define sqlite3_status64 sqlite3_api->status64 +#define sqlite3_strlike sqlite3_api->strlike +#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush +/* Version 3.12.0 and later */ +#define sqlite3_system_errno sqlite3_api->system_errno +/* Version 3.14.0 and later */ +#define sqlite3_trace_v2 sqlite3_api->trace_v2 +#define sqlite3_expanded_sql sqlite3_api->expanded_sql +/* Version 3.18.0 and later */ +#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid +#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ + +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) + /* This case when the file really is being compiled as a loadable + ** extension */ +# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; +# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; +# define SQLITE_EXTENSION_INIT3 \ + extern const sqlite3_api_routines *sqlite3_api; +#else + /* This case when the file is being statically linked into the + ** application */ +# define SQLITE_EXTENSION_INIT1 /*no-op*/ +# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ +# define SQLITE_EXTENSION_INIT3 /*no-op*/ +#endif + +#endif /* SQLITE3EXT_H */ + +/************** End of sqlite3ext.h ******************************************/ +/************** Continuing where we left off in loadext.c ********************/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_LOAD_EXTENSION +/* +** Some API routines are omitted when various features are +** excluded from a build of SQLite. Substitute a NULL pointer +** for any missing APIs. +*/ +#ifndef SQLITE_ENABLE_COLUMN_METADATA +# define sqlite3_column_database_name 0 +# define sqlite3_column_database_name16 0 +# define sqlite3_column_table_name 0 +# define sqlite3_column_table_name16 0 +# define sqlite3_column_origin_name 0 +# define sqlite3_column_origin_name16 0 +#endif + +#ifdef SQLITE_OMIT_AUTHORIZATION +# define sqlite3_set_authorizer 0 +#endif + +#ifdef SQLITE_OMIT_UTF16 +# define sqlite3_bind_text16 0 +# define sqlite3_collation_needed16 0 +# define sqlite3_column_decltype16 0 +# define sqlite3_column_name16 0 +# define sqlite3_column_text16 0 +# define sqlite3_complete16 0 +# define sqlite3_create_collation16 0 +# define sqlite3_create_function16 0 +# define sqlite3_errmsg16 0 +# define sqlite3_open16 0 +# define sqlite3_prepare16 0 +# define sqlite3_prepare16_v2 0 +# define sqlite3_result_error16 0 +# define sqlite3_result_text16 0 +# define sqlite3_result_text16be 0 +# define sqlite3_result_text16le 0 +# define sqlite3_value_text16 0 +# define sqlite3_value_text16be 0 +# define sqlite3_value_text16le 0 +# define sqlite3_column_database_name16 0 +# define sqlite3_column_table_name16 0 +# define sqlite3_column_origin_name16 0 +#endif + +#ifdef SQLITE_OMIT_COMPLETE +# define sqlite3_complete 0 +# define sqlite3_complete16 0 +#endif + +#ifdef SQLITE_OMIT_DECLTYPE +# define sqlite3_column_decltype16 0 +# define sqlite3_column_decltype 0 +#endif + +#ifdef SQLITE_OMIT_PROGRESS_CALLBACK +# define sqlite3_progress_handler 0 +#endif + +#ifdef SQLITE_OMIT_VIRTUALTABLE +# define sqlite3_create_module 0 +# define sqlite3_create_module_v2 0 +# define sqlite3_declare_vtab 0 +# define sqlite3_vtab_config 0 +# define sqlite3_vtab_on_conflict 0 +#endif + +#ifdef SQLITE_OMIT_SHARED_CACHE +# define sqlite3_enable_shared_cache 0 +#endif + +#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED) +# define sqlite3_profile 0 +# define sqlite3_trace 0 +#endif + +#ifdef SQLITE_OMIT_GET_TABLE +# define sqlite3_free_table 0 +# define sqlite3_get_table 0 +#endif + +#ifdef SQLITE_OMIT_INCRBLOB +#define sqlite3_bind_zeroblob 0 +#define sqlite3_blob_bytes 0 +#define sqlite3_blob_close 0 +#define sqlite3_blob_open 0 +#define sqlite3_blob_read 0 +#define sqlite3_blob_write 0 +#define sqlite3_blob_reopen 0 +#endif + +#if defined(SQLITE_OMIT_TRACE) +# define sqlite3_trace_v2 0 +#endif + +/* +** The following structure contains pointers to all SQLite API routines. +** A pointer to this structure is passed into extensions when they are +** loaded so that the extension can make calls back into the SQLite +** library. +** +** When adding new APIs, add them to the bottom of this structure +** in order to preserve backwards compatibility. +** +** Extensions that use newer APIs should first call the +** sqlite3_libversion_number() to make sure that the API they +** intend to use is supported by the library. Extensions should +** also check to make sure that the pointer to the function is +** not NULL before calling it. +*/ +static const sqlite3_api_routines sqlite3Apis = { + sqlite3_aggregate_context, +#ifndef SQLITE_OMIT_DEPRECATED + sqlite3_aggregate_count, +#else + 0, +#endif + sqlite3_bind_blob, + sqlite3_bind_double, + sqlite3_bind_int, + sqlite3_bind_int64, + sqlite3_bind_null, + sqlite3_bind_parameter_count, + sqlite3_bind_parameter_index, + sqlite3_bind_parameter_name, + sqlite3_bind_text, + sqlite3_bind_text16, + sqlite3_bind_value, + sqlite3_busy_handler, + sqlite3_busy_timeout, + sqlite3_changes, + sqlite3_close, + sqlite3_collation_needed, + sqlite3_collation_needed16, + sqlite3_column_blob, + sqlite3_column_bytes, + sqlite3_column_bytes16, + sqlite3_column_count, + sqlite3_column_database_name, + sqlite3_column_database_name16, + sqlite3_column_decltype, + sqlite3_column_decltype16, + sqlite3_column_double, + sqlite3_column_int, + sqlite3_column_int64, + sqlite3_column_name, + sqlite3_column_name16, + sqlite3_column_origin_name, + sqlite3_column_origin_name16, + sqlite3_column_table_name, + sqlite3_column_table_name16, + sqlite3_column_text, + sqlite3_column_text16, + sqlite3_column_type, + sqlite3_column_value, + sqlite3_commit_hook, + sqlite3_complete, + sqlite3_complete16, + sqlite3_create_collation, + sqlite3_create_collation16, + sqlite3_create_function, + sqlite3_create_function16, + sqlite3_create_module, + sqlite3_data_count, + sqlite3_db_handle, + sqlite3_declare_vtab, + sqlite3_enable_shared_cache, + sqlite3_errcode, + sqlite3_errmsg, + sqlite3_errmsg16, + sqlite3_exec, +#ifndef SQLITE_OMIT_DEPRECATED + sqlite3_expired, +#else + 0, +#endif + sqlite3_finalize, + sqlite3_free, + sqlite3_free_table, + sqlite3_get_autocommit, + sqlite3_get_auxdata, + sqlite3_get_table, + 0, /* Was sqlite3_global_recover(), but that function is deprecated */ + sqlite3_interrupt, + sqlite3_last_insert_rowid, + sqlite3_libversion, + sqlite3_libversion_number, + sqlite3_malloc, + sqlite3_mprintf, + sqlite3_open, + sqlite3_open16, + sqlite3_prepare, + sqlite3_prepare16, + sqlite3_profile, + sqlite3_progress_handler, + sqlite3_realloc, + sqlite3_reset, + sqlite3_result_blob, + sqlite3_result_double, + sqlite3_result_error, + sqlite3_result_error16, + sqlite3_result_int, + sqlite3_result_int64, + sqlite3_result_null, + sqlite3_result_text, + sqlite3_result_text16, + sqlite3_result_text16be, + sqlite3_result_text16le, + sqlite3_result_value, + sqlite3_rollback_hook, + sqlite3_set_authorizer, + sqlite3_set_auxdata, + sqlite3_snprintf, + sqlite3_step, + sqlite3_table_column_metadata, +#ifndef SQLITE_OMIT_DEPRECATED + sqlite3_thread_cleanup, +#else + 0, +#endif + sqlite3_total_changes, + sqlite3_trace, +#ifndef SQLITE_OMIT_DEPRECATED + sqlite3_transfer_bindings, +#else + 0, +#endif + sqlite3_update_hook, + sqlite3_user_data, + sqlite3_value_blob, + sqlite3_value_bytes, + sqlite3_value_bytes16, + sqlite3_value_double, + sqlite3_value_int, + sqlite3_value_int64, + sqlite3_value_numeric_type, + sqlite3_value_text, + sqlite3_value_text16, + sqlite3_value_text16be, + sqlite3_value_text16le, + sqlite3_value_type, + sqlite3_vmprintf, + /* + ** The original API set ends here. All extensions can call any + ** of the APIs above provided that the pointer is not NULL. But + ** before calling APIs that follow, extension should check the + ** sqlite3_libversion_number() to make sure they are dealing with + ** a library that is new enough to support that API. + ************************************************************************* + */ + sqlite3_overload_function, + + /* + ** Added after 3.3.13 + */ + sqlite3_prepare_v2, + sqlite3_prepare16_v2, + sqlite3_clear_bindings, + + /* + ** Added for 3.4.1 + */ + sqlite3_create_module_v2, + + /* + ** Added for 3.5.0 + */ + sqlite3_bind_zeroblob, + sqlite3_blob_bytes, + sqlite3_blob_close, + sqlite3_blob_open, + sqlite3_blob_read, + sqlite3_blob_write, + sqlite3_create_collation_v2, + sqlite3_file_control, + sqlite3_memory_highwater, + sqlite3_memory_used, +#ifdef SQLITE_MUTEX_OMIT + 0, + 0, + 0, + 0, + 0, +#else + sqlite3_mutex_alloc, + sqlite3_mutex_enter, + sqlite3_mutex_free, + sqlite3_mutex_leave, + sqlite3_mutex_try, +#endif + sqlite3_open_v2, + sqlite3_release_memory, + sqlite3_result_error_nomem, + sqlite3_result_error_toobig, + sqlite3_sleep, + sqlite3_soft_heap_limit, + sqlite3_vfs_find, + sqlite3_vfs_register, + sqlite3_vfs_unregister, + + /* + ** Added for 3.5.8 + */ + sqlite3_threadsafe, + sqlite3_result_zeroblob, + sqlite3_result_error_code, + sqlite3_test_control, + sqlite3_randomness, + sqlite3_context_db_handle, + + /* + ** Added for 3.6.0 + */ + sqlite3_extended_result_codes, + sqlite3_limit, + sqlite3_next_stmt, + sqlite3_sql, + sqlite3_status, + + /* + ** Added for 3.7.4 + */ + sqlite3_backup_finish, + sqlite3_backup_init, + sqlite3_backup_pagecount, + sqlite3_backup_remaining, + sqlite3_backup_step, +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS + sqlite3_compileoption_get, + sqlite3_compileoption_used, +#else + 0, + 0, +#endif + sqlite3_create_function_v2, + sqlite3_db_config, + sqlite3_db_mutex, + sqlite3_db_status, + sqlite3_extended_errcode, + sqlite3_log, + sqlite3_soft_heap_limit64, + sqlite3_sourceid, + sqlite3_stmt_status, + sqlite3_strnicmp, +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY + sqlite3_unlock_notify, +#else + 0, +#endif +#ifndef SQLITE_OMIT_WAL + sqlite3_wal_autocheckpoint, + sqlite3_wal_checkpoint, + sqlite3_wal_hook, +#else + 0, + 0, + 0, +#endif + sqlite3_blob_reopen, + sqlite3_vtab_config, + sqlite3_vtab_on_conflict, + sqlite3_close_v2, + sqlite3_db_filename, + sqlite3_db_readonly, + sqlite3_db_release_memory, + sqlite3_errstr, + sqlite3_stmt_busy, + sqlite3_stmt_readonly, + sqlite3_stricmp, + sqlite3_uri_boolean, + sqlite3_uri_int64, + sqlite3_uri_parameter, + sqlite3_vsnprintf, + sqlite3_wal_checkpoint_v2, + /* Version 3.8.7 and later */ + sqlite3_auto_extension, + sqlite3_bind_blob64, + sqlite3_bind_text64, + sqlite3_cancel_auto_extension, + sqlite3_load_extension, + sqlite3_malloc64, + sqlite3_msize, + sqlite3_realloc64, + sqlite3_reset_auto_extension, + sqlite3_result_blob64, + sqlite3_result_text64, + sqlite3_strglob, + /* Version 3.8.11 and later */ + (sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup, + sqlite3_value_free, + sqlite3_result_zeroblob64, + sqlite3_bind_zeroblob64, + /* Version 3.9.0 and later */ + sqlite3_value_subtype, + sqlite3_result_subtype, + /* Version 3.10.0 and later */ + sqlite3_status64, + sqlite3_strlike, + sqlite3_db_cacheflush, + /* Version 3.12.0 and later */ + sqlite3_system_errno, + /* Version 3.14.0 and later */ + sqlite3_trace_v2, + sqlite3_expanded_sql, + /* Version 3.18.0 and later */ + sqlite3_set_last_insert_rowid +}; + +/* +** Attempt to load an SQLite extension library contained in the file +** zFile. The entry point is zProc. zProc may be 0 in which case a +** default entry point name (sqlite3_extension_init) is used. Use +** of the default name is recommended. +** +** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong. +** +** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with +** error message text. The calling function should free this memory +** by calling sqlite3DbFree(db, ). +*/ +static int sqlite3LoadExtension( + sqlite3 *db, /* Load the extension into this database connection */ + const char *zFile, /* Name of the shared library containing extension */ + const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ + char **pzErrMsg /* Put error message here if not 0 */ +){ + sqlite3_vfs *pVfs = db->pVfs; + void *handle; + sqlite3_loadext_entry xInit; + char *zErrmsg = 0; + const char *zEntry; + char *zAltEntry = 0; + void **aHandle; + u64 nMsg = 300 + sqlite3Strlen30(zFile); + int ii; + int rc; + + /* Shared library endings to try if zFile cannot be loaded as written */ + static const char *azEndings[] = { +#if SQLITE_OS_WIN + "dll" +#elif defined(__APPLE__) + "dylib" +#else + "so" +#endif + }; + + + if( pzErrMsg ) *pzErrMsg = 0; + + /* Ticket #1863. To avoid a creating security problems for older + ** applications that relink against newer versions of SQLite, the + ** ability to run load_extension is turned off by default. One + ** must call either sqlite3_enable_load_extension(db) or + ** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0) + ** to turn on extension loading. + */ + if( (db->flags & SQLITE_LoadExtension)==0 ){ + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("not authorized"); + } + return SQLITE_ERROR; + } + + zEntry = zProc ? zProc : "sqlite3_extension_init"; + + handle = sqlite3OsDlOpen(pVfs, zFile); +#if SQLITE_OS_UNIX || SQLITE_OS_WIN + for(ii=0; ii sqlite3_example_init + ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init + */ + if( xInit==0 && zProc==0 ){ + int iFile, iEntry, c; + int ncFile = sqlite3Strlen30(zFile); + zAltEntry = sqlite3_malloc64(ncFile+30); + if( zAltEntry==0 ){ + sqlite3OsDlClose(pVfs, handle); + return SQLITE_NOMEM_BKPT; + } + memcpy(zAltEntry, "sqlite3_", 8); + for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){} + iFile++; + if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; + for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ + if( sqlite3Isalpha(c) ){ + zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; + } + } + memcpy(zAltEntry+iEntry, "_init", 6); + zEntry = zAltEntry; + xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); + } + if( xInit==0 ){ + if( pzErrMsg ){ + nMsg += sqlite3Strlen30(zEntry); + *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); + if( zErrmsg ){ + sqlite3_snprintf(nMsg, zErrmsg, + "no entry point [%s] in shared library [%s]", zEntry, zFile); + sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); + } + } + sqlite3OsDlClose(pVfs, handle); + sqlite3_free(zAltEntry); + return SQLITE_ERROR; + } + sqlite3_free(zAltEntry); + rc = xInit(db, &zErrmsg, &sqlite3Apis); + if( rc ){ + if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK; + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); + } + sqlite3_free(zErrmsg); + sqlite3OsDlClose(pVfs, handle); + return SQLITE_ERROR; + } + + /* Append the new shared library handle to the db->aExtension array. */ + aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1)); + if( aHandle==0 ){ + return SQLITE_NOMEM_BKPT; + } + if( db->nExtension>0 ){ + memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension); + } + sqlite3DbFree(db, db->aExtension); + db->aExtension = aHandle; + + db->aExtension[db->nExtension++] = handle; + return SQLITE_OK; +} +SQLITE_API int sqlite3_load_extension( + sqlite3 *db, /* Load the extension into this database connection */ + const char *zFile, /* Name of the shared library containing extension */ + const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ + char **pzErrMsg /* Put error message here if not 0 */ +){ + int rc; + sqlite3_mutex_enter(db->mutex); + rc = sqlite3LoadExtension(db, zFile, zProc, pzErrMsg); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Call this routine when the database connection is closing in order +** to clean up loaded extensions +*/ +SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){ + int i; + assert( sqlite3_mutex_held(db->mutex) ); + for(i=0; inExtension; i++){ + sqlite3OsDlClose(db->pVfs, db->aExtension[i]); + } + sqlite3DbFree(db, db->aExtension); +} + +/* +** Enable or disable extension loading. Extension loading is disabled by +** default so as not to open security holes in older applications. +*/ +SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ + sqlite3_mutex_enter(db->mutex); + if( onoff ){ + db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc; + }else{ + db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc); + } + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */ + +/* +** The following object holds the list of automatically loaded +** extensions. +** +** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER +** mutex must be held while accessing this list. +*/ +typedef struct sqlite3AutoExtList sqlite3AutoExtList; +static SQLITE_WSD struct sqlite3AutoExtList { + u32 nExt; /* Number of entries in aExt[] */ + void (**aExt)(void); /* Pointers to the extension init functions */ +} sqlite3Autoext = { 0, 0 }; + +/* The "wsdAutoext" macro will resolve to the autoextension +** state vector. If writable static data is unsupported on the target, +** we have to locate the state vector at run-time. In the more common +** case where writable static data is supported, wsdStat can refer directly +** to the "sqlite3Autoext" state vector declared above. +*/ +#ifdef SQLITE_OMIT_WSD +# define wsdAutoextInit \ + sqlite3AutoExtList *x = &GLOBAL(sqlite3AutoExtList,sqlite3Autoext) +# define wsdAutoext x[0] +#else +# define wsdAutoextInit +# define wsdAutoext sqlite3Autoext +#endif + + +/* +** Register a statically linked extension that is automatically +** loaded by every new database connection. +*/ +SQLITE_API int sqlite3_auto_extension( + void (*xInit)(void) +){ + int rc = SQLITE_OK; +#ifndef SQLITE_OMIT_AUTOINIT + rc = sqlite3_initialize(); + if( rc ){ + return rc; + }else +#endif + { + u32 i; +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif + wsdAutoextInit; + sqlite3_mutex_enter(mutex); + for(i=0; i=0; i--){ + if( wsdAutoext.aExt[i]==xInit ){ + wsdAutoext.nExt--; + wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt]; + n++; + break; + } + } + sqlite3_mutex_leave(mutex); + return n; +} + +/* +** Reset the automatic extension loading mechanism. +*/ +SQLITE_API void sqlite3_reset_auto_extension(void){ +#ifndef SQLITE_OMIT_AUTOINIT + if( sqlite3_initialize()==SQLITE_OK ) +#endif + { +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif + wsdAutoextInit; + sqlite3_mutex_enter(mutex); + sqlite3_free(wsdAutoext.aExt); + wsdAutoext.aExt = 0; + wsdAutoext.nExt = 0; + sqlite3_mutex_leave(mutex); + } +} + +/* +** Load all automatic extensions. +** +** If anything goes wrong, set an error in the database connection. +*/ +SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ + u32 i; + int go = 1; + int rc; + sqlite3_loadext_entry xInit; + + wsdAutoextInit; + if( wsdAutoext.nExt==0 ){ + /* Common case: early out without every having to acquire a mutex */ + return; + } + for(i=0; go; i++){ + char *zErrmsg; +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif +#ifdef SQLITE_OMIT_LOAD_EXTENSION + const sqlite3_api_routines *pThunk = 0; +#else + const sqlite3_api_routines *pThunk = &sqlite3Apis; +#endif + sqlite3_mutex_enter(mutex); + if( i>=wsdAutoext.nExt ){ + xInit = 0; + go = 0; + }else{ + xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i]; + } + sqlite3_mutex_leave(mutex); + zErrmsg = 0; + if( xInit && (rc = xInit(db, &zErrmsg, pThunk))!=0 ){ + sqlite3ErrorWithMsg(db, rc, + "automatic extension loading failed: %s", zErrmsg); + go = 0; + } + sqlite3_free(zErrmsg); + } +} + +/************** End of loadext.c *********************************************/ +/************** Begin file pragma.c ******************************************/ +/* +** 2003 April 6 +** +** 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 used to implement the PRAGMA command. +*/ +/* #include "sqliteInt.h" */ + +#if !defined(SQLITE_ENABLE_LOCKING_STYLE) +# if defined(__APPLE__) +# define SQLITE_ENABLE_LOCKING_STYLE 1 +# else +# define SQLITE_ENABLE_LOCKING_STYLE 0 +# endif +#endif + +/*************************************************************************** +** The "pragma.h" include file is an automatically generated file that +** that includes the PragType_XXXX macro definitions and the aPragmaName[] +** object. This ensures that the aPragmaName[] table is arranged in +** lexicographical order to facility a binary search of the pragma name. +** Do not edit pragma.h directly. Edit and rerun the script in at +** ../tool/mkpragmatab.tcl. */ +/************** Include pragma.h in the middle of pragma.c *******************/ +/************** Begin file pragma.h ******************************************/ +/* DO NOT EDIT! +** This file is automatically generated by the script at +** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit +** that script and rerun it. +*/ + +/* 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_INCREMENTAL_VACUUM 15 +#define PragTyp_INDEX_INFO 16 +#define PragTyp_INDEX_LIST 17 +#define PragTyp_INTEGRITY_CHECK 18 +#define PragTyp_JOURNAL_MODE 19 +#define PragTyp_JOURNAL_SIZE_LIMIT 20 +#define PragTyp_LOCK_PROXY_FILE 21 +#define PragTyp_LOCKING_MODE 22 +#define PragTyp_PAGE_COUNT 23 +#define PragTyp_MMAP_SIZE 24 +#define PragTyp_OPTIMIZE 25 +#define PragTyp_PAGE_SIZE 26 +#define PragTyp_SECURE_DELETE 27 +#define PragTyp_SHRINK_MEMORY 28 +#define PragTyp_SOFT_HEAP_LIMIT 29 +#define PragTyp_SYNCHRONOUS 30 +#define PragTyp_TABLE_INFO 31 +#define PragTyp_TEMP_STORE 32 +#define PragTyp_TEMP_STORE_DIRECTORY 33 +#define PragTyp_THREADS 34 +#define PragTyp_WAL_AUTOCHECKPOINT 35 +#define PragTyp_WAL_CHECKPOINT 36 +#define PragTyp_ACTIVATE_EXTENSIONS 37 +#define PragTyp_HEXKEY 38 +#define PragTyp_KEY 39 +#define PragTyp_REKEY 40 +#define PragTyp_LOCK_STATUS 41 +#define PragTyp_PARSER_TRACE 42 +#define PragTyp_STATS 43 + +/* Property flags associated with various pragma. */ +#define PragFlg_NeedSchema 0x01 /* Force schema load before running */ +#define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */ +#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */ +#define PragFlg_ReadOnly 0x08 /* Read-only HEADER_VALUE */ +#define PragFlg_Result0 0x10 /* Acts as query when no argument */ +#define PragFlg_Result1 0x20 /* Acts as query when has one argument */ +#define PragFlg_SchemaOpt 0x40 /* Schema restricts name search if present */ +#define PragFlg_SchemaReq 0x80 /* Schema required - "main" is default */ + +/* Names of columns for pragmas that return multi-column result +** or that return single-column results where the name of the +** result column is different from the name of the pragma +*/ +static const char *const pragCName[] = { + /* 0 */ "cache_size", /* Used by: default_cache_size */ + /* 1 */ "cid", /* Used by: table_info */ + /* 2 */ "name", + /* 3 */ "type", + /* 4 */ "notnull", + /* 5 */ "dflt_value", + /* 6 */ "pk", + /* 7 */ "tbl", /* Used by: stats */ + /* 8 */ "idx", + /* 9 */ "wdth", + /* 10 */ "hght", + /* 11 */ "flgs", + /* 12 */ "seqno", /* Used by: index_info */ + /* 13 */ "cid", + /* 14 */ "name", + /* 15 */ "seqno", /* Used by: index_xinfo */ + /* 16 */ "cid", + /* 17 */ "name", + /* 18 */ "desc", + /* 19 */ "coll", + /* 20 */ "key", + /* 21 */ "seq", /* Used by: index_list */ + /* 22 */ "name", + /* 23 */ "unique", + /* 24 */ "origin", + /* 25 */ "partial", + /* 26 */ "seq", /* Used by: database_list */ + /* 27 */ "name", + /* 28 */ "file", + /* 29 */ "seq", /* Used by: collation_list */ + /* 30 */ "name", + /* 31 */ "id", /* Used by: foreign_key_list */ + /* 32 */ "seq", + /* 33 */ "table", + /* 34 */ "from", + /* 35 */ "to", + /* 36 */ "on_update", + /* 37 */ "on_delete", + /* 38 */ "match", + /* 39 */ "table", /* Used by: foreign_key_check */ + /* 40 */ "rowid", + /* 41 */ "parent", + /* 42 */ "fkid", + /* 43 */ "busy", /* Used by: wal_checkpoint */ + /* 44 */ "log", + /* 45 */ "checkpointed", + /* 46 */ "timeout", /* Used by: busy_timeout */ + /* 47 */ "database", /* Used by: lock_status */ + /* 48 */ "status", +}; + +/* Definitions of all built-in pragmas */ +typedef struct PragmaName { + const char *const zName; /* Name of pragma */ + u8 ePragTyp; /* PragTyp_XXX value */ + u8 mPragFlg; /* Zero or more PragFlg_XXX values */ + u8 iPragCName; /* Start of column names in pragCName[] */ + u8 nPragCName; /* Num of col names. 0 means use pragma name */ + u32 iArg; /* Extra argument */ +} PragmaName; +static const PragmaName aPragmaName[] = { +#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) + {/* zName: */ "activate_extensions", + /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + {/* zName: */ "application_id", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_APPLICATION_ID }, +#endif +#if !defined(SQLITE_OMIT_AUTOVACUUM) + {/* zName: */ "auto_vacuum", + /* ePragTyp: */ PragTyp_AUTO_VACUUM, + /* 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) + {/* zName: */ "automatic_index", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_AutoIndex }, +#endif +#endif + {/* zName: */ "busy_timeout", + /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 46, 1, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "cache_size", + /* ePragTyp: */ PragTyp_CACHE_SIZE, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "cache_spill", + /* ePragTyp: */ PragTyp_CACHE_SPILL, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif + {/* zName: */ "case_sensitive_like", + /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, + /* ePragFlg: */ PragFlg_NoColumns, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "cell_size_check", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_CellSizeCk }, +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "checkpoint_fullfsync", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_CkptFullFSync }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + {/* zName: */ "collation_list", + /* ePragTyp: */ PragTyp_COLLATION_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 29, 2, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) + {/* zName: */ "compile_options", + /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "count_changes", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_CountRows }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN + {/* zName: */ "data_store_directory", + /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY, + /* ePragFlg: */ PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + {/* zName: */ "data_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_DATA_VERSION }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + {/* zName: */ "database_list", + /* ePragTyp: */ PragTyp_DATABASE_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, + /* ColNames: */ 26, 3, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) + {/* zName: */ "default_cache_size", + /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 1, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + {/* zName: */ "defer_foreign_keys", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_DeferFKs }, +#endif +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "empty_result_callbacks", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_NullCallback }, +#endif +#if !defined(SQLITE_OMIT_UTF16) + {/* zName: */ "encoding", + /* ePragTyp: */ PragTyp_ENCODING, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + {/* zName: */ "foreign_key_check", + /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, + /* ePragFlg: */ PragFlg_NeedSchema, + /* ColNames: */ 39, 4, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FOREIGN_KEY) + {/* zName: */ "foreign_key_list", + /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 31, 8, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) + {/* zName: */ "foreign_keys", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ForeignKeys }, +#endif +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + {/* zName: */ "freelist_count", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_FREE_PAGE_COUNT }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "full_column_names", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_FullColNames }, + {/* zName: */ "fullfsync", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_FullFSync }, +#endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "hexkey", + /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "hexrekey", + /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if !defined(SQLITE_OMIT_CHECK) + {/* zName: */ "ignore_check_constraints", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_IgnoreChecks }, +#endif +#endif +#if !defined(SQLITE_OMIT_AUTOVACUUM) + {/* zName: */ "incremental_vacuum", + /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + {/* zName: */ "index_info", + /* ePragTyp: */ PragTyp_INDEX_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 12, 3, + /* iArg: */ 0 }, + {/* zName: */ "index_list", + /* ePragTyp: */ PragTyp_INDEX_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 21, 5, + /* iArg: */ 0 }, + {/* zName: */ "index_xinfo", + /* ePragTyp: */ PragTyp_INDEX_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 15, 6, + /* iArg: */ 1 }, +#endif +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) + {/* zName: */ "integrity_check", + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, + /* ePragFlg: */ PragFlg_NeedSchema, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "journal_mode", + /* ePragTyp: */ PragTyp_JOURNAL_MODE, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "journal_size_limit", + /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "key", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "legacy_file_format", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_LegacyFileFmt }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE + {/* zName: */ "lock_proxy_file", + /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE, + /* ePragFlg: */ PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + {/* zName: */ "lock_status", + /* ePragTyp: */ PragTyp_LOCK_STATUS, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 47, 2, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "locking_mode", + /* ePragTyp: */ PragTyp_LOCKING_MODE, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "max_page_count", + /* ePragTyp: */ PragTyp_PAGE_COUNT, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "mmap_size", + /* ePragTyp: */ PragTyp_MMAP_SIZE, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif + {/* zName: */ "optimize", + /* ePragTyp: */ PragTyp_OPTIMIZE, + /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "page_count", + /* ePragTyp: */ PragTyp_PAGE_COUNT, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "page_size", + /* ePragTyp: */ PragTyp_PAGE_SIZE, + /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE) + {/* zName: */ "parser_trace", + /* ePragTyp: */ PragTyp_PARSER_TRACE, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "query_only", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_QueryOnly }, +#endif +#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) + {/* zName: */ "quick_check", + /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, + /* ePragFlg: */ PragFlg_NeedSchema, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "read_uncommitted", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ReadUncommitted }, + {/* zName: */ "recursive_triggers", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_RecTriggers }, +#endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "rekey", + /* ePragTyp: */ PragTyp_REKEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "reverse_unordered_selects", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ReverseOrder }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + {/* zName: */ "schema_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_SCHEMA_VERSION }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "secure_delete", + /* ePragTyp: */ PragTyp_SECURE_DELETE, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "short_column_names", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ShortColNames }, +#endif + {/* zName: */ "shrink_memory", + /* ePragTyp: */ PragTyp_SHRINK_MEMORY, + /* ePragFlg: */ PragFlg_NoColumns, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "soft_heap_limit", + /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if defined(SQLITE_DEBUG) + {/* zName: */ "sql_trace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_SqlTrace }, +#endif +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) + {/* zName: */ "stats", + /* ePragTyp: */ PragTyp_STATS, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, + /* ColNames: */ 7, 5, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "synchronous", + /* ePragTyp: */ PragTyp_SYNCHRONOUS, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + {/* zName: */ "table_info", + /* ePragTyp: */ PragTyp_TABLE_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 1, 6, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + {/* zName: */ "temp_store", + /* ePragTyp: */ PragTyp_TEMP_STORE, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "temp_store_directory", + /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY, + /* ePragFlg: */ PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#endif + {/* zName: */ "threads", + /* ePragTyp: */ PragTyp_THREADS, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + {/* zName: */ "user_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ BTREE_USER_VERSION }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if defined(SQLITE_DEBUG) + {/* zName: */ "vdbe_addoptrace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeAddopTrace }, + {/* zName: */ "vdbe_debug", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace }, + {/* zName: */ "vdbe_eqp", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeEQP }, + {/* zName: */ "vdbe_listing", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeListing }, + {/* zName: */ "vdbe_trace", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_VdbeTrace }, +#endif +#endif +#if !defined(SQLITE_OMIT_WAL) + {/* zName: */ "wal_autocheckpoint", + /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, + {/* zName: */ "wal_checkpoint", + /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, + /* ePragFlg: */ PragFlg_NeedSchema, + /* ColNames: */ 43, 3, + /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "writable_schema", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, +#endif +}; +/* Number of pragmas: 60 on by default, 74 total. */ + +/************** End of pragma.h **********************************************/ +/************** Continuing where we left off in pragma.c *********************/ + +/* +** Interpret the given string as a safety level. Return 0 for OFF, +** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or +** unrecognized string argument. The FULL and EXTRA option is disallowed +** if the omitFull parameter it 1. +** +** Note that the values returned are one less that the values that +** should be passed into sqlite3BtreeSetSafetyLevel(). The is done +** to support legacy SQL code. The safety level used to be boolean +** and older scripts may have used numbers 0 for OFF and 1 for ON. +*/ +static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){ + /* 123456789 123456789 123 */ + static const char zText[] = "onoffalseyestruextrafull"; + static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 15, 20}; + static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 5, 4}; + static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 3, 2}; + /* on no off false yes true extra full */ + int i, n; + if( sqlite3Isdigit(*z) ){ + return (u8)sqlite3Atoi(z); + } + n = sqlite3Strlen30(z); + for(i=0; i=0&&i<=2)?i:0); +} +#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */ + +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +/* +** Interpret the given string as a temp db location. Return 1 for file +** backed temporary databases, 2 for the Red-Black tree in memory database +** and 0 to use the compile-time default. +*/ +static int getTempStore(const char *z){ + if( z[0]>='0' && z[0]<='2' ){ + return z[0] - '0'; + }else if( sqlite3StrICmp(z, "file")==0 ){ + return 1; + }else if( sqlite3StrICmp(z, "memory")==0 ){ + return 2; + }else{ + return 0; + } +} +#endif /* SQLITE_PAGER_PRAGMAS */ + +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +/* +** Invalidate temp storage, either when the temp storage is changed +** from default, or when 'file' and the temp_store_directory has changed +*/ +static int invalidateTempStorage(Parse *pParse){ + sqlite3 *db = pParse->db; + if( db->aDb[1].pBt!=0 ){ + if( !db->autoCommit || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){ + sqlite3ErrorMsg(pParse, "temporary storage cannot be changed " + "from within a transaction"); + return SQLITE_ERROR; + } + sqlite3BtreeClose(db->aDb[1].pBt); + db->aDb[1].pBt = 0; + sqlite3ResetAllSchemasOfConnection(db); + } + return SQLITE_OK; +} +#endif /* SQLITE_PAGER_PRAGMAS */ + +#ifndef SQLITE_OMIT_PAGER_PRAGMAS +/* +** If the TEMP database is open, close it and mark the database schema +** as needing reloading. This must be done when using the SQLITE_TEMP_STORE +** or DEFAULT_TEMP_STORE pragmas. +*/ +static int changeTempStorage(Parse *pParse, const char *zStorageType){ + int ts = getTempStore(zStorageType); + sqlite3 *db = pParse->db; + if( db->temp_store==ts ) return SQLITE_OK; + if( invalidateTempStorage( pParse ) != SQLITE_OK ){ + return SQLITE_ERROR; + } + db->temp_store = (u8)ts; + return SQLITE_OK; +} +#endif /* SQLITE_PAGER_PRAGMAS */ + +/* +** Set result column names for a pragma. +*/ +static void setPragmaResultColumnNames( + Vdbe *v, /* The query under construction */ + const PragmaName *pPragma /* The pragma */ +){ + u8 n = pPragma->nPragCName; + sqlite3VdbeSetNumCols(v, n==0 ? 1 : n); + if( n==0 ){ + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC); + }else{ + int i, j; + for(i=0, j=pPragma->iPragCName; iautoCommit ){ + Db *pDb = db->aDb; + int n = db->nDb; + assert( SQLITE_FullFSync==PAGER_FULLFSYNC ); + assert( SQLITE_CkptFullFSync==PAGER_CKPT_FULLFSYNC ); + assert( SQLITE_CacheSpill==PAGER_CACHESPILL ); + assert( (PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL) + == PAGER_FLAGS_MASK ); + assert( (pDb->safety_level & PAGER_SYNCHRONOUS_MASK)==pDb->safety_level ); + while( (n--) > 0 ){ + if( pDb->pBt ){ + sqlite3BtreeSetPagerFlags(pDb->pBt, + pDb->safety_level | (db->flags & PAGER_FLAGS_MASK) ); + } + pDb++; + } + } +} +#else +# define setAllPagerFlags(X) /* no-op */ +#endif + + +/* +** Return a human-readable name for a constraint resolution action. +*/ +#ifndef SQLITE_OMIT_FOREIGN_KEY +static const char *actionName(u8 action){ + const char *zName; + switch( action ){ + case OE_SetNull: zName = "SET NULL"; break; + case OE_SetDflt: zName = "SET DEFAULT"; break; + case OE_Cascade: zName = "CASCADE"; break; + case OE_Restrict: zName = "RESTRICT"; break; + default: zName = "NO ACTION"; + assert( action==OE_None ); break; + } + return zName; +} +#endif + + +/* +** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants +** defined in pager.h. This function returns the associated lowercase +** journal-mode name. +*/ +SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){ + static char * const azModeName[] = { + "delete", "persist", "off", "truncate", "memory" +#ifndef SQLITE_OMIT_WAL + , "wal" +#endif + }; + assert( PAGER_JOURNALMODE_DELETE==0 ); + assert( PAGER_JOURNALMODE_PERSIST==1 ); + assert( PAGER_JOURNALMODE_OFF==2 ); + assert( PAGER_JOURNALMODE_TRUNCATE==3 ); + assert( PAGER_JOURNALMODE_MEMORY==4 ); + assert( PAGER_JOURNALMODE_WAL==5 ); + assert( eMode>=0 && eMode<=ArraySize(azModeName) ); + + if( eMode==ArraySize(azModeName) ) return 0; + return azModeName[eMode]; +} + +/* +** Locate a pragma in the aPragmaName[] array. +*/ +static const PragmaName *pragmaLocate(const char *zName){ + int upr, lwr, mid = 0, rc; + lwr = 0; + upr = ArraySize(aPragmaName)-1; + while( lwr<=upr ){ + mid = (lwr+upr)/2; + rc = sqlite3_stricmp(zName, aPragmaName[mid].zName); + if( rc==0 ) break; + if( rc<0 ){ + upr = mid - 1; + }else{ + lwr = mid + 1; + } + } + return lwr>upr ? 0 : &aPragmaName[mid]; +} + +/* +** 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. +*/ +static int integrityCheckResultRow(Vdbe *v, int regResult){ + int addr; + sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1); + addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); + return addr; +} + +/* +** Process a pragma statement. +** +** Pragmas are of this form: +** +** PRAGMA [schema.]id [= value] +** +** The identifier might also be a string. The value is a string, and +** identifier, or a number. If minusFlag is true, then the value is +** a number that was preceded by a minus sign. +** +** If the left side is "database.id" then pId1 is the database name +** and pId2 is the id. If the left side is just "id" then pId1 is the +** id and pId2 is any empty string. +*/ +SQLITE_PRIVATE void sqlite3Pragma( + Parse *pParse, + Token *pId1, /* First part of [schema.]id field */ + Token *pId2, /* Second part of [schema.]id field, or NULL */ + Token *pValue, /* Token for , or NULL */ + int minusFlag /* True if a '-' sign preceded */ +){ + char *zLeft = 0; /* Nul-terminated UTF-8 string */ + char *zRight = 0; /* Nul-terminated UTF-8 string , or NULL */ + const char *zDb = 0; /* The database name */ + Token *pId; /* Pointer to token */ + char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */ + int iDb; /* Database index for */ + int rc; /* return value form SQLITE_FCNTL_PRAGMA */ + sqlite3 *db = pParse->db; /* The database connection */ + Db *pDb; /* The specific database being pragmaed */ + Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ + const PragmaName *pPragma; /* The pragma */ + + if( v==0 ) return; + sqlite3VdbeRunOnlyOnce(v); + pParse->nMem = 2; + + /* Interpret the [schema.] part of the pragma statement. iDb is the + ** index of the database this pragma is being applied to in db.aDb[]. */ + iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId); + if( iDb<0 ) return; + pDb = &db->aDb[iDb]; + + /* If the temp database has been explicitly named as part of the + ** pragma, make sure it is open. + */ + if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){ + return; + } + + zLeft = sqlite3NameFromToken(db, pId); + if( !zLeft ) return; + if( minusFlag ){ + zRight = sqlite3MPrintf(db, "-%T", pValue); + }else{ + zRight = sqlite3NameFromToken(db, pValue); + } + + assert( pId2 ); + zDb = pId2->n>0 ? pDb->zDbSName : 0; + if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ + goto pragma_out; + } + + /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS + ** connection. If it returns SQLITE_OK, then assume that the VFS + ** handled the pragma and generate a no-op prepared statement. + ** + ** IMPLEMENTATION-OF: R-12238-55120 Whenever a PRAGMA statement is parsed, + ** an SQLITE_FCNTL_PRAGMA file control is sent to the open sqlite3_file + ** object corresponding to the database file to which the pragma + ** statement refers. + ** + ** IMPLEMENTATION-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA + ** file control is an array of pointers to strings (char**) in which the + ** second element of the array is the name of the pragma and the third + ** element is the argument to the pragma or NULL if the pragma has no + ** argument. + */ + aFcntl[0] = 0; + aFcntl[1] = zLeft; + aFcntl[2] = zRight; + aFcntl[3] = 0; + db->busyHandler.nBusy = 0; + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); + if( rc==SQLITE_OK ){ + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT); + returnSingleText(v, aFcntl[0]); + sqlite3_free(aFcntl[0]); + goto pragma_out; + } + if( rc!=SQLITE_NOTFOUND ){ + if( aFcntl[0] ){ + sqlite3ErrorMsg(pParse, "%s", aFcntl[0]); + sqlite3_free(aFcntl[0]); + } + pParse->nErr++; + pParse->rc = rc; + goto pragma_out; + } + + /* Locate the pragma in the lookup table */ + pPragma = pragmaLocate(zLeft); + if( pPragma==0 ) goto pragma_out; + + /* Make sure the database schema is loaded if the pragma requires that */ + if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ + if( sqlite3ReadSchema(pParse) ) goto pragma_out; + } + + /* Register the result column names for pragmas that return results */ + if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 + && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0) + ){ + setPragmaResultColumnNames(v, pPragma); + } + + /* Jump to the appropriate pragma handler */ + switch( pPragma->ePragTyp ){ + +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) + /* + ** PRAGMA [schema.]default_cache_size + ** PRAGMA [schema.]default_cache_size=N + ** + ** The first form reports the current persistent setting for the + ** page cache size. The value returned is the maximum number of + ** pages in the page cache. The second form sets both the current + ** page cache size value and the persistent page cache size value + ** stored in the database file. + ** + ** Older versions of SQLite would set the default cache size to a + ** negative number to indicate synchronous=OFF. These days, synchronous + ** is always on by default regardless of the sign of the default cache + ** size. But continue to take the absolute value of the default cache + ** size of historical compatibility. + */ + case PragTyp_DEFAULT_CACHE_SIZE: { + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList getCacheSize[] = { + { OP_Transaction, 0, 0, 0}, /* 0 */ + { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ + { OP_IfPos, 1, 8, 0}, + { OP_Integer, 0, 2, 0}, + { OP_Subtract, 1, 2, 1}, + { OP_IfPos, 1, 8, 0}, + { OP_Integer, 0, 1, 0}, /* 6 */ + { OP_Noop, 0, 0, 0}, + { OP_ResultRow, 1, 1, 0}, + }; + VdbeOp *aOp; + sqlite3VdbeUsesBtree(v, iDb); + if( !zRight ){ + pParse->nMem += 2; + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE; + }else{ + int size = sqlite3AbsInt32(sqlite3Atoi(zRight)); + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, size); + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + pDb->pSchema->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); + } + break; + } +#endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */ + +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) + /* + ** PRAGMA [schema.]page_size + ** PRAGMA [schema.]page_size=N + ** + ** The first form reports the current setting for the + ** database page size in bytes. The second form sets the + ** database page size value. The value can only be set if + ** the database has not yet been created. + */ + case PragTyp_PAGE_SIZE: { + Btree *pBt = pDb->pBt; + assert( pBt!=0 ); + if( !zRight ){ + int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0; + returnSingleInt(v, size); + }else{ + /* Malloc may fail when setting the page-size, as there is an internal + ** buffer that the pager module resizes using sqlite3_realloc(). + */ + db->nextPagesize = sqlite3Atoi(zRight); + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){ + sqlite3OomFault(db); + } + } + break; + } + + /* + ** PRAGMA [schema.]secure_delete + ** PRAGMA [schema.]secure_delete=ON/OFF + ** + ** The first form reports the current setting for the + ** secure_delete flag. The second form changes the secure_delete + ** flag setting and reports thenew value. + */ + case PragTyp_SECURE_DELETE: { + Btree *pBt = pDb->pBt; + int b = -1; + assert( pBt!=0 ); + if( zRight ){ + b = sqlite3GetBoolean(zRight, 0); + } + if( pId2->n==0 && b>=0 ){ + int ii; + for(ii=0; iinDb; ii++){ + sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b); + } + } + b = sqlite3BtreeSecureDelete(pBt, b); + returnSingleInt(v, b); + break; + } + + /* + ** PRAGMA [schema.]max_page_count + ** PRAGMA [schema.]max_page_count=N + ** + ** The first form reports the current setting for the + ** maximum number of pages in the database file. The + ** second form attempts to change this setting. Both + ** forms return the current setting. + ** + ** The absolute value of N is used. This is undocumented and might + ** change. The only purpose is to provide an easy way to test + ** the sqlite3AbsInt32() function. + ** + ** PRAGMA [schema.]page_count + ** + ** Return the number of pages in the specified database. + */ + case PragTyp_PAGE_COUNT: { + int iReg; + sqlite3CodeVerifySchema(pParse, iDb); + iReg = ++pParse->nMem; + if( sqlite3Tolower(zLeft[0])=='p' ){ + sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg); + }else{ + sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, + sqlite3AbsInt32(sqlite3Atoi(zRight))); + } + sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1); + break; + } + + /* + ** PRAGMA [schema.]locking_mode + ** PRAGMA [schema.]locking_mode = (normal|exclusive) + */ + case PragTyp_LOCKING_MODE: { + const char *zRet = "normal"; + int eMode = getLockingMode(zRight); + + if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){ + /* Simple "PRAGMA locking_mode;" statement. This is a query for + ** the current default locking mode (which may be different to + ** the locking-mode of the main database). + */ + eMode = db->dfltLockMode; + }else{ + Pager *pPager; + if( pId2->n==0 ){ + /* This indicates that no database name was specified as part + ** of the PRAGMA command. In this case the locking-mode must be + ** set on all attached databases, as well as the main db file. + ** + ** Also, the sqlite3.dfltLockMode variable is set so that + ** any subsequently attached databases also use the specified + ** locking mode. + */ + int ii; + assert(pDb==&db->aDb[0]); + for(ii=2; iinDb; ii++){ + pPager = sqlite3BtreePager(db->aDb[ii].pBt); + sqlite3PagerLockingMode(pPager, eMode); + } + db->dfltLockMode = (u8)eMode; + } + pPager = sqlite3BtreePager(pDb->pBt); + eMode = sqlite3PagerLockingMode(pPager, eMode); + } + + assert( eMode==PAGER_LOCKINGMODE_NORMAL + || eMode==PAGER_LOCKINGMODE_EXCLUSIVE ); + if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){ + zRet = "exclusive"; + } + returnSingleText(v, zRet); + break; + } + + /* + ** PRAGMA [schema.]journal_mode + ** PRAGMA [schema.]journal_mode = + ** (delete|persist|off|truncate|memory|wal|off) + */ + case PragTyp_JOURNAL_MODE: { + int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */ + int ii; /* Loop counter */ + + if( zRight==0 ){ + /* If there is no "=MODE" part of the pragma, do a query for the + ** current mode */ + eMode = PAGER_JOURNALMODE_QUERY; + }else{ + const char *zMode; + int n = sqlite3Strlen30(zRight); + for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){ + if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break; + } + if( !zMode ){ + /* If the "=MODE" part does not match any known journal mode, + ** then do a query */ + eMode = PAGER_JOURNALMODE_QUERY; + } + } + if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){ + /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */ + iDb = 0; + pId2->n = 1; + } + for(ii=db->nDb-1; ii>=0; ii--){ + if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){ + sqlite3VdbeUsesBtree(v, ii); + sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode); + } + } + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); + break; + } + + /* + ** PRAGMA [schema.]journal_size_limit + ** PRAGMA [schema.]journal_size_limit=N + ** + ** Get or set the size limit on rollback journal files. + */ + case PragTyp_JOURNAL_SIZE_LIMIT: { + Pager *pPager = sqlite3BtreePager(pDb->pBt); + i64 iLimit = -2; + if( zRight ){ + sqlite3DecOrHexToI64(zRight, &iLimit); + if( iLimit<-1 ) iLimit = -1; + } + iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); + returnSingleInt(v, iLimit); + break; + } + +#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ + + /* + ** PRAGMA [schema.]auto_vacuum + ** PRAGMA [schema.]auto_vacuum=N + ** + ** Get or set the value of the database 'auto-vacuum' parameter. + ** The value is one of: 0 NONE 1 FULL 2 INCREMENTAL + */ +#ifndef SQLITE_OMIT_AUTOVACUUM + case PragTyp_AUTO_VACUUM: { + Btree *pBt = pDb->pBt; + assert( pBt!=0 ); + if( !zRight ){ + returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt)); + }else{ + int eAuto = getAutoVacuum(zRight); + assert( eAuto>=0 && eAuto<=2 ); + db->nextAutovac = (u8)eAuto; + /* Call SetAutoVacuum() to set initialize the internal auto and + ** incr-vacuum flags. This is required in case this connection + ** creates the database file. It is important that it is created + ** as an auto-vacuum capable db. + */ + rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto); + if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){ + /* When setting the auto_vacuum mode to either "full" or + ** "incremental", write the value of meta[6] in the database + ** file. Before writing to meta[6], check that meta[3] indicates + ** that this really is an auto-vacuum capable database. + */ + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList setMeta6[] = { + { OP_Transaction, 0, 1, 0}, /* 0 */ + { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE}, + { OP_If, 1, 0, 0}, /* 2 */ + { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ + { OP_SetCookie, 0, BTREE_INCR_VACUUM, 0}, /* 4 */ + }; + VdbeOp *aOp; + int iAddr = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[2].p2 = iAddr+4; + aOp[4].p1 = iDb; + aOp[4].p3 = eAuto - 1; + sqlite3VdbeUsesBtree(v, iDb); + } + } + break; + } +#endif + + /* + ** PRAGMA [schema.]incremental_vacuum(N) + ** + ** Do N steps of incremental vacuuming on a database. + */ +#ifndef SQLITE_OMIT_AUTOVACUUM + case PragTyp_INCREMENTAL_VACUUM: { + int iLimit, addr; + if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){ + iLimit = 0x7fffffff; + } + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1); + addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_ResultRow, 1); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); + sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addr); + break; + } +#endif + +#ifndef SQLITE_OMIT_PAGER_PRAGMAS + /* + ** PRAGMA [schema.]cache_size + ** PRAGMA [schema.]cache_size=N + ** + ** The first form reports the current local setting for the + ** page cache size. The second form sets the local + ** page cache size value. If N is positive then that is the + ** number of pages in the cache. If N is negative, then the + ** number of pages is adjusted so that the cache uses -N kibibytes + ** of memory. + */ + case PragTyp_CACHE_SIZE: { + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( !zRight ){ + returnSingleInt(v, pDb->pSchema->cache_size); + }else{ + int size = sqlite3Atoi(zRight); + pDb->pSchema->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); + } + break; + } + + /* + ** PRAGMA [schema.]cache_spill + ** PRAGMA cache_spill=BOOLEAN + ** PRAGMA [schema.]cache_spill=N + ** + ** The first form reports the current local setting for the + ** page cache spill size. The second form turns cache spill on + ** or off. When turnning cache spill on, the size is set to the + ** current cache_size. The third form sets a spill size that + ** may be different form the cache size. + ** If N is positive then that is the + ** number of pages in the cache. If N is negative, then the + ** number of pages is adjusted so that the cache uses -N kibibytes + ** of memory. + ** + ** If the number of cache_spill pages is less then the number of + ** cache_size pages, no spilling occurs until the page count exceeds + ** the number of cache_size pages. + ** + ** The cache_spill=BOOLEAN setting applies to all attached schemas, + ** not just the schema specified. + */ + case PragTyp_CACHE_SPILL: { + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( !zRight ){ + returnSingleInt(v, + (db->flags & SQLITE_CacheSpill)==0 ? 0 : + sqlite3BtreeSetSpillSize(pDb->pBt,0)); + }else{ + int size = 1; + if( sqlite3GetInt32(zRight, &size) ){ + sqlite3BtreeSetSpillSize(pDb->pBt, size); + } + if( sqlite3GetBoolean(zRight, size!=0) ){ + db->flags |= SQLITE_CacheSpill; + }else{ + db->flags &= ~SQLITE_CacheSpill; + } + setAllPagerFlags(db); + } + break; + } + + /* + ** PRAGMA [schema.]mmap_size(N) + ** + ** Used to set mapping size limit. The mapping size limit is + ** used to limit the aggregate size of all memory mapped regions of the + ** database file. If this parameter is set to zero, then memory mapping + ** is not used at all. If N is negative, then the default memory map + ** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set. + ** The parameter N is measured in bytes. + ** + ** This value is advisory. The underlying VFS is free to memory map + ** as little or as much as it wants. Except, if N is set to 0 then the + ** upper layers will never invoke the xFetch interfaces to the VFS. + */ + case PragTyp_MMAP_SIZE: { + sqlite3_int64 sz; +#if SQLITE_MAX_MMAP_SIZE>0 + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( zRight ){ + int ii; + sqlite3DecOrHexToI64(zRight, &sz); + if( sz<0 ) sz = sqlite3GlobalConfig.szMmap; + if( pId2->n==0 ) db->szMmap = sz; + for(ii=db->nDb-1; ii>=0; ii--){ + if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){ + sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz); + } + } + } + sz = -1; + rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_MMAP_SIZE, &sz); +#else + sz = 0; + rc = SQLITE_OK; +#endif + if( rc==SQLITE_OK ){ + returnSingleInt(v, sz); + }else if( rc!=SQLITE_NOTFOUND ){ + pParse->nErr++; + pParse->rc = rc; + } + break; + } + + /* + ** PRAGMA temp_store + ** PRAGMA temp_store = "default"|"memory"|"file" + ** + ** Return or set the local value of the temp_store flag. Changing + ** the local value does not make changes to the disk file and the default + ** value will be restored the next time the database is opened. + ** + ** Note that it is possible for the library compile-time options to + ** override this setting + */ + case PragTyp_TEMP_STORE: { + if( !zRight ){ + returnSingleInt(v, db->temp_store); + }else{ + changeTempStorage(pParse, zRight); + } + break; + } + + /* + ** PRAGMA temp_store_directory + ** PRAGMA temp_store_directory = ""|"directory_name" + ** + ** Return or set the local value of the temp_store_directory flag. Changing + ** the value sets a specific directory to be used for temporary files. + ** Setting to a null string reverts to the default temporary directory search. + ** If temporary directory is changed, then invalidateTempStorage. + ** + */ + case PragTyp_TEMP_STORE_DIRECTORY: { + if( !zRight ){ + returnSingleText(v, sqlite3_temp_directory); + }else{ +#ifndef SQLITE_OMIT_WSD + if( zRight[0] ){ + int res; + rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); + if( rc!=SQLITE_OK || res==0 ){ + sqlite3ErrorMsg(pParse, "not a writable directory"); + goto pragma_out; + } + } + if( SQLITE_TEMP_STORE==0 + || (SQLITE_TEMP_STORE==1 && db->temp_store<=1) + || (SQLITE_TEMP_STORE==2 && db->temp_store==1) + ){ + invalidateTempStorage(pParse); + } + sqlite3_free(sqlite3_temp_directory); + if( zRight[0] ){ + sqlite3_temp_directory = sqlite3_mprintf("%s", zRight); + }else{ + sqlite3_temp_directory = 0; + } +#endif /* SQLITE_OMIT_WSD */ + } + break; + } + +#if SQLITE_OS_WIN + /* + ** PRAGMA data_store_directory + ** PRAGMA data_store_directory = ""|"directory_name" + ** + ** Return or set the local value of the data_store_directory flag. Changing + ** the value sets a specific directory to be used for database files that + ** were specified with a relative pathname. Setting to a null string reverts + ** to the default database directory, which for database files specified with + ** a relative path will probably be based on the current directory for the + ** process. Database file specified with an absolute path are not impacted + ** by this setting, regardless of its value. + ** + */ + case PragTyp_DATA_STORE_DIRECTORY: { + if( !zRight ){ + returnSingleText(v, sqlite3_data_directory); + }else{ +#ifndef SQLITE_OMIT_WSD + if( zRight[0] ){ + int res; + rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); + if( rc!=SQLITE_OK || res==0 ){ + sqlite3ErrorMsg(pParse, "not a writable directory"); + goto pragma_out; + } + } + sqlite3_free(sqlite3_data_directory); + if( zRight[0] ){ + sqlite3_data_directory = sqlite3_mprintf("%s", zRight); + }else{ + sqlite3_data_directory = 0; + } +#endif /* SQLITE_OMIT_WSD */ + } + break; + } +#endif + +#if SQLITE_ENABLE_LOCKING_STYLE + /* + ** PRAGMA [schema.]lock_proxy_file + ** PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path" + ** + ** Return or set the value of the lock_proxy_file flag. Changing + ** the value sets a specific file to be used for database access locks. + ** + */ + case PragTyp_LOCK_PROXY_FILE: { + if( !zRight ){ + Pager *pPager = sqlite3BtreePager(pDb->pBt); + char *proxy_file_path = NULL; + sqlite3_file *pFile = sqlite3PagerFile(pPager); + sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, + &proxy_file_path); + returnSingleText(v, proxy_file_path); + }else{ + Pager *pPager = sqlite3BtreePager(pDb->pBt); + sqlite3_file *pFile = sqlite3PagerFile(pPager); + int res; + if( zRight[0] ){ + res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, + zRight); + } else { + res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, + NULL); + } + if( res!=SQLITE_OK ){ + sqlite3ErrorMsg(pParse, "failed to set lock proxy file"); + goto pragma_out; + } + } + break; + } +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + + /* + ** PRAGMA [schema.]synchronous + ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA + ** + ** Return or set the local value of the synchronous flag. Changing + ** the local value does not make changes to the disk file and the + ** default value will be restored the next time the database is + ** opened. + */ + case PragTyp_SYNCHRONOUS: { + if( !zRight ){ + returnSingleInt(v, pDb->safety_level-1); + }else{ + if( !db->autoCommit ){ + sqlite3ErrorMsg(pParse, + "Safety level may not be changed inside a transaction"); + }else if( iDb!=1 ){ + int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK; + if( iLevel==0 ) iLevel = 1; + pDb->safety_level = iLevel; + pDb->bSyncSet = 1; + setAllPagerFlags(db); + } + } + break; + } +#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ + +#ifndef SQLITE_OMIT_FLAG_PRAGMAS + case PragTyp_FLAG: { + if( zRight==0 ){ + setPragmaResultColumnNames(v, pPragma); + returnSingleInt(v, (db->flags & pPragma->iArg)!=0 ); + }else{ + int mask = pPragma->iArg; /* Mask of bits to set or clear. */ + if( db->autoCommit==0 ){ + /* Foreign key support may not be enabled or disabled while not + ** in auto-commit mode. */ + mask &= ~(SQLITE_ForeignKeys); + } +#if SQLITE_USER_AUTHENTICATION + if( db->auth.authLevel==UAUTH_User ){ + /* Do not allow non-admin users to modify the schema arbitrarily */ + mask &= ~(SQLITE_WriteSchema); + } +#endif + + if( sqlite3GetBoolean(zRight, 0) ){ + db->flags |= mask; + }else{ + db->flags &= ~mask; + if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + } + + /* Many of the flag-pragmas modify the code generated by the SQL + ** compiler (eg. count_changes). So add an opcode to expire all + ** compiled SQL statements after modifying a pragma value. + */ + sqlite3VdbeAddOp0(v, OP_Expire); + setAllPagerFlags(db); + } + break; + } +#endif /* SQLITE_OMIT_FLAG_PRAGMAS */ + +#ifndef SQLITE_OMIT_SCHEMA_PRAGMAS + /* + ** PRAGMA table_info(
    ) + ** + ** Return a single row for each column of the named table. The columns of + ** the returned data set are: + ** + ** cid: Column id (numbered from left to right, starting at 0) + ** name: Column name + ** type: Column declaration type. + ** notnull: True if 'NOT NULL' is part of column declaration + ** dflt_value: The default value for the column, if any. + */ + case PragTyp_TABLE_INFO: if( zRight ){ + Table *pTab; + pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); + if( pTab ){ + int i, k; + int nHidden = 0; + Column *pCol; + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + pParse->nMem = 6; + sqlite3CodeVerifySchema(pParse, iDb); + sqlite3ViewGetColumnNames(pParse, pTab); + for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ + if( IsHiddenColumn(pCol) ){ + nHidden++; + continue; + } + if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ + k = 0; + }else if( pPk==0 ){ + k = 1; + }else{ + for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} + } + assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN ); + sqlite3VdbeMultiLoad(v, 1, "issisi", + i-nHidden, + pCol->zName, + sqlite3ColumnType(pCol,""), + pCol->notNull ? 1 : 0, + pCol->pDflt ? pCol->pDflt->u.zToken : 0, + k); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); + } + } + } + break; + +#ifdef SQLITE_DEBUG + case PragTyp_STATS: { + Index *pIdx; + HashElem *i; + pParse->nMem = 5; + sqlite3CodeVerifySchema(pParse, iDb); + for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ + Table *pTab = sqliteHashData(i); + sqlite3VdbeMultiLoad(v, 1, "ssiii", + pTab->zName, + 0, + pTab->szTabRow, + pTab->nRowLogEst, + pTab->tabFlags); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + sqlite3VdbeMultiLoad(v, 2, "siii", + pIdx->zName, + pIdx->szIdxRow, + pIdx->aiRowLogEst[0], + pIdx->hasStat1); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); + } + } + } + break; +#endif + + case PragTyp_INDEX_INFO: if( zRight ){ + Index *pIdx; + Table *pTab; + pIdx = sqlite3FindIndex(db, zRight, zDb); + if( pIdx ){ + int i; + int mx; + if( pPragma->iArg ){ + /* PRAGMA index_xinfo (newer version with more rows and columns) */ + mx = pIdx->nColumn; + pParse->nMem = 6; + }else{ + /* PRAGMA index_info (legacy version) */ + mx = pIdx->nKeyCol; + pParse->nMem = 3; + } + pTab = pIdx->pTable; + sqlite3CodeVerifySchema(pParse, iDb); + assert( pParse->nMem<=pPragma->nPragCName ); + for(i=0; iaiColumn[i]; + sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum, + cnum<0 ? 0 : pTab->aCol[cnum].zName); + if( pPragma->iArg ){ + sqlite3VdbeMultiLoad(v, 4, "isi", + pIdx->aSortOrder[i], + pIdx->azColl[i], + inKeyCol); + } + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem); + } + } + } + break; + + case PragTyp_INDEX_LIST: if( zRight ){ + Index *pIdx; + Table *pTab; + int i; + pTab = sqlite3FindTable(db, zRight, zDb); + if( pTab ){ + pParse->nMem = 5; + sqlite3CodeVerifySchema(pParse, iDb); + for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ + const char *azOrigin[] = { "c", "u", "pk" }; + sqlite3VdbeMultiLoad(v, 1, "isisi", + i, + pIdx->zName, + IsUniqueIndex(pIdx), + azOrigin[pIdx->idxType], + pIdx->pPartIdxWhere!=0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); + } + } + } + break; + + case PragTyp_DATABASE_LIST: { + int i; + pParse->nMem = 3; + for(i=0; inDb; i++){ + if( db->aDb[i].pBt==0 ) continue; + assert( db->aDb[i].zDbSName!=0 ); + sqlite3VdbeMultiLoad(v, 1, "iss", + i, + db->aDb[i].zDbSName, + sqlite3BtreeGetFilename(db->aDb[i].pBt)); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); + } + } + break; + + case PragTyp_COLLATION_LIST: { + int i = 0; + HashElem *p; + pParse->nMem = 2; + for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ + CollSeq *pColl = (CollSeq *)sqliteHashData(p); + sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); + } + } + break; +#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */ + +#ifndef SQLITE_OMIT_FOREIGN_KEY + case PragTyp_FOREIGN_KEY_LIST: if( zRight ){ + FKey *pFK; + Table *pTab; + pTab = sqlite3FindTable(db, zRight, zDb); + if( pTab ){ + pFK = pTab->pFKey; + if( pFK ){ + int i = 0; + pParse->nMem = 8; + sqlite3CodeVerifySchema(pParse, iDb); + while(pFK){ + int j; + for(j=0; jnCol; j++){ + sqlite3VdbeMultiLoad(v, 1, "iissssss", + i, + j, + pFK->zTo, + pTab->aCol[pFK->aCol[j].iFrom].zName, + pFK->aCol[j].zCol, + actionName(pFK->aAction[1]), /* ON UPDATE */ + actionName(pFK->aAction[0]), /* ON DELETE */ + "NONE"); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8); + } + ++i; + pFK = pFK->pNextFrom; + } + } + } + } + break; +#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ + +#ifndef SQLITE_OMIT_FOREIGN_KEY +#ifndef SQLITE_OMIT_TRIGGER + case PragTyp_FOREIGN_KEY_CHECK: { + FKey *pFK; /* A foreign key constraint */ + Table *pTab; /* Child table contain "REFERENCES" keyword */ + Table *pParent; /* Parent table that child points to */ + Index *pIdx; /* Index in the parent table */ + int i; /* Loop counter: Foreign key number for pTab */ + int j; /* Loop counter: Field of the foreign key */ + HashElem *k; /* Loop counter: Next table in schema */ + int x; /* result variable */ + int regResult; /* 3 registers to hold a result row */ + int regKey; /* Register to hold key for checking the FK */ + int regRow; /* Registers to hold a row from pTab */ + int addrTop; /* Top of a loop checking foreign keys */ + int addrOk; /* Jump here if the key is OK */ + int *aiCols; /* child to parent column mapping */ + + regResult = pParse->nMem+1; + pParse->nMem += 4; + regKey = ++pParse->nMem; + regRow = ++pParse->nMem; + sqlite3CodeVerifySchema(pParse, iDb); + k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); + while( k ){ + if( zRight ){ + pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); + k = 0; + }else{ + pTab = (Table*)sqliteHashData(k); + k = sqliteHashNext(k); + } + if( pTab==0 || pTab->pFKey==0 ) continue; + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; + sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); + sqlite3VdbeLoadString(v, regResult, pTab->zName); + for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ + pParent = sqlite3FindTable(db, pFK->zTo, zDb); + if( pParent==0 ) continue; + pIdx = 0; + sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); + x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); + if( x==0 ){ + if( pIdx==0 ){ + sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); + }else{ + sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + } + }else{ + k = 0; + break; + } + } + assert( pParse->nErr>0 || pFK==0 ); + if( pFK ) break; + if( pParse->nTabnTab = i; + addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v); + for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ + pParent = sqlite3FindTable(db, pFK->zTo, zDb); + pIdx = 0; + aiCols = 0; + if( pParent ){ + x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); + assert( x==0 ); + } + addrOk = sqlite3VdbeMakeLabel(v); + + /* Generate code to read the child key values into registers + ** regRow..regRow+n. If any of the child key values are NULL, this + ** row cannot cause an FK violation. Jump directly to addrOk in + ** this case. */ + for(j=0; jnCol; j++){ + int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; + sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); + sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); + } + + /* Generate code to query the parent index for a matching parent + ** key. If a match is found, jump to addrOk. */ + if( pIdx ){ + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, + sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); + sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); + VdbeCoverage(v); + }else if( pParent ){ + int jmp = sqlite3VdbeCurrentAddr(v)+2; + sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v); + sqlite3VdbeGoto(v, addrOk); + assert( pFK->nCol==1 ); + } + + /* Generate code to report an FK violation to the caller. */ + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); + }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1); + } + sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1); + sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); + sqlite3VdbeResolveLabel(v, addrOk); + sqlite3DbFree(db, aiCols); + } + sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrTop); + } + } + break; +#endif /* !defined(SQLITE_OMIT_TRIGGER) */ +#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ + +#ifndef NDEBUG + case PragTyp_PARSER_TRACE: { + if( zRight ){ + if( sqlite3GetBoolean(zRight, 0) ){ + sqlite3ParserTrace(stdout, "parser: "); + }else{ + sqlite3ParserTrace(0, 0); + } + } + } + break; +#endif + + /* Reinstall the LIKE and GLOB functions. The variant of LIKE + ** used will be case sensitive or not depending on the RHS. + */ + case PragTyp_CASE_SENSITIVE_LIKE: { + if( zRight ){ + sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight, 0)); + } + } + break; + +#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX +# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 +#endif + +#ifndef SQLITE_OMIT_INTEGRITY_CHECK + /* PRAGMA integrity_check + ** PRAGMA integrity_check(N) + ** PRAGMA quick_check + ** PRAGMA quick_check(N) + ** + ** Verify the integrity of the database. + ** + ** The "quick_check" is reduced version of + ** integrity_check designed to detect most database corruption + ** without the overhead of cross-checking indexes. Quick_check + ** is linear time wherease integrity_check is O(NlogN). + */ + case PragTyp_INTEGRITY_CHECK: { + int i, j, addr, mxErr; + + int isQuick = (sqlite3Tolower(zLeft[0])=='q'); + + /* If the PRAGMA command was of the form "PRAGMA .integrity_check", + ** then iDb is set to the index of the database identified by . + ** In this case, the integrity of database iDb only is verified by + ** the VDBE created below. + ** + ** Otherwise, if the command was simply "PRAGMA integrity_check" (or + ** "PRAGMA quick_check"), then iDb is set to 0. In this case, set iDb + ** to -1 here, to indicate that the VDBE should verify the integrity + ** of all attached databases. */ + assert( iDb>=0 ); + assert( iDb==0 || pId2->z ); + if( pId2->z==0 ) iDb = -1; + + /* Initialize the VDBE program */ + pParse->nMem = 6; + + /* Set the maximum error count */ + mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; + if( zRight ){ + sqlite3GetInt32(zRight, &mxErr); + if( mxErr<=0 ){ + mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; + } + } + sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */ + + /* Do an integrity check on each database file */ + for(i=0; inDb; i++){ + HashElem *x; + Hash *pTbls; + int *aRoot; + int cnt = 0; + int mxIdx = 0; + int nIdx; + + if( OMIT_TEMPDB && i==1 ) continue; + if( iDb>=0 && i!=iDb ) continue; + + sqlite3CodeVerifySchema(pParse, i); + + /* Do an integrity check of the B-Tree + ** + ** Begin by finding the root pages numbers + ** for all tables and indices in the database. + */ + 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; + if( HasRowid(pTab) ) cnt++; + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } + if( nIdx>mxIdx ) mxIdx = nIdx; + } + aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1)); + if( aRoot==0 ) break; + for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + Table *pTab = sqliteHashData(x); + Index *pIdx; + if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + aRoot[cnt++] = pIdx->tnum; + } + } + aRoot[cnt] = 0; + + /* Make sure sufficient number of registers have been allocated */ + pParse->nMem = MAX( pParse->nMem, 8+mxIdx ); + + /* Do the b-tree integrity checks */ + sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); + sqlite3VdbeChangeP5(v, (u8)i); + addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); + 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); + sqlite3VdbeJumpHere(v, addr); + + /* Make sure all the indices are constructed correctly. + */ + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + Table *pTab = sqliteHashData(x); + Index *pIdx, *pPk; + Index *pPrior = 0; + int loopTop; + int iDataCur, iIdxCur; + 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); + 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 */ + } + assert( pParse->nMem>=8+j ); + assert( sqlite3NoTempsInRange(pParse,1,7+j) ); + sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); + loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); + /* Verify that all NOT NULL columns really are NOT NULL */ + for(j=0; jnCol; j++){ + char *zErr; + int jmp2; + if( j==pTab->iPKey ) continue; + if( pTab->aCol[j].notNull==0 ) continue; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, + pTab->aCol[j].zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + integrityCheckResultRow(v, 3); + sqlite3VdbeJumpHere(v, jmp2); + } + /* Verify CHECK constraints */ + if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ + ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); + if( db->mallocFailed==0 ){ + int addrCkFault = sqlite3VdbeMakeLabel(v); + int addrCkOk = sqlite3VdbeMakeLabel(v); + char *zErr; + int k; + pParse->iSelfTab = iDataCur; + sqlite3ExprCachePush(pParse); + for(k=pCheck->nExpr-1; k>0; k--){ + sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); + } + sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, + SQLITE_JUMPIFNULL); + sqlite3VdbeResolveLabel(v, addrCkFault); + zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", + pTab->zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + integrityCheckResultRow(v, 3); + 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; kknKeyCol; kk++){ + int iCol = pIdx->aiColumn[kk]; + assert( iCol!=XN_ROWID && iColnCol ); + 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); + } + sqlite3VdbeJumpHere(v, jmp4); + sqlite3ResolvePartIdxLabel(pParse, jmp3); + } + sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, loopTop-1); +#ifndef SQLITE_OMIT_BTREECOUNT + if( !isQuick ){ + sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( pPk==pIdx ) continue; + 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); + sqlite3VdbeJumpHere(v, addr); + } + } +#endif /* SQLITE_OMIT_BTREECOUNT */ + } + } + { + static const int iLn = VDBE_OFFSET_LINENO(2); + static const VdbeOpList endCode[] = { + { OP_AddImm, 1, 0, 0}, /* 0 */ + { OP_IfNotZero, 1, 4, 0}, /* 1 */ + { OP_String8, 0, 3, 0}, /* 2 */ + { OP_ResultRow, 3, 1, 0}, /* 3 */ + }; + VdbeOp *aOp; + + aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); + if( aOp ){ + aOp[0].p2 = 1-mxErr; + aOp[2].p4type = P4_STATIC; + aOp[2].p4.z = "ok"; + } + } + } + break; +#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ + +#ifndef SQLITE_OMIT_UTF16 + /* + ** PRAGMA encoding + ** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be" + ** + ** In its first form, this pragma returns the encoding of the main + ** database. If the database is not initialized, it is initialized now. + ** + ** The second form of this pragma is a no-op if the main database file + ** has not already been initialized. In this case it sets the default + ** encoding that will be used for the main database file if a new file + ** is created. If an existing main database file is opened, then the + ** default text encoding for the existing database is used. + ** + ** In all cases new databases created using the ATTACH command are + ** created to use the same default text encoding as the main database. If + ** the main database has not been initialized and/or created when ATTACH + ** is executed, this is done before the ATTACH operation. + ** + ** In the second form this pragma sets the text encoding to be used in + ** new database files created using this database handle. It is only + ** useful if invoked immediately after the main database i + */ + case PragTyp_ENCODING: { + static const struct EncName { + char *zName; + u8 enc; + } encnames[] = { + { "UTF8", SQLITE_UTF8 }, + { "UTF-8", SQLITE_UTF8 }, /* Must be element [1] */ + { "UTF-16le", SQLITE_UTF16LE }, /* Must be element [2] */ + { "UTF-16be", SQLITE_UTF16BE }, /* Must be element [3] */ + { "UTF16le", SQLITE_UTF16LE }, + { "UTF16be", SQLITE_UTF16BE }, + { "UTF-16", 0 }, /* SQLITE_UTF16NATIVE */ + { "UTF16", 0 }, /* SQLITE_UTF16NATIVE */ + { 0, 0 } + }; + const struct EncName *pEnc; + if( !zRight ){ /* "PRAGMA encoding" */ + if( sqlite3ReadSchema(pParse) ) goto pragma_out; + assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 ); + assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE ); + assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE ); + returnSingleText(v, encnames[ENC(pParse->db)].zName); + }else{ /* "PRAGMA encoding = XXX" */ + /* Only change the value of sqlite.enc if the database handle is not + ** initialized. If the main database exists, the new sqlite.enc value + ** will be overwritten when the schema is next loaded. If it does not + ** already exists, it will be created to use the new encoding value. + */ + if( + !(DbHasProperty(db, 0, DB_SchemaLoaded)) || + DbHasProperty(db, 0, DB_Empty) + ){ + for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ + if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ + SCHEMA_ENC(db) = ENC(db) = + pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; + break; + } + } + if( !pEnc->zName ){ + sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight); + } + } + } + } + break; +#endif /* SQLITE_OMIT_UTF16 */ + +#ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS + /* + ** PRAGMA [schema.]schema_version + ** PRAGMA [schema.]schema_version = + ** + ** PRAGMA [schema.]user_version + ** PRAGMA [schema.]user_version = + ** + ** PRAGMA [schema.]freelist_count + ** + ** PRAGMA [schema.]data_version + ** + ** PRAGMA [schema.]application_id + ** PRAGMA [schema.]application_id = + ** + ** The pragma's schema_version and user_version are used to set or get + ** the value of the schema-version and user-version, respectively. Both + ** the schema-version and the user-version are 32-bit signed integers + ** stored in the database header. + ** + ** The schema-cookie is usually only manipulated internally by SQLite. It + ** is incremented by SQLite whenever the database schema is modified (by + ** creating or dropping a table or index). The schema version is used by + ** SQLite each time a query is executed to ensure that the internal cache + ** of the schema used when compiling the SQL query matches the schema of + ** the database against which the compiled query is actually executed. + ** Subverting this mechanism by using "PRAGMA schema_version" to modify + ** the schema-version is potentially dangerous and may lead to program + ** crashes or database corruption. Use with caution! + ** + ** The user-version is not used internally by SQLite. It may be used by + ** applications for any purpose. + */ + case PragTyp_HEADER_VALUE: { + int iCookie = pPragma->iArg; /* Which cookie to read or write */ + sqlite3VdbeUsesBtree(v, iDb); + if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){ + /* Write the specified cookie value */ + static const VdbeOpList setCookie[] = { + { OP_Transaction, 0, 1, 0}, /* 0 */ + { OP_SetCookie, 0, 0, 0}, /* 1 */ + }; + VdbeOp *aOp; + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[1].p2 = iCookie; + aOp[1].p3 = sqlite3Atoi(zRight); + }else{ + /* Read the specified cookie value */ + static const VdbeOpList readCookie[] = { + { OP_Transaction, 0, 0, 0}, /* 0 */ + { OP_ReadCookie, 0, 1, 0}, /* 1 */ + { OP_ResultRow, 1, 1, 0} + }; + VdbeOp *aOp; + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie)); + aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0); + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; + aOp[0].p1 = iDb; + aOp[1].p1 = iDb; + aOp[1].p3 = iCookie; + sqlite3VdbeReusable(v); + } + } + break; +#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */ + +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS + /* + ** PRAGMA compile_options + ** + ** Return the names of all compile-time options used in this build, + ** one option per row. + */ + case PragTyp_COMPILE_OPTIONS: { + int i = 0; + const char *zOpt; + pParse->nMem = 1; + while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){ + sqlite3VdbeLoadString(v, 1, zOpt); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); + } + sqlite3VdbeReusable(v); + } + break; +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + +#ifndef SQLITE_OMIT_WAL + /* + ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate + ** + ** Checkpoint the database. + */ + case PragTyp_WAL_CHECKPOINT: { + int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED); + int eMode = SQLITE_CHECKPOINT_PASSIVE; + if( zRight ){ + if( sqlite3StrICmp(zRight, "full")==0 ){ + eMode = SQLITE_CHECKPOINT_FULL; + }else if( sqlite3StrICmp(zRight, "restart")==0 ){ + eMode = SQLITE_CHECKPOINT_RESTART; + }else if( sqlite3StrICmp(zRight, "truncate")==0 ){ + eMode = SQLITE_CHECKPOINT_TRUNCATE; + } + } + pParse->nMem = 3; + sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); + } + break; + + /* + ** PRAGMA wal_autocheckpoint + ** PRAGMA wal_autocheckpoint = N + ** + ** Configure a database connection to automatically checkpoint a database + ** after accumulating N frames in the log. Or query for the current value + ** of N. + */ + case PragTyp_WAL_AUTOCHECKPOINT: { + if( zRight ){ + sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight)); + } + returnSingleInt(v, + db->xWalCallback==sqlite3WalDefaultHook ? + SQLITE_PTR_TO_INT(db->pWalArg) : 0); + } + break; +#endif + + /* + ** PRAGMA shrink_memory + ** + ** IMPLEMENTATION-OF: R-23445-46109 This pragma causes the database + ** connection on which it is invoked to free up as much memory as it + ** can, by calling sqlite3_db_release_memory(). + */ + case PragTyp_SHRINK_MEMORY: { + sqlite3_db_release_memory(db); + break; + } + + /* + ** PRAGMA optimize + ** PRAGMA optimize(MASK) + ** PRAGMA schema.optimize + ** PRAGMA schema.optimize(MASK) + ** + ** Attempt to optimize the database. All schemas are optimized in the first + ** two forms, and only the specified schema is optimized in the latter two. + ** + ** The details of optimizations performed by this pragma are expected + ** to change and improve over time. Applications should anticipate that + ** this pragma will perform new optimizations in future releases. + ** + ** The optional argument is a bitmask of optimizations to perform: + ** + ** 0x0001 Debugging mode. Do not actually perform any optimizations + ** but instead return one line of text for each optimization + ** that would have been done. Off by default. + ** + ** 0x0002 Run ANALYZE on tables that might benefit. On by default. + ** See below for additional information. + ** + ** 0x0004 (Not yet implemented) Record usage and performance + ** information from the current session in the + ** database file so that it will be available to "optimize" + ** pragmas run by future database connections. + ** + ** 0x0008 (Not yet implemented) Create indexes that might have + ** been helpful to recent queries + ** + ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all ** of the optimizations listed above except Debug Mode, including new + ** optimizations that have not yet been invented. If new optimizations are + ** ever added that should be off by default, those off-by-default + ** optimizations will have bitmasks of 0x10000 or larger. + ** + ** DETERMINATION OF WHEN TO RUN ANALYZE + ** + ** In the current implementation, a table is analyzed if only if all of + ** the following are true: + ** + ** (1) MASK bit 0x02 is set. + ** + ** (2) The query planner used sqlite_stat1-style statistics for one or + ** more indexes of the table at some point during the lifetime of + ** the current connection. + ** + ** (3) One or more indexes of the table are currently unanalyzed OR + ** the number of rows in the table has increased by 25 times or more + ** since the last time ANALYZE was run. + ** + ** The rules for when tables are analyzed are likely to change in + ** future releases. + */ + case PragTyp_OPTIMIZE: { + int iDbLast; /* Loop termination point for the schema loop */ + int iTabCur; /* Cursor for a table whose size needs checking */ + HashElem *k; /* Loop over tables of a schema */ + Schema *pSchema; /* The current schema */ + Table *pTab; /* A table in the schema */ + Index *pIdx; /* An index of the table */ + LogEst szThreshold; /* Size threshold above which reanalysis is needd */ + char *zSubSql; /* SQL statement for the OP_SqlExec opcode */ + u32 opMask; /* Mask of operations to perform */ + + if( zRight ){ + opMask = (u32)sqlite3Atoi(zRight); + if( (opMask & 0x02)==0 ) break; + }else{ + opMask = 0xfffe; + } + iTabCur = pParse->nTab++; + for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){ + if( iDb==1 ) continue; + sqlite3CodeVerifySchema(pParse, iDb); + pSchema = db->aDb[iDb].pSchema; + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + + /* If table pTab has not been used in a way that would benefit from + ** having analysis statistics during the current session, then skip it. + ** This also has the effect of skipping virtual tables and views */ + if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue; + + /* Reanalyze if the table is 25 times larger than the last analysis */ + szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( !pIdx->hasStat1 ){ + szThreshold = 0; /* Always analyze if any index lacks statistics */ + break; + } + } + if( szThreshold ){ + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, + sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold); + VdbeCoverage(v); + } + zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"", + db->aDb[iDb].zDbSName, pTab->zName); + if( opMask & 0x01 ){ + int r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC); + sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1); + }else{ + sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC); + } + } + } + sqlite3VdbeAddOp0(v, OP_Expire); + break; + } + + /* + ** PRAGMA busy_timeout + ** PRAGMA busy_timeout = N + ** + ** Call sqlite3_busy_timeout(db, N). Return the current timeout value + ** if one is set. If no busy handler or a different busy handler is set + ** then 0 is returned. Setting the busy_timeout to 0 or negative + ** disables the timeout. + */ + /*case PragTyp_BUSY_TIMEOUT*/ default: { + assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT ); + if( zRight ){ + sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); + } + returnSingleInt(v, db->busyTimeout); + break; + } + + /* + ** PRAGMA soft_heap_limit + ** PRAGMA soft_heap_limit = N + ** + ** IMPLEMENTATION-OF: R-26343-45930 This pragma invokes the + ** sqlite3_soft_heap_limit64() interface with the argument N, if N is + ** specified and is a non-negative integer. + ** IMPLEMENTATION-OF: R-64451-07163 The soft_heap_limit pragma always + ** returns the same integer that would be returned by the + ** sqlite3_soft_heap_limit64(-1) C-language function. + */ + case PragTyp_SOFT_HEAP_LIMIT: { + sqlite3_int64 N; + if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ + sqlite3_soft_heap_limit64(N); + } + returnSingleInt(v, sqlite3_soft_heap_limit64(-1)); + break; + } + + /* + ** PRAGMA threads + ** PRAGMA threads = N + ** + ** Configure the maximum number of worker threads. Return the new + ** maximum, which might be less than requested. + */ + case PragTyp_THREADS: { + sqlite3_int64 N; + if( zRight + && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK + && N>=0 + ){ + sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff)); + } + returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1)); + break; + } + +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + /* + ** Report the current state of file logs for all databases + */ + case PragTyp_LOCK_STATUS: { + static const char *const azLockName[] = { + "unlocked", "shared", "reserved", "pending", "exclusive" + }; + int i; + pParse->nMem = 2; + for(i=0; inDb; i++){ + Btree *pBt; + const char *zState = "unknown"; + int j; + if( db->aDb[i].zDbSName==0 ) continue; + pBt = db->aDb[i].pBt; + if( pBt==0 || sqlite3BtreePager(pBt)==0 ){ + zState = "closed"; + }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, + SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ + zState = azLockName[j]; + } + sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); + } + break; + } +#endif + +#ifdef SQLITE_HAS_CODEC + case PragTyp_KEY: { + if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); + break; + } + case PragTyp_REKEY: { + if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); + break; + } + case PragTyp_HEXKEY: { + if( zRight ){ + u8 iByte; + int i; + char zKey[40]; + for(i=0, iByte=0; imPragFlg & PragFlg_NoColumns1) && zRight ){ + sqlite3VdbeVerifyNoResultRow(v); + } + +pragma_out: + sqlite3DbFree(db, zLeft); + sqlite3DbFree(db, zRight); +} +#ifndef SQLITE_OMIT_VIRTUALTABLE +/***************************************************************************** +** Implementation of an eponymous virtual table that runs a pragma. +** +*/ +typedef struct PragmaVtab PragmaVtab; +typedef struct PragmaVtabCursor PragmaVtabCursor; +struct PragmaVtab { + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* The database connection to which it belongs */ + const PragmaName *pName; /* Name of the pragma */ + u8 nHidden; /* Number of hidden columns */ + u8 iHidden; /* Index of the first hidden column */ +}; +struct PragmaVtabCursor { + sqlite3_vtab_cursor base; /* Base class. Must be first */ + sqlite3_stmt *pPragma; /* The pragma statement to run */ + sqlite_int64 iRowid; /* Current rowid */ + char *azArg[2]; /* Value of the argument and schema */ +}; + +/* +** Pragma virtual table module xConnect method. +*/ +static int pragmaVtabConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + const PragmaName *pPragma = (const PragmaName*)pAux; + PragmaVtab *pTab = 0; + int rc; + int i, j; + char cSep = '('; + StrAccum acc; + char zBuf[200]; + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); + sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x"); + for(i=0, j=pPragma->iPragCName; inPragCName; i++, j++){ + sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]); + cSep = ','; + } + if( i==0 ){ + sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName); + cSep = ','; + i++; + } + j = 0; + if( pPragma->mPragFlg & PragFlg_Result1 ){ + sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN"); + j++; + } + if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){ + sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN"); + j++; + } + sqlite3StrAccumAppend(&acc, ")", 1); + sqlite3StrAccumFinish(&acc); + assert( strlen(zBuf) < sizeof(zBuf)-1 ); + rc = sqlite3_declare_vtab(db, zBuf); + if( rc==SQLITE_OK ){ + pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab)); + if( pTab==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pTab, 0, sizeof(PragmaVtab)); + pTab->pName = pPragma; + pTab->db = db; + pTab->iHidden = i; + pTab->nHidden = j; + } + }else{ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + + *ppVtab = (sqlite3_vtab*)pTab; + return rc; +} + +/* +** Pragma virtual table module xDisconnect method. +*/ +static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){ + PragmaVtab *pTab = (PragmaVtab*)pVtab; + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* Figure out the best index to use to search a pragma virtual table. +** +** There are not really any index choices. But we want to encourage the +** query planner to give == constraints on as many hidden parameters as +** possible, and especially on the first hidden parameter. So return a +** high cost if hidden parameters are unconstrained. +*/ +static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + PragmaVtab *pTab = (PragmaVtab*)tab; + const struct sqlite3_index_constraint *pConstraint; + int i, j; + int seen[2]; + + pIdxInfo->estimatedCost = (double)1; + if( pTab->nHidden==0 ){ return SQLITE_OK; } + pConstraint = pIdxInfo->aConstraint; + seen[0] = 0; + seen[1] = 0; + for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->usable==0 ) continue; + if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + if( pConstraint->iColumn < pTab->iHidden ) continue; + j = pConstraint->iColumn - pTab->iHidden; + assert( j < 2 ); + seen[j] = i+1; + } + if( seen[0]==0 ){ + pIdxInfo->estimatedCost = (double)2147483647; + pIdxInfo->estimatedRows = 2147483647; + return SQLITE_OK; + } + j = seen[0]-1; + pIdxInfo->aConstraintUsage[j].argvIndex = 1; + pIdxInfo->aConstraintUsage[j].omit = 1; + if( seen[1]==0 ) return SQLITE_OK; + pIdxInfo->estimatedCost = (double)20; + pIdxInfo->estimatedRows = 20; + j = seen[1]-1; + pIdxInfo->aConstraintUsage[j].argvIndex = 2; + pIdxInfo->aConstraintUsage[j].omit = 1; + return SQLITE_OK; +} + +/* Create a new cursor for the pragma virtual table */ +static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){ + PragmaVtabCursor *pCsr; + pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr)); + if( pCsr==0 ) return SQLITE_NOMEM; + memset(pCsr, 0, sizeof(PragmaVtabCursor)); + pCsr->base.pVtab = pVtab; + *ppCursor = &pCsr->base; + return SQLITE_OK; +} + +/* Clear all content from pragma virtual table cursor. */ +static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){ + int i; + sqlite3_finalize(pCsr->pPragma); + pCsr->pPragma = 0; + for(i=0; iazArg); i++){ + sqlite3_free(pCsr->azArg[i]); + pCsr->azArg[i] = 0; + } +} + +/* Close a pragma virtual table cursor */ +static int pragmaVtabClose(sqlite3_vtab_cursor *cur){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur; + pragmaVtabCursorClear(pCsr); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* Advance the pragma virtual table cursor to the next row */ +static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + int rc = SQLITE_OK; + + /* Increment the xRowid value */ + pCsr->iRowid++; + assert( pCsr->pPragma ); + if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){ + rc = sqlite3_finalize(pCsr->pPragma); + pCsr->pPragma = 0; + pragmaVtabCursorClear(pCsr); + } + return rc; +} + +/* +** Pragma virtual table module xFilter method. +*/ +static int pragmaVtabFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab); + int rc; + int i, j; + StrAccum acc; + char *zSql; + + UNUSED_PARAMETER(idxNum); + UNUSED_PARAMETER(idxStr); + pragmaVtabCursorClear(pCsr); + j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1; + for(i=0; iazArg) ); + pCsr->azArg[j] = sqlite3_mprintf("%s", sqlite3_value_text(argv[i])); + if( pCsr->azArg[j]==0 ){ + return SQLITE_NOMEM; + } + } + sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]); + sqlite3StrAccumAppendAll(&acc, "PRAGMA "); + if( pCsr->azArg[1] ){ + sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]); + } + sqlite3StrAccumAppendAll(&acc, pTab->pName->zName); + if( pCsr->azArg[0] ){ + sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]); + } + zSql = sqlite3StrAccumFinish(&acc); + if( zSql==0 ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0); + sqlite3_free(zSql); + if( rc!=SQLITE_OK ){ + pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); + return rc; + } + return pragmaVtabNext(pVtabCursor); +} + +/* +** Pragma virtual table module xEof method. +*/ +static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + return (pCsr->pPragma==0); +} + +/* The xColumn method simply returns the corresponding column from +** the PRAGMA. +*/ +static int pragmaVtabColumn( + sqlite3_vtab_cursor *pVtabCursor, + sqlite3_context *ctx, + int i +){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab); + if( iiHidden ){ + sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i)); + }else{ + sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT); + } + return SQLITE_OK; +} + +/* +** Pragma virtual table module xRowid method. +*/ +static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){ + PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; + *p = pCsr->iRowid; + return SQLITE_OK; +} + +/* The pragma virtual table object */ +static const sqlite3_module pragmaVtabModule = { + 0, /* iVersion */ + 0, /* xCreate - create a table */ + pragmaVtabConnect, /* xConnect - connect to an existing table */ + pragmaVtabBestIndex, /* xBestIndex - Determine search strategy */ + pragmaVtabDisconnect, /* xDisconnect - Disconnect from a table */ + 0, /* xDestroy - Drop a table */ + pragmaVtabOpen, /* xOpen - open a cursor */ + pragmaVtabClose, /* xClose - close a cursor */ + pragmaVtabFilter, /* xFilter - configure scan constraints */ + pragmaVtabNext, /* xNext - advance a cursor */ + pragmaVtabEof, /* xEof */ + pragmaVtabColumn, /* xColumn - read data */ + pragmaVtabRowid, /* xRowid - read data */ + 0, /* xUpdate - write data */ + 0, /* xBegin - begin transaction */ + 0, /* xSync - sync transaction */ + 0, /* xCommit - commit transaction */ + 0, /* xRollback - rollback transaction */ + 0, /* xFindFunction - function overloading */ + 0, /* xRename - rename the table */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0 /* xRollbackTo */ +}; + +/* +** Check to see if zTabName is really the name of a pragma. If it is, +** then register an eponymous virtual table for that pragma and return +** a pointer to the Module object for the new virtual table. +*/ +SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){ + const PragmaName *pName; + assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 ); + pName = pragmaLocate(zName+7); + if( pName==0 ) return 0; + if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0; + assert( sqlite3HashFind(&db->aModule, zName)==0 ); + return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0); +} + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#endif /* SQLITE_OMIT_PRAGMA */ + +/************** End of pragma.c **********************************************/ +/************** Begin file prepare.c *****************************************/ +/* +** 2005 May 25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains the implementation of the sqlite3_prepare() +** interface, and routines that contribute to loading the database schema +** from disk. +*/ +/* #include "sqliteInt.h" */ + +/* +** Fill the InitData structure with an error message that indicates +** that the database is corrupt. +*/ +static void corruptSchema( + InitData *pData, /* Initialization context */ + const char *zObj, /* Object being parsed at the point of error */ + const char *zExtra /* Error information */ +){ + sqlite3 *db = pData->db; + if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){ + char *z; + if( zObj==0 ) zObj = "?"; + z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); + if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); + sqlite3DbFree(db, *pData->pzErrMsg); + *pData->pzErrMsg = z; + } + pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT; +} + +/* +** This is the callback routine for the code that initializes the +** database. See sqlite3Init() below for additional information. +** This routine is also called from the OP_ParseSchema opcode of the VDBE. +** +** Each callback contains the following information: +** +** argv[0] = name of thing being created +** argv[1] = root page number for table or index. 0 for trigger or view. +** argv[2] = SQL text for the CREATE statement. +** +*/ +SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ + InitData *pData = (InitData*)pInit; + sqlite3 *db = pData->db; + int iDb = pData->iDb; + + assert( argc==3 ); + UNUSED_PARAMETER2(NotUsed, argc); + assert( sqlite3_mutex_held(db->mutex) ); + DbClearProperty(db, iDb, DB_Empty); + if( db->mallocFailed ){ + corruptSchema(pData, argv[0], 0); + return 1; + } + + assert( iDb>=0 && iDbnDb ); + if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ + if( argv[1]==0 ){ + corruptSchema(pData, argv[0], 0); + }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){ + /* Call the parser to process a CREATE TABLE, INDEX or VIEW. + ** But because db->init.busy is set to 1, no VDBE code is generated + ** or executed. All the parser does is build the internal data + ** structures that describe the table, index, or view. + */ + int rc; + u8 saved_iDb = db->init.iDb; + sqlite3_stmt *pStmt; + TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ + + assert( db->init.busy ); + db->init.iDb = iDb; + db->init.newTnum = sqlite3Atoi(argv[1]); + db->init.orphanTrigger = 0; + TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); + rc = db->errCode; + assert( (rc&0xFF)==(rcp&0xFF) ); + db->init.iDb = saved_iDb; + assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 ); + if( SQLITE_OK!=rc ){ + if( db->init.orphanTrigger ){ + assert( iDb==1 ); + }else{ + pData->rc = rc; + if( rc==SQLITE_NOMEM ){ + sqlite3OomFault(db); + }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ + corruptSchema(pData, argv[0], sqlite3_errmsg(db)); + } + } + } + sqlite3_finalize(pStmt); + }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){ + corruptSchema(pData, argv[0], 0); + }else{ + /* If the SQL column is blank it means this is an index that + ** was created to be the PRIMARY KEY or to fulfill a UNIQUE + ** constraint for a CREATE TABLE. The index should have already + ** been created when we processed the CREATE TABLE. All we have + ** to do here is record the root page number for that index. + */ + Index *pIndex; + pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName); + if( pIndex==0 ){ + /* This can occur if there exists an index on a TEMP table which + ** has the same name as another index on a permanent index. Since + ** the permanent table is hidden by the TEMP table, we can also + ** safely ignore the index on the permanent table. + */ + /* Do Nothing */; + }else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){ + corruptSchema(pData, argv[0], "invalid rootpage"); + } + } + return 0; +} + +/* +** Attempt to read the database schema and initialize internal +** data structures for a single database file. The index of the +** database file is given by iDb. iDb==0 is used for the main +** database. iDb==1 should never be used. iDb>=2 is used for +** auxiliary databases. Return one of the SQLITE_ error codes to +** indicate success or failure. +*/ +static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ + int rc; + int i; +#ifndef SQLITE_OMIT_DEPRECATED + int size; +#endif + Db *pDb; + char const *azArg[4]; + int meta[5]; + InitData initData; + const char *zMasterName; + int openedTransaction = 0; + + assert( iDb>=0 && iDbnDb ); + assert( db->aDb[iDb].pSchema ); + assert( sqlite3_mutex_held(db->mutex) ); + assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); + + /* 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 + ** use the abbreviation "x" here. The parser will also automatically tag + ** the schema table as read-only. */ + 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)"; + azArg[3] = 0; + initData.db = db; + initData.iDb = iDb; + initData.rc = SQLITE_OK; + initData.pzErrMsg = pzErrMsg; + sqlite3InitCallback(&initData, 3, (char **)azArg, 0); + if( initData.rc ){ + rc = initData.rc; + goto error_out; + } + + /* Create a cursor to hold the database open + */ + pDb = &db->aDb[iDb]; + if( pDb->pBt==0 ){ + if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){ + DbSetProperty(db, 1, DB_SchemaLoaded); + } + return SQLITE_OK; + } + + /* If there is not already a read-only (or read-write) transaction opened + ** on the b-tree database, open one now. If a transaction is opened, it + ** will be closed before this function returns. */ + sqlite3BtreeEnter(pDb->pBt); + if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){ + rc = sqlite3BtreeBeginTrans(pDb->pBt, 0); + if( rc!=SQLITE_OK ){ + sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); + goto initone_error_out; + } + openedTransaction = 1; + } + + /* Get the database meta information. + ** + ** Meta values are as follows: + ** meta[0] Schema cookie. Changes with each schema change. + ** meta[1] File format of schema layer. + ** meta[2] Size of the page cache. + ** meta[3] Largest rootpage (auto/incr_vacuum mode) + ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE + ** meta[5] User version + ** meta[6] Incremental vacuum mode + ** meta[7] unused + ** meta[8] unused + ** meta[9] unused + ** + ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to + ** the possible values of meta[4]. + */ + for(i=0; ipBt, i+1, (u32 *)&meta[i]); + } + pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1]; + + /* If opening a non-empty database, check the text encoding. For the + ** main database, set sqlite3.enc to the encoding of the main database. + ** For an attached db, it is an error if the encoding is not the same + ** as sqlite3.enc. + */ + if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ + if( iDb==0 ){ +#ifndef SQLITE_OMIT_UTF16 + u8 encoding; + /* If opening the main database, set ENC(db). */ + encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; + if( encoding==0 ) encoding = SQLITE_UTF8; + ENC(db) = encoding; +#else + ENC(db) = SQLITE_UTF8; +#endif + }else{ + /* If opening an attached database, the encoding much match ENC(db) */ + if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){ + sqlite3SetString(pzErrMsg, db, "attached databases must use the same" + " text encoding as main database"); + rc = SQLITE_ERROR; + goto initone_error_out; + } + } + }else{ + DbSetProperty(db, iDb, DB_Empty); + } + pDb->pSchema->enc = ENC(db); + + if( pDb->pSchema->cache_size==0 ){ +#ifndef SQLITE_OMIT_DEPRECATED + size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]); + if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; } + pDb->pSchema->cache_size = size; +#else + pDb->pSchema->cache_size = SQLITE_DEFAULT_CACHE_SIZE; +#endif + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); + } + + /* + ** file_format==1 Version 3.0.0. + ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN + ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults + ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants + */ + pDb->pSchema->file_format = (u8)meta[BTREE_FILE_FORMAT-1]; + if( pDb->pSchema->file_format==0 ){ + pDb->pSchema->file_format = 1; + } + if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ + sqlite3SetString(pzErrMsg, db, "unsupported file format"); + rc = SQLITE_ERROR; + goto initone_error_out; + } + + /* Ticket #2804: When we open a database in the newer file format, + ** clear the legacy_file_format pragma flag so that a VACUUM will + ** not downgrade the database and thus invalidate any descending + ** indices that the user might have created. + */ + if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){ + db->flags &= ~SQLITE_LegacyFileFmt; + } + + /* Read the schema information out of the schema tables + */ + assert( db->init.busy ); + { + char *zSql; + zSql = sqlite3MPrintf(db, + "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid", + db->aDb[iDb].zDbSName, zMasterName); +#ifndef SQLITE_OMIT_AUTHORIZATION + { + sqlite3_xauth xAuth; + xAuth = db->xAuth; + db->xAuth = 0; +#endif + rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; + } +#endif + if( rc==SQLITE_OK ) rc = initData.rc; + sqlite3DbFree(db, zSql); +#ifndef SQLITE_OMIT_ANALYZE + if( rc==SQLITE_OK ){ + sqlite3AnalysisLoad(db, iDb); + } +#endif + } + if( db->mallocFailed ){ + rc = SQLITE_NOMEM_BKPT; + sqlite3ResetAllSchemasOfConnection(db); + } + if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ + /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider + ** the schema loaded, even if errors occurred. In this situation the + ** current sqlite3_prepare() operation will fail, but the following one + ** will attempt to compile the supplied statement against whatever subset + ** of the schema was loaded before the error occurred. The primary + ** purpose of this is to allow access to the sqlite_master table + ** even when its contents have been corrupted. + */ + DbSetProperty(db, iDb, DB_SchemaLoaded); + rc = SQLITE_OK; + } + + /* Jump here for an error that occurs after successfully allocating + ** curMain and calling sqlite3BtreeEnter(). For an error that occurs + ** before that point, jump to error_out. + */ +initone_error_out: + if( openedTransaction ){ + sqlite3BtreeCommit(pDb->pBt); + } + sqlite3BtreeLeave(pDb->pBt); + +error_out: + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomFault(db); + } + return rc; +} + +/* +** Initialize all database files - the main database file, the file +** used to store temporary tables, and any additional database files +** created using ATTACH statements. Return a success code. If an +** error occurs, write an error message into *pzErrMsg. +** +** After a database is initialized, the DB_SchemaLoaded bit is set +** bit is set in the flags field of the Db structure. If the database +** file was of zero-length, then the DB_Empty flag is also set. +*/ +SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ + int i, rc; + int commit_internal = !(db->flags&SQLITE_InternChanges); + + 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 && inDb; 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); + } + } +#endif + + db->init.busy = 0; + if( rc==SQLITE_OK && commit_internal ){ + sqlite3CommitInternalChanges(db); + } + + return rc; +} + +/* +** This routine is a no-op if the database schema is already initialized. +** Otherwise, the schema is loaded. An error code is returned. +*/ +SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ + int rc = SQLITE_OK; + sqlite3 *db = pParse->db; + assert( sqlite3_mutex_held(db->mutex) ); + if( !db->init.busy ){ + rc = sqlite3Init(db, &pParse->zErrMsg); + } + if( rc!=SQLITE_OK ){ + pParse->rc = rc; + pParse->nErr++; + } + return rc; +} + + +/* +** Check schema cookies in all databases. If any cookie is out +** of date set pParse->rc to SQLITE_SCHEMA. If all schema cookies +** make no changes to pParse->rc. +*/ +static void schemaIsValid(Parse *pParse){ + sqlite3 *db = pParse->db; + int iDb; + int rc; + int cookie; + + assert( pParse->checkSchema ); + assert( sqlite3_mutex_held(db->mutex) ); + for(iDb=0; iDbnDb; iDb++){ + int openedTransaction = 0; /* True if a transaction is opened */ + Btree *pBt = db->aDb[iDb].pBt; /* Btree database to read cookie from */ + if( pBt==0 ) continue; + + /* If there is not already a read-only (or read-write) transaction opened + ** on the b-tree database, open one now. If a transaction is opened, it + ** will be closed immediately after reading the meta-value. */ + if( !sqlite3BtreeIsInReadTrans(pBt) ){ + rc = sqlite3BtreeBeginTrans(pBt, 0); + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomFault(db); + } + if( rc!=SQLITE_OK ) return; + openedTransaction = 1; + } + + /* Read the schema cookie from the database. If it does not match the + ** value stored as part of the in-memory schema representation, + ** set Parse.rc to SQLITE_SCHEMA. */ + sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){ + sqlite3ResetOneSchema(db, iDb); + pParse->rc = SQLITE_SCHEMA; + } + + /* Close the transaction, if one was opened. */ + if( openedTransaction ){ + sqlite3BtreeCommit(pBt); + } + } +} + +/* +** Convert a schema pointer into the iDb index that indicates +** which database file in db->aDb[] the schema refers to. +** +** If the same database is attached more than once, the first +** attached database is returned. +*/ +SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ + int i = -1000000; + + /* If pSchema is NULL, then return -1000000. This happens when code in + ** expr.c is trying to resolve a reference to a transient table (i.e. one + ** created by a sub-select). In this case the return value of this + ** function should never be used. + ** + ** We return -1000000 instead of the more usual -1 simply because using + ** -1000000 as the incorrect index into db->aDb[] is much + ** more likely to cause a segfault than -1 (of course there are assert() + ** statements too, but it never hurts to play the odds). + */ + assert( sqlite3_mutex_held(db->mutex) ); + if( pSchema ){ + for(i=0; ALWAYS(inDb); i++){ + if( db->aDb[i].pSchema==pSchema ){ + break; + } + } + assert( i>=0 && inDb ); + } + return i; +} + +/* +** 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; + } +} + +/* +** Compile the UTF-8 encoded SQL statement zSql into a statement handle. +*/ +static int sqlite3Prepare( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + Vdbe *pReprepare, /* VM being reprepared */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + char *zErrMsg = 0; /* Error message */ + int rc = SQLITE_OK; /* Result code */ + int i; /* Loop counter */ + Parse sParse; /* Parsing context */ + + memset(&sParse, 0, PARSE_HDR_SZ); + memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); + sParse.pReprepare = pReprepare; + assert( ppStmt && *ppStmt==0 ); + /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ + assert( sqlite3_mutex_held(db->mutex) ); + + /* Check to verify that it is possible to get a read lock on all + ** database schemas. The inability to get a read lock indicates that + ** some other database connection is holding a write-lock, which in + ** turn means that the other connection has made uncommitted changes + ** to the schema. + ** + ** Were we to proceed and prepare the statement against the uncommitted + ** schema changes and if those schema changes are subsequently rolled + ** back and different changes are made in their place, then when this + ** prepared statement goes to run the schema cookie would fail to detect + ** the schema change. Disaster would follow. + ** + ** This thread is currently holding mutexes on all Btrees (because + ** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it + ** is not possible for another thread to start a new schema change + ** while this routine is running. Hence, we do not need to hold + ** locks on the schema, we just need to make sure nobody else is + ** holding them. + ** + ** Note that setting READ_UNCOMMITTED overrides most lock detection, + ** but it does *not* override schema lock detection, so this all still + ** works even if READ_UNCOMMITTED is set. + */ + for(i=0; inDb; i++) { + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + assert( sqlite3BtreeHoldsMutex(pBt) ); + rc = sqlite3BtreeSchemaLocked(pBt); + if( rc ){ + const char *zDb = db->aDb[i].zDbSName; + sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); + testcase( db->flags & SQLITE_ReadUncommitted ); + goto end_prepare; + } + } + } + + sqlite3VtabUnlockList(db); + + sParse.db = db; + if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ + char *zSqlCopy; + int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; + testcase( nBytes==mxLen ); + testcase( nBytes==mxLen+1 ); + if( nBytes>mxLen ){ + sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long"); + rc = sqlite3ApiExit(db, SQLITE_TOOBIG); + goto end_prepare; + } + zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); + if( zSqlCopy ){ + sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); + sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; + sqlite3DbFree(db, zSqlCopy); + }else{ + sParse.zTail = &zSql[nBytes]; + } + }else{ + sqlite3RunParser(&sParse, zSql, &zErrMsg); + } + assert( 0==sParse.nQueryLoop ); + + if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; + if( sParse.checkSchema ){ + schemaIsValid(&sParse); + } + if( db->mallocFailed ){ + sParse.rc = SQLITE_NOMEM_BKPT; + } + if( pzTail ){ + *pzTail = sParse.zTail; + } + rc = sParse.rc; + +#ifndef SQLITE_OMIT_EXPLAIN + if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ + static const char * const azColName[] = { + "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", + "selectid", "order", "from", "detail" + }; + int iFirst, mx; + if( sParse.explain==2 ){ + sqlite3VdbeSetNumCols(sParse.pVdbe, 4); + iFirst = 8; + mx = 12; + }else{ + sqlite3VdbeSetNumCols(sParse.pVdbe, 8); + iFirst = 0; + mx = 8; + } + for(i=iFirst; iinit.busy==0 ){ + Vdbe *pVdbe = sParse.pVdbe; + sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag); + } + if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ + sqlite3VdbeFinalize(sParse.pVdbe); + assert(!(*ppStmt)); + }else{ + *ppStmt = (sqlite3_stmt*)sParse.pVdbe; + } + + if( zErrMsg ){ + sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg); + sqlite3DbFree(db, zErrMsg); + }else{ + sqlite3Error(db, rc); + } + + /* Delete any TriggerPrg structures allocated while parsing this statement. */ + while( sParse.pTriggerPrg ){ + TriggerPrg *pT = sParse.pTriggerPrg; + sParse.pTriggerPrg = pT->pNext; + sqlite3DbFree(db, pT); + } + +end_prepare: + + sqlite3ParserReset(&sParse); + rc = sqlite3ApiExit(db, rc); + assert( (rc&db->errMask)==rc ); + return rc; +} +static int sqlite3LockAndPrepare( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + Vdbe *pOld, /* VM being reprepared */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + int rc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; +#endif + *ppStmt = 0; + if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ + return SQLITE_MISUSE_BKPT; + } + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); + if( rc==SQLITE_SCHEMA ){ + sqlite3_finalize(*ppStmt); + rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); + } + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + assert( rc==SQLITE_OK || *ppStmt==0 ); + return rc; +} + +/* +** Rerun the compilation of a statement after a schema change. +** +** If the statement is successfully recompiled, return SQLITE_OK. Otherwise, +** if the statement cannot be recompiled because another connection has +** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error +** occurs, return SQLITE_SCHEMA. +*/ +SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ + int rc; + sqlite3_stmt *pNew; + const char *zSql; + sqlite3 *db; + + assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); + zSql = sqlite3_sql((sqlite3_stmt *)p); + assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */ + db = sqlite3VdbeDb(p); + assert( sqlite3_mutex_held(db->mutex) ); + rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0); + if( rc ){ + if( rc==SQLITE_NOMEM ){ + sqlite3OomFault(db); + } + assert( pNew==0 ); + return rc; + }else{ + assert( pNew!=0 ); + } + sqlite3VdbeSwap((Vdbe*)pNew, p); + sqlite3TransferBindings(pNew, (sqlite3_stmt*)p); + sqlite3VdbeResetStepResult((Vdbe*)pNew); + sqlite3VdbeFinalize((Vdbe*)pNew); + return SQLITE_OK; +} + + +/* +** Two versions of the official API. Legacy and new use. In the legacy +** version, the original SQL text is not saved in the prepared statement +** and so if a schema change occurs, SQLITE_SCHEMA is returned by +** sqlite3_step(). In the new version, the original SQL text is retained +** and the statement is automatically recompiled if an schema change +** occurs. +*/ +SQLITE_API int sqlite3_prepare( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + int rc; + rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + return rc; +} +SQLITE_API int sqlite3_prepare_v2( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + int rc; + rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + return rc; +} + + +#ifndef SQLITE_OMIT_UTF16 +/* +** Compile the UTF-16 encoded SQL statement zSql into a statement handle. +*/ +static int sqlite3Prepare16( + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-16 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + /* This function currently works by first transforming the UTF-16 + ** encoded string to UTF-8, then invoking sqlite3_prepare(). The + ** tricky bit is figuring out the pointer to return in *pzTail. + */ + char *zSql8; + const char *zTail8 = 0; + int rc = SQLITE_OK; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; +#endif + *ppStmt = 0; + if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ + return SQLITE_MISUSE_BKPT; + } + if( nBytes>=0 ){ + int sz; + const char *z = (const char*)zSql; + for(sz=0; szmutex); + zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); + if( zSql8 ){ + rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8); + } + + if( zTail8 && pzTail ){ + /* If sqlite3_prepare returns a tail pointer, we calculate the + ** equivalent pointer into the UTF-16 string by counting the unicode + ** characters between zSql8 and zTail8, and then returning a pointer + ** the same number of characters into the UTF-16 string. + */ + int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8)); + *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); + } + sqlite3DbFree(db, zSql8); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Two versions of the official API. Legacy and new use. In the legacy +** version, the original SQL text is not saved in the prepared statement +** and so if a schema change occurs, SQLITE_SCHEMA is returned by +** sqlite3_step(). In the new version, the original SQL text is retained +** and the statement is automatically recompiled if an schema change +** occurs. +*/ +SQLITE_API int sqlite3_prepare16( + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-16 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + int rc; + rc = sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + return rc; +} +SQLITE_API int sqlite3_prepare16_v2( + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-16 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + int rc; + rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + return rc; +} + +#endif /* SQLITE_OMIT_UTF16 */ + +/************** End of prepare.c *********************************************/ +/************** Begin file select.c ******************************************/ +/* +** 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 C code routines that are called by the parser +** to handle SELECT statements in SQLite. +*/ +/* #include "sqliteInt.h" */ + +/* +** Trace output macros +*/ +#if SELECTTRACE_ENABLED +/***/ int sqlite3SelectTrace = 0; +# define SELECTTRACE(K,P,S,X) \ + if(sqlite3SelectTrace&(K)) \ + sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\ + (S)->zSelName,(S)),\ + sqlite3DebugPrintf X +#else +# define SELECTTRACE(K,P,S,X) +#endif + + +/* +** An instance of the following object is used to record information about +** how to process the DISTINCT keyword, to simplify passing that information +** into the selectInnerLoop() routine. +*/ +typedef struct DistinctCtx DistinctCtx; +struct DistinctCtx { + u8 isTnct; /* True if the DISTINCT keyword is present */ + u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ + int tabTnct; /* Ephemeral table used for DISTINCT processing */ + int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ +}; + +/* +** An instance of the following object is used to record information about +** the ORDER BY (or GROUP BY) clause of query is being coded. +*/ +typedef struct SortCtx SortCtx; +struct SortCtx { + ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */ + int nOBSat; /* Number of ORDER BY terms satisfied by indices */ + int iECursor; /* Cursor number for the sorter */ + int regReturn; /* Register holding block-output return address */ + int labelBkOut; /* Start label for the block-output subroutine */ + int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ + int labelDone; /* Jump here when done, ex: LIMIT reached */ + u8 sortFlags; /* Zero or more SORTFLAG_* bits */ + u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */ +}; +#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ + +/* +** Delete all the content of a Select structure. Deallocate the structure +** itself only if bFree is true. +*/ +static void clearSelect(sqlite3 *db, Select *p, int bFree){ + while( p ){ + Select *pPrior = p->pPrior; + sqlite3ExprListDelete(db, p->pEList); + sqlite3SrcListDelete(db, p->pSrc); + sqlite3ExprDelete(db, p->pWhere); + sqlite3ExprListDelete(db, p->pGroupBy); + sqlite3ExprDelete(db, p->pHaving); + sqlite3ExprListDelete(db, p->pOrderBy); + sqlite3ExprDelete(db, p->pLimit); + sqlite3ExprDelete(db, p->pOffset); + if( p->pWith ) sqlite3WithDelete(db, p->pWith); + if( bFree ) sqlite3DbFreeNN(db, p); + p = pPrior; + bFree = 1; + } +} + +/* +** Initialize a SelectDest structure. +*/ +SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){ + pDest->eDest = (u8)eDest; + pDest->iSDParm = iParm; + pDest->zAffSdst = 0; + pDest->iSdst = 0; + pDest->nSdst = 0; +} + + +/* +** Allocate a new Select structure and return a pointer to that +** structure. +*/ +SQLITE_PRIVATE Select *sqlite3SelectNew( + Parse *pParse, /* Parsing context */ + ExprList *pEList, /* which columns to include in the result */ + SrcList *pSrc, /* the FROM clause -- which tables to scan */ + Expr *pWhere, /* the WHERE clause */ + ExprList *pGroupBy, /* the GROUP BY clause */ + Expr *pHaving, /* the HAVING clause */ + ExprList *pOrderBy, /* the ORDER BY clause */ + u32 selFlags, /* Flag parameters, such as SF_Distinct */ + Expr *pLimit, /* LIMIT value. NULL means not used */ + Expr *pOffset /* OFFSET value. NULL means no offset */ +){ + Select *pNew; + Select standin; + pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) ); + if( pNew==0 ){ + assert( pParse->db->mallocFailed ); + pNew = &standin; + } + if( pEList==0 ){ + pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0)); + } + pNew->pEList = pEList; + pNew->op = TK_SELECT; + pNew->selFlags = selFlags; + pNew->iLimit = 0; + pNew->iOffset = 0; +#if SELECTTRACE_ENABLED + pNew->zSelName[0] = 0; +#endif + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->nSelectRow = 0; + if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); + pNew->pSrc = pSrc; + pNew->pWhere = pWhere; + pNew->pGroupBy = pGroupBy; + pNew->pHaving = pHaving; + pNew->pOrderBy = pOrderBy; + pNew->pPrior = 0; + pNew->pNext = 0; + pNew->pLimit = pLimit; + pNew->pOffset = pOffset; + pNew->pWith = 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; + }else{ + assert( pNew->pSrc!=0 || pParse->nErr>0 ); + } + assert( pNew!=&standin ); + return pNew; +} + +#if SELECTTRACE_ENABLED +/* +** Set the name of a Select object +*/ +SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){ + if( p && zName ){ + sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName); + } +} +#endif + + +/* +** Delete the given Select structure and all of its substructures. +*/ +SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ + if( p ) clearSelect(db, p, 1); +} + +/* +** Return a pointer to the right-most SELECT statement in a compound. +*/ +static Select *findRightmost(Select *p){ + while( p->pNext ) p = p->pNext; + return p; +} + +/* +** Given 1 to 3 identifiers preceding the JOIN keyword, determine the +** type of join. Return an integer constant that expresses that type +** in terms of the following bit values: +** +** JT_INNER +** JT_CROSS +** JT_OUTER +** JT_NATURAL +** JT_LEFT +** JT_RIGHT +** +** A full outer join is the combination of JT_LEFT and JT_RIGHT. +** +** If an illegal or unsupported join type is seen, then still return +** a join type, but put an error in the pParse structure. +*/ +SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ + int jointype = 0; + Token *apAll[3]; + Token *p; + /* 0123456789 123456789 123456789 123 */ + static const char zKeyText[] = "naturaleftouterightfullinnercross"; + static const struct { + u8 i; /* Beginning of keyword text in zKeyText[] */ + u8 nChar; /* Length of the keyword in characters */ + u8 code; /* Join type mask */ + } aKeyword[] = { + /* natural */ { 0, 7, JT_NATURAL }, + /* left */ { 6, 4, JT_LEFT|JT_OUTER }, + /* outer */ { 10, 5, JT_OUTER }, + /* right */ { 14, 5, JT_RIGHT|JT_OUTER }, + /* full */ { 19, 4, JT_LEFT|JT_RIGHT|JT_OUTER }, + /* inner */ { 23, 5, JT_INNER }, + /* cross */ { 28, 5, JT_INNER|JT_CROSS }, + }; + int i, j; + apAll[0] = pA; + apAll[1] = pB; + apAll[2] = pC; + for(i=0; i<3 && apAll[i]; i++){ + p = apAll[i]; + for(j=0; jn==aKeyword[j].nChar + && sqlite3StrNICmp((char*)p->z, &zKeyText[aKeyword[j].i], p->n)==0 ){ + jointype |= aKeyword[j].code; + break; + } + } + testcase( j==0 || j==1 || j==2 || j==3 || j==4 || j==5 || j==6 ); + if( j>=ArraySize(aKeyword) ){ + jointype |= JT_ERROR; + break; + } + } + if( + (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) || + (jointype & JT_ERROR)!=0 + ){ + const char *zSp = " "; + assert( pB!=0 ); + if( pC==0 ){ zSp++; } + sqlite3ErrorMsg(pParse, "unknown or unsupported join type: " + "%T %T%s%T", pA, pB, zSp, pC); + jointype = JT_INNER; + }else if( (jointype & JT_OUTER)!=0 + && (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){ + sqlite3ErrorMsg(pParse, + "RIGHT and FULL OUTER JOINs are not currently supported"); + jointype = JT_INNER; + } + return jointype; +} + +/* +** Return the index of a column in a table. Return -1 if the column +** is not contained in the table. +*/ +static int columnIndex(Table *pTab, const char *zCol){ + int i; + for(i=0; inCol; i++){ + if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i; + } + return -1; +} + +/* +** Search the first N tables in pSrc, from left to right, looking for a +** table that has a column named zCol. +** +** When found, set *piTab and *piCol to the table index and column index +** of the matching column and return TRUE. +** +** If not found, return FALSE. +*/ +static int tableAndColumnIndex( + SrcList *pSrc, /* Array of tables to search */ + int N, /* Number of tables in pSrc->a[] to search */ + const char *zCol, /* Name of the column we are looking for */ + int *piTab, /* Write index of pSrc->a[] here */ + int *piCol /* Write index of pSrc->a[*piTab].pTab->aCol[] here */ +){ + int i; /* For looping over tables in pSrc */ + int iCol; /* Index of column matching zCol */ + + assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ + for(i=0; ia[i].pTab, zCol); + if( iCol>=0 ){ + if( piTab ){ + *piTab = i; + *piCol = iCol; + } + return 1; + } + } + return 0; +} + +/* +** This function is used to add terms implied by JOIN syntax to the +** WHERE clause expression of a SELECT statement. The new term, which +** is ANDed with the existing WHERE clause, is of the form: +** +** (tab1.col1 = tab2.col2) +** +** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the +** (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is +** column iColRight of tab2. +*/ +static void addWhereTerm( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* List of tables in FROM clause */ + int iLeft, /* Index of first table to join in pSrc */ + int iColLeft, /* Index of column in first table */ + int iRight, /* Index of second table in pSrc */ + int iColRight, /* Index of column in second table */ + int isOuterJoin, /* True if this is an OUTER join */ + Expr **ppWhere /* IN/OUT: The WHERE clause to add to */ +){ + sqlite3 *db = pParse->db; + Expr *pE1; + Expr *pE2; + Expr *pEq; + + assert( iLeftnSrc>iRight ); + assert( pSrc->a[iLeft].pTab ); + assert( pSrc->a[iRight].pTab ); + + pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft); + pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight); + + pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2); + if( pEq && isOuterJoin ){ + ExprSetProperty(pEq, EP_FromJoin); + assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); + ExprSetVVAProperty(pEq, EP_NoReduce); + pEq->iRightJoinTable = (i16)pE2->iTable; + } + *ppWhere = sqlite3ExprAnd(db, *ppWhere, pEq); +} + +/* +** Set the EP_FromJoin property on all terms of the given expression. +** And set the Expr.iRightJoinTable to iTable for every term in the +** expression. +** +** The EP_FromJoin property is used on terms of an expression to tell +** the LEFT OUTER JOIN processing logic that this term is part of the +** join restriction specified in the ON or USING clause and not a part +** of the more general WHERE clause. These terms are moved over to the +** WHERE clause during join processing but we need to remember that they +** originated in the ON or USING clause. +** +** The Expr.iRightJoinTable tells the WHERE clause processing that the +** expression depends on table iRightJoinTable even if that table is not +** explicitly mentioned in the expression. That information is needed +** for cases like this: +** +** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5 +** +** The where clause needs to defer the handling of the t1.x=5 +** term until after the t2 loop of the join. In that way, a +** NULL t2 row will be inserted whenever t1.x!=5. If we do not +** defer the handling of t1.x=5, it will be processed immediately +** after the t1 loop and rows with t1.x!=5 will never appear in +** the output, which is incorrect. +*/ +static void setJoinExpr(Expr *p, int iTable){ + while( p ){ + ExprSetProperty(p, EP_FromJoin); + assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); + ExprSetVVAProperty(p, EP_NoReduce); + p->iRightJoinTable = (i16)iTable; + if( p->op==TK_FUNCTION && p->x.pList ){ + int i; + for(i=0; ix.pList->nExpr; i++){ + setJoinExpr(p->x.pList->a[i].pExpr, iTable); + } + } + setJoinExpr(p->pLeft, iTable); + p = p->pRight; + } +} + +/* +** This routine processes the join information for a SELECT statement. +** ON and USING clauses are converted into extra terms of the WHERE clause. +** NATURAL joins also create extra WHERE clause terms. +** +** The terms of a FROM clause are contained in the Select.pSrc structure. +** The left most table is the first entry in Select.pSrc. The right-most +** table is the last entry. The join operator is held in the entry to +** the left. Thus entry 0 contains the join operator for the join between +** entries 0 and 1. Any ON or USING clauses associated with the join are +** also attached to the left entry. +** +** This routine returns the number of errors encountered. +*/ +static int sqliteProcessJoin(Parse *pParse, Select *p){ + SrcList *pSrc; /* All tables in the FROM clause */ + int i, j; /* Loop counters */ + struct SrcList_item *pLeft; /* Left table being joined */ + struct SrcList_item *pRight; /* Right table being joined */ + + pSrc = p->pSrc; + pLeft = &pSrc->a[0]; + pRight = &pLeft[1]; + for(i=0; inSrc-1; i++, pRight++, pLeft++){ + Table *pLeftTab = pLeft->pTab; + Table *pRightTab = pRight->pTab; + int isOuter; + + if( NEVER(pLeftTab==0 || pRightTab==0) ) continue; + isOuter = (pRight->fg.jointype & JT_OUTER)!=0; + + /* When the NATURAL keyword is present, add WHERE clause terms for + ** every column that the two tables have in common. + */ + if( pRight->fg.jointype & JT_NATURAL ){ + if( pRight->pOn || pRight->pUsing ){ + sqlite3ErrorMsg(pParse, "a NATURAL join may not have " + "an ON or USING clause", 0); + return 1; + } + for(j=0; jnCol; j++){ + char *zName; /* Name of column in the right table */ + int iLeft; /* Matching left table */ + int iLeftCol; /* Matching column in the left table */ + + zName = pRightTab->aCol[j].zName; + if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){ + addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j, + isOuter, &p->pWhere); + } + } + } + + /* Disallow both ON and USING clauses in the same join + */ + if( pRight->pOn && pRight->pUsing ){ + sqlite3ErrorMsg(pParse, "cannot have both ON and USING " + "clauses in the same join"); + return 1; + } + + /* Add the ON clause to the end of the WHERE clause, connected by + ** an AND operator. + */ + if( pRight->pOn ){ + if( isOuter ) setJoinExpr(pRight->pOn, pRight->iCursor); + p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn); + pRight->pOn = 0; + } + + /* Create extra terms on the WHERE clause for each column named + ** in the USING clause. Example: If the two tables to be joined are + ** A and B and the USING clause names X, Y, and Z, then add this + ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z + ** Report an error if any column mentioned in the USING clause is + ** not contained in both tables to be joined. + */ + if( pRight->pUsing ){ + IdList *pList = pRight->pUsing; + for(j=0; jnId; j++){ + char *zName; /* Name of the term in the USING clause */ + int iLeft; /* Table on the left with matching column name */ + int iLeftCol; /* Column number of matching column on the left */ + int iRightCol; /* Column number of matching column on the right */ + + zName = pList->a[j].zName; + iRightCol = columnIndex(pRightTab, zName); + if( iRightCol<0 + || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) + ){ + sqlite3ErrorMsg(pParse, "cannot join using column %s - column " + "not present in both tables", zName); + return 1; + } + addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol, + isOuter, &p->pWhere); + } + } + } + return 0; +} + +/* Forward reference */ +static KeyInfo *keyInfoFromExprList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Form the KeyInfo object from this ExprList */ + int iStart, /* Begin with this column of pList */ + int nExtra /* Add this many extra columns to the end */ +); + +/* +** Generate code that will push the record in registers regData +** through regData+nData-1 onto the sorter. +*/ +static void pushOntoSorter( + Parse *pParse, /* Parser context */ + SortCtx *pSort, /* Information about the ORDER BY clause */ + Select *pSelect, /* The whole SELECT statement */ + int regData, /* First register holding data to be sorted */ + int regOrigData, /* First register holding data before packing */ + int nData, /* Number of elements in the data array */ + int nPrefixReg /* No. of reg prior to regData available for use */ +){ + Vdbe *v = pParse->pVdbe; /* Stmt under construction */ + int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0); + int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ + int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ + int regBase; /* Regs for sorter record */ + int regRecord = ++pParse->nMem; /* Assembled sorter record */ + int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ + int op; /* Opcode to add sorter record to sorter */ + int iLimit; /* LIMIT counter */ + + assert( bSeq==0 || bSeq==1 ); + assert( nData==1 || regData==regOrigData || regOrigData==0 ); + if( nPrefixReg ){ + assert( nPrefixReg==nExpr+bSeq ); + regBase = regData - nExpr - bSeq; + }else{ + regBase = pParse->nMem + 1; + pParse->nMem += nBase; + } + assert( pSelect->iOffset==0 || pSelect->iLimit!=0 ); + iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; + pSort->labelDone = sqlite3VdbeMakeLabel(v); + sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, + SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0)); + if( bSeq ){ + sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); + } + if( nPrefixReg==0 && nData>0 ){ + sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord); + if( nOBSat>0 ){ + int regPrevKey; /* The first nOBSat columns of the previous row */ + int addrFirst; /* Address of the OP_IfNot opcode */ + int addrJmp; /* Address of the OP_Jump opcode */ + VdbeOp *pOp; /* Opcode that opens the sorter */ + int nKey; /* Number of sorting key columns, including OP_Sequence */ + KeyInfo *pKI; /* Original KeyInfo on the sorter table */ + + regPrevKey = pParse->nMem+1; + pParse->nMem += pSort->nOBSat; + nKey = nExpr - pSort->nOBSat + bSeq; + if( bSeq ){ + addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); + }else{ + addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor); + } + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat); + pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); + if( pParse->db->mallocFailed ) return; + pOp->p2 = nKey + nData; + pKI = pOp->p4.pKeyInfo; + memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ + sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); + testcase( pKI->nXField>2 ); + pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, + pKI->nXField-1); + addrJmp = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); + pSort->labelBkOut = sqlite3VdbeMakeLabel(v); + pSort->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); + if( iLimit ){ + sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone); + VdbeCoverage(v); + } + sqlite3VdbeJumpHere(v, addrFirst); + sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat); + sqlite3VdbeJumpHere(v, addrJmp); + } + if( pSort->sortFlags & SORTFLAG_UseSorter ){ + op = OP_SorterInsert; + }else{ + op = OP_IdxInsert; + } + sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, + regBase+nOBSat, nBase-nOBSat); + if( iLimit ){ + int addr; + int r1 = 0; + /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit + ** register is initialized with value of LIMIT+OFFSET.) After the sorter + ** fills up, delete the least entry in the sorter after each insert. + ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */ + addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + r1 = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1); + VdbeComment((v, "seq")); + } + sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + /* If the inner loop is driven by an index such that values from + ** the same iteration of the inner loop are in sorted order, then + ** immediately jump to the next iteration of an inner loop if the + ** entry from the current iteration does not fit into the top + ** LIMIT+OFFSET entries of the sorter. */ + int iBrk = sqlite3VdbeCurrentAddr(v) + 2; + sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + VdbeCoverage(v); + } + sqlite3VdbeJumpHere(v, addr); + } +} + +/* +** Add code to implement the OFFSET +*/ +static void codeOffset( + Vdbe *v, /* Generate code into this VM */ + int iOffset, /* Register holding the offset counter */ + int iContinue /* Jump here to skip the current record */ +){ + if( iOffset>0 ){ + sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v); + VdbeComment((v, "OFFSET")); + } +} + +/* +** Add code that will check to make sure the N registers starting at iMem +** form a distinct entry. iTab is a sorting index that holds previously +** seen combinations of the N values. A new entry is made in iTab +** if the current N values are new. +** +** A jump to addrRepeat is made and the N+1 values are popped from the +** stack if the top N elements are not distinct. +*/ +static void codeDistinct( + Parse *pParse, /* Parsing and code generating context */ + int iTab, /* A sorting index used to test for distinctness */ + int addrRepeat, /* Jump to here if not distinct */ + int N, /* Number of elements */ + int iMem /* First element */ +){ + Vdbe *v; + int r1; + + v = pParse->pVdbe; + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + sqlite3ReleaseTempReg(pParse, r1); +} + +/* +** This routine generates the code for the inside of the inner loop +** of a SELECT. +** +** If srcTab is negative, then the 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 +** 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 */ + 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 */ + int iContinue, /* Jump here to continue with next row */ + int iBreak /* Jump here to break out of the inner loop */ +){ + Vdbe *v = pParse->pVdbe; + int i; + int hasDistinct; /* True if the DISTINCT keyword is present */ + int eDest = pDest->eDest; /* How to dispose of results */ + int iParm = pDest->iSDParm; /* First argument to disposal method */ + int nResultCol; /* Number of result columns */ + int nPrefixReg = 0; /* Number of extra registers before regResult */ + + /* Usually, regResult is the first cell in an array of memory cells + ** containing the current result row. In this case regOrig is set to the + ** same value. However, if the results are being sent to the sorter, the + ** values for any expressions that are also part of the sort-key are omitted + ** from this array. In this case regOrig is set to zero. */ + int regResult; /* Start of memory holding current results */ + int regOrig; /* Start of memory holding full result (or 0) */ + + assert( v ); + assert( pEList!=0 ); + hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; + if( pSort && pSort->pOrderBy==0 ) pSort = 0; + if( pSort==0 && !hasDistinct ){ + assert( iContinue!=0 ); + codeOffset(v, p->iOffset, iContinue); + } + + /* Pull the requested columns. + */ + nResultCol = pEList->nExpr; + + if( pDest->iSdst==0 ){ + if( pSort ){ + nPrefixReg = pSort->pOrderBy->nExpr; + if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++; + pParse->nMem += nPrefixReg; + } + pDest->iSdst = pParse->nMem+1; + pParse->nMem += nResultCol; + }else if( pDest->iSdst+nResultCol > pParse->nMem ){ + /* This is an error condition that can result, for example, when a SELECT + ** on the right-hand side of an INSERT contains more result columns than + ** there are columns in the table on the left. The error will be caught + ** and reported later. But we need to make sure enough memory is allocated + ** to avoid other spurious errors in the meantime. */ + pParse->nMem += nResultCol; + } + pDest->nSdst = nResultCol; + regOrig = regResult = pDest->iSdst; + if( srcTab>=0 ){ + for(i=0; ia[i].zName)); + } + }else if( eDest!=SRT_Exists ){ + /* If the destination is an EXISTS(...) expression, the actual + ** values returned by the SELECT are not required. + */ + u8 ecelFlags; + if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){ + ecelFlags = SQLITE_ECEL_DUP; + }else{ + 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 + ** 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, + ** saving space and CPU cycles. */ + ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF); + for(i=pSort->nOBSat; ipOrderBy->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; + } + } + regOrig = 0; + assert( eDest==SRT_Set || eDest==SRT_Mem + || eDest==SRT_Coroutine || eDest==SRT_Output ); + } + nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags); + } + + /* If the DISTINCT keyword was present on the SELECT statement + ** and this row has been seen before, then do not make this row + ** part of the result. + */ + if( hasDistinct ){ + switch( pDistinct->eTnctType ){ + case WHERE_DISTINCT_ORDERED: { + VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ + int iJump; /* Jump destination */ + int regPrev; /* Previous row content */ + + /* Allocate space for the previous row */ + regPrev = pParse->nMem+1; + pParse->nMem += nResultCol; + + /* Change the OP_OpenEphemeral coded earlier to an OP_Null + ** sets the MEM_Cleared bit on the first register of the + ** previous value. This will cause the OP_Ne below to always + ** fail on the first iteration of the loop even if the first + ** row is all NULLs. + */ + sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); + pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct); + pOp->opcode = OP_Null; + pOp->p1 = 1; + pOp->p2 = regPrev; + + iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; + for(i=0; ia[i].pExpr); + if( idb->mallocFailed ); + sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1); + break; + } + + case WHERE_DISTINCT_UNIQUE: { + sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); + break; + } + + default: { + assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED ); + codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, + regResult); + break; + } + } + if( pSort==0 ){ + codeOffset(v, p->iOffset, iContinue); + } + } + + switch( eDest ){ + /* In this mode, write each query result to the key of the temporary + ** table iParm. + */ +#ifndef SQLITE_OMIT_COMPOUND_SELECT + case SRT_Union: { + int r1; + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); + sqlite3ReleaseTempReg(pParse, r1); + break; + } + + /* Construct a record from the query result, but instead of + ** saving that record, use it as a key to delete elements from + ** the temporary table iParm. + */ + case SRT_Except: { + sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol); + break; + } +#endif /* SQLITE_OMIT_COMPOUND_SELECT */ + + /* Store the result as data using a unique key. + */ + case SRT_Fifo: + case SRT_DistFifo: + case SRT_Table: + case SRT_EphemTab: { + int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1); + testcase( eDest==SRT_Table ); + testcase( eDest==SRT_EphemTab ); + testcase( eDest==SRT_Fifo ); + testcase( eDest==SRT_DistFifo ); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg); +#ifndef SQLITE_OMIT_CTE + if( eDest==SRT_DistFifo ){ + /* If the destination is DistFifo, then cursor (iParm+1) is open + ** on an ephemeral index. If the current row is already present + ** in the index, do not write it to the output. If not, add the + ** current row to the index and proceed with writing it to the + ** output table as well. */ + int addr = sqlite3VdbeCurrentAddr(v) + 4; + sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); + VdbeCoverage(v); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol); + assert( pSort==0 ); + } +#endif + if( pSort ){ + pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg); + }else{ + int r2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); + sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + sqlite3ReleaseTempReg(pParse, r2); + } + sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1); + break; + } + +#ifndef SQLITE_OMIT_SUBQUERY + /* If we are creating a set for an "expr IN (SELECT ...)" construct, + ** then there should be a single item on the stack. Write this + ** item into the set table with bogus data. + */ + case SRT_Set: { + if( pSort ){ + /* At first glance you would think we could optimize out the + ** ORDER BY in this case since the order of entries in the set + ** does not matter. But there might be a LIMIT clause, in which + ** case the order does matter */ + pushOntoSorter( + pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); + }else{ + int r1 = sqlite3GetTempReg(pParse); + assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, + r1, pDest->zAffSdst, nResultCol); + sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); + sqlite3ReleaseTempReg(pParse, r1); + } + break; + } + + /* If any row exist in the result set, record that fact and abort. + */ + case SRT_Exists: { + sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm); + /* The LIMIT clause will terminate the loop for us */ + break; + } + + /* If this is a scalar select that is part of an expression, then + ** store the results in the appropriate memory cell or array of + ** memory cells and break out of the scan loop. + */ + case SRT_Mem: { + if( pSort ){ + assert( nResultCol<=pDest->nSdst ); + pushOntoSorter( + pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); + }else{ + assert( nResultCol==pDest->nSdst ); + assert( regResult==iParm ); + /* The LIMIT clause will jump out of the loop for us */ + } + break; + } +#endif /* #ifndef SQLITE_OMIT_SUBQUERY */ + + case SRT_Coroutine: /* Send data to a co-routine */ + case SRT_Output: { /* Return the results */ + testcase( eDest==SRT_Coroutine ); + testcase( eDest==SRT_Output ); + if( pSort ){ + pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol, + nPrefixReg); + }else if( eDest==SRT_Coroutine ){ + sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); + }else{ + sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); + sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); + } + break; + } + +#ifndef SQLITE_OMIT_CTE + /* Write the results into a priority queue that is order according to + ** pDest->pOrderBy (in pSO). pDest->iSDParm (in iParm) is the cursor for an + ** index with pSO->nExpr+2 columns. Build a key using pSO for the first + ** pSO->nExpr columns, then make sure all keys are unique by adding a + ** final OP_Sequence column. The last column is the record as a blob. + */ + case SRT_DistQueue: + case SRT_Queue: { + int nKey; + int r1, r2, r3; + int addrTest = 0; + ExprList *pSO; + pSO = pDest->pOrderBy; + assert( pSO ); + nKey = pSO->nExpr; + r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3GetTempRange(pParse, nKey+2); + r3 = r2+nKey+1; + if( eDest==SRT_DistQueue ){ + /* If the destination is DistQueue, then cursor (iParm+1) is open + ** on a second ephemeral index that holds all values every previously + ** added to the queue. */ + addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, + regResult, nResultCol); + VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r3); + if( eDest==SRT_DistQueue ){ + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + } + for(i=0; ia[i].u.x.iOrderByCol - 1, + r2+i); + } + sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey); + sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2); + if( addrTest ) sqlite3VdbeJumpHere(v, addrTest); + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempRange(pParse, r2, nKey+2); + break; + } +#endif /* SQLITE_OMIT_CTE */ + + + +#if !defined(SQLITE_OMIT_TRIGGER) + /* Discard the results. This is used for SELECT statements inside + ** the body of a TRIGGER. The purpose of such selects is to call + ** user-defined functions that have side effects. We do not care + ** about the actual results of the select. + */ + default: { + assert( eDest==SRT_Discard ); + break; + } +#endif + } + + /* Jump to the end of the loop if the LIMIT is reached. Except, if + ** there is a sorter, in which case the sorter has already limited + ** the output for us. + */ + if( pSort==0 && p->iLimit ){ + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); + } +} + +/* +** Allocate a KeyInfo object sufficient for an index of N key columns and +** X extra columns. +*/ +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ + int nExtra = (N+X)*(sizeof(CollSeq*)+1); + 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->enc = ENC(db); + p->db = db; + p->nRef = 1; + memset(&p[1], 0, nExtra); + }else{ + sqlite3OomFault(db); + } + return p; +} + +/* +** Deallocate a KeyInfo object +*/ +SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){ + if( p ){ + assert( p->nRef>0 ); + p->nRef--; + if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p); + } +} + +/* +** Make a new pointer to a KeyInfo object +*/ +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){ + if( p ){ + assert( p->nRef>0 ); + p->nRef++; + } + return p; +} + +#ifdef SQLITE_DEBUG +/* +** Return TRUE if a KeyInfo object can be change. The KeyInfo object +** can only be changed if this is just a single reference to the object. +** +** This routine is used only inside of assert() statements. +*/ +SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } +#endif /* SQLITE_DEBUG */ + +/* +** Given an expression list, generate a KeyInfo structure that records +** the collating sequence for each expression in that expression list. +** +** If the ExprList is an ORDER BY or GROUP BY clause then the resulting +** KeyInfo structure is appropriate for initializing a virtual index to +** implement that clause. If the ExprList is the result set of a SELECT +** then the KeyInfo structure is appropriate for initializing a virtual +** index to implement a DISTINCT test. +** +** Space to hold the KeyInfo structure is obtained from malloc. The calling +** function is responsible for seeing that this structure is eventually +** freed. +*/ +static KeyInfo *keyInfoFromExprList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Form the KeyInfo object from this ExprList */ + int iStart, /* Begin with this column of pList */ + int nExtra /* Add this many extra columns to the end */ +){ + int nExpr; + KeyInfo *pInfo; + struct ExprList_item *pItem; + sqlite3 *db = pParse->db; + int i; + + nExpr = pList->nExpr; + pInfo = sqlite3KeyInfoAlloc(db, nExpr-iStart, nExtra+1); + if( pInfo ){ + assert( sqlite3KeyInfoIsWriteable(pInfo) ); + for(i=iStart, pItem=pList->a+iStart; ipExpr); + if( !pColl ) pColl = db->pDfltColl; + pInfo->aColl[i-iStart] = pColl; + pInfo->aSortOrder[i-iStart] = pItem->sortOrder; + } + } + return pInfo; +} + +/* +** Name of the connection operator, used for error messages. +*/ +static const char *selectOpName(int id){ + char *z; + switch( id ){ + case TK_ALL: z = "UNION ALL"; break; + case TK_INTERSECT: z = "INTERSECT"; break; + case TK_EXCEPT: z = "EXCEPT"; break; + default: z = "UNION"; break; + } + return z; +} + +#ifndef SQLITE_OMIT_EXPLAIN +/* +** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function +** is a no-op. Otherwise, it adds a single row of output to the EQP result, +** where the caption is of the form: +** +** "USE TEMP B-TREE FOR xxx" +** +** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which +** is determined by the zUsage argument. +*/ +static void explainTempTable(Parse *pParse, const char *zUsage){ + if( pParse->explain==2 ){ + Vdbe *v = pParse->pVdbe; + char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage); + sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); + } +} + +/* +** Assign expression b to lvalue a. A second, no-op, version of this macro +** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code +** in sqlite3Select() to assign values to structure member variables that +** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the +** code with #ifndef directives. +*/ +# define explainSetInteger(a, b) a = b + +#else +/* No-op versions of the explainXXX() functions and macros. */ +# define explainTempTable(y,z) +# define explainSetInteger(y,z) +#endif + +#if !defined(SQLITE_OMIT_EXPLAIN) && !defined(SQLITE_OMIT_COMPOUND_SELECT) +/* +** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function +** is a no-op. Otherwise, it adds a single row of output to the EQP result, +** where the caption is of one of the two forms: +** +** "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)" +** "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)" +** +** where iSub1 and iSub2 are the integers passed as the corresponding +** function parameters, and op is the text representation of the parameter +** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT, +** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is +** false, or the second form if it is true. +*/ +static void explainComposite( + Parse *pParse, /* Parse context */ + int op, /* One of TK_UNION, TK_EXCEPT etc. */ + int iSub1, /* Subquery id 1 */ + int iSub2, /* Subquery id 2 */ + int bUseTmp /* True if a temp table was used */ +){ + assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL ); + if( pParse->explain==2 ){ + Vdbe *v = pParse->pVdbe; + char *zMsg = sqlite3MPrintf( + pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2, + bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op) + ); + sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); + } +} +#else +/* No-op versions of the explainXXX() functions and macros. */ +# define explainComposite(v,w,x,y,z) +#endif + +/* +** If the inner loop was generated using a non-null pOrderBy argument, +** then the results were placed in a sorter. After the loop is terminated +** we need to run the sorter and output the results. The following +** routine generates the code needed to do that. +*/ +static void generateSortTail( + Parse *pParse, /* Parsing context */ + Select *p, /* The SELECT statement */ + SortCtx *pSort, /* Information on the ORDER BY clause */ + int nColumn, /* Number of columns of data */ + SelectDest *pDest /* Write the sorted results here */ +){ + Vdbe *v = pParse->pVdbe; /* The prepared statement */ + int addrBreak = pSort->labelDone; /* Jump here to exit loop */ + int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ + int addr; + int addrOnce = 0; + int iTab; + ExprList *pOrderBy = pSort->pOrderBy; + int eDest = pDest->eDest; + int iParm = pDest->iSDParm; + int regRow; + int regRowid; + int iCol; + int nKey; + int iSortTab; /* Sorter cursor to read from */ + int nSortData; /* Trailing values to read from sorter */ + int i; + int bSeq; /* True if sorter record includes seq. no. */ + struct ExprList_item *aOutEx = p->pEList->a; + + assert( addrBreak<0 ); + if( pSort->labelBkOut ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); + sqlite3VdbeGoto(v, addrBreak); + sqlite3VdbeResolveLabel(v, pSort->labelBkOut); + } + iTab = pSort->iECursor; + if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){ + regRowid = 0; + regRow = pDest->iSdst; + nSortData = nColumn; + }else{ + regRowid = sqlite3GetTempReg(pParse); + regRow = sqlite3GetTempRange(pParse, nColumn); + nSortData = nColumn; + } + nKey = pOrderBy->nExpr - pSort->nOBSat; + if( pSort->sortFlags & SORTFLAG_UseSorter ){ + int regSortOut = ++pParse->nMem; + iSortTab = pParse->nTab++; + if( pSort->labelBkOut ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); + addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); + VdbeCoverage(v); + codeOffset(v, p->iOffset, addrContinue); + sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); + bSeq = 0; + }else{ + addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); + codeOffset(v, p->iOffset, addrContinue); + iSortTab = iTab; + bSeq = 1; + } + for(i=0, iCol=nKey+bSeq; izAffSdst) ); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, + pDest->zAffSdst, nColumn); + sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn); + break; + } + case SRT_Mem: { + /* The LIMIT clause will terminate the loop for us */ + break; + } +#endif + default: { + assert( eDest==SRT_Output || eDest==SRT_Coroutine ); + testcase( eDest==SRT_Output ); + testcase( eDest==SRT_Coroutine ); + if( eDest==SRT_Output ){ + sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); + sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn); + }else{ + sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); + } + break; + } + } + if( regRowid ){ + if( eDest==SRT_Set ){ + sqlite3ReleaseTempRange(pParse, regRow, nColumn); + }else{ + sqlite3ReleaseTempReg(pParse, regRow); + } + sqlite3ReleaseTempReg(pParse, regRowid); + } + /* The bottom of the loop + */ + sqlite3VdbeResolveLabel(v, addrContinue); + if( pSort->sortFlags & SORTFLAG_UseSorter ){ + sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v); + }else{ + sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); + } + if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn); + sqlite3VdbeResolveLabel(v, addrBreak); +} + +/* +** Return a pointer to a string containing the 'declaration type' of the +** expression pExpr. The string may be treated as static by the caller. +** +** Also try to estimate the size of the returned value and return that +** result in *pEstWidth. +** +** The declaration type is the exact datatype definition extracted from the +** original CREATE TABLE statement if the expression is a column. The +** declaration type for a ROWID field is INTEGER. Exactly when an expression +** is considered a column can be complex in the presence of subqueries. The +** result-set expression in all of the following SELECT statements is +** considered a column by this function. +** +** SELECT col FROM tbl; +** SELECT (SELECT col FROM tbl; +** SELECT (SELECT col FROM tbl); +** SELECT abc FROM (SELECT col AS abc FROM tbl); +** +** The declaration type for any expression other than a column is NULL. +** +** This routine has either 3 or 6 parameters depending on whether or not +** 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) +#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ +# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F) +#endif +static const char *columnTypeImpl( + NameContext *pNC, + Expr *pExpr, +#ifdef SQLITE_ENABLE_COLUMN_METADATA + const char **pzOrigDb, + const char **pzOrigTab, + 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; + char const *zOrigCol = 0; +#endif + + assert( pExpr!=0 ); + assert( pNC->pSrcList!=0 ); + switch( pExpr->op ){ + case TK_AGG_COLUMN: + case TK_COLUMN: { + /* The expression is a column. Locate the table the column is being + ** extracted from in NameContext.pSrcList. This table may be real + ** database table or a subquery. + */ + Table *pTab = 0; /* Table structure column is extracted from */ + Select *pS = 0; /* Select the column is extracted from */ + int iCol = pExpr->iColumn; /* Index of column in pTab */ + testcase( pExpr->op==TK_AGG_COLUMN ); + testcase( pExpr->op==TK_COLUMN ); + while( pNC && !pTab ){ + SrcList *pTabList = pNC->pSrcList; + for(j=0;jnSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); + if( jnSrc ){ + pTab = pTabList->a[j].pTab; + pS = pTabList->a[j].pSelect; + }else{ + pNC = pNC->pNext; + } + } + + if( pTab==0 ){ + /* At one time, code such as "SELECT new.x" within a trigger would + ** cause this condition to run. Since then, we have restructured how + ** trigger code is generated and so this condition is no longer + ** possible. However, it can still be true for statements like + ** the following: + ** + ** CREATE TABLE t1(col INTEGER); + ** SELECT (SELECT t1.col) FROM FROM t1; + ** + ** when columnType() is called on the expression "t1.col" in the + ** sub-select. In this case, set the column type to NULL, even + ** though it should really be "INTEGER". + ** + ** This is not a problem, as the column type of "t1.col" is never + ** used. When columnType() is called on the expression + ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT + ** branch below. */ + break; + } + + assert( pTab && pExpr->pTab==pTab ); + if( pS ){ + /* The "table" is actually a sub-select or a view in the FROM clause + ** of the SELECT statement. Return the declaration type and origin + ** data for the result-set column of the sub-select. + */ + if( iCol>=0 && ALWAYS(iColpEList->nExpr) ){ + /* If iCol is less than zero, then the expression requests the + ** rowid of the sub-select or view. This expression is legal (see + ** test case misc2.2.2) - it always evaluates to NULL. + ** + ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been + ** caught already by name resolution. + */ + NameContext sNC; + Expr *p = pS->pEList->a[iCol].pExpr; + sNC.pSrcList = pS->pSrc; + sNC.pNext = pNC; + sNC.pParse = pNC->pParse; + zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth); + } + }else if( pTab->pSchema ){ + /* A real table */ + assert( !pS ); + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==-1 || (iCol>=0 && iColnCol) ); +#ifdef SQLITE_ENABLE_COLUMN_METADATA + 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 ){ + int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); + zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; + } +#else + if( iCol<0 ){ + zType = "INTEGER"; + }else{ + zType = sqlite3ColumnType(&pTab->aCol[iCol],0); + estWidth = pTab->aCol[iCol].szEst; + } +#endif + } + break; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_SELECT: { + /* The expression is a sub-select. Return the declaration type and + ** origin info for the single column in the result set of the SELECT + ** statement. + */ + NameContext sNC; + Select *pS = pExpr->x.pSelect; + Expr *p = pS->pEList->a[0].pExpr; + assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + sNC.pSrcList = pS->pSrc; + sNC.pNext = pNC; + sNC.pParse = pNC->pParse; + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth); + break; + } +#endif + } + +#ifdef SQLITE_ENABLE_COLUMN_METADATA + if( pzOrigDb ){ + assert( pzOrigTab && pzOrigCol ); + *pzOrigDb = zOrigDb; + *pzOrigTab = zOrigTab; + *pzOrigCol = zOrigCol; + } +#endif + if( pEstWidth ) *pEstWidth = estWidth; + return zType; +} + +/* +** Generate code that will tell the VDBE the declaration types of columns +** in the result set. +*/ +static void generateColumnTypes( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +){ +#ifndef SQLITE_OMIT_DECLTYPE + Vdbe *v = pParse->pVdbe; + int i; + NameContext sNC; + sNC.pSrcList = pTabList; + sNC.pParse = pParse; + sNC.pNext = 0; + for(i=0; inExpr; i++){ + Expr *p = pEList->a[i].pExpr; + const char *zType; +#ifdef SQLITE_ENABLE_COLUMN_METADATA + const char *zOrigDb = 0; + const char *zOrigTab = 0; + const char *zOrigCol = 0; + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0); + + /* The vdbe must make its own copy of the column-type and other + ** column specific strings, in case the schema is reset before this + ** virtual machine is deleted. + */ + sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT); + 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); +#endif + sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT); + } +#endif /* !defined(SQLITE_OMIT_DECLTYPE) */ +} + +/* +** Return the Table objecct in the SrcList that has cursor iCursor. +** Or return NULL if no such Table object exists in the SrcList. +*/ +static Table *tableWithCursor(SrcList *pList, int iCursor){ + int j; + for(j=0; jnSrc; j++){ + if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab; + } + return 0; +} + + +/* +** Generate code that will tell the VDBE the names of columns +** in the result set. This information is used to provide the +** azCol[] values in the callback. +*/ +static void generateColumnNames( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +){ + Vdbe *v = pParse->pVdbe; + int i; + Table *pTab; + sqlite3 *db = pParse->db; + int fullNames, shortNames; + +#ifndef SQLITE_OMIT_EXPLAIN + /* If this is an EXPLAIN, skip this step */ + if( pParse->explain ){ + return; + } +#endif + + if( pParse->colNamesSet || db->mallocFailed ) return; + assert( v!=0 ); + assert( pTabList!=0 ); + pParse->colNamesSet = 1; + fullNames = (db->flags & SQLITE_FullColNames)!=0; + shortNames = (db->flags & SQLITE_ShortColNames)!=0; + sqlite3VdbeSetNumCols(v, pEList->nExpr); + for(i=0; inExpr; i++){ + Expr *p; + p = pEList->a[i].pExpr; + if( NEVER(p==0) ) continue; + if( pEList->a[i].zName ){ + char *zName = pEList->a[i].zName; + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); + }else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) + && (pTab = tableWithCursor(pTabList, p->iTable))!=0 + ){ + char *zCol; + int iCol = p->iColumn; + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==-1 || (iCol>=0 && iColnCol) ); + if( iCol<0 ){ + zCol = "rowid"; + }else{ + zCol = pTab->aCol[iCol].zName; + } + if( !shortNames && !fullNames ){ + sqlite3VdbeSetColName(v, i, COLNAME_NAME, + sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC); + }else if( fullNames ){ + char *zName = 0; + zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC); + }else{ + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT); + } + }else{ + const char *z = pEList->a[i].zSpan; + z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC); + } + } + generateColumnTypes(pParse, pTabList, pEList); +} + +/* +** Given an expression list (which is really the list of expressions +** that form the result set of a SELECT statement) compute appropriate +** column names for a table that would hold the expression list. +** +** All column names will be unique. +** +** Only the column names are computed. Column.zType, Column.zColl, +** and other fields of Column are zeroed. +** +** Return SQLITE_OK on success. If a memory allocation error occurs, +** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM. +*/ +SQLITE_PRIVATE int sqlite3ColumnsFromExprList( + Parse *pParse, /* Parsing context */ + ExprList *pEList, /* Expr list from which to derive column names */ + i16 *pnCol, /* Write the number of columns here */ + Column **paCol /* Write the new column list here */ +){ + sqlite3 *db = pParse->db; /* Database connection */ + int i, j; /* Loop counters */ + u32 cnt; /* Index added to make the name unique */ + Column *aCol, *pCol; /* For looping over result columns */ + int nCol; /* Number of columns in the result set */ + Expr *p; /* Expression for a single result column */ + char *zName; /* Column name */ + int nName; /* Size of name in zName[] */ + Hash ht; /* Hash table of column names */ + + sqlite3HashInit(&ht); + if( pEList ){ + nCol = pEList->nExpr; + aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); + testcase( aCol==0 ); + }else{ + nCol = 0; + aCol = 0; + } + assert( nCol==(i16)nCol ); + *pnCol = nCol; + *paCol = aCol; + + for(i=0, pCol=aCol; imallocFailed; i++, pCol++){ + /* Get an appropriate name for the column + */ + p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); + if( (zName = pEList->a[i].zName)!=0 ){ + /* If the column contains an "AS " phrase, use as the name */ + }else{ + Expr *pColExpr = p; /* The expression that is the result column name */ + Table *pTab; /* Table associated with this expression */ + while( pColExpr->op==TK_DOT ){ + pColExpr = pColExpr->pRight; + assert( pColExpr!=0 ); + } + if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){ + /* For columns use the column name name */ + int iCol = pColExpr->iColumn; + pTab = pColExpr->pTab; + if( iCol<0 ) iCol = pTab->iPKey; + zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; + }else if( pColExpr->op==TK_ID ){ + assert( !ExprHasProperty(pColExpr, EP_IntValue) ); + zName = pColExpr->u.zToken; + }else{ + /* Use the original text of the column expression as its name */ + zName = pEList->a[i].zSpan; + } + } + zName = sqlite3MPrintf(db, "%s", zName); + + /* Make sure the column name is unique. If the name is not unique, + ** append an integer to the name so that it becomes unique. + */ + cnt = 0; + while( zName && sqlite3HashFind(&ht, zName)!=0 ){ + nName = sqlite3Strlen30(zName); + if( nName>0 ){ + for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){} + if( zName[j]==':' ) nName = j; + } + zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt); + if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt); + } + pCol->zName = zName; + sqlite3ColumnPropertiesFromName(0, pCol); + if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){ + sqlite3OomFault(db); + } + } + sqlite3HashClear(&ht); + if( db->mallocFailed ){ + for(j=0; jdb; + NameContext sNC; + Column *pCol; + CollSeq *pColl; + int i; + Expr *p; + struct ExprList_item *a; + u64 szAll = 0; + + assert( pSelect!=0 ); + assert( (pSelect->selFlags & SF_Resolved)!=0 ); + assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed ); + if( db->mallocFailed ) return; + memset(&sNC, 0, sizeof(sNC)); + sNC.pSrcList = pSelect->pSrc; + a = pSelect->pEList->a; + for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ + const char *zType; + int n, m; + p = a[i].pExpr; + zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst); + szAll += pCol->szEst; + pCol->affinity = sqlite3ExprAffinity(p); + if( zType && (m = sqlite3Strlen30(zType))>0 ){ + n = sqlite3Strlen30(pCol->zName); + pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2); + if( pCol->zName ){ + memcpy(&pCol->zName[n+1], zType, m+1); + pCol->colFlags |= COLFLAG_HASTYPE; + } + } + if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB; + pColl = sqlite3ExprCollSeq(pParse, p); + if( pColl && pCol->zColl==0 ){ + pCol->zColl = sqlite3DbStrDup(db, pColl->zName); + } + } + pTab->szTabRow = sqlite3LogEst(szAll*4); +} + +/* +** Given a SELECT statement, generate a Table structure that describes +** the result set of that SELECT. +*/ +SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ + Table *pTab; + sqlite3 *db = pParse->db; + int savedFlags; + + savedFlags = db->flags; + db->flags &= ~SQLITE_FullColNames; + db->flags |= SQLITE_ShortColNames; + sqlite3SelectPrep(pParse, pSelect, 0); + if( pParse->nErr ) return 0; + while( pSelect->pPrior ) pSelect = pSelect->pPrior; + db->flags = savedFlags; + pTab = sqlite3DbMallocZero(db, sizeof(Table) ); + if( pTab==0 ){ + return 0; + } + /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside + ** is disabled */ + assert( db->lookaside.bDisable ); + pTab->nTabRef = 1; + pTab->zName = 0; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect); + pTab->iPKey = -1; + if( db->mallocFailed ){ + sqlite3DeleteTable(db, pTab); + return 0; + } + return pTab; +} + +/* +** 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); + 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); +} + + +/* +** Compute the iLimit and iOffset fields of the SELECT based on the +** pLimit and pOffset expressions. pLimit and pOffset hold the expressions +** that appear in the original SQL statement after the LIMIT and OFFSET +** keywords. Or NULL if those keywords are omitted. iLimit and iOffset +** are the integer memory register numbers for counters used to compute +** the limit and offset. If there is no limit and/or offset, then +** iLimit and iOffset are negative. +** +** This routine changes the values of iLimit and iOffset only if +** a limit or offset is defined by pLimit and pOffset. iLimit and +** iOffset should have been preset to appropriate default values (zero) +** prior to calling this routine. +** +** The iOffset register (if it exists) is initialized to the value +** of the OFFSET. The iLimit register is initialized to LIMIT. Register +** iOffset+1 is initialized to LIMIT+OFFSET. +** +** Only if pLimit!=0 or pOffset!=0 do the limit registers get +** redefined. The UNION ALL operator uses this property to force +** the reuse of the same limit and offset registers across multiple +** SELECT statements. +*/ +static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ + Vdbe *v = 0; + int iLimit = 0; + int iOffset; + int n; + if( p->iLimit ) return; + + /* + ** "LIMIT -1" always shows all rows. There is some + ** controversy about what the correct behavior should be. + ** The current implementation interprets "LIMIT 0" to mean + ** no rows. + */ + sqlite3ExprCacheClear(pParse); + assert( p->pOffset==0 || p->pLimit!=0 ); + if( p->pLimit ){ + p->iLimit = iLimit = ++pParse->nMem; + v = sqlite3GetVdbe(pParse); + assert( v!=0 ); + if( sqlite3ExprIsInteger(p->pLimit, &n) ){ + sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit); + VdbeComment((v, "LIMIT counter")); + if( n==0 ){ + sqlite3VdbeGoto(v, iBreak); + }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){ + p->nSelectRow = sqlite3LogEst((u64)n); + p->selFlags |= SF_FixedLimit; + } + }else{ + sqlite3ExprCode(pParse, p->pLimit, iLimit); + sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); + VdbeComment((v, "LIMIT counter")); + sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); + } + if( p->pOffset ){ + p->iOffset = iOffset = ++pParse->nMem; + pParse->nMem++; /* Allocate an extra register for limit+offset */ + sqlite3ExprCode(pParse, p->pOffset, iOffset); + sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); + VdbeComment((v, "OFFSET counter")); + sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset); + VdbeComment((v, "LIMIT+OFFSET")); + } + } +} + +#ifndef SQLITE_OMIT_COMPOUND_SELECT +/* +** Return the appropriate collating sequence for the iCol-th column of +** the result set for the compound-select statement "p". Return NULL if +** the column has no default collating sequence. +** +** The collating sequence for the compound select is taken from the +** left-most term of the select that has a collating sequence. +*/ +static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ + CollSeq *pRet; + if( p->pPrior ){ + pRet = multiSelectCollSeq(pParse, p->pPrior, iCol); + }else{ + pRet = 0; + } + assert( iCol>=0 ); + /* iCol must be less than p->pEList->nExpr. Otherwise an error would + ** have been thrown during name resolution and we would not have gotten + ** this far */ + if( pRet==0 && ALWAYS(iColpEList->nExpr) ){ + pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr); + } + return pRet; +} + +/* +** The select statement passed as the second parameter is a compound SELECT +** with an ORDER BY clause. This function allocates and returns a KeyInfo +** structure suitable for implementing the ORDER BY. +** +** Space to hold the KeyInfo structure is obtained from malloc. The calling +** function is responsible for ensuring that this structure is eventually +** freed. +*/ +static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ + ExprList *pOrderBy = p->pOrderBy; + int nOrderBy = p->pOrderBy->nExpr; + sqlite3 *db = pParse->db; + KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1); + if( pRet ){ + int i; + for(i=0; ia[i]; + Expr *pTerm = pItem->pExpr; + CollSeq *pColl; + + if( pTerm->flags & EP_Collate ){ + pColl = sqlite3ExprCollSeq(pParse, pTerm); + }else{ + pColl = multiSelectCollSeq(pParse, p, pItem->u.x.iOrderByCol-1); + if( pColl==0 ) pColl = db->pDfltColl; + pOrderBy->a[i].pExpr = + sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName); + } + assert( sqlite3KeyInfoIsWriteable(pRet) ); + pRet->aColl[i] = pColl; + pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder; + } + } + + return pRet; +} + +#ifndef SQLITE_OMIT_CTE +/* +** This routine generates VDBE code to compute the content of a WITH RECURSIVE +** query of the form: +** +** AS ( UNION [ALL] ) +** \___________/ \_______________/ +** p->pPrior p +** +** +** There is exactly one reference to the recursive-table in the FROM clause +** of recursive-query, marked with the SrcList->a[].fg.isRecursive flag. +** +** The setup-query runs once to generate an initial set of rows that go +** into a Queue table. Rows are extracted from the Queue table one by +** one. Each row extracted from Queue is output to pDest. Then the single +** extracted row (now in the iCurrent table) becomes the content of the +** recursive-table for a recursive-query run. The output of the recursive-query +** is added back into the Queue table. Then another row is extracted from Queue +** and the iteration continues until the Queue table is empty. +** +** If the compound query operator is UNION then no duplicate rows are ever +** inserted into the Queue table. The iDistinct table keeps a copy of all rows +** that have ever been inserted into Queue and causes duplicates to be +** discarded. If the operator is UNION ALL, then duplicates are allowed. +** +** If the query has an ORDER BY, then entries in the Queue table are kept in +** ORDER BY order and the first entry is extracted for each cycle. Without +** an ORDER BY, the Queue table is just a FIFO. +** +** If a LIMIT clause is provided, then the iteration stops after LIMIT rows +** have been output to pDest. A LIMIT of zero means to output no rows and a +** negative LIMIT means to output all rows. If there is also an OFFSET clause +** with a positive value, then the first OFFSET outputs are discarded rather +** than being sent to pDest. The LIMIT count does not begin until after OFFSET +** rows have been skipped. +*/ +static void generateWithRecursiveQuery( + Parse *pParse, /* Parsing context */ + Select *p, /* The recursive SELECT to be coded */ + SelectDest *pDest /* What to do with query results */ +){ + SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */ + int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */ + Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ + Select *pSetup = p->pPrior; /* The setup query */ + int addrTop; /* Top of the loop */ + int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ + int iCurrent = 0; /* The Current table */ + int regCurrent; /* Register holding Current table */ + int iQueue; /* The Queue table */ + int iDistinct = 0; /* To ensure unique results if UNION */ + int eDest = SRT_Fifo; /* How to write to Queue */ + SelectDest destQueue; /* SelectDest targetting the Queue table */ + int i; /* Loop counter */ + int rc; /* Result code */ + ExprList *pOrderBy; /* The ORDER BY clause */ + Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */ + int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ + + /* Obtain authorization to do a recursive query */ + if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; + + /* Process the LIMIT and OFFSET clauses, if they exist */ + addrBreak = sqlite3VdbeMakeLabel(v); + p->nSelectRow = 320; /* 4 billion rows */ + computeLimitRegisters(pParse, p, addrBreak); + pLimit = p->pLimit; + pOffset = p->pOffset; + regLimit = p->iLimit; + regOffset = p->iOffset; + p->pLimit = p->pOffset = 0; + p->iLimit = p->iOffset = 0; + pOrderBy = p->pOrderBy; + + /* Locate the cursor number of the Current table */ + for(i=0; ALWAYS(inSrc); i++){ + if( pSrc->a[i].fg.isRecursive ){ + iCurrent = pSrc->a[i].iCursor; + break; + } + } + + /* Allocate cursors numbers for Queue and Distinct. The cursor number for + ** the Distinct table must be exactly one greater than Queue in order + ** for the SRT_DistFifo and SRT_DistQueue destinations to work. */ + iQueue = pParse->nTab++; + if( p->op==TK_UNION ){ + eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo; + iDistinct = pParse->nTab++; + }else{ + eDest = pOrderBy ? SRT_Queue : SRT_Fifo; + } + sqlite3SelectDestInit(&destQueue, eDest, iQueue); + + /* Allocate cursors for Current, Queue, and Distinct. */ + regCurrent = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol); + if( pOrderBy ){ + KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1); + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue, pOrderBy->nExpr+2, 0, + (char*)pKeyInfo, P4_KEYINFO); + destQueue.pOrderBy = pOrderBy; + }else{ + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iQueue, nCol); + } + VdbeComment((v, "Queue table")); + if( iDistinct ){ + p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0); + p->selFlags |= SF_UsesEphemeral; + } + + /* Detach the ORDER BY clause from the compound SELECT */ + p->pOrderBy = 0; + + /* Store the results of the setup-query in Queue. */ + pSetup->pNext = 0; + rc = sqlite3Select(pParse, pSetup, &destQueue); + pSetup->pNext = p; + if( rc ) goto end_of_recursive_query; + + /* Find the next row in the Queue and output that row */ + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v); + + /* Transfer the next row in Queue over to Current */ + sqlite3VdbeAddOp1(v, OP_NullRow, iCurrent); /* To reset column cache */ + if( pOrderBy ){ + sqlite3VdbeAddOp3(v, OP_Column, iQueue, pOrderBy->nExpr+1, regCurrent); + }else{ + sqlite3VdbeAddOp2(v, OP_RowData, iQueue, regCurrent); + } + sqlite3VdbeAddOp1(v, OP_Delete, iQueue); + + /* Output the single row in Current */ + addrCont = sqlite3VdbeMakeLabel(v); + codeOffset(v, regOffset, addrCont); + selectInnerLoop(pParse, p, p->pEList, iCurrent, + 0, 0, pDest, addrCont, addrBreak); + if( regLimit ){ + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); + VdbeCoverage(v); + } + sqlite3VdbeResolveLabel(v, addrCont); + + /* Execute the recursive SELECT taking the single row in Current as + ** the value for the recursive-table. Store the results in the Queue. + */ + if( p->selFlags & SF_Aggregate ){ + sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); + }else{ + p->pPrior = 0; + sqlite3Select(pParse, p, &destQueue); + assert( p->pPrior==0 ); + p->pPrior = pSetup; + } + + /* Keep running the loop until the Queue is empty */ + sqlite3VdbeGoto(v, addrTop); + sqlite3VdbeResolveLabel(v, addrBreak); + +end_of_recursive_query: + sqlite3ExprListDelete(pParse->db, p->pOrderBy); + p->pOrderBy = pOrderBy; + p->pLimit = pLimit; + p->pOffset = pOffset; + return; +} +#endif /* SQLITE_OMIT_CTE */ + +/* Forward references */ +static int multiSelectOrderBy( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest /* What to do with query results */ +); + +/* +** Handle the special case of a compound-select that originates from a +** VALUES clause. By handling this as a special case, we avoid deep +** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT +** on a VALUES clause. +** +** Because the Select object originates from a VALUES clause: +** (1) It has no LIMIT or OFFSET +** (2) All terms are UNION ALL +** (3) There is no ORDER BY clause +*/ +static int multiSelectValues( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest /* What to do with query results */ +){ + Select *pPrior; + int nRow = 1; + int rc = 0; + assert( p->selFlags & SF_MultiValue ); + do{ + assert( p->selFlags & SF_Values ); + assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); + assert( p->pLimit==0 ); + assert( p->pOffset==0 ); + assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); + if( p->pPrior==0 ) break; + assert( p->pPrior->pNext==p ); + p = p->pPrior; + nRow++; + }while(1); + while( p ){ + pPrior = p->pPrior; + p->pPrior = 0; + rc = sqlite3Select(pParse, p, pDest); + p->pPrior = pPrior; + if( rc ) break; + p->nSelectRow = nRow; + p = p->pNext; + } + return rc; +} + +/* +** This routine is called to process a compound query form from +** two or more separate queries using UNION, UNION ALL, EXCEPT, or +** INTERSECT +** +** "p" points to the right-most of the two queries. the query on the +** left is p->pPrior. The left query could also be a compound query +** in which case this routine will be called recursively. +** +** The results of the total query are to be written into a destination +** of type eDest with parameter iParm. +** +** Example 1: Consider a three-way compound SQL statement. +** +** SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3 +** +** This statement is parsed up as follows: +** +** SELECT c FROM t3 +** | +** `-----> SELECT b FROM t2 +** | +** `------> SELECT a FROM t1 +** +** The arrows in the diagram above represent the Select.pPrior pointer. +** So if this routine is called with p equal to the t3 query, then +** pPrior will be the t2 query. p->op will be TK_UNION in this case. +** +** Notice that because of the way SQLite parses compound SELECTs, the +** individual selects always group from left to right. +*/ +static int multiSelect( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest /* What to do with query results */ +){ + int rc = SQLITE_OK; /* Success code from a subroutine */ + Select *pPrior; /* Another SELECT immediately to our left */ + Vdbe *v; /* Generate code to this VDBE */ + SelectDest dest; /* Alternative data destination */ + Select *pDelete = 0; /* Chain of simple selects to delete */ + sqlite3 *db; /* Database connection */ +#ifndef SQLITE_OMIT_EXPLAIN + int iSub1 = 0; /* EQP id of left-hand query */ + int iSub2 = 0; /* EQP id of right-hand query */ +#endif + + /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only + ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. + */ + assert( p && p->pPrior ); /* Calling function guarantees this much */ + assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); + 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)); + rc = 1; + goto multi_select_end; + } + + v = sqlite3GetVdbe(pParse); + assert( v!=0 ); /* The VDBE already created by calling function */ + + /* Create the destination temporary table if necessary + */ + if( dest.eDest==SRT_EphemTab ){ + assert( p->pEList ); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr); + dest.eDest = SRT_Table; + } + + /* Special handling for a compound-select that originates as a VALUES clause. + */ + if( p->selFlags & SF_MultiValue ){ + rc = multiSelectValues(pParse, p, &dest); + goto multi_select_end; + } + + /* Make sure all SELECTs in the statement have the same number of elements + ** in their result sets. + */ + assert( p->pEList && pPrior->pEList ); + assert( p->pEList->nExpr==pPrior->pEList->nExpr ); + +#ifndef SQLITE_OMIT_CTE + if( p->selFlags & SF_Recursive ){ + generateWithRecursiveQuery(pParse, p, &dest); + }else +#endif + + /* Compound SELECTs that have an ORDER BY clause are handled separately. + */ + if( p->pOrderBy ){ + return multiSelectOrderBy(pParse, p, pDest); + }else + + /* Generate code for the left and right SELECT statements. + */ + switch( p->op ){ + case TK_ALL: { + int addr = 0; + int nLimit; + assert( !pPrior->pLimit ); + pPrior->iLimit = p->iLimit; + pPrior->iOffset = p->iOffset; + pPrior->pLimit = p->pLimit; + pPrior->pOffset = p->pOffset; + explainSetInteger(iSub1, pParse->iNextSelectId); + rc = sqlite3Select(pParse, pPrior, &dest); + p->pLimit = 0; + p->pOffset = 0; + if( rc ){ + goto multi_select_end; + } + p->pPrior = 0; + p->iLimit = pPrior->iLimit; + p->iOffset = pPrior->iOffset; + if( p->iLimit ){ + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); + VdbeComment((v, "Jump ahead if LIMIT reached")); + if( p->iOffset ){ + sqlite3VdbeAddOp3(v, OP_OffsetLimit, + p->iLimit, p->iOffset+1, p->iOffset); + } + } + explainSetInteger(iSub2, pParse->iNextSelectId); + rc = sqlite3Select(pParse, p, &dest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + if( pPrior->pLimit + && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit) + && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) + ){ + p->nSelectRow = sqlite3LogEst((u64)nLimit); + } + if( addr ){ + sqlite3VdbeJumpHere(v, addr); + } + break; + } + case TK_EXCEPT: + case TK_UNION: { + int unionTab; /* Cursor number of the temporary table holding result */ + u8 op = 0; /* One of the SRT_ operations to apply to self */ + int priorOp; /* The SRT_ operation to apply to prior selects */ + Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */ + int addr; + SelectDest uniondest; + + testcase( p->op==TK_EXCEPT ); + testcase( p->op==TK_UNION ); + priorOp = SRT_Union; + if( dest.eDest==priorOp ){ + /* We can reuse a temporary table generated by a SELECT to our + ** right. + */ + assert( p->pLimit==0 ); /* Not allowed on leftward elements */ + assert( p->pOffset==0 ); /* Not allowed on leftward elements */ + unionTab = dest.iSDParm; + }else{ + /* We will need to create our own temporary table to hold the + ** intermediate results. + */ + unionTab = pParse->nTab++; + assert( p->pOrderBy==0 ); + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + findRightmost(p)->selFlags |= SF_UsesEphemeral; + assert( p->pEList ); + } + + /* Code the SELECT statements to our left + */ + assert( !pPrior->pOrderBy ); + sqlite3SelectDestInit(&uniondest, priorOp, unionTab); + explainSetInteger(iSub1, pParse->iNextSelectId); + rc = sqlite3Select(pParse, pPrior, &uniondest); + if( rc ){ + goto multi_select_end; + } + + /* Code the current SELECT statement + */ + if( p->op==TK_EXCEPT ){ + op = SRT_Except; + }else{ + assert( p->op==TK_UNION ); + op = SRT_Union; + } + p->pPrior = 0; + pLimit = p->pLimit; + p->pLimit = 0; + pOffset = p->pOffset; + p->pOffset = 0; + uniondest.eDest = op; + explainSetInteger(iSub2, pParse->iNextSelectId); + rc = sqlite3Select(pParse, p, &uniondest); + testcase( rc!=SQLITE_OK ); + /* Query flattening in sqlite3Select() might refill p->pOrderBy. + ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ + sqlite3ExprListDelete(db, p->pOrderBy); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->pOrderBy = 0; + if( p->op==TK_UNION ){ + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + } + sqlite3ExprDelete(db, p->pLimit); + p->pLimit = pLimit; + p->pOffset = pOffset; + p->iLimit = 0; + p->iOffset = 0; + + /* Convert the data in the temporary table into whatever form + ** it is that we currently need. + */ + assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); + if( dest.eDest!=priorOp ){ + int iCont, iBreak, iStart; + assert( p->pEList ); + if( dest.eDest==SRT_Output ){ + Select *pFirst = p; + while( pFirst->pPrior ) pFirst = pFirst->pPrior; + generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); + } + iBreak = sqlite3VdbeMakeLabel(v); + iCont = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iBreak); + sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); + iStart = sqlite3VdbeCurrentAddr(v); + selectInnerLoop(pParse, p, p->pEList, unionTab, + 0, 0, &dest, iCont, iBreak); + sqlite3VdbeResolveLabel(v, iCont); + sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); + sqlite3VdbeResolveLabel(v, iBreak); + sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); + } + break; + } + default: assert( p->op==TK_INTERSECT ); { + int tab1, tab2; + int iCont, iBreak, iStart; + Expr *pLimit, *pOffset; + int addr; + SelectDest intersectdest; + int r1; + + /* INTERSECT is different from the others since it requires + ** two temporary tables. Hence it has its own case. Begin + ** by allocating the tables we will need. + */ + tab1 = pParse->nTab++; + tab2 = pParse->nTab++; + assert( p->pOrderBy==0 ); + + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + findRightmost(p)->selFlags |= SF_UsesEphemeral; + assert( p->pEList ); + + /* Code the SELECTs to our left into temporary table "tab1". + */ + sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); + explainSetInteger(iSub1, pParse->iNextSelectId); + rc = sqlite3Select(pParse, pPrior, &intersectdest); + if( rc ){ + goto multi_select_end; + } + + /* Code the current SELECT into temporary table "tab2" + */ + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); + assert( p->addrOpenEphm[1] == -1 ); + p->addrOpenEphm[1] = addr; + p->pPrior = 0; + pLimit = p->pLimit; + p->pLimit = 0; + pOffset = p->pOffset; + p->pOffset = 0; + intersectdest.iSDParm = tab2; + explainSetInteger(iSub2, pParse->iNextSelectId); + rc = sqlite3Select(pParse, p, &intersectdest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; + sqlite3ExprDelete(db, p->pLimit); + p->pLimit = pLimit; + p->pOffset = pOffset; + + /* Generate code to take the intersection of the two temporary + ** tables. + */ + assert( p->pEList ); + if( dest.eDest==SRT_Output ){ + Select *pFirst = p; + while( pFirst->pPrior ) pFirst = pFirst->pPrior; + generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); + } + iBreak = sqlite3VdbeMakeLabel(v); + iCont = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iBreak); + sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); + r1 = sqlite3GetTempReg(pParse); + 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, + 0, 0, &dest, iCont, iBreak); + sqlite3VdbeResolveLabel(v, iCont); + sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); + sqlite3VdbeResolveLabel(v, iBreak); + sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); + sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); + break; + } + } + + explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL); + + /* Compute collating sequences used by + ** temporary tables needed to implement the compound select. + ** Attach the KeyInfo structure to all temporary tables. + ** + ** This section is run by the right-most SELECT statement only. + ** SELECT statements to the left always skip this part. The right-most + ** SELECT might also skip this part if it has no ORDER BY clause and + ** no temp tables are required. + */ + if( p->selFlags & SF_UsesEphemeral ){ + int i; /* Loop counter */ + KeyInfo *pKeyInfo; /* Collating sequence for the result set */ + Select *pLoop; /* For looping through SELECT statements */ + CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ + int nCol; /* Number of columns in result set */ + + assert( p->pNext==0 ); + nCol = p->pEList->nExpr; + pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); + if( !pKeyInfo ){ + rc = SQLITE_NOMEM_BKPT; + goto multi_select_end; + } + for(i=0, apColl=pKeyInfo->aColl; ipDfltColl; + } + } + + for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ + for(i=0; i<2; i++){ + int addr = pLoop->addrOpenEphm[i]; + if( addr<0 ){ + /* If [0] is unused then [1] is also unused. So we can + ** always safely abort as soon as the first unused slot is found */ + assert( pLoop->addrOpenEphm[1]<0 ); + break; + } + sqlite3VdbeChangeP2(v, addr, nCol); + sqlite3VdbeChangeP4(v, addr, (char*)sqlite3KeyInfoRef(pKeyInfo), + P4_KEYINFO); + pLoop->addrOpenEphm[i] = -1; + } + } + sqlite3KeyInfoUnref(pKeyInfo); + } + +multi_select_end: + pDest->iSdst = dest.iSdst; + pDest->nSdst = dest.nSdst; + sqlite3SelectDelete(db, pDelete); + return rc; +} +#endif /* SQLITE_OMIT_COMPOUND_SELECT */ + +/* +** Error message for when two or more terms of a compound select have different +** size result sets. +*/ +SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){ + if( p->selFlags & SF_Values ){ + sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); + }else{ + sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" + " do not have the same number of result columns", selectOpName(p->op)); + } +} + +/* +** Code an output subroutine for a coroutine implementation of a +** SELECT statment. +** +** The data to be output is contained in pIn->iSdst. There are +** pIn->nSdst columns to be output. pDest is where the output should +** be sent. +** +** regReturn is the number of the register holding the subroutine +** return address. +** +** If regPrev>0 then it is the first register in a vector that +** records the previous output. mem[regPrev] is a flag that is false +** if there has been no previous output. If regPrev>0 then code is +** generated to suppress duplicates. pKeyInfo is used for comparing +** keys. +** +** If the LIMIT found in p->iLimit is reached, jump immediately to +** iBreak. +*/ +static int generateOutputSubroutine( + Parse *pParse, /* Parsing context */ + Select *p, /* The SELECT statement */ + SelectDest *pIn, /* Coroutine supplying data */ + SelectDest *pDest, /* Where to send the data */ + int regReturn, /* The return address register */ + int regPrev, /* Previous result register. No uniqueness if 0 */ + KeyInfo *pKeyInfo, /* For comparing with previous entry */ + int iBreak /* Jump here if we hit the LIMIT */ +){ + Vdbe *v = pParse->pVdbe; + int iContinue; + int addr; + + addr = sqlite3VdbeCurrentAddr(v); + iContinue = sqlite3VdbeMakeLabel(v); + + /* Suppress duplicates for UNION, EXCEPT, and INTERSECT + */ + if( regPrev ){ + int addr1, addr2; + addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v); + addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst, + (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, addr2+2, iContinue, addr2+2); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev); + } + if( pParse->db->mallocFailed ) return 0; + + /* Suppress the first OFFSET entries if there is an OFFSET clause + */ + codeOffset(v, p->iOffset, iContinue); + + assert( pDest->eDest!=SRT_Exists ); + assert( pDest->eDest!=SRT_Table ); + switch( pDest->eDest ){ + /* Store the result as data using a unique key. + */ + case SRT_EphemTab: { + int r1 = sqlite3GetTempReg(pParse); + int r2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1); + sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2); + sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + sqlite3ReleaseTempReg(pParse, r2); + sqlite3ReleaseTempReg(pParse, r1); + break; + } + +#ifndef SQLITE_OMIT_SUBQUERY + /* If we are creating a set for an "expr IN (SELECT ...)". + */ + case SRT_Set: { + int r1; + testcase( pIn->nSdst>1 ); + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, + r1, pDest->zAffSdst, pIn->nSdst); + sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, + pIn->iSdst, pIn->nSdst); + sqlite3ReleaseTempReg(pParse, r1); + break; + } + + /* If this is a scalar select that is part of an expression, then + ** store the results in the appropriate memory cell and break out + ** of the scan loop. + */ + case SRT_Mem: { + assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 ); + sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1); + /* The LIMIT clause will jump out of the loop for us */ + break; + } +#endif /* #ifndef SQLITE_OMIT_SUBQUERY */ + + /* The results are stored in a sequence of registers + ** starting at pDest->iSdst. Then the co-routine yields. + */ + case SRT_Coroutine: { + if( pDest->iSdst==0 ){ + pDest->iSdst = sqlite3GetTempRange(pParse, pIn->nSdst); + pDest->nSdst = pIn->nSdst; + } + sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSdst, pIn->nSdst); + sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); + break; + } + + /* If none of the above, then the result destination must be + ** SRT_Output. This routine is never called with any other + ** destination other than the ones handled above or SRT_Output. + ** + ** For SRT_Output, results are stored in a sequence of registers. + ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to + ** return the next row of result. + */ + default: { + assert( pDest->eDest==SRT_Output ); + sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst); + sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst); + break; + } + } + + /* Jump to the end of the loop if the LIMIT is reached. + */ + if( p->iLimit ){ + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak); VdbeCoverage(v); + } + + /* Generate the subroutine return + */ + sqlite3VdbeResolveLabel(v, iContinue); + sqlite3VdbeAddOp1(v, OP_Return, regReturn); + + return addr; +} + +/* +** Alternative compound select code generator for cases when there +** is an ORDER BY clause. +** +** We assume a query of the following form: +** +** ORDER BY +** +** is one of UNION ALL, UNION, EXCEPT, or INTERSECT. The idea +** is to code both and with the ORDER BY clause as +** co-routines. Then run the co-routines in parallel and merge the results +** into the output. In addition to the two coroutines (called selectA and +** selectB) there are 7 subroutines: +** +** outA: Move the output of the selectA coroutine into the output +** of the compound query. +** +** outB: Move the output of the selectB coroutine into the output +** of the compound query. (Only generated for UNION and +** UNION ALL. EXCEPT and INSERTSECT never output a row that +** appears only in B.) +** +** AltB: Called when there is data from both coroutines and AB. +** +** EofA: Called when data is exhausted from selectA. +** +** EofB: Called when data is exhausted from selectB. +** +** The implementation of the latter five subroutines depend on which +** is used: +** +** +** UNION ALL UNION EXCEPT INTERSECT +** ------------- ----------------- -------------- ----------------- +** AltB: outA, nextA outA, nextA outA, nextA nextA +** +** AeqB: outA, nextA nextA nextA outA, nextA +** +** AgtB: outB, nextB outB, nextB nextB nextB +** +** EofA: outB, nextB outB, nextB halt halt +** +** EofB: outA, nextA outA, nextA outA, nextA halt +** +** In the AltB, AeqB, and AgtB subroutines, an EOF on A following nextA +** causes an immediate jump to EofA and an EOF on B following nextB causes +** an immediate jump to EofB. Within EofA and EofB, and EOF on entry or +** following nextX causes a jump to the end of the select processing. +** +** Duplicate removal in the UNION, EXCEPT, and INTERSECT cases is handled +** within the output subroutine. The regPrev register set holds the previously +** output value. A comparison is made against this value and the output +** is skipped if the next results would be the same as the previous. +** +** The implementation plan is to implement the two coroutines and seven +** subroutines first, then put the control logic at the bottom. Like this: +** +** goto Init +** coA: coroutine for left query (A) +** coB: coroutine for right query (B) +** outA: output one row of A +** outB: output one row of B (UNION and UNION ALL only) +** EofA: ... +** EofB: ... +** AltB: ... +** AeqB: ... +** AgtB: ... +** Init: initialize coroutine registers +** yield coA +** if eof(A) goto EofA +** yield coB +** if eof(B) goto EofB +** Cmpr: Compare A, B +** Jump AltB, AeqB, AgtB +** End: ... +** +** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not +** actually called using Gosub and they do not Return. EofA and EofB loop +** until all data is exhausted then jump to the "end" labe. AltB, AeqB, +** and AgtB jump to either L2 or to one of EofA or EofB. +*/ +#ifndef SQLITE_OMIT_COMPOUND_SELECT +static int multiSelectOrderBy( + Parse *pParse, /* Parsing context */ + Select *p, /* The right-most of SELECTs to be coded */ + SelectDest *pDest /* What to do with query results */ +){ + int i, j; /* Loop counters */ + Select *pPrior; /* Another SELECT immediately to our left */ + Vdbe *v; /* Generate code to this VDBE */ + SelectDest destA; /* Destination for coroutine A */ + SelectDest destB; /* Destination for coroutine B */ + int regAddrA; /* Address register for select-A coroutine */ + int regAddrB; /* Address register for select-B coroutine */ + int addrSelectA; /* Address of the select-A coroutine */ + int addrSelectB; /* Address of the select-B coroutine */ + int regOutA; /* Address register for the output-A subroutine */ + int regOutB; /* Address register for the output-B subroutine */ + int addrOutA; /* Address of the output-A subroutine */ + int addrOutB = 0; /* Address of the output-B subroutine */ + int addrEofA; /* Address of the select-A-exhausted subroutine */ + int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */ + int addrEofB; /* Address of the select-B-exhausted subroutine */ + int addrAltB; /* Address of the AB subroutine */ + int regLimitA; /* Limit register for select-A */ + int regLimitB; /* Limit register for select-A */ + int regPrev; /* A range of registers to hold previous output */ + int savedLimit; /* Saved value of p->iLimit */ + int savedOffset; /* Saved value of p->iOffset */ + int labelCmpr; /* Label for the start of the merge algorithm */ + int labelEnd; /* Label for the end of the overall SELECT stmt */ + int addr1; /* Jump instructions that get retargetted */ + int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ + KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ + KeyInfo *pKeyMerge; /* Comparison information for merging rows */ + sqlite3 *db; /* Database connection */ + ExprList *pOrderBy; /* The ORDER BY clause */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + int *aPermute; /* Mapping from ORDER BY terms to result set columns */ +#ifndef SQLITE_OMIT_EXPLAIN + int iSub1; /* EQP id of left-hand query */ + int iSub2; /* EQP id of right-hand query */ +#endif + + assert( p->pOrderBy!=0 ); + assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */ + db = pParse->db; + v = pParse->pVdbe; + assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */ + labelEnd = sqlite3VdbeMakeLabel(v); + labelCmpr = sqlite3VdbeMakeLabel(v); + + + /* Patch up the ORDER BY clause + */ + op = p->op; + pPrior = p->pPrior; + assert( pPrior->pOrderBy==0 ); + pOrderBy = p->pOrderBy; + assert( pOrderBy ); + nOrderBy = pOrderBy->nExpr; + + /* For operators other than UNION ALL we have to make sure that + ** the ORDER BY clause covers every term of the result set. Add + ** terms to the ORDER BY clause as necessary. + */ + if( op!=TK_ALL ){ + for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){ + struct ExprList_item *pItem; + for(j=0, pItem=pOrderBy->a; ju.x.iOrderByCol>0 ); + if( pItem->u.x.iOrderByCol==i ) break; + } + if( j==nOrderBy ){ + Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + if( pNew==0 ) return SQLITE_NOMEM_BKPT; + pNew->flags |= EP_IntValue; + pNew->u.iValue = i; + p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); + if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i; + } + } + } + + /* Compute the comparison permutation and keyinfo that is used with + ** the permutation used to determine if the next + ** row of results comes from selectA or selectB. Also add explicit + ** collations to the ORDER BY clause terms so that when the subqueries + ** to the right and the left are evaluated, they use the correct + ** collation. + */ + aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1)); + if( aPermute ){ + struct ExprList_item *pItem; + aPermute[0] = nOrderBy; + for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ + assert( pItem->u.x.iOrderByCol>0 ); + assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); + aPermute[i] = pItem->u.x.iOrderByCol - 1; + } + pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1); + }else{ + pKeyMerge = 0; + } + + /* Reattach the ORDER BY clause to the query. + */ + p->pOrderBy = pOrderBy; + pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0); + + /* Allocate a range of temporary registers and the KeyInfo needed + ** for the logic that removes duplicate result rows when the + ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL). + */ + if( op==TK_ALL ){ + regPrev = 0; + }else{ + int nExpr = p->pEList->nExpr; + assert( nOrderBy>=nExpr || db->mallocFailed ); + regPrev = pParse->nMem+1; + pParse->nMem += nExpr+1; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); + pKeyDup = sqlite3KeyInfoAlloc(db, nExpr, 1); + if( pKeyDup ){ + assert( sqlite3KeyInfoIsWriteable(pKeyDup) ); + for(i=0; iaColl[i] = multiSelectCollSeq(pParse, p, i); + pKeyDup->aSortOrder[i] = 0; + } + } + } + + /* Separate the left and the right query from one another + */ + p->pPrior = 0; + pPrior->pNext = 0; + sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER"); + if( pPrior->pPrior==0 ){ + sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER"); + } + + /* Compute the limit registers */ + computeLimitRegisters(pParse, p, labelEnd); + if( p->iLimit && op==TK_ALL ){ + regLimitA = ++pParse->nMem; + regLimitB = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit, + regLimitA); + sqlite3VdbeAddOp2(v, OP_Copy, regLimitA, regLimitB); + }else{ + regLimitA = regLimitB = 0; + } + sqlite3ExprDelete(db, p->pLimit); + p->pLimit = 0; + sqlite3ExprDelete(db, p->pOffset); + p->pOffset = 0; + + regAddrA = ++pParse->nMem; + regAddrB = ++pParse->nMem; + regOutA = ++pParse->nMem; + regOutB = ++pParse->nMem; + sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); + sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); + + /* Generate a coroutine to evaluate the SELECT statement to the + ** left of the compound operator - the "A" select. + */ + addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; + addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); + VdbeComment((v, "left SELECT")); + pPrior->iLimit = regLimitA; + explainSetInteger(iSub1, pParse->iNextSelectId); + sqlite3Select(pParse, pPrior, &destA); + sqlite3VdbeEndCoroutine(v, regAddrA); + sqlite3VdbeJumpHere(v, addr1); + + /* Generate a coroutine to evaluate the SELECT statement on + ** the right - the "B" select + */ + addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; + addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB); + VdbeComment((v, "right SELECT")); + savedLimit = p->iLimit; + savedOffset = p->iOffset; + p->iLimit = regLimitB; + p->iOffset = 0; + explainSetInteger(iSub2, pParse->iNextSelectId); + sqlite3Select(pParse, p, &destB); + p->iLimit = savedLimit; + p->iOffset = savedOffset; + sqlite3VdbeEndCoroutine(v, regAddrB); + + /* Generate a subroutine that outputs the current row of the A + ** select as the next output row of the compound select. + */ + VdbeNoopComment((v, "Output routine for A")); + addrOutA = generateOutputSubroutine(pParse, + p, &destA, pDest, regOutA, + regPrev, pKeyDup, labelEnd); + + /* Generate a subroutine that outputs the current row of the B + ** select as the next output row of the compound select. + */ + if( op==TK_ALL || op==TK_UNION ){ + VdbeNoopComment((v, "Output routine for B")); + addrOutB = generateOutputSubroutine(pParse, + p, &destB, pDest, regOutB, + regPrev, pKeyDup, labelEnd); + } + sqlite3KeyInfoUnref(pKeyDup); + + /* Generate a subroutine to run when the results from select A + ** are exhausted and only data in select B remains. + */ + if( op==TK_EXCEPT || op==TK_INTERSECT ){ + addrEofA_noB = addrEofA = labelEnd; + }else{ + VdbeNoopComment((v, "eof-A subroutine")); + addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd); + VdbeCoverage(v); + sqlite3VdbeGoto(v, addrEofA); + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + } + + /* Generate a subroutine to run when the results from select B + ** are exhausted and only data in select A remains. + */ + if( op==TK_INTERSECT ){ + addrEofB = addrEofA; + if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; + }else{ + VdbeNoopComment((v, "eof-B subroutine")); + addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v); + sqlite3VdbeGoto(v, addrEofB); + } + + /* Generate code to handle the case of AB + */ + VdbeNoopComment((v, "A-gt-B subroutine")); + addrAgtB = sqlite3VdbeCurrentAddr(v); + if( op==TK_ALL || op==TK_UNION ){ + sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + } + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + sqlite3VdbeGoto(v, labelCmpr); + + /* This code runs once to initialize everything. + */ + sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + + /* Implement the main merge loop + */ + sqlite3VdbeResolveLabel(v, labelCmpr); + sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); + sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, + (char*)pKeyMerge, P4_KEYINFO); + sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); + sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); + + /* Jump to the this point in order to terminate the query. + */ + sqlite3VdbeResolveLabel(v, labelEnd); + + /* Set the number of output columns + */ + if( pDest->eDest==SRT_Output ){ + Select *pFirst = pPrior; + while( pFirst->pPrior ) pFirst = pFirst->pPrior; + generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); + } + + /* Reassembly the compound query so that it will be freed correctly + ** by the calling function */ + if( p->pPrior ){ + sqlite3SelectDelete(db, p->pPrior); + } + p->pPrior = pPrior; + pPrior->pNext = p; + + /*** TBD: Insert subroutine calls to close cursors on incomplete + **** subqueries ****/ + explainComposite(pParse, p->op, iSub1, iSub2, 0); + return pParse->nErr!=0; +} +#endif + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + +/* An instance of the SubstContext object describes an substitution edit +** to be performed on a parse tree. +** +** All references to columns in table iTable are to be replaced by corresponding +** expressions in pEList. +*/ +typedef struct SubstContext { + Parse *pParse; /* The parsing context */ + int iTable; /* Replace references to this table */ + int iNewTable; /* New table number */ + int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ + ExprList *pEList; /* Replacement expressions */ +} SubstContext; + +/* Forward Declarations */ +static void substExprList(SubstContext*, ExprList*); +static void substSelect(SubstContext*, Select*, int); + +/* +** Scan through the expression pExpr. Replace every reference to +** a column in table number iTable with a copy of the iColumn-th +** entry in pEList. (But leave references to the ROWID column +** unchanged.) +** +** This routine is part of the flattening procedure. A subquery +** whose result set is defined by pEList appears as entry in the +** FROM clause of a SELECT such that the VDBE cursor assigned to that +** FORM clause entry is iTable. This routine makes the necessary +** changes to pExpr so that it refers directly to the source table +** of the subquery rather the result set of the subquery. +*/ +static Expr *substExpr( + SubstContext *pSubst, /* Description of the substitution */ + Expr *pExpr /* Expr in which substitution occurs */ +){ + if( pExpr==0 ) return 0; + if( ExprHasProperty(pExpr, EP_FromJoin) && pExpr->iRightJoinTable==pSubst->iTable ){ + pExpr->iRightJoinTable = pSubst->iNewTable; + } + if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){ + if( pExpr->iColumn<0 ){ + pExpr->op = TK_NULL; + }else{ + Expr *pNew; + Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; + Expr ifNullRow; + assert( pSubst->pEList!=0 && pExpr->iColumnpEList->nExpr ); + assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + if( sqlite3ExprIsVector(pCopy) ){ + sqlite3VectorErrorMsg(pSubst->pParse, pCopy); + }else{ + sqlite3 *db = pSubst->pParse->db; + if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){ + memset(&ifNullRow, 0, sizeof(ifNullRow)); + ifNullRow.op = TK_IF_NULL_ROW; + ifNullRow.pLeft = pCopy; + ifNullRow.iTable = pSubst->iNewTable; + pCopy = &ifNullRow; + } + pNew = sqlite3ExprDup(db, pCopy, 0); + if( pNew && (pExpr->flags & EP_FromJoin) ){ + pNew->iRightJoinTable = pExpr->iRightJoinTable; + pNew->flags |= EP_FromJoin; + } + sqlite3ExprDelete(db, pExpr); + pExpr = pNew; + } + } + }else{ + if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){ + pExpr->iTable = pSubst->iNewTable; + } + pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); + pExpr->pRight = substExpr(pSubst, pExpr->pRight); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + substSelect(pSubst, pExpr->x.pSelect, 1); + }else{ + substExprList(pSubst, pExpr->x.pList); + } + } + return pExpr; +} +static void substExprList( + SubstContext *pSubst, /* Description of the substitution */ + ExprList *pList /* List to scan and in which to make substitutes */ +){ + int i; + if( pList==0 ) return; + for(i=0; inExpr; i++){ + pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr); + } +} +static void substSelect( + SubstContext *pSubst, /* Description of the substitution */ + Select *p, /* SELECT statement in which to make substitutions */ + int doPrior /* Do substitutes on p->pPrior too */ +){ + SrcList *pSrc; + struct SrcList_item *pItem; + int i; + if( !p ) return; + do{ + substExprList(pSubst, p->pEList); + substExprList(pSubst, p->pGroupBy); + substExprList(pSubst, p->pOrderBy); + p->pHaving = substExpr(pSubst, p->pHaving); + p->pWhere = substExpr(pSubst, p->pWhere); + pSrc = p->pSrc; + assert( pSrc!=0 ); + for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ + substSelect(pSubst, pItem->pSelect, 1); + if( pItem->fg.isTabFunc ){ + substExprList(pSubst, pItem->u1.pFuncArg); + } + } + }while( doPrior && (p = p->pPrior)!=0 ); +} +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) +/* +** This routine attempts to flatten subqueries as a performance optimization. +** This routine returns 1 if it makes changes and 0 if no flattening occurs. +** +** To understand the concept of flattening, consider the following +** query: +** +** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5 +** +** The default way of implementing this query is to execute the +** subquery first and store the results in a temporary table, then +** run the outer query on that temporary table. This requires two +** passes over the data. Furthermore, because the temporary table +** has no indices, the WHERE clause on the outer query cannot be +** optimized. +** +** This routine attempts to rewrite queries such as the above into +** a single flat select, like this: +** +** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 +** +** The code generated for this simplification gives the same result +** but only has to scan the data once. And because indices might +** 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: +** +** (1) The subquery and the outer query do not both use 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.) +** +** (3) The subquery is not the right operand of a LEFT JOIN +** or the subquery is not itself a join and the outer query is not +** an aggregate. +** +** (4) The subquery is not 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. +** +** (7) The subquery has 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. +** +** (9) The subquery does not use LIMIT or the outer query does not use +** aggregates. +** +** (**) 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." +** +** (11) The subquery and the outer query do 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. +** +** (14) The subquery does not use OFFSET. +** +** (15) The outer query is not part of a compound select or the +** subquery does not have a LIMIT clause. +** (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 +** 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 +** +** The parent and sub-query may contain WHERE clauses. Subject to +** rules (11), (13) and (14), they may also contain ORDER BY, +** LIMIT and OFFSET clauses. The subquery cannot use any compound +** operator other than UNION ALL because all the other compound +** operators have an implied DISTINCT which is disallowed by +** restriction (4). +** +** Also, each component of the sub-query must return the same number +** of result columns. This is actually a requirement for any compound +** SELECT statement, but all the code here does is make sure that no +** such (illegal) sub-query is flattened. The caller will detect the +** syntax error and return a detailed message. +** +** (18) If the sub-query is a compound select, then all terms of the +** ORDER by clause of the parent must be simple references to +** columns of the sub-query. +** +** (19) The subquery does not use LIMIT or the outer query does 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. +** +** (21) The subquery does not use LIMIT or the outer query is not +** DISTINCT. (See ticket [752e1646fc]). +** +** (22) The subquery is not 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 +** 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 +** 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.) +** +** +** 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. +** +** If flattening is not attempted, this routine is a no-op and returns 0. +** If flattening is attempted this routine returns 1. +** +** All of the expression analysis must occur on both the outer query and +** the subquery before this routine runs. +*/ +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 */ +){ + const char *zSavedAuthContext = pParse->zAuthContext; + Select *pParent; /* Current UNION ALL term of the other query */ + Select *pSub; /* The inner query or "subquery" */ + Select *pSub1; /* Pointer to the rightmost select in sub-query */ + SrcList *pSrc; /* The FROM clause of the outer query */ + SrcList *pSubSrc; /* The FROM clause of the subquery */ + ExprList *pList; /* The result set of the outer query */ + int iParent; /* VDBE cursor number of the pSub result set temp table */ + int iNewParent = -1;/* Replacement table for iParent */ + int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ + int i; /* Loop counter */ + Expr *pWhere; /* The WHERE clause */ + struct SrcList_item *pSubitem; /* The subquery */ + sqlite3 *db = pParse->db; + + /* Check to see if flattening is permitted. Return 0 if not. + */ + assert( p!=0 ); + assert( p->pPrior==0 ); /* Unable to flatten compound queries */ + if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; + pSrc = p->pSrc; + assert( pSrc && iFrom>=0 && iFromnSrc ); + pSubitem = &pSrc->a[iFrom]; + 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 ); + /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, + ** not arbitrary expressions, we allowed some combining of LIMIT and OFFSET + ** because they could be computed at compile-time. But when LIMIT and OFFSET + ** became arbitrary expressions, we were forced to add restrictions (13) + ** and (14). */ + if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */ + if( pSub->pOffset ) return 0; /* Restriction (14) */ + if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){ + return 0; /* Restriction (15) */ + } + if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ + if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */ + 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) */ + } + if( isAgg && pSub->pOrderBy ) return 0; /* Restriction (16) */ + if( pSub->pLimit && p->pWhere ) return 0; /* Restriction (19) */ + 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 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: + ** + ** t1 LEFT OUTER JOIN (t2 JOIN t3) + ** + ** If we flatten the above, we would get + ** + ** (t1 LEFT OUTER JOIN t2) JOIN t3 + ** + ** 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 not 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 ){ + return 0; /* Restriction (3) */ + } + } +#ifdef SQLITE_EXTRA_IFNULLROW + else if( iFrom>0 && !isAgg ){ + /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for + ** every reference to any result column from subquery in a join, even though + ** they are not necessary. This will stress-test the OP_IfNullRow opcode. */ + isLeftJoin = -1; + } +#endif + + /* Restriction 17: If the sub-query is a compound SELECT, then it must + ** use only the UNION ALL operator. And none of the simple select queries + ** 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; + } + 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 + ){ + return 0; + } + testcase( pSub1->pSrc->nSrc>1 ); + } + + /* Restriction 18. */ + if( p->pOrderBy ){ + int ii; + for(ii=0; iipOrderBy->nExpr; ii++){ + if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0; + } + } + } + + /***** If we reach this point, flattening is permitted. *****/ + SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", + pSub->zSelName, pSub, iFrom)); + + /* Authorize the subquery */ + pParse->zAuthContext = pSubitem->zName; + TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); + testcase( i==SQLITE_DENY ); + pParse->zAuthContext = zSavedAuthContext; + + /* If the sub-query is a compound SELECT statement, then (by restrictions + ** 17 and 18 above) it must be a UNION ALL and the parent query must + ** be of the form: + ** + ** SELECT FROM () + ** + ** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block + ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or + ** OFFSET clauses and joins them to the left-hand-side of the original + ** using UNION ALL operators. In this case N is the number of simple + ** select statements in the compound sub-query. + ** + ** Example: + ** + ** SELECT a+1 FROM ( + ** SELECT x FROM tab + ** UNION ALL + ** SELECT y FROM tab + ** UNION ALL + ** SELECT abs(z*2) FROM tab2 + ** ) WHERE a!=5 ORDER BY 1 + ** + ** Transformed into: + ** + ** SELECT x+1 FROM tab WHERE x+1!=5 + ** UNION ALL + ** SELECT y+1 FROM tab WHERE y+1!=5 + ** UNION ALL + ** SELECT abs(z*2)+1 FROM tab2 WHERE abs(z*2)+1!=5 + ** ORDER BY 1 + ** + ** We call this the "compound-subquery flattening". + */ + for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ + Select *pNew; + ExprList *pOrderBy = p->pOrderBy; + Expr *pLimit = p->pLimit; + Expr *pOffset = p->pOffset; + Select *pPrior = p->pPrior; + p->pOrderBy = 0; + p->pSrc = 0; + p->pPrior = 0; + p->pLimit = 0; + p->pOffset = 0; + pNew = sqlite3SelectDup(db, p, 0); + sqlite3SelectSetName(pNew, pSub->zSelName); + p->pOffset = pOffset; + p->pLimit = pLimit; + p->pOrderBy = pOrderBy; + p->pSrc = pSrc; + p->op = TK_ALL; + if( pNew==0 ){ + p->pPrior = pPrior; + }else{ + pNew->pPrior = pPrior; + if( pPrior ) pPrior->pNext = pNew; + pNew->pNext = p; + p->pPrior = pNew; + SELECTTRACE(2,pParse,p, + ("compound-subquery flattener creates %s.%p as peer\n", + pNew->zSelName, pNew)); + } + if( db->mallocFailed ) return 1; + } + + /* Begin flattening the iFrom-th entry of the FROM clause + ** in the outer query. + */ + pSub = pSub1 = pSubitem->pSelect; + + /* Delete the transient table structure associated with the + ** subquery + */ + sqlite3DbFree(db, pSubitem->zDatabase); + sqlite3DbFree(db, pSubitem->zName); + sqlite3DbFree(db, pSubitem->zAlias); + pSubitem->zDatabase = 0; + pSubitem->zName = 0; + pSubitem->zAlias = 0; + pSubitem->pSelect = 0; + + /* Defer deleting the Table object associated with the + ** subquery until code generation is + ** complete, since there may still exist Expr.pTab entries that + ** refer to the subquery even after flattening. Ticket #3346. + ** + ** pSubitem->pTab is always non-NULL by test restrictions and tests above. + */ + if( ALWAYS(pSubitem->pTab!=0) ){ + Table *pTabToDel = pSubitem->pTab; + if( pTabToDel->nTabRef==1 ){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + pTabToDel->pNextZombie = pToplevel->pZombieTab; + pToplevel->pZombieTab = pTabToDel; + }else{ + pTabToDel->nTabRef--; + } + pSubitem->pTab = 0; + } + + /* The following loop runs once for each term in a compound-subquery + ** flattening (as described above). If we are doing a different kind + ** of flattening - a flattening other than a compound-subquery flattening - + ** then this loop only runs once. + ** + ** This loop moves all of the FROM elements of the subquery into the + ** the FROM clause of the outer query. Before doing this, remember + ** the cursor number for the original outer query FROM element in + ** iParent. The iParent cursor will never be used. Subsequent code + ** will scan expressions looking for iParent references and replace + ** those references with expressions that resolve to the subquery FROM + ** elements we are now copying in. + */ + for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ + int nSubSrc; + u8 jointype = 0; + pSubSrc = pSub->pSrc; /* FROM clause of subquery */ + nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ + pSrc = pParent->pSrc; /* FROM clause of the outer query */ + + if( pSrc ){ + assert( pParent==p ); /* First time through the loop */ + jointype = pSubitem->fg.jointype; + }else{ + assert( pParent!=p ); /* 2nd and subsequent times through the loop */ + pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + if( pSrc==0 ){ + assert( db->mallocFailed ); + break; + } + } + + /* The subquery uses a single slot of the FROM clause of the outer + ** query. If the subquery has more than one element in its FROM clause, + ** then expand the outer query to make space for it to hold all elements + ** of the subquery. + ** + ** Example: + ** + ** SELECT * FROM tabA, (SELECT * FROM sub1, sub2), tabB; + ** + ** The outer query has 3 slots in its FROM clause. One slot of the + ** outer query (the middle slot) is used by the subquery. The next + ** block of code will expand the outer query FROM clause to 4 slots. + ** The middle slot is expanded to two slots in order to make space + ** for the two elements in the FROM clause of the subquery. + */ + if( nSubSrc>1 ){ + pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1); + if( db->mallocFailed ){ + break; + } + } + + /* Transfer the FROM clause terms from the subquery into the + ** outer query. + */ + for(i=0; ia[i+iFrom].pUsing); + assert( pSrc->a[i+iFrom].fg.isTabFunc==0 ); + pSrc->a[i+iFrom] = pSubSrc->a[i]; + iNewParent = pSubSrc->a[i].iCursor; + memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); + } + pSrc->a[iFrom].fg.jointype = jointype; + + /* Now begin substituting subquery result set expressions for + ** references to the iParent in the outer query. + ** + ** Example: + ** + ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; + ** \ \_____________ subquery __________/ / + ** \_____________________ outer query ______________________________/ + ** + ** We look at every expression in the outer query and every place we see + ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". + */ + pList = pParent->pEList; + for(i=0; inExpr; i++){ + if( pList->a[i].zName==0 ){ + char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan); + sqlite3Dequote(zName); + pList->a[i].zName = zName; + } + } + if( pSub->pOrderBy ){ + /* At this point, any non-zero iOrderByCol values indicate that the + ** ORDER BY column expression is identical to the iOrderByCol'th + ** expression returned by SELECT statement pSub. Since these values + ** do not necessarily correspond to columns in SELECT statement pParent, + ** zero them before transfering the ORDER BY clause. + ** + ** Not doing this may cause an error if a subsequent call to this + ** function attempts to flatten a compound sub-query into pParent + ** (the only way this can happen is if the compound sub-query is + ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */ + ExprList *pOrderBy = pSub->pOrderBy; + for(i=0; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; + } + assert( pParent->pOrderBy==0 ); + assert( pSub->pPrior==0 ); + pParent->pOrderBy = pOrderBy; + pSub->pOrderBy = 0; + } + pWhere = sqlite3ExprDup(db, pSub->pWhere, 0); + 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); + } + if( db->mallocFailed==0 ){ + SubstContext x; + x.pParse = pParse; + x.iTable = iParent; + x.iNewTable = iNewParent; + x.isLeftJoin = isLeftJoin; + x.pEList = pSub->pEList; + substSelect(&x, pParent, 0); + } + + /* The flattened query is distinct if either the inner or the + ** outer query is distinct. + */ + pParent->selFlags |= pSub->selFlags & SF_Distinct; + + /* + ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; + ** + ** One is tempted to try to add a and b to combine the limits. But this + ** does not work if either limit is negative. + */ + if( pSub->pLimit ){ + pParent->pLimit = pSub->pLimit; + pSub->pLimit = 0; + } + } + + /* Finially, delete what is left of the subquery and return + ** success. + */ + sqlite3SelectDelete(db, pSub1); + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After flattening:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + + return 1; +} +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ + + + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) +/* +** Make copies of relevant WHERE clause terms of the outer query into +** the WHERE clause of subquery. Example: +** +** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10; +** +** Transformed into: +** +** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10) +** WHERE x=5 AND y=10; +** +** The hope is that the terms added to the inner query will make it more +** efficient. +** +** 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.) +** +** (2) The inner query is the recursive part of a common table expression. +** +** (3) The inner query has a LIMIT clause (since the changes to the WHERE +** close would change the meaning of the LIMIT). +** +** (4) The inner query is the right operand of a LEFT JOIN. (The caller +** enforces this restriction since this routine does not have enough +** information to know.) +** +** (5) The WHERE clause expression originates in the ON or USING clause +** of a LEFT JOIN. +** +** Return 0 if no changes are made and non-zero if one or more WHERE clause +** terms are duplicated into the subquery. +*/ +static int pushDownWhereTerms( + Parse *pParse, /* Parse context (for malloc() and error reporting) */ + Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ + Expr *pWhere, /* The WHERE clause of the outer query */ + int iCursor /* Cursor number of the subquery */ +){ + 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->pLimit!=0 ){ + return 0; /* restriction (3) */ + } + while( pWhere->op==TK_AND ){ + nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor); + pWhere = pWhere->pLeft; + } + if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */ + if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ + nChng++; + while( pSubq ){ + SubstContext x; + pNew = sqlite3ExprDup(pParse->db, pWhere, 0); + x.pParse = pParse; + x.iTable = iCursor; + x.iNewTable = iCursor; + x.isLeftJoin = 0; + x.pEList = pSubq->pEList; + pNew = substExpr(&x, pNew); + pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); + pSubq = pSubq->pPrior; + } + } + return nChng; +} +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ + +/* +** Based on the contents of the AggInfo structure indicated by the first +** argument, this function checks if the following are true: +** +** * the query contains just a single aggregate function, +** * the aggregate function is either min() or max(), and +** * the argument to the aggregate function is a column value. +** +** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX +** is returned as appropriate. Also, *ppMinMax is set to point to the +** list of arguments passed to the aggregate before returning. +** +** Or, if the conditions above are not met, *ppMinMax is set to 0 and +** WHERE_ORDERBY_NORMAL is returned. +*/ +static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){ + int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ + + *ppMinMax = 0; + if( pAggInfo->nFunc==1 ){ + Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */ + ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */ + + assert( pExpr->op==TK_AGG_FUNCTION ); + if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){ + const char *zFunc = pExpr->u.zToken; + if( sqlite3StrICmp(zFunc, "min")==0 ){ + eRet = WHERE_ORDERBY_MIN; + *ppMinMax = pEList; + }else if( sqlite3StrICmp(zFunc, "max")==0 ){ + eRet = WHERE_ORDERBY_MAX; + *ppMinMax = pEList; + } + } + } + + assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 ); + return eRet; +} + +/* +** The select statement passed as the first argument is an aggregate query. +** The second argument is the associated aggregate-info object. This +** function tests if the SELECT is of the form: +** +** SELECT count(*) FROM +** +** where table is a database table, not a sub-select or view. If the query +** does match this pattern, then a pointer to the Table object representing +** is returned. Otherwise, 0 is returned. +*/ +static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ + Table *pTab; + Expr *pExpr; + + assert( !p->pGroupBy ); + + if( p->pWhere || p->pEList->nExpr!=1 + || p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect + ){ + return 0; + } + pTab = p->pSrc->a[0].pTab; + pExpr = p->pEList->a[0].pExpr; + assert( pTab && !pTab->pSelect && pExpr ); + + if( IsVirtual(pTab) ) return 0; + if( pExpr->op!=TK_AGG_FUNCTION ) return 0; + if( NEVER(pAggInfo->nFunc==0) ) return 0; + if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; + if( pExpr->flags&EP_Distinct ) return 0; + + return pTab; +} + +/* +** If the source-list item passed as an argument was augmented with an +** INDEXED BY clause, then try to locate the specified index. If there +** was such a clause and the named index cannot be found, return +** SQLITE_ERROR and leave an error in pParse. Otherwise, populate +** pFrom->pIndex and return SQLITE_OK. +*/ +SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){ + if( pFrom->pTab && pFrom->fg.isIndexedBy ){ + Table *pTab = pFrom->pTab; + char *zIndexedBy = pFrom->u1.zIndexedBy; + Index *pIdx; + for(pIdx=pTab->pIndex; + pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); + pIdx=pIdx->pNext + ); + if( !pIdx ){ + sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0); + pParse->checkSchema = 1; + return SQLITE_ERROR; + } + pFrom->pIBIndex = pIdx; + } + return SQLITE_OK; +} +/* +** Detect compound SELECT statements that use an ORDER BY clause with +** an alternative collating sequence. +** +** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ... +** +** These are rewritten as a subquery: +** +** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2) +** ORDER BY ... COLLATE ... +** +** This transformation is necessary because the multiSelectOrderBy() routine +** above that generates the code for a compound SELECT with an ORDER BY clause +** uses a merge algorithm that requires the same collating sequence on the +** result columns as on the ORDER BY clause. See ticket +** http://www.sqlite.org/src/info/6709574d2a +** +** This transformation is only needed for EXCEPT, INTERSECT, and UNION. +** The UNION ALL operator works fine with multiSelectOrderBy() even when +** there are COLLATE terms in the ORDER BY. +*/ +static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ + int i; + Select *pNew; + Select *pX; + sqlite3 *db; + struct ExprList_item *a; + SrcList *pNewSrc; + Parse *pParse; + Token dummy; + + if( p->pPrior==0 ) return WRC_Continue; + if( p->pOrderBy==0 ) return WRC_Continue; + for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){} + if( pX==0 ) return WRC_Continue; + a = p->pOrderBy->a; + for(i=p->pOrderBy->nExpr-1; i>=0; i--){ + if( a[i].pExpr->flags & EP_Collate ) break; + } + if( i<0 ) return WRC_Continue; + + /* If we reach this point, that means the transformation is required. */ + + pParse = pWalker->pParse; + db = pParse->db; + pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); + if( pNew==0 ) return WRC_Abort; + memset(&dummy, 0, sizeof(dummy)); + pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0); + if( pNewSrc==0 ) return WRC_Abort; + *pNew = *p; + p->pSrc = pNewSrc; + p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); + p->op = TK_SELECT; + p->pWhere = 0; + pNew->pGroupBy = 0; + pNew->pHaving = 0; + pNew->pOrderBy = 0; + p->pPrior = 0; + p->pNext = 0; + p->pWith = 0; + p->selFlags &= ~SF_Compound; + assert( (p->selFlags & SF_Converted)==0 ); + p->selFlags |= SF_Converted; + assert( pNew->pPrior!=0 ); + pNew->pPrior->pNext = pNew; + pNew->pLimit = 0; + pNew->pOffset = 0; + return WRC_Continue; +} + +/* +** Check to see if the FROM clause term pFrom has table-valued function +** arguments. If it does, leave an error message in pParse and return +** non-zero, since pFrom is not allowed to be a table-valued function. +*/ +static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){ + if( pFrom->fg.isTabFunc ){ + sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName); + return 1; + } + return 0; +} + +#ifndef SQLITE_OMIT_CTE +/* +** Argument pWith (which may be NULL) points to a linked list of nested +** WITH contexts, from inner to outermost. If the table identified by +** FROM clause element pItem is really a common-table-expression (CTE) +** then return a pointer to the CTE definition for that table. Otherwise +** return NULL. +** +** If a non-NULL value is returned, set *ppContext to point to the With +** object that the returned CTE belongs to. +*/ +static struct Cte *searchWith( + With *pWith, /* Current innermost WITH clause */ + struct SrcList_item *pItem, /* FROM clause element to resolve */ + With **ppContext /* OUT: WITH clause return value belongs to */ +){ + const char *zName; + if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){ + With *p; + for(p=pWith; p; p=p->pOuter){ + int i; + for(i=0; inCte; i++){ + if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){ + *ppContext = p; + return &p->a[i]; + } + } + } + } + return 0; +} + +/* The code generator maintains a stack of active WITH clauses +** with the inner-most WITH clause being at the top of the stack. +** +** This routine pushes the WITH clause passed as the second argument +** onto the top of the stack. If argument bFree is true, then this +** WITH clause will never be popped from the stack. In this case it +** should be freed along with the Parse object. In other cases, when +** bFree==0, the With object will be freed along with the SELECT +** statement with which it is associated. +*/ +SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ + assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) ); + if( pWith ){ + assert( pParse->pWith!=pWith ); + pWith->pOuter = pParse->pWith; + pParse->pWith = pWith; + if( bFree ) pParse->pWithToFree = pWith; + } +} + +/* +** This function checks if argument pFrom refers to a CTE declared by +** a WITH clause on the stack currently maintained by the parser. And, +** if currently processing a CTE expression, if it is a recursive +** reference to the current CTE. +** +** If pFrom falls into either of the two categories above, pFrom->pTab +** and other fields are populated accordingly. The caller should check +** (pFrom->pTab!=0) to determine whether or not a successful match +** was found. +** +** Whether or not a match is found, SQLITE_OK is returned if no error +** occurs. If an error does occur, an error message is stored in the +** parser and some error code other than SQLITE_OK returned. +*/ +static int withExpand( + Walker *pWalker, + struct SrcList_item *pFrom +){ + Parse *pParse = pWalker->pParse; + sqlite3 *db = pParse->db; + struct Cte *pCte; /* Matched CTE (or NULL if no match) */ + With *pWith; /* WITH clause that pCte belongs to */ + + assert( pFrom->pTab==0 ); + + pCte = searchWith(pParse->pWith, pFrom, &pWith); + if( pCte ){ + Table *pTab; + ExprList *pEList; + Select *pSel; + Select *pLeft; /* Left-most SELECT statement */ + int bMayRecursive; /* True if compound joined by UNION [ALL] */ + With *pSavedWith; /* Initial value of pParse->pWith */ + + /* If pCte->zCteErr is non-NULL at this point, then this is an illegal + ** recursive reference to CTE pCte. Leave an error in pParse and return + ** early. If pCte->zCteErr is NULL, then this is not a recursive reference. + ** In this case, proceed. */ + if( pCte->zCteErr ){ + sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName); + return SQLITE_ERROR; + } + if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR; + + assert( pFrom->pTab==0 ); + pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); + if( pTab==0 ) return WRC_Abort; + pTab->nTabRef = 1; + pTab->zName = sqlite3DbStrDup(db, pCte->zName); + pTab->iPKey = -1; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; + pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); + if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; + assert( pFrom->pSelect ); + + /* Check if this is a recursive CTE. */ + pSel = pFrom->pSelect; + bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); + if( bMayRecursive ){ + int i; + SrcList *pSrc = pFrom->pSelect->pSrc; + for(i=0; inSrc; i++){ + struct SrcList_item *pItem = &pSrc->a[i]; + if( pItem->zDatabase==0 + && pItem->zName!=0 + && 0==sqlite3StrICmp(pItem->zName, pCte->zName) + ){ + pItem->pTab = pTab; + pItem->fg.isRecursive = 1; + pTab->nTabRef++; + pSel->selFlags |= SF_Recursive; + } + } + } + + /* Only one recursive reference is permitted. */ + if( pTab->nTabRef>2 ){ + sqlite3ErrorMsg( + pParse, "multiple references to recursive table: %s", pCte->zName + ); + return SQLITE_ERROR; + } + assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); + + pCte->zCteErr = "circular reference: %s"; + pSavedWith = pParse->pWith; + pParse->pWith = pWith; + if( bMayRecursive ){ + Select *pPrior = pSel->pPrior; + assert( pPrior->pWith==0 ); + pPrior->pWith = pSel->pWith; + sqlite3WalkSelect(pWalker, pPrior); + pPrior->pWith = 0; + }else{ + sqlite3WalkSelect(pWalker, pSel); + } + pParse->pWith = pWith; + + for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); + pEList = pLeft->pEList; + if( pCte->pCols ){ + if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){ + sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns", + pCte->zName, pEList->nExpr, pCte->pCols->nExpr + ); + pParse->pWith = pSavedWith; + return SQLITE_ERROR; + } + pEList = pCte->pCols; + } + + sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol); + if( bMayRecursive ){ + if( pSel->selFlags & SF_Recursive ){ + pCte->zCteErr = "multiple recursive references: %s"; + }else{ + pCte->zCteErr = "recursive reference in a subquery: %s"; + } + sqlite3WalkSelect(pWalker, pSel); + } + pCte->zCteErr = 0; + pParse->pWith = pSavedWith; + } + + return SQLITE_OK; +} +#endif + +#ifndef SQLITE_OMIT_CTE +/* +** If the SELECT passed as the second argument has an associated WITH +** clause, pop it from the stack stored as part of the Parse object. +** +** This function is used as the xSelectCallback2() callback by +** sqlite3SelectExpand() when walking a SELECT tree to resolve table +** names and other FROM clause elements. +*/ +static void selectPopWith(Walker *pWalker, Select *p){ + Parse *pParse = pWalker->pParse; + if( pParse->pWith && p->pPrior==0 ){ + With *pWith = findRightmost(p)->pWith; + if( pWith!=0 ){ + assert( pParse->pWith==pWith ); + pParse->pWith = pWith->pOuter; + } + } +} +#else +#define selectPopWith 0 +#endif + +/* +** This routine is a Walker callback for "expanding" a SELECT statement. +** "Expanding" means to do the following: +** +** (1) Make sure VDBE cursor numbers have been assigned to every +** element of the FROM clause. +** +** (2) Fill in the pTabList->a[].pTab fields in the SrcList that +** defines FROM clause. When views appear in the FROM clause, +** fill pTabList->a[].pSelect with a copy of the SELECT statement +** that implements the view. A copy is made of the view's SELECT +** statement so that we can freely modify or delete that statement +** without worrying about messing up the persistent representation +** of the view. +** +** (3) Add terms to the WHERE clause to accommodate the NATURAL keyword +** on joins and the ON and USING clause of joins. +** +** (4) Scan the list of columns in the result set (pEList) looking +** for instances of the "*" operator or the TABLE.* operator. +** If found, expand each "*" to be every column in every table +** and TABLE.* to be every column in TABLE. +** +*/ +static int selectExpander(Walker *pWalker, Select *p){ + Parse *pParse = pWalker->pParse; + int i, j, k; + SrcList *pTabList; + ExprList *pEList; + struct SrcList_item *pFrom; + sqlite3 *db = pParse->db; + Expr *pE, *pRight, *pExpr; + u16 selFlags = p->selFlags; + + p->selFlags |= SF_Expanded; + if( db->mallocFailed ){ + return WRC_Abort; + } + if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){ + return WRC_Prune; + } + pTabList = p->pSrc; + pEList = p->pEList; + if( p->pWith ){ + sqlite3WithPush(pParse, p->pWith, 0); + } + + /* Make sure cursor numbers have been assigned to all entries in + ** the FROM clause of the SELECT statement. + */ + sqlite3SrcListAssignCursors(pParse, pTabList); + + /* Look up every table named in the FROM clause of the select. If + ** an entry of the FROM clause is a subquery instead of a table or view, + ** then create a transient table structure to describe the subquery. + */ + for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ + Table *pTab; + assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); + if( pFrom->fg.isRecursive ) continue; + assert( pFrom->pTab==0 ); +#ifndef SQLITE_OMIT_CTE + if( withExpand(pWalker, pFrom) ) return WRC_Abort; + if( pFrom->pTab ) {} else +#endif + if( pFrom->zName==0 ){ +#ifndef SQLITE_OMIT_SUBQUERY + Select *pSel = pFrom->pSelect; + /* A sub-query in the FROM clause of a SELECT */ + assert( pSel!=0 ); + assert( pFrom->pTab==0 ); + if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; + 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); + while( pSel->pPrior ){ pSel = pSel->pPrior; } + sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); + pTab->iPKey = -1; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + pTab->tabFlags |= TF_Ephemeral; +#endif + }else{ + /* An ordinary table or view name in the FROM clause */ + assert( pFrom->pTab==0 ); + pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); + if( pTab==0 ) return WRC_Abort; + if( pTab->nTabRef>=0xffff ){ + sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", + pTab->zName); + pFrom->pTab = 0; + return WRC_Abort; + } + pTab->nTabRef++; + if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){ + return WRC_Abort; + } +#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) + if( IsVirtual(pTab) || pTab->pSelect ){ + i16 nCol; + if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; + assert( pFrom->pSelect==0 ); + pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); + sqlite3SelectSetName(pFrom->pSelect, pTab->zName); + nCol = pTab->nCol; + pTab->nCol = -1; + sqlite3WalkSelect(pWalker, pFrom->pSelect); + pTab->nCol = nCol; + } +#endif + } + + /* Locate the index named by the INDEXED BY clause, if any. */ + if( sqlite3IndexedByLookup(pParse, pFrom) ){ + return WRC_Abort; + } + } + + /* Process NATURAL keywords, and ON and USING clauses of joins. + */ + if( db->mallocFailed || sqliteProcessJoin(pParse, p) ){ + return WRC_Abort; + } + + /* For every "*" that occurs in the column list, insert the names of + ** all columns in all tables. And for every TABLE.* insert the names + ** of all columns in TABLE. The parser inserted a special expression + ** with the TK_ASTERISK operator for each "*" that it found in the column + ** list. The following code just has to locate the TK_ASTERISK + ** expressions and expand each one to the list of all columns in + ** all tables. + ** + ** The first loop just checks to see if there are any "*" operators + ** that need expanding. + */ + for(k=0; knExpr; k++){ + pE = pEList->a[k].pExpr; + if( pE->op==TK_ASTERISK ) break; + assert( pE->op!=TK_DOT || pE->pRight!=0 ); + assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); + if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break; + } + if( knExpr ){ + /* + ** If we get here it means the result set contains one or more "*" + ** operators that need to be expanded. Loop through each expression + ** in the result set and expand them one by one. + */ + struct ExprList_item *a = pEList->a; + ExprList *pNew = 0; + int flags = pParse->db->flags; + int longNames = (flags & SQLITE_FullColNames)!=0 + && (flags & SQLITE_ShortColNames)==0; + + for(k=0; knExpr; k++){ + pE = a[k].pExpr; + pRight = pE->pRight; + assert( pE->op!=TK_DOT || pRight!=0 ); + if( pE->op!=TK_ASTERISK + && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK) + ){ + /* This particular expression does not need to be expanded. + */ + pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); + if( pNew ){ + pNew->a[pNew->nExpr-1].zName = a[k].zName; + pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan; + a[k].zName = 0; + a[k].zSpan = 0; + } + a[k].pExpr = 0; + }else{ + /* This expression is a "*" or a "TABLE.*" and needs to be + ** expanded. */ + int tableSeen = 0; /* Set to 1 when TABLE matches */ + char *zTName = 0; /* text of name of TABLE */ + if( pE->op==TK_DOT ){ + assert( pE->pLeft!=0 ); + assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); + zTName = pE->pLeft->u.zToken; + } + for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ + Table *pTab = pFrom->pTab; + Select *pSub = pFrom->pSelect; + char *zTabName = pFrom->zAlias; + const char *zSchemaName = 0; + int iDb; + if( zTabName==0 ){ + zTabName = pTab->zName; + } + if( db->mallocFailed ) break; + if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){ + pSub = 0; + if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ + continue; + } + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; + } + for(j=0; jnCol; j++){ + char *zName = pTab->aCol[j].zName; + char *zColname; /* The computed column name */ + char *zToFree; /* Malloced string that needs to be freed */ + Token sColname; /* Computed column name as a token */ + + assert( zName ); + if( zTName && pSub + && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0 + ){ + continue; + } + + /* If a column is marked as 'hidden', omit it from the expanded + ** result-set list unless the SELECT has the SF_IncludeHidden + ** bit set. + */ + if( (p->selFlags & SF_IncludeHidden)==0 + && IsHiddenColumn(&pTab->aCol[j]) + ){ + continue; + } + tableSeen = 1; + + if( i>0 && zTName==0 ){ + if( (pFrom->fg.jointype & JT_NATURAL)!=0 + && tableAndColumnIndex(pTabList, i, zName, 0, 0) + ){ + /* In a NATURAL join, omit the join columns from the + ** table to the right of the join */ + continue; + } + if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){ + /* In a join with a USING clause, omit columns in the + ** using clause from the table on the right. */ + continue; + } + } + pRight = sqlite3Expr(db, TK_ID, zName); + zColname = zName; + zToFree = 0; + if( longNames || pTabList->nSrc>1 ){ + Expr *pLeft; + pLeft = sqlite3Expr(db, TK_ID, zTabName); + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); + if( zSchemaName ){ + pLeft = sqlite3Expr(db, TK_ID, zSchemaName); + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr); + } + if( longNames ){ + zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); + zToFree = zColname; + } + }else{ + pExpr = pRight; + } + pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); + sqlite3TokenInit(&sColname, zColname); + sqlite3ExprListSetName(pParse, pNew, &sColname, 0); + if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){ + struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; + if( pSub ){ + pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan); + testcase( pX->zSpan==0 ); + }else{ + pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s", + zSchemaName, zTabName, zColname); + testcase( pX->zSpan==0 ); + } + pX->bSpanIsTab = 1; + } + sqlite3DbFree(db, zToFree); + } + } + if( !tableSeen ){ + if( zTName ){ + sqlite3ErrorMsg(pParse, "no such table: %s", zTName); + }else{ + sqlite3ErrorMsg(pParse, "no tables specified"); + } + } + } + } + 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; +} + +/* +** No-op routine for the parse-tree walker. +** +** When this routine is the Walker.xExprCallback then expression trees +** are walked without any actions being taken at each node. Presumably, +** when this routine is used for Walker.xExprCallback then +** Walker.xSelectCallback is set to do something useful for every +** subquery in the parser tree. +*/ +SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + return WRC_Continue; +} + +/* +** This routine "expands" a SELECT statement and all of its subqueries. +** For additional information on what it means to "expand" a SELECT +** statement, see the comment on the selectExpand worker callback above. +** +** Expanding a SELECT statement is the first step in processing a +** SELECT statement. The SELECT statement must be expanded before +** name resolution is performed. +** +** If anything goes wrong, an error message is written into pParse. +** The calling function can detect the problem by looking at pParse->nErr +** and/or pParse->db->mallocFailed. +*/ +static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = sqlite3ExprWalkNoop; + w.pParse = pParse; + if( pParse->hasCompound ){ + w.xSelectCallback = convertCompoundSelectToSubquery; + sqlite3WalkSelect(&w, pSelect); + } + w.xSelectCallback = selectExpander; + w.xSelectCallback2 = selectPopWith; + sqlite3WalkSelect(&w, pSelect); +} + + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() +** interface. +** +** For each FROM-clause subquery, add Column.zType and Column.zColl +** information to the Table structure that represents the result set +** of that subquery. +** +** The Table structure that represents the result set was constructed +** by selectExpander() but the type and collation information was omitted +** at that point because identifiers had not yet been resolved. This +** routine is called after identifier resolution. +*/ +static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ + Parse *pParse; + int i; + SrcList *pTabList; + struct SrcList_item *pFrom; + + assert( p->selFlags & SF_Resolved ); + assert( (p->selFlags & SF_HasTypeInfo)==0 ); + p->selFlags |= SF_HasTypeInfo; + pParse = pWalker->pParse; + pTabList = p->pSrc; + for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ + Table *pTab = pFrom->pTab; + assert( pTab!=0 ); + if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ + /* A sub-query in the FROM clause of a SELECT */ + Select *pSel = pFrom->pSelect; + if( pSel ){ + while( pSel->pPrior ) pSel = pSel->pPrior; + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel); + } + } + } +} +#endif + + +/* +** This routine adds datatype and collating sequence information to +** the Table structures of all FROM-clause subqueries in a +** SELECT statement. +** +** Use this routine after name resolution. +*/ +static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ +#ifndef SQLITE_OMIT_SUBQUERY + Walker w; + memset(&w, 0, sizeof(w)); + w.xSelectCallback2 = selectAddSubqueryTypeInfo; + w.xExprCallback = sqlite3ExprWalkNoop; + w.pParse = pParse; + sqlite3WalkSelect(&w, pSelect); +#endif +} + + +/* +** This routine sets up a SELECT statement for processing. The +** following is accomplished: +** +** * VDBE Cursor numbers are assigned to all FROM-clause terms. +** * Ephemeral Table objects are created for all FROM-clause subqueries. +** * ON and USING clauses are shifted into WHERE statements +** * Wildcards "*" and "TABLE.*" in result sets are expanded. +** * Identifiers in expression are matched to tables. +** +** This routine acts recursively on all subqueries within the SELECT. +*/ +SQLITE_PRIVATE void sqlite3SelectPrep( + Parse *pParse, /* The parser context */ + 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; + if( p->selFlags & SF_HasTypeInfo ) return; + sqlite3SelectExpand(pParse, p); + if( pParse->nErr || db->mallocFailed ) return; + sqlite3ResolveSelectNames(pParse, p, pOuterNC); + if( pParse->nErr || db->mallocFailed ) return; + sqlite3SelectAddTypeInfo(pParse, p); +} + +/* +** Reset the aggregate accumulator. +** +** The aggregate accumulator is a set of memory cells that hold +** intermediate results while calculating an aggregate. This +** routine generates code that stores NULLs in all of those memory +** cells. +*/ +static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ + Vdbe *v = pParse->pVdbe; + int i; + struct AggInfo_func *pFunc; + int nReg = pAggInfo->nFunc + pAggInfo->nColumn; + if( nReg==0 ) return; +#ifdef SQLITE_DEBUG + /* Verify that all AggInfo registers are within the range specified by + ** AggInfo.mnReg..AggInfo.mxReg */ + assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 ); + for(i=0; inColumn; i++){ + assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg + && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg ); + } + for(i=0; inFunc; i++){ + assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg + && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg ); + } +#endif + sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg); + for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ + if( pFunc->iDistinct>=0 ){ + Expr *pE = pFunc->pExpr; + assert( !ExprHasProperty(pE, EP_xIsSelect) ); + if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ + sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " + "argument"); + pFunc->iDistinct = -1; + }else{ + KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0); + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, + (char*)pKeyInfo, P4_KEYINFO); + } + } + } +} + +/* +** Invoke the OP_AggFinalize opcode for every aggregate function +** in the AggInfo structure. +*/ +static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ + Vdbe *v = pParse->pVdbe; + int i; + struct AggInfo_func *pF; + for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ + ExprList *pList = pF->pExpr->x.pList; + assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0); + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); + } +} + +/* +** Update the accumulator memory cells for an aggregate based on +** the current cursor position. +*/ +static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ + Vdbe *v = pParse->pVdbe; + int i; + int regHit = 0; + int addrHitTest = 0; + struct AggInfo_func *pF; + struct AggInfo_col *pC; + + pAggInfo->directMode = 1; + for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ + int nArg; + int addrNext = 0; + int regAgg; + ExprList *pList = pF->pExpr->x.pList; + assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + if( pList ){ + nArg = pList->nExpr; + regAgg = sqlite3GetTempRange(pParse, nArg); + sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP); + }else{ + nArg = 0; + regAgg = 0; + } + if( pF->iDistinct>=0 ){ + addrNext = sqlite3VdbeMakeLabel(v); + testcase( nArg==0 ); /* Error condition */ + testcase( nArg>1 ); /* Also an error */ + codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); + } + if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ + CollSeq *pColl = 0; + struct ExprList_item *pItem; + int j; + assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */ + for(j=0, pItem=pList->a; !pColl && jpExpr); + } + if( !pColl ){ + pColl = pParse->db->pDfltColl; + } + if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; + sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); + } + sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem); + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)nArg); + sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg); + sqlite3ReleaseTempRange(pParse, regAgg, nArg); + if( addrNext ){ + sqlite3VdbeResolveLabel(v, addrNext); + sqlite3ExprCacheClear(pParse); + } + } + + /* Before populating the accumulator registers, clear the column cache. + ** Otherwise, if any of the required column values are already present + ** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value + ** to pC->iMem. But by the time the value is used, the original register + ** may have been used, invalidating the underlying buffer holding the + ** text or blob value. See ticket [883034dcb5]. + ** + ** Another solution would be to change the OP_SCopy used to copy cached + ** values to an OP_Copy. + */ + if( regHit ){ + addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); + } + sqlite3ExprCacheClear(pParse); + for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ + sqlite3ExprCode(pParse, pC->pExpr, pC->iMem); + } + pAggInfo->directMode = 0; + sqlite3ExprCacheClear(pParse); + if( addrHitTest ){ + sqlite3VdbeJumpHere(v, addrHitTest); + } +} + +/* +** Add a single OP_Explain instruction to the VDBE to explain a simple +** count(*) query ("SELECT count(*) FROM pTab"). +*/ +#ifndef SQLITE_OMIT_EXPLAIN +static void explainSimpleCount( + Parse *pParse, /* Parse context */ + Table *pTab, /* Table being queried */ + Index *pIdx /* Index used to optimize scan, or NULL */ +){ + if( pParse->explain==2 ){ + int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); + char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", + pTab->zName, + bCover ? " USING COVERING INDEX " : "", + bCover ? pIdx->zName : "" + ); + sqlite3VdbeAddOp4( + pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC + ); + } +} +#else +# define explainSimpleCount(a,b,c) +#endif + +/* +** Context object for havingToWhereExprCb(). +*/ +struct HavingToWhereCtx { + Expr **ppWhere; + ExprList *pGroupBy; +}; + +/* +** sqlite3WalkExpr() callback used by havingToWhere(). +** +** If the node passed to the callback is a TK_AND node, return +** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes. +** +** Otherwise, return WRC_Prune. In this case, also check if the +** sub-expression matches the criteria for being moved to the WHERE +** clause. If so, add it to the WHERE clause and replace the sub-expression +** within the HAVING expression with a constant "1". +*/ +static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ + if( pExpr->op!=TK_AND ){ + struct HavingToWhereCtx *p = pWalker->u.pHavingCtx; + if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){ + sqlite3 *db = pWalker->pParse->db; + Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0); + if( pNew ){ + Expr *pWhere = *(p->ppWhere); + SWAP(Expr, *pNew, *pExpr); + pNew = sqlite3ExprAnd(db, pWhere, pNew); + *(p->ppWhere) = pNew; + } + } + return WRC_Prune; + } + return WRC_Continue; +} + +/* +** Transfer eligible terms from the HAVING clause of a query, which is +** processed after grouping, to the WHERE clause, which is processed before +** grouping. For example, the query: +** +** SELECT * FROM WHERE a=? GROUP BY b HAVING b=? AND c=? +** +** can be rewritten as: +** +** SELECT * FROM WHERE a=? AND b=? GROUP BY b HAVING c=? +** +** A term of the HAVING expression is eligible for transfer if it consists +** entirely of constants and expressions that are also GROUP BY terms that +** use the "BINARY" collation sequence. +*/ +static void havingToWhere( + Parse *pParse, + ExprList *pGroupBy, + Expr *pHaving, + Expr **ppWhere +){ + struct HavingToWhereCtx sCtx; + Walker sWalker; + + sCtx.ppWhere = ppWhere; + sCtx.pGroupBy = pGroupBy; + + memset(&sWalker, 0, sizeof(sWalker)); + sWalker.pParse = pParse; + sWalker.xExprCallback = havingToWhereExprCb; + sWalker.u.pHavingCtx = &sCtx; + sqlite3WalkExpr(&sWalker, pHaving); +} + +/* +** Check to see if the pThis entry of pTabList is a self-join of a prior view. +** If it is, then return the SrcList_item for the prior view. If it is not, +** then return 0. +*/ +static struct SrcList_item *isSelfJoinView( + SrcList *pTabList, /* Search for self-joins in this FROM clause */ + struct SrcList_item *pThis /* Search for prior reference to this subquery */ +){ + struct SrcList_item *pItem; + for(pItem = pTabList->a; pItempSelect==0 ) continue; + if( pItem->fg.viaCoroutine ) continue; + if( pItem->zName==0 ) continue; + if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue; + if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; + if( sqlite3ExprCompare(pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) ){ + /* The view was modified by some other optimization such as + ** pushDownWhereTerms() */ + continue; + } + return pItem; + } + return 0; +} + +/* +** Generate code for the SELECT statement given in the p argument. +** +** The results are returned according to the SelectDest structure. +** See comments in sqliteInt.h for further information. +** +** This routine returns the number of errors. If any errors are +** encountered, then an appropriate error message is left in +** pParse->zErrMsg. +** +** This routine does NOT free the Select structure passed in. The +** calling function needs to do that. +*/ +SQLITE_PRIVATE int sqlite3Select( + Parse *pParse, /* The parser context */ + Select *p, /* The SELECT statement being coded. */ + SelectDest *pDest /* What to do with the query results */ +){ + int i, j; /* Loop counters */ + WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */ + Vdbe *v; /* The virtual machine under construction */ + int isAgg; /* True for select lists like "count(*)" */ + ExprList *pEList = 0; /* List of columns to extract. */ + SrcList *pTabList; /* List of tables to select from */ + Expr *pWhere; /* The WHERE clause. May be NULL */ + ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ + Expr *pHaving; /* The HAVING clause. May be NULL */ + int rc = 1; /* Value to return from this function */ + DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ + SortCtx sSort; /* Info on how to code the ORDER BY clause */ + AggInfo sAggInfo; /* Information used by aggregate queries */ + int iEnd; /* Address of the end of the query */ + sqlite3 *db; /* The database connection */ + +#ifndef SQLITE_OMIT_EXPLAIN + int iRestoreSelectId = pParse->iSelectId; + pParse->iSelectId = pParse->iNextSelectId++; +#endif + + db = pParse->db; + if( p==0 || db->mallocFailed || pParse->nErr ){ + return 1; + } + if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; + memset(&sAggInfo, 0, sizeof(sAggInfo)); +#if SELECTTRACE_ENABLED + pParse->nSelectIndent++; + SELECTTRACE(1,pParse,p, ("begin processing:\n")); + if( sqlite3SelectTrace & 0x100 ){ + sqlite3TreeViewSelect(0, p, 0); + } +#endif + + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); + assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); + if( IgnorableOrderby(pDest) ){ + assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || + pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || + pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo || + pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo); + /* If ORDER BY makes no difference in the output then neither does + ** DISTINCT so it can be removed too. */ + sqlite3ExprListDelete(db, p->pOrderBy); + p->pOrderBy = 0; + p->selFlags &= ~SF_Distinct; + } + sqlite3SelectPrep(pParse, p, 0); + memset(&sSort, 0, sizeof(sSort)); + sSort.pOrderBy = p->pOrderBy; + pTabList = p->pSrc; + if( pParse->nErr || db->mallocFailed ){ + goto select_end; + } + assert( p->pEList!=0 ); + isAgg = (p->selFlags & SF_Aggregate)!=0; +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p, ("after name resolution:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + + /* Try to flatten subqueries in the FROM clause up into the main query + */ +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + for(i=0; !p->pPrior && inSrc; i++){ + struct SrcList_item *pItem = &pTabList->a[i]; + Select *pSub = pItem->pSelect; + int isAggSub; + Table *pTab = pItem->pTab; + if( pSub==0 ) continue; + + /* Catch mismatch in the declared columns of a view and the number of + ** columns in the SELECT on the RHS */ + if( pTab->nCol!=pSub->pEList->nExpr ){ + sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d", + pTab->nCol, pTab->zName, pSub->pEList->nExpr); + goto select_end; + } + + isAggSub = (pSub->selFlags & SF_Aggregate)!=0; + if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ + /* This subquery can be absorbed into its parent. */ + if( isAggSub ){ + isAgg = 1; + p->selFlags |= SF_Aggregate; + } + i = -1; + } + pTabList = p->pSrc; + if( db->mallocFailed ) goto select_end; + if( !IgnorableOrderby(pDest) ){ + sSort.pOrderBy = p->pOrderBy; + } + } +#endif + + /* Get a pointer the VDBE under construction, allocating a new VDBE if one + ** does not already exist */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto select_end; + +#ifndef SQLITE_OMIT_COMPOUND_SELECT + /* Handle compound SELECT statements using the separate multiSelect() + ** procedure. + */ + if( p->pPrior ){ + rc = multiSelect(pParse, p, pDest); + explainSetInteger(pParse->iSelectId, iRestoreSelectId); +#if SELECTTRACE_ENABLED + SELECTTRACE(1,pParse,p,("end compound-select processing\n")); + pParse->nSelectIndent--; +#endif + return rc; + } +#endif + + /* For each term in the FROM clause, do two things: + ** (1) Authorized unreferenced tables + ** (2) Generate code for all sub-queries + */ + for(i=0; inSrc; i++){ + struct SrcList_item *pItem = &pTabList->a[i]; + SelectDest dest; + Select *pSub; + + /* 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."" + ** + ** 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, + ** 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. + */ + if( pItem->colUsed==0 ){ + sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); + } + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + /* Generate code for all sub-queries in the FROM clause + */ + pSub = pItem->pSelect; + if( pSub==0 ) continue; + + /* Sometimes the code for a subquery will be generated more than + ** once, if the subquery is part of the WHERE clause in a LEFT JOIN, + ** for example. In that case, do not regenerate the code to manifest + ** a view or the co-routine to implement a view. The first instance + ** is sufficient, though the subroutine to manifest the view does need + ** to be invoked again. */ + if( pItem->addrFillSub ){ + if( pItem->fg.viaCoroutine==0 ){ + /* The subroutine that manifests the view might be a one-time routine, + ** or it might need to be rerun on each iteration because it + ** encodes a correlated subquery. */ + testcase( sqlite3VdbeGetOp(v, pItem->addrFillSub)->opcode==OP_Once ); + sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); + } + continue; + } + + /* Increment Parse.nHeight by the height of the largest expression + ** tree referred to by this, the parent select. The child select + ** may contain expression trees of at most + ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit + ** more conservative than necessary, but much easier than enforcing + ** an exact limit. + */ + pParse->nHeight += sqlite3SelectExprHeight(p); + + /* Make copies of constant WHERE-clause terms in the outer query down + ** inside the subquery. This can help the subquery to run more efficiently. + */ + if( (pItem->fg.jointype & JT_OUTER)==0 + && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor) + ){ +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + } + + /* 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. + ** + ** TODO: Are there other reasons beside (1) to use a co-routine + ** implementation? + */ + if( i==0 + && (pTabList->nSrc==1 + || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ + && (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)); + pItem->addrFillSub = addrTop; + sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + sqlite3Select(pParse, pSub, &dest); + pItem->pTab->nRowLogEst = pSub->nSelectRow; + pItem->fg.viaCoroutine = 1; + pItem->regResult = dest.iSdst; + sqlite3VdbeEndCoroutine(v, pItem->regReturn); + sqlite3VdbeJumpHere(v, addrTop-1); + sqlite3ClearTempRegCache(pParse); + }else{ + /* Generate a subroutine that will fill an ephemeral table with + ** the content of this subquery. pItem->addrFillSub will point + ** to the address of the generated subroutine. pItem->regReturn + ** is a register allocated to hold the subroutine return address + */ + int topAddr; + int onceAddr = 0; + int retAddr; + struct SrcList_item *pPrior; + + assert( pItem->addrFillSub==0 ); + pItem->regReturn = ++pParse->nMem; + topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); + pItem->addrFillSub = topAddr+1; + if( pItem->fg.isCorrelated==0 ){ + /* If the subquery is not correlated and if we are not inside of + ** a trigger, then we only need to compute the value of the subquery + ** once. */ + onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); + }else{ + VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); + } + pPrior = isSelfJoinView(pTabList, pItem); + if( pPrior ){ + sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); + }else{ + sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + sqlite3Select(pParse, pSub, &dest); + } + pItem->pTab->nRowLogEst = pSub->nSelectRow; + if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); + retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); + VdbeComment((v, "end %s", pItem->pTab->zName)); + sqlite3VdbeChangeP1(v, topAddr, retAddr); + sqlite3ClearTempRegCache(pParse); + } + if( db->mallocFailed ) goto select_end; + pParse->nHeight -= sqlite3SelectExprHeight(p); +#endif + } + + /* Various elements of the SELECT copied into local variables for + ** convenience */ + pEList = p->pEList; + pWhere = p->pWhere; + pGroupBy = p->pGroupBy; + pHaving = p->pHaving; + sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + + /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and + ** if the select-list is the same as the ORDER BY list, then this query + ** can be rewritten as a GROUP BY. In other words, this: + ** + ** SELECT DISTINCT xyz FROM ... ORDER BY xyz + ** + ** is transformed to: + ** + ** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz + ** + ** The second form is preferred as a single index (or temp-table) may be + ** used for both the ORDER BY and DISTINCT processing. As originally + ** written the query must use a temp-table for at least one of the ORDER + ** BY and DISTINCT, and an index or separate temp-table for the other. + */ + if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct + && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 + ){ + p->selFlags &= ~SF_Distinct; + pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); + /* Notice that even thought SF_Distinct has been cleared from p->selFlags, + ** the sDistinct.isTnct is still set. Hence, isTnct represents the + ** original setting of the SF_Distinct flag, not the current setting */ + assert( sDistinct.isTnct ); + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + } + + /* If there is an ORDER BY clause, then create an ephemeral index to + ** do the sorting. But this sorting ephemeral index might end up + ** being unused if the data can be extracted in pre-sorted order. + ** If that is the case, then the OP_OpenEphemeral instruction will be + ** changed to an OP_Noop once we figure out that the sorting index is + ** not needed. The sSort.addrSortIndex variable is used to facilitate + ** that change. + */ + if( sSort.pOrderBy ){ + KeyInfo *pKeyInfo; + pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr); + sSort.iECursor = pParse->nTab++; + sSort.addrSortIndex = + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0, + (char*)pKeyInfo, P4_KEYINFO + ); + }else{ + sSort.addrSortIndex = -1; + } + + /* If the output is destined for a temporary table, open that table. + */ + if( pDest->eDest==SRT_EphemTab ){ + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); + } + + /* Set the limiter. + */ + iEnd = sqlite3VdbeMakeLabel(v); + if( (p->selFlags & SF_FixedLimit)==0 ){ + p->nSelectRow = 320; /* 4 billion rows */ + } + computeLimitRegisters(pParse, p, iEnd); + if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ + sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen); + sSort.sortFlags |= SORTFLAG_UseSorter; + } + + /* Open an ephemeral index to use for the distinct set. + */ + if( p->selFlags & SF_Distinct ){ + sDistinct.tabTnct = pParse->nTab++; + sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + sDistinct.tabTnct, 0, 0, + (char*)keyInfoFromExprList(pParse, p->pEList,0,0), + P4_KEYINFO); + sqlite3VdbeChangeP5(v, BTREE_UNORDERED); + sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; + }else{ + sDistinct.eTnctType = WHERE_DISTINCT_NOOP; + } + + if( !isAgg && pGroupBy==0 ){ + /* No aggregate functions and no GROUP BY clause */ + u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); + assert( WHERE_USE_LIMIT==SF_FixedLimit ); + wctrlFlags |= p->selFlags & SF_FixedLimit; + + /* Begin the database scan. */ + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, + p->pEList, wctrlFlags, p->nSelectRow); + if( pWInfo==0 ) goto select_end; + if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ + p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); + } + if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ + sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); + } + if( sSort.pOrderBy ){ + sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); + sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo); + if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ + sSort.pOrderBy = 0; + } + } + + /* If sorting index that was created by a prior OP_OpenEphemeral + ** instruction ended up not being needed, then change the OP_OpenEphemeral + ** into an OP_Noop. + */ + if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){ + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); + } + + /* Use the standard inner loop. */ + selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest, + sqlite3WhereContinueLabel(pWInfo), + sqlite3WhereBreakLabel(pWInfo)); + + /* End the database scan loop. + */ + sqlite3WhereEnd(pWInfo); + }else{ + /* This case when there exist aggregate functions or a GROUP BY clause + ** or both */ + NameContext sNC; /* Name context for processing aggregate information */ + int iAMem; /* First Mem address for storing current GROUP BY */ + int iBMem; /* First Mem address for previous GROUP BY */ + int iUseFlag; /* Mem address holding flag indicating that at least + ** one row of the input to the aggregator has been + ** processed */ + int iAbortFlag; /* Mem address which causes query abort if positive */ + int groupBySort; /* Rows come from source in GROUP BY order */ + int addrEnd; /* End of processing for this SELECT */ + int sortPTab = 0; /* Pseudotable used to decode sorting results */ + int sortOut = 0; /* Output register from the sorter */ + int orderByGrp = 0; /* True if the GROUP BY and ORDER BY are the same */ + + /* Remove any and all aliases between the result set and the + ** GROUP BY clause. + */ + if( pGroupBy ){ + int k; /* Loop counter */ + struct ExprList_item *pItem; /* For looping over expression in a list */ + + for(k=p->pEList->nExpr, pItem=p->pEList->a; k>0; k--, pItem++){ + pItem->u.x.iAlias = 0; + } + for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){ + pItem->u.x.iAlias = 0; + } + assert( 66==sqlite3LogEst(100) ); + if( p->nSelectRow>66 ) p->nSelectRow = 66; + }else{ + assert( 0==sqlite3LogEst(1) ); + p->nSelectRow = 0; + } + + /* If there is both a GROUP BY and an ORDER BY clause and they are + ** identical, then it may be possible to disable the ORDER BY clause + ** on the grounds that the GROUP BY will cause elements to come out + ** in the correct order. It also may not - the GROUP BY might use a + ** database index that causes rows to be grouped together as required + ** but not actually sorted. Either way, record the fact that the + ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp + ** variable. */ + if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ + orderByGrp = 1; + } + + /* Create a label to jump to when we want to abort the query */ + addrEnd = sqlite3VdbeMakeLabel(v); + + /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in + ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the + ** SELECT statement. + */ + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + sNC.pSrcList = pTabList; + sNC.pAggInfo = &sAggInfo; + sAggInfo.mnReg = pParse->nMem+1; + sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; + sAggInfo.pGroupBy = pGroupBy; + sqlite3ExprAnalyzeAggList(&sNC, pEList); + sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); + if( pHaving ){ + if( pGroupBy ){ + assert( pWhere==p->pWhere ); + havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere); + pWhere = p->pWhere; + } + sqlite3ExprAnalyzeAggregates(&sNC, pHaving); + } + sAggInfo.nAccumulator = sAggInfo.nColumn; + for(i=0; ix.pList); + sNC.ncFlags &= ~NC_InAggFunc; + } + sAggInfo.mxReg = pParse->nMem; + if( db->mallocFailed ) goto select_end; + + /* Processing for aggregates with GROUP BY is very different and + ** much more complex than aggregates without a GROUP BY. + */ + if( pGroupBy ){ + KeyInfo *pKeyInfo; /* Keying information for the group by clause */ + int addr1; /* A-vs-B comparision jump */ + int addrOutputRow; /* Start of subroutine that outputs a result row */ + int regOutputRow; /* Return address register for output subroutine */ + int addrSetAbort; /* Set the abort flag and return */ + int addrTopOfLoop; /* Top of the input loop */ + int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ + int addrReset; /* Subroutine for resetting the accumulator */ + int regReset; /* Return address register for reset subroutine */ + + /* If there is a GROUP BY clause we might need a sorting index to + ** implement it. Allocate that sorting index now. If it turns out + ** that we do not need it after all, the OP_SorterOpen instruction + ** will be converted into a Noop. + */ + sAggInfo.sortingIdx = pParse->nTab++; + pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn); + addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, + sAggInfo.sortingIdx, sAggInfo.nSortingColumn, + 0, (char*)pKeyInfo, P4_KEYINFO); + + /* Initialize memory locations used by GROUP BY aggregate processing + */ + iUseFlag = ++pParse->nMem; + iAbortFlag = ++pParse->nMem; + regOutputRow = ++pParse->nMem; + addrOutputRow = sqlite3VdbeMakeLabel(v); + regReset = ++pParse->nMem; + addrReset = sqlite3VdbeMakeLabel(v); + iAMem = pParse->nMem + 1; + pParse->nMem += pGroupBy->nExpr; + iBMem = pParse->nMem + 1; + pParse->nMem += pGroupBy->nExpr; + sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag); + VdbeComment((v, "clear abort flag")); + sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); + VdbeComment((v, "indicate accumulator empty")); + sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1); + + /* Begin a loop that will extract all source rows in GROUP BY order. + ** This might involve two separate loops with an OP_Sort in between, or + ** it might be a single loop that uses an index to extract information + ** in the right order to begin with. + */ + sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, + WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 + ); + if( pWInfo==0 ) goto select_end; + if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ + /* The optimizer is able to deliver rows in group by order so + ** we do not have to sort. The OP_OpenEphemeral table will be + ** cancelled later because we still need to use the pKeyInfo + */ + groupBySort = 0; + }else{ + /* Rows are coming out in undetermined order. We have to push + ** each row into a sorting index, terminate the first loop, + ** then loop over the sorting index in order to get the output + ** in sorted order + */ + int regBase; + int regRecord; + int nCol; + int nGroupBy; + + explainTempTable(pParse, + (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? + "DISTINCT" : "GROUP BY"); + + groupBySort = 1; + nGroupBy = pGroupBy->nExpr; + nCol = nGroupBy; + j = nGroupBy; + for(i=0; i=j ){ + nCol++; + j++; + } + } + regBase = sqlite3GetTempRange(pParse, nCol); + sqlite3ExprCacheClear(pParse); + sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); + j = nGroupBy; + for(i=0; iiSorterColumn>=j ){ + int r1 = j + regBase; + sqlite3ExprCodeGetColumnToReg(pParse, + pCol->pTab, pCol->iColumn, pCol->iTable, r1); + j++; + } + } + regRecord = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); + sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord); + sqlite3ReleaseTempReg(pParse, regRecord); + sqlite3ReleaseTempRange(pParse, regBase, nCol); + sqlite3WhereEnd(pWInfo); + sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++; + sortOut = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); + sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd); + VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); + sAggInfo.useSortingIdx = 1; + sqlite3ExprCacheClear(pParse); + + } + + /* If the index or temporary table used by the GROUP BY sort + ** will naturally deliver rows in the order required by the ORDER BY + ** clause, cancel the ephemeral table open coded earlier. + ** + ** This is an optimization - the correct answer should result regardless. + ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to + ** disable this optimization for testing purposes. */ + if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder) + && (groupBySort || sqlite3WhereIsSorted(pWInfo)) + ){ + sSort.pOrderBy = 0; + sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); + } + + /* Evaluate the current GROUP BY terms and store in b0, b1, b2... + ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) + ** Then compare the current GROUP BY terms against the GROUP BY terms + ** from the previous row currently stored in a0, a1, a2... + */ + addrTopOfLoop = sqlite3VdbeCurrentAddr(v); + sqlite3ExprCacheClear(pParse); + if( groupBySort ){ + sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, + sortOut, sortPTab); + } + for(j=0; jnExpr; j++){ + if( groupBySort ){ + sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); + }else{ + sAggInfo.directMode = 1; + sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); + } + } + sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, + (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO); + addr1 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp3(v, OP_Jump, addr1+1, 0, addr1+1); VdbeCoverage(v); + + /* Generate code that runs whenever the GROUP BY changes. + ** Changes in the GROUP BY are detected by the previous code + ** block. If there were no changes, this block is skipped. + ** + ** This code copies current group by terms in b0,b1,b2,... + ** over to a0,a1,a2. It then calls the output subroutine + ** and resets the aggregate accumulator registers in preparation + ** for the next GROUP BY batch. + */ + sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); + VdbeComment((v, "output one row")); + sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v); + VdbeComment((v, "check abort flag")); + sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); + VdbeComment((v, "reset accumulator")); + + /* Update the aggregate accumulators based on the content of + ** the current row + */ + sqlite3VdbeJumpHere(v, addr1); + updateAccumulator(pParse, &sAggInfo); + sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); + VdbeComment((v, "indicate data in accumulator")); + + /* End of the loop + */ + if( groupBySort ){ + sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop); + VdbeCoverage(v); + }else{ + sqlite3WhereEnd(pWInfo); + sqlite3VdbeChangeToNoop(v, addrSortingIdx); + } + + /* Output the final row of result + */ + sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); + VdbeComment((v, "output final row")); + + /* Jump over the subroutines + */ + sqlite3VdbeGoto(v, addrEnd); + + /* Generate a subroutine that outputs a single row of the result + ** set. This subroutine first looks at the iUseFlag. If iUseFlag + ** is less than or equal to zero, the subroutine is a no-op. If + ** the processing calls for the query to abort, this subroutine + ** increments the iAbortFlag memory location before returning in + ** order to signal the caller to abort. + */ + addrSetAbort = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Integer, 1, iAbortFlag); + VdbeComment((v, "set abort flag")); + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); + sqlite3VdbeResolveLabel(v, addrOutputRow); + addrOutputRow = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); + VdbeCoverage(v); + VdbeComment((v, "Groupby result generator entry point")); + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); + finalizeAggFunctions(pParse, &sAggInfo); + sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); + selectInnerLoop(pParse, p, p->pEList, -1, &sSort, + &sDistinct, pDest, + addrOutputRow+1, addrSetAbort); + sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); + VdbeComment((v, "end groupby result generator")); + + /* Generate a subroutine that will reset the group-by accumulator + */ + sqlite3VdbeResolveLabel(v, addrReset); + resetAccumulator(pParse, &sAggInfo); + sqlite3VdbeAddOp1(v, OP_Return, regReset); + + } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ + else { + ExprList *pDel = 0; +#ifndef SQLITE_OMIT_BTREECOUNT + Table *pTab; + if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){ + /* If isSimpleCount() returns a pointer to a Table structure, then + ** the SQL statement is of the form: + ** + ** SELECT count(*) FROM + ** + ** where the Table structure returned represents table . + ** + ** This statement is so common that it is optimized specially. The + ** OP_Count instruction is executed either on the intkey table that + ** contains the data for table or on one of its indexes. It + ** is better to execute the op on an index, as indexes are almost + ** always spread across less pages than their corresponding tables. + */ + const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */ + Index *pIdx; /* Iterator variable */ + KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */ + Index *pBest = 0; /* Best index found so far */ + int iRoot = pTab->tnum; /* Root page of scanned b-tree */ + + sqlite3CodeVerifySchema(pParse, iDb); + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + + /* Search for the index that has the lowest scan cost. + ** + ** (2011-04-15) Do not do a full scan of an unordered index. + ** + ** (2013-10-03) Do not count the entries in a partial index. + ** + ** In practice the KeyInfo structure will not be used. It is only + ** passed to keep OP_OpenRead happy. + */ + if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->bUnordered==0 + && pIdx->szIdxRowszTabRow + && pIdx->pPartIdxWhere==0 + && (!pBest || pIdx->szIdxRowszIdxRow) + ){ + pBest = pIdx; + } + } + if( pBest ){ + iRoot = pBest->tnum; + pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pBest); + } + + /* Open a read-only cursor, execute the OP_Count, close the cursor. */ + sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1); + if( pKeyInfo ){ + sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO); + } + sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem); + sqlite3VdbeAddOp1(v, OP_Close, iCsr); + explainSimpleCount(pParse, pTab, pBest); + }else +#endif /* SQLITE_OMIT_BTREECOUNT */ + { + /* Check if the query is of one of the following forms: + ** + ** SELECT min(x) FROM ... + ** SELECT max(x) FROM ... + ** + ** If it is, then ask the code in where.c to attempt to sort results + ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause. + ** If where.c is able to produce results sorted in this order, then + ** add vdbe code to break out of the processing loop after the + ** first iteration (since the first iteration of the loop is + ** guaranteed to operate on the row with the minimum or maximum + ** value of x, the only row required). + ** + ** A special flag must be passed to sqlite3WhereBegin() to slightly + ** modify behavior as follows: + ** + ** + If the query is a "SELECT min(x)", then the loop coded by + ** where.c should not iterate over any values with a NULL value + ** for x. + ** + ** + The optimizer code in where.c (the thing that decides which + ** index or indices to use) should place a different priority on + ** satisfying the 'ORDER BY' clause than it does in other cases. + ** Refer to code and comments in where.c for details. + */ + ExprList *pMinMax = 0; + u8 flag = WHERE_ORDERBY_NORMAL; + + assert( p->pGroupBy==0 ); + assert( flag==0 ); + if( p->pHaving==0 ){ + flag = minMaxQuery(&sAggInfo, &pMinMax); + } + assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) ); + + if( flag ){ + pMinMax = sqlite3ExprListDup(db, pMinMax, 0); + pDel = pMinMax; + assert( db->mallocFailed || pMinMax!=0 ); + if( !db->mallocFailed ){ + pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; + pMinMax->a[0].pExpr->op = TK_COLUMN; + } + } + + /* This case runs if the aggregate has no GROUP BY clause. The + ** processing is much simpler since there is only a single row + ** of output. + */ + resetAccumulator(pParse, &sAggInfo); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax, 0,flag,0); + if( pWInfo==0 ){ + sqlite3ExprListDelete(db, pDel); + goto select_end; + } + updateAccumulator(pParse, &sAggInfo); + assert( pMinMax==0 || pMinMax->nExpr==1 ); + if( sqlite3WhereIsOrdered(pWInfo)>0 ){ + sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo)); + VdbeComment((v, "%s() by index", + (flag==WHERE_ORDERBY_MIN?"min":"max"))); + } + sqlite3WhereEnd(pWInfo); + finalizeAggFunctions(pParse, &sAggInfo); + } + + sSort.pOrderBy = 0; + sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); + selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, + pDest, addrEnd, addrEnd); + sqlite3ExprListDelete(db, pDel); + } + sqlite3VdbeResolveLabel(v, addrEnd); + + } /* endif aggregate query */ + + if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){ + explainTempTable(pParse, "DISTINCT"); + } + + /* If there is an ORDER BY clause, then we need to sort the results + ** and send them to the callback one by one. + */ + if( sSort.pOrderBy ){ + explainTempTable(pParse, + sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); + generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); + } + + /* Jump here to skip this query + */ + sqlite3VdbeResolveLabel(v, iEnd); + + /* The SELECT has been coded. If there is an error in the Parse structure, + ** set the return code to 1. Otherwise 0. */ + rc = (pParse->nErr>0); + + /* Control jumps to here if an error is encountered above, or upon + ** successful coding of the SELECT. + */ +select_end: + explainSetInteger(pParse->iSelectId, iRestoreSelectId); + + /* Identify column names if results of the SELECT are to be output. + */ + if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){ + generateColumnNames(pParse, pTabList, pEList); + } + + sqlite3DbFree(db, sAggInfo.aCol); + sqlite3DbFree(db, sAggInfo.aFunc); +#if SELECTTRACE_ENABLED + SELECTTRACE(1,pParse,p,("end processing\n")); + pParse->nSelectIndent--; +#endif + return rc; +} + +/************** End of select.c **********************************************/ +/************** Begin file table.c *******************************************/ +/* +** 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 the sqlite3_get_table() and sqlite3_free_table() +** interface routines. These are just wrappers around the main +** interface routine of sqlite3_exec(). +** +** These routines are in a separate files so that they will not be linked +** if they are not used. +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_GET_TABLE + +/* +** This structure is used to pass data from sqlite3_get_table() through +** to the callback function is uses to build the result. +*/ +typedef struct TabResult { + char **azResult; /* Accumulated output */ + char *zErrMsg; /* Error message text, if an error occurs */ + u32 nAlloc; /* Slots allocated for azResult[] */ + u32 nRow; /* Number of rows in the result */ + u32 nColumn; /* Number of columns in the result */ + u32 nData; /* Slots used in azResult[]. (nRow+1)*nColumn */ + int rc; /* Return code from sqlite3_exec() */ +} TabResult; + +/* +** This routine is called once for each row in the result table. Its job +** is to fill in the TabResult structure appropriately, allocating new +** memory as necessary. +*/ +static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ + TabResult *p = (TabResult*)pArg; /* Result accumulator */ + int need; /* Slots needed in p->azResult[] */ + int i; /* Loop counter */ + char *z; /* A single column of result */ + + /* Make sure there is enough space in p->azResult to hold everything + ** we need to remember from this invocation of the callback. + */ + if( p->nRow==0 && argv!=0 ){ + need = nCol*2; + }else{ + need = nCol; + } + if( p->nData + need > p->nAlloc ){ + char **azNew; + p->nAlloc = p->nAlloc*2 + need; + azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc ); + if( azNew==0 ) goto malloc_failed; + p->azResult = azNew; + } + + /* If this is the first row, then generate an extra row containing + ** the names of all columns. + */ + if( p->nRow==0 ){ + p->nColumn = nCol; + for(i=0; iazResult[p->nData++] = z; + } + }else if( (int)p->nColumn!=nCol ){ + sqlite3_free(p->zErrMsg); + p->zErrMsg = sqlite3_mprintf( + "sqlite3_get_table() called with two or more incompatible queries" + ); + p->rc = SQLITE_ERROR; + return 1; + } + + /* Copy over the row data + */ + if( argv!=0 ){ + for(i=0; iazResult[p->nData++] = z; + } + p->nRow++; + } + return 0; + +malloc_failed: + p->rc = SQLITE_NOMEM_BKPT; + return 1; +} + +/* +** Query the database. But instead of invoking a callback for each row, +** malloc() for space to hold the result and return the entire results +** at the conclusion of the call. +** +** The result that is written to ***pazResult is held in memory obtained +** from malloc(). But the caller cannot free this memory directly. +** Instead, the entire table should be passed to sqlite3_free_table() when +** the calling procedure is finished using it. +*/ +SQLITE_API int sqlite3_get_table( + sqlite3 *db, /* The database on which the SQL executes */ + const char *zSql, /* The SQL to be executed */ + char ***pazResult, /* Write the result table here */ + int *pnRow, /* Write the number of rows in the result here */ + int *pnColumn, /* Write the number of columns of result here */ + char **pzErrMsg /* Write error messages here */ +){ + int rc; + TabResult res; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || pazResult==0 ) return SQLITE_MISUSE_BKPT; +#endif + *pazResult = 0; + if( pnColumn ) *pnColumn = 0; + if( pnRow ) *pnRow = 0; + if( pzErrMsg ) *pzErrMsg = 0; + res.zErrMsg = 0; + res.nRow = 0; + res.nColumn = 0; + res.nData = 1; + res.nAlloc = 20; + res.rc = SQLITE_OK; + res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc ); + if( res.azResult==0 ){ + db->errCode = SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; + } + res.azResult[0] = 0; + rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg); + assert( sizeof(res.azResult[0])>= sizeof(res.nData) ); + res.azResult[0] = SQLITE_INT_TO_PTR(res.nData); + if( (rc&0xff)==SQLITE_ABORT ){ + sqlite3_free_table(&res.azResult[1]); + if( res.zErrMsg ){ + if( pzErrMsg ){ + sqlite3_free(*pzErrMsg); + *pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg); + } + sqlite3_free(res.zErrMsg); + } + db->errCode = res.rc; /* Assume 32-bit assignment is atomic */ + return res.rc; + } + sqlite3_free(res.zErrMsg); + if( rc!=SQLITE_OK ){ + sqlite3_free_table(&res.azResult[1]); + return rc; + } + if( res.nAlloc>res.nData ){ + char **azNew; + azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData ); + if( azNew==0 ){ + sqlite3_free_table(&res.azResult[1]); + db->errCode = SQLITE_NOMEM; + return SQLITE_NOMEM_BKPT; + } + res.azResult = azNew; + } + *pazResult = &res.azResult[1]; + if( pnColumn ) *pnColumn = res.nColumn; + if( pnRow ) *pnRow = res.nRow; + return rc; +} + +/* +** This routine frees the space the sqlite3_get_table() malloced. +*/ +SQLITE_API void sqlite3_free_table( + char **azResult /* Result returned from sqlite3_get_table() */ +){ + if( azResult ){ + int i, n; + azResult--; + assert( azResult!=0 ); + n = SQLITE_PTR_TO_INT(azResult[0]); + for(i=1; ipNext; + + sqlite3ExprDelete(db, pTmp->pWhere); + sqlite3ExprListDelete(db, pTmp->pExprList); + sqlite3SelectDelete(db, pTmp->pSelect); + sqlite3IdListDelete(db, pTmp->pIdList); + + sqlite3DbFree(db, pTmp); + } +} + +/* +** Given table pTab, return a list of all the triggers attached to +** the table. The list is connected by Trigger.pNext pointers. +** +** All of the triggers on pTab that are in the same database as pTab +** are already attached to pTab->pTrigger. But there might be additional +** triggers on pTab in the TEMP schema. This routine prepends all +** TEMP triggers on pTab to the beginning of the pTab->pTrigger list +** and returns the combined list. +** +** To state it another way: This routine returns a list of all triggers +** that fire off of pTab. The list will include any TEMP triggers on +** pTab as well as the triggers lised in pTab->pTrigger. +*/ +SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ + Schema * const pTmpSchema = pParse->db->aDb[1].pSchema; + Trigger *pList = 0; /* List of triggers to return */ + + if( pParse->disableTriggers ){ + return 0; + } + + if( pTmpSchema!=pTab->pSchema ){ + HashElem *p; + assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) ); + for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){ + Trigger *pTrig = (Trigger *)sqliteHashData(p); + if( pTrig->pTabSchema==pTab->pSchema + && 0==sqlite3StrICmp(pTrig->table, pTab->zName) + ){ + pTrig->pNext = (pList ? pList : pTab->pTrigger); + pList = pTrig; + } + } + } + + return (pList ? pList : pTab->pTrigger); +} + +/* +** This is called by the parser when it sees a CREATE TRIGGER statement +** up to the point of the BEGIN before the trigger actions. A Trigger +** structure is generated based on the information available and stored +** in pParse->pNewTrigger. After the trigger actions have been parsed, the +** sqlite3FinishTrigger() function is called to complete the trigger +** construction process. +*/ +SQLITE_PRIVATE void sqlite3BeginTrigger( + Parse *pParse, /* The parse context of the CREATE TRIGGER statement */ + Token *pName1, /* The name of the trigger */ + Token *pName2, /* The name of the trigger */ + int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */ + int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ + IdList *pColumns, /* column list if this is an UPDATE OF trigger */ + SrcList *pTableName,/* The name of the table/view the trigger applies to */ + Expr *pWhen, /* WHEN clause */ + int isTemp, /* True if the TEMPORARY keyword is present */ + int noErr /* Suppress errors if the trigger already exists */ +){ + Trigger *pTrigger = 0; /* The new trigger */ + Table *pTab; /* Table that the trigger fires off of */ + char *zName = 0; /* Name of the trigger */ + sqlite3 *db = pParse->db; /* The database connection */ + int iDb; /* The database to store the trigger in */ + Token *pName; /* The unqualified db name */ + DbFixer sFix; /* State vector for the DB fixer */ + + assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ + assert( pName2!=0 ); + assert( op==TK_INSERT || op==TK_UPDATE || op==TK_DELETE ); + assert( op>0 && op<0xff ); + if( isTemp ){ + /* If TEMP was specified, then the trigger name may not be qualified. */ + if( pName2->n>0 ){ + sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name"); + goto trigger_cleanup; + } + iDb = 1; + pName = pName1; + }else{ + /* Figure out the db that the trigger will be created in */ + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); + if( iDb<0 ){ + goto trigger_cleanup; + } + } + if( !pTableName || db->mallocFailed ){ + goto trigger_cleanup; + } + + /* A long-standing parser bug is that this syntax was allowed: + ** + ** CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab .... + ** ^^^^^^^^ + ** + ** To maintain backwards compatibility, ignore the database + ** name on pTableName if we are reparsing out of SQLITE_MASTER. + */ + if( db->init.busy && iDb!=1 ){ + sqlite3DbFree(db, pTableName->a[0].zDatabase); + pTableName->a[0].zDatabase = 0; + } + + /* If the trigger name was unqualified, and the table is a temp table, + ** then set iDb to 1 to create the trigger in the temporary database. + ** If sqlite3SrcListLookup() returns 0, indicating the table does not + ** exist, the error is caught by the block below. + */ + pTab = sqlite3SrcListLookup(pParse, pTableName); + if( db->init.busy==0 && pName2->n==0 && pTab + && pTab->pSchema==db->aDb[1].pSchema ){ + iDb = 1; + } + + /* Ensure the table name matches database name and that the table exists */ + if( db->mallocFailed ) goto trigger_cleanup; + assert( pTableName->nSrc==1 ); + sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName); + if( sqlite3FixSrcList(&sFix, pTableName) ){ + goto trigger_cleanup; + } + pTab = sqlite3SrcListLookup(pParse, pTableName); + if( !pTab ){ + /* The table does not exist. */ + if( db->init.iDb==1 ){ + /* Ticket #3810. + ** Normally, whenever a table is dropped, all associated triggers are + ** dropped too. But if a TEMP trigger is created on a non-TEMP table + ** and the table is dropped by a different database connection, the + ** trigger is not visible to the database connection that does the + ** drop so the trigger cannot be dropped. This results in an + ** "orphaned trigger" - a trigger whose associated table is missing. + */ + db->init.orphanTrigger = 1; + } + goto trigger_cleanup; + } + if( IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); + goto trigger_cleanup; + } + + /* Check that the trigger name is not reserved and that no trigger of the + ** specified name exists */ + zName = sqlite3NameFromToken(db, pName); + if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + goto trigger_cleanup; + } + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ + if( !noErr ){ + sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); + } + goto trigger_cleanup; + } + + /* Do not create a trigger on a system table */ + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ + sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); + goto trigger_cleanup; + } + + /* INSTEAD of triggers are only for views and views only support INSTEAD + ** of triggers. + */ + if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ + sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", + (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); + goto trigger_cleanup; + } + if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ + sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" + " trigger on table: %S", pTableName, 0); + goto trigger_cleanup; + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + { + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); + int code = SQLITE_CREATE_TRIGGER; + const char *zDb = db->aDb[iTabDb].zDbSName; + const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb; + if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; + if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ + goto trigger_cleanup; + } + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ + goto trigger_cleanup; + } + } +#endif + + /* INSTEAD OF triggers can only appear on views and BEFORE triggers + ** cannot appear on views. So we might as well translate every + ** INSTEAD OF trigger into a BEFORE trigger. It simplifies code + ** elsewhere. + */ + if (tr_tm == TK_INSTEAD){ + tr_tm = TK_BEFORE; + } + + /* Build the Trigger object */ + pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); + if( pTrigger==0 ) goto trigger_cleanup; + pTrigger->zName = zName; + zName = 0; + pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); + pTrigger->pSchema = db->aDb[iDb].pSchema; + pTrigger->pTabSchema = pTab->pSchema; + pTrigger->op = (u8)op; + pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; + pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); + pTrigger->pColumns = sqlite3IdListDup(db, pColumns); + assert( pParse->pNewTrigger==0 ); + pParse->pNewTrigger = pTrigger; + +trigger_cleanup: + sqlite3DbFree(db, zName); + sqlite3SrcListDelete(db, pTableName); + sqlite3IdListDelete(db, pColumns); + sqlite3ExprDelete(db, pWhen); + if( !pParse->pNewTrigger ){ + sqlite3DeleteTrigger(db, pTrigger); + }else{ + assert( pParse->pNewTrigger==pTrigger ); + } +} + +/* +** This routine is called after all of the trigger actions have been parsed +** in order to complete the process of building the trigger. +*/ +SQLITE_PRIVATE void sqlite3FinishTrigger( + Parse *pParse, /* Parser context */ + TriggerStep *pStepList, /* The triggered program */ + Token *pAll /* Token that describes the complete CREATE TRIGGER */ +){ + Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */ + char *zName; /* Name of trigger */ + sqlite3 *db = pParse->db; /* The database */ + DbFixer sFix; /* Fixer object */ + int iDb; /* Database containing the trigger */ + Token nameToken; /* Trigger name for error reporting */ + + pParse->pNewTrigger = 0; + if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; + zName = pTrig->zName; + iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); + pTrig->step_list = pStepList; + while( pStepList ){ + pStepList->pTrig = pTrig; + pStepList = pStepList->pNext; + } + sqlite3TokenInit(&nameToken, pTrig->zName); + sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); + if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) + || sqlite3FixExpr(&sFix, pTrig->pWhen) + ){ + goto triggerfinish_cleanup; + } + + /* if we are not initializing, + ** build the sqlite_master entry + */ + if( !db->init.busy ){ + Vdbe *v; + char *z; + + /* Make an entry in the sqlite_master table */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto triggerfinish_cleanup; + sqlite3BeginWriteOperation(pParse, 0, iDb); + z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); + sqlite3NestedParse(pParse, + "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", + db->aDb[iDb].zDbSName, MASTER_NAME, zName, + pTrig->table, z); + sqlite3DbFree(db, z); + sqlite3ChangeCookie(pParse, iDb); + sqlite3VdbeAddParseSchemaOp(v, iDb, + sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); + } + + if( db->init.busy ){ + Trigger *pLink = pTrig; + Hash *pHash = &db->aDb[iDb].pSchema->trigHash; + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + pTrig = sqlite3HashInsert(pHash, zName, pTrig); + if( pTrig ){ + sqlite3OomFault(db); + }else if( pLink->pSchema==pLink->pTabSchema ){ + Table *pTab; + pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table); + assert( pTab!=0 ); + pLink->pNext = pTab->pTrigger; + pTab->pTrigger = pLink; + } + } + +triggerfinish_cleanup: + sqlite3DeleteTrigger(db, pTrig); + assert( !pParse->pNewTrigger ); + sqlite3DeleteTriggerStep(db, pStepList); +} + +/* +** Turn a SELECT statement (that the pSelect parameter points to) into +** a trigger step. Return a pointer to a TriggerStep structure. +** +** The parser calls this routine when it finds a SELECT statement in +** body of a TRIGGER. +*/ +SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){ + TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); + if( pTriggerStep==0 ) { + sqlite3SelectDelete(db, pSelect); + return 0; + } + pTriggerStep->op = TK_SELECT; + pTriggerStep->pSelect = pSelect; + pTriggerStep->orconf = OE_Default; + return pTriggerStep; +} + +/* +** Allocate space to hold a new trigger step. The allocated space +** holds both the TriggerStep object and the TriggerStep.target.z string. +** +** If an OOM error occurs, NULL is returned and db->mallocFailed is set. +*/ +static TriggerStep *triggerStepAllocate( + sqlite3 *db, /* Database connection */ + u8 op, /* Trigger opcode */ + Token *pName /* The target name */ +){ + TriggerStep *pTriggerStep; + + pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); + if( pTriggerStep ){ + char *z = (char*)&pTriggerStep[1]; + memcpy(z, pName->z, pName->n); + sqlite3Dequote(z); + pTriggerStep->zTarget = z; + pTriggerStep->op = op; + } + return pTriggerStep; +} + +/* +** Build a trigger step out of an INSERT statement. Return a pointer +** to the new trigger step. +** +** The parser calls this routine when it sees an INSERT inside the +** body of a trigger. +*/ +SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( + sqlite3 *db, /* The database connection */ + Token *pTableName, /* Name of the table into which we insert */ + IdList *pColumn, /* List of columns in pTableName to insert into */ + Select *pSelect, /* A SELECT statement that supplies values */ + u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ +){ + TriggerStep *pTriggerStep; + + assert(pSelect != 0 || db->mallocFailed); + + pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName); + if( pTriggerStep ){ + pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + pTriggerStep->pIdList = pColumn; + pTriggerStep->orconf = orconf; + }else{ + sqlite3IdListDelete(db, pColumn); + } + sqlite3SelectDelete(db, pSelect); + + return pTriggerStep; +} + +/* +** Construct a trigger step that implements an UPDATE statement and return +** a pointer to that trigger step. The parser calls this routine when it +** sees an UPDATE statement inside the body of a CREATE TRIGGER. +*/ +SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( + sqlite3 *db, /* The database connection */ + Token *pTableName, /* Name of the table to be updated */ + ExprList *pEList, /* The SET clause: list of column and new values */ + Expr *pWhere, /* The WHERE clause */ + u8 orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ +){ + TriggerStep *pTriggerStep; + + pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName); + if( pTriggerStep ){ + pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); + pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + pTriggerStep->orconf = orconf; + } + sqlite3ExprListDelete(db, pEList); + sqlite3ExprDelete(db, pWhere); + return pTriggerStep; +} + +/* +** Construct a trigger step that implements a DELETE statement and return +** a pointer to that trigger step. The parser calls this routine when it +** sees a DELETE statement inside the body of a CREATE TRIGGER. +*/ +SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( + sqlite3 *db, /* Database connection */ + Token *pTableName, /* The table from which rows are deleted */ + Expr *pWhere /* The WHERE clause */ +){ + TriggerStep *pTriggerStep; + + pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName); + if( pTriggerStep ){ + pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + pTriggerStep->orconf = OE_Default; + } + sqlite3ExprDelete(db, pWhere); + return pTriggerStep; +} + +/* +** Recursively delete a Trigger structure +*/ +SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ + if( pTrigger==0 ) return; + sqlite3DeleteTriggerStep(db, pTrigger->step_list); + sqlite3DbFree(db, pTrigger->zName); + sqlite3DbFree(db, pTrigger->table); + sqlite3ExprDelete(db, pTrigger->pWhen); + sqlite3IdListDelete(db, pTrigger->pColumns); + sqlite3DbFree(db, pTrigger); +} + +/* +** This function is called to drop a trigger from the database schema. +** +** This may be called directly from the parser and therefore identifies +** the trigger by name. The sqlite3DropTriggerPtr() routine does the +** same job as this routine except it takes a pointer to the trigger +** instead of the trigger name. +**/ +SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){ + Trigger *pTrigger = 0; + int i; + const char *zDb; + const char *zName; + sqlite3 *db = pParse->db; + + if( db->mallocFailed ) goto drop_trigger_cleanup; + if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + goto drop_trigger_cleanup; + } + + assert( pName->nSrc==1 ); + zDb = pName->a[0].zDatabase; + zName = pName->a[0].zName; + assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); + for(i=OMIT_TEMPDB; inDb; i++){ + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ + if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue; + assert( sqlite3SchemaMutexHeld(db, j, 0) ); + pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); + if( pTrigger ) break; + } + if( !pTrigger ){ + if( !noErr ){ + sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); + }else{ + sqlite3CodeVerifyNamedSchema(pParse, zDb); + } + pParse->checkSchema = 1; + goto drop_trigger_cleanup; + } + sqlite3DropTriggerPtr(pParse, pTrigger); + +drop_trigger_cleanup: + sqlite3SrcListDelete(db, pName); +} + +/* +** Return a pointer to the Table structure for the table that a trigger +** is set on. +*/ +static Table *tableOfTrigger(Trigger *pTrigger){ + return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table); +} + + +/* +** Drop a trigger given a pointer to that trigger. +*/ +SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ + Table *pTable; + Vdbe *v; + sqlite3 *db = pParse->db; + int iDb; + + iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); + assert( iDb>=0 && iDbnDb ); + pTable = tableOfTrigger(pTrigger); + assert( pTable ); + assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); +#ifndef SQLITE_OMIT_AUTHORIZATION + { + int code = SQLITE_DROP_TRIGGER; + const char *zDb = db->aDb[iDb].zDbSName; + const char *zTab = SCHEMA_TABLE(iDb); + if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; + if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || + sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ + return; + } + } +#endif + + /* Generate code to destroy the database record of the trigger. + */ + assert( pTable!=0 ); + if( (v = sqlite3GetVdbe(pParse))!=0 ){ + sqlite3NestedParse(pParse, + "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", + db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName + ); + sqlite3ChangeCookie(pParse, iDb); + sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); + } +} + +/* +** Remove a trigger from the hash tables of the sqlite* pointer. +*/ +SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ + Trigger *pTrigger; + Hash *pHash; + + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + pHash = &(db->aDb[iDb].pSchema->trigHash); + pTrigger = sqlite3HashInsert(pHash, zName, 0); + if( ALWAYS(pTrigger) ){ + if( pTrigger->pSchema==pTrigger->pTabSchema ){ + Table *pTab = tableOfTrigger(pTrigger); + Trigger **pp; + for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext)); + *pp = (*pp)->pNext; + } + sqlite3DeleteTrigger(db, pTrigger); + db->flags |= SQLITE_InternChanges; + } +} + +/* +** pEList is the SET clause of an UPDATE statement. Each entry +** in pEList is of the format =. If any of the entries +** in pEList have an which matches an identifier in pIdList, +** then return TRUE. If pIdList==NULL, then it is considered a +** wildcard that matches anything. Likewise if pEList==NULL then +** it matches anything so always return true. Return false only +** if there is no match. +*/ +static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){ + int e; + if( pIdList==0 || NEVER(pEList==0) ) return 1; + for(e=0; enExpr; e++){ + if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; + } + return 0; +} + +/* +** Return a list of all triggers on table pTab if there exists at least +** one trigger that must be fired when an operation of type 'op' is +** performed on the table, and, if that operation is an UPDATE, if at +** least one of the columns in pChanges is being modified. +*/ +SQLITE_PRIVATE Trigger *sqlite3TriggersExist( + Parse *pParse, /* Parse context */ + Table *pTab, /* The table the contains the triggers */ + int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ + ExprList *pChanges, /* Columns that change in an UPDATE statement */ + int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ +){ + int mask = 0; + Trigger *pList = 0; + Trigger *p; + + if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){ + pList = sqlite3TriggerList(pParse, pTab); + } + assert( pList==0 || IsVirtual(pTab)==0 ); + for(p=pList; p; p=p->pNext){ + if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ + mask |= p->tr_tm; + } + } + if( pMask ){ + *pMask = mask; + } + return (mask ? pList : 0); +} + +/* +** Convert the pStep->zTarget string into a SrcList and return a pointer +** to that SrcList. +** +** This routine adds a specific database name, if needed, to the target when +** forming the SrcList. This prevents a trigger in one database from +** referring to a target in another database. An exception is when the +** trigger is in TEMP in which case it can refer to any other database it +** wants. +*/ +static SrcList *targetSrcList( + Parse *pParse, /* The parsing context */ + TriggerStep *pStep /* The trigger containing the target token */ +){ + sqlite3 *db = pParse->db; + int iDb; /* Index of the database to use */ + SrcList *pSrc; /* SrcList to be returned */ + + pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + if( pSrc ){ + assert( pSrc->nSrc>0 ); + pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); + iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); + if( iDb==0 || iDb>=2 ){ + const char *zDb; + assert( iDbnDb ); + zDb = db->aDb[iDb].zDbSName; + pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb); + } + } + return pSrc; +} + +/* +** Generate VDBE code for the statements inside the body of a single +** trigger. +*/ +static int codeTriggerProgram( + Parse *pParse, /* The parser context */ + TriggerStep *pStepList, /* List of statements inside the trigger body */ + int orconf /* Conflict algorithm. (OE_Abort, etc) */ +){ + TriggerStep *pStep; + Vdbe *v = pParse->pVdbe; + sqlite3 *db = pParse->db; + + assert( pParse->pTriggerTab && pParse->pToplevel ); + assert( pStepList ); + assert( v!=0 ); + for(pStep=pStepList; pStep; pStep=pStep->pNext){ + /* Figure out the ON CONFLICT policy that will be used for this step + ** of the trigger program. If the statement that caused this trigger + ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use + ** the ON CONFLICT policy that was specified as part of the trigger + ** step statement. Example: + ** + ** CREATE TRIGGER AFTER INSERT ON t1 BEGIN; + ** INSERT OR REPLACE INTO t2 VALUES(new.a, new.b); + ** END; + ** + ** INSERT INTO t1 ... ; -- insert into t2 uses REPLACE policy + ** INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy + */ + pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf; + assert( pParse->okConstFactor==0 ); + + switch( pStep->op ){ + case TK_UPDATE: { + sqlite3Update(pParse, + targetSrcList(pParse, pStep), + sqlite3ExprListDup(db, pStep->pExprList, 0), + sqlite3ExprDup(db, pStep->pWhere, 0), + pParse->eOrconf + ); + break; + } + case TK_INSERT: { + sqlite3Insert(pParse, + targetSrcList(pParse, pStep), + sqlite3SelectDup(db, pStep->pSelect, 0), + sqlite3IdListDup(db, pStep->pIdList), + pParse->eOrconf + ); + break; + } + case TK_DELETE: { + sqlite3DeleteFrom(pParse, + targetSrcList(pParse, pStep), + sqlite3ExprDup(db, pStep->pWhere, 0) + ); + break; + } + default: assert( pStep->op==TK_SELECT ); { + SelectDest sDest; + Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0); + sqlite3SelectDestInit(&sDest, SRT_Discard, 0); + sqlite3Select(pParse, pSelect, &sDest); + sqlite3SelectDelete(db, pSelect); + break; + } + } + if( pStep->op!=TK_SELECT ){ + sqlite3VdbeAddOp0(v, OP_ResetCount); + } + } + + return 0; +} + +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS +/* +** This function is used to add VdbeComment() annotations to a VDBE +** program. It is not used in production code, only for debugging. +*/ +static const char *onErrorText(int onError){ + switch( onError ){ + case OE_Abort: return "abort"; + case OE_Rollback: return "rollback"; + case OE_Fail: return "fail"; + case OE_Replace: return "replace"; + case OE_Ignore: return "ignore"; + case OE_Default: return "default"; + } + return "n/a"; +} +#endif + +/* +** Parse context structure pFrom has just been used to create a sub-vdbe +** (trigger program). If an error has occurred, transfer error information +** from pFrom to pTo. +*/ +static void transferParseError(Parse *pTo, Parse *pFrom){ + assert( pFrom->zErrMsg==0 || pFrom->nErr ); + assert( pTo->zErrMsg==0 || pTo->nErr ); + if( pTo->nErr==0 ){ + pTo->zErrMsg = pFrom->zErrMsg; + pTo->nErr = pFrom->nErr; + pTo->rc = pFrom->rc; + }else{ + sqlite3DbFree(pFrom->db, pFrom->zErrMsg); + } +} + +/* +** Create and populate a new TriggerPrg object with a sub-program +** implementing trigger pTrigger with ON CONFLICT policy orconf. +*/ +static TriggerPrg *codeRowTrigger( + Parse *pParse, /* Current parse context */ + Trigger *pTrigger, /* Trigger to code */ + Table *pTab, /* The table pTrigger is attached to */ + int orconf /* ON CONFLICT policy to code trigger program with */ +){ + Parse *pTop = sqlite3ParseToplevel(pParse); + sqlite3 *db = pParse->db; /* Database handle */ + TriggerPrg *pPrg; /* Value to return */ + Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ + Vdbe *v; /* Temporary VM */ + NameContext sNC; /* Name context for sub-vdbe */ + SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ + Parse *pSubParse; /* Parse context for sub-vdbe */ + int iEndTrigger = 0; /* Label to jump to if WHEN is false */ + + assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); + assert( pTop->pVdbe ); + + /* Allocate the TriggerPrg and SubProgram objects. To ensure that they + ** are freed if an error occurs, link them into the Parse.pTriggerPrg + ** list of the top-level Parse object sooner rather than later. */ + pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg)); + if( !pPrg ) return 0; + pPrg->pNext = pTop->pTriggerPrg; + pTop->pTriggerPrg = pPrg; + pPrg->pProgram = pProgram = sqlite3DbMallocZero(db, sizeof(SubProgram)); + if( !pProgram ) return 0; + sqlite3VdbeLinkSubProgram(pTop->pVdbe, pProgram); + pPrg->pTrigger = pTrigger; + pPrg->orconf = orconf; + pPrg->aColmask[0] = 0xffffffff; + pPrg->aColmask[1] = 0xffffffff; + + /* Allocate and populate a new Parse context to use for coding the + ** trigger sub-program. */ + pSubParse = sqlite3StackAllocZero(db, sizeof(Parse)); + if( !pSubParse ) return 0; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pSubParse; + pSubParse->db = db; + pSubParse->pTriggerTab = pTab; + pSubParse->pToplevel = pTop; + pSubParse->zAuthContext = pTrigger->zName; + pSubParse->eTriggerOp = pTrigger->op; + pSubParse->nQueryLoop = pParse->nQueryLoop; + + v = sqlite3GetVdbe(pSubParse); + if( v ){ + VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", + pTrigger->zName, onErrorText(orconf), + (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"), + (pTrigger->op==TK_UPDATE ? "UPDATE" : ""), + (pTrigger->op==TK_INSERT ? "INSERT" : ""), + (pTrigger->op==TK_DELETE ? "DELETE" : ""), + pTab->zName + )); +#ifndef SQLITE_OMIT_TRACE + sqlite3VdbeChangeP4(v, -1, + sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC + ); +#endif + + /* If one was specified, code the WHEN clause. If it evaluates to false + ** (or NULL) the sub-vdbe is immediately halted by jumping to the + ** OP_Halt inserted at the end of the program. */ + if( pTrigger->pWhen ){ + pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0); + if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) + && db->mallocFailed==0 + ){ + iEndTrigger = sqlite3VdbeMakeLabel(v); + sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); + } + sqlite3ExprDelete(db, pWhen); + } + + /* Code the trigger program into the sub-vdbe. */ + codeTriggerProgram(pSubParse, pTrigger->step_list, orconf); + + /* Insert an OP_Halt at the end of the sub-program. */ + if( iEndTrigger ){ + sqlite3VdbeResolveLabel(v, iEndTrigger); + } + sqlite3VdbeAddOp0(v, OP_Halt); + VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); + + transferParseError(pParse, pSubParse); + if( db->mallocFailed==0 ){ + pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); + } + pProgram->nMem = pSubParse->nMem; + pProgram->nCsr = pSubParse->nTab; + pProgram->token = (void *)pTrigger; + pPrg->aColmask[0] = pSubParse->oldmask; + pPrg->aColmask[1] = pSubParse->newmask; + sqlite3VdbeDelete(v); + } + + assert( !pSubParse->pAinc && !pSubParse->pZombieTab ); + assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); + sqlite3ParserReset(pSubParse); + sqlite3StackFree(db, pSubParse); + + return pPrg; +} + +/* +** Return a pointer to a TriggerPrg object containing the sub-program for +** trigger pTrigger with default ON CONFLICT algorithm orconf. If no such +** TriggerPrg object exists, a new object is allocated and populated before +** being returned. +*/ +static TriggerPrg *getRowTrigger( + Parse *pParse, /* Current parse context */ + Trigger *pTrigger, /* Trigger to code */ + Table *pTab, /* The table trigger pTrigger is attached to */ + int orconf /* ON CONFLICT algorithm. */ +){ + Parse *pRoot = sqlite3ParseToplevel(pParse); + TriggerPrg *pPrg; + + assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); + + /* It may be that this trigger has already been coded (or is in the + ** process of being coded). If this is the case, then an entry with + ** a matching TriggerPrg.pTrigger field will be present somewhere + ** in the Parse.pTriggerPrg list. Search for such an entry. */ + for(pPrg=pRoot->pTriggerPrg; + pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); + pPrg=pPrg->pNext + ); + + /* If an existing TriggerPrg could not be located, create a new one. */ + if( !pPrg ){ + pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf); + } + + return pPrg; +} + +/* +** Generate code for the trigger program associated with trigger p on +** table pTab. The reg, orconf and ignoreJump parameters passed to this +** function are the same as those described in the header function for +** sqlite3CodeRowTrigger() +*/ +SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect( + Parse *pParse, /* Parse context */ + Trigger *p, /* Trigger to code */ + Table *pTab, /* The table to code triggers from */ + int reg, /* Reg array containing OLD.* and NEW.* values */ + int orconf, /* ON CONFLICT policy */ + int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ +){ + Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ + TriggerPrg *pPrg; + pPrg = getRowTrigger(pParse, p, pTab, orconf); + assert( pPrg || pParse->nErr || pParse->db->mallocFailed ); + + /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program + ** is a pointer to the sub-vdbe containing the trigger program. */ + if( pPrg ){ + int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); + + sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem, + (const char *)pPrg->pProgram, P4_SUBPROGRAM); + VdbeComment( + (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf))); + + /* Set the P5 operand of the OP_Program instruction to non-zero if + ** recursive invocation of this trigger program is disallowed. Recursive + ** invocation is disallowed if (a) the sub-program is really a trigger, + ** not a foreign key action, and (b) the flag to enable recursive triggers + ** is clear. */ + sqlite3VdbeChangeP5(v, (u8)bRecursive); + } +} + +/* +** This is called to code the required FOR EACH ROW triggers for an operation +** on table pTab. The operation to code triggers for (INSERT, UPDATE or DELETE) +** is given by the op parameter. The tr_tm parameter determines whether the +** BEFORE or AFTER triggers are coded. If the operation is an UPDATE, then +** parameter pChanges is passed the list of columns being modified. +** +** If there are no triggers that fire at the specified time for the specified +** operation on pTab, this function is a no-op. +** +** The reg argument is the address of the first in an array of registers +** that contain the values substituted for the new.* and old.* references +** in the trigger program. If N is the number of columns in table pTab +** (a copy of pTab->nCol), then registers are populated as follows: +** +** Register Contains +** ------------------------------------------------------ +** reg+0 OLD.rowid +** reg+1 OLD.* value of left-most column of pTab +** ... ... +** reg+N OLD.* value of right-most column of pTab +** reg+N+1 NEW.rowid +** reg+N+2 OLD.* value of left-most column of pTab +** ... ... +** reg+N+N+1 NEW.* value of right-most column of pTab +** +** For ON DELETE triggers, the registers containing the NEW.* values will +** never be accessed by the trigger program, so they are not allocated or +** populated by the caller (there is no data to populate them with anyway). +** Similarly, for ON INSERT triggers the values stored in the OLD.* registers +** are never accessed, and so are not allocated by the caller. So, for an +** ON INSERT trigger, the value passed to this function as parameter reg +** is not a readable register, although registers (reg+N) through +** (reg+N+N+1) are. +** +** Parameter orconf is the default conflict resolution algorithm for the +** trigger program to use (REPLACE, IGNORE etc.). Parameter ignoreJump +** is the instruction that control should jump to if a trigger program +** raises an IGNORE exception. +*/ +SQLITE_PRIVATE void sqlite3CodeRowTrigger( + Parse *pParse, /* Parse context */ + Trigger *pTrigger, /* List of triggers on table pTab */ + int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ + ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ + int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ + Table *pTab, /* The table to code triggers from */ + int reg, /* The first in an array of registers (see above) */ + int orconf, /* ON CONFLICT policy */ + int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ +){ + Trigger *p; /* Used to iterate through pTrigger list */ + + assert( op==TK_UPDATE || op==TK_INSERT || op==TK_DELETE ); + assert( tr_tm==TRIGGER_BEFORE || tr_tm==TRIGGER_AFTER ); + assert( (op==TK_UPDATE)==(pChanges!=0) ); + + for(p=pTrigger; p; p=p->pNext){ + + /* Sanity checking: The schema for the trigger and for the table are + ** always defined. The trigger must be in the same schema as the table + ** or else it must be a TEMP trigger. */ + assert( p->pSchema!=0 ); + assert( p->pTabSchema!=0 ); + assert( p->pSchema==p->pTabSchema + || p->pSchema==pParse->db->aDb[1].pSchema ); + + /* Determine whether we should code this trigger */ + if( p->op==op + && p->tr_tm==tr_tm + && checkColumnOverlap(p->pColumns, pChanges) + ){ + sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); + } + } +} + +/* +** Triggers may access values stored in the old.* or new.* pseudo-table. +** This function returns a 32-bit bitmask indicating which columns of the +** old.* or new.* tables actually are used by triggers. This information +** may be used by the caller, for example, to avoid having to load the entire +** old.* record into memory when executing an UPDATE or DELETE command. +** +** Bit 0 of the returned mask is set if the left-most column of the +** table may be accessed using an [old|new].reference. Bit 1 is set if +** the second leftmost column value is required, and so on. If there +** are more than 32 columns in the table, and at least one of the columns +** with an index greater than 32 may be accessed, 0xffffffff is returned. +** +** It is not possible to determine if the old.rowid or new.rowid column is +** accessed by triggers. The caller must always assume that it is. +** +** Parameter isNew must be either 1 or 0. If it is 0, then the mask returned +** applies to the old.* table. If 1, the new.* table. +** +** Parameter tr_tm must be a mask with one or both of the TRIGGER_BEFORE +** and TRIGGER_AFTER bits set. Values accessed by BEFORE triggers are only +** included in the returned mask if the TRIGGER_BEFORE bit is set in the +** tr_tm parameter. Similarly, values accessed by AFTER triggers are only +** included in the returned mask if the TRIGGER_AFTER bit is set in tr_tm. +*/ +SQLITE_PRIVATE u32 sqlite3TriggerColmask( + Parse *pParse, /* Parse context */ + Trigger *pTrigger, /* List of triggers on table pTab */ + ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ + int isNew, /* 1 for new.* ref mask, 0 for old.* ref mask */ + int tr_tm, /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ + Table *pTab, /* The table to code triggers from */ + int orconf /* Default ON CONFLICT policy for trigger steps */ +){ + const int op = pChanges ? TK_UPDATE : TK_DELETE; + u32 mask = 0; + Trigger *p; + + assert( isNew==1 || isNew==0 ); + for(p=pTrigger; p; p=p->pNext){ + if( p->op==op && (tr_tm&p->tr_tm) + && checkColumnOverlap(p->pColumns,pChanges) + ){ + TriggerPrg *pPrg; + pPrg = getRowTrigger(pParse, p, pTab, orconf); + if( pPrg ){ + mask |= pPrg->aColmask[isNew]; + } + } + } + + return mask; +} + +#endif /* !defined(SQLITE_OMIT_TRIGGER) */ + +/************** End of trigger.c *********************************************/ +/************** Begin file update.c ******************************************/ +/* +** 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 C code routines that are called by the parser +** to handle UPDATE statements. +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Forward declaration */ +static void updateVirtualTable( + Parse *pParse, /* The parsing context */ + SrcList *pSrc, /* The virtual table to be modified */ + Table *pTab, /* The virtual table */ + ExprList *pChanges, /* The columns to change in the UPDATE statement */ + Expr *pRowidExpr, /* Expression used to recompute the rowid */ + int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ + Expr *pWhere, /* WHERE clause of the UPDATE statement */ + int onError /* ON CONFLICT strategy */ +); +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +/* +** The most recently coded instruction was an OP_Column to retrieve the +** i-th column of table pTab. This routine sets the P4 parameter of the +** OP_Column to the default value, if any. +** +** The default value of a column is specified by a DEFAULT clause in the +** column definition. This was either supplied by the user when the table +** was created, or added later to the table definition by an ALTER TABLE +** command. If the latter, then the row-records in the table btree on disk +** may not contain a value for the column and the default value, taken +** from the P4 parameter of the OP_Column instruction, is returned instead. +** If the former, then all row-records are guaranteed to include a value +** for the column and the P4 value is not required. +** +** Column definitions created by an ALTER TABLE command may only have +** literal default values specified: a number, null or a string. (If a more +** complicated default expression value was provided, it is evaluated +** when the ALTER TABLE is executed and one of the literal values written +** into the sqlite_master table.) +** +** Therefore, the P4 parameter is only required if the default value for +** the column is a literal number, string or null. The sqlite3ValueFromExpr() +** function is capable of transforming these types of expressions into +** sqlite3_value objects. +** +** If parameter iReg is not negative, code an OP_RealAffinity instruction +** on register iReg. This is used when an equivalent integer value is +** stored in place of an 8-byte floating point value in order to save +** space. +*/ +SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ + assert( pTab!=0 ); + if( !pTab->pSelect ){ + sqlite3_value *pValue = 0; + u8 enc = ENC(sqlite3VdbeDb(v)); + Column *pCol = &pTab->aCol[i]; + VdbeComment((v, "%s.%s", pTab->zName, pCol->zName)); + assert( inCol ); + sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, + pCol->affinity, &pValue); + if( pValue ){ + sqlite3VdbeAppendP4(v, pValue, P4_MEM); + } + } +#ifndef SQLITE_OMIT_FLOATING_POINT + if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); + } +#endif +} + +/* +** Process an UPDATE statement. +** +** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; +** \_______/ \________/ \______/ \________________/ +* onError pTabList pChanges pWhere +*/ +SQLITE_PRIVATE void sqlite3Update( + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* The table in which we should change things */ + ExprList *pChanges, /* Things to be changed */ + Expr *pWhere, /* The WHERE clause. May be null */ + int onError /* How to handle constraint errors */ +){ + int i, j; /* Loop counters */ + Table *pTab; /* The table to be updated */ + int addrTop = 0; /* VDBE instruction address of the start of the loop */ + WhereInfo *pWInfo; /* Information about the WHERE clause */ + Vdbe *v; /* The virtual database engine */ + Index *pIdx; /* For looping over indices */ + Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */ + int nIdx; /* Number of indices that need updating */ + int iBaseCur; /* Base cursor number */ + int iDataCur; /* Cursor for the canonical data btree */ + int iIdxCur; /* Cursor for the first index */ + sqlite3 *db; /* The database structure */ + int *aRegIdx = 0; /* First register in array assigned to each index */ + int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the + ** an expression for the i-th column of the table. + ** aXRef[i]==-1 if the i-th column is not changed. */ + u8 *aToOpen; /* 1 for tables and indices to be opened */ + u8 chngPk; /* PRIMARY KEY changed in a WITHOUT ROWID table */ + u8 chngRowid; /* Rowid changed in a normal table */ + u8 chngKey; /* Either chngPk or chngRowid */ + Expr *pRowidExpr = 0; /* Expression defining the new record number */ + AuthContext sContext; /* The authorization context */ + NameContext sNC; /* The name-context to resolve expressions in */ + int iDb; /* Database containing the table being updated */ + int eOnePass; /* ONEPASS_XXX value from where.c */ + int hasFK; /* True if foreign key processing is required */ + int labelBreak; /* Jump here to break out of UPDATE loop */ + int labelContinue; /* Jump here to continue next step of UPDATE loop */ + int flags; /* Flags for sqlite3WhereBegin() */ + +#ifndef SQLITE_OMIT_TRIGGER + int isView; /* True when updating a view (INSTEAD OF trigger) */ + Trigger *pTrigger; /* List of triggers on pTab, if required */ + int tmask; /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ +#endif + int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */ + int iEph = 0; /* Ephemeral table holding all primary key values */ + int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */ + int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ + int addrOpen = 0; /* Address of OP_OpenEphemeral */ + int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */ + i16 nPk = 0; /* Number of components of the PRIMARY KEY */ + int bReplace = 0; /* True if REPLACE conflict resolution might happen */ + + /* Register Allocations */ + int regRowCount = 0; /* A count of rows changed */ + int regOldRowid = 0; /* The old rowid */ + int regNewRowid = 0; /* The new rowid */ + int regNew = 0; /* Content of the NEW.* table in triggers */ + int regOld = 0; /* Content of OLD.* table in triggers */ + int regRowSet = 0; /* Rowset of rows to be updated */ + int regKey = 0; /* composite PRIMARY KEY value */ + + memset(&sContext, 0, sizeof(sContext)); + db = pParse->db; + if( pParse->nErr || db->mallocFailed ){ + goto update_cleanup; + } + assert( pTabList->nSrc==1 ); + + /* Locate the table which we want to update. + */ + pTab = sqlite3SrcListLookup(pParse, pTabList); + if( pTab==0 ) goto update_cleanup; + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + + /* Figure out if we have any triggers and if the table being + ** updated is a view. + */ +#ifndef SQLITE_OMIT_TRIGGER + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, &tmask); + isView = pTab->pSelect!=0; + assert( pTrigger || tmask==0 ); +#else +# define pTrigger 0 +# define isView 0 +# define tmask 0 +#endif +#ifdef SQLITE_OMIT_VIEW +# undef isView +# define isView 0 +#endif + + if( sqlite3ViewGetColumnNames(pParse, pTab) ){ + goto update_cleanup; + } + if( sqlite3IsReadOnly(pParse, pTab, tmask) ){ + goto update_cleanup; + } + + /* Allocate a cursors for the main database table and for all indices. + ** The index cursors might not be used, but if they are used they + ** need to occur right after the database cursor. So go ahead and + ** allocate enough space, just in case. + */ + pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++; + iIdxCur = iDataCur+1; + pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ + if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){ + iDataCur = pParse->nTab; + pTabList->a[0].iCursor = iDataCur; + } + pParse->nTab++; + } + + /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. + ** Initialize aXRef[] and aToOpen[] to their default values. + */ + aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 ); + if( aXRef==0 ) goto update_cleanup; + aRegIdx = aXRef+pTab->nCol; + aToOpen = (u8*)(aRegIdx+nIdx); + memset(aToOpen, 1, nIdx+1); + aToOpen[nIdx+1] = 0; + for(i=0; inCol; i++) aXRef[i] = -1; + + /* Initialize the name-context */ + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + sNC.pSrcList = pTabList; + + /* Resolve the column names in all the expressions of the + ** of the UPDATE statement. Also find the column index + ** for each column to be updated in the pChanges array. For each + ** column to be updated, make sure we have authorization to change + ** that column. + */ + chngRowid = chngPk = 0; + for(i=0; inExpr; i++){ + if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ + goto update_cleanup; + } + for(j=0; jnCol; j++){ + if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ + if( j==pTab->iPKey ){ + chngRowid = 1; + pRowidExpr = pChanges->a[i].pExpr; + }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ + chngPk = 1; + } + aXRef[j] = i; + break; + } + } + if( j>=pTab->nCol ){ + if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){ + j = -1; + chngRowid = 1; + pRowidExpr = pChanges->a[i].pExpr; + }else{ + sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); + pParse->checkSchema = 1; + goto update_cleanup; + } + } +#ifndef SQLITE_OMIT_AUTHORIZATION + { + int rc; + rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, + j<0 ? "ROWID" : pTab->aCol[j].zName, + db->aDb[iDb].zDbSName); + if( rc==SQLITE_DENY ){ + goto update_cleanup; + }else if( rc==SQLITE_IGNORE ){ + aXRef[j] = -1; + } + } +#endif + } + assert( (chngRowid & chngPk)==0 ); + assert( chngRowid==0 || chngRowid==1 ); + assert( chngPk==0 || chngPk==1 ); + chngKey = chngRowid + chngPk; + + /* The SET expressions are not actually used inside the WHERE loop. + ** So reset the colUsed mask. Unless this is a virtual table. In that + ** case, set all bits of the colUsed mask (to ensure that the virtual + ** table implementation makes all columns available). + */ + pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0; + + hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); + + /* There is one entry in the aRegIdx[] array for each index on the table + ** being updated. Fill in aRegIdx[] with a register number that will hold + ** the key for accessing each index. + ** + ** FIXME: Be smarter about omitting indexes that use expressions. + */ + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + int reg; + if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){ + reg = ++pParse->nMem; + pParse->nMem += pIdx->nColumn; + }else{ + reg = 0; + for(i=0; inKeyCol; i++){ + i16 iIdxCol = pIdx->aiColumn[i]; + if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){ + reg = ++pParse->nMem; + pParse->nMem += pIdx->nColumn; + if( (onError==OE_Replace) + || (onError==OE_Default && pIdx->onError==OE_Replace) + ){ + bReplace = 1; + } + break; + } + } + } + if( reg==0 ) aToOpen[j+1] = 0; + aRegIdx[j] = reg; + } + if( bReplace ){ + /* If REPLACE conflict resolution might be invoked, open cursors on all + ** indexes in case they are needed to delete records. */ + memset(aToOpen, 1, nIdx+1); + } + + /* Begin generating code. */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto update_cleanup; + if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); + sqlite3BeginWriteOperation(pParse, 1, iDb); + + /* Allocate required registers. */ + if( !IsVirtual(pTab) ){ + regRowSet = ++pParse->nMem; + regOldRowid = regNewRowid = ++pParse->nMem; + if( chngPk || pTrigger || hasFK ){ + regOld = pParse->nMem + 1; + pParse->nMem += pTab->nCol; + } + if( chngKey || pTrigger || hasFK ){ + regNewRowid = ++pParse->nMem; + } + regNew = pParse->nMem + 1; + pParse->nMem += pTab->nCol; + } + + /* Start the view context. */ + if( isView ){ + sqlite3AuthContextPush(pParse, &sContext, pTab->zName); + } + + /* If we are trying to update a view, realize that view into + ** an ephemeral table. + */ +#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) + if( isView ){ + sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur); + } +#endif + + /* Resolve the column names in all the expressions in the + ** WHERE clause. + */ + if( sqlite3ResolveExprNames(&sNC, pWhere) ){ + goto update_cleanup; + } + +#ifndef SQLITE_OMIT_VIRTUALTABLE + /* Virtual tables must be handled separately */ + if( IsVirtual(pTab) ){ + updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, + pWhere, onError); + goto update_cleanup; + } +#endif + + /* Initialize the count of updated rows */ + if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){ + regRowCount = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); + } + + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); + }else{ + assert( pPk!=0 ); + nPk = pPk->nKeyCol; + iPk = pParse->nMem+1; + pParse->nMem += nPk; + regKey = ++pParse->nMem; + iEph = pParse->nTab++; + + sqlite3VdbeAddOp2(v, OP_Null, 0, iPk); + addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); + } + + /* Begin the database scan. + ** + ** Do not consider a single-pass strategy for a multi-row update if + ** there are any triggers or foreign keys to process, or rows may + ** be deleted as a result of REPLACE conflict handling. Any of these + ** things might disturb a cursor being used to scan through the table + ** or index, causing a single-pass approach to malfunction. */ + flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE; + if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ + flags |= WHERE_ONEPASS_MULTIROW; + } + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur); + if( pWInfo==0 ) goto update_cleanup; + + /* A one-pass strategy that might update more than one row may not + ** be used if any column of the index used for the scan is being + ** updated. Otherwise, if there is an index on "b", statements like + ** the following could create an infinite loop: + ** + ** UPDATE t1 SET b=b+1 WHERE b>? + ** + ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI + ** strategy that uses an index for which one or more columns are being + ** updated. */ + eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); + if( eOnePass==ONEPASS_MULTI ){ + int iCur = aiCurOnePass[1]; + if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ + eOnePass = ONEPASS_OFF; + } + assert( iCur!=iDataCur || !HasRowid(pTab) ); + } + + if( HasRowid(pTab) ){ + /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF + ** mode, write the rowid into the FIFO. In either of the one-pass modes, + ** leave it in register regOldRowid. */ + sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); + if( eOnePass==ONEPASS_OFF ){ + sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); + } + }else{ + /* Read the PK of the current row into an array of registers. In + ** ONEPASS_OFF mode, serialize the array into a record and store it in + ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change + ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table + ** is not required) and leave the PK fields in the array of registers. */ + for(i=0; iaiColumn[i]>=0 ); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i); + } + if( eOnePass ){ + sqlite3VdbeChangeToNoop(v, addrOpen); + nKey = nPk; + regKey = iPk; + }else{ + sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, + sqlite3IndexAffinityStr(db, pPk), nPk); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk); + } + } + + if( eOnePass!=ONEPASS_MULTI ){ + sqlite3WhereEnd(pWInfo); + } + + labelBreak = sqlite3VdbeMakeLabel(v); + if( !isView ){ + int addrOnce = 0; + + /* Open every index that needs updating. */ + if( eOnePass!=ONEPASS_OFF ){ + if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; + if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; + } + + if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen, + 0, 0); + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); + } + + /* Top of the update loop */ + if( eOnePass!=ONEPASS_OFF ){ + if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ + assert( pPk ); + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); + VdbeCoverageNeverTaken(v); + } + if( eOnePass==ONEPASS_SINGLE ){ + labelContinue = labelBreak; + }else{ + labelContinue = sqlite3VdbeMakeLabel(v); + } + sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); + VdbeCoverageIf(v, pPk==0); + VdbeCoverageIf(v, pPk!=0); + }else if( pPk ){ + labelContinue = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); + addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); + VdbeCoverage(v); + }else{ + labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, labelBreak, + regOldRowid); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); + VdbeCoverage(v); + } + + /* If the record number will change, set register regNewRowid to + ** contain the new value. If the record number is not being modified, + ** then regNewRowid is the same register as regOldRowid, which is + ** already populated. */ + assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid ); + if( chngRowid ){ + sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); + sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); + } + + /* Compute the old pre-UPDATE content of the row being changed, if that + ** information is needed */ + if( chngPk || hasFK || pTrigger ){ + u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); + oldmask |= sqlite3TriggerColmask(pParse, + pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError + ); + for(i=0; inCol; i++){ + if( oldmask==0xffffffff + || (i<32 && (oldmask & MASKBIT32(i))!=0) + || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 + ){ + testcase( oldmask!=0xffffffff && i==31 ); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i); + }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); + } + } + if( chngRowid==0 && pPk==0 ){ + sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); + } + } + + /* Populate the array of registers beginning at regNew with the new + ** row data. This array is used to check constants, create the new + ** table and index records, and as the values for any new.* references + ** made by triggers. + ** + ** If there are one or more BEFORE triggers, then do not populate the + ** registers associated with columns that are (a) not modified by + ** this UPDATE statement and (b) not accessed by new.* references. The + ** values for registers not modified by the UPDATE must be reloaded from + ** the database after the BEFORE triggers are fired anyway (as the trigger + ** may have modified them). So not loading those that are not going to + ** be used eliminates some redundant opcodes. + */ + newmask = sqlite3TriggerColmask( + pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError + ); + for(i=0; inCol; i++){ + if( i==pTab->iPKey ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); + }else{ + j = aXRef[i]; + if( j>=0 ){ + sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); + }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){ + /* This branch loads the value of a column that will not be changed + ** into a register. This is done if there are no BEFORE triggers, or + ** if there are one or more BEFORE triggers that use this value via + ** a new.* reference in a trigger program. + */ + testcase( i==31 ); + testcase( i==32 ); + sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i); + }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); + } + } + } + + /* Fire any BEFORE UPDATE triggers. This happens before constraints are + ** verified. One could argue that this is wrong. + */ + if( tmask&TRIGGER_BEFORE ){ + sqlite3TableAffinity(v, pTab, regNew); + sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, + TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue); + + /* The row-trigger may have deleted the row being updated. In this + ** case, jump to the next row. No updates or AFTER triggers are + ** required. This behavior - what happens when the row being updated + ** is deleted or renamed by a BEFORE trigger - is left undefined in the + ** documentation. + */ + if( pPk ){ + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey); + VdbeCoverage(v); + }else{ + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); + VdbeCoverage(v); + } + + /* If it did not delete it, the row-trigger may still have modified + ** some of the columns of the row being updated. Load the values for + ** all columns not modified by the update statement into their + ** registers in case this has happened. + */ + for(i=0; inCol; i++){ + if( aXRef[i]<0 && i!=pTab->iPKey ){ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i); + } + } + } + + if( !isView ){ + int addr1 = 0; /* Address of jump instruction */ + + /* Do constraint checks. */ + assert( regOldRowid>0 ); + sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, + regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace, + aXRef); + + /* Do FK constraint checks. */ + if( hasFK ){ + sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey); + } + + /* Delete the index entries associated with the current record. */ + if( bReplace || chngKey ){ + if( pPk ){ + addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey); + }else{ + addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid); + } + VdbeCoverageNeverTaken(v); + } + sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1); + + /* If changing the rowid value, or if there are foreign key constraints + ** to process, delete the old record. Otherwise, add a noop OP_Delete + ** to invoke the pre-update hook. + ** + ** That (regNew==regnewRowid+1) is true is also important for the + ** pre-update hook. If the caller invokes preupdate_new(), the returned + ** value is copied from memory cell (regNewRowid+1+iCol), where iCol + ** is the column index supplied by the user. + */ + assert( regNew==regNewRowid+1 ); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + sqlite3VdbeAddOp3(v, OP_Delete, iDataCur, + OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP), + regNewRowid + ); + if( eOnePass==ONEPASS_MULTI ){ + assert( hasFK==0 && chngKey==0 ); + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); + } + if( !pParse->nested ){ + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + } +#else + if( hasFK>1 || chngKey ){ + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); + } +#endif + if( bReplace || chngKey ){ + sqlite3VdbeJumpHere(v, addr1); + } + + if( hasFK ){ + sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey); + } + + /* Insert the new index entries and the new record. */ + sqlite3CompleteInsertion( + pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx, + OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0), + 0, 0 + ); + + /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to + ** handle rows (possibly in other tables) that refer via a foreign key + ** to the row just updated. */ + if( hasFK ){ + sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey); + } + } + + /* Increment the row counter + */ + if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){ + sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); + } + + sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, + TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue); + + /* Repeat the above with the next record to be updated, until + ** all record selected by the WHERE clause have been updated. + */ + if( eOnePass==ONEPASS_SINGLE ){ + /* Nothing to do at end-of-loop for a single-pass */ + }else if( eOnePass==ONEPASS_MULTI ){ + sqlite3VdbeResolveLabel(v, labelContinue); + sqlite3WhereEnd(pWInfo); + }else if( pPk ){ + sqlite3VdbeResolveLabel(v, labelContinue); + sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); + }else{ + sqlite3VdbeGoto(v, labelContinue); + } + sqlite3VdbeResolveLabel(v, labelBreak); + + /* Update the sqlite_sequence table by storing the content of the + ** maximum rowid counter values recorded while inserting into + ** autoincrement tables. + */ + if( pParse->nested==0 && pParse->pTriggerTab==0 ){ + sqlite3AutoincrementEnd(pParse); + } + + /* + ** Return the number of rows that were changed. If this routine is + ** generating code because of a call to sqlite3NestedParse(), do not + ** invoke the callback function. + */ + if( (db->flags&SQLITE_CountRows) && !pParse->pTriggerTab && !pParse->nested ){ + sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC); + } + +update_cleanup: + sqlite3AuthContextPop(&sContext); + sqlite3DbFree(db, aXRef); /* Also frees aRegIdx[] and aToOpen[] */ + sqlite3SrcListDelete(db, pTabList); + sqlite3ExprListDelete(db, pChanges); + sqlite3ExprDelete(db, pWhere); + return; +} +/* Make sure "isView" and other macros defined above are undefined. Otherwise +** they may interfere with compilation of other functions in this file +** (or in another file, if this file becomes part of the amalgamation). */ +#ifdef isView + #undef isView +#endif +#ifdef pTrigger + #undef pTrigger +#endif + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Generate code for an UPDATE of a virtual table. +** +** There are two possible strategies - the default and the special +** "onepass" strategy. Onepass is only used if the virtual table +** implementation indicates that pWhere may match at most one row. +** +** The default strategy is to create an ephemeral table that contains +** for each row to be changed: +** +** (A) The original rowid of that row. +** (B) The revised rowid for the row. +** (C) The content of every column in the row. +** +** Then loop through the contents of this ephemeral table executing a +** VUpdate for each row. When finished, drop the ephemeral table. +** +** The "onepass" strategy does not use an ephemeral table. Instead, it +** stores the same values (A, B and C above) in a register array and +** makes a single invocation of VUpdate. +*/ +static void updateVirtualTable( + Parse *pParse, /* The parsing context */ + SrcList *pSrc, /* The virtual table to be modified */ + Table *pTab, /* The virtual table */ + ExprList *pChanges, /* The columns to change in the UPDATE statement */ + Expr *pRowid, /* Expression used to recompute the rowid */ + int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ + Expr *pWhere, /* WHERE clause of the UPDATE statement */ + int onError /* ON CONFLICT strategy */ +){ + Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ + int ephemTab; /* Table holding the result of the SELECT */ + int i; /* Loop counter */ + sqlite3 *db = pParse->db; /* Database connection */ + const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); + WhereInfo *pWInfo; + int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ + int regArg; /* First register in VUpdate arg array */ + int regRec; /* Register in which to assemble record */ + int regRowid; /* Register for ephem table rowid */ + int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ + int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ + int bOnePass; /* True to use onepass strategy */ + int addr; /* Address of OP_OpenEphemeral */ + + /* Allocate nArg registers to martial the arguments to VUpdate. Then + ** create and open the ephemeral table in which the records created from + ** these arguments will be temporarily stored. */ + assert( v ); + ephemTab = pParse->nTab++; + addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg); + regArg = pParse->nMem + 1; + pParse->nMem += nArg; + regRec = ++pParse->nMem; + regRowid = ++pParse->nMem; + + /* Start scanning the virtual table */ + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0); + 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; inCol; i++){ + if( aXRef[i]>=0 ){ + sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); + }else{ + sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); + } + } + + bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); + + if( bOnePass ){ + /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded + ** above. Also, if this is a top-level parse (not a trigger), clear the + ** multi-write flag so that the VM does not open a statement journal */ + sqlite3VdbeChangeToNoop(v, addr); + if( sqlite3IsToplevel(pParse) ){ + pParse->isMultiWrite = 0; + } + }else{ + /* Create a record from the argument register contents and insert it into + ** the ephemeral table. */ + sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); + sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); + } + + + if( bOnePass==0 ){ + /* End the virtual table scan */ + sqlite3WhereEnd(pWInfo); + + /* Begin scannning through the ephemeral table. */ + addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); + + /* Extract arguments from the current row of the ephemeral table and + ** invoke the VUpdate method. */ + for(i=0; idb, pNm); + if( iDb<0 ) iDb = 0; +#endif + } + if( iDb!=1 ){ + sqlite3VdbeAddOp1(v, OP_Vacuum, iDb); + sqlite3VdbeUsesBtree(v, iDb); + } + return; +} + +/* +** This routine implements the OP_Vacuum opcode of the VDBE. +*/ +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 */ + int saved_nChange; /* Saved value of db->nChange */ + int saved_nTotalChange; /* Saved value of db->nTotalChange */ + u8 saved_mTrace; /* Saved trace settings */ + Db *pDb = 0; /* Database to detach at end of vacuum */ + int isMemDb; /* True if vacuuming a :memory: database */ + int nRes; /* Bytes of reserved space at the end of each page */ + int nDb; /* Number of attached databases */ + const char *zDbMain; /* Schema name of database to vacuum */ + + if( !db->autoCommit ){ + sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); + return SQLITE_ERROR; + } + if( db->nVdbeActive>1 ){ + sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); + return SQLITE_ERROR; + } + + /* Save the current value of the database flags so that it can be + ** restored before returning. Then set the writable-schema flag, and + ** disable CHECK and foreign key constraints. */ + saved_flags = db->flags; + 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_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); + db->mTrace = 0; + + zDbMain = db->aDb[iDb].zDbSName; + pMain = db->aDb[iDb].pBt; + isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); + + /* Attach the temporary database as 'vacuum_db'. The synchronous pragma + ** can be set to 'off' for this file, as it is not recovered if a crash + ** occurs anyway. The integrity of the database is maintained by a + ** (possibly synchronous) transaction opened on the main database before + ** sqlite3BtreeCopyFile() is called. + ** + ** An optimisation would be to use a non-journaled pager. + ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but + ** that actually made the VACUUM run slower. Very little journalling + ** actually occurs when doing a vacuum since the vacuum_db is initially + ** empty. Only the journal header is written. Apparently it takes more + ** time to parse and run the PRAGMA to turn journalling off than it does + ** to write the journal header file. + */ + nDb = db->nDb; + rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db"); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + assert( (db->nDb-1)==nDb ); + pDb = &db->aDb[nDb]; + assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); + pTemp = pDb->pBt; + + /* The call to execSql() to attach the temp database has left the file + ** locked (as there was more than one active statement when the transaction + ** to read the schema was concluded. Unlock it here so that this doesn't + ** cause problems for the call to BtreeSetPageSize() below. */ + sqlite3BtreeCommit(pTemp); + + nRes = sqlite3BtreeGetOptimalReserve(pMain); + + /* A VACUUM cannot change the pagesize of an encrypted database. */ +#ifdef SQLITE_HAS_CODEC + if( db->nextPagesize ){ + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); + int nKey; + char *zKey; + sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + if( nKey ) db->nextPagesize = 0; + } +#endif + + sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); + sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); + sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL); + + /* Begin a transaction and take an exclusive lock on the main database + ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, + ** to ensure that we do not try to change the page-size on a WAL database. + */ + rc = execSql(db, pzErrMsg, "BEGIN"); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = sqlite3BtreeBeginTrans(pMain, 2); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + + /* Do not attempt to change the page size for a WAL database */ + if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) + ==PAGER_JOURNALMODE_WAL ){ + db->nextPagesize = 0; + } + + if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) + || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) + || NEVER(db->mallocFailed) + ){ + rc = SQLITE_NOMEM_BKPT; + goto end_of_vacuum; + } + +#ifndef SQLITE_OMIT_AUTOVACUUM + sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac : + sqlite3BtreeGetAutoVacuum(pMain)); +#endif + + /* Query the schema of the main database. Create a mirror schema + ** in the temporary database. + */ + db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='table'AND name<>'sqlite_sequence'" + " AND coalesce(rootpage,1)>0", + zDbMain + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='index' AND length(sql)>10", + zDbMain + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + db->init.iDb = 0; + + /* Loop through the tables in the main database. For each, do + ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy + ** the contents to the temporary database. + */ + rc = execSqlF(db, pzErrMsg, + "SELECT'INSERT INTO vacuum_db.'||quote(name)" + "||' SELECT*FROM\"%w\".'||quote(name)" + "FROM vacuum_db.sqlite_master " + "WHERE type='table'AND coalesce(rootpage,1)>0", + zDbMain + ); + assert( (db->flags & SQLITE_Vacuum)!=0 ); + db->flags &= ~SQLITE_Vacuum; + if( rc!=SQLITE_OK ) goto end_of_vacuum; + + /* Copy the triggers, views, and virtual tables from the main database + ** over to the temporary database. None of these objects has any + ** associated storage, so all we have to do is copy their entries + ** from the SQLITE_MASTER table. + */ + rc = execSqlF(db, pzErrMsg, + "INSERT INTO vacuum_db.sqlite_master" + " SELECT*FROM \"%w\".sqlite_master" + " WHERE type IN('view','trigger')" + " OR(type='table'AND rootpage=0)", + zDbMain + ); + if( rc ) goto end_of_vacuum; + + /* At this point, there is a write transaction open on both the + ** vacuum database and the main database. Assuming no error occurs, + ** both transactions are closed by this block - the main database + ** transaction by sqlite3BtreeCopyFile() and the other by an explicit + ** call to sqlite3BtreeCommit(). + */ + { + u32 meta; + int i; + + /* This array determines which meta meta values are preserved in the + ** vacuum. Even entries are the meta value number and odd entries + ** are an increment to apply to the meta value after the vacuum. + ** The increment is used to increase the schema cookie so that other + ** connections to the same database will know to reread the schema. + */ + static const unsigned char aCopy[] = { + BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ + BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ + BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ + BTREE_USER_VERSION, 0, /* Preserve the user version */ + BTREE_APPLICATION_ID, 0, /* Preserve the application id */ + }; + + assert( 1==sqlite3BtreeIsInTrans(pTemp) ); + assert( 1==sqlite3BtreeIsInTrans(pMain) ); + + /* Copy Btree meta values */ + for(i=0; iflags */ + db->init.iDb = 0; + db->flags = saved_flags; + db->nChange = saved_nChange; + db->nTotalChange = saved_nTotalChange; + db->mTrace = saved_mTrace; + sqlite3BtreeSetPageSize(pMain, -1, -1, 1); + + /* Currently there is an SQL level transaction open on the vacuum + ** database. No locks are held on any other files (since the main file + ** was committed at the btree level). So it safe to end the transaction + ** by manually setting the autoCommit flag to true and detaching the + ** vacuum database. The vacuum_db journal file is deleted when the pager + ** is closed by the DETACH. + */ + db->autoCommit = 1; + + if( pDb ){ + sqlite3BtreeClose(pDb->pBt); + pDb->pBt = 0; + pDb->pSchema = 0; + } + + /* This both clears the schemas and reduces the size of the db->aDb[] + ** array. */ + sqlite3ResetAllSchemasOfConnection(db); + + return rc; +} + +#endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */ + +/************** End of vacuum.c **********************************************/ +/************** Begin file vtab.c ********************************************/ +/* +** 2006 June 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 contains code used to help implement virtual tables. +*/ +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* #include "sqliteInt.h" */ + +/* +** Before a virtual table xCreate() or xConnect() method is invoked, the +** sqlite3.pVtabCtx member variable is set to point to an instance of +** this struct allocated on the stack. It is used by the implementation of +** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which +** are invoked only from within xCreate and xConnect methods. +*/ +struct VtabCtx { + VTable *pVTable; /* The virtual table being constructed */ + Table *pTab; /* The Table object to which the virtual table belongs */ + VtabCtx *pPrior; /* Parent context (if any) */ + int bDeclared; /* True after sqlite3_declare_vtab() is called */ +}; + +/* +** Construct and install a Module object for a virtual table. When this +** routine is called, it is guaranteed that all appropriate locks are held +** and the module is not already part of the connection. +*/ +SQLITE_PRIVATE Module *sqlite3VtabCreateModule( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule, /* The definition of the module */ + void *pAux, /* Context pointer for xCreate/xConnect */ + void (*xDestroy)(void *) /* Module destructor function */ +){ + Module *pMod; + int nName = sqlite3Strlen30(zName); + pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1); + if( pMod ){ + Module *pDel; + char *zCopy = (char *)(&pMod[1]); + memcpy(zCopy, zName, nName+1); + pMod->zName = zCopy; + pMod->pModule = pModule; + pMod->pAux = pAux; + pMod->xDestroy = xDestroy; + pMod->pEpoTab = 0; + pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); + assert( pDel==0 || pDel==pMod ); + if( pDel ){ + sqlite3OomFault(db); + sqlite3DbFree(db, pDel); + pMod = 0; + } + } + return pMod; +} + +/* +** The actual function that does the work of creating a new module. +** This function implements the sqlite3_create_module() and +** sqlite3_create_module_v2() interfaces. +*/ +static int createModule( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule, /* The definition of the module */ + void *pAux, /* Context pointer for xCreate/xConnect */ + void (*xDestroy)(void *) /* Module destructor function */ +){ + int rc = SQLITE_OK; + + sqlite3_mutex_enter(db->mutex); + if( sqlite3HashFind(&db->aModule, zName) ){ + rc = SQLITE_MISUSE_BKPT; + }else{ + (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); + } + rc = sqlite3ApiExit(db, rc); + if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); + sqlite3_mutex_leave(db->mutex); + return rc; +} + + +/* +** External API function used to create a new virtual-table module. +*/ +SQLITE_API int sqlite3_create_module( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule, /* The definition of the module */ + void *pAux /* Context pointer for xCreate/xConnect */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif + return createModule(db, zName, pModule, pAux, 0); +} + +/* +** External API function used to create a new virtual-table module. +*/ +SQLITE_API int sqlite3_create_module_v2( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule, /* The definition of the module */ + void *pAux, /* Context pointer for xCreate/xConnect */ + void (*xDestroy)(void *) /* Module destructor function */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif + return createModule(db, zName, pModule, pAux, xDestroy); +} + +/* +** Lock the virtual table so that it cannot be disconnected. +** Locks nest. Every lock should have a corresponding unlock. +** If an unlock is omitted, resources leaks will occur. +** +** If a disconnect is attempted while a virtual table is locked, +** the disconnect is deferred until all locks have been removed. +*/ +SQLITE_PRIVATE void sqlite3VtabLock(VTable *pVTab){ + pVTab->nRef++; +} + + +/* +** pTab is a pointer to a Table structure representing a virtual-table. +** Return a pointer to the VTable object used by connection db to access +** this virtual-table, if one has been created, or NULL otherwise. +*/ +SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ + VTable *pVtab; + assert( IsVirtual(pTab) ); + for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); + return pVtab; +} + +/* +** Decrement the ref-count on a virtual table object. When the ref-count +** reaches zero, call the xDisconnect() method to delete the object. +*/ +SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){ + sqlite3 *db = pVTab->db; + + assert( db ); + assert( pVTab->nRef>0 ); + assert( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ZOMBIE ); + + pVTab->nRef--; + if( pVTab->nRef==0 ){ + sqlite3_vtab *p = pVTab->pVtab; + if( p ){ + p->pModule->xDisconnect(p); + } + sqlite3DbFree(db, pVTab); + } +} + +/* +** Table p is a virtual table. This function moves all elements in the +** p->pVTable list to the sqlite3.pDisconnect lists of their associated +** database connections to be disconnected at the next opportunity. +** Except, if argument db is not NULL, then the entry associated with +** connection db is left in the p->pVTable list. +*/ +static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ + VTable *pRet = 0; + VTable *pVTable = p->pVTable; + p->pVTable = 0; + + /* Assert that the mutex (if any) associated with the BtShared database + ** that contains table p is held by the caller. See header comments + ** above function sqlite3VtabUnlockList() for an explanation of why + ** this makes it safe to access the sqlite3.pDisconnect list of any + ** database connection that may have an entry in the p->pVTable list. + */ + assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); + + while( pVTable ){ + sqlite3 *db2 = pVTable->db; + VTable *pNext = pVTable->pNext; + assert( db2 ); + if( db2==db ){ + pRet = pVTable; + p->pVTable = pRet; + pRet->pNext = 0; + }else{ + pVTable->pNext = db2->pDisconnect; + db2->pDisconnect = pVTable; + } + pVTable = pNext; + } + + assert( !db || pRet ); + return pRet; +} + +/* +** Table *p is a virtual table. This function removes the VTable object +** for table *p associated with database connection db from the linked +** list in p->pVTab. It also decrements the VTable ref count. This is +** used when closing database connection db to free all of its VTable +** objects without disturbing the rest of the Schema object (which may +** be being used by other shared-cache connections). +*/ +SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ + VTable **ppVTab; + + assert( IsVirtual(p) ); + assert( sqlite3BtreeHoldsAllMutexes(db) ); + assert( sqlite3_mutex_held(db->mutex) ); + + for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){ + if( (*ppVTab)->db==db ){ + VTable *pVTab = *ppVTab; + *ppVTab = pVTab->pNext; + sqlite3VtabUnlock(pVTab); + break; + } + } +} + + +/* +** Disconnect all the virtual table objects in the sqlite3.pDisconnect list. +** +** This function may only be called when the mutexes associated with all +** shared b-tree databases opened using connection db are held by the +** caller. This is done to protect the sqlite3.pDisconnect list. The +** sqlite3.pDisconnect list is accessed only as follows: +** +** 1) By this function. In this case, all BtShared mutexes and the mutex +** associated with the database handle itself must be held. +** +** 2) By function vtabDisconnectAll(), when it adds a VTable entry to +** the sqlite3.pDisconnect list. In this case either the BtShared mutex +** associated with the database the virtual table is stored in is held +** or, if the virtual table is stored in a non-sharable database, then +** the database handle mutex is held. +** +** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously +** by multiple threads. It is thread-safe. +*/ +SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){ + VTable *p = db->pDisconnect; + db->pDisconnect = 0; + + assert( sqlite3BtreeHoldsAllMutexes(db) ); + assert( sqlite3_mutex_held(db->mutex) ); + + if( p ){ + sqlite3ExpirePreparedStatements(db); + do { + VTable *pNext = p->pNext; + sqlite3VtabUnlock(p); + p = pNext; + }while( p ); + } +} + +/* +** Clear any and all virtual-table information from the Table record. +** This routine is called, for example, just before deleting the Table +** record. +** +** Since it is a virtual-table, the Table structure contains a pointer +** to the head of a linked list of VTable structures. Each VTable +** structure is associated with a single sqlite3* user of the schema. +** The reference count of the VTable structure associated with database +** connection db is decremented immediately (which may lead to the +** structure being xDisconnected and free). Any other VTable structures +** in the list are moved to the sqlite3.pDisconnect list of the associated +** database connection. +*/ +SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){ + if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); + if( p->azModuleArg ){ + int i; + for(i=0; inModuleArg; i++){ + if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]); + } + sqlite3DbFree(db, p->azModuleArg); + } +} + +/* +** Add a new module argument to pTable->azModuleArg[]. +** The string is not copied - the pointer is stored. The +** string will be freed automatically when the table is +** deleted. +*/ +static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ + int nBytes = sizeof(char *)*(2+pTable->nModuleArg); + char **azModuleArg; + azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); + if( azModuleArg==0 ){ + sqlite3DbFree(db, zArg); + }else{ + int i = pTable->nModuleArg++; + azModuleArg[i] = zArg; + azModuleArg[i+1] = 0; + pTable->azModuleArg = azModuleArg; + } +} + +/* +** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE +** statement. The module name has been parsed, but the optional list +** of parameters that follow the module name are still pending. +*/ +SQLITE_PRIVATE void sqlite3VtabBeginParse( + Parse *pParse, /* Parsing context */ + Token *pName1, /* Name of new table, or database name */ + Token *pName2, /* Name of new table or NULL */ + Token *pModuleName, /* Name of the module for the virtual table */ + int ifNotExists /* No error if the table already exists */ +){ + int iDb; /* The database the table is being created in */ + Table *pTable; /* The new virtual table */ + sqlite3 *db; /* Database connection */ + + sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists); + pTable = pParse->pNewTable; + if( pTable==0 ) return; + assert( 0==pTable->pIndex ); + + db = pParse->db; + iDb = sqlite3SchemaToIndex(db, pTable->pSchema); + assert( iDb>=0 ); + + assert( pTable->nModuleArg==0 ); + addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); + addModuleArgument(db, pTable, 0); + addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); + assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) + || (pParse->sNameToken.z==pName1->z && pName2->z==0) + ); + pParse->sNameToken.n = (int)( + &pModuleName->z[pModuleName->n] - pParse->sNameToken.z + ); + +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Creating a virtual table invokes the authorization callback twice. + ** The first invocation, to obtain permission to INSERT a row into the + ** sqlite_master table, has already been made by sqlite3StartTable(). + ** The second call, to obtain permission to create the table, is made now. + */ + if( pTable->azModuleArg ){ + sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, + pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); + } +#endif +} + +/* +** This routine takes the module argument that has been accumulating +** in pParse->zArg[] and appends it to the list of arguments on the +** virtual table currently under construction in pParse->pTable. +*/ +static void addArgumentToVtab(Parse *pParse){ + if( pParse->sArg.z && pParse->pNewTable ){ + const char *z = (const char*)pParse->sArg.z; + int n = pParse->sArg.n; + sqlite3 *db = pParse->db; + addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); + } +} + +/* +** The parser calls this routine after the CREATE VIRTUAL TABLE statement +** has been completely parsed. +*/ +SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ + Table *pTab = pParse->pNewTable; /* The table being constructed */ + sqlite3 *db = pParse->db; /* The database connection */ + + if( pTab==0 ) return; + addArgumentToVtab(pParse); + pParse->sArg.z = 0; + if( pTab->nModuleArg<1 ) return; + + /* If the CREATE VIRTUAL TABLE statement is being entered for the + ** first time (in other words if the virtual table is actually being + ** created now instead of just being read out of sqlite_master) then + ** do additional initialization work and store the statement text + ** in the sqlite_master table. + */ + if( !db->init.busy ){ + char *zStmt; + char *zWhere; + int iDb; + int iReg; + Vdbe *v; + + /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ + if( pEnd ){ + pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n; + } + zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken); + + /* A slot for the record has already been allocated in the + ** SQLITE_MASTER table. We just need to update that slot with all + ** the information we've collected. + ** + ** The VM register number pParse->regRowid holds the rowid of an + ** entry in the sqlite_master table tht was created for this vtab + ** by sqlite3StartTable(). + */ + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + sqlite3NestedParse(pParse, + "UPDATE %Q.%s " + "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " + "WHERE rowid=#%d", + db->aDb[iDb].zDbSName, MASTER_NAME, + pTab->zName, + pTab->zName, + zStmt, + pParse->regRowid + ); + sqlite3DbFree(db, zStmt); + v = sqlite3GetVdbe(pParse); + sqlite3ChangeCookie(pParse, iDb); + + sqlite3VdbeAddOp0(v, OP_Expire); + zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); + sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); + + iReg = ++pParse->nMem; + sqlite3VdbeLoadString(v, iReg, pTab->zName); + sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); + } + + /* If we are rereading the sqlite_master table create the in-memory + ** record of the table. The xConnect() method is not called until + ** the first time the virtual table is used in an SQL statement. This + ** allows a schema that contains virtual tables to be loaded before + ** the required virtual table implementations are registered. */ + else { + Table *pOld; + Schema *pSchema = pTab->pSchema; + const char *zName = pTab->zName; + assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); + pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); + if( pOld ){ + sqlite3OomFault(db); + assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ + return; + } + pParse->pNewTable = 0; + } +} + +/* +** The parser calls this routine when it sees the first token +** of an argument to the module name in a CREATE VIRTUAL TABLE statement. +*/ +SQLITE_PRIVATE void sqlite3VtabArgInit(Parse *pParse){ + addArgumentToVtab(pParse); + pParse->sArg.z = 0; + pParse->sArg.n = 0; +} + +/* +** The parser calls this routine for each token after the first token +** in an argument to the module name in a CREATE VIRTUAL TABLE statement. +*/ +SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){ + Token *pArg = &pParse->sArg; + if( pArg->z==0 ){ + pArg->z = p->z; + pArg->n = p->n; + }else{ + assert(pArg->z <= p->z); + pArg->n = (int)(&p->z[p->n] - pArg->z); + } +} + +/* +** Invoke a virtual table constructor (either xCreate or xConnect). The +** pointer to the function to invoke is passed as the fourth parameter +** to this procedure. +*/ +static int vtabCallConstructor( + sqlite3 *db, + Table *pTab, + Module *pMod, + int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), + char **pzErr +){ + VtabCtx sCtx; + VTable *pVTable; + int rc; + const char *const*azArg = (const char *const*)pTab->azModuleArg; + int nArg = pTab->nModuleArg; + char *zErr = 0; + char *zModuleName; + int iDb; + VtabCtx *pCtx; + + /* Check that the virtual-table is not already being initialized */ + for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ + if( pCtx->pTab==pTab ){ + *pzErr = sqlite3MPrintf(db, + "vtable constructor called recursively: %s", pTab->zName + ); + return SQLITE_LOCKED; + } + } + + zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); + if( !zModuleName ){ + return SQLITE_NOMEM_BKPT; + } + + pVTable = sqlite3DbMallocZero(db, sizeof(VTable)); + if( !pVTable ){ + sqlite3DbFree(db, zModuleName); + return SQLITE_NOMEM_BKPT; + } + pVTable->db = db; + pVTable->pMod = pMod; + + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + pTab->azModuleArg[1] = db->aDb[iDb].zDbSName; + + /* Invoke the virtual table constructor */ + assert( &db->pVtabCtx ); + assert( xConstruct ); + sCtx.pTab = pTab; + sCtx.pVTable = pVTable; + sCtx.pPrior = db->pVtabCtx; + sCtx.bDeclared = 0; + db->pVtabCtx = &sCtx; + rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); + db->pVtabCtx = sCtx.pPrior; + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); + assert( sCtx.pTab==pTab ); + + if( SQLITE_OK!=rc ){ + if( zErr==0 ){ + *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); + }else { + *pzErr = sqlite3MPrintf(db, "%s", zErr); + sqlite3_free(zErr); + } + sqlite3DbFree(db, pVTable); + }else if( ALWAYS(pVTable->pVtab) ){ + /* Justification of ALWAYS(): A correct vtab constructor must allocate + ** the sqlite3_vtab object if successful. */ + memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); + pVTable->pVtab->pModule = pMod->pModule; + pVTable->nRef = 1; + if( sCtx.bDeclared==0 ){ + const char *zFormat = "vtable constructor did not declare schema: %s"; + *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); + sqlite3VtabUnlock(pVTable); + rc = SQLITE_ERROR; + }else{ + int iCol; + u8 oooHidden = 0; + /* If everything went according to plan, link the new VTable structure + ** into the linked list headed by pTab->pVTable. Then loop through the + ** columns of the table to see if any of them contain the token "hidden". + ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from + ** the type string. */ + pVTable->pNext = pTab->pVTable; + pTab->pVTable = pVTable; + + for(iCol=0; iColnCol; iCol++){ + char *zType = sqlite3ColumnType(&pTab->aCol[iCol], ""); + int nType; + int i = 0; + nType = sqlite3Strlen30(zType); + for(i=0; i0 ){ + assert(zType[i-1]==' '); + zType[i-1] = '\0'; + } + pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN; + oooHidden = TF_OOOHidden; + }else{ + pTab->tabFlags |= oooHidden; + } + } + } + } + + sqlite3DbFree(db, zModuleName); + return rc; +} + +/* +** This function is invoked by the parser to call the xConnect() method +** of the virtual table pTab. If an error occurs, an error code is returned +** and an error left in pParse. +** +** This call is a no-op if table pTab is not a virtual table. +*/ +SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ + sqlite3 *db = pParse->db; + const char *zMod; + Module *pMod; + int rc; + + assert( pTab ); + if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){ + return SQLITE_OK; + } + + /* Locate the required virtual table module */ + zMod = pTab->azModuleArg[0]; + pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); + + if( !pMod ){ + const char *zModule = pTab->azModuleArg[0]; + sqlite3ErrorMsg(pParse, "no such module: %s", zModule); + rc = SQLITE_ERROR; + }else{ + char *zErr = 0; + rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3ErrorMsg(pParse, "%s", zErr); + } + sqlite3DbFree(db, zErr); + } + + return rc; +} +/* +** Grow the db->aVTrans[] array so that there is room for at least one +** more v-table. Return SQLITE_NOMEM if a malloc fails, or SQLITE_OK otherwise. +*/ +static int growVTrans(sqlite3 *db){ + const int ARRAY_INCR = 5; + + /* Grow the sqlite3.aVTrans array if required */ + if( (db->nVTrans%ARRAY_INCR)==0 ){ + VTable **aVTrans; + int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); + aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); + if( !aVTrans ){ + return SQLITE_NOMEM_BKPT; + } + memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR); + db->aVTrans = aVTrans; + } + + return SQLITE_OK; +} + +/* +** Add the virtual table pVTab to the array sqlite3.aVTrans[]. Space should +** have already been reserved using growVTrans(). +*/ +static void addToVTrans(sqlite3 *db, VTable *pVTab){ + /* Add pVtab to the end of sqlite3.aVTrans */ + db->aVTrans[db->nVTrans++] = pVTab; + sqlite3VtabLock(pVTab); +} + +/* +** This function is invoked by the vdbe to call the xCreate method +** of the virtual table named zTab in database iDb. +** +** If an error occurs, *pzErr is set to point to an English language +** description of the error and an SQLITE_XXX error code is returned. +** In this case the caller must call sqlite3DbFree(db, ) on *pzErr. +*/ +SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ + int rc = SQLITE_OK; + Table *pTab; + Module *pMod; + const char *zMod; + + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); + assert( pTab && IsVirtual(pTab) && !pTab->pVTable ); + + /* Locate the required virtual table module */ + zMod = pTab->azModuleArg[0]; + pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); + + /* If the module has been registered and includes a Create method, + ** invoke it now. If the module has not been registered, return an + ** error. Otherwise, do nothing. + */ + if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){ + *pzErr = sqlite3MPrintf(db, "no such module: %s", zMod); + rc = SQLITE_ERROR; + }else{ + rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); + } + + /* Justification of ALWAYS(): The xConstructor method is required to + ** create a valid sqlite3_vtab if it returns SQLITE_OK. */ + if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){ + rc = growVTrans(db); + if( rc==SQLITE_OK ){ + addToVTrans(db, sqlite3GetVTable(db, pTab)); + } + } + + return rc; +} + +/* +** This function is used to set the schema of a virtual table. It is only +** valid to call this function from within the xCreate() or xConnect() of a +** virtual table module. +*/ +SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ + VtabCtx *pCtx; + Parse *pParse; + int rc = SQLITE_OK; + Table *pTab; + char *zErr = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + pCtx = db->pVtabCtx; + if( !pCtx || pCtx->bDeclared ){ + sqlite3Error(db, SQLITE_MISUSE); + sqlite3_mutex_leave(db->mutex); + return SQLITE_MISUSE_BKPT; + } + 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; + } + } + pCtx->bDeclared = 1; + }else{ + sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); + sqlite3DbFree(db, zErr); + rc = SQLITE_ERROR; + } + pParse->declareVtab = 0; + + if( pParse->pVdbe ){ + sqlite3VdbeFinalize(pParse->pVdbe); + } + sqlite3DeleteTable(db, pParse->pNewTable); + sqlite3ParserReset(pParse); + sqlite3StackFree(db, pParse); + } + + assert( (rc&0xff)==rc ); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** This function is invoked by the vdbe to call the xDestroy method +** of the virtual table named zTab in database iDb. This occurs +** when a DROP TABLE is mentioned. +** +** This call is a no-op if zTab is not a virtual table. +*/ +SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ + int rc = SQLITE_OK; + Table *pTab; + + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); + if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ + VTable *p; + int (*xDestroy)(sqlite3_vtab *); + for(p=pTab->pVTable; p; p=p->pNext){ + assert( p->pVtab ); + if( p->pVtab->nRef>0 ){ + return SQLITE_LOCKED; + } + } + p = vtabDisconnectAll(db, pTab); + xDestroy = p->pMod->pModule->xDestroy; + assert( xDestroy!=0 ); /* Checked before the virtual table is created */ + rc = xDestroy(p->pVtab); + /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ + if( rc==SQLITE_OK ){ + assert( pTab->pVTable==p && p->pNext==0 ); + p->pVtab = 0; + pTab->pVTable = 0; + sqlite3VtabUnlock(p); + } + } + + return rc; +} + +/* +** This function invokes either the xRollback or xCommit method +** of each of the virtual tables in the sqlite3.aVTrans array. The method +** called is identified by the second argument, "offset", which is +** the offset of the method to call in the sqlite3_module structure. +** +** The array is cleared after invoking the callbacks. +*/ +static void callFinaliser(sqlite3 *db, int offset){ + int i; + if( db->aVTrans ){ + VTable **aVTrans = db->aVTrans; + db->aVTrans = 0; + for(i=0; inVTrans; i++){ + VTable *pVTab = aVTrans[i]; + sqlite3_vtab *p = pVTab->pVtab; + if( p ){ + int (*x)(sqlite3_vtab *); + x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset); + if( x ) x(p); + } + pVTab->iSavepoint = 0; + sqlite3VtabUnlock(pVTab); + } + sqlite3DbFree(db, aVTrans); + db->nVTrans = 0; + } +} + +/* +** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans +** array. Return the error code for the first error that occurs, or +** SQLITE_OK if all xSync operations are successful. +** +** If an error message is available, leave it in p->zErrMsg. +*/ +SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe *p){ + int i; + int rc = SQLITE_OK; + VTable **aVTrans = db->aVTrans; + + db->aVTrans = 0; + for(i=0; rc==SQLITE_OK && inVTrans; i++){ + int (*x)(sqlite3_vtab *); + sqlite3_vtab *pVtab = aVTrans[i]->pVtab; + if( pVtab && (x = pVtab->pModule->xSync)!=0 ){ + rc = x(pVtab); + sqlite3VtabImportErrmsg(p, pVtab); + } + } + db->aVTrans = aVTrans; + return rc; +} + +/* +** Invoke the xRollback method of all virtual tables in the +** sqlite3.aVTrans array. Then clear the array itself. +*/ +SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){ + callFinaliser(db, offsetof(sqlite3_module,xRollback)); + return SQLITE_OK; +} + +/* +** Invoke the xCommit method of all virtual tables in the +** sqlite3.aVTrans array. Then clear the array itself. +*/ +SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db){ + callFinaliser(db, offsetof(sqlite3_module,xCommit)); + return SQLITE_OK; +} + +/* +** If the virtual table pVtab supports the transaction interface +** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is +** not currently open, invoke the xBegin method now. +** +** If the xBegin call is successful, place the sqlite3_vtab pointer +** in the sqlite3.aVTrans array. +*/ +SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ + int rc = SQLITE_OK; + const sqlite3_module *pModule; + + /* Special case: If db->aVTrans is NULL and db->nVTrans is greater + ** than zero, then this function is being called from within a + ** virtual module xSync() callback. It is illegal to write to + ** virtual module tables in this case, so return SQLITE_LOCKED. + */ + if( sqlite3VtabInSync(db) ){ + return SQLITE_LOCKED; + } + if( !pVTab ){ + return SQLITE_OK; + } + pModule = pVTab->pVtab->pModule; + + if( pModule->xBegin ){ + int i; + + /* If pVtab is already in the aVTrans array, return early */ + for(i=0; inVTrans; i++){ + if( db->aVTrans[i]==pVTab ){ + return SQLITE_OK; + } + } + + /* Invoke the xBegin method. If successful, add the vtab to the + ** sqlite3.aVTrans[] array. */ + rc = growVTrans(db); + if( rc==SQLITE_OK ){ + rc = pModule->xBegin(pVTab->pVtab); + if( rc==SQLITE_OK ){ + int iSvpt = db->nStatement + db->nSavepoint; + addToVTrans(db, pVTab); + if( iSvpt && pModule->xSavepoint ){ + pVTab->iSavepoint = iSvpt; + rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1); + } + } + } + } + return rc; +} + +/* +** Invoke either the xSavepoint, xRollbackTo or xRelease method of all +** virtual tables that currently have an open transaction. Pass iSavepoint +** as the second argument to the virtual table method invoked. +** +** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is +** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is +** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with +** an open transaction is invoked. +** +** If any virtual table method returns an error code other than SQLITE_OK, +** processing is abandoned and the error returned to the caller of this +** function immediately. If all calls to virtual table methods are successful, +** SQLITE_OK is returned. +*/ +SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ + int rc = SQLITE_OK; + + assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); + assert( iSavepoint>=-1 ); + if( db->aVTrans ){ + int i; + for(i=0; rc==SQLITE_OK && inVTrans; i++){ + VTable *pVTab = db->aVTrans[i]; + const sqlite3_module *pMod = pVTab->pMod->pModule; + if( pVTab->pVtab && pMod->iVersion>=2 ){ + int (*xMethod)(sqlite3_vtab *, int); + switch( op ){ + case SAVEPOINT_BEGIN: + xMethod = pMod->xSavepoint; + pVTab->iSavepoint = iSavepoint+1; + break; + case SAVEPOINT_ROLLBACK: + xMethod = pMod->xRollbackTo; + break; + default: + xMethod = pMod->xRelease; + break; + } + if( xMethod && pVTab->iSavepoint>iSavepoint ){ + rc = xMethod(pVTab->pVtab, iSavepoint); + } + } + } + } + return rc; +} + +/* +** The first parameter (pDef) is a function implementation. The +** second parameter (pExpr) is the first argument to this function. +** If pExpr is a column in a virtual table, then let the virtual +** table implementation have an opportunity to overload the function. +** +** This routine is used to allow virtual table implementations to +** overload MATCH, LIKE, GLOB, and REGEXP operators. +** +** Return either the pDef argument (indicating no change) or a +** new FuncDef structure that is marked as ephemeral using the +** SQLITE_FUNC_EPHEM flag. +*/ +SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( + sqlite3 *db, /* Database connection for reporting malloc problems */ + FuncDef *pDef, /* Function to possibly overload */ + int nArg, /* Number of arguments to the function */ + Expr *pExpr /* First argument to the function */ +){ + Table *pTab; + sqlite3_vtab *pVtab; + sqlite3_module *pMod; + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0; + void *pArg = 0; + FuncDef *pNew; + int rc = 0; + char *zLowerName; + unsigned char *z; + + + /* Check to see the left operand is a column in a virtual table */ + if( NEVER(pExpr==0) ) return pDef; + if( pExpr->op!=TK_COLUMN ) return pDef; + pTab = pExpr->pTab; + if( pTab==0 ) return pDef; + if( !IsVirtual(pTab) ) return pDef; + pVtab = sqlite3GetVTable(db, pTab)->pVtab; + assert( pVtab!=0 ); + assert( pVtab->pModule!=0 ); + pMod = (sqlite3_module *)pVtab->pModule; + if( pMod->xFindFunction==0 ) return pDef; + + /* Call the xFindFunction method on the virtual table implementation + ** to see if the implementation wants to overload this function + */ + zLowerName = sqlite3DbStrDup(db, pDef->zName); + if( zLowerName ){ + for(z=(unsigned char*)zLowerName; *z; z++){ + *z = sqlite3UpperToLower[*z]; + } + rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg); + sqlite3DbFree(db, zLowerName); + } + if( rc==0 ){ + return pDef; + } + + /* Create a new ephemeral function definition for the overloaded + ** function */ + pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + + sqlite3Strlen30(pDef->zName) + 1); + if( pNew==0 ){ + return pDef; + } + *pNew = *pDef; + pNew->zName = (const char*)&pNew[1]; + memcpy((char*)&pNew[1], pDef->zName, sqlite3Strlen30(pDef->zName)+1); + pNew->xSFunc = xSFunc; + pNew->pUserData = pArg; + pNew->funcFlags |= SQLITE_FUNC_EPHEM; + return pNew; +} + +/* +** Make sure virtual table pTab is contained in the pParse->apVirtualLock[] +** array so that an OP_VBegin will get generated for it. Add pTab to the +** array if it is missing. If pTab is already in the array, this routine +** is a no-op. +*/ +SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + int i, n; + Table **apVtabLock; + + assert( IsVirtual(pTab) ); + for(i=0; inVtabLock; i++){ + if( pTab==pToplevel->apVtabLock[i] ) return; + } + n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]); + apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n); + if( apVtabLock ){ + pToplevel->apVtabLock = apVtabLock; + pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; + }else{ + sqlite3OomFault(pToplevel->db); + } +} + +/* +** Check to see if virtual table module pMod can be have an eponymous +** virtual table instance. If it can, create one if one does not already +** exist. Return non-zero if the eponymous virtual table instance exists +** when this routine returns, and return zero if it does not exist. +** +** An eponymous virtual table instance is one that is named after its +** module, and more importantly, does not require a CREATE VIRTUAL TABLE +** statement in order to come into existance. Eponymous virtual table +** instances always exist. They cannot be DROP-ed. +** +** Any virtual table module for which xConnect and xCreate are the same +** method can have an eponymous virtual table instance. +*/ +SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ + const sqlite3_module *pModule = pMod->pModule; + Table *pTab; + char *zErr = 0; + int rc; + sqlite3 *db = pParse->db; + if( pMod->pEpoTab ) return 1; + if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0; + pTab = sqlite3DbMallocZero(db, sizeof(Table)); + if( pTab==0 ) return 0; + pTab->zName = sqlite3DbStrDup(db, pMod->zName); + if( pTab->zName==0 ){ + sqlite3DbFree(db, pTab); + return 0; + } + pMod->pEpoTab = pTab; + pTab->nTabRef = 1; + pTab->pSchema = db->aDb[0].pSchema; + assert( pTab->nModuleArg==0 ); + pTab->iPKey = -1; + addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); + addModuleArgument(db, pTab, 0); + addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); + rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); + if( rc ){ + sqlite3ErrorMsg(pParse, "%s", zErr); + sqlite3DbFree(db, zErr); + sqlite3VtabEponymousTableClear(db, pMod); + return 0; + } + return 1; +} + +/* +** Erase the eponymous virtual table instance associated with +** virtual table module pMod, if it exists. +*/ +SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ + Table *pTab = pMod->pEpoTab; + if( pTab!=0 ){ + /* Mark the table as Ephemeral prior to deleting it, so that the + ** sqlite3DeleteTable() routine will know that it is not stored in + ** the schema. */ + pTab->tabFlags |= TF_Ephemeral; + sqlite3DeleteTable(db, pTab); + pMod->pEpoTab = 0; + } +} + +/* +** Return the ON CONFLICT resolution mode in effect for the virtual +** table update operation currently in progress. +** +** The results of this routine are undefined unless it is called from +** within an xUpdate method. +*/ +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){ + static const unsigned char aMap[] = { + SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE + }; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); + assert( OE_Ignore==4 && OE_Replace==5 ); + assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); + return (int)aMap[db->vtabOnConflict-1]; +} + +/* +** Call from within the xCreate() or xConnect() methods to provide +** the SQLite core with additional information about the behavior +** of the virtual table being implemented. +*/ +SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ + va_list ap; + int rc = SQLITE_OK; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + va_start(ap, op); + switch( op ){ + case SQLITE_VTAB_CONSTRAINT_SUPPORT: { + VtabCtx *p = db->pVtabCtx; + if( !p ){ + rc = SQLITE_MISUSE_BKPT; + }else{ + assert( p->pTab==0 || IsVirtual(p->pTab) ); + p->pVTable->bConstraint = (u8)va_arg(ap, int); + } + break; + } + default: + rc = SQLITE_MISUSE_BKPT; + break; + } + va_end(ap); + + if( rc!=SQLITE_OK ) sqlite3Error(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +/************** End of vtab.c ************************************************/ +/************** Begin file wherecode.c ***************************************/ +/* +** 2015-06-06 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This module contains C code that generates VDBE code used to process +** the WHERE clause of SQL statements. +** +** This file was split off from where.c on 2015-06-06 in order to reduce the +** size of where.c and make it easier to edit. This file contains the routines +** that actually generate the bulk of the WHERE loop code. The original where.c +** file retains the code that does query planning and analysis. +*/ +/* #include "sqliteInt.h" */ +/************** Include whereInt.h in the middle of wherecode.c **************/ +/************** Begin file whereInt.h ****************************************/ +/* +** 2013-11-12 +** +** 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 structure and macro definitions for the query +** planner logic in "where.c". These definitions are broken out into +** a separate source file for easier editing. +*/ + +/* +** Trace output macros +*/ +#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) +/***/ int sqlite3WhereTrace; +#endif +#if defined(SQLITE_DEBUG) \ + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) +# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X +# define WHERETRACE_ENABLED 1 +#else +# define WHERETRACE(K,X) +#endif + +/* Forward references +*/ +typedef struct WhereClause WhereClause; +typedef struct WhereMaskSet WhereMaskSet; +typedef struct WhereOrInfo WhereOrInfo; +typedef struct WhereAndInfo WhereAndInfo; +typedef struct WhereLevel WhereLevel; +typedef struct WhereLoop WhereLoop; +typedef struct WherePath WherePath; +typedef struct WhereTerm WhereTerm; +typedef struct WhereLoopBuilder WhereLoopBuilder; +typedef struct WhereScan WhereScan; +typedef struct WhereOrCost WhereOrCost; +typedef struct WhereOrSet WhereOrSet; + +/* +** This object contains information needed to implement a single nested +** loop in WHERE clause. +** +** Contrast this object with WhereLoop. This object describes the +** implementation of the loop. WhereLoop describes the algorithm. +** This object contains a pointer to the WhereLoop algorithm as one of +** its elements. +** +** The WhereInfo object contains a single instance of this object for +** each term in the FROM clause (which is to say, for each of the +** nested loops as implemented). The order of WhereLevel objects determines +** the loop nested order, with WhereInfo.a[0] being the outer loop and +** WhereInfo.a[WhereInfo.nLevel-1] being the inner loop. +*/ +struct WhereLevel { + int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */ + int iTabCur; /* The VDBE cursor used to access the table */ + int iIdxCur; /* The VDBE cursor used to access pIdx */ + int addrBrk; /* Jump here to break out of the loop */ + int addrNxt; /* Jump here to start the next IN combination */ + int addrSkip; /* Jump here for next iteration of skip-scan */ + int addrCont; /* Jump here to continue with the next loop cycle */ + int addrFirst; /* First instruction of interior of the loop */ + int addrBody; /* Beginning of the body of this loop */ +#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS + u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ + int addrLikeRep; /* LIKE range processing address */ +#endif + u8 iFrom; /* Which entry in the FROM clause */ + u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ + int p1, p2; /* Operands of the opcode used to ends the loop */ + union { /* Information that depends on pWLoop->wsFlags */ + struct { + int nIn; /* Number of entries in aInLoop[] */ + struct InLoop { + int iCur; /* The VDBE cursor used by this IN operator */ + int addrInTop; /* Top of the IN loop */ + u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ + } *aInLoop; /* Information about each nested IN operator */ + } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ + Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ + } u; + struct WhereLoop *pWLoop; /* The selected WhereLoop object */ + Bitmask notReady; /* FROM entries not usable at this level */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + int addrVisit; /* Address at which row is visited */ +#endif +}; + +/* +** Each instance of this object represents an algorithm for evaluating one +** term of a join. Every term of the FROM clause will have at least +** one corresponding WhereLoop object (unless INDEXED BY constraints +** prevent a query solution - which is an error) and many terms of the +** FROM clause will have multiple WhereLoop objects, each describing a +** potential way of implementing that FROM-clause term, together with +** dependencies and cost estimates for using the chosen algorithm. +** +** Query planning consists of building up a collection of these WhereLoop +** objects, then computing a particular sequence of WhereLoop objects, with +** one WhereLoop object per FROM clause term, that satisfy all dependencies +** and that minimize the overall cost. +*/ +struct WhereLoop { + Bitmask prereq; /* Bitmask of other loops that must run first */ + Bitmask maskSelf; /* Bitmask identifying table iTab */ +#ifdef SQLITE_DEBUG + char cId; /* Symbolic ID of this loop for debugging use */ +#endif + u8 iTab; /* Position in FROM clause of table for this loop */ + u8 iSortIdx; /* Sorting index number. 0==None */ + LogEst rSetup; /* One-time setup cost (ex: create transient index) */ + LogEst rRun; /* Cost of running each loop */ + LogEst nOut; /* Estimated number of output rows */ + union { + struct { /* Information for internal btree tables */ + u16 nEq; /* Number of equality constraints */ + u16 nBtm; /* Size of BTM vector */ + u16 nTop; /* Size of TOP vector */ + u16 nIdxCol; /* Index column used for ORDER BY */ + Index *pIndex; /* Index used, or NULL */ + } btree; + struct { /* Information for virtual tables */ + int idxNum; /* Index number */ + u8 needFree; /* True if sqlite3_free(idxStr) is needed */ + i8 isOrdered; /* True if satisfies ORDER BY */ + u16 omitMask; /* Terms that may be omitted */ + char *idxStr; /* Index identifier string */ + } vtab; + } u; + u32 wsFlags; /* WHERE_* flags describing the plan */ + u16 nLTerm; /* Number of entries in aLTerm[] */ + u16 nSkip; /* Number of NULL aLTerm[] entries */ + /**** whereLoopXfer() copies fields above ***********************/ +# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) + u16 nLSlot; /* Number of slots allocated for aLTerm[] */ + WhereTerm **aLTerm; /* WhereTerms used */ + WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ + WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */ +}; + +/* This object holds the prerequisites and the cost of running a +** subquery on one operand of an OR operator in the WHERE clause. +** See WhereOrSet for additional information +*/ +struct WhereOrCost { + Bitmask prereq; /* Prerequisites */ + LogEst rRun; /* Cost of running this subquery */ + LogEst nOut; /* Number of outputs for this subquery */ +}; + +/* The WhereOrSet object holds a set of possible WhereOrCosts that +** correspond to the subquery(s) of OR-clause processing. Only the +** best N_OR_COST elements are retained. +*/ +#define N_OR_COST 3 +struct WhereOrSet { + u16 n; /* Number of valid a[] entries */ + WhereOrCost a[N_OR_COST]; /* Set of best costs */ +}; + +/* +** Each instance of this object holds a sequence of WhereLoop objects +** that implement some or all of a query plan. +** +** Think of each WhereLoop object as a node in a graph with arcs +** showing dependencies and costs for travelling between nodes. (That is +** not a completely accurate description because WhereLoop costs are a +** vector, not a scalar, and because dependencies are many-to-one, not +** one-to-one as are graph nodes. But it is a useful visualization aid.) +** Then a WherePath object is a path through the graph that visits some +** or all of the WhereLoop objects once. +** +** The "solver" works by creating the N best WherePath objects of length +** 1. Then using those as a basis to compute the N best WherePath objects +** of length 2. And so forth until the length of WherePaths equals the +** number of nodes in the FROM clause. The best (lowest cost) WherePath +** at the end is the chosen query plan. +*/ +struct WherePath { + Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ + Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ + LogEst nRow; /* Estimated number of rows generated by this path */ + LogEst rCost; /* Total cost of this path */ + LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */ + i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */ + WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ +}; + +/* +** The query generator uses an array of instances of this structure to +** help it analyze the subexpressions of the WHERE clause. Each WHERE +** clause subexpression is separated from the others by AND operators, +** usually, or sometimes subexpressions separated by OR. +** +** All WhereTerms are collected into a single WhereClause structure. +** The following identity holds: +** +** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm +** +** When a term is of the form: +** +** X +** +** where X is a column name and is one of certain operators, +** then WhereTerm.leftCursor and WhereTerm.u.leftColumn record the +** cursor number and column number for X. WhereTerm.eOperator records +** the using a bitmask encoding defined by WO_xxx below. The +** use of a bitmask encoding for the operator allows us to search +** quickly for terms that match any of several different operators. +** +** A WhereTerm might also be two or more subterms connected by OR: +** +** (t1.X ) OR (t1.Y ) OR .... +** +** In this second case, wtFlag has the TERM_ORINFO bit set and eOperator==WO_OR +** and the WhereTerm.u.pOrInfo field points to auxiliary information that +** is collected about the OR clause. +** +** If a term in the WHERE clause does not match either of the two previous +** categories, then eOperator==0. The WhereTerm.pExpr field is still set +** to the original subexpression content and wtFlags is set up appropriately +** but no other fields in the WhereTerm object are meaningful. +** +** When eOperator!=0, prereqRight and prereqAll record sets of cursor numbers, +** but they do so indirectly. A single WhereMaskSet structure translates +** cursor number into bits and the translated bit is stored in the prereq +** fields. The translation is used in order to maximize the number of +** bits that will fit in a Bitmask. The VDBE cursor numbers might be +** spread out over the non-negative integers. For example, the cursor +** numbers might be 3, 8, 9, 10, 20, 23, 41, and 45. The WhereMaskSet +** translates these sparse cursor numbers into consecutive integers +** beginning with 0 in order to make the best possible use of the available +** bits in the Bitmask. So, in the example above, the cursor numbers +** would be mapped into integers 0 through 7. +** +** The number of terms in a join is limited by the number of bits +** in prereqRight and prereqAll. The default is 64 bits, hence SQLite +** is only able to process joins with 64 or fewer tables. +*/ +struct WhereTerm { + Expr *pExpr; /* Pointer to the subexpression that is this term */ + WhereClause *pWC; /* The clause this term is part of */ + LogEst truthProb; /* Probability of truth for this expression */ + u16 wtFlags; /* TERM_xxx bit flags. See below */ + u16 eOperator; /* A WO_xx value describing */ + u8 nChild; /* Number of children that must disable us */ + u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ + int iParent; /* Disable pWC->a[iParent] when this term disabled */ + int leftCursor; /* Cursor number of X in "X " */ + int iField; /* Field in (?,?,?) IN (SELECT...) vector */ + union { + int leftColumn; /* Column number of X in "X " */ + WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ + WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ + } u; + Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ + Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ +}; + +/* +** Allowed values of WhereTerm.wtFlags +*/ +#define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(db, pExpr) */ +#define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */ +#define TERM_CODED 0x04 /* This term is already coded */ +#define TERM_COPIED 0x08 /* Has a child */ +#define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */ +#define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */ +#define TERM_OR_OK 0x40 /* Used during OR-clause processing */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +# define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ +#else +# define TERM_VNULL 0x00 /* Disabled if not using stat3 */ +#endif +#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ +#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ +#define TERM_LIKE 0x400 /* The original LIKE operator */ +#define TERM_IS 0x800 /* Term.pExpr is an IS operator */ + +/* +** An instance of the WhereScan object is used as an iterator for locating +** terms in the WHERE clause that are useful to the query planner. +*/ +struct WhereScan { + WhereClause *pOrigWC; /* Original, innermost WhereClause */ + WhereClause *pWC; /* WhereClause currently being scanned */ + const char *zCollName; /* Required collating sequence, if not NULL */ + Expr *pIdxExpr; /* Search for this index expression */ + char idxaff; /* Must match this affinity, if zCollName!=NULL */ + unsigned char nEquiv; /* Number of entries in aEquiv[] */ + unsigned char iEquiv; /* Next unused slot in aEquiv[] */ + u32 opMask; /* Acceptable operators */ + int k; /* Resume scanning at this->pWC->a[this->k] */ + int aiCur[11]; /* Cursors in the equivalence class */ + i16 aiColumn[11]; /* Corresponding column number in the eq-class */ +}; + +/* +** An instance of the following structure holds all information about a +** WHERE clause. Mostly this is a container for one or more WhereTerms. +** +** Explanation of pOuter: For a WHERE clause of the form +** +** a AND ((b AND c) OR (d AND e)) AND f +** +** There are separate WhereClause objects for the whole clause and for +** the subclauses "(b AND c)" and "(d AND e)". The pOuter field of the +** subclauses points to the WhereClause object for the whole clause. +*/ +struct WhereClause { + WhereInfo *pWInfo; /* WHERE clause processing context */ + WhereClause *pOuter; /* Outer conjunction */ + u8 op; /* Split operator. TK_AND or TK_OR */ + int nTerm; /* Number of terms */ + int nSlot; /* Number of entries in a[] */ + WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ +#if defined(SQLITE_SMALL_STACK) + WhereTerm aStatic[1]; /* Initial static space for a[] */ +#else + WhereTerm aStatic[8]; /* Initial static space for a[] */ +#endif +}; + +/* +** A WhereTerm with eOperator==WO_OR has its u.pOrInfo pointer set to +** a dynamically allocated instance of the following structure. +*/ +struct WhereOrInfo { + WhereClause wc; /* Decomposition into subterms */ + Bitmask indexable; /* Bitmask of all indexable tables in the clause */ +}; + +/* +** A WhereTerm with eOperator==WO_AND has its u.pAndInfo pointer set to +** a dynamically allocated instance of the following structure. +*/ +struct WhereAndInfo { + WhereClause wc; /* The subexpression broken out */ +}; + +/* +** An instance of the following structure keeps track of a mapping +** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. +** +** The VDBE cursor numbers are small integers contained in +** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE +** clause, the cursor numbers might not begin with 0 and they might +** contain gaps in the numbering sequence. But we want to make maximum +** use of the bits in our bitmasks. This structure provides a mapping +** from the sparse cursor numbers into consecutive integers beginning +** with 0. +** +** If WhereMaskSet.ix[A]==B it means that The A-th bit of a Bitmask +** corresponds VDBE cursor number B. The A-th bit of a bitmask is 1<3, 5->1, 8->2, 29->0, +** 57->5, 73->4. Or one of 719 other combinations might be used. It +** does not really matter. What is important is that sparse cursor +** numbers all get mapped into bit numbers that begin with 0 and contain +** no gaps. +*/ +struct WhereMaskSet { + int n; /* Number of assigned cursor values */ + int ix[BMS]; /* Cursor assigned to each bit */ +}; + +/* +** Initialize a WhereMaskSet object +*/ +#define initMaskSet(P) (P)->n=0 + +/* +** This object is a convenience wrapper holding all information needed +** to construct WhereLoop objects for a particular query. +*/ +struct WhereLoopBuilder { + WhereInfo *pWInfo; /* Information about this WHERE */ + WhereClause *pWC; /* WHERE clause terms */ + ExprList *pOrderBy; /* ORDER BY clause */ + WhereLoop *pNew; /* Template WhereLoop */ + WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + UnpackedRecord *pRec; /* Probe for stat4 (if required) */ + int nRecValid; /* Number of valid fields currently in pRec */ +#endif + unsigned int bldFlags; /* SQLITE_BLDF_* flags */ +}; + +/* Allowed values for WhereLoopBuider.bldFlags */ +#define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */ +#define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ + +/* +** The WHERE clause processing routine has two halves. The +** first part does the start of the WHERE loop and the second +** half does the tail of the WHERE loop. An instance of +** this structure is returned by the first half and passed +** into the second half to give some continuity. +** +** An instance of this object holds the complete state of the query +** planner. +*/ +struct WhereInfo { + Parse *pParse; /* Parsing and code generating context */ + SrcList *pTabList; /* List of tables in the join */ + ExprList *pOrderBy; /* The ORDER BY clause or NULL */ + ExprList *pResultSet; /* Result set of the query */ + Expr *pWhere; /* The complete WHERE clause */ + LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ + int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ + int iContinue; /* Jump here to continue with next record */ + int iBreak; /* Jump here to break out of the loop */ + int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ + u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ + u8 nLevel; /* Number of nested loop */ + i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ + u8 sorted; /* True if really sorted (not just grouped) */ + u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ + u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ + u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ + u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */ + int iTop; /* The very beginning of the WHERE loop */ + WhereLoop *pLoops; /* List of all WhereLoop objects */ + Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ + LogEst nRowOut; /* Estimated number of output rows */ + WhereClause sWC; /* Decomposition of the WHERE clause */ + WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ + WhereLevel a[1]; /* Information about each nest loop in WHERE */ +}; + +/* +** Private interfaces - callable only by other where.c routines. +** +** where.c: +*/ +SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); +#ifdef WHERETRACE_ENABLED +SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); +#endif +SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( + WhereClause *pWC, /* The WHERE clause to be searched */ + int iCur, /* Cursor number of LHS */ + int iColumn, /* Column number of LHS */ + Bitmask notReady, /* RHS must not overlap with this mask */ + u32 op, /* Mask of WO_xx values describing operator */ + Index *pIdx /* Must be compatible with this index, if not NULL */ +); + +/* wherecode.c: */ +#ifndef SQLITE_OMIT_EXPLAIN +SQLITE_PRIVATE int sqlite3WhereExplainOneScan( + Parse *pParse, /* Parse context */ + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + int iLevel, /* Value for "level" column of output */ + int iFrom, /* Value for "from" column of output */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +); +#else +# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0 +#endif /* SQLITE_OMIT_EXPLAIN */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +SQLITE_PRIVATE void sqlite3WhereAddScanStatus( + Vdbe *v, /* Vdbe to add scanstatus entry to */ + SrcList *pSrclist, /* FROM clause pLvl reads data from */ + WhereLevel *pLvl, /* Level to add scanstatus() entry for */ + int addrExplain /* Address of OP_Explain (or 0) */ +); +#else +# define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d) +#endif +SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( + WhereInfo *pWInfo, /* Complete information about the WHERE clause */ + int iLevel, /* Which level of pWInfo->a[] should be coded */ + Bitmask notReady /* Which tables are currently available */ +); + +/* whereexpr.c: */ +SQLITE_PRIVATE void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); +SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause*); +SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8); +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); +SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); +SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); +SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*); + + + + + +/* +** Bitmasks for the operators on WhereTerm objects. These are all +** operators that are of interest to the query planner. An +** OR-ed combination of these values can be used when searching for +** particular WhereTerms within a WhereClause. +** +** Value constraints: +** WO_EQ == SQLITE_INDEX_CONSTRAINT_EQ +** WO_LT == SQLITE_INDEX_CONSTRAINT_LT +** 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 +#define WO_LT (WO_EQ<<(TK_LT-TK_EQ)) +#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_IS 0x0080 +#define WO_ISNULL 0x0100 +#define WO_OR 0x0200 /* Two or more OR-connected terms */ +#define WO_AND 0x0400 /* Two or more AND-connected terms */ +#define WO_EQUIV 0x0800 /* Of the form A==B, both columns */ +#define WO_NOOP 0x1000 /* This term does not restrict search space */ + +#define WO_ALL 0x1fff /* Mask of all possible WO_* values */ +#define WO_SINGLE 0x01ff /* Mask of all non-compound WO_* values */ + +/* +** These are definitions of bits in the WhereLoop.wsFlags field. +** The particular combination of bits in each WhereLoop help to +** determine the algorithm that WhereLoop represents. +*/ +#define WHERE_COLUMN_EQ 0x00000001 /* x=EXPR */ +#define WHERE_COLUMN_RANGE 0x00000002 /* xEXPR */ +#define WHERE_COLUMN_IN 0x00000004 /* x IN (...) */ +#define WHERE_COLUMN_NULL 0x00000008 /* x IS NULL */ +#define WHERE_CONSTRAINT 0x0000000f /* Any of the WHERE_COLUMN_xxx values */ +#define WHERE_TOP_LIMIT 0x00000010 /* xEXPR or x>=EXPR constraint */ +#define WHERE_BOTH_LIMIT 0x00000030 /* Both x>EXPR and xaiColumn[i]; + if( i==XN_EXPR ) return ""; + if( i==XN_ROWID ) return "rowid"; + return pIdx->pTable->aCol[i].zName; +} + +/* +** This routine is a helper for explainIndexRange() below +** +** pStr holds the text of an expression that we are building up one term +** at a time. This routine adds a new term to the end of the expression. +** Terms are separated by AND so add the "AND" text for second and subsequent +** terms only. +*/ +static void explainAppendTerm( + StrAccum *pStr, /* The text expression being built */ + Index *pIdx, /* Index to read column names from */ + int nTerm, /* Number of terms */ + int iTerm, /* Zero-based index of first term. */ + int bAnd, /* Non-zero to append " AND " */ + const char *zOp /* Name of the operator */ +){ + int i; + + assert( nTerm>=1 ); + if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5); + + if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); + + sqlite3StrAccumAppend(pStr, zOp, 1); + + if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); +} + +/* +** Argument pLevel describes a strategy for scanning table pTab. This +** function appends text to pStr that describes the subset of table +** rows scanned by the strategy in the form of an SQL expression. +** +** For example, if the query: +** +** SELECT * FROM t1 WHERE a=1 AND b>2; +** +** is run and there is an index on (a, b), then this function returns a +** string similar to: +** +** "a=? AND b>?" +*/ +static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ + Index *pIndex = pLoop->u.btree.pIndex; + u16 nEq = pLoop->u.btree.nEq; + u16 nSkip = pLoop->nSkip; + int i, j; + + if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; + sqlite3StrAccumAppend(pStr, " (", 2); + for(i=0; i=nSkip ? "%s=?" : "ANY(%s)", z); + } + + j = i; + if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ + explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">"); + i = 1; + } + if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ + explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<"); + } + sqlite3StrAccumAppend(pStr, ")", 1); +} + +/* +** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN +** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was +** defined at compile-time. If it is not a no-op, a single OP_Explain opcode +** is added to the output to describe the table scan strategy in pLevel. +** +** If an OP_Explain opcode is added to the VM, its address is returned. +** Otherwise, if no OP_Explain is coded, zero is returned. +*/ +SQLITE_PRIVATE int sqlite3WhereExplainOneScan( + Parse *pParse, /* Parse context */ + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + int iLevel, /* Value for "level" column of output */ + int iFrom, /* Value for "from" column of output */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +){ + int ret = 0; +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) + if( pParse->explain==2 ) +#endif + { + struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; + Vdbe *v = pParse->pVdbe; /* VM being constructed */ + sqlite3 *db = pParse->db; /* Database handle */ + int iId = pParse->iSelectId; /* Select id (left-most output column) */ + int isSearch; /* True for a SEARCH. False for SCAN. */ + WhereLoop *pLoop; /* The controlling WhereLoop object */ + u32 flags; /* Flags that describe this loop */ + char *zMsg; /* Text to add to EQP output */ + StrAccum str; /* EQP output string */ + char zBuf[100]; /* Initial space for EQP output string */ + + pLoop = pLevel->pWLoop; + flags = pLoop->wsFlags; + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; + + isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 + || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) + || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); + + sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); + if( pItem->pSelect ){ + sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId); + }else{ + sqlite3XPrintf(&str, " TABLE %s", pItem->zName); + } + + if( pItem->zAlias ){ + sqlite3XPrintf(&str, " AS %s", pItem->zAlias); + } + if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ + const char *zFmt = 0; + Index *pIdx; + + assert( pLoop->u.btree.pIndex!=0 ); + pIdx = pLoop->u.btree.pIndex; + assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); + if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ + if( isSearch ){ + zFmt = "PRIMARY KEY"; + } + }else if( flags & WHERE_PARTIALIDX ){ + zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; + }else if( flags & WHERE_AUTO_INDEX ){ + zFmt = "AUTOMATIC COVERING INDEX"; + }else if( flags & WHERE_IDX_ONLY ){ + zFmt = "COVERING INDEX %s"; + }else{ + zFmt = "INDEX %s"; + } + if( zFmt ){ + sqlite3StrAccumAppend(&str, " USING ", 7); + sqlite3XPrintf(&str, zFmt, pIdx->zName); + explainIndexRange(&str, pLoop); + } + }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ + const char *zRangeOp; + if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ + zRangeOp = "="; + }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ + zRangeOp = ">? AND rowid<"; + }else if( flags&WHERE_BTM_LIMIT ){ + zRangeOp = ">"; + }else{ + assert( flags&WHERE_TOP_LIMIT); + zRangeOp = "<"; + } + sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ + sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s", + pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); + } +#endif +#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS + if( pLoop->nOut>=10 ){ + sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); + }else{ + sqlite3StrAccumAppend(&str, " (~1 row)", 9); + } +#endif + zMsg = sqlite3StrAccumFinish(&str); + ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); + } + return ret; +} +#endif /* SQLITE_OMIT_EXPLAIN */ + +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +/* +** Configure the VM passed as the first argument with an +** sqlite3_stmt_scanstatus() entry corresponding to the scan used to +** implement level pLvl. Argument pSrclist is a pointer to the FROM +** clause that the scan reads data from. +** +** If argument addrExplain is not 0, it must be the address of an +** OP_Explain instruction that describes the same loop. +*/ +SQLITE_PRIVATE void sqlite3WhereAddScanStatus( + Vdbe *v, /* Vdbe to add scanstatus entry to */ + SrcList *pSrclist, /* FROM clause pLvl reads data from */ + WhereLevel *pLvl, /* Level to add scanstatus() entry for */ + int addrExplain /* Address of OP_Explain (or 0) */ +){ + const char *zObj = 0; + WhereLoop *pLoop = pLvl->pWLoop; + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){ + zObj = pLoop->u.btree.pIndex->zName; + }else{ + zObj = pSrclist->a[pLvl->iFrom].zName; + } + sqlite3VdbeScanStatus( + v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj + ); +} +#endif + + +/* +** Disable a term in the WHERE clause. Except, do not disable the term +** if it controls a LEFT OUTER JOIN and it did not originate in the ON +** or USING clause of that join. +** +** Consider the term t2.z='ok' in the following queries: +** +** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok' +** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok' +** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok' +** +** The t2.z='ok' is disabled in the in (2) because it originates +** in the ON clause. The term is disabled in (3) because it is not part +** of a LEFT OUTER JOIN. In (1), the term is not disabled. +** +** Disabling a term causes that term to not be tested in the inner loop +** of the join. Disabling is an optimization. When terms are satisfied +** by indices, we disable them to prevent redundant tests in the inner +** loop. We would get the correct results if nothing were ever disabled, +** but joins might run a little slower. The trick is to disable as much +** as we can without disabling too much. If we disabled in (1), we'd get +** the wrong answer. See ticket #813. +** +** If all the children of a term are disabled, then that term is also +** automatically disabled. In this way, terms get disabled if derived +** virtual terms are tested first. For example: +** +** x GLOB 'abc*' AND x>='abc' AND x<'acd' +** \___________/ \______/ \_____/ +** parent child1 child2 +** +** Only the parent term was in the original WHERE clause. The child1 +** and child2 terms were added by the LIKE optimization. If both of +** the virtual child terms are valid, then testing of the parent can be +** skipped. +** +** Usually the parent term is marked as TERM_CODED. But if the parent +** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead. +** The TERM_LIKECOND marking indicates that the term should be coded inside +** a conditional such that is only evaluated on the second pass of a +** LIKE-optimization loop, when scanning BLOBs instead of strings. +*/ +static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ + int nLoop = 0; + while( ALWAYS(pTerm!=0) + && (pTerm->wtFlags & TERM_CODED)==0 + && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) + && (pLevel->notReady & pTerm->prereqAll)==0 + ){ + if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ + pTerm->wtFlags |= TERM_LIKECOND; + }else{ + pTerm->wtFlags |= TERM_CODED; + } + if( pTerm->iParent<0 ) break; + pTerm = &pTerm->pWC->a[pTerm->iParent]; + pTerm->nChild--; + if( pTerm->nChild!=0 ) break; + nLoop++; + } +} + +/* +** Code an OP_Affinity opcode to apply the column affinity string zAff +** to the n registers starting at base. +** +** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the +** beginning and end of zAff are ignored. If all entries in zAff are +** SQLITE_AFF_BLOB, then no code gets generated. +** +** This routine makes its own copy of zAff so that the caller is free +** to modify zAff after this routine returns. +*/ +static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ + Vdbe *v = pParse->pVdbe; + if( zAff==0 ){ + assert( pParse->db->mallocFailed ); + return; + } + assert( v!=0 ); + + /* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning + ** and end of the affinity string. + */ + while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){ + n--; + base++; + zAff++; + } + while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){ + n--; + } + + /* Code the OP_Affinity opcode if there is anything left to do. */ + if( n>0 ){ + sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); + sqlite3ExprCacheAffinityChange(pParse, base, n); + } +} + +/* +** Expression pRight, which is the RHS of a comparison operation, is +** either a vector of n elements or, if n==1, a scalar expression. +** Before the comparison operation, affinity zAff is to be applied +** to the pRight values. This function modifies characters within the +** affinity string to SQLITE_AFF_BLOB if either: +** +** * the comparison will be performed with no affinity, or +** * the affinity change in zAff is guaranteed not to change the value. +*/ +static void updateRangeAffinityStr( + Expr *pRight, /* RHS of comparison */ + int n, /* Number of vector elements in comparison */ + char *zAff /* Affinity string to modify */ +){ + int i; + for(i=0; ipExpr; + Vdbe *v = pParse->pVdbe; + int iReg; /* Register holding results */ + + assert( pLevel->pWLoop->aLTerm[iEq]==pTerm ); + assert( iTarget>0 ); + if( pX->op==TK_EQ || pX->op==TK_IS ){ + iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); + }else if( pX->op==TK_ISNULL ){ + iReg = iTarget; + sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); +#ifndef SQLITE_OMIT_SUBQUERY + }else{ + int eType = IN_INDEX_NOOP; + int iTab; + struct InLoop *pIn; + WhereLoop *pLoop = pLevel->pWLoop; + int i; + int nEq = 0; + int *aiMap = 0; + + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 + && pLoop->u.btree.pIndex!=0 + && pLoop->u.btree.pIndex->aSortOrder[iEq] + ){ + testcase( iEq==0 ); + testcase( bRev ); + bRev = !bRev; + } + assert( pX->op==TK_IN ); + iReg = iTarget; + + for(i=0; iaLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){ + disableTerm(pLevel, pTerm); + return iTarget; + } + } + for(i=iEq;inLTerm; i++){ + if( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++; + } + + if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){ + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0); + }else{ + Select *pSelect = pX->x.pSelect; + sqlite3 *db = pParse->db; + u16 savedDbOptFlags = db->dbOptFlags; + ExprList *pOrigRhs = pSelect->pEList; + ExprList *pOrigLhs = pX->pLeft->x.pList; + ExprList *pRhs = 0; /* New Select.pEList for RHS */ + ExprList *pLhs = 0; /* New pX->pLeft vector */ + + for(i=iEq;inLTerm; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + int iField = pLoop->aLTerm[i]->iField - 1; + Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0); + Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0); + + pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs); + pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs); + } + } + if( !db->mallocFailed ){ + Expr *pLeft = pX->pLeft; + + if( pSelect->pOrderBy ){ + /* If the SELECT statement has an ORDER BY clause, zero the + ** iOrderByCol variables. These are set to non-zero when an + ** ORDER BY term exactly matches one of the terms of the + ** result-set. Since the result-set of the SELECT statement may + ** have been modified or reordered, these variables are no longer + ** set correctly. Since setting them is just an optimization, + ** it's easiest just to zero them here. */ + ExprList *pOrderBy = pSelect->pOrderBy; + for(i=0; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; + } + } + + /* Take care here not to generate a TK_VECTOR containing only a + ** single value. Since the parser never creates such a vector, some + ** of the subroutines do not handle this case. */ + if( pLhs->nExpr==1 ){ + pX->pLeft = pLhs->a[0].pExpr; + }else{ + pLeft->x.pList = pLhs; + aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq); + testcase( aiMap==0 ); + } + pSelect->pEList = pRhs; + db->dbOptFlags |= SQLITE_QueryFlattener; + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap); + db->dbOptFlags = savedDbOptFlags; + testcase( aiMap!=0 && aiMap[0]!=0 ); + pSelect->pEList = pOrigRhs; + pLeft->x.pList = pOrigLhs; + pX->pLeft = pLeft; + } + sqlite3ExprListDelete(pParse->db, pLhs); + sqlite3ExprListDelete(pParse->db, pRhs); + } + + if( eType==IN_INDEX_INDEX_DESC ){ + testcase( bRev ); + bRev = !bRev; + } + iTab = pX->iTable; + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); + VdbeCoverageIf(v, bRev); + VdbeCoverageIf(v, !bRev); + assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + + pLoop->wsFlags |= WHERE_IN_ABLE; + if( pLevel->u.in.nIn==0 ){ + pLevel->addrNxt = sqlite3VdbeMakeLabel(v); + } + + i = pLevel->u.in.nIn; + pLevel->u.in.nIn += nEq; + pLevel->u.in.aInLoop = + sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, + sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); + pIn = pLevel->u.in.aInLoop; + if( pIn ){ + int iMap = 0; /* Index in aiMap[] */ + pIn += i; + for(i=iEq;inLTerm; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + int iOut = iReg + i - iEq; + if( eType==IN_INDEX_ROWID ){ + testcase( nEq>1 ); /* Happens with a UNIQUE index on ROWID */ + pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut); + }else{ + int iCol = aiMap ? aiMap[iMap++] : 0; + pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut); + } + sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v); + if( i==iEq ){ + pIn->iCur = iTab; + pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; + }else{ + pIn->eEndLoopOp = OP_Noop; + } + pIn++; + } + } + }else{ + pLevel->u.in.nIn = 0; + } + sqlite3DbFree(pParse->db, aiMap); +#endif + } + disableTerm(pLevel, pTerm); + return iReg; +} + +/* +** Generate code that will evaluate all == and IN constraints for an +** index scan. +** +** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c). +** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10 +** The index has as many as three equality constraints, but in this +** example, the third "c" value is an inequality. So only two +** constraints are coded. This routine will generate code to evaluate +** a==5 and b IN (1,2,3). The current values for a and b will be stored +** in consecutive registers and the index of the first register is returned. +** +** In the example above nEq==2. But this subroutine works for any value +** of nEq including 0. If nEq==0, this routine is nearly a no-op. +** The only thing it does is allocate the pLevel->iMem memory cell and +** compute the affinity string. +** +** The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints +** are == or IN and are covered by the nEq. nExtraReg is 1 if there is +** an inequality constraint (such as the "c>=5 AND c<10" in the example) that +** occurs after the nEq quality constraints. +** +** This routine allocates a range of nEq+nExtraReg memory cells and returns +** the index of the first memory cell in that range. The code that +** calls this routine will use that memory range to store keys for +** start and termination conditions of the loop. +** key value of the loop. If one or more IN operators appear, then +** this routine allocates an additional nEq memory cells for internal +** use. +** +** Before returning, *pzAff is set to point to a buffer containing a +** copy of the column affinity string of the index allocated using +** sqlite3DbMalloc(). Except, entries in the copy of the string associated +** with equality constraints that use BLOB or NONE affinity are set to +** SQLITE_AFF_BLOB. This is to deal with SQL such as the following: +** +** CREATE TABLE t1(a TEXT PRIMARY KEY, b); +** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b; +** +** In the example above, the index on t1(a) has TEXT affinity. But since +** the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity, +** no conversion should be attempted before using a t2.b value as part of +** a key to search the index. Hence the first byte in the returned affinity +** string in this example would be set to SQLITE_AFF_BLOB. +*/ +static int codeAllEqualityTerms( + Parse *pParse, /* Parsing context */ + WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ + int bRev, /* Reverse the order of IN operators */ + int nExtraReg, /* Number of extra registers to allocate */ + char **pzAff /* OUT: Set to point to affinity string */ +){ + u16 nEq; /* The number of == or IN constraints to code */ + u16 nSkip; /* Number of left-most columns to skip */ + Vdbe *v = pParse->pVdbe; /* The vm under construction */ + Index *pIdx; /* The index being used for this loop */ + WhereTerm *pTerm; /* A single constraint term */ + WhereLoop *pLoop; /* The WhereLoop object */ + int j; /* Loop counter */ + int regBase; /* Base register */ + int nReg; /* Number of registers to allocate */ + char *zAff; /* Affinity string to return */ + + /* This module is only called on query plans that use an index. */ + pLoop = pLevel->pWLoop; + assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); + nEq = pLoop->u.btree.nEq; + nSkip = pLoop->nSkip; + pIdx = pLoop->u.btree.pIndex; + assert( pIdx!=0 ); + + /* Figure out how many memory cells we will need then allocate them. + */ + regBase = pParse->nMem + 1; + nReg = pLoop->u.btree.nEq + nExtraReg; + pParse->nMem += nReg; + + zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); + assert( zAff!=0 || pParse->db->mallocFailed ); + + if( nSkip ){ + int iIdxCur = pLevel->iIdxCur; + sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); + j = sqlite3VdbeAddOp0(v, OP_Goto); + pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), + iIdxCur, 0, regBase, nSkip); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + sqlite3VdbeJumpHere(v, j); + for(j=0; jaiColumn[j]==XN_EXPR ); + VdbeComment((v, "%s", explainIndexColumnName(pIdx, j))); + } + } + + /* Evaluate the equality constraints + */ + assert( zAff==0 || (int)strlen(zAff)>=nEq ); + for(j=nSkip; jaLTerm[j]; + assert( pTerm!=0 ); + /* The following testcase is true for indices with redundant columns. + ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ + testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); + if( r1!=regBase+j ){ + if( nReg==1 ){ + sqlite3ReleaseTempReg(pParse, regBase); + regBase = r1; + }else{ + sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); + } + } + if( pTerm->eOperator & WO_IN ){ + if( pTerm->pExpr->flags & EP_xIsSelect ){ + /* No affinity ever needs to be (or should be) applied to a value + ** from the RHS of an "? IN (SELECT ...)" expression. The + ** sqlite3FindInIndex() routine has already ensured that the + ** affinity of the comparison has been applied to the value. */ + if( zAff ) zAff[j] = SQLITE_AFF_BLOB; + } + }else if( (pTerm->eOperator & WO_ISNULL)==0 ){ + Expr *pRight = pTerm->pExpr->pRight; + if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); + VdbeCoverage(v); + } + if( zAff ){ + if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ + zAff[j] = SQLITE_AFF_BLOB; + } + if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ + zAff[j] = SQLITE_AFF_BLOB; + } + } + } + } + *pzAff = zAff; + return regBase; +} + +#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS +/* +** If the most recently coded instruction is a constant range constraint +** (a string literal) that originated from the LIKE optimization, then +** set P3 and P5 on the OP_String opcode so that the string will be cast +** to a BLOB at appropriate times. +** +** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range +** expression: "x>='ABC' AND x<'abd'". But this requires that the range +** scan loop run twice, once for strings and a second time for BLOBs. +** The OP_String opcodes on the second pass convert the upper and lower +** bound string constants to blobs. This routine makes the necessary changes +** to the OP_String opcodes for that to happen. +** +** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then +** only the one pass through the string space is required, so this routine +** becomes a no-op. +*/ +static void whereLikeOptimizationStringFixup( + Vdbe *v, /* prepared statement under construction */ + WhereLevel *pLevel, /* The loop that contains the LIKE operator */ + WhereTerm *pTerm /* The upper or lower bound just coded */ +){ + if( pTerm->wtFlags & TERM_LIKEOPT ){ + VdbeOp *pOp; + assert( pLevel->iLikeRepCntr>0 ); + pOp = sqlite3VdbeGetOp(v, -1); + assert( pOp!=0 ); + assert( pOp->opcode==OP_String8 + || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); + pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ + pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ + } +} +#else +# define whereLikeOptimizationStringFixup(A,B,C) +#endif + +#ifdef SQLITE_ENABLE_CURSOR_HINTS +/* +** Information is passed from codeCursorHint() down to individual nodes of +** the expression tree (by sqlite3WalkExpr()) using an instance of this +** structure. +*/ +struct CCurHint { + int iTabCur; /* Cursor for the main table */ + int iIdxCur; /* Cursor for the index, if pIdx!=0. Unused otherwise */ + Index *pIdx; /* The index used to access the table */ +}; + +/* +** This function is called for every node of an expression that is a candidate +** for a cursor hint on an index cursor. For TK_COLUMN nodes that reference +** the table CCurHint.iTabCur, verify that the same column can be +** accessed through the index. If it cannot, then set pWalker->eCode to 1. +*/ +static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ + struct CCurHint *pHint = pWalker->u.pCCurHint; + assert( pHint->pIdx!=0 ); + if( pExpr->op==TK_COLUMN + && pExpr->iTable==pHint->iTabCur + && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0 + ){ + pWalker->eCode = 1; + } + return WRC_Continue; +} + +/* +** Test whether or not expression pExpr, which was part of a WHERE clause, +** should be included in the cursor-hint for a table that is on the rhs +** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the +** expression is not suitable. +** +** An expression is unsuitable if it might evaluate to non NULL even if +** a TK_COLUMN node that does affect the value of the expression is set +** to NULL. For example: +** +** col IS NULL +** col IS NOT NULL +** coalesce(col, 1) +** CASE WHEN col THEN 0 ELSE 1 END +*/ +static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_IS + || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT + || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE + ){ + pWalker->eCode = 1; + }else if( pExpr->op==TK_FUNCTION ){ + int d1; + char d2[3]; + if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ + pWalker->eCode = 1; + } + } + + return WRC_Continue; +} + + +/* +** This function is called on every node of an expression tree used as an +** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN +** that accesses any table other than the one identified by +** CCurHint.iTabCur, then do the following: +** +** 1) allocate a register and code an OP_Column instruction to read +** the specified column into the new register, and +** +** 2) transform the expression node to a TK_REGISTER node that reads +** from the newly populated register. +** +** Also, if the node is a TK_COLUMN that does access the table idenified +** by pCCurHint.iTabCur, and an index is being used (which we will +** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into +** an access of the index rather than the original table. +*/ +static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ + int rc = WRC_Continue; + struct CCurHint *pHint = pWalker->u.pCCurHint; + if( pExpr->op==TK_COLUMN ){ + if( pExpr->iTable!=pHint->iTabCur ){ + Vdbe *v = pWalker->pParse->pVdbe; + int reg = ++pWalker->pParse->nMem; /* Register for column value */ + sqlite3ExprCodeGetColumnOfTable( + v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg + ); + pExpr->op = TK_REGISTER; + pExpr->iTable = reg; + }else if( pHint->pIdx!=0 ){ + pExpr->iTable = pHint->iIdxCur; + pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); + assert( pExpr->iColumn>=0 ); + } + }else if( pExpr->op==TK_AGG_FUNCTION ){ + /* An aggregate function in the WHERE clause of a query means this must + ** be a correlated sub-query, and expression pExpr is an aggregate from + ** the parent context. Do not walk the function arguments in this case. + ** + ** todo: It should be possible to replace this node with a TK_REGISTER + ** expression, as the result of the expression must be stored in a + ** register at this point. The same holds for TK_AGG_COLUMN nodes. */ + rc = WRC_Prune; + } + return rc; +} + +/* +** Insert an OP_CursorHint instruction if it is appropriate to do so. +*/ +static void codeCursorHint( + struct SrcList_item *pTabItem, /* FROM clause item */ + WhereInfo *pWInfo, /* The where clause */ + WhereLevel *pLevel, /* Which loop to provide hints for */ + WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ +){ + Parse *pParse = pWInfo->pParse; + sqlite3 *db = pParse->db; + Vdbe *v = pParse->pVdbe; + Expr *pExpr = 0; + WhereLoop *pLoop = pLevel->pWLoop; + int iCur; + WhereClause *pWC; + WhereTerm *pTerm; + int i, j; + struct CCurHint sHint; + Walker sWalker; + + if( OptimizationDisabled(db, SQLITE_CursorHints) ) return; + iCur = pLevel->iTabCur; + assert( iCur==pWInfo->pTabList->a[pLevel->iFrom].iCursor ); + sHint.iTabCur = iCur; + sHint.iIdxCur = pLevel->iIdxCur; + sHint.pIdx = pLoop->u.btree.pIndex; + memset(&sWalker, 0, sizeof(sWalker)); + sWalker.pParse = pParse; + sWalker.u.pCCurHint = &sHint; + pWC = &pWInfo->sWC; + for(i=0; inTerm; i++){ + pTerm = &pWC->a[i]; + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( pTerm->prereqAll & pLevel->notReady ) continue; + + /* Any terms specified as part of the ON(...) clause for any LEFT + ** JOIN for which the current table is not the rhs are omitted + ** from the cursor-hint. + ** + ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms + ** that were specified as part of the WHERE clause must be excluded. + ** This is to address the following: + ** + ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; + ** + ** Say there is a single row in t2 that matches (t1.a=t2.b), but its + ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is + ** pushed down to the cursor, this row is filtered out, causing + ** SQLite to synthesize a row of NULL values. Which does match the + ** WHERE clause, and so the query returns a row. Which is incorrect. + ** + ** For the same reason, WHERE terms such as: + ** + ** WHERE 1 = (t2.c IS NULL) + ** + ** are also excluded. See codeCursorHintIsOrFunction() for details. + */ + if( pTabItem->fg.jointype & JT_LEFT ){ + Expr *pExpr = pTerm->pExpr; + if( !ExprHasProperty(pExpr, EP_FromJoin) + || pExpr->iRightJoinTable!=pTabItem->iCursor + ){ + sWalker.eCode = 0; + sWalker.xExprCallback = codeCursorHintIsOrFunction; + sqlite3WalkExpr(&sWalker, pTerm->pExpr); + if( sWalker.eCode ) continue; + } + }else{ + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; + } + + /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize + ** the cursor. These terms are not needed as hints for a pure range + ** scan (that has no == terms) so omit them. */ + if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){ + for(j=0; jnLTerm && pLoop->aLTerm[j]!=pTerm; j++){} + if( jnLTerm ) continue; + } + + /* No subqueries or non-deterministic functions allowed */ + if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue; + + /* For an index scan, make sure referenced columns are actually in + ** the index. */ + if( sHint.pIdx!=0 ){ + sWalker.eCode = 0; + sWalker.xExprCallback = codeCursorHintCheckExpr; + sqlite3WalkExpr(&sWalker, pTerm->pExpr); + if( sWalker.eCode ) continue; + } + + /* If we survive all prior tests, that means this term is worth hinting */ + pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); + } + if( pExpr!=0 ){ + sWalker.xExprCallback = codeCursorHintFixExpr; + sqlite3WalkExpr(&sWalker, pExpr); + sqlite3VdbeAddOp4(v, OP_CursorHint, + (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, + (const char*)pExpr, P4_EXPR); + } +} +#else +# define codeCursorHint(A,B,C,D) /* No-op */ +#endif /* SQLITE_ENABLE_CURSOR_HINTS */ + +/* +** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains +** a rowid value just read from cursor iIdxCur, open on index pIdx. This +** function generates code to do a deferred seek of cursor iCur to the +** rowid stored in register iRowid. +** +** Normally, this is just: +** +** OP_Seek $iCur $iRowid +** +** However, if the scan currently being coded is a branch of an OR-loop and +** the statement currently being coded is a SELECT, then P3 of the OP_Seek +** is set to iIdxCur and P4 is set to point to an array of integers +** containing one entry for each column of the table cursor iCur is open +** on. For each table column, if the column is the i'th column of the +** index, then the corresponding array entry is set to (i+1). If the column +** does not appear in the index at all, the array entry is set to 0. +*/ +static void codeDeferredSeek( + WhereInfo *pWInfo, /* Where clause context */ + Index *pIdx, /* Index scan is using */ + int iCur, /* Cursor for IPK b-tree */ + int iIdxCur /* Index cursor */ +){ + Parse *pParse = pWInfo->pParse; /* Parse context */ + Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ + + assert( iIdxCur>0 ); + assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); + + sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur); + if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) + && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) + ){ + int i; + Table *pTab = pIdx->pTable; + int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1)); + if( ai ){ + ai[0] = pTab->nCol; + for(i=0; inColumn-1; i++){ + assert( pIdx->aiColumn[i]nCol ); + if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1; + } + sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); + } + } +} + +/* +** If the expression passed as the second argument is a vector, generate +** code to write the first nReg elements of the vector into an array +** of registers starting with iReg. +** +** If the expression is not a vector, then nReg must be passed 1. In +** this case, generate code to evaluate the expression and leave the +** result in register iReg. +*/ +static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ + assert( nReg>0 ); + if( sqlite3ExprIsVector(p) ){ +#ifndef SQLITE_OMIT_SUBQUERY + if( (p->flags & EP_xIsSelect) ){ + Vdbe *v = pParse->pVdbe; + int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0); + sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); + }else +#endif + { + int i; + ExprList *pList = p->x.pList; + assert( nReg<=pList->nExpr ); + for(i=0; ia[i].pExpr, iReg+i); + } + } + }else{ + assert( nReg==1 ); + sqlite3ExprCode(pParse, p, iReg); + } +} + +/* An instance of the IdxExprTrans object carries information about a +** mapping from an expression on table columns into a column in an index +** down through the Walker. +*/ +typedef struct IdxExprTrans { + Expr *pIdxExpr; /* The index expression */ + int iTabCur; /* The cursor of the corresponding table */ + int iIdxCur; /* The cursor for the index */ + int iIdxCol; /* The column for the index */ +} IdxExprTrans; + +/* The walker node callback used to transform matching expressions into +** a reference to an index column for an index on an expression. +** +** If pExpr matches, then transform it into a reference to the index column +** that contains the value of pExpr. +*/ +static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ + IdxExprTrans *pX = p->u.pIdxTrans; + if( sqlite3ExprCompare(pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ + pExpr->op = TK_COLUMN; + pExpr->iTable = pX->iIdxCur; + pExpr->iColumn = pX->iIdxCol; + pExpr->pTab = 0; + return WRC_Prune; + }else{ + return WRC_Continue; + } +} + +/* +** 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 */ + int iTabCur, /* Cursor of the table that is being indexed */ + int iIdxCur, /* Cursor of the index itself */ + WhereInfo *pWInfo /* Transform expressions in this WHERE clause */ +){ + int iIdxCol; /* Column number of the index */ + ExprList *aColExpr; /* Expressions that are indexed */ + Walker w; + IdxExprTrans x; + aColExpr = pIdx->aColExpr; + if( aColExpr==0 ) return; /* Not an index on expressions */ + memset(&w, 0, sizeof(w)); + w.xExprCallback = whereIndexExprTransNode; + w.u.pIdxTrans = &x; + x.iTabCur = iTabCur; + x.iIdxCur = iIdxCur; + for(iIdxCol=0; iIdxColnExpr; iIdxCol++){ + if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue; + assert( aColExpr->a[iIdxCol].pExpr!=0 ); + x.iIdxCol = iIdxCol; + x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; + sqlite3WalkExpr(&w, pWInfo->pWhere); + sqlite3WalkExprList(&w, pWInfo->pOrderBy); + sqlite3WalkExprList(&w, pWInfo->pResultSet); + } +} + +/* +** Generate code for the start of the iLevel-th loop in the WHERE clause +** implementation described by pWInfo. +*/ +SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( + WhereInfo *pWInfo, /* Complete information about the WHERE clause */ + int iLevel, /* Which level of pWInfo->a[] should be coded */ + Bitmask notReady /* Which tables are currently available */ +){ + int j, k; /* Loop counters */ + int iCur; /* The VDBE cursor for the table */ + int addrNxt; /* Where to jump to continue with the next IN case */ + int omitTable; /* True if we use the index only */ + int bRev; /* True if we need to scan in reverse order */ + WhereLevel *pLevel; /* The where level to be coded */ + WhereLoop *pLoop; /* The WhereLoop object being coded */ + WhereClause *pWC; /* Decomposition of the entire WHERE clause */ + WhereTerm *pTerm; /* A WHERE clause term */ + Parse *pParse; /* Parsing context */ + sqlite3 *db; /* Database connection */ + Vdbe *v; /* The prepared stmt under constructions */ + struct SrcList_item *pTabItem; /* FROM clause term being coded */ + int addrBrk; /* Jump here to break out of the loop */ + int addrHalt; /* addrBrk for the outermost loop */ + int addrCont; /* Jump here to continue with next cycle */ + int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ + int iReleaseReg = 0; /* Temp register to free before returning */ + Index *pIdx = 0; /* Index used by loop (if any) */ + int loopAgain; /* True if constraint generator loop should repeat */ + + pParse = pWInfo->pParse; + v = pParse->pVdbe; + pWC = &pWInfo->sWC; + db = pParse->db; + pLevel = &pWInfo->a[iLevel]; + pLoop = pLevel->pWLoop; + pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; + iCur = pTabItem->iCursor; + pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); + bRev = (pWInfo->revMask>>iLevel)&1; + omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; + VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); + + /* Create labels for the "break" and "continue" instructions + ** for the current loop. Jump to addrBrk to break out of a loop. + ** Jump to cont to go immediately to the next iteration of the + ** loop. + ** + ** When there is an IN operator, we also have a "addrNxt" label that + ** means to continue with the next IN value combination. When + ** there are no IN operators in the constraints, the "addrNxt" label + ** is the same as "addrBrk". + */ + addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v); + addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v); + + /* If this is the right table of a LEFT OUTER JOIN, allocate and + ** initialize a memory cell that records if this table matches any + ** row of the left table of the join. + */ + if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ + pLevel->iLeftJoin = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); + VdbeComment((v, "init LEFT JOIN no-match flag")); + } + + /* Compute a safe address to jump to if we discover that the table for + ** this loop is empty and can never contribute content. */ + for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){} + addrHalt = pWInfo->a[j].addrBrk; + + /* Special case of a FROM clause subquery implemented as a co-routine */ + if( pTabItem->fg.viaCoroutine ){ + int regYield = pTabItem->regReturn; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); + pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); + VdbeCoverage(v); + VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + pLevel->op = OP_Goto; + }else + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ + /* Case 1: The table is a virtual-table. Use the VFilter and VNext + ** to access the data. + */ + int iReg; /* P3 Value for OP_VFilter */ + int addrNotFound; + int nConstraint = pLoop->nLTerm; + int iIn; /* Counter for IN constraints */ + + sqlite3ExprCachePush(pParse); + iReg = sqlite3GetTempRange(pParse, nConstraint+2); + addrNotFound = pLevel->addrBrk; + for(j=0; jaLTerm[j]; + if( NEVER(pTerm==0) ) continue; + if( pTerm->eOperator & WO_IN ){ + codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); + addrNotFound = pLevel->addrNxt; + }else{ + Expr *pRight = pTerm->pExpr->pRight; + codeExprOrVector(pParse, pRight, iTarget, 1); + } + } + sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); + sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); + sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, + pLoop->u.vtab.idxStr, + pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); + VdbeCoverage(v); + pLoop->u.vtab.needFree = 0; + pLevel->p1 = iCur; + pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; + pLevel->p2 = sqlite3VdbeCurrentAddr(v); + iIn = pLevel->u.in.nIn; + for(j=nConstraint-1; j>=0; j--){ + pTerm = pLoop->aLTerm[j]; + if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ + disableTerm(pLevel, pTerm); + }else if( (pTerm->eOperator & WO_IN)!=0 ){ + Expr *pCompare; /* The comparison operator */ + Expr *pRight; /* RHS of the comparison */ + VdbeOp *pOp; /* Opcode to access the value of the IN constraint */ + + /* Reload the constraint value into reg[iReg+j+2]. The same value + ** was loaded into the same register prior to the OP_VFilter, but + ** the xFilter implementation might have changed the datatype or + ** encoding of the value in the register, so it *must* be reloaded. */ + assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed ); + if( !db->mallocFailed ){ + assert( iIn>0 ); + pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop); + assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid ); + assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 ); + assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 ); + testcase( pOp->opcode==OP_Rowid ); + sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3); + } + + /* Generate code that will continue to the next row if + ** the IN constraint is not satisfied */ + pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0); + assert( pCompare!=0 || db->mallocFailed ); + if( pCompare ){ + pCompare->pLeft = pTerm->pExpr->pLeft; + pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0); + if( pRight ){ + pRight->iTable = iReg+j+2; + sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0); + } + pCompare->pLeft = 0; + sqlite3ExprDelete(db, pCompare); + } + } + } + /* These registers need to be preserved in case there is an IN operator + ** loop. So we could deallocate the registers here (and potentially + ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems + ** simpler and safer to simply not reuse the registers. + ** + ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + */ + sqlite3ExprCachePop(pParse); + }else +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + if( (pLoop->wsFlags & WHERE_IPK)!=0 + && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0 + ){ + /* Case 2: We can directly reference a single row using an + ** equality comparison against the ROWID field. Or + ** we reference multiple rows using a "rowid IN (...)" + ** construct. + */ + assert( pLoop->u.btree.nEq==1 ); + pTerm = pLoop->aLTerm[0]; + assert( pTerm!=0 ); + assert( pTerm->pExpr!=0 ); + assert( omitTable==0 ); + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + iReleaseReg = ++pParse->nMem; + iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); + if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); + addrNxt = pLevel->addrNxt; + sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); + VdbeCoverage(v); + sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); + sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); + VdbeComment((v, "pk")); + pLevel->op = OP_Noop; + }else if( (pLoop->wsFlags & WHERE_IPK)!=0 + && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 + ){ + /* Case 3: We have an inequality comparison against the ROWID field. + */ + int testOp = OP_Noop; + int start; + int memEndValue = 0; + WhereTerm *pStart, *pEnd; + + assert( omitTable==0 ); + j = 0; + pStart = pEnd = 0; + if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; + if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; + assert( pStart!=0 || pEnd!=0 ); + if( bRev ){ + pTerm = pStart; + pStart = pEnd; + pEnd = pTerm; + } + codeCursorHint(pTabItem, pWInfo, pLevel, pEnd); + if( pStart ){ + Expr *pX; /* The expression that defines the start bound */ + int r1, rTemp; /* Registers for holding the start boundary */ + int op; /* Cursor seek operation */ + + /* The following constant maps TK_xx codes into corresponding + ** seek opcodes. It depends on a particular ordering of TK_xx + */ + const u8 aMoveOp[] = { + /* TK_GT */ OP_SeekGT, + /* TK_LE */ OP_SeekLE, + /* TK_LT */ OP_SeekLT, + /* TK_GE */ OP_SeekGE + }; + assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */ + assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */ + assert( TK_GE==TK_GT+3 ); /* ... is correcct. */ + + assert( (pStart->wtFlags & TERM_VNULL)==0 ); + testcase( pStart->wtFlags & TERM_VIRTUAL ); + pX = pStart->pExpr; + assert( pX!=0 ); + testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ + if( sqlite3ExprIsVector(pX->pRight) ){ + r1 = rTemp = sqlite3GetTempReg(pParse); + codeExprOrVector(pParse, pX->pRight, r1, 1); + op = aMoveOp[(pX->op - TK_GT) | 0x0001]; + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); + disableTerm(pLevel, pStart); + op = aMoveOp[(pX->op - TK_GT)]; + } + sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1); + VdbeComment((v, "pk")); + VdbeCoverageIf(v, pX->op==TK_GT); + VdbeCoverageIf(v, pX->op==TK_LE); + VdbeCoverageIf(v, pX->op==TK_LT); + VdbeCoverageIf(v, pX->op==TK_GE); + sqlite3ExprCacheAffinityChange(pParse, r1, 1); + sqlite3ReleaseTempReg(pParse, rTemp); + }else{ + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + } + if( pEnd ){ + Expr *pX; + pX = pEnd->pExpr; + assert( pX!=0 ); + assert( (pEnd->wtFlags & TERM_VNULL)==0 ); + testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ + testcase( pEnd->wtFlags & TERM_VIRTUAL ); + memEndValue = ++pParse->nMem; + codeExprOrVector(pParse, pX->pRight, memEndValue, 1); + if( 0==sqlite3ExprIsVector(pX->pRight) + && (pX->op==TK_LT || pX->op==TK_GT) + ){ + testOp = bRev ? OP_Le : OP_Ge; + }else{ + testOp = bRev ? OP_Lt : OP_Gt; + } + if( 0==sqlite3ExprIsVector(pX->pRight) ){ + disableTerm(pLevel, pEnd); + } + } + start = sqlite3VdbeCurrentAddr(v); + pLevel->op = bRev ? OP_Prev : OP_Next; + pLevel->p1 = iCur; + pLevel->p2 = start; + assert( pLevel->p5==0 ); + if( testOp!=OP_Noop ){ + iRowidReg = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); + sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); + sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); + VdbeCoverageIf(v, testOp==OP_Le); + VdbeCoverageIf(v, testOp==OP_Lt); + VdbeCoverageIf(v, testOp==OP_Ge); + VdbeCoverageIf(v, testOp==OP_Gt); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); + } + }else if( pLoop->wsFlags & WHERE_INDEXED ){ + /* Case 4: A scan using an index. + ** + ** The WHERE clause may contain zero or more equality + ** terms ("==" or "IN" operators) that refer to the N + ** left-most columns of the index. It may also contain + ** inequality constraints (>, <, >= or <=) on the indexed + ** column that immediately follows the N equalities. Only + ** the right-most column can be an inequality - the rest must + ** use the "==" and "IN" operators. For example, if the + ** index is on (x,y,z), then the following clauses are all + ** optimized: + ** + ** x=5 + ** x=5 AND y=10 + ** x=5 AND y<10 + ** x=5 AND y>5 AND y<10 + ** x=5 AND y=5 AND z<=10 + ** + ** The z<10 term of the following cannot be used, only + ** the x=5 term: + ** + ** x=5 AND z<10 + ** + ** N may be zero if there are inequality constraints. + ** If there are no inequality constraints, then N is at + ** least one. + ** + ** This case is also used when there are no WHERE clause + ** constraints but an index is selected anyway, in order + ** to force the output order to conform to an ORDER BY. + */ + static const u8 aStartOp[] = { + 0, + 0, + OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */ + OP_Last, /* 3: (!start_constraints && startEq && bRev) */ + OP_SeekGT, /* 4: (start_constraints && !startEq && !bRev) */ + OP_SeekLT, /* 5: (start_constraints && !startEq && bRev) */ + OP_SeekGE, /* 6: (start_constraints && startEq && !bRev) */ + OP_SeekLE /* 7: (start_constraints && startEq && bRev) */ + }; + static const u8 aEndOp[] = { + OP_IdxGE, /* 0: (end_constraints && !bRev && !endEq) */ + OP_IdxGT, /* 1: (end_constraints && !bRev && endEq) */ + OP_IdxLE, /* 2: (end_constraints && bRev && !endEq) */ + OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */ + }; + u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */ + u16 nBtm = pLoop->u.btree.nBtm; /* Length of BTM vector */ + u16 nTop = pLoop->u.btree.nTop; /* Length of TOP vector */ + int regBase; /* Base register holding constraint values */ + WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */ + WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */ + int startEq; /* True if range start uses ==, >= or <= */ + int endEq; /* True if range end uses ==, >= or <= */ + int start_constraints; /* Start of range is constrained */ + int nConstraint; /* Number of constraint terms */ + int iIdxCur; /* The VDBE cursor for the index */ + int nExtraReg = 0; /* Number of extra registers needed */ + int op; /* Instruction opcode */ + char *zStartAff; /* Affinity for start of range constraint */ + char *zEndAff = 0; /* Affinity for end of range constraint */ + u8 bSeekPastNull = 0; /* True to seek past initial nulls */ + u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ + + pIdx = pLoop->u.btree.pIndex; + iIdxCur = pLevel->iIdxCur; + assert( nEq>=pLoop->nSkip ); + + /* If this loop satisfies a sort order (pOrderBy) request that + ** was passed to this function to implement a "SELECT min(x) ..." + ** query, then the caller will only allow the loop to run for + ** a single iteration. This means that the first row returned + ** should not have a NULL value stored in 'x'. If column 'x' is + ** the first one after the nEq equality constraints in the index, + ** this requires some special handling. + */ + assert( pWInfo->pOrderBy==0 + || pWInfo->pOrderBy->nExpr==1 + || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 ); + if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 + && pWInfo->nOBSat>0 + && (pIdx->nKeyCol>nEq) + ){ + assert( pLoop->nSkip==0 ); + bSeekPastNull = 1; + nExtraReg = 1; + } + + /* Find any inequality constraint terms for the start and end + ** of the range. + */ + j = nEq; + if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ + pRangeStart = pLoop->aLTerm[j++]; + nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm); + /* Like optimization range constraints always occur in pairs */ + assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || + (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 ); + } + if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ + pRangeEnd = pLoop->aLTerm[j++]; + nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop); +#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS + if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ + assert( pRangeStart!=0 ); /* LIKE opt constraints */ + assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ + pLevel->iLikeRepCntr = (u32)++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr); + VdbeComment((v, "LIKE loop counter")); + pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); + /* iLikeRepCntr actually stores 2x the counter register number. The + ** bottom bit indicates whether the search order is ASC or DESC. */ + testcase( bRev ); + testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); + assert( (bRev & ~1)==0 ); + pLevel->iLikeRepCntr <<=1; + pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC); + } +#endif + if( pRangeStart==0 ){ + j = pIdx->aiColumn[nEq]; + if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){ + bSeekPastNull = 1; + } + } + } + assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); + + /* If we are doing a reverse order scan on an ascending index, or + ** a forward order scan on a descending index, interchange the + ** start and end terms (pRangeStart and pRangeEnd). + */ + if( (nEqnKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) + || (bRev && pIdx->nKeyCol==nEq) + ){ + SWAP(WhereTerm *, pRangeEnd, pRangeStart); + SWAP(u8, bSeekPastNull, bStopAtNull); + SWAP(u8, nBtm, nTop); + } + + /* Generate code to evaluate all constraint terms using == or IN + ** and store the values of those terms in an array of registers + ** starting at regBase. + */ + codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd); + regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); + assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); + if( zStartAff && nTop ){ + zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); + } + addrNxt = pLevel->addrNxt; + + testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); + testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); + startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); + endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); + start_constraints = pRangeStart || nEq>0; + + /* Seek the index cursor to the start of the range. */ + nConstraint = nEq; + if( pRangeStart ){ + Expr *pRight = pRangeStart->pExpr->pRight; + codeExprOrVector(pParse, pRight, regBase+nEq, nBtm); + whereLikeOptimizationStringFixup(v, pLevel, pRangeStart); + if( (pRangeStart->wtFlags & TERM_VNULL)==0 + && sqlite3ExprCanBeNull(pRight) + ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); + VdbeCoverage(v); + } + if( zStartAff ){ + updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]); + } + nConstraint += nBtm; + testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); + if( sqlite3ExprIsVector(pRight)==0 ){ + disableTerm(pLevel, pRangeStart); + }else{ + startEq = 1; + } + bSeekPastNull = 0; + }else if( bSeekPastNull ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); + nConstraint++; + startEq = 0; + start_constraints = 1; + } + codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); + if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){ + /* The skip-scan logic inside the call to codeAllEqualityConstraints() + ** above has already left the cursor sitting on the correct row, + ** so no further seeking is needed */ + }else{ + op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; + assert( op!=0 ); + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); + VdbeCoverage(v); + VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); + VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); + VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); + VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); + VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); + VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); + } + + /* Load the value for the inequality constraint at the end of the + ** range (if any). + */ + nConstraint = nEq; + if( pRangeEnd ){ + Expr *pRight = pRangeEnd->pExpr->pRight; + sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); + codeExprOrVector(pParse, pRight, regBase+nEq, nTop); + whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); + if( (pRangeEnd->wtFlags & TERM_VNULL)==0 + && sqlite3ExprCanBeNull(pRight) + ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); + VdbeCoverage(v); + } + if( zEndAff ){ + updateRangeAffinityStr(pRight, nTop, zEndAff); + codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff); + }else{ + assert( pParse->db->mallocFailed ); + } + nConstraint += nTop; + testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); + + if( sqlite3ExprIsVector(pRight)==0 ){ + disableTerm(pLevel, pRangeEnd); + }else{ + endEq = 1; + } + }else if( bStopAtNull ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); + endEq = 0; + nConstraint++; + } + sqlite3DbFree(db, zStartAff); + sqlite3DbFree(db, zEndAff); + + /* Top of the loop body */ + pLevel->p2 = sqlite3VdbeCurrentAddr(v); + + /* Check if the index cursor is past the end of the range. */ + if( nConstraint ){ + op = aEndOp[bRev*2 + endEq]; + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); + testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); + testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); + testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); + testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); + } + + /* Seek the table cursor, if required */ + if( omitTable ){ + /* pIdx is a covering index. No need to access the main table. */ + }else if( HasRowid(pIdx->pTable) ){ + if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || ( + (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) + && (pWInfo->eOnePass==ONEPASS_SINGLE) + )){ + iRowidReg = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); + sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); + VdbeCoverage(v); + }else{ + codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); + } + }else if( iCur!=iIdxCur ){ + Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); + iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); + for(j=0; jnKeyCol; j++){ + k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); + } + sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, + iRowidReg, pPk->nKeyCol); VdbeCoverage(v); + } + + /* If pIdx is an index on one or more expressions, then look through + ** all the expressions in pWInfo and try to transform matching expressions + ** into reference to index columns. + */ + whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); + + + /* Record the instruction used to terminate the loop. */ + if( pLoop->wsFlags & WHERE_ONEROW ){ + pLevel->op = OP_Noop; + }else if( bRev ){ + pLevel->op = OP_Prev; + }else{ + pLevel->op = OP_Next; + } + pLevel->p1 = iIdxCur; + pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0; + if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ + pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; + }else{ + assert( pLevel->p5==0 ); + } + if( omitTable ) pIdx = 0; + }else + +#ifndef SQLITE_OMIT_OR_OPTIMIZATION + if( pLoop->wsFlags & WHERE_MULTI_OR ){ + /* Case 5: Two or more separately indexed terms connected by OR + ** + ** Example: + ** + ** CREATE TABLE t1(a,b,c,d); + ** CREATE INDEX i1 ON t1(a); + ** CREATE INDEX i2 ON t1(b); + ** CREATE INDEX i3 ON t1(c); + ** + ** SELECT * FROM t1 WHERE a=5 OR b=7 OR (c=11 AND d=13) + ** + ** In the example, there are three indexed terms connected by OR. + ** The top of the loop looks like this: + ** + ** Null 1 # Zero the rowset in reg 1 + ** + ** Then, for each indexed term, the following. The arguments to + ** RowSetTest are such that the rowid of the current row is inserted + ** into the RowSet. If it is already present, control skips the + ** Gosub opcode and jumps straight to the code generated by WhereEnd(). + ** + ** sqlite3WhereBegin() + ** RowSetTest # Insert rowid into rowset + ** Gosub 2 A + ** sqlite3WhereEnd() + ** + ** Following the above, code to terminate the loop. Label A, the target + ** of the Gosub above, jumps to the instruction right after the Goto. + ** + ** Null 1 # Zero the rowset in reg 1 + ** Goto B # The loop is finished. + ** + ** A: # Return data, whatever. + ** + ** Return 2 # Jump back to the Gosub + ** + ** B: + ** + ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then + ** use an ephemeral index instead of a RowSet to record the primary + ** keys of the rows we have already seen. + ** + */ + WhereClause *pOrWc; /* The OR-clause broken out into subterms */ + SrcList *pOrTab; /* Shortened table list or OR-clause generation */ + Index *pCov = 0; /* Potential covering index (or NULL) */ + int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ + + int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ + int regRowset = 0; /* Register for RowSet object */ + int regRowid = 0; /* Register holding rowid */ + int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ + int iRetInit; /* Address of regReturn init */ + int untestedTerms = 0; /* Some terms not completely tested */ + int ii; /* Loop counter */ + u16 wctrlFlags; /* Flags for sub-WHERE clause */ + Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ + Table *pTab = pTabItem->pTab; + + pTerm = pLoop->aLTerm[0]; + assert( pTerm!=0 ); + assert( pTerm->eOperator & WO_OR ); + assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); + pOrWc = &pTerm->u.pOrInfo->wc; + pLevel->op = OP_Return; + pLevel->p1 = regReturn; + + /* Set up a new SrcList in pOrTab containing the table being scanned + ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. + ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). + */ + if( pWInfo->nLevel>1 ){ + int nNotReady; /* The number of notReady tables */ + struct SrcList_item *origSrc; /* Original list of tables */ + nNotReady = pWInfo->nLevel - iLevel - 1; + pOrTab = sqlite3StackAllocRaw(db, + sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); + if( pOrTab==0 ) return notReady; + pOrTab->nAlloc = (u8)(nNotReady + 1); + pOrTab->nSrc = pOrTab->nAlloc; + memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); + origSrc = pWInfo->pTabList->a; + for(k=1; k<=nNotReady; k++){ + memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k])); + } + }else{ + pOrTab = pWInfo->pTabList; + } + + /* Initialize the rowset register to contain NULL. An SQL NULL is + ** equivalent to an empty rowset. Or, create an ephemeral index + ** capable of holding primary keys in the case of a WITHOUT ROWID. + ** + ** Also initialize regReturn to contain the address of the instruction + ** immediately following the OP_Return at the bottom of the loop. This + ** is required in a few obscure LEFT JOIN cases where control jumps + ** over the top of the loop into the body of it. In this case the + ** correct response for the end-of-loop code (the OP_Return) is to + ** fall through to the next instruction, just as an OP_Next does if + ** called on an uninitialized cursor. + */ + if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ + if( HasRowid(pTab) ){ + regRowset = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + regRowset = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); + } + regRowid = ++pParse->nMem; + } + iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); + + /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y + ** Then for every term xN, evaluate as the subexpression: xN AND z + ** That way, terms in y that are factored into the disjunction will + ** be picked up by the recursive calls to sqlite3WhereBegin() below. + ** + ** Actually, each subexpression is converted to "xN AND w" where w is + ** the "interesting" terms of z - terms that did not originate in the + ** ON or USING clause of a LEFT JOIN, and terms that are usable as + ** indices. + ** + ** This optimization also only applies if the (x1 OR x2 OR ...) term + ** is not contained in the ON clause of a LEFT JOIN. + ** See ticket http://www.sqlite.org/src/info/f2369304e4 + */ + if( pWC->nTerm>1 ){ + int iTerm; + for(iTerm=0; iTermnTerm; iTerm++){ + Expr *pExpr = pWC->a[iTerm].pExpr; + if( &pWC->a[iTerm] == pTerm ) continue; + if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; + testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); + testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); + if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue; + if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; + testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); + pExpr = sqlite3ExprDup(db, pExpr, 0); + pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); + } + if( pAndExpr ){ + pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr); + } + } + + /* Run a separate WHERE clause for each term of the OR clause. After + ** eliminating duplicates from other WHERE clauses, the action for each + ** sub-WHERE clause is to to invoke the main loop body as a subroutine. + */ + wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); + for(ii=0; iinTerm; ii++){ + WhereTerm *pOrTerm = &pOrWc->a[ii]; + if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ + WhereInfo *pSubWInfo; /* Info for single OR-term scan */ + Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ + int jmp1 = 0; /* Address of jump operation */ + if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ + pAndExpr->pLeft = pOrExpr; + pOrExpr = pAndExpr; + } + /* Loop through table entries that match term pOrTerm. */ + WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); + pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, + wctrlFlags, iCovCur); + assert( pSubWInfo || pParse->nErr || db->mallocFailed ); + if( pSubWInfo ){ + WhereLoop *pSubLoop; + int addrExplain = sqlite3WhereExplainOneScan( + pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 + ); + sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); + + /* This is the sub-WHERE clause body. First skip over + ** duplicate rows from prior sub-WHERE clauses, and record the + ** rowid (or PRIMARY KEY) for the current row so that the same + ** row will be skipped in subsequent sub-WHERE clauses. + */ + if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ + int r; + int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); + if( HasRowid(pTab) ){ + r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0); + jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, + r,iSet); + VdbeCoverage(v); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + int nPk = pPk->nKeyCol; + int iPk; + + /* Read the PK into an array of temp registers. */ + r = sqlite3GetTempRange(pParse, nPk); + for(iPk=0; iPkaiColumn[iPk]; + sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk); + } + + /* Check if the temp table already contains this key. If so, + ** the row has already been included in the result set and + ** can be ignored (by jumping past the Gosub below). Otherwise, + ** insert the key into the temp table and proceed with processing + ** the row. + ** + ** Use some of the same optimizations as OP_RowSetTest: If iSet + ** is zero, assume that the key cannot already be present in + ** the temp table. And if iSet is -1, assume that there is no + ** need to insert the key into the temp table, as it will never + ** be tested for. */ + if( iSet ){ + jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk); + VdbeCoverage(v); + } + if( iSet>=0 ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid, + r, nPk); + if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + } + + /* Release the array of temp registers */ + sqlite3ReleaseTempRange(pParse, r, nPk); + } + } + + /* Invoke the main loop body as a subroutine */ + sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody); + + /* Jump here (skipping the main loop body subroutine) if the + ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */ + if( jmp1 ) sqlite3VdbeJumpHere(v, jmp1); + + /* The pSubWInfo->untestedTerms flag means that this OR term + ** contained one or more AND term from a notReady table. The + ** terms from the notReady table could not be tested and will + ** need to be tested later. + */ + if( pSubWInfo->untestedTerms ) untestedTerms = 1; + + /* If all of the OR-connected terms are optimized using the same + ** index, and the index is opened using the same cursor number + ** by each call to sqlite3WhereBegin() made by this loop, it may + ** be possible to use that index as a covering index. + ** + ** If the call to sqlite3WhereBegin() above resulted in a scan that + ** uses an index, and this is either the first OR-connected term + ** processed or the index is the same as that used by all previous + ** terms, set pCov to the candidate covering index. Otherwise, set + ** pCov to NULL to indicate that no candidate covering index will + ** be available. + */ + pSubLoop = pSubWInfo->a[0].pWLoop; + assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); + if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 + && (ii==0 || pSubLoop->u.btree.pIndex==pCov) + && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) + ){ + assert( pSubWInfo->a[0].iIdxCur==iCovCur ); + pCov = pSubLoop->u.btree.pIndex; + }else{ + pCov = 0; + } + + /* Finish the loop through table entries that match term pOrTerm. */ + sqlite3WhereEnd(pSubWInfo); + } + } + } + pLevel->u.pCovidx = pCov; + if( pCov ) pLevel->iIdxCur = iCovCur; + if( pAndExpr ){ + pAndExpr->pLeft = 0; + sqlite3ExprDelete(db, pAndExpr); + } + sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeGoto(v, pLevel->addrBrk); + sqlite3VdbeResolveLabel(v, iLoopBody); + + if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab); + if( !untestedTerms ) disableTerm(pLevel, pTerm); + }else +#endif /* SQLITE_OMIT_OR_OPTIMIZATION */ + + { + /* Case 6: There is no usable index. We must do a complete + ** scan of the entire table. + */ + static const u8 aStep[] = { OP_Next, OP_Prev }; + static const u8 aStart[] = { OP_Rewind, OP_Last }; + assert( bRev==0 || bRev==1 ); + if( pTabItem->fg.isRecursive ){ + /* Tables marked isRecursive have only a single row that is stored in + ** a pseudo-cursor. No need to Rewind or Next such cursors. */ + pLevel->op = OP_Noop; + }else{ + codeCursorHint(pTabItem, pWInfo, pLevel, 0); + pLevel->op = aStep[bRev]; + pLevel->p1 = iCur; + pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; + } + } + +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + pLevel->addrVisit = sqlite3VdbeCurrentAddr(v); +#endif + + /* Insert code to test every subexpression that can be completely + ** computed using the current set of tables. + ** + ** This loop may run either once (pIdx==0) or twice (pIdx!=0). If + ** it is run twice, then the first iteration codes those sub-expressions + ** that can be computed using columns from pIdx only (without seeking + ** the main table cursor). + */ + do{ + loopAgain = 0; + for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ + Expr *pE; + int skipLikeAddr = 0; + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + testcase( pTerm->wtFlags & TERM_CODED ); + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ + testcase( pWInfo->untestedTerms==0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); + pWInfo->untestedTerms = 1; + continue; + } + pE = pTerm->pExpr; + assert( pE!=0 ); + if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ + continue; + } + if( pIdx && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ + loopAgain = 1; + continue; + } + if( pTerm->wtFlags & TERM_LIKECOND ){ + /* If the TERM_LIKECOND flag is set, that means that the range search + ** is sufficient to guarantee that the LIKE operator is true, so we + ** can skip the call to the like(A,B) function. But this only works + ** for strings. So do not skip the call to the function on the pass + ** that compares BLOBs. */ +#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS + continue; +#else + u32 x = pLevel->iLikeRepCntr; + assert( x>0 ); + skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1)); + VdbeCoverage(v); +#endif + } + sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); + if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); + pTerm->wtFlags |= TERM_CODED; + } + pIdx = 0; + }while( loopAgain ); + + /* Insert code to test for implied constraints based on transitivity + ** of the "==" operator. + ** + ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123" + ** and we are coding the t1 loop and the t2 loop has not yet coded, + ** then we cannot use the "t1.a=t2.b" constraint, but we can code + ** the implied "t1.a=123" constraint. + */ + for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ + Expr *pE, sEAlt; + WhereTerm *pAlt; + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; + if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; + if( pTerm->leftCursor!=iCur ) continue; + if( pLevel->iLeftJoin ) continue; + pE = pTerm->pExpr; + assert( !ExprHasProperty(pE, EP_FromJoin) ); + assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); + pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady, + WO_EQ|WO_IN|WO_IS, 0); + if( pAlt==0 ) continue; + if( pAlt->wtFlags & (TERM_CODED) ) continue; + testcase( pAlt->eOperator & WO_EQ ); + testcase( pAlt->eOperator & WO_IS ); + testcase( pAlt->eOperator & WO_IN ); + VdbeModuleComment((v, "begin transitive constraint")); + sEAlt = *pAlt->pExpr; + sEAlt.pLeft = pE->pLeft; + sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); + } + + /* For a LEFT OUTER JOIN, generate code that will record the fact that + ** at least one row of the right table has matched the left table. + */ + if( pLevel->iLeftJoin ){ + pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); + VdbeComment((v, "record LEFT JOIN hit")); + sqlite3ExprCacheClear(pParse); + for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){ + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + testcase( pTerm->wtFlags & TERM_CODED ); + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ + assert( pWInfo->untestedTerms ); + continue; + } + assert( pTerm->pExpr ); + sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); + pTerm->wtFlags |= TERM_CODED; + } + } + + return pLevel->notReady; +} + +/************** End of wherecode.c *******************************************/ +/************** Begin file whereexpr.c ***************************************/ +/* +** 2015-06-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 module contains C code that generates VDBE code used to process +** the WHERE clause of SQL statements. +** +** This file was originally part of where.c but was split out to improve +** readability and editabiliity. This file contains utility routines for +** analyzing Expr objects in the WHERE clause. +*/ +/* #include "sqliteInt.h" */ +/* #include "whereInt.h" */ + +/* Forward declarations */ +static void exprAnalyze(SrcList*, WhereClause*, int); + +/* +** Deallocate all memory associated with a WhereOrInfo object. +*/ +static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){ + sqlite3WhereClauseClear(&p->wc); + sqlite3DbFree(db, p); +} + +/* +** Deallocate all memory associated with a WhereAndInfo object. +*/ +static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){ + sqlite3WhereClauseClear(&p->wc); + sqlite3DbFree(db, p); +} + +/* +** Add a single new WhereTerm entry to the WhereClause object pWC. +** The new WhereTerm object is constructed from Expr p and with wtFlags. +** The index in pWC->a[] of the new WhereTerm is returned on success. +** 0 is returned if the new WhereTerm could not be added due to a memory +** allocation error. The memory allocation failure will be recorded in +** the db->mallocFailed flag so that higher-level functions can detect it. +** +** This routine will increase the size of the pWC->a[] array as necessary. +** +** If the wtFlags argument includes TERM_DYNAMIC, then responsibility +** for freeing the expression p is assumed by the WhereClause object pWC. +** This is true even if this routine fails to allocate a new WhereTerm. +** +** WARNING: This routine might reallocate the space used to store +** WhereTerms. All pointers to WhereTerms should be invalidated after +** calling this routine. Such pointers may be reinitialized by referencing +** the pWC->a[] array. +*/ +static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ + WhereTerm *pTerm; + int idx; + testcase( wtFlags & TERM_VIRTUAL ); + if( pWC->nTerm>=pWC->nSlot ){ + WhereTerm *pOld = pWC->a; + sqlite3 *db = pWC->pWInfo->pParse->db; + pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 ); + if( pWC->a==0 ){ + if( wtFlags & TERM_DYNAMIC ){ + sqlite3ExprDelete(db, p); + } + pWC->a = pOld; + return 0; + } + memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); + if( pOld!=pWC->aStatic ){ + sqlite3DbFree(db, pOld); + } + pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); + } + pTerm = &pWC->a[idx = pWC->nTerm++]; + if( p && ExprHasProperty(p, EP_Unlikely) ){ + pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; + }else{ + pTerm->truthProb = 1; + } + pTerm->pExpr = sqlite3ExprSkipCollate(p); + pTerm->wtFlags = wtFlags; + pTerm->pWC = pWC; + pTerm->iParent = -1; + memset(&pTerm->eOperator, 0, + sizeof(WhereTerm) - offsetof(WhereTerm,eOperator)); + return idx; +} + +/* +** Return TRUE if the given operator is one of the operators that is +** allowed for an indexable WHERE clause term. The allowed operators are +** "=", "<", ">", "<=", ">=", "IN", "IS", and "IS NULL" +*/ +static int allowedOp(int op){ + assert( TK_GT>TK_EQ && TK_GTTK_EQ && TK_LTTK_EQ && TK_LE=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS; +} + +/* +** Commute a comparison operator. Expressions of the form "X op Y" +** are converted into "Y op X". +** +** If left/right precedence rules come into play when determining the +** collating sequence, then COLLATE operators are adjusted to ensure +** that the collating sequence does not change. For example: +** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on +** the left hand side of a comparison overrides any collation sequence +** attached to the right. For the same reason the EP_Collate flag +** is not commuted. +*/ +static void exprCommute(Parse *pParse, Expr *pExpr){ + u16 expRight = (pExpr->pRight->flags & EP_Collate); + u16 expLeft = (pExpr->pLeft->flags & EP_Collate); + assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); + if( expRight==expLeft ){ + /* Either X and Y both have COLLATE operator or neither do */ + if( expRight ){ + /* Both X and Y have COLLATE operators. Make sure X is always + ** used by clearing the EP_Collate flag from Y. */ + pExpr->pRight->flags &= ~EP_Collate; + }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){ + /* Neither X nor Y have COLLATE operators, but X has a non-default + ** collating sequence. So add the EP_Collate marker on X to cause + ** it to be searched first. */ + pExpr->pLeft->flags |= EP_Collate; + } + } + SWAP(Expr*,pExpr->pRight,pExpr->pLeft); + if( pExpr->op>=TK_GT ){ + assert( TK_LT==TK_GT+2 ); + assert( TK_GE==TK_LE+2 ); + assert( TK_GT>TK_EQ ); + assert( TK_GTop>=TK_GT && pExpr->op<=TK_GE ); + pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; + } +} + +/* +** Translate from TK_xx operator to WO_xx bitmask. +*/ +static u16 operatorMask(int op){ + u16 c; + assert( allowedOp(op) ); + if( op==TK_IN ){ + c = WO_IN; + }else if( op==TK_ISNULL ){ + c = WO_ISNULL; + }else if( op==TK_IS ){ + c = WO_IS; + }else{ + assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff ); + c = (u16)(WO_EQ<<(op-TK_EQ)); + } + assert( op!=TK_ISNULL || c==WO_ISNULL ); + assert( op!=TK_IN || c==WO_IN ); + assert( op!=TK_EQ || c==WO_EQ ); + assert( op!=TK_LT || c==WO_LT ); + assert( op!=TK_LE || c==WO_LE ); + assert( op!=TK_GT || c==WO_GT ); + assert( op!=TK_GE || c==WO_GE ); + assert( op!=TK_IS || c==WO_IS ); + return c; +} + + +#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION +/* +** Check to see if the given expression is a LIKE or GLOB operator that +** can be optimized using inequality constraints. Return TRUE if it is +** so and false if not. +** +** In order for the operator to be optimizible, the RHS must be a string +** literal that does not begin with a wildcard. The LHS must be a column +** that may only be NULL, a string, or a BLOB, never a number. (This means +** that virtual tables cannot participate in the LIKE optimization.) The +** collating sequence for the column on the LHS must be appropriate for +** the operator. +*/ +static int isLikeOrGlob( + Parse *pParse, /* Parsing and code generating context */ + Expr *pExpr, /* Test this expression */ + Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ + 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 */ + 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 */ + sqlite3 *db = pParse->db; /* Database connection */ + sqlite3_value *pVal = 0; + int op; /* Opcode of pRight */ + int rc; /* Result code to return */ + + if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ + return 0; + } +#ifdef SQLITE_EBCDIC + if( *pnoCase ) return 0; +#endif + pList = pExpr->x.pList; + pLeft = pList->a[1].pExpr; + + pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); + op = pRight->op; + if( op==TK_VARIABLE ){ + Vdbe *pReprepare = pParse->pReprepare; + 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); + } + sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); + assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); + }else if( op==TK_STRING ){ + z = pRight->u.zToken; + } + if( z ){ + + /* If the RHS begins with a digit or a minus sign, then the LHS must + ** be an ordinary column (not a virtual table column) with TEXT affinity. + ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false + ** even though "lhs LIKE rhs" is true. But if the RHS does not start + ** with a digit or '-', then "lhs LIKE rhs" will always be false if + ** the LHS is numeric and so the optimization still works. + */ + if( sqlite3Isdigit(z[0]) || z[0]=='-' ){ + if( pLeft->op!=TK_COLUMN + || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT + || IsVirtual(pLeft->pTab) /* Value might be numeric */ + ){ + sqlite3ValueFree(pVal); + return 0; + } + } + cnt = 0; + while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ + cnt++; + } + if( cnt!=0 && 255!=(u8)z[cnt-1] ){ + Expr *pPrefix; + *pisComplete = c==wc[0] && z[cnt+1]==0; + pPrefix = sqlite3Expr(db, TK_STRING, z); + if( pPrefix ) pPrefix->u.zToken[cnt] = 0; + *ppPrefix = pPrefix; + if( op==TK_VARIABLE ){ + Vdbe *v = pParse->pVdbe; + sqlite3VdbeSetVarmask(v, pRight->iColumn); + if( *pisComplete && pRight->u.zToken[1] ){ + /* If the rhs of the LIKE expression is a variable, and the current + ** value of the variable means there is no need to invoke the LIKE + ** function, then no OP_Variable will be added to the program. + ** This causes problems for the sqlite3_bind_parameter_name() + ** API. To work around them, add a dummy OP_Variable here. + */ + int r1 = sqlite3GetTempReg(pParse); + sqlite3ExprCodeTarget(pParse, pRight, r1); + sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0); + sqlite3ReleaseTempReg(pParse, r1); + } + } + }else{ + z = 0; + } + } + + rc = (z!=0); + sqlite3ValueFree(pVal); + return rc; +} +#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ + + +#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( + 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; + + 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; iu.zToken, aOp[i].zOp)==0 ){ + *peOp2 = aOp[i].eOp2; + return 1; + } + } + return 0; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +/* +** If the pBase expression originated in the ON or USING clause of +** a join, then transfer the appropriate markings over to derived. +*/ +static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ + if( pDerived ){ + pDerived->flags |= pBase->flags & EP_FromJoin; + pDerived->iRightJoinTable = pBase->iRightJoinTable; + } +} + +/* +** Mark term iChild as being a child of term iParent +*/ +static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ + pWC->a[iChild].iParent = iParent; + pWC->a[iChild].truthProb = pWC->a[iParent].truthProb; + pWC->a[iParent].nChild++; +} + +/* +** Return the N-th AND-connected subterm of pTerm. Or if pTerm is not +** a conjunction, then return just pTerm when N==0. If N is exceeds +** the number of available subterms, return NULL. +*/ +static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){ + if( pTerm->eOperator!=WO_AND ){ + return N==0 ? pTerm : 0; + } + if( Nu.pAndInfo->wc.nTerm ){ + return &pTerm->u.pAndInfo->wc.a[N]; + } + return 0; +} + +/* +** Subterms pOne and pTwo are contained within WHERE clause pWC. The +** two subterms are in disjunction - they are OR-ed together. +** +** If these two terms are both of the form: "A op B" with the same +** A and B values but different operators and if the operators are +** compatible (if one is = and the other is <, for example) then +** add a new virtual AND term to pWC that is the combination of the +** two. +** +** Some examples: +** +** x x<=y +** x=y OR x=y --> x=y +** x<=y OR x x<=y +** +** The following is NOT generated: +** +** xy --> x!=y +*/ +static void whereCombineDisjuncts( + SrcList *pSrc, /* the FROM clause */ + WhereClause *pWC, /* The complete WHERE clause */ + WhereTerm *pOne, /* First disjunct */ + WhereTerm *pTwo /* Second disjunct */ +){ + u16 eOp = pOne->eOperator | pTwo->eOperator; + sqlite3 *db; /* Database connection (for malloc) */ + Expr *pNew; /* New virtual expression */ + int op; /* Operator for the combined expression */ + int idxNew; /* Index in pWC of the next virtual term */ + + if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; + if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; + if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp + && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; + assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); + assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); + if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; + if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return; + /* If we reach this point, it means the two subterms can be combined */ + if( (eOp & (eOp-1))!=0 ){ + if( eOp & (WO_LT|WO_LE) ){ + eOp = WO_LE; + }else{ + assert( eOp & (WO_GT|WO_GE) ); + eOp = WO_GE; + } + } + db = pWC->pWInfo->pParse->db; + pNew = sqlite3ExprDup(db, pOne->pExpr, 0); + if( pNew==0 ) return; + for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( opop = op; + idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); + exprAnalyze(pSrc, pWC, idxNew); +} + +#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) +/* +** Analyze a term that consists of two or more OR-connected +** subterms. So in: +** +** ... WHERE (a=5) AND (b=7 OR c=9 OR d=13) AND (d=13) +** ^^^^^^^^^^^^^^^^^^^^ +** +** This routine analyzes terms such as the middle term in the above example. +** A WhereOrTerm object is computed and attached to the term under +** analysis, regardless of the outcome of the analysis. Hence: +** +** WhereTerm.wtFlags |= TERM_ORINFO +** WhereTerm.u.pOrInfo = a dynamically allocated WhereOrTerm object +** +** The term being analyzed must have two or more of OR-connected subterms. +** A single subterm might be a set of AND-connected sub-subterms. +** Examples of terms under analysis: +** +** (A) t1.x=t2.y OR t1.x=t2.z OR t1.y=15 OR t1.z=t3.a+5 +** (B) x=expr1 OR expr2=x OR x=expr3 +** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15) +** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*') +** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6) +** (F) x>A OR (x=A AND y>=B) +** +** CASE 1: +** +** If all subterms are of the form T.C=expr for some single column of C and +** a single table T (as shown in example B above) then create a new virtual +** term that is an equivalent IN expression. In other words, if the term +** being analyzed is: +** +** x = expr1 OR expr2 = x OR x = expr3 +** +** then create a new virtual term like this: +** +** x IN (expr1,expr2,expr3) +** +** CASE 2: +** +** If there are exactly two disjuncts and one side has x>A and the other side +** has x=A (for the same x and A) then add a new virtual conjunct term to the +** WHERE clause of the form "x>=A". Example: +** +** x>A OR (x=A AND y>B) adds: x>=A +** +** The added conjunct can sometimes be helpful in query planning. +** +** CASE 3: +** +** If all subterms are indexable by a single table T, then set +** +** WhereTerm.eOperator = WO_OR +** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T +** +** A subterm is "indexable" if it is of the form +** "T.C " where C is any column of table T and +** is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN". +** A subterm is also indexable if it is an AND of two or more +** subsubterms at least one of which is indexable. Indexable AND +** subterms have their eOperator set to WO_AND and they have +** u.pAndInfo set to a dynamically allocated WhereAndTerm object. +** +** From another point of view, "indexable" means that the subterm could +** potentially be used with an index if an appropriate index exists. +** This analysis does not consider whether or not the index exists; that +** is decided elsewhere. This analysis only looks at whether subterms +** appropriate for indexing exist. +** +** All examples A through E above satisfy case 3. But if a term +** also satisfies case 1 (such as B) we know that the optimizer will +** always prefer case 1, so in that case we pretend that case 3 is not +** satisfied. +** +** It might be the case that multiple tables are indexable. For example, +** (E) above is indexable on tables P, Q, and R. +** +** Terms that satisfy case 3 are candidates for lookup by using +** separate indices to find rowids for each subterm and composing +** the union of all rowids using a RowSet object. This is similar +** to "bitmap indices" in other database engines. +** +** OTHERWISE: +** +** If none of cases 1, 2, or 3 apply, then leave the eOperator set to +** zero. This term is not useful for search. +*/ +static void exprAnalyzeOrTerm( + SrcList *pSrc, /* the FROM clause */ + WhereClause *pWC, /* the complete WHERE clause */ + int idxTerm /* Index of the OR-term to be analyzed */ +){ + WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ + Parse *pParse = pWInfo->pParse; /* Parser context */ + sqlite3 *db = pParse->db; /* Database connection */ + WhereTerm *pTerm = &pWC->a[idxTerm]; /* The term to be analyzed */ + Expr *pExpr = pTerm->pExpr; /* The expression of the term */ + int i; /* Loop counters */ + WhereClause *pOrWc; /* Breakup of pTerm into subterms */ + WhereTerm *pOrTerm; /* A Sub-term within the pOrWc */ + WhereOrInfo *pOrInfo; /* Additional information associated with pTerm */ + Bitmask chngToIN; /* Tables that might satisfy case 1 */ + Bitmask indexable; /* Tables that are indexable, satisfying case 2 */ + + /* + ** Break the OR clause into its separate subterms. The subterms are + ** stored in a WhereClause structure containing within the WhereOrInfo + ** object that is attached to the original OR clause term. + */ + assert( (pTerm->wtFlags & (TERM_DYNAMIC|TERM_ORINFO|TERM_ANDINFO))==0 ); + assert( pExpr->op==TK_OR ); + pTerm->u.pOrInfo = pOrInfo = sqlite3DbMallocZero(db, sizeof(*pOrInfo)); + if( pOrInfo==0 ) return; + pTerm->wtFlags |= TERM_ORINFO; + pOrWc = &pOrInfo->wc; + memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic)); + sqlite3WhereClauseInit(pOrWc, pWInfo); + sqlite3WhereSplit(pOrWc, pExpr, TK_OR); + sqlite3WhereExprAnalyze(pSrc, pOrWc); + if( db->mallocFailed ) return; + assert( pOrWc->nTerm>=2 ); + + /* + ** Compute the set of tables that might satisfy cases 1 or 3. + */ + indexable = ~(Bitmask)0; + chngToIN = ~(Bitmask)0; + for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ + if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ + WhereAndInfo *pAndInfo; + assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); + chngToIN = 0; + pAndInfo = sqlite3DbMallocRawNN(db, sizeof(*pAndInfo)); + if( pAndInfo ){ + WhereClause *pAndWC; + WhereTerm *pAndTerm; + int j; + Bitmask b = 0; + pOrTerm->u.pAndInfo = pAndInfo; + pOrTerm->wtFlags |= TERM_ANDINFO; + pOrTerm->eOperator = WO_AND; + pAndWC = &pAndInfo->wc; + memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic)); + sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); + sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); + sqlite3WhereExprAnalyze(pSrc, pAndWC); + pAndWC->pOuter = pWC; + if( !db->mallocFailed ){ + for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ + assert( pAndTerm->pExpr ); + if( allowedOp(pAndTerm->pExpr->op) + || pAndTerm->eOperator==WO_MATCH + ){ + b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); + } + } + } + indexable &= b; + } + }else if( pOrTerm->wtFlags & TERM_COPIED ){ + /* Skip this term for now. We revisit it when we process the + ** corresponding TERM_VIRTUAL term */ + }else{ + Bitmask b; + b = sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor); + if( pOrTerm->wtFlags & TERM_VIRTUAL ){ + WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; + b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pOther->leftCursor); + } + indexable &= b; + if( (pOrTerm->eOperator & WO_EQ)==0 ){ + chngToIN = 0; + }else{ + chngToIN &= b; + } + } + } + + /* + ** Record the set of tables that satisfy case 3. The set might be + ** empty. + */ + pOrInfo->indexable = indexable; + pTerm->eOperator = indexable==0 ? 0 : WO_OR; + + /* For a two-way OR, attempt to implementation case 2. + */ + if( indexable && pOrWc->nTerm==2 ){ + int iOne = 0; + WhereTerm *pOne; + while( (pOne = whereNthSubterm(&pOrWc->a[0],iOne++))!=0 ){ + int iTwo = 0; + WhereTerm *pTwo; + while( (pTwo = whereNthSubterm(&pOrWc->a[1],iTwo++))!=0 ){ + whereCombineDisjuncts(pSrc, pWC, pOne, pTwo); + } + } + } + + /* + ** chngToIN holds a set of tables that *might* satisfy case 1. But + ** we have to do some additional checking to see if case 1 really + ** is satisfied. + ** + ** chngToIN will hold either 0, 1, or 2 bits. The 0-bit case means + ** that there is no possibility of transforming the OR clause into an + ** IN operator because one or more terms in the OR clause contain + ** something other than == on a column in the single table. The 1-bit + ** case means that every term of the OR clause is of the form + ** "table.column=expr" for some single table. The one bit that is set + ** will correspond to the common table. We still need to check to make + ** sure the same column is used on all terms. The 2-bit case is when + ** the all terms are of the form "table1.column=table2.column". It + ** might be possible to form an IN operator with either table1.column + ** or table2.column as the LHS if either is common to every term of + ** the OR clause. + ** + ** Note that terms of the form "table.column1=table.column2" (the + ** same table on both sizes of the ==) cannot be optimized. + */ + if( chngToIN ){ + int okToChngToIN = 0; /* True if the conversion to IN is valid */ + int iColumn = -1; /* Column index on lhs of IN operator */ + int iCursor = -1; /* Table cursor common to all terms */ + int j = 0; /* Loop counter */ + + /* Search for a table and column that appears on one side or the + ** other of the == operator in every subterm. That table and column + ** will be recorded in iCursor and iColumn. There might not be any + ** such table and column. Set okToChngToIN if an appropriate table + ** and column is found but leave okToChngToIN false if not found. + */ + for(j=0; j<2 && !okToChngToIN; j++){ + pOrTerm = pOrWc->a; + for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ + assert( pOrTerm->eOperator & WO_EQ ); + pOrTerm->wtFlags &= ~TERM_OR_OK; + if( pOrTerm->leftCursor==iCursor ){ + /* This is the 2-bit case and we are on the second iteration and + ** current term is from the first iteration. So skip this term. */ + assert( j==1 ); + continue; + } + if( (chngToIN & sqlite3WhereGetMask(&pWInfo->sMaskSet, + pOrTerm->leftCursor))==0 ){ + /* This term must be of the form t1.a==t2.b where t2 is in the + ** chngToIN set but t1 is not. This term will be either preceded + ** or follwed by an inverted copy (t2.b==t1.a). Skip this term + ** and use its inversion. */ + testcase( pOrTerm->wtFlags & TERM_COPIED ); + testcase( pOrTerm->wtFlags & TERM_VIRTUAL ); + assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); + continue; + } + iColumn = pOrTerm->u.leftColumn; + iCursor = pOrTerm->leftCursor; + break; + } + if( i<0 ){ + /* No candidate table+column was found. This can only occur + ** on the second iteration */ + assert( j==1 ); + assert( IsPowerOfTwo(chngToIN) ); + assert( chngToIN==sqlite3WhereGetMask(&pWInfo->sMaskSet, iCursor) ); + break; + } + testcase( j==1 ); + + /* We have found a candidate table and column. Check to see if that + ** table and column is common to every term in the OR clause */ + okToChngToIN = 1; + for(; i>=0 && okToChngToIN; i--, pOrTerm++){ + assert( pOrTerm->eOperator & WO_EQ ); + if( pOrTerm->leftCursor!=iCursor ){ + pOrTerm->wtFlags &= ~TERM_OR_OK; + }else if( pOrTerm->u.leftColumn!=iColumn ){ + okToChngToIN = 0; + }else{ + int affLeft, affRight; + /* If the right-hand side is also a column, then the affinities + ** of both right and left sides must be such that no type + ** conversions are required on the right. (Ticket #2249) + */ + affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight); + affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft); + if( affRight!=0 && affRight!=affLeft ){ + okToChngToIN = 0; + }else{ + pOrTerm->wtFlags |= TERM_OR_OK; + } + } + } + } + + /* At this point, okToChngToIN is true if original pTerm satisfies + ** case 1. In that case, construct a new virtual term that is + ** pTerm converted into an IN operator. + */ + if( okToChngToIN ){ + Expr *pDup; /* A transient duplicate expression */ + ExprList *pList = 0; /* The RHS of the IN operator */ + Expr *pLeft = 0; /* The LHS of the IN operator */ + Expr *pNew; /* The complete IN operator */ + + for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ + if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; + assert( pOrTerm->eOperator & WO_EQ ); + assert( pOrTerm->leftCursor==iCursor ); + assert( pOrTerm->u.leftColumn==iColumn ); + pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); + pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); + pLeft = pOrTerm->pExpr->pLeft; + } + assert( pLeft!=0 ); + pDup = sqlite3ExprDup(db, pLeft, 0); + pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0); + if( pNew ){ + int idxNew; + transferJoinMarkings(pNew, pExpr); + assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + pNew->x.pList = pList; + idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + exprAnalyze(pSrc, pWC, idxNew); + pTerm = &pWC->a[idxTerm]; + markTermAsChild(pWC, idxNew, idxTerm); + }else{ + sqlite3ExprListDelete(db, pList); + } + pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */ + } + } +} +#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ + +/* +** We already know that pExpr is a binary operator where both operands are +** column references. This routine checks to see if pExpr is an equivalence +** relation: +** 1. The SQLITE_Transitive optimization must be enabled +** 2. Must be either an == or an IS operator +** 3. Not originating in the ON clause of an OUTER JOIN +** 4. The affinities of A and B must be compatible +** 5a. Both operands use the same collating sequence OR +** 5b. The overall collating sequence is BINARY +** If this routine returns TRUE, that means that the RHS can be substituted +** for the LHS anyplace else in the WHERE clause where the LHS column occurs. +** This is an optimization. No harm comes from returning 0. But if 1 is +** returned when it should not be, then incorrect answers might result. +*/ +static int termIsEquivalence(Parse *pParse, Expr *pExpr){ + 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; + aff1 = sqlite3ExprAffinity(pExpr->pLeft); + aff2 = sqlite3ExprAffinity(pExpr->pRight); + if( aff1!=aff2 + && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) + ){ + return 0; + } + 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; +} + +/* +** Recursively walk the expressions of a SELECT statement and generate +** a bitmask indicating which tables are used in that expression +** tree. +*/ +static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ + Bitmask mask = 0; + while( pS ){ + SrcList *pSrc = pS->pSrc; + mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pEList); + mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pGroupBy); + mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pOrderBy); + mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); + mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); + if( ALWAYS(pSrc!=0) ){ + int i; + for(i=0; inSrc; i++){ + mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); + mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn); + } + } + pS = pS->pPrior; + } + return mask; +} + +/* +** Expression pExpr is one operand of a comparison operator that might +** be useful for indexing. This routine checks to see if pExpr appears +** in any index. Return TRUE (1) if pExpr is an indexed term and return +** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor +** number of the table that is indexed and aiCurCol[1] to the column number +** of the column that is indexed, or XN_EXPR (-2) if an expression is being +** indexed. +** +** If pExpr is a TK_COLUMN column reference, then this routine always returns +** true even if that particular column is not indexed, because the column +** might be added to an automatic index later. +*/ +static SQLITE_NOINLINE int exprMightBeIndexed2( + SrcList *pFrom, /* The FROM clause */ + Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ + int *aiCurCol, /* Write the referenced table cursor and column here */ + Expr *pExpr /* An operand of a comparison operator */ +){ + Index *pIdx; + int i; + int iCur; + for(i=0; mPrereq>1; i++, mPrereq>>=1){} + iCur = pFrom->a[i].iCursor; + for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->aColExpr==0 ) continue; + for(i=0; inKeyCol; i++){ + if( pIdx->aiColumn[i]!=XN_EXPR ) continue; + if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ + aiCurCol[0] = iCur; + aiCurCol[1] = XN_EXPR; + return 1; + } + } + } + return 0; +} +static int exprMightBeIndexed( + SrcList *pFrom, /* The FROM clause */ + Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ + int *aiCurCol, /* Write the referenced table cursor & column here */ + Expr *pExpr, /* An operand of a comparison operator */ + int op /* The specific comparison operator */ +){ + /* If this expression is a vector to the left or right of a + ** inequality constraint (>, <, >= or <=), perform the processing + ** on the first element of the vector. */ + assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE ); + assert( TK_ISop==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ + pExpr = pExpr->x.pList->a[0].pExpr; + } + + if( pExpr->op==TK_COLUMN ){ + aiCurCol[0] = pExpr->iTable; + aiCurCol[1] = pExpr->iColumn; + return 1; + } + if( mPrereq==0 ) return 0; /* No table references */ + if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ + return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr); +} + +/* +** The input to this routine is an WhereTerm structure with only the +** "pExpr" field filled in. The job of this routine is to analyze the +** subexpression and populate all the other fields of the WhereTerm +** structure. +** +** If the expression is of the form " X" it gets commuted +** to the standard form of "X ". +** +** If the expression is of the form "X Y" where both X and Y are +** columns, then the original expression is unchanged and a new virtual +** term of the form "Y X" is added to the WHERE clause and +** analyzed separately. The original term is marked with TERM_COPIED +** and the new term is marked with TERM_DYNAMIC (because it's pExpr +** needs to be freed with the WhereClause) and TERM_VIRTUAL (because it +** is a commuted copy of a prior term.) The original term has nChild=1 +** and the copy has idxParent set to the index of the original term. +*/ +static void exprAnalyze( + SrcList *pSrc, /* the FROM clause */ + WhereClause *pWC, /* the WHERE clause */ + int idxTerm /* Index of the term to be analyzed */ +){ + WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ + WhereTerm *pTerm; /* The term to be analyzed */ + WhereMaskSet *pMaskSet; /* Set of table index masks */ + Expr *pExpr; /* The expression to be analyzed */ + Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ + Bitmask prereqAll; /* Prerequesites of pExpr */ + Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */ + Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ + int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ + int noCase = 0; /* uppercase equivalent to lowercase */ + int op; /* Top-level operator. pExpr->op */ + Parse *pParse = pWInfo->pParse; /* Parsing context */ + sqlite3 *db = pParse->db; /* Database connection */ + unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */ + int nLeft; /* Number of elements on left side vector */ + + if( db->mallocFailed ){ + return; + } + pTerm = &pWC->a[idxTerm]; + pMaskSet = &pWInfo->sMaskSet; + pExpr = pTerm->pExpr; + assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); + prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft); + op = pExpr->op; + if( op==TK_IN ){ + assert( pExpr->pRight==0 ); + if( sqlite3ExprCheckIN(pParse, pExpr) ) return; + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); + }else{ + pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); + } + }else if( op==TK_ISNULL ){ + pTerm->prereqRight = 0; + }else{ + pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); + } + prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr); + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); + prereqAll |= x; + extraRight = x-1; /* ON clause terms may not be used with an index + ** on left table of a LEFT JOIN. Ticket #3015 */ + if( (prereqAll>>1)>=x ){ + sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); + return; + } + } + pTerm->prereqAll = prereqAll; + pTerm->leftCursor = -1; + pTerm->iParent = -1; + pTerm->eOperator = 0; + if( allowedOp(op) ){ + int aiCurCol[2]; + Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); + Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); + u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; + + if( pTerm->iField>0 ){ + assert( op==TK_IN ); + assert( pLeft->op==TK_VECTOR ); + pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr; + } + + if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ + pTerm->leftCursor = aiCurCol[0]; + pTerm->u.leftColumn = aiCurCol[1]; + pTerm->eOperator = operatorMask(op) & opMask; + } + if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; + if( pRight + && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op) + ){ + WhereTerm *pNew; + Expr *pDup; + u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ + assert( pTerm->iField==0 ); + if( pTerm->leftCursor>=0 ){ + int idxNew; + pDup = sqlite3ExprDup(db, pExpr, 0); + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDup); + return; + } + idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); + if( idxNew==0 ) return; + pNew = &pWC->a[idxNew]; + markTermAsChild(pWC, idxNew, idxTerm); + if( op==TK_IS ) pNew->wtFlags |= TERM_IS; + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + + if( termIsEquivalence(pParse, pDup) ){ + pTerm->eOperator |= WO_EQUIV; + eExtraOp = WO_EQUIV; + } + }else{ + pDup = pExpr; + pNew = pTerm; + } + exprCommute(pParse, pDup); + pNew->leftCursor = aiCurCol[0]; + pNew->u.leftColumn = aiCurCol[1]; + testcase( (prereqLeft | extraRight) != prereqLeft ); + pNew->prereqRight = prereqLeft | extraRight; + pNew->prereqAll = prereqAll; + pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; + } + } + +#ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION + /* If a term is the BETWEEN operator, create two new virtual terms + ** that define the range that the BETWEEN implements. For example: + ** + ** a BETWEEN b AND c + ** + ** is converted into: + ** + ** (a BETWEEN b AND c) AND (a>=b) AND (a<=c) + ** + ** The two new terms are added onto the end of the WhereClause object. + ** The new terms are "dynamic" and are children of the original BETWEEN + ** term. That means that if the BETWEEN term is coded, the children are + ** skipped. Or, if the children are satisfied by an index, the original + ** BETWEEN term is skipped. + */ + else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){ + ExprList *pList = pExpr->x.pList; + int i; + static const u8 ops[] = {TK_GE, TK_LE}; + assert( pList!=0 ); + assert( pList->nExpr==2 ); + for(i=0; i<2; i++){ + Expr *pNewExpr; + int idxNew; + pNewExpr = sqlite3PExpr(pParse, ops[i], + sqlite3ExprDup(db, pExpr->pLeft, 0), + sqlite3ExprDup(db, pList->a[i].pExpr, 0)); + transferJoinMarkings(pNewExpr, pExpr); + idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + exprAnalyze(pSrc, pWC, idxNew); + pTerm = &pWC->a[idxTerm]; + markTermAsChild(pWC, idxNew, idxTerm); + } + } +#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */ + +#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) + /* Analyze a term that is composed of two or more subterms connected by + ** an OR operator. + */ + else if( pExpr->op==TK_OR ){ + assert( pWC->op==TK_AND ); + exprAnalyzeOrTerm(pSrc, pWC, idxTerm); + pTerm = &pWC->a[idxTerm]; + } +#endif /* SQLITE_OMIT_OR_OPTIMIZATION */ + +#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION + /* Add constraints to reduce the search space on a LIKE or GLOB + ** operator. + ** + ** A like pattern of the form "x LIKE 'aBc%'" is changed into constraints + ** + ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' + ** + ** The last character of the prefix "abc" is incremented to form the + ** termination condition "abd". If case is not significant (the default + ** for LIKE) then the lower-bound is made all uppercase and the upper- + ** bound is made all lowercase so that the bounds also work when comparing + ** BLOBs. + */ + if( pWC->op==TK_AND + && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) + ){ + Expr *pLeft; /* LHS of LIKE/GLOB operator */ + Expr *pStr2; /* Copy of pStr1 - RHS of LIKE/GLOB operator */ + Expr *pNewExpr1; + Expr *pNewExpr2; + int idxNew1; + int idxNew2; + const char *zCollSeqName; /* Name of collating sequence */ + const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; + + pLeft = pExpr->x.pList->a[1].pExpr; + pStr2 = sqlite3ExprDup(db, pStr1, 0); + + /* Convert the lower bound to upper-case and the upper bound to + ** lower-case (upper-case is less than lower-case in ASCII) so that + ** the range constraints also work for BLOBs + */ + if( noCase && !pParse->db->mallocFailed ){ + int i; + char c; + pTerm->wtFlags |= TERM_LIKE; + for(i=0; (c = pStr1->u.zToken[i])!=0; i++){ + pStr1->u.zToken[i] = sqlite3Toupper(c); + pStr2->u.zToken[i] = sqlite3Tolower(c); + } + } + + if( !db->mallocFailed ){ + u8 c, *pC; /* Last character before the first wildcard */ + pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; + c = *pC; + if( noCase ){ + /* The point is to increment the last character before the first + ** wildcard. But if we increment '@', that will push it into the + ** alphabetic range where case conversions will mess up the + ** inequality. To avoid this, make sure to also run the full + ** LIKE on all candidate expressions by clearing the isComplete flag + */ + if( c=='A'-1 ) isComplete = 0; + c = sqlite3UpperToLower[c]; + } + *pC = c + 1; + } + zCollSeqName = noCase ? "NOCASE" : "BINARY"; + pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); + pNewExpr1 = sqlite3PExpr(pParse, TK_GE, + sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), + pStr1); + transferJoinMarkings(pNewExpr1, pExpr); + idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); + testcase( idxNew1==0 ); + exprAnalyze(pSrc, pWC, idxNew1); + pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); + pNewExpr2 = sqlite3PExpr(pParse, TK_LT, + sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), + pStr2); + transferJoinMarkings(pNewExpr2, pExpr); + idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); + testcase( idxNew2==0 ); + exprAnalyze(pSrc, pWC, idxNew2); + pTerm = &pWC->a[idxTerm]; + if( isComplete ){ + markTermAsChild(pWC, idxNew1, idxTerm); + markTermAsChild(pWC, idxNew2, idxTerm); + } + } +#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. + ** 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; + 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)); + 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; + } + } +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create + ** new terms for each component comparison - "a = ?" and "b = ?". The + ** new terms completely replace the original vector comparison, which is + ** no longer used. + ** + ** This is only required if at least one side of the comparison operation + ** is not a sub-select. */ + if( pWC->op==TK_AND + && (pExpr->op==TK_EQ || pExpr->op==TK_IS) + && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1 + && sqlite3ExprVectorSize(pExpr->pRight)==nLeft + && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 + || (pExpr->pRight->flags & EP_xIsSelect)==0) + ){ + int i; + for(i=0; ipLeft, i); + Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i); + + pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); + transferJoinMarkings(pNew, pExpr); + idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC); + exprAnalyze(pSrc, pWC, idxNew); + } + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL; /* Disable the original */ + pTerm->eOperator = 0; + } + + /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create + ** a virtual term for each vector component. The expression object + ** used by each such virtual term is pExpr (the full vector IN(...) + ** expression). The WhereTerm.iField variable identifies the index within + ** the vector on the LHS that the virtual term represents. + ** + ** This only works if the RHS is a simple SELECT, not a compound + */ + if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0 + && pExpr->pLeft->op==TK_VECTOR + && pExpr->x.pSelect->pPrior==0 + ){ + int i; + for(i=0; ipLeft); i++){ + int idxNew; + idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL); + pWC->a[idxNew].iField = i+1; + exprAnalyze(pSrc, pWC, idxNew); + markTermAsChild(pWC, idxNew, idxTerm); + } + } + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + /* When sqlite_stat3 histogram data is available an operator of the + ** form "x IS NOT NULL" can sometimes be evaluated more efficiently + ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a + ** virtual term of that form. + ** + ** Note that the virtual term must be tagged with TERM_VNULL. + */ + if( pExpr->op==TK_NOTNULL + && pExpr->pLeft->op==TK_COLUMN + && pExpr->pLeft->iColumn>=0 + && OptimizationEnabled(db, SQLITE_Stat34) + ){ + Expr *pNewExpr; + Expr *pLeft = pExpr->pLeft; + int idxNew; + WhereTerm *pNewTerm; + + pNewExpr = sqlite3PExpr(pParse, TK_GT, + sqlite3ExprDup(db, pLeft, 0), + sqlite3ExprAlloc(db, TK_NULL, 0, 0)); + + idxNew = whereClauseInsert(pWC, pNewExpr, + TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); + if( idxNew ){ + pNewTerm = &pWC->a[idxNew]; + pNewTerm->prereqRight = 0; + pNewTerm->leftCursor = pLeft->iTable; + pNewTerm->u.leftColumn = pLeft->iColumn; + pNewTerm->eOperator = WO_GT; + markTermAsChild(pWC, idxNew, idxTerm); + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + pNewTerm->prereqAll = pTerm->prereqAll; + } + } +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + + /* Prevent ON clause terms of a LEFT JOIN from being used to drive + ** an index for tables to the left of the join. + */ + testcase( pTerm!=&pWC->a[idxTerm] ); + pTerm = &pWC->a[idxTerm]; + pTerm->prereqRight |= extraRight; +} + +/*************************************************************************** +** Routines with file scope above. Interface to the rest of the where.c +** subsystem follows. +***************************************************************************/ + +/* +** This routine identifies subexpressions in the WHERE clause where +** each subexpression is separated by the AND operator or some other +** operator specified in the op parameter. The WhereClause structure +** is filled with pointers to subexpressions. For example: +** +** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22) +** \________/ \_______________/ \________________/ +** slot[0] slot[1] slot[2] +** +** The original WHERE clause in pExpr is unaltered. All this routine +** does is make slot[] entries point to substructure within pExpr. +** +** In the previous sentence and in the diagram, "slot[]" refers to +** the WhereClause.a[] array. The slot[] array grows as needed to contain +** all terms of the WHERE clause. +*/ +SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ + Expr *pE2 = sqlite3ExprSkipCollate(pExpr); + pWC->op = op; + if( pE2==0 ) return; + if( pE2->op!=op ){ + whereClauseInsert(pWC, pExpr, 0); + }else{ + sqlite3WhereSplit(pWC, pE2->pLeft, op); + sqlite3WhereSplit(pWC, pE2->pRight, op); + } +} + +/* +** Initialize a preallocated WhereClause structure. +*/ +SQLITE_PRIVATE void sqlite3WhereClauseInit( + WhereClause *pWC, /* The WhereClause to be initialized */ + WhereInfo *pWInfo /* The WHERE processing context */ +){ + pWC->pWInfo = pWInfo; + pWC->pOuter = 0; + pWC->nTerm = 0; + pWC->nSlot = ArraySize(pWC->aStatic); + pWC->a = pWC->aStatic; +} + +/* +** Deallocate a WhereClause structure. The WhereClause structure +** itself is not freed. This routine is the inverse of +** sqlite3WhereClauseInit(). +*/ +SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){ + int i; + WhereTerm *a; + sqlite3 *db = pWC->pWInfo->pParse->db; + for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){ + if( a->wtFlags & TERM_DYNAMIC ){ + sqlite3ExprDelete(db, a->pExpr); + } + if( a->wtFlags & TERM_ORINFO ){ + whereOrInfoDelete(db, a->u.pOrInfo); + }else if( a->wtFlags & TERM_ANDINFO ){ + whereAndInfoDelete(db, a->u.pAndInfo); + } + } + if( pWC->a!=pWC->aStatic ){ + sqlite3DbFree(db, pWC->a); + } +} + + +/* +** These routines walk (recursively) an expression tree and generate +** a bitmask indicating which tables are used in that expression +** tree. +*/ +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ + Bitmask mask; + if( p==0 ) return 0; + if( p->op==TK_COLUMN ){ + return sqlite3WhereGetMask(pMaskSet, p->iTable); + } + mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; + assert( !ExprHasProperty(p, EP_TokenOnly) ); + if( p->pRight ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight); + if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); + if( ExprHasProperty(p, EP_xIsSelect) ){ + mask |= exprSelectUsage(pMaskSet, p->x.pSelect); + }else if( p->x.pList ){ + mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); + } + return mask; +} +SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){ + int i; + Bitmask mask = 0; + if( pList ){ + for(i=0; inExpr; i++){ + mask |= sqlite3WhereExprUsage(pMaskSet, pList->a[i].pExpr); + } + } + return mask; +} + + +/* +** Call exprAnalyze on all terms in a WHERE clause. +** +** Note that exprAnalyze() might add new virtual terms onto the +** end of the WHERE clause. We do not want to analyze these new +** virtual terms, so start analyzing at the end and work forward +** so that the added virtual terms are never processed. +*/ +SQLITE_PRIVATE void sqlite3WhereExprAnalyze( + SrcList *pTabList, /* the FROM clause */ + WhereClause *pWC /* the WHERE clause to be analyzed */ +){ + int i; + for(i=pWC->nTerm-1; i>=0; i--){ + exprAnalyze(pTabList, pWC, i); + } +} + +/* +** For table-valued-functions, transform the function arguments into +** new WHERE clause terms. +** +** Each function argument translates into an equality constraint against +** a HIDDEN column in the table. +*/ +SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( + Parse *pParse, /* Parsing context */ + struct SrcList_item *pItem, /* The FROM clause term to process */ + WhereClause *pWC /* Xfer function arguments to here */ +){ + Table *pTab; + int j, k; + ExprList *pArgs; + Expr *pColRef; + Expr *pTerm; + if( pItem->fg.isTabFunc==0 ) return; + pTab = pItem->pTab; + assert( pTab!=0 ); + pArgs = pItem->u1.pFuncArg; + if( pArgs==0 ) return; + for(j=k=0; jnExpr; j++){ + while( knCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} + if( k>=pTab->nCol ){ + sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", + pTab->zName, j); + return; + } + pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); + if( pColRef==0 ) return; + pColRef->iTable = pItem->iCursor; + pColRef->iColumn = k++; + pColRef->pTab = pTab; + pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, + sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0)); + whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); + } +} + +/************** End of whereexpr.c *******************************************/ +/************** Begin file where.c *******************************************/ +/* +** 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 module contains C code that generates VDBE code used to process +** the WHERE clause of SQL statements. This module is responsible for +** generating the code that loops through a table looking for applicable +** rows. Indices are selected and used to speed the search when doing +** so is applicable. Because this module is responsible for selecting +** indices, you might also think of this module as the "query optimizer". +*/ +/* #include "sqliteInt.h" */ +/* #include "whereInt.h" */ + +/* Forward declaration of methods */ +static int whereLoopResize(sqlite3*, WhereLoop*, int); + +/* Test variable that can be set to enable WHERE tracing */ +#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) +/***/ int sqlite3WhereTrace = 0; +#endif + + +/* +** Return the estimated number of output rows from a WHERE clause +*/ +SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){ + return pWInfo->nRowOut; +} + +/* +** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this +** WHERE clause returns outputs for DISTINCT processing. +*/ +SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ + return pWInfo->eDistinct; +} + +/* +** Return TRUE if the WHERE clause returns rows in ORDER BY order. +** Return FALSE if the output needs to be sorted. +*/ +SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ + return pWInfo->nOBSat; +} + +/* +** Return TRUE if the innermost loop of the WHERE clause implementation +** returns rows in ORDER BY order for complete run of the inner loop. +** +** Across multiple iterations of outer loops, the output rows need not be +** sorted. As long as rows are sorted for just the innermost loop, this +** routine can return TRUE. +*/ +SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){ + return pWInfo->bOrderedInnerLoop; +} + +/* +** Return the VDBE address or label to jump to in order to continue +** immediately with the next row of a WHERE clause. +*/ +SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ + assert( pWInfo->iContinue!=0 ); + return pWInfo->iContinue; +} + +/* +** Return the VDBE address or label to jump to in order to break +** out of a WHERE loop. +*/ +SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ + return pWInfo->iBreak; +} + +/* +** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to +** operate directly on the rowis returned by a WHERE clause. Return +** ONEPASS_SINGLE (1) if the statement can operation directly because only +** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass +** optimization can be used on multiple +** +** If the ONEPASS optimization is used (if this routine returns true) +** then also write the indices of open cursors used by ONEPASS +** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data +** table and iaCur[1] gets the cursor used by an auxiliary index. +** Either value may be -1, indicating that cursor is not used. +** Any cursors returned will have been opened for writing. +** +** aiCur[0] and aiCur[1] both get -1 if the where-clause logic is +** unable to use the ONEPASS optimization. +*/ +SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){ + memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2); +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace && pWInfo->eOnePass!=ONEPASS_OFF ){ + sqlite3DebugPrintf("%s cursors: %d %d\n", + pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI", + aiCur[0], aiCur[1]); + } +#endif + return pWInfo->eOnePass; +} + +/* +** Move the content of pSrc into pDest +*/ +static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){ + pDest->n = pSrc->n; + memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0])); +} + +/* +** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet. +** +** The new entry might overwrite an existing entry, or it might be +** appended, or it might be discarded. Do whatever is the right thing +** so that pSet keeps the N_OR_COST best entries seen so far. +*/ +static int whereOrInsert( + WhereOrSet *pSet, /* The WhereOrSet to be updated */ + Bitmask prereq, /* Prerequisites of the new entry */ + LogEst rRun, /* Run-cost of the new entry */ + LogEst nOut /* Number of outputs for the new entry */ +){ + u16 i; + WhereOrCost *p; + for(i=pSet->n, p=pSet->a; i>0; i--, p++){ + if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){ + goto whereOrInsert_done; + } + if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){ + return 0; + } + } + if( pSet->na[pSet->n++]; + p->nOut = nOut; + }else{ + p = pSet->a; + for(i=1; in; i++){ + if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i; + } + if( p->rRun<=rRun ) return 0; + } +whereOrInsert_done: + p->prereq = prereq; + p->rRun = rRun; + if( p->nOut>nOut ) p->nOut = nOut; + return 1; +} + +/* +** Return the bitmask for the given cursor number. Return 0 if +** iCursor is not in the set. +*/ +SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){ + int i; + assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 ); + for(i=0; in; i++){ + if( pMaskSet->ix[i]==iCursor ){ + return MASKBIT(i); + } + } + return 0; +} + +/* +** Create a new mask for cursor iCursor. +** +** There is one cursor per table in the FROM clause. The number of +** tables in the FROM clause is limited by a test early in the +** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[] +** array will never overflow. +*/ +static void createMask(WhereMaskSet *pMaskSet, int iCursor){ + assert( pMaskSet->n < ArraySize(pMaskSet->ix) ); + pMaskSet->ix[pMaskSet->n++] = iCursor; +} + +/* +** Advance to the next WhereTerm that matches according to the criteria +** established when the pScan object was initialized by whereScanInit(). +** Return NULL if there are no more matching WhereTerms. +*/ +static WhereTerm *whereScanNext(WhereScan *pScan){ + int iCur; /* The cursor on the LHS of the term */ + i16 iColumn; /* The column on the LHS of the term. -1 for IPK */ + Expr *pX; /* An expression being tested */ + WhereClause *pWC; /* Shorthand for pScan->pWC */ + WhereTerm *pTerm; /* The term being tested */ + int k = pScan->k; /* Where to start scanning */ + + assert( pScan->iEquiv<=pScan->nEquiv ); + pWC = pScan->pWC; + while(1){ + iColumn = pScan->aiColumn[pScan->iEquiv-1]; + iCur = pScan->aiCur[pScan->iEquiv-1]; + assert( pWC!=0 ); + do{ + for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ + if( pTerm->leftCursor==iCur + && pTerm->u.leftColumn==iColumn + && (iColumn!=XN_EXPR + || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft, + pScan->pIdxExpr,iCur)==0) + && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) + ){ + if( (pTerm->eOperator & WO_EQUIV)!=0 + && pScan->nEquivaiCur) + && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN + ){ + int j; + for(j=0; jnEquiv; j++){ + if( pScan->aiCur[j]==pX->iTable + && pScan->aiColumn[j]==pX->iColumn ){ + break; + } + } + if( j==pScan->nEquiv ){ + pScan->aiCur[j] = pX->iTable; + pScan->aiColumn[j] = pX->iColumn; + pScan->nEquiv++; + } + } + if( (pTerm->eOperator & pScan->opMask)!=0 ){ + /* Verify the affinity and collating sequence match */ + if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){ + CollSeq *pColl; + Parse *pParse = pWC->pWInfo->pParse; + pX = pTerm->pExpr; + if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ + continue; + } + assert(pX->pLeft); + pColl = sqlite3BinaryCompareCollSeq(pParse, + pX->pLeft, pX->pRight); + if( pColl==0 ) pColl = pParse->db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ + continue; + } + } + if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 + && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN + && pX->iTable==pScan->aiCur[0] + && pX->iColumn==pScan->aiColumn[0] + ){ + testcase( pTerm->eOperator & WO_IS ); + continue; + } + pScan->pWC = pWC; + pScan->k = k+1; + return pTerm; + } + } + } + pWC = pWC->pOuter; + k = 0; + }while( pWC!=0 ); + if( pScan->iEquiv>=pScan->nEquiv ) break; + pWC = pScan->pOrigWC; + k = 0; + pScan->iEquiv++; + } + return 0; +} + +/* +** Initialize a WHERE clause scanner object. Return a pointer to the +** first match. Return NULL if there are no matches. +** +** The scanner will be searching the WHERE clause pWC. It will look +** for terms of the form "X " where X is column iColumn of table +** iCur. Or if pIdx!=0 then X is column iColumn of index pIdx. pIdx +** must be one of the indexes of table iCur. +** +** The must be one of the operators described by opMask. +** +** If the search is for X and the WHERE clause contains terms of the +** form X=Y then this routine might also return terms of the form +** "Y ". The number of levels of transitivity is limited, +** but is enough to handle most commonly occurring SQL statements. +** +** If X is not the INTEGER PRIMARY KEY then X must be compatible with +** index pIdx. +*/ +static WhereTerm *whereScanInit( + WhereScan *pScan, /* The WhereScan object being initialized */ + WhereClause *pWC, /* The WHERE clause to be scanned */ + int iCur, /* Cursor to scan for */ + int iColumn, /* Column to scan for */ + u32 opMask, /* Operator(s) to scan for */ + Index *pIdx /* Must be compatible with this index */ +){ + pScan->pOrigWC = pWC; + pScan->pWC = pWC; + pScan->pIdxExpr = 0; + pScan->idxaff = 0; + pScan->zCollName = 0; + if( pIdx ){ + int j = iColumn; + iColumn = pIdx->aiColumn[j]; + if( iColumn==XN_EXPR ){ + pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; + pScan->zCollName = pIdx->azColl[j]; + }else if( iColumn==pIdx->pTable->iPKey ){ + iColumn = XN_ROWID; + }else if( iColumn>=0 ){ + pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; + pScan->zCollName = pIdx->azColl[j]; + } + }else if( iColumn==XN_EXPR ){ + return 0; + } + pScan->opMask = opMask; + pScan->k = 0; + pScan->aiCur[0] = iCur; + pScan->aiColumn[0] = iColumn; + pScan->nEquiv = 1; + pScan->iEquiv = 1; + return whereScanNext(pScan); +} + +/* +** Search for a term in the WHERE clause that is of the form "X " +** where X is a reference to the iColumn of table iCur or of index pIdx +** if pIdx!=0 and is one of the WO_xx operator codes specified by +** the op parameter. Return a pointer to the term. Return 0 if not found. +** +** If pIdx!=0 then it must be one of the indexes of table iCur. +** Search for terms matching the iColumn-th column of pIdx +** rather than the iColumn-th column of table iCur. +** +** The term returned might by Y= if there is another constraint in +** the WHERE clause that specifies that X=Y. Any such constraints will be +** identified by the WO_EQUIV bit in the pTerm->eOperator field. The +** aiCur[]/iaColumn[] arrays hold X and all its equivalents. There are 11 +** slots in aiCur[]/aiColumn[] so that means we can look for X plus up to 10 +** other equivalent values. Hence a search for X will return if X=A1 +** and A1=A2 and A2=A3 and ... and A9=A10 and A10=. +** +** If there are multiple terms in the WHERE clause of the form "X " +** then try for the one with no dependencies on - in other words where +** is a constant expression of some kind. Only return entries of +** the form "X Y" where Y is a column in another table if no terms of +** the form "X " exist. If no terms with a constant RHS +** exist, try to return a term that does not use WO_EQUIV. +*/ +SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( + WhereClause *pWC, /* The WHERE clause to be searched */ + int iCur, /* Cursor number of LHS */ + int iColumn, /* Column number of LHS */ + Bitmask notReady, /* RHS must not overlap with this mask */ + u32 op, /* Mask of WO_xx values describing operator */ + Index *pIdx /* Must be compatible with this index, if not NULL */ +){ + WhereTerm *pResult = 0; + WhereTerm *p; + WhereScan scan; + + p = whereScanInit(&scan, pWC, iCur, iColumn, op, pIdx); + op &= WO_EQ|WO_IS; + while( p ){ + if( (p->prereqRight & notReady)==0 ){ + if( p->prereqRight==0 && (p->eOperator&op)!=0 ){ + testcase( p->eOperator & WO_IS ); + return p; + } + if( pResult==0 ) pResult = p; + } + p = whereScanNext(&scan); + } + return pResult; +} + +/* +** This function searches pList for an entry that matches the iCol-th column +** of index pIdx. +** +** If such an expression is found, its index in pList->a[] is returned. If +** no expression is found, -1 is returned. +*/ +static int findIndexCol( + Parse *pParse, /* Parse context */ + ExprList *pList, /* Expression list to search */ + int iBase, /* Cursor for table associated with pIdx */ + Index *pIdx, /* Index to match column of */ + int iCol /* Column of index to match */ +){ + int i; + const char *zColl = pIdx->azColl[iCol]; + + for(i=0; inExpr; i++){ + Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); + if( p->op==TK_COLUMN + && p->iColumn==pIdx->aiColumn[iCol] + && p->iTable==iBase + ){ + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); + if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){ + return i; + } + } + } + + return -1; +} + +/* +** Return TRUE if the iCol-th column of index pIdx is NOT NULL +*/ +static int indexColumnNotNull(Index *pIdx, int iCol){ + int j; + assert( pIdx!=0 ); + assert( iCol>=0 && iColnColumn ); + j = pIdx->aiColumn[iCol]; + if( j>=0 ){ + return pIdx->pTable->aCol[j].notNull; + }else if( j==(-1) ){ + return 1; + }else{ + assert( j==(-2) ); + return 0; /* Assume an indexed expression can always yield a NULL */ + + } +} + +/* +** Return true if the DISTINCT expression-list passed as the third argument +** is redundant. +** +** A DISTINCT list is redundant if any subset of the columns in the +** DISTINCT list are collectively unique and individually non-null. +*/ +static int isDistinctRedundant( + Parse *pParse, /* Parsing context */ + SrcList *pTabList, /* The FROM clause */ + WhereClause *pWC, /* The WHERE clause */ + ExprList *pDistinct /* The result set that needs to be DISTINCT */ +){ + Table *pTab; + Index *pIdx; + int i; + int iBase; + + /* If there is more than one table or sub-select in the FROM clause of + ** this query, then it will not be possible to show that the DISTINCT + ** clause is redundant. */ + if( pTabList->nSrc!=1 ) return 0; + iBase = pTabList->a[0].iCursor; + pTab = pTabList->a[0].pTab; + + /* If any of the expressions is an IPK column on table iBase, then return + ** true. Note: The (p->iTable==iBase) part of this test may be false if the + ** current SELECT is a correlated sub-query. + */ + for(i=0; inExpr; i++){ + Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr); + if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1; + } + + /* Loop through all indices on the table, checking each to see if it makes + ** the DISTINCT qualifier redundant. It does so if: + ** + ** 1. The index is itself UNIQUE, and + ** + ** 2. All of the columns in the index are either part of the pDistinct + ** list, or else the WHERE clause contains a term of the form "col=X", + ** where X is a constant value. The collation sequences of the + ** comparison and select-list expressions must match those of the index. + ** + ** 3. All of those index columns for which the WHERE clause does not + ** contain a "col=X" term are subject to a NOT NULL constraint. + */ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( !IsUniqueIndex(pIdx) ) continue; + for(i=0; inKeyCol; i++){ + if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){ + if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break; + if( indexColumnNotNull(pIdx, i)==0 ) break; + } + } + if( i==pIdx->nKeyCol ){ + /* This index implies that the DISTINCT qualifier is redundant. */ + return 1; + } + } + + return 0; +} + + +/* +** Estimate the logarithm of the input value to base 2. +*/ +static LogEst estLog(LogEst N){ + return N<=10 ? 0 : sqlite3LogEst(N) - 33; +} + +/* +** Convert OP_Column opcodes to OP_Copy in previously generated code. +** +** This routine runs over generated VDBE code and translates OP_Column +** opcodes into OP_Copy when the table is being accessed via co-routine +** instead of via table lookup. +** +** If the bIncrRowid parameter is 0, then any OP_Rowid instructions on +** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero, +** then each OP_Rowid is transformed into an instruction to increment the +** value stored in its output register. +*/ +static void translateColumnToCopy( + Parse *pParse, /* Parsing context */ + int iStart, /* Translate from this opcode to the end */ + int iTabCur, /* OP_Column/OP_Rowid references to this table */ + int iRegister, /* The first column is in this register */ + int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */ +){ + Vdbe *v = pParse->pVdbe; + VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); + int iEnd = sqlite3VdbeCurrentAddr(v); + if( pParse->db->mallocFailed ) return; + for(; iStartp1!=iTabCur ) continue; + if( pOp->opcode==OP_Column ){ + pOp->opcode = OP_Copy; + pOp->p1 = pOp->p2 + iRegister; + pOp->p2 = pOp->p3; + pOp->p3 = 0; + }else if( pOp->opcode==OP_Rowid ){ + if( bIncrRowid ){ + /* Increment the value stored in the P2 operand of the OP_Rowid. */ + pOp->opcode = OP_AddImm; + pOp->p1 = pOp->p2; + pOp->p2 = 1; + }else{ + pOp->opcode = OP_Null; + pOp->p1 = 0; + pOp->p3 = 0; + } + } + } +} + +/* +** Two routines for printing the content of an sqlite3_index_info +** structure. Used for testing and debugging only. If neither +** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines +** are no-ops. +*/ +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED) +static void TRACE_IDX_INPUTS(sqlite3_index_info *p){ + int i; + if( !sqlite3WhereTrace ) return; + for(i=0; inConstraint; i++){ + sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n", + i, + p->aConstraint[i].iColumn, + p->aConstraint[i].iTermOffset, + p->aConstraint[i].op, + p->aConstraint[i].usable); + } + for(i=0; inOrderBy; i++){ + sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n", + i, + p->aOrderBy[i].iColumn, + p->aOrderBy[i].desc); + } +} +static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){ + int i; + if( !sqlite3WhereTrace ) return; + for(i=0; inConstraint; i++){ + sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n", + i, + p->aConstraintUsage[i].argvIndex, + p->aConstraintUsage[i].omit); + } + sqlite3DebugPrintf(" idxNum=%d\n", p->idxNum); + sqlite3DebugPrintf(" idxStr=%s\n", p->idxStr); + sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed); + sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost); + sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows); +} +#else +#define TRACE_IDX_INPUTS(A) +#define TRACE_IDX_OUTPUTS(A) +#endif + +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX +/* +** Return TRUE if the WHERE clause term pTerm is of a form where it +** could be used with an index to access pSrc, assuming an appropriate +** index existed. +*/ +static int termCanDriveIndex( + WhereTerm *pTerm, /* WHERE clause term to check */ + struct SrcList_item *pSrc, /* Table we are trying to access */ + Bitmask notReady /* Tables in outer loops of the join */ +){ + char aff; + if( pTerm->leftCursor!=pSrc->iCursor ) return 0; + if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; + if( (pTerm->prereqRight & notReady)!=0 ) return 0; + if( pTerm->u.leftColumn<0 ) return 0; + aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; + if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; + testcase( pTerm->pExpr->op==TK_IS ); + return 1; +} +#endif + + +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX +/* +** Generate code to construct the Index object for an automatic index +** and to set up the WhereLevel object pLevel so that the code generator +** makes use of the automatic index. +*/ +static void constructAutomaticIndex( + Parse *pParse, /* The parsing context */ + WhereClause *pWC, /* The WHERE clause */ + struct SrcList_item *pSrc, /* The FROM clause term to get the next index */ + Bitmask notReady, /* Mask of cursors that are not available */ + WhereLevel *pLevel /* Write new index here */ +){ + int nKeyCol; /* Number of columns in the constructed index */ + WhereTerm *pTerm; /* A single term of the WHERE clause */ + WhereTerm *pWCEnd; /* End of pWC->a[] */ + Index *pIdx; /* Object describing the transient index */ + Vdbe *v; /* Prepared statement under construction */ + int addrInit; /* Address of the initialization bypass jump */ + Table *pTable; /* The table being indexed */ + int addrTop; /* Top of the index fill loop */ + int regRecord; /* Register holding an index record */ + int n; /* Column counter */ + int i; /* Loop counter */ + int mxBitCol; /* Maximum column in pSrc->colUsed */ + CollSeq *pColl; /* Collating sequence to on a column */ + WhereLoop *pLoop; /* The Loop object */ + char *zNotUsed; /* Extra space on the end of pIdx */ + Bitmask idxCols; /* Bitmap of columns used for indexing */ + Bitmask extraCols; /* Bitmap of additional columns */ + u8 sentWarning = 0; /* True if a warnning has been issued */ + Expr *pPartial = 0; /* Partial Index Expression */ + int iContinue = 0; /* Jump here to skip excluded rows */ + struct SrcList_item *pTabItem; /* FROM clause term being indexed */ + int addrCounter = 0; /* Address where integer counter is initialized */ + int regBase; /* Array of registers where record is assembled */ + + /* Generate code to skip over the creation and initialization of the + ** transient index on 2nd and subsequent iterations of the loop. */ + v = pParse->pVdbe; + assert( v!=0 ); + addrInit = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + + /* Count the number of columns that will be added to the index + ** and used to match WHERE clause constraints */ + nKeyCol = 0; + pTable = pSrc->pTab; + pWCEnd = &pWC->a[pWC->nTerm]; + pLoop = pLevel->pWLoop; + idxCols = 0; + for(pTerm=pWC->a; pTermpExpr; + assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */ + || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */ + || pLoop->prereq!=0 ); /* table of a LEFT JOIN */ + if( pLoop->prereq==0 + && (pTerm->wtFlags & TERM_VIRTUAL)==0 + && !ExprHasProperty(pExpr, EP_FromJoin) + && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ + pPartial = sqlite3ExprAnd(pParse->db, pPartial, + sqlite3ExprDup(pParse->db, pExpr, 0)); + } + if( termCanDriveIndex(pTerm, pSrc, notReady) ){ + int iCol = pTerm->u.leftColumn; + Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); + testcase( iCol==BMS ); + testcase( iCol==BMS-1 ); + if( !sentWarning ){ + sqlite3_log(SQLITE_WARNING_AUTOINDEX, + "automatic index on %s(%s)", pTable->zName, + pTable->aCol[iCol].zName); + sentWarning = 1; + } + if( (idxCols & cMask)==0 ){ + if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){ + goto end_auto_index_create; + } + pLoop->aLTerm[nKeyCol++] = pTerm; + idxCols |= cMask; + } + } + } + assert( nKeyCol>0 ); + pLoop->u.btree.nEq = pLoop->nLTerm = nKeyCol; + pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED + | WHERE_AUTO_INDEX; + + /* Count the number of additional columns needed to create a + ** covering index. A "covering index" is an index that contains all + ** columns that are needed by the query. With a covering index, the + ** original table never needs to be accessed. Automatic indices must + ** be a covering index because the index will not be updated if the + ** original table changes and the index and table cannot both be used + ** if they go out of sync. + */ + extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); + mxBitCol = MIN(BMS-1,pTable->nCol); + testcase( pTable->nCol==BMS-1 ); + testcase( pTable->nCol==BMS-2 ); + for(i=0; icolUsed & MASKBIT(BMS-1) ){ + nKeyCol += pTable->nCol - BMS + 1; + } + + /* Construct the Index object to describe this index */ + pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed); + if( pIdx==0 ) goto end_auto_index_create; + pLoop->u.btree.pIndex = pIdx; + pIdx->zName = "auto-index"; + pIdx->pTable = pTable; + n = 0; + idxCols = 0; + for(pTerm=pWC->a; pTermu.leftColumn; + Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); + testcase( iCol==BMS-1 ); + testcase( iCol==BMS ); + if( (idxCols & cMask)==0 ){ + Expr *pX = pTerm->pExpr; + idxCols |= cMask; + pIdx->aiColumn[n] = pTerm->u.leftColumn; + pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); + pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; + n++; + } + } + } + assert( (u32)n==pLoop->u.btree.nEq ); + + /* Add additional columns needed to make the automatic index into + ** a covering index */ + for(i=0; iaiColumn[n] = i; + pIdx->azColl[n] = sqlite3StrBINARY; + n++; + } + } + if( pSrc->colUsed & MASKBIT(BMS-1) ){ + for(i=BMS-1; inCol; i++){ + pIdx->aiColumn[n] = i; + pIdx->azColl[n] = sqlite3StrBINARY; + n++; + } + } + assert( n==nKeyCol ); + pIdx->aiColumn[n] = XN_ROWID; + pIdx->azColl[n] = sqlite3StrBINARY; + + /* Create the automatic index */ + assert( pLevel->iIdxCur>=0 ); + pLevel->iIdxCur = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); + sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + VdbeComment((v, "for %s", pTable->zName)); + + /* Fill the automatic index with content */ + sqlite3ExprCachePush(pParse); + pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; + if( pTabItem->fg.viaCoroutine ){ + int regYield = pTabItem->regReturn; + addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); + addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); + VdbeCoverage(v); + VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + }else{ + addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); + } + if( pPartial ){ + iContinue = sqlite3VdbeMakeLabel(v); + sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); + pLoop->wsFlags |= WHERE_PARTIALIDX; + } + regRecord = sqlite3GetTempReg(pParse); + regBase = sqlite3GenerateIndexKey( + pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0 + ); + sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); + if( pTabItem->fg.viaCoroutine ){ + sqlite3VdbeChangeP2(v, addrCounter, regBase+n); + testcase( pParse->db->mallocFailed ); + translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, + pTabItem->regResult, 1); + sqlite3VdbeGoto(v, addrTop); + pTabItem->fg.viaCoroutine = 0; + }else{ + sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); + } + sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); + sqlite3VdbeJumpHere(v, addrTop); + sqlite3ReleaseTempReg(pParse, regRecord); + sqlite3ExprCachePop(pParse); + + /* Jump here when skipping the initialization */ + sqlite3VdbeJumpHere(v, addrInit); + +end_auto_index_create: + sqlite3ExprDelete(pParse->db, pPartial); +} +#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Allocate and populate an sqlite3_index_info structure. It is the +** responsibility of the caller to eventually release the structure +** by passing the pointer returned by this function to sqlite3_free(). +*/ +static sqlite3_index_info *allocateIndexInfo( + Parse *pParse, + WhereClause *pWC, + Bitmask mUnusable, /* Ignore terms with these prereqs */ + struct SrcList_item *pSrc, + ExprList *pOrderBy, + u16 *pmNoOmit /* Mask of terms not to omit */ +){ + int i, j; + int nTerm; + struct sqlite3_index_constraint *pIdxCons; + struct sqlite3_index_orderby *pIdxOrderBy; + struct sqlite3_index_constraint_usage *pUsage; + WhereTerm *pTerm; + int nOrderBy; + sqlite3_index_info *pIdxInfo; + u16 mNoOmit = 0; + + /* Count the number of possible WHERE clause constraints referring + ** to this virtual table */ + for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){ + if( pTerm->leftCursor != pSrc->iCursor ) continue; + if( pTerm->prereqRight & mUnusable ) continue; + assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); + testcase( pTerm->eOperator & WO_IN ); + testcase( pTerm->eOperator & WO_ISNULL ); + testcase( pTerm->eOperator & WO_IS ); + testcase( pTerm->eOperator & WO_ALL ); + if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; + if( pTerm->wtFlags & TERM_VNULL ) continue; + assert( pTerm->u.leftColumn>=(-1) ); + nTerm++; + } + + /* If the ORDER BY clause contains only columns in the current + ** virtual table then allocate space for the aOrderBy part of + ** the sqlite3_index_info structure. + */ + nOrderBy = 0; + if( pOrderBy ){ + int n = pOrderBy->nExpr; + for(i=0; ia[i].pExpr; + if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break; + } + if( i==n){ + nOrderBy = n; + } + } + + /* Allocate the sqlite3_index_info structure + */ + pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm + + sizeof(*pIdxOrderBy)*nOrderBy ); + if( pIdxInfo==0 ){ + sqlite3ErrorMsg(pParse, "out of memory"); + return 0; + } + + /* Initialize the structure. The sqlite3_index_info structure contains + ** many fields that are declared "const" to prevent xBestIndex from + ** changing them. We have to do some funky casting in order to + ** initialize those fields. + */ + pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1]; + pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm]; + pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy]; + *(int*)&pIdxInfo->nConstraint = nTerm; + *(int*)&pIdxInfo->nOrderBy = nOrderBy; + *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons; + *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; + *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage = + pUsage; + + for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ + u8 op; + if( pTerm->leftCursor != pSrc->iCursor ) continue; + if( pTerm->prereqRight & mUnusable ) continue; + assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); + testcase( pTerm->eOperator & WO_IN ); + testcase( pTerm->eOperator & WO_IS ); + testcase( pTerm->eOperator & WO_ISNULL ); + testcase( pTerm->eOperator & WO_ALL ); + if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==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; + 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; + } + + j++; + } + for(i=0; ia[i].pExpr; + pIdxOrderBy[i].iColumn = pExpr->iColumn; + pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder; + } + + *pmNoOmit = mNoOmit; + return pIdxInfo; +} + +/* +** The table object reference passed as the second argument to this function +** must represent a virtual table. This function invokes the xBestIndex() +** method of the virtual table with the sqlite3_index_info object that +** comes in as the 3rd argument to this function. +** +** If an error occurs, pParse is populated with an error message and a +** non-zero value is returned. Otherwise, 0 is returned and the output +** part of the sqlite3_index_info structure is left populated. +** +** Whether or not an error is returned, it is the responsibility of the +** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates +** that this is required. +*/ +static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ + sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; + int rc; + + TRACE_IDX_INPUTS(p); + rc = pVtab->pModule->xBestIndex(pVtab, p); + TRACE_IDX_OUTPUTS(p); + + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ){ + sqlite3OomFault(pParse->db); + }else if( !pVtab->zErrMsg ){ + sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); + }else{ + sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); + } + } + sqlite3_free(pVtab->zErrMsg); + pVtab->zErrMsg = 0; + +#if 0 + /* This error is now caught by the caller. + ** Search for "xBestIndex malfunction" below */ + for(i=0; inConstraint; i++){ + if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){ + sqlite3ErrorMsg(pParse, + "table %s: xBestIndex returned an invalid plan", pTab->zName); + } + } +#endif + + return pParse->nErr; +} +#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** Estimate the location of a particular key among all keys in an +** index. Store the results in aStat as follows: +** +** aStat[0] Est. number of rows less than pRec +** aStat[1] Est. number of rows equal to pRec +** +** Return the index of the sample that is the smallest sample that +** is greater than or equal to pRec. Note that this index is not an index +** into the aSample[] array - it is an index into a virtual set of samples +** based on the contents of aSample[] and the number of fields in record +** pRec. +*/ +static int whereKeyStats( + Parse *pParse, /* Database connection */ + Index *pIdx, /* Index to consider domain of */ + UnpackedRecord *pRec, /* Vector of values to consider */ + int roundUp, /* Round up if true. Round down if false */ + tRowcnt *aStat /* OUT: stats written here */ +){ + IndexSample *aSample = pIdx->aSample; + int iCol; /* Index of required stats in anEq[] etc. */ + int i; /* Index of first sample >= pRec */ + int iSample; /* Smallest sample larger than or equal to pRec */ + int iMin = 0; /* Smallest sample not yet tested */ + int iTest; /* Next sample to test */ + int res; /* Result of comparison operation */ + int nField; /* Number of fields in pRec */ + tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */ + +#ifndef SQLITE_DEBUG + UNUSED_PARAMETER( pParse ); +#endif + assert( pRec!=0 ); + assert( pIdx->nSample>0 ); + assert( pRec->nField>0 && pRec->nField<=pIdx->nSampleCol ); + + /* Do a binary search to find the first sample greater than or equal + ** to pRec. If pRec contains a single field, the set of samples to search + ** is simply the aSample[] array. If the samples in aSample[] contain more + ** than one fields, all fields following the first are ignored. + ** + ** If pRec contains N fields, where N is more than one, then as well as the + ** samples in aSample[] (truncated to N fields), the search also has to + ** consider prefixes of those samples. For example, if the set of samples + ** in aSample is: + ** + ** aSample[0] = (a, 5) + ** aSample[1] = (a, 10) + ** aSample[2] = (b, 5) + ** aSample[3] = (c, 100) + ** aSample[4] = (c, 105) + ** + ** Then the search space should ideally be the samples above and the + ** unique prefixes [a], [b] and [c]. But since that is hard to organize, + ** the code actually searches this set: + ** + ** 0: (a) + ** 1: (a, 5) + ** 2: (a, 10) + ** 3: (a, 10) + ** 4: (b) + ** 5: (b, 5) + ** 6: (c) + ** 7: (c, 100) + ** 8: (c, 105) + ** 9: (c, 105) + ** + ** For each sample in the aSample[] array, N samples are present in the + ** effective sample array. In the above, samples 0 and 1 are based on + ** sample aSample[0]. Samples 2 and 3 on aSample[1] etc. + ** + ** Often, sample i of each block of N effective samples has (i+1) fields. + ** Except, each sample may be extended to ensure that it is greater than or + ** equal to the previous sample in the array. For example, in the above, + ** sample 2 is the first sample of a block of N samples, so at first it + ** appears that it should be 1 field in size. However, that would make it + ** smaller than sample 1, so the binary search would not work. As a result, + ** it is extended to two fields. The duplicates that this creates do not + ** cause any problems. + */ + nField = pRec->nField; + iCol = 0; + iSample = pIdx->nSample * nField; + do{ + int iSamp; /* Index in aSample[] of test sample */ + int n; /* Number of fields in test sample */ + + iTest = (iMin+iSample)/2; + iSamp = iTest / nField; + if( iSamp>0 ){ + /* The proposed effective sample is a prefix of sample aSample[iSamp]. + ** Specifically, the shortest prefix of at least (1 + iTest%nField) + ** fields that is greater than the previous effective sample. */ + for(n=(iTest % nField) + 1; nnField = n; + res = sqlite3VdbeRecordCompare(aSample[iSamp].n, aSample[iSamp].p, pRec); + if( res<0 ){ + iLower = aSample[iSamp].anLt[n-1] + aSample[iSamp].anEq[n-1]; + iMin = iTest+1; + }else if( res==0 && ndb->mallocFailed==0 ){ + if( res==0 ){ + /* If (res==0) is true, then pRec must be equal to sample i. */ + assert( inSample ); + assert( iCol==nField-1 ); + pRec->nField = nField; + assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) + || pParse->db->mallocFailed + ); + }else{ + /* Unless i==pIdx->nSample, indicating that pRec is larger than + ** all samples in the aSample[] array, pRec must be smaller than the + ** (iCol+1) field prefix of sample i. */ + assert( i<=pIdx->nSample && i>=0 ); + pRec->nField = iCol+1; + assert( i==pIdx->nSample + || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 + || pParse->db->mallocFailed ); + + /* if i==0 and iCol==0, then record pRec is smaller than all samples + ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must + ** be greater than or equal to the (iCol) field prefix of sample i. + ** If (i>0), then pRec must also be greater than sample (i-1). */ + if( iCol>0 ){ + pRec->nField = iCol; + assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0 + || pParse->db->mallocFailed ); + } + if( i>0 ){ + pRec->nField = nField; + assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 + || pParse->db->mallocFailed ); + } + } + } +#endif /* ifdef SQLITE_DEBUG */ + + if( res==0 ){ + /* Record pRec is equal to sample i */ + assert( iCol==nField-1 ); + aStat[0] = aSample[i].anLt[iCol]; + aStat[1] = aSample[i].anEq[iCol]; + }else{ + /* At this point, the (iCol+1) field prefix of aSample[i] is the first + ** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec + ** is larger than all samples in the array. */ + tRowcnt iUpper, iGap; + if( i>=pIdx->nSample ){ + iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]); + }else{ + iUpper = aSample[i].anLt[iCol]; + } + + if( iLower>=iUpper ){ + iGap = 0; + }else{ + iGap = iUpper - iLower; + } + if( roundUp ){ + iGap = (iGap*2)/3; + }else{ + iGap = iGap/3; + } + aStat[0] = iLower + iGap; + aStat[1] = pIdx->aAvgEq[iCol]; + } + + /* Restore the pRec->nField value before returning. */ + pRec->nField = nField; + return i; +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + +/* +** If it is not NULL, pTerm is a term that provides an upper or lower +** bound on a range scan. Without considering pTerm, it is estimated +** that the scan will visit nNew rows. This function returns the number +** estimated to be visited after taking pTerm into account. +** +** If the user explicitly specified a likelihood() value for this term, +** then the return value is the likelihood multiplied by the number of +** input rows. Otherwise, this function assumes that an "IS NOT NULL" term +** has a likelihood of 0.50, and any other term a likelihood of 0.25. +*/ +static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ + LogEst nRet = nNew; + if( pTerm ){ + if( pTerm->truthProb<=0 ){ + nRet += pTerm->truthProb; + }else if( (pTerm->wtFlags & TERM_VNULL)==0 ){ + nRet -= 20; assert( 20==sqlite3LogEst(4) ); + } + } + return nRet; +} + + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** Return the affinity for a single column of an index. +*/ +SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ + assert( iCol>=0 && iColnColumn ); + if( !pIdx->zColAff ){ + if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; + } + return pIdx->zColAff[iCol]; +} +#endif + + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** This function is called to estimate the number of rows visited by a +** range-scan on a skip-scan index. For example: +** +** CREATE INDEX i1 ON t1(a, b, c); +** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?; +** +** Value pLoop->nOut is currently set to the estimated number of rows +** visited for scanning (a=? AND b=?). This function reduces that estimate +** by some factor to account for the (c BETWEEN ? AND ?) expression based +** on the stat4 data for the index. this scan will be peformed multiple +** times (once for each (a,b) combination that matches a=?) is dealt with +** by the caller. +** +** It does this by scanning through all stat4 samples, comparing values +** extracted from pLower and pUpper with the corresponding column in each +** sample. If L and U are the number of samples found to be less than or +** equal to the values extracted from pLower and pUpper respectively, and +** N is the total number of samples, the pLoop->nOut value is adjusted +** as follows: +** +** nOut = nOut * ( min(U - L, 1) / N ) +** +** If pLower is NULL, or a value cannot be extracted from the term, L is +** set to zero. If pUpper is NULL, or a value cannot be extracted from it, +** U is set to N. +** +** Normally, this function sets *pbDone to 1 before returning. However, +** if no value can be extracted from either pLower or pUpper (and so the +** estimate of the number of rows delivered remains unchanged), *pbDone +** is left as is. +** +** If an error occurs, an SQLite error code is returned. Otherwise, +** SQLITE_OK. +*/ +static int whereRangeSkipScanEst( + Parse *pParse, /* Parsing & code generating context */ + WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ + WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ + WhereLoop *pLoop, /* Update the .nOut value of this loop */ + int *pbDone /* Set to true if at least one expr. value extracted */ +){ + Index *p = pLoop->u.btree.pIndex; + int nEq = pLoop->u.btree.nEq; + sqlite3 *db = pParse->db; + int nLower = -1; + int nUpper = p->nSample+1; + int rc = SQLITE_OK; + u8 aff = sqlite3IndexColumnAffinity(db, p, nEq); + CollSeq *pColl; + + sqlite3_value *p1 = 0; /* Value extracted from pLower */ + sqlite3_value *p2 = 0; /* Value extracted from pUpper */ + sqlite3_value *pVal = 0; /* Value extracted from record */ + + pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]); + if( pLower ){ + rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, aff, &p1); + nLower = 0; + } + if( pUpper && rc==SQLITE_OK ){ + rc = sqlite3Stat4ValueFromExpr(pParse, pUpper->pExpr->pRight, aff, &p2); + nUpper = p2 ? 0 : p->nSample; + } + + if( p1 || p2 ){ + int i; + int nDiff; + for(i=0; rc==SQLITE_OK && inSample; i++){ + rc = sqlite3Stat4Column(db, p->aSample[i].p, p->aSample[i].n, nEq, &pVal); + if( rc==SQLITE_OK && p1 ){ + int res = sqlite3MemCompare(p1, pVal, pColl); + if( res>=0 ) nLower++; + } + if( rc==SQLITE_OK && p2 ){ + int res = sqlite3MemCompare(p2, pVal, pColl); + if( res>=0 ) nUpper++; + } + } + nDiff = (nUpper - nLower); + if( nDiff<=0 ) nDiff = 1; + + /* If there is both an upper and lower bound specified, and the + ** comparisons indicate that they are close together, use the fallback + ** method (assume that the scan visits 1/64 of the rows) for estimating + ** the number of rows visited. Otherwise, estimate the number of rows + ** using the method described in the header comment for this function. */ + if( nDiff!=1 || pUpper==0 || pLower==0 ){ + int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff)); + pLoop->nOut -= nAdjust; + *pbDone = 1; + WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n", + nLower, nUpper, nAdjust*-1, pLoop->nOut)); + } + + }else{ + assert( *pbDone==0 ); + } + + sqlite3ValueFree(p1); + sqlite3ValueFree(p2); + sqlite3ValueFree(pVal); + + return rc; +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + +/* +** This function is used to estimate the number of rows that will be visited +** by scanning an index for a range of values. The range may have an upper +** bound, a lower bound, or both. The WHERE clause terms that set the upper +** and lower bounds are represented by pLower and pUpper respectively. For +** example, assuming that index p is on t1(a): +** +** ... FROM t1 WHERE a > ? AND a < ? ... +** |_____| |_____| +** | | +** pLower pUpper +** +** If either of the upper or lower bound is not present, then NULL is passed in +** place of the corresponding WhereTerm. +** +** The value in (pBuilder->pNew->u.btree.nEq) is the number of the index +** column subject to the range constraint. Or, equivalently, the number of +** equality constraints optimized by the proposed index scan. For example, +** assuming index p is on t1(a, b), and the SQL query is: +** +** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ... +** +** then nEq is set to 1 (as the range restricted column, b, is the second +** left-most column of the index). Or, if the query is: +** +** ... FROM t1 WHERE a > ? AND a < ? ... +** +** then nEq is set to 0. +** +** When this function is called, *pnOut is set to the sqlite3LogEst() of the +** number of rows that the index scan is expected to visit without +** considering the range constraints. If nEq is 0, then *pnOut is the number of +** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced) +** to account for the range constraints pLower and pUpper. +** +** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be +** used, a single range inequality reduces the search space by a factor of 4. +** and a pair of constraints (x>? AND x123" Might be NULL */ + WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ + WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */ +){ + int rc = SQLITE_OK; + int nOut = pLoop->nOut; + LogEst nNew; + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + Index *p = pLoop->u.btree.pIndex; + int nEq = pLoop->u.btree.nEq; + + if( p->nSample>0 && nEqnSampleCol ){ + if( nEq==pBuilder->nRecValid ){ + UnpackedRecord *pRec = pBuilder->pRec; + tRowcnt a[2]; + int nBtm = pLoop->u.btree.nBtm; + int nTop = pLoop->u.btree.nTop; + + /* Variable iLower will be set to the estimate of the number of rows in + ** the index that are less than the lower bound of the range query. The + ** lower bound being the concatenation of $P and $L, where $P is the + ** key-prefix formed by the nEq values matched against the nEq left-most + ** columns of the index, and $L is the value in pLower. + ** + ** Or, if pLower is NULL or $L cannot be extracted from it (because it + ** is not a simple variable or literal value), the lower bound of the + ** range is $P. Due to a quirk in the way whereKeyStats() works, even + ** if $L is available, whereKeyStats() is called for both ($P) and + ** ($P:$L) and the larger of the two returned values is used. + ** + ** Similarly, iUpper is to be set to the estimate of the number of rows + ** less than the upper bound of the range query. Where the upper bound + ** is either ($P) or ($P:$U). Again, even if $U is available, both values + ** of iUpper are requested of whereKeyStats() and the smaller used. + ** + ** The number of rows between the two bounds is then just iUpper-iLower. + */ + tRowcnt iLower; /* Rows less than the lower bound */ + tRowcnt iUpper; /* Rows less than the upper bound */ + int iLwrIdx = -2; /* aSample[] for the lower bound */ + int iUprIdx = -1; /* aSample[] for the upper bound */ + + if( pRec ){ + testcase( pRec->nField!=pBuilder->nRecValid ); + pRec->nField = pBuilder->nRecValid; + } + /* Determine iLower and iUpper using ($P) only. */ + if( nEq==0 ){ + iLower = 0; + iUpper = p->nRowEst0; + }else{ + /* Note: this call could be optimized away - since the same values must + ** have been requested when testing key $P in whereEqualScanEst(). */ + whereKeyStats(pParse, p, pRec, 0, a); + iLower = a[0]; + iUpper = a[0] + a[1]; + } + + assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 ); + assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); + assert( p->aSortOrder!=0 ); + if( p->aSortOrder[nEq] ){ + /* The roles of pLower and pUpper are swapped for a DESC index */ + SWAP(WhereTerm*, pLower, pUpper); + SWAP(int, nBtm, nTop); + } + + /* If possible, improve on the iLower estimate using ($P:$L). */ + if( pLower ){ + int n; /* Values extracted from pExpr */ + Expr *pExpr = pLower->pExpr->pRight; + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n); + if( rc==SQLITE_OK && n ){ + tRowcnt iNew; + u16 mask = WO_GT|WO_LE; + if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); + iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a); + iNew = a[0] + ((pLower->eOperator & mask) ? a[1] : 0); + if( iNew>iLower ) iLower = iNew; + nOut--; + pLower = 0; + } + } + + /* If possible, improve on the iUpper estimate using ($P:$U). */ + if( pUpper ){ + int n; /* Values extracted from pExpr */ + Expr *pExpr = pUpper->pExpr->pRight; + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n); + if( rc==SQLITE_OK && n ){ + tRowcnt iNew; + u16 mask = WO_GT|WO_LE; + if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); + iUprIdx = whereKeyStats(pParse, p, pRec, 1, a); + iNew = a[0] + ((pUpper->eOperator & mask) ? a[1] : 0); + if( iNewpRec = pRec; + if( rc==SQLITE_OK ){ + if( iUpper>iLower ){ + nNew = sqlite3LogEst(iUpper - iLower); + /* TUNING: If both iUpper and iLower are derived from the same + ** sample, then assume they are 4x more selective. This brings + ** the estimated selectivity more in line with what it would be + ** if estimated without the use of STAT3/4 tables. */ + if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); + }else{ + nNew = 10; assert( 10==sqlite3LogEst(2) ); + } + if( nNewwtFlags & TERM_VNULL)==0 ); + nNew = whereRangeAdjust(pLower, nOut); + nNew = whereRangeAdjust(pUpper, nNew); + + /* TUNING: If there is both an upper and lower limit and neither limit + ** has an application-defined likelihood(), assume the range is + ** reduced by an additional 75%. This means that, by default, an open-ended + ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the + ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to + ** match 1/64 of the index. */ + if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){ + nNew -= 20; + } + + nOut -= (pLower!=0) + (pUpper!=0); + if( nNew<10 ) nNew = 10; + if( nNewnOut>nOut ){ + WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n", + pLoop->nOut, nOut)); + } +#endif + pLoop->nOut = (LogEst)nOut; + return rc; +} + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** Estimate the number of rows that will be returned based on +** an equality constraint x=VALUE and where that VALUE occurs in +** the histogram data. This only works when x is the left-most +** column of an index and sqlite_stat3 histogram data is available +** for that index. When pExpr==NULL that means the constraint is +** "x IS NULL" instead of "x=VALUE". +** +** Write the estimated row count into *pnRow and return SQLITE_OK. +** If unable to make an estimate, leave *pnRow unchanged and return +** non-zero. +** +** This routine can fail if it is unable to load a collating sequence +** required for string comparison, or if unable to allocate memory +** for a UTF conversion required for comparison. The error is stored +** in the pParse structure. +*/ +static int whereEqualScanEst( + Parse *pParse, /* Parsing & code generating context */ + WhereLoopBuilder *pBuilder, + Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ + tRowcnt *pnRow /* Write the revised row estimate here */ +){ + Index *p = pBuilder->pNew->u.btree.pIndex; + int nEq = pBuilder->pNew->u.btree.nEq; + UnpackedRecord *pRec = pBuilder->pRec; + int rc; /* Subfunction return code */ + tRowcnt a[2]; /* Statistics */ + int bOk; + + assert( nEq>=1 ); + assert( nEq<=p->nColumn ); + assert( p->aSample!=0 ); + assert( p->nSample>0 ); + assert( pBuilder->nRecValidnRecValid<(nEq-1) ){ + return SQLITE_NOTFOUND; + } + + /* This is an optimization only. The call to sqlite3Stat4ProbeSetValue() + ** below would return the same value. */ + if( nEq>=p->nColumn ){ + *pnRow = 1; + return SQLITE_OK; + } + + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk); + pBuilder->pRec = pRec; + if( rc!=SQLITE_OK ) return rc; + if( bOk==0 ) return SQLITE_NOTFOUND; + pBuilder->nRecValid = nEq; + + whereKeyStats(pParse, p, pRec, 0, a); + WHERETRACE(0x10,("equality scan regions %s(%d): %d\n", + p->zName, nEq-1, (int)a[1])); + *pnRow = a[1]; + + return rc; +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +/* +** Estimate the number of rows that will be returned based on +** an IN constraint where the right-hand side of the IN operator +** is a list of values. Example: +** +** WHERE x IN (1,2,3,4) +** +** Write the estimated row count into *pnRow and return SQLITE_OK. +** If unable to make an estimate, leave *pnRow unchanged and return +** non-zero. +** +** This routine can fail if it is unable to load a collating sequence +** required for string comparison, or if unable to allocate memory +** for a UTF conversion required for comparison. The error is stored +** in the pParse structure. +*/ +static int whereInScanEst( + Parse *pParse, /* Parsing & code generating context */ + WhereLoopBuilder *pBuilder, + ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ + tRowcnt *pnRow /* Write the revised row estimate here */ +){ + Index *p = pBuilder->pNew->u.btree.pIndex; + i64 nRow0 = sqlite3LogEstToInt(p->aiRowLogEst[0]); + int nRecValid = pBuilder->nRecValid; + int rc = SQLITE_OK; /* Subfunction return code */ + tRowcnt nEst; /* Number of rows for a single term */ + tRowcnt nRowEst = 0; /* New estimate of the number of rows */ + int i; /* Loop counter */ + + assert( p->aSample!=0 ); + for(i=0; rc==SQLITE_OK && inExpr; i++){ + nEst = nRow0; + rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst); + nRowEst += nEst; + pBuilder->nRecValid = nRecValid; + } + + if( rc==SQLITE_OK ){ + if( nRowEst > nRow0 ) nRowEst = nRow0; + *pnRow = nRowEst; + WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst)); + } + assert( pBuilder->nRecValid==nRecValid ); + return rc; +} +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + + +#ifdef WHERETRACE_ENABLED +/* +** Print the content of a WhereTerm object +*/ +static void whereTermPrint(WhereTerm *pTerm, int iTerm){ + if( pTerm==0 ){ + sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); + }else{ + char zType[4]; + char zLeft[50]; + memcpy(zType, "...", 4); + if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; + if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + if( pTerm->eOperator & WO_SINGLE ){ + sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", + pTerm->leftCursor, pTerm->u.leftColumn); + }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ + sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", + pTerm->u.pOrInfo->indexable); + }else{ + sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); + } + sqlite3DebugPrintf( + "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x", + iTerm, pTerm, zType, zLeft, pTerm->truthProb, + pTerm->eOperator, pTerm->wtFlags); + if( pTerm->iField ){ + sqlite3DebugPrintf(" iField=%d\n", pTerm->iField); + }else{ + sqlite3DebugPrintf("\n"); + } + sqlite3TreeViewExpr(0, pTerm->pExpr, 0); + } +} +#endif + +#ifdef WHERETRACE_ENABLED +/* +** Show the complete content of a WhereClause +*/ +SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ + int i; + for(i=0; inTerm; i++){ + whereTermPrint(&pWC->a[i], i); + } +} +#endif + +#ifdef WHERETRACE_ENABLED +/* +** Print a WhereLoop object for debugging purposes +*/ +static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ + WhereInfo *pWInfo = pWC->pWInfo; + int nb = 1+(pWInfo->pTabList->nSrc+3)/4; + struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab; + Table *pTab = pItem->pTab; + Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; + sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, + p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); + sqlite3DebugPrintf(" %12s", + pItem->zAlias ? pItem->zAlias : pTab->zName); + if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + const char *zName; + if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ + if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ + int i = sqlite3Strlen30(zName) - 1; + while( zName[i]!='_' ) i--; + zName += i; + } + sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq); + }else{ + sqlite3DebugPrintf("%20s",""); + } + }else{ + char *z; + if( p->u.vtab.idxStr ){ + z = sqlite3_mprintf("(%d,\"%s\",%x)", + p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask); + }else{ + z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask); + } + sqlite3DebugPrintf(" %-19s", z); + sqlite3_free(z); + } + if( p->wsFlags & WHERE_SKIPSCAN ){ + sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); + }else{ + sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); + } + sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); + if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ + int i; + for(i=0; inLTerm; i++){ + whereTermPrint(p->aLTerm[i], i); + } + } +} +#endif + +/* +** Convert bulk memory into a valid WhereLoop that can be passed +** to whereLoopClear harmlessly. +*/ +static void whereLoopInit(WhereLoop *p){ + p->aLTerm = p->aLTermSpace; + p->nLTerm = 0; + p->nLSlot = ArraySize(p->aLTermSpace); + p->wsFlags = 0; +} + +/* +** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. +*/ +static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ + if( p->wsFlags & (WHERE_VIRTUALTABLE|WHERE_AUTO_INDEX) ){ + if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 && p->u.vtab.needFree ){ + sqlite3_free(p->u.vtab.idxStr); + p->u.vtab.needFree = 0; + p->u.vtab.idxStr = 0; + }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ + sqlite3DbFree(db, p->u.btree.pIndex->zColAff); + sqlite3DbFreeNN(db, p->u.btree.pIndex); + p->u.btree.pIndex = 0; + } + } +} + +/* +** Deallocate internal memory used by a WhereLoop object +*/ +static void whereLoopClear(sqlite3 *db, WhereLoop *p){ + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); + whereLoopClearUnion(db, p); + whereLoopInit(p); +} + +/* +** Increase the memory allocation for pLoop->aLTerm[] to be at least n. +*/ +static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ + WhereTerm **paNew; + if( p->nLSlot>=n ) return SQLITE_OK; + n = (n+7)&~7; + paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n); + if( paNew==0 ) return SQLITE_NOMEM_BKPT; + memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); + p->aLTerm = paNew; + p->nLSlot = n; + return SQLITE_OK; +} + +/* +** Transfer content from the second pLoop into the first. +*/ +static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ + whereLoopClearUnion(db, pTo); + if( whereLoopResize(db, pTo, pFrom->nLTerm) ){ + memset(&pTo->u, 0, sizeof(pTo->u)); + return SQLITE_NOMEM_BKPT; + } + memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); + memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); + if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ + pFrom->u.vtab.needFree = 0; + }else if( (pFrom->wsFlags & WHERE_AUTO_INDEX)!=0 ){ + pFrom->u.btree.pIndex = 0; + } + return SQLITE_OK; +} + +/* +** Delete a WhereLoop object +*/ +static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ + whereLoopClear(db, p); + sqlite3DbFreeNN(db, p); +} + +/* +** Free a WhereInfo structure +*/ +static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ + if( ALWAYS(pWInfo) ){ + int i; + for(i=0; inLevel; i++){ + WhereLevel *pLevel = &pWInfo->a[i]; + if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){ + sqlite3DbFree(db, pLevel->u.in.aInLoop); + } + } + sqlite3WhereClauseClear(&pWInfo->sWC); + while( pWInfo->pLoops ){ + WhereLoop *p = pWInfo->pLoops; + pWInfo->pLoops = p->pNextLoop; + whereLoopDelete(db, p); + } + sqlite3DbFreeNN(db, 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. +** +** 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 +** 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. +*/ +static int whereLoopCheaperProperSubset( + const WhereLoop *pX, /* First WhereLoop to compare */ + const WhereLoop *pY /* Compare against this WhereLoop */ +){ + int i, j; + if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ + return 0; /* X is not a subset of Y */ + } + if( pY->nSkip > pX->nSkip ) return 0; + if( pX->rRun >= pY->rRun ){ + if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ + if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ + } + for(i=pX->nLTerm-1; i>=0; i--){ + if( pX->aLTerm[i]==0 ) continue; + for(j=pY->nLTerm-1; j>=0; j--){ + if( pY->aLTerm[j]==pX->aLTerm[i] ) break; + } + if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ + } + return 1; /* All conditions meet */ +} + +/* +** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so +** that: +** +** (1) pTemplate costs less than any other WhereLoops that are a proper +** subset of pTemplate +** +** (2) pTemplate costs more than any other WhereLoops for which pTemplate +** is a proper subset. +** +** To say "WhereLoop X is a proper subset of Y" means that X uses fewer +** WHERE clause terms than Y and that every WHERE clause term used by X is +** also used by Y. +*/ +static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ + if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; + for(; p; p=p->pNextLoop){ + if( p->iTab!=pTemplate->iTab ) continue; + if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; + if( whereLoopCheaperProperSubset(p, pTemplate) ){ + /* Adjust pTemplate cost downward so that it is cheaper than its + ** subset p. */ + WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", + pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1)); + pTemplate->rRun = p->rRun; + pTemplate->nOut = p->nOut - 1; + }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ + /* Adjust pTemplate cost upward so that it is costlier than p since + ** pTemplate is a proper subset of p */ + WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", + pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1)); + pTemplate->rRun = p->rRun; + pTemplate->nOut = p->nOut + 1; + } + } +} + +/* +** Search the list of WhereLoops in *ppPrev looking for one that can be +** supplanted by pTemplate. +** +** Return NULL if the WhereLoop list contains an entry that can supplant +** pTemplate, in other words if pTemplate does not belong on the list. +** +** If pX is a WhereLoop that pTemplate can supplant, then return the +** link that points to pX. +** +** If pTemplate cannot supplant any existing element of the list but needs +** to be added to the list, then return a pointer to the tail of the list. +*/ +static WhereLoop **whereLoopFindLesser( + WhereLoop **ppPrev, + const WhereLoop *pTemplate +){ + WhereLoop *p; + for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){ + if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){ + /* If either the iTab or iSortIdx values for two WhereLoop are different + ** then those WhereLoops need to be considered separately. Neither is + ** a candidate to replace the other. */ + continue; + } + /* In the current implementation, the rSetup value is either zero + ** or the cost of building an automatic index (NlogN) and the NlogN + ** is the same for compatible WhereLoops. */ + assert( p->rSetup==0 || pTemplate->rSetup==0 + || p->rSetup==pTemplate->rSetup ); + + /* whereLoopAddBtree() always generates and inserts the automatic index + ** case first. Hence compatible candidate WhereLoops never have a larger + ** rSetup. Call this SETUP-INVARIANT */ + assert( p->rSetup>=pTemplate->rSetup ); + + /* Any loop using an appliation-defined index (or PRIMARY KEY or + ** UNIQUE constraint) with one or more == constraints is better + ** than an automatic index. Unless it is a skip-scan. */ + if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 + && (pTemplate->nSkip)==0 + && (pTemplate->wsFlags & WHERE_INDEXED)!=0 + && (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0 + && (p->prereq & pTemplate->prereq)==pTemplate->prereq + ){ + break; + } + + /* If existing WhereLoop p is better than pTemplate, pTemplate can be + ** discarded. WhereLoop p is better if: + ** (1) p has no more dependencies than pTemplate, and + ** (2) p has an equal or lower cost than pTemplate + */ + if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */ + && p->rSetup<=pTemplate->rSetup /* (2a) */ + && p->rRun<=pTemplate->rRun /* (2b) */ + && p->nOut<=pTemplate->nOut /* (2c) */ + ){ + return 0; /* Discard pTemplate */ + } + + /* If pTemplate is always better than p, then cause p to be overwritten + ** with pTemplate. pTemplate is better than p if: + ** (1) pTemplate has no more dependences than p, and + ** (2) pTemplate has an equal or lower cost than p. + */ + if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */ + && p->rRun>=pTemplate->rRun /* (2a) */ + && p->nOut>=pTemplate->nOut /* (2b) */ + ){ + assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */ + break; /* Cause p to be overwritten by pTemplate */ + } + } + return ppPrev; +} + +/* +** Insert or replace a WhereLoop entry using the template supplied. +** +** An existing WhereLoop entry might be overwritten if the new template +** is better and has fewer dependencies. Or the template will be ignored +** and no insert will occur if an existing WhereLoop is faster and has +** fewer dependencies than the template. Otherwise a new WhereLoop is +** added based on the template. +** +** If pBuilder->pOrSet is not NULL then we care about only the +** prerequisites and rRun and nOut costs of the N best loops. That +** information is gathered in the pBuilder->pOrSet object. This special +** processing mode is used only for OR clause processing. +** +** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we +** still might overwrite similar loops with the new template if the +** new template is better. Loops may be overwritten if the following +** conditions are met: +** +** (1) They have the same iTab. +** (2) They have the same iSortIdx. +** (3) The template has same or fewer dependencies than the current loop +** (4) The template has the same or lower cost than the current loop +*/ +static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ + WhereLoop **ppPrev, *p; + WhereInfo *pWInfo = pBuilder->pWInfo; + sqlite3 *db = pWInfo->pParse->db; + int rc; + + /* If pBuilder->pOrSet is defined, then only keep track of the costs + ** and prereqs. + */ + if( pBuilder->pOrSet!=0 ){ + if( pTemplate->nLTerm ){ +#if WHERETRACE_ENABLED + u16 n = pBuilder->pOrSet->n; + int x = +#endif + whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun, + pTemplate->nOut); +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n); + whereLoopPrint(pTemplate, pBuilder->pWC); + } +#endif + } + return SQLITE_OK; + } + + /* Look for an existing WhereLoop to replace with pTemplate + */ + whereLoopAdjustCost(pWInfo->pLoops, pTemplate); + ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); + + if( ppPrev==0 ){ + /* There already exists a WhereLoop on the list that is better + ** than pTemplate, so just ignore pTemplate */ +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf(" skip: "); + whereLoopPrint(pTemplate, pBuilder->pWC); + } +#endif + return SQLITE_OK; + }else{ + p = *ppPrev; + } + + /* If we reach this point it means that either p[] should be overwritten + ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new + ** WhereLoop and insert it. + */ +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + if( p!=0 ){ + sqlite3DebugPrintf("replace: "); + whereLoopPrint(p, pBuilder->pWC); + } + sqlite3DebugPrintf(" add: "); + whereLoopPrint(pTemplate, pBuilder->pWC); + } +#endif + if( p==0 ){ + /* Allocate a new WhereLoop to add to the end of the list */ + *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop)); + if( p==0 ) return SQLITE_NOMEM_BKPT; + whereLoopInit(p); + p->pNextLoop = 0; + }else{ + /* We will be overwriting WhereLoop p[]. But before we do, first + ** go through the rest of the list and delete any other entries besides + ** p[] that are also supplated by pTemplate */ + WhereLoop **ppTail = &p->pNextLoop; + WhereLoop *pToDel; + while( *ppTail ){ + ppTail = whereLoopFindLesser(ppTail, pTemplate); + if( ppTail==0 ) break; + pToDel = *ppTail; + if( pToDel==0 ) break; + *ppTail = pToDel->pNextLoop; +#if WHERETRACE_ENABLED /* 0x8 */ + if( sqlite3WhereTrace & 0x8 ){ + sqlite3DebugPrintf(" delete: "); + whereLoopPrint(pToDel, pBuilder->pWC); + } +#endif + whereLoopDelete(db, pToDel); + } + } + rc = whereLoopXfer(db, p, pTemplate); + if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + Index *pIndex = p->u.btree.pIndex; + if( pIndex && pIndex->tnum==0 ){ + p->u.btree.pIndex = 0; + } + } + return rc; +} + +/* +** Adjust the WhereLoop.nOut value downward to account for terms of the +** WHERE clause that reference the loop but which are not used by an +** index. +* +** For every WHERE clause term that is not used by the index +** and which has a truth probability assigned by one of the likelihood(), +** likely(), or unlikely() SQL functions, reduce the estimated number +** of output rows by the probability specified. +** +** TUNING: For every WHERE clause term that is not used by the index +** and which does not have an assigned truth probability, heuristics +** described below are used to try to estimate the truth probability. +** TODO --> Perhaps this is something that could be improved by better +** table statistics. +** +** Heuristic 1: Estimate the truth probability as 93.75%. The 93.75% +** value corresponds to -1 in LogEst notation, so this means decrement +** the WhereLoop.nOut field for every such WHERE clause term. +** +** Heuristic 2: If there exists one or more WHERE clause terms of the +** form "x==EXPR" and EXPR is not a constant 0 or 1, then make sure the +** final output row estimate is no greater than 1/4 of the total number +** of rows in the table. In other words, assume that x==EXPR will filter +** out at least 3 out of 4 rows. If EXPR is -1 or 0 or 1, then maybe the +** "x" column is boolean or else -1 or 0 or 1 is a common default value +** on the "x" column and so in that case only cap the output row estimate +** at 1/2 instead of 1/4. +*/ +static void whereLoopOutputAdjust( + WhereClause *pWC, /* The WHERE clause */ + WhereLoop *pLoop, /* The loop to adjust downward */ + LogEst nRow /* Number of rows in the entire table */ +){ + WhereTerm *pTerm, *pX; + Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); + int i, j, k; + LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ + + assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); + for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){ + if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break; + if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; + if( (pTerm->prereqAll & notAllowed)!=0 ) continue; + for(j=pLoop->nLTerm-1; j>=0; j--){ + pX = pLoop->aLTerm[j]; + if( pX==0 ) continue; + if( pX==pTerm ) break; + if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; + } + if( j<0 ){ + if( pTerm->truthProb<=0 ){ + /* If a truth probability is specified using the likelihood() hints, + ** then use the probability provided by the application. */ + pLoop->nOut += pTerm->truthProb; + }else{ + /* In the absence of explicit truth probabilities, use heuristics to + ** guess a reasonable truth probability. */ + pLoop->nOut--; + if( pTerm->eOperator&(WO_EQ|WO_IS) ){ + Expr *pRight = pTerm->pExpr->pRight; + testcase( pTerm->pExpr->op==TK_IS ); + if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){ + k = 10; + }else{ + k = 20; + } + if( iReducenOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce; +} + +/* +** Term pTerm is a vector range comparison operation. The first comparison +** in the vector can be optimized using column nEq of the index. This +** function returns the total number of vector elements that can be used +** as part of the range comparison. +** +** For example, if the query is: +** +** WHERE a = ? AND (b, c, d) > (?, ?, ?) +** +** and the index: +** +** CREATE INDEX ... ON (a, b, c, d, e) +** +** then this function would be invoked with nEq=1. The value returned in +** this case is 3. +*/ +static int whereRangeVectorLen( + Parse *pParse, /* Parsing context */ + int iCur, /* Cursor open on pIdx */ + Index *pIdx, /* The index to be used for a inequality constraint */ + int nEq, /* Number of prior equality constraints on same index */ + WhereTerm *pTerm /* The vector inequality constraint */ +){ + int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft); + int i; + + nCmp = MIN(nCmp, (pIdx->nColumn - nEq)); + for(i=1; ipExpr->pLeft->x.pList->a[i].pExpr; + Expr *pRhs = pTerm->pExpr->pRight; + if( pRhs->flags & EP_xIsSelect ){ + pRhs = pRhs->x.pSelect->pEList->a[i].pExpr; + }else{ + pRhs = pRhs->x.pList->a[i].pExpr; + } + + /* Check that the LHS of the comparison is a column reference to + ** the right column of the right source table. And that the sort + ** order of the index column is the same as the sort order of the + ** leftmost index column. */ + if( pLhs->op!=TK_COLUMN + || pLhs->iTable!=iCur + || pLhs->iColumn!=pIdx->aiColumn[i+nEq] + || pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq] + ){ + break; + } + + testcase( pLhs->iColumn==XN_ROWID ); + aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs)); + idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn); + if( aff!=idxaff ) break; + + pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); + if( pColl==0 ) break; + if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break; + } + return i; +} + +/* +** Adjust the cost C by the costMult facter T. This only occurs if +** compiled with -DSQLITE_ENABLE_COSTMULT +*/ +#ifdef SQLITE_ENABLE_COSTMULT +# define ApplyCostMultiplier(C,T) C += T +#else +# define ApplyCostMultiplier(C,T) +#endif + +/* +** We have so far matched pBuilder->pNew->u.btree.nEq terms of the +** index pIndex. Try to match one more. +** +** When this function is called, pBuilder->pNew->nOut contains the +** number of rows expected to be visited by filtering using the nEq +** terms only. If it is modified, this value is restored before this +** function returns. +** +** If pProbe->tnum==0, that means pIndex is a fake index used for the +** INTEGER PRIMARY KEY. +*/ +static int whereLoopAddBtreeIndex( + WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ + struct SrcList_item *pSrc, /* FROM clause term being analyzed */ + Index *pProbe, /* An index on pSrc */ + LogEst nInMul /* log(Number of iterations due to IN) */ +){ + WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */ + Parse *pParse = pWInfo->pParse; /* Parsing context */ + sqlite3 *db = pParse->db; /* Database connection malloc context */ + WhereLoop *pNew; /* Template WhereLoop under construction */ + WhereTerm *pTerm; /* A WhereTerm under consideration */ + int opMask; /* Valid operators for constraints */ + WhereScan scan; /* Iterator for WHERE terms */ + Bitmask saved_prereq; /* Original value of pNew->prereq */ + u16 saved_nLTerm; /* Original value of pNew->nLTerm */ + u16 saved_nEq; /* Original value of pNew->u.btree.nEq */ + u16 saved_nBtm; /* Original value of pNew->u.btree.nBtm */ + u16 saved_nTop; /* Original value of pNew->u.btree.nTop */ + u16 saved_nSkip; /* Original value of pNew->nSkip */ + u32 saved_wsFlags; /* Original value of pNew->wsFlags */ + LogEst saved_nOut; /* Original value of pNew->nOut */ + int rc = SQLITE_OK; /* Return code */ + LogEst rSize; /* Number of rows in the table */ + LogEst rLogSize; /* Logarithm of table size */ + WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ + + pNew = pBuilder->pNew; + if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; + WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n", + pProbe->zName, pNew->u.btree.nEq)); + + assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); + assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); + if( pNew->wsFlags & WHERE_BTM_LIMIT ){ + opMask = WO_LT|WO_LE; + }else{ + assert( pNew->u.btree.nBtm==0 ); + opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; + } + if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); + + assert( pNew->u.btree.nEqnColumn ); + + saved_nEq = pNew->u.btree.nEq; + saved_nBtm = pNew->u.btree.nBtm; + saved_nTop = pNew->u.btree.nTop; + saved_nSkip = pNew->nSkip; + saved_nLTerm = pNew->nLTerm; + saved_wsFlags = pNew->wsFlags; + saved_prereq = pNew->prereq; + saved_nOut = pNew->nOut; + pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, saved_nEq, + opMask, pProbe); + pNew->rSetup = 0; + rSize = pProbe->aiRowLogEst[0]; + rLogSize = estLog(rSize); + for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ + u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ + LogEst rCostIdx; + LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ + int nIn = 0; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + int nRecValid = pBuilder->nRecValid; +#endif + if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) + && indexColumnNotNull(pProbe, saved_nEq) + ){ + continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ + } + if( pTerm->prereqRight & pNew->maskSelf ) continue; + + /* Do not allow the upper bound of a LIKE optimization range constraint + ** to mix with a lower range bound from some other source */ + if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; + + /* Do not allow IS constraints from the WHERE clause to be used by the + ** right table of a LEFT JOIN. Only constraints in the ON clause are + ** allowed */ + if( (pSrc->fg.jointype & JT_LEFT)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (eOp & (WO_IS|WO_ISNULL))!=0 + ){ + testcase( eOp & WO_IS ); + testcase( eOp & WO_ISNULL ); + continue; + } + + if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){ + pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE; + }else{ + pBuilder->bldFlags |= SQLITE_BLDF_INDEXED; + } + pNew->wsFlags = saved_wsFlags; + pNew->u.btree.nEq = saved_nEq; + pNew->u.btree.nBtm = saved_nBtm; + pNew->u.btree.nTop = saved_nTop; + pNew->nLTerm = saved_nLTerm; + if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ + pNew->aLTerm[pNew->nLTerm++] = pTerm; + pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; + + assert( nInMul==0 + || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 + || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 + || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 + ); + + if( eOp & WO_IN ){ + Expr *pExpr = pTerm->pExpr; + pNew->wsFlags |= WHERE_COLUMN_IN; + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ + int i; + nIn = 46; assert( 46==sqlite3LogEst(25) ); + + /* The expression may actually be of the form (x, y) IN (SELECT...). + ** In this case there is a separate term for each of (x) and (y). + ** However, the nIn multiplier should only be applied once, not once + ** for each such term. The following loop checks that pTerm is the + ** first such term in use, and sets nIn back to 0 if it is not. */ + for(i=0; inLTerm-1; i++){ + if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; + } + }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ + /* "x IN (value, value, ...)" */ + nIn = sqlite3LogEst(pExpr->x.pList->nExpr); + assert( nIn>0 ); /* RHS always has 2 or more terms... The parser + ** changes "x IN (?)" into "x=?". */ + } + }else if( eOp & (WO_EQ|WO_IS) ){ + int iCol = pProbe->aiColumn[saved_nEq]; + pNew->wsFlags |= WHERE_COLUMN_EQ; + assert( saved_nEq==pNew->u.btree.nEq ); + if( iCol==XN_ROWID + || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) + ){ + if( iCol>=0 && pProbe->uniqNotNull==0 ){ + pNew->wsFlags |= WHERE_UNQ_WANTED; + }else{ + pNew->wsFlags |= WHERE_ONEROW; + } + } + }else if( eOp & WO_ISNULL ){ + pNew->wsFlags |= WHERE_COLUMN_NULL; + }else if( eOp & (WO_GT|WO_GE) ){ + testcase( eOp & WO_GT ); + testcase( eOp & WO_GE ); + pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT; + pNew->u.btree.nBtm = whereRangeVectorLen( + pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm + ); + pBtm = pTerm; + pTop = 0; + if( pTerm->wtFlags & TERM_LIKEOPT ){ + /* Range contraints that come from the LIKE optimization are + ** always used in pairs. */ + pTop = &pTerm[1]; + assert( (pTop-(pTerm->pWC->a))pWC->nTerm ); + assert( pTop->wtFlags & TERM_LIKEOPT ); + assert( pTop->eOperator==WO_LT ); + if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ + pNew->aLTerm[pNew->nLTerm++] = pTop; + pNew->wsFlags |= WHERE_TOP_LIMIT; + pNew->u.btree.nTop = 1; + } + }else{ + assert( eOp & (WO_LT|WO_LE) ); + testcase( eOp & WO_LT ); + testcase( eOp & WO_LE ); + pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; + pNew->u.btree.nTop = whereRangeVectorLen( + pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm + ); + pTop = pTerm; + pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? + pNew->aLTerm[pNew->nLTerm-2] : 0; + } + + /* At this point pNew->nOut is set to the number of rows expected to + ** be visited by the index scan before considering term pTerm, or the + ** values of nIn and nInMul. In other words, assuming that all + ** "x IN(...)" terms are replaced with "x = ?". This block updates + ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ + assert( pNew->nOut==saved_nOut ); + if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ + /* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4 + ** data, using some other estimate. */ + whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); + }else{ + int nEq = ++pNew->u.btree.nEq; + assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) ); + + assert( pNew->nOut==saved_nOut ); + if( pTerm->truthProb<=0 && pProbe->aiColumn[saved_nEq]>=0 ){ + assert( (eOp & WO_IN) || nIn==0 ); + testcase( eOp & WO_IN ); + pNew->nOut += pTerm->truthProb; + pNew->nOut -= nIn; + }else{ +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + tRowcnt nOut = 0; + if( nInMul==0 + && pProbe->nSample + && pNew->u.btree.nEq<=pProbe->nSampleCol + && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) + ){ + Expr *pExpr = pTerm->pExpr; + if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ + testcase( eOp & WO_EQ ); + testcase( eOp & WO_IS ); + testcase( eOp & WO_ISNULL ); + rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); + }else{ + rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut); + } + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; + if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */ + if( nOut ){ + pNew->nOut = sqlite3LogEst(nOut); + if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; + pNew->nOut -= nIn; + } + } + if( nOut==0 ) +#endif + { + pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]); + if( eOp & WO_ISNULL ){ + /* TUNING: If there is no likelihood() value, assume that a + ** "col IS NULL" expression matches twice as many rows + ** as (col=?). */ + pNew->nOut += 10; + } + } + } + } + + /* Set rCostIdx to the cost of visiting selected rows in index. Add + ** it to pNew->rRun, which is currently set to the cost of the index + ** seek only. Then, if this is a non-covering index, add the cost of + ** visiting the rows in the main table. */ + rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; + pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); + if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); + } + ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); + + nOutUnadjusted = pNew->nOut; + pNew->rRun += nInMul + nIn; + pNew->nOut += nInMul + nIn; + whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize); + rc = whereLoopInsert(pBuilder, pNew); + + if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ + pNew->nOut = saved_nOut; + }else{ + pNew->nOut = nOutUnadjusted; + } + + if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 + && pNew->u.btree.nEqnColumn + ){ + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); + } + pNew->nOut = saved_nOut; +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + pBuilder->nRecValid = nRecValid; +#endif + } + pNew->prereq = saved_prereq; + pNew->u.btree.nEq = saved_nEq; + pNew->u.btree.nBtm = saved_nBtm; + pNew->u.btree.nTop = saved_nTop; + pNew->nSkip = saved_nSkip; + pNew->wsFlags = saved_wsFlags; + pNew->nOut = saved_nOut; + pNew->nLTerm = saved_nLTerm; + + /* Consider using a skip-scan if there are no WHERE clause constraints + ** available for the left-most terms of the index, and if the average + ** number of repeats in the left-most terms is at least 18. + ** + ** The magic number 18 is selected on the basis that scanning 17 rows + ** is almost always quicker than an index seek (even though if the index + ** contains fewer than 2^17 rows we assume otherwise in other parts of + ** the code). And, even if it is not, it should not be too much slower. + ** On the other hand, the extra seeks could end up being significantly + ** more expensive. */ + assert( 42==sqlite3LogEst(18) ); + if( saved_nEq==saved_nSkip + && saved_nEq+1nKeyCol + && pProbe->noSkipScan==0 + && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ + && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK + ){ + LogEst nIter; + pNew->u.btree.nEq++; + pNew->nSkip++; + pNew->aLTerm[pNew->nLTerm++] = 0; + pNew->wsFlags |= WHERE_SKIPSCAN; + nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; + pNew->nOut -= nIter; + /* TUNING: Because uncertainties in the estimates for skip-scan queries, + ** add a 1.375 fudge factor to make skip-scan slightly less likely. */ + nIter += 5; + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); + pNew->nOut = saved_nOut; + pNew->u.btree.nEq = saved_nEq; + pNew->nSkip = saved_nSkip; + pNew->wsFlags = saved_wsFlags; + } + + WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n", + pProbe->zName, saved_nEq, rc)); + return rc; +} + +/* +** Return True if it is possible that pIndex might be useful in +** implementing the ORDER BY clause in pBuilder. +** +** Return False if pBuilder does not contain an ORDER BY clause or +** if there is no way for pIndex to be useful in implementing that +** ORDER BY clause. +*/ +static int indexMightHelpWithOrderBy( + WhereLoopBuilder *pBuilder, + Index *pIndex, + int iCursor +){ + ExprList *pOB; + ExprList *aColExpr; + int ii, jj; + + if( pIndex->bUnordered ) return 0; + if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; + for(ii=0; iinExpr; ii++){ + Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); + if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ + if( pExpr->iColumn<0 ) return 1; + for(jj=0; jjnKeyCol; jj++){ + if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; + } + }else if( (aColExpr = pIndex->aColExpr)!=0 ){ + for(jj=0; jjnKeyCol; jj++){ + if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; + if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ + return 1; + } + } + } + } + return 0; +} + +/* +** Return a bitmask where 1s indicate that the corresponding column of +** the table is used by an index. Only the first 63 columns are considered. +*/ +static Bitmask columnsInIndex(Index *pIdx){ + Bitmask m = 0; + int j; + for(j=pIdx->nColumn-1; j>=0; j--){ + int x = pIdx->aiColumn[j]; + if( x>=0 ){ + testcase( x==BMS-1 ); + testcase( x==BMS-2 ); + if( xop==TK_AND ){ + if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0; + pWhere = pWhere->pRight; + } + for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ + Expr *pExpr = pTerm->pExpr; + if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) + && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) + ){ + return 1; + } + } + return 0; +} + +/* +** Add all WhereLoop objects for a single table of the join where the table +** is identified by pBuilder->pNew->iTab. That table is guaranteed to be +** a b-tree table, not a virtual table. +** +** The costs (WhereLoop.rRun) of the b-tree loops added by this function +** are calculated as follows: +** +** For a full scan, assuming the table (or index) contains nRow rows: +** +** cost = nRow * 3.0 // full-table scan +** cost = nRow * K // scan of covering index +** cost = nRow * (K+3.0) // scan of non-covering index +** +** where K is a value between 1.1 and 3.0 set based on the relative +** estimated average size of the index and table records. +** +** For an index scan, where nVisit is the number of index rows visited +** by the scan, and nSeek is the number of seek operations required on +** the index b-tree: +** +** cost = nSeek * (log(nRow) + K * nVisit) // covering index +** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index +** +** Normally, nSeek is 1. nSeek values greater than 1 come about if the +** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when +** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans. +** +** The estimated values (nRow, nVisit, nSeek) often contain a large amount +** of uncertainty. For this reason, scoring is designed to pick plans that +** "do the least harm" if the estimates are inaccurate. For example, a +** log(nRow) factor is omitted from a non-covering index scan in order to +** bias the scoring in favor of using an index, since the worst-case +** performance of using an index is far better than the worst-case performance +** of a full table scan. +*/ +static int whereLoopAddBtree( + WhereLoopBuilder *pBuilder, /* WHERE clause information */ + Bitmask mPrereq /* Extra prerequesites for using this table */ +){ + WhereInfo *pWInfo; /* WHERE analysis context */ + Index *pProbe; /* An index we are evaluating */ + Index sPk; /* A fake index object for the primary key */ + LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ + i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ + SrcList *pTabList; /* The FROM clause */ + struct SrcList_item *pSrc; /* The FROM clause btree term to add */ + WhereLoop *pNew; /* Template WhereLoop object */ + int rc = SQLITE_OK; /* Return code */ + int iSortIdx = 1; /* Index number */ + int b; /* A boolean value */ + LogEst rSize; /* number of rows in the table */ + LogEst rLogSize; /* Logarithm of the number of rows in the table */ + WhereClause *pWC; /* The parsed WHERE clause */ + Table *pTab; /* Table being queried */ + + pNew = pBuilder->pNew; + pWInfo = pBuilder->pWInfo; + pTabList = pWInfo->pTabList; + pSrc = pTabList->a + pNew->iTab; + pTab = pSrc->pTab; + pWC = pBuilder->pWC; + assert( !IsVirtual(pSrc->pTab) ); + + if( pSrc->pIBIndex ){ + /* An INDEXED BY clause specifies a particular index to use */ + pProbe = pSrc->pIBIndex; + }else if( !HasRowid(pTab) ){ + pProbe = pTab->pIndex; + }else{ + /* There is no INDEXED BY clause. Create a fake Index object in local + ** variable sPk to represent the rowid primary key index. Make this + ** fake index the first in a chain of Index objects with all of the real + ** indices to follow */ + Index *pFirst; /* First of real indices on the table */ + memset(&sPk, 0, sizeof(Index)); + sPk.nKeyCol = 1; + sPk.nColumn = 1; + sPk.aiColumn = &aiColumnPk; + sPk.aiRowLogEst = aiRowEstPk; + sPk.onError = OE_Replace; + sPk.pTable = pTab; + sPk.szIdxRow = pTab->szTabRow; + aiRowEstPk[0] = pTab->nRowLogEst; + aiRowEstPk[1] = 0; + pFirst = pSrc->pTab->pIndex; + if( pSrc->fg.notIndexed==0 ){ + /* The real indices of the table are only considered if the + ** NOT INDEXED qualifier is omitted from the FROM clause */ + sPk.pNext = pFirst; + } + pProbe = &sPk; + } + rSize = pTab->nRowLogEst; + rLogSize = estLog(rSize); + +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX + /* Automatic indexes */ + if( !pBuilder->pOrSet /* Not part of an OR optimization */ + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 + && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ + && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ + && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ + && !pSrc->fg.isCorrelated /* Not a correlated subquery */ + && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ + ){ + /* Generate auto-index WhereLoops */ + WhereTerm *pTerm; + WhereTerm *pWCEnd = pWC->a + pWC->nTerm; + for(pTerm=pWC->a; rc==SQLITE_OK && pTermprereqRight & pNew->maskSelf ) continue; + if( termCanDriveIndex(pTerm, pSrc, 0) ){ + pNew->u.btree.nEq = 1; + pNew->nSkip = 0; + pNew->u.btree.pIndex = 0; + pNew->nLTerm = 1; + pNew->aLTerm[0] = pTerm; + /* TUNING: One-time cost for computing the automatic index is + ** estimated to be X*N*log2(N) where N is the number of rows in + ** the table being indexed and where X is 7 (LogEst=28) for normal + ** tables or 1.375 (LogEst=4) for views and subqueries. The value + ** of X is smaller for views and subqueries so that the query planner + ** will be more aggressive about generating automatic indexes for + ** those objects, since there is no opportunity to add schema + ** indexes on subqueries and views. */ + pNew->rSetup = rLogSize + rSize + 4; + if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ + pNew->rSetup += 24; + } + ApplyCostMultiplier(pNew->rSetup, pTab->costMult); + if( pNew->rSetup<0 ) pNew->rSetup = 0; + /* TUNING: Each index lookup yields 20 rows in the table. This + ** is more than the usual guess of 10 rows, since we have no way + ** of knowing how selective the index will ultimately be. It would + ** not be unreasonable to make this value much larger. */ + pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); + pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); + pNew->wsFlags = WHERE_AUTO_INDEX; + pNew->prereq = mPrereq | pTerm->prereqRight; + rc = whereLoopInsert(pBuilder, pNew); + } + } + } +#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ + + /* Loop over all indices + */ + for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ + if( pProbe->pPartIdxWhere!=0 + && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){ + testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ + continue; /* Partial index inappropriate for this query */ + } + rSize = pProbe->aiRowLogEst[0]; + pNew->u.btree.nEq = 0; + pNew->u.btree.nBtm = 0; + pNew->u.btree.nTop = 0; + pNew->nSkip = 0; + pNew->nLTerm = 0; + pNew->iSortIdx = 0; + pNew->rSetup = 0; + pNew->prereq = mPrereq; + pNew->nOut = rSize; + pNew->u.btree.pIndex = pProbe; + b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); + /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ + assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 ); + if( pProbe->tnum<=0 ){ + /* Integer primary key index */ + pNew->wsFlags = WHERE_IPK; + + /* Full table scan */ + pNew->iSortIdx = b ? iSortIdx : 0; + /* TUNING: Cost of full table scan is (N*3.0). */ + pNew->rRun = rSize + 16; + ApplyCostMultiplier(pNew->rRun, pTab->costMult); + whereLoopOutputAdjust(pWC, pNew, rSize); + rc = whereLoopInsert(pBuilder, pNew); + pNew->nOut = rSize; + if( rc ) break; + }else{ + Bitmask m; + if( pProbe->isCovering ){ + pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; + m = 0; + }else{ + m = pSrc->colUsed & ~columnsInIndex(pProbe); + pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; + } + + /* Full scan via index */ + if( b + || !HasRowid(pTab) + || pProbe->pPartIdxWhere!=0 + || ( m==0 + && pProbe->bUnordered==0 + && (pProbe->szIdxRowszTabRow) + && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 + && sqlite3GlobalConfig.bUseCis + && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) + ) + ){ + pNew->iSortIdx = b ? iSortIdx : 0; + + /* The cost of visiting the index rows is N*K, where K is + ** between 1.1 and 3.0, depending on the relative sizes of the + ** index and table rows. */ + pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; + if( m!=0 ){ + /* If this is a non-covering index scan, add in the cost of + ** doing table lookups. The cost will be 3x the number of + ** lookups. Take into account WHERE clause terms that can be + ** satisfied using just the index, and that do not require a + ** table lookup. */ + LogEst nLookup = rSize + 16; /* Base cost: N*3 */ + int ii; + int iCur = pSrc->iCursor; + WhereClause *pWC2 = &pWInfo->sWC; + for(ii=0; iinTerm; ii++){ + WhereTerm *pTerm = &pWC2->a[ii]; + if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){ + break; + } + /* pTerm can be evaluated using just the index. So reduce + ** the expected number of table lookups accordingly */ + if( pTerm->truthProb<=0 ){ + nLookup += pTerm->truthProb; + }else{ + nLookup--; + if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19; + } + } + + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); + } + ApplyCostMultiplier(pNew->rRun, pTab->costMult); + whereLoopOutputAdjust(pWC, pNew, rSize); + rc = whereLoopInsert(pBuilder, pNew); + pNew->nOut = rSize; + if( rc ) break; + } + } + + pBuilder->bldFlags = 0; + rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0); + if( pBuilder->bldFlags==SQLITE_BLDF_INDEXED ){ + /* If a non-unique index is used, or if a prefix of the key for + ** unique index is used (making the index functionally non-unique) + ** then the sqlite_stat1 data becomes important for scoring the + ** plan */ + pTab->tabFlags |= TF_StatsUsed; + } +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sqlite3Stat4ProbeFree(pBuilder->pRec); + pBuilder->nRecValid = 0; + pBuilder->pRec = 0; +#endif + + /* If there was an INDEXED BY clause, then only that one index is + ** considered. */ + if( pSrc->pIBIndex ) break; + } + return rc; +} + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +/* +** Argument pIdxInfo is already populated with all constraints that may +** be used by the virtual table identified by pBuilder->pNew->iTab. This +** function marks a subset of those constraints usable, invokes the +** xBestIndex method and adds the returned plan to pBuilder. +** +** A constraint is marked usable if: +** +** * Argument mUsable indicates that its prerequisites are available, and +** +** * It is not one of the operators specified in the mExclude mask passed +** as the fourth argument (which in practice is either WO_IN or 0). +** +** Argument mPrereq is a mask of tables that must be scanned before the +** virtual table in question. These are added to the plans prerequisites +** before it is added to pBuilder. +** +** Output parameter *pbIn is set to true if the plan added to pBuilder +** uses one or more WO_IN terms, or false otherwise. +*/ +static int whereLoopAddVirtualOne( + WhereLoopBuilder *pBuilder, + Bitmask mPrereq, /* Mask of tables that must be used. */ + Bitmask mUsable, /* Mask of usable tables */ + u16 mExclude, /* Exclude terms using these operators */ + sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ + u16 mNoOmit, /* Do not omit these constraints */ + int *pbIn /* OUT: True if plan uses an IN(...) op */ +){ + WhereClause *pWC = pBuilder->pWC; + struct sqlite3_index_constraint *pIdxCons; + struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage; + int i; + int mxTerm; + int rc = SQLITE_OK; + WhereLoop *pNew = pBuilder->pNew; + Parse *pParse = pBuilder->pWInfo->pParse; + struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab]; + int nConstraint = pIdxInfo->nConstraint; + + assert( (mUsable & mPrereq)==mPrereq ); + *pbIn = 0; + pNew->prereq = mPrereq; + + /* Set the usable flag on the subset of constraints identified by + ** arguments mUsable and mExclude. */ + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + for(i=0; ia[pIdxCons->iTermOffset]; + pIdxCons->usable = 0; + if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight + && (pTerm->eOperator & mExclude)==0 + ){ + pIdxCons->usable = 1; + } + } + + /* Initialize the output fields of the sqlite3_index_info structure */ + memset(pUsage, 0, sizeof(pUsage[0])*nConstraint); + assert( pIdxInfo->needToFreeIdxStr==0 ); + pIdxInfo->idxStr = 0; + pIdxInfo->idxNum = 0; + pIdxInfo->orderByConsumed = 0; + pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; + pIdxInfo->estimatedRows = 25; + pIdxInfo->idxFlags = 0; + pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; + + /* Invoke the virtual table xBestIndex() method */ + rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); + if( rc ) return rc; + + mxTerm = -1; + assert( pNew->nLSlot>=nConstraint ); + for(i=0; iaLTerm[i] = 0; + pNew->u.vtab.omitMask = 0; + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + for(i=0; i=0 ){ + WhereTerm *pTerm; + int j = pIdxCons->iTermOffset; + if( iTerm>=nConstraint + || j<0 + || j>=pWC->nTerm + || pNew->aLTerm[iTerm]!=0 + || pIdxCons->usable==0 + ){ + rc = SQLITE_ERROR; + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); + return rc; + } + testcase( iTerm==nConstraint-1 ); + testcase( j==0 ); + testcase( j==pWC->nTerm-1 ); + pTerm = &pWC->a[j]; + pNew->prereq |= pTerm->prereqRight; + assert( iTermnLSlot ); + pNew->aLTerm[iTerm] = pTerm; + if( iTerm>mxTerm ) mxTerm = iTerm; + testcase( iTerm==15 ); + testcase( iTerm==16 ); + if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ + /* A virtual table that is constrained by an IN clause may not + ** consume the ORDER BY clause because (1) the order of IN terms + ** is not necessarily related to the order of output terms and + ** (2) Multiple outputs from a single IN value will not merge + ** together. */ + pIdxInfo->orderByConsumed = 0; + pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; + *pbIn = 1; assert( (mExclude & WO_IN)==0 ); + } + } + } + pNew->u.vtab.omitMask &= ~mNoOmit; + + pNew->nLTerm = mxTerm+1; + assert( pNew->nLTerm<=pNew->nLSlot ); + pNew->u.vtab.idxNum = pIdxInfo->idxNum; + pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; + pIdxInfo->needToFreeIdxStr = 0; + pNew->u.vtab.idxStr = pIdxInfo->idxStr; + pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? + pIdxInfo->nOrderBy : 0); + pNew->rSetup = 0; + pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); + pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); + + /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated + ** that the scan will visit at most one row. Clear it otherwise. */ + if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){ + pNew->wsFlags |= WHERE_ONEROW; + }else{ + pNew->wsFlags &= ~WHERE_ONEROW; + } + rc = whereLoopInsert(pBuilder, pNew); + if( pNew->u.vtab.needFree ){ + sqlite3_free(pNew->u.vtab.idxStr); + pNew->u.vtab.needFree = 0; + } + WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n", + *pbIn, (sqlite3_uint64)mPrereq, + (sqlite3_uint64)(pNew->prereq & ~mPrereq))); + + return rc; +} + + +/* +** Add all WhereLoop objects for a table of the join identified by +** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. +** +** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and +** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause +** entries that occur before the virtual table in the FROM clause and are +** separated from it by at least one LEFT or CROSS JOIN. Similarly, the +** mUnusable mask contains all FROM clause entries that occur after the +** virtual table and are separated from it by at least one LEFT or +** CROSS JOIN. +** +** For example, if the query were: +** +** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6; +** +** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6). +** +** All the tables in mPrereq must be scanned before the current virtual +** table. So any terms for which all prerequisites are satisfied by +** mPrereq may be specified as "usable" in all calls to xBestIndex. +** Conversely, all tables in mUnusable must be scanned after the current +** virtual table, so any terms for which the prerequisites overlap with +** mUnusable should always be configured as "not-usable" for xBestIndex. +*/ +static int whereLoopAddVirtual( + WhereLoopBuilder *pBuilder, /* WHERE clause information */ + Bitmask mPrereq, /* Tables that must be scanned before this one */ + Bitmask mUnusable /* Tables that must be scanned after this one */ +){ + int rc = SQLITE_OK; /* Return code */ + WhereInfo *pWInfo; /* WHERE analysis context */ + Parse *pParse; /* The parsing context */ + WhereClause *pWC; /* The WHERE clause */ + struct SrcList_item *pSrc; /* The FROM clause term to search */ + sqlite3_index_info *p; /* Object to pass to xBestIndex() */ + int nConstraint; /* Number of constraints in p */ + int bIn; /* True if plan uses IN(...) operator */ + WhereLoop *pNew; + Bitmask mBest; /* Tables used by best possible plan */ + u16 mNoOmit; + + assert( (mPrereq & mUnusable)==0 ); + pWInfo = pBuilder->pWInfo; + pParse = pWInfo->pParse; + pWC = pBuilder->pWC; + pNew = pBuilder->pNew; + pSrc = &pWInfo->pTabList->a[pNew->iTab]; + assert( IsVirtual(pSrc->pTab) ); + p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, + &mNoOmit); + if( p==0 ) return SQLITE_NOMEM_BKPT; + pNew->rSetup = 0; + pNew->wsFlags = WHERE_VIRTUALTABLE; + pNew->nLTerm = 0; + pNew->u.vtab.needFree = 0; + nConstraint = p->nConstraint; + if( whereLoopResize(pParse->db, pNew, nConstraint) ){ + sqlite3DbFree(pParse->db, p); + return SQLITE_NOMEM_BKPT; + } + + /* First call xBestIndex() with all constraints usable. */ + WHERETRACE(0x40, (" VirtualOne: all usable\n")); + rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); + + /* If the call to xBestIndex() with all terms enabled produced a plan + ** that does not require any source tables (IOW: a plan with mBest==0), + ** then there is no point in making any further calls to xBestIndex() + ** since they will all return the same result (if the xBestIndex() + ** implementation is sane). */ + if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){ + int seenZero = 0; /* True if a plan with no prereqs seen */ + int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */ + Bitmask mPrev = 0; + Bitmask mBestNoIn = 0; + + /* If the plan produced by the earlier call uses an IN(...) term, call + ** xBestIndex again, this time with IN(...) terms disabled. */ + if( bIn ){ + WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n")); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn); + assert( bIn==0 ); + mBestNoIn = pNew->prereq & ~mPrereq; + if( mBestNoIn==0 ){ + seenZero = 1; + seenZeroNoIN = 1; + } + } + + /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) + ** in the set of terms that apply to the current virtual table. */ + while( rc==SQLITE_OK ){ + int i; + Bitmask mNext = ALLBITS; + assert( mNext>0 ); + for(i=0; ia[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq + ); + if( mThis>mPrev && mThisprereq==mPrereq ){ + seenZero = 1; + if( bIn==0 ) seenZeroNoIN = 1; + } + } + + /* If the calls to xBestIndex() in the above loop did not find a plan + ** that requires no source tables at all (i.e. one guaranteed to be + ** usable), make a call here with all source tables disabled */ + if( rc==SQLITE_OK && seenZero==0 ){ + WHERETRACE(0x40, (" VirtualOne: all disabled\n")); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn); + if( bIn==0 ) seenZeroNoIN = 1; + } + + /* If the calls to xBestIndex() have so far failed to find a plan + ** that requires no source tables at all and does not use an IN(...) + ** operator, make a final call to obtain one here. */ + if( rc==SQLITE_OK && seenZeroNoIN==0 ){ + WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n")); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn); + } + } + + if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); + sqlite3DbFreeNN(pParse->db, p); + return rc; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +/* +** Add WhereLoop entries to handle OR terms. This works for either +** btrees or virtual tables. +*/ +static int whereLoopAddOr( + WhereLoopBuilder *pBuilder, + Bitmask mPrereq, + Bitmask mUnusable +){ + WhereInfo *pWInfo = pBuilder->pWInfo; + WhereClause *pWC; + WhereLoop *pNew; + WhereTerm *pTerm, *pWCEnd; + int rc = SQLITE_OK; + int iCur; + WhereClause tempWC; + WhereLoopBuilder sSubBuild; + WhereOrSet sSum, sCur; + struct SrcList_item *pItem; + + pWC = pBuilder->pWC; + pWCEnd = pWC->a + pWC->nTerm; + pNew = pBuilder->pNew; + memset(&sSum, 0, sizeof(sSum)); + pItem = pWInfo->pTabList->a + pNew->iTab; + iCur = pItem->iCursor; + + for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 + && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 + ){ + WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; + WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; + WhereTerm *pOrTerm; + int once = 1; + int i, j; + + sSubBuild = *pBuilder; + sSubBuild.pOrderBy = 0; + sSubBuild.pOrSet = &sCur; + + WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); + for(pOrTerm=pOrWC->a; pOrTermeOperator & WO_AND)!=0 ){ + sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; + }else if( pOrTerm->leftCursor==iCur ){ + tempWC.pWInfo = pWC->pWInfo; + tempWC.pOuter = pWC; + tempWC.op = TK_AND; + tempWC.nTerm = 1; + tempWC.a = pOrTerm; + sSubBuild.pWC = &tempWC; + }else{ + continue; + } + sCur.n = 0; +#ifdef WHERETRACE_ENABLED + WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", + (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); + if( sqlite3WhereTrace & 0x400 ){ + sqlite3WhereClausePrint(sSubBuild.pWC); + } +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pItem->pTab) ){ + rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); + }else +#endif + { + rc = whereLoopAddBtree(&sSubBuild, mPrereq); + } + if( rc==SQLITE_OK ){ + rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); + } + assert( rc==SQLITE_OK || sCur.n==0 ); + if( sCur.n==0 ){ + sSum.n = 0; + break; + }else if( once ){ + whereOrMove(&sSum, &sCur); + once = 0; + }else{ + WhereOrSet sPrev; + whereOrMove(&sPrev, &sSum); + sSum.n = 0; + for(i=0; inLTerm = 1; + pNew->aLTerm[0] = pTerm; + pNew->wsFlags = WHERE_MULTI_OR; + pNew->rSetup = 0; + pNew->iSortIdx = 0; + memset(&pNew->u, 0, sizeof(pNew->u)); + for(i=0; rc==SQLITE_OK && irRun = sSum.a[i].rRun + 1; + pNew->nOut = sSum.a[i].nOut; + pNew->prereq = sSum.a[i].prereq; + rc = whereLoopInsert(pBuilder, pNew); + } + WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm)); + } + } + return rc; +} + +/* +** Add all WhereLoop objects for all tables +*/ +static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ + WhereInfo *pWInfo = pBuilder->pWInfo; + Bitmask mPrereq = 0; + Bitmask mPrior = 0; + int iTab; + SrcList *pTabList = pWInfo->pTabList; + struct SrcList_item *pItem; + struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel]; + sqlite3 *db = pWInfo->pParse->db; + int rc = SQLITE_OK; + WhereLoop *pNew; + u8 priorJointype = 0; + + /* Loop over the tables in the join, from left to right */ + pNew = pBuilder->pNew; + whereLoopInit(pNew); + for(iTab=0, pItem=pTabList->a; pItemiTab = iTab; + pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); + if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ + /* This condition is true when pItem is the FROM clause term on the + ** right-hand-side of a LEFT or CROSS JOIN. */ + mPrereq = mPrior; + } + priorJointype = pItem->fg.jointype; +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pItem->pTab) ){ + struct SrcList_item *p; + for(p=&pItem[1]; pfg.jointype & (JT_LEFT|JT_CROSS)) ){ + mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); + } + } + rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); + }else +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + { + rc = whereLoopAddBtree(pBuilder, mPrereq); + } + if( rc==SQLITE_OK ){ + rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); + } + mPrior |= pNew->maskSelf; + if( rc || db->mallocFailed ) break; + } + + whereLoopClear(db, pNew); + return rc; +} + +/* +** Examine a WherePath (with the addition of the extra WhereLoop of the 6th +** parameters) to see if it outputs rows in the requested ORDER BY +** (or GROUP BY) without requiring a separate sort operation. Return N: +** +** N>0: N terms of the ORDER BY clause are satisfied +** N==0: No terms of the ORDER BY clause are satisfied +** N<0: Unknown yet how many terms of ORDER BY might be satisfied. +** +** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as +** strict. With GROUP BY and DISTINCT the only requirement is that +** equivalent rows appear immediately adjacent to one another. GROUP BY +** and DISTINCT do not require rows to appear in any particular order as long +** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT +** the pOrderBy terms can be matched in any order. With ORDER BY, the +** pOrderBy terms must be matched in strict left-to-right order. +*/ +static i8 wherePathSatisfiesOrderBy( + WhereInfo *pWInfo, /* The WHERE clause */ + ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ + WherePath *pPath, /* The WherePath to check */ + u16 wctrlFlags, /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */ + u16 nLoop, /* Number of entries in pPath->aLoop[] */ + WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ + Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ +){ + u8 revSet; /* True if rev is known */ + u8 rev; /* Composite sort order */ + u8 revIdx; /* Index sort order */ + u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */ + u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */ + u8 isMatch; /* iColumn matches a term of the ORDER BY clause */ + u16 eqOpMask; /* Allowed equality operators */ + u16 nKeyCol; /* Number of key columns in pIndex */ + u16 nColumn; /* Total number of ordered columns in the index */ + u16 nOrderBy; /* Number terms in the ORDER BY clause */ + int iLoop; /* Index of WhereLoop in pPath being processed */ + int i, j; /* Loop counters */ + int iCur; /* Cursor number for current WhereLoop */ + int iColumn; /* A column number within table iCur */ + WhereLoop *pLoop = 0; /* Current WhereLoop being processed. */ + WhereTerm *pTerm; /* A single term of the WHERE clause */ + Expr *pOBExpr; /* An expression from the ORDER BY clause */ + CollSeq *pColl; /* COLLATE function from an ORDER BY clause term */ + Index *pIndex; /* The index associated with pLoop */ + sqlite3 *db = pWInfo->pParse->db; /* Database connection */ + Bitmask obSat = 0; /* Mask of ORDER BY terms satisfied so far */ + Bitmask obDone; /* Mask of all ORDER BY terms */ + Bitmask orderDistinctMask; /* Mask of all well-ordered loops */ + Bitmask ready; /* Mask of inner loops */ + + /* + ** We say the WhereLoop is "one-row" if it generates no more than one + ** row of output. A WhereLoop is one-row if all of the following are true: + ** (a) All index columns match with WHERE_COLUMN_EQ. + ** (b) The index is unique + ** Any WhereLoop with an WHERE_COLUMN_EQ constraint on the rowid is one-row. + ** Every one-row WhereLoop will have the WHERE_ONEROW bit set in wsFlags. + ** + ** We say the WhereLoop is "order-distinct" if the set of columns from + ** that WhereLoop that are in the ORDER BY clause are different for every + ** row of the WhereLoop. Every one-row WhereLoop is automatically + ** order-distinct. A WhereLoop that has no columns in the ORDER BY clause + ** is not order-distinct. To be order-distinct is not quite the same as being + ** UNIQUE since a UNIQUE column or index can have multiple rows that + ** are NULL and NULL values are equivalent for the purpose of order-distinct. + ** To be order-distinct, the columns must be UNIQUE and NOT NULL. + ** + ** The rowid for a table is always UNIQUE and NOT NULL so whenever the + ** rowid appears in the ORDER BY clause, the corresponding WhereLoop is + ** automatically order-distinct. + */ + + assert( pOrderBy!=0 ); + if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0; + + nOrderBy = pOrderBy->nExpr; + testcase( nOrderBy==BMS-1 ); + if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ + isOrderDistinct = 1; + obDone = MASKBIT(nOrderBy)-1; + orderDistinctMask = 0; + ready = 0; + eqOpMask = WO_EQ | WO_IS | WO_ISNULL; + if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN; + for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; + if( iLoopaLoop[iLoop]; + if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue; + }else{ + pLoop = pLast; + } + if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ + if( pLoop->u.vtab.isOrdered ) obSat = obDone; + break; + }else{ + pLoop->u.btree.nIdxCol = 0; + } + iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; + + /* Mark off any ORDER BY term X that is a column in the table of + ** the current loop for which there is term in the WHERE + ** clause of the form X IS NULL or X=? that reference only outer + ** loops. + */ + for(i=0; ia[i].pExpr); + if( pOBExpr->op!=TK_COLUMN ) continue; + if( pOBExpr->iTable!=iCur ) continue; + pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, + ~ready, eqOpMask, 0); + if( pTerm==0 ) continue; + if( pTerm->eOperator==WO_IN ){ + /* IN terms are only valid for sorting in the ORDER BY LIMIT + ** optimization, and then only if they are actually used + ** by the query plan */ + assert( wctrlFlags & WHERE_ORDERBY_LIMIT ); + for(j=0; jnLTerm && pTerm!=pLoop->aLTerm[j]; j++){} + 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; + testcase( pTerm->pExpr->op==TK_IS ); + } + obSat |= MASKBIT(i); + } + + if( (pLoop->wsFlags & WHERE_ONEROW)==0 ){ + if( pLoop->wsFlags & WHERE_IPK ){ + pIndex = 0; + nKeyCol = 0; + nColumn = 1; + }else if( (pIndex = pLoop->u.btree.pIndex)==0 || pIndex->bUnordered ){ + return 0; + }else{ + nKeyCol = pIndex->nKeyCol; + nColumn = pIndex->nColumn; + assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); + assert( pIndex->aiColumn[nColumn-1]==XN_ROWID + || !HasRowid(pIndex->pTable)); + isOrderDistinct = IsUniqueIndex(pIndex); + } + + /* Loop through all columns of the index and deal with the ones + ** that are not constrained by == or IN. + */ + rev = revSet = 0; + distinctColumns = 0; + for(j=0; j=pLoop->u.btree.nEq + || (pLoop->aLTerm[j]==0)==(jnSkip) + ); + if( ju.btree.nEq && j>=pLoop->nSkip ){ + u16 eOp = pLoop->aLTerm[j]->eOperator; + + /* Skip over == and IS and ISNULL terms. (Also skip IN terms when + ** doing WHERE_ORDERBY_LIMIT processing). + ** + ** If the current term is a column of an ((?,?) IN (SELECT...)) + ** expression for which the SELECT returns more than one column, + ** check that it is the only column used by this loop. Otherwise, + ** if it is one of two or more, none of the columns can be + ** considered to match an ORDER BY term. */ + if( (eOp & eqOpMask)!=0 ){ + if( eOp & WO_ISNULL ){ + testcase( isOrderDistinct ); + isOrderDistinct = 0; + } + continue; + }else if( ALWAYS(eOp & WO_IN) ){ + /* ALWAYS() justification: eOp is an equality operator due to the + ** ju.btree.nEq constraint above. Any equality other + ** than WO_IN is captured by the previous "if". So this one + ** always has to be WO_IN. */ + Expr *pX = pLoop->aLTerm[j]->pExpr; + for(i=j+1; iu.btree.nEq; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + assert( (pLoop->aLTerm[i]->eOperator & WO_IN) ); + bOnce = 0; + break; + } + } + } + } + + /* Get the column number in the table (iColumn) and sort order + ** (revIdx) for the j-th column of the index. + */ + if( pIndex ){ + iColumn = pIndex->aiColumn[j]; + revIdx = pIndex->aSortOrder[j]; + if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; + }else{ + iColumn = XN_ROWID; + revIdx = 0; + } + + /* An unconstrained column that might be NULL means that this + ** WhereLoop is not well-ordered + */ + if( isOrderDistinct + && iColumn>=0 + && j>=pLoop->u.btree.nEq + && pIndex->pTable->aCol[iColumn].notNull==0 + ){ + isOrderDistinct = 0; + } + + /* Find the ORDER BY term that corresponds to the j-th column + ** of the index and mark that ORDER BY term off + */ + isMatch = 0; + for(i=0; bOnce && ia[i].pExpr); + testcase( wctrlFlags & WHERE_GROUPBY ); + testcase( wctrlFlags & WHERE_DISTINCTBY ); + if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; + if( iColumn>=(-1) ){ + if( pOBExpr->op!=TK_COLUMN ) continue; + if( pOBExpr->iTable!=iCur ) continue; + if( pOBExpr->iColumn!=iColumn ) continue; + }else{ + if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){ + continue; + } + } + if( iColumn>=0 ){ + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); + if( !pColl ) pColl = db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; + } + pLoop->u.btree.nIdxCol = j+1; + isMatch = 1; + break; + } + if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){ + /* Make sure the sort order is compatible in an ORDER BY clause. + ** Sort order is irrelevant for a GROUP BY clause. */ + if( revSet ){ + if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; + }else{ + rev = revIdx ^ pOrderBy->a[i].sortOrder; + if( rev ) *pRevMask |= MASKBIT(iLoop); + revSet = 1; + } + } + if( isMatch ){ + if( iColumn==XN_ROWID ){ + testcase( distinctColumns==0 ); + distinctColumns = 1; + } + obSat |= MASKBIT(i); + }else{ + /* No match found */ + if( j==0 || jmaskSelf; + for(i=0; ia[i].pExpr; + mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p); + if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue; + if( (mTerm&~orderDistinctMask)==0 ){ + obSat |= MASKBIT(i); + } + } + } + } /* End the loop over all WhereLoops from outer-most down to inner-most */ + if( obSat==obDone ) return (i8)nOrderBy; + if( !isOrderDistinct ){ + for(i=nOrderBy-1; i>0; i--){ + Bitmask m = MASKBIT(i) - 1; + if( (obSat&m)==m ) return i; + } + return 0; + } + return -1; +} + + +/* +** If the WHERE_GROUPBY flag is set in the mask passed to sqlite3WhereBegin(), +** the planner assumes that the specified pOrderBy list is actually a GROUP +** BY clause - and so any order that groups rows as required satisfies the +** request. +** +** Normally, in this case it is not possible for the caller to determine +** whether or not the rows are really being delivered in sorted order, or +** just in some other order that provides the required grouping. However, +** if the WHERE_SORTBYGROUP flag is also passed to sqlite3WhereBegin(), then +** this function may be called on the returned WhereInfo object. It returns +** true if the rows really will be sorted in the specified order, or false +** otherwise. +** +** For example, assuming: +** +** CREATE INDEX i1 ON t1(x, Y); +** +** then +** +** SELECT * FROM t1 GROUP BY x,y ORDER BY x,y; -- IsSorted()==1 +** SELECT * FROM t1 GROUP BY y,x ORDER BY y,x; -- IsSorted()==0 +*/ +SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo *pWInfo){ + assert( pWInfo->wctrlFlags & WHERE_GROUPBY ); + assert( pWInfo->wctrlFlags & WHERE_SORTBYGROUP ); + return pWInfo->sorted; +} + +#ifdef WHERETRACE_ENABLED +/* For debugging use only: */ +static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ + static char zName[65]; + int i; + for(i=0; iaLoop[i]->cId; } + if( pLast ) zName[i++] = pLast->cId; + zName[i] = 0; + return zName; +} +#endif + +/* +** Return the cost of sorting nRow rows, assuming that the keys have +** nOrderby columns and that the first nSorted columns are already in +** order. +*/ +static LogEst whereSortingCost( + WhereInfo *pWInfo, + LogEst nRow, + int nOrderBy, + int nSorted +){ + /* TUNING: Estimated cost of a full external sort, where N is + ** the number of rows to sort is: + ** + ** cost = (3.0 * N * log(N)). + ** + ** Or, if the order-by clause has X terms but only the last Y + ** terms are out of order, then block-sorting will reduce the + ** sorting cost to: + ** + ** cost = (3.0 * N * log(N)) * (Y/X) + ** + ** The (Y/X) term is implemented using stack variable rScale + ** below. */ + LogEst rScale, rSortCost; + assert( nOrderBy>0 && 66==sqlite3LogEst(100) ); + rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; + rSortCost = nRow + rScale + 16; + + /* Multiple by log(M) where M is the number of output rows. + ** Use the LIMIT for M if it is smaller */ + if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimitiLimit; + } + rSortCost += estLog(nRow); + return rSortCost; +} + +/* +** Given the list of WhereLoop objects at pWInfo->pLoops, this routine +** attempts to find the lowest cost path that visits each WhereLoop +** once. This path is then loaded into the pWInfo->a[].pWLoop fields. +** +** Assume that the total number of output rows that will need to be sorted +** will be nRowEst (in the 10*log2 representation). Or, ignore sorting +** costs if nRowEst==0. +** +** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation +** error occurs. +*/ +static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ + int mxChoice; /* Maximum number of simultaneous paths tracked */ + int nLoop; /* Number of terms in the join */ + Parse *pParse; /* Parsing context */ + sqlite3 *db; /* The database connection */ + int iLoop; /* Loop counter over the terms of the join */ + int ii, jj; /* Loop counters */ + int mxI = 0; /* Index of next entry to replace */ + int nOrderBy; /* Number of ORDER BY clause terms */ + LogEst mxCost = 0; /* Maximum cost of a set of paths */ + LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ + int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ + WherePath *aFrom; /* All nFrom paths at the previous level */ + WherePath *aTo; /* The nTo best paths at the current level */ + WherePath *pFrom; /* An element of aFrom[] that we are working on */ + WherePath *pTo; /* An element of aTo[] that we are working on */ + WhereLoop *pWLoop; /* One of the WhereLoop objects */ + WhereLoop **pX; /* Used to divy up the pSpace memory */ + LogEst *aSortCost = 0; /* Sorting and partial sorting costs */ + char *pSpace; /* Temporary memory used by this routine */ + int nSpace; /* Bytes of space allocated at pSpace */ + + pParse = pWInfo->pParse; + db = pParse->db; + nLoop = pWInfo->nLevel; + /* TUNING: For simple queries, only the best path is tracked. + ** For 2-way joins, the 5 best paths are followed. + ** For joins of 3 or more tables, track the 10 best paths */ + mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10); + assert( nLoop<=pWInfo->pTabList->nSrc ); + WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst)); + + /* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this + ** case the purpose of this call is to estimate the number of rows returned + ** by the overall query. Once this estimate has been obtained, the caller + ** will invoke this function a second time, passing the estimate as the + ** nRowEst parameter. */ + if( pWInfo->pOrderBy==0 || nRowEst==0 ){ + nOrderBy = 0; + }else{ + nOrderBy = pWInfo->pOrderBy->nExpr; + } + + /* Allocate and initialize space for aTo, aFrom and aSortCost[] */ + nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; + nSpace += sizeof(LogEst) * nOrderBy; + pSpace = sqlite3DbMallocRawNN(db, nSpace); + if( pSpace==0 ) return SQLITE_NOMEM_BKPT; + aTo = (WherePath*)pSpace; + aFrom = aTo+mxChoice; + memset(aFrom, 0, sizeof(aFrom[0])); + pX = (WhereLoop**)(aFrom+mxChoice); + for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){ + pFrom->aLoop = pX; + } + if( nOrderBy ){ + /* If there is an ORDER BY clause and it is not being ignored, set up + ** space for the aSortCost[] array. Each element of the aSortCost array + ** is either zero - meaning it has not yet been initialized - or the + ** cost of sorting nRowEst rows of data where the first X terms of + ** the ORDER BY clause are already in order, where X is the array + ** index. */ + aSortCost = (LogEst*)pX; + memset(aSortCost, 0, sizeof(LogEst) * nOrderBy); + } + assert( aSortCost==0 || &pSpace[nSpace]==(char*)&aSortCost[nOrderBy] ); + assert( aSortCost!=0 || &pSpace[nSpace]==(char*)pX ); + + /* Seed the search with a single WherePath containing zero WhereLoops. + ** + ** TUNING: Do not let the number of iterations go above 28. If the cost + ** of computing an automatic index is not paid back within the first 28 + ** rows, then do not use the automatic index. */ + aFrom[0].nRow = MIN(pParse->nQueryLoop, 48); assert( 48==sqlite3LogEst(28) ); + nFrom = 1; + assert( aFrom[0].isOrdered==0 ); + if( nOrderBy ){ + /* If nLoop is zero, then there are no FROM terms in the query. Since + ** in this case the query may return a maximum of one row, the results + ** are already in the requested order. Set isOrdered to nOrderBy to + ** indicate this. Or, if nLoop is greater than zero, set isOrdered to + ** -1, indicating that the result set may or may not be ordered, + ** depending on the loops added to the current plan. */ + aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy; + } + + /* Compute successively longer WherePaths using the previous generation + ** of WherePaths as the basis for the next. Keep track of the mxChoice + ** best paths at each generation */ + for(iLoop=0; iLooppLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ + LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ + LogEst rCost; /* Cost of path (pFrom+pWLoop) */ + LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ + i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */ + Bitmask maskNew; /* Mask of src visited by (..) */ + Bitmask revMask = 0; /* Mask of rev-order loops for (..) */ + + if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; + if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; + if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){ + /* Do not use an automatic index if the this loop is expected + ** to run less than 2 times. */ + assert( 10==sqlite3LogEst(2) ); + continue; + } + /* At this point, pWLoop is a candidate to be the next loop. + ** Compute its cost */ + rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); + rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); + nOut = pFrom->nRow + pWLoop->nOut; + maskNew = pFrom->maskLoop | pWLoop->maskSelf; + if( isOrdered<0 ){ + isOrdered = wherePathSatisfiesOrderBy(pWInfo, + pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, + iLoop, pWLoop, &revMask); + }else{ + revMask = pFrom->revLoop; + } + if( isOrdered>=0 && isOrderedisOrdered^isOrdered)&0x80)==0" is equivalent + ** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range + ** of legal values for isOrdered, -1..64. + */ + for(jj=0, pTo=aTo; jjmaskLoop==maskNew + && ((pTo->isOrdered^isOrdered)&0x80)==0 + ){ + testcase( jj==nTo-1 ); + break; + } + } + if( jj>=nTo ){ + /* None of the existing best-so-far paths match the candidate. */ + if( nTo>=mxChoice + && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted)) + ){ + /* The current candidate is no better than any of the mxChoice + ** paths currently in the best-so-far buffer. So discard + ** this candidate as not viable. */ +#ifdef WHERETRACE_ENABLED /* 0x4 */ + if( sqlite3WhereTrace&0x4 ){ + sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + isOrdered>=0 ? isOrdered+'0' : '?'); + } +#endif + continue; + } + /* If we reach this points it means that the new candidate path + ** needs to be added to the set of best-so-far paths. */ + if( nTo=0 ? isOrdered+'0' : '?'); + } +#endif + }else{ + /* Control reaches here if best-so-far path pTo=aTo[jj] covers the + ** same set of loops and has the sam isOrdered setting as the + ** candidate path. Check to see if the candidate should replace + ** pTo or if the candidate should be skipped */ + if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){ +#ifdef WHERETRACE_ENABLED /* 0x4 */ + if( sqlite3WhereTrace&0x4 ){ + sqlite3DebugPrintf( + "Skip %s cost=%-3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + isOrdered>=0 ? isOrdered+'0' : '?'); + sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", + wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, + pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + } +#endif + /* Discard the candidate path from further consideration */ + testcase( pTo->rCost==rCost ); + continue; + } + testcase( pTo->rCost==rCost+1 ); + /* Control reaches here if the candidate path is better than the + ** pTo path. Replace pTo with the candidate. */ +#ifdef WHERETRACE_ENABLED /* 0x4 */ + if( sqlite3WhereTrace&0x4 ){ + sqlite3DebugPrintf( + "Update %s cost=%-3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + isOrdered>=0 ? isOrdered+'0' : '?'); + sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", + wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, + pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + } +#endif + } + /* pWLoop is a winner. Add it to the set of best so far */ + pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; + pTo->revLoop = revMask; + pTo->nRow = nOut; + pTo->rCost = rCost; + pTo->rUnsorted = rUnsorted; + pTo->isOrdered = isOrdered; + memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); + pTo->aLoop[iLoop] = pWLoop; + if( nTo>=mxChoice ){ + mxI = 0; + mxCost = aTo[0].rCost; + mxUnsorted = aTo[0].nRow; + for(jj=1, pTo=&aTo[1]; jjrCost>mxCost + || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) + ){ + mxCost = pTo->rCost; + mxUnsorted = pTo->rUnsorted; + mxI = jj; + } + } + } + } + } + +#ifdef WHERETRACE_ENABLED /* >=2 */ + if( sqlite3WhereTrace & 0x02 ){ + sqlite3DebugPrintf("---- after round %d ----\n", iLoop); + for(ii=0, pTo=aTo; iirCost, pTo->nRow, + pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?'); + if( pTo->isOrdered>0 ){ + sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop); + }else{ + sqlite3DebugPrintf("\n"); + } + } + } +#endif + + /* Swap the roles of aFrom and aTo for the next generation */ + pFrom = aTo; + aTo = aFrom; + aFrom = pFrom; + nFrom = nTo; + } + + if( nFrom==0 ){ + sqlite3ErrorMsg(pParse, "no query solution"); + sqlite3DbFreeNN(db, pSpace); + return SQLITE_ERROR; + } + + /* Find the lowest cost path. pFrom will be left pointing to that path */ + pFrom = aFrom; + for(ii=1; iirCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; + } + assert( pWInfo->nLevel==nLoop ); + /* Load the lowest cost path into pWInfo */ + for(iLoop=0; iLoopa + iLoop; + pLevel->pWLoop = pWLoop = pFrom->aLoop[iLoop]; + pLevel->iFrom = pWLoop->iTab; + pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; + } + if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 + && (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0 + && pWInfo->eDistinct==WHERE_DISTINCT_NOOP + && nRowEst + ){ + Bitmask notUsed; + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, + WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); + if( rc==pWInfo->pResultSet->nExpr ){ + pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; + } + } + if( pWInfo->pOrderBy ){ + if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ + if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ + pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; + } + }else{ + pWInfo->nOBSat = pFrom->isOrdered; + pWInfo->revMask = pFrom->revLoop; + if( pWInfo->nOBSat<=0 ){ + pWInfo->nOBSat = 0; + if( nLoop>0 ){ + u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags; + if( (wsFlags & WHERE_ONEROW)==0 + && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN) + ){ + Bitmask m = 0; + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, + WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m); + testcase( wsFlags & WHERE_IPK ); + testcase( wsFlags & WHERE_COLUMN_IN ); + if( rc==pWInfo->pOrderBy->nExpr ){ + pWInfo->bOrderedInnerLoop = 1; + pWInfo->revMask = m; + } + } + } + } + } + if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) + && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 + ){ + Bitmask revMask = 0; + int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, + pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask + ); + assert( pWInfo->sorted==0 ); + if( nOrder==pWInfo->pOrderBy->nExpr ){ + pWInfo->sorted = 1; + pWInfo->revMask = revMask; + } + } + } + + + pWInfo->nRowOut = pFrom->nRow; + + /* Free temporary memory and return success */ + sqlite3DbFreeNN(db, pSpace); + return SQLITE_OK; +} + +/* +** Most queries use only a single table (they are not joins) and have +** simple == constraints against indexed fields. This routine attempts +** to plan those simple cases using much less ceremony than the +** general-purpose query planner, and thereby yield faster sqlite3_prepare() +** times for the common case. +** +** Return non-zero on success, if this query can be handled by this +** no-frills query planner. Return zero if this query needs the +** general-purpose query planner. +*/ +static int whereShortCut(WhereLoopBuilder *pBuilder){ + WhereInfo *pWInfo; + struct SrcList_item *pItem; + WhereClause *pWC; + WhereTerm *pTerm; + WhereLoop *pLoop; + int iCur; + int j; + Table *pTab; + Index *pIdx; + + pWInfo = pBuilder->pWInfo; + if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; + assert( pWInfo->pTabList->nSrc>=1 ); + pItem = pWInfo->pTabList->a; + pTab = pItem->pTab; + if( IsVirtual(pTab) ) return 0; + if( pItem->fg.isIndexedBy ) return 0; + iCur = pItem->iCursor; + pWC = &pWInfo->sWC; + pLoop = pBuilder->pNew; + pLoop->wsFlags = 0; + pLoop->nSkip = 0; + pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); + if( pTerm ){ + testcase( pTerm->eOperator & WO_IS ); + pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; + pLoop->aLTerm[0] = pTerm; + pLoop->nLTerm = 1; + pLoop->u.btree.nEq = 1; + /* TUNING: Cost of a rowid lookup is 10 */ + pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */ + }else{ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int opMask; + assert( pLoop->aLTermSpace==pLoop->aLTerm ); + if( !IsUniqueIndex(pIdx) + || pIdx->pPartIdxWhere!=0 + || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) + ) continue; + opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; + for(j=0; jnKeyCol; j++){ + pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx); + if( pTerm==0 ) break; + testcase( pTerm->eOperator & WO_IS ); + pLoop->aLTerm[j] = pTerm; + } + if( j!=pIdx->nKeyCol ) continue; + pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; + if( pIdx->isCovering || (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){ + pLoop->wsFlags |= WHERE_IDX_ONLY; + } + pLoop->nLTerm = j; + pLoop->u.btree.nEq = j; + pLoop->u.btree.pIndex = pIdx; + /* TUNING: Cost of a unique index lookup is 15 */ + pLoop->rRun = 39; /* 39==sqlite3LogEst(15) */ + break; + } + } + if( pLoop->wsFlags ){ + pLoop->nOut = (LogEst)1; + pWInfo->a[0].pWLoop = pLoop; + assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] ); + pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */ + pWInfo->a[0].iTabCur = iCur; + pWInfo->nRowOut = 1; + if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; + if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ + pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + } +#ifdef SQLITE_DEBUG + pLoop->cId = '0'; +#endif + return 1; + } + return 0; +} + +/* +** Generate the beginning of the loop used for WHERE clause processing. +** The return value is a pointer to an opaque structure that contains +** information needed to terminate the loop. Later, the calling routine +** should invoke sqlite3WhereEnd() with the return value of this function +** in order to complete the WHERE clause processing. +** +** If an error occurs, this routine returns NULL. +** +** The basic idea is to do a nested loop, one loop for each table in +** the FROM clause of a select. (INSERT and UPDATE statements are the +** same as a SELECT with only a single table in the FROM clause.) For +** example, if the SQL is this: +** +** SELECT * FROM t1, t2, t3 WHERE ...; +** +** Then the code generated is conceptually like the following: +** +** foreach row1 in t1 do \ Code generated +** foreach row2 in t2 do |-- by sqlite3WhereBegin() +** foreach row3 in t3 do / +** ... +** end \ Code generated +** end |-- by sqlite3WhereEnd() +** end / +** +** Note that the loops might not be nested in the order in which they +** appear in the FROM clause if a different order is better able to make +** use of indices. Note also that when the IN operator appears in +** the WHERE clause, it might result in additional nested loops for +** scanning through all values on the right-hand side of the IN. +** +** There are Btree cursors associated with each table. t1 uses cursor +** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor. +** And so forth. This routine generates code to open those VDBE cursors +** and sqlite3WhereEnd() generates the code to close them. +** +** The code that sqlite3WhereBegin() generates leaves the cursors named +** in pTabList pointing at their appropriate entries. The [...] code +** can use OP_Column and OP_Rowid opcodes on these cursors to extract +** data from the various tables of the loop. +** +** If the WHERE clause is empty, the foreach loops must each scan their +** entire tables. Thus a three-way join is an O(N^3) operation. But if +** the tables have indices and there are terms in the WHERE clause that +** refer to those indices, a complete table scan can be avoided and the +** code will run much faster. Most of the work of this routine is checking +** to see if there are indices that can be used to speed up the loop. +** +** Terms of the WHERE clause are also used to limit which rows actually +** make it to the "..." in the middle of the loop. After each "foreach", +** terms of the WHERE clause that use only terms in that loop and outer +** loops are evaluated and if false a jump is made around all subsequent +** inner loops (or around the "..." if the test occurs within the inner- +** most loop) +** +** OUTER JOINS +** +** An outer join of tables t1 and t2 is conceptally coded as follows: +** +** foreach row1 in t1 do +** flag = 0 +** foreach row2 in t2 do +** start: +** ... +** flag = 1 +** end +** if flag==0 then +** move the row2 cursor to a null row +** goto start +** fi +** end +** +** ORDER BY CLAUSE PROCESSING +** +** pOrderBy is a pointer to the ORDER BY clause (or the GROUP BY clause +** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement +** if there is one. If there is no ORDER BY clause or if this routine +** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. +** +** The iIdxCur parameter is the cursor number of an index. If +** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index +** to use for OR clause processing. The WHERE clause should use this +** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is +** the first cursor in an array of cursors for all indices. iIdxCur should +** be used to compute the appropriate cursor depending on which index is +** used. +*/ +SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ + Expr *pWhere, /* The WHERE clause */ + ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ + ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */ + u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ + int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number + ** If WHERE_USE_LIMIT, then the limit amount */ +){ + int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ + int nTabList; /* Number of elements in pTabList */ + WhereInfo *pWInfo; /* Will become the return value of this function */ + Vdbe *v = pParse->pVdbe; /* The virtual database engine */ + Bitmask notReady; /* Cursors that are not yet positioned */ + WhereLoopBuilder sWLB; /* The WhereLoop builder */ + WhereMaskSet *pMaskSet; /* The expression mask set */ + WhereLevel *pLevel; /* A single level in pWInfo->a[] */ + WhereLoop *pLoop; /* Pointer to a single WhereLoop object */ + int ii; /* Loop counter */ + sqlite3 *db; /* Database connection */ + int rc; /* Return code */ + u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */ + + assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || ( + (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + )); + + /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */ + assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + || (wctrlFlags & WHERE_USE_LIMIT)==0 ); + + /* Variable initialization */ + db = pParse->db; + memset(&sWLB, 0, sizeof(sWLB)); + + /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ + testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); + if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; + sWLB.pOrderBy = pOrderBy; + + /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via + ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ + if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ + wctrlFlags &= ~WHERE_WANT_DISTINCT; + } + + /* The number of tables in the FROM clause is limited by the number of + ** bits in a Bitmask + */ + testcase( pTabList->nSrc==BMS ); + if( pTabList->nSrc>BMS ){ + sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); + return 0; + } + + /* This function normally generates a nested loop for all tables in + ** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should + ** only generate code for the first table in pTabList and assume that + ** any cursors associated with subsequent tables are uninitialized. + */ + nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc; + + /* Allocate and initialize the WhereInfo structure that will become the + ** return value. A single allocation is used to store the WhereInfo + ** struct, the contents of WhereInfo.a[], the WhereClause structure + ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte + ** field (type Bitmask) it must be aligned on an 8-byte boundary on + ** some architectures. Hence the ROUND8() below. + */ + nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); + pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); + if( db->mallocFailed ){ + sqlite3DbFree(db, pWInfo); + pWInfo = 0; + goto whereBeginError; + } + pWInfo->pParse = pParse; + pWInfo->pTabList = pTabList; + pWInfo->pOrderBy = pOrderBy; + pWInfo->pWhere = pWhere; + pWInfo->pResultSet = pResultSet; + pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; + pWInfo->nLevel = nTabList; + pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); + pWInfo->wctrlFlags = wctrlFlags; + pWInfo->iLimit = iAuxArg; + pWInfo->savedNQueryLoop = pParse->nQueryLoop; + memset(&pWInfo->nOBSat, 0, + offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat)); + memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel)); + assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */ + pMaskSet = &pWInfo->sMaskSet; + sWLB.pWInfo = pWInfo; + sWLB.pWC = &pWInfo->sWC; + sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo); + assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) ); + whereLoopInit(sWLB.pNew); +#ifdef SQLITE_DEBUG + sWLB.pNew->cId = '*'; +#endif + + /* Split the WHERE clause into separate subexpressions where each + ** subexpression is separated by an AND operator. + */ + initMaskSet(pMaskSet); + sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo); + sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND); + + /* Special case: a WHERE clause that is constant. Evaluate the + ** expression and either jump over all of the code or fall thru. + */ + for(ii=0; iinTerm; ii++){ + if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){ + sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak, + SQLITE_JUMPIFNULL); + sWLB.pWC->a[ii].wtFlags |= TERM_CODED; + } + } + + /* Special case: No FROM clause + */ + if( nTabList==0 ){ + if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; + 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<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; iinSrc; ii++){ + createMask(pMaskSet, pTabList->a[ii].iCursor); + sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); + } +#ifdef SQLITE_DEBUG + for(ii=0; iinSrc; ii++){ + Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); + assert( m==MASKBIT(ii) ); + } +#endif + + /* Analyze all of the subexpressions. */ + sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); + if( db->mallocFailed ) goto whereBeginError; + + if( wctrlFlags & WHERE_WANT_DISTINCT ){ + if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ + /* The DISTINCT marking is pointless. Ignore it. */ + pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; + }else if( pOrderBy==0 ){ + /* Try to ORDER BY the result set to make distinct processing easier */ + pWInfo->wctrlFlags |= WHERE_DISTINCTBY; + pWInfo->pOrderBy = pResultSet; + } + } + + /* Construct the WhereLoop objects */ +#if defined(WHERETRACE_ENABLED) + if( sqlite3WhereTrace & 0xffff ){ + sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); + if( wctrlFlags & WHERE_USE_LIMIT ){ + sqlite3DebugPrintf(", limit: %d", iAuxArg); + } + sqlite3DebugPrintf(")\n"); + } + if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ + sqlite3WhereClausePrint(sWLB.pWC); + } +#endif + + if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ + rc = whereLoopAddAll(&sWLB); + if( rc ) goto whereBeginError; + +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */ + WhereLoop *p; + int i; + static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" + "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; + for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ + p->cId = zLabel[i%sizeof(zLabel)]; + whereLoopPrint(p, sWLB.pWC); + } + } +#endif + + wherePathSolver(pWInfo, 0); + if( db->mallocFailed ) goto whereBeginError; + if( pWInfo->pOrderBy ){ + wherePathSolver(pWInfo, pWInfo->nRowOut+1); + if( db->mallocFailed ) goto whereBeginError; + } + } + if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ + pWInfo->revMask = ALLBITS; + } + if( pParse->nErr || NEVER(db->mallocFailed) ){ + goto whereBeginError; + } +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace ){ + sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); + if( pWInfo->nOBSat>0 ){ + sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); + } + switch( pWInfo->eDistinct ){ + case WHERE_DISTINCT_UNIQUE: { + sqlite3DebugPrintf(" DISTINCT=unique"); + break; + } + case WHERE_DISTINCT_ORDERED: { + sqlite3DebugPrintf(" DISTINCT=ordered"); + break; + } + case WHERE_DISTINCT_UNORDERED: { + sqlite3DebugPrintf(" DISTINCT=unordered"); + break; + } + } + sqlite3DebugPrintf("\n"); + for(ii=0; iinLevel; ii++){ + whereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC); + } + } +#endif + /* Attempt to omit tables from the join that do not effect the result */ + if( pWInfo->nLevel>=2 + && pResultSet!=0 + && OptimizationEnabled(db, SQLITE_OmitNoopJoin) + ){ + Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet); + if( sWLB.pOrderBy ){ + tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); + } + while( pWInfo->nLevel>=2 ){ + WhereTerm *pTerm, *pEnd; + pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; + if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break; + if( (wctrlFlags & WHERE_WANT_DISTINCT)==0 + && (pLoop->wsFlags & WHERE_ONEROW)==0 + ){ + break; + } + if( (tabUsed & pLoop->maskSelf)!=0 ) break; + pEnd = sWLB.pWC->a + sWLB.pWC->nTerm; + for(pTerm=sWLB.pWC->a; pTermprereqAll & pLoop->maskSelf)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + ){ + break; + } + } + if( pTerm drop loop %c not used\n", pLoop->cId)); + pWInfo->nLevel--; + nTabList--; + } + } + WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); + pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; + + /* If the caller is an UPDATE or DELETE statement that is requesting + ** to use a one-pass algorithm, determine if this is appropriate. + */ + assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); + if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ + int wsFlags = pWInfo->a[0].pWLoop->wsFlags; + int bOnerow = (wsFlags & WHERE_ONEROW)!=0; + if( bOnerow + || ((wctrlFlags & WHERE_ONEPASS_MULTIROW)!=0 + && 0==(wsFlags & WHERE_VIRTUALTABLE)) + ){ + pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; + if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ + if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ + bFordelete = OPFLAG_FORDELETE; + } + pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY); + } + } + } + + /* Open all tables in the pTabList and any indices selected for + ** searching those tables. + */ + for(ii=0, pLevel=pWInfo->a; iia[pLevel->iFrom]; + pTab = pTabItem->pTab; + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + pLoop = pLevel->pWLoop; + if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){ + /* Do nothing */ + }else +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ + const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); + int iCur = pTabItem->iCursor; + sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB); + }else if( IsVirtual(pTab) ){ + /* noop */ + }else +#endif + if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ + int op = OP_OpenRead; + if( pWInfo->eOnePass!=ONEPASS_OFF ){ + op = OP_OpenWrite; + pWInfo->aiCurOnePass[0] = pTabItem->iCursor; + }; + sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); + assert( pTabItem->iCursor==pLevel->iTabCur ); + testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 ); + testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS ); + if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nColcolUsed; + int n = 0; + for(; b; b=b>>1, n++){} + sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32); + assert( n<=pTab->nCol ); + } +#ifdef SQLITE_ENABLE_CURSOR_HINTS + if( pLoop->u.btree.pIndex!=0 ){ + sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete); + }else +#endif + { + sqlite3VdbeChangeP5(v, bFordelete); + } +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0, + (const u8*)&pTabItem->colUsed, P4_INT64); +#endif + }else{ + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + } + if( pLoop->wsFlags & WHERE_INDEXED ){ + 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 */ + assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); + if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) + && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 + ){ + /* This is one term of an OR-optimization using the PRIMARY KEY of a + ** WITHOUT ROWID table. No need for a separate index */ + iIndexCur = pLevel->iTabCur; + op = 0; + }else if( pWInfo->eOnePass!=ONEPASS_OFF ){ + Index *pJ = pTabItem->pTab->pIndex; + iIndexCur = iAuxArg; + assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); + while( ALWAYS(pJ) && pJ!=pIx ){ + iIndexCur++; + pJ = pJ->pNext; + } + op = OP_OpenWrite; + pWInfo->aiCurOnePass[1] = iIndexCur; + }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ + iIndexCur = iAuxArg; + op = OP_ReopenIdx; + }else{ + iIndexCur = pParse->nTab++; + } + pLevel->iIdxCur = iIndexCur; + assert( pIx->pSchema==pTab->pSchema ); + assert( iIndexCur>=0 ); + if( op ){ + sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIx); + if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 + && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 + && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 + && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED + ){ + sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ + } + VdbeComment((v, "%s", pIx->zName)); +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + { + u64 colUsed = 0; + int ii, jj; + for(ii=0; iinColumn; ii++){ + jj = pIx->aiColumn[ii]; + if( jj<0 ) continue; + if( jj>63 ) jj = 63; + if( (pTabItem->colUsed & MASKBIT(jj))==0 ) continue; + colUsed |= ((u64)1)<<(ii<63 ? ii : 63); + } + sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iIndexCur, 0, 0, + (u8*)&colUsed, P4_INT64); + } +#endif /* SQLITE_ENABLE_COLUMN_USED_MASK */ + } + } + if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); + } + pWInfo->iTop = sqlite3VdbeCurrentAddr(v); + if( db->mallocFailed ) goto whereBeginError; + + /* Generate the code to do the search. Each iteration of the for + ** loop below generates code for a single nested loop of the VM + ** program. + */ + notReady = ~(Bitmask)0; + for(ii=0; iia[ii]; + wsFlags = pLevel->pWLoop->wsFlags; +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX + if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ + constructAutomaticIndex(pParse, &pWInfo->sWC, + &pTabList->a[pLevel->iFrom], notReady, pLevel); + if( db->mallocFailed ) goto whereBeginError; + } +#endif + addrExplain = sqlite3WhereExplainOneScan( + pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags + ); + pLevel->addrBody = sqlite3VdbeCurrentAddr(v); + notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); + pWInfo->iContinue = pLevel->addrCont; + if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ + sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); + } + } + + /* Done. */ + VdbeModuleComment((v, "Begin WHERE-core")); + return pWInfo; + + /* Jump here if malloc fails */ +whereBeginError: + if( pWInfo ){ + pParse->nQueryLoop = pWInfo->savedNQueryLoop; + whereInfoFree(db, pWInfo); + } + return 0; +} + +/* +** Generate the end of the WHERE loop. See comments on +** sqlite3WhereBegin() for additional information. +*/ +SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ + Parse *pParse = pWInfo->pParse; + Vdbe *v = pParse->pVdbe; + int i; + WhereLevel *pLevel; + WhereLoop *pLoop; + SrcList *pTabList = pWInfo->pTabList; + sqlite3 *db = pParse->db; + + /* Generate loop termination code. + */ + VdbeModuleComment((v, "End WHERE-core")); + sqlite3ExprCacheClear(pParse); + for(i=pWInfo->nLevel-1; i>=0; i--){ + int addr; + pLevel = &pWInfo->a[i]; + pLoop = pLevel->pWLoop; + if( pLevel->op!=OP_Noop ){ +#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + int addrSeek = 0; + Index *pIdx; + int n; + if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED + && (pLoop->wsFlags & WHERE_INDEXED)!=0 + && (pIdx = pLoop->u.btree.pIndex)->hasStat1 + && (n = pLoop->u.btree.nIdxCol)>0 + && pIdx->aiRowLogEst[n]>=36 + ){ + int r1 = pParse->nMem+1; + int j, op; + for(j=0; jiIdxCur, j, r1+j); + } + pParse->nMem += n+1; + op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT; + addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n); + VdbeCoverageIf(v, op==OP_SeekLT); + VdbeCoverageIf(v, op==OP_SeekGT); + sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); + } +#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ + /* The common case: Advance to the next row */ + sqlite3VdbeResolveLabel(v, pLevel->addrCont); + sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); + sqlite3VdbeChangeP5(v, pLevel->p5); + VdbeCoverage(v); + VdbeCoverageIf(v, pLevel->op==OP_Next); + VdbeCoverageIf(v, pLevel->op==OP_Prev); + VdbeCoverageIf(v, pLevel->op==OP_VNext); +#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); +#endif + }else{ + sqlite3VdbeResolveLabel(v, pLevel->addrCont); + } + if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ + struct InLoop *pIn; + int j; + sqlite3VdbeResolveLabel(v, pLevel->addrNxt); + for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ + sqlite3VdbeJumpHere(v, pIn->addrInTop+1); + if( pIn->eEndLoopOp!=OP_Noop ){ + sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); + VdbeCoverage(v); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); + } + sqlite3VdbeJumpHere(v, pIn->addrInTop-1); + } + } + sqlite3VdbeResolveLabel(v, pLevel->addrBrk); + if( pLevel->addrSkip ){ + sqlite3VdbeGoto(v, pLevel->addrSkip); + VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); + sqlite3VdbeJumpHere(v, pLevel->addrSkip); + sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); + } +#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS + if( pLevel->addrLikeRep ){ + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1), + pLevel->addrLikeRep); + VdbeCoverage(v); + } +#endif + if( pLevel->iLeftJoin ){ + int ws = pLoop->wsFlags; + addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); + assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); + if( (ws & WHERE_IDX_ONLY)==0 ){ + sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor); + } + if( (ws & WHERE_INDEXED) + || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx) + ){ + sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); + } + if( pLevel->op==OP_Return ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst); + }else{ + sqlite3VdbeGoto(v, pLevel->addrFirst); + } + sqlite3VdbeJumpHere(v, addr); + } + VdbeModuleComment((v, "End WHERE-loop%d: %s", i, + pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); + } + + /* The "break" point is here, just past the end of the outer loop. + ** Set it. + */ + sqlite3VdbeResolveLabel(v, pWInfo->iBreak); + + assert( pWInfo->nLevel<=pTabList->nSrc ); + for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ + int k, last; + VdbeOp *pOp; + Index *pIdx = 0; + struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; + Table *pTab = pTabItem->pTab; + assert( pTab!=0 ); + pLoop = pLevel->pWLoop; + + /* For a co-routine, change all OP_Column references to the table of + ** the co-routine into OP_Copy of result contained in a register. + ** OP_Rowid becomes OP_Null. + */ + if( pTabItem->fg.viaCoroutine ){ + testcase( pParse->db->mallocFailed ); + translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, + pTabItem->regResult, 0); + continue; + } + + /* If this scan uses an index, make VDBE code substitutions to read data + ** from the index instead of from the table where possible. In some cases + ** this optimization prevents the table from ever being read, which can + ** yield a significant performance boost. + ** + ** Calls to the code generator in between sqlite3WhereBegin and + ** sqlite3WhereEnd will have created code that references the table + ** directly. This loop scans all that code looking for opcodes + ** that reference the table and converts them into opcodes that + ** reference the index. + */ + if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ + pIdx = pLoop->u.btree.pIndex; + }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ + pIdx = pLevel->u.pCovidx; + } + if( pIdx + && (pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable)) + && !db->mallocFailed + ){ + last = sqlite3VdbeCurrentAddr(v); + k = pLevel->addrBody; + pOp = sqlite3VdbeGetOp(v, k); + for(; kp1!=pLevel->iTabCur ) continue; + if( pOp->opcode==OP_Column ){ + int x = pOp->p2; + assert( pIdx->pTable==pTab ); + if( !HasRowid(pTab) ){ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + x = pPk->aiColumn[x]; + assert( x>=0 ); + } + x = sqlite3ColumnOfIndex(pIdx, x); + if( x>=0 ){ + pOp->p2 = x; + pOp->p1 = pLevel->iIdxCur; + } + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 + || pWInfo->eOnePass ); + }else if( pOp->opcode==OP_Rowid ){ + pOp->p1 = pLevel->iIdxCur; + pOp->opcode = OP_IdxRowid; + }else if( pOp->opcode==OP_IfNullRow ){ + pOp->p1 = pLevel->iIdxCur; + } + } + } + } + + /* Final cleanup + */ + pParse->nQueryLoop = pWInfo->savedNQueryLoop; + whereInfoFree(db, pWInfo); + return; +} + +/************** End of where.c ***********************************************/ +/************** Begin file parse.c *******************************************/ +/* +** 2000-05-29 +** +** 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. +** +************************************************************************* +** Driver template for the LEMON parser generator. +** +** The "lemon" program processes an LALR(1) input grammar file, then uses +** this template to construct a parser. The "lemon" program inserts text +** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** interstitial "-" characters) contained in this template is changed into +** the value of the %name directive from the grammar. Otherwise, the content +** of this template is copied straight through into the generate parser +** source file. +** +** The following is the concatenation of all %include directives from the +** input grammar file: +*/ +/* #include */ +/************ Begin %include sections from the grammar ************************/ + +/* #include "sqliteInt.h" */ + +/* +** Disable all error recovery processing in the parser push-down +** automaton. +*/ +#define YYNOERRORRECOVERY 1 + +/* +** Make yytestcase() the same as testcase() +*/ +#define yytestcase(X) testcase(X) + +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define YYPARSEFREENEVERNULL 1 + +/* +** In the amalgamation, the parse.c file generated by lemon and the +** tokenize.c file are concatenated. In that case, sqlite3RunParser() +** has access to the the size of the yyParser object and so the parser +** engine can be allocated from stack. In that case, only the +** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked +** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be +** omitted. +*/ +#ifdef SQLITE_AMALGAMATION +# define sqlite3Parser_ENGINEALWAYSONSTACK 1 +#endif + +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define YYMALLOCARGTYPE u64 + +/* +** An instance of this structure holds information about the +** LIMIT clause of a SELECT statement. +*/ +struct LimitVal { + Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */ + Expr *pOffset; /* The OFFSET expression. NULL if there is none */ +}; + +/* +** An instance of the following structure describes the event of a +** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, +** TK_DELETE, or TK_INSTEAD. If the event is of the form +** +** UPDATE ON (a,b,c) +** +** Then the "b" IdList records the list "a,b,c". +*/ +struct TrigEvent { int a; IdList * b; }; + +/* +** Disable lookaside memory allocation for objects that might be +** shared across database connections. +*/ +static void disableLookaside(Parse *pParse){ + pParse->disableLookaside++; + pParse->db->lookaside.bDisable++; +} + + + /* + ** For a compound SELECT statement, make sure p->pPrior->pNext==p for + ** all elements in the list. And make sure list length does not exceed + ** SQLITE_LIMIT_COMPOUND_SELECT. + */ + static void parserDoubleLinkSelect(Parse *pParse, Select *p){ + if( p->pPrior ){ + Select *pNext = 0, *pLoop; + int mxSelect, cnt = 0; + for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ + pLoop->pNext = pNext; + pLoop->selFlags |= SF_Compound; + } + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect + ){ + sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); + } + } + } + + /* This is a utility routine used to set the ExprSpan.zStart and + ** ExprSpan.zEnd values of pOut so that the span covers the complete + ** range of text beginning with pStart and going to the end of pEnd. + */ + static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){ + pOut->zStart = pStart->z; + pOut->zEnd = &pEnd->z[pEnd->n]; + } + + /* Construct a new Expr object from a single identifier. Use the + ** new Expr to populate pOut. Set the span of pOut to be the identifier + ** that created the expression. + */ + static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){ + Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = (u8)op; + p->flags = EP_Leaf; + p->iAgg = -1; + p->u.zToken = (char*)&p[1]; + memcpy(p->u.zToken, t.z, t.n); + p->u.zToken[t.n] = 0; + if( sqlite3Isquote(p->u.zToken[0]) ){ + if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted; + sqlite3Dequote(p->u.zToken); + } +#if SQLITE_MAX_EXPR_DEPTH>0 + p->nHeight = 1; +#endif + } + pOut->pExpr = p; + pOut->zStart = t.z; + pOut->zEnd = &t.z[t.n]; + } + + /* This routine constructs a binary expression node out of two ExprSpan + ** objects and uses the result to populate a new ExprSpan object. + */ + static void spanBinaryExpr( + Parse *pParse, /* The parsing context. Errors accumulate here */ + int op, /* The binary operation */ + ExprSpan *pLeft, /* The left operand, and output */ + ExprSpan *pRight /* The right operand */ + ){ + pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr); + pLeft->zEnd = pRight->zEnd; + } + + /* If doNot is true, then add a TK_NOT Expr-node wrapper around the + ** outside of *ppExpr. + */ + static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){ + if( doNot ){ + pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0); + } + } + + /* Construct an expression node for a unary postfix operator + */ + static void spanUnaryPostfix( + Parse *pParse, /* Parsing context to record errors */ + int op, /* The operator */ + ExprSpan *pOperand, /* The operand, and output */ + Token *pPostOp /* The operand token for setting the span */ + ){ + pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); + pOperand->zEnd = &pPostOp->z[pPostOp->n]; + } + + /* A routine to convert a binary TK_IS or TK_ISNOT expression into a + ** unary TK_ISNULL or TK_NOTNULL expression. */ + static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ + sqlite3 *db = pParse->db; + if( pA && pY && pY->op==TK_NULL ){ + pA->op = (u8)op; + sqlite3ExprDelete(db, pA->pRight); + pA->pRight = 0; + } + } + + /* Construct an expression node for a unary prefix operator + */ + static void spanUnaryPrefix( + ExprSpan *pOut, /* Write the new expression node here */ + Parse *pParse, /* Parsing context to record errors */ + int op, /* The operator */ + ExprSpan *pOperand, /* The operand */ + Token *pPreOp /* The operand token for setting the span */ + ){ + pOut->zStart = pPreOp->z; + pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); + pOut->zEnd = pOperand->zEnd; + } + + /* Add a single new term to an ExprList that is used to store a + ** list of identifiers. Report an error if the ID list contains + ** a COLLATE clause or an ASC or DESC keyword, except ignore the + ** error while parsing a legacy schema. + */ + static ExprList *parserAddExprIdListTerm( + Parse *pParse, + ExprList *pPrior, + Token *pIdToken, + int hasCollate, + int sortOrder + ){ + ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); + if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) + && pParse->db->init.busy==0 + ){ + sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", + pIdToken->n, pIdToken->z); + } + sqlite3ExprListSetName(pParse, p, pIdToken, 1); + return p; + } +/**************** End of %include directives **********************************/ +/* These constants specify the various numeric values for terminal symbols +** in a format understandable to "makeheaders". This section is blank unless +** "lemon" is run with the "-m" command-line option. +***************** Begin makeheaders token definitions *************************/ +/**************** End makeheaders token definitions ***************************/ + +/* The next sections is a series of control #defines. +** various aspects of the generated parser. +** YYCODETYPE is the data type used to store the integer codes +** that represent terminal and non-terminal symbols. +** "unsigned char" is used if there are fewer than +** 256 symbols. Larger types otherwise. +** YYNOCODE is a number of type YYCODETYPE that is not used for +** any terminal or nonterminal symbol. +** YYFALLBACK If defined, this indicates that one or more tokens +** (also known as: "terminal symbols") have fall-back +** values which should be used if the original symbol +** would not parse. This permits keywords to sometimes +** be used as identifiers, for example. +** YYACTIONTYPE is the data type used for "action codes" - numbers +** that indicate what to do in response to the next +** token. +** sqlite3ParserTOKENTYPE is the data type used for minor type for terminal +** symbols. Background: A "minor type" is a semantic +** value associated with a terminal or non-terminal +** symbols. For example, for an "ID" terminal symbol, +** the minor type might be the name of the identifier. +** Each non-terminal can have a different minor type. +** Terminal symbols all have the same minor type, though. +** This macros defines the minor type for terminal +** symbols. +** YYMINORTYPE is the data type used for all minor types. +** This is typically a union of many types, one of +** which is sqlite3ParserTOKENTYPE. The entry in the union +** for terminal symbols is called "yy0". +** YYSTACKDEPTH is the maximum depth of the parser's stack. If +** zero the stack is dynamically sized using realloc() +** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument +** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument +** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser +** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser +** YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** 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_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 +*/ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/************* Begin control #defines *****************************************/ +#define YYCODETYPE unsigned char +#define YYNOCODE 252 +#define YYACTIONTYPE unsigned short int +#define YYWILDCARD 69 +#define sqlite3ParserTOKENTYPE Token +typedef union { + int yyinit; + sqlite3ParserTOKENTYPE yy0; + Expr* yy72; + TriggerStep* yy145; + ExprList* yy148; + SrcList* yy185; + ExprSpan yy190; + int yy194; + Select* yy243; + IdList* yy254; + With* yy285; + struct TrigEvent yy332; + struct LimitVal yy354; + struct {int value; int mask;} yy497; +} YYMINORTYPE; +#ifndef YYSTACKDEPTH +#define YYSTACKDEPTH 100 +#endif +#define sqlite3ParserARG_SDECL Parse *pParse; +#define sqlite3ParserARG_PDECL ,Parse *pParse +#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse +#define sqlite3ParserARG_STORE yypParser->pParse = pParse +#define YYFALLBACK 1 +#define YYNSTATE 456 +#define YYNRULE 332 +#define YY_MAX_SHIFT 455 +#define YY_MIN_SHIFTREDUCE 668 +#define YY_MAX_SHIFTREDUCE 999 +#define YY_MIN_REDUCE 1000 +#define YY_MAX_REDUCE 1331 +#define YY_ERROR_ACTION 1332 +#define YY_ACCEPT_ACTION 1333 +#define YY_NO_ACTION 1334 +/************* End control #defines *******************************************/ + +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. +** +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. +*/ +#ifndef yytestcase +# define yytestcase(X) +#endif + + +/* Next are the tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead +** token onto the stack and goto state N. +** +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. +** +** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE +** and YY_MAX_REDUCE +** +** N == YY_ERROR_ACTION A syntax error has occurred. +** +** N == YY_ACCEPT_ACTION The parser accepts its input. +** +** N == YY_NO_ACTION No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large table named yy_action[]. +** Given state S and lookahead X, the action is computed as either: +** +** (A) N = yy_action[ yy_shift_ofst[S] + X ] +** (B) N = yy_default[S] +** +** The (A) formula is preferred. The B formula is used instead if: +** (1) The yy_shift_ofst[S]+X value is out of range, or +** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or +** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. +** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that +** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) +** +** The formulas above are for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the yy_reduce_ofst[] array is used in place of +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of +** YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** yy_action[] A single table containing all actions. +** yy_lookahead[] A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** yy_shift_ofst[] For each state, the offset into yy_action for +** shifting terminals. +** yy_reduce_ofst[] For each state, the offset into yy_action for +** shifting non-terminals after a reduce. +** yy_default[] Default action for each state. +** +*********** Begin parsing tables **********************************************/ +#define YY_ACTTAB_COUNT (1566) +static const YYACTIONTYPE yy_action[] = { + /* 0 */ 325, 411, 343, 752, 752, 203, 946, 354, 976, 98, + /* 10 */ 98, 98, 98, 91, 96, 96, 96, 96, 95, 95, + /* 20 */ 94, 94, 94, 93, 351, 1333, 155, 155, 2, 813, + /* 30 */ 978, 978, 98, 98, 98, 98, 20, 96, 96, 96, + /* 40 */ 96, 95, 95, 94, 94, 94, 93, 351, 92, 89, + /* 50 */ 178, 99, 100, 90, 853, 856, 845, 845, 97, 97, + /* 60 */ 98, 98, 98, 98, 351, 96, 96, 96, 96, 95, + /* 70 */ 95, 94, 94, 94, 93, 351, 325, 340, 976, 262, + /* 80 */ 365, 251, 212, 169, 287, 405, 282, 404, 199, 791, + /* 90 */ 242, 412, 21, 957, 379, 280, 93, 351, 792, 95, + /* 100 */ 95, 94, 94, 94, 93, 351, 978, 978, 96, 96, + /* 110 */ 96, 96, 95, 95, 94, 94, 94, 93, 351, 813, + /* 120 */ 329, 242, 412, 913, 832, 913, 132, 99, 100, 90, + /* 130 */ 853, 856, 845, 845, 97, 97, 98, 98, 98, 98, + /* 140 */ 450, 96, 96, 96, 96, 95, 95, 94, 94, 94, + /* 150 */ 93, 351, 325, 825, 349, 348, 120, 819, 120, 75, + /* 160 */ 52, 52, 957, 958, 959, 760, 984, 146, 361, 262, + /* 170 */ 370, 261, 957, 982, 961, 983, 92, 89, 178, 371, + /* 180 */ 230, 371, 978, 978, 817, 361, 360, 101, 824, 824, + /* 190 */ 826, 384, 24, 964, 381, 428, 413, 369, 985, 380, + /* 200 */ 985, 708, 325, 99, 100, 90, 853, 856, 845, 845, + /* 210 */ 97, 97, 98, 98, 98, 98, 373, 96, 96, 96, + /* 220 */ 96, 95, 95, 94, 94, 94, 93, 351, 957, 132, + /* 230 */ 897, 450, 978, 978, 896, 60, 94, 94, 94, 93, + /* 240 */ 351, 957, 958, 959, 961, 103, 361, 957, 385, 334, + /* 250 */ 702, 52, 52, 99, 100, 90, 853, 856, 845, 845, + /* 260 */ 97, 97, 98, 98, 98, 98, 698, 96, 96, 96, + /* 270 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 455, + /* 280 */ 670, 450, 227, 61, 157, 243, 344, 114, 701, 888, + /* 290 */ 147, 832, 957, 373, 747, 957, 320, 957, 958, 959, + /* 300 */ 194, 10, 10, 402, 399, 398, 888, 890, 978, 978, + /* 310 */ 762, 171, 170, 157, 397, 337, 957, 958, 959, 702, + /* 320 */ 825, 310, 153, 957, 819, 321, 82, 23, 80, 99, + /* 330 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98, + /* 340 */ 98, 98, 894, 96, 96, 96, 96, 95, 95, 94, + /* 350 */ 94, 94, 93, 351, 325, 824, 824, 826, 277, 231, + /* 360 */ 300, 957, 958, 959, 957, 958, 959, 888, 194, 25, + /* 370 */ 450, 402, 399, 398, 957, 355, 300, 450, 957, 74, + /* 380 */ 450, 1, 397, 132, 978, 978, 957, 224, 224, 813, + /* 390 */ 10, 10, 957, 958, 959, 968, 132, 52, 52, 415, + /* 400 */ 52, 52, 739, 739, 339, 99, 100, 90, 853, 856, + /* 410 */ 845, 845, 97, 97, 98, 98, 98, 98, 790, 96, + /* 420 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351, + /* 430 */ 325, 789, 428, 418, 706, 428, 427, 1270, 1270, 262, + /* 440 */ 370, 261, 957, 957, 958, 959, 757, 957, 958, 959, + /* 450 */ 450, 756, 450, 734, 713, 957, 958, 959, 443, 711, + /* 460 */ 978, 978, 734, 394, 92, 89, 178, 447, 447, 447, + /* 470 */ 51, 51, 52, 52, 439, 778, 700, 92, 89, 178, + /* 480 */ 172, 99, 100, 90, 853, 856, 845, 845, 97, 97, + /* 490 */ 98, 98, 98, 98, 198, 96, 96, 96, 96, 95, + /* 500 */ 95, 94, 94, 94, 93, 351, 325, 428, 408, 916, + /* 510 */ 699, 957, 958, 959, 92, 89, 178, 224, 224, 157, + /* 520 */ 241, 221, 419, 299, 776, 917, 416, 375, 450, 415, + /* 530 */ 58, 324, 737, 737, 920, 379, 978, 978, 379, 777, + /* 540 */ 449, 918, 363, 740, 296, 686, 9, 9, 52, 52, + /* 550 */ 234, 330, 234, 256, 417, 741, 280, 99, 100, 90, + /* 560 */ 853, 856, 845, 845, 97, 97, 98, 98, 98, 98, + /* 570 */ 450, 96, 96, 96, 96, 95, 95, 94, 94, 94, + /* 580 */ 93, 351, 325, 423, 72, 450, 833, 120, 368, 450, + /* 590 */ 10, 10, 5, 301, 203, 450, 177, 976, 253, 420, + /* 600 */ 255, 776, 200, 175, 233, 10, 10, 842, 842, 36, + /* 610 */ 36, 1299, 978, 978, 729, 37, 37, 349, 348, 425, + /* 620 */ 203, 260, 776, 976, 232, 937, 1326, 876, 338, 1326, + /* 630 */ 422, 854, 857, 99, 100, 90, 853, 856, 845, 845, + /* 640 */ 97, 97, 98, 98, 98, 98, 268, 96, 96, 96, + /* 650 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 846, + /* 660 */ 450, 985, 818, 985, 1209, 450, 916, 976, 720, 350, + /* 670 */ 350, 350, 935, 177, 450, 937, 1327, 254, 198, 1327, + /* 680 */ 12, 12, 917, 403, 450, 27, 27, 250, 978, 978, + /* 690 */ 118, 721, 162, 976, 38, 38, 268, 176, 918, 776, + /* 700 */ 433, 1275, 946, 354, 39, 39, 317, 998, 325, 99, + /* 710 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98, + /* 720 */ 98, 98, 935, 96, 96, 96, 96, 95, 95, 94, + /* 730 */ 94, 94, 93, 351, 450, 330, 450, 358, 978, 978, + /* 740 */ 717, 317, 936, 341, 900, 900, 387, 673, 674, 675, + /* 750 */ 275, 996, 318, 999, 40, 40, 41, 41, 268, 99, + /* 760 */ 100, 90, 853, 856, 845, 845, 97, 97, 98, 98, + /* 770 */ 98, 98, 450, 96, 96, 96, 96, 95, 95, 94, + /* 780 */ 94, 94, 93, 351, 325, 450, 356, 450, 999, 450, + /* 790 */ 692, 331, 42, 42, 791, 270, 450, 273, 450, 228, + /* 800 */ 450, 298, 450, 792, 450, 28, 28, 29, 29, 31, + /* 810 */ 31, 450, 817, 450, 978, 978, 43, 43, 44, 44, + /* 820 */ 45, 45, 11, 11, 46, 46, 893, 78, 893, 268, + /* 830 */ 268, 105, 105, 47, 47, 99, 100, 90, 853, 856, + /* 840 */ 845, 845, 97, 97, 98, 98, 98, 98, 450, 96, + /* 850 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351, + /* 860 */ 325, 450, 117, 450, 749, 158, 450, 696, 48, 48, + /* 870 */ 229, 919, 450, 928, 450, 415, 450, 335, 450, 245, + /* 880 */ 450, 33, 33, 49, 49, 450, 50, 50, 246, 817, + /* 890 */ 978, 978, 34, 34, 122, 122, 123, 123, 124, 124, + /* 900 */ 56, 56, 268, 81, 249, 35, 35, 197, 196, 195, + /* 910 */ 325, 99, 100, 90, 853, 856, 845, 845, 97, 97, + /* 920 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95, + /* 930 */ 95, 94, 94, 94, 93, 351, 450, 696, 450, 817, + /* 940 */ 978, 978, 975, 884, 106, 106, 268, 886, 268, 944, + /* 950 */ 2, 892, 268, 892, 336, 716, 53, 53, 107, 107, + /* 960 */ 325, 99, 100, 90, 853, 856, 845, 845, 97, 97, + /* 970 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95, + /* 980 */ 95, 94, 94, 94, 93, 351, 450, 746, 450, 742, + /* 990 */ 978, 978, 715, 267, 108, 108, 446, 331, 332, 133, + /* 1000 */ 223, 175, 301, 225, 386, 933, 104, 104, 121, 121, + /* 1010 */ 325, 99, 88, 90, 853, 856, 845, 845, 97, 97, + /* 1020 */ 98, 98, 98, 98, 817, 96, 96, 96, 96, 95, + /* 1030 */ 95, 94, 94, 94, 93, 351, 450, 347, 450, 167, + /* 1040 */ 978, 978, 932, 815, 372, 319, 202, 202, 374, 263, + /* 1050 */ 395, 202, 74, 208, 726, 727, 119, 119, 112, 112, + /* 1060 */ 325, 407, 100, 90, 853, 856, 845, 845, 97, 97, + /* 1070 */ 98, 98, 98, 98, 450, 96, 96, 96, 96, 95, + /* 1080 */ 95, 94, 94, 94, 93, 351, 450, 757, 450, 345, + /* 1090 */ 978, 978, 756, 278, 111, 111, 74, 719, 718, 709, + /* 1100 */ 286, 883, 754, 1289, 257, 77, 109, 109, 110, 110, + /* 1110 */ 908, 285, 810, 90, 853, 856, 845, 845, 97, 97, + /* 1120 */ 98, 98, 98, 98, 911, 96, 96, 96, 96, 95, + /* 1130 */ 95, 94, 94, 94, 93, 351, 86, 445, 450, 3, + /* 1140 */ 1202, 450, 745, 132, 352, 120, 689, 86, 445, 785, + /* 1150 */ 3, 767, 202, 377, 448, 352, 907, 120, 55, 55, + /* 1160 */ 450, 57, 57, 828, 879, 448, 450, 208, 450, 709, + /* 1170 */ 450, 883, 237, 434, 436, 120, 440, 429, 362, 120, + /* 1180 */ 54, 54, 132, 450, 434, 832, 52, 52, 26, 26, + /* 1190 */ 30, 30, 382, 132, 409, 444, 832, 694, 264, 390, + /* 1200 */ 116, 269, 272, 32, 32, 83, 84, 120, 274, 120, + /* 1210 */ 120, 276, 85, 352, 452, 451, 83, 84, 819, 730, + /* 1220 */ 714, 428, 430, 85, 352, 452, 451, 120, 120, 819, + /* 1230 */ 378, 218, 281, 828, 783, 816, 86, 445, 410, 3, + /* 1240 */ 763, 774, 431, 432, 352, 302, 303, 823, 697, 824, + /* 1250 */ 824, 826, 827, 19, 448, 691, 680, 679, 681, 951, + /* 1260 */ 824, 824, 826, 827, 19, 289, 159, 291, 293, 7, + /* 1270 */ 316, 173, 259, 434, 805, 364, 252, 910, 376, 713, + /* 1280 */ 295, 435, 168, 993, 400, 832, 284, 881, 880, 205, + /* 1290 */ 954, 308, 927, 86, 445, 990, 3, 925, 333, 144, + /* 1300 */ 130, 352, 72, 135, 59, 83, 84, 761, 137, 366, + /* 1310 */ 802, 448, 85, 352, 452, 451, 139, 226, 819, 140, + /* 1320 */ 156, 62, 315, 314, 313, 215, 311, 367, 393, 683, + /* 1330 */ 434, 185, 141, 912, 142, 160, 148, 812, 875, 383, + /* 1340 */ 189, 67, 832, 180, 389, 248, 895, 775, 219, 824, + /* 1350 */ 824, 826, 827, 19, 247, 190, 266, 154, 391, 271, + /* 1360 */ 191, 192, 83, 84, 682, 406, 733, 182, 322, 85, + /* 1370 */ 352, 452, 451, 732, 183, 819, 342, 132, 181, 711, + /* 1380 */ 731, 421, 76, 445, 705, 3, 323, 704, 283, 724, + /* 1390 */ 352, 771, 703, 966, 723, 71, 204, 6, 288, 290, + /* 1400 */ 448, 772, 770, 769, 79, 292, 824, 824, 826, 827, + /* 1410 */ 19, 294, 297, 438, 346, 442, 102, 861, 753, 434, + /* 1420 */ 238, 426, 73, 305, 239, 304, 326, 240, 424, 306, + /* 1430 */ 307, 832, 213, 688, 22, 952, 453, 214, 216, 217, + /* 1440 */ 454, 677, 115, 676, 671, 125, 126, 235, 127, 669, + /* 1450 */ 327, 83, 84, 359, 353, 244, 166, 328, 85, 352, + /* 1460 */ 452, 451, 134, 179, 819, 357, 113, 891, 811, 889, + /* 1470 */ 136, 128, 138, 743, 258, 184, 906, 143, 145, 63, + /* 1480 */ 64, 65, 66, 129, 909, 905, 187, 186, 8, 13, + /* 1490 */ 188, 265, 898, 149, 202, 824, 824, 826, 827, 19, + /* 1500 */ 388, 987, 150, 161, 285, 685, 392, 396, 151, 722, + /* 1510 */ 193, 68, 14, 401, 279, 15, 69, 236, 831, 830, + /* 1520 */ 131, 859, 751, 70, 16, 414, 755, 4, 784, 220, + /* 1530 */ 222, 174, 152, 437, 779, 201, 17, 77, 74, 18, + /* 1540 */ 874, 860, 858, 915, 863, 914, 207, 206, 941, 163, + /* 1550 */ 210, 942, 209, 164, 441, 862, 165, 211, 829, 695, + /* 1560 */ 87, 312, 309, 947, 1291, 1290, +}; +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, 151, 165, 165, 178, 165, 4, + /* 1450 */ 249, 88, 89, 141, 3, 142, 22, 249, 95, 96, + /* 1460 */ 97, 98, 246, 15, 101, 67, 16, 23, 120, 23, + /* 1470 */ 131, 111, 123, 20, 16, 125, 1, 123, 131, 78, + /* 1480 */ 78, 78, 78, 111, 96, 1, 122, 35, 5, 22, + /* 1490 */ 107, 140, 53, 53, 26, 132, 133, 134, 135, 136, + /* 1500 */ 43, 60, 107, 24, 112, 20, 19, 52, 22, 29, + /* 1510 */ 105, 22, 22, 52, 23, 22, 22, 52, 23, 23, + /* 1520 */ 39, 23, 116, 26, 22, 26, 23, 22, 96, 23, + /* 1530 */ 23, 122, 22, 24, 124, 35, 35, 26, 26, 35, + /* 1540 */ 23, 23, 23, 23, 11, 23, 22, 26, 23, 22, + /* 1550 */ 122, 23, 26, 22, 24, 23, 22, 122, 23, 23, + /* 1560 */ 22, 15, 23, 1, 122, 122, +}; +#define YY_SHIFT_USE_DFLT (1566) +#define YY_SHIFT_COUNT (455) +#define YY_SHIFT_MIN (-114) +#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, 1566, 1566, 1566, -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, 1566, 1566, 1566, 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, 1433, 1566, 1566, 1566, + /* 320 */ 1566, 1566, 1566, 1566, 1566, 558, 537, 684, 719, 734, + /* 330 */ 799, 840, 1019, 14, 1020, 1021, 1025, 1026, 1027, 1070, + /* 340 */ 1072, 997, 1047, 999, 1079, 1126, 1074, 1141, 694, 819, + /* 350 */ 1174, 1136, 981, 1445, 1451, 1434, 1313, 1448, 1398, 1450, + /* 360 */ 1444, 1446, 1348, 1339, 1360, 1349, 1453, 1350, 1458, 1475, + /* 370 */ 1354, 1347, 1401, 1402, 1403, 1404, 1372, 1388, 1452, 1364, + /* 380 */ 1484, 1483, 1467, 1383, 1351, 1439, 1468, 1440, 1441, 1457, + /* 390 */ 1395, 1479, 1485, 1487, 1392, 1405, 1486, 1455, 1489, 1490, + /* 400 */ 1491, 1493, 1461, 1480, 1494, 1465, 1481, 1495, 1496, 1498, + /* 410 */ 1497, 1406, 1502, 1503, 1505, 1499, 1409, 1506, 1507, 1432, + /* 420 */ 1500, 1510, 1410, 1511, 1501, 1512, 1504, 1517, 1511, 1518, + /* 430 */ 1519, 1520, 1521, 1522, 1524, 1533, 1525, 1527, 1509, 1526, + /* 440 */ 1528, 1531, 1530, 1526, 1532, 1534, 1535, 1536, 1538, 1428, + /* 450 */ 1435, 1442, 1443, 1539, 1546, 1562, +}; +#define YY_REDUCE_USE_DFLT (-174) +#define YY_REDUCE_COUNT (324) +#define YY_REDUCE_MIN (-173) +#define YY_REDUCE_MAX (1293) +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, 1293, 1201, 1208, 1216, + /* 320 */ 1280, 1281, 1264, 1269, 1283, +}; +static const YYACTIONTYPE yy_default[] = { + /* 0 */ 1280, 1270, 1270, 1270, 1202, 1202, 1202, 1202, 1270, 1096, + /* 10 */ 1125, 1125, 1254, 1332, 1332, 1332, 1332, 1332, 1332, 1201, + /* 20 */ 1332, 1332, 1332, 1332, 1270, 1100, 1131, 1332, 1332, 1332, + /* 30 */ 1332, 1203, 1204, 1332, 1332, 1332, 1253, 1255, 1141, 1140, + /* 40 */ 1139, 1138, 1236, 1112, 1136, 1129, 1133, 1203, 1197, 1198, + /* 50 */ 1196, 1200, 1204, 1332, 1132, 1167, 1181, 1166, 1332, 1332, + /* 60 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 70 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 80 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 90 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 100 */ 1332, 1332, 1332, 1332, 1175, 1180, 1187, 1179, 1176, 1169, + /* 110 */ 1168, 1170, 1171, 1332, 1019, 1067, 1332, 1332, 1332, 1172, + /* 120 */ 1332, 1173, 1184, 1183, 1182, 1261, 1288, 1287, 1332, 1332, + /* 130 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 140 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 150 */ 1332, 1332, 1332, 1332, 1332, 1280, 1270, 1025, 1025, 1332, + /* 160 */ 1270, 1270, 1270, 1270, 1270, 1270, 1266, 1100, 1091, 1332, + /* 170 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 180 */ 1258, 1256, 1332, 1217, 1332, 1332, 1332, 1332, 1332, 1332, + /* 190 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 200 */ 1332, 1332, 1332, 1332, 1096, 1332, 1332, 1332, 1332, 1332, + /* 210 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1282, 1332, 1231, + /* 220 */ 1096, 1096, 1096, 1098, 1080, 1090, 1004, 1135, 1114, 1114, + /* 230 */ 1321, 1135, 1321, 1042, 1302, 1039, 1125, 1114, 1199, 1125, + /* 240 */ 1125, 1097, 1090, 1332, 1324, 1105, 1105, 1323, 1323, 1105, + /* 250 */ 1146, 1070, 1135, 1076, 1076, 1076, 1076, 1105, 1016, 1135, + /* 260 */ 1146, 1070, 1070, 1135, 1105, 1016, 1235, 1318, 1105, 1105, + /* 270 */ 1016, 1210, 1105, 1016, 1105, 1016, 1210, 1068, 1068, 1068, + /* 280 */ 1057, 1210, 1068, 1042, 1068, 1057, 1068, 1068, 1118, 1113, + /* 290 */ 1118, 1113, 1118, 1113, 1118, 1113, 1105, 1205, 1105, 1332, + /* 300 */ 1210, 1214, 1214, 1210, 1130, 1119, 1128, 1126, 1135, 1022, + /* 310 */ 1060, 1285, 1285, 1281, 1281, 1281, 1281, 1329, 1329, 1266, + /* 320 */ 1297, 1297, 1044, 1044, 1297, 1332, 1332, 1332, 1332, 1332, + /* 330 */ 1332, 1292, 1332, 1219, 1332, 1332, 1332, 1332, 1332, 1332, + /* 340 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 350 */ 1332, 1332, 1152, 1332, 1000, 1263, 1332, 1332, 1262, 1332, + /* 360 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 370 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1320, + /* 380 */ 1332, 1332, 1332, 1332, 1332, 1332, 1234, 1233, 1332, 1332, + /* 390 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 400 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + /* 410 */ 1332, 1082, 1332, 1332, 1332, 1306, 1332, 1332, 1332, 1332, + /* 420 */ 1332, 1332, 1332, 1127, 1332, 1120, 1332, 1332, 1311, 1332, + /* 430 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1272, + /* 440 */ 1332, 1332, 1332, 1271, 1332, 1332, 1332, 1332, 1332, 1154, + /* 450 */ 1332, 1153, 1157, 1332, 1010, 1332, +}; +/********** End of lemon-generated parsing tables *****************************/ + +/* The next table maps tokens (terminal symbols) into fallback tokens. +** If a construct like the following: +** +** %fallback ID X Y Z. +** +** appears in the grammar, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. +** +** This feature can be used, for example, to cause some keywords in a language +** to revert to identifiers if they keyword does not apply in the context where +** it appears. +*/ +#ifdef YYFALLBACK +static const YYCODETYPE yyFallback[] = { + 0, /* $ => nothing */ + 0, /* SEMI => nothing */ + 27, /* EXPLAIN => ID */ + 27, /* QUERY => ID */ + 27, /* PLAN => ID */ + 27, /* BEGIN => ID */ + 0, /* TRANSACTION => nothing */ + 27, /* DEFERRED => ID */ + 27, /* IMMEDIATE => ID */ + 27, /* EXCLUSIVE => ID */ + 0, /* COMMIT => nothing */ + 27, /* END => ID */ + 27, /* ROLLBACK => ID */ + 27, /* SAVEPOINT => ID */ + 27, /* RELEASE => ID */ + 0, /* TO => nothing */ + 0, /* TABLE => nothing */ + 0, /* CREATE => nothing */ + 27, /* IF => ID */ + 0, /* NOT => nothing */ + 0, /* EXISTS => nothing */ + 27, /* TEMP => ID */ + 0, /* LP => nothing */ + 0, /* RP => nothing */ + 0, /* AS => nothing */ + 27, /* WITHOUT => ID */ + 0, /* COMMA => 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 */ +}; +#endif /* YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: +** +** + The state number for the parser at this level of the stack. +** +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) +** +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. +** +** After the "shift" half of a SHIFTREDUCE action, the stateno field +** actually contains the reduce action for the second half of the +** SHIFTREDUCE. +*/ +struct yyStackEntry { + YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct yyStackEntry yyStackEntry; + +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct yyParser { + yyStackEntry *yytos; /* Pointer to top element of the stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyhwm; /* High-water mark of the stack */ +#endif +#ifndef YYNOERRORRECOVERY + int yyerrcnt; /* Shifts left before out of the error */ +#endif + sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ +#endif +}; +typedef struct yyParser yyParser; + +#ifndef NDEBUG +/* #include */ +static FILE *yyTraceFILE = 0; +static char *yyTracePrompt = 0; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
      +**
    • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
    • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
    +** +** Outputs: +** None. +*/ +SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){ + yyTraceFILE = TraceFILE; + yyTracePrompt = zTracePrompt; + if( yyTraceFILE==0 ) yyTracePrompt = 0; + else if( yyTracePrompt==0 ) yyTraceFILE = 0; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *const yyTokenName[] = { + "$", "SEMI", "EXPLAIN", "QUERY", + "PLAN", "BEGIN", "TRANSACTION", "DEFERRED", + "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END", + "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", + "BITAND", "BITOR", "LSHIFT", "RSHIFT", + "PLUS", "MINUS", "STAR", "SLASH", + "REM", "CONCAT", "COLLATE", "BITNOT", + "INDEXED", "STRING", "JOIN_KW", "CONSTRAINT", + "DEFAULT", "NULL", "PRIMARY", "UNIQUE", + "CHECK", "REFERENCES", "AUTOINCR", "ON", + "INSERT", "DELETE", "UPDATE", "SET", + "DEFERRABLE", "FOREIGN", "DROP", "UNION", + "ALL", "EXCEPT", "INTERSECT", "SELECT", + "VALUES", "DISTINCT", "DOT", "FROM", + "JOIN", "USING", "ORDER", "GROUP", + "HAVING", "LIMIT", "WHERE", "INTO", + "FLOAT", "BLOB", "INTEGER", "VARIABLE", + "CASE", "WHEN", "THEN", "ELSE", + "INDEX", "ALTER", "ADD", "error", + "input", "cmdlist", "ecmd", "explain", + "cmdx", "cmd", "transtype", "trans_opt", + "nm", "savepoint_opt", "create_table", "create_table_args", + "createkw", "temp", "ifnotexists", "dbnm", + "columnlist", "conslist_opt", "table_options", "select", + "columnname", "carglist", "typetoken", "typename", + "signed", "plus_num", "minus_num", "ccons", + "term", "expr", "onconf", "sortorder", + "autoinc", "eidlist_opt", "refargs", "defer_subclause", + "refarg", "refact", "init_deferred_pred_opt", "conslist", + "tconscomma", "tcons", "sortlist", "eidlist", + "defer_subclause_opt", "orconf", "resolvetype", "raisetype", + "ifexists", "fullname", "selectnowith", "oneselect", + "with", "multiselect_op", "distinct", "selcollist", + "from", "where_opt", "groupby_opt", "having_opt", + "orderby_opt", "limit_opt", "values", "nexprlist", + "exprlist", "sclp", "as", "seltablist", + "stl_prefix", "joinop", "indexed_opt", "on_opt", + "using_opt", "idlist", "setlist", "insert_cmd", + "idlist_opt", "likeop", "between_op", "in_op", + "paren_exprlist", "case_operand", "case_exprlist", "case_else", + "uniqueflag", "collate", "nmnum", "trigger_decl", + "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause", + "when_clause", "trigger_cmd", "trnm", "tridxby", + "database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt", + "create_vtab", "vtabarglist", "vtabarg", "vtabargtoken", + "lp", "anylist", "wqlist", +}; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *const yyRuleName[] = { + /* 0 */ "explain ::= EXPLAIN", + /* 1 */ "explain ::= EXPLAIN QUERY PLAN", + /* 2 */ "cmdx ::= cmd", + /* 3 */ "cmd ::= BEGIN transtype trans_opt", + /* 4 */ "transtype ::=", + /* 5 */ "transtype ::= DEFERRED", + /* 6 */ "transtype ::= IMMEDIATE", + /* 7 */ "transtype ::= EXCLUSIVE", + /* 8 */ "cmd ::= COMMIT trans_opt", + /* 9 */ "cmd ::= END trans_opt", + /* 10 */ "cmd ::= ROLLBACK trans_opt", + /* 11 */ "cmd ::= SAVEPOINT nm", + /* 12 */ "cmd ::= RELEASE savepoint_opt nm", + /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", + /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", + /* 15 */ "createkw ::= CREATE", + /* 16 */ "ifnotexists ::=", + /* 17 */ "ifnotexists ::= IF NOT EXISTS", + /* 18 */ "temp ::= TEMP", + /* 19 */ "temp ::=", + /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_options", + /* 21 */ "create_table_args ::= AS select", + /* 22 */ "table_options ::=", + /* 23 */ "table_options ::= WITHOUT nm", + /* 24 */ "columnname ::= nm typetoken", + /* 25 */ "typetoken ::=", + /* 26 */ "typetoken ::= typename LP signed RP", + /* 27 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 28 */ "typename ::= typename ID|STRING", + /* 29 */ "ccons ::= CONSTRAINT nm", + /* 30 */ "ccons ::= DEFAULT term", + /* 31 */ "ccons ::= DEFAULT LP expr RP", + /* 32 */ "ccons ::= DEFAULT PLUS term", + /* 33 */ "ccons ::= DEFAULT MINUS term", + /* 34 */ "ccons ::= DEFAULT ID|INDEXED", + /* 35 */ "ccons ::= NOT NULL onconf", + /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 37 */ "ccons ::= UNIQUE onconf", + /* 38 */ "ccons ::= CHECK LP expr RP", + /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 40 */ "ccons ::= defer_subclause", + /* 41 */ "ccons ::= COLLATE ID|STRING", + /* 42 */ "autoinc ::=", + /* 43 */ "autoinc ::= AUTOINCR", + /* 44 */ "refargs ::=", + /* 45 */ "refargs ::= refargs refarg", + /* 46 */ "refarg ::= MATCH nm", + /* 47 */ "refarg ::= ON INSERT refact", + /* 48 */ "refarg ::= ON DELETE refact", + /* 49 */ "refarg ::= ON UPDATE refact", + /* 50 */ "refact ::= SET NULL", + /* 51 */ "refact ::= SET DEFAULT", + /* 52 */ "refact ::= CASCADE", + /* 53 */ "refact ::= RESTRICT", + /* 54 */ "refact ::= NO ACTION", + /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 57 */ "init_deferred_pred_opt ::=", + /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 60 */ "conslist_opt ::=", + /* 61 */ "tconscomma ::= COMMA", + /* 62 */ "tcons ::= CONSTRAINT nm", + /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 65 */ "tcons ::= CHECK LP expr RP onconf", + /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 67 */ "defer_subclause_opt ::=", + /* 68 */ "onconf ::=", + /* 69 */ "onconf ::= ON CONFLICT resolvetype", + /* 70 */ "orconf ::=", + /* 71 */ "orconf ::= OR resolvetype", + /* 72 */ "resolvetype ::= IGNORE", + /* 73 */ "resolvetype ::= REPLACE", + /* 74 */ "cmd ::= DROP TABLE ifexists fullname", + /* 75 */ "ifexists ::= IF EXISTS", + /* 76 */ "ifexists ::=", + /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 78 */ "cmd ::= DROP VIEW ifexists fullname", + /* 79 */ "cmd ::= select", + /* 80 */ "select ::= with selectnowith", + /* 81 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 82 */ "multiselect_op ::= UNION", + /* 83 */ "multiselect_op ::= UNION ALL", + /* 84 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 86 */ "values ::= VALUES LP nexprlist RP", + /* 87 */ "values ::= values COMMA LP exprlist RP", + /* 88 */ "distinct ::= DISTINCT", + /* 89 */ "distinct ::= ALL", + /* 90 */ "distinct ::=", + /* 91 */ "sclp ::=", + /* 92 */ "selcollist ::= sclp expr as", + /* 93 */ "selcollist ::= sclp STAR", + /* 94 */ "selcollist ::= sclp nm DOT STAR", + /* 95 */ "as ::= AS nm", + /* 96 */ "as ::=", + /* 97 */ "from ::=", + /* 98 */ "from ::= FROM seltablist", + /* 99 */ "stl_prefix ::= seltablist joinop", + /* 100 */ "stl_prefix ::=", + /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 105 */ "dbnm ::=", + /* 106 */ "dbnm ::= DOT nm", + /* 107 */ "fullname ::= nm dbnm", + /* 108 */ "joinop ::= COMMA|JOIN", + /* 109 */ "joinop ::= JOIN_KW JOIN", + /* 110 */ "joinop ::= JOIN_KW nm JOIN", + /* 111 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 112 */ "on_opt ::= ON expr", + /* 113 */ "on_opt ::=", + /* 114 */ "indexed_opt ::=", + /* 115 */ "indexed_opt ::= INDEXED BY nm", + /* 116 */ "indexed_opt ::= NOT INDEXED", + /* 117 */ "using_opt ::= USING LP idlist RP", + /* 118 */ "using_opt ::=", + /* 119 */ "orderby_opt ::=", + /* 120 */ "orderby_opt ::= ORDER BY sortlist", + /* 121 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 122 */ "sortlist ::= expr sortorder", + /* 123 */ "sortorder ::= ASC", + /* 124 */ "sortorder ::= DESC", + /* 125 */ "sortorder ::=", + /* 126 */ "groupby_opt ::=", + /* 127 */ "groupby_opt ::= GROUP BY nexprlist", + /* 128 */ "having_opt ::=", + /* 129 */ "having_opt ::= HAVING expr", + /* 130 */ "limit_opt ::=", + /* 131 */ "limit_opt ::= LIMIT expr", + /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 133 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt", + /* 135 */ "where_opt ::=", + /* 136 */ "where_opt ::= WHERE expr", + /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", + /* 138 */ "setlist ::= setlist COMMA nm EQ expr", + /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 140 */ "setlist ::= nm EQ expr", + /* 141 */ "setlist ::= LP idlist RP EQ expr", + /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", + /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", + /* 144 */ "insert_cmd ::= INSERT orconf", + /* 145 */ "insert_cmd ::= REPLACE", + /* 146 */ "idlist_opt ::=", + /* 147 */ "idlist_opt ::= LP idlist RP", + /* 148 */ "idlist ::= idlist COMMA nm", + /* 149 */ "idlist ::= nm", + /* 150 */ "expr ::= LP expr RP", + /* 151 */ "term ::= NULL", + /* 152 */ "expr ::= ID|INDEXED", + /* 153 */ "expr ::= JOIN_KW", + /* 154 */ "expr ::= nm DOT nm", + /* 155 */ "expr ::= nm DOT nm DOT nm", + /* 156 */ "term ::= FLOAT|BLOB", + /* 157 */ "term ::= STRING", + /* 158 */ "term ::= INTEGER", + /* 159 */ "expr ::= VARIABLE", + /* 160 */ "expr ::= expr COLLATE ID|STRING", + /* 161 */ "expr ::= CAST LP expr AS typetoken RP", + /* 162 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 163 */ "expr ::= ID|INDEXED LP STAR RP", + /* 164 */ "term ::= CTIME_KW", + /* 165 */ "expr ::= LP nexprlist COMMA expr RP", + /* 166 */ "expr ::= expr AND expr", + /* 167 */ "expr ::= expr OR expr", + /* 168 */ "expr ::= expr LT|GT|GE|LE expr", + /* 169 */ "expr ::= expr EQ|NE expr", + /* 170 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 171 */ "expr ::= expr PLUS|MINUS expr", + /* 172 */ "expr ::= expr STAR|SLASH|REM expr", + /* 173 */ "expr ::= expr CONCAT expr", + /* 174 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 175 */ "expr ::= expr likeop expr", + /* 176 */ "expr ::= expr likeop expr ESCAPE expr", + /* 177 */ "expr ::= expr ISNULL|NOTNULL", + /* 178 */ "expr ::= expr NOT NULL", + /* 179 */ "expr ::= expr IS expr", + /* 180 */ "expr ::= expr IS NOT expr", + /* 181 */ "expr ::= NOT expr", + /* 182 */ "expr ::= BITNOT expr", + /* 183 */ "expr ::= MINUS expr", + /* 184 */ "expr ::= PLUS expr", + /* 185 */ "between_op ::= BETWEEN", + /* 186 */ "between_op ::= NOT BETWEEN", + /* 187 */ "expr ::= expr between_op expr AND expr", + /* 188 */ "in_op ::= IN", + /* 189 */ "in_op ::= NOT IN", + /* 190 */ "expr ::= expr in_op LP exprlist RP", + /* 191 */ "expr ::= LP select RP", + /* 192 */ "expr ::= expr in_op LP select RP", + /* 193 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 194 */ "expr ::= EXISTS LP select RP", + /* 195 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 196 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 197 */ "case_exprlist ::= WHEN expr THEN expr", + /* 198 */ "case_else ::= ELSE expr", + /* 199 */ "case_else ::=", + /* 200 */ "case_operand ::= expr", + /* 201 */ "case_operand ::=", + /* 202 */ "exprlist ::=", + /* 203 */ "nexprlist ::= nexprlist COMMA expr", + /* 204 */ "nexprlist ::= expr", + /* 205 */ "paren_exprlist ::=", + /* 206 */ "paren_exprlist ::= LP exprlist RP", + /* 207 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 208 */ "uniqueflag ::= UNIQUE", + /* 209 */ "uniqueflag ::=", + /* 210 */ "eidlist_opt ::=", + /* 211 */ "eidlist_opt ::= LP eidlist RP", + /* 212 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 213 */ "eidlist ::= nm collate sortorder", + /* 214 */ "collate ::=", + /* 215 */ "collate ::= COLLATE ID|STRING", + /* 216 */ "cmd ::= DROP INDEX ifexists fullname", + /* 217 */ "cmd ::= VACUUM", + /* 218 */ "cmd ::= VACUUM nm", + /* 219 */ "cmd ::= PRAGMA nm dbnm", + /* 220 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 221 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 222 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 223 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 224 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 225 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 226 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 227 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 228 */ "trigger_time ::= BEFORE", + /* 229 */ "trigger_time ::= AFTER", + /* 230 */ "trigger_time ::= INSTEAD OF", + /* 231 */ "trigger_time ::=", + /* 232 */ "trigger_event ::= DELETE|INSERT", + /* 233 */ "trigger_event ::= UPDATE", + /* 234 */ "trigger_event ::= UPDATE OF idlist", + /* 235 */ "when_clause ::=", + /* 236 */ "when_clause ::= WHEN expr", + /* 237 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 238 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 239 */ "trnm ::= nm DOT nm", + /* 240 */ "tridxby ::= INDEXED BY nm", + /* 241 */ "tridxby ::= NOT INDEXED", + /* 242 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", + /* 243 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", + /* 244 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", + /* 245 */ "trigger_cmd ::= select", + /* 246 */ "expr ::= RAISE LP IGNORE RP", + /* 247 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 248 */ "raisetype ::= ROLLBACK", + /* 249 */ "raisetype ::= ABORT", + /* 250 */ "raisetype ::= FAIL", + /* 251 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 252 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 253 */ "cmd ::= DETACH database_kw_opt expr", + /* 254 */ "key_opt ::=", + /* 255 */ "key_opt ::= KEY expr", + /* 256 */ "cmd ::= REINDEX", + /* 257 */ "cmd ::= REINDEX nm dbnm", + /* 258 */ "cmd ::= ANALYZE", + /* 259 */ "cmd ::= ANALYZE nm dbnm", + /* 260 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 261 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 262 */ "add_column_fullname ::= fullname", + /* 263 */ "cmd ::= create_vtab", + /* 264 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 265 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 266 */ "vtabarg ::=", + /* 267 */ "vtabargtoken ::= ANY", + /* 268 */ "vtabargtoken ::= lp anylist RP", + /* 269 */ "lp ::= LP", + /* 270 */ "with ::=", + /* 271 */ "with ::= WITH wqlist", + /* 272 */ "with ::= WITH RECURSIVE wqlist", + /* 273 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 274 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 275 */ "input ::= cmdlist", + /* 276 */ "cmdlist ::= cmdlist ecmd", + /* 277 */ "cmdlist ::= ecmd", + /* 278 */ "ecmd ::= SEMI", + /* 279 */ "ecmd ::= explain cmdx SEMI", + /* 280 */ "explain ::=", + /* 281 */ "trans_opt ::=", + /* 282 */ "trans_opt ::= TRANSACTION", + /* 283 */ "trans_opt ::= TRANSACTION nm", + /* 284 */ "savepoint_opt ::= SAVEPOINT", + /* 285 */ "savepoint_opt ::=", + /* 286 */ "cmd ::= create_table create_table_args", + /* 287 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 288 */ "columnlist ::= columnname carglist", + /* 289 */ "nm ::= ID|INDEXED", + /* 290 */ "nm ::= STRING", + /* 291 */ "nm ::= JOIN_KW", + /* 292 */ "typetoken ::= typename", + /* 293 */ "typename ::= ID|STRING", + /* 294 */ "signed ::= plus_num", + /* 295 */ "signed ::= minus_num", + /* 296 */ "carglist ::= carglist ccons", + /* 297 */ "carglist ::=", + /* 298 */ "ccons ::= NULL onconf", + /* 299 */ "conslist_opt ::= COMMA conslist", + /* 300 */ "conslist ::= conslist tconscomma tcons", + /* 301 */ "conslist ::= tcons", + /* 302 */ "tconscomma ::=", + /* 303 */ "defer_subclause_opt ::= defer_subclause", + /* 304 */ "resolvetype ::= raisetype", + /* 305 */ "selectnowith ::= oneselect", + /* 306 */ "oneselect ::= values", + /* 307 */ "sclp ::= selcollist COMMA", + /* 308 */ "as ::= ID|STRING", + /* 309 */ "expr ::= term", + /* 310 */ "likeop ::= LIKE_KW|MATCH", + /* 311 */ "exprlist ::= nexprlist", + /* 312 */ "nmnum ::= plus_num", + /* 313 */ "nmnum ::= nm", + /* 314 */ "nmnum ::= ON", + /* 315 */ "nmnum ::= DELETE", + /* 316 */ "nmnum ::= DEFAULT", + /* 317 */ "plus_num ::= INTEGER|FLOAT", + /* 318 */ "foreach_clause ::=", + /* 319 */ "foreach_clause ::= FOR EACH ROW", + /* 320 */ "trnm ::= nm", + /* 321 */ "tridxby ::=", + /* 322 */ "database_kw_opt ::= DATABASE", + /* 323 */ "database_kw_opt ::=", + /* 324 */ "kwcolumn_opt ::=", + /* 325 */ "kwcolumn_opt ::= COLUMNKW", + /* 326 */ "vtabarglist ::= vtabarg", + /* 327 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 328 */ "vtabarg ::= vtabarg vtabargtoken", + /* 329 */ "anylist ::=", + /* 330 */ "anylist ::= anylist LP anylist RP", + /* 331 */ "anylist ::= anylist ANY", +}; +#endif /* NDEBUG */ + + +#if YYSTACKDEPTH<=0 +/* +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. +*/ +static int yyGrowStack(yyParser *p){ + int newSize; + int idx; + yyStackEntry *pNew; + + newSize = p->yystksz*2 + 100; + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; + }else{ + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + } + if( pNew ){ + p->yystack = pNew; + p->yytos = &p->yystack[idx]; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); + } +#endif + p->yystksz = newSize; + } + return pNew==0; +} +#endif + +/* Datatype of the argument to the memory allocated passed as the +** second argument to sqlite3ParserAlloc() below. This can be changed by +** putting an appropriate #define in the %include section of the input +** grammar. +*/ +#ifndef YYMALLOCARGTYPE +# define YYMALLOCARGTYPE size_t +#endif + +/* Initialize a new parser that has already been allocated. +*/ +SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){ + yyParser *pParser = (yyParser*)yypParser; +#ifdef YYTRACKMAXSTACKDEPTH + pParser->yyhwm = 0; +#endif +#if YYSTACKDEPTH<=0 + pParser->yytos = NULL; + pParser->yystack = NULL; + pParser->yystksz = 0; + if( yyGrowStack(pParser) ){ + pParser->yystack = &pParser->yystk0; + pParser->yystksz = 1; + } +#endif +#ifndef YYNOERRORRECOVERY + pParser->yyerrcnt = -1; +#endif + pParser->yytos = pParser->yystack; + pParser->yystack[0].stateno = 0; + pParser->yystack[0].major = 0; +} + +#ifndef sqlite3Parser_ENGINEALWAYSONSTACK +/* +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. +** +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to sqlite3Parser and sqlite3ParserFree. +*/ +SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ + yyParser *pParser; + pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); + if( pParser ) sqlite3ParserInit(pParser); + return pParser; +} +#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ + + +/* The following function deletes the "minor type" or semantic value +** associated with a symbol. The symbol can be either a terminal +** or nonterminal. "yymajor" is the symbol code, and "yypminor" is +** a pointer to the value to be deleted. The code used to do the +** deletions is derived from the %destructor and/or %token_destructor +** directives of the input grammar. +*/ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + sqlite3ParserARG_FETCH; + switch( yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are *not* used + ** inside the C code. + */ +/********* Begin destructor definitions ***************************************/ + case 163: /* select */ + case 194: /* selectnowith */ + case 195: /* oneselect */ + case 206: /* values */ +{ +sqlite3SelectDelete(pParse->db, (yypminor->yy243)); +} + break; + case 172: /* term */ + case 173: /* expr */ +{ +sqlite3ExprDelete(pParse->db, (yypminor->yy190).pExpr); +} + break; + case 177: /* eidlist_opt */ + case 186: /* sortlist */ + case 187: /* eidlist */ + case 199: /* selcollist */ + case 202: /* groupby_opt */ + case 204: /* orderby_opt */ + case 207: /* nexprlist */ + case 208: /* exprlist */ + case 209: /* sclp */ + case 218: /* setlist */ + case 224: /* paren_exprlist */ + case 226: /* case_exprlist */ +{ +sqlite3ExprListDelete(pParse->db, (yypminor->yy148)); +} + break; + case 193: /* fullname */ + case 200: /* from */ + case 211: /* seltablist */ + case 212: /* stl_prefix */ +{ +sqlite3SrcListDelete(pParse->db, (yypminor->yy185)); +} + break; + case 196: /* with */ + case 250: /* wqlist */ +{ +sqlite3WithDelete(pParse->db, (yypminor->yy285)); +} + break; + case 201: /* where_opt */ + case 203: /* having_opt */ + case 215: /* on_opt */ + case 225: /* case_operand */ + case 227: /* case_else */ + case 236: /* when_clause */ + case 241: /* key_opt */ +{ +sqlite3ExprDelete(pParse->db, (yypminor->yy72)); +} + break; + case 216: /* using_opt */ + case 217: /* idlist */ + case 220: /* idlist_opt */ +{ +sqlite3IdListDelete(pParse->db, (yypminor->yy254)); +} + break; + case 232: /* trigger_cmd_list */ + case 237: /* trigger_cmd */ +{ +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy145)); +} + break; + case 234: /* trigger_event */ +{ +sqlite3IdListDelete(pParse->db, (yypminor->yy332).b); +} + break; +/********* End destructor definitions *****************************************/ + default: break; /* If no destructor action specified: do nothing */ + } +} + +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +*/ +static void yy_pop_parser_stack(yyParser *pParser){ + yyStackEntry *yytos; + assert( pParser->yytos!=0 ); + assert( pParser->yytos > pParser->yystack ); + yytos = pParser->yytos--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sPopping %s\n", + yyTracePrompt, + yyTokenName[yytos->major]); + } +#endif + yy_destructor(pParser, yytos->major, &yytos->minor); +} + +/* +** Clear all secondary memory allocations from the parser +*/ +SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ + yyParser *pParser = (yyParser*)p; + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); +#endif +} + +#ifndef sqlite3Parser_ENGINEALWAYSONSTACK +/* +** Deallocate and destroy a parser. Destructors are called for +** all stack elements before shutting the parser down. +** +** If the YYPARSEFREENEVERNULL macro exists (for example because it +** is defined in a %include section of the input grammar) then it is +** assumed that the input pointer is never NULL. +*/ +SQLITE_PRIVATE void sqlite3ParserFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ +#ifndef YYPARSEFREENEVERNULL + if( p==0 ) return; +#endif + sqlite3ParserFinalize(p); + (*freeProc)(p); +} +#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ + +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyhwm; +} +#endif + +/* +** Find the appropriate action for a parser given the terminal +** look-ahead token iLookAhead. +*/ +static unsigned int yy_find_shift_action( + yyParser *pParser, /* The parser */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; + int stateno = pParser->yytos->stateno; + + if( stateno>=YY_MIN_REDUCE ) return stateno; + assert( stateno <= YY_SHIFT_COUNT ); + do{ + i = yy_shift_ofst[stateno]; + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ +#ifdef YYFALLBACK + YYCODETYPE iFallback; /* Fallback token */ + if( iLookAhead %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + if( +#if YY_SHIFT_MIN+YYWILDCARD<0 + j>=0 && +#endif +#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT + j0 + ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; + } + } +#endif /* YYWILDCARD */ + return yy_default[stateno]; + }else{ + return yy_action[i]; + } + }while(1); +} + +/* +** Find the appropriate action for a parser given the non-terminal +** look-ahead token iLookAhead. +*/ +static int yy_find_reduce_action( + int stateno, /* Current state number */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_COUNT ){ + return yy_default[stateno]; + } +#else + assert( stateno<=YY_REDUCE_COUNT ); +#endif + i = yy_reduce_ofst[stateno]; + assert( i!=YY_REDUCE_USE_DFLT ); + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; +#ifdef YYERRORSYMBOL + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + return yy_default[stateno]; + } +#else + assert( i>=0 && iyytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ +/******** Begin %stack_overflow code ******************************************/ + + sqlite3ErrorMsg(pParse, "parser stack overflow"); +/******** End %stack_overflow code ********************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ +} + +/* +** Print tracing information for a SHIFT action +*/ +#ifndef NDEBUG +static void yyTraceShift(yyParser *yypParser, int yyNewState){ + if( yyTraceFILE ){ + if( yyNewStateyytos->major], + yyNewState); + }else{ + fprintf(yyTraceFILE,"%sShift '%s'\n", + yyTracePrompt,yyTokenName[yypParser->yytos->major]); + } + } +} +#else +# define yyTraceShift(X,Y) +#endif + +/* +** Perform a shift action. +*/ +static void yy_shift( + yyParser *yypParser, /* The parser to be shifted */ + int yyNewState, /* The new state to shift in */ + int yyMajor, /* The major token to shift in */ + sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ +){ + yyStackEntry *yytos; + yypParser->yytos++; +#ifdef YYTRACKMAXSTACKDEPTH + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ + yypParser->yytos--; + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ + if( yyGrowStack(yypParser) ){ + yypParser->yytos--; + yyStackOverflow(yypParser); + return; + } + } +#endif + if( yyNewState > YY_MAX_SHIFT ){ + yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yytos = yypParser->yytos; + yytos->stateno = (YYACTIONTYPE)yyNewState; + yytos->major = (YYCODETYPE)yyMajor; + yytos->minor.yy0 = yyMinor; + yyTraceShift(yypParser, yyNewState); +} + +/* The following table contains information about every rule that +** is used during the reduce. +*/ +static const struct { + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + unsigned char nrhs; /* Number of right-hand side symbols in the rule */ +} yyRuleInfo[] = { + { 147, 1 }, + { 147, 3 }, + { 148, 1 }, + { 149, 3 }, + { 150, 0 }, + { 150, 1 }, + { 150, 1 }, + { 150, 1 }, + { 149, 2 }, + { 149, 2 }, + { 149, 2 }, + { 149, 2 }, + { 149, 3 }, + { 149, 5 }, + { 154, 6 }, + { 156, 1 }, + { 158, 0 }, + { 158, 3 }, + { 157, 1 }, + { 157, 0 }, + { 155, 5 }, + { 155, 2 }, + { 162, 0 }, + { 162, 2 }, + { 164, 2 }, + { 166, 0 }, + { 166, 4 }, + { 166, 6 }, + { 167, 2 }, + { 171, 2 }, + { 171, 2 }, + { 171, 4 }, + { 171, 3 }, + { 171, 3 }, + { 171, 2 }, + { 171, 3 }, + { 171, 5 }, + { 171, 2 }, + { 171, 4 }, + { 171, 4 }, + { 171, 1 }, + { 171, 2 }, + { 176, 0 }, + { 176, 1 }, + { 178, 0 }, + { 178, 2 }, + { 180, 2 }, + { 180, 3 }, + { 180, 3 }, + { 180, 3 }, + { 181, 2 }, + { 181, 2 }, + { 181, 1 }, + { 181, 1 }, + { 181, 2 }, + { 179, 3 }, + { 179, 2 }, + { 182, 0 }, + { 182, 2 }, + { 182, 2 }, + { 161, 0 }, + { 184, 1 }, + { 185, 2 }, + { 185, 7 }, + { 185, 5 }, + { 185, 5 }, + { 185, 10 }, + { 188, 0 }, + { 174, 0 }, + { 174, 3 }, + { 189, 0 }, + { 189, 2 }, + { 190, 1 }, + { 190, 1 }, + { 149, 4 }, + { 192, 2 }, + { 192, 0 }, + { 149, 9 }, + { 149, 4 }, + { 149, 1 }, + { 163, 2 }, + { 194, 3 }, + { 197, 1 }, + { 197, 2 }, + { 197, 1 }, + { 195, 9 }, + { 206, 4 }, + { 206, 5 }, + { 198, 1 }, + { 198, 1 }, + { 198, 0 }, + { 209, 0 }, + { 199, 3 }, + { 199, 2 }, + { 199, 4 }, + { 210, 2 }, + { 210, 0 }, + { 200, 0 }, + { 200, 2 }, + { 212, 2 }, + { 212, 0 }, + { 211, 7 }, + { 211, 9 }, + { 211, 7 }, + { 211, 7 }, + { 159, 0 }, + { 159, 2 }, + { 193, 2 }, + { 213, 1 }, + { 213, 2 }, + { 213, 3 }, + { 213, 4 }, + { 215, 2 }, + { 215, 0 }, + { 214, 0 }, + { 214, 3 }, + { 214, 2 }, + { 216, 4 }, + { 216, 0 }, + { 204, 0 }, + { 204, 3 }, + { 186, 4 }, + { 186, 2 }, + { 175, 1 }, + { 175, 1 }, + { 175, 0 }, + { 202, 0 }, + { 202, 3 }, + { 203, 0 }, + { 203, 2 }, + { 205, 0 }, + { 205, 2 }, + { 205, 4 }, + { 205, 4 }, + { 149, 6 }, + { 201, 0 }, + { 201, 2 }, + { 149, 8 }, + { 218, 5 }, + { 218, 7 }, + { 218, 3 }, + { 218, 5 }, + { 149, 6 }, + { 149, 7 }, + { 219, 2 }, + { 219, 1 }, + { 220, 0 }, + { 220, 3 }, + { 217, 3 }, + { 217, 1 }, + { 173, 3 }, + { 172, 1 }, + { 173, 1 }, + { 173, 1 }, + { 173, 3 }, + { 173, 5 }, + { 172, 1 }, + { 172, 1 }, + { 172, 1 }, + { 173, 1 }, + { 173, 3 }, + { 173, 6 }, + { 173, 5 }, + { 173, 4 }, + { 172, 1 }, + { 173, 5 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 173, 3 }, + { 221, 2 }, + { 173, 3 }, + { 173, 5 }, + { 173, 2 }, + { 173, 3 }, + { 173, 3 }, + { 173, 4 }, + { 173, 2 }, + { 173, 2 }, + { 173, 2 }, + { 173, 2 }, + { 222, 1 }, + { 222, 2 }, + { 173, 5 }, + { 223, 1 }, + { 223, 2 }, + { 173, 5 }, + { 173, 3 }, + { 173, 5 }, + { 173, 5 }, + { 173, 4 }, + { 173, 5 }, + { 226, 5 }, + { 226, 4 }, + { 227, 2 }, + { 227, 0 }, + { 225, 1 }, + { 225, 0 }, + { 208, 0 }, + { 207, 3 }, + { 207, 1 }, + { 224, 0 }, + { 224, 3 }, + { 149, 12 }, + { 228, 1 }, + { 228, 0 }, + { 177, 0 }, + { 177, 3 }, + { 187, 5 }, + { 187, 3 }, + { 229, 0 }, + { 229, 2 }, + { 149, 4 }, + { 149, 1 }, + { 149, 2 }, + { 149, 3 }, + { 149, 5 }, + { 149, 6 }, + { 149, 5 }, + { 149, 6 }, + { 169, 2 }, + { 170, 2 }, + { 149, 5 }, + { 231, 11 }, + { 233, 1 }, + { 233, 1 }, + { 233, 2 }, + { 233, 0 }, + { 234, 1 }, + { 234, 1 }, + { 234, 3 }, + { 236, 0 }, + { 236, 2 }, + { 232, 3 }, + { 232, 2 }, + { 238, 3 }, + { 239, 3 }, + { 239, 2 }, + { 237, 7 }, + { 237, 5 }, + { 237, 5 }, + { 237, 1 }, + { 173, 4 }, + { 173, 6 }, + { 191, 1 }, + { 191, 1 }, + { 191, 1 }, + { 149, 4 }, + { 149, 6 }, + { 149, 3 }, + { 241, 0 }, + { 241, 2 }, + { 149, 1 }, + { 149, 3 }, + { 149, 1 }, + { 149, 3 }, + { 149, 6 }, + { 149, 7 }, + { 242, 1 }, + { 149, 1 }, + { 149, 4 }, + { 244, 8 }, + { 246, 0 }, + { 247, 1 }, + { 247, 3 }, + { 248, 1 }, + { 196, 0 }, + { 196, 2 }, + { 196, 3 }, + { 250, 6 }, + { 250, 8 }, + { 144, 1 }, + { 145, 2 }, + { 145, 1 }, + { 146, 1 }, + { 146, 3 }, + { 147, 0 }, + { 151, 0 }, + { 151, 1 }, + { 151, 2 }, + { 153, 1 }, + { 153, 0 }, + { 149, 2 }, + { 160, 4 }, + { 160, 2 }, + { 152, 1 }, + { 152, 1 }, + { 152, 1 }, + { 166, 1 }, + { 167, 1 }, + { 168, 1 }, + { 168, 1 }, + { 165, 2 }, + { 165, 0 }, + { 171, 2 }, + { 161, 2 }, + { 183, 3 }, + { 183, 1 }, + { 184, 0 }, + { 188, 1 }, + { 190, 1 }, + { 194, 1 }, + { 195, 1 }, + { 209, 2 }, + { 210, 1 }, + { 173, 1 }, + { 221, 1 }, + { 208, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 169, 1 }, + { 235, 0 }, + { 235, 3 }, + { 238, 1 }, + { 239, 0 }, + { 240, 1 }, + { 240, 0 }, + { 243, 0 }, + { 243, 1 }, + { 245, 1 }, + { 245, 3 }, + { 246, 2 }, + { 249, 0 }, + { 249, 4 }, + { 249, 2 }, +}; + +static void yy_accept(yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +*/ +static void yy_reduce( + yyParser *yypParser, /* The parser */ + unsigned int yyruleno /* Number of the rule by which to reduce */ +){ + int yygoto; /* The next state */ + int yyact; /* The next action */ + yyStackEntry *yymsp; /* The top of the parser's stack */ + int yysize; /* Amount to pop the stack */ + sqlite3ParserARG_FETCH; + yymsp = yypParser->yytos; +#ifndef NDEBUG + if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ + yysize = yyRuleInfo[yyruleno].nrhs; + fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, + yyRuleName[yyruleno], yymsp[-yysize].stateno); + } +#endif /* NDEBUG */ + + /* Check that the stack is large enough to grow by a single entry + ** if the RHS of the rule is empty. This ensures that there is room + ** enough on the stack to push the LHS value */ + if( yyRuleInfo[yyruleno].nrhs==0 ){ +#ifdef YYTRACKMAXSTACKDEPTH + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ + if( yyGrowStack(yypParser) ){ + yyStackOverflow(yypParser); + return; + } + yymsp = yypParser->yytos; + } +#endif + } + + switch( yyruleno ){ + /* Beginning here are the reduction cases. A typical example + ** follows: + ** case 0: + ** #line + ** { ... } // User supplied code + ** #line + ** break; + */ +/********** Begin reduce actions **********************************************/ + YYMINORTYPE yylhsminor; + case 0: /* explain ::= EXPLAIN */ +{ pParse->explain = 1; } + break; + case 1: /* explain ::= EXPLAIN QUERY PLAN */ +{ pParse->explain = 2; } + break; + case 2: /* cmdx ::= cmd */ +{ sqlite3FinishCoding(pParse); } + break; + case 3: /* cmd ::= BEGIN transtype trans_opt */ +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy194);} + break; + case 4: /* transtype ::= */ +{yymsp[1].minor.yy194 = TK_DEFERRED;} + break; + case 5: /* transtype ::= DEFERRED */ + case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); + case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/} + break; + case 8: /* cmd ::= COMMIT trans_opt */ + case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9); +{sqlite3CommitTransaction(pParse);} + break; + case 10: /* cmd ::= ROLLBACK trans_opt */ +{sqlite3RollbackTransaction(pParse);} + break; + case 11: /* cmd ::= SAVEPOINT nm */ +{ + sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); +} + break; + case 12: /* cmd ::= RELEASE savepoint_opt nm */ +{ + sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); +} + break; + case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ +{ + sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); +} + break; + case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ +{ + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194); +} + break; + case 15: /* createkw ::= CREATE */ +{disableLookaside(pParse);} + break; + case 16: /* ifnotexists ::= */ + case 19: /* temp ::= */ yytestcase(yyruleno==19); + case 22: /* table_options ::= */ yytestcase(yyruleno==22); + case 42: /* autoinc ::= */ yytestcase(yyruleno==42); + case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); + case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); + case 76: /* ifexists ::= */ yytestcase(yyruleno==76); + case 90: /* distinct ::= */ yytestcase(yyruleno==90); + case 214: /* collate ::= */ yytestcase(yyruleno==214); +{yymsp[1].minor.yy194 = 0;} + break; + case 17: /* ifnotexists ::= IF NOT EXISTS */ +{yymsp[-2].minor.yy194 = 1;} + break; + case 18: /* temp ::= TEMP */ + case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); +{yymsp[0].minor.yy194 = 1;} + break; + case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ +{ + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0); +} + break; + case 21: /* create_table_args ::= AS select */ +{ + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); +} + break; + case 23: /* table_options ::= WITHOUT nm */ +{ + if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ + yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid; + }else{ + yymsp[-1].minor.yy194 = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); + } +} + break; + case 24: /* columnname ::= nm typetoken */ +{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} + break; + case 25: /* typetoken ::= */ + case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60); + case 96: /* as ::= */ yytestcase(yyruleno==96); +{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} + break; + case 26: /* typetoken ::= typename LP signed RP */ +{ + yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); +} + break; + case 27: /* typetoken ::= typename LP signed COMMA signed RP */ +{ + yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); +} + break; + case 28: /* typename ::= typename ID|STRING */ +{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} + break; + case 29: /* ccons ::= CONSTRAINT nm */ + case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62); +{pParse->constraintName = yymsp[0].minor.yy0;} + break; + case 30: /* ccons ::= DEFAULT term */ + case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32); +{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);} + break; + case 31: /* ccons ::= DEFAULT LP expr RP */ +{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);} + break; + case 33: /* ccons ::= DEFAULT MINUS term */ +{ + ExprSpan v; + v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0); + v.zStart = yymsp[-1].minor.yy0.z; + v.zEnd = yymsp[0].minor.yy190.zEnd; + sqlite3AddDefaultValue(pParse,&v); +} + break; + case 34: /* ccons ::= DEFAULT ID|INDEXED */ +{ + ExprSpan v; + spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0); + sqlite3AddDefaultValue(pParse,&v); +} + break; + case 35: /* ccons ::= NOT NULL onconf */ +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);} + break; + case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);} + break; + case 37: /* ccons ::= UNIQUE onconf */ +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} + break; + case 38: /* ccons ::= CHECK LP expr RP */ +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);} + break; + case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);} + break; + case 40: /* ccons ::= defer_subclause */ +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);} + break; + case 41: /* ccons ::= COLLATE ID|STRING */ +{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} + break; + case 44: /* refargs ::= */ +{ yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */} + break; + case 45: /* refargs ::= refargs refarg */ +{ yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; } + break; + case 46: /* refarg ::= MATCH nm */ +{ yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; } + break; + case 47: /* refarg ::= ON INSERT refact */ +{ yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; } + break; + case 48: /* refarg ::= ON DELETE refact */ +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; } + break; + case 49: /* refarg ::= ON UPDATE refact */ +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; } + break; + case 50: /* refact ::= SET NULL */ +{ yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */} + break; + case 51: /* refact ::= SET DEFAULT */ +{ yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */} + break; + case 52: /* refact ::= CASCADE */ +{ yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */} + break; + case 53: /* refact ::= RESTRICT */ +{ yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */} + break; + case 54: /* refact ::= NO ACTION */ +{ yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */} + break; + case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ +{yymsp[-2].minor.yy194 = 0;} + break; + case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); + case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144); +{yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;} + break; + case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); + case 186: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==186); + case 189: /* in_op ::= NOT IN */ yytestcase(yyruleno==189); + case 215: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==215); +{yymsp[-1].minor.yy194 = 1;} + break; + case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ +{yymsp[-1].minor.yy194 = 0;} + break; + case 61: /* tconscomma ::= COMMA */ +{pParse->constraintName.n = 0;} + break; + case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);} + break; + case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} + break; + case 65: /* tcons ::= CHECK LP expr RP onconf */ +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);} + break; + case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ +{ + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194); +} + break; + case 68: /* onconf ::= */ + case 70: /* orconf ::= */ yytestcase(yyruleno==70); +{yymsp[1].minor.yy194 = OE_Default;} + break; + case 69: /* onconf ::= ON CONFLICT resolvetype */ +{yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;} + break; + case 72: /* resolvetype ::= IGNORE */ +{yymsp[0].minor.yy194 = OE_Ignore;} + break; + case 73: /* resolvetype ::= REPLACE */ + case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145); +{yymsp[0].minor.yy194 = OE_Replace;} + break; + case 74: /* cmd ::= DROP TABLE ifexists fullname */ +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194); +} + break; + case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ +{ + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194); +} + break; + case 78: /* cmd ::= DROP VIEW ifexists fullname */ +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194); +} + break; + case 79: /* cmd ::= select */ +{ + SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; + sqlite3Select(pParse, yymsp[0].minor.yy243, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); +} + break; + case 80: /* select ::= with selectnowith */ +{ + Select *p = yymsp[0].minor.yy243; + if( p ){ + p->pWith = yymsp[-1].minor.yy285; + parserDoubleLinkSelect(pParse, p); + }else{ + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy285); + } + yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/ +} + break; + case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */ +{ + Select *pRhs = yymsp[0].minor.yy243; + Select *pLhs = yymsp[-2].minor.yy243; + if( pRhs && pRhs->pPrior ){ + SrcList *pFrom; + Token x; + x.n = 0; + parserDoubleLinkSelect(pParse, pRhs); + pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); + pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); + } + if( pRhs ){ + pRhs->op = (u8)yymsp[-1].minor.yy194; + pRhs->pPrior = pLhs; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; + pRhs->selFlags &= ~SF_MultiValue; + if( yymsp[-1].minor.yy194!=TK_ALL ) pParse->hasCompound = 1; + }else{ + sqlite3SelectDelete(pParse->db, pLhs); + } + yymsp[-2].minor.yy243 = pRhs; +} + break; + case 82: /* multiselect_op ::= UNION */ + case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84); +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/} + break; + case 83: /* multiselect_op ::= UNION ALL */ +{yymsp[-1].minor.yy194 = TK_ALL;} + break; + case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ +{ +#if SELECTTRACE_ENABLED + Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/ +#endif + yymsp[-8].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy148,yymsp[-5].minor.yy185,yymsp[-4].minor.yy72,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-1].minor.yy148,yymsp[-7].minor.yy194,yymsp[0].minor.yy354.pLimit,yymsp[0].minor.yy354.pOffset); +#if SELECTTRACE_ENABLED + /* Populate the Select.zSelName[] string that is used to help with + ** query planner debugging, to differentiate between multiple Select + ** objects in a complex query. + ** + ** If the SELECT keyword is immediately followed by a C-style comment + ** then extract the first few alphanumeric characters from within that + ** comment to be the zSelName value. Otherwise, the label is #N where + ** is an integer that is incremented with each SELECT statement seen. + */ + if( yymsp[-8].minor.yy243!=0 ){ + const char *z = s.z+6; + int i; + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "#%d", + ++pParse->nSelect); + while( z[0]==' ' ) z++; + if( z[0]=='/' && z[1]=='*' ){ + z += 2; + while( z[0]==' ' ) z++; + for(i=0; sqlite3Isalnum(z[i]); i++){} + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "%.*s", i, z); + } + } +#endif /* SELECTRACE_ENABLED */ +} + break; + case 86: /* values ::= VALUES LP nexprlist RP */ +{ + yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0); +} + break; + case 87: /* values ::= values COMMA LP exprlist RP */ +{ + Select *pRight, *pLeft = yymsp[-4].minor.yy243; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); + if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; + if( pRight ){ + pRight->op = TK_ALL; + pRight->pPrior = pLeft; + yymsp[-4].minor.yy243 = pRight; + }else{ + yymsp[-4].minor.yy243 = pLeft; + } +} + break; + case 88: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy194 = SF_Distinct;} + break; + case 89: /* distinct ::= ALL */ +{yymsp[0].minor.yy194 = SF_All;} + break; + case 91: /* sclp ::= */ + case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119); + case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126); + case 202: /* exprlist ::= */ yytestcase(yyruleno==202); + case 205: /* paren_exprlist ::= */ yytestcase(yyruleno==205); + case 210: /* eidlist_opt ::= */ yytestcase(yyruleno==210); +{yymsp[1].minor.yy148 = 0;} + break; + case 92: /* selcollist ::= sclp expr as */ +{ + yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190); +} + break; + case 93: /* selcollist ::= sclp STAR */ +{ + Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p); +} + break; + case 94: /* selcollist ::= sclp nm DOT STAR */ +{ + Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); + Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); + Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot); +} + break; + case 95: /* as ::= AS nm */ + case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106); + case 224: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==224); + case 225: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==225); +{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} + break; + case 97: /* from ::= */ +{yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));} + break; + case 98: /* from ::= FROM seltablist */ +{ + yymsp[-1].minor.yy185 = yymsp[0].minor.yy185; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185); +} + break; + case 99: /* stl_prefix ::= seltablist joinop */ +{ + if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194; +} + break; + case 100: /* stl_prefix ::= */ +{yymsp[1].minor.yy185 = 0;} + break; + case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ +{ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0); +} + break; + case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ +{ + yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148); +} + break; + case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ +{ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + } + break; + case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ +{ + if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){ + yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185; + }else if( yymsp[-4].minor.yy185->nSrc==1 ){ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + if( yymsp[-6].minor.yy185 ){ + struct SrcList_item *pNew = &yymsp[-6].minor.yy185->a[yymsp[-6].minor.yy185->nSrc-1]; + struct SrcList_item *pOld = yymsp[-4].minor.yy185->a; + pNew->zName = pOld->zName; + pNew->zDatabase = pOld->zDatabase; + pNew->pSelect = pOld->pSelect; + pOld->zName = pOld->zDatabase = 0; + pOld->pSelect = 0; + } + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy185); + }else{ + Select *pSubquery; + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy185); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy185,0,0,0,0,SF_NestedFrom,0,0); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + } + } + break; + case 105: /* dbnm ::= */ + case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114); +{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} + break; + case 107: /* fullname ::= nm dbnm */ +{yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 108: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy194 = JT_INNER; } + break; + case 109: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} + break; + case 110: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + break; + case 111: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + break; + case 112: /* on_opt ::= ON expr */ + case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129); + case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136); + case 198: /* case_else ::= ELSE expr */ yytestcase(yyruleno==198); +{yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;} + break; + case 113: /* on_opt ::= */ + case 128: /* having_opt ::= */ yytestcase(yyruleno==128); + case 135: /* where_opt ::= */ yytestcase(yyruleno==135); + case 199: /* case_else ::= */ yytestcase(yyruleno==199); + case 201: /* case_operand ::= */ yytestcase(yyruleno==201); +{yymsp[1].minor.yy72 = 0;} + break; + case 115: /* indexed_opt ::= INDEXED BY nm */ +{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} + break; + case 116: /* indexed_opt ::= NOT INDEXED */ +{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} + break; + case 117: /* using_opt ::= USING LP idlist RP */ +{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;} + break; + case 118: /* using_opt ::= */ + case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146); +{yymsp[1].minor.yy254 = 0;} + break; + case 120: /* orderby_opt ::= ORDER BY sortlist */ + case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127); +{yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;} + break; + case 121: /* sortlist ::= sortlist COMMA expr sortorder */ +{ + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr); + sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194); +} + break; + case 122: /* sortlist ::= expr sortorder */ +{ + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194); +} + break; + case 123: /* sortorder ::= ASC */ +{yymsp[0].minor.yy194 = SQLITE_SO_ASC;} + break; + case 124: /* sortorder ::= DESC */ +{yymsp[0].minor.yy194 = SQLITE_SO_DESC;} + break; + case 125: /* sortorder ::= */ +{yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;} + break; + case 130: /* limit_opt ::= */ +{yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;} + break; + case 131: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;} + break; + case 132: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;} + break; + case 133: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;} + break; + case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ +{ + sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy185, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy185,yymsp[0].minor.yy72); +} + break; + case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ +{ + sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy148,"set list"); + sqlite3Update(pParse,yymsp[-4].minor.yy185,yymsp[-1].minor.yy148,yymsp[0].minor.yy72,yymsp[-5].minor.yy194); +} + break; + case 138: /* setlist ::= setlist COMMA nm EQ expr */ +{ + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1); +} + break; + case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ +{ + yymsp[-6].minor.yy148 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy148, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); +} + break; + case 140: /* setlist ::= nm EQ expr */ +{ + yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1); +} + yymsp[-2].minor.yy148 = yylhsminor.yy148; + break; + case 141: /* setlist ::= LP idlist RP EQ expr */ +{ + yymsp[-4].minor.yy148 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); +} + break; + case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ +{ + sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194); +} + break; + case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ +{ + sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194); +} + break; + case 147: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} + break; + case 148: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} + break; + case 149: /* idlist ::= nm */ +{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + break; + case 150: /* expr ::= LP expr RP */ +{spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;} + break; + case 151: /* term ::= NULL */ + case 156: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==156); + case 157: /* term ::= STRING */ yytestcase(yyruleno==157); +{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/} + break; + case 152: /* expr ::= ID|INDEXED */ + case 153: /* expr ::= JOIN_KW */ yytestcase(yyruleno==153); +{spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 154: /* expr ::= nm DOT nm */ +{ + Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); + Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); +} + break; + case 155: /* expr ::= nm DOT nm DOT nm */ +{ + Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); + Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); + Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); + Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); +} + break; + case 158: /* term ::= INTEGER */ +{ + yylhsminor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + yylhsminor.yy190.zStart = yymsp[0].minor.yy0.z; + yylhsminor.yy190.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n; + if( yylhsminor.yy190.pExpr ) yylhsminor.yy190.pExpr->flags |= EP_Leaf|EP_Resolved; +} + yymsp[0].minor.yy190 = yylhsminor.yy190; + break; + case 159: /* expr ::= VARIABLE */ +{ + if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ + u32 n = yymsp[0].minor.yy0.n; + spanExpr(&yymsp[0].minor.yy190, pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy190.pExpr, n); + }else{ + /* When doing a nested parse, one can include terms in an expression + ** that look like this: #1 #2 ... These terms refer to registers + ** in the virtual machine. #N is the N-th register. */ + Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ + assert( t.n>=2 ); + spanSet(&yymsp[0].minor.yy190, &t, &t); + if( pParse->nested==0 ){ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); + yymsp[0].minor.yy190.pExpr = 0; + }else{ + yymsp[0].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy190.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy190.pExpr->iTable); + } + } +} + break; + case 160: /* expr ::= expr COLLATE ID|STRING */ +{ + yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; +} + break; + case 161: /* expr ::= CAST LP expr AS typetoken RP */ +{ + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, 0); +} + break; + case 162: /* expr ::= ID|INDEXED LP distinct exprlist RP */ +{ + if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ + sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); + } + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy148, &yymsp[-4].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); + if( yymsp[-2].minor.yy194==SF_Distinct && yylhsminor.yy190.pExpr ){ + yylhsminor.yy190.pExpr->flags |= EP_Distinct; + } +} + yymsp[-4].minor.yy190 = yylhsminor.yy190; + break; + case 163: /* expr ::= ID|INDEXED LP STAR RP */ +{ + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); +} + yymsp[-3].minor.yy190 = yylhsminor.yy190; + break; + case 164: /* term ::= CTIME_KW */ +{ + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); + spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); +} + yymsp[0].minor.yy190 = yylhsminor.yy190; + break; + case 165: /* expr ::= LP nexprlist COMMA expr RP */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy148, yymsp[-1].minor.yy190.pExpr); + yylhsminor.yy190.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yylhsminor.yy190.pExpr ){ + yylhsminor.yy190.pExpr->x.pList = pList; + spanSet(&yylhsminor.yy190, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } +} + yymsp[-4].minor.yy190 = yylhsminor.yy190; + break; + case 166: /* expr ::= expr AND expr */ + case 167: /* expr ::= expr OR expr */ yytestcase(yyruleno==167); + case 168: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==168); + case 169: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==169); + case 170: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==170); + case 171: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==171); + case 172: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==172); + case 173: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==173); +{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);} + break; + case 174: /* likeop ::= NOT LIKE_KW|MATCH */ +{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} + break; + case 175: /* expr ::= expr likeop expr */ +{ + ExprList *pList; + int bNot = yymsp[-1].minor.yy0.n & 0x80000000; + yymsp[-1].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy190.pExpr); + yymsp[-2].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0); + exprNot(pParse, bNot, &yymsp[-2].minor.yy190); + yymsp[-2].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc; +} + break; + case 176: /* expr ::= expr likeop expr ESCAPE expr */ +{ + ExprList *pList; + int bNot = yymsp[-3].minor.yy0.n & 0x80000000; + yymsp[-3].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0); + exprNot(pParse, bNot, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc; +} + break; + case 177: /* expr ::= expr ISNULL|NOTNULL */ +{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);} + break; + case 178: /* expr ::= expr NOT NULL */ +{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);} + break; + case 179: /* expr ::= expr IS expr */ +{ + spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL); +} + break; + case 180: /* expr ::= expr IS NOT expr */ +{ + spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL); +} + break; + case 181: /* expr ::= NOT expr */ + case 182: /* expr ::= BITNOT expr */ yytestcase(yyruleno==182); +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} + break; + case 183: /* expr ::= MINUS expr */ +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} + break; + case 184: /* expr ::= PLUS expr */ +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} + break; + case 185: /* between_op ::= BETWEEN */ + case 188: /* in_op ::= IN */ yytestcase(yyruleno==188); +{yymsp[0].minor.yy194 = 0;} + break; + case 187: /* expr ::= expr between_op expr AND expr */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy190.pExpr, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = pList; + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; +} + break; + case 190: /* expr ::= expr in_op LP exprlist RP */ +{ + if( yymsp[-1].minor.yy148==0 ){ + /* Expressions of the form + ** + ** expr1 IN () + ** expr1 NOT IN () + ** + ** simplify to constants 0 (false) and 1 (true), respectively, + ** regardless of the value of expr1. + */ + sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy194],1); + }else if( yymsp[-1].minor.yy148->nExpr==1 ){ + /* Expressions of the form: + ** + ** expr1 IN (?1) + ** expr1 NOT IN (?2) + ** + ** with exactly one value on the RHS can be simplified to something + ** like this: + ** + ** expr1 == ?1 + ** expr1 <> ?2 + ** + ** But, the RHS of the == or <> is marked with the EP_Generic flag + ** so that it may not contribute to the computation of comparison + ** affinity or the collating sequence to use for comparison. Otherwise, + ** the semantics would be subtly different from IN or NOT IN. + */ + Expr *pRHS = yymsp[-1].minor.yy148->a[0].pExpr; + yymsp[-1].minor.yy148->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); + /* pRHS cannot be NULL because a malloc error would have been detected + ** before now and control would have never reached this point */ + if( ALWAYS(pRHS) ){ + pRHS->flags &= ~EP_Collate; + pRHS->flags |= EP_Generic; + } + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy194 ? TK_NE : TK_EQ, yymsp[-4].minor.yy190.pExpr, pRHS); + }else{ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); + }else{ + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); + } + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + } + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + } + break; + case 191: /* expr ::= LP select RP */ +{ + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243); + } + break; + case 192: /* expr ::= expr in_op LP select RP */ +{ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + } + break; + case 193: /* expr ::= expr in_op nm dbnm paren_exprlist */ +{ + SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); + Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); + if( yymsp[0].minor.yy148 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy148); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, pSelect); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n]; + } + break; + case 194: /* expr ::= EXISTS LP select RP */ +{ + Expr *p; + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + p = yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243); + } + break; + case 195: /* expr ::= CASE case_operand case_exprlist case_else END */ +{ + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy72 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[-1].minor.yy72) : yymsp[-2].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); + }else{ + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy148); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy72); + } +} + break; + case 196: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ +{ + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); +} + break; + case 197: /* case_exprlist ::= WHEN expr THEN expr */ +{ + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr); +} + break; + case 200: /* case_operand ::= expr */ +{yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/} + break; + case 203: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);} + break; + case 204: /* nexprlist ::= expr */ +{yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/} + break; + case 206: /* paren_exprlist ::= LP exprlist RP */ + case 211: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==211); +{yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;} + break; + case 207: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ +{ + sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, + sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF); +} + break; + case 208: /* uniqueflag ::= UNIQUE */ + case 249: /* raisetype ::= ABORT */ yytestcase(yyruleno==249); +{yymsp[0].minor.yy194 = OE_Abort;} + break; + case 209: /* uniqueflag ::= */ +{yymsp[1].minor.yy194 = OE_None;} + break; + case 212: /* eidlist ::= eidlist COMMA nm collate sortorder */ +{ + yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); +} + break; + case 213: /* eidlist ::= nm collate sortorder */ +{ + yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/ +} + break; + case 216: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);} + break; + case 217: /* cmd ::= VACUUM */ +{sqlite3Vacuum(pParse,0);} + break; + case 218: /* cmd ::= VACUUM nm */ +{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} + break; + case 219: /* cmd ::= PRAGMA nm dbnm */ +{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} + break; + case 220: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} + break; + case 221: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} + break; + case 222: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} + break; + case 223: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} + break; + case 226: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ +{ + Token all; + all.z = yymsp[-3].minor.yy0.z; + all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all); +} + break; + case 227: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ +{ + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194); + yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ +} + break; + case 228: /* trigger_time ::= BEFORE */ +{ yymsp[0].minor.yy194 = TK_BEFORE; } + break; + case 229: /* trigger_time ::= AFTER */ +{ yymsp[0].minor.yy194 = TK_AFTER; } + break; + case 230: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy194 = TK_INSTEAD;} + break; + case 231: /* trigger_time ::= */ +{ yymsp[1].minor.yy194 = TK_BEFORE; } + break; + case 232: /* trigger_event ::= DELETE|INSERT */ + case 233: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==233); +{yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;} + break; + case 234: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;} + break; + case 235: /* when_clause ::= */ + case 254: /* key_opt ::= */ yytestcase(yyruleno==254); +{ yymsp[1].minor.yy72 = 0; } + break; + case 236: /* when_clause ::= WHEN expr */ + case 255: /* key_opt ::= KEY expr */ yytestcase(yyruleno==255); +{ yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; } + break; + case 237: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ +{ + assert( yymsp[-2].minor.yy145!=0 ); + yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145; + yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145; +} + break; + case 238: /* trigger_cmd_list ::= trigger_cmd SEMI */ +{ + assert( yymsp[-1].minor.yy145!=0 ); + yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145; +} + break; + case 239: /* trnm ::= nm DOT nm */ +{ + yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; + sqlite3ErrorMsg(pParse, + "qualified table names are not allowed on INSERT, UPDATE, and DELETE " + "statements within triggers"); +} + break; + case 240: /* tridxby ::= INDEXED BY nm */ +{ + sqlite3ErrorMsg(pParse, + "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} + break; + case 241: /* tridxby ::= NOT INDEXED */ +{ + sqlite3ErrorMsg(pParse, + "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} + break; + case 242: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ +{yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);} + break; + case 243: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ +{yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/} + break; + case 244: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ +{yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);} + break; + case 245: /* trigger_cmd ::= select */ +{yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/} + break; + case 246: /* expr ::= RAISE LP IGNORE RP */ +{ + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy190.pExpr ){ + yymsp[-3].minor.yy190.pExpr->affinity = OE_Ignore; + } +} + break; + case 247: /* expr ::= RAISE LP raisetype COMMA nm RP */ +{ + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); + if( yymsp[-5].minor.yy190.pExpr ) { + yymsp[-5].minor.yy190.pExpr->affinity = (char)yymsp[-3].minor.yy194; + } +} + break; + case 248: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy194 = OE_Rollback;} + break; + case 250: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy194 = OE_Fail;} + break; + case 251: /* cmd ::= DROP TRIGGER ifexists fullname */ +{ + sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194); +} + break; + case 252: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ +{ + sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72); +} + break; + case 253: /* cmd ::= DETACH database_kw_opt expr */ +{ + sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr); +} + break; + case 256: /* cmd ::= REINDEX */ +{sqlite3Reindex(pParse, 0, 0);} + break; + case 257: /* cmd ::= REINDEX nm dbnm */ +{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} + break; + case 258: /* cmd ::= ANALYZE */ +{sqlite3Analyze(pParse, 0, 0);} + break; + case 259: /* cmd ::= ANALYZE nm dbnm */ +{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} + break; + case 260: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ +{ + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0); +} + break; + case 261: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ +{ + yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; + sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); +} + break; + case 262: /* add_column_fullname ::= fullname */ +{ + disableLookaside(pParse); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185); +} + break; + case 263: /* cmd ::= create_vtab */ +{sqlite3VtabFinishParse(pParse,0);} + break; + case 264: /* cmd ::= create_vtab LP vtabarglist RP */ +{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} + break; + case 265: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ +{ + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194); +} + break; + case 266: /* vtabarg ::= */ +{sqlite3VtabArgInit(pParse);} + break; + case 267: /* vtabargtoken ::= ANY */ + case 268: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==268); + case 269: /* lp ::= LP */ yytestcase(yyruleno==269); +{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} + break; + case 270: /* with ::= */ +{yymsp[1].minor.yy285 = 0;} + break; + case 271: /* with ::= WITH wqlist */ +{ yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; } + break; + case 272: /* with ::= WITH RECURSIVE wqlist */ +{ yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; } + break; + case 273: /* wqlist ::= nm eidlist_opt AS LP select RP */ +{ + yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/ +} + break; + case 274: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ +{ + yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); +} + break; + default: + /* (275) input ::= cmdlist */ yytestcase(yyruleno==275); + /* (276) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==276); + /* (277) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=277); + /* (278) ecmd ::= SEMI */ yytestcase(yyruleno==278); + /* (279) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==279); + /* (280) explain ::= */ yytestcase(yyruleno==280); + /* (281) trans_opt ::= */ yytestcase(yyruleno==281); + /* (282) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==282); + /* (283) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==283); + /* (284) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==284); + /* (285) savepoint_opt ::= */ yytestcase(yyruleno==285); + /* (286) cmd ::= create_table create_table_args */ yytestcase(yyruleno==286); + /* (287) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==287); + /* (288) columnlist ::= columnname carglist */ yytestcase(yyruleno==288); + /* (289) nm ::= ID|INDEXED */ yytestcase(yyruleno==289); + /* (290) nm ::= STRING */ yytestcase(yyruleno==290); + /* (291) nm ::= JOIN_KW */ yytestcase(yyruleno==291); + /* (292) typetoken ::= typename */ yytestcase(yyruleno==292); + /* (293) typename ::= ID|STRING */ yytestcase(yyruleno==293); + /* (294) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=294); + /* (295) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=295); + /* (296) carglist ::= carglist ccons */ yytestcase(yyruleno==296); + /* (297) carglist ::= */ yytestcase(yyruleno==297); + /* (298) ccons ::= NULL onconf */ yytestcase(yyruleno==298); + /* (299) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==299); + /* (300) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==300); + /* (301) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=301); + /* (302) tconscomma ::= */ yytestcase(yyruleno==302); + /* (303) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=303); + /* (304) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=304); + /* (305) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=305); + /* (306) oneselect ::= values */ yytestcase(yyruleno==306); + /* (307) sclp ::= selcollist COMMA */ yytestcase(yyruleno==307); + /* (308) as ::= ID|STRING */ yytestcase(yyruleno==308); + /* (309) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=309); + /* (310) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==310); + /* (311) exprlist ::= nexprlist */ yytestcase(yyruleno==311); + /* (312) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=312); + /* (313) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=313); + /* (314) nmnum ::= ON */ yytestcase(yyruleno==314); + /* (315) nmnum ::= DELETE */ yytestcase(yyruleno==315); + /* (316) nmnum ::= DEFAULT */ yytestcase(yyruleno==316); + /* (317) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==317); + /* (318) foreach_clause ::= */ yytestcase(yyruleno==318); + /* (319) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==319); + /* (320) trnm ::= nm */ yytestcase(yyruleno==320); + /* (321) tridxby ::= */ yytestcase(yyruleno==321); + /* (322) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==322); + /* (323) database_kw_opt ::= */ yytestcase(yyruleno==323); + /* (324) kwcolumn_opt ::= */ yytestcase(yyruleno==324); + /* (325) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==325); + /* (326) vtabarglist ::= vtabarg */ yytestcase(yyruleno==326); + /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==327); + /* (328) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==328); + /* (329) anylist ::= */ yytestcase(yyruleno==329); + /* (330) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==330); + /* (331) anylist ::= anylist ANY */ yytestcase(yyruleno==331); + break; +/********** End reduce actions ************************************************/ + }; + assert( yyrulenoYY_MAX_SHIFT ){ + yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yymsp -= yysize-1; + yypParser->yytos = yymsp; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yyTraceShift(yypParser, yyact); + }else{ + assert( yyact == YY_ACCEPT_ACTION ); + yypParser->yytos -= yysize; + yy_accept(yypParser); + } +} + +/* +** The following code executes when the parse fails +*/ +#ifndef YYNOERRORRECOVERY +static void yy_parse_failed( + yyParser *yypParser /* The parser */ +){ + sqlite3ParserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + } +#endif + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ +/************ Begin %parse_failure code ***************************************/ +/************ End %parse_failure code *****************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} +#endif /* YYNOERRORRECOVERY */ + +/* +** The following code executes when a syntax error first occurs. +*/ +static void yy_syntax_error( + yyParser *yypParser, /* The parser */ + int yymajor, /* The major type of the error token */ + sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */ +){ + sqlite3ParserARG_FETCH; +#define TOKEN yyminor +/************ Begin %syntax_error code ****************************************/ + + UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ + assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); +/************ End %syntax_error code ******************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following is executed when the parser accepts +*/ +static void yy_accept( + yyParser *yypParser /* The parser */ +){ + sqlite3ParserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + } +#endif +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + assert( yypParser->yytos==yypParser->yystack ); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ +/*********** Begin %parse_accept code *****************************************/ +/*********** End %parse_accept code *******************************************/ + sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "sqlite3ParserAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
      +**
    • A pointer to the parser (an opaque structure.) +**
    • The major token number. +**
    • The minor token number. +**
    • An option argument of a grammar-specified type. +**
    +** +** Outputs: +** None. +*/ +SQLITE_PRIVATE void sqlite3Parser( + void *yyp, /* The parser */ + int yymajor, /* The major token code number */ + sqlite3ParserTOKENTYPE yyminor /* The value for the token */ + sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ +){ + YYMINORTYPE yyminorunion; + unsigned int yyact; /* The parser action. */ +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) + int yyendofinput; /* True if we are at the end of input */ +#endif +#ifdef YYERRORSYMBOL + int yyerrorhit = 0; /* True if yymajor has invoked an error */ +#endif + yyParser *yypParser; /* The parser */ + + yypParser = (yyParser*)yyp; + assert( yypParser->yytos!=0 ); +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) + yyendofinput = (yymajor==0); +#endif + sqlite3ParserARG_STORE; + +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); + } +#endif + + do{ + yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); + if( yyact <= YY_MAX_SHIFTREDUCE ){ + yy_shift(yypParser,yyact,yymajor,yyminor); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt--; +#endif + yymajor = YYNOCODE; + }else if( yyact <= YY_MAX_REDUCE ){ + yy_reduce(yypParser,yyact-YY_MIN_REDUCE); + }else{ + assert( yyact == YY_ERROR_ACTION ); + yyminorunion.yy0 = yyminor; +#ifdef YYERRORSYMBOL + int yymx; +#endif +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + } +#endif +#ifdef YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( yypParser->yyerrcnt<0 ){ + yy_syntax_error(yypParser,yymajor,yyminor); + } + yymx = yypParser->yytos->major; + if( yymx==YYERRORSYMBOL || yyerrorhit ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sDiscard input token %s\n", + yyTracePrompt,yyTokenName[yymajor]); + } +#endif + yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); + yymajor = YYNOCODE; + }else{ + while( yypParser->yytos >= yypParser->yystack + && yymx != YYERRORSYMBOL + && (yyact = yy_find_reduce_action( + yypParser->yytos->stateno, + YYERRORSYMBOL)) >= YY_MIN_REDUCE + ){ + yy_pop_parser_stack(yypParser); + } + if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + yymajor = YYNOCODE; + }else if( yymx!=YYERRORSYMBOL ){ + yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); + } + } + yypParser->yyerrcnt = 3; + yyerrorhit = 1; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor, yyminor); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yymajor = YYNOCODE; + +#else /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( yypParser->yyerrcnt<=0 ){ + yy_syntax_error(yypParser,yymajor, yyminor); + } + yypParser->yyerrcnt = 3; + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + if( yyendofinput ){ + yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + } + yymajor = YYNOCODE; +#endif + } + }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); +#ifndef NDEBUG + if( yyTraceFILE ){ + yyStackEntry *i; + char cDiv = '['; + fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); + for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ + fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); + cDiv = ' '; + } + fprintf(yyTraceFILE,"]\n"); + } +#endif + return; +} + +/************** End of parse.c ***********************************************/ +/************** Begin file tokenize.c ****************************************/ +/* +** 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. +** +************************************************************************* +** An tokenizer for SQL +** +** This file contains C code that splits an SQL input string up into +** individual tokens and sends those tokens one-by-one over to the +** parser for analysis. +*/ +/* #include "sqliteInt.h" */ +/* #include */ + +/* Character classes for tokenizing +** +** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented +** using a lookup table, whereas a switch() directly on c uses a binary search. +** The lookup table is much faster. To maximize speed, and to ensure that +** a lookup table is used, all of the classes need to be small integers and +** all of them need to be used within the switch. +*/ +#define CC_X 0 /* The letter 'x', or start of BLOB literal */ +#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */ +#define CC_ID 2 /* unicode characters usable in IDs */ +#define CC_DIGIT 3 /* Digits */ +#define CC_DOLLAR 4 /* '$' */ +#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */ +#define CC_VARNUM 6 /* '?'. Numeric SQL variables */ +#define CC_SPACE 7 /* Space characters */ +#define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */ +#define CC_QUOTE2 9 /* '['. [...] style quoted ids */ +#define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */ +#define CC_MINUS 11 /* '-'. Minus or SQL-style comment */ +#define CC_LT 12 /* '<'. Part of < or <= or <> */ +#define CC_GT 13 /* '>'. Part of > or >= */ +#define CC_EQ 14 /* '='. Part of = or == */ +#define CC_BANG 15 /* '!'. Part of != */ +#define CC_SLASH 16 /* '/'. / or c-style comment */ +#define CC_LP 17 /* '(' */ +#define CC_RP 18 /* ')' */ +#define CC_SEMI 19 /* ';' */ +#define CC_PLUS 20 /* '+' */ +#define CC_STAR 21 /* '*' */ +#define CC_PERCENT 22 /* '%' */ +#define CC_COMMA 23 /* ',' */ +#define CC_AND 24 /* '&' */ +#define CC_TILDA 25 /* '~' */ +#define CC_DOT 26 /* '.' */ +#define CC_ILLEGAL 27 /* Illegal character */ + +static const unsigned char aiClass[] = { +#ifdef SQLITE_ASCII +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ +/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, +/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, +/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, +/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1, +/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27, +/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +#endif +#ifdef SQLITE_EBCDIC +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ +/* 0x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 7, 7, 27, 27, +/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10, +/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27, +/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6, +/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8, +/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, +/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27, +/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, +/* Ex */ 27, 27, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, +/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 27, 27, 27, 27, 27, +#endif +}; + +/* +** The charMap() macro maps alphabetic characters (only) into their +** lower-case ASCII equivalent. On ASCII machines, this is just +** an upper-to-lower case map. On EBCDIC machines we also need +** to adjust the encoding. The mapping is only valid for alphabetics +** which are the only characters for which this feature is used. +** +** Used by keywordhash.h +*/ +#ifdef SQLITE_ASCII +# define charMap(X) sqlite3UpperToLower[(unsigned char)X] +#endif +#ifdef SQLITE_EBCDIC +# define charMap(X) ebcdicToAscii[(unsigned char)X] +const unsigned char ebcdicToAscii[] = { +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */ + 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */ + 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */ + 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */ + 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */ +}; +#endif + +/* +** The sqlite3KeywordCode function looks up an identifier to determine if +** it is a keyword. If it is a keyword, the token code of that keyword is +** returned. If the input is not a keyword, TK_ID is returned. +** +** The implementation of this routine was generated by a program, +** mkkeywordhash.c, located in the tool subdirectory of the distribution. +** The output of the mkkeywordhash.c program is written into a file +** named keywordhash.h and then included into this source file by +** the #include below. +*/ +/************** Include keywordhash.h in the middle of tokenize.c ************/ +/************** Begin file keywordhash.h *************************************/ +/***** This file contains automatically generated code ****** +** +** The code in this file has been automatically generated by +** +** sqlite/tool/mkkeywordhash.c +** +** The code in this file implements a function that determines whether +** or not a given identifier is really an SQL keyword. The same thing +** might be implemented more directly using a hand-written hash table. +** But by using this automatically generated code, the size of the code +** is substantially reduced. This is important for embedded applications +** on platforms with limited memory. +*/ +/* Hash score: 182 */ +static int keywordCode(const char *z, int n, int *pType){ + /* zText[] encodes 834 bytes of keywords in 554 bytes */ + /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ + /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ + /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ + /* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ + /* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ + /* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ + /* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ + /* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ + /* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ + /* VACUUMVIEWINITIALLY */ + static const char zText[553] = { + 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', + 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', + 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', + 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', + 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N', + 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I', + 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E', + 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E', + 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T', + 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', + 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', + 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', + 'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E', + 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A', + 'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A', + 'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A', + 'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J', + 'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L', + 'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E', + 'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H', + 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E', + 'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E', + 'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M', + 'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R', + 'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A', + 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', + 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', + 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', + 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', + 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', + 'V','I','E','W','I','N','I','T','I','A','L','L','Y', + }; + static const unsigned char aHash[127] = { + 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, + 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, + 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, + 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, + 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, + 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, + 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, + 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, + 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, + 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, + }; + static const unsigned char aNext[124] = { + 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, + 0, 43, 3, 47, 0, 0, 0, 0, 30, 0, 58, 0, 38, + 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, + 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, + 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, + 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, + 73, 83, 0, 35, 68, 0, 0, + }; + static const unsigned char aLen[124] = { + 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, + 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, + 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, + 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, + 6, 6, 5, 6, 5, 5, 9, 7, 7, 3, 2, 4, 4, + 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, + 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, + 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, + 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, + 3, 5, 5, 6, 4, 9, 3, + }; + static const unsigned short int aOffset[124] = { + 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, + 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, + 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, + 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, + 199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246, + 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, + 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, + 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, + 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, + 521, 524, 529, 534, 540, 544, 549, + }; + static const unsigned char aCode[124] = { + TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, + TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, + TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, + TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, + TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, + TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, + TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, + TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, + TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, + TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, + TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, + TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RECURSIVE, TK_BETWEEN, + TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, + TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, + TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, + TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, + TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, + TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND, + TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, + TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, + TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, + TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, + TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, + TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, + TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, + }; + int i, j; + const char *zKW; + if( n>=2 ){ + i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127; + for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){ + if( aLen[i]!=n ) continue; + j = 0; + zKW = &zText[aOffset[i]]; +#ifdef SQLITE_ASCII + while( j=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) +#endif + +/* Make the IdChar function accessible from ctime.c */ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); } +#endif + + +/* +** Return the length (in bytes) of the token that begins at z[0]. +** Store the token type in *tokenType before returning. +*/ +SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ + int i, c; + switch( aiClass[*z] ){ /* Switch on the character-class of the first byte + ** of the token. See the comment on the CC_ defines + ** above. */ + case CC_SPACE: { + testcase( z[0]==' ' ); + testcase( z[0]=='\t' ); + testcase( z[0]=='\n' ); + testcase( z[0]=='\f' ); + testcase( z[0]=='\r' ); + for(i=1; sqlite3Isspace(z[i]); i++){} + *tokenType = TK_SPACE; + return i; + } + case CC_MINUS: { + if( z[1]=='-' ){ + for(i=2; (c=z[i])!=0 && c!='\n'; i++){} + *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ + return i; + } + *tokenType = TK_MINUS; + return 1; + } + case CC_LP: { + *tokenType = TK_LP; + return 1; + } + case CC_RP: { + *tokenType = TK_RP; + return 1; + } + case CC_SEMI: { + *tokenType = TK_SEMI; + return 1; + } + case CC_PLUS: { + *tokenType = TK_PLUS; + return 1; + } + case CC_STAR: { + *tokenType = TK_STAR; + return 1; + } + case CC_SLASH: { + if( z[1]!='*' || z[2]==0 ){ + *tokenType = TK_SLASH; + return 1; + } + for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} + if( c ) i++; + *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ + return i; + } + case CC_PERCENT: { + *tokenType = TK_REM; + return 1; + } + case CC_EQ: { + *tokenType = TK_EQ; + return 1 + (z[1]=='='); + } + case CC_LT: { + if( (c=z[1])=='=' ){ + *tokenType = TK_LE; + return 2; + }else if( c=='>' ){ + *tokenType = TK_NE; + return 2; + }else if( c=='<' ){ + *tokenType = TK_LSHIFT; + return 2; + }else{ + *tokenType = TK_LT; + return 1; + } + } + case CC_GT: { + if( (c=z[1])=='=' ){ + *tokenType = TK_GE; + return 2; + }else if( c=='>' ){ + *tokenType = TK_RSHIFT; + return 2; + }else{ + *tokenType = TK_GT; + return 1; + } + } + case CC_BANG: { + if( z[1]!='=' ){ + *tokenType = TK_ILLEGAL; + return 1; + }else{ + *tokenType = TK_NE; + return 2; + } + } + case CC_PIPE: { + if( z[1]!='|' ){ + *tokenType = TK_BITOR; + return 1; + }else{ + *tokenType = TK_CONCAT; + return 2; + } + } + case CC_COMMA: { + *tokenType = TK_COMMA; + return 1; + } + case CC_AND: { + *tokenType = TK_BITAND; + return 1; + } + case CC_TILDA: { + *tokenType = TK_BITNOT; + return 1; + } + case CC_QUOTE: { + int delim = z[0]; + testcase( delim=='`' ); + testcase( delim=='\'' ); + testcase( delim=='"' ); + for(i=1; (c=z[i])!=0; i++){ + if( c==delim ){ + if( z[i+1]==delim ){ + i++; + }else{ + break; + } + } + } + if( c=='\'' ){ + *tokenType = TK_STRING; + return i+1; + }else if( c!=0 ){ + *tokenType = TK_ID; + return i+1; + }else{ + *tokenType = TK_ILLEGAL; + return i; + } + } + case CC_DOT: { +#ifndef SQLITE_OMIT_FLOATING_POINT + if( !sqlite3Isdigit(z[1]) ) +#endif + { + *tokenType = TK_DOT; + return 1; + } + /* If the next character is a digit, this is a floating point + ** number that begins with ".". Fall thru into the next case */ + } + case CC_DIGIT: { + testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); + testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); + testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); + testcase( z[0]=='9' ); + *tokenType = TK_INTEGER; +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ + for(i=3; sqlite3Isxdigit(z[i]); i++){} + return i; + } +#endif + for(i=0; sqlite3Isdigit(z[i]); i++){} +#ifndef SQLITE_OMIT_FLOATING_POINT + if( z[i]=='.' ){ + i++; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } + if( (z[i]=='e' || z[i]=='E') && + ( sqlite3Isdigit(z[i+1]) + || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) + ) + ){ + i += 2; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } +#endif + while( IdChar(z[i]) ){ + *tokenType = TK_ILLEGAL; + i++; + } + return i; + } + case CC_QUOTE2: { + for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} + *tokenType = c==']' ? TK_ID : TK_ILLEGAL; + return i; + } + case CC_VARNUM: { + *tokenType = TK_VARIABLE; + for(i=1; sqlite3Isdigit(z[i]); i++){} + return i; + } + case CC_DOLLAR: + case CC_VARALPHA: { + int n = 0; + testcase( z[0]=='$' ); testcase( z[0]=='@' ); + testcase( z[0]==':' ); testcase( z[0]=='#' ); + *tokenType = TK_VARIABLE; + for(i=1; (c=z[i])!=0; i++){ + if( IdChar(c) ){ + n++; +#ifndef SQLITE_OMIT_TCL_VARIABLE + }else if( c=='(' && n>0 ){ + do{ + i++; + }while( (c=z[i])!=0 && !sqlite3Isspace(c) && c!=')' ); + if( c==')' ){ + i++; + }else{ + *tokenType = TK_ILLEGAL; + } + break; + }else if( c==':' && z[i+1]==':' ){ + i++; +#endif + }else{ + break; + } + } + if( n==0 ) *tokenType = TK_ILLEGAL; + return i; + } + case CC_KYWD: { + for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} + if( IdChar(z[i]) ){ + /* This token started out using characters that can appear in keywords, + ** but z[i] is a character not allowed within keywords, so this must + ** be an identifier instead */ + i++; + break; + } + *tokenType = TK_ID; + return keywordCode((char*)z, i, tokenType); + } + case CC_X: { +#ifndef SQLITE_OMIT_BLOB_LITERAL + testcase( z[0]=='x' ); testcase( z[0]=='X' ); + if( z[1]=='\'' ){ + *tokenType = TK_BLOB; + for(i=2; sqlite3Isxdigit(z[i]); i++){} + if( z[i]!='\'' || i%2 ){ + *tokenType = TK_ILLEGAL; + while( z[i] && z[i]!='\'' ){ i++; } + } + if( z[i] ) i++; + return i; + } +#endif + /* If it is not a BLOB literal, then it must be an ID, since no + ** SQL keywords start with the letter 'x'. Fall through */ + } + case CC_ID: { + i = 1; + break; + } + default: { + *tokenType = TK_ILLEGAL; + return 1; + } + } + while( IdChar(z[i]) ){ i++; } + *tokenType = TK_ID; + return i; +} + +/* +** Run the parser on the given SQL string. The parser structure is +** passed in. An SQLITE_ status code is returned. If an error occurs +** then an and attempt is made to write an error message into +** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that +** error message. +*/ +SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ + int nErr = 0; /* Number of errors encountered */ + void *pEngine; /* The LEMON-generated LALR(1) parser */ + int n = 0; /* Length of the next token token */ + int tokenType; /* type of the next token */ + int lastTokenParsed = -1; /* type of the previous token */ + sqlite3 *db = pParse->db; /* The database connection */ + int mxSqlLen; /* Max length of an SQL string */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ +#endif + + assert( zSql!=0 ); + mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; + if( db->nVdbeActive==0 ){ + db->u1.isInterrupted = 0; + } + pParse->rc = SQLITE_OK; + pParse->zTail = zSql; + assert( pzErrMsg!=0 ); + /* sqlite3ParserTrace(stdout, "parser: "); */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + pEngine = &sEngine; + sqlite3ParserInit(pEngine); +#else + pEngine = sqlite3ParserAlloc(sqlite3Malloc); + if( pEngine==0 ){ + sqlite3OomFault(db); + return SQLITE_NOMEM_BKPT; + } +#endif + assert( pParse->pNewTable==0 ); + assert( pParse->pNewTrigger==0 ); + assert( pParse->nVar==0 ); + assert( pParse->pVList==0 ); + while( 1 ){ + if( zSql[0]!=0 ){ + n = sqlite3GetToken((u8*)zSql, &tokenType); + mxSqlLen -= n; + if( mxSqlLen<0 ){ + pParse->rc = SQLITE_TOOBIG; + break; + } + }else{ + /* Upon reaching the end of input, call the parser two more times + ** with tokens TK_SEMI and 0, in that order. */ + if( lastTokenParsed==TK_SEMI ){ + tokenType = 0; + }else if( lastTokenParsed==0 ){ + break; + }else{ + tokenType = TK_SEMI; + } + zSql -= n; + } + if( tokenType>=TK_SPACE ){ + assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); + if( db->u1.isInterrupted ){ + pParse->rc = SQLITE_INTERRUPT; + break; + } + if( tokenType==TK_ILLEGAL ){ + sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql); + break; + } + zSql += n; + }else{ + pParse->sLastToken.z = zSql; + pParse->sLastToken.n = n; + sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); + lastTokenParsed = tokenType; + zSql += n; + if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; + } + } + assert( nErr==0 ); + pParse->zTail = zSql; +#ifdef YYTRACKMAXSTACKDEPTH + sqlite3_mutex_enter(sqlite3MallocMutex()); + sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, + sqlite3ParserStackPeak(pEngine) + ); + sqlite3_mutex_leave(sqlite3MallocMutex()); +#endif /* YYDEBUG */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + sqlite3ParserFinalize(pEngine); +#else + sqlite3ParserFree(pEngine, sqlite3_free); +#endif + if( db->mallocFailed ){ + pParse->rc = SQLITE_NOMEM_BKPT; + } + if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ + pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); + } + assert( pzErrMsg!=0 ); + if( pParse->zErrMsg ){ + *pzErrMsg = pParse->zErrMsg; + sqlite3_log(pParse->rc, "%s", *pzErrMsg); + pParse->zErrMsg = 0; + nErr++; + } + if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){ + sqlite3VdbeDelete(pParse->pVdbe); + pParse->pVdbe = 0; + } +#ifndef SQLITE_OMIT_SHARED_CACHE + if( pParse->nested==0 ){ + sqlite3DbFree(db, pParse->aTableLock); + pParse->aTableLock = 0; + pParse->nTableLock = 0; + } +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3_free(pParse->apVtabLock); +#endif + + if( !IN_DECLARE_VTAB ){ + /* If the pParse->declareVtab flag is set, do not delete any table + ** structure built up in pParse->pNewTable. The calling code (see vtab.c) + ** will take responsibility for freeing the Table structure. + */ + sqlite3DeleteTable(db, pParse->pNewTable); + } + + if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); + sqlite3DeleteTrigger(db, pParse->pNewTrigger); + sqlite3DbFree(db, pParse->pVList); + while( pParse->pAinc ){ + AutoincInfo *p = pParse->pAinc; + pParse->pAinc = p->pNext; + sqlite3DbFreeNN(db, p); + } + while( pParse->pZombieTab ){ + Table *p = pParse->pZombieTab; + pParse->pZombieTab = p->pNextZombie; + sqlite3DeleteTable(db, p); + } + assert( nErr==0 || pParse->rc!=SQLITE_OK ); + return nErr; +} + +/************** End of tokenize.c ********************************************/ +/************** Begin file complete.c ****************************************/ +/* +** 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. +** +************************************************************************* +** An tokenizer for SQL +** +** This file contains C code that implements the sqlite3_complete() API. +** This code used to be part of the tokenizer.c source file. But by +** separating it out, the code will be automatically omitted from +** static links that do not use it. +*/ +/* #include "sqliteInt.h" */ +#ifndef SQLITE_OMIT_COMPLETE + +/* +** This is defined in tokenize.c. We just have to import the definition. +*/ +#ifndef SQLITE_AMALGAMATION +#ifdef SQLITE_ASCII +#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) +#endif +#ifdef SQLITE_EBCDIC +SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; +#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) +#endif +#endif /* SQLITE_AMALGAMATION */ + + +/* +** Token types used by the sqlite3_complete() routine. See the header +** comments on that procedure for additional information. +*/ +#define tkSEMI 0 +#define tkWS 1 +#define tkOTHER 2 +#ifndef SQLITE_OMIT_TRIGGER +#define tkEXPLAIN 3 +#define tkCREATE 4 +#define tkTEMP 5 +#define tkTRIGGER 6 +#define tkEND 7 +#endif + +/* +** Return TRUE if the given SQL string ends in a semicolon. +** +** Special handling is require for CREATE TRIGGER statements. +** Whenever the CREATE TRIGGER keywords are seen, the statement +** must end with ";END;". +** +** This implementation uses a state machine with 8 states: +** +** (0) INVALID We have not yet seen a non-whitespace character. +** +** (1) START At the beginning or end of an SQL statement. This routine +** returns 1 if it ends in the START state and 0 if it ends +** in any other state. +** +** (2) NORMAL We are in the middle of statement which ends with a single +** semicolon. +** +** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of +** a statement. +** +** (4) CREATE The keyword CREATE has been seen at the beginning of a +** statement, possibly preceded by EXPLAIN and/or followed by +** TEMP or TEMPORARY +** +** (5) TRIGGER We are in the middle of a trigger definition that must be +** ended by a semicolon, the keyword END, and another semicolon. +** +** (6) SEMI We've seen the first semicolon in the ";END;" that occurs at +** the end of a trigger definition. +** +** (7) END We've seen the ";END" of the ";END;" that occurs at the end +** of a trigger definition. +** +** Transitions between states above are determined by tokens extracted +** from the input. The following tokens are significant: +** +** (0) tkSEMI A semicolon. +** (1) tkWS Whitespace. +** (2) tkOTHER Any other SQL token. +** (3) tkEXPLAIN The "explain" keyword. +** (4) tkCREATE The "create" keyword. +** (5) tkTEMP The "temp" or "temporary" keyword. +** (6) tkTRIGGER The "trigger" keyword. +** (7) tkEND The "end" keyword. +** +** Whitespace never causes a state transition and is always ignored. +** This means that a SQL string of all whitespace is invalid. +** +** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed +** to recognize the end of a trigger can be omitted. All we have to do +** is look for a semicolon that is not part of an string or comment. +*/ +SQLITE_API int sqlite3_complete(const char *zSql){ + u8 state = 0; /* Current state, using numbers defined in header comment */ + u8 token; /* Value of the next token */ + +#ifndef SQLITE_OMIT_TRIGGER + /* A complex statement machine used to detect the end of a CREATE TRIGGER + ** statement. This is the normal case. + */ + static const u8 trans[8][8] = { + /* Token: */ + /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ + /* 0 INVALID: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, + /* 1 START: */ { 1, 1, 2, 3, 4, 2, 2, 2, }, + /* 2 NORMAL: */ { 1, 2, 2, 2, 2, 2, 2, 2, }, + /* 3 EXPLAIN: */ { 1, 3, 3, 2, 4, 2, 2, 2, }, + /* 4 CREATE: */ { 1, 4, 2, 2, 2, 4, 5, 2, }, + /* 5 TRIGGER: */ { 6, 5, 5, 5, 5, 5, 5, 5, }, + /* 6 SEMI: */ { 6, 6, 5, 5, 5, 5, 5, 7, }, + /* 7 END: */ { 1, 7, 5, 5, 5, 5, 5, 5, }, + }; +#else + /* If triggers are not supported by this compile then the statement machine + ** used to detect the end of a statement is much simpler + */ + static const u8 trans[3][3] = { + /* Token: */ + /* State: ** SEMI WS OTHER */ + /* 0 INVALID: */ { 1, 0, 2, }, + /* 1 START: */ { 1, 1, 2, }, + /* 2 NORMAL: */ { 1, 2, 2, }, + }; +#endif /* SQLITE_OMIT_TRIGGER */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( zSql==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + + while( *zSql ){ + switch( *zSql ){ + case ';': { /* A semicolon */ + token = tkSEMI; + break; + } + case ' ': + case '\r': + case '\t': + case '\n': + case '\f': { /* White space is ignored */ + token = tkWS; + break; + } + case '/': { /* C-style comments */ + if( zSql[1]!='*' ){ + token = tkOTHER; + break; + } + zSql += 2; + while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } + if( zSql[0]==0 ) return 0; + zSql++; + token = tkWS; + break; + } + case '-': { /* SQL-style comments from "--" to end of line */ + if( zSql[1]!='-' ){ + token = tkOTHER; + break; + } + while( *zSql && *zSql!='\n' ){ zSql++; } + if( *zSql==0 ) return state==1; + token = tkWS; + break; + } + case '[': { /* Microsoft-style identifiers in [...] */ + zSql++; + while( *zSql && *zSql!=']' ){ zSql++; } + if( *zSql==0 ) return 0; + token = tkOTHER; + break; + } + case '`': /* Grave-accent quoted symbols used by MySQL */ + case '"': /* single- and double-quoted strings */ + case '\'': { + int c = *zSql; + zSql++; + while( *zSql && *zSql!=c ){ zSql++; } + if( *zSql==0 ) return 0; + token = tkOTHER; + break; + } + default: { +#ifdef SQLITE_EBCDIC + unsigned char c; +#endif + if( IdChar((u8)*zSql) ){ + /* Keywords and unquoted identifiers */ + int nId; + for(nId=1; IdChar(zSql[nId]); nId++){} +#ifdef SQLITE_OMIT_TRIGGER + token = tkOTHER; +#else + switch( *zSql ){ + case 'c': case 'C': { + if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){ + token = tkCREATE; + }else{ + token = tkOTHER; + } + break; + } + case 't': case 'T': { + if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){ + token = tkTRIGGER; + }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){ + token = tkTEMP; + }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){ + token = tkTEMP; + }else{ + token = tkOTHER; + } + break; + } + case 'e': case 'E': { + if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){ + token = tkEND; + }else +#ifndef SQLITE_OMIT_EXPLAIN + if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){ + token = tkEXPLAIN; + }else +#endif + { + token = tkOTHER; + } + break; + } + default: { + token = tkOTHER; + break; + } + } +#endif /* SQLITE_OMIT_TRIGGER */ + zSql += nId-1; + }else{ + /* Operators and special symbols */ + token = tkOTHER; + } + break; + } + } + state = trans[state][token]; + zSql++; + } + return state==1; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** This routine is the same as the sqlite3_complete() routine described +** above, except that the parameter is required to be UTF-16 encoded, not +** UTF-8. +*/ +SQLITE_API int sqlite3_complete16(const void *zSql){ + sqlite3_value *pVal; + char const *zSql8; + int rc; + +#ifndef SQLITE_OMIT_AUTOINIT + rc = sqlite3_initialize(); + if( rc ) return rc; +#endif + pVal = sqlite3ValueNew(0); + sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); + zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); + if( zSql8 ){ + rc = sqlite3_complete(zSql8); + }else{ + rc = SQLITE_NOMEM_BKPT; + } + sqlite3ValueFree(pVal); + return rc & 0xff; +} +#endif /* SQLITE_OMIT_UTF16 */ +#endif /* SQLITE_OMIT_COMPLETE */ + +/************** End of complete.c ********************************************/ +/************** Begin file main.c ********************************************/ +/* +** 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. +** +************************************************************************* +** Main file for the SQLite library. The routines in this file +** implement the programmer interface to the library. Routines in +** other files are for internal use by SQLite and should not be +** accessed by users of the library. +*/ +/* #include "sqliteInt.h" */ + +#ifdef SQLITE_ENABLE_FTS3 +/************** Include fts3.h in the middle of main.c ***********************/ +/************** Begin file fts3.h ********************************************/ +/* +** 2006 Oct 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 header file is used by programs that want to link against the +** FTS3 library. All it does is declare the sqlite3Fts3Init() interface. +*/ +/* #include "sqlite3.h" */ + +#if 0 +extern "C" { +#endif /* __cplusplus */ + +SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db); + +#if 0 +} /* extern "C" */ +#endif /* __cplusplus */ + +/************** End of fts3.h ************************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif +#ifdef SQLITE_ENABLE_RTREE +/************** Include rtree.h in the middle of main.c **********************/ +/************** Begin file rtree.h *******************************************/ +/* +** 2008 May 26 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file is used by programs that want to link against the +** RTREE library. All it does is declare the sqlite3RtreeInit() interface. +*/ +/* #include "sqlite3.h" */ + +#if 0 +extern "C" { +#endif /* __cplusplus */ + +SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); + +#if 0 +} /* extern "C" */ +#endif /* __cplusplus */ + +/************** End of rtree.h ***********************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif +#ifdef SQLITE_ENABLE_ICU +/************** Include sqliteicu.h in the middle of main.c ******************/ +/************** Begin file sqliteicu.h ***************************************/ +/* +** 2008 May 26 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file is used by programs that want to link against the +** ICU extension. All it does is declare the sqlite3IcuInit() interface. +*/ +/* #include "sqlite3.h" */ + +#if 0 +extern "C" { +#endif /* __cplusplus */ + +SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); + +#if 0 +} /* extern "C" */ +#endif /* __cplusplus */ + + +/************** End of sqliteicu.h *******************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif +#ifdef SQLITE_ENABLE_JSON1 +SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*); +#endif +#ifdef SQLITE_ENABLE_FTS5 +SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); +#endif + +#ifndef SQLITE_AMALGAMATION +/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant +** contains the text of SQLITE_VERSION macro. +*/ +SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; +#endif + +/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns +** a pointer to the to the sqlite3_version[] string constant. +*/ +SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; } + +/* IMPLEMENTATION-OF: R-63124-39300 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_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. +*/ +SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } + +/* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns +** zero if and only if SQLite was compiled with mutexing code omitted due to +** the SQLITE_THREADSAFE compile-time option being set to 0. +*/ +SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } + +/* +** When compiling the test fixture or with debugging enabled (on Win32), +** this variable being set to non-zero will cause OSTRACE macros to emit +** extra diagnostic information. +*/ +#ifdef SQLITE_HAVE_OS_TRACE +# ifndef SQLITE_DEBUG_OS_TRACE +# define SQLITE_DEBUG_OS_TRACE 0 +# endif + int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; +#endif + +#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) +/* +** If the following function pointer is not NULL and if +** SQLITE_ENABLE_IOTRACE is enabled, then messages describing +** I/O active are written using this function. These messages +** are intended for debugging activity only. +*/ +SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0; +#endif + +/* +** If the following global variable points to a string which is the +** name of a directory, then that directory will be used to store +** temporary files. +** +** See also the "PRAGMA temp_store_directory" SQL command. +*/ +SQLITE_API char *sqlite3_temp_directory = 0; + +/* +** If the following global variable points to a string which is the +** name of a directory, then that directory will be used to store +** all database files specified with a relative pathname. +** +** See also the "PRAGMA data_store_directory" SQL command. +*/ +SQLITE_API char *sqlite3_data_directory = 0; + +/* +** Initialize SQLite. +** +** This routine must be called to initialize the memory allocation, +** VFS, and mutex subsystems prior to doing any serious work with +** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT +** this routine will be called automatically by key routines such as +** sqlite3_open(). +** +** This routine is a no-op except on its very first call for the process, +** or for the first call after a call to sqlite3_shutdown. +** +** The first thread to call this routine runs the initialization to +** completion. If subsequent threads call this routine before the first +** thread has finished the initialization process, then the subsequent +** threads must block until the first thread finishes with the initialization. +** +** The first thread might call this routine recursively. Recursive +** calls to this routine should not block, of course. Otherwise the +** initialization process would never complete. +** +** Let X be the first thread to enter this routine. Let Y be some other +** thread. Then while the initial invocation of this routine by X is +** incomplete, it is required that: +** +** * Calls to this routine from Y must block until the outer-most +** call by X completes. +** +** * Recursive calls to this routine from thread X return immediately +** without blocking. +*/ +SQLITE_API int sqlite3_initialize(void){ + MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ + int rc; /* Result code */ +#ifdef SQLITE_EXTRA_INIT + int bRunExtraInit = 0; /* Extra initialization needed */ +#endif + +#ifdef SQLITE_OMIT_WSD + rc = sqlite3_wsd_init(4096, 24); + if( rc!=SQLITE_OK ){ + return rc; + } +#endif + + /* If the following assert() fails on some obscure processor/compiler + ** combination, the work-around is to set the correct pointer + ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */ + assert( SQLITE_PTRSIZE==sizeof(char*) ); + + /* If SQLite is already completely initialized, then this call + ** to sqlite3_initialize() should be a no-op. But the initialization + ** must be complete. So isInit must not be set until the very end + ** of this routine. + */ + if( sqlite3GlobalConfig.isInit ) return SQLITE_OK; + + /* Make sure the mutex subsystem is initialized. If unable to + ** initialize the mutex subsystem, return early with the error. + ** If the system is so sick that we are unable to allocate a mutex, + ** there is not much SQLite is going to be able to do. + ** + ** The mutex subsystem must take care of serializing its own + ** initialization. + */ + rc = sqlite3MutexInit(); + if( rc ) return rc; + + /* Initialize the malloc() system and the recursive pInitMutex mutex. + ** This operation is protected by the STATIC_MASTER mutex. Note that + ** MutexAlloc() is called for a static mutex prior to initializing the + ** malloc subsystem - this implies that the allocation of a static + ** mutex must not require support from the malloc subsystem. + */ + MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) + sqlite3_mutex_enter(pMaster); + sqlite3GlobalConfig.isMutexInit = 1; + if( !sqlite3GlobalConfig.isMallocInit ){ + rc = sqlite3MallocInit(); + } + if( rc==SQLITE_OK ){ + sqlite3GlobalConfig.isMallocInit = 1; + if( !sqlite3GlobalConfig.pInitMutex ){ + sqlite3GlobalConfig.pInitMutex = + sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); + if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){ + rc = SQLITE_NOMEM_BKPT; + } + } + } + if( rc==SQLITE_OK ){ + sqlite3GlobalConfig.nRefInitMutex++; + } + sqlite3_mutex_leave(pMaster); + + /* If rc is not SQLITE_OK at this point, then either the malloc + ** subsystem could not be initialized or the system failed to allocate + ** the pInitMutex mutex. Return an error in either case. */ + if( rc!=SQLITE_OK ){ + return rc; + } + + /* Do the rest of the initialization under the recursive mutex so + ** that we will be able to handle recursive calls into + ** sqlite3_initialize(). The recursive calls normally come through + ** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other + ** recursive calls might also be possible. + ** + ** IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls + ** to the xInit method, so the xInit method need not be threadsafe. + ** + ** The following mutex is what serializes access to the appdef pcache xInit + ** methods. The sqlite3_pcache_methods.xInit() all is embedded in the + ** call to sqlite3PcacheInitialize(). + */ + sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex); + if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){ + sqlite3GlobalConfig.inProgress = 1; +#ifdef SQLITE_ENABLE_SQLLOG + { + extern void sqlite3_init_sqllog(void); + sqlite3_init_sqllog(); + } +#endif + memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions)); + sqlite3RegisterBuiltinFunctions(); + if( sqlite3GlobalConfig.isPCacheInit==0 ){ + rc = sqlite3PcacheInitialize(); + } + if( rc==SQLITE_OK ){ + sqlite3GlobalConfig.isPCacheInit = 1; + rc = sqlite3OsInit(); + } + if( rc==SQLITE_OK ){ + sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, + sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); + sqlite3GlobalConfig.isInit = 1; +#ifdef SQLITE_EXTRA_INIT + bRunExtraInit = 1; +#endif + } + sqlite3GlobalConfig.inProgress = 0; + } + sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex); + + /* Go back under the static mutex and clean up the recursive + ** mutex to prevent a resource leak. + */ + sqlite3_mutex_enter(pMaster); + sqlite3GlobalConfig.nRefInitMutex--; + if( sqlite3GlobalConfig.nRefInitMutex<=0 ){ + assert( sqlite3GlobalConfig.nRefInitMutex==0 ); + sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex); + sqlite3GlobalConfig.pInitMutex = 0; + } + sqlite3_mutex_leave(pMaster); + + /* The following is just a sanity check to make sure SQLite has + ** been compiled correctly. It is important to run this code, but + ** we don't want to run it too often and soak up CPU cycles for no + ** reason. So we run it once during initialization. + */ +#ifndef NDEBUG +#ifndef SQLITE_OMIT_FLOATING_POINT + /* This section of code's only "output" is via assert() statements. */ + if ( rc==SQLITE_OK ){ + u64 x = (((u64)1)<<63)-1; + double y; + assert(sizeof(x)==8); + assert(sizeof(x)==sizeof(y)); + memcpy(&y, &x, 8); + assert( sqlite3IsNaN(y) ); + } +#endif +#endif + + /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT + ** compile-time option. + */ +#ifdef SQLITE_EXTRA_INIT + if( bRunExtraInit ){ + int SQLITE_EXTRA_INIT(const char*); + rc = SQLITE_EXTRA_INIT(0); + } +#endif + + return rc; +} + +/* +** Undo the effects of sqlite3_initialize(). Must not be called while +** there are outstanding database connections or memory allocations or +** while any part of SQLite is otherwise in use in any thread. This +** routine is not threadsafe. But it is safe to invoke this routine +** on when SQLite is already shut down. If SQLite is already shut down +** when this routine is invoked, then this routine is a harmless no-op. +*/ +SQLITE_API int sqlite3_shutdown(void){ +#ifdef SQLITE_OMIT_WSD + int rc = sqlite3_wsd_init(4096, 24); + if( rc!=SQLITE_OK ){ + return rc; + } +#endif + + if( sqlite3GlobalConfig.isInit ){ +#ifdef SQLITE_EXTRA_SHUTDOWN + void SQLITE_EXTRA_SHUTDOWN(void); + SQLITE_EXTRA_SHUTDOWN(); +#endif + sqlite3_os_end(); + sqlite3_reset_auto_extension(); + sqlite3GlobalConfig.isInit = 0; + } + if( sqlite3GlobalConfig.isPCacheInit ){ + sqlite3PcacheShutdown(); + sqlite3GlobalConfig.isPCacheInit = 0; + } + if( sqlite3GlobalConfig.isMallocInit ){ + sqlite3MallocEnd(); + sqlite3GlobalConfig.isMallocInit = 0; + +#ifndef SQLITE_OMIT_SHUTDOWN_DIRECTORIES + /* The heap subsystem has now been shutdown and these values are supposed + ** to be NULL or point to memory that was obtained from sqlite3_malloc(), + ** which would rely on that heap subsystem; therefore, make sure these + ** values cannot refer to heap memory that was just invalidated when the + ** heap subsystem was shutdown. This is only done if the current call to + ** this function resulted in the heap subsystem actually being shutdown. + */ + sqlite3_data_directory = 0; + sqlite3_temp_directory = 0; +#endif + } + if( sqlite3GlobalConfig.isMutexInit ){ + sqlite3MutexEnd(); + sqlite3GlobalConfig.isMutexInit = 0; + } + + return SQLITE_OK; +} + +/* +** This API allows applications to modify the global configuration of +** the SQLite library at run-time. +** +** This routine should only be called when there are no outstanding +** database connections or memory allocations. This routine is not +** threadsafe. Failure to heed these warnings can lead to unpredictable +** behavior. +*/ +SQLITE_API int sqlite3_config(int op, ...){ + va_list ap; + int rc = SQLITE_OK; + + /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while + ** the SQLite library is in use. */ + if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; + + va_start(ap, op); + switch( op ){ + + /* Mutex configuration options are only available in a threadsafe + ** compile. + */ +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ + case SQLITE_CONFIG_SINGLETHREAD: { + /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to + ** Single-thread. */ + sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ + case SQLITE_CONFIG_MULTITHREAD: { + /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to + ** Multi-thread. */ + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ + case SQLITE_CONFIG_SERIALIZED: { + /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to + ** Serialized. */ + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */ + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ + case SQLITE_CONFIG_MUTEX: { + /* Specify an alternative mutex implementation */ + sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*); + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */ + case SQLITE_CONFIG_GETMUTEX: { + /* Retrieve the current mutex implementation */ + *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex; + break; + } +#endif + + case SQLITE_CONFIG_MALLOC: { + /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The argument specifies alternative + ** low-level memory allocation routines to be used in place of the memory + ** allocation routines built into SQLite. */ + sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); + break; + } + case SQLITE_CONFIG_GETMALLOC: { + /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is + ** filled with the currently defined memory allocation routines. */ + if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault(); + *va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m; + break; + } + case SQLITE_CONFIG_MEMSTATUS: { + /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes + ** single argument of type int, interpreted as a boolean, which enables + ** or disables the collection of memory allocation statistics. */ + 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); + break; + } + case SQLITE_CONFIG_PAGECACHE: { + /* EVIDENCE-OF: R-18761-36601 There are three arguments to + ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem), + ** the size of each page cache line (sz), and the number of cache lines + ** (N). */ + sqlite3GlobalConfig.pPage = va_arg(ap, void*); + sqlite3GlobalConfig.szPage = va_arg(ap, int); + sqlite3GlobalConfig.nPage = va_arg(ap, int); + break; + } + case SQLITE_CONFIG_PCACHE_HDRSZ: { + /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes + ** a single parameter which is a pointer to an integer and writes into + ** that integer the number of extra bytes per page required for each page + ** in SQLITE_CONFIG_PAGECACHE. */ + *va_arg(ap, int*) = + sqlite3HeaderSizeBtree() + + sqlite3HeaderSizePcache() + + sqlite3HeaderSizePcache1(); + break; + } + + case SQLITE_CONFIG_PCACHE: { + /* no-op */ + break; + } + case SQLITE_CONFIG_GETPCACHE: { + /* now an error */ + rc = SQLITE_ERROR; + break; + } + + case SQLITE_CONFIG_PCACHE2: { + /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. This object specifies the interface to a custom page cache + ** implementation. */ + sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*); + break; + } + case SQLITE_CONFIG_GETPCACHE2: { + /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. SQLite copies of the current page cache implementation into + ** that object. */ + if( sqlite3GlobalConfig.pcache2.xInit==0 ){ + sqlite3PCacheSetDefault(); + } + *va_arg(ap, sqlite3_pcache_methods2*) = sqlite3GlobalConfig.pcache2; + break; + } + +/* EVIDENCE-OF: R-06626-12911 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. */ +#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) + case SQLITE_CONFIG_HEAP: { + /* EVIDENCE-OF: R-19854-42126 There are three arguments to + ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the + ** number of bytes in the memory buffer, and the minimum allocation size. + */ + sqlite3GlobalConfig.pHeap = va_arg(ap, void*); + sqlite3GlobalConfig.nHeap = va_arg(ap, int); + sqlite3GlobalConfig.mnReq = va_arg(ap, int); + + if( sqlite3GlobalConfig.mnReq<1 ){ + sqlite3GlobalConfig.mnReq = 1; + }else if( sqlite3GlobalConfig.mnReq>(1<<12) ){ + /* cap min request size at 2^12 */ + sqlite3GlobalConfig.mnReq = (1<<12); + } + + if( sqlite3GlobalConfig.pHeap==0 ){ + /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer) + ** is NULL, then SQLite reverts to using its default memory allocator + ** (the system malloc() implementation), undoing any prior invocation of + ** SQLITE_CONFIG_MALLOC. + ** + ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to + ** revert to its default implementation when sqlite3_initialize() is run + */ + memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m)); + }else{ + /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the + ** alternative memory allocator is engaged to handle all of SQLites + ** memory allocation needs. */ +#ifdef SQLITE_ENABLE_MEMSYS3 + sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3(); +#endif +#ifdef SQLITE_ENABLE_MEMSYS5 + sqlite3GlobalConfig.m = *sqlite3MemGetMemsys5(); +#endif + } + break; + } +#endif + + case SQLITE_CONFIG_LOOKASIDE: { + sqlite3GlobalConfig.szLookaside = va_arg(ap, int); + sqlite3GlobalConfig.nLookaside = va_arg(ap, int); + break; + } + + /* Record a pointer to the logger function and its first argument. + ** The default is NULL. Logging is disabled if the function pointer is + ** NULL. + */ + case SQLITE_CONFIG_LOG: { + /* MSVC is picky about pulling func ptrs from va lists. + ** http://support.microsoft.com/kb/47961 + ** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*)); + */ + typedef void(*LOGFUNC_t)(void*,int,const char*); + sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); + sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); + break; + } + + /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames + ** can be changed at start-time using the + ** sqlite3_config(SQLITE_CONFIG_URI,1) or + ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. + */ + case SQLITE_CONFIG_URI: { + /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single + ** argument of type int. If non-zero, then URI handling is globally + ** enabled. If the parameter is zero, then URI handling is globally + ** disabled. */ + sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); + break; + } + + case SQLITE_CONFIG_COVERING_INDEX_SCAN: { + /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN + ** option takes a single integer argument which is interpreted as a + ** boolean in order to enable or disable the use of covering indices for + ** full table scans in the query optimizer. */ + sqlite3GlobalConfig.bUseCis = va_arg(ap, int); + break; + } + +#ifdef SQLITE_ENABLE_SQLLOG + case SQLITE_CONFIG_SQLLOG: { + typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); + sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); + sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); + break; + } +#endif + + case SQLITE_CONFIG_MMAP_SIZE: { + /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit + ** integer (sqlite3_int64) values that are the default mmap size limit + ** (the default setting for PRAGMA mmap_size) and the maximum allowed + ** mmap size limit. */ + sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); + sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); + /* EVIDENCE-OF: R-53367-43190 If either argument to this option is + ** negative, then that argument is changed to its compile-time default. + ** + ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be + ** silently truncated if necessary so that it does not exceed the + ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE + ** compile-time option. + */ + if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ + mxMmap = SQLITE_MAX_MMAP_SIZE; + } + if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; + if( szMmap>mxMmap) szMmap = mxMmap; + sqlite3GlobalConfig.mxMmap = mxMmap; + sqlite3GlobalConfig.szMmap = szMmap; + break; + } + +#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */ + case SQLITE_CONFIG_WIN32_HEAPSIZE: { + /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit + ** unsigned integer value that specifies the maximum size of the created + ** heap. */ + sqlite3GlobalConfig.nHeap = va_arg(ap, int); + break; + } +#endif + + case SQLITE_CONFIG_PMASZ: { + sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int); + break; + } + + case SQLITE_CONFIG_STMTJRNL_SPILL: { + sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int); + break; + } + + default: { + rc = SQLITE_ERROR; + break; + } + } + va_end(ap); + return rc; +} + +/* +** Set up the lookaside buffers for a database connection. +** Return SQLITE_OK on success. +** If lookaside is already active, return SQLITE_BUSY. +** +** The sz parameter is the number of bytes in each lookaside slot. +** The cnt parameter is the number of slots. If pStart is NULL the +** space for the lookaside memory is obtained from sqlite3_malloc(). +** If pStart is not NULL then it is sz*cnt bytes of memory to use for +** the lookaside memory. +*/ +static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ +#ifndef SQLITE_OMIT_LOOKASIDE + void *pStart; + if( db->lookaside.nOut ){ + return SQLITE_BUSY; + } + /* Free any existing lookaside buffer for this handle before + ** allocating a new one so we don't have to have space for + ** both at the same time. + */ + if( db->lookaside.bMalloced ){ + sqlite3_free(db->lookaside.pStart); + } + /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger + ** than a pointer to be useful. + */ + sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */ + if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; + if( cnt<0 ) cnt = 0; + if( sz==0 || cnt==0 ){ + sz = 0; + pStart = 0; + }else if( pBuf==0 ){ + sqlite3BeginBenignMalloc(); + pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */ + sqlite3EndBenignMalloc(); + if( pStart ) cnt = sqlite3MallocSize(pStart)/sz; + }else{ + pStart = pBuf; + } + db->lookaside.pStart = pStart; + db->lookaside.pFree = 0; + db->lookaside.sz = (u16)sz; + if( pStart ){ + int i; + LookasideSlot *p; + assert( sz > (int)sizeof(LookasideSlot*) ); + p = (LookasideSlot*)pStart; + for(i=cnt-1; i>=0; i--){ + p->pNext = db->lookaside.pFree; + db->lookaside.pFree = p; + p = (LookasideSlot*)&((u8*)p)[sz]; + } + db->lookaside.pEnd = p; + db->lookaside.bDisable = 0; + db->lookaside.bMalloced = pBuf==0 ?1:0; + }else{ + db->lookaside.pStart = db; + db->lookaside.pEnd = db; + db->lookaside.bDisable = 1; + db->lookaside.bMalloced = 0; + } +#endif /* SQLITE_OMIT_LOOKASIDE */ + return SQLITE_OK; +} + +/* +** Return the mutex associated with a database connection. +*/ +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->mutex; +} + +/* +** Free up as much memory as we can from the given database +** connection. +*/ +SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){ + int i; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + Pager *pPager = sqlite3BtreePager(pBt); + sqlite3PagerShrink(pPager); + } + } + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +/* +** Flush any dirty pages in the pager-cache for any attached database +** to disk. +*/ +SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ + int i; + int rc = SQLITE_OK; + int bSeenBusy = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt && sqlite3BtreeIsInTrans(pBt) ){ + Pager *pPager = sqlite3BtreePager(pBt); + rc = sqlite3PagerFlush(pPager); + if( rc==SQLITE_BUSY ){ + bSeenBusy = 1; + rc = SQLITE_OK; + } + } + } + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc); +} + +/* +** Configuration settings for an individual database connection +*/ +SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ + va_list ap; + int rc; + va_start(ap, op); + switch( op ){ + case SQLITE_DBCONFIG_MAINDBNAME: { + db->aDb[0].zDbSName = va_arg(ap,char*); + rc = SQLITE_OK; + break; + } + case SQLITE_DBCONFIG_LOOKASIDE: { + void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ + int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ + int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */ + rc = setupLookaside(db, pBuf, sz, cnt); + break; + } + default: { + static const struct { + int op; /* The opcode */ + u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ + } aFlagOp[] = { + { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, + { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, + { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, + { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, + { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, + }; + unsigned int i; + rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ + for(i=0; iflags; + if( onoff>0 ){ + db->flags |= aFlagOp[i].mask; + }else if( onoff==0 ){ + db->flags &= ~aFlagOp[i].mask; + } + if( oldFlags!=db->flags ){ + sqlite3ExpirePreparedStatements(db); + } + if( pRes ){ + *pRes = (db->flags & aFlagOp[i].mask)!=0; + } + rc = SQLITE_OK; + break; + } + } + break; + } + } + va_end(ap); + return rc; +} + + +/* +** Return true if the buffer z[0..n-1] contains all spaces. +*/ +static int allSpaces(const char *z, int n){ + while( n>0 && z[n-1]==' ' ){ n--; } + return n==0; +} + +/* +** This is the default collating function named "BINARY" which is always +** available. +** +** If the padFlag argument is not NULL then space padding at the end +** of strings is ignored. This implements the RTRIM collation. +*/ +static int binCollFunc( + void *padFlag, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 +){ + int rc, n; + n = nKey1lastRowid; +} + +/* +** Set the value returned by the sqlite3_last_insert_rowid() API function. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif + sqlite3_mutex_enter(db->mutex); + db->lastRowid = iRowid; + sqlite3_mutex_leave(db->mutex); +} + +/* +** Return the number of changes in the most recent call to sqlite3_exec(). +*/ +SQLITE_API int sqlite3_changes(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->nChange; +} + +/* +** Return the number of changes since the database handle was opened. +*/ +SQLITE_API int sqlite3_total_changes(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->nTotalChange; +} + +/* +** Close all open savepoints. This function only manipulates fields of the +** database handle object, it does not close any savepoints that may be open +** at the b-tree/pager level. +*/ +SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){ + while( db->pSavepoint ){ + Savepoint *pTmp = db->pSavepoint; + db->pSavepoint = pTmp->pNext; + sqlite3DbFree(db, pTmp); + } + db->nSavepoint = 0; + db->nStatement = 0; + db->isTransactionSavepoint = 0; +} + +/* +** Invoke the destructor function associated with FuncDef p, if any. Except, +** if this is not the last copy of the function, do not invoke it. Multiple +** copies of a single function are created when create_function() is called +** with SQLITE_ANY as the encoding. +*/ +static void functionDestroy(sqlite3 *db, FuncDef *p){ + FuncDestructor *pDestructor = p->u.pDestructor; + if( pDestructor ){ + pDestructor->nRef--; + if( pDestructor->nRef==0 ){ + pDestructor->xDestroy(pDestructor->pUserData); + sqlite3DbFree(db, pDestructor); + } + } +} + +/* +** Disconnect all sqlite3_vtab objects that belong to database connection +** db. This is called when db is being closed. +*/ +static void disconnectAllVtab(sqlite3 *db){ +#ifndef SQLITE_OMIT_VIRTUALTABLE + int i; + HashElem *p; + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Schema *pSchema = db->aDb[i].pSchema; + if( db->aDb[i].pSchema ){ + for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ + Table *pTab = (Table *)sqliteHashData(p); + if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); + } + } + } + for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ + Module *pMod = (Module *)sqliteHashData(p); + if( pMod->pEpoTab ){ + sqlite3VtabDisconnect(db, pMod->pEpoTab); + } + } + sqlite3VtabUnlockList(db); + sqlite3BtreeLeaveAll(db); +#else + UNUSED_PARAMETER(db); +#endif +} + +/* +** Return TRUE if database connection db has unfinalized prepared +** statements or unfinished sqlite3_backup objects. +*/ +static int connectionIsBusy(sqlite3 *db){ + int j; + assert( sqlite3_mutex_held(db->mutex) ); + if( db->pVdbe ) return 1; + for(j=0; jnDb; j++){ + Btree *pBt = db->aDb[j].pBt; + if( pBt && sqlite3BtreeIsInBackup(pBt) ) return 1; + } + return 0; +} + +/* +** Close an existing SQLite database +*/ +static int sqlite3Close(sqlite3 *db, int forceZombie){ + if( !db ){ + /* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or + ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ + return SQLITE_OK; + } + if( !sqlite3SafetyCheckSickOrOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + sqlite3_mutex_enter(db->mutex); + if( db->mTrace & SQLITE_TRACE_CLOSE ){ + db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); + } + + /* Force xDisconnect calls on all virtual tables */ + disconnectAllVtab(db); + + /* If a transaction is open, the disconnectAllVtab() call above + ** will not have called the xDisconnect() method on any virtual + ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() + ** call will do so. We need to do this before the check for active + ** SQL statements below, as the v-table implementation may be storing + ** some prepared statements internally. + */ + sqlite3VtabRollback(db); + + /* Legacy behavior (sqlite3_close() behavior) is to return + ** SQLITE_BUSY if the connection can not be closed immediately. + */ + if( !forceZombie && connectionIsBusy(db) ){ + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized " + "statements or unfinished backups"); + sqlite3_mutex_leave(db->mutex); + return SQLITE_BUSY; + } + +#ifdef SQLITE_ENABLE_SQLLOG + if( sqlite3GlobalConfig.xSqllog ){ + /* Closing the handle. Fourth parameter is passed the value 2. */ + sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); + } +#endif + + /* Convert the connection into a zombie and then close it. + */ + db->magic = SQLITE_MAGIC_ZOMBIE; + sqlite3LeaveMutexAndCloseZombie(db); + return SQLITE_OK; +} + +/* +** Two variations on the public interface for closing a database +** connection. The sqlite3_close() version returns SQLITE_BUSY and +** leaves the connection option if there are unfinalized prepared +** statements or unfinished sqlite3_backups. The sqlite3_close_v2() +** version forces the connection to become a zombie if there are +** unclosed resources, and arranges for deallocation when the last +** prepare statement or sqlite3_backup closes. +*/ +SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } +SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } + + +/* +** Close the mutex on database connection db. +** +** Furthermore, if database connection db is a zombie (meaning that there +** has been a prior call to sqlite3_close(db) or sqlite3_close_v2(db)) and +** every sqlite3_stmt has now been finalized and every sqlite3_backup has +** finished, then free all resources. +*/ +SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ + HashElem *i; /* Hash table iterator */ + int j; + + /* If there are outstanding sqlite3_stmt or sqlite3_backup objects + ** or if the connection has not yet been closed by sqlite3_close_v2(), + ** then just leave the mutex and return. + */ + if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){ + sqlite3_mutex_leave(db->mutex); + return; + } + + /* If we reach this point, it means that the database connection has + ** closed all sqlite3_stmt and sqlite3_backup objects and has been + ** passed to sqlite3_close (meaning that it is a zombie). Therefore, + ** go ahead and free all resources. + */ + + /* If a transaction is open, roll it back. This also ensures that if + ** any database schemas have been modified by an uncommitted transaction + ** they are reset. And that the required b-tree mutex is held to make + ** the pager rollback and schema reset an atomic operation. */ + sqlite3RollbackAll(db, SQLITE_OK); + + /* Free any outstanding Savepoint structures. */ + sqlite3CloseSavepoints(db); + + /* Close all database connections */ + for(j=0; jnDb; j++){ + struct Db *pDb = &db->aDb[j]; + if( pDb->pBt ){ + sqlite3BtreeClose(pDb->pBt); + pDb->pBt = 0; + if( j!=1 ){ + pDb->pSchema = 0; + } + } + } + /* Clear the TEMP schema separately and last */ + if( db->aDb[1].pSchema ){ + sqlite3SchemaClear(db->aDb[1].pSchema); + } + sqlite3VtabUnlockList(db); + + /* Free up the array of auxiliary databases */ + sqlite3CollapseDatabaseArray(db); + assert( db->nDb<=2 ); + assert( db->aDb==db->aDbStatic ); + + /* Tell the code in notify.c that the connection no longer holds any + ** locks and does not require any further unlock-notify callbacks. + */ + sqlite3ConnectionClosed(db); + + for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ + FuncDef *pNext, *p; + p = sqliteHashData(i); + do{ + functionDestroy(db, p); + pNext = p->pNext; + sqlite3DbFree(db, p); + p = pNext; + }while( p ); + } + sqlite3HashClear(&db->aFunc); + for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ + CollSeq *pColl = (CollSeq *)sqliteHashData(i); + /* Invoke any destructors registered for collation sequence user data. */ + for(j=0; j<3; j++){ + if( pColl[j].xDel ){ + pColl[j].xDel(pColl[j].pUser); + } + } + sqlite3DbFree(db, pColl); + } + sqlite3HashClear(&db->aCollSeq); +#ifndef SQLITE_OMIT_VIRTUALTABLE + for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ + Module *pMod = (Module *)sqliteHashData(i); + if( pMod->xDestroy ){ + pMod->xDestroy(pMod->pAux); + } + sqlite3VtabEponymousTableClear(db, pMod); + sqlite3DbFree(db, pMod); + } + sqlite3HashClear(&db->aModule); +#endif + + sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ + sqlite3ValueFree(db->pErr); + sqlite3CloseExtensions(db); +#if SQLITE_USER_AUTHENTICATION + sqlite3_free(db->auth.zAuthUser); + sqlite3_free(db->auth.zAuthPW); +#endif + + db->magic = SQLITE_MAGIC_ERROR; + + /* The temp-database schema is allocated differently from the other schema + ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). + ** So it needs to be freed here. Todo: Why not roll the temp schema into + ** the same sqliteMalloc() as the one that allocates the database + ** structure? + */ + sqlite3DbFree(db, db->aDb[1].pSchema); + 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 */ + if( db->lookaside.bMalloced ){ + sqlite3_free(db->lookaside.pStart); + } + sqlite3_free(db); +} + +/* +** Rollback all database files. If tripCode is not SQLITE_OK, then +** any write cursors are invalidated ("tripped" - as in "tripping a circuit +** breaker") and made to return tripCode if there are any further +** attempts to use that cursor. Read cursors remain open and valid +** but are "saved" in case the table pages are moved around. +*/ +SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ + int i; + int inTrans = 0; + int schemaChange; + assert( sqlite3_mutex_held(db->mutex) ); + sqlite3BeginBenignMalloc(); + + /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). + ** This is important in case the transaction being rolled back has + ** modified the database schema. If the b-tree mutexes are not taken + ** here, then another shared-cache connection might sneak in between + ** 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; + + for(i=0; inDb; i++){ + Btree *p = db->aDb[i].pBt; + if( p ){ + if( sqlite3BtreeIsInTrans(p) ){ + inTrans = 1; + } + sqlite3BtreeRollback(p, tripCode, !schemaChange); + } + } + sqlite3VtabRollback(db); + sqlite3EndBenignMalloc(); + + if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ + sqlite3ExpirePreparedStatements(db); + sqlite3ResetAllSchemasOfConnection(db); + } + sqlite3BtreeLeaveAll(db); + + /* Any deferred constraint violations have now been resolved. */ + db->nDeferredCons = 0; + db->nDeferredImmCons = 0; + db->flags &= ~SQLITE_DeferFKs; + + /* If one has been configured, invoke the rollback-hook callback */ + if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ + db->xRollbackCallback(db->pRollbackArg); + } +} + +/* +** Return a static string containing the name corresponding to the error code +** specified in the argument. +*/ +#if defined(SQLITE_NEED_ERR_NAME) +SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ + const char *zName = 0; + int i, origRc = rc; + for(i=0; i<2 && zName==0; i++, rc &= 0xff){ + switch( rc ){ + case SQLITE_OK: zName = "SQLITE_OK"; break; + case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; + case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; + case SQLITE_PERM: zName = "SQLITE_PERM"; break; + case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; + case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; + case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; + case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; + case SQLITE_BUSY_SNAPSHOT: zName = "SQLITE_BUSY_SNAPSHOT"; break; + case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; + case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; + case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; + case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; + case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; + case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break; + case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break; + case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break; + case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; + case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; + case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break; + case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break; + case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break; + case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break; + case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break; + case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break; + case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break; + case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; + case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; + case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; + case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; + case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; + case SQLITE_IOERR_CHECKRESERVEDLOCK: + zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; + case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; + case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break; + case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break; + case SQLITE_IOERR_SHMOPEN: zName = "SQLITE_IOERR_SHMOPEN"; break; + case SQLITE_IOERR_SHMSIZE: zName = "SQLITE_IOERR_SHMSIZE"; break; + case SQLITE_IOERR_SHMLOCK: zName = "SQLITE_IOERR_SHMLOCK"; break; + case SQLITE_IOERR_SHMMAP: zName = "SQLITE_IOERR_SHMMAP"; break; + case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break; + case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break; + case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break; + case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break; + case SQLITE_IOERR_CONVPATH: zName = "SQLITE_IOERR_CONVPATH"; break; + case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; + case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; + case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; + case SQLITE_FULL: zName = "SQLITE_FULL"; break; + case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; + case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break; + case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break; + case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break; + case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break; + case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; + case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; + case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; + case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; + case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; + case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break; + case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break; + case SQLITE_CONSTRAINT_FOREIGNKEY: + zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break; + case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break; + case SQLITE_CONSTRAINT_PRIMARYKEY: + zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break; + case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break; + case SQLITE_CONSTRAINT_COMMITHOOK: + zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break; + case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break; + case SQLITE_CONSTRAINT_FUNCTION: + zName = "SQLITE_CONSTRAINT_FUNCTION"; break; + case SQLITE_CONSTRAINT_ROWID: zName = "SQLITE_CONSTRAINT_ROWID"; break; + case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; + case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; + case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; + case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; + case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; + case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; + case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; + case SQLITE_ROW: zName = "SQLITE_ROW"; break; + case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; + case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; + case SQLITE_NOTICE_RECOVER_ROLLBACK: + zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; + case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; + case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; + case SQLITE_DONE: zName = "SQLITE_DONE"; break; + } + } + if( zName==0 ){ + static char zBuf[50]; + sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc); + zName = zBuf; + } + return zName; +} +#endif + +/* +** Return a static string that describes the kind of error specified in the +** argument. +*/ +SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ + static const char* const aMsg[] = { + /* SQLITE_OK */ "not an error", + /* SQLITE_ERROR */ "SQL logic error or missing database", + /* SQLITE_INTERNAL */ 0, + /* SQLITE_PERM */ "access permission denied", + /* SQLITE_ABORT */ "callback requested query abort", + /* SQLITE_BUSY */ "database is locked", + /* SQLITE_LOCKED */ "database table is locked", + /* SQLITE_NOMEM */ "out of memory", + /* SQLITE_READONLY */ "attempt to write a readonly database", + /* SQLITE_INTERRUPT */ "interrupted", + /* SQLITE_IOERR */ "disk I/O error", + /* SQLITE_CORRUPT */ "database disk image is malformed", + /* SQLITE_NOTFOUND */ "unknown operation", + /* SQLITE_FULL */ "database or disk is full", + /* SQLITE_CANTOPEN */ "unable to open database file", + /* SQLITE_PROTOCOL */ "locking protocol", + /* SQLITE_EMPTY */ "table contains no data", + /* SQLITE_SCHEMA */ "database schema has changed", + /* SQLITE_TOOBIG */ "string or blob too big", + /* SQLITE_CONSTRAINT */ "constraint failed", + /* SQLITE_MISMATCH */ "datatype mismatch", + /* SQLITE_MISUSE */ "library routine called out of sequence", + /* SQLITE_NOLFS */ "large file support is disabled", + /* SQLITE_AUTH */ "authorization denied", + /* SQLITE_FORMAT */ "auxiliary database format error", + /* SQLITE_RANGE */ "bind or column index out of range", + /* SQLITE_NOTADB */ "file is encrypted or is not a database", + }; + const char *zErr = "unknown error"; + switch( rc ){ + case SQLITE_ABORT_ROLLBACK: { + zErr = "abort due to ROLLBACK"; + break; + } + default: { + rc &= 0xff; + if( ALWAYS(rc>=0) && rcbusyTimeout; + int delay, prior; + + assert( count>=0 ); + if( count < NDELAY ){ + delay = delays[count]; + prior = totals[count]; + }else{ + delay = delays[NDELAY-1]; + prior = totals[NDELAY-1] + delay*(count-(NDELAY-1)); + } + if( prior + delay > timeout ){ + delay = timeout - prior; + if( delay<=0 ) return 0; + } + sqlite3OsSleep(db->pVfs, delay*1000); + return 1; +#else + sqlite3 *db = (sqlite3 *)ptr; + int timeout = ((sqlite3 *)ptr)->busyTimeout; + if( (count+1)*1000 > timeout ){ + return 0; + } + sqlite3OsSleep(db->pVfs, 1000000); + return 1; +#endif +} + +/* +** Invoke the given busy handler. +** +** This routine is called when an operation failed with a lock. +** If this routine returns non-zero, the lock is retried. If it +** returns 0, the operation aborts with an SQLITE_BUSY error. +*/ +SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){ + int rc; + if( NEVER(p==0) || p->xFunc==0 || p->nBusy<0 ) return 0; + rc = p->xFunc(p->pArg, p->nBusy); + if( rc==0 ){ + p->nBusy = -1; + }else{ + p->nBusy++; + } + return rc; +} + +/* +** This routine sets the busy callback for an Sqlite database to the +** given callback function with the given argument. +*/ +SQLITE_API int sqlite3_busy_handler( + sqlite3 *db, + int (*xBusy)(void*,int), + void *pArg +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->busyHandler.xFunc = xBusy; + db->busyHandler.pArg = pArg; + db->busyHandler.nBusy = 0; + db->busyTimeout = 0; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK +/* +** This routine sets the progress callback for an Sqlite database to the +** given callback function with the given argument. The progress callback will +** be invoked every nOps opcodes. +*/ +SQLITE_API void sqlite3_progress_handler( + sqlite3 *db, + int nOps, + int (*xProgress)(void*), + void *pArg +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( nOps>0 ){ + db->xProgress = xProgress; + db->nProgressOps = (unsigned)nOps; + db->pProgressArg = pArg; + }else{ + db->xProgress = 0; + db->nProgressOps = 0; + db->pProgressArg = 0; + } + sqlite3_mutex_leave(db->mutex); +} +#endif + + +/* +** This routine installs a default busy handler that waits for the +** specified number of milliseconds before returning 0. +*/ +SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + if( ms>0 ){ + sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); + db->busyTimeout = ms; + }else{ + sqlite3_busy_handler(db, 0, 0); + } + return SQLITE_OK; +} + +/* +** Cause any pending operation to stop at its earliest opportunity. +*/ +SQLITE_API void sqlite3_interrupt(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif + db->u1.isInterrupted = 1; +} + + +/* +** This function is exactly the same as sqlite3_create_function(), except +** that it is designed to be called by internal code. The difference is +** that if a malloc() fails in sqlite3_create_function(), an error code +** is returned and the mallocFailed flag cleared. +*/ +SQLITE_PRIVATE int sqlite3CreateFunc( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int enc, + void *pUserData, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*), + FuncDestructor *pDestructor +){ + FuncDef *p; + int nName; + int extraFlags; + + assert( sqlite3_mutex_held(db->mutex) ); + if( zFunctionName==0 || + (xSFunc && (xFinal || xStep)) || + (!xSFunc && (xFinal && !xStep)) || + (!xSFunc && (!xFinal && xStep)) || + (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || + (255<(nName = sqlite3Strlen30( zFunctionName))) ){ + return SQLITE_MISUSE_BKPT; + } + + assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); + extraFlags = enc & SQLITE_DETERMINISTIC; + enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); + +#ifndef SQLITE_OMIT_UTF16 + /* If SQLITE_UTF16 is specified as the encoding type, transform this + ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the + ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + ** + ** If SQLITE_ANY is specified, add three versions of the function + ** to the hash table. + */ + if( enc==SQLITE_UTF16 ){ + enc = SQLITE_UTF16NATIVE; + }else if( enc==SQLITE_ANY ){ + int rc; + rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags, + pUserData, xSFunc, xStep, xFinal, pDestructor); + if( rc==SQLITE_OK ){ + rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags, + pUserData, xSFunc, xStep, xFinal, pDestructor); + } + if( rc!=SQLITE_OK ){ + return rc; + } + enc = SQLITE_UTF16BE; + } +#else + enc = SQLITE_UTF8; +#endif + + /* Check if an existing function is being overridden or deleted. If so, + ** and there are active VMs, then return SQLITE_BUSY. If a function + ** is being overridden/deleted but there are no active VMs, allow the + ** operation to continue but invalidate all precompiled statements. + */ + p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0); + if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){ + if( db->nVdbeActive ){ + sqlite3ErrorWithMsg(db, SQLITE_BUSY, + "unable to delete/modify user-function due to active statements"); + assert( !db->mallocFailed ); + return SQLITE_BUSY; + }else{ + sqlite3ExpirePreparedStatements(db); + } + } + + p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); + assert(p || db->mallocFailed); + if( !p ){ + return SQLITE_NOMEM_BKPT; + } + + /* If an older version of the function with a configured destructor is + ** being replaced invoke the destructor function here. */ + functionDestroy(db, p); + + if( pDestructor ){ + pDestructor->nRef++; + } + p->u.pDestructor = pDestructor; + p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags; + testcase( p->funcFlags & SQLITE_DETERMINISTIC ); + p->xSFunc = xSFunc ? xSFunc : xStep; + p->xFinalize = xFinal; + p->pUserData = pUserData; + p->nArg = (u16)nArg; + return SQLITE_OK; +} + +/* +** Create new user functions. +*/ +SQLITE_API int sqlite3_create_function( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*) +){ + return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep, + xFinal, 0); +} + +SQLITE_API int sqlite3_create_function_v2( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*), + void (*xDestroy)(void *) +){ + int rc = SQLITE_ERROR; + FuncDestructor *pArg = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( xDestroy ){ + pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor)); + if( !pArg ){ + xDestroy(p); + goto out; + } + pArg->xDestroy = xDestroy; + pArg->pUserData = p; + } + rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg); + if( pArg && pArg->nRef==0 ){ + assert( rc!=SQLITE_OK ); + xDestroy(p); + sqlite3DbFree(db, pArg); + } + + out: + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API int sqlite3_create_function16( + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +){ + int rc; + char *zFunc8; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); + rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0); + sqlite3DbFree(db, zFunc8); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} +#endif + + +/* +** Declare that a function has been overloaded by a virtual table. +** +** If the function already exists as a regular global function, then +** this routine is a no-op. If the function does not exist, then create +** a new one that always throws a run-time error. +** +** When virtual tables intend to provide an overloaded function, they +** should call this routine to make sure the global function exists. +** A global function must exist in order for name resolution to work +** properly. +*/ +SQLITE_API int sqlite3_overload_function( + sqlite3 *db, + const char *zName, + int nArg +){ + int rc = SQLITE_OK; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){ + rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, + 0, sqlite3InvalidFunction, 0, 0, 0); + } + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +#ifndef SQLITE_OMIT_TRACE +/* +** Register a trace function. The pArg from the previously registered trace +** is returned. +** +** A NULL trace function means that no tracing is executes. A non-NULL +** trace is a pointer to a function that is invoked at the start of each +** SQL statement. +*/ +#ifndef SQLITE_OMIT_DEPRECATED +SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ + void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pOld = db->pTraceArg; + db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; + db->xTrace = (int(*)(u32,void*,void*,void*))xTrace; + db->pTraceArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pOld; +} +#endif /* SQLITE_OMIT_DEPRECATED */ + +/* Register a trace callback using the version-2 interface. +*/ +SQLITE_API int sqlite3_trace_v2( + sqlite3 *db, /* Trace this connection */ + unsigned mTrace, /* Mask of events to be traced */ + int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ + void *pArg /* Context */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( mTrace==0 ) xTrace = 0; + if( xTrace==0 ) mTrace = 0; + db->mTrace = mTrace; + db->xTrace = xTrace; + db->pTraceArg = pArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** Register a profile function. The pArg from the previously registered +** profile function is returned. +** +** A NULL profile function means that no profiling is executes. A non-NULL +** profile is a pointer to a function that is invoked at the conclusion of +** each SQL statement that is run. +*/ +SQLITE_API void *sqlite3_profile( + sqlite3 *db, + void (*xProfile)(void*,const char*,sqlite_uint64), + void *pArg +){ + void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pOld = db->pProfileArg; + db->xProfile = xProfile; + db->pProfileArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pOld; +} +#endif /* SQLITE_OMIT_DEPRECATED */ +#endif /* SQLITE_OMIT_TRACE */ + +/* +** Register a function to be invoked when a transaction commits. +** If the invoked function returns non-zero, then the commit becomes a +** rollback. +*/ +SQLITE_API void *sqlite3_commit_hook( + sqlite3 *db, /* Attach the hook to this database */ + int (*xCallback)(void*), /* Function to invoke on each commit */ + void *pArg /* Argument to the function */ +){ + void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pOld = db->pCommitArg; + db->xCommitCallback = xCallback; + db->pCommitArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pOld; +} + +/* +** Register a callback to be invoked each time a row is updated, +** inserted or deleted using this database connection. +*/ +SQLITE_API void *sqlite3_update_hook( + sqlite3 *db, /* Attach the hook to this database */ + void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), + void *pArg /* Argument to the function */ +){ + void *pRet; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pRet = db->pUpdateArg; + db->xUpdateCallback = xCallback; + db->pUpdateArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} + +/* +** Register a callback to be invoked each time a transaction is rolled +** back by this database connection. +*/ +SQLITE_API void *sqlite3_rollback_hook( + sqlite3 *db, /* Attach the hook to this database */ + void (*xCallback)(void*), /* Callback function */ + void *pArg /* Argument to the function */ +){ + void *pRet; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pRet = db->pRollbackArg; + db->xRollbackCallback = xCallback; + db->pRollbackArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** Register a callback to be invoked each time a row is updated, +** inserted or deleted using this database connection. +*/ +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, /* Attach the hook to this database */ + void(*xCallback)( /* Callback function */ + void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64), + void *pArg /* First callback argument */ +){ + void *pRet; + sqlite3_mutex_enter(db->mutex); + pRet = db->pPreUpdateArg; + db->xPreUpdateCallback = xCallback; + db->pPreUpdateArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +#ifndef SQLITE_OMIT_WAL +/* +** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). +** Invoke sqlite3_wal_checkpoint if the number of frames in the log file +** is greater than sqlite3.pWalArg cast to an integer (the value configured by +** wal_autocheckpoint()). +*/ +SQLITE_PRIVATE int sqlite3WalDefaultHook( + void *pClientData, /* Argument */ + sqlite3 *db, /* Connection */ + const char *zDb, /* Database */ + int nFrame /* Size of WAL */ +){ + if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){ + sqlite3BeginBenignMalloc(); + sqlite3_wal_checkpoint(db, zDb); + sqlite3EndBenignMalloc(); + } + return SQLITE_OK; +} +#endif /* SQLITE_OMIT_WAL */ + +/* +** Configure an sqlite3_wal_hook() callback to automatically checkpoint +** a database after committing a transaction if there are nFrame or +** more frames in the log file. Passing zero or a negative value as the +** nFrame parameter disables automatic checkpoints entirely. +** +** The callback registered by this function replaces any existing callback +** registered using sqlite3_wal_hook(). Likewise, registering a callback +** using sqlite3_wal_hook() disables the automatic checkpoint mechanism +** configured by this function. +*/ +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ +#ifdef SQLITE_OMIT_WAL + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(nFrame); +#else +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + if( nFrame>0 ){ + sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame)); + }else{ + sqlite3_wal_hook(db, 0, 0); + } +#endif + return SQLITE_OK; +} + +/* +** Register a callback to be invoked each time a transaction is written +** into the write-ahead-log by this database connection. +*/ +SQLITE_API void *sqlite3_wal_hook( + sqlite3 *db, /* Attach the hook to this db handle */ + int(*xCallback)(void *, sqlite3*, const char*, int), + void *pArg /* First argument passed to xCallback() */ +){ +#ifndef SQLITE_OMIT_WAL + void *pRet; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pRet = db->pWalArg; + db->xWalCallback = xCallback; + db->pWalArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +#else + return 0; +#endif +} + +/* +** Checkpoint database zDb. +*/ +SQLITE_API int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +){ +#ifdef SQLITE_OMIT_WAL + return SQLITE_OK; +#else + int rc; /* Return code */ + int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + + /* Initialize the output variables to -1 in case an error occurs. */ + if( pnLog ) *pnLog = -1; + if( pnCkpt ) *pnCkpt = -1; + + assert( SQLITE_CHECKPOINT_PASSIVE==0 ); + assert( SQLITE_CHECKPOINT_FULL==1 ); + assert( SQLITE_CHECKPOINT_RESTART==2 ); + assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); + if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ + /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint + ** mode: */ + return SQLITE_MISUSE; + } + + sqlite3_mutex_enter(db->mutex); + if( zDb && zDb[0] ){ + iDb = sqlite3FindDbName(db, zDb); + } + if( iDb<0 ){ + rc = SQLITE_ERROR; + sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); + }else{ + db->busyHandler.nBusy = 0; + rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); + sqlite3Error(db, rc); + } + rc = sqlite3ApiExit(db, rc); + + /* If there are no active statements, clear the interrupt flag at this + ** point. */ + if( db->nVdbeActive==0 ){ + db->u1.isInterrupted = 0; + } + + sqlite3_mutex_leave(db->mutex); + return rc; +#endif +} + + +/* +** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points +** to contains a zero-length string, all attached databases are +** checkpointed. +*/ +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ + /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to + ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */ + return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0); +} + +#ifndef SQLITE_OMIT_WAL +/* +** Run a checkpoint on database iDb. This is a no-op if database iDb is +** not currently open in WAL mode. +** +** If a transaction is open on the database being checkpointed, this +** function returns SQLITE_LOCKED and a checkpoint is not attempted. If +** an error occurs while running the checkpoint, an SQLite error code is +** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK. +** +** The mutex on database handle db should be held by the caller. The mutex +** associated with the specific b-tree being checkpointed is taken by +** this function while the checkpoint is running. +** +** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are +** 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. +*/ +SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ + int rc = SQLITE_OK; /* Return code */ + int i; /* Used to iterate through attached dbs */ + int bBusy = 0; /* True if SQLITE_BUSY has been encountered */ + + assert( sqlite3_mutex_held(db->mutex) ); + assert( !pnLog || *pnLog==-1 ); + assert( !pnCkpt || *pnCkpt==-1 ); + + for(i=0; inDb && rc==SQLITE_OK; i++){ + if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){ + rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt); + pnLog = 0; + pnCkpt = 0; + if( rc==SQLITE_BUSY ){ + bBusy = 1; + rc = SQLITE_OK; + } + } + } + + return (rc==SQLITE_OK && bBusy) ? SQLITE_BUSY : rc; +} +#endif /* SQLITE_OMIT_WAL */ + +/* +** This function returns true if main-memory should be used instead of +** a temporary file for transient pager files and statement journals. +** The value returned depends on the value of db->temp_store (runtime +** parameter) and the compile time value of SQLITE_TEMP_STORE. The +** following table describes the relationship between these two values +** and this functions return value. +** +** SQLITE_TEMP_STORE db->temp_store Location of temporary database +** ----------------- -------------- ------------------------------ +** 0 any file (return 0) +** 1 1 file (return 0) +** 1 2 memory (return 1) +** 1 0 file (return 0) +** 2 1 file (return 0) +** 2 2 memory (return 1) +** 2 0 memory (return 1) +** 3 any memory (return 1) +*/ +SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){ +#if SQLITE_TEMP_STORE==1 + return ( db->temp_store==2 ); +#endif +#if SQLITE_TEMP_STORE==2 + return ( db->temp_store!=1 ); +#endif +#if SQLITE_TEMP_STORE==3 + UNUSED_PARAMETER(db); + return 1; +#endif +#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3 + UNUSED_PARAMETER(db); + return 0; +#endif +} + +/* +** Return UTF-8 encoded English language explanation of the most recent +** error. +*/ +SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ + const char *z; + if( !db ){ + return sqlite3ErrStr(SQLITE_NOMEM_BKPT); + } + if( !sqlite3SafetyCheckSickOrOk(db) ){ + return sqlite3ErrStr(SQLITE_MISUSE_BKPT); + } + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + z = sqlite3ErrStr(SQLITE_NOMEM_BKPT); + }else{ + testcase( db->pErr==0 ); + z = (char*)sqlite3_value_text(db->pErr); + assert( !db->mallocFailed ); + if( z==0 ){ + z = sqlite3ErrStr(db->errCode); + } + } + sqlite3_mutex_leave(db->mutex); + return z; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Return UTF-16 encoded English language explanation of the most recent +** error. +*/ +SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ + static const u16 outOfMem[] = { + 'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0 + }; + static const u16 misuse[] = { + 'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ', + 'r', 'o', 'u', 't', 'i', 'n', 'e', ' ', + 'c', 'a', 'l', 'l', 'e', 'd', ' ', + 'o', 'u', 't', ' ', + 'o', 'f', ' ', + 's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0 + }; + + const void *z; + if( !db ){ + return (void *)outOfMem; + } + if( !sqlite3SafetyCheckSickOrOk(db) ){ + return (void *)misuse; + } + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + z = (void *)outOfMem; + }else{ + z = sqlite3_value_text16(db->pErr); + if( z==0 ){ + sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode)); + z = sqlite3_value_text16(db->pErr); + } + /* A malloc() may have failed within the call to sqlite3_value_text16() + ** above. If this is the case, then the db->mallocFailed flag needs to + ** be cleared before returning. Do this directly, instead of via + ** sqlite3ApiExit(), to avoid setting the database handle error message. + */ + sqlite3OomClear(db); + } + sqlite3_mutex_leave(db->mutex); + return z; +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** Return the most recent error code generated by an SQLite routine. If NULL is +** passed to this function, we assume a malloc() failed during sqlite3_open(). +*/ +SQLITE_API int sqlite3_errcode(sqlite3 *db){ + if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + if( !db || db->mallocFailed ){ + return SQLITE_NOMEM_BKPT; + } + return db->errCode & db->errMask; +} +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){ + if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + if( !db || db->mallocFailed ){ + return SQLITE_NOMEM_BKPT; + } + return db->errCode; +} +SQLITE_API int sqlite3_system_errno(sqlite3 *db){ + return db ? db->iSysErrno : 0; +} + +/* +** Return a string that describes the kind of error specified in the +** argument. For now, this simply calls the internal sqlite3ErrStr() +** function. +*/ +SQLITE_API const char *sqlite3_errstr(int rc){ + return sqlite3ErrStr(rc); +} + +/* +** Create a new collating function for database "db". The name is zName +** and the encoding is enc. +*/ +static int createCollation( + sqlite3* db, + const char *zName, + u8 enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDel)(void*) +){ + CollSeq *pColl; + int enc2; + + assert( sqlite3_mutex_held(db->mutex) ); + + /* If SQLITE_UTF16 is specified as the encoding type, transform this + ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the + ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + */ + enc2 = enc; + testcase( enc2==SQLITE_UTF16 ); + testcase( enc2==SQLITE_UTF16_ALIGNED ); + if( enc2==SQLITE_UTF16 || enc2==SQLITE_UTF16_ALIGNED ){ + enc2 = SQLITE_UTF16NATIVE; + } + if( enc2SQLITE_UTF16BE ){ + return SQLITE_MISUSE_BKPT; + } + + /* Check if this call is removing or replacing an existing collation + ** sequence. If so, and there are active VMs, return busy. If there + ** are no active VMs, invalidate any pre-compiled statements. + */ + pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); + if( pColl && pColl->xCmp ){ + if( db->nVdbeActive ){ + sqlite3ErrorWithMsg(db, SQLITE_BUSY, + "unable to delete/modify collation sequence due to active statements"); + return SQLITE_BUSY; + } + sqlite3ExpirePreparedStatements(db); + + /* If collation sequence pColl was created directly by a call to + ** sqlite3_create_collation, and not generated by synthCollSeq(), + ** then any copies made by synthCollSeq() need to be invalidated. + ** Also, collation destructor - CollSeq.xDel() - function may need + ** to be called. + */ + if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){ + CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName); + int j; + for(j=0; j<3; j++){ + CollSeq *p = &aColl[j]; + if( p->enc==pColl->enc ){ + if( p->xDel ){ + p->xDel(p->pUser); + } + p->xCmp = 0; + } + } + } + } + + pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1); + if( pColl==0 ) return SQLITE_NOMEM_BKPT; + pColl->xCmp = xCompare; + pColl->pUser = pCtx; + pColl->xDel = xDel; + pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); + sqlite3Error(db, SQLITE_OK); + return SQLITE_OK; +} + + +/* +** This array defines hard upper bounds on limit values. The +** initializer must be kept in sync with the SQLITE_LIMIT_* +** #defines in sqlite3.h. +*/ +static const int aHardLimit[] = { + SQLITE_MAX_LENGTH, + SQLITE_MAX_SQL_LENGTH, + SQLITE_MAX_COLUMN, + SQLITE_MAX_EXPR_DEPTH, + SQLITE_MAX_COMPOUND_SELECT, + SQLITE_MAX_VDBE_OP, + SQLITE_MAX_FUNCTION_ARG, + SQLITE_MAX_ATTACHED, + SQLITE_MAX_LIKE_PATTERN_LENGTH, + SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ + SQLITE_MAX_TRIGGER_DEPTH, + SQLITE_MAX_WORKER_THREADS, +}; + +/* +** Make sure the hard limits are set to reasonable values +*/ +#if SQLITE_MAX_LENGTH<100 +# error SQLITE_MAX_LENGTH must be at least 100 +#endif +#if SQLITE_MAX_SQL_LENGTH<100 +# error SQLITE_MAX_SQL_LENGTH must be at least 100 +#endif +#if SQLITE_MAX_SQL_LENGTH>SQLITE_MAX_LENGTH +# error SQLITE_MAX_SQL_LENGTH must not be greater than SQLITE_MAX_LENGTH +#endif +#if SQLITE_MAX_COMPOUND_SELECT<2 +# error SQLITE_MAX_COMPOUND_SELECT must be at least 2 +#endif +#if SQLITE_MAX_VDBE_OP<40 +# error SQLITE_MAX_VDBE_OP must be at least 40 +#endif +#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127 +# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127 +#endif +#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 +# error SQLITE_MAX_ATTACHED must be between 0 and 125 +#endif +#if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 +# error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 +#endif +#if SQLITE_MAX_COLUMN>32767 +# error SQLITE_MAX_COLUMN must not exceed 32767 +#endif +#if SQLITE_MAX_TRIGGER_DEPTH<1 +# error SQLITE_MAX_TRIGGER_DEPTH must be at least 1 +#endif +#if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50 +# error SQLITE_MAX_WORKER_THREADS must be between 0 and 50 +#endif + + +/* +** Change the value of a limit. Report the old value. +** If an invalid limit index is supplied, report -1. +** Make no changes but still report the old value if the +** new limit is negative. +** +** A new lower limit does not shrink existing constructs. +** It merely prevents new constructs that exceed the limit +** from forming. +*/ +SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ + int oldLimit; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + + /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME + ** there is a hard upper bound set at compile-time by a C preprocessor + ** macro called SQLITE_MAX_NAME. (The "_LIMIT_" in the name is changed to + ** "_MAX_".) + */ + assert( aHardLimit[SQLITE_LIMIT_LENGTH]==SQLITE_MAX_LENGTH ); + assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH ); + assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN ); + assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH ); + assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT); + assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP ); + assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG ); + assert( aHardLimit[SQLITE_LIMIT_ATTACHED]==SQLITE_MAX_ATTACHED ); + assert( aHardLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]== + SQLITE_MAX_LIKE_PATTERN_LENGTH ); + assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); + assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); + assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); + assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); + + + if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ + return -1; + } + oldLimit = db->aLimit[limitId]; + if( newLimit>=0 ){ /* IMP: R-52476-28732 */ + if( newLimit>aHardLimit[limitId] ){ + newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ + } + db->aLimit[limitId] = newLimit; + } + return oldLimit; /* IMP: R-53341-35419 */ +} + +/* +** This function is used to parse both URIs and non-URI filenames passed by the +** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database +** URIs specified as part of ATTACH statements. +** +** The first argument to this function is the name of the VFS to use (or +** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx" +** query parameter. The second argument contains the URI (or non-URI filename) +** itself. When this function is called the *pFlags variable should contain +** the default flags to open the database handle with. The value stored in +** *pFlags may be updated before returning if the URI filename contains +** "cache=xxx" or "mode=xxx" query parameters. +** +** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to +** the VFS that should be used to open the database file. *pzFile is set to +** point to a buffer containing the name of the file to open. It is the +** responsibility of the caller to eventually call sqlite3_free() to release +** this buffer. +** +** If an error occurs, then an SQLite error code is returned and *pzErrMsg +** may be set to point to a buffer containing an English language error +** message. It is the responsibility of the caller to eventually release +** this buffer by calling sqlite3_free(). +*/ +SQLITE_PRIVATE int sqlite3ParseUri( + const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */ + const char *zUri, /* Nul-terminated URI to parse */ + unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */ + sqlite3_vfs **ppVfs, /* OUT: VFS to use */ + char **pzFile, /* OUT: Filename component of URI */ + char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */ +){ + int rc = SQLITE_OK; + unsigned int flags = *pFlags; + const char *zVfs = zDefaultVfs; + char *zFile; + char c; + int nUri = sqlite3Strlen30(zUri); + + assert( *pzErrMsg==0 ); + + if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ + || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ + && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ + ){ + char *zOpt; + int eState; /* Parser state when parsing URI */ + int iIn; /* Input character index */ + int iOut = 0; /* Output character index */ + u64 nByte = nUri+2; /* Bytes of space to allocate */ + + /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen + ** method that there may be extra parameters following the file-name. */ + flags |= SQLITE_OPEN_URI; + + for(iIn=0; iIn=0 && octet<256 ); + if( octet==0 ){ +#ifndef SQLITE_ENABLE_URI_00_ERROR + /* This branch is taken when "%00" appears within the URI. In this + ** case we ignore all text in the remainder of the path, name or + ** value currently being parsed. So ignore the current character + ** and skip to the next "?", "=" or "&", as appropriate. */ + while( (c = zUri[iIn])!=0 && c!='#' + && (eState!=0 || c!='?') + && (eState!=1 || (c!='=' && c!='&')) + && (eState!=2 || c!='&') + ){ + iIn++; + } + continue; +#else + /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */ + *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri"); + rc = SQLITE_ERROR; + goto parse_uri_out; +#endif + } + c = octet; + }else if( eState==1 && (c=='&' || c=='=') ){ + if( zFile[iOut-1]==0 ){ + /* An empty option name. Ignore this option altogether. */ + while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++; + continue; + } + if( c=='&' ){ + zFile[iOut++] = '\0'; + }else{ + eState = 2; + } + c = 0; + }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ + c = 0; + eState = 1; + } + zFile[iOut++] = c; + } + if( eState==1 ) zFile[iOut++] = '\0'; + zFile[iOut++] = '\0'; + zFile[iOut++] = '\0'; + + /* Check if there were any options specified that should be interpreted + ** here. Options that are interpreted here include "vfs" and those that + ** correspond to flags that may be passed to the sqlite3_open_v2() + ** method. */ + zOpt = &zFile[sqlite3Strlen30(zFile)+1]; + while( zOpt[0] ){ + int nOpt = sqlite3Strlen30(zOpt); + char *zVal = &zOpt[nOpt+1]; + int nVal = sqlite3Strlen30(zVal); + + if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ + zVfs = zVal; + }else{ + struct OpenMode { + const char *z; + int mode; + } *aMode = 0; + char *zModeType = 0; + int mask = 0; + int limit = 0; + + if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){ + static struct OpenMode aCacheMode[] = { + { "shared", SQLITE_OPEN_SHAREDCACHE }, + { "private", SQLITE_OPEN_PRIVATECACHE }, + { 0, 0 } + }; + + mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE; + aMode = aCacheMode; + limit = mask; + zModeType = "cache"; + } + if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){ + static struct OpenMode aOpenMode[] = { + { "ro", SQLITE_OPEN_READONLY }, + { "rw", SQLITE_OPEN_READWRITE }, + { "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE }, + { "memory", SQLITE_OPEN_MEMORY }, + { 0, 0 } + }; + + mask = SQLITE_OPEN_READONLY | SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY; + aMode = aOpenMode; + limit = mask & flags; + zModeType = "access"; + } + + if( aMode ){ + int i; + int mode = 0; + for(i=0; aMode[i].z; i++){ + const char *z = aMode[i].z; + if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ + mode = aMode[i].mode; + break; + } + } + if( mode==0 ){ + *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal); + rc = SQLITE_ERROR; + goto parse_uri_out; + } + if( (mode & ~SQLITE_OPEN_MEMORY)>limit ){ + *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s", + zModeType, zVal); + rc = SQLITE_PERM; + goto parse_uri_out; + } + flags = (flags & ~mask) | mode; + } + } + + zOpt = &zVal[nVal+1]; + } + + }else{ + zFile = sqlite3_malloc64(nUri+2); + if( !zFile ) return SQLITE_NOMEM_BKPT; + if( nUri ){ + memcpy(zFile, zUri, nUri); + } + zFile[nUri] = '\0'; + zFile[nUri+1] = '\0'; + flags &= ~SQLITE_OPEN_URI; + } + + *ppVfs = sqlite3_vfs_find(zVfs); + if( *ppVfs==0 ){ + *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); + rc = SQLITE_ERROR; + } + parse_uri_out: + if( rc!=SQLITE_OK ){ + sqlite3_free(zFile); + zFile = 0; + } + *pFlags = flags; + *pzFile = zFile; + return rc; +} + + +/* +** This routine does the work of opening a database on behalf of +** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" +** is UTF-8 encoded. +*/ +static int openDatabase( + const char *zFilename, /* Database filename UTF-8 encoded */ + sqlite3 **ppDb, /* OUT: Returned database handle */ + unsigned int flags, /* Operational flags */ + const char *zVfs /* Name of the VFS to use */ +){ + sqlite3 *db; /* Store allocated handle here */ + int rc; /* Return code */ + int isThreadsafe; /* True for threadsafe connections */ + char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ + char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppDb==0 ) return SQLITE_MISUSE_BKPT; +#endif + *ppDb = 0; +#ifndef SQLITE_OMIT_AUTOINIT + rc = sqlite3_initialize(); + if( rc ) return rc; +#endif + + /* Only allow sensible combinations of bits in the flags argument. + ** Throw an error if any non-sense combination is used. If we + ** do not block illegal combinations here, it could trigger + ** assert() statements in deeper layers. Sensible combinations + ** are: + ** + ** 1: SQLITE_OPEN_READONLY + ** 2: SQLITE_OPEN_READWRITE + ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE + */ + assert( SQLITE_OPEN_READONLY == 0x01 ); + assert( SQLITE_OPEN_READWRITE == 0x02 ); + assert( SQLITE_OPEN_CREATE == 0x04 ); + testcase( (1<<(flags&7))==0x02 ); /* READONLY */ + testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ + testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ + if( ((1<<(flags&7)) & 0x46)==0 ){ + return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ + } + + if( sqlite3GlobalConfig.bCoreMutex==0 ){ + isThreadsafe = 0; + }else if( flags & SQLITE_OPEN_NOMUTEX ){ + isThreadsafe = 0; + }else if( flags & SQLITE_OPEN_FULLMUTEX ){ + isThreadsafe = 1; + }else{ + isThreadsafe = sqlite3GlobalConfig.bFullMutex; + } + if( flags & SQLITE_OPEN_PRIVATECACHE ){ + flags &= ~SQLITE_OPEN_SHAREDCACHE; + }else if( sqlite3GlobalConfig.sharedCacheEnabled ){ + flags |= SQLITE_OPEN_SHAREDCACHE; + } + + /* Remove harmful bits from the flags parameter + ** + ** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were + ** dealt with in the previous code block. Besides these, the only + ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, + ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, + ** SQLITE_OPEN_PRIVATECACHE, and some reserved bits. Silently mask + ** off all other flags. + */ + flags &= ~( SQLITE_OPEN_DELETEONCLOSE | + SQLITE_OPEN_EXCLUSIVE | + SQLITE_OPEN_MAIN_DB | + SQLITE_OPEN_TEMP_DB | + SQLITE_OPEN_TRANSIENT_DB | + SQLITE_OPEN_MAIN_JOURNAL | + SQLITE_OPEN_TEMP_JOURNAL | + SQLITE_OPEN_SUBJOURNAL | + SQLITE_OPEN_MASTER_JOURNAL | + SQLITE_OPEN_NOMUTEX | + SQLITE_OPEN_FULLMUTEX | + SQLITE_OPEN_WAL + ); + + /* Allocate the sqlite data structure */ + db = sqlite3MallocZero( sizeof(sqlite3) ); + if( db==0 ) goto opendb_out; + if( isThreadsafe ){ + db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); + if( db->mutex==0 ){ + sqlite3_free(db); + db = 0; + goto opendb_out; + } + } + sqlite3_mutex_enter(db->mutex); + db->errMask = 0xff; + db->nDb = 2; + db->magic = SQLITE_MAGIC_BUSY; + db->aDb = db->aDbStatic; + + assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); + memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); + db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; + db->autoCommit = 1; + db->nextAutovac = -1; + db->szMmap = sqlite3GlobalConfig.szMmap; + db->nextPagesize = 0; + db->nMaxSorterMmap = 0x7FFFFFFF; + db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill +#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX + | SQLITE_AutoIndex +#endif +#if SQLITE_DEFAULT_CKPTFULLFSYNC + | SQLITE_CkptFullFSync +#endif +#if SQLITE_DEFAULT_FILE_FORMAT<4 + | SQLITE_LegacyFileFmt +#endif +#ifdef SQLITE_ENABLE_LOAD_EXTENSION + | SQLITE_LoadExtension +#endif +#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS + | SQLITE_RecTriggers +#endif +#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS + | SQLITE_ForeignKeys +#endif +#if defined(SQLITE_REVERSE_UNORDERED_SELECTS) + | SQLITE_ReverseOrder +#endif +#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) + | SQLITE_CellSizeCk +#endif +#if defined(SQLITE_ENABLE_FTS3_TOKENIZER) + | SQLITE_Fts3Tokenizer +#endif + ; + sqlite3HashInit(&db->aCollSeq); +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3HashInit(&db->aModule); +#endif + + /* Add the default collation sequence BINARY. BINARY works for both UTF-8 + ** and UTF-16, so add a version for each to avoid any unnecessary + ** conversions. The only error that can occur here is a malloc() failure. + ** + ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating + ** functions: + */ + createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0); + createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); + createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); + createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); + createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0); + if( db->mallocFailed ){ + goto opendb_out; + } + /* EVIDENCE-OF: R-08308-17224 The default collating function for all + ** strings is BINARY. + */ + db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0); + assert( db->pDfltColl!=0 ); + + /* Parse the filename/URI argument. */ + db->openFlags = flags; + rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); + sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); + sqlite3_free(zErrMsg); + goto opendb_out; + } + + /* Open the backend database driver */ + rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, + flags | SQLITE_OPEN_MAIN_DB); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_IOERR_NOMEM ){ + rc = SQLITE_NOMEM_BKPT; + } + sqlite3Error(db, rc); + goto opendb_out; + } + sqlite3BtreeEnter(db->aDb[0].pBt); + db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); + if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db); + sqlite3BtreeLeave(db->aDb[0].pBt); + db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); + + /* The default safety_level for the main database is FULL; for the temp + ** database it is OFF. This matches the pager layer defaults. + */ + db->aDb[0].zDbSName = "main"; + db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; + db->aDb[1].zDbSName = "temp"; + db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; + + db->magic = SQLITE_MAGIC_OPEN; + if( db->mallocFailed ){ + goto opendb_out; + } + + /* Register all built-in functions, but do not attempt to read the + ** database schema yet. This is delayed until the first time the database + ** is accessed. + */ + sqlite3Error(db, SQLITE_OK); + sqlite3RegisterPerConnectionBuiltinFunctions(db); + rc = sqlite3_errcode(db); + +#ifdef SQLITE_ENABLE_FTS5 + /* Register any built-in FTS5 module before loading the automatic + ** extensions. This allows automatic extensions to register FTS5 + ** tokenizers and auxiliary functions. */ + if( !db->mallocFailed && rc==SQLITE_OK ){ + rc = sqlite3Fts5Init(db); + } +#endif + + /* Load automatic extensions - extensions that have been registered + ** using the sqlite3_automatic_extension() API. + */ + if( rc==SQLITE_OK ){ + sqlite3AutoLoadExtensions(db); + rc = sqlite3_errcode(db); + if( rc!=SQLITE_OK ){ + goto opendb_out; + } + } + +#ifdef SQLITE_ENABLE_FTS1 + if( !db->mallocFailed ){ + extern int sqlite3Fts1Init(sqlite3*); + rc = sqlite3Fts1Init(db); + } +#endif + +#ifdef SQLITE_ENABLE_FTS2 + if( !db->mallocFailed && rc==SQLITE_OK ){ + extern int sqlite3Fts2Init(sqlite3*); + rc = sqlite3Fts2Init(db); + } +#endif + +#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */ + if( !db->mallocFailed && rc==SQLITE_OK ){ + rc = sqlite3Fts3Init(db); + } +#endif + +#ifdef SQLITE_ENABLE_ICU + if( !db->mallocFailed && rc==SQLITE_OK ){ + rc = sqlite3IcuInit(db); + } +#endif + +#ifdef SQLITE_ENABLE_RTREE + if( !db->mallocFailed && rc==SQLITE_OK){ + rc = sqlite3RtreeInit(db); + } +#endif + +#ifdef SQLITE_ENABLE_DBSTAT_VTAB + if( !db->mallocFailed && rc==SQLITE_OK){ + rc = sqlite3DbstatRegister(db); + } +#endif + +#ifdef SQLITE_ENABLE_JSON1 + if( !db->mallocFailed && rc==SQLITE_OK){ + rc = sqlite3Json1Init(db); + } +#endif + + /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking + ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking + ** mode. Doing nothing at all also makes NORMAL the default. + */ +#ifdef SQLITE_DEFAULT_LOCKING_MODE + db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE; + sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt), + SQLITE_DEFAULT_LOCKING_MODE); +#endif + + if( rc ) sqlite3Error(db, rc); + + /* Enable the lookaside-malloc subsystem */ + setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside, + sqlite3GlobalConfig.nLookaside); + + sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); + +opendb_out: + if( db ){ + assert( db->mutex!=0 || isThreadsafe==0 + || sqlite3GlobalConfig.bFullMutex==0 ); + sqlite3_mutex_leave(db->mutex); + } + rc = sqlite3_errcode(db); + assert( db!=0 || rc==SQLITE_NOMEM ); + if( rc==SQLITE_NOMEM ){ + sqlite3_close(db); + db = 0; + }else if( rc!=SQLITE_OK ){ + db->magic = SQLITE_MAGIC_SICK; + } + *ppDb = db; +#ifdef SQLITE_ENABLE_SQLLOG + if( sqlite3GlobalConfig.xSqllog ){ + /* Opening a db handle. Fourth parameter is passed 0. */ + void *pArg = sqlite3GlobalConfig.pSqllogArg; + sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); + } +#endif +#if defined(SQLITE_HAS_CODEC) + if( rc==SQLITE_OK ){ + const char *zKey; + if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){ + u8 iByte; + int i; + char zDecoded[40]; + for(i=0, iByte=0; imutex); + assert( !db->mallocFailed ); + rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Register a new collation sequence with the database handle db. +*/ +SQLITE_API int sqlite3_create_collation16( + sqlite3* db, + const void *zName, + int enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*) +){ + int rc = SQLITE_OK; + char *zName8; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE); + if( zName8 ){ + rc = createCollation(db, zName8, (u8)enc, pCtx, xCompare, 0); + sqlite3DbFree(db, zName8); + } + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** Register a collation sequence factory callback with the database handle +** db. Replace any previously installed collation sequence factory. +*/ +SQLITE_API int sqlite3_collation_needed( + sqlite3 *db, + void *pCollNeededArg, + void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*) +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->xCollNeeded = xCollNeeded; + db->xCollNeeded16 = 0; + db->pCollNeededArg = pCollNeededArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Register a collation sequence factory callback with the database handle +** db. Replace any previously installed collation sequence factory. +*/ +SQLITE_API int sqlite3_collation_needed16( + sqlite3 *db, + void *pCollNeededArg, + void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*) +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->xCollNeeded = 0; + db->xCollNeeded16 = xCollNeeded16; + db->pCollNeededArg = pCollNeededArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} +#endif /* SQLITE_OMIT_UTF16 */ + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** This function is now an anachronism. It used to be used to recover from a +** malloc() failure, but SQLite now does this automatically. +*/ +SQLITE_API int sqlite3_global_recover(void){ + return SQLITE_OK; +} +#endif + +/* +** Test to see whether or not the database connection is in autocommit +** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on +** by default. Autocommit is disabled by a BEGIN statement and reenabled +** by the next COMMIT or ROLLBACK. +*/ +SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->autoCommit; +} + +/* +** The following routines are substitutes for constants SQLITE_CORRUPT, +** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error +** constants. They serve two purposes: +** +** 1. Serve as a convenient place to set a breakpoint in a debugger +** to detect when version error conditions occurs. +** +** 2. Invoke sqlite3_log() to provide the source code location where +** a low-level error is first detected. +*/ +static int reportError(int iErr, int lineno, const char *zType){ + sqlite3_log(iErr, "%s at line %d of [%.10s]", + zType, lineno, 20+sqlite3_sourceid()); + return iErr; +} +SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return reportError(SQLITE_CORRUPT, lineno, "database corruption"); +} +SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return reportError(SQLITE_MISUSE, lineno, "misuse"); +} +SQLITE_PRIVATE int sqlite3CantopenError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return reportError(SQLITE_CANTOPEN, lineno, "cannot open file"); +} +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NomemError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return reportError(SQLITE_NOMEM, lineno, "OOM"); +} +SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error"); +} +#endif + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** This is a convenience routine that makes sure that all thread-specific +** data for this thread has been deallocated. +** +** SQLite no longer uses thread-specific data so this routine is now a +** no-op. It is retained for historical compatibility. +*/ +SQLITE_API void sqlite3_thread_cleanup(void){ +} +#endif + +/* +** Return meta information about a specific column of a database table. +** See comment in sqlite3.h (sqlite.h.in) for details. +*/ +SQLITE_API int sqlite3_table_column_metadata( + sqlite3 *db, /* Connection handle */ + const char *zDbName, /* Database name or NULL */ + const char *zTableName, /* Table name */ + const char *zColumnName, /* Column name */ + char const **pzDataType, /* OUTPUT: Declared data type */ + char const **pzCollSeq, /* OUTPUT: Collation sequence name */ + int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int *pPrimaryKey, /* OUTPUT: True if column part of PK */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ +){ + int rc; + char *zErrMsg = 0; + Table *pTab = 0; + Column *pCol = 0; + int iCol = 0; + char const *zDataType = 0; + char const *zCollSeq = 0; + int notnull = 0; + int primarykey = 0; + int autoinc = 0; + + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + + /* Ensure the database schema has been loaded */ + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + rc = sqlite3Init(db, &zErrMsg); + if( SQLITE_OK!=rc ){ + goto error_out; + } + + /* Locate the table in question */ + pTab = sqlite3FindTable(db, zTableName, zDbName); + if( !pTab || pTab->pSelect ){ + pTab = 0; + goto error_out; + } + + /* Find the column for which info is requested */ + if( zColumnName==0 ){ + /* Query for existance of table only */ + }else{ + for(iCol=0; iColnCol; iCol++){ + pCol = &pTab->aCol[iCol]; + if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){ + break; + } + } + if( iCol==pTab->nCol ){ + if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ + iCol = pTab->iPKey; + pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; + }else{ + pTab = 0; + goto error_out; + } + } + } + + /* The following block stores the meta information that will be returned + ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey + ** and autoinc. At this point there are two possibilities: + ** + ** 1. The specified column name was rowid", "oid" or "_rowid_" + ** and there is no explicitly declared IPK column. + ** + ** 2. The table is not a view and the column name identified an + ** explicitly declared column. Copy meta information from *pCol. + */ + if( pCol ){ + zDataType = sqlite3ColumnType(pCol,0); + zCollSeq = pCol->zColl; + notnull = pCol->notNull!=0; + primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; + autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; + }else{ + zDataType = "INTEGER"; + primarykey = 1; + } + if( !zCollSeq ){ + zCollSeq = sqlite3StrBINARY; + } + +error_out: + sqlite3BtreeLeaveAll(db); + + /* Whether the function call succeeded or failed, set the output parameters + ** to whatever their local counterparts contain. If an error did occur, + ** this has the effect of zeroing all output parameters. + */ + if( pzDataType ) *pzDataType = zDataType; + if( pzCollSeq ) *pzCollSeq = zCollSeq; + if( pNotNull ) *pNotNull = notnull; + if( pPrimaryKey ) *pPrimaryKey = primarykey; + if( pAutoinc ) *pAutoinc = autoinc; + + if( SQLITE_OK==rc && !pTab ){ + sqlite3DbFree(db, zErrMsg); + zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName, + zColumnName); + rc = SQLITE_ERROR; + } + sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); + sqlite3DbFree(db, zErrMsg); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Sleep for a little while. Return the amount of time slept. +*/ +SQLITE_API int sqlite3_sleep(int ms){ + sqlite3_vfs *pVfs; + int rc; + pVfs = sqlite3_vfs_find(0); + if( pVfs==0 ) return 0; + + /* This function works in milliseconds, but the underlying OsSleep() + ** API uses microseconds. Hence the 1000's. + */ + rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000); + return rc; +} + +/* +** Enable or disable the extended result codes. +*/ +SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->errMask = onoff ? 0xffffffff : 0xff; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +/* +** Invoke the xFileControl method on a particular database. +*/ +SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ + int rc = SQLITE_ERROR; + Btree *pBtree; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + pBtree = sqlite3DbNameToBtree(db, zDbName); + if( pBtree ){ + Pager *pPager; + sqlite3_file *fd; + sqlite3BtreeEnter(pBtree); + pPager = sqlite3BtreePager(pBtree); + assert( pPager!=0 ); + fd = sqlite3PagerFile(pPager); + assert( fd!=0 ); + if( op==SQLITE_FCNTL_FILE_POINTER ){ + *(sqlite3_file**)pArg = fd; + rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_VFS_POINTER ){ + *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); + rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ + *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); + rc = SQLITE_OK; + }else if( fd->pMethods ){ + rc = sqlite3OsFileControl(fd, op, pArg); + }else{ + rc = SQLITE_NOTFOUND; + } + sqlite3BtreeLeave(pBtree); + } + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Interface to the testing logic. +*/ +SQLITE_API int sqlite3_test_control(int op, ...){ + int rc = 0; +#ifdef SQLITE_UNTESTABLE + UNUSED_PARAMETER(op); +#else + va_list ap; + va_start(ap, op); + switch( op ){ + + /* + ** Save the current state of the PRNG. + */ + case SQLITE_TESTCTRL_PRNG_SAVE: { + sqlite3PrngSaveState(); + break; + } + + /* + ** Restore the state of the PRNG to the last state saved using + ** PRNG_SAVE. If PRNG_SAVE has never before been called, then + ** this verb acts like PRNG_RESET. + */ + case SQLITE_TESTCTRL_PRNG_RESTORE: { + sqlite3PrngRestoreState(); + break; + } + + /* + ** Reset the PRNG back to its uninitialized state. The next call + ** to sqlite3_randomness() will reseed the PRNG using a single call + ** to the xRandomness method of the default VFS. + */ + case SQLITE_TESTCTRL_PRNG_RESET: { + sqlite3_randomness(0,0); + break; + } + + /* + ** sqlite3_test_control(BITVEC_TEST, size, program) + ** + ** Run a test against a Bitvec object of size. The program argument + ** is an array of integers that defines the test. Return -1 on a + ** memory allocation error, 0 on success, or non-zero for an error. + ** See the sqlite3BitvecBuiltinTest() for additional information. + */ + case SQLITE_TESTCTRL_BITVEC_TEST: { + int sz = va_arg(ap, int); + int *aProg = va_arg(ap, int*); + rc = sqlite3BitvecBuiltinTest(sz, aProg); + break; + } + + /* + ** sqlite3_test_control(FAULT_INSTALL, xCallback) + ** + ** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called, + ** if xCallback is not NULL. + ** + ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) + ** is called immediately after installing the new callback and the return + ** value from sqlite3FaultSim(0) becomes the return from + ** sqlite3_test_control(). + */ + case SQLITE_TESTCTRL_FAULT_INSTALL: { + /* MSVC is picky about pulling func ptrs from va lists. + ** http://support.microsoft.com/kb/47961 + ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int)); + */ + typedef int(*TESTCALLBACKFUNC_t)(int); + sqlite3GlobalConfig.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t); + rc = sqlite3FaultSim(0); + break; + } + + /* + ** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd) + ** + ** Register hooks to call to indicate which malloc() failures + ** are benign. + */ + case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: { + typedef void (*void_function)(void); + void_function xBenignBegin; + void_function xBenignEnd; + xBenignBegin = va_arg(ap, void_function); + xBenignEnd = va_arg(ap, void_function); + sqlite3BenignMallocHooks(xBenignBegin, xBenignEnd); + break; + } + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, unsigned int X) + ** + ** Set the PENDING byte to the value in the argument, if X>0. + ** Make no changes if X==0. Return the value of the pending byte + ** as it existing before this routine was called. + ** + ** IMPORTANT: Changing the PENDING byte from 0x40000000 results in + ** an incompatible database file format. Changing the PENDING byte + ** while any database connection is open results in undefined and + ** deleterious behavior. + */ + case SQLITE_TESTCTRL_PENDING_BYTE: { + rc = PENDING_BYTE; +#ifndef SQLITE_OMIT_WSD + { + unsigned int newVal = va_arg(ap, unsigned int); + if( newVal ) sqlite3PendingByte = newVal; + } +#endif + break; + } + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, int X) + ** + ** This action provides a run-time test to see whether or not + ** assert() was enabled at compile-time. If X is true and assert() + ** is enabled, then the return value is true. If X is true and + ** assert() is disabled, then the return value is zero. If X is + ** false and assert() is enabled, then the assertion fires and the + ** process aborts. If X is false and assert() is disabled, then the + ** return value is zero. + */ + case SQLITE_TESTCTRL_ASSERT: { + volatile int x = 0; + assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); + rc = x; + break; + } + + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X) + ** + ** 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 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 + ** default setting. If the return value is 1, then ALWAYS() is either + ** hard-coded to true or else it asserts if its argument is false. + ** The first behavior (hard-coded to true) is the case if + ** SQLITE_TESTCTRL_ASSERT shows that assert() is disabled and the second + ** behavior (assert if the argument to ALWAYS() is false) is the case if + ** SQLITE_TESTCTRL_ASSERT shows that assert() is enabled. + ** + ** The run-time test procedure might look something like this: + ** + ** if( sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, 2)==2 ){ + ** // ALWAYS() and NEVER() are no-op pass-through macros + ** }else if( sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, 1) ){ + ** // ALWAYS(x) asserts that x is true. NEVER(x) asserts x is false. + ** }else{ + ** // ALWAYS(x) is a constant 1. NEVER(x) is a constant 0. + ** } + */ + case SQLITE_TESTCTRL_ALWAYS: { + int x = va_arg(ap,int); + rc = ALWAYS(x); + break; + } + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER); + ** + ** The integer returned reveals the byte-order of the computer on which + ** SQLite is running: + ** + ** 1 big-endian, determined at run-time + ** 10 little-endian, determined at run-time + ** 432101 big-endian, determined at compile-time + ** 123410 little-endian, determined at compile-time + */ + case SQLITE_TESTCTRL_BYTEORDER: { + rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N) + ** + ** Set the nReserve size to N for the main database on the database + ** connection db. + */ + case SQLITE_TESTCTRL_RESERVE: { + sqlite3 *db = va_arg(ap, sqlite3*); + int x = va_arg(ap,int); + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0); + sqlite3_mutex_leave(db->mutex); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N) + ** + ** Enable or disable various optimizations for testing purposes. The + ** argument N is a bitmask of optimizations to be disabled. For normal + ** operation N should be 0. The idea is that a test program (like the + ** SQL Logic Test or SLT test module) can run the same SQL multiple times + ** with various optimizations disabled to verify that the same answer + ** is obtained in every case. + */ + case SQLITE_TESTCTRL_OPTIMIZATIONS: { + sqlite3 *db = va_arg(ap, sqlite3*); + db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff); + break; + } + +#ifdef SQLITE_N_KEYWORD + /* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord) + ** + ** If zWord is a keyword recognized by the parser, then return the + ** number of keywords. Or if zWord is not a keyword, return 0. + ** + ** This test feature is only available in the amalgamation since + ** the SQLITE_N_KEYWORD macro is not defined in this file if SQLite + ** is built using separate source files. + */ + case SQLITE_TESTCTRL_ISKEYWORD: { + const char *zWord = va_arg(ap, const char*); + int n = sqlite3Strlen30(zWord); + rc = (sqlite3KeywordCode((u8*)zWord, n)!=TK_ID) ? SQLITE_N_KEYWORD : 0; + break; + } +#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 + ** subsequent calls to localtime() and variants fail. If onoff is zero, + ** undo this setting. + */ + case SQLITE_TESTCTRL_LOCALTIME_FAULT: { + sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); + ** + ** Set or clear a flag that indicates that the database file is always well- + ** formed and never corrupt. This flag is clear by default, indicating that + ** database files might have arbitrary corruption. Setting the flag during + ** testing causes certain assert() statements in the code to be activated + ** that demonstrat invariants on well-formed database files. + */ + case SQLITE_TESTCTRL_NEVER_CORRUPT: { + sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int); + break; + } + + /* Set the threshold at which OP_Once counters reset back to zero. + ** By default this is 0x7ffffffe (over 2 billion), but that value is + ** too big to test in a reasonable amount of time, so this control is + ** provided to set a small and easily reachable reset value. + */ + case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: { + sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr); + ** + ** Set the VDBE coverage callback function to xCallback with context + ** pointer ptr. + */ + case SQLITE_TESTCTRL_VDBE_COVERAGE: { +#ifdef SQLITE_VDBE_COVERAGE + typedef void (*branch_callback)(void*,int,u8,u8); + sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback); + sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*); +#endif + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */ + case SQLITE_TESTCTRL_SORTER_MMAP: { + sqlite3 *db = va_arg(ap, sqlite3*); + db->nMaxSorterMmap = va_arg(ap, int); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); + ** + ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if + ** not. + */ + case SQLITE_TESTCTRL_ISINIT: { + if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); + ** + ** This test control is used to create imposter tables. "db" is a pointer + ** to the database connection. dbName is the database name (ex: "main" or + ** "temp") which will receive the imposter. "onOff" turns imposter mode on + ** or off. "tnum" is the root page of the b-tree to which the imposter + ** table should connect. + ** + ** Enable imposter mode only when the schema has already been parsed. Then + ** run a single CREATE TABLE statement to construct the imposter table in + ** the parsed schema. Then turn imposter mode back off again. + ** + ** If onOff==0 and tnum>0 then reset the schema for all databases, causing + ** the schema to be reparsed the next time it is needed. This has the + ** effect of erasing all imposter tables. + */ + case SQLITE_TESTCTRL_IMPOSTER: { + sqlite3 *db = va_arg(ap, sqlite3*); + sqlite3_mutex_enter(db->mutex); + db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); + db->init.busy = db->init.imposterTable = va_arg(ap,int); + db->init.newTnum = va_arg(ap,int); + if( db->init.busy==0 && db->init.newTnum>0 ){ + sqlite3ResetAllSchemasOfConnection(db); + } + sqlite3_mutex_leave(db->mutex); + break; + } + } + va_end(ap); +#endif /* SQLITE_UNTESTABLE */ + return rc; +} + +/* +** This is a utility routine, useful to VFS implementations, that checks +** to see if a database file was a URI that contained a specific query +** parameter, and if so obtains the value of the query parameter. +** +** The zFilename argument is the filename pointer passed into the xOpen() +** method of a VFS implementation. The zParam argument is the name of the +** query parameter we seek. This routine returns the value of the zParam +** parameter if it exists. If the parameter does not exist, this routine +** returns a NULL pointer. +*/ +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ + if( zFilename==0 || zParam==0 ) return 0; + zFilename += sqlite3Strlen30(zFilename) + 1; + while( zFilename[0] ){ + int x = strcmp(zFilename, zParam); + zFilename += sqlite3Strlen30(zFilename) + 1; + if( x==0 ) return zFilename; + zFilename += sqlite3Strlen30(zFilename) + 1; + } + return 0; +} + +/* +** Return a boolean value for a query parameter. +*/ +SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){ + const char *z = sqlite3_uri_parameter(zFilename, zParam); + bDflt = bDflt!=0; + return z ? sqlite3GetBoolean(z, bDflt) : bDflt; +} + +/* +** Return a 64-bit integer value for a query parameter. +*/ +SQLITE_API sqlite3_int64 sqlite3_uri_int64( + const char *zFilename, /* Filename as passed to xOpen */ + const char *zParam, /* URI parameter sought */ + sqlite3_int64 bDflt /* return if parameter is missing */ +){ + const char *z = sqlite3_uri_parameter(zFilename, zParam); + sqlite3_int64 v; + if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ + bDflt = v; + } + return bDflt; +} + +/* +** Return the Btree pointer identified by zDbName. Return NULL if not found. +*/ +SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ + int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0; + return iDb<0 ? 0 : db->aDb[iDb].pBt; +} + +/* +** Return the filename of the database associated with a database +** connection. +*/ +SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ + Btree *pBt; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + pBt = sqlite3DbNameToBtree(db, zDbName); + return pBt ? sqlite3BtreeGetFilename(pBt) : 0; +} + +/* +** Return 1 if database is read-only or 0 if read/write. Return -1 if +** no such database exists. +*/ +SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ + Btree *pBt; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + pBt = sqlite3DbNameToBtree(db, zDbName); + return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; +} + +#ifdef SQLITE_ENABLE_SNAPSHOT +/* +** Obtain a snapshot handle for the snapshot of database zDb currently +** being read by handle db. +*/ +SQLITE_API int sqlite3_snapshot_get( + sqlite3 *db, + const char *zDb, + sqlite3_snapshot **ppSnapshot +){ + int rc = SQLITE_ERROR; +#ifndef SQLITE_OMIT_WAL + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + + if( db->autoCommit==0 ){ + int iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( 0==sqlite3BtreeIsInTrans(pBt) ){ + rc = sqlite3BtreeBeginTrans(pBt, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); + } + } + } + } + + sqlite3_mutex_leave(db->mutex); +#endif /* SQLITE_OMIT_WAL */ + return rc; +} + +/* +** Open a read-transaction on the snapshot idendified by pSnapshot. +*/ +SQLITE_API int sqlite3_snapshot_open( + sqlite3 *db, + const char *zDb, + sqlite3_snapshot *pSnapshot +){ + int rc = SQLITE_ERROR; +#ifndef SQLITE_OMIT_WAL + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( db->autoCommit==0 ){ + int iDb; + iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ + rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginTrans(pBt, 0); + sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0); + } + } + } + } + + sqlite3_mutex_leave(db->mutex); +#endif /* SQLITE_OMIT_WAL */ + return rc; +} + +/* +** Recover as many snapshots as possible from the wal file associated with +** schema zDb of database db. +*/ +SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ + int rc = SQLITE_ERROR; + int iDb; +#ifndef SQLITE_OMIT_WAL + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + + sqlite3_mutex_enter(db->mutex); + iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ + rc = sqlite3BtreeBeginTrans(pBt, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); + sqlite3BtreeCommit(pBt); + } + } + } + sqlite3_mutex_leave(db->mutex); +#endif /* SQLITE_OMIT_WAL */ + return rc; +} + +/* +** Free a snapshot handle obtained from sqlite3_snapshot_get(). +*/ +SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ + sqlite3_free(pSnapshot); +} +#endif /* SQLITE_ENABLE_SNAPSHOT */ + +/************** End of main.c ************************************************/ +/************** Begin file notify.c ******************************************/ +/* +** 2009 March 3 +** +** 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 the implementation of the sqlite3_unlock_notify() +** API method and its associated functionality. +*/ +/* #include "sqliteInt.h" */ +/* #include "btreeInt.h" */ + +/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */ +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY + +/* +** Public interfaces: +** +** sqlite3ConnectionBlocked() +** sqlite3ConnectionUnlocked() +** sqlite3ConnectionClosed() +** sqlite3_unlock_notify() +*/ + +#define assertMutexHeld() \ + assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) ) + +/* +** Head of a linked list of all sqlite3 objects created by this process +** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection +** is not NULL. This variable may only accessed while the STATIC_MASTER +** mutex is held. +*/ +static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0; + +#ifndef NDEBUG +/* +** This function is a complex assert() that verifies the following +** properties of the blocked connections list: +** +** 1) Each entry in the list has a non-NULL value for either +** pUnlockConnection or pBlockingConnection, or both. +** +** 2) All entries in the list that share a common value for +** xUnlockNotify are grouped together. +** +** 3) If the argument db is not NULL, then none of the entries in the +** blocked connections list have pUnlockConnection or pBlockingConnection +** set to db. This is used when closing connection db. +*/ +static void checkListProperties(sqlite3 *db){ + sqlite3 *p; + for(p=sqlite3BlockedList; p; p=p->pNextBlocked){ + int seen = 0; + sqlite3 *p2; + + /* Verify property (1) */ + assert( p->pUnlockConnection || p->pBlockingConnection ); + + /* Verify property (2) */ + for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){ + if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1; + assert( p2->xUnlockNotify==p->xUnlockNotify || !seen ); + assert( db==0 || p->pUnlockConnection!=db ); + assert( db==0 || p->pBlockingConnection!=db ); + } + } +} +#else +# define checkListProperties(x) +#endif + +/* +** Remove connection db from the blocked connections list. If connection +** db is not currently a part of the list, this function is a no-op. +*/ +static void removeFromBlockedList(sqlite3 *db){ + sqlite3 **pp; + assertMutexHeld(); + for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){ + if( *pp==db ){ + *pp = (*pp)->pNextBlocked; + break; + } + } +} + +/* +** Add connection db to the blocked connections list. It is assumed +** that it is not already a part of the list. +*/ +static void addToBlockedList(sqlite3 *db){ + sqlite3 **pp; + assertMutexHeld(); + for( + pp=&sqlite3BlockedList; + *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify; + pp=&(*pp)->pNextBlocked + ); + db->pNextBlocked = *pp; + *pp = db; +} + +/* +** Obtain the STATIC_MASTER mutex. +*/ +static void enterMutex(void){ + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); + checkListProperties(0); +} + +/* +** Release the STATIC_MASTER mutex. +*/ +static void leaveMutex(void){ + assertMutexHeld(); + checkListProperties(0); + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +/* +** Register an unlock-notify callback. +** +** This is called after connection "db" has attempted some operation +** but has received an SQLITE_LOCKED error because another connection +** (call it pOther) in the same process was busy using the same shared +** cache. pOther is found by looking at db->pBlockingConnection. +** +** If there is no blocking connection, the callback is invoked immediately, +** before this routine returns. +** +** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate +** a deadlock. +** +** Otherwise, make arrangements to invoke xNotify when pOther drops +** its locks. +** +** Each call to this routine overrides any prior callbacks registered +** on the same "db". If xNotify==0 then any prior callbacks are immediately +** cancelled. +*/ +SQLITE_API int sqlite3_unlock_notify( + sqlite3 *db, + void (*xNotify)(void **, int), + void *pArg +){ + int rc = SQLITE_OK; + + sqlite3_mutex_enter(db->mutex); + enterMutex(); + + if( xNotify==0 ){ + removeFromBlockedList(db); + db->pBlockingConnection = 0; + db->pUnlockConnection = 0; + db->xUnlockNotify = 0; + db->pUnlockArg = 0; + }else if( 0==db->pBlockingConnection ){ + /* The blocking transaction has been concluded. Or there never was a + ** blocking transaction. In either case, invoke the notify callback + ** immediately. + */ + xNotify(&pArg, 1); + }else{ + sqlite3 *p; + + for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){} + if( p ){ + rc = SQLITE_LOCKED; /* Deadlock detected. */ + }else{ + db->pUnlockConnection = db->pBlockingConnection; + db->xUnlockNotify = xNotify; + db->pUnlockArg = pArg; + removeFromBlockedList(db); + addToBlockedList(db); + } + } + + leaveMutex(); + assert( !db->mallocFailed ); + sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0)); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** This function is called while stepping or preparing a statement +** associated with connection db. The operation will return SQLITE_LOCKED +** to the user because it requires a lock that will not be available +** until connection pBlocker concludes its current transaction. +*/ +SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){ + enterMutex(); + if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){ + addToBlockedList(db); + } + db->pBlockingConnection = pBlocker; + leaveMutex(); +} + +/* +** This function is called when +** the transaction opened by database db has just finished. Locks held +** by database connection db have been released. +** +** This function loops through each entry in the blocked connections +** list and does the following: +** +** 1) If the sqlite3.pBlockingConnection member of a list entry is +** set to db, then set pBlockingConnection=0. +** +** 2) If the sqlite3.pUnlockConnection member of a list entry is +** set to db, then invoke the configured unlock-notify callback and +** set pUnlockConnection=0. +** +** 3) If the two steps above mean that pBlockingConnection==0 and +** pUnlockConnection==0, remove the entry from the blocked connections +** list. +*/ +SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){ + void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */ + int nArg = 0; /* Number of entries in aArg[] */ + sqlite3 **pp; /* Iterator variable */ + void **aArg; /* Arguments to the unlock callback */ + void **aDyn = 0; /* Dynamically allocated space for aArg[] */ + void *aStatic[16]; /* Starter space for aArg[]. No malloc required */ + + aArg = aStatic; + enterMutex(); /* Enter STATIC_MASTER mutex */ + + /* This loop runs once for each entry in the blocked-connections list. */ + for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){ + sqlite3 *p = *pp; + + /* Step 1. */ + if( p->pBlockingConnection==db ){ + p->pBlockingConnection = 0; + } + + /* Step 2. */ + if( p->pUnlockConnection==db ){ + assert( p->xUnlockNotify ); + if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){ + xUnlockNotify(aArg, nArg); + nArg = 0; + } + + sqlite3BeginBenignMalloc(); + assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) ); + assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn ); + if( (!aDyn && nArg==(int)ArraySize(aStatic)) + || (aDyn && nArg==(int)(sqlite3MallocSize(aDyn)/sizeof(void*))) + ){ + /* The aArg[] array needs to grow. */ + void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2); + if( pNew ){ + memcpy(pNew, aArg, nArg*sizeof(void *)); + sqlite3_free(aDyn); + aDyn = aArg = pNew; + }else{ + /* This occurs when the array of context pointers that need to + ** be passed to the unlock-notify callback is larger than the + ** aStatic[] array allocated on the stack and the attempt to + ** allocate a larger array from the heap has failed. + ** + ** This is a difficult situation to handle. Returning an error + ** code to the caller is insufficient, as even if an error code + ** is returned the transaction on connection db will still be + ** closed and the unlock-notify callbacks on blocked connections + ** will go unissued. This might cause the application to wait + ** indefinitely for an unlock-notify callback that will never + ** arrive. + ** + ** Instead, invoke the unlock-notify callback with the context + ** array already accumulated. We can then clear the array and + ** begin accumulating any further context pointers without + ** requiring any dynamic allocation. This is sub-optimal because + ** it means that instead of one callback with a large array of + ** context pointers the application will receive two or more + ** callbacks with smaller arrays of context pointers, which will + ** reduce the applications ability to prioritize multiple + ** connections. But it is the best that can be done under the + ** circumstances. + */ + xUnlockNotify(aArg, nArg); + nArg = 0; + } + } + sqlite3EndBenignMalloc(); + + aArg[nArg++] = p->pUnlockArg; + xUnlockNotify = p->xUnlockNotify; + p->pUnlockConnection = 0; + p->xUnlockNotify = 0; + p->pUnlockArg = 0; + } + + /* Step 3. */ + if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){ + /* Remove connection p from the blocked connections list. */ + *pp = p->pNextBlocked; + p->pNextBlocked = 0; + }else{ + pp = &p->pNextBlocked; + } + } + + if( nArg!=0 ){ + xUnlockNotify(aArg, nArg); + } + sqlite3_free(aDyn); + leaveMutex(); /* Leave STATIC_MASTER mutex */ +} + +/* +** This is called when the database connection passed as an argument is +** being closed. The connection is removed from the blocked list. +*/ +SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ + sqlite3ConnectionUnlocked(db); + enterMutex(); + removeFromBlockedList(db); + checkListProperties(db); + leaveMutex(); +} +#endif + +/************** End of notify.c **********************************************/ +/************** Begin file fts3.c ********************************************/ +/* +** 2006 Oct 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 is an SQLite module implementing full-text search. +*/ + +/* +** The code in this file is only compiled if: +** +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +*/ + +/* The full-text index is stored in a series of b+tree (-like) +** structures called segments which map terms to doclists. The +** structures are like b+trees in layout, but are constructed from the +** bottom up in optimal fashion and are not updatable. Since trees +** are built from the bottom up, things will be described from the +** bottom up. +** +** +**** Varints **** +** The basic unit of encoding is a variable-length integer called a +** varint. We encode variable-length integers in little-endian order +** using seven bits * per byte as follows: +** +** KEY: +** A = 0xxxxxxx 7 bits of data and one flag bit +** B = 1xxxxxxx 7 bits of data and one flag bit +** +** 7 bits - A +** 14 bits - BA +** 21 bits - BBA +** and so on. +** +** This is similar in concept to how sqlite encodes "varints" but +** the encoding is not the same. SQLite varints are big-endian +** are are limited to 9 bytes in length whereas FTS3 varints are +** little-endian and can be up to 10 bytes in length (in theory). +** +** Example encodings: +** +** 1: 0x01 +** 127: 0x7f +** 128: 0x81 0x00 +** +** +**** Document lists **** +** A doclist (document list) holds a docid-sorted list of hits for a +** given term. Doclists hold docids and associated token positions. +** A docid is the unique integer identifier for a single document. +** A position is the index of a word within the document. The first +** word of the document has a position of 0. +** +** FTS3 used to optionally store character offsets using a compile-time +** option. But that functionality is no longer supported. +** +** A doclist is stored like this: +** +** array { +** varint docid; (delta from previous doclist) +** array { (position list for column 0) +** varint position; (2 more than the delta from previous position) +** } +** array { +** varint POS_COLUMN; (marks start of position list for new column) +** varint column; (index of new column) +** array { +** varint position; (2 more than the delta from previous position) +** } +** } +** varint POS_END; (marks end of positions for this document. +** } +** +** Here, array { X } means zero or more occurrences of X, adjacent in +** memory. A "position" is an index of a token in the token stream +** generated by the tokenizer. Note that POS_END and POS_COLUMN occur +** in the same logical place as the position element, and act as sentinals +** ending a position list array. POS_END is 0. POS_COLUMN is 1. +** The positions numbers are not stored literally but rather as two more +** than the difference from the prior position, or the just the position plus +** 2 for the first position. Example: +** +** label: A B C D E F G H I J K +** value: 123 5 9 1 1 14 35 0 234 72 0 +** +** The 123 value is the first docid. For column zero in this document +** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1 +** at D signals the start of a new column; the 1 at E indicates that the +** new column is column number 1. There are two positions at 12 and 45 +** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The +** 234 at I is the delta to next docid (357). It has one position 70 +** (72-2) and then terminates with the 0 at K. +** +** A "position-list" is the list of positions for multiple columns for +** a single docid. A "column-list" is the set of positions for a single +** column. Hence, a position-list consists of one or more column-lists, +** a document record consists of a docid followed by a position-list and +** a doclist consists of one or more document records. +** +** A bare doclist omits the position information, becoming an +** array of varint-encoded docids. +** +**** Segment leaf nodes **** +** Segment leaf nodes store terms and doclists, ordered by term. Leaf +** nodes are written using LeafWriter, and read using LeafReader (to +** iterate through a single leaf node's data) and LeavesReader (to +** iterate through a segment's entire leaf layer). Leaf nodes have +** the format: +** +** varint iHeight; (height from leaf level, always 0) +** varint nTerm; (length of first term) +** char pTerm[nTerm]; (content of first term) +** varint nDoclist; (length of term's associated doclist) +** char pDoclist[nDoclist]; (content of doclist) +** array { +** (further terms are delta-encoded) +** varint nPrefix; (length of prefix shared with previous term) +** varint nSuffix; (length of unshared suffix) +** char pTermSuffix[nSuffix];(unshared suffix of next term) +** varint nDoclist; (length of term's associated doclist) +** char pDoclist[nDoclist]; (content of doclist) +** } +** +** Here, array { X } means zero or more occurrences of X, adjacent in +** memory. +** +** Leaf nodes are broken into blocks which are stored contiguously in +** the %_segments table in sorted order. This means that when the end +** of a node is reached, the next term is in the node with the next +** greater node id. +** +** New data is spilled to a new leaf node when the current node +** exceeds LEAF_MAX bytes (default 2048). New data which itself is +** larger than STANDALONE_MIN (default 1024) is placed in a standalone +** node (a leaf node with a single term and doclist). The goal of +** these settings is to pack together groups of small doclists while +** making it efficient to directly access large doclists. The +** assumption is that large doclists represent terms which are more +** likely to be query targets. +** +** TODO(shess) It may be useful for blocking decisions to be more +** dynamic. For instance, it may make more sense to have a 2.5k leaf +** node rather than splitting into 2k and .5k nodes. My intuition is +** that this might extend through 2x or 4x the pagesize. +** +** +**** Segment interior nodes **** +** Segment interior nodes store blockids for subtree nodes and terms +** to describe what data is stored by the each subtree. Interior +** nodes are written using InteriorWriter, and read using +** InteriorReader. InteriorWriters are created as needed when +** SegmentWriter creates new leaf nodes, or when an interior node +** itself grows too big and must be split. The format of interior +** nodes: +** +** varint iHeight; (height from leaf level, always >0) +** varint iBlockid; (block id of node's leftmost subtree) +** optional { +** varint nTerm; (length of first term) +** char pTerm[nTerm]; (content of first term) +** array { +** (further terms are delta-encoded) +** varint nPrefix; (length of shared prefix with previous term) +** varint nSuffix; (length of unshared suffix) +** char pTermSuffix[nSuffix]; (unshared suffix of next term) +** } +** } +** +** Here, optional { X } means an optional element, while array { X } +** means zero or more occurrences of X, adjacent in memory. +** +** An interior node encodes n terms separating n+1 subtrees. The +** subtree blocks are contiguous, so only the first subtree's blockid +** is encoded. The subtree at iBlockid will contain all terms less +** than the first term encoded (or all terms if no term is encoded). +** Otherwise, for terms greater than or equal to pTerm[i] but less +** than pTerm[i+1], the subtree for that term will be rooted at +** iBlockid+i. Interior nodes only store enough term data to +** distinguish adjacent children (if the rightmost term of the left +** child is "something", and the leftmost term of the right child is +** "wicked", only "w" is stored). +** +** New data is spilled to a new interior node at the same height when +** the current node exceeds INTERIOR_MAX bytes (default 2048). +** INTERIOR_MIN_TERMS (default 7) keeps large terms from monopolizing +** interior nodes and making the tree too skinny. The interior nodes +** at a given height are naturally tracked by interior nodes at +** height+1, and so on. +** +** +**** Segment directory **** +** The segment directory in table %_segdir stores meta-information for +** merging and deleting segments, and also the root node of the +** segment's tree. +** +** The root node is the top node of the segment's tree after encoding +** the entire segment, restricted to ROOT_MAX bytes (default 1024). +** This could be either a leaf node or an interior node. If the top +** node requires more than ROOT_MAX bytes, it is flushed to %_segments +** and a new root interior node is generated (which should always fit +** within ROOT_MAX because it only needs space for 2 varints, the +** height and the blockid of the previous root). +** +** The meta-information in the segment directory is: +** level - segment level (see below) +** idx - index within level +** - (level,idx uniquely identify a segment) +** start_block - first leaf node +** leaves_end_block - last leaf node +** end_block - last block (including interior nodes) +** root - contents of root node +** +** If the root node is a leaf node, then start_block, +** leaves_end_block, and end_block are all 0. +** +** +**** Segment merging **** +** To amortize update costs, segments are grouped into levels and +** merged in batches. Each increase in level represents exponentially +** more documents. +** +** New documents (actually, document updates) are tokenized and +** written individually (using LeafWriter) to a level 0 segment, with +** incrementing idx. When idx reaches MERGE_COUNT (default 16), all +** level 0 segments are merged into a single level 1 segment. Level 1 +** is populated like level 0, and eventually MERGE_COUNT level 1 +** segments are merged to a single level 2 segment (representing +** MERGE_COUNT^2 updates), and so on. +** +** A segment merge traverses all segments at a given level in +** parallel, performing a straightforward sorted merge. Since segment +** leaf nodes are written in to the %_segments table in order, this +** merge traverses the underlying sqlite disk structures efficiently. +** After the merge, all segment blocks from the merged level are +** deleted. +** +** MERGE_COUNT controls how often we merge segments. 16 seems to be +** somewhat of a sweet spot for insertion performance. 32 and 64 show +** very similar performance numbers to 16 on insertion, though they're +** a tiny bit slower (perhaps due to more overhead in merge-time +** sorting). 8 is about 20% slower than 16, 4 about 50% slower than +** 16, 2 about 66% slower than 16. +** +** At query time, high MERGE_COUNT increases the number of segments +** which need to be scanned and merged. For instance, with 100k docs +** inserted: +** +** MERGE_COUNT segments +** 16 25 +** 8 12 +** 4 10 +** 2 6 +** +** This appears to have only a moderate impact on queries for very +** frequent terms (which are somewhat dominated by segment merge +** costs), and infrequent and non-existent terms still seem to be fast +** even with many segments. +** +** TODO(shess) That said, it would be nice to have a better query-side +** argument for MERGE_COUNT of 16. Also, it is possible/likely that +** optimizations to things like doclist merging will swing the sweet +** spot around. +** +** +** +**** Handling of deletions and updates **** +** Since we're using a segmented structure, with no docid-oriented +** index into the term index, we clearly cannot simply update the term +** index when a document is deleted or updated. For deletions, we +** write an empty doclist (varint(docid) varint(POS_END)), for updates +** we simply write the new doclist. Segment merges overwrite older +** data for a particular docid with newer data, so deletes or updates +** will eventually overtake the earlier data and knock it out. The +** query logic likewise merges doclists so that newer data knocks out +** older data. +*/ + +/************** Include fts3Int.h in the middle of fts3.c ********************/ +/************** Begin file fts3Int.h *****************************************/ +/* +** 2009 Nov 12 +** +** 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. +** +****************************************************************************** +** +*/ +#ifndef _FTSINT_H +#define _FTSINT_H + +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif + +/* FTS3/FTS4 require virtual tables */ +#ifdef SQLITE_OMIT_VIRTUALTABLE +# undef SQLITE_ENABLE_FTS3 +# undef SQLITE_ENABLE_FTS4 +#endif + +/* +** FTS4 is really an extension for FTS3. It is enabled using the +** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all +** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3. +*/ +#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) +# define SQLITE_ENABLE_FTS3 +#endif + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* If not building as part of the core, include sqlite3ext.h. */ +#ifndef SQLITE_CORE +/* # include "sqlite3ext.h" */ +SQLITE_EXTENSION_INIT3 +#endif + +/* #include "sqlite3.h" */ +/************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/ +/************** Begin file fts3_tokenizer.h **********************************/ +/* +** 2006 July 10 +** +** The author disclaims copyright to this source code. +** +************************************************************************* +** Defines the interface to tokenizers used by fulltext-search. There +** are three basic components: +** +** sqlite3_tokenizer_module is a singleton defining the tokenizer +** interface functions. This is essentially the class structure for +** tokenizers. +** +** sqlite3_tokenizer is used to define a particular tokenizer, perhaps +** including customization information defined at creation time. +** +** sqlite3_tokenizer_cursor is generated by a tokenizer to generate +** tokens from a particular input. +*/ +#ifndef _FTS3_TOKENIZER_H_ +#define _FTS3_TOKENIZER_H_ + +/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. +** If tokenizers are to be allowed to call sqlite3_*() functions, then +** we will need a way to register the API consistently. +*/ +/* #include "sqlite3.h" */ + +/* +** Structures used by the tokenizer interface. When a new tokenizer +** implementation is registered, the caller provides a pointer to +** an sqlite3_tokenizer_module containing pointers to the callback +** functions that make up an implementation. +** +** When an fts3 table is created, it passes any arguments passed to +** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the +** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer +** implementation. The xCreate() function in turn returns an +** sqlite3_tokenizer structure representing the specific tokenizer to +** be used for the fts3 table (customized by the tokenizer clause arguments). +** +** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() +** method is called. It returns an sqlite3_tokenizer_cursor object +** that may be used to tokenize a specific input buffer based on +** the tokenization rules supplied by a specific sqlite3_tokenizer +** object. +*/ +typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; +typedef struct sqlite3_tokenizer sqlite3_tokenizer; +typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; + +struct sqlite3_tokenizer_module { + + /* + ** Structure version. Should always be set to 0 or 1. + */ + int iVersion; + + /* + ** Create a new tokenizer. The values in the argv[] array are the + ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL + ** TABLE statement that created the fts3 table. For example, if + ** the following SQL is executed: + ** + ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) + ** + ** then argc is set to 2, and the argv[] array contains pointers + ** to the strings "arg1" and "arg2". + ** + ** This method should return either SQLITE_OK (0), or an SQLite error + ** code. If SQLITE_OK is returned, then *ppTokenizer should be set + ** to point at the newly created tokenizer structure. The generic + ** sqlite3_tokenizer.pModule variable should not be initialized by + ** this callback. The caller will do so. + */ + int (*xCreate)( + int argc, /* Size of argv array */ + const char *const*argv, /* Tokenizer argument strings */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ + ); + + /* + ** Destroy an existing tokenizer. The fts3 module calls this method + ** exactly once for each successful call to xCreate(). + */ + int (*xDestroy)(sqlite3_tokenizer *pTokenizer); + + /* + ** Create a tokenizer cursor to tokenize an input buffer. The caller + ** is responsible for ensuring that the input buffer remains valid + ** until the cursor is closed (using the xClose() method). + */ + int (*xOpen)( + sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ + const char *pInput, int nBytes, /* Input buffer */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ + ); + + /* + ** Destroy an existing tokenizer cursor. The fts3 module calls this + ** method exactly once for each successful call to xOpen(). + */ + int (*xClose)(sqlite3_tokenizer_cursor *pCursor); + + /* + ** Retrieve the next token from the tokenizer cursor pCursor. This + ** method should either return SQLITE_OK and set the values of the + ** "OUT" variables identified below, or SQLITE_DONE to indicate that + ** the end of the buffer has been reached, or an SQLite error code. + ** + ** *ppToken should be set to point at a buffer containing the + ** normalized version of the token (i.e. after any case-folding and/or + ** stemming has been performed). *pnBytes should be set to the length + ** of this buffer in bytes. The input text that generated the token is + ** identified by the byte offsets returned in *piStartOffset and + ** *piEndOffset. *piStartOffset should be set to the index of the first + ** byte of the token in the input buffer. *piEndOffset should be set + ** to the index of the first byte just past the end of the token in + ** the input buffer. + ** + ** The buffer *ppToken is set to point at is managed by the tokenizer + ** implementation. It is only required to be valid until the next call + ** to xNext() or xClose(). + */ + /* TODO(shess) current implementation requires pInput to be + ** nul-terminated. This should either be fixed, or pInput/nBytes + ** should be converted to zInput. + */ + int (*xNext)( + sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ + const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ + int *piStartOffset, /* OUT: Byte offset of token in input buffer */ + int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ + int *piPosition /* OUT: Number of tokens returned before this one */ + ); + + /*********************************************************************** + ** Methods below this point are only available if iVersion>=1. + */ + + /* + ** Configure the language id of a tokenizer cursor. + */ + int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); +}; + +struct sqlite3_tokenizer { + const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ + /* Tokenizer implementations will typically add additional fields */ +}; + +struct sqlite3_tokenizer_cursor { + sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ + /* Tokenizer implementations will typically add additional fields */ +}; + +int fts3_global_term_cnt(int iTerm, int iCol); +int fts3_term_cnt(int iTerm, int iCol); + + +#endif /* _FTS3_TOKENIZER_H_ */ + +/************** End of fts3_tokenizer.h **************************************/ +/************** Continuing where we left off in fts3Int.h ********************/ +/************** Include fts3_hash.h in the middle of fts3Int.h ***************/ +/************** Begin file fts3_hash.h ***************************************/ +/* +** 2001 September 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This is the header file for the generic hash-table implementation +** used in SQLite. We've modified it slightly to serve as a standalone +** hash table implementation for the full-text indexing module. +** +*/ +#ifndef _FTS3_HASH_H_ +#define _FTS3_HASH_H_ + +/* Forward declarations of structures. */ +typedef struct Fts3Hash Fts3Hash; +typedef struct Fts3HashElem Fts3HashElem; + +/* A complete hash table is an instance of the following structure. +** The internals of this structure are intended to be opaque -- client +** code should not attempt to access or modify the fields of this structure +** directly. Change this structure only by using the routines below. +** However, many of the "procedures" and "functions" for modifying and +** accessing this structure are really macros, so we can't really make +** this structure opaque. +*/ +struct Fts3Hash { + char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ + char copyKey; /* True if copy of key made on insert */ + int count; /* Number of entries in this table */ + Fts3HashElem *first; /* The first element of the array */ + int htsize; /* Number of buckets in the hash table */ + struct _fts3ht { /* the hash table */ + int count; /* Number of entries with this hash */ + Fts3HashElem *chain; /* Pointer to first entry with this hash */ + } *ht; +}; + +/* Each element in the hash table is an instance of the following +** structure. All elements are stored on a single doubly-linked list. +** +** Again, this structure is intended to be opaque, but it can't really +** be opaque because it is used by macros. +*/ +struct Fts3HashElem { + Fts3HashElem *next, *prev; /* Next and previous elements in the table */ + void *data; /* Data associated with this element */ + void *pKey; int nKey; /* Key associated with this element */ +}; + +/* +** There are 2 different modes of operation for a hash table: +** +** FTS3_HASH_STRING pKey points to a string that is nKey bytes long +** (including the null-terminator, if any). Case +** is respected in comparisons. +** +** FTS3_HASH_BINARY pKey points to binary data nKey bytes long. +** memcmp() is used to compare keys. +** +** A copy of the key is made if the copyKey parameter to fts3HashInit is 1. +*/ +#define FTS3_HASH_STRING 1 +#define FTS3_HASH_BINARY 2 + +/* +** Access routines. To delete, insert a NULL pointer. +*/ +SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey); +SQLITE_PRIVATE void *sqlite3Fts3HashInsert(Fts3Hash*, const void *pKey, int nKey, void *pData); +SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash*, const void *pKey, int nKey); +SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash*); +SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const void *, int); + +/* +** Shorthand for the functions above +*/ +#define fts3HashInit sqlite3Fts3HashInit +#define fts3HashInsert sqlite3Fts3HashInsert +#define fts3HashFind sqlite3Fts3HashFind +#define fts3HashClear sqlite3Fts3HashClear +#define fts3HashFindElem sqlite3Fts3HashFindElem + +/* +** Macros for looping over all elements of a hash table. The idiom is +** like this: +** +** Fts3Hash h; +** Fts3HashElem *p; +** ... +** for(p=fts3HashFirst(&h); p; p=fts3HashNext(p)){ +** SomeStructure *pData = fts3HashData(p); +** // do something with pData +** } +*/ +#define fts3HashFirst(H) ((H)->first) +#define fts3HashNext(E) ((E)->next) +#define fts3HashData(E) ((E)->data) +#define fts3HashKey(E) ((E)->pKey) +#define fts3HashKeysize(E) ((E)->nKey) + +/* +** Number of entries in a hash table +*/ +#define fts3HashCount(H) ((H)->count) + +#endif /* _FTS3_HASH_H_ */ + +/************** End of fts3_hash.h *******************************************/ +/************** Continuing where we left off in fts3Int.h ********************/ + +/* +** This constant determines the maximum depth of an FTS expression tree +** that the library will create and use. FTS uses recursion to perform +** various operations on the query tree, so the disadvantage of a large +** limit is that it may allow very large queries to use large amounts +** of stack space (perhaps causing a stack overflow). +*/ +#ifndef SQLITE_FTS3_MAX_EXPR_DEPTH +# define SQLITE_FTS3_MAX_EXPR_DEPTH 12 +#endif + + +/* +** This constant controls how often segments are merged. Once there are +** FTS3_MERGE_COUNT segments of level N, they are merged into a single +** segment of level N+1. +*/ +#define FTS3_MERGE_COUNT 16 + +/* +** This is the maximum amount of data (in bytes) to store in the +** Fts3Table.pendingTerms hash table. Normally, the hash table is +** populated as documents are inserted/updated/deleted in a transaction +** and used to create a new segment when the transaction is committed. +** However if this limit is reached midway through a transaction, a new +** segment is created and the hash table cleared immediately. +*/ +#define FTS3_MAX_PENDING_DATA (1*1024*1024) + +/* +** Macro to return the number of elements in an array. SQLite has a +** similar macro called ArraySize(). Use a different name to avoid +** a collision when building an amalgamation with built-in FTS3. +*/ +#define SizeofArray(X) ((int)(sizeof(X)/sizeof(X[0]))) + + +#ifndef MIN +# define MIN(x,y) ((x)<(y)?(x):(y)) +#endif +#ifndef MAX +# define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +/* +** Maximum length of a varint encoded integer. The varint format is different +** from that used by SQLite, so the maximum length is 10, not 9. +*/ +#define FTS3_VARINT_MAX 10 + +/* +** FTS4 virtual tables may maintain multiple indexes - one index of all terms +** in the document set and zero or more prefix indexes. All indexes are stored +** as one or more b+-trees in the %_segments and %_segdir tables. +** +** It is possible to determine which index a b+-tree belongs to based on the +** value stored in the "%_segdir.level" column. Given this value L, the index +** that the b+-tree belongs to is (L<<10). In other words, all b+-trees with +** level values between 0 and 1023 (inclusive) belong to index 0, all levels +** between 1024 and 2047 to index 1, and so on. +** +** It is considered impossible for an index to use more than 1024 levels. In +** theory though this may happen, but only after at least +** (FTS3_MERGE_COUNT^1024) separate flushes of the pending-terms tables. +*/ +#define FTS3_SEGDIR_MAXLEVEL 1024 +#define FTS3_SEGDIR_MAXLEVEL_STR "1024" + +/* +** The testcase() macro is only used by the amalgamation. If undefined, +** make it a no-op. +*/ +#ifndef testcase +# define testcase(X) +#endif + +/* +** Terminator values for position-lists and column-lists. +*/ +#define POS_COLUMN (1) /* Column-list terminator */ +#define POS_END (0) /* Position-list terminator */ + +/* +** This section provides definitions to allow the +** FTS3 extension to be compiled outside of the +** amalgamation. +*/ +#ifndef SQLITE_AMALGAMATION +/* +** Macros indicating that conditional expressions are always true or +** false. +*/ +#ifdef SQLITE_COVERAGE_TEST +# define ALWAYS(x) (1) +# define NEVER(X) (0) +#elif defined(SQLITE_DEBUG) +# define ALWAYS(x) sqlite3Fts3Always((x)!=0) +# define NEVER(x) sqlite3Fts3Never((x)!=0) +SQLITE_PRIVATE int sqlite3Fts3Always(int b); +SQLITE_PRIVATE int sqlite3Fts3Never(int b); +#else +# define ALWAYS(x) (x) +# define NEVER(x) (x) +#endif + +/* +** Internal types used by SQLite. +*/ +typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */ +typedef short int i16; /* 2-byte (or larger) signed integer */ +typedef unsigned int u32; /* 4-byte unsigned integer */ +typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */ +typedef sqlite3_int64 i64; /* 8-byte signed integer */ + +/* +** Macro used to suppress compiler warnings for unused parameters. +*/ +#define UNUSED_PARAMETER(x) (void)(x) + +/* +** Activate assert() only if SQLITE_TEST is enabled. +*/ +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif + +/* +** The TESTONLY macro is used to enclose variable declarations or +** other bits of code that are needed to support the arguments +** within testcase() and assert() macros. +*/ +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) +# define TESTONLY(X) X +#else +# define TESTONLY(X) +#endif + +#endif /* SQLITE_AMALGAMATION */ + +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3Fts3Corrupt(void); +# define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() +#else +# define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB +#endif + +typedef struct Fts3Table Fts3Table; +typedef struct Fts3Cursor Fts3Cursor; +typedef struct Fts3Expr Fts3Expr; +typedef struct Fts3Phrase Fts3Phrase; +typedef struct Fts3PhraseToken Fts3PhraseToken; + +typedef struct Fts3Doclist Fts3Doclist; +typedef struct Fts3SegFilter Fts3SegFilter; +typedef struct Fts3DeferredToken Fts3DeferredToken; +typedef struct Fts3SegReader Fts3SegReader; +typedef struct Fts3MultiSegReader Fts3MultiSegReader; + +typedef struct MatchinfoBuffer MatchinfoBuffer; + +/* +** A connection to a fulltext index is an instance of the following +** structure. The xCreate and xConnect methods create an instance +** of this structure and xDestroy and xDisconnect free that instance. +** All other methods receive a pointer to the structure as one of their +** arguments. +*/ +struct Fts3Table { + sqlite3_vtab base; /* Base class used by SQLite core */ + sqlite3 *db; /* The database connection */ + const char *zDb; /* logical database name */ + const char *zName; /* virtual table name */ + int nColumn; /* number of named columns in virtual table */ + char **azColumn; /* column names. malloced */ + u8 *abNotindexed; /* True for 'notindexed' columns */ + sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ + char *zContentTbl; /* content=xxx option, or NULL */ + char *zLanguageid; /* languageid=xxx option, or NULL */ + int nAutoincrmerge; /* Value configured by 'automerge' */ + u32 nLeafAdd; /* Number of leaf blocks added this trans */ + + /* Precompiled statements used by the implementation. Each of these + ** statements is run and reset within a single virtual table API call. + */ + sqlite3_stmt *aStmt[40]; + sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */ + + char *zReadExprlist; + char *zWriteExprlist; + + int nNodeSize; /* Soft limit for node size */ + u8 bFts4; /* True for FTS4, false for FTS3 */ + u8 bHasStat; /* True if %_stat table exists (2==unknown) */ + u8 bHasDocsize; /* True if %_docsize table exists */ + u8 bDescIdx; /* True if doclists are in reverse order */ + u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ + int nPgsz; /* Page size for host database */ + char *zSegmentsTbl; /* Name of %_segments table */ + sqlite3_blob *pSegments; /* Blob handle open on %_segments table */ + + /* + ** The following array of hash tables is used to buffer pending index + ** updates during transactions. All pending updates buffered at any one + ** time must share a common language-id (see the FTS4 langid= feature). + ** The current language id is stored in variable iPrevLangid. + ** + ** A single FTS4 table may have multiple full-text indexes. For each index + ** there is an entry in the aIndex[] array. Index 0 is an index of all the + ** terms that appear in the document set. Each subsequent index in aIndex[] + ** is an index of prefixes of a specific length. + ** + ** Variable nPendingData contains an estimate the memory consumed by the + ** pending data structures, including hash table overhead, but not including + ** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash + ** tables are flushed to disk. Variable iPrevDocid is the docid of the most + ** recently inserted record. + */ + int nIndex; /* Size of aIndex[] */ + struct Fts3Index { + int nPrefix; /* Prefix length (0 for main terms index) */ + Fts3Hash hPending; /* Pending terms table for this index */ + } *aIndex; + int nMaxPendingData; /* Max pending data before flush to disk */ + int nPendingData; /* Current bytes of pending data */ + sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ + int iPrevLangid; /* Langid of recently inserted document */ + int bPrevDelete; /* True if last operation was a delete */ + +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) + /* State variables used for validating that the transaction control + ** methods of the virtual table are called at appropriate times. These + ** values do not contribute to FTS functionality; they are used for + ** verifying the operation of the SQLite core. + */ + int inTransaction; /* True after xBegin but before xCommit/xRollback */ + int mxSavepoint; /* Largest valid xSavepoint integer */ +#endif + +#ifdef SQLITE_TEST + /* True to disable the incremental doclist optimization. This is controled + ** by special insert command 'test-no-incr-doclist'. */ + int bNoIncrDoclist; +#endif +}; + +/* +** When the core wants to read from the virtual table, it creates a +** virtual table cursor (an instance of the following structure) using +** the xOpen method. Cursors are destroyed using the xClose method. +*/ +struct Fts3Cursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + i16 eSearch; /* Search strategy (see below) */ + u8 isEof; /* True if at End Of Results */ + u8 isRequireSeek; /* True if must seek pStmt to %_content row */ + u8 bSeekStmt; /* True if pStmt is a seek */ + sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */ + Fts3Expr *pExpr; /* Parsed MATCH query string */ + int iLangid; /* Language being queried for */ + int nPhrase; /* Number of matchable phrases in query */ + Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */ + sqlite3_int64 iPrevId; /* Previous id read from aDoclist */ + char *pNextId; /* Pointer into the body of aDoclist */ + char *aDoclist; /* List of docids for full-text queries */ + int nDoclist; /* Size of buffer at aDoclist */ + u8 bDesc; /* True to sort in descending order */ + int eEvalmode; /* An FTS3_EVAL_XX constant */ + int nRowAvg; /* Average size of database rows, in pages */ + sqlite3_int64 nDoc; /* Documents in table */ + i64 iMinDocid; /* Minimum docid to return */ + i64 iMaxDocid; /* Maximum docid to return */ + int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ + MatchinfoBuffer *pMIBuffer; /* Buffer for matchinfo data */ +}; + +#define FTS3_EVAL_FILTER 0 +#define FTS3_EVAL_NEXT 1 +#define FTS3_EVAL_MATCHINFO 2 + +/* +** The Fts3Cursor.eSearch member is always set to one of the following. +** Actualy, Fts3Cursor.eSearch can be greater than or equal to +** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index +** of the column to be searched. For example, in +** +** CREATE VIRTUAL TABLE ex1 USING fts3(a,b,c,d); +** SELECT docid FROM ex1 WHERE b MATCH 'one two three'; +** +** Because the LHS of the MATCH operator is 2nd column "b", +** Fts3Cursor.eSearch will be set to FTS3_FULLTEXT_SEARCH+1. (+0 for a, +** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1" +** indicating that all columns should be searched, +** then eSearch would be set to FTS3_FULLTEXT_SEARCH+4. +*/ +#define FTS3_FULLSCAN_SEARCH 0 /* Linear scan of %_content table */ +#define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */ +#define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */ + +/* +** The lower 16-bits of the sqlite3_index_info.idxNum value set by +** the xBestIndex() method contains the Fts3Cursor.eSearch value described +** above. The upper 16-bits contain a combination of the following +** bits, used to describe extra constraints on full-text searches. +*/ +#define FTS3_HAVE_LANGID 0x00010000 /* languageid=? */ +#define FTS3_HAVE_DOCID_GE 0x00020000 /* docid>=? */ +#define FTS3_HAVE_DOCID_LE 0x00040000 /* docid<=? */ + +struct Fts3Doclist { + char *aAll; /* Array containing doclist (or NULL) */ + int nAll; /* Size of a[] in bytes */ + char *pNextDocid; /* Pointer to next docid */ + + sqlite3_int64 iDocid; /* Current docid (if pList!=0) */ + int bFreeList; /* True if pList should be sqlite3_free()d */ + char *pList; /* Pointer to position list following iDocid */ + int nList; /* Length of position list */ +}; + +/* +** A "phrase" is a sequence of one or more tokens that must match in +** sequence. A single token is the base case and the most common case. +** For a sequence of tokens contained in double-quotes (i.e. "one two three") +** nToken will be the number of tokens in the string. +*/ +struct Fts3PhraseToken { + char *z; /* Text of the token */ + int n; /* Number of bytes in buffer z */ + int isPrefix; /* True if token ends with a "*" character */ + int bFirst; /* True if token must appear at position 0 */ + + /* Variables above this point are populated when the expression is + ** parsed (by code in fts3_expr.c). Below this point the variables are + ** used when evaluating the expression. */ + Fts3DeferredToken *pDeferred; /* Deferred token object for this token */ + Fts3MultiSegReader *pSegcsr; /* Segment-reader for this token */ +}; + +struct Fts3Phrase { + /* Cache of doclist for this phrase. */ + Fts3Doclist doclist; + int bIncr; /* True if doclist is loaded incrementally */ + int iDoclistToken; + + /* Used by sqlite3Fts3EvalPhrasePoslist() if this is a descendent of an + ** OR condition. */ + char *pOrPoslist; + i64 iOrDocid; + + /* Variables below this point are populated by fts3_expr.c when parsing + ** a MATCH expression. Everything above is part of the evaluation phase. + */ + int nToken; /* Number of tokens in the phrase */ + int iColumn; /* Index of column this phrase must match */ + Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */ +}; + +/* +** A tree of these objects forms the RHS of a MATCH operator. +** +** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist +** points to a malloced buffer, size nDoclist bytes, containing the results +** of this phrase query in FTS3 doclist format. As usual, the initial +** "Length" field found in doclists stored on disk is omitted from this +** buffer. +** +** Variable aMI is used only for FTSQUERY_NEAR nodes to store the global +** matchinfo data. If it is not NULL, it points to an array of size nCol*3, +** where nCol is the number of columns in the queried FTS table. The array +** is populated as follows: +** +** aMI[iCol*3 + 0] = Undefined +** aMI[iCol*3 + 1] = Number of occurrences +** aMI[iCol*3 + 2] = Number of rows containing at least one instance +** +** The aMI array is allocated using sqlite3_malloc(). It should be freed +** when the expression node is. +*/ +struct Fts3Expr { + int eType; /* One of the FTSQUERY_XXX values defined below */ + int nNear; /* Valid if eType==FTSQUERY_NEAR */ + Fts3Expr *pParent; /* pParent->pLeft==this or pParent->pRight==this */ + Fts3Expr *pLeft; /* Left operand */ + Fts3Expr *pRight; /* Right operand */ + Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */ + + /* The following are used by the fts3_eval.c module. */ + sqlite3_int64 iDocid; /* Current docid */ + u8 bEof; /* True this expression is at EOF already */ + u8 bStart; /* True if iDocid is valid */ + u8 bDeferred; /* True if this expression is entirely deferred */ + + /* The following are used by the fts3_snippet.c module. */ + int iPhrase; /* Index of this phrase in matchinfo() results */ + u32 *aMI; /* See above */ +}; + +/* +** Candidate values for Fts3Query.eType. Note that the order of the first +** four values is in order of precedence when parsing expressions. For +** example, the following: +** +** "a OR b AND c NOT d NEAR e" +** +** is equivalent to: +** +** "a OR (b AND (c NOT (d NEAR e)))" +*/ +#define FTSQUERY_NEAR 1 +#define FTSQUERY_NOT 2 +#define FTSQUERY_AND 3 +#define FTSQUERY_OR 4 +#define FTSQUERY_PHRASE 5 + + +/* fts3_write.c */ +SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); +SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *); +SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *); +SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *); +SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64, + sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**); +SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( + Fts3Table*,int,const char*,int,int,Fts3SegReader**); +SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *); +SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, int, sqlite3_stmt **); +SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*); + +SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **); +SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **); + +#ifndef SQLITE_DISABLE_FTS4_DEFERRED +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *); +SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int); +SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *); +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *); +SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *); +#else +# define sqlite3Fts3FreeDeferredTokens(x) +# define sqlite3Fts3DeferToken(x,y,z) SQLITE_OK +# define sqlite3Fts3CacheDeferredDoclists(x) SQLITE_OK +# define sqlite3Fts3FreeDeferredDoclists(x) +# define sqlite3Fts3DeferredTokenList(x,y,z) SQLITE_OK +#endif + +SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *); +SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *, int *); + +/* Special values interpreted by sqlite3SegReaderCursor() */ +#define FTS3_SEGCURSOR_PENDING -1 +#define FTS3_SEGCURSOR_ALL -2 + +SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Fts3SegFilter*); +SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *); +SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *); + +SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *, + int, int, int, const char *, int, int, int, Fts3MultiSegReader *); + +/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */ +#define FTS3_SEGMENT_REQUIRE_POS 0x00000001 +#define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002 +#define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 +#define FTS3_SEGMENT_PREFIX 0x00000008 +#define FTS3_SEGMENT_SCAN 0x00000010 +#define FTS3_SEGMENT_FIRST 0x00000020 + +/* Type passed as 4th argument to SegmentReaderIterate() */ +struct Fts3SegFilter { + const char *zTerm; + int nTerm; + int iCol; + int flags; +}; + +struct Fts3MultiSegReader { + /* Used internally by sqlite3Fts3SegReaderXXX() calls */ + Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */ + int nSegment; /* Size of apSegment array */ + int nAdvance; /* How many seg-readers to advance */ + Fts3SegFilter *pFilter; /* Pointer to filter object */ + char *aBuffer; /* Buffer to merge doclists in */ + int nBuffer; /* Allocated size of aBuffer[] in bytes */ + + int iColFilter; /* If >=0, filter for this column */ + int bRestart; + + /* Used by fts3.c only. */ + int nCost; /* Cost of running iterator */ + int bLookup; /* True if a lookup of a single entry. */ + + /* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */ + char *zTerm; /* Pointer to term buffer */ + int nTerm; /* Size of zTerm in bytes */ + char *aDoclist; /* Pointer to doclist buffer */ + int nDoclist; /* Size of aDoclist[] in bytes */ +}; + +SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int); + +#define fts3GetVarint32(p, piVal) ( \ + (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ +) + +/* fts3.c */ +SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...); +SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64); +SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); +SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); +SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); +SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); +SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); +SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); +SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); +SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*); +SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc); + +/* fts3_tokenizer.c */ +SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *); +SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); +SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, + sqlite3_tokenizer **, char ** +); +SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char); + +/* fts3_snippet.c */ +SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*); +SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, + const char *, const char *, int, int +); +SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); +SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p); + +/* fts3_expr.c */ +SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, + char **, int, int, int, const char *, int, Fts3Expr **, char ** +); +SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); +#ifdef SQLITE_TEST +SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); +SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); +#endif + +SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, + sqlite3_tokenizer_cursor ** +); + +/* fts3_aux.c */ +SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); + +SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); + +SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( + Fts3Table*, Fts3MultiSegReader*, int, const char*, int); +SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( + Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); +SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); +SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); +SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); + +/* fts3_tokenize_vtab.c */ +SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); + +/* fts3_unicode2.c (functions generated by parsing unicode text files) */ +#ifndef SQLITE_DISABLE_FTS3_UNICODE +SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int); +SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); +SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); +#endif + +#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ +#endif /* _FTSINT_H */ + +/************** End of fts3Int.h *********************************************/ +/************** Continuing where we left off in fts3.c ***********************/ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +#if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE) +# define SQLITE_CORE 1 +#endif + +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +/* #include "fts3.h" */ +#ifndef SQLITE_CORE +/* # include "sqlite3ext.h" */ + SQLITE_EXTENSION_INIT1 +#endif + +static int fts3EvalNext(Fts3Cursor *pCsr); +static int fts3EvalStart(Fts3Cursor *pCsr); +static int fts3TermSegReaderCursor( + Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); + +#ifndef SQLITE_AMALGAMATION +# if defined(SQLITE_DEBUG) +SQLITE_PRIVATE int sqlite3Fts3Always(int b) { assert( b ); return b; } +SQLITE_PRIVATE int sqlite3Fts3Never(int b) { assert( !b ); return b; } +# endif +#endif + +/* +** Write a 64-bit variable-length integer to memory starting at p[0]. +** The length of data written will be between 1 and FTS3_VARINT_MAX bytes. +** The number of bytes written is returned. +*/ +SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){ + unsigned char *q = (unsigned char *) p; + sqlite_uint64 vu = v; + do{ + *q++ = (unsigned char) ((vu & 0x7f) | 0x80); + vu >>= 7; + }while( vu!=0 ); + q[-1] &= 0x7f; /* turn off high bit in final byte */ + assert( q - (unsigned char *)p <= FTS3_VARINT_MAX ); + return (int) (q - (unsigned char *)p); +} + +#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \ + v = (v & mask1) | ( (*ptr++) << shift ); \ + if( (v & mask2)==0 ){ var = v; return ret; } +#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \ + v = (*ptr++); \ + if( (v & mask2)==0 ){ var = v; return ret; } + +/* +** Read a 64-bit variable-length integer from memory starting at p[0]. +** Return the number of bytes read, or 0 on error. +** The value is stored in *v. +*/ +SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){ + const unsigned char *p = (const unsigned char*)pBuf; + const unsigned char *pStart = p; + u32 a; + u64 b; + int shift; + + GETVARINT_INIT(a, p, 0, 0x00, 0x80, *v, 1); + GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *v, 2); + GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *v, 3); + GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4); + b = (a & 0x0FFFFFFF ); + + for(shift=28; shift<=63; shift+=7){ + u64 c = *p++; + b += (c&0x7F) << shift; + if( (c & 0x80)==0 ) break; + } + *v = b; + return (int)(p - pStart); +} + +/* +** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to +** a non-negative 32-bit integer before it is returned. +*/ +SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){ + u32 a; + +#ifndef fts3GetVarint32 + GETVARINT_INIT(a, p, 0, 0x00, 0x80, *pi, 1); +#else + a = (*p++); + assert( a & 0x80 ); +#endif + + GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *pi, 2); + GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *pi, 3); + GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4); + a = (a & 0x0FFFFFFF ); + *pi = (int)(a | ((u32)(*p & 0x07) << 28)); + assert( 0==(a & 0x80000000) ); + assert( *pi>=0 ); + return 5; +} + +/* +** Return the number of bytes required to encode v as a varint +*/ +SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64 v){ + int i = 0; + do{ + i++; + v >>= 7; + }while( v!=0 ); + return i; +} + +/* +** Convert an SQL-style quoted string into a normal string by removing +** the quote characters. The conversion is done in-place. If the +** input does not begin with a quote character, then this routine +** is a no-op. +** +** Examples: +** +** "abc" becomes abc +** 'xyz' becomes xyz +** [pqr] becomes pqr +** `mno` becomes mno +** +*/ +SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){ + char quote; /* Quote character (if any ) */ + + quote = z[0]; + if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ + int iIn = 1; /* Index of next byte to read from input */ + int iOut = 0; /* Index of next byte to write to output */ + + /* If the first byte was a '[', then the close-quote character is a ']' */ + if( quote=='[' ) quote = ']'; + + while( z[iIn] ){ + if( z[iIn]==quote ){ + if( z[iIn+1]!=quote ) break; + z[iOut++] = quote; + iIn += 2; + }else{ + z[iOut++] = z[iIn++]; + } + } + z[iOut] = '\0'; + } +} + +/* +** Read a single varint from the doclist at *pp and advance *pp to point +** to the first byte past the end of the varint. Add the value of the varint +** to *pVal. +*/ +static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ + sqlite3_int64 iVal; + *pp += sqlite3Fts3GetVarint(*pp, &iVal); + *pVal += iVal; +} + +/* +** When this function is called, *pp points to the first byte following a +** varint that is part of a doclist (or position-list, or any other list +** of varints). This function moves *pp to point to the start of that varint, +** and sets *pVal by the varint value. +** +** Argument pStart points to the first byte of the doclist that the +** varint is part of. +*/ +static void fts3GetReverseVarint( + char **pp, + char *pStart, + sqlite3_int64 *pVal +){ + sqlite3_int64 iVal; + char *p; + + /* Pointer p now points at the first byte past the varint we are + ** interested in. So, unless the doclist is corrupt, the 0x80 bit is + ** clear on character p[-1]. */ + for(p = (*pp)-2; p>=pStart && *p&0x80; p--); + p++; + *pp = p; + + sqlite3Fts3GetVarint(p, &iVal); + *pVal = iVal; +} + +/* +** The xDisconnect() virtual table method. +*/ +static int fts3DisconnectMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table *)pVtab; + int i; + + assert( p->nPendingData==0 ); + assert( p->pSegments==0 ); + + /* Free any prepared statements held */ + sqlite3_finalize(p->pSeekStmt); + for(i=0; iaStmt); i++){ + sqlite3_finalize(p->aStmt[i]); + } + sqlite3_free(p->zSegmentsTbl); + sqlite3_free(p->zReadExprlist); + sqlite3_free(p->zWriteExprlist); + sqlite3_free(p->zContentTbl); + sqlite3_free(p->zLanguageid); + + /* Invoke the tokenizer destructor to free the tokenizer. */ + p->pTokenizer->pModule->xDestroy(p->pTokenizer); + + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Write an error message into *pzErr +*/ +SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char **pzErr, const char *zFormat, ...){ + va_list ap; + sqlite3_free(*pzErr); + va_start(ap, zFormat); + *pzErr = sqlite3_vmprintf(zFormat, ap); + va_end(ap); +} + +/* +** Construct one or more SQL statements from the format string given +** and then evaluate those statements. The success code is written +** into *pRc. +** +** If *pRc is initially non-zero then this routine is a no-op. +*/ +static void fts3DbExec( + int *pRc, /* Success code */ + sqlite3 *db, /* Database in which to run SQL */ + const char *zFormat, /* Format string for SQL */ + ... /* Arguments to the format string */ +){ + va_list ap; + char *zSql; + if( *pRc ) return; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( zSql==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + *pRc = sqlite3_exec(db, zSql, 0, 0, 0); + sqlite3_free(zSql); + } +} + +/* +** The xDestroy() virtual table method. +*/ +static int fts3DestroyMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table *)pVtab; + int rc = SQLITE_OK; /* Return code */ + const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ + sqlite3 *db = p->db; /* Database handle */ + + /* Drop the shadow tables */ + if( p->zContentTbl==0 ){ + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName); + } + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName); + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName); + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName); + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName); + + /* If everything has worked, invoke fts3DisconnectMethod() to free the + ** memory associated with the Fts3Table structure and return SQLITE_OK. + ** Otherwise, return an SQLite error code. + */ + return (rc==SQLITE_OK ? fts3DisconnectMethod(pVtab) : rc); +} + + +/* +** Invoke sqlite3_declare_vtab() to declare the schema for the FTS3 table +** passed as the first argument. This is done as part of the xConnect() +** and xCreate() methods. +** +** If *pRc is non-zero when this function is called, it is a no-op. +** Otherwise, if an error occurs, an SQLite error code is stored in *pRc +** before returning. +*/ +static void fts3DeclareVtab(int *pRc, Fts3Table *p){ + if( *pRc==SQLITE_OK ){ + int i; /* Iterator variable */ + int rc; /* Return code */ + char *zSql; /* SQL statement passed to declare_vtab() */ + char *zCols; /* List of user defined columns */ + const char *zLanguageid; + + zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid"); + sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + + /* Create a list of user columns for the virtual table */ + zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); + for(i=1; zCols && inColumn; i++){ + zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]); + } + + /* Create the whole "CREATE TABLE" statement to pass to SQLite */ + zSql = sqlite3_mprintf( + "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)", + zCols, p->zName, zLanguageid + ); + if( !zCols || !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_declare_vtab(p->db, zSql); + } + + sqlite3_free(zSql); + sqlite3_free(zCols); + *pRc = rc; + } +} + +/* +** Create the %_stat table if it does not already exist. +*/ +SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){ + fts3DbExec(pRc, p->db, + "CREATE TABLE IF NOT EXISTS %Q.'%q_stat'" + "(id INTEGER PRIMARY KEY, value BLOB);", + p->zDb, p->zName + ); + if( (*pRc)==SQLITE_OK ) p->bHasStat = 1; +} + +/* +** Create the backing store tables (%_content, %_segments and %_segdir) +** required by the FTS3 table passed as the only argument. This is done +** as part of the vtab xCreate() method. +** +** If the p->bHasDocsize boolean is true (indicating that this is an +** FTS4 table, not an FTS3 table) then also create the %_docsize and +** %_stat tables required by FTS4. +*/ +static int fts3CreateTables(Fts3Table *p){ + int rc = SQLITE_OK; /* Return code */ + int i; /* Iterator variable */ + sqlite3 *db = p->db; /* The database connection */ + + if( p->zContentTbl==0 ){ + const char *zLanguageid = p->zLanguageid; + char *zContentCols; /* Columns of %_content table */ + + /* Create a list of user columns for the content table */ + zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); + for(i=0; zContentCols && inColumn; i++){ + char *z = p->azColumn[i]; + zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); + } + if( zLanguageid && zContentCols ){ + zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid); + } + if( zContentCols==0 ) rc = SQLITE_NOMEM; + + /* Create the content table */ + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_content'(%s)", + p->zDb, p->zName, zContentCols + ); + sqlite3_free(zContentCols); + } + + /* Create other tables */ + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", + p->zDb, p->zName + ); + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_segdir'(" + "level INTEGER," + "idx INTEGER," + "start_block INTEGER," + "leaves_end_block INTEGER," + "end_block INTEGER," + "root BLOB," + "PRIMARY KEY(level, idx)" + ");", + p->zDb, p->zName + ); + if( p->bHasDocsize ){ + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);", + p->zDb, p->zName + ); + } + assert( p->bHasStat==p->bFts4 ); + if( p->bHasStat ){ + sqlite3Fts3CreateStatTable(&rc, p); + } + return rc; +} + +/* +** Store the current database page-size in bytes in p->nPgsz. +** +** If *pRc is non-zero when this function is called, it is a no-op. +** Otherwise, if an error occurs, an SQLite error code is stored in *pRc +** before returning. +*/ +static void fts3DatabasePageSize(int *pRc, Fts3Table *p){ + if( *pRc==SQLITE_OK ){ + int rc; /* Return code */ + char *zSql; /* SQL text "PRAGMA %Q.page_size" */ + sqlite3_stmt *pStmt; /* Compiled "PRAGMA %Q.page_size" statement */ + + zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_step(pStmt); + p->nPgsz = sqlite3_column_int(pStmt, 0); + rc = sqlite3_finalize(pStmt); + }else if( rc==SQLITE_AUTH ){ + p->nPgsz = 1024; + rc = SQLITE_OK; + } + } + assert( p->nPgsz>0 || rc!=SQLITE_OK ); + sqlite3_free(zSql); + *pRc = rc; + } +} + +/* +** "Special" FTS4 arguments are column specifications of the following form: +** +** = +** +** There may not be whitespace surrounding the "=" character. The +** term may be quoted, but the may not. +*/ +static int fts3IsSpecialColumn( + const char *z, + int *pnKey, + char **pzValue +){ + char *zValue; + const char *zCsr = z; + + while( *zCsr!='=' ){ + if( *zCsr=='\0' ) return 0; + zCsr++; + } + + *pnKey = (int)(zCsr-z); + zValue = sqlite3_mprintf("%s", &zCsr[1]); + if( zValue ){ + sqlite3Fts3Dequote(zValue); + } + *pzValue = zValue; + return 1; +} + +/* +** Append the output of a printf() style formatting to an existing string. +*/ +static void fts3Appendf( + int *pRc, /* IN/OUT: Error code */ + char **pz, /* IN/OUT: Pointer to string buffer */ + const char *zFormat, /* Printf format string to append */ + ... /* Arguments for printf format string */ +){ + if( *pRc==SQLITE_OK ){ + va_list ap; + char *z; + va_start(ap, zFormat); + z = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( z && *pz ){ + char *z2 = sqlite3_mprintf("%s%s", *pz, z); + sqlite3_free(z); + z = z2; + } + if( z==0 ) *pRc = SQLITE_NOMEM; + sqlite3_free(*pz); + *pz = z; + } +} + +/* +** Return a copy of input string zInput enclosed in double-quotes (") and +** with all double quote characters escaped. For example: +** +** fts3QuoteId("un \"zip\"") -> "un \"\"zip\"\"" +** +** The pointer returned points to memory obtained from sqlite3_malloc(). It +** is the callers responsibility to call sqlite3_free() to release this +** memory. +*/ +static char *fts3QuoteId(char const *zInput){ + int nRet; + char *zRet; + nRet = 2 + (int)strlen(zInput)*2 + 1; + zRet = sqlite3_malloc(nRet); + if( zRet ){ + int i; + char *z = zRet; + *(z++) = '"'; + for(i=0; zInput[i]; i++){ + if( zInput[i]=='"' ) *(z++) = '"'; + *(z++) = zInput[i]; + } + *(z++) = '"'; + *(z++) = '\0'; + } + return zRet; +} + +/* +** Return a list of comma separated SQL expressions and a FROM clause that +** could be used in a SELECT statement such as the following: +** +** SELECT FROM %_content AS x ... +** +** to return the docid, followed by each column of text data in order +** from left to write. If parameter zFunc is not NULL, then instead of +** being returned directly each column of text data is passed to an SQL +** function named zFunc first. For example, if zFunc is "unzip" and the +** table has the three user-defined columns "a", "b", and "c", the following +** string is returned: +** +** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x" +** +** The pointer returned points to a buffer allocated by sqlite3_malloc(). It +** is the responsibility of the caller to eventually free it. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and +** a NULL pointer is returned). Otherwise, if an OOM error is encountered +** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If +** no error occurs, *pRc is left unmodified. +*/ +static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){ + char *zRet = 0; + char *zFree = 0; + char *zFunction; + int i; + + if( p->zContentTbl==0 ){ + if( !zFunc ){ + zFunction = ""; + }else{ + zFree = zFunction = fts3QuoteId(zFunc); + } + fts3Appendf(pRc, &zRet, "docid"); + for(i=0; inColumn; i++){ + fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); + } + if( p->zLanguageid ){ + fts3Appendf(pRc, &zRet, ", x.%Q", "langid"); + } + sqlite3_free(zFree); + }else{ + fts3Appendf(pRc, &zRet, "rowid"); + for(i=0; inColumn; i++){ + fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]); + } + if( p->zLanguageid ){ + fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid); + } + } + fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x", + p->zDb, + (p->zContentTbl ? p->zContentTbl : p->zName), + (p->zContentTbl ? "" : "_content") + ); + return zRet; +} + +/* +** Return a list of N comma separated question marks, where N is the number +** of columns in the %_content table (one for the docid plus one for each +** user-defined text column). +** +** If argument zFunc is not NULL, then all but the first question mark +** is preceded by zFunc and an open bracket, and followed by a closed +** bracket. For example, if zFunc is "zip" and the FTS3 table has three +** user-defined text columns, the following string is returned: +** +** "?, zip(?), zip(?), zip(?)" +** +** The pointer returned points to a buffer allocated by sqlite3_malloc(). It +** is the responsibility of the caller to eventually free it. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and +** a NULL pointer is returned). Otherwise, if an OOM error is encountered +** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If +** no error occurs, *pRc is left unmodified. +*/ +static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){ + char *zRet = 0; + char *zFree = 0; + char *zFunction; + int i; + + if( !zFunc ){ + zFunction = ""; + }else{ + zFree = zFunction = fts3QuoteId(zFunc); + } + fts3Appendf(pRc, &zRet, "?"); + for(i=0; inColumn; i++){ + fts3Appendf(pRc, &zRet, ",%s(?)", zFunction); + } + if( p->zLanguageid ){ + fts3Appendf(pRc, &zRet, ", ?"); + } + sqlite3_free(zFree); + return zRet; +} + +/* +** This function interprets the string at (*pp) as a non-negative integer +** value. It reads the integer and sets *pnOut to the value read, then +** sets *pp to point to the byte immediately following the last byte of +** the integer value. +** +** Only decimal digits ('0'..'9') may be part of an integer value. +** +** If *pp does not being with a decimal digit SQLITE_ERROR is returned and +** the output value undefined. Otherwise SQLITE_OK is returned. +** +** This function is used when parsing the "prefix=" FTS4 parameter. +*/ +static int fts3GobbleInt(const char **pp, int *pnOut){ + const int MAX_NPREFIX = 10000000; + const char *p; /* Iterator pointer */ + int nInt = 0; /* Output value */ + + for(p=*pp; p[0]>='0' && p[0]<='9'; p++){ + nInt = nInt * 10 + (p[0] - '0'); + if( nInt>MAX_NPREFIX ){ + nInt = 0; + break; + } + } + if( p==*pp ) return SQLITE_ERROR; + *pnOut = nInt; + *pp = p; + return SQLITE_OK; +} + +/* +** This function is called to allocate an array of Fts3Index structures +** representing the indexes maintained by the current FTS table. FTS tables +** always maintain the main "terms" index, but may also maintain one or +** more "prefix" indexes, depending on the value of the "prefix=" parameter +** (if any) specified as part of the CREATE VIRTUAL TABLE statement. +** +** Argument zParam is passed the value of the "prefix=" option if one was +** specified, or NULL otherwise. +** +** If no error occurs, SQLITE_OK is returned and *apIndex set to point to +** the allocated array. *pnIndex is set to the number of elements in the +** array. If an error does occur, an SQLite error code is returned. +** +** Regardless of whether or not an error is returned, it is the responsibility +** of the caller to call sqlite3_free() on the output array to free it. +*/ +static int fts3PrefixParameter( + const char *zParam, /* ABC in prefix=ABC parameter to parse */ + int *pnIndex, /* OUT: size of *apIndex[] array */ + struct Fts3Index **apIndex /* OUT: Array of indexes for this table */ +){ + struct Fts3Index *aIndex; /* Allocated array */ + int nIndex = 1; /* Number of entries in array */ + + if( zParam && zParam[0] ){ + const char *p; + nIndex++; + for(p=zParam; *p; p++){ + if( *p==',' ) nIndex++; + } + } + + aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex); + *apIndex = aIndex; + if( !aIndex ){ + return SQLITE_NOMEM; + } + + memset(aIndex, 0, sizeof(struct Fts3Index) * nIndex); + if( zParam ){ + const char *p = zParam; + int i; + for(i=1; i=0 ); + if( nPrefix==0 ){ + nIndex--; + i--; + }else{ + aIndex[i].nPrefix = nPrefix; + } + p++; + } + } + + *pnIndex = nIndex; + return SQLITE_OK; +} + +/* +** This function is called when initializing an FTS4 table that uses the +** content=xxx option. It determines the number of and names of the columns +** of the new FTS4 table. +** +** The third argument passed to this function is the value passed to the +** config=xxx option (i.e. "xxx"). This function queries the database for +** a table of that name. If found, the output variables are populated +** as follows: +** +** *pnCol: Set to the number of columns table xxx has, +** +** *pnStr: Set to the total amount of space required to store a copy +** of each columns name, including the nul-terminator. +** +** *pazCol: Set to point to an array of *pnCol strings. Each string is +** the name of the corresponding column in table xxx. The array +** and its contents are allocated using a single allocation. It +** is the responsibility of the caller to free this allocation +** by eventually passing the *pazCol value to sqlite3_free(). +** +** If the table cannot be found, an error code is returned and the output +** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is +** returned (and the output variables are undefined). +*/ +static int fts3ContentColumns( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */ + const char *zTbl, /* Name of content table */ + const char ***pazCol, /* OUT: Malloc'd array of column names */ + int *pnCol, /* OUT: Size of array *pazCol */ + int *pnStr, /* OUT: Bytes of string content */ + char **pzErr /* OUT: error message */ +){ + int rc = SQLITE_OK; /* Return code */ + char *zSql; /* "SELECT *" statement on zTbl */ + sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */ + + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db)); + } + } + sqlite3_free(zSql); + + if( rc==SQLITE_OK ){ + const char **azCol; /* Output array */ + int nStr = 0; /* Size of all column names (incl. 0x00) */ + int nCol; /* Number of table columns */ + int i; /* Used to iterate through columns */ + + /* Loop through the returned columns. Set nStr to the number of bytes of + ** space required to store a copy of each column name, including the + ** nul-terminator byte. */ + nCol = sqlite3_column_count(pStmt); + for(i=0; i module name ("fts3" or "fts4") +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> "column name" and other module argument fields. +*/ +static int fts3InitVtab( + int isCreate, /* True for xCreate, false for xConnect */ + sqlite3 *db, /* The SQLite database connection */ + void *pAux, /* Hash table containing tokenizers */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ + char **pzErr /* Write any error message here */ +){ + Fts3Hash *pHash = (Fts3Hash *)pAux; + Fts3Table *p = 0; /* Pointer to allocated vtab */ + int rc = SQLITE_OK; /* Return code */ + int i; /* Iterator variable */ + int nByte; /* Size of allocation used for *p */ + int iCol; /* Column index */ + int nString = 0; /* Bytes required to hold all column names */ + int nCol = 0; /* Number of columns in the FTS table */ + char *zCsr; /* Space for holding column names */ + int nDb; /* Bytes required to hold database name */ + int nName; /* Bytes required to hold table name */ + int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */ + const char **aCol; /* Array of column names */ + sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */ + + int nIndex = 0; /* Size of aIndex[] array */ + struct Fts3Index *aIndex = 0; /* Array of indexes for this table */ + + /* The results of parsing supported FTS4 key=value options: */ + int bNoDocsize = 0; /* True to omit %_docsize table */ + int bDescIdx = 0; /* True to store descending indexes */ + char *zPrefix = 0; /* Prefix parameter value (or NULL) */ + char *zCompress = 0; /* compress=? parameter (or NULL) */ + char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ + char *zContent = 0; /* content=? parameter (or NULL) */ + char *zLanguageid = 0; /* languageid=? parameter (or NULL) */ + char **azNotindexed = 0; /* The set of notindexed= columns */ + int nNotindexed = 0; /* Size of azNotindexed[] array */ + + assert( strlen(argv[0])==4 ); + assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) + || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) + ); + + nDb = (int)strlen(argv[1]) + 1; + nName = (int)strlen(argv[2]) + 1; + + nByte = sizeof(const char *) * (argc-2); + aCol = (const char **)sqlite3_malloc(nByte); + if( aCol ){ + memset((void*)aCol, 0, nByte); + azNotindexed = (char **)sqlite3_malloc(nByte); + } + if( azNotindexed ){ + memset(azNotindexed, 0, nByte); + } + if( !aCol || !azNotindexed ){ + rc = SQLITE_NOMEM; + goto fts3_init_out; + } + + /* Loop through all of the arguments passed by the user to the FTS3/4 + ** module (i.e. all the column names and special arguments). This loop + ** does the following: + ** + ** + Figures out the number of columns the FTSX table will have, and + ** the number of bytes of space that must be allocated to store copies + ** of the column names. + ** + ** + If there is a tokenizer specification included in the arguments, + ** initializes the tokenizer pTokenizer. + */ + for(i=3; rc==SQLITE_OK && i8 + && 0==sqlite3_strnicmp(z, "tokenize", 8) + && 0==sqlite3Fts3IsIdChar(z[8]) + ){ + rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr); + } + + /* Check if it is an FTS4 special argument. */ + else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){ + struct Fts4Option { + const char *zOpt; + int nOpt; + } aFts4Opt[] = { + { "matchinfo", 9 }, /* 0 -> MATCHINFO */ + { "prefix", 6 }, /* 1 -> PREFIX */ + { "compress", 8 }, /* 2 -> COMPRESS */ + { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ + { "order", 5 }, /* 4 -> ORDER */ + { "content", 7 }, /* 5 -> CONTENT */ + { "languageid", 10 }, /* 6 -> LANGUAGEID */ + { "notindexed", 10 } /* 7 -> NOTINDEXED */ + }; + + int iOpt; + if( !zVal ){ + rc = SQLITE_NOMEM; + }else{ + for(iOpt=0; iOptnOpt && !sqlite3_strnicmp(z, pOp->zOpt, pOp->nOpt) ){ + break; + } + } + switch( iOpt ){ + case 0: /* MATCHINFO */ + if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){ + sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal); + rc = SQLITE_ERROR; + } + bNoDocsize = 1; + break; + + case 1: /* PREFIX */ + sqlite3_free(zPrefix); + zPrefix = zVal; + zVal = 0; + break; + + case 2: /* COMPRESS */ + sqlite3_free(zCompress); + zCompress = zVal; + zVal = 0; + break; + + case 3: /* UNCOMPRESS */ + sqlite3_free(zUncompress); + zUncompress = zVal; + zVal = 0; + break; + + case 4: /* ORDER */ + if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) + && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) + ){ + sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal); + rc = SQLITE_ERROR; + } + bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); + break; + + case 5: /* CONTENT */ + sqlite3_free(zContent); + zContent = zVal; + zVal = 0; + break; + + case 6: /* LANGUAGEID */ + assert( iOpt==6 ); + sqlite3_free(zLanguageid); + zLanguageid = zVal; + zVal = 0; + break; + + case 7: /* NOTINDEXED */ + azNotindexed[nNotindexed++] = zVal; + zVal = 0; + break; + + default: + assert( iOpt==SizeofArray(aFts4Opt) ); + sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z); + rc = SQLITE_ERROR; + break; + } + sqlite3_free(zVal); + } + } + + /* Otherwise, the argument is a column name. */ + else { + nString += (int)(strlen(z) + 1); + aCol[nCol++] = z; + } + } + + /* If a content=xxx option was specified, the following: + ** + ** 1. Ignore any compress= and uncompress= options. + ** + ** 2. If no column names were specified as part of the CREATE VIRTUAL + ** TABLE statement, use all columns from the content table. + */ + if( rc==SQLITE_OK && zContent ){ + sqlite3_free(zCompress); + sqlite3_free(zUncompress); + zCompress = 0; + zUncompress = 0; + if( nCol==0 ){ + sqlite3_free((void*)aCol); + aCol = 0; + rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr); + + /* If a languageid= option was specified, remove the language id + ** column from the aCol[] array. */ + if( rc==SQLITE_OK && zLanguageid ){ + int j; + for(j=0; jdb = db; + p->nColumn = nCol; + p->nPendingData = 0; + p->azColumn = (char **)&p[1]; + p->pTokenizer = pTokenizer; + p->nMaxPendingData = FTS3_MAX_PENDING_DATA; + p->bHasDocsize = (isFts4 && bNoDocsize==0); + p->bHasStat = (u8)isFts4; + p->bFts4 = (u8)isFts4; + p->bDescIdx = (u8)bDescIdx; + p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ + p->zContentTbl = zContent; + p->zLanguageid = zLanguageid; + zContent = 0; + zLanguageid = 0; + TESTONLY( p->inTransaction = -1 ); + TESTONLY( p->mxSavepoint = -1 ); + + p->aIndex = (struct Fts3Index *)&p->azColumn[nCol]; + memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex); + p->nIndex = nIndex; + for(i=0; iaIndex[i].hPending, FTS3_HASH_STRING, 1); + } + p->abNotindexed = (u8 *)&p->aIndex[nIndex]; + + /* Fill in the zName and zDb fields of the vtab structure. */ + zCsr = (char *)&p->abNotindexed[nCol]; + p->zName = zCsr; + memcpy(zCsr, argv[2], nName); + zCsr += nName; + p->zDb = zCsr; + memcpy(zCsr, argv[1], nDb); + zCsr += nDb; + + /* Fill in the azColumn array */ + for(iCol=0; iCol0 ){ + memcpy(zCsr, z, n); + } + zCsr[n] = '\0'; + sqlite3Fts3Dequote(zCsr); + p->azColumn[iCol] = zCsr; + zCsr += n+1; + assert( zCsr <= &((char *)p)[nByte] ); + } + + /* Fill in the abNotindexed array */ + for(iCol=0; iColazColumn[iCol]); + for(i=0; iazColumn[iCol], zNot, n) + ){ + p->abNotindexed[iCol] = 1; + sqlite3_free(zNot); + azNotindexed[i] = 0; + } + } + } + for(i=0; izReadExprlist = fts3ReadExprList(p, zUncompress, &rc); + p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc); + if( rc!=SQLITE_OK ) goto fts3_init_out; + + /* If this is an xCreate call, create the underlying tables in the + ** database. TODO: For xConnect(), it could verify that said tables exist. + */ + if( isCreate ){ + rc = fts3CreateTables(p); + } + + /* Check to see if a legacy fts3 table has been "upgraded" by the + ** addition of a %_stat table so that it can use incremental merge. + */ + if( !isFts4 && !isCreate ){ + p->bHasStat = 2; + } + + /* Figure out the page-size for the database. This is required in order to + ** estimate the cost of loading large doclists from the database. */ + fts3DatabasePageSize(&rc, p); + p->nNodeSize = p->nPgsz-35; + + /* Declare the table schema to SQLite. */ + fts3DeclareVtab(&rc, p); + +fts3_init_out: + sqlite3_free(zPrefix); + sqlite3_free(aIndex); + sqlite3_free(zCompress); + sqlite3_free(zUncompress); + sqlite3_free(zContent); + sqlite3_free(zLanguageid); + for(i=0; ipModule->xDestroy(pTokenizer); + } + }else{ + assert( p->pSegments==0 ); + *ppVTab = &p->base; + } + return rc; +} + +/* +** The xConnect() and xCreate() methods for the virtual table. All the +** work is done in function fts3InitVtab(). +*/ +static int fts3ConnectMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts3InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr); +} +static int fts3CreateMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts3InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); +} + +/* +** Set the pIdxInfo->estimatedRows variable to nRow. Unless this +** extension is currently being used by a version of SQLite too old to +** support estimatedRows. In that case this function is a no-op. +*/ +static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ +#if SQLITE_VERSION_NUMBER>=3008002 + if( sqlite3_libversion_number()>=3008002 ){ + pIdxInfo->estimatedRows = nRow; + } +#endif +} + +/* +** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this +** extension is currently being used by a version of SQLite too old to +** support index-info flags. In that case this function is a no-op. +*/ +static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){ +#if SQLITE_VERSION_NUMBER>=3008012 + if( sqlite3_libversion_number()>=3008012 ){ + pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; + } +#endif +} + +/* +** Implementation of the xBestIndex method for FTS3 tables. There +** are three possible strategies, in order of preference: +** +** 1. Direct lookup by rowid or docid. +** 2. Full-text search using a MATCH operator on a non-docid column. +** 3. Linear scan of %_content table. +*/ +static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ + Fts3Table *p = (Fts3Table *)pVTab; + int i; /* Iterator variable */ + int iCons = -1; /* Index of constraint to use */ + + int iLangidCons = -1; /* Index of langid=x constraint, if present */ + int iDocidGe = -1; /* Index of docid>=x constraint, if present */ + int iDocidLe = -1; /* Index of docid<=x constraint, if present */ + int iIdx; + + /* By default use a full table scan. This is an expensive option, + ** so search through the constraints to see if a more efficient + ** strategy is possible. + */ + pInfo->idxNum = FTS3_FULLSCAN_SEARCH; + pInfo->estimatedCost = 5000000; + for(i=0; inConstraint; i++){ + int bDocid; /* True if this constraint is on docid */ + struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; + if( pCons->usable==0 ){ + if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ + /* There exists an unusable MATCH constraint. This means that if + ** the planner does elect to use the results of this call as part + ** of the overall query plan the user will see an "unable to use + ** function MATCH in the requested context" error. To discourage + ** this, return a very high cost here. */ + pInfo->idxNum = FTS3_FULLSCAN_SEARCH; + pInfo->estimatedCost = 1e50; + fts3SetEstimatedRows(pInfo, ((sqlite3_int64)1) << 50); + return SQLITE_OK; + } + continue; + } + + bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1); + + /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */ + if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){ + pInfo->idxNum = FTS3_DOCID_SEARCH; + pInfo->estimatedCost = 1.0; + iCons = i; + } + + /* A MATCH constraint. Use a full-text search. + ** + ** If there is more than one MATCH constraint available, use the first + ** one encountered. If there is both a MATCH constraint and a direct + ** rowid/docid lookup, prefer the MATCH strategy. This is done even + ** though the rowid/docid lookup is faster than a MATCH query, selecting + ** it would lead to an "unable to use function MATCH in the requested + ** context" error. + */ + if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH + && pCons->iColumn>=0 && pCons->iColumn<=p->nColumn + ){ + pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn; + pInfo->estimatedCost = 2.0; + iCons = i; + } + + /* Equality constraint on the langid column */ + if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ + && pCons->iColumn==p->nColumn + 2 + ){ + iLangidCons = i; + } + + if( bDocid ){ + switch( pCons->op ){ + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_GT: + iDocidGe = i; + break; + + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + iDocidLe = i; + break; + } + } + } + + /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */ + if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo); + + iIdx = 1; + if( iCons>=0 ){ + pInfo->aConstraintUsage[iCons].argvIndex = iIdx++; + pInfo->aConstraintUsage[iCons].omit = 1; + } + if( iLangidCons>=0 ){ + pInfo->idxNum |= FTS3_HAVE_LANGID; + pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++; + } + if( iDocidGe>=0 ){ + pInfo->idxNum |= FTS3_HAVE_DOCID_GE; + pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++; + } + if( iDocidLe>=0 ){ + pInfo->idxNum |= FTS3_HAVE_DOCID_LE; + pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++; + } + + /* Regardless of the strategy selected, FTS can deliver rows in rowid (or + ** docid) order. Both ascending and descending are possible. + */ + if( pInfo->nOrderBy==1 ){ + struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0]; + if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){ + if( pOrder->desc ){ + pInfo->idxStr = "DESC"; + }else{ + pInfo->idxStr = "ASC"; + } + pInfo->orderByConsumed = 1; + } + } + + assert( p->pSegments==0 ); + return SQLITE_OK; +} + +/* +** Implementation of xOpen method. +*/ +static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + sqlite3_vtab_cursor *pCsr; /* Allocated cursor */ + + UNUSED_PARAMETER(pVTab); + + /* Allocate a buffer large enough for an Fts3Cursor structure. If the + ** allocation succeeds, zero it and return SQLITE_OK. Otherwise, + ** if the allocation fails, return SQLITE_NOMEM. + */ + *ppCsr = pCsr = (sqlite3_vtab_cursor *)sqlite3_malloc(sizeof(Fts3Cursor)); + if( !pCsr ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(Fts3Cursor)); + return SQLITE_OK; +} + +/* +** Finalize the statement handle at pCsr->pStmt. +** +** Or, if that statement handle is one created by fts3CursorSeekStmt(), +** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement +** pointer there instead of finalizing it. +*/ +static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){ + if( pCsr->bSeekStmt ){ + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + if( p->pSeekStmt==0 ){ + p->pSeekStmt = pCsr->pStmt; + sqlite3_reset(pCsr->pStmt); + pCsr->pStmt = 0; + } + pCsr->bSeekStmt = 0; + } + sqlite3_finalize(pCsr->pStmt); +} + +/* +** Close the cursor. For additional information see the documentation +** on the xClose method of the virtual table interface. +*/ +static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + fts3CursorFinalizeStmt(pCsr); + sqlite3Fts3ExprFree(pCsr->pExpr); + sqlite3Fts3FreeDeferredTokens(pCsr); + sqlite3_free(pCsr->aDoclist); + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then +** compose and prepare an SQL statement of the form: +** +** "SELECT FROM %_content WHERE rowid = ?" +** +** (or the equivalent for a content=xxx table) and set pCsr->pStmt to +** it. If an error occurs, return an SQLite error code. +*/ +static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ + int rc = SQLITE_OK; + if( pCsr->pStmt==0 ){ + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + char *zSql; + if( p->pSeekStmt ){ + pCsr->pStmt = p->pSeekStmt; + p->pSeekStmt = 0; + }else{ + zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); + if( !zSql ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + sqlite3_free(zSql); + } + if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1; + } + return rc; +} + +/* +** Position the pCsr->pStmt statement so that it is on the row +** of the %_content table that contains the last match. Return +** SQLITE_OK on success. +*/ +static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ + int rc = SQLITE_OK; + if( pCsr->isRequireSeek ){ + rc = fts3CursorSeekStmt(pCsr); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); + pCsr->isRequireSeek = 0; + if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ + return SQLITE_OK; + }else{ + rc = sqlite3_reset(pCsr->pStmt); + if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ + /* If no row was found and no error has occurred, then the %_content + ** table is missing a row that is present in the full-text index. + ** The data structures are corrupt. */ + rc = FTS_CORRUPT_VTAB; + pCsr->isEof = 1; + } + } + } + } + + if( rc!=SQLITE_OK && pContext ){ + sqlite3_result_error_code(pContext, rc); + } + return rc; +} + +/* +** This function is used to process a single interior node when searching +** a b-tree for a term or term prefix. The node data is passed to this +** function via the zNode/nNode parameters. The term to search for is +** passed in zTerm/nTerm. +** +** If piFirst is not NULL, then this function sets *piFirst to the blockid +** of the child node that heads the sub-tree that may contain the term. +** +** If piLast is not NULL, then *piLast is set to the right-most child node +** that heads a sub-tree that may contain a term for which zTerm/nTerm is +** a prefix. +** +** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK. +*/ +static int fts3ScanInteriorNode( + const char *zTerm, /* Term to select leaves for */ + int nTerm, /* Size of term zTerm in bytes */ + const char *zNode, /* Buffer containing segment interior node */ + int nNode, /* Size of buffer at zNode */ + sqlite3_int64 *piFirst, /* OUT: Selected child node */ + sqlite3_int64 *piLast /* OUT: Selected child node */ +){ + int rc = SQLITE_OK; /* Return code */ + const char *zCsr = zNode; /* Cursor to iterate through node */ + const char *zEnd = &zCsr[nNode];/* End of interior node buffer */ + char *zBuffer = 0; /* Buffer to load terms into */ + int nAlloc = 0; /* Size of allocated buffer */ + int isFirstTerm = 1; /* True when processing first term on page */ + sqlite3_int64 iChild; /* Block id of child node to descend to */ + + /* Skip over the 'height' varint that occurs at the start of every + ** interior node. Then load the blockid of the left-child of the b-tree + ** node into variable iChild. + ** + ** Even if the data structure on disk is corrupted, this (reading two + ** varints from the buffer) does not risk an overread. If zNode is a + ** root node, then the buffer comes from a SELECT statement. SQLite does + ** not make this guarantee explicitly, but in practice there are always + ** either more than 20 bytes of allocated space following the nNode bytes of + ** contents, or two zero bytes. Or, if the node is read from the %_segments + ** table, then there are always 20 bytes of zeroed padding following the + ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). + */ + zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); + zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); + if( zCsr>zEnd ){ + return FTS_CORRUPT_VTAB; + } + + while( zCsr=0 && nSuffix>=0 ); + if( &zCsr[nSuffix]>zEnd ){ + rc = FTS_CORRUPT_VTAB; + goto finish_scan; + } + if( nPrefix+nSuffix>nAlloc ){ + char *zNew; + nAlloc = (nPrefix+nSuffix) * 2; + zNew = (char *)sqlite3_realloc(zBuffer, nAlloc); + if( !zNew ){ + rc = SQLITE_NOMEM; + goto finish_scan; + } + zBuffer = zNew; + } + assert( zBuffer ); + memcpy(&zBuffer[nPrefix], zCsr, nSuffix); + nBuffer = nPrefix + nSuffix; + zCsr += nSuffix; + + /* Compare the term we are searching for with the term just loaded from + ** the interior node. If the specified term is greater than or equal + ** to the term from the interior node, then all terms on the sub-tree + ** headed by node iChild are smaller than zTerm. No need to search + ** iChild. + ** + ** If the interior node term is larger than the specified term, then + ** the tree headed by iChild may contain the specified term. + */ + cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); + if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ + *piFirst = iChild; + piFirst = 0; + } + + if( piLast && cmp<0 ){ + *piLast = iChild; + piLast = 0; + } + + iChild++; + }; + + if( piFirst ) *piFirst = iChild; + if( piLast ) *piLast = iChild; + + finish_scan: + sqlite3_free(zBuffer); + return rc; +} + + +/* +** The buffer pointed to by argument zNode (size nNode bytes) contains an +** interior node of a b-tree segment. The zTerm buffer (size nTerm bytes) +** contains a term. This function searches the sub-tree headed by the zNode +** node for the range of leaf nodes that may contain the specified term +** or terms for which the specified term is a prefix. +** +** If piLeaf is not NULL, then *piLeaf is set to the blockid of the +** left-most leaf node in the tree that may contain the specified term. +** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the +** right-most leaf node that may contain a term for which the specified +** term is a prefix. +** +** It is possible that the range of returned leaf nodes does not contain +** the specified term or any terms for which it is a prefix. However, if the +** segment does contain any such terms, they are stored within the identified +** range. Because this function only inspects interior segment nodes (and +** never loads leaf nodes into memory), it is not possible to be sure. +** +** If an error occurs, an error code other than SQLITE_OK is returned. +*/ +static int fts3SelectLeaf( + Fts3Table *p, /* Virtual table handle */ + const char *zTerm, /* Term to select leaves for */ + int nTerm, /* Size of term zTerm in bytes */ + const char *zNode, /* Buffer containing segment interior node */ + int nNode, /* Size of buffer at zNode */ + sqlite3_int64 *piLeaf, /* Selected leaf node */ + sqlite3_int64 *piLeaf2 /* Selected leaf node */ +){ + int rc = SQLITE_OK; /* Return code */ + int iHeight; /* Height of this node in tree */ + + assert( piLeaf || piLeaf2 ); + + fts3GetVarint32(zNode, &iHeight); + rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); + assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) ); + + if( rc==SQLITE_OK && iHeight>1 ){ + char *zBlob = 0; /* Blob read from %_segments table */ + int nBlob = 0; /* Size of zBlob in bytes */ + + if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){ + rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0); + if( rc==SQLITE_OK ){ + rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0); + } + sqlite3_free(zBlob); + piLeaf = 0; + zBlob = 0; + } + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0); + } + if( rc==SQLITE_OK ){ + rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2); + } + sqlite3_free(zBlob); + } + + return rc; +} + +/* +** This function is used to create delta-encoded serialized lists of FTS3 +** varints. Each call to this function appends a single varint to a list. +*/ +static void fts3PutDeltaVarint( + char **pp, /* IN/OUT: Output pointer */ + sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ + sqlite3_int64 iVal /* Write this value to the list */ +){ + assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); + *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); + *piPrev = iVal; +} + +/* +** When this function is called, *ppPoslist is assumed to point to the +** start of a position-list. After it returns, *ppPoslist points to the +** first byte after the position-list. +** +** A position list is list of positions (delta encoded) and columns for +** a single document record of a doclist. So, in other words, this +** routine advances *ppPoslist so that it points to the next docid in +** the doclist, or to the first byte past the end of the doclist. +** +** If pp is not NULL, then the contents of the position list are copied +** to *pp. *pp is set to point to the first byte past the last byte copied +** before this function returns. +*/ +static void fts3PoslistCopy(char **pp, char **ppPoslist){ + char *pEnd = *ppPoslist; + char c = 0; + + /* The end of a position list is marked by a zero encoded as an FTS3 + ** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by + ** a byte with the 0x80 bit set, then it is not a varint 0, but the tail + ** of some other, multi-byte, value. + ** + ** The following while-loop moves pEnd to point to the first byte that is not + ** immediately preceded by a byte with the 0x80 bit set. Then increments + ** pEnd once more so that it points to the byte immediately following the + ** last byte in the position-list. + */ + while( *pEnd | c ){ + c = *pEnd++ & 0x80; + testcase( c!=0 && (*pEnd)==0 ); + } + pEnd++; /* Advance past the POS_END terminator byte */ + + if( pp ){ + int n = (int)(pEnd - *ppPoslist); + char *p = *pp; + memcpy(p, *ppPoslist, n); + p += n; + *pp = p; + } + *ppPoslist = pEnd; +} + +/* +** When this function is called, *ppPoslist is assumed to point to the +** start of a column-list. After it returns, *ppPoslist points to the +** to the terminator (POS_COLUMN or POS_END) byte of the column-list. +** +** A column-list is list of delta-encoded positions for a single column +** within a single document within a doclist. +** +** The column-list is terminated either by a POS_COLUMN varint (1) or +** a POS_END varint (0). This routine leaves *ppPoslist pointing to +** the POS_COLUMN or POS_END that terminates the column-list. +** +** If pp is not NULL, then the contents of the column-list are copied +** to *pp. *pp is set to point to the first byte past the last byte copied +** before this function returns. The POS_COLUMN or POS_END terminator +** is not copied into *pp. +*/ +static void fts3ColumnlistCopy(char **pp, char **ppPoslist){ + char *pEnd = *ppPoslist; + char c = 0; + + /* A column-list is terminated by either a 0x01 or 0x00 byte that is + ** not part of a multi-byte varint. + */ + while( 0xFE & (*pEnd | c) ){ + c = *pEnd++ & 0x80; + testcase( c!=0 && ((*pEnd)&0xfe)==0 ); + } + if( pp ){ + int n = (int)(pEnd - *ppPoslist); + char *p = *pp; + memcpy(p, *ppPoslist, n); + p += n; + *pp = p; + } + *ppPoslist = pEnd; +} + +/* +** Value used to signify the end of an position-list. This is safe because +** it is not possible to have a document with 2^31 terms. +*/ +#define POSITION_LIST_END 0x7fffffff + +/* +** This function is used to help parse position-lists. When this function is +** called, *pp may point to the start of the next varint in the position-list +** being parsed, or it may point to 1 byte past the end of the position-list +** (in which case **pp will be a terminator bytes POS_END (0) or +** (1)). +** +** If *pp points past the end of the current position-list, set *pi to +** POSITION_LIST_END and return. Otherwise, read the next varint from *pp, +** increment the current value of *pi by the value read, and set *pp to +** point to the next value before returning. +** +** Before calling this routine *pi must be initialized to the value of +** the previous position, or zero if we are reading the first position +** in the position-list. Because positions are delta-encoded, the value +** of the previous position is needed in order to compute the value of +** the next position. +*/ +static void fts3ReadNextPos( + char **pp, /* IN/OUT: Pointer into position-list buffer */ + sqlite3_int64 *pi /* IN/OUT: Value read from position-list */ +){ + if( (**pp)&0xFE ){ + fts3GetDeltaVarint(pp, pi); + *pi -= 2; + }else{ + *pi = POSITION_LIST_END; + } +} + +/* +** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by +** the value of iCol encoded as a varint to *pp. This will start a new +** column list. +** +** Set *pp to point to the byte just after the last byte written before +** returning (do not modify it if iCol==0). Return the total number of bytes +** written (0 if iCol==0). +*/ +static int fts3PutColNumber(char **pp, int iCol){ + int n = 0; /* Number of bytes written */ + if( iCol ){ + char *p = *pp; /* Output pointer */ + n = 1 + sqlite3Fts3PutVarint(&p[1], iCol); + *p = 0x01; + *pp = &p[n]; + } + return n; +} + +/* +** Compute the union of two position lists. The output written +** into *pp contains all positions of both *pp1 and *pp2 in sorted +** order and with any duplicates removed. All pointers are +** updated appropriately. The caller is responsible for insuring +** that there is enough space in *pp to hold the complete output. +*/ +static void fts3PoslistMerge( + char **pp, /* Output buffer */ + char **pp1, /* Left input list */ + char **pp2 /* Right input list */ +){ + char *p = *pp; + char *p1 = *pp1; + char *p2 = *pp2; + + while( *p1 || *p2 ){ + int iCol1; /* The current column index in pp1 */ + int iCol2; /* The current column index in pp2 */ + + if( *p1==POS_COLUMN ) fts3GetVarint32(&p1[1], &iCol1); + else if( *p1==POS_END ) iCol1 = POSITION_LIST_END; + else iCol1 = 0; + + if( *p2==POS_COLUMN ) fts3GetVarint32(&p2[1], &iCol2); + else if( *p2==POS_END ) iCol2 = POSITION_LIST_END; + else iCol2 = 0; + + if( iCol1==iCol2 ){ + sqlite3_int64 i1 = 0; /* Last position from pp1 */ + sqlite3_int64 i2 = 0; /* Last position from pp2 */ + sqlite3_int64 iPrev = 0; + int n = fts3PutColNumber(&p, iCol1); + p1 += n; + p2 += n; + + /* At this point, both p1 and p2 point to the start of column-lists + ** for the same column (the column with index iCol1 and iCol2). + ** A column-list is a list of non-negative delta-encoded varints, each + ** incremented by 2 before being stored. Each list is terminated by a + ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists + ** and writes the results to buffer p. p is left pointing to the byte + ** after the list written. No terminator (POS_END or POS_COLUMN) is + ** written to the output. + */ + fts3GetDeltaVarint(&p1, &i1); + fts3GetDeltaVarint(&p2, &i2); + do { + fts3PutDeltaVarint(&p, &iPrev, (i1pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e. +** when the *pp1 token appears before the *pp2 token, but not more than nToken +** slots before it. +** +** e.g. nToken==1 searches for adjacent positions. +*/ +static int fts3PoslistPhraseMerge( + char **pp, /* IN/OUT: Preallocated output buffer */ + int nToken, /* Maximum difference in token positions */ + int isSaveLeft, /* Save the left position */ + int isExact, /* If *pp1 is exactly nTokens before *pp2 */ + char **pp1, /* IN/OUT: Left input list */ + char **pp2 /* IN/OUT: Right input list */ +){ + char *p = *pp; + char *p1 = *pp1; + char *p2 = *pp2; + int iCol1 = 0; + int iCol2 = 0; + + /* Never set both isSaveLeft and isExact for the same invocation. */ + assert( isSaveLeft==0 || isExact==0 ); + + assert( p!=0 && *p1!=0 && *p2!=0 ); + if( *p1==POS_COLUMN ){ + p1++; + p1 += fts3GetVarint32(p1, &iCol1); + } + if( *p2==POS_COLUMN ){ + p2++; + p2 += fts3GetVarint32(p2, &iCol2); + } + + while( 1 ){ + if( iCol1==iCol2 ){ + char *pSave = p; + sqlite3_int64 iPrev = 0; + sqlite3_int64 iPos1 = 0; + sqlite3_int64 iPos2 = 0; + + if( iCol1 ){ + *p++ = POS_COLUMN; + p += sqlite3Fts3PutVarint(p, iCol1); + } + + assert( *p1!=POS_END && *p1!=POS_COLUMN ); + assert( *p2!=POS_END && *p2!=POS_COLUMN ); + fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; + fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; + + while( 1 ){ + if( iPos2==iPos1+nToken + || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) + ){ + sqlite3_int64 iSave; + iSave = isSaveLeft ? iPos1 : iPos2; + fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; + pSave = 0; + assert( p ); + } + if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ + if( (*p2&0xFE)==0 ) break; + fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; + }else{ + if( (*p1&0xFE)==0 ) break; + fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; + } + } + + if( pSave ){ + assert( pp && p ); + p = pSave; + } + + fts3ColumnlistCopy(0, &p1); + fts3ColumnlistCopy(0, &p2); + assert( (*p1&0xFE)==0 && (*p2&0xFE)==0 ); + if( 0==*p1 || 0==*p2 ) break; + + p1++; + p1 += fts3GetVarint32(p1, &iCol1); + p2++; + p2 += fts3GetVarint32(p2, &iCol2); + } + + /* Advance pointer p1 or p2 (whichever corresponds to the smaller of + ** iCol1 and iCol2) so that it points to either the 0x00 that marks the + ** end of the position list, or the 0x01 that precedes the next + ** column-number in the position list. + */ + else if( iCol1=pEnd ){ + *pp = 0; + }else{ + sqlite3_int64 iVal; + *pp += sqlite3Fts3GetVarint(*pp, &iVal); + if( bDescIdx ){ + *pVal -= iVal; + }else{ + *pVal += iVal; + } + } +} + +/* +** This function is used to write a single varint to a buffer. The varint +** is written to *pp. Before returning, *pp is set to point 1 byte past the +** end of the value written. +** +** If *pbFirst is zero when this function is called, the value written to +** the buffer is that of parameter iVal. +** +** If *pbFirst is non-zero when this function is called, then the value +** written is either (iVal-*piPrev) (if bDescIdx is zero) or (*piPrev-iVal) +** (if bDescIdx is non-zero). +** +** Before returning, this function always sets *pbFirst to 1 and *piPrev +** to the value of parameter iVal. +*/ +static void fts3PutDeltaVarint3( + char **pp, /* IN/OUT: Output pointer */ + int bDescIdx, /* True for descending docids */ + sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ + int *pbFirst, /* IN/OUT: True after first int written */ + sqlite3_int64 iVal /* Write this value to the list */ +){ + sqlite3_int64 iWrite; + if( bDescIdx==0 || *pbFirst==0 ){ + iWrite = iVal - *piPrev; + }else{ + iWrite = *piPrev - iVal; + } + assert( *pbFirst || *piPrev==0 ); + assert( *pbFirst==0 || iWrite>0 ); + *pp += sqlite3Fts3PutVarint(*pp, iWrite); + *piPrev = iVal; + *pbFirst = 1; +} + + +/* +** This macro is used by various functions that merge doclists. The two +** arguments are 64-bit docid values. If the value of the stack variable +** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). +** Otherwise, (i2-i1). +** +** Using this makes it easier to write code that can merge doclists that are +** sorted in either ascending or descending order. +*/ +#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2)) + +/* +** This function does an "OR" merge of two doclists (output contains all +** positions contained in either argument doclist). If the docids in the +** input doclists are sorted in ascending order, parameter bDescDoclist +** should be false. If they are sorted in ascending order, it should be +** passed a non-zero value. +** +** If no error occurs, *paOut is set to point at an sqlite3_malloc'd buffer +** containing the output doclist and SQLITE_OK is returned. In this case +** *pnOut is set to the number of bytes in the output doclist. +** +** If an error occurs, an SQLite error code is returned. The output values +** are undefined in this case. +*/ +static int fts3DoclistOrMerge( + int bDescDoclist, /* True if arguments are desc */ + char *a1, int n1, /* First doclist */ + char *a2, int n2, /* Second doclist */ + char **paOut, int *pnOut /* OUT: Malloc'd doclist */ +){ + sqlite3_int64 i1 = 0; + sqlite3_int64 i2 = 0; + sqlite3_int64 iPrev = 0; + char *pEnd1 = &a1[n1]; + char *pEnd2 = &a2[n2]; + char *p1 = a1; + char *p2 = a2; + char *p; + char *aOut; + int bFirstOut = 0; + + *paOut = 0; + *pnOut = 0; + + /* Allocate space for the output. Both the input and output doclists + ** are delta encoded. If they are in ascending order (bDescDoclist==0), + ** then the first docid in each list is simply encoded as a varint. For + ** each subsequent docid, the varint stored is the difference between the + ** current and previous docid (a positive number - since the list is in + ** ascending order). + ** + ** The first docid written to the output is therefore encoded using the + ** same number of bytes as it is in whichever of the input lists it is + ** read from. And each subsequent docid read from the same input list + ** consumes either the same or less bytes as it did in the input (since + ** the difference between it and the previous value in the output must + ** be a positive value less than or equal to the delta value read from + ** the input list). The same argument applies to all but the first docid + ** read from the 'other' list. And to the contents of all position lists + ** that will be copied and merged from the input to the output. + ** + ** However, if the first docid copied to the output is a negative number, + ** then the encoding of the first docid from the 'other' input list may + ** be larger in the output than it was in the input (since the delta value + ** may be a larger positive integer than the actual docid). + ** + ** The space required to store the output is therefore the sum of the + ** sizes of the two inputs, plus enough space for exactly one of the input + ** docids to grow. + ** + ** A symetric argument may be made if the doclists are in descending + ** order. + */ + aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1); + if( !aOut ) return SQLITE_NOMEM; + + p = aOut; + fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); + while( p1 || p2 ){ + sqlite3_int64 iDiff = DOCID_CMP(i1, i2); + + if( p2 && p1 && iDiff==0 ){ + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); + fts3PoslistMerge(&p, &p1, &p2); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); + }else if( !p2 || (p1 && iDiff<0) ){ + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); + fts3PoslistCopy(&p, &p1); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + }else{ + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2); + fts3PoslistCopy(&p, &p2); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); + } + } + + *paOut = aOut; + *pnOut = (int)(p-aOut); + assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 ); + return SQLITE_OK; +} + +/* +** This function does a "phrase" merge of two doclists. In a phrase merge, +** the output contains a copy of each position from the right-hand input +** doclist for which there is a position in the left-hand input doclist +** exactly nDist tokens before it. +** +** If the docids in the input doclists are sorted in ascending order, +** parameter bDescDoclist should be false. If they are sorted in ascending +** order, it should be passed a non-zero value. +** +** The right-hand input doclist is overwritten by this function. +*/ +static int fts3DoclistPhraseMerge( + int bDescDoclist, /* True if arguments are desc */ + int nDist, /* Distance from left to right (1=adjacent) */ + char *aLeft, int nLeft, /* Left doclist */ + char **paRight, int *pnRight /* IN/OUT: Right/output doclist */ +){ + sqlite3_int64 i1 = 0; + sqlite3_int64 i2 = 0; + sqlite3_int64 iPrev = 0; + char *aRight = *paRight; + char *pEnd1 = &aLeft[nLeft]; + char *pEnd2 = &aRight[*pnRight]; + char *p1 = aLeft; + char *p2 = aRight; + char *p; + int bFirstOut = 0; + char *aOut; + + assert( nDist>0 ); + if( bDescDoclist ){ + aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX); + if( aOut==0 ) return SQLITE_NOMEM; + }else{ + aOut = aRight; + } + p = aOut; + + fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); + + while( p1 && p2 ){ + sqlite3_int64 iDiff = DOCID_CMP(i1, i2); + if( iDiff==0 ){ + char *pSave = p; + sqlite3_int64 iPrevSave = iPrev; + int bFirstOutSave = bFirstOut; + + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); + if( 0==fts3PoslistPhraseMerge(&p, nDist, 0, 1, &p1, &p2) ){ + p = pSave; + iPrev = iPrevSave; + bFirstOut = bFirstOutSave; + } + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); + }else if( iDiff<0 ){ + fts3PoslistCopy(0, &p1); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + }else{ + fts3PoslistCopy(0, &p2); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); + } + } + + *pnRight = (int)(p - aOut); + if( bDescDoclist ){ + sqlite3_free(aRight); + *paRight = aOut; + } + + return SQLITE_OK; +} + +/* +** Argument pList points to a position list nList bytes in size. This +** function checks to see if the position list contains any entries for +** a token in position 0 (of any column). If so, it writes argument iDelta +** to the output buffer pOut, followed by a position list consisting only +** of the entries from pList at position 0, and terminated by an 0x00 byte. +** The value returned is the number of bytes written to pOut (if any). +*/ +SQLITE_PRIVATE int sqlite3Fts3FirstFilter( + sqlite3_int64 iDelta, /* Varint that may be written to pOut */ + char *pList, /* Position list (no 0x00 term) */ + int nList, /* Size of pList in bytes */ + char *pOut /* Write output here */ +){ + int nOut = 0; + int bWritten = 0; /* True once iDelta has been written */ + char *p = pList; + char *pEnd = &pList[nList]; + + if( *p!=0x01 ){ + if( *p==0x02 ){ + nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); + pOut[nOut++] = 0x02; + bWritten = 1; + } + fts3ColumnlistCopy(0, &p); + } + + while( paaOutput); i++){ + if( pTS->aaOutput[i] ){ + if( !aOut ){ + aOut = pTS->aaOutput[i]; + nOut = pTS->anOutput[i]; + pTS->aaOutput[i] = 0; + }else{ + int nNew; + char *aNew; + + int rc = fts3DoclistOrMerge(p->bDescIdx, + pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, &aNew, &nNew + ); + if( rc!=SQLITE_OK ){ + sqlite3_free(aOut); + return rc; + } + + sqlite3_free(pTS->aaOutput[i]); + sqlite3_free(aOut); + pTS->aaOutput[i] = 0; + aOut = aNew; + nOut = nNew; + } + } + } + + pTS->aaOutput[0] = aOut; + pTS->anOutput[0] = nOut; + return SQLITE_OK; +} + +/* +** Merge the doclist aDoclist/nDoclist into the TermSelect object passed +** as the first argument. The merge is an "OR" merge (see function +** fts3DoclistOrMerge() for details). +** +** This function is called with the doclist for each term that matches +** a queried prefix. It merges all these doclists into one, the doclist +** for the specified prefix. Since there can be a very large number of +** doclists to merge, the merging is done pair-wise using the TermSelect +** object. +** +** This function returns SQLITE_OK if the merge is successful, or an +** SQLite error code (SQLITE_NOMEM) if an error occurs. +*/ +static int fts3TermSelectMerge( + Fts3Table *p, /* FTS table handle */ + TermSelect *pTS, /* TermSelect object to merge into */ + char *aDoclist, /* Pointer to doclist */ + int nDoclist /* Size of aDoclist in bytes */ +){ + if( pTS->aaOutput[0]==0 ){ + /* If this is the first term selected, copy the doclist to the output + ** buffer using memcpy(). + ** + ** Add FTS3_VARINT_MAX bytes of unused space to the end of the + ** allocation. This is so as to ensure that the buffer is big enough + ** to hold the current doclist AND'd with any other doclist. If the + ** doclists are stored in order=ASC order, this padding would not be + ** required (since the size of [doclistA AND doclistB] is always less + ** than or equal to the size of [doclistA] in that case). But this is + ** not true for order=DESC. For example, a doclist containing (1, -1) + ** may be smaller than (-1), as in the first example the -1 may be stored + ** as a single-byte delta, whereas in the second it must be stored as a + ** FTS3_VARINT_MAX byte varint. + ** + ** Similar padding is added in the fts3DoclistOrMerge() function. + */ + pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); + pTS->anOutput[0] = nDoclist; + if( pTS->aaOutput[0] ){ + memcpy(pTS->aaOutput[0], aDoclist, nDoclist); + }else{ + return SQLITE_NOMEM; + } + }else{ + char *aMerge = aDoclist; + int nMerge = nDoclist; + int iOut; + + for(iOut=0; iOutaaOutput); iOut++){ + if( pTS->aaOutput[iOut]==0 ){ + assert( iOut>0 ); + pTS->aaOutput[iOut] = aMerge; + pTS->anOutput[iOut] = nMerge; + break; + }else{ + char *aNew; + int nNew; + + int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge, + pTS->aaOutput[iOut], pTS->anOutput[iOut], &aNew, &nNew + ); + if( rc!=SQLITE_OK ){ + if( aMerge!=aDoclist ) sqlite3_free(aMerge); + return rc; + } + + if( aMerge!=aDoclist ) sqlite3_free(aMerge); + sqlite3_free(pTS->aaOutput[iOut]); + pTS->aaOutput[iOut] = 0; + + aMerge = aNew; + nMerge = nNew; + if( (iOut+1)==SizeofArray(pTS->aaOutput) ){ + pTS->aaOutput[iOut] = aMerge; + pTS->anOutput[iOut] = nMerge; + } + } + } + } + return SQLITE_OK; +} + +/* +** Append SegReader object pNew to the end of the pCsr->apSegment[] array. +*/ +static int fts3SegReaderCursorAppend( + Fts3MultiSegReader *pCsr, + Fts3SegReader *pNew +){ + if( (pCsr->nSegment%16)==0 ){ + Fts3SegReader **apNew; + int nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*); + apNew = (Fts3SegReader **)sqlite3_realloc(pCsr->apSegment, nByte); + if( !apNew ){ + sqlite3Fts3SegReaderFree(pNew); + return SQLITE_NOMEM; + } + pCsr->apSegment = apNew; + } + pCsr->apSegment[pCsr->nSegment++] = pNew; + return SQLITE_OK; +} + +/* +** Add seg-reader objects to the Fts3MultiSegReader object passed as the +** 8th argument. +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +static int fts3SegReaderCursor( + Fts3Table *p, /* FTS3 table handle */ + int iLangid, /* Language id */ + int iIndex, /* Index to search (from 0 to p->nIndex-1) */ + int iLevel, /* Level of segments to scan */ + const char *zTerm, /* Term to query for */ + int nTerm, /* Size of zTerm in bytes */ + int isPrefix, /* True for a prefix search */ + int isScan, /* True to scan from zTerm to EOF */ + Fts3MultiSegReader *pCsr /* Cursor object to populate */ +){ + int rc = SQLITE_OK; /* Error code */ + sqlite3_stmt *pStmt = 0; /* Statement to iterate through segments */ + int rc2; /* Result of sqlite3_reset() */ + + /* If iLevel is less than 0 and this is not a scan, include a seg-reader + ** for the pending-terms. If this is a scan, then this call must be being + ** made by an fts4aux module, not an FTS table. In this case calling + ** Fts3SegReaderPending might segfault, as the data structures used by + ** fts4aux are not completely populated. So it's easiest to filter these + ** calls out here. */ + if( iLevel<0 && p->aIndex ){ + Fts3SegReader *pSeg = 0; + rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg); + if( rc==SQLITE_OK && pSeg ){ + rc = fts3SegReaderCursorAppend(pCsr, pSeg); + } + } + + if( iLevel!=FTS3_SEGCURSOR_PENDING ){ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3AllSegdirs(p, iLangid, iIndex, iLevel, &pStmt); + } + + while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ + Fts3SegReader *pSeg = 0; + + /* Read the values returned by the SELECT into local variables. */ + sqlite3_int64 iStartBlock = sqlite3_column_int64(pStmt, 1); + sqlite3_int64 iLeavesEndBlock = sqlite3_column_int64(pStmt, 2); + sqlite3_int64 iEndBlock = sqlite3_column_int64(pStmt, 3); + int nRoot = sqlite3_column_bytes(pStmt, 4); + char const *zRoot = sqlite3_column_blob(pStmt, 4); + + /* If zTerm is not NULL, and this segment is not stored entirely on its + ** root node, the range of leaves scanned can be reduced. Do this. */ + if( iStartBlock && zTerm ){ + sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0); + rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi); + if( rc!=SQLITE_OK ) goto finished; + if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock; + } + + rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1, + (isPrefix==0 && isScan==0), + iStartBlock, iLeavesEndBlock, + iEndBlock, zRoot, nRoot, &pSeg + ); + if( rc!=SQLITE_OK ) goto finished; + rc = fts3SegReaderCursorAppend(pCsr, pSeg); + } + } + + finished: + rc2 = sqlite3_reset(pStmt); + if( rc==SQLITE_DONE ) rc = rc2; + + return rc; +} + +/* +** Set up a cursor object for iterating through a full-text index or a +** single level therein. +*/ +SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor( + Fts3Table *p, /* FTS3 table handle */ + int iLangid, /* Language-id to search */ + int iIndex, /* Index to search (from 0 to p->nIndex-1) */ + int iLevel, /* Level of segments to scan */ + const char *zTerm, /* Term to query for */ + int nTerm, /* Size of zTerm in bytes */ + int isPrefix, /* True for a prefix search */ + int isScan, /* True to scan from zTerm to EOF */ + Fts3MultiSegReader *pCsr /* Cursor object to populate */ +){ + assert( iIndex>=0 && iIndexnIndex ); + assert( iLevel==FTS3_SEGCURSOR_ALL + || iLevel==FTS3_SEGCURSOR_PENDING + || iLevel>=0 + ); + assert( iLevelbase.pVtab; + + if( isPrefix ){ + for(i=1; bFound==0 && inIndex; i++){ + if( p->aIndex[i].nPrefix==nTerm ){ + bFound = 1; + rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, + i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr + ); + pSegcsr->bLookup = 1; + } + } + + for(i=1; bFound==0 && inIndex; i++){ + if( p->aIndex[i].nPrefix==nTerm+1 ){ + bFound = 1; + rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, + i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr + ); + if( rc==SQLITE_OK ){ + rc = fts3SegReaderCursorAddZero( + p, pCsr->iLangid, zTerm, nTerm, pSegcsr + ); + } + } + } + } + + if( bFound==0 ){ + rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, + 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr + ); + pSegcsr->bLookup = !isPrefix; + } + } + + *ppSegcsr = pSegcsr; + return rc; +} + +/* +** Free an Fts3MultiSegReader allocated by fts3TermSegReaderCursor(). +*/ +static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ + sqlite3Fts3SegReaderFinish(pSegcsr); + sqlite3_free(pSegcsr); +} + +/* +** This function retrieves the doclist for the specified term (or term +** prefix) from the database. +*/ +static int fts3TermSelect( + Fts3Table *p, /* Virtual table handle */ + Fts3PhraseToken *pTok, /* Token to query for */ + int iColumn, /* Column to query (or -ve for all columns) */ + int *pnOut, /* OUT: Size of buffer at *ppOut */ + char **ppOut /* OUT: Malloced result buffer */ +){ + int rc; /* Return code */ + Fts3MultiSegReader *pSegcsr; /* Seg-reader cursor for this term */ + TermSelect tsc; /* Object for pair-wise doclist merging */ + Fts3SegFilter filter; /* Segment term filter configuration */ + + pSegcsr = pTok->pSegcsr; + memset(&tsc, 0, sizeof(TermSelect)); + + filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS + | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) + | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0) + | (iColumnnColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); + filter.iCol = iColumn; + filter.zTerm = pTok->z; + filter.nTerm = pTok->n; + + rc = sqlite3Fts3SegReaderStart(p, pSegcsr, &filter); + while( SQLITE_OK==rc + && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr)) + ){ + rc = fts3TermSelectMerge(p, &tsc, pSegcsr->aDoclist, pSegcsr->nDoclist); + } + + if( rc==SQLITE_OK ){ + rc = fts3TermSelectFinishMerge(p, &tsc); + } + if( rc==SQLITE_OK ){ + *ppOut = tsc.aaOutput[0]; + *pnOut = tsc.anOutput[0]; + }else{ + int i; + for(i=0; ipSegcsr = 0; + return rc; +} + +/* +** This function counts the total number of docids in the doclist stored +** in buffer aList[], size nList bytes. +** +** If the isPoslist argument is true, then it is assumed that the doclist +** contains a position-list following each docid. Otherwise, it is assumed +** that the doclist is simply a list of docids stored as delta encoded +** varints. +*/ +static int fts3DoclistCountDocids(char *aList, int nList){ + int nDoc = 0; /* Return value */ + if( aList ){ + char *aEnd = &aList[nList]; /* Pointer to one byte after EOF */ + char *p = aList; /* Cursor */ + while( peSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){ + if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){ + pCsr->isEof = 1; + rc = sqlite3_reset(pCsr->pStmt); + }else{ + pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); + rc = SQLITE_OK; + } + }else{ + rc = fts3EvalNext((Fts3Cursor *)pCursor); + } + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + return rc; +} + +/* +** The following are copied from sqliteInt.h. +** +** Constants for the largest and smallest possible 64-bit signed integers. +** These macros are designed to work correctly on both 32-bit and 64-bit +** compilers. +*/ +#ifndef SQLITE_AMALGAMATION +# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) +# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) +#endif + +/* +** If the numeric type of argument pVal is "integer", then return it +** converted to a 64-bit signed integer. Otherwise, return a copy of +** the second parameter, iDefault. +*/ +static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){ + if( pVal ){ + int eType = sqlite3_value_numeric_type(pVal); + if( eType==SQLITE_INTEGER ){ + return sqlite3_value_int64(pVal); + } + } + return iDefault; +} + +/* +** This is the xFilter interface for the virtual table. See +** the virtual table xFilter method documentation for additional +** information. +** +** If idxNum==FTS3_FULLSCAN_SEARCH then do a full table scan against +** the %_content table. +** +** If idxNum==FTS3_DOCID_SEARCH then do a docid lookup for a single entry +** in the %_content table. +** +** If idxNum>=FTS3_FULLTEXT_SEARCH then use the full text index. The +** column on the left-hand side of the MATCH operator is column +** number idxNum-FTS3_FULLTEXT_SEARCH, 0 indexed. argv[0] is the right-hand +** side of the MATCH operator. +*/ +static int fts3FilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *idxStr, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + int rc = SQLITE_OK; + char *zSql; /* SQL statement used to access %_content */ + int eSearch; + Fts3Table *p = (Fts3Table *)pCursor->pVtab; + Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; + + sqlite3_value *pCons = 0; /* The MATCH or rowid constraint, if any */ + sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */ + sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */ + sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */ + int iIdx; + + UNUSED_PARAMETER(idxStr); + UNUSED_PARAMETER(nVal); + + eSearch = (idxNum & 0x0000FFFF); + assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); + assert( p->pSegments==0 ); + + /* Collect arguments into local variables */ + iIdx = 0; + if( eSearch!=FTS3_FULLSCAN_SEARCH ) pCons = apVal[iIdx++]; + if( idxNum & FTS3_HAVE_LANGID ) pLangid = apVal[iIdx++]; + if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++]; + if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++]; + assert( iIdx==nVal ); + + /* In case the cursor has been used before, clear it now. */ + fts3CursorFinalizeStmt(pCsr); + sqlite3_free(pCsr->aDoclist); + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + sqlite3Fts3ExprFree(pCsr->pExpr); + memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); + + /* Set the lower and upper bounds on docids to return */ + pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); + pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64); + + if( idxStr ){ + pCsr->bDesc = (idxStr[0]=='D'); + }else{ + pCsr->bDesc = p->bDescIdx; + } + pCsr->eSearch = (i16)eSearch; + + if( eSearch!=FTS3_DOCID_SEARCH && eSearch!=FTS3_FULLSCAN_SEARCH ){ + int iCol = eSearch-FTS3_FULLTEXT_SEARCH; + const char *zQuery = (const char *)sqlite3_value_text(pCons); + + if( zQuery==0 && sqlite3_value_type(pCons)!=SQLITE_NULL ){ + return SQLITE_NOMEM; + } + + pCsr->iLangid = 0; + if( pLangid ) pCsr->iLangid = sqlite3_value_int(pLangid); + + assert( p->base.zErrMsg==0 ); + rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, + p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, + &p->base.zErrMsg + ); + if( rc!=SQLITE_OK ){ + return rc; + } + + rc = fts3EvalStart(pCsr); + sqlite3Fts3SegmentsClose(p); + if( rc!=SQLITE_OK ) return rc; + pCsr->pNextId = pCsr->aDoclist; + pCsr->iPrevId = 0; + } + + /* Compile a SELECT statement for this cursor. For a full-table-scan, the + ** statement loops through all rows of the %_content table. For a + ** full-text query or docid lookup, the statement retrieves a single + ** row by docid. + */ + if( eSearch==FTS3_FULLSCAN_SEARCH ){ + if( pDocidGe || pDocidLe ){ + zSql = sqlite3_mprintf( + "SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s", + p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid, + (pCsr->bDesc ? "DESC" : "ASC") + ); + }else{ + zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", + p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") + ); + } + if( zSql ){ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + }else if( eSearch==FTS3_DOCID_SEARCH ){ + rc = fts3CursorSeekStmt(pCsr); + if( rc==SQLITE_OK ){ + rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons); + } + } + if( rc!=SQLITE_OK ) return rc; + + return fts3NextMethod(pCursor); +} + +/* +** This is the xEof method of the virtual table. SQLite calls this +** routine to find out if it has reached the end of a result set. +*/ +static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){ + return ((Fts3Cursor *)pCursor)->isEof; +} + +/* +** This is the xRowid method. The SQLite core calls this routine to +** retrieve the rowid for the current row of the result set. fts3 +** exposes %_content.docid as the rowid for the virtual table. The +** rowid should be written to *pRowid. +*/ +static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; + *pRowid = pCsr->iPrevId; + return SQLITE_OK; +} + +/* +** This is the xColumn method, called by SQLite to request a value from +** the row that the supplied cursor currently points to. +** +** If: +** +** (iCol < p->nColumn) -> The value of the iCol'th user column. +** (iCol == p->nColumn) -> Magic column with the same name as the table. +** (iCol == p->nColumn+1) -> Docid column +** (iCol == p->nColumn+2) -> Langid column +*/ +static int fts3ColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ +){ + int rc = SQLITE_OK; /* Return Code */ + Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; + Fts3Table *p = (Fts3Table *)pCursor->pVtab; + + /* The column value supplied by SQLite must be in range. */ + assert( iCol>=0 && iCol<=p->nColumn+2 ); + + switch( iCol-p->nColumn ){ + case 0: + /* The special 'table-name' column */ + sqlite3_result_blob(pCtx, &pCsr, sizeof(Fts3Cursor*), SQLITE_TRANSIENT); + sqlite3_result_subtype(pCtx, SQLITE_BLOB); + break; + + case 1: + /* The docid column */ + sqlite3_result_int64(pCtx, pCsr->iPrevId); + break; + + case 2: + if( pCsr->pExpr ){ + sqlite3_result_int64(pCtx, pCsr->iLangid); + break; + }else if( p->zLanguageid==0 ){ + sqlite3_result_int(pCtx, 0); + break; + }else{ + iCol = p->nColumn; + /* fall-through */ + } + + default: + /* A user column. Or, if this is a full-table scan, possibly the + ** language-id column. Seek the cursor. */ + rc = fts3CursorSeek(0, pCsr); + if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){ + sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); + } + break; + } + + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + return rc; +} + +/* +** This function is the implementation of the xUpdate callback used by +** FTS3 virtual tables. It is invoked by SQLite each time a row is to be +** inserted, updated or deleted. +*/ +static int fts3UpdateMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nArg, /* Size of argument array */ + sqlite3_value **apVal, /* Array of arguments */ + sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ +){ + return sqlite3Fts3UpdateMethod(pVtab, nArg, apVal, pRowid); +} + +/* +** Implementation of xSync() method. Flush the contents of the pending-terms +** hash-table to the database. +*/ +static int fts3SyncMethod(sqlite3_vtab *pVtab){ + + /* Following an incremental-merge operation, assuming that the input + ** segments are not completely consumed (the usual case), they are updated + ** in place to remove the entries that have already been merged. This + ** involves updating the leaf block that contains the smallest unmerged + ** entry and each block (if any) between the leaf and the root node. So + ** if the height of the input segment b-trees is N, and input segments + ** are merged eight at a time, updating the input segments at the end + ** of an incremental-merge requires writing (8*(1+N)) blocks. N is usually + ** small - often between 0 and 2. So the overhead of the incremental + ** merge is somewhere between 8 and 24 blocks. To avoid this overhead + ** dwarfing the actual productive work accomplished, the incremental merge + ** is only attempted if it will write at least 64 leaf blocks. Hence + ** nMinMerge. + ** + ** Of course, updating the input segments also involves deleting a bunch + ** of blocks from the segments table. But this is not considered overhead + ** as it would also be required by a crisis-merge that used the same input + ** segments. + */ + const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */ + + Fts3Table *p = (Fts3Table*)pVtab; + int rc; + i64 iLastRowid = sqlite3_last_insert_rowid(p->db); + + rc = sqlite3Fts3PendingTermsFlush(p); + if( rc==SQLITE_OK + && p->nLeafAdd>(nMinMerge/16) + && p->nAutoincrmerge && p->nAutoincrmerge!=0xff + ){ + int mxLevel = 0; /* Maximum relative level value in db */ + int A; /* Incr-merge parameter A */ + + rc = sqlite3Fts3MaxLevel(p, &mxLevel); + assert( rc==SQLITE_OK || mxLevel==0 ); + A = p->nLeafAdd * mxLevel; + A += (A/2); + if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); + } + sqlite3Fts3SegmentsClose(p); + sqlite3_set_last_insert_rowid(p->db, iLastRowid); + return rc; +} + +/* +** If it is currently unknown whether or not the FTS table has an %_stat +** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat +** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code +** if an error occurs. +*/ +static int fts3SetHasStat(Fts3Table *p){ + int rc = SQLITE_OK; + if( p->bHasStat==2 ){ + char *zTbl = sqlite3_mprintf("%s_stat", p->zName); + if( zTbl ){ + int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0); + sqlite3_free(zTbl); + p->bHasStat = (res==SQLITE_OK); + }else{ + rc = SQLITE_NOMEM; + } + } + return rc; +} + +/* +** Implementation of xBegin() method. +*/ +static int fts3BeginMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table*)pVtab; + UNUSED_PARAMETER(pVtab); + assert( p->pSegments==0 ); + assert( p->nPendingData==0 ); + assert( p->inTransaction!=1 ); + TESTONLY( p->inTransaction = 1 ); + TESTONLY( p->mxSavepoint = -1; ); + p->nLeafAdd = 0; + return fts3SetHasStat(p); +} + +/* +** Implementation of xCommit() method. This is a no-op. The contents of +** the pending-terms hash-table have already been flushed into the database +** by fts3SyncMethod(). +*/ +static int fts3CommitMethod(sqlite3_vtab *pVtab){ + TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); + UNUSED_PARAMETER(pVtab); + assert( p->nPendingData==0 ); + assert( p->inTransaction!=0 ); + assert( p->pSegments==0 ); + TESTONLY( p->inTransaction = 0 ); + TESTONLY( p->mxSavepoint = -1; ); + return SQLITE_OK; +} + +/* +** Implementation of xRollback(). Discard the contents of the pending-terms +** hash-table. Any changes made to the database are reverted by SQLite. +*/ +static int fts3RollbackMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table*)pVtab; + sqlite3Fts3PendingTermsClear(p); + assert( p->inTransaction!=0 ); + TESTONLY( p->inTransaction = 0 ); + TESTONLY( p->mxSavepoint = -1; ); + return SQLITE_OK; +} + +/* +** When called, *ppPoslist must point to the byte immediately following the +** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function +** moves *ppPoslist so that it instead points to the first byte of the +** same position list. +*/ +static void fts3ReversePoslist(char *pStart, char **ppPoslist){ + char *p = &(*ppPoslist)[-2]; + char c = 0; + + /* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */ + while( p>pStart && (c=*p--)==0 ); + + /* Search backwards for a varint with value zero (the end of the previous + ** poslist). This is an 0x00 byte preceded by some byte that does not + ** have the 0x80 bit set. */ + while( p>pStart && (*p & 0x80) | c ){ + c = *p--; + } + assert( p==pStart || c==0 ); + + /* At this point p points to that preceding byte without the 0x80 bit + ** set. So to find the start of the poslist, skip forward 2 bytes then + ** over a varint. + ** + ** Normally. The other case is that p==pStart and the poslist to return + ** is the first in the doclist. In this case do not skip forward 2 bytes. + ** The second part of the if condition (c==0 && *ppPoslist>&p[2]) + ** is required for cases where the first byte of a doclist and the + ** doclist is empty. For example, if the first docid is 10, a doclist + ** that begins with: + ** + ** 0x0A 0x00 + */ + if( p>pStart || (c==0 && *ppPoslist>&p[2]) ){ p = &p[2]; } + while( *p++&0x80 ); + *ppPoslist = p; +} + +/* +** Helper function used by the implementation of the overloaded snippet(), +** offsets() and optimize() SQL functions. +** +** If the value passed as the third argument is a blob of size +** sizeof(Fts3Cursor*), then the blob contents are copied to the +** output variable *ppCsr and SQLITE_OK is returned. Otherwise, an error +** message is written to context pContext and SQLITE_ERROR returned. The +** string passed via zFunc is used as part of the error message. +*/ +static int fts3FunctionArg( + sqlite3_context *pContext, /* SQL function call context */ + const char *zFunc, /* Function name */ + sqlite3_value *pVal, /* argv[0] passed to function */ + Fts3Cursor **ppCsr /* OUT: Store cursor handle here */ +){ + int rc = SQLITE_OK; + if( sqlite3_value_subtype(pVal)==SQLITE_BLOB ){ + *ppCsr = *(Fts3Cursor**)sqlite3_value_blob(pVal); + }else{ + char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc); + sqlite3_result_error(pContext, zErr, -1); + sqlite3_free(zErr); + rc = SQLITE_ERROR; + } + return rc; +} + +/* +** Implementation of the snippet() function for FTS3 +*/ +static void fts3SnippetFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of apVal[] array */ + sqlite3_value **apVal /* Array of arguments */ +){ + Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ + const char *zStart = ""; + const char *zEnd = ""; + const char *zEllipsis = "..."; + int iCol = -1; + int nToken = 15; /* Default number of tokens in snippet */ + + /* There must be at least one argument passed to this function (otherwise + ** the non-overloaded version would have been called instead of this one). + */ + assert( nVal>=1 ); + + if( nVal>6 ){ + sqlite3_result_error(pContext, + "wrong number of arguments to function snippet()", -1); + return; + } + if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return; + + switch( nVal ){ + case 6: nToken = sqlite3_value_int(apVal[5]); + case 5: iCol = sqlite3_value_int(apVal[4]); + case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); + case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]); + case 2: zStart = (const char*)sqlite3_value_text(apVal[1]); + } + if( !zEllipsis || !zEnd || !zStart ){ + sqlite3_result_error_nomem(pContext); + }else if( nToken==0 ){ + sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); + }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ + sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken); + } +} + +/* +** Implementation of the offsets() function for FTS3 +*/ +static void fts3OffsetsFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of argument array */ + sqlite3_value **apVal /* Array of arguments */ +){ + Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ + + UNUSED_PARAMETER(nVal); + + assert( nVal==1 ); + if( fts3FunctionArg(pContext, "offsets", apVal[0], &pCsr) ) return; + assert( pCsr ); + if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ + sqlite3Fts3Offsets(pContext, pCsr); + } +} + +/* +** Implementation of the special optimize() function for FTS3. This +** function merges all segments in the database to a single segment. +** Example usage is: +** +** SELECT optimize(t) FROM t LIMIT 1; +** +** where 't' is the name of an FTS3 table. +*/ +static void fts3OptimizeFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of argument array */ + sqlite3_value **apVal /* Array of arguments */ +){ + int rc; /* Return code */ + Fts3Table *p; /* Virtual table handle */ + Fts3Cursor *pCursor; /* Cursor handle passed through apVal[0] */ + + UNUSED_PARAMETER(nVal); + + assert( nVal==1 ); + if( fts3FunctionArg(pContext, "optimize", apVal[0], &pCursor) ) return; + p = (Fts3Table *)pCursor->base.pVtab; + assert( p ); + + rc = sqlite3Fts3Optimize(p); + + switch( rc ){ + case SQLITE_OK: + sqlite3_result_text(pContext, "Index optimized", -1, SQLITE_STATIC); + break; + case SQLITE_DONE: + sqlite3_result_text(pContext, "Index already optimal", -1, SQLITE_STATIC); + break; + default: + sqlite3_result_error_code(pContext, rc); + break; + } +} + +/* +** Implementation of the matchinfo() function for FTS3 +*/ +static void fts3MatchinfoFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of argument array */ + sqlite3_value **apVal /* Array of arguments */ +){ + Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ + assert( nVal==1 || nVal==2 ); + if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){ + const char *zArg = 0; + if( nVal>1 ){ + zArg = (const char *)sqlite3_value_text(apVal[1]); + } + sqlite3Fts3Matchinfo(pContext, pCsr, zArg); + } +} + +/* +** This routine implements the xFindFunction method for the FTS3 +** virtual table. +*/ +static int fts3FindFunctionMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nArg, /* Number of SQL function arguments */ + const char *zName, /* Name of SQL function */ + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ + void **ppArg /* Unused */ +){ + struct Overloaded { + const char *zName; + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } aOverload[] = { + { "snippet", fts3SnippetFunc }, + { "offsets", fts3OffsetsFunc }, + { "optimize", fts3OptimizeFunc }, + { "matchinfo", fts3MatchinfoFunc }, + }; + int i; /* Iterator variable */ + + UNUSED_PARAMETER(pVtab); + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(ppArg); + + for(i=0; idb; /* Database connection */ + int rc; /* Return Code */ + + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + rc = fts3SetHasStat(p); + + /* As it happens, the pending terms table is always empty here. This is + ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction + ** always opens a savepoint transaction. And the xSavepoint() method + ** flushes the pending terms table. But leave the (no-op) call to + ** PendingTermsFlush() in in case that changes. + */ + assert( p->nPendingData==0 ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3PendingTermsFlush(p); + } + + if( p->zContentTbl==0 ){ + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", + p->zDb, p->zName, zName + ); + } + + if( p->bHasDocsize ){ + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", + p->zDb, p->zName, zName + ); + } + if( p->bHasStat ){ + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_stat' RENAME TO '%q_stat';", + p->zDb, p->zName, zName + ); + } + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';", + p->zDb, p->zName, zName + ); + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", + p->zDb, p->zName, zName + ); + return rc; +} + +/* +** The xSavepoint() method. +** +** Flush the contents of the pending-terms table to disk. +*/ +static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ + int rc = SQLITE_OK; + UNUSED_PARAMETER(iSavepoint); + assert( ((Fts3Table *)pVtab)->inTransaction ); + assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint ); + TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint ); + if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){ + rc = fts3SyncMethod(pVtab); + } + return rc; +} + +/* +** The xRelease() method. +** +** This is a no-op. +*/ +static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ + TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); + UNUSED_PARAMETER(iSavepoint); + UNUSED_PARAMETER(pVtab); + assert( p->inTransaction ); + assert( p->mxSavepoint >= iSavepoint ); + TESTONLY( p->mxSavepoint = iSavepoint-1 ); + return SQLITE_OK; +} + +/* +** The xRollbackTo() method. +** +** Discard the contents of the pending terms table. +*/ +static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts3Table *p = (Fts3Table*)pVtab; + UNUSED_PARAMETER(iSavepoint); + assert( p->inTransaction ); + assert( p->mxSavepoint >= iSavepoint ); + TESTONLY( p->mxSavepoint = iSavepoint ); + sqlite3Fts3PendingTermsClear(p); + return SQLITE_OK; +} + +static const sqlite3_module fts3Module = { + /* iVersion */ 2, + /* xCreate */ fts3CreateMethod, + /* xConnect */ fts3ConnectMethod, + /* xBestIndex */ fts3BestIndexMethod, + /* xDisconnect */ fts3DisconnectMethod, + /* xDestroy */ fts3DestroyMethod, + /* xOpen */ fts3OpenMethod, + /* xClose */ fts3CloseMethod, + /* xFilter */ fts3FilterMethod, + /* xNext */ fts3NextMethod, + /* xEof */ fts3EofMethod, + /* xColumn */ fts3ColumnMethod, + /* xRowid */ fts3RowidMethod, + /* xUpdate */ fts3UpdateMethod, + /* xBegin */ fts3BeginMethod, + /* xSync */ fts3SyncMethod, + /* xCommit */ fts3CommitMethod, + /* xRollback */ fts3RollbackMethod, + /* xFindFunction */ fts3FindFunctionMethod, + /* xRename */ fts3RenameMethod, + /* xSavepoint */ fts3SavepointMethod, + /* xRelease */ fts3ReleaseMethod, + /* xRollbackTo */ fts3RollbackToMethod, +}; + +/* +** This function is registered as the module destructor (called when an +** FTS3 enabled database connection is closed). It frees the memory +** allocated for the tokenizer hash table. +*/ +static void hashDestroy(void *p){ + Fts3Hash *pHash = (Fts3Hash *)p; + sqlite3Fts3HashClear(pHash); + sqlite3_free(pHash); +} + +/* +** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are +** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c +** respectively. The following three forward declarations are for functions +** declared in these files used to retrieve the respective implementations. +** +** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed +** to by the argument to point to the "simple" tokenizer implementation. +** And so on. +*/ +SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); +SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); +#ifndef SQLITE_DISABLE_FTS3_UNICODE +SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); +#endif +#ifdef SQLITE_ENABLE_ICU +SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); +#endif + +/* +** Initialize the fts3 extension. If this extension is built as part +** of the sqlite library, then this function is called directly by +** SQLite. If fts3 is built as a dynamically loadable extension, this +** function is called by the sqlite3_extension_init() entry point. +*/ +SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ + int rc = SQLITE_OK; + Fts3Hash *pHash = 0; + const sqlite3_tokenizer_module *pSimple = 0; + const sqlite3_tokenizer_module *pPorter = 0; +#ifndef SQLITE_DISABLE_FTS3_UNICODE + const sqlite3_tokenizer_module *pUnicode = 0; +#endif + +#ifdef SQLITE_ENABLE_ICU + const sqlite3_tokenizer_module *pIcu = 0; + sqlite3Fts3IcuTokenizerModule(&pIcu); +#endif + +#ifndef SQLITE_DISABLE_FTS3_UNICODE + sqlite3Fts3UnicodeTokenizer(&pUnicode); +#endif + +#ifdef SQLITE_TEST + rc = sqlite3Fts3InitTerm(db); + if( rc!=SQLITE_OK ) return rc; +#endif + + rc = sqlite3Fts3InitAux(db); + if( rc!=SQLITE_OK ) return rc; + + sqlite3Fts3SimpleTokenizerModule(&pSimple); + sqlite3Fts3PorterTokenizerModule(&pPorter); + + /* Allocate and initialize the hash-table used to store tokenizers. */ + pHash = sqlite3_malloc(sizeof(Fts3Hash)); + if( !pHash ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); + } + + /* Load the built-in tokenizers into the hash table */ + if( rc==SQLITE_OK ){ + if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple) + || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter) + +#ifndef SQLITE_DISABLE_FTS3_UNICODE + || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode) +#endif +#ifdef SQLITE_ENABLE_ICU + || (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu)) +#endif + ){ + rc = SQLITE_NOMEM; + } + } + +#ifdef SQLITE_TEST + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3ExprInitTestInterface(db); + } +#endif + + /* Create the virtual table wrapper around the hash-table and overload + ** the four scalar functions. If this is successful, register the + ** module with sqlite. + */ + if( SQLITE_OK==rc + && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer")) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1)) + ){ + rc = sqlite3_create_module_v2( + db, "fts3", &fts3Module, (void *)pHash, hashDestroy + ); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_module_v2( + db, "fts4", &fts3Module, (void *)pHash, 0 + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3InitTok(db, (void *)pHash); + } + return rc; + } + + + /* An error has occurred. Delete the hash table and return the error code. */ + assert( rc!=SQLITE_OK ); + if( pHash ){ + sqlite3Fts3HashClear(pHash); + sqlite3_free(pHash); + } + return rc; +} + +/* +** Allocate an Fts3MultiSegReader for each token in the expression headed +** by pExpr. +** +** An Fts3SegReader object is a cursor that can seek or scan a range of +** entries within a single segment b-tree. An Fts3MultiSegReader uses multiple +** Fts3SegReader objects internally to provide an interface to seek or scan +** within the union of all segments of a b-tree. Hence the name. +** +** If the allocated Fts3MultiSegReader just seeks to a single entry in a +** segment b-tree (if the term is not a prefix or it is a prefix for which +** there exists prefix b-tree of the right length) then it may be traversed +** and merged incrementally. Otherwise, it has to be merged into an in-memory +** doclist and then traversed. +*/ +static void fts3EvalAllocateReaders( + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Allocate readers for this expression */ + int *pnToken, /* OUT: Total number of tokens in phrase. */ + int *pnOr, /* OUT: Total number of OR nodes in expr. */ + int *pRc /* IN/OUT: Error code */ +){ + if( pExpr && SQLITE_OK==*pRc ){ + if( pExpr->eType==FTSQUERY_PHRASE ){ + int i; + int nToken = pExpr->pPhrase->nToken; + *pnToken += nToken; + for(i=0; ipPhrase->aToken[i]; + int rc = fts3TermSegReaderCursor(pCsr, + pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr + ); + if( rc!=SQLITE_OK ){ + *pRc = rc; + return; + } + } + assert( pExpr->pPhrase->iDoclistToken==0 ); + pExpr->pPhrase->iDoclistToken = -1; + }else{ + *pnOr += (pExpr->eType==FTSQUERY_OR); + fts3EvalAllocateReaders(pCsr, pExpr->pLeft, pnToken, pnOr, pRc); + fts3EvalAllocateReaders(pCsr, pExpr->pRight, pnToken, pnOr, pRc); + } + } +} + +/* +** Arguments pList/nList contain the doclist for token iToken of phrase p. +** It is merged into the main doclist stored in p->doclist.aAll/nAll. +** +** This function assumes that pList points to a buffer allocated using +** sqlite3_malloc(). This function takes responsibility for eventually +** freeing the buffer. +** +** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs. +*/ +static int fts3EvalPhraseMergeToken( + Fts3Table *pTab, /* FTS Table pointer */ + Fts3Phrase *p, /* Phrase to merge pList/nList into */ + int iToken, /* Token pList/nList corresponds to */ + char *pList, /* Pointer to doclist */ + int nList /* Number of bytes in pList */ +){ + int rc = SQLITE_OK; + assert( iToken!=p->iDoclistToken ); + + if( pList==0 ){ + sqlite3_free(p->doclist.aAll); + p->doclist.aAll = 0; + p->doclist.nAll = 0; + } + + else if( p->iDoclistToken<0 ){ + p->doclist.aAll = pList; + p->doclist.nAll = nList; + } + + else if( p->doclist.aAll==0 ){ + sqlite3_free(pList); + } + + else { + char *pLeft; + char *pRight; + int nLeft; + int nRight; + int nDiff; + + if( p->iDoclistTokendoclist.aAll; + nLeft = p->doclist.nAll; + pRight = pList; + nRight = nList; + nDiff = iToken - p->iDoclistToken; + }else{ + pRight = p->doclist.aAll; + nRight = p->doclist.nAll; + pLeft = pList; + nLeft = nList; + nDiff = p->iDoclistToken - iToken; + } + + rc = fts3DoclistPhraseMerge( + pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight + ); + sqlite3_free(pLeft); + p->doclist.aAll = pRight; + p->doclist.nAll = nRight; + } + + if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken; + return rc; +} + +/* +** Load the doclist for phrase p into p->doclist.aAll/nAll. The loaded doclist +** does not take deferred tokens into account. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +*/ +static int fts3EvalPhraseLoad( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p /* Phrase object */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int iToken; + int rc = SQLITE_OK; + + for(iToken=0; rc==SQLITE_OK && iTokennToken; iToken++){ + Fts3PhraseToken *pToken = &p->aToken[iToken]; + assert( pToken->pDeferred==0 || pToken->pSegcsr==0 ); + + if( pToken->pSegcsr ){ + int nThis = 0; + char *pThis = 0; + rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis); + if( rc==SQLITE_OK ){ + rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis); + } + } + assert( pToken->pSegcsr==0 ); + } + + return rc; +} + +/* +** This function is called on each phrase after the position lists for +** any deferred tokens have been loaded into memory. It updates the phrases +** current position list to include only those positions that are really +** instances of the phrase (after considering deferred tokens). If this +** means that the phrase does not appear in the current row, doclist.pList +** and doclist.nList are both zeroed. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +*/ +static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ + int iToken; /* Used to iterate through phrase tokens */ + char *aPoslist = 0; /* Position list for deferred tokens */ + int nPoslist = 0; /* Number of bytes in aPoslist */ + int iPrev = -1; /* Token number of previous deferred token */ + + assert( pPhrase->doclist.bFreeList==0 ); + + for(iToken=0; iTokennToken; iToken++){ + Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; + Fts3DeferredToken *pDeferred = pToken->pDeferred; + + if( pDeferred ){ + char *pList; + int nList; + int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); + if( rc!=SQLITE_OK ) return rc; + + if( pList==0 ){ + sqlite3_free(aPoslist); + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + return SQLITE_OK; + + }else if( aPoslist==0 ){ + aPoslist = pList; + nPoslist = nList; + + }else{ + char *aOut = pList; + char *p1 = aPoslist; + char *p2 = aOut; + + assert( iPrev>=0 ); + fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2); + sqlite3_free(aPoslist); + aPoslist = pList; + nPoslist = (int)(aOut - aPoslist); + if( nPoslist==0 ){ + sqlite3_free(aPoslist); + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + return SQLITE_OK; + } + } + iPrev = iToken; + } + } + + if( iPrev>=0 ){ + int nMaxUndeferred = pPhrase->iDoclistToken; + if( nMaxUndeferred<0 ){ + pPhrase->doclist.pList = aPoslist; + pPhrase->doclist.nList = nPoslist; + pPhrase->doclist.iDocid = pCsr->iPrevId; + pPhrase->doclist.bFreeList = 1; + }else{ + int nDistance; + char *p1; + char *p2; + char *aOut; + + if( nMaxUndeferred>iPrev ){ + p1 = aPoslist; + p2 = pPhrase->doclist.pList; + nDistance = nMaxUndeferred - iPrev; + }else{ + p1 = pPhrase->doclist.pList; + p2 = aPoslist; + nDistance = iPrev - nMaxUndeferred; + } + + aOut = (char *)sqlite3_malloc(nPoslist+8); + if( !aOut ){ + sqlite3_free(aPoslist); + return SQLITE_NOMEM; + } + + pPhrase->doclist.pList = aOut; + if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){ + pPhrase->doclist.bFreeList = 1; + pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList); + }else{ + sqlite3_free(aOut); + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + } + sqlite3_free(aPoslist); + } + } + + return SQLITE_OK; +} + +/* +** Maximum number of tokens a phrase may have to be considered for the +** incremental doclists strategy. +*/ +#define MAX_INCR_PHRASE_TOKENS 4 + +/* +** This function is called for each Fts3Phrase in a full-text query +** expression to initialize the mechanism for returning rows. Once this +** function has been called successfully on an Fts3Phrase, it may be +** used with fts3EvalPhraseNext() to iterate through the matching docids. +** +** If parameter bOptOk is true, then the phrase may (or may not) use the +** incremental loading strategy. Otherwise, the entire doclist is loaded into +** memory within this call. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +*/ +static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; /* Error code */ + int i; + + /* Determine if doclists may be loaded from disk incrementally. This is + ** possible if the bOptOk argument is true, the FTS doclists will be + ** scanned in forward order, and the phrase consists of + ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first" + ** tokens or prefix tokens that cannot use a prefix-index. */ + int bHaveIncr = 0; + int bIncrOk = (bOptOk + && pCsr->bDesc==pTab->bDescIdx + && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 +#ifdef SQLITE_TEST + && pTab->bNoIncrDoclist==0 +#endif + ); + for(i=0; bIncrOk==1 && inToken; i++){ + Fts3PhraseToken *pToken = &p->aToken[i]; + if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){ + bIncrOk = 0; + } + if( pToken->pSegcsr ) bHaveIncr = 1; + } + + if( bIncrOk && bHaveIncr ){ + /* Use the incremental approach. */ + int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); + for(i=0; rc==SQLITE_OK && inToken; i++){ + Fts3PhraseToken *pToken = &p->aToken[i]; + Fts3MultiSegReader *pSegcsr = pToken->pSegcsr; + if( pSegcsr ){ + rc = sqlite3Fts3MsrIncrStart(pTab, pSegcsr, iCol, pToken->z, pToken->n); + } + } + p->bIncr = 1; + }else{ + /* Load the full doclist for the phrase into memory. */ + rc = fts3EvalPhraseLoad(pCsr, p); + p->bIncr = 0; + } + + assert( rc!=SQLITE_OK || p->nToken<1 || p->aToken[0].pSegcsr==0 || p->bIncr ); + return rc; +} + +/* +** This function is used to iterate backwards (from the end to start) +** through doclists. It is used by this module to iterate through phrase +** doclists in reverse and by the fts3_write.c module to iterate through +** pending-terms lists when writing to databases with "order=desc". +** +** The doclist may be sorted in ascending (parameter bDescIdx==0) or +** descending (parameter bDescIdx==1) order of docid. Regardless, this +** function iterates from the end of the doclist to the beginning. +*/ +SQLITE_PRIVATE void sqlite3Fts3DoclistPrev( + int bDescIdx, /* True if the doclist is desc */ + char *aDoclist, /* Pointer to entire doclist */ + int nDoclist, /* Length of aDoclist in bytes */ + char **ppIter, /* IN/OUT: Iterator pointer */ + sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ + int *pnList, /* OUT: List length pointer */ + u8 *pbEof /* OUT: End-of-file flag */ +){ + char *p = *ppIter; + + assert( nDoclist>0 ); + assert( *pbEof==0 ); + assert( p || *piDocid==0 ); + assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) ); + + if( p==0 ){ + sqlite3_int64 iDocid = 0; + char *pNext = 0; + char *pDocid = aDoclist; + char *pEnd = &aDoclist[nDoclist]; + int iMul = 1; + + while( pDocid0 ); + assert( *pbEof==0 ); + assert( p || *piDocid==0 ); + assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) ); + + if( p==0 ){ + p = aDoclist; + p += sqlite3Fts3GetVarint(p, piDocid); + }else{ + fts3PoslistCopy(0, &p); + while( p<&aDoclist[nDoclist] && *p==0 ) p++; + if( p>=&aDoclist[nDoclist] ){ + *pbEof = 1; + }else{ + sqlite3_int64 iVar; + p += sqlite3Fts3GetVarint(p, &iVar); + *piDocid += ((bDescIdx ? -1 : 1) * iVar); + } + } + + *ppIter = p; +} + +/* +** Advance the iterator pDL to the next entry in pDL->aAll/nAll. Set *pbEof +** to true if EOF is reached. +*/ +static void fts3EvalDlPhraseNext( + Fts3Table *pTab, + Fts3Doclist *pDL, + u8 *pbEof +){ + char *pIter; /* Used to iterate through aAll */ + char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */ + + if( pDL->pNextDocid ){ + pIter = pDL->pNextDocid; + }else{ + pIter = pDL->aAll; + } + + if( pIter>=pEnd ){ + /* We have already reached the end of this doclist. EOF. */ + *pbEof = 1; + }else{ + sqlite3_int64 iDelta; + pIter += sqlite3Fts3GetVarint(pIter, &iDelta); + if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){ + pDL->iDocid += iDelta; + }else{ + pDL->iDocid -= iDelta; + } + pDL->pList = pIter; + fts3PoslistCopy(0, &pIter); + pDL->nList = (int)(pIter - pDL->pList); + + /* pIter now points just past the 0x00 that terminates the position- + ** list for document pDL->iDocid. However, if this position-list was + ** edited in place by fts3EvalNearTrim(), then pIter may not actually + ** point to the start of the next docid value. The following line deals + ** with this case by advancing pIter past the zero-padding added by + ** fts3EvalNearTrim(). */ + while( pIterpNextDocid = pIter; + assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter ); + *pbEof = 0; + } +} + +/* +** Helper type used by fts3EvalIncrPhraseNext() and incrPhraseTokenNext(). +*/ +typedef struct TokenDoclist TokenDoclist; +struct TokenDoclist { + int bIgnore; + sqlite3_int64 iDocid; + char *pList; + int nList; +}; + +/* +** Token pToken is an incrementally loaded token that is part of a +** multi-token phrase. Advance it to the next matching document in the +** database and populate output variable *p with the details of the new +** entry. Or, if the iterator has reached EOF, set *pbEof to true. +** +** If an error occurs, return an SQLite error code. Otherwise, return +** SQLITE_OK. +*/ +static int incrPhraseTokenNext( + Fts3Table *pTab, /* Virtual table handle */ + Fts3Phrase *pPhrase, /* Phrase to advance token of */ + int iToken, /* Specific token to advance */ + TokenDoclist *p, /* OUT: Docid and doclist for new entry */ + u8 *pbEof /* OUT: True if iterator is at EOF */ +){ + int rc = SQLITE_OK; + + if( pPhrase->iDoclistToken==iToken ){ + assert( p->bIgnore==0 ); + assert( pPhrase->aToken[iToken].pSegcsr==0 ); + fts3EvalDlPhraseNext(pTab, &pPhrase->doclist, pbEof); + p->pList = pPhrase->doclist.pList; + p->nList = pPhrase->doclist.nList; + p->iDocid = pPhrase->doclist.iDocid; + }else{ + Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; + assert( pToken->pDeferred==0 ); + assert( pToken->pSegcsr || pPhrase->iDoclistToken>=0 ); + if( pToken->pSegcsr ){ + assert( p->bIgnore==0 ); + rc = sqlite3Fts3MsrIncrNext( + pTab, pToken->pSegcsr, &p->iDocid, &p->pList, &p->nList + ); + if( p->pList==0 ) *pbEof = 1; + }else{ + p->bIgnore = 1; + } + } + + return rc; +} + + +/* +** The phrase iterator passed as the second argument: +** +** * features at least one token that uses an incremental doclist, and +** +** * does not contain any deferred tokens. +** +** Advance it to the next matching documnent in the database and populate +** the Fts3Doclist.pList and nList fields. +** +** If there is no "next" entry and no error occurs, then *pbEof is set to +** 1 before returning. Otherwise, if no error occurs and the iterator is +** successfully advanced, *pbEof is set to 0. +** +** If an error occurs, return an SQLite error code. Otherwise, return +** SQLITE_OK. +*/ +static int fts3EvalIncrPhraseNext( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p, /* Phrase object to advance to next docid */ + u8 *pbEof /* OUT: Set to 1 if EOF */ +){ + int rc = SQLITE_OK; + Fts3Doclist *pDL = &p->doclist; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + u8 bEof = 0; + + /* This is only called if it is guaranteed that the phrase has at least + ** one incremental token. In which case the bIncr flag is set. */ + assert( p->bIncr==1 ); + + if( p->nToken==1 ){ + rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, + &pDL->iDocid, &pDL->pList, &pDL->nList + ); + if( pDL->pList==0 ) bEof = 1; + }else{ + int bDescDoclist = pCsr->bDesc; + struct TokenDoclist a[MAX_INCR_PHRASE_TOKENS]; + + memset(a, 0, sizeof(a)); + assert( p->nToken<=MAX_INCR_PHRASE_TOKENS ); + assert( p->iDoclistTokennToken && bEof==0; i++){ + rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); + if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){ + iMax = a[i].iDocid; + bMaxSet = 1; + } + } + assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) ); + assert( rc!=SQLITE_OK || bMaxSet ); + + /* Keep advancing iterators until they all point to the same document */ + for(i=0; inToken; i++){ + while( rc==SQLITE_OK && bEof==0 + && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0 + ){ + rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); + if( DOCID_CMP(a[i].iDocid, iMax)>0 ){ + iMax = a[i].iDocid; + i = 0; + } + } + } + + /* Check if the current entries really are a phrase match */ + if( bEof==0 ){ + int nList = 0; + int nByte = a[p->nToken-1].nList; + char *aDoclist = sqlite3_malloc(nByte+1); + if( !aDoclist ) return SQLITE_NOMEM; + memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); + + for(i=0; i<(p->nToken-1); i++){ + if( a[i].bIgnore==0 ){ + char *pL = a[i].pList; + char *pR = aDoclist; + char *pOut = aDoclist; + int nDist = p->nToken-1-i; + int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR); + if( res==0 ) break; + nList = (int)(pOut - aDoclist); + } + } + if( i==(p->nToken-1) ){ + pDL->iDocid = iMax; + pDL->pList = aDoclist; + pDL->nList = nList; + pDL->bFreeList = 1; + break; + } + sqlite3_free(aDoclist); + } + } + } + + *pbEof = bEof; + return rc; +} + +/* +** Attempt to move the phrase iterator to point to the next matching docid. +** If an error occurs, return an SQLite error code. Otherwise, return +** SQLITE_OK. +** +** If there is no "next" entry and no error occurs, then *pbEof is set to +** 1 before returning. Otherwise, if no error occurs and the iterator is +** successfully advanced, *pbEof is set to 0. +*/ +static int fts3EvalPhraseNext( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p, /* Phrase object to advance to next docid */ + u8 *pbEof /* OUT: Set to 1 if EOF */ +){ + int rc = SQLITE_OK; + Fts3Doclist *pDL = &p->doclist; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + + if( p->bIncr ){ + rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof); + }else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){ + sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll, + &pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof + ); + pDL->pList = pDL->pNextDocid; + }else{ + fts3EvalDlPhraseNext(pTab, pDL, pbEof); + } + + return rc; +} + +/* +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, fts3EvalPhraseStart() is called on all phrases within the +** expression. Also the Fts3Expr.bDeferred variable is set to true for any +** expressions for which all descendent tokens are deferred. +** +** If parameter bOptOk is zero, then it is guaranteed that the +** Fts3Phrase.doclist.aAll/nAll variables contain the entire doclist for +** each phrase in the expression (subject to deferred token processing). +** Or, if bOptOk is non-zero, then one or more tokens within the expression +** may be loaded incrementally, meaning doclist.aAll/nAll is not available. +** +** If an error occurs within this function, *pRc is set to an SQLite error +** code before returning. +*/ +static void fts3EvalStartReaders( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pExpr, /* Expression to initialize phrases in */ + int *pRc /* IN/OUT: Error code */ +){ + if( pExpr && SQLITE_OK==*pRc ){ + if( pExpr->eType==FTSQUERY_PHRASE ){ + int nToken = pExpr->pPhrase->nToken; + if( nToken ){ + int i; + for(i=0; ipPhrase->aToken[i].pDeferred==0 ) break; + } + pExpr->bDeferred = (i==nToken); + } + *pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase); + }else{ + fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc); + fts3EvalStartReaders(pCsr, pExpr->pRight, pRc); + pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred); + } + } +} + +/* +** An array of the following structures is assembled as part of the process +** of selecting tokens to defer before the query starts executing (as part +** of the xFilter() method). There is one element in the array for each +** token in the FTS expression. +** +** Tokens are divided into AND/NEAR clusters. All tokens in a cluster belong +** to phrases that are connected only by AND and NEAR operators (not OR or +** NOT). When determining tokens to defer, each AND/NEAR cluster is considered +** separately. The root of a tokens AND/NEAR cluster is stored in +** Fts3TokenAndCost.pRoot. +*/ +typedef struct Fts3TokenAndCost Fts3TokenAndCost; +struct Fts3TokenAndCost { + Fts3Phrase *pPhrase; /* The phrase the token belongs to */ + int iToken; /* Position of token in phrase */ + Fts3PhraseToken *pToken; /* The token itself */ + Fts3Expr *pRoot; /* Root of NEAR/AND cluster */ + int nOvfl; /* Number of overflow pages to load doclist */ + int iCol; /* The column the token must match */ +}; + +/* +** This function is used to populate an allocated Fts3TokenAndCost array. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, if an error occurs during execution, *pRc is set to an +** SQLite error code. +*/ +static void fts3EvalTokenCosts( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pRoot, /* Root of current AND/NEAR cluster */ + Fts3Expr *pExpr, /* Expression to consider */ + Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ + Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ + int *pRc /* IN/OUT: Error code */ +){ + if( *pRc==SQLITE_OK ){ + if( pExpr->eType==FTSQUERY_PHRASE ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + int i; + for(i=0; *pRc==SQLITE_OK && inToken; i++){ + Fts3TokenAndCost *pTC = (*ppTC)++; + pTC->pPhrase = pPhrase; + pTC->iToken = i; + pTC->pRoot = pRoot; + pTC->pToken = &pPhrase->aToken[i]; + pTC->iCol = pPhrase->iColumn; + *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); + } + }else if( pExpr->eType!=FTSQUERY_NOT ){ + assert( pExpr->eType==FTSQUERY_OR + || pExpr->eType==FTSQUERY_AND + || pExpr->eType==FTSQUERY_NEAR + ); + assert( pExpr->pLeft && pExpr->pRight ); + if( pExpr->eType==FTSQUERY_OR ){ + pRoot = pExpr->pLeft; + **ppOr = pRoot; + (*ppOr)++; + } + fts3EvalTokenCosts(pCsr, pRoot, pExpr->pLeft, ppTC, ppOr, pRc); + if( pExpr->eType==FTSQUERY_OR ){ + pRoot = pExpr->pRight; + **ppOr = pRoot; + (*ppOr)++; + } + fts3EvalTokenCosts(pCsr, pRoot, pExpr->pRight, ppTC, ppOr, pRc); + } + } +} + +/* +** Determine the average document (row) size in pages. If successful, +** write this value to *pnPage and return SQLITE_OK. Otherwise, return +** an SQLite error code. +** +** The average document size in pages is calculated by first calculating +** determining the average size in bytes, B. If B is less than the amount +** of data that will fit on a single leaf page of an intkey table in +** this database, then the average docsize is 1. Otherwise, it is 1 plus +** the number of overflow pages consumed by a record B bytes in size. +*/ +static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ + int rc = SQLITE_OK; + if( pCsr->nRowAvg==0 ){ + /* The average document size, which is required to calculate the cost + ** of each doclist, has not yet been determined. Read the required + ** data from the %_stat table to calculate it. + ** + ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 + ** varints, where nCol is the number of columns in the FTS3 table. + ** The first varint is the number of documents currently stored in + ** the table. The following nCol varints contain the total amount of + ** data stored in all rows of each column of the table, from left + ** to right. + */ + Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; + sqlite3_stmt *pStmt; + sqlite3_int64 nDoc = 0; + sqlite3_int64 nByte = 0; + const char *pEnd; + const char *a; + + rc = sqlite3Fts3SelectDoctotal(p, &pStmt); + if( rc!=SQLITE_OK ) return rc; + a = sqlite3_column_blob(pStmt, 0); + assert( a ); + + pEnd = &a[sqlite3_column_bytes(pStmt, 0)]; + a += sqlite3Fts3GetVarint(a, &nDoc); + while( anDoc = nDoc; + pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz); + assert( pCsr->nRowAvg>0 ); + rc = sqlite3_reset(pStmt); + } + + *pnPage = pCsr->nRowAvg; + return rc; +} + +/* +** This function is called to select the tokens (if any) that will be +** deferred. The array aTC[] has already been populated when this is +** called. +** +** This function is called once for each AND/NEAR cluster in the +** expression. Each invocation determines which tokens to defer within +** the cluster with root node pRoot. See comments above the definition +** of struct Fts3TokenAndCost for more details. +** +** If no error occurs, SQLITE_OK is returned and sqlite3Fts3DeferToken() +** called on each token to defer. Otherwise, an SQLite error code is +** returned. +*/ +static int fts3EvalSelectDeferred( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pRoot, /* Consider tokens with this root node */ + Fts3TokenAndCost *aTC, /* Array of expression tokens and costs */ + int nTC /* Number of entries in aTC[] */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int nDocSize = 0; /* Number of pages per doc loaded */ + int rc = SQLITE_OK; /* Return code */ + int ii; /* Iterator variable for various purposes */ + int nOvfl = 0; /* Total overflow pages used by doclists */ + int nToken = 0; /* Total number of tokens in cluster */ + + int nMinEst = 0; /* The minimum count for any phrase so far. */ + int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ + + /* Tokens are never deferred for FTS tables created using the content=xxx + ** option. The reason being that it is not guaranteed that the content + ** table actually contains the same data as the index. To prevent this from + ** causing any problems, the deferred token optimization is completely + ** disabled for content=xxx tables. */ + if( pTab->zContentTbl ){ + return SQLITE_OK; + } + + /* Count the tokens in this AND/NEAR cluster. If none of the doclists + ** associated with the tokens spill onto overflow pages, or if there is + ** only 1 token, exit early. No tokens to defer in this case. */ + for(ii=0; ii0 ); + + + /* Iterate through all tokens in this AND/NEAR cluster, in ascending order + ** of the number of overflow pages that will be loaded by the pager layer + ** to retrieve the entire doclist for the token from the full-text index. + ** Load the doclists for tokens that are either: + ** + ** a. The cheapest token in the entire query (i.e. the one visited by the + ** first iteration of this loop), or + ** + ** b. Part of a multi-token phrase. + ** + ** After each token doclist is loaded, merge it with the others from the + ** same phrase and count the number of documents that the merged doclist + ** contains. Set variable "nMinEst" to the smallest number of documents in + ** any phrase doclist for which 1 or more token doclists have been loaded. + ** Let nOther be the number of other phrases for which it is certain that + ** one or more tokens will not be deferred. + ** + ** Then, for each token, defer it if loading the doclist would result in + ** loading N or more overflow pages into memory, where N is computed as: + ** + ** (nMinEst + 4^nOther - 1) / (4^nOther) + */ + for(ii=0; iinOvfl) + ){ + pTC = &aTC[iTC]; + } + } + assert( pTC ); + + if( ii && pTC->nOvfl>=((nMinEst+(nLoad4/4)-1)/(nLoad4/4))*nDocSize ){ + /* The number of overflow pages to load for this (and therefore all + ** subsequent) tokens is greater than the estimated number of pages + ** that will be loaded if all subsequent tokens are deferred. + */ + Fts3PhraseToken *pToken = pTC->pToken; + rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); + fts3SegReaderCursorFree(pToken->pSegcsr); + pToken->pSegcsr = 0; + }else{ + /* Set nLoad4 to the value of (4^nOther) for the next iteration of the + ** for-loop. Except, limit the value to 2^24 to prevent it from + ** overflowing the 32-bit integer it is stored in. */ + if( ii<12 ) nLoad4 = nLoad4*4; + + if( ii==0 || (pTC->pPhrase->nToken>1 && ii!=nToken-1) ){ + /* Either this is the cheapest token in the entire query, or it is + ** part of a multi-token phrase. Either way, the entire doclist will + ** (eventually) be loaded into memory. It may as well be now. */ + Fts3PhraseToken *pToken = pTC->pToken; + int nList = 0; + char *pList = 0; + rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList); + assert( rc==SQLITE_OK || pList==0 ); + if( rc==SQLITE_OK ){ + rc = fts3EvalPhraseMergeToken( + pTab, pTC->pPhrase, pTC->iToken,pList,nList + ); + } + if( rc==SQLITE_OK ){ + int nCount; + nCount = fts3DoclistCountDocids( + pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll + ); + if( ii==0 || nCountpToken = 0; + } + + return rc; +} + +/* +** This function is called from within the xFilter method. It initializes +** the full-text query currently stored in pCsr->pExpr. To iterate through +** the results of a query, the caller does: +** +** fts3EvalStart(pCsr); +** while( 1 ){ +** fts3EvalNext(pCsr); +** if( pCsr->bEof ) break; +** ... return row pCsr->iPrevId to the caller ... +** } +*/ +static int fts3EvalStart(Fts3Cursor *pCsr){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int nToken = 0; + int nOr = 0; + + /* Allocate a MultiSegReader for each token in the expression. */ + fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); + + /* Determine which, if any, tokens in the expression should be deferred. */ +#ifndef SQLITE_DISABLE_FTS4_DEFERRED + if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ + Fts3TokenAndCost *aTC; + Fts3Expr **apOr; + aTC = (Fts3TokenAndCost *)sqlite3_malloc( + sizeof(Fts3TokenAndCost) * nToken + + sizeof(Fts3Expr *) * nOr * 2 + ); + apOr = (Fts3Expr **)&aTC[nToken]; + + if( !aTC ){ + rc = SQLITE_NOMEM; + }else{ + int ii; + Fts3TokenAndCost *pTC = aTC; + Fts3Expr **ppOr = apOr; + + fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc); + nToken = (int)(pTC-aTC); + nOr = (int)(ppOr-apOr); + + if( rc==SQLITE_OK ){ + rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken); + for(ii=0; rc==SQLITE_OK && iipExpr, &rc); + return rc; +} + +/* +** Invalidate the current position list for phrase pPhrase. +*/ +static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){ + if( pPhrase->doclist.bFreeList ){ + sqlite3_free(pPhrase->doclist.pList); + } + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + pPhrase->doclist.bFreeList = 0; +} + +/* +** This function is called to edit the position list associated with +** the phrase object passed as the fifth argument according to a NEAR +** condition. For example: +** +** abc NEAR/5 "def ghi" +** +** Parameter nNear is passed the NEAR distance of the expression (5 in +** the example above). When this function is called, *paPoslist points to +** the position list, and *pnToken is the number of phrase tokens in, the +** phrase on the other side of the NEAR operator to pPhrase. For example, +** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to +** the position list associated with phrase "abc". +** +** All positions in the pPhrase position list that are not sufficiently +** close to a position in the *paPoslist position list are removed. If this +** leaves 0 positions, zero is returned. Otherwise, non-zero. +** +** Before returning, *paPoslist is set to point to the position lsit +** associated with pPhrase. And *pnToken is set to the number of tokens in +** pPhrase. +*/ +static int fts3EvalNearTrim( + int nNear, /* NEAR distance. As in "NEAR/nNear". */ + char *aTmp, /* Temporary space to use */ + char **paPoslist, /* IN/OUT: Position list */ + int *pnToken, /* IN/OUT: Tokens in phrase of *paPoslist */ + Fts3Phrase *pPhrase /* The phrase object to trim the doclist of */ +){ + int nParam1 = nNear + pPhrase->nToken; + int nParam2 = nNear + *pnToken; + int nNew; + char *p2; + char *pOut; + int res; + + assert( pPhrase->doclist.pList ); + + p2 = pOut = pPhrase->doclist.pList; + res = fts3PoslistNearMerge( + &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 + ); + if( res ){ + nNew = (int)(pOut - pPhrase->doclist.pList) - 1; + assert( pPhrase->doclist.pList[nNew]=='\0' ); + assert( nNew<=pPhrase->doclist.nList && nNew>0 ); + memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew); + pPhrase->doclist.nList = nNew; + *paPoslist = pPhrase->doclist.pList; + *pnToken = pPhrase->nToken; + } + + return res; +} + +/* +** This function is a no-op if *pRc is other than SQLITE_OK when it is called. +** Otherwise, it advances the expression passed as the second argument to +** point to the next matching row in the database. Expressions iterate through +** matching rows in docid order. Ascending order if Fts3Cursor.bDesc is zero, +** or descending if it is non-zero. +** +** If an error occurs, *pRc is set to an SQLite error code. Otherwise, if +** successful, the following variables in pExpr are set: +** +** Fts3Expr.bEof (non-zero if EOF - there is no next row) +** Fts3Expr.iDocid (valid if bEof==0. The docid of the next row) +** +** If the expression is of type FTSQUERY_PHRASE, and the expression is not +** at EOF, then the following variables are populated with the position list +** for the phrase for the visited row: +** +** FTs3Expr.pPhrase->doclist.nList (length of pList in bytes) +** FTs3Expr.pPhrase->doclist.pList (pointer to position list) +** +** It says above that this function advances the expression to the next +** matching row. This is usually true, but there are the following exceptions: +** +** 1. Deferred tokens are not taken into account. If a phrase consists +** entirely of deferred tokens, it is assumed to match every row in +** the db. In this case the position-list is not populated at all. +** +** Or, if a phrase contains one or more deferred tokens and one or +** more non-deferred tokens, then the expression is advanced to the +** next possible match, considering only non-deferred tokens. In other +** words, if the phrase is "A B C", and "B" is deferred, the expression +** is advanced to the next row that contains an instance of "A * C", +** where "*" may match any single token. The position list in this case +** is populated as for "A * C" before returning. +** +** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is +** advanced to point to the next row that matches "x AND y". +** +** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is +** really a match, taking into account deferred tokens and NEAR operators. +*/ +static void fts3EvalNextRow( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pExpr, /* Expr. to advance to next matching row */ + int *pRc /* IN/OUT: Error code */ +){ + if( *pRc==SQLITE_OK ){ + int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */ + assert( pExpr->bEof==0 ); + pExpr->bStart = 1; + + switch( pExpr->eType ){ + case FTSQUERY_NEAR: + case FTSQUERY_AND: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + assert( !pLeft->bDeferred || !pRight->bDeferred ); + + if( pLeft->bDeferred ){ + /* LHS is entirely deferred. So we assume it matches every row. + ** Advance the RHS iterator to find the next row visited. */ + fts3EvalNextRow(pCsr, pRight, pRc); + pExpr->iDocid = pRight->iDocid; + pExpr->bEof = pRight->bEof; + }else if( pRight->bDeferred ){ + /* RHS is entirely deferred. So we assume it matches every row. + ** Advance the LHS iterator to find the next row visited. */ + fts3EvalNextRow(pCsr, pLeft, pRc); + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = pLeft->bEof; + }else{ + /* Neither the RHS or LHS are deferred. */ + fts3EvalNextRow(pCsr, pLeft, pRc); + fts3EvalNextRow(pCsr, pRight, pRc); + while( !pLeft->bEof && !pRight->bEof && *pRc==SQLITE_OK ){ + sqlite3_int64 iDiff = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + if( iDiff==0 ) break; + if( iDiff<0 ){ + fts3EvalNextRow(pCsr, pLeft, pRc); + }else{ + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = (pLeft->bEof || pRight->bEof); + if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){ + assert( pRight->eType==FTSQUERY_PHRASE ); + if( pRight->pPhrase->doclist.aAll ){ + Fts3Doclist *pDl = &pRight->pPhrase->doclist; + while( *pRc==SQLITE_OK && pRight->bEof==0 ){ + memset(pDl->pList, 0, pDl->nList); + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){ + Fts3Doclist *pDl = &pLeft->pPhrase->doclist; + while( *pRc==SQLITE_OK && pLeft->bEof==0 ){ + memset(pDl->pList, 0, pDl->nList); + fts3EvalNextRow(pCsr, pLeft, pRc); + } + } + } + } + break; + } + + case FTSQUERY_OR: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + + assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); + assert( pRight->bStart || pLeft->iDocid==pRight->iDocid ); + + if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ + fts3EvalNextRow(pCsr, pLeft, pRc); + }else if( pLeft->bEof || iCmp>0 ){ + fts3EvalNextRow(pCsr, pRight, pRc); + }else{ + fts3EvalNextRow(pCsr, pLeft, pRc); + fts3EvalNextRow(pCsr, pRight, pRc); + } + + pExpr->bEof = (pLeft->bEof && pRight->bEof); + iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ + pExpr->iDocid = pLeft->iDocid; + }else{ + pExpr->iDocid = pRight->iDocid; + } + + break; + } + + case FTSQUERY_NOT: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + + if( pRight->bStart==0 ){ + fts3EvalNextRow(pCsr, pRight, pRc); + assert( *pRc!=SQLITE_OK || pRight->bStart ); + } + + fts3EvalNextRow(pCsr, pLeft, pRc); + if( pLeft->bEof==0 ){ + while( !*pRc + && !pRight->bEof + && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0 + ){ + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = pLeft->bEof; + break; + } + + default: { + Fts3Phrase *pPhrase = pExpr->pPhrase; + fts3EvalInvalidatePoslist(pPhrase); + *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof); + pExpr->iDocid = pPhrase->doclist.iDocid; + break; + } + } + } +} + +/* +** If *pRc is not SQLITE_OK, or if pExpr is not the root node of a NEAR +** cluster, then this function returns 1 immediately. +** +** Otherwise, it checks if the current row really does match the NEAR +** expression, using the data currently stored in the position lists +** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression. +** +** If the current row is a match, the position list associated with each +** phrase in the NEAR expression is edited in place to contain only those +** phrase instances sufficiently close to their peers to satisfy all NEAR +** constraints. In this case it returns 1. If the NEAR expression does not +** match the current row, 0 is returned. The position lists may or may not +** be edited if 0 is returned. +*/ +static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ + int res = 1; + + /* The following block runs if pExpr is the root of a NEAR query. + ** For example, the query: + ** + ** "w" NEAR "x" NEAR "y" NEAR "z" + ** + ** which is represented in tree form as: + ** + ** | + ** +--NEAR--+ <-- root of NEAR query + ** | | + ** +--NEAR--+ "z" + ** | | + ** +--NEAR--+ "y" + ** | | + ** "w" "x" + ** + ** The right-hand child of a NEAR node is always a phrase. The + ** left-hand child may be either a phrase or a NEAR node. There are + ** no exceptions to this - it's the way the parser in fts3_expr.c works. + */ + if( *pRc==SQLITE_OK + && pExpr->eType==FTSQUERY_NEAR + && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) + ){ + Fts3Expr *p; + int nTmp = 0; /* Bytes of temp space */ + char *aTmp; /* Temp space for PoslistNearMerge() */ + + /* Allocate temporary working space. */ + for(p=pExpr; p->pLeft; p=p->pLeft){ + assert( p->pRight->pPhrase->doclist.nList>0 ); + nTmp += p->pRight->pPhrase->doclist.nList; + } + nTmp += p->pPhrase->doclist.nList; + aTmp = sqlite3_malloc(nTmp*2); + if( !aTmp ){ + *pRc = SQLITE_NOMEM; + res = 0; + }else{ + char *aPoslist = p->pPhrase->doclist.pList; + int nToken = p->pPhrase->nToken; + + for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ + Fts3Phrase *pPhrase = p->pRight->pPhrase; + int nNear = p->nNear; + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); + } + + aPoslist = pExpr->pRight->pPhrase->doclist.pList; + nToken = pExpr->pRight->pPhrase->nToken; + for(p=pExpr->pLeft; p && res; p=p->pLeft){ + int nNear; + Fts3Phrase *pPhrase; + assert( p->pParent && p->pParent->pLeft==p ); + nNear = p->pParent->nNear; + pPhrase = ( + p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase + ); + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); + } + } + + sqlite3_free(aTmp); + } + + return res; +} + +/* +** This function is a helper function for sqlite3Fts3EvalTestDeferred(). +** Assuming no error occurs or has occurred, It returns non-zero if the +** expression passed as the second argument matches the row that pCsr +** currently points to, or zero if it does not. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** If an error occurs during execution of this function, *pRc is set to +** the appropriate SQLite error code. In this case the returned value is +** undefined. +*/ +static int fts3EvalTestExpr( + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Expr to test. May or may not be root. */ + int *pRc /* IN/OUT: Error code */ +){ + int bHit = 1; /* Return value */ + if( *pRc==SQLITE_OK ){ + switch( pExpr->eType ){ + case FTSQUERY_NEAR: + case FTSQUERY_AND: + bHit = ( + fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) + && fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) + && fts3EvalNearTest(pExpr, pRc) + ); + + /* If the NEAR expression does not match any rows, zero the doclist for + ** all phrases involved in the NEAR. This is because the snippet(), + ** offsets() and matchinfo() functions are not supposed to recognize + ** any instances of phrases that are part of unmatched NEAR queries. + ** For example if this expression: + ** + ** ... MATCH 'a OR (b NEAR c)' + ** + ** is matched against a row containing: + ** + ** 'a b d e' + ** + ** then any snippet() should ony highlight the "a" term, not the "b" + ** (as "b" is part of a non-matching NEAR clause). + */ + if( bHit==0 + && pExpr->eType==FTSQUERY_NEAR + && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) + ){ + Fts3Expr *p; + for(p=pExpr; p->pPhrase==0; p=p->pLeft){ + if( p->pRight->iDocid==pCsr->iPrevId ){ + fts3EvalInvalidatePoslist(p->pRight->pPhrase); + } + } + if( p->iDocid==pCsr->iPrevId ){ + fts3EvalInvalidatePoslist(p->pPhrase); + } + } + + break; + + case FTSQUERY_OR: { + int bHit1 = fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc); + int bHit2 = fts3EvalTestExpr(pCsr, pExpr->pRight, pRc); + bHit = bHit1 || bHit2; + break; + } + + case FTSQUERY_NOT: + bHit = ( + fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) + && !fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) + ); + break; + + default: { +#ifndef SQLITE_DISABLE_FTS4_DEFERRED + if( pCsr->pDeferred + && (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred) + ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 ); + if( pExpr->bDeferred ){ + fts3EvalInvalidatePoslist(pPhrase); + } + *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); + bHit = (pPhrase->doclist.pList!=0); + pExpr->iDocid = pCsr->iPrevId; + }else +#endif + { + bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId); + } + break; + } + } + } + return bHit; +} + +/* +** This function is called as the second part of each xNext operation when +** iterating through the results of a full-text query. At this point the +** cursor points to a row that matches the query expression, with the +** following caveats: +** +** * Up until this point, "NEAR" operators in the expression have been +** treated as "AND". +** +** * Deferred tokens have not yet been considered. +** +** If *pRc is not SQLITE_OK when this function is called, it immediately +** returns 0. Otherwise, it tests whether or not after considering NEAR +** operators and deferred tokens the current row is still a match for the +** expression. It returns 1 if both of the following are true: +** +** 1. *pRc is SQLITE_OK when this function returns, and +** +** 2. After scanning the current FTS table row for the deferred tokens, +** it is determined that the row does *not* match the query. +** +** Or, if no error occurs and it seems the current row does match the FTS +** query, return 0. +*/ +SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){ + int rc = *pRc; + int bMiss = 0; + if( rc==SQLITE_OK ){ + + /* If there are one or more deferred tokens, load the current row into + ** memory and scan it to determine the position list for each deferred + ** token. Then, see if this row is really a match, considering deferred + ** tokens and NEAR operators (neither of which were taken into account + ** earlier, by fts3EvalNextRow()). + */ + if( pCsr->pDeferred ){ + rc = fts3CursorSeek(0, pCsr); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3CacheDeferredDoclists(pCsr); + } + } + bMiss = (0==fts3EvalTestExpr(pCsr, pCsr->pExpr, &rc)); + + /* Free the position-lists accumulated for each deferred token above. */ + sqlite3Fts3FreeDeferredDoclists(pCsr); + *pRc = rc; + } + return (rc==SQLITE_OK && bMiss); +} + +/* +** Advance to the next document that matches the FTS expression in +** Fts3Cursor.pExpr. +*/ +static int fts3EvalNext(Fts3Cursor *pCsr){ + int rc = SQLITE_OK; /* Return Code */ + Fts3Expr *pExpr = pCsr->pExpr; + assert( pCsr->isEof==0 ); + if( pExpr==0 ){ + pCsr->isEof = 1; + }else{ + do { + if( pCsr->isRequireSeek==0 ){ + sqlite3_reset(pCsr->pStmt); + } + assert( sqlite3_data_count(pCsr->pStmt)==0 ); + fts3EvalNextRow(pCsr, pExpr, &rc); + pCsr->isEof = pExpr->bEof; + pCsr->isRequireSeek = 1; + pCsr->isMatchinfoNeeded = 1; + pCsr->iPrevId = pExpr->iDocid; + }while( pCsr->isEof==0 && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); + } + + /* Check if the cursor is past the end of the docid range specified + ** by Fts3Cursor.iMinDocid/iMaxDocid. If so, set the EOF flag. */ + if( rc==SQLITE_OK && ( + (pCsr->bDesc==0 && pCsr->iPrevId>pCsr->iMaxDocid) + || (pCsr->bDesc!=0 && pCsr->iPrevIdiMinDocid) + )){ + pCsr->isEof = 1; + } + + return rc; +} + +/* +** Restart interation for expression pExpr so that the next call to +** fts3EvalNext() visits the first row. Do not allow incremental +** loading or merging of phrase doclists for this iteration. +** +** If *pRc is other than SQLITE_OK when this function is called, it is +** a no-op. If an error occurs within this function, *pRc is set to an +** SQLite error code before returning. +*/ +static void fts3EvalRestart( + Fts3Cursor *pCsr, + Fts3Expr *pExpr, + int *pRc +){ + if( pExpr && *pRc==SQLITE_OK ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + + if( pPhrase ){ + fts3EvalInvalidatePoslist(pPhrase); + if( pPhrase->bIncr ){ + int i; + for(i=0; inToken; i++){ + Fts3PhraseToken *pToken = &pPhrase->aToken[i]; + assert( pToken->pDeferred==0 ); + if( pToken->pSegcsr ){ + sqlite3Fts3MsrIncrRestart(pToken->pSegcsr); + } + } + *pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase); + } + pPhrase->doclist.pNextDocid = 0; + pPhrase->doclist.iDocid = 0; + pPhrase->pOrPoslist = 0; + } + + pExpr->iDocid = 0; + pExpr->bEof = 0; + pExpr->bStart = 0; + + fts3EvalRestart(pCsr, pExpr->pLeft, pRc); + fts3EvalRestart(pCsr, pExpr->pRight, pRc); + } +} + +/* +** After allocating the Fts3Expr.aMI[] array for each phrase in the +** expression rooted at pExpr, the cursor iterates through all rows matched +** by pExpr, calling this function for each row. This function increments +** the values in Fts3Expr.aMI[] according to the position-list currently +** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase +** expression nodes. +*/ +static void fts3EvalUpdateCounts(Fts3Expr *pExpr){ + if( pExpr ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + if( pPhrase && pPhrase->doclist.pList ){ + int iCol = 0; + char *p = pPhrase->doclist.pList; + + assert( *p ); + while( 1 ){ + u8 c = 0; + int iCnt = 0; + while( 0xFE & (*p | c) ){ + if( (c&0x80)==0 ) iCnt++; + c = *p++ & 0x80; + } + + /* aMI[iCol*3 + 1] = Number of occurrences + ** aMI[iCol*3 + 2] = Number of rows containing at least one instance + */ + pExpr->aMI[iCol*3 + 1] += iCnt; + pExpr->aMI[iCol*3 + 2] += (iCnt>0); + if( *p==0x00 ) break; + p++; + p += fts3GetVarint32(p, &iCol); + } + } + + fts3EvalUpdateCounts(pExpr->pLeft); + fts3EvalUpdateCounts(pExpr->pRight); + } +} + +/* +** Expression pExpr must be of type FTSQUERY_PHRASE. +** +** If it is not already allocated and populated, this function allocates and +** populates the Fts3Expr.aMI[] array for expression pExpr. If pExpr is part +** of a NEAR expression, then it also allocates and populates the same array +** for all other phrases that are part of the NEAR expression. +** +** SQLITE_OK is returned if the aMI[] array is successfully allocated and +** populated. Otherwise, if an error occurs, an SQLite error code is returned. +*/ +static int fts3EvalGatherStats( + Fts3Cursor *pCsr, /* Cursor object */ + Fts3Expr *pExpr /* FTSQUERY_PHRASE expression */ +){ + int rc = SQLITE_OK; /* Return code */ + + assert( pExpr->eType==FTSQUERY_PHRASE ); + if( pExpr->aMI==0 ){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + Fts3Expr *pRoot; /* Root of NEAR expression */ + Fts3Expr *p; /* Iterator used for several purposes */ + + sqlite3_int64 iPrevId = pCsr->iPrevId; + sqlite3_int64 iDocid; + u8 bEof; + + /* Find the root of the NEAR expression */ + pRoot = pExpr; + while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){ + pRoot = pRoot->pParent; + } + iDocid = pRoot->iDocid; + bEof = pRoot->bEof; + assert( pRoot->bStart ); + + /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */ + for(p=pRoot; p; p=p->pLeft){ + Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight); + assert( pE->aMI==0 ); + pE->aMI = (u32 *)sqlite3_malloc(pTab->nColumn * 3 * sizeof(u32)); + if( !pE->aMI ) return SQLITE_NOMEM; + memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32)); + } + + fts3EvalRestart(pCsr, pRoot, &rc); + + while( pCsr->isEof==0 && rc==SQLITE_OK ){ + + do { + /* Ensure the %_content statement is reset. */ + if( pCsr->isRequireSeek==0 ) sqlite3_reset(pCsr->pStmt); + assert( sqlite3_data_count(pCsr->pStmt)==0 ); + + /* Advance to the next document */ + fts3EvalNextRow(pCsr, pRoot, &rc); + pCsr->isEof = pRoot->bEof; + pCsr->isRequireSeek = 1; + pCsr->isMatchinfoNeeded = 1; + pCsr->iPrevId = pRoot->iDocid; + }while( pCsr->isEof==0 + && pRoot->eType==FTSQUERY_NEAR + && sqlite3Fts3EvalTestDeferred(pCsr, &rc) + ); + + if( rc==SQLITE_OK && pCsr->isEof==0 ){ + fts3EvalUpdateCounts(pRoot); + } + } + + pCsr->isEof = 0; + pCsr->iPrevId = iPrevId; + + if( bEof ){ + pRoot->bEof = bEof; + }else{ + /* Caution: pRoot may iterate through docids in ascending or descending + ** order. For this reason, even though it seems more defensive, the + ** do loop can not be written: + ** + ** do {...} while( pRoot->iDocidbEof==0 ); + }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); + } + } + return rc; +} + +/* +** This function is used by the matchinfo() module to query a phrase +** expression node for the following information: +** +** 1. The total number of occurrences of the phrase in each column of +** the FTS table (considering all rows), and +** +** 2. For each column, the number of rows in the table for which the +** column contains at least one instance of the phrase. +** +** If no error occurs, SQLITE_OK is returned and the values for each column +** written into the array aiOut as follows: +** +** aiOut[iCol*3 + 1] = Number of occurrences +** aiOut[iCol*3 + 2] = Number of rows containing at least one instance +** +** Caveats: +** +** * If a phrase consists entirely of deferred tokens, then all output +** values are set to the number of documents in the table. In other +** words we assume that very common tokens occur exactly once in each +** column of each row of the table. +** +** * If a phrase contains some deferred tokens (and some non-deferred +** tokens), count the potential occurrence identified by considering +** the non-deferred tokens instead of actual phrase occurrences. +** +** * If the phrase is part of a NEAR expression, then only phrase instances +** that meet the NEAR constraint are included in the counts. +*/ +SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats( + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Phrase expression */ + u32 *aiOut /* Array to write results into (see above) */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int iCol; + + if( pExpr->bDeferred && pExpr->pParent->eType!=FTSQUERY_NEAR ){ + assert( pCsr->nDoc>0 ); + for(iCol=0; iColnColumn; iCol++){ + aiOut[iCol*3 + 1] = (u32)pCsr->nDoc; + aiOut[iCol*3 + 2] = (u32)pCsr->nDoc; + } + }else{ + rc = fts3EvalGatherStats(pCsr, pExpr); + if( rc==SQLITE_OK ){ + assert( pExpr->aMI ); + for(iCol=0; iColnColumn; iCol++){ + aiOut[iCol*3 + 1] = pExpr->aMI[iCol*3 + 1]; + aiOut[iCol*3 + 2] = pExpr->aMI[iCol*3 + 2]; + } + } + } + + return rc; +} + +/* +** The expression pExpr passed as the second argument to this function +** must be of type FTSQUERY_PHRASE. +** +** The returned value is either NULL or a pointer to a buffer containing +** a position-list indicating the occurrences of the phrase in column iCol +** of the current row. +** +** More specifically, the returned buffer contains 1 varint for each +** occurrence of the phrase in the column, stored using the normal (delta+2) +** compression and is terminated by either an 0x01 or 0x00 byte. For example, +** if the requested column contains "a b X c d X X" and the position-list +** for 'X' is requested, the buffer returned may contain: +** +** 0x04 0x05 0x03 0x01 or 0x04 0x05 0x03 0x00 +** +** This function works regardless of whether or not the phrase is deferred, +** incremental, or neither. +*/ +SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist( + Fts3Cursor *pCsr, /* FTS3 cursor object */ + Fts3Expr *pExpr, /* Phrase to return doclist for */ + int iCol, /* Column to return position list for */ + char **ppOut /* OUT: Pointer to position list */ +){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + char *pIter; + int iThis; + sqlite3_int64 iDocid; + + /* If this phrase is applies specifically to some column other than + ** column iCol, return a NULL pointer. */ + *ppOut = 0; + assert( iCol>=0 && iColnColumn ); + if( (pPhrase->iColumnnColumn && pPhrase->iColumn!=iCol) ){ + return SQLITE_OK; + } + + iDocid = pExpr->iDocid; + pIter = pPhrase->doclist.pList; + if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ + int rc = SQLITE_OK; + int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ + int bOr = 0; + u8 bTreeEof = 0; + Fts3Expr *p; /* Used to iterate from pExpr to root */ + Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */ + int bMatch; + + /* Check if this phrase descends from an OR expression node. If not, + ** return NULL. Otherwise, the entry that corresponds to docid + ** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the + ** tree that the node is part of has been marked as EOF, but the node + ** itself is not EOF, then it may point to an earlier entry. */ + pNear = pExpr; + for(p=pExpr->pParent; p; p=p->pParent){ + if( p->eType==FTSQUERY_OR ) bOr = 1; + if( p->eType==FTSQUERY_NEAR ) pNear = p; + if( p->bEof ) bTreeEof = 1; + } + if( bOr==0 ) return SQLITE_OK; + + /* This is the descendent of an OR node. In this case we cannot use + ** an incremental phrase. Load the entire doclist for the phrase + ** into memory in this case. */ + if( pPhrase->bIncr ){ + int bEofSave = pNear->bEof; + fts3EvalRestart(pCsr, pNear, &rc); + while( rc==SQLITE_OK && !pNear->bEof ){ + fts3EvalNextRow(pCsr, pNear, &rc); + if( bEofSave==0 && pNear->iDocid==iDocid ) break; + } + assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); + } + if( bTreeEof ){ + while( rc==SQLITE_OK && !pNear->bEof ){ + fts3EvalNextRow(pCsr, pNear, &rc); + } + } + if( rc!=SQLITE_OK ) return rc; + + bMatch = 1; + for(p=pNear; p; p=p->pLeft){ + u8 bEof = 0; + Fts3Expr *pTest = p; + Fts3Phrase *pPh; + assert( pTest->eType==FTSQUERY_NEAR || pTest->eType==FTSQUERY_PHRASE ); + if( pTest->eType==FTSQUERY_NEAR ) pTest = pTest->pRight; + assert( pTest->eType==FTSQUERY_PHRASE ); + pPh = pTest->pPhrase; + + pIter = pPh->pOrPoslist; + iDocid = pPh->iOrDocid; + if( pCsr->bDesc==bDescDoclist ){ + bEof = !pPh->doclist.nAll || + (pIter >= (pPh->doclist.aAll + pPh->doclist.nAll)); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ + sqlite3Fts3DoclistNext( + bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, + &pIter, &iDocid, &bEof + ); + } + }else{ + bEof = !pPh->doclist.nAll || (pIter && pIter<=pPh->doclist.aAll); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ + int dummy; + sqlite3Fts3DoclistPrev( + bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, + &pIter, &iDocid, &dummy, &bEof + ); + } + } + pPh->pOrPoslist = pIter; + pPh->iOrDocid = iDocid; + if( bEof || iDocid!=pCsr->iPrevId ) bMatch = 0; + } + + if( bMatch ){ + pIter = pPhrase->pOrPoslist; + }else{ + pIter = 0; + } + } + if( pIter==0 ) return SQLITE_OK; + + if( *pIter==0x01 ){ + pIter++; + pIter += fts3GetVarint32(pIter, &iThis); + }else{ + iThis = 0; + } + while( iThisdoclist, and +** * any Fts3MultiSegReader objects held by phrase tokens. +*/ +SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){ + if( pPhrase ){ + int i; + sqlite3_free(pPhrase->doclist.aAll); + fts3EvalInvalidatePoslist(pPhrase); + memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist)); + for(i=0; inToken; i++){ + fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr); + pPhrase->aToken[i].pSegcsr = 0; + } + } +} + + +/* +** Return SQLITE_CORRUPT_VTAB. +*/ +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ + return SQLITE_CORRUPT_VTAB; +} +#endif + +#if !SQLITE_CORE +/* +** Initialize API pointer table, if required. +*/ +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_fts3_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + return sqlite3Fts3Init(db); +} +#endif + +#endif + +/************** End of fts3.c ************************************************/ +/************** Begin file fts3_aux.c ****************************************/ +/* +** 2011 Jan 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ + +typedef struct Fts3auxTable Fts3auxTable; +typedef struct Fts3auxCursor Fts3auxCursor; + +struct Fts3auxTable { + sqlite3_vtab base; /* Base class used by SQLite core */ + Fts3Table *pFts3Tab; +}; + +struct Fts3auxCursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + Fts3MultiSegReader csr; /* Must be right after "base" */ + Fts3SegFilter filter; + char *zStop; + int nStop; /* Byte-length of string zStop */ + int iLangid; /* Language id to query */ + int isEof; /* True if cursor is at EOF */ + sqlite3_int64 iRowid; /* Current rowid */ + + int iCol; /* Current value of 'col' column */ + int nStat; /* Size of aStat[] array */ + struct Fts3auxColstats { + sqlite3_int64 nDoc; /* 'documents' values for current csr row */ + sqlite3_int64 nOcc; /* 'occurrences' values for current csr row */ + } *aStat; +}; + +/* +** Schema of the terms table. +*/ +#define FTS3_AUX_SCHEMA \ + "CREATE TABLE x(term, col, documents, occurrences, languageid HIDDEN)" + +/* +** This function does all the work for both the xConnect and xCreate methods. +** These tables have no persistent representation of their own, so xConnect +** and xCreate are identical operations. +*/ +static int fts3auxConnectMethod( + sqlite3 *db, /* Database connection */ + void *pUnused, /* Unused */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + char const *zDb; /* Name of database (e.g. "main") */ + char const *zFts3; /* Name of fts3 table */ + int nDb; /* Result of strlen(zDb) */ + int nFts3; /* Result of strlen(zFts3) */ + int nByte; /* Bytes of space to allocate here */ + int rc; /* value returned by declare_vtab() */ + Fts3auxTable *p; /* Virtual table object to return */ + + UNUSED_PARAMETER(pUnused); + + /* The user should invoke this in one of two forms: + ** + ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table); + ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table); + */ + if( argc!=4 && argc!=5 ) goto bad_args; + + zDb = argv[1]; + nDb = (int)strlen(zDb); + if( argc==5 ){ + if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){ + zDb = argv[3]; + nDb = (int)strlen(zDb); + zFts3 = argv[4]; + }else{ + goto bad_args; + } + }else{ + zFts3 = argv[3]; + } + nFts3 = (int)strlen(zFts3); + + rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA); + if( rc!=SQLITE_OK ) return rc; + + nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; + p = (Fts3auxTable *)sqlite3_malloc(nByte); + if( !p ) return SQLITE_NOMEM; + memset(p, 0, nByte); + + p->pFts3Tab = (Fts3Table *)&p[1]; + p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; + p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; + p->pFts3Tab->db = db; + p->pFts3Tab->nIndex = 1; + + memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); + memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); + sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); + + *ppVtab = (sqlite3_vtab *)p; + return SQLITE_OK; + + bad_args: + sqlite3Fts3ErrMsg(pzErr, "invalid arguments to fts4aux constructor"); + return SQLITE_ERROR; +} + +/* +** This function does the work for both the xDisconnect and xDestroy methods. +** These tables have no persistent representation of their own, so xDisconnect +** and xDestroy are identical operations. +*/ +static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){ + Fts3auxTable *p = (Fts3auxTable *)pVtab; + Fts3Table *pFts3 = p->pFts3Tab; + int i; + + /* Free any prepared statements held */ + for(i=0; iaStmt); i++){ + sqlite3_finalize(pFts3->aStmt[i]); + } + sqlite3_free(pFts3->zSegmentsTbl); + sqlite3_free(p); + return SQLITE_OK; +} + +#define FTS4AUX_EQ_CONSTRAINT 1 +#define FTS4AUX_GE_CONSTRAINT 2 +#define FTS4AUX_LE_CONSTRAINT 4 + +/* +** xBestIndex - Analyze a WHERE and ORDER BY clause. +*/ +static int fts3auxBestIndexMethod( + sqlite3_vtab *pVTab, + sqlite3_index_info *pInfo +){ + int i; + int iEq = -1; + int iGe = -1; + int iLe = -1; + int iLangid = -1; + int iNext = 1; /* Next free argvIndex value */ + + UNUSED_PARAMETER(pVTab); + + /* This vtab delivers always results in "ORDER BY term ASC" order. */ + if( pInfo->nOrderBy==1 + && pInfo->aOrderBy[0].iColumn==0 + && pInfo->aOrderBy[0].desc==0 + ){ + pInfo->orderByConsumed = 1; + } + + /* Search for equality and range constraints on the "term" column. + ** And equality constraints on the hidden "languageid" column. */ + for(i=0; inConstraint; i++){ + if( pInfo->aConstraint[i].usable ){ + int op = pInfo->aConstraint[i].op; + int iCol = pInfo->aConstraint[i].iColumn; + + if( iCol==0 ){ + if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i; + if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i; + if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i; + if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i; + if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i; + } + if( iCol==4 ){ + if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iLangid = i; + } + } + } + + if( iEq>=0 ){ + pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT; + pInfo->aConstraintUsage[iEq].argvIndex = iNext++; + pInfo->estimatedCost = 5; + }else{ + pInfo->idxNum = 0; + pInfo->estimatedCost = 20000; + if( iGe>=0 ){ + pInfo->idxNum += FTS4AUX_GE_CONSTRAINT; + pInfo->aConstraintUsage[iGe].argvIndex = iNext++; + pInfo->estimatedCost /= 2; + } + if( iLe>=0 ){ + pInfo->idxNum += FTS4AUX_LE_CONSTRAINT; + pInfo->aConstraintUsage[iLe].argvIndex = iNext++; + pInfo->estimatedCost /= 2; + } + } + if( iLangid>=0 ){ + pInfo->aConstraintUsage[iLangid].argvIndex = iNext++; + pInfo->estimatedCost--; + } + + return SQLITE_OK; +} + +/* +** xOpen - Open a cursor. +*/ +static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts3auxCursor *pCsr; /* Pointer to cursor object to return */ + + UNUSED_PARAMETER(pVTab); + + pCsr = (Fts3auxCursor *)sqlite3_malloc(sizeof(Fts3auxCursor)); + if( !pCsr ) return SQLITE_NOMEM; + memset(pCsr, 0, sizeof(Fts3auxCursor)); + + *ppCsr = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** xClose - Close a cursor. +*/ +static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + + sqlite3Fts3SegmentsClose(pFts3); + sqlite3Fts3SegReaderFinish(&pCsr->csr); + sqlite3_free((void *)pCsr->filter.zTerm); + sqlite3_free(pCsr->zStop); + sqlite3_free(pCsr->aStat); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){ + if( nSize>pCsr->nStat ){ + struct Fts3auxColstats *aNew; + aNew = (struct Fts3auxColstats *)sqlite3_realloc(pCsr->aStat, + sizeof(struct Fts3auxColstats) * nSize + ); + if( aNew==0 ) return SQLITE_NOMEM; + memset(&aNew[pCsr->nStat], 0, + sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat) + ); + pCsr->aStat = aNew; + pCsr->nStat = nSize; + } + return SQLITE_OK; +} + +/* +** xNext - Advance the cursor to the next row, if any. +*/ +static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; + int rc; + + /* Increment our pretend rowid value. */ + pCsr->iRowid++; + + for(pCsr->iCol++; pCsr->iColnStat; pCsr->iCol++){ + if( pCsr->aStat[pCsr->iCol].nDoc>0 ) return SQLITE_OK; + } + + rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr); + if( rc==SQLITE_ROW ){ + int i = 0; + int nDoclist = pCsr->csr.nDoclist; + char *aDoclist = pCsr->csr.aDoclist; + int iCol; + + int eState = 0; + + if( pCsr->zStop ){ + int n = (pCsr->nStopcsr.nTerm) ? pCsr->nStop : pCsr->csr.nTerm; + int mc = memcmp(pCsr->zStop, pCsr->csr.zTerm, n); + if( mc<0 || (mc==0 && pCsr->csr.nTerm>pCsr->nStop) ){ + pCsr->isEof = 1; + return SQLITE_OK; + } + } + + if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; + memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); + iCol = 0; + + while( iaStat[0].nDoc++; + eState = 1; + iCol = 0; + break; + + /* State 1. In this state we are expecting either a 1, indicating + ** that the following integer will be a column number, or the + ** start of a position list for column 0. + ** + ** The only difference between state 1 and state 2 is that if the + ** integer encountered in state 1 is not 0 or 1, then we need to + ** increment the column 0 "nDoc" count for this term. + */ + case 1: + assert( iCol==0 ); + if( v>1 ){ + pCsr->aStat[1].nDoc++; + } + eState = 2; + /* fall through */ + + case 2: + if( v==0 ){ /* 0x00. Next integer will be a docid. */ + eState = 0; + }else if( v==1 ){ /* 0x01. Next integer will be a column number. */ + eState = 3; + }else{ /* 2 or greater. A position. */ + pCsr->aStat[iCol+1].nOcc++; + pCsr->aStat[0].nOcc++; + } + break; + + /* State 3. The integer just read is a column number. */ + default: assert( eState==3 ); + iCol = (int)v; + if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; + pCsr->aStat[iCol+1].nDoc++; + eState = 2; + break; + } + } + + pCsr->iCol = 0; + rc = SQLITE_OK; + }else{ + pCsr->isEof = 1; + } + return rc; +} + +/* +** xFilter - Initialize a cursor to point at the start of its data. +*/ +static int fts3auxFilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *idxStr, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; + int rc; + int isScan = 0; + int iLangVal = 0; /* Language id to query */ + + int iEq = -1; /* Index of term=? value in apVal */ + int iGe = -1; /* Index of term>=? value in apVal */ + int iLe = -1; /* Index of term<=? value in apVal */ + int iLangid = -1; /* Index of languageid=? value in apVal */ + int iNext = 0; + + UNUSED_PARAMETER(nVal); + UNUSED_PARAMETER(idxStr); + + assert( idxStr==0 ); + assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0 + || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT + || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) + ); + + if( idxNum==FTS4AUX_EQ_CONSTRAINT ){ + iEq = iNext++; + }else{ + isScan = 1; + if( idxNum & FTS4AUX_GE_CONSTRAINT ){ + iGe = iNext++; + } + if( idxNum & FTS4AUX_LE_CONSTRAINT ){ + iLe = iNext++; + } + } + if( iNextfilter.zTerm); + sqlite3Fts3SegReaderFinish(&pCsr->csr); + sqlite3_free((void *)pCsr->filter.zTerm); + sqlite3_free(pCsr->aStat); + memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); + + pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; + if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; + + if( iEq>=0 || iGe>=0 ){ + const unsigned char *zStr = sqlite3_value_text(apVal[0]); + assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); + if( zStr ){ + pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); + pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]); + if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; + } + } + + if( iLe>=0 ){ + pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); + pCsr->nStop = sqlite3_value_bytes(apVal[iLe]); + if( pCsr->zStop==0 ) return SQLITE_NOMEM; + } + + if( iLangid>=0 ){ + iLangVal = sqlite3_value_int(apVal[iLangid]); + + /* If the user specified a negative value for the languageid, use zero + ** instead. This works, as the "languageid=?" constraint will also + ** be tested by the VDBE layer. The test will always be false (since + ** this module will not return a row with a negative languageid), and + ** so the overall query will return zero rows. */ + if( iLangVal<0 ) iLangVal = 0; + } + pCsr->iLangid = iLangVal; + + rc = sqlite3Fts3SegReaderCursor(pFts3, iLangVal, 0, FTS3_SEGCURSOR_ALL, + pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr + ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); + } + + if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor); + return rc; +} + +/* +** xEof - Return true if the cursor is at EOF, or false otherwise. +*/ +static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + return pCsr->isEof; +} + +/* +** xColumn - Return a column value. +*/ +static int fts3auxColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ +){ + Fts3auxCursor *p = (Fts3auxCursor *)pCursor; + + assert( p->isEof==0 ); + switch( iCol ){ + case 0: /* term */ + sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); + break; + + case 1: /* col */ + if( p->iCol ){ + sqlite3_result_int(pCtx, p->iCol-1); + }else{ + sqlite3_result_text(pCtx, "*", -1, SQLITE_STATIC); + } + break; + + case 2: /* documents */ + sqlite3_result_int64(pCtx, p->aStat[p->iCol].nDoc); + break; + + case 3: /* occurrences */ + sqlite3_result_int64(pCtx, p->aStat[p->iCol].nOcc); + break; + + default: /* languageid */ + assert( iCol==4 ); + sqlite3_result_int(pCtx, p->iLangid); + break; + } + + return SQLITE_OK; +} + +/* +** xRowid - Return the current rowid for the cursor. +*/ +static int fts3auxRowidMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite_int64 *pRowid /* OUT: Rowid value */ +){ + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + *pRowid = pCsr->iRowid; + return SQLITE_OK; +} + +/* +** Register the fts3aux module with database connection db. Return SQLITE_OK +** if successful or an error code if sqlite3_create_module() fails. +*/ +SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){ + static const sqlite3_module fts3aux_module = { + 0, /* iVersion */ + fts3auxConnectMethod, /* xCreate */ + fts3auxConnectMethod, /* xConnect */ + fts3auxBestIndexMethod, /* xBestIndex */ + fts3auxDisconnectMethod, /* xDisconnect */ + fts3auxDisconnectMethod, /* xDestroy */ + fts3auxOpenMethod, /* xOpen */ + fts3auxCloseMethod, /* xClose */ + fts3auxFilterMethod, /* xFilter */ + fts3auxNextMethod, /* xNext */ + fts3auxEofMethod, /* xEof */ + fts3auxColumnMethod, /* xColumn */ + fts3auxRowidMethod, /* xRowid */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindFunction */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0 /* xRollbackTo */ + }; + int rc; /* Return code */ + + rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0); + return rc; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_aux.c ********************************************/ +/************** Begin file fts3_expr.c ***************************************/ +/* +** 2008 Nov 28 +** +** 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 contains code that implements a parser for fts3 query strings +** (the right-hand argument to the MATCH operator). Because the supported +** syntax is relatively simple, the whole tokenizer/parser system is +** hand-coded. +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* +** By default, this module parses the legacy syntax that has been +** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS +** is defined, then it uses the new syntax. The differences between +** the new and the old syntaxes are: +** +** a) The new syntax supports parenthesis. The old does not. +** +** b) The new syntax supports the AND and NOT operators. The old does not. +** +** c) The old syntax supports the "-" token qualifier. This is not +** supported by the new syntax (it is replaced by the NOT operator). +** +** d) When using the old syntax, the OR operator has a greater precedence +** than an implicit AND. When using the new, both implicity and explicit +** AND operators have a higher precedence than OR. +** +** If compiled with SQLITE_TEST defined, then this module exports the +** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable +** to zero causes the module to use the old syntax. If it is set to +** non-zero the new syntax is activated. This is so both syntaxes can +** be tested using a single build of testfixture. +** +** The following describes the syntax supported by the fts3 MATCH +** operator in a similar format to that used by the lemon parser +** generator. This module does not use actually lemon, it uses a +** custom parser. +** +** query ::= andexpr (OR andexpr)*. +** +** andexpr ::= notexpr (AND? notexpr)*. +** +** notexpr ::= nearexpr (NOT nearexpr|-TOKEN)*. +** notexpr ::= LP query RP. +** +** nearexpr ::= phrase (NEAR distance_opt nearexpr)*. +** +** distance_opt ::= . +** distance_opt ::= / INTEGER. +** +** phrase ::= TOKEN. +** phrase ::= COLUMN:TOKEN. +** phrase ::= "TOKEN TOKEN TOKEN...". +*/ + +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_fts3_enable_parentheses = 0; +#else +# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS +# define sqlite3_fts3_enable_parentheses 1 +# else +# define sqlite3_fts3_enable_parentheses 0 +# endif +#endif + +/* +** Default span for NEAR operators. +*/ +#define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 + +/* #include */ +/* #include */ + +/* +** isNot: +** This variable is used by function getNextNode(). When getNextNode() is +** called, it sets ParseContext.isNot to true if the 'next node' is a +** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the +** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to +** zero. +*/ +typedef struct ParseContext ParseContext; +struct ParseContext { + sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ + int iLangid; /* Language id used with tokenizer */ + const char **azCol; /* Array of column names for fts3 table */ + int bFts4; /* True to allow FTS4-only syntax */ + int nCol; /* Number of entries in azCol[] */ + int iDefaultCol; /* Default column to query */ + int isNot; /* True if getNextNode() sees a unary - */ + sqlite3_context *pCtx; /* Write error message here */ + int nNest; /* Number of nested brackets */ +}; + +/* +** This function is equivalent to the standard isspace() function. +** +** The standard isspace() can be awkward to use safely, because although it +** is defined to accept an argument of type int, its behavior when passed +** an integer that falls outside of the range of the unsigned char type +** is undefined (and sometimes, "undefined" means segfault). This wrapper +** is defined to accept an argument of type char, and always returns 0 for +** any values that fall outside of the range of the unsigned char type (i.e. +** negative values). +*/ +static int fts3isspace(char c){ + return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; +} + +/* +** Allocate nByte bytes of memory using sqlite3_malloc(). If successful, +** zero the memory before returning a pointer to it. If unsuccessful, +** return NULL. +*/ +static void *fts3MallocZero(int nByte){ + void *pRet = sqlite3_malloc(nByte); + if( pRet ) memset(pRet, 0, nByte); + return pRet; +} + +SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer( + sqlite3_tokenizer *pTokenizer, + int iLangid, + const char *z, + int n, + sqlite3_tokenizer_cursor **ppCsr +){ + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + sqlite3_tokenizer_cursor *pCsr = 0; + int rc; + + rc = pModule->xOpen(pTokenizer, z, n, &pCsr); + assert( rc==SQLITE_OK || pCsr==0 ); + if( rc==SQLITE_OK ){ + pCsr->pTokenizer = pTokenizer; + if( pModule->iVersion>=1 ){ + rc = pModule->xLanguageid(pCsr, iLangid); + if( rc!=SQLITE_OK ){ + pModule->xClose(pCsr); + pCsr = 0; + } + } + } + *ppCsr = pCsr; + return rc; +} + +/* +** Function getNextNode(), which is called by fts3ExprParse(), may itself +** call fts3ExprParse(). So this forward declaration is required. +*/ +static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); + +/* +** Extract the next token from buffer z (length n) using the tokenizer +** and other information (column names etc.) in pParse. Create an Fts3Expr +** structure of type FTSQUERY_PHRASE containing a phrase consisting of this +** single token and set *ppExpr to point to it. If the end of the buffer is +** reached before a token is found, set *ppExpr to zero. It is the +** responsibility of the caller to eventually deallocate the allocated +** Fts3Expr structure (if any) by passing it to sqlite3_free(). +** +** Return SQLITE_OK if successful, or SQLITE_NOMEM if a memory allocation +** fails. +*/ +static int getNextToken( + ParseContext *pParse, /* fts3 query parse context */ + int iCol, /* Value for Fts3Phrase.iColumn */ + const char *z, int n, /* Input string */ + Fts3Expr **ppExpr, /* OUT: expression */ + int *pnConsumed /* OUT: Number of bytes consumed */ +){ + sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + int rc; + sqlite3_tokenizer_cursor *pCursor; + Fts3Expr *pRet = 0; + int i = 0; + + /* Set variable i to the maximum number of bytes of input to tokenize. */ + for(i=0; iiLangid, z, i, &pCursor); + if( rc==SQLITE_OK ){ + const char *zToken; + int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; + int nByte; /* total space to allocate */ + + rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); + if( rc==SQLITE_OK ){ + nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; + pRet = (Fts3Expr *)fts3MallocZero(nByte); + if( !pRet ){ + rc = SQLITE_NOMEM; + }else{ + pRet->eType = FTSQUERY_PHRASE; + pRet->pPhrase = (Fts3Phrase *)&pRet[1]; + pRet->pPhrase->nToken = 1; + pRet->pPhrase->iColumn = iCol; + pRet->pPhrase->aToken[0].n = nToken; + pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1]; + memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken); + + if( iEndpPhrase->aToken[0].isPrefix = 1; + iEnd++; + } + + while( 1 ){ + if( !sqlite3_fts3_enable_parentheses + && iStart>0 && z[iStart-1]=='-' + ){ + pParse->isNot = 1; + iStart--; + }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){ + pRet->pPhrase->aToken[0].bFirst = 1; + iStart--; + }else{ + break; + } + } + + } + *pnConsumed = iEnd; + }else if( i && rc==SQLITE_DONE ){ + rc = SQLITE_OK; + } + + pModule->xClose(pCursor); + } + + *ppExpr = pRet; + return rc; +} + + +/* +** Enlarge a memory allocation. If an out-of-memory allocation occurs, +** then free the old allocation. +*/ +static void *fts3ReallocOrFree(void *pOrig, int nNew){ + void *pRet = sqlite3_realloc(pOrig, nNew); + if( !pRet ){ + sqlite3_free(pOrig); + } + return pRet; +} + +/* +** Buffer zInput, length nInput, contains the contents of a quoted string +** that appeared as part of an fts3 query expression. Neither quote character +** is included in the buffer. This function attempts to tokenize the entire +** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE +** containing the results. +** +** If successful, SQLITE_OK is returned and *ppExpr set to point at the +** allocated Fts3Expr structure. Otherwise, either SQLITE_NOMEM (out of memory +** error) or SQLITE_ERROR (tokenization error) is returned and *ppExpr set +** to 0. +*/ +static int getNextString( + ParseContext *pParse, /* fts3 query parse context */ + const char *zInput, int nInput, /* Input string */ + Fts3Expr **ppExpr /* OUT: expression */ +){ + sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + int rc; + Fts3Expr *p = 0; + sqlite3_tokenizer_cursor *pCursor = 0; + char *zTemp = 0; + int nTemp = 0; + + const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase); + int nToken = 0; + + /* The final Fts3Expr data structure, including the Fts3Phrase, + ** Fts3PhraseToken structures token buffers are all stored as a single + ** allocation so that the expression can be freed with a single call to + ** sqlite3_free(). Setting this up requires a two pass approach. + ** + ** The first pass, in the block below, uses a tokenizer cursor to iterate + ** through the tokens in the expression. This pass uses fts3ReallocOrFree() + ** to assemble data in two dynamic buffers: + ** + ** Buffer p: Points to the Fts3Expr structure, followed by the Fts3Phrase + ** structure, followed by the array of Fts3PhraseToken + ** structures. This pass only populates the Fts3PhraseToken array. + ** + ** Buffer zTemp: Contains copies of all tokens. + ** + ** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below, + ** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase + ** structures. + */ + rc = sqlite3Fts3OpenTokenizer( + pTokenizer, pParse->iLangid, zInput, nInput, &pCursor); + if( rc==SQLITE_OK ){ + int ii; + for(ii=0; rc==SQLITE_OK; ii++){ + const char *zByte; + int nByte = 0, iBegin = 0, iEnd = 0, iPos = 0; + rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos); + if( rc==SQLITE_OK ){ + Fts3PhraseToken *pToken; + + p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken)); + if( !p ) goto no_mem; + + zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte); + if( !zTemp ) goto no_mem; + + assert( nToken==ii ); + pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii]; + memset(pToken, 0, sizeof(Fts3PhraseToken)); + + memcpy(&zTemp[nTemp], zByte, nByte); + nTemp += nByte; + + pToken->n = nByte; + pToken->isPrefix = (iEndbFirst = (iBegin>0 && zInput[iBegin-1]=='^'); + nToken = ii+1; + } + } + + pModule->xClose(pCursor); + pCursor = 0; + } + + if( rc==SQLITE_DONE ){ + int jj; + char *zBuf = 0; + + p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp); + if( !p ) goto no_mem; + memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p); + p->eType = FTSQUERY_PHRASE; + p->pPhrase = (Fts3Phrase *)&p[1]; + p->pPhrase->iColumn = pParse->iDefaultCol; + p->pPhrase->nToken = nToken; + + zBuf = (char *)&p->pPhrase->aToken[nToken]; + if( zTemp ){ + memcpy(zBuf, zTemp, nTemp); + sqlite3_free(zTemp); + }else{ + assert( nTemp==0 ); + } + + for(jj=0; jjpPhrase->nToken; jj++){ + p->pPhrase->aToken[jj].z = zBuf; + zBuf += p->pPhrase->aToken[jj].n; + } + rc = SQLITE_OK; + } + + *ppExpr = p; + return rc; +no_mem: + + if( pCursor ){ + pModule->xClose(pCursor); + } + sqlite3_free(zTemp); + sqlite3_free(p); + *ppExpr = 0; + return SQLITE_NOMEM; +} + +/* +** The output variable *ppExpr is populated with an allocated Fts3Expr +** structure, or set to 0 if the end of the input buffer is reached. +** +** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM +** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered. +** If SQLITE_ERROR is returned, pContext is populated with an error message. +*/ +static int getNextNode( + ParseContext *pParse, /* fts3 query parse context */ + const char *z, int n, /* Input string */ + Fts3Expr **ppExpr, /* OUT: expression */ + int *pnConsumed /* OUT: Number of bytes consumed */ +){ + static const struct Fts3Keyword { + char *z; /* Keyword text */ + unsigned char n; /* Length of the keyword */ + unsigned char parenOnly; /* Only valid in paren mode */ + unsigned char eType; /* Keyword code */ + } aKeyword[] = { + { "OR" , 2, 0, FTSQUERY_OR }, + { "AND", 3, 1, FTSQUERY_AND }, + { "NOT", 3, 1, FTSQUERY_NOT }, + { "NEAR", 4, 0, FTSQUERY_NEAR } + }; + int ii; + int iCol; + int iColLen; + int rc; + Fts3Expr *pRet = 0; + + const char *zInput = z; + int nInput = n; + + pParse->isNot = 0; + + /* Skip over any whitespace before checking for a keyword, an open or + ** close bracket, or a quoted string. + */ + while( nInput>0 && fts3isspace(*zInput) ){ + nInput--; + zInput++; + } + if( nInput==0 ){ + return SQLITE_DONE; + } + + /* See if we are dealing with a keyword. */ + for(ii=0; ii<(int)(sizeof(aKeyword)/sizeof(struct Fts3Keyword)); ii++){ + const struct Fts3Keyword *pKey = &aKeyword[ii]; + + if( (pKey->parenOnly & ~sqlite3_fts3_enable_parentheses)!=0 ){ + continue; + } + + if( nInput>=pKey->n && 0==memcmp(zInput, pKey->z, pKey->n) ){ + int nNear = SQLITE_FTS3_DEFAULT_NEAR_PARAM; + int nKey = pKey->n; + char cNext; + + /* If this is a "NEAR" keyword, check for an explicit nearness. */ + if( pKey->eType==FTSQUERY_NEAR ){ + assert( nKey==4 ); + if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ + nNear = 0; + for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){ + nNear = nNear * 10 + (zInput[nKey] - '0'); + } + } + } + + /* At this point this is probably a keyword. But for that to be true, + ** the next byte must contain either whitespace, an open or close + ** parenthesis, a quote character, or EOF. + */ + cNext = zInput[nKey]; + if( fts3isspace(cNext) + || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 + ){ + pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr)); + if( !pRet ){ + return SQLITE_NOMEM; + } + pRet->eType = pKey->eType; + pRet->nNear = nNear; + *ppExpr = pRet; + *pnConsumed = (int)((zInput - z) + nKey); + return SQLITE_OK; + } + + /* Turns out that wasn't a keyword after all. This happens if the + ** user has supplied a token such as "ORacle". Continue. + */ + } + } + + /* See if we are dealing with a quoted phrase. If this is the case, then + ** search for the closing quote and pass the whole string to getNextString() + ** for processing. This is easy to do, as fts3 has no syntax for escaping + ** a quote character embedded in a string. + */ + if( *zInput=='"' ){ + for(ii=1; iinNest++; + rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); + if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; } + *pnConsumed = (int)(zInput - z) + 1 + nConsumed; + return rc; + }else if( *zInput==')' ){ + pParse->nNest--; + *pnConsumed = (int)((zInput - z) + 1); + *ppExpr = 0; + return SQLITE_DONE; + } + } + + /* If control flows to this point, this must be a regular token, or + ** the end of the input. Read a regular token using the sqlite3_tokenizer + ** interface. Before doing so, figure out if there is an explicit + ** column specifier for the token. + ** + ** TODO: Strangely, it is not possible to associate a column specifier + ** with a quoted phrase, only with a single token. Not sure if this was + ** an implementation artifact or an intentional decision when fts3 was + ** first implemented. Whichever it was, this module duplicates the + ** limitation. + */ + iCol = pParse->iDefaultCol; + iColLen = 0; + for(ii=0; iinCol; ii++){ + const char *zStr = pParse->azCol[ii]; + int nStr = (int)strlen(zStr); + if( nInput>nStr && zInput[nStr]==':' + && sqlite3_strnicmp(zStr, zInput, nStr)==0 + ){ + iCol = ii; + iColLen = (int)((zInput - z) + nStr + 1); + break; + } + } + rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed); + *pnConsumed += iColLen; + return rc; +} + +/* +** The argument is an Fts3Expr structure for a binary operator (any type +** except an FTSQUERY_PHRASE). Return an integer value representing the +** precedence of the operator. Lower values have a higher precedence (i.e. +** group more tightly). For example, in the C language, the == operator +** groups more tightly than ||, and would therefore have a higher precedence. +** +** When using the new fts3 query syntax (when SQLITE_ENABLE_FTS3_PARENTHESIS +** is defined), the order of the operators in precedence from highest to +** lowest is: +** +** NEAR +** NOT +** AND (including implicit ANDs) +** OR +** +** Note that when using the old query syntax, the OR operator has a higher +** precedence than the AND operator. +*/ +static int opPrecedence(Fts3Expr *p){ + assert( p->eType!=FTSQUERY_PHRASE ); + if( sqlite3_fts3_enable_parentheses ){ + return p->eType; + }else if( p->eType==FTSQUERY_NEAR ){ + return 1; + }else if( p->eType==FTSQUERY_OR ){ + return 2; + } + assert( p->eType==FTSQUERY_AND ); + return 3; +} + +/* +** Argument ppHead contains a pointer to the current head of a query +** expression tree being parsed. pPrev is the expression node most recently +** inserted into the tree. This function adds pNew, which is always a binary +** operator node, into the expression tree based on the relative precedence +** of pNew and the existing nodes of the tree. This may result in the head +** of the tree changing, in which case *ppHead is set to the new root node. +*/ +static void insertBinaryOperator( + Fts3Expr **ppHead, /* Pointer to the root node of a tree */ + Fts3Expr *pPrev, /* Node most recently inserted into the tree */ + Fts3Expr *pNew /* New binary node to insert into expression tree */ +){ + Fts3Expr *pSplit = pPrev; + while( pSplit->pParent && opPrecedence(pSplit->pParent)<=opPrecedence(pNew) ){ + pSplit = pSplit->pParent; + } + + if( pSplit->pParent ){ + assert( pSplit->pParent->pRight==pSplit ); + pSplit->pParent->pRight = pNew; + pNew->pParent = pSplit->pParent; + }else{ + *ppHead = pNew; + } + pNew->pLeft = pSplit; + pSplit->pParent = pNew; +} + +/* +** Parse the fts3 query expression found in buffer z, length n. This function +** returns either when the end of the buffer is reached or an unmatched +** closing bracket - ')' - is encountered. +** +** If successful, SQLITE_OK is returned, *ppExpr is set to point to the +** parsed form of the expression and *pnConsumed is set to the number of +** bytes read from buffer z. Otherwise, *ppExpr is set to 0 and SQLITE_NOMEM +** (out of memory error) or SQLITE_ERROR (parse error) is returned. +*/ +static int fts3ExprParse( + ParseContext *pParse, /* fts3 query parse context */ + const char *z, int n, /* Text of MATCH query */ + Fts3Expr **ppExpr, /* OUT: Parsed query structure */ + int *pnConsumed /* OUT: Number of bytes consumed */ +){ + Fts3Expr *pRet = 0; + Fts3Expr *pPrev = 0; + Fts3Expr *pNotBranch = 0; /* Only used in legacy parse mode */ + int nIn = n; + const char *zIn = z; + int rc = SQLITE_OK; + int isRequirePhrase = 1; + + while( rc==SQLITE_OK ){ + Fts3Expr *p = 0; + int nByte = 0; + + rc = getNextNode(pParse, zIn, nIn, &p, &nByte); + assert( nByte>0 || (rc!=SQLITE_OK && p==0) ); + if( rc==SQLITE_OK ){ + if( p ){ + int isPhrase; + + if( !sqlite3_fts3_enable_parentheses + && p->eType==FTSQUERY_PHRASE && pParse->isNot + ){ + /* Create an implicit NOT operator. */ + Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); + if( !pNot ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_NOMEM; + goto exprparse_out; + } + pNot->eType = FTSQUERY_NOT; + pNot->pRight = p; + p->pParent = pNot; + if( pNotBranch ){ + pNot->pLeft = pNotBranch; + pNotBranch->pParent = pNot; + } + pNotBranch = pNot; + p = pPrev; + }else{ + int eType = p->eType; + isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); + + /* The isRequirePhrase variable is set to true if a phrase or + ** an expression contained in parenthesis is required. If a + ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** isRequirePhrase is set, this is a syntax error. + */ + if( !isPhrase && isRequirePhrase ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase && !isRequirePhrase ){ + /* Insert an implicit AND operator. */ + Fts3Expr *pAnd; + assert( pRet && pPrev ); + pAnd = fts3MallocZero(sizeof(Fts3Expr)); + if( !pAnd ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_NOMEM; + goto exprparse_out; + } + pAnd->eType = FTSQUERY_AND; + insertBinaryOperator(&pRet, pPrev, pAnd); + pPrev = pAnd; + } + + /* This test catches attempts to make either operand of a NEAR + ** operator something other than a phrase. For example, either of + ** the following: + ** + ** (bracketed expression) NEAR phrase + ** phrase NEAR (bracketed expression) + ** + ** Return an error in either case. + */ + if( pPrev && ( + (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) + || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) + )){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase ){ + if( pRet ){ + assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); + pPrev->pRight = p; + p->pParent = pPrev; + }else{ + pRet = p; + } + }else{ + insertBinaryOperator(&pRet, pPrev, p); + } + isRequirePhrase = !isPhrase; + } + pPrev = p; + } + assert( nByte>0 ); + } + assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) ); + nIn -= nByte; + zIn += nByte; + } + + if( rc==SQLITE_DONE && pRet && isRequirePhrase ){ + rc = SQLITE_ERROR; + } + + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + if( !sqlite3_fts3_enable_parentheses && pNotBranch ){ + if( !pRet ){ + rc = SQLITE_ERROR; + }else{ + Fts3Expr *pIter = pNotBranch; + while( pIter->pLeft ){ + pIter = pIter->pLeft; + } + pIter->pLeft = pRet; + pRet->pParent = pIter; + pRet = pNotBranch; + } + } + } + *pnConsumed = n - nIn; + +exprparse_out: + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(pRet); + sqlite3Fts3ExprFree(pNotBranch); + pRet = 0; + } + *ppExpr = pRet; + return rc; +} + +/* +** Return SQLITE_ERROR if the maximum depth of the expression tree passed +** as the only argument is more than nMaxDepth. +*/ +static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){ + int rc = SQLITE_OK; + if( p ){ + if( nMaxDepth<0 ){ + rc = SQLITE_TOOBIG; + }else{ + rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1); + if( rc==SQLITE_OK ){ + rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1); + } + } + } + return rc; +} + +/* +** This function attempts to transform the expression tree at (*pp) to +** an equivalent but more balanced form. The tree is modified in place. +** If successful, SQLITE_OK is returned and (*pp) set to point to the +** new root expression node. +** +** nMaxDepth is the maximum allowable depth of the balanced sub-tree. +** +** Otherwise, if an error occurs, an SQLite error code is returned and +** expression (*pp) freed. +*/ +static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ + int rc = SQLITE_OK; /* Return code */ + Fts3Expr *pRoot = *pp; /* Initial root node */ + Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */ + int eType = pRoot->eType; /* Type of node in this tree */ + + if( nMaxDepth==0 ){ + rc = SQLITE_ERROR; + } + + if( rc==SQLITE_OK ){ + if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ + Fts3Expr **apLeaf; + apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth); + if( 0==apLeaf ){ + rc = SQLITE_NOMEM; + }else{ + memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); + } + + if( rc==SQLITE_OK ){ + int i; + Fts3Expr *p; + + /* Set $p to point to the left-most leaf in the tree of eType nodes. */ + for(p=pRoot; p->eType==eType; p=p->pLeft){ + assert( p->pParent==0 || p->pParent->pLeft==p ); + assert( p->pLeft && p->pRight ); + } + + /* This loop runs once for each leaf in the tree of eType nodes. */ + while( 1 ){ + int iLvl; + Fts3Expr *pParent = p->pParent; /* Current parent of p */ + + assert( pParent==0 || pParent->pLeft==p ); + p->pParent = 0; + if( pParent ){ + pParent->pLeft = 0; + }else{ + pRoot = 0; + } + rc = fts3ExprBalance(&p, nMaxDepth-1); + if( rc!=SQLITE_OK ) break; + + for(iLvl=0; p && iLvlpLeft = apLeaf[iLvl]; + pFree->pRight = p; + pFree->pLeft->pParent = pFree; + pFree->pRight->pParent = pFree; + + p = pFree; + pFree = pFree->pParent; + p->pParent = 0; + apLeaf[iLvl] = 0; + } + } + if( p ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_TOOBIG; + break; + } + + /* If that was the last leaf node, break out of the loop */ + if( pParent==0 ) break; + + /* Set $p to point to the next leaf in the tree of eType nodes */ + for(p=pParent->pRight; p->eType==eType; p=p->pLeft); + + /* Remove pParent from the original tree. */ + assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); + pParent->pRight->pParent = pParent->pParent; + if( pParent->pParent ){ + pParent->pParent->pLeft = pParent->pRight; + }else{ + assert( pParent==pRoot ); + pRoot = pParent->pRight; + } + + /* Link pParent into the free node list. It will be used as an + ** internal node of the new tree. */ + pParent->pParent = pFree; + pFree = pParent; + } + + if( rc==SQLITE_OK ){ + p = 0; + for(i=0; ipParent = 0; + }else{ + assert( pFree!=0 ); + pFree->pRight = p; + pFree->pLeft = apLeaf[i]; + pFree->pLeft->pParent = pFree; + pFree->pRight->pParent = pFree; + + p = pFree; + pFree = pFree->pParent; + p->pParent = 0; + } + } + } + pRoot = p; + }else{ + /* An error occurred. Delete the contents of the apLeaf[] array + ** and pFree list. Everything else is cleaned up by the call to + ** sqlite3Fts3ExprFree(pRoot) below. */ + Fts3Expr *pDel; + for(i=0; ipParent; + sqlite3_free(pDel); + } + } + + assert( pFree==0 ); + sqlite3_free( apLeaf ); + } + }else if( eType==FTSQUERY_NOT ){ + Fts3Expr *pLeft = pRoot->pLeft; + Fts3Expr *pRight = pRoot->pRight; + + pRoot->pLeft = 0; + pRoot->pRight = 0; + pLeft->pParent = 0; + pRight->pParent = 0; + + rc = fts3ExprBalance(&pLeft, nMaxDepth-1); + if( rc==SQLITE_OK ){ + rc = fts3ExprBalance(&pRight, nMaxDepth-1); + } + + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(pRight); + sqlite3Fts3ExprFree(pLeft); + }else{ + assert( pLeft && pRight ); + pRoot->pLeft = pLeft; + pLeft->pParent = pRoot; + pRoot->pRight = pRight; + pRight->pParent = pRoot; + } + } + } + + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(pRoot); + pRoot = 0; + } + *pp = pRoot; + return rc; +} + +/* +** This function is similar to sqlite3Fts3ExprParse(), with the following +** differences: +** +** 1. It does not do expression rebalancing. +** 2. It does not check that the expression does not exceed the +** maximum allowable depth. +** 3. Even if it fails, *ppExpr may still be set to point to an +** expression tree. It should be deleted using sqlite3Fts3ExprFree() +** in this case. +*/ +static int fts3ExprParseUnbalanced( + sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ + int iLangid, /* Language id for tokenizer */ + char **azCol, /* Array of column names for fts3 table */ + int bFts4, /* True to allow FTS4-only syntax */ + int nCol, /* Number of entries in azCol[] */ + int iDefaultCol, /* Default column to query */ + const char *z, int n, /* Text of MATCH query */ + Fts3Expr **ppExpr /* OUT: Parsed query structure */ +){ + int nParsed; + int rc; + ParseContext sParse; + + memset(&sParse, 0, sizeof(ParseContext)); + sParse.pTokenizer = pTokenizer; + sParse.iLangid = iLangid; + sParse.azCol = (const char **)azCol; + sParse.nCol = nCol; + sParse.iDefaultCol = iDefaultCol; + sParse.bFts4 = bFts4; + if( z==0 ){ + *ppExpr = 0; + return SQLITE_OK; + } + if( n<0 ){ + n = (int)strlen(z); + } + rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); + assert( rc==SQLITE_OK || *ppExpr==0 ); + + /* Check for mismatched parenthesis */ + if( rc==SQLITE_OK && sParse.nNest ){ + rc = SQLITE_ERROR; + } + + return rc; +} + +/* +** Parameters z and n contain a pointer to and length of a buffer containing +** an fts3 query expression, respectively. This function attempts to parse the +** query expression and create a tree of Fts3Expr structures representing the +** parsed expression. If successful, *ppExpr is set to point to the head +** of the parsed expression tree and SQLITE_OK is returned. If an error +** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse +** error) is returned and *ppExpr is set to 0. +** +** If parameter n is a negative number, then z is assumed to point to a +** nul-terminated string and the length is determined using strlen(). +** +** The first parameter, pTokenizer, is passed the fts3 tokenizer module to +** use to normalize query tokens while parsing the expression. The azCol[] +** array, which is assumed to contain nCol entries, should contain the names +** of each column in the target fts3 table, in order from left to right. +** Column names must be nul-terminated strings. +** +** The iDefaultCol parameter should be passed the index of the table column +** that appears on the left-hand-side of the MATCH operator (the default +** column to match against for tokens for which a column name is not explicitly +** specified as part of the query string), or -1 if tokens may by default +** match any table column. +*/ +SQLITE_PRIVATE int sqlite3Fts3ExprParse( + sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ + int iLangid, /* Language id for tokenizer */ + char **azCol, /* Array of column names for fts3 table */ + int bFts4, /* True to allow FTS4-only syntax */ + int nCol, /* Number of entries in azCol[] */ + int iDefaultCol, /* Default column to query */ + const char *z, int n, /* Text of MATCH query */ + Fts3Expr **ppExpr, /* OUT: Parsed query structure */ + char **pzErr /* OUT: Error message (sqlite3_malloc) */ +){ + int rc = fts3ExprParseUnbalanced( + pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr + ); + + /* Rebalance the expression. And check that its depth does not exceed + ** SQLITE_FTS3_MAX_EXPR_DEPTH. */ + if( rc==SQLITE_OK && *ppExpr ){ + rc = fts3ExprBalance(ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); + if( rc==SQLITE_OK ){ + rc = fts3ExprCheckDepth(*ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); + } + } + + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(*ppExpr); + *ppExpr = 0; + if( rc==SQLITE_TOOBIG ){ + sqlite3Fts3ErrMsg(pzErr, + "FTS expression tree is too large (maximum depth %d)", + SQLITE_FTS3_MAX_EXPR_DEPTH + ); + rc = SQLITE_ERROR; + }else if( rc==SQLITE_ERROR ){ + sqlite3Fts3ErrMsg(pzErr, "malformed MATCH expression: [%s]", z); + } + } + + return rc; +} + +/* +** Free a single node of an expression tree. +*/ +static void fts3FreeExprNode(Fts3Expr *p){ + assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); + sqlite3Fts3EvalPhraseCleanup(p->pPhrase); + sqlite3_free(p->aMI); + sqlite3_free(p); +} + +/* +** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). +** +** This function would be simpler if it recursively called itself. But +** that would mean passing a sufficiently large expression to ExprParse() +** could cause a stack overflow. +*/ +SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){ + Fts3Expr *p; + assert( pDel==0 || pDel->pParent==0 ); + for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){ + assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft ); + } + while( p ){ + Fts3Expr *pParent = p->pParent; + fts3FreeExprNode(p); + if( pParent && p==pParent->pLeft && pParent->pRight ){ + p = pParent->pRight; + while( p && (p->pLeft || p->pRight) ){ + assert( p==p->pParent->pRight || p==p->pParent->pLeft ); + p = (p->pLeft ? p->pLeft : p->pRight); + } + }else{ + p = pParent; + } + } +} + +/**************************************************************************** +***************************************************************************** +** Everything after this point is just test code. +*/ + +#ifdef SQLITE_TEST + +/* #include */ + +/* +** Function to query the hash-table of tokenizers (see README.tokenizers). +*/ +static int queryTestTokenizer( + sqlite3 *db, + const char *zName, + const sqlite3_tokenizer_module **pp +){ + int rc; + sqlite3_stmt *pStmt; + const char zSql[] = "SELECT fts3_tokenizer(?)"; + + *pp = 0; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + + sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){ + memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); + } + } + + return sqlite3_finalize(pStmt); +} + +/* +** Return a pointer to a buffer containing a text representation of the +** expression passed as the first argument. The buffer is obtained from +** sqlite3_malloc(). It is the responsibility of the caller to use +** sqlite3_free() to release the memory. If an OOM condition is encountered, +** NULL is returned. +** +** If the second argument is not NULL, then its contents are prepended to +** the returned expression text and then freed using sqlite3_free(). +*/ +static char *exprToString(Fts3Expr *pExpr, char *zBuf){ + if( pExpr==0 ){ + return sqlite3_mprintf(""); + } + switch( pExpr->eType ){ + case FTSQUERY_PHRASE: { + Fts3Phrase *pPhrase = pExpr->pPhrase; + int i; + zBuf = sqlite3_mprintf( + "%zPHRASE %d 0", zBuf, pPhrase->iColumn); + for(i=0; zBuf && inToken; i++){ + zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, + pPhrase->aToken[i].n, pPhrase->aToken[i].z, + (pPhrase->aToken[i].isPrefix?"+":"") + ); + } + return zBuf; + } + + case FTSQUERY_NEAR: + zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear); + break; + case FTSQUERY_NOT: + zBuf = sqlite3_mprintf("%zNOT ", zBuf); + break; + case FTSQUERY_AND: + zBuf = sqlite3_mprintf("%zAND ", zBuf); + break; + case FTSQUERY_OR: + zBuf = sqlite3_mprintf("%zOR ", zBuf); + break; + } + + if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf); + if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf); + if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf); + + if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf); + if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf); + + return zBuf; +} + +/* +** This is the implementation of a scalar SQL function used to test the +** expression parser. It should be called as follows: +** +** fts3_exprtest(, , , ...); +** +** The first argument, , is the name of the fts3 tokenizer used +** to parse the query expression (see README.tokenizers). The second argument +** is the query expression to parse. Each subsequent argument is the name +** of a column of the fts3 table that the query expression may refer to. +** For example: +** +** SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2'); +*/ +static void fts3ExprTest( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + sqlite3_tokenizer_module const *pModule = 0; + sqlite3_tokenizer *pTokenizer = 0; + int rc; + char **azCol = 0; + const char *zExpr; + int nExpr; + int nCol; + int ii; + Fts3Expr *pExpr; + char *zBuf = 0; + sqlite3 *db = sqlite3_context_db_handle(context); + + if( argc<3 ){ + sqlite3_result_error(context, + "Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1 + ); + return; + } + + rc = queryTestTokenizer(db, + (const char *)sqlite3_value_text(argv[0]), &pModule); + if( rc==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(context); + goto exprtest_out; + }else if( !pModule ){ + sqlite3_result_error(context, "No such tokenizer module", -1); + goto exprtest_out; + } + + rc = pModule->xCreate(0, 0, &pTokenizer); + assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); + if( rc==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(context); + goto exprtest_out; + } + pTokenizer->pModule = pModule; + + zExpr = (const char *)sqlite3_value_text(argv[1]); + nExpr = sqlite3_value_bytes(argv[1]); + nCol = argc-2; + azCol = (char **)sqlite3_malloc(nCol*sizeof(char *)); + if( !azCol ){ + sqlite3_result_error_nomem(context); + goto exprtest_out; + } + for(ii=0; iixDestroy(pTokenizer); + } + sqlite3_free(azCol); +} + +/* +** Register the query expression parser test function fts3_exprtest() +** with database connection db. +*/ +SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){ + int rc = sqlite3_create_function( + db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0 + ); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "fts3_exprtest_rebalance", + -1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0 + ); + } + return rc; +} + +#endif +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_expr.c *******************************************/ +/************** Begin file fts3_hash.c ***************************************/ +/* +** 2001 September 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This is the implementation of generic hash-tables used in SQLite. +** We've modified it slightly to serve as a standalone hash table +** implementation for the full-text indexing module. +*/ + +/* +** The code in this file is only compiled if: +** +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ +/* #include */ + +/* #include "fts3_hash.h" */ + +/* +** Malloc and Free functions +*/ +static void *fts3HashMalloc(int n){ + void *p = sqlite3_malloc(n); + if( p ){ + memset(p, 0, n); + } + return p; +} +static void fts3HashFree(void *p){ + sqlite3_free(p); +} + +/* Turn bulk memory into a hash table object by initializing the +** fields of the Hash structure. +** +** "pNew" is a pointer to the hash table that is to be initialized. +** keyClass is one of the constants +** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass +** determines what kind of key the hash table will use. "copyKey" is +** true if the hash table should make its own private copy of keys and +** false if it should just use the supplied pointer. +*/ +SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey){ + assert( pNew!=0 ); + assert( keyClass>=FTS3_HASH_STRING && keyClass<=FTS3_HASH_BINARY ); + pNew->keyClass = keyClass; + pNew->copyKey = copyKey; + pNew->first = 0; + pNew->count = 0; + pNew->htsize = 0; + pNew->ht = 0; +} + +/* Remove all entries from a hash table. Reclaim all memory. +** Call this routine to delete a hash table or to reset a hash table +** to the empty state. +*/ +SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash *pH){ + Fts3HashElem *elem; /* For looping over all elements of the table */ + + assert( pH!=0 ); + elem = pH->first; + pH->first = 0; + fts3HashFree(pH->ht); + pH->ht = 0; + pH->htsize = 0; + while( elem ){ + Fts3HashElem *next_elem = elem->next; + if( pH->copyKey && elem->pKey ){ + fts3HashFree(elem->pKey); + } + fts3HashFree(elem); + elem = next_elem; + } + pH->count = 0; +} + +/* +** Hash and comparison functions when the mode is FTS3_HASH_STRING +*/ +static int fts3StrHash(const void *pKey, int nKey){ + const char *z = (const char *)pKey; + unsigned h = 0; + if( nKey<=0 ) nKey = (int) strlen(z); + while( nKey > 0 ){ + h = (h<<3) ^ h ^ *z++; + nKey--; + } + return (int)(h & 0x7fffffff); +} +static int fts3StrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ + if( n1!=n2 ) return 1; + return strncmp((const char*)pKey1,(const char*)pKey2,n1); +} + +/* +** Hash and comparison functions when the mode is FTS3_HASH_BINARY +*/ +static int fts3BinHash(const void *pKey, int nKey){ + int h = 0; + const char *z = (const char *)pKey; + while( nKey-- > 0 ){ + h = (h<<3) ^ h ^ *(z++); + } + return h & 0x7fffffff; +} +static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){ + if( n1!=n2 ) return 1; + return memcmp(pKey1,pKey2,n1); +} + +/* +** Return a pointer to the appropriate hash function given the key class. +** +** The C syntax in this function definition may be unfamilar to some +** programmers, so we provide the following additional explanation: +** +** The name of the function is "ftsHashFunction". The function takes a +** single parameter "keyClass". The return value of ftsHashFunction() +** is a pointer to another function. Specifically, the return value +** of ftsHashFunction() is a pointer to a function that takes two parameters +** with types "const void*" and "int" and returns an "int". +*/ +static int (*ftsHashFunction(int keyClass))(const void*,int){ + if( keyClass==FTS3_HASH_STRING ){ + return &fts3StrHash; + }else{ + assert( keyClass==FTS3_HASH_BINARY ); + return &fts3BinHash; + } +} + +/* +** Return a pointer to the appropriate hash function given the key class. +** +** For help in interpreted the obscure C code in the function definition, +** see the header comment on the previous function. +*/ +static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){ + if( keyClass==FTS3_HASH_STRING ){ + return &fts3StrCompare; + }else{ + assert( keyClass==FTS3_HASH_BINARY ); + return &fts3BinCompare; + } +} + +/* Link an element into the hash table +*/ +static void fts3HashInsertElement( + Fts3Hash *pH, /* The complete hash table */ + struct _fts3ht *pEntry, /* The entry into which pNew is inserted */ + Fts3HashElem *pNew /* The element to be inserted */ +){ + Fts3HashElem *pHead; /* First element already in pEntry */ + pHead = pEntry->chain; + if( pHead ){ + pNew->next = pHead; + pNew->prev = pHead->prev; + if( pHead->prev ){ pHead->prev->next = pNew; } + else { pH->first = pNew; } + pHead->prev = pNew; + }else{ + pNew->next = pH->first; + if( pH->first ){ pH->first->prev = pNew; } + pNew->prev = 0; + pH->first = pNew; + } + pEntry->count++; + pEntry->chain = pNew; +} + + +/* Resize the hash table so that it cantains "new_size" buckets. +** "new_size" must be a power of 2. The hash table might fail +** to resize if sqliteMalloc() fails. +** +** Return non-zero if a memory allocation error occurs. +*/ +static int fts3Rehash(Fts3Hash *pH, int new_size){ + struct _fts3ht *new_ht; /* The new hash table */ + Fts3HashElem *elem, *next_elem; /* For looping over existing elements */ + int (*xHash)(const void*,int); /* The hash function */ + + assert( (new_size & (new_size-1))==0 ); + new_ht = (struct _fts3ht *)fts3HashMalloc( new_size*sizeof(struct _fts3ht) ); + if( new_ht==0 ) return 1; + fts3HashFree(pH->ht); + pH->ht = new_ht; + pH->htsize = new_size; + xHash = ftsHashFunction(pH->keyClass); + for(elem=pH->first, pH->first=0; elem; elem = next_elem){ + int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); + next_elem = elem->next; + fts3HashInsertElement(pH, &new_ht[h], elem); + } + return 0; +} + +/* This function (for internal use only) locates an element in an +** hash table that matches the given key. The hash for this key has +** already been computed and is passed as the 4th parameter. +*/ +static Fts3HashElem *fts3FindElementByHash( + const Fts3Hash *pH, /* The pH to be searched */ + const void *pKey, /* The key we are searching for */ + int nKey, + int h /* The hash for this key. */ +){ + Fts3HashElem *elem; /* Used to loop thru the element list */ + int count; /* Number of elements left to test */ + int (*xCompare)(const void*,int,const void*,int); /* comparison function */ + + if( pH->ht ){ + struct _fts3ht *pEntry = &pH->ht[h]; + elem = pEntry->chain; + count = pEntry->count; + xCompare = ftsCompareFunction(pH->keyClass); + while( count-- && elem ){ + if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ + return elem; + } + elem = elem->next; + } + } + return 0; +} + +/* Remove a single entry from the hash table given a pointer to that +** element and a hash on the element's key. +*/ +static void fts3RemoveElementByHash( + Fts3Hash *pH, /* The pH containing "elem" */ + Fts3HashElem* elem, /* The element to be removed from the pH */ + int h /* Hash value for the element */ +){ + struct _fts3ht *pEntry; + if( elem->prev ){ + elem->prev->next = elem->next; + }else{ + pH->first = elem->next; + } + if( elem->next ){ + elem->next->prev = elem->prev; + } + pEntry = &pH->ht[h]; + if( pEntry->chain==elem ){ + pEntry->chain = elem->next; + } + pEntry->count--; + if( pEntry->count<=0 ){ + pEntry->chain = 0; + } + if( pH->copyKey && elem->pKey ){ + fts3HashFree(elem->pKey); + } + fts3HashFree( elem ); + pH->count--; + if( pH->count<=0 ){ + assert( pH->first==0 ); + assert( pH->count==0 ); + fts3HashClear(pH); + } +} + +SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem( + const Fts3Hash *pH, + const void *pKey, + int nKey +){ + int h; /* A hash on key */ + int (*xHash)(const void*,int); /* The hash function */ + + if( pH==0 || pH->ht==0 ) return 0; + xHash = ftsHashFunction(pH->keyClass); + assert( xHash!=0 ); + h = (*xHash)(pKey,nKey); + assert( (pH->htsize & (pH->htsize-1))==0 ); + return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1)); +} + +/* +** Attempt to locate an element of the hash table pH with a key +** that matches pKey,nKey. Return the data for this element if it is +** found, or NULL if there is no match. +*/ +SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){ + Fts3HashElem *pElem; /* The element that matches key (if any) */ + + pElem = sqlite3Fts3HashFindElem(pH, pKey, nKey); + return pElem ? pElem->data : 0; +} + +/* Insert an element into the hash table pH. The key is pKey,nKey +** and the data is "data". +** +** If no element exists with a matching key, then a new +** element is created. A copy of the key is made if the copyKey +** flag is set. NULL is returned. +** +** If another element already exists with the same key, then the +** new data replaces the old data and the old data is returned. +** The key is not copied in this instance. If a malloc fails, then +** the new data is returned and the hash table is unchanged. +** +** If the "data" parameter to this function is NULL, then the +** element corresponding to "key" is removed from the hash table. +*/ +SQLITE_PRIVATE void *sqlite3Fts3HashInsert( + Fts3Hash *pH, /* The hash table to insert into */ + const void *pKey, /* The key */ + int nKey, /* Number of bytes in the key */ + void *data /* The data */ +){ + int hraw; /* Raw hash value of the key */ + int h; /* the hash of the key modulo hash table size */ + Fts3HashElem *elem; /* Used to loop thru the element list */ + Fts3HashElem *new_elem; /* New element added to the pH */ + int (*xHash)(const void*,int); /* The hash function */ + + assert( pH!=0 ); + xHash = ftsHashFunction(pH->keyClass); + assert( xHash!=0 ); + hraw = (*xHash)(pKey, nKey); + assert( (pH->htsize & (pH->htsize-1))==0 ); + h = hraw & (pH->htsize-1); + elem = fts3FindElementByHash(pH,pKey,nKey,h); + if( elem ){ + void *old_data = elem->data; + if( data==0 ){ + fts3RemoveElementByHash(pH,elem,h); + }else{ + elem->data = data; + } + return old_data; + } + if( data==0 ) return 0; + if( (pH->htsize==0 && fts3Rehash(pH,8)) + || (pH->count>=pH->htsize && fts3Rehash(pH, pH->htsize*2)) + ){ + pH->count = 0; + return data; + } + assert( pH->htsize>0 ); + new_elem = (Fts3HashElem*)fts3HashMalloc( sizeof(Fts3HashElem) ); + if( new_elem==0 ) return data; + if( pH->copyKey && pKey!=0 ){ + new_elem->pKey = fts3HashMalloc( nKey ); + if( new_elem->pKey==0 ){ + fts3HashFree(new_elem); + return data; + } + memcpy((void*)new_elem->pKey, pKey, nKey); + }else{ + new_elem->pKey = (void*)pKey; + } + new_elem->nKey = nKey; + pH->count++; + assert( pH->htsize>0 ); + assert( (pH->htsize & (pH->htsize-1))==0 ); + h = hraw & (pH->htsize-1); + fts3HashInsertElement(pH, &pH->ht[h], new_elem); + new_elem->data = data; + return 0; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_hash.c *******************************************/ +/************** Begin file fts3_porter.c *************************************/ +/* +** 2006 September 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. +** +************************************************************************* +** Implementation of the full-text-search tokenizer that implements +** a Porter stemmer. +*/ + +/* +** The code in this file is only compiled if: +** +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +/* #include "fts3_tokenizer.h" */ + +/* +** Class derived from sqlite3_tokenizer +*/ +typedef struct porter_tokenizer { + sqlite3_tokenizer base; /* Base class */ +} porter_tokenizer; + +/* +** Class derived from sqlite3_tokenizer_cursor +*/ +typedef struct porter_tokenizer_cursor { + sqlite3_tokenizer_cursor base; + const char *zInput; /* input we are tokenizing */ + int nInput; /* size of the input */ + int iOffset; /* current position in zInput */ + int iToken; /* index of next token to be returned */ + char *zToken; /* storage for current token */ + int nAllocated; /* space allocated to zToken buffer */ +} porter_tokenizer_cursor; + + +/* +** Create a new tokenizer instance. +*/ +static int porterCreate( + int argc, const char * const *argv, + sqlite3_tokenizer **ppTokenizer +){ + porter_tokenizer *t; + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + + t = (porter_tokenizer *) sqlite3_malloc(sizeof(*t)); + if( t==NULL ) return SQLITE_NOMEM; + memset(t, 0, sizeof(*t)); + *ppTokenizer = &t->base; + return SQLITE_OK; +} + +/* +** Destroy a tokenizer +*/ +static int porterDestroy(sqlite3_tokenizer *pTokenizer){ + sqlite3_free(pTokenizer); + return SQLITE_OK; +} + +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is zInput[0..nInput-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int porterOpen( + sqlite3_tokenizer *pTokenizer, /* The tokenizer */ + const char *zInput, int nInput, /* String to be tokenized */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +){ + porter_tokenizer_cursor *c; + + UNUSED_PARAMETER(pTokenizer); + + c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); + if( c==NULL ) return SQLITE_NOMEM; + + c->zInput = zInput; + if( zInput==0 ){ + c->nInput = 0; + }else if( nInput<0 ){ + c->nInput = (int)strlen(zInput); + }else{ + c->nInput = nInput; + } + c->iOffset = 0; /* start tokenizing at the beginning */ + c->iToken = 0; + c->zToken = NULL; /* no space allocated, yet. */ + c->nAllocated = 0; + + *ppCursor = &c->base; + return SQLITE_OK; +} + +/* +** Close a tokenization cursor previously opened by a call to +** porterOpen() above. +*/ +static int porterClose(sqlite3_tokenizer_cursor *pCursor){ + porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; + sqlite3_free(c->zToken); + sqlite3_free(c); + return SQLITE_OK; +} +/* +** Vowel or consonant +*/ +static const char cType[] = { + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 2, 1 +}; + +/* +** isConsonant() and isVowel() determine if their first character in +** the string they point to is a consonant or a vowel, according +** to Porter ruls. +** +** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'. +** 'Y' is a consonant unless it follows another consonant, +** in which case it is a vowel. +** +** In these routine, the letters are in reverse order. So the 'y' rule +** is that 'y' is a consonant unless it is followed by another +** consonent. +*/ +static int isVowel(const char*); +static int isConsonant(const char *z){ + int j; + char x = *z; + if( x==0 ) return 0; + assert( x>='a' && x<='z' ); + j = cType[x-'a']; + if( j<2 ) return j; + return z[1]==0 || isVowel(z + 1); +} +static int isVowel(const char *z){ + int j; + char x = *z; + if( x==0 ) return 0; + assert( x>='a' && x<='z' ); + j = cType[x-'a']; + if( j<2 ) return 1-j; + return isConsonant(z + 1); +} + +/* +** Let any sequence of one or more vowels be represented by V and let +** C be sequence of one or more consonants. Then every word can be +** represented as: +** +** [C] (VC){m} [V] +** +** In prose: A word is an optional consonant followed by zero or +** vowel-consonant pairs followed by an optional vowel. "m" is the +** number of vowel consonant pairs. This routine computes the value +** of m for the first i bytes of a word. +** +** Return true if the m-value for z is 1 or more. In other words, +** return true if z contains at least one vowel that is followed +** by a consonant. +** +** In this routine z[] is in reverse order. So we are really looking +** for an instance of a consonant followed by a vowel. +*/ +static int m_gt_0(const char *z){ + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + return *z!=0; +} + +/* Like mgt0 above except we are looking for a value of m which is +** exactly 1 +*/ +static int m_eq_1(const char *z){ + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + if( *z==0 ) return 0; + while( isVowel(z) ){ z++; } + if( *z==0 ) return 1; + while( isConsonant(z) ){ z++; } + return *z==0; +} + +/* Like mgt0 above except we are looking for a value of m>1 instead +** or m>0 +*/ +static int m_gt_1(const char *z){ + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + if( *z==0 ) return 0; + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + return *z!=0; +} + +/* +** Return TRUE if there is a vowel anywhere within z[0..n-1] +*/ +static int hasVowel(const char *z){ + while( isConsonant(z) ){ z++; } + return *z!=0; +} + +/* +** Return TRUE if the word ends in a double consonant. +** +** The text is reversed here. So we are really looking at +** the first two characters of z[]. +*/ +static int doubleConsonant(const char *z){ + return isConsonant(z) && z[0]==z[1]; +} + +/* +** Return TRUE if the word ends with three letters which +** are consonant-vowel-consonent and where the final consonant +** is not 'w', 'x', or 'y'. +** +** The word is reversed here. So we are really checking the +** first three letters and the first one cannot be in [wxy]. +*/ +static int star_oh(const char *z){ + return + isConsonant(z) && + z[0]!='w' && z[0]!='x' && z[0]!='y' && + isVowel(z+1) && + isConsonant(z+2); +} + +/* +** If the word ends with zFrom and xCond() is true for the stem +** of the word that preceeds the zFrom ending, then change the +** ending to zTo. +** +** The input word *pz and zFrom are both in reverse order. zTo +** is in normal order. +** +** Return TRUE if zFrom matches. Return FALSE if zFrom does not +** match. Not that TRUE is returned even if xCond() fails and +** no substitution occurs. +*/ +static int stem( + char **pz, /* The word being stemmed (Reversed) */ + const char *zFrom, /* If the ending matches this... (Reversed) */ + const char *zTo, /* ... change the ending to this (not reversed) */ + int (*xCond)(const char*) /* Condition that must be true */ +){ + char *z = *pz; + while( *zFrom && *zFrom==*z ){ z++; zFrom++; } + if( *zFrom!=0 ) return 0; + if( xCond && !xCond(z) ) return 1; + while( *zTo ){ + *(--z) = *(zTo++); + } + *pz = z; + return 1; +} + +/* +** This is the fallback stemmer used when the porter stemmer is +** inappropriate. The input word is copied into the output with +** US-ASCII case folding. If the input word is too long (more +** than 20 bytes if it contains no digits or more than 6 bytes if +** it contains digits) then word is truncated to 20 or 6 bytes +** by taking 10 or 3 bytes from the beginning and end. +*/ +static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ + int i, mx, j; + int hasDigit = 0; + for(i=0; i='A' && c<='Z' ){ + zOut[i] = c - 'A' + 'a'; + }else{ + if( c>='0' && c<='9' ) hasDigit = 1; + zOut[i] = c; + } + } + mx = hasDigit ? 3 : 10; + if( nIn>mx*2 ){ + for(j=mx, i=nIn-mx; i=(int)sizeof(zReverse)-7 ){ + /* The word is too big or too small for the porter stemmer. + ** Fallback to the copy stemmer */ + copy_stemmer(zIn, nIn, zOut, pnOut); + return; + } + for(i=0, j=sizeof(zReverse)-6; i='A' && c<='Z' ){ + zReverse[j] = c + 'a' - 'A'; + }else if( c>='a' && c<='z' ){ + zReverse[j] = c; + }else{ + /* The use of a character not in [a-zA-Z] means that we fallback + ** to the copy stemmer */ + copy_stemmer(zIn, nIn, zOut, pnOut); + return; + } + } + memset(&zReverse[sizeof(zReverse)-5], 0, 5); + z = &zReverse[j+1]; + + + /* Step 1a */ + if( z[0]=='s' ){ + if( + !stem(&z, "sess", "ss", 0) && + !stem(&z, "sei", "i", 0) && + !stem(&z, "ss", "ss", 0) + ){ + z++; + } + } + + /* Step 1b */ + z2 = z; + if( stem(&z, "dee", "ee", m_gt_0) ){ + /* Do nothing. The work was all in the test */ + }else if( + (stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel)) + && z!=z2 + ){ + if( stem(&z, "ta", "ate", 0) || + stem(&z, "lb", "ble", 0) || + stem(&z, "zi", "ize", 0) ){ + /* Do nothing. The work was all in the test */ + }else if( doubleConsonant(z) && (*z!='l' && *z!='s' && *z!='z') ){ + z++; + }else if( m_eq_1(z) && star_oh(z) ){ + *(--z) = 'e'; + } + } + + /* Step 1c */ + if( z[0]=='y' && hasVowel(z+1) ){ + z[0] = 'i'; + } + + /* Step 2 */ + switch( z[1] ){ + case 'a': + if( !stem(&z, "lanoita", "ate", m_gt_0) ){ + stem(&z, "lanoit", "tion", m_gt_0); + } + break; + case 'c': + if( !stem(&z, "icne", "ence", m_gt_0) ){ + stem(&z, "icna", "ance", m_gt_0); + } + break; + case 'e': + stem(&z, "rezi", "ize", m_gt_0); + break; + case 'g': + stem(&z, "igol", "log", m_gt_0); + break; + case 'l': + if( !stem(&z, "ilb", "ble", m_gt_0) + && !stem(&z, "illa", "al", m_gt_0) + && !stem(&z, "iltne", "ent", m_gt_0) + && !stem(&z, "ile", "e", m_gt_0) + ){ + stem(&z, "ilsuo", "ous", m_gt_0); + } + break; + case 'o': + if( !stem(&z, "noitazi", "ize", m_gt_0) + && !stem(&z, "noita", "ate", m_gt_0) + ){ + stem(&z, "rota", "ate", m_gt_0); + } + break; + case 's': + if( !stem(&z, "msila", "al", m_gt_0) + && !stem(&z, "ssenevi", "ive", m_gt_0) + && !stem(&z, "ssenluf", "ful", m_gt_0) + ){ + stem(&z, "ssensuo", "ous", m_gt_0); + } + break; + case 't': + if( !stem(&z, "itila", "al", m_gt_0) + && !stem(&z, "itivi", "ive", m_gt_0) + ){ + stem(&z, "itilib", "ble", m_gt_0); + } + break; + } + + /* Step 3 */ + switch( z[0] ){ + case 'e': + if( !stem(&z, "etaci", "ic", m_gt_0) + && !stem(&z, "evita", "", m_gt_0) + ){ + stem(&z, "ezila", "al", m_gt_0); + } + break; + case 'i': + stem(&z, "itici", "ic", m_gt_0); + break; + case 'l': + if( !stem(&z, "laci", "ic", m_gt_0) ){ + stem(&z, "luf", "", m_gt_0); + } + break; + case 's': + stem(&z, "ssen", "", m_gt_0); + break; + } + + /* Step 4 */ + switch( z[1] ){ + case 'a': + if( z[0]=='l' && m_gt_1(z+2) ){ + z += 2; + } + break; + case 'c': + if( z[0]=='e' && z[2]=='n' && (z[3]=='a' || z[3]=='e') && m_gt_1(z+4) ){ + z += 4; + } + break; + case 'e': + if( z[0]=='r' && m_gt_1(z+2) ){ + z += 2; + } + break; + case 'i': + if( z[0]=='c' && m_gt_1(z+2) ){ + z += 2; + } + break; + case 'l': + if( z[0]=='e' && z[2]=='b' && (z[3]=='a' || z[3]=='i') && m_gt_1(z+4) ){ + z += 4; + } + break; + case 'n': + if( z[0]=='t' ){ + if( z[2]=='a' ){ + if( m_gt_1(z+3) ){ + z += 3; + } + }else if( z[2]=='e' ){ + if( !stem(&z, "tneme", "", m_gt_1) + && !stem(&z, "tnem", "", m_gt_1) + ){ + stem(&z, "tne", "", m_gt_1); + } + } + } + break; + case 'o': + if( z[0]=='u' ){ + if( m_gt_1(z+2) ){ + z += 2; + } + }else if( z[3]=='s' || z[3]=='t' ){ + stem(&z, "noi", "", m_gt_1); + } + break; + case 's': + if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){ + z += 3; + } + break; + case 't': + if( !stem(&z, "eta", "", m_gt_1) ){ + stem(&z, "iti", "", m_gt_1); + } + break; + case 'u': + if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){ + z += 3; + } + break; + case 'v': + case 'z': + if( z[0]=='e' && z[2]=='i' && m_gt_1(z+3) ){ + z += 3; + } + break; + } + + /* Step 5a */ + if( z[0]=='e' ){ + if( m_gt_1(z+1) ){ + z++; + }else if( m_eq_1(z+1) && !star_oh(z+1) ){ + z++; + } + } + + /* Step 5b */ + if( m_gt_1(z) && z[0]=='l' && z[1]=='l' ){ + z++; + } + + /* z[] is now the stemmed word in reverse order. Flip it back + ** around into forward order and return. + */ + *pnOut = i = (int)strlen(z); + zOut[i] = 0; + while( *z ){ + zOut[--i] = *(z++); + } +} + +/* +** Characters that can be part of a token. We assume any character +** whose value is greater than 0x80 (any UTF character) can be +** part of a token. In other words, delimiters all must have +** values of 0x7f or lower. +*/ +static const char porterIdChar[] = { +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ +}; +#define isDelim(C) (((ch=C)&0x80)==0 && (ch<0x30 || !porterIdChar[ch-0x30])) + +/* +** Extract the next token from a tokenization cursor. The cursor must +** have been opened by a prior call to porterOpen(). +*/ +static int porterNext( + sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by porterOpen */ + const char **pzToken, /* OUT: *pzToken is the token text */ + int *pnBytes, /* OUT: Number of bytes in token */ + int *piStartOffset, /* OUT: Starting offset of token */ + int *piEndOffset, /* OUT: Ending offset of token */ + int *piPosition /* OUT: Position integer of token */ +){ + porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; + const char *z = c->zInput; + + while( c->iOffsetnInput ){ + int iStartOffset, ch; + + /* Scan past delimiter characters */ + while( c->iOffsetnInput && isDelim(z[c->iOffset]) ){ + c->iOffset++; + } + + /* Count non-delimiter characters. */ + iStartOffset = c->iOffset; + while( c->iOffsetnInput && !isDelim(z[c->iOffset]) ){ + c->iOffset++; + } + + if( c->iOffset>iStartOffset ){ + int n = c->iOffset-iStartOffset; + if( n>c->nAllocated ){ + char *pNew; + c->nAllocated = n+20; + pNew = sqlite3_realloc(c->zToken, c->nAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->zToken = pNew; + } + porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); + *pzToken = c->zToken; + *piStartOffset = iStartOffset; + *piEndOffset = c->iOffset; + *piPosition = c->iToken++; + return SQLITE_OK; + } + } + return SQLITE_DONE; +} + +/* +** The set of routines that implement the porter-stemmer tokenizer +*/ +static const sqlite3_tokenizer_module porterTokenizerModule = { + 0, + porterCreate, + porterDestroy, + porterOpen, + porterClose, + porterNext, + 0 +}; + +/* +** Allocate a new porter tokenizer. Return a pointer to the new +** tokenizer in *ppModule +*/ +SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule( + sqlite3_tokenizer_module const**ppModule +){ + *ppModule = &porterTokenizerModule; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_porter.c *****************************************/ +/************** Begin file fts3_tokenizer.c **********************************/ +/* +** 2007 June 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This is part of an SQLite module implementing full-text search. +** This particular file implements the generic tokenizer interface. +*/ + +/* +** The code in this file is only compiled if: +** +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ + +/* +** Return true if the two-argument version of fts3_tokenizer() +** has been activated via a prior call to sqlite3_db_config(db, +** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0); +*/ +static int fts3TokenizerEnabled(sqlite3_context *context){ + sqlite3 *db = sqlite3_context_db_handle(context); + int isEnabled = 0; + sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled); + return isEnabled; +} + +/* +** Implementation of the SQL scalar function for accessing the underlying +** hash table. This function may be called as follows: +** +** SELECT (); +** SELECT (, ); +** +** where is the name passed as the second argument +** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer'). +** +** If the argument is specified, it must be a blob value +** containing a pointer to be stored as the hash data corresponding +** to the string . If is not specified, then +** the string must already exist in the has table. Otherwise, +** an error is returned. +** +** Whether or not the argument is specified, the value returned +** is a blob containing the pointer stored as the hash data corresponding +** to string (after the hash-table is updated, if applicable). +*/ +static void fts3TokenizerFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Fts3Hash *pHash; + void *pPtr = 0; + const unsigned char *zName; + int nName; + + assert( argc==1 || argc==2 ); + + pHash = (Fts3Hash *)sqlite3_user_data(context); + + zName = sqlite3_value_text(argv[0]); + nName = sqlite3_value_bytes(argv[0])+1; + + if( argc==2 ){ + if( fts3TokenizerEnabled(context) ){ + void *pOld; + int n = sqlite3_value_bytes(argv[1]); + if( zName==0 || n!=sizeof(pPtr) ){ + sqlite3_result_error(context, "argument type mismatch", -1); + return; + } + pPtr = *(void **)sqlite3_value_blob(argv[1]); + pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); + if( pOld==pPtr ){ + sqlite3_result_error(context, "out of memory", -1); + } + }else{ + sqlite3_result_error(context, "fts3tokenize disabled", -1); + return; + } + }else{ + if( zName ){ + pPtr = sqlite3Fts3HashFind(pHash, zName, nName); + } + if( !pPtr ){ + char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + return; + } + } + sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); +} + +SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){ + static const char isFtsIdChar[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ + }; + return (c&0x80 || isFtsIdChar[(int)(c)]); +} + +SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){ + const char *z1; + const char *z2 = 0; + + /* Find the start of the next token. */ + z1 = zStr; + while( z2==0 ){ + char c = *z1; + switch( c ){ + case '\0': return 0; /* No more tokens here */ + case '\'': + case '"': + case '`': { + z2 = z1; + while( *++z2 && (*z2!=c || *++z2==c) ); + break; + } + case '[': + z2 = &z1[1]; + while( *z2 && z2[0]!=']' ) z2++; + if( *z2 ) z2++; + break; + + default: + if( sqlite3Fts3IsIdChar(*z1) ){ + z2 = &z1[1]; + while( sqlite3Fts3IsIdChar(*z2) ) z2++; + }else{ + z1++; + } + } + } + + *pn = (int)(z2-z1); + return z1; +} + +SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( + Fts3Hash *pHash, /* Tokenizer hash table */ + const char *zArg, /* Tokenizer name */ + sqlite3_tokenizer **ppTok, /* OUT: Tokenizer (if applicable) */ + char **pzErr /* OUT: Set to malloced error message */ +){ + int rc; + char *z = (char *)zArg; + int n = 0; + char *zCopy; + char *zEnd; /* Pointer to nul-term of zCopy */ + sqlite3_tokenizer_module *m; + + zCopy = sqlite3_mprintf("%s", zArg); + if( !zCopy ) return SQLITE_NOMEM; + zEnd = &zCopy[strlen(zCopy)]; + + z = (char *)sqlite3Fts3NextToken(zCopy, &n); + if( z==0 ){ + assert( n==0 ); + z = zCopy; + } + z[n] = '\0'; + sqlite3Fts3Dequote(z); + + m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1); + if( !m ){ + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z); + rc = SQLITE_ERROR; + }else{ + char const **aArg = 0; + int iArg = 0; + z = &z[n+1]; + while( zxCreate(iArg, aArg, ppTok); + assert( rc!=SQLITE_OK || *ppTok ); + if( rc!=SQLITE_OK ){ + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer"); + }else{ + (*ppTok)->pModule = m; + } + sqlite3_free((void *)aArg); + } + + sqlite3_free(zCopy); + return rc; +} + + +#ifdef SQLITE_TEST + +#if defined(INCLUDE_SQLITE_TCL_H) +# include "sqlite_tcl.h" +#else +# include "tcl.h" +#endif +/* #include */ + +/* +** Implementation of a special SQL scalar function for testing tokenizers +** designed to be used in concert with the Tcl testing framework. This +** function must be called with two or more arguments: +** +** SELECT (, ..., ); +** +** where is the name passed as the second argument +** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer') +** concatenated with the string '_test' (e.g. 'fts3_tokenizer_test'). +** +** The return value is a string that may be interpreted as a Tcl +** list. For each token in the , three elements are +** added to the returned list. The first is the token position, the +** second is the token text (folded, stemmed, etc.) and the third is the +** substring of associated with the token. For example, +** using the built-in "simple" tokenizer: +** +** SELECT fts_tokenizer_test('simple', 'I don't see how'); +** +** will return the string: +** +** "{0 i I 1 dont don't 2 see see 3 how how}" +** +*/ +static void testFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Fts3Hash *pHash; + sqlite3_tokenizer_module *p; + sqlite3_tokenizer *pTokenizer = 0; + sqlite3_tokenizer_cursor *pCsr = 0; + + const char *zErr = 0; + + const char *zName; + int nName; + const char *zInput; + int nInput; + + const char *azArg[64]; + + const char *zToken; + int nToken = 0; + int iStart = 0; + int iEnd = 0; + int iPos = 0; + int i; + + Tcl_Obj *pRet; + + if( argc<2 ){ + sqlite3_result_error(context, "insufficient arguments", -1); + return; + } + + nName = sqlite3_value_bytes(argv[0]); + zName = (const char *)sqlite3_value_text(argv[0]); + nInput = sqlite3_value_bytes(argv[argc-1]); + zInput = (const char *)sqlite3_value_text(argv[argc-1]); + + pHash = (Fts3Hash *)sqlite3_user_data(context); + p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); + + if( !p ){ + char *zErr2 = sqlite3_mprintf("unknown tokenizer: %s", zName); + sqlite3_result_error(context, zErr2, -1); + sqlite3_free(zErr2); + return; + } + + pRet = Tcl_NewObj(); + Tcl_IncrRefCount(pRet); + + for(i=1; ixCreate(argc-2, azArg, &pTokenizer) ){ + zErr = "error in xCreate()"; + goto finish; + } + pTokenizer->pModule = p; + if( sqlite3Fts3OpenTokenizer(pTokenizer, 0, zInput, nInput, &pCsr) ){ + zErr = "error in xOpen()"; + goto finish; + } + + while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){ + Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); + zToken = &zInput[iStart]; + nToken = iEnd-iStart; + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); + } + + if( SQLITE_OK!=p->xClose(pCsr) ){ + zErr = "error in xClose()"; + goto finish; + } + if( SQLITE_OK!=p->xDestroy(pTokenizer) ){ + zErr = "error in xDestroy()"; + goto finish; + } + +finish: + if( zErr ){ + sqlite3_result_error(context, zErr, -1); + }else{ + sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT); + } + Tcl_DecrRefCount(pRet); +} + +static +int registerTokenizer( + sqlite3 *db, + char *zName, + const sqlite3_tokenizer_module *p +){ + int rc; + sqlite3_stmt *pStmt; + const char zSql[] = "SELECT fts3_tokenizer(?, ?)"; + + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + + sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); + sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); + sqlite3_step(pStmt); + + return sqlite3_finalize(pStmt); +} + + +static +int queryTokenizer( + sqlite3 *db, + char *zName, + const sqlite3_tokenizer_module **pp +){ + int rc; + sqlite3_stmt *pStmt; + const char zSql[] = "SELECT fts3_tokenizer(?)"; + + *pp = 0; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + + sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){ + memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); + } + } + + return sqlite3_finalize(pStmt); +} + +SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); + +/* +** Implementation of the scalar function fts3_tokenizer_internal_test(). +** This function is used for testing only, it is not included in the +** build unless SQLITE_TEST is defined. +** +** The purpose of this is to test that the fts3_tokenizer() function +** can be used as designed by the C-code in the queryTokenizer and +** registerTokenizer() functions above. These two functions are repeated +** in the README.tokenizer file as an example, so it is important to +** test them. +** +** To run the tests, evaluate the fts3_tokenizer_internal_test() scalar +** function with no arguments. An assert() will fail if a problem is +** detected. i.e.: +** +** SELECT fts3_tokenizer_internal_test(); +** +*/ +static void intTestFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int rc; + const sqlite3_tokenizer_module *p1; + const sqlite3_tokenizer_module *p2; + sqlite3 *db = (sqlite3 *)sqlite3_user_data(context); + + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + + /* Test the query function */ + sqlite3Fts3SimpleTokenizerModule(&p1); + rc = queryTokenizer(db, "simple", &p2); + assert( rc==SQLITE_OK ); + assert( p1==p2 ); + rc = queryTokenizer(db, "nosuchtokenizer", &p2); + assert( rc==SQLITE_ERROR ); + assert( p2==0 ); + assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); + + /* Test the storage function */ + if( fts3TokenizerEnabled(context) ){ + rc = registerTokenizer(db, "nosuchtokenizer", p1); + assert( rc==SQLITE_OK ); + rc = queryTokenizer(db, "nosuchtokenizer", &p2); + assert( rc==SQLITE_OK ); + assert( p2==p1 ); + } + + sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); +} + +#endif + +/* +** Set up SQL objects in database db used to access the contents of +** the hash table pointed to by argument pHash. The hash table must +** been initialized to use string keys, and to take a private copy +** of the key when a value is inserted. i.e. by a call similar to: +** +** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); +** +** This function adds a scalar function (see header comment above +** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is +** defined at compilation time, a temporary virtual table (see header +** comment above struct HashTableVtab) to the database schema. Both +** provide read/write access to the contents of *pHash. +** +** The third argument to this function, zName, is used as the name +** of both the scalar and, if created, the virtual table. +*/ +SQLITE_PRIVATE int sqlite3Fts3InitHashTable( + sqlite3 *db, + Fts3Hash *pHash, + const char *zName +){ + int rc = SQLITE_OK; + void *p = (void *)pHash; + const int any = SQLITE_ANY; + +#ifdef SQLITE_TEST + char *zTest = 0; + char *zTest2 = 0; + void *pdb = (void *)db; + zTest = sqlite3_mprintf("%s_test", zName); + zTest2 = sqlite3_mprintf("%s_internal_test", zName); + if( !zTest || !zTest2 ){ + rc = SQLITE_NOMEM; + } +#endif + + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0); + } + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0); + } +#ifdef SQLITE_TEST + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zTest, -1, any, p, testFunc, 0, 0); + } + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0); + } +#endif + +#ifdef SQLITE_TEST + sqlite3_free(zTest); + sqlite3_free(zTest2); +#endif + + return rc; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_tokenizer.c **************************************/ +/************** Begin file fts3_tokenizer1.c *********************************/ +/* +** 2006 Oct 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. +** +****************************************************************************** +** +** Implementation of the "simple" full-text-search tokenizer. +*/ + +/* +** The code in this file is only compiled if: +** +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +/* #include "fts3_tokenizer.h" */ + +typedef struct simple_tokenizer { + sqlite3_tokenizer base; + char delim[128]; /* flag ASCII delimiters */ +} simple_tokenizer; + +typedef struct simple_tokenizer_cursor { + sqlite3_tokenizer_cursor base; + const char *pInput; /* input we are tokenizing */ + int nBytes; /* size of the input */ + int iOffset; /* current position in pInput */ + int iToken; /* index of next token to be returned */ + char *pToken; /* storage for current token */ + int nTokenAllocated; /* space allocated to zToken buffer */ +} simple_tokenizer_cursor; + + +static int simpleDelim(simple_tokenizer *t, unsigned char c){ + return c<0x80 && t->delim[c]; +} +static int fts3_isalnum(int x){ + return (x>='0' && x<='9') || (x>='A' && x<='Z') || (x>='a' && x<='z'); +} + +/* +** Create a new tokenizer instance. +*/ +static int simpleCreate( + int argc, const char * const *argv, + sqlite3_tokenizer **ppTokenizer +){ + simple_tokenizer *t; + + t = (simple_tokenizer *) sqlite3_malloc(sizeof(*t)); + if( t==NULL ) return SQLITE_NOMEM; + memset(t, 0, sizeof(*t)); + + /* TODO(shess) Delimiters need to remain the same from run to run, + ** else we need to reindex. One solution would be a meta-table to + ** track such information in the database, then we'd only want this + ** information on the initial create. + */ + if( argc>1 ){ + int i, n = (int)strlen(argv[1]); + for(i=0; i=0x80 ){ + sqlite3_free(t); + return SQLITE_ERROR; + } + t->delim[ch] = 1; + } + } else { + /* Mark non-alphanumeric ASCII characters as delimiters */ + int i; + for(i=1; i<0x80; i++){ + t->delim[i] = !fts3_isalnum(i) ? -1 : 0; + } + } + + *ppTokenizer = &t->base; + return SQLITE_OK; +} + +/* +** Destroy a tokenizer +*/ +static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ + sqlite3_free(pTokenizer); + return SQLITE_OK; +} + +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is pInput[0..nBytes-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int simpleOpen( + sqlite3_tokenizer *pTokenizer, /* The tokenizer */ + const char *pInput, int nBytes, /* String to be tokenized */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +){ + simple_tokenizer_cursor *c; + + UNUSED_PARAMETER(pTokenizer); + + c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); + if( c==NULL ) return SQLITE_NOMEM; + + c->pInput = pInput; + if( pInput==0 ){ + c->nBytes = 0; + }else if( nBytes<0 ){ + c->nBytes = (int)strlen(pInput); + }else{ + c->nBytes = nBytes; + } + c->iOffset = 0; /* start tokenizing at the beginning */ + c->iToken = 0; + c->pToken = NULL; /* no space allocated, yet. */ + c->nTokenAllocated = 0; + + *ppCursor = &c->base; + return SQLITE_OK; +} + +/* +** Close a tokenization cursor previously opened by a call to +** simpleOpen() above. +*/ +static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ + simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; + sqlite3_free(c->pToken); + sqlite3_free(c); + return SQLITE_OK; +} + +/* +** Extract the next token from a tokenization cursor. The cursor must +** have been opened by a prior call to simpleOpen(). +*/ +static int simpleNext( + sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ + const char **ppToken, /* OUT: *ppToken is the token text */ + int *pnBytes, /* OUT: Number of bytes in token */ + int *piStartOffset, /* OUT: Starting offset of token */ + int *piEndOffset, /* OUT: Ending offset of token */ + int *piPosition /* OUT: Position integer of token */ +){ + simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; + simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; + unsigned char *p = (unsigned char *)c->pInput; + + while( c->iOffsetnBytes ){ + int iStartOffset; + + /* Scan past delimiter characters */ + while( c->iOffsetnBytes && simpleDelim(t, p[c->iOffset]) ){ + c->iOffset++; + } + + /* Count non-delimiter characters. */ + iStartOffset = c->iOffset; + while( c->iOffsetnBytes && !simpleDelim(t, p[c->iOffset]) ){ + c->iOffset++; + } + + if( c->iOffset>iStartOffset ){ + int i, n = c->iOffset-iStartOffset; + if( n>c->nTokenAllocated ){ + char *pNew; + c->nTokenAllocated = n+20; + pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->pToken = pNew; + } + for(i=0; ipToken[i] = (char)((ch>='A' && ch<='Z') ? ch-'A'+'a' : ch); + } + *ppToken = c->pToken; + *pnBytes = n; + *piStartOffset = iStartOffset; + *piEndOffset = c->iOffset; + *piPosition = c->iToken++; + + return SQLITE_OK; + } + } + return SQLITE_DONE; +} + +/* +** The set of routines that implement the simple tokenizer +*/ +static const sqlite3_tokenizer_module simpleTokenizerModule = { + 0, + simpleCreate, + simpleDestroy, + simpleOpen, + simpleClose, + simpleNext, + 0, +}; + +/* +** Allocate a new simple tokenizer. Return a pointer to the new +** tokenizer in *ppModule +*/ +SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule( + sqlite3_tokenizer_module const**ppModule +){ + *ppModule = &simpleTokenizerModule; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_tokenizer1.c *************************************/ +/************** Begin file fts3_tokenize_vtab.c ******************************/ +/* +** 2013 Apr 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code for the "fts3tokenize" virtual table module. +** An fts3tokenize virtual table is created as follows: +** +** CREATE VIRTUAL TABLE USING fts3tokenize( +** , , ... +** ); +** +** The table created has the following schema: +** +** CREATE TABLE (input, token, start, end, position) +** +** When queried, the query must include a WHERE clause of type: +** +** input = +** +** The virtual table module tokenizes this , using the FTS3 +** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE +** statement and returns one row for each token in the result. With +** fields set as follows: +** +** input: Always set to a copy of +** token: A token from the input. +** start: Byte offset of the token within the input . +** end: Byte offset of the byte immediately following the end of the +** token within the input string. +** pos: Token offset of token within input. +** +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ + +typedef struct Fts3tokTable Fts3tokTable; +typedef struct Fts3tokCursor Fts3tokCursor; + +/* +** Virtual table structure. +*/ +struct Fts3tokTable { + sqlite3_vtab base; /* Base class used by SQLite core */ + const sqlite3_tokenizer_module *pMod; + sqlite3_tokenizer *pTok; +}; + +/* +** Virtual table cursor structure. +*/ +struct Fts3tokCursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + char *zInput; /* Input string */ + sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */ + int iRowid; /* Current 'rowid' value */ + const char *zToken; /* Current 'token' value */ + int nToken; /* Size of zToken in bytes */ + int iStart; /* Current 'start' value */ + int iEnd; /* Current 'end' value */ + int iPos; /* Current 'pos' value */ +}; + +/* +** Query FTS for the tokenizer implementation named zName. +*/ +static int fts3tokQueryTokenizer( + Fts3Hash *pHash, + const char *zName, + const sqlite3_tokenizer_module **pp, + char **pzErr +){ + sqlite3_tokenizer_module *p; + int nName = (int)strlen(zName); + + p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); + if( !p ){ + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", zName); + return SQLITE_ERROR; + } + + *pp = p; + return SQLITE_OK; +} + +/* +** The second argument, argv[], is an array of pointers to nul-terminated +** strings. This function makes a copy of the array and strings into a +** single block of memory. It then dequotes any of the strings that appear +** to be quoted. +** +** If successful, output parameter *pazDequote is set to point at the +** array of dequoted strings and SQLITE_OK is returned. The caller is +** responsible for eventually calling sqlite3_free() to free the array +** in this case. Or, if an error occurs, an SQLite error code is returned. +** The final value of *pazDequote is undefined in this case. +*/ +static int fts3tokDequoteArray( + int argc, /* Number of elements in argv[] */ + const char * const *argv, /* Input array */ + char ***pazDequote /* Output array */ +){ + int rc = SQLITE_OK; /* Return code */ + if( argc==0 ){ + *pazDequote = 0; + }else{ + int i; + int nByte = 0; + char **azDequote; + + for(i=0; ixCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok); + } + + if( rc==SQLITE_OK ){ + pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable)); + if( pTab==0 ){ + rc = SQLITE_NOMEM; + } + } + + if( rc==SQLITE_OK ){ + memset(pTab, 0, sizeof(Fts3tokTable)); + pTab->pMod = pMod; + pTab->pTok = pTok; + *ppVtab = &pTab->base; + }else{ + if( pTok ){ + pMod->xDestroy(pTok); + } + } + + sqlite3_free(azDequote); + return rc; +} + +/* +** This function does the work for both the xDisconnect and xDestroy methods. +** These tables have no persistent representation of their own, so xDisconnect +** and xDestroy are identical operations. +*/ +static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){ + Fts3tokTable *pTab = (Fts3tokTable *)pVtab; + + pTab->pMod->xDestroy(pTab->pTok); + sqlite3_free(pTab); + return SQLITE_OK; +} + +/* +** xBestIndex - Analyze a WHERE and ORDER BY clause. +*/ +static int fts3tokBestIndexMethod( + sqlite3_vtab *pVTab, + sqlite3_index_info *pInfo +){ + int i; + UNUSED_PARAMETER(pVTab); + + for(i=0; inConstraint; i++){ + if( pInfo->aConstraint[i].usable + && pInfo->aConstraint[i].iColumn==0 + && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + pInfo->idxNum = 1; + pInfo->aConstraintUsage[i].argvIndex = 1; + pInfo->aConstraintUsage[i].omit = 1; + pInfo->estimatedCost = 1; + return SQLITE_OK; + } + } + + pInfo->idxNum = 0; + assert( pInfo->estimatedCost>1000000.0 ); + + return SQLITE_OK; +} + +/* +** xOpen - Open a cursor. +*/ +static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts3tokCursor *pCsr; + UNUSED_PARAMETER(pVTab); + + pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(Fts3tokCursor)); + + *ppCsr = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Reset the tokenizer cursor passed as the only argument. As if it had +** just been returned by fts3tokOpenMethod(). +*/ +static void fts3tokResetCursor(Fts3tokCursor *pCsr){ + if( pCsr->pCsr ){ + Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab); + pTab->pMod->xClose(pCsr->pCsr); + pCsr->pCsr = 0; + } + sqlite3_free(pCsr->zInput); + pCsr->zInput = 0; + pCsr->zToken = 0; + pCsr->nToken = 0; + pCsr->iStart = 0; + pCsr->iEnd = 0; + pCsr->iPos = 0; + pCsr->iRowid = 0; +} + +/* +** xClose - Close a cursor. +*/ +static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + + fts3tokResetCursor(pCsr); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** xNext - Advance the cursor to the next row, if any. +*/ +static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); + int rc; /* Return code */ + + pCsr->iRowid++; + rc = pTab->pMod->xNext(pCsr->pCsr, + &pCsr->zToken, &pCsr->nToken, + &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos + ); + + if( rc!=SQLITE_OK ){ + fts3tokResetCursor(pCsr); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } + + return rc; +} + +/* +** xFilter - Initialize a cursor to point at the start of its data. +*/ +static int fts3tokFilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *idxStr, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + int rc = SQLITE_ERROR; + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); + UNUSED_PARAMETER(idxStr); + UNUSED_PARAMETER(nVal); + + fts3tokResetCursor(pCsr); + if( idxNum==1 ){ + const char *zByte = (const char *)sqlite3_value_text(apVal[0]); + int nByte = sqlite3_value_bytes(apVal[0]); + pCsr->zInput = sqlite3_malloc(nByte+1); + if( pCsr->zInput==0 ){ + rc = SQLITE_NOMEM; + }else{ + memcpy(pCsr->zInput, zByte, nByte); + pCsr->zInput[nByte] = 0; + rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr); + if( rc==SQLITE_OK ){ + pCsr->pCsr->pTokenizer = pTab->pTok; + } + } + } + + if( rc!=SQLITE_OK ) return rc; + return fts3tokNextMethod(pCursor); +} + +/* +** xEof - Return true if the cursor is at EOF, or false otherwise. +*/ +static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + return (pCsr->zToken==0); +} + +/* +** xColumn - Return a column value. +*/ +static int fts3tokColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ +){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + + /* CREATE TABLE x(input, token, start, end, position) */ + switch( iCol ){ + case 0: + sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT); + break; + case 1: + sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT); + break; + case 2: + sqlite3_result_int(pCtx, pCsr->iStart); + break; + case 3: + sqlite3_result_int(pCtx, pCsr->iEnd); + break; + default: + assert( iCol==4 ); + sqlite3_result_int(pCtx, pCsr->iPos); + break; + } + return SQLITE_OK; +} + +/* +** xRowid - Return the current rowid for the cursor. +*/ +static int fts3tokRowidMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite_int64 *pRowid /* OUT: Rowid value */ +){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + *pRowid = (sqlite3_int64)pCsr->iRowid; + return SQLITE_OK; +} + +/* +** Register the fts3tok module with database connection db. Return SQLITE_OK +** if successful or an error code if sqlite3_create_module() fails. +*/ +SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ + static const sqlite3_module fts3tok_module = { + 0, /* iVersion */ + fts3tokConnectMethod, /* xCreate */ + fts3tokConnectMethod, /* xConnect */ + fts3tokBestIndexMethod, /* xBestIndex */ + fts3tokDisconnectMethod, /* xDisconnect */ + fts3tokDisconnectMethod, /* xDestroy */ + fts3tokOpenMethod, /* xOpen */ + fts3tokCloseMethod, /* xClose */ + fts3tokFilterMethod, /* xFilter */ + fts3tokNextMethod, /* xNext */ + fts3tokEofMethod, /* xEof */ + fts3tokColumnMethod, /* xColumn */ + fts3tokRowidMethod, /* xRowid */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindFunction */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0 /* xRollbackTo */ + }; + int rc; /* Return code */ + + rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash); + return rc; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_tokenize_vtab.c **********************************/ +/************** Begin file fts3_write.c **************************************/ +/* +** 2009 Oct 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file is part of the SQLite FTS3 extension module. Specifically, +** this file contains code to insert, update and delete rows from FTS3 +** tables. It also contains code to merge FTS3 b-tree segments. Some +** of the sub-routines used to merge segments are also used by the query +** code in fts3.c. +*/ + +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ +/* #include */ + + +#define FTS_MAX_APPENDABLE_HEIGHT 16 + +/* +** When full-text index nodes are loaded from disk, the buffer that they +** are loaded into has the following number of bytes of padding at the end +** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer +** of 920 bytes is allocated for it. +** +** This means that if we have a pointer into a buffer containing node data, +** it is always safe to read up to two varints from it without risking an +** overread, even if the node data is corrupted. +*/ +#define FTS3_NODE_PADDING (FTS3_VARINT_MAX*2) + +/* +** Under certain circumstances, b-tree nodes (doclists) can be loaded into +** memory incrementally instead of all at once. This can be a big performance +** win (reduced IO and CPU) if SQLite stops calling the virtual table xNext() +** method before retrieving all query results (as may happen, for example, +** if a query has a LIMIT clause). +** +** Incremental loading is used for b-tree nodes FTS3_NODE_CHUNK_THRESHOLD +** bytes and larger. Nodes are loaded in chunks of FTS3_NODE_CHUNKSIZE bytes. +** The code is written so that the hard lower-limit for each of these values +** is 1. Clearly such small values would be inefficient, but can be useful +** for testing purposes. +** +** If this module is built with SQLITE_TEST defined, these constants may +** be overridden at runtime for testing purposes. File fts3_test.c contains +** a Tcl interface to read and write the values. +*/ +#ifdef SQLITE_TEST +int test_fts3_node_chunksize = (4*1024); +int test_fts3_node_chunk_threshold = (4*1024)*4; +# define FTS3_NODE_CHUNKSIZE test_fts3_node_chunksize +# define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold +#else +# define FTS3_NODE_CHUNKSIZE (4*1024) +# define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4) +#endif + +/* +** The two values that may be meaningfully bound to the :1 parameter in +** statements SQL_REPLACE_STAT and SQL_SELECT_STAT. +*/ +#define FTS_STAT_DOCTOTAL 0 +#define FTS_STAT_INCRMERGEHINT 1 +#define FTS_STAT_AUTOINCRMERGE 2 + +/* +** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic +** and incremental merge operation that takes place. This is used for +** debugging FTS only, it should not usually be turned on in production +** systems. +*/ +#ifdef FTS3_LOG_MERGES +static void fts3LogMerge(int nMerge, sqlite3_int64 iAbsLevel){ + sqlite3_log(SQLITE_OK, "%d-way merge from level %d", nMerge, (int)iAbsLevel); +} +#else +#define fts3LogMerge(x, y) +#endif + + +typedef struct PendingList PendingList; +typedef struct SegmentNode SegmentNode; +typedef struct SegmentWriter SegmentWriter; + +/* +** An instance of the following data structure is used to build doclists +** incrementally. See function fts3PendingListAppend() for details. +*/ +struct PendingList { + int nData; + char *aData; + int nSpace; + sqlite3_int64 iLastDocid; + sqlite3_int64 iLastCol; + sqlite3_int64 iLastPos; +}; + + +/* +** Each cursor has a (possibly empty) linked list of the following objects. +*/ +struct Fts3DeferredToken { + Fts3PhraseToken *pToken; /* Pointer to corresponding expr token */ + int iCol; /* Column token must occur in */ + Fts3DeferredToken *pNext; /* Next in list of deferred tokens */ + PendingList *pList; /* Doclist is assembled here */ +}; + +/* +** An instance of this structure is used to iterate through the terms on +** a contiguous set of segment b-tree leaf nodes. Although the details of +** this structure are only manipulated by code in this file, opaque handles +** of type Fts3SegReader* are also used by code in fts3.c to iterate through +** terms when querying the full-text index. See functions: +** +** sqlite3Fts3SegReaderNew() +** sqlite3Fts3SegReaderFree() +** sqlite3Fts3SegReaderIterate() +** +** Methods used to manipulate Fts3SegReader structures: +** +** fts3SegReaderNext() +** fts3SegReaderFirstDocid() +** fts3SegReaderNextDocid() +*/ +struct Fts3SegReader { + int iIdx; /* Index within level, or 0x7FFFFFFF for PT */ + u8 bLookup; /* True for a lookup only */ + u8 rootOnly; /* True for a root-only reader */ + + sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */ + sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */ + sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */ + sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */ + + char *aNode; /* Pointer to node data (or NULL) */ + int nNode; /* Size of buffer at aNode (or 0) */ + int nPopulate; /* If >0, bytes of buffer aNode[] loaded */ + sqlite3_blob *pBlob; /* If not NULL, blob handle to read node */ + + Fts3HashElem **ppNextElem; + + /* Variables set by fts3SegReaderNext(). These may be read directly + ** by the caller. They are valid from the time SegmentReaderNew() returns + ** until SegmentReaderNext() returns something other than SQLITE_OK + ** (i.e. SQLITE_DONE). + */ + int nTerm; /* Number of bytes in current term */ + char *zTerm; /* Pointer to current term */ + int nTermAlloc; /* Allocated size of zTerm buffer */ + char *aDoclist; /* Pointer to doclist of current entry */ + int nDoclist; /* Size of doclist in current entry */ + + /* The following variables are used by fts3SegReaderNextDocid() to iterate + ** through the current doclist (aDoclist/nDoclist). + */ + char *pOffsetList; + int nOffsetList; /* For descending pending seg-readers only */ + sqlite3_int64 iDocid; +}; + +#define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0) +#define fts3SegReaderIsRootOnly(p) ((p)->rootOnly!=0) + +/* +** An instance of this structure is used to create a segment b-tree in the +** database. The internal details of this type are only accessed by the +** following functions: +** +** fts3SegWriterAdd() +** fts3SegWriterFlush() +** fts3SegWriterFree() +*/ +struct SegmentWriter { + SegmentNode *pTree; /* Pointer to interior tree structure */ + sqlite3_int64 iFirst; /* First slot in %_segments written */ + sqlite3_int64 iFree; /* Next free slot in %_segments */ + char *zTerm; /* Pointer to previous term buffer */ + int nTerm; /* Number of bytes in zTerm */ + int nMalloc; /* Size of malloc'd buffer at zMalloc */ + char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ + int nSize; /* Size of allocation at aData */ + int nData; /* Bytes of data in aData */ + char *aData; /* Pointer to block from malloc() */ + i64 nLeafData; /* Number of bytes of leaf data written */ +}; + +/* +** Type SegmentNode is used by the following three functions to create +** the interior part of the segment b+-tree structures (everything except +** the leaf nodes). These functions and type are only ever used by code +** within the fts3SegWriterXXX() family of functions described above. +** +** fts3NodeAddTerm() +** fts3NodeWrite() +** fts3NodeFree() +** +** When a b+tree is written to the database (either as a result of a merge +** or the pending-terms table being flushed), leaves are written into the +** database file as soon as they are completely populated. The interior of +** the tree is assembled in memory and written out only once all leaves have +** been populated and stored. This is Ok, as the b+-tree fanout is usually +** very large, meaning that the interior of the tree consumes relatively +** little memory. +*/ +struct SegmentNode { + SegmentNode *pParent; /* Parent node (or NULL for root node) */ + SegmentNode *pRight; /* Pointer to right-sibling */ + SegmentNode *pLeftmost; /* Pointer to left-most node of this depth */ + int nEntry; /* Number of terms written to node so far */ + char *zTerm; /* Pointer to previous term buffer */ + int nTerm; /* Number of bytes in zTerm */ + int nMalloc; /* Size of malloc'd buffer at zMalloc */ + char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ + int nData; /* Bytes of valid data so far */ + char *aData; /* Node data */ +}; + +/* +** Valid values for the second argument to fts3SqlStmt(). +*/ +#define SQL_DELETE_CONTENT 0 +#define SQL_IS_EMPTY 1 +#define SQL_DELETE_ALL_CONTENT 2 +#define SQL_DELETE_ALL_SEGMENTS 3 +#define SQL_DELETE_ALL_SEGDIR 4 +#define SQL_DELETE_ALL_DOCSIZE 5 +#define SQL_DELETE_ALL_STAT 6 +#define SQL_SELECT_CONTENT_BY_ROWID 7 +#define SQL_NEXT_SEGMENT_INDEX 8 +#define SQL_INSERT_SEGMENTS 9 +#define SQL_NEXT_SEGMENTS_ID 10 +#define SQL_INSERT_SEGDIR 11 +#define SQL_SELECT_LEVEL 12 +#define SQL_SELECT_LEVEL_RANGE 13 +#define SQL_SELECT_LEVEL_COUNT 14 +#define SQL_SELECT_SEGDIR_MAX_LEVEL 15 +#define SQL_DELETE_SEGDIR_LEVEL 16 +#define SQL_DELETE_SEGMENTS_RANGE 17 +#define SQL_CONTENT_INSERT 18 +#define SQL_DELETE_DOCSIZE 19 +#define SQL_REPLACE_DOCSIZE 20 +#define SQL_SELECT_DOCSIZE 21 +#define SQL_SELECT_STAT 22 +#define SQL_REPLACE_STAT 23 + +#define SQL_SELECT_ALL_PREFIX_LEVEL 24 +#define SQL_DELETE_ALL_TERMS_SEGDIR 25 +#define SQL_DELETE_SEGDIR_RANGE 26 +#define SQL_SELECT_ALL_LANGID 27 +#define SQL_FIND_MERGE_LEVEL 28 +#define SQL_MAX_LEAF_NODE_ESTIMATE 29 +#define SQL_DELETE_SEGDIR_ENTRY 30 +#define SQL_SHIFT_SEGDIR_ENTRY 31 +#define SQL_SELECT_SEGDIR 32 +#define SQL_CHOMP_SEGDIR 33 +#define SQL_SEGMENT_IS_APPENDABLE 34 +#define SQL_SELECT_INDEXES 35 +#define SQL_SELECT_MXLEVEL 36 + +#define SQL_SELECT_LEVEL_RANGE2 37 +#define SQL_UPDATE_LEVEL_IDX 38 +#define SQL_UPDATE_LEVEL 39 + +/* +** This function is used to obtain an SQLite prepared statement handle +** for the statement identified by the second argument. If successful, +** *pp is set to the requested statement handle and SQLITE_OK returned. +** Otherwise, an SQLite error code is returned and *pp is set to 0. +** +** If argument apVal is not NULL, then it must point to an array with +** at least as many entries as the requested statement has bound +** parameters. The values are bound to the statements parameters before +** returning. +*/ +static int fts3SqlStmt( + Fts3Table *p, /* Virtual table handle */ + int eStmt, /* One of the SQL_XXX constants above */ + sqlite3_stmt **pp, /* OUT: Statement handle */ + sqlite3_value **apVal /* Values to bind to statement */ +){ + const char *azSql[] = { +/* 0 */ "DELETE FROM %Q.'%q_content' WHERE rowid = ?", +/* 1 */ "SELECT NOT EXISTS(SELECT docid FROM %Q.'%q_content' WHERE rowid!=?)", +/* 2 */ "DELETE FROM %Q.'%q_content'", +/* 3 */ "DELETE FROM %Q.'%q_segments'", +/* 4 */ "DELETE FROM %Q.'%q_segdir'", +/* 5 */ "DELETE FROM %Q.'%q_docsize'", +/* 6 */ "DELETE FROM %Q.'%q_stat'", +/* 7 */ "SELECT %s WHERE rowid=?", +/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", +/* 9 */ "REPLACE INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", +/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", +/* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)", + + /* Return segments in order from oldest to newest.*/ +/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root " + "FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC", +/* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root " + "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?" + "ORDER BY level DESC, idx ASC", + +/* 14 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?", +/* 15 */ "SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", + +/* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?", +/* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?", +/* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%s)", +/* 19 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?", +/* 20 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", +/* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?", +/* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=?", +/* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(?,?)", +/* 24 */ "", +/* 25 */ "", + +/* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", +/* 27 */ "SELECT ? UNION SELECT level / (1024 * ?) FROM %Q.'%q_segdir'", + +/* This statement is used to determine which level to read the input from +** when performing an incremental merge. It returns the absolute level number +** of the oldest level in the db that contains at least ? segments. Or, +** if no level in the FTS index contains more than ? segments, the statement +** returns zero rows. */ +/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' " + " GROUP BY level HAVING cnt>=?" + " ORDER BY (level %% 1024) ASC LIMIT 1", + +/* Estimate the upper limit on the number of leaf nodes in a new segment +** created by merging the oldest :2 segments from absolute level :1. See +** function sqlite3Fts3Incrmerge() for details. */ +/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) " + " FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?", + +/* SQL_DELETE_SEGDIR_ENTRY +** Delete the %_segdir entry on absolute level :1 with index :2. */ +/* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", + +/* SQL_SHIFT_SEGDIR_ENTRY +** Modify the idx value for the segment with idx=:3 on absolute level :2 +** to :1. */ +/* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?", + +/* SQL_SELECT_SEGDIR +** Read a single entry from the %_segdir table. The entry from absolute +** level :1 with index value :2. */ +/* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root " + "FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", + +/* SQL_CHOMP_SEGDIR +** Update the start_block (:1) and root (:2) fields of the %_segdir +** entry located on absolute level :3 with index :4. */ +/* 33 */ "UPDATE %Q.'%q_segdir' SET start_block = ?, root = ?" + "WHERE level = ? AND idx = ?", + +/* SQL_SEGMENT_IS_APPENDABLE +** Return a single row if the segment with end_block=? is appendable. Or +** no rows otherwise. */ +/* 34 */ "SELECT 1 FROM %Q.'%q_segments' WHERE blockid=? AND block IS NULL", + +/* SQL_SELECT_INDEXES +** Return the list of valid segment indexes for absolute level ? */ +/* 35 */ "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC", + +/* SQL_SELECT_MXLEVEL +** Return the largest relative level in the FTS index or indexes. */ +/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'", + + /* Return segments in order from oldest to newest.*/ +/* 37 */ "SELECT level, idx, end_block " + "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? " + "ORDER BY level DESC, idx ASC", + + /* Update statements used while promoting segments */ +/* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? " + "WHERE level=? AND idx=?", +/* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1" + + }; + int rc = SQLITE_OK; + sqlite3_stmt *pStmt; + + assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); + assert( eStmt=0 ); + + pStmt = p->aStmt[eStmt]; + if( !pStmt ){ + char *zSql; + if( eStmt==SQL_CONTENT_INSERT ){ + zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); + }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ + zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); + }else{ + zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); + } + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL); + sqlite3_free(zSql); + assert( rc==SQLITE_OK || pStmt==0 ); + p->aStmt[eStmt] = pStmt; + } + } + if( apVal ){ + int i; + int nParam = sqlite3_bind_parameter_count(pStmt); + for(i=0; rc==SQLITE_OK && inPendingData==0 ){ + sqlite3_stmt *pStmt; + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_null(pStmt, 1); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } + } + + return rc; +} + +/* +** FTS maintains a separate indexes for each language-id (a 32-bit integer). +** Within each language id, a separate index is maintained to store the +** document terms, and each configured prefix size (configured the FTS +** "prefix=" option). And each index consists of multiple levels ("relative +** levels"). +** +** All three of these values (the language id, the specific index and the +** level within the index) are encoded in 64-bit integer values stored +** in the %_segdir table on disk. This function is used to convert three +** separate component values into the single 64-bit integer value that +** can be used to query the %_segdir table. +** +** Specifically, each language-id/index combination is allocated 1024 +** 64-bit integer level values ("absolute levels"). The main terms index +** for language-id 0 is allocate values 0-1023. The first prefix index +** (if any) for language-id 0 is allocated values 1024-2047. And so on. +** Language 1 indexes are allocated immediately following language 0. +** +** So, for a system with nPrefix prefix indexes configured, the block of +** absolute levels that corresponds to language-id iLangid and index +** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024). +*/ +static sqlite3_int64 getAbsoluteLevel( + Fts3Table *p, /* FTS3 table handle */ + int iLangid, /* Language id */ + int iIndex, /* Index in p->aIndex[] */ + int iLevel /* Level of segments */ +){ + sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */ + assert( iLangid>=0 ); + assert( p->nIndex>0 ); + assert( iIndex>=0 && iIndexnIndex ); + + iBase = ((sqlite3_int64)iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL; + return iBase + iLevel; +} + +/* +** Set *ppStmt to a statement handle that may be used to iterate through +** all rows in the %_segdir table, from oldest to newest. If successful, +** return SQLITE_OK. If an error occurs while preparing the statement, +** return an SQLite error code. +** +** There is only ever one instance of this SQL statement compiled for +** each FTS3 table. +** +** The statement returns the following columns from the %_segdir table: +** +** 0: idx +** 1: start_block +** 2: leaves_end_block +** 3: end_block +** 4: root +*/ +SQLITE_PRIVATE int sqlite3Fts3AllSegdirs( + Fts3Table *p, /* FTS3 table */ + int iLangid, /* Language being queried */ + int iIndex, /* Index for p->aIndex[] */ + int iLevel, /* Level to select (relative level) */ + sqlite3_stmt **ppStmt /* OUT: Compiled statement */ +){ + int rc; + sqlite3_stmt *pStmt = 0; + + assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel>=0 ); + assert( iLevel=0 && iIndexnIndex ); + + if( iLevel<0 ){ + /* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */ + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); + sqlite3_bind_int64(pStmt, 2, + getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) + ); + } + }else{ + /* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */ + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel)); + } + } + *ppStmt = pStmt; + return rc; +} + + +/* +** Append a single varint to a PendingList buffer. SQLITE_OK is returned +** if successful, or an SQLite error code otherwise. +** +** This function also serves to allocate the PendingList structure itself. +** For example, to create a new PendingList structure containing two +** varints: +** +** PendingList *p = 0; +** fts3PendingListAppendVarint(&p, 1); +** fts3PendingListAppendVarint(&p, 2); +*/ +static int fts3PendingListAppendVarint( + PendingList **pp, /* IN/OUT: Pointer to PendingList struct */ + sqlite3_int64 i /* Value to append to data */ +){ + PendingList *p = *pp; + + /* Allocate or grow the PendingList as required. */ + if( !p ){ + p = sqlite3_malloc(sizeof(*p) + 100); + if( !p ){ + return SQLITE_NOMEM; + } + p->nSpace = 100; + p->aData = (char *)&p[1]; + p->nData = 0; + } + else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ + int nNew = p->nSpace * 2; + p = sqlite3_realloc(p, sizeof(*p) + nNew); + if( !p ){ + sqlite3_free(*pp); + *pp = 0; + return SQLITE_NOMEM; + } + p->nSpace = nNew; + p->aData = (char *)&p[1]; + } + + /* Append the new serialized varint to the end of the list. */ + p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i); + p->aData[p->nData] = '\0'; + *pp = p; + return SQLITE_OK; +} + +/* +** Add a docid/column/position entry to a PendingList structure. Non-zero +** is returned if the structure is sqlite3_realloced as part of adding +** the entry. Otherwise, zero. +** +** If an OOM error occurs, *pRc is set to SQLITE_NOMEM before returning. +** Zero is always returned in this case. Otherwise, if no OOM error occurs, +** it is set to SQLITE_OK. +*/ +static int fts3PendingListAppend( + PendingList **pp, /* IN/OUT: PendingList structure */ + sqlite3_int64 iDocid, /* Docid for entry to add */ + sqlite3_int64 iCol, /* Column for entry to add */ + sqlite3_int64 iPos, /* Position of term for entry to add */ + int *pRc /* OUT: Return code */ +){ + PendingList *p = *pp; + int rc = SQLITE_OK; + + assert( !p || p->iLastDocid<=iDocid ); + + if( !p || p->iLastDocid!=iDocid ){ + sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0); + if( p ){ + assert( p->nDatanSpace ); + assert( p->aData[p->nData]==0 ); + p->nData++; + } + if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iDelta)) ){ + goto pendinglistappend_out; + } + p->iLastCol = -1; + p->iLastPos = 0; + p->iLastDocid = iDocid; + } + if( iCol>0 && p->iLastCol!=iCol ){ + if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, 1)) + || SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iCol)) + ){ + goto pendinglistappend_out; + } + p->iLastCol = iCol; + p->iLastPos = 0; + } + if( iCol>=0 ){ + assert( iPos>p->iLastPos || (iPos==0 && p->iLastPos==0) ); + rc = fts3PendingListAppendVarint(&p, 2+iPos-p->iLastPos); + if( rc==SQLITE_OK ){ + p->iLastPos = iPos; + } + } + + pendinglistappend_out: + *pRc = rc; + if( p!=*pp ){ + *pp = p; + return 1; + } + return 0; +} + +/* +** Free a PendingList object allocated by fts3PendingListAppend(). +*/ +static void fts3PendingListDelete(PendingList *pList){ + sqlite3_free(pList); +} + +/* +** Add an entry to one of the pending-terms hash tables. +*/ +static int fts3PendingTermsAddOne( + Fts3Table *p, + int iCol, + int iPos, + Fts3Hash *pHash, /* Pending terms hash table to add entry to */ + const char *zToken, + int nToken +){ + PendingList *pList; + int rc = SQLITE_OK; + + pList = (PendingList *)fts3HashFind(pHash, zToken, nToken); + if( pList ){ + p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem)); + } + if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){ + if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){ + /* Malloc failed while inserting the new entry. This can only + ** happen if there was no previous entry for this token. + */ + assert( 0==fts3HashFind(pHash, zToken, nToken) ); + sqlite3_free(pList); + rc = SQLITE_NOMEM; + } + } + if( rc==SQLITE_OK ){ + p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem)); + } + return rc; +} + +/* +** Tokenize the nul-terminated string zText and add all tokens to the +** pending-terms hash-table. The docid used is that currently stored in +** p->iPrevDocid, and the column is specified by argument iCol. +** +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. +*/ +static int fts3PendingTermsAdd( + Fts3Table *p, /* Table into which text will be inserted */ + int iLangid, /* Language id to use */ + const char *zText, /* Text of document to be inserted */ + int iCol, /* Column into which text is being inserted */ + u32 *pnWord /* IN/OUT: Incr. by number tokens inserted */ +){ + int rc; + int iStart = 0; + int iEnd = 0; + int iPos = 0; + int nWord = 0; + + char const *zToken; + int nToken = 0; + + sqlite3_tokenizer *pTokenizer = p->pTokenizer; + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + sqlite3_tokenizer_cursor *pCsr; + int (*xNext)(sqlite3_tokenizer_cursor *pCursor, + const char**,int*,int*,int*,int*); + + assert( pTokenizer && pModule ); + + /* If the user has inserted a NULL value, this function may be called with + ** zText==0. In this case, add zero token entries to the hash table and + ** return early. */ + if( zText==0 ){ + *pnWord = 0; + return SQLITE_OK; + } + + rc = sqlite3Fts3OpenTokenizer(pTokenizer, iLangid, zText, -1, &pCsr); + if( rc!=SQLITE_OK ){ + return rc; + } + + xNext = pModule->xNext; + while( SQLITE_OK==rc + && SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos)) + ){ + int i; + if( iPos>=nWord ) nWord = iPos+1; + + /* Positions cannot be negative; we use -1 as a terminator internally. + ** Tokens must have a non-zero length. + */ + if( iPos<0 || !zToken || nToken<=0 ){ + rc = SQLITE_ERROR; + break; + } + + /* Add the term to the terms index */ + rc = fts3PendingTermsAddOne( + p, iCol, iPos, &p->aIndex[0].hPending, zToken, nToken + ); + + /* Add the term to each of the prefix indexes that it is not too + ** short for. */ + for(i=1; rc==SQLITE_OK && inIndex; i++){ + struct Fts3Index *pIndex = &p->aIndex[i]; + if( nTokennPrefix ) continue; + rc = fts3PendingTermsAddOne( + p, iCol, iPos, &pIndex->hPending, zToken, pIndex->nPrefix + ); + } + } + + pModule->xClose(pCsr); + *pnWord += nWord; + return (rc==SQLITE_DONE ? SQLITE_OK : rc); +} + +/* +** Calling this function indicates that subsequent calls to +** fts3PendingTermsAdd() are to add term/position-list pairs for the +** contents of the document with docid iDocid. +*/ +static int fts3PendingTermsDocid( + Fts3Table *p, /* Full-text table handle */ + int bDelete, /* True if this op is a delete */ + int iLangid, /* Language id of row being written */ + sqlite_int64 iDocid /* Docid of row being written */ +){ + assert( iLangid>=0 ); + assert( bDelete==1 || bDelete==0 ); + + /* TODO(shess) Explore whether partially flushing the buffer on + ** forced-flush would provide better performance. I suspect that if + ** we ordered the doclists by size and flushed the largest until the + ** buffer was half empty, that would let the less frequent terms + ** generate longer doclists. + */ + if( iDocidiPrevDocid + || (iDocid==p->iPrevDocid && p->bPrevDelete==0) + || p->iPrevLangid!=iLangid + || p->nPendingData>p->nMaxPendingData + ){ + int rc = sqlite3Fts3PendingTermsFlush(p); + if( rc!=SQLITE_OK ) return rc; + } + p->iPrevDocid = iDocid; + p->iPrevLangid = iLangid; + p->bPrevDelete = bDelete; + return SQLITE_OK; +} + +/* +** Discard the contents of the pending-terms hash tables. +*/ +SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){ + int i; + for(i=0; inIndex; i++){ + Fts3HashElem *pElem; + Fts3Hash *pHash = &p->aIndex[i].hPending; + for(pElem=fts3HashFirst(pHash); pElem; pElem=fts3HashNext(pElem)){ + PendingList *pList = (PendingList *)fts3HashData(pElem); + fts3PendingListDelete(pList); + } + fts3HashClear(pHash); + } + p->nPendingData = 0; +} + +/* +** This function is called by the xUpdate() method as part of an INSERT +** operation. It adds entries for each term in the new record to the +** pendingTerms hash table. +** +** Argument apVal is the same as the similarly named argument passed to +** fts3InsertData(). Parameter iDocid is the docid of the new row. +*/ +static int fts3InsertTerms( + Fts3Table *p, + int iLangid, + sqlite3_value **apVal, + u32 *aSz +){ + int i; /* Iterator variable */ + for(i=2; inColumn+2; i++){ + int iCol = i-2; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_value_text(apVal[i]); + int rc = fts3PendingTermsAdd(p, iLangid, zText, iCol, &aSz[iCol]); + if( rc!=SQLITE_OK ){ + return rc; + } + aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); + } + } + return SQLITE_OK; +} + +/* +** This function is called by the xUpdate() method for an INSERT operation. +** The apVal parameter is passed a copy of the apVal argument passed by +** SQLite to the xUpdate() method. i.e: +** +** apVal[0] Not used for INSERT. +** apVal[1] rowid +** apVal[2] Left-most user-defined column +** ... +** apVal[p->nColumn+1] Right-most user-defined column +** apVal[p->nColumn+2] Hidden column with same name as table +** apVal[p->nColumn+3] Hidden "docid" column (alias for rowid) +** apVal[p->nColumn+4] Hidden languageid column +*/ +static int fts3InsertData( + Fts3Table *p, /* Full-text table */ + sqlite3_value **apVal, /* Array of values to insert */ + sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ +){ + int rc; /* Return code */ + sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ + + if( p->zContentTbl ){ + sqlite3_value *pRowid = apVal[p->nColumn+3]; + if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ + pRowid = apVal[1]; + } + if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ + return SQLITE_CONSTRAINT; + } + *piDocid = sqlite3_value_int64(pRowid); + return SQLITE_OK; + } + + /* Locate the statement handle used to insert data into the %_content + ** table. The SQL for this statement is: + ** + ** INSERT INTO %_content VALUES(?, ?, ?, ...) + ** + ** The statement features N '?' variables, where N is the number of user + ** defined columns in the FTS3 table, plus one for the docid field. + */ + rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); + if( rc==SQLITE_OK && p->zLanguageid ){ + rc = sqlite3_bind_int( + pContentInsert, p->nColumn+2, + sqlite3_value_int(apVal[p->nColumn+4]) + ); + } + if( rc!=SQLITE_OK ) return rc; + + /* There is a quirk here. The users INSERT statement may have specified + ** a value for the "rowid" field, for the "docid" field, or for both. + ** Which is a problem, since "rowid" and "docid" are aliases for the + ** same value. For example: + ** + ** INSERT INTO fts3tbl(rowid, docid) VALUES(1, 2); + ** + ** In FTS3, this is an error. It is an error to specify non-NULL values + ** for both docid and some other rowid alias. + */ + if( SQLITE_NULL!=sqlite3_value_type(apVal[3+p->nColumn]) ){ + if( SQLITE_NULL==sqlite3_value_type(apVal[0]) + && SQLITE_NULL!=sqlite3_value_type(apVal[1]) + ){ + /* A rowid/docid conflict. */ + return SQLITE_ERROR; + } + rc = sqlite3_bind_value(pContentInsert, 1, apVal[3+p->nColumn]); + if( rc!=SQLITE_OK ) return rc; + } + + /* Execute the statement to insert the record. Set *piDocid to the + ** new docid value. + */ + sqlite3_step(pContentInsert); + rc = sqlite3_reset(pContentInsert); + + *piDocid = sqlite3_last_insert_rowid(p->db); + return rc; +} + + + +/* +** Remove all data from the FTS3 table. Clear the hash table containing +** pending terms. +*/ +static int fts3DeleteAll(Fts3Table *p, int bContent){ + int rc = SQLITE_OK; /* Return code */ + + /* Discard the contents of the pending-terms hash table. */ + sqlite3Fts3PendingTermsClear(p); + + /* Delete everything from the shadow tables. Except, leave %_content as + ** is if bContent is false. */ + assert( p->zContentTbl==0 || bContent==0 ); + if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); + fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); + fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); + if( p->bHasDocsize ){ + fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0); + } + if( p->bHasStat ){ + fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0); + } + return rc; +} + +/* +** +*/ +static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){ + int iLangid = 0; + if( p->zLanguageid ) iLangid = sqlite3_column_int(pSelect, p->nColumn+1); + return iLangid; +} + +/* +** The first element in the apVal[] array is assumed to contain the docid +** (an integer) of a row about to be deleted. Remove all terms from the +** full-text index. +*/ +static void fts3DeleteTerms( + int *pRC, /* Result code */ + Fts3Table *p, /* The FTS table to delete from */ + sqlite3_value *pRowid, /* The docid to be deleted */ + u32 *aSz, /* Sizes of deleted document written here */ + int *pbFound /* OUT: Set to true if row really does exist */ +){ + int rc; + sqlite3_stmt *pSelect; + + assert( *pbFound==0 ); + if( *pRC ) return; + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pSelect) ){ + int i; + int iLangid = langidFromSelect(p, pSelect); + i64 iDocid = sqlite3_column_int64(pSelect, 0); + rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid); + for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){ + int iCol = i-1; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pSelect, i); + rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[iCol]); + aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i); + } + } + if( rc!=SQLITE_OK ){ + sqlite3_reset(pSelect); + *pRC = rc; + return; + } + *pbFound = 1; + } + rc = sqlite3_reset(pSelect); + }else{ + sqlite3_reset(pSelect); + } + *pRC = rc; +} + +/* +** Forward declaration to account for the circular dependency between +** functions fts3SegmentMerge() and fts3AllocateSegdirIdx(). +*/ +static int fts3SegmentMerge(Fts3Table *, int, int, int); + +/* +** This function allocates a new level iLevel index in the segdir table. +** Usually, indexes are allocated within a level sequentially starting +** with 0, so the allocated index is one greater than the value returned +** by: +** +** SELECT max(idx) FROM %_segdir WHERE level = :iLevel +** +** However, if there are already FTS3_MERGE_COUNT indexes at the requested +** level, they are merged into a single level (iLevel+1) segment and the +** allocated index is 0. +** +** If successful, *piIdx is set to the allocated index slot and SQLITE_OK +** returned. Otherwise, an SQLite error code is returned. +*/ +static int fts3AllocateSegdirIdx( + Fts3Table *p, + int iLangid, /* Language id */ + int iIndex, /* Index for p->aIndex */ + int iLevel, + int *piIdx +){ + int rc; /* Return Code */ + sqlite3_stmt *pNextIdx; /* Query for next idx at level iLevel */ + int iNext = 0; /* Result of query pNextIdx */ + + assert( iLangid>=0 ); + assert( p->nIndex>=1 ); + + /* Set variable iNext to the next available segdir index at level iLevel. */ + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pNextIdx, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64( + pNextIdx, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) + ); + if( SQLITE_ROW==sqlite3_step(pNextIdx) ){ + iNext = sqlite3_column_int(pNextIdx, 0); + } + rc = sqlite3_reset(pNextIdx); + } + + if( rc==SQLITE_OK ){ + /* If iNext is FTS3_MERGE_COUNT, indicating that level iLevel is already + ** full, merge all segments in level iLevel into a single iLevel+1 + ** segment and allocate (newly freed) index 0 at level iLevel. Otherwise, + ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext. + */ + if( iNext>=FTS3_MERGE_COUNT ){ + fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel)); + rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel); + *piIdx = 0; + }else{ + *piIdx = iNext; + } + } + + return rc; +} + +/* +** The %_segments table is declared as follows: +** +** CREATE TABLE %_segments(blockid INTEGER PRIMARY KEY, block BLOB) +** +** This function reads data from a single row of the %_segments table. The +** specific row is identified by the iBlockid parameter. If paBlob is not +** NULL, then a buffer is allocated using sqlite3_malloc() and populated +** with the contents of the blob stored in the "block" column of the +** identified table row is. Whether or not paBlob is NULL, *pnBlob is set +** to the size of the blob in bytes before returning. +** +** If an error occurs, or the table does not contain the specified row, +** an SQLite error code is returned. Otherwise, SQLITE_OK is returned. If +** paBlob is non-NULL, then it is the responsibility of the caller to +** eventually free the returned buffer. +** +** This function may leave an open sqlite3_blob* handle in the +** Fts3Table.pSegments variable. This handle is reused by subsequent calls +** to this function. The handle may be closed by calling the +** sqlite3Fts3SegmentsClose() function. Reusing a blob handle is a handy +** performance improvement, but the blob handle should always be closed +** before control is returned to the user (to prevent a lock being held +** on the database file for longer than necessary). Thus, any virtual table +** method (xFilter etc.) that may directly or indirectly call this function +** must call sqlite3Fts3SegmentsClose() before returning. +*/ +SQLITE_PRIVATE int sqlite3Fts3ReadBlock( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iBlockid, /* Access the row with blockid=$iBlockid */ + char **paBlob, /* OUT: Blob data in malloc'd buffer */ + int *pnBlob, /* OUT: Size of blob data */ + int *pnLoad /* OUT: Bytes actually loaded */ +){ + int rc; /* Return code */ + + /* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */ + assert( pnBlob ); + + if( p->pSegments ){ + rc = sqlite3_blob_reopen(p->pSegments, iBlockid); + }else{ + if( 0==p->zSegmentsTbl ){ + p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName); + if( 0==p->zSegmentsTbl ) return SQLITE_NOMEM; + } + rc = sqlite3_blob_open( + p->db, p->zDb, p->zSegmentsTbl, "block", iBlockid, 0, &p->pSegments + ); + } + + if( rc==SQLITE_OK ){ + int nByte = sqlite3_blob_bytes(p->pSegments); + *pnBlob = nByte; + if( paBlob ){ + char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); + if( !aByte ){ + rc = SQLITE_NOMEM; + }else{ + if( pnLoad && nByte>(FTS3_NODE_CHUNK_THRESHOLD) ){ + nByte = FTS3_NODE_CHUNKSIZE; + *pnLoad = nByte; + } + rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0); + memset(&aByte[nByte], 0, FTS3_NODE_PADDING); + if( rc!=SQLITE_OK ){ + sqlite3_free(aByte); + aByte = 0; + } + } + *paBlob = aByte; + } + } + + return rc; +} + +/* +** Close the blob handle at p->pSegments, if it is open. See comments above +** the sqlite3Fts3ReadBlock() function for details. +*/ +SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){ + sqlite3_blob_close(p->pSegments); + p->pSegments = 0; +} + +static int fts3SegReaderIncrRead(Fts3SegReader *pReader){ + int nRead; /* Number of bytes to read */ + int rc; /* Return code */ + + nRead = MIN(pReader->nNode - pReader->nPopulate, FTS3_NODE_CHUNKSIZE); + rc = sqlite3_blob_read( + pReader->pBlob, + &pReader->aNode[pReader->nPopulate], + nRead, + pReader->nPopulate + ); + + if( rc==SQLITE_OK ){ + pReader->nPopulate += nRead; + memset(&pReader->aNode[pReader->nPopulate], 0, FTS3_NODE_PADDING); + if( pReader->nPopulate==pReader->nNode ){ + sqlite3_blob_close(pReader->pBlob); + pReader->pBlob = 0; + pReader->nPopulate = 0; + } + } + return rc; +} + +static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){ + int rc = SQLITE_OK; + assert( !pReader->pBlob + || (pFrom>=pReader->aNode && pFrom<&pReader->aNode[pReader->nNode]) + ); + while( pReader->pBlob && rc==SQLITE_OK + && (pFrom - pReader->aNode + nByte)>pReader->nPopulate + ){ + rc = fts3SegReaderIncrRead(pReader); + } + return rc; +} + +/* +** Set an Fts3SegReader cursor to point at EOF. +*/ +static void fts3SegReaderSetEof(Fts3SegReader *pSeg){ + if( !fts3SegReaderIsRootOnly(pSeg) ){ + sqlite3_free(pSeg->aNode); + sqlite3_blob_close(pSeg->pBlob); + pSeg->pBlob = 0; + } + pSeg->aNode = 0; +} + +/* +** Move the iterator passed as the first argument to the next term in the +** segment. If successful, SQLITE_OK is returned. If there is no next term, +** SQLITE_DONE. Otherwise, an SQLite error code. +*/ +static int fts3SegReaderNext( + Fts3Table *p, + Fts3SegReader *pReader, + int bIncr +){ + int rc; /* Return code of various sub-routines */ + char *pNext; /* Cursor variable */ + int nPrefix; /* Number of bytes in term prefix */ + int nSuffix; /* Number of bytes in term suffix */ + + if( !pReader->aDoclist ){ + pNext = pReader->aNode; + }else{ + pNext = &pReader->aDoclist[pReader->nDoclist]; + } + + if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){ + + if( fts3SegReaderIsPending(pReader) ){ + Fts3HashElem *pElem = *(pReader->ppNextElem); + sqlite3_free(pReader->aNode); + pReader->aNode = 0; + if( pElem ){ + char *aCopy; + PendingList *pList = (PendingList *)fts3HashData(pElem); + int nCopy = pList->nData+1; + pReader->zTerm = (char *)fts3HashKey(pElem); + pReader->nTerm = fts3HashKeysize(pElem); + aCopy = (char*)sqlite3_malloc(nCopy); + if( !aCopy ) return SQLITE_NOMEM; + memcpy(aCopy, pList->aData, nCopy); + pReader->nNode = pReader->nDoclist = nCopy; + pReader->aNode = pReader->aDoclist = aCopy; + pReader->ppNextElem++; + assert( pReader->aNode ); + } + return SQLITE_OK; + } + + fts3SegReaderSetEof(pReader); + + /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf + ** blocks have already been traversed. */ + assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock ); + if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){ + return SQLITE_OK; + } + + rc = sqlite3Fts3ReadBlock( + p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode, + (bIncr ? &pReader->nPopulate : 0) + ); + if( rc!=SQLITE_OK ) return rc; + assert( pReader->pBlob==0 ); + if( bIncr && pReader->nPopulatenNode ){ + pReader->pBlob = p->pSegments; + p->pSegments = 0; + } + pNext = pReader->aNode; + } + + assert( !fts3SegReaderIsPending(pReader) ); + + rc = fts3SegReaderRequire(pReader, pNext, FTS3_VARINT_MAX*2); + if( rc!=SQLITE_OK ) return rc; + + /* Because of the FTS3_NODE_PADDING bytes of padding, the following is + ** safe (no risk of overread) even if the node data is corrupted. */ + pNext += fts3GetVarint32(pNext, &nPrefix); + pNext += fts3GetVarint32(pNext, &nSuffix); + if( nPrefix<0 || nSuffix<=0 + || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] + ){ + return FTS_CORRUPT_VTAB; + } + + if( nPrefix+nSuffix>pReader->nTermAlloc ){ + int nNew = (nPrefix+nSuffix)*2; + char *zNew = sqlite3_realloc(pReader->zTerm, nNew); + if( !zNew ){ + return SQLITE_NOMEM; + } + pReader->zTerm = zNew; + pReader->nTermAlloc = nNew; + } + + rc = fts3SegReaderRequire(pReader, pNext, nSuffix+FTS3_VARINT_MAX); + if( rc!=SQLITE_OK ) return rc; + + memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix); + pReader->nTerm = nPrefix+nSuffix; + pNext += nSuffix; + pNext += fts3GetVarint32(pNext, &pReader->nDoclist); + pReader->aDoclist = pNext; + pReader->pOffsetList = 0; + + /* Check that the doclist does not appear to extend past the end of the + ** b-tree node. And that the final byte of the doclist is 0x00. If either + ** of these statements is untrue, then the data structure is corrupt. + */ + if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] + || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) + ){ + return FTS_CORRUPT_VTAB; + } + return SQLITE_OK; +} + +/* +** Set the SegReader to point to the first docid in the doclist associated +** with the current term. +*/ +static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){ + int rc = SQLITE_OK; + assert( pReader->aDoclist ); + assert( !pReader->pOffsetList ); + if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ + u8 bEof = 0; + pReader->iDocid = 0; + pReader->nOffsetList = 0; + sqlite3Fts3DoclistPrev(0, + pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList, + &pReader->iDocid, &pReader->nOffsetList, &bEof + ); + }else{ + rc = fts3SegReaderRequire(pReader, pReader->aDoclist, FTS3_VARINT_MAX); + if( rc==SQLITE_OK ){ + int n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid); + pReader->pOffsetList = &pReader->aDoclist[n]; + } + } + return rc; +} + +/* +** Advance the SegReader to point to the next docid in the doclist +** associated with the current term. +** +** If arguments ppOffsetList and pnOffsetList are not NULL, then +** *ppOffsetList is set to point to the first column-offset list +** in the doclist entry (i.e. immediately past the docid varint). +** *pnOffsetList is set to the length of the set of column-offset +** lists, not including the nul-terminator byte. For example: +*/ +static int fts3SegReaderNextDocid( + Fts3Table *pTab, + Fts3SegReader *pReader, /* Reader to advance to next docid */ + char **ppOffsetList, /* OUT: Pointer to current position-list */ + int *pnOffsetList /* OUT: Length of *ppOffsetList in bytes */ +){ + int rc = SQLITE_OK; + char *p = pReader->pOffsetList; + char c = 0; + + assert( p ); + + if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ + /* A pending-terms seg-reader for an FTS4 table that uses order=desc. + ** Pending-terms doclists are always built up in ascending order, so + ** we have to iterate through them backwards here. */ + u8 bEof = 0; + if( ppOffsetList ){ + *ppOffsetList = pReader->pOffsetList; + *pnOffsetList = pReader->nOffsetList - 1; + } + sqlite3Fts3DoclistPrev(0, + pReader->aDoclist, pReader->nDoclist, &p, &pReader->iDocid, + &pReader->nOffsetList, &bEof + ); + if( bEof ){ + pReader->pOffsetList = 0; + }else{ + pReader->pOffsetList = p; + } + }else{ + char *pEnd = &pReader->aDoclist[pReader->nDoclist]; + + /* Pointer p currently points at the first byte of an offset list. The + ** following block advances it to point one byte past the end of + ** the same offset list. */ + while( 1 ){ + + /* The following line of code (and the "p++" below the while() loop) is + ** normally all that is required to move pointer p to the desired + ** position. The exception is if this node is being loaded from disk + ** incrementally and pointer "p" now points to the first byte past + ** the populated part of pReader->aNode[]. + */ + while( *p | c ) c = *p++ & 0x80; + assert( *p==0 ); + + if( pReader->pBlob==0 || p<&pReader->aNode[pReader->nPopulate] ) break; + rc = fts3SegReaderIncrRead(pReader); + if( rc!=SQLITE_OK ) return rc; + } + p++; + + /* If required, populate the output variables with a pointer to and the + ** size of the previous offset-list. + */ + if( ppOffsetList ){ + *ppOffsetList = pReader->pOffsetList; + *pnOffsetList = (int)(p - pReader->pOffsetList - 1); + } + + /* List may have been edited in place by fts3EvalNearTrim() */ + while( p=pEnd ){ + pReader->pOffsetList = 0; + }else{ + rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX); + if( rc==SQLITE_OK ){ + sqlite3_int64 iDelta; + pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta); + if( pTab->bDescIdx ){ + pReader->iDocid -= iDelta; + }else{ + pReader->iDocid += iDelta; + } + } + } + } + + return SQLITE_OK; +} + + +SQLITE_PRIVATE int sqlite3Fts3MsrOvfl( + Fts3Cursor *pCsr, + Fts3MultiSegReader *pMsr, + int *pnOvfl +){ + Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; + int nOvfl = 0; + int ii; + int rc = SQLITE_OK; + int pgsz = p->nPgsz; + + assert( p->bFts4 ); + assert( pgsz>0 ); + + for(ii=0; rc==SQLITE_OK && iinSegment; ii++){ + Fts3SegReader *pReader = pMsr->apSegment[ii]; + if( !fts3SegReaderIsPending(pReader) + && !fts3SegReaderIsRootOnly(pReader) + ){ + sqlite3_int64 jj; + for(jj=pReader->iStartBlock; jj<=pReader->iLeafEndBlock; jj++){ + int nBlob; + rc = sqlite3Fts3ReadBlock(p, jj, 0, &nBlob, 0); + if( rc!=SQLITE_OK ) break; + if( (nBlob+35)>pgsz ){ + nOvfl += (nBlob + 34)/pgsz; + } + } + } + } + *pnOvfl = nOvfl; + return rc; +} + +/* +** Free all allocations associated with the iterator passed as the +** second argument. +*/ +SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ + if( pReader ){ + if( !fts3SegReaderIsPending(pReader) ){ + sqlite3_free(pReader->zTerm); + } + if( !fts3SegReaderIsRootOnly(pReader) ){ + sqlite3_free(pReader->aNode); + } + sqlite3_blob_close(pReader->pBlob); + } + sqlite3_free(pReader); +} + +/* +** Allocate a new SegReader object. +*/ +SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( + int iAge, /* Segment "age". */ + int bLookup, /* True for a lookup only */ + sqlite3_int64 iStartLeaf, /* First leaf to traverse */ + sqlite3_int64 iEndLeaf, /* Final leaf to traverse */ + sqlite3_int64 iEndBlock, /* Final block of segment */ + const char *zRoot, /* Buffer containing root node */ + int nRoot, /* Size of buffer containing root node */ + Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */ +){ + Fts3SegReader *pReader; /* Newly allocated SegReader object */ + int nExtra = 0; /* Bytes to allocate segment root node */ + + assert( iStartLeaf<=iEndLeaf ); + if( iStartLeaf==0 ){ + nExtra = nRoot + FTS3_NODE_PADDING; + } + + pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); + if( !pReader ){ + return SQLITE_NOMEM; + } + memset(pReader, 0, sizeof(Fts3SegReader)); + pReader->iIdx = iAge; + pReader->bLookup = bLookup!=0; + pReader->iStartBlock = iStartLeaf; + pReader->iLeafEndBlock = iEndLeaf; + pReader->iEndBlock = iEndBlock; + + if( nExtra ){ + /* The entire segment is stored in the root node. */ + pReader->aNode = (char *)&pReader[1]; + pReader->rootOnly = 1; + pReader->nNode = nRoot; + memcpy(pReader->aNode, zRoot, nRoot); + memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING); + }else{ + pReader->iCurrentBlock = iStartLeaf-1; + } + *ppReader = pReader; + return SQLITE_OK; +} + +/* +** This is a comparison function used as a qsort() callback when sorting +** an array of pending terms by term. This occurs as part of flushing +** the contents of the pending-terms hash table to the database. +*/ +static int SQLITE_CDECL fts3CompareElemByTerm( + const void *lhs, + const void *rhs +){ + char *z1 = fts3HashKey(*(Fts3HashElem **)lhs); + char *z2 = fts3HashKey(*(Fts3HashElem **)rhs); + int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs); + int n2 = fts3HashKeysize(*(Fts3HashElem **)rhs); + + int n = (n1aIndex */ + const char *zTerm, /* Term to search for */ + int nTerm, /* Size of buffer zTerm */ + int bPrefix, /* True for a prefix iterator */ + Fts3SegReader **ppReader /* OUT: SegReader for pending-terms */ +){ + Fts3SegReader *pReader = 0; /* Fts3SegReader object to return */ + Fts3HashElem *pE; /* Iterator variable */ + Fts3HashElem **aElem = 0; /* Array of term hash entries to scan */ + int nElem = 0; /* Size of array at aElem */ + int rc = SQLITE_OK; /* Return Code */ + Fts3Hash *pHash; + + pHash = &p->aIndex[iIndex].hPending; + if( bPrefix ){ + int nAlloc = 0; /* Size of allocated array at aElem */ + + for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){ + char *zKey = (char *)fts3HashKey(pE); + int nKey = fts3HashKeysize(pE); + if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){ + if( nElem==nAlloc ){ + Fts3HashElem **aElem2; + nAlloc += 16; + aElem2 = (Fts3HashElem **)sqlite3_realloc( + aElem, nAlloc*sizeof(Fts3HashElem *) + ); + if( !aElem2 ){ + rc = SQLITE_NOMEM; + nElem = 0; + break; + } + aElem = aElem2; + } + + aElem[nElem++] = pE; + } + } + + /* If more than one term matches the prefix, sort the Fts3HashElem + ** objects in term order using qsort(). This uses the same comparison + ** callback as is used when flushing terms to disk. + */ + if( nElem>1 ){ + qsort(aElem, nElem, sizeof(Fts3HashElem *), fts3CompareElemByTerm); + } + + }else{ + /* The query is a simple term lookup that matches at most one term in + ** the index. All that is required is a straight hash-lookup. + ** + ** Because the stack address of pE may be accessed via the aElem pointer + ** below, the "Fts3HashElem *pE" must be declared so that it is valid + ** within this entire function, not just this "else{...}" block. + */ + pE = fts3HashFindElem(pHash, zTerm, nTerm); + if( pE ){ + aElem = &pE; + nElem = 1; + } + } + + if( nElem>0 ){ + int nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); + pReader = (Fts3SegReader *)sqlite3_malloc(nByte); + if( !pReader ){ + rc = SQLITE_NOMEM; + }else{ + memset(pReader, 0, nByte); + pReader->iIdx = 0x7FFFFFFF; + pReader->ppNextElem = (Fts3HashElem **)&pReader[1]; + memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *)); + } + } + + if( bPrefix ){ + sqlite3_free(aElem); + } + *ppReader = pReader; + return rc; +} + +/* +** Compare the entries pointed to by two Fts3SegReader structures. +** Comparison is as follows: +** +** 1) EOF is greater than not EOF. +** +** 2) The current terms (if any) are compared using memcmp(). If one +** term is a prefix of another, the longer term is considered the +** larger. +** +** 3) By segment age. An older segment is considered larger. +*/ +static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ + int rc; + if( pLhs->aNode && pRhs->aNode ){ + int rc2 = pLhs->nTerm - pRhs->nTerm; + if( rc2<0 ){ + rc = memcmp(pLhs->zTerm, pRhs->zTerm, pLhs->nTerm); + }else{ + rc = memcmp(pLhs->zTerm, pRhs->zTerm, pRhs->nTerm); + } + if( rc==0 ){ + rc = rc2; + } + }else{ + rc = (pLhs->aNode==0) - (pRhs->aNode==0); + } + if( rc==0 ){ + rc = pRhs->iIdx - pLhs->iIdx; + } + assert( rc!=0 ); + return rc; +} + +/* +** A different comparison function for SegReader structures. In this +** version, it is assumed that each SegReader points to an entry in +** a doclist for identical terms. Comparison is made as follows: +** +** 1) EOF (end of doclist in this case) is greater than not EOF. +** +** 2) By current docid. +** +** 3) By segment age. An older segment is considered larger. +*/ +static int fts3SegReaderDoclistCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ + int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); + if( rc==0 ){ + if( pLhs->iDocid==pRhs->iDocid ){ + rc = pRhs->iIdx - pLhs->iIdx; + }else{ + rc = (pLhs->iDocid > pRhs->iDocid) ? 1 : -1; + } + } + assert( pLhs->aNode && pRhs->aNode ); + return rc; +} +static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ + int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); + if( rc==0 ){ + if( pLhs->iDocid==pRhs->iDocid ){ + rc = pRhs->iIdx - pLhs->iIdx; + }else{ + rc = (pLhs->iDocid < pRhs->iDocid) ? 1 : -1; + } + } + assert( pLhs->aNode && pRhs->aNode ); + return rc; +} + +/* +** Compare the term that the Fts3SegReader object passed as the first argument +** points to with the term specified by arguments zTerm and nTerm. +** +** If the pSeg iterator is already at EOF, return 0. Otherwise, return +** -ve if the pSeg term is less than zTerm/nTerm, 0 if the two terms are +** equal, or +ve if the pSeg term is greater than zTerm/nTerm. +*/ +static int fts3SegReaderTermCmp( + Fts3SegReader *pSeg, /* Segment reader object */ + const char *zTerm, /* Term to compare to */ + int nTerm /* Size of term zTerm in bytes */ +){ + int res = 0; + if( pSeg->aNode ){ + if( pSeg->nTerm>nTerm ){ + res = memcmp(pSeg->zTerm, zTerm, nTerm); + }else{ + res = memcmp(pSeg->zTerm, zTerm, pSeg->nTerm); + } + if( res==0 ){ + res = pSeg->nTerm-nTerm; + } + } + return res; +} + +/* +** Argument apSegment is an array of nSegment elements. It is known that +** the final (nSegment-nSuspect) members are already in sorted order +** (according to the comparison function provided). This function shuffles +** the array around until all entries are in sorted order. +*/ +static void fts3SegReaderSort( + Fts3SegReader **apSegment, /* Array to sort entries of */ + int nSegment, /* Size of apSegment array */ + int nSuspect, /* Unsorted entry count */ + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) /* Comparison function */ +){ + int i; /* Iterator variable */ + + assert( nSuspect<=nSegment ); + + if( nSuspect==nSegment ) nSuspect--; + for(i=nSuspect-1; i>=0; i--){ + int j; + for(j=i; j<(nSegment-1); j++){ + Fts3SegReader *pTmp; + if( xCmp(apSegment[j], apSegment[j+1])<0 ) break; + pTmp = apSegment[j+1]; + apSegment[j+1] = apSegment[j]; + apSegment[j] = pTmp; + } + } + +#ifndef NDEBUG + /* Check that the list really is sorted now. */ + for(i=0; i<(nSuspect-1); i++){ + assert( xCmp(apSegment[i], apSegment[i+1])<0 ); + } +#endif +} + +/* +** Insert a record into the %_segments table. +*/ +static int fts3WriteSegment( + Fts3Table *p, /* Virtual table handle */ + sqlite3_int64 iBlock, /* Block id for new block */ + char *z, /* Pointer to buffer containing block data */ + int n /* Size of buffer z in bytes */ +){ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, SQL_INSERT_SEGMENTS, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iBlock); + sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } + return rc; +} + +/* +** Find the largest relative level number in the table. If successful, set +** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs, +** set *pnMax to zero and return an SQLite error code. +*/ +SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){ + int rc; + int mxLevel = 0; + sqlite3_stmt *pStmt = 0; + + rc = fts3SqlStmt(p, SQL_SELECT_MXLEVEL, &pStmt, 0); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + mxLevel = sqlite3_column_int(pStmt, 0); + } + rc = sqlite3_reset(pStmt); + } + *pnMax = mxLevel; + return rc; +} + +/* +** Insert a record into the %_segdir table. +*/ +static int fts3WriteSegdir( + Fts3Table *p, /* Virtual table handle */ + sqlite3_int64 iLevel, /* Value for "level" field (absolute level) */ + int iIdx, /* Value for "idx" field */ + sqlite3_int64 iStartBlock, /* Value for "start_block" field */ + sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */ + sqlite3_int64 iEndBlock, /* Value for "end_block" field */ + sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */ + char *zRoot, /* Blob value for "root" field */ + int nRoot /* Number of bytes in buffer zRoot */ +){ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iLevel); + sqlite3_bind_int(pStmt, 2, iIdx); + sqlite3_bind_int64(pStmt, 3, iStartBlock); + sqlite3_bind_int64(pStmt, 4, iLeafEndBlock); + if( nLeafData==0 ){ + sqlite3_bind_int64(pStmt, 5, iEndBlock); + }else{ + char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); + if( !zEnd ) return SQLITE_NOMEM; + sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); + } + sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } + return rc; +} + +/* +** Return the size of the common prefix (if any) shared by zPrev and +** zNext, in bytes. For example, +** +** fts3PrefixCompress("abc", 3, "abcdef", 6) // returns 3 +** fts3PrefixCompress("abX", 3, "abcdef", 6) // returns 2 +** fts3PrefixCompress("abX", 3, "Xbcdef", 6) // returns 0 +*/ +static int fts3PrefixCompress( + const char *zPrev, /* Buffer containing previous term */ + int nPrev, /* Size of buffer zPrev in bytes */ + const char *zNext, /* Buffer containing next term */ + int nNext /* Size of buffer zNext in bytes */ +){ + int n; + UNUSED_PARAMETER(nNext); + for(n=0; nnData; /* Current size of node in bytes */ + int nReq = nData; /* Required space after adding zTerm */ + int nPrefix; /* Number of bytes of prefix compression */ + int nSuffix; /* Suffix length */ + + nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm); + nSuffix = nTerm-nPrefix; + + nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix; + if( nReq<=p->nNodeSize || !pTree->zTerm ){ + + if( nReq>p->nNodeSize ){ + /* An unusual case: this is the first term to be added to the node + ** and the static node buffer (p->nNodeSize bytes) is not large + ** enough. Use a separately malloced buffer instead This wastes + ** p->nNodeSize bytes, but since this scenario only comes about when + ** the database contain two terms that share a prefix of almost 2KB, + ** this is not expected to be a serious problem. + */ + assert( pTree->aData==(char *)&pTree[1] ); + pTree->aData = (char *)sqlite3_malloc(nReq); + if( !pTree->aData ){ + return SQLITE_NOMEM; + } + } + + if( pTree->zTerm ){ + /* There is no prefix-length field for first term in a node */ + nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nPrefix); + } + + nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nSuffix); + memcpy(&pTree->aData[nData], &zTerm[nPrefix], nSuffix); + pTree->nData = nData + nSuffix; + pTree->nEntry++; + + if( isCopyTerm ){ + if( pTree->nMalloczMalloc, nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } + pTree->nMalloc = nTerm*2; + pTree->zMalloc = zNew; + } + pTree->zTerm = pTree->zMalloc; + memcpy(pTree->zTerm, zTerm, nTerm); + pTree->nTerm = nTerm; + }else{ + pTree->zTerm = (char *)zTerm; + pTree->nTerm = nTerm; + } + return SQLITE_OK; + } + } + + /* If control flows to here, it was not possible to append zTerm to the + ** current node. Create a new node (a right-sibling of the current node). + ** If this is the first node in the tree, the term is added to it. + ** + ** Otherwise, the term is not added to the new node, it is left empty for + ** now. Instead, the term is inserted into the parent of pTree. If pTree + ** has no parent, one is created here. + */ + pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); + if( !pNew ){ + return SQLITE_NOMEM; + } + memset(pNew, 0, sizeof(SegmentNode)); + pNew->nData = 1 + FTS3_VARINT_MAX; + pNew->aData = (char *)&pNew[1]; + + if( pTree ){ + SegmentNode *pParent = pTree->pParent; + rc = fts3NodeAddTerm(p, &pParent, isCopyTerm, zTerm, nTerm); + if( pTree->pParent==0 ){ + pTree->pParent = pParent; + } + pTree->pRight = pNew; + pNew->pLeftmost = pTree->pLeftmost; + pNew->pParent = pParent; + pNew->zMalloc = pTree->zMalloc; + pNew->nMalloc = pTree->nMalloc; + pTree->zMalloc = 0; + }else{ + pNew->pLeftmost = pNew; + rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm); + } + + *ppTree = pNew; + return rc; +} + +/* +** Helper function for fts3NodeWrite(). +*/ +static int fts3TreeFinishNode( + SegmentNode *pTree, + int iHeight, + sqlite3_int64 iLeftChild +){ + int nStart; + assert( iHeight>=1 && iHeight<128 ); + nStart = FTS3_VARINT_MAX - sqlite3Fts3VarintLen(iLeftChild); + pTree->aData[nStart] = (char)iHeight; + sqlite3Fts3PutVarint(&pTree->aData[nStart+1], iLeftChild); + return nStart; +} + +/* +** Write the buffer for the segment node pTree and all of its peers to the +** database. Then call this function recursively to write the parent of +** pTree and its peers to the database. +** +** Except, if pTree is a root node, do not write it to the database. Instead, +** set output variables *paRoot and *pnRoot to contain the root node. +** +** If successful, SQLITE_OK is returned and output variable *piLast is +** set to the largest blockid written to the database (or zero if no +** blocks were written to the db). Otherwise, an SQLite error code is +** returned. +*/ +static int fts3NodeWrite( + Fts3Table *p, /* Virtual table handle */ + SegmentNode *pTree, /* SegmentNode handle */ + int iHeight, /* Height of this node in tree */ + sqlite3_int64 iLeaf, /* Block id of first leaf node */ + sqlite3_int64 iFree, /* Block id of next free slot in %_segments */ + sqlite3_int64 *piLast, /* OUT: Block id of last entry written */ + char **paRoot, /* OUT: Data for root node */ + int *pnRoot /* OUT: Size of root node in bytes */ +){ + int rc = SQLITE_OK; + + if( !pTree->pParent ){ + /* Root node of the tree. */ + int nStart = fts3TreeFinishNode(pTree, iHeight, iLeaf); + *piLast = iFree-1; + *pnRoot = pTree->nData - nStart; + *paRoot = &pTree->aData[nStart]; + }else{ + SegmentNode *pIter; + sqlite3_int64 iNextFree = iFree; + sqlite3_int64 iNextLeaf = iLeaf; + for(pIter=pTree->pLeftmost; pIter && rc==SQLITE_OK; pIter=pIter->pRight){ + int nStart = fts3TreeFinishNode(pIter, iHeight, iNextLeaf); + int nWrite = pIter->nData - nStart; + + rc = fts3WriteSegment(p, iNextFree, &pIter->aData[nStart], nWrite); + iNextFree++; + iNextLeaf += (pIter->nEntry+1); + } + if( rc==SQLITE_OK ){ + assert( iNextLeaf==iFree ); + rc = fts3NodeWrite( + p, pTree->pParent, iHeight+1, iFree, iNextFree, piLast, paRoot, pnRoot + ); + } + } + + return rc; +} + +/* +** Free all memory allocations associated with the tree pTree. +*/ +static void fts3NodeFree(SegmentNode *pTree){ + if( pTree ){ + SegmentNode *p = pTree->pLeftmost; + fts3NodeFree(p->pParent); + while( p ){ + SegmentNode *pRight = p->pRight; + if( p->aData!=(char *)&p[1] ){ + sqlite3_free(p->aData); + } + assert( pRight==0 || p->zMalloc==0 ); + sqlite3_free(p->zMalloc); + sqlite3_free(p); + p = pRight; + } + } +} + +/* +** Add a term to the segment being constructed by the SegmentWriter object +** *ppWriter. When adding the first term to a segment, *ppWriter should +** be passed NULL. This function will allocate a new SegmentWriter object +** and return it via the input/output variable *ppWriter in this case. +** +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. +*/ +static int fts3SegWriterAdd( + Fts3Table *p, /* Virtual table handle */ + SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */ + int isCopyTerm, /* True if buffer zTerm must be copied */ + const char *zTerm, /* Pointer to buffer containing term */ + int nTerm, /* Size of term in bytes */ + const char *aDoclist, /* Pointer to buffer containing doclist */ + int nDoclist /* Size of doclist in bytes */ +){ + int nPrefix; /* Size of term prefix in bytes */ + int nSuffix; /* Size of term suffix in bytes */ + int nReq; /* Number of bytes required on leaf page */ + int nData; + SegmentWriter *pWriter = *ppWriter; + + if( !pWriter ){ + int rc; + sqlite3_stmt *pStmt; + + /* Allocate the SegmentWriter structure */ + pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); + if( !pWriter ) return SQLITE_NOMEM; + memset(pWriter, 0, sizeof(SegmentWriter)); + *ppWriter = pWriter; + + /* Allocate a buffer in which to accumulate data */ + pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); + if( !pWriter->aData ) return SQLITE_NOMEM; + pWriter->nSize = p->nNodeSize; + + /* Find the next free blockid in the %_segments table */ + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + pWriter->iFree = sqlite3_column_int64(pStmt, 0); + pWriter->iFirst = pWriter->iFree; + } + rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ) return rc; + } + nData = pWriter->nData; + + nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); + nSuffix = nTerm-nPrefix; + + /* Figure out how many bytes are required by this new entry */ + nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */ + sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */ + nSuffix + /* Term suffix */ + sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ + nDoclist; /* Doclist data */ + + if( nData>0 && nData+nReq>p->nNodeSize ){ + int rc; + + /* The current leaf node is full. Write it out to the database. */ + rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData); + if( rc!=SQLITE_OK ) return rc; + p->nLeafAdd++; + + /* Add the current term to the interior node tree. The term added to + ** the interior tree must: + ** + ** a) be greater than the largest term on the leaf node just written + ** to the database (still available in pWriter->zTerm), and + ** + ** b) be less than or equal to the term about to be added to the new + ** leaf node (zTerm/nTerm). + ** + ** In other words, it must be the prefix of zTerm 1 byte longer than + ** the common prefix (if any) of zTerm and pWriter->zTerm. + */ + assert( nPrefixpTree, isCopyTerm, zTerm, nPrefix+1); + if( rc!=SQLITE_OK ) return rc; + + nData = 0; + pWriter->nTerm = 0; + + nPrefix = 0; + nSuffix = nTerm; + nReq = 1 + /* varint containing prefix size */ + sqlite3Fts3VarintLen(nTerm) + /* varint containing suffix size */ + nTerm + /* Term suffix */ + sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ + nDoclist; /* Doclist data */ + } + + /* Increase the total number of bytes written to account for the new entry. */ + pWriter->nLeafData += nReq; + + /* If the buffer currently allocated is too small for this entry, realloc + ** the buffer to make it large enough. + */ + if( nReq>pWriter->nSize ){ + char *aNew = sqlite3_realloc(pWriter->aData, nReq); + if( !aNew ) return SQLITE_NOMEM; + pWriter->aData = aNew; + pWriter->nSize = nReq; + } + assert( nData+nReq<=pWriter->nSize ); + + /* Append the prefix-compressed term and doclist to the buffer. */ + nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix); + nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix); + memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix); + nData += nSuffix; + nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist); + memcpy(&pWriter->aData[nData], aDoclist, nDoclist); + pWriter->nData = nData + nDoclist; + + /* Save the current term so that it can be used to prefix-compress the next. + ** If the isCopyTerm parameter is true, then the buffer pointed to by + ** zTerm is transient, so take a copy of the term data. Otherwise, just + ** store a copy of the pointer. + */ + if( isCopyTerm ){ + if( nTerm>pWriter->nMalloc ){ + char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } + pWriter->nMalloc = nTerm*2; + pWriter->zMalloc = zNew; + pWriter->zTerm = zNew; + } + assert( pWriter->zTerm==pWriter->zMalloc ); + memcpy(pWriter->zTerm, zTerm, nTerm); + }else{ + pWriter->zTerm = (char *)zTerm; + } + pWriter->nTerm = nTerm; + + return SQLITE_OK; +} + +/* +** Flush all data associated with the SegmentWriter object pWriter to the +** database. This function must be called after all terms have been added +** to the segment using fts3SegWriterAdd(). If successful, SQLITE_OK is +** returned. Otherwise, an SQLite error code. +*/ +static int fts3SegWriterFlush( + Fts3Table *p, /* Virtual table handle */ + SegmentWriter *pWriter, /* SegmentWriter to flush to the db */ + sqlite3_int64 iLevel, /* Value for 'level' column of %_segdir */ + int iIdx /* Value for 'idx' column of %_segdir */ +){ + int rc; /* Return code */ + if( pWriter->pTree ){ + sqlite3_int64 iLast = 0; /* Largest block id written to database */ + sqlite3_int64 iLastLeaf; /* Largest leaf block id written to db */ + char *zRoot = NULL; /* Pointer to buffer containing root node */ + int nRoot = 0; /* Size of buffer zRoot */ + + iLastLeaf = pWriter->iFree; + rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, pWriter->nData); + if( rc==SQLITE_OK ){ + rc = fts3NodeWrite(p, pWriter->pTree, 1, + pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot); + } + if( rc==SQLITE_OK ){ + rc = fts3WriteSegdir(p, iLevel, iIdx, + pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot); + } + }else{ + /* The entire tree fits on the root node. Write it to the segdir table. */ + rc = fts3WriteSegdir(p, iLevel, iIdx, + 0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData); + } + p->nLeafAdd++; + return rc; +} + +/* +** Release all memory held by the SegmentWriter object passed as the +** first argument. +*/ +static void fts3SegWriterFree(SegmentWriter *pWriter){ + if( pWriter ){ + sqlite3_free(pWriter->aData); + sqlite3_free(pWriter->zMalloc); + fts3NodeFree(pWriter->pTree); + sqlite3_free(pWriter); + } +} + +/* +** The first value in the apVal[] array is assumed to contain an integer. +** This function tests if there exist any documents with docid values that +** are different from that integer. i.e. if deleting the document with docid +** pRowid would mean the FTS3 table were empty. +** +** If successful, *pisEmpty is set to true if the table is empty except for +** document pRowid, or false otherwise, and SQLITE_OK is returned. If an +** error occurs, an SQLite error code is returned. +*/ +static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ + sqlite3_stmt *pStmt; + int rc; + if( p->zContentTbl ){ + /* If using the content=xxx option, assume the table is never empty */ + *pisEmpty = 0; + rc = SQLITE_OK; + }else{ + rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pisEmpty = sqlite3_column_int(pStmt, 0); + } + rc = sqlite3_reset(pStmt); + } + } + return rc; +} + +/* +** Set *pnMax to the largest segment level in the database for the index +** iIndex. +** +** Segment levels are stored in the 'level' column of the %_segdir table. +** +** Return SQLITE_OK if successful, or an SQLite error code if not. +*/ +static int fts3SegmentMaxLevel( + Fts3Table *p, + int iLangid, + int iIndex, + sqlite3_int64 *pnMax +){ + sqlite3_stmt *pStmt; + int rc; + assert( iIndex>=0 && iIndexnIndex ); + + /* Set pStmt to the compiled version of: + ** + ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? + ** + ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). + */ + rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); + sqlite3_bind_int64(pStmt, 2, + getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) + ); + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pnMax = sqlite3_column_int64(pStmt, 0); + } + return sqlite3_reset(pStmt); +} + +/* +** iAbsLevel is an absolute level that may be assumed to exist within +** the database. This function checks if it is the largest level number +** within its index. Assuming no error occurs, *pbMax is set to 1 if +** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK +** is returned. If an error occurs, an error code is returned and the +** final value of *pbMax is undefined. +*/ +static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){ + + /* Set pStmt to the compiled version of: + ** + ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? + ** + ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). + */ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); + sqlite3_bind_int64(pStmt, 2, + ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL + ); + + *pbMax = 0; + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; + } + return sqlite3_reset(pStmt); +} + +/* +** Delete all entries in the %_segments table associated with the segment +** opened with seg-reader pSeg. This function does not affect the contents +** of the %_segdir table. +*/ +static int fts3DeleteSegment( + Fts3Table *p, /* FTS table handle */ + Fts3SegReader *pSeg /* Segment to delete */ +){ + int rc = SQLITE_OK; /* Return code */ + if( pSeg->iStartBlock ){ + sqlite3_stmt *pDelete; /* SQL statement to delete rows */ + rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDelete, 1, pSeg->iStartBlock); + sqlite3_bind_int64(pDelete, 2, pSeg->iEndBlock); + sqlite3_step(pDelete); + rc = sqlite3_reset(pDelete); + } + } + return rc; +} + +/* +** This function is used after merging multiple segments into a single large +** segment to delete the old, now redundant, segment b-trees. Specifically, +** it: +** +** 1) Deletes all %_segments entries for the segments associated with +** each of the SegReader objects in the array passed as the third +** argument, and +** +** 2) deletes all %_segdir entries with level iLevel, or all %_segdir +** entries regardless of level if (iLevel<0). +** +** SQLITE_OK is returned if successful, otherwise an SQLite error code. +*/ +static int fts3DeleteSegdir( + Fts3Table *p, /* Virtual table handle */ + int iLangid, /* Language id */ + int iIndex, /* Index for p->aIndex */ + int iLevel, /* Level of %_segdir entries to delete */ + Fts3SegReader **apSegment, /* Array of SegReader objects */ + int nReader /* Size of array apSegment */ +){ + int rc = SQLITE_OK; /* Return Code */ + int i; /* Iterator variable */ + sqlite3_stmt *pDelete = 0; /* SQL statement to delete rows */ + + for(i=0; rc==SQLITE_OK && i=0 || iLevel==FTS3_SEGCURSOR_ALL ); + if( iLevel==FTS3_SEGCURSOR_ALL ){ + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); + sqlite3_bind_int64(pDelete, 2, + getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) + ); + } + }else{ + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64( + pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) + ); + } + } + + if( rc==SQLITE_OK ){ + sqlite3_step(pDelete); + rc = sqlite3_reset(pDelete); + } + + return rc; +} + +/* +** When this function is called, buffer *ppList (size *pnList bytes) contains +** a position list that may (or may not) feature multiple columns. This +** function adjusts the pointer *ppList and the length *pnList so that they +** identify the subset of the position list that corresponds to column iCol. +** +** If there are no entries in the input position list for column iCol, then +** *pnList is set to zero before returning. +** +** If parameter bZero is non-zero, then any part of the input list following +** the end of the output list is zeroed before returning. +*/ +static void fts3ColumnFilter( + int iCol, /* Column to filter on */ + int bZero, /* Zero out anything following *ppList */ + char **ppList, /* IN/OUT: Pointer to position list */ + int *pnList /* IN/OUT: Size of buffer *ppList in bytes */ +){ + char *pList = *ppList; + int nList = *pnList; + char *pEnd = &pList[nList]; + int iCurrent = 0; + char *p = pList; + + assert( iCol>=0 ); + while( 1 ){ + char c = 0; + while( ppMsr->nBuffer ){ + char *pNew; + pMsr->nBuffer = nList*2; + pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); + if( !pNew ) return SQLITE_NOMEM; + pMsr->aBuffer = pNew; + } + + memcpy(pMsr->aBuffer, pList, nList); + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ + sqlite3_int64 *piDocid, /* OUT: Docid value */ + char **paPoslist, /* OUT: Pointer to position list */ + int *pnPoslist /* OUT: Size of position list in bytes */ +){ + int nMerge = pMsr->nAdvance; + Fts3SegReader **apSegment = pMsr->apSegment; + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( + p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp + ); + + if( nMerge==0 ){ + *paPoslist = 0; + return SQLITE_OK; + } + + while( 1 ){ + Fts3SegReader *pSeg; + pSeg = pMsr->apSegment[0]; + + if( pSeg->pOffsetList==0 ){ + *paPoslist = 0; + break; + }else{ + int rc; + char *pList; + int nList; + int j; + sqlite3_int64 iDocid = apSegment[0]->iDocid; + + rc = fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); + j = 1; + while( rc==SQLITE_OK + && jpOffsetList + && apSegment[j]->iDocid==iDocid + ){ + rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); + j++; + } + if( rc!=SQLITE_OK ) return rc; + fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); + + if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ + rc = fts3MsrBufferData(pMsr, pList, nList+1); + if( rc!=SQLITE_OK ) return rc; + assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); + pList = pMsr->aBuffer; + } + + if( pMsr->iColFilter>=0 ){ + fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList); + } + + if( nList>0 ){ + *paPoslist = pList; + *piDocid = iDocid; + *pnPoslist = nList; + break; + } + } + } + + return SQLITE_OK; +} + +static int fts3SegReaderStart( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr, /* Cursor object */ + const char *zTerm, /* Term searched for (or NULL) */ + int nTerm /* Length of zTerm in bytes */ +){ + int i; + int nSeg = pCsr->nSegment; + + /* If the Fts3SegFilter defines a specific term (or term prefix) to search + ** for, then advance each segment iterator until it points to a term of + ** equal or greater value than the specified term. This prevents many + ** unnecessary merge/sort operations for the case where single segment + ** b-tree leaf nodes contain more than one term. + */ + for(i=0; pCsr->bRestart==0 && inSegment; i++){ + int res = 0; + Fts3SegReader *pSeg = pCsr->apSegment[i]; + do { + int rc = fts3SegReaderNext(p, pSeg, 0); + if( rc!=SQLITE_OK ) return rc; + }while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 ); + + if( pSeg->bLookup && res!=0 ){ + fts3SegReaderSetEof(pSeg); + } + } + fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp); + + return SQLITE_OK; +} + +SQLITE_PRIVATE int sqlite3Fts3SegReaderStart( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr, /* Cursor object */ + Fts3SegFilter *pFilter /* Restrictions on range of iteration */ +){ + pCsr->pFilter = pFilter; + return fts3SegReaderStart(p, pCsr, pFilter->zTerm, pFilter->nTerm); +} + +SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr, /* Cursor object */ + int iCol, /* Column to match on. */ + const char *zTerm, /* Term to iterate through a doclist for */ + int nTerm /* Number of bytes in zTerm */ +){ + int i; + int rc; + int nSegment = pCsr->nSegment; + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( + p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp + ); + + assert( pCsr->pFilter==0 ); + assert( zTerm && nTerm>0 ); + + /* Advance each segment iterator until it points to the term zTerm/nTerm. */ + rc = fts3SegReaderStart(p, pCsr, zTerm, nTerm); + if( rc!=SQLITE_OK ) return rc; + + /* Determine how many of the segments actually point to zTerm/nTerm. */ + for(i=0; iapSegment[i]; + if( !pSeg->aNode || fts3SegReaderTermCmp(pSeg, zTerm, nTerm) ){ + break; + } + } + pCsr->nAdvance = i; + + /* Advance each of the segments to point to the first docid. */ + for(i=0; inAdvance; i++){ + rc = fts3SegReaderFirstDocid(p, pCsr->apSegment[i]); + if( rc!=SQLITE_OK ) return rc; + } + fts3SegReaderSort(pCsr->apSegment, i, i, xCmp); + + assert( iCol<0 || iColnColumn ); + pCsr->iColFilter = iCol; + + return SQLITE_OK; +} + +/* +** This function is called on a MultiSegReader that has been started using +** sqlite3Fts3MsrIncrStart(). One or more calls to MsrIncrNext() may also +** have been made. Calling this function puts the MultiSegReader in such +** a state that if the next two calls are: +** +** sqlite3Fts3SegReaderStart() +** sqlite3Fts3SegReaderStep() +** +** then the entire doclist for the term is available in +** MultiSegReader.aDoclist/nDoclist. +*/ +SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){ + int i; /* Used to iterate through segment-readers */ + + assert( pCsr->zTerm==0 ); + assert( pCsr->nTerm==0 ); + assert( pCsr->aDoclist==0 ); + assert( pCsr->nDoclist==0 ); + + pCsr->nAdvance = 0; + pCsr->bRestart = 1; + for(i=0; inSegment; i++){ + pCsr->apSegment[i]->pOffsetList = 0; + pCsr->apSegment[i]->nOffsetList = 0; + pCsr->apSegment[i]->iDocid = 0; + } + + return SQLITE_OK; +} + + +SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr /* Cursor object */ +){ + int rc = SQLITE_OK; + + int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY); + int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS); + int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); + int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); + int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); + int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST); + + Fts3SegReader **apSegment = pCsr->apSegment; + int nSegment = pCsr->nSegment; + Fts3SegFilter *pFilter = pCsr->pFilter; + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( + p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp + ); + + if( pCsr->nSegment==0 ) return SQLITE_OK; + + do { + int nMerge; + int i; + + /* Advance the first pCsr->nAdvance entries in the apSegment[] array + ** forward. Then sort the list in order of current term again. + */ + for(i=0; inAdvance; i++){ + Fts3SegReader *pSeg = apSegment[i]; + if( pSeg->bLookup ){ + fts3SegReaderSetEof(pSeg); + }else{ + rc = fts3SegReaderNext(p, pSeg, 0); + } + if( rc!=SQLITE_OK ) return rc; + } + fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp); + pCsr->nAdvance = 0; + + /* If all the seg-readers are at EOF, we're finished. return SQLITE_OK. */ + assert( rc==SQLITE_OK ); + if( apSegment[0]->aNode==0 ) break; + + pCsr->nTerm = apSegment[0]->nTerm; + pCsr->zTerm = apSegment[0]->zTerm; + + /* If this is a prefix-search, and if the term that apSegment[0] points + ** to does not share a suffix with pFilter->zTerm/nTerm, then all + ** required callbacks have been made. In this case exit early. + ** + ** Similarly, if this is a search for an exact match, and the first term + ** of segment apSegment[0] is not a match, exit early. + */ + if( pFilter->zTerm && !isScan ){ + if( pCsr->nTermnTerm + || (!isPrefix && pCsr->nTerm>pFilter->nTerm) + || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm) + ){ + break; + } + } + + nMerge = 1; + while( nMergeaNode + && apSegment[nMerge]->nTerm==pCsr->nTerm + && 0==memcmp(pCsr->zTerm, apSegment[nMerge]->zTerm, pCsr->nTerm) + ){ + nMerge++; + } + + assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); + if( nMerge==1 + && !isIgnoreEmpty + && !isFirst + && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) + ){ + pCsr->nDoclist = apSegment[0]->nDoclist; + if( fts3SegReaderIsPending(apSegment[0]) ){ + rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); + pCsr->aDoclist = pCsr->aBuffer; + }else{ + pCsr->aDoclist = apSegment[0]->aDoclist; + } + if( rc==SQLITE_OK ) rc = SQLITE_ROW; + }else{ + int nDoclist = 0; /* Size of doclist */ + sqlite3_int64 iPrev = 0; /* Previous docid stored in doclist */ + + /* The current term of the first nMerge entries in the array + ** of Fts3SegReader objects is the same. The doclists must be merged + ** and a single term returned with the merged doclist. + */ + for(i=0; ipOffsetList ){ + int j; /* Number of segments that share a docid */ + char *pList = 0; + int nList = 0; + int nByte; + sqlite3_int64 iDocid = apSegment[0]->iDocid; + fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); + j = 1; + while( jpOffsetList + && apSegment[j]->iDocid==iDocid + ){ + fts3SegReaderNextDocid(p, apSegment[j], 0, 0); + j++; + } + + if( isColFilter ){ + fts3ColumnFilter(pFilter->iCol, 0, &pList, &nList); + } + + if( !isIgnoreEmpty || nList>0 ){ + + /* Calculate the 'docid' delta value to write into the merged + ** doclist. */ + sqlite3_int64 iDelta; + if( p->bDescIdx && nDoclist>0 ){ + iDelta = iPrev - iDocid; + }else{ + iDelta = iDocid - iPrev; + } + assert( iDelta>0 || (nDoclist==0 && iDelta==iDocid) ); + assert( nDoclist>0 || iDelta==iDocid ); + + nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); + if( nDoclist+nByte>pCsr->nBuffer ){ + char *aNew; + pCsr->nBuffer = (nDoclist+nByte)*2; + aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); + if( !aNew ){ + return SQLITE_NOMEM; + } + pCsr->aBuffer = aNew; + } + + if( isFirst ){ + char *a = &pCsr->aBuffer[nDoclist]; + int nWrite; + + nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); + if( nWrite ){ + iPrev = iDocid; + nDoclist += nWrite; + } + }else{ + nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); + iPrev = iDocid; + if( isRequirePos ){ + memcpy(&pCsr->aBuffer[nDoclist], pList, nList); + nDoclist += nList; + pCsr->aBuffer[nDoclist++] = '\0'; + } + } + } + + fts3SegReaderSort(apSegment, nMerge, j, xCmp); + } + if( nDoclist>0 ){ + pCsr->aDoclist = pCsr->aBuffer; + pCsr->nDoclist = nDoclist; + rc = SQLITE_ROW; + } + } + pCsr->nAdvance = nMerge; + }while( rc==SQLITE_OK ); + + return rc; +} + + +SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish( + Fts3MultiSegReader *pCsr /* Cursor object */ +){ + if( pCsr ){ + int i; + for(i=0; inSegment; i++){ + sqlite3Fts3SegReaderFree(pCsr->apSegment[i]); + } + sqlite3_free(pCsr->apSegment); + sqlite3_free(pCsr->aBuffer); + + pCsr->nSegment = 0; + pCsr->apSegment = 0; + pCsr->aBuffer = 0; + } +} + +/* +** Decode the "end_block" field, selected by column iCol of the SELECT +** statement passed as the first argument. +** +** The "end_block" field may contain either an integer, or a text field +** containing the text representation of two non-negative integers separated +** by one or more space (0x20) characters. In the first case, set *piEndBlock +** to the integer value and *pnByte to zero before returning. In the second, +** set *piEndBlock to the first value and *pnByte to the second. +*/ +static void fts3ReadEndBlockField( + sqlite3_stmt *pStmt, + int iCol, + i64 *piEndBlock, + i64 *pnByte +){ + const unsigned char *zText = sqlite3_column_text(pStmt, iCol); + if( zText ){ + int i; + int iMul = 1; + i64 iVal = 0; + for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); + } + *piEndBlock = iVal; + while( zText[i]==' ' ) i++; + iVal = 0; + if( zText[i]=='-' ){ + i++; + iMul = -1; + } + for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); + } + *pnByte = (iVal * (i64)iMul); + } +} + + +/* +** A segment of size nByte bytes has just been written to absolute level +** iAbsLevel. Promote any segments that should be promoted as a result. +*/ +static int fts3PromoteSegments( + Fts3Table *p, /* FTS table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level just updated */ + sqlite3_int64 nByte /* Size of new segment at iAbsLevel */ +){ + int rc = SQLITE_OK; + sqlite3_stmt *pRange; + + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0); + + if( rc==SQLITE_OK ){ + int bOk = 0; + i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1; + i64 nLimit = (nByte*3)/2; + + /* Loop through all entries in the %_segdir table corresponding to + ** segments in this index on levels greater than iAbsLevel. If there is + ** at least one such segment, and it is possible to determine that all + ** such segments are smaller than nLimit bytes in size, they will be + ** promoted to level iAbsLevel. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel+1); + sqlite3_bind_int64(pRange, 2, iLast); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + i64 nSize = 0, dummy; + fts3ReadEndBlockField(pRange, 2, &dummy, &nSize); + if( nSize<=0 || nSize>nLimit ){ + /* If nSize==0, then the %_segdir.end_block field does not not + ** contain a size value. This happens if it was written by an + ** old version of FTS. In this case it is not possible to determine + ** the size of the segment, and so segment promotion does not + ** take place. */ + bOk = 0; + break; + } + bOk = 1; + } + rc = sqlite3_reset(pRange); + + if( bOk ){ + int iIdx = 0; + sqlite3_stmt *pUpdate1 = 0; + sqlite3_stmt *pUpdate2 = 0; + + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); + } + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0); + } + + if( rc==SQLITE_OK ){ + + /* Loop through all %_segdir entries for segments in this index with + ** levels equal to or greater than iAbsLevel. As each entry is visited, + ** updated it to set (level = -1) and (idx = N), where N is 0 for the + ** oldest segment in the range, 1 for the next oldest, and so on. + ** + ** In other words, move all segments being promoted to level -1, + ** setting the "idx" fields as appropriate to keep them in the same + ** order. The contents of level -1 (which is never used, except + ** transiently here), will be moved back to level iAbsLevel below. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + sqlite3_bind_int(pUpdate1, 1, iIdx++); + sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0)); + sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1)); + sqlite3_step(pUpdate1); + rc = sqlite3_reset(pUpdate1); + if( rc!=SQLITE_OK ){ + sqlite3_reset(pRange); + break; + } + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3_reset(pRange); + } + + /* Move level -1 to level iAbsLevel */ + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pUpdate2, 1, iAbsLevel); + sqlite3_step(pUpdate2); + rc = sqlite3_reset(pUpdate2); + } + } + } + + + return rc; +} + +/* +** Merge all level iLevel segments in the database into a single +** iLevel+1 segment. Or, if iLevel<0, merge all segments into a +** single segment with a level equal to the numerically largest level +** currently present in the database. +** +** If this function is called with iLevel<0, but there is only one +** segment in the database, SQLITE_DONE is returned immediately. +** Otherwise, if successful, SQLITE_OK is returned. If an error occurs, +** an SQLite error code is returned. +*/ +static int fts3SegmentMerge( + Fts3Table *p, + int iLangid, /* Language id to merge */ + int iIndex, /* Index in p->aIndex[] to merge */ + int iLevel /* Level to merge */ +){ + int rc; /* Return code */ + int iIdx = 0; /* Index of new segment */ + sqlite3_int64 iNewLevel = 0; /* Level/index to create new segment at */ + SegmentWriter *pWriter = 0; /* Used to write the new, merged, segment */ + Fts3SegFilter filter; /* Segment term filter condition */ + Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */ + int bIgnoreEmpty = 0; /* True to ignore empty segments */ + i64 iMaxLevel = 0; /* Max level number for this index/langid */ + + assert( iLevel==FTS3_SEGCURSOR_ALL + || iLevel==FTS3_SEGCURSOR_PENDING + || iLevel>=0 + ); + assert( iLevel=0 && iIndexnIndex ); + + rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr); + if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished; + + if( iLevel!=FTS3_SEGCURSOR_PENDING ){ + rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel); + if( rc!=SQLITE_OK ) goto finished; + } + + if( iLevel==FTS3_SEGCURSOR_ALL ){ + /* This call is to merge all segments in the database to a single + ** segment. The level of the new segment is equal to the numerically + ** greatest segment level currently present in the database for this + ** index. The idx of the new segment is always 0. */ + if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){ + rc = SQLITE_DONE; + goto finished; + } + iNewLevel = iMaxLevel; + bIgnoreEmpty = 1; + + }else{ + /* This call is to merge all segments at level iLevel. find the next + ** available segment index at level iLevel+1. The call to + ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to + ** a single iLevel+2 segment if necessary. */ + assert( FTS3_SEGCURSOR_PENDING==-1 ); + iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); + rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); + bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); + } + if( rc!=SQLITE_OK ) goto finished; + + assert( csr.nSegment>0 ); + assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); + assert( iNewLevelnLeafData); + } + } + } + + finished: + fts3SegWriterFree(pWriter); + sqlite3Fts3SegReaderFinish(&csr); + return rc; +} + + +/* +** Flush the contents of pendingTerms to level 0 segments. +*/ +SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ + int rc = SQLITE_OK; + int i; + + for(i=0; rc==SQLITE_OK && inIndex; i++){ + rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } + sqlite3Fts3PendingTermsClear(p); + + /* Determine the auto-incr-merge setting if unknown. If enabled, + ** estimate the number of leaf blocks of content to be written + */ + if( rc==SQLITE_OK && p->bHasStat + && p->nAutoincrmerge==0xff && p->nLeafAdd>0 + ){ + sqlite3_stmt *pStmt = 0; + rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); + rc = sqlite3_step(pStmt); + if( rc==SQLITE_ROW ){ + p->nAutoincrmerge = sqlite3_column_int(pStmt, 0); + if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8; + }else if( rc==SQLITE_DONE ){ + p->nAutoincrmerge = 0; + } + rc = sqlite3_reset(pStmt); + } + } + return rc; +} + +/* +** Encode N integers as varints into a blob. +*/ +static void fts3EncodeIntArray( + int N, /* The number of integers to encode */ + u32 *a, /* The integer values */ + char *zBuf, /* Write the BLOB here */ + int *pNBuf /* Write number of bytes if zBuf[] used here */ +){ + int i, j; + for(i=j=0; iiPrevDocid. The sizes are encoded as +** a blob of varints. +*/ +static void fts3InsertDocsize( + int *pRC, /* Result code */ + Fts3Table *p, /* Table into which to insert */ + u32 *aSz /* Sizes of each column, in tokens */ +){ + char *pBlob; /* The BLOB encoding of the document size */ + int nBlob; /* Number of bytes in the BLOB */ + sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ + int rc; /* Result code from subfunctions */ + + if( *pRC ) return; + pBlob = sqlite3_malloc( 10*p->nColumn ); + if( pBlob==0 ){ + *pRC = SQLITE_NOMEM; + return; + } + fts3EncodeIntArray(p->nColumn, aSz, pBlob, &nBlob); + rc = fts3SqlStmt(p, SQL_REPLACE_DOCSIZE, &pStmt, 0); + if( rc ){ + sqlite3_free(pBlob); + *pRC = rc; + return; + } + sqlite3_bind_int64(pStmt, 1, p->iPrevDocid); + sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, sqlite3_free); + sqlite3_step(pStmt); + *pRC = sqlite3_reset(pStmt); +} + +/* +** Record 0 of the %_stat table contains a blob consisting of N varints, +** where N is the number of user defined columns in the fts3 table plus +** two. If nCol is the number of user defined columns, then values of the +** varints are set as follows: +** +** Varint 0: Total number of rows in the table. +** +** Varint 1..nCol: For each column, the total number of tokens stored in +** the column for all rows of the table. +** +** Varint 1+nCol: The total size, in bytes, of all text values in all +** columns of all rows of the table. +** +*/ +static void fts3UpdateDocTotals( + int *pRC, /* The result code */ + Fts3Table *p, /* Table being updated */ + u32 *aSzIns, /* Size increases */ + u32 *aSzDel, /* Size decreases */ + int nChng /* Change in the number of documents */ +){ + char *pBlob; /* Storage for BLOB written into %_stat */ + int nBlob; /* Size of BLOB written into %_stat */ + u32 *a; /* Array of integers that becomes the BLOB */ + sqlite3_stmt *pStmt; /* Statement for reading and writing */ + int i; /* Loop counter */ + int rc; /* Result code from subfunctions */ + + const int nStat = p->nColumn+2; + + if( *pRC ) return; + a = sqlite3_malloc( (sizeof(u32)+10)*nStat ); + if( a==0 ){ + *pRC = SQLITE_NOMEM; + return; + } + pBlob = (char*)&a[nStat]; + rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); + if( rc ){ + sqlite3_free(a); + *pRC = rc; + return; + } + sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + fts3DecodeIntArray(nStat, a, + sqlite3_column_blob(pStmt, 0), + sqlite3_column_bytes(pStmt, 0)); + }else{ + memset(a, 0, sizeof(u32)*(nStat) ); + } + rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ){ + sqlite3_free(a); + *pRC = rc; + return; + } + if( nChng<0 && a[0]<(u32)(-nChng) ){ + a[0] = 0; + }else{ + a[0] += nChng; + } + for(i=0; inColumn+1; i++){ + u32 x = a[i+1]; + if( x+aSzIns[i] < aSzDel[i] ){ + x = 0; + }else{ + x = x + aSzIns[i] - aSzDel[i]; + } + a[i+1] = x; + } + fts3EncodeIntArray(nStat, a, pBlob, &nBlob); + rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); + if( rc ){ + sqlite3_free(a); + *pRC = rc; + return; + } + sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); + sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC); + sqlite3_step(pStmt); + *pRC = sqlite3_reset(pStmt); + sqlite3_free(a); +} + +/* +** Merge the entire database so that there is one segment for each +** iIndex/iLangid combination. +*/ +static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ + int bSeenDone = 0; + int rc; + sqlite3_stmt *pAllLangid = 0; + + rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); + if( rc==SQLITE_OK ){ + int rc2; + sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); + sqlite3_bind_int(pAllLangid, 2, p->nIndex); + while( sqlite3_step(pAllLangid)==SQLITE_ROW ){ + int i; + int iLangid = sqlite3_column_int(pAllLangid, 0); + for(i=0; rc==SQLITE_OK && inIndex; i++){ + rc = fts3SegmentMerge(p, iLangid, i, FTS3_SEGCURSOR_ALL); + if( rc==SQLITE_DONE ){ + bSeenDone = 1; + rc = SQLITE_OK; + } + } + } + rc2 = sqlite3_reset(pAllLangid); + if( rc==SQLITE_OK ) rc = rc2; + } + + sqlite3Fts3SegmentsClose(p); + sqlite3Fts3PendingTermsClear(p); + + return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; +} + +/* +** This function is called when the user executes the following statement: +** +** INSERT INTO () VALUES('rebuild'); +** +** The entire FTS index is discarded and rebuilt. If the table is one +** created using the content=xxx option, then the new index is based on +** the current contents of the xxx table. Otherwise, it is rebuilt based +** on the contents of the %_content table. +*/ +static int fts3DoRebuild(Fts3Table *p){ + int rc; /* Return Code */ + + rc = fts3DeleteAll(p, 0); + if( rc==SQLITE_OK ){ + u32 *aSz = 0; + u32 *aSzIns = 0; + u32 *aSzDel = 0; + sqlite3_stmt *pStmt = 0; + int nEntry = 0; + + /* Compose and prepare an SQL statement to loop through the content table */ + char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } + + if( rc==SQLITE_OK ){ + int nByte = sizeof(u32) * (p->nColumn+1)*3; + aSz = (u32 *)sqlite3_malloc(nByte); + if( aSz==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(aSz, 0, nByte); + aSzIns = &aSz[p->nColumn+1]; + aSzDel = &aSzIns[p->nColumn+1]; + } + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + int iCol; + int iLangid = langidFromSelect(p, pStmt); + rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0)); + memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); + for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ + if( p->abNotindexed[iCol]==0 ){ + const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); + rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); + aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); + } + } + if( p->bHasDocsize ){ + fts3InsertDocsize(&rc, p, aSz); + } + if( rc!=SQLITE_OK ){ + sqlite3_finalize(pStmt); + pStmt = 0; + }else{ + nEntry++; + for(iCol=0; iCol<=p->nColumn; iCol++){ + aSzIns[iCol] += aSz[iCol]; + } + } + } + if( p->bFts4 ){ + fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry); + } + sqlite3_free(aSz); + + if( pStmt ){ + int rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + + return rc; +} + + +/* +** This function opens a cursor used to read the input data for an +** incremental merge operation. Specifically, it opens a cursor to scan +** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute +** level iAbsLevel. +*/ +static int fts3IncrmergeCsr( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level to open */ + int nSeg, /* Number of segments to merge */ + Fts3MultiSegReader *pCsr /* Cursor object to populate */ +){ + int rc; /* Return Code */ + sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ + int nByte; /* Bytes allocated at pCsr->apSegment[] */ + + /* Allocate space for the Fts3MultiSegReader.aCsr[] array */ + memset(pCsr, 0, sizeof(*pCsr)); + nByte = sizeof(Fts3SegReader *) * nSeg; + pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte); + + if( pCsr->apSegment==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pCsr->apSegment, 0, nByte); + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); + } + if( rc==SQLITE_OK ){ + int i; + int rc2; + sqlite3_bind_int64(pStmt, 1, iAbsLevel); + assert( pCsr->nSegment==0 ); + for(i=0; rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW && iapSegment[i] + ); + pCsr->nSegment++; + } + rc2 = sqlite3_reset(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + } + + return rc; +} + +typedef struct IncrmergeWriter IncrmergeWriter; +typedef struct NodeWriter NodeWriter; +typedef struct Blob Blob; +typedef struct NodeReader NodeReader; + +/* +** An instance of the following structure is used as a dynamic buffer +** to build up nodes or other blobs of data in. +** +** The function blobGrowBuffer() is used to extend the allocation. +*/ +struct Blob { + char *a; /* Pointer to allocation */ + int n; /* Number of valid bytes of data in a[] */ + int nAlloc; /* Allocated size of a[] (nAlloc>=n) */ +}; + +/* +** This structure is used to build up buffers containing segment b-tree +** nodes (blocks). +*/ +struct NodeWriter { + sqlite3_int64 iBlock; /* Current block id */ + Blob key; /* Last key written to the current block */ + Blob block; /* Current block image */ +}; + +/* +** An object of this type contains the state required to create or append +** to an appendable b-tree segment. +*/ +struct IncrmergeWriter { + int nLeafEst; /* Space allocated for leaf blocks */ + int nWork; /* Number of leaf pages flushed */ + sqlite3_int64 iAbsLevel; /* Absolute level of input segments */ + int iIdx; /* Index of *output* segment in iAbsLevel+1 */ + sqlite3_int64 iStart; /* Block number of first allocated block */ + sqlite3_int64 iEnd; /* Block number of last allocated block */ + sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */ + u8 bNoLeafData; /* If true, store 0 for segment size */ + NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT]; +}; + +/* +** An object of the following type is used to read data from a single +** FTS segment node. See the following functions: +** +** nodeReaderInit() +** nodeReaderNext() +** nodeReaderRelease() +*/ +struct NodeReader { + const char *aNode; + int nNode; + int iOff; /* Current offset within aNode[] */ + + /* Output variables. Containing the current node entry. */ + sqlite3_int64 iChild; /* Pointer to child node */ + Blob term; /* Current term */ + const char *aDoclist; /* Pointer to doclist */ + int nDoclist; /* Size of doclist in bytes */ +}; + +/* +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, if the allocation at pBlob->a is not already at least nMin +** bytes in size, extend (realloc) it to be so. +** +** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a +** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc +** to reflect the new size of the pBlob->a[] buffer. +*/ +static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ + if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ + int nAlloc = nMin; + char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); + if( a ){ + pBlob->nAlloc = nAlloc; + pBlob->a = a; + }else{ + *pRc = SQLITE_NOMEM; + } + } +} + +/* +** Attempt to advance the node-reader object passed as the first argument to +** the next entry on the node. +** +** Return an error code if an error occurs (SQLITE_NOMEM is possible). +** Otherwise return SQLITE_OK. If there is no next entry on the node +** (e.g. because the current entry is the last) set NodeReader->aNode to +** NULL to indicate EOF. Otherwise, populate the NodeReader structure output +** variables for the new entry. +*/ +static int nodeReaderNext(NodeReader *p){ + int bFirst = (p->term.n==0); /* True for first term on the node */ + int nPrefix = 0; /* Bytes to copy from previous term */ + int nSuffix = 0; /* Bytes to append to the prefix */ + int rc = SQLITE_OK; /* Return code */ + + assert( p->aNode ); + if( p->iChild && bFirst==0 ) p->iChild++; + if( p->iOff>=p->nNode ){ + /* EOF */ + p->aNode = 0; + }else{ + if( bFirst==0 ){ + p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nPrefix); + } + p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); + + blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); + if( rc==SQLITE_OK ){ + memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); + p->term.n = nPrefix+nSuffix; + p->iOff += nSuffix; + if( p->iChild==0 ){ + p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist); + p->aDoclist = &p->aNode[p->iOff]; + p->iOff += p->nDoclist; + } + } + } + + assert( p->iOff<=p->nNode ); + + return rc; +} + +/* +** Release all dynamic resources held by node-reader object *p. +*/ +static void nodeReaderRelease(NodeReader *p){ + sqlite3_free(p->term.a); +} + +/* +** Initialize a node-reader object to read the node in buffer aNode/nNode. +** +** If successful, SQLITE_OK is returned and the NodeReader object set to +** point to the first entry on the node (if any). Otherwise, an SQLite +** error code is returned. +*/ +static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){ + memset(p, 0, sizeof(NodeReader)); + p->aNode = aNode; + p->nNode = nNode; + + /* Figure out if this is a leaf or an internal node. */ + if( p->aNode[0] ){ + /* An internal node. */ + p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild); + }else{ + p->iOff = 1; + } + + return nodeReaderNext(p); +} + +/* +** This function is called while writing an FTS segment each time a leaf o +** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed +** to be greater than the largest key on the node just written, but smaller +** than or equal to the first key that will be written to the next leaf +** node. +** +** The block id of the leaf node just written to disk may be found in +** (pWriter->aNodeWriter[0].iBlock) when this function is called. +*/ +static int fts3IncrmergePush( + Fts3Table *p, /* Fts3 table handle */ + IncrmergeWriter *pWriter, /* Writer object */ + const char *zTerm, /* Term to write to internal node */ + int nTerm /* Bytes at zTerm */ +){ + sqlite3_int64 iPtr = pWriter->aNodeWriter[0].iBlock; + int iLayer; + + assert( nTerm>0 ); + for(iLayer=1; ALWAYS(iLayeraNodeWriter[iLayer]; + int rc = SQLITE_OK; + int nPrefix; + int nSuffix; + int nSpace; + + /* Figure out how much space the key will consume if it is written to + ** the current node of layer iLayer. Due to the prefix compression, + ** the space required changes depending on which node the key is to + ** be added to. */ + nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm); + nSuffix = nTerm - nPrefix; + nSpace = sqlite3Fts3VarintLen(nPrefix); + nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; + + if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){ + /* If the current node of layer iLayer contains zero keys, or if adding + ** the key to it will not cause it to grow to larger than nNodeSize + ** bytes in size, write the key here. */ + + Blob *pBlk = &pNode->block; + if( pBlk->n==0 ){ + blobGrowBuffer(pBlk, p->nNodeSize, &rc); + if( rc==SQLITE_OK ){ + pBlk->a[0] = (char)iLayer; + pBlk->n = 1 + sqlite3Fts3PutVarint(&pBlk->a[1], iPtr); + } + } + blobGrowBuffer(pBlk, pBlk->n + nSpace, &rc); + blobGrowBuffer(&pNode->key, nTerm, &rc); + + if( rc==SQLITE_OK ){ + if( pNode->key.n ){ + pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix); + } + pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix); + memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix); + pBlk->n += nSuffix; + + memcpy(pNode->key.a, zTerm, nTerm); + pNode->key.n = nTerm; + } + }else{ + /* Otherwise, flush the current node of layer iLayer to disk. + ** Then allocate a new, empty sibling node. The key will be written + ** into the parent of this node. */ + rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); + + assert( pNode->block.nAlloc>=p->nNodeSize ); + pNode->block.a[0] = (char)iLayer; + pNode->block.n = 1 + sqlite3Fts3PutVarint(&pNode->block.a[1], iPtr+1); + + iNextPtr = pNode->iBlock; + pNode->iBlock++; + pNode->key.n = 0; + } + + if( rc!=SQLITE_OK || iNextPtr==0 ) return rc; + iPtr = iNextPtr; + } + + assert( 0 ); + return 0; +} + +/* +** Append a term and (optionally) doclist to the FTS segment node currently +** stored in blob *pNode. The node need not contain any terms, but the +** header must be written before this function is called. +** +** A node header is a single 0x00 byte for a leaf node, or a height varint +** followed by the left-hand-child varint for an internal node. +** +** The term to be appended is passed via arguments zTerm/nTerm. For a +** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal +** node, both aDoclist and nDoclist must be passed 0. +** +** If the size of the value in blob pPrev is zero, then this is the first +** term written to the node. Otherwise, pPrev contains a copy of the +** previous term. Before this function returns, it is updated to contain a +** copy of zTerm/nTerm. +** +** It is assumed that the buffer associated with pNode is already large +** enough to accommodate the new entry. The buffer associated with pPrev +** is extended by this function if requrired. +** +** If an error (i.e. OOM condition) occurs, an SQLite error code is +** returned. Otherwise, SQLITE_OK. +*/ +static int fts3AppendToNode( + Blob *pNode, /* Current node image to append to */ + Blob *pPrev, /* Buffer containing previous term written */ + const char *zTerm, /* New term to write */ + int nTerm, /* Size of zTerm in bytes */ + const char *aDoclist, /* Doclist (or NULL) to write */ + int nDoclist /* Size of aDoclist in bytes */ +){ + int rc = SQLITE_OK; /* Return code */ + int bFirst = (pPrev->n==0); /* True if this is the first term written */ + int nPrefix; /* Size of term prefix in bytes */ + int nSuffix; /* Size of term suffix in bytes */ + + /* Node must have already been started. There must be a doclist for a + ** leaf node, and there must not be a doclist for an internal node. */ + assert( pNode->n>0 ); + assert( (pNode->a[0]=='\0')==(aDoclist!=0) ); + + blobGrowBuffer(pPrev, nTerm, &rc); + if( rc!=SQLITE_OK ) return rc; + + nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm); + nSuffix = nTerm - nPrefix; + memcpy(pPrev->a, zTerm, nTerm); + pPrev->n = nTerm; + + if( bFirst==0 ){ + pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nPrefix); + } + pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nSuffix); + memcpy(&pNode->a[pNode->n], &zTerm[nPrefix], nSuffix); + pNode->n += nSuffix; + + if( aDoclist ){ + pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nDoclist); + memcpy(&pNode->a[pNode->n], aDoclist, nDoclist); + pNode->n += nDoclist; + } + + assert( pNode->n<=pNode->nAlloc ); + + return SQLITE_OK; +} + +/* +** Append the current term and doclist pointed to by cursor pCsr to the +** appendable b-tree segment opened for writing by pWriter. +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. +*/ +static int fts3IncrmergeAppend( + Fts3Table *p, /* Fts3 table handle */ + IncrmergeWriter *pWriter, /* Writer object */ + Fts3MultiSegReader *pCsr /* Cursor containing term and doclist */ +){ + const char *zTerm = pCsr->zTerm; + int nTerm = pCsr->nTerm; + const char *aDoclist = pCsr->aDoclist; + int nDoclist = pCsr->nDoclist; + int rc = SQLITE_OK; /* Return code */ + int nSpace; /* Total space in bytes required on leaf */ + int nPrefix; /* Size of prefix shared with previous term */ + int nSuffix; /* Size of suffix (nTerm - nPrefix) */ + NodeWriter *pLeaf; /* Object used to write leaf nodes */ + + pLeaf = &pWriter->aNodeWriter[0]; + nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm); + nSuffix = nTerm - nPrefix; + + nSpace = sqlite3Fts3VarintLen(nPrefix); + nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; + nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; + + /* If the current block is not empty, and if adding this term/doclist + ** to the current block would make it larger than Fts3Table.nNodeSize + ** bytes, write this block out to the database. */ + if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){ + rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n); + pWriter->nWork++; + + /* Add the current term to the parent node. The term added to the + ** parent must: + ** + ** a) be greater than the largest term on the leaf node just written + ** to the database (still available in pLeaf->key), and + ** + ** b) be less than or equal to the term about to be added to the new + ** leaf node (zTerm/nTerm). + ** + ** In other words, it must be the prefix of zTerm 1 byte longer than + ** the common prefix (if any) of zTerm and pWriter->zTerm. + */ + if( rc==SQLITE_OK ){ + rc = fts3IncrmergePush(p, pWriter, zTerm, nPrefix+1); + } + + /* Advance to the next output block */ + pLeaf->iBlock++; + pLeaf->key.n = 0; + pLeaf->block.n = 0; + + nSuffix = nTerm; + nSpace = 1; + nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; + nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; + } + + pWriter->nLeafData += nSpace; + blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc); + if( rc==SQLITE_OK ){ + if( pLeaf->block.n==0 ){ + pLeaf->block.n = 1; + pLeaf->block.a[0] = '\0'; + } + rc = fts3AppendToNode( + &pLeaf->block, &pLeaf->key, zTerm, nTerm, aDoclist, nDoclist + ); + } + + return rc; +} + +/* +** This function is called to release all dynamic resources held by the +** merge-writer object pWriter, and if no error has occurred, to flush +** all outstanding node buffers held by pWriter to disk. +** +** If *pRc is not SQLITE_OK when this function is called, then no attempt +** is made to write any data to disk. Instead, this function serves only +** to release outstanding resources. +** +** Otherwise, if *pRc is initially SQLITE_OK and an error occurs while +** flushing buffers to disk, *pRc is set to an SQLite error code before +** returning. +*/ +static void fts3IncrmergeRelease( + Fts3Table *p, /* FTS3 table handle */ + IncrmergeWriter *pWriter, /* Merge-writer object */ + int *pRc /* IN/OUT: Error code */ +){ + int i; /* Used to iterate through non-root layers */ + int iRoot; /* Index of root in pWriter->aNodeWriter */ + NodeWriter *pRoot; /* NodeWriter for root node */ + int rc = *pRc; /* Error code */ + + /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment + ** root node. If the segment fits entirely on a single leaf node, iRoot + ** will be set to 0. If the root node is the parent of the leaves, iRoot + ** will be 1. And so on. */ + for(iRoot=FTS_MAX_APPENDABLE_HEIGHT-1; iRoot>=0; iRoot--){ + NodeWriter *pNode = &pWriter->aNodeWriter[iRoot]; + if( pNode->block.n>0 ) break; + assert( *pRc || pNode->block.nAlloc==0 ); + assert( *pRc || pNode->key.nAlloc==0 ); + sqlite3_free(pNode->block.a); + sqlite3_free(pNode->key.a); + } + + /* Empty output segment. This is a no-op. */ + if( iRoot<0 ) return; + + /* The entire output segment fits on a single node. Normally, this means + ** the node would be stored as a blob in the "root" column of the %_segdir + ** table. However, this is not permitted in this case. The problem is that + ** space has already been reserved in the %_segments table, and so the + ** start_block and end_block fields of the %_segdir table must be populated. + ** And, by design or by accident, released versions of FTS cannot handle + ** segments that fit entirely on the root node with start_block!=0. + ** + ** Instead, create a synthetic root node that contains nothing but a + ** pointer to the single content node. So that the segment consists of a + ** single leaf and a single interior (root) node. + ** + ** Todo: Better might be to defer allocating space in the %_segments + ** table until we are sure it is needed. + */ + if( iRoot==0 ){ + Blob *pBlock = &pWriter->aNodeWriter[1].block; + blobGrowBuffer(pBlock, 1 + FTS3_VARINT_MAX, &rc); + if( rc==SQLITE_OK ){ + pBlock->a[0] = 0x01; + pBlock->n = 1 + sqlite3Fts3PutVarint( + &pBlock->a[1], pWriter->aNodeWriter[0].iBlock + ); + } + iRoot = 1; + } + pRoot = &pWriter->aNodeWriter[iRoot]; + + /* Flush all currently outstanding nodes to disk. */ + for(i=0; iaNodeWriter[i]; + if( pNode->block.n>0 && rc==SQLITE_OK ){ + rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); + } + sqlite3_free(pNode->block.a); + sqlite3_free(pNode->key.a); + } + + /* Write the %_segdir record. */ + if( rc==SQLITE_OK ){ + rc = fts3WriteSegdir(p, + pWriter->iAbsLevel+1, /* level */ + pWriter->iIdx, /* idx */ + pWriter->iStart, /* start_block */ + pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */ + pWriter->iEnd, /* end_block */ + (pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */ + pRoot->block.a, pRoot->block.n /* root */ + ); + } + sqlite3_free(pRoot->block.a); + sqlite3_free(pRoot->key.a); + + *pRc = rc; +} + +/* +** Compare the term in buffer zLhs (size in bytes nLhs) with that in +** zRhs (size in bytes nRhs) using memcmp. If one term is a prefix of +** the other, it is considered to be smaller than the other. +** +** Return -ve if zLhs is smaller than zRhs, 0 if it is equal, or +ve +** if it is greater. +*/ +static int fts3TermCmp( + const char *zLhs, int nLhs, /* LHS of comparison */ + const char *zRhs, int nRhs /* RHS of comparison */ +){ + int nCmp = MIN(nLhs, nRhs); + int res; + + res = memcmp(zLhs, zRhs, nCmp); + if( res==0 ) res = nLhs - nRhs; + + return res; +} + + +/* +** Query to see if the entry in the %_segments table with blockid iEnd is +** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before +** returning. Otherwise, set *pbRes to 0. +** +** Or, if an error occurs while querying the database, return an SQLite +** error code. The final value of *pbRes is undefined in this case. +** +** This is used to test if a segment is an "appendable" segment. If it +** is, then a NULL entry has been inserted into the %_segments table +** with blockid %_segdir.end_block. +*/ +static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){ + int bRes = 0; /* Result to set *pbRes to */ + sqlite3_stmt *pCheck = 0; /* Statement to query database with */ + int rc; /* Return code */ + + rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pCheck, 1, iEnd); + if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1; + rc = sqlite3_reset(pCheck); + } + + *pbRes = bRes; + return rc; +} + +/* +** This function is called when initializing an incremental-merge operation. +** It checks if the existing segment with index value iIdx at absolute level +** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the +** merge-writer object *pWriter is initialized to write to it. +** +** An existing segment can be appended to by an incremental merge if: +** +** * It was initially created as an appendable segment (with all required +** space pre-allocated), and +** +** * The first key read from the input (arguments zKey and nKey) is +** greater than the largest key currently stored in the potential +** output segment. +*/ +static int fts3IncrmergeLoad( + Fts3Table *p, /* Fts3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ + int iIdx, /* Index of candidate output segment */ + const char *zKey, /* First key to write */ + int nKey, /* Number of bytes in nKey */ + IncrmergeWriter *pWriter /* Populate this object */ +){ + int rc; /* Return code */ + sqlite3_stmt *pSelect = 0; /* SELECT to read %_segdir entry */ + + rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pSelect, 0); + if( rc==SQLITE_OK ){ + sqlite3_int64 iStart = 0; /* Value of %_segdir.start_block */ + sqlite3_int64 iLeafEnd = 0; /* Value of %_segdir.leaves_end_block */ + sqlite3_int64 iEnd = 0; /* Value of %_segdir.end_block */ + const char *aRoot = 0; /* Pointer to %_segdir.root buffer */ + int nRoot = 0; /* Size of aRoot[] in bytes */ + int rc2; /* Return code from sqlite3_reset() */ + int bAppendable = 0; /* Set to true if segment is appendable */ + + /* Read the %_segdir entry for index iIdx absolute level (iAbsLevel+1) */ + sqlite3_bind_int64(pSelect, 1, iAbsLevel+1); + sqlite3_bind_int(pSelect, 2, iIdx); + if( sqlite3_step(pSelect)==SQLITE_ROW ){ + iStart = sqlite3_column_int64(pSelect, 1); + iLeafEnd = sqlite3_column_int64(pSelect, 2); + fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); + if( pWriter->nLeafData<0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } + pWriter->bNoLeafData = (pWriter->nLeafData==0); + nRoot = sqlite3_column_bytes(pSelect, 4); + aRoot = sqlite3_column_blob(pSelect, 4); + }else{ + return sqlite3_reset(pSelect); + } + + /* Check for the zero-length marker in the %_segments table */ + rc = fts3IsAppendable(p, iEnd, &bAppendable); + + /* Check that zKey/nKey is larger than the largest key the candidate */ + if( rc==SQLITE_OK && bAppendable ){ + char *aLeaf = 0; + int nLeaf = 0; + + rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0); + if( rc==SQLITE_OK ){ + NodeReader reader; + for(rc = nodeReaderInit(&reader, aLeaf, nLeaf); + rc==SQLITE_OK && reader.aNode; + rc = nodeReaderNext(&reader) + ){ + assert( reader.aNode ); + } + if( fts3TermCmp(zKey, nKey, reader.term.a, reader.term.n)<=0 ){ + bAppendable = 0; + } + nodeReaderRelease(&reader); + } + sqlite3_free(aLeaf); + } + + if( rc==SQLITE_OK && bAppendable ){ + /* It is possible to append to this segment. Set up the IncrmergeWriter + ** object to do so. */ + int i; + int nHeight = (int)aRoot[0]; + NodeWriter *pNode; + + pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; + pWriter->iStart = iStart; + pWriter->iEnd = iEnd; + pWriter->iAbsLevel = iAbsLevel; + pWriter->iIdx = iIdx; + + for(i=nHeight+1; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; + } + + pNode = &pWriter->aNodeWriter[nHeight]; + pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; + blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc); + if( rc==SQLITE_OK ){ + memcpy(pNode->block.a, aRoot, nRoot); + pNode->block.n = nRoot; + } + + for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ + NodeReader reader; + pNode = &pWriter->aNodeWriter[i]; + + rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); + while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); + blobGrowBuffer(&pNode->key, reader.term.n, &rc); + if( rc==SQLITE_OK ){ + memcpy(pNode->key.a, reader.term.a, reader.term.n); + pNode->key.n = reader.term.n; + if( i>0 ){ + char *aBlock = 0; + int nBlock = 0; + pNode = &pWriter->aNodeWriter[i-1]; + pNode->iBlock = reader.iChild; + rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0); + blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc); + if( rc==SQLITE_OK ){ + memcpy(pNode->block.a, aBlock, nBlock); + pNode->block.n = nBlock; + } + sqlite3_free(aBlock); + } + } + nodeReaderRelease(&reader); + } + } + + rc2 = sqlite3_reset(pSelect); + if( rc==SQLITE_OK ) rc = rc2; + } + + return rc; +} + +/* +** Determine the largest segment index value that exists within absolute +** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus +** one before returning SQLITE_OK. Or, if there are no segments at all +** within level iAbsLevel, set *piIdx to zero. +** +** If an error occurs, return an SQLite error code. The final value of +** *piIdx is undefined in this case. +*/ +static int fts3IncrmergeOutputIdx( + Fts3Table *p, /* FTS Table handle */ + sqlite3_int64 iAbsLevel, /* Absolute index of input segments */ + int *piIdx /* OUT: Next free index at iAbsLevel+1 */ +){ + int rc; + sqlite3_stmt *pOutputIdx = 0; /* SQL used to find output index */ + + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pOutputIdx, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pOutputIdx, 1, iAbsLevel+1); + sqlite3_step(pOutputIdx); + *piIdx = sqlite3_column_int(pOutputIdx, 0); + rc = sqlite3_reset(pOutputIdx); + } + + return rc; +} + +/* +** Allocate an appendable output segment on absolute level iAbsLevel+1 +** with idx value iIdx. +** +** In the %_segdir table, a segment is defined by the values in three +** columns: +** +** start_block +** leaves_end_block +** end_block +** +** When an appendable segment is allocated, it is estimated that the +** maximum number of leaf blocks that may be required is the sum of the +** number of leaf blocks consumed by the input segments, plus the number +** of input segments, multiplied by two. This value is stored in stack +** variable nLeafEst. +** +** A total of 16*nLeafEst blocks are allocated when an appendable segment +** is created ((1 + end_block - start_block)==16*nLeafEst). The contiguous +** array of leaf nodes starts at the first block allocated. The array +** of interior nodes that are parents of the leaf nodes start at block +** (start_block + (1 + end_block - start_block) / 16). And so on. +** +** In the actual code below, the value "16" is replaced with the +** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT. +*/ +static int fts3IncrmergeWriter( + Fts3Table *p, /* Fts3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ + int iIdx, /* Index of new output segment */ + Fts3MultiSegReader *pCsr, /* Cursor that data will be read from */ + IncrmergeWriter *pWriter /* Populate this object */ +){ + int rc; /* Return Code */ + int i; /* Iterator variable */ + int nLeafEst = 0; /* Blocks allocated for leaf nodes */ + sqlite3_stmt *pLeafEst = 0; /* SQL used to determine nLeafEst */ + sqlite3_stmt *pFirstBlock = 0; /* SQL used to determine first block */ + + /* Calculate nLeafEst. */ + rc = fts3SqlStmt(p, SQL_MAX_LEAF_NODE_ESTIMATE, &pLeafEst, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pLeafEst, 1, iAbsLevel); + sqlite3_bind_int64(pLeafEst, 2, pCsr->nSegment); + if( SQLITE_ROW==sqlite3_step(pLeafEst) ){ + nLeafEst = sqlite3_column_int(pLeafEst, 0); + } + rc = sqlite3_reset(pLeafEst); + } + if( rc!=SQLITE_OK ) return rc; + + /* Calculate the first block to use in the output segment */ + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pFirstBlock, 0); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pFirstBlock) ){ + pWriter->iStart = sqlite3_column_int64(pFirstBlock, 0); + pWriter->iEnd = pWriter->iStart - 1; + pWriter->iEnd += nLeafEst * FTS_MAX_APPENDABLE_HEIGHT; + } + rc = sqlite3_reset(pFirstBlock); + } + if( rc!=SQLITE_OK ) return rc; + + /* Insert the marker in the %_segments table to make sure nobody tries + ** to steal the space just allocated. This is also used to identify + ** appendable segments. */ + rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0); + if( rc!=SQLITE_OK ) return rc; + + pWriter->iAbsLevel = iAbsLevel; + pWriter->nLeafEst = nLeafEst; + pWriter->iIdx = iIdx; + + /* Set up the array of NodeWriter objects */ + for(i=0; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; + } + return SQLITE_OK; +} + +/* +** Remove an entry from the %_segdir table. This involves running the +** following two statements: +** +** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx +** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx +** +** The DELETE statement removes the specific %_segdir level. The UPDATE +** statement ensures that the remaining segments have contiguously allocated +** idx values. +*/ +static int fts3RemoveSegdirEntry( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level to delete from */ + int iIdx /* Index of %_segdir entry to delete */ +){ + int rc; /* Return code */ + sqlite3_stmt *pDelete = 0; /* DELETE statement */ + + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_ENTRY, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDelete, 1, iAbsLevel); + sqlite3_bind_int(pDelete, 2, iIdx); + sqlite3_step(pDelete); + rc = sqlite3_reset(pDelete); + } + + return rc; +} + +/* +** One or more segments have just been removed from absolute level iAbsLevel. +** Update the 'idx' values of the remaining segments in the level so that +** the idx values are a contiguous sequence starting from 0. +*/ +static int fts3RepackSegdirLevel( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel /* Absolute level to repack */ +){ + int rc; /* Return code */ + int *aIdx = 0; /* Array of remaining idx values */ + int nIdx = 0; /* Valid entries in aIdx[] */ + int nAlloc = 0; /* Allocated size of aIdx[] */ + int i; /* Iterator variable */ + sqlite3_stmt *pSelect = 0; /* Select statement to read idx values */ + sqlite3_stmt *pUpdate = 0; /* Update statement to modify idx values */ + + rc = fts3SqlStmt(p, SQL_SELECT_INDEXES, &pSelect, 0); + if( rc==SQLITE_OK ){ + int rc2; + sqlite3_bind_int64(pSelect, 1, iAbsLevel); + while( SQLITE_ROW==sqlite3_step(pSelect) ){ + if( nIdx>=nAlloc ){ + int *aNew; + nAlloc += 16; + aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); + if( !aNew ){ + rc = SQLITE_NOMEM; + break; + } + aIdx = aNew; + } + aIdx[nIdx++] = sqlite3_column_int(pSelect, 0); + } + rc2 = sqlite3_reset(pSelect); + if( rc==SQLITE_OK ) rc = rc2; + } + + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_SHIFT_SEGDIR_ENTRY, &pUpdate, 0); + } + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pUpdate, 2, iAbsLevel); + } + + assert( p->bIgnoreSavepoint==0 ); + p->bIgnoreSavepoint = 1; + for(i=0; rc==SQLITE_OK && ibIgnoreSavepoint = 0; + + sqlite3_free(aIdx); + return rc; +} + +static void fts3StartNode(Blob *pNode, int iHeight, sqlite3_int64 iChild){ + pNode->a[0] = (char)iHeight; + if( iChild ){ + assert( pNode->nAlloc>=1+sqlite3Fts3VarintLen(iChild) ); + pNode->n = 1 + sqlite3Fts3PutVarint(&pNode->a[1], iChild); + }else{ + assert( pNode->nAlloc>=1 ); + pNode->n = 1; + } +} + +/* +** The first two arguments are a pointer to and the size of a segment b-tree +** node. The node may be a leaf or an internal node. +** +** This function creates a new node image in blob object *pNew by copying +** all terms that are greater than or equal to zTerm/nTerm (for leaf nodes) +** or greater than zTerm/nTerm (for internal nodes) from aNode/nNode. +*/ +static int fts3TruncateNode( + const char *aNode, /* Current node image */ + int nNode, /* Size of aNode in bytes */ + Blob *pNew, /* OUT: Write new node image here */ + const char *zTerm, /* Omit all terms smaller than this */ + int nTerm, /* Size of zTerm in bytes */ + sqlite3_int64 *piBlock /* OUT: Block number in next layer down */ +){ + NodeReader reader; /* Reader object */ + Blob prev = {0, 0, 0}; /* Previous term written to new node */ + int rc = SQLITE_OK; /* Return code */ + int bLeaf = aNode[0]=='\0'; /* True for a leaf node */ + + /* Allocate required output space */ + blobGrowBuffer(pNew, nNode, &rc); + if( rc!=SQLITE_OK ) return rc; + pNew->n = 0; + + /* Populate new node buffer */ + for(rc = nodeReaderInit(&reader, aNode, nNode); + rc==SQLITE_OK && reader.aNode; + rc = nodeReaderNext(&reader) + ){ + if( pNew->n==0 ){ + int res = fts3TermCmp(reader.term.a, reader.term.n, zTerm, nTerm); + if( res<0 || (bLeaf==0 && res==0) ) continue; + fts3StartNode(pNew, (int)aNode[0], reader.iChild); + *piBlock = reader.iChild; + } + rc = fts3AppendToNode( + pNew, &prev, reader.term.a, reader.term.n, + reader.aDoclist, reader.nDoclist + ); + if( rc!=SQLITE_OK ) break; + } + if( pNew->n==0 ){ + fts3StartNode(pNew, (int)aNode[0], reader.iChild); + *piBlock = reader.iChild; + } + assert( pNew->n<=pNew->nAlloc ); + + nodeReaderRelease(&reader); + sqlite3_free(prev.a); + return rc; +} + +/* +** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute +** level iAbsLevel. This may involve deleting entries from the %_segments +** table, and modifying existing entries in both the %_segments and %_segdir +** tables. +** +** SQLITE_OK is returned if the segment is updated successfully. Or an +** SQLite error code otherwise. +*/ +static int fts3TruncateSegment( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level of segment to modify */ + int iIdx, /* Index within level of segment to modify */ + const char *zTerm, /* Remove terms smaller than this */ + int nTerm /* Number of bytes in buffer zTerm */ +){ + int rc = SQLITE_OK; /* Return code */ + Blob root = {0,0,0}; /* New root page image */ + Blob block = {0,0,0}; /* Buffer used for any other block */ + sqlite3_int64 iBlock = 0; /* Block id */ + sqlite3_int64 iNewStart = 0; /* New value for iStartBlock */ + sqlite3_int64 iOldStart = 0; /* Old value for iStartBlock */ + sqlite3_stmt *pFetch = 0; /* Statement used to fetch segdir */ + + rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pFetch, 0); + if( rc==SQLITE_OK ){ + int rc2; /* sqlite3_reset() return code */ + sqlite3_bind_int64(pFetch, 1, iAbsLevel); + sqlite3_bind_int(pFetch, 2, iIdx); + if( SQLITE_ROW==sqlite3_step(pFetch) ){ + const char *aRoot = sqlite3_column_blob(pFetch, 4); + int nRoot = sqlite3_column_bytes(pFetch, 4); + iOldStart = sqlite3_column_int64(pFetch, 1); + rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock); + } + rc2 = sqlite3_reset(pFetch); + if( rc==SQLITE_OK ) rc = rc2; + } + + while( rc==SQLITE_OK && iBlock ){ + char *aBlock = 0; + int nBlock = 0; + iNewStart = iBlock; + + rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0); + if( rc==SQLITE_OK ){ + rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock); + } + if( rc==SQLITE_OK ){ + rc = fts3WriteSegment(p, iNewStart, block.a, block.n); + } + sqlite3_free(aBlock); + } + + /* Variable iNewStart now contains the first valid leaf node. */ + if( rc==SQLITE_OK && iNewStart ){ + sqlite3_stmt *pDel = 0; + rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDel, 1, iOldStart); + sqlite3_bind_int64(pDel, 2, iNewStart-1); + sqlite3_step(pDel); + rc = sqlite3_reset(pDel); + } + } + + if( rc==SQLITE_OK ){ + sqlite3_stmt *pChomp = 0; + rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pChomp, 1, iNewStart); + sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC); + sqlite3_bind_int64(pChomp, 3, iAbsLevel); + sqlite3_bind_int(pChomp, 4, iIdx); + sqlite3_step(pChomp); + rc = sqlite3_reset(pChomp); + } + } + + sqlite3_free(root.a); + sqlite3_free(block.a); + return rc; +} + +/* +** This function is called after an incrmental-merge operation has run to +** merge (or partially merge) two or more segments from absolute level +** iAbsLevel. +** +** Each input segment is either removed from the db completely (if all of +** its data was copied to the output segment by the incrmerge operation) +** or modified in place so that it no longer contains those entries that +** have been duplicated in the output segment. +*/ +static int fts3IncrmergeChomp( + Fts3Table *p, /* FTS table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level containing segments */ + Fts3MultiSegReader *pCsr, /* Chomp all segments opened by this cursor */ + int *pnRem /* Number of segments not deleted */ +){ + int i; + int nRem = 0; + int rc = SQLITE_OK; + + for(i=pCsr->nSegment-1; i>=0 && rc==SQLITE_OK; i--){ + Fts3SegReader *pSeg = 0; + int j; + + /* Find the Fts3SegReader object with Fts3SegReader.iIdx==i. It is hiding + ** somewhere in the pCsr->apSegment[] array. */ + for(j=0; ALWAYS(jnSegment); j++){ + pSeg = pCsr->apSegment[j]; + if( pSeg->iIdx==i ) break; + } + assert( jnSegment && pSeg->iIdx==i ); + + if( pSeg->aNode==0 ){ + /* Seg-reader is at EOF. Remove the entire input segment. */ + rc = fts3DeleteSegment(p, pSeg); + if( rc==SQLITE_OK ){ + rc = fts3RemoveSegdirEntry(p, iAbsLevel, pSeg->iIdx); + } + *pnRem = 0; + }else{ + /* The incremental merge did not copy all the data from this + ** segment to the upper level. The segment is modified in place + ** so that it contains no keys smaller than zTerm/nTerm. */ + const char *zTerm = pSeg->zTerm; + int nTerm = pSeg->nTerm; + rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm); + nRem++; + } + } + + if( rc==SQLITE_OK && nRem!=pCsr->nSegment ){ + rc = fts3RepackSegdirLevel(p, iAbsLevel); + } + + *pnRem = nRem; + return rc; +} + +/* +** Store an incr-merge hint in the database. +*/ +static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){ + sqlite3_stmt *pReplace = 0; + int rc; /* Return code */ + + rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT); + sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + } + + return rc; +} + +/* +** Load an incr-merge hint from the database. The incr-merge hint, if one +** exists, is stored in the rowid==1 row of the %_stat table. +** +** If successful, populate blob *pHint with the value read from the %_stat +** table and return SQLITE_OK. Otherwise, if an error occurs, return an +** SQLite error code. +*/ +static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){ + sqlite3_stmt *pSelect = 0; + int rc; + + pHint->n = 0; + rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pSelect, 0); + if( rc==SQLITE_OK ){ + int rc2; + sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT); + if( SQLITE_ROW==sqlite3_step(pSelect) ){ + const char *aHint = sqlite3_column_blob(pSelect, 0); + int nHint = sqlite3_column_bytes(pSelect, 0); + if( aHint ){ + blobGrowBuffer(pHint, nHint, &rc); + if( rc==SQLITE_OK ){ + memcpy(pHint->a, aHint, nHint); + pHint->n = nHint; + } + } + } + rc2 = sqlite3_reset(pSelect); + if( rc==SQLITE_OK ) rc = rc2; + } + + return rc; +} + +/* +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, append an entry to the hint stored in blob *pHint. Each entry +** consists of two varints, the absolute level number of the input segments +** and the number of input segments. +** +** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs, +** set *pRc to an SQLite error code before returning. +*/ +static void fts3IncrmergeHintPush( + Blob *pHint, /* Hint blob to append to */ + i64 iAbsLevel, /* First varint to store in hint */ + int nInput, /* Second varint to store in hint */ + int *pRc /* IN/OUT: Error code */ +){ + blobGrowBuffer(pHint, pHint->n + 2*FTS3_VARINT_MAX, pRc); + if( *pRc==SQLITE_OK ){ + pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], iAbsLevel); + pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], (i64)nInput); + } +} + +/* +** Read the last entry (most recently pushed) from the hint blob *pHint +** and then remove the entry. Write the two values read to *piAbsLevel and +** *pnInput before returning. +** +** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does +** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB. +*/ +static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ + const int nHint = pHint->n; + int i; + + i = pHint->n-2; + while( i>0 && (pHint->a[i-1] & 0x80) ) i--; + while( i>0 && (pHint->a[i-1] & 0x80) ) i--; + + pHint->n = i; + i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel); + i += fts3GetVarint32(&pHint->a[i], pnInput); + if( i!=nHint ) return FTS_CORRUPT_VTAB; + + return SQLITE_OK; +} + + +/* +** Attempt an incremental merge that writes nMerge leaf blocks. +** +** Incremental merges happen nMin segments at a time. The segments +** to be merged are the nMin oldest segments (the ones with the smallest +** values for the _segdir.idx field) in the highest level that contains +** at least nMin segments. Multiple merges might occur in an attempt to +** write the quota of nMerge leaf blocks. +*/ +SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ + int rc; /* Return code */ + int nRem = nMerge; /* Number of leaf pages yet to be written */ + Fts3MultiSegReader *pCsr; /* Cursor used to read input data */ + Fts3SegFilter *pFilter; /* Filter used with cursor pCsr */ + IncrmergeWriter *pWriter; /* Writer object */ + int nSeg = 0; /* Number of input segments */ + sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */ + Blob hint = {0, 0, 0}; /* Hint read from %_stat table */ + int bDirtyHint = 0; /* True if blob 'hint' has been modified */ + + /* Allocate space for the cursor, filter and writer objects */ + const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); + pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); + if( !pWriter ) return SQLITE_NOMEM; + pFilter = (Fts3SegFilter *)&pWriter[1]; + pCsr = (Fts3MultiSegReader *)&pFilter[1]; + + rc = fts3IncrmergeHintLoad(p, &hint); + while( rc==SQLITE_OK && nRem>0 ){ + const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; + sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */ + int bUseHint = 0; /* True if attempting to append */ + int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ + + /* Search the %_segdir table for the absolute level with the smallest + ** relative level number that contains at least nMin segments, if any. + ** If one is found, set iAbsLevel to the absolute level number and + ** nSeg to nMin. If no level with at least nMin segments can be found, + ** set nSeg to -1. + */ + rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0); + sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin)); + if( sqlite3_step(pFindLevel)==SQLITE_ROW ){ + iAbsLevel = sqlite3_column_int64(pFindLevel, 0); + nSeg = sqlite3_column_int(pFindLevel, 1); + assert( nSeg>=2 ); + }else{ + nSeg = -1; + } + rc = sqlite3_reset(pFindLevel); + + /* If the hint read from the %_stat table is not empty, check if the + ** last entry in it specifies a relative level smaller than or equal + ** to the level identified by the block above (if any). If so, this + ** iteration of the loop will work on merging at the hinted level. + */ + if( rc==SQLITE_OK && hint.n ){ + int nHint = hint.n; + sqlite3_int64 iHintAbsLevel = 0; /* Hint level */ + int nHintSeg = 0; /* Hint number of segments */ + + rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg); + if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){ + iAbsLevel = iHintAbsLevel; + nSeg = nHintSeg; + bUseHint = 1; + bDirtyHint = 1; + }else{ + /* This undoes the effect of the HintPop() above - so that no entry + ** is removed from the hint blob. */ + hint.n = nHint; + } + } + + /* If nSeg is less that zero, then there is no level with at least + ** nMin segments and no hint in the %_stat table. No work to do. + ** Exit early in this case. */ + if( nSeg<0 ) break; + + /* Open a cursor to iterate through the contents of the oldest nSeg + ** indexes of absolute level iAbsLevel. If this cursor is opened using + ** the 'hint' parameters, it is possible that there are less than nSeg + ** segments available in level iAbsLevel. In this case, no work is + ** done on iAbsLevel - fall through to the next iteration of the loop + ** to start work on some other level. */ + memset(pWriter, 0, nAlloc); + pFilter->flags = FTS3_SEGMENT_REQUIRE_POS; + + if( rc==SQLITE_OK ){ + rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); + assert( bUseHint==1 || bUseHint==0 ); + if( iIdx==0 || (bUseHint && iIdx==1) ){ + int bIgnore = 0; + rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore); + if( bIgnore ){ + pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY; + } + } + } + + if( rc==SQLITE_OK ){ + rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); + } + if( SQLITE_OK==rc && pCsr->nSegment==nSeg + && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) + && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr)) + ){ + if( bUseHint && iIdx>0 ){ + const char *zKey = pCsr->zTerm; + int nKey = pCsr->nTerm; + rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); + }else{ + rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); + } + + if( rc==SQLITE_OK && pWriter->nLeafEst ){ + fts3LogMerge(nSeg, iAbsLevel); + do { + rc = fts3IncrmergeAppend(p, pWriter, pCsr); + if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr); + if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK; + }while( rc==SQLITE_ROW ); + + /* Update or delete the input segments */ + if( rc==SQLITE_OK ){ + nRem -= (1 + pWriter->nWork); + rc = fts3IncrmergeChomp(p, iAbsLevel, pCsr, &nSeg); + if( nSeg!=0 ){ + bDirtyHint = 1; + fts3IncrmergeHintPush(&hint, iAbsLevel, nSeg, &rc); + } + } + } + + if( nSeg!=0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } + fts3IncrmergeRelease(p, pWriter, &rc); + if( nSeg==0 && pWriter->bNoLeafData==0 ){ + fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData); + } + } + + sqlite3Fts3SegReaderFinish(pCsr); + } + + /* Write the hint values into the %_stat table for the next incr-merger */ + if( bDirtyHint && rc==SQLITE_OK ){ + rc = fts3IncrmergeHintStore(p, &hint); + } + + sqlite3_free(pWriter); + sqlite3_free(hint.a); + return rc; +} + +/* +** Convert the text beginning at *pz into an integer and return +** its value. Advance *pz to point to the first character past +** the integer. +** +** This function used for parameters to merge= and incrmerge= +** commands. +*/ +static int fts3Getint(const char **pz){ + const char *z = *pz; + int i = 0; + while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0'; + *pz = z; + return i; +} + +/* +** Process statements of the form: +** +** INSERT INTO table(table) VALUES('merge=A,B'); +** +** A and B are integers that decode to be the number of leaf pages +** written for the merge, and the minimum number of segments on a level +** before it will be selected for a merge, respectively. +*/ +static int fts3DoIncrmerge( + Fts3Table *p, /* FTS3 table handle */ + const char *zParam /* Nul-terminated string containing "A,B" */ +){ + int rc; + int nMin = (FTS3_MERGE_COUNT / 2); + int nMerge = 0; + const char *z = zParam; + + /* Read the first integer value */ + nMerge = fts3Getint(&z); + + /* If the first integer value is followed by a ',', read the second + ** integer value. */ + if( z[0]==',' && z[1]!='\0' ){ + z++; + nMin = fts3Getint(&z); + } + + if( z[0]!='\0' || nMin<2 ){ + rc = SQLITE_ERROR; + }else{ + rc = SQLITE_OK; + if( !p->bHasStat ){ + assert( p->bFts4==0 ); + sqlite3Fts3CreateStatTable(&rc, p); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3Incrmerge(p, nMerge, nMin); + } + sqlite3Fts3SegmentsClose(p); + } + return rc; +} + +/* +** Process statements of the form: +** +** INSERT INTO table(table) VALUES('automerge=X'); +** +** where X is an integer. X==0 means to turn automerge off. X!=0 means +** turn it on. The setting is persistent. +*/ +static int fts3DoAutoincrmerge( + Fts3Table *p, /* FTS3 table handle */ + const char *zParam /* Nul-terminated string containing boolean */ +){ + int rc = SQLITE_OK; + sqlite3_stmt *pStmt = 0; + p->nAutoincrmerge = fts3Getint(&zParam); + if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){ + p->nAutoincrmerge = 8; + } + if( !p->bHasStat ){ + assert( p->bFts4==0 ); + sqlite3Fts3CreateStatTable(&rc, p); + if( rc ) return rc; + } + rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); + if( rc ) return rc; + sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); + sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + return rc; +} + +/* +** Return a 64-bit checksum for the FTS index entry specified by the +** arguments to this function. +*/ +static u64 fts3ChecksumEntry( + const char *zTerm, /* Pointer to buffer containing term */ + int nTerm, /* Size of zTerm in bytes */ + int iLangid, /* Language id for current row */ + int iIndex, /* Index (0..Fts3Table.nIndex-1) */ + i64 iDocid, /* Docid for current row. */ + int iCol, /* Column number */ + int iPos /* Position */ +){ + int i; + u64 ret = (u64)iDocid; + + ret += (ret<<3) + iLangid; + ret += (ret<<3) + iIndex; + ret += (ret<<3) + iCol; + ret += (ret<<3) + iPos; + for(i=0; inIndex-1) */ + int *pRc /* OUT: Return code */ +){ + Fts3SegFilter filter; + Fts3MultiSegReader csr; + int rc; + u64 cksum = 0; + + assert( *pRc==SQLITE_OK ); + + memset(&filter, 0, sizeof(filter)); + memset(&csr, 0, sizeof(csr)); + filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; + filter.flags |= FTS3_SEGMENT_SCAN; + + rc = sqlite3Fts3SegReaderCursor( + p, iLangid, iIndex, FTS3_SEGCURSOR_ALL, 0, 0, 0, 1,&csr + ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); + } + + if( rc==SQLITE_OK ){ + while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){ + char *pCsr = csr.aDoclist; + char *pEnd = &pCsr[csr.nDoclist]; + + i64 iDocid = 0; + i64 iCol = 0; + i64 iPos = 0; + + pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid); + while( pCsriPrevLangid); + sqlite3_bind_int(pAllLangid, 2, p->nIndex); + while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){ + int iLangid = sqlite3_column_int(pAllLangid, 0); + int i; + for(i=0; inIndex; i++){ + cksum1 = cksum1 ^ fts3ChecksumIndex(p, iLangid, i, &rc); + } + } + rc2 = sqlite3_reset(pAllLangid); + if( rc==SQLITE_OK ) rc = rc2; + } + + /* This block calculates the checksum according to the %_content table */ + if( rc==SQLITE_OK ){ + sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule; + sqlite3_stmt *pStmt = 0; + char *zSql; + + zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + i64 iDocid = sqlite3_column_int64(pStmt, 0); + int iLang = langidFromSelect(p, pStmt); + int iCol; + + for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); + int nText = sqlite3_column_bytes(pStmt, iCol+1); + sqlite3_tokenizer_cursor *pT = 0; + + rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT); + while( rc==SQLITE_OK ){ + char const *zToken; /* Buffer containing token */ + int nToken = 0; /* Number of bytes in token */ + int iDum1 = 0, iDum2 = 0; /* Dummy variables */ + int iPos = 0; /* Position of token in zText */ + + rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); + if( rc==SQLITE_OK ){ + int i; + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, nToken, iLang, 0, iDocid, iCol, iPos + ); + for(i=1; inIndex; i++){ + if( p->aIndex[i].nPrefix<=nToken ){ + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos + ); + } + } + } + } + if( pT ) pModule->xClose(pT); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } + } + } + + sqlite3_finalize(pStmt); + } + + *pbOk = (cksum1==cksum2); + return rc; +} + +/* +** Run the integrity-check. If no error occurs and the current contents of +** the FTS index are correct, return SQLITE_OK. Or, if the contents of the +** FTS index are incorrect, return SQLITE_CORRUPT_VTAB. +** +** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite +** error code. +** +** The integrity-check works as follows. For each token and indexed token +** prefix in the document set, a 64-bit checksum is calculated (by code +** in fts3ChecksumEntry()) based on the following: +** +** + The index number (0 for the main index, 1 for the first prefix +** index etc.), +** + The token (or token prefix) text itself, +** + The language-id of the row it appears in, +** + The docid of the row it appears in, +** + The column it appears in, and +** + The tokens position within that column. +** +** The checksums for all entries in the index are XORed together to create +** a single checksum for the entire index. +** +** The integrity-check code calculates the same checksum in two ways: +** +** 1. By scanning the contents of the FTS index, and +** 2. By scanning and tokenizing the content table. +** +** If the two checksums are identical, the integrity-check is deemed to have +** passed. +*/ +static int fts3DoIntegrityCheck( + Fts3Table *p /* FTS3 table handle */ +){ + int rc; + int bOk = 0; + rc = fts3IntegrityCheck(p, &bOk); + if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB; + return rc; +} + +/* +** Handle a 'special' INSERT of the form: +** +** "INSERT INTO tbl(tbl) VALUES()" +** +** Argument pVal contains the result of . Currently the only +** meaningful value to insert is the text 'optimize'. +*/ +static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ + int rc; /* Return Code */ + const char *zVal = (const char *)sqlite3_value_text(pVal); + int nVal = sqlite3_value_bytes(pVal); + + if( !zVal ){ + return SQLITE_NOMEM; + }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ + rc = fts3DoOptimize(p, 0); + }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ + rc = fts3DoRebuild(p); + }else if( nVal==15 && 0==sqlite3_strnicmp(zVal, "integrity-check", 15) ){ + rc = fts3DoIntegrityCheck(p); + }else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){ + rc = fts3DoIncrmerge(p, &zVal[6]); + }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){ + rc = fts3DoAutoincrmerge(p, &zVal[10]); +#ifdef SQLITE_TEST + }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ + p->nNodeSize = atoi(&zVal[9]); + rc = SQLITE_OK; + }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ + p->nMaxPendingData = atoi(&zVal[11]); + rc = SQLITE_OK; + }else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){ + p->bNoIncrDoclist = atoi(&zVal[21]); + rc = SQLITE_OK; +#endif + }else{ + rc = SQLITE_ERROR; + } + + return rc; +} + +#ifndef SQLITE_DISABLE_FTS4_DEFERRED +/* +** Delete all cached deferred doclists. Deferred doclists are cached +** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function. +*/ +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){ + Fts3DeferredToken *pDef; + for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){ + fts3PendingListDelete(pDef->pList); + pDef->pList = 0; + } +} + +/* +** Free all entries in the pCsr->pDeffered list. Entries are added to +** this list using sqlite3Fts3DeferToken(). +*/ +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){ + Fts3DeferredToken *pDef; + Fts3DeferredToken *pNext; + for(pDef=pCsr->pDeferred; pDef; pDef=pNext){ + pNext = pDef->pNext; + fts3PendingListDelete(pDef->pList); + sqlite3_free(pDef); + } + pCsr->pDeferred = 0; +} + +/* +** Generate deferred-doclists for all tokens in the pCsr->pDeferred list +** based on the row that pCsr currently points to. +** +** A deferred-doclist is like any other doclist with position information +** included, except that it only contains entries for a single row of the +** table, not for all rows. +*/ +SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){ + int rc = SQLITE_OK; /* Return code */ + if( pCsr->pDeferred ){ + int i; /* Used to iterate through table columns */ + sqlite3_int64 iDocid; /* Docid of the row pCsr points to */ + Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */ + + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + sqlite3_tokenizer *pT = p->pTokenizer; + sqlite3_tokenizer_module const *pModule = pT->pModule; + + assert( pCsr->isRequireSeek==0 ); + iDocid = sqlite3_column_int64(pCsr->pStmt, 0); + + for(i=0; inColumn && rc==SQLITE_OK; i++){ + if( p->abNotindexed[i]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1); + sqlite3_tokenizer_cursor *pTC = 0; + + rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC); + while( rc==SQLITE_OK ){ + char const *zToken; /* Buffer containing token */ + int nToken = 0; /* Number of bytes in token */ + int iDum1 = 0, iDum2 = 0; /* Dummy variables */ + int iPos = 0; /* Position of token in zText */ + + rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); + for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ + Fts3PhraseToken *pPT = pDef->pToken; + if( (pDef->iCol>=p->nColumn || pDef->iCol==i) + && (pPT->bFirst==0 || iPos==0) + && (pPT->n==nToken || (pPT->isPrefix && pPT->nz, pPT->n)) + ){ + fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); + } + } + } + if( pTC ) pModule->xClose(pTC); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } + } + + for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ + if( pDef->pList ){ + rc = fts3PendingListAppendVarint(&pDef->pList, 0); + } + } + } + + return rc; +} + +SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList( + Fts3DeferredToken *p, + char **ppData, + int *pnData +){ + char *pRet; + int nSkip; + sqlite3_int64 dummy; + + *ppData = 0; + *pnData = 0; + + if( p->pList==0 ){ + return SQLITE_OK; + } + + pRet = (char *)sqlite3_malloc(p->pList->nData); + if( !pRet ) return SQLITE_NOMEM; + + nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); + *pnData = p->pList->nData - nSkip; + *ppData = pRet; + + memcpy(pRet, &p->pList->aData[nSkip], *pnData); + return SQLITE_OK; +} + +/* +** Add an entry for token pToken to the pCsr->pDeferred list. +*/ +SQLITE_PRIVATE int sqlite3Fts3DeferToken( + Fts3Cursor *pCsr, /* Fts3 table cursor */ + Fts3PhraseToken *pToken, /* Token to defer */ + int iCol /* Column that token must appear in (or -1) */ +){ + Fts3DeferredToken *pDeferred; + pDeferred = sqlite3_malloc(sizeof(*pDeferred)); + if( !pDeferred ){ + return SQLITE_NOMEM; + } + memset(pDeferred, 0, sizeof(*pDeferred)); + pDeferred->pToken = pToken; + pDeferred->pNext = pCsr->pDeferred; + pDeferred->iCol = iCol; + pCsr->pDeferred = pDeferred; + + assert( pToken->pDeferred==0 ); + pToken->pDeferred = pDeferred; + + return SQLITE_OK; +} +#endif + +/* +** SQLite value pRowid contains the rowid of a row that may or may not be +** present in the FTS3 table. If it is, delete it and adjust the contents +** of subsiduary data structures accordingly. +*/ +static int fts3DeleteByRowid( + Fts3Table *p, + sqlite3_value *pRowid, + int *pnChng, /* IN/OUT: Decrement if row is deleted */ + u32 *aSzDel +){ + int rc = SQLITE_OK; /* Return code */ + int bFound = 0; /* True if *pRowid really is in the table */ + + fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound); + if( bFound && rc==SQLITE_OK ){ + int isEmpty = 0; /* Deleting *pRowid leaves the table empty */ + rc = fts3IsEmpty(p, pRowid, &isEmpty); + if( rc==SQLITE_OK ){ + if( isEmpty ){ + /* Deleting this row means the whole table is empty. In this case + ** delete the contents of all three tables and throw away any + ** data in the pendingTerms hash table. */ + rc = fts3DeleteAll(p, 1); + *pnChng = 0; + memset(aSzDel, 0, sizeof(u32) * (p->nColumn+1) * 2); + }else{ + *pnChng = *pnChng - 1; + if( p->zContentTbl==0 ){ + fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); + } + if( p->bHasDocsize ){ + fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); + } + } + } + } + + return rc; +} + +/* +** This function does the work for the xUpdate method of FTS3 virtual +** tables. The schema of the virtual table being: +** +** CREATE TABLE
    ( +** , +**
    HIDDEN, +** docid HIDDEN, +** HIDDEN +** ); +** +** +*/ +SQLITE_PRIVATE int sqlite3Fts3UpdateMethod( + sqlite3_vtab *pVtab, /* FTS3 vtab object */ + int nArg, /* Size of argument array */ + sqlite3_value **apVal, /* Array of arguments */ + sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ +){ + Fts3Table *p = (Fts3Table *)pVtab; + int rc = SQLITE_OK; /* Return Code */ + int isRemove = 0; /* True for an UPDATE or DELETE */ + u32 *aSzIns = 0; /* Sizes of inserted documents */ + u32 *aSzDel = 0; /* Sizes of deleted documents */ + int nChng = 0; /* Net change in number of documents */ + int bInsertDone = 0; + + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + assert( p->bHasStat==0 || p->bHasStat==1 ); + + assert( p->pSegments==0 ); + assert( + nArg==1 /* DELETE operations */ + || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */ + ); + + /* Check for a "special" INSERT operation. One of the form: + ** + ** INSERT INTO xyz(xyz) VALUES('command'); + */ + if( nArg>1 + && sqlite3_value_type(apVal[0])==SQLITE_NULL + && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL + ){ + rc = fts3SpecialInsert(p, apVal[p->nColumn+2]); + goto update_out; + } + + if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){ + rc = SQLITE_CONSTRAINT; + goto update_out; + } + + /* Allocate space to hold the change in document sizes */ + aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 ); + if( aSzDel==0 ){ + rc = SQLITE_NOMEM; + goto update_out; + } + aSzIns = &aSzDel[p->nColumn+1]; + memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2); + + rc = fts3Writelock(p); + if( rc!=SQLITE_OK ) goto update_out; + + /* If this is an INSERT operation, or an UPDATE that modifies the rowid + ** value, then this operation requires constraint handling. + ** + ** If the on-conflict mode is REPLACE, this means that the existing row + ** should be deleted from the database before inserting the new row. Or, + ** if the on-conflict mode is other than REPLACE, then this method must + ** detect the conflict and return SQLITE_CONSTRAINT before beginning to + ** modify the database file. + */ + if( nArg>1 && p->zContentTbl==0 ){ + /* Find the value object that holds the new rowid value. */ + sqlite3_value *pNewRowid = apVal[3+p->nColumn]; + if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ + pNewRowid = apVal[1]; + } + + if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( + sqlite3_value_type(apVal[0])==SQLITE_NULL + || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) + )){ + /* The new rowid is not NULL (in this case the rowid will be + ** automatically assigned and there is no chance of a conflict), and + ** the statement is either an INSERT or an UPDATE that modifies the + ** rowid column. So if the conflict mode is REPLACE, then delete any + ** existing row with rowid=pNewRowid. + ** + ** Or, if the conflict mode is not REPLACE, insert the new record into + ** the %_content table. If we hit the duplicate rowid constraint (or any + ** other error) while doing so, return immediately. + ** + ** This branch may also run if pNewRowid contains a value that cannot + ** be losslessly converted to an integer. In this case, the eventual + ** call to fts3InsertData() (either just below or further on in this + ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is + ** invoked, it will delete zero rows (since no row will have + ** docid=$pNewRowid if $pNewRowid is not an integer value). + */ + if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ + rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); + }else{ + rc = fts3InsertData(p, apVal, pRowid); + bInsertDone = 1; + } + } + } + if( rc!=SQLITE_OK ){ + goto update_out; + } + + /* If this is a DELETE or UPDATE operation, remove the old record. */ + if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ + assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); + rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); + isRemove = 1; + } + + /* If this is an INSERT or UPDATE operation, insert the new record. */ + if( nArg>1 && rc==SQLITE_OK ){ + int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]); + if( bInsertDone==0 ){ + rc = fts3InsertData(p, apVal, pRowid); + if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ + rc = FTS_CORRUPT_VTAB; + } + } + if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ + rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid); + } + if( rc==SQLITE_OK ){ + assert( p->iPrevDocid==*pRowid ); + rc = fts3InsertTerms(p, iLangid, apVal, aSzIns); + } + if( p->bHasDocsize ){ + fts3InsertDocsize(&rc, p, aSzIns); + } + nChng++; + } + + if( p->bFts4 ){ + fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng); + } + + update_out: + sqlite3_free(aSzDel); + sqlite3Fts3SegmentsClose(p); + return rc; +} + +/* +** Flush any data in the pending-terms hash table to disk. If successful, +** merge all segments in the database (including the new segment, if +** there was any data to flush) into a single segment. +*/ +SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){ + int rc; + rc = sqlite3_exec(p->db, "SAVEPOINT fts3", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = fts3DoOptimize(p, 1); + if( rc==SQLITE_OK || rc==SQLITE_DONE ){ + int rc2 = sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); + if( rc2!=SQLITE_OK ) rc = rc2; + }else{ + sqlite3_exec(p->db, "ROLLBACK TO fts3", 0, 0, 0); + sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); + } + } + sqlite3Fts3SegmentsClose(p); + return rc; +} + +#endif + +/************** End of fts3_write.c ******************************************/ +/************** Begin file fts3_snippet.c ************************************/ +/* +** 2009 Oct 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +*/ + +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ + +/* +** Characters that may appear in the second argument to matchinfo(). +*/ +#define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ +#define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ +#define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ +#define FTS3_MATCHINFO_AVGLENGTH 'a' /* nCol values */ +#define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */ +#define FTS3_MATCHINFO_LCS 's' /* nCol values */ +#define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */ +#define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */ +#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */ + +/* +** The default value for the second argument to matchinfo(). +*/ +#define FTS3_MATCHINFO_DEFAULT "pcx" + + +/* +** Used as an fts3ExprIterate() context when loading phrase doclists to +** Fts3Expr.aDoclist[]/nDoclist. +*/ +typedef struct LoadDoclistCtx LoadDoclistCtx; +struct LoadDoclistCtx { + Fts3Cursor *pCsr; /* FTS3 Cursor */ + int nPhrase; /* Number of phrases seen so far */ + int nToken; /* Number of tokens seen so far */ +}; + +/* +** The following types are used as part of the implementation of the +** fts3BestSnippet() routine. +*/ +typedef struct SnippetIter SnippetIter; +typedef struct SnippetPhrase SnippetPhrase; +typedef struct SnippetFragment SnippetFragment; + +struct SnippetIter { + Fts3Cursor *pCsr; /* Cursor snippet is being generated from */ + int iCol; /* Extract snippet from this column */ + int nSnippet; /* Requested snippet length (in tokens) */ + int nPhrase; /* Number of phrases in query */ + SnippetPhrase *aPhrase; /* Array of size nPhrase */ + int iCurrent; /* First token of current snippet */ +}; + +struct SnippetPhrase { + int nToken; /* Number of tokens in phrase */ + char *pList; /* Pointer to start of phrase position list */ + int iHead; /* Next value in position list */ + char *pHead; /* Position list data following iHead */ + int iTail; /* Next value in trailing position list */ + char *pTail; /* Position list data following iTail */ +}; + +struct SnippetFragment { + int iCol; /* Column snippet is extracted from */ + int iPos; /* Index of first token in snippet */ + u64 covered; /* Mask of query phrases covered */ + u64 hlmask; /* Mask of snippet terms to highlight */ +}; + +/* +** This type is used as an fts3ExprIterate() context object while +** accumulating the data returned by the matchinfo() function. +*/ +typedef struct MatchInfo MatchInfo; +struct MatchInfo { + Fts3Cursor *pCursor; /* FTS3 Cursor */ + int nCol; /* Number of columns in table */ + int nPhrase; /* Number of matchable phrases in query */ + sqlite3_int64 nDoc; /* Number of docs in database */ + char flag; + u32 *aMatchinfo; /* Pre-allocated buffer */ +}; + +/* +** An instance of this structure is used to manage a pair of buffers, each +** (nElem * sizeof(u32)) bytes in size. See the MatchinfoBuffer code below +** for details. +*/ +struct MatchinfoBuffer { + u8 aRef[3]; + int nElem; + int bGlobal; /* Set if global data is loaded */ + char *zMatchinfo; + u32 aMatchinfo[1]; +}; + + +/* +** The snippet() and offsets() functions both return text values. An instance +** of the following structure is used to accumulate those values while the +** functions are running. See fts3StringAppend() for details. +*/ +typedef struct StrBuffer StrBuffer; +struct StrBuffer { + char *z; /* Pointer to buffer containing string */ + int n; /* Length of z in bytes (excl. nul-term) */ + int nAlloc; /* Allocated size of buffer z in bytes */ +}; + + +/************************************************************************* +** Start of MatchinfoBuffer code. +*/ + +/* +** Allocate a two-slot MatchinfoBuffer object. +*/ +static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){ + MatchinfoBuffer *pRet; + int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer); + int nStr = (int)strlen(zMatchinfo); + + pRet = sqlite3_malloc(nByte + nStr+1); + if( pRet ){ + memset(pRet, 0, nByte); + pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; + pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1); + pRet->nElem = nElem; + pRet->zMatchinfo = ((char*)pRet) + nByte; + memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); + pRet->aRef[0] = 1; + } + + return pRet; +} + +static void fts3MIBufferFree(void *p){ + MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); + + assert( (u32*)p==&pBuf->aMatchinfo[1] + || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] + ); + if( (u32*)p==&pBuf->aMatchinfo[1] ){ + pBuf->aRef[1] = 0; + }else{ + pBuf->aRef[2] = 0; + } + + if( pBuf->aRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){ + sqlite3_free(pBuf); + } +} + +static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ + void (*xRet)(void*) = 0; + u32 *aOut = 0; + + if( p->aRef[1]==0 ){ + p->aRef[1] = 1; + aOut = &p->aMatchinfo[1]; + xRet = fts3MIBufferFree; + } + else if( p->aRef[2]==0 ){ + p->aRef[2] = 1; + aOut = &p->aMatchinfo[p->nElem+2]; + xRet = fts3MIBufferFree; + }else{ + aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32)); + if( aOut ){ + xRet = sqlite3_free; + if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); + } + } + + *paOut = aOut; + return xRet; +} + +static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ + p->bGlobal = 1; + memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); +} + +/* +** Free a MatchinfoBuffer object allocated using fts3MIBufferNew() +*/ +SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){ + if( p ){ + assert( p->aRef[0]==1 ); + p->aRef[0] = 0; + if( p->aRef[0]==0 && p->aRef[1]==0 && p->aRef[2]==0 ){ + sqlite3_free(p); + } + } +} + +/* +** End of MatchinfoBuffer code. +*************************************************************************/ + + +/* +** This function is used to help iterate through a position-list. A position +** list is a list of unique integers, sorted from smallest to largest. Each +** element of the list is represented by an FTS3 varint that takes the value +** of the difference between the current element and the previous one plus +** two. For example, to store the position-list: +** +** 4 9 113 +** +** the three varints: +** +** 6 7 106 +** +** are encoded. +** +** When this function is called, *pp points to the start of an element of +** the list. *piPos contains the value of the previous entry in the list. +** After it returns, *piPos contains the value of the next element of the +** list and *pp is advanced to the following varint. +*/ +static void fts3GetDeltaPosition(char **pp, int *piPos){ + int iVal; + *pp += fts3GetVarint32(*pp, &iVal); + *piPos += (iVal-2); +} + +/* +** Helper function for fts3ExprIterate() (see below). +*/ +static int fts3ExprIterate2( + Fts3Expr *pExpr, /* Expression to iterate phrases of */ + int *piPhrase, /* Pointer to phrase counter */ + int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ + void *pCtx /* Second argument to pass to callback */ +){ + int rc; /* Return code */ + int eType = pExpr->eType; /* Type of expression node pExpr */ + + if( eType!=FTSQUERY_PHRASE ){ + assert( pExpr->pLeft && pExpr->pRight ); + rc = fts3ExprIterate2(pExpr->pLeft, piPhrase, x, pCtx); + if( rc==SQLITE_OK && eType!=FTSQUERY_NOT ){ + rc = fts3ExprIterate2(pExpr->pRight, piPhrase, x, pCtx); + } + }else{ + rc = x(pExpr, *piPhrase, pCtx); + (*piPhrase)++; + } + return rc; +} + +/* +** Iterate through all phrase nodes in an FTS3 query, except those that +** are part of a sub-tree that is the right-hand-side of a NOT operator. +** For each phrase node found, the supplied callback function is invoked. +** +** If the callback function returns anything other than SQLITE_OK, +** the iteration is abandoned and the error code returned immediately. +** Otherwise, SQLITE_OK is returned after a callback has been made for +** all eligible phrase nodes. +*/ +static int fts3ExprIterate( + Fts3Expr *pExpr, /* Expression to iterate phrases of */ + int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ + void *pCtx /* Second argument to pass to callback */ +){ + int iPhrase = 0; /* Variable used as the phrase counter */ + return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx); +} + + +/* +** This is an fts3ExprIterate() callback used while loading the doclists +** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also +** fts3ExprLoadDoclists(). +*/ +static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ + int rc = SQLITE_OK; + Fts3Phrase *pPhrase = pExpr->pPhrase; + LoadDoclistCtx *p = (LoadDoclistCtx *)ctx; + + UNUSED_PARAMETER(iPhrase); + + p->nPhrase++; + p->nToken += pPhrase->nToken; + + return rc; +} + +/* +** Load the doclists for each phrase in the query associated with FTS3 cursor +** pCsr. +** +** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable +** phrases in the expression (all phrases except those directly or +** indirectly descended from the right-hand-side of a NOT operator). If +** pnToken is not NULL, then it is set to the number of tokens in all +** matchable phrases of the expression. +*/ +static int fts3ExprLoadDoclists( + Fts3Cursor *pCsr, /* Fts3 cursor for current query */ + int *pnPhrase, /* OUT: Number of phrases in query */ + int *pnToken /* OUT: Number of tokens in query */ +){ + int rc; /* Return Code */ + LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */ + sCtx.pCsr = pCsr; + rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx); + if( pnPhrase ) *pnPhrase = sCtx.nPhrase; + if( pnToken ) *pnToken = sCtx.nToken; + return rc; +} + +static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ + (*(int *)ctx)++; + pExpr->iPhrase = iPhrase; + return SQLITE_OK; +} +static int fts3ExprPhraseCount(Fts3Expr *pExpr){ + int nPhrase = 0; + (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase); + return nPhrase; +} + +/* +** Advance the position list iterator specified by the first two +** arguments so that it points to the first element with a value greater +** than or equal to parameter iNext. +*/ +static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){ + char *pIter = *ppIter; + if( pIter ){ + int iIter = *piIter; + + while( iIteriCurrent<0 ){ + /* The SnippetIter object has just been initialized. The first snippet + ** candidate always starts at offset 0 (even if this candidate has a + ** score of 0.0). + */ + pIter->iCurrent = 0; + + /* Advance the 'head' iterator of each phrase to the first offset that + ** is greater than or equal to (iNext+nSnippet). + */ + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, pIter->nSnippet); + } + }else{ + int iStart; + int iEnd = 0x7FFFFFFF; + + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + if( pPhrase->pHead && pPhrase->iHeadiHead; + } + } + if( iEnd==0x7FFFFFFF ){ + return 1; + } + + pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1; + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1); + fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart); + } + } + + return 0; +} + +/* +** Retrieve information about the current candidate snippet of snippet +** iterator pIter. +*/ +static void fts3SnippetDetails( + SnippetIter *pIter, /* Snippet iterator */ + u64 mCovered, /* Bitmask of phrases already covered */ + int *piToken, /* OUT: First token of proposed snippet */ + int *piScore, /* OUT: "Score" for this snippet */ + u64 *pmCover, /* OUT: Bitmask of phrases covered */ + u64 *pmHighlight /* OUT: Bitmask of terms to highlight */ +){ + int iStart = pIter->iCurrent; /* First token of snippet */ + int iScore = 0; /* Score of this snippet */ + int i; /* Loop counter */ + u64 mCover = 0; /* Mask of phrases covered by this snippet */ + u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */ + + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + if( pPhrase->pTail ){ + char *pCsr = pPhrase->pTail; + int iCsr = pPhrase->iTail; + + while( iCsr<(iStart+pIter->nSnippet) ){ + int j; + u64 mPhrase = (u64)1 << i; + u64 mPos = (u64)1 << (iCsr - iStart); + assert( iCsr>=iStart ); + if( (mCover|mCovered)&mPhrase ){ + iScore++; + }else{ + iScore += 1000; + } + mCover |= mPhrase; + + for(j=0; jnToken; j++){ + mHighlight |= (mPos>>j); + } + + if( 0==(*pCsr & 0x0FE) ) break; + fts3GetDeltaPosition(&pCsr, &iCsr); + } + } + } + + /* Set the output variables before returning. */ + *piToken = iStart; + *piScore = iScore; + *pmCover = mCover; + *pmHighlight = mHighlight; +} + +/* +** This function is an fts3ExprIterate() callback used by fts3BestSnippet(). +** Each invocation populates an element of the SnippetIter.aPhrase[] array. +*/ +static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ + SnippetIter *p = (SnippetIter *)ctx; + SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; + char *pCsr; + int rc; + + pPhrase->nToken = pExpr->pPhrase->nToken; + rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); + assert( rc==SQLITE_OK || pCsr==0 ); + if( pCsr ){ + int iFirst = 0; + pPhrase->pList = pCsr; + fts3GetDeltaPosition(&pCsr, &iFirst); + assert( iFirst>=0 ); + pPhrase->pHead = pCsr; + pPhrase->pTail = pCsr; + pPhrase->iHead = iFirst; + pPhrase->iTail = iFirst; + }else{ + assert( rc!=SQLITE_OK || ( + pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 + )); + } + + return rc; +} + +/* +** Select the fragment of text consisting of nFragment contiguous tokens +** from column iCol that represent the "best" snippet. The best snippet +** is the snippet with the highest score, where scores are calculated +** by adding: +** +** (a) +1 point for each occurrence of a matchable phrase in the snippet. +** +** (b) +1000 points for the first occurrence of each matchable phrase in +** the snippet for which the corresponding mCovered bit is not set. +** +** The selected snippet parameters are stored in structure *pFragment before +** returning. The score of the selected snippet is stored in *piScore +** before returning. +*/ +static int fts3BestSnippet( + int nSnippet, /* Desired snippet length */ + Fts3Cursor *pCsr, /* Cursor to create snippet for */ + int iCol, /* Index of column to create snippet from */ + u64 mCovered, /* Mask of phrases already covered */ + u64 *pmSeen, /* IN/OUT: Mask of phrases seen */ + SnippetFragment *pFragment, /* OUT: Best snippet found */ + int *piScore /* OUT: Score of snippet pFragment */ +){ + int rc; /* Return Code */ + int nList; /* Number of phrases in expression */ + SnippetIter sIter; /* Iterates through snippet candidates */ + int nByte; /* Number of bytes of space to allocate */ + int iBestScore = -1; /* Best snippet score found so far */ + int i; /* Loop counter */ + + memset(&sIter, 0, sizeof(sIter)); + + /* Iterate through the phrases in the expression to count them. The same + ** callback makes sure the doclists are loaded for each phrase. + */ + rc = fts3ExprLoadDoclists(pCsr, &nList, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + + /* Now that it is known how many phrases there are, allocate and zero + ** the required space using malloc(). + */ + nByte = sizeof(SnippetPhrase) * nList; + sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte); + if( !sIter.aPhrase ){ + return SQLITE_NOMEM; + } + memset(sIter.aPhrase, 0, nByte); + + /* Initialize the contents of the SnippetIter object. Then iterate through + ** the set of phrases in the expression to populate the aPhrase[] array. + */ + sIter.pCsr = pCsr; + sIter.iCol = iCol; + sIter.nSnippet = nSnippet; + sIter.nPhrase = nList; + sIter.iCurrent = -1; + rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter); + if( rc==SQLITE_OK ){ + + /* Set the *pmSeen output variable. */ + for(i=0; iiCol = iCol; + while( !fts3SnippetNextCandidate(&sIter) ){ + int iPos; + int iScore; + u64 mCover; + u64 mHighlite; + fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite); + assert( iScore>=0 ); + if( iScore>iBestScore ){ + pFragment->iPos = iPos; + pFragment->hlmask = mHighlite; + pFragment->covered = mCover; + iBestScore = iScore; + } + } + + *piScore = iBestScore; + } + sqlite3_free(sIter.aPhrase); + return rc; +} + + +/* +** Append a string to the string-buffer passed as the first argument. +** +** If nAppend is negative, then the length of the string zAppend is +** determined using strlen(). +*/ +static int fts3StringAppend( + StrBuffer *pStr, /* Buffer to append to */ + const char *zAppend, /* Pointer to data to append to buffer */ + int nAppend /* Size of zAppend in bytes (or -1) */ +){ + if( nAppend<0 ){ + nAppend = (int)strlen(zAppend); + } + + /* If there is insufficient space allocated at StrBuffer.z, use realloc() + ** to grow the buffer until so that it is big enough to accomadate the + ** appended data. + */ + if( pStr->n+nAppend+1>=pStr->nAlloc ){ + int nAlloc = pStr->nAlloc+nAppend+100; + char *zNew = sqlite3_realloc(pStr->z, nAlloc); + if( !zNew ){ + return SQLITE_NOMEM; + } + pStr->z = zNew; + pStr->nAlloc = nAlloc; + } + assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) ); + + /* Append the data to the string buffer. */ + memcpy(&pStr->z[pStr->n], zAppend, nAppend); + pStr->n += nAppend; + pStr->z[pStr->n] = '\0'; + + return SQLITE_OK; +} + +/* +** The fts3BestSnippet() function often selects snippets that end with a +** query term. That is, the final term of the snippet is always a term +** that requires highlighting. For example, if 'X' is a highlighted term +** and '.' is a non-highlighted term, BestSnippet() may select: +** +** ........X.....X +** +** This function "shifts" the beginning of the snippet forward in the +** document so that there are approximately the same number of +** non-highlighted terms to the right of the final highlighted term as there +** are to the left of the first highlighted term. For example, to this: +** +** ....X.....X.... +** +** This is done as part of extracting the snippet text, not when selecting +** the snippet. Snippet selection is done based on doclists only, so there +** is no way for fts3BestSnippet() to know whether or not the document +** actually contains terms that follow the final highlighted term. +*/ +static int fts3SnippetShift( + Fts3Table *pTab, /* FTS3 table snippet comes from */ + int iLangid, /* Language id to use in tokenizing */ + int nSnippet, /* Number of tokens desired for snippet */ + const char *zDoc, /* Document text to extract snippet from */ + int nDoc, /* Size of buffer zDoc in bytes */ + int *piPos, /* IN/OUT: First token of snippet */ + u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */ +){ + u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */ + + if( hlmask ){ + int nLeft; /* Tokens to the left of first highlight */ + int nRight; /* Tokens to the right of last highlight */ + int nDesired; /* Ideal number of tokens to shift forward */ + + for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++); + for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++); + nDesired = (nLeft-nRight)/2; + + /* Ideally, the start of the snippet should be pushed forward in the + ** document nDesired tokens. This block checks if there are actually + ** nDesired tokens to the right of the snippet. If so, *piPos and + ** *pHlMask are updated to shift the snippet nDesired tokens to the + ** right. Otherwise, the snippet is shifted by the number of tokens + ** available. + */ + if( nDesired>0 ){ + int nShift; /* Number of tokens to shift snippet by */ + int iCurrent = 0; /* Token counter */ + int rc; /* Return Code */ + sqlite3_tokenizer_module *pMod; + sqlite3_tokenizer_cursor *pC; + pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; + + /* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired) + ** or more tokens in zDoc/nDoc. + */ + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC); + if( rc!=SQLITE_OK ){ + return rc; + } + while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){ + const char *ZDUMMY; int DUMMY1 = 0, DUMMY2 = 0, DUMMY3 = 0; + rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent); + } + pMod->xClose(pC); + if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; } + + nShift = (rc==SQLITE_DONE)+iCurrent-nSnippet; + assert( nShift<=nDesired ); + if( nShift>0 ){ + *piPos += nShift; + *pHlmask = hlmask >> nShift; + } + } + } + return SQLITE_OK; +} + +/* +** Extract the snippet text for fragment pFragment from cursor pCsr and +** append it to string buffer pOut. +*/ +static int fts3SnippetText( + Fts3Cursor *pCsr, /* FTS3 Cursor */ + SnippetFragment *pFragment, /* Snippet to extract */ + int iFragment, /* Fragment number */ + int isLast, /* True for final fragment in snippet */ + int nSnippet, /* Number of tokens in extracted snippet */ + const char *zOpen, /* String inserted before highlighted term */ + const char *zClose, /* String inserted after highlighted term */ + const char *zEllipsis, /* String inserted between snippets */ + StrBuffer *pOut /* Write output here */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc; /* Return code */ + const char *zDoc; /* Document text to extract snippet from */ + int nDoc; /* Size of zDoc in bytes */ + int iCurrent = 0; /* Current token number of document */ + int iEnd = 0; /* Byte offset of end of current token */ + int isShiftDone = 0; /* True after snippet is shifted */ + int iPos = pFragment->iPos; /* First token of snippet */ + u64 hlmask = pFragment->hlmask; /* Highlight-mask for snippet */ + int iCol = pFragment->iCol+1; /* Query column to extract text from */ + sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */ + sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */ + + zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol); + if( zDoc==0 ){ + if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){ + return SQLITE_NOMEM; + } + return SQLITE_OK; + } + nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol); + + /* Open a token cursor on the document. */ + pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc,nDoc,&pC); + if( rc!=SQLITE_OK ){ + return rc; + } + + while( rc==SQLITE_OK ){ + const char *ZDUMMY; /* Dummy argument used with tokenizer */ + int DUMMY1 = -1; /* Dummy argument used with tokenizer */ + int iBegin = 0; /* Offset in zDoc of start of token */ + int iFin = 0; /* Offset in zDoc of end of token */ + int isHighlight = 0; /* True for highlighted terms */ + + /* Variable DUMMY1 is initialized to a negative value above. Elsewhere + ** in the FTS code the variable that the third argument to xNext points to + ** is initialized to zero before the first (*but not necessarily + ** subsequent*) call to xNext(). This is done for a particular application + ** that needs to know whether or not the tokenizer is being used for + ** snippet generation or for some other purpose. + ** + ** Extreme care is required when writing code to depend on this + ** initialization. It is not a documented part of the tokenizer interface. + ** If a tokenizer is used directly by any code outside of FTS, this + ** convention might not be respected. */ + rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + /* Special case - the last token of the snippet is also the last token + ** of the column. Append any punctuation that occurred between the end + ** of the previous token and the end of the document to the output. + ** Then break out of the loop. */ + rc = fts3StringAppend(pOut, &zDoc[iEnd], -1); + } + break; + } + if( iCurrentiLangid, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask + ); + isShiftDone = 1; + + /* Now that the shift has been done, check if the initial "..." are + ** required. They are required if (a) this is not the first fragment, + ** or (b) this fragment does not begin at position 0 of its column. + */ + if( rc==SQLITE_OK ){ + if( iPos>0 || iFragment>0 ){ + rc = fts3StringAppend(pOut, zEllipsis, -1); + }else if( iBegin ){ + rc = fts3StringAppend(pOut, zDoc, iBegin); + } + } + if( rc!=SQLITE_OK || iCurrent=(iPos+nSnippet) ){ + if( isLast ){ + rc = fts3StringAppend(pOut, zEllipsis, -1); + } + break; + } + + /* Set isHighlight to true if this term should be highlighted. */ + isHighlight = (hlmask & ((u64)1 << (iCurrent-iPos)))!=0; + + if( iCurrent>iPos ) rc = fts3StringAppend(pOut, &zDoc[iEnd], iBegin-iEnd); + if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zOpen, -1); + if( rc==SQLITE_OK ) rc = fts3StringAppend(pOut, &zDoc[iBegin], iFin-iBegin); + if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zClose, -1); + + iEnd = iFin; + } + + pMod->xClose(pC); + return rc; +} + + +/* +** This function is used to count the entries in a column-list (a +** delta-encoded list of term offsets within a single column of a single +** row). When this function is called, *ppCollist should point to the +** beginning of the first varint in the column-list (the varint that +** contains the position of the first matching term in the column data). +** Before returning, *ppCollist is set to point to the first byte after +** the last varint in the column-list (either the 0x00 signifying the end +** of the position-list, or the 0x01 that precedes the column number of +** the next column in the position-list). +** +** The number of elements in the column-list is returned. +*/ +static int fts3ColumnlistCount(char **ppCollist){ + char *pEnd = *ppCollist; + char c = 0; + int nEntry = 0; + + /* A column-list is terminated by either a 0x01 or 0x00. */ + while( 0xFE & (*pEnd | c) ){ + c = *pEnd++ & 0x80; + if( !c ) nEntry++; + } + + *ppCollist = pEnd; + return nEntry; +} + +/* +** This function gathers 'y' or 'b' data for a single phrase. +*/ +static void fts3ExprLHits( + Fts3Expr *pExpr, /* Phrase expression node */ + MatchInfo *p /* Matchinfo context */ +){ + Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab; + int iStart; + Fts3Phrase *pPhrase = pExpr->pPhrase; + char *pIter = pPhrase->doclist.pList; + int iCol = 0; + + assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS ); + if( p->flag==FTS3_MATCHINFO_LHITS ){ + iStart = pExpr->iPhrase * p->nCol; + }else{ + iStart = pExpr->iPhrase * ((p->nCol + 31) / 32); + } + + while( 1 ){ + int nHit = fts3ColumnlistCount(&pIter); + if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ + if( p->flag==FTS3_MATCHINFO_LHITS ){ + p->aMatchinfo[iStart + iCol] = (u32)nHit; + }else if( nHit ){ + p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); + } + } + assert( *pIter==0x00 || *pIter==0x01 ); + if( *pIter!=0x01 ) break; + pIter++; + pIter += fts3GetVarint32(pIter, &iCol); + } +} + +/* +** Gather the results for matchinfo directives 'y' and 'b'. +*/ +static void fts3ExprLHitGather( + Fts3Expr *pExpr, + MatchInfo *p +){ + assert( (pExpr->pLeft==0)==(pExpr->pRight==0) ); + if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ + if( pExpr->pLeft ){ + fts3ExprLHitGather(pExpr->pLeft, p); + fts3ExprLHitGather(pExpr->pRight, p); + }else{ + fts3ExprLHits(pExpr, p); + } + } +} + +/* +** fts3ExprIterate() callback used to collect the "global" matchinfo stats +** for a single query. +** +** fts3ExprIterate() callback to load the 'global' elements of a +** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements +** of the matchinfo array that are constant for all rows returned by the +** current query. +** +** Argument pCtx is actually a pointer to a struct of type MatchInfo. This +** function populates Matchinfo.aMatchinfo[] as follows: +** +** for(iCol=0; iColpCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol] + ); +} + +/* +** fts3ExprIterate() callback used to collect the "local" part of the +** FTS3_MATCHINFO_HITS array. The local stats are those elements of the +** array that are different for each row returned by the query. +*/ +static int fts3ExprLocalHitsCb( + Fts3Expr *pExpr, /* Phrase expression node */ + int iPhrase, /* Phrase number */ + void *pCtx /* Pointer to MatchInfo structure */ +){ + int rc = SQLITE_OK; + MatchInfo *p = (MatchInfo *)pCtx; + int iStart = iPhrase * p->nCol * 3; + int i; + + for(i=0; inCol && rc==SQLITE_OK; i++){ + char *pCsr; + rc = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i, &pCsr); + if( pCsr ){ + p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr); + }else{ + p->aMatchinfo[iStart+i*3] = 0; + } + } + + return rc; +} + +static int fts3MatchinfoCheck( + Fts3Table *pTab, + char cArg, + char **pzErr +){ + if( (cArg==FTS3_MATCHINFO_NPHRASE) + || (cArg==FTS3_MATCHINFO_NCOL) + || (cArg==FTS3_MATCHINFO_NDOC && pTab->bFts4) + || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bFts4) + || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize) + || (cArg==FTS3_MATCHINFO_LCS) + || (cArg==FTS3_MATCHINFO_HITS) + || (cArg==FTS3_MATCHINFO_LHITS) + || (cArg==FTS3_MATCHINFO_LHITS_BM) + ){ + return SQLITE_OK; + } + sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); + return SQLITE_ERROR; +} + +static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ + int nVal; /* Number of integers output by cArg */ + + switch( cArg ){ + case FTS3_MATCHINFO_NDOC: + case FTS3_MATCHINFO_NPHRASE: + case FTS3_MATCHINFO_NCOL: + nVal = 1; + break; + + case FTS3_MATCHINFO_AVGLENGTH: + case FTS3_MATCHINFO_LENGTH: + case FTS3_MATCHINFO_LCS: + nVal = pInfo->nCol; + break; + + case FTS3_MATCHINFO_LHITS: + nVal = pInfo->nCol * pInfo->nPhrase; + break; + + case FTS3_MATCHINFO_LHITS_BM: + nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + break; + + default: + assert( cArg==FTS3_MATCHINFO_HITS ); + nVal = pInfo->nCol * pInfo->nPhrase * 3; + break; + } + + return nVal; +} + +static int fts3MatchinfoSelectDoctotal( + Fts3Table *pTab, + sqlite3_stmt **ppStmt, + sqlite3_int64 *pnDoc, + const char **paLen +){ + sqlite3_stmt *pStmt; + const char *a; + sqlite3_int64 nDoc; + + if( !*ppStmt ){ + int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt); + if( rc!=SQLITE_OK ) return rc; + } + pStmt = *ppStmt; + assert( sqlite3_data_count(pStmt)==1 ); + + a = sqlite3_column_blob(pStmt, 0); + a += sqlite3Fts3GetVarint(a, &nDoc); + if( nDoc==0 ) return FTS_CORRUPT_VTAB; + *pnDoc = (u32)nDoc; + + if( paLen ) *paLen = a; + return SQLITE_OK; +} + +/* +** An instance of the following structure is used to store state while +** iterating through a multi-column position-list corresponding to the +** hits for a single phrase on a single row in order to calculate the +** values for a matchinfo() FTS3_MATCHINFO_LCS request. +*/ +typedef struct LcsIterator LcsIterator; +struct LcsIterator { + Fts3Expr *pExpr; /* Pointer to phrase expression */ + int iPosOffset; /* Tokens count up to end of this phrase */ + char *pRead; /* Cursor used to iterate through aDoclist */ + int iPos; /* Current position */ +}; + +/* +** If LcsIterator.iCol is set to the following value, the iterator has +** finished iterating through all offsets for all columns. +*/ +#define LCS_ITERATOR_FINISHED 0x7FFFFFFF; + +static int fts3MatchinfoLcsCb( + Fts3Expr *pExpr, /* Phrase expression node */ + int iPhrase, /* Phrase number (numbered from zero) */ + void *pCtx /* Pointer to MatchInfo structure */ +){ + LcsIterator *aIter = (LcsIterator *)pCtx; + aIter[iPhrase].pExpr = pExpr; + return SQLITE_OK; +} + +/* +** Advance the iterator passed as an argument to the next position. Return +** 1 if the iterator is at EOF or if it now points to the start of the +** position list for the next column. +*/ +static int fts3LcsIteratorAdvance(LcsIterator *pIter){ + char *pRead = pIter->pRead; + sqlite3_int64 iRead; + int rc = 0; + + pRead += sqlite3Fts3GetVarint(pRead, &iRead); + if( iRead==0 || iRead==1 ){ + pRead = 0; + rc = 1; + }else{ + pIter->iPos += (int)(iRead-2); + } + + pIter->pRead = pRead; + return rc; +} + +/* +** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag. +** +** If the call is successful, the longest-common-substring lengths for each +** column are written into the first nCol elements of the pInfo->aMatchinfo[] +** array before returning. SQLITE_OK is returned in this case. +** +** Otherwise, if an error occurs, an SQLite error code is returned and the +** data written to the first nCol elements of pInfo->aMatchinfo[] is +** undefined. +*/ +static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ + LcsIterator *aIter; + int i; + int iCol; + int nToken = 0; + + /* Allocate and populate the array of LcsIterator objects. The array + ** contains one element for each matchable phrase in the query. + **/ + aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase); + if( !aIter ) return SQLITE_NOMEM; + memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase); + (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); + + for(i=0; inPhrase; i++){ + LcsIterator *pIter = &aIter[i]; + nToken -= pIter->pExpr->pPhrase->nToken; + pIter->iPosOffset = nToken; + } + + for(iCol=0; iColnCol; iCol++){ + int nLcs = 0; /* LCS value for this column */ + int nLive = 0; /* Number of iterators in aIter not at EOF */ + + for(i=0; inPhrase; i++){ + int rc; + LcsIterator *pIt = &aIter[i]; + rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead); + if( rc!=SQLITE_OK ) return rc; + if( pIt->pRead ){ + pIt->iPos = pIt->iPosOffset; + fts3LcsIteratorAdvance(&aIter[i]); + nLive++; + } + } + + while( nLive>0 ){ + LcsIterator *pAdv = 0; /* The iterator to advance by one position */ + int nThisLcs = 0; /* LCS for the current iterator positions */ + + for(i=0; inPhrase; i++){ + LcsIterator *pIter = &aIter[i]; + if( pIter->pRead==0 ){ + /* This iterator is already at EOF for this column. */ + nThisLcs = 0; + }else{ + if( pAdv==0 || pIter->iPosiPos ){ + pAdv = pIter; + } + if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){ + nThisLcs++; + }else{ + nThisLcs = 1; + } + if( nThisLcs>nLcs ) nLcs = nThisLcs; + } + } + if( fts3LcsIteratorAdvance(pAdv) ) nLive--; + } + + pInfo->aMatchinfo[iCol] = nLcs; + } + + sqlite3_free(aIter); + return SQLITE_OK; +} + +/* +** Populate the buffer pInfo->aMatchinfo[] with an array of integers to +** be returned by the matchinfo() function. Argument zArg contains the +** format string passed as the second argument to matchinfo (or the +** default value "pcx" if no second argument was specified). The format +** string has already been validated and the pInfo->aMatchinfo[] array +** is guaranteed to be large enough for the output. +** +** If bGlobal is true, then populate all fields of the matchinfo() output. +** If it is false, then assume that those fields that do not change between +** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS) +** have already been populated. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. If a value other than SQLITE_OK is returned, the state the +** pInfo->aMatchinfo[] buffer is left in is undefined. +*/ +static int fts3MatchinfoValues( + Fts3Cursor *pCsr, /* FTS3 cursor object */ + int bGlobal, /* True to grab the global stats */ + MatchInfo *pInfo, /* Matchinfo context object */ + const char *zArg /* Matchinfo format string */ +){ + int rc = SQLITE_OK; + int i; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + sqlite3_stmt *pSelect = 0; + + for(i=0; rc==SQLITE_OK && zArg[i]; i++){ + pInfo->flag = zArg[i]; + switch( zArg[i] ){ + case FTS3_MATCHINFO_NPHRASE: + if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase; + break; + + case FTS3_MATCHINFO_NCOL: + if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol; + break; + + case FTS3_MATCHINFO_NDOC: + if( bGlobal ){ + sqlite3_int64 nDoc = 0; + rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0); + pInfo->aMatchinfo[0] = (u32)nDoc; + } + break; + + case FTS3_MATCHINFO_AVGLENGTH: + if( bGlobal ){ + sqlite3_int64 nDoc; /* Number of rows in table */ + const char *a; /* Aggregate column length array */ + + rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a); + if( rc==SQLITE_OK ){ + int iCol; + for(iCol=0; iColnCol; iCol++){ + u32 iVal; + sqlite3_int64 nToken; + a += sqlite3Fts3GetVarint(a, &nToken); + iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc); + pInfo->aMatchinfo[iCol] = iVal; + } + } + } + break; + + case FTS3_MATCHINFO_LENGTH: { + sqlite3_stmt *pSelectDocsize = 0; + rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize); + if( rc==SQLITE_OK ){ + int iCol; + const char *a = sqlite3_column_blob(pSelectDocsize, 0); + for(iCol=0; iColnCol; iCol++){ + sqlite3_int64 nToken; + a += sqlite3Fts3GetVarint(a, &nToken); + pInfo->aMatchinfo[iCol] = (u32)nToken; + } + } + sqlite3_reset(pSelectDocsize); + break; + } + + case FTS3_MATCHINFO_LCS: + rc = fts3ExprLoadDoclists(pCsr, 0, 0); + if( rc==SQLITE_OK ){ + rc = fts3MatchinfoLcs(pCsr, pInfo); + } + break; + + case FTS3_MATCHINFO_LHITS_BM: + case FTS3_MATCHINFO_LHITS: { + int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); + memset(pInfo->aMatchinfo, 0, nZero); + fts3ExprLHitGather(pCsr->pExpr, pInfo); + break; + } + + default: { + Fts3Expr *pExpr; + assert( zArg[i]==FTS3_MATCHINFO_HITS ); + pExpr = pCsr->pExpr; + rc = fts3ExprLoadDoclists(pCsr, 0, 0); + if( rc!=SQLITE_OK ) break; + if( bGlobal ){ + if( pCsr->pDeferred ){ + rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0); + if( rc!=SQLITE_OK ) break; + } + rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); + sqlite3Fts3EvalTestDeferred(pCsr, &rc); + if( rc!=SQLITE_OK ) break; + } + (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); + break; + } + } + + pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]); + } + + sqlite3_reset(pSelect); + return rc; +} + + +/* +** Populate pCsr->aMatchinfo[] with data for the current row. The +** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32). +*/ +static void fts3GetMatchinfo( + sqlite3_context *pCtx, /* Return results here */ + Fts3Cursor *pCsr, /* FTS3 Cursor object */ + const char *zArg /* Second argument to matchinfo() function */ +){ + MatchInfo sInfo; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int bGlobal = 0; /* Collect 'global' stats as well as local */ + + u32 *aOut = 0; + void (*xDestroyOut)(void*) = 0; + + memset(&sInfo, 0, sizeof(MatchInfo)); + sInfo.pCursor = pCsr; + sInfo.nCol = pTab->nColumn; + + /* If there is cached matchinfo() data, but the format string for the + ** cache does not match the format string for this request, discard + ** the cached data. */ + if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){ + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + pCsr->pMIBuffer = 0; + } + + /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the + ** matchinfo function has been called for this query. In this case + ** allocate the array used to accumulate the matchinfo data and + ** initialize those elements that are constant for every row. + */ + if( pCsr->pMIBuffer==0 ){ + int nMatchinfo = 0; /* Number of u32 elements in match-info */ + int i; /* Used to iterate through zArg */ + + /* Determine the number of phrases in the query */ + pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr); + sInfo.nPhrase = pCsr->nPhrase; + + /* Determine the number of integers in the buffer returned by this call. */ + for(i=0; zArg[i]; i++){ + char *zErr = 0; + if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){ + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + return; + } + nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]); + } + + /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */ + pCsr->pMIBuffer = fts3MIBufferNew(nMatchinfo, zArg); + if( !pCsr->pMIBuffer ) rc = SQLITE_NOMEM; + + pCsr->isMatchinfoNeeded = 1; + bGlobal = 1; + } + + if( rc==SQLITE_OK ){ + xDestroyOut = fts3MIBufferAlloc(pCsr->pMIBuffer, &aOut); + if( xDestroyOut==0 ){ + rc = SQLITE_NOMEM; + } + } + + if( rc==SQLITE_OK ){ + sInfo.aMatchinfo = aOut; + sInfo.nPhrase = pCsr->nPhrase; + rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg); + if( bGlobal ){ + fts3MIBufferSetGlobal(pCsr->pMIBuffer); + } + } + + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + if( xDestroyOut ) xDestroyOut(aOut); + }else{ + int n = pCsr->pMIBuffer->nElem * sizeof(u32); + sqlite3_result_blob(pCtx, aOut, n, xDestroyOut); + } +} + +/* +** Implementation of snippet() function. +*/ +SQLITE_PRIVATE void sqlite3Fts3Snippet( + sqlite3_context *pCtx, /* SQLite function call context */ + Fts3Cursor *pCsr, /* Cursor object */ + const char *zStart, /* Snippet start text - "" */ + const char *zEnd, /* Snippet end text - "" */ + const char *zEllipsis, /* Snippet ellipsis text - "..." */ + int iCol, /* Extract snippet from this column */ + int nToken /* Approximate number of tokens in snippet */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int i; + StrBuffer res = {0, 0, 0}; + + /* The returned text includes up to four fragments of text extracted from + ** the data in the current row. The first iteration of the for(...) loop + ** below attempts to locate a single fragment of text nToken tokens in + ** size that contains at least one instance of all phrases in the query + ** expression that appear in the current row. If such a fragment of text + ** cannot be found, the second iteration of the loop attempts to locate + ** a pair of fragments, and so on. + */ + int nSnippet = 0; /* Number of fragments in this snippet */ + SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */ + int nFToken = -1; /* Number of tokens in each fragment */ + + if( !pCsr->pExpr ){ + sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); + return; + } + + for(nSnippet=1; 1; nSnippet++){ + + int iSnip; /* Loop counter 0..nSnippet-1 */ + u64 mCovered = 0; /* Bitmask of phrases covered by snippet */ + u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */ + + if( nToken>=0 ){ + nFToken = (nToken+nSnippet-1) / nSnippet; + }else{ + nFToken = -1 * nToken; + } + + for(iSnip=0; iSnipnColumn; iRead++){ + SnippetFragment sF = {0, 0, 0, 0}; + int iS = 0; + if( iCol>=0 && iRead!=iCol ) continue; + + /* Find the best snippet of nFToken tokens in column iRead. */ + rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS); + if( rc!=SQLITE_OK ){ + goto snippet_out; + } + if( iS>iBestScore ){ + *pFragment = sF; + iBestScore = iS; + } + } + + mCovered |= pFragment->covered; + } + + /* If all query phrases seen by fts3BestSnippet() are present in at least + ** one of the nSnippet snippet fragments, break out of the loop. + */ + assert( (mCovered&mSeen)==mCovered ); + if( mSeen==mCovered || nSnippet==SizeofArray(aSnippet) ) break; + } + + assert( nFToken>0 ); + + for(i=0; ipCsr, pExpr, p->iCol, &pList); + nTerm = pExpr->pPhrase->nToken; + if( pList ){ + fts3GetDeltaPosition(&pList, &iPos); + assert( iPos>=0 ); + } + + for(iTerm=0; iTermaTerm[p->iTerm++]; + pT->iOff = nTerm-iTerm-1; + pT->pList = pList; + pT->iPos = iPos; + } + + return rc; +} + +/* +** Implementation of offsets() function. +*/ +SQLITE_PRIVATE void sqlite3Fts3Offsets( + sqlite3_context *pCtx, /* SQLite function call context */ + Fts3Cursor *pCsr /* Cursor object */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule; + int rc; /* Return Code */ + int nToken; /* Number of tokens in query */ + int iCol; /* Column currently being processed */ + StrBuffer res = {0, 0, 0}; /* Result string */ + TermOffsetCtx sCtx; /* Context for fts3ExprTermOffsetInit() */ + + if( !pCsr->pExpr ){ + sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); + return; + } + + memset(&sCtx, 0, sizeof(sCtx)); + assert( pCsr->isRequireSeek==0 ); + + /* Count the number of terms in the query */ + rc = fts3ExprLoadDoclists(pCsr, 0, &nToken); + if( rc!=SQLITE_OK ) goto offsets_out; + + /* Allocate the array of TermOffset iterators. */ + sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken); + if( 0==sCtx.aTerm ){ + rc = SQLITE_NOMEM; + goto offsets_out; + } + sCtx.iDocid = pCsr->iPrevId; + sCtx.pCsr = pCsr; + + /* Loop through the table columns, appending offset information to + ** string-buffer res for each column. + */ + for(iCol=0; iColnColumn; iCol++){ + sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */ + const char *ZDUMMY; /* Dummy argument used with xNext() */ + int NDUMMY = 0; /* Dummy argument used with xNext() */ + int iStart = 0; + int iEnd = 0; + int iCurrent = 0; + const char *zDoc; + int nDoc; + + /* Initialize the contents of sCtx.aTerm[] for column iCol. There is + ** no way that this operation can fail, so the return code from + ** fts3ExprIterate() can be discarded. + */ + sCtx.iCol = iCol; + sCtx.iTerm = 0; + (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); + + /* Retreive the text stored in column iCol. If an SQL NULL is stored + ** in column iCol, jump immediately to the next iteration of the loop. + ** If an OOM occurs while retrieving the data (this can happen if SQLite + ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM + ** to the caller. + */ + zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1); + nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1); + if( zDoc==0 ){ + if( sqlite3_column_type(pCsr->pStmt, iCol+1)==SQLITE_NULL ){ + continue; + } + rc = SQLITE_NOMEM; + goto offsets_out; + } + + /* Initialize a tokenizer iterator to iterate through column iCol. */ + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, + zDoc, nDoc, &pC + ); + if( rc!=SQLITE_OK ) goto offsets_out; + + rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); + while( rc==SQLITE_OK ){ + int i; /* Used to loop through terms */ + int iMinPos = 0x7FFFFFFF; /* Position of next token */ + TermOffset *pTerm = 0; /* TermOffset associated with next token */ + + for(i=0; ipList && (pT->iPos-pT->iOff)iPos-pT->iOff; + pTerm = pT; + } + } + + if( !pTerm ){ + /* All offsets for this column have been gathered. */ + rc = SQLITE_DONE; + }else{ + assert( iCurrent<=iMinPos ); + if( 0==(0xFE&*pTerm->pList) ){ + pTerm->pList = 0; + }else{ + fts3GetDeltaPosition(&pTerm->pList, &pTerm->iPos); + } + while( rc==SQLITE_OK && iCurrentxNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); + } + if( rc==SQLITE_OK ){ + char aBuffer[64]; + sqlite3_snprintf(sizeof(aBuffer), aBuffer, + "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart + ); + rc = fts3StringAppend(&res, aBuffer, -1); + }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){ + rc = FTS_CORRUPT_VTAB; + } + } + } + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + } + + pMod->xClose(pC); + if( rc!=SQLITE_OK ) goto offsets_out; + } + + offsets_out: + sqlite3_free(sCtx.aTerm); + assert( rc!=SQLITE_DONE ); + sqlite3Fts3SegmentsClose(pTab); + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + sqlite3_free(res.z); + }else{ + sqlite3_result_text(pCtx, res.z, res.n-1, sqlite3_free); + } + return; +} + +/* +** Implementation of matchinfo() function. +*/ +SQLITE_PRIVATE void sqlite3Fts3Matchinfo( + sqlite3_context *pContext, /* Function call context */ + Fts3Cursor *pCsr, /* FTS3 table cursor */ + const char *zArg /* Second arg to matchinfo() function */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + const char *zFormat; + + if( zArg ){ + zFormat = zArg; + }else{ + zFormat = FTS3_MATCHINFO_DEFAULT; + } + + if( !pCsr->pExpr ){ + sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC); + return; + }else{ + /* Retrieve matchinfo() data. */ + fts3GetMatchinfo(pContext, pCsr, zFormat); + sqlite3Fts3SegmentsClose(pTab); + } +} + +#endif + +/************** End of fts3_snippet.c ****************************************/ +/************** Begin file fts3_unicode.c ************************************/ +/* +** 2012 May 24 +** +** 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. +** +****************************************************************************** +** +** Implementation of the "unicode" full-text-search tokenizer. +*/ + +#ifndef SQLITE_DISABLE_FTS3_UNICODE + +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +/* #include "fts3_tokenizer.h" */ + +/* +** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied +** from the sqlite3 source file utf.c. If this file is compiled as part +** of the amalgamation, they are not required. +*/ +#ifndef SQLITE_AMALGAMATION + +static const unsigned char sqlite3Utf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + +#define READ_UTF8(zIn, zTerm, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = sqlite3Utf8Trans1[c-0xc0]; \ + while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + if( c<0x80 \ + || (c&0xFFFFF800)==0xD800 \ + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ + } + +#define WRITE_UTF8(zOut, c) { \ + if( c<0x00080 ){ \ + *zOut++ = (u8)(c&0xFF); \ + } \ + else if( c<0x00800 ){ \ + *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + } \ + else if( c<0x10000 ){ \ + *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \ + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + }else{ \ + *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \ + *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \ + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + } \ +} + +#endif /* ifndef SQLITE_AMALGAMATION */ + +typedef struct unicode_tokenizer unicode_tokenizer; +typedef struct unicode_cursor unicode_cursor; + +struct unicode_tokenizer { + sqlite3_tokenizer base; + int bRemoveDiacritic; + int nException; + int *aiException; +}; + +struct unicode_cursor { + sqlite3_tokenizer_cursor base; + const unsigned char *aInput; /* Input text being tokenized */ + int nInput; /* Size of aInput[] in bytes */ + int iOff; /* Current offset within aInput[] */ + int iToken; /* Index of next token to be returned */ + char *zToken; /* storage for current token */ + int nAlloc; /* space allocated at zToken */ +}; + + +/* +** Destroy a tokenizer allocated by unicodeCreate(). +*/ +static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){ + if( pTokenizer ){ + unicode_tokenizer *p = (unicode_tokenizer *)pTokenizer; + sqlite3_free(p->aiException); + sqlite3_free(p); + } + return SQLITE_OK; +} + +/* +** As part of a tokenchars= or separators= option, the CREATE VIRTUAL TABLE +** statement has specified that the tokenizer for this table shall consider +** all characters in string zIn/nIn to be separators (if bAlnum==0) or +** token characters (if bAlnum==1). +** +** For each codepoint in the zIn/nIn string, this function checks if the +** sqlite3FtsUnicodeIsalnum() function already returns the desired result. +** If so, no action is taken. Otherwise, the codepoint is added to the +** unicode_tokenizer.aiException[] array. For the purposes of tokenization, +** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all +** codepoints in the aiException[] array. +** +** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic() +** identifies as a diacritic) occurs in the zIn/nIn string it is ignored. +** It is not possible to change the behavior of the tokenizer with respect +** to these codepoints. +*/ +static int unicodeAddExceptions( + unicode_tokenizer *p, /* Tokenizer to add exceptions to */ + int bAlnum, /* Replace Isalnum() return value with this */ + const char *zIn, /* Array of characters to make exceptions */ + int nIn /* Length of z in bytes */ +){ + const unsigned char *z = (const unsigned char *)zIn; + const unsigned char *zTerm = &z[nIn]; + unsigned int iCode; + int nEntry = 0; + + assert( bAlnum==0 || bAlnum==1 ); + + while( zaiException, (p->nException+nEntry)*sizeof(int)); + if( aNew==0 ) return SQLITE_NOMEM; + nNew = p->nException; + + z = (const unsigned char *)zIn; + while( zi; j--) aNew[j] = aNew[j-1]; + aNew[i] = (int)iCode; + nNew++; + } + } + p->aiException = aNew; + p->nException = nNew; + } + + return SQLITE_OK; +} + +/* +** Return true if the p->aiException[] array contains the value iCode. +*/ +static int unicodeIsException(unicode_tokenizer *p, int iCode){ + if( p->nException>0 ){ + int *a = p->aiException; + int iLo = 0; + int iHi = p->nException-1; + + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( iCode==a[iTest] ){ + return 1; + }else if( iCode>a[iTest] ){ + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + } + + return 0; +} + +/* +** Return true if, for the purposes of tokenization, codepoint iCode is +** considered a token character (not a separator). +*/ +static int unicodeIsAlnum(unicode_tokenizer *p, int iCode){ + assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 ); + return sqlite3FtsUnicodeIsalnum(iCode) ^ unicodeIsException(p, iCode); +} + +/* +** Create a new tokenizer instance. +*/ +static int unicodeCreate( + int nArg, /* Size of array argv[] */ + const char * const *azArg, /* Tokenizer creation arguments */ + sqlite3_tokenizer **pp /* OUT: New tokenizer handle */ +){ + unicode_tokenizer *pNew; /* New tokenizer object */ + int i; + int rc = SQLITE_OK; + + pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer)); + if( pNew==NULL ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(unicode_tokenizer)); + pNew->bRemoveDiacritic = 1; + + for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = 1; + } + else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){ + pNew->bRemoveDiacritic = 0; + } + else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){ + rc = unicodeAddExceptions(pNew, 1, &z[11], n-11); + } + else if( n>=11 && memcmp("separators=", z, 11)==0 ){ + rc = unicodeAddExceptions(pNew, 0, &z[11], n-11); + } + else{ + /* Unrecognized argument */ + rc = SQLITE_ERROR; + } + } + + if( rc!=SQLITE_OK ){ + unicodeDestroy((sqlite3_tokenizer *)pNew); + pNew = 0; + } + *pp = (sqlite3_tokenizer *)pNew; + return rc; +} + +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is pInput[0..nBytes-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int unicodeOpen( + sqlite3_tokenizer *p, /* The tokenizer */ + const char *aInput, /* Input string */ + int nInput, /* Size of string aInput in bytes */ + sqlite3_tokenizer_cursor **pp /* OUT: New cursor object */ +){ + unicode_cursor *pCsr; + + pCsr = (unicode_cursor *)sqlite3_malloc(sizeof(unicode_cursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(unicode_cursor)); + + pCsr->aInput = (const unsigned char *)aInput; + if( aInput==0 ){ + pCsr->nInput = 0; + }else if( nInput<0 ){ + pCsr->nInput = (int)strlen(aInput); + }else{ + pCsr->nInput = nInput; + } + + *pp = &pCsr->base; + UNUSED_PARAMETER(p); + return SQLITE_OK; +} + +/* +** Close a tokenization cursor previously opened by a call to +** simpleOpen() above. +*/ +static int unicodeClose(sqlite3_tokenizer_cursor *pCursor){ + unicode_cursor *pCsr = (unicode_cursor *) pCursor; + sqlite3_free(pCsr->zToken); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Extract the next token from a tokenization cursor. The cursor must +** have been opened by a prior call to simpleOpen(). +*/ +static int unicodeNext( + sqlite3_tokenizer_cursor *pC, /* Cursor returned by simpleOpen */ + const char **paToken, /* OUT: Token text */ + int *pnToken, /* OUT: Number of bytes at *paToken */ + int *piStart, /* OUT: Starting offset of token */ + int *piEnd, /* OUT: Ending offset of token */ + int *piPos /* OUT: Position integer of token */ +){ + unicode_cursor *pCsr = (unicode_cursor *)pC; + unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer); + unsigned int iCode = 0; + char *zOut; + const unsigned char *z = &pCsr->aInput[pCsr->iOff]; + const unsigned char *zStart = z; + const unsigned char *zEnd; + const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput]; + + /* Scan past any delimiter characters before the start of the next token. + ** Return SQLITE_DONE early if this takes us all the way to the end of + ** the input. */ + while( z=zTerm ) return SQLITE_DONE; + + zOut = pCsr->zToken; + do { + int iOut; + + /* Grow the output buffer if required. */ + if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){ + char *zNew = sqlite3_realloc(pCsr->zToken, pCsr->nAlloc+64); + if( !zNew ) return SQLITE_NOMEM; + zOut = &zNew[zOut - pCsr->zToken]; + pCsr->zToken = zNew; + pCsr->nAlloc += 64; + } + + /* Write the folded case of the last character read to the output */ + zEnd = z; + iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic); + if( iOut ){ + WRITE_UTF8(zOut, iOut); + } + + /* If the cursor is not at EOF, read the next character */ + if( z>=zTerm ) break; + READ_UTF8(z, zTerm, iCode); + }while( unicodeIsAlnum(p, (int)iCode) + || sqlite3FtsUnicodeIsdiacritic((int)iCode) + ); + + /* Set the output variables and return. */ + pCsr->iOff = (int)(z - pCsr->aInput); + *paToken = pCsr->zToken; + *pnToken = (int)(zOut - pCsr->zToken); + *piStart = (int)(zStart - pCsr->aInput); + *piEnd = (int)(zEnd - pCsr->aInput); + *piPos = pCsr->iToken++; + return SQLITE_OK; +} + +/* +** Set *ppModule to a pointer to the sqlite3_tokenizer_module +** structure for the unicode tokenizer. +*/ +SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){ + static const sqlite3_tokenizer_module module = { + 0, + unicodeCreate, + unicodeDestroy, + unicodeOpen, + unicodeClose, + unicodeNext, + 0, + }; + *ppModule = &module; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ +#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */ + +/************** End of fts3_unicode.c ****************************************/ +/************** Begin file fts3_unicode2.c ***********************************/ +/* +** 2012 May 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. +** +****************************************************************************** +*/ + +/* +** DO NOT EDIT THIS MACHINE GENERATED FILE. +*/ + +#ifndef SQLITE_DISABLE_FTS3_UNICODE +#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) + +/* #include */ + +/* +** Return true if the argument corresponds to a unicode codepoint +** classified as either a letter or a number. Otherwise false. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ + /* Each unsigned integer in the following array corresponds to a contiguous + ** range of unicode codepoints that are not either letters or numbers (i.e. + ** codepoints for which this function should return 0). + ** + ** The most significant 22 bits in each 32-bit value contain the first + ** codepoint in the range. The least significant 10 bits are used to store + ** the size of the range (always at least 1). In other words, the value + ** ((C<<22) + N) represents a range of N codepoints starting with codepoint + ** C. It is not possible to represent a range larger than 1023 codepoints + ** using this format. + */ + static const unsigned int aEntry[] = { + 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, + 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, + 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, + 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, + 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, + 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, + 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, + 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, + 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, + 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, + 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, + 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, + 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, + 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, + 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, + 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, + 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, + 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, + 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, + 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, + 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, + 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, + 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, + 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, + 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, + 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, + 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, + 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, + 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, + 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, + 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, + 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, + 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, + 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, + 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, + 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, + 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, + 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, + 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, + 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, + 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, + 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, + 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, + 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, + 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, + 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, + 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, + 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, + 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, + 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, + 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, + 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, + 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, + 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, + 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, + 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, + 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, + 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, + 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, + 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, + 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, + 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, + 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, + 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, + 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, + 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, + 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, + 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, + 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, + 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, + 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, + 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, + 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, + 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, + 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, + 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, + 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, + 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, + 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, + 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, + 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, + 0x380400F0, + }; + static const unsigned int aAscii[4] = { + 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, + }; + + if( (unsigned int)c<128 ){ + return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 ); + }else if( (unsigned int)c<(1<<22) ){ + unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; + int iRes = 0; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aEntry[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + assert( aEntry[0]=aEntry[iRes] ); + return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); + } + return 1; +} + + +/* +** If the argument is a codepoint corresponding to a lowercase letter +** in the ASCII range with a diacritic added, return the codepoint +** of the ASCII letter only. For example, if passed 235 - "LATIN +** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER +** E"). The resuls of passing a codepoint that corresponds to an +** uppercase letter are undefined. +*/ +static int remove_diacritic(int c){ + unsigned short aDia[] = { + 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, + 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, + 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, + 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, + 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, + 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, + 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, + 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, + 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, + 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, + 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, + 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, + 62924, 63050, 63082, 63274, 63390, + }; + char aChar[] = { + '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', + 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', + 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', + 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', + 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', + 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', + 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', + 'e', 'i', 'o', 'u', 'y', + }; + + unsigned int key = (((unsigned int)c)<<3) | 0x00000007; + int iRes = 0; + int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aDia[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + assert( key>=aDia[iRes] ); + return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); +} + + +/* +** Return true if the argument interpreted as a unicode codepoint +** is a diacritical modifier character. +*/ +SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){ + unsigned int mask0 = 0x08029FDF; + unsigned int mask1 = 0x000361F8; + if( c<768 || c>817 ) return 0; + return (c < 768+32) ? + (mask0 & (1 << (c-768))) : + (mask1 & (1 << (c-768-32))); +} + + +/* +** Interpret the argument as a unicode codepoint. If the codepoint +** is an upper case character that has a lower case equivalent, +** return the codepoint corresponding to the lower case version. +** Otherwise, return a copy of the argument. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ + /* Each entry in the following array defines a rule for folding a range + ** of codepoints to lower case. The rule applies to a range of nRange + ** codepoints starting at codepoint iCode. + ** + ** If the least significant bit in flags is clear, then the rule applies + ** to all nRange codepoints (i.e. all nRange codepoints are upper case and + ** need to be folded). Or, if it is set, then the rule only applies to + ** every second codepoint in the range, starting with codepoint C. + ** + ** The 7 most significant bits in flags are an index into the aiOff[] + ** array. If a specific codepoint C does require folding, then its lower + ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF). + ** + ** The contents of this array are generated by parsing the CaseFolding.txt + ** file distributed as part of the "Unicode Character Database". See + ** http://www.unicode.org for details. + */ + static const struct TableEntry { + unsigned short iCode; + unsigned char flags; + unsigned char nRange; + } aEntry[] = { + {65, 14, 26}, {181, 64, 1}, {192, 14, 23}, + {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, + {313, 1, 16}, {330, 1, 46}, {376, 116, 1}, + {377, 1, 6}, {383, 104, 1}, {385, 50, 1}, + {386, 1, 4}, {390, 44, 1}, {391, 0, 1}, + {393, 42, 2}, {395, 0, 1}, {398, 32, 1}, + {399, 38, 1}, {400, 40, 1}, {401, 0, 1}, + {403, 42, 1}, {404, 46, 1}, {406, 52, 1}, + {407, 48, 1}, {408, 0, 1}, {412, 52, 1}, + {413, 54, 1}, {415, 56, 1}, {416, 1, 6}, + {422, 60, 1}, {423, 0, 1}, {425, 60, 1}, + {428, 0, 1}, {430, 60, 1}, {431, 0, 1}, + {433, 58, 2}, {435, 1, 4}, {439, 62, 1}, + {440, 0, 1}, {444, 0, 1}, {452, 2, 1}, + {453, 0, 1}, {455, 2, 1}, {456, 0, 1}, + {458, 2, 1}, {459, 1, 18}, {478, 1, 18}, + {497, 2, 1}, {498, 1, 4}, {502, 122, 1}, + {503, 134, 1}, {504, 1, 40}, {544, 110, 1}, + {546, 1, 18}, {570, 70, 1}, {571, 0, 1}, + {573, 108, 1}, {574, 68, 1}, {577, 0, 1}, + {579, 106, 1}, {580, 28, 1}, {581, 30, 1}, + {582, 1, 10}, {837, 36, 1}, {880, 1, 4}, + {886, 0, 1}, {902, 18, 1}, {904, 16, 3}, + {908, 26, 1}, {910, 24, 2}, {913, 14, 17}, + {931, 14, 9}, {962, 0, 1}, {975, 4, 1}, + {976, 140, 1}, {977, 142, 1}, {981, 146, 1}, + {982, 144, 1}, {984, 1, 24}, {1008, 136, 1}, + {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1}, + {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1}, + {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32}, + {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1}, + {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38}, + {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1}, + {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1}, + {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6}, + {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6}, + {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8}, + {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2}, + {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1}, + {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2}, + {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2}, + {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2}, + {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1}, + {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16}, + {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47}, + {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1}, + {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1}, + {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1}, + {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2}, + {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1}, + {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14}, + {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1}, + {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1}, + {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1}, + {65313, 14, 26}, + }; + static const unsigned short aiOff[] = { + 1, 2, 8, 15, 16, 26, 28, 32, + 37, 38, 40, 48, 63, 64, 69, 71, + 79, 80, 116, 202, 203, 205, 206, 207, + 209, 210, 211, 213, 214, 217, 218, 219, + 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, + 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, + 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, + 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, + 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, + 65514, 65521, 65527, 65528, 65529, + }; + + int ret = c; + + assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); + + if( c<128 ){ + if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); + }else if( c<65536 ){ + const struct TableEntry *p; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + int iRes = -1; + + assert( c>aEntry[0].iCode ); + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + int cmp = (c - aEntry[iTest].iCode); + if( cmp>=0 ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; + } + } + + assert( iRes>=0 && c>=aEntry[iRes].iCode ); + p = &aEntry[iRes]; + if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ + ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; + assert( ret>0 ); + } + + if( bRemoveDiacritic ) ret = remove_diacritic(ret); + } + + else if( c>=66560 && c<66600 ){ + ret = c + 40; + } + + return ret; +} +#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */ +#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */ + +/************** End of fts3_unicode2.c ***************************************/ +/************** Begin file rtree.c *******************************************/ +/* +** 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 for implementations of the r-tree and r*-tree +** algorithms packaged as an SQLite virtual table module. +*/ + +/* +** Database Format of R-Tree Tables +** -------------------------------- +** +** The data structure for a single virtual r-tree table is stored in three +** native SQLite tables declared as follows. In each case, the '%' character +** in the table name is replaced with the user-supplied name of the r-tree +** table. +** +** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB) +** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) +** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER) +** +** The data for each node of the r-tree structure is stored in the %_node +** table. For each node that is not the root node of the r-tree, there is +** an entry in the %_parent table associating the node with its parent. +** And for each row of data in the table, there is an entry in the %_rowid +** table that maps from the entries rowid to the id of the node that it +** is stored on. +** +** The root node of an r-tree always exists, even if the r-tree table is +** empty. The nodeno of the root node is always 1. All other nodes in the +** table must be the same size as the root node. The content of each node +** is formatted as follows: +** +** 1. If the node is the root node (node 1), then the first 2 bytes +** of the node contain the tree depth as a big-endian integer. +** For non-root nodes, the first 2 bytes are left unused. +** +** 2. The next 2 bytes contain the number of entries currently +** stored in the node. +** +** 3. The remainder of the node contains the node entries. Each entry +** consists of a single 8-byte integer followed by an even number +** of 4-byte coordinates. For leaf nodes the integer is the rowid +** of a record. For internal nodes it is the node number of a +** child page. +*/ + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE) + +#ifndef SQLITE_CORE +/* #include "sqlite3ext.h" */ + SQLITE_EXTENSION_INIT1 +#else +/* #include "sqlite3.h" */ +#endif + +/* #include */ +/* #include */ +/* #include */ + +#ifndef SQLITE_AMALGAMATION +#include "sqlite3rtree.h" +typedef sqlite3_int64 i64; +typedef sqlite3_uint64 u64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +#endif + +/* The following macro is used to suppress compiler warnings. +*/ +#ifndef UNUSED_PARAMETER +# define UNUSED_PARAMETER(x) (void)(x) +#endif + +typedef struct Rtree Rtree; +typedef struct RtreeCursor RtreeCursor; +typedef struct RtreeNode RtreeNode; +typedef struct RtreeCell RtreeCell; +typedef struct RtreeConstraint RtreeConstraint; +typedef struct RtreeMatchArg RtreeMatchArg; +typedef struct RtreeGeomCallback RtreeGeomCallback; +typedef union RtreeCoord RtreeCoord; +typedef struct RtreeSearchPoint RtreeSearchPoint; + +/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ +#define RTREE_MAX_DIMENSIONS 5 + +/* Size of hash table Rtree.aHash. This hash table is not expected to +** ever contain very many entries, so a fixed number of buckets is +** used. +*/ +#define HASHSIZE 97 + +/* The xBestIndex method of this virtual table requires an estimate of +** the number of rows in the virtual table to calculate the costs of +** various strategies. If possible, this estimate is loaded from the +** sqlite_stat1 table (with RTREE_MIN_ROWEST as a hard-coded minimum). +** Otherwise, if no sqlite_stat1 entry is available, use +** RTREE_DEFAULT_ROWEST. +*/ +#define RTREE_DEFAULT_ROWEST 1048576 +#define RTREE_MIN_ROWEST 100 + +/* +** An rtree virtual-table object. +*/ +struct Rtree { + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* Host database connection */ + int iNodeSize; /* Size in bytes of each node in the node table */ + u8 nDim; /* Number of dimensions */ + u8 nDim2; /* Twice the number of dimensions */ + u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ + u8 nBytesPerCell; /* Bytes consumed per cell */ + u8 inWrTrans; /* True if inside write transaction */ + int iDepth; /* Current depth of the r-tree structure */ + char *zDb; /* Name of database containing r-tree table */ + char *zName; /* Name of r-tree table */ + u32 nBusy; /* Current number of users of this structure */ + i64 nRowEst; /* Estimated number of rows in this table */ + u32 nCursor; /* Number of open cursors */ + + /* List of nodes removed during a CondenseTree operation. List is + ** linked together via the pointer normally used for hash chains - + ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree + ** headed by the node (leaf nodes have RtreeNode.iNode==0). + */ + RtreeNode *pDeleted; + int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */ + + /* Blob I/O on xxx_node */ + sqlite3_blob *pNodeBlob; + + /* Statements to read/write/delete a record from xxx_node */ + sqlite3_stmt *pWriteNode; + sqlite3_stmt *pDeleteNode; + + /* Statements to read/write/delete a record from xxx_rowid */ + sqlite3_stmt *pReadRowid; + sqlite3_stmt *pWriteRowid; + sqlite3_stmt *pDeleteRowid; + + /* Statements to read/write/delete a record from xxx_parent */ + sqlite3_stmt *pReadParent; + sqlite3_stmt *pWriteParent; + sqlite3_stmt *pDeleteParent; + + RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ +}; + +/* Possible values for Rtree.eCoordType: */ +#define RTREE_COORD_REAL32 0 +#define RTREE_COORD_INT32 1 + +/* +** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will +** only deal with integer coordinates. No floating point operations +** will be done. +*/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ + typedef int RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0 +#else + typedef double RtreeDValue; /* High accuracy coordinate */ + typedef float RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0.0 +#endif + +/* +** When doing a search of an r-tree, instances of the following structure +** record intermediate results from the tree walk. +** +** The id is always a node-id. For iLevel>=1 the id is the node-id of +** the node that the RtreeSearchPoint represents. When iLevel==0, however, +** the id is of the parent node and the cell that RtreeSearchPoint +** represents is the iCell-th entry in the parent node. +*/ +struct RtreeSearchPoint { + RtreeDValue rScore; /* The score for this node. Smallest goes first. */ + sqlite3_int64 id; /* Node ID */ + u8 iLevel; /* 0=entries. 1=leaf node. 2+ for higher */ + u8 eWithin; /* PARTLY_WITHIN or FULLY_WITHIN */ + u8 iCell; /* Cell index within the node */ +}; + +/* +** The minimum number of cells allowed for a node is a third of the +** maximum. In Gutman's notation: +** +** m = M/3 +** +** If an R*-tree "Reinsert" operation is required, the same number of +** cells are removed from the overfull node and reinserted into the tree. +*/ +#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3) +#define RTREE_REINSERT(p) RTREE_MINCELLS(p) +#define RTREE_MAXCELLS 51 + +/* +** The smallest possible node-size is (512-64)==448 bytes. And the largest +** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates). +** Therefore all non-root nodes must contain at least 3 entries. Since +** 2^40 is greater than 2^64, an r-tree structure always has a depth of +** 40 or less. +*/ +#define RTREE_MAX_DEPTH 40 + + +/* +** Number of entries in the cursor RtreeNode cache. The first entry is +** used to cache the RtreeNode for RtreeCursor.sPoint. The remaining +** entries cache the RtreeNode for the first elements of the priority queue. +*/ +#define RTREE_CACHE_SZ 5 + +/* +** An rtree cursor object. +*/ +struct RtreeCursor { + sqlite3_vtab_cursor base; /* Base class. Must be first */ + u8 atEOF; /* True if at end of search */ + u8 bPoint; /* True if sPoint is valid */ + int iStrategy; /* Copy of idxNum search parameter */ + int nConstraint; /* Number of entries in aConstraint */ + RtreeConstraint *aConstraint; /* Search constraints. */ + int nPointAlloc; /* Number of slots allocated for aPoint[] */ + int nPoint; /* Number of slots used in aPoint[] */ + int mxLevel; /* iLevel value for root of the tree */ + RtreeSearchPoint *aPoint; /* Priority queue for search points */ + RtreeSearchPoint sPoint; /* Cached next search point */ + RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ + u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ +}; + +/* Return the Rtree of a RtreeCursor */ +#define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) + +/* +** A coordinate can be either a floating point number or a integer. All +** coordinates within a single R-Tree are always of the same time. +*/ +union RtreeCoord { + RtreeValue f; /* Floating point value */ + int i; /* Integer value */ + u32 u; /* Unsigned for byte-order conversions */ +}; + +/* +** The argument is an RtreeCoord. Return the value stored within the RtreeCoord +** formatted as a RtreeDValue (double or int64). This macro assumes that local +** variable pRtree points to the Rtree structure associated with the +** RtreeCoord. +*/ +#ifdef SQLITE_RTREE_INT_ONLY +# define DCOORD(coord) ((RtreeDValue)coord.i) +#else +# define DCOORD(coord) ( \ + (pRtree->eCoordType==RTREE_COORD_REAL32) ? \ + ((double)coord.f) : \ + ((double)coord.i) \ + ) +#endif + +/* +** A search constraint. +*/ +struct RtreeConstraint { + int iCoord; /* Index of constrained coordinate */ + int op; /* Constraining operation */ + union { + RtreeDValue rValue; /* Constraint value. */ + int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + } u; + sqlite3_rtree_query_info *pInfo; /* xGeom and xQueryFunc argument */ +}; + +/* Possible values for RtreeConstraint.op */ +#define RTREE_EQ 0x41 /* A */ +#define RTREE_LE 0x42 /* B */ +#define RTREE_LT 0x43 /* C */ +#define RTREE_GE 0x44 /* D */ +#define RTREE_GT 0x45 /* E */ +#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ +#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ + + +/* +** An rtree structure node. +*/ +struct RtreeNode { + RtreeNode *pParent; /* Parent node */ + i64 iNode; /* The node number */ + int nRef; /* Number of references to this node */ + int isDirty; /* True if the node needs to be written to disk */ + u8 *zData; /* Content of the node, as should be on disk */ + RtreeNode *pNext; /* Next node in this hash collision chain */ +}; + +/* Return the number of cells in a node */ +#define NCELL(pNode) readInt16(&(pNode)->zData[2]) + +/* +** A single cell from a node, deserialized +*/ +struct RtreeCell { + i64 iRowid; /* Node or entry ID */ + RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; /* Bounding box coordinates */ +}; + + +/* +** This object becomes the sqlite3_user_data() for the SQL functions +** that are created by sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() and which appear on the right of MATCH +** operators in order to constrain a search. +** +** xGeom and xQueryFunc are the callback functions. Exactly one of +** xGeom and xQueryFunc fields is non-NULL, depending on whether the +** SQL function was created using sqlite3_rtree_geometry_callback() or +** sqlite3_rtree_query_callback(). +** +** This object is deleted automatically by the destructor mechanism in +** sqlite3_create_function_v2(). +*/ +struct RtreeGeomCallback { + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + void (*xDestructor)(void*); + void *pContext; +}; + + +/* +** Value for the first field of every RtreeMatchArg object. The MATCH +** operator tests that the first field of a blob operand matches this +** value to avoid operating on invalid blobs (which could cause a segfault). +*/ +#define RTREE_GEOMETRY_MAGIC 0x891245AB + +/* +** An instance of this structure (in the form of a BLOB) is returned by +** the SQL functions that sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() create, and is read as the right-hand +** operand to the MATCH operator of an R-Tree. +*/ +struct RtreeMatchArg { + u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ + RtreeGeomCallback cb; /* Info about the callback functions */ + int nParam; /* Number of parameters to the SQL function */ + sqlite3_value **apSqlParam; /* Original SQL parameter values */ + RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ +}; + +#ifndef MAX +# define MAX(x,y) ((x) < (y) ? (y) : (x)) +#endif +#ifndef MIN +# define MIN(x,y) ((x) > (y) ? (y) : (x)) +#endif + +/* What version of GCC is being used. 0 means GCC is not being used . +** Note that the GCC_VERSION macro will also be set correctly when using +** clang, since clang works hard to be gcc compatible. So the gcc +** optimizations will also work when compiling with clang. +*/ +#ifndef GCC_VERSION +#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) +# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) +#else +# define GCC_VERSION 0 +#endif +#endif + +/* The testcase() macro should already be defined in the amalgamation. If +** it is not, make it a no-op. +*/ +#ifndef SQLITE_AMALGAMATION +# define testcase(X) +#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 +** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined +** at run-time. +*/ +#ifndef SQLITE_BYTEORDER +#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__) +# define SQLITE_BYTEORDER 1234 +#elif defined(sparc) || defined(__ppc__) +# define SQLITE_BYTEORDER 4321 +#else +# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ +#endif +#endif + + +/* What version of MSVC is being used. 0 means MSVC is not being used */ +#ifndef MSVC_VERSION +#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) +# define MSVC_VERSION _MSC_VER +#else +# define MSVC_VERSION 0 +#endif +#endif + +/* +** Functions to deserialize a 16 bit integer, 32 bit real number and +** 64 bit integer. The deserialized value is returned. +*/ +static int readInt16(u8 *p){ + return (p[0]<<8) + p[1]; +} +static void readCoord(u8 *p, RtreeCoord *pCoord){ + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + pCoord->u = _byteswap_ulong(*(u32*)p); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + pCoord->u = __builtin_bswap32(*(u32*)p); +#elif SQLITE_BYTEORDER==4321 + pCoord->u = *(u32*)p; +#else + pCoord->u = ( + (((u32)p[0]) << 24) + + (((u32)p[1]) << 16) + + (((u32)p[2]) << 8) + + (((u32)p[3]) << 0) + ); +#endif +} +static i64 readInt64(u8 *p){ +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + u64 x; + memcpy(&x, p, 8); + return (i64)_byteswap_uint64(x); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + u64 x; + memcpy(&x, p, 8); + return (i64)__builtin_bswap64(x); +#elif SQLITE_BYTEORDER==4321 + i64 x; + memcpy(&x, p, 8); + return x; +#else + return (i64)( + (((u64)p[0]) << 56) + + (((u64)p[1]) << 48) + + (((u64)p[2]) << 40) + + (((u64)p[3]) << 32) + + (((u64)p[4]) << 24) + + (((u64)p[5]) << 16) + + (((u64)p[6]) << 8) + + (((u64)p[7]) << 0) + ); +#endif +} + +/* +** Functions to serialize a 16 bit integer, 32 bit real number and +** 64 bit integer. The value returned is the number of bytes written +** to the argument buffer (always 2, 4 and 8 respectively). +*/ +static void writeInt16(u8 *p, int i){ + p[0] = (i>> 8)&0xFF; + p[1] = (i>> 0)&0xFF; +} +static int writeCoord(u8 *p, RtreeCoord *pCoord){ + u32 i; + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ + assert( sizeof(RtreeCoord)==4 ); + assert( sizeof(u32)==4 ); +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + i = __builtin_bswap32(pCoord->u); + memcpy(p, &i, 4); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + i = _byteswap_ulong(pCoord->u); + memcpy(p, &i, 4); +#elif SQLITE_BYTEORDER==4321 + i = pCoord->u; + memcpy(p, &i, 4); +#else + i = pCoord->u; + p[0] = (i>>24)&0xFF; + p[1] = (i>>16)&0xFF; + p[2] = (i>> 8)&0xFF; + p[3] = (i>> 0)&0xFF; +#endif + return 4; +} +static int writeInt64(u8 *p, i64 i){ +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + i = (i64)__builtin_bswap64((u64)i); + memcpy(p, &i, 8); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + i = (i64)_byteswap_uint64((u64)i); + memcpy(p, &i, 8); +#elif SQLITE_BYTEORDER==4321 + memcpy(p, &i, 8); +#else + p[0] = (i>>56)&0xFF; + p[1] = (i>>48)&0xFF; + p[2] = (i>>40)&0xFF; + p[3] = (i>>32)&0xFF; + p[4] = (i>>24)&0xFF; + p[5] = (i>>16)&0xFF; + p[6] = (i>> 8)&0xFF; + p[7] = (i>> 0)&0xFF; +#endif + return 8; +} + +/* +** Increment the reference count of node p. +*/ +static void nodeReference(RtreeNode *p){ + if( p ){ + p->nRef++; + } +} + +/* +** Clear the content of node p (set all bytes to 0x00). +*/ +static void nodeZero(Rtree *pRtree, RtreeNode *p){ + memset(&p->zData[2], 0, pRtree->iNodeSize-2); + p->isDirty = 1; +} + +/* +** Given a node number iNode, return the corresponding key to use +** in the Rtree.aHash table. +*/ +static int nodeHash(i64 iNode){ + return iNode % HASHSIZE; +} + +/* +** Search the node hash table for node iNode. If found, return a pointer +** to it. Otherwise, return 0. +*/ +static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){ + RtreeNode *p; + for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext); + return p; +} + +/* +** Add node pNode to the node hash table. +*/ +static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){ + int iHash; + assert( pNode->pNext==0 ); + iHash = nodeHash(pNode->iNode); + pNode->pNext = pRtree->aHash[iHash]; + pRtree->aHash[iHash] = pNode; +} + +/* +** Remove node pNode from the node hash table. +*/ +static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){ + RtreeNode **pp; + if( pNode->iNode!=0 ){ + pp = &pRtree->aHash[nodeHash(pNode->iNode)]; + for( ; (*pp)!=pNode; pp = &(*pp)->pNext){ assert(*pp); } + *pp = pNode->pNext; + pNode->pNext = 0; + } +} + +/* +** Allocate and return new r-tree node. Initially, (RtreeNode.iNode==0), +** indicating that node has not yet been assigned a node number. It is +** assigned a node number when nodeWrite() is called to write the +** node contents out to the database. +*/ +static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ + RtreeNode *pNode; + pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize); + if( pNode ){ + memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); + pNode->zData = (u8 *)&pNode[1]; + pNode->nRef = 1; + pNode->pParent = pParent; + pNode->isDirty = 1; + nodeReference(pParent); + } + return pNode; +} + +/* +** Clear the Rtree.pNodeBlob object +*/ +static void nodeBlobReset(Rtree *pRtree){ + if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + sqlite3_blob_close(pBlob); + } +} + +/* +** Obtain a reference to an r-tree node. +*/ +static int nodeAcquire( + Rtree *pRtree, /* R-tree structure */ + i64 iNode, /* Node number to load */ + RtreeNode *pParent, /* Either the parent node or NULL */ + RtreeNode **ppNode /* OUT: Acquired node */ +){ + int rc = SQLITE_OK; + RtreeNode *pNode = 0; + + /* Check if the requested node is already in the hash table. If so, + ** increase its reference count and return it. + */ + if( (pNode = nodeHashLookup(pRtree, iNode)) ){ + assert( !pParent || !pNode->pParent || pNode->pParent==pParent ); + if( pParent && !pNode->pParent ){ + nodeReference(pParent); + pNode->pParent = pParent; + } + pNode->nRef++; + *ppNode = pNode; + return SQLITE_OK; + } + + if( pRtree->pNodeBlob ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + rc = sqlite3_blob_reopen(pBlob, iNode); + pRtree->pNodeBlob = pBlob; + if( rc ){ + nodeBlobReset(pRtree); + if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM; + } + } + if( pRtree->pNodeBlob==0 ){ + char *zTab = sqlite3_mprintf("%s_node", pRtree->zName); + if( zTab==0 ) return SQLITE_NOMEM; + rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0, + &pRtree->pNodeBlob); + sqlite3_free(zTab); + } + if( rc ){ + nodeBlobReset(pRtree); + *ppNode = 0; + /* If unable to open an sqlite3_blob on the desired row, that can only + ** be because the shadow tables hold erroneous data. */ + if( rc==SQLITE_ERROR ) rc = SQLITE_CORRUPT_VTAB; + }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ + pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize); + if( !pNode ){ + rc = SQLITE_NOMEM; + }else{ + pNode->pParent = pParent; + pNode->zData = (u8 *)&pNode[1]; + pNode->nRef = 1; + pNode->iNode = iNode; + pNode->isDirty = 0; + pNode->pNext = 0; + rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, + pRtree->iNodeSize, 0); + nodeReference(pParent); + } + } + + /* If the root node was just loaded, set pRtree->iDepth to the height + ** of the r-tree structure. A height of zero means all data is stored on + ** the root node. A height of one means the children of the root node + ** are the leaves, and so on. If the depth as specified on the root node + ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. + */ + if( pNode && iNode==1 ){ + pRtree->iDepth = readInt16(pNode->zData); + if( pRtree->iDepth>RTREE_MAX_DEPTH ){ + rc = SQLITE_CORRUPT_VTAB; + } + } + + /* If no error has occurred so far, check if the "number of entries" + ** field on the node is too large. If so, set the return code to + ** SQLITE_CORRUPT_VTAB. + */ + if( pNode && rc==SQLITE_OK ){ + if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ + rc = SQLITE_CORRUPT_VTAB; + } + } + + if( rc==SQLITE_OK ){ + if( pNode!=0 ){ + nodeHashInsert(pRtree, pNode); + }else{ + rc = SQLITE_CORRUPT_VTAB; + } + *ppNode = pNode; + }else{ + sqlite3_free(pNode); + *ppNode = 0; + } + + return rc; +} + +/* +** Overwrite cell iCell of node pNode with the contents of pCell. +*/ +static void nodeOverwriteCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node into which the cell is to be written */ + RtreeCell *pCell, /* The cell to write */ + int iCell /* Index into pNode into which pCell is written */ +){ + int ii; + u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; + p += writeInt64(p, pCell->iRowid); + for(ii=0; iinDim2; ii++){ + p += writeCoord(p, &pCell->aCoord[ii]); + } + pNode->isDirty = 1; +} + +/* +** Remove the cell with index iCell from node pNode. +*/ +static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ + u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; + u8 *pSrc = &pDst[pRtree->nBytesPerCell]; + int nByte = (NCELL(pNode) - iCell - 1) * pRtree->nBytesPerCell; + memmove(pDst, pSrc, nByte); + writeInt16(&pNode->zData[2], NCELL(pNode)-1); + pNode->isDirty = 1; +} + +/* +** Insert the contents of cell pCell into node pNode. If the insert +** is successful, return SQLITE_OK. +** +** If there is not enough free space in pNode, return SQLITE_FULL. +*/ +static int nodeInsertCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* Write new cell into this node */ + RtreeCell *pCell /* The cell to be inserted */ +){ + int nCell; /* Current number of cells in pNode */ + int nMaxCell; /* Maximum number of cells for pNode */ + + nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell; + nCell = NCELL(pNode); + + assert( nCell<=nMaxCell ); + if( nCellzData[2], nCell+1); + pNode->isDirty = 1; + } + + return (nCell==nMaxCell); +} + +/* +** If the node is dirty, write it out to the database. +*/ +static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ + int rc = SQLITE_OK; + if( pNode->isDirty ){ + sqlite3_stmt *p = pRtree->pWriteNode; + if( pNode->iNode ){ + sqlite3_bind_int64(p, 1, pNode->iNode); + }else{ + sqlite3_bind_null(p, 1); + } + sqlite3_bind_blob(p, 2, pNode->zData, pRtree->iNodeSize, SQLITE_STATIC); + sqlite3_step(p); + pNode->isDirty = 0; + rc = sqlite3_reset(p); + if( pNode->iNode==0 && rc==SQLITE_OK ){ + pNode->iNode = sqlite3_last_insert_rowid(pRtree->db); + nodeHashInsert(pRtree, pNode); + } + } + return rc; +} + +/* +** Release a reference to a node. If the node is dirty and the reference +** count drops to zero, the node data is written to the database. +*/ +static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ + int rc = SQLITE_OK; + if( pNode ){ + assert( pNode->nRef>0 ); + pNode->nRef--; + if( pNode->nRef==0 ){ + if( pNode->iNode==1 ){ + pRtree->iDepth = -1; + } + if( pNode->pParent ){ + rc = nodeRelease(pRtree, pNode->pParent); + } + if( rc==SQLITE_OK ){ + rc = nodeWrite(pRtree, pNode); + } + nodeHashDelete(pRtree, pNode); + sqlite3_free(pNode); + } + } + return rc; +} + +/* +** Return the 64-bit integer value associated with cell iCell of +** node pNode. If pNode is a leaf node, this is a rowid. If it is +** an internal node, then the 64-bit integer is a child page number. +*/ +static i64 nodeGetRowid( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract the ID */ + int iCell /* The cell index from which to extract the ID */ +){ + assert( iCellzData[4 + pRtree->nBytesPerCell*iCell]); +} + +/* +** Return coordinate iCoord from cell iCell in node pNode. +*/ +static void nodeGetCoord( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract a coordinate */ + int iCell, /* The index of the cell within the node */ + int iCoord, /* Which coordinate to extract */ + RtreeCoord *pCoord /* OUT: Space to write result to */ +){ + readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); +} + +/* +** Deserialize cell iCell of node pNode. Populate the structure pointed +** to by pCell with the results. +*/ +static void nodeGetCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node containing the cell to be read */ + int iCell, /* Index of the cell within the node */ + RtreeCell *pCell /* OUT: Write the cell contents here */ +){ + u8 *pData; + RtreeCoord *pCoord; + int ii = 0; + pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); + pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); + pCoord = pCell->aCoord; + do{ + readCoord(pData, &pCoord[ii]); + readCoord(pData+4, &pCoord[ii+1]); + pData += 8; + ii += 2; + }while( iinDim2 ); +} + + +/* Forward declaration for the function that does the work of +** the virtual table module xCreate() and xConnect() methods. +*/ +static int rtreeInit( + sqlite3 *, void *, int, const char *const*, sqlite3_vtab **, char **, int +); + +/* +** Rtree virtual table module xCreate method. +*/ +static int rtreeCreate( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 1); +} + +/* +** Rtree virtual table module xConnect method. +*/ +static int rtreeConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 0); +} + +/* +** Increment the r-tree reference count. +*/ +static void rtreeReference(Rtree *pRtree){ + pRtree->nBusy++; +} + +/* +** Decrement the r-tree reference count. When the reference count reaches +** zero the structure is deleted. +*/ +static void rtreeRelease(Rtree *pRtree){ + pRtree->nBusy--; + if( pRtree->nBusy==0 ){ + pRtree->inWrTrans = 0; + pRtree->nCursor = 0; + nodeBlobReset(pRtree); + sqlite3_finalize(pRtree->pWriteNode); + sqlite3_finalize(pRtree->pDeleteNode); + sqlite3_finalize(pRtree->pReadRowid); + sqlite3_finalize(pRtree->pWriteRowid); + sqlite3_finalize(pRtree->pDeleteRowid); + sqlite3_finalize(pRtree->pReadParent); + sqlite3_finalize(pRtree->pWriteParent); + sqlite3_finalize(pRtree->pDeleteParent); + sqlite3_free(pRtree); + } +} + +/* +** Rtree virtual table module xDisconnect method. +*/ +static int rtreeDisconnect(sqlite3_vtab *pVtab){ + rtreeRelease((Rtree *)pVtab); + return SQLITE_OK; +} + +/* +** Rtree virtual table module xDestroy method. +*/ +static int rtreeDestroy(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; + int rc; + char *zCreate = sqlite3_mprintf( + "DROP TABLE '%q'.'%q_node';" + "DROP TABLE '%q'.'%q_rowid';" + "DROP TABLE '%q'.'%q_parent';", + pRtree->zDb, pRtree->zName, + pRtree->zDb, pRtree->zName, + pRtree->zDb, pRtree->zName + ); + if( !zCreate ){ + rc = SQLITE_NOMEM; + }else{ + nodeBlobReset(pRtree); + rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0); + sqlite3_free(zCreate); + } + if( rc==SQLITE_OK ){ + rtreeRelease(pRtree); + } + + return rc; +} + +/* +** Rtree virtual table module xOpen method. +*/ +static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + int rc = SQLITE_NOMEM; + Rtree *pRtree = (Rtree *)pVTab; + RtreeCursor *pCsr; + + pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor)); + if( pCsr ){ + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = pVTab; + rc = SQLITE_OK; + pRtree->nCursor++; + } + *ppCursor = (sqlite3_vtab_cursor *)pCsr; + + return rc; +} + + +/* +** Free the RtreeCursor.aConstraint[] array and its contents. +*/ +static void freeCursorConstraints(RtreeCursor *pCsr){ + if( pCsr->aConstraint ){ + int i; /* Used to iterate through constraint array */ + for(i=0; inConstraint; i++){ + sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; + if( pInfo ){ + if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); + sqlite3_free(pInfo); + } + } + sqlite3_free(pCsr->aConstraint); + pCsr->aConstraint = 0; + } +} + +/* +** Rtree virtual table module xClose method. +*/ +static int rtreeClose(sqlite3_vtab_cursor *cur){ + Rtree *pRtree = (Rtree *)(cur->pVtab); + int ii; + RtreeCursor *pCsr = (RtreeCursor *)cur; + assert( pRtree->nCursor>0 ); + freeCursorConstraints(pCsr); + sqlite3_free(pCsr->aPoint); + for(ii=0; iiaNode[ii]); + sqlite3_free(pCsr); + pRtree->nCursor--; + nodeBlobReset(pRtree); + return SQLITE_OK; +} + +/* +** Rtree virtual table module xEof method. +** +** Return non-zero if the cursor does not currently point to a valid +** record (i.e if the scan has finished), or zero otherwise. +*/ +static int rtreeEof(sqlite3_vtab_cursor *cur){ + RtreeCursor *pCsr = (RtreeCursor *)cur; + return pCsr->atEOF; +} + +/* +** Convert raw bits from the on-disk RTree record into a coordinate value. +** The on-disk format is big-endian and needs to be converted for little- +** endian platforms. The on-disk record stores integer coordinates if +** eInt is true and it stores 32-bit floating point records if eInt is +** false. a[] is the four bytes of the on-disk record to be decoded. +** Store the results in "r". +** +** There are five versions of this macro. The last one is generic. The +** other four are various architectures-specific optimizations. +*/ +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = _byteswap_ulong(*(u32*)a); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = __builtin_bswap32(*(u32*)a); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==1234 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + c.u = ((c.u>>24)&0xff)|((c.u>>8)&0xff00)| \ + ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==4321 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#else +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = ((u32)a[0]<<24) + ((u32)a[1]<<16) \ + +((u32)a[2]<<8) + a[3]; \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#endif + +/* +** Check the RTree node or entry given by pCellData and p against the MATCH +** constraint pConstraint. +*/ +static int rtreeCallbackConstraint( + RtreeConstraint *pConstraint, /* The constraint to test */ + int eInt, /* True if RTree holding integer coordinates */ + u8 *pCellData, /* Raw cell content */ + RtreeSearchPoint *pSearch, /* Container of this cell */ + sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ + int *peWithin /* OUT: visibility of the cell */ +){ + sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ + int nCoord = pInfo->nCoord; /* No. of coordinates */ + int rc; /* Callback return code */ + RtreeCoord c; /* Translator union */ + sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ + + assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); + assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 ); + + if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){ + pInfo->iRowid = readInt64(pCellData); + } + pCellData += 8; +#ifndef SQLITE_RTREE_INT_ONLY + if( eInt==0 ){ + switch( nCoord ){ + case 10: readCoord(pCellData+36, &c); aCoord[9] = c.f; + readCoord(pCellData+32, &c); aCoord[8] = c.f; + case 8: readCoord(pCellData+28, &c); aCoord[7] = c.f; + readCoord(pCellData+24, &c); aCoord[6] = c.f; + case 6: readCoord(pCellData+20, &c); aCoord[5] = c.f; + readCoord(pCellData+16, &c); aCoord[4] = c.f; + case 4: readCoord(pCellData+12, &c); aCoord[3] = c.f; + readCoord(pCellData+8, &c); aCoord[2] = c.f; + default: readCoord(pCellData+4, &c); aCoord[1] = c.f; + readCoord(pCellData, &c); aCoord[0] = c.f; + } + }else +#endif + { + switch( nCoord ){ + case 10: readCoord(pCellData+36, &c); aCoord[9] = c.i; + readCoord(pCellData+32, &c); aCoord[8] = c.i; + case 8: readCoord(pCellData+28, &c); aCoord[7] = c.i; + readCoord(pCellData+24, &c); aCoord[6] = c.i; + case 6: readCoord(pCellData+20, &c); aCoord[5] = c.i; + readCoord(pCellData+16, &c); aCoord[4] = c.i; + case 4: readCoord(pCellData+12, &c); aCoord[3] = c.i; + readCoord(pCellData+8, &c); aCoord[2] = c.i; + default: readCoord(pCellData+4, &c); aCoord[1] = c.i; + readCoord(pCellData, &c); aCoord[0] = c.i; + } + } + if( pConstraint->op==RTREE_MATCH ){ + int eWithin = 0; + rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, + nCoord, aCoord, &eWithin); + if( eWithin==0 ) *peWithin = NOT_WITHIN; + *prScore = RTREE_ZERO; + }else{ + pInfo->aCoord = aCoord; + pInfo->iLevel = pSearch->iLevel - 1; + pInfo->rScore = pInfo->rParentScore = pSearch->rScore; + pInfo->eWithin = pInfo->eParentWithin = pSearch->eWithin; + rc = pConstraint->u.xQueryFunc(pInfo); + if( pInfo->eWithin<*peWithin ) *peWithin = pInfo->eWithin; + if( pInfo->rScore<*prScore || *prScorerScore; + } + } + return rc; +} + +/* +** Check the internal RTree node given by pCellData against constraint p. +** If this constraint cannot be satisfied by any child within the node, +** set *peWithin to NOT_WITHIN. +*/ +static void rtreeNonleafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ +){ + sqlite3_rtree_dbl val; /* Coordinate value convert to a double */ + + /* p->iCoord might point to either a lower or upper bound coordinate + ** in a coordinate pair. But make pCellData point to the lower bound. + */ + pCellData += 8 + 4*(p->iCoord&0xfe); + + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ ); + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ + switch( p->op ){ + case RTREE_LE: + case RTREE_LT: + case RTREE_EQ: + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the lower bound of the coordinate pair */ + if( p->u.rValue>=val ) return; + if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ + /* Fall through for the RTREE_EQ case */ + + default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ + pCellData += 4; + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the upper bound of the coordinate pair */ + if( p->u.rValue<=val ) return; + } + *peWithin = NOT_WITHIN; +} + +/* +** Check the leaf RTree cell given by pCellData against constraint p. +** If this constraint is not satisfied, set *peWithin to NOT_WITHIN. +** If the constraint is satisfied, leave *peWithin unchanged. +** +** The constraint is of the form: xN op $val +** +** The op is given by p->op. The xN is p->iCoord-th coordinate in +** pCellData. $val is given by p->u.rValue. +*/ +static void rtreeLeafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ +){ + RtreeDValue xN; /* Coordinate value converted to a double */ + + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ ); + pCellData += 8 + p->iCoord*4; + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ + RTREE_DECODE_COORD(eInt, pCellData, xN); + switch( p->op ){ + case RTREE_LE: if( xN <= p->u.rValue ) return; break; + case RTREE_LT: if( xN < p->u.rValue ) return; break; + case RTREE_GE: if( xN >= p->u.rValue ) return; break; + case RTREE_GT: if( xN > p->u.rValue ) return; break; + default: if( xN == p->u.rValue ) return; break; + } + *peWithin = NOT_WITHIN; +} + +/* +** One of the cells in node pNode is guaranteed to have a 64-bit +** integer value equal to iRowid. Return the index of this cell. +*/ +static int nodeRowidIndex( + Rtree *pRtree, + RtreeNode *pNode, + i64 iRowid, + int *piIndex +){ + int ii; + int nCell = NCELL(pNode); + assert( nCell<200 ); + for(ii=0; iipParent; + if( pParent ){ + return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); + } + *piIndex = -1; + return SQLITE_OK; +} + +/* +** Compare two search points. Return negative, zero, or positive if the first +** is less than, equal to, or greater than the second. +** +** The rScore is the primary key. Smaller rScore values come first. +** If the rScore is a tie, then use iLevel as the tie breaker with smaller +** iLevel values coming first. In this way, if rScore is the same for all +** SearchPoints, then iLevel becomes the deciding factor and the result +** is a depth-first search, which is the desired default behavior. +*/ +static int rtreeSearchPointCompare( + const RtreeSearchPoint *pA, + const RtreeSearchPoint *pB +){ + if( pA->rScorerScore ) return -1; + if( pA->rScore>pB->rScore ) return +1; + if( pA->iLeveliLevel ) return -1; + if( pA->iLevel>pB->iLevel ) return +1; + return 0; +} + +/* +** Interchange two search points in a cursor. +*/ +static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ + RtreeSearchPoint t = p->aPoint[i]; + assert( iaPoint[i] = p->aPoint[j]; + p->aPoint[j] = t; + i++; j++; + if( i=RTREE_CACHE_SZ ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + }else{ + RtreeNode *pTemp = p->aNode[i]; + p->aNode[i] = p->aNode[j]; + p->aNode[j] = pTemp; + } + } +} + +/* +** Return the search point with the lowest current score. +*/ +static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){ + return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0; +} + +/* +** Get the RtreeNode for the search point with the lowest score. +*/ +static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){ + sqlite3_int64 id; + int ii = 1 - pCur->bPoint; + assert( ii==0 || ii==1 ); + assert( pCur->bPoint || pCur->nPoint ); + if( pCur->aNode[ii]==0 ){ + assert( pRC!=0 ); + id = ii ? pCur->aPoint[0].id : pCur->sPoint.id; + *pRC = nodeAcquire(RTREE_OF_CURSOR(pCur), id, 0, &pCur->aNode[ii]); + } + return pCur->aNode[ii]; +} + +/* +** Push a new element onto the priority queue +*/ +static RtreeSearchPoint *rtreeEnqueue( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ +){ + int i, j; + RtreeSearchPoint *pNew; + if( pCur->nPoint>=pCur->nPointAlloc ){ + int nNew = pCur->nPointAlloc*2 + 8; + pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); + if( pNew==0 ) return 0; + pCur->aPoint = pNew; + pCur->nPointAlloc = nNew; + } + i = pCur->nPoint++; + pNew = pCur->aPoint + i; + pNew->rScore = rScore; + pNew->iLevel = iLevel; + assert( iLevel<=RTREE_MAX_DEPTH ); + while( i>0 ){ + RtreeSearchPoint *pParent; + j = (i-1)/2; + pParent = pCur->aPoint + j; + if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; + rtreeSearchPointSwap(pCur, j, i); + i = j; + pNew = pParent; + } + return pNew; +} + +/* +** Allocate a new RtreeSearchPoint and return a pointer to it. Return +** NULL if malloc fails. +*/ +static RtreeSearchPoint *rtreeSearchPointNew( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ +){ + RtreeSearchPoint *pNew, *pFirst; + pFirst = rtreeSearchPointFirst(pCur); + pCur->anQueue[iLevel]++; + if( pFirst==0 + || pFirst->rScore>rScore + || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) + ){ + if( pCur->bPoint ){ + int ii; + pNew = rtreeEnqueue(pCur, rScore, iLevel); + if( pNew==0 ) return 0; + ii = (int)(pNew - pCur->aPoint) + 1; + if( iiaNode[ii]==0 ); + pCur->aNode[ii] = pCur->aNode[0]; + }else{ + nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); + } + pCur->aNode[0] = 0; + *pNew = pCur->sPoint; + } + pCur->sPoint.rScore = rScore; + pCur->sPoint.iLevel = iLevel; + pCur->bPoint = 1; + return &pCur->sPoint; + }else{ + return rtreeEnqueue(pCur, rScore, iLevel); + } +} + +#if 0 +/* Tracing routines for the RtreeSearchPoint queue */ +static void tracePoint(RtreeSearchPoint *p, int idx, RtreeCursor *pCur){ + if( idx<0 ){ printf(" s"); }else{ printf("%2d", idx); } + printf(" %d.%05lld.%02d %g %d", + p->iLevel, p->id, p->iCell, p->rScore, p->eWithin + ); + idx++; + if( idxaNode[idx]); + }else{ + printf("\n"); + } +} +static void traceQueue(RtreeCursor *pCur, const char *zPrefix){ + int ii; + printf("=== %9s ", zPrefix); + if( pCur->bPoint ){ + tracePoint(&pCur->sPoint, -1, pCur); + } + for(ii=0; iinPoint; ii++){ + if( ii>0 || pCur->bPoint ) printf(" "); + tracePoint(&pCur->aPoint[ii], ii, pCur); + } +} +# define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B) +#else +# define RTREE_QUEUE_TRACE(A,B) /* no-op */ +#endif + +/* Remove the search point with the lowest current score. +*/ +static void rtreeSearchPointPop(RtreeCursor *p){ + int i, j, k, n; + i = 1 - p->bPoint; + assert( i==0 || i==1 ); + if( p->aNode[i] ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + } + if( p->bPoint ){ + p->anQueue[p->sPoint.iLevel]--; + p->bPoint = 0; + }else if( p->nPoint ){ + p->anQueue[p->aPoint[0].iLevel]--; + n = --p->nPoint; + p->aPoint[0] = p->aPoint[n]; + if( naNode[1] = p->aNode[n+1]; + p->aNode[n+1] = 0; + } + i = 0; + while( (j = i*2+1)aPoint[k], &p->aPoint[j])<0 ){ + if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, k); + i = k; + }else{ + break; + } + }else{ + if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, j); + i = j; + }else{ + break; + } + } + } + } +} + + +/* +** Continue the search on cursor pCur until the front of the queue +** contains an entry suitable for returning as a result-set row, +** or until the RtreeSearchPoint queue is empty, indicating that the +** query has completed. +*/ +static int rtreeStepToLeaf(RtreeCursor *pCur){ + RtreeSearchPoint *p; + Rtree *pRtree = RTREE_OF_CURSOR(pCur); + RtreeNode *pNode; + int eWithin; + int rc = SQLITE_OK; + int nCell; + int nConstraint = pCur->nConstraint; + int ii; + int eInt; + RtreeSearchPoint x; + + eInt = pRtree->eCoordType==RTREE_COORD_INT32; + while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ + pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); + if( rc ) return rc; + nCell = NCELL(pNode); + assert( nCell<200 ); + while( p->iCellzData + (4+pRtree->nBytesPerCell*p->iCell); + eWithin = FULLY_WITHIN; + for(ii=0; iiaConstraint + ii; + if( pConstraint->op>=RTREE_MATCH ){ + rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, + &rScore, &eWithin); + if( rc ) return rc; + }else if( p->iLevel==1 ){ + rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); + }else{ + rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); + } + if( eWithin==NOT_WITHIN ) break; + } + p->iCell++; + if( eWithin==NOT_WITHIN ) continue; + x.iLevel = p->iLevel - 1; + if( x.iLevel ){ + x.id = readInt64(pCellData); + x.iCell = 0; + }else{ + x.id = p->id; + x.iCell = p->iCell - 1; + } + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-S:"); + rtreeSearchPointPop(pCur); + } + if( rScoreeWithin = (u8)eWithin; + p->id = x.id; + p->iCell = x.iCell; + RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); + break; + } + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-Se:"); + rtreeSearchPointPop(pCur); + } + } + pCur->atEOF = p==0; + return SQLITE_OK; +} + +/* +** Rtree virtual table module xNext method. +*/ +static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + int rc = SQLITE_OK; + + /* Move to the next entry that matches the configured constraints. */ + RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); + rtreeSearchPointPop(pCsr); + rc = rtreeStepToLeaf(pCsr); + return rc; +} + +/* +** Rtree virtual table module xRowid method. +*/ +static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + if( rc==SQLITE_OK && p ){ + *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); + } + return rc; +} + +/* +** Rtree virtual table module xColumn method. +*/ +static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ + Rtree *pRtree = (Rtree *)cur->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)cur; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + RtreeCoord c; + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + + if( rc ) return rc; + if( p==0 ) return SQLITE_OK; + if( i==0 ){ + sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); + }else{ + nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + sqlite3_result_double(ctx, c.f); + }else +#endif + { + assert( pRtree->eCoordType==RTREE_COORD_INT32 ); + sqlite3_result_int(ctx, c.i); + } + } + return SQLITE_OK; +} + +/* +** Use nodeAcquire() to obtain the leaf node containing the record with +** rowid iRowid. If successful, set *ppLeaf to point to the node and +** return SQLITE_OK. If there is no such record in the table, set +** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf +** to zero and return an SQLite error code. +*/ +static int findLeafNode( + Rtree *pRtree, /* RTree to search */ + i64 iRowid, /* The rowid searching for */ + RtreeNode **ppLeaf, /* Write the node here */ + sqlite3_int64 *piNode /* Write the node-id here */ +){ + int rc; + *ppLeaf = 0; + sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); + if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ + i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); + if( piNode ) *piNode = iNode; + rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); + sqlite3_reset(pRtree->pReadRowid); + }else{ + rc = sqlite3_reset(pRtree->pReadRowid); + } + return rc; +} + +/* +** This function is called to configure the RtreeConstraint object passed +** as the second argument for a MATCH constraint. The value passed as the +** first argument to this function is the right-hand operand to the MATCH +** operator. +*/ +static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ + RtreeMatchArg *pBlob; /* BLOB returned by geometry function */ + sqlite3_rtree_query_info *pInfo; /* Callback information */ + int nBlob; /* Size of the geometry function blob */ + int nExpected; /* Expected size of the BLOB */ + + /* Check that value is actually a blob. */ + if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; + + /* Check that the blob is roughly the right size. */ + nBlob = sqlite3_value_bytes(pValue); + if( nBlob<(int)sizeof(RtreeMatchArg) ){ + return SQLITE_ERROR; + } + + pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob ); + if( !pInfo ) return SQLITE_NOMEM; + memset(pInfo, 0, sizeof(*pInfo)); + pBlob = (RtreeMatchArg*)&pInfo[1]; + + memcpy(pBlob, sqlite3_value_blob(pValue), nBlob); + nExpected = (int)(sizeof(RtreeMatchArg) + + pBlob->nParam*sizeof(sqlite3_value*) + + (pBlob->nParam-1)*sizeof(RtreeDValue)); + if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){ + sqlite3_free(pInfo); + return SQLITE_ERROR; + } + pInfo->pContext = pBlob->cb.pContext; + pInfo->nParam = pBlob->nParam; + pInfo->aParam = pBlob->aParam; + pInfo->apSqlParam = pBlob->apSqlParam; + + if( pBlob->cb.xGeom ){ + pCons->u.xGeom = pBlob->cb.xGeom; + }else{ + pCons->op = RTREE_QUERY; + pCons->u.xQueryFunc = pBlob->cb.xQueryFunc; + } + pCons->pInfo = pInfo; + return SQLITE_OK; +} + +/* +** Rtree virtual table module xFilter method. +*/ +static int rtreeFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeNode *pRoot = 0; + int ii; + int rc = SQLITE_OK; + int iCell = 0; + + rtreeReference(pRtree); + + /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ + freeCursorConstraints(pCsr); + sqlite3_free(pCsr->aPoint); + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = (sqlite3_vtab*)pRtree; + + pCsr->iStrategy = idxNum; + if( idxNum==1 ){ + /* Special case - lookup by rowid. */ + RtreeNode *pLeaf; /* Leaf on which the required cell resides */ + RtreeSearchPoint *p; /* Search point for the leaf */ + i64 iRowid = sqlite3_value_int64(argv[0]); + i64 iNode = 0; + rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); + if( rc==SQLITE_OK && pLeaf!=0 ){ + p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); + assert( p!=0 ); /* Always returns pCsr->sPoint */ + pCsr->aNode[0] = pLeaf; + p->id = iNode; + p->eWithin = PARTLY_WITHIN; + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); + p->iCell = (u8)iCell; + RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); + }else{ + pCsr->atEOF = 1; + } + }else{ + /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array + ** with the configured constraints. + */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + if( rc==SQLITE_OK && argc>0 ){ + pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc); + pCsr->nConstraint = argc; + if( !pCsr->aConstraint ){ + rc = SQLITE_NOMEM; + }else{ + memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); + memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); + assert( (idxStr==0 && argc==0) + || (idxStr && (int)strlen(idxStr)==argc*2) ); + for(ii=0; iiaConstraint[ii]; + p->op = idxStr[ii*2]; + p->iCoord = idxStr[ii*2+1]-'0'; + if( p->op>=RTREE_MATCH ){ + /* A MATCH operator. The right-hand-side must be a blob that + ** can be cast into an RtreeMatchArg object. One created using + ** an sqlite3_rtree_geometry_callback() SQL user function. + */ + rc = deserializeGeometry(argv[ii], p); + if( rc!=SQLITE_OK ){ + break; + } + p->pInfo->nCoord = pRtree->nDim2; + p->pInfo->anQueue = pCsr->anQueue; + p->pInfo->mxLevel = pRtree->iDepth + 1; + }else{ +#ifdef SQLITE_RTREE_INT_ONLY + p->u.rValue = sqlite3_value_int64(argv[ii]); +#else + p->u.rValue = sqlite3_value_double(argv[ii]); +#endif + } + } + } + } + if( rc==SQLITE_OK ){ + RtreeSearchPoint *pNew; + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->id = 1; + pNew->iCell = 0; + pNew->eWithin = PARTLY_WITHIN; + assert( pCsr->bPoint==1 ); + pCsr->aNode[0] = pRoot; + pRoot = 0; + RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); + rc = rtreeStepToLeaf(pCsr); + } + } + + nodeRelease(pRtree, pRoot); + rtreeRelease(pRtree); + return rc; +} + +/* +** Rtree virtual table module xBestIndex method. There are three +** table scan strategies to choose from (in order from most to +** least desirable): +** +** idxNum idxStr Strategy +** ------------------------------------------------ +** 1 Unused Direct lookup by rowid. +** 2 See below R-tree query or full-table scan. +** ------------------------------------------------ +** +** If strategy 1 is used, then idxStr is not meaningful. If strategy +** 2 is used, idxStr is formatted to contain 2 bytes for each +** constraint used. The first two bytes of idxStr correspond to +** the constraint in sqlite3_index_info.aConstraintUsage[] with +** (argvIndex==1) etc. +** +** The first of each pair of bytes in idxStr identifies the constraint +** operator as follows: +** +** Operator Byte Value +** ---------------------- +** = 0x41 ('A') +** <= 0x42 ('B') +** < 0x43 ('C') +** >= 0x44 ('D') +** > 0x45 ('E') +** MATCH 0x46 ('F') +** ---------------------- +** +** The second of each pair of bytes identifies the coordinate column +** to which the constraint applies. The leftmost coordinate column +** is 'a', the second from the left 'b' etc. +*/ +static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + Rtree *pRtree = (Rtree*)tab; + int rc = SQLITE_OK; + int ii; + int bMatch = 0; /* True if there exists a MATCH constraint */ + i64 nRow; /* Estimated rows returned by this scan */ + + int iIdx = 0; + char zIdxStr[RTREE_MAX_DIMENSIONS*8+1]; + memset(zIdxStr, 0, sizeof(zIdxStr)); + + /* Check if there exists a MATCH constraint - even an unusable one. If there + ** is, do not consider the lookup-by-rowid plan as using such a plan would + ** require the VDBE to evaluate the MATCH constraint, which is not currently + ** possible. */ + for(ii=0; iinConstraint; ii++){ + if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){ + bMatch = 1; + } + } + + assert( pIdxInfo->idxStr==0 ); + for(ii=0; iinConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; + + if( bMatch==0 && p->usable + && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + /* We have an equality constraint on the rowid. Use strategy 1. */ + int jj; + for(jj=0; jjaConstraintUsage[jj].argvIndex = 0; + pIdxInfo->aConstraintUsage[jj].omit = 0; + } + pIdxInfo->idxNum = 1; + pIdxInfo->aConstraintUsage[ii].argvIndex = 1; + pIdxInfo->aConstraintUsage[jj].omit = 1; + + /* This strategy involves a two rowid lookups on an B-Tree structures + ** and then a linear search of an R-Tree node. This should be + ** considered almost as quick as a direct rowid lookup (for which + ** sqlite uses an internal cost of 0.0). It is expected to return + ** a single row. + */ + pIdxInfo->estimatedCost = 30.0; + pIdxInfo->estimatedRows = 1; + return SQLITE_OK; + } + + if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ + u8 op; + switch( p->op ){ + case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; + case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; + case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; + case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; + case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; + default: + assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH ); + op = RTREE_MATCH; + break; + } + zIdxStr[iIdx++] = op; + zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); + pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); + pIdxInfo->aConstraintUsage[ii].omit = 1; + } + } + + pIdxInfo->idxNum = 2; + pIdxInfo->needToFreeIdxStr = 1; + if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ + return SQLITE_NOMEM; + } + + nRow = pRtree->nRowEst >> (iIdx/2); + pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; + pIdxInfo->estimatedRows = nRow; + + return rc; +} + +/* +** Return the N-dimensional volumn of the cell stored in *p. +*/ +static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ + RtreeDValue area = (RtreeDValue)1; + assert( pRtree->nDim>=1 && pRtree->nDim<=5 ); +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + switch( pRtree->nDim ){ + case 5: area = p->aCoord[9].f - p->aCoord[8].f; + case 4: area *= p->aCoord[7].f - p->aCoord[6].f; + case 3: area *= p->aCoord[5].f - p->aCoord[4].f; + case 2: area *= p->aCoord[3].f - p->aCoord[2].f; + default: area *= p->aCoord[1].f - p->aCoord[0].f; + } + }else +#endif + { + switch( pRtree->nDim ){ + case 5: area = p->aCoord[9].i - p->aCoord[8].i; + case 4: area *= p->aCoord[7].i - p->aCoord[6].i; + case 3: area *= p->aCoord[5].i - p->aCoord[4].i; + case 2: area *= p->aCoord[3].i - p->aCoord[2].i; + default: area *= p->aCoord[1].i - p->aCoord[0].i; + } + } + return area; +} + +/* +** Return the margin length of cell p. The margin length is the sum +** of the objects size in each dimension. +*/ +static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){ + RtreeDValue margin = 0; + int ii = pRtree->nDim2 - 2; + do{ + margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); + ii -= 2; + }while( ii>=0 ); + return margin; +} + +/* +** Store the union of cells p1 and p2 in p1. +*/ +static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ + int ii = 0; + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + do{ + p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f); + p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f); + ii += 2; + }while( iinDim2 ); + }else{ + do{ + p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i); + p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i); + ii += 2; + }while( iinDim2 ); + } +} + +/* +** Return true if the area covered by p2 is a subset of the area covered +** by p1. False otherwise. +*/ +static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ + int ii; + int isInt = (pRtree->eCoordType==RTREE_COORD_INT32); + for(ii=0; iinDim2; ii+=2){ + RtreeCoord *a1 = &p1->aCoord[ii]; + RtreeCoord *a2 = &p2->aCoord[ii]; + if( (!isInt && (a2[0].fa1[1].f)) + || ( isInt && (a2[0].ia1[1].i)) + ){ + return 0; + } + } + return 1; +} + +/* +** Return the amount cell p would grow by if it were unioned with pCell. +*/ +static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ + RtreeDValue area; + RtreeCell cell; + memcpy(&cell, p, sizeof(RtreeCell)); + area = cellArea(pRtree, &cell); + cellUnion(pRtree, &cell, pCell); + return (cellArea(pRtree, &cell)-area); +} + +static RtreeDValue cellOverlap( + Rtree *pRtree, + RtreeCell *p, + RtreeCell *aCell, + int nCell +){ + int ii; + RtreeDValue overlap = RTREE_ZERO; + for(ii=0; iinDim2; jj+=2){ + RtreeDValue x1, x2; + x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); + x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); + if( x2iDepth-iHeight); ii++){ + int iCell; + sqlite3_int64 iBest = 0; + + RtreeDValue fMinGrowth = RTREE_ZERO; + RtreeDValue fMinArea = RTREE_ZERO; + + int nCell = NCELL(pNode); + RtreeCell cell; + RtreeNode *pChild; + + RtreeCell *aCell = 0; + + /* Select the child node which will be enlarged the least if pCell + ** is inserted into it. Resolve ties by choosing the entry with + ** the smallest area. + */ + for(iCell=0; iCellpParent ){ + RtreeNode *pParent = p->pParent; + RtreeCell cell; + int iCell; + + if( nodeParentIndex(pRtree, p, &iCell) ){ + return SQLITE_CORRUPT_VTAB; + } + + nodeGetCell(pRtree, pParent, iCell, &cell); + if( !cellContains(pRtree, &cell, pCell) ){ + cellUnion(pRtree, &cell, pCell); + nodeOverwriteCell(pRtree, pParent, &cell, iCell); + } + + p = pParent; + } + return SQLITE_OK; +} + +/* +** Write mapping (iRowid->iNode) to the _rowid table. +*/ +static int rowidWrite(Rtree *pRtree, sqlite3_int64 iRowid, sqlite3_int64 iNode){ + sqlite3_bind_int64(pRtree->pWriteRowid, 1, iRowid); + sqlite3_bind_int64(pRtree->pWriteRowid, 2, iNode); + sqlite3_step(pRtree->pWriteRowid); + return sqlite3_reset(pRtree->pWriteRowid); +} + +/* +** Write mapping (iNode->iPar) to the _parent table. +*/ +static int parentWrite(Rtree *pRtree, sqlite3_int64 iNode, sqlite3_int64 iPar){ + sqlite3_bind_int64(pRtree->pWriteParent, 1, iNode); + sqlite3_bind_int64(pRtree->pWriteParent, 2, iPar); + sqlite3_step(pRtree->pWriteParent); + return sqlite3_reset(pRtree->pWriteParent); +} + +static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int); + + +/* +** Arguments aIdx, aDistance and aSpare all point to arrays of size +** nIdx. The aIdx array contains the set of integers from 0 to +** (nIdx-1) in no particular order. This function sorts the values +** in aIdx according to the indexed values in aDistance. For +** example, assuming the inputs: +** +** aIdx = { 0, 1, 2, 3 } +** aDistance = { 5.0, 2.0, 7.0, 6.0 } +** +** this function sets the aIdx array to contain: +** +** aIdx = { 0, 1, 2, 3 } +** +** The aSpare array is used as temporary working space by the +** sorting algorithm. +*/ +static void SortByDistance( + int *aIdx, + int nIdx, + RtreeDValue *aDistance, + int *aSpare +){ + if( nIdx>1 ){ + int iLeft = 0; + int iRight = 0; + + int nLeft = nIdx/2; + int nRight = nIdx-nLeft; + int *aLeft = aIdx; + int *aRight = &aIdx[nLeft]; + + SortByDistance(aLeft, nLeft, aDistance, aSpare); + SortByDistance(aRight, nRight, aDistance, aSpare); + + memcpy(aSpare, aLeft, sizeof(int)*nLeft); + aLeft = aSpare; + + while( iLeft1 ){ + + int iLeft = 0; + int iRight = 0; + + int nLeft = nIdx/2; + int nRight = nIdx-nLeft; + int *aLeft = aIdx; + int *aRight = &aIdx[nLeft]; + + SortByDimension(pRtree, aLeft, nLeft, iDim, aCell, aSpare); + SortByDimension(pRtree, aRight, nRight, iDim, aCell, aSpare); + + memcpy(aSpare, aLeft, sizeof(int)*nLeft); + aLeft = aSpare; + while( iLeftnDim+1)*(sizeof(int*)+nCell*sizeof(int)); + + aaSorted = (int **)sqlite3_malloc(nByte); + if( !aaSorted ){ + return SQLITE_NOMEM; + } + + aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell]; + memset(aaSorted, 0, nByte); + for(ii=0; iinDim; ii++){ + int jj; + aaSorted[ii] = &((int *)&aaSorted[pRtree->nDim])[ii*nCell]; + for(jj=0; jjnDim; ii++){ + RtreeDValue margin = RTREE_ZERO; + RtreeDValue fBestOverlap = RTREE_ZERO; + RtreeDValue fBestArea = RTREE_ZERO; + int iBestLeft = 0; + int nLeft; + + for( + nLeft=RTREE_MINCELLS(pRtree); + nLeft<=(nCell-RTREE_MINCELLS(pRtree)); + nLeft++ + ){ + RtreeCell left; + RtreeCell right; + int kk; + RtreeDValue overlap; + RtreeDValue area; + + memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); + memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); + for(kk=1; kk<(nCell-1); kk++){ + if( kk0 ){ + RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); + if( pChild ){ + nodeRelease(pRtree, pChild->pParent); + nodeReference(pNode); + pChild->pParent = pNode; + } + } + return xSetMapping(pRtree, iRowid, pNode->iNode); +} + +static int SplitNode( + Rtree *pRtree, + RtreeNode *pNode, + RtreeCell *pCell, + int iHeight +){ + int i; + int newCellIsRight = 0; + + int rc = SQLITE_OK; + int nCell = NCELL(pNode); + RtreeCell *aCell; + int *aiUsed; + + RtreeNode *pLeft = 0; + RtreeNode *pRight = 0; + + RtreeCell leftbbox; + RtreeCell rightbbox; + + /* Allocate an array and populate it with a copy of pCell and + ** all cells from node pLeft. Then zero the original node. + */ + aCell = sqlite3_malloc((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); + if( !aCell ){ + rc = SQLITE_NOMEM; + goto splitnode_out; + } + aiUsed = (int *)&aCell[nCell+1]; + memset(aiUsed, 0, sizeof(int)*(nCell+1)); + for(i=0; iiNode==1 ){ + pRight = nodeNew(pRtree, pNode); + pLeft = nodeNew(pRtree, pNode); + pRtree->iDepth++; + pNode->isDirty = 1; + writeInt16(pNode->zData, pRtree->iDepth); + }else{ + pLeft = pNode; + pRight = nodeNew(pRtree, pLeft->pParent); + nodeReference(pLeft); + } + + if( !pLeft || !pRight ){ + rc = SQLITE_NOMEM; + goto splitnode_out; + } + + memset(pLeft->zData, 0, pRtree->iNodeSize); + memset(pRight->zData, 0, pRtree->iNodeSize); + + rc = splitNodeStartree(pRtree, aCell, nCell, pLeft, pRight, + &leftbbox, &rightbbox); + if( rc!=SQLITE_OK ){ + goto splitnode_out; + } + + /* Ensure both child nodes have node numbers assigned to them by calling + ** nodeWrite(). Node pRight always needs a node number, as it was created + ** by nodeNew() above. But node pLeft sometimes already has a node number. + ** In this case avoid the all to nodeWrite(). + */ + if( SQLITE_OK!=(rc = nodeWrite(pRtree, pRight)) + || (0==pLeft->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pLeft))) + ){ + goto splitnode_out; + } + + rightbbox.iRowid = pRight->iNode; + leftbbox.iRowid = pLeft->iNode; + + if( pNode->iNode==1 ){ + rc = rtreeInsertCell(pRtree, pLeft->pParent, &leftbbox, iHeight+1); + if( rc!=SQLITE_OK ){ + goto splitnode_out; + } + }else{ + RtreeNode *pParent = pLeft->pParent; + int iCell; + rc = nodeParentIndex(pRtree, pLeft, &iCell); + if( rc==SQLITE_OK ){ + nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); + rc = AdjustTree(pRtree, pParent, &leftbbox); + } + if( rc!=SQLITE_OK ){ + goto splitnode_out; + } + } + if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){ + goto splitnode_out; + } + + for(i=0; iiRowid ){ + newCellIsRight = 1; + } + if( rc!=SQLITE_OK ){ + goto splitnode_out; + } + } + if( pNode->iNode==1 ){ + for(i=0; iiRowid, pLeft, iHeight); + } + + if( rc==SQLITE_OK ){ + rc = nodeRelease(pRtree, pRight); + pRight = 0; + } + if( rc==SQLITE_OK ){ + rc = nodeRelease(pRtree, pLeft); + pLeft = 0; + } + +splitnode_out: + nodeRelease(pRtree, pRight); + nodeRelease(pRtree, pLeft); + sqlite3_free(aCell); + return rc; +} + +/* +** If node pLeaf is not the root of the r-tree and its pParent pointer is +** still NULL, load all ancestor nodes of pLeaf into memory and populate +** the pLeaf->pParent chain all the way up to the root node. +** +** This operation is required when a row is deleted (or updated - an update +** is implemented as a delete followed by an insert). SQLite provides the +** rowid of the row to delete, which can be used to find the leaf on which +** the entry resides (argument pLeaf). Once the leaf is located, this +** function is called to determine its ancestry. +*/ +static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){ + int rc = SQLITE_OK; + RtreeNode *pChild = pLeaf; + while( rc==SQLITE_OK && pChild->iNode!=1 && pChild->pParent==0 ){ + int rc2 = SQLITE_OK; /* sqlite3_reset() return code */ + sqlite3_bind_int64(pRtree->pReadParent, 1, pChild->iNode); + rc = sqlite3_step(pRtree->pReadParent); + if( rc==SQLITE_ROW ){ + RtreeNode *pTest; /* Used to test for reference loops */ + i64 iNode; /* Node number of parent node */ + + /* Before setting pChild->pParent, test that we are not creating a + ** loop of references (as we would if, say, pChild==pParent). We don't + ** want to do this as it leads to a memory leak when trying to delete + ** the referenced counted node structures. + */ + iNode = sqlite3_column_int64(pRtree->pReadParent, 0); + for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); + if( !pTest ){ + rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); + } + } + rc = sqlite3_reset(pRtree->pReadParent); + if( rc==SQLITE_OK ) rc = rc2; + if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB; + pChild = pChild->pParent; + } + return rc; +} + +static int deleteCell(Rtree *, RtreeNode *, int, int); + +static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){ + int rc; + int rc2; + RtreeNode *pParent = 0; + int iCell; + + assert( pNode->nRef==1 ); + + /* Remove the entry in the parent cell. */ + rc = nodeParentIndex(pRtree, pNode, &iCell); + if( rc==SQLITE_OK ){ + pParent = pNode->pParent; + pNode->pParent = 0; + rc = deleteCell(pRtree, pParent, iCell, iHeight+1); + } + rc2 = nodeRelease(pRtree, pParent); + if( rc==SQLITE_OK ){ + rc = rc2; + } + if( rc!=SQLITE_OK ){ + return rc; + } + + /* Remove the xxx_node entry. */ + sqlite3_bind_int64(pRtree->pDeleteNode, 1, pNode->iNode); + sqlite3_step(pRtree->pDeleteNode); + if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteNode)) ){ + return rc; + } + + /* Remove the xxx_parent entry. */ + sqlite3_bind_int64(pRtree->pDeleteParent, 1, pNode->iNode); + sqlite3_step(pRtree->pDeleteParent); + if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteParent)) ){ + return rc; + } + + /* Remove the node from the in-memory hash table and link it into + ** the Rtree.pDeleted list. Its contents will be re-inserted later on. + */ + nodeHashDelete(pRtree, pNode); + pNode->iNode = iHeight; + pNode->pNext = pRtree->pDeleted; + pNode->nRef++; + pRtree->pDeleted = pNode; + + return SQLITE_OK; +} + +static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){ + RtreeNode *pParent = pNode->pParent; + int rc = SQLITE_OK; + if( pParent ){ + int ii; + int nCell = NCELL(pNode); + RtreeCell box; /* Bounding box for pNode */ + nodeGetCell(pRtree, pNode, 0, &box); + for(ii=1; iiiNode; + rc = nodeParentIndex(pRtree, pNode, &ii); + if( rc==SQLITE_OK ){ + nodeOverwriteCell(pRtree, pParent, &box, ii); + rc = fixBoundingBox(pRtree, pParent); + } + } + return rc; +} + +/* +** Delete the cell at index iCell of node pNode. After removing the +** cell, adjust the r-tree data structure if required. +*/ +static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){ + RtreeNode *pParent; + int rc; + + if( SQLITE_OK!=(rc = fixLeafParent(pRtree, pNode)) ){ + return rc; + } + + /* Remove the cell from the node. This call just moves bytes around + ** the in-memory node image, so it cannot fail. + */ + nodeDeleteCell(pRtree, pNode, iCell); + + /* If the node is not the tree root and now has less than the minimum + ** number of cells, remove it from the tree. Otherwise, update the + ** cell in the parent node so that it tightly contains the updated + ** node. + */ + pParent = pNode->pParent; + assert( pParent || pNode->iNode==1 ); + if( pParent ){ + if( NCELL(pNode)nDim; iDim++){ + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]); + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]); + } + } + for(iDim=0; iDimnDim; iDim++){ + aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2)); + } + + for(ii=0; iinDim; iDim++){ + RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - + DCOORD(aCell[ii].aCoord[iDim*2])); + aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); + } + } + + SortByDistance(aOrder, nCell, aDistance, aSpare); + nodeZero(pRtree, pNode); + + for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){ + RtreeCell *p = &aCell[aOrder[ii]]; + nodeInsertCell(pRtree, pNode, p); + if( p->iRowid==pCell->iRowid ){ + if( iHeight==0 ){ + rc = rowidWrite(pRtree, p->iRowid, pNode->iNode); + }else{ + rc = parentWrite(pRtree, p->iRowid, pNode->iNode); + } + } + } + if( rc==SQLITE_OK ){ + rc = fixBoundingBox(pRtree, pNode); + } + for(; rc==SQLITE_OK && iiiNode currently contains + ** the height of the sub-tree headed by the cell. + */ + RtreeNode *pInsert; + RtreeCell *p = &aCell[aOrder[ii]]; + rc = ChooseLeaf(pRtree, p, iHeight, &pInsert); + if( rc==SQLITE_OK ){ + int rc2; + rc = rtreeInsertCell(pRtree, pInsert, p, iHeight); + rc2 = nodeRelease(pRtree, pInsert); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + + sqlite3_free(aCell); + return rc; +} + +/* +** Insert cell pCell into node pNode. Node pNode is the head of a +** subtree iHeight high (leaf nodes have iHeight==0). +*/ +static int rtreeInsertCell( + Rtree *pRtree, + RtreeNode *pNode, + RtreeCell *pCell, + int iHeight +){ + int rc = SQLITE_OK; + if( iHeight>0 ){ + RtreeNode *pChild = nodeHashLookup(pRtree, pCell->iRowid); + if( pChild ){ + nodeRelease(pRtree, pChild->pParent); + nodeReference(pNode); + pChild->pParent = pNode; + } + } + if( nodeInsertCell(pRtree, pNode, pCell) ){ + if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ + rc = SplitNode(pRtree, pNode, pCell, iHeight); + }else{ + pRtree->iReinsertHeight = iHeight; + rc = Reinsert(pRtree, pNode, pCell, iHeight); + } + }else{ + rc = AdjustTree(pRtree, pNode, pCell); + if( rc==SQLITE_OK ){ + if( iHeight==0 ){ + rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); + }else{ + rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode); + } + } + } + return rc; +} + +static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){ + int ii; + int rc = SQLITE_OK; + int nCell = NCELL(pNode); + + for(ii=0; rc==SQLITE_OK && iiiNode currently contains + ** the height of the sub-tree headed by the cell. + */ + rc = ChooseLeaf(pRtree, &cell, (int)pNode->iNode, &pInsert); + if( rc==SQLITE_OK ){ + int rc2; + rc = rtreeInsertCell(pRtree, pInsert, &cell, (int)pNode->iNode); + rc2 = nodeRelease(pRtree, pInsert); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + return rc; +} + +/* +** Select a currently unused rowid for a new r-tree record. +*/ +static int newRowid(Rtree *pRtree, i64 *piRowid){ + int rc; + sqlite3_bind_null(pRtree->pWriteRowid, 1); + sqlite3_bind_null(pRtree->pWriteRowid, 2); + sqlite3_step(pRtree->pWriteRowid); + rc = sqlite3_reset(pRtree->pWriteRowid); + *piRowid = sqlite3_last_insert_rowid(pRtree->db); + return rc; +} + +/* +** Remove the entry with rowid=iDelete from the r-tree structure. +*/ +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 */ + + + /* Obtain a reference to the root node to initialize Rtree.iDepth */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + + /* Obtain a reference to the leaf node that contains the entry + ** about to be deleted. + */ + if( rc==SQLITE_OK ){ + rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); + } + + /* Delete the cell in question from the leaf node. */ + if( rc==SQLITE_OK ){ + int rc2; + rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); + if( rc==SQLITE_OK ){ + rc = deleteCell(pRtree, pLeaf, iCell, 0); + } + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + + /* Delete the corresponding entry in the _rowid table. */ + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); + sqlite3_step(pRtree->pDeleteRowid); + rc = sqlite3_reset(pRtree->pDeleteRowid); + } + + /* Check if the root node now has exactly one child. If so, remove + ** it, schedule the contents of the child for reinsertion and + ** reduce the tree height by one. + ** + ** This is equivalent to copying the contents of the child into + ** the root node (the operation that Gutman's paper says to perform + ** in this scenario). + */ + if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ + int rc2; + RtreeNode *pChild; + i64 iChild = nodeGetRowid(pRtree, pRoot, 0); + rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); + if( rc==SQLITE_OK ){ + rc = removeNode(pRtree, pChild, pRtree->iDepth-1); + } + rc2 = nodeRelease(pRtree, pChild); + if( rc==SQLITE_OK ) rc = rc2; + if( rc==SQLITE_OK ){ + pRtree->iDepth--; + writeInt16(pRoot->zData, pRtree->iDepth); + pRoot->isDirty = 1; + } + } + + /* Re-insert the contents of any underfull nodes removed from the tree. */ + for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ + if( rc==SQLITE_OK ){ + rc = reinsertNodeContent(pRtree, pLeaf); + } + pRtree->pDeleted = pLeaf->pNext; + sqlite3_free(pLeaf); + } + + /* Release the reference to the root node. */ + if( rc==SQLITE_OK ){ + rc = nodeRelease(pRtree, pRoot); + }else{ + nodeRelease(pRtree, pRoot); + } + + return rc; +} + +/* +** Rounding constants for float->double conversion. +*/ +#define RNDTOWARDS (1.0 - 1.0/8388608.0) /* Round towards zero */ +#define RNDAWAY (1.0 + 1.0/8388608.0) /* Round away from zero */ + +#if !defined(SQLITE_RTREE_INT_ONLY) +/* +** Convert an sqlite3_value into an RtreeValue (presumably a float) +** while taking care to round toward negative or positive, respectively. +*/ +static RtreeValue rtreeValueDown(sqlite3_value *v){ + double d = sqlite3_value_double(v); + float f = (float)d; + if( f>d ){ + f = (float)(d*(d<0 ? RNDAWAY : RNDTOWARDS)); + } + return f; +} +static RtreeValue rtreeValueUp(sqlite3_value *v){ + double d = sqlite3_value_double(v); + float f = (float)d; + if( fbase.zErrMsg) to an appropriate value and returns +** SQLITE_CONSTRAINT. +** +** Parameter iCol is the index of the leftmost column involved in the +** constraint failure. If it is 0, then the constraint that failed is +** the unique constraint on the id column. Otherwise, it is the rtree +** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. +** +** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. +*/ +static int rtreeConstraintError(Rtree *pRtree, int iCol){ + sqlite3_stmt *pStmt = 0; + char *zSql; + int rc; + + assert( iCol==0 || iCol%2 ); + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); + if( zSql ){ + rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); + }else{ + rc = SQLITE_NOMEM; + } + sqlite3_free(zSql); + + if( rc==SQLITE_OK ){ + if( iCol==0 ){ + const char *zCol = sqlite3_column_name(pStmt, 0); + pRtree->base.zErrMsg = sqlite3_mprintf( + "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol + ); + }else{ + const char *zCol1 = sqlite3_column_name(pStmt, iCol); + const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); + pRtree->base.zErrMsg = sqlite3_mprintf( + "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 + ); + } + } + + sqlite3_finalize(pStmt); + return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); +} + + + +/* +** The xUpdate method for rtree module virtual tables. +*/ +static int rtreeUpdate( + sqlite3_vtab *pVtab, + int nData, + sqlite3_value **azData, + sqlite_int64 *pRowid +){ + Rtree *pRtree = (Rtree *)pVtab; + int rc = SQLITE_OK; + RtreeCell cell; /* New cell to insert if nData>1 */ + int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ + + rtreeReference(pRtree); + assert(nData>=1); + + cell.iRowid = 0; /* Used only to suppress a compiler warning */ + + /* Constraint handling. A write operation on an r-tree table may return + ** SQLITE_CONSTRAINT for two reasons: + ** + ** 1. A duplicate rowid value, or + ** 2. The supplied data violates the "x2>=x1" constraint. + ** + ** In the first case, if the conflict-handling mode is REPLACE, then + ** the conflicting row can be removed before proceeding. In the second + ** case, SQLITE_CONSTRAINT must be returned regardless of the + ** conflict-handling mode specified by the user. + */ + if( nData>1 ){ + int ii; + + /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. + ** + ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared + ** with "column" that are interpreted as table constraints. + ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); + ** This problem was discovered after years of use, so we silently ignore + ** these kinds of misdeclared tables to avoid breaking any legacy. + */ + assert( nData<=(pRtree->nDim2 + 3) ); + +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + for(ii=0; iicell.aCoord[ii+1].f ){ + rc = rtreeConstraintError(pRtree, ii+1); + goto constraint; + } + } + }else +#endif + { + for(ii=0; iicell.aCoord[ii+1].i ){ + rc = rtreeConstraintError(pRtree, ii+1); + goto constraint; + } + } + } + + /* If a rowid value was supplied, check if it is already present in + ** the table. If so, the constraint has failed. */ + if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ + cell.iRowid = sqlite3_value_int64(azData[2]); + if( sqlite3_value_type(azData[0])==SQLITE_NULL + || sqlite3_value_int64(azData[0])!=cell.iRowid + ){ + int steprc; + sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); + steprc = sqlite3_step(pRtree->pReadRowid); + rc = sqlite3_reset(pRtree->pReadRowid); + if( SQLITE_ROW==steprc ){ + if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ + rc = rtreeDeleteRowid(pRtree, cell.iRowid); + }else{ + rc = rtreeConstraintError(pRtree, 0); + goto constraint; + } + } + } + bHaveRowid = 1; + } + } + + /* If azData[0] is not an SQL NULL value, it is the rowid of a + ** record to delete from the r-tree table. The following block does + ** just that. + */ + if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ + rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0])); + } + + /* If the azData[] array contains more than one element, elements + ** (azData[2]..azData[argc-1]) contain a new record to insert into + ** the r-tree structure. + */ + if( rc==SQLITE_OK && nData>1 ){ + /* Insert the new record into the r-tree */ + RtreeNode *pLeaf = 0; + + /* Figure out the rowid of the new row. */ + if( bHaveRowid==0 ){ + rc = newRowid(pRtree, &cell.iRowid); + } + *pRowid = cell.iRowid; + + if( rc==SQLITE_OK ){ + rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); + } + if( rc==SQLITE_OK ){ + int rc2; + pRtree->iReinsertHeight = -1; + rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + +constraint: + rtreeRelease(pRtree); + return rc; +} + +/* +** Called when a transaction starts. +*/ +static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; + assert( pRtree->inWrTrans==0 ); + pRtree->inWrTrans++; + return SQLITE_OK; +} + +/* +** Called when a transaction completes (either by COMMIT or ROLLBACK). +** The sqlite3_blob object should be released at this point. +*/ +static int rtreeEndTransaction(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; + pRtree->inWrTrans = 0; + nodeBlobReset(pRtree); + return SQLITE_OK; +} + +/* +** The xRename method for rtree module virtual tables. +*/ +static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ + Rtree *pRtree = (Rtree *)pVtab; + int rc = SQLITE_NOMEM; + char *zSql = sqlite3_mprintf( + "ALTER TABLE %Q.'%q_node' RENAME TO \"%w_node\";" + "ALTER TABLE %Q.'%q_parent' RENAME TO \"%w_parent\";" + "ALTER TABLE %Q.'%q_rowid' RENAME TO \"%w_rowid\";" + , pRtree->zDb, pRtree->zName, zNewName + , pRtree->zDb, pRtree->zName, zNewName + , pRtree->zDb, pRtree->zName, zNewName + ); + if( zSql ){ + nodeBlobReset(pRtree); + rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0); + sqlite3_free(zSql); + } + return rc; +} + +/* +** The xSavepoint method. +** +** This module does not need to do anything to support savepoints. However, +** it uses this hook to close any open blob handle. This is done because a +** DROP TABLE command - which fortunately always opens a savepoint - cannot +** succeed if there are any open blob handles. i.e. if the blob handle were +** not closed here, the following would fail: +** +** BEGIN; +** INSERT INTO rtree... +** DROP TABLE ; -- Would fail with SQLITE_LOCKED +** COMMIT; +*/ +static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ + Rtree *pRtree = (Rtree *)pVtab; + int iwt = pRtree->inWrTrans; + UNUSED_PARAMETER(iSavepoint); + pRtree->inWrTrans = 0; + nodeBlobReset(pRtree); + pRtree->inWrTrans = iwt; + return SQLITE_OK; +} + +/* +** This function populates the pRtree->nRowEst variable with an estimate +** of the number of rows in the virtual table. If possible, this is based +** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. +*/ +static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ + const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; + char *zSql; + sqlite3_stmt *p; + int rc; + i64 nRow = 0; + + rc = sqlite3_table_column_metadata( + db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 + ); + if( rc!=SQLITE_OK ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + return rc==SQLITE_ERROR ? SQLITE_OK : rc; + } + zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); + if( rc==SQLITE_OK ){ + if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); + rc = sqlite3_finalize(p); + }else if( rc!=SQLITE_NOMEM ){ + rc = SQLITE_OK; + } + + if( rc==SQLITE_OK ){ + if( nRow==0 ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + }else{ + pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); + } + } + sqlite3_free(zSql); + } + + return rc; +} + +static sqlite3_module rtreeModule = { + 2, /* iVersion */ + rtreeCreate, /* xCreate - create a table */ + rtreeConnect, /* xConnect - connect to an existing table */ + rtreeBestIndex, /* xBestIndex - Determine search strategy */ + rtreeDisconnect, /* xDisconnect - Disconnect from a table */ + rtreeDestroy, /* xDestroy - Drop a table */ + rtreeOpen, /* xOpen - open a cursor */ + rtreeClose, /* xClose - close a cursor */ + rtreeFilter, /* xFilter - configure scan constraints */ + rtreeNext, /* xNext - advance a cursor */ + rtreeEof, /* xEof */ + rtreeColumn, /* xColumn - read data */ + rtreeRowid, /* xRowid - read data */ + rtreeUpdate, /* xUpdate - write data */ + rtreeBeginTransaction, /* xBegin - begin transaction */ + rtreeEndTransaction, /* xSync - sync transaction */ + rtreeEndTransaction, /* xCommit - commit transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ + 0, /* xFindFunction - function overloading */ + rtreeRename, /* xRename - rename the table */ + rtreeSavepoint, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ +}; + +static int rtreeSqlInit( + Rtree *pRtree, + sqlite3 *db, + const char *zDb, + const char *zPrefix, + int isCreate +){ + int rc = SQLITE_OK; + + #define N_STATEMENT 8 + static const char *azSql[N_STATEMENT] = { + /* Write the xxx_node table */ + "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)", + "DELETE FROM '%q'.'%q_node' WHERE nodeno = :1", + + /* Read and write the xxx_rowid table */ + "SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = :1", + "INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(:1, :2)", + "DELETE FROM '%q'.'%q_rowid' WHERE rowid = :1", + + /* Read and write the xxx_parent table */ + "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = :1", + "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(:1, :2)", + "DELETE FROM '%q'.'%q_parent' WHERE nodeno = :1" + }; + sqlite3_stmt **appStmt[N_STATEMENT]; + int i; + + pRtree->db = db; + + if( isCreate ){ + char *zCreate = sqlite3_mprintf( +"CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);" +"CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);" +"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY," + " parentnode INTEGER);" +"INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))", + zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize + ); + if( !zCreate ){ + return SQLITE_NOMEM; + } + rc = sqlite3_exec(db, zCreate, 0, 0, 0); + sqlite3_free(zCreate); + if( rc!=SQLITE_OK ){ + return rc; + } + } + + appStmt[0] = &pRtree->pWriteNode; + appStmt[1] = &pRtree->pDeleteNode; + appStmt[2] = &pRtree->pReadRowid; + appStmt[3] = &pRtree->pWriteRowid; + appStmt[4] = &pRtree->pDeleteRowid; + appStmt[5] = &pRtree->pReadParent; + appStmt[6] = &pRtree->pWriteParent; + appStmt[7] = &pRtree->pDeleteParent; + + rc = rtreeQueryStat1(db, pRtree); + for(i=0; iiNodeSize is populated and SQLITE_OK returned. +** Otherwise, an SQLite error code is returned. +** +** If this function is being called as part of an xConnect(), then the rtree +** table already exists. In this case the node-size is determined by inspecting +** the root node of the tree. +** +** Otherwise, for an xCreate(), use 64 bytes less than the database page-size. +** This ensures that each node is stored on a single database page. If the +** database page-size is so large that more than RTREE_MAXCELLS entries +** would fit in a single node, use a smaller node-size. +*/ +static int getNodeSize( + sqlite3 *db, /* Database handle */ + Rtree *pRtree, /* Rtree handle */ + int isCreate, /* True for xCreate, false for xConnect */ + char **pzErr /* OUT: Error message, if any */ +){ + int rc; + char *zSql; + if( isCreate ){ + int iPageSize = 0; + zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb); + rc = getIntFromStmt(db, zSql, &iPageSize); + if( rc==SQLITE_OK ){ + pRtree->iNodeSize = iPageSize-64; + if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)iNodeSize ){ + pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS; + } + }else{ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + }else{ + zSql = sqlite3_mprintf( + "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1", + pRtree->zDb, pRtree->zName + ); + rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); + if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + } + + sqlite3_free(zSql); + return rc; +} + +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the r-tree virtual table. +** +** argv[0] -> module name +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> column names... +*/ +static int rtreeInit( + sqlite3 *db, /* Database connection */ + void *pAux, /* One of the RTREE_COORD_* constants */ + int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ + sqlite3_vtab **ppVtab, /* OUT: New virtual table */ + char **pzErr, /* OUT: Error message, if any */ + int isCreate /* True for xCreate, false for xConnect */ +){ + int rc = SQLITE_OK; + Rtree *pRtree; + int nDb; /* Length of string argv[1] */ + int nName; /* Length of string argv[2] */ + int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32); + + const char *aErrMsg[] = { + 0, /* 0 */ + "Wrong number of columns for an rtree table", /* 1 */ + "Too few columns for an rtree table", /* 2 */ + "Too many columns for an rtree table" /* 3 */ + }; + + int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2; + if( aErrMsg[iErr] ){ + *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); + return SQLITE_ERROR; + } + + sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + + /* Allocate the sqlite3_vtab structure */ + nDb = (int)strlen(argv[1]); + nName = (int)strlen(argv[2]); + pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); + if( !pRtree ){ + return SQLITE_NOMEM; + } + memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); + pRtree->nBusy = 1; + pRtree->base.pModule = &rtreeModule; + pRtree->zDb = (char *)&pRtree[1]; + pRtree->zName = &pRtree->zDb[nDb+1]; + pRtree->nDim = (u8)((argc-4)/2); + pRtree->nDim2 = pRtree->nDim*2; + pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; + pRtree->eCoordType = (u8)eCoordType; + memcpy(pRtree->zDb, argv[1], nDb); + memcpy(pRtree->zName, argv[2], nName); + + /* Figure out the node size to use. */ + rc = getNodeSize(db, pRtree, isCreate, pzErr); + + /* Create/Connect to the underlying relational database schema. If + ** that is successful, call sqlite3_declare_vtab() to configure + ** the r-tree table schema. + */ + if( rc==SQLITE_OK ){ + if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + }else{ + char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]); + char *zTmp; + int ii; + for(ii=4; zSql && iinBusy==1 ); + rtreeRelease(pRtree); + } + return rc; +} + + +/* +** Implementation of a scalar function that decodes r-tree nodes to +** human readable strings. This can be used for debugging and analysis. +** +** The scalar function takes two arguments: (1) the number of dimensions +** to the rtree (between 1 and 5, inclusive) and (2) a blob of data containing +** an r-tree node. For a two-dimensional r-tree structure called "rt", to +** deserialize all nodes, a statement like: +** +** SELECT rtreenode(2, data) FROM rt_node; +** +** The human readable string takes the form of a Tcl list with one +** entry for each cell in the r-tree node. Each entry is itself a +** list, containing the 8-byte rowid/pageno followed by the +** *2 coordinates. +*/ +static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ + char *zText = 0; + RtreeNode node; + Rtree tree; + int ii; + + UNUSED_PARAMETER(nArg); + memset(&node, 0, sizeof(RtreeNode)); + memset(&tree, 0, sizeof(Rtree)); + tree.nDim = (u8)sqlite3_value_int(apArg[0]); + tree.nDim2 = tree.nDim*2; + tree.nBytesPerCell = 8 + 8 * tree.nDim; + node.zData = (u8 *)sqlite3_value_blob(apArg[1]); + + for(ii=0; iixDestructor ) pInfo->xDestructor(pInfo->pContext); + sqlite3_free(p); +} + +/* +** This routine frees the BLOB that is returned by geomCallback(). +*/ +static void rtreeMatchArgFree(void *pArg){ + int i; + RtreeMatchArg *p = (RtreeMatchArg*)pArg; + for(i=0; inParam; i++){ + sqlite3_value_free(p->apSqlParam[i]); + } + sqlite3_free(p); +} + +/* +** Each call to sqlite3_rtree_geometry_callback() or +** sqlite3_rtree_query_callback() creates an ordinary SQLite +** scalar function that is implemented by this routine. +** +** All this function does is construct an RtreeMatchArg object that +** contains the geometry-checking callback routines and a list of +** parameters to this function, then return that RtreeMatchArg object +** as a BLOB. +** +** The R-Tree MATCH operator will read the returned BLOB, deserialize +** the RtreeMatchArg object, and use the RtreeMatchArg object to figure +** out which elements of the R-Tree should be returned by the query. +*/ +static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ + RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx); + RtreeMatchArg *pBlob; + int nBlob; + int memErr = 0; + + nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue) + + nArg*sizeof(sqlite3_value*); + pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob); + if( !pBlob ){ + sqlite3_result_error_nomem(ctx); + }else{ + int i; + pBlob->magic = RTREE_GEOMETRY_MAGIC; + pBlob->cb = pGeomCtx[0]; + pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg]; + pBlob->nParam = nArg; + for(i=0; iapSqlParam[i] = sqlite3_value_dup(aArg[i]); + if( pBlob->apSqlParam[i]==0 ) memErr = 1; +#ifdef SQLITE_RTREE_INT_ONLY + pBlob->aParam[i] = sqlite3_value_int64(aArg[i]); +#else + pBlob->aParam[i] = sqlite3_value_double(aArg[i]); +#endif + } + if( memErr ){ + sqlite3_result_error_nomem(ctx); + rtreeMatchArgFree(pBlob); + }else{ + sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree); + } + } +} + +/* +** Register a new geometry function for use with the r-tree MATCH operator. +*/ +SQLITE_API int sqlite3_rtree_geometry_callback( + sqlite3 *db, /* Register SQL function on this connection */ + const char *zGeom, /* Name of the new SQL function */ + int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */ + void *pContext /* Extra data associated with the callback */ +){ + RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ + + /* Allocate and populate the context object. */ + pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); + if( !pGeomCtx ) return SQLITE_NOMEM; + pGeomCtx->xGeom = xGeom; + pGeomCtx->xQueryFunc = 0; + pGeomCtx->xDestructor = 0; + pGeomCtx->pContext = pContext; + return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, + (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback + ); +} + +/* +** Register a new 2nd-generation geometry function for use with the +** r-tree MATCH operator. +*/ +SQLITE_API int sqlite3_rtree_query_callback( + sqlite3 *db, /* Register SQL function on this connection */ + const char *zQueryFunc, /* Name of new SQL function */ + int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */ + void *pContext, /* Extra data passed into the callback */ + void (*xDestructor)(void*) /* Destructor for the extra data */ +){ + RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ + + /* Allocate and populate the context object. */ + pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); + if( !pGeomCtx ) return SQLITE_NOMEM; + pGeomCtx->xGeom = 0; + pGeomCtx->xQueryFunc = xQueryFunc; + pGeomCtx->xDestructor = xDestructor; + pGeomCtx->pContext = pContext; + return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, + (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback + ); +} + +#if !SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_rtree_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + return sqlite3RtreeInit(db); +} +#endif + +#endif + +/************** End of rtree.c ***********************************************/ +/************** Begin file icu.c *********************************************/ +/* +** 2007 May 6 +** +** 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. +** +************************************************************************* +** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ +** +** This file implements an integration between the ICU library +** ("International Components for Unicode", an open-source library +** for handling unicode data) and SQLite. The integration uses +** ICU to provide the following to SQLite: +** +** * An implementation of the SQL regexp() function (and hence REGEXP +** operator) using the ICU uregex_XX() APIs. +** +** * Implementations of the SQL scalar upper() and lower() functions +** for case mapping. +** +** * Integration of ICU and SQLite collation sequences. +** +** * An implementation of the LIKE operator that uses ICU to +** provide case-independent matching. +*/ + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) + +/* Include ICU headers */ +#include +#include +#include +#include + +/* #include */ + +#ifndef SQLITE_CORE +/* #include "sqlite3ext.h" */ + SQLITE_EXTENSION_INIT1 +#else +/* #include "sqlite3.h" */ +#endif + +/* +** Maximum length (in bytes) of the pattern in a LIKE or GLOB +** operator. +*/ +#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH +# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 +#endif + +/* +** Version of sqlite3_free() that is always a function, never a macro. +*/ +static void xFree(void *p){ + sqlite3_free(p); +} + +/* +** This lookup table is used to help decode the first byte of +** a multi-byte UTF8 character. It is copied here from SQLite source +** code file utf8.c. +*/ +static const unsigned char icuUtf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; + +#define SQLITE_ICU_READ_UTF8(zIn, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = icuUtf8Trans1[c-0xc0]; \ + while( (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + } + +#define SQLITE_ICU_SKIP_UTF8(zIn) \ + assert( *zIn ); \ + if( *(zIn++)>=0xc0 ){ \ + while( (*zIn & 0xc0)==0x80 ){zIn++;} \ + } + + +/* +** Compare two UTF-8 strings for equality where the first string is +** a "LIKE" expression. Return true (1) if they are the same and +** false (0) if they are different. +*/ +static int icuLikeCompare( + const uint8_t *zPattern, /* LIKE pattern */ + const uint8_t *zString, /* The UTF-8 string to compare against */ + const UChar32 uEsc /* The escape character */ +){ + static const int MATCH_ONE = (UChar32)'_'; + static const int MATCH_ALL = (UChar32)'%'; + + int prevEscape = 0; /* True if the previous character was uEsc */ + + while( 1 ){ + + /* Read (and consume) the next character from the input pattern. */ + UChar32 uPattern; + SQLITE_ICU_READ_UTF8(zPattern, uPattern); + if( uPattern==0 ) break; + + /* There are now 4 possibilities: + ** + ** 1. uPattern is an unescaped match-all character "%", + ** 2. uPattern is an unescaped match-one character "_", + ** 3. uPattern is an unescaped escape character, or + ** 4. uPattern is to be handled as an ordinary character + */ + if( !prevEscape && uPattern==MATCH_ALL ){ + /* Case 1. */ + uint8_t c; + + /* Skip any MATCH_ALL or MATCH_ONE characters that follow a + ** MATCH_ALL. For each MATCH_ONE, skip one character in the + ** test string. + */ + while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ + if( c==MATCH_ONE ){ + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); + } + zPattern++; + } + + if( *zPattern==0 ) return 1; + + while( *zString ){ + if( icuLikeCompare(zPattern, zString, uEsc) ){ + return 1; + } + SQLITE_ICU_SKIP_UTF8(zString); + } + return 0; + + }else if( !prevEscape && uPattern==MATCH_ONE ){ + /* Case 2. */ + if( *zString==0 ) return 0; + SQLITE_ICU_SKIP_UTF8(zString); + + }else if( !prevEscape && uPattern==uEsc){ + /* Case 3. */ + prevEscape = 1; + + }else{ + /* Case 4. */ + UChar32 uString; + SQLITE_ICU_READ_UTF8(zString, uString); + uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT); + uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT); + if( uString!=uPattern ){ + return 0; + } + prevEscape = 0; + } + } + + return *zString==0; +} + +/* +** Implementation of the like() SQL function. This function implements +** the build-in LIKE operator. The first argument to the function is the +** pattern and the second argument is the string. So, the SQL statements: +** +** A LIKE B +** +** is implemented as like(B, A). If there is an escape character E, +** +** A LIKE B ESCAPE E +** +** is mapped to like(B, A, E). +*/ +static void icuLikeFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zA = sqlite3_value_text(argv[0]); + const unsigned char *zB = sqlite3_value_text(argv[1]); + UChar32 uEsc = 0; + + /* Limit the length of the LIKE or GLOB pattern to avoid problems + ** of deep recursion and N*N behavior in patternCompare(). + */ + if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ + sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); + return; + } + + + if( argc==3 ){ + /* The escape character string must consist of a single UTF-8 character. + ** Otherwise, return an error. + */ + int nE= sqlite3_value_bytes(argv[2]); + const unsigned char *zE = sqlite3_value_text(argv[2]); + int i = 0; + if( zE==0 ) return; + U8_NEXT(zE, i, nE, uEsc); + if( i!=nE){ + sqlite3_result_error(context, + "ESCAPE expression must be a single character", -1); + return; + } + } + + if( zA && zB ){ + sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc)); + } +} + +/* +** This function is called when an ICU function called from within +** the implementation of an SQL scalar function returns an error. +** +** The scalar function context passed as the first argument is +** loaded with an error message based on the following two args. +*/ +static void icuFunctionError( + sqlite3_context *pCtx, /* SQLite scalar function context */ + const char *zName, /* Name of ICU function that failed */ + UErrorCode e /* Error code returned by ICU function */ +){ + char zBuf[128]; + sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); + zBuf[127] = '\0'; + sqlite3_result_error(pCtx, zBuf, -1); +} + +/* +** Function to delete compiled regexp objects. Registered as +** a destructor function with sqlite3_set_auxdata(). +*/ +static void icuRegexpDelete(void *p){ + URegularExpression *pExpr = (URegularExpression *)p; + uregex_close(pExpr); +} + +/* +** Implementation of SQLite REGEXP operator. This scalar function takes +** two arguments. The first is a regular expression pattern to compile +** the second is a string to match against that pattern. If either +** argument is an SQL NULL, then NULL Is returned. Otherwise, the result +** is 1 if the string matches the pattern, or 0 otherwise. +** +** SQLite maps the regexp() function to the regexp() operator such +** that the following two are equivalent: +** +** zString REGEXP zPattern +** regexp(zPattern, zString) +** +** Uses the following ICU regexp APIs: +** +** uregex_open() +** uregex_matches() +** uregex_close() +*/ +static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ + UErrorCode status = U_ZERO_ERROR; + URegularExpression *pExpr; + UBool res; + const UChar *zString = sqlite3_value_text16(apArg[1]); + + (void)nArg; /* Unused parameter */ + + /* If the left hand side of the regexp operator is NULL, + ** then the result is also NULL. + */ + if( !zString ){ + return; + } + + pExpr = sqlite3_get_auxdata(p, 0); + if( !pExpr ){ + const UChar *zPattern = sqlite3_value_text16(apArg[0]); + if( !zPattern ){ + return; + } + pExpr = uregex_open(zPattern, -1, 0, 0, &status); + + if( U_SUCCESS(status) ){ + sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); + }else{ + assert(!pExpr); + icuFunctionError(p, "uregex_open", status); + return; + } + } + + /* Configure the text that the regular expression operates on. */ + uregex_setText(pExpr, zString, -1, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "uregex_setText", status); + return; + } + + /* Attempt the match */ + res = uregex_matches(pExpr, 0, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "uregex_matches", status); + return; + } + + /* Set the text that the regular expression operates on to a NULL + ** pointer. This is not really necessary, but it is tidier than + ** leaving the regular expression object configured with an invalid + ** pointer after this function returns. + */ + uregex_setText(pExpr, 0, 0, &status); + + /* Return 1 or 0. */ + sqlite3_result_int(p, res ? 1 : 0); +} + +/* +** Implementations of scalar functions for case mapping - upper() and +** lower(). Function upper() converts its input to upper-case (ABC). +** Function lower() converts to lower-case (abc). +** +** ICU provides two types of case mapping, "general" case mapping and +** "language specific". Refer to ICU documentation for the differences +** between the two. +** +** To utilise "general" case mapping, the upper() or lower() scalar +** functions are invoked with one argument: +** +** upper('ABC') -> 'abc' +** lower('abc') -> 'ABC' +** +** To access ICU "language specific" case mapping, upper() or lower() +** should be invoked with two arguments. The second argument is the name +** of the locale to use. Passing an empty string ("") or SQL NULL value +** as the second argument is the same as invoking the 1 argument version +** of upper() or lower(). +** +** lower('I', 'en_us') -> 'i' +** lower('I', 'tr_tr') -> '\u131' (small dotless i) +** +** http://www.icu-project.org/userguide/posix.html#case_mappings +*/ +static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ + const UChar *zInput; /* Pointer to input string */ + UChar *zOutput = 0; /* Pointer to output buffer */ + int nInput; /* Size of utf-16 input string in bytes */ + int nOut; /* Size of output buffer in bytes */ + int cnt; + int bToUpper; /* True for toupper(), false for tolower() */ + UErrorCode status; + const char *zLocale = 0; + + assert(nArg==1 || nArg==2); + bToUpper = (sqlite3_user_data(p)!=0); + if( nArg==2 ){ + zLocale = (const char *)sqlite3_value_text(apArg[1]); + } + + zInput = sqlite3_value_text16(apArg[0]); + if( !zInput ){ + return; + } + nOut = nInput = sqlite3_value_bytes16(apArg[0]); + if( nOut==0 ){ + sqlite3_result_text16(p, "", 0, SQLITE_STATIC); + return; + } + + for(cnt=0; cnt<2; cnt++){ + UChar *zNew = sqlite3_realloc(zOutput, nOut); + if( zNew==0 ){ + sqlite3_free(zOutput); + sqlite3_result_error_nomem(p); + return; + } + zOutput = zNew; + status = U_ZERO_ERROR; + if( bToUpper ){ + nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + }else{ + nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + } + + if( U_SUCCESS(status) ){ + sqlite3_result_text16(p, zOutput, nOut, xFree); + }else if( status==U_BUFFER_OVERFLOW_ERROR ){ + assert( cnt==0 ); + continue; + }else{ + icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); + } + return; + } + assert( 0 ); /* Unreachable */ +} + +/* +** Collation sequence destructor function. The pCtx argument points to +** a UCollator structure previously allocated using ucol_open(). +*/ +static void icuCollationDel(void *pCtx){ + UCollator *p = (UCollator *)pCtx; + ucol_close(p); +} + +/* +** Collation sequence comparison function. The pCtx argument points to +** a UCollator structure previously allocated using ucol_open(). +*/ +static int icuCollationColl( + void *pCtx, + int nLeft, + const void *zLeft, + int nRight, + const void *zRight +){ + UCollationResult res; + UCollator *p = (UCollator *)pCtx; + res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2); + switch( res ){ + case UCOL_LESS: return -1; + case UCOL_GREATER: return +1; + case UCOL_EQUAL: return 0; + } + assert(!"Unexpected return value from ucol_strcoll()"); + return 0; +} + +/* +** Implementation of the scalar function icu_load_collation(). +** +** This scalar function is used to add ICU collation based collation +** types to an SQLite database connection. It is intended to be called +** as follows: +** +** SELECT icu_load_collation(, ); +** +** Where is a string containing an ICU locale identifier (i.e. +** "en_AU", "tr_TR" etc.) and is the name of the +** collation sequence to create. +*/ +static void icuLoadCollation( + sqlite3_context *p, + int nArg, + sqlite3_value **apArg +){ + sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); + UErrorCode status = U_ZERO_ERROR; + const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ + const char *zName; /* SQL Collation sequence name (eg. "japanese") */ + UCollator *pUCollator; /* ICU library collation object */ + int rc; /* Return code from sqlite3_create_collation_x() */ + + assert(nArg==2); + (void)nArg; /* Unused parameter */ + zLocale = (const char *)sqlite3_value_text(apArg[0]); + zName = (const char *)sqlite3_value_text(apArg[1]); + + if( !zLocale || !zName ){ + return; + } + + pUCollator = ucol_open(zLocale, &status); + if( !U_SUCCESS(status) ){ + icuFunctionError(p, "ucol_open", status); + return; + } + assert(p); + + rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, + icuCollationColl, icuCollationDel + ); + if( rc!=SQLITE_OK ){ + ucol_close(pUCollator); + sqlite3_result_error(p, "Error registering collation function", -1); + } +} + +/* +** Register the ICU extension functions with database db. +*/ +SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ + static const struct IcuScalar { + const char *zName; /* Function name */ + unsigned char nArg; /* Number of arguments */ + unsigned short enc; /* Optimal text encoding */ + unsigned char iContext; /* sqlite3_user_data() context */ + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } scalars[] = { + {"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation}, + {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc}, + {"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, + {"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, + {"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, + }; + int rc = SQLITE_OK; + int i; + + + for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ + const struct IcuScalar *p = &scalars[i]; + rc = sqlite3_create_function( + db, p->zName, p->nArg, p->enc, + p->iContext ? (void*)db : (void*)0, + p->xFunc, 0, 0 + ); + } + + return rc; +} + +#if !SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_icu_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + return sqlite3IcuInit(db); +} +#endif + +#endif + +/************** End of icu.c *************************************************/ +/************** Begin file fts3_icu.c ****************************************/ +/* +** 2007 June 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file implements a tokenizer for fts3 based on the ICU library. +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) +#ifdef SQLITE_ENABLE_ICU + +/* #include */ +/* #include */ +/* #include "fts3_tokenizer.h" */ + +#include +/* #include */ +/* #include */ +#include + +typedef struct IcuTokenizer IcuTokenizer; +typedef struct IcuCursor IcuCursor; + +struct IcuTokenizer { + sqlite3_tokenizer base; + char *zLocale; +}; + +struct IcuCursor { + sqlite3_tokenizer_cursor base; + + UBreakIterator *pIter; /* ICU break-iterator object */ + int nChar; /* Number of UChar elements in pInput */ + UChar *aChar; /* Copy of input using utf-16 encoding */ + int *aOffset; /* Offsets of each character in utf-8 input */ + + int nBuffer; + char *zBuffer; + + int iToken; +}; + +/* +** Create a new tokenizer instance. +*/ +static int icuCreate( + int argc, /* Number of entries in argv[] */ + const char * const *argv, /* Tokenizer creation arguments */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ +){ + IcuTokenizer *p; + int n = 0; + + if( argc>0 ){ + n = strlen(argv[0])+1; + } + p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n); + if( !p ){ + return SQLITE_NOMEM; + } + memset(p, 0, sizeof(IcuTokenizer)); + + if( n ){ + p->zLocale = (char *)&p[1]; + memcpy(p->zLocale, argv[0], n); + } + + *ppTokenizer = (sqlite3_tokenizer *)p; + + return SQLITE_OK; +} + +/* +** Destroy a tokenizer +*/ +static int icuDestroy(sqlite3_tokenizer *pTokenizer){ + IcuTokenizer *p = (IcuTokenizer *)pTokenizer; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is pInput[0..nBytes-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int icuOpen( + sqlite3_tokenizer *pTokenizer, /* The tokenizer */ + const char *zInput, /* Input string */ + int nInput, /* Length of zInput in bytes */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +){ + IcuTokenizer *p = (IcuTokenizer *)pTokenizer; + IcuCursor *pCsr; + + const int32_t opt = U_FOLD_CASE_DEFAULT; + UErrorCode status = U_ZERO_ERROR; + int nChar; + + UChar32 c; + int iInput = 0; + int iOut = 0; + + *ppCursor = 0; + + if( zInput==0 ){ + nInput = 0; + zInput = ""; + }else if( nInput<0 ){ + nInput = strlen(zInput); + } + nChar = nInput+1; + pCsr = (IcuCursor *)sqlite3_malloc( + sizeof(IcuCursor) + /* IcuCursor */ + ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ + (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ + ); + if( !pCsr ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(IcuCursor)); + pCsr->aChar = (UChar *)&pCsr[1]; + pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; + + pCsr->aOffset[iOut] = iInput; + U8_NEXT(zInput, iInput, nInput, c); + while( c>0 ){ + int isError = 0; + c = u_foldCase(c, opt); + U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); + if( isError ){ + sqlite3_free(pCsr); + return SQLITE_ERROR; + } + pCsr->aOffset[iOut] = iInput; + + if( iInputpIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); + if( !U_SUCCESS(status) ){ + sqlite3_free(pCsr); + return SQLITE_ERROR; + } + pCsr->nChar = iOut; + + ubrk_first(pCsr->pIter); + *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Close a tokenization cursor previously opened by a call to icuOpen(). +*/ +static int icuClose(sqlite3_tokenizer_cursor *pCursor){ + IcuCursor *pCsr = (IcuCursor *)pCursor; + ubrk_close(pCsr->pIter); + sqlite3_free(pCsr->zBuffer); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Extract the next token from a tokenization cursor. +*/ +static int icuNext( + sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ + const char **ppToken, /* OUT: *ppToken is the token text */ + int *pnBytes, /* OUT: Number of bytes in token */ + int *piStartOffset, /* OUT: Starting offset of token */ + int *piEndOffset, /* OUT: Ending offset of token */ + int *piPosition /* OUT: Position integer of token */ +){ + IcuCursor *pCsr = (IcuCursor *)pCursor; + + int iStart = 0; + int iEnd = 0; + int nByte = 0; + + while( iStart==iEnd ){ + UChar32 c; + + iStart = ubrk_current(pCsr->pIter); + iEnd = ubrk_next(pCsr->pIter); + if( iEnd==UBRK_DONE ){ + return SQLITE_DONE; + } + + while( iStartaChar, iWhite, pCsr->nChar, c); + if( u_isspace(c) ){ + iStart = iWhite; + }else{ + break; + } + } + assert(iStart<=iEnd); + } + + do { + UErrorCode status = U_ZERO_ERROR; + if( nByte ){ + char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); + if( !zNew ){ + return SQLITE_NOMEM; + } + pCsr->zBuffer = zNew; + pCsr->nBuffer = nByte; + } + + u_strToUTF8( + pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ + &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ + &status /* Output success/failure */ + ); + } while( nByte>pCsr->nBuffer ); + + *ppToken = pCsr->zBuffer; + *pnBytes = nByte; + *piStartOffset = pCsr->aOffset[iStart]; + *piEndOffset = pCsr->aOffset[iEnd]; + *piPosition = pCsr->iToken++; + + return SQLITE_OK; +} + +/* +** The set of routines that implement the simple tokenizer +*/ +static const sqlite3_tokenizer_module icuTokenizerModule = { + 0, /* iVersion */ + icuCreate, /* xCreate */ + icuDestroy, /* xCreate */ + icuOpen, /* xOpen */ + icuClose, /* xClose */ + icuNext, /* xNext */ + 0, /* xLanguageid */ +}; + +/* +** Set *ppModule to point at the implementation of the ICU tokenizer. +*/ +SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( + sqlite3_tokenizer_module const**ppModule +){ + *ppModule = &icuTokenizerModule; +} + +#endif /* defined(SQLITE_ENABLE_ICU) */ +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_icu.c ********************************************/ +/************** Begin file sqlite3rbu.c **************************************/ +/* +** 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. +** +************************************************************************* +** +** +** OVERVIEW +** +** The RBU extension requires that the RBU update be packaged as an +** SQLite database. The tables it expects to find are described in +** sqlite3rbu.h. Essentially, for each table xyz in the target database +** that the user wishes to write to, a corresponding data_xyz table is +** created in the RBU database and populated with one row for each row to +** update, insert or delete from the target table. +** +** The update proceeds in three stages: +** +** 1) The database is updated. The modified database pages are written +** to a *-oal file. A *-oal file is just like a *-wal file, except +** that it is named "-oal" instead of "-wal". +** Because regular SQLite clients do not look for file named +** "-oal", they go on using the original database in +** rollback mode while the *-oal file is being generated. +** +** During this stage RBU does not update the database by writing +** directly to the target tables. Instead it creates "imposter" +** tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses +** to update each b-tree individually. All updates required by each +** b-tree are completed before moving on to the next, and all +** updates are done in sorted key order. +** +** 2) The "-oal" file is moved to the equivalent "-wal" +** location using a call to rename(2). Before doing this the RBU +** module takes an EXCLUSIVE lock on the database file, ensuring +** that there are no other active readers. +** +** Once the EXCLUSIVE lock is released, any other database readers +** detect the new *-wal file and read the database in wal mode. At +** this point they see the new version of the database - including +** the updates made as part of the RBU update. +** +** 3) The new *-wal file is checkpointed. This proceeds in the same way +** as a regular database checkpoint, except that a single frame is +** checkpointed each time sqlite3rbu_step() is called. If the RBU +** handle is closed before the entire *-wal file is checkpointed, +** the checkpoint progress is saved in the RBU database and the +** checkpoint can be resumed by another RBU client at some point in +** the future. +** +** POTENTIAL PROBLEMS +** +** The rename() call might not be portable. And RBU is not currently +** syncing the directory after renaming the file. +** +** When state is saved, any commit to the *-oal file and the commit to +** the RBU update database are not atomic. So if the power fails at the +** wrong moment they might get out of sync. As the main database will be +** committed before the RBU update database this will likely either just +** pass unnoticed, or result in SQLITE_CONSTRAINT errors (due to UNIQUE +** constraint violations). +** +** If some client does modify the target database mid RBU update, or some +** other error occurs, the RBU extension will keep throwing errors. It's +** not really clear how to get out of this state. The system could just +** by delete the RBU update database and *-oal file and have the device +** download the update again and start over. +** +** At present, for an UPDATE, both the new.* and old.* records are +** collected in the rbu_xyz table. And for both UPDATEs and DELETEs all +** fields are collected. This means we're probably writing a lot more +** data to disk when saving the state of an ongoing update to the RBU +** update database than is strictly necessary. +** +*/ + +/* #include */ +/* #include */ +/* #include */ + +/* #include "sqlite3.h" */ + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) +/************** Include sqlite3rbu.h in the middle of sqlite3rbu.c ***********/ +/************** Begin file sqlite3rbu.h **************************************/ +/* +** 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. +** +************************************************************************* +** +** This file contains the public interface for the RBU extension. +*/ + +/* +** SUMMARY +** +** Writing a transaction containing a large number of operations on +** b-tree indexes that are collectively larger than the available cache +** memory can be very inefficient. +** +** The problem is that in order to update a b-tree, the leaf page (at least) +** containing the entry being inserted or deleted must be modified. If the +** working set of leaves is larger than the available cache memory, then a +** single leaf that is modified more than once as part of the transaction +** may be loaded from or written to the persistent media multiple times. +** Additionally, because the index updates are likely to be applied in +** random order, access to pages within the database is also likely to be in +** random order, which is itself quite inefficient. +** +** One way to improve the situation is to sort the operations on each index +** by index key before applying them to the b-tree. This leads to an IO +** pattern that resembles a single linear scan through the index b-tree, +** and all but guarantees each modified leaf page is loaded and stored +** exactly once. SQLite uses this trick to improve the performance of +** CREATE INDEX commands. This extension allows it to be used to improve +** the performance of large transactions on existing databases. +** +** Additionally, this extension allows the work involved in writing the +** large transaction to be broken down into sub-transactions performed +** sequentially by separate processes. This is useful if the system cannot +** guarantee that a single update process will run for long enough to apply +** the entire update, for example because the update is being applied on a +** mobile device that is frequently rebooted. Even after the writer process +** has committed one or more sub-transactions, other database clients continue +** to read from the original database snapshot. In other words, partially +** applied transactions are not visible to other clients. +** +** "RBU" stands for "Resumable Bulk Update". As in a large database update +** transmitted via a wireless network to a mobile device. A transaction +** applied using this extension is hence refered to as an "RBU update". +** +** +** LIMITATIONS +** +** An "RBU update" transaction is subject to the following limitations: +** +** * The transaction must consist of INSERT, UPDATE and DELETE operations +** only. +** +** * INSERT statements may not use any default values. +** +** * UPDATE and DELETE statements must identify their target rows by +** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY +** KEY fields may not be updated or deleted. If the table being written +** has no PRIMARY KEY, affected rows must be identified by rowid. +** +** * UPDATE statements may not modify PRIMARY KEY columns. +** +** * No triggers will be fired. +** +** * No foreign key violations are detected or reported. +** +** * CHECK constraints are not enforced. +** +** * No constraint handling mode except for "OR ROLLBACK" is supported. +** +** +** PREPARATION +** +** An "RBU update" is stored as a separate SQLite database. A database +** containing an RBU update is an "RBU database". For each table in the +** target database to be updated, the RBU database should contain a table +** named "data_" containing the same set of columns as the +** target table, and one more - "rbu_control". The data_% table should +** have no PRIMARY KEY or UNIQUE constraints, but each column should have +** the same type as the corresponding column in the target database. +** The "rbu_control" column should have no type at all. For example, if +** the target database contains: +** +** CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c UNIQUE); +** +** Then the RBU database should contain: +** +** CREATE TABLE data_t1(a INTEGER, b TEXT, c, rbu_control); +** +** The order of the columns in the data_% table does not matter. +** +** Instead of a regular table, the RBU database may also contain virtual +** tables or view named using the data_ naming scheme. +** +** Instead of the plain data_ naming scheme, RBU database tables +** may also be named data_, where is any sequence +** of zero or more numeric characters (0-9). This can be significant because +** tables within the RBU database are always processed in order sorted by +** name. By judicious selection of the portion of the names +** of the RBU tables the user can therefore control the order in which they +** are processed. This can be useful, for example, to ensure that "external +** content" FTS4 tables are updated before their underlying content tables. +** +** If the target database table is a virtual table or a table that has no +** PRIMARY KEY declaration, the data_% table must also contain a column +** named "rbu_rowid". This column is mapped to the tables implicit primary +** key column - "rowid". Virtual tables for which the "rowid" column does +** not function like a primary key value cannot be updated using RBU. For +** example, if the target db contains either of the following: +** +** CREATE VIRTUAL TABLE x1 USING fts3(a, b); +** CREATE TABLE x1(a, b) +** +** then the RBU database should contain: +** +** CREATE TABLE data_x1(a, b, rbu_rowid, rbu_control); +** +** All non-hidden columns (i.e. all columns matched by "SELECT *") of the +** target table must be present in the input table. For virtual tables, +** hidden columns are optional - they are updated by RBU if present in +** the input table, or not otherwise. For example, to write to an fts4 +** table with a hidden languageid column such as: +** +** CREATE VIRTUAL TABLE ft1 USING fts4(a, b, languageid='langid'); +** +** Either of the following input table schemas may be used: +** +** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control); +** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control); +** +** For each row to INSERT into the target database as part of the RBU +** update, the corresponding data_% table should contain a single record +** with the "rbu_control" column set to contain integer value 0. The +** other columns should be set to the values that make up the new record +** to insert. +** +** If the target database table has an INTEGER PRIMARY KEY, it is not +** possible to insert a NULL value into the IPK column. Attempting to +** do so results in an SQLITE_MISMATCH error. +** +** For each row to DELETE from the target database as part of the RBU +** update, the corresponding data_% table should contain a single record +** with the "rbu_control" column set to contain integer value 1. The +** real primary key values of the row to delete should be stored in the +** corresponding columns of the data_% table. The values stored in the +** other columns are not used. +** +** For each row to UPDATE from the target database as part of the RBU +** update, the corresponding data_% table should contain a single record +** with the "rbu_control" column set to contain a value of type text. +** The real primary key values identifying the row to update should be +** stored in the corresponding columns of the data_% table row, as should +** the new values of all columns being update. The text value in the +** "rbu_control" column must contain the same number of characters as +** there are columns in the target database table, and must consist entirely +** of 'x' and '.' characters (or in some special cases 'd' - see below). For +** each column that is being updated, the corresponding character is set to +** 'x'. For those that remain as they are, the corresponding character of the +** rbu_control value should be set to '.'. For example, given the tables +** above, the update statement: +** +** UPDATE t1 SET c = 'usa' WHERE a = 4; +** +** is represented by the data_t1 row created by: +** +** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..x'); +** +** Instead of an 'x' character, characters of the rbu_control value specified +** for UPDATEs may also be set to 'd'. In this case, instead of updating the +** target table with the value stored in the corresponding data_% column, the +** user-defined SQL function "rbu_delta()" is invoked and the result stored in +** the target table column. rbu_delta() is invoked with two arguments - the +** original value currently stored in the target table column and the +** value specified in the data_xxx table. +** +** For example, this row: +** +** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d'); +** +** is similar to an UPDATE statement such as: +** +** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4; +** +** Finally, if an 'f' character appears in place of a 'd' or 's' in an +** ota_control string, the contents of the data_xxx table column is assumed +** to be a "fossil delta" - a patch to be applied to a blob value in the +** format used by the fossil source-code management system. In this case +** the existing value within the target database table must be of type BLOB. +** It is replaced by the result of applying the specified fossil delta to +** itself. +** +** If the target database table is a virtual table or a table with no PRIMARY +** KEY, the rbu_control value should not include a character corresponding +** to the rbu_rowid value. For example, this: +** +** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control) +** VALUES(NULL, 'usa', 12, '.x'); +** +** causes a result similar to: +** +** UPDATE ft1 SET b = 'usa' WHERE rowid = 12; +** +** The data_xxx tables themselves should have no PRIMARY KEY declarations. +** However, RBU is more efficient if reading the rows in from each data_xxx +** table in "rowid" order is roughly the same as reading them sorted by +** the PRIMARY KEY of the corresponding target database table. In other +** words, rows should be sorted using the destination table PRIMARY KEY +** fields before they are inserted into the data_xxx tables. +** +** USAGE +** +** The API declared below allows an application to apply an RBU update +** stored on disk to an existing target database. Essentially, the +** application: +** +** 1) Opens an RBU handle using the sqlite3rbu_open() function. +** +** 2) Registers any required virtual table modules with the database +** handle returned by sqlite3rbu_db(). Also, if required, register +** the rbu_delta() implementation. +** +** 3) Calls the sqlite3rbu_step() function one or more times on +** the new handle. Each call to sqlite3rbu_step() performs a single +** b-tree operation, so thousands of calls may be required to apply +** a complete update. +** +** 4) Calls sqlite3rbu_close() to close the RBU update handle. If +** sqlite3rbu_step() has been called enough times to completely +** apply the update to the target database, then the RBU database +** is marked as fully applied. Otherwise, the state of the RBU +** update application is saved in the RBU database for later +** resumption. +** +** See comments below for more detail on APIs. +** +** If an update is only partially applied to the target database by the +** time sqlite3rbu_close() is called, various state information is saved +** within the RBU database. This allows subsequent processes to automatically +** resume the RBU update from where it left off. +** +** To remove all RBU extension state information, returning an RBU database +** to its original contents, it is sufficient to drop all tables that begin +** with the prefix "rbu_" +** +** DATABASE LOCKING +** +** An RBU update may not be applied to a database in WAL mode. Attempting +** to do so is an error (SQLITE_ERROR). +** +** While an RBU handle is open, a SHARED lock may be held on the target +** database file. This means it is possible for other clients to read the +** database, but not to write it. +** +** If an RBU update is started and then suspended before it is completed, +** then an external client writes to the database, then attempting to resume +** the suspended RBU update is also an error (SQLITE_BUSY). +*/ + +#ifndef _SQLITE3RBU_H +#define _SQLITE3RBU_H + +/* #include "sqlite3.h" ** Required for error code definitions ** */ + +#if 0 +extern "C" { +#endif + +typedef struct sqlite3rbu sqlite3rbu; + +/* +** Open an RBU handle. +** +** Argument zTarget is the path to the target database. Argument zRbu is +** the path to the RBU database. Each call to this function must be matched +** by a call to sqlite3rbu_close(). When opening the databases, RBU passes +** the SQLITE_CONFIG_URI flag to sqlite3_open_v2(). So if either zTarget +** or zRbu begin with "file:", it will be interpreted as an SQLite +** database URI, not a regular file name. +** +** If the zState argument is passed a NULL value, the RBU extension stores +** the current state of the update (how many rows have been updated, which +** indexes are yet to be updated etc.) within the RBU database itself. This +** can be convenient, as it means that the RBU application does not need to +** organize removing a separate state file after the update is concluded. +** Or, if zState is non-NULL, it must be a path to a database file in which +** the RBU extension can store the state of the update. +** +** When resuming an RBU update, the zState argument must be passed the same +** value as when the RBU update was started. +** +** Once the RBU update is finished, the RBU extension does not +** automatically remove any zState database file, even if it created it. +** +** By default, RBU uses the default VFS to access the files on disk. To +** use a VFS other than the default, an SQLite "file:" URI containing a +** "vfs=..." option may be passed as the zTarget option. +** +** IMPORTANT NOTE FOR ZIPVFS USERS: The RBU extension works with all of +** SQLite's built-in VFSs, including the multiplexor VFS. However it does +** 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. +*/ +SQLITE_API sqlite3rbu *sqlite3rbu_open( + const char *zTarget, + const char *zRbu, + const char *zState +); + +/* +** Open an RBU handle to perform an RBU vacuum on database file zTarget. +** An RBU vacuum is similar to SQLite's built-in VACUUM command, except +** that it can be suspended and resumed like an RBU update. +** +** The second argument to this function identifies a database in which +** to store the state of the RBU vacuum operation if it is suspended. The +** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum +** operation, the state database should either not exist or be empty +** (contain no tables). If an RBU vacuum is suspended by calling +** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has +** returned SQLITE_DONE, the vacuum state is stored in the state database. +** The vacuum can be resumed by calling this function to open a new RBU +** handle specifying the same target and state databases. +** +** If the second argument passed to this function is NULL, then the +** name of the state database is "-vacuum", where +** is the name of the target database file. In this case, on UNIX, if the +** state database is not already present in the file-system, it is created +** with the same permissions as the target db is made. +** +** This function does not delete the state database after an RBU vacuum +** is completed, even if it created it. However, if the call to +** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents +** of the state tables within the state database are zeroed. This way, +** the next call to sqlite3rbu_vacuum() opens a handle that starts a +** new RBU vacuum operation. +** +** As with sqlite3rbu_open(), Zipvfs users should rever to the comment +** describing the sqlite3rbu_create_vfs() API function below for +** a description of the complications associated with using RBU with +** zipvfs databases. +*/ +SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( + const char *zTarget, + const char *zState +); + +/* +** 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. +** +** The first argument passed to this function must be a valid, open, RBU +** handle. The second argument should be passed zero to access the target +** database handle, or non-zero to access the rbu update database handle. +** Accessing the underlying database handles may be useful in the +** following scenarios: +** +** * If any target tables are virtual tables, it may be necessary to +** call sqlite3_create_module() on the target database handle to +** register the required virtual table implementations. +** +** * If the data_xxx tables in the RBU source database are virtual +** tables, the application may need to call sqlite3_create_module() on +** the rbu update db handle to any required virtual table +** implementations. +** +** * If the application uses the "rbu_delta()" feature described above, +** it must use sqlite3_create_function() or similar to register the +** rbu_delta() implementation with the target database handle. +** +** If an error has occurred, either while opening or stepping the RBU object, +** this function may return NULL. The error code and message may be collected +** when sqlite3rbu_close() is called. +** +** Database handles returned by this function remain valid until the next +** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db(). +*/ +SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu); + +/* +** Do some work towards applying the RBU update to the target db. +** +** Return SQLITE_DONE if the update has been completely applied, or +** SQLITE_OK if no error occurs but there remains work to do to apply +** the RBU update. If an error does occur, some other error code is +** returned. +** +** Once a call to sqlite3rbu_step() has returned a value other than +** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops +** that immediately return the same value. +*/ +SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu); + +/* +** Force RBU to save its state to disk. +** +** If a power failure or application crash occurs during an update, following +** system recovery RBU may resume the update from the point at which the state +** was last saved. In other words, from the most recent successful call to +** sqlite3rbu_close() or this function. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); + +/* +** Close an RBU handle. +** +** If the RBU update has been completely applied, mark the RBU database +** as fully applied. Otherwise, assuming no error has occurred, save the +** current state of the RBU update appliation to the RBU database. +** +** If an error has already occurred as part of an sqlite3rbu_step() +** or sqlite3rbu_open() call, or if one occurs within this function, an +** SQLite error code is returned. Additionally, *pzErrmsg may be set to +** point to a buffer containing a utf-8 formatted English language error +** message. It is the responsibility of the caller to eventually free any +** such buffer using sqlite3_free(). +** +** Otherwise, if no error occurs, this function returns SQLITE_OK if the +** update has been partially applied, or SQLITE_DONE if it has been +** completely applied. +*/ +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. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu); + +/* +** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100) +** progress indications for the two stages of an RBU update. This API may +** be useful for driving GUI progress indicators and similar. +** +** An RBU update is divided into two stages: +** +** * Stage 1, in which changes are accumulated in an oal/wal file, and +** * Stage 2, in which the contents of the wal file are copied into the +** main database. +** +** The update is visible to non-RBU clients during stage 2. During stage 1 +** non-RBU reader clients may see the original database. +** +** If this API is called during stage 2 of the update, output variable +** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo) +** to a value between 0 and 10000 to indicate the permyriadage progress of +** stage 2. A value of 5000 indicates that stage 2 is half finished, +** 9000 indicates that it is 90% finished, and so on. +** +** If this API is called during stage 1 of the update, output variable +** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The +** value to which (*pnOne) is set depends on whether or not the RBU +** database contains an "rbu_count" table. The rbu_count table, if it +** exists, must contain the same columns as the following: +** +** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID; +** +** There must be one row in the table for each source (data_xxx) table within +** the RBU database. The 'tbl' column should contain the name of the source +** table. The 'cnt' column should contain the number of rows within the +** source table. +** +** If the rbu_count table is present and populated correctly and this +** API is called during stage 1, the *pnOne output variable is set to the +** permyriadage progress of the same stage. If the rbu_count table does +** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count +** 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); + +/* +** Obtain an indication as to the current stage of an RBU update or vacuum. +** This function always returns one of the SQLITE_RBU_STATE_XXX constants +** defined in this file. Return values should be interpreted as follows: +** +** SQLITE_RBU_STATE_OAL: +** RBU is currently building a *-oal file. The next call to sqlite3rbu_step() +** may either add further data to the *-oal file, or compute data that will +** be added by a subsequent call. +** +** SQLITE_RBU_STATE_MOVE: +** RBU has finished building the *-oal file. The next call to sqlite3rbu_step() +** will move the *-oal file to the equivalent *-wal path. If the current +** operation is an RBU update, then the updated version of the database +** file will become visible to ordinary SQLite clients following the next +** call to sqlite3rbu_step(). +** +** SQLITE_RBU_STATE_CHECKPOINT: +** RBU is currently performing an incremental checkpoint. The next call to +** sqlite3rbu_step() will copy a page of data from the *-wal file into +** the target database file. +** +** SQLITE_RBU_STATE_DONE: +** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step() +** will immediately return SQLITE_DONE. +** +** SQLITE_RBU_STATE_ERROR: +** An error has occurred. Any subsequent calls to sqlite3rbu_step() will +** immediately return the SQLite error code associated with the error. +*/ +#define SQLITE_RBU_STATE_OAL 1 +#define SQLITE_RBU_STATE_MOVE 2 +#define SQLITE_RBU_STATE_CHECKPOINT 3 +#define SQLITE_RBU_STATE_DONE 4 +#define SQLITE_RBU_STATE_ERROR 5 + +SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu); + +/* +** Create an RBU VFS named zName that accesses the underlying file-system +** via existing VFS zParent. Or, if the zParent parameter is passed NULL, +** then the new RBU VFS uses the default system VFS to access the file-system. +** The new object is registered as a non-default VFS with SQLite before +** returning. +** +** Part of the RBU implementation uses a custom VFS object. Usually, this +** object is created and deleted automatically by RBU. +** +** The exception is for applications that also use zipvfs. In this case, +** the custom VFS must be explicitly created by the user before the RBU +** handle is opened. The RBU VFS should be installed so that the zipvfs +** VFS uses the RBU VFS, which in turn uses any other VFS layers in use +** (for example multiplexor) to access the file-system. For example, +** to assemble an RBU enabled VFS stack that uses both zipvfs and +** multiplexor (error checking omitted): +** +** // Create a VFS named "multiplex" (not the default). +** sqlite3_multiplex_initialize(0, 0); +** +** // Create an rbu VFS named "rbu" that uses multiplexor. If the +** // second argument were replaced with NULL, the "rbu" VFS would +** // access the file-system via the system default VFS, bypassing the +** // multiplexor. +** sqlite3rbu_create_vfs("rbu", "multiplex"); +** +** // Create a zipvfs VFS named "zipvfs" that uses rbu. +** zipvfs_create_vfs_v3("zipvfs", "rbu", 0, xCompressorAlgorithmDetector); +** +** // Make zipvfs the default VFS. +** sqlite3_vfs_register(sqlite3_vfs_find("zipvfs"), 1); +** +** Because the default VFS created above includes a RBU functionality, it +** may be used by RBU clients. Attempting to use RBU with a zipvfs VFS stack +** that does not include the RBU layer results in an error. +** +** The overhead of adding the "rbu" VFS to the system is negligible for +** non-RBU users. There is no harm in an application accessing the +** file-system via "rbu" all the time, even if it only uses RBU functionality +** occasionally. +*/ +SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent); + +/* +** Deregister and destroy an RBU vfs created by an earlier call to +** sqlite3rbu_create_vfs(). +** +** VFS objects are not reference counted. If a VFS object is destroyed +** before all database handles that use it have been closed, the results +** are undefined. +*/ +SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); + +#if 0 +} /* end of the 'extern "C"' block */ +#endif + +#endif /* _SQLITE3RBU_H */ + +/************** End of sqlite3rbu.h ******************************************/ +/************** Continuing where we left off in sqlite3rbu.c *****************/ + +#if defined(_WIN32_WCE) +/* #include "windows.h" */ +#endif + +/* Maximum number of prepared UPDATE statements held by this module */ +#define SQLITE_RBU_UPDATE_CACHESIZE 16 + +/* +** Swap two objects of type TYPE. +*/ +#if !defined(SQLITE_AMALGAMATION) +# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} +#endif + +/* +** The rbu_state table is used to save the state of a partially applied +** update so that it can be resumed later. The table consists of integer +** keys mapped to values as follows: +** +** RBU_STATE_STAGE: +** May be set to integer values 1, 2, 4 or 5. As follows: +** 1: the *-rbu file is currently under construction. +** 2: the *-rbu file has been constructed, but not yet moved +** to the *-wal path. +** 4: the checkpoint is underway. +** 5: the rbu update has been checkpointed. +** +** RBU_STATE_TBL: +** Only valid if STAGE==1. The target database name of the table +** currently being written. +** +** RBU_STATE_IDX: +** Only valid if STAGE==1. The target database name of the index +** currently being written, or NULL if the main table is currently being +** updated. +** +** RBU_STATE_ROW: +** Only valid if STAGE==1. Number of rows already processed for the current +** table/index. +** +** RBU_STATE_PROGRESS: +** Trbul number of sqlite3rbu_step() calls made so far as part of this +** rbu update. +** +** RBU_STATE_CKPT: +** Valid if STAGE==4. The 64-bit checksum associated with the wal-index +** header created by recovering the *-wal file. This is used to detect +** cases when another client appends frames to the *-wal file in the +** middle of an incremental checkpoint (an incremental checkpoint cannot +** be continued if this happens). +** +** RBU_STATE_COOKIE: +** Valid if STAGE==1. The current change-counter cookie value in the +** target db file. +** +** RBU_STATE_OALSZ: +** Valid if STAGE==1. The size in bytes of the *-oal file. +*/ +#define RBU_STATE_STAGE 1 +#define RBU_STATE_TBL 2 +#define RBU_STATE_IDX 3 +#define RBU_STATE_ROW 4 +#define RBU_STATE_PROGRESS 5 +#define RBU_STATE_CKPT 6 +#define RBU_STATE_COOKIE 7 +#define RBU_STATE_OALSZ 8 +#define RBU_STATE_PHASEONESTEP 9 + +#define RBU_STAGE_OAL 1 +#define RBU_STAGE_MOVE 2 +#define RBU_STAGE_CAPTURE 3 +#define RBU_STAGE_CKPT 4 +#define RBU_STAGE_DONE 5 + + +#define RBU_CREATE_STATE \ + "CREATE TABLE IF NOT EXISTS %s.rbu_state(k INTEGER PRIMARY KEY, v)" + +typedef struct RbuFrame RbuFrame; +typedef struct RbuObjIter RbuObjIter; +typedef struct RbuState RbuState; +typedef struct rbu_vfs rbu_vfs; +typedef struct rbu_file rbu_file; +typedef struct RbuUpdateStmt RbuUpdateStmt; + +#if !defined(SQLITE_AMALGAMATION) +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +typedef sqlite3_int64 i64; +#endif + +/* +** These values must match the values defined in wal.c for the equivalent +** locks. These are not magic numbers as they are part of the SQLite file +** format. +*/ +#define WAL_LOCK_WRITE 0 +#define WAL_LOCK_CKPT 1 +#define WAL_LOCK_READ0 3 + +#define SQLITE_FCNTL_RBUCNT 5149216 + +/* +** A structure to store values read from the rbu_state table in memory. +*/ +struct RbuState { + int eStage; + char *zTbl; + char *zIdx; + i64 iWalCksum; + int nRow; + i64 nProgress; + u32 iCookie; + i64 iOalSz; + i64 nPhaseOneStep; +}; + +struct RbuUpdateStmt { + char *zMask; /* Copy of update mask used with pUpdate */ + sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */ + RbuUpdateStmt *pNext; +}; + +/* +** An iterator of this type is used to iterate through all objects in +** the target database that require updating. For each such table, the +** iterator visits, in order: +** +** * the table itself, +** * each index of the table (zero or more points to visit), and +** * a special "cleanup table" state. +** +** abIndexed: +** If the table has no indexes on it, abIndexed is set to NULL. Otherwise, +** it points to an array of flags nTblCol elements in size. The flag is +** set for each column that is either a part of the PK or a part of an +** index. Or clear otherwise. +** +*/ +struct RbuObjIter { + sqlite3_stmt *pTblIter; /* Iterate through tables */ + sqlite3_stmt *pIdxIter; /* Index iterator */ + int nTblCol; /* Size of azTblCol[] array */ + char **azTblCol; /* Array of unquoted target column names */ + char **azTblType; /* Array of target column types */ + int *aiSrcOrder; /* src table col -> target table col */ + u8 *abTblPk; /* Array of flags, set on target PK columns */ + u8 *abNotNull; /* Array of flags, set on NOT NULL columns */ + u8 *abIndexed; /* Array of flags, set on indexed & PK cols */ + int eType; /* Table type - an RBU_PK_XXX value */ + + /* Output variables. zTbl==0 implies EOF. */ + int bCleanup; /* True in "cleanup" state */ + const char *zTbl; /* Name of target db table */ + const char *zDataTbl; /* Name of rbu db table (or null) */ + const char *zIdx; /* Name of target db index (or null) */ + int iTnum; /* Root page of current object */ + int iPkTnum; /* If eType==EXTERNAL, root of PK index */ + int bUnique; /* Current index is unique */ + int nIndex; /* Number of aux. indexes on table zTbl */ + + /* Statements created by rbuObjIterPrepareAll() */ + int nCol; /* Number of columns in current object */ + sqlite3_stmt *pSelect; /* Source data */ + sqlite3_stmt *pInsert; /* Statement for INSERT operations */ + sqlite3_stmt *pDelete; /* Statement for DELETE ops */ + sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */ + + /* Last UPDATE used (for PK b-tree updates only), or NULL. */ + RbuUpdateStmt *pRbuUpdate; +}; + +/* +** Values for RbuObjIter.eType +** +** 0: Table does not exist (error) +** 1: Table has an implicit rowid. +** 2: Table has an explicit IPK column. +** 3: Table has an external PK index. +** 4: Table is WITHOUT ROWID. +** 5: Table is a virtual table. +*/ +#define RBU_PK_NOTABLE 0 +#define RBU_PK_NONE 1 +#define RBU_PK_IPK 2 +#define RBU_PK_EXTERNAL 3 +#define RBU_PK_WITHOUT_ROWID 4 +#define RBU_PK_VTAB 5 + + +/* +** Within the RBU_STAGE_OAL stage, each call to sqlite3rbu_step() performs +** one of the following operations. +*/ +#define RBU_INSERT 1 /* Insert on a main table b-tree */ +#define RBU_DELETE 2 /* Delete a row from a main table b-tree */ +#define RBU_REPLACE 3 /* Delete and then insert a row */ +#define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */ +#define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */ + +#define RBU_UPDATE 6 /* Update a row in a main table b-tree */ + +/* +** A single step of an incremental checkpoint - frame iWalFrame of the wal +** file should be copied to page iDbPage of the database file. +*/ +struct RbuFrame { + u32 iDbPage; + u32 iWalFrame; +}; + +/* +** RBU handle. +** +** nPhaseOneStep: +** If the RBU database contains an rbu_count table, this value is set to +** a running estimate of the number of b-tree operations required to +** finish populating the *-oal file. This allows the sqlite3_bp_progress() +** API to calculate the permyriadage progress of populating the *-oal file +** using the formula: +** +** permyriadage = (10000 * nProgress) / nPhaseOneStep +** +** nPhaseOneStep is initialized to the sum of: +** +** nRow * (nIndex + 1) +** +** for all source tables in the RBU database, where nRow is the number +** of rows in the source table and nIndex the number of indexes on the +** corresponding target database table. +** +** This estimate is accurate if the RBU update consists entirely of +** INSERT operations. However, it is inaccurate if: +** +** * the RBU update contains any UPDATE operations. If the PK specified +** for an UPDATE operation does not exist in the target table, then +** no b-tree operations are required on index b-trees. Or if the +** specified PK does exist, then (nIndex*2) such operations are +** required (one delete and one insert on each index b-tree). +** +** * the RBU update contains any DELETE operations for which the specified +** PK does not exist. In this case no operations are required on index +** b-trees. +** +** * the RBU update contains REPLACE operations. These are similar to +** UPDATE operations. +** +** nPhaseOneStep is updated to account for the conditions above during the +** first pass of each source table. The updated nPhaseOneStep value is +** stored in the rbu_state table if the RBU update is suspended. +*/ +struct sqlite3rbu { + int eStage; /* Value of RBU_STATE_STAGE field */ + sqlite3 *dbMain; /* target database handle */ + sqlite3 *dbRbu; /* rbu database handle */ + char *zTarget; /* Path to target db */ + char *zRbu; /* Path to rbu db */ + char *zState; /* Path to state db (or NULL if zRbu) */ + char zStateDb[5]; /* Db name for state ("stat" or "main") */ + int rc; /* Value returned by last rbu_step() call */ + char *zErrmsg; /* Error message if rc!=SQLITE_OK */ + int nStep; /* Rows processed for current object */ + int nProgress; /* Rows processed for all objects */ + RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ + const char *zVfsName; /* Name of automatically created rbu vfs */ + rbu_file *pTargetFd; /* File handle open on target db */ + int nPagePerSector; /* Pages per sector for pTargetFd */ + i64 iOalSz; + i64 nPhaseOneStep; + + /* The following state variables are used as part of the incremental + ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding + ** function rbuSetupCheckpoint() for details. */ + u32 iMaxFrame; /* Largest iWalFrame value in aFrame[] */ + u32 mLock; + int nFrame; /* Entries in aFrame[] array */ + int nFrameAlloc; /* Allocated size of aFrame[] array */ + RbuFrame *aFrame; + int pgsz; + u8 *aBuf; + i64 iWalCksum; + + /* Used in RBU vacuum mode only */ + int nRbu; /* Number of RBU VFS in the stack */ + rbu_file *pRbuFd; /* Fd for main db of dbRbu */ +}; + +/* +** An rbu VFS is implemented using an instance of this structure. +*/ +struct rbu_vfs { + sqlite3_vfs base; /* rbu VFS shim methods */ + sqlite3_vfs *pRealVfs; /* Underlying VFS */ + sqlite3_mutex *mutex; /* Mutex to protect pMain */ + 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. +*/ +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) */ + + int openFlags; /* Flags this file was opened with */ + u32 iCookie; /* Cookie value for main db files */ + u8 iWriteVer; /* "write-version" value for main db files */ + u8 bNolock; /* True to fail EXCLUSIVE locks */ + + int nShm; /* Number of entries in apShm[] array */ + char **apShm; /* Array of mmap'd *-shm regions */ + char *zDel; /* Delete this when closing file */ + + const char *zWal; /* Wal filename for this main db file */ + rbu_file *pWalFd; /* Wal file descriptor for this main db */ + rbu_file *pMainNext; /* Next MAIN_DB file */ +}; + +/* +** True for an RBU vacuum handle, or false otherwise. +*/ +#define rbuIsVacuum(p) ((p)->zTarget==0) + + +/************************************************************************* +** The following three functions, found below: +** +** rbuDeltaGetInt() +** rbuDeltaChecksum() +** rbuDeltaApply() +** +** are lifted from the fossil source code (http://fossil-scm.org). They +** are used to implement the scalar SQL function rbu_fossil_delta(). +*/ + +/* +** Read bytes from *pz and convert them into a positive integer. When +** finished, leave *pz pointing to the first character past the end of +** the integer. The *pLen parameter holds the length of the string +** in *pz and is decremented once for each character in the integer. +*/ +static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ + static const signed char zValue[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, + -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1, + }; + unsigned int v = 0; + int c; + unsigned char *z = (unsigned char*)*pz; + unsigned char *zStart = z; + while( (c = zValue[0x7f&*(z++)])>=0 ){ + v = (v<<6) + c; + } + z--; + *pLen -= z - zStart; + *pz = (char*)z; + return v; +} + +/* +** Compute a 32-bit checksum on the N-byte buffer. Return the result. +*/ +static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){ + const unsigned char *z = (const unsigned char *)zIn; + unsigned sum0 = 0; + unsigned sum1 = 0; + unsigned sum2 = 0; + unsigned sum3 = 0; + while(N >= 16){ + sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]); + sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]); + sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]); + sum3 += ((unsigned)z[3] + z[7] + z[11]+ z[15]); + z += 16; + N -= 16; + } + while(N >= 4){ + sum0 += z[0]; + sum1 += z[1]; + sum2 += z[2]; + sum3 += z[3]; + z += 4; + N -= 4; + } + sum3 += (sum2 << 8) + (sum1 << 16) + (sum0 << 24); + switch(N){ + case 3: sum3 += (z[2] << 8); + case 2: sum3 += (z[1] << 16); + case 1: sum3 += (z[0] << 24); + default: ; + } + return sum3; +} + +/* +** Apply a delta. +** +** The output buffer should be big enough to hold the whole output +** file and a NUL terminator at the end. The delta_output_size() +** routine will determine this size for you. +** +** The delta string should be null-terminated. But the delta string +** may contain embedded NUL characters (if the input and output are +** binary files) so we also have to pass in the length of the delta in +** the lenDelta parameter. +** +** This function returns the size of the output file in bytes (excluding +** the final NUL terminator character). Except, if the delta string is +** malformed or intended for use with a source file other than zSrc, +** then this routine returns -1. +** +** Refer to the delta_create() documentation above for a description +** of the delta file format. +*/ +static int rbuDeltaApply( + const char *zSrc, /* The source or pattern file */ + int lenSrc, /* Length of the source file */ + const char *zDelta, /* Delta to apply to the pattern */ + int lenDelta, /* Length of the delta */ + char *zOut /* Write the output into this preallocated buffer */ +){ + unsigned int limit; + unsigned int total = 0; +#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST + char *zOrigOut = zOut; +#endif + + limit = rbuDeltaGetInt(&zDelta, &lenDelta); + if( *zDelta!='\n' ){ + /* ERROR: size integer not terminated by "\n" */ + return -1; + } + zDelta++; lenDelta--; + while( *zDelta && lenDelta>0 ){ + unsigned int cnt, ofst; + cnt = rbuDeltaGetInt(&zDelta, &lenDelta); + switch( zDelta[0] ){ + case '@': { + zDelta++; lenDelta--; + ofst = rbuDeltaGetInt(&zDelta, &lenDelta); + if( lenDelta>0 && zDelta[0]!=',' ){ + /* ERROR: copy command not terminated by ',' */ + return -1; + } + zDelta++; lenDelta--; + total += cnt; + if( total>limit ){ + /* ERROR: copy exceeds output file size */ + return -1; + } + if( (int)(ofst+cnt) > lenSrc ){ + /* ERROR: copy extends past end of input */ + return -1; + } + memcpy(zOut, &zSrc[ofst], cnt); + zOut += cnt; + break; + } + case ':': { + zDelta++; lenDelta--; + total += cnt; + if( total>limit ){ + /* ERROR: insert command gives an output larger than predicted */ + return -1; + } + if( (int)cnt>lenDelta ){ + /* ERROR: insert count exceeds size of delta */ + return -1; + } + memcpy(zOut, zDelta, cnt); + zOut += cnt; + zDelta += cnt; + lenDelta -= cnt; + break; + } + case ';': { + zDelta++; lenDelta--; + zOut[0] = 0; +#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST + if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){ + /* ERROR: bad checksum */ + return -1; + } +#endif + if( total!=limit ){ + /* ERROR: generated size does not match predicted size */ + return -1; + } + return total; + } + default: { + /* ERROR: unknown delta operator */ + return -1; + } + } + } + /* ERROR: unterminated delta */ + return -1; +} + +static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){ + int size; + size = rbuDeltaGetInt(&zDelta, &lenDelta); + if( *zDelta!='\n' ){ + /* ERROR: size integer not terminated by "\n" */ + return -1; + } + return size; +} + +/* +** End of code taken from fossil. +*************************************************************************/ + +/* +** Implementation of SQL scalar function rbu_fossil_delta(). +** +** This function applies a fossil delta patch to a blob. Exactly two +** arguments must be passed to this function. The first is the blob to +** patch and the second the patch to apply. If no error occurs, this +** function returns the patched blob. +*/ +static void rbuFossilDeltaFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *aDelta; + int nDelta; + const char *aOrig; + int nOrig; + + int nOut; + int nOut2; + char *aOut; + + assert( argc==2 ); + + nOrig = sqlite3_value_bytes(argv[0]); + aOrig = (const char*)sqlite3_value_blob(argv[0]); + nDelta = sqlite3_value_bytes(argv[1]); + aDelta = (const char*)sqlite3_value_blob(argv[1]); + + /* Figure out the size of the output */ + nOut = rbuDeltaOutputSize(aDelta, nDelta); + if( nOut<0 ){ + sqlite3_result_error(context, "corrupt fossil delta", -1); + return; + } + + aOut = sqlite3_malloc(nOut+1); + if( aOut==0 ){ + sqlite3_result_error_nomem(context); + }else{ + nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); + if( nOut2!=nOut ){ + sqlite3_result_error(context, "corrupt fossil delta", -1); + }else{ + sqlite3_result_blob(context, aOut, nOut, sqlite3_free); + } + } +} + + +/* +** Prepare the SQL statement in buffer zSql against database handle db. +** If successful, set *ppStmt to point to the new statement and return +** SQLITE_OK. +** +** Otherwise, if an error does occur, set *ppStmt to NULL and return +** an SQLite error code. Additionally, set output variable *pzErrmsg to +** point to a buffer containing an error message. It is the responsibility +** of the caller to (eventually) free this buffer using sqlite3_free(). +*/ +static int prepareAndCollectError( + sqlite3 *db, + sqlite3_stmt **ppStmt, + char **pzErrmsg, + const char *zSql +){ + int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); + if( rc!=SQLITE_OK ){ + *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + *ppStmt = 0; + } + return rc; +} + +/* +** Reset the SQL statement passed as the first argument. Return a copy +** of the value returned by sqlite3_reset(). +** +** If an error has occurred, then set *pzErrmsg to point to a buffer +** containing an error message. It is the responsibility of the caller +** to eventually free this buffer using sqlite3_free(). +*/ +static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){ + int rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ){ + *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(sqlite3_db_handle(pStmt))); + } + return rc; +} + +/* +** Unless it is NULL, argument zSql points to a buffer allocated using +** sqlite3_malloc containing an SQL statement. This function prepares the SQL +** statement against database db and frees the buffer. If statement +** compilation is successful, *ppStmt is set to point to the new statement +** handle and SQLITE_OK is returned. +** +** Otherwise, if an error occurs, *ppStmt is set to NULL and an error code +** returned. In this case, *pzErrmsg may also be set to point to an error +** message. It is the responsibility of the caller to free this error message +** buffer using sqlite3_free(). +** +** If argument zSql is NULL, this function assumes that an OOM has occurred. +** In this case SQLITE_NOMEM is returned and *ppStmt set to NULL. +*/ +static int prepareFreeAndCollectError( + sqlite3 *db, + sqlite3_stmt **ppStmt, + char **pzErrmsg, + char *zSql +){ + int rc; + assert( *pzErrmsg==0 ); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + *ppStmt = 0; + }else{ + rc = prepareAndCollectError(db, ppStmt, pzErrmsg, zSql); + sqlite3_free(zSql); + } + return rc; +} + +/* +** Free the RbuObjIter.azTblCol[] and RbuObjIter.abTblPk[] arrays allocated +** by an earlier call to rbuObjIterCacheTableInfo(). +*/ +static void rbuObjIterFreeCols(RbuObjIter *pIter){ + int i; + for(i=0; inTblCol; i++){ + sqlite3_free(pIter->azTblCol[i]); + sqlite3_free(pIter->azTblType[i]); + } + sqlite3_free(pIter->azTblCol); + pIter->azTblCol = 0; + pIter->azTblType = 0; + pIter->aiSrcOrder = 0; + pIter->abTblPk = 0; + pIter->abNotNull = 0; + pIter->nTblCol = 0; + pIter->eType = 0; /* Invalid value */ +} + +/* +** Finalize all statements and free all allocations that are specific to +** the current object (table/index pair). +*/ +static void rbuObjIterClearStatements(RbuObjIter *pIter){ + RbuUpdateStmt *pUp; + + sqlite3_finalize(pIter->pSelect); + sqlite3_finalize(pIter->pInsert); + sqlite3_finalize(pIter->pDelete); + sqlite3_finalize(pIter->pTmpInsert); + pUp = pIter->pRbuUpdate; + while( pUp ){ + RbuUpdateStmt *pTmp = pUp->pNext; + sqlite3_finalize(pUp->pUpdate); + sqlite3_free(pUp); + pUp = pTmp; + } + + pIter->pSelect = 0; + pIter->pInsert = 0; + pIter->pDelete = 0; + pIter->pRbuUpdate = 0; + pIter->pTmpInsert = 0; + pIter->nCol = 0; +} + +/* +** Clean up any resources allocated as part of the iterator object passed +** as the only argument. +*/ +static void rbuObjIterFinalize(RbuObjIter *pIter){ + rbuObjIterClearStatements(pIter); + sqlite3_finalize(pIter->pTblIter); + sqlite3_finalize(pIter->pIdxIter); + rbuObjIterFreeCols(pIter); + memset(pIter, 0, sizeof(RbuObjIter)); +} + +/* +** Advance the iterator to the next position. +** +** If no error occurs, SQLITE_OK is returned and the iterator is left +** pointing to the next entry. Otherwise, an error code and message is +** left in the RBU handle passed as the first argument. A copy of the +** error code is returned. +*/ +static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){ + int rc = p->rc; + if( rc==SQLITE_OK ){ + + /* Free any SQLite statements used while processing the previous object */ + rbuObjIterClearStatements(pIter); + if( pIter->zIdx==0 ){ + rc = sqlite3_exec(p->dbMain, + "DROP TRIGGER IF EXISTS temp.rbu_insert_tr;" + "DROP TRIGGER IF EXISTS temp.rbu_update1_tr;" + "DROP TRIGGER IF EXISTS temp.rbu_update2_tr;" + "DROP TRIGGER IF EXISTS temp.rbu_delete_tr;" + , 0, 0, &p->zErrmsg + ); + } + + if( rc==SQLITE_OK ){ + if( pIter->bCleanup ){ + rbuObjIterFreeCols(pIter); + pIter->bCleanup = 0; + rc = sqlite3_step(pIter->pTblIter); + if( rc!=SQLITE_ROW ){ + rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg); + pIter->zTbl = 0; + }else{ + pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0); + pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1); + rc = (pIter->zDataTbl && pIter->zTbl) ? SQLITE_OK : SQLITE_NOMEM; + } + }else{ + if( pIter->zIdx==0 ){ + sqlite3_stmt *pIdx = pIter->pIdxIter; + rc = sqlite3_bind_text(pIdx, 1, pIter->zTbl, -1, SQLITE_STATIC); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_step(pIter->pIdxIter); + if( rc!=SQLITE_ROW ){ + rc = resetAndCollectError(pIter->pIdxIter, &p->zErrmsg); + pIter->bCleanup = 1; + pIter->zIdx = 0; + }else{ + pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0); + pIter->iTnum = sqlite3_column_int(pIter->pIdxIter, 1); + pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2); + rc = pIter->zIdx ? SQLITE_OK : SQLITE_NOMEM; + } + } + } + } + } + + if( rc!=SQLITE_OK ){ + rbuObjIterFinalize(pIter); + p->rc = rc; + } + return rc; +} + + +/* +** The implementation of the rbu_target_name() SQL function. This function +** accepts one or two arguments. The first argument is the name of a table - +** the name of a table in the RBU database. The second, if it is present, is 1 +** for a view or 0 for a table. +** +** For a non-vacuum RBU handle, if the table name matches the pattern: +** +** data[0-9]_ +** +** where is any sequence of 1 or more characters, is returned. +** Otherwise, if the only argument does not match the above pattern, an SQL +** NULL is returned. +** +** "data_t1" -> "t1" +** "data0123_t2" -> "t2" +** "dataAB_t3" -> NULL +** +** For an rbu vacuum handle, a copy of the first argument is returned if +** the second argument is either missing or 0 (not a view). +*/ +static void rbuTargetNameFunc( + sqlite3_context *pCtx, + int argc, + sqlite3_value **argv +){ + sqlite3rbu *p = sqlite3_user_data(pCtx); + const char *zIn; + assert( argc==1 || argc==2 ); + + zIn = (const char*)sqlite3_value_text(argv[0]); + if( zIn ){ + if( rbuIsVacuum(p) ){ + if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ + sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); + } + }else{ + if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){ + int i; + for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++); + if( zIn[i]=='_' && zIn[i+1] ){ + sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC); + } + } + } + } +} + +/* +** Initialize the iterator structure passed as the second argument. +** +** If no error occurs, SQLITE_OK is returned and the iterator is left +** pointing to the first entry. Otherwise, an error code and message is +** left in the RBU handle passed as the first argument. A copy of the +** error code is returned. +*/ +static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ + int rc; + memset(pIter, 0, sizeof(RbuObjIter)); + + rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, + sqlite3_mprintf( + "SELECT rbu_target_name(name, type='view') AS target, name " + "FROM sqlite_master " + "WHERE type IN ('table', 'view') AND target IS NOT NULL " + " %s " + "ORDER BY name" + , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : "")); + + if( rc==SQLITE_OK ){ + rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, + "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' " + " FROM main.sqlite_master " + " WHERE type='index' AND tbl_name = ?" + ); + } + + pIter->bCleanup = 1; + p->rc = rc; + return rbuObjIterNext(p, pIter); +} + +/* +** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs, +** an error code is stored in the RBU handle passed as the first argument. +** +** If an error has already occurred (p->rc is already set to something other +** than SQLITE_OK), then this function returns NULL without modifying the +** stored error code. In this case it still calls sqlite3_free() on any +** printf() parameters associated with %z conversions. +*/ +static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){ + char *zSql = 0; + va_list ap; + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + if( p->rc==SQLITE_OK ){ + if( zSql==0 ) p->rc = SQLITE_NOMEM; + }else{ + sqlite3_free(zSql); + zSql = 0; + } + va_end(ap); + return zSql; +} + +/* +** Argument zFmt is a sqlite3_mprintf() style format string. The trailing +** arguments are the usual subsitution values. This function performs +** the printf() style substitutions and executes the result as an SQL +** statement on the RBU handles database. +** +** If an error occurs, an error code and error message is stored in the +** RBU handle. If an error has already occurred when this function is +** called, it is a no-op. +*/ +static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){ + va_list ap; + char *zSql; + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + if( p->rc==SQLITE_OK ){ + if( zSql==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + p->rc = sqlite3_exec(db, zSql, 0, 0, &p->zErrmsg); + } + } + sqlite3_free(zSql); + va_end(ap); + return p->rc; +} + +/* +** Attempt to allocate and return a pointer to a zeroed block of nByte +** bytes. +** +** If an error (i.e. an OOM condition) occurs, return NULL and leave an +** error code in the rbu handle passed as the first argument. Or, if an +** error has already occurred when this function is called, return NULL +** immediately without attempting the allocation or modifying the stored +** error code. +*/ +static void *rbuMalloc(sqlite3rbu *p, int nByte){ + void *pRet = 0; + if( p->rc==SQLITE_OK ){ + assert( nByte>0 ); + pRet = sqlite3_malloc64(nByte); + if( pRet==0 ){ + p->rc = SQLITE_NOMEM; + }else{ + memset(pRet, 0, nByte); + } + } + return pRet; +} + + +/* +** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that +** there is room for at least nCol elements. If an OOM occurs, store an +** error code in the RBU handle passed as the first argument. +*/ +static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){ + int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; + char **azNew; + + azNew = (char**)rbuMalloc(p, nByte); + if( azNew ){ + pIter->azTblCol = azNew; + pIter->azTblType = &azNew[nCol]; + pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol]; + pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol]; + pIter->abNotNull = (u8*)&pIter->abTblPk[nCol]; + pIter->abIndexed = (u8*)&pIter->abNotNull[nCol]; + } +} + +/* +** The first argument must be a nul-terminated string. This function +** returns a copy of the string in memory obtained from sqlite3_malloc(). +** It is the responsibility of the caller to eventually free this memory +** using sqlite3_free(). +** +** If an OOM condition is encountered when attempting to allocate memory, +** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise, +** if the allocation succeeds, (*pRc) is left unchanged. +*/ +static char *rbuStrndup(const char *zStr, int *pRc){ + char *zRet = 0; + + assert( *pRc==SQLITE_OK ); + if( zStr ){ + size_t nCopy = strlen(zStr) + 1; + zRet = (char*)sqlite3_malloc64(nCopy); + if( zRet ){ + memcpy(zRet, zStr, nCopy); + }else{ + *pRc = SQLITE_NOMEM; + } + } + + return zRet; +} + +/* +** Finalize the statement passed as the second argument. +** +** If the sqlite3_finalize() call indicates that an error occurs, and the +** rbu handle error code is not already set, set the error code and error +** message accordingly. +*/ +static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){ + sqlite3 *db = sqlite3_db_handle(pStmt); + int rc = sqlite3_finalize(pStmt); + if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){ + p->rc = rc; + p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } +} + +/* Determine the type of a table. +** +** peType is of type (int*), a pointer to an output parameter of type +** (int). This call sets the output parameter as follows, depending +** on the type of the table specified by parameters dbName and zTbl. +** +** RBU_PK_NOTABLE: No such table. +** RBU_PK_NONE: Table has an implicit rowid. +** RBU_PK_IPK: Table has an explicit IPK column. +** RBU_PK_EXTERNAL: Table has an external PK index. +** RBU_PK_WITHOUT_ROWID: Table is WITHOUT ROWID. +** RBU_PK_VTAB: Table is a virtual table. +** +** Argument *piPk is also of type (int*), and also points to an output +** parameter. Unless the table has an external primary key index +** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or, +** if the table does have an external primary key index, then *piPk +** is set to the root page number of the primary key index before +** returning. +** +** ALGORITHM: +** +** if( no entry exists in sqlite_master ){ +** return RBU_PK_NOTABLE +** }else if( sql for the entry starts with "CREATE VIRTUAL" ){ +** return RBU_PK_VTAB +** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){ +** if( the index that is the pk exists in sqlite_master ){ +** *piPK = rootpage of that index. +** return RBU_PK_EXTERNAL +** }else{ +** return RBU_PK_WITHOUT_ROWID +** } +** }else if( "PRAGMA table_info()" lists one or more "pk" columns ){ +** return RBU_PK_IPK +** }else{ +** return RBU_PK_NONE +** } +*/ +static void rbuTableType( + sqlite3rbu *p, + const char *zTab, + int *peType, + int *piTnum, + int *piPk +){ + /* + ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q) + ** 1) PRAGMA index_list = ? + ** 2) SELECT count(*) FROM sqlite_master where name=%Q + ** 3) PRAGMA table_info = ? + */ + sqlite3_stmt *aStmt[4] = {0, 0, 0, 0}; + + *peType = RBU_PK_NOTABLE; + *piPk = 0; + + assert( p->rc==SQLITE_OK ); + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg, + sqlite3_mprintf( + "SELECT (sql LIKE 'create virtual%%'), rootpage" + " FROM sqlite_master" + " WHERE name=%Q", zTab + )); + if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){ + /* Either an error, or no such table. */ + goto rbuTableType_end; + } + if( sqlite3_column_int(aStmt[0], 0) ){ + *peType = RBU_PK_VTAB; /* virtual table */ + goto rbuTableType_end; + } + *piTnum = sqlite3_column_int(aStmt[0], 1); + + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg, + sqlite3_mprintf("PRAGMA index_list=%Q",zTab) + ); + if( p->rc ) goto rbuTableType_end; + while( sqlite3_step(aStmt[1])==SQLITE_ROW ){ + const u8 *zOrig = sqlite3_column_text(aStmt[1], 3); + const u8 *zIdx = sqlite3_column_text(aStmt[1], 1); + if( zOrig && zIdx && zOrig[0]=='p' ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg, + sqlite3_mprintf( + "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx + )); + if( p->rc==SQLITE_OK ){ + if( sqlite3_step(aStmt[2])==SQLITE_ROW ){ + *piPk = sqlite3_column_int(aStmt[2], 0); + *peType = RBU_PK_EXTERNAL; + }else{ + *peType = RBU_PK_WITHOUT_ROWID; + } + } + goto rbuTableType_end; + } + } + + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg, + sqlite3_mprintf("PRAGMA table_info=%Q",zTab) + ); + if( p->rc==SQLITE_OK ){ + while( sqlite3_step(aStmt[3])==SQLITE_ROW ){ + if( sqlite3_column_int(aStmt[3],5)>0 ){ + *peType = RBU_PK_IPK; /* explicit IPK column */ + goto rbuTableType_end; + } + } + *peType = RBU_PK_NONE; + } + +rbuTableType_end: { + unsigned int i; + for(i=0; iabIndexed[] array. +*/ +static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){ + sqlite3_stmt *pList = 0; + int bIndex = 0; + + if( p->rc==SQLITE_OK ){ + memcpy(pIter->abIndexed, pIter->abTblPk, sizeof(u8)*pIter->nTblCol); + p->rc = prepareFreeAndCollectError(p->dbMain, &pList, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) + ); + } + + pIter->nIndex = 0; + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ + const char *zIdx = (const char*)sqlite3_column_text(pList, 1); + sqlite3_stmt *pXInfo = 0; + if( zIdx==0 ) break; + p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) + ); + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ + int iCid = sqlite3_column_int(pXInfo, 1); + if( iCid>=0 ) pIter->abIndexed[iCid] = 1; + } + rbuFinalize(p, pXInfo); + bIndex = 1; + pIter->nIndex++; + } + + if( pIter->eType==RBU_PK_WITHOUT_ROWID ){ + /* "PRAGMA index_list" includes the main PK b-tree */ + pIter->nIndex--; + } + + rbuFinalize(p, pList); + if( bIndex==0 ) pIter->abIndexed = 0; +} + + +/* +** If they are not already populated, populate the pIter->azTblCol[], +** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to +** the table (not index) that the iterator currently points to. +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. If +** an error does occur, an error code and error message are also left in +** the RBU handle. +*/ +static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ + if( pIter->azTblCol==0 ){ + sqlite3_stmt *pStmt = 0; + int nCol = 0; + int i; /* for() loop iterator variable */ + int bRbuRowid = 0; /* If input table has column "rbu_rowid" */ + int iOrder = 0; + int iTnum = 0; + + /* Figure out the type of table this step will deal with. */ + assert( pIter->eType==0 ); + rbuTableType(p, pIter->zTbl, &pIter->eType, &iTnum, &pIter->iPkTnum); + if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_NOTABLE ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("no such table: %s", pIter->zTbl); + } + if( p->rc ) return p->rc; + if( pIter->zIdx==0 ) pIter->iTnum = iTnum; + + assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK + || pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_WITHOUT_ROWID + || pIter->eType==RBU_PK_VTAB + ); + + /* Populate the azTblCol[] and nTblCol variables based on the columns + ** of the input table. Ignore any input table columns that begin with + ** "rbu_". */ + p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, + sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl) + ); + if( p->rc==SQLITE_OK ){ + nCol = sqlite3_column_count(pStmt); + rbuAllocateIterArrays(p, pIter, nCol); + } + for(i=0; p->rc==SQLITE_OK && irc); + pIter->aiSrcOrder[pIter->nTblCol] = pIter->nTblCol; + pIter->azTblCol[pIter->nTblCol++] = zCopy; + } + else if( 0==sqlite3_stricmp("rbu_rowid", zName) ){ + bRbuRowid = 1; + } + } + sqlite3_finalize(pStmt); + pStmt = 0; + + if( p->rc==SQLITE_OK + && rbuIsVacuum(p)==0 + && bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) + ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf( + "table %q %s rbu_rowid column", pIter->zDataTbl, + (bRbuRowid ? "may not have" : "requires") + ); + } + + /* Check that all non-HIDDEN columns in the destination table are also + ** present in the input table. Populate the abTblPk[], azTblType[] and + ** aiTblOrder[] arrays at the same time. */ + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, + sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl) + ); + } + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zName = (const char*)sqlite3_column_text(pStmt, 1); + if( zName==0 ) break; /* An OOM - finalize() below returns S_NOMEM */ + for(i=iOrder; inTblCol; i++){ + if( 0==strcmp(zName, pIter->azTblCol[i]) ) break; + } + if( i==pIter->nTblCol ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("column missing from %q: %s", + pIter->zDataTbl, zName + ); + }else{ + int iPk = sqlite3_column_int(pStmt, 5); + int bNotNull = sqlite3_column_int(pStmt, 3); + const char *zType = (const char*)sqlite3_column_text(pStmt, 2); + + if( i!=iOrder ){ + SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]); + SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]); + } + + pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc); + pIter->abTblPk[iOrder] = (iPk!=0); + pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); + iOrder++; + } + } + + rbuFinalize(p, pStmt); + rbuObjIterCacheIndexedCols(p, pIter); + assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 ); + assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 ); + } + + return p->rc; +} + +/* +** This function constructs and returns a pointer to a nul-terminated +** string containing some SQL clause or list based on one or more of the +** column names currently stored in the pIter->azTblCol[] array. +*/ +static char *rbuObjIterGetCollist( + sqlite3rbu *p, /* RBU object */ + RbuObjIter *pIter /* Object iterator for column names */ +){ + char *zList = 0; + const char *zSep = ""; + int i; + for(i=0; inTblCol; i++){ + const char *z = pIter->azTblCol[i]; + zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z); + zSep = ", "; + } + return zList; +} + +/* +** This function is used to create a SELECT list (the list of SQL +** expressions that follows a SELECT keyword) for a SELECT statement +** used to read from an data_xxx or rbu_tmp_xxx table while updating the +** index object currently indicated by the iterator object passed as the +** second argument. A "PRAGMA index_xinfo = " statement is used +** to obtain the required information. +** +** If the index is of the following form: +** +** CREATE INDEX i1 ON t1(c, b COLLATE nocase); +** +** and "t1" is a table with an explicit INTEGER PRIMARY KEY column +** "ipk", the returned string is: +** +** "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'" +** +** As well as the returned string, three other malloc'd strings are +** returned via output parameters. As follows: +** +** pzImposterCols: ... +** pzImposterPk: ... +** pzWhere: ... +*/ +static char *rbuObjIterGetIndexCols( + sqlite3rbu *p, /* RBU object */ + RbuObjIter *pIter, /* Object iterator for column names */ + char **pzImposterCols, /* OUT: Columns for imposter table */ + char **pzImposterPk, /* OUT: Imposter PK clause */ + char **pzWhere, /* OUT: WHERE clause */ + int *pnBind /* OUT: Trbul number of columns */ +){ + int rc = p->rc; /* Error code */ + int rc2; /* sqlite3_finalize() return code */ + char *zRet = 0; /* String to return */ + char *zImpCols = 0; /* String to return via *pzImposterCols */ + char *zImpPK = 0; /* String to return via *pzImposterPK */ + char *zWhere = 0; /* String to return via *pzWhere */ + int nBind = 0; /* Value to return via *pnBind */ + const char *zCom = ""; /* Set to ", " later on */ + const char *zAnd = ""; /* Set to " AND " later on */ + sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = ? */ + + if( rc==SQLITE_OK ){ + assert( p->zErrmsg==0 ); + rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx) + ); + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ + int iCid = sqlite3_column_int(pXInfo, 1); + int bDesc = sqlite3_column_int(pXInfo, 3); + const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); + const char *zCol; + const char *zType; + + if( iCid<0 ){ + /* An integer primary key. If the table has an explicit IPK, use + ** its name. Otherwise, use "rbu_rowid". */ + if( pIter->eType==RBU_PK_IPK ){ + int i; + for(i=0; pIter->abTblPk[i]==0; i++); + assert( inTblCol ); + zCol = pIter->azTblCol[i]; + }else if( rbuIsVacuum(p) ){ + zCol = "_rowid_"; + }else{ + zCol = "rbu_rowid"; + } + zType = "INTEGER"; + }else{ + zCol = pIter->azTblCol[iCid]; + zType = pIter->azTblType[iCid]; + } + + zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom, zCol, zCollate); + if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){ + const char *zOrder = (bDesc ? " DESC" : ""); + zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s", + zImpPK, zCom, nBind, zCol, zOrder + ); + } + zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q", + zImpCols, zCom, nBind, zCol, zType, zCollate + ); + zWhere = sqlite3_mprintf( + "%z%s\"rbu_imp_%d%w\" IS ?", zWhere, zAnd, nBind, zCol + ); + if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM; + zCom = ", "; + zAnd = " AND "; + nBind++; + } + + rc2 = sqlite3_finalize(pXInfo); + if( rc==SQLITE_OK ) rc = rc2; + + if( rc!=SQLITE_OK ){ + sqlite3_free(zRet); + sqlite3_free(zImpCols); + sqlite3_free(zImpPK); + sqlite3_free(zWhere); + zRet = 0; + zImpCols = 0; + zImpPK = 0; + zWhere = 0; + p->rc = rc; + } + + *pzImposterCols = zImpCols; + *pzImposterPk = zImpPK; + *pzWhere = zWhere; + *pnBind = nBind; + return zRet; +} + +/* +** Assuming the current table columns are "a", "b" and "c", and the zObj +** paramter is passed "old", return a string of the form: +** +** "old.a, old.b, old.b" +** +** With the column names escaped. +** +** For tables with implicit rowids - RBU_PK_EXTERNAL and RBU_PK_NONE, append +** the text ", old._rowid_" to the returned value. +*/ +static char *rbuObjIterGetOldlist( + sqlite3rbu *p, + RbuObjIter *pIter, + const char *zObj +){ + char *zList = 0; + if( p->rc==SQLITE_OK && pIter->abIndexed ){ + const char *zS = ""; + int i; + for(i=0; inTblCol; i++){ + if( pIter->abIndexed[i] ){ + const char *zCol = pIter->azTblCol[i]; + zList = sqlite3_mprintf("%z%s%s.\"%w\"", zList, zS, zObj, zCol); + }else{ + zList = sqlite3_mprintf("%z%sNULL", zList, zS); + } + zS = ", "; + if( zList==0 ){ + p->rc = SQLITE_NOMEM; + break; + } + } + + /* For a table with implicit rowids, append "old._rowid_" to the list. */ + if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ + zList = rbuMPrintf(p, "%z, %s._rowid_", zList, zObj); + } + } + return zList; +} + +/* +** Return an expression that can be used in a WHERE clause to match the +** primary key of the current table. For example, if the table is: +** +** CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)); +** +** Return the string: +** +** "b = ?1 AND c = ?2" +*/ +static char *rbuObjIterGetWhere( + sqlite3rbu *p, + RbuObjIter *pIter +){ + char *zList = 0; + if( pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE ){ + zList = rbuMPrintf(p, "_rowid_ = ?%d", pIter->nTblCol+1); + }else if( pIter->eType==RBU_PK_EXTERNAL ){ + const char *zSep = ""; + int i; + for(i=0; inTblCol; i++){ + if( pIter->abTblPk[i] ){ + zList = rbuMPrintf(p, "%z%sc%d=?%d", zList, zSep, i, i+1); + zSep = " AND "; + } + } + zList = rbuMPrintf(p, + "_rowid_ = (SELECT id FROM rbu_imposter2 WHERE %z)", zList + ); + + }else{ + const char *zSep = ""; + int i; + for(i=0; inTblCol; i++){ + if( pIter->abTblPk[i] ){ + const char *zCol = pIter->azTblCol[i]; + zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", zList, zSep, zCol, i+1); + zSep = " AND "; + } + } + } + return zList; +} + +/* +** The SELECT statement iterating through the keys for the current object +** (p->objiter.pSelect) currently points to a valid row. However, there +** is something wrong with the rbu_control value in the rbu_control value +** stored in the (p->nCol+1)'th column. Set the error code and error message +** of the RBU handle to something reflecting this. +*/ +static void rbuBadControlError(sqlite3rbu *p){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("invalid rbu_control value"); +} + + +/* +** Return a nul-terminated string containing the comma separated list of +** assignments that should be included following the "SET" keyword of +** an UPDATE statement used to update the table object that the iterator +** passed as the second argument currently points to if the rbu_control +** column of the data_xxx table entry is set to zMask. +** +** The memory for the returned string is obtained from sqlite3_malloc(). +** It is the responsibility of the caller to eventually free it using +** sqlite3_free(). +** +** If an OOM error is encountered when allocating space for the new +** string, an error code is left in the rbu handle passed as the first +** argument and NULL is returned. Or, if an error has already occurred +** when this function is called, NULL is returned immediately, without +** attempting the allocation or modifying the stored error code. +*/ +static char *rbuObjIterGetSetlist( + sqlite3rbu *p, + RbuObjIter *pIter, + const char *zMask +){ + char *zList = 0; + if( p->rc==SQLITE_OK ){ + int i; + + if( (int)strlen(zMask)!=pIter->nTblCol ){ + rbuBadControlError(p); + }else{ + const char *zSep = ""; + for(i=0; inTblCol; i++){ + char c = zMask[pIter->aiSrcOrder[i]]; + if( c=='x' ){ + zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", + zList, zSep, pIter->azTblCol[i], i+1 + ); + zSep = ", "; + } + else if( c=='d' ){ + zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)", + zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 + ); + zSep = ", "; + } + else if( c=='f' ){ + zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)", + zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 + ); + zSep = ", "; + } + } + } + } + return zList; +} + +/* +** Return a nul-terminated string consisting of nByte comma separated +** "?" expressions. For example, if nByte is 3, return a pointer to +** a buffer containing the string "?,?,?". +** +** The memory for the returned string is obtained from sqlite3_malloc(). +** It is the responsibility of the caller to eventually free it using +** sqlite3_free(). +** +** If an OOM error is encountered when allocating space for the new +** string, an error code is left in the rbu handle passed as the first +** argument and NULL is returned. Or, if an error has already occurred +** when this function is called, NULL is returned immediately, without +** attempting the allocation or modifying the stored error code. +*/ +static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ + char *zRet = 0; + int nByte = nBind*2 + 1; + + zRet = (char*)rbuMalloc(p, nByte); + if( zRet ){ + int i; + for(i=0; izIdx==0 ); + if( p->rc==SQLITE_OK ){ + const char *zSep = "PRIMARY KEY("; + sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */ + sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = */ + + p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) + ); + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXList) ){ + const char *zOrig = (const char*)sqlite3_column_text(pXList,3); + if( zOrig && strcmp(zOrig, "pk")==0 ){ + const char *zIdx = (const char*)sqlite3_column_text(pXList,1); + if( zIdx ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) + ); + } + break; + } + } + rbuFinalize(p, pXList); + + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ + if( sqlite3_column_int(pXInfo, 5) ){ + /* int iCid = sqlite3_column_int(pXInfo, 0); */ + const char *zCol = (const char*)sqlite3_column_text(pXInfo, 2); + const char *zDesc = sqlite3_column_int(pXInfo, 3) ? " DESC" : ""; + z = rbuMPrintf(p, "%z%s\"%w\"%s", z, zSep, zCol, zDesc); + zSep = ", "; + } + } + z = rbuMPrintf(p, "%z)", z); + rbuFinalize(p, pXInfo); + } + return z; +} + +/* +** This function creates the second imposter table used when writing to +** a table b-tree where the table has an external primary key. If the +** iterator passed as the second argument does not currently point to +** a table (not index) with an external primary key, this function is a +** no-op. +** +** Assuming the iterator does point to a table with an external PK, this +** function creates a WITHOUT ROWID imposter table named "rbu_imposter2" +** used to access that PK index. For example, if the target table is +** declared as follows: +** +** CREATE TABLE t1(a, b TEXT, c REAL, PRIMARY KEY(b, c)); +** +** then the imposter table schema is: +** +** CREATE TABLE rbu_imposter2(c1 TEXT, c2 REAL, id INTEGER) WITHOUT ROWID; +** +*/ +static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){ + if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_EXTERNAL ){ + int tnum = pIter->iPkTnum; /* Root page of PK index */ + sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */ + const char *zIdx = 0; /* Name of PK index */ + sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */ + const char *zComma = ""; + char *zCols = 0; /* Used to build up list of table cols */ + char *zPk = 0; /* Used to build up table PK declaration */ + + /* Figure out the name of the primary key index for the current table. + ** This is needed for the argument to "PRAGMA index_xinfo". Set + ** zIdx to point to a nul-terminated string containing this name. */ + p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg, + "SELECT name FROM sqlite_master WHERE rootpage = ?" + ); + if( p->rc==SQLITE_OK ){ + sqlite3_bind_int(pQuery, 1, tnum); + if( SQLITE_ROW==sqlite3_step(pQuery) ){ + zIdx = (const char*)sqlite3_column_text(pQuery, 0); + } + } + if( zIdx ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) + ); + } + rbuFinalize(p, pQuery); + + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ + int bKey = sqlite3_column_int(pXInfo, 5); + if( bKey ){ + int iCid = sqlite3_column_int(pXInfo, 1); + int bDesc = sqlite3_column_int(pXInfo, 3); + const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); + zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %s", zCols, zComma, + iCid, pIter->azTblType[iCid], zCollate + ); + zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":""); + zComma = ", "; + } + } + zCols = rbuMPrintf(p, "%z, id INTEGER", zCols); + rbuFinalize(p, pXInfo); + + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum); + rbuMPrintfExec(p, p->dbMain, + "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID", + zCols, zPk + ); + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); + } +} + +/* +** If an error has already occurred when this function is called, it +** immediately returns zero (without doing any work). Or, if an error +** occurs during the execution of this function, it sets the error code +** in the sqlite3rbu object indicated by the first argument and returns +** zero. +** +** The iterator passed as the second argument is guaranteed to point to +** a table (not an index) when this function is called. This function +** attempts to create any imposter table required to write to the main +** table b-tree of the table before returning. Non-zero is returned if +** an imposter table are created, or zero otherwise. +** +** An imposter table is required in all cases except RBU_PK_VTAB. Only +** virtual tables are written to directly. The imposter table has the +** same schema as the actual target table (less any UNIQUE constraints). +** More precisely, the "same schema" means the same columns, types, +** collation sequences. For tables that do not have an external PRIMARY +** KEY, it also means the same PRIMARY KEY declaration. +*/ +static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){ + if( p->rc==SQLITE_OK && pIter->eType!=RBU_PK_VTAB ){ + int tnum = pIter->iTnum; + const char *zComma = ""; + char *zSql = 0; + int iCol; + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); + + for(iCol=0; p->rc==SQLITE_OK && iColnTblCol; iCol++){ + const char *zPk = ""; + const char *zCol = pIter->azTblCol[iCol]; + const char *zColl = 0; + + p->rc = sqlite3_table_column_metadata( + p->dbMain, "main", pIter->zTbl, zCol, 0, &zColl, 0, 0, 0 + ); + + if( pIter->eType==RBU_PK_IPK && pIter->abTblPk[iCol] ){ + /* If the target table column is an "INTEGER PRIMARY KEY", add + ** "PRIMARY KEY" to the imposter table column declaration. */ + zPk = "PRIMARY KEY "; + } + zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s", + zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl, + (pIter->abNotNull[iCol] ? " NOT NULL" : "") + ); + zComma = ", "; + } + + if( pIter->eType==RBU_PK_WITHOUT_ROWID ){ + char *zPk = rbuWithoutRowidPK(p, pIter); + if( zPk ){ + zSql = rbuMPrintf(p, "%z, %z", zSql, zPk); + } + } + + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum); + rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s", + pIter->zTbl, zSql, + (pIter->eType==RBU_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "") + ); + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); + } +} + +/* +** Prepare a statement used to insert rows into the "rbu_tmp_xxx" table. +** Specifically a statement of the form: +** +** INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...); +** +** The number of bound variables is equal to the number of columns in +** the target table, plus one (for the rbu_control column), plus one more +** (for the rbu_rowid column) if the target table is an implicit IPK or +** virtual table. +*/ +static void rbuObjIterPrepareTmpInsert( + sqlite3rbu *p, + RbuObjIter *pIter, + const char *zCollist, + const char *zRbuRowid +){ + int bRbuRowid = (pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE); + char *zBind = rbuObjIterGetBindlist(p, pIter->nTblCol + 1 + bRbuRowid); + if( zBind ){ + assert( pIter->pTmpInsert==0 ); + p->rc = prepareFreeAndCollectError( + p->dbRbu, &pIter->pTmpInsert, &p->zErrmsg, sqlite3_mprintf( + "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)", + p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind + )); + } +} + +static void rbuTmpInsertFunc( + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal +){ + sqlite3rbu *p = sqlite3_user_data(pCtx); + int rc = SQLITE_OK; + int i; + + assert( sqlite3_value_int(apVal[0])!=0 + || p->objiter.eType==RBU_PK_EXTERNAL + || p->objiter.eType==RBU_PK_NONE + ); + if( sqlite3_value_int(apVal[0])!=0 ){ + p->nPhaseOneStep += p->objiter.nIndex; + } + + for(i=0; rc==SQLITE_OK && iobjiter.pTmpInsert, i+1, apVal[i]); + } + if( rc==SQLITE_OK ){ + sqlite3_step(p->objiter.pTmpInsert); + rc = sqlite3_reset(p->objiter.pTmpInsert); + } + + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + } +} + +/* +** Ensure that the SQLite statement handles required to update the +** target database object currently indicated by the iterator passed +** as the second argument are available. +*/ +static int rbuObjIterPrepareAll( + sqlite3rbu *p, + RbuObjIter *pIter, + int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */ +){ + assert( pIter->bCleanup==0 ); + if( pIter->pSelect==0 && rbuObjIterCacheTableInfo(p, pIter)==SQLITE_OK ){ + const int tnum = pIter->iTnum; + char *zCollist = 0; /* List of indexed columns */ + char **pz = &p->zErrmsg; + const char *zIdx = pIter->zIdx; + char *zLimit = 0; + + if( nOffset ){ + zLimit = sqlite3_mprintf(" LIMIT -1 OFFSET %d", nOffset); + if( !zLimit ) p->rc = SQLITE_NOMEM; + } + + if( zIdx ){ + const char *zTbl = pIter->zTbl; + char *zImposterCols = 0; /* Columns for imposter table */ + char *zImposterPK = 0; /* Primary key declaration for imposter */ + char *zWhere = 0; /* WHERE clause on PK columns */ + char *zBind = 0; + int nBind = 0; + + assert( pIter->eType!=RBU_PK_VTAB ); + zCollist = rbuObjIterGetIndexCols( + p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind + ); + zBind = rbuObjIterGetBindlist(p, nBind); + + /* Create the imposter table used to write to this index. */ + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1,tnum); + rbuMPrintfExec(p, p->dbMain, + "CREATE TABLE \"rbu_imp_%w\"( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID", + zTbl, zImposterCols, zImposterPK + ); + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); + + /* Create the statement to insert index entries */ + pIter->nCol = nBind; + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError( + p->dbMain, &pIter->pInsert, &p->zErrmsg, + sqlite3_mprintf("INSERT INTO \"rbu_imp_%w\" VALUES(%s)", zTbl, zBind) + ); + } + + /* And to delete index entries */ + if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError( + p->dbMain, &pIter->pDelete, &p->zErrmsg, + sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere) + ); + } + + /* Create the SELECT statement to read keys in sorted order */ + if( p->rc==SQLITE_OK ){ + char *zSql; + if( rbuIsVacuum(p) ){ + zSql = sqlite3_mprintf( + "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s", + zCollist, + pIter->zDataTbl, + zCollist, zLimit + ); + }else + + if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ + zSql = sqlite3_mprintf( + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s", + zCollist, p->zStateDb, pIter->zDataTbl, + zCollist, zLimit + ); + }else{ + zSql = sqlite3_mprintf( + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' " + "UNION ALL " + "SELECT %s, rbu_control FROM '%q' " + "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 " + "ORDER BY %s%s", + zCollist, p->zStateDb, pIter->zDataTbl, + zCollist, pIter->zDataTbl, + zCollist, zLimit + ); + } + p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql); + } + + sqlite3_free(zImposterCols); + sqlite3_free(zImposterPK); + sqlite3_free(zWhere); + sqlite3_free(zBind); + }else{ + int bRbuRowid = (pIter->eType==RBU_PK_VTAB) + ||(pIter->eType==RBU_PK_NONE) + ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)); + const char *zTbl = pIter->zTbl; /* Table this step applies to */ + const char *zWrite; /* Imposter table name */ + + char *zBindings = rbuObjIterGetBindlist(p, pIter->nTblCol + bRbuRowid); + char *zWhere = rbuObjIterGetWhere(p, pIter); + char *zOldlist = rbuObjIterGetOldlist(p, pIter, "old"); + char *zNewlist = rbuObjIterGetOldlist(p, pIter, "new"); + + zCollist = rbuObjIterGetCollist(p, pIter); + pIter->nCol = pIter->nTblCol; + + /* Create the imposter table or tables (if required). */ + rbuCreateImposterTable(p, pIter); + rbuCreateImposterTable2(p, pIter); + zWrite = (pIter->eType==RBU_PK_VTAB ? "" : "rbu_imp_"); + + /* Create the INSERT statement to write to the target PK b-tree */ + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pInsert, pz, + sqlite3_mprintf( + "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)", + zWrite, zTbl, zCollist, (bRbuRowid ? ", _rowid_" : ""), zBindings + ) + ); + } + + /* Create the DELETE statement to write to the target PK b-tree. + ** Because it only performs INSERT operations, this is not required for + ** an rbu vacuum handle. */ + if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz, + sqlite3_mprintf( + "DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere + ) + ); + } + + if( rbuIsVacuum(p)==0 && pIter->abIndexed ){ + const char *zRbuRowid = ""; + if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ + zRbuRowid = ", rbu_rowid"; + } + + /* Create the rbu_tmp_xxx table and the triggers to populate it. */ + rbuMPrintfExec(p, p->dbRbu, + "CREATE TABLE IF NOT EXISTS %s.'rbu_tmp_%q' AS " + "SELECT *%s FROM '%q' WHERE 0;" + , p->zStateDb, pIter->zDataTbl + , (pIter->eType==RBU_PK_EXTERNAL ? ", 0 AS rbu_rowid" : "") + , pIter->zDataTbl + ); + + rbuMPrintfExec(p, p->dbMain, + "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" " + "BEGIN " + " SELECT rbu_tmp_insert(3, %s);" + "END;" + + "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" " + "BEGIN " + " SELECT rbu_tmp_insert(3, %s);" + "END;" + + "CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" " + "BEGIN " + " SELECT rbu_tmp_insert(4, %s);" + "END;", + zWrite, zTbl, zOldlist, + zWrite, zTbl, zOldlist, + zWrite, zTbl, zNewlist + ); + + if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ + rbuMPrintfExec(p, p->dbMain, + "CREATE TEMP TRIGGER rbu_insert_tr AFTER INSERT ON \"%s%w\" " + "BEGIN " + " SELECT rbu_tmp_insert(0, %s);" + "END;", + zWrite, zTbl, zNewlist + ); + } + + rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid); + } + + /* Create the SELECT statement to read keys from data_xxx */ + if( p->rc==SQLITE_OK ){ + const char *zRbuRowid = ""; + if( bRbuRowid ){ + zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; + } + p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, + sqlite3_mprintf( + "SELECT %s,%s rbu_control%s FROM '%q'%s", + zCollist, + (rbuIsVacuum(p) ? "0 AS " : ""), + zRbuRowid, + pIter->zDataTbl, zLimit + ) + ); + } + + sqlite3_free(zWhere); + sqlite3_free(zOldlist); + sqlite3_free(zNewlist); + sqlite3_free(zBindings); + } + sqlite3_free(zCollist); + sqlite3_free(zLimit); + } + + return p->rc; +} + +/* +** Set output variable *ppStmt to point to an UPDATE statement that may +** be used to update the imposter table for the main table b-tree of the +** table object that pIter currently points to, assuming that the +** rbu_control column of the data_xyz table contains zMask. +** +** If the zMask string does not specify any columns to update, then this +** is not an error. Output variable *ppStmt is set to NULL in this case. +*/ +static int rbuGetUpdateStmt( + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter, /* Object iterator */ + const char *zMask, /* rbu_control value ('x.x.') */ + sqlite3_stmt **ppStmt /* OUT: UPDATE statement handle */ +){ + RbuUpdateStmt **pp; + RbuUpdateStmt *pUp = 0; + int nUp = 0; + + /* In case an error occurs */ + *ppStmt = 0; + + /* Search for an existing statement. If one is found, shift it to the front + ** of the LRU queue and return immediately. Otherwise, leave nUp pointing + ** to the number of statements currently in the cache and pUp to the + ** last object in the list. */ + for(pp=&pIter->pRbuUpdate; *pp; pp=&((*pp)->pNext)){ + pUp = *pp; + if( strcmp(pUp->zMask, zMask)==0 ){ + *pp = pUp->pNext; + pUp->pNext = pIter->pRbuUpdate; + pIter->pRbuUpdate = pUp; + *ppStmt = pUp->pUpdate; + return SQLITE_OK; + } + nUp++; + } + assert( pUp==0 || pUp->pNext==0 ); + + if( nUp>=SQLITE_RBU_UPDATE_CACHESIZE ){ + for(pp=&pIter->pRbuUpdate; *pp!=pUp; pp=&((*pp)->pNext)); + *pp = 0; + sqlite3_finalize(pUp->pUpdate); + pUp->pUpdate = 0; + }else{ + pUp = (RbuUpdateStmt*)rbuMalloc(p, sizeof(RbuUpdateStmt)+pIter->nTblCol+1); + } + + if( pUp ){ + char *zWhere = rbuObjIterGetWhere(p, pIter); + char *zSet = rbuObjIterGetSetlist(p, pIter, zMask); + char *zUpdate = 0; + + pUp->zMask = (char*)&pUp[1]; + memcpy(pUp->zMask, zMask, pIter->nTblCol); + pUp->pNext = pIter->pRbuUpdate; + pIter->pRbuUpdate = pUp; + + if( zSet ){ + const char *zPrefix = ""; + + if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_"; + zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s", + zPrefix, pIter->zTbl, zSet, zWhere + ); + p->rc = prepareFreeAndCollectError( + p->dbMain, &pUp->pUpdate, &p->zErrmsg, zUpdate + ); + *ppStmt = pUp->pUpdate; + } + sqlite3_free(zWhere); + sqlite3_free(zSet); + } + + return p->rc; +} + +static sqlite3 *rbuOpenDbhandle( + sqlite3rbu *p, + const char *zName, + int bUseVfs +){ + sqlite3 *db = 0; + if( p->rc==SQLITE_OK ){ + const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI; + p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0); + if( p->rc ){ + p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + sqlite3_close(db); + db = 0; + } + } + return db; +} + +/* +** Free an RbuState object allocated by rbuLoadState(). +*/ +static void rbuFreeState(RbuState *p){ + if( p ){ + sqlite3_free(p->zTbl); + sqlite3_free(p->zIdx); + sqlite3_free(p); + } +} + +/* +** Allocate an RbuState object and load the contents of the rbu_state +** table into it. Return a pointer to the new object. It is the +** responsibility of the caller to eventually free the object using +** sqlite3_free(). +** +** If an error occurs, leave an error code and message in the rbu handle +** and return NULL. +*/ +static RbuState *rbuLoadState(sqlite3rbu *p){ + RbuState *pRet = 0; + sqlite3_stmt *pStmt = 0; + int rc; + int rc2; + + pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState)); + if( pRet==0 ) return 0; + + rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, + sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb) + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + switch( sqlite3_column_int(pStmt, 0) ){ + case RBU_STATE_STAGE: + pRet->eStage = sqlite3_column_int(pStmt, 1); + if( pRet->eStage!=RBU_STAGE_OAL + && pRet->eStage!=RBU_STAGE_MOVE + && pRet->eStage!=RBU_STAGE_CKPT + ){ + p->rc = SQLITE_CORRUPT; + } + break; + + case RBU_STATE_TBL: + pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); + break; + + case RBU_STATE_IDX: + pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); + break; + + case RBU_STATE_ROW: + pRet->nRow = sqlite3_column_int(pStmt, 1); + break; + + case RBU_STATE_PROGRESS: + pRet->nProgress = sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_CKPT: + pRet->iWalCksum = sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_COOKIE: + pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_OALSZ: + pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1); + break; + + case RBU_STATE_PHASEONESTEP: + pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1); + break; + + default: + rc = SQLITE_CORRUPT; + break; + } + } + rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + + p->rc = rc; + return pRet; +} + + +/* +** Open the database handle and attach the RBU database as "rbu". If an +** error occurs, leave an error code and message in the RBU handle. +*/ +static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ + assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); + assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); + + /* Open the RBU database */ + p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); + + if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ + sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); + if( p->zState==0 ){ + const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); + p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile); + } + } + + /* If using separate RBU and state databases, attach the state database to + ** the RBU db handle now. */ + if( p->zState ){ + rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState); + memcpy(p->zStateDb, "stat", 4); + }else{ + memcpy(p->zStateDb, "main", 4); + } + +#if 0 + if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ + p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0); + } +#endif + + /* If it has not already been created, create the rbu_state table */ + rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb); + +#if 0 + if( rbuIsVacuum(p) ){ + if( p->rc==SQLITE_OK ){ + int rc2; + int bOk = 0; + sqlite3_stmt *pCnt = 0; + p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg, + "SELECT count(*) FROM stat.sqlite_master" + ); + if( p->rc==SQLITE_OK + && sqlite3_step(pCnt)==SQLITE_ROW + && 1==sqlite3_column_int(pCnt, 0) + ){ + bOk = 1; + } + rc2 = sqlite3_finalize(pCnt); + if( p->rc==SQLITE_OK ) p->rc = rc2; + + if( p->rc==SQLITE_OK && bOk==0 ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("invalid state database"); + } + + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); + } + } + } +#endif + + if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ + int bOpen = 0; + int rc; + p->nRbu = 0; + p->pRbuFd = 0; + rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); + if( rc!=SQLITE_NOTFOUND ) p->rc = rc; + if( p->eStage>=RBU_STAGE_MOVE ){ + bOpen = 1; + }else{ + RbuState *pState = rbuLoadState(p); + if( pState ){ + bOpen = (pState->eStage>=RBU_STAGE_MOVE); + rbuFreeState(pState); + } + } + if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1); + } + + p->eStage = 0; + if( p->rc==SQLITE_OK && p->dbMain==0 ){ + if( !rbuIsVacuum(p) ){ + p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1); + }else if( p->pRbuFd->pWalFd ){ + if( pbRetry ){ + p->pRbuFd->bNolock = 0; + sqlite3_close(p->dbRbu); + sqlite3_close(p->dbMain); + p->dbMain = 0; + p->dbRbu = 0; + *pbRetry = 1; + return; + } + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database"); + }else{ + char *zTarget; + char *zExtra = 0; + if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){ + zExtra = &p->zRbu[5]; + while( *zExtra ){ + if( *zExtra++=='?' ) break; + } + if( *zExtra=='\0' ) zExtra = 0; + } + + zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", + sqlite3_db_filename(p->dbRbu, "main"), + (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra) + ); + + if( zTarget==0 ){ + p->rc = SQLITE_NOMEM; + return; + } + p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1); + sqlite3_free(zTarget); + } + } + + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_create_function(p->dbMain, + "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0 + ); + } + + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_create_function(p->dbMain, + "rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0 + ); + } + + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_create_function(p->dbRbu, + "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0 + ); + } + + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); + } + rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master"); + + /* Mark the database file just opened as an RBU target database. If + ** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use. + ** This is an error. */ + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); + } + + if( p->rc==SQLITE_NOTFOUND ){ + p->rc = SQLITE_ERROR; + p->zErrmsg = sqlite3_mprintf("rbu vfs not found"); + } +} + +/* +** This routine is a copy of the sqlite3FileSuffix3() routine from the core. +** It is a no-op unless SQLITE_ENABLE_8_3_NAMES is defined. +** +** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database +** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and +** if filename in z[] has a suffix (a.k.a. "extension") that is longer than +** three characters, then shorten the suffix on z[] to be the last three +** characters of the original suffix. +** +** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always +** do the suffix shortening regardless of URI parameter. +** +** Examples: +** +** test.db-journal => test.nal +** test.db-wal => test.wal +** test.db-shm => test.shm +** test.db-mj7f3319fa => test.9fa +*/ +static void rbuFileSuffix3(const char *zBase, char *z){ +#ifdef SQLITE_ENABLE_8_3_NAMES +#if SQLITE_ENABLE_8_3_NAMES<2 + if( sqlite3_uri_boolean(zBase, "8_3_names", 0) ) +#endif + { + int i, sz; + sz = (int)strlen(z)&0xffffff; + for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} + if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); + } +#endif +} + +/* +** Return the current wal-index header checksum for the target database +** as a 64-bit integer. +** +** The checksum is store in the first page of xShmMap memory as an 8-byte +** blob starting at byte offset 40. +*/ +static i64 rbuShmChecksum(sqlite3rbu *p){ + i64 iRet = 0; + if( p->rc==SQLITE_OK ){ + sqlite3_file *pDb = p->pTargetFd->pReal; + u32 volatile *ptr; + p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr); + if( p->rc==SQLITE_OK ){ + iRet = ((i64)ptr[10] << 32) + ptr[11]; + } + } + return iRet; +} + +/* +** This function is called as part of initializing or reinitializing an +** incremental checkpoint. +** +** It populates the sqlite3rbu.aFrame[] array with the set of +** (wal frame -> db page) copy operations required to checkpoint the +** current wal file, and obtains the set of shm locks required to safely +** perform the copy operations directly on the file-system. +** +** If argument pState is not NULL, then the incremental checkpoint is +** being resumed. In this case, if the checksum of the wal-index-header +** following recovery is not the same as the checksum saved in the RbuState +** object, then the rbu handle is set to DONE state. This occurs if some +** other client appends a transaction to the wal file in the middle of +** an incremental checkpoint. +*/ +static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){ + + /* If pState is NULL, then the wal file may not have been opened and + ** recovered. Running a read-statement here to ensure that doing so + ** does not interfere with the "capture" process below. */ + if( pState==0 ){ + p->eStage = 0; + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0); + } + } + + /* Assuming no error has occurred, run a "restart" checkpoint with the + ** sqlite3rbu.eStage variable set to CAPTURE. This turns on the following + ** special behaviour in the rbu VFS: + ** + ** * If the exclusive shm WRITER or READ0 lock cannot be obtained, + ** the checkpoint fails with SQLITE_BUSY (normally SQLite would + ** proceed with running a passive checkpoint instead of failing). + ** + ** * Attempts to read from the *-wal file or write to the database file + ** do not perform any IO. Instead, the frame/page combinations that + ** would be read/written are recorded in the sqlite3rbu.aFrame[] + ** array. + ** + ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, + ** READ0 and CHECKPOINT locks taken as part of the checkpoint are + ** no-ops. These locks will not be released until the connection + ** is closed. + ** + ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL + ** error. + ** + ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the + ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[] + ** array populated with a set of (frame -> page) mappings. Because the + ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy + ** data from the wal file into the database file according to the + ** contents of aFrame[]. + */ + if( p->rc==SQLITE_OK ){ + int rc2; + p->eStage = RBU_STAGE_CAPTURE; + rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0); + if( rc2!=SQLITE_INTERNAL ) p->rc = rc2; + } + + if( p->rc==SQLITE_OK && p->nFrame>0 ){ + p->eStage = RBU_STAGE_CKPT; + p->nStep = (pState ? pState->nRow : 0); + p->aBuf = rbuMalloc(p, p->pgsz); + p->iWalCksum = rbuShmChecksum(p); + } + + if( p->rc==SQLITE_OK ){ + if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){ + p->rc = SQLITE_DONE; + p->eStage = RBU_STAGE_DONE; + }else{ + int nSectorSize; + sqlite3_file *pDb = p->pTargetFd->pReal; + sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal; + assert( p->nPagePerSector==0 ); + nSectorSize = pDb->pMethods->xSectorSize(pDb); + if( nSectorSize>p->pgsz ){ + p->nPagePerSector = nSectorSize / p->pgsz; + }else{ + p->nPagePerSector = 1; + } + + /* Call xSync() on the wal file. This causes SQLite to sync the + ** directory in which the target database and the wal file reside, in + ** case it has not been synced since the rename() call in + ** rbuMoveOalFile(). */ + p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL); + } + } +} + +/* +** Called when iAmt bytes are read from offset iOff of the wal file while +** the rbu object is in capture mode. Record the frame number of the frame +** being read in the aFrame[] array. +*/ +static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ + const u32 mReq = (1<mLock!=mReq ){ + pRbu->rc = SQLITE_BUSY; + return SQLITE_INTERNAL; + } + + pRbu->pgsz = iAmt; + if( pRbu->nFrame==pRbu->nFrameAlloc ){ + int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2; + RbuFrame *aNew; + aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame)); + if( aNew==0 ) return SQLITE_NOMEM; + pRbu->aFrame = aNew; + pRbu->nFrameAlloc = nNew; + } + + iFrame = (u32)((iOff-32) / (i64)(iAmt+24)) + 1; + if( pRbu->iMaxFrame